puzzles-20170606.272beef/0000755000175000017500000000000013115375151013666 5ustar simonsimonpuzzles-20170606.272beef/compile0000755000175000017500000001624513115373620015253 0ustar simonsimon#! /bin/sh # Wrapper for compilers which do not understand '-c -o'. scriptversion=2012-10-14.11; # UTC # Copyright (C) 1999-2014 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 ) 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 '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: puzzles-20170606.272beef/missing0000755000175000017500000001533013115373620015266 0ustar simonsimon#! /bin/sh # Common wrapper for a few potentially missing GNU programs. scriptversion=2013-10-28.13; # UTC # Copyright (C) 1996-2014 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=http://www.perl.org/ flex_URL=http://flex.sourceforge.net/ gnu_software_URL=http://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 '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: puzzles-20170606.272beef/install-sh0000755000175000017500000003546313115373620015704 0ustar simonsimon#!/bin/sh # install - install a program, script, or datafile scriptversion=2014-09-12.12; # 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; won't work # if double slashes aren't ignored. 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 dst=$dstdir/`basename "$src"` dstdir_status=0 else dstdir=`dirname "$dst"` test -d "$dstdir" dstdir_status=$? fi fi 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. ;; *) # $RANDOM is not portable (e.g. dash); use it when possible to # lower collision chance tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0 # As "mkdir -p" follows symlinks and we work in /tmp possibly; so # create the $tmpdir first (and fail if unsuccessful) to make sure # that nobody tries to guess the $tmpdir name. 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=$dstdir/_inst.$$_ rmtmp=$dstdir/_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 '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: puzzles-20170606.272beef/depcomp0000755000175000017500000005601613115373621015253 0ustar simonsimon#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2013-05-30.07; # UTC # Copyright (C) 1999-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. # Originally written by Alexandre Oliva . case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&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 '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: puzzles-20170606.272beef/configure0000755000175000017500000052143613115375150015607 0ustar simonsimon#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for puzzles 20170606.272beef. # # 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" 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 anakin@pobox.com $0: about your system, including any error possibly output $0: before this message. Then install a modern shell, or $0: manually run the script under such a shell if you do $0: have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &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='puzzles' PACKAGE_TARNAME='puzzles' PACKAGE_VERSION='20170606.272beef' PACKAGE_STRING='puzzles 20170606.272beef' PACKAGE_BUGREPORT='anakin@pobox.com' PACKAGE_URL='' ac_unique_file="midend.c" ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS LIBOBJS RANLIB PKG_CONFIG_LIBDIR PKG_CONFIG_PATH GTK_LIBS GTK_CFLAGS PKG_CONFIG am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE am__nodep AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE am__quote am__include DEPDIR OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC AM_BACKSLASH AM_DEFAULT_VERBOSITY AM_DEFAULT_V AM_V am__untar am__tar AMTAR am__leading_dot SET_MAKE AWK mkdir_p MKDIR_P INSTALL_STRIP_PROGRAM STRIP install_sh MAKEINFO AUTOHEADER AUTOMAKE AUTOCONF ACLOCAL VERSION PACKAGE CYGPATH_W am__isrc INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir runstatedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_silent_rules enable_dependency_tracking with_gtk enable_gtktest ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS PKG_CONFIG PKG_CONFIG_PATH PKG_CONFIG_LIBDIR' # 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 puzzles 20170606.272beef 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/puzzles] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF Program names: --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of puzzles 20170606.272beef:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-silent-rules less verbose build output (undo: "make V=1") --disable-silent-rules verbose build output (undo: "make V=0") --enable-dependency-tracking do not reject slow dependency extractors --disable-dependency-tracking speeds up one-time build --disable-gtktest do not try to compile and run a test GTK+ program Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-gtk=VER specify GTK version to use (`2' or `3') 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 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 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 puzzles configure 20170606.272beef 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_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_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 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 puzzles $as_me 20170606.272beef, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu am__api_version='1.15' 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='puzzles' VERSION='20170606.272beef' 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_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 DEPDIR="${am__leading_dot}deps" ac_config_commands="$ac_config_commands depfiles" am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 $as_echo_n "checking for style of include used by $am_make... " >&6; } am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from 'make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 $as_echo "$_am_result" >&6; } rm -f confinc confmf # Check whether --enable-dependency-tracking was given. if test "${enable_dependency_tracking+set}" = set; then : enableval=$enable_dependency_tracking; fi if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi if test "x$enable_dependency_tracking" != xno; then AMDEP_TRUE= AMDEP_FALSE='#' else AMDEP_TRUE='#' AMDEP_FALSE= fi depcc="$CC" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CC_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 $as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi # Check whether --with-gtk was given. if test "${with_gtk+set}" = set; then : withval=$with_gtk; gtk_version_desired="$withval" else gtk_version_desired="any" fi case "$gtk_version_desired" in 2 | 3 | any) ;; yes) gtk_version_desired="any" ;; *) as_fn_error $? "Invalid GTK version specified" "$LINENO" 5 esac gtk=none case "$gtk_version_desired:$gtk" in 3:none | any:none) # Check whether --enable-gtktest was given. if test "${enable_gtktest+set}" = set; then : enableval=$enable_gtktest; else enable_gtktest=yes fi min_gtk_version=3.0.0 pkg_config_args="gtk+-3.0 >= $min_gtk_version" for module in . do case "$module" in gthread) pkg_config_args="$pkg_config_args gthread-2.0" ;; esac done no_gtk="" # 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_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 test -z "$ac_cv_path_PKG_CONFIG" && ac_cv_path_PKG_CONFIG="no" ;; 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 if test x$PKG_CONFIG != xno ; then if $PKG_CONFIG --atleast-pkgconfig-version 0.7 ; then : else echo "*** pkg-config too old; version 0.7 or better required." no_gtk=yes PKG_CONFIG=no fi else no_gtk=yes fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GTK+ - version >= $min_gtk_version" >&5 $as_echo_n "checking for GTK+ - version >= $min_gtk_version... " >&6; } if test x$PKG_CONFIG != xno ; then ## don't try to run the test against uninstalled libtool libs if $PKG_CONFIG --uninstalled $pkg_config_args; then echo "Will use uninstalled version of GTK+ found in PKG_CONFIG_PATH" enable_gtktest=no fi if $PKG_CONFIG $pkg_config_args; then : else no_gtk=yes fi fi if test x"$no_gtk" = x ; then GTK_CFLAGS=`$PKG_CONFIG $pkg_config_args --cflags` GTK_LIBS=`$PKG_CONFIG $pkg_config_args --libs` gtk_config_major_version=`$PKG_CONFIG --modversion gtk+-3.0 | \ sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\1/'` gtk_config_minor_version=`$PKG_CONFIG --modversion gtk+-3.0 | \ sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\2/'` gtk_config_micro_version=`$PKG_CONFIG --modversion gtk+-3.0 | \ sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\3/'` if test "x$enable_gtktest" = "xyes" ; then ac_save_CFLAGS="$CFLAGS" ac_save_LIBS="$LIBS" CFLAGS="$CFLAGS $GTK_CFLAGS" LIBS="$GTK_LIBS $LIBS" rm -f conf.gtktest if test "$cross_compiling" = yes; then : echo $ac_n "cross compiling; assumed OK... $ac_c" else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include int main () { unsigned int major, minor, micro; fclose (fopen ("conf.gtktest", "w")); if (sscanf("$min_gtk_version", "%u.%u.%u", &major, &minor, µ) != 3) { printf("%s, bad version string\n", "$min_gtk_version"); exit(1); } if ((gtk_major_version != $gtk_config_major_version) || (gtk_minor_version != $gtk_config_minor_version) || (gtk_micro_version != $gtk_config_micro_version)) { printf("\n*** 'pkg-config --modversion gtk+-3.0' returned %d.%d.%d, but GTK+ (%d.%d.%d)\n", $gtk_config_major_version, $gtk_config_minor_version, $gtk_config_micro_version, gtk_major_version, gtk_minor_version, gtk_micro_version); printf ("*** was found! If pkg-config was correct, then it is best\n"); printf ("*** to remove the old version of GTK+. You may also be able to fix the error\n"); printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n"); printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n"); printf("*** required on your system.\n"); printf("*** If pkg-config was wrong, set the environment variable PKG_CONFIG_PATH\n"); printf("*** to point to the correct configuration files\n"); } else if ((gtk_major_version != GTK_MAJOR_VERSION) || (gtk_minor_version != GTK_MINOR_VERSION) || (gtk_micro_version != GTK_MICRO_VERSION)) { printf("*** GTK+ header files (version %d.%d.%d) do not match\n", GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION); printf("*** library (version %d.%d.%d)\n", gtk_major_version, gtk_minor_version, gtk_micro_version); } else { if ((gtk_major_version > major) || ((gtk_major_version == major) && (gtk_minor_version > minor)) || ((gtk_major_version == major) && (gtk_minor_version == minor) && (gtk_micro_version >= micro))) { return 0; } else { printf("\n*** An old version of GTK+ (%u.%u.%u) was found.\n", gtk_major_version, gtk_minor_version, gtk_micro_version); printf("*** You need a version of GTK+ newer than %u.%u.%u. The latest version of\n", major, minor, micro); printf("*** GTK+ is always available from ftp://ftp.gtk.org.\n"); printf("***\n"); printf("*** If you have already installed a sufficiently new version, this error\n"); printf("*** probably means that the wrong copy of the pkg-config shell script is\n"); printf("*** being found. The easiest way to fix this is to remove the old version\n"); printf("*** of GTK+, but you can also set the PKG_CONFIG environment to point to the\n"); printf("*** correct copy of pkg-config. (In this case, you will have to\n"); printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); printf("*** so that the correct libraries are found at run-time))\n"); } } return 1; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else no_gtk=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" fi fi if test "x$no_gtk" = x ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (version $gtk_config_major_version.$gtk_config_minor_version.$gtk_config_micro_version)" >&5 $as_echo "yes (version $gtk_config_major_version.$gtk_config_minor_version.$gtk_config_micro_version)" >&6; } gtk=3 else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if test "$PKG_CONFIG" = "no" ; then echo "*** A new enough version of pkg-config was not found." echo "*** See http://pkgconfig.sourceforge.net" else if test -f conf.gtktest ; then : else echo "*** Could not run GTK+ test program, checking why..." ac_save_CFLAGS="$CFLAGS" ac_save_LIBS="$LIBS" CFLAGS="$CFLAGS $GTK_CFLAGS" LIBS="$LIBS $GTK_LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { return ((gtk_major_version) || (gtk_minor_version) || (gtk_micro_version)); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : echo "*** The test program compiled, but did not run. This usually means" echo "*** that the run-time linker is not finding GTK+ or finding the wrong" echo "*** version of GTK+. If it is not finding GTK+, you'll need to set your" echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" echo "*** to the installed location Also, make sure you have run ldconfig if that" echo "*** is required on your system" echo "***" echo "*** If you have an old version installed, it is best to remove it, although" echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" else echo "*** The test program failed to compile or link. See the file config.log for the" echo "*** exact error that occured. This usually means GTK+ is incorrectly installed." fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" fi fi GTK_CFLAGS="" GTK_LIBS="" : fi rm -f conf.gtktest ;; esac case "$gtk_version_desired:$gtk" in 2:none | any:none) 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 # Check whether --enable-gtktest was given. if test "${enable_gtktest+set}" = set; then : enableval=$enable_gtktest; else enable_gtktest=yes fi pkg_config_args=gtk+-2.0 for module in . do case "$module" in gthread) pkg_config_args="$pkg_config_args gthread-2.0" ;; esac done no_gtk="" 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.7 { $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 min_gtk_version=2.0.0 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GTK+ - version >= $min_gtk_version" >&5 $as_echo_n "checking for GTK+ - version >= $min_gtk_version... " >&6; } if test x$PKG_CONFIG != xno ; then ## don't try to run the test against uninstalled libtool libs if $PKG_CONFIG --uninstalled $pkg_config_args; then echo "Will use uninstalled version of GTK+ found in PKG_CONFIG_PATH" enable_gtktest=no fi if $PKG_CONFIG --atleast-version $min_gtk_version $pkg_config_args; then : else no_gtk=yes fi fi if test x"$no_gtk" = x ; then GTK_CFLAGS=`$PKG_CONFIG $pkg_config_args --cflags` GTK_LIBS=`$PKG_CONFIG $pkg_config_args --libs` gtk_config_major_version=`$PKG_CONFIG --modversion gtk+-2.0 | \ sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\1/'` gtk_config_minor_version=`$PKG_CONFIG --modversion gtk+-2.0 | \ sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\2/'` gtk_config_micro_version=`$PKG_CONFIG --modversion gtk+-2.0 | \ sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\3/'` if test "x$enable_gtktest" = "xyes" ; then ac_save_CFLAGS="$CFLAGS" ac_save_LIBS="$LIBS" CFLAGS="$CFLAGS $GTK_CFLAGS" LIBS="$GTK_LIBS $LIBS" rm -f conf.gtktest if test "$cross_compiling" = yes; then : echo $ac_n "cross compiling; assumed OK... $ac_c" else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include int main () { int major, minor, micro; char *tmp_version; fclose (fopen ("conf.gtktest", "w")); /* HP/UX 9 (%@#!) writes to sscanf strings */ tmp_version = g_strdup("$min_gtk_version"); if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { printf("%s, bad version string\n", "$min_gtk_version"); exit(1); } if ((gtk_major_version != $gtk_config_major_version) || (gtk_minor_version != $gtk_config_minor_version) || (gtk_micro_version != $gtk_config_micro_version)) { printf("\n*** 'pkg-config --modversion gtk+-2.0' returned %d.%d.%d, but GTK+ (%d.%d.%d)\n", $gtk_config_major_version, $gtk_config_minor_version, $gtk_config_micro_version, gtk_major_version, gtk_minor_version, gtk_micro_version); printf ("*** was found! If pkg-config was correct, then it is best\n"); printf ("*** to remove the old version of GTK+. You may also be able to fix the error\n"); printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n"); printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n"); printf("*** required on your system.\n"); printf("*** If pkg-config was wrong, set the environment variable PKG_CONFIG_PATH\n"); printf("*** to point to the correct configuration files\n"); } else if ((gtk_major_version != GTK_MAJOR_VERSION) || (gtk_minor_version != GTK_MINOR_VERSION) || (gtk_micro_version != GTK_MICRO_VERSION)) { printf("*** GTK+ header files (version %d.%d.%d) do not match\n", GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION); printf("*** library (version %d.%d.%d)\n", gtk_major_version, gtk_minor_version, gtk_micro_version); } else { if ((gtk_major_version > major) || ((gtk_major_version == major) && (gtk_minor_version > minor)) || ((gtk_major_version == major) && (gtk_minor_version == minor) && (gtk_micro_version >= micro))) { return 0; } else { printf("\n*** An old version of GTK+ (%d.%d.%d) was found.\n", gtk_major_version, gtk_minor_version, gtk_micro_version); printf("*** You need a version of GTK+ newer than %d.%d.%d. The latest version of\n", major, minor, micro); printf("*** GTK+ is always available from ftp://ftp.gtk.org.\n"); printf("***\n"); printf("*** If you have already installed a sufficiently new version, this error\n"); printf("*** probably means that the wrong copy of the pkg-config shell script is\n"); printf("*** being found. The easiest way to fix this is to remove the old version\n"); printf("*** of GTK+, but you can also set the PKG_CONFIG environment to point to the\n"); printf("*** correct copy of pkg-config. (In this case, you will have to\n"); printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); printf("*** so that the correct libraries are found at run-time))\n"); } } return 1; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else no_gtk=yes fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" fi fi if test "x$no_gtk" = x ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (version $gtk_config_major_version.$gtk_config_minor_version.$gtk_config_micro_version)" >&5 $as_echo "yes (version $gtk_config_major_version.$gtk_config_minor_version.$gtk_config_micro_version)" >&6; } gtk=2 else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if test "$PKG_CONFIG" = "no" ; then echo "*** A new enough version of pkg-config was not found." echo "*** See http://pkgconfig.sourceforge.net" else if test -f conf.gtktest ; then : else echo "*** Could not run GTK+ test program, checking why..." ac_save_CFLAGS="$CFLAGS" ac_save_LIBS="$LIBS" CFLAGS="$CFLAGS $GTK_CFLAGS" LIBS="$LIBS $GTK_LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { return ((gtk_major_version) || (gtk_minor_version) || (gtk_micro_version)); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : echo "*** The test program compiled, but did not run. This usually means" echo "*** that the run-time linker is not finding GTK+ or finding the wrong" echo "*** version of GTK+. If it is not finding GTK+, you'll need to set your" echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" echo "*** to the installed location Also, make sure you have run ldconfig if that" echo "*** is required on your system" echo "***" echo "*** If you have an old version installed, it is best to remove it, although" echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" else echo "*** The test program failed to compile or link. See the file config.log for the" echo "*** exact error that occured. This usually means GTK+ is incorrectly installed." fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" fi fi GTK_CFLAGS="" GTK_LIBS="" : fi rm -f conf.gtktest ;; esac if test "$gtk" = "none"; then as_fn_error $? "cannot build without GTK 2 or GTK 3" "$LINENO" 5 fi if test "x$GCC" = "xyes"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for usable gcc warning flags" >&5 $as_echo_n "checking for usable gcc warning flags... " >&6; } gccwarningflags= for flag in -Wall -Werror -std=c89 -pedantic; do ac_save_CFLAGS="$CFLAGS" ac_save_LIBS="$LIBS" CFLAGS="$CFLAGS$gccwarningflags $flag $GTK_CFLAGS" LIBS="$GTK_LIBS $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include int main () { return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : gccwarningflags="$gccwarningflags $flag" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" done { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gccwarningflags" >&5 $as_echo "$gccwarningflags" >&6; } CFLAGS="$CFLAGS$gccwarningflags" 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 ac_config_files="$ac_config_files Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. ac_script=' :mline /\\$/{ N s,\\\n,, b mline } t clear :clear s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g t quote s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g t quote b any :quote s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g s/\[/\\&/g s/\]/\\&/g s/\$/$$/g H :any ${ g s/^\n// s/\n/ /g p } ' DEFS=`sed -n "$ac_script" confdefs.h` ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs { $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 $as_echo_n "checking that generated files are newer than configure... " >&6; } if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 $as_echo "done" >&6; } if test -n "$EXEEXT"; then am__EXEEXT_TRUE= am__EXEEXT_FALSE='#' else am__EXEEXT_TRUE='#' am__EXEEXT_FALSE= fi if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then as_fn_error $? "conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by puzzles $as_me 20170606.272beef, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_commands="$ac_config_commands" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE Configuration files: $config_files Configuration commands: $config_commands Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ puzzles config.status 20170606.272beef configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' MKDIR_P='$MKDIR_P' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --he | --h | --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` 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" eval set X " :F $CONFIG_FILES :C $CONFIG_COMMANDS" shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac ac_MKDIR_P=$MKDIR_P case $MKDIR_P in [\\/$]* | ?:[\\/]* ) ;; */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t s&@MKDIR_P@&$ac_MKDIR_P&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 $as_echo "$as_me: executing $ac_file commands" >&6;} ;; esac case $ac_file$ac_mode in "depfiles":C) test x"$AMDEP_TRUE" != x"" || { # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named 'Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`$as_dirname -- "$mf" || $as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$mf" : 'X\(//\)[^/]' \| \ X"$mf" : 'X\(//\)$' \| \ X"$mf" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running 'make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "$am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`$as_dirname -- "$file" || $as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$file" : 'X\(//\)[^/]' \| \ X"$file" : 'X\(//\)$' \| \ X"$file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir=$dirpart/$fdir; as_fn_mkdir_p # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ;; 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 puzzles-20170606.272beef/aclocal.m40000644000175000017500000020467013115373617015544 0ustar simonsimon# generated automatically by aclocal 1.15 -*- Autoconf -*- # Copyright (C) 1996-2014 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'.])]) # Configure paths for GTK+ # Owen Taylor 1997-2001 dnl AM_PATH_GTK_2_0([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND [, MODULES]]]]) dnl Test for GTK+, and define GTK_CFLAGS and GTK_LIBS, if gthread is specified in MODULES, dnl pass to pkg-config dnl AC_DEFUN([AM_PATH_GTK_2_0], [dnl dnl Get the cflags and libraries from pkg-config dnl AC_ARG_ENABLE(gtktest, [ --disable-gtktest do not try to compile and run a test GTK+ program], , enable_gtktest=yes) pkg_config_args=gtk+-2.0 for module in . $4 do case "$module" in gthread) pkg_config_args="$pkg_config_args gthread-2.0" ;; esac done no_gtk="" AC_REQUIRE([PKG_PROG_PKG_CONFIG]) PKG_PROG_PKG_CONFIG([0.7]) min_gtk_version=ifelse([$1], ,2.0.0,$1) AC_MSG_CHECKING(for GTK+ - version >= $min_gtk_version) if test x$PKG_CONFIG != xno ; then ## don't try to run the test against uninstalled libtool libs if $PKG_CONFIG --uninstalled $pkg_config_args; then echo "Will use uninstalled version of GTK+ found in PKG_CONFIG_PATH" enable_gtktest=no fi if $PKG_CONFIG --atleast-version $min_gtk_version $pkg_config_args; then : else no_gtk=yes fi fi if test x"$no_gtk" = x ; then GTK_CFLAGS=`$PKG_CONFIG $pkg_config_args --cflags` GTK_LIBS=`$PKG_CONFIG $pkg_config_args --libs` gtk_config_major_version=`$PKG_CONFIG --modversion gtk+-2.0 | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` gtk_config_minor_version=`$PKG_CONFIG --modversion gtk+-2.0 | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` gtk_config_micro_version=`$PKG_CONFIG --modversion gtk+-2.0 | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` if test "x$enable_gtktest" = "xyes" ; then ac_save_CFLAGS="$CFLAGS" ac_save_LIBS="$LIBS" CFLAGS="$CFLAGS $GTK_CFLAGS" LIBS="$GTK_LIBS $LIBS" dnl dnl Now check if the installed GTK+ is sufficiently new. (Also sanity dnl checks the results of pkg-config to some extent) dnl rm -f conf.gtktest AC_TRY_RUN([ #include #include #include int main () { int major, minor, micro; char *tmp_version; fclose (fopen ("conf.gtktest", "w")); /* HP/UX 9 (%@#!) writes to sscanf strings */ tmp_version = g_strdup("$min_gtk_version"); if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { printf("%s, bad version string\n", "$min_gtk_version"); exit(1); } if ((gtk_major_version != $gtk_config_major_version) || (gtk_minor_version != $gtk_config_minor_version) || (gtk_micro_version != $gtk_config_micro_version)) { printf("\n*** 'pkg-config --modversion gtk+-2.0' returned %d.%d.%d, but GTK+ (%d.%d.%d)\n", $gtk_config_major_version, $gtk_config_minor_version, $gtk_config_micro_version, gtk_major_version, gtk_minor_version, gtk_micro_version); printf ("*** was found! If pkg-config was correct, then it is best\n"); printf ("*** to remove the old version of GTK+. You may also be able to fix the error\n"); printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n"); printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n"); printf("*** required on your system.\n"); printf("*** If pkg-config was wrong, set the environment variable PKG_CONFIG_PATH\n"); printf("*** to point to the correct configuration files\n"); } else if ((gtk_major_version != GTK_MAJOR_VERSION) || (gtk_minor_version != GTK_MINOR_VERSION) || (gtk_micro_version != GTK_MICRO_VERSION)) { printf("*** GTK+ header files (version %d.%d.%d) do not match\n", GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION); printf("*** library (version %d.%d.%d)\n", gtk_major_version, gtk_minor_version, gtk_micro_version); } else { if ((gtk_major_version > major) || ((gtk_major_version == major) && (gtk_minor_version > minor)) || ((gtk_major_version == major) && (gtk_minor_version == minor) && (gtk_micro_version >= micro))) { return 0; } else { printf("\n*** An old version of GTK+ (%d.%d.%d) was found.\n", gtk_major_version, gtk_minor_version, gtk_micro_version); printf("*** You need a version of GTK+ newer than %d.%d.%d. The latest version of\n", major, minor, micro); printf("*** GTK+ is always available from ftp://ftp.gtk.org.\n"); printf("***\n"); printf("*** If you have already installed a sufficiently new version, this error\n"); printf("*** probably means that the wrong copy of the pkg-config shell script is\n"); printf("*** being found. The easiest way to fix this is to remove the old version\n"); printf("*** of GTK+, but you can also set the PKG_CONFIG environment to point to the\n"); printf("*** correct copy of pkg-config. (In this case, you will have to\n"); printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); printf("*** so that the correct libraries are found at run-time))\n"); } } return 1; } ],, no_gtk=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" fi fi if test "x$no_gtk" = x ; then AC_MSG_RESULT(yes (version $gtk_config_major_version.$gtk_config_minor_version.$gtk_config_micro_version)) ifelse([$2], , :, [$2]) else AC_MSG_RESULT(no) if test "$PKG_CONFIG" = "no" ; then echo "*** A new enough version of pkg-config was not found." echo "*** See http://pkgconfig.sourceforge.net" else if test -f conf.gtktest ; then : else echo "*** Could not run GTK+ test program, checking why..." ac_save_CFLAGS="$CFLAGS" ac_save_LIBS="$LIBS" CFLAGS="$CFLAGS $GTK_CFLAGS" LIBS="$LIBS $GTK_LIBS" AC_TRY_LINK([ #include #include ], [ return ((gtk_major_version) || (gtk_minor_version) || (gtk_micro_version)); ], [ echo "*** The test program compiled, but did not run. This usually means" echo "*** that the run-time linker is not finding GTK+ or finding the wrong" echo "*** version of GTK+. If it is not finding GTK+, you'll need to set your" echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" echo "*** to the installed location Also, make sure you have run ldconfig if that" echo "*** is required on your system" echo "***" echo "*** If you have an old version installed, it is best to remove it, although" echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" ], [ echo "*** The test program failed to compile or link. See the file config.log for the" echo "*** exact error that occured. This usually means GTK+ is incorrectly installed."]) CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" fi fi GTK_CFLAGS="" GTK_LIBS="" ifelse([$3], , :, [$3]) fi AC_SUBST(GTK_CFLAGS) AC_SUBST(GTK_LIBS) rm -f conf.gtktest ]) # Configure paths for GTK+ # Owen Taylor 1997-2001 dnl AM_PATH_GTK_3_0([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND [, MODULES]]]]) dnl Test for GTK+, and define GTK_CFLAGS and GTK_LIBS, if gthread is specified in MODULES, dnl pass to pkg-config dnl AC_DEFUN([AM_PATH_GTK_3_0], [m4_warn([obsolete], [AM_PATH_GTK_3_0 is deprecated, use PKG_CHECK_MODULES([GTK], [gtk+-3.0]) instead]) dnl Get the cflags and libraries from pkg-config dnl AC_ARG_ENABLE(gtktest, [ --disable-gtktest do not try to compile and run a test GTK+ program], , enable_gtktest=yes) min_gtk_version=ifelse([$1], [], [3.0.0], [$1]) pkg_config_args="gtk+-3.0 >= $min_gtk_version" for module in . $4 do case "$module" in gthread) pkg_config_args="$pkg_config_args gthread-2.0" ;; esac done no_gtk="" AC_PATH_PROG(PKG_CONFIG, pkg-config, no) if test x$PKG_CONFIG != xno ; then if $PKG_CONFIG --atleast-pkgconfig-version 0.7 ; then : else echo "*** pkg-config too old; version 0.7 or better required." no_gtk=yes PKG_CONFIG=no fi else no_gtk=yes fi AC_MSG_CHECKING(for GTK+ - version >= $min_gtk_version) if test x$PKG_CONFIG != xno ; then ## don't try to run the test against uninstalled libtool libs if $PKG_CONFIG --uninstalled $pkg_config_args; then echo "Will use uninstalled version of GTK+ found in PKG_CONFIG_PATH" enable_gtktest=no fi if $PKG_CONFIG $pkg_config_args; then : else no_gtk=yes fi fi if test x"$no_gtk" = x ; then GTK_CFLAGS=`$PKG_CONFIG $pkg_config_args --cflags` GTK_LIBS=`$PKG_CONFIG $pkg_config_args --libs` gtk_config_major_version=`$PKG_CONFIG --modversion gtk+-3.0 | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` gtk_config_minor_version=`$PKG_CONFIG --modversion gtk+-3.0 | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` gtk_config_micro_version=`$PKG_CONFIG --modversion gtk+-3.0 | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` if test "x$enable_gtktest" = "xyes" ; then ac_save_CFLAGS="$CFLAGS" ac_save_LIBS="$LIBS" CFLAGS="$CFLAGS $GTK_CFLAGS" LIBS="$GTK_LIBS $LIBS" dnl dnl Now check if the installed GTK+ is sufficiently new. (Also sanity dnl checks the results of pkg-config to some extent) dnl rm -f conf.gtktest AC_TRY_RUN([ #include #include #include int main () { unsigned int major, minor, micro; fclose (fopen ("conf.gtktest", "w")); if (sscanf("$min_gtk_version", "%u.%u.%u", &major, &minor, µ) != 3) { printf("%s, bad version string\n", "$min_gtk_version"); exit(1); } if ((gtk_major_version != $gtk_config_major_version) || (gtk_minor_version != $gtk_config_minor_version) || (gtk_micro_version != $gtk_config_micro_version)) { printf("\n*** 'pkg-config --modversion gtk+-3.0' returned %d.%d.%d, but GTK+ (%d.%d.%d)\n", $gtk_config_major_version, $gtk_config_minor_version, $gtk_config_micro_version, gtk_major_version, gtk_minor_version, gtk_micro_version); printf ("*** was found! If pkg-config was correct, then it is best\n"); printf ("*** to remove the old version of GTK+. You may also be able to fix the error\n"); printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n"); printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n"); printf("*** required on your system.\n"); printf("*** If pkg-config was wrong, set the environment variable PKG_CONFIG_PATH\n"); printf("*** to point to the correct configuration files\n"); } else if ((gtk_major_version != GTK_MAJOR_VERSION) || (gtk_minor_version != GTK_MINOR_VERSION) || (gtk_micro_version != GTK_MICRO_VERSION)) { printf("*** GTK+ header files (version %d.%d.%d) do not match\n", GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION); printf("*** library (version %d.%d.%d)\n", gtk_major_version, gtk_minor_version, gtk_micro_version); } else { if ((gtk_major_version > major) || ((gtk_major_version == major) && (gtk_minor_version > minor)) || ((gtk_major_version == major) && (gtk_minor_version == minor) && (gtk_micro_version >= micro))) { return 0; } else { printf("\n*** An old version of GTK+ (%u.%u.%u) was found.\n", gtk_major_version, gtk_minor_version, gtk_micro_version); printf("*** You need a version of GTK+ newer than %u.%u.%u. The latest version of\n", major, minor, micro); printf("*** GTK+ is always available from ftp://ftp.gtk.org.\n"); printf("***\n"); printf("*** If you have already installed a sufficiently new version, this error\n"); printf("*** probably means that the wrong copy of the pkg-config shell script is\n"); printf("*** being found. The easiest way to fix this is to remove the old version\n"); printf("*** of GTK+, but you can also set the PKG_CONFIG environment to point to the\n"); printf("*** correct copy of pkg-config. (In this case, you will have to\n"); printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); printf("*** so that the correct libraries are found at run-time))\n"); } } return 1; } ],, no_gtk=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" fi fi if test "x$no_gtk" = x ; then AC_MSG_RESULT(yes (version $gtk_config_major_version.$gtk_config_minor_version.$gtk_config_micro_version)) ifelse([$2], , :, [$2]) else AC_MSG_RESULT(no) if test "$PKG_CONFIG" = "no" ; then echo "*** A new enough version of pkg-config was not found." echo "*** See http://pkgconfig.sourceforge.net" else if test -f conf.gtktest ; then : else echo "*** Could not run GTK+ test program, checking why..." ac_save_CFLAGS="$CFLAGS" ac_save_LIBS="$LIBS" CFLAGS="$CFLAGS $GTK_CFLAGS" LIBS="$LIBS $GTK_LIBS" AC_TRY_LINK([ #include #include ], [ return ((gtk_major_version) || (gtk_minor_version) || (gtk_micro_version)); ], [ echo "*** The test program compiled, but did not run. This usually means" echo "*** that the run-time linker is not finding GTK+ or finding the wrong" echo "*** version of GTK+. If it is not finding GTK+, you'll need to set your" echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" echo "*** to the installed location Also, make sure you have run ldconfig if that" echo "*** is required on your system" echo "***" echo "*** If you have an old version installed, it is best to remove it, although" echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" ], [ echo "*** The test program failed to compile or link. See the file config.log for the" echo "*** exact error that occured. This usually means GTK+ is incorrectly installed."]) CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" fi fi GTK_CFLAGS="" GTK_LIBS="" ifelse([$3], , :, [$3]) fi AC_SUBST(GTK_CFLAGS) AC_SUBST(GTK_LIBS) rm -f conf.gtktest ]) dnl GTK_CHECK_BACKEND(BACKEND-NAME [, MINIMUM-VERSION [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]]) dnl Tests for BACKEND-NAME in the GTK targets list dnl AC_DEFUN([GTK_CHECK_BACKEND], [m4_warn([obsolete], [GTK_CHECK_BACKEND is deprecated, use PKG_CHECK_MODULES([GTK_X11], [gtk+-x11-3.0]) or similar instead]) pkg_config_args=ifelse([$1],,gtk+-3.0, gtk+-$1-3.0) min_gtk_version=ifelse([$2],,3.0.0,$2) pkg_config_args="$pkg_config_args >= $min_gtk_version" AC_PATH_PROG(PKG_CONFIG, [pkg-config], [AC_MSG_ERROR([No pkg-config found])]) if $PKG_CONFIG $pkg_config_args ; then target_found=yes else target_found=no fi if test "x$target_found" = "xno"; then ifelse([$4],,[AC_MSG_ERROR([Backend $backend not found.])],[$4]) else ifelse([$3],,[:],[$3]) 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-2014 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.15' 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.15], [], [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.15])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-2014 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-2014 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-2014 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-2014 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. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named 'Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`AS_DIRNAME("$mf")` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running 'make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "$am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`AS_DIRNAME(["$file"])` AS_MKDIR_P([$dirpart/$fdir]) # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ])# _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. FIXME. This creates each '.P' file that we will # 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" ac_aux_dir="$ac_aux_dir"]) ]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996-2014 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-2014 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-2014 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-2014 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 to see how make treats includes. AC_DEFUN([AM_MAKE_INCLUDE], [am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. AC_MSG_CHECKING([for style of include used by $am_make]) am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from 'make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi AC_SUBST([am__include]) AC_SUBST([am__quote]) AC_MSG_RESULT([$_am_result]) rm -f confinc confmf ]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997-2014 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-2014 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-2014 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-2014 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-2014 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-2014 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-2014 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-2014 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-2014 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 puzzles-20170606.272beef/mkauto.sh0000755000175000017500000000006213115373615015526 0ustar simonsimon#! /bin/sh autoreconf -i && rm -rf autom4te.cache puzzles-20170606.272beef/configure.ac0000644000175000017500000000420413115373615016157 0ustar simonsimondnl Configure script for the Unix GTK build of puzzles. AC_INIT([puzzles], [20170606.272beef], [anakin@pobox.com]) AC_CONFIG_SRCDIR([midend.c]) AM_INIT_AUTOMAKE([foreign]) AC_PROG_CC AC_ARG_WITH([gtk], [AS_HELP_STRING([--with-gtk=VER], [specify GTK version to use (`2' or `3')])], [gtk_version_desired="$withval"], [gtk_version_desired="any"]) case "$gtk_version_desired" in 2 | 3 | any) ;; yes) gtk_version_desired="any" ;; *) AC_ERROR([Invalid GTK version specified]) esac gtk=none case "$gtk_version_desired:$gtk" in 3:none | any:none) ifdef([AM_PATH_GTK_3_0],[ AM_PATH_GTK_3_0([3.0.0], [gtk=3], []) ],[AC_WARNING([generating configure script without GTK 3 autodetection])]) ;; esac case "$gtk_version_desired:$gtk" in 2:none | any:none) ifdef([AM_PATH_GTK_2_0],[ AM_PATH_GTK_2_0([2.0.0], [gtk=2], []) ],[AC_WARNING([generating configure script without GTK 2 autodetection])]) ;; esac if test "$gtk" = "none"; then AC_MSG_ERROR([cannot build without GTK 2 or GTK 3]) fi if test "x$GCC" = "xyes"; then AC_MSG_CHECKING([for usable gcc warning flags]) gccwarningflags= for flag in -Wall -Werror -std=c89 -pedantic; do ac_save_CFLAGS="$CFLAGS" ac_save_LIBS="$LIBS" CFLAGS="$CFLAGS$gccwarningflags $flag $GTK_CFLAGS" LIBS="$GTK_LIBS $LIBS" AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include ],[ return 0; ])], [gccwarningflags="$gccwarningflags $flag"], []) CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" done AC_MSG_RESULT($gccwarningflags) CFLAGS="$CFLAGS$gccwarningflags" fi AC_PROG_RANLIB AC_PROG_INSTALL AC_CONFIG_FILES([Makefile]) AC_OUTPUT puzzles-20170606.272beef/puzzles.chm0000644000175000017500000021234513115374020016074 0ustar simonsimonITSF`4Vx ý|ª{О  É"æìý|ª{О  É"æì`xTÌþåITSPT ÿÿÿÿ j’].!Ðù É"æìTÿÿÿÿÿÿÿÿÿÿÿÿPMGLžÿÿÿÿÿÿÿÿ//#IDXHDR‘À) /#ITBITS /#STRINGS‘à)Ž8/#SYSTEM¡W/#TOCIDXÁVÉ /#TOPICS‘Šv`/#URLSTR‘¦>™k/#URLTBL‘šV‹h /#WINDOWSÀ L/blackbox-controls.html†În–./blackbox-parameters.html†åŠ=/blackbox.html†²Oœ/bridges-controls.htmlˆÙœs/bridges-parameters.htmlˆö /bridges.htmlˆÊ/chm.css»~/common-actions.htmlê1Ÿ/common-cmdline.html»1–c/common-id.html‰8©^/common-type.html³ˆ/common-unix-cmdline.htmlÒ£F /common.htmlâˆ+ /contents.hhc½¦ /cube-controls.html‚²]‰y/cube-params.html‚¼Vˆ /cube.html‚¤)Ž4/dominosa-controls.html†„/dominosa-parameters.html†‘‹(/dominosa.html…úY‰@/fifteen-controls.html‚ΉN/fifteen-params.html‚×l†F /fifteen.html‚Ät‰*/filling-controls.html‰é‹o/filling-parameters.html‰õ…; /filling.html‰Ü /flip-controls.html…¡.‰e/flip-parameters.html…«‰2 /flip.html…˜rˆ</flood-controls.htmlŒÝc‰/flood-parameters.htmlŒæk) /flood.htmlŒÑaŒ/galaxies-controls.html‰Âs‘&/galaxies-parameters.html‰Ô‡q/galaxies.html‰·#‹P/guess-controls.html…¿\‘/guess-parameters.html…ÐjŒa /guess.html…´E‹ /index.hhkŽãÜ| /index.htmlË,/inertia-controls.htmlˆ•f:/inertia-parameters.htmlˆ£ † /inertia.htmlˆ‡ŽS /intro.htmlË,–Z/keen-controls.htmlŠŽ’)/keen-parameters.htmlŠ DŠO /keen.html‰ú;“` /licence.html¬Žn/lightup-controls.html‡¢JŠ</lightup-parameters.html‡­‹= /lightup.html‡”/Ž/loopy-controls.html‡ò<ˆE/loopy-parameters.html‡ûŒ /loopy.html‡ä"Ž/magnets-controls.html‹ /magnets-parameters.html‹ŽŠ9 /magnets.htmlŠóQ9/map-controls.html‡Å “B/map-parameters.html‡ØL‹V /map.html‡¸CŒG/mines-controls.html„Ó'–/mines-parameters.html„é+‹E /mines.html„ÆKŒ\/net-controls.html‚‚-/net-params.html‚’@‘i /net.htmlõZŒS/netslide.htmlƒ×Š/palisade-controls.htmlC‡Z/Palisade-parameters.html¥†{/palisade.html’FŠ}/pattern-controls.htmlƒî</pattern-parameters.htmlƒûN…p /pattern.htmlƒá$/pearl-controls.html‹ôAŽP/pearl-parameters.htmlŒƒ…- /pearl.html‹ãIx/pegs-controls.html…æŠ~/pegs-parameters.html…ñ‰B /pegs.html…ÝKˆN/range-controls.html‹Ó%Š/range-parameters.html‹ÝD† /range.html‹Â@e /rect.htmlƒ¨DY/rectangles-controls.htmlƒ¸Œ/rectangles-params.htmlƒÄ+’W/samegame-controls.html„ÿI‰o/samegame-parameters.html…‰8:/samegame.html„ôpŠY/signpost-controls.html‹¦<“`/signpost-parameters.html‹ºˆ$/signpost.html‹˜Lp/singles-controls.htmlŠäˆa/singles-parameters.htmlŠìi†h /singles.htmlŠ×YŒ//sixteen-controls.html‚ì.Š]/sixteen-params.html‚÷ ŠX /sixteen.html‚Þ2|/slant-controls.html†û^Ž/slant-parameters.html‡‰yŠ6 /slant.html†ïYŒ/solo-controls.html„›MW/solo-parameters.html„¬$š' /solo.html„>š/tents-controls.htmlˆµHŒJ/tents-parameters.htmlˆÂ‡u /tents.htmlˆ©+Œ/towers-controls.htmlŠº”/towers-parameters.htmlŠÎ6‰# /towers.htmlŠ«/tracks-controls.htmlŒýŠ/tracks-parameters.html‡.‹ /tracks.htmlŒô‰/twiddle-controls.htmlƒH‹L/twiddle-parameters.htmlƒ™0 /twiddle.htmlƒc‹e/undead-controls.htmlŒ˜”}/undead-parameters.htmlŒ¬~†d /undead.htmlŒˆ>C/unequal-controls.html‰—\•4/unequal-parameters.html‰­Š /unequal.html‰†‘K/unruly-controls.htmlŒ¾q‰x/unruly-parameters.htmlŒÈiˆx /unruly.htmlŒ³b‹/untangle-controls.html†¥c†/untangle-parameters.html†«z†U/untangle.html†œD‰::DataSpace/NameList¡W<(::DataSpace/Storage/MSCompressed/Content¢ƒäL,::DataSpace/Storage/MSCompressed/ControlData„‡ )::DataSpace/Storage/MSCompressed/SpanInfo„‡/::DataSpace/Storage/MSCompressed/Transform/List„†_&i::DataSpace/Storage/MSCompressed/Transform/{7FC28940-9D31-11D0-9B27-00A0C91E9C7C}/InstanceData/ResetTable„‡)p{ Ì M Ä C È I Ð N ½?ËCËQÚ_âgûy{ÿ†‰= Halibut, unidentified version *Simon Tatham's Portable Puzzle Collection index.html contents.hhc index.hhkmain$ D3"ˆwfU · þ³×ÿ T#SMxV4~ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ Uncompressed MSCompressed3T03^Uð³´n–ÇÈ‘Èߊ¤‹î$ϽâŠálææ ŽK”d-»m›2Ÿg0ï¿æøf¨ Fª ùFkµÜÝ.c.óò,ÆÃð-<˜s9±ÜÍ“âk^nD1 6T ¶$ •ªÎI’TTm* Ч TRuª„ÚU[ê@’øh«D‚$þÕûî ÍTï=½w;çÌÌ˼ªº—¹¤’ÇŽM—9ŽPz @I@ˆ8„"PP’)|I€ BÖe¾›·¹?{é3‡Ÿém÷=çTo· è³³ú SÊHC¡Kí¡ÌéCzN_A˜‰, ×O‘P‘JQ(¶ÏPÏÏŸ @— 9ÎÐÐm)¨³HI(”"€‘‚HÚ÷l‘z ·(C8*=ã$V¡÷”"Šqb J¥T¡ˆ¨z%U@vL%@ P†¡WÍìíÊæf¦f.ª…P lÒ#EŒ%à(œOHÈa(†‚Ù¹_nť484Û3<Ù Š Ó„¾Õˆ‘„A¦$ôD¢[Abg¡J2T.GXiÉ$)Üþ¡J JÚÙ\s¯4TµP¨+çZhS ¹ð}UÅÀ"=i† Íõ"€C[5 IÅÁùO¬Î˜T(‚ r0…ª„2ÆUz2Iø!AB³j©VFµJ ª: N KËJL–£0EæaZü|J¨dôD†að Žðœ® ô%ħʊ 6ªé©Uø²ŒUy(e jZpJDÉ@CØa³C¥ öšA®ÍGÖ hA¥Œ”vmAhÚ~˜71ô¡ÊÅ̜͆«]¢ˆm2Œ58(“v¤*“TyU¶¨M `oúJVcb\ôX©£^¨Ö{7%´‚ÁµR*äº?ਕA × ×lÑÄ~Ï QÄc*Ê÷ëz4|°Õq¥hÝ“]4Q€Cj§‰m9Âذ·0ÞNF›)äúS®.7lu4ŨúæöÔ×NËaŽzšµ°^4¶(’~>çfy=_»õõ¬Ø¨o©Ž¯YŠœÒlËÛ@À|ÃNüSa¥ˆÎ¬Òabº™²µŸGçÔRkJÏÅA4°Fì&›[Þ¨œ)?²rw/ptç²å”KA²Ý½ÆÑz9¥š²ÃS©( Ee'­Žâ‹ ”4“‡Í‹1²ËJOB*,©ºÇ¥_g=*KƉmZà¨÷²ìTOå:×A*+iL.Ü*¤]³s¤:¨ùèEù\-'ÚÏySd]üõË¥wn‡´ xrÔ$»‡çqH^ާ¦V-¥#DÉã·÷¼¸áOrQžƒ! âÃGórŒ“ìžT!õ’PMËi: \8Nm;3å¿'.åsP¤¼X8'gA±Kw·”åhêµC¥yºèÄ[7N–¾KüZŰ¹,RàA Í ¡ÕÚ¥<AJyiÊzk¬ïøÝýZ.'gÏ%~-ã(XÏ¥&Zr^ ­³¢]ž´ ½¼He)(RgAùZ.'GÏ |#zÐÕŒ¢a?ŸÝÝI ÎK¡uVÔýóÐÝ@µŸÎA± Fjî‘÷&̸ž¾uùyºÑáœñµ½.'FWjô*¤^’‹©•½+£ô 5÷h¬Õ"™ì·—å‰OË*GhAyV»ìÂÑûæ\ZAoôÇÃ1=x^‚ðL¹ W=‡Á’/Æ.d£7%˜÷ð(·“<ÜPqïê,s{‘ÉåF¯Cż¹9©EvÁèUH½$vS¹—PD¿¡f}kâæ_ñʼn/ËZF¬BæEZݳËF¯Aºih¿z¦3wÍÈrCÄ=÷æ‹*|Y.7zR>†Ê9©UvÝèUHÎ$Ò £9FÃjîQ= ˜µËËù^–ôŽX…匪×vYèuHû -Ýuùž¨ùGö¸`~¿uù7—‹Þ…´X™i,ã>»{ô¤›†ùÒPh^d‡š{¤½¿†ñ¬O̪GhA¼!Z°—¶iTÒ‚ý÷q ÓRäó5÷(§Ì㋞˜ÔŽX…ÑŽqÑ]–z Ò9C ÕKÓù¥‹5—ûøÒÁN¡sz—R7,4/NçtB¶è]HÙŽqHgóÀBëeæC;Tsâóõ2b~7å=£T!98G.ɽË)µ Ò›õ´çj÷¥bÖ¸è\œô¸¤nÄ*•vä8ËæžwԎЂ{Óô“]ð=løÝžÌ·âÿ§¨B8 ¼„*ŠnÙeáüð&«„.k‰çTÆ09XÁ5ûò½‰²øûÞ—ó=1i" ´ŒTíÒÒ#.^Z²^ùÇÉ¥D;doãŽÿâ‹ —”‘‡åŽêŒ]Nz–RFIT/Õ lͨ¹—Š>„˜wS¼Uá½¥!ò)Ý ¨üv9éM/?jqod_¨çjýåïÝx7ïý+—=ýeñí ›Rùì’ÑÃ_î©Þ}YÌ\¬ÒrÔ\K<ÂÞö^ú}z)K:äñÍ£—)5³¢ÂÑ _TtÞ¬sƒ9ä^j÷%Ü;Cn¾W¬\hô8¤v|^”å GÙ%£T!]—ä2 @¾÷ƒ)ÉP¸1ýœÖ}Y]̘V4zRu@/ËIÆÄrÑòY«Š ! Ã`Z8ÔnLÛ63ñ!.èz_R:A Î žº‹£7 ż´e½J>jA°?7­¯"¢Ç•Ü•°zKQk¶'Ò c3”ÑŠânˆùztmg³½–@MÃ+!Z+=Œ%;¢ÿ¨µúÁÇŸ¶‘e@TÂs¬«ð6bäŽCOeág¦™OÍÜe=ÿ î‚eŸÙ®¯èTlµS83YŠê+ú4[ùèá¨lé”Ädí:ä\ˆÅ ~T(¢÷‘2fê3¥¨¡‡¾ˆÀó-ˆ®ª!Æ”žŠVðCRdø‚¥Ejµ©¢1h‡`Ÿ´)aÅõLŸK¤ÊED…"ßÔ-CD%Pê:P ¡31ð!:ƒbSÀ¼”à:™ŸúÄÁœ^œH­ ¬?§±½I£±BU8 B1BIEÏjŽ8ñSÕ=2V/ $4H`20–D¢÷Äž Q¼¡‹âF;ËCuM­x+ÙâÄUA”wj/Uе ’¼€¨å¨95Ïìу@²y¿ ê!¹¾bºžÒäËp©¥ÕÆÑ ‚9{” ÷¹8Ô úá¸BøÆ(åè”Px÷ fVð_qjÁJzDú*6•± ¹¦dõÞJ±6÷ädqøŒièC|q";’À² ½ÄÉA€©§'ëµH=?Ãß\š2ÓÛYi-‡F¯Îš©!ÈËv¤)“añ0©! ö¿¯l‚î–s¥©L3ˆÀv&uà-Á„%³ÕãÀŸBPÃ=€ Œ ÓÆtBÕÙs­´É,}eè¦menç!ØŠ*¦[ •fx¦ªH]ë<¯óE»¬½óÇMTôuŸÒ‰=ïd°&ºÜ9ˆ0ë$RÀa¥dEAЕŒÖp¥(¡ðšXZzu›oŽ=,4mÙåASD‰ÏCÄIÉÖ°m!µùñ@Ów›«‰ûUò¸byj‚­²­‚¨eTŽât ¥¾ î3.Sê{V·ñ %€EZh-»Ùë¤Õ†=œRñ¬´8x” ¥Tr‘¥LÀÿKóŠ-_4š\3,ìF0íÑ^Ö—gTQ) •VšE°›ø†ø­yOHsÀ ‘è´UU™™6F%m®T·îAC»S'.¦ò¶^%)ùÙßúQœ$¬{Sóí´%)ÛjUxûI0:¦(â=k”—-·©ö˜W¸â5¨ó¾ýàNÚ€ vô6îYƒð@Mu®ýN‰ÓS©ÂWs«VÅi~÷ͬ -¶a0ÏYšy–ã`¹Oýï_W$Ë—ëîÒ\µÔ(ðˆ}# :ðß>TTe l[åUòb.ó3¹•½ý²ýD5ÉM‰¤5$qì ÔXÖJ i®i¶ý7€Ž^²Ä{üpµÖŒÜ@+N u.P:¶EôJ["ØbÝÚ4u@L¦Ñ[ðk³ÙêØ–ly Œèe•Á(˜Ïà{/I¥8è&v÷&G29·À>»ñ‹k9=noV¾¦Eå=îtû–ßÎ@d&ÀXÌDÂ8j%“câ ½‚+8kžþî¼VÔü4.qÍSO-€·,îFÿ-lÍY– A3ýcúâ·ÞŸY£˜û²/jqBfÇ2Æòÿw¸åè.ü؃é·9±)ý'íŸÅ&úÀzOû “:С¤÷Ä)Ȳ*{‰¾Ñcw{]ñ]©qÍÙ0­y‰NÉ`/nc;Àƒ±šçD6˜âÆÍŽâñ•ib3 Shî&E#^2i˜ æö ­”XòoÙ(y“eÞª×l ºNgÚN¯&Ê“ <¨$ƒ>û Œ¤­¶Cv´SðõMš‡ªJ½þ%U™(³ äݨÂLafS6l¶P“)½8Ñø¾;‘‹^k¯ÓS0ïÑ ƒž¨a½‡ÛnKuèzÁ~ææó&3%ðd›ó!odbâM†®%¡~äÁñ´Ï×u°}XóQý7uü»É¹º|•dk»]àØÖ3×.å¼tó`ŸÖÓÍŠŠ|w_¸˜á#`ˆ%—®J÷«‰íª†Û”úr·âU®„q2â)0ÍË<”s%ãÍ\²¥·‡.ñ:Æf_lmÊrÁ]ZðZB!2¨†|¢0³^‹+=N“æ:t/ìŠY¶©! ³í!:djU|ž÷KtÉ»‹GÆÿ2PƒSb»°!!ØÆ¼‚"¸øŽçQàñîµVÈ¢°& î¸ìZ”mÇâ-Ó«ëÖéÀèýžÝÅ4¦£®ª(ÇÂ)þÔ‡œí±7´aA6õx}ð= Cb&\§ÆfJ àÄ„aÅ)Áq)×¶'Áìœ,¯Û÷ŸÓv"|œ+t>Kc%ûö1‰D‘˜iÈ+ûÿ0ÉŸÿ€—¡ê†ˆ+rúj_Ö¿dYâÂýK ±‹$¼Z›ÈšÏäÿ¢Žsb‘ 9×¢[cFK{¨Øu·[Yÿs7ÅHØ­‘Ëì—AfXFcJƒ|fK\VŸÊß@š~=‚à ¿û×@ãÆ,ÒäœPé¼-™XKäƒýÝáW¨‡jU_ñð8Ò 9HÊzÜ«y~rЄàV¥¿êZÖĸû¯)䗗ůß|ðmÎrÎÔ)7ô…Þ²`†úÄS}.²å‰a9…KÎËe—Ç;2Þ®ï‘^];¯¤^™ˆòð’ÜHçš V‚ÜŒì€$¤yÀwœ¥Nm|4€Š ¿Ü8 Ú"Ò*a|#jç&¹²tÖä _äâ”Ý]„ìHê„{tºïùÑ‚fÔš«…ZìÔ©aå\^¡%Hñ)7:§ÈÛ¥wcN=¯ëwß2^hx{¢Àòƒƒ,ظ–ö½¯ï+B UVŒSOi»Ã\×Ί6'ÒÃúÚ„}ˆc^´ :ŸÆ"Ëe–ï÷—b{ÖYÚ7dW:¼ å°ueW¼ò‚€Ä/àBÈæºá`N·s mbi%ý“îŸÆU¢‘tSdÚ>#ÕëÈ€¹b;æ|Øøoýµjè@°ºù †ì¤¶=µlZ¹„àV r›Ô0#)#‘Ù,ÖajÉÁV½:)AõƒÕ°ÈíX—²ó^·]½fÿËÅ—HÝ­H4Œ“¥±ÛÎBYlùIû{ÊzùÌ;ŠÔQw¤n•þÆ MÞ;¹ÉW±úXÆ ó¼9V>ÿ,ÝdäÎhúsn<0ÍC´?Û…N ;ý<×á(€|èýa˜¹ÞžY„åFIÏWÛ&Mœz‰›r¹ÄÖZÕˆÿ£±ju ÿYíö‡¾¬QdÀÉ@°ç: ÿ°Rˆ¤„Ðnÿg%Þi¾“êÿçoêûïCú<‚ãaÓg"\qçï`À¿ Î]['ÌFMÙ¸~¿E äzÑǦ0¡ëÊógt‰ËM'x”\% öp‡×`äÒ×)é1ËÓ½óΜÿЪÖðf¤“suö+iκ§vIÔøÿ¤Ñ~_É^‡å%qÖ¼’¿]½»߃—·?”ÕäÀ›/Á/÷û˜¥W,v5¦ê!½D÷‡U¢gݾž¤Ù©ÅVƒ‚ètIJÝh# mF¥¿T¦»¯¼þJ=øN¡{#3ül/%ypù½Hëlßé@$ßI 3AÂõÁ]*^Çe‘=a ÒQškCõ¤âçàl"öÜ(Ðò–%gY^„qãÁÏå(: †{çæl,ªÿê}â·°o Þ“0Ùè ÜQ.ê=ðѤõárŒ6 y»úþÕÌ2㤱© ððBÄHW&ÉQkíOÒCT ÄUÜ* ÍßçL•)'ßK{J'9¿ÉÏ.'èeÐs’¼¬ü_ù›Eëü^¶ë¶ÃñóãH v4Á• †•U»OwÆw4ÈŒh¬•F02}WEú¸f«:aÒcð¶§l¾‹\xÇ»Ô SùB/rü@2ž‹íƒïÑ —›'®TL˜Ž`îøþéõÌÛïk±Ϭ8ÆRø‘kSí–ª¥…ìЦ¶ˆÞŒAãÔ‘…_;œ"—4 Ìø¼ wFâ£boÃ{Sž~ÁuÔ#ÅhÁbݘ»<²¬T¹¡~ªÌZÂw†\nÔ>­%éÏl=‚þ‹-8´òÂ+ç"“ÜO÷‰˜ö!<×Ô¿…÷C=7®±ûC#}M´‹kù˜UmšÞ!—Ÿ¤-QqjÄ®ª|Mztj‘Æ<ÔXÖTëáò>Ÿf±1¨â{“ ÅÅC&÷3ôcž­&U‚‹ž]Ÿü2É·†Àüa •¯ŠÒFµåvÐót÷»Ï] ‰7!:‘Ûa–uçæ’â×h>¢9šŸˆSr•57}#K+ǃ‡gôcÞ‡sgB ·L•œa¯:*ö@—äŪú*ßIŒ‘­¹Þ|MÎv4ºÄ2tKì¶ |wuF¸:íRöì4ª2!ßNoÌ~qµ“ËAøf0aO9 kP-²Ç¿tcr2ëŸ?(K2„/Š xœ”‹N¡ƒ€Ož"^3d¸šµF¯ŠL0šj#þR¢VŸÉsðøvÌí‹9ÀúóÇÅ·à¡ñŠ˜»DÜái¢cô"ê¿%˜³Ý3An`tc÷`rg˜+³æ(\Ž™ýH°n[„Y´ßK‚éÙë5í'‰`n£­ F/'$”¾ }o:r6dÝN#¹4âÖADR–ávßúžFwò’ ãNUb†¿Jè#Ç<Œù†LÕüjk èÐ&·k³_XÛf²Kxª á{ô3m[EÊ È=OÔR¥-P¸Çe·¿ÈÚj±“ÄÙv±¦>£“®ÖÐürè6gž®\HDrŠá›ïôB.ç“ö©ÿ¨(…à«I[p‘ô°½0·gY¸™¤uwj‚æ\ì­n0˜¦Êiy4l[¢[Yt¼­=“îìþè– õq˜`ѶJjê©ÛZˆº õŠ: œq «ÈÖ|S7ò\]ñ5uY.Ú˳—ĈßÃåÌuc×÷uÏNÀ½JElÕ¾a.‚~,ºâÐ3ÝpéÖºÕ’>gÕxVÄM’µ2¼È`e88 ]Ï Î³ÇÑ/ óâš—¹{¼w_ß!®cyè‚§ï»àD{8ÚÕRB7¹ ©JM·›°'çk“UIŸÐÁðêd8W*8+4,¶2o ´5-zçD£í‰õI²×‡)ošÜùºº÷£.?îç{Ÿ“Pcl 3]­wÒà˜7 ázF ›B:ôâóå^Ìì¡/íO~t̯ÂBº£Û7r…é#J¾Ã¯G~ ¥·ªÊ3Nl뫎QŸËf ,«¾’K±q’Û+qw+qE‹ãÖ*G¹.{zmРÈÙ~Úâ¾}ßr“çNäŸÜ•òzÊõéº,X$Ž@¢¡M4Jwh <Çg mŸ!è Ípħ7< w]´™Ú»+C ¦ ~Óä[?’hëY±?Žš6çÁ šï0§;úlƸdùQ;`ÊiÅÏ3ÆÇB{jʳåXT„…IŽ6ט,Âã$Ýu~æ1¶Ã{gq„=í Ù³¼YÔ(Иb™«y5ÞÓê ÇêøvÇÅþÍ3eâVö—:¤ákÁ3;„±:çàé•Êä"¦“j†(j»A:³FðOm¼§Õ)!‘H^w$) –žk=ëa³ö?í•Ì™apxgùÈó¨F<=ùÿ §]#™ô¶ž·yÊkWy7º=Ý2Ír‹dõõ6õ¡ä *õš«èˆ £Vx¤gUÄkzš_ÍbgjåêY'üã‘Írú@ï¢âh”@°`ç;Ë ®xœƒôKhdt¢]ÕfM”ú °€§ŠîÁ,N*>-\ò´{•¢ õxåoQ¼ Ú¼’ËYÕ­¢ âLOFïŽO^…ÉG¼U2Ü¡`üýûst §^ˆ¿P|ôà1Ò}òe]j˜$ f±½ ß)Å(•¡ðn.7·52N±öT«¬žÅYê{ûÙˆ¨Ž†ª7Á³º×È%8ñz}Æ2;ùÑØ¡kШ Ã~ƒÙ°œ‡¬_°:ÛU>u>mq»\~€þ®‰a¥–7(¶ˆàIx6©Å,i‹³Câ§ra€ô„0T¹4aód¦ƒ 6*{’ÀÓ'$­¦…j¸þŽ^—àVÔÓ»ËÖ:Xg\Y.i= aÇo¬ô ú](óhI°jKŽûäÈmBÄÝô{lömç–~Qai-~ CÄ|KiHÛ&˜L³Ðf¾Xï!'X¡ìõó¯/xP’Ánb¦Oc¶ £¬G——kضlí=Â$zäZÞrÎ%€äÎÌÛ,Bª]²R»Bí²PfK`ë§ý ƒ>¨î%X–I¶.¢+<Ë- ·ÃX§7J¹$ä„£¾'¶rœÑL´­µ¿h>u±Uó4Ö§9¦T:ž­:RMq Ífƒë6È:¹b£rü§YG“òÿºwì1Ë@·Û£óò4pB+÷¢ÒÙ7÷|vQ2Eæ nw^fuÍáôœª=XÕóÍtö^×̓ÎÌp­sÙÁ¹C#ŽXøýM]h;ãPj ë°5ñ¶³Ê§–˜RÏ7Pü…Ùoÿ©®Bãè¡ßŠœ  ‡Ù,»8nìn½ý3&`y×±ƒ8 H–lRkg$8ÑŒm&¤ÿ7óqƒ~'s¤•+1í)„.WcC½Òy„è ^¦6™ù[YïÒ4/LåÀ‡4- U»*¤h²sæ)ãâÐÜÿ·€» ;S ŸÊxTò(Œ…±—ôHý$là˜á.£8™ùHV°%öøŽ@Fè8&ªó^0}ŒQÀž!‡âÎ&›¯£7ã7$…Çxs?Ïuø„Où–¯KUìñ‡3Çp;Ï´Wu÷ã½s®]LÃSÛgDºó¿â˜¡«s ®{W>>×úð˜~sÞñkœ±äÁùhtšuO¼î~[|¥ΟkïpùÉFÍÂ*ÜïÎÀƒîO‹¼“›†¨4ÈѲß$w3ž˜âpWðȰtä´»ì“&wâ²Ò2Uþ®•ô÷5OC¸ÙôͲãB™ÐjÛ‡7VcÚjg\ß¡{¬¿§5YÝ EÙr\bzPj««'›½>‡õý_Ïšd;J>fáèsE£aÏH¿ûÐ0‰|i(ÔùÙõ,5˜ƒ–¸ m¬¤ ÑúömŒ¥ú&C–1Û79ØXí«[Ji'\ªæY)¨¶^ûžeé_¾x 0(ãr ‡‰žür^œëÄ>J±î-Éni §X>óåŒb1):Œ Êøº”³ª!Λä+æ"£×Fä²™n‹ œGîkÿØÏíÊÒ³ÖÐ2%É ”ºç—¤;_¡LdL[¤†sñUî'Ç‹xüCyóG}`Cæ•@u1°{Œûö‚™·‘¨ÛG9.A¾_ƒ>@ýQÖÀ=ø¨SÐp¿1ùGõáõ-þÑõ»~ iÐ犕2fc¾®ßÜä_G0L•Ò×¶ŒÝוk«Û¨¸¨úàQ¬s¯C®yú”>D5„B¹ÖXO˜D#ÑLÁ}£ô¨bäA7ôu¬öʔͯ1M¬ÌCÙKô¾3oã/EäïnU¯g»à  gàHµ6÷+>Qåéã—³0îÞˆZ°·Kf[Ѐ!ÙýõÏ9µ½½õ4÷Ÿfz@+Ã3MÄ$O @ñaÒçu¦žZûÅsX'¢]T ÌȃäÈ?ðX0 S?»Ñ­Ô"/ÓÕIW©‡oäðÐÙk/ø]‘÷~Ê&û¯Ñg tø…‘éí†úÉ '’ÌøFîe=ŽÅ‡·XWíî,r.†9kÙ·˜.³OÕA›ÅH6R8¡÷–·Dà`þDºò‘–g{E:T²¦8'ã­aùik"0‹£‹)+£UzàBUöIÇ•Þ/¿aÆ?ýÔX Åíþr{WV#_u]c*×P<%¶'9†ýËC‰Ò|;þàÕôjù¦Pó4¬˜é^9·™puêÂGža]?ÙÊéàÌ¿øöCÙJD» Ò´&"÷%Ô·€øæY•ËPôú׬‡q…#³A¡Ø?C>?ÛƒGV¶ Äy% L+™”ÁÔ‡0 pý@Ê¥ 4;G)=ͦ; IšI[ ±š~6Q0›P@i@ ½¥ÊbˆxR.,n²])¥t ûA5höxÁ¶ T©Ÿâ¹GîG¸þAð‘2¤6Vr Täíqš€‰ôÈØˆMá§g@)|*@âÛ@A¤60ýÊsÏÌt(Ž¥¡€+œ2HQ‘ååkÒµäÚõÒè iZY¤Ñ*JOÁ÷Ë/=fbðs½í>0çüê­¶}öVdj (T©}”y}(Ï)ãKs‘%C!úé2ò*) KWü4ºNÈs†So… Èú)H)(~$ýPn!+›šWtà¨XÞ“„ð›*ƪTAȇú"¡tPTdÇUeHzÜÌÖ®fnjjå¢Pí¡GÓÿÿ¬: 苪H9 áLV"‹¦3Fâ™ypœŸÄè ®)«Q‘кe4%YŠP*<€9µ¥Åp%*(…e7ÞŽ^‘Õ¨­FMfHè±Û‰Z³Ú€|-‰yú×qäl6'ï Hlé ŒÀ@(T!4„…ø(8:d¸:tƒ@‚@Rúé•@çÕÂÜHÙcÙ.„fÓ[5¬I;í°€XA(ÙCø¡Ç–à‡*.F”ˆQàÏÖpš£pîörÜ(t?FD(Ž¢v–B|Öji(ªŠE‚e‹ku÷›µh-Ûþ¯~í£Êz+¶ð ´êDãI_±g%¶ÀÃvjBTµQoWg^«`ñK+yÁ6@ЂÔ5•h&glD«³ó„×u™áŸ_%OG‘ãX % ùÕÄ*ã覉B”cªFÝ PûlIå’€+p ¯D¼'ÐTÔB<›À·þ̆‡uÞ¥, JUZ @V´ÔÁ‚\«,d:ÊáЙ€$²ñyNÔÑ€€r4’¡$HSPz¨RÏVhÛ[‹@¾A굡^À2…Z±a¼fä¯JéÒØ øý÷¾&^ ±JÙ*@9¥±ì=È´z âæfþÄ1?.l Uò;€Ô;©´äP_‰+éËiÅ¿í’YcœN‡;¦¬·¾@×O˜Åý¸'òe»•,ŽŸ÷ÂJ~A±©#Ãv¬AÚä ·VÈÏÀrp»µ1š`#Œ•ÝÁÁ­¤ür¸Wb¼ ZŒ÷,¹¢M‚Šéô\Œ€œmÓÝÀŒ/57ôÎ{Æ« O­ÆÕ¡¹\r¼*åì¨Rî üZКÛT» ™¡3”¯~–Ý3ã/\ƒFdQO*R[8…dpâžå Å&BgM®ðŸgIí‘V­ÃmíéÖIÍÐSÈÞÉt^°Á$ñƒF<&("Ðlgµ®ä9îøÚ;"»TÛ¶%ß[š­.9쎒"I)]æy. baï&ö/±ÍÙÞjv˜ðížBµ ¨ðÒV=ØYëeÊÖØÔopX¼í›Í7KëýD§ÆÌ£  2Wóvl@ôãœü÷¦÷…«Ùð‘¸Õg—ï¾Òp7à×7ú?à߉v]LbýǪ$þß'[EÆ_`S]iƒÚ8c¸f-Zp5þn”/DÝ eÜùrhaU±ìÛcŸ\–k­ö|¨7¡˜ÔzŽA(ü²¸B¨¤Ñý‚íûÚ@ySÀºElÒ'ü9ìn{·Ã¯ È£š»‰­s_x†cÿ¿þ›Ý ÒTL¶•œÓ`¢ùnlõ^Ùx¢ªâ5¸^gDj*ì4Ça€“3!¬‰_ i¨ÃÄY§.ŽqÉñ–­&îã‹mÁB— tœ^Ï–‡ï6pKœ!Sx¤­gwúÆË&49Pžš,0;ö²Òïo¼›;Ó::7w¶½Î*rOw‡[¢Iº’/Îpõe±'6ŒÒ(üµ1iÕ+:Tn4é»·‘Ã×E~N³Á(QwûA6*rì'hx˜Äf-sÌz)ÉŸQŠ0»TÐSóbä)⮪'5Ö²Ê ¶;«N½ñÌÜ|Xà0ï­©Y—Õ0A À/\ßa7ZŒ÷]Õj$v9‡/»–Ë_ðN$™ÙZ†\z£z’¯Y×Ïw4ÁcFëî¢ìÖ.¦CYdk-=ñ×b(.’ý‡WAµŽ×åX™ùzRCª¨¬Ò¨Ïv­´A1pgŒ>Ux´°Õ鱋3q›½Ç$ø"¨ª)¤! 3˜pRäŒðøk9ÛAÁ´UjȆôvšŽdùoäqáðŽ!@"(ERŽR^±`„ó¼œ)¢D‰ÙZ¥KÏÕ­hòïÚma›¬¼Öh"uà_‡Þæ¥Õ¸ûÛÍähý;5œ ž,¬Í𦠬÷ü_ÍÜäo¬Ö…½?ƒçÞâ÷;Öü¦ãª‡¿ÕdmÝis3.Åv¬.«iÇ«™5RCêŒ1§_ÎSŽ…Ý þ {ñ[p ðæÿÐÙ#×3èT1ì–Ÿ¯›†"2K¶,Å*Ùsp¦Áºè!fŸõpZ¹&¶'—m &xE_ }G;§U[ˆ±µ»°ù,rqÆpu…à s>Lñú8>©©U>ŒAð`³¢ºéM×3%(SïÓÌþÏÂÕÕCá´9üŸìYÈ &Ïù§VkÂ^Fñ»L›V1_¢ÿÛvøç*é¢+ôHæh’¥© CË€FÈ¡°v{I.‘©Åä“°µ*Ydd°6Ô r|1ÄÎL,ÁÜÙ¹g!7Õo©sÿë‡;Úó¢,×r˜Ë}í³z¯?ˆ·a÷½ŽJˆê¼":ª–ÁnÍ!)\ð²Æ¬‡SÄ㩃‹?‘óP´›˜1’/8ïÝËI¦æ½/F$-fHè5žfìöísý9ÍN¿û¥±PógiÜ”ž—ÑÙ¹ŠWÂ*4ŒÕ#d2›‘¶ŠGS÷'žcáRÁ «unÏ .±M¦ï }Gtýâ9#ƒ&ï<ŸÇÔ°úFû‰—mOÀô^’xÄÖ2¸rä’ókdtÍ‘¹3ÈfC”“ïîªÊ6íÍç‹E)ÑÝþÏ ÕÕ3êØ9~S‰púgh•µü/Ëxa&ªÔ†ÿùçñpüìxH0ü?éºIaVÄiXÐ3ÙMÆÝƒØR..{«Æ^²2Àw)¬I±ß€VE¸ÛhtŒFïÙú;ä–úLã6•,v©;p¨øf î !ÑRI¾îÐ3¸œdI÷éxêlΉÑaâŒ=yb m¸1vNÎð.}‰•Uò<âÙˇßeÔ'1íy Í÷*Ïa ¹5m)lÒ·¿¶~ZïyÒQ÷ãSí +C‡xæiлJÔéœ7e=[åþé}·wÙLäæñ¿Þs€ cŒúsS9¥¾Oyèy²ˆ1ô¤ðÖóBúAŠžFŸÒ‘ ~õâxµ9]þ¹¬Ž­¯ê¹ h·ÚõY]ÎŒ´žÖÀwÞÙhSõ¼#ë²^æ‚Yú¡p[ÒUz®ó bÖ¯oôNkPú})Èÿï:cw,ÙÌÌèî‘]ÏÞìݸ–-Ñpë©ð4ƒâ˜Î±qqNóºHœ2³ÿôÿ#˜«åIÖˆ ‡’&¹ª=˜(MðlÂ÷%ïó–ÌjóˆxÃø’–µ£ 7Ô‹àŸD ãi¤@^CHÄH¯ä"íŠîÌ'ú.Š“™WÉï,ã}¦W÷O‚::l¸*Å’wêÚ¨{¤#SàSîCÀ›í9úM$gòÌûãÑŒ&³"<¢õ¨^ìˆí¯‚ààQnz*ϽŸ@B3àr“©h{r.+UÌ)õ>ÎéqO À>àî1—ªöE7<îİÿ«·  MÅæú@Ûb÷¡#qïM3ȽÅo'_8&ëïõª/Õ?³Ó4i+—ÝB¡€°YœÊàÌÃàÓ oϬ¥2•ò›õÏBù^ƒö²÷` ˜µ¹^×ݰ»†Û…጑5b7Åž j;2ç‘Ìv¤SW#i9z#0ÔÙÛðÏMÙŠEDKB^TÿÓÖÆ;eèŠA¥òS|œ#Fdìtã9áP¬¾þËxyÛ%—ÁMܼ­ ‰¦Î\|ÁHð.+^n&¯EÈ ,O÷!¤˜\«ç ?,è2‹:q!ùÕB‡8ê°öÿ2Q !Ò€ìóN‚:XócÒ~—³hޏbÊÑûsßÓ×GÀg€@óãS €ÜßçÙTI†ò Á7jK¼WÊ‹ù4ÓVxÛÝ¢9}Î÷±ÙÙ¬ÿgÙÛÙ_u¹©®bÿë^¬Ûä›wØm,Ë‚1˜æ^=âÄÁŽØƒÊóWäÖÚ>Þ”OÒHQ3æ ê›,øR´«pÿ­ÐQ hn(s§aZ)Ï‚E|¡ióΔI„d 'ðP¼Ny˜0þàHúÈ5)ªù$IŸ?µ@.JëüÀEt¶t’ñÏZgÁi«ìÇï•_® Ĺ'óíQóÀ?  ÓF>vj̺œîg8]$5=Ê'q›t=¦ÿFî/¢ì¬ö«… ƒ|ê´ôøÐ¥¯´` ç¼Î𮮬@âÏü˜ÈûL¯Øü]•Ž_á[×¶Êü&µ¿DF©ýóËI„Á nTo©;i&ügq1ÚÖó⸑ÀËWQueµlîÄðIN£mê A&VDülG½2&ZªhöpѶPAÊ}Õ¥EèPŸã=浺™Xà²xM’ôXÑõ{n‚©àùÃÒ1àqvìu™ ˜§},Ú!¤‡Œ‚é¾:ê À»zôc†ê‹è˜ì2üKv¬½A=%AšD­ë8ë1Èðÿ5A ·"JHõ¡ß"ñ}($¥å¦#K–˜E–­1ÐóP®áÈ©ÿ÷B׋MAž " ¥X†1€h‹¿kc£Šǫ̈š´½É&†GƒÃ;6ª:<µ^÷†í©"ZG;Í®jÁ³–iätŽðëë_ó†MVU,؆½u ,âŃ¡xTü“Éäà#†,¸ûEâ§#/s\ošŠ“‰2d+nX"оwå+ö0ÇÈáBå|&…ç{ž0¡d‰§Ä_âËH(±1KÎ|ïe›²¢ËgòDN‹ixQm90×á¼¢SVÍ—ï…êzÊbÕ‘£¥*ˆ-O[ñÿkB ¾b6¼£ “çŒ]aºc eùèbfäc(‘gyëÊž£¸º¶ö4E(Z.ì†âÐ8,4áç«ÁëY–Ÿˆ_\ ÂÊ ·ØcÊÕPZ»üèidF•†ÞSUìÛwšó„¾R1~ì ²O^c](Þ#ÌÚú¬Æ:ë®Ö£ýAà~éŒ[ñ ¯ư¯û:ÃF1æÿ´AÈSRZ>PmUü·tŽLm,["Ž^¯„£N%I+Ó¦«WýÆ]1+7Ì6Â}Òé*`|åC¬`„¥Ùi>î{bÖ•¨yûÕ-[—žÊÍze x–Oš§X¡Óšíì¯øœíÔ×îgÖ²O;jö ì7‘œ–”…ŸºÇ\uútYŒð¦@™µ¤‹H½#úÞg×Ü8*ápñ‚ûfÜ© XG-b‘³%¢¤îåjPõ\S‘öðáÊÔÄÈŽƒ„gœudæù=düÖÉ_\8ÊŸ+ÞÕ0ôó»Iô>cJž¦ÓÀsù#0¯¢¦¬#Bܾ晈ŸyÅbàXT´6¶ f¹zºƒ.¸¹¼®ç{—§\At;"žE-9šh%ÞÃyÉ0N½ìW£äkd=ýè¡yG°‹&ò¢rð’]œ4>ûŒwÊ:ù2ñ$8£ „€ì›Wø2RO¸÷©»ƒ5¾oUd õµ²(Óüq‚JAØRãEy¾Åàþha U ¦ã÷Û ³s` úëa“ÚQ„Vˤžl¸pSËžBå?›‘‡šÿG Ùý>òå™|§¤>•Dð­êá –÷¾M’}³ ¯§e„ö›‡)*üV•×kþÔ_ç3ÏÇÿØ\Ò— /âÔc(~ÁGëÝ«éÿPoÑÉ:s™AÍûËÛ¯û-"SN+ü';ØévÕï{Ñò:ó¤¢2•cW¼¢~ }d¼W™¦Ø‘oåÓMÚÃ,cÓoXqÁmò€TŽs:”ÓÛ~ ÖxÄQÂ6:áL˜:þ®Ã—÷Î#7žTªFƒÓj¸úÇ´q¥àže×O=Y§§aÜú®î²RÌÿí!,ë1»]êEF¸–-Ç×7Ó­N¿aõÁË5±›·}ˆZþze90G¡ž Ñfœ…×¶˜iÏþ?: ʾ3#Ζ"#2¥ºŒÀ2‡ˆêò¹µN¹Á Ó˜ª˜×šo‰ëx?ÿÓàŠÍâ¢÷iαþt‹ v5•8MŒð5°úî}sÈqc…¥¤Æ wclŸ«hÙž?æ‡Ïiߺ¹¾R^Œðôÿ<.÷]5ßÅNÉÖø¶w…Lû0^$žÛø4Ôh>^¸÷ˆåÍ7dæg|;–.v·7ÆôÞ>ÿ~“‹m‹2„½…Ã4À1ÒÖ¼!þ”®g¾{LFGwö%†E$oh×µm•M~«5|ª ×ɶ_ Ah¸ñÉ܇7Óz•Ï®å± EX„«ÓW97o×Ü¢ ¹åüäLúšÿfîý9Ù𧣜‰x!Ír’yÒÿœ"*¿‰ðEùsמ5MJ¿Näfd )Úëk eàJ†lz­’ç”RGkÔ= ™Ï"VEë¼y7õ^§vöxkRkhKY§á*™û= HÌêH0üç‚úbG îºuCM€ÉÝŸÃc¸Ô|<õ'ŠSÂÐåï7P­¸?òÓoøÞa}ï)ÐêwPªôq$´{êFÓÆS<ò‡zþȼûp·u‡òõš,Ÿ”#ó,ñóè°5û #‡Ýú%g€É!né3™ÿqÜ‘&ÈÁc<ù±ó!ËçØd‹ c²Ùùë§QEí=Ðèóýè†þày¨ª\¦»6¼œF¬§êá qOmJHàCÜúR¬¥ÐRn-'fä½n0Yp¹Ñÿ[ ËôÃÛot).ÃË«¯õqÓ¾l;_“H*ÿh´~!sO>ð–h_þoÑ4r^hì+…¼ z2ÝW>´uº89WÛ8Ä"ï”okqYª¼T=Ï*«£û¥¹þ£òè23üu(ÒÖ8kÿGã2DG3eð˜E{‰Y¸ºã$E @Ò£n!m½b̬®»~’r’;}ÿ¦„s¾U¿ÿä*ª¸œ3;íwÍœa8À>|?8s pøÞf:ñtYÃ`ß™ÉɈꞒi¨‹Œ•:Ê—˜¢L2ÉL—¬Jm‰–V”¬ZÕdUë¦ÚüµÑÆ_)™J½gôž û •Í]ýÞýÿ÷çœÜ–I–³d#ãÖx´‰‰G+i0ZÕ!Q鯛ª±|ØL#ßîO7yç5Θ ¥°Mm¡ý‘m—Â3_„}é @)‘éŸ(¡RÈ€ñ°`ŽŠã¦@Rú“´í}Ê»¾¶]SüOÆ¢${7ö’íºÉðN¸SüŠÍ›M,%é*Àô&sßàÜ‚»GL¡EÔìM¼&†ýaÏ?³ç7 Í¦ë6&âôJ@?%”ÃÄÓÿnñ}}ÿÆoóBw›z[ÿÕì{~úï®&pb¾gfØÚ&îwfý;ÌÏGöö3S­;¿æ¯]aJö‰3³*>(b£’|L’ýïXЦl0K¡}˜ˆôµå}(‘ESÁÁâDÀô9?O£:z$ô`2Å`Á)¯õ^G8`RpÆ)D(E°ûèé;K¸}îÝ.éÆ` ø¾É‘LÛ«þ¶]bD'(:úåôxMb^/R"€Bá`˜" 8a ¥5°ÇwÒE_¿q'Äþ1Àº ±©§‹Åô%V:D¼³Ž€Ò){Ϫ¤Ö!Œ˜JÄÿöv,Bõ¥‹Ûš…í…ú–ý:ÔÄ ×ÛÅgMMDm ‡mìÍлÖÄlóïhE‰žˆ‚ç_Ñ6!‘"CºëX †ˆž1¥ ˜ˆRd‰QHRÇc!Ÿ{,Ô %|é131-ò¨…X â³…nw£),,ÁD1c¤‚ŠÈ1õŽÒ:` ʈ0%B“ºSU‘j”Ë‘âÜf‡U ?Ë=°£±×íÛT€ë=ÇFMH­…Ä‚…$’–E¡¢4B€[©‚NŽË(ÕÅ$lŽ$bjÿ=¼Î¿¢YïûJ,™{ìÚ„ç¤@@D)F™£ˆBþå±¶a1—aв ¹X1};ó7ßùòÓ1f˜£ùÄ|#ŒAMüîNr™NvJa†X‹kîIèÂ(€;-[+!*¶Uhûß™ˆzÓk`ù&ÄççøL¡ž*)Ÿ›Rk1‚dJr•IOˆQ"c}ê·ûÜ\E”?á^ñ·ŽìiÔzv3XjNÆut~àÝ–ÂJ[oƤ /›<ÑÑ·#˜ë#pi)3P’1¦(¡˜Gërn׉w­bÍÇŽ’ K†{âNCœŒä ßË‘ÅçÿÙc€->½u²®D7ó¤Z$uBÿIî„§/1—±{4'Uú2`wo¤.¯D¬`mô–÷ù¸—B= øÏ#ìá_-.ýڛÚ<0:[7Z·@ò)rí‹ÄEܱû¨>R'¦ÝU5#2!µ^Å(ée5³Û¦ aOòj=¸_ñãìÕ^À¾Æ%Ø–x7»ü/ÝB`ÐÔS˜ðï™R™±‡—Y Ä›øgÞ*~PwÚÅH±»ò~†–+_t1 å}VE@ðZžK›é9èöÓÓºËͬ¿:?%ŠC9o;› ιºAv…×Z`QÄ·Ö ¸ Ïè¶±)½ô–Œ»¸ÈïB ÈP¦01| U)sK án“Åþàá„oRÛ4 ü s¸ ­o½š¡è}ÃGÓ{ßF†÷Ôß›ZMTҪ½‹a+Ÿ ‚Ñ ¤FgHò2FøFo°eq‘Ÿ!V›¥…™À‹Ÿa…} Ω°þ‡Ð ƒí*_~›Ø£—Imòü¬°èñ|„)ˆÃ™¡>C³$·=,Ýô ‰1´«öb ± ¬Øß5—X8ºe+í¦Þ×ãEc7 )¾Ë^©fbGþg2=RÈ êxƒ±Û[wê¿n1Bë Ì|¯³[.ƒƒ+áqo¨‚VMÚƒôuh –‡‡¢€ºU£çébª0–1 WÉÀ}³Ü\ÓÂdgä?Ï.6²¾Ê\_m9Ãæà^ˆ¼Lܱ!&B{.z¾a¸|[4>¢¶¿å×E ø¾ ×&«¦d,ŒK àmý ÔøXWª¤¼#Œè†¢4Q5„.Ë€fc綸 >¯ÏŰ$(' Ì€ k8!¼Y vò…_וPxMX›ƒÕPr>åBÒÐcËæ¤£j ÈÚÏNi` $ºÉÿÄ!p}ìµga¦ƒ ¶ôͬ¾Ÿ¡“#ž°Tø‰Dïµu€ÿ¸^Ý{’nWhÜ…;ãJ| zQÆgTã:ÙÝšBØëc ¶Ù}k«É~·™™RÌ”â=€J³™Q¦G'Æï¬¢C-¤g³e]“„í:ÈëPY¹o±G]1þÍL\ØbøDKfeU.)îÒ$>‘;¯œ˜ÕV€œt!Bé7ôŽbÅåÚº\Úê {Zìq2ö£TØFñðSÓÁcÔ·dç„£À½øú¯´6ÆŒb„îå«Ï: ~`¢þFð¾4·Ç ÂcO<í͉šI$Å“=”ø+0KR76çà&Ìfë5]âV.é>„”í§Jp”|mnaÜâ®>·ÎÍ¥$^½·+Ãv­š$ øéE"õkWÒ—·¼)Qì\Ûéó±ûCwN¸î;ÏÓ ]¤£Äwºv™às§FQMÌ0B·~m¡‰S<¤J "†µT,¡¼œÐn!¯]&BCÓ„ÝÄ\Ë2‰ÌÝTç‡ûº(ÔÈ>Óh ÊÌÏèÛÉo+^PqÒqÆð 7Y˜ ÓOª®±­ìA ®Ð±Ïp-ò.Røƒ(K àQ1 5KÁ‰ó…}Iÿ*'Wavjå‡ÌÙñ…yÒŠßÒ[¸ë‘ƒ h^†°~˜_®ê°6ÎQ®Q|êè^£é‡*&pn-”öK¶ç`hòò‘zTœAÚC™äížãÖ%× Ha4Tõ!â3]Z-¹÷‹aE¶Ôîf±,†j 5^P·VJëW.‚fÊn¯Ñ–‘+k„®Qöw\å´!€?ë76Úc<¦=k¿¹‚wÓq7«¸…͹gÚ¦çj»È››ßMTªú>ŒÃ£Ý!_õ®Nrœôšj oA×Üæ4FIÉÌß} i\% }tÏ;qÄ¥{uBpÊÍá]ê4°B23,ê·*¦¶Võœ0í%¾;I»ä§s(mýíj[¹û×ú.óÓ#!³dMª‡Õk í¿Ô¹ý¥³±ùÇÂxÜö‚¾€û`NÀ@fîdø0•úS RèÚ7©GJœ×W£Öus Ì:š´ïZѳ¶!,GÇF¦é3ð*ë²ßIu@üP‚KÄâ.‡‘ãD:säÿÚ² Úåý‰vÙþGA ¹€´\¸B:rñt*»V°Q0qˆÁŒ‰gs‘Ù3°EÌœ?³=‡Ù)Â\‚1;£ô~BŠka´o5šlߨ« 5û0`fE¿Í_ÆèJhªÉI›Œm申°`ÿÈl¿qå2!¶wÏ4EÅØWÜR½þÛ|ý!]É`G¤î "„i²¦‡¤œUøŒÆÕ@ô¿°“Ö‰+A ›Œî3b†/OüÎ[BVHUºñ|_|fñÜŒQã}k®mûo´6‹ùnî¥& &Ðx¼3;ÅÒûÚZ2ß81ÂÌÈH©„¹Ö“‘[ÏÛ‚éYœ-¹.Ü I¨¦Âjhæ‹4&Wï£ HRºŸ„ dãŠgδ¯M±ÍƒCíºæÙvd!Q(ÖÒžãˆô ŸÞHn“yp@íd+ç »sŒ–{ˆ4Ax11Åõ¥ä®ÈB’®\:{l6?ÝôÉX#BÌœéjñe<Å b×Ù–»³îîÙO¯‘cË…x«FÉÝ9bžC´ Y¤–&ÏDNOqltGtc ÈK«ÅÁdóŽ ‘ú“c«Ž‰bõ?ÙáÒ•_øÆùñ6– ͇Òìµ")9ÒF„ypÜ0¤ç¹ÑC(‰,«fßœf½\@ð^YŨ\ù¼Ál@ží÷aÌî’·0ñˆAEµešyõó©3=sN¼…“*TÈû|þ6 M‚ÒA /ƒ«‹RÒØ§jˆÈÊéi]m‡Ð++'\ÄЦ±³·K!õÐsé‘Ôœé·`Ìx¡œ@j&‡d¡Öß®7ˆ7’dN¢*ÈÜ áÁ7Ä¿îHdH¶dÔÿq)ÁE¹Ô¶¾²ú•„An¢ê:h 0çoª.iÁ?R·1¡Ë…€Â¤änø¶‰ÌBöÇyÙÁŽŽ&3ø©ÒdŠ ÝdÆ>Ýx~WäPËx-h÷͘áLcÞºEŽäÎê¼N–¼«Î9?‹Œ\æ¶š§:¢¦×ÄàD™yv«Jä¾LË›ànúI½M÷¹<Å~öTq2k7 Ñsõò>Ài{HÔHŽf  ½!H’ËC"groži¡’I:Éš Ê]Anƒò5ÈŸéõ•žÉIÜÊnX¶\KŠƒ£0;J‘ž·Yz„À×)ºÉ¢ BV /ŒFë'3T¦³œÑa÷øP¢º·þ1,ð»æ¡ˆ?;3üƒéb¦ë#—áw{’žD"ÄôøB»½)›õñ’ÿ-Á¨)ÑÑÔð^ûüÞçIÓ­™ØoÉྞutêðôf¼Y–öü£pIeA-ä°Kŵ–—VöµðÔxq则ª` hÁù7ôg=±JAžôkaÍn°Æ–‚à­Tf‡V68Äw+‚IhÌ|•\˜n´é¢ûmÒ®ñžØ.6ªr2µ ÷c!,/p€À3å"HÆ;æ¹6’q¥Béô@±"÷“iÎmS“ûzzÃw5Ï,†¦ˆ M­ò¤©Vq¼ÜצK²‰¶Ê«|ùÜê MCK—©^©ëºìôA4É0Å|Í®Ü×¥z?ó§;%Ÿ›(GÀ4 ‹ñ¼Í–uþèîÀI’¥w®Á‰¬ç Ùñ²ôø¯!çm»0ÏïÇÈ;.npܱ%.;_žÀ°ç/lyîä‡Ïûá½ß',, =ê[µwVOÚ”ßTf˺V“Õ½Å(=æØÎ¡µÝ i1.º>edΟ<õÉ(.µžä,qÄD¿Ü¦üÏúcÏšè£ÒÎÝã<ÖIQ‡ œ ÖÏ/,>Z*bÁR·šÒ–TTˆ4½ŸÄ.—yYÊCoX.ráÑþKô|&sˆá“¢ýwó=¤>îv§ñ•.È®(Ä·½JÊ`ÁåupÆoŒŽ¯8><‹5U¹£¬§§ˆJøÑÑÅ•s)Ë%ctð3¤~E?¦(XÛ¸e#8ÑÑ\B]ªo²—¸³¢£@^üµ™Ì•ÌøÌ'㔈-¡†c³'wý’e»æÞ ¬üÜf‘ÒÂS&sFÂÕ }§² Zµ¨-LqîdÂ4ŒºP:’z;9‚†Ò¸l 9^EÆbÞÇçX ¸Æ<ÉööT¯J0`Ï:CÈ"á¡H¬—)Οðˆt§$MRÒOÉç'Aœ†vL+® …t9)õ=o§±ZPråé«UèøM1ï"”R)TÉÆD¶ÖÜ8®JÝpŒ±á欋¾tH(\ð3ÚIÙÅLÇþdu”NÝoÉ/§©ô9“ZbÒ#=HæÃâEÊ>õžàшQ;)…aC²Ùx÷1%˜ÃUçÂæb#mÓ¾6ÏŽ÷Ìlm•X%0_ýa¯tªgܱ?ïB»6ïK–,e 0R¥/0¥N¢r™™ß9›ª‘àDà’Ã?‘ÌI×XÎò{“ÍðÓãå%…1'WE ’Z»S3Öù8€ Eªçßü9ž7ùíTr¡ÏŸ4¤ ‚¡©Z§uêk+â{Þ'´-@t|VÿÔf5EyFG­i8ãt;)2óìø”úË>B籟³Ë8ò{—‹cWuÍÕ E½ï’½<·8FÙÕÂ*„úÜohí´¾Âº*Ä—.êÖ¬5Qg”µ‡ïÕNZ'àW”ÐZ>Ì^0:Ó•)µ¡ËS*ÐUP‹€âq?„f¼Ö/ Ñ‚rŽÛ'j °’L*Í"¹fV! ¿ƒjùŸ<›3"i³‡Qɰ©Õ¸zð³؇ËÔ´^€dö¢ØÏçF+]ñGꀵÏmçÒH!è˘— üUÝß^ªÉík¼8PM:U:9r~ù©¯Ê*b3V«ñeØŽ œÕ;›]tðÓ¦jQ°¡õ)þìX:’¬/yÆÀ0ñÖ’ÒûX[/òRÁJâeTUÒDØå|55äêìb)¿÷É÷%2Á'Hœ’>Žð;VLZÀ“)eä‹”ÉõËðáD>Ä-ê(“ý¹ÔoÅn%c4CÀ$òúªG¹Ô¯K[ oª–ÃPoÐRþŠYàw Ð?àž¢Ô-¾S°¸pZ_@.ë°©¯p³9Æ *;ݽ-ÃÄßè°5l^›ÖG¬dq—Ћ'àe®*1Å ;{åÏ­Ùé‚´m*†m:ŽeúåŸÝÝ.vÁ[åRºÌð˜—-Þùï¦ãy¯‚6Û‰n§ö·íb–<ÎÏyT°Ê¾~ §™&µ¯ÇÁ´RȃÑV|뜩Bï‡Så?”|Þ°†b)Ì»òð‚ë÷±ÉÐgʳû —Ai´#˜ËT­ä™ê»€ú…'¯ú8ƒi¼ð))/¼ÔÌ·¢¤K_–>ú‰ôËÖ|¹2Z©fj_ÓFŽg4Rþó¦Ü*­¶§û˜&ì°‘I¯5®•v¶£¿†£ëõ"&’Jî×j®Ò->Ë€JÊûä›\»ÿ7Î Íi¡;Ý(ƒn\ž[ÆæK9qó]ßCºÝš”á¥FŽ (wº¸Í÷‹ãXDCó=•KGg¡ç#|ú07P=¡ú6SîD´Ü ¨ñ¼ë*`-×Àc´¯¦ûo+»~ÿþÏêŒpÛ!q!/ME–cS^jcÐÙÁ ¥tÁ™´îãïØš%F©mÆ©–8ÝÞõxNþrK§ñ“¸ÆO<,Ž ¬EDuhÛø#à»ÝÑbLyëHkPëbi ×;ƒt‹Þˆ&Ô–ê…N`^%þËÂ}^×»{ÄéÏ1æ`€òZ݉Ru.+ŽÞ…JÍë>Ùt³oC´b0)¯;äê‹•öls¢Œ¾ÅSáæ +.ùâdoÈ’åðnêø[ª&„ðÖ¯Êúô“Îï;HÝÖC¥$î:~óÚa•‚}ü‡°-ýÁxž·FiF-1j@0–] +hTf8ƒN»º£^r‹F”LqS”YG缉dfI¾Öõ´GR$5ïmu‡”SÛÉ£"èíÕQߞʤa¿ÿ¬#zšÃÙ~#$N ³·7Z¿ˆÐ©>µ_^ ÐBâ-}ôfÇñ\éá=«vxÔ‘Õù É›µRC &¹R†¬&‡65©•¨k¾]ö~䳬çÈâ·Ÿtq|”åY¼Õ4'`Wµp)Ž|¬kqUü#}äÊSÉíd£f‹_Ñ&¸É9øða:®5¨|5"þ8· Õ/„Q8*³™µ¹wyÎõ8üî.²æüBB ål5µ«–ÓUï Ü^=«í¢^¾QˆœìUh¸sﯴðÅ)U³š=Ø«í ý–Ñ ÿRÞî5°6¼ŠtåÅ 14 i%í/›šÂÅþ9íE‹Ñ Ä š€uà‰°åÞEÉ™Í>w€‹1¤ó~QkÎè{M¸j¡¿þKuì3Ü lŽ{¨ðQÏü¥Ñ¦x`ÂÒ:XÀ iG¹®ž®ŒÍËÜ®÷ÐÊ„?µP~RƒS^ ,½{oP%&‡èawh1¾‚pöÚ–”³¡Ù@¼û˜Í᪟aó1é^>3/Ñ÷6C“žÍÕl5_X~0*VppåŠ.I[oêÐyGÃPÐZa"5ÁáÌóbê…6d0«Ã€Õ̺“øù[( TC¡˜H“ÑýN!]6 ³ š<½aryŠØ<S·¿Òsu•G݆Éâ1„=QÒAOP¬u­ÑÆÌ 9&kÓG7ÚÔÊ-náSžñ¨Õ4RAHëU©a=¹¶ƒê¬Î±†>…7á-8R½¹àžƒ2‡Ë^0쫬æÞŒ‚wàÜRK‚·&18ªÙúÂ;‡ÿêMîÿðO©Y0Ø!yy}ñ;áP² ›(Æþ/l2ÝZä@&ÁQ7 É¡@Ä„P¢h¸³Ðu§‰ €Ó5Ò@þß׫ìû÷A†IöoŸTÒ”tƒµnu@B“¾PpRH¼É‡šA´ÙËöoöí ­v ƒoÃõ`ìDZŋMÇä"àû¬û/O'Ûò÷½ ïL$–üg`*Hîöˆo½MØK)õ;ü¿Tªžz~¯« D75*ø@_jÇõîS3y6Mv¦Ü±¡Ù±ò›Ý¨T«ÌhEÕÛ®)~‰¾'18 $Ü»µ—o×M†w˜âT”iÞob(IPÁW.°½¸eq$„ÀÊD=ÞTkÂØÏöl3~óÚ|ºbbh D à§›ª¿þ¹Å÷õÿ½Í ÝoêoýMT³ïúé½»šÀ‰ùŸ™ck™¸Ü™÷ï3?ÙMØÌL·îýš½v†)Ú'ÌÌP¨ú ‰Jò3Iö¿a)™²Tb2¢1¾²¼%¸¨e-•«ôP?À£9zOú:àéÉ ƒ§O¼=Öyà€KÁ¥¦>+³˜¾·ôÛîÞæ’` Û๰™O“Ùu"ÀŽþ9½ž@“×Kš°¡}mnüÕLj ©×Ù°Š®YHGŠi @çÒÏ yEk¥L,â,@uT%´š´XôÏöu–ñö„²Æ8|Ø}ÁÑÇéŠÕ[3&2ŽÛ”š1@ÐC¤¨ ±½®PÙïÿ8, {AbsØŸLãBx¾J$!^2u¹­¹r«ËR ÄÑ›ø”ò ñjšS+”PafLJ*ÄrÌbãáp`a åǨîÔEý#³•½ ’­%õ»6¹¡ˆsT²Ú >êRÕ¢I! 6føj’X/ƒ1ŠþgH§E%vñ|¡ ÁPÛÜ6L‚LÛkðŒ ×"%²ï!Gï[ÄÅ>(H/Äó-ª÷µ¢ü«çܲ™«I}ެÈrè”ÞkÛ‹™û¥÷m!½3C{ìzI}9dG(ݵg(_ìÒR÷w±bþa€ÿ¬÷Ô«êO—V@T†k¤^)`¢0r7‚úÉÉ×!ìÄæKý :ñ8Å© GÖ_›.4ÓÄ¥ŸGI³*š13g_/1åæša”Œï*»o\cN¿$v”›oQÃ.·Õ¬ºøÎDxlÌì×›¬§0Ðà–KK³_¢54nŸ_•5¸x½pŽ‘ŒóÉ…§WnâD¥f?Á°~‚*­æ·zrNK 7bDÜÒ€z-¹ʤ(ª…¿úfÛ@>Ç«ûmÚÐðé¶6úêù·…^Kî”põT €è5[m^[½Ò¿™;eÞ„˜¡;é5œŽ–[‰Ì=°.¬]uï«F# æZ<>dŠ*M`eR(Œ†RLÍãAMF8d2Gºx¢ duõì%„LQ¦Y-»¤ƒE2t» ÿIM´Xˆ.ªF׃¦Ô(ñÜŽñi)ID¹!D«’½÷è½âC²¾ÇJ˜tóç§ÿ/†Ã±p‡ü¥¤q¹\]VrÕ£O•ãcC]ÔÊ;ù‰>Š—E¾Ý Ù(ù·¶ñ?Ó¥-uXË Cp¡ÿŽÿ'÷Ýìß7V·Þî¡‚ÿð´3æy¹°ÛFOU¾µ¾ð)ó‚žÐ£…U÷‘øàP3áÉt1n'¡³ài‹cAžS‰õ “Ã4‰ Ù=’©C;¤DU ¸ ¬Í¾/²n^÷ ÷9‚P§Àâ¼ÿ3AŸV?äbÞó¡Æ7@£D³æUíx_aútu%âÕd„{jãªê¾]6Ê!Q§BûJ5<»W´ÓÍ'Óyšâ†ûÙ÷Om¹OªhØëe¯ÒOh¸(¢É‚È(:‘˜|‹ÅàÝ7±“+ÕÛ0æÉܺC}‡šàÅbqÇæÑéЪc6ú{$jáØÇ$àåš JžââzX,ë\5ÿïM›"0ÍrOŸˆû¼â­xňXÈÖs/ügFÛ¹äÿ°Áê 3k,«ü”î×Qol–“vY'0SuÐõ€¤=—ëF+)ƒê=ç•`ïMv `b5¾Ä!õ³ã0ˆÿA,ŽÚ5ºÈZJ*&Îã¸H5GZ¿•ÅS-h1ûþí粑Ìn"ÖNõÅ0ÕŸòˆ±¢‚˜Õ‹ºB)«„÷MLÍ}ùaÄ{jq˹¬•ÔÙÀ"&faÓÒ yº›Q‰"÷Lx¼SÉ¢ßLÆ6ÜqSÔš/'_5ãTì”èh«—È–A•C³¤”ÉA CYSÉ™,Ç Mâ¦!®XûdºE¤ÜWµ=åKftZ~2åf ÍùvSùñ³E‡¡¶H6 ˆ é^13^u×ÖK¹Ó!·ZqötŠ&Þõª`ƒhTù˜õÒ®ûc‰Ž‡Ë¹Ž»së#Ñïý,êµ€}ë _â ªƒÂÐõcw‰Kä'ã,FüßHÀà¡Õr]+«Ó±H±%^sø—š¨ò¨‰ šÙÆ+M:’ ((´o£­*“ R“¿%>Ô[?LFµCYüŸX!?‡´²@)u†L´L=?%k!+ ¡?7 Uäš]ÚW^‚+g¢S@l“ –8?¯ŸNë-Kb¤È2?Ýoî-ÏýIÜc¯öÔ?&&ôô»?ÿë|ðèÿM×þŸí?Èô·›»¾~ø¿žz(ýúáÂ5MM{Ì× `Aù½žÐºÌ'¡9l|‰B¨…A“#¯'éà%¯žØ¿7W,–‰ö[ù2Ãx~È=lª©ÅxÜò©½r‰»X¸¡J½Po™ä>YÒVó’=ºîåË%A.ÀÎ2.x‘IvuyKhƒ*a¶V¨E—=U[Vì¨_¡À&Ÿipírºt­£Ý½ss3ÖèSº'3+1R$<‘²s"yb’ݨž“Ñ0¼Ù•A¼Dl#cì2Š#8]·˜Z˜Rvõ‡ûìP¸½LäÅ?&%ö—ÆZ«ekŸ8pÿÍΚ»-¤äÅ?v¶¨åJè».+²!^c},zCvùäGf"¢û ˜ý!äŒv‘÷Ò^ d+¶ ¸:ûÅV߯‰ý]ÍÍòe<'ˆZ½«Ô숺 r®0D´„?L÷ V¼ìY'±ê€æŸŸœN ¡šB­¶/òìêY6RÏZÒà…ó޲gÌ<_‡?º€ð_¯6ÖÈŒtC0“IÝΡËå‹Ôà©;)U¡h_ úíÃ9¤Á©[Éw¬m½»§Á´œæUÃm ƒŠ‘¬ø@áÃ#状¢/¬Á´°t8¸b XØãÙóŠÆøp‘³âÇð:,$ `¯«÷ñ¶C•à ´Ç³É¤ô¸'uÜÄ¡h9£REG‡:`p`â½:„hÔö.)ªÚüI$lÝ?ásí’UVQ½^g®IFÁ^°Í‡ÕYu:Cœy‘vraºR{ ¯ÔM†—8òÝ]?È@+F×8"úbá­0}“©­Áº”ŽçÓ(À;w©lJUÈ 8LØ À#ެµè¤ƒÕÅbJ‹8x l}1ê̱`žu¹ˆ”œòæ-Ñ‹"ëÖ̳80ýWEÁ0œú&C¯gââÚà+‚è:Ñ9µž…ù×m<};rÒD®SCðJg哨Õ%®ï¸Jh| q%¯L»·Ãtì…–òƒµBT¥ó8ßùÎÉ$ϽÓšOã¨>YC…6è-'rT“Pêƒìúgc.ã ¡Ò1š3ÙòË’úò¶M6q#«uàþòC€Eà1NkâóöUÒSò–‘_¥¥ä-¸EFçéýžJ¼,]hôåM•É~L5ÐvØïÝÄZG"„òáC¼î1 ø§=·E™7̇µ¤A’•†AÒ€¬.[ûµœM)Õ›-dyúLx)_¢ p_Öü[KÈAî O„™<Ñ<œâ.Ûqq»on¸:uuYuU)z«B¥¼a„%gŽÑ[¬YØvuÜ3ªÌ™ìŒÍŸ.cdpeÏFÄl¤WZÔÀR"<™q.è“ýw EëâN×_U–FÎs}óo׬_КqkhÆ\Ñ- w˜¯Ücew·½}ì°QUnªeó¿(EehàÐ'·õ<¯½×T{\¥§P™½RuÔ!µ£ï¶ ÆXG¥lT"å´¯ í³”Ùòm¼”,â÷1·Q6m~a§šöD†[bó¨S× þ¥«Q·(’ÙÇUåþã(²åêV3z®ùY+ÜÆo»J/žKÀ‘rt±Ä­ŸG>ÑiÛ0 ÍÃ'7¾´™>$ù|LÚ¿ñÊ1šß?7»©Å«b!³£`8@U"Ù)ÇÉg•¹ ûŽXèE;{n!‰¥ UQ·Õp4}7CcM·È®ûŒ ®¬œ 7vüC§Ža»ZçV,8B¯PQ¡­vcÜúzðì-&ˆï¥ÏÊþeÂS61z»WÑ|ÛhaƆkˆ2ôýÞ,TÁö¦¯ 8b˜ç¹èªŽQ¼÷c~&¥å0ûHV©ÇBRbˆ²P¾úŒîò ÙtRcί1‚?‰xjÆgòl)ñ´Ù •K€"-Àx´Ô;÷`kór,,v‰J’Òx$}·fã«t¿ì ¥SÑt 1C™¸²„cí¾ÅÙ—Þ6ƒë($>ý¶®)(ç¤>¶h%ïµ* ë’ö™~œ ò,Lñ©pŸE%¬Z•¬/VïSš÷ÔG&V·AW€µ\„›Hæë—ýòÉBû8›‡蜌ŒÕ~,䄾f¾D5ºÖ#Rãâȉ™Ñ*w®ÖêðîÒiGVê¡×îXÕ‚>4«##KIèí?™§ÅöЙÿ„”Îvœó_:#²éõÖë«9IìÑe(¿Å©bp þòü°¼ƒà ºryf8¦kǨJ7¿™ûä<Í«…Ú¹}ëªäsÑ,õl=hüjGÛ7ü’Ìweòpx‹ÈjÁ"1Ù70¿kØÑÏ-l!Ÿãï½Di¡Î…6›¡h£qþŒi|,pÄXŸL |»åâö] 5K¢y©¬5½…Ìòšª½ÙÓKfËÅÒN¢ã(V%T-žÑGãA†7ˆÈŽÏE½x!… L&¯–)lÊ=—¾šòí@1GúÎ…!k*µ@è™m+ŒÔ‡’Þl>iƒa‘¿%"ÿâðE Ÿ7ow0à|Ø‚kÍÁ†Ô•föUe¡XVfÌò枦#aaœHÞ™±ÈNÂß*ò#ð0M'Œ)ä'_en«÷F²õ…+q·"§XùŠbÎìôd t$öXdœ•[”ðÒâ’ˆ_‹ lDv¾Ô)ØÂ4oЖWFѤŒýà.2T¤¢CWÒ¶7&ØFøž‹”ýýNÃÉŠv9õ¥W_ÖøÜÃG,½BeSÃüûÕfjµ¥ÿÐ`nöõ{¤Œ¿î’9rW˜qx¯á¬s 3œ›h™ª/‘9wñGÆ4Bh‘þdÙ‚¼hIF©O73U£eŽ.¥>v‹9çL¹1çG1wë³ÌŠ%ÆYg„‚š•êƒÆ_çdp~‰u-ŽþƒMÐü¼RrJR5¶o èx*«¾ ®Fä$¢7ì8ÇÁZ[,m‚(\g¡ñOåD"^ˈõl¢Ð˜£—/LgjSD4›¸I­aH0"ÊÔJ‚äÅ©!Ç=ÉrO~í#vA‡Q|ÂÒw¯Ô«ìwm§aºð’šZ9UW¥ˆ^ñ»K;í¹ãÌ’¬t¡–é·%ÉâþЀgÿf +6C†’û)¾ê9yž·þµ“©g³ò"œÒN‘»¬Ð :6€µùL ‹EÔõ}‰lƒg¿¤¸Ž›–‡<ÎÊ~˜ùO£•Äóåm?…`I_áQ”D‚^Ÿ®å»-r²œÓ)ÕEÚu_…À½3ôù@eˆLà̵ðü·ç·ì÷K—¦6±¹Ò*ÍÝÑÈV ’:ÅÊÖ±}#zçŠ-V¨Fgñã´Ö¾ Åúè“ÞÕÑóuæ`Õcœ}ƒäêm ”y(LS4!š¨…U ùÜÿɱ Egä¬+Œ=É®xœçŽ,jÐ!öqô(™Ð‚§A201(›é–ÅÁUW¤`CÛøôj§iåéd¹9|3çøœ©ÂÖ¡£‡_v:xòm'Jz[vþÕhë¯`lœ/}í¢œòQ‡êKš…?þÅ…¾'ï0Þ^Ôqy ·–h„ΖÍz¯ß‰Ód«£\Ê Bǘ͑öÓ2`.«¥>¤í–õnº*µ¤ªv.µ¦8Ù¬˜Ù’Ä!¡ÁP'ÝuCQ8$éATC7×-À£c9¢DsPÅYhËWÖo;¼f<=›yˆù SµU›ñzµ2Å7zew:nkËî‘|€Òà‘*Á¾rR|$Bý@ú††>Ê‘žGËÙúû+®øË3sÔJ8ë§%&…éáó‡±ix–9ãÊà¯<ÅÉÒÙ!§¬]ë2Û,Ÿ‚¢ ooªiRƒ´Ù@”§«%|–™ãõ÷Äo0Jf^­Þf÷ûóGgÞÏC±÷>Þ#b4Ä2F¶^a)Àâ§‘‘’µóÂ*–:ñDÙî^ å*î¬Í—Å£ïú’­5îCáñ<ÁÉ„$´pNßM>›4~y.äiú(¬[ÝÝÛ©Z¦ ¹Ëð+›Gžë“@d®Ô ZUÌg©—«Eè³xRÿ!ã®?ž¢œûàñœþÿ9#`y5iêrMT,ü¥ðÀ­¾Ý¹˜eS‡zz¥q 'ÖŒN7ïxM­E¬lQ¿5¿}hŒ®.†ž­µ4Ûo£íýÿTRüeD–¿,Åo>Rš°JVCYç£#ÃýY±.C°¨¶×µó’øÊ=CaRÚé¿y‚w”R”9^%$lΓÒíŸkCÜ26k›¨…Uò¬%´#’ùKz„7>«–4é¤Ó"†v×·÷§Y"Gž÷ÜëãþâáÿpoMƒióûmWÛÂW}Ëö@“cñ¬UÈ\~óÙÓãP[¥€êÖz_ʳãÙÇš¼0nŠ¡hâç‹9v£t+Ã=ÒP?茊×!ÊRÿø™`NóTNjPöAð‰A¹¹ïîÆÍiá½H†8œUF€é¬%¯$V|Oãs˜X[Çß?°åZOˆÌðRW| ³M=ôV!ª¤2€<.«Wõ¬„&™Ø}V“(Þ(QW$­j>ƒBpè¶áMÖñŒ>ûÑô¥Ë¢ÆVY³ ‚¿2XÚ³ýÆa{ß…ø½ßy’jnQ©ßµþÔQ ÔzZ’7L;ËA~Û/lE^¼ÀQÏ)×fcëý`Êè9_\w·Œ«­+PVƒúg¢’!hçýW x“!ä}ýóÓ·ßPAUe»¿»ì%F’kV´˜„Ša«!gŸ7;UõÒàÛ°ÏÓè;þÃ+U±‰=~ØëÕ!ôxÁ_?y¸ÒÇŒš]}”͇Åèͦ‰qÑŒ¿ì§ð2¦¢Ú<¼ýªÃ:ÐÔî÷‰Sž$øðŸq9M¬Þ÷þšV¥Cu²õg°ÚëPâ:Qq´M “ßuÑŠ_&•Ïìü™ i &ø]¦xìXÞðÀt>€&YßÔ”®Âÿ‘ÓKÜš‹R  ‡ŒÃçe Êq¸Žé‹|ð´žbžÀȱ” @ZÇWØÈ¾;‹oï¸ÿ6ü®S.¤ï£Zß³çÕÙ U[aÿ˜LŒ.P’Þ“7,^©ø‰sV+iûø†?¸FføfKp},êOíˆÙÝ>Ðò;y­yÕ+vHÊÏÆwBÍkÚzèÀŒÞAÅç­>Cé€h_B7Á=44Âêî {bS·’:2;ý8è­©çÕV~ciÿÇN£êÂñÎ"ÔǦm“†'¿¢ø¦ðÖæ?}ö+õ0wª;(…5Ã1em÷±'x'þf¾Š&L7.u¤s¤å=±ulTÉNWû7ÌEn¸PÍÓåGípv¬ŽŸb»ˆ81X|7?yPsân¡TK?Ù.˜S ÿ“%¬wµ[ÓxØ+{°HÃ¥«cosOå qJ_™ê.©Z,m‰l%¿_û _”ÌmE©Þe(ôUYéùçIù­»h‡µ*r­]ûçôüÑÛìWõmûK\owH¶“&sÃÄmŽ“vOd'‹ß êô?€Ÿ3D73dð™²n¥=d¿¦qMÒš(ZZÏR¤ãÏшƒ%‹$ýÙ¥ÛlqlßCòïÌÌXAÉ’½™Ä[¹gf3<—Çoœ7=ð Ϻ™=±uo=¨)næ5 ˆA%‚#M $¨ªŽ•~rBUUGp„´]­ •$@[þªU'´ò—hUª%úAs qw ûH UÍ”»ýÞþ÷›s·Ü¥)¥a H„zPi’ ´[;ZHmxšÈÔn†ŸcŸ ð¤†õgüñàcIŒ`EÅ€¥aB$«VL)Ä…@Hå‚`,§7£#‰1‰K'J(Þ ±Kü,ETĈ‚–o‰`Ȉ¥¥¨Âs¨ÿrZ’–h¡G5 FU^°V‚ƒ)/Šh^Å¡"@i¥!lpAšæ0Iï€@a€Õ,“«ïß,ÕÊÆats¶!÷W`ô³u*Xï”)¾ôƒeºÚKA⌣ÚÕÉQ€ 0\ù NXm ë)dr4%QJ%7+ŠöA¨é>ù`0¿´LdÖkÕ4H„upW@¡ °&¥4ftƒÐ$Ô¤fÜ5 Qe9èWE#Ù»Žè hÕþ eº l3z@Ž—"ËT™îck@ÿ °›hnpR…"Qőڼ(Qkê¥k† 8–©¤EZ;¦¥`EéVʦ›jBQÒl_Mo? ²dŽV#[e}Å÷Ê%¬ôPÕÏI‹úù†¿\7Ö0$êZ¨¡e„„%½ ÿ´lírO;ÜëL¢ˆ,M8¢Ì*~7׿€+ñz-½ö¢N”§'#F1g²1“û–“ÛA BÚ¸±™Ü˜¯ŽhÞ5ŪP€Ü¥zh­©ú:Bµˆ:¢IŠÅ)ëO¶'Êe Y„ý`úDäÄ`åÓÿ2*Ë]5v[s_÷k¨èÿ¶«oéGBú¾zŸ¿né„(œ™5öS´»³=ZįÉõ“u³Óo»fReb¦QجÎÎ\®*¹jí‹R;SëGCU:]£eæÄ¥¦Ñ;jôPq² XNNñ-Ηi™ÖŒóåÙŸ'2èËt{£jäBRàÌw¾¹¯Úœhn·›Š9š¤¸giÅÑNÙsþ²1urÜHDe:`a¥¦¥ˆL°¨ó(H¦¥(ç‹ §]Z#KéSwš2Z¿¨pÀHoݤêc±[~ù‹ýÄôõ^ @Tp.Ê)[dÌNZ©é]ÚÙæ è£U›³= Ù,!óph¦õ§ÆÔÎ.P‰«$þ»þ&büÏúµ‹ø1Y²˜³üúç¤UšDõ–Ôîèó›&¶iÇڅߌºSu¦-LŠ¢aXŸ(1•ør¿:tñ鿼¯•V ‹`5‡GQ €IZ)<°ïWR­ˆ¢¥:ËÓIЧåŠW×€\•ûäÛ)ª*ؤâ€ô¼Ã¯A|ÙÓ'J%ß;7&k›j©øþÅ*€? ôJŽÐôú>¥ô:à)KŠJ Ð&ÕEá#òp3¨Çb¼+S#LmæÇ7ùQø‘dì!!i}-¿ÊÂ¥ZKS2¤ˆUÐÅÕRvÀÕ05k£²Ág„6RýJoQ7§+ÝŸ¼òùÉ êIí_(lDhª\¼§ÕòÅ÷x å®Ê32WrŒåGI ½Q¶¨\kü›QñäL_I4Uz¢ ƒxj’‹ú7Uz ¬%= ÝÇjêx@yeNµ„pg=c_ng¦@BŠ6Q¶Ô4)úêSqäsxk!ÎUÖß»‹A€ð{æ¨\êt¸·‘;1d…:gº ê7ͪCŒr9ü S‘ÚyÖSånèYÉøFÂ9'·{¤B_­ºíBƒëmö>¦ö'^Äž¾³B¬ š#·®”oͱõ_OO_½V#ªÊ'­„6 çžz:{z«ùŽÉÛ`'ø{޳óY4@dÚ¥Ñ6)v3ƒ2Nw’d­Àï™QàY,éþæŠûµg^©§ÜÏw.\ãÏÙ’üN¨&^•Ù˜u- ì›}çI˜­üþÌ,¹ÎôòÏ]‚D®’ù;¦Ú)0ƒoÅÄ#lªîþá|,¿>ÁkuÕûõND6ê_t¯?OUþýW—:JÿR¿ØÞ’þ)“j1TVûäߺ΀Û*u*ž‚¹È_ÿxˆÒòëÒ×ÂÆ4EPz”^Ÿ®Èiù=E¨´° å7k/€º©a€lÜn¢©o(õº]ï/Ê¢¦/+Þ”ÞC«Í0·‹â¾ZÀTʲ‹ÜwE”?(ºOd¤ ÝI¬YXmJ^!U]Z¬löÚ»}‘Ý ®î&ÕC`ù(V¢÷CXâK`yi5Âdi#:‘ðÒu†@…á3»æCûþ²8â_<±Š fSB õoq:éM~Ÿòð²NÅë2VÕ¹›þ‹,'J59ÑéÞ©©ýÒ|’ V+ ©ð Ÿnލf#a=‡[°h†Á–¬ÜTÁNš–ÞSB%$ß7›Ï6z¯“Ú‡l¸A…t6”æVw ³º½vI™ÿ'>Óo·J•ô%o3\÷UÃ`aЭV&ܧxGa¿À(91¦cÅϺñú!ÏIï•?ã[9ßûÎVïúV³(-‘£{ųЋàøD'q¿ØÏZrC8m*¾wþ¸^®´÷øàãôs …‹[s%&ÛηŒpfŽ;,J  Q¢‘-í\Mô„bÃì†WP¤‡ûYq¶2çuÛá°!ÿùb‡ÿ!±«]%ÿùÔ|š쮰ñÒ‹¼}ÎŒ¯±Â\üäý]–(úÀ¥–JðóÇR¥ŒbùÄŽ˜ÿPàzK‘ü0F'AöÕAXLÚ'!{o "žÉäh¬>ðú!7”G#QwBÛíÜ÷\8‰×yçÕ† îÍ$,³én7âÿv%À6I Ä~©?ûüSzû¤ c¬—)m‘…Eúˆ¾// mEJæM]o•‘ÍšýØñˆŒ +y«­ÕQ÷¬iiq>W°sß LþSü õÂòsëîuÎvVʶ°\>c+Aˆ&foÇ͉*û…hVàc…ŒÖ%R™EDnšêˆÄ7!Òþ·‰p)8J&ã@6Åb!hä¸Ãª{¦ gÞLP¯å¨—sli™i5*$CFÔ¿-8kÖ¥‹˜»ùz$øoµˆæYm£ü®v ¹ÁŠøÆƒQïúŠðœÑœ*< ¨ß½*ŠÐ…f_òoÉe ?æxp²Œm@1ƒâ‚[h2o»rñGiOø.N°¦7[Š7¯FÑ, )SƒEŒ›õ @>Šê㱱ɚ •eÿ~Í5`ü:«/ xqŸ†„£)tkó{÷†Ã/”ò´¹¿…(Ô˜‡ÔÞ—C¯½k8³ÎYí(}l›æ$È+3ì#"/ýë»vމ’Aëi4Øüx%ñÔÊ‘RIãÞÆdiš¨tǘ4ÛµdQ¢ÔqÝñÉÌ€qI!­Ó9XÚýæ×*U¹/H°ž£ž*#1>i"ÃÂ8ìá Rx«Ÿ®¾ŽHçì¥Ná%r—ÔpˆØhQ«Åïb 8a¥ž7}ÌóÓ±h„)fñQz¨&.óFô W;UòKíSù¨‹Z×E¾ 9©Z¨µ`8B|ééÈÍ  Âo;PÜeÈ"[›š®ßfÃ+wÈ»ÁÕ™å¬࢜ *ž(2k›ÈŒÐ<«Œ1øÂFS,•3RÄ~¨ª°¶Í\\=Pìõ«¹£¹Öô ÅÅ=¾E™‘pNܘd Þñ?¯ç¬ÛsîÝûp<0ÄPÔª C6HƒÔ™’"#–ÐßJ &œÜNùG6örF.Áü~“Çtg1Ž´$2j“„•ýã*Ò¤‚”A{2ç„ d ùÇfHãðeÏ¡ý‘{.µS/µ¾ÚÜFµ¼ðÞy%q˜ç—¤$2a¦ùC¶Â‰ qðÅâ÷û×u0E"V‰ xFâ<â¸èR•½)û¥‚~1…ÙAŒ3-¡ÂRo%ªïˆðßîç^k‰ýLˆ!ß[9ÇÑÑ×Ti¥ËnÈ?0á5A¬RÅ8Q—ŒÕ%œNÏÇ9ÜÈÕÆç Bq½MŠ3—âøÉÕõñ!ÎÅ?š mgê¼ õàh@ÉñlOÙ²¾«Ã£nV) »YÇŽNV·–.R{=D¹µD¾®Nràò51±öº} ¾ ŒˆúG$”Fl•Uà˜Ê}ÄA½ ét /fû“ ¶__b¬ì^ö©çPºP',‰ñô·˜Õ6Á—âJõè| Ôùµu½&"™—zYÙ:{gé/BÕ¨˜ÅuIRˆ»Ê"jéâÝO¡è’™à—g]Ñ~Þ÷g’¦ÊœÃ¼à¹Â6Ž ÷pœ€öqЋx =xï 0Î ÛIP›ý‹8YeyüïA1säè­YC«?ó‹°[<"ð‹Dpn ´³—3ž+SE%±;9¥VÁ±`wõËI/·ñ É"ºÐ~†îíªÜœrÐ<Ç\™÷ã J¬•Q ÉaϨûb ÜÊ¢ô; «|û¬Ð“«ÂôL)¥„²Üš •„yñÑ„¦s›´¤ð9]®éñ°Ëí§²G½êz°É-qqÐËæüeìs&•ï®”Ê6ë7t{5m˜Üe?µjˆ´Yæ%,7Æô+çŒÉ‘ ÚWÖOsgë¥m3‹ÏÚ'•öµ>¨Ö[:~ e¸dÐÿå..)%i¯;^/Õúu´ÿBf®X–Ð$pŸ¢ÓÀ=ÄÒË1UE(,•Ã\‰Îd _H–’Åï5‰¤+9–¿‘ÞàÅP‰TèÀp.×Ù€‹»Ü%¯ßL Y€ËW0·©Ÿ·O(ÂØ ± iï%ÖÉ~êì¹»/<"½,ÍQvù fÆ%å35Gê š’Da ãAP O*t²r0G‹™cS&í˨¯–ûePŽóp°N”A¹áiäCv‘É®Ñ]¯0ów‘Á¹€Ž½Ú¦%Aá`/?îÛ1R‹½ÅÃ}ê’¡(ûMT9ÆY;n×úcX`ÿè–šÚÚR”Þ"3y¶˜ðyÔõìt/Qz &´¯C×& ¤Ã†˜nƒ+™ÿ ?d$ ˜£603¸ЯKh\dùB÷ÊÝ'y²ÏcÒ”Äg<ô_: lÍG2?ÿY-1U<Ì$l£+Â4a>÷­ËbÂl²y¶…wàAˆJêâV÷úkÒ95Uïß¹š’Úø½jïKñ6xuˆ§ö·ï¡¬"}¼¯Kzîb¼’ø4“Û2Ÿ³íZaÕ<¯Ö»z¢Ê1_î©"=Úhàl±0Àð,;äÙk‚c_Ùu¾ ßxGòáYK>˜¬ÆÍÀÿ¼¯«}Ö÷Î4zat®ë>Øå)ÝéÚoß^½ÎŠBØ’l©-Ì?—ïË@Š ™²(~ÿ »¾ÝF0›ê›Ä”}™ßEû;‹“÷ùáZ€—`çÌÛ>°t]ÐÕjàæç¹¬q›îYQùD³Dä YâiÛ1଻²ƒ'ëÝÞ yN…f’QTŽYŽ$ïE]îw{L?Y_q¢éÝÜþâ[i“>©t é ­®›€I+fȇÛP‘1±œg¢¿Þ¢pH‡²ÃÄÞ›Î2+hêô@eå»§þFðDÙ*Í-eR¡yKðN²ƒÌ±7ÄåÌÁ³­ëé¹…Ê€¶GÙ·Ä8zÛˆ‡éT âV(ûÃ3£F nà|Ë6‚¾Q®0ŸC#ô‚giçÀ_$×·bìía¤Ápà×·G`ÇvtU#¨Ûí’T‡ò ;D¿5Áú¯Žë#ÕUãéù¡vv(ðvˆpÎRÓ)Þ‘#ïR^H«€<‘âoª–Â1=Ú÷Iðâü‘´ü­½¶ÈÛ(çgƒü0¨œŒÑ‹OrSoá~&HJÛ0D¶kéÁvk&ª{–Åp¡a®AW&çH«71.JÖ/Œ~€@ªvü™ú¥Z¨’ˆ˜Ã‹ÊH©Ö”vq.¨ÜêÅJÓ4U»è­¥ÌÃѱ•gùÅü‚Õ>5 &õÀ_Ìe–§ïLÄ]}-.ë1€4)ÎwGI5 ‚¸y LÉ"™<ëk&Lžòi*çg¿_ŽaÒþ/ÈÆÇ¼;ä|¨|¯^A›ËPkbm™ö?ƒcÏŽõ™‹±‡©š—i3§¤/Ya V£y”[Y{“0ÿÙ´52Z¥ÇÁk)O/è|·H},P×ý,”5;ñ‹bËN½£èÄ¥íŽN¢ã†ÂbÅnúto‘&Ï>téÞ-z2¬¸ÖQL¡Éº§&x$ƒÛf¤²ÇW¨‰NñsAoô†Åúˆq ï´à´¤·þ6L?ƒ®ö‰üF#GwﶬÙ=H0Íùñ£yéðïÅN{òÞñqhî/â¦Ûwà þd§_¹µÔÃk!À‘˧ËìÖ¬0ƒ ×UWw%}Á‘ezKÓв'á»L7¦\¿œ¿°ë;—,ŸÈÄ~‘Áö~@Þ® 8ÐKÉ;A– äÅd!t„Naé±Qž¥’ùueW¹„÷¬Œæ%ÇP9Ô²æ¥aàǼ˜­æë§˜.~l!Íî¥ÈÁ?Ë¢3où“ã<ã_ÚI3`Š˜@É7¾B¥¸Œ2dUA«4½ÒÓ@Þ@µòÎìü=òªÈ yl©Ï¿¹o ¼Üì°èxÁiü3ÕJ®Ç¸k]ÃEªùïÇrGÛ9¬­epZg§šÐbé—B xï^ý[“á™¶A€helõË-²™9žnºèϽ(£sÊ3sgÅìL ™?"–V ÎEa³Kj­ea›ôA±‚•¼!‚,û§«vÌUü^ØT#§Ï¹±°£@ =ØÌ-¢S‹‡0÷½Ù¤ñÏÃÝ“†âcK¨»oÝýÈm¼\ß»9¿‡U÷ á>œÔu>È´Vœ“¬›Î:RÙ\ú Õ Y2 çSƒ¡ysí6}:”.ö×… ;Àåòºh]áǽ䳤°H7ç^/ú0êNZ÷FìÃôœðª,â÷¬µã’öy¯[ <¨G+¥y£Þá¸Ñ…,±äþ™‚!ÜîŒè™Šß®O8G‘£tõšÅÇWƒ«aQУŽyéZZb_ä•V3†ôœSΚƒeÀºé<ç5xRYÕ`ÇÖK}Hh14ÂyáO„ô¡,e’Ó¹á ¦ÄC¾5²2ÎÙ’æUÙÜî÷¥–1JLW4<8£{gV{ˆPSØ9Pí´ñ«ÝH´Èç;37=õò4*«)l\tf{ ¿,:ïf ׋Znõt½[ ¶É9nØ$È]÷o‡êãÊÞÜR¤2¿¤…HØGu`Øš·oôöZâ(²ÐRlCšQÌ.qsó"r5œžŸÑ2ùGnîKµ‘Ëñ.÷OÌÓâmŒ„ùzhxCh«ë«ÒF@‰ñxdv1‰ì– /jIÍ¢ôô™üñK+Û6ïö[³ï“ìqbµ­ B×b—çéÖ4÷‰Â6ÏiÁJQd2¾6 d J\×]è^£…màÈo%²!‰80oùèU‡'©¢"÷]É‹<¶  r‚ŵ ÙDúNÂn:<ð {À ¢äÌÂcu£¾µuˆ5|ñïäŠ\‹ü÷ëƸZyO_’{¢AaCÍ}Íõh/ò´=Ýtúrnµ‚÷±¨À1³2;©SÃØuKF§F&¦«4 ñV:ö%–#Ç·À^)ã0´Qä8à.¥S»âPšíf ò¨—˜ú"Jäàœhõló>Ò9G'ƒÛðX¹¡>º„Ã[ÍIäúª¿kvîN¾ÓeRܸðû@ê_Ö<µb]=‹vƹvæ3²GÁÛ„¨6€]ihõî<ü6ŠëóHe>È#w~K3ïβy9ñ¥L|…aWðÆ'äa/Õ€ŽQjJ½Üê|WJ† òúi5=‘‚dÙ£¯ipMدµM”[ §9ׂKa>ºÍðø4d‹¿Z¶ô¼â¬díó“³´r5ò7 yE_/']e+Ÿ:ògÿ\V©AyúVl¼°¥RÌ: CÔ»^i6ï”LúâGT`½T0'ÉåÜÎxоFO’b 8ÆÎƒháp³|rÈ/µãÃØ÷¨ÀTvA~}¦Eå‚wŠ•ŽeIMPû˜| S<)£cœ‹¡grÑc ¶ãl ˜µµ­GÖñ»R(‘£~ˋͫrŠ_üü¬¥ì Ó°÷Åï¬ü2îðòƒª~È,BM#ØRs±¥^æðw²$#fœV¼ÐX°”²Y“c<ÃëŸ]Û×ä¢p|µ1¥Õé—0`3¼.Ã]Ã({oÈ£ øW‹$ÏU ·.P>#ñâÙò`vP(ùuºR¿e}aCx×}PyLy–¾•I ¿1­-þìðþ_æa+° :«Hÿ¾e¹O±æ·ñs<7‰Oóº$8±®¬("Oÿè­Ëâ¿èÍânüÎÁC‡íUÚ{§C¥)ñÜñ˜gšu;àéV;ÌõˆÄQ“JÅr–äùšø.yJÞÃÒ­v ½ïiÖõ¹‡ói‚:ûÅCy4G§:ÍA­_-ZŽª2…“à³ÏxÙRY Q(cdŸÝ¤ÐÚÒ}`Xܯš}3\ã¶½Sbˆ5²BgK@©—Æeÿ½_Ù „]FV®©×ú–Ý(øb«²ï&¨ÅÊè¥qN‡ˆÎÑ© µÏÒ>Ͱ‹S»(Ù*ÐXKC’9Ü͆¸üFü½ÏŠòCp_¾Ña("Öž”™¿ ÆùqÁå"LR¯t9bç‰<õDß1W+‹\GÖ¨›jßâ9ʯÓFòJ• b€¨æÆE\?èWÒqh걇ڗ0GOùîúS ê5%\³Á×4ÝÅmx«“@î<Õ:,#Ù Ì#6#;ÞÍsC‡â"4,>dïn0x Ù›Û‹PIýy(DüäÁ|LJÓušÐš¬fë¿GrÃø:Ê¿á&L ÚõÄè kB.]¢ò¢Ä§w.ߢô¬Ññ¦ØüHÉŸ'.Îé£i;yFB\º?B7”à8Bä…Ÿ´ÁAðstáê|ƒh¾^#¨¬Æ¼;À‹X–|¡;sÍ|áJ¤.jÅ2­êâ‹€ë›î¤>¿ÿ™À™”ÎðRu´@ãXkîdÝÿ‘Àó¦R<‹{LeÅú#`*'@hŠÂÊV2ÕE¬ˆî¥8f§§áï¤ûÃ^Mùlx‡ÓgIblcu*BáR”¢IIŽ‚ IØý)u:–¥SÊûcM¤jsÁ ÆÊ)j!}² Ï@5üüÁö'b2O "HIq00*0­€ä aE(C¬xÕJ€i†X)¿Và§÷h!Á´SÉèþÇRR5°q:X År4‰ôH& ‘”(…jA4ØÌ%µ„ö(ˆÃNû„™VZlš64øÕbIvÉšÞý‹­ß0Þñ4Î2¬'J(Þ±ºÂZÙ|÷2¯z~†‚_{ýlìk(lB$¸пQÿóëÌÎjÑ`Ô«•ÚMðUGƒ@XÅé~dš)UïxÖ ß}~*_{ôCmR† ¬r…,é…Ê”…Ô2³æ±ï”j1Kc;²"ÈáA \Hó*B*Ѻ¿a‘Q|x¹«ûƒ‘_IqL›²æ­hØÐdæ°¤7‚/?Ý+"–ìeâ•)«&iĶþÌØòÏO¶Ðê‘GßÄçQV­`’X ÄŸz´HQ¼´™ä…€DR9VL+®d2ýö¥¼ÔœÁ§xi)Y»%ÿ”´ç#i¨$KªTmC9J1ŽÖ·lׯݯÍ7±ijM¬Œr˜¬gÎÜ9H9EÔ ¶HmÁß09¿0×ÓÔ#¡žóF›!8ZÆ®³‹Z7U Cm£ÆNóïMl­¦Iæz౽Ŏö]Q’0¢:dÙt›Ìæ³Ç‘Ö j`a9N#€z–…Å9®ì/D‚”Ü^AœY^û~‹@à3”  Ù¢"£À™Î€3U)¬*zŠgzf«P¬-§gS¶ì¢ÒæjÝÌZ{ÅK^û]ÕX…°à–Ñ?®ŽÆöàöþY3È7¯BÓLçVÁÚ úý'ˆ|Ck¨ø›«=!æ!ËYÅ>A”–unĺµ üŽžDøuüp9^«@-6ˆ01ŸGÏÝnÿ›üžO/9¹%8Á/°-÷õS‘[ûÕÍœ¶´ÕêéY”¦¢OhæÕ¢š§)f×”ô§â“õ Ûe²þ,}Â0b¢rri°Šå—«Ÿüksè÷ÿ¨«¶GoúézB¿¾éŸ(n™„œö´5³SZ»¯=õÄuÉÓ“»³RobfQe¬¦Îخι\í*RjS‹G;Uë]Ca:Ž¥Ôœ£Í4~G*‚£oZà"ãt—°3òw5œÀzöL€ÉtÝ U‘`–ó }½æÌsÓ¸ETÜÑÜ Í6Ñÿù9@‚4é<ø–£T´”–É­È©¨ûÍ_T2#Ý¿u’ª)ÅÜ–éöༀ¨5à|““´È˜´RÓ»ÓisœQ¢öTÀÍê¶[:Û 8¼ú9ÆÏÁÕ:ð»à&ár4eäØZÓ;›ª‚ɼ@Ãê­Õ8WMâ:äúS»áõ.ÊaêŸîf°Fjð¶wKг†fØ;J ña­Ä« 2š§ejB¾€ye+]ëÊRYz…bø.}Ûvùï(ñ…›/i)jï N«ÛõH[?;\’r¨œZ ks–[LžM0ÁÊŠO™U9ŒERêR4‰õJRúŒägÄ%³¥w›Èd2{RÇݨï”N¼ XzÍgðU“¥”]ûõ{µ|ºo2\ñÛ~ñj²^f9—>xI£1ð &¨&XZÞ™üalç1÷ãõ¹?7ŒþíÅ`~4@øàÏÅÁð%Rx) 7ø´V0\æÃ`->Ö’!öÆs„á4ÎNØÜ#¨weßeÖ쬿sä«>ˆµMðÈX6ÂoB´ X'»÷á6M]¶^½s×’ã@ªˆÓ`I‚œBj/ÏÕb¤6ë%öª*\–b‰°Mú ØÁÊÞ^¤ Á3sX³°Ó©>DNUͬg"`€†ŠÒ æ:0ñ R·yߟ Aß- wlolóØèên[7Vòm¢¾s¸wî«ÐˆõÔUzƒÖÕŠo’góØYìÏ'JȬfù~ó "aàsF8ÂmætÚ]úú)ñª™¥³ï¦ÈÒvE« ×îí•=ߤÎm¦ÛUà8?!·Izl"Ô'vb­ðNYÞ^¬­"U–É`ŽwÎYÎŒc«‘ã+GŽîÝlÝXš×yõKåè©.–úÆàÀSªQ”o‡ºT®ý9®?Œ«8–'9•*y®¡5ŸžÛ7Å»j¸¾…fñ¿e‰‚Œuð.)†.Œ.… ÒtWå(¼m6ÇVµÙjÈö4ÌÁˉ7ºÔI\â ðÏYï•iÒÏ÷/ƒÈŒ<€n(ÂÞÌÜQZu`aNÍ’8àî0•®MÒúpØáÀ“üJcî]‰„óÜùXÍ.õ^é ñÓ‰úk„ÙYP¥X³ó¢¦ý‰­”T*³½¥õ–æ7Ë÷v &"tõVÆÆZŠ7†Ày}ÇRø!¤| ÆÊ=‹ÈÊÁîS¸e¿è”æJO{ÎzÒ«¾‚ÑhkÑ^VOÃI4À¤.NѼ:G¨~wÑĿܱ uCºÍòÃǾÝS’¥8NóXä~¾$æºa¯ÙË*Í¢.ÞMæSa¦pSžxÉ’6´9dQ˜¡6=ÈD=iŽO…I^«0—â¤úð‚ô[&«ŒZ"¦vUÌÄÉ~ÃZ]ÿH‹ð]e'ú!ÅEœ–Ak—}ßÁcÐ- –lÇ‘îZ>Aú YËô›Ã;5Hš”ÈàÈ“³â«vÍnE„›4}+áŸDé;öìçN)±ÊÄýýüÖ?è€w¨˜=q„BÛ¨x&,Y¿Ñô¼ºvl7›÷)Åt;¯Oé3:>o:•n-ù$ŒEµhÛ³”s¬^ÆðS Kzð:üZºü}Çm;úÐÄ †ËÔsG(R™œ]ð"uk„@–„*)‹pYÇì)˜v‘ò¤íÐ2e°5gm‘]@ nÀ]C ªdĂܙõfÙuÎ2°¼Ù ‹0Oì`Ç"P‘MRÄŒ!„ŸDË“º‚ ÁÉ#1iHúa› k×1LYû@,ˆªE`ÿïŠ;`x˜‰II}ˆ Ìî Ž|@ìò)™,³àHªû¾ƒq…ÁCOŽÕQ"Àhv÷ù-10ÐÒ}ª/~×½nà‚YvôTvm×Ú•öU#uWQÒ¡ç®æ3bá¨ÄëUòÁ§‰ÆQSâíñáÖÄø «Ðî·¡”µ"È&¹G"ÖRÑXw<0?;+,ÞšÙØ†k|=†Ý»×u`–k7O$b‘[]¶a€™Dÿh'e¦Öø6eÑ[×2ÌR.1«`y†FÕ“á4öLmJù>Ö»¥K¿×56¥¹VÈΧ˜]ÜçàÞšCnæiÈ·€÷_S…ˆ>I¸Y²EåXsé4¦fʇæò+Öò¶zÚû=Þ<]¦ÃðþÒù_Þíâð7,'ÀmnÏ1dõοDâ÷ËCÏ'³Ž‰Y@Ÿ«¤ÀÇ÷޾iep å!l„~}0tžávÌuñ ߑӮàŽg¬ Ò⮓Îuܹ'=†Ðè2‰ÁzÃ;ÇÅp°©©´%z¿ÍÜÛÍ-³æ'…h*ûˆËðóï¢tÊmj ãN(n IU7DnhðR‹Z÷Ið®¿oTÕ™ôëuR±h½oü®Ãà ²ýuñ‡±åïãã™Ö¬ƒ¢ö}Îu òAò{Ý ›ÏûlR2<Ú]ØšbãlØUcLa2‰VƒÜkôAL\Þ>lp>1\íw!îèOïŧµs}ßÃØñíÖijÕõ6ÙGŒlNñ“/Êù J-tIÂ…ïr×+ uâ’¦ílùJIÖäüäüE%°p ²3ß¼÷)ñüÍì! 5¶3,BSIØ÷£Ÿ Ñ‹–ºŸïaÅ/6ã|µázœ?.jGf)"¡CÒEÕ9•±=¢bŽZ8¸¡‹¨ó1ÌÃvîüñÂ0¶}›Ãn£°Ah¡fŽB­åž[SkâÙŸï­ÍfZµ¨ãñðÙ{ØÖd‘$Hÿ%ŽÁ%­±SÌ á"êYÌïÑï)yÊ‘’‡ês’y 1Ë›‚¹Ä8B>Ãߎ°å¥P£¯ þsðQ ™]AÌe—uùð#)’…:üÔ¿¥îŹ›\à º'¢dcM4c @õàÞæ¥ƒæX ¨0ô픑cTiai¾ÙB«Z{*ÚŠYÁï‡qô¬_ÐðZ~%üà/'½ìˆ8Re–… ÜØØdQ‰ WÒÅ-¸Þúîá åï7§&l€@ 3ýŠxh6ÃV7‰òÙkÚLœÏ Å‹FÔ„äâìmDA ¬¸ò;Üþû÷²Ÿ?RáK_£øÅ1´n5ëß°þo©àö8ý¸ë%„-&2 —°Oîtgêë±9?u ½%bðÞ×Pgg W¶ íõ’å½eÚÜöšÆ3jp G¦n‚[ Þ Ÿ<D÷ï:WGU+î´^n©@÷7¿Kò€D¿ë«äÎ GÇåÝÇ;D“'„‚eÓv05h.7V{»að2âlõ!'o«n—B×eÞçúæ_iVMƒB3^Òñz7`ÜN]÷Þ,˜mý£Þ ÀOñãú®£GçxG“œÓn2T±ÝfNº™êÆØEojµˆ˜Y…ËhûiäÓ`É>‚I® ZW¿†„oxårÑYü¹;óX?]¬vø¤q Ñ)•/îîìy¢%Êy{úCôC=<(0¾ 8šf™‘Ð!%>Ýêz°tæ¨[Öß°P.VŤOÏ:keRS¥ÙlÇ16(M¿Ò1êòãA†_×ïЯ A ç3«_¦êZd+©×5yþRÆ{÷W)c}º¹‚íBz®£]õ~ëì¡ ^º´æV|ó·eL}‹éw4ƒ}I“‡I 4?°ç¤ÝÄE³«õÝTr(dúYLŸa=ô$Õ«4¢ëê‡6­PO3†lΡ©¬¨õ«u˜b¯m¦ut®cÍp>èÀLVCgEÝ®³ë×Dô†&n|ÇL›¤ÞeÿaâÁJ\ß×pˆ#µœù˜‹e—4æwé[´~†JPo@IŽ£™*dg­¡?&ñ5áÇÀáøýVÀ›V*µ”^­MŸF>“ó¶*oÍÅUµX:©— ¢b£XHCÿau4y7ýÜi|`ñú»3’ë_üœþ„ò87~E¶§_‰»°W/ª”¤¢kº"E|–²<î¯[³DtŠÑ¼îòGʧd¡„w`LˆâzïÀÝkg¤XÑ‹EÞHÁRÙ;YÕ7i±Ýû$¯ÌÄÝBQЯƒâäœ%º¼‹«-w íÁ,àïÑ¿=¤‚< ÷{Ì´±4Ø1–½…÷@ãìtÛÌÞ.ºÖ,H¾"ú2#+úßÄCÒýDªqµ¼SFÉ7GÀSÑ22+]%†%ö6ÕÃ-wÿ”¦[DDPr6UzôXÙ!mj4CÅúyÍüdÈu“žrš# K¥E’ÎÌHâp•+®æÌI¹Þb§ìŠ Ýhª˜š-§úŠ9Ö×Óô€ŠRçHŒ·Vdûv„¹›Žt©n_Ž@:Þµ¿Kô†¹eé@Íë舿y±K«+…h׊%ü Ú¬¦ÓNߊz |¸ÂZä’jp±¯5OwöèD© ¶Ôê*xÛû»…¯¿è×kôœ+§óÁ20Ùïd`Û†*ÆÏÁãw˜{S¨Ô/T·i°[¬ÂÊï =²'°*XO¢ Cm1ytÊì Ý_…TåäaFµˆ¶CÌMu·‚@pÚ¦UÇ&Ѱu&+8r&iMKîF×C1˜ÔÚùï¹><×ð;¡nA¨ÅÇßZÁqäVkµþmk3»'ÎPWãøn‡,)»qKÁN< û»‡^Ó¸ya:5ùÃ͈ß\±ø1TËËRTÐn0"g¯‘Úíï 7PÇ|ç´ Èº [<$æ±#…ÍÅQ×âxÉAoØŽ=zöYÝžÇÀ°OxaGñ :ž£ó:¯á¼×Á‚;Ôò¥:¾„^¥ŠHcap2¥DÈíÀhXÁ¨e†PÉ*I]Éñã ¯„âwXœM9öÉ–bòž¥æ¨älÓ°¨¢Í ¥L ÅŇg².SdF#0Ÿü5Ìî±RP^÷_KíÇ‘>n¦ ïtõhGHÜ<åà°Ø]Z.~lÙl ‹ñ‡äJ¿<®(öCÂ7܉Î}Z?¤ÍìÝa´‡s×x¡ú~‰Œ+ú +D¤J)üÄ+iÅÀ°_Pžë\ÇÏo}扢ø­A5g(ü¤eÄŽ áÔÊìgÁà=úm 7ˆX_e^2™‡ìK–¬ÏΔ~ætÃ_w œ·yYK=Ã^wRO\¯7œ€¡ÕœÑGx3 ¿v¼wi8ó ÛYH›=\‚Cƒ}8ãfyy-^Úu6ÈÑE‡‹¬ ]çnfË÷Eƒžæçq†tó±ŽqüìY;>¢€fŽo˜"k"~ÚqÆŸ¯õ„ð¤h–K²ÍOoV‡æANYWú•N;ýT.\õâÒ®ªö_P]ñA¤HG41>[,øn¤ÁP Íûãsñ;0€ÐnQ±õ×Mõ„\NcW×o6h£I°"ŸÄã6Ó8 ­ªÒDÉôôu½Û€ï&¥…3^x×Gˆ—At¢Åߥ¨ úÓÂq®ó†½¨æËïúzÞadiÞK2ad<é?:¯hÍ?¡±Ä ÝY­~´ßŽðÀÞÿߣu@Ây½ý˜AÈjë(Ʋ š÷·R›¼ÅÌ”W£QÐÔš‡ØïÎŒ…]À‹ãrJÔ ¾¾žEV¼ypgR/Ïh^Uì'ÃÙ¿í™÷ÞòÀéFãS„H?Ñ·Í!fË™¢­f2´Ñ7MÞg1'OxuÙnŸ2õÌU ý1Œ£‘ŸUÚ¯fuƒŸã:Ÿô嘧˜‡é‰¼·  Í°–…EøØÀÎpýœöx9ÁU!5q³g‘ðÉwÈ.$ŠûMÊtK;åg1Õ¯|H¥÷)⬓œÍBeÉ€lÉø"q¶ƒ\B«‰-Ô—.3™ç™Qó¦ñÑG&ÆÌzSÕD@ð§¶J?2Ehuse©U]±´Ž_Û<)þ@Í ¶é8„ê×£ÔðGê±ÜùX«ž54è0SxW¦¾óèÀÅ1ý^L9´_Åý›h±»’¹¼Ë"S­Í–—dàñy %z^0™)Ѫ¼žU¡æÝ/ÄZ›h/§ï«B•ú…¢z{âxÑïiîá¥Ûï8ü iñÄ›Û\HD=<lÙñ><àõ„Âë€5ooQÎ8ñŸFd| Ä Bð?P·ØŸ$I QˆÓ·ð7ß* ‹d’79÷)5{,±ã¦àògÕ-–ñ%U?JBk‹d>äiæçO¬ l”Ýu¾”ÄìcDáôPO…ò•¯è7j|%•”ÜØ hZŒI¸ºå\B´Á…jóðžHù1\NÄR!.¬á~ç¹LzÛb³i¦€€Èþköd„PIã/{•-ã>ÿ\ÄíóŠWrbž’È¿+TöÁRøæñ'2=sSxf@Ätæ«äL÷}Þ´b?còñ–ñ’j¹ší—m'AHè§ZÛ]]išq<}””#彪“?£Ù&[i ô¼Õ=9[Ž Ò1¶ð?å7²ŸÕçžJŠÉ¦ûù¦BÁ ÆD9£¨8ÍÁP+Áƒä?:ËÀáCCE#^Uà± ó¼«Tm$Ÿµ•±„P™l ®¦®®›´&ɳá/vµK——¾ï¿ÌôÈ TÑVA9iêZ¬f–<<ã¹1~Äâ‘KkL2k<ê8R¡êU =íFª·’„ñ«Y58¤´Tœõ´m¶šjü©ßJÅ‹Ch”Š«&œ@ÑG#êTrƒŸ†=f ˆFîߌ|ÿÌÜò¹3…>wwÓ@i4²ä82ø6²VJ[Ä‹<Å-0@J(OeÖ™#Skò‘‘¾õØ·^ýgiÑ{¤‚U'%„ßx¶ƳÕËÏOÌU~Ô6AšN²À0Žf²9š¹!CÓauu­Afÿ†èFò68än!zuC˜'‡±6$XªZ ;ˆc„ØÕš,€  äîMÄaߊÜ8G·@xˆ<©î$ ±9Òµbkn÷Ž,G O¼Lë ÖwÞæâòv ³ì:HFÍ­ð…Ôfêùòµl}Bò¶.KݪƒÒ }Ю\~n´¦[1ØÏQ÷œs‡×Hð³8ˆ¯{›ª—ï±ð5%>7/ÊãZ鬽@Ëž¿áü•±ÝGø,·ÂkÀîÞníÂE!‡o´pV—Pà( }ßámfg§ol\xÙk~5¶Ô’Å©{IÃ(vÎï^‘⥈õZ¢ `\•@½‘Ÿ &¤ÎK¸‘& ZP1ÀbáynÐ89fa{›ûåàFA í»÷²8B›¯o=>¸úXÏà(wQ{á´òy¬ü¿¿òvϘ>е×¼K_<޶C®)#–ƒG÷z7¶)©Ò-‹19\¦þˆ>ˆ6ýc¤®æ Rô勃Ó@1ˆ ®x>ð²ÿovqûFúåîÂ(Ag7 üq%°Ç-·íæà8Ú¿¡•nÁûÞ„ÇbËPÜèA­âRëcÑ¥AHѬªB÷N§ó-ÂdN£VãŽÀ,3Å£Eç°õC=°ÊjûO¿Àj~QÉOä´efå“xw¾¹ý#…4Õÿ[8gÒŽdÒ=!ßIvöTeŸÅÕ"•³ôñ<$$3.3÷D vwd.O&$\r|$Ž#oémUÍIð–=ŠçgÑè@&' ïe$d†<1í§yäâ¼z‰<8ÃÊq#mŠÝ)"^ ™¼(°÷ÿÈëžÔx¦õHä¾{…§·™á'•·ÿÄnòlÂbȬ[šŽG:ÙE’uœøCDze|”ˆ·‘×ÈážiÜzZo’ø~Óé'ogïCFWFØô€õ ®Ÿ}/yi Ýœµ§_jϽ)6ïŒ43mú¡Q_ðÃcËm1.B„nEEGœc¦vÕI(çmMì2à»$’V·ÿE×ù[Úqg€¤YÇ¢Ýì›ß9殫ìýî}ëÄíqYè ´%oÚôÈ©õEL&T=,øCºû}»¯ò‚³¶Þ(·½uã­8)O5I¾yž×'¡¼zÙ ú35m“Û,éÄÞfìC—]æýŠI™Á˽‡¡ÑÊëó5¯–IêçWì _ôúçû Px«J+¸›þ ψ‘ÿ:]â ÝÑÿ é?‹ J9RŠÞ §ï Sõl‚Q[¹ <¸ñ‘o0 v»%㚊~S‘_¹w¢ Þ©ìÙªÑâ»Ò´âÍ_ݘd«íã©wNÔÚ»³ÎÅþíéqÞ!·èéÛm|ÑT¨wô¨\Iü [$$îá'å—s³Û$Ÿü51w‹'(ùˆžÞT4ìƒùжrêE¼ÁƶõöÛ\\ϯkÅ,Ú {#õH¡zü]±ð»Uê‹ø›=C•æ"Fà|òï"€ÂfBUz‘¬÷¥íÌnΨÄïX×zcÿ',ÆBkt ø«kkØÂÇÁ†\ w}ñ 4ƒƒ9q8»ÂƒÅ0°ãÙ|6¢Y)IYåùƒ¬¸fù ÚE%jô;!(K´H¶àÁÎ!9è"ât½ä¹CEvŽsgbŽRÊ^Gx·„Ñ8¥;¼±†á0sټίÔ6‚ÿ¯T{Ë?øé¸Ü½FMnœ­}t[·lÛTê¸#•ßÿóuL}’ùŒd\ r¢ÿ ÓÝ ‘V$/v¨ã÷£-…ÿ®úOðò2ÍxÂÂrÕ9IYÞÀ׸•N…~nè,j÷õ¡öv¼ èöùÃÈYsíÞ­oÕʯJ1ƒåöfM{üż‰8”²;uòh{´°·›O|²Cú hÙ&.: ‘¼å8ûÁ£YR°™§ƒ$Úl<ÓØ6ñ^þæ'å gòxZ8Êòòø[{*R^k¬üˆóõ÷{ÒÆDÙAÇÎ$óù³ïýíÆ§ÕžÙ¦aEçà"§ÈÍë þzš™3Ç r¤ý3(zò¤þëjÁ!¼÷Vp+ø™õ½¿öSŠ^úæ>4FcüoèN¤™È]´}ðû?ê,#|¥³„•-J§è(ͤOr‘ÂeÉ…&m$"rû7°õÄÜçmæ(Ël>‰°#—æ•C·7/¸×«/Á‚<ÈÌ,ªïœÌi™ð‹äºã=L f†iÅw¨Eöö_ß F0Ü›Œ¸yá4õO³ø_ºTVM¡…NaS« Õ…áä™ù×N¥¶Þ®FÁoûÿ}›wÿTm…za£Þ[™^º½O×9û0uA#š;R9WlæbË”zׂHœSBêB’¤c³ÃECZkÌ^qn @çƒUõ*^^Í_¦¸/šg|êWDƒ8éÚÕÕ“—š¨~e;_D,D7•w9€sG‚O‹̕þŸCôƒn…ި׎õwéO¬›YôЉ 6MV‰dÃ^`€Xø—õ>&؇‰LuSˆšDþ„°°‹7Ϥµ÷0“·½ãpT»öß>ôZМ­5XKGpÿŸ¢¶gÆ -z6š@³™‡ì‹ÇúRŽwñÔ„4:Ršt0òÑá¼qÞÈŽ;p®)ý׫Mó»Œðr¤+8½DJÏ ¯ÉpEZiÈÎmÍ«¦fÛýÞb[ÖÝÙöì<ÞÜj–Ž”%é#”°ìo -á©bZ¨F“$߬x…”³èŸ<˜º,R¦J³¸ìÂãß<,›¤†åÚ¬©&Å~îJl´8ç$*ž1ÉT?0ó°¶ Þ½ñ‘³r.AYoë-Ê©)qËÐjKkäË:}‰X67̘wzð/€d3ާ¸7®öÛ syÉÝÚc9%¿#7}Ó™RÜ+\BHÝá'ÝMs±-u9ˆm"˃='¹õe˜V¦ô4œ«Ñ°çïìà~âÅ)<¹Û ô,Çrˆ9ÓIšg“¹&è!ðm„™ö.åz²–»G¾-á a4ÿÏ®À©ð T K–¥ðI}§~<žEÝËÚC»?(ÊÈF–uOr—’EÙv<ý;ºd¯Žf\y7Iõ–²êÝyi.ú{_yØB—{¼9ÏElDüç£Ý÷(è'J­†šª’г«w‘R>ßݯô³sÓGÇÃwÆŽŽxnf>è9§rëxÎàïýÇë”±á{ÄD) uëuØé“S@ÒS™ë±PС€·iŒ d¯ŠÖ¡–,¨Â6{»ëR½ÀžKt&+ìÇSÓh±Ðà´IeFMŽÉ2×Âf¢Ž“…h=,(éP+²Qd¤ÜÖim¾Aõþ˜¬ÖÙ°iŒQØJmúlTìš‘3“õ{Vk»n-¼é˲ÚQa¾F'žžF•š£4¹6Éf²žÝži ³%k3ÂàÚ×10m¢4G_¿Gúj°‹à)ÂD›–Na[ËÔDTt´v,¾ôÅl x]»…Tö˜éKëÁ_ NT[ØSäOÑ×ó1¼­ÿ—ƒ½TVø¬°Df¥ŸÖVjÑ]ÖNnГ½+F¾“!Ne=-=x¸l”ˆÓžÙ™êô±ÄÑÚ‚v¹¡Ê£ÔW,ÚÑùº;;z$»ÔµnZßc#H¤]ú¯YrŒ¿ËXKRQVDbºucþàêú(Å µ}ÓêÕoÚcá5©º‚kã`â`™A (`œƒ”[ÓXdæ90ú†} ‰É3‡£žñª›LH §ú Ç×ç·›Üs˜e;tsƒŸòHï䥸ndÅd±®"†ñÖ«mþ=?ÅD}¤ÓÕbp}¦5cš*ök¾¤Ü™ O¿–…±•v3òÔ;´ù Šê¬=e£=?AKBäT·÷ú¤æ/gè©q ˜é+Í&}³Þ™}¹FFÓ=ùdz.£ÿJ¶ãH’…“%é¬ïLù`ÌãByeýÔ…ûQ]Á{oeXRTÍꣂÝ&¿Éúhnvø]a40rZ<-í ´ÄÌv°Ü™]ª•|¯â@çìÿy÷ÿ{){áñéˆyCRÅo°ÍüçÊ€+Z7@#°v’V‰®745ˉ(}3ÑŠ]%NÒŸ„£ú›£Ð·žÀ]"+. ÑÀzuv2¸w­¸ø µÓ<ÂÐQÆõŸ–ßn7I®Ø§Ä_õ“Ò'½¡õ:Gäå 0š`•‡û_BQwÏ ü¢ ͱiedaµšÎÉ™‰žŸ_¦¾N Ò×Õ1²Ì3t³€Õ=LH™}¹FN×WNê:Z‹!³ólÔç§>¿»j 8â‡54.‚ƒgèÏv˜EƒÎl[B¨ØmÆÁÑÛ0†G¶ŒÃhÁð4æ…uÕEý¼ÔÅp$8V"îWå$Á(]îí̈!Ö‹fˆŠöFTm 6ë©JŠ¯ë’”B0XDuÙkY„Ð" áБÐ8Š´JôÚPFxÀ¢80#Å7hÅåQ¨Œæ‡N·C&ªÏ½„v®¿E¢7€£50†´$ëh¤…Ú YðžAT­Ý„Οxƒ¦¿¿Ë2ZwåŠÒëžöí·á¿®ÏaÓn¸æjdyLP8«„±%dsû sÿ3RÝ‹^î@F±V€(¡.á«ÃÑ`@ƒ:À? ™Ü¾ƒVÜ}žZœ·Âp"ãY,/='µ©±âçônxMoýÎ*Î>lûaŒg•Höq§,ñqõßG QS¸ïK½ºçãhŒÖÕHE„ŒpãÊèu,º±D‚E1B¡£^@‚° I§íUYìBanE50#Õ=´èëhòBª„«ê ¿m|"y Jíµ´…ÿ¥Õ®nT°ÿ´þÛß$Ãþœ“¸7µ7©í¯:Ä“Ù?,¶ Œ07ߨcÃOêîøQo–ßç^68çÿ,V Œ0·ë¨aÛjê7¾©ú~cÜ`Á!ËNT6“oñp{\pEõ/]„Ë@bœßæÜùtúÀǪÊðFôXP¢(À!û7ЊËoP‹Í£F0E17 éu–²¯Y³gV\·õ©þ±‡>«TÁîî[ç(_ójÊR-÷ûz?y˜—2{]°v—û_]uϵ@øí©õ­gfk¨oûŠ^|iíÛר_ÉNª ø£VŸT {ÖÎL%…# V“¦¿ÛÖãsØîÙz-‹ëÖÒŒóI:ŒøKî]-o/䫸š@zï”Ö´(ö'¿ìÌ 6‘MQX,6(.—çRPìÐm6ZøG”ø¬4Ô² 5E&™\š“¹ºËÅZ¨ÿÐ\싹›9ô1zbЉúH§ªÅàúMkÇ4Tì×2æj_XÎv)µ¦î®aÚÍJ«xmáªëg#NhÔÕš4Ñ^&ƒ»[Þ.zF¨á£7AL³ySÄɽJ3äï¾=ß‹ÛW¾@>ܺÅÜ“>rŸã³cÝb:Á¡Ç˜ù¯~ÊÂ#š\¦]ÙÎæÝ‡ÓêÏxŠ(HËó"IÕeF¸ó8µÇzÅ‚/íè›eA,¬¡rÌ,<ß1‹°*<ð: L‡©Nh¹ÏœÝâZÂà rM¡ aÍÎBÙ6‰.ö”.â»õ´Öj7 I¹Ø!>£¹fÒUš%/œ¹HTŽ$”"QÒ® 0‡*Ý„ª•õ•sNÀ’k%l’¹aòãÛ‡ª'R²D‘»„ ©,Ãü%’.!“¨˜ CéŠ0%$·XÌB’tª2R`´Á½bœEaæK8ø2¤øÒ(H¶"„}ÿ ¡–ç)±!´™E¤CHƒ¼±ØÝ´¸Û%¢†R¹ªf!;9ËTäºs;Q*Ÿ¶SÛ‚ù 2Œg²ì,Û4 Ù¨[¨1¹6~´P¨*0E)lÜ»]È­tñ†d«¨¸b›-ûÌ"Rÿê²pYœŠ%k3YùÌßQ³. ‘Ý)WüµV Ù*ôÅRõ%«¹WÈjrÇb:ÅÅ/‚ŒE×*ACfiç-u¨—’Y ï–PµŠBY“ú%@¡¥]õâ(}©vOw)gZLSÄ•”û„TseŽ}u¿æ[œ¼¯°Q‚-àßœÇß1fcÁp4·Uòj=¬Â®†Øªõ›[¬’ ~韟ëcÈÛ;5ð`Öésܾ!4¦KØW,S>ï¿Ér ù•r¾r_Vn2è’}˜²ÑÖäÇ,C °P¨ÌÝ¿@062Ô…š½ƒ†‰“  —îKžKfq"¹‡¨ÎËA‚ûežp¸çÆò?Ò'»Æä¡“‹u+俀á"IŽúÁѾË|ñQÞ~Ì0Ø€Cæq²Êù¥lŽ}DôYc‘K\MžT¦õ0sö ôÍ•¾ÿ‚Ǿ ²Ö"€¤†Óó:žOÅ@)Uã›–E Òr(ÑŦ$·p*Ù’W¶ûAõV­¡vßa°úUè4‰Ø{D$»BÌ9FI]"¾_!ïàED°+Dî+G58†ô•t®x 6ÉR ÍÝ”Oìþ÷ÑÚËÕœ{€ed¤ÕjRዼB¢ 'û> ²i#ÿ{K’i•§&ööb«êaœ;ö ÒØ­PöaÇ=?e o}ó~WßÜdò8)]¥‘ RanÌ ã—OU¦Ð’ûšì>‚Fé/NM´Ù‹Ín]-Üöc¾XíøåYßñºª‰ø¼PdÔj"Þó©,CªÈ•,Q#îyÆÌß)ô½²þ?µbZÃIZ£(ï¹fe¿¥‘ w?êlÎì¬Õ§æ…jçô<î Ðs)2¢¬­]›¥êE§ôÑ–ÞnQ:3¶jóªz½±¯^õàŽ{ôYºTÛË·¥ô@áT§Ø~ÖÁåB½3ö~/…&Ê"K52ús.á%è‰"2SÁ˜Qè‚/ (™ÈŒº(y4uè–ªK‰ÃêÂGaqO’HœRü--t±)×Â^ê£[R/%1‚Ö…—²àκè–ÎJ‰ ÝúQ)+äêùD3©Ðöвa%æàu--¸Ñ´.î¥ÇB¤ø]äRR¨þ‡è÷ÑÅ+à¾È^ì[G𺀗Ö=‚Îõ¦zÐK‘|dD Ö%À µLWR4"pËn³¶:3άÿoâåe¥Ù´YYJ_VÓ¶ÔšËз]·un7»îV»ûÒ“±’I9@™Ç]I•äÂ¥(ÐhÀͧ¼â²’æ RbÊ<&fˆÐÍÌ\¢ÆñŠXð~A™]˜¾òb9 $ · 1MdfŽÅˆYŠòã/Æ"(±X±‘1)ƒî8ê(£¤E¥í&GÝÜã~Q!PÈ=4AÙÈýƒtÝä¤9ûÎ Í»=˶±±Ý[ £€Á q¤'”³’9€B‚ß@ñ ñÿ6 ¼4}”zÅfxVð°JµCRÒ‡§#4¡ÔˆÄ‡ß#Ò@U¥5h‡:Wp®‡µ±¸·â©UNÿîeôÈA¹¨$:#ä¤ÿ9ªžúÕɳõšæY¯:¦HûøfèЗ´»ÈI\™È·¼LQ×}¥´¯ç:lÙlŒã½¨} ’—'¬œÍn4(+!è2rºÕôh|UÙ‡Rt(ØÖçª.Ó©‹ ™~ª!_Ɖg_NΟQ}:$"t ôø$iñ¡œøècNoEI3õæ}ß:•~u¦{ m¬ñx棑mIâ™1Î ·’FúÀꈌþr‚úú |°ó÷TØŽgeŸBbåˆâ ‡#Nß.z4ò'ÚN§-¿O6Ðrj.óì/Œ¾ãŒ#.-‰X¨÷øŸ£ê†îP¡Õ°ãßRóÄ\#Nâ6ŸØ‚–¦kRŸ@r~·ÆÞ†žÝn^®´$´r8Twýù˘£ÑŸÆPYqÔÇtŒTëÔ ½’¯zÔšõÀfápY¶éˆ^¶#µÒ}æ6æ©¿þŽñ+·zßሠ´êzúÞHC’~/ûýØ/‚Y3ÜeŽ:Ý=15‘Óµš¾ù³ÿ´½7âô>’¤ÀfFi›m9@|i꽫[¢Ì¬êÓ®¾´|«™ž ?£Ï|øøPƒ@¾Z—yå”bZò±¿²îçÙS e<ß“ìÊðËÇãÅP=R[Ö¬<œÀ;G¼MŸý–y[Íq>C™¦úd@w-û^ÖÖŸî‘8Ê–÷žö9_Ëã×uèuÉ•Æ!þ:úÖý‡:öûé;È;’ÿÖ&j›Ô7F}ìšsÝÆã®jÙgîcÞèkhH#ꆎáueÿÍ0Kú¶þx“=ŽËÙèwZ½õâ¥4Ÿ(N@}•m±4ù+ïØ`Ž ò¾†Î`2—¹½T=å߉ó=Ÿé;<òË÷:&²SNŸ›yí¯É;mÌióGÞ›ø=m¤ocìuÿ=v5gÇî;›àiŒ[ùt{#íÓ»ÛGN:&±ûš¬ôu¯ìgrõ§»ÉO1¾æ×’ÓÇ<ÖO[½=;3ú‡m3LþòüXl>ÓsÏä[²=®[Æêß­Š¡NáWìÝv™ö´ñò U¶b0ùžlk0nÎ`Þî¼aOÄÔÅN³þuüTç"&¸¹1˜Š‹Á[„¤‰¬d’•V²ÉJ+Yd%•¬²’JVYÉý/ÆÃË9^5jÙØj°[n1l¸ž8?îÍ×qµÈ¶kj³´‰Ùcìfp³,×~³¼Y¾kZ –18áh}ѱeÈÛ‚ ¼Ç¸6÷À'¨ #¨Û'–×§Þh2’ž‰K¨Š*à¶Ü¢OPC©¡‘ÄÃó[ãŠ#qê¬*Î'Ñ“–—s¿ü°UTŽŽQ«T”“a/¹%'“9bŽ \rDn5vŽZ£¢ŸŒ^sš[vœ¾’EçNχk92[ÑQtƒn¤'x~Ï"D"üñš¡ß‰®×j5ŠJÀ’ ^uª[윣«.»b7;e¬dDþdyé¥{g8Q°¥T(Å¡Ž×yóµd,ÅôLå†Sêãn=ëŽÜVzÞÀ[÷Éå•©¼HÈÉå©`Š«iVw”ÞÐ[÷É嵩½tÌr©`ŠËqV‰Qt :žž©¼qêÐ×Ü?H5Óãâ#|V…(¨ªøh¼âTùH(â«oô³Žo«-ÊdøúûßòåÔ9þ°UDŽŽp«. d üàòæT9NXˆ .ÁqØjÕŠ’2¤ ~pyqjÑÛ¹6Yî„ëp\s„·¢Q»±{Ô“•×NMã\,ëªP*.r„jŠª2ªx½¼œâGÂK/ìv¸¡#ªU*Êɰëê®Ê(§^wU°Å…Ž`V‡QwŒ;…Ÿ\^œ*Mz£M®çqÃ5ÕÊj²Šz2òÒ)­¼ËòpVÁ×:²­äQ\W]OU^9ÕŽ‰V_á ðpCG<+ž¨OF^^åU.8Ï­Vä‡ p\säâ‡^ƒO”'Câ—,§õñòKóKõ|ÅxްV¬('^{jO÷r¸,q…#aÕ J¬+øÉå•©ÄlÌsV°Å5ŽŒ+ÄYAVû“åÕTï¦ã½¯sm\ÏãR#ŠÕœª¬(+øÉ嵩Å1Äjõq(Ž‹Ž0«²”YaVÙ“•×NÇB«.ihp½Ž>+Ÿ(N¼úTŸ<äsF°×ìȱbÅ“ÁÚ¡•TN&ýå¾gºå§ñÃMV?QœŒòê§:Q.Žõq(Ž«Ž4­£ö Ì3ÏÌ;3ìΨ9ƒãL„3ãÍ 73ÚÍ\4SÐÌ83ÃÌL23ÇÌ0#^mM”5ÓÕMT5IÓKS%Md4ÑKB/ý¾ÔøÒÙKD/R¼Kï.µº¤æK.½³}©›øÐfâ¦9ÎÆ˜‘:!0cd)‹|5¿\¤‘L›Y£öôƒ‰™E@sÒÉ&Å,òz$zbÂ9Ìø“h ç>àÃ$Ë"_!&­,{“ˆ‹çä@Ä$”EÀssQbÜdøbÅ‚€P$2bÅßÈ ¶“`èBMcb‚hLõXðL¢,n¡sDŽI ‹@t ©è1—± F“˜`¾.ذIƒÅ€_'îø#¤IhE²t‰x lÇ Pzñl` MbX¤Lw j“ ‹Áée€m¯ý³à6‰°Ø–Äx›w°É“øƒpòíx€¹I êI„ŹuH Ý$ñA°| Ah7î?¨&ðë y“Ùƒós`o|ý]Л䜨 ~“ &1ÿ‚ÕÜ€Fæƒàù¼(ÐX<^0hD> @„^,hî¬?±ä¹ßÂßÐ=ˆ°nÁK èƒ û±… ¡ó }Ä_thL:0 › ƒàýC0ÑÝw0h4‚RÑw‹F¹ˆFÁ‹ëÚˆ£ä ðºDbÔhw`FȎĪƒG#â` vÆðѾt14¢‚Ó‡8‘F~ìp¤]s2˜4"”ï·‚“FºAí“¥bä/³?¦k7m¥Ú``±p¥ßpPZ!\ _Zö­1·û˜2­yƒ@õ­(4­‘kZåõL঻ÛS€iEÄ®oAtZ¦ 8´¢ îØ—DžVBƒAîRЧØkTð(ÅkY ;0P>gÈ(Åj0€¿¡JG tJDvB<”WvJ±$x7 ¥Kí)ÊFA8 ¥{½J±™øÄ¸ŸïÉ4£iÉH±z$ ŒG´cq°[CSÄ;“Èz². ᵞFD1,àC?ÄSyJe¶Oü!ääÊ[ˆ„'_H­Þõ›h’ýÐ_&ùºäšþT cDÞÔPä'¾`’õÀÝ¡ïs³ð:¾MÞà7{ËôøÿèoÞ7Á”?—ÞÛ–›ÃŠye¥àzÄEÔ®òÓo¹Ý¡~7†—¥,JߨQÂVõá[ôïŒ5rϲx׿…­¯X5Ñçôz+[”«Î5ÀÛ†=“º%jÎaß+jÞuåò"¶¿ÊïcW7²uÂH§d§Û7{8‘+ãýúà[3¯0Jd½_ê…ÚÒ¯\wé6n«j§$رQ ÒâË%)^í(¿E™W‘ÅÈ×ÝãÍц%“7Ò#¸Â-$Ý܇-vܱ.ýt t7Q’×[6v_Öž+jÔG•·z’$“&Õ¥Ê-Ä}ˆîæ×…± Ô½ûÒéâ’P“Lævâx Ï,µ;èN¸¨9b ]‘U§¹D'µÒÁ¥¹¢•‡“”¿Mû—Çój¤s£|µØyØnCÅ’Ç6%ÝÏ» ±5ɾ@†7}ø/”Z&FrH®ü“3 -‹”}°²l±„U¨×rì‘u?6§±ò`fÉžø þÞŸS-7qrÉ¥“ $ßEøŸÈd_ð owÊÅ‘Q}qáUL¨¢ëáô·©÷^rUr?øÍ‘š–5äB)»ÒØk0~!Ú;L,ë‹}&µ·ŠnNL+ª“ wsâ/+kfç/ÿürºþ ¥ïGtБØiÿU\jWçBÄÿ,Þ6‡¢åªÝË3m!ioÐêÐßÕ…³Iï±zýÝ'0Cr=/ën æWr}*îØ‡´Ia,›þTTq? -c"Jµ•oñCŸRè” Z—ðSñÿ»¶©•°¦åQÖÔŸ£¦t<+ÛO®9¤PÅû -/ÔöÊzÙ¾U|g^ÁzÀÕóQ7 2á›ó©¸Jü²³dš/Ážå»[²2wöÌéïñ-ÿV“0óx>*®ew·–æ;÷ h×éôô,ÍŒáu%qhù‚uµ‘_ŸRGZC‹¤}Y®ÃÅKÉ¡Ÿ™ÀgªÇéŸ7•Ì•ù¯ãéÏP ê%ì…n““.ªBœýtR Ó^@µ ÿVW2æŠÿ ?ÙVuat+`,§·&ȧúuúÙlêøZüøéˆã·¸Še~ðJqf¶×Ð¥C•3óÏÖˆáhq½ÇxG°,NN–{¨r¡kvéxKï¿ÞÃ*ÓóЦ‚1´Þ_ÏíOØ3ÛÓðL’§ÜÑ!ŸêS¥®S—pø´X>9GˆCUÓó³÷GÇ0çøqeš~XorhËæ“u–øeuÊæ b¶ñ)}#ýSQ­t%öÚwµÄýS2=í¬‰9ði}*ÔUËäøÙòðrÓ|ª˜„éüäÜvZj´ÃÜ·jzú³}Ì´éõ(òU5RÔáÏqåqh£ QÇÖšsî>¾•0h=ž\=Åö}O1ª¦üiÿ¡ÝLï?LÚÒ=ìV0*½÷ü Ò½jãß1ÑsMŸ"†+Yd%•¬²’JVYÉ%+¬d’•V²þK4€ùt‹Rßæ#Í^$5£¼õ2óë4Ýíù/™2ÿX¹x@ÍñÏœ/væ ‚Ä´y]:µ­ÿÀ•Sœ §ÚIú}‡=Î>j°²~J4²3òÃ6©¤Ì8†£nkæîâØW®­ô[ßÖAÒ;Ó!³½¾ÿ»O.*£þæTv1>PìΟv>ü6ÎcFò×î·þŒÛr6úalÿ-Z‰¨N¦Å¸÷÷-3ç.i5gïö–Šfæ,ŸÄq³šÙ³(›¬ Œ7ÆNH;ªoH½×‘hqæ¨Òfœ5ß}ÞG–xèGZÜki‡’suG=ŸÁ–™¹—™ÍLMþÆ™`=Urž¦©iæ?SÙ)WevÌý©ÒÞì¡ÌÖ3Ü*æÐ–L³sÞŽÉìÍl™Z½»z¼5ή^;ήMCã˜eÅ3L6ŸpÏ›Z|')Ä/êó3‰²4³OÁzÕÛæ lhêΞV¡'È3“éÕrœPo™q‚‘–¼ãrü_YñIdkA׺žë+Š®ÿúæ^Ô ‘ •¼¶N±â›G¨yþyy½šAê=õsœawÙŒû’•V²ÉJ+Yd%п{7FC28940-9D31-11D0awLZXC (awLò€¨"@„`Œ~<Ê· Ñ$Úpuzzles-20170606.272beef/puzzles.cnt0000644000175000017500000001346613115375151016122 0ustar simonsimon:Title Simon Tatham's Portable Puzzle Collection 1 Contents=Top 1 Chapter 1: Introduction 2 Chapter 1: Introduction=t00000000 1 Chapter 2: Common features 2 Chapter 2: Common features=t00000001 2 Section 2.1: Common actions=t00000002 2 Section 2.2: Specifying games with the game ID=t00000003 2 Section 2.3: The ‘Type’ menu=t00000004 2 Section 2.4: Specifying game parameters on the command line=t00000005 2 Section 2.5: Unix command-line options=t00000006 1 Chapter 3: Net 2 Chapter 3: Net=games.net 2 Section 3.1: Net controls=t00000007 2 Section 3.2: Net parameters=t00000008 1 Chapter 4: Cube 2 Chapter 4: Cube=games.cube 2 Section 4.1: Cube controls=t00000009 2 Section 4.2: Cube parameters=t00000010 1 Chapter 5: Fifteen 2 Chapter 5: Fifteen=games.fifteen 2 Section 5.1: Fifteen controls=t00000011 2 Section 5.2: Fifteen parameters=t00000012 1 Chapter 6: Sixteen 2 Chapter 6: Sixteen=games.sixteen 2 Section 6.1: Sixteen controls=t00000013 2 Section 6.2: Sixteen parameters=t00000014 1 Chapter 7: Twiddle 2 Chapter 7: Twiddle=games.twiddle 2 Section 7.1: Twiddle controls=t00000015 2 Section 7.2: Twiddle parameters=t00000016 1 Chapter 8: Rectangles 2 Chapter 8: Rectangles=games.rectangles 2 Section 8.1: Rectangles controls=t00000017 2 Section 8.2: Rectangles parameters=t00000018 1 Chapter 9: Netslide 2 Chapter 9: Netslide=games.netslide 1 Chapter 10: Pattern 2 Chapter 10: Pattern=games.pattern 2 Section 10.1: Pattern controls=t00000019 2 Section 10.2: Pattern parameters=t00000020 1 Chapter 11: Solo 2 Chapter 11: Solo=games.solo 2 Section 11.1: Solo controls=t00000021 2 Section 11.2: Solo parameters=t00000022 1 Chapter 12: Mines 2 Chapter 12: Mines=games.mines 2 Section 12.1: Mines controls=t00000023 2 Section 12.2: Mines parameters=t00000024 1 Chapter 13: Same Game 2 Chapter 13: Same Game=games.samegame 2 Section 13.1: Same Game controls=t00000025 2 Section 13.2: Same Game parameters=t00000026 1 Chapter 14: Flip 2 Chapter 14: Flip=games.flip 2 Section 14.1: Flip controls=t00000027 2 Section 14.2: Flip parameters=t00000028 1 Chapter 15: Guess 2 Chapter 15: Guess=games.guess 2 Section 15.1: Guess controls=t00000029 2 Section 15.2: Guess parameters=t00000030 1 Chapter 16: Pegs 2 Chapter 16: Pegs=games.pegs 2 Section 16.1: Pegs controls=t00000031 2 Section 16.2: Pegs parameters=t00000032 1 Chapter 17: Dominosa 2 Chapter 17: Dominosa=games.dominosa 2 Section 17.1: Dominosa controls=t00000033 2 Section 17.2: Dominosa parameters=t00000034 1 Chapter 18: Untangle 2 Chapter 18: Untangle=games.untangle 2 Section 18.1: Untangle controls=t00000035 2 Section 18.2: Untangle parameters=t00000036 1 Chapter 19: Black Box 2 Chapter 19: Black Box=games.blackbox 2 Section 19.1: Black Box controls=t00000037 2 Section 19.2: Black Box parameters=t00000038 1 Chapter 20: Slant 2 Chapter 20: Slant=games.slant 2 Section 20.1: Slant controls=t00000039 2 Section 20.2: Slant parameters=t00000040 1 Chapter 21: Light Up 2 Chapter 21: Light Up=games.lightup 2 Section 21.1: Light Up controls=t00000041 2 Section 21.2: Light Up parameters=t00000042 1 Chapter 22: Map 2 Chapter 22: Map=games.map 2 Section 22.1: Map controls=t00000043 2 Section 22.2: Map parameters=t00000044 1 Chapter 23: Loopy 2 Chapter 23: Loopy=games.loopy 2 Section 23.1: Loopy controls=t00000045 2 Section 23.2: Loopy parameters=t00000046 1 Chapter 24: Inertia 2 Chapter 24: Inertia=games.inertia 2 Section 24.1: Inertia controls=t00000047 2 Section 24.2: Inertia parameters=t00000048 1 Chapter 25: Tents 2 Chapter 25: Tents=games.tents 2 Section 25.1: Tents controls=t00000049 2 Section 25.2: Tents parameters=t00000050 1 Chapter 26: Bridges 2 Chapter 26: Bridges=games.bridges 2 Section 26.1: Bridges controls=t00000051 2 Section 26.2: Bridges parameters=t00000052 1 Chapter 27: Unequal 2 Chapter 27: Unequal=games.unequal 2 Section 27.1: Unequal controls=t00000053 2 Section 27.2: Unequal parameters=t00000054 1 Chapter 28: Galaxies 2 Chapter 28: Galaxies=games.galaxies 2 Section 28.1: Galaxies controls=t00000055 2 Section 28.2: Galaxies parameters=t00000056 1 Chapter 29: Filling 2 Chapter 29: Filling=games.filling 2 Section 29.1: Filling controls=t00000057 2 Section 29.2: Filling parameters=t00000058 1 Chapter 30: Keen 2 Chapter 30: Keen=games.keen 2 Section 30.1: Keen controls=t00000059 2 Section 30.2: Keen parameters=t00000060 1 Chapter 31: Towers 2 Chapter 31: Towers=games.towers 2 Section 31.1: Towers controls=t00000061 2 Section 31.2: Towers parameters=t00000062 1 Chapter 32: Singles 2 Chapter 32: Singles=games.singles 2 Section 32.1: Singles controls=t00000063 2 Section 32.2: Singles parameters=t00000064 1 Chapter 33: Magnets 2 Chapter 33: Magnets=games.magnets 2 Section 33.1: Magnets controls=t00000065 2 Section 33.2: Magnets parameters=t00000066 1 Chapter 34: Signpost 2 Chapter 34: Signpost=games.signpost 2 Section 34.1: Signpost controls=t00000067 2 Section 34.2: Signpost parameters=t00000068 1 Chapter 35: Range 2 Chapter 35: Range=games.range 2 Section 35.1: Range controls=t00000069 2 Section 35.2: Range parameters=t00000070 1 Chapter 36: Pearl 2 Chapter 36: Pearl=games.pearl 2 Section 36.1: Pearl controls=t00000071 2 Section 36.2: Pearl parameters=t00000072 1 Chapter 37: Undead 2 Chapter 37: Undead=games.undead 2 Section 37.1: Undead controls=t00000073 2 Section 37.2: Undead parameters=t00000074 1 Chapter 38: Unruly 2 Chapter 38: Unruly=games.unruly 2 Section 38.1: Unruly controls=t00000075 2 Section 38.2: Unruly parameters=t00000076 1 Chapter 39: Flood 2 Chapter 39: Flood=games.flood 2 Section 39.1: Flood controls=t00000077 2 Section 39.2: Flood parameters=t00000078 1 Chapter 40: Tracks 2 Chapter 40: Tracks=games.tracks 2 Section 40.1: Tracks controls=t00000079 2 Section 40.2: Tracks parameters=t00000080 1 Chapter 41: Palisade 2 Chapter 41: Palisade=games.palisade 2 Section 41.1: Palisade controls=t00000081 2 Section 41.2: Palisade parameters=t00000082 1 Appendix A: Licence 2 Appendix A: Licence=t00000083 puzzles-20170606.272beef/puzzles.hlp0000644000175000017500000061145213115375151016120 0ustar simonsimon?_ûÿÿÿÿ*/&;)L4ÿÿ||ÿÿÿÿY c°¥_#2mo½« ÄT( LÆ9 %–ö‹ñ‚ u™d@U‚JÙ³Jiˆ8CãK^xÄùNuŠyÄùNMzÄùN–{ÄùN˜ |ÄùN¶…}ÄùN ‰~ÄùN-ÄùNÖ €ÄùNÄùNɆ£ÄùN,‚¤ÄùNˆ¥ÄùNö ¦ÄùN1…§ÄùN¨ÄùN}©ÄùN ªÄùNˆ«ÄùN’†¬ÄùNÎÄùN! ÏÄùNH ÐÄùNÔƒ ÑÄùNæ‡ ÒÄùN¨ ÓÄùNj ÔÄùNŠ„ ÕÄùNC ÖÄùN¬ ×ÄùNç ùÄùN¿† úÄùN“‰ ûÄùN“ üÄùN¡ ýÄùNªˆ þÄùNC ÿÄùNí ÅùN ÅùN… ÅùNC€ $ÅùN%ÅùNЄ&ÅùN['ÅùN€(ÅùNæ„)ÅùN*ÅùN¯+ÅùNE,ÅùN‹…-ÅùNûˆ OÅùNEPÅùNǃQÅùNÕˆRÅùNCSÅùNÆTÅùNÜUÅùN …VÅùNCWÅùNÛXÅùNzÅùN¬…{ÅùNŠ|ÅùNª}ÅùNC€~ÅùN§ƒÅùNI†€ÅùNÛÅùN‚ÅùN€ƒÅùN  ¥ÅùNˆ¦ÅùN‰§ÅùNήÅùN¹‚ûÅùNûƒüÅùNG…ýÅùNPþÅùNމÿÅùN‹ÆùNPÆùN™ŠÆùNÏÆùNR„ÆùNDÐYFQiÌAR&$Þ`ƒ‚Drnâ…W‹p<»½Ëp†† Šæ‰Ï£³ Y {,¾¯ “&ø¶Æ÷N½W˵½FˆiGH¿ˆØJÝØ²…¯YmÙ%ˆ (¬Ù¥ƒÎý©Ú©„ õ×ÖÚ.ÿ!nÛ~€M‘Ûå 6‘Û‰‡ùÑÛâsÜÊ +?ܧ K’¦à `RáÓ PãUáUòÀ[áÑ,Òaál ò¾eá¿ êá hArialCourier NewTimes New Roman/ & ;)F24ÿÿÊ lÿÿ15-puzzleBlack BoxBridgesCube DominosaEdit menuFifteenFile menuFilling Flip$Flood(FreeNet,Futoshiki0Galaxies4Game menu8Guess@HitoriDID formatHID, gameLInertiaPJankoTKeen\KenKen`Latin squaredLight UphLinuxlLoopytMIT licencexMac OS X€MagnetsMap”Mastermind˜MinesœNETGAME.EXE Net¤NetWalk¨Netslide¬Nikoli °PalisadeàPatternäPearlèPegsìPlanarityðPostScriptôPuzzle PalaceøRandom SeedüRangeRectanglesSame GameSignpost SinglesSixteenSkyscrapersSlantSolitaire, Peg Solo$Tents(Towers,Tracks0Twiddle4Type menu8Undead<Unequal@UnixDUnrulyLUntanglePWindowsTbugs\command line`common featureslcontrolspcontrols, for Black Boxtcontrols, for Bridgesxcontrols, for Cube|controls, for Dominosa€controls, for Fifteen„controls, for Fillingˆcontrols, for FlipŒcontrols, for Floodcontrols, for Galaxies”controls, for Guess˜controls, for Inertiaœcontrols, for Keen controls, for Light Up¤controls, for Loopy¨controls, for Magnets¬controls, for Map°controls, for Mines´controls, for Net¸controls, for Netslide¼controls, for PalisadeÀcontrols, for PatternÄcontrols, for PearlÈcontrols, for PegsÌcontrols, for RangeÐcontrols, for RectanglesÔcontrols, for Same GameØcontrols, for SignpostÜcontrols, for Singlesàcontrols, for Sixteenäcontrols, for Slantècontrols, for Soloìcontrols, for Tentsðcontrols, for Towersôcontrols, for Tracksøcontrols, for Twiddleücontrols, for Undeadcontrols, for UnequalQcontrols, for Unrulycontrols, for Untangle copycopyrightdefault parameters, specifyingexitfeedback format, ID$four-colouring(game ID,game ID, format0game ID, generating4generating game IDs8initial state<keys@keys, for Black BoxDkeys, for CubeHkeys, for FifteenLkeys, for FlipPkeys, for GuessTkeys, for InertiaXkeys, for Net\keys, for Same Game`licencedlicence, MIThloadpnew gamexnonograms|parameters€parameters, for Black Boxˆparameters, for BridgesŒparameters, for Cubeparameters, for Dominosa”parameters, for Fifteen˜parameters, for Fillingœparameters, for Flood parameters, for Galaxies¤parameters, for Guess¨parameters, for Inertia¬parameters, for Keen°parameters, for Light Up´parameters, for Loopy¸parameters, for Magnets¼parameters, for MapÀparameters, for MinesÄparameters, for NetÈparameters, for NetslideÌparameters, for PalisadeÐparameters, for PatternÔparameters, for PearlØparameters, for PegsÜparameters, for Rangeàparameters, for Rectanglesäparameters, for Same Gameèparameters, for Signpostìparameters, for Singlesðparameters, for Sixteenôparameters, for Slantøparameters, for Soloüparameters, for Tentsparameters, for Towersparameters, for Tracksparameters, for Twiddle parameters, for Undeadparameters, for Unequalparameters, for Unrulyparameters, for Untangleparameters, for flip patches$preferences, specifying default(preset,printing, on Unix0printing, on Windows4quit8redo<restart game@saveDshortcuts (keyboard)Lshortcuts (keyboard), for Black BoxPshortcuts (keyboard), for CubeTshortcuts (keyboard), for FifteenX£ ÿÿshortcuts (keyboard), for Flip\shortcuts (keyboard), for Guess`shortcuts (keyboard), for Inertiadshortcuts (keyboard), for Nethshortcuts (keyboard), for Same Gamelsolvepsource codetstate, initialxundo|version€website„‘Custom’, menu optionˆ‘Specific’, menu optionŒÂcontrols, for Unrulyshortcuts (keyboard), for Flip™iˆY ÆÓ « G…iˆG…^U%ˆ‰‡æ‰U‚G…P¥ƒâ…PP &iÑÑæ‰ñ‚ DP©„ DÎDG…P‹&å ¥ƒ.‰‡‰‡‰‡†¿Ê ñ‚ ©„ ÆU‚^â…â~€²…²…ˆ~€l PPâFˆiâ…<¥Ê l ¿§ ¥ƒ‚މæ‰DP% D‰‡DP‹PûƒG…Š„ R„Ôƒ uН Ûæ„’†í ‹…¿† ªˆ Æ“ ö ™Š†ˆ¬…! Û- …Õˆ–¬ ,‚… E€¶…ª[§ƒ¨ G…΋G…DPå PPPPPG…Š„ R„uŠ ’†í ™ŠÎDÎG…PG…ˆPމC ЄɆæ‡ MEç  “‰ C Ü¡ 1…φ‰ŠH   Ö }CC˜ C€ ˆûˆ ǃ¹‚ ‰C€€I†j ˆD‹މPG…G…G…G…G…PG…Š„ R„uŠ ’†í ™ŠG…DPG…PDމPl½ull!iú5Y  #CB("btn_about","&About","About()") CB("btn_up","&Up","Contents()")BrowseButtons()*Simon Tatham's Portable Puzzle Collection°This manual is copyright 2004-2014 Simon Tatham. All rights reserved. You may distribute this documentation under the MIT licence. See appendix A for the licence text in full.>È5Èÿÿÿÿ FÿÿÿÿR1n ÿÿÿÿDR¡À ContentsDB("btn_up")O, ¡# €X€€‚ÿSimon Tatham's Portable Puzzle Collection^9Rÿ% €r€˜€€‚ÿThis is a collection of small one-player puzzle games.à´¡ß, &€i€˜€€ã§ÅùN‰‚ÿThis manual is copyright 2004-2014 Simon Tatham. All rights reserved. You may distribute this documentation under the MIT licence. See appendix A for the licence text in full.Mÿ,/ .€<€ãÆùN€€€‰‚ÿChapter 1: IntroductionP!ß|/ .€B€ãûÅùN€€€‰‚ÿChapter 2: Common featuresD,À/ .€*€ã6‘Û€€€‰‚ÿChapter 3: NetE|/ .€,€ã`Rက€‰‚ÿChapter 4: CubeHÀM/ .€2€ãJÙ³J€€€‰‚ÿChapter 5: FifteenH•/ .€2€ãW‹p€€€‰‚ÿChapter 6: SixteenHMÝ/ .€2€ã$Þ`€€€‰‚ÿChapter 7: TwiddleK•(/ .€8€ã÷N½€€€‰‚ÿChapter 8: RectanglesIÝq/ .€4€ã»½Ëp€€€‰‚ÿChapter 9: NetslideI(º/ .€4€ãiGH¿€€€‰‚ÿChapter 10: PatternFq/ .€.€ãò¾eက€‰‚ÿChapter 11: SoloGºG/ .€0€ãõ×ÖÚ€€€‰‚ÿChapter 12: MinesK’/ .€8€ãW˵½€€€‰‚ÿChapter 13: Same GameFGØ/ .€.€ãPãUက€‰‚ÿChapter 14: FlipG’/ .€0€ã (¬Ù€€€‰‚ÿChapter 15: GuessFØe/ .€.€ã,Òaက€‰‚ÿChapter 16: PegsJ¯/ .€6€ãmo½€€€‰‚ÿChapter 17: DominosaJeù/ .€6€ã{,¾¯€€€‰‚ÿChapter 18: UntangleK¯D/ .€8€ãÏ£³ €€€‰‚ÿChapter 19: Black BoxGù‹/ .€0€ãsÜ€€€‰‚ÿChapter 20: SlantJDÕ/ .€6€ã–ö‹€€€‰‚ÿChapter 21: Light UpE‹/ .€,€ãM‘Û€€€‰‚ÿChapter 22: MapGÕa/ .€0€ãÎý©Ú€€€‰‚ÿChapter 23: LoopyIª/ .€4€ãK’¦à€€€‰‚ÿChapter 24: InertiaGañ/ .€0€ã+?Ü€€€‰‚ÿChapter 25: TentsIª: / .€4€ã“&ø¶€€€‰‚ÿChapter 26: BridgesIñƒ / .€4€ã† Š€€€‰‚ÿChapter 27: UnequalJ: Í / .€6€ãu™d@€€€‰‚ÿChapter 28: GalaxiesIƒ  / .€4€ã8CãK€€€‰‚ÿChapter 29: FillingFÍ \ / .€.€ãòÀ[က€‰‚ÿChapter 30: KeenH ¤ / .€2€ãc°€€€‰‚ÿChapter 31: TowersI\ í / .€4€ãDrn€€€‰‚ÿChapter 32: SinglesI¤ 6 / .€4€ãÌAR€€€‰‚ÿChapter 33: MagnetsJí € / .€6€ãÐYFQ€€€‰‚ÿChapter 34: SignpostG6 Ç / .€0€ãùÑÛ€€€‰‚ÿChapter 35: RangeG€  / .€0€ãÿ!nÛ€€€‰‚ÿChapter 36: PearlHÇ V / .€2€ãÄT( €€€‰‚ÿChapter 37: UndeadH ž / .€2€ãLÆ9 €€€‰‚ÿChapter 38: UnrulyGV å / .€0€ã¯YmÙ€€€‰‚ÿChapter 39: FloodHž - / .€2€ã_#2€€€‰‚ÿChapter 40: TracksJå w / .€6€ãØJÝØ€€€‰‚ÿChapter 41: PalisadeI- À / .€4€ã§ÅùN€€€‰‚ÿAppendix A: LicencerAw 21Öûƒ2wGChapter 1: IntroductionCBB("btn_up","JI(`',`Top')");EB("btn_up")EÀ w) "€8€€€€‚ÿChapter 1: Introduction£}2&B& €û€˜€€‚ÿI wrote this collection because I thought there should be more small desktop toys available: little games you can pop up in a window and play for two or three minutes while you take a break from whatever else you were doing. And I was also annoyed that every time I found a good game on (say) Unix, it wasn't available the next time I was sitting at a Wiw&BÀ ndows machine, or vice versa; so I arranged that everything in my personal puzzle collection will happily run on both, and have more recently done a port to Mac OS X as well. When I find (or perhaps invent) further puzzle games that I like, they'll be added to this collection and will immediately be available on both platforms. And if anyone feels like writing any other front ends – PocketPC, Mac OS pre-10, or whatever it might be – then all the games in this framework will immediately become available on another platform as well.„^wªC& €½€˜€€‚ÿThe actual games in this collection were mostly not my invention; they are re-implementations of existing game concepts within my portable puzzle framework. I do not claim credit, in general, for inventing the rules of any of these puzzles. (I don't even claim authorship of all the code; some of the puzzles have been submitted by other authors.)#÷&BÍD, &€ï€˜€€ã§ÅùN‰‚ÿThis collection is distributed under the MIT licence (see appendix A). This means that you can do pretty much anything you like with the game binaries or the code, except pretending you wrote them yourself, or suing me if anything goes wrong.¡vªCnE+ &€ì€˜€€€€‚ÿThe most recent versions, and source code, can be found at https://www.chiark.greenend.org.uk/~sgtatham/puzzles/.žsÍD F+ &€æ€˜€€€€‚ÿPlease report bugs to anakin@pobox.com. You might find it helpful to read this article before reporting a bug:^9nEjF% €r€˜€€‚ÿhttps://www.chiark.greenend.org.uk/~sgtatham/bugs.htmlª„ FG& € €˜€€‚ÿPatches are welcome. Especially if they provide a new front end (to make all these games run on another platform), or a new game.uDjF‰G1…DG…‰GÑGJChapter 2: Common featuresCBB("btn_up","JI(`',`Top')");EB("btn_up")HGÑG) "€>€€€€‚ÿChapter 2: Common featuresiD‰G:H% €ˆ€˜€€‚ÿThis chapter describes features that are common to all the games.Q"ÑG‹H/ .€D€ãüÅùN€€€‰‚ÿSection 2.1: Common actionsd5:HïH/ .€j€ãýÅùN€€€‰‚ÿSection 2.2: Specifying games with the game IDR#‹HAI/ .€F€ãþÅùN€€€‰‚ÿSection 2.3: The ‘Type’ menuqBïH²I/ .€„€ãÿÅùN€€€‰‚ÿSection 2.4: Specifying game parameters on the command line\-AIJ/ .€Z€ãÆùN€€€‰‚ÿSection 2.5: Unix command-line options|K²IŠJ1gûƒPŠJÓJýˆSection 2.1: Common actionsCBB("btn_up","JI(`',`t00000001')");EB("btn_up")I JÓJ) "€@€€€€‚ÿSection 2.1: Common actions¢}ŠJuK% €ú€˜€€‚ÿThese actions are all available from the ‘Game’ menu and via keyboard shortcuts, in addition to any game-specific actions.ª„ÓJL& € €˜€€‚ÿ(On Mac OS X, to conform with local user interface standards, these actions are situated on the ‘File’ and ‘Edit’ menus instead.)DuKcL( €8€˜€€€‚ÿNew game (‘N’, Ctrl+‘N’)X2L»L& €d€˜‘€€‚ÿStarts a new game, with a random initial state.4cLïL% €€˜€€‚ÿRestart gamelF»L[M& €Œ€˜‘€€‚ÿResets the current game to its initial state. (This can be undone.),ïL‡M% €€˜€€‚ÿLoadP*[M×M& €T€˜‘€€‚ÿLoads a saved game from a file on disk.,‡MN% €€˜€€‚ÿSave`:×McN& €t€˜‘€€‚ÿSaves the current state of your game to a file on disk.¾—N!O' €/€˜‘€€‚ÿThe Load and Save operations preserve your entire game history (so you can save, reload, and still Undo and Redo things you had done before saving).-cNNO% €€˜€€‚ÿPrintwP!OÑ€' €¡€˜‘€€‚ÿWhere supported (currently only on Windows), brings up a dialog allowing you to print an arbitrary number of puzzles randomly generated frNOÑ€Jom the current parameters, optionally including the current puzzle. (Only for puzzles which make sense to print, of course – it's hard to think of a sensible printable representation of Fifteen!)J"NO( €D€˜€€€‚ÿUndo (‘U’, Ctrl+‘Z’, Ctrl+‘_’)uOÑ€& €ž€˜‘€€‚ÿUndoes a single move. (You can undo moves back to the start of the session.)@Ð( €0€˜€€€‚ÿRedo (‘R’, Ctrl+‘R’)I#‚& €F€˜‘€€‚ÿRedoes a previously undone move.,ÐE‚% €€˜€€‚ÿCopyì‚Xƒ' €Ù€˜‘€€‚ÿCopies the current state of your game to the clipboard in text format, so that you can paste it into (say) an e-mail client or a web message board if you're discussing the game with someone else. (Not all games support this feature.)-E‚…ƒ% €€˜€€‚ÿSolvej=Xƒï…- (€{€˜‘€€€€‚ÿTransforms the puzzle instantly into its solved state. For some games (Cube) this feature is not supported at all because it is of no particular use. For other games (such as Pattern), the solved state can be used to give you information, if you can't see how a solution can exist at all or you want to know where you made a mistake. For still other games (such as Sixteen), automatic solution tells you nothing about how to get to the solution, but it does provide a useful way to get there quickly so that you can experiment with set-piece moves and transformations.•h…ƒ„‡- (€Ñ€˜‘€€€€‚ÿSome games (such as Solo) are capable of solving a game ID you have typed in from elsewhere. Other games (such as Rectangles) cannot solve a game ID they didn't invent themself, but when they did invent the game ID they know what the solution is already. Still other games (Pattern) can solve some external game IDs, but only if they aren't too difficult.ðÉï…tˆ' €“€˜‘€€‚ÿThe ‘Solve’ command adds the solved state to the end of the undo chain for the puzzle. In other words, if you want to go back to solving it yourself after seeing the answer, you can just press Undo.@„‡´ˆ( €0€˜€€€‚ÿQuit (‘Q’, Ctrl+‘Q’)I#tˆýˆ& €F€˜‘€€‚ÿCloses the application entirely.^´ˆŒ‰1ëG…މŒ‰è‰ƒÌSection 2.2: Specifying games with the game IDCBB("btn_up","JI(`',`t00000001')");EB("btn_up")\3ýˆè‰) "€f€€€€‚ÿSection 2.2: Specifying games with the game IDº”Œ‰¢Š& €)€˜€€‚ÿThere are two ways to save a game specification out of a puzzle and recreate it later, or recreate it in somebody else's copy of the same puzzle.üÖ艞‹& €­€˜€€‚ÿThe ‘Specific’ and ‘Random Seed’ options from the ‘Game’ menu (or the ‘File’ menu, on Mac OS X) each show a piece of text (a ‘game ID’) which is sufficient to reconstruct precisely the same game at a later date.O#¢ŠíŒ, &€G€˜€€ãÿÅùN‰‚ÿYou can enter either of these pieces of text back into the program (via the same ‘Specific’ or ‘Random Seed’ menu options) at a later point, and it will recreate the same game. You can also use either one as a command line argument (on Windows or Unix); see section 2.4 for more detail.M!ž‹:Ž, &€C€˜€€€€‚ÿThe difference between the two forms is that a descriptive game ID is a literal description of the initial state of the game, whereas a random seed is just a piece of arbitrary text which was provided as input to the random number generator used to create the puzzle. This means that:g-팡: B€[€T˜‘€8‚€ƒ€ã`Rቀ€‚ÿ•Descriptive game IDs tend to be longer in many puzzles (although some, such as Cube (chapter 4), only need very short descriptions). So a random seed is often a quicker way to note down the puzzle you're currently playing, or to tell it to somebody else so they can play the same one as you. Û:޶Á. *€·€T˜‘€8‚€ƒ€‚ÿ•Any text at all is a valid random seed. The a¡¶Áýˆutomatically generated ones are fifteen-digit numbers, but anything will do; you can type in your full name, or a word you just made up, and a valid puzzle will be generated from it. This provides a way for two or more people to race to complete the same puzzle: you think of a random seed, then everybody types it in at the same time, and nobody has an advantage due to having seen the generated puzzle before anybody else.ಡ–Â. *€e€T˜‘€8‚€ƒ€‚ÿ•It is often possible to convert puzzles from other sources (such as ‘nonograms’ or ‘sudoku’ from newspapers) into descriptive game IDs suitable for use with these programs.ð¼¶Á†Ä4 6€y€T˜‘€8‚€ƒ€€€‚ÿ•Random seeds are not guaranteed to produce the same result if you use them with a different version of the puzzle program. This is because the generation algorithm might have been improved or modified in later versions of the code, and will therefore produce a different result when given the same sequence of random numbers. Use a descriptive game ID if you aren't sure that it will be used on the same version of the program as yours.ã¼–ÂiÅ' €y€˜‘€€‚ÿ(Use the ‘About’ menu option to find out the version number of the program. Programs with the same version number running on different platforms should still be random-seed compatible.)uI†ÄÞÆ, &€“€˜€€€€‚ÿA descriptive game ID starts with a piece of text which encodes the parameters of the current game (such as grid size). Then there is a colon, and after that is the description of the game's initial state. A random seed starts with a similar string of parameters, but then it contains a hash sign followed by arbitrary data.X&iÅ6È2 2€M€˜€€€€€€‚ÿIf you enter a descriptive game ID, the program will not be able to show you the random seed which generated it, since it wasn't generated from a random seed. If you enter a random seed, however, the program will be able to show you the descriptive game ID derived from that random seed.öÄÞÆ,Ê2 2€‰€˜€€€€ãò¾eቂÿNote that the game parameter strings are not always identical between the two forms. For some games, there will be parameter data provided with the random seed which is not included in the descriptive game ID. This is because that parameter information is only relevant when generating puzzle grids, and is not important when playing them. Thus, for example, the difficulty level in Solo (chapter 11) is not mentioned in the descriptive game ID.W16ȃÌ& €c€˜€€‚ÿThese additional parameters are also not set permanently if you type in a game ID. For example, suppose you have Solo set to ‘Advanced’ difficulty level, and then a friend wants your help with a ‘Trivial’ puzzle; so the friend reads out a random seed specifying ‘Trivial’ difficulty, and you type it in. The program will generate you the same ‘Trivial’ grid which your friend was having trouble with, but once you have finished playing it, when you ask for a new game it will automatically go back to the ‘Advanced’ difficulty which it was previously set on.}L,ÊÍ1øP‹ÍJÍøÎSection 2.3: The ‘Type’ menuCBB("btn_up","JI(`',`t00000001')");EB("btn_up")J!ƒÌJÍ) "€B€€€€‚ÿSection 2.3: The ‘Type’ menuÄžÍÎ& €=€˜€€‚ÿThe ‘Type’ menu, if present, may contain a list of preset game settings. Selecting one of these will start a new random game with the parameters specified.êÄJÍøÎ& €‰€˜€€‚ÿThe ‘Type’ menu may also contain a ‘Custom’ option which allows you to fine-tune game parameters. The parameters available are specific to each game and are described in the following sections.œkΔÏ1 މP”Ï ºSection 2.4: Specifying game parameters on the command lineCBB("btn_up","JI(`',`t00000001')");EB("btn_up")i@øÎ ) "€€€€€€‚ÿSection 2.4: Specifying game parameters on the command line”Ï øÎ^9”Ïj% €r€˜€€‚ÿ(This section does not apply to the Mac OS X version.)`: Ê& €u€˜€€‚ÿThe games in this collection deliberately do not ever save information on to the computer they run on: they have no high score tables and no saved preferences. (This is because I expect at least some people to play them at work, and those people will probably appreciate leaving as little evidence as possible!)º”j„& €)€˜€€‚ÿHowever, if you do want to arrange for one of these games to default to a particular set of parameters, you can specify them on the command line.ܪÊ`2 2€U€˜€€ãþÅùN‰ãýÅùN‰‚ÿThe easiest way to do this is to set up the parameters you want using the ‘Type’ menu (see section 2.3), and then to select ‘Random Seed’ from the ‘Game’ or ‘File’ menu (see section 2.2). The text in the ‘Game ID’ box will be composed of two parts, separated by a hash. The first of these parts represents the game parameters (the size of the playing area, for example, and anything else you set using the ‘Type’ menu). {„% €ö€˜€€‚ÿIf you run the game with just that parameter text on the command line, it will start up with the settings you specified.t6`t> J€m€˜€€ã`Rቀ€€€€€‚ÿFor example: if you run Cube (see chapter 4), select ‘Octahedron’ from the ‘Type’ menu, and then go to the game ID selection, you will see a string of the form ‘o2x2#338686542711620’. Take only the part before the hash (‘o2x2’), and start Cube with that text on the command line: ‘PREFIX-cube o2x2’.#÷—, &€ï€˜€€€€‚ÿIf you copy the entire game ID on to the command line, the game will start up in the specific game that was described. This is occasionally a more convenient way to start a particular game ID than by pasting it into the game ID selection box.#÷tº, &€ï€˜€€ãýÅùN‰‚ÿ(You could also retrieve the encoded game parameters using the ‘Specific’ menu option instead of ‘Random Seed’, but if you do then some options, such as the difficulty level in Solo, will be missing. See section 2.2 for more details on this.)‡V—A 1Ó‹‰‡A •  KSection 2.5: Unix command-line optionsCBB("btn_up","JI(`',`t00000001')");EB("btn_up")T+º• ) "€V€€€€‚ÿSection 2.5: Unix command-line optionsU0A ê % €`€˜€€‚ÿ(This section only applies to the Unix port.)­• — , &€€˜€€ãÿÅùN‰‚ÿIn addition to being able to specify game parameters on the command line (see section 2.4), there are various other options:. ê Å % €€˜€€‚ÿ--game. — ó % €€˜€€‚ÿ--load.Å ! ' €€˜‘€€‚ÿThese options respectively determine whether the command-line argument is treated as specifying game parameters or a save file to load. Only one should be specified. If neither of these options is specified, a guess is made based on the format of the argument.8ó Y ( € €˜€€€‚ÿ--generate n)! ‚ ' €€˜‘€€‚ÿIf this option is specified, instead of a puzzle being displayed, a number of descriptive game IDs will be invented and printed on standard output. This is useful for gaining access to the game generation algorithms without necessarily using the frontend.¿˜Y A' €1€˜‘€€‚ÿIf game parameters are specified on the command-line, they will be used to generate the game IDs; otherwise a default set of parameters will be used.²…‚ ó- (€ €˜‘€€€€‚ÿThe most common use of this option is in conjunction with --print, in which case its behaviour is slightly different; see below.?A2. ,€"€˜€€€€€‚ÿ--print wxhÖ¯ó@' €_€˜‘€€‚ÿIf this option is specified, instead of a puzzle being displayed, a printed representation of one or more unsolved puzzles is sent to standard output, in PostScript f2@ºormat.ÍŽ2á@? L€€˜‘€€€€€€€€€€‚ÿOn each page of puzzles, there will be w across and h down. If there are more puzzles than w×h, more than one page will be printed.O@0B9 @€-€˜‘€€€€ãýÅùN‰€€‚ÿIf --generate has also been specified, the invented game IDs will be used to generate the printed output. Otherwise, a list of game IDs is expected on standard input (which can be descriptive or random seeds; see section 2.2), in the same format produced by --generate.5á@eB& €€˜‘€€‚ÿFor example:X20B½B& €d€˜‘€€‚ÿPREFIX-net --generate 12 --print 2x3 7x7w | lpròÅeB¯C- (€‹€˜‘€€€€‚ÿwill generate two pages of printed Net puzzles (each of which will have a 7×7 wrapping grid), and pipe the output to the lpr command, which on many systems will send them to an actual printer.jD½BD& €ˆ€˜‘€€‚ÿThere are various other options which affect printing; see below.l8¯C…D4 8€p€˜€€€€€€€‚ÿ--save file-prefix [ --save-suffix file-suffix ]æ¿DkE' €€˜‘€€‚ÿIf this option is specified, instead of a puzzle being displayed, saved-game files for one or more unsolved puzzles are written to files constructed from the supplied prefix and/or suffix.O…DºF9 @€-€˜‘€€€€ãýÅùN‰€€‚ÿIf --generate has also been specified, the invented game IDs will be used to generate the printed output. Otherwise, a list of game IDs is expected on standard input (which can be descriptive or random seeds; see section 2.2), in the same format produced by --generate.5kEïF& €€˜‘€€‚ÿFor example:`:ºFOG& €t€˜‘€€‚ÿPREFIX-net --generate 12 --save game --save-suffix .savŠXïFÙG2 4€°€˜‘€€€€€€‚ÿwill generate twelve Net saved-game files with the names game0.sav to game11.sav.1 OG H% €€˜€€‚ÿ--versionc=ÙGmH& €z€˜‘€€‚ÿPrints version information about the game, and then quits.wL HäH+ &€˜€˜€€€€‚ÿThe following options are only meaningful if --print is also specified:8mHI% €&€˜€€‚ÿ--with-solutionsŠdäH¦I& €È€˜‘€€‚ÿThe set of pages filled with unsolved puzzles will be followed by the solutions to those puzzles.5 IÛI( €€˜€€€‚ÿ--scale ng¦IhJ& €Î€˜‘€€‚ÿAdjusts how big each puzzle is when printed. Larger numbers make puzzles bigger; the default is 1.0.0 ÛI˜J% €€˜€€‚ÿ--colourˆbhJ K& €Ä€˜‘€€‚ÿPuzzles will be printed in colour, rather than in black and white (if supported by the puzzle).i8˜J‰K1"P™Š‰KÅK«OChapter 3: NetCBB("btn_up","JI(`',`Top')");EB("btn_up")< KÅK) "€&€€€€‚ÿChapter 3: Net¬u‰KqL7 >€ê€˜€€€€€€€€‚ÿ(Note: the Windows version of this game is called NETGAME.EXE to avoid clashing with Windows's own NET.EXE.)?ÅK°N, &€'€˜€€ã6‘Û‰‚ÿI originally saw this in the form of a Flash game called FreeNet [1], written by Pavils Jurjans; there are several other implementations under the name NetWalk. The computer prepares a network by connecting up the centres of squares in a grid, and then shuffles the network by rotating every tile randomly. Your job is to rotate it all back into place. The successful solution will be an entirely connected network, with no closed loops. As a visual aid, all tiles which are connected to the one in the middle are highlighted.[3qL O( €f€˜€€€‚ÿ[1] http://www.jurjans.lv/stuff/net/FreeNet.htmO °NZO/ .€@€ãÆùN€€€‰‚ÿSection 3.1: Net controlsQ" O«O/ .€D€ãÆùN€€€‰‚ÿSection 3.2: Net parameterszIZO1€1H‰‡Ï 1€x€y‡Section 3.1: Net controlsCBB("btn_u«O1€«Op","JI(`',`games.net')");EB("btn_up")G«Ox€) "€<€€€€‚ÿSection 3.1: Net controlsxS1€ð€% €¦€˜€€‚ÿThis game can be played with either the keyboard or the mouse. The controls are:R*x€B( €T€˜€€€‚ÿSelect tile: mouse pointer, arrow keysa9ð€£( €r€˜€€€‚ÿRotate tile anticlockwise: left mouse button, ‘A’ key^6B‚( €l€˜€€€‚ÿRotate tile clockwise: right mouse button, ‘D’ keyO'£P‚( €N€˜€€€‚ÿRotate tile by 180 degrees: ‘F’ keylD‚¼‚( €ˆ€˜€€€‚ÿLock (or unlock) tile: middle mouse button, shift-click, ‘S’ key¶P‚rƒ' €€˜‘€€‚ÿYou can lock a tile once you're sure of its orientation. You can also unlock it again, but while it's locked you can't accidentally turn it.yT¼‚ëƒ% €¨€˜€€‚ÿThe following controls are not necessary to complete the game, but may be useful:J"rƒ5„( €D€˜€€€‚ÿShift grid: Shift + arrow keys®‡ëƒã„' €€˜‘€€‚ÿOn grids that wrap, you can move the origin of the grid, so that tiles that were on opposite sides of the grid can be seen together.J"5„-…( €D€˜€€€‚ÿMove centre: Ctrl + arrow keys0 ã„]†' €€˜‘€€‚ÿYou can change which tile is used as the source of highlighting. (It doesn't ultimately matter which tile this is, as every tile will be connected to every other tile in a correct solution, but it may be helpful in the intermediate stages of solving the puzzle.)A-…ž†( €2€˜€€€‚ÿJumble tiles: ‘J’ keymG]† ‡& €Ž€˜‘€€‚ÿThis key turns all tiles that are not locked to random orientations.nCž†y‡+ &€†€˜€€ãüÅùN‰‚ÿ(All the actions described in section 2.1 are also available.)|K ‡õ‡1¿™ŠÓ  õ‡>ˆ´Section 3.2: Net parametersCBB("btn_up","JI(`',`games.net')");EB("btn_up")I y‡>ˆ) "€@€€€€‚ÿSection 3.2: Net parametersvQõ‡´ˆ% €¢€˜€€‚ÿThese parameters are available from the ‘Custom...’ option on the ‘Type’ menu.=>ˆñˆ+ &€$€˜€€€€‚ÿWidth, Height?´ˆ0‰& €2€˜‘€€‚ÿSize of grid in tiles.9ñˆi‰% €(€˜€€‚ÿWalls wrap aroundj0‰ù‰& €Ô€˜‘€€‚ÿIf checked, flow can pass from the left edge to the right edge, and from top to bottom, and vice versa.;i‰4Š% €,€˜€€‚ÿBarrier probability$ýù‰X‹' €û€˜‘€€‚ÿA number between 0.0 and 1.0 controlling whether an immovable barrier is placed between two tiles to prevent flow between them (a higher number gives more barriers). Since barriers are immovable, they act as constraints on the solution (i.e., hints).¢o4Šú3 4€ß€˜‘€€ãýÅùN‰€€‚ÿThe grid generation in Net has been carefully arranged so that the barriers are independent of the rest of the grid. This means that if you note down the random seed used to generate the current puzzle (see section 2.2), change the Barrier probability parameter, and then re-enter the same random seed, you should see exactly the same starting grid, with the only change being the number of barriers. So if you're stuck on a particular grid and need a hint, you could start up another instance of Net, set up the same parameters but a higher barrier probability, and enter the game seed from the original Net window.>X‹8Ž% €2€˜€€‚ÿEnsure unique solution|Oú´- (€Ÿ€˜‘€€€€‚ÿNormally, Net will make sure that the puzzles it presents have only one solution. Puzzles with ambiguous sections can be more difficult and more subtle, so if you like you can turn off this feature and risk having ambiguous puzzles. (Also, finding all the possible solutions can be an additional challenge for an advanced player.)j98Ž*À1SÏR„ *ÀgÀ}ÅChapter 4: CubeCBB("btn_up´*À´","JI(`',`Top')");EB("btn_up")=´gÀ) "€(€€€€‚ÿChapter 4: CubeÿÓ*ÀfÃ, &€§€˜€€ã`RቂÿThis is another one I originally saw as a web game. This one was a Java game [2], by Paul Scott. You have a grid of 16 squares, six of which are blue; on one square rests a cube. Your move is to use the arrow keys to roll the cube through 90 degrees so that it moves to an adjacent square. If you roll the cube on to a blue square, the blue square is picked up on one face of the cube; if you roll a blue face of the cube on to a non-blue square, the blueness is put down again. (In general, whenever you roll the cube, the two faces that come into contact swap colours.) Your job is to get all six blue squares on to the six faces of the cube at the same time. Count your moves and try to do it in as few as possible.ïgÀ{Ä& €ß€˜€€‚ÿUnlike the original Java game, my version has an additional feature: once you've mastered the game with a cube rolling on a square grid, you can change to a triangular grid and roll any of a tetrahedron, an octahedron or an icosahedron.`8fÃÛÄ( €p€˜€€€‚ÿ[2] http://www3.sympatico.ca/paulscott/cube/cube.htmP!{Ä+Å/ .€B€ãÆùN€€€‰‚ÿSection 4.1: Cube controlsR#ÛÄ}Å/ .€F€ãÄùN€€€‰‚ÿSection 4.2: Cube parameters|K+ÅùÅ1;Ó Ɇ ùÅAÆ4ÉSection 4.1: Cube controlsCBB("btn_up","JI(`',`games.cube')");EB("btn_up")H}ÅAÆ) "€>€€€€‚ÿSection 4.1: Cube controlsfAùŧÆ% €‚€˜€€‚ÿThis game can be played with either the keyboard or the mouse.‹fAÆ2Ç% €Ì€˜€€‚ÿLeft-clicking anywhere on the window will move the cube (or other solid) towards the mouse pointer.”n§ÆÆÈ& €Ý€˜€€‚ÿThe arrow keys can also used to roll the cube on its square grid in the four cardinal directions. On the triangular grids, the mapping of arrow keys to directions is more approximate. Vertical movement is disallowed where it doesn't make sense. The four keys surrounding the arrow keys on the numeric keypad (‘7’, ‘9’, ‘1’, ‘3’) can be used for diagonal movement.nC2Ç4É+ &€†€˜€€ãüÅùN‰‚ÿ(All the actions described in section 2.1 are also available.)~MÆÈ²É1‹R„iˆ ²ÉüÉ=ÌSection 4.2: Cube parametersCBB("btn_up","JI(`',`games.cube')");EB("btn_up")J!4ÉüÉ) "€B€€€€‚ÿSection 4.2: Cube parametersvQ²ÉrÊ% €¢€˜€€‚ÿThese parameters are available from the ‘Custom...’ option on the ‘Type’ menu.5üɧÊ% € €˜€€‚ÿType of solid”nrÊ;Ë& €Ü€˜‘€€‚ÿSelects the solid to roll (and hence the shape of the grid): tetrahedron, cube, octahedron, or icosahedron.L!§Ê‡Ë+ &€B€˜€€€€‚ÿWidth / top, Height / bottom¶;Ë=Ì' €€˜‘€€‚ÿOn a square grid, horizontal and vertical dimensions. On a triangular grid, the number of triangles on the top and bottom rows respectively.m<‡ËªÌ1¿ɆuŠªÌêÌiÏChapter 5: FifteenCBB("btn_up","JI(`',`Top')");EB("btn_up")@=ÌêÌ) "€.€€€€‚ÿChapter 5: Fifteen׫ªÌÁÎ, &€W€˜€€€€‚ÿThe old ones are the best: this is the good old ‘15-puzzle’ with sliding tiles. You have a 4×4 square grid; 15 squares contain numbered tiles, and the sixteenth is empty. Your move is to choose a tile next to the empty space, and slide it into the space. The aim is to end up with the tiles in numerical order, with the space in the bottom right (so that the top row reads 1,2,3,4 and the bottom row reads 13,14,15,space).S$êÌÏ/ .€H€ãxÄùN€€€‰‚ÿSection 5.1: Fifteen controlsU&ÁÎiÏ/ .€L€ãyÄùN€€€‰‚ÿSection 5.2: Fifteen parameters‚QÏ 1>iˆM WJSection 5.1: Fifteen controlsCBB("btn_up","JI(`',`games.fifteen')");EB("btn_up")iÏ iÏK"iÏW) "€D€€€€‚ÿSection 5.1: Fifteen controlsc> º% €|€˜€€‚ÿThis game can be controlled with the mouse or the keyboard.Á›W{& €7€˜€€‚ÿA left-click with the mouse in the row or column containing the empty space will move as many tiles as necessary to move the space to the mouse pointer.¯ƒº*, &€€˜€€€€‚ÿThe arrow keys will move a tile adjacent to the space in the direction indicated (moving the space in the opposite direction).²Œ{Ü& €€˜€€‚ÿPressing ‘h’ will make a suggested move. Pressing ‘h’ enough times will solve the game, but it may scramble your progress while doing so.nC*J+ &€†€˜€€ãüÅùN‰‚ÿ(All the actions described in section 2.1 are also available.)„SÜÎ1JuŠ<ÎSection 5.2: Fifteen parametersCBB("btn_up","JI(`',`games.fifteen')");EB("btn_up")M$J) "€H€€€€‚ÿSection 5.2: Fifteen parametersýËÎ2 2€—€˜€€€€€€‚ÿThe only options available from the ‘Custom...’ option on the ‘Type’ menu are Width and Height, which are self-explanatory. (Once you've changed these, it's not a ‘15-puzzle’ any more, of course!)m<…19M–…ž Chapter 6: SixteenCBB("btn_up","JI(`',`Top')");EB("btn_up")@Å) "€.€€€€‚ÿChapter 6: SixteennB…3, &€…€˜€€ãJÙ³J‰‚ÿAnother sliding tile puzzle, visually similar to Fifteen (see chapter 5) but with a different type of move. This time, there is no hole: all 16 squares on the grid contain numbered squares. Your move is to shift an entire row left or right, or shift an entire column up or down; every time you do that, the tile you shift off the grid re-appears at the other end of the same row, in the space you just vacated. To win, arrange the tiles into numerical order (1,2,3,4 on the top row, 13,14,15,16 on the bottom). When you've done that, try playing on different sizes of grid.ã·Å , &€o€˜€€€€‚ÿI might have invented this game myself, though only by accident if so (and I'm sure other people have independently invented it). I thought I was imitating a screensaver I'd seen, but I have a feeling that the screensaver might actually have been a Fifteen-type puzzle rather than this slightly different kind. So this might be the one thing in my puzzle collection which represents creativity on my part rather than just engineering.S$3i / .€H€ãzÄùN€€€‰‚ÿSection 6.1: Sixteen controlsU& ¾ / .€L€ã{ÄùN€€€‰‚ÿSection 6.2: Sixteen parameters‚Qi @ 1È<˜ @ ‹ Section 6.1: Sixteen controlsCBB("btn_up","JI(`',`games.sixteen')");EB("btn_up")K"¾ ‹ ) "€D€€€€‚ÿSection 6.1: Sixteen controls½—@ H & €/€˜€€‚ÿLeft-clicking on an arrow will move the appropriate row or column in the direction indicated. Right-clicking will move it in the opposite direction.Ñ«‹  & €W€˜€€‚ÿAlternatively, use the cursor keys to move the position indicator around the edge of the grid, and use the return key to move the row/column in the direction indicated.[H š& €·€˜€€‚ÿYou can also move the tiles directly. Move the cursor onto a tile, hold Control and press an arrow key to move the tile under the cursor and move the cursor along with the tile. Or, hold Shift to move only the tile. Pressing Enter simulates holding down Control (press Enter again to release), while pressing Space simulates holding down shift.nC + &€†€˜€€ãüÅùN‰‚ÿ(All the actions described in section 2.1 are also available.)„SšŒ1¨–ƒ‚ŒÙ@CSection 6.2: Sixteen parametersCBB("btn_up","JI(`',`games.sixteen')");EB("btn_up")M$Ù) "€H€€€€‚ÿSection 6.2: Sixteen parameterstOŒY@% €ž€˜€€‚ÿTÙY@he parameters available from the ‘Custom...’ option on the ‘Type’ menu are:l6ÙÅ@6 <€l€T˜‘€8‚€ƒ€€€€‚ÿ•Width and Height, which are self-explanatory.{MY@@C. *€›€T˜‘€8‚€ƒ€‚ÿ•You can ask for a limited shuffling operation to be performed on the grid. By default, Sixteen will shuffle the grid in such a way that any arrangement is about as probable as any other. You can override this by requesting a precise number of shuffling moves to be performed. Typically your aim is then to determine the precise set of shuffling moves and invert them exactly, so that you answer (say) a four-move shuffle with a four-move solution. Note that the more moves you ask for, the more likely it is that solutions shorter than the target length will turn out to be possible.m<Å@­C12˜ ¶…­CíCßGChapter 7: TwiddleCBB("btn_up","JI(`',`Top')");EB("btn_up")@@CíC) "€.€€€€‚ÿChapter 7: TwiddleÖ­CïD, &€­€˜€€ãW‹p‰‚ÿTwiddle is a tile-rearrangement puzzle, visually similar to Sixteen (see chapter 6): you are given a grid of square tiles, each containing a number, and your aim is to arrange the numbers into ascending order.%ÿíCF& €ÿ€˜€€‚ÿIn basic Twiddle, your move is to rotate a square group of four tiles about their common centre. (Orientation is not significant in the basic puzzle, although you can select it.) On more advanced settings, you can rotate a larger square group of tiles.#ýïD7G& €û€˜€€‚ÿI first saw this type of puzzle in the GameCube game ‘Metroid Prime 2’. In the Main Gyro Chamber in that game, there is a puzzle you solve to unlock a door, which is a special case of Twiddle. I developed this game as a generalisation of that puzzle.S$FŠG/ .€H€ã|ÄùN€€€‰‚ÿSection 7.1: Twiddle controlsU&7GßG/ .€L€ã}ÄùN€€€‰‚ÿSection 7.2: Twiddle parameters‚QŠGaH1Bƒ‚ ‰aH¬H£LSection 7.1: Twiddle controlsCBB("btn_up","JI(`',`games.twiddle')");EB("btn_up")K"ßG¬H) "€D€€€€‚ÿSection 7.1: Twiddle controlsòÌaHžI& €™€˜€€‚ÿTo play Twiddle, click the mouse in the centre of the square group you wish to rotate. In the basic mode, you rotate a 2×2 square, which means you have to click at a corner point where four tiles meet.Ý·¬H{J& €o€˜€€‚ÿIn more advanced modes you might be rotating 3×3 or even more at a time; if the size of the square is odd then you simply click in the centre tile of the square you want to rotate.¡|žIK% €ø€˜€€‚ÿClicking with the left mouse button rotates the group anticlockwise. Clicking with the right button rotates it clockwise.ó{J5L& €ç€˜€€‚ÿYou can also move an outline square around the grid with the cursor keys; the square is the size above (2×2 by default, or larger). Pressing the return key or space bar will rotate the current square anticlockwise or clockwise respectively.nCK£L+ &€†€˜€€ãüÅùN‰‚ÿ(All the actions described in section 2.1 are also available.)„S5L'M1€¶…'MtM³ƒSection 7.2: Twiddle parametersCBB("btn_up","JI(`',`games.twiddle')");EB("btn_up")M$£LtM) "€H€€€€‚ÿSection 7.2: Twiddle parameters‚]'MöM% €º€˜€€‚ÿTwiddle provides several configuration options via the ‘Custom’ option on the ‘Type’ menu:m@tMcN- *€€€T˜‘€8‚€ƒ€‚ÿ•You can configure the width and height of the puzzle grid.uHöMØN- *€€T˜‘€8‚€ƒ€‚ÿ•You can configure the size of square block that rotates at a time.W)cN;€. *€S€T˜‘€8‚€ƒ€‚ÿ•You can ask for every square in the grid to be distinguishable (the default), or you can ask for a simplified puzzle in which there are groups of identical numbers. In the simplified puzzle your aim is just to arrange all the 1s into the first roØN;€£Lw, all the 2s into the second row, and so on.ÕØN>. *€«€T˜‘€8‚€ƒ€‚ÿ•You can configure whether the orientation of tiles matters. If you ask for an orientable puzzle, each tile will have a triangle drawn in it. All the triangles must be pointing upwards to complete the puzzle.uG;€³ƒ. *€€T˜‘€8‚€ƒ€‚ÿ•You can ask for a limited shuffling operation to be performed on the grid. By default, Twiddle will shuffle the grid so much that any arrangement is about as probable as any other. You can override this by requesting a precise number of shuffling moves to be performed. Typically your aim is then to determine the precise set of shuffling moves and invert them exactly, so that you answer (say) a four-move shuffle with a four-move solution. Note that the more moves you ask for, the more likely it is that solutions shorter than the target length will turn out to be possible.p?>#„1C ‰-#„f„f‰Chapter 8: RectanglesCBB("btn_up","JI(`',`Top')");EB("btn_up")C³ƒf„) "€4€€€€‚ÿChapter 8: Rectanglesb<#„È…& €y€˜€€‚ÿYou have a grid of squares, with numbers written in some (but not all) of the squares. Your task is to subdivide the grid into rectangles of various sizes, such that (a) every rectangle contains exactly one numbered square, and (b) the area of each rectangle is equal to the number written in its numbered square.è¶f„°‡2 2€m€˜€€ã÷N½‰ã÷N½‰‚ÿCredit for this game goes to the Japanese puzzle magazine Nikoli [3]; I've also seen a Palm implementation at Puzzle Palace [4]. Unlike Puzzle Palace's implementation, my version automatically generates random grids of any size you like. The quality of puzzle design is therefore not quite as good as hand-crafted puzzles would be, but on the plus side you get an inexhaustible supply of puzzles tailored to your own specification.uJÈ…%ˆ+ &€”€˜€€€€‚ÿ[3] http://www.nikoli.co.jp/en/puzzles/shikaku.html (beware of Flash)“k°‡¸ˆ( €Ö€˜€€€‚ÿ[4] https://web.archive.org/web/20041024001459/http://www.puzzle.gr.jp/puzzle/sikaku/palm/index.html.enV'%ˆ‰/ .€N€ã~ÄùN€€€‰‚ÿSection 8.1: Rectangles controlsX)¸ˆf‰/ .€R€ãÄùN€€€‰‚ÿSection 8.2: Rectangles parametersˆW‰î‰1“Ö î‰<ŠŽSection 8.1: Rectangles controlsCBB("btn_up","JI(`',`games.rectangles')");EB("btn_up")N%f‰<Š) "€J€€€€‚ÿSection 8.1: Rectangles controlsZ5Š% €j€˜€€‚ÿThis game is played with the mouse or cursor keys.I#<Šß‹& €G€˜€€‚ÿLeft-click any edge to toggle it on or off, or left-click and drag to draw an entire rectangle (or line) on the grid in one go (removing any existing edges within that rectangle). Right-clicking and dragging will allow you to erase the contents of a rectangle without affecting its edges.Ç¡–Ц& €C€˜€€‚ÿAlternatively, use the cursor keys to move the position indicator around the board. Pressing the return key then allows you to use the cursor keys to drag a rectangle out from that position, and pressing the return key again completes the rectangle. Using the space bar instead of the return key allows you to erase the contents of a rectangle without affecting its edges, as above. Pressing escape cancels a drag.mHß‹Ž% €€˜€€‚ÿWhen a rectangle of the correct size is completed, it will be shaded.nC¦Ž+ &€†€˜€€ãüÅùN‰‚ÿ(All the actions described in section 2.1 are also available.)ŠYŽ 1$-† [;ÇSection 8.2: Rectangles parametersCBB("btn_up","JI(`',`games.rectangles')");EB("btn_up")P'Ž[) "€N€€€€‚ÿSection 8.2: Rectangles parametersvQ Ñ% €¢€˜€€‚ÿThese parameters are available from the ‘Custom...’ option on the ‘Type’ menu.=[À+ &€$€˜€€€€‚ÿWidÑÀŽth, HeightBÑ\À& €8€˜‘€€‚ÿSize of grid, in squares.8À”À% €&€˜€€‚ÿExpansion factorm@\ÀÂ- (€€˜‘€€€€‚ÿThis is a mechanism for changing the type of grids generated by the program. Some people prefer a grid containing a few large rectangles to one containing many small ones. So you can ask Rectangles to essentially generate a smaller grid than the size you specified, and then to expand it by adding rows and columns.Ò«”ÀÓÃ' €W€˜‘€€‚ÿThe default expansion factor of zero means that Rectangles will simply generate a grid of the size you ask for, and do nothing further. If you set an expansion factor of (say) 0.5, it means that each dimension of the grid will be expanded to half again as big after generation. In other words, the initial grid will be 2/3 the size in each dimension, and will be expanded to its full size without adding any more rectangles.l?Â?Å- (€€˜‘€€€€‚ÿSetting an expansion factor of around 0.5 tends to make the game more difficult, and also (in my experience) rewards a less deductive and more intuitive playing style. If you set it too high, though, the game simply cannot generate more than a few rectangles to cover the entire grid, and the game becomes trivial.>ÓÃ}Å% €2€˜€€‚ÿEnsure unique solution¾‘?Å;Ç- (€#€˜‘€€€€‚ÿNormally, Rectangles will make sure that the puzzles it presents have only one solution. Puzzles with ambiguous sections can be more difficult and more subtle, so if you like you can turn off this feature and risk having ambiguous puzzles. Also, finding all the possible solutions can be an additional challenge for an advanced player. Turning off this option can also speed up puzzle generation.n=}Å©Ç1÷Ö ˆ©ÇêÇ ÊChapter 9: NetslideCBB("btn_up","JI(`',`Top')");EB("btn_up")A;ÇêÇ) "€0€€€€‚ÿChapter 9: Netslide*ø©ÇÉ2 2€ñ€˜€€ã6‘Û‰ãW‹p‰‚ÿThis game combines the grid generation of Net (see chapter 3) with the movement of Sixteen (see chapter 6): you have a Net grid, but instead of rotating tiles back into place you have to slide them into place by moving a whole row at a time.yNêÇÉ+ &€œ€˜€€ãzÄùN‰‚ÿAs in Sixteen, control is with the mouse or cursor keys. See section 6.1.¬{É9Ê1 2€ö€˜€€ãÆùN‰ã{ÄùN‰‚ÿThe available game parameters have similar meanings to those in Net (see section 3.2) and Sixteen (see section 6.2).gBÉ Ê% €„€˜€€‚ÿNetslide was contributed to this collection by Richard Boulton.n=9ÊË1ø†ËOËChapter 10: PatternCBB("btn_up","JI(`',`Top')");EB("btn_up")A ÊOË) "€0€€€€‚ÿChapter 10: Patterna;˰Ì& €w€˜€€‚ÿYou have a grid of squares, which must all be filled in either black or white. Beside each row of the grid are listed the lengths of the runs of black squares on that row; above each column are listed the lengths of the runs of black squares in that column. Your aim is to fill in the entire grid black or white.°ŠOË`Í& €€˜€€‚ÿI first saw this puzzle form around 1995, under the name ‘nonograms’. I've seen it in various places since then, under different names.üаÌ\Ï, &€¡€˜€€€€‚ÿNormally, puzzles of this type turn out to be a meaningful picture of something once you've solved them. However, since this version generates the puzzles automatically, they will just look like random groupings of squares. (One user has suggested that this is actually a good thing, since it prevents you from guessing the colour of squares based on the picture, and forces you to use logic instead.) The advantage, though, is that you never run out of them.T%`ͰÏ/ .€J€ã€ÄùN€€€‰‚ÿSection 10.1: Pattern controlsV'\Ï/ .€N€ã¬ÄùN€€€‰‚ÿSection 10.2: Pattern paramet°Ï ÊersƒR°Ï•1)ˆ•á¾Section 10.1: Pattern controlsCBB("btn_up","JI(`',`games.pattern')");EB("btn_up")L#á) "€F€€€€‚ÿSection 10.1: Pattern controlsK&•,% €L€˜€€‚ÿThis game is played with the mouse.óáE& €ç€˜€€‚ÿLeft-click in a square to colour it black. Right-click to colour it white. If you make a mistake, you can middle-click, or hold down Shift while clicking with any button, to colour the square in the default grey (meaning ‘undecided’) again.8,}& €%€˜€€‚ÿYou can click and drag with the left or right mouse button to colour a vertical or horizontal line of squares black or white at a time (respectively). If you click and drag with the middle button, or with Shift held down, you can colour a whole rectangle of squares grey.ùÓEv& €§€˜€€‚ÿYou can also move around the grid with the cursor keys. Pressing the return key will cycle the current cell through empty, then black, then white, then empty, and the space bar does the same cycle in reverse.Ú´}P& €i€˜€€‚ÿMoving the cursor while holding Control will colour the moved-over squares black. Holding Shift will colour the moved-over squares white, and holding both will colour them grey.nCv¾+ &€†€˜€€ãüÅùN‰‚ÿ(All the actions described in section 2.1 are also available.)…TPC1¿C‘ESection 10.2: Pattern parametersCBB("btn_up","JI(`',`games.pattern')");EB("btn_up")N%¾‘) "€J€€€€‚ÿSection 10.2: Pattern parameters´‚CE2 2€€˜€€€€€€‚ÿThe only options available from the ‘Custom...’ option on the ‘Type’ menu are Width and Height, which are self-explanatory.k:‘°1V ,‚°î!CChapter 11: SoloCBB("btn_up","JI(`',`Top')");EB("btn_up")>Eî) "€*€€€€‚ÿChapter 11: SoloëŰÙ& €‹€˜€€‚ÿYou have a square grid, which is divided into as many equally sized sub-blocks as the grid has rows. Each square must be filled in with a digit from 1 to the size of the grid, in such a way thatg:î@ - *€t€T˜‘€8‚€ƒ€‚ÿ•every row contains only one occurrence of each digitj=Ùª - *€z€T˜‘€8‚€ƒ€‚ÿ•every column contains only one occurrence of each digitj=@  - *€z€T˜‘€8‚€ƒ€‚ÿ•every block contains only one occurrence of each digit.£vª · - *€ì€T˜‘€8‚€ƒ€‚ÿ•(optionally, by default off) each of the square's two main diagonals contains only one occurrence of each digit.‹f B % €Ì€˜€€‚ÿYou are given some of the numbers as clues; your aim is to place the rest of the numbers correctly.÷  & €;€˜€€‚ÿUnder the default settings, the sub-blocks are square or rectangular. The default puzzle size is 3×3 (a 9×9 actual grid, divided into nine 3×3 blocks). You can also select sizes with rectangular blocks instead of square ones, such as 2×3 (a 6×6 grid divided into six 3×2 blocks). Alternatively, you can select ‘jigsaw’ mode, in which the sub-blocks are arbitrary shapes which differ between individual puzzles.žxB £& €ñ€˜€€‚ÿAnother available mode is ‘killer’. In this mode, clues are not given in the form of filled-in squares; instead, the grid is divided into ‘cages’ by coloured lines, and for each cage the game tells you what the sum of all the digits in that cage should be. Also, no digit may appear more than once within a cage, even if the cage crosses the boundaries of existing regions.N  @8 >€-€˜€€€€€€€€‚ÿIf you select a puzzle size which requires more than 9 digits, the additional digits will be letters of the alphabet. For example, if you select 3×4 then the digits which go in your grid will be 1 to 9, plus ‘a’, ‘b’ and ‘c’. This cannot be selected for killer puzzles.£ @Eªr£¶A8 >€å€˜€€ãò¾eቀ€ãò¾eቂÿI first saw this puzzle in Nikoli [5], although it's also been popularised by various newspapers under the name ‘Sudoku’ or ‘Su Doku’. Howard Garns is considered the inventor of the modern form of the puzzle, and it was first published in Dell Pencil Puzzles and Word Games. A more elaborate treatment of the history of the puzzle can be found on Wikipedia [6].tI @*B+ &€’€˜€€€€‚ÿ[5] http://www.nikoli.co.jp/en/puzzles/sudoku.html (beware of Flash)S+¶A}B( €V€˜€€€‚ÿ[6] http://en.wikipedia.org/wiki/SudokuQ"*BÎB/ .€D€ã£ÄùN€€€‰‚ÿSection 11.1: Solo controlsS$}B!C/ .€H€ã¤ÄùN€€€‰‚ÿSection 11.2: Solo parameters}LÎBžC1¿ˆžCçC³JSection 11.1: Solo controlsCBB("btn_up","JI(`',`games.solo')");EB("btn_up")I !CçC) "€@€€€€‚ÿSection 11.1: Solo controls"üžC E& €ù€˜€€‚ÿTo play Solo, simply click the mouse in any empty square and then type a digit or letter on the keyboard to fill that square. If you make a mistake, click the mouse in the incorrect square and press Space to clear it again (or use the Undo feature)./çC8F, &€€˜€€€€‚ÿIf you right-click in a square and then type a number, that number will be entered in the square as a ‘pencil mark’. You can have pencil marks for multiple numbers in the same square. Squares containing filled-in numbers cannot also contain pencil marks.hB E G& €…€˜€€‚ÿThe game pays no attention to pencil marks, so exactly what you use them for is up to you: you can use them as reminders that a particular square needs to be re-examined once you know more about a particular number, or you can use them as lists of the possible numbers in a given square, or anything else you feel like.€[8F H% €¶€˜€€‚ÿTo erase a single pencil mark, right-click in the square and type the same number again.ß¹ GÿH& €s€˜€€‚ÿAll pencil marks in a square are erased when you left-click and type a number, or when you left-click and press space. Right-clicking and pressing space will also erase pencil marks.F  HEJ& €A€˜€€‚ÿAlternatively, use the cursor keys to move the mark around the grid. Pressing the return key toggles the mark (from a normal mark to a pencil mark), and typing a number in is entered in the square in the appropriate way; typing in a 0 or using the space bar will clear a filled square.nCÿH³J+ &€†€˜€€ãüÅùN‰‚ÿ(All the actions described in section 2.1 are also available.)NEJ2K1 ,‚. 2K}K؆Section 11.2: Solo parametersCBB("btn_up","JI(`',`games.solo')");EB("btn_up")K"³J}K) "€D€€€€‚ÿSection 11.2: Solo parametersiC2KæL& €‡€˜€€‚ÿSolo allows you to configure two separate dimensions of the puzzle grid on the ‘Type’ menu: the number of columns, and the number of rows, into which the main grid is divided. (The size of a block is the inverse of this: for example, if you select 2 columns and 3 rows, each actual block will have 3 columns and 2 rows.)_9}KEN& €s€˜€€‚ÿIf you tick the ‘X’ checkbox, Solo will apply the optional extra constraint that the two main diagonals of the grid also contain one of every digit. (This is sometimes known as ‘Sudoku-X’ in newspapers.) In this mode, the squares on the two main diagonals will be shaded slightly so that you know it's enabled.®ˆæL €& €€˜€€‚ÿIf you tick the ‘Jigsaw’ checkbox, Solo will generate randomly shaped sub-blocks. In this mode, the actual grid size will be taken to be the product of the numbers entered in the ‘Columns’ and ‘Rows’ boxes. There is no reason why you have to enter a number greater than 1 in both boxes; Jigsaw mode has no constraint on the grid size, and it can even be a prime number if you feel like it.EN €³J%ÿEN1& €ÿ€˜€€‚ÿIf you tick the ‘Killer’ checkbox, Solo will generate a set of of cages, which are randomly shaped and drawn in an outline of a different colour. Each of these regions contains a smaller clue which shows the digit sum of all the squares in this region.gA €˜‚& €ƒ€˜€€‚ÿYou can also configure the type of symmetry shown in the generated puzzles. More symmetry makes the puzzles look prettier but may also make them easier, since the symmetry constraints can force more clues than necessary to be present. Completely asymmetric puzzles have the freedom to contain as few clues as possible.þÒ1–…, &€¥€˜€€€€‚ÿFinally, you can configure the difficulty of the generated puzzles. Difficulty levels are judged by the complexity of the techniques of deduction required to solve the puzzle: each level requires a mode of reasoning which was not necessary in the previous one. In particular, on difficulty levels ‘Trivial’ and ‘Basic’ there will be a square you can fill in with a single number at all times, whereas at ‘Intermediate’ level and beyond you will have to make partial deductions about the set of squares a number could be in (or the set of numbers that could be in a square). At ‘Unreasonable’ level, even this is not enough, and you will eventually have to make a guess, and then backtrack if it turns out to be wrong.B˜‚؆& €9€˜€€‚ÿGenerating difficult puzzles is itself difficult: if you select one of the higher difficulty levels, Solo may have to make many attempts at generating a puzzle before it finds one hard enough for you. Be prepared to wait, especially if you have also configured a large puzzle size.l;–…D‡1͈ö !D‡ƒ‡ŒChapter 12: MinesCBB("btn_up","JI(`',`Top')");EB("btn_up")?؆ƒ‡) "€,€€€€‚ÿChapter 12: MinesŠ^D‡ ‰, &€½€˜€€€€‚ÿYou have a grid of covered squares, some of which contain mines, but you don't know which. Your job is to uncover every square which does not contain a mine. If you uncover a square containing a mine, you lose. If you uncover a square which does not contain a mine, you are told how many mines are contained within the eight surrounding squares.§ƒ‡´‰& €€˜€€‚ÿThis game needs no introduction; popularised by Windows, it is perhaps the single best known desktop puzzle game in existence.·‹ ‰k‹, &€€˜€€€€‚ÿThis version of it has an unusual property. By default, it will generate its mine positions in such a way as to ensure that you never need to guess where a mine is: you will always be able to deduce it somehow. So you will never, as can happen in other versions, get to the last four squares and discover that there are two mines left but you have no way of knowing for sure where they are.R#´‰½‹/ .€F€ã¥ÄùN€€€‰‚ÿSection 12.1: Mines controlsT%k‹Œ/ .€J€ã¦ÄùN€€€‰‚ÿSection 12.2: Mines parametersN½‹Œ1ú .1…"ŒÚŒ–ÆSection 12.1: Mines controlsCBB("btn_up","JI(`',`games.mines')");EB("btn_up")J!ŒÚŒ) "€B€€€€‚ÿSection 12.1: Mines controlsK&Œ%% €L€˜€€‚ÿThis game is played with the mouse.d?ÚŒ‰% €~€˜€€‚ÿIf you left-click in a covered square, it will be uncovered.÷%¦Ž& €ï€˜€€‚ÿIf you right-click in a covered square, it will place a flag which indicates that the square is believed to be a mine. Left-clicking in a marked square will not uncover it, for safety. You can right-click again to remove a mark placed in error.급œÀ2 2€q€˜€€€€€€‚ÿIf you left-click in an uncovered square, it will ‘clear around’ the square. This means: if the square has exactly as many flags surrounding it as it should have mines, then all the covered squares next to it which are not flagged will be uncovered. So once you think you know the location o¦ŽœÀŒf all the mines around a square, you can use this function as a shortcut to avoid having to click on each of the remaining squares one by one.pD¦Ž Â, &€‰€˜€€€€‚ÿIf you uncover a square which has no mines in the surrounding eight squares, then it is obviously safe to uncover those squares in turn, and so on if any of them also has no surrounding mines. This will be done for you automatically; so sometimes when you uncover a square, a whole new area will open up to be explored.X2œÀdÃ& €e€˜€€‚ÿYou can also use the cursor keys to move around the minefield. Pressing the return key in a covered square uncovers it, and in an uncovered square will clear around it (so it acts as the left button), pressing the space bar in a covered square will place a flag (similarly, it acts as the right button).lA ÂÐÃ+ &€‚€˜€€ãüÅùN‰‚ÿAll the actions described in section 2.1 are also available.ÛdÃÑÅ& €·€˜€€‚ÿEven Undo is available, although you might consider it cheating to use it. If you step on a mine, the program will only reveal the mine in question (unlike most other implementations, which reveal all of them). You can then Undo your fatal move and continue playing if you like. The program will track the number of times you died (and Undo will not reduce that counter), so when you get to the end of the game you know whether or not you did it without making any errors.ÅŸÐÖÆ& €?€˜€€‚ÿ(If you really want to know the full layout of the grid, which other implementations will show you after you die, you can always use the Solve menu option.)PÑÅÇ1yö Fˆ#ÇcÇËSection 12.2: Mines parametersCBB("btn_up","JI(`',`games.mines')");EB("btn_up")L#–ÆcÇ) "€F€€€€‚ÿSection 12.2: Mines parametersqLÇÔÇ% €˜€˜€€‚ÿThe options available from the ‘Custom...’ option on the ‘Type’ menu are:=cÇÈ+ &€$€˜€€€€‚ÿWidth, HeightAÔÇRÈ& €6€˜‘€€‚ÿSize of grid in squares.-ÈÈ% €€˜€€‚ÿMines àRÈŒÉ- (€Á€˜‘€€€€‚ÿNumber of mines in the grid. You can enter this as an absolute mine count, or alternatively you can put a % sign on the end in which case the game will arrange for that proportion of the squares in the grid to be mines.©‚È5Ê' €€˜‘€€‚ÿBeware of setting the mine count too high. At very high densities, the program may spend forever searching for a solvable grid.9ŒÉnÊ% €(€˜€€‚ÿEnsure solubility"û5ÊË' €÷€˜‘€€‚ÿWhen this option is enabled (as it is by default), Mines will ensure that the entire grid can be fully deduced starting from the initial open space. If you prefer the riskier grids generated by other implementations, you can switch off this option.p?nÊÌ1Ü1…$ÌCÌ Chapter 13: Same GameCBB("btn_up","JI(`',`Top')");EB("btn_up")CËCÌ) "€4€€€€‚ÿChapter 13: Same Game çÌPÍ& €Ï€˜€€‚ÿYou have a grid of coloured squares, which you have to clear by highlighting contiguous regions of more than one coloured square; the larger the region you highlight, the more points you get (and the faster you clear the arena).°ŠCÌÎ& €€˜€€‚ÿIf you clear the grid you win. If you end up with nothing but single squares (i.e., there are no more clickable regions left) you lose.É£PÍÉÎ& €G€˜€€‚ÿRemoving a region causes the rest of the grid to shuffle up: blocks that are suspended will fall down (first), and then empty columns are filled from the right.e@Î.Ï% €€€˜€€‚ÿSame Game was contributed to this collection by James Harvey.V'É΄Ï/ .€N€ã§ÄùN€€€‰‚ÿSection 13.1: Same Game controlsX).Ï / .€R€ã¨ÄùN€€€‰‚ÿSection 13.2: Same Game parameters„Ï Ë†U„Ï’1‹Fˆ}%’àSection 13.1: Same Game controlsCBB("btn_up","JI(`',`games.samegame')");EB("btn_up")N% à) "€J€€€€‚ÿSection 13.1: Same Game controlsfA’F% €‚€˜€€‚ÿThis game can be played with either the keyboard or the mouse.ŽiàÔ% €Ò€˜€€‚ÿIf you left-click an unselected region, it becomes selected (possibly clearing the current selection).’mFf% €Ú€˜€€‚ÿIf you left-click the selected region, it will be removed (and the rest of the grid shuffled immediately).fAÔÌ% €‚€˜€€‚ÿIf you right-click the selected region, it will be unselected.ã½f¯& €{€˜€€‚ÿThe cursor keys move a cursor around the grid. Pressing the Space or Enter keys while the cursor is in an unselected region selects it; pressing Space or Enter again removes it as above.nCÌ+ &€†€˜€€ãüÅùN‰‚ÿ(All the actions described in section 2.1 are also available.)ˆW¯¥1‡U&¥õ, Section 13.2: Same Game parametersCBB("btn_up","JI(`',`games.samegame')");EB("btn_up")P'õ) "€N€€€€‚ÿSection 13.2: Same Game parametersvQ¥k% €¢€˜€€‚ÿThese parameters are available from the ‘Custom...’ option on the ‘Type’ menu.=õ¨+ &€$€˜€€€€‚ÿWidth, HeightAké& €6€˜‘€€‚ÿSize of grid in squares.6¨% €"€˜€€‚ÿNo. of coloursÒ«éñ' €W€˜‘€€‚ÿNumber of different colours used to fill the grid; the more colours, the fewer large regions of colour and thus the more difficult it is to successfully clear the grid.6'% €"€˜€€‚ÿScoring systemEñl' €=€˜‘€€‚ÿControls the precise mechanism used for scoring. With the default system, ‘(n-2)^2’, only regions of three squares or more will score any points at all. With the alternative ‘(n-1)^2’ system, regions of two squares score a point each, and larger regions score relatively more points.9'¥% €(€˜€€‚ÿEnsure solubility˜rl= & €ä€˜‘€€‚ÿIf this option is ticked (the default state), generated grids will be guaranteed to have at least one solution.ïÂ¥, - (€…€˜‘€€€€‚ÿIf you turn it off, the game generator will not try to guarantee soluble grids; it will, however, still ensure that there are at least 2 squares of each colour on the grid at the start (since a grid with exactly one square of a given colour is definitely insoluble). Grids generated with this option disabled may contain more large areas of contiguous colour, leading to opportunities for higher scores; they can also take less time to generate.k:= — 1} '— Õ &Chapter 14: FlipCBB("btn_up","JI(`',`Top')");EB("btn_up")>, Õ ) "€*€€€€‚ÿChapter 14: Flip,—  & € €˜€€‚ÿYou have a grid of squares, some light and some dark. Your aim is to light all the squares up at the same time. You can choose any square and flip its state from light to dark or dark to light, but when you do so, other squares around it change state as well.\Õ ‚ % €¸€˜€€‚ÿEach square contains a small diagram showing which other squares change when you flip it.Q" Ó / .€D€ã©ÄùN€€€‰‚ÿSection 14.1: Flip controlsS$‚ &/ .€H€ãªÄùN€€€‰‚ÿSection 14.2: Flip parameters}LÓ £1FUˆ(£ìõASection 14.1: Flip controlsCBB("btn_up","JI(`',`games.flip')");EB("btn_up")I &ì) "€@€€€€‚ÿSection 14.1: Flip controlsfA£R% €‚€˜€€‚ÿThis game can be played with either the keyboard or the mouse.¸’ì@& €%€˜€€‚ÿLeft-click in a square to flip it and its associated squares, or use the cursor keys to choose a square and the space bar or Enter key R@&to flip.qER‡A, &€‹€˜€€€€‚ÿIf you use the ‘Solve’ function on this game, it will mark some of the squares in red. If you click once in every square with a red mark, the game should be solved. (If you click in a square without a red mark, a red mark will appear in it to indicate that you will need to reverse that operation to reach the solution.)nC@õA+ &€†€˜€€ãüÅùN‰‚ÿ(All the actions described in section 2.1 are also available.)N‡AtB1 ¥ƒ)tB¿B|ESection 14.2: Flip parametersCBB("btn_up","JI(`',`games.flip')");EB("btn_up")K"õA¿B) "€D€€€€‚ÿSection 14.2: Flip parametersvQtB5C% €¢€˜€€‚ÿThese parameters are available from the ‘Custom...’ option on the ‘Type’ menu.=¿BrC+ &€$€˜€€€€‚ÿWidth, HeightA5C³C& €6€˜‘€€‚ÿSize of grid in squares.2 rCåC% €€˜€€‚ÿShape type—p³C|E' €á€˜‘€€‚ÿThis control determines the shape of the region which is flipped by clicking in any given square. The default setting, ‘Crosses’, causes every square to flip itself and its four immediate neighbours (or three or two if it's at an edge or corner). The other setting, ‘Random’, causes a random shape to be chosen for every square, so the game is different every time.l;åCèE1 ˆ’†*èE'FóIChapter 15: GuessCBB("btn_up","JI(`',`Top')");EB("btn_up")?|E'F) "€,€€€€‚ÿChapter 15: Guess½—èEäF& €/€˜€€‚ÿYou have a set of coloured pegs, and have to reproduce a predetermined sequence of them (chosen by the computer) within a certain number of guesses.Ûµ'F¿G& €k€˜€€‚ÿEach guess gets marked with the number of correctly-coloured pegs in the correct places (in black), and also the number of correctly-coloured pegs in the wrong places (in white).-äFìH& €€˜€€‚ÿThis game is also known (and marketed, by Hasbro, mainly) as a board game ‘Mastermind’, with 6 colours, 4 pegs per row, and 10 guesses. However, this version allows custom settings of number of colours (up to 10), number of pegs per row, and number of guesses.a<¿GMI% €x€˜€€‚ÿGuess was contributed to this collection by James Harvey.R#ìHŸI/ .€F€ã«ÄùN€€€‰‚ÿSection 15.1: Guess controlsT%MIóI/ .€J€ã×ÄùN€€€‰‚ÿSection 15.2: Guess parametersNŸIrJ1-¥ƒç +rJ¼J«Section 15.1: Guess controlsCBB("btn_up","JI(`',`games.guess')");EB("btn_up")J!óI¼J) "€B€€€€‚ÿSection 15.1: Guess controlsfArJ"K% €‚€˜€€‚ÿThis game can be played with either the keyboard or the mouse.6¼JXL& €!€˜€€‚ÿWith the mouse, drag a coloured peg from the tray on the left-hand side to its required position in the current guess; pegs may also be dragged from current and past guesses to copy them elsewhere. To remove a peg, drag it off its current position to somewhere invalid.»•"KM& €+€˜€€‚ÿRight-clicking in the current guess adds a ‘hold’ marker; pegs that have hold markers will be automatically added to the next guess after marking.W1XLjN& €c€˜€€‚ÿAlternatively, with the keyboard, the up and down cursor keys can be used to select a peg colour, the left and right keys to select a peg position, and the space bar or Enter key to place a peg of the selected colour in the chosen position. ‘D’ or Backspace removes a peg, and Space adds a hold marker.±‹MO& €€˜€€‚ÿPressing ‘h’ or ‘?’ will fill the current guess with a suggested guess. Using this is not recommended for 10 or more pegs as it is slow.L&jNs€& €M€˜€€‚ÿWhen the guess is complete, the smaller feedback pegs will be highlighted; clicking on these (or moving the peg cursor to them with the arrow keys and pressing the space bar or Enter key) wiOs€óIll mark the current guess, copy any held pegs to the next guess, and move the ‘current guess’ marker.ʤO=& €I€˜€€‚ÿIf you correctly position all the pegs the solution will be displayed below; if you run out of guesses (or select ‘Solve...’) the solution will also be revealed.nCs€«+ &€†€˜€€ãüÅùN‰‚ÿ(All the actions described in section 2.1 are also available.)P=,‚1s’†l ,,‚x‚Ÿ‡Section 15.2: Guess parametersCBB("btn_up","JI(`',`games.guess')");EB("btn_up")L#«x‚) "€F€€€€‚ÿSection 15.2: Guess parametersÀš,‚8ƒ& €5€˜€€‚ÿThese parameters are available from the ‘Custom...’ option on the ‘Type’ menu. The default game matches the parameters for the board game ‘Mastermind’./ x‚gƒ% €€˜€€‚ÿColoursvP8ƒ݃& € €˜‘€€‚ÿNumber of colours the solution is chosen from; from 2 to 10 (more is harder).6gƒ„% €"€˜€€‚ÿPegs per guessS-݃f„& €Z€˜‘€€‚ÿNumber of pegs per guess (more is harder)./ „•„% €€˜€€‚ÿGuessesnHf„…& €€˜‘€€‚ÿNumber of guesses you have to find the solution in (fewer is harder).4•„7…% €€˜€€‚ÿAllow blanks×°…†' €a€˜‘€€‚ÿAllows blank pegs to be given as part of a guess (makes it easier, because you know that those will never be counted as part of the solution). This is turned off by default.’l7… †& €Ø€˜‘€€‚ÿNote that this doesn't allow blank pegs in the solution; if you really wanted that, use one extra colour.8†؆% €&€˜€€‚ÿAllow duplicatesÇ  †Ÿ‡' €A€˜‘€€‚ÿAllows the solution (and the guesses) to contain colours more than once; this increases the search space (making things harder), and is turned on by default.k:؆ ˆ1‡ç ! - ˆHˆ‘ŠChapter 16: PegsCBB("btn_up","JI(`',`Top')");EB("btn_up")>Ÿ‡Hˆ) "€*€€€€‚ÿChapter 16: Pegsí ˆ[‰& €Û€˜€€‚ÿA number of pegs are placed in holes on a board. You can remove a peg by jumping an adjacent peg over it (horizontally or vertically) to a vacant hole on the other side. Your aim is to remove all but one of the pegs initially present.’mHˆí‰% €Ú€˜€€‚ÿThis game, best known as ‘Peg Solitaire’, is possibly one of the oldest puzzle games still commonly known.Q"[‰>Š/ .€D€ãÎÄùN€€€‰‚ÿSection 16.1: Pegs controlsS$퉑Š/ .€H€ãÏÄùN€€€‰‚ÿSection 16.2: Pegs parameters}L>Š‹1íl H .‹W‹ûŽSection 16.1: Pegs controlsCBB("btn_up","JI(`',`games.pegs')");EB("btn_up")I ‘ŠW‹) "€@€€€€‚ÿSection 16.1: Pegs controls^8‹µŒ& €q€˜€€‚ÿTo move a peg, drag it with the mouse from its current position to its final position. If the final position is exactly two holes away from the initial position, is currently unoccupied by a peg, and there is a peg in the intervening square, the move will be permitted and the intervening peg will be removed.Ý·W‹’& €o€˜€€‚ÿVacant spaces which you can move a peg into are marked with holes. A space with no peg and no hole is not available for moving at all: it is an obstacle which you must work around.ûÕµŒŽ& €«€˜€€‚ÿYou can also use the cursor keys to move a position indicator around the board. Pressing the return key while over a peg, followed by a cursor key, will jump the peg in that direction (if that is a legal move).nC’ûŽ+ &€†€˜€€ãüÅùN‰‚ÿ(All the actions described in section 2.1 are also available.)NŽz1 ! « /zÅÂSection 16.2: Pegs parametersCBB("btn_up","JI(`',`games.pegs')");EB("btn_up")K"ûŽÅ) "€D€€€€‚ÿSection 16.2: Pegs parametersvQzGÀ% €¢€˜€€‚ÿThese parameters are ÅGÀûŽavailable from the ‘Custom...’ option on the ‘Type’ menu.=Å„À+ &€$€˜€€€€‚ÿWidth, Height?GÀÃÀ& €2€˜‘€€‚ÿSize of grid in holes.2 „ÀõÀ% €€˜€€‚ÿBoard typešsÃÀÂ' €ç€˜‘€€‚ÿControls whether you are given a board of a standard shape or a randomly generated shape. The two standard shapes currently supported are ‘Cross’ and ‘Octagon’ (also commonly known as the English and European traditional board layouts respectively). Selecting ‘Random’ will give you a different board shape every time (but always one that is known to have a solution).o>õÀþÂ1ûH Ôƒ 0þÂ@ÃùÅChapter 17: DominosaCBB("btn_up","JI(`',`Top')");EB("btn_up")BÂ@Ã) "€2€€€€‚ÿChapter 17: Dominosa‡aþÂÇÄ& €Ã€˜€€‚ÿA normal set of dominoes – that is, one instance of every (unordered) pair of numbers from 0 to 6 – has been arranged irregularly into a rectangle; then the number in each square has been written down and the dominoes themselves removed. Your task is to reconstruct the pattern by arranging the set of dominoes to match the provided array of numbers.†a@ÃMÅ% €Â€˜€€‚ÿThis puzzle is widely credited to O. S. Adler, and takes part of its name from those initials.U&ÇÄ¢Å/ .€L€ãÐÄùN€€€‰‚ÿSection 17.1: Dominosa controlsW(MÅùÅ/ .€P€ãÑÄùN€€€‰‚ÿSection 17.2: Dominosa parameters…T¢Å~Æ1« æ‡ 1~ÆËÆ‚ËSection 17.1: Dominosa controlsCBB("btn_up","JI(`',`games.dominosa')");EB("btn_up")M$ùÅËÆ) "€H€€€€‚ÿSection 17.1: Dominosa controlsûÕ~ÆÆÇ& €«€˜€€‚ÿLeft-clicking between any two adjacent numbers places a domino covering them, or removes one if it is already present. Trying to place a domino which overlaps existing dominoes will remove the ones it overlaps.ÛËÆÍÈ, &€·€˜€€€€‚ÿRight-clicking between two adjacent numbers draws a line between them, which you can use to remind yourself that you know those two numbers are not covered by a single domino. Right-clicking again removes the line.`:ÆÇ-Ê& €u€˜€€‚ÿYou can also use the cursor keys to move a cursor around the grid. When the cursor is half way between two adjacent numbers, pressing the return key will place a domino covering those numbers, or pressing the space bar will lay a line between the two squares. Repeating either action removes the domino or line.çÁÍÈË& €ƒ€˜€€‚ÿPressing a number key will highlight all occurrences of that number. Pressing that number again will clear the highlighting. Up to two different numbers can be highlighted at any given time.nC-Ê‚Ë+ &€†€˜€€ãüÅùN‰‚ÿ(All the actions described in section 2.1 are also available.)‡VË Ì1Ôƒ 2 ÌXÌSection 17.2: Dominosa parametersCBB("btn_up","JI(`',`games.dominosa')");EB("btn_up")O&‚ËXÌ) "€L€€€€‚ÿSection 17.2: Dominosa parametersvQ ÌÎÌ% €¢€˜€€‚ÿThese parameters are available from the ‘Custom...’ option on the ‘Type’ menu.BXÌÍ% €:€˜€€‚ÿMaximum number on dominoesòÎÌ)Î' €å€˜‘€€‚ÿControls the size of the puzzle, by controlling the size of the set of dominoes used to make it. Dominoes with numbers going up to N will give rise to an (N+2) × (N+1) rectangle; so, in particular, the default value of 6 gives an 8×7 grid.>ÍgÎ% €2€˜€€‚ÿEnsure unique solution¤w)Î- (€ï€˜‘€€€€‚ÿNormally, Dominosa will make sure that the puzzles it presents have only one solution. Puzzles with ambiguous sections can be more difficult and sometimes more subtle, so if you like you can turn off this feature. Also, finding all the possible solutions can be an additional challenge for an advanced player. Turning off this option can also speed up puzzle geg΂Ëneration.o>gΆ1¨æ‡ ¨ 3†È.Chapter 18: UntangleCBB("btn_up","JI(`',`Top')");EB("btn_up")BÈ) "€2€€€€‚ÿChapter 18: UntangleæÀ†®& €€˜€€‚ÿYou are given a number of points, some of which have lines drawn between them. You can move the points about arbitrarily; your aim is to position the points so that no line crosses another.eÈ>+ &€Ê€˜€€ã{,¾¯‰‚ÿI originally saw this in the form of a Flash game called Planarity [7], written by John Tantalo.D®‚( €8€˜€€€‚ÿ[7] http://planarity.netU&>×/ .€L€ãÒÄùN€€€‰‚ÿSection 18.1: Untangle controlsW(‚./ .€P€ãÓÄùN€€€‰‚ÿSection 18.2: Untangle parameters…T׳1; j 4³îSection 18.1: Untangle controlsCBB("btn_up","JI(`',`games.untangle')");EB("btn_up")M$.) "€H€€€€‚ÿSection 18.1: Untangle controls€[³€% €¶€˜€€‚ÿTo move a point, click on it with the left mouse button and drag it into a new position.nCî+ &€†€˜€€ãüÅùN‰‚ÿ(All the actions described in section 2.1 are also available.)‡V€u1ˆ¨ Y 5uÄýSection 18.2: Untangle parametersCBB("btn_up","JI(`',`games.untangle')");EB("btn_up")O&îÄ) "€L€€€€‚ÿSection 18.2: Untangle parameters}XuA% €°€˜€€‚ÿThere is only one parameter available from the ‘Custom...’ option on the ‘Type’ menu:8Äy% €&€˜€€‚ÿNumber of points„^Aý& €¼€˜‘€€‚ÿControls the size of the puzzle, by specifying the number of points in the generated graph.p?ym1tj Š„ 6m°íGChapter 19: Black BoxCBB("btn_up","JI(`',`Top')");EB("btn_up")Cý°) "€4€€€€‚ÿChapter 19: Black BoxîÈmž& €‘€˜€€‚ÿA number of balls are hidden in a rectangular arena. You have to deduce the positions of the balls by firing lasers positioned at the edges of the arena and observing how their beams are deflected.ز°v & €e€˜€€‚ÿBeams will travel straight from their origin until they hit the opposite side of the arena (at which point they emerge), unless affected by balls in one of the following ways:¾ž4 . *€!€T˜‘€8‚€ƒ€‚ÿ•A beam that hits a ball head-on is absorbed and will never re-emerge. This includes beams that meet a ball on the first rank of the arena.žqv Ò - *€â€T˜‘€8‚€ƒ€‚ÿ•A beam with a ball in its front-left square and no ball ahead of it gets deflected 90 degrees to the right.p4 o - *€à€T˜‘€8‚€ƒ€‚ÿ•A beam with a ball in its front-right square and no ball ahead of it gets similarly deflected to the left.‡ZÒ ö - *€´€T˜‘€8‚€ƒ€‚ÿ•A beam that would re-emerge from its entry location is considered to be ‘reflected’.Ò¤o È . *€I€T˜‘€8‚€ƒ€‚ÿ•A beam which would get deflected before entering the arena by a ball to the front-left or front-right of its entry point is also considered to be ‘reflected’.üÖö Ä & €­€˜€€‚ÿBeams that are reflected appear as a ‘R’; beams that hit balls head-on appear as ‘H’. Otherwise, a number appears at the firing point and the location where the beam emerges (this number is unique to that shot).ðÊÈ ´& €•€˜€€‚ÿYou can place guesses as to the location of the balls, based on the entry and exit patterns of the beams; once you have placed enough balls a button appears enabling you to have your guesses checked.kÄ D% €Ö€˜€€‚ÿHere is a diagram showing how the positions of balls can create each of the beam behaviours shown above:1 ´u$ €€€€‚ÿ 1RHR---- 1 D¦$ €€€€‚ÿ|..O.O...|1 u×$ €€€€‚ÿ2........31 ¦@$ €€€€‚ÿ|...×@ý.....|1 ×E@$ €€€€‚ÿ|........|1 @v@$ €€€€‚ÿ3........|1 E@§@$ €€€€‚ÿ|......O.|1 v@Ø@$ €€€€‚ÿH........|1 §@ A$ €€€€‚ÿ|.....O..|1 Ø@:A% €€˜€€‚ÿ 12-RR--- æ AFB& €Í€˜€€‚ÿAs shown, it is possible for a beam to receive multiple reflections before re-emerging (see turn 3). Similarly, a beam may be reflected (possibly more than once) before receiving a hit (the ‘H’ on the left side of the example).)ý:AoC, &€û€˜€€€€‚ÿNote that any layout with more than 4 balls may have a non-unique solution. The following diagram illustrates this; if you know the board contains 5 balls, it is impossible to determine where the fifth ball is (possible positions marked with an x):1 FB C$ €€€€‚ÿ -------- 1 oCÑC$ €€€€‚ÿ|........|1  CD$ €€€€‚ÿ|........|1 ÑC3D$ €€€€‚ÿ|..O..O..|1 DdD$ €€€€‚ÿ|...xx...|1 3D•D$ €€€€‚ÿ|...xx...|1 dDÆD$ €€€€‚ÿ|..O..O..|1 •D÷D$ €€€€‚ÿ|........|1 ÆD(E$ €€€€‚ÿ|........|1 ÷DYE% €€˜€€‚ÿ --------I(EÚF8 >€“€˜€€€€€€€€‚ÿFor this reason, when you have your guesses checked, the game will check that your solution produces the same results as the computer's, rather than that your solution is identical to the computer's. So in the above example, you could put the fifth ball at any of the locations marked with an x, and you would still win.e@YE?G% €€€˜€€‚ÿBlack Box was contributed to this collection by James Harvey.V'ÚF•G/ .€N€ãÔÄùN€€€‰‚ÿSection 19.1: Black Box controlsX)?GíG/ .€R€ãÕÄùN€€€‰‚ÿSection 19.2: Black Box parameters†U•GsH1ó Y C 7sHÁHr‚Section 19.1: Black Box controlsCBB("btn_up","JI(`',`games.blackbox')");EB("btn_up")N%íGÁH) "€J€€€€‚ÿSection 19.1: Black Box controlsDsHJ& €=€˜€€‚ÿTo fire a laser beam, left-click in a square around the edge of the arena. The results will be displayed immediately. Clicking or holding the left button on one of these squares will highlight the current go (or a previous go) to confirm the exit point for that laser, if applicable.¿™ÁHÄJ& €3€˜€€‚ÿTo guess the location of a ball, left-click within the arena and a black circle will appear marking the guess; click again to remove the guessed ball.ßJÉK& €¿€˜€€‚ÿLocations in the arena may be locked against modification by right-clicking; whole rows and columns may be similarly locked by right-clicking in the laser square above/below that column, or to the left/right of that row.â¼ÄJ«L& €y€˜€€‚ÿThe cursor keys may also be used to move around the grid. Pressing the Enter key will fire a laser or add a new ball-location guess, and pressing Space will lock a cell, row, or column.Ö°ÉKM& €a€˜€€‚ÿWhen an appropriate number of balls have been guessed, a button will appear at the top-left corner of the grid; clicking that (with mouse or cursor) will check your guesses.ù«L O& €ó€˜€€‚ÿIf you click the ‘check’ button and your guesses are not correct, the game will show you the minimum information necessary to demonstrate this to you, so you can try again. If your ball positions are not consistent with the beam paths you already know about, one beam path will be circled to indicate that it proves you wrong. If your positions match all the existing beam paths but are still wrong, one new beam path will be revealed (written in red) which is not consistent with your current guesses.X,M‚, &€Y€˜€€€€‚ÿIf you decide to give up completely, you can select O‚íG Solve to reveal the actual ball positions. At this point, correctly-placed balls will be displayed as filled black circles, incorrectly-placed balls as filled black circles with red crosses, and missing balls as filled red circles. In addition, a red circle marks any laser you had already fired which is not consistent with your ball layout (just as when you press the ‘check’ button), and red text marks any laser you could have fired in order to distinguish your ball layout from the correct one.nC Or‚+ &€†€˜€€ãüÅùN‰‚ÿ(All the actions described in section 2.1 are also available.)ˆW‚ú‚1~Š„ Ê 8ú‚Jƒx†Section 19.2: Black Box parametersCBB("btn_up","JI(`',`games.blackbox')");EB("btn_up")P'r‚Jƒ) "€N€€€€‚ÿSection 19.2: Black Box parametersvQú‚Àƒ% €¢€˜€€‚ÿThese parameters are available from the ‘Custom...’ option on the ‘Type’ menu.=Jƒýƒ+ &€$€˜€€€€‚ÿWidth, HeightŸmÀƒœ„2 4€Ú€˜‘€€€€€€‚ÿSize of grid in squares. There are 2 × Width × Height lasers per grid, two per row and two per column.4ýƒЄ% €€˜€€‚ÿNo. of balls¨œ„x†' €€˜‘€€‚ÿNumber of balls to place in the grid. This can be a single number, or a range (separated with a hyphen, like ‘2-6’), and determines the number of balls to place on the grid. The ‘reveal’ button is only enabled if you have guessed an appropriate number of balls; a guess using a different number to the original solution is still acceptable, if all the beam inputs and outputs match.l;Єä†1@C ¬ 9ä†#‡$‹Chapter 20: SlantCBB("btn_up","JI(`',`Top')");EB("btn_up")?x†#‡) "€,€€€€‚ÿChapter 20: Slantͧä†ð‡& €O€˜€€‚ÿYou have a grid of squares. Your aim is to draw a diagonal line through each square, and choose which way each line slants so that the following conditions are met:X+#‡Hˆ- *€V€T˜‘€8‚€ƒ€‚ÿ•The diagonal lines never form a loop.i;ð‡±‰. *€w€T˜‘€8‚€ƒ€‚ÿ•Any point with a circled number has precisely that many lines meeting at it. (Thus, a 4 is the centre of a cross shape, whereas a zero is the centre of a diamond shape – or rather, a partial diamond shape, because a zero can never appear in the middle of the grid because that would immediately cause a loop.)Z/Hˆ Š+ &€^€˜€€ãs܉‚ÿCredit for this puzzle goes to Nikoli [8].sH±‰~Š+ &€€˜€€€€‚ÿ[8] http://www.nikoli.co.jp/ja/puzzles/gokigen_naname (in Japanese)R# ŠЊ/ .€F€ãÖÄùN€€€‰‚ÿSection 20.1: Slant controlsT%~Š$‹/ .€J€ãÅùN€€€‰‚ÿSection 20.2: Slant parametersNЊ£‹1KÊ C€ :£‹í‹úÀSection 20.1: Slant controlsCBB("btn_up","JI(`',`games.slant')");EB("btn_up")J!$‹í‹) "€B€€€€‚ÿSection 20.1: Slant controlsB£‹/2 2€!€˜€€€€€€‚ÿLeft-clicking in a blank square will place a \ in it (a line leaning to the left, i.e. running from the top left of the square to the bottom right). Right-clicking in a blank square will place a / in it (leaning to the right, running from top right to bottom left).²tí‹áŽ> J€é€˜€€€€€€€€€€‚ÿContinuing to click either button will cycle between the three possible square contents. Thus, if you left-click repeatedly in a blank square it will change from blank to \ to / back to blank, and if you right-click repeatedly the square will change from blank to / to \ back to blank. (Therefore, you can play the game entirely with one button if you need to.)ŸU/ŒÀJ b€«€˜€€€€€€€€€€€€€€‚ÿYou can also use the cursor keys to move around the grid. Pressing the return or space keys will place a \ or a /, respectively, and will then cycle them as above. You can also press / or \ to place a /ᎌÀ$‹ or \, respectively, independent of what is already in the cursor square. Backspace removes any line from the cursor square.nCáŽúÀ+ &€†€˜€€ãüÅùN‰‚ÿ(All the actions described in section 2.1 are also available.)PŒÀ{Á1Ÿ¬ ñ‚ ;{ÁÇÁÅSection 20.2: Slant parametersCBB("btn_up","JI(`',`games.slant')");EB("btn_up")L#úÀÇÁ) "€F€€€€‚ÿSection 20.2: Slant parametersvQ{Á=Â% €¢€˜€€‚ÿThese parameters are available from the ‘Custom...’ option on the ‘Type’ menu.=ÇÁzÂ+ &€$€˜€€€€‚ÿWidth, HeightA=»Â& €6€˜‘€€‚ÿSize of grid in squares.2 zÂíÂ% €€˜€€‚ÿDifficulty-»ÂÅ- (€€˜‘€€€€‚ÿControls the difficulty of the generated puzzle. At Hard level, you are required to do deductions based on knowledge of relationships between squares rather than always being able to deduce the exact contents of one square at a time. (For example, you might know that two squares slant in the same direction, even if you don't yet know what that direction is, and this might enable you to deduce something about still other squares.) Even at Hard level, guesswork and backtracking should never be necessary.o>í‰Å1îC€ ¿† <‰ÅËÅwËChapter 21: Light UpCBB("btn_up","JI(`',`Top')");EB("btn_up")BÅËÅ) "€2€€€€‚ÿChapter 21: Light UpÞ¸‰Å©Æ& €q€˜€€‚ÿYou have a grid of squares. Some are filled in black; some of the black squares are numbered. Your aim is to ‘light up’ all the empty squares by placing light bulbs in some of them.ÀšËÅiÇ& €5€˜€€‚ÿEach light bulb illuminates the square it is on, plus all squares in line with it horizontally or vertically unless a black square is blocking the way.c>©ÆÌÇ% €|€˜€€‚ÿTo win the game, you must satisfy the following conditions:Q$iÇÈ- *€H€T˜‘€8‚€ƒ€‚ÿ•All non-black squares are lit.T'ÌÇqÈ- *€N€T˜‘€8‚€ƒ€‚ÿ•No light is lit by another light.·‰È(É. *€€T˜‘€8‚€ƒ€‚ÿ•All numbered black squares have exactly that number of lights adjacent to them (in the four squares above, below, and to the side).rMqÈšÉ% €š€˜€€‚ÿNon-numbered black squares may have any number of lights adjacent to them.Z/(ÉôÉ+ &€^€˜€€ã–ö‹‰‚ÿCredit for this puzzle goes to Nikoli [9].d?šÉXÊ% €~€˜€€‚ÿLight Up was contributed to this collection by James Harvey.sHôÉËÊ+ &€€˜€€€€‚ÿ[9] http://www.nikoli.co.jp/en/puzzles/akari.html (beware of Flash)U&XÊ Ë/ .€L€ãùÄùN€€€‰‚ÿSection 21.1: Light Up controlsW(ËÊwË/ .€P€ãúÄùN€€€‰‚ÿSection 21.2: Light Up parameters„S ËûË1¾ñ‚ “‰ =ûËH̹ÏSection 21.1: Light Up controlsCBB("btn_up","JI(`',`games.lightup')");EB("btn_up")M$wËHÌ) "€H€€€€‚ÿSection 21.1: Light Up controlséûËWÍ& €Ó€˜€€‚ÿLeft-clicking in a non-black square will toggle the presence of a light in that square. Right-clicking in a non-black square toggles a mark there to aid solving; it can be used to highlight squares that cannot be lit, for example.wRHÌÎÍ% €¤€˜€€‚ÿYou may not place a light in a marked square, nor place a mark in a lit square.îÈWͼÎ& €‘€˜€€‚ÿThe game will highlight obvious errors in red. Lights lit by other lights are highlighted in this way, as are numbered squares which do not (or cannot) have the right number of lights next to them.jÎÍKÏ% €Ô€˜€€‚ÿThus, the grid is solved when all non-black squares have yellow highlights and there are no red lights.nC¼Î¹Ï+ &€†€˜€€ãüÅùN‰‚ÿ(All the actions described in section 2.1 are also available.)†UKÏK1Ž¿† å >KšÙSection 21.2: Light Up¹ÏK¹Ï parametersCBB("btn_up","JI(`',`games.lightup')");EB("btn_up")O&¹Ïš) "€L€€€€‚ÿSection 21.2: Light Up parametersvQK% €¢€˜€€‚ÿThese parameters are available from the ‘Custom...’ option on the ‘Type’ menu.=šM+ &€$€˜€€€€‚ÿWidth, HeightAŽ& €6€˜‘€€‚ÿSize of grid in squares.=MË% €0€˜€€‚ÿ%age of black squaresW1Ž"& €b€˜‘€€‚ÿRough percentage of black squares in the grid.çÀË ' €€˜‘€€‚ÿThis is a hint rather than an instruction. If the grid generator is unable to generate a puzzle to this precise specification, it will increase the proportion of black squares until it can.0 "9% €€˜€€‚ÿSymmetry¸‘ ñ' €#€˜‘€€‚ÿAllows you to specify the required symmetry of the black squares in the grid. (This does not affect the difficulty of the puzzles noticeably.)2 9#% €€˜€€‚ÿDifficulty¶ñÙ' €€˜‘€€‚ÿ‘Easy’ means that the puzzles should be soluble without backtracking or guessing, ‘Hard’ means that some guesses will probably be necessary.j9#C1­“‰ “ ?C€ð Chapter 22: MapCBB("btn_up","JI(`',`Top')");EB("btn_up")=Ù€) "€(€€€€‚ÿChapter 22: MapU/CÕ& €_€˜€€‚ÿYou are given a map consisting of a number of regions. Your task is to colour each region with one of four colours, in such a way that no two regions sharing a boundary have the same colour. You are provided with some regions already coloured, sufficient to make the remainder of the solution unique.ã·€¸, &€o€˜€€€€‚ÿOnly regions which share a length of border are required to be different colours. Two regions which meet at only one point (i.e. are diagonally separated) may be the same colour.–pÕN & €á€˜€€‚ÿI believe this puzzle is original; I've never seen an implementation of it anywhere else. The concept of a four-colouring puzzle was suggested by Owen Dunn; credit must also go to Nikoli and to Verity Allan for inspiring the train of thought that led to me realising Owen's suggestion was a viable puzzle. Thanks also to Gareth Taylor for many detailed suggestions.P!¸ž / .€B€ãûÄùN€€€‰‚ÿSection 22.1: Map controlsR#N ð / .€F€ãüÄùN€€€‰‚ÿSection 22.2: Map parameters{Jž k 1}å ¡ @k ³ ôBSection 22.1: Map controlsCBB("btn_up","JI(`',`games.map')");EB("btn_up")Hð ³ ) "€>€€€€‚ÿSection 22.1: Map controls®ˆk a & €€˜€€‚ÿTo colour a region, click the left mouse button on an existing region of the desired colour and drag that colour into the new region.¦€³  & €€˜€€‚ÿ(The program will always ensure the starting puzzle has at least one region of each colour, so that this is always possible!)ª„a ± & € €˜€€‚ÿIf you need to clear a region, you can drag from an empty region, or from the puzzle boundary if there are no empty regions left.Z(  2 2€Q€˜€€€€€€‚ÿDragging a colour using the right mouse button will stipple the region in that colour, which you can use as a note to yourself that you think the region might be that colour. A region can contain stipples in multiple colours at once. (This is often useful at the harder difficulty levels.)ëű A& €‹€˜€€‚ÿYou can also use the cursor keys to move around the map: the colour of the cursor indicates the position of the colour you would drag (which is not obvious if you're on a region's boundary, since it depends on the direction from which you approached the boundary). Pressing the return key starts a drag of that colour, as above, which you control with the cursor keys; pressing the return key again finishes the drag. The space bar can be used similarly to creat Að e a stippled region. Double-pressing the return key (without moving the cursor) will clear the region, as a drag from an empty region does: this is useful with the cursor mode if you have filled the entire map in but need to correct the layout.„^ †B& €½€˜€€‚ÿIf you press L during play, the game will toggle display of a number in each region of the map. This is useful if you want to discuss a particular puzzle instance with a friend – having an unambiguous name for each region is much easier than trying to refer to them all by names such as ‘the one down and right of the brown one on the top border’.nCAôB+ &€†€˜€€ãüÅùN‰‚ÿ(All the actions described in section 2.1 are also available.)}L†BqC1e“ ©„ AqC»CÖGSection 22.2: Map parametersCBB("btn_up","JI(`',`games.map')");EB("btn_up")J!ôB»C) "€B€€€€‚ÿSection 22.2: Map parametersvQqC1D% €¢€˜€€‚ÿThese parameters are available from the ‘Custom...’ option on the ‘Type’ menu.=»CnD+ &€$€˜€€€€‚ÿWidth, HeightA1D¯D& €6€˜‘€€‚ÿSize of grid in squares./ nDÞD% €€˜€€‚ÿRegionsP*¯D.E& €T€˜‘€€‚ÿNumber of regions in the generated map.2 ÞD`E% €€˜€€‚ÿDifficultyL%.E¬F' €K€˜‘€€‚ÿIn ‘Easy’ mode, there should always be at least one region whose colour can be determined trivially. In ‘Normal’ and ‘Hard’ modes, you will have to use increasingly complex logic to deduce the colour of some regions. However, it will always be possible without having to guess or backtrack.*`EÖG' €€˜‘€€‚ÿIn ‘Unreasonable’ mode, the program will feel free to generate puzzles which are as hard as it can possibly make them: the only constraint is that they should still have a unique solution. Solving Unreasonable puzzles may require guessing and backtracking.l;¬FBH1v¡ ªˆ BBHH¸MChapter 23: LoopyCBB("btn_up","JI(`',`Top')");EB("btn_up")?ÖGH) "€,€€€€‚ÿChapter 23: LoopyóBHšI& €ç€˜€€‚ÿYou are given a grid of dots, marked with yellow lines to indicate which dots you are allowed to connect directly together. Your aim is to use some subset of those yellow lines to draw a single unbroken loop from dot to dot within the grid.ïH¯J& €ß€˜€€‚ÿSome of the spaces between the lines contain numbers. These numbers indicate how many of the lines around that space form part of the loop. The loop you draw must correctly satisfy all of these clues to be considered a correct solution.ÀššIoK& €5€˜€€‚ÿIn the default mode, the dots are arranged in a grid of squares; however, you can also play on triangular or hexagonal grids, or even more exotic ones.e:¯JÔK+ &€t€˜€€ãÎý©Ú‰‚ÿCredit for the basic puzzle idea goes to Nikoli [10].ÄžoK˜L& €=€˜€€‚ÿLoopy was originally contributed to this collection by Mike Pinna, and subsequently enhanced to handle various types of non-square grid by Lambros Lambrou.zOÔKM+ &€ž€˜€€€€‚ÿ[10] http://www.nikoli.co.jp/en/puzzles/slitherlink.html (beware of Flash)R#˜LdM/ .€F€ãýÄùN€€€‰‚ÿSection 23.1: Loopy controlsT%M¸M/ .€J€ãþÄùN€€€‰‚ÿSection 23.2: Loopy parametersNdM7N1‘©„ C C7NNÔ€Section 23.1: Loopy controlsCBB("btn_up","JI(`',`games.loopy')");EB("btn_up")J!¸MN) "€B€€€€‚ÿSection 23.1: Loopy controlsâ¼7NcO& €y€˜€€‚ÿClick the left mouse button on a yellow line to turn it black, indicating that you think it is part of the loop. Click again to turn the line yellow again (meaning you aren't sure yet).÷ËNf€, &€—€˜€€€€‚ÿIf you are sure that a particular line segment is not part of the loop, you can click the right mouse button tcOf€¸Mo remove it completely. Again, clicking a second time will turn the line back to yellow.nCcOÔ€+ &€†€˜€€ãüÅùN‰‚ÿ(All the actions described in section 2.1 are also available.)Pf€U1©ªˆ  DU¡þ…Section 23.2: Loopy parametersCBB("btn_up","JI(`',`games.loopy')");EB("btn_up")L#Ô€¡) "€F€€€€‚ÿSection 23.2: Loopy parametersvQU‚% €¢€˜€€‚ÿThese parameters are available from the ‘Custom...’ option on the ‘Type’ menu.=¡T‚+ &€$€˜€€€€‚ÿWidth, HeightôÍ‚Hƒ' €›€˜‘€€‚ÿSize of grid, measured in number of regions across and down. For square grids, it's clear how this is counted; for other types of grid you may have to think a bit to see how the dimensions are measured.1 T‚yƒ% €€˜€€‚ÿGrid typeùºHƒr…? L€u€˜‘€€€€€€€€€€‚ÿAllows you to choose between a selection of types of tiling. Some have all the faces the same but may have multiple different types of vertex (e.g. the Cairo or Kites mode); others have all the vertices the same but may have different types of face (e.g. the Great Hexagonal). The square, triangular and honeycomb grids are fully regular, and have all their vertices and faces the same; this makes them the least confusing to play.2 yƒ¤…% €€˜€€‚ÿDifficultyZ4r…þ…& €h€˜‘€€‚ÿControls the difficulty of the generated puzzle. n=¤…l†1©C í El†­†ŒChapter 24: InertiaCBB("btn_up","JI(`',`Top')");EB("btn_up")Aþ…­†) "€0€€€€‚ÿChapter 24: Inertia¬†l†Y‡& € €˜€€‚ÿYou are a small green ball sitting in a grid full of obstacles. Your aim is to collect all the gems without running into any mines.í­†x‰2 2€Û€˜€€€€€€‚ÿYou can move the ball in any orthogonal or diagonal direction. Once the ball starts moving, it will continue until something stops it. A wall directly in its path will stop it (but if it is moving diagonally, it will move through a diagonal gap between two other walls without stopping). Also, some of the squares are ‘stops’; when the ball moves on to a stop, it will stop moving no matter what direction it was going in. Gems do not stop the ball; it picks them up and keeps on going.É£Y‡AŠ& €G€˜€€‚ÿRunning into a mine is fatal. Even if you picked up the last gem in the same move which then hit a mine, the game will count you as dead rather than victorious.é½x‰*‹, &€{€˜€€ãK’¦à‰‚ÿThis game was originally implemented for Windows by Ben Olmstead [11], who was kind enough to release his source code on request so that it could be re-implemented for this collection.AAŠk‹( €2€˜€€€‚ÿ[11] http://xn13.com/T%*‹¿‹/ .€J€ãÿÄùN€€€‰‚ÿSection 24.1: Inertia controlsV'k‹Œ/ .€N€ãÅùN€€€‰‚ÿSection 24.2: Inertia parametersƒR¿‹˜Œ1ö  F˜ŒäŒšÁSection 24.1: Inertia controlsCBB("btn_up","JI(`',`games.inertia')");EB("btn_up")L#ŒäŒ) "€F€€€€‚ÿSection 24.1: Inertia controlsÚ˜Œä& €µ€˜€€‚ÿYou can move the ball in any of the eight directions using the numeric keypad. Alternatively, if you click the left mouse button on the grid, the ball will begin a move in the general direction of where you clicked.zTäŒjÀ& €©€˜€€‚ÿIf you use the ‘Solve’ function on this game, the program will compute a path through the grid which collects all the remaining gems and returns to the current position. A hint arrow will appear on the ball indicating the direction in which you should move to begin on this path. If you then move in that direction, the arrow will update to indicate the next direction on the path. You can also press Space to automatically move in the direction of the hint arrow. If you move in a different directionäjÀŒ from the one shown by the arrow, arrows will be shown only if the puzzle is still solvable.0äšÁ, &€ €˜€€ãüÅùN‰‚ÿAll the actions described in section 2.1 are also available. In particular, if you do run into a mine and die, you can use the Undo function and resume playing from before the fatal move. The game will keep track of the number of times you have done this.…TjÀÂ1Bí § GÂmÂaÃSection 24.2: Inertia parametersCBB("btn_up","JI(`',`games.inertia')");EB("btn_up")N%šÁmÂ) "€J€€€€‚ÿSection 24.2: Inertia parametersvQÂãÂ% €¢€˜€€‚ÿThese parameters are available from the ‘Custom...’ option on the ‘Type’ menu.=m Ã+ &€$€˜€€€€‚ÿWidth, HeightAãÂaÃ& €6€˜‘€€‚ÿSize of grid in squares.l; ÃÍÃ1 … HÍà ÄÍÈChapter 25: TentsCBB("btn_up","JI(`',`Top')");EB("btn_up")?aà Ä) "€,€€€€‚ÿChapter 25: TentsÓ­ÍÃßÄ& €[€˜€€‚ÿYou have a grid of squares, some of which contain trees. Your aim is to place tents in some of the remaining squares, in such a way that the following conditions are met:\/ Ä;Å- *€^€T˜‘€8‚€ƒ€‚ÿ•There are exactly as many tents as trees.âßÄKÆ. *€Å€T˜‘€8‚€ƒ€‚ÿ•The tents and trees can be matched up in such a way that each tent is directly adjacent (horizontally or vertically, but not diagonally) to its own tree. However, a tent may be adjacent to other trees as well as its own.|I;ÅÇÆ3 6€’€T˜‘€8‚€ƒ€€€‚ÿ•No two tents are adjacent horizontally, vertically or diagonally.žqKÆeÇ- *€â€T˜‘€8‚€ƒ€‚ÿ•The number of tents in each row, and in each column, matches the numbers given round the sides of the grid.ÂœÇÆ'È& €9€˜€€‚ÿThis puzzle can be found in several places on the Internet, and was brought to my attention by e-mail. I don't know who I should credit for inventing it.R#eÇyÈ/ .€F€ãÅùN€€€‰‚ÿSection 25.1: Tents controlsT%'ÈÍÈ/ .€J€ã-ÅùN€€€‰‚ÿSection 25.2: Tents parametersNyÈLÉ1´§ ûˆ ILÉ–ÉÎSection 25.1: Tents controlsCBB("btn_up","JI(`',`games.tents')");EB("btn_up")J!ÍÈ–É) "€B€€€€‚ÿSection 25.1: Tents controls ÞLÉ Ê, &€½€˜€€€€‚ÿLeft-clicking in a blank square will place a tent in it. Right-clicking in a blank square will colour it green, indicating that you are sure it isn't a tent. Clicking either button in an occupied square will clear it.*þ–ÉÊË, &€ý€˜€€€€‚ÿIf you drag with the right button along a row or column, every blank square in the region you cover will be turned green, and no other squares will be affected. (This is useful for clearing the remainder of a row once you have placed all its tents.)È¢ Ê’Í& €E€˜€€‚ÿYou can also use the cursor keys to move around the grid. Pressing the return key over an empty square will place a tent, and pressing the space bar over an empty square will colour it green; either key will clear an occupied square. Holding Shift and pressing the cursor keys will colour empty squares green. Holding Control and pressing the cursor keys will colour green both empty squares and squares with tents.nCÊËÎ+ &€†€˜€€ãüÅùN‰‚ÿ(All the actions described in section 2.1 are also available.)P’ÍÎ1_… ÆJÎÍÎùSection 25.2: Tents parametersCBB("btn_up","JI(`',`games.tents')");EB("btn_up")L#ÎÍÎ) "€F€€€€‚ÿSection 25.2: Tents parametersvQÎCÏ% €¢€˜€€‚ÿThese parameters are available from the ‘Custom...’ option on the ‘Type’ menu.=Í΀Ï+ &€$€˜€€€€‚ÿWidth, HeightACÏÁÏ& €6€˜‘€€‚ÿSize of grid in squares.2 €Ï % €€˜€€‚ÿDifficultyÁÏ ÎíÆÁÏù' €€˜‘€€‚ÿControls the difficulty of the generated puzzle. More difficult puzzles require more complex deductions, but at present none of the available difficulty levels requires guesswork or backtracking.n= g1qûˆ Kg¨ØChapter 26: BridgesCBB("btn_up","JI(`',`Top')");EB("btn_up")Aù¨) "€0€€€€‚ÿChapter 26: BridgesÔ®g|& €]€˜€€‚ÿYou have a set of islands distributed across the playing area. Each island contains a number. Your aim is to connect the islands together with bridges, in such a way that:Z-¨Ö- *€Z€T˜‘€8‚€ƒ€‚ÿ•Bridges run horizontally or vertically.‘d|g- *€È€T˜‘€8‚€ƒ€‚ÿ•The number of bridges terminating at any island is equal to the number written in that island.cÖ÷- *€Æ€T˜‘€8‚€ƒ€‚ÿ•Two bridges may run in parallel between the same two islands, but no more than two may do so.T'gK- *€N€T˜‘€8‚€ƒ€‚ÿ•No bridge crosses another bridge.Z-÷¥- *€Z€T˜‘€8‚€ƒ€‚ÿ•All the islands are connected together.O)Kô& €S€˜€€‚ÿThere are some configurable alternative modes, which involve changing the parallel-bridge limit to something other than 2, and introducing the additional constraint that no sequence of bridges may form a loop from one island back to the same island. The rules stated above are the default ones.[0¥O+ &€`€˜€€ã“&ø¶‰‚ÿCredit for this puzzle goes to Nikoli [12].c>ô²% €|€˜€€‚ÿBridges was contributed to this collection by James Harvey.|QO.+ &€¢€˜€€€€‚ÿ[12] http://www.nikoli.co.jp/en/puzzles/hashiwokakero.html (beware of Flash)T%²‚/ .€J€ã$ÅùN€€€‰‚ÿSection 26.1: Bridges controlsV'.Ø/ .€N€ã%ÅùN€€€‰‚ÿSection 26.2: Bridges parametersƒR‚[1Ê ÆЄL[§1FSection 26.1: Bridges controlsCBB("btn_up","JI(`',`games.bridges')");EB("btn_up")L#ا) "€F€€€€‚ÿSection 26.1: Bridges controlsžx[E & €ñ€˜€€‚ÿTo place a bridge between two islands, click the mouse down on one island and drag it towards the other. You do not need to drag all the way to the other island; you only need to move the mouse far enough for the intended bridge direction to be unambiguous. (So you can keep the mouse near the starting island and conveniently throw bridges out from it in many directions.))§n & €€˜€€‚ÿDoing this again when a bridge is already present will add another parallel bridge. If there are already as many bridges between the two islands as permitted by the current game rules (i.e. two by default), the same dragging action will remove all of them.ݱE K , &€c€˜€€€€‚ÿIf you want to remind yourself that two islands definitely do not have a bridge between them, you can right-drag between them in the same way to draw a ‘non-bridge’ marker.â¼n -& €y€˜€€‚ÿIf you think you have finished with an island (i.e. you have placed all its bridges and are confident that they are in the right places), you can mark the island as finished by left-clicking on it. This will highlight it and all the bridges connected to it, and you will be prevented from accidentally modifying any of those bridges in future. Left-clicking again on a highlighted island will unmark it and restore your ability to modify it.Ö°K @& €a€˜€€‚ÿYou can also use the cursor keys to move around the grid: if possible the cursor will always move orthogonally, otherwise it will move towards the nearest island to the indicated direction. Holding Control and pressing a cursor key will lay a bridge in that direction (if available); Shift and a cursor key will lay a ‘non-bridge’ marker. Pressing the return key followed by a cursor key will also lay a bridge in that direction-@Ø.‰d-˜@% €È€˜€€‚ÿYou can mark an island as finished by pressing the space bar or by pressing the return key twice.±‹@IA& €€˜€€‚ÿBy pressing a number key, you can jump to the nearest island with that number. Letters ‘a’, ..., ‘f’ count as 10, ..., 15 and ‘0’ as 16.]8˜@¦A% €p€˜€€‚ÿViolations of the puzzle rules will be marked in red:nAIAB- *€‚€T˜‘€8‚€ƒ€‚ÿ•An island with too many bridges will be highlighted in red.Q#¦AeC. *€G€T˜‘€8‚€ƒ€‚ÿ•An island with too few bridges will be highlighted in red if it is definitely an error (as opposed to merely not being finished yet): if adding enough bridges would involve having to cross another bridge or remove a non-bridge marker, or if the island has been highlighted as complete.ŸqBE. *€ã€T˜‘€8‚€ƒ€‚ÿ•A group of islands and bridges may be highlighted in red if it is a closed subset of the puzzle with no way to connect it to the rest of the islands. For example, if you directly connect two 1s together with a bridge and they are not the only two islands on the grid, they will light up red to indicate that such a group cannot be contained in any valid solution.¿‘eCÃE. *€#€T˜‘€8‚€ƒ€‚ÿ•If you have selected the (non-default) option to disallow loops in the solution, a group of bridges which forms a loop will be highlighted.nCE1F+ &€†€˜€€ãüÅùN‰‚ÿ(All the actions described in section 2.1 are also available.)…TÃE¶F1Wæ‰M¶FG NSection 26.2: Bridges parametersCBB("btn_up","JI(`',`games.bridges')");EB("btn_up")N%1FG) "€J€€€€‚ÿSection 26.2: Bridges parametersvQ¶FzG% €¢€˜€€‚ÿThese parameters are available from the ‘Custom...’ option on the ‘Type’ menu.=G·G+ &€$€˜€€€€‚ÿWidth, HeightAzGøG& €6€˜‘€€‚ÿSize of grid in squares.2 ·G*H% €€˜€€‚ÿDifficultyDøGnH& €<€˜‘€€‚ÿDifficulty level of puzzle.3*H¡H% €€˜€€‚ÿAllow loopså¾nH†I' €}€˜‘€€‚ÿThis is set by default. If cleared, puzzles will be generated in such a way that they are always soluble without creating a loop, and solutions which do involve a loop will be disallowed.B¡HÈI% €:€˜€€‚ÿMax. bridges per direction³Œ†I{J' €€˜‘€€‚ÿMaximum number of bridges in any particular direction. The default is 2, but you can change it to 1, 3 or 4. In general, fewer is easier.>ÈI¹J% €2€˜€€‚ÿ%age of island squaresر{J‘K' €c€˜‘€€‚ÿGives a rough percentage of islands the generator will try and lay before finishing the puzzle. Certain layouts will not manage to lay enough islands; this is an upper bound.?¹JÐK% €4€˜€€‚ÿExpansion factor (%age)ƒ\‘KSM' €¹€˜‘€€‚ÿThe grid generator works by picking an existing island at random (after first creating an initial island somewhere). It then decides on a direction (at random), and then works out how far it could extend before creating another island. This parameter determines how likely it is to extend as far as it can, rather than choosing somewhere closer.º“ÐK N' €'€˜‘€€‚ÿHigh expansion factors usually mean easier puzzles with fewer possible islands; low expansion factors can create lots of tightly-packed islands.n=SM{N1‰Є[N{N¼N†Chapter 27: UnequalCBB("btn_up","JI(`',`Top')");EB("btn_up")A N¼N) "€0€€€€‚ÿChapter 27: UnequalîÈ{NªO& €‘€˜€€‚ÿYou have a square grid; each square may contain a digit from 1 to the size of the grid, and some squares have clue signs between them. Your aim is to fully populate the grid with numbers such that:f9¼N€- *€r€T˜‘€8‚€ƒ€‚ÿ•Each row contains only one occurrenceªO€ N of each digiti<ªO…€- *€x€T˜‘€8‚€ƒ€‚ÿ•Each column contains only one occurrence of each digitT'€Ù€- *€N€T˜‘€8‚€ƒ€‚ÿ•All the clue signs are satisfied.d?…€=% €~€˜€€‚ÿThere are two modes for this game, ‘Unequal’ and ‘Adjacent’.÷ÑÙ€4‚& €£€˜€€‚ÿIn ‘Unequal’ mode, the clue signs are greater-than symbols indicating one square's value is greater than its neighbour's. In this mode not all clues may be visible, particularly at higher difficulty levels.V0=Šƒ& €a€˜€€‚ÿIn ‘Adjacent’ mode, the clue signs are bars indicating one square's value is numerically adjacent (i.e. one higher or one lower) than its neighbour. In this mode all clues are always visible: absence of a bar thus means that a square's value is definitely not numerically adjacent to that neighbour's.ز4‚b„& €e€˜€€‚ÿIn ‘Trivial’ difficulty level (available via the ‘Custom’ game type selector), there are no greater-than signs in ‘Unequal’ mode; the puzzle is to solve the Latin square only.¡|Šƒ…% €ø€˜€€‚ÿAt the time of writing, the ‘Unequal’ mode of this puzzle is appearing in the Guardian weekly under the name ‘Futoshiki’.c>b„f…% €|€˜€€‚ÿUnequal was contributed to this collection by James Harvey.T%…º…/ .€J€ã&ÅùN€€€‰‚ÿSection 27.1: Unequal controlsV'f…†/ .€N€ã'ÅùN€€€‰‚ÿSection 27.2: Unequal parametersƒRº…“†1­ 所O“†߆LÀSection 27.1: Unequal controlsCBB("btn_up","JI(`',`games.unequal')");EB("btn_up")L#†߆) "€F€€€€‚ÿSection 27.1: Unequal controls\7“†;‡% €n€˜€€‚ÿUnequal shares much of its control system with Solo.%ÿ߆`ˆ& €ÿ€˜€€‚ÿTo play Unequal, simply click the mouse in any empty square and then type a digit or letter on the keyboard to fill that square. If you make a mistake, click the mouse in the incorrect square and press Space to clear it again (or use the Undo feature)./;‡‰, &€€˜€€€€‚ÿIf you right-click in a square and then type a number, that number will be entered in the square as a ‘pencil mark’. You can have pencil marks for multiple numbers in the same square. Squares containing filled-in numbers cannot also contain pencil marks.hB`ˆ÷Š& €…€˜€€‚ÿThe game pays no attention to pencil marks, so exactly what you use them for is up to you: you can use them as reminders that a particular square needs to be re-examined once you know more about a particular number, or you can use them as lists of the possible numbers in a given square, or anything else you feel like.€[‰w‹% €¶€˜€€‚ÿTo erase a single pencil mark, right-click in the square and type the same number again.ß¹÷ŠVŒ& €s€˜€€‚ÿAll pencil marks in a square are erased when you left-click and type a number, or when you left-click and press space. Right-clicking and pressing space will also erase pencil marks.5w‹‹& €€˜€€‚ÿAs for Solo, the cursor keys can be used in conjunction with the digit keys to set numbers or pencil marks. You can also use the ‘M’ key to auto-fill every numeric hint, ready for removal as required, or the ‘H’ key to do the same but also to remove all obvious hints.F VŒÑŽ& €A€˜€€‚ÿAlternatively, use the cursor keys to move the mark around the grid. Pressing the return key toggles the mark (from a normal mark to a pencil mark), and typing a number in is entered in the square in the appropriate way; typing in a 0 or using the space bar will clear a filled square.Û‹Ò& €·€˜€€‚ÿLeft-clicking a clue will mark it as done (grey it out), or unmark it if it is already marked. Holding Control or Shift and pressing an arrow key likewise marks any clue adjacent to the cursor in the given direction.nCÑŽLÀ+ &€†€˜€€ãüÅùN‰‚ÿ(AÒLÀ†ll the actions described in section 2.1 are also available.)…TÒÑÀ1…[U‚PÑÀÁVÄSection 27.2: Unequal parametersCBB("btn_up","JI(`',`games.unequal')");EB("btn_up")N%LÀÁ) "€J€€€€‚ÿSection 27.2: Unequal parametersvQÑÀ•Á% €¢€˜€€‚ÿThese parameters are available from the ‘Custom...’ option on the ‘Type’ menu.,ÁÁÁ% €€˜€€‚ÿModeU/•ÁÂ& €^€˜‘€€‚ÿMode of the puzzle (‘Unequal’ or ‘Adjacent’)2 ÁÁHÂ% €€˜€€‚ÿSize (s*s)6Â~Â& € €˜‘€€‚ÿSize of grid.2 H°Â% €€˜€€‚ÿDifficulty¦~ÂVÄ' €ÿ€˜‘€€‚ÿControls the difficulty of the generated puzzle. At Trivial level, there are no greater-than signs; the puzzle is to solve the Latin square only. At Recursive level (only available via the ‘Custom’ game type selector) backtracking will be required, but the solution should still be unique. The levels in between require increasingly complex reasoning to avoid having to backtrack.o>°ÂÅÄ1·€æ„QÅÄÅ|ÈChapter 28: GalaxiesCBB("btn_up","JI(`',`Top')");EB("btn_up")BVÄÅ) "€2€€€€‚ÿChapter 28: GalaxiesAÅÄHÆ& €7€˜€€‚ÿYou have a rectangular grid containing a number of dots. Your aim is to draw edges along the grid lines which divide the rectangle into regions in such a way that every region is 180° rotationally symmetric, and contains exactly one dot which is located at its centre of symmetry.ºŽÅÇ, &€€˜€€ãu™d@‰‚ÿThis puzzle was invented by Nikoli [13], under the name ‘Tentai Show’; its name is commonly translated into English as ‘Spiral Galaxies’.d?HÆfÇ% €~€˜€€‚ÿGalaxies was contributed to this collection by James Harvey.jBÇÐÇ( €„€˜€€€‚ÿ[13] http://www.nikoli.co.jp/en/puzzles/astronomical_show.htmlU&fÇ%È/ .€L€ã(ÅùN€€€‰‚ÿSection 28.1: Galaxies controlsW(ÐÇ|È/ .€P€ã)ÅùN€€€‰‚ÿSection 28.2: Galaxies parameters…T%ÈÉ1U‚RÉNÉSection 28.1: Galaxies controlsCBB("btn_up","JI(`',`games.galaxies')");EB("btn_up")M$|ÈNÉ) "€H€€€€‚ÿSection 28.1: Galaxies controlsjÉÞÊ& €Õ€˜€€‚ÿLeft-click on any grid line to draw an edge if there isn't one already, or to remove one if there is. When you create a valid region (one which is closed, contains exactly one dot, is 180° symmetric about that dot, and contains no extraneous edges inside it) it will be highlighted automatically; so your aim is to have the whole grid highlighted in that way. äNÉèÍ& €É€˜€€‚ÿDuring solving, you might know that a particular grid square belongs to a specific dot, but not be sure of where the edges go and which other squares are connected to the dot. In order to mark this so you don't forget, you can right-click on the dot and drag, which will create an arrow marker pointing at the dot. Drop that in a square of your choice and it will remind you which dot it's associated with. You can also right-click on existing arrows to pick them up and move them, or destroy them by dropping them off the edge of the grid. (Also, if you're not sure which dot an arrow is pointing at, you can pick it up and move it around to make it clearer. It will swivel constantly as you drag it, to stay pointed at its parent dot.)¯‰ÞÊ—Ï& €€˜€€‚ÿYou can also use the cursor keys to move around the grid squares and lines. Pressing the return key when over a grid line will draw or clear its edge, as above. Pressing the return key when over a dot will pick up an arrow, to be dropped the next time the return key is pressed; this can also be used to move existing arrows around, removing them by dropping them on a dot or another arrow.nCèÍ+ &€†€˜€€ãüÅùN‰‚ÿ(All the actions described in section 2.1 are also availabl—Ï|Èe.)‡V—Ϙ1Iæ„^S˜çáSection 28.2: Galaxies parametersCBB("btn_up","JI(`',`games.galaxies')");EB("btn_up")O&ç) "€L€€€€‚ÿSection 28.2: Galaxies parametersvQ˜]% €¢€˜€€‚ÿThese parameters are available from the ‘Custom...’ option on the ‘Type’ menu.=çš+ &€$€˜€€€€‚ÿWidth, HeightA]Û& €6€˜‘€€‚ÿSize of grid in squares.2 š % €€˜€€‚ÿDifficultyÔ­Ûá' €[€˜‘€€‚ÿControls the difficulty of the generated puzzle. More difficult puzzles require more complex deductions, and the ‘Unreasonable’ difficulty level may require backtracking.n= O1Á¯TOChapter 29: FillingCBB("btn_up","JI(`',`Top')");EB("btn_up")Aá) "€0€€€€‚ÿChapter 29: Filling*Oº& € €˜€€‚ÿYou have a grid of squares, some of which contain digits, and the rest of which are empty. Your job is to fill in digits in the empty squares, in such a way that each connected region of squares all containing the same digit has an area equal to that digit.•pO% €à€˜€€‚ÿ(‘Connected region’, for the purposes of this game, does not count diagonally separated squares as adjacent.)÷ѺF& €£€˜€€‚ÿFor example, it follows that no square can contain a zero, and that two adjacent squares can not both contain a one. No region has an area greater than 9 (because then its area would not be a single digit).[0O¡+ &€`€˜€€ã8CãK‰‚ÿCredit for this puzzle goes to Nikoli [14].c>F% €|€˜€€‚ÿFilling was contributed to this collection by Jonas Kölker.b:¡f( €t€˜€€€‚ÿ[14] http://www.nikoli.co.jp/en/puzzles/fillomino.htmlT%º/ .€J€ã*ÅùN€€€‰‚ÿSection 29.1: Filling controlsV'f/ .€N€ã+ÅùN€€€‰‚ÿSection 29.2: Filling parametersƒRº“16^EU“ßÉ Section 29.1: Filling controlsCBB("btn_up","JI(`',`games.filling')");EB("btn_up")L#ß) "€F€€€€‚ÿSection 29.1: Filling controls‰c“h & €Ç€˜€€‚ÿTo play Filling, simply click the mouse in any empty square and then type a digit on the keyboard to fill that square. By dragging the mouse, you can select multiple squares to fill with a single keypress. If you make a mistake, click the mouse in the incorrect square and press 0, Space, Backspace or Enter to clear it again (or use the Undo feature).óÍß[ & €›€˜€€‚ÿYou can also move around the grid with the cursor keys; typing a digit will fill the square containing the cursor with that number; typing 0 will clear it. You can also select multiple squares for numbering or clearing with the return and arrow keys, before typing a digit to fill or clear the highlighted squares (as above). The space bar adds and removes single squares to and from the selection. Backspace and escape remove all squares from the selection.nCh É + &€†€˜€€ãüÅùN‰‚ÿ(All the actions described in section 2.1 are also available.)…T[ N 1Ú¯ÑVN œ (Section 29.2: Filling parametersCBB("btn_up","JI(`',`games.filling')");EB("btn_up")N%É œ ) "€J€€€€‚ÿSection 29.2: Filling parametersŒgN (% €Î€˜€€‚ÿFilling allows you to configure the number of rows and columns of the grid, through the ‘Type’ menu.k:œ “1ÜE‹…W“ÑŠGChapter 30: KeenCBB("btn_up","JI(`',`Top')");EB("btn_up")>(Ñ) "€*€€€€‚ÿChapter 30: Keen ú“ @& €õ€˜€€‚ÿYou have a square grid; each square may contain a digit from 1 to the size of the grid. The grid is divided into blocks of varying shape and size, with arithmetic clues written in them. Your aim is to fully populate the grid with digits such that:Ñ @(f9Ñr@- *€r€T˜‘€8‚€ƒ€‚ÿ•Each row contains only one occurrence of each digiti< @Û@- *€x€T˜‘€8‚€ƒ€‚ÿ•Each column contains only one occurrence of each digit¾r@™A. *€!€T˜‘€8‚€ƒ€‚ÿ•The digits in each block can be combined to form the number stated in the clue, using the arithmetic operation given in the clue. That is:Ó¥Û@lB. *€K€T˜!8‚€ƒ€‚ÿ•An addition clue means that the sum of the digits in the block must be the given number. For example, ‘15+’ means the contents of the block adds up to fifteen.®€™AC. *€€T˜!8‚€ƒ€‚ÿ•A multiplication clue (e.g. ‘60×’), similarly, means that the product of the digits in the block must be the given number.šilB´D1 0€Ó€T˜!8‚€ƒ€€‚ÿ•A subtraction clue will always be written in a block of size two, and it means that one of the digits in the block is greater than the other by the given amount. For example, ‘2-’ means that one of the digits in the block is 2 more than the other, or equivalently that one digit minus the other one is 2. The two digits could be either way round, though.ÈšC|E. *€5€T˜!8‚€ƒ€‚ÿ•A division clue (e.g. ‘3÷’), similarly, is always in a block of size two and means that one digit divided by the other is equal to the given amount. Ü´D…F- (€¹€˜‘€€ãò¾eቂÿNote that a block may contain the same digit more than once (provided the identical ones are not in the same row and column). This rule is precisely the opposite of the rule in Solo's ‘Killer’ mode (see chapter 11).a<|EæF% €x€˜€€‚ÿThis puzzle appears in the Times under the name ‘KenKen’.Q"…F7G/ .€D€ã,ÅùN€€€‰‚ÿSection 30.1: Keen controlsS$æFŠG/ .€H€ãXÅùN€€€‰‚ÿSection 30.2: Keen parameters}L7GH1#ÑXHPH6€Section 30.1: Keen controlsCBB("btn_up","JI(`',`games.keen')");EB("btn_up")I ŠGPH) "€@€€€€‚ÿSection 30.1: Keen controlsgBH·H% €„€˜€€‚ÿKeen shares much of its control system with Solo (and Unequal).òPHÏI& €å€˜€€‚ÿTo play Keen, simply click the mouse in any empty square and then type a digit on the keyboard to fill that square. If you make a mistake, click the mouse in the incorrect square and press Space to clear it again (or use the Undo feature)./·HþJ, &€€˜€€€€‚ÿIf you right-click in a square and then type a number, that number will be entered in the square as a ‘pencil mark’. You can have pencil marks for multiple numbers in the same square. Squares containing filled-in numbers cannot also contain pencil marks.hBÏIfL& €…€˜€€‚ÿThe game pays no attention to pencil marks, so exactly what you use them for is up to you: you can use them as reminders that a particular square needs to be re-examined once you know more about a particular number, or you can use them as lists of the possible numbers in a given square, or anything else you feel like.€[þJæL% €¶€˜€€‚ÿTo erase a single pencil mark, right-click in the square and type the same number again.ß¹fLÅM& €s€˜€€‚ÿAll pencil marks in a square are erased when you left-click and type a number, or when you left-click and press space. Right-clicking and pressing space will also erase pencil marks.f@æL+O& €€˜€€‚ÿAs for Solo, the cursor keys can be used in conjunction with the digit keys to set numbers or pencil marks. Use the cursor keys to move a highlight around the grid, and type a digit to enter it in the highlighted square. Pressing return toggles the highlight into a mode in which you can enter or remove pencil marks.‘lÅM¼O% €Ø€˜€€‚ÿPressing M will fill in a full set of pencil marks in every square that does not have a main digit in it.nC+O6€+ &€†€˜€€ãüÅùN‰‚ÿ(All the actions describ¼O6€ŠGed in section 2.1 are also available.)N¼Oµ€1Ö‹…¥Yµ€‹„Section 30.2: Keen parametersCBB("btn_up","JI(`',`games.keen')");EB("btn_up")K"6€) "€D€€€€‚ÿSection 30.2: Keen parametersvQµ€v% €¢€˜€€‚ÿThese parameters are available from the ‘Custom...’ option on the ‘Type’ menu.1 §% €€˜€€‚ÿGrid sizeÜvj‚' €9€˜‘€€‚ÿSpecifies the size of the grid. Lower limit is 3; upper limit is 9 (because the user interface would become more difficult with ‘digits’ bigger than 9!).2 §œ‚% €€˜€€‚ÿDifficultyñj‚´ƒ' €ã€˜‘€€‚ÿControls the difficulty of the generated puzzle. At Unreasonable level, some backtracking will be required, but the solution should still be unique. The remaining levels require increasingly complex reasoning to avoid having to backtrack.;œ‚ïƒ% €,€˜€€‚ÿMultiplication onlyœv´ƒ‹„& €ì€˜‘€€‚ÿIf this is enabled, all boxes will be multiplication boxes. With this rule, the puzzle is known as ‘Inshi No Heya’.m<ïƒø„1EEZø„8…=‹Chapter 31: TowersCBB("btn_up","JI(`',`Top')");EB("btn_up")@‹„8…) "€.€€€€‚ÿChapter 31: TowersÞ¸ø„†& €q€˜€€‚ÿYou have a square grid. On each square of the grid you can build a tower, with its height ranging from 1 to the size of the grid. Around the edge of the grid are some numeric clues.jE8…€†% €Š€˜€€‚ÿYour task is to build a tower on every square, in such a way that:h;†è†- *€v€T˜‘€8‚€ƒ€‚ÿ•Each row contains every possible height of tower oncek>€†S‡- *€|€T˜‘€8‚€ƒ€‚ÿ•Each column contains every possible height of tower onceïÁè†B‰. *€ƒ€T˜‘€8‚€ƒ€‚ÿ•Each numeric clue describes the number of towers that can be seen if you look into the square from that direction, assuming that shorter towers are hidden behind taller ones. For example, in a 5×5 grid, a clue marked ‘5’ indicates that the five tower heights must appear in increasing order (otherwise you would not be able to see all five towers), whereas a clue marked ‘1’ indicates that the tallest tower (the one marked 5) must come first.´ŽS‡ö‰& €€˜€€‚ÿIn harder or larger puzzles, some towers will be specified for you as well as the clues round the edge, and some edge clues may be missing.ŸzB‰•Š% €ô€˜€€‚ÿThis puzzle appears on the web under various names, particularly ‘Skyscrapers’, but I don't know who first invented it.S$ö‰èŠ/ .€H€ãOÅùN€€€‰‚ÿSection 31.1: Towers controlsU&•Š=‹/ .€L€ãPÅùN€€€‰‚ÿSection 31.2: Towers parametersP芾‹1/ ¥ǃ[¾‹ ŒùÄSection 31.1: Towers controlsCBB("btn_up","JI(`',`games.towers')");EB("btn_up")K"=‹ Œ) "€D€€€€‚ÿSection 31.1: Towers controlsmH¾‹vŒ% €€˜€€‚ÿTowers shares much of its control system with Solo, Unequal and Keen.; Œ±& €+€˜€€‚ÿTo play Towers, simply click the mouse in any empty square and then type a digit on the keyboard to fill that square with a tower of the given height. If you make a mistake, click the mouse in the incorrect square and press Space to clear it again (or use the Undo feature).&úvŒ׎, &€õ€˜€€€€‚ÿIf you right-click in a square and then type a number, that number will be entered in the square as a ‘pencil mark’. You can have pencil marks for multiple numbers in the same square. A square containing a tower cannot also contain pencil marks.hB±KÀ& €…€˜€€‚ÿThe game pays no attention to pencil marks, so exactly what you use them for is up to you: you can use them as reminders that a particular square needs to be re-examined once you know more about a particular number, or you can use them as lists of the possib׎KÀ=‹le numbers in a given square, or anything else you feel like.€[׎ËÀ% €¶€˜€€‚ÿTo erase a single pencil mark, right-click in the square and type the same number again.ß¹KÀªÁ& €s€˜€€‚ÿAll pencil marks in a square are erased when you left-click and type a number, or when you left-click and press space. Right-clicking and pressing space will also erase pencil marks.f@ËÀÃ& €€˜€€‚ÿAs for Solo, the cursor keys can be used in conjunction with the digit keys to set numbers or pencil marks. Use the cursor keys to move a highlight around the grid, and type a digit to enter it in the highlighted square. Pressing return toggles the highlight into a mode in which you can enter or remove pencil marks.‘lªÁ¡Ã% €Ø€˜€€‚ÿPressing M will fill in a full set of pencil marks in every square that does not have a main digit in it.êÄËÄ& €‰€˜€€‚ÿLeft-clicking a clue will mark it as done (grey it out), or unmark it if it is already marked. Holding Control or Shift and pressing an arrow key likewise marks any clue in the given direction.nC¡ÃùÄ+ &€†€˜€€ãüÅùN‰‚ÿ(All the actions described in section 2.1 are also available.)ƒR‹Ä|Å1Eâ…\|ÅÉÅ}ÈSection 31.2: Towers parametersCBB("btn_up","JI(`',`games.towers')");EB("btn_up")M$ùÄÉÅ) "€H€€€€‚ÿSection 31.2: Towers parametersvQ|Å?Æ% €¢€˜€€‚ÿThese parameters are available from the ‘Custom...’ option on the ‘Type’ menu.1 ÉÅpÆ% €€˜€€‚ÿGrid sizeÜ?Æ3Ç' €9€˜‘€€‚ÿSpecifies the size of the grid. Lower limit is 3; upper limit is 9 (because the user interface would become more difficult with ‘digits’ bigger than 9!).2 pÆeÇ% €€˜€€‚ÿDifficultyñ3Ç}È' €ã€˜‘€€‚ÿControls the difficulty of the generated puzzle. At Unreasonable level, some backtracking will be required, but the solution should still be unique. The remaining levels require increasingly complex reasoning to avoid having to backtrack.n=eÇëÈ1¢ǃÕˆ]ëÈ,ÉÍChapter 32: SinglesCBB("btn_up","JI(`',`Top')");EB("btn_up")A}È,É) "€0€€€€‚ÿChapter 32: Singlesá»ëÈ Ê& €w€˜€€‚ÿYou have a grid of white squares, all of which contain numbers. Your task is to colour some of the squares black (removing the number) so as to satisfy all of the following conditions:h;,ÉuÊ- *€v€T˜‘€8‚€ƒ€‚ÿ•No number occurs more than once in any row or column.„W ÊùÊ- *€®€T˜‘€8‚€ƒ€‚ÿ•No black square is horizontally or vertically adjacent to any other black square.¦yuÊŸË- *€ò€T˜‘€8‚€ƒ€‚ÿ•The remaining white squares must all form one contiguous region (connected by edges, not just touching at corners).nCùÊ Ì+ &€†€˜€€ãDrn‰‚ÿCredit for this puzzle goes to Nikoli [15] who call it Hitori.c>ŸËpÌ% €|€˜€€‚ÿSingles was contributed to this collection by James Harvey.sH ÌãÌ+ &€€˜€€€€‚ÿ[15] http://www.nikoli.com/en/puzzles/hitori.html (beware of Flash)T%pÌ7Í/ .€J€ãQÅùN€€€‰‚ÿSection 32.1: Singles controlsV'ãÌÍ/ .€N€ãRÅùN€€€‰‚ÿSection 32.2: Singles parametersƒR7ÍÎ1¨â…C^Î\ÎÄ Section 32.1: Singles controlsCBB("btn_up","JI(`',`games.singles')");EB("btn_up")L#Í\Î) "€F€€€€‚ÿSection 32.1: Singles controlsêÄÎFÏ& €‰€˜€€‚ÿLeft-clicking on an empty square will colour it black; left-clicking again will restore the number. Right-clicking will add a circle (useful for indicating that a cell is definitely not black).Þ\ÎV & €½€˜€€‚ÿYou can also use the cursor keys to move around the grid. Pressing the return or space keys will turn a square black or add a circle respectively, FÏV Íand pressing the key again will restore the number or remove the circle.nCFÏÄ + &€†€˜€€ãüÅùN‰‚ÿ(All the actions described in section 2.1 are also available.)…TV I 1ÍÕˆ&_I —  Section 32.2: Singles parametersCBB("btn_up","JI(`',`games.singles')");EB("btn_up")N%Ä — ) "€J€€€€‚ÿSection 32.2: Singles parametersvQI  % €¢€˜€€‚ÿThese parameters are available from the ‘Custom...’ option on the ‘Type’ menu.=— J + &€$€˜€€€€‚ÿWidth, HeightA  ‹ & €6€˜‘€€‚ÿSize of grid in squares.2 J ½ % €€˜€€‚ÿDifficultyY3‹  & €f€˜‘€€‚ÿControls the difficulty of the generated puzzle.n=½ „ 1ëCÆ`„ Å o Chapter 33: MagnetsCBB("btn_up","JI(`',`Top')");EB("btn_up")A Å ) "€0€€€€‚ÿChapter 33: Magnets¢|„ g & €ù€˜€€‚ÿA rectangular grid has been filled with a mixture of magnets (that is, dominoes with one positive end and one negative end) and blank dominoes (that is, dominoes with two neutral poles). These dominoes are initially only seen in silhouette. Around the grid are placed a number of clues indicating the number of positive and negative poles contained in certain columns and rows.CÅ ª & €;€˜€€‚ÿYour aim is to correctly place the magnets and blank dominoes such that all the clues are satisfied, with the additional constraint that no two similar magnetic poles may be orthogonally adjacent (since they repel). Neutral poles do not repel, and can be adjacent to any other pole.Z/g  + &€^€˜€€ãÌAR‰‚ÿCredit for this puzzle goes to Janko [16].c>ª g % €|€˜€€‚ÿMagnets was contributed to this collection by James Harvey.^6 Å ( €l€˜€€€‚ÿ[16] http://www.janko.at/Raetsel/Magnete/index.htmT%g  / .€J€ãSÅùN€€€‰‚ÿSection 33.1: Magnets controlsV'Å o / .€N€ãTÅùN€€€‰‚ÿSection 33.2: Magnets parametersƒR ò 1&Üaò > ó Section 33.1: Magnets controlsCBB("btn_up","JI(`',`games.magnets')");EB("btn_up")L#o > ) "€F€€€€‚ÿSection 33.1: Magnets controlsñò U & €ã€˜€€‚ÿLeft-clicking on an empty square places a magnet at that position with the positive pole on the square and the negative pole on the other half of the magnet; left-clicking again reverses the polarity, and a third click removes the magnet.,> & € €˜€€‚ÿRight-clicking on an empty square places a blank domino there. Right-clicking again places two question marks on the domino, signifying ‘this cannot be blank’ (which can be useful to note deductions while solving), and right-clicking again empties the domino.†aU  % €Â€˜€€‚ÿLeft-clicking a clue will mark it as done (grey it out), or unmark it if it is already marked.~X … & €±€˜€€‚ÿYou can also use the cursor keys to move a cursor around the grid. Pressing the return key will lay a domino with a positive pole at that position; pressing again reverses the polarity and then removes the domino, as with left-clicking. Using the space bar allows placement of blank dominoes and cannot-be-blank hints, as for right-clicking.nC ó + &€†€˜€€ãüÅùN‰‚ÿ(All the actions described in section 2.1 are also available.)…T… x 1æÆibx Æ jB Section 33.2: Magnets parametersCBB("btn_up","JI(`',`games.magnets')");EB("btn_up")N%ó Æ ) "€J€€€€‚ÿSection 33.2: Magnets parametersvQx < % €¢€˜€€‚ÿThese parameters are available from the ‘Custom...’ option on the ‘Type’ menu.=Æ y + &€$€˜€€€€‚ÿWidth, Height¿Œ< D@ 3 4€€˜‘€€€€€€‚ÿSize of grid in squares. There will be half Width × Height dominoes in the gridy D@ ó : if this number is odd then one square will be blank.lFy °@ & €Œ€˜‘€€‚ÿ(Grids with at least one odd dimension tend to be easier to solve.)2 D@ â@ % €€˜€€‚ÿDifficultyÀ™°@ ¢A ' €3€˜‘€€‚ÿControls the difficulty of the generated puzzle. At Tricky level, you are required to make more deductions about empty dominoes and row/column counts.3â@ ÕA % €€˜€€‚ÿStrip clues•o¢A jB & €Þ€˜‘€€‚ÿIf true, some of the clues around the grid are removed at generation time, making the puzzle more difficult.o>ÕA ÙB 1Ü …cÙB C ÚG Chapter 34: SignpostCBB("btn_up","JI(`',`Top')");EB("btn_up")BjB C ) "€2€€€€‚ÿChapter 34: Signpost8ÙB SE & €%€˜€€‚ÿYou have a grid of squares; each square (except the last one) contains an arrow, and some squares also contain numbers. Your job is to connect the squares to form a continuous list of numbers starting at 1 and linked in the direction of the arrows – so the arrow inside the square with the number 1 will point to the square containing the number 2, which will point to the square containing the number 3, etc. Each square can be any distance away from the previous one, as long as it is somewhere in the direction of the arrow.™tC ìE % €è€˜€€‚ÿBy convention the first and last numbers are shown; one or more interim numbers may also appear at the beginning.‚WSE nF + &€®€˜€€ãÐYFQ‰‚ÿCredit for this puzzle goes to Janko [17], who call it ‘Pfeilpfad’ (‘arrow path’).d?ìE ÒF % €~€˜€€‚ÿSignpost was contributed to this collection by James Harvey.\4nF .G ( €h€˜€€€‚ÿ[17] http://janko.at/Raetsel/Pfeilpfad/index.htmU&ÒF ƒG / .€L€ãUÅùN€€€‰‚ÿSection 34.1: Signpost controlsW(.G ÚG / .€P€ãVÅùN€€€‰‚ÿSection 34.2: Signpost parameters…TƒG _H 1[iCd_H ¬H Æ€ Section 34.1: Signpost controlsCBB("btn_up","JI(`',`games.signpost')");EB("btn_up")M$ÚG ¬H ) "€H€€€€‚ÿSection 34.1: Signpost controls'_H ÓI & €€˜€€‚ÿTo play Signpost, you connect squares together by dragging from one square to another, indicating that they are adjacent in the sequence. Drag with the left button from a square to its successor, or with the right button from a square to its predecessor.þÀ¬H ÑK > J€€˜€€€€€€€€€€‚ÿIf you connect together two squares in this way and one of them has a number in it, the appropriate number will appear in the other square. If you connect two non-numbered squares, they will be assigned temporary algebraic labels: on the first occasion, they will be labelled ‘a’ and ‘a+1’, and then ‘b’ and ‘b+1’, and so on. Connecting more squares on to the ends of such a chain will cause them all to be labelled with the same letter.‰dÓI ZL % €È€˜€€‚ÿWhen you left-click or right-click in a square, the legal squares to connect it to will be shown.hBÑK ÂM & €…€˜€€‚ÿThe arrow in each square starts off black, and goes grey once you connect the square to its successor. Also, each square which needs a predecessor has a small dot in the bottom left corner, which vanishes once you link a square to it. So your aim is always to connect a square with a black arrow to a square with a dot.×±ZL ™N & €c€˜€€‚ÿTo remove any links for a particular square (both incoming and outgoing), left-drag it off the grid. To remove a whole chain, right-drag any square in the chain off the grid.³ÂM X€ & €€˜€€‚ÿYou can also use the cursor keys to move around the grid squares and lines. Pressing the return key when over a square starts a link operation, and pressing the return key again over a square will finish the link, if allowable. Pressing the space bar over a square will show the other squares pointing to it, and allow y™N X€ ÚG ou to form a backward link, and pressing the space bar again cancels this.nC™N Æ€ + &€†€˜€€ãüÅùN‰‚ÿ(All the actions described in section 2.1 are also available.)‡VX€ M 1Š …âeM œ ׃ Section 34.2: Signpost parametersCBB("btn_up","JI(`',`games.signpost')");EB("btn_up")O&Æ€ œ ) "€L€€€€‚ÿSection 34.2: Signpost parametersvQM ‚ % €¢€˜€€‚ÿThese parameters are available from the ‘Custom...’ option on the ‘Type’ menu.=œ O‚ + &€$€˜€€€€‚ÿWidth, HeightA‚ ‚ & €6€˜‘€€‚ÿSize of grid in squares.BO‚ Ò‚ % €:€˜€€‚ÿForce start/end to cornersÞ‚ ׃ ' €½€˜‘€€‚ÿIf true, the start and end squares are always placed in opposite corners (the start at the top left, and the end at the bottom right). If false the start and end squares are placed randomly (although always both shown).l;Ò‚ C„ 1úCÛfC„ ‚„ =‹ Chapter 35: RangeCBB("btn_up","JI(`',`Top')");EB("btn_up")?׃ ‚„ ) "€,€€€€‚ÿChapter 35: Range½—C„ ?… & €/€˜€€‚ÿYou have a grid of squares; some squares contain numbers. Your job is to colour some of the squares black, such that several criteria are satisfied:]0‚„ œ… - *€`€T˜‘€8‚€ƒ€‚ÿ•no square with a number is coloured black.rE?… † - *€Š€T˜‘€8‚€ƒ€‚ÿ•no two black squares are adjacent (horizontally or vertically).„Wœ… ’† - *€®€T˜‘€8‚€ƒ€‚ÿ•for any two white squares, there is a path between them using only white squares.H† Ú‡ . *€5€T˜‘€8‚€ƒ€‚ÿ•for each square with a number, that number denotes the total number of white squares reachable from that square going in a straight line in any horizontal or vertical direction until hitting a wall or a black square; the square with the number is included in the total (once).C’† ‰ & €;€˜€€‚ÿFor instance, a square containing the number one must have four black squares as its neighbours by the last criterion; but then it's impossible for it to be connected to any outside white square, which violates the second to last criterion. So no square will contain the number one.¬€Ú‡ ɉ , &€€˜€€ãùÑÛ‰‚ÿCredit for this puzzle goes to Nikoli, who have variously called it ‘Kurodoko’, ‘Kuromasu’ or ‘Where is Black Cells’. [18].a<‰ *Š % €x€˜€€‚ÿRange was contributed to this collection by Jonas Kölker.mEɉ —Š ( €Š€˜€€€‚ÿ[18] http://www.nikoli.co.jp/en/puzzles/where_is_black_cells.htmlR#*Š éŠ / .€F€ãWÅùN€€€‰‚ÿSection 35.1: Range controlsT%—Š =‹ / .€J€ãƒÅùN€€€‰‚ÿSection 35.2: Range parametersNéŠ ¼‹ 1kâ  g¼‹ Œ ' Section 35.1: Range controlsCBB("btn_up","JI(`',`games.range')");EB("btn_up")J!=‹ Œ ) "€B€€€€‚ÿSection 35.1: Range controlsf:¼‹ l , &€u€˜€€€€‚ÿClick with the left button to paint a square black, or with the right button to mark a square with a dot to indicate that you are sure it should not be painted black. Repeated clicking with either button will cycle the square through the three possible states (filled, dotted or empty) in opposite directions.M'Œ ¹Ž & €O€˜€€‚ÿYou can also use the cursor keys to move around the grid squares. Pressing Return does the same as clicking with the left button, while pressing Space does the same as a right button click. Moving with the cursor keys while holding Shift will place dots in all squares that are moved through.nCl ' + &€†€˜€€ãüÅùN‰‚ÿ(All the actions described in section 2.1 are also available.)P¹Ž ¨ 1@Û~€h¨ À Á Section 35.2: Range parametersCBB("btn_up","JI(`',`games.range')");EB("btn_up")L#' À ) "€F€€€€‚ÿSection 35.2: Range parameters¨ À ' vQ¨ ‚À % €¢€˜€€‚ÿThese parameters are available from the ‘Custom...’ option on the ‘Type’ menu.= À ¿À + &€$€˜€€€€‚ÿWidth, HeightA‚À Á & €6€˜‘€€‚ÿSize of grid in squares.l;¿À lÁ 1ÿ  ¬…ilÁ «Á kÈ Chapter 36: PearlCBB("btn_up","JI(`',`Top')");EB("btn_up")?Á «Á ) "€,€€€€‚ÿChapter 36: PearlÆ lÁ qà & €A€˜€€‚ÿYou have a grid of squares. Your job is to draw lines between the centres of horizontally or vertically adjacent squares, so that the lines form a single closed loop. In the resulting grid, some of the squares that the loop passes through will contain corners, and some will be straight horizontal or vertical lines. (And some squares can be completely empty – the loop doesn't have to pass through every square.)ˆc«Á ùà % €Æ€˜€€‚ÿSome of the squares contain black and white circles, which are clues that the loop must satisfy.³qà ¬Ä & €€˜€€‚ÿA black circle in a square indicates that that square is a corner, but neither of the squares adjacent to it in the loop is also a corner.µ‰ùà aÅ , &€€˜€€€€‚ÿA white circle indicates that the square is a straight edge, but at least one of the squares adjacent to it in the loop is a corner.è¬Ä {Æ 2 2€Ñ€˜€€€€€€‚ÿ(In both cases, the clue only constrains the two squares adjacent in the loop, that is, the squares that the loop passes into after leaving the clue square. The squares that are only adjacent in the grid are not constrained.)pEaÅ ëÆ + &€Š€˜€€ãÿ!nÛ‰‚ÿCredit for this puzzle goes to Nikoli, who call it ‘Masyu’. [19]fA{Æ QÇ % €‚€˜€€‚ÿThanks to James Harvey for assistance with the implementation.tIëÆ ÅÇ + &€’€˜€€€€‚ÿ[19] http://www.nikoli.co.jp/en/puzzles/masyu.html (beware of Flash)R#QÇ È / .€F€ãzÅùN€€€‰‚ÿSection 36.1: Pearl controlsT%ÅÇ kÈ / .€J€ã{ÅùN€€€‰‚ÿSection 36.2: Pearl parametersNÈ êÈ 1í~€ŠjêÈ 4É ×Î Section 36.1: Pearl controlsCBB("btn_up","JI(`',`games.pearl')");EB("btn_up")J!kÈ 4É ) "€B€€€€‚ÿSection 36.1: Pearl controls¬†êÈ àÉ & € €˜€€‚ÿClick with the left button on a grid edge to draw a segment of the loop through that edge, or to remove a segment once it is drawn.ï4É õÊ & €ß€˜€€‚ÿDrag with the left button through a series of squares to draw more than one segment of the loop in one go. Alternatively, drag over an existing part of the loop to undraw it, or to undraw part of it and then go in a different direction.ƒWàÉ xÌ , &€¯€˜€€€€‚ÿClick with the right button on a grid edge to mark it with a cross, indicating that you are sure the loop does not go through that edge. (For instance, if you have decided which of the squares adjacent to a white clue has to be a corner, but don't yet know which way the corner turns, you might mark the one way it can't go with a cross.)?õÊ ·Í & €3€˜€€‚ÿAlternatively, use the cursor keys to move the cursor. Use the Enter key to begin and end keyboard ‘drag’ operations. Use the Space, Escape or Backspace keys to cancel the drag. Or, hold Control while dragging with the cursor keys to toggle segments as you move between squares.²ŒxÌ iÎ & €€˜€€‚ÿPressing Control-Shift-arrowkey or Shift-arrowkey simulates a left or right click, respectively, on the edge in the direction of the key.nC·Í ×Î + &€†€˜€€ãüÅùN‰‚ÿ(All the actions described in section 2.1 are also available.)PiÎ XÏ 1¬…kXÏ ¤Ï & Section 36.2: Pearl parametersCBB("btn_up","JI(`',`games.pearl')");EB("btn_up")L#×Î ¤Ï ) "€F€€€€‚ÿSection 36.2: Pearl parametersvQXÏ & % €¢€˜€€‚ÿThese parameters are available from the ‘Custom...’ op¤Ï & ×Î tion on the ‘Type’ menu.m<¤Ï “ 1Šªl“ Ó ® Chapter 37: UndeadCBB("btn_up","JI(`',`Top')");EB("btn_up")@& Ó ) "€.€€€€‚ÿChapter 37: UndeadïÉ“  & €“€˜€€‚ÿYou are given a grid of squares, some of which contain diagonal mirrors. Every square which is not a mirror must be filled with one of three types of undead monster: a ghost, a vampire, or a zombie.ÛÓ Ã & €·€˜€€‚ÿVampires can be seen directly, but are invisible when reflected in mirrors. Ghosts are the opposite way round: they can be seen in mirrors, but are invisible when looked at directly. Zombies are visible by any means.߹ ¢ & €s€˜€€‚ÿYou are also told the total number of each type of monster in the grid. Also around the edge of the grid are written numbers, which indicate how many monsters can be seen if you look into the grid along a row or column starting from that position. (The diagonal mirrors are reflective on both sides. If your reflected line of sight crosses the same monster more than once, the number will count it each time it is visible, not just once.)Ÿtà A + &€è€˜€€ãÄT( ‰‚ÿThis puzzle type was invented by David Millar, under the name ‘Haunted Mirror Maze’. See [20] for more details.c>¢ ¤ % €|€˜€€‚ÿUndead was contributed to this collection by Steffen Bauer.b:A  ( €t€˜€€€‚ÿ[20] http://www.janko.at/Raetsel/Spukschloss/index.htmS$¤ Y / .€H€ã|ÅùN€€€‰‚ÿSection 37.1: Undead controlsU& ® / .€L€ã}ÅùN€€€‰‚ÿSection 37.2: Undead parametersPY / 1` C€m/ z ›@ Section 37.1: Undead controlsCBB("btn_up","JI(`',`games.undead')");EB("btn_up")K"® z ) "€D€€€€‚ÿSection 37.1: Undead controlsfA/ à % €‚€˜€€‚ÿUndead has a similar control system to Solo, Unequal and Keen.X2z 8 & €e€˜€€‚ÿTo play Undead, click the mouse in any empty square and then type a letter on the keyboard indicating the type of monster: ‘G’ for a ghost, ‘V’ for a vampire, or ‘Z’ for a zombie. If you make a mistake, click the mouse in the incorrect square and press Space to clear it again (or use the Undo feature).Q%à ‰ , &€K€˜€€€€‚ÿIf you right-click in a square and then type a letter, the corresponding monster will be shown in reduced size in that square, as a ‘pencil mark’. You can have pencil marks for multiple monsters in the same square. A square containing a full-size monster cannot also contain pencil marks.iC8 ò & €‡€˜€€‚ÿThe game pays no attention to pencil marks, so exactly what you use them for is up to you: you can use them as reminders that a particular square needs to be re-examined once you know more about a particular monster, or you can use them as lists of the possible monster in a given square, or anything else you feel like.€[‰ r % €¶€˜€€‚ÿTo erase a single pencil mark, right-click in the square and type the same letter again.çÁò Y & €ƒ€˜€€‚ÿAll pencil marks in a square are erased when you left-click and type a monster letter, or when you left-click and press Space. Right-clicking and pressing space will also erase pencil marks.sMr Ì & €›€˜€€‚ÿAs for Solo, the cursor keys can be used in conjunction with the letter keys to place monsters or pencil marks. Use the cursor keys to move a highlight around the grid, and type a monster letter to enter it in the highlighted square. Pressing return toggles the highlight into a mode in which you can enter or remove pencil marks.Ï©Y › & €S€˜€€‚ÿIf you prefer plain letters of the alphabet to cute monster pictures, you can press ‘A’ to toggle between showing the monsters as monsters or showing them as letters.†aÌ -@ % €Â€˜€€‚ÿLeft-clicking a clue will mark it as done (grey it out), or unm› -@ ® ark it if it is already marked.nC› ›@ + &€†€˜€€ãüÅùN‰‚ÿ(All the actions described in section 2.1 are also available.)ƒR-@ A 1̪%nA kA êB Section 37.2: Undead parametersCBB("btn_up","JI(`',`games.undead')");EB("btn_up")M$›@ kA ) "€H€€€€‚ÿSection 37.2: Undead parametersvQA áA % €¢€˜€€‚ÿThese parameters are available from the ‘Custom...’ option on the ‘Type’ menu.=kA B + &€$€˜€€€€‚ÿWidth, HeightAáA _B & €6€˜‘€€‚ÿSize of grid in squares.2 B ‘B % €€˜€€‚ÿDifficultyY3_B êB & €f€˜‘€€‚ÿControls the difficulty of the generated puzzle.m<‘B WC 1§C€§ƒoWC —C þF Chapter 38: UnrulyCBB("btn_up","JI(`',`Top')");EB("btn_up")@êB —C ) "€.€€€€‚ÿChapter 38: Unruly\6WC óD & €m€˜€€‚ÿYou are given a grid of squares, which you must colour either black or white. Some squares are provided as clues; the rest are left for you to fill in. Each row and column must contain the same number of black and white squares, and no row or column may contain three consecutive squares of the same colour.œq—C E + &€â€˜€€ãLÆ9 ‰‚ÿThis puzzle type was invented by Adolfo Zanellati, under the name ‘Tohu wa Vohu’. See [21] for more details.d?óD óE % €~€˜€€‚ÿUnruly was contributed to this collection by Lennard Sprong.c;E VF ( €v€˜€€€‚ÿ[21] http://www.janko.at/Raetsel/Tohu-Wa-Vohu/index.htmS$óE ©F / .€H€ã~ÅùN€€€‰‚ÿSection 38.1: Unruly controlsU&VF þF / .€L€ãÅùN€€€‰‚ÿSection 38.2: Unruly parametersP©F G 1B%I†pG ÊG ÁJ Section 38.1: Unruly controlsCBB("btn_up","JI(`',`games.unruly')");EB("btn_up")K"þF ÊG ) "€D€€€€‚ÿSection 38.1: Unruly controlsW1G !I & €c€˜€€‚ÿTo play Unruly, click the mouse in a square to change its colour. Left-clicking an empty square will turn it black, and right-clicking will turn it white. Keep clicking the same button to cycle through the three possible states for the square. If you middle-click in a square it will be reset to empty.2 ÊG SJ & €€˜€€‚ÿYou can also use the cursor keys to move around the grid. Pressing the return or space keys will turn an empty square black or white respectively (and then cycle the colours in the same way as the mouse buttons), and pressing Backspace will reset a square to empty.nC!I ÁJ + &€†€˜€€ãüÅùN‰‚ÿ(All the actions described in section 2.1 are also available.)ƒRSJ DK 1§ƒ%ˆqDK ‘K VN Section 38.2: Unruly parametersCBB("btn_up","JI(`',`games.unruly')");EB("btn_up")M$ÁJ ‘K ) "€H€€€€‚ÿSection 38.2: Unruly parametersvQDK L % €¢€˜€€‚ÿThese parameters are available from the ‘Custom...’ option on the ‘Type’ menu.=‘K DL + &€$€˜€€€€‚ÿWidth, Height™sL ÝL & €æ€˜‘€€‚ÿSize of grid in squares. (Note that the rules of the game require both the width and height to be even numbers.)2 DL M % €€˜€€‚ÿDifficultyY3ÝL hM & €f€˜‘€€‚ÿControls the difficulty of the generated puzzle.?M §M % €4€˜€€‚ÿUnique rows and columns¯ˆhM VN ' €€˜‘€€‚ÿIf enabled, no two rows are permitted to have exactly the same pattern, and likewise columns. (A row and a column can match, though.)l;§M ÂN 1sI†ÛrÂN O Aƒ Chapter 39: FloodCBB("btn_up","JI(`',`Top')");EB("btn_up")?VN O ) "€,€€€€‚ÿChapter 39: Flood¯‰ÂN ¼€ & €€˜€€‚ÿYou are given a grid of squares, coloured at random in multiple colours. In each move, you can flood-fill the top left square in a colour of your choice (i.e. every square reachable from the starting square by an ortO ¼€ VN hogonally connected path of squares all the same colour will be filled in the new colour). As you do this, more and more of the grid becomes connected to the starting square.)O å & €€˜€€‚ÿYour aim is to make the whole grid the same colour, in as few moves as possible. The game will set a limit on the number of moves, based on running its own internal solver. You win if you can make the whole grid the same colour in that many moves or fewer.¶¼€ ›‚ & €!€˜€€‚ÿI saw this game (with a fixed grid size, fixed number of colours, and fixed move limit) at http://floodit.appspot.com (no longer accessible).R#å í‚ / .€F€ã€ÅùN€€€‰‚ÿSection 39.1: Flood controlsT%›‚ Aƒ / .€J€ãÅùN€€€‰‚ÿSection 39.2: Flood parametersNí‚ Àƒ 1Õ%ˆsÀƒ „ •† Section 39.1: Flood controlsCBB("btn_up","JI(`',`games.flood')");EB("btn_up")J!Aƒ „ ) "€B€€€€‚ÿSection 39.1: Flood controls7Àƒ A… & €#€˜€€‚ÿTo play Flood, click the mouse in a square. The top left corner and everything connected to it will be flood-filled with the colour of the square you clicked. Clicking a square the same colour as the top left corner has no effect, and therefore does not count as a move.æÀ „ '† & €€˜€€‚ÿYou can also use the cursor keys to move a cursor (outline black square) around the grid. Pressing the return key will fill the top left corner in the colour of the square under the cursor.nCA… •† + &€†€˜€€ãüÅùN‰‚ÿ(All the actions described in section 2.1 are also available.)P'† ‡ 1cÛt‡ b‡ yŒ Section 39.2: Flood parametersCBB("btn_up","JI(`',`games.flood')");EB("btn_up")L#•† b‡ ) "€F€€€€‚ÿSection 39.2: Flood parametersvQ‡ ؇ % €¢€˜€€‚ÿThese parameters are available from the ‘Custom...’ option on the ‘Type’ menu.=b‡ ˆ + &€$€˜€€€€‚ÿWidth, HeightF ؇ [ˆ & €@€˜‘€€‚ÿSize of the grid, in squares./ ˆ Šˆ % €€˜€€‚ÿColoursÙ²[ˆ c‰ ' €e€˜‘€€‚ÿNumber of colours used to fill the grid. Must be at least 3 (with two colours there would only be one legal move at any stage, hence no choice to make at all), and at most 10.=Šˆ  ‰ % €0€˜€€‚ÿExtra moves permittedªƒc‰ J‹ ' €€˜‘€€‚ÿControls the difficulty of the puzzle, by increasing the move limit. In each new grid, Flood will run an internal solver to generate its own solution, and then the value in this field will be added to the length of Flood's solution to generate the game's move limit. So a value of 0 requires you to be just as efficient as Flood's automated solver, and a larger value makes it easier./ ‰ yŒ - (€€˜‘€€€€‚ÿ(Note that Flood's internal solver will not necessarily find the shortest possible solution, though I believe it's pretty close. For a real challenge, set this value to 0 and then try to solve a grid in strictly fewer moves than the limit you're given!)m<J‹ æŒ 1ð€uæŒ & À Chapter 40: TracksCBB("btn_up","JI(`',`Top')");EB("btn_up")@yŒ & ) "€.€€€€‚ÿChapter 40: Tracks'æŒ MŽ & €€˜€€‚ÿYou are given a grid of squares, some of which are filled with train tracks. You need to complete the track from A to B so that the rows and columns contain the same number of track segments as are indicated in the clues to the top and right of the grid.Z& ÌŽ % €´€˜€€‚ÿThere are only straight and 90 degree curved rails, and the track may not cross itself.b=MŽ . % €z€˜€€‚ÿTracks was contributed to this collection by James Harvey.S$ÌŽ / .€H€ã‚ÅùN€€€‰‚ÿSection 40.1: Tracks controlsU&. À / .€L€ã®ÅùN€€€‰‚ÿSection 40.2: Tracks parameters À yŒ P À 1¹‚vÀ ØÀ Ä Section 40.1: Tracks controlsCBB("btn_up","JI(`',`games.tracks')");EB("btn_up")K" À ØÀ ) "€D€€€€‚ÿSection 40.1: Tracks controlsÞ¸À ¶Á & €q€˜€€‚ÿLeft-clicking on an edge between two squares adds a track segment between the two squares. Right-clicking on an edge adds a cross on the edge, indicating no track is possible there.ïØÀ Ë & €ß€˜€€‚ÿLeft-clicking in a square adds a colour indicator showing that you know the square must contain a track, even if you don't know which edges it crosses yet. Right-clicking in a square adds a cross indicating it contains no track segment.Ó­¶Á žÃ & €[€˜€€‚ÿLeft- or right-dragging between squares allows you to lay a straight line of is-track or is-not-track indicators, useful for filling in rows or columns to match the clue.nCËÂ Ä + &€†€˜€€ãüÅùN‰‚ÿ(All the actions described in section 2.1 are also available.)ƒRžÃ Ä 10€²…wÄ ÜÄ ¿È Section 40.2: Tracks parametersCBB("btn_up","JI(`',`games.tracks')");EB("btn_up")M$ Ä ÜÄ ) "€H€€€€‚ÿSection 40.2: Tracks parametersvQÄ RÅ % €¢€˜€€‚ÿThese parameters are available from the ‘Custom...’ option on the ‘Type’ menu.=ÜÄ Å + &€$€˜€€€€‚ÿWidth, HeightF RÅ ÕÅ & €@€˜‘€€‚ÿSize of the grid, in squares.2 Å Æ % €€˜€€‚ÿDifficultyà¹ÕÅ çÆ ' €s€˜‘€€‚ÿControls the difficulty of the generated puzzle: at Tricky level, you are required to make more deductions regarding disregarding moves that would lead to impossible crossings later.DÆ +Ç % €>€˜€€‚ÿDisallow consecutive 1 clues”mçÆ ¿È ' €Û€˜‘€€‚ÿControls whether the Tracks game generation permits two adjacent rows or columns to have a 1 clue, or permits the row or column of the track's endpoint to have a 1 clue. By default this is not permitted, to avoid long straight boring segments of track and make the games more twiddly and interesting. If you want to restore the possibility, turn this option off.o>+Ç .É 1{¹‚ˆx.É pÉ ©Ì Chapter 41: PalisadeCBB("btn_up","JI(`',`Top')");EB("btn_up")B¿È pÉ ) "€2€€€€‚ÿChapter 41: PalisadeT..É ÄÊ & €]€˜€€‚ÿYou're given a grid of squares, some of which contain numbers. Your goal is to subdivide the grid into contiguous regions, all of the same (given) size, such that each square containing a number is adjacent to exactly that many edges (including those between the inside and the outside of the grid).vKpÉ :Ë + &€–€˜€€ãØJÝØ‰‚ÿCredit for this puzzle goes to Nikoli, who call it ‘Five Cells’. [22].d?ÄÊ žË % €~€˜€€‚ÿPalisade was contributed to this collection by Jonas Kölker._7:Ë ýË ( €n€˜€€€‚ÿ[22] http://nikoli.co.jp/en/puzzles/five_cells.htmlU&žË RÌ / .€L€ã¥ÅùN€€€‰‚ÿSection 41.1: Palisade controlsW(ýË ©Ì / .€P€ã¦ÅùN€€€‰‚ÿSection 41.2: Palisade parameters…TRÌ .Í 1ó²…‰y.Í {Í !Ï Section 41.1: Palisade controlsCBB("btn_up","JI(`',`games.palisade')");EB("btn_up")M$©Ì {Í ) "€H€€€€‚ÿSection 41.1: Palisade controls8.Í ³Î & €%€˜€€‚ÿLeft-click to place an edge. Right-click to indicate ‘no edge’. Alternatively, the arrow keys will move a keyboard cursor. Holding Control while pressing an arrow key will place an edge. Press Shift-arrowkey to switch off an edge. Repeat an action to perform its inverse.nC{Í !Ï + &€†€˜€€ãüÅùN‰‚ÿ(All the actions described in section 2.1 are also available.)‡V³Î ¨Ï 1ÞˆÎz¨Ï › Section 41.2: Palisade parametersCBB("btn_up","JI(`',`games.palisade')");EB("btn_up")O&!Ï ) "€L€€€€‚ÿSection 41.2: Palisade parameters¨Ï !Ï vQ¨Ï ‚ % €¢€˜€€‚ÿThese parameters are available from the ‘Custom...’ option on the ‘Type’ menu.= ¿ + &€$€˜€€€€‚ÿWidth, HeightA‚  & €6€˜‘€€‚ÿSize of grid in squares.3¿ 3 % €€˜€€‚ÿRegion sizehB › & €„€˜‘€€‚ÿThe size of the regions into which the grid must be subdivided.n=3  1û‰ÿÿÿÿ{  J  Appendix A: LicenceCBB("btn_up","JI(`',`Top')");EB("btn_up")A› J ) "€0€€€€‚ÿAppendix A: LicenceZ5  ¤ % €j€˜€€‚ÿThis software is copyright 2004-2014 Simon Tatham.ëÅJ  & €‹€˜€€‚ÿPortions copyright Richard Boulton, James Harvey, Mike Pinna, Jonas Kölker, Dariusz Olszewski, Michael Schierl, Lambros Lambrou, Bernd Schmidt, Steffen Bauer, Lennard Sprong and Rogier Goossens.Ù³¤ h & €g€˜€€‚ÿ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.õÏh  & €Ÿ€˜€€‚ÿ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 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.1 ÿÿÿÿ1ÿÿÿÿÿÿÿÿ|ÿÿÿÿÿÿÿÿÿÿÿÿ/&;)Lzÿÿ|@ÿÿContentsDChapter 1: IntroductionûƒChapter 2: Common featuresG…Section 2.1: Common actionsPSection 2.2: Specifying games with the game IDމSection 2.3: The ‘Type’ menu‹Section 2.4: Specifying game parameters on the command linePSection 2.5: Unix command-line options‰‡Chapter 3: Net™ŠSection 3.1: Net controlsÏSection 3.2: Net parametersÓ Chapter 4: CubeR„Section 4.1: Cube controlsɆSection 4.2: Cube parametersiˆChapter 5: FifteenuŠSection 5.1: Fifteen controlsMSection 5.2: Fifteen parameters<Chapter 6: Sixteen–Section 6.1: Sixteen controls˜ Section 6.2: Sixteen parametersƒ‚Chapter 7: Twiddle¶…Section 7.1: Twiddle controls ‰Section 7.2: Twiddle parametersChapter 8: Rectangles-Section 8.1: Rectangles controlsÖ Section 8.2: Rectangles parameters†Chapter 9: NetslideˆChapter 10: PatternSection 10.1: Pattern controlsSection 10.2: Pattern parameters¿Chapter 11: Solo,‚Section 11.1: Solo controlsˆSection 11.2: Solo parameters.Chapter 12: Minesö Section 12.1: Mines controls1…Section 12.2: Mines parametersFˆChapter 13: Same GameSection 13.1: Same Game controls}Section 13.2: Same Game parametersUChapter 14: Flip Section 14.1: Flip controlsˆSection 14.2: Flip parameters¥ƒChapter 15: Guess’†Section 15.1: Guess controlsç Section 15.2: Guess parametersl Chapter 16: Pegs! Section 16.1: Pegs controlsH Section 16.2: Pegs parameters« Chapter 17: DominosaÔƒ Section 17.1: Dominosa controlsæ‡ Section 17.2: Dominosa parameters Chapter 18: Untangle¨ Section 18.1: Untangle controlsj Section 18.2: Untangle parametersY Chapter 19: Black BoxŠ„ Section 19.1: Black Box controlsC Section 19.2: Black Box parametersÊ Chapter 20: Slant¬ Section 20.1: Slant controlsC€ Section 20.2: Slant parametersñ‚ Chapter 21: Light Up¿† Section 21.1: Light Up controls“‰ Section 21.2: Light Up parameterså Chapter 22: Mapª<ÿÿ“ Section 22.1: Map controls¡ Section 22.2: Map parameters©„ Chapter 23: Loopyªˆ Section 23.1: Loopy controlsC Section 23.2: Loopy parameters Chapter 24: Inertiaí Section 24.1: Inertia controls Section 24.2: Inertia parameters§ Chapter 25: Tents… Section 25.1: Tents controlsûˆ Section 25.2: Tents parametersÆChapter 26: BridgesSection 26.1: Bridges controlsЄSection 26.2: Bridges parametersæ‰Chapter 27: Unequal[Section 27.1: Unequal controls€Section 27.2: Unequal parametersU‚Chapter 28: Galaxiesæ„Section 28.1: Galaxies controlsSection 28.2: Galaxies parameters^Chapter 29: Filling¯Section 29.1: Filling controlsESection 29.2: Filling parametersÑChapter 30: Keen‹…Section 30.1: Keen controlsSection 30.2: Keen parameters¥Chapter 31: TowersESection 31.1: Towers controlsǃSection 31.2: Towers parametersâ…Chapter 32: SinglesÕˆSection 32.1: Singles controlsCSection 32.2: Singles parameters&Chapter 33: MagnetsÆSection 33.1: Magnets controlsÜSection 33.2: Magnets parametersiChapter 34: Signpost …Section 34.1: Signpost controlsCSection 34.2: Signpost parametersâChapter 35: RangeÛSection 35.1: Range controls  Section 35.2: Range parameters~€Chapter 36: Pearl¬…Section 36.1: Pearl controlsŠSection 36.2: Pearl parametersChapter 37: UndeadªSection 37.1: Undead controlsC€Section 37.2: Undead parameters%Chapter 38: Unruly§ƒSection 38.1: Unruly controlsI†Section 38.2: Unruly parameters%ˆChapter 39: FloodÛSection 39.1: Flood controlsSection 39.2: Flood parametersChapter 40: Tracks€Section 40.1: Tracks controls¹‚Section 40.2: Tracks parameters²…Chapter 41: PalisadeˆSection 41.1: Palisade controls‰Section 41.2: Palisade parametersÎAppendix A: Licenceô“ /&;)z4ÿÿ ‹ ÿÿÿÿ|CONTEXT|CTXOMAP?|FONTJ|KWBTREE4 |KWDATAc)|KWMAPü,|SYSTEM-|TOPICŽ.|TTLBTREEÌöpuzzles-20170606.272beef/puzzles.txt0000644000175000017500000041342613115375151016155 0ustar simonsimon Simon Tatham's Portable Puzzle Collection ========================================= This is a collection of small one-player puzzle games. This manual is copyright 2004-2014 Simon Tatham. All rights reserved. You may distribute this documentation under the MIT licence. See appendix A for the licence text in full. Chapter 1: Introduction ----------------------- I wrote this collection because I thought there should be more small desktop toys available: little games you can pop up in a window and play for two or three minutes while you take a break from whatever else you were doing. And I was also annoyed that every time I found a good game on (say) Unix, it wasn't available the next time I was sitting at a Windows machine, or vice versa; so I arranged that everything in my personal puzzle collection will happily run on both, and have more recently done a port to Mac OS X as well. When I find (or perhaps invent) further puzzle games that I like, they'll be added to this collection and will immediately be available on both platforms. And if anyone feels like writing any other front ends - PocketPC, Mac OS pre-10, or whatever it might be - then all the games in this framework will immediately become available on another platform as well. The actual games in this collection were mostly not my invention; they are re-implementations of existing game concepts within my portable puzzle framework. I do not claim credit, in general, for inventing the rules of any of these puzzles. (I don't even claim authorship of all the code; some of the puzzles have been submitted by other authors.) This collection is distributed under the MIT licence (see appendix A). This means that you can do pretty much anything you like with the game binaries or the code, except pretending you wrote them yourself, or suing me if anything goes wrong. The most recent versions, and source code, can be found at https://www.chiark.greenend.org.uk/~sgtatham/puzzles/. Please report bugs to anakin@pobox.com. You might find it helpful to read this article before reporting a bug: https://www.chiark.greenend.org.uk/~sgtatham/bugs.html Patches are welcome. Especially if they provide a new front end (to make all these games run on another platform), or a new game. Chapter 2: Common features -------------------------- This chapter describes features that are common to all the games. 2.1 Common actions These actions are all available from the `Game' menu and via keyboard shortcuts, in addition to any game-specific actions. (On Mac OS X, to conform with local user interface standards, these actions are situated on the `File' and `Edit' menus instead.) _New game_ (`N', Ctrl+`N') Starts a new game, with a random initial state. _Restart game_ Resets the current game to its initial state. (This can be undone.) _Load_ Loads a saved game from a file on disk. _Save_ Saves the current state of your game to a file on disk. The Load and Save operations preserve your entire game history (so you can save, reload, and still Undo and Redo things you had done before saving). _Print_ Where supported (currently only on Windows), brings up a dialog allowing you to print an arbitrary number of puzzles randomly generated from the current parameters, optionally including the current puzzle. (Only for puzzles which make sense to print, of course - it's hard to think of a sensible printable representation of Fifteen!) _Undo_ (`U', Ctrl+`Z', Ctrl+`_') Undoes a single move. (You can undo moves back to the start of the session.) _Redo_ (`R', Ctrl+`R') Redoes a previously undone move. _Copy_ Copies the current state of your game to the clipboard in text format, so that you can paste it into (say) an e-mail client or a web message board if you're discussing the game with someone else. (Not all games support this feature.) _Solve_ Transforms the puzzle instantly into its solved state. For some games (Cube) this feature is not supported at all because it is of no particular use. For other games (such as Pattern), the solved state can be used to give you information, if you can't see how a solution can exist at all or you want to know where you made a mistake. For still other games (such as Sixteen), automatic solution tells you nothing about how to _get_ to the solution, but it does provide a useful way to get there quickly so that you can experiment with set-piece moves and transformations. Some games (such as Solo) are capable of solving a game ID you have typed in from elsewhere. Other games (such as Rectangles) cannot solve a game ID they didn't invent themself, but when they did invent the game ID they know what the solution is already. Still other games (Pattern) can solve _some_ external game IDs, but only if they aren't too difficult. The `Solve' command adds the solved state to the end of the undo chain for the puzzle. In other words, if you want to go back to solving it yourself after seeing the answer, you can just press Undo. _Quit_ (`Q', Ctrl+`Q') Closes the application entirely. 2.2 Specifying games with the game ID There are two ways to save a game specification out of a puzzle and recreate it later, or recreate it in somebody else's copy of the same puzzle. The `Specific' and `Random Seed' options from the `Game' menu (or the `File' menu, on Mac OS X) each show a piece of text (a `game ID') which is sufficient to reconstruct precisely the same game at a later date. You can enter either of these pieces of text back into the program (via the same `Specific' or `Random Seed' menu options) at a later point, and it will recreate the same game. You can also use either one as a command line argument (on Windows or Unix); see section 2.4 for more detail. The difference between the two forms is that a descriptive game ID is a literal _description_ of the initial state of the game, whereas a random seed is just a piece of arbitrary text which was provided as input to the random number generator used to create the puzzle. This means that: - Descriptive game IDs tend to be longer in many puzzles (although some, such as Cube (chapter 4), only need very short descriptions). So a random seed is often a _quicker_ way to note down the puzzle you're currently playing, or to tell it to somebody else so they can play the same one as you. - Any text at all is a valid random seed. The automatically generated ones are fifteen-digit numbers, but anything will do; you can type in your full name, or a word you just made up, and a valid puzzle will be generated from it. This provides a way for two or more people to race to complete the same puzzle: you think of a random seed, then everybody types it in at the same time, and nobody has an advantage due to having seen the generated puzzle before anybody else. - It is often possible to convert puzzles from other sources (such as `nonograms' or `sudoku' from newspapers) into descriptive game IDs suitable for use with these programs. - Random seeds are not guaranteed to produce the same result if you use them with a different _version_ of the puzzle program. This is because the generation algorithm might have been improved or modified in later versions of the code, and will therefore produce a different result when given the same sequence of random numbers. Use a descriptive game ID if you aren't sure that it will be used on the same version of the program as yours. (Use the `About' menu option to find out the version number of the program. Programs with the same version number running on different platforms should still be random-seed compatible.) A descriptive game ID starts with a piece of text which encodes the _parameters_ of the current game (such as grid size). Then there is a colon, and after that is the description of the game's initial state. A random seed starts with a similar string of parameters, but then it contains a hash sign followed by arbitrary data. If you enter a descriptive game ID, the program will not be able to show you the random seed which generated it, since it wasn't generated _from_ a random seed. If you _enter_ a random seed, however, the program will be able to show you the descriptive game ID derived from that random seed. Note that the game parameter strings are not always identical between the two forms. For some games, there will be parameter data provided with the random seed which is not included in the descriptive game ID. This is because that parameter information is only relevant when _generating_ puzzle grids, and is not important when playing them. Thus, for example, the difficulty level in Solo (chapter 11) is not mentioned in the descriptive game ID. These additional parameters are also not set permanently if you type in a game ID. For example, suppose you have Solo set to `Advanced' difficulty level, and then a friend wants your help with a `Trivial' puzzle; so the friend reads out a random seed specifying `Trivial' difficulty, and you type it in. The program will generate you the same `Trivial' grid which your friend was having trouble with, but once you have finished playing it, when you ask for a new game it will automatically go back to the `Advanced' difficulty which it was previously set on. 2.3 The `Type' menu The `Type' menu, if present, may contain a list of preset game settings. Selecting one of these will start a new random game with the parameters specified. The `Type' menu may also contain a `Custom' option which allows you to fine-tune game parameters. The parameters available are specific to each game and are described in the following sections. 2.4 Specifying game parameters on the command line (This section does not apply to the Mac OS X version.) The games in this collection deliberately do not ever save information on to the computer they run on: they have no high score tables and no saved preferences. (This is because I expect at least some people to play them at work, and those people will probably appreciate leaving as little evidence as possible!) However, if you do want to arrange for one of these games to default to a particular set of parameters, you can specify them on the command line. The easiest way to do this is to set up the parameters you want using the `Type' menu (see section 2.3), and then to select `Random Seed' from the `Game' or `File' menu (see section 2.2). The text in the `Game ID' box will be composed of two parts, separated by a hash. The first of these parts represents the game parameters (the size of the playing area, for example, and anything else you set using the `Type' menu). If you run the game with just that parameter text on the command line, it will start up with the settings you specified. For example: if you run Cube (see chapter 4), select `Octahedron' from the `Type' menu, and then go to the game ID selection, you will see a string of the form `o2x2#338686542711620'. Take only the part before the hash (`o2x2'), and start Cube with that text on the command line: `PREFIX-cube o2x2'. If you copy the _entire_ game ID on to the command line, the game will start up in the specific game that was described. This is occasionally a more convenient way to start a particular game ID than by pasting it into the game ID selection box. (You could also retrieve the encoded game parameters using the `Specific' menu option instead of `Random Seed', but if you do then some options, such as the difficulty level in Solo, will be missing. See section 2.2 for more details on this.) 2.5 Unix command-line options (This section only applies to the Unix port.) In addition to being able to specify game parameters on the command line (see section 2.4), there are various other options: --game --load These options respectively determine whether the command-line argument is treated as specifying game parameters or a save file to load. Only one should be specified. If neither of these options is specified, a guess is made based on the format of the argument. --generate _n_ If this option is specified, instead of a puzzle being displayed, a number of descriptive game IDs will be invented and printed on standard output. This is useful for gaining access to the game generation algorithms without necessarily using the frontend. If game parameters are specified on the command-line, they will be used to generate the game IDs; otherwise a default set of parameters will be used. The most common use of this option is in conjunction with `-- print', in which case its behaviour is slightly different; see below. --print _w_x_h_ If this option is specified, instead of a puzzle being displayed, a printed representation of one or more unsolved puzzles is sent to standard output, in PostScript format. On each page of puzzles, there will be _w_ across and _h_ down. If there are more puzzles than _w_x_h_, more than one page will be printed. If `--generate' has also been specified, the invented game IDs will be used to generate the printed output. Otherwise, a list of game IDs is expected on standard input (which can be descriptive or random seeds; see section 2.2), in the same format produced by `--generate'. For example: PREFIX-net --generate 12 --print 2x3 7x7w | lpr will generate two pages of printed Net puzzles (each of which will have a 7x7 wrapping grid), and pipe the output to the `lpr' command, which on many systems will send them to an actual printer. There are various other options which affect printing; see below. --save _file-prefix_ [ --save-suffix _file-suffix_ ] If this option is specified, instead of a puzzle being displayed, saved-game files for one or more unsolved puzzles are written to files constructed from the supplied prefix and/or suffix. If `--generate' has also been specified, the invented game IDs will be used to generate the printed output. Otherwise, a list of game IDs is expected on standard input (which can be descriptive or random seeds; see section 2.2), in the same format produced by `--generate'. For example: PREFIX-net --generate 12 --save game --save-suffix .sav will generate twelve Net saved-game files with the names game0.sav to game11.sav. --version Prints version information about the game, and then quits. The following options are only meaningful if `--print' is also specified: --with-solutions The set of pages filled with unsolved puzzles will be followed by the solutions to those puzzles. --scale _n_ Adjusts how big each puzzle is when printed. Larger numbers make puzzles bigger; the default is 1.0. --colour Puzzles will be printed in colour, rather than in black and white (if supported by the puzzle). Chapter 3: Net -------------- (_Note:_ the Windows version of this game is called NETGAME.EXE to avoid clashing with Windows's own NET.EXE.) I originally saw this in the form of a Flash game called FreeNet [1], written by Pavils Jurjans; there are several other implementations under the name NetWalk. The computer prepares a network by connecting up the centres of squares in a grid, and then shuffles the network by rotating every tile randomly. Your job is to rotate it all back into place. The successful solution will be an entirely connected network, with no closed loops. As a visual aid, all tiles which are connected to the one in the middle are highlighted. [1] http://www.jurjans.lv/stuff/net/FreeNet.htm 3.1 Net controls This game can be played with either the keyboard or the mouse. The controls are: _Select tile_: mouse pointer, arrow keys _Rotate tile anticlockwise_: left mouse button, `A' key _Rotate tile clockwise_: right mouse button, `D' key _Rotate tile by 180 degrees_: `F' key _Lock (or unlock) tile_: middle mouse button, shift-click, `S' key You can lock a tile once you're sure of its orientation. You can also unlock it again, but while it's locked you can't accidentally turn it. The following controls are not necessary to complete the game, but may be useful: _Shift grid_: Shift + arrow keys On grids that wrap, you can move the origin of the grid, so that tiles that were on opposite sides of the grid can be seen together. _Move centre_: Ctrl + arrow keys You can change which tile is used as the source of highlighting. (It doesn't ultimately matter which tile this is, as every tile will be connected to every other tile in a correct solution, but it may be helpful in the intermediate stages of solving the puzzle.) _Jumble tiles_: `J' key This key turns all tiles that are not locked to random orientations. (All the actions described in section 2.1 are also available.) 3.2 Net parameters These parameters are available from the `Custom...' option on the `Type' menu. _Width_, _Height_ Size of grid in tiles. _Walls wrap around_ If checked, flow can pass from the left edge to the right edge, and from top to bottom, and vice versa. _Barrier probability_ A number between 0.0 and 1.0 controlling whether an immovable barrier is placed between two tiles to prevent flow between them (a higher number gives more barriers). Since barriers are immovable, they act as constraints on the solution (i.e., hints). The grid generation in Net has been carefully arranged so that the barriers are independent of the rest of the grid. This means that if you note down the random seed used to generate the current puzzle (see section 2.2), change the _Barrier probability_ parameter, and then re-enter the same random seed, you should see exactly the same starting grid, with the only change being the number of barriers. So if you're stuck on a particular grid and need a hint, you could start up another instance of Net, set up the same parameters but a higher barrier probability, and enter the game seed from the original Net window. _Ensure unique solution_ Normally, Net will make sure that the puzzles it presents have only one solution. Puzzles with ambiguous sections can be more difficult and more subtle, so if you like you can turn off this feature and risk having ambiguous puzzles. (Also, finding _all_ the possible solutions can be an additional challenge for an advanced player.) Chapter 4: Cube --------------- This is another one I originally saw as a web game. This one was a Java game [2], by Paul Scott. You have a grid of 16 squares, six of which are blue; on one square rests a cube. Your move is to use the arrow keys to roll the cube through 90 degrees so that it moves to an adjacent square. If you roll the cube on to a blue square, the blue square is picked up on one face of the cube; if you roll a blue face of the cube on to a non-blue square, the blueness is put down again. (In general, whenever you roll the cube, the two faces that come into contact swap colours.) Your job is to get all six blue squares on to the six faces of the cube at the same time. Count your moves and try to do it in as few as possible. Unlike the original Java game, my version has an additional feature: once you've mastered the game with a cube rolling on a square grid, you can change to a triangular grid and roll any of a tetrahedron, an octahedron or an icosahedron. [2] http://www3.sympatico.ca/paulscott/cube/cube.htm 4.1 Cube controls This game can be played with either the keyboard or the mouse. Left-clicking anywhere on the window will move the cube (or other solid) towards the mouse pointer. The arrow keys can also used to roll the cube on its square grid in the four cardinal directions. On the triangular grids, the mapping of arrow keys to directions is more approximate. Vertical movement is disallowed where it doesn't make sense. The four keys surrounding the arrow keys on the numeric keypad (`7', `9', `1', `3') can be used for diagonal movement. (All the actions described in section 2.1 are also available.) 4.2 Cube parameters These parameters are available from the `Custom...' option on the `Type' menu. _Type of solid_ Selects the solid to roll (and hence the shape of the grid): tetrahedron, cube, octahedron, or icosahedron. _Width / top_, _Height / bottom_ On a square grid, horizontal and vertical dimensions. On a triangular grid, the number of triangles on the top and bottom rows respectively. Chapter 5: Fifteen ------------------ The old ones are the best: this is the good old `15-puzzle' with sliding tiles. You have a 4x4 square grid; 15 squares contain numbered tiles, and the sixteenth is empty. Your move is to choose a tile next to the empty space, and slide it into the space. The aim is to end up with the tiles in numerical order, with the space in the bottom right (so that the top row reads 1,2,3,4 and the bottom row reads 13,14,15,_space_). 5.1 Fifteen controls This game can be controlled with the mouse or the keyboard. A left-click with the mouse in the row or column containing the empty space will move as many tiles as necessary to move the space to the mouse pointer. The arrow keys will move a tile adjacent to the space in the direction indicated (moving the space in the _opposite_ direction). Pressing `h' will make a suggested move. Pressing `h' enough times will solve the game, but it may scramble your progress while doing so. (All the actions described in section 2.1 are also available.) 5.2 Fifteen parameters The only options available from the `Custom...' option on the `Type' menu are _Width_ and _Height_, which are self-explanatory. (Once you've changed these, it's not a `15-puzzle' any more, of course!) Chapter 6: Sixteen ------------------ Another sliding tile puzzle, visually similar to Fifteen (see chapter 5) but with a different type of move. This time, there is no hole: all 16 squares on the grid contain numbered squares. Your move is to shift an entire row left or right, or shift an entire column up or down; every time you do that, the tile you shift off the grid re-appears at the other end of the same row, in the space you just vacated. To win, arrange the tiles into numerical order (1,2,3,4 on the top row, 13,14,15,16 on the bottom). When you've done that, try playing on different sizes of grid. I _might_ have invented this game myself, though only by accident if so (and I'm sure other people have independently invented it). I thought I was imitating a screensaver I'd seen, but I have a feeling that the screensaver might actually have been a Fifteen-type puzzle rather than this slightly different kind. So this might be the one thing in my puzzle collection which represents creativity on my part rather than just engineering. 6.1 Sixteen controls Left-clicking on an arrow will move the appropriate row or column in the direction indicated. Right-clicking will move it in the opposite direction. Alternatively, use the cursor keys to move the position indicator around the edge of the grid, and use the return key to move the row/column in the direction indicated. You can also move the tiles directly. Move the cursor onto a tile, hold Control and press an arrow key to move the tile under the cursor and move the cursor along with the tile. Or, hold Shift to move only the tile. Pressing Enter simulates holding down Control (press Enter again to release), while pressing Space simulates holding down shift. (All the actions described in section 2.1 are also available.) 6.2 Sixteen parameters The parameters available from the `Custom...' option on the `Type' menu are: - _Width_ and _Height_, which are self-explanatory. - You can ask for a limited shuffling operation to be performed on the grid. By default, Sixteen will shuffle the grid in such a way that any arrangement is about as probable as any other. You can override this by requesting a precise number of shuffling moves to be performed. Typically your aim is then to determine the precise set of shuffling moves and invert them exactly, so that you answer (say) a four-move shuffle with a four-move solution. Note that the more moves you ask for, the more likely it is that solutions shorter than the target length will turn out to be possible. Chapter 7: Twiddle ------------------ Twiddle is a tile-rearrangement puzzle, visually similar to Sixteen (see chapter 6): you are given a grid of square tiles, each containing a number, and your aim is to arrange the numbers into ascending order. In basic Twiddle, your move is to rotate a square group of four tiles about their common centre. (Orientation is not significant in the basic puzzle, although you can select it.) On more advanced settings, you can rotate a larger square group of tiles. I first saw this type of puzzle in the GameCube game `Metroid Prime 2'. In the Main Gyro Chamber in that game, there is a puzzle you solve to unlock a door, which is a special case of Twiddle. I developed this game as a generalisation of that puzzle. 7.1 Twiddle controls To play Twiddle, click the mouse in the centre of the square group you wish to rotate. In the basic mode, you rotate a 2x2 square, which means you have to click at a corner point where four tiles meet. In more advanced modes you might be rotating 3x3 or even more at a time; if the size of the square is odd then you simply click in the centre tile of the square you want to rotate. Clicking with the left mouse button rotates the group anticlockwise. Clicking with the right button rotates it clockwise. You can also move an outline square around the grid with the cursor keys; the square is the size above (2x2 by default, or larger). Pressing the return key or space bar will rotate the current square anticlockwise or clockwise respectively. (All the actions described in section 2.1 are also available.) 7.2 Twiddle parameters Twiddle provides several configuration options via the `Custom' option on the `Type' menu: - You can configure the width and height of the puzzle grid. - You can configure the size of square block that rotates at a time. - You can ask for every square in the grid to be distinguishable (the default), or you can ask for a simplified puzzle in which there are groups of identical numbers. In the simplified puzzle your aim is just to arrange all the 1s into the first row, all the 2s into the second row, and so on. - You can configure whether the orientation of tiles matters. If you ask for an orientable puzzle, each tile will have a triangle drawn in it. All the triangles must be pointing upwards to complete the puzzle. - You can ask for a limited shuffling operation to be performed on the grid. By default, Twiddle will shuffle the grid so much that any arrangement is about as probable as any other. You can override this by requesting a precise number of shuffling moves to be performed. Typically your aim is then to determine the precise set of shuffling moves and invert them exactly, so that you answer (say) a four-move shuffle with a four-move solution. Note that the more moves you ask for, the more likely it is that solutions shorter than the target length will turn out to be possible. Chapter 8: Rectangles --------------------- You have a grid of squares, with numbers written in some (but not all) of the squares. Your task is to subdivide the grid into rectangles of various sizes, such that (a) every rectangle contains exactly one numbered square, and (b) the area of each rectangle is equal to the number written in its numbered square. Credit for this game goes to the Japanese puzzle magazine Nikoli [3]; I've also seen a Palm implementation at Puzzle Palace [4]. Unlike Puzzle Palace's implementation, my version automatically generates random grids of any size you like. The quality of puzzle design is therefore not quite as good as hand-crafted puzzles would be, but on the plus side you get an inexhaustible supply of puzzles tailored to your own specification. [3] http://www.nikoli.co.jp/en/puzzles/shikaku.html (beware of Flash) [4] https://web.archive.org/web/20041024001459/http://www.puzzle.gr.jp/puzzle/sikaku/palm/index.html.en 8.1 Rectangles controls This game is played with the mouse or cursor keys. Left-click any edge to toggle it on or off, or left-click and drag to draw an entire rectangle (or line) on the grid in one go (removing any existing edges within that rectangle). Right-clicking and dragging will allow you to erase the contents of a rectangle without affecting its edges. Alternatively, use the cursor keys to move the position indicator around the board. Pressing the return key then allows you to use the cursor keys to drag a rectangle out from that position, and pressing the return key again completes the rectangle. Using the space bar instead of the return key allows you to erase the contents of a rectangle without affecting its edges, as above. Pressing escape cancels a drag. When a rectangle of the correct size is completed, it will be shaded. (All the actions described in section 2.1 are also available.) 8.2 Rectangles parameters These parameters are available from the `Custom...' option on the `Type' menu. _Width_, _Height_ Size of grid, in squares. _Expansion factor_ This is a mechanism for changing the type of grids generated by the program. Some people prefer a grid containing a few large rectangles to one containing many small ones. So you can ask Rectangles to essentially generate a _smaller_ grid than the size you specified, and then to expand it by adding rows and columns. The default expansion factor of zero means that Rectangles will simply generate a grid of the size you ask for, and do nothing further. If you set an expansion factor of (say) 0.5, it means that each dimension of the grid will be expanded to half again as big after generation. In other words, the initial grid will be 2/3 the size in each dimension, and will be expanded to its full size without adding any more rectangles. Setting an expansion factor of around 0.5 tends to make the game more difficult, and also (in my experience) rewards a less deductive and more intuitive playing style. If you set it _too_ high, though, the game simply cannot generate more than a few rectangles to cover the entire grid, and the game becomes trivial. _Ensure unique solution_ Normally, Rectangles will make sure that the puzzles it presents have only one solution. Puzzles with ambiguous sections can be more difficult and more subtle, so if you like you can turn off this feature and risk having ambiguous puzzles. Also, finding _all_ the possible solutions can be an additional challenge for an advanced player. Turning off this option can also speed up puzzle generation. Chapter 9: Netslide ------------------- This game combines the grid generation of Net (see chapter 3) with the movement of Sixteen (see chapter 6): you have a Net grid, but instead of rotating tiles back into place you have to slide them into place by moving a whole row at a time. As in Sixteen, control is with the mouse or cursor keys. See section 6.1. The available game parameters have similar meanings to those in Net (see section 3.2) and Sixteen (see section 6.2). Netslide was contributed to this collection by Richard Boulton. Chapter 10: Pattern ------------------- You have a grid of squares, which must all be filled in either black or white. Beside each row of the grid are listed the lengths of the runs of black squares on that row; above each column are listed the lengths of the runs of black squares in that column. Your aim is to fill in the entire grid black or white. I first saw this puzzle form around 1995, under the name `nonograms'. I've seen it in various places since then, under different names. Normally, puzzles of this type turn out to be a meaningful picture of something once you've solved them. However, since this version generates the puzzles automatically, they will just look like random groupings of squares. (One user has suggested that this is actually a _good_ thing, since it prevents you from guessing the colour of squares based on the picture, and forces you to use logic instead.) The advantage, though, is that you never run out of them. 10.1 Pattern controls This game is played with the mouse. Left-click in a square to colour it black. Right-click to colour it white. If you make a mistake, you can middle-click, or hold down Shift while clicking with any button, to colour the square in the default grey (meaning `undecided') again. You can click and drag with the left or right mouse button to colour a vertical or horizontal line of squares black or white at a time (respectively). If you click and drag with the middle button, or with Shift held down, you can colour a whole rectangle of squares grey. You can also move around the grid with the cursor keys. Pressing the return key will cycle the current cell through empty, then black, then white, then empty, and the space bar does the same cycle in reverse. Moving the cursor while holding Control will colour the moved-over squares black. Holding Shift will colour the moved-over squares white, and holding both will colour them grey. (All the actions described in section 2.1 are also available.) 10.2 Pattern parameters The only options available from the `Custom...' option on the `Type' menu are _Width_ and _Height_, which are self-explanatory. Chapter 11: Solo ---------------- You have a square grid, which is divided into as many equally sized sub-blocks as the grid has rows. Each square must be filled in with a digit from 1 to the size of the grid, in such a way that - every row contains only one occurrence of each digit - every column contains only one occurrence of each digit - every block contains only one occurrence of each digit. - (optionally, by default off) each of the square's two main diagonals contains only one occurrence of each digit. You are given some of the numbers as clues; your aim is to place the rest of the numbers correctly. Under the default settings, the sub-blocks are square or rectangular. The default puzzle size is 3x3 (a 9x9 actual grid, divided into nine 3x3 blocks). You can also select sizes with rectangular blocks instead of square ones, such as 2x3 (a 6x6 grid divided into six 3x2 blocks). Alternatively, you can select `jigsaw' mode, in which the sub-blocks are arbitrary shapes which differ between individual puzzles. Another available mode is `killer'. In this mode, clues are not given in the form of filled-in squares; instead, the grid is divided into `cages' by coloured lines, and for each cage the game tells you what the sum of all the digits in that cage should be. Also, no digit may appear more than once within a cage, even if the cage crosses the boundaries of existing regions. If you select a puzzle size which requires more than 9 digits, the additional digits will be letters of the alphabet. For example, if you select 3x4 then the digits which go in your grid will be 1 to 9, plus `a', `b' and `c'. This cannot be selected for killer puzzles. I first saw this puzzle in Nikoli [5], although it's also been popularised by various newspapers under the name `Sudoku' or `Su Doku'. Howard Garns is considered the inventor of the modern form of the puzzle, and it was first published in _Dell Pencil Puzzles and Word Games_. A more elaborate treatment of the history of the puzzle can be found on Wikipedia [6]. [5] http://www.nikoli.co.jp/en/puzzles/sudoku.html (beware of Flash) [6] http://en.wikipedia.org/wiki/Sudoku 11.1 Solo controls To play Solo, simply click the mouse in any empty square and then type a digit or letter on the keyboard to fill that square. If you make a mistake, click the mouse in the incorrect square and press Space to clear it again (or use the Undo feature). If you _right_-click in a square and then type a number, that number will be entered in the square as a `pencil mark'. You can have pencil marks for multiple numbers in the same square. Squares containing filled-in numbers cannot also contain pencil marks. The game pays no attention to pencil marks, so exactly what you use them for is up to you: you can use them as reminders that a particular square needs to be re-examined once you know more about a particular number, or you can use them as lists of the possible numbers in a given square, or anything else you feel like. To erase a single pencil mark, right-click in the square and type the same number again. All pencil marks in a square are erased when you left-click and type a number, or when you left-click and press space. Right-clicking and pressing space will also erase pencil marks. Alternatively, use the cursor keys to move the mark around the grid. Pressing the return key toggles the mark (from a normal mark to a pencil mark), and typing a number in is entered in the square in the appropriate way; typing in a 0 or using the space bar will clear a filled square. (All the actions described in section 2.1 are also available.) 11.2 Solo parameters Solo allows you to configure two separate dimensions of the puzzle grid on the `Type' menu: the number of columns, and the number of rows, into which the main grid is divided. (The size of a block is the inverse of this: for example, if you select 2 columns and 3 rows, each actual block will have 3 columns and 2 rows.) If you tick the `X' checkbox, Solo will apply the optional extra constraint that the two main diagonals of the grid also contain one of every digit. (This is sometimes known as `Sudoku-X' in newspapers.) In this mode, the squares on the two main diagonals will be shaded slightly so that you know it's enabled. If you tick the `Jigsaw' checkbox, Solo will generate randomly shaped sub-blocks. In this mode, the actual grid size will be taken to be the product of the numbers entered in the `Columns' and `Rows' boxes. There is no reason why you have to enter a number greater than 1 in both boxes; Jigsaw mode has no constraint on the grid size, and it can even be a prime number if you feel like it. If you tick the `Killer' checkbox, Solo will generate a set of of cages, which are randomly shaped and drawn in an outline of a different colour. Each of these regions contains a smaller clue which shows the digit sum of all the squares in this region. You can also configure the type of symmetry shown in the generated puzzles. More symmetry makes the puzzles look prettier but may also make them easier, since the symmetry constraints can force more clues than necessary to be present. Completely asymmetric puzzles have the freedom to contain as few clues as possible. Finally, you can configure the difficulty of the generated puzzles. Difficulty levels are judged by the complexity of the techniques of deduction required to solve the puzzle: each level requires a mode of reasoning which was not necessary in the previous one. In particular, on difficulty levels `Trivial' and `Basic' there will be a square you can fill in with a single number at all times, whereas at `Intermediate' level and beyond you will have to make partial deductions about the _set_ of squares a number could be in (or the set of numbers that could be in a square). At `Unreasonable' level, even this is not enough, and you will eventually have to make a guess, and then backtrack if it turns out to be wrong. Generating difficult puzzles is itself difficult: if you select one of the higher difficulty levels, Solo may have to make many attempts at generating a puzzle before it finds one hard enough for you. Be prepared to wait, especially if you have also configured a large puzzle size. Chapter 12: Mines ----------------- You have a grid of covered squares, some of which contain mines, but you don't know which. Your job is to uncover every square which does _not_ contain a mine. If you uncover a square containing a mine, you lose. If you uncover a square which does not contain a mine, you are told how many mines are contained within the eight surrounding squares. This game needs no introduction; popularised by Windows, it is perhaps the single best known desktop puzzle game in existence. This version of it has an unusual property. By default, it will generate its mine positions in such a way as to ensure that you never need to _guess_ where a mine is: you will always be able to deduce it somehow. So you will never, as can happen in other versions, get to the last four squares and discover that there are two mines left but you have no way of knowing for sure where they are. 12.1 Mines controls This game is played with the mouse. If you left-click in a covered square, it will be uncovered. If you right-click in a covered square, it will place a flag which indicates that the square is believed to be a mine. Left-clicking in a marked square will not uncover it, for safety. You can right-click again to remove a mark placed in error. If you left-click in an _uncovered_ square, it will `clear around' the square. This means: if the square has exactly as many flags surrounding it as it should have mines, then all the covered squares next to it which are _not_ flagged will be uncovered. So once you think you know the location of all the mines around a square, you can use this function as a shortcut to avoid having to click on each of the remaining squares one by one. If you uncover a square which has _no_ mines in the surrounding eight squares, then it is obviously safe to uncover those squares in turn, and so on if any of them also has no surrounding mines. This will be done for you automatically; so sometimes when you uncover a square, a whole new area will open up to be explored. You can also use the cursor keys to move around the minefield. Pressing the return key in a covered square uncovers it, and in an uncovered square will clear around it (so it acts as the left button), pressing the space bar in a covered square will place a flag (similarly, it acts as the right button). All the actions described in section 2.1 are also available. Even Undo is available, although you might consider it cheating to use it. If you step on a mine, the program will only reveal the mine in question (unlike most other implementations, which reveal all of them). You can then Undo your fatal move and continue playing if you like. The program will track the number of times you died (and Undo will not reduce that counter), so when you get to the end of the game you know whether or not you did it without making any errors. (If you really want to know the full layout of the grid, which other implementations will show you after you die, you can always use the Solve menu option.) 12.2 Mines parameters The options available from the `Custom...' option on the `Type' menu are: _Width_, _Height_ Size of grid in squares. _Mines_ Number of mines in the grid. You can enter this as an absolute mine count, or alternatively you can put a % sign on the end in which case the game will arrange for that proportion of the squares in the grid to be mines. Beware of setting the mine count too high. At very high densities, the program may spend forever searching for a solvable grid. _Ensure solubility_ When this option is enabled (as it is by default), Mines will ensure that the entire grid can be fully deduced starting from the initial open space. If you prefer the riskier grids generated by other implementations, you can switch off this option. Chapter 13: Same Game --------------------- You have a grid of coloured squares, which you have to clear by highlighting contiguous regions of more than one coloured square; the larger the region you highlight, the more points you get (and the faster you clear the arena). If you clear the grid you win. If you end up with nothing but single squares (i.e., there are no more clickable regions left) you lose. Removing a region causes the rest of the grid to shuffle up: blocks that are suspended will fall down (first), and then empty columns are filled from the right. Same Game was contributed to this collection by James Harvey. 13.1 Same Game controls This game can be played with either the keyboard or the mouse. If you left-click an unselected region, it becomes selected (possibly clearing the current selection). If you left-click the selected region, it will be removed (and the rest of the grid shuffled immediately). If you right-click the selected region, it will be unselected. The cursor keys move a cursor around the grid. Pressing the Space or Enter keys while the cursor is in an unselected region selects it; pressing Space or Enter again removes it as above. (All the actions described in section 2.1 are also available.) 13.2 Same Game parameters These parameters are available from the `Custom...' option on the `Type' menu. _Width_, _Height_ Size of grid in squares. _No. of colours_ Number of different colours used to fill the grid; the more colours, the fewer large regions of colour and thus the more difficult it is to successfully clear the grid. _Scoring system_ Controls the precise mechanism used for scoring. With the default system, `(n-2)^2', only regions of three squares or more will score any points at all. With the alternative `(n-1)^2' system, regions of two squares score a point each, and larger regions score relatively more points. _Ensure solubility_ If this option is ticked (the default state), generated grids will be guaranteed to have at least one solution. If you turn it off, the game generator will not try to guarantee soluble grids; it will, however, still ensure that there are at least 2 squares of each colour on the grid at the start (since a grid with exactly one square of a given colour is _definitely_ insoluble). Grids generated with this option disabled may contain more large areas of contiguous colour, leading to opportunities for higher scores; they can also take less time to generate. Chapter 14: Flip ---------------- You have a grid of squares, some light and some dark. Your aim is to light all the squares up at the same time. You can choose any square and flip its state from light to dark or dark to light, but when you do so, other squares around it change state as well. Each square contains a small diagram showing which other squares change when you flip it. 14.1 Flip controls This game can be played with either the keyboard or the mouse. Left-click in a square to flip it and its associated squares, or use the cursor keys to choose a square and the space bar or Enter key to flip. If you use the `Solve' function on this game, it will mark some of the squares in red. If you click once in every square with a red mark, the game should be solved. (If you click in a square _without_ a red mark, a red mark will appear in it to indicate that you will need to reverse that operation to reach the solution.) (All the actions described in section 2.1 are also available.) 14.2 Flip parameters These parameters are available from the `Custom...' option on the `Type' menu. _Width_, _Height_ Size of grid in squares. _Shape type_ This control determines the shape of the region which is flipped by clicking in any given square. The default setting, `Crosses', causes every square to flip itself and its four immediate neighbours (or three or two if it's at an edge or corner). The other setting, `Random', causes a random shape to be chosen for every square, so the game is different every time. Chapter 15: Guess ----------------- You have a set of coloured pegs, and have to reproduce a predetermined sequence of them (chosen by the computer) within a certain number of guesses. Each guess gets marked with the number of correctly-coloured pegs in the correct places (in black), and also the number of correctly- coloured pegs in the wrong places (in white). This game is also known (and marketed, by Hasbro, mainly) as a board game `Mastermind', with 6 colours, 4 pegs per row, and 10 guesses. However, this version allows custom settings of number of colours (up to 10), number of pegs per row, and number of guesses. Guess was contributed to this collection by James Harvey. 15.1 Guess controls This game can be played with either the keyboard or the mouse. With the mouse, drag a coloured peg from the tray on the left-hand side to its required position in the current guess; pegs may also be dragged from current and past guesses to copy them elsewhere. To remove a peg, drag it off its current position to somewhere invalid. Right-clicking in the current guess adds a `hold' marker; pegs that have hold markers will be automatically added to the next guess after marking. Alternatively, with the keyboard, the up and down cursor keys can be used to select a peg colour, the left and right keys to select a peg position, and the space bar or Enter key to place a peg of the selected colour in the chosen position. `D' or Backspace removes a peg, and Space adds a hold marker. Pressing `h' or `?' will fill the current guess with a suggested guess. Using this is not recommended for 10 or more pegs as it is slow. When the guess is complete, the smaller feedback pegs will be highlighted; clicking on these (or moving the peg cursor to them with the arrow keys and pressing the space bar or Enter key) will mark the current guess, copy any held pegs to the next guess, and move the `current guess' marker. If you correctly position all the pegs the solution will be displayed below; if you run out of guesses (or select `Solve...') the solution will also be revealed. (All the actions described in section 2.1 are also available.) 15.2 Guess parameters These parameters are available from the `Custom...' option on the `Type' menu. The default game matches the parameters for the board game `Mastermind'. _Colours_ Number of colours the solution is chosen from; from 2 to 10 (more is harder). _Pegs per guess_ Number of pegs per guess (more is harder). _Guesses_ Number of guesses you have to find the solution in (fewer is harder). _Allow blanks_ Allows blank pegs to be given as part of a guess (makes it easier, because you know that those will never be counted as part of the solution). This is turned off by default. Note that this doesn't allow blank pegs in the solution; if you really wanted that, use one extra colour. _Allow duplicates_ Allows the solution (and the guesses) to contain colours more than once; this increases the search space (making things harder), and is turned on by default. Chapter 16: Pegs ---------------- A number of pegs are placed in holes on a board. You can remove a peg by jumping an adjacent peg over it (horizontally or vertically) to a vacant hole on the other side. Your aim is to remove all but one of the pegs initially present. This game, best known as `Peg Solitaire', is possibly one of the oldest puzzle games still commonly known. 16.1 Pegs controls To move a peg, drag it with the mouse from its current position to its final position. If the final position is exactly two holes away from the initial position, is currently unoccupied by a peg, and there is a peg in the intervening square, the move will be permitted and the intervening peg will be removed. Vacant spaces which you can move a peg into are marked with holes. A space with no peg and no hole is not available for moving at all: it is an obstacle which you must work around. You can also use the cursor keys to move a position indicator around the board. Pressing the return key while over a peg, followed by a cursor key, will jump the peg in that direction (if that is a legal move). (All the actions described in section 2.1 are also available.) 16.2 Pegs parameters These parameters are available from the `Custom...' option on the `Type' menu. _Width_, _Height_ Size of grid in holes. _Board type_ Controls whether you are given a board of a standard shape or a randomly generated shape. The two standard shapes currently supported are `Cross' and `Octagon' (also commonly known as the English and European traditional board layouts respectively). Selecting `Random' will give you a different board shape every time (but always one that is known to have a solution). Chapter 17: Dominosa -------------------- A normal set of dominoes - that is, one instance of every (unordered) pair of numbers from 0 to 6 - has been arranged irregularly into a rectangle; then the number in each square has been written down and the dominoes themselves removed. Your task is to reconstruct the pattern by arranging the set of dominoes to match the provided array of numbers. This puzzle is widely credited to O. S. Adler, and takes part of its name from those initials. 17.1 Dominosa controls Left-clicking between any two adjacent numbers places a domino covering them, or removes one if it is already present. Trying to place a domino which overlaps existing dominoes will remove the ones it overlaps. Right-clicking between two adjacent numbers draws a line between them, which you can use to remind yourself that you know those two numbers are _not_ covered by a single domino. Right-clicking again removes the line. You can also use the cursor keys to move a cursor around the grid. When the cursor is half way between two adjacent numbers, pressing the return key will place a domino covering those numbers, or pressing the space bar will lay a line between the two squares. Repeating either action removes the domino or line. Pressing a number key will highlight all occurrences of that number. Pressing that number again will clear the highlighting. Up to two different numbers can be highlighted at any given time. (All the actions described in section 2.1 are also available.) 17.2 Dominosa parameters These parameters are available from the `Custom...' option on the `Type' menu. _Maximum number on dominoes_ Controls the size of the puzzle, by controlling the size of the set of dominoes used to make it. Dominoes with numbers going up to N will give rise to an (N+2) x (N+1) rectangle; so, in particular, the default value of 6 gives an 8x7 grid. _Ensure unique solution_ Normally, Dominosa will make sure that the puzzles it presents have only one solution. Puzzles with ambiguous sections can be more difficult and sometimes more subtle, so if you like you can turn off this feature. Also, finding _all_ the possible solutions can be an additional challenge for an advanced player. Turning off this option can also speed up puzzle generation. Chapter 18: Untangle -------------------- You are given a number of points, some of which have lines drawn between them. You can move the points about arbitrarily; your aim is to position the points so that no line crosses another. I originally saw this in the form of a Flash game called Planarity [7], written by John Tantalo. [7] http://planarity.net 18.1 Untangle controls To move a point, click on it with the left mouse button and drag it into a new position. (All the actions described in section 2.1 are also available.) 18.2 Untangle parameters There is only one parameter available from the `Custom...' option on the `Type' menu: _Number of points_ Controls the size of the puzzle, by specifying the number of points in the generated graph. Chapter 19: Black Box --------------------- A number of balls are hidden in a rectangular arena. You have to deduce the positions of the balls by firing lasers positioned at the edges of the arena and observing how their beams are deflected. Beams will travel straight from their origin until they hit the opposite side of the arena (at which point they emerge), unless affected by balls in one of the following ways: - A beam that hits a ball head-on is absorbed and will never re- emerge. This includes beams that meet a ball on the first rank of the arena. - A beam with a ball in its front-left square and no ball ahead of it gets deflected 90 degrees to the right. - A beam with a ball in its front-right square and no ball ahead of it gets similarly deflected to the left. - A beam that would re-emerge from its entry location is considered to be `reflected'. - A beam which would get deflected before entering the arena by a ball to the front-left or front-right of its entry point is also considered to be `reflected'. Beams that are reflected appear as a `R'; beams that hit balls head- on appear as `H'. Otherwise, a number appears at the firing point and the location where the beam emerges (this number is unique to that shot). You can place guesses as to the location of the balls, based on the entry and exit patterns of the beams; once you have placed enough balls a button appears enabling you to have your guesses checked. Here is a diagram showing how the positions of balls can create each of the beam behaviours shown above: 1RHR---- |..O.O...| 2........3 |........| |........| 3........| |......O.| H........| |.....O..| 12-RR--- As shown, it is possible for a beam to receive multiple reflections before re-emerging (see turn 3). Similarly, a beam may be reflected (possibly more than once) before receiving a hit (the `H' on the left side of the example). Note that any layout with more than 4 balls may have a non-unique solution. The following diagram illustrates this; if you know the board contains 5 balls, it is impossible to determine where the fifth ball is (possible positions marked with an x): -------- |........| |........| |..O..O..| |...xx...| |...xx...| |..O..O..| |........| |........| -------- For this reason, when you have your guesses checked, the game will check that your solution _produces the same results_ as the computer's, rather than that your solution is identical to the computer's. So in the above example, you could put the fifth ball at _any_ of the locations marked with an x, and you would still win. Black Box was contributed to this collection by James Harvey. 19.1 Black Box controls To fire a laser beam, left-click in a square around the edge of the arena. The results will be displayed immediately. Clicking or holding the left button on one of these squares will highlight the current go (or a previous go) to confirm the exit point for that laser, if applicable. To guess the location of a ball, left-click within the arena and a black circle will appear marking the guess; click again to remove the guessed ball. Locations in the arena may be locked against modification by right- clicking; whole rows and columns may be similarly locked by right- clicking in the laser square above/below that column, or to the left/right of that row. The cursor keys may also be used to move around the grid. Pressing the Enter key will fire a laser or add a new ball-location guess, and pressing Space will lock a cell, row, or column. When an appropriate number of balls have been guessed, a button will appear at the top-left corner of the grid; clicking that (with mouse or cursor) will check your guesses. If you click the `check' button and your guesses are not correct, the game will show you the minimum information necessary to demonstrate this to you, so you can try again. If your ball positions are not consistent with the beam paths you already know about, one beam path will be circled to indicate that it proves you wrong. If your positions match all the existing beam paths but are still wrong, one new beam path will be revealed (written in red) which is not consistent with your current guesses. If you decide to give up completely, you can select Solve to reveal the actual ball positions. At this point, correctly-placed balls will be displayed as filled black circles, incorrectly-placed balls as filled black circles with red crosses, and missing balls as filled red circles. In addition, a red circle marks any laser you had already fired which is not consistent with your ball layout (just as when you press the `check' button), and red text marks any laser you _could_ have fired in order to distinguish your ball layout from the correct one. (All the actions described in section 2.1 are also available.) 19.2 Black Box parameters These parameters are available from the `Custom...' option on the `Type' menu. _Width_, _Height_ Size of grid in squares. There are 2 x _Width_ x _Height_ lasers per grid, two per row and two per column. _No. of balls_ Number of balls to place in the grid. This can be a single number, or a range (separated with a hyphen, like `2-6'), and determines the number of balls to place on the grid. The `reveal' button is only enabled if you have guessed an appropriate number of balls; a guess using a different number to the original solution is still acceptable, if all the beam inputs and outputs match. Chapter 20: Slant ----------------- You have a grid of squares. Your aim is to draw a diagonal line through each square, and choose which way each line slants so that the following conditions are met: - The diagonal lines never form a loop. - Any point with a circled number has precisely that many lines meeting at it. (Thus, a 4 is the centre of a cross shape, whereas a zero is the centre of a diamond shape - or rather, a partial diamond shape, because a zero can never appear in the middle of the grid because that would immediately cause a loop.) Credit for this puzzle goes to Nikoli [8]. [8] http://www.nikoli.co.jp/ja/puzzles/gokigen_naname (in Japanese) 20.1 Slant controls Left-clicking in a blank square will place a \ in it (a line leaning to the left, i.e. running from the top left of the square to the bottom right). Right-clicking in a blank square will place a / in it (leaning to the right, running from top right to bottom left). Continuing to click either button will cycle between the three possible square contents. Thus, if you left-click repeatedly in a blank square it will change from blank to \ to / back to blank, and if you right-click repeatedly the square will change from blank to / to \ back to blank. (Therefore, you can play the game entirely with one button if you need to.) You can also use the cursor keys to move around the grid. Pressing the return or space keys will place a \ or a /, respectively, and will then cycle them as above. You can also press / or \ to place a / or \, respectively, independent of what is already in the cursor square. Backspace removes any line from the cursor square. (All the actions described in section 2.1 are also available.) 20.2 Slant parameters These parameters are available from the `Custom...' option on the `Type' menu. _Width_, _Height_ Size of grid in squares. _Difficulty_ Controls the difficulty of the generated puzzle. At Hard level, you are required to do deductions based on knowledge of _relationships_ between squares rather than always being able to deduce the exact contents of one square at a time. (For example, you might know that two squares slant in the same direction, even if you don't yet know what that direction is, and this might enable you to deduce something about still other squares.) Even at Hard level, guesswork and backtracking should never be necessary. Chapter 21: Light Up -------------------- You have a grid of squares. Some are filled in black; some of the black squares are numbered. Your aim is to `light up' all the empty squares by placing light bulbs in some of them. Each light bulb illuminates the square it is on, plus all squares in line with it horizontally or vertically unless a black square is blocking the way. To win the game, you must satisfy the following conditions: - All non-black squares are lit. - No light is lit by another light. - All numbered black squares have exactly that number of lights adjacent to them (in the four squares above, below, and to the side). Non-numbered black squares may have any number of lights adjacent to them. Credit for this puzzle goes to Nikoli [9]. Light Up was contributed to this collection by James Harvey. [9] http://www.nikoli.co.jp/en/puzzles/akari.html (beware of Flash) 21.1 Light Up controls Left-clicking in a non-black square will toggle the presence of a light in that square. Right-clicking in a non-black square toggles a mark there to aid solving; it can be used to highlight squares that cannot be lit, for example. You may not place a light in a marked square, nor place a mark in a lit square. The game will highlight obvious errors in red. Lights lit by other lights are highlighted in this way, as are numbered squares which do not (or cannot) have the right number of lights next to them. Thus, the grid is solved when all non-black squares have yellow highlights and there are no red lights. (All the actions described in section 2.1 are also available.) 21.2 Light Up parameters These parameters are available from the `Custom...' option on the `Type' menu. _Width_, _Height_ Size of grid in squares. _%age of black squares_ Rough percentage of black squares in the grid. This is a hint rather than an instruction. If the grid generator is unable to generate a puzzle to this precise specification, it will increase the proportion of black squares until it can. _Symmetry_ Allows you to specify the required symmetry of the black squares in the grid. (This does not affect the difficulty of the puzzles noticeably.) _Difficulty_ `Easy' means that the puzzles should be soluble without backtracking or guessing, `Hard' means that some guesses will probably be necessary. Chapter 22: Map --------------- You are given a map consisting of a number of regions. Your task is to colour each region with one of four colours, in such a way that no two regions sharing a boundary have the same colour. You are provided with some regions already coloured, sufficient to make the remainder of the solution unique. Only regions which share a length of border are required to be different colours. Two regions which meet at only one _point_ (i.e. are diagonally separated) may be the same colour. I believe this puzzle is original; I've never seen an implementation of it anywhere else. The concept of a four-colouring puzzle was suggested by Owen Dunn; credit must also go to Nikoli and to Verity Allan for inspiring the train of thought that led to me realising Owen's suggestion was a viable puzzle. Thanks also to Gareth Taylor for many detailed suggestions. 22.1 Map controls To colour a region, click the left mouse button on an existing region of the desired colour and drag that colour into the new region. (The program will always ensure the starting puzzle has at least one region of each colour, so that this is always possible!) If you need to clear a region, you can drag from an empty region, or from the puzzle boundary if there are no empty regions left. Dragging a colour using the _right_ mouse button will stipple the region in that colour, which you can use as a note to yourself that you think the region _might_ be that colour. A region can contain stipples in multiple colours at once. (This is often useful at the harder difficulty levels.) You can also use the cursor keys to move around the map: the colour of the cursor indicates the position of the colour you would drag (which is not obvious if you're on a region's boundary, since it depends on the direction from which you approached the boundary). Pressing the return key starts a drag of that colour, as above, which you control with the cursor keys; pressing the return key again finishes the drag. The space bar can be used similarly to create a stippled region. Double-pressing the return key (without moving the cursor) will clear the region, as a drag from an empty region does: this is useful with the cursor mode if you have filled the entire map in but need to correct the layout. If you press L during play, the game will toggle display of a number in each region of the map. This is useful if you want to discuss a particular puzzle instance with a friend - having an unambiguous name for each region is much easier than trying to refer to them all by names such as `the one down and right of the brown one on the top border'. (All the actions described in section 2.1 are also available.) 22.2 Map parameters These parameters are available from the `Custom...' option on the `Type' menu. _Width_, _Height_ Size of grid in squares. _Regions_ Number of regions in the generated map. _Difficulty_ In `Easy' mode, there should always be at least one region whose colour can be determined trivially. In `Normal' and `Hard' modes, you will have to use increasingly complex logic to deduce the colour of some regions. However, it will always be possible without having to guess or backtrack. In `Unreasonable' mode, the program will feel free to generate puzzles which are as hard as it can possibly make them: the only constraint is that they should still have a unique solution. Solving Unreasonable puzzles may require guessing and backtracking. Chapter 23: Loopy ----------------- You are given a grid of dots, marked with yellow lines to indicate which dots you are allowed to connect directly together. Your aim is to use some subset of those yellow lines to draw a single unbroken loop from dot to dot within the grid. Some of the spaces between the lines contain numbers. These numbers indicate how many of the lines around that space form part of the loop. The loop you draw must correctly satisfy all of these clues to be considered a correct solution. In the default mode, the dots are arranged in a grid of squares; however, you can also play on triangular or hexagonal grids, or even more exotic ones. Credit for the basic puzzle idea goes to Nikoli [10]. Loopy was originally contributed to this collection by Mike Pinna, and subsequently enhanced to handle various types of non-square grid by Lambros Lambrou. [10] http://www.nikoli.co.jp/en/puzzles/slitherlink.html (beware of Flash) 23.1 Loopy controls Click the left mouse button on a yellow line to turn it black, indicating that you think it is part of the loop. Click again to turn the line yellow again (meaning you aren't sure yet). If you are sure that a particular line segment is _not_ part of the loop, you can click the right mouse button to remove it completely. Again, clicking a second time will turn the line back to yellow. (All the actions described in section 2.1 are also available.) 23.2 Loopy parameters These parameters are available from the `Custom...' option on the `Type' menu. _Width_, _Height_ Size of grid, measured in number of regions across and down. For square grids, it's clear how this is counted; for other types of grid you may have to think a bit to see how the dimensions are measured. _Grid type_ Allows you to choose between a selection of types of tiling. Some have all the faces the same but may have multiple different types of vertex (e.g. the _Cairo_ or _Kites_ mode); others have all the vertices the same but may have different types of face (e.g. the _Great Hexagonal_). The square, triangular and honeycomb grids are fully regular, and have all their vertices _and_ faces the same; this makes them the least confusing to play. _Difficulty_ Controls the difficulty of the generated puzzle. Chapter 24: Inertia ------------------- You are a small green ball sitting in a grid full of obstacles. Your aim is to collect all the gems without running into any mines. You can move the ball in any orthogonal _or diagonal_ direction. Once the ball starts moving, it will continue until something stops it. A wall directly in its path will stop it (but if it is moving diagonally, it will move through a diagonal gap between two other walls without stopping). Also, some of the squares are `stops'; when the ball moves on to a stop, it will stop moving no matter what direction it was going in. Gems do _not_ stop the ball; it picks them up and keeps on going. Running into a mine is fatal. Even if you picked up the last gem in the same move which then hit a mine, the game will count you as dead rather than victorious. This game was originally implemented for Windows by Ben Olmstead [11], who was kind enough to release his source code on request so that it could be re-implemented for this collection. [11] http://xn13.com/ 24.1 Inertia controls You can move the ball in any of the eight directions using the numeric keypad. Alternatively, if you click the left mouse button on the grid, the ball will begin a move in the general direction of where you clicked. If you use the `Solve' function on this game, the program will compute a path through the grid which collects all the remaining gems and returns to the current position. A hint arrow will appear on the ball indicating the direction in which you should move to begin on this path. If you then move in that direction, the arrow will update to indicate the next direction on the path. You can also press Space to automatically move in the direction of the hint arrow. If you move in a different direction from the one shown by the arrow, arrows will be shown only if the puzzle is still solvable. All the actions described in section 2.1 are also available. In particular, if you do run into a mine and die, you can use the Undo function and resume playing from before the fatal move. The game will keep track of the number of times you have done this. 24.2 Inertia parameters These parameters are available from the `Custom...' option on the `Type' menu. _Width_, _Height_ Size of grid in squares. Chapter 25: Tents ----------------- You have a grid of squares, some of which contain trees. Your aim is to place tents in some of the remaining squares, in such a way that the following conditions are met: - There are exactly as many tents as trees. - The tents and trees can be matched up in such a way that each tent is directly adjacent (horizontally or vertically, but not diagonally) to its own tree. However, a tent may be adjacent to other trees as well as its own. - No two tents are adjacent horizontally, vertically _or diagonally_. - The number of tents in each row, and in each column, matches the numbers given round the sides of the grid. This puzzle can be found in several places on the Internet, and was brought to my attention by e-mail. I don't know who I should credit for inventing it. 25.1 Tents controls Left-clicking in a blank square will place a tent in it. Right- clicking in a blank square will colour it green, indicating that you are sure it _isn't_ a tent. Clicking either button in an occupied square will clear it. If you _drag_ with the right button along a row or column, every blank square in the region you cover will be turned green, and no other squares will be affected. (This is useful for clearing the remainder of a row once you have placed all its tents.) You can also use the cursor keys to move around the grid. Pressing the return key over an empty square will place a tent, and pressing the space bar over an empty square will colour it green; either key will clear an occupied square. Holding Shift and pressing the cursor keys will colour empty squares green. Holding Control and pressing the cursor keys will colour green both empty squares and squares with tents. (All the actions described in section 2.1 are also available.) 25.2 Tents parameters These parameters are available from the `Custom...' option on the `Type' menu. _Width_, _Height_ Size of grid in squares. _Difficulty_ Controls the difficulty of the generated puzzle. More difficult puzzles require more complex deductions, but at present none of the available difficulty levels requires guesswork or backtracking. Chapter 26: Bridges ------------------- You have a set of islands distributed across the playing area. Each island contains a number. Your aim is to connect the islands together with bridges, in such a way that: - Bridges run horizontally or vertically. - The number of bridges terminating at any island is equal to the number written in that island. - Two bridges may run in parallel between the same two islands, but no more than two may do so. - No bridge crosses another bridge. - All the islands are connected together. There are some configurable alternative modes, which involve changing the parallel-bridge limit to something other than 2, and introducing the additional constraint that no sequence of bridges may form a loop from one island back to the same island. The rules stated above are the default ones. Credit for this puzzle goes to Nikoli [12]. Bridges was contributed to this collection by James Harvey. [12] http://www.nikoli.co.jp/en/puzzles/hashiwokakero.html (beware of Flash) 26.1 Bridges controls To place a bridge between two islands, click the mouse down on one island and drag it towards the other. You do not need to drag all the way to the other island; you only need to move the mouse far enough for the intended bridge direction to be unambiguous. (So you can keep the mouse near the starting island and conveniently throw bridges out from it in many directions.) Doing this again when a bridge is already present will add another parallel bridge. If there are already as many bridges between the two islands as permitted by the current game rules (i.e. two by default), the same dragging action will remove all of them. If you want to remind yourself that two islands definitely _do not_ have a bridge between them, you can right-drag between them in the same way to draw a `non-bridge' marker. If you think you have finished with an island (i.e. you have placed all its bridges and are confident that they are in the right places), you can mark the island as finished by left-clicking on it. This will highlight it and all the bridges connected to it, and you will be prevented from accidentally modifying any of those bridges in future. Left-clicking again on a highlighted island will unmark it and restore your ability to modify it. You can also use the cursor keys to move around the grid: if possible the cursor will always move orthogonally, otherwise it will move towards the nearest island to the indicated direction. Holding Control and pressing a cursor key will lay a bridge in that direction (if available); Shift and a cursor key will lay a `non- bridge' marker. Pressing the return key followed by a cursor key will also lay a bridge in that direction. You can mark an island as finished by pressing the space bar or by pressing the return key twice. By pressing a number key, you can jump to the nearest island with that number. Letters `a', ..., `f' count as 10, ..., 15 and `0' as 16. Violations of the puzzle rules will be marked in red: - An island with too many bridges will be highlighted in red. - An island with too few bridges will be highlighted in red if it is definitely an error (as opposed to merely not being finished yet): if adding enough bridges would involve having to cross another bridge or remove a non-bridge marker, or if the island has been highlighted as complete. - A group of islands and bridges may be highlighted in red if it is a closed subset of the puzzle with no way to connect it to the rest of the islands. For example, if you directly connect two 1s together with a bridge and they are not the only two islands on the grid, they will light up red to indicate that such a group cannot be contained in any valid solution. - If you have selected the (non-default) option to disallow loops in the solution, a group of bridges which forms a loop will be highlighted. (All the actions described in section 2.1 are also available.) 26.2 Bridges parameters These parameters are available from the `Custom...' option on the `Type' menu. _Width_, _Height_ Size of grid in squares. _Difficulty_ Difficulty level of puzzle. _Allow loops_ This is set by default. If cleared, puzzles will be generated in such a way that they are always soluble without creating a loop, and solutions which do involve a loop will be disallowed. _Max. bridges per direction_ Maximum number of bridges in any particular direction. The default is 2, but you can change it to 1, 3 or 4. In general, fewer is easier. _%age of island squares_ Gives a rough percentage of islands the generator will try and lay before finishing the puzzle. Certain layouts will not manage to lay enough islands; this is an upper bound. _Expansion factor (%age)_ The grid generator works by picking an existing island at random (after first creating an initial island somewhere). It then decides on a direction (at random), and then works out how far it could extend before creating another island. This parameter determines how likely it is to extend as far as it can, rather than choosing somewhere closer. High expansion factors usually mean easier puzzles with fewer possible islands; low expansion factors can create lots of tightly-packed islands. Chapter 27: Unequal ------------------- You have a square grid; each square may contain a digit from 1 to the size of the grid, and some squares have clue signs between them. Your aim is to fully populate the grid with numbers such that: - Each row contains only one occurrence of each digit - Each column contains only one occurrence of each digit - All the clue signs are satisfied. There are two modes for this game, `Unequal' and `Adjacent'. In `Unequal' mode, the clue signs are greater-than symbols indicating one square's value is greater than its neighbour's. In this mode not all clues may be visible, particularly at higher difficulty levels. In `Adjacent' mode, the clue signs are bars indicating one square's value is numerically adjacent (i.e. one higher or one lower) than its neighbour. In this mode all clues are always visible: absence of a bar thus means that a square's value is definitely not numerically adjacent to that neighbour's. In `Trivial' difficulty level (available via the `Custom' game type selector), there are no greater-than signs in `Unequal' mode; the puzzle is to solve the Latin square only. At the time of writing, the `Unequal' mode of this puzzle is appearing in the Guardian weekly under the name `Futoshiki'. Unequal was contributed to this collection by James Harvey. 27.1 Unequal controls Unequal shares much of its control system with Solo. To play Unequal, simply click the mouse in any empty square and then type a digit or letter on the keyboard to fill that square. If you make a mistake, click the mouse in the incorrect square and press Space to clear it again (or use the Undo feature). If you _right_-click in a square and then type a number, that number will be entered in the square as a `pencil mark'. You can have pencil marks for multiple numbers in the same square. Squares containing filled-in numbers cannot also contain pencil marks. The game pays no attention to pencil marks, so exactly what you use them for is up to you: you can use them as reminders that a particular square needs to be re-examined once you know more about a particular number, or you can use them as lists of the possible numbers in a given square, or anything else you feel like. To erase a single pencil mark, right-click in the square and type the same number again. All pencil marks in a square are erased when you left-click and type a number, or when you left-click and press space. Right-clicking and pressing space will also erase pencil marks. As for Solo, the cursor keys can be used in conjunction with the digit keys to set numbers or pencil marks. You can also use the `M' key to auto-fill every numeric hint, ready for removal as required, or the `H' key to do the same but also to remove all obvious hints. Alternatively, use the cursor keys to move the mark around the grid. Pressing the return key toggles the mark (from a normal mark to a pencil mark), and typing a number in is entered in the square in the appropriate way; typing in a 0 or using the space bar will clear a filled square. Left-clicking a clue will mark it as done (grey it out), or unmark it if it is already marked. Holding Control or Shift and pressing an arrow key likewise marks any clue adjacent to the cursor in the given direction. (All the actions described in section 2.1 are also available.) 27.2 Unequal parameters These parameters are available from the `Custom...' option on the `Type' menu. _Mode_ Mode of the puzzle (`Unequal' or `Adjacent') _Size (s*s)_ Size of grid. _Difficulty_ Controls the difficulty of the generated puzzle. At Trivial level, there are no greater-than signs; the puzzle is to solve the Latin square only. At Recursive level (only available via the `Custom' game type selector) backtracking will be required, but the solution should still be unique. The levels in between require increasingly complex reasoning to avoid having to backtrack. Chapter 28: Galaxies -------------------- You have a rectangular grid containing a number of dots. Your aim is to draw edges along the grid lines which divide the rectangle into regions in such a way that every region is 180-degree rotationally symmetric, and contains exactly one dot which is located at its centre of symmetry. This puzzle was invented by Nikoli [13], under the name `Tentai Show'; its name is commonly translated into English as `Spiral Galaxies'. Galaxies was contributed to this collection by James Harvey. [13] http://www.nikoli.co.jp/en/puzzles/astronomical_show.html 28.1 Galaxies controls Left-click on any grid line to draw an edge if there isn't one already, or to remove one if there is. When you create a valid region (one which is closed, contains exactly one dot, is 180-degree symmetric about that dot, and contains no extraneous edges inside it) it will be highlighted automatically; so your aim is to have the whole grid highlighted in that way. During solving, you might know that a particular grid square belongs to a specific dot, but not be sure of where the edges go and which other squares are connected to the dot. In order to mark this so you don't forget, you can right-click on the dot and drag, which will create an arrow marker pointing at the dot. Drop that in a square of your choice and it will remind you which dot it's associated with. You can also right-click on existing arrows to pick them up and move them, or destroy them by dropping them off the edge of the grid. (Also, if you're not sure which dot an arrow is pointing at, you can pick it up and move it around to make it clearer. It will swivel constantly as you drag it, to stay pointed at its parent dot.) You can also use the cursor keys to move around the grid squares and lines. Pressing the return key when over a grid line will draw or clear its edge, as above. Pressing the return key when over a dot will pick up an arrow, to be dropped the next time the return key is pressed; this can also be used to move existing arrows around, removing them by dropping them on a dot or another arrow. (All the actions described in section 2.1 are also available.) 28.2 Galaxies parameters These parameters are available from the `Custom...' option on the `Type' menu. _Width_, _Height_ Size of grid in squares. _Difficulty_ Controls the difficulty of the generated puzzle. More difficult puzzles require more complex deductions, and the `Unreasonable' difficulty level may require backtracking. Chapter 29: Filling ------------------- You have a grid of squares, some of which contain digits, and the rest of which are empty. Your job is to fill in digits in the empty squares, in such a way that each connected region of squares all containing the same digit has an area equal to that digit. (`Connected region', for the purposes of this game, does not count diagonally separated squares as adjacent.) For example, it follows that no square can contain a zero, and that two adjacent squares can not both contain a one. No region has an area greater than 9 (because then its area would not be a single digit). Credit for this puzzle goes to Nikoli [14]. Filling was contributed to this collection by Jonas Koelker. [14] http://www.nikoli.co.jp/en/puzzles/fillomino.html 29.1 Filling controls To play Filling, simply click the mouse in any empty square and then type a digit on the keyboard to fill that square. By dragging the mouse, you can select multiple squares to fill with a single keypress. If you make a mistake, click the mouse in the incorrect square and press 0, Space, Backspace or Enter to clear it again (or use the Undo feature). You can also move around the grid with the cursor keys; typing a digit will fill the square containing the cursor with that number; typing 0 will clear it. You can also select multiple squares for numbering or clearing with the return and arrow keys, before typing a digit to fill or clear the highlighted squares (as above). The space bar adds and removes single squares to and from the selection. Backspace and escape remove all squares from the selection. (All the actions described in section 2.1 are also available.) 29.2 Filling parameters Filling allows you to configure the number of rows and columns of the grid, through the `Type' menu. Chapter 30: Keen ---------------- You have a square grid; each square may contain a digit from 1 to the size of the grid. The grid is divided into blocks of varying shape and size, with arithmetic clues written in them. Your aim is to fully populate the grid with digits such that: - Each row contains only one occurrence of each digit - Each column contains only one occurrence of each digit - The digits in each block can be combined to form the number stated in the clue, using the arithmetic operation given in the clue. That is: - An addition clue means that the sum of the digits in the block must be the given number. For example, `15+' means the contents of the block adds up to fifteen. - A multiplication clue (e.g. `60*'), similarly, means that the product of the digits in the block must be the given number. - A subtraction clue will always be written in a block of size two, and it means that one of the digits in the block is greater than the other by the given amount. For example, `2-' means that one of the digits in the block is 2 more than the other, or equivalently that one digit minus the other one is 2. The two digits could be either way round, though. - A division clue (e.g. `3/'), similarly, is always in a block of size two and means that one digit divided by the other is equal to the given amount. Note that a block may contain the same digit more than once (provided the identical ones are not in the same row and column). This rule is precisely the opposite of the rule in Solo's `Killer' mode (see chapter 11). This puzzle appears in the Times under the name `KenKen'. 30.1 Keen controls Keen shares much of its control system with Solo (and Unequal). To play Keen, simply click the mouse in any empty square and then type a digit on the keyboard to fill that square. If you make a mistake, click the mouse in the incorrect square and press Space to clear it again (or use the Undo feature). If you _right_-click in a square and then type a number, that number will be entered in the square as a `pencil mark'. You can have pencil marks for multiple numbers in the same square. Squares containing filled-in numbers cannot also contain pencil marks. The game pays no attention to pencil marks, so exactly what you use them for is up to you: you can use them as reminders that a particular square needs to be re-examined once you know more about a particular number, or you can use them as lists of the possible numbers in a given square, or anything else you feel like. To erase a single pencil mark, right-click in the square and type the same number again. All pencil marks in a square are erased when you left-click and type a number, or when you left-click and press space. Right-clicking and pressing space will also erase pencil marks. As for Solo, the cursor keys can be used in conjunction with the digit keys to set numbers or pencil marks. Use the cursor keys to move a highlight around the grid, and type a digit to enter it in the highlighted square. Pressing return toggles the highlight into a mode in which you can enter or remove pencil marks. Pressing M will fill in a full set of pencil marks in every square that does not have a main digit in it. (All the actions described in section 2.1 are also available.) 30.2 Keen parameters These parameters are available from the `Custom...' option on the `Type' menu. _Grid size_ Specifies the size of the grid. Lower limit is 3; upper limit is 9 (because the user interface would become more difficult with `digits' bigger than 9!). _Difficulty_ Controls the difficulty of the generated puzzle. At Unreasonable level, some backtracking will be required, but the solution should still be unique. The remaining levels require increasingly complex reasoning to avoid having to backtrack. _Multiplication only_ If this is enabled, all boxes will be multiplication boxes. With this rule, the puzzle is known as `Inshi No Heya'. Chapter 31: Towers ------------------ You have a square grid. On each square of the grid you can build a tower, with its height ranging from 1 to the size of the grid. Around the edge of the grid are some numeric clues. Your task is to build a tower on every square, in such a way that: - Each row contains every possible height of tower once - Each column contains every possible height of tower once - Each numeric clue describes the number of towers that can be seen if you look into the square from that direction, assuming that shorter towers are hidden behind taller ones. For example, in a 5x5 grid, a clue marked `5' indicates that the five tower heights must appear in increasing order (otherwise you would not be able to see all five towers), whereas a clue marked `1' indicates that the tallest tower (the one marked 5) must come first. In harder or larger puzzles, some towers will be specified for you as well as the clues round the edge, and some edge clues may be missing. This puzzle appears on the web under various names, particularly `Skyscrapers', but I don't know who first invented it. 31.1 Towers controls Towers shares much of its control system with Solo, Unequal and Keen. To play Towers, simply click the mouse in any empty square and then type a digit on the keyboard to fill that square with a tower of the given height. If you make a mistake, click the mouse in the incorrect square and press Space to clear it again (or use the Undo feature). If you _right_-click in a square and then type a number, that number will be entered in the square as a `pencil mark'. You can have pencil marks for multiple numbers in the same square. A square containing a tower cannot also contain pencil marks. The game pays no attention to pencil marks, so exactly what you use them for is up to you: you can use them as reminders that a particular square needs to be re-examined once you know more about a particular number, or you can use them as lists of the possible numbers in a given square, or anything else you feel like. To erase a single pencil mark, right-click in the square and type the same number again. All pencil marks in a square are erased when you left-click and type a number, or when you left-click and press space. Right-clicking and pressing space will also erase pencil marks. As for Solo, the cursor keys can be used in conjunction with the digit keys to set numbers or pencil marks. Use the cursor keys to move a highlight around the grid, and type a digit to enter it in the highlighted square. Pressing return toggles the highlight into a mode in which you can enter or remove pencil marks. Pressing M will fill in a full set of pencil marks in every square that does not have a main digit in it. Left-clicking a clue will mark it as done (grey it out), or unmark it if it is already marked. Holding Control or Shift and pressing an arrow key likewise marks any clue in the given direction. (All the actions described in section 2.1 are also available.) 31.2 Towers parameters These parameters are available from the `Custom...' option on the `Type' menu. _Grid size_ Specifies the size of the grid. Lower limit is 3; upper limit is 9 (because the user interface would become more difficult with `digits' bigger than 9!). _Difficulty_ Controls the difficulty of the generated puzzle. At Unreasonable level, some backtracking will be required, but the solution should still be unique. The remaining levels require increasingly complex reasoning to avoid having to backtrack. Chapter 32: Singles ------------------- You have a grid of white squares, all of which contain numbers. Your task is to colour some of the squares black (removing the number) so as to satisfy all of the following conditions: - No number occurs more than once in any row or column. - No black square is horizontally or vertically adjacent to any other black square. - The remaining white squares must all form one contiguous region (connected by edges, not just touching at corners). Credit for this puzzle goes to Nikoli [15] who call it Hitori. Singles was contributed to this collection by James Harvey. [15] http://www.nikoli.com/en/puzzles/hitori.html (beware of Flash) 32.1 Singles controls Left-clicking on an empty square will colour it black; left-clicking again will restore the number. Right-clicking will add a circle (useful for indicating that a cell is definitely not black). You can also use the cursor keys to move around the grid. Pressing the return or space keys will turn a square black or add a circle respectively, and pressing the key again will restore the number or remove the circle. (All the actions described in section 2.1 are also available.) 32.2 Singles parameters These parameters are available from the `Custom...' option on the `Type' menu. _Width_, _Height_ Size of grid in squares. _Difficulty_ Controls the difficulty of the generated puzzle. Chapter 33: Magnets ------------------- A rectangular grid has been filled with a mixture of magnets (that is, dominoes with one positive end and one negative end) and blank dominoes (that is, dominoes with two neutral poles). These dominoes are initially only seen in silhouette. Around the grid are placed a number of clues indicating the number of positive and negative poles contained in certain columns and rows. Your aim is to correctly place the magnets and blank dominoes such that all the clues are satisfied, with the additional constraint that no two similar magnetic poles may be orthogonally adjacent (since they repel). Neutral poles do not repel, and can be adjacent to any other pole. Credit for this puzzle goes to Janko [16]. Magnets was contributed to this collection by James Harvey. [16] http://www.janko.at/Raetsel/Magnete/index.htm 33.1 Magnets controls Left-clicking on an empty square places a magnet at that position with the positive pole on the square and the negative pole on the other half of the magnet; left-clicking again reverses the polarity, and a third click removes the magnet. Right-clicking on an empty square places a blank domino there. Right-clicking again places two question marks on the domino, signifying `this cannot be blank' (which can be useful to note deductions while solving), and right-clicking again empties the domino. Left-clicking a clue will mark it as done (grey it out), or unmark it if it is already marked. You can also use the cursor keys to move a cursor around the grid. Pressing the return key will lay a domino with a positive pole at that position; pressing again reverses the polarity and then removes the domino, as with left-clicking. Using the space bar allows placement of blank dominoes and cannot-be-blank hints, as for right- clicking. (All the actions described in section 2.1 are also available.) 33.2 Magnets parameters These parameters are available from the `Custom...' option on the `Type' menu. _Width_, _Height_ Size of grid in squares. There will be half _Width_ x _Height_ dominoes in the grid: if this number is odd then one square will be blank. (Grids with at least one odd dimension tend to be easier to solve.) _Difficulty_ Controls the difficulty of the generated puzzle. At Tricky level, you are required to make more deductions about empty dominoes and row/column counts. _Strip clues_ If true, some of the clues around the grid are removed at generation time, making the puzzle more difficult. Chapter 34: Signpost -------------------- You have a grid of squares; each square (except the last one) contains an arrow, and some squares also contain numbers. Your job is to connect the squares to form a continuous list of numbers starting at 1 and linked in the direction of the arrows - so the arrow inside the square with the number 1 will point to the square containing the number 2, which will point to the square containing the number 3, etc. Each square can be any distance away from the previous one, as long as it is somewhere in the direction of the arrow. By convention the first and last numbers are shown; one or more interim numbers may also appear at the beginning. Credit for this puzzle goes to Janko [17], who call it `Pfeilpfad' (`arrow path'). Signpost was contributed to this collection by James Harvey. [17] http://janko.at/Raetsel/Pfeilpfad/index.htm 34.1 Signpost controls To play Signpost, you connect squares together by dragging from one square to another, indicating that they are adjacent in the sequence. Drag with the left button from a square to its successor, or with the right button from a square to its predecessor. If you connect together two squares in this way and one of them has a number in it, the appropriate number will appear in the other square. If you connect two non-numbered squares, they will be assigned temporary algebraic labels: on the first occasion, they will be labelled `a' and `a+1', and then `b' and `b+1', and so on. Connecting more squares on to the ends of such a chain will cause them all to be labelled with the same letter. When you left-click or right-click in a square, the legal squares to connect it to will be shown. The arrow in each square starts off black, and goes grey once you connect the square to its successor. Also, each square which needs a predecessor has a small dot in the bottom left corner, which vanishes once you link a square to it. So your aim is always to connect a square with a black arrow to a square with a dot. To remove any links for a particular square (both incoming and outgoing), left-drag it off the grid. To remove a whole chain, right-drag any square in the chain off the grid. You can also use the cursor keys to move around the grid squares and lines. Pressing the return key when over a square starts a link operation, and pressing the return key again over a square will finish the link, if allowable. Pressing the space bar over a square will show the other squares pointing to it, and allow you to form a backward link, and pressing the space bar again cancels this. (All the actions described in section 2.1 are also available.) 34.2 Signpost parameters These parameters are available from the `Custom...' option on the `Type' menu. _Width_, _Height_ Size of grid in squares. _Force start/end to corners_ If true, the start and end squares are always placed in opposite corners (the start at the top left, and the end at the bottom right). If false the start and end squares are placed randomly (although always both shown). Chapter 35: Range ----------------- You have a grid of squares; some squares contain numbers. Your job is to colour some of the squares black, such that several criteria are satisfied: - no square with a number is coloured black. - no two black squares are adjacent (horizontally or vertically). - for any two white squares, there is a path between them using only white squares. - for each square with a number, that number denotes the total number of white squares reachable from that square going in a straight line in any horizontal or vertical direction until hitting a wall or a black square; the square with the number is included in the total (once). For instance, a square containing the number one must have four black squares as its neighbours by the last criterion; but then it's impossible for it to be connected to any outside white square, which violates the second to last criterion. So no square will contain the number one. Credit for this puzzle goes to Nikoli, who have variously called it `Kurodoko', `Kuromasu' or `Where is Black Cells'. [18]. Range was contributed to this collection by Jonas Koelker. [18] http://www.nikoli.co.jp/en/puzzles/where_is_black_cells.html 35.1 Range controls Click with the left button to paint a square black, or with the right button to mark a square with a dot to indicate that you are sure it should _not_ be painted black. Repeated clicking with either button will cycle the square through the three possible states (filled, dotted or empty) in opposite directions. You can also use the cursor keys to move around the grid squares. Pressing Return does the same as clicking with the left button, while pressing Space does the same as a right button click. Moving with the cursor keys while holding Shift will place dots in all squares that are moved through. (All the actions described in section 2.1 are also available.) 35.2 Range parameters These parameters are available from the `Custom...' option on the `Type' menu. _Width_, _Height_ Size of grid in squares. Chapter 36: Pearl ----------------- You have a grid of squares. Your job is to draw lines between the centres of horizontally or vertically adjacent squares, so that the lines form a single closed loop. In the resulting grid, some of the squares that the loop passes through will contain corners, and some will be straight horizontal or vertical lines. (And some squares can be completely empty - the loop doesn't have to pass through every square.) Some of the squares contain black and white circles, which are clues that the loop must satisfy. A black circle in a square indicates that that square is a corner, but neither of the squares adjacent to it in the loop is also a corner. A white circle indicates that the square is a straight edge, but _at least one_ of the squares adjacent to it in the loop is a corner. (In both cases, the clue only constrains the two squares adjacent _in the loop_, that is, the squares that the loop passes into after leaving the clue square. The squares that are only adjacent _in the grid_ are not constrained.) Credit for this puzzle goes to Nikoli, who call it `Masyu'. [19] Thanks to James Harvey for assistance with the implementation. [19] http://www.nikoli.co.jp/en/puzzles/masyu.html (beware of Flash) 36.1 Pearl controls Click with the left button on a grid edge to draw a segment of the loop through that edge, or to remove a segment once it is drawn. Drag with the left button through a series of squares to draw more than one segment of the loop in one go. Alternatively, drag over an existing part of the loop to undraw it, or to undraw part of it and then go in a different direction. Click with the right button on a grid edge to mark it with a cross, indicating that you are sure the loop does not go through that edge. (For instance, if you have decided which of the squares adjacent to a white clue has to be a corner, but don't yet know which way the corner turns, you might mark the one way it _can't_ go with a cross.) Alternatively, use the cursor keys to move the cursor. Use the Enter key to begin and end keyboard `drag' operations. Use the Space, Escape or Backspace keys to cancel the drag. Or, hold Control while dragging with the cursor keys to toggle segments as you move between squares. Pressing Control-Shift-arrowkey or Shift-arrowkey simulates a left or right click, respectively, on the edge in the direction of the key. (All the actions described in section 2.1 are also available.) 36.2 Pearl parameters These parameters are available from the `Custom...' option on the `Type' menu. Chapter 37: Undead ------------------ You are given a grid of squares, some of which contain diagonal mirrors. Every square which is not a mirror must be filled with one of three types of undead monster: a ghost, a vampire, or a zombie. Vampires can be seen directly, but are invisible when reflected in mirrors. Ghosts are the opposite way round: they can be seen in mirrors, but are invisible when looked at directly. Zombies are visible by any means. You are also told the total number of each type of monster in the grid. Also around the edge of the grid are written numbers, which indicate how many monsters can be seen if you look into the grid along a row or column starting from that position. (The diagonal mirrors are reflective on both sides. If your reflected line of sight crosses the same monster more than once, the number will count it each time it is visible, not just once.) This puzzle type was invented by David Millar, under the name `Haunted Mirror Maze'. See [20] for more details. Undead was contributed to this collection by Steffen Bauer. [20] http://www.janko.at/Raetsel/Spukschloss/index.htm 37.1 Undead controls Undead has a similar control system to Solo, Unequal and Keen. To play Undead, click the mouse in any empty square and then type a letter on the keyboard indicating the type of monster: `G' for a ghost, `V' for a vampire, or `Z' for a zombie. If you make a mistake, click the mouse in the incorrect square and press Space to clear it again (or use the Undo feature). If you _right_-click in a square and then type a letter, the corresponding monster will be shown in reduced size in that square, as a `pencil mark'. You can have pencil marks for multiple monsters in the same square. A square containing a full-size monster cannot also contain pencil marks. The game pays no attention to pencil marks, so exactly what you use them for is up to you: you can use them as reminders that a particular square needs to be re-examined once you know more about a particular monster, or you can use them as lists of the possible monster in a given square, or anything else you feel like. To erase a single pencil mark, right-click in the square and type the same letter again. All pencil marks in a square are erased when you left-click and type a monster letter, or when you left-click and press Space. Right- clicking and pressing space will also erase pencil marks. As for Solo, the cursor keys can be used in conjunction with the letter keys to place monsters or pencil marks. Use the cursor keys to move a highlight around the grid, and type a monster letter to enter it in the highlighted square. Pressing return toggles the highlight into a mode in which you can enter or remove pencil marks. If you prefer plain letters of the alphabet to cute monster pictures, you can press `A' to toggle between showing the monsters as monsters or showing them as letters. Left-clicking a clue will mark it as done (grey it out), or unmark it if it is already marked. (All the actions described in section 2.1 are also available.) 37.2 Undead parameters These parameters are available from the `Custom...' option on the `Type' menu. _Width_, _Height_ Size of grid in squares. _Difficulty_ Controls the difficulty of the generated puzzle. Chapter 38: Unruly ------------------ You are given a grid of squares, which you must colour either black or white. Some squares are provided as clues; the rest are left for you to fill in. Each row and column must contain the same number of black and white squares, and no row or column may contain three consecutive squares of the same colour. This puzzle type was invented by Adolfo Zanellati, under the name `Tohu wa Vohu'. See [21] for more details. Unruly was contributed to this collection by Lennard Sprong. [21] http://www.janko.at/Raetsel/Tohu-Wa-Vohu/index.htm 38.1 Unruly controls To play Unruly, click the mouse in a square to change its colour. Left-clicking an empty square will turn it black, and right-clicking will turn it white. Keep clicking the same button to cycle through the three possible states for the square. If you middle-click in a square it will be reset to empty. You can also use the cursor keys to move around the grid. Pressing the return or space keys will turn an empty square black or white respectively (and then cycle the colours in the same way as the mouse buttons), and pressing Backspace will reset a square to empty. (All the actions described in section 2.1 are also available.) 38.2 Unruly parameters These parameters are available from the `Custom...' option on the `Type' menu. _Width_, _Height_ Size of grid in squares. (Note that the rules of the game require both the width and height to be even numbers.) _Difficulty_ Controls the difficulty of the generated puzzle. _Unique rows and columns_ If enabled, no two rows are permitted to have exactly the same pattern, and likewise columns. (A row and a column can match, though.) Chapter 39: Flood ----------------- You are given a grid of squares, coloured at random in multiple colours. In each move, you can flood-fill the top left square in a colour of your choice (i.e. every square reachable from the starting square by an orthogonally connected path of squares all the same colour will be filled in the new colour). As you do this, more and more of the grid becomes connected to the starting square. Your aim is to make the whole grid the same colour, in as few moves as possible. The game will set a limit on the number of moves, based on running its own internal solver. You win if you can make the whole grid the same colour in that many moves or fewer. I saw this game (with a fixed grid size, fixed number of colours, and fixed move limit) at http://floodit.appspot.com (no longer accessible). 39.1 Flood controls To play Flood, click the mouse in a square. The top left corner and everything connected to it will be flood-filled with the colour of the square you clicked. Clicking a square the same colour as the top left corner has no effect, and therefore does not count as a move. You can also use the cursor keys to move a cursor (outline black square) around the grid. Pressing the return key will fill the top left corner in the colour of the square under the cursor. (All the actions described in section 2.1 are also available.) 39.2 Flood parameters These parameters are available from the `Custom...' option on the `Type' menu. _Width_, _Height_ Size of the grid, in squares. _Colours_ Number of colours used to fill the grid. Must be at least 3 (with two colours there would only be one legal move at any stage, hence no choice to make at all), and at most 10. _Extra moves permitted_ Controls the difficulty of the puzzle, by increasing the move limit. In each new grid, Flood will run an internal solver to generate its own solution, and then the value in this field will be added to the length of Flood's solution to generate the game's move limit. So a value of 0 requires you to be just as efficient as Flood's automated solver, and a larger value makes it easier. (Note that Flood's internal solver will not necessarily find the shortest possible solution, though I believe it's pretty close. For a real challenge, set this value to 0 and then try to solve a grid in _strictly fewer_ moves than the limit you're given!) Chapter 40: Tracks ------------------ You are given a grid of squares, some of which are filled with train tracks. You need to complete the track from A to B so that the rows and columns contain the same number of track segments as are indicated in the clues to the top and right of the grid. There are only straight and 90 degree curved rails, and the track may not cross itself. Tracks was contributed to this collection by James Harvey. 40.1 Tracks controls Left-clicking on an edge between two squares adds a track segment between the two squares. Right-clicking on an edge adds a cross on the edge, indicating no track is possible there. Left-clicking in a square adds a colour indicator showing that you know the square must contain a track, even if you don't know which edges it crosses yet. Right-clicking in a square adds a cross indicating it contains no track segment. Left- or right-dragging between squares allows you to lay a straight line of is-track or is-not-track indicators, useful for filling in rows or columns to match the clue. (All the actions described in section 2.1 are also available.) 40.2 Tracks parameters These parameters are available from the `Custom...' option on the `Type' menu. _Width_, _Height_ Size of the grid, in squares. _Difficulty_ Controls the difficulty of the generated puzzle: at Tricky level, you are required to make more deductions regarding disregarding moves that would lead to impossible crossings later. _Disallow consecutive 1 clues_ Controls whether the Tracks game generation permits two adjacent rows or columns to have a 1 clue, or permits the row or column of the track's endpoint to have a 1 clue. By default this is not permitted, to avoid long straight boring segments of track and make the games more twiddly and interesting. If you want to restore the possibility, turn this option off. Chapter 41: Palisade -------------------- You're given a grid of squares, some of which contain numbers. Your goal is to subdivide the grid into contiguous regions, all of the same (given) size, such that each square containing a number is adjacent to exactly that many edges (including those between the inside and the outside of the grid). Credit for this puzzle goes to Nikoli, who call it `Five Cells'. [22]. Palisade was contributed to this collection by Jonas Koelker. [22] http://nikoli.co.jp/en/puzzles/five_cells.html 41.1 Palisade controls Left-click to place an edge. Right-click to indicate `no edge'. Alternatively, the arrow keys will move a keyboard cursor. Holding Control while pressing an arrow key will place an edge. Press Shift- arrowkey to switch off an edge. Repeat an action to perform its inverse. (All the actions described in section 2.1 are also available.) 41.2 Palisade parameters These parameters are available from the `Custom...' option on the `Type' menu. _Width_, _Height_ Size of grid in squares. _Region size_ The size of the regions into which the grid must be subdivided. Appendix A: Licence ------------------- This software is copyright 2004-2014 Simon Tatham. Portions copyright Richard Boulton, James Harvey, Mike Pinna, Jonas Koelker, Dariusz Olszewski, Michael Schierl, Lambros Lambrou, Bernd Schmidt, Steffen Bauer, Lennard Sprong and Rogier Goossens. 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 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. [Simon Tatham's Portable Puzzle Collection, version 20170606.272beef] puzzles-20170606.272beef/HACKING0000644000175000017500000061557713115375151014702 0ustar simonsimonDeveloper documentation for Simon Tatham's puzzle collection ============================================================ This is a guide to the internal structure of Simon Tatham's Portable Puzzle Collection (henceforth referred to simply as `Puzzles'), for use by anyone attempting to implement a new puzzle or port to a new platform. This guide is believed correct as of r6190. Hopefully it will be updated along with the code in future, but if not, I've at least left this version number in here so you can figure out what's changed by tracking commit comments from there onwards. 1. Introduction --------------- The Puzzles code base is divided into four parts: a set of interchangeable front ends, a set of interchangeable back ends, a universal `middle end' which acts as a buffer between the two, and a bunch of miscellaneous utility functions. In the following sections I give some general discussion of each of these parts. 1.1. Front end -------------- The front end is the non-portable part of the code: it's the bit that you replace completely when you port to a different platform. So it's responsible for all system calls, all GUI interaction, and anything else platform-specific. The current front ends in the main code base are for Windows, GTK and MacOS X; I also know of a third-party front end for PalmOS. The front end contains main() or the local platform's equivalent. Top- level control over the application's execution flow belongs to the front end (it isn't, for example, a set of functions called by a universal main() somewhere else). The front end has complete freedom to design the GUI for any given port of Puzzles. There is no centralised mechanism for maintaining the menu layout, for example. This has a cost in consistency (when I _do_ want the same menu layout on more than one platform, I have to edit two pieces of code in parallel every time I make a change), but the advantage is that local GUI conventions can be conformed to and local constraints adapted to. For example, MacOS X has strict human interface guidelines which specify a different menu layout from the one I've used on Windows and GTK; there's nothing stopping the OS X front end from providing a menu layout consistent with those guidelines. Although the front end is mostly caller rather than the callee in its interactions with other parts of the code, it is required to implement a small API for other modules to call, mostly of drawing functions for games to use when drawing their graphics. The drawing API is documented in chapter 3; the other miscellaneous front end API functions are documented in section 4.34. 1.2. Back end ------------- A `back end', in this collection, is synonymous with a `puzzle'. Each back end implements a different game. At the top level, a back end is simply a data structure, containing a few constants (flag words, preferred pixel size) and a large number of function pointers. Back ends are almost invariably callee rather than caller, which means there's a limitation on what a back end can do on its own initiative. The persistent state in a back end is divided into a number of data structures, which are used for different purposes and therefore likely to be switched around, changed without notice, and otherwise updated by the rest of the code. It is important when designing a back end to put the right pieces of data into the right structures, or standard midend- provided features (such as Undo) may fail to work. The functions and variables provided in the back end data structure are documented in chapter 2. 1.3. Middle end --------------- Puzzles has a single and universal `middle end'. This code is common to all platforms and all games; it sits in between the front end and the back end and provides standard functionality everywhere. People adding new back ends or new front ends should generally not need to edit the middle end. On rare occasions there might be a change that can be made to the middle end to permit a new game to do something not currently anticipated by the middle end's present design; however, this is terribly easy to get wrong and should probably not be undertaken without consulting the primary maintainer (me). Patch submissions containing unannounced mid-end changes will be treated on their merits like any other patch; this is just a friendly warning that mid-end changes will need quite a lot of merits to make them acceptable. Functionality provided by the mid-end includes: - Maintaining a list of game state structures and moving back and forth along that list to provide Undo and Redo. - Handling timers (for move animations, flashes on completion, and in some cases actually timing the game). - Handling the container format of game IDs: receiving them, picking them apart into parameters, description and/or random seed, and so on. The game back end need only handle the individual parts of a game ID (encoded parameters and encoded game description); everything else is handled centrally by the mid-end. - Handling standard keystrokes and menu commands, such as `New Game', `Restart Game' and `Quit'. - Pre-processing mouse events so that the game back ends can rely on them arriving in a sensible order (no missing button-release events, no sudden changes of which button is currently pressed, etc). - Handling the dialog boxes which ask the user for a game ID. - Handling serialisation of entire games (for loading and saving a half-finished game to a disk file, or for handling application shutdown and restart on platforms such as PalmOS where state is expected to be saved). Thus, there's a lot of work done once by the mid-end so that individual back ends don't have to worry about it. All the back end has to do is cooperate in ensuring the mid-end can do its work properly. The API of functions provided by the mid-end to be called by the front end is documented in chapter 4. 1.4. Miscellaneous utilities ---------------------------- In addition to these three major structural components, the Puzzles code also contains a variety of utility modules usable by all of the above components. There is a set of functions to provide platform-independent random number generation; functions to make memory allocation easier; functions which implement a balanced tree structure to be used as necessary in complex algorithms; and a few other miscellaneous functions. All of these are documented in chapter 5. 1.5. Structure of this guide ---------------------------- There are a number of function call interfaces within Puzzles, and this guide will discuss each one in a chapter of its own. After that, chapter 6 discusses how to design new games, with some general design thoughts and tips. 2. Interface to the back end ---------------------------- This chapter gives a detailed discussion of the interface that each back end must implement. At the top level, each back end source file exports a single global symbol, which is a `const struct game' containing a large number of function pointers and a small amount of constant data. This structure is called by different names depending on what kind of platform the puzzle set is being compiled on: - On platforms such as Windows and GTK, which build a separate binary for each puzzle, the game structure in every back end has the same name, `thegame'; the front end refers directly to this name, so that compiling the same front end module against a different back end module builds a different puzzle. - On platforms such as MacOS X and PalmOS, which build all the puzzles into a single monolithic binary, the game structure in each back end must have a different name, and there's a helper module `list.c' (constructed automatically by the same Perl script that builds the Makefiles) which contains a complete list of those game structures. On the latter type of platform, source files may assume that the preprocessor symbol `COMBINED' has been defined. Thus, the usual code to declare the game structure looks something like this: #ifdef COMBINED #define thegame net /* or whatever this game is called */ #endif const struct game thegame = { /* lots of structure initialisation in here */ }; Game back ends must also internally define a number of data structures, for storing their various persistent state. This chapter will first discuss the nature and use of those structures, and then go on to give details of every element of the game structure. 2.1. Data structures -------------------- Each game is required to define four separate data structures. This section discusses each one and suggests what sorts of things need to be put in it. 2.1.1. `game_params' -------------------- The `game_params' structure contains anything which affects the automatic generation of new puzzles. So if puzzle generation is parametrised in any way, those parameters need to be stored in `game_params'. Most puzzles currently in this collection are played on a grid of squares, meaning that the most obvious parameter is the grid size. Many puzzles have additional parameters; for example, Mines allows you to control the number of mines in the grid independently of its size, Net can be wrapping or non-wrapping, Solo has difficulty levels and symmetry settings, and so on. A simple rule for deciding whether a data item needs to go in `game_params' is: would the user expect to be able to control this data item from either the preset-game-types menu or the `Custom' game type configuration? If so, it's part of `game_params'. `game_params' structures are permitted to contain pointers to subsidiary data if they need to. The back end is required to provide functions to create and destroy `game_params', and those functions can allocate and free additional memory if necessary. (It has not yet been necessary to do this in any puzzle so far, but the capability is there just in case.) `game_params' is also the only structure which the game's compute_size() function may refer to; this means that any aspect of the game which affects the size of the window it needs to be drawn in must be stored in `game_params'. In particular, this imposes the fundamental limitation that random game generation may not have a random effect on the window size: game generation algorithms are constrained to work by starting from the grid size rather than generating it as an emergent phenomenon. (Although this is a restriction in theory, it has not yet seemed to be a problem.) 2.1.2. `game_state' ------------------- While the user is actually playing a puzzle, the `game_state' structure stores all the data corresponding to the current state of play. The mid-end keeps `game_state's in a list, and adds to the list every time the player makes a move; the Undo and Redo functions step back and forth through that list. Therefore, a good means of deciding whether a data item needs to go in `game_state' is: would a player expect that data item to be restored on undo? If so, put it in `game_state', and this will automatically happen without you having to lift a finger. If not - for example, the deaths counter in Mines is precisely something that does _not_ want to be reset to its previous state on an undo - then you might have found a data item that needs to go in `game_ui' instead. During play, `game_state's are often passed around without an accompanying `game_params' structure. Therefore, any information in `game_params' which is important during play (such as the grid size) must be duplicated within the `game_state'. One simple method of doing this is to have the `game_state' structure _contain_ a `game_params' structure as one of its members, although this isn't obligatory if you prefer to do it another way. 2.1.3. `game_drawstate' ----------------------- `game_drawstate' carries persistent state relating to the current graphical contents of the puzzle window. The same `game_drawstate' is passed to every call to the game redraw function, so that it can remember what it has already drawn and what needs redrawing. A typical use for a `game_drawstate' is to have an array mirroring the array of grid squares in the `game_state'; then every time the redraw function was passed a `game_state', it would loop over all the squares, and physically redraw any whose description in the `game_state' (i.e. what the square needs to look like when the redraw is completed) did not match its description in the `game_drawstate' (i.e. what the square currently looks like). `game_drawstate' is occasionally completely torn down and reconstructed by the mid-end, if the user somehow forces a full redraw. Therefore, no data should be stored in `game_drawstate' which is _not_ related to the state of the puzzle window, because it might be unexpectedly destroyed. The back end provides functions to create and destroy `game_drawstate', which means it can contain pointers to subsidiary allocated data if it needs to. A common thing to want to allocate in a `game_drawstate' is a `blitter'; see section 3.1.13 for more on this subject. 2.1.4. `game_ui' ---------------- `game_ui' contains whatever doesn't fit into the above three structures! A new `game_ui' is created when the user begins playing a new instance of a puzzle (i.e. during `New Game' or after entering a game ID etc). It persists until the user finishes playing that game and begins another one (or closes the window); in particular, `Restart Game' does _not_ destroy the `game_ui'. `game_ui' is useful for implementing user-interface state which is not part of `game_state'. Common examples are keyboard control (you wouldn't want to have to separately Undo through every cursor motion) and mouse dragging. See section 6.3.2 and section 6.3.3, respectively, for more details. Another use for `game_ui' is to store highly persistent data such as the Mines death counter. This is conceptually rather different: where the Net cursor position was _not important enough_ to preserve for the player to restore by Undo, the Mines death counter is _too important_ to permit the player to revert by Undo! A final use for `game_ui' is to pass information to the redraw function about recent changes to the game state. This is used in Mines, for example, to indicate whether a requested `flash' should be a white flash for victory or a red flash for defeat; see section 6.3.5. 2.2. Simple data in the back end -------------------------------- In this section I begin to discuss each individual element in the back end structure. To begin with, here are some simple self-contained data elements. 2.2.1. `name' ------------- const char *name; This is a simple ASCII string giving the name of the puzzle. This name will be used in window titles, in game selection menus on monolithic platforms, and anywhere else that the front end needs to know the name of a game. 2.2.2. `winhelp_topic' ---------------------- const char *winhelp_topic; This member is used on Windows only, to provide online help. Although the Windows front end provides a separate binary for each puzzle, it has a single monolithic help file; so when a user selects `Help' from the menu, the program needs to open the help file and jump to the chapter describing that particular puzzle. Therefore, each chapter in `puzzles.but' is labelled with a _help topic_ name, similar to this: \cfg{winhelp-topic}{games.net} And then the corresponding game back end encodes the topic string (here `games.net') in the `winhelp_topic' element of the game structure. 2.3. Handling game parameter sets --------------------------------- In this section I present the various functions which handle the `game_params' structure. 2.3.1. default_params() ----------------------- game_params *(*default_params)(void); This function allocates a new `game_params' structure, fills it with the default values, and returns a pointer to it. 2.3.2. fetch_preset() --------------------- int (*fetch_preset)(int i, char **name, game_params **params); This function is one of the two APIs a back end can provide to populate the `Type' menu, which provides a list of conveniently accessible preset parameters for most games. The function is called with `i' equal to the index of the preset required (numbering from zero). It returns FALSE if that preset does not exist (if `i' is less than zero or greater than the largest preset index). Otherwise, it sets `*params' to point at a newly allocated `game_params' structure containing the preset information, sets `*name' to point at a newly allocated C string containing the preset title (to go on the `Type' menu), and returns TRUE. If the game does not wish to support any presets at all, this function is permitted to return FALSE always. If the game wants to return presets in the form of a hierarchical menu instead of a flat list (and, indeed, even if it doesn't), then it may set this function pointer to NULL, and instead fill in the alternative function pointer preset_menu (section 2.3.3). 2.3.3. preset_menu() -------------------- struct preset_menu *(*preset_menu)(void); This function is the more flexible of the two APIs by which a back end can define a collection of preset game parameters. This function simply returns a complete menu hierarchy, in the form of a `struct preset_menu' (see section 4.15) and further submenus (if it wishes) dangling off it. There are utility functions described in section 5.2 to make it easy for the back end to construct this menu. If the game has no need to return a hierarchy of menus, it may instead opt to implement the fetch_preset() function (see section 2.3.2). The game need not fill in the `id' fields in the preset menu structures. The mid-end will do that after it receives the structure from the game, and before passing it on to the front end. 2.3.4. encode_params() ---------------------- char *(*encode_params)(const game_params *params, int full); The job of this function is to take a `game_params', and encode it in a string form for use in game IDs. The return value must be a newly allocated C string, and _must_ not contain a colon or a hash (since those characters are used to mark the end of the parameter section in a game ID). Ideally, it should also not contain any other potentially controversial punctuation; bear in mind when designing a string parameter format that it will probably be used on both Windows and Unix command lines under a variety of exciting shell quoting and metacharacter rules. Sticking entirely to alphanumerics is the safest thing; if you really need punctuation, you can probably get away with commas, periods or underscores without causing anybody any major inconvenience. If you venture far beyond that, you're likely to irritate _somebody_. (At the time of writing this, all existing games have purely alphanumeric string parameter formats. Usually these involve a letter denoting a parameter, followed optionally by a number giving the value of that parameter, with a few mandatory parts at the beginning such as numeric width and height separated by `x'.) If the `full' parameter is TRUE, this function should encode absolutely everything in the `game_params', such that a subsequent call to decode_params() (section 2.3.5) will yield an identical structure. If `full' is FALSE, however, you should leave out anything which is not necessary to describe a _specific puzzle instance_, i.e. anything which only takes effect when a new puzzle is _generated_. For example, the Solo `game_params' includes a difficulty rating used when constructing new puzzles; but a Solo game ID need not explicitly include the difficulty, since to describe a puzzle once generated it's sufficient to give the grid dimensions and the location and contents of the clue squares. (Indeed, one might very easily type in a puzzle out of a newspaper without _knowing_ what its difficulty level is in Solo's terminology.) Therefore, Solo's encode_params() only encodes the difficulty level if `full' is set. 2.3.5. decode_params() ---------------------- void (*decode_params)(game_params *params, char const *string); This function is the inverse of encode_params() (section 2.3.4). It parses the supplied string and fills in the supplied `game_params' structure. Note that the structure will _already_ have been allocated: this function is not expected to create a _new_ `game_params', but to modify an existing one. This function can receive a string which only encodes a subset of the parameters. The most obvious way in which this can happen is if the string was constructed by encode_params() with its `full' parameter set to FALSE; however, it could also happen if the user typed in a parameter set manually and missed something out. Be prepared to deal with a wide range of possibilities. When dealing with a parameter which is not specified in the input string, what to do requires a judgment call on the part of the programmer. Sometimes it makes sense to adjust other parameters to bring them into line with the new ones. In Mines, for example, you would probably not want to keep the same mine count if the user dropped the grid size and didn't specify one, since you might easily end up with more mines than would actually fit in the grid! On the other hand, sometimes it makes sense to leave the parameter alone: a Solo player might reasonably expect to be able to configure size and difficulty independently of one another. This function currently has no direct means of returning an error if the string cannot be parsed at all. However, the returned `game_params' is almost always subsequently passed to validate_params() (section 2.3.11), so if you really want to signal parse errors, you could always have a `char *' in your parameters structure which stored an error message, and have validate_params() return it if it is non-NULL. 2.3.6. free_params() -------------------- void (*free_params)(game_params *params); This function frees a `game_params' structure, and any subsidiary allocations contained within it. 2.3.7. dup_params() ------------------- game_params *(*dup_params)(const game_params *params); This function allocates a new `game_params' structure and initialises it with an exact copy of the information in the one provided as input. It returns a pointer to the new duplicate. 2.3.8. `can_configure' ---------------------- int can_configure; This boolean data element is set to TRUE if the back end supports custom parameter configuration via a dialog box. If it is TRUE, then the functions configure() and custom_params() are expected to work. See section 2.3.9 and section 2.3.10 for more details. 2.3.9. configure() ------------------ config_item *(*configure)(const game_params *params); This function is called when the user requests a dialog box for custom parameter configuration. It returns a newly allocated array of config_item structures, describing the GUI elements required in the dialog box. The array should have one more element than the number of controls, since it is terminated with a C_END marker (see below). Each array element describes the control together with its initial value; the front end will modify the value fields and return the updated array to custom_params() (see section 2.3.10). The config_item structure contains the following elements: char *name; int type; char *sval; int ival; `name' is an ASCII string giving the textual label for a GUI control. It is _not_ expected to be dynamically allocated. `type' contains one of a small number of `enum' values defining what type of control is being described. The meaning of the `sval' and `ival' fields depends on the value in `type'. The valid values are: `C_STRING' Describes a text input box. (This is also used for numeric input. The back end does not bother informing the front end that the box is numeric rather than textual; some front ends do have the capacity to take this into account, but I decided it wasn't worth the extra complexity in the interface.) For this type, `ival' is unused, and `sval' contains a dynamically allocated string representing the contents of the input box. `C_BOOLEAN' Describes a simple checkbox. For this type, `sval' is unused, and `ival' is TRUE or FALSE. `C_CHOICES' Describes a drop-down list presenting one of a small number of fixed choices. For this type, `sval' contains a list of strings describing the choices; the very first character of `sval' is used as a delimiter when processing the rest (so that the strings `:zero:one:two', `!zero!one!two' and `xzeroxonextwo' all define a three-element list containing `zero', `one' and `two'). `ival' contains the index of the currently selected element, numbering from zero (so that in the above example, 0 would mean `zero' and 2 would mean `two'). Note that for this control type, `sval' is _not_ dynamically allocated, whereas it was for `C_STRING'. `C_END' Marks the end of the array of `config_item's. All other fields are unused. The array returned from this function is expected to have filled in the initial values of all the controls according to the input `game_params' structure. If the game's `can_configure' flag is set to FALSE, this function is never called and need not do anything at all. 2.3.10. custom_params() ----------------------- game_params *(*custom_params)(const config_item *cfg); This function is the counterpart to configure() (section 2.3.9). It receives as input an array of `config_item's which was originally created by configure(), but in which the control values have since been changed in accordance with user input. Its function is to read the new values out of the controls and return a newly allocated `game_params' structure representing the user's chosen parameter set. (The front end will have modified the controls' _values_, but there will still always be the same set of controls, in the same order, as provided by configure(). It is not necessary to check the `name' and `type' fields, although you could use assert() if you were feeling energetic.) This function is not expected to (and indeed _must not_) free the input `config_item' array. (If the parameters fail to validate, the dialog box will stay open.) If the game's `can_configure' flag is set to FALSE, this function is never called and need not do anything at all. 2.3.11. validate_params() ------------------------- char *(*validate_params)(const game_params *params, int full); This function takes a `game_params' structure as input, and checks that the parameters described in it fall within sensible limits. (At the very least, grid dimensions should almost certainly be strictly positive, for example.) Return value is NULL if no problems were found, or alternatively a (non- dynamically-allocated) ASCII string describing the error in human- readable form. If the `full' parameter is set, full validation should be performed: any set of parameters which would not permit generation of a sensible puzzle should be faulted. If `full' is _not_ set, the implication is that these parameters are not going to be used for _generating_ a puzzle; so parameters which can't even sensibly _describe_ a valid puzzle should still be faulted, but parameters which only affect puzzle generation should not be. (The `full' option makes a difference when parameter combinations are non-orthogonal. For example, Net has a boolean option controlling whether it enforces a unique solution; it turns out that it's impossible to generate a uniquely soluble puzzle with wrapping walls and width 2, so validate_params() will complain if you ask for one. However, if the user had just been playing a unique wrapping puzzle of a more sensible width, and then pastes in a game ID acquired from somebody else which happens to describe a _non_-unique wrapping width-2 puzzle, then validate_params() will be passed a `game_params' containing the width and wrapping settings from the new game ID and the uniqueness setting from the old one. This would be faulted, if it weren't for the fact that `full' is not set during this call, so Net ignores the inconsistency. The resulting `game_params' is never subsequently used to generate a puzzle; this is a promise made by the mid-end when it asks for a non- full validation.) 2.4. Handling game descriptions ------------------------------- In this section I present the functions that deal with a textual description of a puzzle, i.e. the part that comes after the colon in a descriptive-format game ID. 2.4.1. new_desc() ----------------- char *(*new_desc)(const game_params *params, random_state *rs, char **aux, int interactive); This function is where all the really hard work gets done. This is the function whose job is to randomly generate a new puzzle, ensuring solubility and uniqueness as appropriate. As input it is given a `game_params' structure and a random state (see section 5.1 for the random number API). It must invent a puzzle instance, encode it in string form, and return a dynamically allocated C string containing that encoding. Additionally, it may return a second dynamically allocated string in `*aux'. (If it doesn't want to, then it can leave that parameter completely alone; it isn't required to set it to NULL, although doing so is harmless.) That string, if present, will be passed to solve() (section 2.7.4) later on; so if the puzzle is generated in such a way that a solution is known, then information about that solution can be saved in `*aux' for solve() to use. The `interactive' parameter should be ignored by almost all puzzles. Its purpose is to distinguish between generating a puzzle within a GUI context for immediate play, and generating a puzzle in a command-line context for saving to be played later. The only puzzle that currently uses this distinction (and, I fervently hope, the only one which will _ever_ need to use it) is Mines, which chooses a random first-click location when generating puzzles non-interactively, but which waits for the user to place the first click when interactive. If you think you have come up with another puzzle which needs to make use of this parameter, please think for at least ten minutes about whether there is _any_ alternative! Note that game description strings are not required to contain an encoding of parameters such as grid size; a game description is never separated from the `game_params' it was generated with, so any information contained in that structure need not be encoded again in the game description. 2.4.2. validate_desc() ---------------------- char *(*validate_desc)(const game_params *params, const char *desc); This function is given a game description, and its job is to validate that it describes a puzzle which makes sense. To some extent it's up to the user exactly how far they take the phrase `makes sense'; there are no particularly strict rules about how hard the user is permitted to shoot themself in the foot when typing in a bogus game description by hand. (For example, Rectangles will not verify that the sum of all the numbers in the grid equals the grid's area. So a user could enter a puzzle which was provably not soluble, and the program wouldn't complain; there just wouldn't happen to be any sequence of moves which solved it.) The one non-negotiable criterion is that any game description which makes it through validate_desc() _must not_ subsequently cause a crash or an assertion failure when fed to new_game() and thence to the rest of the back end. The return value is NULL on success, or a non-dynamically-allocated C string containing an error message. 2.4.3. new_game() ----------------- game_state *(*new_game)(midend *me, const game_params *params, const char *desc); This function takes a game description as input, together with its accompanying `game_params', and constructs a `game_state' describing the initial state of the puzzle. It returns a newly allocated `game_state' structure. Almost all puzzles should ignore the `me' parameter. It is required by Mines, which needs it for later passing to midend_supersede_game_desc() (see section 2.11.2) once the user has placed the first click. I fervently hope that no other puzzle will be awkward enough to require it, so everybody else should ignore it. As with the `interactive' parameter in new_desc() (section 2.4.1), if you think you have a reason to need this parameter, please try very hard to think of an alternative approach! 2.5. Handling game states ------------------------- This section describes the functions which create and destroy `game_state' structures. (Well, except new_game(), which is in section 2.4.3 instead of under here; but it deals with game descriptions _and_ game states and it had to go in one section or the other.) 2.5.1. dup_game() ----------------- game_state *(*dup_game)(const game_state *state); This function allocates a new `game_state' structure and initialises it with an exact copy of the information in the one provided as input. It returns a pointer to the new duplicate. 2.5.2. free_game() ------------------ void (*free_game)(game_state *state); This function frees a `game_state' structure, and any subsidiary allocations contained within it. 2.6. Handling `game_ui' ----------------------- 2.6.1. new_ui() --------------- game_ui *(*new_ui)(const game_state *state); This function allocates and returns a new `game_ui' structure for playing a particular puzzle. It is passed a pointer to the initial `game_state', in case it needs to refer to that when setting up the initial values for the new game. 2.6.2. free_ui() ---------------- void (*free_ui)(game_ui *ui); This function frees a `game_ui' structure, and any subsidiary allocations contained within it. 2.6.3. encode_ui() ------------------ char *(*encode_ui)(const game_ui *ui); This function encodes any _important_ data in a `game_ui' structure in string form. It is only called when saving a half-finished game to a file. It should be used sparingly. Almost all data in a `game_ui' is not important enough to save. The location of the keyboard-controlled cursor, for example, can be reset to a default position on reloading the game without impacting the user experience. If the user should somehow manage to save a game while a mouse drag was in progress, then discarding that mouse drag would be an outright _feature_. A typical thing that _would_ be worth encoding in this function is the Mines death counter: it's in the `game_ui' rather than the `game_state' because it's too important to allow the user to revert it by using Undo, and therefore it's also too important to allow the user to revert it by saving and reloading. (Of course, the user could edit the save file by hand... But if the user is _that_ determined to cheat, they could just as easily modify the game's source.) 2.6.4. decode_ui() ------------------ void (*decode_ui)(game_ui *ui, const char *encoding); This function parses a string previously output by encode_ui(), and writes the decoded data back into the provided `game_ui' structure. 2.6.5. changed_state() ---------------------- void (*changed_state)(game_ui *ui, const game_state *oldstate, const game_state *newstate); This function is called by the mid-end whenever the current game state changes, for any reason. Those reasons include: - a fresh move being made by interpret_move() and execute_move() - a solve operation being performed by solve() and execute_move() - the user moving back and forth along the undo list by means of the Undo and Redo operations - the user selecting Restart to go back to the initial game state. The job of changed_state() is to update the `game_ui' for consistency with the new game state, if any update is necessary. For example, Same Game stores data about the currently selected tile group in its `game_ui', and this data is intrinsically related to the game state it was derived from. So it's very likely to become invalid when the game state changes; thus, Same Game's changed_state() function clears the current selection whenever it is called. When anim_length() or flash_length() are called, you can be sure that there has been a previous call to changed_state(). So changed_state() can set up data in the `game_ui' which will be read by anim_length() and flash_length(), and those functions will not have to worry about being called without the data having been initialised. 2.7. Making moves ----------------- This section describes the functions which actually make moves in the game: that is, the functions which process user input and end up producing new `game_state's. 2.7.1. interpret_move() ----------------------- char *(*interpret_move)(const game_state *state, game_ui *ui, const game_drawstate *ds, int x, int y, int button); This function receives user input and processes it. Its input parameters are the current `game_state', the current `game_ui' and the current `game_drawstate', plus details of the input event. `button' is either an ASCII value or a special code (listed below) indicating an arrow or function key or a mouse event; when `button' is a mouse event, `x' and `y' contain the pixel coordinates of the mouse pointer relative to the top left of the puzzle's drawing area. (The pointer to the `game_drawstate' is marked `const', because `interpret_move' should not write to it. The normal use of that pointer will be to read the game's tile size parameter in order to divide mouse coordinates by it.) interpret_move() may return in three different ways: - Returning NULL indicates that no action whatsoever occurred in response to the input event; the puzzle was not interested in it at all. - Returning the empty string ("") indicates that the input event has resulted in a change being made to the `game_ui' which will require a redraw of the game window, but that no actual _move_ was made (i.e. no new `game_state' needs to be created). - Returning anything else indicates that a move was made and that a new `game_state' must be created. However, instead of actually constructing a new `game_state' itself, this function is required to return a string description of the details of the move. This string will be passed to execute_move() (section 2.7.2) to actually create the new `game_state'. (Encoding moves as strings in this way means that the mid-end can keep the strings as well as the game states, and the strings can be written to disk when saving the game and fed to execute_move() again on reloading.) The return value from interpret_move() is expected to be dynamically allocated if and only if it is not either NULL _or_ the empty string. After this function is called, the back end is permitted to rely on some subsequent operations happening in sequence: - execute_move() will be called to convert this move description into a new `game_state' - changed_state() will be called with the new `game_state'. This means that if interpret_move() needs to do updates to the `game_ui' which are easier to perform by referring to the new `game_state', it can safely leave them to be done in changed_state() and not worry about them failing to happen. (Note, however, that execute_move() may _also_ be called in other circumstances. It is only interpret_move() which can rely on a subsequent call to changed_state().) The special key codes supported by this function are: LEFT_BUTTON, MIDDLE_BUTTON, RIGHT_BUTTON Indicate that one of the mouse buttons was pressed down. LEFT_DRAG, MIDDLE_DRAG, RIGHT_DRAG Indicate that the mouse was moved while one of the mouse buttons was still down. The mid-end guarantees that when one of these events is received, it will always have been preceded by a button-down event (and possibly other drag events) for the same mouse button, and no event involving another mouse button will have appeared in between. LEFT_RELEASE, MIDDLE_RELEASE, RIGHT_RELEASE Indicate that a mouse button was released. The mid-end guarantees that when one of these events is received, it will always have been preceded by a button-down event (and possibly some drag events) for the same mouse button, and no event involving another mouse button will have appeared in between. CURSOR_UP, CURSOR_DOWN, CURSOR_LEFT, CURSOR_RIGHT Indicate that an arrow key was pressed. CURSOR_SELECT On platforms which have a prominent `select' button alongside their cursor keys, indicates that that button was pressed. In addition, there are some modifiers which can be bitwise-ORed into the `button' parameter: MOD_CTRL, MOD_SHFT These indicate that the Control or Shift key was pressed alongside the key. They only apply to the cursor keys, not to mouse buttons or anything else. MOD_NUM_KEYPAD This applies to some ASCII values, and indicates that the key code was input via the numeric keypad rather than the main keyboard. Some puzzles may wish to treat this differently (for example, a puzzle might want to use the numeric keypad as an eight-way directional pad), whereas others might not (a game involving numeric input probably just wants to treat the numeric keypad as numbers). MOD_MASK This mask is the bitwise OR of all the available modifiers; you can bitwise-AND with ~MOD_MASK to strip all the modifiers off any input value. 2.7.2. execute_move() --------------------- game_state *(*execute_move)(const game_state *state, char *move); This function takes an input `game_state' and a move string as output from interpret_move(). It returns a newly allocated `game_state' which contains the result of applying the specified move to the input game state. This function may return NULL if it cannot parse the move string (and this is definitely preferable to crashing or failing an assertion, since one way this can happen is if loading a corrupt save file). However, it must not return NULL for any move string that really was output from interpret_move(): this is punishable by assertion failure in the mid- end. 2.7.3. `can_solve' ------------------ int can_solve; This boolean field is set to TRUE if the game's solve() function does something. If it's set to FALSE, the game will not even offer the `Solve' menu option. 2.7.4. solve() -------------- char *(*solve)(const game_state *orig, const game_state *curr, const char *aux, char **error); This function is called when the user selects the `Solve' option from the menu. It is passed two input game states: `orig' is the game state from the very start of the puzzle, and `curr' is the current one. (Different games find one or other or both of these convenient.) It is also passed the `aux' string saved by new_desc() (section 2.4.1), in case that encodes important information needed to provide the solution. If this function is unable to produce a solution (perhaps, for example, the game has no in-built solver so it can only solve puzzles it invented internally and has an `aux' string for) then it may return NULL. If it does this, it must also set `*error' to an error message to be presented to the user (such as `Solution not known for this puzzle'); that error message is not expected to be dynamically allocated. If this function _does_ produce a solution, it returns a move string suitable for feeding to execute_move() (section 2.7.2). Like a (non- empty) string returned from interpret_move(), the returned string should be dynamically allocated. 2.8. Drawing the game graphics ------------------------------ This section discusses the back end functions that deal with drawing. 2.8.1. new_drawstate() ---------------------- game_drawstate *(*new_drawstate)(drawing *dr, const game_state *state); This function allocates and returns a new `game_drawstate' structure for drawing a particular puzzle. It is passed a pointer to a `game_state', in case it needs to refer to that when setting up any initial data. This function may not rely on the puzzle having been newly started; a new draw state can be constructed at any time if the front end requests a forced redraw. For games like Pattern, in which initial game states are much simpler than general ones, this might be important to keep in mind. The parameter `dr' is a drawing object (see chapter 3) which the function might need to use to allocate blitters. (However, this isn't recommended; it's usually more sensible to wait to allocate a blitter until set_size() is called, because that way you can tailor it to the scale at which the puzzle is being drawn.) 2.8.2. free_drawstate() ----------------------- void (*free_drawstate)(drawing *dr, game_drawstate *ds); This function frees a `game_drawstate' structure, and any subsidiary allocations contained within it. The parameter `dr' is a drawing object (see chapter 3), which might be required if you are freeing a blitter. 2.8.3. `preferred_tilesize' --------------------------- int preferred_tilesize; Each game is required to define a single integer parameter which expresses, in some sense, the scale at which it is drawn. This is described in the APIs as `tilesize', since most puzzles are on a square (or possibly triangular or hexagonal) grid and hence a sensible interpretation of this parameter is to define it as the size of one grid tile in pixels; however, there's no actual requirement that the `tile size' be proportional to the game window size. Window size is required to increase monotonically with `tile size', however. The data element `preferred_tilesize' indicates the tile size which should be used in the absence of a good reason to do otherwise (such as the screen being too small, or the user explicitly requesting a resize if that ever gets implemented). 2.8.4. compute_size() --------------------- void (*compute_size)(const game_params *params, int tilesize, int *x, int *y); This function is passed a `game_params' structure and a tile size. It returns, in `*x' and `*y', the size in pixels of the drawing area that would be required to render a puzzle with those parameters at that tile size. 2.8.5. set_size() ----------------- void (*set_size)(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize); This function is responsible for setting up a `game_drawstate' to draw at a given tile size. Typically this will simply involve copying the supplied `tilesize' parameter into a `tilesize' field inside the draw state; for some more complex games it might also involve setting up other dimension fields, or possibly allocating a blitter (see section 3.1.13). The parameter `dr' is a drawing object (see chapter 3), which is required if a blitter needs to be allocated. Back ends may assume (and may enforce by assertion) that this function will be called at most once for any `game_drawstate'. If a puzzle needs to be redrawn at a different size, the mid-end will create a fresh drawstate. 2.8.6. colours() ---------------- float *(*colours)(frontend *fe, int *ncolours); This function is responsible for telling the front end what colours the puzzle will need to draw itself. It returns the number of colours required in `*ncolours', and the return value from the function itself is a dynamically allocated array of three times that many `float's, containing the red, green and blue components of each colour respectively as numbers in the range [0,1]. The second parameter passed to this function is a front end handle. The only things it is permitted to do with this handle are to call the front-end function called frontend_default_colour() (see section 4.39) or the utility function called game_mkhighlight() (see section 5.5.7). (The latter is a wrapper on the former, so front end implementors only need to provide frontend_default_colour().) This allows colours() to take local configuration into account when deciding on its own colour allocations. Most games use the front end's default colour as their background, apart from a few which depend on drawing relief highlights so they adjust the background colour if it's too light for highlights to show up against it. Note that the colours returned from this function are for _drawing_, not for printing. Printing has an entirely different colour allocation policy. 2.8.7. anim_length() -------------------- float (*anim_length)(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui); This function is called when a move is made, undone or redone. It is given the old and the new `game_state', and its job is to decide whether the transition between the two needs to be animated or can be instant. `oldstate' is the state that was current until this call; `newstate' is the state that will be current after it. `dir' specifies the chronological order of those states: if it is positive, then the transition is the result of a move or a redo (and so `newstate' is the later of the two moves), whereas if it is negative then the transition is the result of an undo (so that `newstate' is the _earlier_ move). If this function decides the transition should be animated, it returns the desired length of the animation in seconds. If not, it returns zero. State changes as a result of a Restart operation are never animated; the mid-end will handle them internally and never consult this function at all. State changes as a result of Solve operations are also not animated by default, although you can change this for a particular game by setting a flag in `flags' (section 2.10.7). The function is also passed a pointer to the local `game_ui'. It may refer to information in here to help with its decision (see section 6.3.7 for an example of this), and/or it may _write_ information about the nature of the animation which will be read later by redraw(). When this function is called, it may rely on changed_state() having been called previously, so if anim_length() needs to refer to information in the `game_ui', then changed_state() is a reliable place to have set that information up. Move animations do not inhibit further input events. If the user continues playing before a move animation is complete, the animation will be abandoned and the display will jump straight to the final state. 2.8.8. flash_length() --------------------- float (*flash_length)(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui); This function is called when a move is completed. (`Completed' means that not only has the move been made, but any animation which accompanied it has finished.) It decides whether the transition from `oldstate' to `newstate' merits a `flash'. A flash is much like a move animation, but it is _not_ interrupted by further user interface activity; it runs to completion in parallel with whatever else might be going on on the display. The only thing which will rush a flash to completion is another flash. The purpose of flashes is to indicate that the game has been completed. They were introduced as a separate concept from move animations because of Net: the habit of most Net players (and certainly me) is to rotate a tile into place and immediately lock it, then move on to another tile. When you make your last move, at the instant the final tile is rotated into place the screen starts to flash to indicate victory - but if you then press the lock button out of habit, then the move animation is cancelled, and the victory flash does not complete. (And if you _don't_ press the lock button, the completed grid will look untidy because there will be one unlocked square.) Therefore, I introduced a specific concept of a `flash' which is separate from a move animation and can proceed in parallel with move animations and any other display activity, so that the victory flash in Net is not cancelled by that final locking move. The input parameters to flash_length() are exactly the same as the ones to anim_length(). Just like anim_length(), when this function is called, it may rely on changed_state() having been called previously, so if it needs to refer to information in the `game_ui' then changed_state() is a reliable place to have set that information up. (Some games use flashes to indicate defeat as well as victory; Mines, for example, flashes in a different colour when you tread on a mine from the colour it uses when you complete the game. In order to achieve this, its flash_length() function has to store a flag in the `game_ui' to indicate which flash type is required.) 2.8.9. status() --------------- int (*status)(const game_state *state); This function returns a status value indicating whether the current game is still in play, or has been won, or has been conclusively lost. The mid-end uses this to implement midend_status() (section 4.26). The return value should be +1 if the game has been successfully solved. If the game has been lost in a situation where further play is unlikely, the return value should be -1. If neither is true (so play is still ongoing), return zero. Front ends may wish to use a non-zero status as a cue to proactively offer the option of starting a new game. Therefore, back ends should not return -1 if the game has been _technically_ lost but undoing and continuing is still a realistic possibility. (For instance, games with hidden information such as Guess or Mines might well return a non-zero status whenever they reveal the solution, whether or not the player guessed it correctly, on the grounds that a player would be unlikely to hide the solution and continue playing after the answer was spoiled. On the other hand, games where you can merely get into a dead end such as Same Game or Inertia might choose to return 0 in that situation, on the grounds that the player would quite likely press Undo and carry on playing.) 2.8.10. redraw() ---------------- void (*redraw)(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *newstate, int dir, const game_ui *ui, float anim_time, float flash_time); This function is responsible for actually drawing the contents of the game window, and for redrawing every time the game state or the `game_ui' changes. The parameter `dr' is a drawing object which may be passed to the drawing API functions (see chapter 3 for documentation of the drawing API). This function may not save `dr' and use it elsewhere; it must only use it for calling back to the drawing API functions within its own lifetime. `ds' is the local `game_drawstate', of course, and `ui' is the local `game_ui'. `newstate' is the semantically-current game state, and is always non- NULL. If `oldstate' is also non-NULL, it means that a move has recently been made and the game is still in the process of displaying an animation linking the old and new states; in this situation, `anim_time' will give the length of time (in seconds) that the animation has already been running. If `oldstate' is NULL, then `anim_time' is unused (and will hopefully be set to zero to avoid confusion). `flash_time', if it is is non-zero, denotes that the game is in the middle of a flash, and gives the time since the start of the flash. See section 2.8.8 for general discussion of flashes. The very first time this function is called for a new `game_drawstate', it is expected to redraw the _entire_ drawing area. Since this often involves drawing visual furniture which is never subsequently altered, it is often simplest to arrange this by having a special `first time' flag in the draw state, and resetting it after the first redraw. When this function (or any subfunction) calls the drawing API, it is expected to pass colour indices which were previously defined by the colours() function. 2.9. Printing functions ----------------------- This section discusses the back end functions that deal with printing puzzles out on paper. 2.9.1. `can_print' ------------------ int can_print; This flag is set to TRUE if the puzzle is capable of printing itself on paper. (This makes sense for some puzzles, such as Solo, which can be filled in with a pencil. Other puzzles, such as Twiddle, inherently involve moving things around and so would not make sense to print.) If this flag is FALSE, then the functions print_size() and print() will never be called. 2.9.2. `can_print_in_colour' ---------------------------- int can_print_in_colour; This flag is set to TRUE if the puzzle is capable of printing itself differently when colour is available. For example, Map can actually print coloured regions in different _colours_ rather than resorting to cross-hatching. If the `can_print' flag is FALSE, then this flag will be ignored. 2.9.3. print_size() ------------------- void (*print_size)(const game_params *params, float *x, float *y); This function is passed a `game_params' structure and a tile size. It returns, in `*x' and `*y', the preferred size in _millimetres_ of that puzzle if it were to be printed out on paper. If the `can_print' flag is FALSE, this function will never be called. 2.9.4. print() -------------- void (*print)(drawing *dr, const game_state *state, int tilesize); This function is called when a puzzle is to be printed out on paper. It should use the drawing API functions (see chapter 3) to print itself. This function is separate from redraw() because it is often very different: - The printing function may not depend on pixel accuracy, since printer resolution is variable. Draw as if your canvas had infinite resolution. - The printing function sometimes needs to display things in a completely different style. Net, for example, is very different as an on-screen puzzle and as a printed one. - The printing function is often much simpler since it has no need to deal with repeated partial redraws. However, there's no reason the printing and redraw functions can't share some code if they want to. When this function (or any subfunction) calls the drawing API, the colour indices it passes should be colours which have been allocated by the print_*_colour() functions within this execution of print(). This is very different from the fixed small number of colours used in redraw(), because printers do not have a limitation on the total number of colours that may be used. Some puzzles' printing functions might wish to allocate only one `ink' colour and use it for all drawing; others might wish to allocate _more_ colours than are used on screen. One possible colour policy worth mentioning specifically is that a puzzle's printing function might want to allocate the _same_ colour indices as are used by the redraw function, so that code shared between drawing and printing does not have to keep switching its colour indices. In order to do this, the simplest thing is to make use of the fact that colour indices returned from print_*_colour() are guaranteed to be in increasing order from zero. So if you have declared an `enum' defining three colours COL_BACKGROUND, COL_THIS and COL_THAT, you might then write int c; c = print_mono_colour(dr, 1); assert(c == COL_BACKGROUND); c = print_mono_colour(dr, 0); assert(c == COL_THIS); c = print_mono_colour(dr, 0); assert(c == COL_THAT); If the `can_print' flag is FALSE, this function will never be called. 2.10. Miscellaneous ------------------- 2.10.1. `can_format_as_text_ever' --------------------------------- int can_format_as_text_ever; This boolean field is TRUE if the game supports formatting a game state as ASCII text (typically ASCII art) for copying to the clipboard and pasting into other applications. If it is FALSE, front ends will not offer the `Copy' command at all. If this field is TRUE, the game does not necessarily have to support text formatting for _all_ games: e.g. a game which can be played on a square grid or a triangular one might only support copy and paste for the former, because triangular grids in ASCII art are just too difficult. If this field is FALSE, the functions can_format_as_text_now() (section 2.10.2) and text_format() (section 2.10.3) are never called. 2.10.2. `can_format_as_text_now()' ---------------------------------- int (*can_format_as_text_now)(const game_params *params); This function is passed a `game_params' and returns a boolean, which is TRUE if the game can support ASCII text output for this particular game type. If it returns FALSE, front ends will grey out or otherwise disable the `Copy' command. Games may enable and disable the copy-and-paste function for different game _parameters_, but are currently constrained to return the same answer from this function for all game _states_ sharing the same parameters. In other words, the `Copy' function may enable or disable itself when the player changes game preset, but will never change during play of a single game or when another game of exactly the same type is generated. This function should not take into account aspects of the game parameters which are not encoded by encode_params() (section 2.3.4) when the `full' parameter is set to FALSE. Such parameters will not necessarily match up between a call to this function and a subsequent call to text_format() itself. (For instance, game _difficulty_ should not affect whether the game can be copied to the clipboard. Only the actual visible _shape_ of the game can affect that.) 2.10.3. text_format() --------------------- char *(*text_format)(const game_state *state); This function is passed a `game_state', and returns a newly allocated C string containing an ASCII representation of that game state. It is used to implement the `Copy' operation in many front ends. This function will only ever be called if the back end field `can_format_as_text_ever' (section 2.10.1) is TRUE _and_ the function can_format_as_text_now() (section 2.10.2) has returned TRUE for the currently selected game parameters. The returned string may contain line endings (and will probably want to), using the normal C internal `\n' convention. For consistency between puzzles, all multi-line textual puzzle representations should _end_ with a newline as well as containing them internally. (There are currently no puzzles which have a one-line ASCII representation, so there's no precedent yet for whether that should come with a newline or not.) 2.10.4. wants_statusbar ----------------------- int wants_statusbar; This boolean field is set to TRUE if the puzzle has a use for a textual status line (to display score, completion status, currently active tiles, etc). 2.10.5. `is_timed' ------------------ int is_timed; This boolean field is TRUE if the puzzle is time-critical. If so, the mid-end will maintain a game timer while the user plays. If this field is FALSE, then timing_state() will never be called and need not do anything. 2.10.6. timing_state() ---------------------- int (*timing_state)(const game_state *state, game_ui *ui); This function is passed the current `game_state' and the local `game_ui'; it returns TRUE if the game timer should currently be running. A typical use for the `game_ui' in this function is to note when the game was first completed (by setting a flag in changed_state() - see section 2.6.5), and freeze the timer thereafter so that the user can undo back through their solution process without altering their time. 2.10.7. `flags' --------------- int flags; This field contains miscellaneous per-backend flags. It consists of the bitwise OR of some combination of the following: BUTTON_BEATS(x,y) Given any x and y from the set {LEFT_BUTTON, MIDDLE_BUTTON, RIGHT_BUTTON}, this macro evaluates to a bit flag which indicates that when buttons x and y are both pressed simultaneously, the mid- end should consider x to have priority. (In the absence of any such flags, the mid-end will always consider the most recently pressed button to have priority.) SOLVE_ANIMATES This flag indicates that moves generated by solve() (section 2.7.4) are candidates for animation just like any other move. For most games, solve moves should not be animated, so the mid-end doesn't even bother calling anim_length() (section 2.8.7), thus saving some special-case code in each game. On the rare occasion that animated solve moves are actually required, you can set this flag. REQUIRE_RBUTTON This flag indicates that the puzzle cannot be usefully played without the use of mouse buttons other than the left one. On some PDA platforms, this flag is used by the front end to enable right- button emulation through an appropriate gesture. Note that a puzzle is not required to set this just because it _uses_ the right button, but only if its use of the right button is critical to playing the game. (Slant, for example, uses the right button to cycle through the three square states in the opposite order from the left button, and hence can manage fine without it.) REQUIRE_NUMPAD This flag indicates that the puzzle cannot be usefully played without the use of number-key input. On some PDA platforms it causes an emulated number pad to appear on the screen. Similarly to REQUIRE_RBUTTON, a puzzle need not specify this simply if its use of the number keys is not critical. 2.11. Things a back end may do on its own initiative ---------------------------------------------------- This section describes a couple of things that a back end may choose to do by calling functions elsewhere in the program, which would not otherwise be obvious. 2.11.1. Create a random state ----------------------------- If a back end needs random numbers at some point during normal play, it can create a fresh `random_state' by first calling `get_random_seed' (section 4.35) and then passing the returned seed data to random_new(). This is likely not to be what you want. If a puzzle needs randomness in the middle of play, it's likely to be more sensible to store some sort of random state within the `game_state', so that the random numbers are tied to the particular game state and hence the player can't simply keep undoing their move until they get numbers they like better. This facility is currently used only in Net, to implement the `jumble' command, which sets every unlocked tile to a new random orientation. This randomness _is_ a reasonable use of the feature, because it's non- adversarial - there's no advantage to the user in getting different random numbers. 2.11.2. Supersede its own game description ------------------------------------------ In response to a move, a back end is (reluctantly) permitted to call midend_supersede_game_desc(): void midend_supersede_game_desc(midend *me, char *desc, char *privdesc); When the user selects `New Game', the mid-end calls new_desc() (section 2.4.1) to get a new game description, and (as well as using that to generate an initial game state) stores it for the save file and for telling to the user. The function above overwrites that game description, and also splits it in two. `desc' becomes the new game description which is provided to the user on request, and is also the one used to construct a new initial game state if the user selects `Restart'. `privdesc' is a `private' game description, used to reconstruct the game's initial state when reloading. The distinction between the two, as well as the need for this function at all, comes from Mines. Mines begins with a blank grid and no idea of where the mines actually are; new_desc() does almost no work in interactive mode, and simply returns a string encoding the `random_state'. When the user first clicks to open a tile, _then_ Mines generates the mine positions, in such a way that the game is soluble from that starting point. Then it uses this function to supersede the random-state game description with a proper one. But it needs two: one containing the initial click location (because that's what you want to happen if you restart the game, and also what you want to send to a friend so that they play _the same game_ as you), and one without the initial click location (because when you save and reload the game, you expect to see the same blank initial state as you had before saving). I should stress again that this function is a horrid hack. Nobody should use it if they're not Mines; if you think you need to use it, think again repeatedly in the hope of finding a better way to do whatever it was you needed to do. 3. The drawing API ------------------ The back end function redraw() (section 2.8.10) is required to draw the puzzle's graphics on the window's drawing area, or on paper if the puzzle is printable. To do this portably, it is provided with a drawing API allowing it to talk directly to the front end. In this chapter I document that API, both for the benefit of back end authors trying to use it and for front end authors trying to implement it. The drawing API as seen by the back end is a collection of global functions, each of which takes a pointer to a `drawing' structure (a `drawing object'). These objects are supplied as parameters to the back end's redraw() and print() functions. In fact these global functions are not implemented directly by the front end; instead, they are implemented centrally in `drawing.c' and form a small piece of middleware. The drawing API as supplied by the front end is a structure containing a set of function pointers, plus a `void *' handle which is passed to each of those functions. This enables a single front end to switch between multiple implementations of the drawing API if necessary. For example, the Windows API supplies a printing mechanism integrated into the same GDI which deals with drawing in windows, and therefore the same API implementation can handle both drawing and printing; but on Unix, the most common way for applications to print is by producing PostScript output directly, and although it would be _possible_ to write a single (say) draw_rect() function which checked a global flag to decide whether to do GTK drawing operations or output PostScript to a file, it's much nicer to have two separate functions and switch between them as appropriate. When drawing, the puzzle window is indexed by pixel coordinates, with the top left pixel defined as (0,0) and the bottom right pixel (w-1,h- 1), where `w' and `h' are the width and height values returned by the back end function compute_size() (section 2.8.4). When printing, the puzzle's print area is indexed in exactly the same way (with an arbitrary tile size provided by the printing module `printing.c'), to facilitate sharing of code between the drawing and printing routines. However, when printing, puzzles may no longer assume that the coordinate unit has any relationship to a pixel; the printer's actual resolution might very well not even be known at print time, so the coordinate unit might be smaller or larger than a pixel. Puzzles' print functions should restrict themselves to drawing geometric shapes rather than fiddly pixel manipulation. _Puzzles' redraw functions may assume that the surface they draw on is persistent_. It is the responsibility of every front end to preserve the puzzle's window contents in the face of GUI window expose issues and similar. It is not permissible to request that the back end redraw any part of a window that it has already drawn, unless something has actually changed as a result of making moves in the puzzle. Most front ends accomplish this by having the drawing routines draw on a stored bitmap rather than directly on the window, and copying the bitmap to the window every time a part of the window needs to be redrawn. Therefore, it is vitally important that whenever the back end does any drawing it informs the front end of which parts of the window it has accessed, and hence which parts need repainting. This is done by calling draw_update() (section 3.1.11). Persistence of old drawing is convenient. However, a puzzle should be very careful about how it updates its drawing area. The problem is that some front ends do anti-aliased drawing: rather than simply choosing between leaving each pixel untouched or painting it a specified colour, an antialiased drawing function will _blend_ the original and new colours in pixels at a figure's boundary according to the proportion of the pixel occupied by the figure (probably modified by some heuristic fudge factors). All of this produces a smoother appearance for curves and diagonal lines. An unfortunate effect of drawing an anti-aliased figure repeatedly is that the pixels around the figure's boundary come steadily more saturated with `ink' and the boundary appears to `spread out'. Worse, redrawing a figure in a different colour won't fully paint over the old boundary pixels, so the end result is a rather ugly smudge. A good strategy to avoid unpleasant anti-aliasing artifacts is to identify a number of rectangular areas which need to be redrawn, clear them to the background colour, and then redraw their contents from scratch, being careful all the while not to stray beyond the boundaries of the original rectangles. The clip() function (section 3.1.9) comes in very handy here. Games based on a square grid can often do this fairly easily. Other games may need to be somewhat more careful. For example, Loopy's redraw function first identifies portions of the display which need to be updated. Then, if the changes are fairly well localised, it clears and redraws a rectangle containing each changed area. Otherwise, it gives up and redraws the entire grid from scratch. It is possible to avoid clearing to background and redrawing from scratch if one is very careful about which drawing functions one uses: if a function is documented as not anti-aliasing under some circumstances, you can rely on each pixel in a drawing either being left entirely alone or being set to the requested colour, with no blending being performed. In the following sections I first discuss the drawing API as seen by the back end, and then the _almost_ identical function-pointer form seen by the front end. 3.1. Drawing API as seen by the back end ---------------------------------------- This section documents the back-end drawing API, in the form of functions which take a `drawing' object as an argument. 3.1.1. draw_rect() ------------------ void draw_rect(drawing *dr, int x, int y, int w, int h, int colour); Draws a filled rectangle in the puzzle window. `x' and `y' give the coordinates of the top left pixel of the rectangle. `w' and `h' give its width and height. Thus, the horizontal extent of the rectangle runs from `x' to `x+w-1' inclusive, and the vertical extent from `y' to `y+h-1' inclusive. `colour' is an integer index into the colours array returned by the back end function colours() (section 2.8.6). There is no separate pixel-plotting function. If you want to plot a single pixel, the approved method is to use draw_rect() with width and height set to 1. Unlike many of the other drawing functions, this function is guaranteed to be pixel-perfect: the rectangle will be sharply defined and not anti- aliased or anything like that. This function may be used for both drawing and printing. 3.1.2. draw_rect_outline() -------------------------- void draw_rect_outline(drawing *dr, int x, int y, int w, int h, int colour); Draws an outline rectangle in the puzzle window. `x' and `y' give the coordinates of the top left pixel of the rectangle. `w' and `h' give its width and height. Thus, the horizontal extent of the rectangle runs from `x' to `x+w-1' inclusive, and the vertical extent from `y' to `y+h-1' inclusive. `colour' is an integer index into the colours array returned by the back end function colours() (section 2.8.6). From a back end perspective, this function may be considered to be part of the drawing API. However, front ends are not required to implement it, since it is actually implemented centrally (in misc.c) as a wrapper on draw_polygon(). This function may be used for both drawing and printing. 3.1.3. draw_line() ------------------ void draw_line(drawing *dr, int x1, int y1, int x2, int y2, int colour); Draws a straight line in the puzzle window. `x1' and `y1' give the coordinates of one end of the line. `x2' and `y2' give the coordinates of the other end. The line drawn includes both those points. `colour' is an integer index into the colours array returned by the back end function colours() (section 2.8.6). Some platforms may perform anti-aliasing on this function. Therefore, do not assume that you can erase a line by drawing the same line over it in the background colour; anti-aliasing might lead to perceptible ghost artefacts around the vanished line. Horizontal and vertical lines, however, are pixel-perfect and not anti-aliased. This function may be used for both drawing and printing. 3.1.4. draw_polygon() --------------------- void draw_polygon(drawing *dr, int *coords, int npoints, int fillcolour, int outlinecolour); Draws an outlined or filled polygon in the puzzle window. `coords' is an array of (2*npoints) integers, containing the `x' and `y' coordinates of `npoints' vertices. `fillcolour' and `outlinecolour' are integer indices into the colours array returned by the back end function colours() (section 2.8.6). `fillcolour' may also be -1 to indicate that the polygon should be outlined only. The polygon defined by the specified list of vertices is first filled in `fillcolour', if specified, and then outlined in `outlinecolour'. `outlinecolour' may _not_ be -1; it must be a valid colour (and front ends are permitted to enforce this by assertion). This is because different platforms disagree on whether a filled polygon should include its boundary line or not, so drawing _only_ a filled polygon would have non-portable effects. If you want your filled polygon not to have a visible outline, you must set `outlinecolour' to the same as `fillcolour'. Some platforms may perform anti-aliasing on this function. Therefore, do not assume that you can erase a polygon by drawing the same polygon over it in the background colour. Also, be prepared for the polygon to extend a pixel beyond its obvious bounding box as a result of this; if you really need it not to do this to avoid interfering with other delicate graphics, you should probably use clip() (section 3.1.9). You can rely on horizontal and vertical lines not being anti-aliased. This function may be used for both drawing and printing. 3.1.5. draw_circle() -------------------- void draw_circle(drawing *dr, int cx, int cy, int radius, int fillcolour, int outlinecolour); Draws an outlined or filled circle in the puzzle window. `cx' and `cy' give the coordinates of the centre of the circle. `radius' gives its radius. The total horizontal pixel extent of the circle is from `cx-radius+1' to `cx+radius-1' inclusive, and the vertical extent similarly around `cy'. `fillcolour' and `outlinecolour' are integer indices into the colours array returned by the back end function colours() (section 2.8.6). `fillcolour' may also be -1 to indicate that the circle should be outlined only. The circle is first filled in `fillcolour', if specified, and then outlined in `outlinecolour'. `outlinecolour' may _not_ be -1; it must be a valid colour (and front ends are permitted to enforce this by assertion). This is because different platforms disagree on whether a filled circle should include its boundary line or not, so drawing _only_ a filled circle would have non-portable effects. If you want your filled circle not to have a visible outline, you must set `outlinecolour' to the same as `fillcolour'. Some platforms may perform anti-aliasing on this function. Therefore, do not assume that you can erase a circle by drawing the same circle over it in the background colour. Also, be prepared for the circle to extend a pixel beyond its obvious bounding box as a result of this; if you really need it not to do this to avoid interfering with other delicate graphics, you should probably use clip() (section 3.1.9). This function may be used for both drawing and printing. 3.1.6. draw_thick_line() ------------------------ void draw_thick_line(drawing *dr, float thickness, float x1, float y1, float x2, float y2, int colour) Draws a line in the puzzle window, giving control over the line's thickness. `x1' and `y1' give the coordinates of one end of the line. `x2' and `y2' give the coordinates of the other end. `thickness' gives the thickness of the line, in pixels. Note that the coordinates and thickness are floating-point: the continuous coordinate system is in effect here. It's important to be able to address points with better-than-pixel precision in this case, because one can't otherwise properly express the endpoints of lines with both odd and even thicknesses. Some platforms may perform anti-aliasing on this function. The precise pixels affected by a thick-line drawing operation may vary between platforms, and no particular guarantees are provided. Indeed, even horizontal or vertical lines may be anti-aliased. This function may be used for both drawing and printing. 3.1.7. draw_text() ------------------ void draw_text(drawing *dr, int x, int y, int fonttype, int fontsize, int align, int colour, char *text); Draws text in the puzzle window. `x' and `y' give the coordinates of a point. The relation of this point to the location of the text is specified by `align', which is a bitwise OR of horizontal and vertical alignment flags: ALIGN_VNORMAL Indicates that `y' is aligned with the baseline of the text. ALIGN_VCENTRE Indicates that `y' is aligned with the vertical centre of the text. (In fact, it's aligned with the vertical centre of normal _capitalised_ text: displaying two pieces of text with ALIGN_VCENTRE at the same y-coordinate will cause their baselines to be aligned with one another, even if one is an ascender and the other a descender.) ALIGN_HLEFT Indicates that `x' is aligned with the left-hand end of the text. ALIGN_HCENTRE Indicates that `x' is aligned with the horizontal centre of the text. ALIGN_HRIGHT Indicates that `x' is aligned with the right-hand end of the text. `fonttype' is either FONT_FIXED or FONT_VARIABLE, for a monospaced or proportional font respectively. (No more detail than that may be specified; it would only lead to portability issues between different platforms.) `fontsize' is the desired size, in pixels, of the text. This size corresponds to the overall point size of the text, not to any internal dimension such as the cap-height. `colour' is an integer index into the colours array returned by the back end function colours() (section 2.8.6). This function may be used for both drawing and printing. The character set used to encode the text passed to this function is specified _by the drawing object_, although it must be a superset of ASCII. If a puzzle wants to display text that is not contained in ASCII, it should use the text_fallback() function (section 3.1.8) to query the drawing object for an appropriate representation of the characters it wants. 3.1.8. text_fallback() ---------------------- char *text_fallback(drawing *dr, const char *const *strings, int nstrings); This function is used to request a translation of UTF-8 text into whatever character encoding is expected by the drawing object's implementation of draw_text(). The input is a list of strings encoded in UTF-8: nstrings gives the number of strings in the list, and strings[0], strings[1], ..., strings[nstrings-1] are the strings themselves. The returned string (which is dynamically allocated and must be freed when finished with) is derived from the first string in the list that the drawing object expects to be able to display reliably; it will consist of that string translated into the character set expected by draw_text(). Drawing implementations are not required to handle anything outside ASCII, but are permitted to assume that _some_ string will be successfully translated. So every call to this function must include a string somewhere in the list (presumably the last element) which consists of nothing but ASCII, to be used by any front end which cannot handle anything else. For example, if a puzzle wished to display a string including a multiplication sign (U+00D7 in Unicode, represented by the bytes C3 97 in UTF-8), it might do something like this: static const char *const times_signs[] = { "\xC3\x97", "x" }; char *times_sign = text_fallback(dr, times_signs, 2); sprintf(buffer, "%d%s%d", width, times_sign, height); draw_text(dr, x, y, font, size, align, colour, buffer); sfree(buffer); which would draw a string with a times sign in the middle on platforms that support it, and fall back to a simple ASCII `x' where there was no alternative. 3.1.9. clip() ------------- void clip(drawing *dr, int x, int y, int w, int h); Establishes a clipping rectangle in the puzzle window. `x' and `y' give the coordinates of the top left pixel of the clipping rectangle. `w' and `h' give its width and height. Thus, the horizontal extent of the rectangle runs from `x' to `x+w-1' inclusive, and the vertical extent from `y' to `y+h-1' inclusive. (These are exactly the same semantics as draw_rect().) After this call, no drawing operation will affect anything outside the specified rectangle. The effect can be reversed by calling unclip() (section 3.1.10). The clipping rectangle is pixel-perfect: pixels within the rectangle are affected as usual by drawing functions; pixels outside are completely untouched. Back ends should not assume that a clipping rectangle will be automatically cleared up by the front end if it's left lying around; that might work on current front ends, but shouldn't be relied upon. Always explicitly call unclip(). This function may be used for both drawing and printing. 3.1.10. unclip() ---------------- void unclip(drawing *dr); Reverts the effect of a previous call to clip(). After this call, all drawing operations will be able to affect the entire puzzle window again. This function may be used for both drawing and printing. 3.1.11. draw_update() --------------------- void draw_update(drawing *dr, int x, int y, int w, int h); Informs the front end that a rectangular portion of the puzzle window has been drawn on and needs to be updated. `x' and `y' give the coordinates of the top left pixel of the update rectangle. `w' and `h' give its width and height. Thus, the horizontal extent of the rectangle runs from `x' to `x+w-1' inclusive, and the vertical extent from `y' to `y+h-1' inclusive. (These are exactly the same semantics as draw_rect().) The back end redraw function _must_ call this function to report any changes it has made to the window. Otherwise, those changes may not become immediately visible, and may then appear at an unpredictable subsequent time such as the next time the window is covered and re- exposed. This function is only important when drawing. It may be called when printing as well, but doing so is not compulsory, and has no effect. (So if you have a shared piece of code between the drawing and printing routines, that code may safely call draw_update().) 3.1.12. status_bar() -------------------- void status_bar(drawing *dr, char *text); Sets the text in the game's status bar to `text'. The text is copied from the supplied buffer, so the caller is free to deallocate or modify the buffer after use. (This function is not exactly a _drawing_ function, but it shares with the drawing API the property that it may only be called from within the back end redraw function, so this is as good a place as any to document it.) The supplied text is filtered through the mid-end for optional rewriting before being passed on to the front end; the mid-end will prepend the current game time if the game is timed (and may in future perform other rewriting if it seems like a good idea). This function is for drawing only; it must never be called during printing. 3.1.13. Blitter functions ------------------------- This section describes a group of related functions which save and restore a section of the puzzle window. This is most commonly used to implement user interfaces involving dragging a puzzle element around the window: at the end of each call to redraw(), if an object is currently being dragged, the back end saves the window contents under that location and then draws the dragged object, and at the start of the next redraw() the first thing it does is to restore the background. The front end defines an opaque type called a `blitter', which is capable of storing a rectangular area of a specified size. Blitter functions are for drawing only; they must never be called during printing. 3.1.13.1. blitter_new() ----------------------- blitter *blitter_new(drawing *dr, int w, int h); Creates a new blitter object which stores a rectangle of size `w' by `h' pixels. Returns a pointer to the blitter object. Blitter objects are best stored in the `game_drawstate'. A good time to create them is in the set_size() function (section 2.8.5), since it is at this point that you first know how big a rectangle they will need to save. 3.1.13.2. blitter_free() ------------------------ void blitter_free(drawing *dr, blitter *bl); Disposes of a blitter object. Best called in free_drawstate(). (However, check that the blitter object is not NULL before attempting to free it; it is possible that a draw state might be created and freed without ever having set_size() called on it in between.) 3.1.13.3. blitter_save() ------------------------ void blitter_save(drawing *dr, blitter *bl, int x, int y); This is a true drawing API function, in that it may only be called from within the game redraw routine. It saves a rectangular portion of the puzzle window into the specified blitter object. `x' and `y' give the coordinates of the top left corner of the saved rectangle. The rectangle's width and height are the ones specified when the blitter object was created. This function is required to cope and do the right thing if `x' and `y' are out of range. (The right thing probably means saving whatever part of the blitter rectangle overlaps with the visible area of the puzzle window.) 3.1.13.4. blitter_load() ------------------------ void blitter_load(drawing *dr, blitter *bl, int x, int y); This is a true drawing API function, in that it may only be called from within the game redraw routine. It restores a rectangular portion of the puzzle window from the specified blitter object. `x' and `y' give the coordinates of the top left corner of the rectangle to be restored. The rectangle's width and height are the ones specified when the blitter object was created. Alternatively, you can specify both `x' and `y' as the special value BLITTER_FROMSAVED, in which case the rectangle will be restored to exactly where it was saved from. (This is probably what you want to do almost all the time, if you're using blitters to implement draggable puzzle elements.) This function is required to cope and do the right thing if `x' and `y' (or the equivalent ones saved in the blitter) are out of range. (The right thing probably means restoring whatever part of the blitter rectangle overlaps with the visible area of the puzzle window.) If this function is called on a blitter which had previously been saved from a partially out-of-range rectangle, then the parts of the saved bitmap which were not visible at save time are undefined. If the blitter is restored to a different position so as to make those parts visible, the effect on the drawing area is undefined. 3.1.14. print_mono_colour() --------------------------- int print_mono_colour(drawing *dr, int grey); This function allocates a colour index for a simple monochrome colour during printing. `grey' must be 0 or 1. If `grey' is 0, the colour returned is black; if `grey' is 1, the colour is white. 3.1.15. print_grey_colour() --------------------------- int print_grey_colour(drawing *dr, float grey); This function allocates a colour index for a grey-scale colour during printing. `grey' may be any number between 0 (black) and 1 (white); for example, 0.5 indicates a medium grey. The chosen colour will be rendered to the limits of the printer's halftoning capability. 3.1.16. print_hatched_colour() ------------------------------ int print_hatched_colour(drawing *dr, int hatch); This function allocates a colour index which does not represent a literal _colour_. Instead, regions shaded in this colour will be hatched with parallel lines. The `hatch' parameter defines what type of hatching should be used in place of this colour: HATCH_SLASH This colour will be hatched by lines slanting to the right at 45 degrees. HATCH_BACKSLASH This colour will be hatched by lines slanting to the left at 45 degrees. HATCH_HORIZ This colour will be hatched by horizontal lines. HATCH_VERT This colour will be hatched by vertical lines. HATCH_PLUS This colour will be hatched by criss-crossing horizontal and vertical lines. HATCH_X This colour will be hatched by criss-crossing diagonal lines. Colours defined to use hatching may not be used for drawing lines or text; they may only be used for filling areas. That is, they may be used as the `fillcolour' parameter to draw_circle() and draw_polygon(), and as the colour parameter to draw_rect(), but may not be used as the `outlinecolour' parameter to draw_circle() or draw_polygon(), or with draw_line() or draw_text(). 3.1.17. print_rgb_mono_colour() ------------------------------- int print_rgb_mono_colour(drawing *dr, float r, float g, float b, float grey); This function allocates a colour index for a fully specified RGB colour during printing. `r', `g' and `b' may each be anywhere in the range from 0 to 1. If printing in black and white only, these values will be ignored, and either pure black or pure white will be used instead, according to the `grey' parameter. (The fallback colour is the same as the one which would be allocated by print_mono_colour(grey).) 3.1.18. print_rgb_grey_colour() ------------------------------- int print_rgb_grey_colour(drawing *dr, float r, float g, float b, float grey); This function allocates a colour index for a fully specified RGB colour during printing. `r', `g' and `b' may each be anywhere in the range from 0 to 1. If printing in black and white only, these values will be ignored, and a shade of grey given by the `grey' parameter will be used instead. (The fallback colour is the same as the one which would be allocated by print_grey_colour(grey).) 3.1.19. print_rgb_hatched_colour() ---------------------------------- int print_rgb_hatched_colour(drawing *dr, float r, float g, float b, float hatched); This function allocates a colour index for a fully specified RGB colour during printing. `r', `g' and `b' may each be anywhere in the range from 0 to 1. If printing in black and white only, these values will be ignored, and a form of cross-hatching given by the `hatch' parameter will be used instead; see section 3.1.16 for the possible values of this parameter. (The fallback colour is the same as the one which would be allocated by print_hatched_colour(hatch).) 3.1.20. print_line_width() -------------------------- void print_line_width(drawing *dr, int width); This function is called to set the thickness of lines drawn during printing. It is meaningless in drawing: all lines drawn by draw_line(), draw_circle and draw_polygon() are one pixel in thickness. However, in printing there is no clear definition of a pixel and so line widths must be explicitly specified. The line width is specified in the usual coordinate system. Note, however, that it is a hint only: the central printing system may choose to vary line thicknesses at user request or due to printer capabilities. 3.1.21. print_line_dotted() --------------------------- void print_line_dotted(drawing *dr, int dotted); This function is called to toggle the drawing of dotted lines during printing. It is not supported during drawing. The parameter `dotted' is a boolean; TRUE means that future lines drawn by draw_line(), draw_circle and draw_polygon() will be dotted, and FALSE means that they will be solid. Some front ends may impose restrictions on the width of dotted lines. Asking for a dotted line via this front end will override any line width request if the front end requires it. 3.2. The drawing API as implemented by the front end ---------------------------------------------------- This section describes the drawing API in the function-pointer form in which it is implemented by a front end. (It isn't only platform-specific front ends which implement this API; the platform-independent module `ps.c' also provides an implementation of it which outputs PostScript. Thus, any platform which wants to do PS printing can do so with minimum fuss.) The following entries all describe function pointer fields in a structure called `drawing_api'. Each of the functions takes a `void *' context pointer, which it should internally cast back to a more useful type. Thus, a drawing _object_ (`drawing *)' suitable for passing to the back end redraw or printing functions is constructed by passing a `drawing_api' and a `void *' to the function drawing_new() (see section 3.3.1). 3.2.1. draw_text() ------------------ void (*draw_text)(void *handle, int x, int y, int fonttype, int fontsize, int align, int colour, char *text); This function behaves exactly like the back end draw_text() function; see section 3.1.7. 3.2.2. draw_rect() ------------------ void (*draw_rect)(void *handle, int x, int y, int w, int h, int colour); This function behaves exactly like the back end draw_rect() function; see section 3.1.1. 3.2.3. draw_line() ------------------ void (*draw_line)(void *handle, int x1, int y1, int x2, int y2, int colour); This function behaves exactly like the back end draw_line() function; see section 3.1.3. 3.2.4. draw_polygon() --------------------- void (*draw_polygon)(void *handle, int *coords, int npoints, int fillcolour, int outlinecolour); This function behaves exactly like the back end draw_polygon() function; see section 3.1.4. 3.2.5. draw_circle() -------------------- void (*draw_circle)(void *handle, int cx, int cy, int radius, int fillcolour, int outlinecolour); This function behaves exactly like the back end draw_circle() function; see section 3.1.5. 3.2.6. draw_thick_line() ------------------------ void draw_thick_line(drawing *dr, float thickness, float x1, float y1, float x2, float y2, int colour) This function behaves exactly like the back end draw_thick_line() function; see section 3.1.6. An implementation of this API which doesn't provide high-quality rendering of thick lines is permitted to define this function pointer to be NULL. The middleware in drawing.c will notice and provide a low- quality alternative using draw_polygon(). 3.2.7. draw_update() -------------------- void (*draw_update)(void *handle, int x, int y, int w, int h); This function behaves exactly like the back end draw_update() function; see section 3.1.11. An implementation of this API which only supports printing is permitted to define this function pointer to be NULL rather than bothering to define an empty function. The middleware in drawing.c will notice and avoid calling it. 3.2.8. clip() ------------- void (*clip)(void *handle, int x, int y, int w, int h); This function behaves exactly like the back end clip() function; see section 3.1.9. 3.2.9. unclip() --------------- void (*unclip)(void *handle); This function behaves exactly like the back end unclip() function; see section 3.1.10. 3.2.10. start_draw() -------------------- void (*start_draw)(void *handle); This function is called at the start of drawing. It allows the front end to initialise any temporary data required to draw with, such as device contexts. Implementations of this API which do not provide drawing services may define this function pointer to be NULL; it will never be called unless drawing is attempted. 3.2.11. end_draw() ------------------ void (*end_draw)(void *handle); This function is called at the end of drawing. It allows the front end to do cleanup tasks such as deallocating device contexts and scheduling appropriate GUI redraw events. Implementations of this API which do not provide drawing services may define this function pointer to be NULL; it will never be called unless drawing is attempted. 3.2.12. status_bar() -------------------- void (*status_bar)(void *handle, char *text); This function behaves exactly like the back end status_bar() function; see section 3.1.12. Front ends implementing this function need not worry about it being called repeatedly with the same text; the middleware code in status_bar() will take care of this. Implementations of this API which do not provide drawing services may define this function pointer to be NULL; it will never be called unless drawing is attempted. 3.2.13. blitter_new() --------------------- blitter *(*blitter_new)(void *handle, int w, int h); This function behaves exactly like the back end blitter_new() function; see section 3.1.13.1. Implementations of this API which do not provide drawing services may define this function pointer to be NULL; it will never be called unless drawing is attempted. 3.2.14. blitter_free() ---------------------- void (*blitter_free)(void *handle, blitter *bl); This function behaves exactly like the back end blitter_free() function; see section 3.1.13.2. Implementations of this API which do not provide drawing services may define this function pointer to be NULL; it will never be called unless drawing is attempted. 3.2.15. blitter_save() ---------------------- void (*blitter_save)(void *handle, blitter *bl, int x, int y); This function behaves exactly like the back end blitter_save() function; see section 3.1.13.3. Implementations of this API which do not provide drawing services may define this function pointer to be NULL; it will never be called unless drawing is attempted. 3.2.16. blitter_load() ---------------------- void (*blitter_load)(void *handle, blitter *bl, int x, int y); This function behaves exactly like the back end blitter_load() function; see section 3.1.13.4. Implementations of this API which do not provide drawing services may define this function pointer to be NULL; it will never be called unless drawing is attempted. 3.2.17. begin_doc() ------------------- void (*begin_doc)(void *handle, int pages); This function is called at the beginning of a printing run. It gives the front end an opportunity to initialise any required printing subsystem. It also provides the number of pages in advance. Implementations of this API which do not provide printing services may define this function pointer to be NULL; it will never be called unless printing is attempted. 3.2.18. begin_page() -------------------- void (*begin_page)(void *handle, int number); This function is called during printing, at the beginning of each page. It gives the page number (numbered from 1 rather than 0, so suitable for use in user-visible contexts). Implementations of this API which do not provide printing services may define this function pointer to be NULL; it will never be called unless printing is attempted. 3.2.19. begin_puzzle() ---------------------- void (*begin_puzzle)(void *handle, float xm, float xc, float ym, float yc, int pw, int ph, float wmm); This function is called during printing, just before printing a single puzzle on a page. It specifies the size and location of the puzzle on the page. `xm' and `xc' specify the horizontal position of the puzzle on the page, as a linear function of the page width. The front end is expected to multiply the page width by `xm', add `xc' (measured in millimetres), and use the resulting x-coordinate as the left edge of the puzzle. Similarly, `ym' and `yc' specify the vertical position of the puzzle as a function of the page height: the page height times `ym', plus `yc' millimetres, equals the desired distance from the top of the page to the top of the puzzle. (This unwieldy mechanism is required because not all printing systems can communicate the page size back to the software. The PostScript back end, for example, writes out PS which determines the page size at print time by means of calling `clippath', and centres the puzzles within that. Thus, exactly the same PS file works on A4 or on US Letter paper without needing local configuration, which simplifies matters.) pw and ph give the size of the puzzle in drawing API coordinates. The printing system will subsequently call the puzzle's own print function, which will in turn call drawing API functions in the expectation that an area pw by ph units is available to draw the puzzle on. Finally, wmm gives the desired width of the puzzle in millimetres. (The aspect ratio is expected to be preserved, so if the desired puzzle height is also needed then it can be computed as wmm*ph/pw.) Implementations of this API which do not provide printing services may define this function pointer to be NULL; it will never be called unless printing is attempted. 3.2.20. end_puzzle() -------------------- void (*end_puzzle)(void *handle); This function is called after the printing of a specific puzzle is complete. Implementations of this API which do not provide printing services may define this function pointer to be NULL; it will never be called unless printing is attempted. 3.2.21. end_page() ------------------ void (*end_page)(void *handle, int number); This function is called after the printing of a page is finished. Implementations of this API which do not provide printing services may define this function pointer to be NULL; it will never be called unless printing is attempted. 3.2.22. end_doc() ----------------- void (*end_doc)(void *handle); This function is called after the printing of the entire document is finished. This is the moment to close files, send things to the print spooler, or whatever the local convention is. Implementations of this API which do not provide printing services may define this function pointer to be NULL; it will never be called unless printing is attempted. 3.2.23. line_width() -------------------- void (*line_width)(void *handle, float width); This function is called to set the line thickness, during printing only. Note that the width is a float here, where it was an int as seen by the back end. This is because drawing.c may have scaled it on the way past. However, the width is still specified in the same coordinate system as the rest of the drawing. Implementations of this API which do not provide printing services may define this function pointer to be NULL; it will never be called unless printing is attempted. 3.2.24. text_fallback() ----------------------- char *(*text_fallback)(void *handle, const char *const *strings, int nstrings); This function behaves exactly like the back end text_fallback() function; see section 3.1.8. Implementations of this API which do not support any characters outside ASCII may define this function pointer to be NULL, in which case the central code in drawing.c will provide a default implementation. 3.3. The drawing API as called by the front end ----------------------------------------------- There are a small number of functions provided in drawing.c which the front end needs to _call_, rather than helping to implement. They are described in this section. 3.3.1. drawing_new() -------------------- drawing *drawing_new(const drawing_api *api, midend *me, void *handle); This function creates a drawing object. It is passed a `drawing_api', which is a structure containing nothing but function pointers; and also a `void *' handle. The handle is passed back to each function pointer when it is called. The `midend' parameter is used for rewriting the status bar contents: status_bar() (see section 3.1.12) has to call a function in the mid- end which might rewrite the status bar text. If the drawing object is to be used only for printing, or if the game is known not to call status_bar(), this parameter may be NULL. 3.3.2. drawing_free() --------------------- void drawing_free(drawing *dr); This function frees a drawing object. Note that the `void *' handle is not freed; if that needs cleaning up it must be done by the front end. 3.3.3. print_get_colour() ------------------------- void print_get_colour(drawing *dr, int colour, int printincolour, int *hatch, float *r, float *g, float *b) This function is called by the implementations of the drawing API functions when they are called in a printing context. It takes a colour index as input, and returns the description of the colour as requested by the back end. `printincolour' is TRUE iff the implementation is printing in colour. This will alter the results returned if the colour in question was specified with a black-and-white fallback value. If the colour should be rendered by hatching, `*hatch' is filled with the type of hatching desired. See section 3.1.15 for details of the values this integer can take. If the colour should be rendered as solid colour, `*hatch' is given a negative value, and `*r', `*g' and `*b' are filled with the RGB values of the desired colour (if printing in colour), or all filled with the grey-scale value (if printing in black and white). 4. The API provided by the mid-end ---------------------------------- This chapter documents the API provided by the mid-end to be called by the front end. You probably only need to read this if you are a front end implementor, i.e. you are porting Puzzles to a new platform. If you're only interested in writing new puzzles, you can safely skip this chapter. All the persistent state in the mid-end is encapsulated within a `midend' structure, to facilitate having multiple mid-ends in any port which supports multiple puzzle windows open simultaneously. Each `midend' is intended to handle the contents of a single puzzle window. 4.1. midend_new() ----------------- midend *midend_new(frontend *fe, const game *ourgame, const drawing_api *drapi, void *drhandle) Allocates and returns a new mid-end structure. The `fe' argument is stored in the mid-end. It will be used when calling back to functions such as activate_timer() (section 4.36), and will be passed on to the back end function colours() (section 2.8.6). The parameters `drapi' and `drhandle' are passed to drawing_new() (section 3.3.1) to construct a drawing object which will be passed to the back end function redraw() (section 2.8.10). Hence, all drawing- related function pointers defined in `drapi' can expect to be called with `drhandle' as their first argument. The `ourgame' argument points to a container structure describing a game back end. The mid-end thus created will only be capable of handling that one game. (So even in a monolithic front end containing all the games, this imposes the constraint that any individual puzzle window is tied to a single game. Unless, of course, you feel brave enough to change the mid-end for the window without closing the window...) 4.2. midend_free() ------------------ void midend_free(midend *me); Frees a mid-end structure and all its associated data. 4.3. midend_tilesize() ---------------------- int midend_tilesize(midend *me); Returns the `tilesize' parameter being used to display the current puzzle (section 2.8.3). 4.4. midend_set_params() ------------------------ void midend_set_params(midend *me, game_params *params); Sets the current game parameters for a mid-end. Subsequent games generated by midend_new_game() (section 4.8) will use these parameters until further notice. The usual way in which the front end will have an actual `game_params' structure to pass to this function is if it had previously got it from midend_get_presets() (section 4.15). Thus, this function is usually called in response to the user making a selection from the presets menu. 4.5. midend_get_params() ------------------------ game_params *midend_get_params(midend *me); Returns the current game parameters stored in this mid-end. The returned value is dynamically allocated, and should be freed when finished with by passing it to the game's own free_params() function (see section 2.3.6). 4.6. midend_size() ------------------ void midend_size(midend *me, int *x, int *y, int user_size); Tells the mid-end to figure out its window size. On input, `*x' and `*y' should contain the maximum or requested size for the window. (Typically this will be the size of the screen that the window has to fit on, or similar.) The mid-end will repeatedly call the back end function compute_size() (section 2.8.4), searching for a tile size that best satisfies the requirements. On exit, `*x' and `*y' will contain the size needed for the puzzle window's drawing area. (It is of course up to the front end to adjust this for any additional window furniture such as menu bars and window borders, if necessary. The status bar is also not included in this size.) Use `user_size' to indicate whether `*x' and `*y' are a requested size, or just a maximum size. If `user_size' is set to TRUE, the mid-end will treat the input size as a request, and will pick a tile size which approximates it _as closely as possible_, going over the game's preferred tile size if necessary to achieve this. The mid-end will also use the resulting tile size as its preferred one until further notice, on the assumption that this size was explicitly requested by the user. Use this option if you want your front end to support dynamic resizing of the puzzle window with automatic scaling of the puzzle to fit. If `user_size' is set to FALSE, then the game's tile size will never go over its preferred one, although it may go under in order to fit within the maximum bounds specified by `*x' and `*y'. This is the recommended approach when opening a new window at default size: the game will use its preferred size unless it has to use a smaller one to fit on the screen. If the tile size is shrunk for this reason, the change will not persist; if a smaller grid is subsequently chosen, the tile size will recover. The mid-end will try as hard as it can to return a size which is less than or equal to the input size, in both dimensions. In extreme circumstances it may fail (if even the lowest possible tile size gives window dimensions greater than the input), in which case it will return a size greater than the input size. Front ends should be prepared for this to happen (i.e. don't crash or fail an assertion), but may handle it in any way they see fit: by rejecting the game parameters which caused the problem, by opening a window larger than the screen regardless of inconvenience, by introducing scroll bars on the window, by drawing on a large bitmap and scaling it into a smaller window, or by any other means you can think of. It is likely that when the tile size is that small the game will be unplayable anyway, so don't put _too_ much effort into handling it creatively. If your platform has no limit on window size (or if you're planning to use scroll bars for large puzzles), you can pass dimensions of INT_MAX as input to this function. You should probably not do that _and_ set the `user_size' flag, though! The midend relies on the frontend calling midend_new_game() (section 4.8) before calling midend_size(). 4.7. midend_reset_tilesize() ---------------------------- void midend_reset_tilesize(midend *me); This function resets the midend's preferred tile size to that of the standard puzzle. As discussed in section 4.6, puzzle resizes are typically 'sticky', in that once the user has dragged the puzzle to a different window size, the resulting tile size will be remembered and used when the puzzle configuration changes. If you _don't_ want that, e.g. if you want to provide a command to explicitly reset the puzzle size back to its default, then you can call this just before calling midend_size() (which, in turn, you would probably call with `user_size' set to FALSE). 4.8. midend_new_game() ---------------------- void midend_new_game(midend *me); Causes the mid-end to begin a new game. Normally the game will be a new randomly generated puzzle. However, if you have previously called midend_game_id() or midend_set_config(), the game generated might be dictated by the results of those functions. (In particular, you _must_ call midend_new_game() after calling either of those functions, or else no immediate effect will be visible.) You will probably need to call midend_size() after calling this function, because if the game parameters have been changed since the last new game then the window size might need to change. (If you know the parameters _haven't_ changed, you don't need to do this.) This function will create a new `game_drawstate', but does not actually perform a redraw (since you often need to call midend_size() before the redraw can be done). So after calling this function and after calling midend_size(), you should then call midend_redraw(). (It is not necessary to call midend_force_redraw(); that will discard the draw state and create a fresh one, which is unnecessary in this case since there's a fresh one already. It would work, but it's usually excessive.) 4.9. midend_restart_game() -------------------------- void midend_restart_game(midend *me); This function causes the current game to be restarted. This is done by placing a new copy of the original game state on the end of the undo list (so that an accidental restart can be undone). This function automatically causes a redraw, i.e. the front end can expect its drawing API to be called from _within_ a call to this function. Some back ends require that midend_size() (section 4.6) is called before midend_restart_game(). 4.10. midend_force_redraw() --------------------------- void midend_force_redraw(midend *me); Forces a complete redraw of the puzzle window, by means of discarding the current `game_drawstate' and creating a new one from scratch before calling the game's redraw() function. The front end can expect its drawing API to be called from within a call to this function. Some back ends require that midend_size() (section 4.6) is called before midend_force_redraw(). 4.11. midend_redraw() --------------------- void midend_redraw(midend *me); Causes a partial redraw of the puzzle window, by means of simply calling the game's redraw() function. (That is, the only things redrawn will be things that have changed since the last redraw.) The front end can expect its drawing API to be called from within a call to this function. Some back ends require that midend_size() (section 4.6) is called before midend_redraw(). 4.12. midend_process_key() -------------------------- int midend_process_key(midend *me, int x, int y, int button); The front end calls this function to report a mouse or keyboard event. The parameters `x', `y' and `button' are almost identical to the ones passed to the back end function interpret_move() (section 2.7.1), except that the front end is _not_ required to provide the guarantees about mouse event ordering. The mid-end will sort out multiple simultaneous button presses and changes of button; the front end's responsibility is simply to pass on the mouse events it receives as accurately as possible. (Some platforms may need to emulate absent mouse buttons by means of using a modifier key such as Shift with another mouse button. This tends to mean that if Shift is pressed or released in the middle of a mouse drag, the mid-end will suddenly stop receiving, say, LEFT_DRAG events and start receiving RIGHT_DRAGs, with no intervening button release or press events. This too is something which the mid-end will sort out for you; the front end has no obligation to maintain sanity in this area.) The front end _should_, however, always eventually send some kind of button release. On some platforms this requires special effort: Windows, for example, requires a call to the system API function SetCapture() in order to ensure that your window receives a mouse-up event even if the pointer has left the window by the time the mouse button is released. On any platform that requires this sort of thing, the front end _is_ responsible for doing it. Calling this function is very likely to result in calls back to the front end's drawing API and/or activate_timer() (section 4.36). The return value from midend_process_key() is non-zero, unless the effect of the keypress was to request termination of the program. A front end should shut down the puzzle in response to a zero return. 4.13. midend_colours() ---------------------- float *midend_colours(midend *me, int *ncolours); Returns an array of the colours required by the game, in exactly the same format as that returned by the back end function colours() (section 2.8.6). Front ends should call this function rather than calling the back end's version directly, since the mid-end adds standard customisation facilities. (At the time of writing, those customisation facilities are implemented hackily by means of environment variables, but it's not impossible that they may become more full and formal in future.) 4.14. midend_timer() -------------------- void midend_timer(midend *me, float tplus); If the mid-end has called activate_timer() (section 4.36) to request regular callbacks for purposes of animation or timing, this is the function the front end should call on a regular basis. The argument `tplus' gives the time, in seconds, since the last time either this function was called or activate_timer() was invoked. One of the major purposes of timing in the mid-end is to perform move animation. Therefore, calling this function is very likely to result in calls back to the front end's drawing API. 4.15. midend_get_presets() -------------------------- struct preset_menu *midend_get_presets(midend *me, int *id_limit); Returns a data structure describing this game's collection of preset game parameters, organised into a hierarchical structure of menus and submenus. The return value is a pointer to a data structure containing the following fields (among others, which are not intended for front end use): struct preset_menu { int n_entries; struct preset_menu_entry *entries; /* and other things */ }; Those fields describe the intended contents of one particular menu in the hierarchy. `entries' points to an array of `n_entries' items, each of which is a structure containing the following fields: struct preset_menu_entry { char *title; game_params *params; struct preset_menu *submenu; int id; }; Of these fields, `title' and `id' are present in every entry, giving (respectively) the textual name of the menu item and an integer identifier for it. The integer id will correspond to the one returned by `midend_which_preset' (section 4.16), when that preset is the one selected. The other two fields are mutually exclusive. Each `struct preset_menu_entry' will have one of those fields NULL and the other one non-null. If the menu item is an actual preset, then `params' will point to the set of game parameters that go with the name; if it's a submenu, then `submenu' instead will be non-null, and will point at a subsidiary `struct preset_menu'. The complete hierarchy of these structures is owned by the mid-end, and will be freed when the mid-end is freed. The front end should not attempt to free any of it. The integer identifiers will be allocated densely from 0 upwards, so that it's reasonable for the front end to allocate an array which uses them as indices, if it needs to store information per preset menu item. For this purpose, the front end may pass the second parameter `id_limit' to midend_get_presets as the address of an `int' variable, into which midend_get_presets will write an integer one larger than the largest id number actually used (i.e. the number of elements the front end would need in the array). Submenu-type entries also have integer identifiers. 4.16. midend_which_preset() --------------------------- int midend_which_preset(midend *me); Returns the numeric index of the preset game parameter structure which matches the current game parameters, or a negative number if no preset matches. Front ends could use this to maintain a tick beside one of the items in the menu (or tick the `Custom' option if the return value is less than zero). The returned index value (if non-negative) will match the `id' field of the corresponding struct preset_menu_entry returned by `midend_get_presets()' (section 4.15). 4.17. midend_wants_statusbar() ------------------------------ int midend_wants_statusbar(midend *me); This function returns TRUE if the puzzle has a use for a textual status line (to display score, completion status, currently active tiles, time, or anything else). Front ends should call this function rather than talking directly to the back end. 4.18. midend_get_config() ------------------------- config_item *midend_get_config(midend *me, int which, char **wintitle); Returns a dialog box description for user configuration. On input, which should be set to one of three values, which select which of the various dialog box descriptions is returned: CFG_SETTINGS Requests the GUI parameter configuration box generated by the puzzle itself. This should be used when the user selects `Custom' from the game types menu (or equivalent). The mid-end passes this request on to the back end function configure() (section 2.3.9). CFG_DESC Requests a box suitable for entering a descriptive game ID (and viewing the existing one). The mid-end generates this dialog box description itself. This should be used when the user selects `Specific' from the game menu (or equivalent). CFG_SEED Requests a box suitable for entering a random-seed game ID (and viewing the existing one). The mid-end generates this dialog box description itself. This should be used when the user selects `Random Seed' from the game menu (or equivalent). The returned value is an array of config_items, exactly as described in section 2.3.9. Another returned value is an ASCII string giving a suitable title for the configuration window, in `*wintitle'. Both returned values are dynamically allocated and will need to be freed. The window title can be freed in the obvious way; the config_item array is a slightly complex structure, so a utility function free_cfg() is provided to free it for you. See section 5.3.6. (Of course, you will probably not want to free the config_item array until the dialog box is dismissed, because before then you will probably need to pass it to midend_set_config.) 4.19. midend_set_config() ------------------------- char *midend_set_config(midend *me, int which, config_item *cfg); Passes the mid-end the results of a configuration dialog box. `which' should have the same value which it had when midend_get_config() was called; `cfg' should be the array of `config_item's returned from midend_get_config(), modified to contain the results of the user's editing operations. This function returns NULL on success, or otherwise (if the configuration data was in some way invalid) an ASCII string containing an error message suitable for showing to the user. If the function succeeds, it is likely that the game parameters will have been changed and it is certain that a new game will be requested. The front end should therefore call midend_new_game(), and probably also re-think the window size using midend_size() and eventually perform a refresh using midend_redraw(). 4.20. midend_game_id() ---------------------- char *midend_game_id(midend *me, char *id); Passes the mid-end a string game ID (of any of the valid forms `params', `params:description' or `params#seed') which the mid-end will process and use for the next generated game. This function returns NULL on success, or otherwise (if the configuration data was in some way invalid) an ASCII string containing an error message (not dynamically allocated) suitable for showing to the user. In the event of an error, the mid-end's internal state will be left exactly as it was before the call. If the function succeeds, it is likely that the game parameters will have been changed and it is certain that a new game will be requested. The front end should therefore call midend_new_game(), and probably also re-think the window size using midend_size() and eventually case a refresh using midend_redraw(). 4.21. midend_get_game_id() -------------------------- char *midend_get_game_id(midend *me) Returns a descriptive game ID (i.e. one in the form `params:description') describing the game currently active in the mid- end. The returned string is dynamically allocated. 4.22. midend_get_random_seed() ------------------------------ char *midend_get_random_seed(midend *me) Returns a random game ID (i.e. one in the form `params#seedstring') describing the game currently active in the mid-end, if there is one. If the game was created by entering a description, no random seed will currently exist and this function will return NULL. The returned string, if it is non-NULL, is dynamically allocated. 4.23. midend_can_format_as_text_now() ------------------------------------- int midend_can_format_as_text_now(midend *me); Returns TRUE if the game code is capable of formatting puzzles of the currently selected game type as ASCII. If this returns FALSE, then midend_text_format() (section 4.24) will return NULL. 4.24. midend_text_format() -------------------------- char *midend_text_format(midend *me); Formats the current game's current state as ASCII text suitable for copying to the clipboard. The returned string is dynamically allocated. If the game's `can_format_as_text_ever' flag is FALSE, or if its can_format_as_text_now() function returns FALSE, then this function will return NULL. If the returned string contains multiple lines (which is likely), it will use the normal C line ending convention (\n only). On platforms which use a different line ending convention for data in the clipboard, it is the front end's responsibility to perform the conversion. 4.25. midend_solve() -------------------- char *midend_solve(midend *me); Requests the mid-end to perform a Solve operation. On success, NULL is returned. On failure, an error message (not dynamically allocated) is returned, suitable for showing to the user. The front end can expect its drawing API and/or activate_timer() to be called from within a call to this function. Some back ends require that midend_size() (section 4.6) is called before midend_solve(). 4.26. midend_status() --------------------- int midend_status(midend *me); This function returns +1 if the midend is currently displaying a game in a solved state, -1 if the game is in a permanently lost state, or 0 otherwise. This function just calls the back end's status() function. Front ends may wish to use this as a cue to proactively offer the option of starting a new game. (See section 2.8.9 for more detail about the back end's status() function and discussion of what should count as which status code.) 4.27. midend_can_undo() ----------------------- int midend_can_undo(midend *me); Returns TRUE if the midend is currently in a state where the undo operation is meaningful (i.e. at least one position exists on the undo chain before the present one). Front ends may wish to use this to visually activate and deactivate an undo button. 4.28. midend_can_redo() ----------------------- int midend_can_redo(midend *me); Returns TRUE if the midend is currently in a state where the redo operation is meaningful (i.e. at least one position exists on the redo chain after the present one). Front ends may wish to use this to visually activate and deactivate a redo button. 4.29. midend_serialise() ------------------------ void midend_serialise(midend *me, void (*write)(void *ctx, void *buf, int len), void *wctx); Calling this function causes the mid-end to convert its entire internal state into a long ASCII text string, and to pass that string (piece by piece) to the supplied `write' function. Desktop implementations can use this function to save a game in any state (including half-finished) to a disk file, by supplying a `write' function which is a wrapper on fwrite() (or local equivalent). Other implementations may find other uses for it, such as compressing the large and sprawling mid-end state into a manageable amount of memory when a palmtop application is suspended so that another one can run; in this case write might want to write to a memory buffer rather than a file. There may be other uses for it as well. This function will call back to the supplied `write' function a number of times, with the first parameter (`ctx') equal to `wctx', and the other two parameters pointing at a piece of the output string. 4.30. midend_deserialise() -------------------------- char *midend_deserialise(midend *me, int (*read)(void *ctx, void *buf, int len), void *rctx); This function is the counterpart to midend_serialise(). It calls the supplied read function repeatedly to read a quantity of data, and attempts to interpret that data as a serialised mid-end as output by midend_serialise(). The read function is called with the first parameter (`ctx') equal to `rctx', and should attempt to read `len' bytes of data into the buffer pointed to by `buf'. It should return FALSE on failure or TRUE on success. It should not report success unless it has filled the entire buffer; on platforms which might be reading from a pipe or other blocking data source, `read' is responsible for looping until the whole buffer has been filled. If the de-serialisation operation is successful, the mid-end's internal data structures will be replaced by the results of the load, and NULL will be returned. Otherwise, the mid-end's state will be completely unchanged and an error message (typically some variation on `save file is corrupt') will be returned. As usual, the error message string is not dynamically allocated. If this function succeeds, it is likely that the game parameters will have been changed. The front end should therefore probably re-think the window size using midend_size(), and probably cause a refresh using midend_redraw(). Because each mid-end is tied to a specific game back end, this function will fail if you attempt to read in a save file generated by a different game from the one configured in this mid-end, even if your application is a monolithic one containing all the puzzles. See section 4.31 for a helper function which will allow you to identify a save file before you instantiate your mid-end in the first place. 4.31. identify_game() --------------------- char *identify_game(char **name, int (*read)(void *ctx, void *buf, int len), void *rctx); This function examines a serialised midend stream, of the same kind used by midend_serialise() and midend_deserialise(), and returns the name field of the game back end from which it was saved. You might want this if your front end was a monolithic one containing all the puzzles, and you wanted to be able to load an arbitrary save file and automatically switch to the right game. Probably your next step would be to iterate through gamelist (section 4.33) looking for a game structure whose name field matched the returned string, and give an error if you didn't find one. On success, the return value of this function is NULL, and the game name string is written into *name. The caller should free that string after using it. On failure, *name is NULL, and the return value is an error message (which does not need freeing at all). (This isn't strictly speaking a midend function, since it doesn't accept or return a pointer to a midend. You'd probably call it just _before_ deciding what kind of midend you wanted to instantiate.) 4.32. midend_request_id_changes() --------------------------------- void midend_request_id_changes(midend *me, void (*notify)(void *), void *ctx); This function is called by the front end to request notification by the mid-end when the current game IDs (either descriptive or random-seed) change. This can occur as a result of keypresses ('n' for New Game, for example) or when a puzzle supersedes its game description (see section 2.11.2). After this function is called, any change of the game ids will cause the mid-end to call notify(ctx) after the change. This is for use by puzzles which want to present the game description to the user constantly (e.g. as an HTML hyperlink) instead of only showing it when the user explicitly requests it. This is a function I anticipate few front ends needing to implement, so I make it a callback rather than a static function in order to relieve most front ends of the need to provide an empty implementation. 4.33. Direct reference to the back end structure by the front end ----------------------------------------------------------------- Although _most_ things the front end needs done should be done by calling the mid-end, there are a few situations in which the front end needs to refer directly to the game back end structure. The most obvious of these is - passing the game back end as a parameter to midend_new(). There are a few other back end features which are not wrapped by the mid-end because there didn't seem much point in doing so: - fetching the `name' field to use in window titles and similar - reading the `can_configure', `can_solve' and `can_format_as_text_ever' fields to decide whether to add those items to the menu bar or equivalent - reading the `winhelp_topic' field (Windows only) - the GTK front end provides a `--generate' command-line option which directly calls the back end to do most of its work. This is not really part of the main front end code, though, and I'm not sure it counts. In order to find the game back end structure, the front end does one of two things: - If the particular front end is compiling a separate binary per game, then the back end structure is a global variable with the standard name `thegame': extern const game thegame; - If the front end is compiled as a monolithic application containing all the puzzles together (in which case the preprocessor symbol COMBINED must be defined when compiling most of the code base), then there will be two global variables defined: extern const game *gamelist[]; extern const int gamecount; `gamelist' will be an array of `gamecount' game structures, declared in the automatically constructed source module `list.c'. The application should search that array for the game it wants, probably by reaching into each game structure and looking at its `name' field. 4.34. Mid-end to front-end calls -------------------------------- This section describes the small number of functions which a front end must provide to be called by the mid-end or other standard utility modules. 4.35. get_random_seed() ----------------------- void get_random_seed(void **randseed, int *randseedsize); This function is called by a new mid-end, and also occasionally by game back ends. Its job is to return a piece of data suitable for using as a seed for initialisation of a new `random_state'. On exit, `*randseed' should be set to point at a newly allocated piece of memory containing some seed data, and `*randseedsize' should be set to the length of that data. A simple and entirely adequate implementation is to return a piece of data containing the current system time at the highest conveniently available resolution. 4.36. activate_timer() ---------------------- void activate_timer(frontend *fe); This is called by the mid-end to request that the front end begin calling it back at regular intervals. The timeout interval is left up to the front end; the finer it is, the smoother move animations will be, but the more CPU time will be used. Current front ends use values around 20ms (i.e. 50Hz). After this function is called, the mid-end will expect to receive calls to midend_timer() on a regular basis. 4.37. deactivate_timer() ------------------------ void deactivate_timer(frontend *fe); This is called by the mid-end to request that the front end stop calling midend_timer(). 4.38. fatal() ------------- void fatal(char *fmt, ...); This is called by some utility functions if they encounter a genuinely fatal error such as running out of memory. It is a variadic function in the style of printf(), and is expected to show the formatted error message to the user any way it can and then terminate the application. It must not return. 4.39. frontend_default_colour() ------------------------------- void frontend_default_colour(frontend *fe, float *output); This function expects to be passed a pointer to an array of three floats. It returns the platform's local preferred background colour in those three floats, as red, green and blue values (in that order) ranging from 0.0 to 1.0. This function should only ever be called by the back end function colours() (section 2.8.6). (Thus, it isn't a _midend_-to-frontend function as such, but there didn't seem to be anywhere else particularly good to put it. Sorry.) 5. Utility APIs --------------- This chapter documents a variety of utility APIs provided for the general use of the rest of the Puzzles code. 5.1. Random number generation ----------------------------- Platforms' local random number generators vary widely in quality and seed size. Puzzles therefore supplies its own high-quality random number generator, with the additional advantage of giving the same results if fed the same seed data on different platforms. This allows game random seeds to be exchanged between different ports of Puzzles and still generate the same games. Unlike the ANSI C rand() function, the Puzzles random number generator has an _explicit_ state object called a `random_state'. One of these is managed by each mid-end, for example, and passed to the back end to generate a game with. 5.1.1. random_new() ------------------- random_state *random_new(char *seed, int len); Allocates, initialises and returns a new `random_state'. The input data is used as the seed for the random number stream (i.e. using the same seed at a later time will generate the same stream). The seed data can be any data at all; there is no requirement to use printable ASCII, or NUL-terminated strings, or anything like that. 5.1.2. random_copy() -------------------- random_state *random_copy(random_state *tocopy); Allocates a new `random_state', copies the contents of another `random_state' into it, and returns the new state. If exactly the same sequence of functions is subseqently called on both the copy and the original, the results will be identical. This may be useful for speculatively performing some operation using a given random state, and later replaying that operation precisely. 5.1.3. random_free() -------------------- void random_free(random_state *state); Frees a `random_state'. 5.1.4. random_bits() -------------------- unsigned long random_bits(random_state *state, int bits); Returns a random number from 0 to 2^bits-1 inclusive. `bits' should be between 1 and 32 inclusive. 5.1.5. random_upto() -------------------- unsigned long random_upto(random_state *state, unsigned long limit); Returns a random number from 0 to limit-1 inclusive. 5.1.6. random_state_encode() ---------------------------- char *random_state_encode(random_state *state); Encodes the entire contents of a `random_state' in printable ASCII. Returns a dynamically allocated string containing that encoding. This can subsequently be passed to random_state_decode() to reconstruct the same `random_state'. 5.1.7. random_state_decode() ---------------------------- random_state *random_state_decode(char *input); Decodes a string generated by random_state_encode() and reconstructs an equivalent `random_state' to the one encoded, i.e. it should produce the same stream of random numbers. This function has no error reporting; if you pass it an invalid string it will simply generate an arbitrary random state, which may turn out to be noticeably non-random. 5.1.8. shuffle() ---------------- void shuffle(void *array, int nelts, int eltsize, random_state *rs); Shuffles an array into a random order. The interface is much like ANSI C qsort(), except that there's no need for a compare function. `array' is a pointer to the first element of the array. `nelts' is the number of elements in the array; `eltsize' is the size of a single element (typically measured using `sizeof'). `rs' is a `random_state' used to generate all the random numbers for the shuffling process. 5.2. Presets menu management ---------------------------- The function `midend_get_presets()' (section 4.15) returns a data structure describing a menu hierarchy. Back ends can also choose to provide such a structure to the mid-end, if they want to group their presets hierarchically. To make this easy, there are a few utility functions to construct preset menu structures, and also one intended for front-end use. 5.2.1. preset_menu_new() ------------------------ struct preset_menu *preset_menu_new(void); Allocates a new `struct preset_menu', and initialises it to hold no menu items. 5.2.2. preset_menu_add_submenu() -------------------------------- struct preset_menu *preset_menu_add_submenu (struct preset_menu *parent, char *title); Adds a new submenu to the end of an existing preset menu, and returns a pointer to a newly allocated `struct preset_menu' describing the submenu. The string parameter `title' must be dynamically allocated by the caller. The preset-menu structure will take ownership of it, so the caller must not free it. 5.2.3. preset_menu_add_preset() ------------------------------- void preset_menu_add_preset (struct preset_menu *menu, char *title, game_params *params); Adds a preset game configuration to the end of a preset menu. Both the string parameter `title' and the game parameter structure `params' itself must be dynamically allocated by the caller. The preset- menu structure will take ownership of it, so the caller must not free it. 5.2.4. preset_menu_lookup_by_id() --------------------------------- game_params *preset_menu_lookup_by_id (struct preset_menu *menu, int id); Given a numeric index, searches recursively through a preset menu hierarchy to find the corresponding menu entry, and returns a pointer to its existing `game_params' structure. This function is intended for front end use (but front ends need not use it if they prefer to do things another way). If a front end finds it inconvenient to store anything more than a numeric index alongside each menu item, then this function provides an easy way for the front end to get back the actual game parameters corresponding to a menu item that the user has selected. 5.3. Memory allocation ---------------------- Puzzles has some central wrappers on the standard memory allocation functions, which provide compile-time type checking, and run-time error checking by means of quitting the application if it runs out of memory. This doesn't provide the best possible recovery from memory shortage, but on the other hand it greatly simplifies the rest of the code, because nothing else anywhere needs to worry about NULL returns from allocation. 5.3.1. snew() ------------- var = snew(type); This macro takes a single argument which is a _type name_. It allocates space for one object of that type. If allocation fails it will call fatal() and not return; so if it does return, you can be confident that its return value is non-NULL. The return value is cast to the specified type, so that the compiler will type-check it against the variable you assign it into. Thus, this ensures you don't accidentally allocate memory the size of the wrong type and assign it into a variable of the right one (or vice versa!). 5.3.2. snewn() -------------- var = snewn(n, type); This macro is the array form of snew(). It takes two arguments; the first is a number, and the second is a type name. It allocates space for that many objects of that type, and returns a type-checked non-NULL pointer just as snew() does. 5.3.3. sresize() ---------------- var = sresize(var, n, type); This macro is a type-checked form of realloc(). It takes three arguments: an input memory block, a new size in elements, and a type. It re-sizes the input memory block to a size sufficient to contain that many elements of that type. It returns a type-checked non-NULL pointer, like snew() and snewn(). The input memory block can be NULL, in which case this function will behave exactly like snewn(). (In principle any ANSI-compliant realloc() implementation ought to cope with this, but I've never quite trusted it to work everywhere.) 5.3.4. sfree() -------------- void sfree(void *p); This function is pretty much equivalent to free(). It is provided with a dynamically allocated block, and frees it. The input memory block can be NULL, in which case this function will do nothing. (In principle any ANSI-compliant free() implementation ought to cope with this, but I've never quite trusted it to work everywhere.) 5.3.5. dupstr() --------------- char *dupstr(const char *s); This function dynamically allocates a duplicate of a C string. Like the snew() functions, it guarantees to return non-NULL or not return at all. (Many platforms provide the function strdup(). As well as guaranteeing never to return NULL, my version has the advantage of being defined _everywhere_, rather than inconveniently not quite everywhere.) 5.3.6. free_cfg() ----------------- void free_cfg(config_item *cfg); This function correctly frees an array of `config_item's, including walking the array until it gets to the end and freeing precisely those `sval' fields which are expected to be dynamically allocated. (See section 2.3.9 for details of the `config_item' structure.) 5.4. Sorted and counted tree functions -------------------------------------- Many games require complex algorithms for generating random puzzles, and some require moderately complex algorithms even during play. A common requirement during these algorithms is for a means of maintaining sorted or unsorted lists of items, such that items can be removed and added conveniently. For general use, Puzzles provides the following set of functions which maintain 2-3-4 trees in memory. (A 2-3-4 tree is a balanced tree structure, with the property that all lookups, insertions, deletions, splits and joins can be done in O(log N) time.) All these functions expect you to be storing a tree of `void *' pointers. You can put anything you like in those pointers. By the use of per-node element counts, these tree structures have the slightly unusual ability to look elements up by their numeric index within the list represented by the tree. This means that they can be used to store an unsorted list (in which case, every time you insert a new element, you must explicitly specify the position where you wish to insert it). They can also do numeric lookups in a sorted tree, which might be useful for (for example) tracking the median of a changing data set. As well as storing sorted lists, these functions can be used for storing `maps' (associative arrays), by defining each element of a tree to be a (key, value) pair. 5.4.1. newtree234() ------------------- tree234 *newtree234(cmpfn234 cmp); Creates a new empty tree, and returns a pointer to it. The parameter `cmp' determines the sorting criterion on the tree. Its prototype is typedef int (*cmpfn234)(void *, void *); If you want a sorted tree, you should provide a function matching this prototype, which returns like strcmp() does (negative if the first argument is smaller than the second, positive if it is bigger, zero if they compare equal). In this case, the function addpos234() will not be usable on your tree (because all insertions must respect the sorting order). If you want an unsorted tree, pass NULL. In this case you will not be able to use either add234() or del234(), or any other function such as find234() which depends on a sorting order. Your tree will become something more like an array, except that it will efficiently support insertion and deletion as well as lookups by numeric index. 5.4.2. freetree234() -------------------- void freetree234(tree234 *t); Frees a tree. This function will not free the _elements_ of the tree (because they might not be dynamically allocated, or you might be storing the same set of elements in more than one tree); it will just free the tree structure itself. If you want to free all the elements of a tree, you should empty it before passing it to freetree234(), by means of code along the lines of while ((element = delpos234(tree, 0)) != NULL) sfree(element); /* or some more complicated free function */ 5.4.3. add234() --------------- void *add234(tree234 *t, void *e); Inserts a new element `e' into the tree `t'. This function expects the tree to be sorted; the new element is inserted according to the sort order. If an element comparing equal to `e' is already in the tree, then the insertion will fail, and the return value will be the existing element. Otherwise, the insertion succeeds, and `e' is returned. 5.4.4. addpos234() ------------------ void *addpos234(tree234 *t, void *e, int index); Inserts a new element into an unsorted tree. Since there is no sorting order to dictate where the new element goes, you must specify where you want it to go. Setting `index' to zero puts the new element right at the start of the list; setting `index' to the current number of elements in the tree puts the new element at the end. Return value is `e', in line with add234() (although this function cannot fail except by running out of memory, in which case it will bomb out and die rather than returning an error indication). 5.4.5. index234() ----------------- void *index234(tree234 *t, int index); Returns a pointer to the `index'th element of the tree, or NULL if `index' is out of range. Elements of the tree are numbered from zero. 5.4.6. find234() ---------------- void *find234(tree234 *t, void *e, cmpfn234 cmp); Searches for an element comparing equal to `e' in a sorted tree. If `cmp' is NULL, the tree's ordinary comparison function will be used to perform the search. However, sometimes you don't want that; suppose, for example, each of your elements is a big structure containing a `char *' name field, and you want to find the element with a given name. You _could_ achieve this by constructing a fake element structure, setting its name field appropriately, and passing it to find234(), but you might find it more convenient to pass _just_ a name string to find234(), supplying an alternative comparison function which expects one of its arguments to be a bare name and the other to be a large structure containing a name field. Therefore, if `cmp' is not NULL, then it will be used to compare `e' to elements of the tree. The first argument passed to `cmp' will always be `e'; the second will be an element of the tree. (See section 5.4.1 for the definition of the `cmpfn234' function pointer type.) The returned value is the element found, or NULL if the search is unsuccessful. 5.4.7. findrel234() ------------------- void *findrel234(tree234 *t, void *e, cmpfn234 cmp, int relation); This function is like find234(), but has the additional ability to do a _relative_ search. The additional parameter `relation' can be one of the following values: REL234_EQ Find only an element that compares equal to `e'. This is exactly the behaviour of find234(). REL234_LT Find the greatest element that compares strictly less than `e'. `e' may be NULL, in which case it finds the greatest element in the whole tree (which could also be done by index234(t, count234(t)-1)). REL234_LE Find the greatest element that compares less than or equal to `e'. (That is, find an element that compares equal to `e' if possible, but failing that settle for something just less than it.) REL234_GT Find the smallest element that compares strictly greater than `e'. `e' may be NULL, in which case it finds the smallest element in the whole tree (which could also be done by index234(t, 0)). REL234_GE Find the smallest element that compares greater than or equal to `e'. (That is, find an element that compares equal to `e' if possible, but failing that settle for something just bigger than it.) Return value, as before, is the element found or NULL if no element satisfied the search criterion. 5.4.8. findpos234() ------------------- void *findpos234(tree234 *t, void *e, cmpfn234 cmp, int *index); This function is like find234(), but has the additional feature of returning the index of the element found in the tree; that index is written to `*index' in the event of a successful search (a non-NULL return value). `index' may be NULL, in which case this function behaves exactly like find234(). 5.4.9. findrelpos234() ---------------------- void *findrelpos234(tree234 *t, void *e, cmpfn234 cmp, int relation, int *index); This function combines all the features of findrel234() and findpos234(). 5.4.10. del234() ---------------- void *del234(tree234 *t, void *e); Finds an element comparing equal to `e' in the tree, deletes it, and returns it. The input tree must be sorted. The element found might be `e' itself, or might merely compare equal to it. Return value is NULL if no such element is found. 5.4.11. delpos234() ------------------- void *delpos234(tree234 *t, int index); Deletes the element at position `index' in the tree, and returns it. Return value is NULL if the index is out of range. 5.4.12. count234() ------------------ int count234(tree234 *t); Returns the number of elements currently in the tree. 5.4.13. splitpos234() --------------------- tree234 *splitpos234(tree234 *t, int index, int before); Splits the input tree into two pieces at a given position, and creates a new tree containing all the elements on one side of that position. If `before' is TRUE, then all the items at or after position `index' are left in the input tree, and the items before that point are returned in the new tree. Otherwise, the reverse happens: all the items at or after `index' are moved into the new tree, and those before that point are left in the old one. If `index' is equal to 0 or to the number of elements in the input tree, then one of the two trees will end up empty (and this is not an error condition). If `index' is further out of range in either direction, the operation will fail completely and return NULL. This operation completes in O(log N) time, no matter how large the tree or how balanced or unbalanced the split. 5.4.14. split234() ------------------ tree234 *split234(tree234 *t, void *e, cmpfn234 cmp, int rel); Splits a sorted tree according to its sort order. `rel' can be any of the relation constants described in section 5.4.7, _except_ for REL234_EQ. All the elements having that relation to `e' will be transferred into the new tree; the rest will be left in the old one. The parameter `cmp' has the same semantics as it does in find234(): if it is not NULL, it will be used in place of the tree's own comparison function when comparing elements to `e', in such a way that `e' itself is always the first of its two operands. Again, this operation completes in O(log N) time, no matter how large the tree or how balanced or unbalanced the split. 5.4.15. join234() ----------------- tree234 *join234(tree234 *t1, tree234 *t2); Joins two trees together by concatenating the lists they represent. All the elements of `t2' are moved into `t1', in such a way that they appear _after_ the elements of `t1'. The tree `t2' is freed; the return value is `t1'. If you apply this function to a sorted tree and it violates the sort order (i.e. the smallest element in `t2' is smaller than or equal to the largest element in `t1'), the operation will fail and return NULL. This operation completes in O(log N) time, no matter how large the trees being joined together. 5.4.16. join234r() ------------------ tree234 *join234r(tree234 *t1, tree234 *t2); Joins two trees together in exactly the same way as join234(), but this time the combined tree is returned in `t2', and `t1' is destroyed. The elements in `t1' still appear before those in `t2'. Again, this operation completes in O(log N) time, no matter how large the trees being joined together. 5.4.17. copytree234() --------------------- tree234 *copytree234(tree234 *t, copyfn234 copyfn, void *copyfnstate); Makes a copy of an entire tree. If `copyfn' is NULL, the tree will be copied but the elements will not be; i.e. the new tree will contain pointers to exactly the same physical elements as the old one. If you want to copy each actual element during the operation, you can instead pass a function in `copyfn' which makes a copy of each element. That function has the prototype typedef void *(*copyfn234)(void *state, void *element); and every time it is called, the `state' parameter will be set to the value you passed in as `copyfnstate'. 5.5. Miscellaneous utility functions and macros ----------------------------------------------- This section contains all the utility functions which didn't sensibly fit anywhere else. 5.5.1. TRUE and FALSE --------------------- The main Puzzles header file defines the macros TRUE and FALSE, which are used throughout the code in place of 1 and 0 (respectively) to indicate that the values are in a boolean context. For code base consistency, I'd prefer it if submissions of new code followed this convention as well. 5.5.2. max() and min() ---------------------- The main Puzzles header file defines the pretty standard macros max() and min(), each of which is given two arguments and returns the one which compares greater or less respectively. These macros may evaluate their arguments multiple times. Avoid side effects. 5.5.3. PI --------- The main Puzzles header file defines a macro PI which expands to a floating-point constant representing pi. (I've never understood why ANSI's doesn't define this. It'd be so useful!) 5.5.4. obfuscate_bitmap() ------------------------- void obfuscate_bitmap(unsigned char *bmp, int bits, int decode); This function obscures the contents of a piece of data, by cryptographic methods. It is useful for games of hidden information (such as Mines, Guess or Black Box), in which the game ID theoretically reveals all the information the player is supposed to be trying to guess. So in order that players should be able to send game IDs to one another without accidentally spoiling the resulting game by looking at them, these games obfuscate their game IDs using this function. Although the obfuscation function is cryptographic, it cannot properly be called encryption because it has no key. Therefore, anybody motivated enough can re-implement it, or hack it out of the Puzzles source, and strip the obfuscation off one of these game IDs to see what lies beneath. (Indeed, they could usually do it much more easily than that, by entering the game ID into their own copy of the puzzle and hitting Solve.) The aim is not to protect against a determined attacker; the aim is simply to protect people who wanted to play the game honestly from _accidentally_ spoiling their own fun. The input argument `bmp' points at a piece of memory to be obfuscated. `bits' gives the length of the data. Note that that length is in _bits_ rather than bytes: if you ask for obfuscation of a partial number of bytes, then you will get it. Bytes are considered to be used from the top down: thus, for example, setting `bits' to 10 will cover the whole of bmp[0] and the _top two_ bits of bmp[1]. The remainder of a partially used byte is undefined (i.e. it may be corrupted by the function). The parameter `decode' is FALSE for an encoding operation, and TRUE for a decoding operation. Each is the inverse of the other. (There's no particular reason you shouldn't obfuscate by decoding and restore cleartext by encoding, if you really wanted to; it should still work.) The input bitmap is processed in place. 5.5.5. bin2hex() ---------------- char *bin2hex(const unsigned char *in, int inlen); This function takes an input byte array and converts it into an ASCII string encoding those bytes in (lower-case) hex. It returns a dynamically allocated string containing that encoding. This function is useful for encoding the result of obfuscate_bitmap() in printable ASCII for use in game IDs. 5.5.6. hex2bin() ---------------- unsigned char *hex2bin(const char *in, int outlen); This function takes an ASCII string containing hex digits, and converts it back into a byte array of length `outlen'. If there aren't enough hex digits in the string, the contents of the resulting array will be undefined. This function is the inverse of bin2hex(). 5.5.7. game_mkhighlight() ------------------------- void game_mkhighlight(frontend *fe, float *ret, int background, int highlight, int lowlight); It's reasonably common for a puzzle game's graphics to use highlights and lowlights to indicate `raised' or `lowered' sections. Fifteen, Sixteen and Twiddle are good examples of this. Puzzles using this graphical style are running a risk if they just use whatever background colour is supplied to them by the front end, because that background colour might be too light to see any highlights on at all. (In particular, it's not unheard of for the front end to specify a default background colour of white.) Therefore, such puzzles can call this utility function from their colours() routine (section 2.8.6). You pass it your front end handle, a pointer to the start of your return array, and three colour indices. It will: - call frontend_default_colour() (section 4.39) to fetch the front end's default background colour - alter the brightness of that colour if it's unsuitable - define brighter and darker variants of the colour to be used as highlights and lowlights - write those results into the relevant positions in the `ret' array. Thus, ret[background*3] to ret[background*3+2] will be set to RGB values defining a sensible background colour, and similary `highlight' and `lowlight' will be set to sensible colours. 6. How to write a new puzzle ---------------------------- This chapter gives a guide to how to actually write a new puzzle: where to start, what to do first, how to solve common problems. The previous chapters have been largely composed of facts. This one is mostly advice. 6.1. Choosing a puzzle ---------------------- Before you start writing a puzzle, you have to choose one. Your taste in puzzle games is up to you, of course; and, in fact, you're probably reading this guide because you've _already_ thought of a game you want to write. But if you want to get it accepted into the official Puzzles distribution, then there's a criterion it has to meet. The current Puzzles editorial policy is that all games should be _fair_. A fair game is one which a player can only fail to complete through demonstrable lack of skill - that is, such that a better player in the same situation would have _known_ to do something different. For a start, that means every game presented to the user must have _at least one solution_. Giving the unsuspecting user a puzzle which is actually impossible is not acceptable. (There is an exception: if the user has selected some non-default option which is clearly labelled as potentially unfair, _then_ you're allowed to generate possibly insoluble puzzles, because the user isn't unsuspecting any more. Same Game and Mines both have options of this type.) Also, this actually _rules out_ games such as Klondike, or the normal form of Mahjong Solitaire. Those games have the property that even if there is a solution (i.e. some sequence of moves which will get from the start state to the solved state), the player doesn't necessarily have enough information to _find_ that solution. In both games, it is possible to reach a dead end because you had an arbitrary choice to make and made it the wrong way. This violates the fairness criterion, because a better player couldn't have known they needed to make the other choice. (GNOME has a variant on Mahjong Solitaire which makes it fair: there is a Shuffle operation which randomly permutes all the remaining tiles without changing their positions, which allows you to get out of a sticky situation. Using this operation adds a 60-second penalty to your solution time, so it's to the player's advantage to try to minimise the chance of having to use it. It's still possible to render the game uncompletable if you end up with only two tiles vertically stacked, but that's easy to foresee and avoid using a shuffle operation. This form of the game _is_ fair. Implementing it in Puzzles would require an infrastructure change so that the back end could communicate time penalties to the mid-end, but that would be easy enough.) Providing a _unique_ solution is a little more negotiable; it depends on the puzzle. Solo would have been of unacceptably low quality if it didn't always have a unique solution, whereas Twiddle inherently has multiple solutions by its very nature and it would have been meaningless to even _suggest_ making it uniquely soluble. Somewhere in between, Flip could reasonably be made to have unique solutions (by enforcing a zero- dimension kernel in every generated matrix) but it doesn't seem like a serious quality problem that it doesn't. Of course, you don't _have_ to care about all this. There's nothing stopping you implementing any puzzle you want to if you're happy to maintain your puzzle yourself, distribute it from your own web site, fork the Puzzles code completely, or anything like that. It's free software; you can do what you like with it. But any game that you want to be accepted into _my_ Puzzles code base has to satisfy the fairness criterion, which means all randomly generated puzzles must have a solution (unless the user has deliberately chosen otherwise) and it must be possible _in theory_ to find that solution without having to guess. 6.2. Getting started -------------------- The simplest way to start writing a new puzzle is to copy `nullgame.c'. This is a template puzzle source file which does almost nothing, but which contains all the back end function prototypes and declares the back end data structure correctly. It is built every time the rest of Puzzles is built, to ensure that it doesn't get out of sync with the code and remains buildable. So start by copying `nullgame.c' into your new source file. Then you'll gradually add functionality until the very boring Null Game turns into your real game. Next you'll need to add your puzzle to the Makefiles, in order to compile it conveniently. _Do not edit the Makefiles_: they are created automatically by the script `mkfiles.pl', from the file called `Recipe'. Edit `Recipe', and then re-run `mkfiles.pl'. Also, don't forget to add your puzzle to `list.c': if you don't, then it will still run fine on platforms which build each puzzle separately, but Mac OS X and other monolithic platforms will not include your new puzzle in their single binary. Once your source file is building, you can move on to the fun bit. 6.2.1. Puzzle generation ------------------------ Randomly generating instances of your puzzle is almost certain to be the most difficult part of the code, and also the task with the highest chance of turning out to be completely infeasible. Therefore I strongly recommend doing it _first_, so that if it all goes horribly wrong you haven't wasted any more time than you absolutely had to. What I usually do is to take an unmodified `nullgame.c', and start adding code to new_game_desc() which tries to generate a puzzle instance and print it out using printf(). Once that's working, _then_ I start connecting it up to the return value of new_game_desc(), populating other structures like `game_params', and generally writing the rest of the source file. There are many ways to generate a puzzle which is known to be soluble. In this section I list all the methods I currently know of, in case any of them can be applied to your puzzle. (Not all of these methods will work, or in some cases even make sense, for all puzzles.) Some puzzles are mathematically tractable, meaning you can work out in advance which instances are soluble. Sixteen, for example, has a parity constraint in some settings which renders exactly half the game space unreachable, but it can be mathematically proved that any position not in that half _is_ reachable. Therefore, Sixteen's grid generation simply consists of selecting at random from a well defined subset of the game space. Cube in its default state is even easier: _every_ possible arrangement of the blue squares and the cube's starting position is soluble! Another option is to redefine what you mean by `soluble'. Black Box takes this approach. There are layouts of balls in the box which are completely indistinguishable from one another no matter how many beams you fire into the box from which angles, which would normally be grounds for declaring those layouts unfair; but fortunately, detecting that indistinguishability is computationally easy. So Black Box doesn't demand that your ball placements match its own; it merely demands that your ball placements be _indistinguishable_ from the ones it was thinking of. If you have an ambiguous puzzle, then any of the possible answers is considered to be a solution. Having redefined the rules in that way, any puzzle is soluble again. Those are the simple techniques. If they don't work, you have to get cleverer. One way to generate a soluble puzzle is to start from the solved state and make inverse moves until you reach a starting state. Then you know there's a solution, because you can just list the inverse moves you made and make them in the opposite order to return to the solved state. This method can be simple and effective for puzzles where you get to decide what's a starting state and what's not. In Pegs, for example, the generator begins with one peg in the centre of the board and makes inverse moves until it gets bored; in this puzzle, valid inverse moves are easy to detect, and _any_ state that's reachable from the solved state by inverse moves is a reasonable starting position. So Pegs just continues making inverse moves until the board satisfies some criteria about extent and density, and then stops and declares itself done. For other puzzles, it can be a lot more difficult. Same Game uses this strategy too, and it's lucky to get away with it at all: valid inverse moves aren't easy to find (because although it's easy to insert additional squares in a Same Game position, it's difficult to arrange that _after_ the insertion they aren't adjacent to any other squares of the same colour), so you're constantly at risk of running out of options and having to backtrack or start again. Also, Same Game grids never start off half-empty, which means you can't just stop when you run out of moves - you have to find a way to fill the grid up _completely_. The other way to generate a puzzle that's soluble is to start from the other end, and actually write a _solver_. This tends to ensure that a puzzle has a _unique_ solution over and above having a solution at all, so it's a good technique to apply to puzzles for which that's important. One theoretical drawback of generating soluble puzzles by using a solver is that your puzzles are restricted in difficulty to those which the solver can handle. (Most solvers are not fully general: many sets of puzzle rules are NP-complete or otherwise nasty, so most solvers can only handle a subset of the theoretically soluble puzzles.) It's been my experience in practice, however, that this usually isn't a problem; computers are good at very different things from humans, and what the computer thinks is nice and easy might still be pleasantly challenging for a human. For example, when solving Dominosa puzzles I frequently find myself using a variety of reasoning techniques that my solver doesn't know about; in principle, therefore, I should be able to solve the puzzle using only those techniques it _does_ know about, but this would involve repeatedly searching the entire grid for the one simple deduction I can make. Computers are good at this sort of exhaustive search, but it's been my experience that human solvers prefer to do more complex deductions than to spend ages searching for simple ones. So in many cases I don't find my own playing experience to be limited by the restrictions on the solver. (This isn't _always_ the case. Solo is a counter-example; generating Solo puzzles using a simple solver does lead to qualitatively easier puzzles. Therefore I had to make the Solo solver rather more advanced than most of them.) There are several different ways to apply a solver to the problem of generating a soluble puzzle. I list a few of them below. The simplest approach is brute force: randomly generate a puzzle, use the solver to see if it's soluble, and if not, throw it away and try again until you get lucky. This is often a viable technique if all else fails, but it tends not to scale well: for many puzzle types, the probability of finding a uniquely soluble instance decreases sharply as puzzle size goes up, so this technique might work reasonably fast for small puzzles but take (almost) forever at larger sizes. Still, if there's no other alternative it can be usable: Pattern and Dominosa both use this technique. (However, Dominosa has a means of tweaking the randomly generated grids to increase the _probability_ of them being soluble, by ruling out one of the most common ambiguous cases. This improved generation speed by over a factor of 10 on the highest preset!) An approach which can be more scalable involves generating a grid and then tweaking it to make it soluble. This is the technique used by Mines and also by Net: first a random puzzle is generated, and then the solver is run to see how far it gets. Sometimes the solver will get stuck; when that happens, examine the area it's having trouble with, and make a small random change in that area to allow it to make more progress. Continue solving (possibly even without restarting the solver), tweaking as necessary, until the solver finishes. Then restart the solver from the beginning to ensure that the tweaks haven't caused new problems in the process of solving old ones (which can sometimes happen). This strategy works well in situations where the usual solver failure mode is to get stuck in an easily localised spot. Thus it works well for Net and Mines, whose most common failure mode tends to be that most of the grid is fine but there are a few widely separated ambiguous sections; but it would work less well for Dominosa, in which the way you get stuck is to have scoured the whole grid and not found anything you can deduce _anywhere_. Also, it relies on there being a low probability that tweaking the grid introduces a new problem at the same time as solving the old one; Mines and Net also have the property that most of their deductions are local, so that it's very unlikely for a tweak to affect something half way across the grid from the location where it was applied. In Dominosa, by contrast, a lot of deductions use information about half the grid (`out of all the sixes, only one is next to a three', which can depend on the values of up to 32 of the 56 squares in the default setting!), so this tweaking strategy would be rather less likely to work well. A more specialised strategy is that used in Solo and Slant. These puzzles have the property that they derive their difficulty from not presenting all the available clues. (In Solo's case, if all the possible clues were provided then the puzzle would already be solved; in Slant it would still require user action to fill in the lines, but it would present no challenge at all). Therefore, a simple generation technique is to leave the decision of which clues to provide until the last minute. In other words, first generate a random _filled_ grid with all possible clues present, and then gradually remove clues for as long as the solver reports that it's still soluble. Unlike the methods described above, this technique _cannot_ fail - once you've got a filled grid, nothing can stop you from being able to convert it into a viable puzzle. However, it wouldn't even be meaningful to apply this technique to (say) Pattern, in which clues can never be left out, so the only way to affect the set of clues is by altering the solution. (Unfortunately, Solo is complicated by the need to provide puzzles at varying difficulty levels. It's easy enough to generate a puzzle of _at most_ a given level of difficulty; you just have a solver with configurable intelligence, and you set it to a given level and apply the above technique, thus guaranteeing that the resulting grid is solvable by someone with at most that much intelligence. However, generating a puzzle of _at least_ a given level of difficulty is rather harder; if you go for _at most_ Intermediate level, you're likely to find that you've accidentally generated a Trivial grid a lot of the time, because removing just one number is sufficient to take the puzzle from Trivial straight to Ambiguous. In that situation Solo has no remaining options but to throw the puzzle away and start again.) A final strategy is to use the solver _during_ puzzle construction: lay out a bit of the grid, run the solver to see what it allows you to deduce, and then lay out a bit more to allow the solver to make more progress. There are articles on the web that recommend constructing Sudoku puzzles by this method (which is completely the opposite way round to how Solo does it); for Sudoku it has the advantage that you get to specify your clue squares in advance (so you can have them make pretty patterns). Rectangles uses a strategy along these lines. First it generates a grid by placing the actual rectangles; then it has to decide where in each rectangle to place a number. It uses a solver to help it place the numbers in such a way as to ensure a unique solution. It does this by means of running a test solver, but it runs the solver _before_ it's placed any of the numbers - which means the solver must be capable of coping with uncertainty about exactly where the numbers are! It runs the solver as far as it can until it gets stuck; then it narrows down the possible positions of a number in order to allow the solver to make more progress, and so on. Most of the time this process terminates with the grid fully solved, at which point any remaining number-placement decisions can be made at random from the options not so far ruled out. Note that unlike the Net/Mines tweaking strategy described above, this algorithm does not require a checking run after it completes: if it finishes successfully at all, then it has definitely produced a uniquely soluble puzzle. Most of the strategies described above are not 100% reliable. Each one has a failure rate: every so often it has to throw out the whole grid and generate a fresh one from scratch. (Solo's strategy would be the exception, if it weren't for the need to provide configurable difficulty levels.) Occasional failures are not a fundamental problem in this sort of work, however: it's just a question of dividing the grid generation time by the success rate (if it takes 10ms to generate a candidate grid and 1/5 of them work, then it will take 50ms on average to generate a viable one), and seeing whether the expected time taken to _successfully_ generate a puzzle is unacceptably slow. Dominosa's generator has a very low success rate (about 1 out of 20 candidate grids turn out to be usable, and if you think _that's_ bad then go and look at the source code and find the comment showing what the figures were before the generation-time tweaks!), but the generator itself is very fast so this doesn't matter. Rectangles has a slower generator, but fails well under 50% of the time. So don't be discouraged if you have an algorithm that doesn't always work: if it _nearly_ always works, that's probably good enough. The one place where reliability is important is that your algorithm must never produce false positives: it must not claim a puzzle is soluble when it isn't. It can produce false negatives (failing to notice that a puzzle is soluble), and it can fail to generate a puzzle at all, provided it doesn't do either so often as to become slow. One last piece of advice: for grid-based puzzles, when writing and testing your generation algorithm, it's almost always a good idea _not_ to test it initially on a grid that's square (i.e. w==h), because if the grid is square then you won't notice if you mistakenly write `h' instead of `w' (or vice versa) somewhere in the code. Use a rectangular grid for testing, and any size of grid will be likely to work after that. 6.2.2. Designing textual description formats -------------------------------------------- Another aspect of writing a puzzle which is worth putting some thought into is the design of the various text description formats: the format of the game parameter encoding, the game description encoding, and the move encoding. The first two of these should be reasonably intuitive for a user to type in; so provide some flexibility where possible. Suppose, for example, your parameter format consists of two numbers separated by an `x' to specify the grid dimensions (`10x10' or `20x15'), and then has some suffixes to specify other aspects of the game type. It's almost always a good idea in this situation to arrange that decode_params() can handle the suffixes appearing in any order, even if encode_params() only ever generates them in one order. These formats will also be expected to be reasonably stable: users will expect to be able to exchange game IDs with other users who aren't running exactly the same version of your game. So make them robust and stable: don't build too many assumptions into the game ID format which will have to be changed every time something subtle changes in the puzzle code. 6.3. Common how-to questions ---------------------------- This section lists some common things people want to do when writing a puzzle, and describes how to achieve them within the Puzzles framework. 6.3.1. Drawing objects at only one position ------------------------------------------- A common phenomenon is to have an object described in the `game_state' or the `game_ui' which can only be at one position. A cursor - probably specified in the `game_ui' - is a good example. In the `game_ui', it would _obviously_ be silly to have an array covering the whole game grid with a boolean flag stating whether the cursor was at each position. Doing that would waste space, would make it difficult to find the cursor in order to do anything with it, and would introduce the potential for synchronisation bugs in which you ended up with two cursors or none. The obviously sensible way to store a cursor in the `game_ui' is to have fields directly encoding the cursor's coordinates. However, it is a mistake to assume that the same logic applies to the `game_drawstate'. If you replicate the cursor position fields in the draw state, the redraw code will get very complicated. In the draw state, in fact, it _is_ probably the right thing to have a cursor flag for every position in the grid. You probably have an array for the whole grid in the drawstate already (stating what is currently displayed in the window at each position); the sensible approach is to add a `cursor' flag to each element of that array. Then the main redraw loop will look something like this (pseudo-code): for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { int value = state->symbol_at_position[y][x]; if (x == ui->cursor_x && y == ui->cursor_y) value |= CURSOR; if (ds->symbol_at_position[y][x] != value) { symbol_drawing_subroutine(dr, ds, x, y, value); ds->symbol_at_position[y][x] = value; } } } This loop is very simple, pretty hard to get wrong, and _automatically_ deals both with erasing the previous cursor and drawing the new one, with no special case code required. This type of loop is generally a sensible way to write a redraw function, in fact. The best thing is to ensure that the information stored in the draw state for each position tells you _everything_ about what was drawn there. A good way to ensure that is to pass precisely the same information, and _only_ that information, to a subroutine that does the actual drawing; then you know there's no additional information which affects the drawing but which you don't notice changes in. 6.3.2. Implementing a keyboard-controlled cursor ------------------------------------------------ It is often useful to provide a keyboard control method in a basically mouse-controlled game. A keyboard-controlled cursor is best implemented by storing its location in the `game_ui' (since if it were in the `game_state' then the user would have to separately undo every cursor move operation). So the procedure would be: - Put cursor position fields in the `game_ui'. - interpret_move() responds to arrow keys by modifying the cursor position fields and returning "". - interpret_move() responds to some sort of fire button by actually performing a move based on the current cursor location. - You might want an additional `game_ui' field stating whether the cursor is currently visible, and having it disappear when a mouse action occurs (so that it doesn't clutter the display when not actually in use). - You might also want to automatically hide the cursor in changed_state() when the current game state changes to one in which there is no move to make (which is the case in some types of completed game). - redraw() draws the cursor using the technique described in section 6.3.1. 6.3.3. Implementing draggable sprites ------------------------------------- Some games have a user interface which involves dragging some sort of game element around using the mouse. If you need to show a graphic moving smoothly over the top of other graphics, use a blitter (see section 3.1.13 for the blitter API) to save the background underneath it. The typical scenario goes: - Have a blitter field in the `game_drawstate'. - Set the blitter field to NULL in the game's new_drawstate() function, since you don't yet know how big the piece of saved background needs to be. - In the game's set_size() function, once you know the size of the object you'll be dragging around the display and hence the required size of the blitter, actually allocate the blitter. - In free_drawstate(), free the blitter if it's not NULL. - In interpret_move(), respond to mouse-down and mouse-drag events by updating some fields in the game_ui which indicate that a drag is in progress. - At the _very end_ of redraw(), after all other drawing has been done, draw the moving object if there is one. First save the background under the object in the blitter; then set a clip rectangle covering precisely the area you just saved (just in case anti-aliasing or some other error causes your drawing to go beyond the area you saved). Then draw the object, and call unclip(). Finally, set a flag in the game_drawstate that indicates that the blitter needs restoring. - At the very start of redraw(), before doing anything else at all, check the flag in the game_drawstate, and if it says the blitter needs restoring then restore it. (Then clear the flag, so that this won't happen again in the next redraw if no moving object is drawn this time.) This way, you will be able to write the rest of the redraw function completely ignoring the dragged object, as if it were floating above your bitmap and being completely separate. 6.3.4. Sharing large invariant data between all game states ----------------------------------------------------------- In some puzzles, there is a large amount of data which never changes between game states. The array of numbers in Dominosa is a good example. You _could_ dynamically allocate a copy of that array in every `game_state', and have dup_game() make a fresh copy of it for every new `game_state'; but it would waste memory and time. A more efficient way is to use a reference-counted structure. - Define a structure type containing the data in question, and also containing an integer reference count. - Have a field in `game_state' which is a pointer to this structure. - In new_game(), when creating a fresh game state at the start of a new game, create an instance of this structure, initialise it with the invariant data, and set its reference count to 1. - In dup_game(), rather than making a copy of the structure for the new game state, simply set the new game state to point at the same copy of the structure, and increment its reference count. - In free_game(), decrement the reference count in the structure pointed to by the game state; if the count reaches zero, free the structure. This way, the invariant data will persist for only as long as it's genuinely needed; _as soon_ as the last game state for a particular puzzle instance is freed, the invariant data for that puzzle will vanish as well. Reference counting is a very efficient form of garbage collection, when it works at all. (Which it does in this instance, of course, because there's no possibility of circular references.) 6.3.5. Implementing multiple types of flash ------------------------------------------- In some games you need to flash in more than one different way. Mines, for example, flashes white when you win, and flashes red when you tread on a mine and die. The simple way to do this is: - Have a field in the `game_ui' which describes the type of flash. - In flash_length(), examine the old and new game states to decide whether a flash is required and what type. Write the type of flash to the `game_ui' field whenever you return non-zero. - In redraw(), when you detect that `flash_time' is non-zero, examine the field in `game_ui' to decide which type of flash to draw. redraw() will never be called with `flash_time' non-zero unless flash_length() was first called to tell the mid-end that a flash was required; so whenever redraw() notices that `flash_time' is non-zero, you can be sure that the field in `game_ui' is correctly set. 6.3.6. Animating game moves --------------------------- A number of puzzle types benefit from a quick animation of each move you make. For some games, such as Fifteen, this is particularly easy. Whenever redraw() is called with `oldstate' non-NULL, Fifteen simply compares the position of each tile in the two game states, and if the tile is not in the same place then it draws it some fraction of the way from its old position to its new position. This method copes automatically with undo. Other games are less obvious. In Sixteen, for example, you can't just draw each tile a fraction of the way from its old to its new position: if you did that, the end tile would zip very rapidly past all the others to get to the other end and that would look silly. (Worse, it would look inconsistent if the end tile was drawn on top going one way and on the bottom going the other way.) A useful trick here is to define a field or two in the game state that indicates what the last move was. - Add a `last move' field to the `game_state' (or two or more fields if the move is complex enough to need them). - new_game() initialises this field to a null value for a new game state. - execute_move() sets up the field to reflect the move it just performed. - redraw() now needs to examine its `dir' parameter. If `dir' is positive, it determines the move being animated by looking at the last-move field in `newstate'; but if `dir' is negative, it has to look at the last-move field in `oldstate', and invert whatever move it finds there. Note also that Sixteen needs to store the _direction_ of the move, because you can't quite determine it by examining the row or column in question. You can in almost all cases, but when the row is precisely two squares long it doesn't work since a move in either direction looks the same. (You could argue that since moving a 2-element row left and right has the same effect, it doesn't matter which one you animate; but in fact it's very disorienting to click the arrow left and find the row moving right, and almost as bad to undo a move to the right and find the game animating _another_ move to the right.) 6.3.7. Animating drag operations -------------------------------- In Untangle, moves are made by dragging a node from an old position to a new position. Therefore, at the time when the move is initially made, it should not be animated, because the node has already been dragged to the right place and doesn't need moving there. However, it's nice to animate the same move if it's later undone or redone. This requires a bit of fiddling. The obvious approach is to have a flag in the `game_ui' which inhibits move animation, and to set that flag in interpret_move(). The question is, when would the flag be reset again? The obvious place to do so is changed_state(), which will be called once per move. But it will be called _before_ anim_length(), so if it resets the flag then anim_length() will never see the flag set at all. The solution is to have _two_ flags in a queue. - Define two flags in `game_ui'; let's call them `current' and `next'. - Set both to FALSE in `new_ui()'. - When a drag operation completes in interpret_move(), set the `next' flag to TRUE. - Every time changed_state() is called, set the value of `current' to the value in `next', and then set the value of `next' to FALSE. - That way, `current' will be TRUE _after_ a call to changed_state() if and only if that call to changed_state() was the result of a drag operation processed by interpret_move(). Any other call to changed_state(), due to an Undo or a Redo or a Restart or a Solve, will leave `current' FALSE. - So now anim_length() can request a move animation if and only if the `current' flag is _not_ set. 6.3.8. Inhibiting the victory flash when Solve is used ------------------------------------------------------ Many games flash when you complete them, as a visual congratulation for having got to the end of the puzzle. It often seems like a good idea to disable that flash when the puzzle is brought to a solved state by means of the Solve operation. This is easily done: - Add a `cheated' flag to the `game_state'. - Set this flag to FALSE in new_game(). - Have solve() return a move description string which clearly identifies the move as a solve operation. - Have execute_move() respond to that clear identification by setting the `cheated' flag in the returned `game_state'. The flag will then be propagated to all subsequent game states, even if the user continues fiddling with the game after it is solved. - flash_length() now returns non-zero if `oldstate' is not completed and `newstate' is, _and_ neither state has the `cheated' flag set. 6.4. Things to test once your puzzle is written ----------------------------------------------- Puzzle implementations written in this framework are self-testing as far as I could make them. Textual game and move descriptions, for example, are generated and parsed as part of the normal process of play. Therefore, if you can make moves in the game _at all_ you can be reasonably confident that the mid-end serialisation interface will function correctly and you will be able to save your game. (By contrast, if I'd stuck with a single make_move() function performing the jobs of both interpret_move() and execute_move(), and had separate functions to encode and decode a game state in string form, then those functions would not be used during normal play; so they could have been completely broken, and you'd never know it until you tried to save the game - which would have meant you'd have to test game saving _extensively_ and make sure to test every possible type of game state. As an added bonus, doing it the way I did leads to smaller save files.) There is one exception to this, which is the string encoding of the `game_ui'. Most games do not store anything permanent in the `game_ui', and hence do not need to put anything in its encode and decode functions; but if there is anything in there, you do need to test game loading and saving to ensure those functions work properly. It's also worth testing undo and redo of all operations, to ensure that the redraw and the animations (if any) work properly. Failing to animate undo properly seems to be a common error. Other than that, just use your common sense. puzzles-20170606.272beef/Makefile.wce0000644000175000017500000013732113115375145016115 0ustar simonsimon# Makefile for puzzles on PocketPC using eMbedded Visual C. # # This file was created by `mkfiles.pl' from the `Recipe' file. # DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead. # If you rename this file to `Makefile', you should change this line, # so that the .rsp files still depend on the correct makefile. MAKEFILE = Makefile.wce # This makefile expects the environment to have been set up by one # of the PocketPC batch files wcearmv4.bat and wceemulator.bat. No # other build targets are currently supported, because they would # need a section in this if statement. !if "$(TARGETCPU)" == "emulator" PLATFORM_DEFS=/D "_i386_" /D "i_386_" /D "_X86_" /D "x86" CC=cl BASELIBS=commctrl.lib coredll.lib corelibc.lib aygshell.lib MACHINE=IX86 !else PLATFORM_DEFS=/D "ARM" /D "_ARM_" /D "ARMV4" CC=clarm BASELIBS=commctrl.lib coredll.lib aygshell.lib MACHINE=ARM !endif # C compilation flags CFLAGS = /nologo /W3 /O1 /MC /D _WIN32_WCE=420 /D "WIN32_PLATFORM_PSPC=400" /D UNDER_CE=420 \ $(PLATFORM_DEFS) \ /D "UNICODE" /D "_UNICODE" /D "NDEBUG" /D "NO_HTMLHELP" LFLAGS = /nologo /incremental:no \ /base:0x00010000 /stack:0x10000,0x1000 /entry:WinMainCRTStartup \ /nodefaultlib:libc.lib /nodefaultlib:libcmt.lib /nodefaultlib:msvcrt.lib /nodefaultlib:OLDNAMES.lib \ /subsystem:windowsce,4.20 /align:4096 /MACHINE:$(MACHINE) RCFL = /d UNDER_CE=420 /d _WIN32_WCE=420 /d "WIN32_PLATFORM_PSPC=400" \ $(PLATFORM_DEFS) \ /d "NDEBUG" /d "UNICODE" /d "_UNICODE" all: blackbox.exe bridges.exe cube.exe dominosa.exe fifteen.exe filling.exe \ flip.exe flood.exe galaxies.exe guess.exe inertia.exe \ keen.exe lightup.exe loopy.exe magnets.exe map.exe mines.exe \ netgame.exe netslide.exe nullgame.exe palisade.exe \ pattern.exe pearl.exe pegs.exe puzzles.exe range.exe \ rect.exe samegame.exe signpost.exe singles.exe sixteen.exe \ slant.exe solo.exe tents.exe towers.exe tracks.exe \ twiddle.exe undead.exe unequal.exe unruly.exe untangle.exe blackbox.exe: blackbox.obj blackbox.res drawing.obj malloc.obj midend.obj \ misc.obj printing.obj random.obj version.obj windows.obj \ blackbox.rsp link $(LFLAGS) -out:blackbox.exe -map:blackbox.map @blackbox.rsp bridges.exe: bridges.obj bridges.res drawing.obj dsf.obj findloop.obj \ malloc.obj midend.obj misc.obj printing.obj random.obj \ version.obj windows.obj bridges.rsp link $(LFLAGS) -out:bridges.exe -map:bridges.map @bridges.rsp cube.exe: cube.obj cube.res drawing.obj malloc.obj midend.obj misc.obj \ printing.obj random.obj version.obj windows.obj cube.rsp link $(LFLAGS) -out:cube.exe -map:cube.map @cube.rsp dominosa.exe: dominosa.obj dominosa.res drawing.obj laydomino.obj malloc.obj \ midend.obj misc.obj printing.obj random.obj version.obj \ windows.obj dominosa.rsp link $(LFLAGS) -out:dominosa.exe -map:dominosa.map @dominosa.rsp fifteen.exe: drawing.obj fifteen.obj fifteen.res malloc.obj midend.obj \ misc.obj printing.obj random.obj version.obj windows.obj \ fifteen.rsp link $(LFLAGS) -out:fifteen.exe -map:fifteen.map @fifteen.rsp filling.exe: drawing.obj dsf.obj filling.obj filling.res malloc.obj \ midend.obj misc.obj printing.obj random.obj version.obj \ windows.obj filling.rsp link $(LFLAGS) -out:filling.exe -map:filling.map @filling.rsp flip.exe: drawing.obj flip.obj flip.res malloc.obj midend.obj misc.obj \ printing.obj random.obj tree234.obj version.obj windows.obj \ flip.rsp link $(LFLAGS) -out:flip.exe -map:flip.map @flip.rsp flood.exe: drawing.obj flood.obj flood.res malloc.obj midend.obj misc.obj \ printing.obj random.obj version.obj windows.obj flood.rsp link $(LFLAGS) -out:flood.exe -map:flood.map @flood.rsp galaxies.exe: drawing.obj dsf.obj galaxies.obj galaxies.res malloc.obj \ midend.obj misc.obj printing.obj random.obj version.obj \ windows.obj galaxies.rsp link $(LFLAGS) -out:galaxies.exe -map:galaxies.map @galaxies.rsp guess.exe: drawing.obj guess.obj guess.res malloc.obj midend.obj misc.obj \ printing.obj random.obj version.obj windows.obj guess.rsp link $(LFLAGS) -out:guess.exe -map:guess.map @guess.rsp inertia.exe: drawing.obj inertia.obj inertia.res malloc.obj midend.obj \ misc.obj printing.obj random.obj version.obj windows.obj \ inertia.rsp link $(LFLAGS) -out:inertia.exe -map:inertia.map @inertia.rsp keen.exe: drawing.obj dsf.obj keen.obj keen.res latin.obj malloc.obj \ maxflow.obj midend.obj misc.obj printing.obj random.obj \ tree234.obj version.obj windows.obj keen.rsp link $(LFLAGS) -out:keen.exe -map:keen.map @keen.rsp lightup.exe: combi.obj drawing.obj lightup.obj lightup.res malloc.obj \ midend.obj misc.obj printing.obj random.obj version.obj \ windows.obj lightup.rsp link $(LFLAGS) -out:lightup.exe -map:lightup.map @lightup.rsp loopy.exe: drawing.obj dsf.obj grid.obj loopgen.obj loopy.obj loopy.res \ malloc.obj midend.obj misc.obj penrose.obj printing.obj \ random.obj tree234.obj version.obj windows.obj loopy.rsp link $(LFLAGS) -out:loopy.exe -map:loopy.map @loopy.rsp magnets.exe: drawing.obj laydomino.obj magnets.obj magnets.res malloc.obj \ midend.obj misc.obj printing.obj random.obj version.obj \ windows.obj magnets.rsp link $(LFLAGS) -out:magnets.exe -map:magnets.map @magnets.rsp map.exe: drawing.obj dsf.obj malloc.obj map.obj map.res midend.obj misc.obj \ printing.obj random.obj version.obj windows.obj map.rsp link $(LFLAGS) -out:map.exe -map:map.map @map.rsp mines.exe: drawing.obj malloc.obj midend.obj mines.obj mines.res misc.obj \ printing.obj random.obj tree234.obj version.obj windows.obj \ mines.rsp link $(LFLAGS) -out:mines.exe -map:mines.map @mines.rsp netgame.exe: drawing.obj dsf.obj findloop.obj malloc.obj midend.obj misc.obj \ net.obj net.res printing.obj random.obj tree234.obj \ version.obj windows.obj netgame.rsp link $(LFLAGS) -out:netgame.exe -map:netgame.map @netgame.rsp netslide.exe: drawing.obj malloc.obj midend.obj misc.obj netslide.obj \ netslide.res printing.obj random.obj tree234.obj version.obj \ windows.obj netslide.rsp link $(LFLAGS) -out:netslide.exe -map:netslide.map @netslide.rsp nullgame.exe: drawing.obj malloc.obj midend.obj misc.obj noicon.res \ nullgame.obj printing.obj random.obj version.obj windows.obj \ nullgame.rsp link $(LFLAGS) -out:nullgame.exe -map:nullgame.map @nullgame.rsp palisade.exe: divvy.obj drawing.obj dsf.obj malloc.obj midend.obj misc.obj \ palisade.obj palisade.res printing.obj random.obj \ version.obj windows.obj palisade.rsp link $(LFLAGS) -out:palisade.exe -map:palisade.map @palisade.rsp pattern.exe: drawing.obj malloc.obj midend.obj misc.obj pattern.obj \ pattern.res printing.obj random.obj version.obj windows.obj \ pattern.rsp link $(LFLAGS) -out:pattern.exe -map:pattern.map @pattern.rsp pearl.exe: drawing.obj dsf.obj grid.obj loopgen.obj malloc.obj midend.obj \ misc.obj pearl.obj pearl.res penrose.obj printing.obj \ random.obj tdq.obj tree234.obj version.obj windows.obj \ pearl.rsp link $(LFLAGS) -out:pearl.exe -map:pearl.map @pearl.rsp pegs.exe: drawing.obj malloc.obj midend.obj misc.obj pegs.obj pegs.res \ printing.obj random.obj tree234.obj version.obj windows.obj \ pegs.rsp link $(LFLAGS) -out:pegs.exe -map:pegs.map @pegs.rsp puzzles.exe: blackbo3.obj bridges3.obj combi.obj cube3.obj divvy.obj \ dominos3.obj drawing.obj dsf.obj fifteen5.obj filling5.obj \ findloop.obj flip3.obj flood3.obj galaxie7.obj grid.obj \ guess3.obj inertia3.obj keen5.obj latin.obj laydomino.obj \ lightup5.obj list.obj loopgen.obj loopy5.obj magnets5.obj \ malloc.obj map5.obj maxflow.obj midend.obj mines5.obj \ misc.obj net3.obj netslid3.obj noicon.res palisad3.obj \ pattern7.obj pearl5.obj pegs3.obj penrose.obj printing.obj \ random.obj range3.obj rect3.obj samegam3.obj signpos5.obj \ singles5.obj sixteen3.obj slant5.obj solo5.obj tdq.obj \ tents5.obj towers5.obj tracks3.obj tree234.obj twiddle3.obj \ undead3.obj unequal5.obj unruly5.obj untangl3.obj \ version.obj windows1.obj puzzles.rsp link $(LFLAGS) -out:puzzles.exe -map:puzzles.map @puzzles.rsp range.exe: drawing.obj dsf.obj malloc.obj midend.obj misc.obj printing.obj \ random.obj range.obj range.res version.obj windows.obj \ range.rsp link $(LFLAGS) -out:range.exe -map:range.map @range.rsp rect.exe: drawing.obj malloc.obj midend.obj misc.obj printing.obj random.obj \ rect.obj rect.res version.obj windows.obj rect.rsp link $(LFLAGS) -out:rect.exe -map:rect.map @rect.rsp samegame.exe: drawing.obj malloc.obj midend.obj misc.obj printing.obj \ random.obj samegame.obj samegame.res version.obj windows.obj \ samegame.rsp link $(LFLAGS) -out:samegame.exe -map:samegame.map @samegame.rsp signpost.exe: drawing.obj dsf.obj malloc.obj midend.obj misc.obj \ printing.obj random.obj signpost.obj signpost.res \ version.obj windows.obj signpost.rsp link $(LFLAGS) -out:signpost.exe -map:signpost.map @signpost.rsp singles.exe: drawing.obj dsf.obj latin.obj malloc.obj maxflow.obj midend.obj \ misc.obj printing.obj random.obj singles.obj singles.res \ tree234.obj version.obj windows.obj singles.rsp link $(LFLAGS) -out:singles.exe -map:singles.map @singles.rsp sixteen.exe: drawing.obj malloc.obj midend.obj misc.obj printing.obj \ random.obj sixteen.obj sixteen.res version.obj windows.obj \ sixteen.rsp link $(LFLAGS) -out:sixteen.exe -map:sixteen.map @sixteen.rsp slant.exe: drawing.obj dsf.obj findloop.obj malloc.obj midend.obj misc.obj \ printing.obj random.obj slant.obj slant.res version.obj \ windows.obj slant.rsp link $(LFLAGS) -out:slant.exe -map:slant.map @slant.rsp solo.exe: divvy.obj drawing.obj dsf.obj malloc.obj midend.obj misc.obj \ printing.obj random.obj solo.obj solo.res version.obj \ windows.obj solo.rsp link $(LFLAGS) -out:solo.exe -map:solo.map @solo.rsp tents.exe: drawing.obj dsf.obj malloc.obj maxflow.obj midend.obj misc.obj \ printing.obj random.obj tents.obj tents.res version.obj \ windows.obj tents.rsp link $(LFLAGS) -out:tents.exe -map:tents.map @tents.rsp towers.exe: drawing.obj latin.obj malloc.obj maxflow.obj midend.obj misc.obj \ printing.obj random.obj towers.obj towers.res tree234.obj \ version.obj windows.obj towers.rsp link $(LFLAGS) -out:towers.exe -map:towers.map @towers.rsp tracks.exe: drawing.obj dsf.obj findloop.obj malloc.obj midend.obj misc.obj \ printing.obj random.obj tracks.obj tracks.res version.obj \ windows.obj tracks.rsp link $(LFLAGS) -out:tracks.exe -map:tracks.map @tracks.rsp twiddle.exe: drawing.obj malloc.obj midend.obj misc.obj printing.obj \ random.obj twiddle.obj twiddle.res version.obj windows.obj \ twiddle.rsp link $(LFLAGS) -out:twiddle.exe -map:twiddle.map @twiddle.rsp undead.exe: drawing.obj malloc.obj midend.obj misc.obj printing.obj \ random.obj undead.obj undead.res version.obj windows.obj \ undead.rsp link $(LFLAGS) -out:undead.exe -map:undead.map @undead.rsp unequal.exe: drawing.obj latin.obj malloc.obj maxflow.obj midend.obj \ misc.obj printing.obj random.obj tree234.obj unequal.obj \ unequal.res version.obj windows.obj unequal.rsp link $(LFLAGS) -out:unequal.exe -map:unequal.map @unequal.rsp unruly.exe: drawing.obj malloc.obj midend.obj misc.obj printing.obj \ random.obj unruly.obj unruly.res version.obj windows.obj \ unruly.rsp link $(LFLAGS) -out:unruly.exe -map:unruly.map @unruly.rsp untangle.exe: drawing.obj malloc.obj midend.obj misc.obj printing.obj \ random.obj tree234.obj untangle.obj untangle.res version.obj \ windows.obj untangle.rsp link $(LFLAGS) -out:untangle.exe -map:untangle.map @untangle.rsp blackbox.rsp: $(MAKEFILE) echo $(BASELIBS) > blackbox.rsp echo blackbox.obj blackbox.res drawing.obj malloc.obj >> blackbox.rsp echo midend.obj misc.obj printing.obj random.obj >> blackbox.rsp echo version.obj windows.obj >> blackbox.rsp bridges.rsp: $(MAKEFILE) echo $(BASELIBS) > bridges.rsp echo bridges.obj bridges.res drawing.obj dsf.obj >> bridges.rsp echo findloop.obj malloc.obj midend.obj misc.obj >> bridges.rsp echo printing.obj random.obj version.obj windows.obj >> bridges.rsp cube.rsp: $(MAKEFILE) echo $(BASELIBS) > cube.rsp echo cube.obj cube.res drawing.obj malloc.obj >> cube.rsp echo midend.obj misc.obj printing.obj random.obj >> cube.rsp echo version.obj windows.obj >> cube.rsp dominosa.rsp: $(MAKEFILE) echo $(BASELIBS) > dominosa.rsp echo dominosa.obj dominosa.res drawing.obj >> dominosa.rsp echo laydomino.obj malloc.obj midend.obj misc.obj >> dominosa.rsp echo printing.obj random.obj version.obj windows.obj >> dominosa.rsp fifteen.rsp: $(MAKEFILE) echo $(BASELIBS) > fifteen.rsp echo drawing.obj fifteen.obj fifteen.res malloc.obj >> fifteen.rsp echo midend.obj misc.obj printing.obj random.obj >> fifteen.rsp echo version.obj windows.obj >> fifteen.rsp filling.rsp: $(MAKEFILE) echo $(BASELIBS) > filling.rsp echo drawing.obj dsf.obj filling.obj filling.res >> filling.rsp echo malloc.obj midend.obj misc.obj printing.obj >> filling.rsp echo random.obj version.obj windows.obj >> filling.rsp flip.rsp: $(MAKEFILE) echo $(BASELIBS) > flip.rsp echo drawing.obj flip.obj flip.res malloc.obj >> flip.rsp echo midend.obj misc.obj printing.obj random.obj >> flip.rsp echo tree234.obj version.obj windows.obj >> flip.rsp flood.rsp: $(MAKEFILE) echo $(BASELIBS) > flood.rsp echo drawing.obj flood.obj flood.res malloc.obj >> flood.rsp echo midend.obj misc.obj printing.obj random.obj >> flood.rsp echo version.obj windows.obj >> flood.rsp galaxies.rsp: $(MAKEFILE) echo $(BASELIBS) > galaxies.rsp echo drawing.obj dsf.obj galaxies.obj galaxies.res >> galaxies.rsp echo malloc.obj midend.obj misc.obj printing.obj >> galaxies.rsp echo random.obj version.obj windows.obj >> galaxies.rsp guess.rsp: $(MAKEFILE) echo $(BASELIBS) > guess.rsp echo drawing.obj guess.obj guess.res malloc.obj >> guess.rsp echo midend.obj misc.obj printing.obj random.obj >> guess.rsp echo version.obj windows.obj >> guess.rsp inertia.rsp: $(MAKEFILE) echo $(BASELIBS) > inertia.rsp echo drawing.obj inertia.obj inertia.res malloc.obj >> inertia.rsp echo midend.obj misc.obj printing.obj random.obj >> inertia.rsp echo version.obj windows.obj >> inertia.rsp keen.rsp: $(MAKEFILE) echo $(BASELIBS) > keen.rsp echo drawing.obj dsf.obj keen.obj keen.res latin.obj >> keen.rsp echo malloc.obj maxflow.obj midend.obj misc.obj >> keen.rsp echo printing.obj random.obj tree234.obj version.obj >> keen.rsp echo windows.obj >> keen.rsp lightup.rsp: $(MAKEFILE) echo $(BASELIBS) > lightup.rsp echo combi.obj drawing.obj lightup.obj lightup.res >> lightup.rsp echo malloc.obj midend.obj misc.obj printing.obj >> lightup.rsp echo random.obj version.obj windows.obj >> lightup.rsp loopy.rsp: $(MAKEFILE) echo $(BASELIBS) > loopy.rsp echo drawing.obj dsf.obj grid.obj loopgen.obj >> loopy.rsp echo loopy.obj loopy.res malloc.obj midend.obj >> loopy.rsp echo misc.obj penrose.obj printing.obj random.obj >> loopy.rsp echo tree234.obj version.obj windows.obj >> loopy.rsp magnets.rsp: $(MAKEFILE) echo $(BASELIBS) > magnets.rsp echo drawing.obj laydomino.obj magnets.obj magnets.res >> magnets.rsp echo malloc.obj midend.obj misc.obj printing.obj >> magnets.rsp echo random.obj version.obj windows.obj >> magnets.rsp map.rsp: $(MAKEFILE) echo $(BASELIBS) > map.rsp echo drawing.obj dsf.obj malloc.obj map.obj map.res >> map.rsp echo midend.obj misc.obj printing.obj random.obj >> map.rsp echo version.obj windows.obj >> map.rsp mines.rsp: $(MAKEFILE) echo $(BASELIBS) > mines.rsp echo drawing.obj malloc.obj midend.obj mines.obj >> mines.rsp echo mines.res misc.obj printing.obj random.obj >> mines.rsp echo tree234.obj version.obj windows.obj >> mines.rsp netgame.rsp: $(MAKEFILE) echo $(BASELIBS) > netgame.rsp echo drawing.obj dsf.obj findloop.obj malloc.obj >> netgame.rsp echo midend.obj misc.obj net.obj net.res printing.obj >> netgame.rsp echo random.obj tree234.obj version.obj windows.obj >> netgame.rsp netslide.rsp: $(MAKEFILE) echo $(BASELIBS) > netslide.rsp echo drawing.obj malloc.obj midend.obj misc.obj >> netslide.rsp echo netslide.obj netslide.res printing.obj random.obj >> netslide.rsp echo tree234.obj version.obj windows.obj >> netslide.rsp nullgame.rsp: $(MAKEFILE) echo $(BASELIBS) > nullgame.rsp echo drawing.obj malloc.obj midend.obj misc.obj >> nullgame.rsp echo noicon.res nullgame.obj printing.obj random.obj >> nullgame.rsp echo version.obj windows.obj >> nullgame.rsp palisade.rsp: $(MAKEFILE) echo $(BASELIBS) > palisade.rsp echo divvy.obj drawing.obj dsf.obj malloc.obj >> palisade.rsp echo midend.obj misc.obj palisade.obj palisade.res >> palisade.rsp echo printing.obj random.obj version.obj windows.obj >> palisade.rsp pattern.rsp: $(MAKEFILE) echo $(BASELIBS) > pattern.rsp echo drawing.obj malloc.obj midend.obj misc.obj >> pattern.rsp echo pattern.obj pattern.res printing.obj random.obj >> pattern.rsp echo version.obj windows.obj >> pattern.rsp pearl.rsp: $(MAKEFILE) echo $(BASELIBS) > pearl.rsp echo drawing.obj dsf.obj grid.obj loopgen.obj >> pearl.rsp echo malloc.obj midend.obj misc.obj pearl.obj >> pearl.rsp echo pearl.res penrose.obj printing.obj random.obj >> pearl.rsp echo tdq.obj tree234.obj version.obj windows.obj >> pearl.rsp pegs.rsp: $(MAKEFILE) echo $(BASELIBS) > pegs.rsp echo drawing.obj malloc.obj midend.obj misc.obj >> pegs.rsp echo pegs.obj pegs.res printing.obj random.obj >> pegs.rsp echo tree234.obj version.obj windows.obj >> pegs.rsp puzzles.rsp: $(MAKEFILE) echo $(BASELIBS) > puzzles.rsp echo blackbo3.obj bridges3.obj combi.obj cube3.obj >> puzzles.rsp echo divvy.obj dominos3.obj drawing.obj dsf.obj >> puzzles.rsp echo fifteen5.obj filling5.obj findloop.obj flip3.obj >> puzzles.rsp echo flood3.obj galaxie7.obj grid.obj guess3.obj >> puzzles.rsp echo inertia3.obj keen5.obj latin.obj laydomino.obj >> puzzles.rsp echo lightup5.obj list.obj loopgen.obj loopy5.obj >> puzzles.rsp echo magnets5.obj malloc.obj map5.obj maxflow.obj >> puzzles.rsp echo midend.obj mines5.obj misc.obj net3.obj >> puzzles.rsp echo netslid3.obj noicon.res palisad3.obj pattern7.obj >> puzzles.rsp echo pearl5.obj pegs3.obj penrose.obj printing.obj >> puzzles.rsp echo random.obj range3.obj rect3.obj samegam3.obj >> puzzles.rsp echo signpos5.obj singles5.obj sixteen3.obj slant5.obj >> puzzles.rsp echo solo5.obj tdq.obj tents5.obj towers5.obj >> puzzles.rsp echo tracks3.obj tree234.obj twiddle3.obj undead3.obj >> puzzles.rsp echo unequal5.obj unruly5.obj untangl3.obj version.obj >> puzzles.rsp echo windows1.obj >> puzzles.rsp range.rsp: $(MAKEFILE) echo $(BASELIBS) > range.rsp echo drawing.obj dsf.obj malloc.obj midend.obj >> range.rsp echo misc.obj printing.obj random.obj range.obj >> range.rsp echo range.res version.obj windows.obj >> range.rsp rect.rsp: $(MAKEFILE) echo $(BASELIBS) > rect.rsp echo drawing.obj malloc.obj midend.obj misc.obj >> rect.rsp echo printing.obj random.obj rect.obj rect.res >> rect.rsp echo version.obj windows.obj >> rect.rsp samegame.rsp: $(MAKEFILE) echo $(BASELIBS) > samegame.rsp echo drawing.obj malloc.obj midend.obj misc.obj >> samegame.rsp echo printing.obj random.obj samegame.obj samegame.res >> samegame.rsp echo version.obj windows.obj >> samegame.rsp signpost.rsp: $(MAKEFILE) echo $(BASELIBS) > signpost.rsp echo drawing.obj dsf.obj malloc.obj midend.obj >> signpost.rsp echo misc.obj printing.obj random.obj signpost.obj >> signpost.rsp echo signpost.res version.obj windows.obj >> signpost.rsp singles.rsp: $(MAKEFILE) echo $(BASELIBS) > singles.rsp echo drawing.obj dsf.obj latin.obj malloc.obj >> singles.rsp echo maxflow.obj midend.obj misc.obj printing.obj >> singles.rsp echo random.obj singles.obj singles.res tree234.obj >> singles.rsp echo version.obj windows.obj >> singles.rsp sixteen.rsp: $(MAKEFILE) echo $(BASELIBS) > sixteen.rsp echo drawing.obj malloc.obj midend.obj misc.obj >> sixteen.rsp echo printing.obj random.obj sixteen.obj sixteen.res >> sixteen.rsp echo version.obj windows.obj >> sixteen.rsp slant.rsp: $(MAKEFILE) echo $(BASELIBS) > slant.rsp echo drawing.obj dsf.obj findloop.obj malloc.obj >> slant.rsp echo midend.obj misc.obj printing.obj random.obj >> slant.rsp echo slant.obj slant.res version.obj windows.obj >> slant.rsp solo.rsp: $(MAKEFILE) echo $(BASELIBS) > solo.rsp echo divvy.obj drawing.obj dsf.obj malloc.obj >> solo.rsp echo midend.obj misc.obj printing.obj random.obj >> solo.rsp echo solo.obj solo.res version.obj windows.obj >> solo.rsp tents.rsp: $(MAKEFILE) echo $(BASELIBS) > tents.rsp echo drawing.obj dsf.obj malloc.obj maxflow.obj >> tents.rsp echo midend.obj misc.obj printing.obj random.obj >> tents.rsp echo tents.obj tents.res version.obj windows.obj >> tents.rsp towers.rsp: $(MAKEFILE) echo $(BASELIBS) > towers.rsp echo drawing.obj latin.obj malloc.obj maxflow.obj >> towers.rsp echo midend.obj misc.obj printing.obj random.obj >> towers.rsp echo towers.obj towers.res tree234.obj version.obj >> towers.rsp echo windows.obj >> towers.rsp tracks.rsp: $(MAKEFILE) echo $(BASELIBS) > tracks.rsp echo drawing.obj dsf.obj findloop.obj malloc.obj >> tracks.rsp echo midend.obj misc.obj printing.obj random.obj >> tracks.rsp echo tracks.obj tracks.res version.obj windows.obj >> tracks.rsp twiddle.rsp: $(MAKEFILE) echo $(BASELIBS) > twiddle.rsp echo drawing.obj malloc.obj midend.obj misc.obj >> twiddle.rsp echo printing.obj random.obj twiddle.obj twiddle.res >> twiddle.rsp echo version.obj windows.obj >> twiddle.rsp undead.rsp: $(MAKEFILE) echo $(BASELIBS) > undead.rsp echo drawing.obj malloc.obj midend.obj misc.obj >> undead.rsp echo printing.obj random.obj undead.obj undead.res >> undead.rsp echo version.obj windows.obj >> undead.rsp unequal.rsp: $(MAKEFILE) echo $(BASELIBS) > unequal.rsp echo drawing.obj latin.obj malloc.obj maxflow.obj >> unequal.rsp echo midend.obj misc.obj printing.obj random.obj >> unequal.rsp echo tree234.obj unequal.obj unequal.res version.obj >> unequal.rsp echo windows.obj >> unequal.rsp unruly.rsp: $(MAKEFILE) echo $(BASELIBS) > unruly.rsp echo drawing.obj malloc.obj midend.obj misc.obj >> unruly.rsp echo printing.obj random.obj unruly.obj unruly.res >> unruly.rsp echo version.obj windows.obj >> unruly.rsp untangle.rsp: $(MAKEFILE) echo $(BASELIBS) > untangle.rsp echo drawing.obj malloc.obj midend.obj misc.obj >> untangle.rsp echo printing.obj random.obj tree234.obj untangle.obj >> untangle.rsp echo untangle.res version.obj windows.obj >> untangle.rsp blackbox.obj: .\blackbox.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\blackbox.c /Foblackbox.obj blackbox-icon.obj: icons\blackbox-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\blackbox-icon.c /Foblackbox-icon.obj blackbox.res: icons\blackbox.rc .\puzzles.rc2 icons\blackbox.ico \ .\resource.h rc $(FWHACK) $(RCFL) -r -foblackbox.res icons\blackbox.rc blackbo3.obj: .\blackbox.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\blackbox.c /Foblackbo3.obj bridges.obj: .\bridges.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\bridges.c /Fobridges.obj bridges-icon.obj: icons\bridges-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\bridges-icon.c /Fobridges-icon.obj bridges.res: icons\bridges.rc .\puzzles.rc2 icons\bridges.ico .\resource.h rc $(FWHACK) $(RCFL) -r -fobridges.res icons\bridges.rc bridges3.obj: .\bridges.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\bridges.c /Fobridges3.obj combi.obj: .\combi.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\combi.c /Focombi.obj cube.obj: .\cube.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\cube.c /Focube.obj cube-icon.obj: icons\cube-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\cube-icon.c /Focube-icon.obj cube.res: icons\cube.rc .\puzzles.rc2 icons\cube.ico .\resource.h rc $(FWHACK) $(RCFL) -r -focube.res icons\cube.rc cube3.obj: .\cube.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\cube.c /Focube3.obj divvy.obj: .\divvy.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\divvy.c /Fodivvy.obj dominosa.obj: .\dominosa.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\dominosa.c /Fodominosa.obj dominosa-icon.obj: icons\dominosa-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\dominosa-icon.c /Fodominosa-icon.obj dominosa.res: icons\dominosa.rc .\puzzles.rc2 icons\dominosa.ico \ .\resource.h rc $(FWHACK) $(RCFL) -r -fodominosa.res icons\dominosa.rc dominos3.obj: .\dominosa.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\dominosa.c /Fodominos3.obj drawing.obj: .\drawing.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\drawing.c /Fodrawing.obj dsf.obj: .\dsf.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\dsf.c /Fodsf.obj fifteen.obj: .\fifteen.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\fifteen.c /Fofifteen.obj fifteen-icon.obj: icons\fifteen-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\fifteen-icon.c /Fofifteen-icon.obj fifteen.res: icons\fifteen.rc .\puzzles.rc2 icons\fifteen.ico .\resource.h rc $(FWHACK) $(RCFL) -r -fofifteen.res icons\fifteen.rc fifteen5.obj: .\fifteen.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\fifteen.c /Fofifteen5.obj fifteen2.obj: .\fifteen.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_SOLVER /c .\fifteen.c /Fofifteen2.obj filling.obj: .\filling.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\filling.c /Fofilling.obj filling-icon.obj: icons\filling-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\filling-icon.c /Fofilling-icon.obj filling.res: icons\filling.rc .\puzzles.rc2 icons\filling.ico .\resource.h rc $(FWHACK) $(RCFL) -r -fofilling.res icons\filling.rc filling5.obj: .\filling.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\filling.c /Fofilling5.obj filling2.obj: .\filling.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_SOLVER /c .\filling.c /Fofilling2.obj findloop.obj: .\findloop.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\findloop.c /Fofindloop.obj flip.obj: .\flip.c .\puzzles.h .\tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\flip.c /Foflip.obj flip-icon.obj: icons\flip-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\flip-icon.c /Foflip-icon.obj flip.res: icons\flip.rc .\puzzles.rc2 icons\flip.ico .\resource.h rc $(FWHACK) $(RCFL) -r -foflip.res icons\flip.rc flip3.obj: .\flip.c .\puzzles.h .\tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\flip.c /Foflip3.obj flood.obj: .\flood.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\flood.c /Foflood.obj flood-icon.obj: icons\flood-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\flood-icon.c /Foflood-icon.obj flood.res: icons\flood.rc .\puzzles.rc2 icons\flood.ico .\resource.h rc $(FWHACK) $(RCFL) -r -foflood.res icons\flood.rc flood3.obj: .\flood.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\flood.c /Foflood3.obj galaxies.obj: .\galaxies.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\galaxies.c /Fogalaxies.obj galaxies-icon.obj: icons\galaxies-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\galaxies-icon.c /Fogalaxies-icon.obj galaxies.res: icons\galaxies.rc .\puzzles.rc2 icons\galaxies.ico \ .\resource.h rc $(FWHACK) $(RCFL) -r -fogalaxies.res icons\galaxies.rc galaxie7.obj: .\galaxies.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\galaxies.c /Fogalaxie7.obj galaxie4.obj: .\galaxies.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_PICTURE_GENERATOR /c .\galaxies.c /Fogalaxie4.obj galaxie2.obj: .\galaxies.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_SOLVER /c .\galaxies.c /Fogalaxie2.obj grid.obj: .\grid.c .\puzzles.h .\tree234.h .\grid.h .\penrose.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\grid.c /Fogrid.obj gtk.obj: .\gtk.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\gtk.c /Fogtk.obj guess.obj: .\guess.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\guess.c /Foguess.obj guess-icon.obj: icons\guess-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\guess-icon.c /Foguess-icon.obj guess.res: icons\guess.rc .\puzzles.rc2 icons\guess.ico .\resource.h rc $(FWHACK) $(RCFL) -r -foguess.res icons\guess.rc guess3.obj: .\guess.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\guess.c /Foguess3.obj inertia.obj: .\inertia.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\inertia.c /Foinertia.obj inertia-icon.obj: icons\inertia-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\inertia-icon.c /Foinertia-icon.obj inertia.res: icons\inertia.rc .\puzzles.rc2 icons\inertia.ico .\resource.h rc $(FWHACK) $(RCFL) -r -foinertia.res icons\inertia.rc inertia3.obj: .\inertia.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\inertia.c /Foinertia3.obj keen.obj: .\keen.c .\puzzles.h .\latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\keen.c /Fokeen.obj keen-icon.obj: icons\keen-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\keen-icon.c /Fokeen-icon.obj keen.res: icons\keen.rc .\puzzles.rc2 icons\keen.ico .\resource.h rc $(FWHACK) $(RCFL) -r -fokeen.res icons\keen.rc keen5.obj: .\keen.c .\puzzles.h .\latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\keen.c /Fokeen5.obj keen2.obj: .\keen.c .\puzzles.h .\latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_SOLVER /c .\keen.c /Fokeen2.obj latin.obj: .\latin.c .\puzzles.h .\tree234.h .\maxflow.h .\latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\latin.c /Folatin.obj latin8.obj: .\latin.c .\puzzles.h .\tree234.h .\maxflow.h .\latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_LATIN_TEST /c .\latin.c /Folatin8.obj latin6.obj: .\latin.c .\puzzles.h .\tree234.h .\maxflow.h .\latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_SOLVER /c .\latin.c /Folatin6.obj laydomino.obj: .\laydomino.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\laydomino.c /Folaydomino.obj lightup.obj: .\lightup.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\lightup.c /Folightup.obj lightup-icon.obj: icons\lightup-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\lightup-icon.c /Folightup-icon.obj lightup.res: icons\lightup.rc .\puzzles.rc2 icons\lightup.ico .\resource.h rc $(FWHACK) $(RCFL) -r -folightup.res icons\lightup.rc lightup5.obj: .\lightup.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\lightup.c /Folightup5.obj lightup2.obj: .\lightup.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_SOLVER /c .\lightup.c /Folightup2.obj list.obj: .\list.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\list.c /Folist.obj loopgen.obj: .\loopgen.c .\puzzles.h .\tree234.h .\grid.h .\loopgen.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\loopgen.c /Foloopgen.obj loopy.obj: .\loopy.c .\puzzles.h .\tree234.h .\grid.h .\loopgen.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\loopy.c /Foloopy.obj loopy-icon.obj: icons\loopy-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\loopy-icon.c /Foloopy-icon.obj loopy.res: icons\loopy.rc .\puzzles.rc2 icons\loopy.ico .\resource.h rc $(FWHACK) $(RCFL) -r -foloopy.res icons\loopy.rc loopy5.obj: .\loopy.c .\puzzles.h .\tree234.h .\grid.h .\loopgen.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\loopy.c /Foloopy5.obj loopy2.obj: .\loopy.c .\puzzles.h .\tree234.h .\grid.h .\loopgen.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_SOLVER /c .\loopy.c /Foloopy2.obj magnets.obj: .\magnets.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\magnets.c /Fomagnets.obj magnets-icon.obj: icons\magnets-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\magnets-icon.c /Fomagnets-icon.obj magnets.res: icons\magnets.rc .\puzzles.rc2 icons\magnets.ico .\resource.h rc $(FWHACK) $(RCFL) -r -fomagnets.res icons\magnets.rc magnets5.obj: .\magnets.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\magnets.c /Fomagnets5.obj magnets2.obj: .\magnets.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_SOLVER /c .\magnets.c /Fomagnets2.obj malloc.obj: .\malloc.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\malloc.c /Fomalloc.obj map.obj: .\map.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\map.c /Fomap.obj map-icon.obj: icons\map-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\map-icon.c /Fomap-icon.obj map.res: icons\map.rc .\puzzles.rc2 icons\map.ico .\resource.h rc $(FWHACK) $(RCFL) -r -fomap.res icons\map.rc map5.obj: .\map.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\map.c /Fomap5.obj map2.obj: .\map.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_SOLVER /c .\map.c /Fomap2.obj maxflow.obj: .\maxflow.c .\maxflow.h .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\maxflow.c /Fomaxflow.obj midend.obj: .\midend.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\midend.c /Fomidend.obj mines.obj: .\mines.c .\tree234.h .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\mines.c /Fomines.obj mines-icon.obj: icons\mines-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\mines-icon.c /Fomines-icon.obj mines.res: icons\mines.rc .\puzzles.rc2 icons\mines.ico .\resource.h rc $(FWHACK) $(RCFL) -r -fomines.res icons\mines.rc mines5.obj: .\mines.c .\tree234.h .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\mines.c /Fomines5.obj mines2.obj: .\mines.c .\tree234.h .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_OBFUSCATOR /c .\mines.c /Fomines2.obj misc.obj: .\misc.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\misc.c /Fomisc.obj net.obj: .\net.c .\puzzles.h .\tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\net.c /Fonet.obj net-icon.obj: icons\net-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\net-icon.c /Fonet-icon.obj net.res: icons\net.rc .\puzzles.rc2 icons\net.ico .\resource.h rc $(FWHACK) $(RCFL) -r -fonet.res icons\net.rc net3.obj: .\net.c .\puzzles.h .\tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\net.c /Fonet3.obj netslide.obj: .\netslide.c .\puzzles.h .\tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\netslide.c /Fonetslide.obj netslide-icon.obj: icons\netslide-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\netslide-icon.c /Fonetslide-icon.obj netslide.res: icons\netslide.rc .\puzzles.rc2 icons\netslide.ico \ .\resource.h rc $(FWHACK) $(RCFL) -r -fonetslide.res icons\netslide.rc netslid3.obj: .\netslide.c .\puzzles.h .\tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\netslide.c /Fonetslid3.obj no-icon.obj: .\no-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\no-icon.c /Fono-icon.obj noicon.res: .\noicon.rc .\puzzles.rc2 .\resource.h rc $(FWHACK) $(RCFL) -r -fonoicon.res .\noicon.rc nullfe.obj: .\nullfe.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\nullfe.c /Fonullfe.obj nullgame.obj: .\nullgame.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\nullgame.c /Fonullgame.obj obfusc.obj: .\obfusc.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\obfusc.c /Foobfusc.obj osx.obj: .\osx.m .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\osx.m /Foosx.obj palisade.obj: .\palisade.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\palisade.c /Fopalisade.obj palisade-icon.obj: icons\palisade-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\palisade-icon.c /Fopalisade-icon.obj palisade.res: icons\palisade.rc .\puzzles.rc2 icons\palisade.ico \ .\resource.h rc $(FWHACK) $(RCFL) -r -fopalisade.res icons\palisade.rc palisad3.obj: .\palisade.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\palisade.c /Fopalisad3.obj pattern.obj: .\pattern.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\pattern.c /Fopattern.obj pattern-icon.obj: icons\pattern-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\pattern-icon.c /Fopattern-icon.obj pattern.res: icons\pattern.rc .\puzzles.rc2 icons\pattern.ico .\resource.h rc $(FWHACK) $(RCFL) -r -fopattern.res icons\pattern.rc pattern7.obj: .\pattern.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\pattern.c /Fopattern7.obj pattern4.obj: .\pattern.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_PICTURE_GENERATOR /c .\pattern.c /Fopattern4.obj pattern2.obj: .\pattern.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_SOLVER /c .\pattern.c /Fopattern2.obj pearl.obj: .\pearl.c .\puzzles.h .\grid.h .\loopgen.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\pearl.c /Fopearl.obj pearl-icon.obj: icons\pearl-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\pearl-icon.c /Fopearl-icon.obj pearl.res: icons\pearl.rc .\puzzles.rc2 icons\pearl.ico .\resource.h rc $(FWHACK) $(RCFL) -r -fopearl.res icons\pearl.rc pearl5.obj: .\pearl.c .\puzzles.h .\grid.h .\loopgen.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\pearl.c /Fopearl5.obj pearl2.obj: .\pearl.c .\puzzles.h .\grid.h .\loopgen.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_SOLVER /c .\pearl.c /Fopearl2.obj pegs.obj: .\pegs.c .\puzzles.h .\tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\pegs.c /Fopegs.obj pegs-icon.obj: icons\pegs-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\pegs-icon.c /Fopegs-icon.obj pegs.res: icons\pegs.rc .\puzzles.rc2 icons\pegs.ico .\resource.h rc $(FWHACK) $(RCFL) -r -fopegs.res icons\pegs.rc pegs3.obj: .\pegs.c .\puzzles.h .\tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\pegs.c /Fopegs3.obj penrose.obj: .\penrose.c .\puzzles.h .\penrose.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\penrose.c /Fopenrose.obj printing.obj: .\printing.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\printing.c /Foprinting.obj ps.obj: .\ps.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\ps.c /Fops.obj random.obj: .\random.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\random.c /Forandom.obj range.obj: .\range.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\range.c /Forange.obj range-icon.obj: icons\range-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\range-icon.c /Forange-icon.obj range.res: icons\range.rc .\puzzles.rc2 icons\range.ico .\resource.h rc $(FWHACK) $(RCFL) -r -forange.res icons\range.rc range3.obj: .\range.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\range.c /Forange3.obj rect.obj: .\rect.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\rect.c /Forect.obj rect-icon.obj: icons\rect-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\rect-icon.c /Forect-icon.obj rect.res: icons\rect.rc .\puzzles.rc2 icons\rect.ico .\resource.h rc $(FWHACK) $(RCFL) -r -forect.res icons\rect.rc rect3.obj: .\rect.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\rect.c /Forect3.obj samegame.obj: .\samegame.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\samegame.c /Fosamegame.obj samegame-icon.obj: icons\samegame-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\samegame-icon.c /Fosamegame-icon.obj samegame.res: icons\samegame.rc .\puzzles.rc2 icons\samegame.ico \ .\resource.h rc $(FWHACK) $(RCFL) -r -fosamegame.res icons\samegame.rc samegam3.obj: .\samegame.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\samegame.c /Fosamegam3.obj signpost.obj: .\signpost.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\signpost.c /Fosignpost.obj signpost-icon.obj: icons\signpost-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\signpost-icon.c /Fosignpost-icon.obj signpost.res: icons\signpost.rc .\puzzles.rc2 icons\signpost.ico \ .\resource.h rc $(FWHACK) $(RCFL) -r -fosignpost.res icons\signpost.rc signpos5.obj: .\signpost.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\signpost.c /Fosignpos5.obj signpos2.obj: .\signpost.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_SOLVER /c .\signpost.c /Fosignpos2.obj singles.obj: .\singles.c .\puzzles.h .\latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\singles.c /Fosingles.obj singles-icon.obj: icons\singles-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\singles-icon.c /Fosingles-icon.obj singles.res: icons\singles.rc .\puzzles.rc2 icons\singles.ico .\resource.h rc $(FWHACK) $(RCFL) -r -fosingles.res icons\singles.rc singles5.obj: .\singles.c .\puzzles.h .\latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\singles.c /Fosingles5.obj singles3.obj: .\singles.c .\puzzles.h .\latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_SOLVER /c .\singles.c /Fosingles3.obj sixteen.obj: .\sixteen.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\sixteen.c /Fosixteen.obj sixteen-icon.obj: icons\sixteen-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\sixteen-icon.c /Fosixteen-icon.obj sixteen.res: icons\sixteen.rc .\puzzles.rc2 icons\sixteen.ico .\resource.h rc $(FWHACK) $(RCFL) -r -fosixteen.res icons\sixteen.rc sixteen3.obj: .\sixteen.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\sixteen.c /Fosixteen3.obj slant.obj: .\slant.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\slant.c /Foslant.obj slant-icon.obj: icons\slant-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\slant-icon.c /Foslant-icon.obj slant.res: icons\slant.rc .\puzzles.rc2 icons\slant.ico .\resource.h rc $(FWHACK) $(RCFL) -r -foslant.res icons\slant.rc slant5.obj: .\slant.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\slant.c /Foslant5.obj slant2.obj: .\slant.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_SOLVER /c .\slant.c /Foslant2.obj solo.obj: .\solo.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\solo.c /Fosolo.obj solo-icon.obj: icons\solo-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\solo-icon.c /Fosolo-icon.obj solo.res: icons\solo.rc .\puzzles.rc2 icons\solo.ico .\resource.h rc $(FWHACK) $(RCFL) -r -fosolo.res icons\solo.rc solo5.obj: .\solo.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\solo.c /Fosolo5.obj solo2.obj: .\solo.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_SOLVER /c .\solo.c /Fosolo2.obj tdq.obj: .\tdq.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\tdq.c /Fotdq.obj tents.obj: .\tents.c .\puzzles.h .\maxflow.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\tents.c /Fotents.obj tents-icon.obj: icons\tents-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\tents-icon.c /Fotents-icon.obj tents.res: icons\tents.rc .\puzzles.rc2 icons\tents.ico .\resource.h rc $(FWHACK) $(RCFL) -r -fotents.res icons\tents.rc tents5.obj: .\tents.c .\puzzles.h .\maxflow.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\tents.c /Fotents5.obj tents3.obj: .\tents.c .\puzzles.h .\maxflow.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_SOLVER /c .\tents.c /Fotents3.obj towers.obj: .\towers.c .\puzzles.h .\latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\towers.c /Fotowers.obj towers-icon.obj: icons\towers-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\towers-icon.c /Fotowers-icon.obj towers.res: icons\towers.rc .\puzzles.rc2 icons\towers.ico .\resource.h rc $(FWHACK) $(RCFL) -r -fotowers.res icons\towers.rc towers5.obj: .\towers.c .\puzzles.h .\latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\towers.c /Fotowers5.obj towers2.obj: .\towers.c .\puzzles.h .\latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_SOLVER /c .\towers.c /Fotowers2.obj tracks.obj: .\tracks.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\tracks.c /Fotracks.obj tracks-icon.obj: icons\tracks-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\tracks-icon.c /Fotracks-icon.obj tracks.res: icons\tracks.rc .\puzzles.rc2 icons\tracks.ico .\resource.h rc $(FWHACK) $(RCFL) -r -fotracks.res icons\tracks.rc tracks3.obj: .\tracks.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\tracks.c /Fotracks3.obj tree234.obj: .\tree234.c .\tree234.h .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\tree234.c /Fotree234.obj twiddle.obj: .\twiddle.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\twiddle.c /Fotwiddle.obj twiddle-icon.obj: icons\twiddle-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\twiddle-icon.c /Fotwiddle-icon.obj twiddle.res: icons\twiddle.rc .\puzzles.rc2 icons\twiddle.ico .\resource.h rc $(FWHACK) $(RCFL) -r -fotwiddle.res icons\twiddle.rc twiddle3.obj: .\twiddle.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\twiddle.c /Fotwiddle3.obj undead.obj: .\undead.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\undead.c /Foundead.obj undead-icon.obj: icons\undead-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\undead-icon.c /Foundead-icon.obj undead.res: icons\undead.rc .\puzzles.rc2 icons\undead.ico .\resource.h rc $(FWHACK) $(RCFL) -r -foundead.res icons\undead.rc undead3.obj: .\undead.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\undead.c /Foundead3.obj unequal.obj: .\unequal.c .\puzzles.h .\latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\unequal.c /Founequal.obj unequal-icon.obj: icons\unequal-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\unequal-icon.c /Founequal-icon.obj unequal.res: icons\unequal.rc .\puzzles.rc2 icons\unequal.ico .\resource.h rc $(FWHACK) $(RCFL) -r -founequal.res icons\unequal.rc unequal5.obj: .\unequal.c .\puzzles.h .\latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\unequal.c /Founequal5.obj unequal2.obj: .\unequal.c .\puzzles.h .\latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_SOLVER /c .\unequal.c /Founequal2.obj unruly.obj: .\unruly.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\unruly.c /Founruly.obj unruly-icon.obj: icons\unruly-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\unruly-icon.c /Founruly-icon.obj unruly.res: icons\unruly.rc .\puzzles.rc2 icons\unruly.ico .\resource.h rc $(FWHACK) $(RCFL) -r -founruly.res icons\unruly.rc unruly5.obj: .\unruly.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\unruly.c /Founruly5.obj unruly2.obj: .\unruly.c .\puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_SOLVER /c .\unruly.c /Founruly2.obj untangle.obj: .\untangle.c .\puzzles.h .\tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\untangle.c /Fountangle.obj untangle-icon.obj: icons\untangle-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\untangle-icon.c /Fountangle-icon.obj untangle.res: icons\untangle.rc .\puzzles.rc2 icons\untangle.ico \ .\resource.h rc $(FWHACK) $(RCFL) -r -fountangle.res icons\untangle.rc untangl3.obj: .\untangle.c .\puzzles.h .\tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\untangle.c /Fountangl3.obj version.obj: .\version.c .\version.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\version.c /Foversion.obj windows.obj: .\windows.c .\puzzles.h .\resource.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\windows.c /Fowindows.obj windows1.obj: .\windows.c .\puzzles.h .\resource.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\windows.c /Fowindows1.obj clean: tidy -del *.exe tidy: -del *.obj -del *.res -del *.pch -del *.aps -del *.ilk -del *.pdb -del *.rsp -del *.dsp -del *.dsw -del *.ncb -del *.opt -del *.plg -del *.map -del *.idb -del debug.log puzzles-20170606.272beef/Makefile.vc0000644000175000017500000017074213115375145015753 0ustar simonsimon# Makefile for puzzles under Visual C. # # This file was created by `mkfiles.pl' from the `Recipe' file. # DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead. # If you rename this file to `Makefile', you should change this line, # so that the .rsp files still depend on the correct makefile. MAKEFILE = Makefile.vc # C compilation flags CFLAGS = /nologo /W3 /O1 /D_WINDOWS /D_WIN32_WINDOWS=0x401 /DWINVER=0x401 /I. LFLAGS = /incremental:no /fixed all: blackbox.exe bridges.exe cube.exe dominosa.exe fifteen.exe \ fifteensolver.exe filling.exe fillingsolver.exe flip.exe \ flood.exe galaxies.exe galaxiespicture.exe \ galaxiessolver.exe guess.exe inertia.exe keen.exe \ keensolver.exe latincheck.exe lightup.exe lightupsolver.exe \ loopy.exe loopysolver.exe magnets.exe magnetssolver.exe \ map.exe mapsolver.exe mineobfusc.exe mines.exe netgame.exe \ netslide.exe nullgame.exe palisade.exe pattern.exe \ patternpicture.exe patternsolver.exe pearl.exe \ pearlbench.exe pegs.exe puzzles.exe range.exe rect.exe \ samegame.exe signpost.exe signpostsolver.exe singles.exe \ singlessolver.exe sixteen.exe slant.exe slantsolver.exe \ solo.exe solosolver.exe tents.exe tentssolver.exe towers.exe \ towerssolver.exe tracks.exe twiddle.exe undead.exe \ unequal.exe unequalsolver.exe unruly.exe unrulysolver.exe \ untangle.exe blackbox.exe: blackbox.obj blackbox.res drawing.obj malloc.obj midend.obj \ misc.obj printing.obj random.obj version.obj windows.obj \ blackbox.rsp link $(LFLAGS) -out:blackbox.exe -map:blackbox.map @blackbox.rsp bridges.exe: bridges.obj bridges.res drawing.obj dsf.obj findloop.obj \ malloc.obj midend.obj misc.obj printing.obj random.obj \ version.obj windows.obj bridges.rsp link $(LFLAGS) -out:bridges.exe -map:bridges.map @bridges.rsp cube.exe: cube.obj cube.res drawing.obj malloc.obj midend.obj misc.obj \ printing.obj random.obj version.obj windows.obj cube.rsp link $(LFLAGS) -out:cube.exe -map:cube.map @cube.rsp dominosa.exe: dominosa.obj dominosa.res drawing.obj laydomino.obj malloc.obj \ midend.obj misc.obj printing.obj random.obj version.obj \ windows.obj dominosa.rsp link $(LFLAGS) -out:dominosa.exe -map:dominosa.map @dominosa.rsp fifteen.exe: drawing.obj fifteen.obj fifteen.res malloc.obj midend.obj \ misc.obj printing.obj random.obj version.obj windows.obj \ fifteen.rsp link $(LFLAGS) -out:fifteen.exe -map:fifteen.map @fifteen.rsp fifteensolver.exe: fifteen2.obj malloc.obj misc.obj nullfe.obj random.obj \ fifteensolver.rsp link $(LFLAGS) -out:fifteensolver.exe -map:fifteensolver.map @fifteensolver.rsp filling.exe: drawing.obj dsf.obj filling.obj filling.res malloc.obj \ midend.obj misc.obj printing.obj random.obj version.obj \ windows.obj filling.rsp link $(LFLAGS) -out:filling.exe -map:filling.map @filling.rsp fillingsolver.exe: dsf.obj filling2.obj malloc.obj misc.obj nullfe.obj \ random.obj fillingsolver.rsp link $(LFLAGS) -out:fillingsolver.exe -map:fillingsolver.map @fillingsolver.rsp flip.exe: drawing.obj flip.obj flip.res malloc.obj midend.obj misc.obj \ printing.obj random.obj tree234.obj version.obj windows.obj \ flip.rsp link $(LFLAGS) -out:flip.exe -map:flip.map @flip.rsp flood.exe: drawing.obj flood.obj flood.res malloc.obj midend.obj misc.obj \ printing.obj random.obj version.obj windows.obj flood.rsp link $(LFLAGS) -out:flood.exe -map:flood.map @flood.rsp galaxies.exe: drawing.obj dsf.obj galaxies.obj galaxies.res malloc.obj \ midend.obj misc.obj printing.obj random.obj version.obj \ windows.obj galaxies.rsp link $(LFLAGS) -out:galaxies.exe -map:galaxies.map @galaxies.rsp galaxiespicture.exe: dsf.obj galaxie4.obj malloc.obj misc.obj nullfe.obj \ random.obj galaxiespicture.rsp link $(LFLAGS) -out:galaxiespicture.exe -map:galaxiespicture.map @galaxiespicture.rsp galaxiessolver.exe: dsf.obj galaxie2.obj malloc.obj misc.obj nullfe.obj \ random.obj galaxiessolver.rsp link $(LFLAGS) -out:galaxiessolver.exe -map:galaxiessolver.map @galaxiessolver.rsp guess.exe: drawing.obj guess.obj guess.res malloc.obj midend.obj misc.obj \ printing.obj random.obj version.obj windows.obj guess.rsp link $(LFLAGS) -out:guess.exe -map:guess.map @guess.rsp inertia.exe: drawing.obj inertia.obj inertia.res malloc.obj midend.obj \ misc.obj printing.obj random.obj version.obj windows.obj \ inertia.rsp link $(LFLAGS) -out:inertia.exe -map:inertia.map @inertia.rsp keen.exe: drawing.obj dsf.obj keen.obj keen.res latin.obj malloc.obj \ maxflow.obj midend.obj misc.obj printing.obj random.obj \ tree234.obj version.obj windows.obj keen.rsp link $(LFLAGS) -out:keen.exe -map:keen.map @keen.rsp keensolver.exe: dsf.obj keen2.obj latin6.obj malloc.obj maxflow.obj misc.obj \ nullfe.obj random.obj tree234.obj keensolver.rsp link $(LFLAGS) -out:keensolver.exe -map:keensolver.map @keensolver.rsp latincheck.exe: latin8.obj malloc.obj maxflow.obj misc.obj nullfe.obj \ random.obj tree234.obj latincheck.rsp link $(LFLAGS) -out:latincheck.exe -map:latincheck.map @latincheck.rsp lightup.exe: combi.obj drawing.obj lightup.obj lightup.res malloc.obj \ midend.obj misc.obj printing.obj random.obj version.obj \ windows.obj lightup.rsp link $(LFLAGS) -out:lightup.exe -map:lightup.map @lightup.rsp lightupsolver.exe: combi.obj lightup2.obj malloc.obj misc.obj nullfe.obj \ random.obj lightupsolver.rsp link $(LFLAGS) -out:lightupsolver.exe -map:lightupsolver.map @lightupsolver.rsp loopy.exe: drawing.obj dsf.obj grid.obj loopgen.obj loopy.obj loopy.res \ malloc.obj midend.obj misc.obj penrose.obj printing.obj \ random.obj tree234.obj version.obj windows.obj loopy.rsp link $(LFLAGS) -out:loopy.exe -map:loopy.map @loopy.rsp loopysolver.exe: dsf.obj grid.obj loopgen.obj loopy2.obj malloc.obj misc.obj \ nullfe.obj penrose.obj random.obj tree234.obj \ loopysolver.rsp link $(LFLAGS) -out:loopysolver.exe -map:loopysolver.map @loopysolver.rsp magnets.exe: drawing.obj laydomino.obj magnets.obj magnets.res malloc.obj \ midend.obj misc.obj printing.obj random.obj version.obj \ windows.obj magnets.rsp link $(LFLAGS) -out:magnets.exe -map:magnets.map @magnets.rsp magnetssolver.exe: laydomino.obj magnets2.obj malloc.obj misc.obj nullfe.obj \ random.obj magnetssolver.rsp link $(LFLAGS) -out:magnetssolver.exe -map:magnetssolver.map @magnetssolver.rsp map.exe: drawing.obj dsf.obj malloc.obj map.obj map.res midend.obj misc.obj \ printing.obj random.obj version.obj windows.obj map.rsp link $(LFLAGS) -out:map.exe -map:map.map @map.rsp mapsolver.exe: dsf.obj malloc.obj map2.obj misc.obj nullfe.obj random.obj \ mapsolver.rsp link $(LFLAGS) -out:mapsolver.exe -map:mapsolver.map @mapsolver.rsp mineobfusc.exe: malloc.obj mines2.obj misc.obj nullfe.obj random.obj \ tree234.obj mineobfusc.rsp link $(LFLAGS) -out:mineobfusc.exe -map:mineobfusc.map @mineobfusc.rsp mines.exe: drawing.obj malloc.obj midend.obj mines.obj mines.res misc.obj \ printing.obj random.obj tree234.obj version.obj windows.obj \ mines.rsp link $(LFLAGS) -out:mines.exe -map:mines.map @mines.rsp netgame.exe: drawing.obj dsf.obj findloop.obj malloc.obj midend.obj misc.obj \ net.obj net.res printing.obj random.obj tree234.obj \ version.obj windows.obj netgame.rsp link $(LFLAGS) -out:netgame.exe -map:netgame.map @netgame.rsp netslide.exe: drawing.obj malloc.obj midend.obj misc.obj netslide.obj \ netslide.res printing.obj random.obj tree234.obj version.obj \ windows.obj netslide.rsp link $(LFLAGS) -out:netslide.exe -map:netslide.map @netslide.rsp nullgame.exe: drawing.obj malloc.obj midend.obj misc.obj noicon.res \ nullgame.obj printing.obj random.obj version.obj windows.obj \ nullgame.rsp link $(LFLAGS) -out:nullgame.exe -map:nullgame.map @nullgame.rsp palisade.exe: divvy.obj drawing.obj dsf.obj malloc.obj midend.obj misc.obj \ palisade.obj palisade.res printing.obj random.obj \ version.obj windows.obj palisade.rsp link $(LFLAGS) -out:palisade.exe -map:palisade.map @palisade.rsp pattern.exe: drawing.obj malloc.obj midend.obj misc.obj pattern.obj \ pattern.res printing.obj random.obj version.obj windows.obj \ pattern.rsp link $(LFLAGS) -out:pattern.exe -map:pattern.map @pattern.rsp patternpicture.exe: malloc.obj misc.obj nullfe.obj pattern4.obj random.obj \ patternpicture.rsp link $(LFLAGS) -out:patternpicture.exe -map:patternpicture.map @patternpicture.rsp patternsolver.exe: malloc.obj misc.obj nullfe.obj pattern2.obj random.obj \ patternsolver.rsp link $(LFLAGS) -out:patternsolver.exe -map:patternsolver.map @patternsolver.rsp pearl.exe: drawing.obj dsf.obj grid.obj loopgen.obj malloc.obj midend.obj \ misc.obj pearl.obj pearl.res penrose.obj printing.obj \ random.obj tdq.obj tree234.obj version.obj windows.obj \ pearl.rsp link $(LFLAGS) -out:pearl.exe -map:pearl.map @pearl.rsp pearlbench.exe: dsf.obj grid.obj loopgen.obj malloc.obj misc.obj nullfe.obj \ pearl2.obj penrose.obj random.obj tdq.obj tree234.obj \ pearlbench.rsp link $(LFLAGS) -out:pearlbench.exe -map:pearlbench.map @pearlbench.rsp pegs.exe: drawing.obj malloc.obj midend.obj misc.obj pegs.obj pegs.res \ printing.obj random.obj tree234.obj version.obj windows.obj \ pegs.rsp link $(LFLAGS) -out:pegs.exe -map:pegs.map @pegs.rsp puzzles.exe: blackbo3.obj bridges3.obj combi.obj cube3.obj divvy.obj \ dominos3.obj drawing.obj dsf.obj fifteen5.obj filling5.obj \ findloop.obj flip3.obj flood3.obj galaxie7.obj grid.obj \ guess3.obj inertia3.obj keen5.obj latin.obj laydomino.obj \ lightup5.obj list.obj loopgen.obj loopy5.obj magnets5.obj \ malloc.obj map5.obj maxflow.obj midend.obj mines5.obj \ misc.obj net3.obj netslid3.obj noicon.res palisad3.obj \ pattern7.obj pearl5.obj pegs3.obj penrose.obj printing.obj \ random.obj range3.obj rect3.obj samegam3.obj signpos5.obj \ singles5.obj sixteen3.obj slant5.obj solo5.obj tdq.obj \ tents5.obj towers5.obj tracks3.obj tree234.obj twiddle3.obj \ undead3.obj unequal5.obj unruly5.obj untangl3.obj \ version.obj windows1.obj puzzles.rsp link $(LFLAGS) -out:puzzles.exe -map:puzzles.map @puzzles.rsp range.exe: drawing.obj dsf.obj malloc.obj midend.obj misc.obj printing.obj \ random.obj range.obj range.res version.obj windows.obj \ range.rsp link $(LFLAGS) -out:range.exe -map:range.map @range.rsp rect.exe: drawing.obj malloc.obj midend.obj misc.obj printing.obj random.obj \ rect.obj rect.res version.obj windows.obj rect.rsp link $(LFLAGS) -out:rect.exe -map:rect.map @rect.rsp samegame.exe: drawing.obj malloc.obj midend.obj misc.obj printing.obj \ random.obj samegame.obj samegame.res version.obj windows.obj \ samegame.rsp link $(LFLAGS) -out:samegame.exe -map:samegame.map @samegame.rsp signpost.exe: drawing.obj dsf.obj malloc.obj midend.obj misc.obj \ printing.obj random.obj signpost.obj signpost.res \ version.obj windows.obj signpost.rsp link $(LFLAGS) -out:signpost.exe -map:signpost.map @signpost.rsp signpostsolver.exe: dsf.obj malloc.obj misc.obj nullfe.obj random.obj \ signpos2.obj signpostsolver.rsp link $(LFLAGS) -out:signpostsolver.exe -map:signpostsolver.map @signpostsolver.rsp singles.exe: drawing.obj dsf.obj latin.obj malloc.obj maxflow.obj midend.obj \ misc.obj printing.obj random.obj singles.obj singles.res \ tree234.obj version.obj windows.obj singles.rsp link $(LFLAGS) -out:singles.exe -map:singles.map @singles.rsp singlessolver.exe: dsf.obj latin.obj malloc.obj maxflow.obj misc.obj \ nullfe.obj random.obj singles3.obj tree234.obj \ singlessolver.rsp link $(LFLAGS) -out:singlessolver.exe -map:singlessolver.map @singlessolver.rsp sixteen.exe: drawing.obj malloc.obj midend.obj misc.obj printing.obj \ random.obj sixteen.obj sixteen.res version.obj windows.obj \ sixteen.rsp link $(LFLAGS) -out:sixteen.exe -map:sixteen.map @sixteen.rsp slant.exe: drawing.obj dsf.obj findloop.obj malloc.obj midend.obj misc.obj \ printing.obj random.obj slant.obj slant.res version.obj \ windows.obj slant.rsp link $(LFLAGS) -out:slant.exe -map:slant.map @slant.rsp slantsolver.exe: dsf.obj findloop.obj malloc.obj misc.obj nullfe.obj \ random.obj slant2.obj slantsolver.rsp link $(LFLAGS) -out:slantsolver.exe -map:slantsolver.map @slantsolver.rsp solo.exe: divvy.obj drawing.obj dsf.obj malloc.obj midend.obj misc.obj \ printing.obj random.obj solo.obj solo.res version.obj \ windows.obj solo.rsp link $(LFLAGS) -out:solo.exe -map:solo.map @solo.rsp solosolver.exe: divvy.obj dsf.obj malloc.obj misc.obj nullfe.obj random.obj \ solo2.obj solosolver.rsp link $(LFLAGS) -out:solosolver.exe -map:solosolver.map @solosolver.rsp tents.exe: drawing.obj dsf.obj malloc.obj maxflow.obj midend.obj misc.obj \ printing.obj random.obj tents.obj tents.res version.obj \ windows.obj tents.rsp link $(LFLAGS) -out:tents.exe -map:tents.map @tents.rsp tentssolver.exe: dsf.obj malloc.obj maxflow.obj misc.obj nullfe.obj \ random.obj tents3.obj tentssolver.rsp link $(LFLAGS) -out:tentssolver.exe -map:tentssolver.map @tentssolver.rsp towers.exe: drawing.obj latin.obj malloc.obj maxflow.obj midend.obj misc.obj \ printing.obj random.obj towers.obj towers.res tree234.obj \ version.obj windows.obj towers.rsp link $(LFLAGS) -out:towers.exe -map:towers.map @towers.rsp towerssolver.exe: latin6.obj malloc.obj maxflow.obj misc.obj nullfe.obj \ random.obj towers2.obj tree234.obj towerssolver.rsp link $(LFLAGS) -out:towerssolver.exe -map:towerssolver.map @towerssolver.rsp tracks.exe: drawing.obj dsf.obj findloop.obj malloc.obj midend.obj misc.obj \ printing.obj random.obj tracks.obj tracks.res version.obj \ windows.obj tracks.rsp link $(LFLAGS) -out:tracks.exe -map:tracks.map @tracks.rsp twiddle.exe: drawing.obj malloc.obj midend.obj misc.obj printing.obj \ random.obj twiddle.obj twiddle.res version.obj windows.obj \ twiddle.rsp link $(LFLAGS) -out:twiddle.exe -map:twiddle.map @twiddle.rsp undead.exe: drawing.obj malloc.obj midend.obj misc.obj printing.obj \ random.obj undead.obj undead.res version.obj windows.obj \ undead.rsp link $(LFLAGS) -out:undead.exe -map:undead.map @undead.rsp unequal.exe: drawing.obj latin.obj malloc.obj maxflow.obj midend.obj \ misc.obj printing.obj random.obj tree234.obj unequal.obj \ unequal.res version.obj windows.obj unequal.rsp link $(LFLAGS) -out:unequal.exe -map:unequal.map @unequal.rsp unequalsolver.exe: latin6.obj malloc.obj maxflow.obj misc.obj nullfe.obj \ random.obj tree234.obj unequal2.obj unequalsolver.rsp link $(LFLAGS) -out:unequalsolver.exe -map:unequalsolver.map @unequalsolver.rsp unruly.exe: drawing.obj malloc.obj midend.obj misc.obj printing.obj \ random.obj unruly.obj unruly.res version.obj windows.obj \ unruly.rsp link $(LFLAGS) -out:unruly.exe -map:unruly.map @unruly.rsp unrulysolver.exe: malloc.obj misc.obj nullfe.obj random.obj unruly2.obj \ unrulysolver.rsp link $(LFLAGS) -out:unrulysolver.exe -map:unrulysolver.map @unrulysolver.rsp untangle.exe: drawing.obj malloc.obj midend.obj misc.obj printing.obj \ random.obj tree234.obj untangle.obj untangle.res version.obj \ windows.obj untangle.rsp link $(LFLAGS) -out:untangle.exe -map:untangle.map @untangle.rsp blackbox.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > blackbox.rsp echo blackbox.obj blackbox.res comctl32.lib >> blackbox.rsp echo comdlg32.lib drawing.obj gdi32.lib malloc.obj >> blackbox.rsp echo midend.obj misc.obj printing.obj random.obj >> blackbox.rsp echo user32.lib version.obj windows.obj winspool.lib >> blackbox.rsp bridges.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > bridges.rsp echo bridges.obj bridges.res comctl32.lib comdlg32.lib >> bridges.rsp echo drawing.obj dsf.obj findloop.obj gdi32.lib >> bridges.rsp echo malloc.obj midend.obj misc.obj printing.obj >> bridges.rsp echo random.obj user32.lib version.obj windows.obj >> bridges.rsp echo winspool.lib >> bridges.rsp cube.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > cube.rsp echo comctl32.lib comdlg32.lib cube.obj cube.res >> cube.rsp echo drawing.obj gdi32.lib malloc.obj midend.obj >> cube.rsp echo misc.obj printing.obj random.obj user32.lib >> cube.rsp echo version.obj windows.obj winspool.lib >> cube.rsp dominosa.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > dominosa.rsp echo comctl32.lib comdlg32.lib dominosa.obj >> dominosa.rsp echo dominosa.res drawing.obj gdi32.lib laydomino.obj >> dominosa.rsp echo malloc.obj midend.obj misc.obj printing.obj >> dominosa.rsp echo random.obj user32.lib version.obj windows.obj >> dominosa.rsp echo winspool.lib >> dominosa.rsp fifteen.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > fifteen.rsp echo comctl32.lib comdlg32.lib drawing.obj fifteen.obj >> fifteen.rsp echo fifteen.res gdi32.lib malloc.obj midend.obj >> fifteen.rsp echo misc.obj printing.obj random.obj user32.lib >> fifteen.rsp echo version.obj windows.obj winspool.lib >> fifteen.rsp fifteensolver.rsp: $(MAKEFILE) echo /nologo /subsystem:console > fifteensolver.rsp echo fifteen2.obj malloc.obj misc.obj nullfe.obj >> fifteensolver.rsp echo random.obj >> fifteensolver.rsp filling.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > filling.rsp echo comctl32.lib comdlg32.lib drawing.obj dsf.obj >> filling.rsp echo filling.obj filling.res gdi32.lib malloc.obj >> filling.rsp echo midend.obj misc.obj printing.obj random.obj >> filling.rsp echo user32.lib version.obj windows.obj winspool.lib >> filling.rsp fillingsolver.rsp: $(MAKEFILE) echo /nologo /subsystem:console > fillingsolver.rsp echo dsf.obj filling2.obj malloc.obj misc.obj >> fillingsolver.rsp echo nullfe.obj random.obj >> fillingsolver.rsp flip.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > flip.rsp echo comctl32.lib comdlg32.lib drawing.obj flip.obj >> flip.rsp echo flip.res gdi32.lib malloc.obj midend.obj misc.obj >> flip.rsp echo printing.obj random.obj tree234.obj user32.lib >> flip.rsp echo version.obj windows.obj winspool.lib >> flip.rsp flood.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > flood.rsp echo comctl32.lib comdlg32.lib drawing.obj flood.obj >> flood.rsp echo flood.res gdi32.lib malloc.obj midend.obj >> flood.rsp echo misc.obj printing.obj random.obj user32.lib >> flood.rsp echo version.obj windows.obj winspool.lib >> flood.rsp galaxies.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > galaxies.rsp echo comctl32.lib comdlg32.lib drawing.obj dsf.obj >> galaxies.rsp echo galaxies.obj galaxies.res gdi32.lib malloc.obj >> galaxies.rsp echo midend.obj misc.obj printing.obj random.obj >> galaxies.rsp echo user32.lib version.obj windows.obj winspool.lib >> galaxies.rsp galaxiespicture.rsp: $(MAKEFILE) echo /nologo /subsystem:console > galaxiespicture.rsp echo dsf.obj galaxie4.obj malloc.obj misc.obj >> galaxiespicture.rsp echo nullfe.obj random.obj >> galaxiespicture.rsp galaxiessolver.rsp: $(MAKEFILE) echo /nologo /subsystem:console > galaxiessolver.rsp echo dsf.obj galaxie2.obj malloc.obj misc.obj >> galaxiessolver.rsp echo nullfe.obj random.obj >> galaxiessolver.rsp guess.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > guess.rsp echo comctl32.lib comdlg32.lib drawing.obj gdi32.lib >> guess.rsp echo guess.obj guess.res malloc.obj midend.obj >> guess.rsp echo misc.obj printing.obj random.obj user32.lib >> guess.rsp echo version.obj windows.obj winspool.lib >> guess.rsp inertia.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > inertia.rsp echo comctl32.lib comdlg32.lib drawing.obj gdi32.lib >> inertia.rsp echo inertia.obj inertia.res malloc.obj midend.obj >> inertia.rsp echo misc.obj printing.obj random.obj user32.lib >> inertia.rsp echo version.obj windows.obj winspool.lib >> inertia.rsp keen.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > keen.rsp echo comctl32.lib comdlg32.lib drawing.obj dsf.obj >> keen.rsp echo gdi32.lib keen.obj keen.res latin.obj malloc.obj >> keen.rsp echo maxflow.obj midend.obj misc.obj printing.obj >> keen.rsp echo random.obj tree234.obj user32.lib version.obj >> keen.rsp echo windows.obj winspool.lib >> keen.rsp keensolver.rsp: $(MAKEFILE) echo /nologo /subsystem:console > keensolver.rsp echo dsf.obj keen2.obj latin6.obj malloc.obj >> keensolver.rsp echo maxflow.obj misc.obj nullfe.obj random.obj >> keensolver.rsp echo tree234.obj >> keensolver.rsp latincheck.rsp: $(MAKEFILE) echo /nologo /subsystem:console > latincheck.rsp echo latin8.obj malloc.obj maxflow.obj misc.obj >> latincheck.rsp echo nullfe.obj random.obj tree234.obj >> latincheck.rsp lightup.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > lightup.rsp echo combi.obj comctl32.lib comdlg32.lib drawing.obj >> lightup.rsp echo gdi32.lib lightup.obj lightup.res malloc.obj >> lightup.rsp echo midend.obj misc.obj printing.obj random.obj >> lightup.rsp echo user32.lib version.obj windows.obj winspool.lib >> lightup.rsp lightupsolver.rsp: $(MAKEFILE) echo /nologo /subsystem:console > lightupsolver.rsp echo combi.obj lightup2.obj malloc.obj misc.obj >> lightupsolver.rsp echo nullfe.obj random.obj >> lightupsolver.rsp loopy.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > loopy.rsp echo comctl32.lib comdlg32.lib drawing.obj dsf.obj >> loopy.rsp echo gdi32.lib grid.obj loopgen.obj loopy.obj >> loopy.rsp echo loopy.res malloc.obj midend.obj misc.obj >> loopy.rsp echo penrose.obj printing.obj random.obj tree234.obj >> loopy.rsp echo user32.lib version.obj windows.obj winspool.lib >> loopy.rsp loopysolver.rsp: $(MAKEFILE) echo /nologo /subsystem:console > loopysolver.rsp echo dsf.obj grid.obj loopgen.obj loopy2.obj >> loopysolver.rsp echo malloc.obj misc.obj nullfe.obj penrose.obj >> loopysolver.rsp echo random.obj tree234.obj >> loopysolver.rsp magnets.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > magnets.rsp echo comctl32.lib comdlg32.lib drawing.obj gdi32.lib >> magnets.rsp echo laydomino.obj magnets.obj magnets.res malloc.obj >> magnets.rsp echo midend.obj misc.obj printing.obj random.obj >> magnets.rsp echo user32.lib version.obj windows.obj winspool.lib >> magnets.rsp magnetssolver.rsp: $(MAKEFILE) echo /nologo /subsystem:console > magnetssolver.rsp echo laydomino.obj magnets2.obj malloc.obj misc.obj >> magnetssolver.rsp echo nullfe.obj random.obj >> magnetssolver.rsp map.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > map.rsp echo comctl32.lib comdlg32.lib drawing.obj dsf.obj >> map.rsp echo gdi32.lib malloc.obj map.obj map.res midend.obj >> map.rsp echo misc.obj printing.obj random.obj user32.lib >> map.rsp echo version.obj windows.obj winspool.lib >> map.rsp mapsolver.rsp: $(MAKEFILE) echo /nologo /subsystem:console > mapsolver.rsp echo dsf.obj malloc.obj map2.obj misc.obj nullfe.obj >> mapsolver.rsp echo random.obj >> mapsolver.rsp mineobfusc.rsp: $(MAKEFILE) echo /nologo /subsystem:console > mineobfusc.rsp echo malloc.obj mines2.obj misc.obj nullfe.obj >> mineobfusc.rsp echo random.obj tree234.obj >> mineobfusc.rsp mines.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > mines.rsp echo comctl32.lib comdlg32.lib drawing.obj gdi32.lib >> mines.rsp echo malloc.obj midend.obj mines.obj mines.res >> mines.rsp echo misc.obj printing.obj random.obj tree234.obj >> mines.rsp echo user32.lib version.obj windows.obj winspool.lib >> mines.rsp netgame.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > netgame.rsp echo comctl32.lib comdlg32.lib drawing.obj dsf.obj >> netgame.rsp echo findloop.obj gdi32.lib malloc.obj midend.obj >> netgame.rsp echo misc.obj net.obj net.res printing.obj random.obj >> netgame.rsp echo tree234.obj user32.lib version.obj windows.obj >> netgame.rsp echo winspool.lib >> netgame.rsp netslide.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > netslide.rsp echo comctl32.lib comdlg32.lib drawing.obj gdi32.lib >> netslide.rsp echo malloc.obj midend.obj misc.obj netslide.obj >> netslide.rsp echo netslide.res printing.obj random.obj tree234.obj >> netslide.rsp echo user32.lib version.obj windows.obj winspool.lib >> netslide.rsp nullgame.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > nullgame.rsp echo comctl32.lib comdlg32.lib drawing.obj gdi32.lib >> nullgame.rsp echo malloc.obj midend.obj misc.obj noicon.res >> nullgame.rsp echo nullgame.obj printing.obj random.obj user32.lib >> nullgame.rsp echo version.obj windows.obj winspool.lib >> nullgame.rsp palisade.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > palisade.rsp echo comctl32.lib comdlg32.lib divvy.obj drawing.obj >> palisade.rsp echo dsf.obj gdi32.lib malloc.obj midend.obj misc.obj >> palisade.rsp echo palisade.obj palisade.res printing.obj random.obj >> palisade.rsp echo user32.lib version.obj windows.obj winspool.lib >> palisade.rsp pattern.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > pattern.rsp echo comctl32.lib comdlg32.lib drawing.obj gdi32.lib >> pattern.rsp echo malloc.obj midend.obj misc.obj pattern.obj >> pattern.rsp echo pattern.res printing.obj random.obj user32.lib >> pattern.rsp echo version.obj windows.obj winspool.lib >> pattern.rsp patternpicture.rsp: $(MAKEFILE) echo /nologo /subsystem:console > patternpicture.rsp echo malloc.obj misc.obj nullfe.obj pattern4.obj >> patternpicture.rsp echo random.obj >> patternpicture.rsp patternsolver.rsp: $(MAKEFILE) echo /nologo /subsystem:console > patternsolver.rsp echo malloc.obj misc.obj nullfe.obj pattern2.obj >> patternsolver.rsp echo random.obj >> patternsolver.rsp pearl.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > pearl.rsp echo comctl32.lib comdlg32.lib drawing.obj dsf.obj >> pearl.rsp echo gdi32.lib grid.obj loopgen.obj malloc.obj >> pearl.rsp echo midend.obj misc.obj pearl.obj pearl.res >> pearl.rsp echo penrose.obj printing.obj random.obj tdq.obj >> pearl.rsp echo tree234.obj user32.lib version.obj windows.obj >> pearl.rsp echo winspool.lib >> pearl.rsp pearlbench.rsp: $(MAKEFILE) echo /nologo /subsystem:console > pearlbench.rsp echo dsf.obj grid.obj loopgen.obj malloc.obj misc.obj >> pearlbench.rsp echo nullfe.obj pearl2.obj penrose.obj random.obj >> pearlbench.rsp echo tdq.obj tree234.obj >> pearlbench.rsp pegs.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > pegs.rsp echo comctl32.lib comdlg32.lib drawing.obj gdi32.lib >> pegs.rsp echo malloc.obj midend.obj misc.obj pegs.obj pegs.res >> pegs.rsp echo printing.obj random.obj tree234.obj user32.lib >> pegs.rsp echo version.obj windows.obj winspool.lib >> pegs.rsp puzzles.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > puzzles.rsp echo blackbo3.obj bridges3.obj combi.obj comctl32.lib >> puzzles.rsp echo comdlg32.lib cube3.obj divvy.obj dominos3.obj >> puzzles.rsp echo drawing.obj dsf.obj fifteen5.obj filling5.obj >> puzzles.rsp echo findloop.obj flip3.obj flood3.obj galaxie7.obj >> puzzles.rsp echo gdi32.lib grid.obj guess3.obj inertia3.obj >> puzzles.rsp echo keen5.obj latin.obj laydomino.obj lightup5.obj >> puzzles.rsp echo list.obj loopgen.obj loopy5.obj magnets5.obj >> puzzles.rsp echo malloc.obj map5.obj maxflow.obj midend.obj >> puzzles.rsp echo mines5.obj misc.obj net3.obj netslid3.obj >> puzzles.rsp echo noicon.res palisad3.obj pattern7.obj pearl5.obj >> puzzles.rsp echo pegs3.obj penrose.obj printing.obj random.obj >> puzzles.rsp echo range3.obj rect3.obj samegam3.obj signpos5.obj >> puzzles.rsp echo singles5.obj sixteen3.obj slant5.obj solo5.obj >> puzzles.rsp echo tdq.obj tents5.obj towers5.obj tracks3.obj >> puzzles.rsp echo tree234.obj twiddle3.obj undead3.obj unequal5.obj >> puzzles.rsp echo unruly5.obj untangl3.obj user32.lib version.obj >> puzzles.rsp echo windows1.obj winspool.lib >> puzzles.rsp range.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > range.rsp echo comctl32.lib comdlg32.lib drawing.obj dsf.obj >> range.rsp echo gdi32.lib malloc.obj midend.obj misc.obj >> range.rsp echo printing.obj random.obj range.obj range.res >> range.rsp echo user32.lib version.obj windows.obj winspool.lib >> range.rsp rect.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > rect.rsp echo comctl32.lib comdlg32.lib drawing.obj gdi32.lib >> rect.rsp echo malloc.obj midend.obj misc.obj printing.obj >> rect.rsp echo random.obj rect.obj rect.res user32.lib >> rect.rsp echo version.obj windows.obj winspool.lib >> rect.rsp samegame.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > samegame.rsp echo comctl32.lib comdlg32.lib drawing.obj gdi32.lib >> samegame.rsp echo malloc.obj midend.obj misc.obj printing.obj >> samegame.rsp echo random.obj samegame.obj samegame.res user32.lib >> samegame.rsp echo version.obj windows.obj winspool.lib >> samegame.rsp signpost.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > signpost.rsp echo comctl32.lib comdlg32.lib drawing.obj dsf.obj >> signpost.rsp echo gdi32.lib malloc.obj midend.obj misc.obj >> signpost.rsp echo printing.obj random.obj signpost.obj signpost.res >> signpost.rsp echo user32.lib version.obj windows.obj winspool.lib >> signpost.rsp signpostsolver.rsp: $(MAKEFILE) echo /nologo /subsystem:console > signpostsolver.rsp echo dsf.obj malloc.obj misc.obj nullfe.obj random.obj >> signpostsolver.rsp echo signpos2.obj >> signpostsolver.rsp singles.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > singles.rsp echo comctl32.lib comdlg32.lib drawing.obj dsf.obj >> singles.rsp echo gdi32.lib latin.obj malloc.obj maxflow.obj >> singles.rsp echo midend.obj misc.obj printing.obj random.obj >> singles.rsp echo singles.obj singles.res tree234.obj user32.lib >> singles.rsp echo version.obj windows.obj winspool.lib >> singles.rsp singlessolver.rsp: $(MAKEFILE) echo /nologo /subsystem:console > singlessolver.rsp echo dsf.obj latin.obj malloc.obj maxflow.obj misc.obj >> singlessolver.rsp echo nullfe.obj random.obj singles3.obj tree234.obj >> singlessolver.rsp sixteen.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > sixteen.rsp echo comctl32.lib comdlg32.lib drawing.obj gdi32.lib >> sixteen.rsp echo malloc.obj midend.obj misc.obj printing.obj >> sixteen.rsp echo random.obj sixteen.obj sixteen.res user32.lib >> sixteen.rsp echo version.obj windows.obj winspool.lib >> sixteen.rsp slant.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > slant.rsp echo comctl32.lib comdlg32.lib drawing.obj dsf.obj >> slant.rsp echo findloop.obj gdi32.lib malloc.obj midend.obj >> slant.rsp echo misc.obj printing.obj random.obj slant.obj >> slant.rsp echo slant.res user32.lib version.obj windows.obj >> slant.rsp echo winspool.lib >> slant.rsp slantsolver.rsp: $(MAKEFILE) echo /nologo /subsystem:console > slantsolver.rsp echo dsf.obj findloop.obj malloc.obj misc.obj >> slantsolver.rsp echo nullfe.obj random.obj slant2.obj >> slantsolver.rsp solo.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > solo.rsp echo comctl32.lib comdlg32.lib divvy.obj drawing.obj >> solo.rsp echo dsf.obj gdi32.lib malloc.obj midend.obj misc.obj >> solo.rsp echo printing.obj random.obj solo.obj solo.res >> solo.rsp echo user32.lib version.obj windows.obj winspool.lib >> solo.rsp solosolver.rsp: $(MAKEFILE) echo /nologo /subsystem:console > solosolver.rsp echo divvy.obj dsf.obj malloc.obj misc.obj nullfe.obj >> solosolver.rsp echo random.obj solo2.obj >> solosolver.rsp tents.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > tents.rsp echo comctl32.lib comdlg32.lib drawing.obj dsf.obj >> tents.rsp echo gdi32.lib malloc.obj maxflow.obj midend.obj >> tents.rsp echo misc.obj printing.obj random.obj tents.obj >> tents.rsp echo tents.res user32.lib version.obj windows.obj >> tents.rsp echo winspool.lib >> tents.rsp tentssolver.rsp: $(MAKEFILE) echo /nologo /subsystem:console > tentssolver.rsp echo dsf.obj malloc.obj maxflow.obj misc.obj >> tentssolver.rsp echo nullfe.obj random.obj tents3.obj >> tentssolver.rsp towers.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > towers.rsp echo comctl32.lib comdlg32.lib drawing.obj gdi32.lib >> towers.rsp echo latin.obj malloc.obj maxflow.obj midend.obj >> towers.rsp echo misc.obj printing.obj random.obj towers.obj >> towers.rsp echo towers.res tree234.obj user32.lib version.obj >> towers.rsp echo windows.obj winspool.lib >> towers.rsp towerssolver.rsp: $(MAKEFILE) echo /nologo /subsystem:console > towerssolver.rsp echo latin6.obj malloc.obj maxflow.obj misc.obj >> towerssolver.rsp echo nullfe.obj random.obj towers2.obj tree234.obj >> towerssolver.rsp tracks.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > tracks.rsp echo comctl32.lib comdlg32.lib drawing.obj dsf.obj >> tracks.rsp echo findloop.obj gdi32.lib malloc.obj midend.obj >> tracks.rsp echo misc.obj printing.obj random.obj tracks.obj >> tracks.rsp echo tracks.res user32.lib version.obj windows.obj >> tracks.rsp echo winspool.lib >> tracks.rsp twiddle.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > twiddle.rsp echo comctl32.lib comdlg32.lib drawing.obj gdi32.lib >> twiddle.rsp echo malloc.obj midend.obj misc.obj printing.obj >> twiddle.rsp echo random.obj twiddle.obj twiddle.res user32.lib >> twiddle.rsp echo version.obj windows.obj winspool.lib >> twiddle.rsp undead.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > undead.rsp echo comctl32.lib comdlg32.lib drawing.obj gdi32.lib >> undead.rsp echo malloc.obj midend.obj misc.obj printing.obj >> undead.rsp echo random.obj undead.obj undead.res user32.lib >> undead.rsp echo version.obj windows.obj winspool.lib >> undead.rsp unequal.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > unequal.rsp echo comctl32.lib comdlg32.lib drawing.obj gdi32.lib >> unequal.rsp echo latin.obj malloc.obj maxflow.obj midend.obj >> unequal.rsp echo misc.obj printing.obj random.obj tree234.obj >> unequal.rsp echo unequal.obj unequal.res user32.lib version.obj >> unequal.rsp echo windows.obj winspool.lib >> unequal.rsp unequalsolver.rsp: $(MAKEFILE) echo /nologo /subsystem:console > unequalsolver.rsp echo latin6.obj malloc.obj maxflow.obj misc.obj >> unequalsolver.rsp echo nullfe.obj random.obj tree234.obj unequal2.obj >> unequalsolver.rsp unruly.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > unruly.rsp echo comctl32.lib comdlg32.lib drawing.obj gdi32.lib >> unruly.rsp echo malloc.obj midend.obj misc.obj printing.obj >> unruly.rsp echo random.obj unruly.obj unruly.res user32.lib >> unruly.rsp echo version.obj windows.obj winspool.lib >> unruly.rsp unrulysolver.rsp: $(MAKEFILE) echo /nologo /subsystem:console > unrulysolver.rsp echo malloc.obj misc.obj nullfe.obj random.obj >> unrulysolver.rsp echo unruly2.obj >> unrulysolver.rsp untangle.rsp: $(MAKEFILE) echo /nologo /subsystem:windows > untangle.rsp echo comctl32.lib comdlg32.lib drawing.obj gdi32.lib >> untangle.rsp echo malloc.obj midend.obj misc.obj printing.obj >> untangle.rsp echo random.obj tree234.obj untangle.obj untangle.res >> untangle.rsp echo user32.lib version.obj windows.obj winspool.lib >> untangle.rsp blackbox.obj: .\blackbox.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\blackbox.c /Foblackbox.obj blackbox-icon.obj: icons\blackbox-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\blackbox-icon.c /Foblackbox-icon.obj blackbox.res: icons\blackbox.rc .\puzzles.rc2 icons\blackbox.ico \ .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -foblackbox.res icons\blackbox.rc blackbo3.obj: .\blackbox.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\blackbox.c /Foblackbo3.obj bridges.obj: .\bridges.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\bridges.c /Fobridges.obj bridges-icon.obj: icons\bridges-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\bridges-icon.c /Fobridges-icon.obj bridges.res: icons\bridges.rc .\puzzles.rc2 icons\bridges.ico .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -fobridges.res icons\bridges.rc bridges3.obj: .\bridges.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\bridges.c /Fobridges3.obj combi.obj: .\combi.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\combi.c /Focombi.obj cube.obj: .\cube.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\cube.c /Focube.obj cube-icon.obj: icons\cube-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\cube-icon.c /Focube-icon.obj cube.res: icons\cube.rc .\puzzles.rc2 icons\cube.ico .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -focube.res icons\cube.rc cube3.obj: .\cube.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\cube.c /Focube3.obj divvy.obj: .\divvy.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\divvy.c /Fodivvy.obj dominosa.obj: .\dominosa.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\dominosa.c /Fodominosa.obj dominosa-icon.obj: icons\dominosa-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\dominosa-icon.c /Fodominosa-icon.obj dominosa.res: icons\dominosa.rc .\puzzles.rc2 icons\dominosa.ico \ .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -fodominosa.res icons\dominosa.rc dominos3.obj: .\dominosa.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\dominosa.c /Fodominos3.obj drawing.obj: .\drawing.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\drawing.c /Fodrawing.obj dsf.obj: .\dsf.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\dsf.c /Fodsf.obj fifteen.obj: .\fifteen.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\fifteen.c /Fofifteen.obj fifteen-icon.obj: icons\fifteen-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\fifteen-icon.c /Fofifteen-icon.obj fifteen.res: icons\fifteen.rc .\puzzles.rc2 icons\fifteen.ico .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -fofifteen.res icons\fifteen.rc fifteen5.obj: .\fifteen.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\fifteen.c /Fofifteen5.obj fifteen2.obj: .\fifteen.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_SOLVER /c .\fifteen.c /Fofifteen2.obj filling.obj: .\filling.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\filling.c /Fofilling.obj filling-icon.obj: icons\filling-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\filling-icon.c /Fofilling-icon.obj filling.res: icons\filling.rc .\puzzles.rc2 icons\filling.ico .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -fofilling.res icons\filling.rc filling5.obj: .\filling.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\filling.c /Fofilling5.obj filling2.obj: .\filling.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_SOLVER /c .\filling.c /Fofilling2.obj findloop.obj: .\findloop.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\findloop.c /Fofindloop.obj flip.obj: .\flip.c .\puzzles.h .\tree234.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\flip.c /Foflip.obj flip-icon.obj: icons\flip-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\flip-icon.c /Foflip-icon.obj flip.res: icons\flip.rc .\puzzles.rc2 icons\flip.ico .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -foflip.res icons\flip.rc flip3.obj: .\flip.c .\puzzles.h .\tree234.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\flip.c /Foflip3.obj flood.obj: .\flood.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\flood.c /Foflood.obj flood-icon.obj: icons\flood-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\flood-icon.c /Foflood-icon.obj flood.res: icons\flood.rc .\puzzles.rc2 icons\flood.ico .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -foflood.res icons\flood.rc flood3.obj: .\flood.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\flood.c /Foflood3.obj galaxies.obj: .\galaxies.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\galaxies.c /Fogalaxies.obj galaxies-icon.obj: icons\galaxies-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\galaxies-icon.c /Fogalaxies-icon.obj galaxies.res: icons\galaxies.rc .\puzzles.rc2 icons\galaxies.ico \ .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -fogalaxies.res icons\galaxies.rc galaxie7.obj: .\galaxies.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\galaxies.c /Fogalaxie7.obj galaxie4.obj: .\galaxies.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_PICTURE_GENERATOR /c .\galaxies.c /Fogalaxie4.obj galaxie2.obj: .\galaxies.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_SOLVER /c .\galaxies.c /Fogalaxie2.obj grid.obj: .\grid.c .\puzzles.h .\tree234.h .\grid.h .\penrose.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\grid.c /Fogrid.obj gtk.obj: .\gtk.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\gtk.c /Fogtk.obj guess.obj: .\guess.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\guess.c /Foguess.obj guess-icon.obj: icons\guess-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\guess-icon.c /Foguess-icon.obj guess.res: icons\guess.rc .\puzzles.rc2 icons\guess.ico .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -foguess.res icons\guess.rc guess3.obj: .\guess.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\guess.c /Foguess3.obj inertia.obj: .\inertia.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\inertia.c /Foinertia.obj inertia-icon.obj: icons\inertia-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\inertia-icon.c /Foinertia-icon.obj inertia.res: icons\inertia.rc .\puzzles.rc2 icons\inertia.ico .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -foinertia.res icons\inertia.rc inertia3.obj: .\inertia.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\inertia.c /Foinertia3.obj keen.obj: .\keen.c .\puzzles.h .\latin.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\keen.c /Fokeen.obj keen-icon.obj: icons\keen-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\keen-icon.c /Fokeen-icon.obj keen.res: icons\keen.rc .\puzzles.rc2 icons\keen.ico .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -fokeen.res icons\keen.rc keen5.obj: .\keen.c .\puzzles.h .\latin.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\keen.c /Fokeen5.obj keen2.obj: .\keen.c .\puzzles.h .\latin.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_SOLVER /c .\keen.c /Fokeen2.obj latin.obj: .\latin.c .\puzzles.h .\tree234.h .\maxflow.h .\latin.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\latin.c /Folatin.obj latin8.obj: .\latin.c .\puzzles.h .\tree234.h .\maxflow.h .\latin.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_LATIN_TEST /c .\latin.c /Folatin8.obj latin6.obj: .\latin.c .\puzzles.h .\tree234.h .\maxflow.h .\latin.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_SOLVER /c .\latin.c /Folatin6.obj laydomino.obj: .\laydomino.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\laydomino.c /Folaydomino.obj lightup.obj: .\lightup.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\lightup.c /Folightup.obj lightup-icon.obj: icons\lightup-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\lightup-icon.c /Folightup-icon.obj lightup.res: icons\lightup.rc .\puzzles.rc2 icons\lightup.ico .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -folightup.res icons\lightup.rc lightup5.obj: .\lightup.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\lightup.c /Folightup5.obj lightup2.obj: .\lightup.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_SOLVER /c .\lightup.c /Folightup2.obj list.obj: .\list.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\list.c /Folist.obj loopgen.obj: .\loopgen.c .\puzzles.h .\tree234.h .\grid.h .\loopgen.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\loopgen.c /Foloopgen.obj loopy.obj: .\loopy.c .\puzzles.h .\tree234.h .\grid.h .\loopgen.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\loopy.c /Foloopy.obj loopy-icon.obj: icons\loopy-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\loopy-icon.c /Foloopy-icon.obj loopy.res: icons\loopy.rc .\puzzles.rc2 icons\loopy.ico .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -foloopy.res icons\loopy.rc loopy5.obj: .\loopy.c .\puzzles.h .\tree234.h .\grid.h .\loopgen.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\loopy.c /Foloopy5.obj loopy2.obj: .\loopy.c .\puzzles.h .\tree234.h .\grid.h .\loopgen.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_SOLVER /c .\loopy.c /Foloopy2.obj magnets.obj: .\magnets.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\magnets.c /Fomagnets.obj magnets-icon.obj: icons\magnets-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\magnets-icon.c /Fomagnets-icon.obj magnets.res: icons\magnets.rc .\puzzles.rc2 icons\magnets.ico .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -fomagnets.res icons\magnets.rc magnets5.obj: .\magnets.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\magnets.c /Fomagnets5.obj magnets2.obj: .\magnets.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_SOLVER /c .\magnets.c /Fomagnets2.obj malloc.obj: .\malloc.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\malloc.c /Fomalloc.obj map.obj: .\map.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\map.c /Fomap.obj map-icon.obj: icons\map-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\map-icon.c /Fomap-icon.obj map.res: icons\map.rc .\puzzles.rc2 icons\map.ico .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -fomap.res icons\map.rc map5.obj: .\map.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\map.c /Fomap5.obj map2.obj: .\map.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_SOLVER /c .\map.c /Fomap2.obj maxflow.obj: .\maxflow.c .\maxflow.h .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\maxflow.c /Fomaxflow.obj midend.obj: .\midend.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\midend.c /Fomidend.obj mines.obj: .\mines.c .\tree234.h .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\mines.c /Fomines.obj mines-icon.obj: icons\mines-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\mines-icon.c /Fomines-icon.obj mines.res: icons\mines.rc .\puzzles.rc2 icons\mines.ico .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -fomines.res icons\mines.rc mines5.obj: .\mines.c .\tree234.h .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\mines.c /Fomines5.obj mines2.obj: .\mines.c .\tree234.h .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_OBFUSCATOR /c .\mines.c /Fomines2.obj misc.obj: .\misc.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\misc.c /Fomisc.obj net.obj: .\net.c .\puzzles.h .\tree234.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\net.c /Fonet.obj net-icon.obj: icons\net-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\net-icon.c /Fonet-icon.obj net.res: icons\net.rc .\puzzles.rc2 icons\net.ico .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -fonet.res icons\net.rc net3.obj: .\net.c .\puzzles.h .\tree234.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\net.c /Fonet3.obj netslide.obj: .\netslide.c .\puzzles.h .\tree234.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\netslide.c /Fonetslide.obj netslide-icon.obj: icons\netslide-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\netslide-icon.c /Fonetslide-icon.obj netslide.res: icons\netslide.rc .\puzzles.rc2 icons\netslide.ico \ .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -fonetslide.res icons\netslide.rc netslid3.obj: .\netslide.c .\puzzles.h .\tree234.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\netslide.c /Fonetslid3.obj no-icon.obj: .\no-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\no-icon.c /Fono-icon.obj noicon.res: .\noicon.rc .\puzzles.rc2 .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -fonoicon.res .\noicon.rc nullfe.obj: .\nullfe.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\nullfe.c /Fonullfe.obj nullgame.obj: .\nullgame.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\nullgame.c /Fonullgame.obj obfusc.obj: .\obfusc.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\obfusc.c /Foobfusc.obj osx.obj: .\osx.m .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\osx.m /Foosx.obj palisade.obj: .\palisade.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\palisade.c /Fopalisade.obj palisade-icon.obj: icons\palisade-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\palisade-icon.c /Fopalisade-icon.obj palisade.res: icons\palisade.rc .\puzzles.rc2 icons\palisade.ico \ .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -fopalisade.res icons\palisade.rc palisad3.obj: .\palisade.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\palisade.c /Fopalisad3.obj pattern.obj: .\pattern.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\pattern.c /Fopattern.obj pattern-icon.obj: icons\pattern-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\pattern-icon.c /Fopattern-icon.obj pattern.res: icons\pattern.rc .\puzzles.rc2 icons\pattern.ico .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -fopattern.res icons\pattern.rc pattern7.obj: .\pattern.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\pattern.c /Fopattern7.obj pattern4.obj: .\pattern.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_PICTURE_GENERATOR /c .\pattern.c /Fopattern4.obj pattern2.obj: .\pattern.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_SOLVER /c .\pattern.c /Fopattern2.obj pearl.obj: .\pearl.c .\puzzles.h .\grid.h .\loopgen.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\pearl.c /Fopearl.obj pearl-icon.obj: icons\pearl-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\pearl-icon.c /Fopearl-icon.obj pearl.res: icons\pearl.rc .\puzzles.rc2 icons\pearl.ico .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -fopearl.res icons\pearl.rc pearl5.obj: .\pearl.c .\puzzles.h .\grid.h .\loopgen.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\pearl.c /Fopearl5.obj pearl2.obj: .\pearl.c .\puzzles.h .\grid.h .\loopgen.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_SOLVER /c .\pearl.c /Fopearl2.obj pegs.obj: .\pegs.c .\puzzles.h .\tree234.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\pegs.c /Fopegs.obj pegs-icon.obj: icons\pegs-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\pegs-icon.c /Fopegs-icon.obj pegs.res: icons\pegs.rc .\puzzles.rc2 icons\pegs.ico .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -fopegs.res icons\pegs.rc pegs3.obj: .\pegs.c .\puzzles.h .\tree234.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\pegs.c /Fopegs3.obj penrose.obj: .\penrose.c .\puzzles.h .\penrose.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\penrose.c /Fopenrose.obj printing.obj: .\printing.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\printing.c /Foprinting.obj ps.obj: .\ps.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\ps.c /Fops.obj random.obj: .\random.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\random.c /Forandom.obj range.obj: .\range.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\range.c /Forange.obj range-icon.obj: icons\range-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\range-icon.c /Forange-icon.obj range.res: icons\range.rc .\puzzles.rc2 icons\range.ico .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -forange.res icons\range.rc range3.obj: .\range.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\range.c /Forange3.obj rect.obj: .\rect.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\rect.c /Forect.obj rect-icon.obj: icons\rect-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\rect-icon.c /Forect-icon.obj rect.res: icons\rect.rc .\puzzles.rc2 icons\rect.ico .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -forect.res icons\rect.rc rect3.obj: .\rect.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\rect.c /Forect3.obj samegame.obj: .\samegame.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\samegame.c /Fosamegame.obj samegame-icon.obj: icons\samegame-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\samegame-icon.c /Fosamegame-icon.obj samegame.res: icons\samegame.rc .\puzzles.rc2 icons\samegame.ico \ .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -fosamegame.res icons\samegame.rc samegam3.obj: .\samegame.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\samegame.c /Fosamegam3.obj signpost.obj: .\signpost.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\signpost.c /Fosignpost.obj signpost-icon.obj: icons\signpost-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\signpost-icon.c /Fosignpost-icon.obj signpost.res: icons\signpost.rc .\puzzles.rc2 icons\signpost.ico \ .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -fosignpost.res icons\signpost.rc signpos5.obj: .\signpost.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\signpost.c /Fosignpos5.obj signpos2.obj: .\signpost.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_SOLVER /c .\signpost.c /Fosignpos2.obj singles.obj: .\singles.c .\puzzles.h .\latin.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\singles.c /Fosingles.obj singles-icon.obj: icons\singles-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\singles-icon.c /Fosingles-icon.obj singles.res: icons\singles.rc .\puzzles.rc2 icons\singles.ico .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -fosingles.res icons\singles.rc singles5.obj: .\singles.c .\puzzles.h .\latin.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\singles.c /Fosingles5.obj singles3.obj: .\singles.c .\puzzles.h .\latin.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_SOLVER /c .\singles.c /Fosingles3.obj sixteen.obj: .\sixteen.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\sixteen.c /Fosixteen.obj sixteen-icon.obj: icons\sixteen-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\sixteen-icon.c /Fosixteen-icon.obj sixteen.res: icons\sixteen.rc .\puzzles.rc2 icons\sixteen.ico .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -fosixteen.res icons\sixteen.rc sixteen3.obj: .\sixteen.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\sixteen.c /Fosixteen3.obj slant.obj: .\slant.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\slant.c /Foslant.obj slant-icon.obj: icons\slant-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\slant-icon.c /Foslant-icon.obj slant.res: icons\slant.rc .\puzzles.rc2 icons\slant.ico .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -foslant.res icons\slant.rc slant5.obj: .\slant.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\slant.c /Foslant5.obj slant2.obj: .\slant.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_SOLVER /c .\slant.c /Foslant2.obj solo.obj: .\solo.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\solo.c /Fosolo.obj solo-icon.obj: icons\solo-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\solo-icon.c /Fosolo-icon.obj solo.res: icons\solo.rc .\puzzles.rc2 icons\solo.ico .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -fosolo.res icons\solo.rc solo5.obj: .\solo.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\solo.c /Fosolo5.obj solo2.obj: .\solo.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_SOLVER /c .\solo.c /Fosolo2.obj tdq.obj: .\tdq.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\tdq.c /Fotdq.obj tents.obj: .\tents.c .\puzzles.h .\maxflow.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\tents.c /Fotents.obj tents-icon.obj: icons\tents-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\tents-icon.c /Fotents-icon.obj tents.res: icons\tents.rc .\puzzles.rc2 icons\tents.ico .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -fotents.res icons\tents.rc tents5.obj: .\tents.c .\puzzles.h .\maxflow.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\tents.c /Fotents5.obj tents3.obj: .\tents.c .\puzzles.h .\maxflow.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_SOLVER /c .\tents.c /Fotents3.obj towers.obj: .\towers.c .\puzzles.h .\latin.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\towers.c /Fotowers.obj towers-icon.obj: icons\towers-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\towers-icon.c /Fotowers-icon.obj towers.res: icons\towers.rc .\puzzles.rc2 icons\towers.ico .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -fotowers.res icons\towers.rc towers5.obj: .\towers.c .\puzzles.h .\latin.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\towers.c /Fotowers5.obj towers2.obj: .\towers.c .\puzzles.h .\latin.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_SOLVER /c .\towers.c /Fotowers2.obj tracks.obj: .\tracks.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\tracks.c /Fotracks.obj tracks-icon.obj: icons\tracks-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\tracks-icon.c /Fotracks-icon.obj tracks.res: icons\tracks.rc .\puzzles.rc2 icons\tracks.ico .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -fotracks.res icons\tracks.rc tracks3.obj: .\tracks.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\tracks.c /Fotracks3.obj tree234.obj: .\tree234.c .\tree234.h .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\tree234.c /Fotree234.obj twiddle.obj: .\twiddle.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\twiddle.c /Fotwiddle.obj twiddle-icon.obj: icons\twiddle-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\twiddle-icon.c /Fotwiddle-icon.obj twiddle.res: icons\twiddle.rc .\puzzles.rc2 icons\twiddle.ico .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -fotwiddle.res icons\twiddle.rc twiddle3.obj: .\twiddle.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\twiddle.c /Fotwiddle3.obj undead.obj: .\undead.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\undead.c /Foundead.obj undead-icon.obj: icons\undead-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\undead-icon.c /Foundead-icon.obj undead.res: icons\undead.rc .\puzzles.rc2 icons\undead.ico .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -foundead.res icons\undead.rc undead3.obj: .\undead.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\undead.c /Foundead3.obj unequal.obj: .\unequal.c .\puzzles.h .\latin.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\unequal.c /Founequal.obj unequal-icon.obj: icons\unequal-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\unequal-icon.c /Founequal-icon.obj unequal.res: icons\unequal.rc .\puzzles.rc2 icons\unequal.ico .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -founequal.res icons\unequal.rc unequal5.obj: .\unequal.c .\puzzles.h .\latin.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\unequal.c /Founequal5.obj unequal2.obj: .\unequal.c .\puzzles.h .\latin.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_SOLVER /c .\unequal.c /Founequal2.obj unruly.obj: .\unruly.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\unruly.c /Founruly.obj unruly-icon.obj: icons\unruly-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\unruly-icon.c /Founruly-icon.obj unruly.res: icons\unruly.rc .\puzzles.rc2 icons\unruly.ico .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -founruly.res icons\unruly.rc unruly5.obj: .\unruly.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\unruly.c /Founruly5.obj unruly2.obj: .\unruly.c .\puzzles.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DSTANDALONE_SOLVER /c .\unruly.c /Founruly2.obj untangle.obj: .\untangle.c .\puzzles.h .\tree234.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\untangle.c /Fountangle.obj untangle-icon.obj: icons\untangle-icon.c cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c icons\untangle-icon.c /Fountangle-icon.obj untangle.res: icons\untangle.rc .\puzzles.rc2 icons\untangle.ico \ .\resource.h rc $(FWHACK) $(RCFL) -r -DWIN32 -D_WIN32 -DWINVER=0x0400 -fountangle.res icons\untangle.rc untangl3.obj: .\untangle.c .\puzzles.h .\tree234.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\untangle.c /Fountangl3.obj version.obj: .\version.c .\version.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\version.c /Foversion.obj windows.obj: .\windows.c .\puzzles.h .\resource.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /c .\windows.c /Fowindows.obj windows1.obj: .\windows.c .\puzzles.h .\resource.h cl $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) /DCOMBINED /c .\windows.c /Fowindows1.obj clean: tidy -del *.exe tidy: -del *.obj -del *.res -del *.pch -del *.aps -del *.ilk -del *.pdb -del *.rsp -del *.dsp -del *.dsw -del *.ncb -del *.opt -del *.plg -del *.map -del *.idb -del debug.log puzzles-20170606.272beef/Makefile.osx0000644000175000017500000011130313115375145016140 0ustar simonsimon# Makefile for puzzles under Mac OS X. # # This file was created by `mkfiles.pl' from the `Recipe' file. # DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead. CC = $(TOOLPATH)gcc LIPO = $(TOOLPATH)lipo CFLAGS = -O2 -Wall -Werror -g -I./ -Iicons/ LDFLAGS = -framework Cocoa all: Puzzles fifteensolver fillingsolver galaxiespicture galaxiessolver \ keensolver latincheck lightupsolver loopysolver \ magnetssolver mapsolver mineobfusc obfusc patternpicture \ patternsolver pearlbench signpostsolver singlessolver \ slantsolver solosolver tentssolver towerssolver \ unequalsolver unrulysolver Puzzles_extra = Puzzles.app/Contents/Resources/Help/index.html Puzzles.app/Contents/Resources/Help/index.html: \ Puzzles.app/Contents/Resources/Help osx-help.but puzzles.but cd Puzzles.app/Contents/Resources/Help; \ halibut --html ../../../../osx-help.but ../../../../puzzles.but Puzzles.app/Contents/Resources/Help: Puzzles.app/Contents/Resources mkdir -p Puzzles.app/Contents/Resources/Help release: Puzzles.dmg Puzzles.dmg: Puzzles rm -f raw.dmg hdiutil create -megabytes 5 -layout NONE raw.dmg hdid -nomount raw.dmg > devicename newfs_hfs -v "Simon Tatham's Puzzle Collection" `cat devicename` hdiutil eject `cat devicename` hdid raw.dmg | cut -f1 -d' ' > devicename cp -R Puzzles.app /Volumes/"Simon Tatham's Puzzle Collection" hdiutil eject `cat devicename` rm -f Puzzles.dmg hdiutil convert -format UDCO raw.dmg -o Puzzles.dmg rm -f raw.dmg devicename .SUFFIXES: .o .c .m Puzzles.app: mkdir -p $@ Puzzles.app/Contents: Puzzles.app mkdir -p $@ Puzzles.app/Contents/MacOS: Puzzles.app/Contents mkdir -p $@ Puzzles.app/Contents/Resources: Puzzles.app/Contents mkdir -p $@ Puzzles.app/Contents/Resources/Puzzles.icns: Puzzles.app/Contents/Resources osx.icns cp osx.icns $@ Puzzles.app/Contents/Info.plist: Puzzles.app/Contents/Resources osx-info.plist cp osx-info.plist $@ Puzzles: Puzzles.app/Contents/MacOS/Puzzles \ Puzzles.app/Contents/Resources/Puzzles.icns \ Puzzles.app/Contents/Info.plist $(Puzzles_extra) Puzzles.i386.bin: blackbo3.i386.o bridges3.i386.o combi.i386.o cube3.i386.o \ divvy.i386.o dominos3.i386.o drawing.i386.o dsf.i386.o \ fifteen5.i386.o filling5.i386.o findloop.i386.o flip3.i386.o \ flood3.i386.o galaxie7.i386.o grid.i386.o guess3.i386.o \ inertia3.i386.o keen5.i386.o latin.i386.o laydomino.i386.o \ lightup5.i386.o list.i386.o loopgen.i386.o loopy5.i386.o \ magnets5.i386.o malloc.i386.o map5.i386.o maxflow.i386.o \ midend.i386.o mines5.i386.o misc.i386.o net3.i386.o \ netslid3.i386.o osx.i386.o palisad3.i386.o pattern7.i386.o \ pearl5.i386.o pegs3.i386.o penrose.i386.o random.i386.o \ range3.i386.o rect3.i386.o samegam3.i386.o signpos5.i386.o \ singles5.i386.o sixteen3.i386.o slant5.i386.o solo5.i386.o \ tdq.i386.o tents5.i386.o towers5.i386.o tracks3.i386.o \ tree234.i386.o twiddle3.i386.o undead3.i386.o \ unequal5.i386.o unruly5.i386.o untangl3.i386.o \ version.i386.o $(CC) -arch i386 -mmacosx-version-min=10.4 $(LDFLAGS) -o $@ \ blackbo3.i386.o bridges3.i386.o combi.i386.o cube3.i386.o \ divvy.i386.o dominos3.i386.o drawing.i386.o dsf.i386.o \ fifteen5.i386.o filling5.i386.o findloop.i386.o flip3.i386.o \ flood3.i386.o galaxie7.i386.o grid.i386.o guess3.i386.o \ inertia3.i386.o keen5.i386.o latin.i386.o laydomino.i386.o \ lightup5.i386.o list.i386.o loopgen.i386.o loopy5.i386.o \ magnets5.i386.o malloc.i386.o map5.i386.o maxflow.i386.o \ midend.i386.o mines5.i386.o misc.i386.o net3.i386.o \ netslid3.i386.o osx.i386.o palisad3.i386.o pattern7.i386.o \ pearl5.i386.o pegs3.i386.o penrose.i386.o random.i386.o \ range3.i386.o rect3.i386.o samegam3.i386.o signpos5.i386.o \ singles5.i386.o sixteen3.i386.o slant5.i386.o solo5.i386.o \ tdq.i386.o tents5.i386.o towers5.i386.o tracks3.i386.o \ tree234.i386.o twiddle3.i386.o undead3.i386.o \ unequal5.i386.o unruly5.i386.o untangl3.i386.o \ version.i386.o Puzzles.app/Contents/MacOS/Puzzles: Puzzles.app/Contents/MacOS \ Puzzles.i386.bin $(LIPO) -create Puzzles.i386.bin -output $@ fifteensolver.i386: fifteen2.i386.o malloc.i386.o misc.i386.o nullfe.i386.o \ random.i386.o $(CC) -arch i386 -mmacosx-version-min=10.4 $(ULDFLAGS) -o $@ \ fifteen2.i386.o malloc.i386.o misc.i386.o nullfe.i386.o \ random.i386.o fifteensolver: fifteensolver.i386 $(LIPO) -create fifteensolver.i386 -output $@ fillingsolver.i386: dsf.i386.o filling2.i386.o malloc.i386.o misc.i386.o \ nullfe.i386.o random.i386.o $(CC) -arch i386 -mmacosx-version-min=10.4 $(ULDFLAGS) -o $@ \ dsf.i386.o filling2.i386.o malloc.i386.o misc.i386.o \ nullfe.i386.o random.i386.o fillingsolver: fillingsolver.i386 $(LIPO) -create fillingsolver.i386 -output $@ galaxiespicture.i386: dsf.i386.o galaxie4.i386.o malloc.i386.o misc.i386.o \ nullfe.i386.o random.i386.o $(CC) -arch i386 -mmacosx-version-min=10.4 $(ULDFLAGS) -o $@ \ dsf.i386.o galaxie4.i386.o malloc.i386.o misc.i386.o \ nullfe.i386.o random.i386.o -lm galaxiespicture: galaxiespicture.i386 $(LIPO) -create galaxiespicture.i386 -output $@ galaxiessolver.i386: dsf.i386.o galaxie2.i386.o malloc.i386.o misc.i386.o \ nullfe.i386.o random.i386.o $(CC) -arch i386 -mmacosx-version-min=10.4 $(ULDFLAGS) -o $@ \ dsf.i386.o galaxie2.i386.o malloc.i386.o misc.i386.o \ nullfe.i386.o random.i386.o -lm galaxiessolver: galaxiessolver.i386 $(LIPO) -create galaxiessolver.i386 -output $@ keensolver.i386: dsf.i386.o keen2.i386.o latin6.i386.o malloc.i386.o \ maxflow.i386.o misc.i386.o nullfe.i386.o random.i386.o \ tree234.i386.o $(CC) -arch i386 -mmacosx-version-min=10.4 $(ULDFLAGS) -o $@ \ dsf.i386.o keen2.i386.o latin6.i386.o malloc.i386.o \ maxflow.i386.o misc.i386.o nullfe.i386.o random.i386.o \ tree234.i386.o keensolver: keensolver.i386 $(LIPO) -create keensolver.i386 -output $@ latincheck.i386: latin8.i386.o malloc.i386.o maxflow.i386.o misc.i386.o \ nullfe.i386.o random.i386.o tree234.i386.o $(CC) -arch i386 -mmacosx-version-min=10.4 $(ULDFLAGS) -o $@ \ latin8.i386.o malloc.i386.o maxflow.i386.o misc.i386.o \ nullfe.i386.o random.i386.o tree234.i386.o latincheck: latincheck.i386 $(LIPO) -create latincheck.i386 -output $@ lightupsolver.i386: combi.i386.o lightup2.i386.o malloc.i386.o misc.i386.o \ nullfe.i386.o random.i386.o $(CC) -arch i386 -mmacosx-version-min=10.4 $(ULDFLAGS) -o $@ \ combi.i386.o lightup2.i386.o malloc.i386.o misc.i386.o \ nullfe.i386.o random.i386.o lightupsolver: lightupsolver.i386 $(LIPO) -create lightupsolver.i386 -output $@ loopysolver.i386: dsf.i386.o grid.i386.o loopgen.i386.o loopy2.i386.o \ malloc.i386.o misc.i386.o nullfe.i386.o penrose.i386.o \ random.i386.o tree234.i386.o $(CC) -arch i386 -mmacosx-version-min=10.4 $(ULDFLAGS) -o $@ \ dsf.i386.o grid.i386.o loopgen.i386.o loopy2.i386.o \ malloc.i386.o misc.i386.o nullfe.i386.o penrose.i386.o \ random.i386.o tree234.i386.o -lm loopysolver: loopysolver.i386 $(LIPO) -create loopysolver.i386 -output $@ magnetssolver.i386: laydomino.i386.o magnets2.i386.o malloc.i386.o \ misc.i386.o nullfe.i386.o random.i386.o $(CC) -arch i386 -mmacosx-version-min=10.4 $(ULDFLAGS) -o $@ \ laydomino.i386.o magnets2.i386.o malloc.i386.o misc.i386.o \ nullfe.i386.o random.i386.o -lm magnetssolver: magnetssolver.i386 $(LIPO) -create magnetssolver.i386 -output $@ mapsolver.i386: dsf.i386.o malloc.i386.o map2.i386.o misc.i386.o \ nullfe.i386.o random.i386.o $(CC) -arch i386 -mmacosx-version-min=10.4 $(ULDFLAGS) -o $@ \ dsf.i386.o malloc.i386.o map2.i386.o misc.i386.o \ nullfe.i386.o random.i386.o -lm mapsolver: mapsolver.i386 $(LIPO) -create mapsolver.i386 -output $@ mineobfusc.i386: malloc.i386.o mines2.i386.o misc.i386.o nullfe.i386.o \ random.i386.o tree234.i386.o $(CC) -arch i386 -mmacosx-version-min=10.4 $(ULDFLAGS) -o $@ \ malloc.i386.o mines2.i386.o misc.i386.o nullfe.i386.o \ random.i386.o tree234.i386.o mineobfusc: mineobfusc.i386 $(LIPO) -create mineobfusc.i386 -output $@ obfusc.i386: malloc.i386.o misc.i386.o nullfe.i386.o obfusc.i386.o \ random.i386.o $(CC) -arch i386 -mmacosx-version-min=10.4 $(ULDFLAGS) -o $@ \ malloc.i386.o misc.i386.o nullfe.i386.o obfusc.i386.o \ random.i386.o obfusc: obfusc.i386 $(LIPO) -create obfusc.i386 -output $@ patternpicture.i386: malloc.i386.o misc.i386.o nullfe.i386.o pattern4.i386.o \ random.i386.o $(CC) -arch i386 -mmacosx-version-min=10.4 $(ULDFLAGS) -o $@ \ malloc.i386.o misc.i386.o nullfe.i386.o pattern4.i386.o \ random.i386.o patternpicture: patternpicture.i386 $(LIPO) -create patternpicture.i386 -output $@ patternsolver.i386: malloc.i386.o misc.i386.o nullfe.i386.o pattern2.i386.o \ random.i386.o $(CC) -arch i386 -mmacosx-version-min=10.4 $(ULDFLAGS) -o $@ \ malloc.i386.o misc.i386.o nullfe.i386.o pattern2.i386.o \ random.i386.o patternsolver: patternsolver.i386 $(LIPO) -create patternsolver.i386 -output $@ pearlbench.i386: dsf.i386.o grid.i386.o loopgen.i386.o malloc.i386.o \ misc.i386.o nullfe.i386.o pearl2.i386.o penrose.i386.o \ random.i386.o tdq.i386.o tree234.i386.o $(CC) -arch i386 -mmacosx-version-min=10.4 $(ULDFLAGS) -o $@ \ dsf.i386.o grid.i386.o loopgen.i386.o malloc.i386.o \ misc.i386.o nullfe.i386.o pearl2.i386.o penrose.i386.o \ random.i386.o tdq.i386.o tree234.i386.o -lm pearlbench: pearlbench.i386 $(LIPO) -create pearlbench.i386 -output $@ signpostsolver.i386: dsf.i386.o malloc.i386.o misc.i386.o nullfe.i386.o \ random.i386.o signpos2.i386.o $(CC) -arch i386 -mmacosx-version-min=10.4 $(ULDFLAGS) -o $@ \ dsf.i386.o malloc.i386.o misc.i386.o nullfe.i386.o \ random.i386.o signpos2.i386.o -lm signpostsolver: signpostsolver.i386 $(LIPO) -create signpostsolver.i386 -output $@ singlessolver.i386: dsf.i386.o latin.i386.o malloc.i386.o maxflow.i386.o \ misc.i386.o nullfe.i386.o random.i386.o singles3.i386.o \ tree234.i386.o $(CC) -arch i386 -mmacosx-version-min=10.4 $(ULDFLAGS) -o $@ \ dsf.i386.o latin.i386.o malloc.i386.o maxflow.i386.o \ misc.i386.o nullfe.i386.o random.i386.o singles3.i386.o \ tree234.i386.o singlessolver: singlessolver.i386 $(LIPO) -create singlessolver.i386 -output $@ slantsolver.i386: dsf.i386.o findloop.i386.o malloc.i386.o misc.i386.o \ nullfe.i386.o random.i386.o slant2.i386.o $(CC) -arch i386 -mmacosx-version-min=10.4 $(ULDFLAGS) -o $@ \ dsf.i386.o findloop.i386.o malloc.i386.o misc.i386.o \ nullfe.i386.o random.i386.o slant2.i386.o slantsolver: slantsolver.i386 $(LIPO) -create slantsolver.i386 -output $@ solosolver.i386: divvy.i386.o dsf.i386.o malloc.i386.o misc.i386.o \ nullfe.i386.o random.i386.o solo2.i386.o $(CC) -arch i386 -mmacosx-version-min=10.4 $(ULDFLAGS) -o $@ \ divvy.i386.o dsf.i386.o malloc.i386.o misc.i386.o \ nullfe.i386.o random.i386.o solo2.i386.o solosolver: solosolver.i386 $(LIPO) -create solosolver.i386 -output $@ tentssolver.i386: dsf.i386.o malloc.i386.o maxflow.i386.o misc.i386.o \ nullfe.i386.o random.i386.o tents3.i386.o $(CC) -arch i386 -mmacosx-version-min=10.4 $(ULDFLAGS) -o $@ \ dsf.i386.o malloc.i386.o maxflow.i386.o misc.i386.o \ nullfe.i386.o random.i386.o tents3.i386.o tentssolver: tentssolver.i386 $(LIPO) -create tentssolver.i386 -output $@ towerssolver.i386: latin6.i386.o malloc.i386.o maxflow.i386.o misc.i386.o \ nullfe.i386.o random.i386.o towers2.i386.o tree234.i386.o $(CC) -arch i386 -mmacosx-version-min=10.4 $(ULDFLAGS) -o $@ \ latin6.i386.o malloc.i386.o maxflow.i386.o misc.i386.o \ nullfe.i386.o random.i386.o towers2.i386.o tree234.i386.o towerssolver: towerssolver.i386 $(LIPO) -create towerssolver.i386 -output $@ unequalsolver.i386: latin6.i386.o malloc.i386.o maxflow.i386.o misc.i386.o \ nullfe.i386.o random.i386.o tree234.i386.o unequal2.i386.o $(CC) -arch i386 -mmacosx-version-min=10.4 $(ULDFLAGS) -o $@ \ latin6.i386.o malloc.i386.o maxflow.i386.o misc.i386.o \ nullfe.i386.o random.i386.o tree234.i386.o unequal2.i386.o unequalsolver: unequalsolver.i386 $(LIPO) -create unequalsolver.i386 -output $@ unrulysolver.i386: malloc.i386.o misc.i386.o nullfe.i386.o random.i386.o \ unruly2.i386.o $(CC) -arch i386 -mmacosx-version-min=10.4 $(ULDFLAGS) -o $@ \ malloc.i386.o misc.i386.o nullfe.i386.o random.i386.o \ unruly2.i386.o unrulysolver: unrulysolver.i386 $(LIPO) -create unrulysolver.i386 -output $@ blackbox.i386.o: ./blackbox.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ blackbox-icon.i386.o: icons/blackbox-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ blackbo3.i386.o: ./blackbox.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ bridges.i386.o: ./bridges.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ bridges-icon.i386.o: icons/bridges-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ bridges3.i386.o: ./bridges.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ combi.i386.o: ./combi.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ cube.i386.o: ./cube.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ cube-icon.i386.o: icons/cube-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ cube3.i386.o: ./cube.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ divvy.i386.o: ./divvy.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ dominosa.i386.o: ./dominosa.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ dominosa-icon.i386.o: icons/dominosa-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ dominos3.i386.o: ./dominosa.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ drawing.i386.o: ./drawing.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ dsf.i386.o: ./dsf.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ fifteen.i386.o: ./fifteen.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ fifteen-icon.i386.o: icons/fifteen-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ fifteen5.i386.o: ./fifteen.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ fifteen2.i386.o: ./fifteen.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ filling.i386.o: ./filling.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ filling-icon.i386.o: icons/filling-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ filling5.i386.o: ./filling.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ filling2.i386.o: ./filling.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ findloop.i386.o: ./findloop.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ flip.i386.o: ./flip.c ./puzzles.h ./tree234.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ flip-icon.i386.o: icons/flip-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ flip3.i386.o: ./flip.c ./puzzles.h ./tree234.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ flood.i386.o: ./flood.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ flood-icon.i386.o: icons/flood-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ flood3.i386.o: ./flood.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ galaxies.i386.o: ./galaxies.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ galaxies-icon.i386.o: icons/galaxies-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ galaxie7.i386.o: ./galaxies.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ galaxie4.i386.o: ./galaxies.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_PICTURE_GENERATOR -c $< -o $@ galaxie2.i386.o: ./galaxies.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ grid.i386.o: ./grid.c ./puzzles.h ./tree234.h ./grid.h ./penrose.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ gtk.i386.o: ./gtk.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ guess.i386.o: ./guess.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ guess-icon.i386.o: icons/guess-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ guess3.i386.o: ./guess.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ inertia.i386.o: ./inertia.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ inertia-icon.i386.o: icons/inertia-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ inertia3.i386.o: ./inertia.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ keen.i386.o: ./keen.c ./puzzles.h ./latin.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ keen-icon.i386.o: icons/keen-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ keen5.i386.o: ./keen.c ./puzzles.h ./latin.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ keen2.i386.o: ./keen.c ./puzzles.h ./latin.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ latin.i386.o: ./latin.c ./puzzles.h ./tree234.h ./maxflow.h ./latin.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ latin8.i386.o: ./latin.c ./puzzles.h ./tree234.h ./maxflow.h ./latin.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_LATIN_TEST -c $< -o $@ latin6.i386.o: ./latin.c ./puzzles.h ./tree234.h ./maxflow.h ./latin.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ laydomino.i386.o: ./laydomino.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ lightup.i386.o: ./lightup.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ lightup-icon.i386.o: icons/lightup-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ lightup5.i386.o: ./lightup.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ lightup2.i386.o: ./lightup.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ list.i386.o: ./list.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ loopgen.i386.o: ./loopgen.c ./puzzles.h ./tree234.h ./grid.h ./loopgen.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ loopy.i386.o: ./loopy.c ./puzzles.h ./tree234.h ./grid.h ./loopgen.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ loopy-icon.i386.o: icons/loopy-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ loopy5.i386.o: ./loopy.c ./puzzles.h ./tree234.h ./grid.h ./loopgen.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ loopy2.i386.o: ./loopy.c ./puzzles.h ./tree234.h ./grid.h ./loopgen.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ magnets.i386.o: ./magnets.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ magnets-icon.i386.o: icons/magnets-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ magnets5.i386.o: ./magnets.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ magnets2.i386.o: ./magnets.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ malloc.i386.o: ./malloc.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ map.i386.o: ./map.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ map-icon.i386.o: icons/map-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ map5.i386.o: ./map.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ map2.i386.o: ./map.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ maxflow.i386.o: ./maxflow.c ./maxflow.h ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ midend.i386.o: ./midend.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ mines.i386.o: ./mines.c ./tree234.h ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ mines-icon.i386.o: icons/mines-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ mines5.i386.o: ./mines.c ./tree234.h ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ mines2.i386.o: ./mines.c ./tree234.h ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_OBFUSCATOR -c $< -o $@ misc.i386.o: ./misc.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ net.i386.o: ./net.c ./puzzles.h ./tree234.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ net-icon.i386.o: icons/net-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ net3.i386.o: ./net.c ./puzzles.h ./tree234.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ netslide.i386.o: ./netslide.c ./puzzles.h ./tree234.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ netslide-icon.i386.o: icons/netslide-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ netslid3.i386.o: ./netslide.c ./puzzles.h ./tree234.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ no-icon.i386.o: ./no-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ nullfe.i386.o: ./nullfe.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ nullgame.i386.o: ./nullgame.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ obfusc.i386.o: ./obfusc.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ osx.i386.o: ./osx.m ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 -x objective-c $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ palisade.i386.o: ./palisade.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ palisade-icon.i386.o: icons/palisade-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ palisad3.i386.o: ./palisade.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ pattern.i386.o: ./pattern.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ pattern-icon.i386.o: icons/pattern-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ pattern7.i386.o: ./pattern.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ pattern4.i386.o: ./pattern.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_PICTURE_GENERATOR -c $< -o $@ pattern2.i386.o: ./pattern.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ pearl.i386.o: ./pearl.c ./puzzles.h ./grid.h ./loopgen.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ pearl-icon.i386.o: icons/pearl-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ pearl5.i386.o: ./pearl.c ./puzzles.h ./grid.h ./loopgen.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ pearl2.i386.o: ./pearl.c ./puzzles.h ./grid.h ./loopgen.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ pegs.i386.o: ./pegs.c ./puzzles.h ./tree234.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ pegs-icon.i386.o: icons/pegs-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ pegs3.i386.o: ./pegs.c ./puzzles.h ./tree234.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ penrose.i386.o: ./penrose.c ./puzzles.h ./penrose.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ printing.i386.o: ./printing.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ ps.i386.o: ./ps.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ random.i386.o: ./random.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ range.i386.o: ./range.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ range-icon.i386.o: icons/range-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ range3.i386.o: ./range.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ rect.i386.o: ./rect.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ rect-icon.i386.o: icons/rect-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ rect3.i386.o: ./rect.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ samegame.i386.o: ./samegame.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ samegame-icon.i386.o: icons/samegame-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ samegam3.i386.o: ./samegame.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ signpost.i386.o: ./signpost.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ signpost-icon.i386.o: icons/signpost-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ signpos5.i386.o: ./signpost.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ signpos2.i386.o: ./signpost.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ singles.i386.o: ./singles.c ./puzzles.h ./latin.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ singles-icon.i386.o: icons/singles-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ singles5.i386.o: ./singles.c ./puzzles.h ./latin.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ singles3.i386.o: ./singles.c ./puzzles.h ./latin.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ sixteen.i386.o: ./sixteen.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ sixteen-icon.i386.o: icons/sixteen-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ sixteen3.i386.o: ./sixteen.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ slant.i386.o: ./slant.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ slant-icon.i386.o: icons/slant-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ slant5.i386.o: ./slant.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ slant2.i386.o: ./slant.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ solo.i386.o: ./solo.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ solo-icon.i386.o: icons/solo-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ solo5.i386.o: ./solo.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ solo2.i386.o: ./solo.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ tdq.i386.o: ./tdq.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ tents.i386.o: ./tents.c ./puzzles.h ./maxflow.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ tents-icon.i386.o: icons/tents-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ tents5.i386.o: ./tents.c ./puzzles.h ./maxflow.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ tents3.i386.o: ./tents.c ./puzzles.h ./maxflow.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ towers.i386.o: ./towers.c ./puzzles.h ./latin.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ towers-icon.i386.o: icons/towers-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ towers5.i386.o: ./towers.c ./puzzles.h ./latin.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ towers2.i386.o: ./towers.c ./puzzles.h ./latin.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ tracks.i386.o: ./tracks.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ tracks-icon.i386.o: icons/tracks-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ tracks3.i386.o: ./tracks.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ tree234.i386.o: ./tree234.c ./tree234.h ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ twiddle.i386.o: ./twiddle.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ twiddle-icon.i386.o: icons/twiddle-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ twiddle3.i386.o: ./twiddle.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ undead.i386.o: ./undead.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ undead-icon.i386.o: icons/undead-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ undead3.i386.o: ./undead.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ unequal.i386.o: ./unequal.c ./puzzles.h ./latin.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ unequal-icon.i386.o: icons/unequal-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ unequal5.i386.o: ./unequal.c ./puzzles.h ./latin.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ unequal2.i386.o: ./unequal.c ./puzzles.h ./latin.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ unruly.i386.o: ./unruly.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ unruly-icon.i386.o: icons/unruly-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ unruly5.i386.o: ./unruly.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ unruly2.i386.o: ./unruly.c ./puzzles.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ untangle.i386.o: ./untangle.c ./puzzles.h ./tree234.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ untangle-icon.i386.o: icons/untangle-icon.c $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ untangl3.i386.o: ./untangle.c ./puzzles.h ./tree234.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ version.i386.o: ./version.c ./version.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ windows.i386.o: ./windows.c ./puzzles.h ./resource.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ windows1.i386.o: ./windows.c ./puzzles.h ./resource.h $(CC) -arch i386 -mmacosx-version-min=10.4 $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ clean: rm -f *.o *.dmg fifteensolver fifteensolver.i386 fillingsolver fillingsolver.i386 galaxiespicture galaxiespicture.i386 galaxiessolver galaxiessolver.i386 keensolver keensolver.i386 latincheck latincheck.i386 lightupsolver lightupsolver.i386 loopysolver loopysolver.i386 magnetssolver magnetssolver.i386 mapsolver mapsolver.i386 mineobfusc mineobfusc.i386 obfusc obfusc.i386 patternpicture patternpicture.i386 patternsolver patternsolver.i386 pearlbench pearlbench.i386 signpostsolver signpostsolver.i386 singlessolver singlessolver.i386 slantsolver slantsolver.i386 solosolver solosolver.i386 tentssolver tentssolver.i386 towerssolver towerssolver.i386 unequalsolver unequalsolver.i386 unrulysolver unrulysolver.i386 rm -rf *.app puzzles-20170606.272beef/Makefile.nestedvm0000644000175000017500000007417413115375145017172 0ustar simonsimon# Makefile for puzzles under NestedVM. # # This file was created by `mkfiles.pl' from the `Recipe' file. # DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead. # This path points at the nestedvm root directory NESTEDVM = /opt/nestedvm # You can define this path to point at your tools if you need to TOOLPATH = $(NESTEDVM)/upstream/install/bin CC = $(TOOLPATH)/mips-unknown-elf-gcc CFLAGS = -O2 -Wall -Werror -DSLOW_SYSTEM -g -I./ -Iicons/ all: blackbox.jar bridges.jar cube.jar dominosa.jar fifteen.jar filling.jar \ flip.jar flood.jar galaxies.jar guess.jar inertia.jar \ keen.jar lightup.jar loopy.jar magnets.jar map.jar mines.jar \ net.jar netslide.jar nullgame.jar palisade.jar pattern.jar \ pearl.jar pegs.jar range.jar rect.jar samegame.jar \ signpost.jar singles.jar sixteen.jar slant.jar solo.jar \ tents.jar towers.jar tracks.jar twiddle.jar undead.jar \ unequal.jar unruly.jar untangle.jar blackbox.mips: blackbox.o blackbox-icon.o drawing.o nestedvm.o malloc.o \ midend.o misc.o printing.o ps.o random.o version.o $(CC) $(XLDFLAGS) -o $@ blackbox.o blackbox-icon.o drawing.o \ nestedvm.o malloc.o midend.o misc.o printing.o ps.o random.o \ version.o -lm bridges.mips: bridges.o bridges-icon.o drawing.o dsf.o findloop.o nestedvm.o \ malloc.o midend.o misc.o printing.o ps.o random.o version.o $(CC) $(XLDFLAGS) -o $@ bridges.o bridges-icon.o drawing.o dsf.o \ findloop.o nestedvm.o malloc.o midend.o misc.o printing.o \ ps.o random.o version.o -lm cube.mips: cube.o cube-icon.o drawing.o nestedvm.o malloc.o midend.o misc.o \ printing.o ps.o random.o version.o $(CC) $(XLDFLAGS) -o $@ cube.o cube-icon.o drawing.o nestedvm.o \ malloc.o midend.o misc.o printing.o ps.o random.o version.o \ -lm dominosa.mips: dominosa.o dominosa-icon.o drawing.o nestedvm.o laydomino.o \ malloc.o midend.o misc.o printing.o ps.o random.o version.o $(CC) $(XLDFLAGS) -o $@ dominosa.o dominosa-icon.o drawing.o \ nestedvm.o laydomino.o malloc.o midend.o misc.o printing.o \ ps.o random.o version.o -lm fifteen.mips: drawing.o fifteen.o fifteen-icon.o nestedvm.o malloc.o \ midend.o misc.o printing.o ps.o random.o version.o $(CC) $(XLDFLAGS) -o $@ drawing.o fifteen.o fifteen-icon.o \ nestedvm.o malloc.o midend.o misc.o printing.o ps.o random.o \ version.o -lm filling.mips: drawing.o dsf.o filling.o filling-icon.o nestedvm.o malloc.o \ midend.o misc.o printing.o ps.o random.o version.o $(CC) $(XLDFLAGS) -o $@ drawing.o dsf.o filling.o filling-icon.o \ nestedvm.o malloc.o midend.o misc.o printing.o ps.o random.o \ version.o -lm flip.mips: drawing.o flip.o flip-icon.o nestedvm.o malloc.o midend.o misc.o \ printing.o ps.o random.o tree234.o version.o $(CC) $(XLDFLAGS) -o $@ drawing.o flip.o flip-icon.o nestedvm.o \ malloc.o midend.o misc.o printing.o ps.o random.o tree234.o \ version.o -lm flood.mips: drawing.o flood.o flood-icon.o nestedvm.o malloc.o midend.o \ misc.o printing.o ps.o random.o version.o $(CC) $(XLDFLAGS) -o $@ drawing.o flood.o flood-icon.o nestedvm.o \ malloc.o midend.o misc.o printing.o ps.o random.o version.o \ -lm galaxies.mips: drawing.o dsf.o galaxies.o galaxies-icon.o nestedvm.o \ malloc.o midend.o misc.o printing.o ps.o random.o version.o $(CC) $(XLDFLAGS) -o $@ drawing.o dsf.o galaxies.o galaxies-icon.o \ nestedvm.o malloc.o midend.o misc.o printing.o ps.o random.o \ version.o -lm guess.mips: drawing.o nestedvm.o guess.o guess-icon.o malloc.o midend.o \ misc.o printing.o ps.o random.o version.o $(CC) $(XLDFLAGS) -o $@ drawing.o nestedvm.o guess.o guess-icon.o \ malloc.o midend.o misc.o printing.o ps.o random.o version.o \ -lm inertia.mips: drawing.o nestedvm.o inertia.o inertia-icon.o malloc.o \ midend.o misc.o printing.o ps.o random.o version.o $(CC) $(XLDFLAGS) -o $@ drawing.o nestedvm.o inertia.o \ inertia-icon.o malloc.o midend.o misc.o printing.o ps.o \ random.o version.o -lm keen.mips: drawing.o dsf.o nestedvm.o keen.o keen-icon.o latin.o malloc.o \ maxflow.o midend.o misc.o printing.o ps.o random.o tree234.o \ version.o $(CC) $(XLDFLAGS) -o $@ drawing.o dsf.o nestedvm.o keen.o \ keen-icon.o latin.o malloc.o maxflow.o midend.o misc.o \ printing.o ps.o random.o tree234.o version.o -lm lightup.mips: combi.o drawing.o nestedvm.o lightup.o lightup-icon.o malloc.o \ midend.o misc.o printing.o ps.o random.o version.o $(CC) $(XLDFLAGS) -o $@ combi.o drawing.o nestedvm.o lightup.o \ lightup-icon.o malloc.o midend.o misc.o printing.o ps.o \ random.o version.o -lm loopy.mips: drawing.o dsf.o grid.o nestedvm.o loopgen.o loopy.o loopy-icon.o \ malloc.o midend.o misc.o penrose.o printing.o ps.o random.o \ tree234.o version.o $(CC) $(XLDFLAGS) -o $@ drawing.o dsf.o grid.o nestedvm.o loopgen.o \ loopy.o loopy-icon.o malloc.o midend.o misc.o penrose.o \ printing.o ps.o random.o tree234.o version.o -lm magnets.mips: drawing.o nestedvm.o laydomino.o magnets.o magnets-icon.o \ malloc.o midend.o misc.o printing.o ps.o random.o version.o $(CC) $(XLDFLAGS) -o $@ drawing.o nestedvm.o laydomino.o magnets.o \ magnets-icon.o malloc.o midend.o misc.o printing.o ps.o \ random.o version.o -lm map.mips: drawing.o dsf.o nestedvm.o malloc.o map.o map-icon.o midend.o \ misc.o printing.o ps.o random.o version.o $(CC) $(XLDFLAGS) -o $@ drawing.o dsf.o nestedvm.o malloc.o map.o \ map-icon.o midend.o misc.o printing.o ps.o random.o \ version.o -lm mines.mips: drawing.o nestedvm.o malloc.o midend.o mines.o mines-icon.o \ misc.o printing.o ps.o random.o tree234.o version.o $(CC) $(XLDFLAGS) -o $@ drawing.o nestedvm.o malloc.o midend.o \ mines.o mines-icon.o misc.o printing.o ps.o random.o \ tree234.o version.o -lm net.mips: drawing.o dsf.o findloop.o nestedvm.o malloc.o midend.o misc.o \ net.o net-icon.o printing.o ps.o random.o tree234.o \ version.o $(CC) $(XLDFLAGS) -o $@ drawing.o dsf.o findloop.o nestedvm.o \ malloc.o midend.o misc.o net.o net-icon.o printing.o ps.o \ random.o tree234.o version.o -lm netslide.mips: drawing.o nestedvm.o malloc.o midend.o misc.o netslide.o \ netslide-icon.o printing.o ps.o random.o tree234.o version.o $(CC) $(XLDFLAGS) -o $@ drawing.o nestedvm.o malloc.o midend.o \ misc.o netslide.o netslide-icon.o printing.o ps.o random.o \ tree234.o version.o -lm nullgame.mips: drawing.o nestedvm.o malloc.o midend.o misc.o no-icon.o \ nullgame.o printing.o ps.o random.o version.o $(CC) $(XLDFLAGS) -o $@ drawing.o nestedvm.o malloc.o midend.o \ misc.o no-icon.o nullgame.o printing.o ps.o random.o \ version.o -lm palisade.mips: divvy.o drawing.o dsf.o nestedvm.o malloc.o midend.o misc.o \ palisade.o palisade-icon.o printing.o ps.o random.o \ version.o $(CC) $(XLDFLAGS) -o $@ divvy.o drawing.o dsf.o nestedvm.o malloc.o \ midend.o misc.o palisade.o palisade-icon.o printing.o ps.o \ random.o version.o -lm pattern.mips: drawing.o nestedvm.o malloc.o midend.o misc.o pattern.o \ pattern-icon.o printing.o ps.o random.o version.o $(CC) $(XLDFLAGS) -o $@ drawing.o nestedvm.o malloc.o midend.o \ misc.o pattern.o pattern-icon.o printing.o ps.o random.o \ version.o -lm pearl.mips: drawing.o dsf.o grid.o nestedvm.o loopgen.o malloc.o midend.o \ misc.o pearl.o pearl-icon.o penrose.o printing.o ps.o \ random.o tdq.o tree234.o version.o $(CC) $(XLDFLAGS) -o $@ drawing.o dsf.o grid.o nestedvm.o loopgen.o \ malloc.o midend.o misc.o pearl.o pearl-icon.o penrose.o \ printing.o ps.o random.o tdq.o tree234.o version.o -lm pegs.mips: drawing.o nestedvm.o malloc.o midend.o misc.o pegs.o pegs-icon.o \ printing.o ps.o random.o tree234.o version.o $(CC) $(XLDFLAGS) -o $@ drawing.o nestedvm.o malloc.o midend.o \ misc.o pegs.o pegs-icon.o printing.o ps.o random.o tree234.o \ version.o -lm range.mips: drawing.o dsf.o nestedvm.o malloc.o midend.o misc.o printing.o \ ps.o random.o range.o range-icon.o version.o $(CC) $(XLDFLAGS) -o $@ drawing.o dsf.o nestedvm.o malloc.o midend.o \ misc.o printing.o ps.o random.o range.o range-icon.o \ version.o -lm rect.mips: drawing.o nestedvm.o malloc.o midend.o misc.o printing.o ps.o \ random.o rect.o rect-icon.o version.o $(CC) $(XLDFLAGS) -o $@ drawing.o nestedvm.o malloc.o midend.o \ misc.o printing.o ps.o random.o rect.o rect-icon.o version.o \ -lm samegame.mips: drawing.o nestedvm.o malloc.o midend.o misc.o printing.o ps.o \ random.o samegame.o samegame-icon.o version.o $(CC) $(XLDFLAGS) -o $@ drawing.o nestedvm.o malloc.o midend.o \ misc.o printing.o ps.o random.o samegame.o samegame-icon.o \ version.o -lm signpost.mips: drawing.o dsf.o nestedvm.o malloc.o midend.o misc.o \ printing.o ps.o random.o signpost.o signpost-icon.o \ version.o $(CC) $(XLDFLAGS) -o $@ drawing.o dsf.o nestedvm.o malloc.o midend.o \ misc.o printing.o ps.o random.o signpost.o signpost-icon.o \ version.o -lm singles.mips: drawing.o dsf.o nestedvm.o latin.o malloc.o maxflow.o midend.o \ misc.o printing.o ps.o random.o singles.o singles-icon.o \ tree234.o version.o $(CC) $(XLDFLAGS) -o $@ drawing.o dsf.o nestedvm.o latin.o malloc.o \ maxflow.o midend.o misc.o printing.o ps.o random.o singles.o \ singles-icon.o tree234.o version.o -lm sixteen.mips: drawing.o nestedvm.o malloc.o midend.o misc.o printing.o ps.o \ random.o sixteen.o sixteen-icon.o version.o $(CC) $(XLDFLAGS) -o $@ drawing.o nestedvm.o malloc.o midend.o \ misc.o printing.o ps.o random.o sixteen.o sixteen-icon.o \ version.o -lm slant.mips: drawing.o dsf.o findloop.o nestedvm.o malloc.o midend.o misc.o \ printing.o ps.o random.o slant.o slant-icon.o version.o $(CC) $(XLDFLAGS) -o $@ drawing.o dsf.o findloop.o nestedvm.o \ malloc.o midend.o misc.o printing.o ps.o random.o slant.o \ slant-icon.o version.o -lm solo.mips: divvy.o drawing.o dsf.o nestedvm.o malloc.o midend.o misc.o \ printing.o ps.o random.o solo.o solo-icon.o version.o $(CC) $(XLDFLAGS) -o $@ divvy.o drawing.o dsf.o nestedvm.o malloc.o \ midend.o misc.o printing.o ps.o random.o solo.o solo-icon.o \ version.o -lm tents.mips: drawing.o dsf.o nestedvm.o malloc.o maxflow.o midend.o misc.o \ printing.o ps.o random.o tents.o tents-icon.o version.o $(CC) $(XLDFLAGS) -o $@ drawing.o dsf.o nestedvm.o malloc.o \ maxflow.o midend.o misc.o printing.o ps.o random.o tents.o \ tents-icon.o version.o -lm towers.mips: drawing.o nestedvm.o latin.o malloc.o maxflow.o midend.o misc.o \ printing.o ps.o random.o towers.o towers-icon.o tree234.o \ version.o $(CC) $(XLDFLAGS) -o $@ drawing.o nestedvm.o latin.o malloc.o \ maxflow.o midend.o misc.o printing.o ps.o random.o towers.o \ towers-icon.o tree234.o version.o -lm tracks.mips: drawing.o dsf.o findloop.o nestedvm.o malloc.o midend.o misc.o \ printing.o ps.o random.o tracks.o tracks-icon.o version.o $(CC) $(XLDFLAGS) -o $@ drawing.o dsf.o findloop.o nestedvm.o \ malloc.o midend.o misc.o printing.o ps.o random.o tracks.o \ tracks-icon.o version.o -lm twiddle.mips: drawing.o nestedvm.o malloc.o midend.o misc.o printing.o ps.o \ random.o twiddle.o twiddle-icon.o version.o $(CC) $(XLDFLAGS) -o $@ drawing.o nestedvm.o malloc.o midend.o \ misc.o printing.o ps.o random.o twiddle.o twiddle-icon.o \ version.o -lm undead.mips: drawing.o nestedvm.o malloc.o midend.o misc.o printing.o ps.o \ random.o undead.o undead-icon.o version.o $(CC) $(XLDFLAGS) -o $@ drawing.o nestedvm.o malloc.o midend.o \ misc.o printing.o ps.o random.o undead.o undead-icon.o \ version.o -lm unequal.mips: drawing.o nestedvm.o latin.o malloc.o maxflow.o midend.o \ misc.o printing.o ps.o random.o tree234.o unequal.o \ unequal-icon.o version.o $(CC) $(XLDFLAGS) -o $@ drawing.o nestedvm.o latin.o malloc.o \ maxflow.o midend.o misc.o printing.o ps.o random.o tree234.o \ unequal.o unequal-icon.o version.o -lm unruly.mips: drawing.o nestedvm.o malloc.o midend.o misc.o printing.o ps.o \ random.o unruly.o unruly-icon.o version.o $(CC) $(XLDFLAGS) -o $@ drawing.o nestedvm.o malloc.o midend.o \ misc.o printing.o ps.o random.o unruly.o unruly-icon.o \ version.o -lm untangle.mips: drawing.o nestedvm.o malloc.o midend.o misc.o printing.o ps.o \ random.o tree234.o untangle.o untangle-icon.o version.o $(CC) $(XLDFLAGS) -o $@ drawing.o nestedvm.o malloc.o midend.o \ misc.o printing.o ps.o random.o tree234.o untangle.o \ untangle-icon.o version.o -lm blackbox.o: ./blackbox.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ blackbox-icon.o: icons/blackbox-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ blackbo3.o: ./blackbox.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ bridges.o: ./bridges.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ bridges-icon.o: icons/bridges-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ bridges3.o: ./bridges.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ combi.o: ./combi.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ cube.o: ./cube.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ cube-icon.o: icons/cube-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ cube3.o: ./cube.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ divvy.o: ./divvy.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ dominosa.o: ./dominosa.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ dominosa-icon.o: icons/dominosa-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ dominos3.o: ./dominosa.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ drawing.o: ./drawing.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ dsf.o: ./dsf.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ fifteen.o: ./fifteen.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ fifteen-icon.o: icons/fifteen-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ fifteen5.o: ./fifteen.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ fifteen2.o: ./fifteen.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ filling.o: ./filling.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ filling-icon.o: icons/filling-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ filling5.o: ./filling.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ filling2.o: ./filling.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ findloop.o: ./findloop.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ flip.o: ./flip.c ./puzzles.h ./tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ flip-icon.o: icons/flip-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ flip3.o: ./flip.c ./puzzles.h ./tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ flood.o: ./flood.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ flood-icon.o: icons/flood-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ flood3.o: ./flood.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ galaxies.o: ./galaxies.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ galaxies-icon.o: icons/galaxies-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ galaxie7.o: ./galaxies.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ galaxie4.o: ./galaxies.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_PICTURE_GENERATOR -c $< -o $@ galaxie2.o: ./galaxies.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ grid.o: ./grid.c ./puzzles.h ./tree234.h ./grid.h ./penrose.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ nestedvm.o: ./nestedvm.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ guess.o: ./guess.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ guess-icon.o: icons/guess-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ guess3.o: ./guess.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ inertia.o: ./inertia.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ inertia-icon.o: icons/inertia-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ inertia3.o: ./inertia.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ keen.o: ./keen.c ./puzzles.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ keen-icon.o: icons/keen-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ keen5.o: ./keen.c ./puzzles.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ keen2.o: ./keen.c ./puzzles.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ latin.o: ./latin.c ./puzzles.h ./tree234.h ./maxflow.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ latin8.o: ./latin.c ./puzzles.h ./tree234.h ./maxflow.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_LATIN_TEST -c $< -o $@ latin6.o: ./latin.c ./puzzles.h ./tree234.h ./maxflow.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ laydomino.o: ./laydomino.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ lightup.o: ./lightup.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ lightup-icon.o: icons/lightup-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ lightup5.o: ./lightup.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ lightup2.o: ./lightup.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ list.o: ./list.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ loopgen.o: ./loopgen.c ./puzzles.h ./tree234.h ./grid.h ./loopgen.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ loopy.o: ./loopy.c ./puzzles.h ./tree234.h ./grid.h ./loopgen.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ loopy-icon.o: icons/loopy-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ loopy5.o: ./loopy.c ./puzzles.h ./tree234.h ./grid.h ./loopgen.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ loopy2.o: ./loopy.c ./puzzles.h ./tree234.h ./grid.h ./loopgen.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ magnets.o: ./magnets.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ magnets-icon.o: icons/magnets-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ magnets5.o: ./magnets.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ magnets2.o: ./magnets.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ malloc.o: ./malloc.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ map.o: ./map.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ map-icon.o: icons/map-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ map5.o: ./map.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ map2.o: ./map.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ maxflow.o: ./maxflow.c ./maxflow.h ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ midend.o: ./midend.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ mines.o: ./mines.c ./tree234.h ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ mines-icon.o: icons/mines-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ mines5.o: ./mines.c ./tree234.h ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ mines2.o: ./mines.c ./tree234.h ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_OBFUSCATOR -c $< -o $@ misc.o: ./misc.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ net.o: ./net.c ./puzzles.h ./tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ net-icon.o: icons/net-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ net3.o: ./net.c ./puzzles.h ./tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ netslide.o: ./netslide.c ./puzzles.h ./tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ netslide-icon.o: icons/netslide-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ netslid3.o: ./netslide.c ./puzzles.h ./tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ no-icon.o: ./no-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ nullfe.o: ./nullfe.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ nullgame.o: ./nullgame.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ obfusc.o: ./obfusc.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ osx.o: ./osx.m ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ palisade.o: ./palisade.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ palisade-icon.o: icons/palisade-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ palisad3.o: ./palisade.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ pattern.o: ./pattern.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ pattern-icon.o: icons/pattern-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ pattern7.o: ./pattern.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ pattern4.o: ./pattern.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_PICTURE_GENERATOR -c $< -o $@ pattern2.o: ./pattern.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ pearl.o: ./pearl.c ./puzzles.h ./grid.h ./loopgen.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ pearl-icon.o: icons/pearl-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ pearl5.o: ./pearl.c ./puzzles.h ./grid.h ./loopgen.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ pearl2.o: ./pearl.c ./puzzles.h ./grid.h ./loopgen.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ pegs.o: ./pegs.c ./puzzles.h ./tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ pegs-icon.o: icons/pegs-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ pegs3.o: ./pegs.c ./puzzles.h ./tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ penrose.o: ./penrose.c ./puzzles.h ./penrose.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ printing.o: ./printing.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ ps.o: ./ps.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ random.o: ./random.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ range.o: ./range.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ range-icon.o: icons/range-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ range3.o: ./range.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ rect.o: ./rect.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ rect-icon.o: icons/rect-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ rect3.o: ./rect.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ samegame.o: ./samegame.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ samegame-icon.o: icons/samegame-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ samegam3.o: ./samegame.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ signpost.o: ./signpost.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ signpost-icon.o: icons/signpost-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ signpos5.o: ./signpost.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ signpos2.o: ./signpost.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ singles.o: ./singles.c ./puzzles.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ singles-icon.o: icons/singles-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ singles5.o: ./singles.c ./puzzles.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ singles3.o: ./singles.c ./puzzles.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ sixteen.o: ./sixteen.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ sixteen-icon.o: icons/sixteen-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ sixteen3.o: ./sixteen.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ slant.o: ./slant.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ slant-icon.o: icons/slant-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ slant5.o: ./slant.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ slant2.o: ./slant.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ solo.o: ./solo.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ solo-icon.o: icons/solo-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ solo5.o: ./solo.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ solo2.o: ./solo.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ tdq.o: ./tdq.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ tents.o: ./tents.c ./puzzles.h ./maxflow.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ tents-icon.o: icons/tents-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ tents5.o: ./tents.c ./puzzles.h ./maxflow.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ tents3.o: ./tents.c ./puzzles.h ./maxflow.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ towers.o: ./towers.c ./puzzles.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ towers-icon.o: icons/towers-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ towers5.o: ./towers.c ./puzzles.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ towers2.o: ./towers.c ./puzzles.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ tracks.o: ./tracks.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ tracks-icon.o: icons/tracks-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ tracks3.o: ./tracks.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ tree234.o: ./tree234.c ./tree234.h ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ twiddle.o: ./twiddle.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ twiddle-icon.o: icons/twiddle-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ twiddle3.o: ./twiddle.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ undead.o: ./undead.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ undead-icon.o: icons/undead-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ undead3.o: ./undead.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ unequal.o: ./unequal.c ./puzzles.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ unequal-icon.o: icons/unequal-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ unequal5.o: ./unequal.c ./puzzles.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ unequal2.o: ./unequal.c ./puzzles.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ unruly.o: ./unruly.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ unruly-icon.o: icons/unruly-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ unruly5.o: ./unruly.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ unruly2.o: ./unruly.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ untangle.o: ./untangle.c ./puzzles.h ./tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ untangle-icon.o: icons/untangle-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ untangl3.o: ./untangle.c ./puzzles.h ./tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ version.o: ./version.c ./version.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ windows.o: ./windows.c ./puzzles.h ./resource.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ windows1.o: ./windows.c ./puzzles.h ./resource.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ .PRECIOUS: %.class %.class: %.mips java -cp $(NESTEDVM)/build:$(NESTEDVM)/upstream/build/classgen/build \ org.ibex.nestedvm.Compiler -outformat class -d . \ PuzzleEngine $< mv PuzzleEngine.class $@ org: mkdir -p org/ibex/nestedvm/util cp $(NESTEDVM)/build/org/ibex/nestedvm/Registers.class org/ibex/nestedvm cp $(NESTEDVM)/build/org/ibex/nestedvm/UsermodeConstants.class org/ibex/nestedvm cp $(NESTEDVM)/build/org/ibex/nestedvm/Runtime*.class org/ibex/nestedvm cp $(NESTEDVM)/build/org/ibex/nestedvm/util/Platform*.class org/ibex/nestedvm/util cp $(NESTEDVM)/build/org/ibex/nestedvm/util/Seekable*.class org/ibex/nestedvm/util echo "Main-Class: PuzzleApplet" >applet.manifest PuzzleApplet.class: PuzzleApplet.java org javac -source 1.3 -target 1.3 PuzzleApplet.java %.jar: %.class PuzzleApplet.class org mv $< PuzzleEngine.class jar cfm $@ applet.manifest PuzzleEngine.class PuzzleApplet*.class org echo '' >$*.html mv PuzzleEngine.class $< clean: rm -rf *.o *.mips *.class *.html *.jar org applet.manifest puzzles-20170606.272beef/Makefile.in0000644000175000017500000045211213115375151015740 0ustar simonsimon# Makefile.in generated by automake 1.15 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2014 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@ # Makefile.am for puzzles under Unix with Autoconf/Automake. # # This file was created by `mkfiles.pl' from the `Recipe' file. # DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead. 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 = : noinst_PROGRAMS = blackbox$(EXEEXT) bridges$(EXEEXT) cube$(EXEEXT) \ dominosa$(EXEEXT) fifteen$(EXEEXT) fifteensolver$(EXEEXT) \ filling$(EXEEXT) fillingsolver$(EXEEXT) flip$(EXEEXT) \ flood$(EXEEXT) galaxies$(EXEEXT) galaxiespicture$(EXEEXT) \ galaxiessolver$(EXEEXT) guess$(EXEEXT) inertia$(EXEEXT) \ keen$(EXEEXT) keensolver$(EXEEXT) latincheck$(EXEEXT) \ lightup$(EXEEXT) lightupsolver$(EXEEXT) loopy$(EXEEXT) \ loopysolver$(EXEEXT) magnets$(EXEEXT) magnetssolver$(EXEEXT) \ map$(EXEEXT) mapsolver$(EXEEXT) mineobfusc$(EXEEXT) \ mines$(EXEEXT) net$(EXEEXT) netslide$(EXEEXT) \ nullgame$(EXEEXT) obfusc$(EXEEXT) palisade$(EXEEXT) \ pattern$(EXEEXT) patternpicture$(EXEEXT) \ patternsolver$(EXEEXT) pearl$(EXEEXT) pearlbench$(EXEEXT) \ pegs$(EXEEXT) range$(EXEEXT) rect$(EXEEXT) samegame$(EXEEXT) \ signpost$(EXEEXT) signpostsolver$(EXEEXT) singles$(EXEEXT) \ singlessolver$(EXEEXT) sixteen$(EXEEXT) slant$(EXEEXT) \ slantsolver$(EXEEXT) solo$(EXEEXT) solosolver$(EXEEXT) \ tents$(EXEEXT) tentssolver$(EXEEXT) towers$(EXEEXT) \ towerssolver$(EXEEXT) tracks$(EXEEXT) twiddle$(EXEEXT) \ undead$(EXEEXT) unequal$(EXEEXT) unequalsolver$(EXEEXT) \ unruly$(EXEEXT) unrulysolver$(EXEEXT) untangle$(EXEEXT) bin_PROGRAMS = $(am__EXEEXT_1) subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ $(am__configure_deps) $(am__DIST_COMMON) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) AR = ar ARFLAGS = cru AM_V_AR = $(am__v_AR_@AM_V@) am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) am__v_AR_0 = @echo " AR " $@; am__v_AR_1 = libfifteen2_a_AR = $(AR) $(ARFLAGS) libfifteen2_a_LIBADD = am__dirstamp = $(am__leading_dot)dirstamp am_libfifteen2_a_OBJECTS = ./libfifteen2_a-fifteen.$(OBJEXT) libfifteen2_a_OBJECTS = $(am_libfifteen2_a_OBJECTS) libfilling2_a_AR = $(AR) $(ARFLAGS) libfilling2_a_LIBADD = am_libfilling2_a_OBJECTS = ./libfilling2_a-filling.$(OBJEXT) libfilling2_a_OBJECTS = $(am_libfilling2_a_OBJECTS) libgalaxie2_a_AR = $(AR) $(ARFLAGS) libgalaxie2_a_LIBADD = am_libgalaxie2_a_OBJECTS = ./libgalaxie2_a-galaxies.$(OBJEXT) libgalaxie2_a_OBJECTS = $(am_libgalaxie2_a_OBJECTS) libgalaxie4_a_AR = $(AR) $(ARFLAGS) libgalaxie4_a_LIBADD = am_libgalaxie4_a_OBJECTS = ./libgalaxie4_a-galaxies.$(OBJEXT) libgalaxie4_a_OBJECTS = $(am_libgalaxie4_a_OBJECTS) libkeen2_a_AR = $(AR) $(ARFLAGS) libkeen2_a_LIBADD = am_libkeen2_a_OBJECTS = ./libkeen2_a-keen.$(OBJEXT) libkeen2_a_OBJECTS = $(am_libkeen2_a_OBJECTS) liblatin6_a_AR = $(AR) $(ARFLAGS) liblatin6_a_LIBADD = am_liblatin6_a_OBJECTS = ./liblatin6_a-latin.$(OBJEXT) liblatin6_a_OBJECTS = $(am_liblatin6_a_OBJECTS) liblatin8_a_AR = $(AR) $(ARFLAGS) liblatin8_a_LIBADD = am_liblatin8_a_OBJECTS = ./liblatin8_a-latin.$(OBJEXT) liblatin8_a_OBJECTS = $(am_liblatin8_a_OBJECTS) liblightup2_a_AR = $(AR) $(ARFLAGS) liblightup2_a_LIBADD = am_liblightup2_a_OBJECTS = ./liblightup2_a-lightup.$(OBJEXT) liblightup2_a_OBJECTS = $(am_liblightup2_a_OBJECTS) libloopy2_a_AR = $(AR) $(ARFLAGS) libloopy2_a_LIBADD = am_libloopy2_a_OBJECTS = ./libloopy2_a-loopy.$(OBJEXT) libloopy2_a_OBJECTS = $(am_libloopy2_a_OBJECTS) libmagnets2_a_AR = $(AR) $(ARFLAGS) libmagnets2_a_LIBADD = am_libmagnets2_a_OBJECTS = ./libmagnets2_a-magnets.$(OBJEXT) libmagnets2_a_OBJECTS = $(am_libmagnets2_a_OBJECTS) libmap2_a_AR = $(AR) $(ARFLAGS) libmap2_a_LIBADD = am_libmap2_a_OBJECTS = ./libmap2_a-map.$(OBJEXT) libmap2_a_OBJECTS = $(am_libmap2_a_OBJECTS) libmines2_a_AR = $(AR) $(ARFLAGS) libmines2_a_LIBADD = am_libmines2_a_OBJECTS = ./libmines2_a-mines.$(OBJEXT) libmines2_a_OBJECTS = $(am_libmines2_a_OBJECTS) libpattern2_a_AR = $(AR) $(ARFLAGS) libpattern2_a_LIBADD = am_libpattern2_a_OBJECTS = ./libpattern2_a-pattern.$(OBJEXT) libpattern2_a_OBJECTS = $(am_libpattern2_a_OBJECTS) libpattern4_a_AR = $(AR) $(ARFLAGS) libpattern4_a_LIBADD = am_libpattern4_a_OBJECTS = ./libpattern4_a-pattern.$(OBJEXT) libpattern4_a_OBJECTS = $(am_libpattern4_a_OBJECTS) libpearl2_a_AR = $(AR) $(ARFLAGS) libpearl2_a_LIBADD = am_libpearl2_a_OBJECTS = ./libpearl2_a-pearl.$(OBJEXT) libpearl2_a_OBJECTS = $(am_libpearl2_a_OBJECTS) libsignpos2_a_AR = $(AR) $(ARFLAGS) libsignpos2_a_LIBADD = am_libsignpos2_a_OBJECTS = ./libsignpos2_a-signpost.$(OBJEXT) libsignpos2_a_OBJECTS = $(am_libsignpos2_a_OBJECTS) libsingles3_a_AR = $(AR) $(ARFLAGS) libsingles3_a_LIBADD = am_libsingles3_a_OBJECTS = ./libsingles3_a-singles.$(OBJEXT) libsingles3_a_OBJECTS = $(am_libsingles3_a_OBJECTS) libslant2_a_AR = $(AR) $(ARFLAGS) libslant2_a_LIBADD = am_libslant2_a_OBJECTS = ./libslant2_a-slant.$(OBJEXT) libslant2_a_OBJECTS = $(am_libslant2_a_OBJECTS) libsolo2_a_AR = $(AR) $(ARFLAGS) libsolo2_a_LIBADD = am_libsolo2_a_OBJECTS = ./libsolo2_a-solo.$(OBJEXT) libsolo2_a_OBJECTS = $(am_libsolo2_a_OBJECTS) libtents3_a_AR = $(AR) $(ARFLAGS) libtents3_a_LIBADD = am_libtents3_a_OBJECTS = ./libtents3_a-tents.$(OBJEXT) libtents3_a_OBJECTS = $(am_libtents3_a_OBJECTS) libtowers2_a_AR = $(AR) $(ARFLAGS) libtowers2_a_LIBADD = am_libtowers2_a_OBJECTS = ./libtowers2_a-towers.$(OBJEXT) libtowers2_a_OBJECTS = $(am_libtowers2_a_OBJECTS) libunequal2_a_AR = $(AR) $(ARFLAGS) libunequal2_a_LIBADD = am_libunequal2_a_OBJECTS = ./libunequal2_a-unequal.$(OBJEXT) libunequal2_a_OBJECTS = $(am_libunequal2_a_OBJECTS) libunruly2_a_AR = $(AR) $(ARFLAGS) libunruly2_a_LIBADD = am_libunruly2_a_OBJECTS = ./libunruly2_a-unruly.$(OBJEXT) libunruly2_a_OBJECTS = $(am_libunruly2_a_OBJECTS) am__EXEEXT_1 = blackbox$(EXEEXT) bridges$(EXEEXT) cube$(EXEEXT) \ dominosa$(EXEEXT) fifteen$(EXEEXT) filling$(EXEEXT) \ flip$(EXEEXT) flood$(EXEEXT) galaxies$(EXEEXT) guess$(EXEEXT) \ inertia$(EXEEXT) keen$(EXEEXT) lightup$(EXEEXT) loopy$(EXEEXT) \ magnets$(EXEEXT) map$(EXEEXT) mines$(EXEEXT) net$(EXEEXT) \ netslide$(EXEEXT) palisade$(EXEEXT) pattern$(EXEEXT) \ pearl$(EXEEXT) pegs$(EXEEXT) range$(EXEEXT) rect$(EXEEXT) \ samegame$(EXEEXT) signpost$(EXEEXT) singles$(EXEEXT) \ sixteen$(EXEEXT) slant$(EXEEXT) solo$(EXEEXT) tents$(EXEEXT) \ towers$(EXEEXT) tracks$(EXEEXT) twiddle$(EXEEXT) \ undead$(EXEEXT) unequal$(EXEEXT) unruly$(EXEEXT) \ untangle$(EXEEXT) am__installdirs = "$(DESTDIR)$(bindir)" PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) am_blackbox_OBJECTS = ./blackbox.$(OBJEXT) ./drawing.$(OBJEXT) \ ./gtk.$(OBJEXT) ./malloc.$(OBJEXT) ./midend.$(OBJEXT) \ ./misc.$(OBJEXT) ./printing.$(OBJEXT) ./ps.$(OBJEXT) \ ./random.$(OBJEXT) ./version.$(OBJEXT) \ icons/blackbox-icon.$(OBJEXT) blackbox_OBJECTS = $(am_blackbox_OBJECTS) am__DEPENDENCIES_1 = blackbox_DEPENDENCIES = $(am__DEPENDENCIES_1) am_bridges_OBJECTS = ./bridges.$(OBJEXT) ./drawing.$(OBJEXT) \ ./dsf.$(OBJEXT) ./findloop.$(OBJEXT) ./gtk.$(OBJEXT) \ ./malloc.$(OBJEXT) ./midend.$(OBJEXT) ./misc.$(OBJEXT) \ ./printing.$(OBJEXT) ./ps.$(OBJEXT) ./random.$(OBJEXT) \ ./version.$(OBJEXT) icons/bridges-icon.$(OBJEXT) bridges_OBJECTS = $(am_bridges_OBJECTS) bridges_DEPENDENCIES = $(am__DEPENDENCIES_1) am_cube_OBJECTS = ./cube.$(OBJEXT) ./drawing.$(OBJEXT) ./gtk.$(OBJEXT) \ ./malloc.$(OBJEXT) ./midend.$(OBJEXT) ./misc.$(OBJEXT) \ ./printing.$(OBJEXT) ./ps.$(OBJEXT) ./random.$(OBJEXT) \ ./version.$(OBJEXT) icons/cube-icon.$(OBJEXT) cube_OBJECTS = $(am_cube_OBJECTS) cube_DEPENDENCIES = $(am__DEPENDENCIES_1) am_dominosa_OBJECTS = ./dominosa.$(OBJEXT) ./drawing.$(OBJEXT) \ ./gtk.$(OBJEXT) ./laydomino.$(OBJEXT) ./malloc.$(OBJEXT) \ ./midend.$(OBJEXT) ./misc.$(OBJEXT) ./printing.$(OBJEXT) \ ./ps.$(OBJEXT) ./random.$(OBJEXT) ./version.$(OBJEXT) \ icons/dominosa-icon.$(OBJEXT) dominosa_OBJECTS = $(am_dominosa_OBJECTS) dominosa_DEPENDENCIES = $(am__DEPENDENCIES_1) am_fifteen_OBJECTS = ./drawing.$(OBJEXT) ./fifteen.$(OBJEXT) \ ./gtk.$(OBJEXT) ./malloc.$(OBJEXT) ./midend.$(OBJEXT) \ ./misc.$(OBJEXT) ./printing.$(OBJEXT) ./ps.$(OBJEXT) \ ./random.$(OBJEXT) ./version.$(OBJEXT) \ icons/fifteen-icon.$(OBJEXT) fifteen_OBJECTS = $(am_fifteen_OBJECTS) fifteen_DEPENDENCIES = $(am__DEPENDENCIES_1) am_fifteensolver_OBJECTS = ./malloc.$(OBJEXT) ./misc.$(OBJEXT) \ ./nullfe.$(OBJEXT) ./random.$(OBJEXT) fifteensolver_OBJECTS = $(am_fifteensolver_OBJECTS) fifteensolver_DEPENDENCIES = libfifteen2_a-fifteen.$(OBJEXT) am_filling_OBJECTS = ./drawing.$(OBJEXT) ./dsf.$(OBJEXT) \ ./filling.$(OBJEXT) ./gtk.$(OBJEXT) ./malloc.$(OBJEXT) \ ./midend.$(OBJEXT) ./misc.$(OBJEXT) ./printing.$(OBJEXT) \ ./ps.$(OBJEXT) ./random.$(OBJEXT) ./version.$(OBJEXT) \ icons/filling-icon.$(OBJEXT) filling_OBJECTS = $(am_filling_OBJECTS) filling_DEPENDENCIES = $(am__DEPENDENCIES_1) am_fillingsolver_OBJECTS = ./dsf.$(OBJEXT) ./malloc.$(OBJEXT) \ ./misc.$(OBJEXT) ./nullfe.$(OBJEXT) ./random.$(OBJEXT) fillingsolver_OBJECTS = $(am_fillingsolver_OBJECTS) fillingsolver_DEPENDENCIES = libfilling2_a-filling.$(OBJEXT) am_flip_OBJECTS = ./drawing.$(OBJEXT) ./flip.$(OBJEXT) ./gtk.$(OBJEXT) \ ./malloc.$(OBJEXT) ./midend.$(OBJEXT) ./misc.$(OBJEXT) \ ./printing.$(OBJEXT) ./ps.$(OBJEXT) ./random.$(OBJEXT) \ ./tree234.$(OBJEXT) ./version.$(OBJEXT) \ icons/flip-icon.$(OBJEXT) flip_OBJECTS = $(am_flip_OBJECTS) flip_DEPENDENCIES = $(am__DEPENDENCIES_1) am_flood_OBJECTS = ./drawing.$(OBJEXT) ./flood.$(OBJEXT) \ ./gtk.$(OBJEXT) ./malloc.$(OBJEXT) ./midend.$(OBJEXT) \ ./misc.$(OBJEXT) ./printing.$(OBJEXT) ./ps.$(OBJEXT) \ ./random.$(OBJEXT) ./version.$(OBJEXT) \ icons/flood-icon.$(OBJEXT) flood_OBJECTS = $(am_flood_OBJECTS) flood_DEPENDENCIES = $(am__DEPENDENCIES_1) am_galaxies_OBJECTS = ./drawing.$(OBJEXT) ./dsf.$(OBJEXT) \ ./galaxies.$(OBJEXT) ./gtk.$(OBJEXT) ./malloc.$(OBJEXT) \ ./midend.$(OBJEXT) ./misc.$(OBJEXT) ./printing.$(OBJEXT) \ ./ps.$(OBJEXT) ./random.$(OBJEXT) ./version.$(OBJEXT) \ icons/galaxies-icon.$(OBJEXT) galaxies_OBJECTS = $(am_galaxies_OBJECTS) galaxies_DEPENDENCIES = $(am__DEPENDENCIES_1) am_galaxiespicture_OBJECTS = ./dsf.$(OBJEXT) ./malloc.$(OBJEXT) \ ./misc.$(OBJEXT) ./nullfe.$(OBJEXT) ./random.$(OBJEXT) galaxiespicture_OBJECTS = $(am_galaxiespicture_OBJECTS) galaxiespicture_DEPENDENCIES = libgalaxie4_a-galaxies.$(OBJEXT) am_galaxiessolver_OBJECTS = ./dsf.$(OBJEXT) ./malloc.$(OBJEXT) \ ./misc.$(OBJEXT) ./nullfe.$(OBJEXT) ./random.$(OBJEXT) galaxiessolver_OBJECTS = $(am_galaxiessolver_OBJECTS) galaxiessolver_DEPENDENCIES = libgalaxie2_a-galaxies.$(OBJEXT) am_guess_OBJECTS = ./drawing.$(OBJEXT) ./gtk.$(OBJEXT) \ ./guess.$(OBJEXT) ./malloc.$(OBJEXT) ./midend.$(OBJEXT) \ ./misc.$(OBJEXT) ./printing.$(OBJEXT) ./ps.$(OBJEXT) \ ./random.$(OBJEXT) ./version.$(OBJEXT) \ icons/guess-icon.$(OBJEXT) guess_OBJECTS = $(am_guess_OBJECTS) guess_DEPENDENCIES = $(am__DEPENDENCIES_1) am_inertia_OBJECTS = ./drawing.$(OBJEXT) ./gtk.$(OBJEXT) \ ./inertia.$(OBJEXT) ./malloc.$(OBJEXT) ./midend.$(OBJEXT) \ ./misc.$(OBJEXT) ./printing.$(OBJEXT) ./ps.$(OBJEXT) \ ./random.$(OBJEXT) ./version.$(OBJEXT) \ icons/inertia-icon.$(OBJEXT) inertia_OBJECTS = $(am_inertia_OBJECTS) inertia_DEPENDENCIES = $(am__DEPENDENCIES_1) am_keen_OBJECTS = ./drawing.$(OBJEXT) ./dsf.$(OBJEXT) ./gtk.$(OBJEXT) \ ./keen.$(OBJEXT) ./latin.$(OBJEXT) ./malloc.$(OBJEXT) \ ./maxflow.$(OBJEXT) ./midend.$(OBJEXT) ./misc.$(OBJEXT) \ ./printing.$(OBJEXT) ./ps.$(OBJEXT) ./random.$(OBJEXT) \ ./tree234.$(OBJEXT) ./version.$(OBJEXT) \ icons/keen-icon.$(OBJEXT) keen_OBJECTS = $(am_keen_OBJECTS) keen_DEPENDENCIES = $(am__DEPENDENCIES_1) am_keensolver_OBJECTS = ./dsf.$(OBJEXT) ./malloc.$(OBJEXT) \ ./maxflow.$(OBJEXT) ./misc.$(OBJEXT) ./nullfe.$(OBJEXT) \ ./random.$(OBJEXT) ./tree234.$(OBJEXT) keensolver_OBJECTS = $(am_keensolver_OBJECTS) keensolver_DEPENDENCIES = libkeen2_a-keen.$(OBJEXT) \ liblatin6_a-latin.$(OBJEXT) am_latincheck_OBJECTS = ./malloc.$(OBJEXT) ./maxflow.$(OBJEXT) \ ./misc.$(OBJEXT) ./nullfe.$(OBJEXT) ./random.$(OBJEXT) \ ./tree234.$(OBJEXT) latincheck_OBJECTS = $(am_latincheck_OBJECTS) latincheck_DEPENDENCIES = liblatin8_a-latin.$(OBJEXT) am_lightup_OBJECTS = ./combi.$(OBJEXT) ./drawing.$(OBJEXT) \ ./gtk.$(OBJEXT) ./lightup.$(OBJEXT) ./malloc.$(OBJEXT) \ ./midend.$(OBJEXT) ./misc.$(OBJEXT) ./printing.$(OBJEXT) \ ./ps.$(OBJEXT) ./random.$(OBJEXT) ./version.$(OBJEXT) \ icons/lightup-icon.$(OBJEXT) lightup_OBJECTS = $(am_lightup_OBJECTS) lightup_DEPENDENCIES = $(am__DEPENDENCIES_1) am_lightupsolver_OBJECTS = ./combi.$(OBJEXT) ./malloc.$(OBJEXT) \ ./misc.$(OBJEXT) ./nullfe.$(OBJEXT) ./random.$(OBJEXT) lightupsolver_OBJECTS = $(am_lightupsolver_OBJECTS) lightupsolver_DEPENDENCIES = liblightup2_a-lightup.$(OBJEXT) am_loopy_OBJECTS = ./drawing.$(OBJEXT) ./dsf.$(OBJEXT) \ ./grid.$(OBJEXT) ./gtk.$(OBJEXT) ./loopgen.$(OBJEXT) \ ./loopy.$(OBJEXT) ./malloc.$(OBJEXT) ./midend.$(OBJEXT) \ ./misc.$(OBJEXT) ./penrose.$(OBJEXT) ./printing.$(OBJEXT) \ ./ps.$(OBJEXT) ./random.$(OBJEXT) ./tree234.$(OBJEXT) \ ./version.$(OBJEXT) icons/loopy-icon.$(OBJEXT) loopy_OBJECTS = $(am_loopy_OBJECTS) loopy_DEPENDENCIES = $(am__DEPENDENCIES_1) am_loopysolver_OBJECTS = ./dsf.$(OBJEXT) ./grid.$(OBJEXT) \ ./loopgen.$(OBJEXT) ./malloc.$(OBJEXT) ./misc.$(OBJEXT) \ ./nullfe.$(OBJEXT) ./penrose.$(OBJEXT) ./random.$(OBJEXT) \ ./tree234.$(OBJEXT) loopysolver_OBJECTS = $(am_loopysolver_OBJECTS) loopysolver_DEPENDENCIES = libloopy2_a-loopy.$(OBJEXT) am_magnets_OBJECTS = ./drawing.$(OBJEXT) ./gtk.$(OBJEXT) \ ./laydomino.$(OBJEXT) ./magnets.$(OBJEXT) ./malloc.$(OBJEXT) \ ./midend.$(OBJEXT) ./misc.$(OBJEXT) ./printing.$(OBJEXT) \ ./ps.$(OBJEXT) ./random.$(OBJEXT) ./version.$(OBJEXT) \ icons/magnets-icon.$(OBJEXT) magnets_OBJECTS = $(am_magnets_OBJECTS) magnets_DEPENDENCIES = $(am__DEPENDENCIES_1) am_magnetssolver_OBJECTS = ./laydomino.$(OBJEXT) ./malloc.$(OBJEXT) \ ./misc.$(OBJEXT) ./nullfe.$(OBJEXT) ./random.$(OBJEXT) magnetssolver_OBJECTS = $(am_magnetssolver_OBJECTS) magnetssolver_DEPENDENCIES = libmagnets2_a-magnets.$(OBJEXT) am_map_OBJECTS = ./drawing.$(OBJEXT) ./dsf.$(OBJEXT) ./gtk.$(OBJEXT) \ ./malloc.$(OBJEXT) ./map.$(OBJEXT) ./midend.$(OBJEXT) \ ./misc.$(OBJEXT) ./printing.$(OBJEXT) ./ps.$(OBJEXT) \ ./random.$(OBJEXT) ./version.$(OBJEXT) \ icons/map-icon.$(OBJEXT) map_OBJECTS = $(am_map_OBJECTS) map_DEPENDENCIES = $(am__DEPENDENCIES_1) am_mapsolver_OBJECTS = ./dsf.$(OBJEXT) ./malloc.$(OBJEXT) \ ./misc.$(OBJEXT) ./nullfe.$(OBJEXT) ./random.$(OBJEXT) mapsolver_OBJECTS = $(am_mapsolver_OBJECTS) mapsolver_DEPENDENCIES = libmap2_a-map.$(OBJEXT) am_mineobfusc_OBJECTS = ./malloc.$(OBJEXT) ./misc.$(OBJEXT) \ ./nullfe.$(OBJEXT) ./random.$(OBJEXT) ./tree234.$(OBJEXT) mineobfusc_OBJECTS = $(am_mineobfusc_OBJECTS) mineobfusc_DEPENDENCIES = libmines2_a-mines.$(OBJEXT) am_mines_OBJECTS = ./drawing.$(OBJEXT) ./gtk.$(OBJEXT) \ ./malloc.$(OBJEXT) ./midend.$(OBJEXT) ./mines.$(OBJEXT) \ ./misc.$(OBJEXT) ./printing.$(OBJEXT) ./ps.$(OBJEXT) \ ./random.$(OBJEXT) ./tree234.$(OBJEXT) ./version.$(OBJEXT) \ icons/mines-icon.$(OBJEXT) mines_OBJECTS = $(am_mines_OBJECTS) mines_DEPENDENCIES = $(am__DEPENDENCIES_1) am_net_OBJECTS = ./drawing.$(OBJEXT) ./dsf.$(OBJEXT) \ ./findloop.$(OBJEXT) ./gtk.$(OBJEXT) ./malloc.$(OBJEXT) \ ./midend.$(OBJEXT) ./misc.$(OBJEXT) ./net.$(OBJEXT) \ ./printing.$(OBJEXT) ./ps.$(OBJEXT) ./random.$(OBJEXT) \ ./tree234.$(OBJEXT) ./version.$(OBJEXT) \ icons/net-icon.$(OBJEXT) net_OBJECTS = $(am_net_OBJECTS) net_DEPENDENCIES = $(am__DEPENDENCIES_1) am_netslide_OBJECTS = ./drawing.$(OBJEXT) ./gtk.$(OBJEXT) \ ./malloc.$(OBJEXT) ./midend.$(OBJEXT) ./misc.$(OBJEXT) \ ./netslide.$(OBJEXT) ./printing.$(OBJEXT) ./ps.$(OBJEXT) \ ./random.$(OBJEXT) ./tree234.$(OBJEXT) ./version.$(OBJEXT) \ icons/netslide-icon.$(OBJEXT) netslide_OBJECTS = $(am_netslide_OBJECTS) netslide_DEPENDENCIES = $(am__DEPENDENCIES_1) am_nullgame_OBJECTS = ./drawing.$(OBJEXT) ./gtk.$(OBJEXT) \ ./malloc.$(OBJEXT) ./midend.$(OBJEXT) ./misc.$(OBJEXT) \ ./no-icon.$(OBJEXT) ./nullgame.$(OBJEXT) ./printing.$(OBJEXT) \ ./ps.$(OBJEXT) ./random.$(OBJEXT) ./version.$(OBJEXT) nullgame_OBJECTS = $(am_nullgame_OBJECTS) nullgame_DEPENDENCIES = $(am__DEPENDENCIES_1) am_obfusc_OBJECTS = ./malloc.$(OBJEXT) ./misc.$(OBJEXT) \ ./nullfe.$(OBJEXT) ./obfusc.$(OBJEXT) ./random.$(OBJEXT) obfusc_OBJECTS = $(am_obfusc_OBJECTS) obfusc_DEPENDENCIES = am_palisade_OBJECTS = ./divvy.$(OBJEXT) ./drawing.$(OBJEXT) \ ./dsf.$(OBJEXT) ./gtk.$(OBJEXT) ./malloc.$(OBJEXT) \ ./midend.$(OBJEXT) ./misc.$(OBJEXT) ./palisade.$(OBJEXT) \ ./printing.$(OBJEXT) ./ps.$(OBJEXT) ./random.$(OBJEXT) \ ./version.$(OBJEXT) icons/palisade-icon.$(OBJEXT) palisade_OBJECTS = $(am_palisade_OBJECTS) palisade_DEPENDENCIES = $(am__DEPENDENCIES_1) am_pattern_OBJECTS = ./drawing.$(OBJEXT) ./gtk.$(OBJEXT) \ ./malloc.$(OBJEXT) ./midend.$(OBJEXT) ./misc.$(OBJEXT) \ ./pattern.$(OBJEXT) ./printing.$(OBJEXT) ./ps.$(OBJEXT) \ ./random.$(OBJEXT) ./version.$(OBJEXT) \ icons/pattern-icon.$(OBJEXT) pattern_OBJECTS = $(am_pattern_OBJECTS) pattern_DEPENDENCIES = $(am__DEPENDENCIES_1) am_patternpicture_OBJECTS = ./malloc.$(OBJEXT) ./misc.$(OBJEXT) \ ./nullfe.$(OBJEXT) ./random.$(OBJEXT) patternpicture_OBJECTS = $(am_patternpicture_OBJECTS) patternpicture_DEPENDENCIES = libpattern4_a-pattern.$(OBJEXT) am_patternsolver_OBJECTS = ./malloc.$(OBJEXT) ./misc.$(OBJEXT) \ ./nullfe.$(OBJEXT) ./random.$(OBJEXT) patternsolver_OBJECTS = $(am_patternsolver_OBJECTS) patternsolver_DEPENDENCIES = libpattern2_a-pattern.$(OBJEXT) am_pearl_OBJECTS = ./drawing.$(OBJEXT) ./dsf.$(OBJEXT) \ ./grid.$(OBJEXT) ./gtk.$(OBJEXT) ./loopgen.$(OBJEXT) \ ./malloc.$(OBJEXT) ./midend.$(OBJEXT) ./misc.$(OBJEXT) \ ./pearl.$(OBJEXT) ./penrose.$(OBJEXT) ./printing.$(OBJEXT) \ ./ps.$(OBJEXT) ./random.$(OBJEXT) ./tdq.$(OBJEXT) \ ./tree234.$(OBJEXT) ./version.$(OBJEXT) \ icons/pearl-icon.$(OBJEXT) pearl_OBJECTS = $(am_pearl_OBJECTS) pearl_DEPENDENCIES = $(am__DEPENDENCIES_1) am_pearlbench_OBJECTS = ./dsf.$(OBJEXT) ./grid.$(OBJEXT) \ ./loopgen.$(OBJEXT) ./malloc.$(OBJEXT) ./misc.$(OBJEXT) \ ./nullfe.$(OBJEXT) ./penrose.$(OBJEXT) ./random.$(OBJEXT) \ ./tdq.$(OBJEXT) ./tree234.$(OBJEXT) pearlbench_OBJECTS = $(am_pearlbench_OBJECTS) pearlbench_DEPENDENCIES = libpearl2_a-pearl.$(OBJEXT) am_pegs_OBJECTS = ./drawing.$(OBJEXT) ./gtk.$(OBJEXT) \ ./malloc.$(OBJEXT) ./midend.$(OBJEXT) ./misc.$(OBJEXT) \ ./pegs.$(OBJEXT) ./printing.$(OBJEXT) ./ps.$(OBJEXT) \ ./random.$(OBJEXT) ./tree234.$(OBJEXT) ./version.$(OBJEXT) \ icons/pegs-icon.$(OBJEXT) pegs_OBJECTS = $(am_pegs_OBJECTS) pegs_DEPENDENCIES = $(am__DEPENDENCIES_1) am_range_OBJECTS = ./drawing.$(OBJEXT) ./dsf.$(OBJEXT) ./gtk.$(OBJEXT) \ ./malloc.$(OBJEXT) ./midend.$(OBJEXT) ./misc.$(OBJEXT) \ ./printing.$(OBJEXT) ./ps.$(OBJEXT) ./random.$(OBJEXT) \ ./range.$(OBJEXT) ./version.$(OBJEXT) \ icons/range-icon.$(OBJEXT) range_OBJECTS = $(am_range_OBJECTS) range_DEPENDENCIES = $(am__DEPENDENCIES_1) am_rect_OBJECTS = ./drawing.$(OBJEXT) ./gtk.$(OBJEXT) \ ./malloc.$(OBJEXT) ./midend.$(OBJEXT) ./misc.$(OBJEXT) \ ./printing.$(OBJEXT) ./ps.$(OBJEXT) ./random.$(OBJEXT) \ ./rect.$(OBJEXT) ./version.$(OBJEXT) icons/rect-icon.$(OBJEXT) rect_OBJECTS = $(am_rect_OBJECTS) rect_DEPENDENCIES = $(am__DEPENDENCIES_1) am_samegame_OBJECTS = ./drawing.$(OBJEXT) ./gtk.$(OBJEXT) \ ./malloc.$(OBJEXT) ./midend.$(OBJEXT) ./misc.$(OBJEXT) \ ./printing.$(OBJEXT) ./ps.$(OBJEXT) ./random.$(OBJEXT) \ ./samegame.$(OBJEXT) ./version.$(OBJEXT) \ icons/samegame-icon.$(OBJEXT) samegame_OBJECTS = $(am_samegame_OBJECTS) samegame_DEPENDENCIES = $(am__DEPENDENCIES_1) am_signpost_OBJECTS = ./drawing.$(OBJEXT) ./dsf.$(OBJEXT) \ ./gtk.$(OBJEXT) ./malloc.$(OBJEXT) ./midend.$(OBJEXT) \ ./misc.$(OBJEXT) ./printing.$(OBJEXT) ./ps.$(OBJEXT) \ ./random.$(OBJEXT) ./signpost.$(OBJEXT) ./version.$(OBJEXT) \ icons/signpost-icon.$(OBJEXT) signpost_OBJECTS = $(am_signpost_OBJECTS) signpost_DEPENDENCIES = $(am__DEPENDENCIES_1) am_signpostsolver_OBJECTS = ./dsf.$(OBJEXT) ./malloc.$(OBJEXT) \ ./misc.$(OBJEXT) ./nullfe.$(OBJEXT) ./random.$(OBJEXT) signpostsolver_OBJECTS = $(am_signpostsolver_OBJECTS) signpostsolver_DEPENDENCIES = libsignpos2_a-signpost.$(OBJEXT) am_singles_OBJECTS = ./drawing.$(OBJEXT) ./dsf.$(OBJEXT) \ ./gtk.$(OBJEXT) ./latin.$(OBJEXT) ./malloc.$(OBJEXT) \ ./maxflow.$(OBJEXT) ./midend.$(OBJEXT) ./misc.$(OBJEXT) \ ./printing.$(OBJEXT) ./ps.$(OBJEXT) ./random.$(OBJEXT) \ ./singles.$(OBJEXT) ./tree234.$(OBJEXT) ./version.$(OBJEXT) \ icons/singles-icon.$(OBJEXT) singles_OBJECTS = $(am_singles_OBJECTS) singles_DEPENDENCIES = $(am__DEPENDENCIES_1) am_singlessolver_OBJECTS = ./dsf.$(OBJEXT) ./latin.$(OBJEXT) \ ./malloc.$(OBJEXT) ./maxflow.$(OBJEXT) ./misc.$(OBJEXT) \ ./nullfe.$(OBJEXT) ./random.$(OBJEXT) ./tree234.$(OBJEXT) singlessolver_OBJECTS = $(am_singlessolver_OBJECTS) singlessolver_DEPENDENCIES = libsingles3_a-singles.$(OBJEXT) am_sixteen_OBJECTS = ./drawing.$(OBJEXT) ./gtk.$(OBJEXT) \ ./malloc.$(OBJEXT) ./midend.$(OBJEXT) ./misc.$(OBJEXT) \ ./printing.$(OBJEXT) ./ps.$(OBJEXT) ./random.$(OBJEXT) \ ./sixteen.$(OBJEXT) ./version.$(OBJEXT) \ icons/sixteen-icon.$(OBJEXT) sixteen_OBJECTS = $(am_sixteen_OBJECTS) sixteen_DEPENDENCIES = $(am__DEPENDENCIES_1) am_slant_OBJECTS = ./drawing.$(OBJEXT) ./dsf.$(OBJEXT) \ ./findloop.$(OBJEXT) ./gtk.$(OBJEXT) ./malloc.$(OBJEXT) \ ./midend.$(OBJEXT) ./misc.$(OBJEXT) ./printing.$(OBJEXT) \ ./ps.$(OBJEXT) ./random.$(OBJEXT) ./slant.$(OBJEXT) \ ./version.$(OBJEXT) icons/slant-icon.$(OBJEXT) slant_OBJECTS = $(am_slant_OBJECTS) slant_DEPENDENCIES = $(am__DEPENDENCIES_1) am_slantsolver_OBJECTS = ./dsf.$(OBJEXT) ./findloop.$(OBJEXT) \ ./malloc.$(OBJEXT) ./misc.$(OBJEXT) ./nullfe.$(OBJEXT) \ ./random.$(OBJEXT) slantsolver_OBJECTS = $(am_slantsolver_OBJECTS) slantsolver_DEPENDENCIES = libslant2_a-slant.$(OBJEXT) am_solo_OBJECTS = ./divvy.$(OBJEXT) ./drawing.$(OBJEXT) \ ./dsf.$(OBJEXT) ./gtk.$(OBJEXT) ./malloc.$(OBJEXT) \ ./midend.$(OBJEXT) ./misc.$(OBJEXT) ./printing.$(OBJEXT) \ ./ps.$(OBJEXT) ./random.$(OBJEXT) ./solo.$(OBJEXT) \ ./version.$(OBJEXT) icons/solo-icon.$(OBJEXT) solo_OBJECTS = $(am_solo_OBJECTS) solo_DEPENDENCIES = $(am__DEPENDENCIES_1) am_solosolver_OBJECTS = ./divvy.$(OBJEXT) ./dsf.$(OBJEXT) \ ./malloc.$(OBJEXT) ./misc.$(OBJEXT) ./nullfe.$(OBJEXT) \ ./random.$(OBJEXT) solosolver_OBJECTS = $(am_solosolver_OBJECTS) solosolver_DEPENDENCIES = libsolo2_a-solo.$(OBJEXT) am_tents_OBJECTS = ./drawing.$(OBJEXT) ./dsf.$(OBJEXT) ./gtk.$(OBJEXT) \ ./malloc.$(OBJEXT) ./maxflow.$(OBJEXT) ./midend.$(OBJEXT) \ ./misc.$(OBJEXT) ./printing.$(OBJEXT) ./ps.$(OBJEXT) \ ./random.$(OBJEXT) ./tents.$(OBJEXT) ./version.$(OBJEXT) \ icons/tents-icon.$(OBJEXT) tents_OBJECTS = $(am_tents_OBJECTS) tents_DEPENDENCIES = $(am__DEPENDENCIES_1) am_tentssolver_OBJECTS = ./dsf.$(OBJEXT) ./malloc.$(OBJEXT) \ ./maxflow.$(OBJEXT) ./misc.$(OBJEXT) ./nullfe.$(OBJEXT) \ ./random.$(OBJEXT) tentssolver_OBJECTS = $(am_tentssolver_OBJECTS) tentssolver_DEPENDENCIES = libtents3_a-tents.$(OBJEXT) am_towers_OBJECTS = ./drawing.$(OBJEXT) ./gtk.$(OBJEXT) \ ./latin.$(OBJEXT) ./malloc.$(OBJEXT) ./maxflow.$(OBJEXT) \ ./midend.$(OBJEXT) ./misc.$(OBJEXT) ./printing.$(OBJEXT) \ ./ps.$(OBJEXT) ./random.$(OBJEXT) ./towers.$(OBJEXT) \ ./tree234.$(OBJEXT) ./version.$(OBJEXT) \ icons/towers-icon.$(OBJEXT) towers_OBJECTS = $(am_towers_OBJECTS) towers_DEPENDENCIES = $(am__DEPENDENCIES_1) am_towerssolver_OBJECTS = ./malloc.$(OBJEXT) ./maxflow.$(OBJEXT) \ ./misc.$(OBJEXT) ./nullfe.$(OBJEXT) ./random.$(OBJEXT) \ ./tree234.$(OBJEXT) towerssolver_OBJECTS = $(am_towerssolver_OBJECTS) towerssolver_DEPENDENCIES = liblatin6_a-latin.$(OBJEXT) \ libtowers2_a-towers.$(OBJEXT) am_tracks_OBJECTS = ./drawing.$(OBJEXT) ./dsf.$(OBJEXT) \ ./findloop.$(OBJEXT) ./gtk.$(OBJEXT) ./malloc.$(OBJEXT) \ ./midend.$(OBJEXT) ./misc.$(OBJEXT) ./printing.$(OBJEXT) \ ./ps.$(OBJEXT) ./random.$(OBJEXT) ./tracks.$(OBJEXT) \ ./version.$(OBJEXT) icons/tracks-icon.$(OBJEXT) tracks_OBJECTS = $(am_tracks_OBJECTS) tracks_DEPENDENCIES = $(am__DEPENDENCIES_1) am_twiddle_OBJECTS = ./drawing.$(OBJEXT) ./gtk.$(OBJEXT) \ ./malloc.$(OBJEXT) ./midend.$(OBJEXT) ./misc.$(OBJEXT) \ ./printing.$(OBJEXT) ./ps.$(OBJEXT) ./random.$(OBJEXT) \ ./twiddle.$(OBJEXT) ./version.$(OBJEXT) \ icons/twiddle-icon.$(OBJEXT) twiddle_OBJECTS = $(am_twiddle_OBJECTS) twiddle_DEPENDENCIES = $(am__DEPENDENCIES_1) am_undead_OBJECTS = ./drawing.$(OBJEXT) ./gtk.$(OBJEXT) \ ./malloc.$(OBJEXT) ./midend.$(OBJEXT) ./misc.$(OBJEXT) \ ./printing.$(OBJEXT) ./ps.$(OBJEXT) ./random.$(OBJEXT) \ ./undead.$(OBJEXT) ./version.$(OBJEXT) \ icons/undead-icon.$(OBJEXT) undead_OBJECTS = $(am_undead_OBJECTS) undead_DEPENDENCIES = $(am__DEPENDENCIES_1) am_unequal_OBJECTS = ./drawing.$(OBJEXT) ./gtk.$(OBJEXT) \ ./latin.$(OBJEXT) ./malloc.$(OBJEXT) ./maxflow.$(OBJEXT) \ ./midend.$(OBJEXT) ./misc.$(OBJEXT) ./printing.$(OBJEXT) \ ./ps.$(OBJEXT) ./random.$(OBJEXT) ./tree234.$(OBJEXT) \ ./unequal.$(OBJEXT) ./version.$(OBJEXT) \ icons/unequal-icon.$(OBJEXT) unequal_OBJECTS = $(am_unequal_OBJECTS) unequal_DEPENDENCIES = $(am__DEPENDENCIES_1) am_unequalsolver_OBJECTS = ./malloc.$(OBJEXT) ./maxflow.$(OBJEXT) \ ./misc.$(OBJEXT) ./nullfe.$(OBJEXT) ./random.$(OBJEXT) \ ./tree234.$(OBJEXT) unequalsolver_OBJECTS = $(am_unequalsolver_OBJECTS) unequalsolver_DEPENDENCIES = liblatin6_a-latin.$(OBJEXT) \ libunequal2_a-unequal.$(OBJEXT) am_unruly_OBJECTS = ./drawing.$(OBJEXT) ./gtk.$(OBJEXT) \ ./malloc.$(OBJEXT) ./midend.$(OBJEXT) ./misc.$(OBJEXT) \ ./printing.$(OBJEXT) ./ps.$(OBJEXT) ./random.$(OBJEXT) \ ./unruly.$(OBJEXT) ./version.$(OBJEXT) \ icons/unruly-icon.$(OBJEXT) unruly_OBJECTS = $(am_unruly_OBJECTS) unruly_DEPENDENCIES = $(am__DEPENDENCIES_1) am_unrulysolver_OBJECTS = ./malloc.$(OBJEXT) ./misc.$(OBJEXT) \ ./nullfe.$(OBJEXT) ./random.$(OBJEXT) unrulysolver_OBJECTS = $(am_unrulysolver_OBJECTS) unrulysolver_DEPENDENCIES = libunruly2_a-unruly.$(OBJEXT) am_untangle_OBJECTS = ./drawing.$(OBJEXT) ./gtk.$(OBJEXT) \ ./malloc.$(OBJEXT) ./midend.$(OBJEXT) ./misc.$(OBJEXT) \ ./printing.$(OBJEXT) ./ps.$(OBJEXT) ./random.$(OBJEXT) \ ./tree234.$(OBJEXT) ./untangle.$(OBJEXT) ./version.$(OBJEXT) \ icons/untangle-icon.$(OBJEXT) untangle_OBJECTS = $(am_untangle_OBJECTS) untangle_DEPENDENCIES = $(am__DEPENDENCIES_1) 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@ depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f 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 = 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 = $(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 = SOURCES = $(libfifteen2_a_SOURCES) $(libfilling2_a_SOURCES) \ $(libgalaxie2_a_SOURCES) $(libgalaxie4_a_SOURCES) \ $(libkeen2_a_SOURCES) $(liblatin6_a_SOURCES) \ $(liblatin8_a_SOURCES) $(liblightup2_a_SOURCES) \ $(libloopy2_a_SOURCES) $(libmagnets2_a_SOURCES) \ $(libmap2_a_SOURCES) $(libmines2_a_SOURCES) \ $(libpattern2_a_SOURCES) $(libpattern4_a_SOURCES) \ $(libpearl2_a_SOURCES) $(libsignpos2_a_SOURCES) \ $(libsingles3_a_SOURCES) $(libslant2_a_SOURCES) \ $(libsolo2_a_SOURCES) $(libtents3_a_SOURCES) \ $(libtowers2_a_SOURCES) $(libunequal2_a_SOURCES) \ $(libunruly2_a_SOURCES) $(blackbox_SOURCES) $(bridges_SOURCES) \ $(cube_SOURCES) $(dominosa_SOURCES) $(fifteen_SOURCES) \ $(fifteensolver_SOURCES) $(filling_SOURCES) \ $(fillingsolver_SOURCES) $(flip_SOURCES) $(flood_SOURCES) \ $(galaxies_SOURCES) $(galaxiespicture_SOURCES) \ $(galaxiessolver_SOURCES) $(guess_SOURCES) $(inertia_SOURCES) \ $(keen_SOURCES) $(keensolver_SOURCES) $(latincheck_SOURCES) \ $(lightup_SOURCES) $(lightupsolver_SOURCES) $(loopy_SOURCES) \ $(loopysolver_SOURCES) $(magnets_SOURCES) \ $(magnetssolver_SOURCES) $(map_SOURCES) $(mapsolver_SOURCES) \ $(mineobfusc_SOURCES) $(mines_SOURCES) $(net_SOURCES) \ $(netslide_SOURCES) $(nullgame_SOURCES) $(obfusc_SOURCES) \ $(palisade_SOURCES) $(pattern_SOURCES) \ $(patternpicture_SOURCES) $(patternsolver_SOURCES) \ $(pearl_SOURCES) $(pearlbench_SOURCES) $(pegs_SOURCES) \ $(range_SOURCES) $(rect_SOURCES) $(samegame_SOURCES) \ $(signpost_SOURCES) $(signpostsolver_SOURCES) \ $(singles_SOURCES) $(singlessolver_SOURCES) $(sixteen_SOURCES) \ $(slant_SOURCES) $(slantsolver_SOURCES) $(solo_SOURCES) \ $(solosolver_SOURCES) $(tents_SOURCES) $(tentssolver_SOURCES) \ $(towers_SOURCES) $(towerssolver_SOURCES) $(tracks_SOURCES) \ $(twiddle_SOURCES) $(undead_SOURCES) $(unequal_SOURCES) \ $(unequalsolver_SOURCES) $(unruly_SOURCES) \ $(unrulysolver_SOURCES) $(untangle_SOURCES) DIST_SOURCES = $(libfifteen2_a_SOURCES) $(libfilling2_a_SOURCES) \ $(libgalaxie2_a_SOURCES) $(libgalaxie4_a_SOURCES) \ $(libkeen2_a_SOURCES) $(liblatin6_a_SOURCES) \ $(liblatin8_a_SOURCES) $(liblightup2_a_SOURCES) \ $(libloopy2_a_SOURCES) $(libmagnets2_a_SOURCES) \ $(libmap2_a_SOURCES) $(libmines2_a_SOURCES) \ $(libpattern2_a_SOURCES) $(libpattern4_a_SOURCES) \ $(libpearl2_a_SOURCES) $(libsignpos2_a_SOURCES) \ $(libsingles3_a_SOURCES) $(libslant2_a_SOURCES) \ $(libsolo2_a_SOURCES) $(libtents3_a_SOURCES) \ $(libtowers2_a_SOURCES) $(libunequal2_a_SOURCES) \ $(libunruly2_a_SOURCES) $(blackbox_SOURCES) $(bridges_SOURCES) \ $(cube_SOURCES) $(dominosa_SOURCES) $(fifteen_SOURCES) \ $(fifteensolver_SOURCES) $(filling_SOURCES) \ $(fillingsolver_SOURCES) $(flip_SOURCES) $(flood_SOURCES) \ $(galaxies_SOURCES) $(galaxiespicture_SOURCES) \ $(galaxiessolver_SOURCES) $(guess_SOURCES) $(inertia_SOURCES) \ $(keen_SOURCES) $(keensolver_SOURCES) $(latincheck_SOURCES) \ $(lightup_SOURCES) $(lightupsolver_SOURCES) $(loopy_SOURCES) \ $(loopysolver_SOURCES) $(magnets_SOURCES) \ $(magnetssolver_SOURCES) $(map_SOURCES) $(mapsolver_SOURCES) \ $(mineobfusc_SOURCES) $(mines_SOURCES) $(net_SOURCES) \ $(netslide_SOURCES) $(nullgame_SOURCES) $(obfusc_SOURCES) \ $(palisade_SOURCES) $(pattern_SOURCES) \ $(patternpicture_SOURCES) $(patternsolver_SOURCES) \ $(pearl_SOURCES) $(pearlbench_SOURCES) $(pegs_SOURCES) \ $(range_SOURCES) $(rect_SOURCES) $(samegame_SOURCES) \ $(signpost_SOURCES) $(signpostsolver_SOURCES) \ $(singles_SOURCES) $(singlessolver_SOURCES) $(sixteen_SOURCES) \ $(slant_SOURCES) $(slantsolver_SOURCES) $(solo_SOURCES) \ $(solosolver_SOURCES) $(tents_SOURCES) $(tentssolver_SOURCES) \ $(towers_SOURCES) $(towerssolver_SOURCES) $(tracks_SOURCES) \ $(twiddle_SOURCES) $(undead_SOURCES) $(unequal_SOURCES) \ $(unequalsolver_SOURCES) $(unruly_SOURCES) \ $(unrulysolver_SOURCES) $(untangle_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) # 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 AM_RECURSIVE_TARGETS = cscope am__DIST_COMMON = $(srcdir)/Makefile.in README compile depcomp \ install-sh missing DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ if test -d "$(distdir)"; then \ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -rf "$(distdir)" \ || { sleep 5 && rm -rf "$(distdir)"; }; \ else :; fi am__post_remove_distdir = $(am__remove_distdir) DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best DIST_TARGETS = dist-gzip distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EXEEXT = @EXEEXT@ GTK_CFLAGS = @GTK_CFLAGS@ GTK_LIBS = @GTK_LIBS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ GAMES = blackbox bridges cube dominosa fifteen filling flip flood \ galaxies guess inertia keen lightup loopy magnets map mines \ net netslide palisade pattern pearl pegs range rect samegame \ signpost singles sixteen slant solo tents towers tracks \ twiddle undead unequal unruly untangle AUTOMAKE_OPTIONS = subdir-objects allsources = ./blackbox.c ./bridges.c ./combi.c ./cube.c ./divvy.c \ ./dominosa.c ./drawing.c ./dsf.c ./fifteen.c ./filling.c \ ./findloop.c ./flip.c ./flood.c ./galaxies.c ./grid.c \ ./grid.h ./gtk.c ./guess.c ./inertia.c ./keen.c ./latin.c \ ./latin.h ./laydomino.c ./lightup.c ./list.c ./loopgen.c \ ./loopgen.h ./loopy.c ./magnets.c ./malloc.c ./map.c \ ./maxflow.c ./maxflow.h ./midend.c ./mines.c ./misc.c \ ./net.c ./netslide.c ./no-icon.c ./nullfe.c ./nullgame.c \ ./obfusc.c ./osx.m ./palisade.c ./pattern.c ./pearl.c \ ./pegs.c ./penrose.c ./penrose.h ./printing.c ./ps.c \ ./puzzles.h ./random.c ./range.c ./rect.c ./resource.h \ ./samegame.c ./signpost.c ./singles.c ./sixteen.c ./slant.c \ ./solo.c ./tdq.c ./tents.c ./towers.c ./tracks.c ./tree234.c \ ./tree234.h ./twiddle.c ./undead.c ./unequal.c ./unruly.c \ ./untangle.c ./version.c ./version.h ./windows.c \ icons/blackbox-icon.c icons/bridges-icon.c icons/cube-icon.c \ icons/dominosa-icon.c icons/fifteen-icon.c \ icons/filling-icon.c icons/flip-icon.c icons/flood-icon.c \ icons/galaxies-icon.c icons/guess-icon.c \ icons/inertia-icon.c icons/keen-icon.c icons/lightup-icon.c \ icons/loopy-icon.c icons/magnets-icon.c icons/map-icon.c \ icons/mines-icon.c icons/net-icon.c icons/netslide-icon.c \ icons/palisade-icon.c icons/pattern-icon.c \ icons/pearl-icon.c icons/pegs-icon.c icons/range-icon.c \ icons/rect-icon.c icons/samegame-icon.c \ icons/signpost-icon.c icons/singles-icon.c \ icons/sixteen-icon.c icons/slant-icon.c icons/solo-icon.c \ icons/tents-icon.c icons/towers-icon.c icons/tracks-icon.c \ icons/twiddle-icon.c icons/undead-icon.c \ icons/unequal-icon.c icons/unruly-icon.c \ icons/untangle-icon.c AM_CPPFLAGS = -I$(srcdir)/./ -I$(srcdir)/icons/ AM_CFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) blackbox_SOURCES = ./blackbox.c ./drawing.c ./gtk.c ./malloc.c ./midend.c \ ./misc.c ./printing.c ./ps.c ./puzzles.h ./random.c \ ./version.c ./version.h icons/blackbox-icon.c blackbox_LDADD = $(GTK_LIBS) -lm bridges_SOURCES = ./bridges.c ./drawing.c ./dsf.c ./findloop.c ./gtk.c \ ./malloc.c ./midend.c ./misc.c ./printing.c ./ps.c \ ./puzzles.h ./random.c ./version.c ./version.h \ icons/bridges-icon.c bridges_LDADD = $(GTK_LIBS) -lm cube_SOURCES = ./cube.c ./drawing.c ./gtk.c ./malloc.c ./midend.c ./misc.c \ ./printing.c ./ps.c ./puzzles.h ./random.c ./version.c \ ./version.h icons/cube-icon.c cube_LDADD = $(GTK_LIBS) -lm dominosa_SOURCES = ./dominosa.c ./drawing.c ./gtk.c ./laydomino.c ./malloc.c \ ./midend.c ./misc.c ./printing.c ./ps.c ./puzzles.h \ ./random.c ./version.c ./version.h icons/dominosa-icon.c dominosa_LDADD = $(GTK_LIBS) -lm fifteen_SOURCES = ./drawing.c ./fifteen.c ./gtk.c ./malloc.c ./midend.c \ ./misc.c ./printing.c ./ps.c ./puzzles.h ./random.c \ ./version.c ./version.h icons/fifteen-icon.c fifteen_LDADD = $(GTK_LIBS) -lm fifteensolver_SOURCES = ./malloc.c ./misc.c ./nullfe.c ./puzzles.h \ ./random.c fifteensolver_LDADD = libfifteen2_a-fifteen.$(OBJEXT) -lm filling_SOURCES = ./drawing.c ./dsf.c ./filling.c ./gtk.c ./malloc.c \ ./midend.c ./misc.c ./printing.c ./ps.c ./puzzles.h \ ./random.c ./version.c ./version.h icons/filling-icon.c filling_LDADD = $(GTK_LIBS) -lm fillingsolver_SOURCES = ./dsf.c ./malloc.c ./misc.c ./nullfe.c ./puzzles.h \ ./random.c fillingsolver_LDADD = libfilling2_a-filling.$(OBJEXT) -lm flip_SOURCES = ./drawing.c ./flip.c ./gtk.c ./malloc.c ./midend.c ./misc.c \ ./printing.c ./ps.c ./puzzles.h ./random.c ./tree234.c \ ./tree234.h ./version.c ./version.h icons/flip-icon.c flip_LDADD = $(GTK_LIBS) -lm flood_SOURCES = ./drawing.c ./flood.c ./gtk.c ./malloc.c ./midend.c ./misc.c \ ./printing.c ./ps.c ./puzzles.h ./random.c ./version.c \ ./version.h icons/flood-icon.c flood_LDADD = $(GTK_LIBS) -lm galaxies_SOURCES = ./drawing.c ./dsf.c ./galaxies.c ./gtk.c ./malloc.c \ ./midend.c ./misc.c ./printing.c ./ps.c ./puzzles.h \ ./random.c ./version.c ./version.h icons/galaxies-icon.c galaxies_LDADD = $(GTK_LIBS) -lm galaxiespicture_SOURCES = ./dsf.c ./malloc.c ./misc.c ./nullfe.c ./puzzles.h \ ./random.c galaxiespicture_LDADD = libgalaxie4_a-galaxies.$(OBJEXT) -lm galaxiessolver_SOURCES = ./dsf.c ./malloc.c ./misc.c ./nullfe.c ./puzzles.h \ ./random.c galaxiessolver_LDADD = libgalaxie2_a-galaxies.$(OBJEXT) -lm guess_SOURCES = ./drawing.c ./gtk.c ./guess.c ./malloc.c ./midend.c ./misc.c \ ./printing.c ./ps.c ./puzzles.h ./random.c ./version.c \ ./version.h icons/guess-icon.c guess_LDADD = $(GTK_LIBS) -lm inertia_SOURCES = ./drawing.c ./gtk.c ./inertia.c ./malloc.c ./midend.c \ ./misc.c ./printing.c ./ps.c ./puzzles.h ./random.c \ ./version.c ./version.h icons/inertia-icon.c inertia_LDADD = $(GTK_LIBS) -lm keen_SOURCES = ./drawing.c ./dsf.c ./gtk.c ./keen.c ./latin.c ./latin.h \ ./malloc.c ./maxflow.c ./maxflow.h ./midend.c ./misc.c \ ./printing.c ./ps.c ./puzzles.h ./random.c ./tree234.c \ ./tree234.h ./version.c ./version.h icons/keen-icon.c keen_LDADD = $(GTK_LIBS) -lm keensolver_SOURCES = ./dsf.c ./malloc.c ./maxflow.c ./maxflow.h ./misc.c \ ./nullfe.c ./puzzles.h ./random.c ./tree234.c ./tree234.h keensolver_LDADD = libkeen2_a-keen.$(OBJEXT) liblatin6_a-latin.$(OBJEXT) -lm latincheck_SOURCES = ./malloc.c ./maxflow.c ./maxflow.h ./misc.c ./nullfe.c \ ./puzzles.h ./random.c ./tree234.c ./tree234.h latincheck_LDADD = liblatin8_a-latin.$(OBJEXT) -lm lightup_SOURCES = ./combi.c ./drawing.c ./gtk.c ./lightup.c ./malloc.c \ ./midend.c ./misc.c ./printing.c ./ps.c ./puzzles.h \ ./random.c ./version.c ./version.h icons/lightup-icon.c lightup_LDADD = $(GTK_LIBS) -lm lightupsolver_SOURCES = ./combi.c ./malloc.c ./misc.c ./nullfe.c ./puzzles.h \ ./random.c lightupsolver_LDADD = liblightup2_a-lightup.$(OBJEXT) -lm loopy_SOURCES = ./drawing.c ./dsf.c ./grid.c ./grid.h ./gtk.c ./loopgen.c \ ./loopgen.h ./loopy.c ./malloc.c ./midend.c ./misc.c \ ./penrose.c ./penrose.h ./printing.c ./ps.c ./puzzles.h \ ./random.c ./tree234.c ./tree234.h ./version.c ./version.h \ icons/loopy-icon.c loopy_LDADD = $(GTK_LIBS) -lm loopysolver_SOURCES = ./dsf.c ./grid.c ./grid.h ./loopgen.c ./loopgen.h \ ./malloc.c ./misc.c ./nullfe.c ./penrose.c ./penrose.h \ ./puzzles.h ./random.c ./tree234.c ./tree234.h loopysolver_LDADD = libloopy2_a-loopy.$(OBJEXT) -lm magnets_SOURCES = ./drawing.c ./gtk.c ./laydomino.c ./magnets.c ./malloc.c \ ./midend.c ./misc.c ./printing.c ./ps.c ./puzzles.h \ ./random.c ./version.c ./version.h icons/magnets-icon.c magnets_LDADD = $(GTK_LIBS) -lm magnetssolver_SOURCES = ./laydomino.c ./malloc.c ./misc.c ./nullfe.c \ ./puzzles.h ./random.c magnetssolver_LDADD = libmagnets2_a-magnets.$(OBJEXT) -lm map_SOURCES = ./drawing.c ./dsf.c ./gtk.c ./malloc.c ./map.c ./midend.c \ ./misc.c ./printing.c ./ps.c ./puzzles.h ./random.c \ ./version.c ./version.h icons/map-icon.c map_LDADD = $(GTK_LIBS) -lm mapsolver_SOURCES = ./dsf.c ./malloc.c ./misc.c ./nullfe.c ./puzzles.h \ ./random.c mapsolver_LDADD = libmap2_a-map.$(OBJEXT) -lm mineobfusc_SOURCES = ./malloc.c ./misc.c ./nullfe.c ./puzzles.h ./random.c \ ./tree234.c ./tree234.h mineobfusc_LDADD = libmines2_a-mines.$(OBJEXT) -lm mines_SOURCES = ./drawing.c ./gtk.c ./malloc.c ./midend.c ./mines.c ./misc.c \ ./printing.c ./ps.c ./puzzles.h ./random.c ./tree234.c \ ./tree234.h ./version.c ./version.h icons/mines-icon.c mines_LDADD = $(GTK_LIBS) -lm net_SOURCES = ./drawing.c ./dsf.c ./findloop.c ./gtk.c ./malloc.c ./midend.c \ ./misc.c ./net.c ./printing.c ./ps.c ./puzzles.h ./random.c \ ./tree234.c ./tree234.h ./version.c ./version.h \ icons/net-icon.c net_LDADD = $(GTK_LIBS) -lm netslide_SOURCES = ./drawing.c ./gtk.c ./malloc.c ./midend.c ./misc.c \ ./netslide.c ./printing.c ./ps.c ./puzzles.h ./random.c \ ./tree234.c ./tree234.h ./version.c ./version.h \ icons/netslide-icon.c netslide_LDADD = $(GTK_LIBS) -lm nullgame_SOURCES = ./drawing.c ./gtk.c ./malloc.c ./midend.c ./misc.c \ ./no-icon.c ./nullgame.c ./printing.c ./ps.c ./puzzles.h \ ./random.c ./version.c ./version.h nullgame_LDADD = $(GTK_LIBS) -lm obfusc_SOURCES = ./malloc.c ./misc.c ./nullfe.c ./obfusc.c ./puzzles.h \ ./random.c obfusc_LDADD = -lm palisade_SOURCES = ./divvy.c ./drawing.c ./dsf.c ./gtk.c ./malloc.c \ ./midend.c ./misc.c ./palisade.c ./printing.c ./ps.c \ ./puzzles.h ./random.c ./version.c ./version.h \ icons/palisade-icon.c palisade_LDADD = $(GTK_LIBS) -lm pattern_SOURCES = ./drawing.c ./gtk.c ./malloc.c ./midend.c ./misc.c \ ./pattern.c ./printing.c ./ps.c ./puzzles.h ./random.c \ ./version.c ./version.h icons/pattern-icon.c pattern_LDADD = $(GTK_LIBS) -lm patternpicture_SOURCES = ./malloc.c ./misc.c ./nullfe.c ./puzzles.h \ ./random.c patternpicture_LDADD = libpattern4_a-pattern.$(OBJEXT) -lm patternsolver_SOURCES = ./malloc.c ./misc.c ./nullfe.c ./puzzles.h \ ./random.c patternsolver_LDADD = libpattern2_a-pattern.$(OBJEXT) -lm pearl_SOURCES = ./drawing.c ./dsf.c ./grid.c ./grid.h ./gtk.c ./loopgen.c \ ./loopgen.h ./malloc.c ./midend.c ./misc.c ./pearl.c \ ./penrose.c ./penrose.h ./printing.c ./ps.c ./puzzles.h \ ./random.c ./tdq.c ./tree234.c ./tree234.h ./version.c \ ./version.h icons/pearl-icon.c pearl_LDADD = $(GTK_LIBS) -lm pearlbench_SOURCES = ./dsf.c ./grid.c ./grid.h ./loopgen.c ./loopgen.h \ ./malloc.c ./misc.c ./nullfe.c ./penrose.c ./penrose.h \ ./puzzles.h ./random.c ./tdq.c ./tree234.c ./tree234.h pearlbench_LDADD = libpearl2_a-pearl.$(OBJEXT) -lm pegs_SOURCES = ./drawing.c ./gtk.c ./malloc.c ./midend.c ./misc.c ./pegs.c \ ./printing.c ./ps.c ./puzzles.h ./random.c ./tree234.c \ ./tree234.h ./version.c ./version.h icons/pegs-icon.c pegs_LDADD = $(GTK_LIBS) -lm range_SOURCES = ./drawing.c ./dsf.c ./gtk.c ./malloc.c ./midend.c ./misc.c \ ./printing.c ./ps.c ./puzzles.h ./random.c ./range.c \ ./version.c ./version.h icons/range-icon.c range_LDADD = $(GTK_LIBS) -lm rect_SOURCES = ./drawing.c ./gtk.c ./malloc.c ./midend.c ./misc.c \ ./printing.c ./ps.c ./puzzles.h ./random.c ./rect.c \ ./version.c ./version.h icons/rect-icon.c rect_LDADD = $(GTK_LIBS) -lm samegame_SOURCES = ./drawing.c ./gtk.c ./malloc.c ./midend.c ./misc.c \ ./printing.c ./ps.c ./puzzles.h ./random.c ./samegame.c \ ./version.c ./version.h icons/samegame-icon.c samegame_LDADD = $(GTK_LIBS) -lm signpost_SOURCES = ./drawing.c ./dsf.c ./gtk.c ./malloc.c ./midend.c \ ./misc.c ./printing.c ./ps.c ./puzzles.h ./random.c \ ./signpost.c ./version.c ./version.h icons/signpost-icon.c signpost_LDADD = $(GTK_LIBS) -lm signpostsolver_SOURCES = ./dsf.c ./malloc.c ./misc.c ./nullfe.c ./puzzles.h \ ./random.c signpostsolver_LDADD = libsignpos2_a-signpost.$(OBJEXT) -lm singles_SOURCES = ./drawing.c ./dsf.c ./gtk.c ./latin.c ./latin.h ./malloc.c \ ./maxflow.c ./maxflow.h ./midend.c ./misc.c ./printing.c \ ./ps.c ./puzzles.h ./random.c ./singles.c ./tree234.c \ ./tree234.h ./version.c ./version.h icons/singles-icon.c singles_LDADD = $(GTK_LIBS) -lm singlessolver_SOURCES = ./dsf.c ./latin.c ./latin.h ./malloc.c ./maxflow.c \ ./maxflow.h ./misc.c ./nullfe.c ./puzzles.h ./random.c \ ./tree234.c ./tree234.h singlessolver_LDADD = libsingles3_a-singles.$(OBJEXT) -lm sixteen_SOURCES = ./drawing.c ./gtk.c ./malloc.c ./midend.c ./misc.c \ ./printing.c ./ps.c ./puzzles.h ./random.c ./sixteen.c \ ./version.c ./version.h icons/sixteen-icon.c sixteen_LDADD = $(GTK_LIBS) -lm slant_SOURCES = ./drawing.c ./dsf.c ./findloop.c ./gtk.c ./malloc.c \ ./midend.c ./misc.c ./printing.c ./ps.c ./puzzles.h \ ./random.c ./slant.c ./version.c ./version.h \ icons/slant-icon.c slant_LDADD = $(GTK_LIBS) -lm slantsolver_SOURCES = ./dsf.c ./findloop.c ./malloc.c ./misc.c ./nullfe.c \ ./puzzles.h ./random.c slantsolver_LDADD = libslant2_a-slant.$(OBJEXT) -lm solo_SOURCES = ./divvy.c ./drawing.c ./dsf.c ./gtk.c ./malloc.c ./midend.c \ ./misc.c ./printing.c ./ps.c ./puzzles.h ./random.c ./solo.c \ ./version.c ./version.h icons/solo-icon.c solo_LDADD = $(GTK_LIBS) -lm solosolver_SOURCES = ./divvy.c ./dsf.c ./malloc.c ./misc.c ./nullfe.c \ ./puzzles.h ./random.c solosolver_LDADD = libsolo2_a-solo.$(OBJEXT) -lm tents_SOURCES = ./drawing.c ./dsf.c ./gtk.c ./malloc.c ./maxflow.c \ ./maxflow.h ./midend.c ./misc.c ./printing.c ./ps.c \ ./puzzles.h ./random.c ./tents.c ./version.c ./version.h \ icons/tents-icon.c tents_LDADD = $(GTK_LIBS) -lm tentssolver_SOURCES = ./dsf.c ./malloc.c ./maxflow.c ./maxflow.h ./misc.c \ ./nullfe.c ./puzzles.h ./random.c tentssolver_LDADD = libtents3_a-tents.$(OBJEXT) -lm towers_SOURCES = ./drawing.c ./gtk.c ./latin.c ./latin.h ./malloc.c \ ./maxflow.c ./maxflow.h ./midend.c ./misc.c ./printing.c \ ./ps.c ./puzzles.h ./random.c ./towers.c ./tree234.c \ ./tree234.h ./version.c ./version.h icons/towers-icon.c towers_LDADD = $(GTK_LIBS) -lm towerssolver_SOURCES = ./malloc.c ./maxflow.c ./maxflow.h ./misc.c \ ./nullfe.c ./puzzles.h ./random.c ./tree234.c ./tree234.h towerssolver_LDADD = liblatin6_a-latin.$(OBJEXT) \ libtowers2_a-towers.$(OBJEXT) -lm tracks_SOURCES = ./drawing.c ./dsf.c ./findloop.c ./gtk.c ./malloc.c \ ./midend.c ./misc.c ./printing.c ./ps.c ./puzzles.h \ ./random.c ./tracks.c ./version.c ./version.h \ icons/tracks-icon.c tracks_LDADD = $(GTK_LIBS) -lm twiddle_SOURCES = ./drawing.c ./gtk.c ./malloc.c ./midend.c ./misc.c \ ./printing.c ./ps.c ./puzzles.h ./random.c ./twiddle.c \ ./version.c ./version.h icons/twiddle-icon.c twiddle_LDADD = $(GTK_LIBS) -lm undead_SOURCES = ./drawing.c ./gtk.c ./malloc.c ./midend.c ./misc.c \ ./printing.c ./ps.c ./puzzles.h ./random.c ./undead.c \ ./version.c ./version.h icons/undead-icon.c undead_LDADD = $(GTK_LIBS) -lm unequal_SOURCES = ./drawing.c ./gtk.c ./latin.c ./latin.h ./malloc.c \ ./maxflow.c ./maxflow.h ./midend.c ./misc.c ./printing.c \ ./ps.c ./puzzles.h ./random.c ./tree234.c ./tree234.h \ ./unequal.c ./version.c ./version.h icons/unequal-icon.c unequal_LDADD = $(GTK_LIBS) -lm unequalsolver_SOURCES = ./malloc.c ./maxflow.c ./maxflow.h ./misc.c \ ./nullfe.c ./puzzles.h ./random.c ./tree234.c ./tree234.h unequalsolver_LDADD = liblatin6_a-latin.$(OBJEXT) \ libunequal2_a-unequal.$(OBJEXT) -lm unruly_SOURCES = ./drawing.c ./gtk.c ./malloc.c ./midend.c ./misc.c \ ./printing.c ./ps.c ./puzzles.h ./random.c ./unruly.c \ ./version.c ./version.h icons/unruly-icon.c unruly_LDADD = $(GTK_LIBS) -lm unrulysolver_SOURCES = ./malloc.c ./misc.c ./nullfe.c ./puzzles.h ./random.c unrulysolver_LDADD = libunruly2_a-unruly.$(OBJEXT) -lm untangle_SOURCES = ./drawing.c ./gtk.c ./malloc.c ./midend.c ./misc.c \ ./printing.c ./ps.c ./puzzles.h ./random.c ./tree234.c \ ./tree234.h ./untangle.c ./version.c ./version.h \ icons/untangle-icon.c untangle_LDADD = $(GTK_LIBS) -lm libfifteen2_a_SOURCES = ./fifteen.c ./puzzles.h libfifteen2_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_SOLVER libfilling2_a_SOURCES = ./filling.c ./puzzles.h libfilling2_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_SOLVER libgalaxie2_a_SOURCES = ./galaxies.c ./puzzles.h libgalaxie2_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_SOLVER libgalaxie4_a_SOURCES = ./galaxies.c ./puzzles.h libgalaxie4_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) \ -DSTANDALONE_PICTURE_GENERATOR libkeen2_a_SOURCES = ./keen.c ./puzzles.h ./latin.h libkeen2_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_SOLVER liblatin6_a_SOURCES = ./latin.c ./puzzles.h ./tree234.h ./maxflow.h \ ./latin.h liblatin6_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_SOLVER liblatin8_a_SOURCES = ./latin.c ./puzzles.h ./tree234.h ./maxflow.h \ ./latin.h liblatin8_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_LATIN_TEST liblightup2_a_SOURCES = ./lightup.c ./puzzles.h liblightup2_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_SOLVER libloopy2_a_SOURCES = ./loopy.c ./puzzles.h ./tree234.h ./grid.h ./loopgen.h libloopy2_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_SOLVER libmagnets2_a_SOURCES = ./magnets.c ./puzzles.h libmagnets2_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_SOLVER libmap2_a_SOURCES = ./map.c ./puzzles.h libmap2_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_SOLVER libmines2_a_SOURCES = ./mines.c ./tree234.h ./puzzles.h libmines2_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_OBFUSCATOR libpattern2_a_SOURCES = ./pattern.c ./puzzles.h libpattern2_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_SOLVER libpattern4_a_SOURCES = ./pattern.c ./puzzles.h libpattern4_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) \ -DSTANDALONE_PICTURE_GENERATOR libpearl2_a_SOURCES = ./pearl.c ./puzzles.h ./grid.h ./loopgen.h libpearl2_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_SOLVER libsignpos2_a_SOURCES = ./signpost.c ./puzzles.h libsignpos2_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_SOLVER libsingles3_a_SOURCES = ./singles.c ./puzzles.h ./latin.h libsingles3_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_SOLVER libslant2_a_SOURCES = ./slant.c ./puzzles.h libslant2_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_SOLVER libsolo2_a_SOURCES = ./solo.c ./puzzles.h libsolo2_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_SOLVER libtents3_a_SOURCES = ./tents.c ./puzzles.h ./maxflow.h libtents3_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_SOLVER libtowers2_a_SOURCES = ./towers.c ./puzzles.h ./latin.h libtowers2_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_SOLVER libunequal2_a_SOURCES = ./unequal.c ./puzzles.h ./latin.h libunequal2_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_SOLVER libunruly2_a_SOURCES = ./unruly.c ./puzzles.h libunruly2_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_SOLVER noinst_LIBRARIES = libfifteen2.a libfilling2.a libgalaxie2.a libgalaxie4.a \ libkeen2.a liblatin6.a liblatin8.a liblightup2.a libloopy2.a \ libmagnets2.a libmap2.a libmines2.a libpattern2.a \ libpattern4.a libpearl2.a libsignpos2.a libsingles3.a \ libslant2.a libsolo2.a libtents3.a libtowers2.a \ libunequal2.a libunruly2.a all: all-am .SUFFIXES: .SUFFIXES: .c .o .obj 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__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ 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): clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) ./$(am__dirstamp): @$(MKDIR_P) . @: > ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) ./$(DEPDIR) @: > $(DEPDIR)/$(am__dirstamp) ./libfifteen2_a-fifteen.$(OBJEXT): ./$(am__dirstamp) \ $(DEPDIR)/$(am__dirstamp) libfifteen2.a: $(libfifteen2_a_OBJECTS) $(libfifteen2_a_DEPENDENCIES) $(EXTRA_libfifteen2_a_DEPENDENCIES) $(AM_V_at)-rm -f libfifteen2.a $(AM_V_AR)$(libfifteen2_a_AR) libfifteen2.a $(libfifteen2_a_OBJECTS) $(libfifteen2_a_LIBADD) $(AM_V_at)$(RANLIB) libfifteen2.a ./libfilling2_a-filling.$(OBJEXT): ./$(am__dirstamp) \ $(DEPDIR)/$(am__dirstamp) libfilling2.a: $(libfilling2_a_OBJECTS) $(libfilling2_a_DEPENDENCIES) $(EXTRA_libfilling2_a_DEPENDENCIES) $(AM_V_at)-rm -f libfilling2.a $(AM_V_AR)$(libfilling2_a_AR) libfilling2.a $(libfilling2_a_OBJECTS) $(libfilling2_a_LIBADD) $(AM_V_at)$(RANLIB) libfilling2.a ./libgalaxie2_a-galaxies.$(OBJEXT): ./$(am__dirstamp) \ $(DEPDIR)/$(am__dirstamp) libgalaxie2.a: $(libgalaxie2_a_OBJECTS) $(libgalaxie2_a_DEPENDENCIES) $(EXTRA_libgalaxie2_a_DEPENDENCIES) $(AM_V_at)-rm -f libgalaxie2.a $(AM_V_AR)$(libgalaxie2_a_AR) libgalaxie2.a $(libgalaxie2_a_OBJECTS) $(libgalaxie2_a_LIBADD) $(AM_V_at)$(RANLIB) libgalaxie2.a ./libgalaxie4_a-galaxies.$(OBJEXT): ./$(am__dirstamp) \ $(DEPDIR)/$(am__dirstamp) libgalaxie4.a: $(libgalaxie4_a_OBJECTS) $(libgalaxie4_a_DEPENDENCIES) $(EXTRA_libgalaxie4_a_DEPENDENCIES) $(AM_V_at)-rm -f libgalaxie4.a $(AM_V_AR)$(libgalaxie4_a_AR) libgalaxie4.a $(libgalaxie4_a_OBJECTS) $(libgalaxie4_a_LIBADD) $(AM_V_at)$(RANLIB) libgalaxie4.a ./libkeen2_a-keen.$(OBJEXT): ./$(am__dirstamp) \ $(DEPDIR)/$(am__dirstamp) libkeen2.a: $(libkeen2_a_OBJECTS) $(libkeen2_a_DEPENDENCIES) $(EXTRA_libkeen2_a_DEPENDENCIES) $(AM_V_at)-rm -f libkeen2.a $(AM_V_AR)$(libkeen2_a_AR) libkeen2.a $(libkeen2_a_OBJECTS) $(libkeen2_a_LIBADD) $(AM_V_at)$(RANLIB) libkeen2.a ./liblatin6_a-latin.$(OBJEXT): ./$(am__dirstamp) \ $(DEPDIR)/$(am__dirstamp) liblatin6.a: $(liblatin6_a_OBJECTS) $(liblatin6_a_DEPENDENCIES) $(EXTRA_liblatin6_a_DEPENDENCIES) $(AM_V_at)-rm -f liblatin6.a $(AM_V_AR)$(liblatin6_a_AR) liblatin6.a $(liblatin6_a_OBJECTS) $(liblatin6_a_LIBADD) $(AM_V_at)$(RANLIB) liblatin6.a ./liblatin8_a-latin.$(OBJEXT): ./$(am__dirstamp) \ $(DEPDIR)/$(am__dirstamp) liblatin8.a: $(liblatin8_a_OBJECTS) $(liblatin8_a_DEPENDENCIES) $(EXTRA_liblatin8_a_DEPENDENCIES) $(AM_V_at)-rm -f liblatin8.a $(AM_V_AR)$(liblatin8_a_AR) liblatin8.a $(liblatin8_a_OBJECTS) $(liblatin8_a_LIBADD) $(AM_V_at)$(RANLIB) liblatin8.a ./liblightup2_a-lightup.$(OBJEXT): ./$(am__dirstamp) \ $(DEPDIR)/$(am__dirstamp) liblightup2.a: $(liblightup2_a_OBJECTS) $(liblightup2_a_DEPENDENCIES) $(EXTRA_liblightup2_a_DEPENDENCIES) $(AM_V_at)-rm -f liblightup2.a $(AM_V_AR)$(liblightup2_a_AR) liblightup2.a $(liblightup2_a_OBJECTS) $(liblightup2_a_LIBADD) $(AM_V_at)$(RANLIB) liblightup2.a ./libloopy2_a-loopy.$(OBJEXT): ./$(am__dirstamp) \ $(DEPDIR)/$(am__dirstamp) libloopy2.a: $(libloopy2_a_OBJECTS) $(libloopy2_a_DEPENDENCIES) $(EXTRA_libloopy2_a_DEPENDENCIES) $(AM_V_at)-rm -f libloopy2.a $(AM_V_AR)$(libloopy2_a_AR) libloopy2.a $(libloopy2_a_OBJECTS) $(libloopy2_a_LIBADD) $(AM_V_at)$(RANLIB) libloopy2.a ./libmagnets2_a-magnets.$(OBJEXT): ./$(am__dirstamp) \ $(DEPDIR)/$(am__dirstamp) libmagnets2.a: $(libmagnets2_a_OBJECTS) $(libmagnets2_a_DEPENDENCIES) $(EXTRA_libmagnets2_a_DEPENDENCIES) $(AM_V_at)-rm -f libmagnets2.a $(AM_V_AR)$(libmagnets2_a_AR) libmagnets2.a $(libmagnets2_a_OBJECTS) $(libmagnets2_a_LIBADD) $(AM_V_at)$(RANLIB) libmagnets2.a ./libmap2_a-map.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) libmap2.a: $(libmap2_a_OBJECTS) $(libmap2_a_DEPENDENCIES) $(EXTRA_libmap2_a_DEPENDENCIES) $(AM_V_at)-rm -f libmap2.a $(AM_V_AR)$(libmap2_a_AR) libmap2.a $(libmap2_a_OBJECTS) $(libmap2_a_LIBADD) $(AM_V_at)$(RANLIB) libmap2.a ./libmines2_a-mines.$(OBJEXT): ./$(am__dirstamp) \ $(DEPDIR)/$(am__dirstamp) libmines2.a: $(libmines2_a_OBJECTS) $(libmines2_a_DEPENDENCIES) $(EXTRA_libmines2_a_DEPENDENCIES) $(AM_V_at)-rm -f libmines2.a $(AM_V_AR)$(libmines2_a_AR) libmines2.a $(libmines2_a_OBJECTS) $(libmines2_a_LIBADD) $(AM_V_at)$(RANLIB) libmines2.a ./libpattern2_a-pattern.$(OBJEXT): ./$(am__dirstamp) \ $(DEPDIR)/$(am__dirstamp) libpattern2.a: $(libpattern2_a_OBJECTS) $(libpattern2_a_DEPENDENCIES) $(EXTRA_libpattern2_a_DEPENDENCIES) $(AM_V_at)-rm -f libpattern2.a $(AM_V_AR)$(libpattern2_a_AR) libpattern2.a $(libpattern2_a_OBJECTS) $(libpattern2_a_LIBADD) $(AM_V_at)$(RANLIB) libpattern2.a ./libpattern4_a-pattern.$(OBJEXT): ./$(am__dirstamp) \ $(DEPDIR)/$(am__dirstamp) libpattern4.a: $(libpattern4_a_OBJECTS) $(libpattern4_a_DEPENDENCIES) $(EXTRA_libpattern4_a_DEPENDENCIES) $(AM_V_at)-rm -f libpattern4.a $(AM_V_AR)$(libpattern4_a_AR) libpattern4.a $(libpattern4_a_OBJECTS) $(libpattern4_a_LIBADD) $(AM_V_at)$(RANLIB) libpattern4.a ./libpearl2_a-pearl.$(OBJEXT): ./$(am__dirstamp) \ $(DEPDIR)/$(am__dirstamp) libpearl2.a: $(libpearl2_a_OBJECTS) $(libpearl2_a_DEPENDENCIES) $(EXTRA_libpearl2_a_DEPENDENCIES) $(AM_V_at)-rm -f libpearl2.a $(AM_V_AR)$(libpearl2_a_AR) libpearl2.a $(libpearl2_a_OBJECTS) $(libpearl2_a_LIBADD) $(AM_V_at)$(RANLIB) libpearl2.a ./libsignpos2_a-signpost.$(OBJEXT): ./$(am__dirstamp) \ $(DEPDIR)/$(am__dirstamp) libsignpos2.a: $(libsignpos2_a_OBJECTS) $(libsignpos2_a_DEPENDENCIES) $(EXTRA_libsignpos2_a_DEPENDENCIES) $(AM_V_at)-rm -f libsignpos2.a $(AM_V_AR)$(libsignpos2_a_AR) libsignpos2.a $(libsignpos2_a_OBJECTS) $(libsignpos2_a_LIBADD) $(AM_V_at)$(RANLIB) libsignpos2.a ./libsingles3_a-singles.$(OBJEXT): ./$(am__dirstamp) \ $(DEPDIR)/$(am__dirstamp) libsingles3.a: $(libsingles3_a_OBJECTS) $(libsingles3_a_DEPENDENCIES) $(EXTRA_libsingles3_a_DEPENDENCIES) $(AM_V_at)-rm -f libsingles3.a $(AM_V_AR)$(libsingles3_a_AR) libsingles3.a $(libsingles3_a_OBJECTS) $(libsingles3_a_LIBADD) $(AM_V_at)$(RANLIB) libsingles3.a ./libslant2_a-slant.$(OBJEXT): ./$(am__dirstamp) \ $(DEPDIR)/$(am__dirstamp) libslant2.a: $(libslant2_a_OBJECTS) $(libslant2_a_DEPENDENCIES) $(EXTRA_libslant2_a_DEPENDENCIES) $(AM_V_at)-rm -f libslant2.a $(AM_V_AR)$(libslant2_a_AR) libslant2.a $(libslant2_a_OBJECTS) $(libslant2_a_LIBADD) $(AM_V_at)$(RANLIB) libslant2.a ./libsolo2_a-solo.$(OBJEXT): ./$(am__dirstamp) \ $(DEPDIR)/$(am__dirstamp) libsolo2.a: $(libsolo2_a_OBJECTS) $(libsolo2_a_DEPENDENCIES) $(EXTRA_libsolo2_a_DEPENDENCIES) $(AM_V_at)-rm -f libsolo2.a $(AM_V_AR)$(libsolo2_a_AR) libsolo2.a $(libsolo2_a_OBJECTS) $(libsolo2_a_LIBADD) $(AM_V_at)$(RANLIB) libsolo2.a ./libtents3_a-tents.$(OBJEXT): ./$(am__dirstamp) \ $(DEPDIR)/$(am__dirstamp) libtents3.a: $(libtents3_a_OBJECTS) $(libtents3_a_DEPENDENCIES) $(EXTRA_libtents3_a_DEPENDENCIES) $(AM_V_at)-rm -f libtents3.a $(AM_V_AR)$(libtents3_a_AR) libtents3.a $(libtents3_a_OBJECTS) $(libtents3_a_LIBADD) $(AM_V_at)$(RANLIB) libtents3.a ./libtowers2_a-towers.$(OBJEXT): ./$(am__dirstamp) \ $(DEPDIR)/$(am__dirstamp) libtowers2.a: $(libtowers2_a_OBJECTS) $(libtowers2_a_DEPENDENCIES) $(EXTRA_libtowers2_a_DEPENDENCIES) $(AM_V_at)-rm -f libtowers2.a $(AM_V_AR)$(libtowers2_a_AR) libtowers2.a $(libtowers2_a_OBJECTS) $(libtowers2_a_LIBADD) $(AM_V_at)$(RANLIB) libtowers2.a ./libunequal2_a-unequal.$(OBJEXT): ./$(am__dirstamp) \ $(DEPDIR)/$(am__dirstamp) libunequal2.a: $(libunequal2_a_OBJECTS) $(libunequal2_a_DEPENDENCIES) $(EXTRA_libunequal2_a_DEPENDENCIES) $(AM_V_at)-rm -f libunequal2.a $(AM_V_AR)$(libunequal2_a_AR) libunequal2.a $(libunequal2_a_OBJECTS) $(libunequal2_a_LIBADD) $(AM_V_at)$(RANLIB) libunequal2.a ./libunruly2_a-unruly.$(OBJEXT): ./$(am__dirstamp) \ $(DEPDIR)/$(am__dirstamp) libunruly2.a: $(libunruly2_a_OBJECTS) $(libunruly2_a_DEPENDENCIES) $(EXTRA_libunruly2_a_DEPENDENCIES) $(AM_V_at)-rm -f libunruly2.a $(AM_V_AR)$(libunruly2_a_AR) libunruly2.a $(libunruly2_a_OBJECTS) $(libunruly2_a_LIBADD) $(AM_V_at)$(RANLIB) libunruly2.a 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 \ ; 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) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(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: -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) clean-noinstPROGRAMS: -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) ./blackbox.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) ./drawing.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) ./gtk.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) ./malloc.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) ./midend.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) ./misc.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) ./printing.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) ./ps.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) ./random.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) ./version.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/$(am__dirstamp): @$(MKDIR_P) icons @: > icons/$(am__dirstamp) icons/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) icons/$(DEPDIR) @: > icons/$(DEPDIR)/$(am__dirstamp) icons/blackbox-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) blackbox$(EXEEXT): $(blackbox_OBJECTS) $(blackbox_DEPENDENCIES) $(EXTRA_blackbox_DEPENDENCIES) @rm -f blackbox$(EXEEXT) $(AM_V_CCLD)$(LINK) $(blackbox_OBJECTS) $(blackbox_LDADD) $(LIBS) ./bridges.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) ./dsf.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) ./findloop.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/bridges-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) bridges$(EXEEXT): $(bridges_OBJECTS) $(bridges_DEPENDENCIES) $(EXTRA_bridges_DEPENDENCIES) @rm -f bridges$(EXEEXT) $(AM_V_CCLD)$(LINK) $(bridges_OBJECTS) $(bridges_LDADD) $(LIBS) ./cube.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/cube-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) cube$(EXEEXT): $(cube_OBJECTS) $(cube_DEPENDENCIES) $(EXTRA_cube_DEPENDENCIES) @rm -f cube$(EXEEXT) $(AM_V_CCLD)$(LINK) $(cube_OBJECTS) $(cube_LDADD) $(LIBS) ./dominosa.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) ./laydomino.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/dominosa-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) dominosa$(EXEEXT): $(dominosa_OBJECTS) $(dominosa_DEPENDENCIES) $(EXTRA_dominosa_DEPENDENCIES) @rm -f dominosa$(EXEEXT) $(AM_V_CCLD)$(LINK) $(dominosa_OBJECTS) $(dominosa_LDADD) $(LIBS) ./fifteen.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/fifteen-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) fifteen$(EXEEXT): $(fifteen_OBJECTS) $(fifteen_DEPENDENCIES) $(EXTRA_fifteen_DEPENDENCIES) @rm -f fifteen$(EXEEXT) $(AM_V_CCLD)$(LINK) $(fifteen_OBJECTS) $(fifteen_LDADD) $(LIBS) ./nullfe.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) fifteensolver$(EXEEXT): $(fifteensolver_OBJECTS) $(fifteensolver_DEPENDENCIES) $(EXTRA_fifteensolver_DEPENDENCIES) @rm -f fifteensolver$(EXEEXT) $(AM_V_CCLD)$(LINK) $(fifteensolver_OBJECTS) $(fifteensolver_LDADD) $(LIBS) ./filling.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/filling-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) filling$(EXEEXT): $(filling_OBJECTS) $(filling_DEPENDENCIES) $(EXTRA_filling_DEPENDENCIES) @rm -f filling$(EXEEXT) $(AM_V_CCLD)$(LINK) $(filling_OBJECTS) $(filling_LDADD) $(LIBS) fillingsolver$(EXEEXT): $(fillingsolver_OBJECTS) $(fillingsolver_DEPENDENCIES) $(EXTRA_fillingsolver_DEPENDENCIES) @rm -f fillingsolver$(EXEEXT) $(AM_V_CCLD)$(LINK) $(fillingsolver_OBJECTS) $(fillingsolver_LDADD) $(LIBS) ./flip.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) ./tree234.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/flip-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) flip$(EXEEXT): $(flip_OBJECTS) $(flip_DEPENDENCIES) $(EXTRA_flip_DEPENDENCIES) @rm -f flip$(EXEEXT) $(AM_V_CCLD)$(LINK) $(flip_OBJECTS) $(flip_LDADD) $(LIBS) ./flood.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/flood-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) flood$(EXEEXT): $(flood_OBJECTS) $(flood_DEPENDENCIES) $(EXTRA_flood_DEPENDENCIES) @rm -f flood$(EXEEXT) $(AM_V_CCLD)$(LINK) $(flood_OBJECTS) $(flood_LDADD) $(LIBS) ./galaxies.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/galaxies-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) galaxies$(EXEEXT): $(galaxies_OBJECTS) $(galaxies_DEPENDENCIES) $(EXTRA_galaxies_DEPENDENCIES) @rm -f galaxies$(EXEEXT) $(AM_V_CCLD)$(LINK) $(galaxies_OBJECTS) $(galaxies_LDADD) $(LIBS) galaxiespicture$(EXEEXT): $(galaxiespicture_OBJECTS) $(galaxiespicture_DEPENDENCIES) $(EXTRA_galaxiespicture_DEPENDENCIES) @rm -f galaxiespicture$(EXEEXT) $(AM_V_CCLD)$(LINK) $(galaxiespicture_OBJECTS) $(galaxiespicture_LDADD) $(LIBS) galaxiessolver$(EXEEXT): $(galaxiessolver_OBJECTS) $(galaxiessolver_DEPENDENCIES) $(EXTRA_galaxiessolver_DEPENDENCIES) @rm -f galaxiessolver$(EXEEXT) $(AM_V_CCLD)$(LINK) $(galaxiessolver_OBJECTS) $(galaxiessolver_LDADD) $(LIBS) ./guess.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/guess-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) guess$(EXEEXT): $(guess_OBJECTS) $(guess_DEPENDENCIES) $(EXTRA_guess_DEPENDENCIES) @rm -f guess$(EXEEXT) $(AM_V_CCLD)$(LINK) $(guess_OBJECTS) $(guess_LDADD) $(LIBS) ./inertia.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/inertia-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) inertia$(EXEEXT): $(inertia_OBJECTS) $(inertia_DEPENDENCIES) $(EXTRA_inertia_DEPENDENCIES) @rm -f inertia$(EXEEXT) $(AM_V_CCLD)$(LINK) $(inertia_OBJECTS) $(inertia_LDADD) $(LIBS) ./keen.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) ./latin.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) ./maxflow.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/keen-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) keen$(EXEEXT): $(keen_OBJECTS) $(keen_DEPENDENCIES) $(EXTRA_keen_DEPENDENCIES) @rm -f keen$(EXEEXT) $(AM_V_CCLD)$(LINK) $(keen_OBJECTS) $(keen_LDADD) $(LIBS) keensolver$(EXEEXT): $(keensolver_OBJECTS) $(keensolver_DEPENDENCIES) $(EXTRA_keensolver_DEPENDENCIES) @rm -f keensolver$(EXEEXT) $(AM_V_CCLD)$(LINK) $(keensolver_OBJECTS) $(keensolver_LDADD) $(LIBS) latincheck$(EXEEXT): $(latincheck_OBJECTS) $(latincheck_DEPENDENCIES) $(EXTRA_latincheck_DEPENDENCIES) @rm -f latincheck$(EXEEXT) $(AM_V_CCLD)$(LINK) $(latincheck_OBJECTS) $(latincheck_LDADD) $(LIBS) ./combi.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) ./lightup.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/lightup-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) lightup$(EXEEXT): $(lightup_OBJECTS) $(lightup_DEPENDENCIES) $(EXTRA_lightup_DEPENDENCIES) @rm -f lightup$(EXEEXT) $(AM_V_CCLD)$(LINK) $(lightup_OBJECTS) $(lightup_LDADD) $(LIBS) lightupsolver$(EXEEXT): $(lightupsolver_OBJECTS) $(lightupsolver_DEPENDENCIES) $(EXTRA_lightupsolver_DEPENDENCIES) @rm -f lightupsolver$(EXEEXT) $(AM_V_CCLD)$(LINK) $(lightupsolver_OBJECTS) $(lightupsolver_LDADD) $(LIBS) ./grid.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) ./loopgen.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) ./loopy.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) ./penrose.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/loopy-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) loopy$(EXEEXT): $(loopy_OBJECTS) $(loopy_DEPENDENCIES) $(EXTRA_loopy_DEPENDENCIES) @rm -f loopy$(EXEEXT) $(AM_V_CCLD)$(LINK) $(loopy_OBJECTS) $(loopy_LDADD) $(LIBS) loopysolver$(EXEEXT): $(loopysolver_OBJECTS) $(loopysolver_DEPENDENCIES) $(EXTRA_loopysolver_DEPENDENCIES) @rm -f loopysolver$(EXEEXT) $(AM_V_CCLD)$(LINK) $(loopysolver_OBJECTS) $(loopysolver_LDADD) $(LIBS) ./magnets.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/magnets-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) magnets$(EXEEXT): $(magnets_OBJECTS) $(magnets_DEPENDENCIES) $(EXTRA_magnets_DEPENDENCIES) @rm -f magnets$(EXEEXT) $(AM_V_CCLD)$(LINK) $(magnets_OBJECTS) $(magnets_LDADD) $(LIBS) magnetssolver$(EXEEXT): $(magnetssolver_OBJECTS) $(magnetssolver_DEPENDENCIES) $(EXTRA_magnetssolver_DEPENDENCIES) @rm -f magnetssolver$(EXEEXT) $(AM_V_CCLD)$(LINK) $(magnetssolver_OBJECTS) $(magnetssolver_LDADD) $(LIBS) ./map.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/map-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) map$(EXEEXT): $(map_OBJECTS) $(map_DEPENDENCIES) $(EXTRA_map_DEPENDENCIES) @rm -f map$(EXEEXT) $(AM_V_CCLD)$(LINK) $(map_OBJECTS) $(map_LDADD) $(LIBS) mapsolver$(EXEEXT): $(mapsolver_OBJECTS) $(mapsolver_DEPENDENCIES) $(EXTRA_mapsolver_DEPENDENCIES) @rm -f mapsolver$(EXEEXT) $(AM_V_CCLD)$(LINK) $(mapsolver_OBJECTS) $(mapsolver_LDADD) $(LIBS) mineobfusc$(EXEEXT): $(mineobfusc_OBJECTS) $(mineobfusc_DEPENDENCIES) $(EXTRA_mineobfusc_DEPENDENCIES) @rm -f mineobfusc$(EXEEXT) $(AM_V_CCLD)$(LINK) $(mineobfusc_OBJECTS) $(mineobfusc_LDADD) $(LIBS) ./mines.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/mines-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) mines$(EXEEXT): $(mines_OBJECTS) $(mines_DEPENDENCIES) $(EXTRA_mines_DEPENDENCIES) @rm -f mines$(EXEEXT) $(AM_V_CCLD)$(LINK) $(mines_OBJECTS) $(mines_LDADD) $(LIBS) ./net.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/net-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) net$(EXEEXT): $(net_OBJECTS) $(net_DEPENDENCIES) $(EXTRA_net_DEPENDENCIES) @rm -f net$(EXEEXT) $(AM_V_CCLD)$(LINK) $(net_OBJECTS) $(net_LDADD) $(LIBS) ./netslide.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/netslide-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) netslide$(EXEEXT): $(netslide_OBJECTS) $(netslide_DEPENDENCIES) $(EXTRA_netslide_DEPENDENCIES) @rm -f netslide$(EXEEXT) $(AM_V_CCLD)$(LINK) $(netslide_OBJECTS) $(netslide_LDADD) $(LIBS) ./no-icon.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) ./nullgame.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) nullgame$(EXEEXT): $(nullgame_OBJECTS) $(nullgame_DEPENDENCIES) $(EXTRA_nullgame_DEPENDENCIES) @rm -f nullgame$(EXEEXT) $(AM_V_CCLD)$(LINK) $(nullgame_OBJECTS) $(nullgame_LDADD) $(LIBS) ./obfusc.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) obfusc$(EXEEXT): $(obfusc_OBJECTS) $(obfusc_DEPENDENCIES) $(EXTRA_obfusc_DEPENDENCIES) @rm -f obfusc$(EXEEXT) $(AM_V_CCLD)$(LINK) $(obfusc_OBJECTS) $(obfusc_LDADD) $(LIBS) ./divvy.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) ./palisade.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/palisade-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) palisade$(EXEEXT): $(palisade_OBJECTS) $(palisade_DEPENDENCIES) $(EXTRA_palisade_DEPENDENCIES) @rm -f palisade$(EXEEXT) $(AM_V_CCLD)$(LINK) $(palisade_OBJECTS) $(palisade_LDADD) $(LIBS) ./pattern.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/pattern-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) pattern$(EXEEXT): $(pattern_OBJECTS) $(pattern_DEPENDENCIES) $(EXTRA_pattern_DEPENDENCIES) @rm -f pattern$(EXEEXT) $(AM_V_CCLD)$(LINK) $(pattern_OBJECTS) $(pattern_LDADD) $(LIBS) patternpicture$(EXEEXT): $(patternpicture_OBJECTS) $(patternpicture_DEPENDENCIES) $(EXTRA_patternpicture_DEPENDENCIES) @rm -f patternpicture$(EXEEXT) $(AM_V_CCLD)$(LINK) $(patternpicture_OBJECTS) $(patternpicture_LDADD) $(LIBS) patternsolver$(EXEEXT): $(patternsolver_OBJECTS) $(patternsolver_DEPENDENCIES) $(EXTRA_patternsolver_DEPENDENCIES) @rm -f patternsolver$(EXEEXT) $(AM_V_CCLD)$(LINK) $(patternsolver_OBJECTS) $(patternsolver_LDADD) $(LIBS) ./pearl.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) ./tdq.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/pearl-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) pearl$(EXEEXT): $(pearl_OBJECTS) $(pearl_DEPENDENCIES) $(EXTRA_pearl_DEPENDENCIES) @rm -f pearl$(EXEEXT) $(AM_V_CCLD)$(LINK) $(pearl_OBJECTS) $(pearl_LDADD) $(LIBS) pearlbench$(EXEEXT): $(pearlbench_OBJECTS) $(pearlbench_DEPENDENCIES) $(EXTRA_pearlbench_DEPENDENCIES) @rm -f pearlbench$(EXEEXT) $(AM_V_CCLD)$(LINK) $(pearlbench_OBJECTS) $(pearlbench_LDADD) $(LIBS) ./pegs.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/pegs-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) pegs$(EXEEXT): $(pegs_OBJECTS) $(pegs_DEPENDENCIES) $(EXTRA_pegs_DEPENDENCIES) @rm -f pegs$(EXEEXT) $(AM_V_CCLD)$(LINK) $(pegs_OBJECTS) $(pegs_LDADD) $(LIBS) ./range.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/range-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) range$(EXEEXT): $(range_OBJECTS) $(range_DEPENDENCIES) $(EXTRA_range_DEPENDENCIES) @rm -f range$(EXEEXT) $(AM_V_CCLD)$(LINK) $(range_OBJECTS) $(range_LDADD) $(LIBS) ./rect.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/rect-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) rect$(EXEEXT): $(rect_OBJECTS) $(rect_DEPENDENCIES) $(EXTRA_rect_DEPENDENCIES) @rm -f rect$(EXEEXT) $(AM_V_CCLD)$(LINK) $(rect_OBJECTS) $(rect_LDADD) $(LIBS) ./samegame.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/samegame-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) samegame$(EXEEXT): $(samegame_OBJECTS) $(samegame_DEPENDENCIES) $(EXTRA_samegame_DEPENDENCIES) @rm -f samegame$(EXEEXT) $(AM_V_CCLD)$(LINK) $(samegame_OBJECTS) $(samegame_LDADD) $(LIBS) ./signpost.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/signpost-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) signpost$(EXEEXT): $(signpost_OBJECTS) $(signpost_DEPENDENCIES) $(EXTRA_signpost_DEPENDENCIES) @rm -f signpost$(EXEEXT) $(AM_V_CCLD)$(LINK) $(signpost_OBJECTS) $(signpost_LDADD) $(LIBS) signpostsolver$(EXEEXT): $(signpostsolver_OBJECTS) $(signpostsolver_DEPENDENCIES) $(EXTRA_signpostsolver_DEPENDENCIES) @rm -f signpostsolver$(EXEEXT) $(AM_V_CCLD)$(LINK) $(signpostsolver_OBJECTS) $(signpostsolver_LDADD) $(LIBS) ./singles.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/singles-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) singles$(EXEEXT): $(singles_OBJECTS) $(singles_DEPENDENCIES) $(EXTRA_singles_DEPENDENCIES) @rm -f singles$(EXEEXT) $(AM_V_CCLD)$(LINK) $(singles_OBJECTS) $(singles_LDADD) $(LIBS) singlessolver$(EXEEXT): $(singlessolver_OBJECTS) $(singlessolver_DEPENDENCIES) $(EXTRA_singlessolver_DEPENDENCIES) @rm -f singlessolver$(EXEEXT) $(AM_V_CCLD)$(LINK) $(singlessolver_OBJECTS) $(singlessolver_LDADD) $(LIBS) ./sixteen.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/sixteen-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) sixteen$(EXEEXT): $(sixteen_OBJECTS) $(sixteen_DEPENDENCIES) $(EXTRA_sixteen_DEPENDENCIES) @rm -f sixteen$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sixteen_OBJECTS) $(sixteen_LDADD) $(LIBS) ./slant.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/slant-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) slant$(EXEEXT): $(slant_OBJECTS) $(slant_DEPENDENCIES) $(EXTRA_slant_DEPENDENCIES) @rm -f slant$(EXEEXT) $(AM_V_CCLD)$(LINK) $(slant_OBJECTS) $(slant_LDADD) $(LIBS) slantsolver$(EXEEXT): $(slantsolver_OBJECTS) $(slantsolver_DEPENDENCIES) $(EXTRA_slantsolver_DEPENDENCIES) @rm -f slantsolver$(EXEEXT) $(AM_V_CCLD)$(LINK) $(slantsolver_OBJECTS) $(slantsolver_LDADD) $(LIBS) ./solo.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/solo-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) solo$(EXEEXT): $(solo_OBJECTS) $(solo_DEPENDENCIES) $(EXTRA_solo_DEPENDENCIES) @rm -f solo$(EXEEXT) $(AM_V_CCLD)$(LINK) $(solo_OBJECTS) $(solo_LDADD) $(LIBS) solosolver$(EXEEXT): $(solosolver_OBJECTS) $(solosolver_DEPENDENCIES) $(EXTRA_solosolver_DEPENDENCIES) @rm -f solosolver$(EXEEXT) $(AM_V_CCLD)$(LINK) $(solosolver_OBJECTS) $(solosolver_LDADD) $(LIBS) ./tents.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/tents-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) tents$(EXEEXT): $(tents_OBJECTS) $(tents_DEPENDENCIES) $(EXTRA_tents_DEPENDENCIES) @rm -f tents$(EXEEXT) $(AM_V_CCLD)$(LINK) $(tents_OBJECTS) $(tents_LDADD) $(LIBS) tentssolver$(EXEEXT): $(tentssolver_OBJECTS) $(tentssolver_DEPENDENCIES) $(EXTRA_tentssolver_DEPENDENCIES) @rm -f tentssolver$(EXEEXT) $(AM_V_CCLD)$(LINK) $(tentssolver_OBJECTS) $(tentssolver_LDADD) $(LIBS) ./towers.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/towers-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) towers$(EXEEXT): $(towers_OBJECTS) $(towers_DEPENDENCIES) $(EXTRA_towers_DEPENDENCIES) @rm -f towers$(EXEEXT) $(AM_V_CCLD)$(LINK) $(towers_OBJECTS) $(towers_LDADD) $(LIBS) towerssolver$(EXEEXT): $(towerssolver_OBJECTS) $(towerssolver_DEPENDENCIES) $(EXTRA_towerssolver_DEPENDENCIES) @rm -f towerssolver$(EXEEXT) $(AM_V_CCLD)$(LINK) $(towerssolver_OBJECTS) $(towerssolver_LDADD) $(LIBS) ./tracks.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/tracks-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) tracks$(EXEEXT): $(tracks_OBJECTS) $(tracks_DEPENDENCIES) $(EXTRA_tracks_DEPENDENCIES) @rm -f tracks$(EXEEXT) $(AM_V_CCLD)$(LINK) $(tracks_OBJECTS) $(tracks_LDADD) $(LIBS) ./twiddle.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/twiddle-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) twiddle$(EXEEXT): $(twiddle_OBJECTS) $(twiddle_DEPENDENCIES) $(EXTRA_twiddle_DEPENDENCIES) @rm -f twiddle$(EXEEXT) $(AM_V_CCLD)$(LINK) $(twiddle_OBJECTS) $(twiddle_LDADD) $(LIBS) ./undead.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/undead-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) undead$(EXEEXT): $(undead_OBJECTS) $(undead_DEPENDENCIES) $(EXTRA_undead_DEPENDENCIES) @rm -f undead$(EXEEXT) $(AM_V_CCLD)$(LINK) $(undead_OBJECTS) $(undead_LDADD) $(LIBS) ./unequal.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/unequal-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) unequal$(EXEEXT): $(unequal_OBJECTS) $(unequal_DEPENDENCIES) $(EXTRA_unequal_DEPENDENCIES) @rm -f unequal$(EXEEXT) $(AM_V_CCLD)$(LINK) $(unequal_OBJECTS) $(unequal_LDADD) $(LIBS) unequalsolver$(EXEEXT): $(unequalsolver_OBJECTS) $(unequalsolver_DEPENDENCIES) $(EXTRA_unequalsolver_DEPENDENCIES) @rm -f unequalsolver$(EXEEXT) $(AM_V_CCLD)$(LINK) $(unequalsolver_OBJECTS) $(unequalsolver_LDADD) $(LIBS) ./unruly.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/unruly-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) unruly$(EXEEXT): $(unruly_OBJECTS) $(unruly_DEPENDENCIES) $(EXTRA_unruly_DEPENDENCIES) @rm -f unruly$(EXEEXT) $(AM_V_CCLD)$(LINK) $(unruly_OBJECTS) $(unruly_LDADD) $(LIBS) unrulysolver$(EXEEXT): $(unrulysolver_OBJECTS) $(unrulysolver_DEPENDENCIES) $(EXTRA_unrulysolver_DEPENDENCIES) @rm -f unrulysolver$(EXEEXT) $(AM_V_CCLD)$(LINK) $(unrulysolver_OBJECTS) $(unrulysolver_LDADD) $(LIBS) ./untangle.$(OBJEXT): ./$(am__dirstamp) $(DEPDIR)/$(am__dirstamp) icons/untangle-icon.$(OBJEXT): icons/$(am__dirstamp) \ icons/$(DEPDIR)/$(am__dirstamp) untangle$(EXEEXT): $(untangle_OBJECTS) $(untangle_DEPENDENCIES) $(EXTRA_untangle_DEPENDENCIES) @rm -f untangle$(EXEEXT) $(AM_V_CCLD)$(LINK) $(untangle_OBJECTS) $(untangle_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f ./*.$(OBJEXT) -rm -f icons/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/blackbox.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bridges.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/combi.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cube.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/divvy.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dominosa.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/drawing.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dsf.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fifteen.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filling.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/findloop.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flip.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flood.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/galaxies.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/grid.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gtk.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/guess.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/inertia.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/keen.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/latin.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/laydomino.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libfifteen2_a-fifteen.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libfilling2_a-filling.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgalaxie2_a-galaxies.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgalaxie4_a-galaxies.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkeen2_a-keen.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblatin6_a-latin.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblatin8_a-latin.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblightup2_a-lightup.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libloopy2_a-loopy.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmagnets2_a-magnets.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmap2_a-map.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmines2_a-mines.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpattern2_a-pattern.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpattern4_a-pattern.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpearl2_a-pearl.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsignpos2_a-signpost.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsingles3_a-singles.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libslant2_a-slant.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsolo2_a-solo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtents3_a-tents.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtowers2_a-towers.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libunequal2_a-unequal.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libunruly2_a-unruly.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lightup.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/loopgen.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/loopy.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/magnets.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/malloc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/map.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/maxflow.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/midend.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mines.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/misc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/net.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/netslide.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/no-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nullfe.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nullgame.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/obfusc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/palisade.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pattern.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pearl.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pegs.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/penrose.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/printing.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ps.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/random.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/range.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rect.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/samegame.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/signpost.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/singles.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sixteen.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/slant.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/solo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tdq.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tents.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/towers.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tracks.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tree234.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/twiddle.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/undead.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unequal.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unruly.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/untangle.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/version.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/blackbox-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/bridges-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/cube-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/dominosa-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/fifteen-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/filling-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/flip-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/flood-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/galaxies-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/guess-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/inertia-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/keen-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/lightup-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/loopy-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/magnets-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/map-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/mines-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/net-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/netslide-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/palisade-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/pattern-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/pearl-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/pegs-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/range-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/rect-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/samegame-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/signpost-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/singles-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/sixteen-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/slant-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/solo-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/tents-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/towers-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/tracks-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/twiddle-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/undead-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/unequal-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/unruly-icon.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@icons/$(DEPDIR)/untangle-icon.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.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)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.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) '$<'` ./libfifteen2_a-fifteen.o: ./fifteen.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfifteen2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libfifteen2_a-fifteen.o -MD -MP -MF $(DEPDIR)/libfifteen2_a-fifteen.Tpo -c -o ./libfifteen2_a-fifteen.o `test -f './fifteen.c' || echo '$(srcdir)/'`./fifteen.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libfifteen2_a-fifteen.Tpo $(DEPDIR)/libfifteen2_a-fifteen.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./fifteen.c' object='./libfifteen2_a-fifteen.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) $(libfifteen2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libfifteen2_a-fifteen.o `test -f './fifteen.c' || echo '$(srcdir)/'`./fifteen.c ./libfifteen2_a-fifteen.obj: ./fifteen.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfifteen2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libfifteen2_a-fifteen.obj -MD -MP -MF $(DEPDIR)/libfifteen2_a-fifteen.Tpo -c -o ./libfifteen2_a-fifteen.obj `if test -f './fifteen.c'; then $(CYGPATH_W) './fifteen.c'; else $(CYGPATH_W) '$(srcdir)/./fifteen.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libfifteen2_a-fifteen.Tpo $(DEPDIR)/libfifteen2_a-fifteen.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./fifteen.c' object='./libfifteen2_a-fifteen.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) $(libfifteen2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libfifteen2_a-fifteen.obj `if test -f './fifteen.c'; then $(CYGPATH_W) './fifteen.c'; else $(CYGPATH_W) '$(srcdir)/./fifteen.c'; fi` ./libfilling2_a-filling.o: ./filling.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfilling2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libfilling2_a-filling.o -MD -MP -MF $(DEPDIR)/libfilling2_a-filling.Tpo -c -o ./libfilling2_a-filling.o `test -f './filling.c' || echo '$(srcdir)/'`./filling.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libfilling2_a-filling.Tpo $(DEPDIR)/libfilling2_a-filling.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./filling.c' object='./libfilling2_a-filling.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) $(libfilling2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libfilling2_a-filling.o `test -f './filling.c' || echo '$(srcdir)/'`./filling.c ./libfilling2_a-filling.obj: ./filling.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfilling2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libfilling2_a-filling.obj -MD -MP -MF $(DEPDIR)/libfilling2_a-filling.Tpo -c -o ./libfilling2_a-filling.obj `if test -f './filling.c'; then $(CYGPATH_W) './filling.c'; else $(CYGPATH_W) '$(srcdir)/./filling.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libfilling2_a-filling.Tpo $(DEPDIR)/libfilling2_a-filling.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./filling.c' object='./libfilling2_a-filling.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) $(libfilling2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libfilling2_a-filling.obj `if test -f './filling.c'; then $(CYGPATH_W) './filling.c'; else $(CYGPATH_W) '$(srcdir)/./filling.c'; fi` ./libgalaxie2_a-galaxies.o: ./galaxies.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgalaxie2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libgalaxie2_a-galaxies.o -MD -MP -MF $(DEPDIR)/libgalaxie2_a-galaxies.Tpo -c -o ./libgalaxie2_a-galaxies.o `test -f './galaxies.c' || echo '$(srcdir)/'`./galaxies.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgalaxie2_a-galaxies.Tpo $(DEPDIR)/libgalaxie2_a-galaxies.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./galaxies.c' object='./libgalaxie2_a-galaxies.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) $(libgalaxie2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libgalaxie2_a-galaxies.o `test -f './galaxies.c' || echo '$(srcdir)/'`./galaxies.c ./libgalaxie2_a-galaxies.obj: ./galaxies.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgalaxie2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libgalaxie2_a-galaxies.obj -MD -MP -MF $(DEPDIR)/libgalaxie2_a-galaxies.Tpo -c -o ./libgalaxie2_a-galaxies.obj `if test -f './galaxies.c'; then $(CYGPATH_W) './galaxies.c'; else $(CYGPATH_W) '$(srcdir)/./galaxies.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgalaxie2_a-galaxies.Tpo $(DEPDIR)/libgalaxie2_a-galaxies.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./galaxies.c' object='./libgalaxie2_a-galaxies.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) $(libgalaxie2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libgalaxie2_a-galaxies.obj `if test -f './galaxies.c'; then $(CYGPATH_W) './galaxies.c'; else $(CYGPATH_W) '$(srcdir)/./galaxies.c'; fi` ./libgalaxie4_a-galaxies.o: ./galaxies.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgalaxie4_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libgalaxie4_a-galaxies.o -MD -MP -MF $(DEPDIR)/libgalaxie4_a-galaxies.Tpo -c -o ./libgalaxie4_a-galaxies.o `test -f './galaxies.c' || echo '$(srcdir)/'`./galaxies.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgalaxie4_a-galaxies.Tpo $(DEPDIR)/libgalaxie4_a-galaxies.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./galaxies.c' object='./libgalaxie4_a-galaxies.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) $(libgalaxie4_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libgalaxie4_a-galaxies.o `test -f './galaxies.c' || echo '$(srcdir)/'`./galaxies.c ./libgalaxie4_a-galaxies.obj: ./galaxies.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgalaxie4_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libgalaxie4_a-galaxies.obj -MD -MP -MF $(DEPDIR)/libgalaxie4_a-galaxies.Tpo -c -o ./libgalaxie4_a-galaxies.obj `if test -f './galaxies.c'; then $(CYGPATH_W) './galaxies.c'; else $(CYGPATH_W) '$(srcdir)/./galaxies.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgalaxie4_a-galaxies.Tpo $(DEPDIR)/libgalaxie4_a-galaxies.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./galaxies.c' object='./libgalaxie4_a-galaxies.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) $(libgalaxie4_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libgalaxie4_a-galaxies.obj `if test -f './galaxies.c'; then $(CYGPATH_W) './galaxies.c'; else $(CYGPATH_W) '$(srcdir)/./galaxies.c'; fi` ./libkeen2_a-keen.o: ./keen.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkeen2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libkeen2_a-keen.o -MD -MP -MF $(DEPDIR)/libkeen2_a-keen.Tpo -c -o ./libkeen2_a-keen.o `test -f './keen.c' || echo '$(srcdir)/'`./keen.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkeen2_a-keen.Tpo $(DEPDIR)/libkeen2_a-keen.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./keen.c' object='./libkeen2_a-keen.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) $(libkeen2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libkeen2_a-keen.o `test -f './keen.c' || echo '$(srcdir)/'`./keen.c ./libkeen2_a-keen.obj: ./keen.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkeen2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libkeen2_a-keen.obj -MD -MP -MF $(DEPDIR)/libkeen2_a-keen.Tpo -c -o ./libkeen2_a-keen.obj `if test -f './keen.c'; then $(CYGPATH_W) './keen.c'; else $(CYGPATH_W) '$(srcdir)/./keen.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkeen2_a-keen.Tpo $(DEPDIR)/libkeen2_a-keen.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./keen.c' object='./libkeen2_a-keen.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) $(libkeen2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libkeen2_a-keen.obj `if test -f './keen.c'; then $(CYGPATH_W) './keen.c'; else $(CYGPATH_W) '$(srcdir)/./keen.c'; fi` ./liblatin6_a-latin.o: ./latin.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblatin6_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./liblatin6_a-latin.o -MD -MP -MF $(DEPDIR)/liblatin6_a-latin.Tpo -c -o ./liblatin6_a-latin.o `test -f './latin.c' || echo '$(srcdir)/'`./latin.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblatin6_a-latin.Tpo $(DEPDIR)/liblatin6_a-latin.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./latin.c' object='./liblatin6_a-latin.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) $(liblatin6_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./liblatin6_a-latin.o `test -f './latin.c' || echo '$(srcdir)/'`./latin.c ./liblatin6_a-latin.obj: ./latin.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblatin6_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./liblatin6_a-latin.obj -MD -MP -MF $(DEPDIR)/liblatin6_a-latin.Tpo -c -o ./liblatin6_a-latin.obj `if test -f './latin.c'; then $(CYGPATH_W) './latin.c'; else $(CYGPATH_W) '$(srcdir)/./latin.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblatin6_a-latin.Tpo $(DEPDIR)/liblatin6_a-latin.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./latin.c' object='./liblatin6_a-latin.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) $(liblatin6_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./liblatin6_a-latin.obj `if test -f './latin.c'; then $(CYGPATH_W) './latin.c'; else $(CYGPATH_W) '$(srcdir)/./latin.c'; fi` ./liblatin8_a-latin.o: ./latin.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblatin8_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./liblatin8_a-latin.o -MD -MP -MF $(DEPDIR)/liblatin8_a-latin.Tpo -c -o ./liblatin8_a-latin.o `test -f './latin.c' || echo '$(srcdir)/'`./latin.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblatin8_a-latin.Tpo $(DEPDIR)/liblatin8_a-latin.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./latin.c' object='./liblatin8_a-latin.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) $(liblatin8_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./liblatin8_a-latin.o `test -f './latin.c' || echo '$(srcdir)/'`./latin.c ./liblatin8_a-latin.obj: ./latin.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblatin8_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./liblatin8_a-latin.obj -MD -MP -MF $(DEPDIR)/liblatin8_a-latin.Tpo -c -o ./liblatin8_a-latin.obj `if test -f './latin.c'; then $(CYGPATH_W) './latin.c'; else $(CYGPATH_W) '$(srcdir)/./latin.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblatin8_a-latin.Tpo $(DEPDIR)/liblatin8_a-latin.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./latin.c' object='./liblatin8_a-latin.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) $(liblatin8_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./liblatin8_a-latin.obj `if test -f './latin.c'; then $(CYGPATH_W) './latin.c'; else $(CYGPATH_W) '$(srcdir)/./latin.c'; fi` ./liblightup2_a-lightup.o: ./lightup.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblightup2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./liblightup2_a-lightup.o -MD -MP -MF $(DEPDIR)/liblightup2_a-lightup.Tpo -c -o ./liblightup2_a-lightup.o `test -f './lightup.c' || echo '$(srcdir)/'`./lightup.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightup2_a-lightup.Tpo $(DEPDIR)/liblightup2_a-lightup.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./lightup.c' object='./liblightup2_a-lightup.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) $(liblightup2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./liblightup2_a-lightup.o `test -f './lightup.c' || echo '$(srcdir)/'`./lightup.c ./liblightup2_a-lightup.obj: ./lightup.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblightup2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./liblightup2_a-lightup.obj -MD -MP -MF $(DEPDIR)/liblightup2_a-lightup.Tpo -c -o ./liblightup2_a-lightup.obj `if test -f './lightup.c'; then $(CYGPATH_W) './lightup.c'; else $(CYGPATH_W) '$(srcdir)/./lightup.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblightup2_a-lightup.Tpo $(DEPDIR)/liblightup2_a-lightup.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./lightup.c' object='./liblightup2_a-lightup.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) $(liblightup2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./liblightup2_a-lightup.obj `if test -f './lightup.c'; then $(CYGPATH_W) './lightup.c'; else $(CYGPATH_W) '$(srcdir)/./lightup.c'; fi` ./libloopy2_a-loopy.o: ./loopy.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libloopy2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libloopy2_a-loopy.o -MD -MP -MF $(DEPDIR)/libloopy2_a-loopy.Tpo -c -o ./libloopy2_a-loopy.o `test -f './loopy.c' || echo '$(srcdir)/'`./loopy.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libloopy2_a-loopy.Tpo $(DEPDIR)/libloopy2_a-loopy.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./loopy.c' object='./libloopy2_a-loopy.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) $(libloopy2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libloopy2_a-loopy.o `test -f './loopy.c' || echo '$(srcdir)/'`./loopy.c ./libloopy2_a-loopy.obj: ./loopy.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libloopy2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libloopy2_a-loopy.obj -MD -MP -MF $(DEPDIR)/libloopy2_a-loopy.Tpo -c -o ./libloopy2_a-loopy.obj `if test -f './loopy.c'; then $(CYGPATH_W) './loopy.c'; else $(CYGPATH_W) '$(srcdir)/./loopy.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libloopy2_a-loopy.Tpo $(DEPDIR)/libloopy2_a-loopy.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./loopy.c' object='./libloopy2_a-loopy.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) $(libloopy2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libloopy2_a-loopy.obj `if test -f './loopy.c'; then $(CYGPATH_W) './loopy.c'; else $(CYGPATH_W) '$(srcdir)/./loopy.c'; fi` ./libmagnets2_a-magnets.o: ./magnets.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmagnets2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libmagnets2_a-magnets.o -MD -MP -MF $(DEPDIR)/libmagnets2_a-magnets.Tpo -c -o ./libmagnets2_a-magnets.o `test -f './magnets.c' || echo '$(srcdir)/'`./magnets.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmagnets2_a-magnets.Tpo $(DEPDIR)/libmagnets2_a-magnets.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./magnets.c' object='./libmagnets2_a-magnets.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) $(libmagnets2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libmagnets2_a-magnets.o `test -f './magnets.c' || echo '$(srcdir)/'`./magnets.c ./libmagnets2_a-magnets.obj: ./magnets.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmagnets2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libmagnets2_a-magnets.obj -MD -MP -MF $(DEPDIR)/libmagnets2_a-magnets.Tpo -c -o ./libmagnets2_a-magnets.obj `if test -f './magnets.c'; then $(CYGPATH_W) './magnets.c'; else $(CYGPATH_W) '$(srcdir)/./magnets.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmagnets2_a-magnets.Tpo $(DEPDIR)/libmagnets2_a-magnets.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./magnets.c' object='./libmagnets2_a-magnets.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) $(libmagnets2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libmagnets2_a-magnets.obj `if test -f './magnets.c'; then $(CYGPATH_W) './magnets.c'; else $(CYGPATH_W) '$(srcdir)/./magnets.c'; fi` ./libmap2_a-map.o: ./map.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmap2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libmap2_a-map.o -MD -MP -MF $(DEPDIR)/libmap2_a-map.Tpo -c -o ./libmap2_a-map.o `test -f './map.c' || echo '$(srcdir)/'`./map.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmap2_a-map.Tpo $(DEPDIR)/libmap2_a-map.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./map.c' object='./libmap2_a-map.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) $(libmap2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libmap2_a-map.o `test -f './map.c' || echo '$(srcdir)/'`./map.c ./libmap2_a-map.obj: ./map.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmap2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libmap2_a-map.obj -MD -MP -MF $(DEPDIR)/libmap2_a-map.Tpo -c -o ./libmap2_a-map.obj `if test -f './map.c'; then $(CYGPATH_W) './map.c'; else $(CYGPATH_W) '$(srcdir)/./map.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmap2_a-map.Tpo $(DEPDIR)/libmap2_a-map.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./map.c' object='./libmap2_a-map.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) $(libmap2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libmap2_a-map.obj `if test -f './map.c'; then $(CYGPATH_W) './map.c'; else $(CYGPATH_W) '$(srcdir)/./map.c'; fi` ./libmines2_a-mines.o: ./mines.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmines2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libmines2_a-mines.o -MD -MP -MF $(DEPDIR)/libmines2_a-mines.Tpo -c -o ./libmines2_a-mines.o `test -f './mines.c' || echo '$(srcdir)/'`./mines.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmines2_a-mines.Tpo $(DEPDIR)/libmines2_a-mines.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./mines.c' object='./libmines2_a-mines.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) $(libmines2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libmines2_a-mines.o `test -f './mines.c' || echo '$(srcdir)/'`./mines.c ./libmines2_a-mines.obj: ./mines.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmines2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libmines2_a-mines.obj -MD -MP -MF $(DEPDIR)/libmines2_a-mines.Tpo -c -o ./libmines2_a-mines.obj `if test -f './mines.c'; then $(CYGPATH_W) './mines.c'; else $(CYGPATH_W) '$(srcdir)/./mines.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmines2_a-mines.Tpo $(DEPDIR)/libmines2_a-mines.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./mines.c' object='./libmines2_a-mines.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) $(libmines2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libmines2_a-mines.obj `if test -f './mines.c'; then $(CYGPATH_W) './mines.c'; else $(CYGPATH_W) '$(srcdir)/./mines.c'; fi` ./libpattern2_a-pattern.o: ./pattern.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpattern2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libpattern2_a-pattern.o -MD -MP -MF $(DEPDIR)/libpattern2_a-pattern.Tpo -c -o ./libpattern2_a-pattern.o `test -f './pattern.c' || echo '$(srcdir)/'`./pattern.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpattern2_a-pattern.Tpo $(DEPDIR)/libpattern2_a-pattern.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./pattern.c' object='./libpattern2_a-pattern.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) $(libpattern2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libpattern2_a-pattern.o `test -f './pattern.c' || echo '$(srcdir)/'`./pattern.c ./libpattern2_a-pattern.obj: ./pattern.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpattern2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libpattern2_a-pattern.obj -MD -MP -MF $(DEPDIR)/libpattern2_a-pattern.Tpo -c -o ./libpattern2_a-pattern.obj `if test -f './pattern.c'; then $(CYGPATH_W) './pattern.c'; else $(CYGPATH_W) '$(srcdir)/./pattern.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpattern2_a-pattern.Tpo $(DEPDIR)/libpattern2_a-pattern.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./pattern.c' object='./libpattern2_a-pattern.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) $(libpattern2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libpattern2_a-pattern.obj `if test -f './pattern.c'; then $(CYGPATH_W) './pattern.c'; else $(CYGPATH_W) '$(srcdir)/./pattern.c'; fi` ./libpattern4_a-pattern.o: ./pattern.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpattern4_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libpattern4_a-pattern.o -MD -MP -MF $(DEPDIR)/libpattern4_a-pattern.Tpo -c -o ./libpattern4_a-pattern.o `test -f './pattern.c' || echo '$(srcdir)/'`./pattern.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpattern4_a-pattern.Tpo $(DEPDIR)/libpattern4_a-pattern.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./pattern.c' object='./libpattern4_a-pattern.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) $(libpattern4_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libpattern4_a-pattern.o `test -f './pattern.c' || echo '$(srcdir)/'`./pattern.c ./libpattern4_a-pattern.obj: ./pattern.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpattern4_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libpattern4_a-pattern.obj -MD -MP -MF $(DEPDIR)/libpattern4_a-pattern.Tpo -c -o ./libpattern4_a-pattern.obj `if test -f './pattern.c'; then $(CYGPATH_W) './pattern.c'; else $(CYGPATH_W) '$(srcdir)/./pattern.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpattern4_a-pattern.Tpo $(DEPDIR)/libpattern4_a-pattern.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./pattern.c' object='./libpattern4_a-pattern.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) $(libpattern4_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libpattern4_a-pattern.obj `if test -f './pattern.c'; then $(CYGPATH_W) './pattern.c'; else $(CYGPATH_W) '$(srcdir)/./pattern.c'; fi` ./libpearl2_a-pearl.o: ./pearl.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpearl2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libpearl2_a-pearl.o -MD -MP -MF $(DEPDIR)/libpearl2_a-pearl.Tpo -c -o ./libpearl2_a-pearl.o `test -f './pearl.c' || echo '$(srcdir)/'`./pearl.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpearl2_a-pearl.Tpo $(DEPDIR)/libpearl2_a-pearl.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./pearl.c' object='./libpearl2_a-pearl.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) $(libpearl2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libpearl2_a-pearl.o `test -f './pearl.c' || echo '$(srcdir)/'`./pearl.c ./libpearl2_a-pearl.obj: ./pearl.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpearl2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libpearl2_a-pearl.obj -MD -MP -MF $(DEPDIR)/libpearl2_a-pearl.Tpo -c -o ./libpearl2_a-pearl.obj `if test -f './pearl.c'; then $(CYGPATH_W) './pearl.c'; else $(CYGPATH_W) '$(srcdir)/./pearl.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpearl2_a-pearl.Tpo $(DEPDIR)/libpearl2_a-pearl.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./pearl.c' object='./libpearl2_a-pearl.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) $(libpearl2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libpearl2_a-pearl.obj `if test -f './pearl.c'; then $(CYGPATH_W) './pearl.c'; else $(CYGPATH_W) '$(srcdir)/./pearl.c'; fi` ./libsignpos2_a-signpost.o: ./signpost.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsignpos2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libsignpos2_a-signpost.o -MD -MP -MF $(DEPDIR)/libsignpos2_a-signpost.Tpo -c -o ./libsignpos2_a-signpost.o `test -f './signpost.c' || echo '$(srcdir)/'`./signpost.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsignpos2_a-signpost.Tpo $(DEPDIR)/libsignpos2_a-signpost.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./signpost.c' object='./libsignpos2_a-signpost.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) $(libsignpos2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libsignpos2_a-signpost.o `test -f './signpost.c' || echo '$(srcdir)/'`./signpost.c ./libsignpos2_a-signpost.obj: ./signpost.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsignpos2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libsignpos2_a-signpost.obj -MD -MP -MF $(DEPDIR)/libsignpos2_a-signpost.Tpo -c -o ./libsignpos2_a-signpost.obj `if test -f './signpost.c'; then $(CYGPATH_W) './signpost.c'; else $(CYGPATH_W) '$(srcdir)/./signpost.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsignpos2_a-signpost.Tpo $(DEPDIR)/libsignpos2_a-signpost.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./signpost.c' object='./libsignpos2_a-signpost.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) $(libsignpos2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libsignpos2_a-signpost.obj `if test -f './signpost.c'; then $(CYGPATH_W) './signpost.c'; else $(CYGPATH_W) '$(srcdir)/./signpost.c'; fi` ./libsingles3_a-singles.o: ./singles.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsingles3_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libsingles3_a-singles.o -MD -MP -MF $(DEPDIR)/libsingles3_a-singles.Tpo -c -o ./libsingles3_a-singles.o `test -f './singles.c' || echo '$(srcdir)/'`./singles.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsingles3_a-singles.Tpo $(DEPDIR)/libsingles3_a-singles.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./singles.c' object='./libsingles3_a-singles.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) $(libsingles3_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libsingles3_a-singles.o `test -f './singles.c' || echo '$(srcdir)/'`./singles.c ./libsingles3_a-singles.obj: ./singles.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsingles3_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libsingles3_a-singles.obj -MD -MP -MF $(DEPDIR)/libsingles3_a-singles.Tpo -c -o ./libsingles3_a-singles.obj `if test -f './singles.c'; then $(CYGPATH_W) './singles.c'; else $(CYGPATH_W) '$(srcdir)/./singles.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsingles3_a-singles.Tpo $(DEPDIR)/libsingles3_a-singles.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./singles.c' object='./libsingles3_a-singles.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) $(libsingles3_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libsingles3_a-singles.obj `if test -f './singles.c'; then $(CYGPATH_W) './singles.c'; else $(CYGPATH_W) '$(srcdir)/./singles.c'; fi` ./libslant2_a-slant.o: ./slant.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libslant2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libslant2_a-slant.o -MD -MP -MF $(DEPDIR)/libslant2_a-slant.Tpo -c -o ./libslant2_a-slant.o `test -f './slant.c' || echo '$(srcdir)/'`./slant.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libslant2_a-slant.Tpo $(DEPDIR)/libslant2_a-slant.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./slant.c' object='./libslant2_a-slant.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) $(libslant2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libslant2_a-slant.o `test -f './slant.c' || echo '$(srcdir)/'`./slant.c ./libslant2_a-slant.obj: ./slant.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libslant2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libslant2_a-slant.obj -MD -MP -MF $(DEPDIR)/libslant2_a-slant.Tpo -c -o ./libslant2_a-slant.obj `if test -f './slant.c'; then $(CYGPATH_W) './slant.c'; else $(CYGPATH_W) '$(srcdir)/./slant.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libslant2_a-slant.Tpo $(DEPDIR)/libslant2_a-slant.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./slant.c' object='./libslant2_a-slant.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) $(libslant2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libslant2_a-slant.obj `if test -f './slant.c'; then $(CYGPATH_W) './slant.c'; else $(CYGPATH_W) '$(srcdir)/./slant.c'; fi` ./libsolo2_a-solo.o: ./solo.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsolo2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libsolo2_a-solo.o -MD -MP -MF $(DEPDIR)/libsolo2_a-solo.Tpo -c -o ./libsolo2_a-solo.o `test -f './solo.c' || echo '$(srcdir)/'`./solo.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsolo2_a-solo.Tpo $(DEPDIR)/libsolo2_a-solo.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./solo.c' object='./libsolo2_a-solo.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) $(libsolo2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libsolo2_a-solo.o `test -f './solo.c' || echo '$(srcdir)/'`./solo.c ./libsolo2_a-solo.obj: ./solo.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsolo2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libsolo2_a-solo.obj -MD -MP -MF $(DEPDIR)/libsolo2_a-solo.Tpo -c -o ./libsolo2_a-solo.obj `if test -f './solo.c'; then $(CYGPATH_W) './solo.c'; else $(CYGPATH_W) '$(srcdir)/./solo.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsolo2_a-solo.Tpo $(DEPDIR)/libsolo2_a-solo.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./solo.c' object='./libsolo2_a-solo.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) $(libsolo2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libsolo2_a-solo.obj `if test -f './solo.c'; then $(CYGPATH_W) './solo.c'; else $(CYGPATH_W) '$(srcdir)/./solo.c'; fi` ./libtents3_a-tents.o: ./tents.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtents3_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libtents3_a-tents.o -MD -MP -MF $(DEPDIR)/libtents3_a-tents.Tpo -c -o ./libtents3_a-tents.o `test -f './tents.c' || echo '$(srcdir)/'`./tents.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtents3_a-tents.Tpo $(DEPDIR)/libtents3_a-tents.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./tents.c' object='./libtents3_a-tents.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) $(libtents3_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libtents3_a-tents.o `test -f './tents.c' || echo '$(srcdir)/'`./tents.c ./libtents3_a-tents.obj: ./tents.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtents3_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libtents3_a-tents.obj -MD -MP -MF $(DEPDIR)/libtents3_a-tents.Tpo -c -o ./libtents3_a-tents.obj `if test -f './tents.c'; then $(CYGPATH_W) './tents.c'; else $(CYGPATH_W) '$(srcdir)/./tents.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtents3_a-tents.Tpo $(DEPDIR)/libtents3_a-tents.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./tents.c' object='./libtents3_a-tents.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) $(libtents3_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libtents3_a-tents.obj `if test -f './tents.c'; then $(CYGPATH_W) './tents.c'; else $(CYGPATH_W) '$(srcdir)/./tents.c'; fi` ./libtowers2_a-towers.o: ./towers.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtowers2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libtowers2_a-towers.o -MD -MP -MF $(DEPDIR)/libtowers2_a-towers.Tpo -c -o ./libtowers2_a-towers.o `test -f './towers.c' || echo '$(srcdir)/'`./towers.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtowers2_a-towers.Tpo $(DEPDIR)/libtowers2_a-towers.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./towers.c' object='./libtowers2_a-towers.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) $(libtowers2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libtowers2_a-towers.o `test -f './towers.c' || echo '$(srcdir)/'`./towers.c ./libtowers2_a-towers.obj: ./towers.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtowers2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libtowers2_a-towers.obj -MD -MP -MF $(DEPDIR)/libtowers2_a-towers.Tpo -c -o ./libtowers2_a-towers.obj `if test -f './towers.c'; then $(CYGPATH_W) './towers.c'; else $(CYGPATH_W) '$(srcdir)/./towers.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtowers2_a-towers.Tpo $(DEPDIR)/libtowers2_a-towers.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./towers.c' object='./libtowers2_a-towers.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) $(libtowers2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libtowers2_a-towers.obj `if test -f './towers.c'; then $(CYGPATH_W) './towers.c'; else $(CYGPATH_W) '$(srcdir)/./towers.c'; fi` ./libunequal2_a-unequal.o: ./unequal.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libunequal2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libunequal2_a-unequal.o -MD -MP -MF $(DEPDIR)/libunequal2_a-unequal.Tpo -c -o ./libunequal2_a-unequal.o `test -f './unequal.c' || echo '$(srcdir)/'`./unequal.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libunequal2_a-unequal.Tpo $(DEPDIR)/libunequal2_a-unequal.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./unequal.c' object='./libunequal2_a-unequal.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) $(libunequal2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libunequal2_a-unequal.o `test -f './unequal.c' || echo '$(srcdir)/'`./unequal.c ./libunequal2_a-unequal.obj: ./unequal.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libunequal2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libunequal2_a-unequal.obj -MD -MP -MF $(DEPDIR)/libunequal2_a-unequal.Tpo -c -o ./libunequal2_a-unequal.obj `if test -f './unequal.c'; then $(CYGPATH_W) './unequal.c'; else $(CYGPATH_W) '$(srcdir)/./unequal.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libunequal2_a-unequal.Tpo $(DEPDIR)/libunequal2_a-unequal.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./unequal.c' object='./libunequal2_a-unequal.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) $(libunequal2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libunequal2_a-unequal.obj `if test -f './unequal.c'; then $(CYGPATH_W) './unequal.c'; else $(CYGPATH_W) '$(srcdir)/./unequal.c'; fi` ./libunruly2_a-unruly.o: ./unruly.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libunruly2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libunruly2_a-unruly.o -MD -MP -MF $(DEPDIR)/libunruly2_a-unruly.Tpo -c -o ./libunruly2_a-unruly.o `test -f './unruly.c' || echo '$(srcdir)/'`./unruly.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libunruly2_a-unruly.Tpo $(DEPDIR)/libunruly2_a-unruly.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./unruly.c' object='./libunruly2_a-unruly.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) $(libunruly2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libunruly2_a-unruly.o `test -f './unruly.c' || echo '$(srcdir)/'`./unruly.c ./libunruly2_a-unruly.obj: ./unruly.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libunruly2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT ./libunruly2_a-unruly.obj -MD -MP -MF $(DEPDIR)/libunruly2_a-unruly.Tpo -c -o ./libunruly2_a-unruly.obj `if test -f './unruly.c'; then $(CYGPATH_W) './unruly.c'; else $(CYGPATH_W) '$(srcdir)/./unruly.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libunruly2_a-unruly.Tpo $(DEPDIR)/libunruly2_a-unruly.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='./unruly.c' object='./libunruly2_a-unruly.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) $(libunruly2_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o ./libunruly2_a-unruly.obj `if test -f './unruly.c'; then $(CYGPATH_W) './unruly.c'; else $(CYGPATH_W) '$(srcdir)/./unruly.c'; fi` ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-am TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ $(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-am 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-am 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: $(DISTFILES) $(am__remove_distdir) test -d "$(distdir)" || mkdir "$(distdir)" @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done -test -n "$(am__skip_mode_fix)" \ || find "$(distdir)" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r "$(distdir)" dist-gzip: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -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) | GZIP=$(GZIP_ENV) gzip -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*) \ GZIP=$(GZIP_ENV) gzip -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*) \ GZIP=$(GZIP_ENV) gzip -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-am all-am: Makefile $(LIBRARIES) $(PROGRAMS) installdirs: for dir in "$(DESTDIR)$(bindir)"; 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) -rm -f ./$(am__dirstamp) -rm -f icons/$(DEPDIR)/$(am__dirstamp) -rm -f icons/$(am__dirstamp) -test -z "$(DEPDIR)/$(am__dirstamp)" || rm -f $(DEPDIR)/$(am__dirstamp) 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-binPROGRAMS clean-generic clean-noinstLIBRARIES \ clean-noinstPROGRAMS mostlyclean-am distclean: distclean-am -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf ./$(DEPDIR) icons/$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags 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-binPROGRAMS 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 $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -rf ./$(DEPDIR) icons/$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binPROGRAMS .MAKE: install-am install-strip .PHONY: CTAGS GTAGS TAGS all all-am am--refresh check check-am clean \ clean-binPROGRAMS clean-cscope clean-generic \ clean-noinstLIBRARIES clean-noinstPROGRAMS cscope \ cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \ dist-gzip dist-lzip dist-shar dist-tarZ dist-xz dist-zip \ distcheck distclean distclean-compile distclean-generic \ distclean-tags distcleancheck distdir distuninstallcheck 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 \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-binPROGRAMS .PRECIOUS: Makefile test: benchmark.html benchmark.txt benchmark.html: benchmark.txt benchmark.pl ./benchmark.pl benchmark.txt > $@ benchmark.txt: benchmark.sh $(GAMES) ./benchmark.sh > $@ # 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: puzzles-20170606.272beef/Makefile.gtk0000644000175000017500000011176713115375145016132 0ustar simonsimon# Makefile for puzzles under X/GTK and Unix. # # This file was created by `mkfiles.pl' from the `Recipe' file. # DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead. # You can define this path to point at your tools if you need to # TOOLPATH = /opt/gcc/bin CC := $(TOOLPATH)$(CC) # You can manually set this to `gtk-config' or `pkg-config gtk+-1.2' # (depending on what works on your system) if you want to enforce # building with GTK 1.2, or you can set it to `pkg-config gtk+-2.0' # if you want to enforce 2.0. The default is to try 2.0 and fall back # to 1.2 if it isn't found. GTK_CONFIG = sh -c 'pkg-config gtk+-2.0 $$0 2>/dev/null || gtk-config $$0' CFLAGS := -O2 -Wall -Werror -ansi -pedantic -g -I./ -Iicons/ `$(GTK_CONFIG) \ --cflags` $(CFLAGS) XLIBS = `$(GTK_CONFIG) --libs` -lm ULIBS = -lm# INSTALL=install INSTALL_PROGRAM=$(INSTALL) INSTALL_DATA=$(INSTALL) prefix=/usr/local exec_prefix=$(prefix) bindir=$(exec_prefix)/bin gamesdir=$(exec_prefix)/games mandir=$(prefix)/man man1dir=$(mandir)/man1 all: $(BINPREFIX)blackbox $(BINPREFIX)bridges $(BINPREFIX)cube \ $(BINPREFIX)dominosa $(BINPREFIX)fifteen \ $(BINPREFIX)fifteensolver $(BINPREFIX)filling \ $(BINPREFIX)fillingsolver $(BINPREFIX)flip $(BINPREFIX)flood \ $(BINPREFIX)galaxies $(BINPREFIX)galaxiespicture \ $(BINPREFIX)galaxiessolver $(BINPREFIX)guess \ $(BINPREFIX)inertia $(BINPREFIX)keen $(BINPREFIX)keensolver \ $(BINPREFIX)latincheck $(BINPREFIX)lightup \ $(BINPREFIX)lightupsolver $(BINPREFIX)loopy \ $(BINPREFIX)loopysolver $(BINPREFIX)magnets \ $(BINPREFIX)magnetssolver $(BINPREFIX)map \ $(BINPREFIX)mapsolver $(BINPREFIX)mineobfusc \ $(BINPREFIX)mines $(BINPREFIX)net $(BINPREFIX)netslide \ $(BINPREFIX)nullgame $(BINPREFIX)obfusc $(BINPREFIX)palisade \ $(BINPREFIX)pattern $(BINPREFIX)patternpicture \ $(BINPREFIX)patternsolver $(BINPREFIX)pearl \ $(BINPREFIX)pearlbench $(BINPREFIX)pegs $(BINPREFIX)range \ $(BINPREFIX)rect $(BINPREFIX)samegame $(BINPREFIX)signpost \ $(BINPREFIX)signpostsolver $(BINPREFIX)singles \ $(BINPREFIX)singlessolver $(BINPREFIX)sixteen \ $(BINPREFIX)slant $(BINPREFIX)slantsolver $(BINPREFIX)solo \ $(BINPREFIX)solosolver $(BINPREFIX)tents \ $(BINPREFIX)tentssolver $(BINPREFIX)towers \ $(BINPREFIX)towerssolver $(BINPREFIX)tracks \ $(BINPREFIX)twiddle $(BINPREFIX)undead $(BINPREFIX)unequal \ $(BINPREFIX)unequalsolver $(BINPREFIX)unruly \ $(BINPREFIX)unrulysolver $(BINPREFIX)untangle $(BINPREFIX)blackbox: blackbox.o blackbox-icon.o drawing.o gtk.o malloc.o \ midend.o misc.o printing.o ps.o random.o version.o $(CC) -o $@ blackbox.o blackbox-icon.o drawing.o gtk.o malloc.o \ midend.o misc.o printing.o ps.o random.o version.o \ $(XLFLAGS) $(XLIBS) $(BINPREFIX)bridges: bridges.o bridges-icon.o drawing.o dsf.o findloop.o \ gtk.o malloc.o midend.o misc.o printing.o ps.o random.o \ version.o $(CC) -o $@ bridges.o bridges-icon.o drawing.o dsf.o findloop.o \ gtk.o malloc.o midend.o misc.o printing.o ps.o random.o \ version.o $(XLFLAGS) $(XLIBS) $(BINPREFIX)cube: cube.o cube-icon.o drawing.o gtk.o malloc.o midend.o \ misc.o printing.o ps.o random.o version.o $(CC) -o $@ cube.o cube-icon.o drawing.o gtk.o malloc.o midend.o \ misc.o printing.o ps.o random.o version.o $(XLFLAGS) \ $(XLIBS) $(BINPREFIX)dominosa: dominosa.o dominosa-icon.o drawing.o gtk.o laydomino.o \ malloc.o midend.o misc.o printing.o ps.o random.o version.o $(CC) -o $@ dominosa.o dominosa-icon.o drawing.o gtk.o laydomino.o \ malloc.o midend.o misc.o printing.o ps.o random.o version.o \ $(XLFLAGS) $(XLIBS) $(BINPREFIX)fifteen: drawing.o fifteen.o fifteen-icon.o gtk.o malloc.o \ midend.o misc.o printing.o ps.o random.o version.o $(CC) -o $@ drawing.o fifteen.o fifteen-icon.o gtk.o malloc.o \ midend.o misc.o printing.o ps.o random.o version.o \ $(XLFLAGS) $(XLIBS) $(BINPREFIX)fifteensolver: fifteen2.o malloc.o misc.o nullfe.o random.o $(CC) -o $@ fifteen2.o malloc.o misc.o nullfe.o random.o $(XLFLAGS) \ $(ULIBS) $(BINPREFIX)filling: drawing.o dsf.o filling.o filling-icon.o gtk.o malloc.o \ midend.o misc.o printing.o ps.o random.o version.o $(CC) -o $@ drawing.o dsf.o filling.o filling-icon.o gtk.o malloc.o \ midend.o misc.o printing.o ps.o random.o version.o \ $(XLFLAGS) $(XLIBS) $(BINPREFIX)fillingsolver: dsf.o filling2.o malloc.o misc.o nullfe.o \ random.o $(CC) -o $@ dsf.o filling2.o malloc.o misc.o nullfe.o random.o \ $(XLFLAGS) $(ULIBS) $(BINPREFIX)flip: drawing.o flip.o flip-icon.o gtk.o malloc.o midend.o \ misc.o printing.o ps.o random.o tree234.o version.o $(CC) -o $@ drawing.o flip.o flip-icon.o gtk.o malloc.o midend.o \ misc.o printing.o ps.o random.o tree234.o version.o \ $(XLFLAGS) $(XLIBS) $(BINPREFIX)flood: drawing.o flood.o flood-icon.o gtk.o malloc.o midend.o \ misc.o printing.o ps.o random.o version.o $(CC) -o $@ drawing.o flood.o flood-icon.o gtk.o malloc.o midend.o \ misc.o printing.o ps.o random.o version.o $(XLFLAGS) \ $(XLIBS) $(BINPREFIX)galaxies: drawing.o dsf.o galaxies.o galaxies-icon.o gtk.o \ malloc.o midend.o misc.o printing.o ps.o random.o version.o $(CC) -o $@ drawing.o dsf.o galaxies.o galaxies-icon.o gtk.o \ malloc.o midend.o misc.o printing.o ps.o random.o version.o \ $(XLFLAGS) $(XLIBS) $(BINPREFIX)galaxiespicture: dsf.o galaxie4.o malloc.o misc.o nullfe.o \ random.o $(CC) -o $@ dsf.o galaxie4.o malloc.o misc.o nullfe.o random.o -lm \ $(XLFLAGS) $(ULIBS) $(BINPREFIX)galaxiessolver: dsf.o galaxie2.o malloc.o misc.o nullfe.o \ random.o $(CC) -o $@ dsf.o galaxie2.o malloc.o misc.o nullfe.o random.o -lm \ $(XLFLAGS) $(ULIBS) $(BINPREFIX)guess: drawing.o gtk.o guess.o guess-icon.o malloc.o midend.o \ misc.o printing.o ps.o random.o version.o $(CC) -o $@ drawing.o gtk.o guess.o guess-icon.o malloc.o midend.o \ misc.o printing.o ps.o random.o version.o $(XLFLAGS) \ $(XLIBS) $(BINPREFIX)inertia: drawing.o gtk.o inertia.o inertia-icon.o malloc.o \ midend.o misc.o printing.o ps.o random.o version.o $(CC) -o $@ drawing.o gtk.o inertia.o inertia-icon.o malloc.o \ midend.o misc.o printing.o ps.o random.o version.o \ $(XLFLAGS) $(XLIBS) $(BINPREFIX)keen: drawing.o dsf.o gtk.o keen.o keen-icon.o latin.o malloc.o \ maxflow.o midend.o misc.o printing.o ps.o random.o tree234.o \ version.o $(CC) -o $@ drawing.o dsf.o gtk.o keen.o keen-icon.o latin.o \ malloc.o maxflow.o midend.o misc.o printing.o ps.o random.o \ tree234.o version.o $(XLFLAGS) $(XLIBS) $(BINPREFIX)keensolver: dsf.o keen2.o latin6.o malloc.o maxflow.o misc.o \ nullfe.o random.o tree234.o $(CC) -o $@ dsf.o keen2.o latin6.o malloc.o maxflow.o misc.o \ nullfe.o random.o tree234.o $(XLFLAGS) $(ULIBS) $(BINPREFIX)latincheck: latin8.o malloc.o maxflow.o misc.o nullfe.o random.o \ tree234.o $(CC) -o $@ latin8.o malloc.o maxflow.o misc.o nullfe.o random.o \ tree234.o $(XLFLAGS) $(ULIBS) $(BINPREFIX)lightup: combi.o drawing.o gtk.o lightup.o lightup-icon.o \ malloc.o midend.o misc.o printing.o ps.o random.o version.o $(CC) -o $@ combi.o drawing.o gtk.o lightup.o lightup-icon.o \ malloc.o midend.o misc.o printing.o ps.o random.o version.o \ $(XLFLAGS) $(XLIBS) $(BINPREFIX)lightupsolver: combi.o lightup2.o malloc.o misc.o nullfe.o \ random.o $(CC) -o $@ combi.o lightup2.o malloc.o misc.o nullfe.o random.o \ $(XLFLAGS) $(ULIBS) $(BINPREFIX)loopy: drawing.o dsf.o grid.o gtk.o loopgen.o loopy.o \ loopy-icon.o malloc.o midend.o misc.o penrose.o printing.o \ ps.o random.o tree234.o version.o $(CC) -o $@ drawing.o dsf.o grid.o gtk.o loopgen.o loopy.o \ loopy-icon.o malloc.o midend.o misc.o penrose.o printing.o \ ps.o random.o tree234.o version.o $(XLFLAGS) $(XLIBS) $(BINPREFIX)loopysolver: dsf.o grid.o loopgen.o loopy2.o malloc.o misc.o \ nullfe.o penrose.o random.o tree234.o $(CC) -o $@ dsf.o grid.o loopgen.o loopy2.o malloc.o misc.o nullfe.o \ penrose.o random.o tree234.o -lm $(XLFLAGS) $(ULIBS) $(BINPREFIX)magnets: drawing.o gtk.o laydomino.o magnets.o magnets-icon.o \ malloc.o midend.o misc.o printing.o ps.o random.o version.o $(CC) -o $@ drawing.o gtk.o laydomino.o magnets.o magnets-icon.o \ malloc.o midend.o misc.o printing.o ps.o random.o version.o \ $(XLFLAGS) $(XLIBS) $(BINPREFIX)magnetssolver: laydomino.o magnets2.o malloc.o misc.o nullfe.o \ random.o $(CC) -o $@ laydomino.o magnets2.o malloc.o misc.o nullfe.o random.o \ -lm $(XLFLAGS) $(ULIBS) $(BINPREFIX)map: drawing.o dsf.o gtk.o malloc.o map.o map-icon.o midend.o \ misc.o printing.o ps.o random.o version.o $(CC) -o $@ drawing.o dsf.o gtk.o malloc.o map.o map-icon.o midend.o \ misc.o printing.o ps.o random.o version.o $(XLFLAGS) \ $(XLIBS) $(BINPREFIX)mapsolver: dsf.o malloc.o map2.o misc.o nullfe.o random.o $(CC) -o $@ dsf.o malloc.o map2.o misc.o nullfe.o random.o -lm \ $(XLFLAGS) $(ULIBS) $(BINPREFIX)mineobfusc: malloc.o mines2.o misc.o nullfe.o random.o tree234.o $(CC) -o $@ malloc.o mines2.o misc.o nullfe.o random.o tree234.o \ $(XLFLAGS) $(ULIBS) $(BINPREFIX)mines: drawing.o gtk.o malloc.o midend.o mines.o mines-icon.o \ misc.o printing.o ps.o random.o tree234.o version.o $(CC) -o $@ drawing.o gtk.o malloc.o midend.o mines.o mines-icon.o \ misc.o printing.o ps.o random.o tree234.o version.o \ $(XLFLAGS) $(XLIBS) $(BINPREFIX)net: drawing.o dsf.o findloop.o gtk.o malloc.o midend.o misc.o \ net.o net-icon.o printing.o ps.o random.o tree234.o \ version.o $(CC) -o $@ drawing.o dsf.o findloop.o gtk.o malloc.o midend.o \ misc.o net.o net-icon.o printing.o ps.o random.o tree234.o \ version.o $(XLFLAGS) $(XLIBS) $(BINPREFIX)netslide: drawing.o gtk.o malloc.o midend.o misc.o netslide.o \ netslide-icon.o printing.o ps.o random.o tree234.o version.o $(CC) -o $@ drawing.o gtk.o malloc.o midend.o misc.o netslide.o \ netslide-icon.o printing.o ps.o random.o tree234.o version.o \ $(XLFLAGS) $(XLIBS) $(BINPREFIX)nullgame: drawing.o gtk.o malloc.o midend.o misc.o no-icon.o \ nullgame.o printing.o ps.o random.o version.o $(CC) -o $@ drawing.o gtk.o malloc.o midend.o misc.o no-icon.o \ nullgame.o printing.o ps.o random.o version.o $(XLFLAGS) \ $(XLIBS) $(BINPREFIX)obfusc: malloc.o misc.o nullfe.o obfusc.o random.o $(CC) -o $@ malloc.o misc.o nullfe.o obfusc.o random.o $(XLFLAGS) \ $(ULIBS) $(BINPREFIX)palisade: divvy.o drawing.o dsf.o gtk.o malloc.o midend.o misc.o \ palisade.o palisade-icon.o printing.o ps.o random.o \ version.o $(CC) -o $@ divvy.o drawing.o dsf.o gtk.o malloc.o midend.o misc.o \ palisade.o palisade-icon.o printing.o ps.o random.o \ version.o $(XLFLAGS) $(XLIBS) $(BINPREFIX)pattern: drawing.o gtk.o malloc.o midend.o misc.o pattern.o \ pattern-icon.o printing.o ps.o random.o version.o $(CC) -o $@ drawing.o gtk.o malloc.o midend.o misc.o pattern.o \ pattern-icon.o printing.o ps.o random.o version.o \ $(XLFLAGS) $(XLIBS) $(BINPREFIX)patternpicture: malloc.o misc.o nullfe.o pattern4.o random.o $(CC) -o $@ malloc.o misc.o nullfe.o pattern4.o random.o $(XLFLAGS) \ $(ULIBS) $(BINPREFIX)patternsolver: malloc.o misc.o nullfe.o pattern2.o random.o $(CC) -o $@ malloc.o misc.o nullfe.o pattern2.o random.o $(XLFLAGS) \ $(ULIBS) $(BINPREFIX)pearl: drawing.o dsf.o grid.o gtk.o loopgen.o malloc.o midend.o \ misc.o pearl.o pearl-icon.o penrose.o printing.o ps.o \ random.o tdq.o tree234.o version.o $(CC) -o $@ drawing.o dsf.o grid.o gtk.o loopgen.o malloc.o midend.o \ misc.o pearl.o pearl-icon.o penrose.o printing.o ps.o \ random.o tdq.o tree234.o version.o $(XLFLAGS) $(XLIBS) $(BINPREFIX)pearlbench: dsf.o grid.o loopgen.o malloc.o misc.o nullfe.o \ pearl2.o penrose.o random.o tdq.o tree234.o $(CC) -o $@ dsf.o grid.o loopgen.o malloc.o misc.o nullfe.o pearl2.o \ penrose.o random.o tdq.o tree234.o -lm $(XLFLAGS) $(ULIBS) $(BINPREFIX)pegs: drawing.o gtk.o malloc.o midend.o misc.o pegs.o \ pegs-icon.o printing.o ps.o random.o tree234.o version.o $(CC) -o $@ drawing.o gtk.o malloc.o midend.o misc.o pegs.o \ pegs-icon.o printing.o ps.o random.o tree234.o version.o \ $(XLFLAGS) $(XLIBS) $(BINPREFIX)range: drawing.o dsf.o gtk.o malloc.o midend.o misc.o printing.o \ ps.o random.o range.o range-icon.o version.o $(CC) -o $@ drawing.o dsf.o gtk.o malloc.o midend.o misc.o \ printing.o ps.o random.o range.o range-icon.o version.o \ $(XLFLAGS) $(XLIBS) $(BINPREFIX)rect: drawing.o gtk.o malloc.o midend.o misc.o printing.o ps.o \ random.o rect.o rect-icon.o version.o $(CC) -o $@ drawing.o gtk.o malloc.o midend.o misc.o printing.o ps.o \ random.o rect.o rect-icon.o version.o $(XLFLAGS) $(XLIBS) $(BINPREFIX)samegame: drawing.o gtk.o malloc.o midend.o misc.o printing.o \ ps.o random.o samegame.o samegame-icon.o version.o $(CC) -o $@ drawing.o gtk.o malloc.o midend.o misc.o printing.o ps.o \ random.o samegame.o samegame-icon.o version.o $(XLFLAGS) \ $(XLIBS) $(BINPREFIX)signpost: drawing.o dsf.o gtk.o malloc.o midend.o misc.o \ printing.o ps.o random.o signpost.o signpost-icon.o \ version.o $(CC) -o $@ drawing.o dsf.o gtk.o malloc.o midend.o misc.o \ printing.o ps.o random.o signpost.o signpost-icon.o \ version.o $(XLFLAGS) $(XLIBS) $(BINPREFIX)signpostsolver: dsf.o malloc.o misc.o nullfe.o random.o \ signpos2.o $(CC) -o $@ dsf.o malloc.o misc.o nullfe.o random.o signpos2.o -lm \ $(XLFLAGS) $(ULIBS) $(BINPREFIX)singles: drawing.o dsf.o gtk.o latin.o malloc.o maxflow.o \ midend.o misc.o printing.o ps.o random.o singles.o \ singles-icon.o tree234.o version.o $(CC) -o $@ drawing.o dsf.o gtk.o latin.o malloc.o maxflow.o \ midend.o misc.o printing.o ps.o random.o singles.o \ singles-icon.o tree234.o version.o $(XLFLAGS) $(XLIBS) $(BINPREFIX)singlessolver: dsf.o latin.o malloc.o maxflow.o misc.o nullfe.o \ random.o singles3.o tree234.o $(CC) -o $@ dsf.o latin.o malloc.o maxflow.o misc.o nullfe.o \ random.o singles3.o tree234.o $(XLFLAGS) $(ULIBS) $(BINPREFIX)sixteen: drawing.o gtk.o malloc.o midend.o misc.o printing.o \ ps.o random.o sixteen.o sixteen-icon.o version.o $(CC) -o $@ drawing.o gtk.o malloc.o midend.o misc.o printing.o ps.o \ random.o sixteen.o sixteen-icon.o version.o $(XLFLAGS) \ $(XLIBS) $(BINPREFIX)slant: drawing.o dsf.o findloop.o gtk.o malloc.o midend.o misc.o \ printing.o ps.o random.o slant.o slant-icon.o version.o $(CC) -o $@ drawing.o dsf.o findloop.o gtk.o malloc.o midend.o \ misc.o printing.o ps.o random.o slant.o slant-icon.o \ version.o $(XLFLAGS) $(XLIBS) $(BINPREFIX)slantsolver: dsf.o findloop.o malloc.o misc.o nullfe.o random.o \ slant2.o $(CC) -o $@ dsf.o findloop.o malloc.o misc.o nullfe.o random.o \ slant2.o $(XLFLAGS) $(ULIBS) $(BINPREFIX)solo: divvy.o drawing.o dsf.o gtk.o malloc.o midend.o misc.o \ printing.o ps.o random.o solo.o solo-icon.o version.o $(CC) -o $@ divvy.o drawing.o dsf.o gtk.o malloc.o midend.o misc.o \ printing.o ps.o random.o solo.o solo-icon.o version.o \ $(XLFLAGS) $(XLIBS) $(BINPREFIX)solosolver: divvy.o dsf.o malloc.o misc.o nullfe.o random.o \ solo2.o $(CC) -o $@ divvy.o dsf.o malloc.o misc.o nullfe.o random.o solo2.o \ $(XLFLAGS) $(ULIBS) $(BINPREFIX)tents: drawing.o dsf.o gtk.o malloc.o maxflow.o midend.o misc.o \ printing.o ps.o random.o tents.o tents-icon.o version.o $(CC) -o $@ drawing.o dsf.o gtk.o malloc.o maxflow.o midend.o misc.o \ printing.o ps.o random.o tents.o tents-icon.o version.o \ $(XLFLAGS) $(XLIBS) $(BINPREFIX)tentssolver: dsf.o malloc.o maxflow.o misc.o nullfe.o random.o \ tents3.o $(CC) -o $@ dsf.o malloc.o maxflow.o misc.o nullfe.o random.o \ tents3.o $(XLFLAGS) $(ULIBS) $(BINPREFIX)towers: drawing.o gtk.o latin.o malloc.o maxflow.o midend.o \ misc.o printing.o ps.o random.o towers.o towers-icon.o \ tree234.o version.o $(CC) -o $@ drawing.o gtk.o latin.o malloc.o maxflow.o midend.o \ misc.o printing.o ps.o random.o towers.o towers-icon.o \ tree234.o version.o $(XLFLAGS) $(XLIBS) $(BINPREFIX)towerssolver: latin6.o malloc.o maxflow.o misc.o nullfe.o \ random.o towers2.o tree234.o $(CC) -o $@ latin6.o malloc.o maxflow.o misc.o nullfe.o random.o \ towers2.o tree234.o $(XLFLAGS) $(ULIBS) $(BINPREFIX)tracks: drawing.o dsf.o findloop.o gtk.o malloc.o midend.o \ misc.o printing.o ps.o random.o tracks.o tracks-icon.o \ version.o $(CC) -o $@ drawing.o dsf.o findloop.o gtk.o malloc.o midend.o \ misc.o printing.o ps.o random.o tracks.o tracks-icon.o \ version.o $(XLFLAGS) $(XLIBS) $(BINPREFIX)twiddle: drawing.o gtk.o malloc.o midend.o misc.o printing.o \ ps.o random.o twiddle.o twiddle-icon.o version.o $(CC) -o $@ drawing.o gtk.o malloc.o midend.o misc.o printing.o ps.o \ random.o twiddle.o twiddle-icon.o version.o $(XLFLAGS) \ $(XLIBS) $(BINPREFIX)undead: drawing.o gtk.o malloc.o midend.o misc.o printing.o ps.o \ random.o undead.o undead-icon.o version.o $(CC) -o $@ drawing.o gtk.o malloc.o midend.o misc.o printing.o ps.o \ random.o undead.o undead-icon.o version.o $(XLFLAGS) \ $(XLIBS) $(BINPREFIX)unequal: drawing.o gtk.o latin.o malloc.o maxflow.o midend.o \ misc.o printing.o ps.o random.o tree234.o unequal.o \ unequal-icon.o version.o $(CC) -o $@ drawing.o gtk.o latin.o malloc.o maxflow.o midend.o \ misc.o printing.o ps.o random.o tree234.o unequal.o \ unequal-icon.o version.o $(XLFLAGS) $(XLIBS) $(BINPREFIX)unequalsolver: latin6.o malloc.o maxflow.o misc.o nullfe.o \ random.o tree234.o unequal2.o $(CC) -o $@ latin6.o malloc.o maxflow.o misc.o nullfe.o random.o \ tree234.o unequal2.o $(XLFLAGS) $(ULIBS) $(BINPREFIX)unruly: drawing.o gtk.o malloc.o midend.o misc.o printing.o ps.o \ random.o unruly.o unruly-icon.o version.o $(CC) -o $@ drawing.o gtk.o malloc.o midend.o misc.o printing.o ps.o \ random.o unruly.o unruly-icon.o version.o $(XLFLAGS) \ $(XLIBS) $(BINPREFIX)unrulysolver: malloc.o misc.o nullfe.o random.o unruly2.o $(CC) -o $@ malloc.o misc.o nullfe.o random.o unruly2.o $(XLFLAGS) \ $(ULIBS) $(BINPREFIX)untangle: drawing.o gtk.o malloc.o midend.o misc.o printing.o \ ps.o random.o tree234.o untangle.o untangle-icon.o version.o $(CC) -o $@ drawing.o gtk.o malloc.o midend.o misc.o printing.o ps.o \ random.o tree234.o untangle.o untangle-icon.o version.o \ $(XLFLAGS) $(XLIBS) blackbox.o: ./blackbox.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ blackbox-icon.o: icons/blackbox-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ blackbo3.o: ./blackbox.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ bridges.o: ./bridges.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ bridges-icon.o: icons/bridges-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ bridges3.o: ./bridges.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ combi.o: ./combi.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ cube.o: ./cube.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ cube-icon.o: icons/cube-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ cube3.o: ./cube.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ divvy.o: ./divvy.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ dominosa.o: ./dominosa.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ dominosa-icon.o: icons/dominosa-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ dominos3.o: ./dominosa.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ drawing.o: ./drawing.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ dsf.o: ./dsf.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ fifteen.o: ./fifteen.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ fifteen-icon.o: icons/fifteen-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ fifteen5.o: ./fifteen.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ fifteen2.o: ./fifteen.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ filling.o: ./filling.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ filling-icon.o: icons/filling-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ filling5.o: ./filling.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ filling2.o: ./filling.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ findloop.o: ./findloop.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ flip.o: ./flip.c ./puzzles.h ./tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ flip-icon.o: icons/flip-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ flip3.o: ./flip.c ./puzzles.h ./tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ flood.o: ./flood.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ flood-icon.o: icons/flood-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ flood3.o: ./flood.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ galaxies.o: ./galaxies.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ galaxies-icon.o: icons/galaxies-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ galaxie7.o: ./galaxies.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ galaxie4.o: ./galaxies.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_PICTURE_GENERATOR -c $< -o $@ galaxie2.o: ./galaxies.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ grid.o: ./grid.c ./puzzles.h ./tree234.h ./grid.h ./penrose.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ gtk.o: ./gtk.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ guess.o: ./guess.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ guess-icon.o: icons/guess-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ guess3.o: ./guess.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ inertia.o: ./inertia.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ inertia-icon.o: icons/inertia-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ inertia3.o: ./inertia.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ keen.o: ./keen.c ./puzzles.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ keen-icon.o: icons/keen-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ keen5.o: ./keen.c ./puzzles.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ keen2.o: ./keen.c ./puzzles.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ latin.o: ./latin.c ./puzzles.h ./tree234.h ./maxflow.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ latin8.o: ./latin.c ./puzzles.h ./tree234.h ./maxflow.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_LATIN_TEST -c $< -o $@ latin6.o: ./latin.c ./puzzles.h ./tree234.h ./maxflow.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ laydomino.o: ./laydomino.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ lightup.o: ./lightup.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ lightup-icon.o: icons/lightup-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ lightup5.o: ./lightup.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ lightup2.o: ./lightup.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ list.o: ./list.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ loopgen.o: ./loopgen.c ./puzzles.h ./tree234.h ./grid.h ./loopgen.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ loopy.o: ./loopy.c ./puzzles.h ./tree234.h ./grid.h ./loopgen.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ loopy-icon.o: icons/loopy-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ loopy5.o: ./loopy.c ./puzzles.h ./tree234.h ./grid.h ./loopgen.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ loopy2.o: ./loopy.c ./puzzles.h ./tree234.h ./grid.h ./loopgen.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ magnets.o: ./magnets.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ magnets-icon.o: icons/magnets-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ magnets5.o: ./magnets.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ magnets2.o: ./magnets.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ malloc.o: ./malloc.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ map.o: ./map.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ map-icon.o: icons/map-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ map5.o: ./map.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ map2.o: ./map.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ maxflow.o: ./maxflow.c ./maxflow.h ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ midend.o: ./midend.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ mines.o: ./mines.c ./tree234.h ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ mines-icon.o: icons/mines-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ mines5.o: ./mines.c ./tree234.h ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ mines2.o: ./mines.c ./tree234.h ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_OBFUSCATOR -c $< -o $@ misc.o: ./misc.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ net.o: ./net.c ./puzzles.h ./tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ net-icon.o: icons/net-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ net3.o: ./net.c ./puzzles.h ./tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ netslide.o: ./netslide.c ./puzzles.h ./tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ netslide-icon.o: icons/netslide-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ netslid3.o: ./netslide.c ./puzzles.h ./tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ no-icon.o: ./no-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ nullfe.o: ./nullfe.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ nullgame.o: ./nullgame.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ obfusc.o: ./obfusc.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ osx.o: ./osx.m ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ palisade.o: ./palisade.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ palisade-icon.o: icons/palisade-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ palisad3.o: ./palisade.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ pattern.o: ./pattern.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ pattern-icon.o: icons/pattern-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ pattern7.o: ./pattern.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ pattern4.o: ./pattern.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_PICTURE_GENERATOR -c $< -o $@ pattern2.o: ./pattern.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ pearl.o: ./pearl.c ./puzzles.h ./grid.h ./loopgen.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ pearl-icon.o: icons/pearl-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ pearl5.o: ./pearl.c ./puzzles.h ./grid.h ./loopgen.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ pearl2.o: ./pearl.c ./puzzles.h ./grid.h ./loopgen.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ pegs.o: ./pegs.c ./puzzles.h ./tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ pegs-icon.o: icons/pegs-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ pegs3.o: ./pegs.c ./puzzles.h ./tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ penrose.o: ./penrose.c ./puzzles.h ./penrose.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ printing.o: ./printing.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ ps.o: ./ps.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ random.o: ./random.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ range.o: ./range.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ range-icon.o: icons/range-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ range3.o: ./range.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ rect.o: ./rect.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ rect-icon.o: icons/rect-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ rect3.o: ./rect.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ samegame.o: ./samegame.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ samegame-icon.o: icons/samegame-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ samegam3.o: ./samegame.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ signpost.o: ./signpost.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ signpost-icon.o: icons/signpost-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ signpos5.o: ./signpost.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ signpos2.o: ./signpost.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ singles.o: ./singles.c ./puzzles.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ singles-icon.o: icons/singles-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ singles5.o: ./singles.c ./puzzles.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ singles3.o: ./singles.c ./puzzles.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ sixteen.o: ./sixteen.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ sixteen-icon.o: icons/sixteen-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ sixteen3.o: ./sixteen.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ slant.o: ./slant.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ slant-icon.o: icons/slant-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ slant5.o: ./slant.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ slant2.o: ./slant.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ solo.o: ./solo.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ solo-icon.o: icons/solo-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ solo5.o: ./solo.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ solo2.o: ./solo.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ tdq.o: ./tdq.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ tents.o: ./tents.c ./puzzles.h ./maxflow.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ tents-icon.o: icons/tents-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ tents5.o: ./tents.c ./puzzles.h ./maxflow.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ tents3.o: ./tents.c ./puzzles.h ./maxflow.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ towers.o: ./towers.c ./puzzles.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ towers-icon.o: icons/towers-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ towers5.o: ./towers.c ./puzzles.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ towers2.o: ./towers.c ./puzzles.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ tracks.o: ./tracks.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ tracks-icon.o: icons/tracks-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ tracks3.o: ./tracks.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ tree234.o: ./tree234.c ./tree234.h ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ twiddle.o: ./twiddle.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ twiddle-icon.o: icons/twiddle-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ twiddle3.o: ./twiddle.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ undead.o: ./undead.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ undead-icon.o: icons/undead-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ undead3.o: ./undead.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ unequal.o: ./unequal.c ./puzzles.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ unequal-icon.o: icons/unequal-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ unequal5.o: ./unequal.c ./puzzles.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ unequal2.o: ./unequal.c ./puzzles.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ unruly.o: ./unruly.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ unruly-icon.o: icons/unruly-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ unruly5.o: ./unruly.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ unruly2.o: ./unruly.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ untangle.o: ./untangle.c ./puzzles.h ./tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ untangle-icon.o: icons/untangle-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ untangl3.o: ./untangle.c ./puzzles.h ./tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ version.o: ./version.c ./version.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ windows.o: ./windows.c ./puzzles.h ./resource.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ windows1.o: ./windows.c ./puzzles.h ./resource.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ GAMES += blackbox GAMES += bridges GAMES += cube GAMES += dominosa GAMES += fifteen GAMES += filling GAMES += flip GAMES += flood GAMES += galaxies GAMES += guess GAMES += inertia GAMES += keen GAMES += lightup GAMES += loopy GAMES += magnets GAMES += map GAMES += mines GAMES += net GAMES += netslide GAMES += palisade GAMES += pattern GAMES += pearl GAMES += pegs GAMES += range GAMES += rect GAMES += samegame GAMES += signpost GAMES += singles GAMES += sixteen GAMES += slant GAMES += solo GAMES += tents GAMES += towers GAMES += tracks GAMES += twiddle GAMES += undead GAMES += unequal GAMES += unruly GAMES += untangle install: for i in $(GAMES); do \ $(INSTALL_PROGRAM) -m 755 $(BINPREFIX)$$i $(DESTDIR)$(gamesdir)/$(BINPREFIX)$$i \ || exit 1; \ done test: benchmark.html benchmark.txt benchmark.html: benchmark.txt benchmark.pl ./benchmark.pl benchmark.txt > $@ benchmark.txt: benchmark.sh $(GAMES) ./benchmark.sh > $@ clean: rm -f *.o $(BINPREFIX)blackbox $(BINPREFIX)bridges $(BINPREFIX)cube $(BINPREFIX)dominosa $(BINPREFIX)fifteen $(BINPREFIX)fifteensolver $(BINPREFIX)filling $(BINPREFIX)fillingsolver $(BINPREFIX)flip $(BINPREFIX)flood $(BINPREFIX)galaxies $(BINPREFIX)galaxiespicture $(BINPREFIX)galaxiessolver $(BINPREFIX)guess $(BINPREFIX)inertia $(BINPREFIX)keen $(BINPREFIX)keensolver $(BINPREFIX)latincheck $(BINPREFIX)lightup $(BINPREFIX)lightupsolver $(BINPREFIX)loopy $(BINPREFIX)loopysolver $(BINPREFIX)magnets $(BINPREFIX)magnetssolver $(BINPREFIX)map $(BINPREFIX)mapsolver $(BINPREFIX)mineobfusc $(BINPREFIX)mines $(BINPREFIX)net $(BINPREFIX)netslide $(BINPREFIX)nullgame $(BINPREFIX)obfusc $(BINPREFIX)palisade $(BINPREFIX)pattern $(BINPREFIX)patternpicture $(BINPREFIX)patternsolver $(BINPREFIX)pearl $(BINPREFIX)pearlbench $(BINPREFIX)pegs $(BINPREFIX)range $(BINPREFIX)rect $(BINPREFIX)samegame $(BINPREFIX)signpost $(BINPREFIX)signpostsolver $(BINPREFIX)singles $(BINPREFIX)singlessolver $(BINPREFIX)sixteen $(BINPREFIX)slant $(BINPREFIX)slantsolver $(BINPREFIX)solo $(BINPREFIX)solosolver $(BINPREFIX)tents $(BINPREFIX)tentssolver $(BINPREFIX)towers $(BINPREFIX)towerssolver $(BINPREFIX)tracks $(BINPREFIX)twiddle $(BINPREFIX)undead $(BINPREFIX)unequal $(BINPREFIX)unequalsolver $(BINPREFIX)unruly $(BINPREFIX)unrulysolver $(BINPREFIX)untangle puzzles-20170606.272beef/Makefile.gnustep0000644000175000017500000006271113115375145017024 0ustar simonsimon# Makefile for puzzles under GNUstep. # # This file was created by `mkfiles.pl' from the `Recipe' file. # DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead. NEEDS_GUI=yes include $(GNUSTEP_MAKEFILES)/common.make include $(GNUSTEP_MAKEFILES)/rules.make include $(GNUSTEP_MAKEFILES)/Instance/rules.make all:: Puzzles fifteensolver fillingsolver galaxiespicture galaxiessolver \ keensolver latincheck lightupsolver loopysolver \ magnetssolver mapsolver mineobfusc obfusc patternpicture \ patternsolver pearlbench signpostsolver singlessolver \ slantsolver solosolver tentssolver towerssolver \ unequalsolver unrulysolver .SUFFIXES: .o .c .m Puzzles.app: mkdir -p $@ Puzzles.app/Resources: Puzzles.app mkdir -p $@ Puzzles.app/Resources/Puzzles.icns: Puzzles.app/Resources osx.icns cp osx.icns $@ Puzzles.app/Info.plist: Puzzles.app osx-info.plist cp osx-info.plist $@ Puzzles: Puzzles.app Puzzles.app/Puzzles \ Puzzles.app/Resources/Puzzles.icns Puzzles.app/Info.plist \ $(Puzzles_extra) Puzzles.app/Puzzles: blackbo3.o bridges3.o combi.o cube3.o divvy.o \ dominos3.o drawing.o dsf.o fifteen5.o filling5.o findloop.o \ flip3.o flood3.o galaxie7.o grid.o guess3.o inertia3.o \ keen5.o latin.o laydomino.o lightup5.o list.o loopgen.o \ loopy5.o magnets5.o malloc.o map5.o maxflow.o midend.o \ mines5.o misc.o net3.o netslid3.o osx.o palisad3.o \ pattern7.o pearl5.o pegs3.o penrose.o random.o range3.o \ rect3.o samegam3.o signpos5.o singles5.o sixteen3.o slant5.o \ solo5.o tdq.o tents5.o towers5.o tracks3.o tree234.o \ twiddle3.o undead3.o unequal5.o unruly5.o untangl3.o \ version.o $(CC) $(ALL_LDFLAGS) -o $@ blackbo3.o bridges3.o combi.o cube3.o \ divvy.o dominos3.o drawing.o dsf.o fifteen5.o filling5.o \ findloop.o flip3.o flood3.o galaxie7.o grid.o guess3.o \ inertia3.o keen5.o latin.o laydomino.o lightup5.o list.o \ loopgen.o loopy5.o magnets5.o malloc.o map5.o maxflow.o \ midend.o mines5.o misc.o net3.o netslid3.o osx.o palisad3.o \ pattern7.o pearl5.o pegs3.o penrose.o random.o range3.o \ rect3.o samegam3.o signpos5.o singles5.o sixteen3.o slant5.o \ solo5.o tdq.o tents5.o towers5.o tracks3.o tree234.o \ twiddle3.o undead3.o unequal5.o unruly5.o untangl3.o \ version.o $(ALL_LIB_DIRS) $(ALL_LIBS) fifteensolver: fifteen2.o malloc.o misc.o nullfe.o random.o $(CC) $(ULDFLAGS) -o $@ fifteen2.o malloc.o misc.o nullfe.o random.o fillingsolver: dsf.o filling2.o malloc.o misc.o nullfe.o random.o $(CC) $(ULDFLAGS) -o $@ dsf.o filling2.o malloc.o misc.o nullfe.o \ random.o galaxiespicture: dsf.o galaxie4.o malloc.o misc.o nullfe.o random.o $(CC) $(ULDFLAGS) -o $@ dsf.o galaxie4.o malloc.o misc.o nullfe.o \ random.o -lm galaxiessolver: dsf.o galaxie2.o malloc.o misc.o nullfe.o random.o $(CC) $(ULDFLAGS) -o $@ dsf.o galaxie2.o malloc.o misc.o nullfe.o \ random.o -lm keensolver: dsf.o keen2.o latin6.o malloc.o maxflow.o misc.o nullfe.o \ random.o tree234.o $(CC) $(ULDFLAGS) -o $@ dsf.o keen2.o latin6.o malloc.o maxflow.o \ misc.o nullfe.o random.o tree234.o latincheck: latin8.o malloc.o maxflow.o misc.o nullfe.o random.o tree234.o $(CC) $(ULDFLAGS) -o $@ latin8.o malloc.o maxflow.o misc.o nullfe.o \ random.o tree234.o lightupsolver: combi.o lightup2.o malloc.o misc.o nullfe.o random.o $(CC) $(ULDFLAGS) -o $@ combi.o lightup2.o malloc.o misc.o nullfe.o \ random.o loopysolver: dsf.o grid.o loopgen.o loopy2.o malloc.o misc.o nullfe.o \ penrose.o random.o tree234.o $(CC) $(ULDFLAGS) -o $@ dsf.o grid.o loopgen.o loopy2.o malloc.o \ misc.o nullfe.o penrose.o random.o tree234.o -lm magnetssolver: laydomino.o magnets2.o malloc.o misc.o nullfe.o random.o $(CC) $(ULDFLAGS) -o $@ laydomino.o magnets2.o malloc.o misc.o \ nullfe.o random.o -lm mapsolver: dsf.o malloc.o map2.o misc.o nullfe.o random.o $(CC) $(ULDFLAGS) -o $@ dsf.o malloc.o map2.o misc.o nullfe.o \ random.o -lm mineobfusc: malloc.o mines2.o misc.o nullfe.o random.o tree234.o $(CC) $(ULDFLAGS) -o $@ malloc.o mines2.o misc.o nullfe.o random.o \ tree234.o obfusc: malloc.o misc.o nullfe.o obfusc.o random.o $(CC) $(ULDFLAGS) -o $@ malloc.o misc.o nullfe.o obfusc.o random.o patternpicture: malloc.o misc.o nullfe.o pattern4.o random.o $(CC) $(ULDFLAGS) -o $@ malloc.o misc.o nullfe.o pattern4.o random.o patternsolver: malloc.o misc.o nullfe.o pattern2.o random.o $(CC) $(ULDFLAGS) -o $@ malloc.o misc.o nullfe.o pattern2.o random.o pearlbench: dsf.o grid.o loopgen.o malloc.o misc.o nullfe.o pearl2.o \ penrose.o random.o tdq.o tree234.o $(CC) $(ULDFLAGS) -o $@ dsf.o grid.o loopgen.o malloc.o misc.o \ nullfe.o pearl2.o penrose.o random.o tdq.o tree234.o -lm signpostsolver: dsf.o malloc.o misc.o nullfe.o random.o signpos2.o $(CC) $(ULDFLAGS) -o $@ dsf.o malloc.o misc.o nullfe.o random.o \ signpos2.o -lm singlessolver: dsf.o latin.o malloc.o maxflow.o misc.o nullfe.o random.o \ singles3.o tree234.o $(CC) $(ULDFLAGS) -o $@ dsf.o latin.o malloc.o maxflow.o misc.o \ nullfe.o random.o singles3.o tree234.o slantsolver: dsf.o findloop.o malloc.o misc.o nullfe.o random.o slant2.o $(CC) $(ULDFLAGS) -o $@ dsf.o findloop.o malloc.o misc.o nullfe.o \ random.o slant2.o solosolver: divvy.o dsf.o malloc.o misc.o nullfe.o random.o solo2.o $(CC) $(ULDFLAGS) -o $@ divvy.o dsf.o malloc.o misc.o nullfe.o \ random.o solo2.o tentssolver: dsf.o malloc.o maxflow.o misc.o nullfe.o random.o tents3.o $(CC) $(ULDFLAGS) -o $@ dsf.o malloc.o maxflow.o misc.o nullfe.o \ random.o tents3.o towerssolver: latin6.o malloc.o maxflow.o misc.o nullfe.o random.o towers2.o \ tree234.o $(CC) $(ULDFLAGS) -o $@ latin6.o malloc.o maxflow.o misc.o nullfe.o \ random.o towers2.o tree234.o unequalsolver: latin6.o malloc.o maxflow.o misc.o nullfe.o random.o \ tree234.o unequal2.o $(CC) $(ULDFLAGS) -o $@ latin6.o malloc.o maxflow.o misc.o nullfe.o \ random.o tree234.o unequal2.o unrulysolver: malloc.o misc.o nullfe.o random.o unruly2.o $(CC) $(ULDFLAGS) -o $@ malloc.o misc.o nullfe.o random.o unruly2.o blackbox.o: ./blackbox.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ blackbox-icon.o: icons/blackbox-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ blackbo3.o: ./blackbox.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ bridges.o: ./bridges.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ bridges-icon.o: icons/bridges-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ bridges3.o: ./bridges.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ combi.o: ./combi.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ cube.o: ./cube.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ cube-icon.o: icons/cube-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ cube3.o: ./cube.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ divvy.o: ./divvy.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ dominosa.o: ./dominosa.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ dominosa-icon.o: icons/dominosa-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ dominos3.o: ./dominosa.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ drawing.o: ./drawing.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ dsf.o: ./dsf.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ fifteen.o: ./fifteen.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ fifteen-icon.o: icons/fifteen-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ fifteen5.o: ./fifteen.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ fifteen2.o: ./fifteen.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ filling.o: ./filling.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ filling-icon.o: icons/filling-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ filling5.o: ./filling.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ filling2.o: ./filling.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ findloop.o: ./findloop.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ flip.o: ./flip.c ./puzzles.h ./tree234.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ flip-icon.o: icons/flip-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ flip3.o: ./flip.c ./puzzles.h ./tree234.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ flood.o: ./flood.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ flood-icon.o: icons/flood-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ flood3.o: ./flood.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ galaxies.o: ./galaxies.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ galaxies-icon.o: icons/galaxies-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ galaxie7.o: ./galaxies.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ galaxie4.o: ./galaxies.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_PICTURE_GENERATOR -c $< -o $@ galaxie2.o: ./galaxies.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ grid.o: ./grid.c ./puzzles.h ./tree234.h ./grid.h ./penrose.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ gtk.o: ./gtk.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ guess.o: ./guess.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ guess-icon.o: icons/guess-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ guess3.o: ./guess.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ inertia.o: ./inertia.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ inertia-icon.o: icons/inertia-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ inertia3.o: ./inertia.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ keen.o: ./keen.c ./puzzles.h ./latin.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ keen-icon.o: icons/keen-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ keen5.o: ./keen.c ./puzzles.h ./latin.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ keen2.o: ./keen.c ./puzzles.h ./latin.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ latin.o: ./latin.c ./puzzles.h ./tree234.h ./maxflow.h ./latin.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ latin8.o: ./latin.c ./puzzles.h ./tree234.h ./maxflow.h ./latin.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_LATIN_TEST -c $< -o $@ latin6.o: ./latin.c ./puzzles.h ./tree234.h ./maxflow.h ./latin.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ laydomino.o: ./laydomino.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ lightup.o: ./lightup.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ lightup-icon.o: icons/lightup-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ lightup5.o: ./lightup.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ lightup2.o: ./lightup.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ list.o: ./list.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ loopgen.o: ./loopgen.c ./puzzles.h ./tree234.h ./grid.h ./loopgen.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ loopy.o: ./loopy.c ./puzzles.h ./tree234.h ./grid.h ./loopgen.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ loopy-icon.o: icons/loopy-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ loopy5.o: ./loopy.c ./puzzles.h ./tree234.h ./grid.h ./loopgen.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ loopy2.o: ./loopy.c ./puzzles.h ./tree234.h ./grid.h ./loopgen.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ magnets.o: ./magnets.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ magnets-icon.o: icons/magnets-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ magnets5.o: ./magnets.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ magnets2.o: ./magnets.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ malloc.o: ./malloc.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ map.o: ./map.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ map-icon.o: icons/map-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ map5.o: ./map.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ map2.o: ./map.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ maxflow.o: ./maxflow.c ./maxflow.h ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ midend.o: ./midend.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ mines.o: ./mines.c ./tree234.h ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ mines-icon.o: icons/mines-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ mines5.o: ./mines.c ./tree234.h ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ mines2.o: ./mines.c ./tree234.h ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_OBFUSCATOR -c $< -o $@ misc.o: ./misc.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ net.o: ./net.c ./puzzles.h ./tree234.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ net-icon.o: icons/net-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ net3.o: ./net.c ./puzzles.h ./tree234.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ netslide.o: ./netslide.c ./puzzles.h ./tree234.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ netslide-icon.o: icons/netslide-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ netslid3.o: ./netslide.c ./puzzles.h ./tree234.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ no-icon.o: ./no-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ nullfe.o: ./nullfe.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ nullgame.o: ./nullgame.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ obfusc.o: ./obfusc.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ osx.o: ./osx.m ./puzzles.h $(CC) -DGNUSTEP $(ALL_OBJCFLAGS) $(COMPAT) $(FWHACK) $(OBJCFLAGS) $(XFLAGS) -c $< -o $@ palisade.o: ./palisade.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ palisade-icon.o: icons/palisade-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ palisad3.o: ./palisade.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ pattern.o: ./pattern.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ pattern-icon.o: icons/pattern-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ pattern7.o: ./pattern.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ pattern4.o: ./pattern.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_PICTURE_GENERATOR -c $< -o $@ pattern2.o: ./pattern.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ pearl.o: ./pearl.c ./puzzles.h ./grid.h ./loopgen.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ pearl-icon.o: icons/pearl-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ pearl5.o: ./pearl.c ./puzzles.h ./grid.h ./loopgen.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ pearl2.o: ./pearl.c ./puzzles.h ./grid.h ./loopgen.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ pegs.o: ./pegs.c ./puzzles.h ./tree234.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ pegs-icon.o: icons/pegs-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ pegs3.o: ./pegs.c ./puzzles.h ./tree234.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ penrose.o: ./penrose.c ./puzzles.h ./penrose.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ printing.o: ./printing.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ ps.o: ./ps.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ random.o: ./random.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ range.o: ./range.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ range-icon.o: icons/range-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ range3.o: ./range.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ rect.o: ./rect.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ rect-icon.o: icons/rect-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ rect3.o: ./rect.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ samegame.o: ./samegame.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ samegame-icon.o: icons/samegame-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ samegam3.o: ./samegame.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ signpost.o: ./signpost.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ signpost-icon.o: icons/signpost-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ signpos5.o: ./signpost.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ signpos2.o: ./signpost.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ singles.o: ./singles.c ./puzzles.h ./latin.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ singles-icon.o: icons/singles-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ singles5.o: ./singles.c ./puzzles.h ./latin.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ singles3.o: ./singles.c ./puzzles.h ./latin.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ sixteen.o: ./sixteen.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ sixteen-icon.o: icons/sixteen-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ sixteen3.o: ./sixteen.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ slant.o: ./slant.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ slant-icon.o: icons/slant-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ slant5.o: ./slant.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ slant2.o: ./slant.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ solo.o: ./solo.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ solo-icon.o: icons/solo-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ solo5.o: ./solo.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ solo2.o: ./solo.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ tdq.o: ./tdq.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ tents.o: ./tents.c ./puzzles.h ./maxflow.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ tents-icon.o: icons/tents-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ tents5.o: ./tents.c ./puzzles.h ./maxflow.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ tents3.o: ./tents.c ./puzzles.h ./maxflow.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ towers.o: ./towers.c ./puzzles.h ./latin.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ towers-icon.o: icons/towers-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ towers5.o: ./towers.c ./puzzles.h ./latin.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ towers2.o: ./towers.c ./puzzles.h ./latin.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ tracks.o: ./tracks.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ tracks-icon.o: icons/tracks-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ tracks3.o: ./tracks.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ tree234.o: ./tree234.c ./tree234.h ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ twiddle.o: ./twiddle.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ twiddle-icon.o: icons/twiddle-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ twiddle3.o: ./twiddle.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ undead.o: ./undead.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ undead-icon.o: icons/undead-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ undead3.o: ./undead.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ unequal.o: ./unequal.c ./puzzles.h ./latin.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ unequal-icon.o: icons/unequal-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ unequal5.o: ./unequal.c ./puzzles.h ./latin.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ unequal2.o: ./unequal.c ./puzzles.h ./latin.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ unruly.o: ./unruly.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ unruly-icon.o: icons/unruly-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ unruly5.o: ./unruly.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ unruly2.o: ./unruly.c ./puzzles.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ untangle.o: ./untangle.c ./puzzles.h ./tree234.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ untangle-icon.o: icons/untangle-icon.c $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ untangl3.o: ./untangle.c ./puzzles.h ./tree234.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ version.o: ./version.c ./version.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ windows.o: ./windows.c ./puzzles.h ./resource.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ windows1.o: ./windows.c ./puzzles.h ./resource.h $(CC) $(ALL_CFLAGS) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ clean:: rm -f *.o fifteensolver fillingsolver galaxiespicture galaxiessolver keensolver latincheck lightupsolver loopysolver magnetssolver mapsolver mineobfusc obfusc patternpicture patternsolver pearlbench signpostsolver singlessolver slantsolver solosolver tentssolver towerssolver unequalsolver unrulysolver rm -rf *.app puzzles-20170606.272beef/Makefile.emcc0000644000175000017500000010311413115375145016237 0ustar simonsimon# Makefile for puzzles using Emscripten. Requires GNU make. # # This file was created by `mkfiles.pl' from the `Recipe' file. # DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead. # This can be set on the command line to point at the emcc command, # if it is not on your PATH. EMCC = emcc CFLAGS = -DSLOW_SYSTEM -I./ -Iicons/ all: $(OUTPREFIX)blackbox.js $(OUTPREFIX)bridges.js $(OUTPREFIX)cube.js \ $(OUTPREFIX)dominosa.js $(OUTPREFIX)fifteen.js \ $(OUTPREFIX)filling.js $(OUTPREFIX)flip.js \ $(OUTPREFIX)flood.js $(OUTPREFIX)galaxies.js \ $(OUTPREFIX)guess.js $(OUTPREFIX)inertia.js \ $(OUTPREFIX)keen.js $(OUTPREFIX)lightup.js \ $(OUTPREFIX)loopy.js $(OUTPREFIX)magnets.js \ $(OUTPREFIX)map.js $(OUTPREFIX)mines.js $(OUTPREFIX)net.js \ $(OUTPREFIX)netslide.js $(OUTPREFIX)nullgame.js \ $(OUTPREFIX)palisade.js $(OUTPREFIX)pattern.js \ $(OUTPREFIX)pearl.js $(OUTPREFIX)pegs.js \ $(OUTPREFIX)range.js $(OUTPREFIX)rect.js \ $(OUTPREFIX)samegame.js $(OUTPREFIX)signpost.js \ $(OUTPREFIX)singles.js $(OUTPREFIX)sixteen.js \ $(OUTPREFIX)slant.js $(OUTPREFIX)solo.js \ $(OUTPREFIX)tents.js $(OUTPREFIX)towers.js \ $(OUTPREFIX)tracks.js $(OUTPREFIX)twiddle.js \ $(OUTPREFIX)undead.js $(OUTPREFIX)unequal.js \ $(OUTPREFIX)unruly.js $(OUTPREFIX)untangle.js $(OUTPREFIX)blackbox.js: blackbox.o blackbox-icon.o drawing.o emcc.o \ malloc.o midend.o misc.o printing.o ps.o random.o version.o \ emccpre.js emcclib.js emccx.json $(EMCC) -o $(OUTPREFIX)blackbox.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" blackbox.o blackbox-icon.o drawing.o emcc.o malloc.o midend.o misc.o printing.o ps.o random.o version.o $(OUTPREFIX)bridges.js: bridges.o bridges-icon.o drawing.o dsf.o findloop.o \ emcc.o malloc.o midend.o misc.o printing.o ps.o random.o \ version.o emccpre.js emcclib.js emccx.json $(EMCC) -o $(OUTPREFIX)bridges.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" bridges.o bridges-icon.o drawing.o dsf.o findloop.o emcc.o malloc.o midend.o misc.o printing.o ps.o random.o version.o $(OUTPREFIX)cube.js: cube.o cube-icon.o drawing.o emcc.o malloc.o midend.o \ misc.o printing.o ps.o random.o version.o emccpre.js \ emcclib.js emccx.json $(EMCC) -o $(OUTPREFIX)cube.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" cube.o cube-icon.o drawing.o emcc.o malloc.o midend.o misc.o printing.o ps.o random.o version.o $(OUTPREFIX)dominosa.js: dominosa.o dominosa-icon.o drawing.o emcc.o \ laydomino.o malloc.o midend.o misc.o printing.o ps.o \ random.o version.o emccpre.js emcclib.js emccx.json $(EMCC) -o $(OUTPREFIX)dominosa.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" dominosa.o dominosa-icon.o drawing.o emcc.o laydomino.o malloc.o midend.o misc.o printing.o ps.o random.o version.o $(OUTPREFIX)fifteen.js: drawing.o fifteen.o fifteen-icon.o emcc.o malloc.o \ midend.o misc.o printing.o ps.o random.o version.o \ emccpre.js emcclib.js emccx.json $(EMCC) -o $(OUTPREFIX)fifteen.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" drawing.o fifteen.o fifteen-icon.o emcc.o malloc.o midend.o misc.o printing.o ps.o random.o version.o $(OUTPREFIX)filling.js: drawing.o dsf.o filling.o filling-icon.o emcc.o \ malloc.o midend.o misc.o printing.o ps.o random.o version.o \ emccpre.js emcclib.js emccx.json $(EMCC) -o $(OUTPREFIX)filling.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" drawing.o dsf.o filling.o filling-icon.o emcc.o malloc.o midend.o misc.o printing.o ps.o random.o version.o $(OUTPREFIX)flip.js: drawing.o flip.o flip-icon.o emcc.o malloc.o midend.o \ misc.o printing.o ps.o random.o tree234.o version.o \ emccpre.js emcclib.js emccx.json $(EMCC) -o $(OUTPREFIX)flip.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" drawing.o flip.o flip-icon.o emcc.o malloc.o midend.o misc.o printing.o ps.o random.o tree234.o version.o $(OUTPREFIX)flood.js: drawing.o flood.o flood-icon.o emcc.o malloc.o \ midend.o misc.o printing.o ps.o random.o version.o \ emccpre.js emcclib.js emccx.json $(EMCC) -o $(OUTPREFIX)flood.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" drawing.o flood.o flood-icon.o emcc.o malloc.o midend.o misc.o printing.o ps.o random.o version.o $(OUTPREFIX)galaxies.js: drawing.o dsf.o galaxies.o galaxies-icon.o emcc.o \ malloc.o midend.o misc.o printing.o ps.o random.o version.o \ emccpre.js emcclib.js emccx.json $(EMCC) -o $(OUTPREFIX)galaxies.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" drawing.o dsf.o galaxies.o galaxies-icon.o emcc.o malloc.o midend.o misc.o printing.o ps.o random.o version.o $(OUTPREFIX)guess.js: drawing.o emcc.o guess.o guess-icon.o malloc.o \ midend.o misc.o printing.o ps.o random.o version.o \ emccpre.js emcclib.js emccx.json $(EMCC) -o $(OUTPREFIX)guess.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" drawing.o emcc.o guess.o guess-icon.o malloc.o midend.o misc.o printing.o ps.o random.o version.o $(OUTPREFIX)inertia.js: drawing.o emcc.o inertia.o inertia-icon.o malloc.o \ midend.o misc.o printing.o ps.o random.o version.o \ emccpre.js emcclib.js emccx.json $(EMCC) -o $(OUTPREFIX)inertia.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" drawing.o emcc.o inertia.o inertia-icon.o malloc.o midend.o misc.o printing.o ps.o random.o version.o $(OUTPREFIX)keen.js: drawing.o dsf.o emcc.o keen.o keen-icon.o latin.o \ malloc.o maxflow.o midend.o misc.o printing.o ps.o random.o \ tree234.o version.o emccpre.js emcclib.js emccx.json $(EMCC) -o $(OUTPREFIX)keen.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" drawing.o dsf.o emcc.o keen.o keen-icon.o latin.o malloc.o maxflow.o midend.o misc.o printing.o ps.o random.o tree234.o version.o $(OUTPREFIX)lightup.js: combi.o drawing.o emcc.o lightup.o lightup-icon.o \ malloc.o midend.o misc.o printing.o ps.o random.o version.o \ emccpre.js emcclib.js emccx.json $(EMCC) -o $(OUTPREFIX)lightup.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" combi.o drawing.o emcc.o lightup.o lightup-icon.o malloc.o midend.o misc.o printing.o ps.o random.o version.o $(OUTPREFIX)loopy.js: drawing.o dsf.o grid.o emcc.o loopgen.o loopy.o \ loopy-icon.o malloc.o midend.o misc.o penrose.o printing.o \ ps.o random.o tree234.o version.o emccpre.js emcclib.js \ emccx.json $(EMCC) -o $(OUTPREFIX)loopy.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" drawing.o dsf.o grid.o emcc.o loopgen.o loopy.o loopy-icon.o malloc.o midend.o misc.o penrose.o printing.o ps.o random.o tree234.o version.o $(OUTPREFIX)magnets.js: drawing.o emcc.o laydomino.o magnets.o \ magnets-icon.o malloc.o midend.o misc.o printing.o ps.o \ random.o version.o emccpre.js emcclib.js emccx.json $(EMCC) -o $(OUTPREFIX)magnets.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" drawing.o emcc.o laydomino.o magnets.o magnets-icon.o malloc.o midend.o misc.o printing.o ps.o random.o version.o $(OUTPREFIX)map.js: drawing.o dsf.o emcc.o malloc.o map.o map-icon.o \ midend.o misc.o printing.o ps.o random.o version.o \ emccpre.js emcclib.js emccx.json $(EMCC) -o $(OUTPREFIX)map.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" drawing.o dsf.o emcc.o malloc.o map.o map-icon.o midend.o misc.o printing.o ps.o random.o version.o $(OUTPREFIX)mines.js: drawing.o emcc.o malloc.o midend.o mines.o \ mines-icon.o misc.o printing.o ps.o random.o tree234.o \ version.o emccpre.js emcclib.js emccx.json $(EMCC) -o $(OUTPREFIX)mines.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" drawing.o emcc.o malloc.o midend.o mines.o mines-icon.o misc.o printing.o ps.o random.o tree234.o version.o $(OUTPREFIX)net.js: drawing.o dsf.o findloop.o emcc.o malloc.o midend.o \ misc.o net.o net-icon.o printing.o ps.o random.o tree234.o \ version.o emccpre.js emcclib.js emccx.json $(EMCC) -o $(OUTPREFIX)net.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" drawing.o dsf.o findloop.o emcc.o malloc.o midend.o misc.o net.o net-icon.o printing.o ps.o random.o tree234.o version.o $(OUTPREFIX)netslide.js: drawing.o emcc.o malloc.o midend.o misc.o \ netslide.o netslide-icon.o printing.o ps.o random.o \ tree234.o version.o emccpre.js emcclib.js emccx.json $(EMCC) -o $(OUTPREFIX)netslide.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" drawing.o emcc.o malloc.o midend.o misc.o netslide.o netslide-icon.o printing.o ps.o random.o tree234.o version.o $(OUTPREFIX)nullgame.js: drawing.o emcc.o malloc.o midend.o misc.o no-icon.o \ nullgame.o printing.o ps.o random.o version.o emccpre.js \ emcclib.js emccx.json $(EMCC) -o $(OUTPREFIX)nullgame.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" drawing.o emcc.o malloc.o midend.o misc.o no-icon.o nullgame.o printing.o ps.o random.o version.o $(OUTPREFIX)palisade.js: divvy.o drawing.o dsf.o emcc.o malloc.o midend.o \ misc.o palisade.o palisade-icon.o printing.o ps.o random.o \ version.o emccpre.js emcclib.js emccx.json $(EMCC) -o $(OUTPREFIX)palisade.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" divvy.o drawing.o dsf.o emcc.o malloc.o midend.o misc.o palisade.o palisade-icon.o printing.o ps.o random.o version.o $(OUTPREFIX)pattern.js: drawing.o emcc.o malloc.o midend.o misc.o pattern.o \ pattern-icon.o printing.o ps.o random.o version.o emccpre.js \ emcclib.js emccx.json $(EMCC) -o $(OUTPREFIX)pattern.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" drawing.o emcc.o malloc.o midend.o misc.o pattern.o pattern-icon.o printing.o ps.o random.o version.o $(OUTPREFIX)pearl.js: drawing.o dsf.o grid.o emcc.o loopgen.o malloc.o \ midend.o misc.o pearl.o pearl-icon.o penrose.o printing.o \ ps.o random.o tdq.o tree234.o version.o emccpre.js \ emcclib.js emccx.json $(EMCC) -o $(OUTPREFIX)pearl.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" drawing.o dsf.o grid.o emcc.o loopgen.o malloc.o midend.o misc.o pearl.o pearl-icon.o penrose.o printing.o ps.o random.o tdq.o tree234.o version.o $(OUTPREFIX)pegs.js: drawing.o emcc.o malloc.o midend.o misc.o pegs.o \ pegs-icon.o printing.o ps.o random.o tree234.o version.o \ emccpre.js emcclib.js emccx.json $(EMCC) -o $(OUTPREFIX)pegs.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" drawing.o emcc.o malloc.o midend.o misc.o pegs.o pegs-icon.o printing.o ps.o random.o tree234.o version.o $(OUTPREFIX)range.js: drawing.o dsf.o emcc.o malloc.o midend.o misc.o \ printing.o ps.o random.o range.o range-icon.o version.o \ emccpre.js emcclib.js emccx.json $(EMCC) -o $(OUTPREFIX)range.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" drawing.o dsf.o emcc.o malloc.o midend.o misc.o printing.o ps.o random.o range.o range-icon.o version.o $(OUTPREFIX)rect.js: drawing.o emcc.o malloc.o midend.o misc.o printing.o \ ps.o random.o rect.o rect-icon.o version.o emccpre.js \ emcclib.js emccx.json $(EMCC) -o $(OUTPREFIX)rect.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" drawing.o emcc.o malloc.o midend.o misc.o printing.o ps.o random.o rect.o rect-icon.o version.o $(OUTPREFIX)samegame.js: drawing.o emcc.o malloc.o midend.o misc.o \ printing.o ps.o random.o samegame.o samegame-icon.o \ version.o emccpre.js emcclib.js emccx.json $(EMCC) -o $(OUTPREFIX)samegame.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" drawing.o emcc.o malloc.o midend.o misc.o printing.o ps.o random.o samegame.o samegame-icon.o version.o $(OUTPREFIX)signpost.js: drawing.o dsf.o emcc.o malloc.o midend.o misc.o \ printing.o ps.o random.o signpost.o signpost-icon.o \ version.o emccpre.js emcclib.js emccx.json $(EMCC) -o $(OUTPREFIX)signpost.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" drawing.o dsf.o emcc.o malloc.o midend.o misc.o printing.o ps.o random.o signpost.o signpost-icon.o version.o $(OUTPREFIX)singles.js: drawing.o dsf.o emcc.o latin.o malloc.o maxflow.o \ midend.o misc.o printing.o ps.o random.o singles.o \ singles-icon.o tree234.o version.o emccpre.js emcclib.js \ emccx.json $(EMCC) -o $(OUTPREFIX)singles.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" drawing.o dsf.o emcc.o latin.o malloc.o maxflow.o midend.o misc.o printing.o ps.o random.o singles.o singles-icon.o tree234.o version.o $(OUTPREFIX)sixteen.js: drawing.o emcc.o malloc.o midend.o misc.o printing.o \ ps.o random.o sixteen.o sixteen-icon.o version.o emccpre.js \ emcclib.js emccx.json $(EMCC) -o $(OUTPREFIX)sixteen.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" drawing.o emcc.o malloc.o midend.o misc.o printing.o ps.o random.o sixteen.o sixteen-icon.o version.o $(OUTPREFIX)slant.js: drawing.o dsf.o findloop.o emcc.o malloc.o midend.o \ misc.o printing.o ps.o random.o slant.o slant-icon.o \ version.o emccpre.js emcclib.js emccx.json $(EMCC) -o $(OUTPREFIX)slant.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" drawing.o dsf.o findloop.o emcc.o malloc.o midend.o misc.o printing.o ps.o random.o slant.o slant-icon.o version.o $(OUTPREFIX)solo.js: divvy.o drawing.o dsf.o emcc.o malloc.o midend.o misc.o \ printing.o ps.o random.o solo.o solo-icon.o version.o \ emccpre.js emcclib.js emccx.json $(EMCC) -o $(OUTPREFIX)solo.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" divvy.o drawing.o dsf.o emcc.o malloc.o midend.o misc.o printing.o ps.o random.o solo.o solo-icon.o version.o $(OUTPREFIX)tents.js: drawing.o dsf.o emcc.o malloc.o maxflow.o midend.o \ misc.o printing.o ps.o random.o tents.o tents-icon.o \ version.o emccpre.js emcclib.js emccx.json $(EMCC) -o $(OUTPREFIX)tents.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" drawing.o dsf.o emcc.o malloc.o maxflow.o midend.o misc.o printing.o ps.o random.o tents.o tents-icon.o version.o $(OUTPREFIX)towers.js: drawing.o emcc.o latin.o malloc.o maxflow.o midend.o \ misc.o printing.o ps.o random.o towers.o towers-icon.o \ tree234.o version.o emccpre.js emcclib.js emccx.json $(EMCC) -o $(OUTPREFIX)towers.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" drawing.o emcc.o latin.o malloc.o maxflow.o midend.o misc.o printing.o ps.o random.o towers.o towers-icon.o tree234.o version.o $(OUTPREFIX)tracks.js: drawing.o dsf.o findloop.o emcc.o malloc.o midend.o \ misc.o printing.o ps.o random.o tracks.o tracks-icon.o \ version.o emccpre.js emcclib.js emccx.json $(EMCC) -o $(OUTPREFIX)tracks.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" drawing.o dsf.o findloop.o emcc.o malloc.o midend.o misc.o printing.o ps.o random.o tracks.o tracks-icon.o version.o $(OUTPREFIX)twiddle.js: drawing.o emcc.o malloc.o midend.o misc.o printing.o \ ps.o random.o twiddle.o twiddle-icon.o version.o emccpre.js \ emcclib.js emccx.json $(EMCC) -o $(OUTPREFIX)twiddle.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" drawing.o emcc.o malloc.o midend.o misc.o printing.o ps.o random.o twiddle.o twiddle-icon.o version.o $(OUTPREFIX)undead.js: drawing.o emcc.o malloc.o midend.o misc.o printing.o \ ps.o random.o undead.o undead-icon.o version.o emccpre.js \ emcclib.js emccx.json $(EMCC) -o $(OUTPREFIX)undead.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" drawing.o emcc.o malloc.o midend.o misc.o printing.o ps.o random.o undead.o undead-icon.o version.o $(OUTPREFIX)unequal.js: drawing.o emcc.o latin.o malloc.o maxflow.o midend.o \ misc.o printing.o ps.o random.o tree234.o unequal.o \ unequal-icon.o version.o emccpre.js emcclib.js emccx.json $(EMCC) -o $(OUTPREFIX)unequal.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" drawing.o emcc.o latin.o malloc.o maxflow.o midend.o misc.o printing.o ps.o random.o tree234.o unequal.o unequal-icon.o version.o $(OUTPREFIX)unruly.js: drawing.o emcc.o malloc.o midend.o misc.o printing.o \ ps.o random.o unruly.o unruly-icon.o version.o emccpre.js \ emcclib.js emccx.json $(EMCC) -o $(OUTPREFIX)unruly.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" drawing.o emcc.o malloc.o midend.o misc.o printing.o ps.o random.o unruly.o unruly-icon.o version.o $(OUTPREFIX)untangle.js: drawing.o emcc.o malloc.o midend.o misc.o \ printing.o ps.o random.o tree234.o untangle.o \ untangle-icon.o version.o emccpre.js emcclib.js emccx.json $(EMCC) -o $(OUTPREFIX)untangle.js -O2 -s ASM_JS=1 --pre-js emccpre.js --js-library emcclib.js -s EXPORTED_FUNCTIONS="`sed 's://.*::' emccx.json | tr -d ' \n'`" drawing.o emcc.o malloc.o midend.o misc.o printing.o ps.o random.o tree234.o untangle.o untangle-icon.o version.o blackbox.o: ./blackbox.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ blackbox-icon.o: icons/blackbox-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ blackbo3.o: ./blackbox.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ bridges.o: ./bridges.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ bridges-icon.o: icons/bridges-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ bridges3.o: ./bridges.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ combi.o: ./combi.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ cube.o: ./cube.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ cube-icon.o: icons/cube-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ cube3.o: ./cube.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ divvy.o: ./divvy.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ dominosa.o: ./dominosa.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ dominosa-icon.o: icons/dominosa-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ dominos3.o: ./dominosa.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ drawing.o: ./drawing.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ dsf.o: ./dsf.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ fifteen.o: ./fifteen.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ fifteen-icon.o: icons/fifteen-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ fifteen5.o: ./fifteen.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ fifteen2.o: ./fifteen.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ filling.o: ./filling.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ filling-icon.o: icons/filling-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ filling5.o: ./filling.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ filling2.o: ./filling.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ findloop.o: ./findloop.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ flip.o: ./flip.c ./puzzles.h ./tree234.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ flip-icon.o: icons/flip-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ flip3.o: ./flip.c ./puzzles.h ./tree234.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ flood.o: ./flood.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ flood-icon.o: icons/flood-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ flood3.o: ./flood.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ galaxies.o: ./galaxies.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ galaxies-icon.o: icons/galaxies-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ galaxie7.o: ./galaxies.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ galaxie4.o: ./galaxies.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DSTANDALONE_PICTURE_GENERATOR -c $< -o $@ galaxie2.o: ./galaxies.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ grid.o: ./grid.c ./puzzles.h ./tree234.h ./grid.h ./penrose.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ emcc.o: ./emcc.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ guess.o: ./guess.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ guess-icon.o: icons/guess-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ guess3.o: ./guess.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ inertia.o: ./inertia.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ inertia-icon.o: icons/inertia-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ inertia3.o: ./inertia.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ keen.o: ./keen.c ./puzzles.h ./latin.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ keen-icon.o: icons/keen-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ keen5.o: ./keen.c ./puzzles.h ./latin.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ keen2.o: ./keen.c ./puzzles.h ./latin.h $(EMCC) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ latin.o: ./latin.c ./puzzles.h ./tree234.h ./maxflow.h ./latin.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ latin8.o: ./latin.c ./puzzles.h ./tree234.h ./maxflow.h ./latin.h $(EMCC) $(CFLAGS) $(XFLAGS) -DSTANDALONE_LATIN_TEST -c $< -o $@ latin6.o: ./latin.c ./puzzles.h ./tree234.h ./maxflow.h ./latin.h $(EMCC) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ laydomino.o: ./laydomino.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ lightup.o: ./lightup.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ lightup-icon.o: icons/lightup-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ lightup5.o: ./lightup.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ lightup2.o: ./lightup.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ list.o: ./list.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ loopgen.o: ./loopgen.c ./puzzles.h ./tree234.h ./grid.h ./loopgen.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ loopy.o: ./loopy.c ./puzzles.h ./tree234.h ./grid.h ./loopgen.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ loopy-icon.o: icons/loopy-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ loopy5.o: ./loopy.c ./puzzles.h ./tree234.h ./grid.h ./loopgen.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ loopy2.o: ./loopy.c ./puzzles.h ./tree234.h ./grid.h ./loopgen.h $(EMCC) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ magnets.o: ./magnets.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ magnets-icon.o: icons/magnets-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ magnets5.o: ./magnets.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ magnets2.o: ./magnets.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ malloc.o: ./malloc.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ map.o: ./map.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ map-icon.o: icons/map-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ map5.o: ./map.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ map2.o: ./map.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ maxflow.o: ./maxflow.c ./maxflow.h ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ midend.o: ./midend.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ mines.o: ./mines.c ./tree234.h ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ mines-icon.o: icons/mines-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ mines5.o: ./mines.c ./tree234.h ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ mines2.o: ./mines.c ./tree234.h ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DSTANDALONE_OBFUSCATOR -c $< -o $@ misc.o: ./misc.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ net.o: ./net.c ./puzzles.h ./tree234.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ net-icon.o: icons/net-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ net3.o: ./net.c ./puzzles.h ./tree234.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ netslide.o: ./netslide.c ./puzzles.h ./tree234.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ netslide-icon.o: icons/netslide-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ netslid3.o: ./netslide.c ./puzzles.h ./tree234.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ no-icon.o: ./no-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ nullfe.o: ./nullfe.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ nullgame.o: ./nullgame.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ obfusc.o: ./obfusc.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ osx.o: ./osx.m ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ palisade.o: ./palisade.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ palisade-icon.o: icons/palisade-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ palisad3.o: ./palisade.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ pattern.o: ./pattern.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ pattern-icon.o: icons/pattern-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ pattern7.o: ./pattern.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ pattern4.o: ./pattern.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DSTANDALONE_PICTURE_GENERATOR -c $< -o $@ pattern2.o: ./pattern.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ pearl.o: ./pearl.c ./puzzles.h ./grid.h ./loopgen.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ pearl-icon.o: icons/pearl-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ pearl5.o: ./pearl.c ./puzzles.h ./grid.h ./loopgen.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ pearl2.o: ./pearl.c ./puzzles.h ./grid.h ./loopgen.h $(EMCC) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ pegs.o: ./pegs.c ./puzzles.h ./tree234.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ pegs-icon.o: icons/pegs-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ pegs3.o: ./pegs.c ./puzzles.h ./tree234.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ penrose.o: ./penrose.c ./puzzles.h ./penrose.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ printing.o: ./printing.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ ps.o: ./ps.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ random.o: ./random.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ range.o: ./range.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ range-icon.o: icons/range-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ range3.o: ./range.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ rect.o: ./rect.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ rect-icon.o: icons/rect-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ rect3.o: ./rect.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ samegame.o: ./samegame.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ samegame-icon.o: icons/samegame-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ samegam3.o: ./samegame.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ signpost.o: ./signpost.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ signpost-icon.o: icons/signpost-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ signpos5.o: ./signpost.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ signpos2.o: ./signpost.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ singles.o: ./singles.c ./puzzles.h ./latin.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ singles-icon.o: icons/singles-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ singles5.o: ./singles.c ./puzzles.h ./latin.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ singles3.o: ./singles.c ./puzzles.h ./latin.h $(EMCC) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ sixteen.o: ./sixteen.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ sixteen-icon.o: icons/sixteen-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ sixteen3.o: ./sixteen.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ slant.o: ./slant.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ slant-icon.o: icons/slant-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ slant5.o: ./slant.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ slant2.o: ./slant.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ solo.o: ./solo.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ solo-icon.o: icons/solo-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ solo5.o: ./solo.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ solo2.o: ./solo.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ tdq.o: ./tdq.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ tents.o: ./tents.c ./puzzles.h ./maxflow.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ tents-icon.o: icons/tents-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ tents5.o: ./tents.c ./puzzles.h ./maxflow.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ tents3.o: ./tents.c ./puzzles.h ./maxflow.h $(EMCC) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ towers.o: ./towers.c ./puzzles.h ./latin.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ towers-icon.o: icons/towers-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ towers5.o: ./towers.c ./puzzles.h ./latin.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ towers2.o: ./towers.c ./puzzles.h ./latin.h $(EMCC) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ tracks.o: ./tracks.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ tracks-icon.o: icons/tracks-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ tracks3.o: ./tracks.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ tree234.o: ./tree234.c ./tree234.h ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ twiddle.o: ./twiddle.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ twiddle-icon.o: icons/twiddle-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ twiddle3.o: ./twiddle.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ undead.o: ./undead.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ undead-icon.o: icons/undead-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ undead3.o: ./undead.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ unequal.o: ./unequal.c ./puzzles.h ./latin.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ unequal-icon.o: icons/unequal-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ unequal5.o: ./unequal.c ./puzzles.h ./latin.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ unequal2.o: ./unequal.c ./puzzles.h ./latin.h $(EMCC) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ unruly.o: ./unruly.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ unruly-icon.o: icons/unruly-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ unruly5.o: ./unruly.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ unruly2.o: ./unruly.c ./puzzles.h $(EMCC) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ untangle.o: ./untangle.c ./puzzles.h ./tree234.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ untangle-icon.o: icons/untangle-icon.c $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ untangl3.o: ./untangle.c ./puzzles.h ./tree234.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ version.o: ./version.c ./version.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ windows.o: ./windows.c ./puzzles.h ./resource.h $(EMCC) $(CFLAGS) $(XFLAGS) -c $< -o $@ windows1.o: ./windows.c ./puzzles.h ./resource.h $(EMCC) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ clean: rm -rf *.o $(OUTPREFIX)blackbox.js $(OUTPREFIX)bridges.js $(OUTPREFIX)cube.js $(OUTPREFIX)dominosa.js $(OUTPREFIX)fifteen.js $(OUTPREFIX)filling.js $(OUTPREFIX)flip.js $(OUTPREFIX)flood.js $(OUTPREFIX)galaxies.js $(OUTPREFIX)guess.js $(OUTPREFIX)inertia.js $(OUTPREFIX)keen.js $(OUTPREFIX)lightup.js $(OUTPREFIX)loopy.js $(OUTPREFIX)magnets.js $(OUTPREFIX)map.js $(OUTPREFIX)mines.js $(OUTPREFIX)net.js $(OUTPREFIX)netslide.js $(OUTPREFIX)nullgame.js $(OUTPREFIX)palisade.js $(OUTPREFIX)pattern.js $(OUTPREFIX)pearl.js $(OUTPREFIX)pegs.js $(OUTPREFIX)range.js $(OUTPREFIX)rect.js $(OUTPREFIX)samegame.js $(OUTPREFIX)signpost.js $(OUTPREFIX)singles.js $(OUTPREFIX)sixteen.js $(OUTPREFIX)slant.js $(OUTPREFIX)solo.js $(OUTPREFIX)tents.js $(OUTPREFIX)towers.js $(OUTPREFIX)tracks.js $(OUTPREFIX)twiddle.js $(OUTPREFIX)undead.js $(OUTPREFIX)unequal.js $(OUTPREFIX)unruly.js $(OUTPREFIX)untangle.js puzzles-20170606.272beef/Makefile.doc0000644000175000017500000000077213115373615016103 0ustar simonsimonall: puzzles.chm puzzles.hlp puzzles.txt HACKING preprocessed.but: puzzles.but sed 's/PREFIX-/$(BINPREFIX)/g' puzzles.but > preprocessed.but puzzles.chm: preprocessed.but halibut --chm=puzzles.chm preprocessed.but puzzles.hlp: preprocessed.but halibut --winhelp=puzzles.hlp preprocessed.but puzzles.txt: preprocessed.but halibut --text=puzzles.txt preprocessed.but HACKING: devel.but halibut --text=HACKING devel.but clean: rm -f puzzles.hlp puzzles.txt preprocessed.but HACKING *.html *.hh[pck] puzzles-20170606.272beef/Makefile.cyg0000644000175000017500000012471213115375145016121 0ustar simonsimon# Makefile for puzzles under cygwin. # # This file was created by `mkfiles.pl' from the `Recipe' file. # DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead. # You can define this path to point at your tools if you need to # TOOLPATH = c:\cygwin\bin\ # or similar, if you're running Windows # TOOLPATH = /pkg/mingw32msvc/i386-mingw32msvc/bin/ CC = $(TOOLPATH)gcc RC = $(TOOLPATH)windres # Uncomment the following two lines to compile under Winelib # CC = winegcc # RC = wrc # You may also need to tell windres where to find include files: # RCINC = --include-dir c:\cygwin\include\ CFLAGS = -mno-cygwin -Wall -O2 -D_WINDOWS -DDEBUG -DWIN32S_COMPAT \ -D_NO_OLDNAMES -DNO_MULTIMON -DNO_HTMLHELP -I./ -Iicons/ LDFLAGS = -mno-cygwin -s RCFLAGS = $(RCINC) --define WIN32=1 --define _WIN32=1 --define WINVER=0x0400 \ --define MINGW32_FIX=1 --include ./ --include icons/ all: blackbox.exe bridges.exe cube.exe dominosa.exe fifteen.exe \ fifteensolver.exe filling.exe fillingsolver.exe flip.exe \ flood.exe galaxies.exe galaxiespicture.exe \ galaxiessolver.exe guess.exe inertia.exe keen.exe \ keensolver.exe latincheck.exe lightup.exe lightupsolver.exe \ loopy.exe loopysolver.exe magnets.exe magnetssolver.exe \ map.exe mapsolver.exe mineobfusc.exe mines.exe netgame.exe \ netslide.exe nullgame.exe palisade.exe pattern.exe \ patternpicture.exe patternsolver.exe pearl.exe \ pearlbench.exe pegs.exe puzzles.exe range.exe rect.exe \ samegame.exe signpost.exe signpostsolver.exe singles.exe \ singlessolver.exe sixteen.exe slant.exe slantsolver.exe \ solo.exe solosolver.exe tents.exe tentssolver.exe towers.exe \ towerssolver.exe tracks.exe twiddle.exe undead.exe \ unequal.exe unequalsolver.exe unruly.exe unrulysolver.exe \ untangle.exe blackbox.exe: blackbox.o blackbox.res.o drawing.o malloc.o midend.o misc.o \ printing.o random.o version.o windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,blackbox.map blackbox.o \ blackbox.res.o drawing.o malloc.o midend.o misc.o printing.o \ random.o version.o windows.o -lcomctl32 -lcomdlg32 -lgdi32 \ -luser32 -lwinspool bridges.exe: bridges.o bridges.res.o drawing.o dsf.o findloop.o malloc.o \ midend.o misc.o printing.o random.o version.o windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,bridges.map bridges.o \ bridges.res.o drawing.o dsf.o findloop.o malloc.o midend.o \ misc.o printing.o random.o version.o windows.o -lcomctl32 \ -lcomdlg32 -lgdi32 -luser32 -lwinspool cube.exe: cube.o cube.res.o drawing.o malloc.o midend.o misc.o printing.o \ random.o version.o windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,cube.map cube.o cube.res.o \ drawing.o malloc.o midend.o misc.o printing.o random.o \ version.o windows.o -lcomctl32 -lcomdlg32 -lgdi32 -luser32 \ -lwinspool dominosa.exe: dominosa.o dominosa.res.o drawing.o laydomino.o malloc.o \ midend.o misc.o printing.o random.o version.o windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,dominosa.map dominosa.o \ dominosa.res.o drawing.o laydomino.o malloc.o midend.o \ misc.o printing.o random.o version.o windows.o -lcomctl32 \ -lcomdlg32 -lgdi32 -luser32 -lwinspool fifteen.exe: drawing.o fifteen.o fifteen.res.o malloc.o midend.o misc.o \ printing.o random.o version.o windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,fifteen.map drawing.o \ fifteen.o fifteen.res.o malloc.o midend.o misc.o printing.o \ random.o version.o windows.o -lcomctl32 -lcomdlg32 -lgdi32 \ -luser32 -lwinspool fifteensolver.exe: fifteen2.o malloc.o misc.o nullfe.o random.o $(CC) $(LDFLAGS) -o $@ -Wl,-Map,fifteensolver.map fifteen2.o \ malloc.o misc.o nullfe.o random.o filling.exe: drawing.o dsf.o filling.o filling.res.o malloc.o midend.o \ misc.o printing.o random.o version.o windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,filling.map drawing.o \ dsf.o filling.o filling.res.o malloc.o midend.o misc.o \ printing.o random.o version.o windows.o -lcomctl32 \ -lcomdlg32 -lgdi32 -luser32 -lwinspool fillingsolver.exe: dsf.o filling2.o malloc.o misc.o nullfe.o random.o $(CC) $(LDFLAGS) -o $@ -Wl,-Map,fillingsolver.map dsf.o filling2.o \ malloc.o misc.o nullfe.o random.o flip.exe: drawing.o flip.o flip.res.o malloc.o midend.o misc.o printing.o \ random.o tree234.o version.o windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,flip.map drawing.o flip.o \ flip.res.o malloc.o midend.o misc.o printing.o random.o \ tree234.o version.o windows.o -lcomctl32 -lcomdlg32 -lgdi32 \ -luser32 -lwinspool flood.exe: drawing.o flood.o flood.res.o malloc.o midend.o misc.o printing.o \ random.o version.o windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,flood.map drawing.o \ flood.o flood.res.o malloc.o midend.o misc.o printing.o \ random.o version.o windows.o -lcomctl32 -lcomdlg32 -lgdi32 \ -luser32 -lwinspool galaxies.exe: drawing.o dsf.o galaxies.o galaxies.res.o malloc.o midend.o \ misc.o printing.o random.o version.o windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,galaxies.map drawing.o \ dsf.o galaxies.o galaxies.res.o malloc.o midend.o misc.o \ printing.o random.o version.o windows.o -lcomctl32 \ -lcomdlg32 -lgdi32 -luser32 -lwinspool galaxiespicture.exe: dsf.o galaxie4.o malloc.o misc.o nullfe.o random.o $(CC) $(LDFLAGS) -o $@ -Wl,-Map,galaxiespicture.map dsf.o galaxie4.o \ malloc.o misc.o nullfe.o random.o galaxiessolver.exe: dsf.o galaxie2.o malloc.o misc.o nullfe.o random.o $(CC) $(LDFLAGS) -o $@ -Wl,-Map,galaxiessolver.map dsf.o galaxie2.o \ malloc.o misc.o nullfe.o random.o guess.exe: drawing.o guess.o guess.res.o malloc.o midend.o misc.o printing.o \ random.o version.o windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,guess.map drawing.o \ guess.o guess.res.o malloc.o midend.o misc.o printing.o \ random.o version.o windows.o -lcomctl32 -lcomdlg32 -lgdi32 \ -luser32 -lwinspool inertia.exe: drawing.o inertia.o inertia.res.o malloc.o midend.o misc.o \ printing.o random.o version.o windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,inertia.map drawing.o \ inertia.o inertia.res.o malloc.o midend.o misc.o printing.o \ random.o version.o windows.o -lcomctl32 -lcomdlg32 -lgdi32 \ -luser32 -lwinspool keen.exe: drawing.o dsf.o keen.o keen.res.o latin.o malloc.o maxflow.o \ midend.o misc.o printing.o random.o tree234.o version.o \ windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,keen.map drawing.o dsf.o \ keen.o keen.res.o latin.o malloc.o maxflow.o midend.o misc.o \ printing.o random.o tree234.o version.o windows.o -lcomctl32 \ -lcomdlg32 -lgdi32 -luser32 -lwinspool keensolver.exe: dsf.o keen2.o latin6.o malloc.o maxflow.o misc.o nullfe.o \ random.o tree234.o $(CC) $(LDFLAGS) -o $@ -Wl,-Map,keensolver.map dsf.o keen2.o \ latin6.o malloc.o maxflow.o misc.o nullfe.o random.o \ tree234.o latincheck.exe: latin8.o malloc.o maxflow.o misc.o nullfe.o random.o \ tree234.o $(CC) $(LDFLAGS) -o $@ -Wl,-Map,latincheck.map latin8.o malloc.o \ maxflow.o misc.o nullfe.o random.o tree234.o lightup.exe: combi.o drawing.o lightup.o lightup.res.o malloc.o midend.o \ misc.o printing.o random.o version.o windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,lightup.map combi.o \ drawing.o lightup.o lightup.res.o malloc.o midend.o misc.o \ printing.o random.o version.o windows.o -lcomctl32 \ -lcomdlg32 -lgdi32 -luser32 -lwinspool lightupsolver.exe: combi.o lightup2.o malloc.o misc.o nullfe.o random.o $(CC) $(LDFLAGS) -o $@ -Wl,-Map,lightupsolver.map combi.o lightup2.o \ malloc.o misc.o nullfe.o random.o loopy.exe: drawing.o dsf.o grid.o loopgen.o loopy.o loopy.res.o malloc.o \ midend.o misc.o penrose.o printing.o random.o tree234.o \ version.o windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,loopy.map drawing.o dsf.o \ grid.o loopgen.o loopy.o loopy.res.o malloc.o midend.o \ misc.o penrose.o printing.o random.o tree234.o version.o \ windows.o -lcomctl32 -lcomdlg32 -lgdi32 -luser32 -lwinspool loopysolver.exe: dsf.o grid.o loopgen.o loopy2.o malloc.o misc.o nullfe.o \ penrose.o random.o tree234.o $(CC) $(LDFLAGS) -o $@ -Wl,-Map,loopysolver.map dsf.o grid.o \ loopgen.o loopy2.o malloc.o misc.o nullfe.o penrose.o \ random.o tree234.o magnets.exe: drawing.o laydomino.o magnets.o magnets.res.o malloc.o midend.o \ misc.o printing.o random.o version.o windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,magnets.map drawing.o \ laydomino.o magnets.o magnets.res.o malloc.o midend.o misc.o \ printing.o random.o version.o windows.o -lcomctl32 \ -lcomdlg32 -lgdi32 -luser32 -lwinspool magnetssolver.exe: laydomino.o magnets2.o malloc.o misc.o nullfe.o random.o $(CC) $(LDFLAGS) -o $@ -Wl,-Map,magnetssolver.map laydomino.o \ magnets2.o malloc.o misc.o nullfe.o random.o map.exe: drawing.o dsf.o malloc.o map.o map.res.o midend.o misc.o printing.o \ random.o version.o windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,map.map drawing.o dsf.o \ malloc.o map.o map.res.o midend.o misc.o printing.o random.o \ version.o windows.o -lcomctl32 -lcomdlg32 -lgdi32 -luser32 \ -lwinspool mapsolver.exe: dsf.o malloc.o map2.o misc.o nullfe.o random.o $(CC) $(LDFLAGS) -o $@ -Wl,-Map,mapsolver.map dsf.o malloc.o map2.o \ misc.o nullfe.o random.o mineobfusc.exe: malloc.o mines2.o misc.o nullfe.o random.o tree234.o $(CC) $(LDFLAGS) -o $@ -Wl,-Map,mineobfusc.map malloc.o mines2.o \ misc.o nullfe.o random.o tree234.o mines.exe: drawing.o malloc.o midend.o mines.o mines.res.o misc.o printing.o \ random.o tree234.o version.o windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,mines.map drawing.o \ malloc.o midend.o mines.o mines.res.o misc.o printing.o \ random.o tree234.o version.o windows.o -lcomctl32 -lcomdlg32 \ -lgdi32 -luser32 -lwinspool netgame.exe: drawing.o dsf.o findloop.o malloc.o midend.o misc.o net.o \ net.res.o printing.o random.o tree234.o version.o windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,netgame.map drawing.o \ dsf.o findloop.o malloc.o midend.o misc.o net.o net.res.o \ printing.o random.o tree234.o version.o windows.o -lcomctl32 \ -lcomdlg32 -lgdi32 -luser32 -lwinspool netslide.exe: drawing.o malloc.o midend.o misc.o netslide.o netslide.res.o \ printing.o random.o tree234.o version.o windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,netslide.map drawing.o \ malloc.o midend.o misc.o netslide.o netslide.res.o \ printing.o random.o tree234.o version.o windows.o -lcomctl32 \ -lcomdlg32 -lgdi32 -luser32 -lwinspool nullgame.exe: drawing.o malloc.o midend.o misc.o noicon.res.o nullgame.o \ printing.o random.o version.o windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,nullgame.map drawing.o \ malloc.o midend.o misc.o noicon.res.o nullgame.o printing.o \ random.o version.o windows.o -lcomctl32 -lcomdlg32 -lgdi32 \ -luser32 -lwinspool palisade.exe: divvy.o drawing.o dsf.o malloc.o midend.o misc.o palisade.o \ palisade.res.o printing.o random.o version.o windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,palisade.map divvy.o \ drawing.o dsf.o malloc.o midend.o misc.o palisade.o \ palisade.res.o printing.o random.o version.o windows.o \ -lcomctl32 -lcomdlg32 -lgdi32 -luser32 -lwinspool pattern.exe: drawing.o malloc.o midend.o misc.o pattern.o pattern.res.o \ printing.o random.o version.o windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,pattern.map drawing.o \ malloc.o midend.o misc.o pattern.o pattern.res.o printing.o \ random.o version.o windows.o -lcomctl32 -lcomdlg32 -lgdi32 \ -luser32 -lwinspool patternpicture.exe: malloc.o misc.o nullfe.o pattern4.o random.o $(CC) $(LDFLAGS) -o $@ -Wl,-Map,patternpicture.map malloc.o misc.o \ nullfe.o pattern4.o random.o patternsolver.exe: malloc.o misc.o nullfe.o pattern2.o random.o $(CC) $(LDFLAGS) -o $@ -Wl,-Map,patternsolver.map malloc.o misc.o \ nullfe.o pattern2.o random.o pearl.exe: drawing.o dsf.o grid.o loopgen.o malloc.o midend.o misc.o pearl.o \ pearl.res.o penrose.o printing.o random.o tdq.o tree234.o \ version.o windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,pearl.map drawing.o dsf.o \ grid.o loopgen.o malloc.o midend.o misc.o pearl.o \ pearl.res.o penrose.o printing.o random.o tdq.o tree234.o \ version.o windows.o -lcomctl32 -lcomdlg32 -lgdi32 -luser32 \ -lwinspool pearlbench.exe: dsf.o grid.o loopgen.o malloc.o misc.o nullfe.o pearl2.o \ penrose.o random.o tdq.o tree234.o $(CC) $(LDFLAGS) -o $@ -Wl,-Map,pearlbench.map dsf.o grid.o \ loopgen.o malloc.o misc.o nullfe.o pearl2.o penrose.o \ random.o tdq.o tree234.o pegs.exe: drawing.o malloc.o midend.o misc.o pegs.o pegs.res.o printing.o \ random.o tree234.o version.o windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,pegs.map drawing.o \ malloc.o midend.o misc.o pegs.o pegs.res.o printing.o \ random.o tree234.o version.o windows.o -lcomctl32 -lcomdlg32 \ -lgdi32 -luser32 -lwinspool puzzles.exe: blackbo3.o bridges3.o combi.o cube3.o divvy.o dominos3.o \ drawing.o dsf.o fifteen5.o filling5.o findloop.o flip3.o \ flood3.o galaxie7.o grid.o guess3.o inertia3.o keen5.o \ latin.o laydomino.o lightup5.o list.o loopgen.o loopy5.o \ magnets5.o malloc.o map5.o maxflow.o midend.o mines5.o \ misc.o net3.o netslid3.o noicon.res.o palisad3.o pattern7.o \ pearl5.o pegs3.o penrose.o printing.o random.o range3.o \ rect3.o samegam3.o signpos5.o singles5.o sixteen3.o slant5.o \ solo5.o tdq.o tents5.o towers5.o tracks3.o tree234.o \ twiddle3.o undead3.o unequal5.o unruly5.o untangl3.o \ version.o windows1.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,puzzles.map blackbo3.o \ bridges3.o combi.o cube3.o divvy.o dominos3.o drawing.o \ dsf.o fifteen5.o filling5.o findloop.o flip3.o flood3.o \ galaxie7.o grid.o guess3.o inertia3.o keen5.o latin.o \ laydomino.o lightup5.o list.o loopgen.o loopy5.o magnets5.o \ malloc.o map5.o maxflow.o midend.o mines5.o misc.o net3.o \ netslid3.o noicon.res.o palisad3.o pattern7.o pearl5.o \ pegs3.o penrose.o printing.o random.o range3.o rect3.o \ samegam3.o signpos5.o singles5.o sixteen3.o slant5.o solo5.o \ tdq.o tents5.o towers5.o tracks3.o tree234.o twiddle3.o \ undead3.o unequal5.o unruly5.o untangl3.o version.o \ windows1.o -lcomctl32 -lcomdlg32 -lgdi32 -luser32 -lwinspool range.exe: drawing.o dsf.o malloc.o midend.o misc.o printing.o random.o \ range.o range.res.o version.o windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,range.map drawing.o dsf.o \ malloc.o midend.o misc.o printing.o random.o range.o \ range.res.o version.o windows.o -lcomctl32 -lcomdlg32 \ -lgdi32 -luser32 -lwinspool rect.exe: drawing.o malloc.o midend.o misc.o printing.o random.o rect.o \ rect.res.o version.o windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,rect.map drawing.o \ malloc.o midend.o misc.o printing.o random.o rect.o \ rect.res.o version.o windows.o -lcomctl32 -lcomdlg32 -lgdi32 \ -luser32 -lwinspool samegame.exe: drawing.o malloc.o midend.o misc.o printing.o random.o \ samegame.o samegame.res.o version.o windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,samegame.map drawing.o \ malloc.o midend.o misc.o printing.o random.o samegame.o \ samegame.res.o version.o windows.o -lcomctl32 -lcomdlg32 \ -lgdi32 -luser32 -lwinspool signpost.exe: drawing.o dsf.o malloc.o midend.o misc.o printing.o random.o \ signpost.o signpost.res.o version.o windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,signpost.map drawing.o \ dsf.o malloc.o midend.o misc.o printing.o random.o \ signpost.o signpost.res.o version.o windows.o -lcomctl32 \ -lcomdlg32 -lgdi32 -luser32 -lwinspool signpostsolver.exe: dsf.o malloc.o misc.o nullfe.o random.o signpos2.o $(CC) $(LDFLAGS) -o $@ -Wl,-Map,signpostsolver.map dsf.o malloc.o \ misc.o nullfe.o random.o signpos2.o singles.exe: drawing.o dsf.o latin.o malloc.o maxflow.o midend.o misc.o \ printing.o random.o singles.o singles.res.o tree234.o \ version.o windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,singles.map drawing.o \ dsf.o latin.o malloc.o maxflow.o midend.o misc.o printing.o \ random.o singles.o singles.res.o tree234.o version.o \ windows.o -lcomctl32 -lcomdlg32 -lgdi32 -luser32 -lwinspool singlessolver.exe: dsf.o latin.o malloc.o maxflow.o misc.o nullfe.o random.o \ singles3.o tree234.o $(CC) $(LDFLAGS) -o $@ -Wl,-Map,singlessolver.map dsf.o latin.o \ malloc.o maxflow.o misc.o nullfe.o random.o singles3.o \ tree234.o sixteen.exe: drawing.o malloc.o midend.o misc.o printing.o random.o \ sixteen.o sixteen.res.o version.o windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,sixteen.map drawing.o \ malloc.o midend.o misc.o printing.o random.o sixteen.o \ sixteen.res.o version.o windows.o -lcomctl32 -lcomdlg32 \ -lgdi32 -luser32 -lwinspool slant.exe: drawing.o dsf.o findloop.o malloc.o midend.o misc.o printing.o \ random.o slant.o slant.res.o version.o windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,slant.map drawing.o dsf.o \ findloop.o malloc.o midend.o misc.o printing.o random.o \ slant.o slant.res.o version.o windows.o -lcomctl32 \ -lcomdlg32 -lgdi32 -luser32 -lwinspool slantsolver.exe: dsf.o findloop.o malloc.o misc.o nullfe.o random.o slant2.o $(CC) $(LDFLAGS) -o $@ -Wl,-Map,slantsolver.map dsf.o findloop.o \ malloc.o misc.o nullfe.o random.o slant2.o solo.exe: divvy.o drawing.o dsf.o malloc.o midend.o misc.o printing.o \ random.o solo.o solo.res.o version.o windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,solo.map divvy.o drawing.o \ dsf.o malloc.o midend.o misc.o printing.o random.o solo.o \ solo.res.o version.o windows.o -lcomctl32 -lcomdlg32 -lgdi32 \ -luser32 -lwinspool solosolver.exe: divvy.o dsf.o malloc.o misc.o nullfe.o random.o solo2.o $(CC) $(LDFLAGS) -o $@ -Wl,-Map,solosolver.map divvy.o dsf.o \ malloc.o misc.o nullfe.o random.o solo2.o tents.exe: drawing.o dsf.o malloc.o maxflow.o midend.o misc.o printing.o \ random.o tents.o tents.res.o version.o windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,tents.map drawing.o dsf.o \ malloc.o maxflow.o midend.o misc.o printing.o random.o \ tents.o tents.res.o version.o windows.o -lcomctl32 \ -lcomdlg32 -lgdi32 -luser32 -lwinspool tentssolver.exe: dsf.o malloc.o maxflow.o misc.o nullfe.o random.o tents3.o $(CC) $(LDFLAGS) -o $@ -Wl,-Map,tentssolver.map dsf.o malloc.o \ maxflow.o misc.o nullfe.o random.o tents3.o towers.exe: drawing.o latin.o malloc.o maxflow.o midend.o misc.o printing.o \ random.o towers.o towers.res.o tree234.o version.o windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,towers.map drawing.o \ latin.o malloc.o maxflow.o midend.o misc.o printing.o \ random.o towers.o towers.res.o tree234.o version.o windows.o \ -lcomctl32 -lcomdlg32 -lgdi32 -luser32 -lwinspool towerssolver.exe: latin6.o malloc.o maxflow.o misc.o nullfe.o random.o \ towers2.o tree234.o $(CC) $(LDFLAGS) -o $@ -Wl,-Map,towerssolver.map latin6.o malloc.o \ maxflow.o misc.o nullfe.o random.o towers2.o tree234.o tracks.exe: drawing.o dsf.o findloop.o malloc.o midend.o misc.o printing.o \ random.o tracks.o tracks.res.o version.o windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,tracks.map drawing.o dsf.o \ findloop.o malloc.o midend.o misc.o printing.o random.o \ tracks.o tracks.res.o version.o windows.o -lcomctl32 \ -lcomdlg32 -lgdi32 -luser32 -lwinspool twiddle.exe: drawing.o malloc.o midend.o misc.o printing.o random.o \ twiddle.o twiddle.res.o version.o windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,twiddle.map drawing.o \ malloc.o midend.o misc.o printing.o random.o twiddle.o \ twiddle.res.o version.o windows.o -lcomctl32 -lcomdlg32 \ -lgdi32 -luser32 -lwinspool undead.exe: drawing.o malloc.o midend.o misc.o printing.o random.o undead.o \ undead.res.o version.o windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,undead.map drawing.o \ malloc.o midend.o misc.o printing.o random.o undead.o \ undead.res.o version.o windows.o -lcomctl32 -lcomdlg32 \ -lgdi32 -luser32 -lwinspool unequal.exe: drawing.o latin.o malloc.o maxflow.o midend.o misc.o printing.o \ random.o tree234.o unequal.o unequal.res.o version.o \ windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,unequal.map drawing.o \ latin.o malloc.o maxflow.o midend.o misc.o printing.o \ random.o tree234.o unequal.o unequal.res.o version.o \ windows.o -lcomctl32 -lcomdlg32 -lgdi32 -luser32 -lwinspool unequalsolver.exe: latin6.o malloc.o maxflow.o misc.o nullfe.o random.o \ tree234.o unequal2.o $(CC) $(LDFLAGS) -o $@ -Wl,-Map,unequalsolver.map latin6.o malloc.o \ maxflow.o misc.o nullfe.o random.o tree234.o unequal2.o unruly.exe: drawing.o malloc.o midend.o misc.o printing.o random.o unruly.o \ unruly.res.o version.o windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,unruly.map drawing.o \ malloc.o midend.o misc.o printing.o random.o unruly.o \ unruly.res.o version.o windows.o -lcomctl32 -lcomdlg32 \ -lgdi32 -luser32 -lwinspool unrulysolver.exe: malloc.o misc.o nullfe.o random.o unruly2.o $(CC) $(LDFLAGS) -o $@ -Wl,-Map,unrulysolver.map malloc.o misc.o \ nullfe.o random.o unruly2.o untangle.exe: drawing.o malloc.o midend.o misc.o printing.o random.o \ tree234.o untangle.o untangle.res.o version.o windows.o $(CC) -mwindows $(LDFLAGS) -o $@ -Wl,-Map,untangle.map drawing.o \ malloc.o midend.o misc.o printing.o random.o tree234.o \ untangle.o untangle.res.o version.o windows.o -lcomctl32 \ -lcomdlg32 -lgdi32 -luser32 -lwinspool blackbox.o: ./blackbox.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ blackbox-icon.o: icons/blackbox-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ blackbox.res.o: icons/blackbox.rc ./puzzles.rc2 icons/blackbox.ico \ ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ blackbo3.o: ./blackbox.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ bridges.o: ./bridges.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ bridges-icon.o: icons/bridges-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ bridges.res.o: icons/bridges.rc ./puzzles.rc2 icons/bridges.ico ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ bridges3.o: ./bridges.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ combi.o: ./combi.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ cube.o: ./cube.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ cube-icon.o: icons/cube-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ cube.res.o: icons/cube.rc ./puzzles.rc2 icons/cube.ico ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ cube3.o: ./cube.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ divvy.o: ./divvy.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ dominosa.o: ./dominosa.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ dominosa-icon.o: icons/dominosa-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ dominosa.res.o: icons/dominosa.rc ./puzzles.rc2 icons/dominosa.ico \ ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ dominos3.o: ./dominosa.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ drawing.o: ./drawing.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ dsf.o: ./dsf.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ fifteen.o: ./fifteen.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ fifteen-icon.o: icons/fifteen-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ fifteen.res.o: icons/fifteen.rc ./puzzles.rc2 icons/fifteen.ico ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ fifteen5.o: ./fifteen.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ fifteen2.o: ./fifteen.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ filling.o: ./filling.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ filling-icon.o: icons/filling-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ filling.res.o: icons/filling.rc ./puzzles.rc2 icons/filling.ico ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ filling5.o: ./filling.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ filling2.o: ./filling.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ findloop.o: ./findloop.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ flip.o: ./flip.c ./puzzles.h ./tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ flip-icon.o: icons/flip-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ flip.res.o: icons/flip.rc ./puzzles.rc2 icons/flip.ico ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ flip3.o: ./flip.c ./puzzles.h ./tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ flood.o: ./flood.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ flood-icon.o: icons/flood-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ flood.res.o: icons/flood.rc ./puzzles.rc2 icons/flood.ico ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ flood3.o: ./flood.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ galaxies.o: ./galaxies.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ galaxies-icon.o: icons/galaxies-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ galaxies.res.o: icons/galaxies.rc ./puzzles.rc2 icons/galaxies.ico \ ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ galaxie7.o: ./galaxies.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ galaxie4.o: ./galaxies.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_PICTURE_GENERATOR -c $< -o $@ galaxie2.o: ./galaxies.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ grid.o: ./grid.c ./puzzles.h ./tree234.h ./grid.h ./penrose.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ gtk.o: ./gtk.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ guess.o: ./guess.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ guess-icon.o: icons/guess-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ guess.res.o: icons/guess.rc ./puzzles.rc2 icons/guess.ico ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ guess3.o: ./guess.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ inertia.o: ./inertia.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ inertia-icon.o: icons/inertia-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ inertia.res.o: icons/inertia.rc ./puzzles.rc2 icons/inertia.ico ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ inertia3.o: ./inertia.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ keen.o: ./keen.c ./puzzles.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ keen-icon.o: icons/keen-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ keen.res.o: icons/keen.rc ./puzzles.rc2 icons/keen.ico ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ keen5.o: ./keen.c ./puzzles.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ keen2.o: ./keen.c ./puzzles.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ latin.o: ./latin.c ./puzzles.h ./tree234.h ./maxflow.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ latin8.o: ./latin.c ./puzzles.h ./tree234.h ./maxflow.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_LATIN_TEST -c $< -o $@ latin6.o: ./latin.c ./puzzles.h ./tree234.h ./maxflow.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ laydomino.o: ./laydomino.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ lightup.o: ./lightup.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ lightup-icon.o: icons/lightup-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ lightup.res.o: icons/lightup.rc ./puzzles.rc2 icons/lightup.ico ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ lightup5.o: ./lightup.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ lightup2.o: ./lightup.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ list.o: ./list.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ loopgen.o: ./loopgen.c ./puzzles.h ./tree234.h ./grid.h ./loopgen.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ loopy.o: ./loopy.c ./puzzles.h ./tree234.h ./grid.h ./loopgen.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ loopy-icon.o: icons/loopy-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ loopy.res.o: icons/loopy.rc ./puzzles.rc2 icons/loopy.ico ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ loopy5.o: ./loopy.c ./puzzles.h ./tree234.h ./grid.h ./loopgen.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ loopy2.o: ./loopy.c ./puzzles.h ./tree234.h ./grid.h ./loopgen.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ magnets.o: ./magnets.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ magnets-icon.o: icons/magnets-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ magnets.res.o: icons/magnets.rc ./puzzles.rc2 icons/magnets.ico ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ magnets5.o: ./magnets.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ magnets2.o: ./magnets.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ malloc.o: ./malloc.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ map.o: ./map.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ map-icon.o: icons/map-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ map.res.o: icons/map.rc ./puzzles.rc2 icons/map.ico ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ map5.o: ./map.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ map2.o: ./map.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ maxflow.o: ./maxflow.c ./maxflow.h ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ midend.o: ./midend.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ mines.o: ./mines.c ./tree234.h ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ mines-icon.o: icons/mines-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ mines.res.o: icons/mines.rc ./puzzles.rc2 icons/mines.ico ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ mines5.o: ./mines.c ./tree234.h ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ mines2.o: ./mines.c ./tree234.h ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_OBFUSCATOR -c $< -o $@ misc.o: ./misc.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ net.o: ./net.c ./puzzles.h ./tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ net-icon.o: icons/net-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ net.res.o: icons/net.rc ./puzzles.rc2 icons/net.ico ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ net3.o: ./net.c ./puzzles.h ./tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ netslide.o: ./netslide.c ./puzzles.h ./tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ netslide-icon.o: icons/netslide-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ netslide.res.o: icons/netslide.rc ./puzzles.rc2 icons/netslide.ico \ ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ netslid3.o: ./netslide.c ./puzzles.h ./tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ no-icon.o: ./no-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ noicon.res.o: ./noicon.rc ./puzzles.rc2 ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ nullfe.o: ./nullfe.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ nullgame.o: ./nullgame.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ obfusc.o: ./obfusc.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ osx.o: ./osx.m ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ palisade.o: ./palisade.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ palisade-icon.o: icons/palisade-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ palisade.res.o: icons/palisade.rc ./puzzles.rc2 icons/palisade.ico \ ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ palisad3.o: ./palisade.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ pattern.o: ./pattern.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ pattern-icon.o: icons/pattern-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ pattern.res.o: icons/pattern.rc ./puzzles.rc2 icons/pattern.ico ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ pattern7.o: ./pattern.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ pattern4.o: ./pattern.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_PICTURE_GENERATOR -c $< -o $@ pattern2.o: ./pattern.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ pearl.o: ./pearl.c ./puzzles.h ./grid.h ./loopgen.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ pearl-icon.o: icons/pearl-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ pearl.res.o: icons/pearl.rc ./puzzles.rc2 icons/pearl.ico ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ pearl5.o: ./pearl.c ./puzzles.h ./grid.h ./loopgen.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ pearl2.o: ./pearl.c ./puzzles.h ./grid.h ./loopgen.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ pegs.o: ./pegs.c ./puzzles.h ./tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ pegs-icon.o: icons/pegs-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ pegs.res.o: icons/pegs.rc ./puzzles.rc2 icons/pegs.ico ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ pegs3.o: ./pegs.c ./puzzles.h ./tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ penrose.o: ./penrose.c ./puzzles.h ./penrose.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ printing.o: ./printing.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ ps.o: ./ps.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ random.o: ./random.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ range.o: ./range.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ range-icon.o: icons/range-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ range.res.o: icons/range.rc ./puzzles.rc2 icons/range.ico ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ range3.o: ./range.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ rect.o: ./rect.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ rect-icon.o: icons/rect-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ rect.res.o: icons/rect.rc ./puzzles.rc2 icons/rect.ico ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ rect3.o: ./rect.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ samegame.o: ./samegame.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ samegame-icon.o: icons/samegame-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ samegame.res.o: icons/samegame.rc ./puzzles.rc2 icons/samegame.ico \ ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ samegam3.o: ./samegame.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ signpost.o: ./signpost.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ signpost-icon.o: icons/signpost-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ signpost.res.o: icons/signpost.rc ./puzzles.rc2 icons/signpost.ico \ ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ signpos5.o: ./signpost.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ signpos2.o: ./signpost.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ singles.o: ./singles.c ./puzzles.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ singles-icon.o: icons/singles-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ singles.res.o: icons/singles.rc ./puzzles.rc2 icons/singles.ico ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ singles5.o: ./singles.c ./puzzles.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ singles3.o: ./singles.c ./puzzles.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ sixteen.o: ./sixteen.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ sixteen-icon.o: icons/sixteen-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ sixteen.res.o: icons/sixteen.rc ./puzzles.rc2 icons/sixteen.ico ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ sixteen3.o: ./sixteen.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ slant.o: ./slant.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ slant-icon.o: icons/slant-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ slant.res.o: icons/slant.rc ./puzzles.rc2 icons/slant.ico ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ slant5.o: ./slant.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ slant2.o: ./slant.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ solo.o: ./solo.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ solo-icon.o: icons/solo-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ solo.res.o: icons/solo.rc ./puzzles.rc2 icons/solo.ico ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ solo5.o: ./solo.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ solo2.o: ./solo.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ tdq.o: ./tdq.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ tents.o: ./tents.c ./puzzles.h ./maxflow.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ tents-icon.o: icons/tents-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ tents.res.o: icons/tents.rc ./puzzles.rc2 icons/tents.ico ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ tents5.o: ./tents.c ./puzzles.h ./maxflow.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ tents3.o: ./tents.c ./puzzles.h ./maxflow.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ towers.o: ./towers.c ./puzzles.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ towers-icon.o: icons/towers-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ towers.res.o: icons/towers.rc ./puzzles.rc2 icons/towers.ico ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ towers5.o: ./towers.c ./puzzles.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ towers2.o: ./towers.c ./puzzles.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ tracks.o: ./tracks.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ tracks-icon.o: icons/tracks-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ tracks.res.o: icons/tracks.rc ./puzzles.rc2 icons/tracks.ico ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ tracks3.o: ./tracks.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ tree234.o: ./tree234.c ./tree234.h ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ twiddle.o: ./twiddle.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ twiddle-icon.o: icons/twiddle-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ twiddle.res.o: icons/twiddle.rc ./puzzles.rc2 icons/twiddle.ico ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ twiddle3.o: ./twiddle.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ undead.o: ./undead.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ undead-icon.o: icons/undead-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ undead.res.o: icons/undead.rc ./puzzles.rc2 icons/undead.ico ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ undead3.o: ./undead.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ unequal.o: ./unequal.c ./puzzles.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ unequal-icon.o: icons/unequal-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ unequal.res.o: icons/unequal.rc ./puzzles.rc2 icons/unequal.ico ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ unequal5.o: ./unequal.c ./puzzles.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ unequal2.o: ./unequal.c ./puzzles.h ./latin.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ unruly.o: ./unruly.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ unruly-icon.o: icons/unruly-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ unruly.res.o: icons/unruly.rc ./puzzles.rc2 icons/unruly.ico ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ unruly5.o: ./unruly.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ unruly2.o: ./unruly.c ./puzzles.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DSTANDALONE_SOLVER -c $< -o $@ untangle.o: ./untangle.c ./puzzles.h ./tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ untangle-icon.o: icons/untangle-icon.c $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ untangle.res.o: icons/untangle.rc ./puzzles.rc2 icons/untangle.ico \ ./resource.h $(RC) $(FWHACK) $(RCFL) $(RCFLAGS) $< $@ untangl3.o: ./untangle.c ./puzzles.h ./tree234.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ version.o: ./version.c ./version.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ windows.o: ./windows.c ./puzzles.h ./resource.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -c $< -o $@ windows1.o: ./windows.c ./puzzles.h ./resource.h $(CC) $(COMPAT) $(FWHACK) $(CFLAGS) $(XFLAGS) -DCOMBINED -c $< -o $@ clean: rm -f *.o *.exe *.res.o *.map puzzles-20170606.272beef/Makefile.am0000644000175000017500000004665713115375145015747 0ustar simonsimon# Makefile.am for puzzles under Unix with Autoconf/Automake. # # This file was created by `mkfiles.pl' from the `Recipe' file. # DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead. GAMES = noinst_PROGRAMS = blackbox bridges cube dominosa fifteen fifteensolver \ filling fillingsolver flip flood galaxies galaxiespicture \ galaxiessolver guess inertia keen keensolver latincheck \ lightup lightupsolver loopy loopysolver magnets \ magnetssolver map mapsolver mineobfusc mines net netslide \ nullgame obfusc palisade pattern patternpicture \ patternsolver pearl pearlbench pegs range rect samegame \ signpost signpostsolver singles singlessolver sixteen slant \ slantsolver solo solosolver tents tentssolver towers \ towerssolver tracks twiddle undead unequal unequalsolver \ unruly unrulysolver untangle AUTOMAKE_OPTIONS = subdir-objects allsources = ./blackbox.c ./bridges.c ./combi.c ./cube.c ./divvy.c \ ./dominosa.c ./drawing.c ./dsf.c ./fifteen.c ./filling.c \ ./findloop.c ./flip.c ./flood.c ./galaxies.c ./grid.c \ ./grid.h ./gtk.c ./guess.c ./inertia.c ./keen.c ./latin.c \ ./latin.h ./laydomino.c ./lightup.c ./list.c ./loopgen.c \ ./loopgen.h ./loopy.c ./magnets.c ./malloc.c ./map.c \ ./maxflow.c ./maxflow.h ./midend.c ./mines.c ./misc.c \ ./net.c ./netslide.c ./no-icon.c ./nullfe.c ./nullgame.c \ ./obfusc.c ./osx.m ./palisade.c ./pattern.c ./pearl.c \ ./pegs.c ./penrose.c ./penrose.h ./printing.c ./ps.c \ ./puzzles.h ./random.c ./range.c ./rect.c ./resource.h \ ./samegame.c ./signpost.c ./singles.c ./sixteen.c ./slant.c \ ./solo.c ./tdq.c ./tents.c ./towers.c ./tracks.c ./tree234.c \ ./tree234.h ./twiddle.c ./undead.c ./unequal.c ./unruly.c \ ./untangle.c ./version.c ./version.h ./windows.c \ icons/blackbox-icon.c icons/bridges-icon.c icons/cube-icon.c \ icons/dominosa-icon.c icons/fifteen-icon.c \ icons/filling-icon.c icons/flip-icon.c icons/flood-icon.c \ icons/galaxies-icon.c icons/guess-icon.c \ icons/inertia-icon.c icons/keen-icon.c icons/lightup-icon.c \ icons/loopy-icon.c icons/magnets-icon.c icons/map-icon.c \ icons/mines-icon.c icons/net-icon.c icons/netslide-icon.c \ icons/palisade-icon.c icons/pattern-icon.c \ icons/pearl-icon.c icons/pegs-icon.c icons/range-icon.c \ icons/rect-icon.c icons/samegame-icon.c \ icons/signpost-icon.c icons/singles-icon.c \ icons/sixteen-icon.c icons/slant-icon.c icons/solo-icon.c \ icons/tents-icon.c icons/towers-icon.c icons/tracks-icon.c \ icons/twiddle-icon.c icons/undead-icon.c \ icons/unequal-icon.c icons/unruly-icon.c \ icons/untangle-icon.c AM_CPPFLAGS = -I$(srcdir)/./ -I$(srcdir)/icons/ AM_CFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) blackbox_SOURCES = ./blackbox.c ./drawing.c ./gtk.c ./malloc.c ./midend.c \ ./misc.c ./printing.c ./ps.c ./puzzles.h ./random.c \ ./version.c ./version.h icons/blackbox-icon.c blackbox_LDADD = $(GTK_LIBS) -lm bridges_SOURCES = ./bridges.c ./drawing.c ./dsf.c ./findloop.c ./gtk.c \ ./malloc.c ./midend.c ./misc.c ./printing.c ./ps.c \ ./puzzles.h ./random.c ./version.c ./version.h \ icons/bridges-icon.c bridges_LDADD = $(GTK_LIBS) -lm cube_SOURCES = ./cube.c ./drawing.c ./gtk.c ./malloc.c ./midend.c ./misc.c \ ./printing.c ./ps.c ./puzzles.h ./random.c ./version.c \ ./version.h icons/cube-icon.c cube_LDADD = $(GTK_LIBS) -lm dominosa_SOURCES = ./dominosa.c ./drawing.c ./gtk.c ./laydomino.c ./malloc.c \ ./midend.c ./misc.c ./printing.c ./ps.c ./puzzles.h \ ./random.c ./version.c ./version.h icons/dominosa-icon.c dominosa_LDADD = $(GTK_LIBS) -lm fifteen_SOURCES = ./drawing.c ./fifteen.c ./gtk.c ./malloc.c ./midend.c \ ./misc.c ./printing.c ./ps.c ./puzzles.h ./random.c \ ./version.c ./version.h icons/fifteen-icon.c fifteen_LDADD = $(GTK_LIBS) -lm fifteensolver_SOURCES = ./malloc.c ./misc.c ./nullfe.c ./puzzles.h \ ./random.c fifteensolver_LDADD = libfifteen2_a-fifteen.$(OBJEXT) -lm filling_SOURCES = ./drawing.c ./dsf.c ./filling.c ./gtk.c ./malloc.c \ ./midend.c ./misc.c ./printing.c ./ps.c ./puzzles.h \ ./random.c ./version.c ./version.h icons/filling-icon.c filling_LDADD = $(GTK_LIBS) -lm fillingsolver_SOURCES = ./dsf.c ./malloc.c ./misc.c ./nullfe.c ./puzzles.h \ ./random.c fillingsolver_LDADD = libfilling2_a-filling.$(OBJEXT) -lm flip_SOURCES = ./drawing.c ./flip.c ./gtk.c ./malloc.c ./midend.c ./misc.c \ ./printing.c ./ps.c ./puzzles.h ./random.c ./tree234.c \ ./tree234.h ./version.c ./version.h icons/flip-icon.c flip_LDADD = $(GTK_LIBS) -lm flood_SOURCES = ./drawing.c ./flood.c ./gtk.c ./malloc.c ./midend.c ./misc.c \ ./printing.c ./ps.c ./puzzles.h ./random.c ./version.c \ ./version.h icons/flood-icon.c flood_LDADD = $(GTK_LIBS) -lm galaxies_SOURCES = ./drawing.c ./dsf.c ./galaxies.c ./gtk.c ./malloc.c \ ./midend.c ./misc.c ./printing.c ./ps.c ./puzzles.h \ ./random.c ./version.c ./version.h icons/galaxies-icon.c galaxies_LDADD = $(GTK_LIBS) -lm galaxiespicture_SOURCES = ./dsf.c ./malloc.c ./misc.c ./nullfe.c ./puzzles.h \ ./random.c galaxiespicture_LDADD = libgalaxie4_a-galaxies.$(OBJEXT) -lm galaxiessolver_SOURCES = ./dsf.c ./malloc.c ./misc.c ./nullfe.c ./puzzles.h \ ./random.c galaxiessolver_LDADD = libgalaxie2_a-galaxies.$(OBJEXT) -lm guess_SOURCES = ./drawing.c ./gtk.c ./guess.c ./malloc.c ./midend.c ./misc.c \ ./printing.c ./ps.c ./puzzles.h ./random.c ./version.c \ ./version.h icons/guess-icon.c guess_LDADD = $(GTK_LIBS) -lm inertia_SOURCES = ./drawing.c ./gtk.c ./inertia.c ./malloc.c ./midend.c \ ./misc.c ./printing.c ./ps.c ./puzzles.h ./random.c \ ./version.c ./version.h icons/inertia-icon.c inertia_LDADD = $(GTK_LIBS) -lm keen_SOURCES = ./drawing.c ./dsf.c ./gtk.c ./keen.c ./latin.c ./latin.h \ ./malloc.c ./maxflow.c ./maxflow.h ./midend.c ./misc.c \ ./printing.c ./ps.c ./puzzles.h ./random.c ./tree234.c \ ./tree234.h ./version.c ./version.h icons/keen-icon.c keen_LDADD = $(GTK_LIBS) -lm keensolver_SOURCES = ./dsf.c ./malloc.c ./maxflow.c ./maxflow.h ./misc.c \ ./nullfe.c ./puzzles.h ./random.c ./tree234.c ./tree234.h keensolver_LDADD = libkeen2_a-keen.$(OBJEXT) liblatin6_a-latin.$(OBJEXT) -lm latincheck_SOURCES = ./malloc.c ./maxflow.c ./maxflow.h ./misc.c ./nullfe.c \ ./puzzles.h ./random.c ./tree234.c ./tree234.h latincheck_LDADD = liblatin8_a-latin.$(OBJEXT) -lm lightup_SOURCES = ./combi.c ./drawing.c ./gtk.c ./lightup.c ./malloc.c \ ./midend.c ./misc.c ./printing.c ./ps.c ./puzzles.h \ ./random.c ./version.c ./version.h icons/lightup-icon.c lightup_LDADD = $(GTK_LIBS) -lm lightupsolver_SOURCES = ./combi.c ./malloc.c ./misc.c ./nullfe.c ./puzzles.h \ ./random.c lightupsolver_LDADD = liblightup2_a-lightup.$(OBJEXT) -lm loopy_SOURCES = ./drawing.c ./dsf.c ./grid.c ./grid.h ./gtk.c ./loopgen.c \ ./loopgen.h ./loopy.c ./malloc.c ./midend.c ./misc.c \ ./penrose.c ./penrose.h ./printing.c ./ps.c ./puzzles.h \ ./random.c ./tree234.c ./tree234.h ./version.c ./version.h \ icons/loopy-icon.c loopy_LDADD = $(GTK_LIBS) -lm loopysolver_SOURCES = ./dsf.c ./grid.c ./grid.h ./loopgen.c ./loopgen.h \ ./malloc.c ./misc.c ./nullfe.c ./penrose.c ./penrose.h \ ./puzzles.h ./random.c ./tree234.c ./tree234.h loopysolver_LDADD = libloopy2_a-loopy.$(OBJEXT) -lm magnets_SOURCES = ./drawing.c ./gtk.c ./laydomino.c ./magnets.c ./malloc.c \ ./midend.c ./misc.c ./printing.c ./ps.c ./puzzles.h \ ./random.c ./version.c ./version.h icons/magnets-icon.c magnets_LDADD = $(GTK_LIBS) -lm magnetssolver_SOURCES = ./laydomino.c ./malloc.c ./misc.c ./nullfe.c \ ./puzzles.h ./random.c magnetssolver_LDADD = libmagnets2_a-magnets.$(OBJEXT) -lm map_SOURCES = ./drawing.c ./dsf.c ./gtk.c ./malloc.c ./map.c ./midend.c \ ./misc.c ./printing.c ./ps.c ./puzzles.h ./random.c \ ./version.c ./version.h icons/map-icon.c map_LDADD = $(GTK_LIBS) -lm mapsolver_SOURCES = ./dsf.c ./malloc.c ./misc.c ./nullfe.c ./puzzles.h \ ./random.c mapsolver_LDADD = libmap2_a-map.$(OBJEXT) -lm mineobfusc_SOURCES = ./malloc.c ./misc.c ./nullfe.c ./puzzles.h ./random.c \ ./tree234.c ./tree234.h mineobfusc_LDADD = libmines2_a-mines.$(OBJEXT) -lm mines_SOURCES = ./drawing.c ./gtk.c ./malloc.c ./midend.c ./mines.c ./misc.c \ ./printing.c ./ps.c ./puzzles.h ./random.c ./tree234.c \ ./tree234.h ./version.c ./version.h icons/mines-icon.c mines_LDADD = $(GTK_LIBS) -lm net_SOURCES = ./drawing.c ./dsf.c ./findloop.c ./gtk.c ./malloc.c ./midend.c \ ./misc.c ./net.c ./printing.c ./ps.c ./puzzles.h ./random.c \ ./tree234.c ./tree234.h ./version.c ./version.h \ icons/net-icon.c net_LDADD = $(GTK_LIBS) -lm netslide_SOURCES = ./drawing.c ./gtk.c ./malloc.c ./midend.c ./misc.c \ ./netslide.c ./printing.c ./ps.c ./puzzles.h ./random.c \ ./tree234.c ./tree234.h ./version.c ./version.h \ icons/netslide-icon.c netslide_LDADD = $(GTK_LIBS) -lm nullgame_SOURCES = ./drawing.c ./gtk.c ./malloc.c ./midend.c ./misc.c \ ./no-icon.c ./nullgame.c ./printing.c ./ps.c ./puzzles.h \ ./random.c ./version.c ./version.h nullgame_LDADD = $(GTK_LIBS) -lm obfusc_SOURCES = ./malloc.c ./misc.c ./nullfe.c ./obfusc.c ./puzzles.h \ ./random.c obfusc_LDADD = -lm palisade_SOURCES = ./divvy.c ./drawing.c ./dsf.c ./gtk.c ./malloc.c \ ./midend.c ./misc.c ./palisade.c ./printing.c ./ps.c \ ./puzzles.h ./random.c ./version.c ./version.h \ icons/palisade-icon.c palisade_LDADD = $(GTK_LIBS) -lm pattern_SOURCES = ./drawing.c ./gtk.c ./malloc.c ./midend.c ./misc.c \ ./pattern.c ./printing.c ./ps.c ./puzzles.h ./random.c \ ./version.c ./version.h icons/pattern-icon.c pattern_LDADD = $(GTK_LIBS) -lm patternpicture_SOURCES = ./malloc.c ./misc.c ./nullfe.c ./puzzles.h \ ./random.c patternpicture_LDADD = libpattern4_a-pattern.$(OBJEXT) -lm patternsolver_SOURCES = ./malloc.c ./misc.c ./nullfe.c ./puzzles.h \ ./random.c patternsolver_LDADD = libpattern2_a-pattern.$(OBJEXT) -lm pearl_SOURCES = ./drawing.c ./dsf.c ./grid.c ./grid.h ./gtk.c ./loopgen.c \ ./loopgen.h ./malloc.c ./midend.c ./misc.c ./pearl.c \ ./penrose.c ./penrose.h ./printing.c ./ps.c ./puzzles.h \ ./random.c ./tdq.c ./tree234.c ./tree234.h ./version.c \ ./version.h icons/pearl-icon.c pearl_LDADD = $(GTK_LIBS) -lm pearlbench_SOURCES = ./dsf.c ./grid.c ./grid.h ./loopgen.c ./loopgen.h \ ./malloc.c ./misc.c ./nullfe.c ./penrose.c ./penrose.h \ ./puzzles.h ./random.c ./tdq.c ./tree234.c ./tree234.h pearlbench_LDADD = libpearl2_a-pearl.$(OBJEXT) -lm pegs_SOURCES = ./drawing.c ./gtk.c ./malloc.c ./midend.c ./misc.c ./pegs.c \ ./printing.c ./ps.c ./puzzles.h ./random.c ./tree234.c \ ./tree234.h ./version.c ./version.h icons/pegs-icon.c pegs_LDADD = $(GTK_LIBS) -lm range_SOURCES = ./drawing.c ./dsf.c ./gtk.c ./malloc.c ./midend.c ./misc.c \ ./printing.c ./ps.c ./puzzles.h ./random.c ./range.c \ ./version.c ./version.h icons/range-icon.c range_LDADD = $(GTK_LIBS) -lm rect_SOURCES = ./drawing.c ./gtk.c ./malloc.c ./midend.c ./misc.c \ ./printing.c ./ps.c ./puzzles.h ./random.c ./rect.c \ ./version.c ./version.h icons/rect-icon.c rect_LDADD = $(GTK_LIBS) -lm samegame_SOURCES = ./drawing.c ./gtk.c ./malloc.c ./midend.c ./misc.c \ ./printing.c ./ps.c ./puzzles.h ./random.c ./samegame.c \ ./version.c ./version.h icons/samegame-icon.c samegame_LDADD = $(GTK_LIBS) -lm signpost_SOURCES = ./drawing.c ./dsf.c ./gtk.c ./malloc.c ./midend.c \ ./misc.c ./printing.c ./ps.c ./puzzles.h ./random.c \ ./signpost.c ./version.c ./version.h icons/signpost-icon.c signpost_LDADD = $(GTK_LIBS) -lm signpostsolver_SOURCES = ./dsf.c ./malloc.c ./misc.c ./nullfe.c ./puzzles.h \ ./random.c signpostsolver_LDADD = libsignpos2_a-signpost.$(OBJEXT) -lm singles_SOURCES = ./drawing.c ./dsf.c ./gtk.c ./latin.c ./latin.h ./malloc.c \ ./maxflow.c ./maxflow.h ./midend.c ./misc.c ./printing.c \ ./ps.c ./puzzles.h ./random.c ./singles.c ./tree234.c \ ./tree234.h ./version.c ./version.h icons/singles-icon.c singles_LDADD = $(GTK_LIBS) -lm singlessolver_SOURCES = ./dsf.c ./latin.c ./latin.h ./malloc.c ./maxflow.c \ ./maxflow.h ./misc.c ./nullfe.c ./puzzles.h ./random.c \ ./tree234.c ./tree234.h singlessolver_LDADD = libsingles3_a-singles.$(OBJEXT) -lm sixteen_SOURCES = ./drawing.c ./gtk.c ./malloc.c ./midend.c ./misc.c \ ./printing.c ./ps.c ./puzzles.h ./random.c ./sixteen.c \ ./version.c ./version.h icons/sixteen-icon.c sixteen_LDADD = $(GTK_LIBS) -lm slant_SOURCES = ./drawing.c ./dsf.c ./findloop.c ./gtk.c ./malloc.c \ ./midend.c ./misc.c ./printing.c ./ps.c ./puzzles.h \ ./random.c ./slant.c ./version.c ./version.h \ icons/slant-icon.c slant_LDADD = $(GTK_LIBS) -lm slantsolver_SOURCES = ./dsf.c ./findloop.c ./malloc.c ./misc.c ./nullfe.c \ ./puzzles.h ./random.c slantsolver_LDADD = libslant2_a-slant.$(OBJEXT) -lm solo_SOURCES = ./divvy.c ./drawing.c ./dsf.c ./gtk.c ./malloc.c ./midend.c \ ./misc.c ./printing.c ./ps.c ./puzzles.h ./random.c ./solo.c \ ./version.c ./version.h icons/solo-icon.c solo_LDADD = $(GTK_LIBS) -lm solosolver_SOURCES = ./divvy.c ./dsf.c ./malloc.c ./misc.c ./nullfe.c \ ./puzzles.h ./random.c solosolver_LDADD = libsolo2_a-solo.$(OBJEXT) -lm tents_SOURCES = ./drawing.c ./dsf.c ./gtk.c ./malloc.c ./maxflow.c \ ./maxflow.h ./midend.c ./misc.c ./printing.c ./ps.c \ ./puzzles.h ./random.c ./tents.c ./version.c ./version.h \ icons/tents-icon.c tents_LDADD = $(GTK_LIBS) -lm tentssolver_SOURCES = ./dsf.c ./malloc.c ./maxflow.c ./maxflow.h ./misc.c \ ./nullfe.c ./puzzles.h ./random.c tentssolver_LDADD = libtents3_a-tents.$(OBJEXT) -lm towers_SOURCES = ./drawing.c ./gtk.c ./latin.c ./latin.h ./malloc.c \ ./maxflow.c ./maxflow.h ./midend.c ./misc.c ./printing.c \ ./ps.c ./puzzles.h ./random.c ./towers.c ./tree234.c \ ./tree234.h ./version.c ./version.h icons/towers-icon.c towers_LDADD = $(GTK_LIBS) -lm towerssolver_SOURCES = ./malloc.c ./maxflow.c ./maxflow.h ./misc.c \ ./nullfe.c ./puzzles.h ./random.c ./tree234.c ./tree234.h towerssolver_LDADD = liblatin6_a-latin.$(OBJEXT) \ libtowers2_a-towers.$(OBJEXT) -lm tracks_SOURCES = ./drawing.c ./dsf.c ./findloop.c ./gtk.c ./malloc.c \ ./midend.c ./misc.c ./printing.c ./ps.c ./puzzles.h \ ./random.c ./tracks.c ./version.c ./version.h \ icons/tracks-icon.c tracks_LDADD = $(GTK_LIBS) -lm twiddle_SOURCES = ./drawing.c ./gtk.c ./malloc.c ./midend.c ./misc.c \ ./printing.c ./ps.c ./puzzles.h ./random.c ./twiddle.c \ ./version.c ./version.h icons/twiddle-icon.c twiddle_LDADD = $(GTK_LIBS) -lm undead_SOURCES = ./drawing.c ./gtk.c ./malloc.c ./midend.c ./misc.c \ ./printing.c ./ps.c ./puzzles.h ./random.c ./undead.c \ ./version.c ./version.h icons/undead-icon.c undead_LDADD = $(GTK_LIBS) -lm unequal_SOURCES = ./drawing.c ./gtk.c ./latin.c ./latin.h ./malloc.c \ ./maxflow.c ./maxflow.h ./midend.c ./misc.c ./printing.c \ ./ps.c ./puzzles.h ./random.c ./tree234.c ./tree234.h \ ./unequal.c ./version.c ./version.h icons/unequal-icon.c unequal_LDADD = $(GTK_LIBS) -lm unequalsolver_SOURCES = ./malloc.c ./maxflow.c ./maxflow.h ./misc.c \ ./nullfe.c ./puzzles.h ./random.c ./tree234.c ./tree234.h unequalsolver_LDADD = liblatin6_a-latin.$(OBJEXT) \ libunequal2_a-unequal.$(OBJEXT) -lm unruly_SOURCES = ./drawing.c ./gtk.c ./malloc.c ./midend.c ./misc.c \ ./printing.c ./ps.c ./puzzles.h ./random.c ./unruly.c \ ./version.c ./version.h icons/unruly-icon.c unruly_LDADD = $(GTK_LIBS) -lm unrulysolver_SOURCES = ./malloc.c ./misc.c ./nullfe.c ./puzzles.h ./random.c unrulysolver_LDADD = libunruly2_a-unruly.$(OBJEXT) -lm untangle_SOURCES = ./drawing.c ./gtk.c ./malloc.c ./midend.c ./misc.c \ ./printing.c ./ps.c ./puzzles.h ./random.c ./tree234.c \ ./tree234.h ./untangle.c ./version.c ./version.h \ icons/untangle-icon.c untangle_LDADD = $(GTK_LIBS) -lm libfifteen2_a_SOURCES = ./fifteen.c ./puzzles.h libfifteen2_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_SOLVER libfilling2_a_SOURCES = ./filling.c ./puzzles.h libfilling2_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_SOLVER libgalaxie2_a_SOURCES = ./galaxies.c ./puzzles.h libgalaxie2_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_SOLVER libgalaxie4_a_SOURCES = ./galaxies.c ./puzzles.h libgalaxie4_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) \ -DSTANDALONE_PICTURE_GENERATOR libkeen2_a_SOURCES = ./keen.c ./puzzles.h ./latin.h libkeen2_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_SOLVER liblatin6_a_SOURCES = ./latin.c ./puzzles.h ./tree234.h ./maxflow.h \ ./latin.h liblatin6_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_SOLVER liblatin8_a_SOURCES = ./latin.c ./puzzles.h ./tree234.h ./maxflow.h \ ./latin.h liblatin8_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_LATIN_TEST liblightup2_a_SOURCES = ./lightup.c ./puzzles.h liblightup2_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_SOLVER libloopy2_a_SOURCES = ./loopy.c ./puzzles.h ./tree234.h ./grid.h ./loopgen.h libloopy2_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_SOLVER libmagnets2_a_SOURCES = ./magnets.c ./puzzles.h libmagnets2_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_SOLVER libmap2_a_SOURCES = ./map.c ./puzzles.h libmap2_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_SOLVER libmines2_a_SOURCES = ./mines.c ./tree234.h ./puzzles.h libmines2_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_OBFUSCATOR libpattern2_a_SOURCES = ./pattern.c ./puzzles.h libpattern2_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_SOLVER libpattern4_a_SOURCES = ./pattern.c ./puzzles.h libpattern4_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) \ -DSTANDALONE_PICTURE_GENERATOR libpearl2_a_SOURCES = ./pearl.c ./puzzles.h ./grid.h ./loopgen.h libpearl2_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_SOLVER libsignpos2_a_SOURCES = ./signpost.c ./puzzles.h libsignpos2_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_SOLVER libsingles3_a_SOURCES = ./singles.c ./puzzles.h ./latin.h libsingles3_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_SOLVER libslant2_a_SOURCES = ./slant.c ./puzzles.h libslant2_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_SOLVER libsolo2_a_SOURCES = ./solo.c ./puzzles.h libsolo2_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_SOLVER libtents3_a_SOURCES = ./tents.c ./puzzles.h ./maxflow.h libtents3_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_SOLVER libtowers2_a_SOURCES = ./towers.c ./puzzles.h ./latin.h libtowers2_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_SOLVER libunequal2_a_SOURCES = ./unequal.c ./puzzles.h ./latin.h libunequal2_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_SOLVER libunruly2_a_SOURCES = ./unruly.c ./puzzles.h libunruly2_a_CPPFLAGS = $(GTK_CFLAGS) $(WARNINGOPTS) -DSTANDALONE_SOLVER noinst_LIBRARIES = libfifteen2.a libfilling2.a libgalaxie2.a libgalaxie4.a \ libkeen2.a liblatin6.a liblatin8.a liblightup2.a libloopy2.a \ libmagnets2.a libmap2.a libmines2.a libpattern2.a \ libpattern4.a libpearl2.a libsignpos2.a libsingles3.a \ libslant2.a libsolo2.a libtents3.a libtowers2.a \ libunequal2.a libunruly2.a GAMES += blackbox GAMES += bridges GAMES += cube GAMES += dominosa GAMES += fifteen GAMES += filling GAMES += flip GAMES += flood GAMES += galaxies GAMES += guess GAMES += inertia GAMES += keen GAMES += lightup GAMES += loopy GAMES += magnets GAMES += map GAMES += mines GAMES += net GAMES += netslide GAMES += palisade GAMES += pattern GAMES += pearl GAMES += pegs GAMES += range GAMES += rect GAMES += samegame GAMES += signpost GAMES += singles GAMES += sixteen GAMES += slant GAMES += solo GAMES += tents GAMES += towers GAMES += tracks GAMES += twiddle GAMES += undead GAMES += unequal GAMES += unruly GAMES += untangle bin_PROGRAMS = $(GAMES) test: benchmark.html benchmark.txt benchmark.html: benchmark.txt benchmark.pl ./benchmark.pl benchmark.txt > $@ benchmark.txt: benchmark.sh $(GAMES) ./benchmark.sh > $@ puzzles-20170606.272beef/mkfiles.pl0000755000175000017500000017515113115373615015675 0ustar simonsimon#!/usr/bin/env perl # # Cross-platform Makefile generator. # # Reads the file `Recipe' to determine the list of generated # executables and their component objects. Then reads the source # files to compute #include dependencies. Finally, writes out the # various target Makefiles. # PuTTY specifics which could still do with removing: # - Mac makefile is not portabilised at all. Include directories # are hardwired, and also the libraries are fixed. This is # mainly because I was too scared to go anywhere near it. # - sbcsgen.pl is still run at startup. # Other things undone: # - special-define objects (foo.o[PREPROCSYMBOL]) are not # supported in the mac or vcproj makefiles. use warnings; use IO::Handle; use Cwd; use File::Basename; while ($#ARGV >= 0) { if ($ARGV[0] eq "-U") { # Convenience for Unix users: -U means that after we finish what # we're doing here, we also run mkauto.sh and then 'configure'. So # it's a one-stop shop for regenerating the actual end-product # Unix makefile. # # Arguments supplied after -U go to configure. $do_unix = 1; shift @ARGV; @confargs = @ARGV; @ARGV = (); } else { die "unrecognised command-line argument '$ARGV[0]'\n"; } } @filestack = (); $in = new IO::Handle; open $in, "Recipe" or do { # We want to deal correctly with being run from one of the # subdirs in the source tree. So if we can't find Recipe here, # try one level up. chdir ".."; open $in, "Recipe" or die "unable to open Recipe file\n"; }; push @filestack, $in; # HACK: One of the source files in `charset' is auto-generated by # sbcsgen.pl. We need to generate that _now_, before attempting # dependency analysis. eval 'chdir "charset"; require "sbcsgen.pl"; chdir ".."'; @srcdirs = ("./"); $divert = undef; # ref to array of refs of scalars in which text is # currently being put $help = ""; # list of newline-free lines of help text $project_name = "project"; # this is a good enough default %makefiles = (); # maps makefile types to output makefile pathnames %makefile_extra = (); # maps makefile types to extra Makefile text %programs = (); # maps prog name + type letter to listref of objects/resources %groups = (); # maps group name to listref of objects/resources @allobjs = (); # all object file names readinput: while (1) { $in = $filestack[$#filestack]; while (not defined ($_ = <$in>)) { close $filestack[$#filestack]; pop @filestack; last readinput if 0 == scalar @filestack; $in = $filestack[$#filestack]; } chomp; @_ = split; # If we're gathering help text, keep doing so. if (defined $divert) { if ((defined $_[0]) && $_[0] eq "!end") { $divert = undef; } else { for my $ref (@$divert) { ${$ref} .= "$_\n"; } } next; } # Skip comments and blank lines. next if /^\s*#/ or scalar @_ == 0; if ($_[0] eq "!begin" and $_[1] eq "help") { $divert = [\$help]; next; } if ($_[0] eq "!name") { $project_name = $_[1]; next; } if ($_[0] eq "!srcdir") { push @srcdirs, $_[1]; next; } if ($_[0] eq "!makefile" and &mfval($_[1])) { $makefiles{$_[1]}=$_[2]; next;} if ($_[0] eq "!specialobj" and &mfval($_[1])) { $specialobj{$_[1]}->{$_[2]} = 1; next;} if ($_[0] eq "!cflags" and &mfval($_[1])) { ($rest = $_) =~ s/^\s*\S+\s+\S+\s+\S+\s*//; # find rest of input line $rest = 1 if $rest eq ""; $cflags{$_[1]}->{$_[2]} = $rest; next; } if ($_[0] eq "!begin") { my @args = @_; shift @args; $divert = []; for my $component (@args) { if ($component =~ /^>(.*)/) { push @$divert, \$auxfiles{$1}; } elsif ($component =~ /^([^_]*)(_.*)?$/ and &mfval($1)) { push @$divert, \$makefile_extra{$component}; } } next; } if ($_[0] eq "!include") { @newfiles = (); for ($i = 1; $i <= $#_; $i++) { push @newfiles, (sort glob $_[$i]); } for ($i = $#newfiles; $i >= 0; $i--) { $file = $newfiles[$i]; $f = new IO::Handle; open $f, "<$file" or die "unable to open include file '$file'\n"; push @filestack, $f; } next; } # Now we have an ordinary line. See if it's an = line, a : line # or a + line. @objs = @_; if ($_[0] eq "+") { $listref = $lastlistref; $prog = undef; die "$.: unexpected + line\n" if !defined $lastlistref; } elsif ($_[1] eq "=") { $groups{$_[0]} = []; $listref = $groups{$_[0]}; $prog = undef; shift @objs; # eat the group name } elsif ($_[1] eq "+=") { $groups{$_[0]} = [] if !defined $groups{$_[0]}; $listref = $groups{$_[0]}; $prog = undef; shift @objs; # eat the group name } elsif ($_[1] eq ":") { $listref = []; $prog = $_[0]; shift @objs; # eat the program name } else { die "$.: unrecognised line type: '$_'\n"; } shift @objs; # eat the +, the = or the : while (scalar @objs > 0) { $i = shift @objs; if ($groups{$i}) { foreach $j (@{$groups{$i}}) { unshift @objs, $j; } } elsif (($i eq "[G]" or $i eq "[C]" or $i eq "[M]" or $i eq "[X]" or $i eq "[U]" or $i eq "[MX]") and defined $prog) { $type = substr($i,1,(length $i)-2); } else { if ($i =~ /\?$/) { # Object files with a trailing question mark are optional: # the build can proceed fine without them, so we only use # them if their primary source files are present. $i =~ s/\?$//; $i = undef unless defined &finddep($i); } elsif ($i =~ /\|/) { # Object file descriptions containing a vertical bar are # lists of choices: we use the _first_ one whose primary # source file is present. @options = split /\|/, $i; $j = undef; foreach $k (@options) { $j=$k, last if defined &finddep($k); } die "no alternative found for $i\n" unless defined $j; $i = $j; } if (defined $i) { push @$listref, $i; push @allobjs, $i; } } } if ($prog and $type) { die "multiple program entries for $prog [$type]\n" if defined $programs{$prog . "," . $type}; $programs{$prog . "," . $type} = $listref; } $lastlistref = $listref; } foreach $aux (sort keys %auxfiles) { open AUX, ">$aux"; print AUX $auxfiles{$aux}; close AUX; } # Find object file names with predefines (in square brackets after # the module name), and decide on actual object names for them. foreach $i (@allobjs) { if ($i !~ /\[/) { $objname{$i} = $i; $srcname{$i} = $i; $usedobjname{$i} = 1; } } foreach $i (@allobjs) { if ($i =~ /^(.*)\[([^\]]*)/) { $defs{$i} = [ split ",",$2 ]; $srcname{$i} = $s = $1; $index = 1; while (1) { $maxlen = length $s; $maxlen = 8 if $maxlen < 8; $chop = $maxlen - length $index; $chop = length $s if $chop > length $s; $chop = 0 if $chop < 0; $name = substr($s, 0, $chop) . $index; $index++, next if $usedobjname{$name}; $objname{$i} = $name; $usedobjname{$name} = 1; last; } } } # Now retrieve the complete list of objects and resource files, and # construct dependency data for them. While we're here, expand the # object list for each program, and complain if its type isn't set. @prognames = sort keys %programs; %depends = (); @scanlist = (); foreach $i (@prognames) { ($prog, $type) = split ",", $i; # Strip duplicate object names. $prev = ''; @list = grep { $status = ($prev ne $_); $prev=$_; $status } sort @{$programs{$i}}; $programs{$i} = [@list]; foreach $jj (@list) { $j = $srcname{$jj}; $file = &finddep($j); if (defined $file) { $depends{$jj} = [$file]; push @scanlist, $file; } } } # Scan each file on @scanlist and find further inclusions. # Inclusions are given by lines of the form `#include "otherfile"' # (system headers are automatically ignored by this because they'll # be given in angle brackets). Files included by this method are # added back on to @scanlist to be scanned in turn (if not already # done). # # Resource scripts (.rc) can also include a file by means of a line # ending `ICON "filename"'. Files included by this method are not # added to @scanlist because they can never include further files. # # In this pass we write out a hash %further which maps a source # file name into a listref containing further source file names. %further = (); while (scalar @scanlist > 0) { $file = shift @scanlist; next if defined $further{$file}; # skip if we've already done it $further{$file} = []; $dirfile = &findfile($file); open IN, "$dirfile" or die "unable to open source file $file\n"; while () { chomp; /^\s*#include\s+\"([^\"]+)\"/ and do { push @{$further{$file}}, $1; push @scanlist, $1; next; }; /ICON\s+\"([^\"]+)\"\s*$/ and do { push @{$further{$file}}, $1; next; } } close IN; } # Now we're ready to generate the final dependencies section. For # each key in %depends, we must expand the dependencies list by # iteratively adding entries from %further. foreach $i (keys %depends) { %dep = (); @scanlist = @{$depends{$i}}; foreach $i (@scanlist) { $dep{$i} = 1; } while (scalar @scanlist > 0) { $file = shift @scanlist; foreach $j (@{$further{$file}}) { if (!$dep{$j}) { $dep{$j} = 1; push @{$depends{$i}}, $j; push @scanlist, $j; } } } # printf "%s: %s\n", $i, join ' ',@{$depends{$i}}; } # Validation of input. sub mfval($) { my ($type) = @_; # Returns true if the argument is a known makefile type. Otherwise, # prints a warning and returns false; if (grep { $type eq $_ } ("vc","vcproj","cygwin","borland","lcc","gtk","am","mpw","nestedvm","osx","wce","gnustep","emcc")) { return 1; } warn "$.:unknown makefile type '$type'\n"; return 0; } # Utility routines while writing out the Makefiles. sub dirpfx { my ($path) = shift @_; my ($sep) = shift @_; my $ret = ""; my $i; while (($i = index $path, $sep) >= 0) { $path = substr $path, ($i + length $sep); $ret .= "..$sep"; } return $ret; } sub findfile { my ($name) = @_; my $dir; my $i; my $outdir = undef; unless (defined $findfilecache{$name}) { $i = 0; foreach $dir (@srcdirs) { $outdir = $dir, $i++ if -f "$dir$name"; } die "multiple instances of source file $name\n" if $i > 1; $findfilecache{$name} = (defined $outdir ? $outdir . $name : undef); } return $findfilecache{$name}; } sub finddep { my $j = shift @_; my $file; # Find the first dependency of an object. # Dependencies for "x" start with "x.c" or "x.m" (depending on # which one exists). # Dependencies for "x.res" start with "x.rc". # Dependencies for "x.rsrc" start with "x.r". # Both types of file are pushed on the list of files to scan. # Libraries (.lib) don't have dependencies at all. if ($j =~ /^(.*)\.res$/) { $file = "$1.rc"; } elsif ($j =~ /^(.*)\.rsrc$/) { $file = "$1.r"; } elsif ($j !~ /\./) { $file = "$j.c"; $file = "$j.m" unless &findfile($file); } else { # For everything else, we assume it's its own dependency. $file = $j; } $file = undef unless &findfile($file); return $file; } sub objects { my ($prog, $otmpl, $rtmpl, $ltmpl, $prefix, $dirsep) = @_; my @ret; my ($i, $x, $y); ($otmpl, $rtmpl, $ltmpl) = map { defined $_ ? $_ : "" } ($otmpl, $rtmpl, $ltmpl); @ret = (); foreach $ii (@{$programs{$prog}}) { $i = $objname{$ii}; $x = ""; if ($i =~ /^(.*)\.(res|rsrc)/) { $y = $1; ($x = $rtmpl) =~ s/X/$y/; } elsif ($i =~ /^(.*)\.lib/) { $y = $1; ($x = $ltmpl) =~ s/X/$y/; } elsif ($i !~ /\./) { ($x = $otmpl) =~ s/X/$i/; } push @ret, $x if $x ne ""; } return join " ", @ret; } sub special { my ($prog, $suffix) = @_; my @ret; my ($i, $x, $y); @ret = (); foreach $ii (@{$programs{$prog}}) { $i = $objname{$ii}; if (substr($i, (length $i) - (length $suffix)) eq $suffix) { push @ret, $i; } } return join " ", @ret; } sub splitline { my ($line, $width, $splitchar) = @_; my $result = ""; my $len; $len = (defined $width ? $width : 76); $splitchar = (defined $splitchar ? $splitchar : '\\'); while (length $line > $len) { $line =~ /^(.{0,$len})\s(.*)$/ or $line =~ /^(.{$len,}?\s(.*)$/; $result .= $1; $result .= " ${splitchar}\n\t\t" if $2 ne ''; $line = $2; $len = 60; } return $result . $line; } sub deps { my ($otmpl, $rtmpl, $prefix, $dirsep, $depchar, $splitchar) = @_; my ($i, $x, $y); my @deps; my @ret; @ret = (); $depchar ||= ':'; foreach $ii (sort keys %depends) { $i = $objname{$ii}; next if $specialobj{$mftyp}->{$i}; if ($i =~ /^(.*)\.(res|rsrc)/) { next if !defined $rtmpl; $y = $1; ($x = $rtmpl) =~ s/X/$y/; } else { ($x = $otmpl) =~ s/X/$i/; } @deps = @{$depends{$ii}}; # Skip things which are their own dependency. next if grep { $_ eq $i } @deps; @deps = map { $_ = &findfile($_); s/\//$dirsep/g; $_ = $prefix . $_; } @deps; push @ret, {obj => $x, deps => [@deps], defs => $defs{$ii}}; } return @ret; } sub prognames { my ($types) = @_; my ($n, $prog, $type); my @ret; @ret = (); foreach $n (@prognames) { ($prog, $type) = split ",", $n; push @ret, $n if index(":$types:", ":$type:") >= 0; } return @ret; } sub progrealnames { my ($types) = @_; my ($n, $prog, $type); my @ret; @ret = (); foreach $n (@prognames) { ($prog, $type) = split ",", $n; push @ret, $prog if index(":$types:", ":$type:") >= 0; } return @ret; } sub manpages { my ($types,$suffix) = @_; # assume that all UNIX programs have a man page if($suffix eq "1" && $types =~ /:X:/) { return map("$_.1", &progrealnames($types)); } return (); } $orig_dir = cwd; # Now we're ready to output the actual Makefiles. if (defined $makefiles{'cygwin'}) { $mftyp = 'cygwin'; $dirpfx = &dirpfx($makefiles{'cygwin'}, "/"); ##-- CygWin makefile open OUT, ">$makefiles{'cygwin'}"; select OUT; print "# Makefile for $project_name under cygwin.\n". "#\n# This file was created by `mkfiles.pl' from the `Recipe' file.\n". "# DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead.\n"; # gcc command line option is -D not /D ($_ = $help) =~ s/=\/D/=-D/gs; print $_; print "\n". "# You can define this path to point at your tools if you need to\n". "# TOOLPATH = c:\\cygwin\\bin\\ # or similar, if you're running Windows\n". "# TOOLPATH = /pkg/mingw32msvc/i386-mingw32msvc/bin/\n". "CC = \$(TOOLPATH)gcc\n". "RC = \$(TOOLPATH)windres\n". "# Uncomment the following two lines to compile under Winelib\n". "# CC = winegcc\n". "# RC = wrc\n". "# You may also need to tell windres where to find include files:\n". "# RCINC = --include-dir c:\\cygwin\\include\\\n". "\n". &splitline("CFLAGS = -mno-cygwin -Wall -O2 -D_WINDOWS -DDEBUG -DWIN32S_COMPAT". " -D_NO_OLDNAMES -DNO_MULTIMON -DNO_HTMLHELP " . (join " ", map {"-I$dirpfx$_"} @srcdirs)) . "\n". "LDFLAGS = -mno-cygwin -s\n". &splitline("RCFLAGS = \$(RCINC) --define WIN32=1 --define _WIN32=1". " --define WINVER=0x0400 --define MINGW32_FIX=1 " . (join " ", map {"--include $dirpfx$_"} @srcdirs) )."\n". "\n"; print &splitline("all:" . join "", map { " $_.exe" } &progrealnames("G:C")); print "\n\n"; foreach $p (&prognames("G:C")) { ($prog, $type) = split ",", $p; $objstr = &objects($p, "X.o", "X.res.o", undef); print &splitline($prog . ".exe: " . $objstr), "\n"; my $mw = $type eq "G" ? " -mwindows" : ""; $libstr = &objects($p, undef, undef, "-lX"); print &splitline("\t\$(CC)" . $mw . " \$(LDFLAGS) -o \$@ " . "-Wl,-Map,$prog.map " . $objstr . " $libstr", 69), "\n\n"; } foreach $d (&deps("X.o", "X.res.o", $dirpfx, "/")) { print &splitline(sprintf("%s: %s", $d->{obj}, join " ", @{$d->{deps}})), "\n"; if ($d->{obj} =~ /\.res\.o$/) { print "\t\$(RC) \$(FWHACK) \$(RCFL) \$(RCFLAGS) \$< \$\@\n"; } else { $deflist = join "", map { " -D$_" } @{$d->{defs}}; print "\t\$(CC) \$(COMPAT) \$(FWHACK) \$(CFLAGS)" . " \$(XFLAGS)$deflist -c \$< -o \$\@\n"; } } print "\n"; print $makefile_extra{'cygwin'} || ""; print "\nclean:\n". "\trm -f *.o *.exe *.res.o *.map\n". "\n"; select STDOUT; close OUT; } ##-- Borland makefile if (defined $makefiles{'borland'}) { $mftyp = 'borland'; $dirpfx = &dirpfx($makefiles{'borland'}, "\\"); %stdlibs = ( # Borland provides many Win32 API libraries intrinsically "advapi32" => 1, "comctl32" => 1, "comdlg32" => 1, "gdi32" => 1, "imm32" => 1, "shell32" => 1, "user32" => 1, "winmm" => 1, "winspool" => 1, "wsock32" => 1, ); open OUT, ">$makefiles{'borland'}"; select OUT; print "# Makefile for $project_name under Borland C.\n". "#\n# This file was created by `mkfiles.pl' from the `Recipe' file.\n". "# DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead.\n"; # bcc32 command line option is -D not /D ($_ = $help) =~ s/=\/D/=-D/gs; print $_; print "\n". "# If you rename this file to `Makefile', you should change this line,\n". "# so that the .rsp files still depend on the correct makefile.\n". "MAKEFILE = Makefile.bor\n". "\n". "# C compilation flags\n". "CFLAGS = -D_WINDOWS -DWINVER=0x0401\n". "\n". "# Get include directory for resource compiler\n". "!if !\$d(BCB)\n". "BCB = \$(MAKEDIR)\\..\n". "!endif\n". "\n"; print &splitline("all:" . join "", map { " $_.exe" } &progrealnames("G:C")); print "\n\n"; foreach $p (&prognames("G:C")) { ($prog, $type) = split ",", $p; $objstr = &objects($p, "X.obj", "X.res", undef); print &splitline("$prog.exe: " . $objstr . " $prog.rsp"), "\n"; my $ap = ($type eq "G") ? "-aa" : "-ap"; print "\tilink32 $ap -Gn -L\$(BCB)\\lib \@$prog.rsp\n\n"; } foreach $p (&prognames("G:C")) { ($prog, $type) = split ",", $p; print $prog, ".rsp: \$(MAKEFILE)\n"; $objstr = &objects($p, "X.obj", undef, undef); @objlist = split " ", $objstr; @objlines = (""); foreach $i (@objlist) { if (length($objlines[$#objlines] . " $i") > 50) { push @objlines, ""; } $objlines[$#objlines] .= " $i"; } $c0w = ($type eq "G") ? "c0w32" : "c0x32"; print "\techo $c0w + > $prog.rsp\n"; for ($i=0; $i<=$#objlines; $i++) { $plus = ($i < $#objlines ? " +" : ""); print "\techo$objlines[$i]$plus >> $prog.rsp\n"; } print "\techo $prog.exe >> $prog.rsp\n"; $objstr = &objects($p, "X.obj", "X.res", undef); @libs = split " ", &objects($p, undef, undef, "X"); @libs = grep { !$stdlibs{$_} } @libs; unshift @libs, "cw32", "import32"; $libstr = join ' ', @libs; print "\techo nul,$libstr, >> $prog.rsp\n"; print "\techo " . &objects($p, undef, "X.res", undef) . " >> $prog.rsp\n"; print "\n"; } foreach $d (&deps("X.obj", "X.res", $dirpfx, "\\")) { print &splitline(sprintf("%s: %s", $d->{obj}, join " ", @{$d->{deps}})), "\n"; if ($d->{obj} =~ /\.res$/) { print &splitline("\tbrcc32 \$(FWHACK) \$(RCFL) " . "-i \$(BCB)\\include -r -DNO_WINRESRC_H -DWIN32". " -D_WIN32 -DWINVER=0x0401 \$*.rc",69)."\n"; } else { $deflist = join "", map { " -D$_" } @{$d->{defs}}; print &splitline("\tbcc32 -w-aus -w-ccc -w-par -w-pia \$(COMPAT)" . " \$(FWHACK) \$(CFLAGS) \$(XFLAGS)$deflist ". (join " ", map {"-I$dirpfx$_"} @srcdirs) . " /o$d->{obj} /c ".$d->{deps}->[0],69)."\n"; } } print "\n"; print $makefile_extra{'borland'} || ""; print "\nclean:\n". "\t-del *.obj\n". "\t-del *.exe\n". "\t-del *.res\n". "\t-del *.pch\n". "\t-del *.aps\n". "\t-del *.il*\n". "\t-del *.pdb\n". "\t-del *.rsp\n". "\t-del *.tds\n". "\t-del *.\$\$\$\$\$\$\n"; select STDOUT; close OUT; } if (defined $makefiles{'vc'}) { $mftyp = 'vc'; $dirpfx = &dirpfx($makefiles{'vc'}, "\\"); ##-- Visual C++ makefile open OUT, ">$makefiles{'vc'}"; select OUT; print "# Makefile for $project_name under Visual C.\n". "#\n# This file was created by `mkfiles.pl' from the `Recipe' file.\n". "# DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead.\n"; print $help; print "\n". "# If you rename this file to `Makefile', you should change this line,\n". "# so that the .rsp files still depend on the correct makefile.\n". "MAKEFILE = Makefile.vc\n". "\n". "# C compilation flags\n". "CFLAGS = /nologo /W3 /O1 /D_WINDOWS /D_WIN32_WINDOWS=0x401 /DWINVER=0x401 /I.\n". "LFLAGS = /incremental:no /fixed\n". "\n"; print &splitline("all:" . join "", map { " $_.exe" } &progrealnames("G:C")); print "\n\n"; foreach $p (&prognames("G:C")) { ($prog, $type) = split ",", $p; $objstr = &objects($p, "X.obj", "X.res", undef); print &splitline("$prog.exe: " . $objstr . " $prog.rsp"), "\n"; print "\tlink \$(LFLAGS) -out:$prog.exe -map:$prog.map \@$prog.rsp\n\n"; } foreach $p (&prognames("G:C")) { ($prog, $type) = split ",", $p; print $prog, ".rsp: \$(MAKEFILE)\n"; $objstr = &objects($p, "X.obj", "X.res", "X.lib"); @objlist = split " ", $objstr; @objlines = (""); foreach $i (@objlist) { if (length($objlines[$#objlines] . " $i") > 50) { push @objlines, ""; } $objlines[$#objlines] .= " $i"; } $subsys = ($type eq "G") ? "windows" : "console"; print "\techo /nologo /subsystem:$subsys > $prog.rsp\n"; for ($i=0; $i<=$#objlines; $i++) { print "\techo$objlines[$i] >> $prog.rsp\n"; } print "\n"; } foreach $d (&deps("X.obj", "X.res", $dirpfx, "\\")) { print &splitline(sprintf("%s: %s", $d->{obj}, join " ", @{$d->{deps}})), "\n"; if ($d->{obj} =~ /\.res$/) { print "\trc \$(FWHACK) \$(RCFL) -r -DWIN32 -D_WIN32 ". "-DWINVER=0x0400 -fo".$d->{obj}." ".$d->{deps}->[0]."\n"; } else { $deflist = join "", map { " /D$_" } @{$d->{defs}}; print "\tcl \$(COMPAT) \$(FWHACK) \$(CFLAGS) \$(XFLAGS)$deflist". " /c ".$d->{deps}->[0]." /Fo$d->{obj}\n"; } } print "\n"; print $makefile_extra{'vc'} || ""; print "\nclean: tidy\n". "\t-del *.exe\n\n". "tidy:\n". "\t-del *.obj\n". "\t-del *.res\n". "\t-del *.pch\n". "\t-del *.aps\n". "\t-del *.ilk\n". "\t-del *.pdb\n". "\t-del *.rsp\n". "\t-del *.dsp\n". "\t-del *.dsw\n". "\t-del *.ncb\n". "\t-del *.opt\n". "\t-del *.plg\n". "\t-del *.map\n". "\t-del *.idb\n". "\t-del debug.log\n"; select STDOUT; close OUT; } if (defined $makefiles{'wce'}) { $mftyp = 'wce'; $dirpfx = &dirpfx($makefiles{'wce'}, "\\"); ##-- eMbedded Visual C PocketPC makefile open OUT, ">$makefiles{'wce'}"; select OUT; print "# Makefile for $project_name on PocketPC using eMbedded Visual C.\n". "#\n# This file was created by `mkfiles.pl' from the `Recipe' file.\n". "# DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead.\n"; print $help; print "\n". "# If you rename this file to `Makefile', you should change this line,\n". "# so that the .rsp files still depend on the correct makefile.\n". "MAKEFILE = Makefile.wce\n". "\n". "# This makefile expects the environment to have been set up by one\n". "# of the PocketPC batch files wcearmv4.bat and wceemulator.bat. No\n". "# other build targets are currently supported, because they would\n". "# need a section in this if statement.\n". "!if \"\$(TARGETCPU)\" == \"emulator\"\n". "PLATFORM_DEFS=/D \"_i386_\" /D \"i_386_\" /D \"_X86_\" /D \"x86\"\n". "CC=cl\n". "BASELIBS=commctrl.lib coredll.lib corelibc.lib aygshell.lib\n". "MACHINE=IX86\n". "!else\n". "PLATFORM_DEFS=/D \"ARM\" /D \"_ARM_\" /D \"ARMV4\"\n". "CC=clarm\n". "BASELIBS=commctrl.lib coredll.lib aygshell.lib\n". "MACHINE=ARM\n". "!endif\n". "\n". "# C compilation flags\n". "CFLAGS = /nologo /W3 /O1 /MC /D _WIN32_WCE=420 /D \"WIN32_PLATFORM_PSPC=400\" /D UNDER_CE=420 \\\n". " \$(PLATFORM_DEFS) \\\n". " /D \"UNICODE\" /D \"_UNICODE\" /D \"NDEBUG\" /D \"NO_HTMLHELP\"\n". "\n". "LFLAGS = /nologo /incremental:no \\\n". " /base:0x00010000 /stack:0x10000,0x1000 /entry:WinMainCRTStartup \\\n". " /nodefaultlib:libc.lib /nodefaultlib:libcmt.lib /nodefaultlib:msvcrt.lib /nodefaultlib:OLDNAMES.lib \\\n". " /subsystem:windowsce,4.20 /align:4096 /MACHINE:\$(MACHINE)\n". "\n". "RCFL = /d UNDER_CE=420 /d _WIN32_WCE=420 /d \"WIN32_PLATFORM_PSPC=400\" \\\n". " \$(PLATFORM_DEFS) \\\n". " /d \"NDEBUG\" /d \"UNICODE\" /d \"_UNICODE\"\n". "\n"; print &splitline("all:" . join "", map { " $_.exe" } &progrealnames("G")); print "\n\n"; foreach $p (&prognames("G")) { ($prog, $type) = split ",", $p; $objstr = &objects($p, "X.obj", "X.res", undef); print &splitline("$prog.exe: " . $objstr . " $prog.rsp"), "\n"; print "\tlink \$(LFLAGS) -out:$prog.exe -map:$prog.map \@$prog.rsp\n\n"; } foreach $p (&prognames("G")) { ($prog, $type) = split ",", $p; print $prog, ".rsp: \$(MAKEFILE)\n"; $objstr = &objects($p, "X.obj", "X.res", undef); @objlist = split " ", $objstr; @objlines = (""); foreach $i (@objlist) { if (length($objlines[$#objlines] . " $i") > 50) { push @objlines, ""; } $objlines[$#objlines] .= " $i"; } print "\techo \$(BASELIBS) > $prog.rsp\n"; for ($i=0; $i<=$#objlines; $i++) { print "\techo$objlines[$i] >> $prog.rsp\n"; } print "\n"; } foreach $d (&deps("X.obj", "X.res", $dirpfx, "\\")) { print &splitline(sprintf("%s: %s", $d->{obj}, join " ", @{$d->{deps}})), "\n"; if ($d->{obj} =~ /\.res$/) { print "\trc \$(FWHACK) \$(RCFL) -r -fo". $d->{obj}." ".$d->{deps}->[0]."\n"; } else { $deflist = join "", map { " /D$_" } @{$d->{defs}}; print "\t\$(CC) \$(COMPAT) \$(FWHACK) \$(CFLAGS) \$(XFLAGS)$deflist". " /c ".$d->{deps}->[0]." /Fo$d->{obj}\n"; } } print "\n"; print $makefile_extra{'wce'} || ""; print "\nclean: tidy\n". "\t-del *.exe\n\n". "tidy:\n". "\t-del *.obj\n". "\t-del *.res\n". "\t-del *.pch\n". "\t-del *.aps\n". "\t-del *.ilk\n". "\t-del *.pdb\n". "\t-del *.rsp\n". "\t-del *.dsp\n". "\t-del *.dsw\n". "\t-del *.ncb\n". "\t-del *.opt\n". "\t-del *.plg\n". "\t-del *.map\n". "\t-del *.idb\n". "\t-del debug.log\n"; select STDOUT; close OUT; } if (defined $makefiles{'vcproj'}) { $mftyp = 'vcproj'; ##-- MSVC 6 Workspace and projects # # Note: All files created in this section are written in binary # mode, because although MSVC's command-line make can deal with # LF-only line endings, MSVC project files really _need_ to be # CRLF. Hence, in order for mkfiles.pl to generate usable project # files even when run from Unix, I make sure all files are binary # and explicitly write the CRLFs. # # Create directories if necessary mkdir $makefiles{'vcproj'} if(! -d $makefiles{'vcproj'}); chdir $makefiles{'vcproj'}; @deps = &deps("X.obj", "X.res", "", "\\"); %all_object_deps = map {$_->{obj} => $_->{deps}} @deps; # Create the project files # Get names of all Windows projects (GUI and console) my @prognames = &prognames("G:C"); foreach $progname (@prognames) { create_project(\%all_object_deps, $progname); } # Create the workspace file open OUT, ">$project_name.dsw"; binmode OUT; select OUT; print "Microsoft Developer Studio Workspace File, Format Version 6.00\r\n". "# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!\r\n". "\r\n". "###############################################################################\r\n". "\r\n"; # List projects foreach $progname (@prognames) { ($windows_project, $type) = split ",", $progname; print "Project: \"$windows_project\"=\".\\$windows_project\\$windows_project.dsp\" - Package Owner=<4>\r\n"; } print "\r\n". "Package=<5>\r\n". "{{{\r\n". "}}}\r\n". "\r\n". "Package=<4>\r\n". "{{{\r\n". "}}}\r\n". "\r\n". "###############################################################################\r\n". "\r\n". "Global:\r\n". "\r\n". "Package=<5>\r\n". "{{{\r\n". "}}}\r\n". "\r\n". "Package=<3>\r\n". "{{{\r\n". "}}}\r\n". "\r\n". "###############################################################################\r\n". "\r\n"; select STDOUT; close OUT; chdir $orig_dir; sub create_project { my ($all_object_deps, $progname) = @_; # Construct program's dependency info %seen_objects = (); %lib_files = (); %source_files = (); %header_files = (); %resource_files = (); @object_files = split " ", &objects($progname, "X.obj", "X.res", "X.lib"); foreach $object_file (@object_files) { next if defined $seen_objects{$object_file}; $seen_objects{$object_file} = 1; if($object_file =~ /\.lib$/io) { $lib_files{$object_file} = 1; next; } $object_deps = $all_object_deps{$object_file}; foreach $object_dep (@$object_deps) { if($object_dep =~ /\.c$/io) { $source_files{$object_dep} = 1; next; } if($object_dep =~ /\.h$/io) { $header_files{$object_dep} = 1; next; } if($object_dep =~ /\.(rc|ico)$/io) { $resource_files{$object_dep} = 1; next; } } } $libs = join " ", sort keys %lib_files; @source_files = sort keys %source_files; @header_files = sort keys %header_files; @resources = sort keys %resource_files; ($windows_project, $type) = split ",", $progname; mkdir $windows_project if(! -d $windows_project); chdir $windows_project; $subsys = ($type eq "G") ? "windows" : "console"; open OUT, ">$windows_project.dsp"; binmode OUT; select OUT; print "# Microsoft Developer Studio Project File - Name=\"$windows_project\" - Package Owner=<4>\r\n". "# Microsoft Developer Studio Generated Build File, Format Version 6.00\r\n". "# ** DO NOT EDIT **\r\n". "\r\n". "# TARGTYPE \"Win32 (x86) Application\" 0x0101\r\n". "\r\n". "CFG=$windows_project - Win32 Debug\r\n". "!MESSAGE This is not a valid makefile. To build this project using NMAKE,\r\n". "!MESSAGE use the Export Makefile command and run\r\n". "!MESSAGE \r\n". "!MESSAGE NMAKE /f \"$windows_project.mak\".\r\n". "!MESSAGE \r\n". "!MESSAGE You can specify a configuration when running NMAKE\r\n". "!MESSAGE by defining the macro CFG on the command line. For example:\r\n". "!MESSAGE \r\n". "!MESSAGE NMAKE /f \"$windows_project.mak\" CFG=\"$windows_project - Win32 Debug\"\r\n". "!MESSAGE \r\n". "!MESSAGE Possible choices for configuration are:\r\n". "!MESSAGE \r\n". "!MESSAGE \"$windows_project - Win32 Release\" (based on \"Win32 (x86) Application\")\r\n". "!MESSAGE \"$windows_project - Win32 Debug\" (based on \"Win32 (x86) Application\")\r\n". "!MESSAGE \r\n". "\r\n". "# Begin Project\r\n". "# PROP AllowPerConfigDependencies 0\r\n". "# PROP Scc_ProjName \"\"\r\n". "# PROP Scc_LocalPath \"\"\r\n". "CPP=cl.exe\r\n". "MTL=midl.exe\r\n". "RSC=rc.exe\r\n". "\r\n". "!IF \"\$(CFG)\" == \"$windows_project - Win32 Release\"\r\n". "\r\n". "# PROP BASE Use_MFC 0\r\n". "# PROP BASE Use_Debug_Libraries 0\r\n". "# PROP BASE Output_Dir \"Release\"\r\n". "# PROP BASE Intermediate_Dir \"Release\"\r\n". "# PROP BASE Target_Dir \"\"\r\n". "# PROP Use_MFC 0\r\n". "# PROP Use_Debug_Libraries 0\r\n". "# PROP Output_Dir \"Release\"\r\n". "# PROP Intermediate_Dir \"Release\"\r\n". "# PROP Ignore_Export_Lib 0\r\n". "# PROP Target_Dir \"\"\r\n". "# ADD BASE CPP /nologo /W3 /GX /O2 /D \"WIN32\" /D \"NDEBUG\" /D \"_WINDOWS\" /D \"_MBCS\" /YX /FD /c\r\n". "# ADD CPP /nologo /W3 /GX /O2 /D \"WIN32\" /D \"NDEBUG\" /D \"_WINDOWS\" /D \"_MBCS\" /YX /FD /c\r\n". "# ADD BASE MTL /nologo /D \"NDEBUG\" /mktyplib203 /win32\r\n". "# ADD MTL /nologo /D \"NDEBUG\" /mktyplib203 /win32\r\n". "# ADD BASE RSC /l 0x809 /d \"NDEBUG\"\r\n". "# ADD RSC /l 0x809 /d \"NDEBUG\"\r\n". "BSC32=bscmake.exe\r\n". "# ADD BASE BSC32 /nologo\r\n". "# ADD BSC32 /nologo\r\n". "LINK32=link.exe\r\n". "# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:$subsys /machine:I386\r\n". "# ADD LINK32 $libs /nologo /subsystem:$subsys /machine:I386\r\n". "# SUBTRACT LINK32 /pdb:none\r\n". "\r\n". "!ELSEIF \"\$(CFG)\" == \"$windows_project - Win32 Debug\"\r\n". "\r\n". "# PROP BASE Use_MFC 0\r\n". "# PROP BASE Use_Debug_Libraries 1\r\n". "# PROP BASE Output_Dir \"Debug\"\r\n". "# PROP BASE Intermediate_Dir \"Debug\"\r\n". "# PROP BASE Target_Dir \"\"\r\n". "# PROP Use_MFC 0\r\n". "# PROP Use_Debug_Libraries 1\r\n". "# PROP Output_Dir \"Debug\"\r\n". "# PROP Intermediate_Dir \"Debug\"\r\n". "# PROP Ignore_Export_Lib 0\r\n". "# PROP Target_Dir \"\"\r\n". "# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D \"WIN32\" /D \"_DEBUG\" /D \"_WINDOWS\" /D \"_MBCS\" /YX /FD /GZ /c\r\n". "# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D \"WIN32\" /D \"_DEBUG\" /D \"_WINDOWS\" /D \"_MBCS\" /YX /FD /GZ /c\r\n". "# ADD BASE MTL /nologo /D \"_DEBUG\" /mktyplib203 /win32\r\n". "# ADD MTL /nologo /D \"_DEBUG\" /mktyplib203 /win32\r\n". "# ADD BASE RSC /l 0x809 /d \"_DEBUG\"\r\n". "# ADD RSC /l 0x809 /d \"_DEBUG\"\r\n". "BSC32=bscmake.exe\r\n". "# ADD BASE BSC32 /nologo\r\n". "# ADD BSC32 /nologo\r\n". "LINK32=link.exe\r\n". "# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:$subsys /debug /machine:I386 /pdbtype:sept\r\n". "# ADD LINK32 $libs /nologo /subsystem:$subsys /debug /machine:I386 /pdbtype:sept\r\n". "# SUBTRACT LINK32 /pdb:none\r\n". "\r\n". "!ENDIF \r\n". "\r\n". "# Begin Target\r\n". "\r\n". "# Name \"$windows_project - Win32 Release\"\r\n". "# Name \"$windows_project - Win32 Debug\"\r\n". "# Begin Group \"Source Files\"\r\n". "\r\n". "# PROP Default_Filter \"cpp;c;cxx;rc;def;r;odl;idl;hpj;bat\"\r\n"; foreach $source_file (@source_files) { print "# Begin Source File\r\n". "\r\n". "SOURCE=..\\..\\$source_file\r\n"; if($source_file =~ /ssh\.c/io) { # Disable 'Edit and continue' as Visual Studio can't handle the macros print "\r\n". "!IF \"\$(CFG)\" == \"$windows_project - Win32 Release\"\r\n". "\r\n". "!ELSEIF \"\$(CFG)\" == \"$windows_project - Win32 Debug\"\r\n". "\r\n". "# ADD CPP /Zi\r\n". "\r\n". "!ENDIF \r\n". "\r\n"; } print "# End Source File\r\n"; } print "# End Group\r\n". "# Begin Group \"Header Files\"\r\n". "\r\n". "# PROP Default_Filter \"h;hpp;hxx;hm;inl\"\r\n"; foreach $header_file (@header_files) { print "# Begin Source File\r\n". "\r\n". "SOURCE=..\\..\\$header_file\r\n". "# End Source File\r\n"; } print "# End Group\r\n". "# Begin Group \"Resource Files\"\r\n". "\r\n". "# PROP Default_Filter \"ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe\"\r\n"; foreach $resource_file (@resources) { print "# Begin Source File\r\n". "\r\n". "SOURCE=..\\..\\$resource_file\r\n". "# End Source File\r\n"; } print "# End Group\r\n". "# End Target\r\n". "# End Project\r\n"; select STDOUT; close OUT; chdir ".."; } } if (defined $makefiles{'gtk'}) { $mftyp = 'gtk'; $dirpfx = &dirpfx($makefiles{'gtk'}, "/"); ##-- X/GTK/Unix makefile open OUT, ">$makefiles{'gtk'}"; select OUT; print "# Makefile for $project_name under X/GTK and Unix.\n". "#\n# This file was created by `mkfiles.pl' from the `Recipe' file.\n". "# DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead.\n"; # gcc command line option is -D not /D ($_ = $help) =~ s/=\/D/=-D/gs; print $_; print "\n". "# You can define this path to point at your tools if you need to\n". "# TOOLPATH = /opt/gcc/bin\n". "CC := \$(TOOLPATH)\$(CC)\n". "# You can manually set this to `gtk-config' or `pkg-config gtk+-1.2'\n". "# (depending on what works on your system) if you want to enforce\n". "# building with GTK 1.2, or you can set it to `pkg-config gtk+-2.0'\n". "# if you want to enforce 2.0. The default is to try 2.0 and fall back\n". "# to 1.2 if it isn't found.\n". "GTK_CONFIG = sh -c 'pkg-config gtk+-2.0 \$\$0 2>/dev/null || gtk-config \$\$0'\n". "\n". &splitline("CFLAGS := -O2 -Wall -Werror -ansi -pedantic -g " . (join " ", map {"-I$dirpfx$_"} @srcdirs) . " `\$(GTK_CONFIG) --cflags` \$(CFLAGS)")."\n". "XLIBS = `\$(GTK_CONFIG) --libs` -lm\n". "ULIBS = -lm#\n". "INSTALL=install\n", "INSTALL_PROGRAM=\$(INSTALL)\n", "INSTALL_DATA=\$(INSTALL)\n", "prefix=/usr/local\n", "exec_prefix=\$(prefix)\n", "bindir=\$(exec_prefix)/bin\n", "gamesdir=\$(exec_prefix)/games\n", "mandir=\$(prefix)/man\n", "man1dir=\$(mandir)/man1\n", "\n"; print &splitline("all:" . join "", map { " \$(BINPREFIX)$_" } &progrealnames("X:U")); print "\n\n"; foreach $p (&prognames("X:U")) { ($prog, $type) = split ",", $p; $objstr = &objects($p, "X.o", undef, undef); print &splitline("\$(BINPREFIX)" . $prog . ": " . $objstr), "\n"; $libstr = &objects($p, undef, undef, "-lX"); print &splitline("\t\$(CC) -o \$@ $objstr $libstr \$(XLFLAGS) \$(${type}LIBS)", 69), "\n\n"; } foreach $d (&deps("X.o", undef, $dirpfx, "/")) { print &splitline(sprintf("%s: %s", $d->{obj}, join " ", @{$d->{deps}})), "\n"; $deflist = join "", map { " -D$_" } @{$d->{defs}}; print "\t\$(CC) \$(COMPAT) \$(FWHACK) \$(CFLAGS) \$(XFLAGS)$deflist" . " -c \$< -o \$\@\n"; } print "\n"; print $makefile_extra{'gtk'} || ""; print "\nclean:\n". "\trm -f *.o". (join "", map { " \$(BINPREFIX)$_" } &progrealnames("X:U")) . "\n"; select STDOUT; close OUT; } if (defined $makefiles{'am'}) { $mftyp = 'am'; die "Makefile.am in a subdirectory is not supported\n" if &dirpfx($makefiles{'am'}, "/") ne ""; ##-- Unix/autoconf Makefile.am open OUT, ">$makefiles{'am'}"; select OUT; print "# Makefile.am for $project_name under Unix with Autoconf/Automake.\n". "#\n# This file was created by `mkfiles.pl' from the `Recipe' file.\n". "# DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead.\n\n"; print $makefile_extra{'am_begin'} || ""; # All programs go in noinstprogs by default. If you want them # installed anywhere else, you have to also add them to # bin_PROGRAMS using '!begin am'. (Automake doesn't seem to mind # having a program name in _both_ of bin_PROGRAMS and # noinst_PROGRAMS.) @noinstprogs = (); foreach $p (&prognames("X:U")) { ($prog, $type) = split ",", $p; push @noinstprogs, $prog; } print &splitline(join " ", "noinst_PROGRAMS", "=", @noinstprogs), "\n"; %objtosrc = (); %amspeciallibs = (); %amlibobjname = (); %allsources = (); foreach $d (&deps("X", undef, "", "/", "am")) { my $obj = $d->{obj}; my $use_archive = 0; if (defined $d->{defs}) { # This file needs to go in an archive, so that we can # change the preprocess flags to include some -Ds $use_archive = 1; $archivecppflags{$obj} = [map { " -D$_" } @{$d->{defs}}]; } if (defined $cflags{'am'} && $cflags{'am'}->{$obj}) { # This file needs to go in an archive, so that we can # change the compile flags as specified in Recipe $use_archive = 1; $archivecflags{$obj} = [$cflags{'am'}->{$obj}]; } if ($use_archive) { $amspeciallibs{$obj} = "lib${obj}.a"; $amlibobjname{$obj} = "lib${obj}_a-" . basename($d->{deps}->[0], ".c", ".m") . ".\$(OBJEXT)"; } $objtosrc{$obj} = $d->{deps}; map { $allsources{$_} = 1 } @{$d->{deps}}; } # 2014-02-22: as of automake-1.14 we begin to get complained at if # we don't use this option print "AUTOMAKE_OPTIONS = subdir-objects\n\n"; # Complete list of source and header files. Not used by the # auto-generated parts of this makefile, but Recipe might like to # have it available as a variable so that mandatory-rebuild things # (version.o) can conveniently be made to depend on it. print &splitline(join " ", "allsources", "=", sort {$a cmp $b} keys %allsources), "\n\n"; @amcppflags = map {"-I\$(srcdir)/$_"} @srcdirs; print &splitline(join " ", "AM_CPPFLAGS", "=", @amcppflags, "\n"); @amcflags = ("\$(GTK_CFLAGS)", "\$(WARNINGOPTS)"); print &splitline(join " ", "AM_CFLAGS", "=", @amcflags), "\n"; %amlibsused = (); foreach $p (&prognames("X:U")) { ($prog, $type) = split ",", $p; @progsources = ("${prog}_SOURCES", "="); %sourcefiles = (); @ldadd = (); $objstr = &objects($p, "X", undef, undef); foreach $obj (split / /,$objstr) { if ($amspeciallibs{$obj}) { $amlibsused{$obj} = 1; push @ldadd, $amlibobjname{$obj}; } else { map { $sourcefiles{$_} = 1 } @{$objtosrc{$obj}}; } } push @progsources, sort { $a cmp $b } keys %sourcefiles; print &splitline(join " ", @progsources), "\n"; if ($type eq "X") { push @ldadd, "\$(GTK_LIBS)"; } push @ldadd, "-lm"; print &splitline(join " ", "${prog}_LDADD", "=", @ldadd), "\n"; print "\n"; } foreach $obj (sort { $a cmp $b } keys %amlibsused) { print &splitline(join " ", "lib${obj}_a_SOURCES", "=", @{$objtosrc{$obj}}), "\n"; print &splitline(join " ", "lib${obj}_a_CPPFLAGS", "=", @amcflags, @{$archivecppflags{$obj}}), "\n" if $archivecppflags{$obj}; print &splitline(join " ", "lib${obj}_a_CFLAGS", "=", @amcflags, @{$archivecflags{$obj}}), "\n" if $archivecflags{$obj}; } print &splitline(join " ", "noinst_LIBRARIES", "=", sort { $a cmp $b } map { $amspeciallibs{$_} } keys %amlibsused), "\n\n"; print $makefile_extra{'am'} || ""; select STDOUT; close OUT; } if (defined $makefiles{'mpw'}) { $mftyp = 'mpw'; ##-- MPW Makefile open OUT, ">$makefiles{'mpw'}"; select OUT; print "# Makefile for $project_name under MPW.\n#\n". "# This file was created by `mkfiles.pl' from the `Recipe' file.\n". "# DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead.\n"; # MPW command line option is -d not /D ($_ = $help) =~ s/=\/D/=-d /gs; print $_; print "\n\n". "ROptions = `Echo \"{VER}\" | StreamEdit -e \"1,\$ replace /=(\xc5)\xa81\xb0/ 'STR=\xb6\xb6\xb6\xb6\xb6\"' \xa81 '\xb6\xb6\xb6\xb6\xb6\"'\"`". "\n". "C_68K = {C}\n". "C_CFM68K = {C}\n". "C_PPC = {PPCC}\n". "C_Carbon = {PPCC}\n". "\n". "# -w 35 disables \"unused parameter\" warnings\n". "COptions = -i : -i :: -i ::charset -w 35 -w err -proto strict -ansi on \xb6\n". " -notOnce\n". "COptions_68K = {COptions} -model far -opt time\n". "# Enabling \"-opt space\" for CFM-68K gives me undefined references to\n". "# _\$LDIVT and _\$LMODT.\n". "COptions_CFM68K = {COptions} -model cfmSeg -opt time\n". "COptions_PPC = {COptions} -opt size -traceback\n". "COptions_Carbon = {COptions} -opt size -traceback -d TARGET_API_MAC_CARBON\n". "\n". "Link_68K = ILink\n". "Link_CFM68K = ILink\n". "Link_PPC = PPCLink\n". "Link_Carbon = PPCLink\n". "\n". "LinkOptions = -c 'pTTY'\n". "LinkOptions_68K = {LinkOptions} -br 68k -model far -compact\n". "LinkOptions_CFM68K = {LinkOptions} -br 020 -model cfmseg -compact\n". "LinkOptions_PPC = {LinkOptions}\n". "LinkOptions_Carbon = -m __appstart -w {LinkOptions}\n". "\n". "Libs_68K = \"{CLibraries}StdCLib.far.o\" \xb6\n". " \"{Libraries}MacRuntime.o\" \xb6\n". " \"{Libraries}MathLib.far.o\" \xb6\n". " \"{Libraries}IntEnv.far.o\" \xb6\n". " \"{Libraries}Interface.o\" \xb6\n". " \"{Libraries}Navigation.far.o\" \xb6\n". " \"{Libraries}OpenTransport.o\" \xb6\n". " \"{Libraries}OpenTransportApp.o\" \xb6\n". " \"{Libraries}OpenTptInet.o\" \xb6\n". " \"{Libraries}UnicodeConverterLib.far.o\"\n". "\n". "Libs_CFM = \"{SharedLibraries}InterfaceLib\" \xb6\n". " \"{SharedLibraries}StdCLib\" \xb6\n". " \"{SharedLibraries}AppearanceLib\" \xb6\n". " -weaklib AppearanceLib \xb6\n". " \"{SharedLibraries}NavigationLib\" \xb6\n". " -weaklib NavigationLib \xb6\n". " \"{SharedLibraries}TextCommon\" \xb6\n". " -weaklib TextCommon \xb6\n". " \"{SharedLibraries}UnicodeConverter\" \xb6\n". " -weaklib UnicodeConverter\n". "\n". "Libs_CFM68K = {Libs_CFM} \xb6\n". " \"{CFM68KLibraries}NuMacRuntime.o\"\n". "\n". "Libs_PPC = {Libs_CFM} \xb6\n". " \"{SharedLibraries}ControlsLib\" \xb6\n". " -weaklib ControlsLib \xb6\n". " \"{SharedLibraries}WindowsLib\" \xb6\n". " -weaklib WindowsLib \xb6\n". " \"{SharedLibraries}OpenTransportLib\" \xb6\n". " -weaklib OTClientLib \xb6\n". " -weaklib OTClientUtilLib \xb6\n". " \"{SharedLibraries}OpenTptInternetLib\" \xb6\n". " -weaklib OTInetClientLib \xb6\n". " \"{PPCLibraries}StdCRuntime.o\" \xb6\n". " \"{PPCLibraries}PPCCRuntime.o\" \xb6\n". " \"{PPCLibraries}CarbonAccessors.o\" \xb6\n". " \"{PPCLibraries}OpenTransportAppPPC.o\" \xb6\n". " \"{PPCLibraries}OpenTptInetPPC.o\"\n". "\n". "Libs_Carbon = \"{PPCLibraries}CarbonStdCLib.o\" \xb6\n". " \"{PPCLibraries}StdCRuntime.o\" \xb6\n". " \"{PPCLibraries}PPCCRuntime.o\" \xb6\n". " \"{SharedLibraries}CarbonLib\" \xb6\n". " \"{SharedLibraries}StdCLib\"\n". "\n"; print &splitline("all \xc4 " . join(" ", &progrealnames("M")), undef, "\xb6"); print "\n\n"; foreach $p (&prognames("M")) { ($prog, $type) = split ",", $p; print &splitline("$prog \xc4 $prog.68k $prog.ppc $prog.carbon", undef, "\xb6"), "\n\n"; $rsrc = &objects($p, "", "X.rsrc", undef); foreach $arch (qw(68K CFM68K PPC Carbon)) { $objstr = &objects($p, "X.\L$arch\E.o", "", undef); print &splitline("$prog.\L$arch\E \xc4 $objstr $rsrc", undef, "\xb6"); print "\n"; print &splitline("\tDuplicate -y $rsrc {Targ}", 69, "\xb6"), "\n"; print &splitline("\t{Link_$arch} -o {Targ} -fragname $prog " . "{LinkOptions_$arch} " . $objstr . " {Libs_$arch}", 69, "\xb6"), "\n"; print &splitline("\tSetFile -a BMi {Targ}", 69, "\xb6"), "\n\n"; } } foreach $d (&deps("", "X.rsrc", "::", ":")) { next unless $d->{obj}; print &splitline(sprintf("%s \xc4 %s", $d->{obj}, join " ", @{$d->{deps}}), undef, "\xb6"), "\n"; print "\tRez ", $d->{deps}->[0], " -o {Targ} {ROptions}\n\n"; } foreach $arch (qw(68K CFM68K)) { foreach $d (&deps("X.\L$arch\E.o", "", "::", ":")) { next unless $d->{obj}; print &splitline(sprintf("%s \xc4 %s", $d->{obj}, join " ", @{$d->{deps}}), undef, "\xb6"), "\n"; print "\t{C_$arch} ", $d->{deps}->[0], " -o {Targ} {COptions_$arch}\n\n"; } } foreach $arch (qw(PPC Carbon)) { foreach $d (&deps("X.\L$arch\E.o", "", "::", ":")) { next unless $d->{obj}; print &splitline(sprintf("%s \xc4 %s", $d->{obj}, join " ", @{$d->{deps}}), undef, "\xb6"), "\n"; # The odd stuff here seems to stop afpd getting confused. print "\techo -n > {Targ}\n"; print "\tsetfile -t XCOF {Targ}\n"; print "\t{C_$arch} ", $d->{deps}->[0], " -o {Targ} {COptions_$arch}\n\n"; } } select STDOUT; close OUT; } if (defined $makefiles{'lcc'}) { $mftyp = 'lcc'; $dirpfx = &dirpfx($makefiles{'lcc'}, "\\"); ##-- lcc makefile open OUT, ">$makefiles{'lcc'}"; select OUT; print "# Makefile for $project_name under lcc.\n". "#\n# This file was created by `mkfiles.pl' from the `Recipe' file.\n". "# DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead.\n"; # lcc command line option is -D not /D ($_ = $help) =~ s/=\/D/=-D/gs; print $_; print "\n". "# If you rename this file to `Makefile', you should change this line,\n". "# so that the .rsp files still depend on the correct makefile.\n". "MAKEFILE = Makefile.lcc\n". "\n". "# C compilation flags\n". "CFLAGS = -D_WINDOWS " . (join " ", map {"-I$dirpfx$_"} @srcdirs) . "\n". "\n". "# Get include directory for resource compiler\n". "\n"; print &splitline("all:" . join "", map { " $_.exe" } &progrealnames("G:C")); print "\n\n"; foreach $p (&prognames("G:C")) { ($prog, $type) = split ",", $p; $objstr = &objects($p, "X.obj", "X.res", undef); print &splitline("$prog.exe: " . $objstr ), "\n"; $subsystemtype = undef; if ($type eq "G") { $subsystemtype = "-subsystem windows"; } my $libss = "shell32.lib wsock32.lib ws2_32.lib winspool.lib winmm.lib imm32.lib"; print &splitline("\tlcclnk $subsystemtype -o $prog.exe $objstr $libss"); print "\n\n"; } foreach $d (&deps("X.obj", "X.res", $dirpfx, "\\")) { print &splitline(sprintf("%s: %s", $d->{obj}, join " ", @{$d->{deps}})), "\n"; if ($d->{obj} =~ /\.res$/) { print &splitline("\tlrc \$(FWHACK) \$(RCFL) -r \$*.rc",69)."\n"; } else { $deflist = join "", map { " -D$_" } @{$d->{defs}}; print &splitline("\tlcc -O -p6 \$(COMPAT) \$(FWHACK) \$(CFLAGS)". " \$(XFLAGS)$deflist ".$d->{deps}->[0]." -o \$\@",69)."\n"; } } print "\n"; print $makefile_extra{'lcc'} || ""; print "\nclean:\n". "\t-del *.obj\n". "\t-del *.exe\n". "\t-del *.res\n"; select STDOUT; close OUT; } if (defined $makefiles{'nestedvm'}) { $mftyp = 'nestedvm'; $dirpfx = &dirpfx($makefiles{'nestedvm'}, "/"); ##-- NestedVM makefile open OUT, ">$makefiles{'nestedvm'}"; select OUT; print "# Makefile for $project_name under NestedVM.\n". "#\n# This file was created by `mkfiles.pl' from the `Recipe' file.\n". "# DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead.\n"; # gcc command line option is -D not /D ($_ = $help) =~ s/=\/D/=-D/gs; print $_; print "\n". "# This path points at the nestedvm root directory\n". "NESTEDVM = /opt/nestedvm\n". "# You can define this path to point at your tools if you need to\n". "TOOLPATH = \$(NESTEDVM)/upstream/install/bin\n". "CC = \$(TOOLPATH)/mips-unknown-elf-gcc\n". "\n". &splitline("CFLAGS = -O2 -Wall -Werror -DSLOW_SYSTEM -g " . (join " ", map {"-I$dirpfx$_"} @srcdirs))."\n". "\n"; print &splitline("all:" . join "", map { " $_.jar" } &progrealnames("X")); print "\n\n"; foreach $p (&prognames("X")) { ($prog, $type) = split ",", $p; $objstr = &objects($p, "X.o", undef, undef); $objstr =~ s/gtk\.o/nestedvm\.o/g; print &splitline($prog . ".mips: " . $objstr), "\n"; $libstr = &objects($p, undef, undef, "-lX"); print &splitline("\t\$(CC) \$(${type}LDFLAGS) -o \$@ " . $objstr . " $libstr -lm", 69), "\n\n"; } foreach $d (&deps("X.o", undef, $dirpfx, "/")) { $oobjs = $d->{obj}; $ddeps= join " ", @{$d->{deps}}; $oobjs =~ s/gtk/nestedvm/g; $ddeps =~ s/gtk/nestedvm/g; print &splitline(sprintf("%s: %s", $oobjs, $ddeps)), "\n"; $deflist = join "", map { " -D$_" } @{$d->{defs}}; print "\t\$(CC) \$(COMPAT) \$(FWHACK) \$(CFLAGS) \$(XFLAGS)$deflist" . " -c \$< -o \$\@\n"; } print "\n"; print $makefile_extra{'nestedvm'} || ""; print "\nclean:\n". "\trm -rf *.o *.mips *.class *.html *.jar org applet.manifest\n"; select STDOUT; close OUT; } if (defined $makefiles{'osx'}) { $mftyp = 'osx'; $dirpfx = &dirpfx($makefiles{'osx'}, "/"); @osxarchs = ('i386'); ##-- Mac OS X makefile open OUT, ">$makefiles{'osx'}"; select OUT; print "# Makefile for $project_name under Mac OS X.\n". "#\n# This file was created by `mkfiles.pl' from the `Recipe' file.\n". "# DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead.\n"; # gcc command line option is -D not /D ($_ = $help) =~ s/=\/D/=-D/gs; print $_; print "CC = \$(TOOLPATH)gcc\n". "LIPO = \$(TOOLPATH)lipo\n". "\n". &splitline("CFLAGS = -O2 -Wall -Werror -g " . (join " ", map {"-I$dirpfx$_"} @srcdirs))."\n". "LDFLAGS = -framework Cocoa\n". &splitline("all:" . join "", map { " $_" } &progrealnames("MX:U")) . "\n"; print $makefile_extra{'osx'} || ""; print "\n". ".SUFFIXES: .o .c .m\n". "\n"; print "\n\n"; foreach $p (&prognames("MX")) { ($prog, $type) = split ",", $p; $icon = &special($p, ".icns"); $infoplist = &special($p, "info.plist"); print "${prog}.app:\n\tmkdir -p \$\@\n"; print "${prog}.app/Contents: ${prog}.app\n\tmkdir -p \$\@\n"; print "${prog}.app/Contents/MacOS: ${prog}.app/Contents\n\tmkdir -p \$\@\n"; $targets = "${prog}.app/Contents/MacOS/$prog"; if (defined $icon) { print "${prog}.app/Contents/Resources: ${prog}.app/Contents\n\tmkdir -p \$\@\n"; print "${prog}.app/Contents/Resources/${prog}.icns: ${prog}.app/Contents/Resources $icon\n\tcp $icon \$\@\n"; $targets .= " ${prog}.app/Contents/Resources/${prog}.icns"; } if (defined $infoplist) { print "${prog}.app/Contents/Info.plist: ${prog}.app/Contents/Resources $infoplist\n\tcp $infoplist \$\@\n"; $targets .= " ${prog}.app/Contents/Info.plist"; } $targets .= " \$(${prog}_extra)"; print &splitline("${prog}: $targets", 69) . "\n\n"; $libstr = &objects($p, undef, undef, "-lX"); $archbins = ""; foreach $arch (@osxarchs) { $objstr = &objects($p, "X.${arch}.o", undef, undef); print &splitline("${prog}.${arch}.bin: " . $objstr), "\n"; print &splitline("\t\$(CC) -arch ${arch} -mmacosx-version-min=10.4 \$(LDFLAGS) -o \$@ " . $objstr . " $libstr", 69), "\n\n"; $archbins .= " ${prog}.${arch}.bin"; } print &splitline("${prog}.app/Contents/MacOS/$prog: ". "${prog}.app/Contents/MacOS" . $archbins), "\n"; print &splitline("\t\$(LIPO) -create $archbins -output \$@", 69), "\n\n"; } foreach $p (&prognames("U")) { ($prog, $type) = split ",", $p; $libstr = &objects($p, undef, undef, "-lX"); $archbins = ""; foreach $arch (@osxarchs) { $objstr = &objects($p, "X.${arch}.o", undef, undef); print &splitline("${prog}.${arch}: " . $objstr), "\n"; print &splitline("\t\$(CC) -arch ${arch} -mmacosx-version-min=10.4 \$(ULDFLAGS) -o \$@ " . $objstr . " $libstr", 69), "\n\n"; $archbins .= " ${prog}.${arch}"; } print &splitline("${prog}:" . $archbins), "\n"; print &splitline("\t\$(LIPO) -create $archbins -output \$@", 69), "\n\n"; } foreach $arch (@osxarchs) { foreach $d (&deps("X.${arch}.o", undef, $dirpfx, "/")) { print &splitline(sprintf("%s: %s", $d->{obj}, join " ", @{$d->{deps}})), "\n"; $deflist = join "", map { " -D$_" } @{$d->{defs}}; if ($d->{deps}->[0] =~ /\.m$/) { print "\t\$(CC) -arch $arch -mmacosx-version-min=10.4 -x objective-c \$(COMPAT) \$(FWHACK) \$(CFLAGS)". " \$(XFLAGS)$deflist -c \$< -o \$\@\n"; } else { print "\t\$(CC) -arch $arch -mmacosx-version-min=10.4 \$(COMPAT) \$(FWHACK) \$(CFLAGS) \$(XFLAGS)$deflist" . " -c \$< -o \$\@\n"; } } } print "\nclean:\n". "\trm -f *.o *.dmg". (join "", map { my $a=$_; (" $a", map { " ${a}.$_" } @osxarchs) } &progrealnames("U")) . "\n". "\trm -rf *.app\n"; select STDOUT; close OUT; } if (defined $makefiles{'gnustep'}) { $mftyp = 'gnustep'; $dirpfx = &dirpfx($makefiles{'gnustep'}, "/"); ##-- GNUstep makefile (use with 'gs_make -f Makefile.gnustep') # This is a pretty evil way to do things. In an ideal world, I'd # use the approved GNUstep makefile mechanism which just defines a # variable or two saying what source files go into what binary and # then includes application.make. Unfortunately, that has the # automake-ish limitation that it doesn't let you choose different # command lines for each object, so I can't arrange for all those # files with -DTHIS and -DTHAT to Just Work. # # A simple if ugly fix would be to have mkfiles.pl construct a # directory full of stub C files of the form '#define thing', # '#include "real_source_file"', and then reference those in this # makefile. That would also make it easy to build a proper # automake makefile. open OUT, ">$makefiles{'gnustep'}"; select OUT; print "# Makefile for $project_name under GNUstep.\n". "#\n# This file was created by `mkfiles.pl' from the `Recipe' file.\n". "# DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead.\n"; # gcc command line option is -D not /D ($_ = $help) =~ s/=\/D/=-D/gs; print $_; print "NEEDS_GUI=yes\n". "include \$(GNUSTEP_MAKEFILES)/common.make\n". "include \$(GNUSTEP_MAKEFILES)/rules.make\n". "include \$(GNUSTEP_MAKEFILES)/Instance/rules.make\n". "\n". &splitline("all::" . join "", map { " $_" } &progrealnames("MX:U")) . "\n"; print $makefile_extra{'gnustep'} || ""; print "\n". ".SUFFIXES: .o .c .m\n". "\n"; print "\n\n"; foreach $p (&prognames("MX")) { ($prog, $type) = split ",", $p; $icon = &special($p, ".icns"); $infoplist = &special($p, "info.plist"); print "${prog}.app:\n\tmkdir -p \$\@\n"; $targets = "${prog}.app ${prog}.app/$prog"; if (defined $icon) { print "${prog}.app/Resources: ${prog}.app\n\tmkdir -p \$\@\n"; print "${prog}.app/Resources/${prog}.icns: ${prog}.app/Resources $icon\n\tcp $icon \$\@\n"; $targets .= " ${prog}.app/Resources/${prog}.icns"; } if (defined $infoplist) { print "${prog}.app/Info.plist: ${prog}.app $infoplist\n\tcp $infoplist \$\@\n"; $targets .= " ${prog}.app/Info.plist"; } $targets .= " \$(${prog}_extra)"; print &splitline("${prog}: $targets", 69) . "\n\n"; $libstr = &objects($p, undef, undef, "-lX"); $objstr = &objects($p, "X.o", undef, undef); print &splitline("${prog}.app/$prog: " . $objstr), "\n"; print &splitline("\t\$(CC) \$(ALL_LDFLAGS) -o \$@ " . $objstr . " \$(ALL_LIB_DIRS) $libstr \$(ALL_LIBS)", 69), "\n\n"; } foreach $p (&prognames("U")) { ($prog, $type) = split ",", $p; $libstr = &objects($p, undef, undef, "-lX"); $objstr = &objects($p, "X.o", undef, undef); print &splitline("${prog}: " . $objstr), "\n"; print &splitline("\t\$(CC) \$(ULDFLAGS) -o \$@ " . $objstr . " $libstr", 69), "\n\n"; } foreach $d (&deps("X.o", undef, $dirpfx, "/")) { print &splitline(sprintf("%s: %s", $d->{obj}, join " ", @{$d->{deps}})), "\n"; $deflist = join "", map { " -D$_" } @{$d->{defs}}; if ($d->{deps}->[0] =~ /\.m$/) { print "\t\$(CC) -DGNUSTEP \$(ALL_OBJCFLAGS) \$(COMPAT) \$(FWHACK) \$(OBJCFLAGS)". " \$(XFLAGS)$deflist -c \$< -o \$\@\n"; } else { print "\t\$(CC) \$(ALL_CFLAGS) \$(COMPAT) \$(FWHACK) \$(CFLAGS) \$(XFLAGS)$deflist" . " -c \$< -o \$\@\n"; } } print "\nclean::\n". "\trm -f *.o ". (join " ", &progrealnames("U")) . "\n". "\trm -rf *.app\n"; select STDOUT; close OUT; } if (defined $makefiles{'emcc'}) { $mftyp = 'emcc'; $dirpfx = &dirpfx($makefiles{'emcc'}, "/"); ##-- Makefile for building Javascript puzzles via Emscripten open OUT, ">$makefiles{'emcc'}"; select OUT; print "# Makefile for $project_name using Emscripten. Requires GNU make.\n". "#\n# This file was created by `mkfiles.pl' from the `Recipe' file.\n". "# DO NOT EDIT THIS FILE DIRECTLY; edit Recipe or mkfiles.pl instead.\n"; # emcc command line option is -D not /D ($_ = $help) =~ s/=\/D/=-D/gs; print $_; print "\n". "# This can be set on the command line to point at the emcc command,\n". "# if it is not on your PATH.\n". "EMCC = emcc\n". "\n". &splitline("CFLAGS = -DSLOW_SYSTEM " . (join " ", map {"-I$dirpfx$_"} @srcdirs))."\n". "\n"; $output_js_files = join "", map { " \$(OUTPREFIX)$_.js" } &progrealnames("X"); print &splitline("all:" . $output_js_files); print "\n\n"; foreach $p (&prognames("X")) { ($prog, $type) = split ",", $p; $objstr = &objects($p, "X.o", undef, undef); $objstr =~ s/gtk\.o/emcc\.o/g; print &splitline("\$(OUTPREFIX)" . $prog . ".js: " . $objstr . " emccpre.js emcclib.js emccx.json"), "\n"; print "\t\$(EMCC) -o \$(OUTPREFIX)".$prog.".js ". "-O2 ". "-s ASM_JS=1 ". "--pre-js emccpre.js ". "--js-library emcclib.js ". "-s EXPORTED_FUNCTIONS=\"`sed 's://.*::' emccx.json | tr -d ' \\n'`\" " . $objstr . "\n\n"; } foreach $d (&deps("X.o", undef, $dirpfx, "/")) { $oobjs = $d->{obj}; $ddeps= join " ", @{$d->{deps}}; $oobjs =~ s/gtk/emcc/g; $ddeps =~ s/gtk/emcc/g; print &splitline(sprintf("%s: %s", $oobjs, $ddeps)), "\n"; $deflist = join "", map { " -D$_" } @{$d->{defs}}; print "\t\$(EMCC) \$(CFLAGS) \$(XFLAGS)$deflist" . " -c \$< -o \$\@\n"; } print "\n"; print $makefile_extra{'emcc'} || ""; print "\nclean:\n". "\trm -rf *.o $output_js_files\n"; select STDOUT; close OUT; } # All done, so do the Unix postprocessing if asked to. if ($do_unix) { chdir $orig_dir; system "./mkauto.sh"; die "mkfiles.pl: mkauto.sh returned $?\n" if $? > 0; system "./configure", @confargs; die "mkfiles.pl: configure returned $?\n" if $? > 0; } puzzles-20170606.272beef/puzzles.rc20000644000175000017500000000312713115373615016020 0ustar simonsimon/* Standard stuff that goes into the Windows resources for all puzzles. */ #ifdef _WIN32_WCE #include #include #define SHMENUBAR RCDATA #define I_IMAGENONE (-2) #define IDC_STATIC (-1) #include "resource.h" IDR_MENUBAR1 MENU DISCARDABLE BEGIN POPUP "Game" BEGIN MENUITEM "Dummy", 0 END POPUP "Type" BEGIN MENUITEM "Dummy", 0 END END IDR_MENUBAR1 SHMENUBAR DISCARDABLE BEGIN IDR_MENUBAR1, 2, I_IMAGENONE, ID_GAME, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE, IDS_CAP_GAME, 0, 0, I_IMAGENONE, ID_TYPE, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE, IDS_CAP_TYPE, 0, 1, END STRINGTABLE DISCARDABLE BEGIN IDS_CAP_GAME "Game" IDS_CAP_TYPE "Type" END IDD_ABOUT DIALOG DISCARDABLE 0, 0, 0, 0 STYLE WS_POPUP FONT 8, "Tahoma" BEGIN LTEXT "", IDC_ABOUT_CAPTION, 4, 4, 150, 8 LTEXT "", IDC_ABOUT_LINE, 4, 16, 150, 1, WS_BORDER LTEXT "", IDC_ABOUT_GAME, 4, 22, 150, 8 LTEXT "from Simon Tatham's Portable Puzzle Collection", IDC_STATIC, 4, 36, 150, 8, SS_LEFTNOWORDWRAP LTEXT "Pocket PC port by Darek Olszewski", IDC_STATIC, 4, 46, 150, 8 LTEXT "", IDC_ABOUT_VERSION, 4, 60, 150, 8 END IDD_CONFIG DIALOG DISCARDABLE 0, 0, 0, 0 STYLE WS_POPUP FONT 8, "Tahoma" BEGIN LTEXT "", IDC_CONFIG_CAPTION, 4, 4, 150, 8 LTEXT "", IDC_CONFIG_LINE, 4, 16, 150, 1, WS_BORDER END IDR_PADTOOLBAR BITMAP DISCARDABLE "padtoolbar.bmp" #endif /* _WIN32_WCE */ puzzles-20170606.272beef/Recipe0000644000175000017500000001132413115373615015024 0ustar simonsimon# -*- makefile -*- # # This file describes which puzzle binaries are made up from which # object and resource files. It is processed into the various # Makefiles by means of a Perl script. Makefile changes should # really be made by editing this file and/or the Perl script, not # by editing the actual Makefiles. !name puzzles !makefile gtk Makefile.gtk !makefile am Makefile.am !makefile vc Makefile.vc !makefile wce Makefile.wce !makefile cygwin Makefile.cyg !makefile osx Makefile.osx !makefile gnustep Makefile.gnustep !makefile nestedvm Makefile.nestedvm !makefile emcc Makefile.emcc !srcdir icons/ WINDOWS_COMMON = printing + user32.lib gdi32.lib comctl32.lib comdlg32.lib winspool.lib WINDOWS = windows WINDOWS_COMMON COMMON = midend drawing misc malloc random version GTK = gtk printing ps # Objects needed for auxiliary command-line programs. STANDALONE = nullfe random misc malloc ALL = list # First half of list.c. !begin >list.c /* * list.c: List of pointers to puzzle structures, for monolithic * platforms. * * This file is automatically generated by mkfiles.pl. Do not edit * it directly, or the changes will be lost next time mkfiles.pl runs. * Instead, edit Recipe and/or its *.R subfiles. */ #include "puzzles.h" #define GAMELIST(A) \ !end # Now each .R file adds part of the macro definition of GAMELIST to list.c. !include *.R # Then we finish up list.c as follows: !begin >list.c #define DECL(x) extern const game x; #define REF(x) &x, GAMELIST(DECL) const game *gamelist[] = { GAMELIST(REF) }; const int gamecount = lenof(gamelist); !end # Unix standalone application for special-purpose obfuscation. obfusc : [U] obfusc STANDALONE puzzles : [G] windows[COMBINED] WINDOWS_COMMON COMMON ALL noicon.res # Mac OS X unified application containing all the puzzles. Puzzles : [MX] osx osx.icns osx-info.plist COMMON ALL # For OS X, we must create the online help and include it in the # application bundle.) Also we add -DCOMBINED to the compiler flags # so as to inform the code that we're building a single binary for # all the puzzles. Then I've also got some code in here to build a # distributable .dmg disk image. !begin osx Puzzles_extra = Puzzles.app/Contents/Resources/Help/index.html Puzzles.app/Contents/Resources/Help/index.html: \ Puzzles.app/Contents/Resources/Help osx-help.but puzzles.but cd Puzzles.app/Contents/Resources/Help; \ halibut --html ../../../../osx-help.but ../../../../puzzles.but Puzzles.app/Contents/Resources/Help: Puzzles.app/Contents/Resources mkdir -p Puzzles.app/Contents/Resources/Help release: Puzzles.dmg Puzzles.dmg: Puzzles rm -f raw.dmg hdiutil create -megabytes 5 -layout NONE raw.dmg hdid -nomount raw.dmg > devicename newfs_hfs -v "Simon Tatham's Puzzle Collection" `cat devicename` hdiutil eject `cat devicename` hdid raw.dmg | cut -f1 -d' ' > devicename cp -R Puzzles.app /Volumes/"Simon Tatham's Puzzle Collection" hdiutil eject `cat devicename` rm -f Puzzles.dmg hdiutil convert -format UDCO raw.dmg -o Puzzles.dmg rm -f raw.dmg devicename !end !begin am bin_PROGRAMS = $(GAMES) !end !begin am_begin GAMES = !end # make install for Unix. !begin gtk install: for i in $(GAMES); do \ $(INSTALL_PROGRAM) -m 755 $(BINPREFIX)$$i $(DESTDIR)$(gamesdir)/$(BINPREFIX)$$i \ || exit 1; \ done !end !begin nestedvm .PRECIOUS: %.class %.class: %.mips java -cp $(NESTEDVM)/build:$(NESTEDVM)/upstream/build/classgen/build \ org.ibex.nestedvm.Compiler -outformat class -d . \ PuzzleEngine $< mv PuzzleEngine.class $@ org: mkdir -p org/ibex/nestedvm/util cp $(NESTEDVM)/build/org/ibex/nestedvm/Registers.class org/ibex/nestedvm cp $(NESTEDVM)/build/org/ibex/nestedvm/UsermodeConstants.class org/ibex/nestedvm cp $(NESTEDVM)/build/org/ibex/nestedvm/Runtime*.class org/ibex/nestedvm cp $(NESTEDVM)/build/org/ibex/nestedvm/util/Platform*.class org/ibex/nestedvm/util cp $(NESTEDVM)/build/org/ibex/nestedvm/util/Seekable*.class org/ibex/nestedvm/util echo "Main-Class: PuzzleApplet" >applet.manifest PuzzleApplet.class: PuzzleApplet.java org javac -source 1.3 -target 1.3 PuzzleApplet.java %.jar: %.class PuzzleApplet.class org mv $< PuzzleEngine.class jar cfm $@ applet.manifest PuzzleEngine.class PuzzleApplet*.class org echo '' >$*.html mv PuzzleEngine.class $< !end # A benchmarking and testing target for the GTK puzzles. !begin gtk test: benchmark.html benchmark.txt benchmark.html: benchmark.txt benchmark.pl ./benchmark.pl benchmark.txt > $@ benchmark.txt: benchmark.sh $(GAMES) ./benchmark.sh > $@ !end !begin am test: benchmark.html benchmark.txt benchmark.html: benchmark.txt benchmark.pl ./benchmark.pl benchmark.txt > $@ benchmark.txt: benchmark.sh $(GAMES) ./benchmark.sh > $@ !end puzzles-20170606.272beef/README0000644000175000017500000000517213115373615014556 0ustar simonsimonThis is the README accompanying the source code to Simon Tatham's puzzle collection. The collection's web site is at . If you've obtained the source code by downloading a .tar.gz archive from the Puzzles web site, you should find several Makefiles in the source code. However, if you've checked the source code out from the Puzzles git repository, you won't find the Makefiles: they're automatically generated by `mkfiles.pl', so run that to create them. The Makefiles include: - `Makefile.am', together with the static `configure.ac', is intended as input to automake. Run `mkauto.sh' to turn these into a configure script and Makefile.in, after which you can then run `./configure' to create an actual Unix Makefile. - `Makefile.vc' should work under MS Visual C++ on Windows. Run 'nmake /f Makefile.vc' in a Visual Studio command prompt. - `Makefile.cyg' should work under Cygwin / MinGW. With appropriate tweaks and setting of TOOLPATH, it should work for both compiling on Windows and cross-compiling on Unix. - `Makefile.osx' should work under Mac OS X, provided the Xcode tools are installed. It builds a single monolithic OS X application capable of running any of the puzzles, or even more than one of them at a time. - `Makefile.wce' should work under MS eMbedded Visual C++ on Windows and the Pocket PC SDK; it builds Pocket PC binaries. Many of these Makefiles build a program called `nullgame' in addition to the actual game binaries. This program doesn't do anything; it's just a template for people to start from when adding a new game to the collection, and it's compiled every time to ensure that it _does_ compile and link successfully (because otherwise it wouldn't be much use as a template). Once it's built, you can run it if you really want to (but it's very boring), and then you should ignore it. DO NOT EDIT THE MAKEFILES DIRECTLY, if you plan to send any changes back to the maintainer. The makefiles are generated automatically by the Perl script `mkfiles.pl' from the file `Recipe' and the various .R files. If you need to change the makefiles as part of a patch, you should change Recipe, *.R, and/or mkfiles.pl. The manual is provided in Windows Help format for the Windows build; in text format for anyone who needs it; and in HTML for the Mac OS X application and for the web site. It is generated from a Halibut source file (puzzles.but), which is the preferred form for modification. To generate the manual in other formats, rebuild it, or learn about Halibut, visit the Halibut website at . puzzles-20170606.272beef/LICENCE0000644000175000017500000000237313115373615014663 0ustar simonsimonThis software is copyright (c) 2004-2014 Simon Tatham. Portions copyright Richard Boulton, James Harvey, Mike Pinna, Jonas Kölker, Dariusz Olszewski, Michael Schierl, Lambros Lambrou, Bernd Schmidt, Steffen Bauer, Lennard Sprong and Rogier Goossens. 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 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. puzzles-20170606.272beef/osx.icns0000644000175000017500000013671513115373615015375 0ustar simonsimonicns½Íics#Hÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿis32þ6,,.,,-,@JJA?C=Y,˜ËȧfCv;,`z¿¨:T@- \ˆ´€´£i2v=,´ÿÅž²˜‚Z‡9*¬ü¿·¸•{WŒ;R­°oGIqІdq[M@A/-.$+‹Š‚:>êÿ¬hq_fgsž¼º=³¾¿‹„‡v1ŠŠ‚:=áÿþþÿ¦cl;`llw£Á¿@¸ÃÃŽ‡Šy1ŠŠ‚:SÜòïïô¬y€€~u€ˆ¢³³B}‡†`[]Q_b\*ÔÔÕÕÖ¶Ÿ€¢Ÿ¨¢ž™£¡y–™™““]7#¢ÐÀ€Á¿¾¾¿¾º¼Ç¾³­ÅÿÄÅÄÄÅÅÈŸ˜"¥Ê´€¶·¶€·²½Ã¸±©Â…ÁŶ©£ÐÃ…Äÿ²¯—¢ÂÀ€Á ÀÁÁÀÅœ°È©¤ÓÃÅÄÄÅÅ®ÂÂ…£ÃÀÁÁÀÁÀÀÁÄœ°ÂËL¤Ð½…¿&¼«ÁÀ†£ÃÀÀÁÀÁÀÁÀÅœ°ÂÈI£Ï¾¿¿ÀÃÁ¿À¿¼«ÁÀ†¢Ã…ÁÅœ°ÂÉI¤Ï¾ÀÀ´®ÀÀ¿¼«ÁÀ†£Ã„ÀÁÅœ°ÂÉI¤Ð¾¿Á°s„Ä¿À¼«ÁÀ†£ÄÀÁÀÁÀ€ÁÅœ°ÃÈI¤Ï½¿ÀÀ¶À¿¿¼«ÁÀ†£ÃƒÁÀÁÅœ°ÂÈI¤Ï½ÀÀµŽÃ€¿¼«ÁÀ†¦Ê…ÇË¡±ÂÉI¤Ð½À¿¿Á¿¿À¿¼«ÁÀ‡‚‹€‰ˆ‰ˆ‰‰‹q®ÅÈI£Ð¾¿À¿ÀÀ»«ÁÀŠ/ˆ=»ÌI¢ÑÀÁÀÁÀÁ¾«ÀÁŠ2ˆ;ÃM¤Ä®‚° ±±°®«ÁÁ‹2‰CAªå‡ßåéê§=Š9‹8)„J8 e ¤ ¥xrusstwc8 ‚ u¿ÅÄÄÅňz……~„w8 u¿ÅÆÁÁÂŽ~ÿþÜyu8  )DBW¿ÁÂ~¡ÿÿâzu8 ‚ b¦§7¶ÁÂ~Ÿÿÿßyu8 €  6YUa—ÁÀA¶ÂÂ…x‚y~€u8 €|ÿÿíØÄ½<·ÃÇŠ}i†Œt8 xÿÿ⨤i¡¦§~y|sgx~i8 xÿÿçÓÀ¿ÅÀ¿À…ˆ~l…Št8xÿþçÕÃÁ€Â ÃŽ‡Š€l†‹t8‚‚yÿÿéϹ¸¹‡€ƒzl†‹t;nyxxzX8€;7_–“Š|}|~|~~mjkkt…‹t>êÿ¬hq_fgs»·{³½½Š‚…|l†‹t=áÿþþÿ¦cl;`llw¤Á¾~¹ÃÃŽ‡Š€l†‹tSÜòïïô¬y€€~uˆ¢³²q~‡†`[]UJ]bRÔÔÕÕÖ¶Ÿ€¢Ÿ¨¢ ™£ —™™““’p6¢ÐÀ€Á¿¾¾¿¾º¼Ç¾´­ÅÃÁÄÅÄÄÅÅÈ¡˜"¥Ê´€¶·¶€·²½Ã¸±ªÂ…ÁÅœ¶©£ÐÃ…Äÿ²¯—£ÂÀ€Á ÀÁÁÀÅœ°È©¤ÓÃÅÄÄÅÅ®ÂÂ…£ÃÀÁÁÀÁÀÀÁÄœ°ÂËL¤Ð½…¿&¼«ÁÀ†£ÃÀÀÁÀÁÀÁÀÅœ°ÂÈI£Ï¾¿¿ÀÃÁ¿À¿¼«ÁÀ†¢Ã…ÁÅœ°ÂÉI¤Ï¾ÀÀ´®ÀÀ¿¼«ÁÀ†£Ã„ÀÁÅœ°ÂÉI¤Ð¾¿Á°s„Ä¿À¼«ÁÀ†£ÄÀÁÀÁÀ€ÁÅœ°ÃÈI¤Ï½¿ÀÀ¶À¿¿¼«ÁÀ†£ÃƒÁÀÁÅœ°ÂÈI¤Ï½ÀÀµŽÃ€¿¼«ÁÀ†¦Ê…ÇË¡±ÂÉI¤Ð½À¿¿Á¿¿À¿¼«ÁÀ‡‚‹€‰ˆ‰ˆ‰‰‹q®ÅÈI£Ð¾¿À¿ÀÀ»«ÁÀŠ/ˆ=»ÌI¢ÑÀÁÀÁÀÁ¾«ÀÁŠ2ˆ;ÃM¤Ä®‚° ±±°®«ÁÁ‹2‰CAªå‡ßåéê§=Š9‹8)€„J8 e ¤ ¥xrusstwc8 ‚ u¿ÅÄÄÅňz……~„w8 u¿ÅÆÁÁÂŽ~ÿþÜyu8  )DBW¿ÁÂ~¡ÿÿâzu8 ‚ b¦§7¶ÁÂ~Ÿÿÿßyu8 €  6YUa—ÁÀA¶ÂÂ…x‚y~€u8 €|ÿÿíØÄ½<·ÃÇŠ}i†Œt8 xÿÿ⨤i¡¦§~y|sgx~i8 xÿÿçÓÀ¿ÅÀ¿À…ˆ~l…Št8xÿþçÕÃÁ€Â ÃŽ‡Š€l†‹t8‚‚yÿÿéϹ¸¹‡€ƒzl†‹t;nyxxzX8€;7_–“Š|}|~|~~mjkkt…‹t>êÿ¬hq_fgs»·{³½½‰‚…{k†‹t=áÿþþÿ¦cl;`llw¤Á¾~¹ÃÃ‡Š€l…ŠsSÜòïïô¬y€€~uˆ¢³±y¸ÂÁ™”–~¢¤‘ÔÔÕÕÖ¶Ÿ€¢Ÿ¨¢ ™£ ¢¥¥›žžx–ÚÔ<¢ÐÀ€Á ¿¾¾¿¾º¼Ç¾´­ÅÃÁà ÄÄÇž˜´ÿa¥Ê´€¶·¶€·²½Ã¸°ªÂ…ÁÅœ³§¼a£ÐÃ…Äÿ²¯Ÿ¥ÂÀ€Á ÀÁÁÀÅœ°Æ¯7¤ÓÃÅÄÄÅŮ¿®ÂÀÁÁÀÁÀÀÁÄœ°ÂÊI¤Ð½…¿&¼«ÁÀ¯ÂÀÀÁÀÁÀÁÀÅœ°ÂÈI£Ï¾¿¿ÀÃÁ¿À¿¼«ÀÀ®…ÁÅœ°ÂÉI¤Ï¾ÀÀ´®ÀÀ¿¼«ÀÀ¯„ÀÁÅœ°ÂÉI¤Ð¾¿Á°s„Ä¿À¼«€Á¯ÃÀÁÀÁÀ€ÁÅœ°ÃÈI¤Ï½¿ÀÀ¶À¿¿¼«ÀÀ¯ƒÁÀÁÅœ°ÂÈI¤Ï½ÀÀµŽÃ€¿(¼«ÀÀ±ÅÄÃÄÃÄÃÄÃÈž±ÂÉI¤Ð½À¿¿Á¿¿À¿¼«ÁÀ˜¦¢£ƒ¢ ¦†ªÅÈI£Ð¾¿À¿ ÀÀ»«À¿Ï­Èñ„ë ìæ—°ÌI¢ÑÀÁÀÁ ÀÁ¾«À¿ÏêºÝ†ÿô”¸L¤Ä®‚° ±±°®«ÁÀÑòÿÆå†ÿþ§>ªå‡ßåééÁ„d^>…baeV l8mkÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿich#Hÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿih32½9;„<;;„<;<<;;98:†=@‡?Bs;&‚#„$/V~”ƒ“”l‡stA<„„€#f¥ÇÆÅÆÅÆÅÆÁ€‹‹‹Žs?<„„#d¡ÂÀÀÁÀÁÂÀ»}‰†]WXXW\…‹s?<„„#c Á€À¼~‰‚ Œs?<„„ %e¤ÆÅÄÆ€Á¼}Šƒ Œs?<„„!('$XÂÂÁÁ¼}Šƒ Œs?<„„?dy{\¹ÂÀÁ»}‰ƒ Œs?<„„€!d¦ÉÍœºÂÀÁ¼}Šƒ Œs?;#‚ƒ &0/.4H|¨ÁÆ–º€Á¼}‰…C<% ;Aƒ‹s?<‚ ƒ HýùùõÙÙÈÁÆ–»€Â¼}‰ˆŽ”Y’Žˆ‹s?<„„G€ÿûßÜÌÃɘ¼ÅÄľ~‹Š‰VŒŠ‰t?<„„ GÿþÿøÓ雞„8˜€œ˜n€v zIxvvxh@<„„GÿþþúÜÖÁ¸¸º¾¹¹¸ºµ{…„„‰R‡„„‡q?<„„GÿþþúÞÚÊÀÁÂÁÁÂÀ¼~‰ˆˆU‹ˆˆ‹s?<„„ GÿþþúÝÚÉÀÁÁ€ÀÁÁ¼}‰ˆˆU‹‡ˆŠs?<„„GÿþÿùÝÚÊÁÂÂÃÃÁÂý~€‰ ŽVŠˆˆ‹s?<„ „GÿâÙĺº¹º»µy„ƒƒˆR‹ˆˆ‹s?9A„G?**)€* )&Fž›› zB"€  ‹ˆˆ‹s?0¬„ÿ±cƒo p[acbhm~—št€–’b€j nAŠˆˆ‹s?0ªÿ‚þÿ¯a€m$lmmn[jmlp| ¸ÇË™¿ÆÆÇÁ€Œ‹‹‘W‹‡ˆ‹s?/ªÿ‚þÿ¯`€lkklmYjkkoy´ÁÆ–»ÄÂĽ€‰ŽVŒ‰‰‹t?4¬ÿúûúúûÿ¯gn‚q)r_pqqt} µÂÆ™­´³³®t~~ƒO~~k;N¹ñëéêëêð³}„†s‹†…ˆŽ¢¬´·—!muuspI€NQ/€UVH)jÆÝÙ€ÚØÝ¶—›œ›=™‰ªš›™Š’ŽR…‡ˆ†…x~~}€lB2'++&ˆÓÉÈÈÇÇÈȽ±²³´³´´° É°³³©ŸÄÃÄ»¨Ã€ÄÃÀ€Å*ǽƒ‡/ ˜ÜÁ¾¿¿À¿À¿ÀÀ¿ÀÀ¿Á»¬Û¾¿Á³ŸÃÁÁÀÁÀÁÁÀ€Á€ÀÆ”¢¤€—ÝÃÁ‚ÁÀ€Á€Â½­ÜÀÁô Ä€ÁÀÀÁÁÀÀÁÁÀÁÁŔˢ™Ó¨¥¥„¦§¦¥¦¦¤­Ì¤¥ª£“¾ÀÀÁÁÀÁÀÁ ÀÁÁÅ“ÄÇ¢˜ÛÕ†ÖÕ‚Öȹ´µ°–„Á+ÀÀÁÁÀÁÁÅ“ÅÁÇ¥—ÜÅÃÄÃÃÄÃÄÃÃÂÄÃÄÄÁ£ÀÁóp—ÄÀÀ€ÁÀÀƒÁ Æ“žÄÁÀË@—ÜÀƒ¿ÀÀ¾¾À€¿½ ¿¿Á²s–Ä‚ÀÁ‚À ÁÀÀÆ“ÅÁÀÇ=—ÛÁ€¿À¿¾¾À¿À€¿ ¾½¢ÀÀÁ²s—ÄÀÀÁÀÀ€ÁÀÀÂÅ“ÄÀÀÇ>—ÜÀÀ„¿À‚¿½ ¿¿À²s–Ä€ÀÁÁÀÂÁÀ€ÁÀÁÅ”žÅÁÁÈ=—ÚÀÀ¿€ÀÁ¿¾ÀÀ¿À½ ¿ÀÁ³s–ÃÀ…ÁÂÁÀÁÁÆ“ÄÀÀÈ=—Ü€À¿¿À­¢¨ºÀ¿ÀÀ¿½Ÿ¿¿Á³s—ĉÀ ÁÁÆ“ÅÁÁÈ=—ÜÀ¿Ác;¢ÂÀ¿ÀÀ¼ŸÀÀÁ²s–ÅÁ‡À€Á Å”žÄÁÀÈ=—ÜÀÀ¿Ǧn¿¿€À9¼¡¿À²s—ÄÀÀÁÂÁÁÂÁÁÂÁÀÁÁÆ“ÅÁÀÇ=—ÛÀ¾¿¿ÀÀÄc£ÃÀ¾¿¾¿½ŸÀ¿Á²s—ÃÀ„ÁÀÁÀÁÁÀÆ“ÄÀÀÇ>—ÜÀ¿Á¬Y¿À¿½¡À¿Á³s–ÄÀÀÁÁÀÁ€ÀÁÀÁÀÀÆ“ÅÁÁÈ=—ÜÀ¿Á³¦Á¿¿À¿¿À¼ À¿Á²s™ÉÆÆÇ‚ÆÇÆÇÆÆÇ˘žÄÀÀÈ=—ÛÁ¿€À¿ÀÿÀ¿¿ÀÀ¿½ ÀÀÁ²t‚˜‘‘’‘‘’€‘ ’‘•oœÈÁÁÈ=—ÜÁ€¿À¿À¿¿À€¿ ÀÀ¼ ¿¿Á²y= /°ÆÁÇ=–ÜÁÀÀ…¿ À¿¿À¼Ÿ¿¿Á²y?Ž+°ÆÈ=•ÜÀÀ‚¿ÀÀ¿À¾¿ÀÀ¾ŸÀ¿Â³y@ +°Ì=—ÝÀ¿¿¾¿¾€¿¾€¿ ¾¿¼ ¿¾Á²y@+·B˜Î¦¦¥¤¦¥¥¦¥¦¥¦¦¤¦¥§ÆÄƸ|B‘3.¢ëŒìëîïïñÞ•Q“9;„<;;„<;€<7$“Z;&‚#„$$A_poonoonolHO…NR-<„„€$h¨ËÊ€ÉÊÉÊĄޒ‚‘Ž”R<„„#d¡ÂÀÀÁÀÁÂÀ»}‰…fhf„ŽN<„„#c Á€À¼~‰wíääì–uN<„„ %e¤ÆÅÄÆ€Á¼}Šw¢ÿ©sN<„„!('$XÂÂÁÁ¼}Šw ÿ¨tN<„„?dy{\¹ÂÀÁ»}‰w ÿ¨tN<„„€!d¦ÉÍœºÂÀÁ¼}Šwœÿýýÿ¤sN;#‚ƒ &0/.4H|¨ÁÆ–º€Á¼}‰ƒbsfdpbŽN<‚ ƒ HýùùõÙÙÈÁÆ–»€Â¼}‰‰ŠŠnh‚ЉŽN<„„G€ÿûßÜÌÃɘ¼ÅÄľ~‹Š‰qj„ЉO<„„ GÿþÿøÓ雞„8˜€œ˜n€v xdfpvv{D<„„GÿþþúÜÖÁ¸¸º¾¹¹¸ºµ{…„„‡mi„„ŠL<„„GÿþþúÞÚÊÀÁÂÁÁÂÀ¼~‰ˆˆ‹pjƒˆˆŽN<„„ GÿþþúÝÚÉÀÁÁ€ÀÁÁ¼}‰ˆˆ‹pjƒ‡ˆŽN<„„GÿþÿùÝÚÊÁÂÂÃÃÁÂý~€‰ Œqj‚ˆˆŽN<„ „GÿáÖ¿´´³²€´µ¯s~}}€gjƒˆˆŽN9A„G?**)€*)&Fž››Ÿ‡wpoprƒn€poh€i huw‚ˆˆŽN0¬„ÿ±cƒo p[acbhn„–¡£ˆs•€ œl€t vfl‚ˆˆŽN0ªÿ‚þÿ¯a€mlmmn[jmlp| ¸ÇÊ£p¹€ÆÁ€Œ‹ŠŽrjƒ‡ˆŽN/ªÿ‚þÿ¯`€lkklmYjkkoy´ÁÅ¡p¶ÄÂĽ€‰Œqk„‰‰O4¬ÿúûúúûÿ¯gn‚q)r_pqqt} ¸ÁÅ¢o¨´³³®t~~hbz~~„IN¹ñëéêëêð³}„†s‹†…ˆŽ¢¬´·ž`iuuspI€N P@>PUUY1jÆÝÙ€ÚØÝ¶—›œ›=™‰ªš›™Š’Ž…vƒ‡ˆ†…x~~}v_/'+,ˆÓÉÈÈÇÇÈȽ±²³´³´´° É°³µ¬ŸÄÃĽ¶Â€ÄÃÀ€Å*ÆÂ…/  ˜ÜÁ¾¿¿À¿À¿ÀÀ¿ÀÀ¿Á»¬Û¾¿Á²ŸÃÁÁÀÁÀÁÁÀ€Á€ÀÅ“¢¤€—ÝÃÁ‚ÁÀ€Á€Â½­ÜÀÁô Ä€ÁÀÀÁÁÀÀÁÁÀÁÁŔˢ™Ó¨¥¥„¦ §¦¥¦¦¤­Ì¤¥ª¢•€ÀÁÁÀÁÀÁ ÀÁÁÅ“ÄÇ¢˜ÛÕ†ÖÕ‚Öȹ´µ°—„Á+ÀÀÁÁÀÁÁÅ“ÅÁÇ¥—ÜÅÃÄÃÃÄÃÄÃÃÂÄÃÄÄÁ£ÀÁóp—ÄÀÀ€ÁÀÀƒÁ Æ“žÄÁÀË@—ÜÀƒ¿ÀÀ¾¾À€¿½ ¿¿Á²s–Ä‚ÀÁ‚À ÁÀÀÆ“ÅÁÀÇ=—ÛÁ€¿À¿¾¾À¿À€¿ ¾½¢ÀÀÁ²s—ÄÀÀÁÀÀ€ÁÀÀÂÅ“ÄÀÀÇ>—ÜÀÀ„¿À‚¿½ ¿¿À²s–Ä€ÀÁÁÀÂÁÀ€ÁÀÁÅ”žÅÁÁÈ=—ÚÀÀ¿€ÀÁ¿¾ÀÀ¿À½ ¿ÀÁ³s–ÃÀ…ÁÂÁÀÁÁÆ“ÄÀÀÈ=—Ü€À¿¿À­¢¨ºÀ¿ÀÀ¿½Ÿ¿¿Á³s—ĉÀ ÁÁÆ“ÅÁÁÈ=—ÜÀ¿Ác;¢ÂÀ¿ÀÀ¼ŸÀÀÁ²s–ÅÁ‡À€Á Å”žÄÁÀÈ=—ÜÀÀ¿Ǧn¿¿€À9¼¡¿À²s—ÄÀÀÁÂÁÁÂÁÁÂÁÀÁÁÆ“ÅÁÀÇ=—ÛÀ¾¿¿ÀÀÄc£ÃÀ¾¿¾¿½ŸÀ¿Á²s—ÃÀ„ÁÀÁÀÁÁÀÆ“ÄÀÀÇ>—ÜÀ¿Á¬Y¿À¿½¡À¿Á³s–ÄÀÀÁÁÀÁ€ÀÁÀÁÀÀÆ“ÅÁÁÈ=—ÜÀ¿Á³¦Á¿¿À¿¿À¼ À¿Á²s™ÉÆÆÇ‚ÆÇÆÇÆÆÇ˘žÄÀÀÈ=—ÛÁ¿€À¿ÀÿÀ¿¿ÀÀ¿½ ÀÀÁ²t‚˜‘‘’‘‘’€‘ ’‘•oœÈÁÁÈ=—ÜÁ€¿À¿À¿¿À€¿ ÀÀ¼ ¿¿Á²y= /°ÆÁÇ=–ÜÁÀÀ…¿ À¿¿À¼Ÿ¿¿Á²y?Ž+°ÆÈ=•ÜÀÀ‚¿ÀÀ¿À¾¿ÀÀ¾ŸÀ¿Â³y@ +°Ì=—ÝÀ¿¿¾¿¾€¿¾€¿ ¾¿¼ ¿¾Á²y@+·B˜Î¦¦¥¤¦¥¥¦¥¦¥¦¦¤¦¥§ÆÄƸ|B‘3.¢ëŒìëîïïñÞ•Q“9;„<;;„<;€<7$“Z;&‚#„$$A_poonoonolHO…NR-<„„€$h¨ËÊ€ÉÊÉÊĄޒ‚‘Ž”R<„„#d¡ÂÀÀÁÀÁÂÀ»}‰…fhf„ŽN<„„#c Á€À¼~‰wíääì–uN<„„ %e¤ÆÅÄÆ€Á¼}Šw¢ÿ©sN<„„!('$XÂÂÁÁ¼}Šw ÿ¨tN<„„?dy{\¹ÂÀÁ»}‰w ÿ¨tN<„„€!d¦ÉÍœºÂÀÁ¼}Šwœÿýýÿ¤sN;#‚ƒ &0/.4H|¨ÁÆ–º€Á¼}‰ƒbsfdpbŽN<‚ ƒ HýùùõÙÙÈÁÆ–»€Â¼}‰‰ŠŠnh‚ЉŽN<„„G€ÿûßÜÌÃɘ¼ÅÄľ~‹Š‰qj„ЉO<„„ GÿþÿøÓ雞„8˜€œ˜n€v xdfpvv{D<„„GÿþþúÜÖÁ¸¸º¾¹¹¸ºµ{…„„‡mi„„ŠL<„„GÿþþúÞÚÊÀÁÂÁÁÂÀ¼~‰ˆˆ‹pjƒˆˆŽN<„„ GÿþþúÝÚÉÀÁÁ€ÀÁÁ¼}‰ˆˆ‹pjƒ‡ˆŽN<„„GÿþÿùÝÚÊÁÂÂÃÃÁÂý~€‰ Œqj‚ˆˆŽN<„ „GÿáÖ¿´´³²€´µ¯s~}}€gjƒˆˆŽN9A„G?**)**+)&Fž››Ÿ‡wpoprƒo€poh€i huw‚ˆˆŽN0¬„ÿ±cƒop[acbhn„–¡£ˆs•¡  œl€t vfl‚ˆˆŽN0ªÿ‚þÿ¯a€mlmmn[jmlp| ¸ÇÊ£p¹€ÆÁ€Œ‹ŠŽrjƒ‡ˆŽN/ªÿ‚þÿ¯`€lkklmYjkkoy´ÁÅ¡o´ÂÀ»}€‡Šoi‚‡‡M4¬ÿúûúúûÿ¯gn‚q)r_pqqt} ¸ÁÅ¢p¹ÆÅÅÀ…’wp‰ŽŽ”UN¹ñëéêëêð³}„†!s‹†…ˆŽ¢¬´·œj¸ÉÅÅÁ•œœŸˆ„©¬ª°~ jÆÝÙ€ÚØÝ¶—›œ›=™‰ªš›™Š’Ž…w“’‘‚ˆˆ‡‰€fwÈÊ˯'ˆÓÉÈÈÇÇÈȽ±²³´³´´° É°³µ¬ŸÄÃĽ¶Á€Ã¿€Ä*ÅÁ–óúðB˜ÜÁ¾¿¿À¿À¿ÀÀ¿ÀÀ¿Á»¬Û¾¿Á²ŸÃÁÁÀÁÀÁÁÀ€Á€À Å“¡žýÿR—ÝÃÁ‚ÁÀ€Á€Â½­ÜÀÁô Ä€ÁÀÀÁÁÀÀÁÁÀÁÁŔɚÿS™Ó¨¥¥„¦ §¦¥¦¦¤­Ì¤¥©¡•€ÀÁÁÀÁÀÁ ÀÁÁœůš™J˜ÛÕ†ÖÕ‚Öȹ´´²—˜Â„Á+ÀÀÁÁÀÁÁÅ“ÅÁÅ¥#—ÜÅÃÄÃÃÄÃÄÃÃÂÄÃÄÄÁ£ÀÁÁŽ ÃÀÀ€ÁÀÀƒÁ Æ“žÄÁÀÊ>—ÜÀƒ¿ÀÀ¾¾À€¿½ €¿ÄŠÂÀÁ‚À ÁÀÀÆ“ÅÁÀÇ=—ÛÁ€¿À¿¾¾À¿À€¿ ¾½¢ÀÀ¿ÄÄ¡ÃÀÀÁÀÀ€ÁÀÀÂÅ“ÄÀÀÇ>—ÜÀÀ„¿À‚¿½ €¿ÄĠÀÀÁÁÀÂÁÀ€ÁÀÁÅ”žÅÁÁÈ=—ÚÀÀ¿€ÀÁ¿¾ÀÀ¿À½ ¿À¿ÅÄ ÂÀ…ÁÂÁÀÁÁÆ“ÄÀÀÈ=—Ü€À ¿¿À­¢¨ºÀ¿ÀÀ¿½Ÿ€¿ÅġÉÀ ÁÁÆ“ÅÁÁÈ=—ÜÀ¿Ác;¢ÂÀ¿ÀÀ¼ŸÀÀ¿ÄÄ ÄÁ‡À€Á Å”žÄÁÀÈ=—ÜÀÀ¿Ǧn¿¿€À9¼¡¿ÀÀÄÄ¡ÃÀÀÁÂÁÁÂÁÁÂÁÀÁÁÆ“ÅÁÀÇ=—ÛÀ¾¿¿ÀÀÄc£ÃÀ¾¿¾¿½ŸÀ¿¿ÄÄ¡ÂÀ„ÁÀÁÀÁÁÀÆ“ÄÀÀÇ>—ÜÀ¿Á¬Y¿À¿½¡À¿¿ÅÄ ÃÀÀÁÁÀÁ€ÀÁÀÁÀÀÆ“ÅÁÁÈ=—ÜÀ¿,Á³¦Á¿¿À¿¿À¼ À¿¿ÄÄ£ÈÅÅÆÅÅÆÅÅÆÅÆÅÅÆÊ—žÄÀÀÈ=—ÛÁ¿€À¿ÀÿÀ¿¿ÀÀ¿½ ÀÀ¿ÄÅŠœ““”““”“” ˜p—ÈÁÁÈ=—ÜÁ€¿À¿À¿¿À€¿ÀÀ¼ €¿ÃÓ“¢ØÑ…ÒÑ ÒÍy¦ÆÁÇ=–ÜÁÀÀ…¿À¿¿À¼Ÿ€¿ÂÔãžÓŒÿ ës¦ÆÈ=•ÜÀÀ‚¿ÀÀ¿À¾¿ÀÀ¾ŸÀ¿ÀÃÓæð–ÍŒÿ ìr¦Ì=—ÝÀ¿¿¾¿¾€¿¾€¿ ¾¿¼ ¿¾¿ÂÓäøú—ÏŒÿ!ës­B˜Î¦¦¥¤¦¥¥¦¥¦¥¦¦¤¦¥§ÆÄÄÉÚìþÿÿ¡×Œÿô‚)¢ëŒì ëîïïð䲆_PSI'R‹QV?h8mk ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿit32G¦¹91++ ·À¹9J\o‚–©¾Óé·ÿ¹91+#·ÿ€9“9”9‡ 9Qg{’®–ÀQ›ˆÿ€9“9”9‡ >Qg{ˆ®–ÀQ›ˆÿ€9“9”9‡ >Qgƒ’®€ÀɇÀɇÀQ“ˆƒ„ˆÿ€9“9”9‡ 9Qgƒ’¦“ÀÉÀÀYˆˆƒˆÿ€9“9”9‡ >Qg{ˆ®†ÀɃÀÉ…ÀQ›ˆÿ€9“9”9‡ 9Qgƒ’®ŽÀÉ„ÀQ›ˆÿ€9“9”9‡ 9Qg{’®‹ÀɇÀQ„ˆ€ˆƒ€ˆÿ€9“9”9‡ >Qg{’¦ƒÀÉÀQ€ˆƒ€ˆ„ˆÿ€9“9”9‡ 9Qg{’¦†ÀɇÀÉ€ÀÉQ„ˆ„ˆÿ€9“9”9‡ 9Qg{’¦–ÀQ‚ˆƒˆ„ˆÿ€9“9”9‡ >Qg{’®€ÀɇÀɇÀQ„ˆ„ˆÿ€9“9”9‡ >Qg{’¦ÀÉ€ÀÉÀQ„ˆƒƒˆÿ€9“9”9‡ 9Qg{’®†ÀɃÀÉ…ÀQ„ˆ„ˆÿ€9“9”9š€ÀɈÀQ„ˆ‚ˆƒˆÿ€9“9”9›ˆÀÉÀÀQ„ˆ„ˆÿ€9“9”9›ÀɆÀQˆƒ‚ˆ„ˆÿ€9“9”9‡ >Qgƒˆ¦ÉƒÀÉ€‹ÀQ„ˆ„ˆÿ€9“9”9‡ 9Qgƒ’®…À€‹ÀQ„ˆ„ˆÿ€9“9”9‡ 9Qg{’¦…À€ˆÀÉÀÀQ„ˆ„ˆÿ€9“9”9‡ >Qg{’®…À€ÀɆÀQ„ˆ„ˆÿ€9“9”9‡ 9Qg{’¦ÀÉ€À€ÀɈÀÉQ„ˆ„ˆÿ€9“9”9‡ 9Qg{ˆ®…À€‹ÀQ„ˆ„ˆÿ¹9GQ>g{ˆ¦®…À€„ÀɃÀQ‹ˆ€†ˆƒ€ˆÿ€9“9”9ˆþ ñÉçÝÝÓÉÉÀÀÉ‚À€É„ÀÉ€ÀÉÀQˆƒ†ˆƒˆˆ€Šˆÿ€9“9”9‡þññÀçÝÝÓÉÉ…À€‹ÀQ‹ˆ€Šˆÿ€9“9”9ˆþñÀçÝÝÓÉÉ€ÀÉ€ÀÉ€ÀÀÉ€ÀÉ€ÀÉ€ÀQ‹ˆ€Šˆÿ€9“9”9‡þññÉçÝ€ÓÉ…À€‹ÀQ„ˆƒƒˆ€Šˆÿ€9“9”9ˆþñÀççÓÓÉÉ…À€‹ÀQ‹ˆ€ˆƒˆƒƒˆÿ€9“9”9‡þññÉçÝÝÓɆÀ€‹ÀQ‹ˆ€Šˆÿ€9“9”9ˆþñÀçÝÝÓÓÉ€ÀÉ€ÀÉ€„ÀɃÀQˆƒ‰ˆ€Šˆÿ€9“9”9‡þñÓÉ®¦ˆƒmg†QQY„QYŽQ€ŠQÿ€9“9”9‡þññÉ€ÝÓÉÉ–ÀQˆˆƒˆˆ€Šˆÿ€9“9”9ˆþñÉçÝÝÓÉÉ–ÀQ‹ˆ€Šˆÿ€9“9”9ˆþñÉçÝÝÓÉÉ“ÀÉÀÀY€ˆƒ‡ˆ€Šˆÿ€9“9”9‡þññÉ€ÝÓÉÉ‹ÀɇÀQ‹ˆ€Šˆÿ€9“9”9ˆþñÉçÝÝÓÉÉ„ÀÉŽÀQ‹ˆ€ƒˆƒƒˆÿ€9“9”9‡þññÉçÝ€ÓɃÀÉ…ÀɆÀQ‹ˆ€Šˆÿ€9“9”9ˆþñÀçÝÝÓÉÉ–ÀQ†ˆƒˆ€ˆƒ…ˆÿ€9“>”9‡þññÉçÝÝÓÉÉÀɃÀQ‹ˆ€†ˆƒ€ˆÿ€9“>”9ˆþñÉçÝ€ÓÉ€ÀÉÀÉÀQ‹ˆ€Šˆÿ€9“9”9‡þññÀçÝÝÓÉÉ…ÀÉ€ÀÉ„ÀÉÀQˆƒ‰ˆ€Šˆÿ€9“9”9‡þññÉçÝÓÓÉɆÀÉ€ÀɈÀQ‹ˆ€ˆƒˆˆÿ€9“9”9ˆþñÀçÝÝÓÓÉÀɃÀQ‹ˆ€Šˆÿ€9“9”9‡þññÉççÝÓÉÉ€ÀÉ’ÀQ„ˆƒƒˆ€ƒˆƒƒˆÿ€9“9”9ˆþñÉçÝÓÓÉÉ‘ÀÉÀQˆˆƒˆˆ€Šˆÿ€9“9”9ˆþñɈgY9#¨ƒˆƒƒˆÿ§9>…9>…9>Q# ¨Šˆÿ€9“þ9mmg€mg‡mggm9mg‚m{{_91# ¨Šˆÿ€9“þ9mgmgƒmgƒmgmm9‚m gmmgmmƒgˆ’¦®·…À€ŠÀÉQ‹ˆ€ˆˆƒ‡ˆÿ€9“þ9gg€mg€mgmgˆm9mgmgmmgm{g’’¦®·…À€‹ÀQ‹ˆ€Šˆÿ€9“þ9Œmgmgmm9‡m {ƒgˆ’¦¦®·ÀɃÀ€‹ÀQ‹ˆ€Šˆÿ€9“þ9”m9†m gmƒgˆ’¦®·€ÀÉÀ€„ÀÉ€ÀÉÀÀQ„ˆƒƒˆ€ˆƒ…ˆÿ€9“þ9€mg€mg€mg‚mg‚m9€mg„m{g’¦®·…À€ÀÀɈÀQ‹ˆ€Šˆÿ€9“þ9g€mgm9g‚mg€m {{gˆ’¦®·ÀÀÉ‚À€†ÀÉ€ÀÉQ‹ˆ€Šˆÿ€9“þ9mg„mg€mgmmgmgm9ˆm{_ˆ¦®·ƒÀÉÀ€ÀɆÀQˆˆƒˆˆ€€ˆƒ‚ˆƒ€ˆÿ€9“þ9Šmg„mgm9€mgmg€m g{{g’’¦®·…À€‹ÀQ‹ˆ€Šˆÿ€9“þ9mgmg€mgmmgmgmmgg9‚mg‚mƒgˆ¦©·…À€ÀÀɈÀQ…ˆƒ‚ˆ€ŠˆGÿ>>Gþþñþñþñþñþñþñþñþñþñþñþ>m{mmgm{{m{m{m{{mm{m{m{{>{{g{m{{mm{{ƒg’®®·…À ‹¨G‹v€ŠvßGQQþ’ñQƒƒ{€ƒ{{ƒƒ{{ƒƒ{€ƒ{{ƒƒmQˆˆ{{ƒƒ{ƒ{ƒƒˆm€®®·…À‹’>‹g€Šg ÂQQgþççñçññçñçññçñçñ_ƒˆƒ€ˆƒ€ˆƒ€ˆƒ€ˆƒ€ˆ{Qˆ’ƒ€ˆƒ‚ˆƒ€®·…À+>‹|5‹W€ŠW¤_Yƒþ‚çÝ„çÝ„çg“ˆ{Y¦„ˆ’ˆˆ¦¦®®·†À>>‚g|ƒgff,‹G€ŠGˆ_g’þÝçÝ{’’’’€’€’€’’’{g®®’’’’’’ˆ¦mmgYY„QY€‹Q#‹91‰9 ˆmmñÝÓÝÓÝÓ€ÝÓÝÓÝÓÓˆ“ƒm··‰Y‡’g|g’‚’ˆ’†’g|gˆR{m·ñ’Ó’‚¦¦ƒ{ÉɈ¦®g€·†À{|{€ÀɇÀ‡ÀÉ€À{|{+-‡+9{ƒÉñ‹ÉÓ‚ÉÓ€®¦®ˆ{ÓÓ€®¦®¦©®·Y··‡À’“’‹À®‹À’“’À’†"ˆˆÝñÀÀ€ÉÀ€É ÀÉÀÉÀÉÉÀÉÀÉÉ®€·®·’ƒçÝ·®‡·Y‰À¦©®‹À·‹À®©® ÀÀ’ „ ’’ññ À·„À·’’ññ‰ÀQÀ·ªÀ€Àˆ‡’’ññ†À·‡À·”À’’ññ‚À·€À·ÀÀQ„ÀɇÀÉŠÀÉ‹ÀÀˆ†’’ññ‚À·†À·‰À·„À·ƒÀ·’’ññ‰ÀQ’ÀÉÀÉ€ÀÉÀ‚Àˆ…’’ññÀ·À·ƒÀ·‡À·ÀÀ’’ññÀ·€À·ƒÀQƒÀÉŠÀÉ—ÀƒÀˆ„’’ññÀ·ƒÀ·ŽÀ’’ññ‰ÀQ‡ÀÉ—ÀÉ„ÀÉÀ„Àˆƒ’’ññ‡À·€À·…À·‘À’’ññ‰ÀQÀÉŠÀÉ„ÀɃÀÀÀÉ‚Àˆ‚’’ññ€À·€À·–À·À·‚À’’ññ‡À·ÀQ·ˆÀɉÀÉ€ÀÉŽÀ‚ÀÉ€Àˆ’’ññ®ª’ññ¦ƒ’’€>®©®·¨À‡Àˆ€’ñª’ñ‚’ˆ’ˆ€¦>®®·‘ÀɆÀÉ€ÀÉ€ÀÉ€ÀÉÀˆÀ¦€’’ñç¨ñÀÀ·ˆÀQ„ÀɇÀɈÀÉÀÀÀÉ€ÀÉ‚Àˆ’’«ñç‡À®ˆ{_Q‰ÀÉ…ÀÉ–ÀŠÀ¦’’çñ˜À··‰À·ÀÀ’‡À¨’|fQ‰ÀÉ€ÀɈÀÉÀ‰ÀÉÀ’’ññ†À·ÀÀ·‡À·‘À’’‡À¨’|fQÀɈÀÉ€ÀÉ€ÀÉ€ÀÉ€À„ÀɃÀ’’ññ·€À·‰À·ŒÀ·‡À’’‚À·À¨’|fQ‡ÀÉŒÀÉ‘ÀÉŠÀ’’ññ˜À·À·ƒÀ·„À’’†À·¨’|fQÀ·ªÀ‚ÀÉ…À’’ññ…À·À·›À’’ÀÀ·„À¨’|fQ¡ÀÉ„ÀÉÀÀ‹À’’ññ–À·‹À·€À’ˆ‡À¨’|fQÀɘÀ€ÀÉ€ÀɃÀ’’çñ‚À·ˆÀ·ÀÀ·ŠÀ·†À’’…À·À¨’|fQ—ÀÉ‘À‹À’’ññ…À·“À·‚À·À·À’‡À¨’|fQ‡ÀÉ€ÀÉÀÀɈÀÉ€ÀÉ„ÀÉ‚ÀŠÀÉ’’ññÀ·À·ÀÀ·“À’’‡À¨’|fQ¥ÀɃÀ‹À’’ññ•À·‹À·À’’·À·À¨’|fQ·‹ÀÉ„ÀÉ”À‹À’’ññÀÀ·À·€À·ÀÀ·ŒÀ·À·…À’’…À·À¨’|fQ“ÀÉ„ÀÉ€ÀɈÀÉÀÀÉ€ÀÉ€ÀÉ€À’’ñç¨À·’’‡À¨’|fQ‹ÀÉ“ÀɆÀˆÀÉÀÀ’’çñƒÀ·‰À·ƒÀ·À·ŒÀ’’ƒÀ·€À¨’|fQ·À·ÀÉ€ÀÉÀÉ€ÀÉ€ÀÉ€ÀɈÀɃÀ‹À’’ññ“À·ŒÀ·‚À’’·†À¨’|fQœÀɈÀÉ€À‹À’’ññ‡À·ŽÀ·‹À·’’€À·ƒÀ¨’|fQ¬ÀÀÀÉ„ÀÉ€À’’ññÀ·ˆÀ·À·ˆÀ’’ƒÀ·€À¨’|fQ¢ÀɆÀ‚ÀÉ…À’’ññŽÀ’QGQGQGQ’ŠÀ·Àˆ’‡À¨’|fQ¥ÀɃÀ‰ÀÉÀ’’ññŠÀ·€À_ƒmÀÀ·‹À·’’†À·¨’|fQÀɧÀ„ÀɃÀ’’ññÀ·€À·‹À1#…À·‡À’’‡À¨’|fQ·žÀɈÀÉÉŠÀ’’ññÀ·‘Àˆ¦·ŽÀ·’’ÀÀ·ƒÀ·¨’|fQ„ÀÉ€ÀÉ€ÀÉ€ÀÉ€ÀÉ€ÀɆÀɆÀ‚ÀÉ…À’’ññ†À·ÀÀ·ÀÀ·‚À® Q‚À·‹À’’‡À¨’|fQ‹ÀÉ„ÀÉ„ÀɆÀɃÀ‹À’’ññÀ·ÀÀQ ®ŽÀ·ÀÀ’’‡À¨’|fQœÀɈÀÉ€À€ÀÉ€ÀɃÀ’’ññ‚À·‹À·_ÀÀ·ƒÀ·€À·„Àˆ’€À·À·À¨’|fQ¬À‹À’’ñç€À·À_®’À’’‡À¨’|fQÀÀ·ÀÉ„ÀÉ„ÀÉŠÀɆÀŠÀÉ’’ññ†À·‡À 1‡À·À·ÀÀ·ÀÀ·€Àˆ’‡À¨’|fQ‡ÀÉ€ÀÉ€ÀÉ„ÀÉ€ÀÉ‚ÀÉ„ÀÉÀÀ‹À’’ññ‚À·ŠÀ{“À’’ƒÀ·€À¨’|fQ¬À‹À’’ññŠÀ·‚À_®À·€À·ŠÀ’’‡À¨’|fQÀ·ªÀÀÀÉ€ÀÉ€ÀÉ€À’’ññÀ·ŒÀ··1À·’À’’À·À·€À¨’|fQÀÉŠÀÉ„ÀÉ‚ÀˆÀÉÀÀ’’ññÀ·À·™À·ƒÀ·À’’‡À¨’|fQ‡ÀÉŒÀÉ‘À‹À’’ññ‡À·‰À·€À·‡À·‚Àˆ’…À·À¨’|fQ¬À‹À’’çñÀ·–À’’‡À¨’|fQŸÀÉ€ÀÉ€ÀÉ€ÀÉÀÀÉ„ÀÉ€À’’ññ‹À·ŒÀ·ŠÀ’’‡À¨’|fQˆÀÉ€ÀÉ€ÀÉ„ÀÉÀ‚ÀÉ…À’’ññ€À··À·‹À·À’’…À ·À¨’|fQ9+ ©ˆŠÀ’’ññ’À·„À·ŠÀ·’’‡À¨’|fQ@+ ©_€ÀÉ€ÀÉÀ’’ññ…À·ƒÀ·ŽÀ·‡À’’‡À¨’|fQ9- ª_ˆÀ’’ññŽÀ·ƒÀ·À·’ˆÀÀ·À·À ·¨’|fQ>- ¬_‡À’ˆññ™À·‰À·ÀÀ’’É„À ·À¨’|fQ>+ ­_‚ÀÉ€À’’ññ‡À·†À·ŒÀ·„À’ˆ‡À¨’|fQ>+ ®_‚ÀÉÀÀˆ’ññ·‚À·ƒÀ·ˆÀ·ƒÀ·ˆÀ’’‡À¨’|fQ>+ ¯_„À’’ññŽÀ·—À’ˆÀ·‚À ¨’|fQ>+ ­_ƒÀ’’ññ†À·À·À·ÀÀ·†À’’‡À¨’|fQ>+ °_‚À’’ññŒÀ·™À’’‡À¨’|fQ>+ ­_À’’ññ—À·ŽÀ’’À·‚À¨’|fQ>+ ‚­_€À’’ññ“À·…ÀÉÀ·À·‚À’’„À ·ÀÀ¨’|fQ>+ ƒ­ _ÀÉ’’ññ¦’ˆ‚’ˆ’ˆ‚’ˆ„’ˆ‚’ˆ‚’ˆ…’ˆ‡À¨’|fQ>+ „¬_À’ñª’¦À·‚À¨’|fQ>+ …¬_’ˆÝ¶ñÓ·›€gM6 †®ˆ¸ñÓ·’ƒgQ1#¸¹91++ ·À¹93,% ¸¹91+#¹€9“9”9‡ 9Qg{’®–ÀQ›ˆ€€9“9”9‡ >Qg{ˆ®–ÀQ›ˆ€€9“9”9‡ >Qgƒ’®€ÀɇÀɇÀQ“ˆƒ„ˆ€€9“9”9‡ 9Qgƒ’¦“ÀÉÀÀYˆˆƒˆ€€9“9”9‡ >Qg{ˆ®†ÀɃÀÉ…ÀQ›ˆ€€9“9”9‡ 9Qgƒ’®ŽÀÉ„ÀQ›ˆ€€9“9”9‡ 9Qg{’®‹ÀɇÀQ„ˆ€ˆƒ€ˆ€€9“9”9‡ >Qg{’¦ƒÀÉÀQ€ˆƒ€ˆ‹ÿ„ˆ€€9“9”9‡ 9Qg{’¦†ÀɇÀÉ€ÀÉQ„ˆ‹ÿ„ˆ€€9“9”9‡ 9Qg{’¦–ÀQ‚ˆƒˆ‹ÿ„ˆ€€9“9”9‡ >Qg{’®€ÀɇÀɇÀQ„ˆ‹ÿ„ˆ€€9“9”9‡ >Qg{’¦ÀÉ€ÀÉÀQ„ˆ‹ÿƒƒˆ€€9“9”9‡ 9Qg{’®†ÀɃÀÉ…ÀQ„ˆ‹ÿ„ˆ€€9“9”9š€ÀɈÀQ„ˆ‹ÿ‚ˆƒˆ€€9“9”9›ˆÀÉÀÀQ„ˆ‹ÿ„ˆ€€9“9”9›ÀɆÀQˆƒ‚ˆ‹ÿ„ˆ€€9“9”9‡ >Qgƒˆ¦ÉƒÀÉ€‹ÀQ„ˆ‹ÿ„ˆ€€9“9”9‡ 9Qgƒ’®…À€‹ÀQ„ˆ‹ÿ„ˆ€€9“9”9‡ 9Qg{’¦…À€ˆÀÉÀÀQ„ˆ‹ÿ„ˆ€€9“9”9‡ >Qg{’®…À€ÀɆÀQ„ˆ‹ÿ„ˆ€€9“9”9‡ 9Qg{’¦ÀÉ€À€ÀɈÀÉQ„ˆ‹ÿ„ˆ€€9“9”9‡ 9Qg{ˆ®…À€‹ÀQ„ˆ„ˆ€¹9GQ>g{ˆ¦®…À€„ÀɃÀQ‹ˆÿ†ˆƒ€ˆ€€9“9”9ˆþ ñÉçÝÝÓÉÉÀÀÉ‚À€É„ÀÉ€ÀÉÀQˆƒ†ˆƒˆˆÿŠˆ€€9“9”9‡þññÀçÝÝÓÉÉ…À€‹ÀQ‹ˆÿŠˆ€€9“9”9ˆþñÀçÝÝÓÉÉ€ÀÉ€ÀÉ€ÀÀÉ€ÀÉ€ÀÉ€ÀQ‹ˆÿŠˆ€€9“9”9‡þññÉçÝ€ÓÉ…À€‹ÀQ„ˆƒƒˆÿŠˆ€€9“9”9ˆþñÀççÓÓÉÉ…À€‹ÀQ‹ˆÿˆƒˆƒƒˆ€€9“9”9‡þññÉçÝÝÓɆÀ€‹ÀQ‹ˆÿŠˆ€€9“9”9ˆþñÀçÝÝÓÓÉ€ÀÉ€ÀÉ€„ÀɃÀQˆƒ‰ˆÿŠˆ€€9“9”9‡þñÓÉ®¦ˆƒmg†QQY„QYŽQÿŠQ€€9“9”9‡þññÉ€ÝÓÉÉ–ÀQˆˆƒˆˆÿŠˆ€€9“9”9ˆþñÉçÝÝÓÉÉ–ÀQ‹ˆÿŠˆ€€9“9”9ˆþñÉçÝÝÓÉÉ“ÀÉÀÀY€ˆƒ‡ˆÿŠˆ€€9“9”9‡þññÉ€ÝÓÉÉ‹ÀɇÀQ‹ˆÿŠˆ€€9“9”9ˆþñÉçÝÝÓÉÉ„ÀÉŽÀQ‹ˆÿƒˆƒƒˆ€€9“9”9‡þññÉçÝ€ÓɃÀÉ…ÀɆÀQ‹ˆÿŠˆ€€9“9”9ˆþñÀçÝÝÓÉÉ–ÀQ†ˆƒˆÿˆƒ…ˆ€€9“>”9‡þññÉçÝÝÓÉÉÀɃÀQ‹ˆÿ†ˆƒ€ˆ€€9“>”9ˆþñÉçÝ€ÓÉ€ÀÉÀÉÀQ‹ˆÿŠˆ€€9“9”9‡þññÀçÝÝÓÉÉ…ÀÉ€ÀÉ„ÀÉÀQˆƒ‰ˆÿŠˆ€€9“9”9‡þññÉçÝÓÓÉɆÀÉ€ÀɈÀQ‹ˆÿˆƒˆˆ€€9“9”9ˆþñÀçÝÝÓÓÉÀɃÀQ‹ˆÿŠˆ€€9“9”9‡þññÉççÝÓÉÉ€ÀÉ’ÀQ„ˆƒƒˆÿƒˆƒƒˆ€€9“9”9ˆþñÉçÝÓÓÉÉ‘ÀÉÀQˆˆƒˆˆÿŠˆ€€9“9”9ˆþñɈgY9#¦ÿƒˆƒƒˆ€§9>…9>…9>Q#‚–©¾Óé§ÿŠˆ€€9“þ9mmg€mg‡mggm9mg‚m{{_91# †ÿœÿŠˆ€€9“þ9mgmgƒmgƒmgmm9‚m gmmgmmƒgˆ’¦®·…ÀÿŠÀÉQ‹ˆÿˆˆƒ‡ˆ€€9“þ9gg€mg€mgmgˆm9mgmgmmgm{g’’¦®·…Àÿ‹ÀQ‹ˆÿŠˆ€€9“þ9Œmgmgmm9‡m {ƒgˆ’¦¦®·ÀɃÀÿ‹ÀQ‹ˆÿŠˆ€€9“þ9”m9†m gmƒgˆ’¦®·€ÀÉÀÿ„ÀÉ€ÀÉÀÀQ„ˆƒƒˆÿˆƒ…ˆ€€9“þ9€mg€mg€mg‚mg‚m9€mg„m{g’¦®·…ÀÿÀÀɈÀQ‹ˆÿŠˆ€€9“þ9g€mgm9g‚mg€m {{gˆ’¦®·ÀÀÉ‚Àÿ†ÀÉ€ÀÉQ‹ˆÿŠˆ€€9“þ9mg„mg€mgmmgmgm9ˆm{_ˆ¦®·ƒÀÉÀÿÀɆÀQˆˆƒˆˆÿ€ˆƒ‚ˆƒ€ˆ€€9“þ9Šmg„mgm9€mgmg€m g{{g’’¦®·…Àÿ‹ÀQ‹ˆÿŠˆ€€9“þ9mgmg€mgmmgmgmmgg9‚mg‚mƒgˆ¦Ç·…ÀÿÀÀɈÀQ…ˆƒ‚ˆÿŠˆ€D>>Gþþñþñþñþñþñþñþñþñþñþñþ>m{mmgm{{m{m{m{{mm{m{m{{>{{g{m{{mm{{ƒg’®®·…À ø‹¨G‹vߊv€GQQþ’ñQƒƒ{€ƒ{{ƒƒ{{ƒƒ{€ƒ{{ƒƒmQˆˆ{{ƒƒ{ƒ{ƒƒˆm€®®·…Àñ‹’>‹gŠg€ QQgþççñçññçñçññçñçñ_ƒˆƒ€ˆƒ€ˆƒ€ˆƒ€ˆƒ€ˆ{Qˆ’ƒ€ˆƒ‚ˆƒ€®·…À+å‹|5‹W¤ŠW€_Yƒþ‚çÝ„çÝ„çg“ˆ{Y¦„ˆ’ˆˆ¦¦®®·†À>å‚g|ƒgff,‹GˆŠG€_g’þÝçÝ{’’’’€’€’€’’’{g®®’’’’’’ˆ¦mmgYY„QYl‹Q#‹9‚1‰9€ mmñÝÓÝÓÝÓ€ÝÓÝÓÝÓÓˆ“ƒm··‰Y‡’gÓg’‚’ˆ’†’gÓgˆ€{m·ñ’Ó’‚¦¦ƒ{ÉɈ¦®g€·†À{Ó{€ÀɇÀ‡ÀÉ€À{Ó{+-‡+€{ƒÉñ‹ÉÓ‚ÉÓ€®¦®ˆ{ÓÓ€®¦®¦Ç®·Y··‡À’Í’‹À®‹À’Í’À’†€ˆˆÝñÀÀ€ÉÀ€É ÀÉÀÉÀÉÉÀÉÀÉÉ®€·®·’ƒçÝ·®‡·Y‰À¦Ç®‹À·‹À®Ç® ÀÀ’ „ €’’ññ À·„À·’’ññ‰ÀQÀ·ªÀ€Àˆ‡’’ññ†À·‡À·”À’’ññ‚À·€À·ÀÀQ„ÀɇÀÉŠÀÉ‹ÀÀˆ†’’ññ‚À·†À·‰À·„À·ƒÀ·’’ññ‰ÀQ’ÀÉÀÉ€ÀÉÀ‚Àˆ…’’ññÀ·À·ƒÀ·‡À·ÀÀ’’ññÀ·€À·ƒÀQƒÀÉŠÀÉ—ÀƒÀˆ„’’ññÀ·ƒÀ·ŽÀ’’ññ‰ÀQ‡ÀÉ—ÀÉ„ÀÉÀ„Àˆƒ’’ññ‡À·€À·…À·‘À’’ññ‰ÀQÀÉŠÀÉ„ÀɃÀÀÀÉ‚Àˆ‚’’ññ€À·€À·–À·À·‚À’’ññ‡À·ÀQ·ˆÀɉÀÉ€ÀÉŽÀ‚ÀÉ€Àˆ’’ññ®ª’ññ¦ƒ’’€>®Ç®·¨À‡Àˆ€’ñª’ñ‚’ˆ’ˆ€¦>®®·‘ÀɆÀÉ€ÀÉ€ÀÉ€ÀÉÀˆÀ¦€’’ñç¨ñÀÀ·ˆÀQ„ÀɇÀɈÀÉÀÀÀÉ€ÀÉ‚Àˆ’’«ñç‡À®ˆ{_Q‰ÀÉ…ÀÉ–ÀŠÀ¦’’çñ˜À··‰À·ÀÀ’‡À¨’|fQ‰ÀÉ€ÀɈÀÉÀ‰ÀÉÀ’’ññ†À·ÀÀ·‡À·‘À’’‡À¨’|fQÀɈÀÉ€ÀÉ€ÀÉ€ÀÉ€À„ÀɃÀ’’ññ·€À·‰À·ŒÀ·‡À’’‚À·À¨’|fQ‡ÀÉŒÀÉ‘ÀÉŠÀ’’ññ˜À·À·ƒÀ·„À’’†À·¨’|fQÀ·ªÀ‚ÀÉ…À’’ññ…À·À·›À’’ÀÀ·„À¨’|fQ¡ÀÉ„ÀÉÀÀ‹À’’ññ–À·‹À·€À’ˆ‡À¨’|fQÀɘÀ€ÀÉ€ÀɃÀ’’çñ‚À·ˆÀ·ÀÀ·ŠÀ·†À’’…À·À¨’|fQ—ÀÉ‘À‹À’’ññ…À·“À·‚À·À·À’‡À¨’|fQ‡ÀÉ€ÀÉÀÀɈÀÉ€ÀÉ„ÀÉ‚ÀŠÀÉ’’ññÀ·À·ÀÀ·“À’’‡À¨’|fQ¥ÀɃÀ‹À’’ññ•À·‹À·À’’·À·À¨’|fQ·‹ÀÉ„ÀÉ”À‹À’’ññÀÀ·À·€À·ÀÀ·ŒÀ·À·…À’’…À·À¨’|fQ“ÀÉ„ÀÉ€ÀɈÀÉÀÀÉ€ÀÉ€ÀÉ€À’’ñç¨À·’’‡À¨’|fQ‹ÀÉ“ÀɆÀˆÀÉÀÀ’’çñƒÀ·‰À·ƒÀ·À·ŒÀ’’ƒÀ·€À¨’|fQ·À·ÀÉ€ÀÉÀÉ€ÀÉ€ÀÉ€ÀɈÀɃÀ‹À’’ññ“À·ŒÀ·‚À’’·†À¨’|fQœÀɈÀÉ€À‹À’’ññ‡À·ŽÀ·‹À·’’€À·ƒÀ¨’|fQ¬ÀÀÀÉ„ÀÉ€À’’ññÀ·ˆÀ·À·ˆÀ’’ƒÀ·€À¨’|fQ¢ÀɆÀ‚ÀÉ…À’’ññŽÀ’QGQGQGQ’ŠÀ·Àˆ’‡À¨’|fQ¥ÀɃÀ‰ÀÉÀ’’ññŠÀ·€À_ƒmÀÀ·‹À·’’†À·¨’|fQÀɧÀ„ÀɃÀ’’ññÀ·€À·‹À1#…À·‡À’’‡À¨’|fQ·žÀɈÀÉÉŠÀ’’ññÀ·‘Àˆ¦·ŽÀ·’’ÀÀ·ƒÀ·¨’|fQ„ÀÉ€ÀÉ€ÀÉ€ÀÉ€ÀÉ€ÀɆÀɆÀ‚ÀÉ…À’’ññ†À·ÀÀ·ÀÀ·‚À® Q‚À·‹À’’‡À¨’|fQ‹ÀÉ„ÀÉ„ÀɆÀɃÀ‹À’’ññÀ·ÀÀQ ®ŽÀ·ÀÀ’’‡À¨’|fQœÀɈÀÉ€À€ÀÉ€ÀɃÀ’’ññ‚À·‹À·_ÀÀ·ƒÀ·€À·„Àˆ’€À·À·À¨’|fQ¬À‹À’’ñç€À·À_®’À’’‡À¨’|fQÀÀ·ÀÉ„ÀÉ„ÀÉŠÀɆÀŠÀÉ’’ññ†À·‡À 1‡À·À·ÀÀ·ÀÀ·€Àˆ’‡À¨’|fQ‡ÀÉ€ÀÉ€ÀÉ„ÀÉ€ÀÉ‚ÀÉ„ÀÉÀÀ‹À’’ññ‚À·ŠÀ{“À’’ƒÀ·€À¨’|fQ¬À‹À’’ññŠÀ·‚À_®À·€À·ŠÀ’’‡À¨’|fQÀ·ªÀÀÀÉ€ÀÉ€ÀÉ€À’’ññÀ·ŒÀ··1À·’À’’À·À·€À¨’|fQÀÉŠÀÉ„ÀÉ‚ÀˆÀÉÀÀ’’ññÀ·À·™À·ƒÀ·À’’‡À¨’|fQ‡ÀÉŒÀÉ‘À‹À’’ññ‡À·‰À·€À·‡À·‚Àˆ’…À·À¨’|fQ¬À‹À’’çñÀ·–À’’‡À¨’|fQŸÀÉ€ÀÉ€ÀÉ€ÀÉÀÀÉ„ÀÉ€À’’ññ‹À·ŒÀ·ŠÀ’’‡À¨’|fQˆÀÉ€ÀÉ€ÀÉ„ÀÉÀ‚ÀÉ…À’’ññ€À··À·‹À·À’’…À ·À¨’|fQ9+ ©ˆŠÀ’’ññ’À·„À·ŠÀ·’’‡À¨’|fQ@+ ©_€ÀÉ€ÀÉÀ’’ññ…À·ƒÀ·ŽÀ·‡À’’‡À¨’|fQ9- ª_ˆÀ’’ññŽÀ·ƒÀ·À·’ˆÀÀ·À·À ·¨’|fQ>- ¬_‡À’ˆññ™À·‰À·ÀÀ’’É„À ·À¨’|fQ>+ ­_‚ÀÉ€À’’ññ‡À·†À·ŒÀ·„À’ˆ‡À¨’|fQ>+ ®_‚ÀÉÀÀˆ’ññ·‚À·ƒÀ·ˆÀ·ƒÀ·ˆÀ’’‡À¨’|fQ>+ ¯_„À’’ññŽÀ·—À’ˆÀ·‚À ¨’|fQ>+ ­_ƒÀ’’ññ†À·À·À·ÀÀ·†À’’‡À¨’|fQ>+ °_‚À’’ññŒÀ·™À’’‡À¨’|fQ>+ ­_À’’ññ—À·ŽÀ’’À·‚À¨’|fQ>+ ‚­_€À’’ññ“À·…ÀÉÀ·À·‚À’’„À ·ÀÀ¨’|fQ>+ ƒ­ _ÀÉ’’ññ¦’ˆ‚’ˆ’ˆ‚’ˆ„’ˆ‚’ˆ‚’ˆ…’ˆ‡À¨’|fQ>+ „¬_À’ñª’¦À·‚À¨’|fQ>+ …¬_’ˆÝ¶ñÓ·›€gM6 †®ˆ¸ñÓ·’ƒgQ1#¸¹91++ ·À¹93,% ¸¹91+#¸€9“9”9‡ 9Qg{’®–ÀQ›ˆ€€9“9”9‡ >Qg{ˆ®–ÀQ›ˆ€€9“9”9‡ >Qgƒ’®€ÀɇÀɇÀQ“ˆƒ„ˆ€€9“9”9‡ 9Qgƒ’¦“ÀÉÀÀYˆˆƒˆ€€9“9”9‡ >Qg{ˆ®†ÀɃÀÉ…ÀQ›ˆ€€9“9”9‡ 9Qgƒ’®ŽÀÉ„ÀQ›ˆ€€9“9”9‡ 9Qg{’®‹ÀɇÀQ„ˆ€ˆƒ€ˆ€€9“9”9‡ >Qg{’¦ƒÀÉÀQ€ˆƒ€ˆ‹ÿ„ˆ€€9“9”9‡ 9Qg{’¦†ÀɇÀÉ€ÀÉQ„ˆ‹ÿ„ˆ€€9“9”9‡ 9Qg{’¦–ÀQ‚ˆƒˆ‹ÿ„ˆ€€9“9”9‡ >Qg{’®€ÀɇÀɇÀQ„ˆ‹ÿ„ˆ€€9“9”9‡ >Qg{’¦ÀÉ€ÀÉÀQ„ˆ‹ÿƒƒˆ€€9“9”9‡ 9Qg{’®†ÀɃÀÉ…ÀQ„ˆ‹ÿ„ˆ€€9“9”9š€ÀɈÀQ„ˆ‹ÿ‚ˆƒˆ€€9“9”9›ˆÀÉÀÀQ„ˆ‹ÿ„ˆ€€9“9”9›ÀɆÀQˆƒ‚ˆ‹ÿ„ˆ€€9“9”9‡ >Qgƒˆ¦ÉƒÀÉ€‹ÀQ„ˆ‹ÿ„ˆ€€9“9”9‡ 9Qgƒ’®…À€‹ÀQ„ˆ‹ÿ„ˆ€€9“9”9‡ 9Qg{’¦…À€ˆÀÉÀÀQ„ˆ‹ÿ„ˆ€€9“9”9‡ >Qg{’®…À€ÀɆÀQ„ˆ‹ÿ„ˆ€€9“9”9‡ 9Qg{’¦ÀÉ€À€ÀɈÀÉQ„ˆ‹ÿ„ˆ€€9“9”9‡ 9Qg{ˆ®…À€‹ÀQ„ˆ„ˆ€¹9GQ>g{ˆ¦®…À€„ÀɃÀQ‹ˆÿ†ˆƒ€ˆ€€9“9”9ˆþ ñÉçÝÝÓÉÉÀÀÉ‚À€É„ÀÉ€ÀÉÀQˆƒ†ˆƒˆˆÿŠˆ€€9“9”9‡þññÀçÝÝÓÉÉ…À€‹ÀQ‹ˆÿŠˆ€€9“9”9ˆþñÀçÝÝÓÉÉ€ÀÉ€ÀÉ€ÀÀÉ€ÀÉ€ÀÉ€ÀQ‹ˆÿŠˆ€€9“9”9‡þññÉçÝ€ÓÉ…À€‹ÀQ„ˆƒƒˆÿŠˆ€€9“9”9ˆþñÀççÓÓÉÉ…À€‹ÀQ‹ˆÿˆƒˆƒƒˆ€€9“9”9‡þññÉçÝÝÓɆÀ€‹ÀQ‹ˆÿŠˆ€€9“9”9ˆþñÀçÝÝÓÓÉ€ÀÉ€ÀÉ€„ÀɃÀQˆƒ‰ˆÿŠˆ€€9“9”9‡þñÓÉ®¦ˆƒmg†QQY„QYŽQÿŠQ€€9“9”9‡þññÉ€ÝÓÉÉ–ÀQˆˆƒˆˆÿŠˆ€€9“9”9ˆþñÉçÝÝÓÉÉ–ÀQ‹ˆÿŠˆ€€9“9”9ˆþñÉçÝÝÓÉÉ“ÀÉÀÀY€ˆƒ‡ˆÿŠˆ€€9“9”9‡þññÉ€ÝÓÉÉ‹ÀɇÀQ‹ˆÿŠˆ€€9“9”9ˆþñÉçÝÝÓÉÉ„ÀÉŽÀQ‹ˆÿƒˆƒƒˆ€€9“9”9‡þññÉçÝ€ÓɃÀÉ…ÀɆÀQ‹ˆÿŠˆ€€9“9”9ˆþñÀçÝÝÓÉÉ–ÀQ†ˆƒˆÿˆƒ…ˆ€€9“>”9‡þññÉçÝÝÓÉÉÀɃÀQ‹ˆÿ†ˆƒ€ˆ€€9“>”9ˆþñÉçÝ€ÓÉ€ÀÉÀÉÀQ‹ˆÿŠˆ€€9“9”9‡þññÀçÝÝÓÉÉ…ÀÉ€ÀÉ„ÀÉÀQˆƒ‰ˆÿŠˆ€€9“9”9‡þññÉçÝÓÓÉɆÀÉ€ÀɈÀQ‹ˆÿˆƒˆˆ€€9“9”9ˆþñÀçÝÝÓÓÉÀɃÀQ‹ˆÿŠˆ€€9“9”9‡þññÉççÝÓÉÉ€ÀÉ’ÀQ„ˆƒƒˆÿƒˆƒƒˆ€€9“9”9ˆþñÉçÝÓÓÉÉ‘ÀÉÀQˆˆƒˆˆÿŠˆ€€9“9†…9ˆþñɈgY9#¦ÿƒˆƒƒˆ€§9>…9>…9>Q#‚–©¾Óé§ÿŠˆ€€9“þ9mmg€mg‡mggm9mg‚m{{_91# †ÿ—ÿŠˆ€€9“þ9mgmgƒmgƒmgmm9‚m gmmgmmƒgˆ’¦®·…ÀÿŠÀÉQ‹ˆÿˆˆƒ‡ˆ€€9“þ9gg€mg€mgmgˆm9mgmgmmgm{g’’¦®·…Àÿ‹ÀQ‹ˆÿŠˆ€€9“þ9Œmgmgmm9‡m {ƒgˆ’¦¦®·ÀɃÀÿ‹ÀQ‹ˆÿŠˆ€€9“þ9”m9†m gmƒgˆ’¦®·€ÀÉÀÿ„ÀÉ€ÀÉÀÀQ„ˆƒƒˆÿˆƒ…ˆ€€9“þ9€mg€mg€mg‚mg‚m9€mg„m{g’¦®·…ÀÿÀÀɈÀQ‹ˆÿŠˆ€€9“þ9g€mgm9g‚mg€m {{gˆ’¦®·ÀÀÉ‚Àÿ†ÀÉ€ÀÉQ‹ˆÿŠˆ€€9“þ9mg„mg€mgmmgmgm9ˆm{_ˆ¦®·ƒÀÉÀÿÀɆÀQˆˆƒˆˆÿ€ˆƒ‚ˆƒ€ˆ€€9“þ9Šmg„mgm9€mgmg€m g{{g’’¦®·…Àÿ‹ÀQ‹ˆÿŠˆ€€9“þ9mgmg€mgmmgmgmmgg9‚mg‚mƒgˆ¦Ç·…ÀÿÀÀɈÀQ…ˆƒ‚ˆÿŠˆ€D>>Gþþñþñþñþñþñþñþñþñþñþñþ>m{mmgm{{m{m{m{{mm{m{m{{>{{g{m{{mm{{ƒg’®®·…À ø‹Æa‹“ÿŠ“GQQþ’ñQƒƒ{€ƒ{{ƒƒ{{ƒƒ{€ƒ{{ƒƒmQˆˆ{{ƒƒ{ƒ{ƒƒˆm€®®·…Àñ‹Ìq‹ž#ÿ#Šž ##QQgþççñçññçñçññçñçñ_ƒˆƒ€ˆƒ€ˆƒ€ˆƒ€ˆƒ€ˆ{Qˆ’ƒ€ˆƒ‚ˆƒ€®·…À+å‹Ò‹©9ÿ9Š©99_Yƒþ‚çÝ„çÝ„çg“ˆ{Y¦„ˆ’ˆˆ¦¦®®·†À>åÙøÒƒÙØØ“‹µRÿRеRR_g’þÝçÝ{’’’’€’€’€’’’{g®®’’’’’’ˆ¦mmgYY„QYl‹Q#‹9‚1¯ˆÂ lRmmñÝÓÝÓÝÓ€ÝÓÝÓÝÓÓˆ“ƒm··‰Y‡’gÓg’‚’ˆ’†’gÓg%‹‡µˆˆ{m·ñ’Ó’‚¦¦ƒ{ÉɈ¦®g€·†À{Ó{€ÀɇÀ‡ÀÉ€À{Ó{+6·†ë¤¤{ƒÉñ‹ÉÓ‚ÉÓ€®¦®ˆ{ÓÓ€®¦®¦Ç®·Y··‡À’Í’‹À®‹À’Í’À’%µ…ñˆˆÝñÀÀ€ÉÀ€É ÀÉÀÉÀÉÉÀÉÀÉÉ®€·®·’ƒçÝ·®‡·Y‰À¦Ç®‹À·‹À®Ç® ÀÀ’µƒøýßß’’ññ À·„À·’’ññ‰ÀQÀ·ªÀ€Àˆ ´…ÿ’’ññ†À·‡À·”À’’ññ‚À·€À·ÀÀQ„ÀɇÀÉŠÀÉ‹ÀÀˆ ´„ÿ’’ññ‚À·†À·‰À·„À·ƒÀ·’’ññ‰ÀQ’ÀÉÀÉ€ÀÉÀ‚Àˆ ´ƒÿ’’ññÀ·À·ƒÀ·‡À·ÀÀ’’ññÀ·€À·ƒÀQƒÀÉŠÀÉ—ÀƒÀˆ ´‚ÿ’’ññÀ·ƒÀ·ŽÀ’’ññ‰ÀQ‡ÀÉ—ÀÉ„ÀÉÀ„Àˆ ´ÿ’’ññ‡À·€À·…À·‘À’’ññ‰ÀQÀÉŠÀÉ„ÀɃÀÀÀÉ‚Àˆ ´€ÿ’’ññ€À·€À·–À·À·‚À’’ññ‡À·ÀQ·ˆÀɉÀÉ€ÀÉŽÀ‚ÀÉ€À ˆ ´ÿÿ’’ññ®ª’ññ¦ƒ’’€>®Ç®·¨À‡Àˆ ¤ÿ’ñª’ñ‚’ˆ’ˆ€¦>®®·‘ÀɆÀÉ€ÀÉ€ÀÉ€ÀÉÀˆÀ¦´’’ñç¨ñÀÀ·ˆÀQ„ÀɇÀɈÀÉÀÀÀÉ€ÀÉ‚Àˆ ’’«ñç‡À®ˆ{_Q‰ÀÉ…ÀÉ–ÀŠÀ¦’’çñ˜À··‰À·ÀÀ’‡ÀÆÌÒØQ‰ÀÉ€ÀɈÀÉÀ‰ÀÉÀ’’ññ†À·ÀÀ·‡À·‘À’’‡ÀÆÌÒÊQÀɈÀÉ€ÀÉ€ÀÉ€ÀÉ€À„ÀɃÀ’’ññ·€À·‰À·ŒÀ·‡À’’‚À·ÀÆÌÒØQ‡ÀÉŒÀÉ‘ÀÉŠÀ’’ññ˜À·À·ƒÀ·„À’’†À·ÆÌÒØQÀ·ªÀ‚ÀÉ…À’’ññ…À·À·›À’’ÀÀ·„ÀÆÌÒØQ¡ÀÉ„ÀÉÀÀ‹À’’ññ–À·‹À·€À’ˆ‡ÀÆÌÒØQÀɘÀ€ÀÉ€ÀɃÀ’’çñ‚À·ˆÀ·ÀÀ·ŠÀ·†À’’…À·ÀÆÌÒØQ—ÀÉ‘À‹À’’ññ…À·“À·‚À·À·À’‡ÀÆÌÒØQ‡ÀÉ€ÀÉÀÀɈÀÉ€ÀÉ„ÀÉ‚ÀŠÀÉ’’ññÀ·À·ÀÀ·“À’’‡ÀÆÌÒØQ¥ÀɃÀ‹À’’ññ•À·‹À·À’’·À·ÀÆÌÒØQ·‹ÀÉ„ÀÉ”À‹À’’ññÀÀ·À·€À·ÀÀ·ŒÀ·À·…À’’…À·ÀÆÌÒØQ“ÀÉ„ÀÉ€ÀɈÀÉÀÀÉ€ÀÉ€ÀÉ€À’’ñç¨À·’’‡ÀÆÌÒØQ‹ÀÉ“ÀɆÀˆÀÉÀÀ’’çñƒÀ·‰À·ƒÀ·À·ŒÀ’’ƒÀ·€ÀÆÌÒØQ·À·ÀÉ€ÀÉÀÉ€ÀÉ€ÀÉ€ÀɈÀɃÀ‹À’’ññ“À·ŒÀ·‚À’’·†ÀÆÌÒØQœÀɈÀÉ€À‹À’’ññ‡À·ŽÀ·‹À·’’€À·ƒÀÆÌÒØQ¬ÀÀÀÉ„ÀÉ€À’’ññÀ·ˆÀ·À·ˆÀ’’ƒÀ·€ÀÆÌÒØQ¢ÀɆÀ‚ÀÉ…À’’ññŽÀ’QGQGQGQ’ŠÀ·Àˆ’‡ÀÆÌÒØQ¥ÀɃÀ‰ÀÉÀ’’ññŠÀ·€À_ƒmÀÀ·‹À·’’†À·ÆÌÒØQÀɧÀ„ÀɃÀ’’ññÀ·€À·‹À1#…À·‡À’’‡ÀÆÌÒØQ·žÀɈÀÉÉŠÀ’’ññÀ·‘Àˆ¦·ŽÀ·’’ÀÀ·ƒÀ·ÆÌÒØQ„ÀÉ€ÀÉ€ÀÉ€ÀÉ€ÀÉ€ÀɆÀɆÀ‚ÀÉ…À’’ññ†À·ÀÀ·ÀÀ·‚À® Q‚À·‹À’’‡ÀÆÌÒØQ‹ÀÉ„ÀÉ„ÀɆÀɃÀ‹À’’ññÀ·ÀÀQ ®ŽÀ·ÀÀ’’‡ÀÆÌÒØQœÀɈÀÉ€À€ÀÉ€ÀɃÀ’’ññ‚À·‹À·_ÀÀ·ƒÀ·€À·„Àˆ’€À·À·ÀÆÌÒØQ¬À‹À’’ñç€À·À_®’À’’‡ÀÆÌÒØQÀÀ·ÀÉ„ÀÉ„ÀÉŠÀɆÀŠÀÉ’’ññ†À·‡À 1‡À·À·ÀÀ·ÀÀ·€Àˆ’‡ÀÆÌÒØQ‡ÀÉ€ÀÉ€ÀÉ„ÀÉ€ÀÉ‚ÀÉ„ÀÉÀÀ‹À’’ññ‚À·ŠÀ{“À’’ƒÀ·€ÀÆÌÒØQ¬À‹À’’ññŠÀ·‚À_®À·€À·ŠÀ’’‡ÀÆÌÒØQÀ·ªÀÀÀÉ€ÀÉ€ÀÉ€À’’ññÀ·ŒÀ··1À·’À’’À·À·€ÀÆÌÒØQÀÉŠÀÉ„ÀÉ‚ÀˆÀÉÀÀ’’ññÀ·À·™À·ƒÀ·À’’‡ÀÆÌÒØQ‡ÀÉŒÀÉ‘À‹À’’ññ‡À·‰À·€À·‡À·‚Àˆ’…À·ÀÆÌÒØQ¬À‹À’’çñÀ·–À’’‡ÀÆÌÒØQŸÀÉ€ÀÉ€ÀÉ€ÀÉÀÀÉ„ÀÉ€À’’ññ‹À·ŒÀ·ŠÀ’’‡ÀÆÌÒØQˆÀÉ€ÀÉ€ÀÉ„ÀÉÀ‚ÀÉ…À’’ññ€À··À·‹À·À’’…À ·ÀÆÌÒÊQ9+ ©ˆŠÀ’’ññ’À·„À·ŠÀ·’’‡ÀÆÌÒØ¹H·ñø¨ÿ´ _€ÀÉ€ÀÉÀ’’ññ…À·ƒÀ·ŽÀ·‡À’’‡ÀÆÌÒØßÂ6‹ø©ÿ´ _ˆÀ’’ññŽÀ·ƒÀ·À·’ˆÀÀ·À·À ·ÆÌÒØßåµ6µªÿ´_‡À’ˆññ™À·‰À·ÀÀ’’É„À ·ÀÆÌÒØßåëµ´ªÿ´_‚ÀÉ€À’’ññ‡À·†À·ŒÀ·„À’ˆ‡À ÆÌÒØßåëñµ¤ªÿ´_‚ÀÉÀÀˆ’ññ·‚À·ƒÀ·ˆÀ·ƒÀ·ˆÀ’’‡À ÆÌÒØßåëñø¤´ªÿ´_„À’’ññŽÀ·—À’ˆÀ·‚À ÆÌÒØßåëñøÿ´ ¤ªÿ´_ƒÀ’’ññ†À·À·À·ÀÀ·†À’’‡À ÆÌÒØßåëñøÿÿ¤´ªÿ¤ _‚À’’ññŒÀ·™À’’‡ÀÆÌÒØßåëñø€ÿ´ ´ªÿ´_À’’ññ—À·ŽÀ’’À·‚ÀÆÌÒØßåëñøÿ´ ´ªÿ´_€À’’ññ“À·…ÀÉÀ·À·‚À’’„À ·ÀÀÆÌÒØßåëñø‚ÿ´ ´ªÿ ´_ÀÉ’’ññ¦’ˆ‚’ˆ’ˆ‚’ˆ„’ˆ‚’ˆ‚’ˆ…’ˆ‡ÀÆÌÒØßåëñøƒÿ´ ´ªÿ¤ _À’ñª’¦À·‚ÀÆÌÒØßåëñø„ÿ´ ´ªÿ¤ _’ˆÝ¶ñóôõöøùúûý…ÿ´ ´ªÿ¤ˆ¸ñÓ·’ƒgQ1#´€t8mk@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿpuzzles-20170606.272beef/osx-info.plist0000644000175000017500000000211613115373615016510 0ustar simonsimon CFBundleIconFile Puzzles.icns CFBundleHelpBookFolder Help CFBundleHelpBookName Puzzles Help CFBundleName Puzzles CFBundleDisplayName Puzzles CFBundleExecutable Puzzles CFBundleVersion 20170606.272beef CFBundleShortVersionString 20170606.272beef CFBundleDevelopmentRegion en CFBundleIdentifier uk.org.greenend.chiark.sgtatham.puzzles CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType APPL CFBundleSignature ???? NSHumanReadableCopyright This software is copyright (c) 2004-2014 Simon Tatham puzzles-20170606.272beef/puzzles.but0000644000175000017500000040165213115373615016131 0ustar simonsimon\title Simon Tatham's Portable Puzzle Collection \cfg{winhelp-filename}{puzzles.hlp} \cfg{winhelp-contents-titlepage}{Contents} \cfg{text-filename}{puzzles.txt} \cfg{html-contents-filename}{index.html} \cfg{html-template-filename}{%k.html} \cfg{html-index-filename}{docindex.html} \cfg{html-leaf-level}{1} \cfg{html-contents-depth-0}{1} \cfg{html-contents-depth-1}{2} \cfg{html-leaf-contains-contents}{true} \cfg{chm-filename}{puzzles.chm} \cfg{chm-contents-filename}{index.html} \cfg{chm-template-filename}{%k.html} \cfg{chm-head-end}{} \cfg{chm-extra-file}{chm.css} \cfg{info-filename}{puzzles.info} \cfg{ps-filename}{puzzles.ps} \cfg{pdf-filename}{puzzles.pdf} \define{by} \u00D7{x} \define{dash} \u2013{-} \define{times} \u00D7{*} \define{divide} \u00F7{/} \define{minus} \u2212{-} This is a collection of small one-player puzzle games. \copyright This manual is copyright 2004-2014 Simon Tatham. All rights reserved. You may distribute this documentation under the MIT licence. See \k{licence} for the licence text in full. \cfg{html-local-head}{} \C{intro} Introduction I wrote this collection because I thought there should be more small desktop toys available: little games you can pop up in a window and play for two or three minutes while you take a break from whatever else you were doing. And I was also annoyed that every time I found a good game on (say) \i{Unix}, it wasn't available the next time I was sitting at a \i{Windows} machine, or vice versa; so I arranged that everything in my personal puzzle collection will happily run on both, and have more recently done a port to \i{Mac OS X} as well. When I find (or perhaps invent) further puzzle games that I like, they'll be added to this collection and will immediately be available on both platforms. And if anyone feels like writing any other front ends \dash PocketPC, Mac OS pre-10, or whatever it might be \dash then all the games in this framework will immediately become available on another platform as well. The actual games in this collection were mostly not my invention; they are re-implementations of existing game concepts within my portable puzzle framework. I do not claim credit, in general, for inventing the rules of any of these puzzles. (I don't even claim authorship of all the code; some of the puzzles have been submitted by other authors.) This collection is distributed under the \i{MIT licence} (see \k{licence}). This means that you can do pretty much anything you like with the game binaries or the code, except pretending you wrote them yourself, or suing me if anything goes wrong. The most recent versions, and \i{source code}, can be found at \I{website}\W{https://www.chiark.greenend.org.uk/~sgtatham/puzzles/}\cw{https://www.chiark.greenend.org.uk/~sgtatham/puzzles/}. Please report \I{feedback}\i{bugs} to \W{mailto:anakin@pobox.com}\cw{anakin@pobox.com}. You might find it helpful to read this article before reporting a bug: \W{https://www.chiark.greenend.org.uk/~sgtatham/bugs.html}\cw{https://www.chiark.greenend.org.uk/~sgtatham/bugs.html} \ii{Patches} are welcome. Especially if they provide a new front end (to make all these games run on another platform), or a new game. \C{common} \ii{Common features} This chapter describes features that are common to all the games. \H{common-actions} \I{controls}Common actions These actions are all available from the \I{Game menu}\q{Game} menu and via \I{keys}keyboard shortcuts, in addition to any game-specific actions. (On \i{Mac OS X}, to conform with local user interface standards, these actions are situated on the \I{File menu}\q{File} and \I{Edit menu}\q{Edit} menus instead.) \dt \ii\e{New game} (\q{N}, Ctrl+\q{N}) \dd Starts a new game, with a random initial state. \dt \ii\e{Restart game} \dd Resets the current game to its initial state. (This can be undone.) \dt \ii\e{Load} \dd Loads a saved game from a file on disk. \dt \ii\e{Save} \dd Saves the current state of your game to a file on disk. \lcont{ The Load and Save operations preserve your entire game history (so you can save, reload, and still Undo and Redo things you had done before saving). } \dt \I{printing, on Windows}\e{Print} \dd Where supported (currently only on Windows), brings up a dialog allowing you to print an arbitrary number of puzzles randomly generated from the current parameters, optionally including the current puzzle. (Only for puzzles which make sense to print, of course \dash it's hard to think of a sensible printable representation of Fifteen!) \dt \ii\e{Undo} (\q{U}, Ctrl+\q{Z}, Ctrl+\q{_}) \dd Undoes a single move. (You can undo moves back to the start of the session.) \dt \ii\e{Redo} (\q{R}, Ctrl+\q{R}) \dd Redoes a previously undone move. \dt \ii\e{Copy} \dd Copies the current state of your game to the clipboard in text format, so that you can paste it into (say) an e-mail client or a web message board if you're discussing the game with someone else. (Not all games support this feature.) \dt \ii\e{Solve} \dd Transforms the puzzle instantly into its solved state. For some games (Cube) this feature is not supported at all because it is of no particular use. For other games (such as Pattern), the solved state can be used to give you information, if you can't see how a solution can exist at all or you want to know where you made a mistake. For still other games (such as Sixteen), automatic solution tells you nothing about how to \e{get} to the solution, but it does provide a useful way to get there quickly so that you can experiment with set-piece moves and transformations. \lcont{ Some games (such as Solo) are capable of solving a game ID you have typed in from elsewhere. Other games (such as Rectangles) cannot solve a game ID they didn't invent themself, but when they did invent the game ID they know what the solution is already. Still other games (Pattern) can solve \e{some} external game IDs, but only if they aren't too difficult. The \q{Solve} command adds the solved state to the end of the undo chain for the puzzle. In other words, if you want to go back to solving it yourself after seeing the answer, you can just press Undo. } \dt \I{exit}\ii\e{Quit} (\q{Q}, Ctrl+\q{Q}) \dd Closes the application entirely. \H{common-id} Specifying games with the \ii{game ID} There are two ways to save a game specification out of a puzzle and recreate it later, or recreate it in somebody else's copy of the same puzzle. The \q{\i{Specific}} and \q{\i{Random Seed}} options from the \I{Game menu}\q{Game} menu (or the \q{File} menu, on \i{Mac OS X}) each show a piece of text (a \q{game ID}) which is sufficient to reconstruct precisely the same game at a later date. You can enter either of these pieces of text back into the program (via the same \q{Specific} or \q{Random Seed} menu options) at a later point, and it will recreate the same game. You can also use either one as a \i{command line} argument (on Windows or Unix); see \k{common-cmdline} for more detail. The difference between the two forms is that a descriptive game ID is a literal \e{description} of the \i{initial state} of the game, whereas a random seed is just a piece of arbitrary text which was provided as input to the random number generator used to create the puzzle. This means that: \b Descriptive game IDs tend to be longer in many puzzles (although some, such as Cube (\k{cube}), only need very short descriptions). So a random seed is often a \e{quicker} way to note down the puzzle you're currently playing, or to tell it to somebody else so they can play the same one as you. \b Any text at all is a valid random seed. The automatically generated ones are fifteen-digit numbers, but anything will do; you can type in your full name, or a word you just made up, and a valid puzzle will be generated from it. This provides a way for two or more people to race to complete the same puzzle: you think of a random seed, then everybody types it in at the same time, and nobody has an advantage due to having seen the generated puzzle before anybody else. \b It is often possible to convert puzzles from other sources (such as \q{nonograms} or \q{sudoku} from newspapers) into descriptive game IDs suitable for use with these programs. \b Random seeds are not guaranteed to produce the same result if you use them with a different \i\e{version} of the puzzle program. This is because the generation algorithm might have been improved or modified in later versions of the code, and will therefore produce a different result when given the same sequence of random numbers. Use a descriptive game ID if you aren't sure that it will be used on the same version of the program as yours. \lcont{(Use the \q{About} menu option to find out the version number of the program. Programs with the same version number running on different platforms should still be random-seed compatible.)} \I{ID format}A descriptive game ID starts with a piece of text which encodes the \i\e{parameters} of the current game (such as grid size). Then there is a colon, and after that is the description of the game's initial state. A random seed starts with a similar string of parameters, but then it contains a hash sign followed by arbitrary data. If you enter a descriptive game ID, the program will not be able to show you the random seed which generated it, since it wasn't generated \e{from} a random seed. If you \e{enter} a random seed, however, the program will be able to show you the descriptive game ID derived from that random seed. Note that the game parameter strings are not always identical between the two forms. For some games, there will be parameter data provided with the random seed which is not included in the descriptive game ID. This is because that parameter information is only relevant when \e{generating} puzzle grids, and is not important when playing them. Thus, for example, the difficulty level in Solo (\k{solo}) is not mentioned in the descriptive game ID. These additional parameters are also not set permanently if you type in a game ID. For example, suppose you have Solo set to \q{Advanced} difficulty level, and then a friend wants your help with a \q{Trivial} puzzle; so the friend reads out a random seed specifying \q{Trivial} difficulty, and you type it in. The program will generate you the same \q{Trivial} grid which your friend was having trouble with, but once you have finished playing it, when you ask for a new game it will automatically go back to the \q{Advanced} difficulty which it was previously set on. \H{common-type} The \q{Type} menu The \I{Type menu}\q{Type} menu, if present, may contain a list of \i{preset} game settings. Selecting one of these will start a new random game with the parameters specified. The \q{Type} menu may also contain a \q{\i{Custom}} option which allows you to fine-tune game \i{parameters}. The parameters available are specific to each game and are described in the following sections. \H{common-cmdline} Specifying game parameters on the \i{command line} (This section does not apply to the \i{Mac OS X} version.) The games in this collection deliberately do not ever save information on to the computer they run on: they have no high score tables and no saved preferences. (This is because I expect at least some people to play them at work, and those people will probably appreciate leaving as little evidence as possible!) However, if you do want to arrange for one of these games to \I{default parameters, specifying}default to a particular set of parameters, you can specify them on the command line. The easiest way to do this is to set up the parameters you want using the \q{Type} menu (see \k{common-type}), and then to select \q{Random Seed} from the \q{Game} or \q{File} menu (see \k{common-id}). The text in the \q{Game ID} box will be composed of two parts, separated by a hash. The first of these parts represents the game parameters (the size of the playing area, for example, and anything else you set using the \q{Type} menu). If you run the game with just that parameter text on the command line, it will start up with the settings you specified. For example: if you run Cube (see \k{cube}), select \q{Octahedron} from the \q{Type} menu, and then go to the game ID selection, you will see a string of the form \cq{o2x2#338686542711620}. Take only the part before the hash (\cq{o2x2}), and start Cube with that text on the command line: \cq{PREFIX-cube o2x2}. If you copy the \e{entire} game ID on to the command line, the game will start up in the specific game that was described. This is occasionally a more convenient way to start a particular game ID than by pasting it into the game ID selection box. (You could also retrieve the encoded game parameters using the \q{Specific} menu option instead of \q{Random Seed}, but if you do then some options, such as the difficulty level in Solo, will be missing. See \k{common-id} for more details on this.) \H{common-unix-cmdline} \i{Unix} \i{command-line} options (This section only applies to the Unix port.) In addition to being able to specify game parameters on the command line (see \k{common-cmdline}), there are various other options: \dt \cw{--game} \dt \cw{--load} \dd These options respectively determine whether the command-line argument is treated as specifying game parameters or a \i{save} file to \i{load}. Only one should be specified. If neither of these options is specified, a guess is made based on the format of the argument. \dt \cw{--generate }\e{n} \dd If this option is specified, instead of a puzzle being displayed, a number of descriptive game IDs will be \I{generating game IDs}invented and printed on standard output. This is useful for gaining access to the game generation algorithms without necessarily using the frontend. \lcont{ If game parameters are specified on the command-line, they will be used to generate the game IDs; otherwise a default set of parameters will be used. The most common use of this option is in conjunction with \c{--print}, in which case its behaviour is slightly different; see below. } \dt \I{printing, on Unix}\cw{--print }\e{w}\cw{x}\e{h} \dd If this option is specified, instead of a puzzle being displayed, a printed representation of one or more unsolved puzzles is sent to standard output, in \i{PostScript} format. \lcont{ On each page of puzzles, there will be \e{w} across and \e{h} down. If there are more puzzles than \e{w}\by\e{h}, more than one page will be printed. If \c{--generate} has also been specified, the invented game IDs will be used to generate the printed output. Otherwise, a list of game IDs is expected on standard input (which can be descriptive or random seeds; see \k{common-id}), in the same format produced by \c{--generate}. For example: \c PREFIX-net --generate 12 --print 2x3 7x7w | lpr will generate two pages of printed Net puzzles (each of which will have a 7\by\.7 wrapping grid), and pipe the output to the \c{lpr} command, which on many systems will send them to an actual printer. There are various other options which affect printing; see below. } \dt \cw{--save }\e{file-prefix} [ \cw{--save-suffix }\e{file-suffix} ] \dd If this option is specified, instead of a puzzle being displayed, saved-game files for one or more unsolved puzzles are written to files constructed from the supplied prefix and/or suffix. \lcont{ If \c{--generate} has also been specified, the invented game IDs will be used to generate the printed output. Otherwise, a list of game IDs is expected on standard input (which can be descriptive or random seeds; see \k{common-id}), in the same format produced by \c{--generate}. For example: \c PREFIX-net --generate 12 --save game --save-suffix .sav will generate twelve Net saved-game files with the names \cw{game0.sav} to \cw{game11.sav}. } \dt \cw{--version} \dd Prints version information about the game, and then quits. The following options are only meaningful if \c{--print} is also specified: \dt \cw{--with-solutions} \dd The set of pages filled with unsolved puzzles will be followed by the solutions to those puzzles. \dt \cw{--scale }\e{n} \dd Adjusts how big each puzzle is when printed. Larger numbers make puzzles bigger; the default is 1.0. \dt \cw{--colour} \dd Puzzles will be printed in colour, rather than in black and white (if supported by the puzzle). \C{net} \i{Net} \cfg{winhelp-topic}{games.net} (\e{Note:} the \i{Windows} version of this game is called \i\cw{NETGAME.EXE} to avoid clashing with Windows's own \cw{NET.EXE}.) I originally saw this in the form of a Flash game called \i{FreeNet} \k{FreeNet}, written by Pavils Jurjans; there are several other implementations under the name \i{NetWalk}. The computer prepares a network by connecting up the centres of squares in a grid, and then shuffles the network by rotating every tile randomly. Your job is to rotate it all back into place. The successful solution will be an entirely connected network, with no closed loops. \#{The latter clause means that there are no closed paths within the network. Could this be clearer? "No closed paths"?} As a visual aid, all tiles which are connected to the one in the middle are highlighted. \B{FreeNet} \W{http://www.jurjans.lv/stuff/net/FreeNet.htm}\cw{http://www.jurjans.lv/stuff/net/FreeNet.htm} \H{net-controls} \i{Net controls} \IM{Net controls} controls, for Net \IM{Net controls} keys, for Net \IM{Net controls} shortcuts (keyboard), for Net This game can be played with either the keyboard or the mouse. The controls are: \dt \e{Select tile}: mouse pointer, arrow keys \dt \e{Rotate tile anticlockwise}: left mouse button, \q{A} key \dt \e{Rotate tile clockwise}: right mouse button, \q{D} key \dt \e{Rotate tile by 180 degrees}: \q{F} key \dt \e{Lock (or unlock) tile}: middle mouse button, shift-click, \q{S} key \dd You can lock a tile once you're sure of its orientation. You can also unlock it again, but while it's locked you can't accidentally turn it. The following controls are not necessary to complete the game, but may be useful: \dt \e{Shift grid}: Shift + arrow keys \dd On grids that wrap, you can move the origin of the grid, so that tiles that were on opposite sides of the grid can be seen together. \dt \e{Move centre}: Ctrl + arrow keys \dd You can change which tile is used as the source of highlighting. (It doesn't ultimately matter which tile this is, as every tile will be connected to every other tile in a correct solution, but it may be helpful in the intermediate stages of solving the puzzle.) \dt \e{Jumble tiles}: \q{J} key \dd This key turns all tiles that are not locked to random orientations. (All the actions described in \k{common-actions} are also available.) \H{net-params} \I{parameters, for Net}Net parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid in tiles. \dt \e{Walls wrap around} \dd If checked, flow can pass from the left edge to the right edge, and from top to bottom, and vice versa. \dt \e{Barrier probability} \dd A number between 0.0 and 1.0 controlling whether an immovable barrier is placed between two tiles to prevent flow between them (a higher number gives more barriers). Since barriers are immovable, they act as constraints on the solution (i.e., hints). \lcont{ The grid generation in Net has been carefully arranged so that the barriers are independent of the rest of the grid. This means that if you note down the random seed used to generate the current puzzle (see \k{common-id}), change the \e{Barrier probability} parameter, and then re-enter the same random seed, you should see exactly the same starting grid, with the only change being the number of barriers. So if you're stuck on a particular grid and need a hint, you could start up another instance of Net, set up the same parameters but a higher barrier probability, and enter the game seed from the original Net window. } \dt \e{Ensure unique solution} \dd Normally, Net will make sure that the puzzles it presents have only one solution. Puzzles with ambiguous sections can be more difficult and more subtle, so if you like you can turn off this feature and risk having ambiguous puzzles. (Also, finding \e{all} the possible solutions can be an additional challenge for an advanced player.) \C{cube} \i{Cube} \cfg{winhelp-topic}{games.cube} This is another one I originally saw as a web game. This one was a Java game \k{cube-java-game}, by Paul Scott. You have a grid of 16 squares, six of which are blue; on one square rests a cube. Your move is to use the arrow keys to roll the cube through 90 degrees so that it moves to an adjacent square. If you roll the cube on to a blue square, the blue square is picked up on one face of the cube; if you roll a blue face of the cube on to a non-blue square, the blueness is put down again. (In general, whenever you roll the cube, the two faces that come into contact swap colours.) Your job is to get all six blue squares on to the six faces of the cube at the same time. Count your moves and try to do it in as few as possible. Unlike the original Java game, my version has an additional feature: once you've mastered the game with a cube rolling on a square grid, you can change to a triangular grid and roll any of a tetrahedron, an octahedron or an icosahedron. \B{cube-java-game} \W{http://www3.sympatico.ca/paulscott/cube/cube.htm}\cw{http://www3.sympatico.ca/paulscott/cube/cube.htm} \H{cube-controls} \i{Cube controls} \IM{Cube controls} controls, for Cube \IM{Cube controls} keys, for Cube \IM{Cube controls} shortcuts (keyboard), for Cube This game can be played with either the keyboard or the mouse. Left-clicking anywhere on the window will move the cube (or other solid) towards the mouse pointer. The arrow keys can also used to roll the cube on its square grid in the four cardinal directions. On the triangular grids, the mapping of arrow keys to directions is more approximate. Vertical movement is disallowed where it doesn't make sense. The four keys surrounding the arrow keys on the numeric keypad (\q{7}, \q{9}, \q{1}, \q{3}) can be used for diagonal movement. (All the actions described in \k{common-actions} are also available.) \H{cube-params} \I{parameters, for Cube}Cube parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Type of solid} \dd Selects the solid to roll (and hence the shape of the grid): tetrahedron, cube, octahedron, or icosahedron. \dt \e{Width / top}, \e{Height / bottom} \dd On a square grid, horizontal and vertical dimensions. On a triangular grid, the number of triangles on the top and bottom rows respectively. \C{fifteen} \i{Fifteen} \cfg{winhelp-topic}{games.fifteen} The old ones are the best: this is the good old \q{\i{15-puzzle}} with sliding tiles. You have a 4\by\.4 square grid; 15 squares contain numbered tiles, and the sixteenth is empty. Your move is to choose a tile next to the empty space, and slide it into the space. The aim is to end up with the tiles in numerical order, with the space in the bottom right (so that the top row reads 1,2,3,4 and the bottom row reads 13,14,15,\e{space}). \H{fifteen-controls} \i{Fifteen controls} \IM{Fifteen controls} controls, for Fifteen \IM{Fifteen controls} keys, for Fifteen \IM{Fifteen controls} shortcuts (keyboard), for Fifteen This game can be controlled with the mouse or the keyboard. A left-click with the mouse in the row or column containing the empty space will move as many tiles as necessary to move the space to the mouse pointer. The arrow keys will move a tile adjacent to the space in the direction indicated (moving the space in the \e{opposite} direction). Pressing \q{h} will make a suggested move. Pressing \q{h} enough times will solve the game, but it may scramble your progress while doing so. (All the actions described in \k{common-actions} are also available.) \H{fifteen-params} \I{parameters, for Fifteen}Fifteen parameters The only options available from the \q{Custom...} option on the \q{Type} menu are \e{Width} and \e{Height}, which are self-explanatory. (Once you've changed these, it's not a \q{15-puzzle} any more, of course!) \C{sixteen} \i{Sixteen} \cfg{winhelp-topic}{games.sixteen} Another sliding tile puzzle, visually similar to Fifteen (see \k{fifteen}) but with a different type of move. This time, there is no hole: all 16 squares on the grid contain numbered squares. Your move is to shift an entire row left or right, or shift an entire column up or down; every time you do that, the tile you shift off the grid re-appears at the other end of the same row, in the space you just vacated. To win, arrange the tiles into numerical order (1,2,3,4 on the top row, 13,14,15,16 on the bottom). When you've done that, try playing on different sizes of grid. I \e{might} have invented this game myself, though only by accident if so (and I'm sure other people have independently invented it). I thought I was imitating a screensaver I'd seen, but I have a feeling that the screensaver might actually have been a Fifteen-type puzzle rather than this slightly different kind. So this might be the one thing in my puzzle collection which represents creativity on my part rather than just engineering. \H{sixteen-controls} \I{controls, for Sixteen}Sixteen controls Left-clicking on an arrow will move the appropriate row or column in the direction indicated. Right-clicking will move it in the opposite direction. Alternatively, use the cursor keys to move the position indicator around the edge of the grid, and use the return key to move the row/column in the direction indicated. You can also move the tiles directly. Move the cursor onto a tile, hold Control and press an arrow key to move the tile under the cursor and move the cursor along with the tile. Or, hold Shift to move only the tile. Pressing Enter simulates holding down Control (press Enter again to release), while pressing Space simulates holding down shift. (All the actions described in \k{common-actions} are also available.) \H{sixteen-params} \I{parameters, for Sixteen}Sixteen parameters The parameters available from the \q{Custom...} option on the \q{Type} menu are: \b \e{Width} and \e{Height}, which are self-explanatory. \b You can ask for a limited shuffling operation to be performed on the grid. By default, Sixteen will shuffle the grid in such a way that any arrangement is about as probable as any other. You can override this by requesting a precise number of shuffling moves to be performed. Typically your aim is then to determine the precise set of shuffling moves and invert them exactly, so that you answer (say) a four-move shuffle with a four-move solution. Note that the more moves you ask for, the more likely it is that solutions shorter than the target length will turn out to be possible. \C{twiddle} \i{Twiddle} \cfg{winhelp-topic}{games.twiddle} Twiddle is a tile-rearrangement puzzle, visually similar to Sixteen (see \k{sixteen}): you are given a grid of square tiles, each containing a number, and your aim is to arrange the numbers into ascending order. In basic Twiddle, your move is to rotate a square group of four tiles about their common centre. (Orientation is not significant in the basic puzzle, although you can select it.) On more advanced settings, you can rotate a larger square group of tiles. I first saw this type of puzzle in the GameCube game \q{Metroid Prime 2}. In the Main Gyro Chamber in that game, there is a puzzle you solve to unlock a door, which is a special case of Twiddle. I developed this game as a generalisation of that puzzle. \H{twiddle-controls} \I{controls, for Twiddle}Twiddle controls To play Twiddle, click the mouse in the centre of the square group you wish to rotate. In the basic mode, you rotate a 2\by\.2 square, which means you have to click at a corner point where four tiles meet. In more advanced modes you might be rotating 3\by\.3 or even more at a time; if the size of the square is odd then you simply click in the centre tile of the square you want to rotate. Clicking with the left mouse button rotates the group anticlockwise. Clicking with the right button rotates it clockwise. You can also move an outline square around the grid with the cursor keys; the square is the size above (2\by\.2 by default, or larger). Pressing the return key or space bar will rotate the current square anticlockwise or clockwise respectively. (All the actions described in \k{common-actions} are also available.) \H{twiddle-parameters} \I{parameters, for Twiddle}Twiddle parameters Twiddle provides several configuration options via the \q{Custom} option on the \q{Type} menu: \b You can configure the width and height of the puzzle grid. \b You can configure the size of square block that rotates at a time. \b You can ask for every square in the grid to be distinguishable (the default), or you can ask for a simplified puzzle in which there are groups of identical numbers. In the simplified puzzle your aim is just to arrange all the 1s into the first row, all the 2s into the second row, and so on. \b You can configure whether the orientation of tiles matters. If you ask for an orientable puzzle, each tile will have a triangle drawn in it. All the triangles must be pointing upwards to complete the puzzle. \b You can ask for a limited shuffling operation to be performed on the grid. By default, Twiddle will shuffle the grid so much that any arrangement is about as probable as any other. You can override this by requesting a precise number of shuffling moves to be performed. Typically your aim is then to determine the precise set of shuffling moves and invert them exactly, so that you answer (say) a four-move shuffle with a four-move solution. Note that the more moves you ask for, the more likely it is that solutions shorter than the target length will turn out to be possible. \C{rect} \i{Rectangles} \cfg{winhelp-topic}{games.rectangles} You have a grid of squares, with numbers written in some (but not all) of the squares. Your task is to subdivide the grid into rectangles of various sizes, such that (a) every rectangle contains exactly one numbered square, and (b) the area of each rectangle is equal to the number written in its numbered square. Credit for this game goes to the Japanese puzzle magazine \i{Nikoli} \k{nikoli-rect}; I've also seen a Palm implementation at \i{Puzzle Palace} \k{puzzle-palace-rect}. Unlike Puzzle Palace's implementation, my version automatically generates random grids of any size you like. The quality of puzzle design is therefore not quite as good as hand-crafted puzzles would be, but on the plus side you get an inexhaustible supply of puzzles tailored to your own specification. \B{nikoli-rect} \W{http://www.nikoli.co.jp/en/puzzles/shikaku.html}\cw{http://www.nikoli.co.jp/en/puzzles/shikaku.html} (beware of Flash) \B{puzzle-palace-rect} \W{https://web.archive.org/web/20041024001459/http://www.puzzle.gr.jp/puzzle/sikaku/palm/index.html.en}\cw{https://web.archive.org/web/20041024001459/http://www.puzzle.gr.jp/puzzle/sikaku/palm/index.html.en} \H{rectangles-controls} \I{controls, for Rectangles}Rectangles controls This game is played with the mouse or cursor keys. Left-click any edge to toggle it on or off, or left-click and drag to draw an entire rectangle (or line) on the grid in one go (removing any existing edges within that rectangle). Right-clicking and dragging will allow you to erase the contents of a rectangle without affecting its edges. Alternatively, use the cursor keys to move the position indicator around the board. Pressing the return key then allows you to use the cursor keys to drag a rectangle out from that position, and pressing the return key again completes the rectangle. Using the space bar instead of the return key allows you to erase the contents of a rectangle without affecting its edges, as above. Pressing escape cancels a drag. When a rectangle of the correct size is completed, it will be shaded. (All the actions described in \k{common-actions} are also available.) \H{rectangles-params} \I{parameters, for Rectangles}Rectangles parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid, in squares. \dt \e{Expansion factor} \dd This is a mechanism for changing the type of grids generated by the program. Some people prefer a grid containing a few large rectangles to one containing many small ones. So you can ask Rectangles to essentially generate a \e{smaller} grid than the size you specified, and then to expand it by adding rows and columns. \lcont{ The default expansion factor of zero means that Rectangles will simply generate a grid of the size you ask for, and do nothing further. If you set an expansion factor of (say) 0.5, it means that each dimension of the grid will be expanded to half again as big after generation. In other words, the initial grid will be 2/3 the size in each dimension, and will be expanded to its full size without adding any more rectangles. Setting an expansion factor of around 0.5 tends to make the game more difficult, and also (in my experience) rewards a less deductive and more intuitive playing style. If you set it \e{too} high, though, the game simply cannot generate more than a few rectangles to cover the entire grid, and the game becomes trivial. } \dt \e{Ensure unique solution} \dd Normally, Rectangles will make sure that the puzzles it presents have only one solution. Puzzles with ambiguous sections can be more difficult and more subtle, so if you like you can turn off this feature and risk having ambiguous puzzles. Also, finding \e{all} the possible solutions can be an additional challenge for an advanced player. Turning off this option can also speed up puzzle generation. \C{netslide} \i{Netslide} \cfg{winhelp-topic}{games.netslide} This game combines the grid generation of Net (see \k{net}) with the movement of Sixteen (see \k{sixteen}): you have a Net grid, but instead of rotating tiles back into place you have to slide them into place by moving a whole row at a time. As in Sixteen, \I{controls, for Netslide}control is with the mouse or cursor keys. See \k{sixteen-controls}. \I{parameters, for Netslide}The available game parameters have similar meanings to those in Net (see \k{net-params}) and Sixteen (see \k{sixteen-params}). Netslide was contributed to this collection by Richard Boulton. \C{pattern} \i{Pattern} \cfg{winhelp-topic}{games.pattern} You have a grid of squares, which must all be filled in either black or white. Beside each row of the grid are listed the lengths of the runs of black squares on that row; above each column are listed the lengths of the runs of black squares in that column. Your aim is to fill in the entire grid black or white. I first saw this puzzle form around 1995, under the name \q{\i{nonograms}}. I've seen it in various places since then, under different names. Normally, puzzles of this type turn out to be a meaningful picture of something once you've solved them. However, since this version generates the puzzles automatically, they will just look like random groupings of squares. (One user has suggested that this is actually a \e{good} thing, since it prevents you from guessing the colour of squares based on the picture, and forces you to use logic instead.) The advantage, though, is that you never run out of them. \H{pattern-controls} \I{controls, for Pattern}Pattern controls This game is played with the mouse. Left-click in a square to colour it black. Right-click to colour it white. If you make a mistake, you can middle-click, or hold down Shift while clicking with any button, to colour the square in the default grey (meaning \q{undecided}) again. You can click and drag with the left or right mouse button to colour a vertical or horizontal line of squares black or white at a time (respectively). If you click and drag with the middle button, or with Shift held down, you can colour a whole rectangle of squares grey. You can also move around the grid with the cursor keys. Pressing the return key will cycle the current cell through empty, then black, then white, then empty, and the space bar does the same cycle in reverse. Moving the cursor while holding Control will colour the moved-over squares black. Holding Shift will colour the moved-over squares white, and holding both will colour them grey. (All the actions described in \k{common-actions} are also available.) \H{pattern-parameters} \I{parameters, for Pattern}Pattern parameters The only options available from the \q{Custom...} option on the \q{Type} menu are \e{Width} and \e{Height}, which are self-explanatory. \C{solo} \i{Solo} \cfg{winhelp-topic}{games.solo} You have a square grid, which is divided into as many equally sized sub-blocks as the grid has rows. Each square must be filled in with a digit from 1 to the size of the grid, in such a way that \b every row contains only one occurrence of each digit \b every column contains only one occurrence of each digit \b every block contains only one occurrence of each digit. \b (optionally, by default off) each of the square's two main diagonals contains only one occurrence of each digit. You are given some of the numbers as clues; your aim is to place the rest of the numbers correctly. Under the default settings, the sub-blocks are square or rectangular. The default puzzle size is 3\by\.3 (a 9\by\.9 actual grid, divided into nine 3\by\.3 blocks). You can also select sizes with rectangular blocks instead of square ones, such as 2\by\.3 (a 6\by\.6 grid divided into six 3\by\.2 blocks). Alternatively, you can select \q{jigsaw} mode, in which the sub-blocks are arbitrary shapes which differ between individual puzzles. Another available mode is \q{killer}. In this mode, clues are not given in the form of filled-in squares; instead, the grid is divided into \q{cages} by coloured lines, and for each cage the game tells you what the sum of all the digits in that cage should be. Also, no digit may appear more than once within a cage, even if the cage crosses the boundaries of existing regions. If you select a puzzle size which requires more than 9 digits, the additional digits will be letters of the alphabet. For example, if you select 3\by\.4 then the digits which go in your grid will be 1 to 9, plus \cq{a}, \cq{b} and \cq{c}. This cannot be selected for killer puzzles. I first saw this puzzle in \i{Nikoli} \k{nikoli-solo}, although it's also been popularised by various newspapers under the name \q{Sudoku} or \q{Su Doku}. Howard Garns is considered the inventor of the modern form of the puzzle, and it was first published in \e{Dell Pencil Puzzles and Word Games}. A more elaborate treatment of the history of the puzzle can be found on Wikipedia \k{wikipedia-solo}. \B{nikoli-solo} \W{http://www.nikoli.co.jp/en/puzzles/sudoku.html}\cw{http://www.nikoli.co.jp/en/puzzles/sudoku.html} (beware of Flash) \B{wikipedia-solo} \W{http://en.wikipedia.org/wiki/Sudoku}\cw{http://en.wikipedia.org/wiki/Sudoku} \H{solo-controls} \I{controls, for Solo}Solo controls To play Solo, simply click the mouse in any empty square and then type a digit or letter on the keyboard to fill that square. If you make a mistake, click the mouse in the incorrect square and press Space to clear it again (or use the Undo feature). If you \e{right}-click in a square and then type a number, that number will be entered in the square as a \q{pencil mark}. You can have pencil marks for multiple numbers in the same square. Squares containing filled-in numbers cannot also contain pencil marks. The game pays no attention to pencil marks, so exactly what you use them for is up to you: you can use them as reminders that a particular square needs to be re-examined once you know more about a particular number, or you can use them as lists of the possible numbers in a given square, or anything else you feel like. To erase a single pencil mark, right-click in the square and type the same number again. All pencil marks in a square are erased when you left-click and type a number, or when you left-click and press space. Right-clicking and pressing space will also erase pencil marks. Alternatively, use the cursor keys to move the mark around the grid. Pressing the return key toggles the mark (from a normal mark to a pencil mark), and typing a number in is entered in the square in the appropriate way; typing in a 0 or using the space bar will clear a filled square. (All the actions described in \k{common-actions} are also available.) \H{solo-parameters} \I{parameters, for Solo}Solo parameters Solo allows you to configure two separate dimensions of the puzzle grid on the \q{Type} menu: the number of columns, and the number of rows, into which the main grid is divided. (The size of a block is the inverse of this: for example, if you select 2 columns and 3 rows, each actual block will have 3 columns and 2 rows.) If you tick the \q{X} checkbox, Solo will apply the optional extra constraint that the two main diagonals of the grid also contain one of every digit. (This is sometimes known as \q{Sudoku-X} in newspapers.) In this mode, the squares on the two main diagonals will be shaded slightly so that you know it's enabled. If you tick the \q{Jigsaw} checkbox, Solo will generate randomly shaped sub-blocks. In this mode, the actual grid size will be taken to be the product of the numbers entered in the \q{Columns} and \q{Rows} boxes. There is no reason why you have to enter a number greater than 1 in both boxes; Jigsaw mode has no constraint on the grid size, and it can even be a prime number if you feel like it. If you tick the \q{Killer} checkbox, Solo will generate a set of of cages, which are randomly shaped and drawn in an outline of a different colour. Each of these regions contains a smaller clue which shows the digit sum of all the squares in this region. You can also configure the type of symmetry shown in the generated puzzles. More symmetry makes the puzzles look prettier but may also make them easier, since the symmetry constraints can force more clues than necessary to be present. Completely asymmetric puzzles have the freedom to contain as few clues as possible. Finally, you can configure the difficulty of the generated puzzles. Difficulty levels are judged by the complexity of the techniques of deduction required to solve the puzzle: each level requires a mode of reasoning which was not necessary in the previous one. In particular, on difficulty levels \q{Trivial} and \q{Basic} there will be a square you can fill in with a single number at all times, whereas at \q{Intermediate} level and beyond you will have to make partial deductions about the \e{set} of squares a number could be in (or the set of numbers that could be in a square). \#{Advanced, Extreme?} At \q{Unreasonable} level, even this is not enough, and you will eventually have to make a guess, and then backtrack if it turns out to be wrong. Generating difficult puzzles is itself difficult: if you select one of the higher difficulty levels, Solo may have to make many attempts at generating a puzzle before it finds one hard enough for you. Be prepared to wait, especially if you have also configured a large puzzle size. \C{mines} \i{Mines} \cfg{winhelp-topic}{games.mines} You have a grid of covered squares, some of which contain mines, but you don't know which. Your job is to uncover every square which does \e{not} contain a mine. If you uncover a square containing a mine, you lose. If you uncover a square which does not contain a mine, you are told how many mines are contained within the eight surrounding squares. This game needs no introduction; popularised by Windows, it is perhaps the single best known desktop puzzle game in existence. This version of it has an unusual property. By default, it will generate its mine positions in such a way as to ensure that you never need to \e{guess} where a mine is: you will always be able to deduce it somehow. So you will never, as can happen in other versions, get to the last four squares and discover that there are two mines left but you have no way of knowing for sure where they are. \H{mines-controls} \I{controls, for Mines}Mines controls This game is played with the mouse. If you left-click in a covered square, it will be uncovered. If you right-click in a covered square, it will place a flag which indicates that the square is believed to be a mine. Left-clicking in a marked square will not uncover it, for safety. You can right-click again to remove a mark placed in error. If you left-click in an \e{uncovered} square, it will \q{clear around} the square. This means: if the square has exactly as many flags surrounding it as it should have mines, then all the covered squares next to it which are \e{not} flagged will be uncovered. So once you think you know the location of all the mines around a square, you can use this function as a shortcut to avoid having to click on each of the remaining squares one by one. If you uncover a square which has \e{no} mines in the surrounding eight squares, then it is obviously safe to uncover those squares in turn, and so on if any of them also has no surrounding mines. This will be done for you automatically; so sometimes when you uncover a square, a whole new area will open up to be explored. You can also use the cursor keys to move around the minefield. Pressing the return key in a covered square uncovers it, and in an uncovered square will clear around it (so it acts as the left button), pressing the space bar in a covered square will place a flag (similarly, it acts as the right button). All the actions described in \k{common-actions} are also available. Even Undo is available, although you might consider it cheating to use it. If you step on a mine, the program will only reveal the mine in question (unlike most other implementations, which reveal all of them). You can then Undo your fatal move and continue playing if you like. The program will track the number of times you died (and Undo will not reduce that counter), so when you get to the end of the game you know whether or not you did it without making any errors. (If you really want to know the full layout of the grid, which other implementations will show you after you die, you can always use the Solve menu option.) \H{mines-parameters} \I{parameters, for Mines}Mines parameters The options available from the \q{Custom...} option on the \q{Type} menu are: \dt \e{Width}, \e{Height} \dd Size of grid in squares. \dt \e{Mines} \dd Number of mines in the grid. You can enter this as an absolute mine count, or alternatively you can put a \cw{%} sign on the end in which case the game will arrange for that proportion of the squares in the grid to be mines. \lcont{ Beware of setting the mine count too high. At very high densities, the program may spend forever searching for a solvable grid. } \dt \e{Ensure solubility} \dd When this option is enabled (as it is by default), Mines will ensure that the entire grid can be fully deduced starting from the initial open space. If you prefer the riskier grids generated by other implementations, you can switch off this option. \C{samegame} \i{Same Game} \cfg{winhelp-topic}{games.samegame} You have a grid of coloured squares, which you have to clear by highlighting contiguous regions of more than one coloured square; the larger the region you highlight, the more points you get (and the faster you clear the arena). If you clear the grid you win. If you end up with nothing but single squares (i.e., there are no more clickable regions left) you lose. Removing a region causes the rest of the grid to shuffle up: blocks that are suspended will fall down (first), and then empty columns are filled from the right. Same Game was contributed to this collection by James Harvey. \H{samegame-controls} \i{Same Game controls} \IM{Same Game controls} controls, for Same Game \IM{Same Game controls} keys, for Same Game \IM{Same Game controls} shortcuts (keyboard), for Same Game This game can be played with either the keyboard or the mouse. If you left-click an unselected region, it becomes selected (possibly clearing the current selection). If you left-click the selected region, it will be removed (and the rest of the grid shuffled immediately). If you right-click the selected region, it will be unselected. The cursor keys move a cursor around the grid. Pressing the Space or Enter keys while the cursor is in an unselected region selects it; pressing Space or Enter again removes it as above. (All the actions described in \k{common-actions} are also available.) \H{samegame-parameters} \I{parameters, for Same Game}Same Game parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid in squares. \dt \e{No. of colours} \dd Number of different colours used to fill the grid; the more colours, the fewer large regions of colour and thus the more difficult it is to successfully clear the grid. \dt \e{Scoring system} \dd Controls the precise mechanism used for scoring. With the default system, \q{(n-2)^2}, only regions of three squares or more will score any points at all. With the alternative \q{(n-1)^2} system, regions of two squares score a point each, and larger regions score relatively more points. \dt \e{Ensure solubility} \dd If this option is ticked (the default state), generated grids will be guaranteed to have at least one solution. \lcont{ If you turn it off, the game generator will not try to guarantee soluble grids; it will, however, still ensure that there are at least 2 squares of each colour on the grid at the start (since a grid with exactly one square of a given colour is \e{definitely} insoluble). Grids generated with this option disabled may contain more large areas of contiguous colour, leading to opportunities for higher scores; they can also take less time to generate. } \C{flip} \i{Flip} \cfg{winhelp-topic}{games.flip} You have a grid of squares, some light and some dark. Your aim is to light all the squares up at the same time. You can choose any square and flip its state from light to dark or dark to light, but when you do so, other squares around it change state as well. Each square contains a small diagram showing which other squares change when you flip it. \H{flip-controls} \i{Flip controls} \IM{Flip controls} controls, for Flip \IM{Flip controls} keys, for Flip \IM{Flip controls} shortcuts (keyboard), for Flip This game can be played with either the keyboard or the mouse. Left-click in a square to flip it and its associated squares, or use the cursor keys to choose a square and the space bar or Enter key to flip. If you use the \q{Solve} function on this game, it will mark some of the squares in red. If you click once in every square with a red mark, the game should be solved. (If you click in a square \e{without} a red mark, a red mark will appear in it to indicate that you will need to reverse that operation to reach the solution.) (All the actions described in \k{common-actions} are also available.) \H{flip-parameters} \I{parameters, for flip}Flip parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid in squares. \dt \e{Shape type} \dd This control determines the shape of the region which is flipped by clicking in any given square. The default setting, \q{Crosses}, causes every square to flip itself and its four immediate neighbours (or three or two if it's at an edge or corner). The other setting, \q{Random}, causes a random shape to be chosen for every square, so the game is different every time. \C{guess} \i{Guess} \cfg{winhelp-topic}{games.guess} You have a set of coloured pegs, and have to reproduce a predetermined sequence of them (chosen by the computer) within a certain number of guesses. Each guess gets marked with the number of correctly-coloured pegs in the correct places (in black), and also the number of correctly-coloured pegs in the wrong places (in white). This game is also known (and marketed, by Hasbro, mainly) as a board game \q{\i{Mastermind}}, with 6 colours, 4 pegs per row, and 10 guesses. However, this version allows custom settings of number of colours (up to 10), number of pegs per row, and number of guesses. Guess was contributed to this collection by James Harvey. \H{guess-controls} \i{Guess controls} \IM{Guess controls} controls, for Guess \IM{Guess controls} keys, for Guess \IM{Guess controls} shortcuts (keyboard), for Guess This game can be played with either the keyboard or the mouse. With the mouse, drag a coloured peg from the tray on the left-hand side to its required position in the current guess; pegs may also be dragged from current and past guesses to copy them elsewhere. To remove a peg, drag it off its current position to somewhere invalid. Right-clicking in the current guess adds a \q{hold} marker; pegs that have hold markers will be automatically added to the next guess after marking. Alternatively, with the keyboard, the up and down cursor keys can be used to select a peg colour, the left and right keys to select a peg position, and the space bar or Enter key to place a peg of the selected colour in the chosen position. \q{D} or Backspace removes a peg, and Space adds a hold marker. Pressing \q{h} or \q{?} will fill the current guess with a suggested guess. Using this is not recommended for 10 or more pegs as it is slow. When the guess is complete, the smaller feedback pegs will be highlighted; clicking on these (or moving the peg cursor to them with the arrow keys and pressing the space bar or Enter key) will mark the current guess, copy any held pegs to the next guess, and move the \q{current guess} marker. If you correctly position all the pegs the solution will be displayed below; if you run out of guesses (or select \q{Solve...}) the solution will also be revealed. (All the actions described in \k{common-actions} are also available.) \H{guess-parameters} \I{parameters, for Guess}Guess parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. The default game matches the parameters for the board game \q{Mastermind}. \dt \e{Colours} \dd Number of colours the solution is chosen from; from 2 to 10 (more is harder). \dt \e{Pegs per guess} \dd Number of pegs per guess (more is harder). \dt \e{Guesses} \dd Number of guesses you have to find the solution in (fewer is harder). \dt \e{Allow blanks} \dd Allows blank pegs to be given as part of a guess (makes it easier, because you know that those will never be counted as part of the solution). This is turned off by default. \lcont{ Note that this doesn't allow blank pegs in the solution; if you really wanted that, use one extra colour. } \dt \e{Allow duplicates} \dd Allows the solution (and the guesses) to contain colours more than once; this increases the search space (making things harder), and is turned on by default. \C{pegs} \i{Pegs} \cfg{winhelp-topic}{games.pegs} A number of pegs are placed in holes on a board. You can remove a peg by jumping an adjacent peg over it (horizontally or vertically) to a vacant hole on the other side. Your aim is to remove all but one of the pegs initially present. This game, best known as \I{Solitaire, Peg}\q{Peg Solitaire}, is possibly one of the oldest puzzle games still commonly known. \H{pegs-controls} \i{Pegs controls} \IM{Pegs controls} controls, for Pegs To move a peg, drag it with the mouse from its current position to its final position. If the final position is exactly two holes away from the initial position, is currently unoccupied by a peg, and there is a peg in the intervening square, the move will be permitted and the intervening peg will be removed. Vacant spaces which you can move a peg into are marked with holes. A space with no peg and no hole is not available for moving at all: it is an obstacle which you must work around. You can also use the cursor keys to move a position indicator around the board. Pressing the return key while over a peg, followed by a cursor key, will jump the peg in that direction (if that is a legal move). (All the actions described in \k{common-actions} are also available.) \H{pegs-parameters} \I{parameters, for Pegs}Pegs parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid in holes. \dt \e{Board type} \dd Controls whether you are given a board of a standard shape or a randomly generated shape. The two standard shapes currently supported are \q{Cross} and \q{Octagon} (also commonly known as the English and European traditional board layouts respectively). Selecting \q{Random} will give you a different board shape every time (but always one that is known to have a solution). \C{dominosa} \i{Dominosa} \cfg{winhelp-topic}{games.dominosa} A normal set of dominoes \dash that is, one instance of every (unordered) pair of numbers from 0 to 6 \dash has been arranged irregularly into a rectangle; then the number in each square has been written down and the dominoes themselves removed. Your task is to reconstruct the pattern by arranging the set of dominoes to match the provided array of numbers. This puzzle is widely credited to O. S. Adler, and takes part of its name from those initials. \H{dominosa-controls} \i{Dominosa controls} \IM{Dominosa controls} controls, for Dominosa Left-clicking between any two adjacent numbers places a domino covering them, or removes one if it is already present. Trying to place a domino which overlaps existing dominoes will remove the ones it overlaps. Right-clicking between two adjacent numbers draws a line between them, which you can use to remind yourself that you know those two numbers are \e{not} covered by a single domino. Right-clicking again removes the line. You can also use the cursor keys to move a cursor around the grid. When the cursor is half way between two adjacent numbers, pressing the return key will place a domino covering those numbers, or pressing the space bar will lay a line between the two squares. Repeating either action removes the domino or line. Pressing a number key will highlight all occurrences of that number. Pressing that number again will clear the highlighting. Up to two different numbers can be highlighted at any given time. (All the actions described in \k{common-actions} are also available.) \H{dominosa-parameters} \I{parameters, for Dominosa}Dominosa parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Maximum number on dominoes} \dd Controls the size of the puzzle, by controlling the size of the set of dominoes used to make it. Dominoes with numbers going up to N will give rise to an (N+2) \by (N+1) rectangle; so, in particular, the default value of 6 gives an 8\by\.7 grid. \dt \e{Ensure unique solution} \dd Normally, Dominosa will make sure that the puzzles it presents have only one solution. Puzzles with ambiguous sections can be more difficult and sometimes more subtle, so if you like you can turn off this feature. Also, finding \e{all} the possible solutions can be an additional challenge for an advanced player. Turning off this option can also speed up puzzle generation. \C{untangle} \i{Untangle} \cfg{winhelp-topic}{games.untangle} You are given a number of points, some of which have lines drawn between them. You can move the points about arbitrarily; your aim is to position the points so that no line crosses another. I originally saw this in the form of a Flash game called \i{Planarity} \k{Planarity}, written by John Tantalo. \B{Planarity} \W{http://planarity.net}\cw{http://planarity.net} \H{untangle-controls} \i{Untangle controls} \IM{Untangle controls} controls, for Untangle To move a point, click on it with the left mouse button and drag it into a new position. (All the actions described in \k{common-actions} are also available.) \H{untangle-parameters} \I{parameters, for Untangle}Untangle parameters There is only one parameter available from the \q{Custom...} option on the \q{Type} menu: \dt \e{Number of points} \dd Controls the size of the puzzle, by specifying the number of points in the generated graph. \C{blackbox} \i{Black Box} \cfg{winhelp-topic}{games.blackbox} A number of balls are hidden in a rectangular arena. You have to deduce the positions of the balls by firing lasers positioned at the edges of the arena and observing how their beams are deflected. Beams will travel straight from their origin until they hit the opposite side of the arena (at which point they emerge), unless affected by balls in one of the following ways: \b A beam that hits a ball head-on is absorbed and will never re-emerge. This includes beams that meet a ball on the first rank of the arena. \b A beam with a ball in its front-left square and no ball ahead of it gets deflected 90 degrees to the right. \b A beam with a ball in its front-right square and no ball ahead of it gets similarly deflected to the left. \b A beam that would re-emerge from its entry location is considered to be \q{reflected}. \b A beam which would get deflected before entering the arena by a ball to the front-left or front-right of its entry point is also considered to be \q{reflected}. Beams that are reflected appear as a \q{R}; beams that hit balls head-on appear as \q{H}. Otherwise, a number appears at the firing point and the location where the beam emerges (this number is unique to that shot). You can place guesses as to the location of the balls, based on the entry and exit patterns of the beams; once you have placed enough balls a button appears enabling you to have your guesses checked. Here is a diagram showing how the positions of balls can create each of the beam behaviours shown above: \c 1RHR---- \c |..O.O...| \c 2........3 \c |........| \c |........| \c 3........| \c |......O.| \c H........| \c |.....O..| \c 12-RR--- As shown, it is possible for a beam to receive multiple reflections before re-emerging (see turn 3). Similarly, a beam may be reflected (possibly more than once) before receiving a hit (the \q{H} on the left side of the example). Note that any layout with more than 4 balls may have a non-unique solution. The following diagram illustrates this; if you know the board contains 5 balls, it is impossible to determine where the fifth ball is (possible positions marked with an \cw{x}): \c -------- \c |........| \c |........| \c |..O..O..| \c |...xx...| \c |...xx...| \c |..O..O..| \c |........| \c |........| \c -------- For this reason, when you have your guesses checked, the game will check that your solution \e{produces the same results} as the computer's, rather than that your solution is identical to the computer's. So in the above example, you could put the fifth ball at \e{any} of the locations marked with an \cw{x}, and you would still win. Black Box was contributed to this collection by James Harvey. \H{blackbox-controls} \i{Black Box controls} \IM{Black Box controls} controls, for Black Box \IM{Black Box controls} keys, for Black Box \IM{Black Box controls} shortcuts (keyboard), for Black Box To fire a laser beam, left-click in a square around the edge of the arena. The results will be displayed immediately. Clicking or holding the left button on one of these squares will highlight the current go (or a previous go) to confirm the exit point for that laser, if applicable. To guess the location of a ball, left-click within the arena and a black circle will appear marking the guess; click again to remove the guessed ball. Locations in the arena may be locked against modification by right-clicking; whole rows and columns may be similarly locked by right-clicking in the laser square above/below that column, or to the left/right of that row. The cursor keys may also be used to move around the grid. Pressing the Enter key will fire a laser or add a new ball-location guess, and pressing Space will lock a cell, row, or column. When an appropriate number of balls have been guessed, a button will appear at the top-left corner of the grid; clicking that (with mouse or cursor) will check your guesses. If you click the \q{check} button and your guesses are not correct, the game will show you the minimum information necessary to demonstrate this to you, so you can try again. If your ball positions are not consistent with the beam paths you already know about, one beam path will be circled to indicate that it proves you wrong. If your positions match all the existing beam paths but are still wrong, one new beam path will be revealed (written in red) which is not consistent with your current guesses. If you decide to give up completely, you can select Solve to reveal the actual ball positions. At this point, correctly-placed balls will be displayed as filled black circles, incorrectly-placed balls as filled black circles with red crosses, and missing balls as filled red circles. In addition, a red circle marks any laser you had already fired which is not consistent with your ball layout (just as when you press the \q{check} button), and red text marks any laser you \e{could} have fired in order to distinguish your ball layout from the correct one. (All the actions described in \k{common-actions} are also available.) \H{blackbox-parameters} \I{parameters, for Black Box}Black Box parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid in squares. There are 2 \by \e{Width} \by \e{Height} lasers per grid, two per row and two per column. \dt \e{No. of balls} \dd Number of balls to place in the grid. This can be a single number, or a range (separated with a hyphen, like \q{2-6}), and determines the number of balls to place on the grid. The \q{reveal} button is only enabled if you have guessed an appropriate number of balls; a guess using a different number to the original solution is still acceptable, if all the beam inputs and outputs match. \C{slant} \i{Slant} \cfg{winhelp-topic}{games.slant} You have a grid of squares. Your aim is to draw a diagonal line through each square, and choose which way each line slants so that the following conditions are met: \b The diagonal lines never form a loop. \b Any point with a circled number has precisely that many lines meeting at it. (Thus, a 4 is the centre of a cross shape, whereas a zero is the centre of a diamond shape \dash or rather, a partial diamond shape, because a zero can never appear in the middle of the grid because that would immediately cause a loop.) Credit for this puzzle goes to \i{Nikoli} \k{nikoli-slant}. \B{nikoli-slant} \W{http://www.nikoli.co.jp/ja/puzzles/gokigen_naname}\cw{http://www.nikoli.co.jp/ja/puzzles/gokigen_naname} (in Japanese) \H{slant-controls} \i{Slant controls} \IM{Slant controls} controls, for Slant Left-clicking in a blank square will place a \cw{\\} in it (a line leaning to the left, i.e. running from the top left of the square to the bottom right). Right-clicking in a blank square will place a \cw{/} in it (leaning to the right, running from top right to bottom left). Continuing to click either button will cycle between the three possible square contents. Thus, if you left-click repeatedly in a blank square it will change from blank to \cw{\\} to \cw{/} back to blank, and if you right-click repeatedly the square will change from blank to \cw{/} to \cw{\\} back to blank. (Therefore, you can play the game entirely with one button if you need to.) You can also use the cursor keys to move around the grid. Pressing the return or space keys will place a \cw{\\} or a \cw{/}, respectively, and will then cycle them as above. You can also press \cw{/} or \cw{\\} to place a \cw{/} or \cw{\\}, respectively, independent of what is already in the cursor square. Backspace removes any line from the cursor square. (All the actions described in \k{common-actions} are also available.) \H{slant-parameters} \I{parameters, for Slant}Slant parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid in squares. \dt \e{Difficulty} \dd Controls the difficulty of the generated puzzle. At Hard level, you are required to do deductions based on knowledge of \e{relationships} between squares rather than always being able to deduce the exact contents of one square at a time. (For example, you might know that two squares slant in the same direction, even if you don't yet know what that direction is, and this might enable you to deduce something about still other squares.) Even at Hard level, guesswork and backtracking should never be necessary. \C{lightup} \i{Light Up} \cfg{winhelp-topic}{games.lightup} You have a grid of squares. Some are filled in black; some of the black squares are numbered. Your aim is to \q{light up} all the empty squares by placing light bulbs in some of them. Each light bulb illuminates the square it is on, plus all squares in line with it horizontally or vertically unless a black square is blocking the way. To win the game, you must satisfy the following conditions: \b All non-black squares are lit. \b No light is lit by another light. \b All numbered black squares have exactly that number of lights adjacent to them (in the four squares above, below, and to the side). Non-numbered black squares may have any number of lights adjacent to them. Credit for this puzzle goes to \i{Nikoli} \k{nikoli-lightup}. Light Up was contributed to this collection by James Harvey. \B{nikoli-lightup} \W{http://www.nikoli.co.jp/en/puzzles/akari.html}\cw{http://www.nikoli.co.jp/en/puzzles/akari.html} (beware of Flash) \H{lightup-controls} \i{Light Up controls} \IM{Light Up controls} controls, for Light Up Left-clicking in a non-black square will toggle the presence of a light in that square. Right-clicking in a non-black square toggles a mark there to aid solving; it can be used to highlight squares that cannot be lit, for example. You may not place a light in a marked square, nor place a mark in a lit square. The game will highlight obvious errors in red. Lights lit by other lights are highlighted in this way, as are numbered squares which do not (or cannot) have the right number of lights next to them. Thus, the grid is solved when all non-black squares have yellow highlights and there are no red lights. (All the actions described in \k{common-actions} are also available.) \H{lightup-parameters} \I{parameters, for Light Up}Light Up parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid in squares. \dt \e{%age of black squares} \dd Rough percentage of black squares in the grid. \lcont{ This is a hint rather than an instruction. If the grid generator is unable to generate a puzzle to this precise specification, it will increase the proportion of black squares until it can. } \dt \e{Symmetry} \dd Allows you to specify the required symmetry of the black squares in the grid. (This does not affect the difficulty of the puzzles noticeably.) \dt \e{Difficulty} \dd \q{Easy} means that the puzzles should be soluble without backtracking or guessing, \q{Hard} means that some guesses will probably be necessary. \C{map} \i{Map} \cfg{winhelp-topic}{games.map} You are given a map consisting of a number of regions. Your task is to colour each region with one of four colours, in such a way that no two regions sharing a boundary have the same colour. You are provided with some regions already coloured, sufficient to make the remainder of the solution unique. Only regions which share a length of border are required to be different colours. Two regions which meet at only one \e{point} (i.e. are diagonally separated) may be the same colour. I believe this puzzle is original; I've never seen an implementation of it anywhere else. The concept of a \i{four-colouring} puzzle was suggested by Owen Dunn; credit must also go to Nikoli and to Verity Allan for inspiring the train of thought that led to me realising Owen's suggestion was a viable puzzle. Thanks also to Gareth Taylor for many detailed suggestions. \H{map-controls} \i{Map controls} \IM{Map controls} controls, for Map To colour a region, click the left mouse button on an existing region of the desired colour and drag that colour into the new region. (The program will always ensure the starting puzzle has at least one region of each colour, so that this is always possible!) If you need to clear a region, you can drag from an empty region, or from the puzzle boundary if there are no empty regions left. Dragging a colour using the \e{right} mouse button will stipple the region in that colour, which you can use as a note to yourself that you think the region \e{might} be that colour. A region can contain stipples in multiple colours at once. (This is often useful at the harder difficulty levels.) You can also use the cursor keys to move around the map: the colour of the cursor indicates the position of the colour you would drag (which is not obvious if you're on a region's boundary, since it depends on the direction from which you approached the boundary). Pressing the return key starts a drag of that colour, as above, which you control with the cursor keys; pressing the return key again finishes the drag. The space bar can be used similarly to create a stippled region. Double-pressing the return key (without moving the cursor) will clear the region, as a drag from an empty region does: this is useful with the cursor mode if you have filled the entire map in but need to correct the layout. If you press L during play, the game will toggle display of a number in each region of the map. This is useful if you want to discuss a particular puzzle instance with a friend \dash having an unambiguous name for each region is much easier than trying to refer to them all by names such as \q{the one down and right of the brown one on the top border}. (All the actions described in \k{common-actions} are also available.) \H{map-parameters} \I{parameters, for Map}Map parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid in squares. \dt \e{Regions} \dd Number of regions in the generated map. \dt \e{Difficulty} \dd In \q{Easy} mode, there should always be at least one region whose colour can be determined trivially. In \q{Normal} and \q{Hard} modes, you will have to use increasingly complex logic to deduce the colour of some regions. However, it will always be possible without having to guess or backtrack. \lcont{ In \q{Unreasonable} mode, the program will feel free to generate puzzles which are as hard as it can possibly make them: the only constraint is that they should still have a unique solution. Solving Unreasonable puzzles may require guessing and backtracking. } \C{loopy} \i{Loopy} \cfg{winhelp-topic}{games.loopy} You are given a grid of dots, marked with yellow lines to indicate which dots you are allowed to connect directly together. Your aim is to use some subset of those yellow lines to draw a single unbroken loop from dot to dot within the grid. Some of the spaces between the lines contain numbers. These numbers indicate how many of the lines around that space form part of the loop. The loop you draw must correctly satisfy all of these clues to be considered a correct solution. In the default mode, the dots are arranged in a grid of squares; however, you can also play on triangular or hexagonal grids, or even more exotic ones. Credit for the basic puzzle idea goes to \i{Nikoli} \k{nikoli-loopy}. Loopy was originally contributed to this collection by Mike Pinna, and subsequently enhanced to handle various types of non-square grid by Lambros Lambrou. \B{nikoli-loopy} \W{http://www.nikoli.co.jp/en/puzzles/slitherlink.html}\cw{http://www.nikoli.co.jp/en/puzzles/slitherlink.html} (beware of Flash) \H{loopy-controls} \i{Loopy controls} \IM{Loopy controls} controls, for Loopy Click the left mouse button on a yellow line to turn it black, indicating that you think it is part of the loop. Click again to turn the line yellow again (meaning you aren't sure yet). If you are sure that a particular line segment is \e{not} part of the loop, you can click the right mouse button to remove it completely. Again, clicking a second time will turn the line back to yellow. (All the actions described in \k{common-actions} are also available.) \H{loopy-parameters} \I{parameters, for Loopy}Loopy parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid, measured in number of regions across and down. For square grids, it's clear how this is counted; for other types of grid you may have to think a bit to see how the dimensions are measured. \dt \e{Grid type} \dd Allows you to choose between a selection of types of tiling. Some have all the faces the same but may have multiple different types of vertex (e.g. the \e{Cairo} or \e{Kites} mode); others have all the vertices the same but may have different types of face (e.g. the \e{Great Hexagonal}). The square, triangular and honeycomb grids are fully regular, and have all their vertices \e{and} faces the same; this makes them the least confusing to play. \dt \e{Difficulty} \dd Controls the difficulty of the generated puzzle. \#{FIXME: what distinguishes Easy, Medium, and Hard? In particular, when are backtracking/guesswork required, if ever?} \C{inertia} \i{Inertia} \cfg{winhelp-topic}{games.inertia} You are a small green ball sitting in a grid full of obstacles. Your aim is to collect all the gems without running into any mines. You can move the ball in any orthogonal \e{or diagonal} direction. Once the ball starts moving, it will continue until something stops it. A wall directly in its path will stop it (but if it is moving diagonally, it will move through a diagonal gap between two other walls without stopping). Also, some of the squares are \q{stops}; when the ball moves on to a stop, it will stop moving no matter what direction it was going in. Gems do \e{not} stop the ball; it picks them up and keeps on going. Running into a mine is fatal. Even if you picked up the last gem in the same move which then hit a mine, the game will count you as dead rather than victorious. This game was originally implemented for Windows by Ben Olmstead \k{bem}, who was kind enough to release his source code on request so that it could be re-implemented for this collection. \B{bem} \W{http://xn13.com/}\cw{http://xn13.com/} \H{inertia-controls} \i{Inertia controls} \IM{Inertia controls} controls, for Inertia \IM{Inertia controls} keys, for Inertia \IM{Inertia controls} shortcuts (keyboard), for Inertia You can move the ball in any of the eight directions using the numeric keypad. Alternatively, if you click the left mouse button on the grid, the ball will begin a move in the general direction of where you clicked. If you use the \q{Solve} function on this game, the program will compute a path through the grid which collects all the remaining gems and returns to the current position. A hint arrow will appear on the ball indicating the direction in which you should move to begin on this path. If you then move in that direction, the arrow will update to indicate the next direction on the path. You can also press Space to automatically move in the direction of the hint arrow. If you move in a different direction from the one shown by the arrow, arrows will be shown only if the puzzle is still solvable. All the actions described in \k{common-actions} are also available. In particular, if you do run into a mine and die, you can use the Undo function and resume playing from before the fatal move. The game will keep track of the number of times you have done this. \H{inertia-parameters} \I{parameters, for Inertia}Inertia parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid in squares. \C{tents} \i{Tents} \cfg{winhelp-topic}{games.tents} You have a grid of squares, some of which contain trees. Your aim is to place tents in some of the remaining squares, in such a way that the following conditions are met: \b There are exactly as many tents as trees. \b The tents and trees can be matched up in such a way that each tent is directly adjacent (horizontally or vertically, but not diagonally) to its own tree. However, a tent may be adjacent to other trees as well as its own. \b No two tents are adjacent horizontally, vertically \e{or diagonally}. \b The number of tents in each row, and in each column, matches the numbers given round the sides of the grid. This puzzle can be found in several places on the Internet, and was brought to my attention by e-mail. I don't know who I should credit for inventing it. \H{tents-controls} \i{Tents controls} \IM{Tents controls} controls, for Tents Left-clicking in a blank square will place a tent in it. Right-clicking in a blank square will colour it green, indicating that you are sure it \e{isn't} a tent. Clicking either button in an occupied square will clear it. If you \e{drag} with the right button along a row or column, every blank square in the region you cover will be turned green, and no other squares will be affected. (This is useful for clearing the remainder of a row once you have placed all its tents.) You can also use the cursor keys to move around the grid. Pressing the return key over an empty square will place a tent, and pressing the space bar over an empty square will colour it green; either key will clear an occupied square. Holding Shift and pressing the cursor keys will colour empty squares green. Holding Control and pressing the cursor keys will colour green both empty squares and squares with tents. (All the actions described in \k{common-actions} are also available.) \H{tents-parameters} \I{parameters, for Tents}Tents parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid in squares. \dt \e{Difficulty} \dd Controls the difficulty of the generated puzzle. More difficult puzzles require more complex deductions, but at present none of the available difficulty levels requires guesswork or backtracking. \C{bridges} \i{Bridges} \cfg{winhelp-topic}{games.bridges} You have a set of islands distributed across the playing area. Each island contains a number. Your aim is to connect the islands together with bridges, in such a way that: \b Bridges run horizontally or vertically. \b The number of bridges terminating at any island is equal to the number written in that island. \b Two bridges may run in parallel between the same two islands, but no more than two may do so. \b No bridge crosses another bridge. \b All the islands are connected together. There are some configurable alternative modes, which involve changing the parallel-bridge limit to something other than 2, and introducing the additional constraint that no sequence of bridges may form a loop from one island back to the same island. The rules stated above are the default ones. Credit for this puzzle goes to \i{Nikoli} \k{nikoli-bridges}. Bridges was contributed to this collection by James Harvey. \B{nikoli-bridges} \W{http://www.nikoli.co.jp/en/puzzles/hashiwokakero.html}\cw{http://www.nikoli.co.jp/en/puzzles/hashiwokakero.html} (beware of Flash) \H{bridges-controls} \i{Bridges controls} \IM{Bridges controls} controls, for Bridges To place a bridge between two islands, click the mouse down on one island and drag it towards the other. You do not need to drag all the way to the other island; you only need to move the mouse far enough for the intended bridge direction to be unambiguous. (So you can keep the mouse near the starting island and conveniently throw bridges out from it in many directions.) Doing this again when a bridge is already present will add another parallel bridge. If there are already as many bridges between the two islands as permitted by the current game rules (i.e. two by default), the same dragging action will remove all of them. If you want to remind yourself that two islands definitely \e{do not} have a bridge between them, you can right-drag between them in the same way to draw a \q{non-bridge} marker. If you think you have finished with an island (i.e. you have placed all its bridges and are confident that they are in the right places), you can mark the island as finished by left-clicking on it. This will highlight it and all the bridges connected to it, and you will be prevented from accidentally modifying any of those bridges in future. Left-clicking again on a highlighted island will unmark it and restore your ability to modify it. You can also use the cursor keys to move around the grid: if possible the cursor will always move orthogonally, otherwise it will move towards the nearest island to the indicated direction. Holding Control and pressing a cursor key will lay a bridge in that direction (if available); Shift and a cursor key will lay a \q{non-bridge} marker. Pressing the return key followed by a cursor key will also lay a bridge in that direction. You can mark an island as finished by pressing the space bar or by pressing the return key twice. By pressing a number key, you can jump to the nearest island with that number. Letters \q{a}, ..., \q{f} count as 10, ..., 15 and \q{0} as 16. Violations of the puzzle rules will be marked in red: \b An island with too many bridges will be highlighted in red. \b An island with too few bridges will be highlighted in red if it is definitely an error (as opposed to merely not being finished yet): if adding enough bridges would involve having to cross another bridge or remove a non-bridge marker, or if the island has been highlighted as complete. \b A group of islands and bridges may be highlighted in red if it is a closed subset of the puzzle with no way to connect it to the rest of the islands. For example, if you directly connect two 1s together with a bridge and they are not the only two islands on the grid, they will light up red to indicate that such a group cannot be contained in any valid solution. \b If you have selected the (non-default) option to disallow loops in the solution, a group of bridges which forms a loop will be highlighted. (All the actions described in \k{common-actions} are also available.) \H{bridges-parameters} \I{parameters, for Bridges}Bridges parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid in squares. \dt \e{Difficulty} \dd Difficulty level of puzzle. \dt \e{Allow loops} \dd This is set by default. If cleared, puzzles will be generated in such a way that they are always soluble without creating a loop, and solutions which do involve a loop will be disallowed. \dt \e{Max. bridges per direction} \dd Maximum number of bridges in any particular direction. The default is 2, but you can change it to 1, 3 or 4. In general, fewer is easier. \dt \e{%age of island squares} \dd Gives a rough percentage of islands the generator will try and lay before finishing the puzzle. Certain layouts will not manage to lay enough islands; this is an upper bound. \dt \e{Expansion factor (%age)} \dd The grid generator works by picking an existing island at random (after first creating an initial island somewhere). It then decides on a direction (at random), and then works out how far it could extend before creating another island. This parameter determines how likely it is to extend as far as it can, rather than choosing somewhere closer. \lcont{ High expansion factors usually mean easier puzzles with fewer possible islands; low expansion factors can create lots of tightly-packed islands. } \C{unequal} \i{Unequal} \cfg{winhelp-topic}{games.unequal} You have a square grid; each square may contain a digit from 1 to the size of the grid, and some squares have clue signs between them. Your aim is to fully populate the grid with numbers such that: \b Each row contains only one occurrence of each digit \b Each column contains only one occurrence of each digit \b All the clue signs are satisfied. There are two modes for this game, \q{Unequal} and \q{Adjacent}. In \q{Unequal} mode, the clue signs are greater-than symbols indicating one square's value is greater than its neighbour's. In this mode not all clues may be visible, particularly at higher difficulty levels. In \q{Adjacent} mode, the clue signs are bars indicating one square's value is numerically adjacent (i.e. one higher or one lower) than its neighbour. In this mode all clues are always visible: absence of a bar thus means that a square's value is definitely not numerically adjacent to that neighbour's. In \q{Trivial} difficulty level (available via the \q{Custom} game type selector), there are no greater-than signs in \q{Unequal} mode; the puzzle is to solve the \i{Latin square} only. At the time of writing, the \q{Unequal} mode of this puzzle is appearing in the Guardian weekly under the name \q{\i{Futoshiki}}. Unequal was contributed to this collection by James Harvey. \H{unequal-controls} \i{Unequal controls} \IM{Unequal controls} controls, for Unequal Unequal shares much of its control system with Solo. To play Unequal, simply click the mouse in any empty square and then type a digit or letter on the keyboard to fill that square. If you make a mistake, click the mouse in the incorrect square and press Space to clear it again (or use the Undo feature). If you \e{right}-click in a square and then type a number, that number will be entered in the square as a \q{pencil mark}. You can have pencil marks for multiple numbers in the same square. Squares containing filled-in numbers cannot also contain pencil marks. The game pays no attention to pencil marks, so exactly what you use them for is up to you: you can use them as reminders that a particular square needs to be re-examined once you know more about a particular number, or you can use them as lists of the possible numbers in a given square, or anything else you feel like. To erase a single pencil mark, right-click in the square and type the same number again. All pencil marks in a square are erased when you left-click and type a number, or when you left-click and press space. Right-clicking and pressing space will also erase pencil marks. As for Solo, the cursor keys can be used in conjunction with the digit keys to set numbers or pencil marks. You can also use the \q{M} key to auto-fill every numeric hint, ready for removal as required, or the \q{H} key to do the same but also to remove all obvious hints. Alternatively, use the cursor keys to move the mark around the grid. Pressing the return key toggles the mark (from a normal mark to a pencil mark), and typing a number in is entered in the square in the appropriate way; typing in a 0 or using the space bar will clear a filled square. Left-clicking a clue will mark it as done (grey it out), or unmark it if it is already marked. Holding Control or Shift and pressing an arrow key likewise marks any clue adjacent to the cursor in the given direction. (All the actions described in \k{common-actions} are also available.) \H{unequal-parameters} \I{parameters, for Unequal}Unequal parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Mode} \dd Mode of the puzzle (\q{Unequal} or \q{Adjacent}) \dt \e{Size (s*s)} \dd Size of grid. \dt \e{Difficulty} \dd Controls the difficulty of the generated puzzle. At Trivial level, there are no greater-than signs; the puzzle is to solve the Latin square only. At Recursive level (only available via the \q{Custom} game type selector) backtracking will be required, but the solution should still be unique. The levels in between require increasingly complex reasoning to avoid having to backtrack. \C{galaxies} \i{Galaxies} \cfg{winhelp-topic}{games.galaxies} You have a rectangular grid containing a number of dots. Your aim is to draw edges along the grid lines which divide the rectangle into regions in such a way that every region is 180\u00b0{-degree} rotationally symmetric, and contains exactly one dot which is located at its centre of symmetry. This puzzle was invented by \i{Nikoli} \k{nikoli-galaxies}, under the name \q{Tentai Show}; its name is commonly translated into English as \q{Spiral Galaxies}. Galaxies was contributed to this collection by James Harvey. \B{nikoli-galaxies} \W{http://www.nikoli.co.jp/en/puzzles/astronomical_show.html}\cw{http://www.nikoli.co.jp/en/puzzles/astronomical_show.html} \H{galaxies-controls} \i{Galaxies controls} \IM{Galaxies controls} controls, for Galaxies Left-click on any grid line to draw an edge if there isn't one already, or to remove one if there is. When you create a valid region (one which is closed, contains exactly one dot, is 180\u00b0{-degree} symmetric about that dot, and contains no extraneous edges inside it) it will be highlighted automatically; so your aim is to have the whole grid highlighted in that way. During solving, you might know that a particular grid square belongs to a specific dot, but not be sure of where the edges go and which other squares are connected to the dot. In order to mark this so you don't forget, you can right-click on the dot and drag, which will create an arrow marker pointing at the dot. Drop that in a square of your choice and it will remind you which dot it's associated with. You can also right-click on existing arrows to pick them up and move them, or destroy them by dropping them off the edge of the grid. (Also, if you're not sure which dot an arrow is pointing at, you can pick it up and move it around to make it clearer. It will swivel constantly as you drag it, to stay pointed at its parent dot.) You can also use the cursor keys to move around the grid squares and lines. Pressing the return key when over a grid line will draw or clear its edge, as above. Pressing the return key when over a dot will pick up an arrow, to be dropped the next time the return key is pressed; this can also be used to move existing arrows around, removing them by dropping them on a dot or another arrow. (All the actions described in \k{common-actions} are also available.) \H{galaxies-parameters} \I{parameters, for Galaxies}Galaxies parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid in squares. \dt \e{Difficulty} \dd Controls the difficulty of the generated puzzle. More difficult puzzles require more complex deductions, and the \q{Unreasonable} difficulty level may require backtracking. \C{filling} \i{Filling} \cfg{winhelp-topic}{games.filling} You have a grid of squares, some of which contain digits, and the rest of which are empty. Your job is to fill in digits in the empty squares, in such a way that each connected region of squares all containing the same digit has an area equal to that digit. (\q{Connected region}, for the purposes of this game, does not count diagonally separated squares as adjacent.) For example, it follows that no square can contain a zero, and that two adjacent squares can not both contain a one. No region has an area greater than 9 (because then its area would not be a single digit). Credit for this puzzle goes to \i{Nikoli} \k{nikoli-fillomino}. Filling was contributed to this collection by Jonas K\u00F6{oe}lker. \B{nikoli-fillomino} \W{http://www.nikoli.co.jp/en/puzzles/fillomino.html}\cw{http://www.nikoli.co.jp/en/puzzles/fillomino.html} \H{filling-controls} \I{controls, for Filling}Filling controls To play Filling, simply click the mouse in any empty square and then type a digit on the keyboard to fill that square. By dragging the mouse, you can select multiple squares to fill with a single keypress. If you make a mistake, click the mouse in the incorrect square and press 0, Space, Backspace or Enter to clear it again (or use the Undo feature). You can also move around the grid with the cursor keys; typing a digit will fill the square containing the cursor with that number; typing 0 will clear it. You can also select multiple squares for numbering or clearing with the return and arrow keys, before typing a digit to fill or clear the highlighted squares (as above). The space bar adds and removes single squares to and from the selection. Backspace and escape remove all squares from the selection. (All the actions described in \k{common-actions} are also available.) \H{filling-parameters} \I{parameters, for Filling}Filling parameters Filling allows you to configure the number of rows and columns of the grid, through the \q{Type} menu. \C{keen} \i{Keen} \cfg{winhelp-topic}{games.keen} You have a square grid; each square may contain a digit from 1 to the size of the grid. The grid is divided into blocks of varying shape and size, with arithmetic clues written in them. Your aim is to fully populate the grid with digits such that: \b Each row contains only one occurrence of each digit \b Each column contains only one occurrence of each digit \b The digits in each block can be combined to form the number stated in the clue, using the arithmetic operation given in the clue. That is: \lcont{ \b An addition clue means that the sum of the digits in the block must be the given number. For example, \q{15+} means the contents of the block adds up to fifteen. \b A multiplication clue (e.g. \q{60\times}), similarly, means that the product of the digits in the block must be the given number. \b A subtraction clue will always be written in a block of size two, and it means that one of the digits in the block is greater than the other by the given amount. For example, \q{2\minus} means that one of the digits in the block is 2 more than the other, or equivalently that one digit minus the other one is 2. The two digits could be either way round, though. \b A division clue (e.g. \q{3\divide}), similarly, is always in a block of size two and means that one digit divided by the other is equal to the given amount. Note that a block may contain the same digit more than once (provided the identical ones are not in the same row and column). This rule is precisely the opposite of the rule in Solo's \q{Killer} mode (see \k{solo}). } This puzzle appears in the Times under the name \q{\i{KenKen}}. \H{keen-controls} \i{Keen controls} \IM{Keen controls} controls, for Keen Keen shares much of its control system with Solo (and Unequal). To play Keen, simply click the mouse in any empty square and then type a digit on the keyboard to fill that square. If you make a mistake, click the mouse in the incorrect square and press Space to clear it again (or use the Undo feature). If you \e{right}-click in a square and then type a number, that number will be entered in the square as a \q{pencil mark}. You can have pencil marks for multiple numbers in the same square. Squares containing filled-in numbers cannot also contain pencil marks. The game pays no attention to pencil marks, so exactly what you use them for is up to you: you can use them as reminders that a particular square needs to be re-examined once you know more about a particular number, or you can use them as lists of the possible numbers in a given square, or anything else you feel like. To erase a single pencil mark, right-click in the square and type the same number again. All pencil marks in a square are erased when you left-click and type a number, or when you left-click and press space. Right-clicking and pressing space will also erase pencil marks. As for Solo, the cursor keys can be used in conjunction with the digit keys to set numbers or pencil marks. Use the cursor keys to move a highlight around the grid, and type a digit to enter it in the highlighted square. Pressing return toggles the highlight into a mode in which you can enter or remove pencil marks. Pressing M will fill in a full set of pencil marks in every square that does not have a main digit in it. (All the actions described in \k{common-actions} are also available.) \H{keen-parameters} \I{parameters, for Keen}Keen parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Grid size} \dd Specifies the size of the grid. Lower limit is 3; upper limit is 9 (because the user interface would become more difficult with \q{digits} bigger than 9!). \dt \e{Difficulty} \dd Controls the difficulty of the generated puzzle. At Unreasonable level, some backtracking will be required, but the solution should still be unique. The remaining levels require increasingly complex reasoning to avoid having to backtrack. \dt \e{Multiplication only} \dd If this is enabled, all boxes will be multiplication boxes. With this rule, the puzzle is known as \q{Inshi No Heya}. \C{towers} \i{Towers} \cfg{winhelp-topic}{games.towers} You have a square grid. On each square of the grid you can build a tower, with its height ranging from 1 to the size of the grid. Around the edge of the grid are some numeric clues. Your task is to build a tower on every square, in such a way that: \b Each row contains every possible height of tower once \b Each column contains every possible height of tower once \b Each numeric clue describes the number of towers that can be seen if you look into the square from that direction, assuming that shorter towers are hidden behind taller ones. For example, in a 5\by\.5 grid, a clue marked \q{5} indicates that the five tower heights must appear in increasing order (otherwise you would not be able to see all five towers), whereas a clue marked \q{1} indicates that the tallest tower (the one marked 5) must come first. In harder or larger puzzles, some towers will be specified for you as well as the clues round the edge, and some edge clues may be missing. This puzzle appears on the web under various names, particularly \q{\i{Skyscrapers}}, but I don't know who first invented it. \H{towers-controls} \i{Towers controls} \IM{Towers controls} controls, for Towers Towers shares much of its control system with Solo, Unequal and Keen. To play Towers, simply click the mouse in any empty square and then type a digit on the keyboard to fill that square with a tower of the given height. If you make a mistake, click the mouse in the incorrect square and press Space to clear it again (or use the Undo feature). If you \e{right}-click in a square and then type a number, that number will be entered in the square as a \q{pencil mark}. You can have pencil marks for multiple numbers in the same square. A square containing a tower cannot also contain pencil marks. The game pays no attention to pencil marks, so exactly what you use them for is up to you: you can use them as reminders that a particular square needs to be re-examined once you know more about a particular number, or you can use them as lists of the possible numbers in a given square, or anything else you feel like. To erase a single pencil mark, right-click in the square and type the same number again. All pencil marks in a square are erased when you left-click and type a number, or when you left-click and press space. Right-clicking and pressing space will also erase pencil marks. As for Solo, the cursor keys can be used in conjunction with the digit keys to set numbers or pencil marks. Use the cursor keys to move a highlight around the grid, and type a digit to enter it in the highlighted square. Pressing return toggles the highlight into a mode in which you can enter or remove pencil marks. Pressing M will fill in a full set of pencil marks in every square that does not have a main digit in it. Left-clicking a clue will mark it as done (grey it out), or unmark it if it is already marked. Holding Control or Shift and pressing an arrow key likewise marks any clue in the given direction. (All the actions described in \k{common-actions} are also available.) \H{towers-parameters} \I{parameters, for Towers}Towers parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Grid size} \dd Specifies the size of the grid. Lower limit is 3; upper limit is 9 (because the user interface would become more difficult with \q{digits} bigger than 9!). \dt \e{Difficulty} \dd Controls the difficulty of the generated puzzle. At Unreasonable level, some backtracking will be required, but the solution should still be unique. The remaining levels require increasingly complex reasoning to avoid having to backtrack. \C{singles} \i{Singles} \cfg{winhelp-topic}{games.singles} You have a grid of white squares, all of which contain numbers. Your task is to colour some of the squares black (removing the number) so as to satisfy all of the following conditions: \b No number occurs more than once in any row or column. \b No black square is horizontally or vertically adjacent to any other black square. \b The remaining white squares must all form one contiguous region (connected by edges, not just touching at corners). Credit for this puzzle goes to \i{Nikoli} \k{nikoli-hitori} who call it \i{Hitori}. Singles was contributed to this collection by James Harvey. \B{nikoli-hitori} \W{http://www.nikoli.com/en/puzzles/hitori.html}\cw{http://www.nikoli.com/en/puzzles/hitori.html} (beware of Flash) \H{singles-controls} \i{Singles controls} \IM{Singles controls} controls, for Singles Left-clicking on an empty square will colour it black; left-clicking again will restore the number. Right-clicking will add a circle (useful for indicating that a cell is definitely not black). You can also use the cursor keys to move around the grid. Pressing the return or space keys will turn a square black or add a circle respectively, and pressing the key again will restore the number or remove the circle. (All the actions described in \k{common-actions} are also available.) \H{singles-parameters} \I{parameters, for Singles}Singles parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid in squares. \dt \e{Difficulty} \dd Controls the difficulty of the generated puzzle. \C{magnets} \i{Magnets} \cfg{winhelp-topic}{games.magnets} A rectangular grid has been filled with a mixture of magnets (that is, dominoes with one positive end and one negative end) and blank dominoes (that is, dominoes with two neutral poles). These dominoes are initially only seen in silhouette. Around the grid are placed a number of clues indicating the number of positive and negative poles contained in certain columns and rows. Your aim is to correctly place the magnets and blank dominoes such that all the clues are satisfied, with the additional constraint that no two similar magnetic poles may be orthogonally adjacent (since they repel). Neutral poles do not repel, and can be adjacent to any other pole. Credit for this puzzle goes to \i{Janko} \k{janko-magnets}. Magnets was contributed to this collection by James Harvey. \B{janko-magnets} \W{http://www.janko.at/Raetsel/Magnete/index.htm}\cw{http://www.janko.at/Raetsel/Magnete/index.htm} \H{magnets-controls} \i{Magnets controls} \IM{Magnets controls} controls, for Magnets Left-clicking on an empty square places a magnet at that position with the positive pole on the square and the negative pole on the other half of the magnet; left-clicking again reverses the polarity, and a third click removes the magnet. Right-clicking on an empty square places a blank domino there. Right-clicking again places two question marks on the domino, signifying \q{this cannot be blank} (which can be useful to note deductions while solving), and right-clicking again empties the domino. Left-clicking a clue will mark it as done (grey it out), or unmark it if it is already marked. You can also use the cursor keys to move a cursor around the grid. Pressing the return key will lay a domino with a positive pole at that position; pressing again reverses the polarity and then removes the domino, as with left-clicking. Using the space bar allows placement of blank dominoes and cannot-be-blank hints, as for right-clicking. (All the actions described in \k{common-actions} are also available.) \H{magnets-parameters} \I{parameters, for Magnets}Magnets parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid in squares. There will be half \e{Width} \by \e{Height} dominoes in the grid: if this number is odd then one square will be blank. \lcont{ (Grids with at least one odd dimension tend to be easier to solve.) } \dt \e{Difficulty} \dd Controls the difficulty of the generated puzzle. At Tricky level, you are required to make more deductions about empty dominoes and row/column counts. \dt \e{Strip clues} \dd If true, some of the clues around the grid are removed at generation time, making the puzzle more difficult. \C{signpost} \i{Signpost} \cfg{winhelp-topic}{games.signpost} You have a grid of squares; each square (except the last one) contains an arrow, and some squares also contain numbers. Your job is to connect the squares to form a continuous list of numbers starting at 1 and linked in the direction of the arrows \dash so the arrow inside the square with the number 1 will point to the square containing the number 2, which will point to the square containing the number 3, etc. Each square can be any distance away from the previous one, as long as it is somewhere in the direction of the arrow. By convention the first and last numbers are shown; one or more interim numbers may also appear at the beginning. Credit for this puzzle goes to \i{Janko} \k{janko-arrowpath}, who call it \q{Pfeilpfad} (\q{arrow path}). Signpost was contributed to this collection by James Harvey. \B{janko-arrowpath} \W{http://janko.at/Raetsel/Pfeilpfad/index.htm}\cw{http://janko.at/Raetsel/Pfeilpfad/index.htm} \H{signpost-controls} \I{controls, for Signpost}Signpost controls To play Signpost, you connect squares together by dragging from one square to another, indicating that they are adjacent in the sequence. Drag with the left button from a square to its successor, or with the right button from a square to its predecessor. If you connect together two squares in this way and one of them has a number in it, the appropriate number will appear in the other square. If you connect two non-numbered squares, they will be assigned temporary algebraic labels: on the first occasion, they will be labelled \cq{a} and \cq{a+1}, and then \cq{b} and \cq{b+1}, and so on. Connecting more squares on to the ends of such a chain will cause them all to be labelled with the same letter. When you left-click or right-click in a square, the legal squares to connect it to will be shown. The arrow in each square starts off black, and goes grey once you connect the square to its successor. Also, each square which needs a predecessor has a small dot in the bottom left corner, which vanishes once you link a square to it. So your aim is always to connect a square with a black arrow to a square with a dot. To remove any links for a particular square (both incoming and outgoing), left-drag it off the grid. To remove a whole chain, right-drag any square in the chain off the grid. You can also use the cursor keys to move around the grid squares and lines. Pressing the return key when over a square starts a link operation, and pressing the return key again over a square will finish the link, if allowable. Pressing the space bar over a square will show the other squares pointing to it, and allow you to form a backward link, and pressing the space bar again cancels this. (All the actions described in \k{common-actions} are also available.) \H{signpost-parameters} \I{parameters, for Signpost}Signpost parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid in squares. \dt \e{Force start/end to corners} \dd If true, the start and end squares are always placed in opposite corners (the start at the top left, and the end at the bottom right). If false the start and end squares are placed randomly (although always both shown). \C{range} \i{Range} \cfg{winhelp-topic}{games.range} You have a grid of squares; some squares contain numbers. Your job is to colour some of the squares black, such that several criteria are satisfied: \b no square with a number is coloured black. \b no two black squares are adjacent (horizontally or vertically). \b for any two white squares, there is a path between them using only white squares. \b for each square with a number, that number denotes the total number of white squares reachable from that square going in a straight line in any horizontal or vertical direction until hitting a wall or a black square; the square with the number is included in the total (once). For instance, a square containing the number one must have four black squares as its neighbours by the last criterion; but then it's impossible for it to be connected to any outside white square, which violates the second to last criterion. So no square will contain the number one. Credit for this puzzle goes to \i{Nikoli}, who have variously called it \q{Kurodoko}, \q{Kuromasu} or \q{Where is Black Cells}. \k{nikoli-range}. Range was contributed to this collection by Jonas K\u00F6{oe}lker. \B{nikoli-range} \W{http://www.nikoli.co.jp/en/puzzles/where_is_black_cells.html}\cw{http://www.nikoli.co.jp/en/puzzles/where_is_black_cells.html} \H{range-controls} \I{controls, for Range}Range controls Click with the left button to paint a square black, or with the right button to mark a square with a dot to indicate that you are sure it should \e{not} be painted black. Repeated clicking with either button will cycle the square through the three possible states (filled, dotted or empty) in opposite directions. You can also use the cursor keys to move around the grid squares. Pressing Return does the same as clicking with the left button, while pressing Space does the same as a right button click. Moving with the cursor keys while holding Shift will place dots in all squares that are moved through. (All the actions described in \k{common-actions} are also available.) \H{range-parameters} \I{parameters, for Range}Range parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid in squares. \C{pearl} \i{Pearl} \cfg{winhelp-topic}{games.pearl} You have a grid of squares. Your job is to draw lines between the centres of horizontally or vertically adjacent squares, so that the lines form a single closed loop. In the resulting grid, some of the squares that the loop passes through will contain corners, and some will be straight horizontal or vertical lines. (And some squares can be completely empty \dash the loop doesn't have to pass through every square.) Some of the squares contain black and white circles, which are clues that the loop must satisfy. A black circle in a square indicates that that square is a corner, but neither of the squares adjacent to it in the loop is also a corner. A white circle indicates that the square is a straight edge, but \e{at least one} of the squares adjacent to it in the loop is a corner. (In both cases, the clue only constrains the two squares adjacent \e{in the loop}, that is, the squares that the loop passes into after leaving the clue square. The squares that are only adjacent \e{in the grid} are not constrained.) Credit for this puzzle goes to \i{Nikoli}, who call it \q{Masyu}. \k{nikoli-pearl} Thanks to James Harvey for assistance with the implementation. \B{nikoli-pearl} \W{http://www.nikoli.co.jp/en/puzzles/masyu.html}\cw{http://www.nikoli.co.jp/en/puzzles/masyu.html} (beware of Flash) \H{pearl-controls} \I{controls, for Pearl}Pearl controls Click with the left button on a grid edge to draw a segment of the loop through that edge, or to remove a segment once it is drawn. Drag with the left button through a series of squares to draw more than one segment of the loop in one go. Alternatively, drag over an existing part of the loop to undraw it, or to undraw part of it and then go in a different direction. Click with the right button on a grid edge to mark it with a cross, indicating that you are sure the loop does not go through that edge. (For instance, if you have decided which of the squares adjacent to a white clue has to be a corner, but don't yet know which way the corner turns, you might mark the one way it \e{can't} go with a cross.) Alternatively, use the cursor keys to move the cursor. Use the Enter key to begin and end keyboard \q{drag} operations. Use the Space, Escape or Backspace keys to cancel the drag. Or, hold Control while dragging with the cursor keys to toggle segments as you move between squares. Pressing Control-Shift-arrowkey or Shift-arrowkey simulates a left or right click, respectively, on the edge in the direction of the key. (All the actions described in \k{common-actions} are also available.) \H{pearl-parameters} \I{parameters, for Pearl}Pearl parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \C{undead} \i{Undead} \cfg{winhelp-topic}{games.undead} You are given a grid of squares, some of which contain diagonal mirrors. Every square which is not a mirror must be filled with one of three types of undead monster: a ghost, a vampire, or a zombie. Vampires can be seen directly, but are invisible when reflected in mirrors. Ghosts are the opposite way round: they can be seen in mirrors, but are invisible when looked at directly. Zombies are visible by any means. You are also told the total number of each type of monster in the grid. Also around the edge of the grid are written numbers, which indicate how many monsters can be seen if you look into the grid along a row or column starting from that position. (The diagonal mirrors are reflective on both sides. If your reflected line of sight crosses the same monster more than once, the number will count it each time it is visible, not just once.) This puzzle type was invented by David Millar, under the name \q{Haunted Mirror Maze}. See \k{janko-undead} for more details. Undead was contributed to this collection by Steffen Bauer. \B{janko-undead} \W{http://www.janko.at/Raetsel/Spukschloss/index.htm}\cw{http://www.janko.at/Raetsel/Spukschloss/index.htm} \H{undead-controls} \I{controls, for Undead}Undead controls Undead has a similar control system to Solo, Unequal and Keen. To play Undead, click the mouse in any empty square and then type a letter on the keyboard indicating the type of monster: \q{G} for a ghost, \q{V} for a vampire, or \q{Z} for a zombie. If you make a mistake, click the mouse in the incorrect square and press Space to clear it again (or use the Undo feature). If you \e{right}-click in a square and then type a letter, the corresponding monster will be shown in reduced size in that square, as a \q{pencil mark}. You can have pencil marks for multiple monsters in the same square. A square containing a full-size monster cannot also contain pencil marks. The game pays no attention to pencil marks, so exactly what you use them for is up to you: you can use them as reminders that a particular square needs to be re-examined once you know more about a particular monster, or you can use them as lists of the possible monster in a given square, or anything else you feel like. To erase a single pencil mark, right-click in the square and type the same letter again. All pencil marks in a square are erased when you left-click and type a monster letter, or when you left-click and press Space. Right-clicking and pressing space will also erase pencil marks. As for Solo, the cursor keys can be used in conjunction with the letter keys to place monsters or pencil marks. Use the cursor keys to move a highlight around the grid, and type a monster letter to enter it in the highlighted square. Pressing return toggles the highlight into a mode in which you can enter or remove pencil marks. If you prefer plain letters of the alphabet to cute monster pictures, you can press \q{A} to toggle between showing the monsters as monsters or showing them as letters. Left-clicking a clue will mark it as done (grey it out), or unmark it if it is already marked. (All the actions described in \k{common-actions} are also available.) \H{undead-parameters} \I{parameters, for Undead}Undead parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid in squares. \dt \e{Difficulty} \dd Controls the difficulty of the generated puzzle. \C{unruly} \i{Unruly} \cfg{winhelp-topic}{games.unruly} You are given a grid of squares, which you must colour either black or white. Some squares are provided as clues; the rest are left for you to fill in. Each row and column must contain the same number of black and white squares, and no row or column may contain three consecutive squares of the same colour. This puzzle type was invented by Adolfo Zanellati, under the name \q{Tohu wa Vohu}. See \k{janko-unruly} for more details. Unruly was contributed to this collection by Lennard Sprong. \B{janko-unruly} \W{http://www.janko.at/Raetsel/Tohu-Wa-Vohu/index.htm}\cw{http://www.janko.at/Raetsel/Tohu-Wa-Vohu/index.htm} \H{unruly-controls} \I{controls, for Unruly}Unruly controls To play Unruly, click the mouse in a square to change its colour. Left-clicking an empty square will turn it black, and right-clicking will turn it white. Keep clicking the same button to cycle through the three possible states for the square. If you middle-click in a square it will be reset to empty. You can also use the cursor keys to move around the grid. Pressing the return or space keys will turn an empty square black or white respectively (and then cycle the colours in the same way as the mouse buttons), and pressing Backspace will reset a square to empty. (All the actions described in \k{common-actions} are also available.) \H{unruly-parameters} \I{parameters, for Unruly}Unruly parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid in squares. (Note that the rules of the game require both the width and height to be even numbers.) \dt \e{Difficulty} \dd Controls the difficulty of the generated puzzle. \dt \e{Unique rows and columns} \dd If enabled, no two rows are permitted to have exactly the same pattern, and likewise columns. (A row and a column can match, though.) \C{flood} \i{Flood} \cfg{winhelp-topic}{games.flood} You are given a grid of squares, coloured at random in multiple colours. In each move, you can flood-fill the top left square in a colour of your choice (i.e. every square reachable from the starting square by an orthogonally connected path of squares all the same colour will be filled in the new colour). As you do this, more and more of the grid becomes connected to the starting square. Your aim is to make the whole grid the same colour, in as few moves as possible. The game will set a limit on the number of moves, based on running its own internal solver. You win if you can make the whole grid the same colour in that many moves or fewer. I saw this game (with a fixed grid size, fixed number of colours, and fixed move limit) at http://floodit.appspot.com (no longer accessible). \H{flood-controls} \I{controls, for Flood}Flood controls To play Flood, click the mouse in a square. The top left corner and everything connected to it will be flood-filled with the colour of the square you clicked. Clicking a square the same colour as the top left corner has no effect, and therefore does not count as a move. You can also use the cursor keys to move a cursor (outline black square) around the grid. Pressing the return key will fill the top left corner in the colour of the square under the cursor. (All the actions described in \k{common-actions} are also available.) \H{flood-parameters} \I{parameters, for Flood}Flood parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of the grid, in squares. \dt \e{Colours} \dd Number of colours used to fill the grid. Must be at least 3 (with two colours there would only be one legal move at any stage, hence no choice to make at all), and at most 10. \dt \e{Extra moves permitted} \dd Controls the difficulty of the puzzle, by increasing the move limit. In each new grid, Flood will run an internal solver to generate its own solution, and then the value in this field will be added to the length of Flood's solution to generate the game's move limit. So a value of 0 requires you to be just as efficient as Flood's automated solver, and a larger value makes it easier. \lcont{ (Note that Flood's internal solver will not necessarily find the shortest possible solution, though I believe it's pretty close. For a real challenge, set this value to 0 and then try to solve a grid in \e{strictly fewer} moves than the limit you're given!) } \C{tracks} \i{Tracks} \cfg{winhelp-topic}{games.tracks} You are given a grid of squares, some of which are filled with train tracks. You need to complete the track from A to B so that the rows and columns contain the same number of track segments as are indicated in the clues to the top and right of the grid. There are only straight and 90 degree curved rails, and the track may not cross itself. Tracks was contributed to this collection by James Harvey. \H{tracks-controls} \I{controls, for Tracks}Tracks controls Left-clicking on an edge between two squares adds a track segment between the two squares. Right-clicking on an edge adds a cross on the edge, indicating no track is possible there. Left-clicking in a square adds a colour indicator showing that you know the square must contain a track, even if you don't know which edges it crosses yet. Right-clicking in a square adds a cross indicating it contains no track segment. Left- or right-dragging between squares allows you to lay a straight line of is-track or is-not-track indicators, useful for filling in rows or columns to match the clue. (All the actions described in \k{common-actions} are also available.) \H{tracks-parameters} \I{parameters, for Tracks}Tracks parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of the grid, in squares. \dt \e{Difficulty} \dd Controls the difficulty of the generated puzzle: at Tricky level, you are required to make more deductions regarding disregarding moves that would lead to impossible crossings later. \dt \e{Disallow consecutive 1 clues} \dd Controls whether the Tracks game generation permits two adjacent rows or columns to have a 1 clue, or permits the row or column of the track's endpoint to have a 1 clue. By default this is not permitted, to avoid long straight boring segments of track and make the games more twiddly and interesting. If you want to restore the possibility, turn this option off. \C{palisade} \i{Palisade} \cfg{winhelp-topic}{games.palisade} You're given a grid of squares, some of which contain numbers. Your goal is to subdivide the grid into contiguous regions, all of the same (given) size, such that each square containing a number is adjacent to exactly that many edges (including those between the inside and the outside of the grid). Credit for this puzzle goes to \i{Nikoli}, who call it \q{Five Cells}. \k{nikoli-palisade}. Palisade was contributed to this collection by Jonas K\u00F6{oe}lker. \B{nikoli-palisade} \W{http://nikoli.co.jp/en/puzzles/five_cells.html}\cw{http://nikoli.co.jp/en/puzzles/five_cells.html} \H{palisade-controls} \I{controls, for Palisade}Palisade controls Left-click to place an edge. Right-click to indicate \q{no edge}. Alternatively, the arrow keys will move a keyboard cursor. Holding Control while pressing an arrow key will place an edge. Press Shift-arrowkey to switch off an edge. Repeat an action to perform its inverse. (All the actions described in \k{common-actions} are also available.) \H{Palisade-parameters} \I{parameters, for Palisade}Palisade parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid in squares. \dt \e{Region size} \dd The size of the regions into which the grid must be subdivided. \A{licence} \I{MIT licence}\ii{Licence} This software is \i{copyright} 2004-2014 Simon Tatham. Portions copyright Richard Boulton, James Harvey, Mike Pinna, Jonas K\u00F6{oe}lker, Dariusz Olszewski, Michael Schierl, Lambros Lambrou, Bernd Schmidt, Steffen Bauer, Lennard Sprong and Rogier Goossens. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \q{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 \q{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 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \IM{command-line}{command line} command line \IM{default parameters, specifying} default parameters, specifying \IM{default parameters, specifying} preferences, specifying default \IM{Unix} Unix \IM{Unix} Linux \IM{generating game IDs} generating game IDs \IM{generating game IDs} game ID, generating \IM{specific} \q{Specific}, menu option \IM{custom} \q{Custom}, menu option \IM{game ID} game ID \IM{game ID} ID, game \IM{ID format} ID format \IM{ID format} format, ID \IM{ID format} game ID, format \IM{keys} keys \IM{keys} shortcuts (keyboard) \IM{initial state} initial state \IM{initial state} state, initial \IM{MIT licence} MIT licence \IM{MIT licence} licence, MIT \versionid Simon Tatham's Portable Puzzle Collection, version 20170606.272beef puzzles-20170606.272beef/preprocessed.but0000644000175000017500000040162513115374020017102 0ustar simonsimon\title Simon Tatham's Portable Puzzle Collection \cfg{winhelp-filename}{puzzles.hlp} \cfg{winhelp-contents-titlepage}{Contents} \cfg{text-filename}{puzzles.txt} \cfg{html-contents-filename}{index.html} \cfg{html-template-filename}{%k.html} \cfg{html-index-filename}{docindex.html} \cfg{html-leaf-level}{1} \cfg{html-contents-depth-0}{1} \cfg{html-contents-depth-1}{2} \cfg{html-leaf-contains-contents}{true} \cfg{chm-filename}{puzzles.chm} \cfg{chm-contents-filename}{index.html} \cfg{chm-template-filename}{%k.html} \cfg{chm-head-end}{} \cfg{chm-extra-file}{chm.css} \cfg{info-filename}{puzzles.info} \cfg{ps-filename}{puzzles.ps} \cfg{pdf-filename}{puzzles.pdf} \define{by} \u00D7{x} \define{dash} \u2013{-} \define{times} \u00D7{*} \define{divide} \u00F7{/} \define{minus} \u2212{-} This is a collection of small one-player puzzle games. \copyright This manual is copyright 2004-2014 Simon Tatham. All rights reserved. You may distribute this documentation under the MIT licence. See \k{licence} for the licence text in full. \cfg{html-local-head}{} \C{intro} Introduction I wrote this collection because I thought there should be more small desktop toys available: little games you can pop up in a window and play for two or three minutes while you take a break from whatever else you were doing. And I was also annoyed that every time I found a good game on (say) \i{Unix}, it wasn't available the next time I was sitting at a \i{Windows} machine, or vice versa; so I arranged that everything in my personal puzzle collection will happily run on both, and have more recently done a port to \i{Mac OS X} as well. When I find (or perhaps invent) further puzzle games that I like, they'll be added to this collection and will immediately be available on both platforms. And if anyone feels like writing any other front ends \dash PocketPC, Mac OS pre-10, or whatever it might be \dash then all the games in this framework will immediately become available on another platform as well. The actual games in this collection were mostly not my invention; they are re-implementations of existing game concepts within my portable puzzle framework. I do not claim credit, in general, for inventing the rules of any of these puzzles. (I don't even claim authorship of all the code; some of the puzzles have been submitted by other authors.) This collection is distributed under the \i{MIT licence} (see \k{licence}). This means that you can do pretty much anything you like with the game binaries or the code, except pretending you wrote them yourself, or suing me if anything goes wrong. The most recent versions, and \i{source code}, can be found at \I{website}\W{https://www.chiark.greenend.org.uk/~sgtatham/puzzles/}\cw{https://www.chiark.greenend.org.uk/~sgtatham/puzzles/}. Please report \I{feedback}\i{bugs} to \W{mailto:anakin@pobox.com}\cw{anakin@pobox.com}. You might find it helpful to read this article before reporting a bug: \W{https://www.chiark.greenend.org.uk/~sgtatham/bugs.html}\cw{https://www.chiark.greenend.org.uk/~sgtatham/bugs.html} \ii{Patches} are welcome. Especially if they provide a new front end (to make all these games run on another platform), or a new game. \C{common} \ii{Common features} This chapter describes features that are common to all the games. \H{common-actions} \I{controls}Common actions These actions are all available from the \I{Game menu}\q{Game} menu and via \I{keys}keyboard shortcuts, in addition to any game-specific actions. (On \i{Mac OS X}, to conform with local user interface standards, these actions are situated on the \I{File menu}\q{File} and \I{Edit menu}\q{Edit} menus instead.) \dt \ii\e{New game} (\q{N}, Ctrl+\q{N}) \dd Starts a new game, with a random initial state. \dt \ii\e{Restart game} \dd Resets the current game to its initial state. (This can be undone.) \dt \ii\e{Load} \dd Loads a saved game from a file on disk. \dt \ii\e{Save} \dd Saves the current state of your game to a file on disk. \lcont{ The Load and Save operations preserve your entire game history (so you can save, reload, and still Undo and Redo things you had done before saving). } \dt \I{printing, on Windows}\e{Print} \dd Where supported (currently only on Windows), brings up a dialog allowing you to print an arbitrary number of puzzles randomly generated from the current parameters, optionally including the current puzzle. (Only for puzzles which make sense to print, of course \dash it's hard to think of a sensible printable representation of Fifteen!) \dt \ii\e{Undo} (\q{U}, Ctrl+\q{Z}, Ctrl+\q{_}) \dd Undoes a single move. (You can undo moves back to the start of the session.) \dt \ii\e{Redo} (\q{R}, Ctrl+\q{R}) \dd Redoes a previously undone move. \dt \ii\e{Copy} \dd Copies the current state of your game to the clipboard in text format, so that you can paste it into (say) an e-mail client or a web message board if you're discussing the game with someone else. (Not all games support this feature.) \dt \ii\e{Solve} \dd Transforms the puzzle instantly into its solved state. For some games (Cube) this feature is not supported at all because it is of no particular use. For other games (such as Pattern), the solved state can be used to give you information, if you can't see how a solution can exist at all or you want to know where you made a mistake. For still other games (such as Sixteen), automatic solution tells you nothing about how to \e{get} to the solution, but it does provide a useful way to get there quickly so that you can experiment with set-piece moves and transformations. \lcont{ Some games (such as Solo) are capable of solving a game ID you have typed in from elsewhere. Other games (such as Rectangles) cannot solve a game ID they didn't invent themself, but when they did invent the game ID they know what the solution is already. Still other games (Pattern) can solve \e{some} external game IDs, but only if they aren't too difficult. The \q{Solve} command adds the solved state to the end of the undo chain for the puzzle. In other words, if you want to go back to solving it yourself after seeing the answer, you can just press Undo. } \dt \I{exit}\ii\e{Quit} (\q{Q}, Ctrl+\q{Q}) \dd Closes the application entirely. \H{common-id} Specifying games with the \ii{game ID} There are two ways to save a game specification out of a puzzle and recreate it later, or recreate it in somebody else's copy of the same puzzle. The \q{\i{Specific}} and \q{\i{Random Seed}} options from the \I{Game menu}\q{Game} menu (or the \q{File} menu, on \i{Mac OS X}) each show a piece of text (a \q{game ID}) which is sufficient to reconstruct precisely the same game at a later date. You can enter either of these pieces of text back into the program (via the same \q{Specific} or \q{Random Seed} menu options) at a later point, and it will recreate the same game. You can also use either one as a \i{command line} argument (on Windows or Unix); see \k{common-cmdline} for more detail. The difference between the two forms is that a descriptive game ID is a literal \e{description} of the \i{initial state} of the game, whereas a random seed is just a piece of arbitrary text which was provided as input to the random number generator used to create the puzzle. This means that: \b Descriptive game IDs tend to be longer in many puzzles (although some, such as Cube (\k{cube}), only need very short descriptions). So a random seed is often a \e{quicker} way to note down the puzzle you're currently playing, or to tell it to somebody else so they can play the same one as you. \b Any text at all is a valid random seed. The automatically generated ones are fifteen-digit numbers, but anything will do; you can type in your full name, or a word you just made up, and a valid puzzle will be generated from it. This provides a way for two or more people to race to complete the same puzzle: you think of a random seed, then everybody types it in at the same time, and nobody has an advantage due to having seen the generated puzzle before anybody else. \b It is often possible to convert puzzles from other sources (such as \q{nonograms} or \q{sudoku} from newspapers) into descriptive game IDs suitable for use with these programs. \b Random seeds are not guaranteed to produce the same result if you use them with a different \i\e{version} of the puzzle program. This is because the generation algorithm might have been improved or modified in later versions of the code, and will therefore produce a different result when given the same sequence of random numbers. Use a descriptive game ID if you aren't sure that it will be used on the same version of the program as yours. \lcont{(Use the \q{About} menu option to find out the version number of the program. Programs with the same version number running on different platforms should still be random-seed compatible.)} \I{ID format}A descriptive game ID starts with a piece of text which encodes the \i\e{parameters} of the current game (such as grid size). Then there is a colon, and after that is the description of the game's initial state. A random seed starts with a similar string of parameters, but then it contains a hash sign followed by arbitrary data. If you enter a descriptive game ID, the program will not be able to show you the random seed which generated it, since it wasn't generated \e{from} a random seed. If you \e{enter} a random seed, however, the program will be able to show you the descriptive game ID derived from that random seed. Note that the game parameter strings are not always identical between the two forms. For some games, there will be parameter data provided with the random seed which is not included in the descriptive game ID. This is because that parameter information is only relevant when \e{generating} puzzle grids, and is not important when playing them. Thus, for example, the difficulty level in Solo (\k{solo}) is not mentioned in the descriptive game ID. These additional parameters are also not set permanently if you type in a game ID. For example, suppose you have Solo set to \q{Advanced} difficulty level, and then a friend wants your help with a \q{Trivial} puzzle; so the friend reads out a random seed specifying \q{Trivial} difficulty, and you type it in. The program will generate you the same \q{Trivial} grid which your friend was having trouble with, but once you have finished playing it, when you ask for a new game it will automatically go back to the \q{Advanced} difficulty which it was previously set on. \H{common-type} The \q{Type} menu The \I{Type menu}\q{Type} menu, if present, may contain a list of \i{preset} game settings. Selecting one of these will start a new random game with the parameters specified. The \q{Type} menu may also contain a \q{\i{Custom}} option which allows you to fine-tune game \i{parameters}. The parameters available are specific to each game and are described in the following sections. \H{common-cmdline} Specifying game parameters on the \i{command line} (This section does not apply to the \i{Mac OS X} version.) The games in this collection deliberately do not ever save information on to the computer they run on: they have no high score tables and no saved preferences. (This is because I expect at least some people to play them at work, and those people will probably appreciate leaving as little evidence as possible!) However, if you do want to arrange for one of these games to \I{default parameters, specifying}default to a particular set of parameters, you can specify them on the command line. The easiest way to do this is to set up the parameters you want using the \q{Type} menu (see \k{common-type}), and then to select \q{Random Seed} from the \q{Game} or \q{File} menu (see \k{common-id}). The text in the \q{Game ID} box will be composed of two parts, separated by a hash. The first of these parts represents the game parameters (the size of the playing area, for example, and anything else you set using the \q{Type} menu). If you run the game with just that parameter text on the command line, it will start up with the settings you specified. For example: if you run Cube (see \k{cube}), select \q{Octahedron} from the \q{Type} menu, and then go to the game ID selection, you will see a string of the form \cq{o2x2#338686542711620}. Take only the part before the hash (\cq{o2x2}), and start Cube with that text on the command line: \cq{cube o2x2}. If you copy the \e{entire} game ID on to the command line, the game will start up in the specific game that was described. This is occasionally a more convenient way to start a particular game ID than by pasting it into the game ID selection box. (You could also retrieve the encoded game parameters using the \q{Specific} menu option instead of \q{Random Seed}, but if you do then some options, such as the difficulty level in Solo, will be missing. See \k{common-id} for more details on this.) \H{common-unix-cmdline} \i{Unix} \i{command-line} options (This section only applies to the Unix port.) In addition to being able to specify game parameters on the command line (see \k{common-cmdline}), there are various other options: \dt \cw{--game} \dt \cw{--load} \dd These options respectively determine whether the command-line argument is treated as specifying game parameters or a \i{save} file to \i{load}. Only one should be specified. If neither of these options is specified, a guess is made based on the format of the argument. \dt \cw{--generate }\e{n} \dd If this option is specified, instead of a puzzle being displayed, a number of descriptive game IDs will be \I{generating game IDs}invented and printed on standard output. This is useful for gaining access to the game generation algorithms without necessarily using the frontend. \lcont{ If game parameters are specified on the command-line, they will be used to generate the game IDs; otherwise a default set of parameters will be used. The most common use of this option is in conjunction with \c{--print}, in which case its behaviour is slightly different; see below. } \dt \I{printing, on Unix}\cw{--print }\e{w}\cw{x}\e{h} \dd If this option is specified, instead of a puzzle being displayed, a printed representation of one or more unsolved puzzles is sent to standard output, in \i{PostScript} format. \lcont{ On each page of puzzles, there will be \e{w} across and \e{h} down. If there are more puzzles than \e{w}\by\e{h}, more than one page will be printed. If \c{--generate} has also been specified, the invented game IDs will be used to generate the printed output. Otherwise, a list of game IDs is expected on standard input (which can be descriptive or random seeds; see \k{common-id}), in the same format produced by \c{--generate}. For example: \c net --generate 12 --print 2x3 7x7w | lpr will generate two pages of printed Net puzzles (each of which will have a 7\by\.7 wrapping grid), and pipe the output to the \c{lpr} command, which on many systems will send them to an actual printer. There are various other options which affect printing; see below. } \dt \cw{--save }\e{file-prefix} [ \cw{--save-suffix }\e{file-suffix} ] \dd If this option is specified, instead of a puzzle being displayed, saved-game files for one or more unsolved puzzles are written to files constructed from the supplied prefix and/or suffix. \lcont{ If \c{--generate} has also been specified, the invented game IDs will be used to generate the printed output. Otherwise, a list of game IDs is expected on standard input (which can be descriptive or random seeds; see \k{common-id}), in the same format produced by \c{--generate}. For example: \c net --generate 12 --save game --save-suffix .sav will generate twelve Net saved-game files with the names \cw{game0.sav} to \cw{game11.sav}. } \dt \cw{--version} \dd Prints version information about the game, and then quits. The following options are only meaningful if \c{--print} is also specified: \dt \cw{--with-solutions} \dd The set of pages filled with unsolved puzzles will be followed by the solutions to those puzzles. \dt \cw{--scale }\e{n} \dd Adjusts how big each puzzle is when printed. Larger numbers make puzzles bigger; the default is 1.0. \dt \cw{--colour} \dd Puzzles will be printed in colour, rather than in black and white (if supported by the puzzle). \C{net} \i{Net} \cfg{winhelp-topic}{games.net} (\e{Note:} the \i{Windows} version of this game is called \i\cw{NETGAME.EXE} to avoid clashing with Windows's own \cw{NET.EXE}.) I originally saw this in the form of a Flash game called \i{FreeNet} \k{FreeNet}, written by Pavils Jurjans; there are several other implementations under the name \i{NetWalk}. The computer prepares a network by connecting up the centres of squares in a grid, and then shuffles the network by rotating every tile randomly. Your job is to rotate it all back into place. The successful solution will be an entirely connected network, with no closed loops. \#{The latter clause means that there are no closed paths within the network. Could this be clearer? "No closed paths"?} As a visual aid, all tiles which are connected to the one in the middle are highlighted. \B{FreeNet} \W{http://www.jurjans.lv/stuff/net/FreeNet.htm}\cw{http://www.jurjans.lv/stuff/net/FreeNet.htm} \H{net-controls} \i{Net controls} \IM{Net controls} controls, for Net \IM{Net controls} keys, for Net \IM{Net controls} shortcuts (keyboard), for Net This game can be played with either the keyboard or the mouse. The controls are: \dt \e{Select tile}: mouse pointer, arrow keys \dt \e{Rotate tile anticlockwise}: left mouse button, \q{A} key \dt \e{Rotate tile clockwise}: right mouse button, \q{D} key \dt \e{Rotate tile by 180 degrees}: \q{F} key \dt \e{Lock (or unlock) tile}: middle mouse button, shift-click, \q{S} key \dd You can lock a tile once you're sure of its orientation. You can also unlock it again, but while it's locked you can't accidentally turn it. The following controls are not necessary to complete the game, but may be useful: \dt \e{Shift grid}: Shift + arrow keys \dd On grids that wrap, you can move the origin of the grid, so that tiles that were on opposite sides of the grid can be seen together. \dt \e{Move centre}: Ctrl + arrow keys \dd You can change which tile is used as the source of highlighting. (It doesn't ultimately matter which tile this is, as every tile will be connected to every other tile in a correct solution, but it may be helpful in the intermediate stages of solving the puzzle.) \dt \e{Jumble tiles}: \q{J} key \dd This key turns all tiles that are not locked to random orientations. (All the actions described in \k{common-actions} are also available.) \H{net-params} \I{parameters, for Net}Net parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid in tiles. \dt \e{Walls wrap around} \dd If checked, flow can pass from the left edge to the right edge, and from top to bottom, and vice versa. \dt \e{Barrier probability} \dd A number between 0.0 and 1.0 controlling whether an immovable barrier is placed between two tiles to prevent flow between them (a higher number gives more barriers). Since barriers are immovable, they act as constraints on the solution (i.e., hints). \lcont{ The grid generation in Net has been carefully arranged so that the barriers are independent of the rest of the grid. This means that if you note down the random seed used to generate the current puzzle (see \k{common-id}), change the \e{Barrier probability} parameter, and then re-enter the same random seed, you should see exactly the same starting grid, with the only change being the number of barriers. So if you're stuck on a particular grid and need a hint, you could start up another instance of Net, set up the same parameters but a higher barrier probability, and enter the game seed from the original Net window. } \dt \e{Ensure unique solution} \dd Normally, Net will make sure that the puzzles it presents have only one solution. Puzzles with ambiguous sections can be more difficult and more subtle, so if you like you can turn off this feature and risk having ambiguous puzzles. (Also, finding \e{all} the possible solutions can be an additional challenge for an advanced player.) \C{cube} \i{Cube} \cfg{winhelp-topic}{games.cube} This is another one I originally saw as a web game. This one was a Java game \k{cube-java-game}, by Paul Scott. You have a grid of 16 squares, six of which are blue; on one square rests a cube. Your move is to use the arrow keys to roll the cube through 90 degrees so that it moves to an adjacent square. If you roll the cube on to a blue square, the blue square is picked up on one face of the cube; if you roll a blue face of the cube on to a non-blue square, the blueness is put down again. (In general, whenever you roll the cube, the two faces that come into contact swap colours.) Your job is to get all six blue squares on to the six faces of the cube at the same time. Count your moves and try to do it in as few as possible. Unlike the original Java game, my version has an additional feature: once you've mastered the game with a cube rolling on a square grid, you can change to a triangular grid and roll any of a tetrahedron, an octahedron or an icosahedron. \B{cube-java-game} \W{http://www3.sympatico.ca/paulscott/cube/cube.htm}\cw{http://www3.sympatico.ca/paulscott/cube/cube.htm} \H{cube-controls} \i{Cube controls} \IM{Cube controls} controls, for Cube \IM{Cube controls} keys, for Cube \IM{Cube controls} shortcuts (keyboard), for Cube This game can be played with either the keyboard or the mouse. Left-clicking anywhere on the window will move the cube (or other solid) towards the mouse pointer. The arrow keys can also used to roll the cube on its square grid in the four cardinal directions. On the triangular grids, the mapping of arrow keys to directions is more approximate. Vertical movement is disallowed where it doesn't make sense. The four keys surrounding the arrow keys on the numeric keypad (\q{7}, \q{9}, \q{1}, \q{3}) can be used for diagonal movement. (All the actions described in \k{common-actions} are also available.) \H{cube-params} \I{parameters, for Cube}Cube parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Type of solid} \dd Selects the solid to roll (and hence the shape of the grid): tetrahedron, cube, octahedron, or icosahedron. \dt \e{Width / top}, \e{Height / bottom} \dd On a square grid, horizontal and vertical dimensions. On a triangular grid, the number of triangles on the top and bottom rows respectively. \C{fifteen} \i{Fifteen} \cfg{winhelp-topic}{games.fifteen} The old ones are the best: this is the good old \q{\i{15-puzzle}} with sliding tiles. You have a 4\by\.4 square grid; 15 squares contain numbered tiles, and the sixteenth is empty. Your move is to choose a tile next to the empty space, and slide it into the space. The aim is to end up with the tiles in numerical order, with the space in the bottom right (so that the top row reads 1,2,3,4 and the bottom row reads 13,14,15,\e{space}). \H{fifteen-controls} \i{Fifteen controls} \IM{Fifteen controls} controls, for Fifteen \IM{Fifteen controls} keys, for Fifteen \IM{Fifteen controls} shortcuts (keyboard), for Fifteen This game can be controlled with the mouse or the keyboard. A left-click with the mouse in the row or column containing the empty space will move as many tiles as necessary to move the space to the mouse pointer. The arrow keys will move a tile adjacent to the space in the direction indicated (moving the space in the \e{opposite} direction). Pressing \q{h} will make a suggested move. Pressing \q{h} enough times will solve the game, but it may scramble your progress while doing so. (All the actions described in \k{common-actions} are also available.) \H{fifteen-params} \I{parameters, for Fifteen}Fifteen parameters The only options available from the \q{Custom...} option on the \q{Type} menu are \e{Width} and \e{Height}, which are self-explanatory. (Once you've changed these, it's not a \q{15-puzzle} any more, of course!) \C{sixteen} \i{Sixteen} \cfg{winhelp-topic}{games.sixteen} Another sliding tile puzzle, visually similar to Fifteen (see \k{fifteen}) but with a different type of move. This time, there is no hole: all 16 squares on the grid contain numbered squares. Your move is to shift an entire row left or right, or shift an entire column up or down; every time you do that, the tile you shift off the grid re-appears at the other end of the same row, in the space you just vacated. To win, arrange the tiles into numerical order (1,2,3,4 on the top row, 13,14,15,16 on the bottom). When you've done that, try playing on different sizes of grid. I \e{might} have invented this game myself, though only by accident if so (and I'm sure other people have independently invented it). I thought I was imitating a screensaver I'd seen, but I have a feeling that the screensaver might actually have been a Fifteen-type puzzle rather than this slightly different kind. So this might be the one thing in my puzzle collection which represents creativity on my part rather than just engineering. \H{sixteen-controls} \I{controls, for Sixteen}Sixteen controls Left-clicking on an arrow will move the appropriate row or column in the direction indicated. Right-clicking will move it in the opposite direction. Alternatively, use the cursor keys to move the position indicator around the edge of the grid, and use the return key to move the row/column in the direction indicated. You can also move the tiles directly. Move the cursor onto a tile, hold Control and press an arrow key to move the tile under the cursor and move the cursor along with the tile. Or, hold Shift to move only the tile. Pressing Enter simulates holding down Control (press Enter again to release), while pressing Space simulates holding down shift. (All the actions described in \k{common-actions} are also available.) \H{sixteen-params} \I{parameters, for Sixteen}Sixteen parameters The parameters available from the \q{Custom...} option on the \q{Type} menu are: \b \e{Width} and \e{Height}, which are self-explanatory. \b You can ask for a limited shuffling operation to be performed on the grid. By default, Sixteen will shuffle the grid in such a way that any arrangement is about as probable as any other. You can override this by requesting a precise number of shuffling moves to be performed. Typically your aim is then to determine the precise set of shuffling moves and invert them exactly, so that you answer (say) a four-move shuffle with a four-move solution. Note that the more moves you ask for, the more likely it is that solutions shorter than the target length will turn out to be possible. \C{twiddle} \i{Twiddle} \cfg{winhelp-topic}{games.twiddle} Twiddle is a tile-rearrangement puzzle, visually similar to Sixteen (see \k{sixteen}): you are given a grid of square tiles, each containing a number, and your aim is to arrange the numbers into ascending order. In basic Twiddle, your move is to rotate a square group of four tiles about their common centre. (Orientation is not significant in the basic puzzle, although you can select it.) On more advanced settings, you can rotate a larger square group of tiles. I first saw this type of puzzle in the GameCube game \q{Metroid Prime 2}. In the Main Gyro Chamber in that game, there is a puzzle you solve to unlock a door, which is a special case of Twiddle. I developed this game as a generalisation of that puzzle. \H{twiddle-controls} \I{controls, for Twiddle}Twiddle controls To play Twiddle, click the mouse in the centre of the square group you wish to rotate. In the basic mode, you rotate a 2\by\.2 square, which means you have to click at a corner point where four tiles meet. In more advanced modes you might be rotating 3\by\.3 or even more at a time; if the size of the square is odd then you simply click in the centre tile of the square you want to rotate. Clicking with the left mouse button rotates the group anticlockwise. Clicking with the right button rotates it clockwise. You can also move an outline square around the grid with the cursor keys; the square is the size above (2\by\.2 by default, or larger). Pressing the return key or space bar will rotate the current square anticlockwise or clockwise respectively. (All the actions described in \k{common-actions} are also available.) \H{twiddle-parameters} \I{parameters, for Twiddle}Twiddle parameters Twiddle provides several configuration options via the \q{Custom} option on the \q{Type} menu: \b You can configure the width and height of the puzzle grid. \b You can configure the size of square block that rotates at a time. \b You can ask for every square in the grid to be distinguishable (the default), or you can ask for a simplified puzzle in which there are groups of identical numbers. In the simplified puzzle your aim is just to arrange all the 1s into the first row, all the 2s into the second row, and so on. \b You can configure whether the orientation of tiles matters. If you ask for an orientable puzzle, each tile will have a triangle drawn in it. All the triangles must be pointing upwards to complete the puzzle. \b You can ask for a limited shuffling operation to be performed on the grid. By default, Twiddle will shuffle the grid so much that any arrangement is about as probable as any other. You can override this by requesting a precise number of shuffling moves to be performed. Typically your aim is then to determine the precise set of shuffling moves and invert them exactly, so that you answer (say) a four-move shuffle with a four-move solution. Note that the more moves you ask for, the more likely it is that solutions shorter than the target length will turn out to be possible. \C{rect} \i{Rectangles} \cfg{winhelp-topic}{games.rectangles} You have a grid of squares, with numbers written in some (but not all) of the squares. Your task is to subdivide the grid into rectangles of various sizes, such that (a) every rectangle contains exactly one numbered square, and (b) the area of each rectangle is equal to the number written in its numbered square. Credit for this game goes to the Japanese puzzle magazine \i{Nikoli} \k{nikoli-rect}; I've also seen a Palm implementation at \i{Puzzle Palace} \k{puzzle-palace-rect}. Unlike Puzzle Palace's implementation, my version automatically generates random grids of any size you like. The quality of puzzle design is therefore not quite as good as hand-crafted puzzles would be, but on the plus side you get an inexhaustible supply of puzzles tailored to your own specification. \B{nikoli-rect} \W{http://www.nikoli.co.jp/en/puzzles/shikaku.html}\cw{http://www.nikoli.co.jp/en/puzzles/shikaku.html} (beware of Flash) \B{puzzle-palace-rect} \W{https://web.archive.org/web/20041024001459/http://www.puzzle.gr.jp/puzzle/sikaku/palm/index.html.en}\cw{https://web.archive.org/web/20041024001459/http://www.puzzle.gr.jp/puzzle/sikaku/palm/index.html.en} \H{rectangles-controls} \I{controls, for Rectangles}Rectangles controls This game is played with the mouse or cursor keys. Left-click any edge to toggle it on or off, or left-click and drag to draw an entire rectangle (or line) on the grid in one go (removing any existing edges within that rectangle). Right-clicking and dragging will allow you to erase the contents of a rectangle without affecting its edges. Alternatively, use the cursor keys to move the position indicator around the board. Pressing the return key then allows you to use the cursor keys to drag a rectangle out from that position, and pressing the return key again completes the rectangle. Using the space bar instead of the return key allows you to erase the contents of a rectangle without affecting its edges, as above. Pressing escape cancels a drag. When a rectangle of the correct size is completed, it will be shaded. (All the actions described in \k{common-actions} are also available.) \H{rectangles-params} \I{parameters, for Rectangles}Rectangles parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid, in squares. \dt \e{Expansion factor} \dd This is a mechanism for changing the type of grids generated by the program. Some people prefer a grid containing a few large rectangles to one containing many small ones. So you can ask Rectangles to essentially generate a \e{smaller} grid than the size you specified, and then to expand it by adding rows and columns. \lcont{ The default expansion factor of zero means that Rectangles will simply generate a grid of the size you ask for, and do nothing further. If you set an expansion factor of (say) 0.5, it means that each dimension of the grid will be expanded to half again as big after generation. In other words, the initial grid will be 2/3 the size in each dimension, and will be expanded to its full size without adding any more rectangles. Setting an expansion factor of around 0.5 tends to make the game more difficult, and also (in my experience) rewards a less deductive and more intuitive playing style. If you set it \e{too} high, though, the game simply cannot generate more than a few rectangles to cover the entire grid, and the game becomes trivial. } \dt \e{Ensure unique solution} \dd Normally, Rectangles will make sure that the puzzles it presents have only one solution. Puzzles with ambiguous sections can be more difficult and more subtle, so if you like you can turn off this feature and risk having ambiguous puzzles. Also, finding \e{all} the possible solutions can be an additional challenge for an advanced player. Turning off this option can also speed up puzzle generation. \C{netslide} \i{Netslide} \cfg{winhelp-topic}{games.netslide} This game combines the grid generation of Net (see \k{net}) with the movement of Sixteen (see \k{sixteen}): you have a Net grid, but instead of rotating tiles back into place you have to slide them into place by moving a whole row at a time. As in Sixteen, \I{controls, for Netslide}control is with the mouse or cursor keys. See \k{sixteen-controls}. \I{parameters, for Netslide}The available game parameters have similar meanings to those in Net (see \k{net-params}) and Sixteen (see \k{sixteen-params}). Netslide was contributed to this collection by Richard Boulton. \C{pattern} \i{Pattern} \cfg{winhelp-topic}{games.pattern} You have a grid of squares, which must all be filled in either black or white. Beside each row of the grid are listed the lengths of the runs of black squares on that row; above each column are listed the lengths of the runs of black squares in that column. Your aim is to fill in the entire grid black or white. I first saw this puzzle form around 1995, under the name \q{\i{nonograms}}. I've seen it in various places since then, under different names. Normally, puzzles of this type turn out to be a meaningful picture of something once you've solved them. However, since this version generates the puzzles automatically, they will just look like random groupings of squares. (One user has suggested that this is actually a \e{good} thing, since it prevents you from guessing the colour of squares based on the picture, and forces you to use logic instead.) The advantage, though, is that you never run out of them. \H{pattern-controls} \I{controls, for Pattern}Pattern controls This game is played with the mouse. Left-click in a square to colour it black. Right-click to colour it white. If you make a mistake, you can middle-click, or hold down Shift while clicking with any button, to colour the square in the default grey (meaning \q{undecided}) again. You can click and drag with the left or right mouse button to colour a vertical or horizontal line of squares black or white at a time (respectively). If you click and drag with the middle button, or with Shift held down, you can colour a whole rectangle of squares grey. You can also move around the grid with the cursor keys. Pressing the return key will cycle the current cell through empty, then black, then white, then empty, and the space bar does the same cycle in reverse. Moving the cursor while holding Control will colour the moved-over squares black. Holding Shift will colour the moved-over squares white, and holding both will colour them grey. (All the actions described in \k{common-actions} are also available.) \H{pattern-parameters} \I{parameters, for Pattern}Pattern parameters The only options available from the \q{Custom...} option on the \q{Type} menu are \e{Width} and \e{Height}, which are self-explanatory. \C{solo} \i{Solo} \cfg{winhelp-topic}{games.solo} You have a square grid, which is divided into as many equally sized sub-blocks as the grid has rows. Each square must be filled in with a digit from 1 to the size of the grid, in such a way that \b every row contains only one occurrence of each digit \b every column contains only one occurrence of each digit \b every block contains only one occurrence of each digit. \b (optionally, by default off) each of the square's two main diagonals contains only one occurrence of each digit. You are given some of the numbers as clues; your aim is to place the rest of the numbers correctly. Under the default settings, the sub-blocks are square or rectangular. The default puzzle size is 3\by\.3 (a 9\by\.9 actual grid, divided into nine 3\by\.3 blocks). You can also select sizes with rectangular blocks instead of square ones, such as 2\by\.3 (a 6\by\.6 grid divided into six 3\by\.2 blocks). Alternatively, you can select \q{jigsaw} mode, in which the sub-blocks are arbitrary shapes which differ between individual puzzles. Another available mode is \q{killer}. In this mode, clues are not given in the form of filled-in squares; instead, the grid is divided into \q{cages} by coloured lines, and for each cage the game tells you what the sum of all the digits in that cage should be. Also, no digit may appear more than once within a cage, even if the cage crosses the boundaries of existing regions. If you select a puzzle size which requires more than 9 digits, the additional digits will be letters of the alphabet. For example, if you select 3\by\.4 then the digits which go in your grid will be 1 to 9, plus \cq{a}, \cq{b} and \cq{c}. This cannot be selected for killer puzzles. I first saw this puzzle in \i{Nikoli} \k{nikoli-solo}, although it's also been popularised by various newspapers under the name \q{Sudoku} or \q{Su Doku}. Howard Garns is considered the inventor of the modern form of the puzzle, and it was first published in \e{Dell Pencil Puzzles and Word Games}. A more elaborate treatment of the history of the puzzle can be found on Wikipedia \k{wikipedia-solo}. \B{nikoli-solo} \W{http://www.nikoli.co.jp/en/puzzles/sudoku.html}\cw{http://www.nikoli.co.jp/en/puzzles/sudoku.html} (beware of Flash) \B{wikipedia-solo} \W{http://en.wikipedia.org/wiki/Sudoku}\cw{http://en.wikipedia.org/wiki/Sudoku} \H{solo-controls} \I{controls, for Solo}Solo controls To play Solo, simply click the mouse in any empty square and then type a digit or letter on the keyboard to fill that square. If you make a mistake, click the mouse in the incorrect square and press Space to clear it again (or use the Undo feature). If you \e{right}-click in a square and then type a number, that number will be entered in the square as a \q{pencil mark}. You can have pencil marks for multiple numbers in the same square. Squares containing filled-in numbers cannot also contain pencil marks. The game pays no attention to pencil marks, so exactly what you use them for is up to you: you can use them as reminders that a particular square needs to be re-examined once you know more about a particular number, or you can use them as lists of the possible numbers in a given square, or anything else you feel like. To erase a single pencil mark, right-click in the square and type the same number again. All pencil marks in a square are erased when you left-click and type a number, or when you left-click and press space. Right-clicking and pressing space will also erase pencil marks. Alternatively, use the cursor keys to move the mark around the grid. Pressing the return key toggles the mark (from a normal mark to a pencil mark), and typing a number in is entered in the square in the appropriate way; typing in a 0 or using the space bar will clear a filled square. (All the actions described in \k{common-actions} are also available.) \H{solo-parameters} \I{parameters, for Solo}Solo parameters Solo allows you to configure two separate dimensions of the puzzle grid on the \q{Type} menu: the number of columns, and the number of rows, into which the main grid is divided. (The size of a block is the inverse of this: for example, if you select 2 columns and 3 rows, each actual block will have 3 columns and 2 rows.) If you tick the \q{X} checkbox, Solo will apply the optional extra constraint that the two main diagonals of the grid also contain one of every digit. (This is sometimes known as \q{Sudoku-X} in newspapers.) In this mode, the squares on the two main diagonals will be shaded slightly so that you know it's enabled. If you tick the \q{Jigsaw} checkbox, Solo will generate randomly shaped sub-blocks. In this mode, the actual grid size will be taken to be the product of the numbers entered in the \q{Columns} and \q{Rows} boxes. There is no reason why you have to enter a number greater than 1 in both boxes; Jigsaw mode has no constraint on the grid size, and it can even be a prime number if you feel like it. If you tick the \q{Killer} checkbox, Solo will generate a set of of cages, which are randomly shaped and drawn in an outline of a different colour. Each of these regions contains a smaller clue which shows the digit sum of all the squares in this region. You can also configure the type of symmetry shown in the generated puzzles. More symmetry makes the puzzles look prettier but may also make them easier, since the symmetry constraints can force more clues than necessary to be present. Completely asymmetric puzzles have the freedom to contain as few clues as possible. Finally, you can configure the difficulty of the generated puzzles. Difficulty levels are judged by the complexity of the techniques of deduction required to solve the puzzle: each level requires a mode of reasoning which was not necessary in the previous one. In particular, on difficulty levels \q{Trivial} and \q{Basic} there will be a square you can fill in with a single number at all times, whereas at \q{Intermediate} level and beyond you will have to make partial deductions about the \e{set} of squares a number could be in (or the set of numbers that could be in a square). \#{Advanced, Extreme?} At \q{Unreasonable} level, even this is not enough, and you will eventually have to make a guess, and then backtrack if it turns out to be wrong. Generating difficult puzzles is itself difficult: if you select one of the higher difficulty levels, Solo may have to make many attempts at generating a puzzle before it finds one hard enough for you. Be prepared to wait, especially if you have also configured a large puzzle size. \C{mines} \i{Mines} \cfg{winhelp-topic}{games.mines} You have a grid of covered squares, some of which contain mines, but you don't know which. Your job is to uncover every square which does \e{not} contain a mine. If you uncover a square containing a mine, you lose. If you uncover a square which does not contain a mine, you are told how many mines are contained within the eight surrounding squares. This game needs no introduction; popularised by Windows, it is perhaps the single best known desktop puzzle game in existence. This version of it has an unusual property. By default, it will generate its mine positions in such a way as to ensure that you never need to \e{guess} where a mine is: you will always be able to deduce it somehow. So you will never, as can happen in other versions, get to the last four squares and discover that there are two mines left but you have no way of knowing for sure where they are. \H{mines-controls} \I{controls, for Mines}Mines controls This game is played with the mouse. If you left-click in a covered square, it will be uncovered. If you right-click in a covered square, it will place a flag which indicates that the square is believed to be a mine. Left-clicking in a marked square will not uncover it, for safety. You can right-click again to remove a mark placed in error. If you left-click in an \e{uncovered} square, it will \q{clear around} the square. This means: if the square has exactly as many flags surrounding it as it should have mines, then all the covered squares next to it which are \e{not} flagged will be uncovered. So once you think you know the location of all the mines around a square, you can use this function as a shortcut to avoid having to click on each of the remaining squares one by one. If you uncover a square which has \e{no} mines in the surrounding eight squares, then it is obviously safe to uncover those squares in turn, and so on if any of them also has no surrounding mines. This will be done for you automatically; so sometimes when you uncover a square, a whole new area will open up to be explored. You can also use the cursor keys to move around the minefield. Pressing the return key in a covered square uncovers it, and in an uncovered square will clear around it (so it acts as the left button), pressing the space bar in a covered square will place a flag (similarly, it acts as the right button). All the actions described in \k{common-actions} are also available. Even Undo is available, although you might consider it cheating to use it. If you step on a mine, the program will only reveal the mine in question (unlike most other implementations, which reveal all of them). You can then Undo your fatal move and continue playing if you like. The program will track the number of times you died (and Undo will not reduce that counter), so when you get to the end of the game you know whether or not you did it without making any errors. (If you really want to know the full layout of the grid, which other implementations will show you after you die, you can always use the Solve menu option.) \H{mines-parameters} \I{parameters, for Mines}Mines parameters The options available from the \q{Custom...} option on the \q{Type} menu are: \dt \e{Width}, \e{Height} \dd Size of grid in squares. \dt \e{Mines} \dd Number of mines in the grid. You can enter this as an absolute mine count, or alternatively you can put a \cw{%} sign on the end in which case the game will arrange for that proportion of the squares in the grid to be mines. \lcont{ Beware of setting the mine count too high. At very high densities, the program may spend forever searching for a solvable grid. } \dt \e{Ensure solubility} \dd When this option is enabled (as it is by default), Mines will ensure that the entire grid can be fully deduced starting from the initial open space. If you prefer the riskier grids generated by other implementations, you can switch off this option. \C{samegame} \i{Same Game} \cfg{winhelp-topic}{games.samegame} You have a grid of coloured squares, which you have to clear by highlighting contiguous regions of more than one coloured square; the larger the region you highlight, the more points you get (and the faster you clear the arena). If you clear the grid you win. If you end up with nothing but single squares (i.e., there are no more clickable regions left) you lose. Removing a region causes the rest of the grid to shuffle up: blocks that are suspended will fall down (first), and then empty columns are filled from the right. Same Game was contributed to this collection by James Harvey. \H{samegame-controls} \i{Same Game controls} \IM{Same Game controls} controls, for Same Game \IM{Same Game controls} keys, for Same Game \IM{Same Game controls} shortcuts (keyboard), for Same Game This game can be played with either the keyboard or the mouse. If you left-click an unselected region, it becomes selected (possibly clearing the current selection). If you left-click the selected region, it will be removed (and the rest of the grid shuffled immediately). If you right-click the selected region, it will be unselected. The cursor keys move a cursor around the grid. Pressing the Space or Enter keys while the cursor is in an unselected region selects it; pressing Space or Enter again removes it as above. (All the actions described in \k{common-actions} are also available.) \H{samegame-parameters} \I{parameters, for Same Game}Same Game parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid in squares. \dt \e{No. of colours} \dd Number of different colours used to fill the grid; the more colours, the fewer large regions of colour and thus the more difficult it is to successfully clear the grid. \dt \e{Scoring system} \dd Controls the precise mechanism used for scoring. With the default system, \q{(n-2)^2}, only regions of three squares or more will score any points at all. With the alternative \q{(n-1)^2} system, regions of two squares score a point each, and larger regions score relatively more points. \dt \e{Ensure solubility} \dd If this option is ticked (the default state), generated grids will be guaranteed to have at least one solution. \lcont{ If you turn it off, the game generator will not try to guarantee soluble grids; it will, however, still ensure that there are at least 2 squares of each colour on the grid at the start (since a grid with exactly one square of a given colour is \e{definitely} insoluble). Grids generated with this option disabled may contain more large areas of contiguous colour, leading to opportunities for higher scores; they can also take less time to generate. } \C{flip} \i{Flip} \cfg{winhelp-topic}{games.flip} You have a grid of squares, some light and some dark. Your aim is to light all the squares up at the same time. You can choose any square and flip its state from light to dark or dark to light, but when you do so, other squares around it change state as well. Each square contains a small diagram showing which other squares change when you flip it. \H{flip-controls} \i{Flip controls} \IM{Flip controls} controls, for Flip \IM{Flip controls} keys, for Flip \IM{Flip controls} shortcuts (keyboard), for Flip This game can be played with either the keyboard or the mouse. Left-click in a square to flip it and its associated squares, or use the cursor keys to choose a square and the space bar or Enter key to flip. If you use the \q{Solve} function on this game, it will mark some of the squares in red. If you click once in every square with a red mark, the game should be solved. (If you click in a square \e{without} a red mark, a red mark will appear in it to indicate that you will need to reverse that operation to reach the solution.) (All the actions described in \k{common-actions} are also available.) \H{flip-parameters} \I{parameters, for flip}Flip parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid in squares. \dt \e{Shape type} \dd This control determines the shape of the region which is flipped by clicking in any given square. The default setting, \q{Crosses}, causes every square to flip itself and its four immediate neighbours (or three or two if it's at an edge or corner). The other setting, \q{Random}, causes a random shape to be chosen for every square, so the game is different every time. \C{guess} \i{Guess} \cfg{winhelp-topic}{games.guess} You have a set of coloured pegs, and have to reproduce a predetermined sequence of them (chosen by the computer) within a certain number of guesses. Each guess gets marked with the number of correctly-coloured pegs in the correct places (in black), and also the number of correctly-coloured pegs in the wrong places (in white). This game is also known (and marketed, by Hasbro, mainly) as a board game \q{\i{Mastermind}}, with 6 colours, 4 pegs per row, and 10 guesses. However, this version allows custom settings of number of colours (up to 10), number of pegs per row, and number of guesses. Guess was contributed to this collection by James Harvey. \H{guess-controls} \i{Guess controls} \IM{Guess controls} controls, for Guess \IM{Guess controls} keys, for Guess \IM{Guess controls} shortcuts (keyboard), for Guess This game can be played with either the keyboard or the mouse. With the mouse, drag a coloured peg from the tray on the left-hand side to its required position in the current guess; pegs may also be dragged from current and past guesses to copy them elsewhere. To remove a peg, drag it off its current position to somewhere invalid. Right-clicking in the current guess adds a \q{hold} marker; pegs that have hold markers will be automatically added to the next guess after marking. Alternatively, with the keyboard, the up and down cursor keys can be used to select a peg colour, the left and right keys to select a peg position, and the space bar or Enter key to place a peg of the selected colour in the chosen position. \q{D} or Backspace removes a peg, and Space adds a hold marker. Pressing \q{h} or \q{?} will fill the current guess with a suggested guess. Using this is not recommended for 10 or more pegs as it is slow. When the guess is complete, the smaller feedback pegs will be highlighted; clicking on these (or moving the peg cursor to them with the arrow keys and pressing the space bar or Enter key) will mark the current guess, copy any held pegs to the next guess, and move the \q{current guess} marker. If you correctly position all the pegs the solution will be displayed below; if you run out of guesses (or select \q{Solve...}) the solution will also be revealed. (All the actions described in \k{common-actions} are also available.) \H{guess-parameters} \I{parameters, for Guess}Guess parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. The default game matches the parameters for the board game \q{Mastermind}. \dt \e{Colours} \dd Number of colours the solution is chosen from; from 2 to 10 (more is harder). \dt \e{Pegs per guess} \dd Number of pegs per guess (more is harder). \dt \e{Guesses} \dd Number of guesses you have to find the solution in (fewer is harder). \dt \e{Allow blanks} \dd Allows blank pegs to be given as part of a guess (makes it easier, because you know that those will never be counted as part of the solution). This is turned off by default. \lcont{ Note that this doesn't allow blank pegs in the solution; if you really wanted that, use one extra colour. } \dt \e{Allow duplicates} \dd Allows the solution (and the guesses) to contain colours more than once; this increases the search space (making things harder), and is turned on by default. \C{pegs} \i{Pegs} \cfg{winhelp-topic}{games.pegs} A number of pegs are placed in holes on a board. You can remove a peg by jumping an adjacent peg over it (horizontally or vertically) to a vacant hole on the other side. Your aim is to remove all but one of the pegs initially present. This game, best known as \I{Solitaire, Peg}\q{Peg Solitaire}, is possibly one of the oldest puzzle games still commonly known. \H{pegs-controls} \i{Pegs controls} \IM{Pegs controls} controls, for Pegs To move a peg, drag it with the mouse from its current position to its final position. If the final position is exactly two holes away from the initial position, is currently unoccupied by a peg, and there is a peg in the intervening square, the move will be permitted and the intervening peg will be removed. Vacant spaces which you can move a peg into are marked with holes. A space with no peg and no hole is not available for moving at all: it is an obstacle which you must work around. You can also use the cursor keys to move a position indicator around the board. Pressing the return key while over a peg, followed by a cursor key, will jump the peg in that direction (if that is a legal move). (All the actions described in \k{common-actions} are also available.) \H{pegs-parameters} \I{parameters, for Pegs}Pegs parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid in holes. \dt \e{Board type} \dd Controls whether you are given a board of a standard shape or a randomly generated shape. The two standard shapes currently supported are \q{Cross} and \q{Octagon} (also commonly known as the English and European traditional board layouts respectively). Selecting \q{Random} will give you a different board shape every time (but always one that is known to have a solution). \C{dominosa} \i{Dominosa} \cfg{winhelp-topic}{games.dominosa} A normal set of dominoes \dash that is, one instance of every (unordered) pair of numbers from 0 to 6 \dash has been arranged irregularly into a rectangle; then the number in each square has been written down and the dominoes themselves removed. Your task is to reconstruct the pattern by arranging the set of dominoes to match the provided array of numbers. This puzzle is widely credited to O. S. Adler, and takes part of its name from those initials. \H{dominosa-controls} \i{Dominosa controls} \IM{Dominosa controls} controls, for Dominosa Left-clicking between any two adjacent numbers places a domino covering them, or removes one if it is already present. Trying to place a domino which overlaps existing dominoes will remove the ones it overlaps. Right-clicking between two adjacent numbers draws a line between them, which you can use to remind yourself that you know those two numbers are \e{not} covered by a single domino. Right-clicking again removes the line. You can also use the cursor keys to move a cursor around the grid. When the cursor is half way between two adjacent numbers, pressing the return key will place a domino covering those numbers, or pressing the space bar will lay a line between the two squares. Repeating either action removes the domino or line. Pressing a number key will highlight all occurrences of that number. Pressing that number again will clear the highlighting. Up to two different numbers can be highlighted at any given time. (All the actions described in \k{common-actions} are also available.) \H{dominosa-parameters} \I{parameters, for Dominosa}Dominosa parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Maximum number on dominoes} \dd Controls the size of the puzzle, by controlling the size of the set of dominoes used to make it. Dominoes with numbers going up to N will give rise to an (N+2) \by (N+1) rectangle; so, in particular, the default value of 6 gives an 8\by\.7 grid. \dt \e{Ensure unique solution} \dd Normally, Dominosa will make sure that the puzzles it presents have only one solution. Puzzles with ambiguous sections can be more difficult and sometimes more subtle, so if you like you can turn off this feature. Also, finding \e{all} the possible solutions can be an additional challenge for an advanced player. Turning off this option can also speed up puzzle generation. \C{untangle} \i{Untangle} \cfg{winhelp-topic}{games.untangle} You are given a number of points, some of which have lines drawn between them. You can move the points about arbitrarily; your aim is to position the points so that no line crosses another. I originally saw this in the form of a Flash game called \i{Planarity} \k{Planarity}, written by John Tantalo. \B{Planarity} \W{http://planarity.net}\cw{http://planarity.net} \H{untangle-controls} \i{Untangle controls} \IM{Untangle controls} controls, for Untangle To move a point, click on it with the left mouse button and drag it into a new position. (All the actions described in \k{common-actions} are also available.) \H{untangle-parameters} \I{parameters, for Untangle}Untangle parameters There is only one parameter available from the \q{Custom...} option on the \q{Type} menu: \dt \e{Number of points} \dd Controls the size of the puzzle, by specifying the number of points in the generated graph. \C{blackbox} \i{Black Box} \cfg{winhelp-topic}{games.blackbox} A number of balls are hidden in a rectangular arena. You have to deduce the positions of the balls by firing lasers positioned at the edges of the arena and observing how their beams are deflected. Beams will travel straight from their origin until they hit the opposite side of the arena (at which point they emerge), unless affected by balls in one of the following ways: \b A beam that hits a ball head-on is absorbed and will never re-emerge. This includes beams that meet a ball on the first rank of the arena. \b A beam with a ball in its front-left square and no ball ahead of it gets deflected 90 degrees to the right. \b A beam with a ball in its front-right square and no ball ahead of it gets similarly deflected to the left. \b A beam that would re-emerge from its entry location is considered to be \q{reflected}. \b A beam which would get deflected before entering the arena by a ball to the front-left or front-right of its entry point is also considered to be \q{reflected}. Beams that are reflected appear as a \q{R}; beams that hit balls head-on appear as \q{H}. Otherwise, a number appears at the firing point and the location where the beam emerges (this number is unique to that shot). You can place guesses as to the location of the balls, based on the entry and exit patterns of the beams; once you have placed enough balls a button appears enabling you to have your guesses checked. Here is a diagram showing how the positions of balls can create each of the beam behaviours shown above: \c 1RHR---- \c |..O.O...| \c 2........3 \c |........| \c |........| \c 3........| \c |......O.| \c H........| \c |.....O..| \c 12-RR--- As shown, it is possible for a beam to receive multiple reflections before re-emerging (see turn 3). Similarly, a beam may be reflected (possibly more than once) before receiving a hit (the \q{H} on the left side of the example). Note that any layout with more than 4 balls may have a non-unique solution. The following diagram illustrates this; if you know the board contains 5 balls, it is impossible to determine where the fifth ball is (possible positions marked with an \cw{x}): \c -------- \c |........| \c |........| \c |..O..O..| \c |...xx...| \c |...xx...| \c |..O..O..| \c |........| \c |........| \c -------- For this reason, when you have your guesses checked, the game will check that your solution \e{produces the same results} as the computer's, rather than that your solution is identical to the computer's. So in the above example, you could put the fifth ball at \e{any} of the locations marked with an \cw{x}, and you would still win. Black Box was contributed to this collection by James Harvey. \H{blackbox-controls} \i{Black Box controls} \IM{Black Box controls} controls, for Black Box \IM{Black Box controls} keys, for Black Box \IM{Black Box controls} shortcuts (keyboard), for Black Box To fire a laser beam, left-click in a square around the edge of the arena. The results will be displayed immediately. Clicking or holding the left button on one of these squares will highlight the current go (or a previous go) to confirm the exit point for that laser, if applicable. To guess the location of a ball, left-click within the arena and a black circle will appear marking the guess; click again to remove the guessed ball. Locations in the arena may be locked against modification by right-clicking; whole rows and columns may be similarly locked by right-clicking in the laser square above/below that column, or to the left/right of that row. The cursor keys may also be used to move around the grid. Pressing the Enter key will fire a laser or add a new ball-location guess, and pressing Space will lock a cell, row, or column. When an appropriate number of balls have been guessed, a button will appear at the top-left corner of the grid; clicking that (with mouse or cursor) will check your guesses. If you click the \q{check} button and your guesses are not correct, the game will show you the minimum information necessary to demonstrate this to you, so you can try again. If your ball positions are not consistent with the beam paths you already know about, one beam path will be circled to indicate that it proves you wrong. If your positions match all the existing beam paths but are still wrong, one new beam path will be revealed (written in red) which is not consistent with your current guesses. If you decide to give up completely, you can select Solve to reveal the actual ball positions. At this point, correctly-placed balls will be displayed as filled black circles, incorrectly-placed balls as filled black circles with red crosses, and missing balls as filled red circles. In addition, a red circle marks any laser you had already fired which is not consistent with your ball layout (just as when you press the \q{check} button), and red text marks any laser you \e{could} have fired in order to distinguish your ball layout from the correct one. (All the actions described in \k{common-actions} are also available.) \H{blackbox-parameters} \I{parameters, for Black Box}Black Box parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid in squares. There are 2 \by \e{Width} \by \e{Height} lasers per grid, two per row and two per column. \dt \e{No. of balls} \dd Number of balls to place in the grid. This can be a single number, or a range (separated with a hyphen, like \q{2-6}), and determines the number of balls to place on the grid. The \q{reveal} button is only enabled if you have guessed an appropriate number of balls; a guess using a different number to the original solution is still acceptable, if all the beam inputs and outputs match. \C{slant} \i{Slant} \cfg{winhelp-topic}{games.slant} You have a grid of squares. Your aim is to draw a diagonal line through each square, and choose which way each line slants so that the following conditions are met: \b The diagonal lines never form a loop. \b Any point with a circled number has precisely that many lines meeting at it. (Thus, a 4 is the centre of a cross shape, whereas a zero is the centre of a diamond shape \dash or rather, a partial diamond shape, because a zero can never appear in the middle of the grid because that would immediately cause a loop.) Credit for this puzzle goes to \i{Nikoli} \k{nikoli-slant}. \B{nikoli-slant} \W{http://www.nikoli.co.jp/ja/puzzles/gokigen_naname}\cw{http://www.nikoli.co.jp/ja/puzzles/gokigen_naname} (in Japanese) \H{slant-controls} \i{Slant controls} \IM{Slant controls} controls, for Slant Left-clicking in a blank square will place a \cw{\\} in it (a line leaning to the left, i.e. running from the top left of the square to the bottom right). Right-clicking in a blank square will place a \cw{/} in it (leaning to the right, running from top right to bottom left). Continuing to click either button will cycle between the three possible square contents. Thus, if you left-click repeatedly in a blank square it will change from blank to \cw{\\} to \cw{/} back to blank, and if you right-click repeatedly the square will change from blank to \cw{/} to \cw{\\} back to blank. (Therefore, you can play the game entirely with one button if you need to.) You can also use the cursor keys to move around the grid. Pressing the return or space keys will place a \cw{\\} or a \cw{/}, respectively, and will then cycle them as above. You can also press \cw{/} or \cw{\\} to place a \cw{/} or \cw{\\}, respectively, independent of what is already in the cursor square. Backspace removes any line from the cursor square. (All the actions described in \k{common-actions} are also available.) \H{slant-parameters} \I{parameters, for Slant}Slant parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid in squares. \dt \e{Difficulty} \dd Controls the difficulty of the generated puzzle. At Hard level, you are required to do deductions based on knowledge of \e{relationships} between squares rather than always being able to deduce the exact contents of one square at a time. (For example, you might know that two squares slant in the same direction, even if you don't yet know what that direction is, and this might enable you to deduce something about still other squares.) Even at Hard level, guesswork and backtracking should never be necessary. \C{lightup} \i{Light Up} \cfg{winhelp-topic}{games.lightup} You have a grid of squares. Some are filled in black; some of the black squares are numbered. Your aim is to \q{light up} all the empty squares by placing light bulbs in some of them. Each light bulb illuminates the square it is on, plus all squares in line with it horizontally or vertically unless a black square is blocking the way. To win the game, you must satisfy the following conditions: \b All non-black squares are lit. \b No light is lit by another light. \b All numbered black squares have exactly that number of lights adjacent to them (in the four squares above, below, and to the side). Non-numbered black squares may have any number of lights adjacent to them. Credit for this puzzle goes to \i{Nikoli} \k{nikoli-lightup}. Light Up was contributed to this collection by James Harvey. \B{nikoli-lightup} \W{http://www.nikoli.co.jp/en/puzzles/akari.html}\cw{http://www.nikoli.co.jp/en/puzzles/akari.html} (beware of Flash) \H{lightup-controls} \i{Light Up controls} \IM{Light Up controls} controls, for Light Up Left-clicking in a non-black square will toggle the presence of a light in that square. Right-clicking in a non-black square toggles a mark there to aid solving; it can be used to highlight squares that cannot be lit, for example. You may not place a light in a marked square, nor place a mark in a lit square. The game will highlight obvious errors in red. Lights lit by other lights are highlighted in this way, as are numbered squares which do not (or cannot) have the right number of lights next to them. Thus, the grid is solved when all non-black squares have yellow highlights and there are no red lights. (All the actions described in \k{common-actions} are also available.) \H{lightup-parameters} \I{parameters, for Light Up}Light Up parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid in squares. \dt \e{%age of black squares} \dd Rough percentage of black squares in the grid. \lcont{ This is a hint rather than an instruction. If the grid generator is unable to generate a puzzle to this precise specification, it will increase the proportion of black squares until it can. } \dt \e{Symmetry} \dd Allows you to specify the required symmetry of the black squares in the grid. (This does not affect the difficulty of the puzzles noticeably.) \dt \e{Difficulty} \dd \q{Easy} means that the puzzles should be soluble without backtracking or guessing, \q{Hard} means that some guesses will probably be necessary. \C{map} \i{Map} \cfg{winhelp-topic}{games.map} You are given a map consisting of a number of regions. Your task is to colour each region with one of four colours, in such a way that no two regions sharing a boundary have the same colour. You are provided with some regions already coloured, sufficient to make the remainder of the solution unique. Only regions which share a length of border are required to be different colours. Two regions which meet at only one \e{point} (i.e. are diagonally separated) may be the same colour. I believe this puzzle is original; I've never seen an implementation of it anywhere else. The concept of a \i{four-colouring} puzzle was suggested by Owen Dunn; credit must also go to Nikoli and to Verity Allan for inspiring the train of thought that led to me realising Owen's suggestion was a viable puzzle. Thanks also to Gareth Taylor for many detailed suggestions. \H{map-controls} \i{Map controls} \IM{Map controls} controls, for Map To colour a region, click the left mouse button on an existing region of the desired colour and drag that colour into the new region. (The program will always ensure the starting puzzle has at least one region of each colour, so that this is always possible!) If you need to clear a region, you can drag from an empty region, or from the puzzle boundary if there are no empty regions left. Dragging a colour using the \e{right} mouse button will stipple the region in that colour, which you can use as a note to yourself that you think the region \e{might} be that colour. A region can contain stipples in multiple colours at once. (This is often useful at the harder difficulty levels.) You can also use the cursor keys to move around the map: the colour of the cursor indicates the position of the colour you would drag (which is not obvious if you're on a region's boundary, since it depends on the direction from which you approached the boundary). Pressing the return key starts a drag of that colour, as above, which you control with the cursor keys; pressing the return key again finishes the drag. The space bar can be used similarly to create a stippled region. Double-pressing the return key (without moving the cursor) will clear the region, as a drag from an empty region does: this is useful with the cursor mode if you have filled the entire map in but need to correct the layout. If you press L during play, the game will toggle display of a number in each region of the map. This is useful if you want to discuss a particular puzzle instance with a friend \dash having an unambiguous name for each region is much easier than trying to refer to them all by names such as \q{the one down and right of the brown one on the top border}. (All the actions described in \k{common-actions} are also available.) \H{map-parameters} \I{parameters, for Map}Map parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid in squares. \dt \e{Regions} \dd Number of regions in the generated map. \dt \e{Difficulty} \dd In \q{Easy} mode, there should always be at least one region whose colour can be determined trivially. In \q{Normal} and \q{Hard} modes, you will have to use increasingly complex logic to deduce the colour of some regions. However, it will always be possible without having to guess or backtrack. \lcont{ In \q{Unreasonable} mode, the program will feel free to generate puzzles which are as hard as it can possibly make them: the only constraint is that they should still have a unique solution. Solving Unreasonable puzzles may require guessing and backtracking. } \C{loopy} \i{Loopy} \cfg{winhelp-topic}{games.loopy} You are given a grid of dots, marked with yellow lines to indicate which dots you are allowed to connect directly together. Your aim is to use some subset of those yellow lines to draw a single unbroken loop from dot to dot within the grid. Some of the spaces between the lines contain numbers. These numbers indicate how many of the lines around that space form part of the loop. The loop you draw must correctly satisfy all of these clues to be considered a correct solution. In the default mode, the dots are arranged in a grid of squares; however, you can also play on triangular or hexagonal grids, or even more exotic ones. Credit for the basic puzzle idea goes to \i{Nikoli} \k{nikoli-loopy}. Loopy was originally contributed to this collection by Mike Pinna, and subsequently enhanced to handle various types of non-square grid by Lambros Lambrou. \B{nikoli-loopy} \W{http://www.nikoli.co.jp/en/puzzles/slitherlink.html}\cw{http://www.nikoli.co.jp/en/puzzles/slitherlink.html} (beware of Flash) \H{loopy-controls} \i{Loopy controls} \IM{Loopy controls} controls, for Loopy Click the left mouse button on a yellow line to turn it black, indicating that you think it is part of the loop. Click again to turn the line yellow again (meaning you aren't sure yet). If you are sure that a particular line segment is \e{not} part of the loop, you can click the right mouse button to remove it completely. Again, clicking a second time will turn the line back to yellow. (All the actions described in \k{common-actions} are also available.) \H{loopy-parameters} \I{parameters, for Loopy}Loopy parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid, measured in number of regions across and down. For square grids, it's clear how this is counted; for other types of grid you may have to think a bit to see how the dimensions are measured. \dt \e{Grid type} \dd Allows you to choose between a selection of types of tiling. Some have all the faces the same but may have multiple different types of vertex (e.g. the \e{Cairo} or \e{Kites} mode); others have all the vertices the same but may have different types of face (e.g. the \e{Great Hexagonal}). The square, triangular and honeycomb grids are fully regular, and have all their vertices \e{and} faces the same; this makes them the least confusing to play. \dt \e{Difficulty} \dd Controls the difficulty of the generated puzzle. \#{FIXME: what distinguishes Easy, Medium, and Hard? In particular, when are backtracking/guesswork required, if ever?} \C{inertia} \i{Inertia} \cfg{winhelp-topic}{games.inertia} You are a small green ball sitting in a grid full of obstacles. Your aim is to collect all the gems without running into any mines. You can move the ball in any orthogonal \e{or diagonal} direction. Once the ball starts moving, it will continue until something stops it. A wall directly in its path will stop it (but if it is moving diagonally, it will move through a diagonal gap between two other walls without stopping). Also, some of the squares are \q{stops}; when the ball moves on to a stop, it will stop moving no matter what direction it was going in. Gems do \e{not} stop the ball; it picks them up and keeps on going. Running into a mine is fatal. Even if you picked up the last gem in the same move which then hit a mine, the game will count you as dead rather than victorious. This game was originally implemented for Windows by Ben Olmstead \k{bem}, who was kind enough to release his source code on request so that it could be re-implemented for this collection. \B{bem} \W{http://xn13.com/}\cw{http://xn13.com/} \H{inertia-controls} \i{Inertia controls} \IM{Inertia controls} controls, for Inertia \IM{Inertia controls} keys, for Inertia \IM{Inertia controls} shortcuts (keyboard), for Inertia You can move the ball in any of the eight directions using the numeric keypad. Alternatively, if you click the left mouse button on the grid, the ball will begin a move in the general direction of where you clicked. If you use the \q{Solve} function on this game, the program will compute a path through the grid which collects all the remaining gems and returns to the current position. A hint arrow will appear on the ball indicating the direction in which you should move to begin on this path. If you then move in that direction, the arrow will update to indicate the next direction on the path. You can also press Space to automatically move in the direction of the hint arrow. If you move in a different direction from the one shown by the arrow, arrows will be shown only if the puzzle is still solvable. All the actions described in \k{common-actions} are also available. In particular, if you do run into a mine and die, you can use the Undo function and resume playing from before the fatal move. The game will keep track of the number of times you have done this. \H{inertia-parameters} \I{parameters, for Inertia}Inertia parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid in squares. \C{tents} \i{Tents} \cfg{winhelp-topic}{games.tents} You have a grid of squares, some of which contain trees. Your aim is to place tents in some of the remaining squares, in such a way that the following conditions are met: \b There are exactly as many tents as trees. \b The tents and trees can be matched up in such a way that each tent is directly adjacent (horizontally or vertically, but not diagonally) to its own tree. However, a tent may be adjacent to other trees as well as its own. \b No two tents are adjacent horizontally, vertically \e{or diagonally}. \b The number of tents in each row, and in each column, matches the numbers given round the sides of the grid. This puzzle can be found in several places on the Internet, and was brought to my attention by e-mail. I don't know who I should credit for inventing it. \H{tents-controls} \i{Tents controls} \IM{Tents controls} controls, for Tents Left-clicking in a blank square will place a tent in it. Right-clicking in a blank square will colour it green, indicating that you are sure it \e{isn't} a tent. Clicking either button in an occupied square will clear it. If you \e{drag} with the right button along a row or column, every blank square in the region you cover will be turned green, and no other squares will be affected. (This is useful for clearing the remainder of a row once you have placed all its tents.) You can also use the cursor keys to move around the grid. Pressing the return key over an empty square will place a tent, and pressing the space bar over an empty square will colour it green; either key will clear an occupied square. Holding Shift and pressing the cursor keys will colour empty squares green. Holding Control and pressing the cursor keys will colour green both empty squares and squares with tents. (All the actions described in \k{common-actions} are also available.) \H{tents-parameters} \I{parameters, for Tents}Tents parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid in squares. \dt \e{Difficulty} \dd Controls the difficulty of the generated puzzle. More difficult puzzles require more complex deductions, but at present none of the available difficulty levels requires guesswork or backtracking. \C{bridges} \i{Bridges} \cfg{winhelp-topic}{games.bridges} You have a set of islands distributed across the playing area. Each island contains a number. Your aim is to connect the islands together with bridges, in such a way that: \b Bridges run horizontally or vertically. \b The number of bridges terminating at any island is equal to the number written in that island. \b Two bridges may run in parallel between the same two islands, but no more than two may do so. \b No bridge crosses another bridge. \b All the islands are connected together. There are some configurable alternative modes, which involve changing the parallel-bridge limit to something other than 2, and introducing the additional constraint that no sequence of bridges may form a loop from one island back to the same island. The rules stated above are the default ones. Credit for this puzzle goes to \i{Nikoli} \k{nikoli-bridges}. Bridges was contributed to this collection by James Harvey. \B{nikoli-bridges} \W{http://www.nikoli.co.jp/en/puzzles/hashiwokakero.html}\cw{http://www.nikoli.co.jp/en/puzzles/hashiwokakero.html} (beware of Flash) \H{bridges-controls} \i{Bridges controls} \IM{Bridges controls} controls, for Bridges To place a bridge between two islands, click the mouse down on one island and drag it towards the other. You do not need to drag all the way to the other island; you only need to move the mouse far enough for the intended bridge direction to be unambiguous. (So you can keep the mouse near the starting island and conveniently throw bridges out from it in many directions.) Doing this again when a bridge is already present will add another parallel bridge. If there are already as many bridges between the two islands as permitted by the current game rules (i.e. two by default), the same dragging action will remove all of them. If you want to remind yourself that two islands definitely \e{do not} have a bridge between them, you can right-drag between them in the same way to draw a \q{non-bridge} marker. If you think you have finished with an island (i.e. you have placed all its bridges and are confident that they are in the right places), you can mark the island as finished by left-clicking on it. This will highlight it and all the bridges connected to it, and you will be prevented from accidentally modifying any of those bridges in future. Left-clicking again on a highlighted island will unmark it and restore your ability to modify it. You can also use the cursor keys to move around the grid: if possible the cursor will always move orthogonally, otherwise it will move towards the nearest island to the indicated direction. Holding Control and pressing a cursor key will lay a bridge in that direction (if available); Shift and a cursor key will lay a \q{non-bridge} marker. Pressing the return key followed by a cursor key will also lay a bridge in that direction. You can mark an island as finished by pressing the space bar or by pressing the return key twice. By pressing a number key, you can jump to the nearest island with that number. Letters \q{a}, ..., \q{f} count as 10, ..., 15 and \q{0} as 16. Violations of the puzzle rules will be marked in red: \b An island with too many bridges will be highlighted in red. \b An island with too few bridges will be highlighted in red if it is definitely an error (as opposed to merely not being finished yet): if adding enough bridges would involve having to cross another bridge or remove a non-bridge marker, or if the island has been highlighted as complete. \b A group of islands and bridges may be highlighted in red if it is a closed subset of the puzzle with no way to connect it to the rest of the islands. For example, if you directly connect two 1s together with a bridge and they are not the only two islands on the grid, they will light up red to indicate that such a group cannot be contained in any valid solution. \b If you have selected the (non-default) option to disallow loops in the solution, a group of bridges which forms a loop will be highlighted. (All the actions described in \k{common-actions} are also available.) \H{bridges-parameters} \I{parameters, for Bridges}Bridges parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid in squares. \dt \e{Difficulty} \dd Difficulty level of puzzle. \dt \e{Allow loops} \dd This is set by default. If cleared, puzzles will be generated in such a way that they are always soluble without creating a loop, and solutions which do involve a loop will be disallowed. \dt \e{Max. bridges per direction} \dd Maximum number of bridges in any particular direction. The default is 2, but you can change it to 1, 3 or 4. In general, fewer is easier. \dt \e{%age of island squares} \dd Gives a rough percentage of islands the generator will try and lay before finishing the puzzle. Certain layouts will not manage to lay enough islands; this is an upper bound. \dt \e{Expansion factor (%age)} \dd The grid generator works by picking an existing island at random (after first creating an initial island somewhere). It then decides on a direction (at random), and then works out how far it could extend before creating another island. This parameter determines how likely it is to extend as far as it can, rather than choosing somewhere closer. \lcont{ High expansion factors usually mean easier puzzles with fewer possible islands; low expansion factors can create lots of tightly-packed islands. } \C{unequal} \i{Unequal} \cfg{winhelp-topic}{games.unequal} You have a square grid; each square may contain a digit from 1 to the size of the grid, and some squares have clue signs between them. Your aim is to fully populate the grid with numbers such that: \b Each row contains only one occurrence of each digit \b Each column contains only one occurrence of each digit \b All the clue signs are satisfied. There are two modes for this game, \q{Unequal} and \q{Adjacent}. In \q{Unequal} mode, the clue signs are greater-than symbols indicating one square's value is greater than its neighbour's. In this mode not all clues may be visible, particularly at higher difficulty levels. In \q{Adjacent} mode, the clue signs are bars indicating one square's value is numerically adjacent (i.e. one higher or one lower) than its neighbour. In this mode all clues are always visible: absence of a bar thus means that a square's value is definitely not numerically adjacent to that neighbour's. In \q{Trivial} difficulty level (available via the \q{Custom} game type selector), there are no greater-than signs in \q{Unequal} mode; the puzzle is to solve the \i{Latin square} only. At the time of writing, the \q{Unequal} mode of this puzzle is appearing in the Guardian weekly under the name \q{\i{Futoshiki}}. Unequal was contributed to this collection by James Harvey. \H{unequal-controls} \i{Unequal controls} \IM{Unequal controls} controls, for Unequal Unequal shares much of its control system with Solo. To play Unequal, simply click the mouse in any empty square and then type a digit or letter on the keyboard to fill that square. If you make a mistake, click the mouse in the incorrect square and press Space to clear it again (or use the Undo feature). If you \e{right}-click in a square and then type a number, that number will be entered in the square as a \q{pencil mark}. You can have pencil marks for multiple numbers in the same square. Squares containing filled-in numbers cannot also contain pencil marks. The game pays no attention to pencil marks, so exactly what you use them for is up to you: you can use them as reminders that a particular square needs to be re-examined once you know more about a particular number, or you can use them as lists of the possible numbers in a given square, or anything else you feel like. To erase a single pencil mark, right-click in the square and type the same number again. All pencil marks in a square are erased when you left-click and type a number, or when you left-click and press space. Right-clicking and pressing space will also erase pencil marks. As for Solo, the cursor keys can be used in conjunction with the digit keys to set numbers or pencil marks. You can also use the \q{M} key to auto-fill every numeric hint, ready for removal as required, or the \q{H} key to do the same but also to remove all obvious hints. Alternatively, use the cursor keys to move the mark around the grid. Pressing the return key toggles the mark (from a normal mark to a pencil mark), and typing a number in is entered in the square in the appropriate way; typing in a 0 or using the space bar will clear a filled square. Left-clicking a clue will mark it as done (grey it out), or unmark it if it is already marked. Holding Control or Shift and pressing an arrow key likewise marks any clue adjacent to the cursor in the given direction. (All the actions described in \k{common-actions} are also available.) \H{unequal-parameters} \I{parameters, for Unequal}Unequal parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Mode} \dd Mode of the puzzle (\q{Unequal} or \q{Adjacent}) \dt \e{Size (s*s)} \dd Size of grid. \dt \e{Difficulty} \dd Controls the difficulty of the generated puzzle. At Trivial level, there are no greater-than signs; the puzzle is to solve the Latin square only. At Recursive level (only available via the \q{Custom} game type selector) backtracking will be required, but the solution should still be unique. The levels in between require increasingly complex reasoning to avoid having to backtrack. \C{galaxies} \i{Galaxies} \cfg{winhelp-topic}{games.galaxies} You have a rectangular grid containing a number of dots. Your aim is to draw edges along the grid lines which divide the rectangle into regions in such a way that every region is 180\u00b0{-degree} rotationally symmetric, and contains exactly one dot which is located at its centre of symmetry. This puzzle was invented by \i{Nikoli} \k{nikoli-galaxies}, under the name \q{Tentai Show}; its name is commonly translated into English as \q{Spiral Galaxies}. Galaxies was contributed to this collection by James Harvey. \B{nikoli-galaxies} \W{http://www.nikoli.co.jp/en/puzzles/astronomical_show.html}\cw{http://www.nikoli.co.jp/en/puzzles/astronomical_show.html} \H{galaxies-controls} \i{Galaxies controls} \IM{Galaxies controls} controls, for Galaxies Left-click on any grid line to draw an edge if there isn't one already, or to remove one if there is. When you create a valid region (one which is closed, contains exactly one dot, is 180\u00b0{-degree} symmetric about that dot, and contains no extraneous edges inside it) it will be highlighted automatically; so your aim is to have the whole grid highlighted in that way. During solving, you might know that a particular grid square belongs to a specific dot, but not be sure of where the edges go and which other squares are connected to the dot. In order to mark this so you don't forget, you can right-click on the dot and drag, which will create an arrow marker pointing at the dot. Drop that in a square of your choice and it will remind you which dot it's associated with. You can also right-click on existing arrows to pick them up and move them, or destroy them by dropping them off the edge of the grid. (Also, if you're not sure which dot an arrow is pointing at, you can pick it up and move it around to make it clearer. It will swivel constantly as you drag it, to stay pointed at its parent dot.) You can also use the cursor keys to move around the grid squares and lines. Pressing the return key when over a grid line will draw or clear its edge, as above. Pressing the return key when over a dot will pick up an arrow, to be dropped the next time the return key is pressed; this can also be used to move existing arrows around, removing them by dropping them on a dot or another arrow. (All the actions described in \k{common-actions} are also available.) \H{galaxies-parameters} \I{parameters, for Galaxies}Galaxies parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid in squares. \dt \e{Difficulty} \dd Controls the difficulty of the generated puzzle. More difficult puzzles require more complex deductions, and the \q{Unreasonable} difficulty level may require backtracking. \C{filling} \i{Filling} \cfg{winhelp-topic}{games.filling} You have a grid of squares, some of which contain digits, and the rest of which are empty. Your job is to fill in digits in the empty squares, in such a way that each connected region of squares all containing the same digit has an area equal to that digit. (\q{Connected region}, for the purposes of this game, does not count diagonally separated squares as adjacent.) For example, it follows that no square can contain a zero, and that two adjacent squares can not both contain a one. No region has an area greater than 9 (because then its area would not be a single digit). Credit for this puzzle goes to \i{Nikoli} \k{nikoli-fillomino}. Filling was contributed to this collection by Jonas K\u00F6{oe}lker. \B{nikoli-fillomino} \W{http://www.nikoli.co.jp/en/puzzles/fillomino.html}\cw{http://www.nikoli.co.jp/en/puzzles/fillomino.html} \H{filling-controls} \I{controls, for Filling}Filling controls To play Filling, simply click the mouse in any empty square and then type a digit on the keyboard to fill that square. By dragging the mouse, you can select multiple squares to fill with a single keypress. If you make a mistake, click the mouse in the incorrect square and press 0, Space, Backspace or Enter to clear it again (or use the Undo feature). You can also move around the grid with the cursor keys; typing a digit will fill the square containing the cursor with that number; typing 0 will clear it. You can also select multiple squares for numbering or clearing with the return and arrow keys, before typing a digit to fill or clear the highlighted squares (as above). The space bar adds and removes single squares to and from the selection. Backspace and escape remove all squares from the selection. (All the actions described in \k{common-actions} are also available.) \H{filling-parameters} \I{parameters, for Filling}Filling parameters Filling allows you to configure the number of rows and columns of the grid, through the \q{Type} menu. \C{keen} \i{Keen} \cfg{winhelp-topic}{games.keen} You have a square grid; each square may contain a digit from 1 to the size of the grid. The grid is divided into blocks of varying shape and size, with arithmetic clues written in them. Your aim is to fully populate the grid with digits such that: \b Each row contains only one occurrence of each digit \b Each column contains only one occurrence of each digit \b The digits in each block can be combined to form the number stated in the clue, using the arithmetic operation given in the clue. That is: \lcont{ \b An addition clue means that the sum of the digits in the block must be the given number. For example, \q{15+} means the contents of the block adds up to fifteen. \b A multiplication clue (e.g. \q{60\times}), similarly, means that the product of the digits in the block must be the given number. \b A subtraction clue will always be written in a block of size two, and it means that one of the digits in the block is greater than the other by the given amount. For example, \q{2\minus} means that one of the digits in the block is 2 more than the other, or equivalently that one digit minus the other one is 2. The two digits could be either way round, though. \b A division clue (e.g. \q{3\divide}), similarly, is always in a block of size two and means that one digit divided by the other is equal to the given amount. Note that a block may contain the same digit more than once (provided the identical ones are not in the same row and column). This rule is precisely the opposite of the rule in Solo's \q{Killer} mode (see \k{solo}). } This puzzle appears in the Times under the name \q{\i{KenKen}}. \H{keen-controls} \i{Keen controls} \IM{Keen controls} controls, for Keen Keen shares much of its control system with Solo (and Unequal). To play Keen, simply click the mouse in any empty square and then type a digit on the keyboard to fill that square. If you make a mistake, click the mouse in the incorrect square and press Space to clear it again (or use the Undo feature). If you \e{right}-click in a square and then type a number, that number will be entered in the square as a \q{pencil mark}. You can have pencil marks for multiple numbers in the same square. Squares containing filled-in numbers cannot also contain pencil marks. The game pays no attention to pencil marks, so exactly what you use them for is up to you: you can use them as reminders that a particular square needs to be re-examined once you know more about a particular number, or you can use them as lists of the possible numbers in a given square, or anything else you feel like. To erase a single pencil mark, right-click in the square and type the same number again. All pencil marks in a square are erased when you left-click and type a number, or when you left-click and press space. Right-clicking and pressing space will also erase pencil marks. As for Solo, the cursor keys can be used in conjunction with the digit keys to set numbers or pencil marks. Use the cursor keys to move a highlight around the grid, and type a digit to enter it in the highlighted square. Pressing return toggles the highlight into a mode in which you can enter or remove pencil marks. Pressing M will fill in a full set of pencil marks in every square that does not have a main digit in it. (All the actions described in \k{common-actions} are also available.) \H{keen-parameters} \I{parameters, for Keen}Keen parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Grid size} \dd Specifies the size of the grid. Lower limit is 3; upper limit is 9 (because the user interface would become more difficult with \q{digits} bigger than 9!). \dt \e{Difficulty} \dd Controls the difficulty of the generated puzzle. At Unreasonable level, some backtracking will be required, but the solution should still be unique. The remaining levels require increasingly complex reasoning to avoid having to backtrack. \dt \e{Multiplication only} \dd If this is enabled, all boxes will be multiplication boxes. With this rule, the puzzle is known as \q{Inshi No Heya}. \C{towers} \i{Towers} \cfg{winhelp-topic}{games.towers} You have a square grid. On each square of the grid you can build a tower, with its height ranging from 1 to the size of the grid. Around the edge of the grid are some numeric clues. Your task is to build a tower on every square, in such a way that: \b Each row contains every possible height of tower once \b Each column contains every possible height of tower once \b Each numeric clue describes the number of towers that can be seen if you look into the square from that direction, assuming that shorter towers are hidden behind taller ones. For example, in a 5\by\.5 grid, a clue marked \q{5} indicates that the five tower heights must appear in increasing order (otherwise you would not be able to see all five towers), whereas a clue marked \q{1} indicates that the tallest tower (the one marked 5) must come first. In harder or larger puzzles, some towers will be specified for you as well as the clues round the edge, and some edge clues may be missing. This puzzle appears on the web under various names, particularly \q{\i{Skyscrapers}}, but I don't know who first invented it. \H{towers-controls} \i{Towers controls} \IM{Towers controls} controls, for Towers Towers shares much of its control system with Solo, Unequal and Keen. To play Towers, simply click the mouse in any empty square and then type a digit on the keyboard to fill that square with a tower of the given height. If you make a mistake, click the mouse in the incorrect square and press Space to clear it again (or use the Undo feature). If you \e{right}-click in a square and then type a number, that number will be entered in the square as a \q{pencil mark}. You can have pencil marks for multiple numbers in the same square. A square containing a tower cannot also contain pencil marks. The game pays no attention to pencil marks, so exactly what you use them for is up to you: you can use them as reminders that a particular square needs to be re-examined once you know more about a particular number, or you can use them as lists of the possible numbers in a given square, or anything else you feel like. To erase a single pencil mark, right-click in the square and type the same number again. All pencil marks in a square are erased when you left-click and type a number, or when you left-click and press space. Right-clicking and pressing space will also erase pencil marks. As for Solo, the cursor keys can be used in conjunction with the digit keys to set numbers or pencil marks. Use the cursor keys to move a highlight around the grid, and type a digit to enter it in the highlighted square. Pressing return toggles the highlight into a mode in which you can enter or remove pencil marks. Pressing M will fill in a full set of pencil marks in every square that does not have a main digit in it. Left-clicking a clue will mark it as done (grey it out), or unmark it if it is already marked. Holding Control or Shift and pressing an arrow key likewise marks any clue in the given direction. (All the actions described in \k{common-actions} are also available.) \H{towers-parameters} \I{parameters, for Towers}Towers parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Grid size} \dd Specifies the size of the grid. Lower limit is 3; upper limit is 9 (because the user interface would become more difficult with \q{digits} bigger than 9!). \dt \e{Difficulty} \dd Controls the difficulty of the generated puzzle. At Unreasonable level, some backtracking will be required, but the solution should still be unique. The remaining levels require increasingly complex reasoning to avoid having to backtrack. \C{singles} \i{Singles} \cfg{winhelp-topic}{games.singles} You have a grid of white squares, all of which contain numbers. Your task is to colour some of the squares black (removing the number) so as to satisfy all of the following conditions: \b No number occurs more than once in any row or column. \b No black square is horizontally or vertically adjacent to any other black square. \b The remaining white squares must all form one contiguous region (connected by edges, not just touching at corners). Credit for this puzzle goes to \i{Nikoli} \k{nikoli-hitori} who call it \i{Hitori}. Singles was contributed to this collection by James Harvey. \B{nikoli-hitori} \W{http://www.nikoli.com/en/puzzles/hitori.html}\cw{http://www.nikoli.com/en/puzzles/hitori.html} (beware of Flash) \H{singles-controls} \i{Singles controls} \IM{Singles controls} controls, for Singles Left-clicking on an empty square will colour it black; left-clicking again will restore the number. Right-clicking will add a circle (useful for indicating that a cell is definitely not black). You can also use the cursor keys to move around the grid. Pressing the return or space keys will turn a square black or add a circle respectively, and pressing the key again will restore the number or remove the circle. (All the actions described in \k{common-actions} are also available.) \H{singles-parameters} \I{parameters, for Singles}Singles parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid in squares. \dt \e{Difficulty} \dd Controls the difficulty of the generated puzzle. \C{magnets} \i{Magnets} \cfg{winhelp-topic}{games.magnets} A rectangular grid has been filled with a mixture of magnets (that is, dominoes with one positive end and one negative end) and blank dominoes (that is, dominoes with two neutral poles). These dominoes are initially only seen in silhouette. Around the grid are placed a number of clues indicating the number of positive and negative poles contained in certain columns and rows. Your aim is to correctly place the magnets and blank dominoes such that all the clues are satisfied, with the additional constraint that no two similar magnetic poles may be orthogonally adjacent (since they repel). Neutral poles do not repel, and can be adjacent to any other pole. Credit for this puzzle goes to \i{Janko} \k{janko-magnets}. Magnets was contributed to this collection by James Harvey. \B{janko-magnets} \W{http://www.janko.at/Raetsel/Magnete/index.htm}\cw{http://www.janko.at/Raetsel/Magnete/index.htm} \H{magnets-controls} \i{Magnets controls} \IM{Magnets controls} controls, for Magnets Left-clicking on an empty square places a magnet at that position with the positive pole on the square and the negative pole on the other half of the magnet; left-clicking again reverses the polarity, and a third click removes the magnet. Right-clicking on an empty square places a blank domino there. Right-clicking again places two question marks on the domino, signifying \q{this cannot be blank} (which can be useful to note deductions while solving), and right-clicking again empties the domino. Left-clicking a clue will mark it as done (grey it out), or unmark it if it is already marked. You can also use the cursor keys to move a cursor around the grid. Pressing the return key will lay a domino with a positive pole at that position; pressing again reverses the polarity and then removes the domino, as with left-clicking. Using the space bar allows placement of blank dominoes and cannot-be-blank hints, as for right-clicking. (All the actions described in \k{common-actions} are also available.) \H{magnets-parameters} \I{parameters, for Magnets}Magnets parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid in squares. There will be half \e{Width} \by \e{Height} dominoes in the grid: if this number is odd then one square will be blank. \lcont{ (Grids with at least one odd dimension tend to be easier to solve.) } \dt \e{Difficulty} \dd Controls the difficulty of the generated puzzle. At Tricky level, you are required to make more deductions about empty dominoes and row/column counts. \dt \e{Strip clues} \dd If true, some of the clues around the grid are removed at generation time, making the puzzle more difficult. \C{signpost} \i{Signpost} \cfg{winhelp-topic}{games.signpost} You have a grid of squares; each square (except the last one) contains an arrow, and some squares also contain numbers. Your job is to connect the squares to form a continuous list of numbers starting at 1 and linked in the direction of the arrows \dash so the arrow inside the square with the number 1 will point to the square containing the number 2, which will point to the square containing the number 3, etc. Each square can be any distance away from the previous one, as long as it is somewhere in the direction of the arrow. By convention the first and last numbers are shown; one or more interim numbers may also appear at the beginning. Credit for this puzzle goes to \i{Janko} \k{janko-arrowpath}, who call it \q{Pfeilpfad} (\q{arrow path}). Signpost was contributed to this collection by James Harvey. \B{janko-arrowpath} \W{http://janko.at/Raetsel/Pfeilpfad/index.htm}\cw{http://janko.at/Raetsel/Pfeilpfad/index.htm} \H{signpost-controls} \I{controls, for Signpost}Signpost controls To play Signpost, you connect squares together by dragging from one square to another, indicating that they are adjacent in the sequence. Drag with the left button from a square to its successor, or with the right button from a square to its predecessor. If you connect together two squares in this way and one of them has a number in it, the appropriate number will appear in the other square. If you connect two non-numbered squares, they will be assigned temporary algebraic labels: on the first occasion, they will be labelled \cq{a} and \cq{a+1}, and then \cq{b} and \cq{b+1}, and so on. Connecting more squares on to the ends of such a chain will cause them all to be labelled with the same letter. When you left-click or right-click in a square, the legal squares to connect it to will be shown. The arrow in each square starts off black, and goes grey once you connect the square to its successor. Also, each square which needs a predecessor has a small dot in the bottom left corner, which vanishes once you link a square to it. So your aim is always to connect a square with a black arrow to a square with a dot. To remove any links for a particular square (both incoming and outgoing), left-drag it off the grid. To remove a whole chain, right-drag any square in the chain off the grid. You can also use the cursor keys to move around the grid squares and lines. Pressing the return key when over a square starts a link operation, and pressing the return key again over a square will finish the link, if allowable. Pressing the space bar over a square will show the other squares pointing to it, and allow you to form a backward link, and pressing the space bar again cancels this. (All the actions described in \k{common-actions} are also available.) \H{signpost-parameters} \I{parameters, for Signpost}Signpost parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid in squares. \dt \e{Force start/end to corners} \dd If true, the start and end squares are always placed in opposite corners (the start at the top left, and the end at the bottom right). If false the start and end squares are placed randomly (although always both shown). \C{range} \i{Range} \cfg{winhelp-topic}{games.range} You have a grid of squares; some squares contain numbers. Your job is to colour some of the squares black, such that several criteria are satisfied: \b no square with a number is coloured black. \b no two black squares are adjacent (horizontally or vertically). \b for any two white squares, there is a path between them using only white squares. \b for each square with a number, that number denotes the total number of white squares reachable from that square going in a straight line in any horizontal or vertical direction until hitting a wall or a black square; the square with the number is included in the total (once). For instance, a square containing the number one must have four black squares as its neighbours by the last criterion; but then it's impossible for it to be connected to any outside white square, which violates the second to last criterion. So no square will contain the number one. Credit for this puzzle goes to \i{Nikoli}, who have variously called it \q{Kurodoko}, \q{Kuromasu} or \q{Where is Black Cells}. \k{nikoli-range}. Range was contributed to this collection by Jonas K\u00F6{oe}lker. \B{nikoli-range} \W{http://www.nikoli.co.jp/en/puzzles/where_is_black_cells.html}\cw{http://www.nikoli.co.jp/en/puzzles/where_is_black_cells.html} \H{range-controls} \I{controls, for Range}Range controls Click with the left button to paint a square black, or with the right button to mark a square with a dot to indicate that you are sure it should \e{not} be painted black. Repeated clicking with either button will cycle the square through the three possible states (filled, dotted or empty) in opposite directions. You can also use the cursor keys to move around the grid squares. Pressing Return does the same as clicking with the left button, while pressing Space does the same as a right button click. Moving with the cursor keys while holding Shift will place dots in all squares that are moved through. (All the actions described in \k{common-actions} are also available.) \H{range-parameters} \I{parameters, for Range}Range parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid in squares. \C{pearl} \i{Pearl} \cfg{winhelp-topic}{games.pearl} You have a grid of squares. Your job is to draw lines between the centres of horizontally or vertically adjacent squares, so that the lines form a single closed loop. In the resulting grid, some of the squares that the loop passes through will contain corners, and some will be straight horizontal or vertical lines. (And some squares can be completely empty \dash the loop doesn't have to pass through every square.) Some of the squares contain black and white circles, which are clues that the loop must satisfy. A black circle in a square indicates that that square is a corner, but neither of the squares adjacent to it in the loop is also a corner. A white circle indicates that the square is a straight edge, but \e{at least one} of the squares adjacent to it in the loop is a corner. (In both cases, the clue only constrains the two squares adjacent \e{in the loop}, that is, the squares that the loop passes into after leaving the clue square. The squares that are only adjacent \e{in the grid} are not constrained.) Credit for this puzzle goes to \i{Nikoli}, who call it \q{Masyu}. \k{nikoli-pearl} Thanks to James Harvey for assistance with the implementation. \B{nikoli-pearl} \W{http://www.nikoli.co.jp/en/puzzles/masyu.html}\cw{http://www.nikoli.co.jp/en/puzzles/masyu.html} (beware of Flash) \H{pearl-controls} \I{controls, for Pearl}Pearl controls Click with the left button on a grid edge to draw a segment of the loop through that edge, or to remove a segment once it is drawn. Drag with the left button through a series of squares to draw more than one segment of the loop in one go. Alternatively, drag over an existing part of the loop to undraw it, or to undraw part of it and then go in a different direction. Click with the right button on a grid edge to mark it with a cross, indicating that you are sure the loop does not go through that edge. (For instance, if you have decided which of the squares adjacent to a white clue has to be a corner, but don't yet know which way the corner turns, you might mark the one way it \e{can't} go with a cross.) Alternatively, use the cursor keys to move the cursor. Use the Enter key to begin and end keyboard \q{drag} operations. Use the Space, Escape or Backspace keys to cancel the drag. Or, hold Control while dragging with the cursor keys to toggle segments as you move between squares. Pressing Control-Shift-arrowkey or Shift-arrowkey simulates a left or right click, respectively, on the edge in the direction of the key. (All the actions described in \k{common-actions} are also available.) \H{pearl-parameters} \I{parameters, for Pearl}Pearl parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \C{undead} \i{Undead} \cfg{winhelp-topic}{games.undead} You are given a grid of squares, some of which contain diagonal mirrors. Every square which is not a mirror must be filled with one of three types of undead monster: a ghost, a vampire, or a zombie. Vampires can be seen directly, but are invisible when reflected in mirrors. Ghosts are the opposite way round: they can be seen in mirrors, but are invisible when looked at directly. Zombies are visible by any means. You are also told the total number of each type of monster in the grid. Also around the edge of the grid are written numbers, which indicate how many monsters can be seen if you look into the grid along a row or column starting from that position. (The diagonal mirrors are reflective on both sides. If your reflected line of sight crosses the same monster more than once, the number will count it each time it is visible, not just once.) This puzzle type was invented by David Millar, under the name \q{Haunted Mirror Maze}. See \k{janko-undead} for more details. Undead was contributed to this collection by Steffen Bauer. \B{janko-undead} \W{http://www.janko.at/Raetsel/Spukschloss/index.htm}\cw{http://www.janko.at/Raetsel/Spukschloss/index.htm} \H{undead-controls} \I{controls, for Undead}Undead controls Undead has a similar control system to Solo, Unequal and Keen. To play Undead, click the mouse in any empty square and then type a letter on the keyboard indicating the type of monster: \q{G} for a ghost, \q{V} for a vampire, or \q{Z} for a zombie. If you make a mistake, click the mouse in the incorrect square and press Space to clear it again (or use the Undo feature). If you \e{right}-click in a square and then type a letter, the corresponding monster will be shown in reduced size in that square, as a \q{pencil mark}. You can have pencil marks for multiple monsters in the same square. A square containing a full-size monster cannot also contain pencil marks. The game pays no attention to pencil marks, so exactly what you use them for is up to you: you can use them as reminders that a particular square needs to be re-examined once you know more about a particular monster, or you can use them as lists of the possible monster in a given square, or anything else you feel like. To erase a single pencil mark, right-click in the square and type the same letter again. All pencil marks in a square are erased when you left-click and type a monster letter, or when you left-click and press Space. Right-clicking and pressing space will also erase pencil marks. As for Solo, the cursor keys can be used in conjunction with the letter keys to place monsters or pencil marks. Use the cursor keys to move a highlight around the grid, and type a monster letter to enter it in the highlighted square. Pressing return toggles the highlight into a mode in which you can enter or remove pencil marks. If you prefer plain letters of the alphabet to cute monster pictures, you can press \q{A} to toggle between showing the monsters as monsters or showing them as letters. Left-clicking a clue will mark it as done (grey it out), or unmark it if it is already marked. (All the actions described in \k{common-actions} are also available.) \H{undead-parameters} \I{parameters, for Undead}Undead parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid in squares. \dt \e{Difficulty} \dd Controls the difficulty of the generated puzzle. \C{unruly} \i{Unruly} \cfg{winhelp-topic}{games.unruly} You are given a grid of squares, which you must colour either black or white. Some squares are provided as clues; the rest are left for you to fill in. Each row and column must contain the same number of black and white squares, and no row or column may contain three consecutive squares of the same colour. This puzzle type was invented by Adolfo Zanellati, under the name \q{Tohu wa Vohu}. See \k{janko-unruly} for more details. Unruly was contributed to this collection by Lennard Sprong. \B{janko-unruly} \W{http://www.janko.at/Raetsel/Tohu-Wa-Vohu/index.htm}\cw{http://www.janko.at/Raetsel/Tohu-Wa-Vohu/index.htm} \H{unruly-controls} \I{controls, for Unruly}Unruly controls To play Unruly, click the mouse in a square to change its colour. Left-clicking an empty square will turn it black, and right-clicking will turn it white. Keep clicking the same button to cycle through the three possible states for the square. If you middle-click in a square it will be reset to empty. You can also use the cursor keys to move around the grid. Pressing the return or space keys will turn an empty square black or white respectively (and then cycle the colours in the same way as the mouse buttons), and pressing Backspace will reset a square to empty. (All the actions described in \k{common-actions} are also available.) \H{unruly-parameters} \I{parameters, for Unruly}Unruly parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid in squares. (Note that the rules of the game require both the width and height to be even numbers.) \dt \e{Difficulty} \dd Controls the difficulty of the generated puzzle. \dt \e{Unique rows and columns} \dd If enabled, no two rows are permitted to have exactly the same pattern, and likewise columns. (A row and a column can match, though.) \C{flood} \i{Flood} \cfg{winhelp-topic}{games.flood} You are given a grid of squares, coloured at random in multiple colours. In each move, you can flood-fill the top left square in a colour of your choice (i.e. every square reachable from the starting square by an orthogonally connected path of squares all the same colour will be filled in the new colour). As you do this, more and more of the grid becomes connected to the starting square. Your aim is to make the whole grid the same colour, in as few moves as possible. The game will set a limit on the number of moves, based on running its own internal solver. You win if you can make the whole grid the same colour in that many moves or fewer. I saw this game (with a fixed grid size, fixed number of colours, and fixed move limit) at http://floodit.appspot.com (no longer accessible). \H{flood-controls} \I{controls, for Flood}Flood controls To play Flood, click the mouse in a square. The top left corner and everything connected to it will be flood-filled with the colour of the square you clicked. Clicking a square the same colour as the top left corner has no effect, and therefore does not count as a move. You can also use the cursor keys to move a cursor (outline black square) around the grid. Pressing the return key will fill the top left corner in the colour of the square under the cursor. (All the actions described in \k{common-actions} are also available.) \H{flood-parameters} \I{parameters, for Flood}Flood parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of the grid, in squares. \dt \e{Colours} \dd Number of colours used to fill the grid. Must be at least 3 (with two colours there would only be one legal move at any stage, hence no choice to make at all), and at most 10. \dt \e{Extra moves permitted} \dd Controls the difficulty of the puzzle, by increasing the move limit. In each new grid, Flood will run an internal solver to generate its own solution, and then the value in this field will be added to the length of Flood's solution to generate the game's move limit. So a value of 0 requires you to be just as efficient as Flood's automated solver, and a larger value makes it easier. \lcont{ (Note that Flood's internal solver will not necessarily find the shortest possible solution, though I believe it's pretty close. For a real challenge, set this value to 0 and then try to solve a grid in \e{strictly fewer} moves than the limit you're given!) } \C{tracks} \i{Tracks} \cfg{winhelp-topic}{games.tracks} You are given a grid of squares, some of which are filled with train tracks. You need to complete the track from A to B so that the rows and columns contain the same number of track segments as are indicated in the clues to the top and right of the grid. There are only straight and 90 degree curved rails, and the track may not cross itself. Tracks was contributed to this collection by James Harvey. \H{tracks-controls} \I{controls, for Tracks}Tracks controls Left-clicking on an edge between two squares adds a track segment between the two squares. Right-clicking on an edge adds a cross on the edge, indicating no track is possible there. Left-clicking in a square adds a colour indicator showing that you know the square must contain a track, even if you don't know which edges it crosses yet. Right-clicking in a square adds a cross indicating it contains no track segment. Left- or right-dragging between squares allows you to lay a straight line of is-track or is-not-track indicators, useful for filling in rows or columns to match the clue. (All the actions described in \k{common-actions} are also available.) \H{tracks-parameters} \I{parameters, for Tracks}Tracks parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of the grid, in squares. \dt \e{Difficulty} \dd Controls the difficulty of the generated puzzle: at Tricky level, you are required to make more deductions regarding disregarding moves that would lead to impossible crossings later. \dt \e{Disallow consecutive 1 clues} \dd Controls whether the Tracks game generation permits two adjacent rows or columns to have a 1 clue, or permits the row or column of the track's endpoint to have a 1 clue. By default this is not permitted, to avoid long straight boring segments of track and make the games more twiddly and interesting. If you want to restore the possibility, turn this option off. \C{palisade} \i{Palisade} \cfg{winhelp-topic}{games.palisade} You're given a grid of squares, some of which contain numbers. Your goal is to subdivide the grid into contiguous regions, all of the same (given) size, such that each square containing a number is adjacent to exactly that many edges (including those between the inside and the outside of the grid). Credit for this puzzle goes to \i{Nikoli}, who call it \q{Five Cells}. \k{nikoli-palisade}. Palisade was contributed to this collection by Jonas K\u00F6{oe}lker. \B{nikoli-palisade} \W{http://nikoli.co.jp/en/puzzles/five_cells.html}\cw{http://nikoli.co.jp/en/puzzles/five_cells.html} \H{palisade-controls} \I{controls, for Palisade}Palisade controls Left-click to place an edge. Right-click to indicate \q{no edge}. Alternatively, the arrow keys will move a keyboard cursor. Holding Control while pressing an arrow key will place an edge. Press Shift-arrowkey to switch off an edge. Repeat an action to perform its inverse. (All the actions described in \k{common-actions} are also available.) \H{Palisade-parameters} \I{parameters, for Palisade}Palisade parameters These parameters are available from the \q{Custom...} option on the \q{Type} menu. \dt \e{Width}, \e{Height} \dd Size of grid in squares. \dt \e{Region size} \dd The size of the regions into which the grid must be subdivided. \A{licence} \I{MIT licence}\ii{Licence} This software is \i{copyright} 2004-2014 Simon Tatham. Portions copyright Richard Boulton, James Harvey, Mike Pinna, Jonas K\u00F6{oe}lker, Dariusz Olszewski, Michael Schierl, Lambros Lambrou, Bernd Schmidt, Steffen Bauer, Lennard Sprong and Rogier Goossens. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \q{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 \q{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 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \IM{command-line}{command line} command line \IM{default parameters, specifying} default parameters, specifying \IM{default parameters, specifying} preferences, specifying default \IM{Unix} Unix \IM{Unix} Linux \IM{generating game IDs} generating game IDs \IM{generating game IDs} game ID, generating \IM{specific} \q{Specific}, menu option \IM{custom} \q{Custom}, menu option \IM{game ID} game ID \IM{game ID} ID, game \IM{ID format} ID format \IM{ID format} format, ID \IM{ID format} game ID, format \IM{keys} keys \IM{keys} shortcuts (keyboard) \IM{initial state} initial state \IM{initial state} state, initial \IM{MIT licence} MIT licence \IM{MIT licence} licence, MIT \versionid Simon Tatham's Portable Puzzle Collection, version 20170606.272beef puzzles-20170606.272beef/osx-help.but0000644000175000017500000000056613115373615016153 0ustar simonsimon\# Additional Halibut fragment to set up the HTML output \# appropriately for MacOS online help. \cfg{html-head-end}{ } puzzles-20170606.272beef/devel.but0000644000175000017500000062747513115373615015531 0ustar simonsimon\cfg{text-indent}{0} \cfg{text-width}{72} \cfg{text-title-align}{left} \cfg{text-chapter-align}{left} \cfg{text-chapter-numeric}{true} \cfg{text-chapter-suffix}{. } \cfg{text-chapter-underline}{-} \cfg{text-section-align}{0}{left} \cfg{text-section-numeric}{0}{true} \cfg{text-section-suffix}{0}{. } \cfg{text-section-underline}{0}{-} \cfg{text-section-align}{1}{left} \cfg{text-section-numeric}{1}{true} \cfg{text-section-suffix}{1}{. } \cfg{text-section-underline}{1}{-} \cfg{text-versionid}{0} \cfg{html-contents-filename}{index.html} \cfg{html-template-filename}{%k.html} \cfg{html-index-filename}{docindex.html} \cfg{html-leaf-level}{1} \cfg{html-contents-depth-0}{1} \cfg{html-contents-depth-1}{3} \cfg{html-leaf-contains-contents}{true} \define{dash} \u2013{-} \title Developer documentation for Simon Tatham's puzzle collection This is a guide to the internal structure of Simon Tatham's Portable Puzzle Collection (henceforth referred to simply as \q{Puzzles}), for use by anyone attempting to implement a new puzzle or port to a new platform. This guide is believed correct as of r6190. Hopefully it will be updated along with the code in future, but if not, I've at least left this version number in here so you can figure out what's changed by tracking commit comments from there onwards. \C{intro} Introduction The Puzzles code base is divided into four parts: a set of interchangeable front ends, a set of interchangeable back ends, a universal \q{middle end} which acts as a buffer between the two, and a bunch of miscellaneous utility functions. In the following sections I give some general discussion of each of these parts. \H{intro-frontend} Front end The front end is the non-portable part of the code: it's the bit that you replace completely when you port to a different platform. So it's responsible for all system calls, all GUI interaction, and anything else platform-specific. The current front ends in the main code base are for Windows, GTK and MacOS X; I also know of a third-party front end for PalmOS. The front end contains \cw{main()} or the local platform's equivalent. Top-level control over the application's execution flow belongs to the front end (it isn't, for example, a set of functions called by a universal \cw{main()} somewhere else). The front end has complete freedom to design the GUI for any given port of Puzzles. There is no centralised mechanism for maintaining the menu layout, for example. This has a cost in consistency (when I \e{do} want the same menu layout on more than one platform, I have to edit two pieces of code in parallel every time I make a change), but the advantage is that local GUI conventions can be conformed to and local constraints adapted to. For example, MacOS X has strict human interface guidelines which specify a different menu layout from the one I've used on Windows and GTK; there's nothing stopping the OS X front end from providing a menu layout consistent with those guidelines. Although the front end is mostly caller rather than the callee in its interactions with other parts of the code, it is required to implement a small API for other modules to call, mostly of drawing functions for games to use when drawing their graphics. The drawing API is documented in \k{drawing}; the other miscellaneous front end API functions are documented in \k{frontend-api}. \H{intro-backend} Back end A \q{back end}, in this collection, is synonymous with a \q{puzzle}. Each back end implements a different game. At the top level, a back end is simply a data structure, containing a few constants (flag words, preferred pixel size) and a large number of function pointers. Back ends are almost invariably callee rather than caller, which means there's a limitation on what a back end can do on its own initiative. The persistent state in a back end is divided into a number of data structures, which are used for different purposes and therefore likely to be switched around, changed without notice, and otherwise updated by the rest of the code. It is important when designing a back end to put the right pieces of data into the right structures, or standard midend-provided features (such as Undo) may fail to work. The functions and variables provided in the back end data structure are documented in \k{backend}. \H{intro-midend} Middle end Puzzles has a single and universal \q{middle end}. This code is common to all platforms and all games; it sits in between the front end and the back end and provides standard functionality everywhere. People adding new back ends or new front ends should generally not need to edit the middle end. On rare occasions there might be a change that can be made to the middle end to permit a new game to do something not currently anticipated by the middle end's present design; however, this is terribly easy to get wrong and should probably not be undertaken without consulting the primary maintainer (me). Patch submissions containing unannounced mid-end changes will be treated on their merits like any other patch; this is just a friendly warning that mid-end changes will need quite a lot of merits to make them acceptable. Functionality provided by the mid-end includes: \b Maintaining a list of game state structures and moving back and forth along that list to provide Undo and Redo. \b Handling timers (for move animations, flashes on completion, and in some cases actually timing the game). \b Handling the container format of game IDs: receiving them, picking them apart into parameters, description and/or random seed, and so on. The game back end need only handle the individual parts of a game ID (encoded parameters and encoded game description); everything else is handled centrally by the mid-end. \b Handling standard keystrokes and menu commands, such as \q{New Game}, \q{Restart Game} and \q{Quit}. \b Pre-processing mouse events so that the game back ends can rely on them arriving in a sensible order (no missing button-release events, no sudden changes of which button is currently pressed, etc). \b Handling the dialog boxes which ask the user for a game ID. \b Handling serialisation of entire games (for loading and saving a half-finished game to a disk file, or for handling application shutdown and restart on platforms such as PalmOS where state is expected to be saved). Thus, there's a lot of work done once by the mid-end so that individual back ends don't have to worry about it. All the back end has to do is cooperate in ensuring the mid-end can do its work properly. The API of functions provided by the mid-end to be called by the front end is documented in \k{midend}. \H{intro-utils} Miscellaneous utilities In addition to these three major structural components, the Puzzles code also contains a variety of utility modules usable by all of the above components. There is a set of functions to provide platform-independent random number generation; functions to make memory allocation easier; functions which implement a balanced tree structure to be used as necessary in complex algorithms; and a few other miscellaneous functions. All of these are documented in \k{utils}. \H{intro-structure} Structure of this guide There are a number of function call interfaces within Puzzles, and this guide will discuss each one in a chapter of its own. After that, \k{writing} discusses how to design new games, with some general design thoughts and tips. \C{backend} Interface to the back end This chapter gives a detailed discussion of the interface that each back end must implement. At the top level, each back end source file exports a single global symbol, which is a \c{const struct game} containing a large number of function pointers and a small amount of constant data. This structure is called by different names depending on what kind of platform the puzzle set is being compiled on: \b On platforms such as Windows and GTK, which build a separate binary for each puzzle, the game structure in every back end has the same name, \cq{thegame}; the front end refers directly to this name, so that compiling the same front end module against a different back end module builds a different puzzle. \b On platforms such as MacOS X and PalmOS, which build all the puzzles into a single monolithic binary, the game structure in each back end must have a different name, and there's a helper module \c{list.c} (constructed automatically by the same Perl script that builds the \cw{Makefile}s) which contains a complete list of those game structures. On the latter type of platform, source files may assume that the preprocessor symbol \c{COMBINED} has been defined. Thus, the usual code to declare the game structure looks something like this: \c #ifdef COMBINED \c #define thegame net /* or whatever this game is called */ \e iii iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii \c #endif \c \c const struct game thegame = { \c /* lots of structure initialisation in here */ \e iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii \c }; Game back ends must also internally define a number of data structures, for storing their various persistent state. This chapter will first discuss the nature and use of those structures, and then go on to give details of every element of the game structure. \H{backend-structs} Data structures Each game is required to define four separate data structures. This section discusses each one and suggests what sorts of things need to be put in it. \S{backend-game-params} \c{game_params} The \c{game_params} structure contains anything which affects the automatic generation of new puzzles. So if puzzle generation is parametrised in any way, those parameters need to be stored in \c{game_params}. Most puzzles currently in this collection are played on a grid of squares, meaning that the most obvious parameter is the grid size. Many puzzles have additional parameters; for example, Mines allows you to control the number of mines in the grid independently of its size, Net can be wrapping or non-wrapping, Solo has difficulty levels and symmetry settings, and so on. A simple rule for deciding whether a data item needs to go in \c{game_params} is: would the user expect to be able to control this data item from either the preset-game-types menu or the \q{Custom} game type configuration? If so, it's part of \c{game_params}. \c{game_params} structures are permitted to contain pointers to subsidiary data if they need to. The back end is required to provide functions to create and destroy \c{game_params}, and those functions can allocate and free additional memory if necessary. (It has not yet been necessary to do this in any puzzle so far, but the capability is there just in case.) \c{game_params} is also the only structure which the game's \cw{compute_size()} function may refer to; this means that any aspect of the game which affects the size of the window it needs to be drawn in must be stored in \c{game_params}. In particular, this imposes the fundamental limitation that random game generation may not have a random effect on the window size: game generation algorithms are constrained to work by starting from the grid size rather than generating it as an emergent phenomenon. (Although this is a restriction in theory, it has not yet seemed to be a problem.) \S{backend-game-state} \c{game_state} While the user is actually playing a puzzle, the \c{game_state} structure stores all the data corresponding to the current state of play. The mid-end keeps \c{game_state}s in a list, and adds to the list every time the player makes a move; the Undo and Redo functions step back and forth through that list. Therefore, a good means of deciding whether a data item needs to go in \c{game_state} is: would a player expect that data item to be restored on undo? If so, put it in \c{game_state}, and this will automatically happen without you having to lift a finger. If not \dash for example, the deaths counter in Mines is precisely something that does \e{not} want to be reset to its previous state on an undo \dash then you might have found a data item that needs to go in \c{game_ui} instead. During play, \c{game_state}s are often passed around without an accompanying \c{game_params} structure. Therefore, any information in \c{game_params} which is important during play (such as the grid size) must be duplicated within the \c{game_state}. One simple method of doing this is to have the \c{game_state} structure \e{contain} a \c{game_params} structure as one of its members, although this isn't obligatory if you prefer to do it another way. \S{backend-game-drawstate} \c{game_drawstate} \c{game_drawstate} carries persistent state relating to the current graphical contents of the puzzle window. The same \c{game_drawstate} is passed to every call to the game redraw function, so that it can remember what it has already drawn and what needs redrawing. A typical use for a \c{game_drawstate} is to have an array mirroring the array of grid squares in the \c{game_state}; then every time the redraw function was passed a \c{game_state}, it would loop over all the squares, and physically redraw any whose description in the \c{game_state} (i.e. what the square needs to look like when the redraw is completed) did not match its description in the \c{game_drawstate} (i.e. what the square currently looks like). \c{game_drawstate} is occasionally completely torn down and reconstructed by the mid-end, if the user somehow forces a full redraw. Therefore, no data should be stored in \c{game_drawstate} which is \e{not} related to the state of the puzzle window, because it might be unexpectedly destroyed. The back end provides functions to create and destroy \c{game_drawstate}, which means it can contain pointers to subsidiary allocated data if it needs to. A common thing to want to allocate in a \c{game_drawstate} is a \c{blitter}; see \k{drawing-blitter} for more on this subject. \S{backend-game-ui} \c{game_ui} \c{game_ui} contains whatever doesn't fit into the above three structures! A new \c{game_ui} is created when the user begins playing a new instance of a puzzle (i.e. during \q{New Game} or after entering a game ID etc). It persists until the user finishes playing that game and begins another one (or closes the window); in particular, \q{Restart Game} does \e{not} destroy the \c{game_ui}. \c{game_ui} is useful for implementing user-interface state which is not part of \c{game_state}. Common examples are keyboard control (you wouldn't want to have to separately Undo through every cursor motion) and mouse dragging. See \k{writing-keyboard-cursor} and \k{writing-howto-dragging}, respectively, for more details. Another use for \c{game_ui} is to store highly persistent data such as the Mines death counter. This is conceptually rather different: where the Net cursor position was \e{not important enough} to preserve for the player to restore by Undo, the Mines death counter is \e{too important} to permit the player to revert by Undo! A final use for \c{game_ui} is to pass information to the redraw function about recent changes to the game state. This is used in Mines, for example, to indicate whether a requested \q{flash} should be a white flash for victory or a red flash for defeat; see \k{writing-flash-types}. \H{backend-simple} Simple data in the back end In this section I begin to discuss each individual element in the back end structure. To begin with, here are some simple self-contained data elements. \S{backend-name} \c{name} \c const char *name; This is a simple ASCII string giving the name of the puzzle. This name will be used in window titles, in game selection menus on monolithic platforms, and anywhere else that the front end needs to know the name of a game. \S{backend-winhelp} \c{winhelp_topic} \c const char *winhelp_topic; This member is used on Windows only, to provide online help. Although the Windows front end provides a separate binary for each puzzle, it has a single monolithic help file; so when a user selects \q{Help} from the menu, the program needs to open the help file and jump to the chapter describing that particular puzzle. Therefore, each chapter in \c{puzzles.but} is labelled with a \e{help topic} name, similar to this: \c \cfg{winhelp-topic}{games.net} And then the corresponding game back end encodes the topic string (here \cq{games.net}) in the \c{winhelp_topic} element of the game structure. \H{backend-params} Handling game parameter sets In this section I present the various functions which handle the \c{game_params} structure. \S{backend-default-params} \cw{default_params()} \c game_params *(*default_params)(void); This function allocates a new \c{game_params} structure, fills it with the default values, and returns a pointer to it. \S{backend-fetch-preset} \cw{fetch_preset()} \c int (*fetch_preset)(int i, char **name, game_params **params); This function is one of the two APIs a back end can provide to populate the \q{Type} menu, which provides a list of conveniently accessible preset parameters for most games. The function is called with \c{i} equal to the index of the preset required (numbering from zero). It returns \cw{FALSE} if that preset does not exist (if \c{i} is less than zero or greater than the largest preset index). Otherwise, it sets \c{*params} to point at a newly allocated \c{game_params} structure containing the preset information, sets \c{*name} to point at a newly allocated C string containing the preset title (to go on the \q{Type} menu), and returns \cw{TRUE}. If the game does not wish to support any presets at all, this function is permitted to return \cw{FALSE} always. If the game wants to return presets in the form of a hierarchical menu instead of a flat list (and, indeed, even if it doesn't), then it may set this function pointer to \cw{NULL}, and instead fill in the alternative function pointer \cw{preset_menu} (\k{backend-preset-menu}). \S{backend-preset-menu} \cw{preset_menu()} \c struct preset_menu *(*preset_menu)(void); This function is the more flexible of the two APIs by which a back end can define a collection of preset game parameters. This function simply returns a complete menu hierarchy, in the form of a \c{struct preset_menu} (see \k{midend-get-presets}) and further submenus (if it wishes) dangling off it. There are utility functions described in \k{utils-presets} to make it easy for the back end to construct this menu. If the game has no need to return a hierarchy of menus, it may instead opt to implement the \cw{fetch_preset()} function (see \k{backend-fetch-preset}). The game need not fill in the \c{id} fields in the preset menu structures. The mid-end will do that after it receives the structure from the game, and before passing it on to the front end. \S{backend-encode-params} \cw{encode_params()} \c char *(*encode_params)(const game_params *params, int full); The job of this function is to take a \c{game_params}, and encode it in a string form for use in game IDs. The return value must be a newly allocated C string, and \e{must} not contain a colon or a hash (since those characters are used to mark the end of the parameter section in a game ID). Ideally, it should also not contain any other potentially controversial punctuation; bear in mind when designing a string parameter format that it will probably be used on both Windows and Unix command lines under a variety of exciting shell quoting and metacharacter rules. Sticking entirely to alphanumerics is the safest thing; if you really need punctuation, you can probably get away with commas, periods or underscores without causing anybody any major inconvenience. If you venture far beyond that, you're likely to irritate \e{somebody}. (At the time of writing this, all existing games have purely alphanumeric string parameter formats. Usually these involve a letter denoting a parameter, followed optionally by a number giving the value of that parameter, with a few mandatory parts at the beginning such as numeric width and height separated by \cq{x}.) If the \c{full} parameter is \cw{TRUE}, this function should encode absolutely everything in the \c{game_params}, such that a subsequent call to \cw{decode_params()} (\k{backend-decode-params}) will yield an identical structure. If \c{full} is \cw{FALSE}, however, you should leave out anything which is not necessary to describe a \e{specific puzzle instance}, i.e. anything which only takes effect when a new puzzle is \e{generated}. For example, the Solo \c{game_params} includes a difficulty rating used when constructing new puzzles; but a Solo game ID need not explicitly include the difficulty, since to describe a puzzle once generated it's sufficient to give the grid dimensions and the location and contents of the clue squares. (Indeed, one might very easily type in a puzzle out of a newspaper without \e{knowing} what its difficulty level is in Solo's terminology.) Therefore, Solo's \cw{encode_params()} only encodes the difficulty level if \c{full} is set. \S{backend-decode-params} \cw{decode_params()} \c void (*decode_params)(game_params *params, char const *string); This function is the inverse of \cw{encode_params()} (\k{backend-encode-params}). It parses the supplied string and fills in the supplied \c{game_params} structure. Note that the structure will \e{already} have been allocated: this function is not expected to create a \e{new} \c{game_params}, but to modify an existing one. This function can receive a string which only encodes a subset of the parameters. The most obvious way in which this can happen is if the string was constructed by \cw{encode_params()} with its \c{full} parameter set to \cw{FALSE}; however, it could also happen if the user typed in a parameter set manually and missed something out. Be prepared to deal with a wide range of possibilities. When dealing with a parameter which is not specified in the input string, what to do requires a judgment call on the part of the programmer. Sometimes it makes sense to adjust other parameters to bring them into line with the new ones. In Mines, for example, you would probably not want to keep the same mine count if the user dropped the grid size and didn't specify one, since you might easily end up with more mines than would actually fit in the grid! On the other hand, sometimes it makes sense to leave the parameter alone: a Solo player might reasonably expect to be able to configure size and difficulty independently of one another. This function currently has no direct means of returning an error if the string cannot be parsed at all. However, the returned \c{game_params} is almost always subsequently passed to \cw{validate_params()} (\k{backend-validate-params}), so if you really want to signal parse errors, you could always have a \c{char *} in your parameters structure which stored an error message, and have \cw{validate_params()} return it if it is non-\cw{NULL}. \S{backend-free-params} \cw{free_params()} \c void (*free_params)(game_params *params); This function frees a \c{game_params} structure, and any subsidiary allocations contained within it. \S{backend-dup-params} \cw{dup_params()} \c game_params *(*dup_params)(const game_params *params); This function allocates a new \c{game_params} structure and initialises it with an exact copy of the information in the one provided as input. It returns a pointer to the new duplicate. \S{backend-can-configure} \c{can_configure} \c int can_configure; This boolean data element is set to \cw{TRUE} if the back end supports custom parameter configuration via a dialog box. If it is \cw{TRUE}, then the functions \cw{configure()} and \cw{custom_params()} are expected to work. See \k{backend-configure} and \k{backend-custom-params} for more details. \S{backend-configure} \cw{configure()} \c config_item *(*configure)(const game_params *params); This function is called when the user requests a dialog box for custom parameter configuration. It returns a newly allocated array of \cw{config_item} structures, describing the GUI elements required in the dialog box. The array should have one more element than the number of controls, since it is terminated with a \cw{C_END} marker (see below). Each array element describes the control together with its initial value; the front end will modify the value fields and return the updated array to \cw{custom_params()} (see \k{backend-custom-params}). The \cw{config_item} structure contains the following elements: \c char *name; \c int type; \c char *sval; \c int ival; \c{name} is an ASCII string giving the textual label for a GUI control. It is \e{not} expected to be dynamically allocated. \c{type} contains one of a small number of \c{enum} values defining what type of control is being described. The meaning of the \c{sval} and \c{ival} fields depends on the value in \c{type}. The valid values are: \dt \c{C_STRING} \dd Describes a text input box. (This is also used for numeric input. The back end does not bother informing the front end that the box is numeric rather than textual; some front ends do have the capacity to take this into account, but I decided it wasn't worth the extra complexity in the interface.) For this type, \c{ival} is unused, and \c{sval} contains a dynamically allocated string representing the contents of the input box. \dt \c{C_BOOLEAN} \dd Describes a simple checkbox. For this type, \c{sval} is unused, and \c{ival} is \cw{TRUE} or \cw{FALSE}. \dt \c{C_CHOICES} \dd Describes a drop-down list presenting one of a small number of fixed choices. For this type, \c{sval} contains a list of strings describing the choices; the very first character of \c{sval} is used as a delimiter when processing the rest (so that the strings \cq{:zero:one:two}, \cq{!zero!one!two} and \cq{xzeroxonextwo} all define a three-element list containing \cq{zero}, \cq{one} and \cq{two}). \c{ival} contains the index of the currently selected element, numbering from zero (so that in the above example, 0 would mean \cq{zero} and 2 would mean \cq{two}). \lcont{ Note that for this control type, \c{sval} is \e{not} dynamically allocated, whereas it was for \c{C_STRING}. } \dt \c{C_END} \dd Marks the end of the array of \c{config_item}s. All other fields are unused. The array returned from this function is expected to have filled in the initial values of all the controls according to the input \c{game_params} structure. If the game's \c{can_configure} flag is set to \cw{FALSE}, this function is never called and need not do anything at all. \S{backend-custom-params} \cw{custom_params()} \c game_params *(*custom_params)(const config_item *cfg); This function is the counterpart to \cw{configure()} (\k{backend-configure}). It receives as input an array of \c{config_item}s which was originally created by \cw{configure()}, but in which the control values have since been changed in accordance with user input. Its function is to read the new values out of the controls and return a newly allocated \c{game_params} structure representing the user's chosen parameter set. (The front end will have modified the controls' \e{values}, but there will still always be the same set of controls, in the same order, as provided by \cw{configure()}. It is not necessary to check the \c{name} and \c{type} fields, although you could use \cw{assert()} if you were feeling energetic.) This function is not expected to (and indeed \e{must not}) free the input \c{config_item} array. (If the parameters fail to validate, the dialog box will stay open.) If the game's \c{can_configure} flag is set to \cw{FALSE}, this function is never called and need not do anything at all. \S{backend-validate-params} \cw{validate_params()} \c char *(*validate_params)(const game_params *params, int full); This function takes a \c{game_params} structure as input, and checks that the parameters described in it fall within sensible limits. (At the very least, grid dimensions should almost certainly be strictly positive, for example.) Return value is \cw{NULL} if no problems were found, or alternatively a (non-dynamically-allocated) ASCII string describing the error in human-readable form. If the \c{full} parameter is set, full validation should be performed: any set of parameters which would not permit generation of a sensible puzzle should be faulted. If \c{full} is \e{not} set, the implication is that these parameters are not going to be used for \e{generating} a puzzle; so parameters which can't even sensibly \e{describe} a valid puzzle should still be faulted, but parameters which only affect puzzle generation should not be. (The \c{full} option makes a difference when parameter combinations are non-orthogonal. For example, Net has a boolean option controlling whether it enforces a unique solution; it turns out that it's impossible to generate a uniquely soluble puzzle with wrapping walls and width 2, so \cw{validate_params()} will complain if you ask for one. However, if the user had just been playing a unique wrapping puzzle of a more sensible width, and then pastes in a game ID acquired from somebody else which happens to describe a \e{non}-unique wrapping width-2 puzzle, then \cw{validate_params()} will be passed a \c{game_params} containing the width and wrapping settings from the new game ID and the uniqueness setting from the old one. This would be faulted, if it weren't for the fact that \c{full} is not set during this call, so Net ignores the inconsistency. The resulting \c{game_params} is never subsequently used to generate a puzzle; this is a promise made by the mid-end when it asks for a non-full validation.) \H{backend-descs} Handling game descriptions In this section I present the functions that deal with a textual description of a puzzle, i.e. the part that comes after the colon in a descriptive-format game ID. \S{backend-new-desc} \cw{new_desc()} \c char *(*new_desc)(const game_params *params, random_state *rs, \c char **aux, int interactive); This function is where all the really hard work gets done. This is the function whose job is to randomly generate a new puzzle, ensuring solubility and uniqueness as appropriate. As input it is given a \c{game_params} structure and a random state (see \k{utils-random} for the random number API). It must invent a puzzle instance, encode it in string form, and return a dynamically allocated C string containing that encoding. Additionally, it may return a second dynamically allocated string in \c{*aux}. (If it doesn't want to, then it can leave that parameter completely alone; it isn't required to set it to \cw{NULL}, although doing so is harmless.) That string, if present, will be passed to \cw{solve()} (\k{backend-solve}) later on; so if the puzzle is generated in such a way that a solution is known, then information about that solution can be saved in \c{*aux} for \cw{solve()} to use. The \c{interactive} parameter should be ignored by almost all puzzles. Its purpose is to distinguish between generating a puzzle within a GUI context for immediate play, and generating a puzzle in a command-line context for saving to be played later. The only puzzle that currently uses this distinction (and, I fervently hope, the only one which will \e{ever} need to use it) is Mines, which chooses a random first-click location when generating puzzles non-interactively, but which waits for the user to place the first click when interactive. If you think you have come up with another puzzle which needs to make use of this parameter, please think for at least ten minutes about whether there is \e{any} alternative! Note that game description strings are not required to contain an encoding of parameters such as grid size; a game description is never separated from the \c{game_params} it was generated with, so any information contained in that structure need not be encoded again in the game description. \S{backend-validate-desc} \cw{validate_desc()} \c char *(*validate_desc)(const game_params *params, const char *desc); This function is given a game description, and its job is to validate that it describes a puzzle which makes sense. To some extent it's up to the user exactly how far they take the phrase \q{makes sense}; there are no particularly strict rules about how hard the user is permitted to shoot themself in the foot when typing in a bogus game description by hand. (For example, Rectangles will not verify that the sum of all the numbers in the grid equals the grid's area. So a user could enter a puzzle which was provably not soluble, and the program wouldn't complain; there just wouldn't happen to be any sequence of moves which solved it.) The one non-negotiable criterion is that any game description which makes it through \cw{validate_desc()} \e{must not} subsequently cause a crash or an assertion failure when fed to \cw{new_game()} and thence to the rest of the back end. The return value is \cw{NULL} on success, or a non-dynamically-allocated C string containing an error message. \S{backend-new-game} \cw{new_game()} \c game_state *(*new_game)(midend *me, const game_params *params, \c const char *desc); This function takes a game description as input, together with its accompanying \c{game_params}, and constructs a \c{game_state} describing the initial state of the puzzle. It returns a newly allocated \c{game_state} structure. Almost all puzzles should ignore the \c{me} parameter. It is required by Mines, which needs it for later passing to \cw{midend_supersede_game_desc()} (see \k{backend-supersede}) once the user has placed the first click. I fervently hope that no other puzzle will be awkward enough to require it, so everybody else should ignore it. As with the \c{interactive} parameter in \cw{new_desc()} (\k{backend-new-desc}), if you think you have a reason to need this parameter, please try very hard to think of an alternative approach! \H{backend-states} Handling game states This section describes the functions which create and destroy \c{game_state} structures. (Well, except \cw{new_game()}, which is in \k{backend-new-game} instead of under here; but it deals with game descriptions \e{and} game states and it had to go in one section or the other.) \S{backend-dup-game} \cw{dup_game()} \c game_state *(*dup_game)(const game_state *state); This function allocates a new \c{game_state} structure and initialises it with an exact copy of the information in the one provided as input. It returns a pointer to the new duplicate. \S{backend-free-game} \cw{free_game()} \c void (*free_game)(game_state *state); This function frees a \c{game_state} structure, and any subsidiary allocations contained within it. \H{backend-ui} Handling \c{game_ui} \S{backend-new-ui} \cw{new_ui()} \c game_ui *(*new_ui)(const game_state *state); This function allocates and returns a new \c{game_ui} structure for playing a particular puzzle. It is passed a pointer to the initial \c{game_state}, in case it needs to refer to that when setting up the initial values for the new game. \S{backend-free-ui} \cw{free_ui()} \c void (*free_ui)(game_ui *ui); This function frees a \c{game_ui} structure, and any subsidiary allocations contained within it. \S{backend-encode-ui} \cw{encode_ui()} \c char *(*encode_ui)(const game_ui *ui); This function encodes any \e{important} data in a \c{game_ui} structure in string form. It is only called when saving a half-finished game to a file. It should be used sparingly. Almost all data in a \c{game_ui} is not important enough to save. The location of the keyboard-controlled cursor, for example, can be reset to a default position on reloading the game without impacting the user experience. If the user should somehow manage to save a game while a mouse drag was in progress, then discarding that mouse drag would be an outright \e{feature}. A typical thing that \e{would} be worth encoding in this function is the Mines death counter: it's in the \c{game_ui} rather than the \c{game_state} because it's too important to allow the user to revert it by using Undo, and therefore it's also too important to allow the user to revert it by saving and reloading. (Of course, the user could edit the save file by hand... But if the user is \e{that} determined to cheat, they could just as easily modify the game's source.) \S{backend-decode-ui} \cw{decode_ui()} \c void (*decode_ui)(game_ui *ui, const char *encoding); This function parses a string previously output by \cw{encode_ui()}, and writes the decoded data back into the provided \c{game_ui} structure. \S{backend-changed-state} \cw{changed_state()} \c void (*changed_state)(game_ui *ui, const game_state *oldstate, \c const game_state *newstate); This function is called by the mid-end whenever the current game state changes, for any reason. Those reasons include: \b a fresh move being made by \cw{interpret_move()} and \cw{execute_move()} \b a solve operation being performed by \cw{solve()} and \cw{execute_move()} \b the user moving back and forth along the undo list by means of the Undo and Redo operations \b the user selecting Restart to go back to the initial game state. The job of \cw{changed_state()} is to update the \c{game_ui} for consistency with the new game state, if any update is necessary. For example, Same Game stores data about the currently selected tile group in its \c{game_ui}, and this data is intrinsically related to the game state it was derived from. So it's very likely to become invalid when the game state changes; thus, Same Game's \cw{changed_state()} function clears the current selection whenever it is called. When \cw{anim_length()} or \cw{flash_length()} are called, you can be sure that there has been a previous call to \cw{changed_state()}. So \cw{changed_state()} can set up data in the \c{game_ui} which will be read by \cw{anim_length()} and \cw{flash_length()}, and those functions will not have to worry about being called without the data having been initialised. \H{backend-moves} Making moves This section describes the functions which actually make moves in the game: that is, the functions which process user input and end up producing new \c{game_state}s. \S{backend-interpret-move} \cw{interpret_move()} \c char *(*interpret_move)(const game_state *state, game_ui *ui, \c const game_drawstate *ds, \c int x, int y, int button); This function receives user input and processes it. Its input parameters are the current \c{game_state}, the current \c{game_ui} and the current \c{game_drawstate}, plus details of the input event. \c{button} is either an ASCII value or a special code (listed below) indicating an arrow or function key or a mouse event; when \c{button} is a mouse event, \c{x} and \c{y} contain the pixel coordinates of the mouse pointer relative to the top left of the puzzle's drawing area. (The pointer to the \c{game_drawstate} is marked \c{const}, because \c{interpret_move} should not write to it. The normal use of that pointer will be to read the game's tile size parameter in order to divide mouse coordinates by it.) \cw{interpret_move()} may return in three different ways: \b Returning \cw{NULL} indicates that no action whatsoever occurred in response to the input event; the puzzle was not interested in it at all. \b Returning the empty string (\cw{""}) indicates that the input event has resulted in a change being made to the \c{game_ui} which will require a redraw of the game window, but that no actual \e{move} was made (i.e. no new \c{game_state} needs to be created). \b Returning anything else indicates that a move was made and that a new \c{game_state} must be created. However, instead of actually constructing a new \c{game_state} itself, this function is required to return a string description of the details of the move. This string will be passed to \cw{execute_move()} (\k{backend-execute-move}) to actually create the new \c{game_state}. (Encoding moves as strings in this way means that the mid-end can keep the strings as well as the game states, and the strings can be written to disk when saving the game and fed to \cw{execute_move()} again on reloading.) The return value from \cw{interpret_move()} is expected to be dynamically allocated if and only if it is not either \cw{NULL} \e{or} the empty string. After this function is called, the back end is permitted to rely on some subsequent operations happening in sequence: \b \cw{execute_move()} will be called to convert this move description into a new \c{game_state} \b \cw{changed_state()} will be called with the new \c{game_state}. This means that if \cw{interpret_move()} needs to do updates to the \c{game_ui} which are easier to perform by referring to the new \c{game_state}, it can safely leave them to be done in \cw{changed_state()} and not worry about them failing to happen. (Note, however, that \cw{execute_move()} may \e{also} be called in other circumstances. It is only \cw{interpret_move()} which can rely on a subsequent call to \cw{changed_state()}.) The special key codes supported by this function are: \dt \cw{LEFT_BUTTON}, \cw{MIDDLE_BUTTON}, \cw{RIGHT_BUTTON} \dd Indicate that one of the mouse buttons was pressed down. \dt \cw{LEFT_DRAG}, \cw{MIDDLE_DRAG}, \cw{RIGHT_DRAG} \dd Indicate that the mouse was moved while one of the mouse buttons was still down. The mid-end guarantees that when one of these events is received, it will always have been preceded by a button-down event (and possibly other drag events) for the same mouse button, and no event involving another mouse button will have appeared in between. \dt \cw{LEFT_RELEASE}, \cw{MIDDLE_RELEASE}, \cw{RIGHT_RELEASE} \dd Indicate that a mouse button was released. The mid-end guarantees that when one of these events is received, it will always have been preceded by a button-down event (and possibly some drag events) for the same mouse button, and no event involving another mouse button will have appeared in between. \dt \cw{CURSOR_UP}, \cw{CURSOR_DOWN}, \cw{CURSOR_LEFT}, \cw{CURSOR_RIGHT} \dd Indicate that an arrow key was pressed. \dt \cw{CURSOR_SELECT} \dd On platforms which have a prominent \q{select} button alongside their cursor keys, indicates that that button was pressed. In addition, there are some modifiers which can be bitwise-ORed into the \c{button} parameter: \dt \cw{MOD_CTRL}, \cw{MOD_SHFT} \dd These indicate that the Control or Shift key was pressed alongside the key. They only apply to the cursor keys, not to mouse buttons or anything else. \dt \cw{MOD_NUM_KEYPAD} \dd This applies to some ASCII values, and indicates that the key code was input via the numeric keypad rather than the main keyboard. Some puzzles may wish to treat this differently (for example, a puzzle might want to use the numeric keypad as an eight-way directional pad), whereas others might not (a game involving numeric input probably just wants to treat the numeric keypad as numbers). \dt \cw{MOD_MASK} \dd This mask is the bitwise OR of all the available modifiers; you can bitwise-AND with \cw{~MOD_MASK} to strip all the modifiers off any input value. \S{backend-execute-move} \cw{execute_move()} \c game_state *(*execute_move)(const game_state *state, char *move); This function takes an input \c{game_state} and a move string as output from \cw{interpret_move()}. It returns a newly allocated \c{game_state} which contains the result of applying the specified move to the input game state. This function may return \cw{NULL} if it cannot parse the move string (and this is definitely preferable to crashing or failing an assertion, since one way this can happen is if loading a corrupt save file). However, it must not return \cw{NULL} for any move string that really was output from \cw{interpret_move()}: this is punishable by assertion failure in the mid-end. \S{backend-can-solve} \c{can_solve} \c int can_solve; This boolean field is set to \cw{TRUE} if the game's \cw{solve()} function does something. If it's set to \cw{FALSE}, the game will not even offer the \q{Solve} menu option. \S{backend-solve} \cw{solve()} \c char *(*solve)(const game_state *orig, const game_state *curr, \c const char *aux, char **error); This function is called when the user selects the \q{Solve} option from the menu. It is passed two input game states: \c{orig} is the game state from the very start of the puzzle, and \c{curr} is the current one. (Different games find one or other or both of these convenient.) It is also passed the \c{aux} string saved by \cw{new_desc()} (\k{backend-new-desc}), in case that encodes important information needed to provide the solution. If this function is unable to produce a solution (perhaps, for example, the game has no in-built solver so it can only solve puzzles it invented internally and has an \c{aux} string for) then it may return \cw{NULL}. If it does this, it must also set \c{*error} to an error message to be presented to the user (such as \q{Solution not known for this puzzle}); that error message is not expected to be dynamically allocated. If this function \e{does} produce a solution, it returns a move string suitable for feeding to \cw{execute_move()} (\k{backend-execute-move}). Like a (non-empty) string returned from \cw{interpret_move()}, the returned string should be dynamically allocated. \H{backend-drawing} Drawing the game graphics This section discusses the back end functions that deal with drawing. \S{backend-new-drawstate} \cw{new_drawstate()} \c game_drawstate *(*new_drawstate)(drawing *dr, \c const game_state *state); This function allocates and returns a new \c{game_drawstate} structure for drawing a particular puzzle. It is passed a pointer to a \c{game_state}, in case it needs to refer to that when setting up any initial data. This function may not rely on the puzzle having been newly started; a new draw state can be constructed at any time if the front end requests a forced redraw. For games like Pattern, in which initial game states are much simpler than general ones, this might be important to keep in mind. The parameter \c{dr} is a drawing object (see \k{drawing}) which the function might need to use to allocate blitters. (However, this isn't recommended; it's usually more sensible to wait to allocate a blitter until \cw{set_size()} is called, because that way you can tailor it to the scale at which the puzzle is being drawn.) \S{backend-free-drawstate} \cw{free_drawstate()} \c void (*free_drawstate)(drawing *dr, game_drawstate *ds); This function frees a \c{game_drawstate} structure, and any subsidiary allocations contained within it. The parameter \c{dr} is a drawing object (see \k{drawing}), which might be required if you are freeing a blitter. \S{backend-preferred-tilesize} \c{preferred_tilesize} \c int preferred_tilesize; Each game is required to define a single integer parameter which expresses, in some sense, the scale at which it is drawn. This is described in the APIs as \cq{tilesize}, since most puzzles are on a square (or possibly triangular or hexagonal) grid and hence a sensible interpretation of this parameter is to define it as the size of one grid tile in pixels; however, there's no actual requirement that the \q{tile size} be proportional to the game window size. Window size is required to increase monotonically with \q{tile size}, however. The data element \c{preferred_tilesize} indicates the tile size which should be used in the absence of a good reason to do otherwise (such as the screen being too small, or the user explicitly requesting a resize if that ever gets implemented). \S{backend-compute-size} \cw{compute_size()} \c void (*compute_size)(const game_params *params, int tilesize, \c int *x, int *y); This function is passed a \c{game_params} structure and a tile size. It returns, in \c{*x} and \c{*y}, the size in pixels of the drawing area that would be required to render a puzzle with those parameters at that tile size. \S{backend-set-size} \cw{set_size()} \c void (*set_size)(drawing *dr, game_drawstate *ds, \c const game_params *params, int tilesize); This function is responsible for setting up a \c{game_drawstate} to draw at a given tile size. Typically this will simply involve copying the supplied \c{tilesize} parameter into a \c{tilesize} field inside the draw state; for some more complex games it might also involve setting up other dimension fields, or possibly allocating a blitter (see \k{drawing-blitter}). The parameter \c{dr} is a drawing object (see \k{drawing}), which is required if a blitter needs to be allocated. Back ends may assume (and may enforce by assertion) that this function will be called at most once for any \c{game_drawstate}. If a puzzle needs to be redrawn at a different size, the mid-end will create a fresh drawstate. \S{backend-colours} \cw{colours()} \c float *(*colours)(frontend *fe, int *ncolours); This function is responsible for telling the front end what colours the puzzle will need to draw itself. It returns the number of colours required in \c{*ncolours}, and the return value from the function itself is a dynamically allocated array of three times that many \c{float}s, containing the red, green and blue components of each colour respectively as numbers in the range [0,1]. The second parameter passed to this function is a front end handle. The only things it is permitted to do with this handle are to call the front-end function called \cw{frontend_default_colour()} (see \k{frontend-default-colour}) or the utility function called \cw{game_mkhighlight()} (see \k{utils-game-mkhighlight}). (The latter is a wrapper on the former, so front end implementors only need to provide \cw{frontend_default_colour()}.) This allows \cw{colours()} to take local configuration into account when deciding on its own colour allocations. Most games use the front end's default colour as their background, apart from a few which depend on drawing relief highlights so they adjust the background colour if it's too light for highlights to show up against it. Note that the colours returned from this function are for \e{drawing}, not for printing. Printing has an entirely different colour allocation policy. \S{backend-anim-length} \cw{anim_length()} \c float (*anim_length)(const game_state *oldstate, \c const game_state *newstate, \c int dir, game_ui *ui); This function is called when a move is made, undone or redone. It is given the old and the new \c{game_state}, and its job is to decide whether the transition between the two needs to be animated or can be instant. \c{oldstate} is the state that was current until this call; \c{newstate} is the state that will be current after it. \c{dir} specifies the chronological order of those states: if it is positive, then the transition is the result of a move or a redo (and so \c{newstate} is the later of the two moves), whereas if it is negative then the transition is the result of an undo (so that \c{newstate} is the \e{earlier} move). If this function decides the transition should be animated, it returns the desired length of the animation in seconds. If not, it returns zero. State changes as a result of a Restart operation are never animated; the mid-end will handle them internally and never consult this function at all. State changes as a result of Solve operations are also not animated by default, although you can change this for a particular game by setting a flag in \c{flags} (\k{backend-flags}). The function is also passed a pointer to the local \c{game_ui}. It may refer to information in here to help with its decision (see \k{writing-conditional-anim} for an example of this), and/or it may \e{write} information about the nature of the animation which will be read later by \cw{redraw()}. When this function is called, it may rely on \cw{changed_state()} having been called previously, so if \cw{anim_length()} needs to refer to information in the \c{game_ui}, then \cw{changed_state()} is a reliable place to have set that information up. Move animations do not inhibit further input events. If the user continues playing before a move animation is complete, the animation will be abandoned and the display will jump straight to the final state. \S{backend-flash-length} \cw{flash_length()} \c float (*flash_length)(const game_state *oldstate, \c const game_state *newstate, \c int dir, game_ui *ui); This function is called when a move is completed. (\q{Completed} means that not only has the move been made, but any animation which accompanied it has finished.) It decides whether the transition from \c{oldstate} to \c{newstate} merits a \q{flash}. A flash is much like a move animation, but it is \e{not} interrupted by further user interface activity; it runs to completion in parallel with whatever else might be going on on the display. The only thing which will rush a flash to completion is another flash. The purpose of flashes is to indicate that the game has been completed. They were introduced as a separate concept from move animations because of Net: the habit of most Net players (and certainly me) is to rotate a tile into place and immediately lock it, then move on to another tile. When you make your last move, at the instant the final tile is rotated into place the screen starts to flash to indicate victory \dash but if you then press the lock button out of habit, then the move animation is cancelled, and the victory flash does not complete. (And if you \e{don't} press the lock button, the completed grid will look untidy because there will be one unlocked square.) Therefore, I introduced a specific concept of a \q{flash} which is separate from a move animation and can proceed in parallel with move animations and any other display activity, so that the victory flash in Net is not cancelled by that final locking move. The input parameters to \cw{flash_length()} are exactly the same as the ones to \cw{anim_length()}. Just like \cw{anim_length()}, when this function is called, it may rely on \cw{changed_state()} having been called previously, so if it needs to refer to information in the \c{game_ui} then \cw{changed_state()} is a reliable place to have set that information up. (Some games use flashes to indicate defeat as well as victory; Mines, for example, flashes in a different colour when you tread on a mine from the colour it uses when you complete the game. In order to achieve this, its \cw{flash_length()} function has to store a flag in the \c{game_ui} to indicate which flash type is required.) \S{backend-status} \cw{status()} \c int (*status)(const game_state *state); This function returns a status value indicating whether the current game is still in play, or has been won, or has been conclusively lost. The mid-end uses this to implement \cw{midend_status()} (\k{midend-status}). The return value should be +1 if the game has been successfully solved. If the game has been lost in a situation where further play is unlikely, the return value should be -1. If neither is true (so play is still ongoing), return zero. Front ends may wish to use a non-zero status as a cue to proactively offer the option of starting a new game. Therefore, back ends should not return -1 if the game has been \e{technically} lost but undoing and continuing is still a realistic possibility. (For instance, games with hidden information such as Guess or Mines might well return a non-zero status whenever they reveal the solution, whether or not the player guessed it correctly, on the grounds that a player would be unlikely to hide the solution and continue playing after the answer was spoiled. On the other hand, games where you can merely get into a dead end such as Same Game or Inertia might choose to return 0 in that situation, on the grounds that the player would quite likely press Undo and carry on playing.) \S{backend-redraw} \cw{redraw()} \c void (*redraw)(drawing *dr, game_drawstate *ds, \c const game_state *oldstate, \c const game_state *newstate, \c int dir, const game_ui *ui, \c float anim_time, float flash_time); This function is responsible for actually drawing the contents of the game window, and for redrawing every time the game state or the \c{game_ui} changes. The parameter \c{dr} is a drawing object which may be passed to the drawing API functions (see \k{drawing} for documentation of the drawing API). This function may not save \c{dr} and use it elsewhere; it must only use it for calling back to the drawing API functions within its own lifetime. \c{ds} is the local \c{game_drawstate}, of course, and \c{ui} is the local \c{game_ui}. \c{newstate} is the semantically-current game state, and is always non-\cw{NULL}. If \c{oldstate} is also non-\cw{NULL}, it means that a move has recently been made and the game is still in the process of displaying an animation linking the old and new states; in this situation, \c{anim_time} will give the length of time (in seconds) that the animation has already been running. If \c{oldstate} is \cw{NULL}, then \c{anim_time} is unused (and will hopefully be set to zero to avoid confusion). \c{flash_time}, if it is is non-zero, denotes that the game is in the middle of a flash, and gives the time since the start of the flash. See \k{backend-flash-length} for general discussion of flashes. The very first time this function is called for a new \c{game_drawstate}, it is expected to redraw the \e{entire} drawing area. Since this often involves drawing visual furniture which is never subsequently altered, it is often simplest to arrange this by having a special \q{first time} flag in the draw state, and resetting it after the first redraw. When this function (or any subfunction) calls the drawing API, it is expected to pass colour indices which were previously defined by the \cw{colours()} function. \H{backend-printing} Printing functions This section discusses the back end functions that deal with printing puzzles out on paper. \S{backend-can-print} \c{can_print} \c int can_print; This flag is set to \cw{TRUE} if the puzzle is capable of printing itself on paper. (This makes sense for some puzzles, such as Solo, which can be filled in with a pencil. Other puzzles, such as Twiddle, inherently involve moving things around and so would not make sense to print.) If this flag is \cw{FALSE}, then the functions \cw{print_size()} and \cw{print()} will never be called. \S{backend-can-print-in-colour} \c{can_print_in_colour} \c int can_print_in_colour; This flag is set to \cw{TRUE} if the puzzle is capable of printing itself differently when colour is available. For example, Map can actually print coloured regions in different \e{colours} rather than resorting to cross-hatching. If the \c{can_print} flag is \cw{FALSE}, then this flag will be ignored. \S{backend-print-size} \cw{print_size()} \c void (*print_size)(const game_params *params, float *x, float *y); This function is passed a \c{game_params} structure and a tile size. It returns, in \c{*x} and \c{*y}, the preferred size in \e{millimetres} of that puzzle if it were to be printed out on paper. If the \c{can_print} flag is \cw{FALSE}, this function will never be called. \S{backend-print} \cw{print()} \c void (*print)(drawing *dr, const game_state *state, int tilesize); This function is called when a puzzle is to be printed out on paper. It should use the drawing API functions (see \k{drawing}) to print itself. This function is separate from \cw{redraw()} because it is often very different: \b The printing function may not depend on pixel accuracy, since printer resolution is variable. Draw as if your canvas had infinite resolution. \b The printing function sometimes needs to display things in a completely different style. Net, for example, is very different as an on-screen puzzle and as a printed one. \b The printing function is often much simpler since it has no need to deal with repeated partial redraws. However, there's no reason the printing and redraw functions can't share some code if they want to. When this function (or any subfunction) calls the drawing API, the colour indices it passes should be colours which have been allocated by the \cw{print_*_colour()} functions within this execution of \cw{print()}. This is very different from the fixed small number of colours used in \cw{redraw()}, because printers do not have a limitation on the total number of colours that may be used. Some puzzles' printing functions might wish to allocate only one \q{ink} colour and use it for all drawing; others might wish to allocate \e{more} colours than are used on screen. One possible colour policy worth mentioning specifically is that a puzzle's printing function might want to allocate the \e{same} colour indices as are used by the redraw function, so that code shared between drawing and printing does not have to keep switching its colour indices. In order to do this, the simplest thing is to make use of the fact that colour indices returned from \cw{print_*_colour()} are guaranteed to be in increasing order from zero. So if you have declared an \c{enum} defining three colours \cw{COL_BACKGROUND}, \cw{COL_THIS} and \cw{COL_THAT}, you might then write \c int c; \c c = print_mono_colour(dr, 1); assert(c == COL_BACKGROUND); \c c = print_mono_colour(dr, 0); assert(c == COL_THIS); \c c = print_mono_colour(dr, 0); assert(c == COL_THAT); If the \c{can_print} flag is \cw{FALSE}, this function will never be called. \H{backend-misc} Miscellaneous \S{backend-can-format-as-text-ever} \c{can_format_as_text_ever} \c int can_format_as_text_ever; This boolean field is \cw{TRUE} if the game supports formatting a game state as ASCII text (typically ASCII art) for copying to the clipboard and pasting into other applications. If it is \cw{FALSE}, front ends will not offer the \q{Copy} command at all. If this field is \cw{TRUE}, the game does not necessarily have to support text formatting for \e{all} games: e.g. a game which can be played on a square grid or a triangular one might only support copy and paste for the former, because triangular grids in ASCII art are just too difficult. If this field is \cw{FALSE}, the functions \cw{can_format_as_text_now()} (\k{backend-can-format-as-text-now}) and \cw{text_format()} (\k{backend-text-format}) are never called. \S{backend-can-format-as-text-now} \c{can_format_as_text_now()} \c int (*can_format_as_text_now)(const game_params *params); This function is passed a \c{game_params} and returns a boolean, which is \cw{TRUE} if the game can support ASCII text output for this particular game type. If it returns \cw{FALSE}, front ends will grey out or otherwise disable the \q{Copy} command. Games may enable and disable the copy-and-paste function for different game \e{parameters}, but are currently constrained to return the same answer from this function for all game \e{states} sharing the same parameters. In other words, the \q{Copy} function may enable or disable itself when the player changes game preset, but will never change during play of a single game or when another game of exactly the same type is generated. This function should not take into account aspects of the game parameters which are not encoded by \cw{encode_params()} (\k{backend-encode-params}) when the \c{full} parameter is set to \cw{FALSE}. Such parameters will not necessarily match up between a call to this function and a subsequent call to \cw{text_format()} itself. (For instance, game \e{difficulty} should not affect whether the game can be copied to the clipboard. Only the actual visible \e{shape} of the game can affect that.) \S{backend-text-format} \cw{text_format()} \c char *(*text_format)(const game_state *state); This function is passed a \c{game_state}, and returns a newly allocated C string containing an ASCII representation of that game state. It is used to implement the \q{Copy} operation in many front ends. This function will only ever be called if the back end field \c{can_format_as_text_ever} (\k{backend-can-format-as-text-ever}) is \cw{TRUE} \e{and} the function \cw{can_format_as_text_now()} (\k{backend-can-format-as-text-now}) has returned \cw{TRUE} for the currently selected game parameters. The returned string may contain line endings (and will probably want to), using the normal C internal \cq{\\n} convention. For consistency between puzzles, all multi-line textual puzzle representations should \e{end} with a newline as well as containing them internally. (There are currently no puzzles which have a one-line ASCII representation, so there's no precedent yet for whether that should come with a newline or not.) \S{backend-wants-statusbar} \cw{wants_statusbar} \c int wants_statusbar; This boolean field is set to \cw{TRUE} if the puzzle has a use for a textual status line (to display score, completion status, currently active tiles, etc). \S{backend-is-timed} \c{is_timed} \c int is_timed; This boolean field is \cw{TRUE} if the puzzle is time-critical. If so, the mid-end will maintain a game timer while the user plays. If this field is \cw{FALSE}, then \cw{timing_state()} will never be called and need not do anything. \S{backend-timing-state} \cw{timing_state()} \c int (*timing_state)(const game_state *state, game_ui *ui); This function is passed the current \c{game_state} and the local \c{game_ui}; it returns \cw{TRUE} if the game timer should currently be running. A typical use for the \c{game_ui} in this function is to note when the game was first completed (by setting a flag in \cw{changed_state()} \dash see \k{backend-changed-state}), and freeze the timer thereafter so that the user can undo back through their solution process without altering their time. \S{backend-flags} \c{flags} \c int flags; This field contains miscellaneous per-backend flags. It consists of the bitwise OR of some combination of the following: \dt \cw{BUTTON_BEATS(x,y)} \dd Given any \cw{x} and \cw{y} from the set \{\cw{LEFT_BUTTON}, \cw{MIDDLE_BUTTON}, \cw{RIGHT_BUTTON}\}, this macro evaluates to a bit flag which indicates that when buttons \cw{x} and \cw{y} are both pressed simultaneously, the mid-end should consider \cw{x} to have priority. (In the absence of any such flags, the mid-end will always consider the most recently pressed button to have priority.) \dt \cw{SOLVE_ANIMATES} \dd This flag indicates that moves generated by \cw{solve()} (\k{backend-solve}) are candidates for animation just like any other move. For most games, solve moves should not be animated, so the mid-end doesn't even bother calling \cw{anim_length()} (\k{backend-anim-length}), thus saving some special-case code in each game. On the rare occasion that animated solve moves are actually required, you can set this flag. \dt \cw{REQUIRE_RBUTTON} \dd This flag indicates that the puzzle cannot be usefully played without the use of mouse buttons other than the left one. On some PDA platforms, this flag is used by the front end to enable right-button emulation through an appropriate gesture. Note that a puzzle is not required to set this just because it \e{uses} the right button, but only if its use of the right button is critical to playing the game. (Slant, for example, uses the right button to cycle through the three square states in the opposite order from the left button, and hence can manage fine without it.) \dt \cw{REQUIRE_NUMPAD} \dd This flag indicates that the puzzle cannot be usefully played without the use of number-key input. On some PDA platforms it causes an emulated number pad to appear on the screen. Similarly to \cw{REQUIRE_RBUTTON}, a puzzle need not specify this simply if its use of the number keys is not critical. \H{backend-initiative} Things a back end may do on its own initiative This section describes a couple of things that a back end may choose to do by calling functions elsewhere in the program, which would not otherwise be obvious. \S{backend-newrs} Create a random state If a back end needs random numbers at some point during normal play, it can create a fresh \c{random_state} by first calling \c{get_random_seed} (\k{frontend-get-random-seed}) and then passing the returned seed data to \cw{random_new()}. This is likely not to be what you want. If a puzzle needs randomness in the middle of play, it's likely to be more sensible to store some sort of random state within the \c{game_state}, so that the random numbers are tied to the particular game state and hence the player can't simply keep undoing their move until they get numbers they like better. This facility is currently used only in Net, to implement the \q{jumble} command, which sets every unlocked tile to a new random orientation. This randomness \e{is} a reasonable use of the feature, because it's non-adversarial \dash there's no advantage to the user in getting different random numbers. \S{backend-supersede} Supersede its own game description In response to a move, a back end is (reluctantly) permitted to call \cw{midend_supersede_game_desc()}: \c void midend_supersede_game_desc(midend *me, \c char *desc, char *privdesc); When the user selects \q{New Game}, the mid-end calls \cw{new_desc()} (\k{backend-new-desc}) to get a new game description, and (as well as using that to generate an initial game state) stores it for the save file and for telling to the user. The function above overwrites that game description, and also splits it in two. \c{desc} becomes the new game description which is provided to the user on request, and is also the one used to construct a new initial game state if the user selects \q{Restart}. \c{privdesc} is a \q{private} game description, used to reconstruct the game's initial state when reloading. The distinction between the two, as well as the need for this function at all, comes from Mines. Mines begins with a blank grid and no idea of where the mines actually are; \cw{new_desc()} does almost no work in interactive mode, and simply returns a string encoding the \c{random_state}. When the user first clicks to open a tile, \e{then} Mines generates the mine positions, in such a way that the game is soluble from that starting point. Then it uses this function to supersede the random-state game description with a proper one. But it needs two: one containing the initial click location (because that's what you want to happen if you restart the game, and also what you want to send to a friend so that they play \e{the same game} as you), and one without the initial click location (because when you save and reload the game, you expect to see the same blank initial state as you had before saving). I should stress again that this function is a horrid hack. Nobody should use it if they're not Mines; if you think you need to use it, think again repeatedly in the hope of finding a better way to do whatever it was you needed to do. \C{drawing} The drawing API The back end function \cw{redraw()} (\k{backend-redraw}) is required to draw the puzzle's graphics on the window's drawing area, or on paper if the puzzle is printable. To do this portably, it is provided with a drawing API allowing it to talk directly to the front end. In this chapter I document that API, both for the benefit of back end authors trying to use it and for front end authors trying to implement it. The drawing API as seen by the back end is a collection of global functions, each of which takes a pointer to a \c{drawing} structure (a \q{drawing object}). These objects are supplied as parameters to the back end's \cw{redraw()} and \cw{print()} functions. In fact these global functions are not implemented directly by the front end; instead, they are implemented centrally in \c{drawing.c} and form a small piece of middleware. The drawing API as supplied by the front end is a structure containing a set of function pointers, plus a \cq{void *} handle which is passed to each of those functions. This enables a single front end to switch between multiple implementations of the drawing API if necessary. For example, the Windows API supplies a printing mechanism integrated into the same GDI which deals with drawing in windows, and therefore the same API implementation can handle both drawing and printing; but on Unix, the most common way for applications to print is by producing PostScript output directly, and although it would be \e{possible} to write a single (say) \cw{draw_rect()} function which checked a global flag to decide whether to do GTK drawing operations or output PostScript to a file, it's much nicer to have two separate functions and switch between them as appropriate. When drawing, the puzzle window is indexed by pixel coordinates, with the top left pixel defined as \cw{(0,0)} and the bottom right pixel \cw{(w-1,h-1)}, where \c{w} and \c{h} are the width and height values returned by the back end function \cw{compute_size()} (\k{backend-compute-size}). When printing, the puzzle's print area is indexed in exactly the same way (with an arbitrary tile size provided by the printing module \c{printing.c}), to facilitate sharing of code between the drawing and printing routines. However, when printing, puzzles may no longer assume that the coordinate unit has any relationship to a pixel; the printer's actual resolution might very well not even be known at print time, so the coordinate unit might be smaller or larger than a pixel. Puzzles' print functions should restrict themselves to drawing geometric shapes rather than fiddly pixel manipulation. \e{Puzzles' redraw functions may assume that the surface they draw on is persistent}. It is the responsibility of every front end to preserve the puzzle's window contents in the face of GUI window expose issues and similar. It is not permissible to request that the back end redraw any part of a window that it has already drawn, unless something has actually changed as a result of making moves in the puzzle. Most front ends accomplish this by having the drawing routines draw on a stored bitmap rather than directly on the window, and copying the bitmap to the window every time a part of the window needs to be redrawn. Therefore, it is vitally important that whenever the back end does any drawing it informs the front end of which parts of the window it has accessed, and hence which parts need repainting. This is done by calling \cw{draw_update()} (\k{drawing-draw-update}). Persistence of old drawing is convenient. However, a puzzle should be very careful about how it updates its drawing area. The problem is that some front ends do anti-aliased drawing: rather than simply choosing between leaving each pixel untouched or painting it a specified colour, an antialiased drawing function will \e{blend} the original and new colours in pixels at a figure's boundary according to the proportion of the pixel occupied by the figure (probably modified by some heuristic fudge factors). All of this produces a smoother appearance for curves and diagonal lines. An unfortunate effect of drawing an anti-aliased figure repeatedly is that the pixels around the figure's boundary come steadily more saturated with \q{ink} and the boundary appears to \q{spread out}. Worse, redrawing a figure in a different colour won't fully paint over the old boundary pixels, so the end result is a rather ugly smudge. A good strategy to avoid unpleasant anti-aliasing artifacts is to identify a number of rectangular areas which need to be redrawn, clear them to the background colour, and then redraw their contents from scratch, being careful all the while not to stray beyond the boundaries of the original rectangles. The \cw{clip()} function (\k{drawing-clip}) comes in very handy here. Games based on a square grid can often do this fairly easily. Other games may need to be somewhat more careful. For example, Loopy's redraw function first identifies portions of the display which need to be updated. Then, if the changes are fairly well localised, it clears and redraws a rectangle containing each changed area. Otherwise, it gives up and redraws the entire grid from scratch. It is possible to avoid clearing to background and redrawing from scratch if one is very careful about which drawing functions one uses: if a function is documented as not anti-aliasing under some circumstances, you can rely on each pixel in a drawing either being left entirely alone or being set to the requested colour, with no blending being performed. In the following sections I first discuss the drawing API as seen by the back end, and then the \e{almost} identical function-pointer form seen by the front end. \H{drawing-backend} Drawing API as seen by the back end This section documents the back-end drawing API, in the form of functions which take a \c{drawing} object as an argument. \S{drawing-draw-rect} \cw{draw_rect()} \c void draw_rect(drawing *dr, int x, int y, int w, int h, \c int colour); Draws a filled rectangle in the puzzle window. \c{x} and \c{y} give the coordinates of the top left pixel of the rectangle. \c{w} and \c{h} give its width and height. Thus, the horizontal extent of the rectangle runs from \c{x} to \c{x+w-1} inclusive, and the vertical extent from \c{y} to \c{y+h-1} inclusive. \c{colour} is an integer index into the colours array returned by the back end function \cw{colours()} (\k{backend-colours}). There is no separate pixel-plotting function. If you want to plot a single pixel, the approved method is to use \cw{draw_rect()} with width and height set to 1. Unlike many of the other drawing functions, this function is guaranteed to be pixel-perfect: the rectangle will be sharply defined and not anti-aliased or anything like that. This function may be used for both drawing and printing. \S{drawing-draw-rect-outline} \cw{draw_rect_outline()} \c void draw_rect_outline(drawing *dr, int x, int y, int w, int h, \c int colour); Draws an outline rectangle in the puzzle window. \c{x} and \c{y} give the coordinates of the top left pixel of the rectangle. \c{w} and \c{h} give its width and height. Thus, the horizontal extent of the rectangle runs from \c{x} to \c{x+w-1} inclusive, and the vertical extent from \c{y} to \c{y+h-1} inclusive. \c{colour} is an integer index into the colours array returned by the back end function \cw{colours()} (\k{backend-colours}). From a back end perspective, this function may be considered to be part of the drawing API. However, front ends are not required to implement it, since it is actually implemented centrally (in \cw{misc.c}) as a wrapper on \cw{draw_polygon()}. This function may be used for both drawing and printing. \S{drawing-draw-line} \cw{draw_line()} \c void draw_line(drawing *dr, int x1, int y1, int x2, int y2, \c int colour); Draws a straight line in the puzzle window. \c{x1} and \c{y1} give the coordinates of one end of the line. \c{x2} and \c{y2} give the coordinates of the other end. The line drawn includes both those points. \c{colour} is an integer index into the colours array returned by the back end function \cw{colours()} (\k{backend-colours}). Some platforms may perform anti-aliasing on this function. Therefore, do not assume that you can erase a line by drawing the same line over it in the background colour; anti-aliasing might lead to perceptible ghost artefacts around the vanished line. Horizontal and vertical lines, however, are pixel-perfect and not anti-aliased. This function may be used for both drawing and printing. \S{drawing-draw-polygon} \cw{draw_polygon()} \c void draw_polygon(drawing *dr, int *coords, int npoints, \c int fillcolour, int outlinecolour); Draws an outlined or filled polygon in the puzzle window. \c{coords} is an array of \cw{(2*npoints)} integers, containing the \c{x} and \c{y} coordinates of \c{npoints} vertices. \c{fillcolour} and \c{outlinecolour} are integer indices into the colours array returned by the back end function \cw{colours()} (\k{backend-colours}). \c{fillcolour} may also be \cw{-1} to indicate that the polygon should be outlined only. The polygon defined by the specified list of vertices is first filled in \c{fillcolour}, if specified, and then outlined in \c{outlinecolour}. \c{outlinecolour} may \e{not} be \cw{-1}; it must be a valid colour (and front ends are permitted to enforce this by assertion). This is because different platforms disagree on whether a filled polygon should include its boundary line or not, so drawing \e{only} a filled polygon would have non-portable effects. If you want your filled polygon not to have a visible outline, you must set \c{outlinecolour} to the same as \c{fillcolour}. Some platforms may perform anti-aliasing on this function. Therefore, do not assume that you can erase a polygon by drawing the same polygon over it in the background colour. Also, be prepared for the polygon to extend a pixel beyond its obvious bounding box as a result of this; if you really need it not to do this to avoid interfering with other delicate graphics, you should probably use \cw{clip()} (\k{drawing-clip}). You can rely on horizontal and vertical lines not being anti-aliased. This function may be used for both drawing and printing. \S{drawing-draw-circle} \cw{draw_circle()} \c void draw_circle(drawing *dr, int cx, int cy, int radius, \c int fillcolour, int outlinecolour); Draws an outlined or filled circle in the puzzle window. \c{cx} and \c{cy} give the coordinates of the centre of the circle. \c{radius} gives its radius. The total horizontal pixel extent of the circle is from \c{cx-radius+1} to \c{cx+radius-1} inclusive, and the vertical extent similarly around \c{cy}. \c{fillcolour} and \c{outlinecolour} are integer indices into the colours array returned by the back end function \cw{colours()} (\k{backend-colours}). \c{fillcolour} may also be \cw{-1} to indicate that the circle should be outlined only. The circle is first filled in \c{fillcolour}, if specified, and then outlined in \c{outlinecolour}. \c{outlinecolour} may \e{not} be \cw{-1}; it must be a valid colour (and front ends are permitted to enforce this by assertion). This is because different platforms disagree on whether a filled circle should include its boundary line or not, so drawing \e{only} a filled circle would have non-portable effects. If you want your filled circle not to have a visible outline, you must set \c{outlinecolour} to the same as \c{fillcolour}. Some platforms may perform anti-aliasing on this function. Therefore, do not assume that you can erase a circle by drawing the same circle over it in the background colour. Also, be prepared for the circle to extend a pixel beyond its obvious bounding box as a result of this; if you really need it not to do this to avoid interfering with other delicate graphics, you should probably use \cw{clip()} (\k{drawing-clip}). This function may be used for both drawing and printing. \S{drawing-draw-thick-line} \cw{draw_thick_line()} \c void draw_thick_line(drawing *dr, float thickness, \c float x1, float y1, float x2, float y2, \c int colour) Draws a line in the puzzle window, giving control over the line's thickness. \c{x1} and \c{y1} give the coordinates of one end of the line. \c{x2} and \c{y2} give the coordinates of the other end. \c{thickness} gives the thickness of the line, in pixels. Note that the coordinates and thickness are floating-point: the continuous coordinate system is in effect here. It's important to be able to address points with better-than-pixel precision in this case, because one can't otherwise properly express the endpoints of lines with both odd and even thicknesses. Some platforms may perform anti-aliasing on this function. The precise pixels affected by a thick-line drawing operation may vary between platforms, and no particular guarantees are provided. Indeed, even horizontal or vertical lines may be anti-aliased. This function may be used for both drawing and printing. \S{drawing-draw-text} \cw{draw_text()} \c void draw_text(drawing *dr, int x, int y, int fonttype, \c int fontsize, int align, int colour, char *text); Draws text in the puzzle window. \c{x} and \c{y} give the coordinates of a point. The relation of this point to the location of the text is specified by \c{align}, which is a bitwise OR of horizontal and vertical alignment flags: \dt \cw{ALIGN_VNORMAL} \dd Indicates that \c{y} is aligned with the baseline of the text. \dt \cw{ALIGN_VCENTRE} \dd Indicates that \c{y} is aligned with the vertical centre of the text. (In fact, it's aligned with the vertical centre of normal \e{capitalised} text: displaying two pieces of text with \cw{ALIGN_VCENTRE} at the same \cw{y}-coordinate will cause their baselines to be aligned with one another, even if one is an ascender and the other a descender.) \dt \cw{ALIGN_HLEFT} \dd Indicates that \c{x} is aligned with the left-hand end of the text. \dt \cw{ALIGN_HCENTRE} \dd Indicates that \c{x} is aligned with the horizontal centre of the text. \dt \cw{ALIGN_HRIGHT} \dd Indicates that \c{x} is aligned with the right-hand end of the text. \c{fonttype} is either \cw{FONT_FIXED} or \cw{FONT_VARIABLE}, for a monospaced or proportional font respectively. (No more detail than that may be specified; it would only lead to portability issues between different platforms.) \c{fontsize} is the desired size, in pixels, of the text. This size corresponds to the overall point size of the text, not to any internal dimension such as the cap-height. \c{colour} is an integer index into the colours array returned by the back end function \cw{colours()} (\k{backend-colours}). This function may be used for both drawing and printing. The character set used to encode the text passed to this function is specified \e{by the drawing object}, although it must be a superset of ASCII. If a puzzle wants to display text that is not contained in ASCII, it should use the \cw{text_fallback()} function (\k{drawing-text-fallback}) to query the drawing object for an appropriate representation of the characters it wants. \S{drawing-text-fallback} \cw{text_fallback()} \c char *text_fallback(drawing *dr, const char *const *strings, \c int nstrings); This function is used to request a translation of UTF-8 text into whatever character encoding is expected by the drawing object's implementation of \cw{draw_text()}. The input is a list of strings encoded in UTF-8: \cw{nstrings} gives the number of strings in the list, and \cw{strings[0]}, \cw{strings[1]}, ..., \cw{strings[nstrings-1]} are the strings themselves. The returned string (which is dynamically allocated and must be freed when finished with) is derived from the first string in the list that the drawing object expects to be able to display reliably; it will consist of that string translated into the character set expected by \cw{draw_text()}. Drawing implementations are not required to handle anything outside ASCII, but are permitted to assume that \e{some} string will be successfully translated. So every call to this function must include a string somewhere in the list (presumably the last element) which consists of nothing but ASCII, to be used by any front end which cannot handle anything else. For example, if a puzzle wished to display a string including a multiplication sign (U+00D7 in Unicode, represented by the bytes C3 97 in UTF-8), it might do something like this: \c static const char *const times_signs[] = { "\xC3\x97", "x" }; \c char *times_sign = text_fallback(dr, times_signs, 2); \c sprintf(buffer, "%d%s%d", width, times_sign, height); \c draw_text(dr, x, y, font, size, align, colour, buffer); \c sfree(buffer); which would draw a string with a times sign in the middle on platforms that support it, and fall back to a simple ASCII \cq{x} where there was no alternative. \S{drawing-clip} \cw{clip()} \c void clip(drawing *dr, int x, int y, int w, int h); Establishes a clipping rectangle in the puzzle window. \c{x} and \c{y} give the coordinates of the top left pixel of the clipping rectangle. \c{w} and \c{h} give its width and height. Thus, the horizontal extent of the rectangle runs from \c{x} to \c{x+w-1} inclusive, and the vertical extent from \c{y} to \c{y+h-1} inclusive. (These are exactly the same semantics as \cw{draw_rect()}.) After this call, no drawing operation will affect anything outside the specified rectangle. The effect can be reversed by calling \cw{unclip()} (\k{drawing-unclip}). The clipping rectangle is pixel-perfect: pixels within the rectangle are affected as usual by drawing functions; pixels outside are completely untouched. Back ends should not assume that a clipping rectangle will be automatically cleared up by the front end if it's left lying around; that might work on current front ends, but shouldn't be relied upon. Always explicitly call \cw{unclip()}. This function may be used for both drawing and printing. \S{drawing-unclip} \cw{unclip()} \c void unclip(drawing *dr); Reverts the effect of a previous call to \cw{clip()}. After this call, all drawing operations will be able to affect the entire puzzle window again. This function may be used for both drawing and printing. \S{drawing-draw-update} \cw{draw_update()} \c void draw_update(drawing *dr, int x, int y, int w, int h); Informs the front end that a rectangular portion of the puzzle window has been drawn on and needs to be updated. \c{x} and \c{y} give the coordinates of the top left pixel of the update rectangle. \c{w} and \c{h} give its width and height. Thus, the horizontal extent of the rectangle runs from \c{x} to \c{x+w-1} inclusive, and the vertical extent from \c{y} to \c{y+h-1} inclusive. (These are exactly the same semantics as \cw{draw_rect()}.) The back end redraw function \e{must} call this function to report any changes it has made to the window. Otherwise, those changes may not become immediately visible, and may then appear at an unpredictable subsequent time such as the next time the window is covered and re-exposed. This function is only important when drawing. It may be called when printing as well, but doing so is not compulsory, and has no effect. (So if you have a shared piece of code between the drawing and printing routines, that code may safely call \cw{draw_update()}.) \S{drawing-status-bar} \cw{status_bar()} \c void status_bar(drawing *dr, char *text); Sets the text in the game's status bar to \c{text}. The text is copied from the supplied buffer, so the caller is free to deallocate or modify the buffer after use. (This function is not exactly a \e{drawing} function, but it shares with the drawing API the property that it may only be called from within the back end redraw function, so this is as good a place as any to document it.) The supplied text is filtered through the mid-end for optional rewriting before being passed on to the front end; the mid-end will prepend the current game time if the game is timed (and may in future perform other rewriting if it seems like a good idea). This function is for drawing only; it must never be called during printing. \S{drawing-blitter} Blitter functions This section describes a group of related functions which save and restore a section of the puzzle window. This is most commonly used to implement user interfaces involving dragging a puzzle element around the window: at the end of each call to \cw{redraw()}, if an object is currently being dragged, the back end saves the window contents under that location and then draws the dragged object, and at the start of the next \cw{redraw()} the first thing it does is to restore the background. The front end defines an opaque type called a \c{blitter}, which is capable of storing a rectangular area of a specified size. Blitter functions are for drawing only; they must never be called during printing. \S2{drawing-blitter-new} \cw{blitter_new()} \c blitter *blitter_new(drawing *dr, int w, int h); Creates a new blitter object which stores a rectangle of size \c{w} by \c{h} pixels. Returns a pointer to the blitter object. Blitter objects are best stored in the \c{game_drawstate}. A good time to create them is in the \cw{set_size()} function (\k{backend-set-size}), since it is at this point that you first know how big a rectangle they will need to save. \S2{drawing-blitter-free} \cw{blitter_free()} \c void blitter_free(drawing *dr, blitter *bl); Disposes of a blitter object. Best called in \cw{free_drawstate()}. (However, check that the blitter object is not \cw{NULL} before attempting to free it; it is possible that a draw state might be created and freed without ever having \cw{set_size()} called on it in between.) \S2{drawing-blitter-save} \cw{blitter_save()} \c void blitter_save(drawing *dr, blitter *bl, int x, int y); This is a true drawing API function, in that it may only be called from within the game redraw routine. It saves a rectangular portion of the puzzle window into the specified blitter object. \c{x} and \c{y} give the coordinates of the top left corner of the saved rectangle. The rectangle's width and height are the ones specified when the blitter object was created. This function is required to cope and do the right thing if \c{x} and \c{y} are out of range. (The right thing probably means saving whatever part of the blitter rectangle overlaps with the visible area of the puzzle window.) \S2{drawing-blitter-load} \cw{blitter_load()} \c void blitter_load(drawing *dr, blitter *bl, int x, int y); This is a true drawing API function, in that it may only be called from within the game redraw routine. It restores a rectangular portion of the puzzle window from the specified blitter object. \c{x} and \c{y} give the coordinates of the top left corner of the rectangle to be restored. The rectangle's width and height are the ones specified when the blitter object was created. Alternatively, you can specify both \c{x} and \c{y} as the special value \cw{BLITTER_FROMSAVED}, in which case the rectangle will be restored to exactly where it was saved from. (This is probably what you want to do almost all the time, if you're using blitters to implement draggable puzzle elements.) This function is required to cope and do the right thing if \c{x} and \c{y} (or the equivalent ones saved in the blitter) are out of range. (The right thing probably means restoring whatever part of the blitter rectangle overlaps with the visible area of the puzzle window.) If this function is called on a blitter which had previously been saved from a partially out-of-range rectangle, then the parts of the saved bitmap which were not visible at save time are undefined. If the blitter is restored to a different position so as to make those parts visible, the effect on the drawing area is undefined. \S{print-mono-colour} \cw{print_mono_colour()} \c int print_mono_colour(drawing *dr, int grey); This function allocates a colour index for a simple monochrome colour during printing. \c{grey} must be 0 or 1. If \c{grey} is 0, the colour returned is black; if \c{grey} is 1, the colour is white. \S{print-grey-colour} \cw{print_grey_colour()} \c int print_grey_colour(drawing *dr, float grey); This function allocates a colour index for a grey-scale colour during printing. \c{grey} may be any number between 0 (black) and 1 (white); for example, 0.5 indicates a medium grey. The chosen colour will be rendered to the limits of the printer's halftoning capability. \S{print-hatched-colour} \cw{print_hatched_colour()} \c int print_hatched_colour(drawing *dr, int hatch); This function allocates a colour index which does not represent a literal \e{colour}. Instead, regions shaded in this colour will be hatched with parallel lines. The \c{hatch} parameter defines what type of hatching should be used in place of this colour: \dt \cw{HATCH_SLASH} \dd This colour will be hatched by lines slanting to the right at 45 degrees. \dt \cw{HATCH_BACKSLASH} \dd This colour will be hatched by lines slanting to the left at 45 degrees. \dt \cw{HATCH_HORIZ} \dd This colour will be hatched by horizontal lines. \dt \cw{HATCH_VERT} \dd This colour will be hatched by vertical lines. \dt \cw{HATCH_PLUS} \dd This colour will be hatched by criss-crossing horizontal and vertical lines. \dt \cw{HATCH_X} \dd This colour will be hatched by criss-crossing diagonal lines. Colours defined to use hatching may not be used for drawing lines or text; they may only be used for filling areas. That is, they may be used as the \c{fillcolour} parameter to \cw{draw_circle()} and \cw{draw_polygon()}, and as the colour parameter to \cw{draw_rect()}, but may not be used as the \c{outlinecolour} parameter to \cw{draw_circle()} or \cw{draw_polygon()}, or with \cw{draw_line()} or \cw{draw_text()}. \S{print-rgb-mono-colour} \cw{print_rgb_mono_colour()} \c int print_rgb_mono_colour(drawing *dr, float r, float g, \c float b, float grey); This function allocates a colour index for a fully specified RGB colour during printing. \c{r}, \c{g} and \c{b} may each be anywhere in the range from 0 to 1. If printing in black and white only, these values will be ignored, and either pure black or pure white will be used instead, according to the \q{grey} parameter. (The fallback colour is the same as the one which would be allocated by \cw{print_mono_colour(grey)}.) \S{print-rgb-grey-colour} \cw{print_rgb_grey_colour()} \c int print_rgb_grey_colour(drawing *dr, float r, float g, \c float b, float grey); This function allocates a colour index for a fully specified RGB colour during printing. \c{r}, \c{g} and \c{b} may each be anywhere in the range from 0 to 1. If printing in black and white only, these values will be ignored, and a shade of grey given by the \c{grey} parameter will be used instead. (The fallback colour is the same as the one which would be allocated by \cw{print_grey_colour(grey)}.) \S{print-rgb-hatched-colour} \cw{print_rgb_hatched_colour()} \c int print_rgb_hatched_colour(drawing *dr, float r, float g, \c float b, float hatched); This function allocates a colour index for a fully specified RGB colour during printing. \c{r}, \c{g} and \c{b} may each be anywhere in the range from 0 to 1. If printing in black and white only, these values will be ignored, and a form of cross-hatching given by the \c{hatch} parameter will be used instead; see \k{print-hatched-colour} for the possible values of this parameter. (The fallback colour is the same as the one which would be allocated by \cw{print_hatched_colour(hatch)}.) \S{print-line-width} \cw{print_line_width()} \c void print_line_width(drawing *dr, int width); This function is called to set the thickness of lines drawn during printing. It is meaningless in drawing: all lines drawn by \cw{draw_line()}, \cw{draw_circle} and \cw{draw_polygon()} are one pixel in thickness. However, in printing there is no clear definition of a pixel and so line widths must be explicitly specified. The line width is specified in the usual coordinate system. Note, however, that it is a hint only: the central printing system may choose to vary line thicknesses at user request or due to printer capabilities. \S{print-line-dotted} \cw{print_line_dotted()} \c void print_line_dotted(drawing *dr, int dotted); This function is called to toggle the drawing of dotted lines during printing. It is not supported during drawing. The parameter \cq{dotted} is a boolean; \cw{TRUE} means that future lines drawn by \cw{draw_line()}, \cw{draw_circle} and \cw{draw_polygon()} will be dotted, and \cw{FALSE} means that they will be solid. Some front ends may impose restrictions on the width of dotted lines. Asking for a dotted line via this front end will override any line width request if the front end requires it. \H{drawing-frontend} The drawing API as implemented by the front end This section describes the drawing API in the function-pointer form in which it is implemented by a front end. (It isn't only platform-specific front ends which implement this API; the platform-independent module \c{ps.c} also provides an implementation of it which outputs PostScript. Thus, any platform which wants to do PS printing can do so with minimum fuss.) The following entries all describe function pointer fields in a structure called \c{drawing_api}. Each of the functions takes a \cq{void *} context pointer, which it should internally cast back to a more useful type. Thus, a drawing \e{object} (\c{drawing *)} suitable for passing to the back end redraw or printing functions is constructed by passing a \c{drawing_api} and a \cq{void *} to the function \cw{drawing_new()} (see \k{drawing-new}). \S{drawingapi-draw-text} \cw{draw_text()} \c void (*draw_text)(void *handle, int x, int y, int fonttype, \c int fontsize, int align, int colour, char *text); This function behaves exactly like the back end \cw{draw_text()} function; see \k{drawing-draw-text}. \S{drawingapi-draw-rect} \cw{draw_rect()} \c void (*draw_rect)(void *handle, int x, int y, int w, int h, \c int colour); This function behaves exactly like the back end \cw{draw_rect()} function; see \k{drawing-draw-rect}. \S{drawingapi-draw-line} \cw{draw_line()} \c void (*draw_line)(void *handle, int x1, int y1, int x2, int y2, \c int colour); This function behaves exactly like the back end \cw{draw_line()} function; see \k{drawing-draw-line}. \S{drawingapi-draw-polygon} \cw{draw_polygon()} \c void (*draw_polygon)(void *handle, int *coords, int npoints, \c int fillcolour, int outlinecolour); This function behaves exactly like the back end \cw{draw_polygon()} function; see \k{drawing-draw-polygon}. \S{drawingapi-draw-circle} \cw{draw_circle()} \c void (*draw_circle)(void *handle, int cx, int cy, int radius, \c int fillcolour, int outlinecolour); This function behaves exactly like the back end \cw{draw_circle()} function; see \k{drawing-draw-circle}. \S{drawingapi-draw-thick-line} \cw{draw_thick_line()} \c void draw_thick_line(drawing *dr, float thickness, \c float x1, float y1, float x2, float y2, \c int colour) This function behaves exactly like the back end \cw{draw_thick_line()} function; see \k{drawing-draw-thick-line}. An implementation of this API which doesn't provide high-quality rendering of thick lines is permitted to define this function pointer to be \cw{NULL}. The middleware in \cw{drawing.c} will notice and provide a low-quality alternative using \cw{draw_polygon()}. \S{drawingapi-draw-update} \cw{draw_update()} \c void (*draw_update)(void *handle, int x, int y, int w, int h); This function behaves exactly like the back end \cw{draw_update()} function; see \k{drawing-draw-update}. An implementation of this API which only supports printing is permitted to define this function pointer to be \cw{NULL} rather than bothering to define an empty function. The middleware in \cw{drawing.c} will notice and avoid calling it. \S{drawingapi-clip} \cw{clip()} \c void (*clip)(void *handle, int x, int y, int w, int h); This function behaves exactly like the back end \cw{clip()} function; see \k{drawing-clip}. \S{drawingapi-unclip} \cw{unclip()} \c void (*unclip)(void *handle); This function behaves exactly like the back end \cw{unclip()} function; see \k{drawing-unclip}. \S{drawingapi-start-draw} \cw{start_draw()} \c void (*start_draw)(void *handle); This function is called at the start of drawing. It allows the front end to initialise any temporary data required to draw with, such as device contexts. Implementations of this API which do not provide drawing services may define this function pointer to be \cw{NULL}; it will never be called unless drawing is attempted. \S{drawingapi-end-draw} \cw{end_draw()} \c void (*end_draw)(void *handle); This function is called at the end of drawing. It allows the front end to do cleanup tasks such as deallocating device contexts and scheduling appropriate GUI redraw events. Implementations of this API which do not provide drawing services may define this function pointer to be \cw{NULL}; it will never be called unless drawing is attempted. \S{drawingapi-status-bar} \cw{status_bar()} \c void (*status_bar)(void *handle, char *text); This function behaves exactly like the back end \cw{status_bar()} function; see \k{drawing-status-bar}. Front ends implementing this function need not worry about it being called repeatedly with the same text; the middleware code in \cw{status_bar()} will take care of this. Implementations of this API which do not provide drawing services may define this function pointer to be \cw{NULL}; it will never be called unless drawing is attempted. \S{drawingapi-blitter-new} \cw{blitter_new()} \c blitter *(*blitter_new)(void *handle, int w, int h); This function behaves exactly like the back end \cw{blitter_new()} function; see \k{drawing-blitter-new}. Implementations of this API which do not provide drawing services may define this function pointer to be \cw{NULL}; it will never be called unless drawing is attempted. \S{drawingapi-blitter-free} \cw{blitter_free()} \c void (*blitter_free)(void *handle, blitter *bl); This function behaves exactly like the back end \cw{blitter_free()} function; see \k{drawing-blitter-free}. Implementations of this API which do not provide drawing services may define this function pointer to be \cw{NULL}; it will never be called unless drawing is attempted. \S{drawingapi-blitter-save} \cw{blitter_save()} \c void (*blitter_save)(void *handle, blitter *bl, int x, int y); This function behaves exactly like the back end \cw{blitter_save()} function; see \k{drawing-blitter-save}. Implementations of this API which do not provide drawing services may define this function pointer to be \cw{NULL}; it will never be called unless drawing is attempted. \S{drawingapi-blitter-load} \cw{blitter_load()} \c void (*blitter_load)(void *handle, blitter *bl, int x, int y); This function behaves exactly like the back end \cw{blitter_load()} function; see \k{drawing-blitter-load}. Implementations of this API which do not provide drawing services may define this function pointer to be \cw{NULL}; it will never be called unless drawing is attempted. \S{drawingapi-begin-doc} \cw{begin_doc()} \c void (*begin_doc)(void *handle, int pages); This function is called at the beginning of a printing run. It gives the front end an opportunity to initialise any required printing subsystem. It also provides the number of pages in advance. Implementations of this API which do not provide printing services may define this function pointer to be \cw{NULL}; it will never be called unless printing is attempted. \S{drawingapi-begin-page} \cw{begin_page()} \c void (*begin_page)(void *handle, int number); This function is called during printing, at the beginning of each page. It gives the page number (numbered from 1 rather than 0, so suitable for use in user-visible contexts). Implementations of this API which do not provide printing services may define this function pointer to be \cw{NULL}; it will never be called unless printing is attempted. \S{drawingapi-begin-puzzle} \cw{begin_puzzle()} \c void (*begin_puzzle)(void *handle, float xm, float xc, \c float ym, float yc, int pw, int ph, float wmm); This function is called during printing, just before printing a single puzzle on a page. It specifies the size and location of the puzzle on the page. \c{xm} and \c{xc} specify the horizontal position of the puzzle on the page, as a linear function of the page width. The front end is expected to multiply the page width by \c{xm}, add \c{xc} (measured in millimetres), and use the resulting x-coordinate as the left edge of the puzzle. Similarly, \c{ym} and \c{yc} specify the vertical position of the puzzle as a function of the page height: the page height times \c{ym}, plus \c{yc} millimetres, equals the desired distance from the top of the page to the top of the puzzle. (This unwieldy mechanism is required because not all printing systems can communicate the page size back to the software. The PostScript back end, for example, writes out PS which determines the page size at print time by means of calling \cq{clippath}, and centres the puzzles within that. Thus, exactly the same PS file works on A4 or on US Letter paper without needing local configuration, which simplifies matters.) \cw{pw} and \cw{ph} give the size of the puzzle in drawing API coordinates. The printing system will subsequently call the puzzle's own print function, which will in turn call drawing API functions in the expectation that an area \cw{pw} by \cw{ph} units is available to draw the puzzle on. Finally, \cw{wmm} gives the desired width of the puzzle in millimetres. (The aspect ratio is expected to be preserved, so if the desired puzzle height is also needed then it can be computed as \cw{wmm*ph/pw}.) Implementations of this API which do not provide printing services may define this function pointer to be \cw{NULL}; it will never be called unless printing is attempted. \S{drawingapi-end-puzzle} \cw{end_puzzle()} \c void (*end_puzzle)(void *handle); This function is called after the printing of a specific puzzle is complete. Implementations of this API which do not provide printing services may define this function pointer to be \cw{NULL}; it will never be called unless printing is attempted. \S{drawingapi-end-page} \cw{end_page()} \c void (*end_page)(void *handle, int number); This function is called after the printing of a page is finished. Implementations of this API which do not provide printing services may define this function pointer to be \cw{NULL}; it will never be called unless printing is attempted. \S{drawingapi-end-doc} \cw{end_doc()} \c void (*end_doc)(void *handle); This function is called after the printing of the entire document is finished. This is the moment to close files, send things to the print spooler, or whatever the local convention is. Implementations of this API which do not provide printing services may define this function pointer to be \cw{NULL}; it will never be called unless printing is attempted. \S{drawingapi-line-width} \cw{line_width()} \c void (*line_width)(void *handle, float width); This function is called to set the line thickness, during printing only. Note that the width is a \cw{float} here, where it was an \cw{int} as seen by the back end. This is because \cw{drawing.c} may have scaled it on the way past. However, the width is still specified in the same coordinate system as the rest of the drawing. Implementations of this API which do not provide printing services may define this function pointer to be \cw{NULL}; it will never be called unless printing is attempted. \S{drawingapi-text-fallback} \cw{text_fallback()} \c char *(*text_fallback)(void *handle, const char *const *strings, \c int nstrings); This function behaves exactly like the back end \cw{text_fallback()} function; see \k{drawing-text-fallback}. Implementations of this API which do not support any characters outside ASCII may define this function pointer to be \cw{NULL}, in which case the central code in \cw{drawing.c} will provide a default implementation. \H{drawingapi-frontend} The drawing API as called by the front end There are a small number of functions provided in \cw{drawing.c} which the front end needs to \e{call}, rather than helping to implement. They are described in this section. \S{drawing-new} \cw{drawing_new()} \c drawing *drawing_new(const drawing_api *api, midend *me, \c void *handle); This function creates a drawing object. It is passed a \c{drawing_api}, which is a structure containing nothing but function pointers; and also a \cq{void *} handle. The handle is passed back to each function pointer when it is called. The \c{midend} parameter is used for rewriting the status bar contents: \cw{status_bar()} (see \k{drawing-status-bar}) has to call a function in the mid-end which might rewrite the status bar text. If the drawing object is to be used only for printing, or if the game is known not to call \cw{status_bar()}, this parameter may be \cw{NULL}. \S{drawing-free} \cw{drawing_free()} \c void drawing_free(drawing *dr); This function frees a drawing object. Note that the \cq{void *} handle is not freed; if that needs cleaning up it must be done by the front end. \S{drawing-print-get-colour} \cw{print_get_colour()} \c void print_get_colour(drawing *dr, int colour, int printincolour, \c int *hatch, float *r, float *g, float *b) This function is called by the implementations of the drawing API functions when they are called in a printing context. It takes a colour index as input, and returns the description of the colour as requested by the back end. \c{printincolour} is \cw{TRUE} iff the implementation is printing in colour. This will alter the results returned if the colour in question was specified with a black-and-white fallback value. If the colour should be rendered by hatching, \c{*hatch} is filled with the type of hatching desired. See \k{print-grey-colour} for details of the values this integer can take. If the colour should be rendered as solid colour, \c{*hatch} is given a negative value, and \c{*r}, \c{*g} and \c{*b} are filled with the RGB values of the desired colour (if printing in colour), or all filled with the grey-scale value (if printing in black and white). \C{midend} The API provided by the mid-end This chapter documents the API provided by the mid-end to be called by the front end. You probably only need to read this if you are a front end implementor, i.e. you are porting Puzzles to a new platform. If you're only interested in writing new puzzles, you can safely skip this chapter. All the persistent state in the mid-end is encapsulated within a \c{midend} structure, to facilitate having multiple mid-ends in any port which supports multiple puzzle windows open simultaneously. Each \c{midend} is intended to handle the contents of a single puzzle window. \H{midend-new} \cw{midend_new()} \c midend *midend_new(frontend *fe, const game *ourgame, \c const drawing_api *drapi, void *drhandle) Allocates and returns a new mid-end structure. The \c{fe} argument is stored in the mid-end. It will be used when calling back to functions such as \cw{activate_timer()} (\k{frontend-activate-timer}), and will be passed on to the back end function \cw{colours()} (\k{backend-colours}). The parameters \c{drapi} and \c{drhandle} are passed to \cw{drawing_new()} (\k{drawing-new}) to construct a drawing object which will be passed to the back end function \cw{redraw()} (\k{backend-redraw}). Hence, all drawing-related function pointers defined in \c{drapi} can expect to be called with \c{drhandle} as their first argument. The \c{ourgame} argument points to a container structure describing a game back end. The mid-end thus created will only be capable of handling that one game. (So even in a monolithic front end containing all the games, this imposes the constraint that any individual puzzle window is tied to a single game. Unless, of course, you feel brave enough to change the mid-end for the window without closing the window...) \H{midend-free} \cw{midend_free()} \c void midend_free(midend *me); Frees a mid-end structure and all its associated data. \H{midend-tilesize} \cw{midend_tilesize()} \c int midend_tilesize(midend *me); Returns the \cq{tilesize} parameter being used to display the current puzzle (\k{backend-preferred-tilesize}). \H{midend-set-params} \cw{midend_set_params()} \c void midend_set_params(midend *me, game_params *params); Sets the current game parameters for a mid-end. Subsequent games generated by \cw{midend_new_game()} (\k{midend-new-game}) will use these parameters until further notice. The usual way in which the front end will have an actual \c{game_params} structure to pass to this function is if it had previously got it from \cw{midend_get_presets()} (\k{midend-get-presets}). Thus, this function is usually called in response to the user making a selection from the presets menu. \H{midend-get-params} \cw{midend_get_params()} \c game_params *midend_get_params(midend *me); Returns the current game parameters stored in this mid-end. The returned value is dynamically allocated, and should be freed when finished with by passing it to the game's own \cw{free_params()} function (see \k{backend-free-params}). \H{midend-size} \cw{midend_size()} \c void midend_size(midend *me, int *x, int *y, int user_size); Tells the mid-end to figure out its window size. On input, \c{*x} and \c{*y} should contain the maximum or requested size for the window. (Typically this will be the size of the screen that the window has to fit on, or similar.) The mid-end will repeatedly call the back end function \cw{compute_size()} (\k{backend-compute-size}), searching for a tile size that best satisfies the requirements. On exit, \c{*x} and \c{*y} will contain the size needed for the puzzle window's drawing area. (It is of course up to the front end to adjust this for any additional window furniture such as menu bars and window borders, if necessary. The status bar is also not included in this size.) Use \c{user_size} to indicate whether \c{*x} and \c{*y} are a requested size, or just a maximum size. If \c{user_size} is set to \cw{TRUE}, the mid-end will treat the input size as a request, and will pick a tile size which approximates it \e{as closely as possible}, going over the game's preferred tile size if necessary to achieve this. The mid-end will also use the resulting tile size as its preferred one until further notice, on the assumption that this size was explicitly requested by the user. Use this option if you want your front end to support dynamic resizing of the puzzle window with automatic scaling of the puzzle to fit. If \c{user_size} is set to \cw{FALSE}, then the game's tile size will never go over its preferred one, although it may go under in order to fit within the maximum bounds specified by \c{*x} and \c{*y}. This is the recommended approach when opening a new window at default size: the game will use its preferred size unless it has to use a smaller one to fit on the screen. If the tile size is shrunk for this reason, the change will not persist; if a smaller grid is subsequently chosen, the tile size will recover. The mid-end will try as hard as it can to return a size which is less than or equal to the input size, in both dimensions. In extreme circumstances it may fail (if even the lowest possible tile size gives window dimensions greater than the input), in which case it will return a size greater than the input size. Front ends should be prepared for this to happen (i.e. don't crash or fail an assertion), but may handle it in any way they see fit: by rejecting the game parameters which caused the problem, by opening a window larger than the screen regardless of inconvenience, by introducing scroll bars on the window, by drawing on a large bitmap and scaling it into a smaller window, or by any other means you can think of. It is likely that when the tile size is that small the game will be unplayable anyway, so don't put \e{too} much effort into handling it creatively. If your platform has no limit on window size (or if you're planning to use scroll bars for large puzzles), you can pass dimensions of \cw{INT_MAX} as input to this function. You should probably not do that \e{and} set the \c{user_size} flag, though! The midend relies on the frontend calling \cw{midend_new_game()} (\k{midend-new-game}) before calling \cw{midend_size()}. \H{midend-reset-tilesize} \cw{midend_reset_tilesize()} \c void midend_reset_tilesize(midend *me); This function resets the midend's preferred tile size to that of the standard puzzle. As discussed in \k{midend-size}, puzzle resizes are typically 'sticky', in that once the user has dragged the puzzle to a different window size, the resulting tile size will be remembered and used when the puzzle configuration changes. If you \e{don't} want that, e.g. if you want to provide a command to explicitly reset the puzzle size back to its default, then you can call this just before calling \cw{midend_size()} (which, in turn, you would probably call with \c{user_size} set to \cw{FALSE}). \H{midend-new-game} \cw{midend_new_game()} \c void midend_new_game(midend *me); Causes the mid-end to begin a new game. Normally the game will be a new randomly generated puzzle. However, if you have previously called \cw{midend_game_id()} or \cw{midend_set_config()}, the game generated might be dictated by the results of those functions. (In particular, you \e{must} call \cw{midend_new_game()} after calling either of those functions, or else no immediate effect will be visible.) You will probably need to call \cw{midend_size()} after calling this function, because if the game parameters have been changed since the last new game then the window size might need to change. (If you know the parameters \e{haven't} changed, you don't need to do this.) This function will create a new \c{game_drawstate}, but does not actually perform a redraw (since you often need to call \cw{midend_size()} before the redraw can be done). So after calling this function and after calling \cw{midend_size()}, you should then call \cw{midend_redraw()}. (It is not necessary to call \cw{midend_force_redraw()}; that will discard the draw state and create a fresh one, which is unnecessary in this case since there's a fresh one already. It would work, but it's usually excessive.) \H{midend-restart-game} \cw{midend_restart_game()} \c void midend_restart_game(midend *me); This function causes the current game to be restarted. This is done by placing a new copy of the original game state on the end of the undo list (so that an accidental restart can be undone). This function automatically causes a redraw, i.e. the front end can expect its drawing API to be called from \e{within} a call to this function. Some back ends require that \cw{midend_size()} (\k{midend-size}) is called before \cw{midend_restart_game()}. \H{midend-force-redraw} \cw{midend_force_redraw()} \c void midend_force_redraw(midend *me); Forces a complete redraw of the puzzle window, by means of discarding the current \c{game_drawstate} and creating a new one from scratch before calling the game's \cw{redraw()} function. The front end can expect its drawing API to be called from within a call to this function. Some back ends require that \cw{midend_size()} (\k{midend-size}) is called before \cw{midend_force_redraw()}. \H{midend-redraw} \cw{midend_redraw()} \c void midend_redraw(midend *me); Causes a partial redraw of the puzzle window, by means of simply calling the game's \cw{redraw()} function. (That is, the only things redrawn will be things that have changed since the last redraw.) The front end can expect its drawing API to be called from within a call to this function. Some back ends require that \cw{midend_size()} (\k{midend-size}) is called before \cw{midend_redraw()}. \H{midend-process-key} \cw{midend_process_key()} \c int midend_process_key(midend *me, int x, int y, int button); The front end calls this function to report a mouse or keyboard event. The parameters \c{x}, \c{y} and \c{button} are almost identical to the ones passed to the back end function \cw{interpret_move()} (\k{backend-interpret-move}), except that the front end is \e{not} required to provide the guarantees about mouse event ordering. The mid-end will sort out multiple simultaneous button presses and changes of button; the front end's responsibility is simply to pass on the mouse events it receives as accurately as possible. (Some platforms may need to emulate absent mouse buttons by means of using a modifier key such as Shift with another mouse button. This tends to mean that if Shift is pressed or released in the middle of a mouse drag, the mid-end will suddenly stop receiving, say, \cw{LEFT_DRAG} events and start receiving \cw{RIGHT_DRAG}s, with no intervening button release or press events. This too is something which the mid-end will sort out for you; the front end has no obligation to maintain sanity in this area.) The front end \e{should}, however, always eventually send some kind of button release. On some platforms this requires special effort: Windows, for example, requires a call to the system API function \cw{SetCapture()} in order to ensure that your window receives a mouse-up event even if the pointer has left the window by the time the mouse button is released. On any platform that requires this sort of thing, the front end \e{is} responsible for doing it. Calling this function is very likely to result in calls back to the front end's drawing API and/or \cw{activate_timer()} (\k{frontend-activate-timer}). The return value from \cw{midend_process_key()} is non-zero, unless the effect of the keypress was to request termination of the program. A front end should shut down the puzzle in response to a zero return. \H{midend-colours} \cw{midend_colours()} \c float *midend_colours(midend *me, int *ncolours); Returns an array of the colours required by the game, in exactly the same format as that returned by the back end function \cw{colours()} (\k{backend-colours}). Front ends should call this function rather than calling the back end's version directly, since the mid-end adds standard customisation facilities. (At the time of writing, those customisation facilities are implemented hackily by means of environment variables, but it's not impossible that they may become more full and formal in future.) \H{midend-timer} \cw{midend_timer()} \c void midend_timer(midend *me, float tplus); If the mid-end has called \cw{activate_timer()} (\k{frontend-activate-timer}) to request regular callbacks for purposes of animation or timing, this is the function the front end should call on a regular basis. The argument \c{tplus} gives the time, in seconds, since the last time either this function was called or \cw{activate_timer()} was invoked. One of the major purposes of timing in the mid-end is to perform move animation. Therefore, calling this function is very likely to result in calls back to the front end's drawing API. \H{midend-get-presets} \cw{midend_get_presets()} \c struct preset_menu *midend_get_presets(midend *me, int *id_limit); Returns a data structure describing this game's collection of preset game parameters, organised into a hierarchical structure of menus and submenus. The return value is a pointer to a data structure containing the following fields (among others, which are not intended for front end use): \c struct preset_menu { \c int n_entries; \c struct preset_menu_entry *entries; \c /* and other things */ \e iiiiiiiiiiiiiiiiiiiiii \c }; Those fields describe the intended contents of one particular menu in the hierarchy. \cq{entries} points to an array of \cq{n_entries} items, each of which is a structure containing the following fields: \c struct preset_menu_entry { \c char *title; \c game_params *params; \c struct preset_menu *submenu; \c int id; \c }; Of these fields, \cq{title} and \cq{id} are present in every entry, giving (respectively) the textual name of the menu item and an integer identifier for it. The integer id will correspond to the one returned by \c{midend_which_preset} (\k{midend-which-preset}), when that preset is the one selected. The other two fields are mutually exclusive. Each \c{struct preset_menu_entry} will have one of those fields \cw{NULL} and the other one non-null. If the menu item is an actual preset, then \cq{params} will point to the set of game parameters that go with the name; if it's a submenu, then \cq{submenu} instead will be non-null, and will point at a subsidiary \c{struct preset_menu}. The complete hierarchy of these structures is owned by the mid-end, and will be freed when the mid-end is freed. The front end should not attempt to free any of it. The integer identifiers will be allocated densely from 0 upwards, so that it's reasonable for the front end to allocate an array which uses them as indices, if it needs to store information per preset menu item. For this purpose, the front end may pass the second parameter \cq{id_limit} to \cw{midend_get_presets} as the address of an \c{int} variable, into which \cw{midend_get_presets} will write an integer one larger than the largest id number actually used (i.e. the number of elements the front end would need in the array). Submenu-type entries also have integer identifiers. \H{midend-which-preset} \cw{midend_which_preset()} \c int midend_which_preset(midend *me); Returns the numeric index of the preset game parameter structure which matches the current game parameters, or a negative number if no preset matches. Front ends could use this to maintain a tick beside one of the items in the menu (or tick the \q{Custom} option if the return value is less than zero). The returned index value (if non-negative) will match the \c{id} field of the corresponding \cw{struct preset_menu_entry} returned by \c{midend_get_presets()} (\k{midend-get-presets}). \H{midend-wants-statusbar} \cw{midend_wants_statusbar()} \c int midend_wants_statusbar(midend *me); This function returns \cw{TRUE} if the puzzle has a use for a textual status line (to display score, completion status, currently active tiles, time, or anything else). Front ends should call this function rather than talking directly to the back end. \H{midend-get-config} \cw{midend_get_config()} \c config_item *midend_get_config(midend *me, int which, \c char **wintitle); Returns a dialog box description for user configuration. On input, \cw{which} should be set to one of three values, which select which of the various dialog box descriptions is returned: \dt \cw{CFG_SETTINGS} \dd Requests the GUI parameter configuration box generated by the puzzle itself. This should be used when the user selects \q{Custom} from the game types menu (or equivalent). The mid-end passes this request on to the back end function \cw{configure()} (\k{backend-configure}). \dt \cw{CFG_DESC} \dd Requests a box suitable for entering a descriptive game ID (and viewing the existing one). The mid-end generates this dialog box description itself. This should be used when the user selects \q{Specific} from the game menu (or equivalent). \dt \cw{CFG_SEED} \dd Requests a box suitable for entering a random-seed game ID (and viewing the existing one). The mid-end generates this dialog box description itself. This should be used when the user selects \q{Random Seed} from the game menu (or equivalent). The returned value is an array of \cw{config_item}s, exactly as described in \k{backend-configure}. Another returned value is an ASCII string giving a suitable title for the configuration window, in \c{*wintitle}. Both returned values are dynamically allocated and will need to be freed. The window title can be freed in the obvious way; the \cw{config_item} array is a slightly complex structure, so a utility function \cw{free_cfg()} is provided to free it for you. See \k{utils-free-cfg}. (Of course, you will probably not want to free the \cw{config_item} array until the dialog box is dismissed, because before then you will probably need to pass it to \cw{midend_set_config}.) \H{midend-set-config} \cw{midend_set_config()} \c char *midend_set_config(midend *me, int which, \c config_item *cfg); Passes the mid-end the results of a configuration dialog box. \c{which} should have the same value which it had when \cw{midend_get_config()} was called; \c{cfg} should be the array of \c{config_item}s returned from \cw{midend_get_config()}, modified to contain the results of the user's editing operations. This function returns \cw{NULL} on success, or otherwise (if the configuration data was in some way invalid) an ASCII string containing an error message suitable for showing to the user. If the function succeeds, it is likely that the game parameters will have been changed and it is certain that a new game will be requested. The front end should therefore call \cw{midend_new_game()}, and probably also re-think the window size using \cw{midend_size()} and eventually perform a refresh using \cw{midend_redraw()}. \H{midend-game-id} \cw{midend_game_id()} \c char *midend_game_id(midend *me, char *id); Passes the mid-end a string game ID (of any of the valid forms \cq{params}, \cq{params:description} or \cq{params#seed}) which the mid-end will process and use for the next generated game. This function returns \cw{NULL} on success, or otherwise (if the configuration data was in some way invalid) an ASCII string containing an error message (not dynamically allocated) suitable for showing to the user. In the event of an error, the mid-end's internal state will be left exactly as it was before the call. If the function succeeds, it is likely that the game parameters will have been changed and it is certain that a new game will be requested. The front end should therefore call \cw{midend_new_game()}, and probably also re-think the window size using \cw{midend_size()} and eventually case a refresh using \cw{midend_redraw()}. \H{midend-get-game-id} \cw{midend_get_game_id()} \c char *midend_get_game_id(midend *me) Returns a descriptive game ID (i.e. one in the form \cq{params:description}) describing the game currently active in the mid-end. The returned string is dynamically allocated. \H{midend-get-random-seed} \cw{midend_get_random_seed()} \c char *midend_get_random_seed(midend *me) Returns a random game ID (i.e. one in the form \cq{params#seedstring}) describing the game currently active in the mid-end, if there is one. If the game was created by entering a description, no random seed will currently exist and this function will return \cw{NULL}. The returned string, if it is non-\cw{NULL}, is dynamically allocated. \H{midend-can-format-as-text-now} \cw{midend_can_format_as_text_now()} \c int midend_can_format_as_text_now(midend *me); Returns \cw{TRUE} if the game code is capable of formatting puzzles of the currently selected game type as ASCII. If this returns \cw{FALSE}, then \cw{midend_text_format()} (\k{midend-text-format}) will return \cw{NULL}. \H{midend-text-format} \cw{midend_text_format()} \c char *midend_text_format(midend *me); Formats the current game's current state as ASCII text suitable for copying to the clipboard. The returned string is dynamically allocated. If the game's \c{can_format_as_text_ever} flag is \cw{FALSE}, or if its \cw{can_format_as_text_now()} function returns \cw{FALSE}, then this function will return \cw{NULL}. If the returned string contains multiple lines (which is likely), it will use the normal C line ending convention (\cw{\\n} only). On platforms which use a different line ending convention for data in the clipboard, it is the front end's responsibility to perform the conversion. \H{midend-solve} \cw{midend_solve()} \c char *midend_solve(midend *me); Requests the mid-end to perform a Solve operation. On success, \cw{NULL} is returned. On failure, an error message (not dynamically allocated) is returned, suitable for showing to the user. The front end can expect its drawing API and/or \cw{activate_timer()} to be called from within a call to this function. Some back ends require that \cw{midend_size()} (\k{midend-size}) is called before \cw{midend_solve()}. \H{midend-status} \cw{midend_status()} \c int midend_status(midend *me); This function returns +1 if the midend is currently displaying a game in a solved state, -1 if the game is in a permanently lost state, or 0 otherwise. This function just calls the back end's \cw{status()} function. Front ends may wish to use this as a cue to proactively offer the option of starting a new game. (See \k{backend-status} for more detail about the back end's \cw{status()} function and discussion of what should count as which status code.) \H{midend-can-undo} \cw{midend_can_undo()} \c int midend_can_undo(midend *me); Returns \cw{TRUE} if the midend is currently in a state where the undo operation is meaningful (i.e. at least one position exists on the undo chain before the present one). Front ends may wish to use this to visually activate and deactivate an undo button. \H{midend-can-redo} \cw{midend_can_redo()} \c int midend_can_redo(midend *me); Returns \cw{TRUE} if the midend is currently in a state where the redo operation is meaningful (i.e. at least one position exists on the redo chain after the present one). Front ends may wish to use this to visually activate and deactivate a redo button. \H{midend-serialise} \cw{midend_serialise()} \c void midend_serialise(midend *me, \c void (*write)(void *ctx, void *buf, int len), \c void *wctx); Calling this function causes the mid-end to convert its entire internal state into a long ASCII text string, and to pass that string (piece by piece) to the supplied \c{write} function. Desktop implementations can use this function to save a game in any state (including half-finished) to a disk file, by supplying a \c{write} function which is a wrapper on \cw{fwrite()} (or local equivalent). Other implementations may find other uses for it, such as compressing the large and sprawling mid-end state into a manageable amount of memory when a palmtop application is suspended so that another one can run; in this case \cw{write} might want to write to a memory buffer rather than a file. There may be other uses for it as well. This function will call back to the supplied \c{write} function a number of times, with the first parameter (\c{ctx}) equal to \c{wctx}, and the other two parameters pointing at a piece of the output string. \H{midend-deserialise} \cw{midend_deserialise()} \c char *midend_deserialise(midend *me, \c int (*read)(void *ctx, void *buf, int len), \c void *rctx); This function is the counterpart to \cw{midend_serialise()}. It calls the supplied \cw{read} function repeatedly to read a quantity of data, and attempts to interpret that data as a serialised mid-end as output by \cw{midend_serialise()}. The \cw{read} function is called with the first parameter (\c{ctx}) equal to \c{rctx}, and should attempt to read \c{len} bytes of data into the buffer pointed to by \c{buf}. It should return \cw{FALSE} on failure or \cw{TRUE} on success. It should not report success unless it has filled the entire buffer; on platforms which might be reading from a pipe or other blocking data source, \c{read} is responsible for looping until the whole buffer has been filled. If the de-serialisation operation is successful, the mid-end's internal data structures will be replaced by the results of the load, and \cw{NULL} will be returned. Otherwise, the mid-end's state will be completely unchanged and an error message (typically some variation on \q{save file is corrupt}) will be returned. As usual, the error message string is not dynamically allocated. If this function succeeds, it is likely that the game parameters will have been changed. The front end should therefore probably re-think the window size using \cw{midend_size()}, and probably cause a refresh using \cw{midend_redraw()}. Because each mid-end is tied to a specific game back end, this function will fail if you attempt to read in a save file generated by a different game from the one configured in this mid-end, even if your application is a monolithic one containing all the puzzles. See \k{identify-game} for a helper function which will allow you to identify a save file before you instantiate your mid-end in the first place. \H{identify-game} \cw{identify_game()} \c char *identify_game(char **name, \c int (*read)(void *ctx, void *buf, int len), \c void *rctx); This function examines a serialised midend stream, of the same kind used by \cw{midend_serialise()} and \cw{midend_deserialise()}, and returns the \cw{name} field of the game back end from which it was saved. You might want this if your front end was a monolithic one containing all the puzzles, and you wanted to be able to load an arbitrary save file and automatically switch to the right game. Probably your next step would be to iterate through \cw{gamelist} (\k{frontend-backend}) looking for a game structure whose \cw{name} field matched the returned string, and give an error if you didn't find one. On success, the return value of this function is \cw{NULL}, and the game name string is written into \cw{*name}. The caller should free that string after using it. On failure, \cw{*name} is \cw{NULL}, and the return value is an error message (which does not need freeing at all). (This isn't strictly speaking a midend function, since it doesn't accept or return a pointer to a midend. You'd probably call it just \e{before} deciding what kind of midend you wanted to instantiate.) \H{midend-request-id-changes} \cw{midend_request_id_changes()} \c void midend_request_id_changes(midend *me, \c void (*notify)(void *), void *ctx); This function is called by the front end to request notification by the mid-end when the current game IDs (either descriptive or random-seed) change. This can occur as a result of keypresses ('n' for New Game, for example) or when a puzzle supersedes its game description (see \k{backend-supersede}). After this function is called, any change of the game ids will cause the mid-end to call \cw{notify(ctx)} after the change. This is for use by puzzles which want to present the game description to the user constantly (e.g. as an HTML hyperlink) instead of only showing it when the user explicitly requests it. This is a function I anticipate few front ends needing to implement, so I make it a callback rather than a static function in order to relieve most front ends of the need to provide an empty implementation. \H{frontend-backend} Direct reference to the back end structure by the front end Although \e{most} things the front end needs done should be done by calling the mid-end, there are a few situations in which the front end needs to refer directly to the game back end structure. The most obvious of these is \b passing the game back end as a parameter to \cw{midend_new()}. There are a few other back end features which are not wrapped by the mid-end because there didn't seem much point in doing so: \b fetching the \c{name} field to use in window titles and similar \b reading the \c{can_configure}, \c{can_solve} and \c{can_format_as_text_ever} fields to decide whether to add those items to the menu bar or equivalent \b reading the \c{winhelp_topic} field (Windows only) \b the GTK front end provides a \cq{--generate} command-line option which directly calls the back end to do most of its work. This is not really part of the main front end code, though, and I'm not sure it counts. In order to find the game back end structure, the front end does one of two things: \b If the particular front end is compiling a separate binary per game, then the back end structure is a global variable with the standard name \cq{thegame}: \lcont{ \c extern const game thegame; } \b If the front end is compiled as a monolithic application containing all the puzzles together (in which case the preprocessor symbol \cw{COMBINED} must be defined when compiling most of the code base), then there will be two global variables defined: \lcont{ \c extern const game *gamelist[]; \c extern const int gamecount; \c{gamelist} will be an array of \c{gamecount} game structures, declared in the automatically constructed source module \c{list.c}. The application should search that array for the game it wants, probably by reaching into each game structure and looking at its \c{name} field. } \H{frontend-api} Mid-end to front-end calls This section describes the small number of functions which a front end must provide to be called by the mid-end or other standard utility modules. \H{frontend-get-random-seed} \cw{get_random_seed()} \c void get_random_seed(void **randseed, int *randseedsize); This function is called by a new mid-end, and also occasionally by game back ends. Its job is to return a piece of data suitable for using as a seed for initialisation of a new \c{random_state}. On exit, \c{*randseed} should be set to point at a newly allocated piece of memory containing some seed data, and \c{*randseedsize} should be set to the length of that data. A simple and entirely adequate implementation is to return a piece of data containing the current system time at the highest conveniently available resolution. \H{frontend-activate-timer} \cw{activate_timer()} \c void activate_timer(frontend *fe); This is called by the mid-end to request that the front end begin calling it back at regular intervals. The timeout interval is left up to the front end; the finer it is, the smoother move animations will be, but the more CPU time will be used. Current front ends use values around 20ms (i.e. 50Hz). After this function is called, the mid-end will expect to receive calls to \cw{midend_timer()} on a regular basis. \H{frontend-deactivate-timer} \cw{deactivate_timer()} \c void deactivate_timer(frontend *fe); This is called by the mid-end to request that the front end stop calling \cw{midend_timer()}. \H{frontend-fatal} \cw{fatal()} \c void fatal(char *fmt, ...); This is called by some utility functions if they encounter a genuinely fatal error such as running out of memory. It is a variadic function in the style of \cw{printf()}, and is expected to show the formatted error message to the user any way it can and then terminate the application. It must not return. \H{frontend-default-colour} \cw{frontend_default_colour()} \c void frontend_default_colour(frontend *fe, float *output); This function expects to be passed a pointer to an array of three \cw{float}s. It returns the platform's local preferred background colour in those three floats, as red, green and blue values (in that order) ranging from \cw{0.0} to \cw{1.0}. This function should only ever be called by the back end function \cw{colours()} (\k{backend-colours}). (Thus, it isn't a \e{midend}-to-frontend function as such, but there didn't seem to be anywhere else particularly good to put it. Sorry.) \C{utils} Utility APIs This chapter documents a variety of utility APIs provided for the general use of the rest of the Puzzles code. \H{utils-random} Random number generation Platforms' local random number generators vary widely in quality and seed size. Puzzles therefore supplies its own high-quality random number generator, with the additional advantage of giving the same results if fed the same seed data on different platforms. This allows game random seeds to be exchanged between different ports of Puzzles and still generate the same games. Unlike the ANSI C \cw{rand()} function, the Puzzles random number generator has an \e{explicit} state object called a \c{random_state}. One of these is managed by each mid-end, for example, and passed to the back end to generate a game with. \S{utils-random-init} \cw{random_new()} \c random_state *random_new(char *seed, int len); Allocates, initialises and returns a new \c{random_state}. The input data is used as the seed for the random number stream (i.e. using the same seed at a later time will generate the same stream). The seed data can be any data at all; there is no requirement to use printable ASCII, or NUL-terminated strings, or anything like that. \S{utils-random-copy} \cw{random_copy()} \c random_state *random_copy(random_state *tocopy); Allocates a new \c{random_state}, copies the contents of another \c{random_state} into it, and returns the new state. If exactly the same sequence of functions is subseqently called on both the copy and the original, the results will be identical. This may be useful for speculatively performing some operation using a given random state, and later replaying that operation precisely. \S{utils-random-free} \cw{random_free()} \c void random_free(random_state *state); Frees a \c{random_state}. \S{utils-random-bits} \cw{random_bits()} \c unsigned long random_bits(random_state *state, int bits); Returns a random number from 0 to \cw{2^bits-1} inclusive. \c{bits} should be between 1 and 32 inclusive. \S{utils-random-upto} \cw{random_upto()} \c unsigned long random_upto(random_state *state, unsigned long limit); Returns a random number from 0 to \cw{limit-1} inclusive. \S{utils-random-state-encode} \cw{random_state_encode()} \c char *random_state_encode(random_state *state); Encodes the entire contents of a \c{random_state} in printable ASCII. Returns a dynamically allocated string containing that encoding. This can subsequently be passed to \cw{random_state_decode()} to reconstruct the same \c{random_state}. \S{utils-random-state-decode} \cw{random_state_decode()} \c random_state *random_state_decode(char *input); Decodes a string generated by \cw{random_state_encode()} and reconstructs an equivalent \c{random_state} to the one encoded, i.e. it should produce the same stream of random numbers. This function has no error reporting; if you pass it an invalid string it will simply generate an arbitrary random state, which may turn out to be noticeably non-random. \S{utils-shuffle} \cw{shuffle()} \c void shuffle(void *array, int nelts, int eltsize, random_state *rs); Shuffles an array into a random order. The interface is much like ANSI C \cw{qsort()}, except that there's no need for a compare function. \c{array} is a pointer to the first element of the array. \c{nelts} is the number of elements in the array; \c{eltsize} is the size of a single element (typically measured using \c{sizeof}). \c{rs} is a \c{random_state} used to generate all the random numbers for the shuffling process. \H{utils-presets} Presets menu management The function \c{midend_get_presets()} (\k{midend-get-presets}) returns a data structure describing a menu hierarchy. Back ends can also choose to provide such a structure to the mid-end, if they want to group their presets hierarchically. To make this easy, there are a few utility functions to construct preset menu structures, and also one intended for front-end use. \S{utils-preset-menu-new} \cw{preset_menu_new()} \c struct preset_menu *preset_menu_new(void); Allocates a new \c{struct preset_menu}, and initialises it to hold no menu items. \S{utils-preset-menu-add_submenu} \cw{preset_menu_add_submenu()} \c struct preset_menu *preset_menu_add_submenu \c (struct preset_menu *parent, char *title); Adds a new submenu to the end of an existing preset menu, and returns a pointer to a newly allocated \c{struct preset_menu} describing the submenu. The string parameter \cq{title} must be dynamically allocated by the caller. The preset-menu structure will take ownership of it, so the caller must not free it. \S{utils-preset-menu-add-preset} \cw{preset_menu_add_preset()} \c void preset_menu_add_preset \c (struct preset_menu *menu, char *title, game_params *params); Adds a preset game configuration to the end of a preset menu. Both the string parameter \cq{title} and the game parameter structure \cq{params} itself must be dynamically allocated by the caller. The preset-menu structure will take ownership of it, so the caller must not free it. \S{utils-preset-menu-lookup-by-id} \cw{preset_menu_lookup_by_id()} \c game_params *preset_menu_lookup_by_id \c (struct preset_menu *menu, int id); Given a numeric index, searches recursively through a preset menu hierarchy to find the corresponding menu entry, and returns a pointer to its existing \c{game_params} structure. This function is intended for front end use (but front ends need not use it if they prefer to do things another way). If a front end finds it inconvenient to store anything more than a numeric index alongside each menu item, then this function provides an easy way for the front end to get back the actual game parameters corresponding to a menu item that the user has selected. \H{utils-alloc} Memory allocation Puzzles has some central wrappers on the standard memory allocation functions, which provide compile-time type checking, and run-time error checking by means of quitting the application if it runs out of memory. This doesn't provide the best possible recovery from memory shortage, but on the other hand it greatly simplifies the rest of the code, because nothing else anywhere needs to worry about \cw{NULL} returns from allocation. \S{utils-snew} \cw{snew()} \c var = snew(type); \e iii iiii This macro takes a single argument which is a \e{type name}. It allocates space for one object of that type. If allocation fails it will call \cw{fatal()} and not return; so if it does return, you can be confident that its return value is non-\cw{NULL}. The return value is cast to the specified type, so that the compiler will type-check it against the variable you assign it into. Thus, this ensures you don't accidentally allocate memory the size of the wrong type and assign it into a variable of the right one (or vice versa!). \S{utils-snewn} \cw{snewn()} \c var = snewn(n, type); \e iii i iiii This macro is the array form of \cw{snew()}. It takes two arguments; the first is a number, and the second is a type name. It allocates space for that many objects of that type, and returns a type-checked non-\cw{NULL} pointer just as \cw{snew()} does. \S{utils-sresize} \cw{sresize()} \c var = sresize(var, n, type); \e iii iii i iiii This macro is a type-checked form of \cw{realloc()}. It takes three arguments: an input memory block, a new size in elements, and a type. It re-sizes the input memory block to a size sufficient to contain that many elements of that type. It returns a type-checked non-\cw{NULL} pointer, like \cw{snew()} and \cw{snewn()}. The input memory block can be \cw{NULL}, in which case this function will behave exactly like \cw{snewn()}. (In principle any ANSI-compliant \cw{realloc()} implementation ought to cope with this, but I've never quite trusted it to work everywhere.) \S{utils-sfree} \cw{sfree()} \c void sfree(void *p); This function is pretty much equivalent to \cw{free()}. It is provided with a dynamically allocated block, and frees it. The input memory block can be \cw{NULL}, in which case this function will do nothing. (In principle any ANSI-compliant \cw{free()} implementation ought to cope with this, but I've never quite trusted it to work everywhere.) \S{utils-dupstr} \cw{dupstr()} \c char *dupstr(const char *s); This function dynamically allocates a duplicate of a C string. Like the \cw{snew()} functions, it guarantees to return non-\cw{NULL} or not return at all. (Many platforms provide the function \cw{strdup()}. As well as guaranteeing never to return \cw{NULL}, my version has the advantage of being defined \e{everywhere}, rather than inconveniently not quite everywhere.) \S{utils-free-cfg} \cw{free_cfg()} \c void free_cfg(config_item *cfg); This function correctly frees an array of \c{config_item}s, including walking the array until it gets to the end and freeing precisely those \c{sval} fields which are expected to be dynamically allocated. (See \k{backend-configure} for details of the \c{config_item} structure.) \H{utils-tree234} Sorted and counted tree functions Many games require complex algorithms for generating random puzzles, and some require moderately complex algorithms even during play. A common requirement during these algorithms is for a means of maintaining sorted or unsorted lists of items, such that items can be removed and added conveniently. For general use, Puzzles provides the following set of functions which maintain 2-3-4 trees in memory. (A 2-3-4 tree is a balanced tree structure, with the property that all lookups, insertions, deletions, splits and joins can be done in \cw{O(log N)} time.) All these functions expect you to be storing a tree of \c{void *} pointers. You can put anything you like in those pointers. By the use of per-node element counts, these tree structures have the slightly unusual ability to look elements up by their numeric index within the list represented by the tree. This means that they can be used to store an unsorted list (in which case, every time you insert a new element, you must explicitly specify the position where you wish to insert it). They can also do numeric lookups in a sorted tree, which might be useful for (for example) tracking the median of a changing data set. As well as storing sorted lists, these functions can be used for storing \q{maps} (associative arrays), by defining each element of a tree to be a (key, value) pair. \S{utils-newtree234} \cw{newtree234()} \c tree234 *newtree234(cmpfn234 cmp); Creates a new empty tree, and returns a pointer to it. The parameter \c{cmp} determines the sorting criterion on the tree. Its prototype is \c typedef int (*cmpfn234)(void *, void *); If you want a sorted tree, you should provide a function matching this prototype, which returns like \cw{strcmp()} does (negative if the first argument is smaller than the second, positive if it is bigger, zero if they compare equal). In this case, the function \cw{addpos234()} will not be usable on your tree (because all insertions must respect the sorting order). If you want an unsorted tree, pass \cw{NULL}. In this case you will not be able to use either \cw{add234()} or \cw{del234()}, or any other function such as \cw{find234()} which depends on a sorting order. Your tree will become something more like an array, except that it will efficiently support insertion and deletion as well as lookups by numeric index. \S{utils-freetree234} \cw{freetree234()} \c void freetree234(tree234 *t); Frees a tree. This function will not free the \e{elements} of the tree (because they might not be dynamically allocated, or you might be storing the same set of elements in more than one tree); it will just free the tree structure itself. If you want to free all the elements of a tree, you should empty it before passing it to \cw{freetree234()}, by means of code along the lines of \c while ((element = delpos234(tree, 0)) != NULL) \c sfree(element); /* or some more complicated free function */ \e iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii \S{utils-add234} \cw{add234()} \c void *add234(tree234 *t, void *e); Inserts a new element \c{e} into the tree \c{t}. This function expects the tree to be sorted; the new element is inserted according to the sort order. If an element comparing equal to \c{e} is already in the tree, then the insertion will fail, and the return value will be the existing element. Otherwise, the insertion succeeds, and \c{e} is returned. \S{utils-addpos234} \cw{addpos234()} \c void *addpos234(tree234 *t, void *e, int index); Inserts a new element into an unsorted tree. Since there is no sorting order to dictate where the new element goes, you must specify where you want it to go. Setting \c{index} to zero puts the new element right at the start of the list; setting \c{index} to the current number of elements in the tree puts the new element at the end. Return value is \c{e}, in line with \cw{add234()} (although this function cannot fail except by running out of memory, in which case it will bomb out and die rather than returning an error indication). \S{utils-index234} \cw{index234()} \c void *index234(tree234 *t, int index); Returns a pointer to the \c{index}th element of the tree, or \cw{NULL} if \c{index} is out of range. Elements of the tree are numbered from zero. \S{utils-find234} \cw{find234()} \c void *find234(tree234 *t, void *e, cmpfn234 cmp); Searches for an element comparing equal to \c{e} in a sorted tree. If \c{cmp} is \cw{NULL}, the tree's ordinary comparison function will be used to perform the search. However, sometimes you don't want that; suppose, for example, each of your elements is a big structure containing a \c{char *} name field, and you want to find the element with a given name. You \e{could} achieve this by constructing a fake element structure, setting its name field appropriately, and passing it to \cw{find234()}, but you might find it more convenient to pass \e{just} a name string to \cw{find234()}, supplying an alternative comparison function which expects one of its arguments to be a bare name and the other to be a large structure containing a name field. Therefore, if \c{cmp} is not \cw{NULL}, then it will be used to compare \c{e} to elements of the tree. The first argument passed to \c{cmp} will always be \c{e}; the second will be an element of the tree. (See \k{utils-newtree234} for the definition of the \c{cmpfn234} function pointer type.) The returned value is the element found, or \cw{NULL} if the search is unsuccessful. \S{utils-findrel234} \cw{findrel234()} \c void *findrel234(tree234 *t, void *e, cmpfn234 cmp, int relation); This function is like \cw{find234()}, but has the additional ability to do a \e{relative} search. The additional parameter \c{relation} can be one of the following values: \dt \cw{REL234_EQ} \dd Find only an element that compares equal to \c{e}. This is exactly the behaviour of \cw{find234()}. \dt \cw{REL234_LT} \dd Find the greatest element that compares strictly less than \c{e}. \c{e} may be \cw{NULL}, in which case it finds the greatest element in the whole tree (which could also be done by \cw{index234(t, count234(t)-1)}). \dt \cw{REL234_LE} \dd Find the greatest element that compares less than or equal to \c{e}. (That is, find an element that compares equal to \c{e} if possible, but failing that settle for something just less than it.) \dt \cw{REL234_GT} \dd Find the smallest element that compares strictly greater than \c{e}. \c{e} may be \cw{NULL}, in which case it finds the smallest element in the whole tree (which could also be done by \cw{index234(t, 0)}). \dt \cw{REL234_GE} \dd Find the smallest element that compares greater than or equal to \c{e}. (That is, find an element that compares equal to \c{e} if possible, but failing that settle for something just bigger than it.) Return value, as before, is the element found or \cw{NULL} if no element satisfied the search criterion. \S{utils-findpos234} \cw{findpos234()} \c void *findpos234(tree234 *t, void *e, cmpfn234 cmp, int *index); This function is like \cw{find234()}, but has the additional feature of returning the index of the element found in the tree; that index is written to \c{*index} in the event of a successful search (a non-\cw{NULL} return value). \c{index} may be \cw{NULL}, in which case this function behaves exactly like \cw{find234()}. \S{utils-findrelpos234} \cw{findrelpos234()} \c void *findrelpos234(tree234 *t, void *e, cmpfn234 cmp, int relation, \c int *index); This function combines all the features of \cw{findrel234()} and \cw{findpos234()}. \S{utils-del234} \cw{del234()} \c void *del234(tree234 *t, void *e); Finds an element comparing equal to \c{e} in the tree, deletes it, and returns it. The input tree must be sorted. The element found might be \c{e} itself, or might merely compare equal to it. Return value is \cw{NULL} if no such element is found. \S{utils-delpos234} \cw{delpos234()} \c void *delpos234(tree234 *t, int index); Deletes the element at position \c{index} in the tree, and returns it. Return value is \cw{NULL} if the index is out of range. \S{utils-count234} \cw{count234()} \c int count234(tree234 *t); Returns the number of elements currently in the tree. \S{utils-splitpos234} \cw{splitpos234()} \c tree234 *splitpos234(tree234 *t, int index, int before); Splits the input tree into two pieces at a given position, and creates a new tree containing all the elements on one side of that position. If \c{before} is \cw{TRUE}, then all the items at or after position \c{index} are left in the input tree, and the items before that point are returned in the new tree. Otherwise, the reverse happens: all the items at or after \c{index} are moved into the new tree, and those before that point are left in the old one. If \c{index} is equal to 0 or to the number of elements in the input tree, then one of the two trees will end up empty (and this is not an error condition). If \c{index} is further out of range in either direction, the operation will fail completely and return \cw{NULL}. This operation completes in \cw{O(log N)} time, no matter how large the tree or how balanced or unbalanced the split. \S{utils-split234} \cw{split234()} \c tree234 *split234(tree234 *t, void *e, cmpfn234 cmp, int rel); Splits a sorted tree according to its sort order. \c{rel} can be any of the relation constants described in \k{utils-findrel234}, \e{except} for \cw{REL234_EQ}. All the elements having that relation to \c{e} will be transferred into the new tree; the rest will be left in the old one. The parameter \c{cmp} has the same semantics as it does in \cw{find234()}: if it is not \cw{NULL}, it will be used in place of the tree's own comparison function when comparing elements to \c{e}, in such a way that \c{e} itself is always the first of its two operands. Again, this operation completes in \cw{O(log N)} time, no matter how large the tree or how balanced or unbalanced the split. \S{utils-join234} \cw{join234()} \c tree234 *join234(tree234 *t1, tree234 *t2); Joins two trees together by concatenating the lists they represent. All the elements of \c{t2} are moved into \c{t1}, in such a way that they appear \e{after} the elements of \c{t1}. The tree \c{t2} is freed; the return value is \c{t1}. If you apply this function to a sorted tree and it violates the sort order (i.e. the smallest element in \c{t2} is smaller than or equal to the largest element in \c{t1}), the operation will fail and return \cw{NULL}. This operation completes in \cw{O(log N)} time, no matter how large the trees being joined together. \S{utils-join234r} \cw{join234r()} \c tree234 *join234r(tree234 *t1, tree234 *t2); Joins two trees together in exactly the same way as \cw{join234()}, but this time the combined tree is returned in \c{t2}, and \c{t1} is destroyed. The elements in \c{t1} still appear before those in \c{t2}. Again, this operation completes in \cw{O(log N)} time, no matter how large the trees being joined together. \S{utils-copytree234} \cw{copytree234()} \c tree234 *copytree234(tree234 *t, copyfn234 copyfn, \c void *copyfnstate); Makes a copy of an entire tree. If \c{copyfn} is \cw{NULL}, the tree will be copied but the elements will not be; i.e. the new tree will contain pointers to exactly the same physical elements as the old one. If you want to copy each actual element during the operation, you can instead pass a function in \c{copyfn} which makes a copy of each element. That function has the prototype \c typedef void *(*copyfn234)(void *state, void *element); and every time it is called, the \c{state} parameter will be set to the value you passed in as \c{copyfnstate}. \H{utils-misc} Miscellaneous utility functions and macros This section contains all the utility functions which didn't sensibly fit anywhere else. \S{utils-truefalse} \cw{TRUE} and \cw{FALSE} The main Puzzles header file defines the macros \cw{TRUE} and \cw{FALSE}, which are used throughout the code in place of 1 and 0 (respectively) to indicate that the values are in a boolean context. For code base consistency, I'd prefer it if submissions of new code followed this convention as well. \S{utils-maxmin} \cw{max()} and \cw{min()} The main Puzzles header file defines the pretty standard macros \cw{max()} and \cw{min()}, each of which is given two arguments and returns the one which compares greater or less respectively. These macros may evaluate their arguments multiple times. Avoid side effects. \S{utils-pi} \cw{PI} The main Puzzles header file defines a macro \cw{PI} which expands to a floating-point constant representing pi. (I've never understood why ANSI's \cw{} doesn't define this. It'd be so useful!) \S{utils-obfuscate-bitmap} \cw{obfuscate_bitmap()} \c void obfuscate_bitmap(unsigned char *bmp, int bits, int decode); This function obscures the contents of a piece of data, by cryptographic methods. It is useful for games of hidden information (such as Mines, Guess or Black Box), in which the game ID theoretically reveals all the information the player is supposed to be trying to guess. So in order that players should be able to send game IDs to one another without accidentally spoiling the resulting game by looking at them, these games obfuscate their game IDs using this function. Although the obfuscation function is cryptographic, it cannot properly be called encryption because it has no key. Therefore, anybody motivated enough can re-implement it, or hack it out of the Puzzles source, and strip the obfuscation off one of these game IDs to see what lies beneath. (Indeed, they could usually do it much more easily than that, by entering the game ID into their own copy of the puzzle and hitting Solve.) The aim is not to protect against a determined attacker; the aim is simply to protect people who wanted to play the game honestly from \e{accidentally} spoiling their own fun. The input argument \c{bmp} points at a piece of memory to be obfuscated. \c{bits} gives the length of the data. Note that that length is in \e{bits} rather than bytes: if you ask for obfuscation of a partial number of bytes, then you will get it. Bytes are considered to be used from the top down: thus, for example, setting \c{bits} to 10 will cover the whole of \cw{bmp[0]} and the \e{top two} bits of \cw{bmp[1]}. The remainder of a partially used byte is undefined (i.e. it may be corrupted by the function). The parameter \c{decode} is \cw{FALSE} for an encoding operation, and \cw{TRUE} for a decoding operation. Each is the inverse of the other. (There's no particular reason you shouldn't obfuscate by decoding and restore cleartext by encoding, if you really wanted to; it should still work.) The input bitmap is processed in place. \S{utils-bin2hex} \cw{bin2hex()} \c char *bin2hex(const unsigned char *in, int inlen); This function takes an input byte array and converts it into an ASCII string encoding those bytes in (lower-case) hex. It returns a dynamically allocated string containing that encoding. This function is useful for encoding the result of \cw{obfuscate_bitmap()} in printable ASCII for use in game IDs. \S{utils-hex2bin} \cw{hex2bin()} \c unsigned char *hex2bin(const char *in, int outlen); This function takes an ASCII string containing hex digits, and converts it back into a byte array of length \c{outlen}. If there aren't enough hex digits in the string, the contents of the resulting array will be undefined. This function is the inverse of \cw{bin2hex()}. \S{utils-game-mkhighlight} \cw{game_mkhighlight()} \c void game_mkhighlight(frontend *fe, float *ret, \c int background, int highlight, int lowlight); It's reasonably common for a puzzle game's graphics to use highlights and lowlights to indicate \q{raised} or \q{lowered} sections. Fifteen, Sixteen and Twiddle are good examples of this. Puzzles using this graphical style are running a risk if they just use whatever background colour is supplied to them by the front end, because that background colour might be too light to see any highlights on at all. (In particular, it's not unheard of for the front end to specify a default background colour of white.) Therefore, such puzzles can call this utility function from their \cw{colours()} routine (\k{backend-colours}). You pass it your front end handle, a pointer to the start of your return array, and three colour indices. It will: \b call \cw{frontend_default_colour()} (\k{frontend-default-colour}) to fetch the front end's default background colour \b alter the brightness of that colour if it's unsuitable \b define brighter and darker variants of the colour to be used as highlights and lowlights \b write those results into the relevant positions in the \c{ret} array. Thus, \cw{ret[background*3]} to \cw{ret[background*3+2]} will be set to RGB values defining a sensible background colour, and similary \c{highlight} and \c{lowlight} will be set to sensible colours. \C{writing} How to write a new puzzle This chapter gives a guide to how to actually write a new puzzle: where to start, what to do first, how to solve common problems. The previous chapters have been largely composed of facts. This one is mostly advice. \H{writing-editorial} Choosing a puzzle Before you start writing a puzzle, you have to choose one. Your taste in puzzle games is up to you, of course; and, in fact, you're probably reading this guide because you've \e{already} thought of a game you want to write. But if you want to get it accepted into the official Puzzles distribution, then there's a criterion it has to meet. The current Puzzles editorial policy is that all games should be \e{fair}. A fair game is one which a player can only fail to complete through demonstrable lack of skill \dash that is, such that a better player in the same situation would have \e{known} to do something different. For a start, that means every game presented to the user must have \e{at least one solution}. Giving the unsuspecting user a puzzle which is actually impossible is not acceptable. (There is an exception: if the user has selected some non-default option which is clearly labelled as potentially unfair, \e{then} you're allowed to generate possibly insoluble puzzles, because the user isn't unsuspecting any more. Same Game and Mines both have options of this type.) Also, this actually \e{rules out} games such as Klondike, or the normal form of Mahjong Solitaire. Those games have the property that even if there is a solution (i.e. some sequence of moves which will get from the start state to the solved state), the player doesn't necessarily have enough information to \e{find} that solution. In both games, it is possible to reach a dead end because you had an arbitrary choice to make and made it the wrong way. This violates the fairness criterion, because a better player couldn't have known they needed to make the other choice. (GNOME has a variant on Mahjong Solitaire which makes it fair: there is a Shuffle operation which randomly permutes all the remaining tiles without changing their positions, which allows you to get out of a sticky situation. Using this operation adds a 60-second penalty to your solution time, so it's to the player's advantage to try to minimise the chance of having to use it. It's still possible to render the game uncompletable if you end up with only two tiles vertically stacked, but that's easy to foresee and avoid using a shuffle operation. This form of the game \e{is} fair. Implementing it in Puzzles would require an infrastructure change so that the back end could communicate time penalties to the mid-end, but that would be easy enough.) Providing a \e{unique} solution is a little more negotiable; it depends on the puzzle. Solo would have been of unacceptably low quality if it didn't always have a unique solution, whereas Twiddle inherently has multiple solutions by its very nature and it would have been meaningless to even \e{suggest} making it uniquely soluble. Somewhere in between, Flip could reasonably be made to have unique solutions (by enforcing a zero-dimension kernel in every generated matrix) but it doesn't seem like a serious quality problem that it doesn't. Of course, you don't \e{have} to care about all this. There's nothing stopping you implementing any puzzle you want to if you're happy to maintain your puzzle yourself, distribute it from your own web site, fork the Puzzles code completely, or anything like that. It's free software; you can do what you like with it. But any game that you want to be accepted into \e{my} Puzzles code base has to satisfy the fairness criterion, which means all randomly generated puzzles must have a solution (unless the user has deliberately chosen otherwise) and it must be possible \e{in theory} to find that solution without having to guess. \H{writing-gs} Getting started The simplest way to start writing a new puzzle is to copy \c{nullgame.c}. This is a template puzzle source file which does almost nothing, but which contains all the back end function prototypes and declares the back end data structure correctly. It is built every time the rest of Puzzles is built, to ensure that it doesn't get out of sync with the code and remains buildable. So start by copying \c{nullgame.c} into your new source file. Then you'll gradually add functionality until the very boring Null Game turns into your real game. Next you'll need to add your puzzle to the Makefiles, in order to compile it conveniently. \e{Do not edit the Makefiles}: they are created automatically by the script \c{mkfiles.pl}, from the file called \c{Recipe}. Edit \c{Recipe}, and then re-run \c{mkfiles.pl}. Also, don't forget to add your puzzle to \c{list.c}: if you don't, then it will still run fine on platforms which build each puzzle separately, but Mac OS X and other monolithic platforms will not include your new puzzle in their single binary. Once your source file is building, you can move on to the fun bit. \S{writing-generation} Puzzle generation Randomly generating instances of your puzzle is almost certain to be the most difficult part of the code, and also the task with the highest chance of turning out to be completely infeasible. Therefore I strongly recommend doing it \e{first}, so that if it all goes horribly wrong you haven't wasted any more time than you absolutely had to. What I usually do is to take an unmodified \c{nullgame.c}, and start adding code to \cw{new_game_desc()} which tries to generate a puzzle instance and print it out using \cw{printf()}. Once that's working, \e{then} I start connecting it up to the return value of \cw{new_game_desc()}, populating other structures like \c{game_params}, and generally writing the rest of the source file. There are many ways to generate a puzzle which is known to be soluble. In this section I list all the methods I currently know of, in case any of them can be applied to your puzzle. (Not all of these methods will work, or in some cases even make sense, for all puzzles.) Some puzzles are mathematically tractable, meaning you can work out in advance which instances are soluble. Sixteen, for example, has a parity constraint in some settings which renders exactly half the game space unreachable, but it can be mathematically proved that any position not in that half \e{is} reachable. Therefore, Sixteen's grid generation simply consists of selecting at random from a well defined subset of the game space. Cube in its default state is even easier: \e{every} possible arrangement of the blue squares and the cube's starting position is soluble! Another option is to redefine what you mean by \q{soluble}. Black Box takes this approach. There are layouts of balls in the box which are completely indistinguishable from one another no matter how many beams you fire into the box from which angles, which would normally be grounds for declaring those layouts unfair; but fortunately, detecting that indistinguishability is computationally easy. So Black Box doesn't demand that your ball placements match its own; it merely demands that your ball placements be \e{indistinguishable} from the ones it was thinking of. If you have an ambiguous puzzle, then any of the possible answers is considered to be a solution. Having redefined the rules in that way, any puzzle is soluble again. Those are the simple techniques. If they don't work, you have to get cleverer. One way to generate a soluble puzzle is to start from the solved state and make inverse moves until you reach a starting state. Then you know there's a solution, because you can just list the inverse moves you made and make them in the opposite order to return to the solved state. This method can be simple and effective for puzzles where you get to decide what's a starting state and what's not. In Pegs, for example, the generator begins with one peg in the centre of the board and makes inverse moves until it gets bored; in this puzzle, valid inverse moves are easy to detect, and \e{any} state that's reachable from the solved state by inverse moves is a reasonable starting position. So Pegs just continues making inverse moves until the board satisfies some criteria about extent and density, and then stops and declares itself done. For other puzzles, it can be a lot more difficult. Same Game uses this strategy too, and it's lucky to get away with it at all: valid inverse moves aren't easy to find (because although it's easy to insert additional squares in a Same Game position, it's difficult to arrange that \e{after} the insertion they aren't adjacent to any other squares of the same colour), so you're constantly at risk of running out of options and having to backtrack or start again. Also, Same Game grids never start off half-empty, which means you can't just stop when you run out of moves \dash you have to find a way to fill the grid up \e{completely}. The other way to generate a puzzle that's soluble is to start from the other end, and actually write a \e{solver}. This tends to ensure that a puzzle has a \e{unique} solution over and above having a solution at all, so it's a good technique to apply to puzzles for which that's important. One theoretical drawback of generating soluble puzzles by using a solver is that your puzzles are restricted in difficulty to those which the solver can handle. (Most solvers are not fully general: many sets of puzzle rules are NP-complete or otherwise nasty, so most solvers can only handle a subset of the theoretically soluble puzzles.) It's been my experience in practice, however, that this usually isn't a problem; computers are good at very different things from humans, and what the computer thinks is nice and easy might still be pleasantly challenging for a human. For example, when solving Dominosa puzzles I frequently find myself using a variety of reasoning techniques that my solver doesn't know about; in principle, therefore, I should be able to solve the puzzle using only those techniques it \e{does} know about, but this would involve repeatedly searching the entire grid for the one simple deduction I can make. Computers are good at this sort of exhaustive search, but it's been my experience that human solvers prefer to do more complex deductions than to spend ages searching for simple ones. So in many cases I don't find my own playing experience to be limited by the restrictions on the solver. (This isn't \e{always} the case. Solo is a counter-example; generating Solo puzzles using a simple solver does lead to qualitatively easier puzzles. Therefore I had to make the Solo solver rather more advanced than most of them.) There are several different ways to apply a solver to the problem of generating a soluble puzzle. I list a few of them below. The simplest approach is brute force: randomly generate a puzzle, use the solver to see if it's soluble, and if not, throw it away and try again until you get lucky. This is often a viable technique if all else fails, but it tends not to scale well: for many puzzle types, the probability of finding a uniquely soluble instance decreases sharply as puzzle size goes up, so this technique might work reasonably fast for small puzzles but take (almost) forever at larger sizes. Still, if there's no other alternative it can be usable: Pattern and Dominosa both use this technique. (However, Dominosa has a means of tweaking the randomly generated grids to increase the \e{probability} of them being soluble, by ruling out one of the most common ambiguous cases. This improved generation speed by over a factor of 10 on the highest preset!) An approach which can be more scalable involves generating a grid and then tweaking it to make it soluble. This is the technique used by Mines and also by Net: first a random puzzle is generated, and then the solver is run to see how far it gets. Sometimes the solver will get stuck; when that happens, examine the area it's having trouble with, and make a small random change in that area to allow it to make more progress. Continue solving (possibly even without restarting the solver), tweaking as necessary, until the solver finishes. Then restart the solver from the beginning to ensure that the tweaks haven't caused new problems in the process of solving old ones (which can sometimes happen). This strategy works well in situations where the usual solver failure mode is to get stuck in an easily localised spot. Thus it works well for Net and Mines, whose most common failure mode tends to be that most of the grid is fine but there are a few widely separated ambiguous sections; but it would work less well for Dominosa, in which the way you get stuck is to have scoured the whole grid and not found anything you can deduce \e{anywhere}. Also, it relies on there being a low probability that tweaking the grid introduces a new problem at the same time as solving the old one; Mines and Net also have the property that most of their deductions are local, so that it's very unlikely for a tweak to affect something half way across the grid from the location where it was applied. In Dominosa, by contrast, a lot of deductions use information about half the grid (\q{out of all the sixes, only one is next to a three}, which can depend on the values of up to 32 of the 56 squares in the default setting!), so this tweaking strategy would be rather less likely to work well. A more specialised strategy is that used in Solo and Slant. These puzzles have the property that they derive their difficulty from not presenting all the available clues. (In Solo's case, if all the possible clues were provided then the puzzle would already be solved; in Slant it would still require user action to fill in the lines, but it would present no challenge at all). Therefore, a simple generation technique is to leave the decision of which clues to provide until the last minute. In other words, first generate a random \e{filled} grid with all possible clues present, and then gradually remove clues for as long as the solver reports that it's still soluble. Unlike the methods described above, this technique \e{cannot} fail \dash once you've got a filled grid, nothing can stop you from being able to convert it into a viable puzzle. However, it wouldn't even be meaningful to apply this technique to (say) Pattern, in which clues can never be left out, so the only way to affect the set of clues is by altering the solution. (Unfortunately, Solo is complicated by the need to provide puzzles at varying difficulty levels. It's easy enough to generate a puzzle of \e{at most} a given level of difficulty; you just have a solver with configurable intelligence, and you set it to a given level and apply the above technique, thus guaranteeing that the resulting grid is solvable by someone with at most that much intelligence. However, generating a puzzle of \e{at least} a given level of difficulty is rather harder; if you go for \e{at most} Intermediate level, you're likely to find that you've accidentally generated a Trivial grid a lot of the time, because removing just one number is sufficient to take the puzzle from Trivial straight to Ambiguous. In that situation Solo has no remaining options but to throw the puzzle away and start again.) A final strategy is to use the solver \e{during} puzzle construction: lay out a bit of the grid, run the solver to see what it allows you to deduce, and then lay out a bit more to allow the solver to make more progress. There are articles on the web that recommend constructing Sudoku puzzles by this method (which is completely the opposite way round to how Solo does it); for Sudoku it has the advantage that you get to specify your clue squares in advance (so you can have them make pretty patterns). Rectangles uses a strategy along these lines. First it generates a grid by placing the actual rectangles; then it has to decide where in each rectangle to place a number. It uses a solver to help it place the numbers in such a way as to ensure a unique solution. It does this by means of running a test solver, but it runs the solver \e{before} it's placed any of the numbers \dash which means the solver must be capable of coping with uncertainty about exactly where the numbers are! It runs the solver as far as it can until it gets stuck; then it narrows down the possible positions of a number in order to allow the solver to make more progress, and so on. Most of the time this process terminates with the grid fully solved, at which point any remaining number-placement decisions can be made at random from the options not so far ruled out. Note that unlike the Net/Mines tweaking strategy described above, this algorithm does not require a checking run after it completes: if it finishes successfully at all, then it has definitely produced a uniquely soluble puzzle. Most of the strategies described above are not 100% reliable. Each one has a failure rate: every so often it has to throw out the whole grid and generate a fresh one from scratch. (Solo's strategy would be the exception, if it weren't for the need to provide configurable difficulty levels.) Occasional failures are not a fundamental problem in this sort of work, however: it's just a question of dividing the grid generation time by the success rate (if it takes 10ms to generate a candidate grid and 1/5 of them work, then it will take 50ms on average to generate a viable one), and seeing whether the expected time taken to \e{successfully} generate a puzzle is unacceptably slow. Dominosa's generator has a very low success rate (about 1 out of 20 candidate grids turn out to be usable, and if you think \e{that's} bad then go and look at the source code and find the comment showing what the figures were before the generation-time tweaks!), but the generator itself is very fast so this doesn't matter. Rectangles has a slower generator, but fails well under 50% of the time. So don't be discouraged if you have an algorithm that doesn't always work: if it \e{nearly} always works, that's probably good enough. The one place where reliability is important is that your algorithm must never produce false positives: it must not claim a puzzle is soluble when it isn't. It can produce false negatives (failing to notice that a puzzle is soluble), and it can fail to generate a puzzle at all, provided it doesn't do either so often as to become slow. One last piece of advice: for grid-based puzzles, when writing and testing your generation algorithm, it's almost always a good idea \e{not} to test it initially on a grid that's square (i.e. \cw{w==h}), because if the grid is square then you won't notice if you mistakenly write \c{h} instead of \c{w} (or vice versa) somewhere in the code. Use a rectangular grid for testing, and any size of grid will be likely to work after that. \S{writing-textformats} Designing textual description formats Another aspect of writing a puzzle which is worth putting some thought into is the design of the various text description formats: the format of the game parameter encoding, the game description encoding, and the move encoding. The first two of these should be reasonably intuitive for a user to type in; so provide some flexibility where possible. Suppose, for example, your parameter format consists of two numbers separated by an \c{x} to specify the grid dimensions (\c{10x10} or \c{20x15}), and then has some suffixes to specify other aspects of the game type. It's almost always a good idea in this situation to arrange that \cw{decode_params()} can handle the suffixes appearing in any order, even if \cw{encode_params()} only ever generates them in one order. These formats will also be expected to be reasonably stable: users will expect to be able to exchange game IDs with other users who aren't running exactly the same version of your game. So make them robust and stable: don't build too many assumptions into the game ID format which will have to be changed every time something subtle changes in the puzzle code. \H{writing-howto} Common how-to questions This section lists some common things people want to do when writing a puzzle, and describes how to achieve them within the Puzzles framework. \S{writing-howto-cursor} Drawing objects at only one position A common phenomenon is to have an object described in the \c{game_state} or the \c{game_ui} which can only be at one position. A cursor \dash probably specified in the \c{game_ui} \dash is a good example. In the \c{game_ui}, it would \e{obviously} be silly to have an array covering the whole game grid with a boolean flag stating whether the cursor was at each position. Doing that would waste space, would make it difficult to find the cursor in order to do anything with it, and would introduce the potential for synchronisation bugs in which you ended up with two cursors or none. The obviously sensible way to store a cursor in the \c{game_ui} is to have fields directly encoding the cursor's coordinates. However, it is a mistake to assume that the same logic applies to the \c{game_drawstate}. If you replicate the cursor position fields in the draw state, the redraw code will get very complicated. In the draw state, in fact, it \e{is} probably the right thing to have a cursor flag for every position in the grid. You probably have an array for the whole grid in the drawstate already (stating what is currently displayed in the window at each position); the sensible approach is to add a \q{cursor} flag to each element of that array. Then the main redraw loop will look something like this (pseudo-code): \c for (y = 0; y < h; y++) { \c for (x = 0; x < w; x++) { \c int value = state->symbol_at_position[y][x]; \c if (x == ui->cursor_x && y == ui->cursor_y) \c value |= CURSOR; \c if (ds->symbol_at_position[y][x] != value) { \c symbol_drawing_subroutine(dr, ds, x, y, value); \c ds->symbol_at_position[y][x] = value; \c } \c } \c } This loop is very simple, pretty hard to get wrong, and \e{automatically} deals both with erasing the previous cursor and drawing the new one, with no special case code required. This type of loop is generally a sensible way to write a redraw function, in fact. The best thing is to ensure that the information stored in the draw state for each position tells you \e{everything} about what was drawn there. A good way to ensure that is to pass precisely the same information, and \e{only} that information, to a subroutine that does the actual drawing; then you know there's no additional information which affects the drawing but which you don't notice changes in. \S{writing-keyboard-cursor} Implementing a keyboard-controlled cursor It is often useful to provide a keyboard control method in a basically mouse-controlled game. A keyboard-controlled cursor is best implemented by storing its location in the \c{game_ui} (since if it were in the \c{game_state} then the user would have to separately undo every cursor move operation). So the procedure would be: \b Put cursor position fields in the \c{game_ui}. \b \cw{interpret_move()} responds to arrow keys by modifying the cursor position fields and returning \cw{""}. \b \cw{interpret_move()} responds to some sort of fire button by actually performing a move based on the current cursor location. \b You might want an additional \c{game_ui} field stating whether the cursor is currently visible, and having it disappear when a mouse action occurs (so that it doesn't clutter the display when not actually in use). \b You might also want to automatically hide the cursor in \cw{changed_state()} when the current game state changes to one in which there is no move to make (which is the case in some types of completed game). \b \cw{redraw()} draws the cursor using the technique described in \k{writing-howto-cursor}. \S{writing-howto-dragging} Implementing draggable sprites Some games have a user interface which involves dragging some sort of game element around using the mouse. If you need to show a graphic moving smoothly over the top of other graphics, use a blitter (see \k{drawing-blitter} for the blitter API) to save the background underneath it. The typical scenario goes: \b Have a blitter field in the \c{game_drawstate}. \b Set the blitter field to \cw{NULL} in the game's \cw{new_drawstate()} function, since you don't yet know how big the piece of saved background needs to be. \b In the game's \cw{set_size()} function, once you know the size of the object you'll be dragging around the display and hence the required size of the blitter, actually allocate the blitter. \b In \cw{free_drawstate()}, free the blitter if it's not \cw{NULL}. \b In \cw{interpret_move()}, respond to mouse-down and mouse-drag events by updating some fields in the \cw{game_ui} which indicate that a drag is in progress. \b At the \e{very end} of \cw{redraw()}, after all other drawing has been done, draw the moving object if there is one. First save the background under the object in the blitter; then set a clip rectangle covering precisely the area you just saved (just in case anti-aliasing or some other error causes your drawing to go beyond the area you saved). Then draw the object, and call \cw{unclip()}. Finally, set a flag in the \cw{game_drawstate} that indicates that the blitter needs restoring. \b At the very start of \cw{redraw()}, before doing anything else at all, check the flag in the \cw{game_drawstate}, and if it says the blitter needs restoring then restore it. (Then clear the flag, so that this won't happen again in the next redraw if no moving object is drawn this time.) This way, you will be able to write the rest of the redraw function completely ignoring the dragged object, as if it were floating above your bitmap and being completely separate. \S{writing-ref-counting} Sharing large invariant data between all game states In some puzzles, there is a large amount of data which never changes between game states. The array of numbers in Dominosa is a good example. You \e{could} dynamically allocate a copy of that array in every \c{game_state}, and have \cw{dup_game()} make a fresh copy of it for every new \c{game_state}; but it would waste memory and time. A more efficient way is to use a reference-counted structure. \b Define a structure type containing the data in question, and also containing an integer reference count. \b Have a field in \c{game_state} which is a pointer to this structure. \b In \cw{new_game()}, when creating a fresh game state at the start of a new game, create an instance of this structure, initialise it with the invariant data, and set its reference count to 1. \b In \cw{dup_game()}, rather than making a copy of the structure for the new game state, simply set the new game state to point at the same copy of the structure, and increment its reference count. \b In \cw{free_game()}, decrement the reference count in the structure pointed to by the game state; if the count reaches zero, free the structure. This way, the invariant data will persist for only as long as it's genuinely needed; \e{as soon} as the last game state for a particular puzzle instance is freed, the invariant data for that puzzle will vanish as well. Reference counting is a very efficient form of garbage collection, when it works at all. (Which it does in this instance, of course, because there's no possibility of circular references.) \S{writing-flash-types} Implementing multiple types of flash In some games you need to flash in more than one different way. Mines, for example, flashes white when you win, and flashes red when you tread on a mine and die. The simple way to do this is: \b Have a field in the \c{game_ui} which describes the type of flash. \b In \cw{flash_length()}, examine the old and new game states to decide whether a flash is required and what type. Write the type of flash to the \c{game_ui} field whenever you return non-zero. \b In \cw{redraw()}, when you detect that \c{flash_time} is non-zero, examine the field in \c{game_ui} to decide which type of flash to draw. \cw{redraw()} will never be called with \c{flash_time} non-zero unless \cw{flash_length()} was first called to tell the mid-end that a flash was required; so whenever \cw{redraw()} notices that \c{flash_time} is non-zero, you can be sure that the field in \c{game_ui} is correctly set. \S{writing-move-anim} Animating game moves A number of puzzle types benefit from a quick animation of each move you make. For some games, such as Fifteen, this is particularly easy. Whenever \cw{redraw()} is called with \c{oldstate} non-\cw{NULL}, Fifteen simply compares the position of each tile in the two game states, and if the tile is not in the same place then it draws it some fraction of the way from its old position to its new position. This method copes automatically with undo. Other games are less obvious. In Sixteen, for example, you can't just draw each tile a fraction of the way from its old to its new position: if you did that, the end tile would zip very rapidly past all the others to get to the other end and that would look silly. (Worse, it would look inconsistent if the end tile was drawn on top going one way and on the bottom going the other way.) A useful trick here is to define a field or two in the game state that indicates what the last move was. \b Add a \q{last move} field to the \c{game_state} (or two or more fields if the move is complex enough to need them). \b \cw{new_game()} initialises this field to a null value for a new game state. \b \cw{execute_move()} sets up the field to reflect the move it just performed. \b \cw{redraw()} now needs to examine its \c{dir} parameter. If \c{dir} is positive, it determines the move being animated by looking at the last-move field in \c{newstate}; but if \c{dir} is negative, it has to look at the last-move field in \c{oldstate}, and invert whatever move it finds there. Note also that Sixteen needs to store the \e{direction} of the move, because you can't quite determine it by examining the row or column in question. You can in almost all cases, but when the row is precisely two squares long it doesn't work since a move in either direction looks the same. (You could argue that since moving a 2-element row left and right has the same effect, it doesn't matter which one you animate; but in fact it's very disorienting to click the arrow left and find the row moving right, and almost as bad to undo a move to the right and find the game animating \e{another} move to the right.) \S{writing-conditional-anim} Animating drag operations In Untangle, moves are made by dragging a node from an old position to a new position. Therefore, at the time when the move is initially made, it should not be animated, because the node has already been dragged to the right place and doesn't need moving there. However, it's nice to animate the same move if it's later undone or redone. This requires a bit of fiddling. The obvious approach is to have a flag in the \c{game_ui} which inhibits move animation, and to set that flag in \cw{interpret_move()}. The question is, when would the flag be reset again? The obvious place to do so is \cw{changed_state()}, which will be called once per move. But it will be called \e{before} \cw{anim_length()}, so if it resets the flag then \cw{anim_length()} will never see the flag set at all. The solution is to have \e{two} flags in a queue. \b Define two flags in \c{game_ui}; let's call them \q{current} and \q{next}. \b Set both to \cw{FALSE} in \c{new_ui()}. \b When a drag operation completes in \cw{interpret_move()}, set the \q{next} flag to \cw{TRUE}. \b Every time \cw{changed_state()} is called, set the value of \q{current} to the value in \q{next}, and then set the value of \q{next} to \cw{FALSE}. \b That way, \q{current} will be \cw{TRUE} \e{after} a call to \cw{changed_state()} if and only if that call to \cw{changed_state()} was the result of a drag operation processed by \cw{interpret_move()}. Any other call to \cw{changed_state()}, due to an Undo or a Redo or a Restart or a Solve, will leave \q{current} \cw{FALSE}. \b So now \cw{anim_length()} can request a move animation if and only if the \q{current} flag is \e{not} set. \S{writing-cheating} Inhibiting the victory flash when Solve is used Many games flash when you complete them, as a visual congratulation for having got to the end of the puzzle. It often seems like a good idea to disable that flash when the puzzle is brought to a solved state by means of the Solve operation. This is easily done: \b Add a \q{cheated} flag to the \c{game_state}. \b Set this flag to \cw{FALSE} in \cw{new_game()}. \b Have \cw{solve()} return a move description string which clearly identifies the move as a solve operation. \b Have \cw{execute_move()} respond to that clear identification by setting the \q{cheated} flag in the returned \c{game_state}. The flag will then be propagated to all subsequent game states, even if the user continues fiddling with the game after it is solved. \b \cw{flash_length()} now returns non-zero if \c{oldstate} is not completed and \c{newstate} is, \e{and} neither state has the \q{cheated} flag set. \H{writing-testing} Things to test once your puzzle is written Puzzle implementations written in this framework are self-testing as far as I could make them. Textual game and move descriptions, for example, are generated and parsed as part of the normal process of play. Therefore, if you can make moves in the game \e{at all} you can be reasonably confident that the mid-end serialisation interface will function correctly and you will be able to save your game. (By contrast, if I'd stuck with a single \cw{make_move()} function performing the jobs of both \cw{interpret_move()} and \cw{execute_move()}, and had separate functions to encode and decode a game state in string form, then those functions would not be used during normal play; so they could have been completely broken, and you'd never know it until you tried to save the game \dash which would have meant you'd have to test game saving \e{extensively} and make sure to test every possible type of game state. As an added bonus, doing it the way I did leads to smaller save files.) There is one exception to this, which is the string encoding of the \c{game_ui}. Most games do not store anything permanent in the \c{game_ui}, and hence do not need to put anything in its encode and decode functions; but if there is anything in there, you do need to test game loading and saving to ensure those functions work properly. It's also worth testing undo and redo of all operations, to ensure that the redraw and the animations (if any) work properly. Failing to animate undo properly seems to be a common error. Other than that, just use your common sense. \versionid Simon Tatham's Portable Puzzle Collection, version 20170606.272beef puzzles-20170606.272beef/noicon.rc0000644000175000017500000000060613115373615015506 0ustar simonsimon/* Puzzle resource file without an icon, used in the absence of icons/foo.rc */ #include "puzzles.rc2" /* XXX this probably isn't the right test, but it'll do. */ #ifdef MINGW32_FIX /* XXX The MinGW toolchain (specifically, windres) doesn't like a resource * file with no resources. Give it a dummy one. * This can go if/when VERSIONINFO resources are added. */ 200 RCDATA { 0 } #endif puzzles-20170606.272beef/untangle.R0000644000175000017500000000070713115373615015635 0ustar simonsimon# -*- makefile -*- UNTANGLE_EXTRA = tree234 untangle : [X] GTK COMMON untangle UNTANGLE_EXTRA untangle-icon|no-icon untangle : [G] WINDOWS COMMON untangle UNTANGLE_EXTRA untangle.res|noicon.res ALL += untangle[COMBINED] UNTANGLE_EXTRA !begin am gtk GAMES += untangle !end !begin >list.c A(untangle) \ !end !begin >gamedesc.txt untangle:untangle.exe:Untangle:Planar graph layout puzzle:Reposition the points so that the lines do not cross. !end puzzles-20170606.272beef/unruly.R0000644000175000017500000000073413115373615015356 0ustar simonsimon# -*- makefile -*- unruly : [X] GTK COMMON unruly unruly-icon|no-icon unruly : [G] WINDOWS COMMON unruly unruly.res|noicon.res unrulysolver : [U] unruly[STANDALONE_SOLVER] STANDALONE unrulysolver : [C] unruly[STANDALONE_SOLVER] STANDALONE ALL += unruly[COMBINED] !begin am gtk GAMES += unruly !end !begin >list.c A(unruly) \ !end !begin >gamedesc.txt unruly:unruly.exe:Unruly:Black and white grid puzzle:Fill in the black and white grid to avoid runs of three. !end puzzles-20170606.272beef/unequal.R0000644000175000017500000000143613115373615015472 0ustar simonsimon# -*- makefile -*- UNEQUAL_EXTRA = latin tree234 maxflow unequal : [X] GTK COMMON unequal UNEQUAL_EXTRA unequal-icon|no-icon unequal : [G] WINDOWS COMMON unequal UNEQUAL_EXTRA unequal.res|noicon.res unequalsolver : [U] unequal[STANDALONE_SOLVER] latin[STANDALONE_SOLVER] tree234 maxflow STANDALONE unequalsolver : [C] unequal[STANDALONE_SOLVER] latin[STANDALONE_SOLVER] tree234 maxflow STANDALONE latincheck : [U] latin[STANDALONE_LATIN_TEST] tree234 maxflow STANDALONE latincheck : [C] latin[STANDALONE_LATIN_TEST] tree234 maxflow STANDALONE ALL += unequal[COMBINED] UNEQUAL_EXTRA !begin am gtk GAMES += unequal !end !begin >list.c A(unequal) \ !end !begin >gamedesc.txt unequal:unequal.exe:Unequal:Latin square puzzle:Complete the latin square in accordance with the > signs. !end puzzles-20170606.272beef/undead.R0000644000175000017500000000061213115373615015253 0ustar simonsimon# -*- makefile -*- undead : [X] GTK COMMON undead undead-icon|no-icon undead : [G] WINDOWS COMMON undead undead.res|noicon.res ALL += undead[COMBINED] !begin am gtk GAMES += undead !end !begin >list.c A(undead) \ !end !begin >gamedesc.txt undead:undead.exe:Undead:Monster-placing puzzle:Place ghosts, vampires and zombies so that the right numbers of them can be seen in mirrors. !end puzzles-20170606.272beef/twiddle.R0000644000175000017500000000060413115373615015450 0ustar simonsimon# -*- makefile -*- twiddle : [X] GTK COMMON twiddle twiddle-icon|no-icon twiddle : [G] WINDOWS COMMON twiddle twiddle.res|noicon.res ALL += twiddle[COMBINED] !begin am gtk GAMES += twiddle !end !begin >list.c A(twiddle) \ !end !begin >gamedesc.txt twiddle:twiddle.exe:Twiddle:Rotational sliding block puzzle:Rotate the tiles around themselves to arrange them into order. !end puzzles-20170606.272beef/tracks.R0000644000175000017500000000066113115373615015306 0ustar simonsimon# -*- makefile -*- TRACKS_EXTRA = dsf findloop tracks : [X] GTK COMMON tracks TRACKS_EXTRA tracks-icon|no-icon tracks : [G] WINDOWS COMMON tracks TRACKS_EXTRA tracks.res|noicon.res ALL += tracks[COMBINED] TRACKS_EXTRA !begin am gtk GAMES += tracks !end !begin >list.c A(tracks) \ !end !begin >gamedesc.txt tracks:tracks.exe:Tracks:Path-finding railway track puzzle:Fill in the railway track according to the clues. !end puzzles-20170606.272beef/towers.R0000644000175000017500000000127713115373615015346 0ustar simonsimon# -*- makefile -*- TOWERS_LATIN_EXTRA = tree234 maxflow TOWERS_EXTRA = latin TOWERS_LATIN_EXTRA towers : [X] GTK COMMON towers TOWERS_EXTRA towers-icon|no-icon towers : [G] WINDOWS COMMON towers TOWERS_EXTRA towers.res|noicon.res towerssolver : [U] towers[STANDALONE_SOLVER] latin[STANDALONE_SOLVER] TOWERS_LATIN_EXTRA STANDALONE towerssolver : [C] towers[STANDALONE_SOLVER] latin[STANDALONE_SOLVER] TOWERS_LATIN_EXTRA STANDALONE ALL += towers[COMBINED] TOWERS_EXTRA !begin am gtk GAMES += towers !end !begin >list.c A(towers) \ !end !begin >gamedesc.txt towers:towers.exe:Towers:Tower-placing Latin square puzzle:Complete the latin square of towers in accordance with the clues. !end puzzles-20170606.272beef/tents.R0000644000175000017500000000101513115373615015146 0ustar simonsimon# -*- makefile -*- TENTS_EXTRA = maxflow dsf tents : [X] GTK COMMON tents TENTS_EXTRA tents-icon|no-icon tents : [G] WINDOWS COMMON tents TENTS_EXTRA tents.res|noicon.res ALL += tents[COMBINED] TENTS_EXTRA tentssolver : [U] tents[STANDALONE_SOLVER] TENTS_EXTRA STANDALONE tentssolver : [C] tents[STANDALONE_SOLVER] TENTS_EXTRA STANDALONE !begin am gtk GAMES += tents !end !begin >list.c A(tents) \ !end !begin >gamedesc.txt tents:tents.exe:Tents:Tent-placing puzzle:Place a tent next to each tree. !end puzzles-20170606.272beef/solo.R0000644000175000017500000000106513115373615014772 0ustar simonsimon# -*- makefile -*- SOLO_EXTRA = divvy dsf solo : [X] GTK COMMON solo SOLO_EXTRA solo-icon|no-icon solo : [G] WINDOWS COMMON solo SOLO_EXTRA solo.res|noicon.res solosolver : [U] solo[STANDALONE_SOLVER] SOLO_EXTRA STANDALONE solosolver : [C] solo[STANDALONE_SOLVER] SOLO_EXTRA STANDALONE ALL += solo[COMBINED] SOLO_EXTRA !begin am gtk GAMES += solo !end !begin >list.c A(solo) \ !end !begin >gamedesc.txt solo:solo.exe:Solo:Number placement puzzle:Fill in the grid so that each row, column and square block contains one of every digit. !end puzzles-20170606.272beef/slant.R0000644000175000017500000000104413115373615015134 0ustar simonsimon# -*- makefile -*- SLANT_EXTRA = dsf findloop slant : [X] GTK COMMON slant SLANT_EXTRA slant-icon|no-icon slant : [G] WINDOWS COMMON slant SLANT_EXTRA slant.res|noicon.res slantsolver : [U] slant[STANDALONE_SOLVER] SLANT_EXTRA STANDALONE slantsolver : [C] slant[STANDALONE_SOLVER] SLANT_EXTRA STANDALONE ALL += slant[COMBINED] SLANT_EXTRA !begin am gtk GAMES += slant !end !begin >list.c A(slant) \ !end !begin >gamedesc.txt slant:slant.exe:Slant:Maze-drawing puzzle:Draw a maze of slanting lines that matches the clues. !end puzzles-20170606.272beef/sixteen.R0000644000175000017500000000057213115373615015477 0ustar simonsimon# -*- makefile -*- sixteen : [X] GTK COMMON sixteen sixteen-icon|no-icon sixteen : [G] WINDOWS COMMON sixteen sixteen.res|noicon.res ALL += sixteen[COMBINED] !begin am gtk GAMES += sixteen !end !begin >list.c A(sixteen) \ !end !begin >gamedesc.txt sixteen:sixteen.exe:Sixteen:Toroidal sliding block puzzle:Slide a row at a time to arrange the tiles into order. !end puzzles-20170606.272beef/singles.R0000644000175000017500000000111513115373615015456 0ustar simonsimon# -*- makefile -*- SINGLES_EXTRA = dsf latin maxflow tree234 singles : [X] GTK COMMON singles SINGLES_EXTRA singles-icon|no-icon singles : [G] WINDOWS COMMON singles SINGLES_EXTRA singles.res|noicon.res ALL += singles[COMBINED] SINGLES_EXTRA singlessolver : [U] singles[STANDALONE_SOLVER] SINGLES_EXTRA STANDALONE singlessolver : [C] singles[STANDALONE_SOLVER] SINGLES_EXTRA STANDALONE !begin am gtk GAMES += singles !end !begin >list.c A(singles) \ !end !begin >gamedesc.txt singles:singles.exe:Singles:Number-removing puzzle:Black out the right set of duplicate numbers. !end puzzles-20170606.272beef/signpost.R0000644000175000017500000000113513115373615015662 0ustar simonsimon# -*- makefile -*- SIGNPOST_EXTRA = dsf signpost : [X] GTK COMMON signpost SIGNPOST_EXTRA signpost-icon|no-icon signpost : [G] WINDOWS COMMON signpost SIGNPOST_EXTRA signpost.res|noicon.res signpostsolver : [U] signpost[STANDALONE_SOLVER] SIGNPOST_EXTRA STANDALONE m.lib signpostsolver : [C] signpost[STANDALONE_SOLVER] SIGNPOST_EXTRA STANDALONE ALL += signpost[COMBINED] SIGNPOST_EXTRA !begin am gtk GAMES += signpost !end !begin >list.c A(signpost) \ !end !begin >gamedesc.txt signpost:signpost.exe:Signpost:Square-connecting puzzle:Connect the squares into a path following the arrows. !end puzzles-20170606.272beef/samegame.R0000644000175000017500000000061513115373615015575 0ustar simonsimon# -*- makefile -*- samegame : [X] GTK COMMON samegame samegame-icon|no-icon samegame : [G] WINDOWS COMMON samegame samegame.res|noicon.res ALL += samegame[COMBINED] !begin am gtk GAMES += samegame !end !begin >list.c A(samegame) \ !end !begin >gamedesc.txt samegame:samegame.exe:Same Game:Block-clearing puzzle:Clear the grid by removing touching groups of the same colour squares. !end puzzles-20170606.272beef/rect.R0000644000175000017500000000054013115373615014750 0ustar simonsimon# -*- makefile -*- rect : [X] GTK COMMON rect rect-icon|no-icon rect : [G] WINDOWS COMMON rect rect.res|noicon.res ALL += rect[COMBINED] !begin am gtk GAMES += rect !end !begin >list.c A(rect) \ !end !begin >gamedesc.txt rect:rect.exe:Rectangles:Rectangles puzzle:Divide the grid into rectangles with areas equal to the numbers. !end puzzles-20170606.272beef/range.R0000644000175000017500000000065313115373615015114 0ustar simonsimon# -*- makefile -*- RANGE_EXTRA = dsf range : [X] GTK COMMON range RANGE_EXTRA range-icon|no-icon range : [G] WINDOWS COMMON range RANGE_EXTRA range.res|noicon.res ALL += range[COMBINED] RANGE_EXTRA !begin am gtk GAMES += range !end !begin >list.c A(range) \ !end !begin >gamedesc.txt range:range.exe:Range:Visible-distance puzzle:Place black squares to limit the visible distance from each numbered cell. !end puzzles-20170606.272beef/pegs.R0000644000175000017500000000060413115373615014752 0ustar simonsimon# -*- makefile -*- PEGS_EXTRA = tree234 pegs : [X] GTK COMMON pegs PEGS_EXTRA pegs-icon|no-icon pegs : [G] WINDOWS COMMON pegs PEGS_EXTRA pegs.res|noicon.res ALL += pegs[COMBINED] PEGS_EXTRA !begin am gtk GAMES += pegs !end !begin >list.c A(pegs) \ !end !begin >gamedesc.txt pegs:pegs.exe:Pegs:Peg solitaire puzzle:Jump pegs over each other to remove all but one. !end puzzles-20170606.272beef/pearl.R0000644000175000017500000000113413115373615015116 0ustar simonsimon# -*- makefile -*- PEARL_EXTRA = dsf tree234 grid penrose loopgen tdq pearl : [X] GTK COMMON pearl PEARL_EXTRA pearl-icon|no-icon pearl : [G] WINDOWS COMMON pearl PEARL_EXTRA pearl.res? pearlbench : [U] pearl[STANDALONE_SOLVER] PEARL_EXTRA STANDALONE m.lib pearlbench : [C] pearl[STANDALONE_SOLVER] PEARL_EXTRA STANDALONE ALL += pearl[COMBINED] PEARL_EXTRA !begin am gtk GAMES += pearl !end !begin >list.c A(pearl) \ !end !begin >gamedesc.txt pearl:pearl.exe:Pearl:Loop-drawing puzzle:Draw a single closed loop, given clues about corner and straight squares. !end puzzles-20170606.272beef/pattern.R0000644000175000017500000000121013115373615015463 0ustar simonsimon# -*- makefile -*- pattern : [X] GTK COMMON pattern pattern-icon|no-icon pattern : [G] WINDOWS COMMON pattern pattern.res|noicon.res patternsolver : [U] pattern[STANDALONE_SOLVER] STANDALONE patternsolver : [C] pattern[STANDALONE_SOLVER] STANDALONE patternpicture : [U] pattern[STANDALONE_PICTURE_GENERATOR] STANDALONE patternpicture : [C] pattern[STANDALONE_PICTURE_GENERATOR] STANDALONE ALL += pattern[COMBINED] !begin am gtk GAMES += pattern !end !begin >list.c A(pattern) \ !end !begin >gamedesc.txt pattern:pattern.exe:Pattern:Pattern puzzle:Fill in the pattern in the grid, given only the lengths of runs of black squares. !end puzzles-20170606.272beef/palisade.R0000644000175000017500000000073013115373615015576 0ustar simonsimon# -*- makefile -*- PALISADE_EXTRA = divvy dsf palisade : [X] GTK COMMON palisade PALISADE_EXTRA palisade-icon|no-icon palisade : [G] WINDOWS COMMON palisade PALISADE_EXTRA palisade.res|noicon.res ALL += palisade[COMBINED] PALISADE_EXTRA !begin am gtk GAMES += palisade !end !begin >list.c A(palisade) \ !end !begin >gamedesc.txt palisade:palisade.exe:Palisade:Grid-division puzzle:Divide the grid into equal-sized areas in accordance with the clues. !end puzzles-20170606.272beef/nullgame.R0000644000175000017500000000116313115373615015621 0ustar simonsimon# -*- makefile -*- # The `nullgame' source file is a largely blank one, which contains # all the correct function definitions to compile and link, but # which defines the null game in which nothing is ever drawn and # there are no valid moves. Its main purpose is to act as a # template for writing new game definition source files. I include # it in the Makefile because it will be worse than useless if it # ever fails to compile, so it's important that it should actually # be built on a regular basis. nullgame : [X] GTK COMMON nullgame nullgame-icon|no-icon nullgame : [G] WINDOWS COMMON nullgame nullgame.res|noicon.res puzzles-20170606.272beef/netslide.R0000644000175000017500000000070713115373615015627 0ustar simonsimon# -*- makefile -*- NETSLIDE_EXTRA = tree234 netslide : [X] GTK COMMON netslide NETSLIDE_EXTRA netslide-icon|no-icon netslide : [G] WINDOWS COMMON netslide NETSLIDE_EXTRA netslide.res|noicon.res ALL += netslide[COMBINED] NETSLIDE_EXTRA !begin am gtk GAMES += netslide !end !begin >list.c A(netslide) \ !end !begin >gamedesc.txt netslide:netslide.exe:Netslide:Toroidal sliding network puzzle:Slide a row at a time to reassemble the network. !end puzzles-20170606.272beef/net.R0000644000175000017500000000100413115373615014575 0ustar simonsimon# -*- makefile -*- NET_EXTRA = tree234 dsf findloop net : [X] GTK COMMON net NET_EXTRA net-icon|no-icon # The Windows Net shouldn't be called `net.exe' since Windows # already has a reasonably important utility program by that name! netgame : [G] WINDOWS COMMON net NET_EXTRA net.res|noicon.res ALL += net[COMBINED] NET_EXTRA !begin am gtk GAMES += net !end !begin >list.c A(net) \ !end !begin >gamedesc.txt net:netgame.exe:Net:Network jigsaw puzzle:Rotate each tile to reassemble the network. !end puzzles-20170606.272beef/mines.R0000644000175000017500000000104513115373615015127 0ustar simonsimon# -*- makefile -*- MINES_EXTRA = tree234 mines : [X] GTK COMMON mines MINES_EXTRA mines-icon|no-icon mines : [G] WINDOWS COMMON mines MINES_EXTRA mines.res|noicon.res mineobfusc : [U] mines[STANDALONE_OBFUSCATOR] MINES_EXTRA STANDALONE mineobfusc : [C] mines[STANDALONE_OBFUSCATOR] MINES_EXTRA STANDALONE ALL += mines[COMBINED] MINES_EXTRA !begin am gtk GAMES += mines !end !begin >list.c A(mines) \ !end !begin >gamedesc.txt mines:mines.exe:Mines:Mine-finding puzzle:Find all the mines without treading on any of them. !end puzzles-20170606.272beef/map.R0000644000175000017500000000101313115373615014564 0ustar simonsimon# -*- makefile -*- MAP_EXTRA = dsf map : [X] GTK COMMON map MAP_EXTRA map-icon|no-icon map : [G] WINDOWS COMMON map MAP_EXTRA map.res|noicon.res mapsolver : [U] map[STANDALONE_SOLVER] MAP_EXTRA STANDALONE m.lib mapsolver : [C] map[STANDALONE_SOLVER] MAP_EXTRA STANDALONE ALL += map[COMBINED] MAP_EXTRA !begin am gtk GAMES += map !end !begin >list.c A(map) \ !end !begin >gamedesc.txt map:map.exe:Map:Map-colouring puzzle:Colour the map so that adjacent regions are never the same colour. !end puzzles-20170606.272beef/magnets.R0000644000175000017500000000115113115373615015450 0ustar simonsimon# -*- makefile -*- MAGNETS_EXTRA = laydomino magnets : [X] GTK COMMON magnets MAGNETS_EXTRA magnets-icon|no-icon magnets : [G] WINDOWS COMMON magnets MAGNETS_EXTRA magnets.res|noicon.res magnetssolver : [U] magnets[STANDALONE_SOLVER] MAGNETS_EXTRA STANDALONE m.lib magnetssolver : [C] magnets[STANDALONE_SOLVER] MAGNETS_EXTRA STANDALONE ALL += magnets[COMBINED] MAGNETS_EXTRA !begin am gtk GAMES += magnets !end !begin >list.c A(magnets) \ !end !begin >gamedesc.txt magnets:magnets.exe:Magnets:Magnet-placing puzzle:Place magnets to satisfy the clues and avoid like poles touching. !end puzzles-20170606.272beef/loopy.R0000644000175000017500000000147413115373615015164 0ustar simonsimon# -*- makefile -*- LOOPY_EXTRA = tree234 dsf grid penrose loopgen loopy : [X] GTK COMMON loopy LOOPY_EXTRA loopy-icon|no-icon loopy : [G] WINDOWS COMMON loopy LOOPY_EXTRA loopy.res|noicon.res loopysolver : [U] loopy[STANDALONE_SOLVER] LOOPY_EXTRA STANDALONE m.lib loopysolver : [C] loopy[STANDALONE_SOLVER] LOOPY_EXTRA STANDALONE #penrose : [U] penrose[TEST_PENROSE] STANDALONE m.lib #penrose : [C] penrose[TEST_PENROSE] STANDALONE #test-basis : [U] penrose[TEST_VECTORS] tree234 STANDALONE m.lib #test-basis : [C] penrose[TEST_VECTORS] tree234 STANDALONE ALL += loopy[COMBINED] LOOPY_EXTRA !begin am gtk GAMES += loopy !end !begin >list.c A(loopy) \ !end !begin >gamedesc.txt loopy:loopy.exe:Loopy:Loop-drawing puzzle:Draw a single closed loop, given clues about number of adjacent edges. !end puzzles-20170606.272beef/lightup.R0000644000175000017500000000107313115373615015471 0ustar simonsimon# -*- makefile -*- LIGHTUP_EXTRA = combi lightup : [X] GTK COMMON lightup LIGHTUP_EXTRA lightup-icon|no-icon lightup : [G] WINDOWS COMMON lightup LIGHTUP_EXTRA lightup.res|noicon.res lightupsolver : [U] lightup[STANDALONE_SOLVER] LIGHTUP_EXTRA STANDALONE lightupsolver : [C] lightup[STANDALONE_SOLVER] LIGHTUP_EXTRA STANDALONE ALL += lightup[COMBINED] LIGHTUP_EXTRA !begin am gtk GAMES += lightup !end !begin >list.c A(lightup) \ !end !begin >gamedesc.txt lightup:lightup.exe:Light Up:Light-bulb placing puzzle:Place bulbs to light up all the squares. !end puzzles-20170606.272beef/keen.R0000644000175000017500000000122113115373615014732 0ustar simonsimon# -*- makefile -*- KEEN_LATIN_EXTRA = tree234 maxflow dsf KEEN_EXTRA = latin KEEN_LATIN_EXTRA keen : [X] GTK COMMON keen KEEN_EXTRA keen-icon|no-icon keen : [G] WINDOWS COMMON keen KEEN_EXTRA keen.res|noicon.res keensolver : [U] keen[STANDALONE_SOLVER] latin[STANDALONE_SOLVER] KEEN_LATIN_EXTRA STANDALONE keensolver : [C] keen[STANDALONE_SOLVER] latin[STANDALONE_SOLVER] KEEN_LATIN_EXTRA STANDALONE ALL += keen[COMBINED] KEEN_EXTRA !begin am gtk GAMES += keen !end !begin >list.c A(keen) \ !end !begin >gamedesc.txt keen:keen.exe:Keen:Arithmetic Latin square puzzle:Complete the latin square in accordance with the arithmetic clues. !end puzzles-20170606.272beef/inertia.R0000644000175000017500000000056713115373615015457 0ustar simonsimon# -*- makefile -*- inertia : [X] GTK COMMON inertia inertia-icon|no-icon inertia : [G] WINDOWS COMMON inertia inertia.res|noicon.res ALL += inertia[COMBINED] !begin am gtk GAMES += inertia !end !begin >list.c A(inertia) \ !end !begin >gamedesc.txt inertia:inertia.exe:Inertia:Gem-collecting puzzle:Collect all the gems without running into any of the mines. !end puzzles-20170606.272beef/guess.R0000644000175000017500000000052613115373615015145 0ustar simonsimon# -*- makefile -*- guess : [X] GTK COMMON guess guess-icon|no-icon guess : [G] WINDOWS COMMON guess guess.res|noicon.res ALL += guess[COMBINED] !begin am gtk GAMES += guess !end !begin >list.c A(guess) \ !end !begin >gamedesc.txt guess:guess.exe:Guess:Combination-guessing puzzle:Guess the hidden combination of colours. !end puzzles-20170606.272beef/galaxies.R0000644000175000017500000000147413115373615015617 0ustar simonsimon# -*- makefile -*- GALAXIES_EXTRA = dsf galaxies : [X] GTK COMMON galaxies GALAXIES_EXTRA galaxies-icon|no-icon galaxies : [G] WINDOWS COMMON galaxies GALAXIES_EXTRA galaxies.res|noicon.res galaxiessolver : [U] galaxies[STANDALONE_SOLVER] GALAXIES_EXTRA STANDALONE m.lib galaxiessolver : [C] galaxies[STANDALONE_SOLVER] GALAXIES_EXTRA STANDALONE galaxiespicture : [U] galaxies[STANDALONE_PICTURE_GENERATOR] GALAXIES_EXTRA STANDALONE + m.lib galaxiespicture : [C] galaxies[STANDALONE_PICTURE_GENERATOR] GALAXIES_EXTRA STANDALONE ALL += galaxies[COMBINED] GALAXIES_EXTRA !begin am gtk GAMES += galaxies !end !begin >list.c A(galaxies) \ !end !begin >gamedesc.txt galaxies:galaxies.exe:Galaxies:Symmetric polyomino puzzle:Divide the grid into rotationally symmetric regions each centred on a dot. !end puzzles-20170606.272beef/flood.R0000644000175000017500000000055113115373615015120 0ustar simonsimon# -*- makefile -*- flood : [X] GTK COMMON flood flood-icon|no-icon flood : [G] WINDOWS COMMON flood flood.res|noicon.res ALL += flood[COMBINED] !begin am gtk GAMES += flood !end !begin >list.c A(flood) \ !end !begin >gamedesc.txt flood:flood.exe:Flood:Flood-filling puzzle:Turn the grid the same colour in as few flood fills as possible. !end puzzles-20170606.272beef/flip.R0000644000175000017500000000061113115373615014744 0ustar simonsimon# -*- makefile -*- FLIP_EXTRA = tree234 flip : [X] GTK COMMON flip FLIP_EXTRA flip-icon|no-icon flip : [G] WINDOWS COMMON flip FLIP_EXTRA flip.res|noicon.res ALL += flip[COMBINED] FLIP_EXTRA !begin am gtk GAMES += flip !end !begin >list.c A(flip) \ !end !begin >gamedesc.txt flip:flip.exe:Flip:Tile inversion puzzle:Flip groups of squares to light them all up at once. !end puzzles-20170606.272beef/filling.R0000644000175000017500000000107613115373615015444 0ustar simonsimon# -*- makefile -*- FILLING_EXTRA = dsf fillingsolver : [U] filling[STANDALONE_SOLVER] FILLING_EXTRA STANDALONE fillingsolver : [C] filling[STANDALONE_SOLVER] FILLING_EXTRA STANDALONE filling : [X] GTK COMMON filling FILLING_EXTRA filling-icon|no-icon filling : [G] WINDOWS COMMON filling FILLING_EXTRA filling.res|noicon.res ALL += filling[COMBINED] FILLING_EXTRA !begin am gtk GAMES += filling !end !begin >list.c A(filling) \ !end !begin >gamedesc.txt filling:filling.exe:Filling:Polyomino puzzle:Mark every square with the area of its containing region. !end puzzles-20170606.272beef/fifteen.R0000644000175000017500000000075013115373615015436 0ustar simonsimon# -*- makefile -*- fifteen : [X] GTK COMMON fifteen fifteen-icon|no-icon fifteen : [G] WINDOWS COMMON fifteen fifteen.res|noicon.res fifteensolver : [U] fifteen[STANDALONE_SOLVER] STANDALONE fifteensolver : [C] fifteen[STANDALONE_SOLVER] STANDALONE ALL += fifteen[COMBINED] !begin am gtk GAMES += fifteen !end !begin >list.c A(fifteen) \ !end !begin >gamedesc.txt fifteen:fifteen.exe:Fifteen:Sliding block puzzle:Slide the tiles around to arrange them into order. !end puzzles-20170606.272beef/dominosa.R0000644000175000017500000000067513115373615015635 0ustar simonsimon# -*- makefile -*- DOMINOSA_EXTRA = laydomino dominosa : [X] GTK COMMON dominosa DOMINOSA_EXTRA dominosa-icon|no-icon dominosa : [G] WINDOWS COMMON dominosa DOMINOSA_EXTRA dominosa.res|noicon.res ALL += dominosa[COMBINED] DOMINOSA_EXTRA !begin am gtk GAMES += dominosa !end !begin >list.c A(dominosa) \ !end !begin >gamedesc.txt dominosa:dominosa.exe:Dominosa:Domino tiling puzzle:Tile the rectangle with a full set of dominoes. !end puzzles-20170606.272beef/cube.R0000644000175000017500000000052713115373615014736 0ustar simonsimon# -*- makefile -*- cube : [X] GTK COMMON cube cube-icon|no-icon cube : [G] WINDOWS COMMON cube cube.res|noicon.res ALL += cube[COMBINED] !begin am gtk GAMES += cube !end !begin >list.c A(cube) \ !end !begin >gamedesc.txt cube:cube.exe:Cube:Rolling cube puzzle:Pick up all the blue squares by rolling the cube over them. !end puzzles-20170606.272beef/bridges.R0000644000175000017500000000066613115373615015443 0ustar simonsimon# -*- makefile -*- BRIDGES_EXTRA = dsf findloop bridges : [X] GTK COMMON bridges BRIDGES_EXTRA bridges-icon|no-icon bridges : [G] WINDOWS COMMON bridges BRIDGES_EXTRA bridges.res|noicon.res ALL += bridges[COMBINED] BRIDGES_EXTRA !begin am gtk GAMES += bridges !end !begin >list.c A(bridges) \ !end !begin >gamedesc.txt bridges:bridges.exe:Bridges:Bridge-placing puzzle:Connect all the islands with a network of bridges. !end puzzles-20170606.272beef/blackbox.R0000644000175000017500000000060713115373615015604 0ustar simonsimon# -*- makefile -*- blackbox : [X] GTK COMMON blackbox blackbox-icon|no-icon blackbox : [G] WINDOWS COMMON blackbox blackbox.res|noicon.res ALL += blackbox[COMBINED] !begin am gtk GAMES += blackbox !end !begin >list.c A(blackbox) \ !end !begin >gamedesc.txt blackbox:blackbox.exe:Black Box:Ball-finding puzzle:Find the hidden balls in the box by bouncing laser beams off them. !end puzzles-20170606.272beef/version.h0000644000175000017500000000012113115373615015521 0ustar simonsimon/* Generated by automated build script */ #define VER "Version 20170606.272beef" puzzles-20170606.272beef/tree234.h0000644000175000017500000001607213115373615015240 0ustar simonsimon/* * tree234.h: header defining functions in tree234.c. * * This file is copyright 1999-2001 Simon Tatham. * * 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 SIMON TATHAM BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #ifndef TREE234_H #define TREE234_H /* * This typedef is opaque outside tree234.c itself. */ typedef struct tree234_Tag tree234; typedef int (*cmpfn234)(void *, void *); typedef void *(*copyfn234)(void *state, void *element); /* * Create a 2-3-4 tree. If `cmp' is NULL, the tree is unsorted, and * lookups by key will fail: you can only look things up by numeric * index, and you have to use addpos234() and delpos234(). */ tree234 *newtree234(cmpfn234 cmp); /* * Free a 2-3-4 tree (not including freeing the elements). */ void freetree234(tree234 *t); /* * Add an element e to a sorted 2-3-4 tree t. Returns e on success, * or if an existing element compares equal, returns that. */ void *add234(tree234 *t, void *e); /* * Add an element e to an unsorted 2-3-4 tree t. Returns e on * success, NULL on failure. (Failure should only occur if the * index is out of range or the tree is sorted.) * * Index range can be from 0 to the tree's current element count, * inclusive. */ void *addpos234(tree234 *t, void *e, int index); /* * Look up the element at a given numeric index in a 2-3-4 tree. * Returns NULL if the index is out of range. * * One obvious use for this function is in iterating over the whole * of a tree (sorted or unsorted): * * for (i = 0; (p = index234(tree, i)) != NULL; i++) consume(p); * * or * * int maxcount = count234(tree); * for (i = 0; i < maxcount; i++) { * p = index234(tree, i); * assert(p != NULL); * consume(p); * } */ void *index234(tree234 *t, int index); /* * Find an element e in a sorted 2-3-4 tree t. Returns NULL if not * found. e is always passed as the first argument to cmp, so cmp * can be an asymmetric function if desired. cmp can also be passed * as NULL, in which case the compare function from the tree proper * will be used. * * Three of these functions are special cases of findrelpos234. The * non-`pos' variants lack the `index' parameter: if the parameter * is present and non-NULL, it must point to an integer variable * which will be filled with the numeric index of the returned * element. * * The non-`rel' variants lack the `relation' parameter. This * parameter allows you to specify what relation the element you * provide has to the element you're looking for. This parameter * can be: * * REL234_EQ - find only an element that compares equal to e * REL234_LT - find the greatest element that compares < e * REL234_LE - find the greatest element that compares <= e * REL234_GT - find the smallest element that compares > e * REL234_GE - find the smallest element that compares >= e * * Non-`rel' variants assume REL234_EQ. * * If `rel' is REL234_GT or REL234_LT, the `e' parameter may be * NULL. In this case, REL234_GT will return the smallest element * in the tree, and REL234_LT will return the greatest. This gives * an alternative means of iterating over a sorted tree, instead of * using index234: * * // to loop forwards * for (p = NULL; (p = findrel234(tree, p, NULL, REL234_GT)) != NULL ;) * consume(p); * * // to loop backwards * for (p = NULL; (p = findrel234(tree, p, NULL, REL234_LT)) != NULL ;) * consume(p); */ enum { REL234_EQ, REL234_LT, REL234_LE, REL234_GT, REL234_GE }; void *find234(tree234 *t, void *e, cmpfn234 cmp); void *findrel234(tree234 *t, void *e, cmpfn234 cmp, int relation); void *findpos234(tree234 *t, void *e, cmpfn234 cmp, int *index); void *findrelpos234(tree234 *t, void *e, cmpfn234 cmp, int relation, int *index); /* * Delete an element e in a 2-3-4 tree. Does not free the element, * merely removes all links to it from the tree nodes. * * delpos234 deletes the element at a particular tree index: it * works on both sorted and unsorted trees. * * del234 deletes the element passed to it, so it only works on * sorted trees. (It's equivalent to using findpos234 to determine * the index of an element, and then passing that index to * delpos234.) * * Both functions return a pointer to the element they delete, for * the user to free or pass on elsewhere or whatever. If the index * is out of range (delpos234) or the element is already not in the * tree (del234) then they return NULL. */ void *del234(tree234 *t, void *e); void *delpos234(tree234 *t, int index); /* * Return the total element count of a tree234. */ int count234(tree234 *t); /* * Split a tree234 into two valid tree234s. * * splitpos234 splits at a given index. If `before' is TRUE, the * items at and after that index are left in t and the ones before * are returned; if `before' is FALSE, the items before that index * are left in t and the rest are returned. * * split234 splits at a given key. You can pass any of the * relations used with findrel234, except for REL234_EQ. The items * in the tree that satisfy the relation are returned; the * remainder are left. */ tree234 *splitpos234(tree234 *t, int index, int before); tree234 *split234(tree234 *t, void *e, cmpfn234 cmp, int rel); /* * Join two tree234s together into a single one. * * All the elements in t1 are placed to the left of all the * elements in t2. If the trees are sorted, there will be a test to * ensure that this satisfies the ordering criterion, and NULL will * be returned otherwise. If the trees are unsorted, there is no * restriction on the use of join234. * * The tree returned is t1 (join234) or t2 (join234r), if the * operation is successful. */ tree234 *join234(tree234 *t1, tree234 *t2); tree234 *join234r(tree234 *t1, tree234 *t2); /* * Make a complete copy of a tree234. Element pointers will be * reused unless copyfn is non-NULL, in which case it will be used * to copy each element. (copyfn takes two `void *' parameters; the * first is private state and the second is the element. A simple * copy routine probably won't need private state.) */ tree234 *copytree234(tree234 *t, copyfn234 copyfn, void *copyfnstate); #endif /* TREE234_H */ puzzles-20170606.272beef/resource.h0000644000175000017500000000100613115373615015666 0ustar simonsimon #define IDR_MENUBAR1 101 #define ID_GAME 40005 #define ID_TYPE 40006 #define IDS_CAP_GAME 40105 #define IDS_CAP_TYPE 40106 #define IDD_ABOUT 2000 #define IDC_ABOUT_CAPTION 2001 #define IDC_ABOUT_LINE 2002 #define IDC_ABOUT_GAME 2003 #define IDC_ABOUT_VERSION 2004 #define IDD_CONFIG 2100 #define IDC_CONFIG_CAPTION 2101 #define IDC_CONFIG_LINE 2102 #define IDR_PADTOOLBAR 4000 puzzles-20170606.272beef/puzzles.h0000644000175000017500000006246613115373615015574 0ustar simonsimon/* * puzzles.h: header file for my puzzle collection */ #ifndef PUZZLES_PUZZLES_H #define PUZZLES_PUZZLES_H #include /* for FILE */ #include /* for size_t */ #include /* for UINT_MAX */ #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif #define PI 3.141592653589793238462643383279502884197169399 #define lenof(array) ( sizeof(array) / sizeof(*(array)) ) #define STR_INT(x) #x #define STR(x) STR_INT(x) /* NB not perfect because they evaluate arguments multiple times. */ #ifndef max #define max(x,y) ( (x)>(y) ? (x) : (y) ) #endif /* max */ #ifndef min #define min(x,y) ( (x)<(y) ? (x) : (y) ) #endif /* min */ enum { LEFT_BUTTON = 0x0200, MIDDLE_BUTTON, RIGHT_BUTTON, LEFT_DRAG, MIDDLE_DRAG, RIGHT_DRAG, LEFT_RELEASE, MIDDLE_RELEASE, RIGHT_RELEASE, CURSOR_UP, CURSOR_DOWN, CURSOR_LEFT, CURSOR_RIGHT, CURSOR_SELECT, CURSOR_SELECT2, /* made smaller because of 'limited range of datatype' errors. */ MOD_CTRL = 0x1000, MOD_SHFT = 0x2000, MOD_NUM_KEYPAD = 0x4000, MOD_MASK = 0x7000 /* mask for all modifiers */ }; #define IS_MOUSE_DOWN(m) ( (unsigned)((m) - LEFT_BUTTON) <= \ (unsigned)(RIGHT_BUTTON - LEFT_BUTTON)) #define IS_MOUSE_DRAG(m) ( (unsigned)((m) - LEFT_DRAG) <= \ (unsigned)(RIGHT_DRAG - LEFT_DRAG)) #define IS_MOUSE_RELEASE(m) ( (unsigned)((m) - LEFT_RELEASE) <= \ (unsigned)(RIGHT_RELEASE - LEFT_RELEASE)) #define IS_CURSOR_MOVE(m) ( (m) == CURSOR_UP || (m) == CURSOR_DOWN || \ (m) == CURSOR_RIGHT || (m) == CURSOR_LEFT ) #define IS_CURSOR_SELECT(m) ( (m) == CURSOR_SELECT || (m) == CURSOR_SELECT2) /* * Flags in the back end's `flags' word. */ /* Bit flags indicating mouse button priorities */ #define BUTTON_BEATS(x,y) ( 1 << (((x)-LEFT_BUTTON)*3+(y)-LEFT_BUTTON) ) /* Flag indicating that Solve operations should be animated */ #define SOLVE_ANIMATES ( 1 << 9 ) /* Pocket PC: Game requires right mouse button emulation */ #define REQUIRE_RBUTTON ( 1 << 10 ) /* Pocket PC: Game requires numeric input */ #define REQUIRE_NUMPAD ( 1 << 11 ) /* end of `flags' word definitions */ #ifdef _WIN32_WCE /* Pocket PC devices have small, portrait screen that requires more vivid colours */ #define SMALL_SCREEN #define PORTRAIT_SCREEN #define VIVID_COLOURS #define STYLUS_BASED #endif #define IGNOREARG(x) ( (x) = (x) ) typedef struct frontend frontend; typedef struct config_item config_item; typedef struct midend midend; typedef struct random_state random_state; typedef struct game_params game_params; typedef struct game_state game_state; typedef struct game_ui game_ui; typedef struct game_drawstate game_drawstate; typedef struct game game; typedef struct blitter blitter; typedef struct document document; typedef struct drawing_api drawing_api; typedef struct drawing drawing; typedef struct psdata psdata; #define ALIGN_VNORMAL 0x000 #define ALIGN_VCENTRE 0x100 #define ALIGN_HLEFT 0x000 #define ALIGN_HCENTRE 0x001 #define ALIGN_HRIGHT 0x002 #define FONT_FIXED 0 #define FONT_VARIABLE 1 /* For printing colours */ #define HATCH_SLASH 1 #define HATCH_BACKSLASH 2 #define HATCH_HORIZ 3 #define HATCH_VERT 4 #define HATCH_PLUS 5 #define HATCH_X 6 /* * Structure used to pass configuration data between frontend and * game */ enum { C_STRING, C_CHOICES, C_BOOLEAN, C_END }; struct config_item { /* * `name' is never dynamically allocated. */ char *name; /* * `type' contains one of the above values. */ int type; /* * For C_STRING, `sval' is always dynamically allocated and * non-NULL. For C_BOOLEAN and C_END, `sval' is always NULL. * For C_CHOICES, `sval' is non-NULL, _not_ dynamically * allocated, and contains a set of option strings separated by * a delimiter. The delimeter is also the first character in * the string, so for example ":Foo:Bar:Baz" gives three * options `Foo', `Bar' and `Baz'. */ char *sval; /* * For C_BOOLEAN, this is TRUE or FALSE. For C_CHOICES, it * indicates the chosen index from the `sval' list. In the * above example, 0==Foo, 1==Bar and 2==Baz. */ int ival; }; /* * Structure used to communicate the presets menu from midend to * frontend. In principle, it's also used to pass the same information * from game to midend, though games that don't specify a menu * hierarchy (i.e. most of them) will use the simpler fetch_preset() * function to return an unstructured list. * * A tree of these structures always belongs to the midend, and only * the midend should ever need to free it. The front end should treat * them as read-only. */ struct preset_menu_entry { char *title; /* Exactly one of the next two fields is NULL, depending on * whether this entry is a submenu title or an actual preset */ game_params *params; struct preset_menu *submenu; /* Every preset menu entry has a number allocated by the mid-end, * so that midend_which_preset() can return a value that * identifies an entry anywhere in the menu hierarchy. The values * will be allocated reasonably densely from 1 upwards (so it's * reasonable for the front end to use them as array indices if it * needs to store GUI state per menu entry), but no other * guarantee is given about their ordering. * * Entries containing submenus have ids too - not only the actual * presets are numbered. */ int id; }; struct preset_menu { int n_entries; /* number of entries actually in use */ int entries_size; /* space currently allocated in this array */ struct preset_menu_entry *entries; }; /* For games which do want to directly return a tree of these, here * are convenience routines (in midend.c) for constructing one. These * assume that 'title' and 'encoded_params' are already dynamically * allocated by the caller; the resulting preset_menu tree takes * ownership of them. */ struct preset_menu *preset_menu_new(void); struct preset_menu *preset_menu_add_submenu(struct preset_menu *parent, char *title); void preset_menu_add_preset(struct preset_menu *menu, char *title, game_params *params); /* Helper routine front ends can use for one of the ways they might * want to organise their preset menu usage */ game_params *preset_menu_lookup_by_id(struct preset_menu *menu, int id); /* * Platform routines */ /* We can't use #ifdef DEBUG, because Cygwin defines it by default. */ #ifdef DEBUGGING #define debug(x) (debug_printf x) void debug_printf(char *fmt, ...); #else #define debug(x) #endif void fatal(char *fmt, ...); void frontend_default_colour(frontend *fe, float *output); void deactivate_timer(frontend *fe); void activate_timer(frontend *fe); void get_random_seed(void **randseed, int *randseedsize); /* * drawing.c */ drawing *drawing_new(const drawing_api *api, midend *me, void *handle); void drawing_free(drawing *dr); void draw_text(drawing *dr, int x, int y, int fonttype, int fontsize, int align, int colour, char *text); void draw_rect(drawing *dr, int x, int y, int w, int h, int colour); void draw_line(drawing *dr, int x1, int y1, int x2, int y2, int colour); void draw_polygon(drawing *dr, int *coords, int npoints, int fillcolour, int outlinecolour); void draw_circle(drawing *dr, int cx, int cy, int radius, int fillcolour, int outlinecolour); void draw_thick_line(drawing *dr, float thickness, float x1, float y1, float x2, float y2, int colour); void clip(drawing *dr, int x, int y, int w, int h); void unclip(drawing *dr); void start_draw(drawing *dr); void draw_update(drawing *dr, int x, int y, int w, int h); void end_draw(drawing *dr); char *text_fallback(drawing *dr, const char *const *strings, int nstrings); void status_bar(drawing *dr, char *text); blitter *blitter_new(drawing *dr, int w, int h); void blitter_free(drawing *dr, blitter *bl); /* save puts the portion of the current display with top-left corner * (x,y) to the blitter. load puts it back again to the specified * coords, or else wherever it was saved from * (if x = y = BLITTER_FROMSAVED). */ void blitter_save(drawing *dr, blitter *bl, int x, int y); #define BLITTER_FROMSAVED (-1) void blitter_load(drawing *dr, blitter *bl, int x, int y); void print_begin_doc(drawing *dr, int pages); void print_begin_page(drawing *dr, int number); void print_begin_puzzle(drawing *dr, float xm, float xc, float ym, float yc, int pw, int ph, float wmm, float scale); void print_end_puzzle(drawing *dr); void print_end_page(drawing *dr, int number); void print_end_doc(drawing *dr); void print_get_colour(drawing *dr, int colour, int printing_in_colour, int *hatch, float *r, float *g, float *b); int print_mono_colour(drawing *dr, int grey); /* 0==black, 1==white */ int print_grey_colour(drawing *dr, float grey); int print_hatched_colour(drawing *dr, int hatch); int print_rgb_mono_colour(drawing *dr, float r, float g, float b, int mono); int print_rgb_grey_colour(drawing *dr, float r, float g, float b, float grey); int print_rgb_hatched_colour(drawing *dr, float r, float g, float b, int hatch); void print_line_width(drawing *dr, int width); void print_line_dotted(drawing *dr, int dotted); /* * midend.c */ midend *midend_new(frontend *fe, const game *ourgame, const drawing_api *drapi, void *drhandle); void midend_free(midend *me); const game *midend_which_game(midend *me); void midend_set_params(midend *me, game_params *params); game_params *midend_get_params(midend *me); void midend_size(midend *me, int *x, int *y, int user_size); void midend_reset_tilesize(midend *me); void midend_new_game(midend *me); void midend_restart_game(midend *me); void midend_stop_anim(midend *me); int midend_process_key(midend *me, int x, int y, int button); void midend_force_redraw(midend *me); void midend_redraw(midend *me); float *midend_colours(midend *me, int *ncolours); void midend_freeze_timer(midend *me, float tprop); void midend_timer(midend *me, float tplus); struct preset_menu *midend_get_presets(midend *me, int *id_limit); int midend_which_preset(midend *me); int midend_wants_statusbar(midend *me); enum { CFG_SETTINGS, CFG_SEED, CFG_DESC, CFG_FRONTEND_SPECIFIC }; config_item *midend_get_config(midend *me, int which, char **wintitle); char *midend_set_config(midend *me, int which, config_item *cfg); char *midend_game_id(midend *me, char *id); char *midend_get_game_id(midend *me); char *midend_get_random_seed(midend *me); int midend_can_format_as_text_now(midend *me); char *midend_text_format(midend *me); char *midend_solve(midend *me); int midend_status(midend *me); int midend_can_undo(midend *me); int midend_can_redo(midend *me); void midend_supersede_game_desc(midend *me, char *desc, char *privdesc); char *midend_rewrite_statusbar(midend *me, char *text); void midend_serialise(midend *me, void (*write)(void *ctx, void *buf, int len), void *wctx); char *midend_deserialise(midend *me, int (*read)(void *ctx, void *buf, int len), void *rctx); char *identify_game(char **name, int (*read)(void *ctx, void *buf, int len), void *rctx); void midend_request_id_changes(midend *me, void (*notify)(void *), void *ctx); /* Printing functions supplied by the mid-end */ char *midend_print_puzzle(midend *me, document *doc, int with_soln); int midend_tilesize(midend *me); /* * malloc.c */ void *smalloc(size_t size); void *srealloc(void *p, size_t size); void sfree(void *p); char *dupstr(const char *s); #define snew(type) \ ( (type *) smalloc (sizeof (type)) ) #define snewn(number, type) \ ( (type *) smalloc ((number) * sizeof (type)) ) #define sresize(array, number, type) \ ( (type *) srealloc ((array), (number) * sizeof (type)) ) /* * misc.c */ void free_cfg(config_item *cfg); void obfuscate_bitmap(unsigned char *bmp, int bits, int decode); /* allocates output each time. len is always in bytes of binary data. * May assert (or just go wrong) if lengths are unchecked. */ char *bin2hex(const unsigned char *in, int inlen); unsigned char *hex2bin(const char *in, int outlen); /* Sets (and possibly dims) background from frontend default colour, * and auto-generates highlight and lowlight colours too. */ void game_mkhighlight(frontend *fe, float *ret, int background, int highlight, int lowlight); /* As above, but starts from a provided background colour rather * than the frontend default. */ void game_mkhighlight_specific(frontend *fe, float *ret, int background, int highlight, int lowlight); /* Randomly shuffles an array of items. */ void shuffle(void *array, int nelts, int eltsize, random_state *rs); /* Draw a rectangle outline, using the drawing API's draw_line. */ void draw_rect_outline(drawing *dr, int x, int y, int w, int h, int colour); /* Draw a set of rectangle corners (e.g. for a cursor display). */ void draw_rect_corners(drawing *dr, int cx, int cy, int r, int col); void move_cursor(int button, int *x, int *y, int maxw, int maxh, int wrap); /* Used in netslide.c and sixteen.c for cursor movement around edge. */ int c2pos(int w, int h, int cx, int cy); int c2diff(int w, int h, int cx, int cy, int button); void pos2c(int w, int h, int pos, int *cx, int *cy); /* Draws text with an 'outline' formed by offsetting the text * by one pixel; useful for highlighting. Outline is omitted if -1. */ void draw_text_outline(drawing *dr, int x, int y, int fonttype, int fontsize, int align, int text_colour, int outline_colour, char *text); /* Copies text left-justified with spaces. Length of string must be * less than buffer size. */ void copy_left_justified(char *buf, size_t sz, const char *str); /* * dsf.c */ int *snew_dsf(int size); void print_dsf(int *dsf, int size); /* Return the canonical element of the equivalence class containing element * val. If 'inverse' is non-NULL, this function will put into it a flag * indicating whether the canonical element is inverse to val. */ int edsf_canonify(int *dsf, int val, int *inverse); int dsf_canonify(int *dsf, int val); int dsf_size(int *dsf, int val); /* Allow the caller to specify that two elements should be in the same * equivalence class. If 'inverse' is TRUE, the elements are actually opposite * to one another in some sense. This function will fail an assertion if the * caller gives it self-contradictory data, ie if two elements are claimed to * be both opposite and non-opposite. */ void edsf_merge(int *dsf, int v1, int v2, int inverse); void dsf_merge(int *dsf, int v1, int v2); void dsf_init(int *dsf, int len); /* * tdq.c */ /* * Data structure implementing a 'to-do queue', a simple * de-duplicating to-do list mechanism. * * Specification: a tdq is a queue which can hold integers from 0 to * n-1, where n was some constant specified at tdq creation time. No * integer may appear in the queue's current contents more than once; * an attempt to add an already-present integer again will do nothing, * so that that integer is removed from the queue at the position * where it was _first_ inserted. The add and remove operations take * constant time. * * The idea is that you might use this in applications like solvers: * keep a tdq listing the indices of grid squares that you currently * need to process in some way. Whenever you modify a square in a way * that will require you to re-scan its neighbours, add them to the * list with tdq_add; meanwhile you're constantly taking elements off * the list when you need another square to process. In solvers where * deductions are mostly localised, this should prevent repeated * O(N^2) loops over the whole grid looking for something to do. (But * if only _most_ of the deductions are localised, then you should * respond to an empty to-do list by re-adding everything using * tdq_fill, so _then_ you rescan the whole grid looking for newly * enabled non-local deductions. Only if you've done that and emptied * the list again finding nothing new to do are you actually done.) */ typedef struct tdq tdq; tdq *tdq_new(int n); void tdq_free(tdq *tdq); void tdq_add(tdq *tdq, int k); int tdq_remove(tdq *tdq); /* returns -1 if nothing available */ void tdq_fill(tdq *tdq); /* add everything to the tdq at once */ /* * laydomino.c */ int *domino_layout(int w, int h, random_state *rs); void domino_layout_prealloc(int w, int h, random_state *rs, int *grid, int *grid2, int *list); /* * version.c */ extern char ver[]; /* * random.c */ random_state *random_new(const char *seed, int len); random_state *random_copy(random_state *tocopy); unsigned long random_bits(random_state *state, int bits); unsigned long random_upto(random_state *state, unsigned long limit); void random_free(random_state *state); char *random_state_encode(random_state *state); random_state *random_state_decode(const char *input); /* random.c also exports SHA, which occasionally comes in useful. */ #if __STDC_VERSION__ >= 199901L #include typedef uint32_t uint32; #elif UINT_MAX >= 4294967295L typedef unsigned int uint32; #else typedef unsigned long uint32; #endif typedef struct { uint32 h[5]; unsigned char block[64]; int blkused; uint32 lenhi, lenlo; } SHA_State; void SHA_Init(SHA_State *s); void SHA_Bytes(SHA_State *s, const void *p, int len); void SHA_Final(SHA_State *s, unsigned char *output); void SHA_Simple(const void *p, int len, unsigned char *output); /* * printing.c */ document *document_new(int pw, int ph, float userscale); void document_free(document *doc); void document_add_puzzle(document *doc, const game *game, game_params *par, game_state *st, game_state *st2); void document_print(document *doc, drawing *dr); /* * ps.c */ psdata *ps_init(FILE *outfile, int colour); void ps_free(psdata *ps); drawing *ps_drawing_api(psdata *ps); /* * combi.c: provides a structure and functions for iterating over * combinations (i.e. choosing r things out of n). */ typedef struct _combi_ctx { int r, n, nleft, total; int *a; } combi_ctx; combi_ctx *new_combi(int r, int n); void reset_combi(combi_ctx *combi); combi_ctx *next_combi(combi_ctx *combi); /* returns NULL for end */ void free_combi(combi_ctx *combi); /* * divvy.c */ /* divides w*h rectangle into pieces of size k. Returns w*h dsf. */ int *divvy_rectangle(int w, int h, int k, random_state *rs); /* * findloop.c */ struct findloopstate; struct findloopstate *findloop_new_state(int nvertices); void findloop_free_state(struct findloopstate *); /* * Callback provided by the client code to enumerate the graph * vertices joined directly to a given vertex. * * Semantics: if vertex >= 0, return one of its neighbours; if vertex * < 0, return a previously unmentioned neighbour of whatever vertex * was last passed as input. Write to 'ctx' as necessary to store * state. In either case, return < 0 if no such vertex can be found. */ typedef int (*neighbour_fn_t)(int vertex, void *ctx); /* * Actual function to find loops. 'ctx' will be passed unchanged to * the 'neighbour' function to query graph edges. Returns FALSE if no * loop was found, or TRUE if one was. */ int findloop_run(struct findloopstate *state, int nvertices, neighbour_fn_t neighbour, void *ctx); /* * Query whether an edge is part of a loop, in the output of * find_loops. * * Due to the internal storage format, if you pass u,v which are not * connected at all, the output will be TRUE. (The algorithm actually * stores an exhaustive list of *non*-loop edges, because there are * fewer of those, so really it's querying whether the edge is on that * list.) */ int findloop_is_loop_edge(struct findloopstate *state, int u, int v); /* * Data structure containing the function calls and data specific * to a particular game. This is enclosed in a data structure so * that a particular platform can choose, if it wishes, to compile * all the games into a single combined executable rather than * having lots of little ones. */ struct game { const char *name; const char *winhelp_topic, *htmlhelp_topic; game_params *(*default_params)(void); int (*fetch_preset)(int i, char **name, game_params **params); struct preset_menu *(*preset_menu)(void); void (*decode_params)(game_params *, char const *string); char *(*encode_params)(const game_params *, int full); void (*free_params)(game_params *params); game_params *(*dup_params)(const game_params *params); int can_configure; config_item *(*configure)(const game_params *params); game_params *(*custom_params)(const config_item *cfg); char *(*validate_params)(const game_params *params, int full); char *(*new_desc)(const game_params *params, random_state *rs, char **aux, int interactive); char *(*validate_desc)(const game_params *params, const char *desc); game_state *(*new_game)(midend *me, const game_params *params, const char *desc); game_state *(*dup_game)(const game_state *state); void (*free_game)(game_state *state); int can_solve; char *(*solve)(const game_state *orig, const game_state *curr, const char *aux, char **error); int can_format_as_text_ever; int (*can_format_as_text_now)(const game_params *params); char *(*text_format)(const game_state *state); game_ui *(*new_ui)(const game_state *state); void (*free_ui)(game_ui *ui); char *(*encode_ui)(const game_ui *ui); void (*decode_ui)(game_ui *ui, const char *encoding); void (*changed_state)(game_ui *ui, const game_state *oldstate, const game_state *newstate); char *(*interpret_move)(const game_state *state, game_ui *ui, const game_drawstate *ds, int x, int y, int button); game_state *(*execute_move)(const game_state *state, const char *move); int preferred_tilesize; void (*compute_size)(const game_params *params, int tilesize, int *x, int *y); void (*set_size)(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize); float *(*colours)(frontend *fe, int *ncolours); game_drawstate *(*new_drawstate)(drawing *dr, const game_state *state); void (*free_drawstate)(drawing *dr, game_drawstate *ds); void (*redraw)(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *newstate, int dir, const game_ui *ui, float anim_time, float flash_time); float (*anim_length)(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui); float (*flash_length)(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui); int (*status)(const game_state *state); int can_print, can_print_in_colour; void (*print_size)(const game_params *params, float *x, float *y); void (*print)(drawing *dr, const game_state *state, int tilesize); int wants_statusbar; int is_timed; int (*timing_state)(const game_state *state, game_ui *ui); int flags; }; /* * Data structure containing the drawing API implemented by the * front end and also by cross-platform printing modules such as * PostScript. */ struct drawing_api { void (*draw_text)(void *handle, int x, int y, int fonttype, int fontsize, int align, int colour, char *text); void (*draw_rect)(void *handle, int x, int y, int w, int h, int colour); void (*draw_line)(void *handle, int x1, int y1, int x2, int y2, int colour); void (*draw_polygon)(void *handle, int *coords, int npoints, int fillcolour, int outlinecolour); void (*draw_circle)(void *handle, int cx, int cy, int radius, int fillcolour, int outlinecolour); void (*draw_update)(void *handle, int x, int y, int w, int h); void (*clip)(void *handle, int x, int y, int w, int h); void (*unclip)(void *handle); void (*start_draw)(void *handle); void (*end_draw)(void *handle); void (*status_bar)(void *handle, char *text); blitter *(*blitter_new)(void *handle, int w, int h); void (*blitter_free)(void *handle, blitter *bl); void (*blitter_save)(void *handle, blitter *bl, int x, int y); void (*blitter_load)(void *handle, blitter *bl, int x, int y); void (*begin_doc)(void *handle, int pages); void (*begin_page)(void *handle, int number); void (*begin_puzzle)(void *handle, float xm, float xc, float ym, float yc, int pw, int ph, float wmm); void (*end_puzzle)(void *handle); void (*end_page)(void *handle, int number); void (*end_doc)(void *handle); void (*line_width)(void *handle, float width); void (*line_dotted)(void *handle, int dotted); char *(*text_fallback)(void *handle, const char *const *strings, int nstrings); void (*draw_thick_line)(void *handle, float thickness, float x1, float y1, float x2, float y2, int colour); }; /* * For one-game-at-a-time platforms, there's a single structure * like the above, under a fixed name. For all-at-once platforms, * there's a list of all available puzzles in array form. */ #ifdef COMBINED extern const game *gamelist[]; extern const int gamecount; #else extern const game thegame; #endif /* A little bit of help to lazy developers */ #define DEFAULT_STATUSBAR_TEXT "Use status_bar() to fill this in." #endif /* PUZZLES_PUZZLES_H */ puzzles-20170606.272beef/penrose.h0000644000175000017500000000334213115373615015517 0ustar simonsimon/* penrose.h * * Penrose tiling functions. * * Provides an interface with which to generate Penrose tilings * by recursive subdivision of an initial tile of choice (one of the * four sets of two pairs kite/dart, or thin/thick rhombus). * * You supply a callback function and a context pointer, which is * called with each tile in turn: you choose how many times to recurse. */ #ifndef _PENROSE_H #define _PENROSE_H #ifndef PHI #define PHI 1.6180339887 #endif typedef struct vector vector; double v_x(vector *vs, int i); double v_y(vector *vs, int i); typedef struct penrose_state penrose_state; /* Return non-zero to clip the tree here (i.e. not recurse * below this tile). * * Parameters are state, vector array, npoints, depth. * ctx is inside state. */ typedef int (*tile_callback)(penrose_state *, vector *, int, int); struct penrose_state { int start_size; /* initial side length */ int max_depth; /* Recursion depth */ tile_callback new_tile; void *ctx; /* for callback */ }; enum { PENROSE_P2, PENROSE_P3 }; extern int penrose(penrose_state *state, int which, int angle); /* Returns the side-length of a penrose tile at recursion level * gen, given a starting side length. */ extern double penrose_side_length(double start_size, int depth); /* Returns the count of each type of tile at a given recursion depth. */ extern void penrose_count_tiles(int gen, int *nlarge, int *nsmall); /* Calculate start size and recursion depth required to produce a * width-by-height sized patch of penrose tiles with the given tilesize */ extern void penrose_calculate_size(int which, int tilesize, int w, int h, double *required_radius, int *start_size, int *depth); #endif puzzles-20170606.272beef/maxflow.h0000644000175000017500000000710613115373615015523 0ustar simonsimon/* * Edmonds-Karp algorithm for finding a maximum flow and minimum * cut in a network. Almost identical to the Ford-Fulkerson * algorithm, but apparently using breadth-first search to find the * _shortest_ augmenting path is a good way to guarantee * termination and ensure the time complexity is not dependent on * the actual value of the maximum flow. I don't understand why * that should be, but it's claimed on the Internet that it's been * proved, and that's good enough for me. I prefer BFS to DFS * anyway :-) */ #ifndef MAXFLOW_MAXFLOW_H #define MAXFLOW_MAXFLOW_H /* * The actual algorithm. * * Inputs: * * - `scratch' is previously allocated scratch space of a size * previously determined by calling `maxflow_scratch_size'. * * - `nv' is the number of vertices. Vertices are assumed to be * numbered from 0 to nv-1. * * - `source' and `sink' are the distinguished source and sink * vertices. * * - `ne' is the number of edges in the graph. * * - `edges' is an array of 2*ne integers, giving a (source, dest) * pair for each network edge. Edge pairs are expected to be * sorted in lexicographic order. * * - `backedges' is an array of `ne' integers, each a distinct * index into `edges'. The edges in `edges', if permuted as * specified by this array, should end up sorted in the _other_ * lexicographic order, i.e. dest taking priority over source. * * - `capacity' is an array of `ne' integers, giving a maximum * flow capacity for each edge. A negative value is taken to * indicate unlimited capacity on that edge, but note that there * may not be any unlimited-capacity _path_ from source to sink * or an assertion will be failed. * * Output: * * - `flow' must be non-NULL. It is an array of `ne' integers, * each giving the final flow along each edge. * * - `cut' may be NULL. If non-NULL, it is an array of `nv' * integers, which will be set to zero or one on output, in such * a way that: * + the set of zero vertices includes the source * + the set of one vertices includes the sink * + the maximum flow capacity between the zero and one vertex * sets is achieved (i.e. all edges from a zero vertex to a * one vertex are at full capacity, while all edges from a * one vertex to a zero vertex have no flow at all). * * - the returned value from the function is the total flow * achieved. */ int maxflow_with_scratch(void *scratch, int nv, int source, int sink, int ne, const int *edges, const int *backedges, const int *capacity, int *flow, int *cut); /* * The above function expects its `scratch' and `backedges' * parameters to have already been set up. This allows you to set * them up once and use them in multiple invocates of the * algorithm. Now I provide functions to actually do the setting * up. */ int maxflow_scratch_size(int nv); void maxflow_setup_backedges(int ne, const int *edges, int *backedges); /* * Simplified version of the above function. All parameters are the * same, except that `scratch' and `backedges' are constructed * internally. This is the simplest way to call the algorithm as a * one-off; however, if you need to call it multiple times on the * same network, it is probably better to call the above version * directly so that you only construct `scratch' and `backedges' * once. * * Additional return value is now -1, meaning that scratch space * could not be allocated. */ int maxflow(int nv, int source, int sink, int ne, const int *edges, const int *capacity, int *flow, int *cut); #endif /* MAXFLOW_MAXFLOW_H */ puzzles-20170606.272beef/loopgen.h0000644000175000017500000000237313115373615015512 0ustar simonsimon/* * loopgen.h: interface file for loop generation functions for grid.[ch]. */ #ifndef _LOOPGEN_H #define _LOOPGEN_H #include "puzzles.h" #include "grid.h" enum face_colour { FACE_WHITE, FACE_GREY, FACE_BLACK }; /* face should be of type grid_face* here. */ #define FACE_COLOUR(face) \ ( (face) == NULL ? FACE_BLACK : \ board[(face) - g->faces] ) typedef int (*loopgen_bias_fn_t)(void *ctx, char *board, int face); /* 'board' should be a char array whose length is the same as * g->num_faces: this will be filled in with FACE_WHITE or FACE_BLACK * after loop generation. * * If 'bias' is non-null, it should be a user-provided function which * rates a half-finished board (i.e. may include some FACE_GREYs) for * desirability; this will cause the loop generator to bias in favour * of loops with a high return value from that function. The 'face' * parameter to the bias function indicates which face of the grid has * been modified since the last call; it is guaranteed that only one * will have been (so that bias functions can work incrementally * rather than re-scanning the whole grid on every call). */ extern void generate_loop(grid *g, char *board, random_state *rs, loopgen_bias_fn_t bias, void *biasctx); #endif puzzles-20170606.272beef/latin.h0000644000175000017500000001004513115373615015151 0ustar simonsimon#ifndef LATIN_H #define LATIN_H #include "puzzles.h" typedef unsigned char digit; /* --- Solver structures, definitions --- */ #ifdef STANDALONE_SOLVER extern int solver_show_working, solver_recurse_depth; #endif struct latin_solver { int o; /* order of latin square */ unsigned char *cube; /* o^3, indexed by x, y, and digit: TRUE in that position indicates a possibility */ digit *grid; /* o^2, indexed by x and y: for final deductions */ unsigned char *row; /* o^2: row[y*cr+n-1] TRUE if n is in row y */ unsigned char *col; /* o^2: col[x*cr+n-1] TRUE if n is in col x */ #ifdef STANDALONE_SOLVER char **names; /* o: names[n-1] gives name of 'digit' n */ #endif }; #define cubepos(x,y,n) (((x)*solver->o+(y))*solver->o+(n)-1) #define cube(x,y,n) (solver->cube[cubepos(x,y,n)]) #define gridpos(x,y) ((y)*solver->o+(x)) #define grid(x,y) (solver->grid[gridpos(x,y)]) /* --- Solver individual strategies --- */ /* Place a value at a specific location. */ void latin_solver_place(struct latin_solver *solver, int x, int y, int n); /* Positional elimination. */ int latin_solver_elim(struct latin_solver *solver, int start, int step #ifdef STANDALONE_SOLVER , char *fmt, ... #endif ); struct latin_solver_scratch; /* private to latin.c */ /* Set elimination */ int latin_solver_set(struct latin_solver *solver, struct latin_solver_scratch *scratch, int start, int step1, int step2 #ifdef STANDALONE_SOLVER , char *fmt, ... #endif ); /* Forcing chains */ int latin_solver_forcing(struct latin_solver *solver, struct latin_solver_scratch *scratch); /* --- Solver allocation --- */ /* Fills in (and allocates members for) a latin_solver struct. * Will allocate members of snew, but not snew itself * (allowing 'struct latin_solver' to be the first element in a larger * struct, for example). */ void latin_solver_alloc(struct latin_solver *solver, digit *grid, int o); void latin_solver_free(struct latin_solver *solver); /* Allocates scratch space (for _set and _forcing) */ struct latin_solver_scratch * latin_solver_new_scratch(struct latin_solver *solver); void latin_solver_free_scratch(struct latin_solver_scratch *scratch); /* --- Solver guts --- */ /* Looped positional elimination */ int latin_solver_diff_simple(struct latin_solver *solver); /* Looped set elimination; *extreme is set if it used * the more difficult single-number elimination. */ int latin_solver_diff_set(struct latin_solver *solver, struct latin_solver_scratch *scratch, int extreme); typedef int (*usersolver_t)(struct latin_solver *solver, void *ctx); typedef void *(*ctxnew_t)(void *ctx); typedef void (*ctxfree_t)(void *ctx); /* Individual puzzles should use their enumerations for their * own difficulty levels, ensuring they don't clash with these. */ enum { diff_impossible = 10, diff_ambiguous, diff_unfinished }; /* Externally callable function that allocates and frees a latin_solver */ int latin_solver(digit *grid, int o, int maxdiff, int diff_simple, int diff_set_0, int diff_set_1, int diff_forcing, int diff_recursive, usersolver_t const *usersolvers, void *ctx, ctxnew_t ctxnew, ctxfree_t ctxfree); /* Version you can call if you want to alloc and free latin_solver yourself */ int latin_solver_main(struct latin_solver *solver, int maxdiff, int diff_simple, int diff_set_0, int diff_set_1, int diff_forcing, int diff_recursive, usersolver_t const *usersolvers, void *ctx, ctxnew_t ctxnew, ctxfree_t ctxfree); void latin_solver_debug(unsigned char *cube, int o); /* --- Generation and checking --- */ digit *latin_generate(int o, random_state *rs); /* The order of the latin rectangle is max(w,h). */ digit *latin_generate_rect(int w, int h, random_state *rs); int latin_check(digit *sq, int order); /* !0 => not a latin square */ void latin_debug(digit *sq, int order); #endif puzzles-20170606.272beef/grid.h0000644000175000017500000001123613115373615014772 0ustar simonsimon/* * (c) Lambros Lambrou 2008 * * Code for working with general grids, which can be any planar graph * with faces, edges and vertices (dots). Includes generators for a few * types of grid, including square, hexagonal, triangular and others. */ #ifndef PUZZLES_GRID_H #define PUZZLES_GRID_H #include "puzzles.h" /* for random_state */ /* Useful macros */ #define SQ(x) ( (x) * (x) ) /* ---------------------------------------------------------------------- * Grid structures: * A grid is made up of faces, edges and dots. These structures hold * the incidence relationships between these types. For example, an * edge always joins two dots, and is adjacent to two faces. * The "grid_xxx **" members are lists of pointers which are dynamically * allocated during grid generation. * A pointer to a face/edge/dot will always point somewhere inside one of the * three lists of the main "grid" structure: faces, edges, dots. * Could have used integer offsets into these lists, but using actual * pointers instead gives us type-safety. */ /* Need forward declarations */ typedef struct grid_face grid_face; typedef struct grid_edge grid_edge; typedef struct grid_dot grid_dot; struct grid_face { int order; /* Number of edges, also the number of dots */ grid_edge **edges; /* edges around this face */ grid_dot **dots; /* corners of this face */ /* * For each face, we optionally compute and store its 'incentre'. * The incentre of a triangle is the centre of a circle tangent to * all three edges; I generalise the concept to arbitrary polygons * by defining it to be the centre of the largest circle you can fit * anywhere in the polygon. It's a useful thing to know because if * you want to draw any symbol or text in the face (e.g. clue * numbers in Loopy), that's the place it will most easily fit. * * When a grid is first generated, no face has this information * computed, because it's fiddly to do. You can call * grid_find_incentre() on a face, and it will fill in ix,iy below * and set has_incentre to indicate that it's done so. */ int has_incentre; int ix, iy; /* incentre (centre of largest inscribed circle) */ }; struct grid_edge { grid_dot *dot1, *dot2; grid_face *face1, *face2; /* Use NULL for the infinite outside face */ }; struct grid_dot { int order; grid_edge **edges; grid_face **faces; /* A NULL grid_face* means infinite outside face */ /* Position in some fairly arbitrary (Cartesian) coordinate system. * Use large enough values such that we can get away with * integer arithmetic, but small enough such that arithmetic * won't overflow. */ int x, y; }; typedef struct grid { /* These are (dynamically allocated) arrays of all the * faces, edges, dots that are in the grid. */ int num_faces; grid_face *faces; int num_edges; grid_edge *edges; int num_dots; grid_dot *dots; /* Cache the bounding-box of the grid, so the drawing-code can quickly * figure out the proper scaling to draw onto a given area. */ int lowest_x, lowest_y, highest_x, highest_y; /* A measure of tile size for this grid (in grid coordinates), to help * the renderer decide how large to draw the grid. * Roughly the size of a single tile - for example the side-length * of a square cell. */ int tilesize; /* We really don't want to copy this monstrosity! * A grid is immutable once generated. */ int refcount; } grid; /* Grids are specified by type: GRID_SQUARE, GRID_KITE, etc. */ #define GRIDGEN_LIST(A) \ A(SQUARE,square) \ A(HONEYCOMB,honeycomb) \ A(TRIANGULAR,triangular) \ A(SNUBSQUARE,snubsquare) \ A(CAIRO,cairo) \ A(GREATHEXAGONAL,greathexagonal) \ A(OCTAGONAL,octagonal) \ A(KITE,kites) \ A(FLORET,floret) \ A(DODECAGONAL,dodecagonal) \ A(GREATDODECAGONAL,greatdodecagonal) \ A(GREATGREATDODECAGONAL,greatgreatdodecagonal) \ A(PENROSE_P2,penrose_p2_kite) \ A(PENROSE_P3,penrose_p3_thick) #define ENUM(upper,lower) GRID_ ## upper, typedef enum grid_type { GRIDGEN_LIST(ENUM) GRID_TYPE_MAX } grid_type; #undef ENUM /* Free directly after use if non-NULL. Will never contain an underscore * (so clients can safely use that as a separator). */ char *grid_new_desc(grid_type type, int width, int height, random_state *rs); char *grid_validate_desc(grid_type type, int width, int height, const char *desc); grid *grid_new(grid_type type, int width, int height, const char *desc); void grid_free(grid *g); grid_edge *grid_nearest_edge(grid *g, int x, int y); void grid_compute_size(grid_type type, int width, int height, int *tilesize, int *xextent, int *yextent); void grid_find_incentre(grid_face *f); #endif /* PUZZLES_GRID_H */ puzzles-20170606.272beef/osx.m0000644000175000017500000013472313115373615014672 0ustar simonsimon/* * Mac OS X / Cocoa front end to puzzles. * * Still to do: * * - I'd like to be able to call up context help for a specific * game at a time. * * Mac interface issues that possibly could be done better: * * - is there a better approach to frontend_default_colour? * * - do we need any more options in the Window menu? * * - can / should we be doing anything with the titles of the * configuration boxes? * * - not sure what I should be doing about default window * placement. Centring new windows is a bit feeble, but what's * better? Is there a standard way to tell the OS "here's the * _size_ of window I want, now use your best judgment about the * initial position"? * + there's a standard _policy_ on window placement, given in * the HI guidelines. Have to implement it ourselves though, * bah. * * - a brief frob of the Mac numeric keypad suggests that it * generates numbers no matter what you do. I wonder if I should * try to figure out a way of detecting keypad codes so I can * implement UP_LEFT and friends. Alternatively, perhaps I * should simply assign the number keys to UP_LEFT et al? * They're not in use for anything else right now. * * - see if we can do anything to one-button-ise the multi-button * dependent puzzle UIs: * - Pattern is a _little_ unwieldy but not too bad (since * generally you never need the middle button unless you've * made a mistake, so it's just click versus command-click). * - Net is utterly vile; having normal click be one rotate and * command-click be the other introduces a horrid asymmetry, * and yet requiring a shift key for _each_ click would be * even worse because rotation feels as if it ought to be the * default action. I fear this is why the Flash Net had the * UI it did... * + I've tried out an alternative dragging interface for * Net; it might work nicely for stylus-based platforms * where you have better hand/eye feedback for the thing * you're clicking on, but it's rather unwieldy on the * Mac. I fear even shift-clicking is better than that. * * - Should we _return_ to a game configuration sheet once an * error is reported by midend_set_config, to allow the user to * correct the one faulty input and keep the other five OK ones? * The Apple `one sheet at a time' restriction would require me * to do this by closing the config sheet, opening the alert * sheet, and then reopening the config sheet when the alert is * closed; and the human interface types, who presumably * invented the one-sheet-at-a-time rule for good reasons, might * look with disfavour on me trying to get round them to fake a * nested sheet. On the other hand I think there are good * practical reasons for wanting it that way. Uncertain. * * - User feedback dislikes nothing happening when you start the * app; they suggest a finder-like window containing an icon for * each puzzle type, enabling you to start one easily. Needs * thought. * * Grotty implementation details that could probably be improved: * * - I am _utterly_ unconvinced that NSImageView was the right way * to go about having a window with a reliable backing store! It * just doesn't feel right; NSImageView is a _control_. Is there * a simpler way? * * - Resizing is currently very bad; rather than bother to work * out how to resize the NSImageView, I just splatter and * recreate it. */ #define COMBINED /* we put all the puzzles in one binary in this port */ #include #include #include #import #include "puzzles.h" /* ---------------------------------------------------------------------- * Global variables. */ /* * The `Type' menu. We frob this dynamically to allow the user to * choose a preset set of settings from the current game. */ NSMenu *typemenu; /* * Forward reference. */ extern const struct drawing_api osx_drawing; /* * The NSApplication shared instance, which I'll want to refer to from * a few places here and there. */ NSApplication *app; /* ---------------------------------------------------------------------- * Miscellaneous support routines that aren't part of any object or * clearly defined subsystem. */ void fatal(char *fmt, ...) { va_list ap; char errorbuf[2048]; NSAlert *alert; va_start(ap, fmt); vsnprintf(errorbuf, lenof(errorbuf), fmt, ap); va_end(ap); alert = [NSAlert alloc]; /* * We may have come here because we ran out of memory, in which * case it's entirely likely that that alloc will fail, so we * should have a fallback of some sort. */ if (!alert) { fprintf(stderr, "fatal error (and NSAlert failed): %s\n", errorbuf); } else { alert = [[alert init] autorelease]; [alert addButtonWithTitle:@"Oh dear"]; [alert setInformativeText:[NSString stringWithUTF8String:errorbuf]]; [alert runModal]; } exit(1); } void frontend_default_colour(frontend *fe, float *output) { /* FIXME: Is there a system default we can tap into for this? */ output[0] = output[1] = output[2] = 0.8F; } void get_random_seed(void **randseed, int *randseedsize) { time_t *tp = snew(time_t); time(tp); *randseed = (void *)tp; *randseedsize = sizeof(time_t); } static void savefile_write(void *wctx, void *buf, int len) { FILE *fp = (FILE *)wctx; fwrite(buf, 1, len, fp); } static int savefile_read(void *wctx, void *buf, int len) { FILE *fp = (FILE *)wctx; int ret; ret = fread(buf, 1, len, fp); return (ret == len); } /* * Since this front end does not support printing (yet), we need * this stub to satisfy the reference in midend_print_puzzle(). */ void document_add_puzzle(document *doc, const game *game, game_params *par, game_state *st, game_state *st2) { } /* * setAppleMenu isn't listed in the NSApplication header, but an * NSApp responds to it, so we're adding it here to silence * warnings. (This was removed from the headers in 10.4, so we * only need to include it for 10.4+.) */ #if MAC_OS_X_VERSION_MAX_ALLOWED >= 1040 @interface NSApplication(NSAppleMenu) - (void)setAppleMenu:(NSMenu *)menu; @end #endif /* ---------------------------------------------------------------------- * Tiny extension to NSMenuItem which carries a payload of a `void * *', allowing several menu items to invoke the same message but * pass different data through it. */ @interface DataMenuItem : NSMenuItem { void *payload; } - (void)setPayload:(void *)d; - (void *)getPayload; @end @implementation DataMenuItem - (void)setPayload:(void *)d { payload = d; } - (void *)getPayload { return payload; } @end /* ---------------------------------------------------------------------- * Utility routines for constructing OS X menus. */ NSMenu *newmenu(const char *title) { return [[[NSMenu allocWithZone:[NSMenu menuZone]] initWithTitle:[NSString stringWithUTF8String:title]] autorelease]; } NSMenu *newsubmenu(NSMenu *parent, const char *title) { NSMenuItem *item; NSMenu *child; item = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:[NSString stringWithUTF8String:title] action:NULL keyEquivalent:@""] autorelease]; child = newmenu(title); [item setEnabled:YES]; [item setSubmenu:child]; [parent addItem:item]; return child; } id initnewitem(NSMenuItem *item, NSMenu *parent, const char *title, const char *key, id target, SEL action) { unsigned mask = NSCommandKeyMask; if (key[strcspn(key, "-")]) { while (*key && *key != '-') { int c = tolower((unsigned char)*key); if (c == 's') { mask |= NSShiftKeyMask; } else if (c == 'o' || c == 'a') { mask |= NSAlternateKeyMask; } key++; } if (*key) key++; } item = [[item initWithTitle:[NSString stringWithUTF8String:title] action:NULL keyEquivalent:[NSString stringWithUTF8String:key]] autorelease]; if (*key) [item setKeyEquivalentModifierMask: mask]; [item setEnabled:YES]; [item setTarget:target]; [item setAction:action]; [parent addItem:item]; return item; } NSMenuItem *newitem(NSMenu *parent, char *title, char *key, id target, SEL action) { return initnewitem([NSMenuItem allocWithZone:[NSMenu menuZone]], parent, title, key, target, action); } /* ---------------------------------------------------------------------- * About box. */ @class AboutBox; @interface AboutBox : NSWindow { } - (id)init; @end @implementation AboutBox - (id)init { NSRect totalrect; NSView *views[16]; int nviews = 0; NSImageView *iv; NSTextField *tf; NSFont *font1 = [NSFont systemFontOfSize:0]; NSFont *font2 = [NSFont boldSystemFontOfSize:[font1 pointSize] * 1.1]; const int border = 24; int i; double y; /* * Construct the controls that go in the About box. */ iv = [[NSImageView alloc] initWithFrame:NSMakeRect(0,0,64,64)]; [iv setImage:[NSImage imageNamed:@"NSApplicationIcon"]]; views[nviews++] = iv; tf = [[NSTextField alloc] initWithFrame:NSMakeRect(0,0,400,1)]; [tf setEditable:NO]; [tf setSelectable:NO]; [tf setBordered:NO]; [tf setDrawsBackground:NO]; [tf setFont:font2]; [tf setStringValue:@"Simon Tatham's Portable Puzzle Collection"]; [tf sizeToFit]; views[nviews++] = tf; tf = [[NSTextField alloc] initWithFrame:NSMakeRect(0,0,400,1)]; [tf setEditable:NO]; [tf setSelectable:NO]; [tf setBordered:NO]; [tf setDrawsBackground:NO]; [tf setFont:font1]; [tf setStringValue:[NSString stringWithUTF8String:ver]]; [tf sizeToFit]; views[nviews++] = tf; /* * Lay the controls out. */ totalrect = NSMakeRect(0,0,0,0); for (i = 0; i < nviews; i++) { NSRect r = [views[i] frame]; if (totalrect.size.width < r.size.width) totalrect.size.width = r.size.width; totalrect.size.height += border + r.size.height; } totalrect.size.width += 2 * border; totalrect.size.height += border; y = totalrect.size.height; for (i = 0; i < nviews; i++) { NSRect r = [views[i] frame]; r.origin.x = (totalrect.size.width - r.size.width) / 2; y -= border + r.size.height; r.origin.y = y; [views[i] setFrame:r]; } self = [super initWithContentRect:totalrect styleMask:(NSTitledWindowMask | NSMiniaturizableWindowMask | NSClosableWindowMask) backing:NSBackingStoreBuffered defer:YES]; for (i = 0; i < nviews; i++) [[self contentView] addSubview:views[i]]; [self center]; /* :-) */ return self; } @end /* ---------------------------------------------------------------------- * The front end presented to midend.c. * * This is mostly a subclass of NSWindow. The actual `frontend' * structure passed to the midend contains a variety of pointers, * including that window object but also including the image we * draw on, an ImageView to display it in the window, and so on. */ @class GameWindow; @class MyImageView; struct frontend { GameWindow *window; NSImage *image; MyImageView *view; NSColor **colours; int ncolours; int clipped; int w, h; }; @interface MyImageView : NSImageView { GameWindow *ourwin; } - (void)setWindow:(GameWindow *)win; - (void)mouseEvent:(NSEvent *)ev button:(int)b; - (void)mouseDown:(NSEvent *)ev; - (void)mouseDragged:(NSEvent *)ev; - (void)mouseUp:(NSEvent *)ev; - (void)rightMouseDown:(NSEvent *)ev; - (void)rightMouseDragged:(NSEvent *)ev; - (void)rightMouseUp:(NSEvent *)ev; - (void)otherMouseDown:(NSEvent *)ev; - (void)otherMouseDragged:(NSEvent *)ev; - (void)otherMouseUp:(NSEvent *)ev; @end @interface GameWindow : NSWindow { const game *ourgame; midend *me; struct frontend fe; struct timeval last_time; NSTimer *timer; NSWindow *sheet; config_item *cfg; int cfg_which; NSView **cfg_controls; int cfg_ncontrols; NSTextField *status; struct preset_menu *preset_menu; NSMenuItem **preset_menu_items; int n_preset_menu_items; } - (id)initWithGame:(const game *)g; - (void)dealloc; - (void)processButton:(int)b x:(int)x y:(int)y; - (void)processKey:(int)b; - (void)keyDown:(NSEvent *)ev; - (void)activateTimer; - (void)deactivateTimer; - (void)setStatusLine:(char *)text; - (void)resizeForNewGameParams; - (void)updateTypeMenuTick; @end @implementation MyImageView - (void)setWindow:(GameWindow *)win { ourwin = win; } - (void)mouseEvent:(NSEvent *)ev button:(int)b { NSPoint point = [self convertPoint:[ev locationInWindow] fromView:nil]; [ourwin processButton:b x:point.x y:point.y]; } - (void)mouseDown:(NSEvent *)ev { unsigned mod = [ev modifierFlags]; [self mouseEvent:ev button:((mod & NSCommandKeyMask) ? RIGHT_BUTTON : (mod & NSShiftKeyMask) ? MIDDLE_BUTTON : LEFT_BUTTON)]; } - (void)mouseDragged:(NSEvent *)ev { unsigned mod = [ev modifierFlags]; [self mouseEvent:ev button:((mod & NSCommandKeyMask) ? RIGHT_DRAG : (mod & NSShiftKeyMask) ? MIDDLE_DRAG : LEFT_DRAG)]; } - (void)mouseUp:(NSEvent *)ev { unsigned mod = [ev modifierFlags]; [self mouseEvent:ev button:((mod & NSCommandKeyMask) ? RIGHT_RELEASE : (mod & NSShiftKeyMask) ? MIDDLE_RELEASE : LEFT_RELEASE)]; } - (void)rightMouseDown:(NSEvent *)ev { unsigned mod = [ev modifierFlags]; [self mouseEvent:ev button:((mod & NSShiftKeyMask) ? MIDDLE_BUTTON : RIGHT_BUTTON)]; } - (void)rightMouseDragged:(NSEvent *)ev { unsigned mod = [ev modifierFlags]; [self mouseEvent:ev button:((mod & NSShiftKeyMask) ? MIDDLE_DRAG : RIGHT_DRAG)]; } - (void)rightMouseUp:(NSEvent *)ev { unsigned mod = [ev modifierFlags]; [self mouseEvent:ev button:((mod & NSShiftKeyMask) ? MIDDLE_RELEASE : RIGHT_RELEASE)]; } - (void)otherMouseDown:(NSEvent *)ev { [self mouseEvent:ev button:MIDDLE_BUTTON]; } - (void)otherMouseDragged:(NSEvent *)ev { [self mouseEvent:ev button:MIDDLE_DRAG]; } - (void)otherMouseUp:(NSEvent *)ev { [self mouseEvent:ev button:MIDDLE_RELEASE]; } @end @implementation GameWindow - (void)setupContentView { NSRect frame; int w, h; if (status) { frame = [status frame]; frame.origin.y = frame.size.height; } else frame.origin.y = 0; frame.origin.x = 0; w = h = INT_MAX; midend_size(me, &w, &h, FALSE); frame.size.width = w; frame.size.height = h; fe.w = w; fe.h = h; fe.image = [[NSImage alloc] initWithSize:frame.size]; fe.view = [[MyImageView alloc] initWithFrame:frame]; [fe.view setImage:fe.image]; [fe.view setWindow:self]; midend_redraw(me); [[self contentView] addSubview:fe.view]; } - (id)initWithGame:(const game *)g { NSRect rect = { {0,0}, {0,0} }, rect2; int w, h; ourgame = g; preset_menu = NULL; preset_menu_items = NULL; fe.window = self; me = midend_new(&fe, ourgame, &osx_drawing, &fe); /* * If we ever need to open a fresh window using a provided game * ID, I think the right thing is to move most of this method * into a new initWithGame:gameID: method, and have * initWithGame: simply call that one and pass it NULL. */ midend_new_game(me); w = h = INT_MAX; midend_size(me, &w, &h, FALSE); rect.size.width = w; rect.size.height = h; fe.w = w; fe.h = h; /* * Create the status bar, which will just be an NSTextField. */ if (midend_wants_statusbar(me)) { status = [[NSTextField alloc] initWithFrame:NSMakeRect(0,0,100,50)]; [status setEditable:NO]; [status setSelectable:NO]; [status setBordered:YES]; [status setBezeled:YES]; [status setBezelStyle:NSTextFieldSquareBezel]; [status setDrawsBackground:YES]; [[status cell] setTitle:@DEFAULT_STATUSBAR_TEXT]; [status sizeToFit]; rect2 = [status frame]; rect.size.height += rect2.size.height; rect2.size.width = rect.size.width; rect2.origin.x = rect2.origin.y = 0; [status setFrame:rect2]; } else status = nil; self = [super initWithContentRect:rect styleMask:(NSTitledWindowMask | NSMiniaturizableWindowMask | NSClosableWindowMask) backing:NSBackingStoreBuffered defer:YES]; [self setTitle:[NSString stringWithUTF8String:ourgame->name]]; { float *colours; int i, ncolours; colours = midend_colours(me, &ncolours); fe.ncolours = ncolours; fe.colours = snewn(ncolours, NSColor *); for (i = 0; i < ncolours; i++) { fe.colours[i] = [[NSColor colorWithDeviceRed:colours[i*3] green:colours[i*3+1] blue:colours[i*3+2] alpha:1.0] retain]; } } [self setupContentView]; if (status) [[self contentView] addSubview:status]; [self setIgnoresMouseEvents:NO]; [self center]; /* :-) */ return self; } - (void)dealloc { int i; for (i = 0; i < fe.ncolours; i++) { [fe.colours[i] release]; } sfree(fe.colours); sfree(preset_menu_items); midend_free(me); [super dealloc]; } - (void)processButton:(int)b x:(int)x y:(int)y { if (!midend_process_key(me, x, fe.h - 1 - y, b)) [self close]; } - (void)processKey:(int)b { if (!midend_process_key(me, -1, -1, b)) [self close]; } - (void)keyDown:(NSEvent *)ev { NSString *s = [ev characters]; int i, n = [s length]; for (i = 0; i < n; i++) { int c = [s characterAtIndex:i]; /* * ASCII gets passed straight to midend_process_key. * Anything above that has to be translated to our own * function key codes. */ if (c >= 0x80) { int mods = FALSE; switch (c) { case NSUpArrowFunctionKey: c = CURSOR_UP; mods = TRUE; break; case NSDownArrowFunctionKey: c = CURSOR_DOWN; mods = TRUE; break; case NSLeftArrowFunctionKey: c = CURSOR_LEFT; mods = TRUE; break; case NSRightArrowFunctionKey: c = CURSOR_RIGHT; mods = TRUE; break; default: continue; } if (mods) { if ([ev modifierFlags] & NSShiftKeyMask) c |= MOD_SHFT; if ([ev modifierFlags] & NSControlKeyMask) c |= MOD_CTRL; } } if (c >= '0' && c <= '9' && ([ev modifierFlags] & NSNumericPadKeyMask)) c |= MOD_NUM_KEYPAD; [self processKey:c]; } } - (void)activateTimer { if (timer != nil) return; timer = [NSTimer scheduledTimerWithTimeInterval:0.02 target:self selector:@selector(timerTick:) userInfo:nil repeats:YES]; gettimeofday(&last_time, NULL); } - (void)deactivateTimer { if (timer == nil) return; [timer invalidate]; timer = nil; } - (void)timerTick:(id)sender { struct timeval now; float elapsed; gettimeofday(&now, NULL); elapsed = ((now.tv_usec - last_time.tv_usec) * 0.000001F + (now.tv_sec - last_time.tv_sec)); midend_timer(me, elapsed); last_time = now; } - (void)showError:(char *)message { NSAlert *alert; alert = [[[NSAlert alloc] init] autorelease]; [alert addButtonWithTitle:@"Bah"]; [alert setInformativeText:[NSString stringWithUTF8String:message]]; [alert beginSheetModalForWindow:self modalDelegate:nil didEndSelector:NULL contextInfo:nil]; } - (void)newGame:(id)sender { [self processKey:'n']; } - (void)restartGame:(id)sender { midend_restart_game(me); } - (void)saveGame:(id)sender { NSSavePanel *sp = [NSSavePanel savePanel]; if ([sp runModal] == NSFileHandlingPanelOKButton) { const char *name = [[sp filename] UTF8String]; FILE *fp = fopen(name, "w"); if (!fp) { [self showError:"Unable to open save file"]; return; } midend_serialise(me, savefile_write, fp); fclose(fp); } } - (void)loadSavedGame:(id)sender { NSOpenPanel *op = [NSOpenPanel openPanel]; [op setAllowsMultipleSelection:NO]; if ([op runModalForTypes:nil] == NSOKButton) { /* * This used to be * * [[[op filenames] objectAtIndex:0] cString] * * but the plain cString method became deprecated and Xcode 7 * started complaining about it. Since OS X 10.9 we can * apparently use the more modern API * * [[[op URLs] objectAtIndex:0] fileSystemRepresentation] * * but the alternative below still compiles with Xcode 7 and * is a bit more backwards compatible, so I'll try it for the * moment. */ const char *name = [[[op filenames] objectAtIndex:0] cStringUsingEncoding: [NSString defaultCStringEncoding]]; char *err; FILE *fp = fopen(name, "r"); if (!fp) { [self showError:"Unable to open saved game file"]; return; } err = midend_deserialise(me, savefile_read, fp); fclose(fp); if (err) { [self showError:err]; return; } [self resizeForNewGameParams]; [self updateTypeMenuTick]; } } - (void)undoMove:(id)sender { [self processKey:'u']; } - (void)redoMove:(id)sender { [self processKey:'r'&0x1F]; } - (void)copy:(id)sender { char *text; if ((text = midend_text_format(me)) != NULL) { NSPasteboard *pb = [NSPasteboard generalPasteboard]; NSArray *a = [NSArray arrayWithObject:NSStringPboardType]; [pb declareTypes:a owner:nil]; [pb setString:[NSString stringWithUTF8String:text] forType:NSStringPboardType]; } else NSBeep(); } - (void)solveGame:(id)sender { char *msg; msg = midend_solve(me); if (msg) [self showError:msg]; } - (BOOL)validateMenuItem:(NSMenuItem *)item { if ([item action] == @selector(copy:)) return (ourgame->can_format_as_text_ever && midend_can_format_as_text_now(me) ? YES : NO); else if ([item action] == @selector(solveGame:)) return (ourgame->can_solve ? YES : NO); else return [super validateMenuItem:item]; } - (void)clearTypeMenu { int i; while ([typemenu numberOfItems] > 1) [typemenu removeItemAtIndex:0]; [[typemenu itemAtIndex:0] setState:NSOffState]; for (i = 0; i < n_preset_menu_items; i++) preset_menu_items[i] = NULL; } - (void)updateTypeMenuTick { int i, n; n = midend_which_preset(me); for (i = 0; i < n_preset_menu_items; i++) if (preset_menu_items[i]) [preset_menu_items[i] setState:(i == n ? NSOnState : NSOffState)]; /* * The Custom menu item is always right at the bottom of the * Type menu. */ [[typemenu itemAtIndex:[typemenu numberOfItems]-1] setState:(n < 0 ? NSOnState : NSOffState)]; } - (void)populateTypeMenu:(NSMenu *)nsmenu from:(struct preset_menu *)menu { int i; /* * We process the entries in reverse order so that (in the * top-level Type menu at least) we don't disturb the 'Custom' * item which remains fixed even when we change back and forth * between puzzle type windows. */ for (i = menu->n_entries; i-- > 0 ;) { struct preset_menu_entry *entry = &menu->entries[i]; NSMenuItem *item; if (entry->params) { DataMenuItem *ditem; ditem = [[[DataMenuItem alloc] initWithTitle:[NSString stringWithUTF8String: entry->title] action:NULL keyEquivalent:@""] autorelease]; [ditem setTarget:self]; [ditem setAction:@selector(presetGame:)]; [ditem setPayload:entry->params]; preset_menu_items[entry->id] = ditem; item = ditem; } else { NSMenu *nssubmenu; item = [[[NSMenuItem alloc] initWithTitle:[NSString stringWithUTF8String: entry->title] action:NULL keyEquivalent:@""] autorelease]; nssubmenu = newmenu(entry->title); [item setSubmenu:nssubmenu]; [self populateTypeMenu:nssubmenu from:entry->submenu]; } [item setEnabled:YES]; [nsmenu insertItem:item atIndex:0]; } } - (void)becomeKeyWindow { [self clearTypeMenu]; [super becomeKeyWindow]; if (!preset_menu) { int i; preset_menu = midend_get_presets(me, &n_preset_menu_items); preset_menu_items = snewn(n_preset_menu_items, NSMenuItem *); for (i = 0; i < n_preset_menu_items; i++) preset_menu_items[i] = NULL; } if (preset_menu->n_entries > 0) { [typemenu insertItem:[NSMenuItem separatorItem] atIndex:0]; [self populateTypeMenu:typemenu from:preset_menu]; } [self updateTypeMenuTick]; } - (void)resignKeyWindow { [self clearTypeMenu]; [super resignKeyWindow]; } - (void)close { [self clearTypeMenu]; [super close]; } - (void)resizeForNewGameParams { NSSize size = {0,0}; int w, h; w = h = INT_MAX; midend_size(me, &w, &h, FALSE); size.width = w; size.height = h; fe.w = w; fe.h = h; if (status) { NSRect frame = [status frame]; size.height += frame.size.height; frame.size.width = size.width; [status setFrame:frame]; } #ifndef GNUSTEP NSDisableScreenUpdates(); #endif [self setContentSize:size]; [self setupContentView]; #ifndef GNUSTEP NSEnableScreenUpdates(); #endif } - (void)presetGame:(id)sender { game_params *params = [sender getPayload]; midend_set_params(me, params); midend_new_game(me); [self resizeForNewGameParams]; [self updateTypeMenuTick]; } - (void)startConfigureSheet:(int)which { NSButton *ok, *cancel; int actw, acth, leftw, rightw, totalw, h, thish, y; int k; NSRect rect, tmprect; const int SPACING = 16; char *title; config_item *i; int cfg_controlsize; NSTextField *tf; NSButton *b; NSPopUpButton *pb; assert(sheet == NULL); /* * Every control we create here is going to have this size * until we tell it to calculate a better one. */ tmprect = NSMakeRect(0, 0, 100, 50); /* * Set up OK and Cancel buttons. (Actually, MacOS doesn't seem * to be fond of generic OK and Cancel wording, so I'm going to * rename them to something nicer.) */ actw = acth = 0; cancel = [[NSButton alloc] initWithFrame:tmprect]; [cancel setBezelStyle:NSRoundedBezelStyle]; [cancel setTitle:@"Abandon"]; [cancel setTarget:self]; [cancel setKeyEquivalent:@"\033"]; [cancel setAction:@selector(sheetCancelButton:)]; [cancel sizeToFit]; rect = [cancel frame]; if (actw < rect.size.width) actw = rect.size.width; if (acth < rect.size.height) acth = rect.size.height; ok = [[NSButton alloc] initWithFrame:tmprect]; [ok setBezelStyle:NSRoundedBezelStyle]; [ok setTitle:@"Accept"]; [ok setTarget:self]; [ok setKeyEquivalent:@"\r"]; [ok setAction:@selector(sheetOKButton:)]; [ok sizeToFit]; rect = [ok frame]; if (actw < rect.size.width) actw = rect.size.width; if (acth < rect.size.height) acth = rect.size.height; totalw = SPACING + 2 * actw; h = 2 * SPACING + acth; /* * Now fetch the midend config data and go through it creating * controls. */ cfg = midend_get_config(me, which, &title); sfree(title); /* FIXME: should we use this somehow? */ cfg_which = which; cfg_ncontrols = cfg_controlsize = 0; cfg_controls = NULL; leftw = rightw = 0; for (i = cfg; i->type != C_END; i++) { if (cfg_controlsize < cfg_ncontrols + 5) { cfg_controlsize = cfg_ncontrols + 32; cfg_controls = sresize(cfg_controls, cfg_controlsize, NSView *); } thish = 0; switch (i->type) { case C_STRING: /* * Two NSTextFields, one being a label and the other * being an edit box. */ tf = [[NSTextField alloc] initWithFrame:tmprect]; [tf setEditable:NO]; [tf setSelectable:NO]; [tf setBordered:NO]; [tf setDrawsBackground:NO]; [[tf cell] setTitle:[NSString stringWithUTF8String:i->name]]; [tf sizeToFit]; rect = [tf frame]; if (thish < rect.size.height + 1) thish = rect.size.height + 1; if (leftw < rect.size.width + 1) leftw = rect.size.width + 1; cfg_controls[cfg_ncontrols++] = tf; tf = [[NSTextField alloc] initWithFrame:tmprect]; [tf setEditable:YES]; [tf setSelectable:YES]; [tf setBordered:YES]; [[tf cell] setTitle:[NSString stringWithUTF8String:i->sval]]; [tf sizeToFit]; rect = [tf frame]; /* * We impose a minimum and maximum width on editable * NSTextFields. If we allow them to size themselves to * the contents of the text within them, then they will * look very silly if that text is only one or two * characters, and equally silly if it's an absolutely * enormous Rectangles or Pattern game ID! */ if (rect.size.width < 75) rect.size.width = 75; if (rect.size.width > 400) rect.size.width = 400; if (thish < rect.size.height + 1) thish = rect.size.height + 1; if (rightw < rect.size.width + 1) rightw = rect.size.width + 1; cfg_controls[cfg_ncontrols++] = tf; break; case C_BOOLEAN: /* * A checkbox is an NSButton with a type of * NSSwitchButton. */ b = [[NSButton alloc] initWithFrame:tmprect]; [b setBezelStyle:NSRoundedBezelStyle]; [b setButtonType:NSSwitchButton]; [b setTitle:[NSString stringWithUTF8String:i->name]]; [b sizeToFit]; [b setState:(i->ival ? NSOnState : NSOffState)]; rect = [b frame]; if (totalw < rect.size.width + 1) totalw = rect.size.width + 1; if (thish < rect.size.height + 1) thish = rect.size.height + 1; cfg_controls[cfg_ncontrols++] = b; break; case C_CHOICES: /* * A pop-up menu control is an NSPopUpButton, which * takes an embedded NSMenu. We also need an * NSTextField to act as a label. */ tf = [[NSTextField alloc] initWithFrame:tmprect]; [tf setEditable:NO]; [tf setSelectable:NO]; [tf setBordered:NO]; [tf setDrawsBackground:NO]; [[tf cell] setTitle:[NSString stringWithUTF8String:i->name]]; [tf sizeToFit]; rect = [tf frame]; if (thish < rect.size.height + 1) thish = rect.size.height + 1; if (leftw < rect.size.width + 1) leftw = rect.size.width + 1; cfg_controls[cfg_ncontrols++] = tf; pb = [[NSPopUpButton alloc] initWithFrame:tmprect pullsDown:NO]; [pb setBezelStyle:NSRoundedBezelStyle]; { char c, *p; p = i->sval; c = *p++; while (*p) { char *q, *copy; q = p; while (*p && *p != c) p++; copy = snewn((p-q) + 1, char); memcpy(copy, q, p-q); copy[p-q] = '\0'; [pb addItemWithTitle:[NSString stringWithUTF8String:copy]]; sfree(copy); if (*p) p++; } } [pb selectItemAtIndex:i->ival]; [pb sizeToFit]; rect = [pb frame]; if (rightw < rect.size.width + 1) rightw = rect.size.width + 1; if (thish < rect.size.height + 1) thish = rect.size.height + 1; cfg_controls[cfg_ncontrols++] = pb; break; } h += SPACING + thish; } if (totalw < leftw + SPACING + rightw) totalw = leftw + SPACING + rightw; if (totalw > leftw + SPACING + rightw) { int excess = totalw - (leftw + SPACING + rightw); int leftexcess = leftw * excess / (leftw + rightw); int rightexcess = excess - leftexcess; leftw += leftexcess; rightw += rightexcess; } /* * Now go through the list again, setting the final position * for each control. */ k = 0; y = h; for (i = cfg; i->type != C_END; i++) { y -= SPACING; thish = 0; switch (i->type) { case C_STRING: case C_CHOICES: /* * These two are treated identically, since both expect * a control on the left and another on the right. */ rect = [cfg_controls[k] frame]; if (thish < rect.size.height + 1) thish = rect.size.height + 1; rect = [cfg_controls[k+1] frame]; if (thish < rect.size.height + 1) thish = rect.size.height + 1; rect = [cfg_controls[k] frame]; rect.origin.y = y - thish/2 - rect.size.height/2; rect.origin.x = SPACING; rect.size.width = leftw; [cfg_controls[k] setFrame:rect]; rect = [cfg_controls[k+1] frame]; rect.origin.y = y - thish/2 - rect.size.height/2; rect.origin.x = 2 * SPACING + leftw; rect.size.width = rightw; [cfg_controls[k+1] setFrame:rect]; k += 2; break; case C_BOOLEAN: rect = [cfg_controls[k] frame]; if (thish < rect.size.height + 1) thish = rect.size.height + 1; rect.origin.y = y - thish/2 - rect.size.height/2; rect.origin.x = SPACING; rect.size.width = totalw; [cfg_controls[k] setFrame:rect]; k++; break; } y -= thish; } assert(k == cfg_ncontrols); [cancel setFrame:NSMakeRect(SPACING+totalw/4-actw/2, SPACING, actw, acth)]; [ok setFrame:NSMakeRect(SPACING+3*totalw/4-actw/2, SPACING, actw, acth)]; sheet = [[NSWindow alloc] initWithContentRect:NSMakeRect(0,0,totalw + 2*SPACING,h) styleMask:NSTitledWindowMask | NSClosableWindowMask backing:NSBackingStoreBuffered defer:YES]; [[sheet contentView] addSubview:cancel]; [[sheet contentView] addSubview:ok]; for (k = 0; k < cfg_ncontrols; k++) [[sheet contentView] addSubview:cfg_controls[k]]; [app beginSheet:sheet modalForWindow:self modalDelegate:nil didEndSelector:NULL contextInfo:nil]; } - (void)specificGame:(id)sender { [self startConfigureSheet:CFG_DESC]; } - (void)specificRandomGame:(id)sender { [self startConfigureSheet:CFG_SEED]; } - (void)customGameType:(id)sender { [self startConfigureSheet:CFG_SETTINGS]; } - (void)sheetEndWithStatus:(BOOL)update { assert(sheet != NULL); [app endSheet:sheet]; [sheet orderOut:self]; sheet = NULL; if (update) { int k; config_item *i; char *error; k = 0; for (i = cfg; i->type != C_END; i++) { switch (i->type) { case C_STRING: sfree(i->sval); i->sval = dupstr([[[(id)cfg_controls[k+1] cell] title] UTF8String]); k += 2; break; case C_BOOLEAN: i->ival = [(id)cfg_controls[k] state] == NSOnState; k++; break; case C_CHOICES: i->ival = [(id)cfg_controls[k+1] indexOfSelectedItem]; k += 2; break; } } error = midend_set_config(me, cfg_which, cfg); if (error) { NSAlert *alert = [[[NSAlert alloc] init] autorelease]; [alert addButtonWithTitle:@"Bah"]; [alert setInformativeText:[NSString stringWithUTF8String:error]]; [alert beginSheetModalForWindow:self modalDelegate:nil didEndSelector:NULL contextInfo:nil]; } else { midend_new_game(me); [self resizeForNewGameParams]; [self updateTypeMenuTick]; } } sfree(cfg_controls); cfg_controls = NULL; } - (void)sheetOKButton:(id)sender { [self sheetEndWithStatus:YES]; } - (void)sheetCancelButton:(id)sender { [self sheetEndWithStatus:NO]; } - (void)setStatusLine:(char *)text { [[status cell] setTitle:[NSString stringWithUTF8String:text]]; } @end /* * Drawing routines called by the midend. */ static void osx_draw_polygon(void *handle, int *coords, int npoints, int fillcolour, int outlinecolour) { frontend *fe = (frontend *)handle; NSBezierPath *path = [NSBezierPath bezierPath]; int i; [[NSGraphicsContext currentContext] setShouldAntialias:YES]; for (i = 0; i < npoints; i++) { NSPoint p = { coords[i*2] + 0.5, fe->h - coords[i*2+1] - 0.5 }; if (i == 0) [path moveToPoint:p]; else [path lineToPoint:p]; } [path closePath]; if (fillcolour >= 0) { assert(fillcolour >= 0 && fillcolour < fe->ncolours); [fe->colours[fillcolour] set]; [path fill]; } assert(outlinecolour >= 0 && outlinecolour < fe->ncolours); [fe->colours[outlinecolour] set]; [path stroke]; } static void osx_draw_circle(void *handle, int cx, int cy, int radius, int fillcolour, int outlinecolour) { frontend *fe = (frontend *)handle; NSBezierPath *path = [NSBezierPath bezierPath]; [[NSGraphicsContext currentContext] setShouldAntialias:YES]; [path appendBezierPathWithArcWithCenter:NSMakePoint(cx+0.5, fe->h-cy-0.5) radius:radius startAngle:0.0 endAngle:360.0]; [path closePath]; if (fillcolour >= 0) { assert(fillcolour >= 0 && fillcolour < fe->ncolours); [fe->colours[fillcolour] set]; [path fill]; } assert(outlinecolour >= 0 && outlinecolour < fe->ncolours); [fe->colours[outlinecolour] set]; [path stroke]; } static void osx_draw_line(void *handle, int x1, int y1, int x2, int y2, int colour) { frontend *fe = (frontend *)handle; NSBezierPath *path = [NSBezierPath bezierPath]; NSPoint p1 = { x1 + 0.5, fe->h - y1 - 0.5 }; NSPoint p2 = { x2 + 0.5, fe->h - y2 - 0.5 }; [[NSGraphicsContext currentContext] setShouldAntialias:NO]; assert(colour >= 0 && colour < fe->ncolours); [fe->colours[colour] set]; [path moveToPoint:p1]; [path lineToPoint:p2]; [path stroke]; NSRectFill(NSMakeRect(x1, fe->h-y1-1, 1, 1)); NSRectFill(NSMakeRect(x2, fe->h-y2-1, 1, 1)); } static void osx_draw_thick_line( void *handle, float thickness, float x1, float y1, float x2, float y2, int colour) { frontend *fe = (frontend *)handle; NSBezierPath *path = [NSBezierPath bezierPath]; assert(colour >= 0 && colour < fe->ncolours); [fe->colours[colour] set]; [[NSGraphicsContext currentContext] setShouldAntialias: YES]; [path setLineWidth: thickness]; [path setLineCapStyle: NSButtLineCapStyle]; [path moveToPoint: NSMakePoint(x1, fe->h-y1)]; [path lineToPoint: NSMakePoint(x2, fe->h-y2)]; [path stroke]; } static void osx_draw_rect(void *handle, int x, int y, int w, int h, int colour) { frontend *fe = (frontend *)handle; NSRect r = { {x, fe->h - y - h}, {w,h} }; [[NSGraphicsContext currentContext] setShouldAntialias:NO]; assert(colour >= 0 && colour < fe->ncolours); [fe->colours[colour] set]; NSRectFill(r); } static void osx_draw_text(void *handle, int x, int y, int fonttype, int fontsize, int align, int colour, char *text) { frontend *fe = (frontend *)handle; NSString *string = [NSString stringWithUTF8String:text]; NSDictionary *attr; NSFont *font; NSSize size; NSPoint point; [[NSGraphicsContext currentContext] setShouldAntialias:YES]; assert(colour >= 0 && colour < fe->ncolours); if (fonttype == FONT_FIXED) font = [NSFont userFixedPitchFontOfSize:fontsize]; else font = [NSFont userFontOfSize:fontsize]; attr = [NSDictionary dictionaryWithObjectsAndKeys: fe->colours[colour], NSForegroundColorAttributeName, font, NSFontAttributeName, nil]; point.x = x; point.y = fe->h - y; size = [string sizeWithAttributes:attr]; if (align & ALIGN_HRIGHT) point.x -= size.width; else if (align & ALIGN_HCENTRE) point.x -= size.width / 2; if (align & ALIGN_VCENTRE) point.y -= size.height / 2; [string drawAtPoint:point withAttributes:attr]; } static char *osx_text_fallback(void *handle, const char *const *strings, int nstrings) { /* * We assume OS X can cope with any UTF-8 likely to be emitted * by a puzzle. */ return dupstr(strings[0]); } struct blitter { int w, h; int x, y; NSImage *img; }; static blitter *osx_blitter_new(void *handle, int w, int h) { blitter *bl = snew(blitter); bl->x = bl->y = -1; bl->w = w; bl->h = h; bl->img = [[NSImage alloc] initWithSize:NSMakeSize(w, h)]; return bl; } static void osx_blitter_free(void *handle, blitter *bl) { [bl->img release]; sfree(bl); } static void osx_blitter_save(void *handle, blitter *bl, int x, int y) { frontend *fe = (frontend *)handle; int sx, sy, sX, sY, dx, dy, dX, dY; [fe->image unlockFocus]; [bl->img lockFocus]; /* * Find the intersection of the source and destination rectangles, * so as to avoid trying to copy from outside the source image, * which GNUstep dislikes. * * Lower-case x,y coordinates are bottom left box corners; * upper-case X,Y are the top right. */ sx = x; sy = fe->h - y - bl->h; sX = sx + bl->w; sY = sy + bl->h; dx = dy = 0; dX = bl->w; dY = bl->h; if (sx < 0) { dx += -sx; sx = 0; } if (sy < 0) { dy += -sy; sy = 0; } if (sX > fe->w) { dX -= (sX - fe->w); sX = fe->w; } if (sY > fe->h) { dY -= (sY - fe->h); sY = fe->h; } [fe->image drawInRect:NSMakeRect(dx, dy, dX-dx, dY-dy) fromRect:NSMakeRect(sx, sy, sX-sx, sY-sy) operation:NSCompositeCopy fraction:1.0]; [bl->img unlockFocus]; [fe->image lockFocus]; bl->x = x; bl->y = y; } static void osx_blitter_load(void *handle, blitter *bl, int x, int y) { frontend *fe = (frontend *)handle; if (x == BLITTER_FROMSAVED && y == BLITTER_FROMSAVED) { x = bl->x; y = bl->y; } [bl->img drawInRect:NSMakeRect(x, fe->h - y - bl->h, bl->w, bl->h) fromRect:NSMakeRect(0, 0, bl->w, bl->h) operation:NSCompositeCopy fraction:1.0]; } static void osx_draw_update(void *handle, int x, int y, int w, int h) { frontend *fe = (frontend *)handle; [fe->view setNeedsDisplayInRect:NSMakeRect(x, fe->h - y - h, w, h)]; } static void osx_clip(void *handle, int x, int y, int w, int h) { frontend *fe = (frontend *)handle; NSRect r = { {x, fe->h - y - h}, {w, h} }; if (!fe->clipped) [[NSGraphicsContext currentContext] saveGraphicsState]; [NSBezierPath clipRect:r]; fe->clipped = TRUE; } static void osx_unclip(void *handle) { frontend *fe = (frontend *)handle; if (fe->clipped) [[NSGraphicsContext currentContext] restoreGraphicsState]; fe->clipped = FALSE; } static void osx_start_draw(void *handle) { frontend *fe = (frontend *)handle; [fe->image lockFocus]; fe->clipped = FALSE; } static void osx_end_draw(void *handle) { frontend *fe = (frontend *)handle; [fe->image unlockFocus]; } static void osx_status_bar(void *handle, char *text) { frontend *fe = (frontend *)handle; [fe->window setStatusLine:text]; } const struct drawing_api osx_drawing = { osx_draw_text, osx_draw_rect, osx_draw_line, osx_draw_polygon, osx_draw_circle, osx_draw_update, osx_clip, osx_unclip, osx_start_draw, osx_end_draw, osx_status_bar, osx_blitter_new, osx_blitter_free, osx_blitter_save, osx_blitter_load, NULL, NULL, NULL, NULL, NULL, NULL, /* {begin,end}_{doc,page,puzzle} */ NULL, NULL, /* line_width, line_dotted */ osx_text_fallback, osx_draw_thick_line, }; void deactivate_timer(frontend *fe) { [fe->window deactivateTimer]; } void activate_timer(frontend *fe) { [fe->window activateTimer]; } /* ---------------------------------------------------------------------- * AppController: the object which receives the messages from all * menu selections that aren't standard OS X functions. */ @interface AppController : NSObject { } - (void)newGameWindow:(id)sender; - (void)about:(id)sender; @end @implementation AppController - (void)newGameWindow:(id)sender { const game *g = [sender getPayload]; id win; win = [[GameWindow alloc] initWithGame:g]; [win makeKeyAndOrderFront:self]; } - (void)about:(id)sender { id win; win = [[AboutBox alloc] init]; [win makeKeyAndOrderFront:self]; } - (NSMenu *)applicationDockMenu:(NSApplication *)sender { NSMenu *menu = newmenu("Dock Menu"); { int i; for (i = 0; i < gamecount; i++) { id item = initnewitem([DataMenuItem allocWithZone:[NSMenu menuZone]], menu, gamelist[i]->name, "", self, @selector(newGameWindow:)); [item setPayload:(void *)gamelist[i]]; } } return menu; } @end /* ---------------------------------------------------------------------- * Main program. Constructs the menus and runs the application. */ int main(int argc, char **argv) { NSAutoreleasePool *pool; NSMenu *menu; AppController *controller; NSImage *icon; pool = [[NSAutoreleasePool alloc] init]; icon = [NSImage imageNamed:@"NSApplicationIcon"]; app = [NSApplication sharedApplication]; [app setApplicationIconImage:icon]; controller = [[[AppController alloc] init] autorelease]; [app setDelegate:controller]; [app setMainMenu: newmenu("Main Menu")]; menu = newsubmenu([app mainMenu], "Apple Menu"); newitem(menu, "About Puzzles", "", NULL, @selector(about:)); [menu addItem:[NSMenuItem separatorItem]]; [app setServicesMenu:newsubmenu(menu, "Services")]; [menu addItem:[NSMenuItem separatorItem]]; newitem(menu, "Hide Puzzles", "h", app, @selector(hide:)); newitem(menu, "Hide Others", "o-h", app, @selector(hideOtherApplications:)); newitem(menu, "Show All", "", app, @selector(unhideAllApplications:)); [menu addItem:[NSMenuItem separatorItem]]; newitem(menu, "Quit", "q", app, @selector(terminate:)); [app setAppleMenu: menu]; menu = newsubmenu([app mainMenu], "File"); newitem(menu, "Open", "o", NULL, @selector(loadSavedGame:)); newitem(menu, "Save As", "s", NULL, @selector(saveGame:)); newitem(menu, "New Game", "n", NULL, @selector(newGame:)); newitem(menu, "Restart Game", "r", NULL, @selector(restartGame:)); newitem(menu, "Specific Game", "", NULL, @selector(specificGame:)); newitem(menu, "Specific Random Seed", "", NULL, @selector(specificRandomGame:)); [menu addItem:[NSMenuItem separatorItem]]; { NSMenu *submenu = newsubmenu(menu, "New Window"); int i; for (i = 0; i < gamecount; i++) { id item = initnewitem([DataMenuItem allocWithZone:[NSMenu menuZone]], submenu, gamelist[i]->name, "", controller, @selector(newGameWindow:)); [item setPayload:(void *)gamelist[i]]; } } [menu addItem:[NSMenuItem separatorItem]]; newitem(menu, "Close", "w", NULL, @selector(performClose:)); menu = newsubmenu([app mainMenu], "Edit"); newitem(menu, "Undo", "z", NULL, @selector(undoMove:)); newitem(menu, "Redo", "S-z", NULL, @selector(redoMove:)); [menu addItem:[NSMenuItem separatorItem]]; newitem(menu, "Cut", "x", NULL, @selector(cut:)); newitem(menu, "Copy", "c", NULL, @selector(copy:)); newitem(menu, "Paste", "v", NULL, @selector(paste:)); [menu addItem:[NSMenuItem separatorItem]]; newitem(menu, "Solve", "S-s", NULL, @selector(solveGame:)); menu = newsubmenu([app mainMenu], "Type"); typemenu = menu; newitem(menu, "Custom", "", NULL, @selector(customGameType:)); menu = newsubmenu([app mainMenu], "Window"); [app setWindowsMenu: menu]; newitem(menu, "Minimise Window", "m", NULL, @selector(performMiniaturize:)); menu = newsubmenu([app mainMenu], "Help"); newitem(menu, "Puzzles Help", "?", app, @selector(showHelp:)); [app run]; [pool release]; return 0; } puzzles-20170606.272beef/windows.c0000644000175000017500000027714613115373615015550 0ustar simonsimon/* * windows.c: Windows front end for my puzzle collection. */ #include #include #ifndef NO_HTMLHELP #include #endif /* NO_HTMLHELP */ #ifdef _WIN32_WCE #include #include #endif #include #include #include #include #include #include #include #include "puzzles.h" #ifdef _WIN32_WCE #include "resource.h" #endif #define IDM_NEW 0x0010 #define IDM_RESTART 0x0020 #define IDM_UNDO 0x0030 #define IDM_REDO 0x0040 #define IDM_COPY 0x0050 #define IDM_SOLVE 0x0060 #define IDM_QUIT 0x0070 #define IDM_CONFIG 0x0080 #define IDM_DESC 0x0090 #define IDM_SEED 0x00A0 #define IDM_HELPC 0x00B0 #define IDM_GAMEHELP 0x00C0 #define IDM_ABOUT 0x00D0 #define IDM_SAVE 0x00E0 #define IDM_LOAD 0x00F0 #define IDM_PRINT 0x0100 #define IDM_PRESETS 0x0110 #define IDM_GAMES 0x0300 #define IDM_KEYEMUL 0x0400 #define HELP_FILE_NAME "puzzles.hlp" #define HELP_CNT_NAME "puzzles.cnt" #ifndef NO_HTMLHELP #define CHM_FILE_NAME "puzzles.chm" #endif /* NO_HTMLHELP */ #ifndef NO_HTMLHELP typedef HWND (CALLBACK *htmlhelp_t)(HWND, LPCSTR, UINT, DWORD); static htmlhelp_t htmlhelp; static HINSTANCE hh_dll; #endif /* NO_HTMLHELP */ enum { NONE, HLP, CHM } help_type; char *help_path; int help_has_contents; #ifndef FILENAME_MAX #define FILENAME_MAX (260) #endif #ifndef HGDI_ERROR #define HGDI_ERROR ((HANDLE)GDI_ERROR) #endif #ifdef COMBINED #define CLASSNAME "Puzzles" #else #define CLASSNAME thegame.name #endif #ifdef _WIN32_WCE /* * Wrapper implementations of functions not supplied by the * PocketPC API. */ #define SHGetSubMenu(hWndMB,ID_MENU) (HMENU)SendMessage((hWndMB), SHCMBM_GETSUBMENU, (WPARAM)0, (LPARAM)ID_MENU) #undef MessageBox int MessageBox(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) { TCHAR wText[2048]; TCHAR wCaption[2048]; MultiByteToWideChar (CP_ACP, 0, lpText, -1, wText, 2048); MultiByteToWideChar (CP_ACP, 0, lpCaption, -1, wCaption, 2048); return MessageBoxW (hWnd, wText, wCaption, uType); } BOOL SetDlgItemTextA(HWND hDlg, int nIDDlgItem, LPCSTR lpString) { TCHAR wText[256]; MultiByteToWideChar (CP_ACP, 0, lpString, -1, wText, 256); return SetDlgItemTextW(hDlg, nIDDlgItem, wText); } LPCSTR getenv(LPCSTR buf) { return NULL; } BOOL GetKeyboardState(PBYTE pb) { return FALSE; } static TCHAR wClassName[256], wGameName[256]; #endif #ifdef DEBUGGING static FILE *debug_fp = NULL; static HANDLE debug_hdl = INVALID_HANDLE_VALUE; static int debug_got_console = 0; void dputs(char *buf) { /*DWORD dw; if (!debug_got_console) { if (AllocConsole()) { debug_got_console = 1; debug_hdl = GetStdHandle(STD_OUTPUT_HANDLE); } } if (!debug_fp) { debug_fp = fopen("debug.log", "w"); } if (debug_hdl != INVALID_HANDLE_VALUE) { WriteFile(debug_hdl, buf, strlen(buf), &dw, NULL); } if (debug_fp) { fputs(buf, debug_fp); fflush(debug_fp); }*/ OutputDebugString(buf); } void debug_printf(char *fmt, ...) { char buf[4096]; va_list ap; static int debugging = -1; if (debugging == -1) debugging = getenv("DEBUG_PUZZLES") ? 1 : 0; if (debugging) { va_start(ap, fmt); _vsnprintf(buf, 4095, fmt, ap); dputs(buf); va_end(ap); } } #endif #ifndef _WIN32_WCE #define WINFLAGS (WS_OVERLAPPEDWINDOW &~ \ (WS_MAXIMIZEBOX | WS_OVERLAPPED)) #else #define WINFLAGS (WS_CAPTION | WS_SYSMENU) #endif static void new_game_size(frontend *fe, float scale); struct font { HFONT font; int type; int size; }; struct cfg_aux { int ctlid; }; struct blitter { HBITMAP bitmap; frontend *fe; int x, y, w, h; }; enum { CFG_PRINT = CFG_FRONTEND_SPECIFIC }; struct preset_menuitemref { HMENU which_menu; int item_index; }; struct frontend { const game *game; midend *me; HWND hwnd, statusbar, cfgbox; #ifdef _WIN32_WCE HWND numpad; /* window handle for the numeric pad */ #endif HINSTANCE inst; HBITMAP bitmap, prevbm; RECT bitmapPosition; /* game bitmap position within game window */ HDC hdc; COLORREF *colours; HBRUSH *brushes; HPEN *pens; HRGN clip; HMENU gamemenu, typemenu; UINT timer; DWORD timer_last_tickcount; struct preset_menu *preset_menu; struct preset_menuitemref *preset_menuitems; int n_preset_menuitems; struct font *fonts; int nfonts, fontsize; config_item *cfg; struct cfg_aux *cfgaux; int cfg_which, dlg_done; HFONT cfgfont; HBRUSH oldbr; HPEN oldpen; int help_running; enum { DRAWING, PRINTING, NOTHING } drawstatus; DOCINFO di; int printcount, printw, printh, printsolns, printcurr, printcolour; float printscale; int printoffsetx, printoffsety; float printpixelscale; int fontstart; int linewidth, linedotted; drawing *dr; int xmin, ymin; float puzz_scale; }; void frontend_free(frontend *fe) { midend_free(fe->me); sfree(fe->colours); sfree(fe->brushes); sfree(fe->pens); sfree(fe->fonts); sfree(fe); } static void update_type_menu_tick(frontend *fe); static void update_copy_menu_greying(frontend *fe); void fatal(char *fmt, ...) { char buf[2048]; va_list ap; va_start(ap, fmt); vsprintf(buf, fmt, ap); va_end(ap); MessageBox(NULL, buf, "Fatal error", MB_ICONEXCLAMATION | MB_OK); exit(1); } char *geterrstr(void) { LPVOID lpMsgBuf; DWORD dw = GetLastError(); char *ret; FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL ); ret = dupstr(lpMsgBuf); LocalFree(lpMsgBuf); return ret; } void get_random_seed(void **randseed, int *randseedsize) { SYSTEMTIME *st = snew(SYSTEMTIME); GetLocalTime(st); *randseed = (void *)st; *randseedsize = sizeof(SYSTEMTIME); } static void win_status_bar(void *handle, char *text) { #ifdef _WIN32_WCE TCHAR wText[255]; #endif frontend *fe = (frontend *)handle; #ifdef _WIN32_WCE MultiByteToWideChar (CP_ACP, 0, text, -1, wText, 255); SendMessage(fe->statusbar, SB_SETTEXT, (WPARAM) 255 | SBT_NOBORDERS, (LPARAM) wText); #else SetWindowText(fe->statusbar, text); #endif } static blitter *win_blitter_new(void *handle, int w, int h) { blitter *bl = snew(blitter); memset(bl, 0, sizeof(blitter)); bl->w = w; bl->h = h; bl->bitmap = 0; return bl; } static void win_blitter_free(void *handle, blitter *bl) { if (bl->bitmap) DeleteObject(bl->bitmap); sfree(bl); } static void blitter_mkbitmap(frontend *fe, blitter *bl) { HDC hdc = GetDC(fe->hwnd); bl->bitmap = CreateCompatibleBitmap(hdc, bl->w, bl->h); ReleaseDC(fe->hwnd, hdc); } /* BitBlt(dstDC, dstX, dstY, dstW, dstH, srcDC, srcX, srcY, dType) */ static void win_blitter_save(void *handle, blitter *bl, int x, int y) { frontend *fe = (frontend *)handle; HDC hdc_win, hdc_blit; HBITMAP prev_blit; assert(fe->drawstatus == DRAWING); if (!bl->bitmap) blitter_mkbitmap(fe, bl); bl->x = x; bl->y = y; hdc_win = GetDC(fe->hwnd); hdc_blit = CreateCompatibleDC(hdc_win); if (!hdc_blit) fatal("hdc_blit failed: 0x%x", GetLastError()); prev_blit = SelectObject(hdc_blit, bl->bitmap); if (prev_blit == NULL || prev_blit == HGDI_ERROR) fatal("SelectObject for hdc_main failed: 0x%x", GetLastError()); if (!BitBlt(hdc_blit, 0, 0, bl->w, bl->h, fe->hdc, x, y, SRCCOPY)) fatal("BitBlt failed: 0x%x", GetLastError()); SelectObject(hdc_blit, prev_blit); DeleteDC(hdc_blit); ReleaseDC(fe->hwnd, hdc_win); } static void win_blitter_load(void *handle, blitter *bl, int x, int y) { frontend *fe = (frontend *)handle; HDC hdc_win, hdc_blit; HBITMAP prev_blit; assert(fe->drawstatus == DRAWING); assert(bl->bitmap); /* we should always have saved before loading */ if (x == BLITTER_FROMSAVED) x = bl->x; if (y == BLITTER_FROMSAVED) y = bl->y; hdc_win = GetDC(fe->hwnd); hdc_blit = CreateCompatibleDC(hdc_win); prev_blit = SelectObject(hdc_blit, bl->bitmap); BitBlt(fe->hdc, x, y, bl->w, bl->h, hdc_blit, 0, 0, SRCCOPY); SelectObject(hdc_blit, prev_blit); DeleteDC(hdc_blit); ReleaseDC(fe->hwnd, hdc_win); } void frontend_default_colour(frontend *fe, float *output) { DWORD c = GetSysColor(COLOR_MENU); /* ick */ output[0] = (float)(GetRValue(c) / 255.0); output[1] = (float)(GetGValue(c) / 255.0); output[2] = (float)(GetBValue(c) / 255.0); } static POINT win_transform_point(frontend *fe, int x, int y) { POINT ret; assert(fe->drawstatus != NOTHING); if (fe->drawstatus == PRINTING) { ret.x = (int)(fe->printoffsetx + fe->printpixelscale * x); ret.y = (int)(fe->printoffsety + fe->printpixelscale * y); } else { ret.x = x; ret.y = y; } return ret; } static void win_text_colour(frontend *fe, int colour) { assert(fe->drawstatus != NOTHING); if (fe->drawstatus == PRINTING) { int hatch; float r, g, b; print_get_colour(fe->dr, colour, fe->printcolour, &hatch, &r, &g, &b); /* * Displaying text in hatched colours is not permitted. */ assert(hatch < 0); SetTextColor(fe->hdc, RGB(r * 255, g * 255, b * 255)); } else { SetTextColor(fe->hdc, fe->colours[colour]); } } static void win_set_brush(frontend *fe, int colour) { HBRUSH br; assert(fe->drawstatus != NOTHING); if (fe->drawstatus == PRINTING) { int hatch; float r, g, b; print_get_colour(fe->dr, colour, fe->printcolour, &hatch, &r, &g, &b); if (hatch < 0) { br = CreateSolidBrush(RGB(r * 255, g * 255, b * 255)); } else { #ifdef _WIN32_WCE /* * This is only ever required during printing, and the * PocketPC port doesn't support printing. */ fatal("CreateHatchBrush not supported"); #else br = CreateHatchBrush(hatch == HATCH_BACKSLASH ? HS_FDIAGONAL : hatch == HATCH_SLASH ? HS_BDIAGONAL : hatch == HATCH_HORIZ ? HS_HORIZONTAL : hatch == HATCH_VERT ? HS_VERTICAL : hatch == HATCH_PLUS ? HS_CROSS : /* hatch == HATCH_X ? */ HS_DIAGCROSS, RGB(0,0,0)); #endif } } else { br = fe->brushes[colour]; } fe->oldbr = SelectObject(fe->hdc, br); } static void win_reset_brush(frontend *fe) { HBRUSH br; assert(fe->drawstatus != NOTHING); br = SelectObject(fe->hdc, fe->oldbr); if (fe->drawstatus == PRINTING) DeleteObject(br); } static void win_set_pen(frontend *fe, int colour, int thin) { HPEN pen; assert(fe->drawstatus != NOTHING); if (fe->drawstatus == PRINTING) { int hatch; float r, g, b; int width = thin ? 0 : fe->linewidth; if (fe->linedotted) width = 0; print_get_colour(fe->dr, colour, fe->printcolour, &hatch, &r, &g, &b); /* * Stroking in hatched colours is not permitted. */ assert(hatch < 0); pen = CreatePen(fe->linedotted ? PS_DOT : PS_SOLID, width, RGB(r * 255, g * 255, b * 255)); } else { pen = fe->pens[colour]; } fe->oldpen = SelectObject(fe->hdc, pen); } static void win_reset_pen(frontend *fe) { HPEN pen; assert(fe->drawstatus != NOTHING); pen = SelectObject(fe->hdc, fe->oldpen); if (fe->drawstatus == PRINTING) DeleteObject(pen); } static void win_clip(void *handle, int x, int y, int w, int h) { frontend *fe = (frontend *)handle; POINT p, q; if (fe->drawstatus == NOTHING) return; p = win_transform_point(fe, x, y); q = win_transform_point(fe, x+w, y+h); IntersectClipRect(fe->hdc, p.x, p.y, q.x, q.y); } static void win_unclip(void *handle) { frontend *fe = (frontend *)handle; if (fe->drawstatus == NOTHING) return; SelectClipRgn(fe->hdc, NULL); } static void win_draw_text(void *handle, int x, int y, int fonttype, int fontsize, int align, int colour, char *text) { frontend *fe = (frontend *)handle; POINT xy; int i; LOGFONT lf; if (fe->drawstatus == NOTHING) return; if (fe->drawstatus == PRINTING) fontsize = (int)(fontsize * fe->printpixelscale); xy = win_transform_point(fe, x, y); /* * Find or create the font. */ for (i = fe->fontstart; i < fe->nfonts; i++) if (fe->fonts[i].type == fonttype && fe->fonts[i].size == fontsize) break; if (i == fe->nfonts) { if (fe->fontsize <= fe->nfonts) { fe->fontsize = fe->nfonts + 10; fe->fonts = sresize(fe->fonts, fe->fontsize, struct font); } fe->nfonts++; fe->fonts[i].type = fonttype; fe->fonts[i].size = fontsize; memset (&lf, 0, sizeof(LOGFONT)); lf.lfHeight = -fontsize; lf.lfWeight = (fe->drawstatus == PRINTING ? 0 : FW_BOLD); lf.lfCharSet = DEFAULT_CHARSET; lf.lfOutPrecision = OUT_DEFAULT_PRECIS; lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; lf.lfQuality = DEFAULT_QUALITY; lf.lfPitchAndFamily = (fonttype == FONT_FIXED ? FIXED_PITCH | FF_DONTCARE : VARIABLE_PITCH | FF_SWISS); #ifdef _WIN32_WCE wcscpy(lf.lfFaceName, TEXT("Tahoma")); #endif fe->fonts[i].font = CreateFontIndirect(&lf); } /* * Position and draw the text. */ { HFONT oldfont; TEXTMETRIC tm; SIZE size; WCHAR wText[256]; MultiByteToWideChar (CP_UTF8, 0, text, -1, wText, 256); oldfont = SelectObject(fe->hdc, fe->fonts[i].font); if (GetTextMetrics(fe->hdc, &tm)) { if (align & ALIGN_VCENTRE) xy.y -= (tm.tmAscent+tm.tmDescent)/2; else xy.y -= tm.tmAscent; } if (GetTextExtentPoint32W(fe->hdc, wText, wcslen(wText), &size)) { if (align & ALIGN_HCENTRE) xy.x -= size.cx / 2; else if (align & ALIGN_HRIGHT) xy.x -= size.cx; } SetBkMode(fe->hdc, TRANSPARENT); win_text_colour(fe, colour); ExtTextOutW(fe->hdc, xy.x, xy.y, 0, NULL, wText, wcslen(wText), NULL); SelectObject(fe->hdc, oldfont); } } static void win_draw_rect(void *handle, int x, int y, int w, int h, int colour) { frontend *fe = (frontend *)handle; POINT p, q; if (fe->drawstatus == NOTHING) return; if (fe->drawstatus == DRAWING && w == 1 && h == 1) { /* * Rectangle() appears to get uppity if asked to draw a 1x1 * rectangle, presumably on the grounds that that's beneath * its dignity and you ought to be using SetPixel instead. * So I will. */ SetPixel(fe->hdc, x, y, fe->colours[colour]); } else { win_set_brush(fe, colour); win_set_pen(fe, colour, TRUE); p = win_transform_point(fe, x, y); q = win_transform_point(fe, x+w, y+h); Rectangle(fe->hdc, p.x, p.y, q.x, q.y); win_reset_brush(fe); win_reset_pen(fe); } } static void win_draw_line(void *handle, int x1, int y1, int x2, int y2, int colour) { frontend *fe = (frontend *)handle; POINT pp[2]; if (fe->drawstatus == NOTHING) return; win_set_pen(fe, colour, FALSE); pp[0] = win_transform_point(fe, x1, y1); pp[1] = win_transform_point(fe, x2, y2); Polyline(fe->hdc, pp, 2); if (fe->drawstatus == DRAWING) SetPixel(fe->hdc, pp[1].x, pp[1].y, fe->colours[colour]); win_reset_pen(fe); } static void win_draw_circle(void *handle, int cx, int cy, int radius, int fillcolour, int outlinecolour) { frontend *fe = (frontend *)handle; POINT p, q; assert(outlinecolour >= 0); if (fe->drawstatus == NOTHING) return; if (fillcolour >= 0) win_set_brush(fe, fillcolour); else fe->oldbr = SelectObject(fe->hdc, GetStockObject(NULL_BRUSH)); win_set_pen(fe, outlinecolour, FALSE); p = win_transform_point(fe, cx - radius, cy - radius); q = win_transform_point(fe, cx + radius, cy + radius); Ellipse(fe->hdc, p.x, p.y, q.x+1, q.y+1); win_reset_brush(fe); win_reset_pen(fe); } static void win_draw_polygon(void *handle, int *coords, int npoints, int fillcolour, int outlinecolour) { frontend *fe = (frontend *)handle; POINT *pts; int i; if (fe->drawstatus == NOTHING) return; pts = snewn(npoints+1, POINT); for (i = 0; i <= npoints; i++) { int j = (i < npoints ? i : 0); pts[i] = win_transform_point(fe, coords[j*2], coords[j*2+1]); } assert(outlinecolour >= 0); if (fillcolour >= 0) { win_set_brush(fe, fillcolour); win_set_pen(fe, outlinecolour, FALSE); Polygon(fe->hdc, pts, npoints); win_reset_brush(fe); win_reset_pen(fe); } else { win_set_pen(fe, outlinecolour, FALSE); Polyline(fe->hdc, pts, npoints+1); win_reset_pen(fe); } sfree(pts); } static void win_start_draw(void *handle) { frontend *fe = (frontend *)handle; HDC hdc_win; assert(fe->drawstatus == NOTHING); hdc_win = GetDC(fe->hwnd); fe->hdc = CreateCompatibleDC(hdc_win); fe->prevbm = SelectObject(fe->hdc, fe->bitmap); ReleaseDC(fe->hwnd, hdc_win); fe->clip = NULL; #ifndef _WIN32_WCE SetMapMode(fe->hdc, MM_TEXT); #endif fe->drawstatus = DRAWING; } static void win_draw_update(void *handle, int x, int y, int w, int h) { frontend *fe = (frontend *)handle; RECT r; if (fe->drawstatus != DRAWING) return; r.left = x; r.top = y; r.right = x + w; r.bottom = y + h; OffsetRect(&r, fe->bitmapPosition.left, fe->bitmapPosition.top); InvalidateRect(fe->hwnd, &r, FALSE); } static void win_end_draw(void *handle) { frontend *fe = (frontend *)handle; assert(fe->drawstatus == DRAWING); SelectObject(fe->hdc, fe->prevbm); DeleteDC(fe->hdc); if (fe->clip) { DeleteObject(fe->clip); fe->clip = NULL; } fe->drawstatus = NOTHING; } static void win_line_width(void *handle, float width) { frontend *fe = (frontend *)handle; assert(fe->drawstatus != DRAWING); if (fe->drawstatus == NOTHING) return; fe->linewidth = (int)(width * fe->printpixelscale); } static void win_line_dotted(void *handle, int dotted) { frontend *fe = (frontend *)handle; assert(fe->drawstatus != DRAWING); if (fe->drawstatus == NOTHING) return; fe->linedotted = dotted; } static void win_begin_doc(void *handle, int pages) { frontend *fe = (frontend *)handle; assert(fe->drawstatus != DRAWING); if (fe->drawstatus == NOTHING) return; if (StartDoc(fe->hdc, &fe->di) <= 0) { char *e = geterrstr(); MessageBox(fe->hwnd, e, "Error starting to print", MB_ICONERROR | MB_OK); sfree(e); fe->drawstatus = NOTHING; } /* * Push a marker on the font stack so that we won't use the * same fonts for printing and drawing. (This is because * drawing seems to look generally better in bold, but printing * is better not in bold.) */ fe->fontstart = fe->nfonts; } static void win_begin_page(void *handle, int number) { frontend *fe = (frontend *)handle; assert(fe->drawstatus != DRAWING); if (fe->drawstatus == NOTHING) return; if (StartPage(fe->hdc) <= 0) { char *e = geterrstr(); MessageBox(fe->hwnd, e, "Error starting a page", MB_ICONERROR | MB_OK); sfree(e); fe->drawstatus = NOTHING; } } static void win_begin_puzzle(void *handle, float xm, float xc, float ym, float yc, int pw, int ph, float wmm) { frontend *fe = (frontend *)handle; int ppw, pph, pox, poy; float mmpw, mmph, mmox, mmoy; float scale; assert(fe->drawstatus != DRAWING); if (fe->drawstatus == NOTHING) return; ppw = GetDeviceCaps(fe->hdc, HORZRES); pph = GetDeviceCaps(fe->hdc, VERTRES); mmpw = (float)GetDeviceCaps(fe->hdc, HORZSIZE); mmph = (float)GetDeviceCaps(fe->hdc, VERTSIZE); /* * Compute the puzzle's position on the logical page. */ mmox = xm * mmpw + xc; mmoy = ym * mmph + yc; /* * Work out what that comes to in pixels. */ pox = (int)(mmox * (float)ppw / mmpw); poy = (int)(mmoy * (float)pph / mmph); /* * And determine the scale. * * I need a scale such that the maximum puzzle-coordinate * extent of the rectangle (pw * scale) is equal to the pixel * equivalent of the puzzle's millimetre width (wmm * ppw / * mmpw). */ scale = (wmm * ppw) / (mmpw * pw); /* * Now store pox, poy and scale for use in the main drawing * functions. */ fe->printoffsetx = pox; fe->printoffsety = poy; fe->printpixelscale = scale; fe->linewidth = 1; fe->linedotted = FALSE; } static void win_end_puzzle(void *handle) { /* Nothing needs to be done here. */ } static void win_end_page(void *handle, int number) { frontend *fe = (frontend *)handle; assert(fe->drawstatus != DRAWING); if (fe->drawstatus == NOTHING) return; if (EndPage(fe->hdc) <= 0) { char *e = geterrstr(); MessageBox(fe->hwnd, e, "Error finishing a page", MB_ICONERROR | MB_OK); sfree(e); fe->drawstatus = NOTHING; } } static void win_end_doc(void *handle) { frontend *fe = (frontend *)handle; assert(fe->drawstatus != DRAWING); /* * Free all the fonts created since we began printing. */ while (fe->nfonts > fe->fontstart) { fe->nfonts--; DeleteObject(fe->fonts[fe->nfonts].font); } fe->fontstart = 0; /* * The MSDN web site sample code doesn't bother to call EndDoc * if an error occurs half way through printing. I expect doing * so would cause the erroneous document to actually be * printed, or something equally undesirable. */ if (fe->drawstatus == NOTHING) return; if (EndDoc(fe->hdc) <= 0) { char *e = geterrstr(); MessageBox(fe->hwnd, e, "Error finishing printing", MB_ICONERROR | MB_OK); sfree(e); fe->drawstatus = NOTHING; } } char *win_text_fallback(void *handle, const char *const *strings, int nstrings) { /* * We assume Windows can cope with any UTF-8 likely to be * emitted by a puzzle. */ return dupstr(strings[0]); } const struct drawing_api win_drawing = { win_draw_text, win_draw_rect, win_draw_line, win_draw_polygon, win_draw_circle, win_draw_update, win_clip, win_unclip, win_start_draw, win_end_draw, win_status_bar, win_blitter_new, win_blitter_free, win_blitter_save, win_blitter_load, win_begin_doc, win_begin_page, win_begin_puzzle, win_end_puzzle, win_end_page, win_end_doc, win_line_width, win_line_dotted, win_text_fallback, }; void print(frontend *fe) { #ifndef _WIN32_WCE PRINTDLG pd; char doctitle[256]; document *doc; midend *nme = NULL; /* non-interactive midend for bulk puzzle generation */ int i; char *err = NULL; /* * Create our document structure and fill it up with puzzles. */ doc = document_new(fe->printw, fe->printh, fe->printscale / 100.0F); for (i = 0; i < fe->printcount; i++) { if (i == 0 && fe->printcurr) { err = midend_print_puzzle(fe->me, doc, fe->printsolns); } else { if (!nme) { game_params *params; nme = midend_new(NULL, fe->game, NULL, NULL); /* * Set the non-interactive mid-end to have the same * parameters as the standard one. */ params = midend_get_params(fe->me); midend_set_params(nme, params); fe->game->free_params(params); } midend_new_game(nme); err = midend_print_puzzle(nme, doc, fe->printsolns); } if (err) break; } if (nme) midend_free(nme); if (err) { MessageBox(fe->hwnd, err, "Error preparing puzzles for printing", MB_ICONERROR | MB_OK); document_free(doc); return; } memset(&pd, 0, sizeof(pd)); pd.lStructSize = sizeof(pd); pd.hwndOwner = fe->hwnd; pd.hDevMode = NULL; pd.hDevNames = NULL; pd.Flags = PD_USEDEVMODECOPIESANDCOLLATE | PD_RETURNDC | PD_NOPAGENUMS | PD_NOSELECTION; pd.nCopies = 1; pd.nFromPage = pd.nToPage = 0xFFFF; pd.nMinPage = pd.nMaxPage = 1; if (!PrintDlg(&pd)) { document_free(doc); return; } /* * Now pd.hDC is a device context for the printer. */ /* * FIXME: IWBNI we put up an Abort box here. */ memset(&fe->di, 0, sizeof(fe->di)); fe->di.cbSize = sizeof(fe->di); sprintf(doctitle, "Printed puzzles from %s (from Simon Tatham's" " Portable Puzzle Collection)", fe->game->name); fe->di.lpszDocName = doctitle; fe->di.lpszOutput = NULL; fe->di.lpszDatatype = NULL; fe->di.fwType = 0; fe->drawstatus = PRINTING; fe->hdc = pd.hDC; fe->dr = drawing_new(&win_drawing, NULL, fe); document_print(doc, fe->dr); drawing_free(fe->dr); fe->dr = NULL; fe->drawstatus = NOTHING; DeleteDC(pd.hDC); document_free(doc); #endif } void deactivate_timer(frontend *fe) { if (!fe) return; /* for non-interactive midend */ if (fe->hwnd) KillTimer(fe->hwnd, fe->timer); fe->timer = 0; } void activate_timer(frontend *fe) { if (!fe) return; /* for non-interactive midend */ if (!fe->timer) { fe->timer = SetTimer(fe->hwnd, 1, 20, NULL); fe->timer_last_tickcount = GetTickCount(); } } void write_clip(HWND hwnd, char *data) { HGLOBAL clipdata; int len, i, j; char *data2; void *lock; /* * Windows expects CRLF in the clipboard, so we must convert * any \n that has come out of the puzzle backend. */ len = 0; for (i = 0; data[i]; i++) { if (data[i] == '\n') len++; len++; } data2 = snewn(len+1, char); j = 0; for (i = 0; data[i]; i++) { if (data[i] == '\n') data2[j++] = '\r'; data2[j++] = data[i]; } assert(j == len); data2[j] = '\0'; clipdata = GlobalAlloc(GMEM_DDESHARE | GMEM_MOVEABLE, len + 1); if (!clipdata) { sfree(data2); return; } lock = GlobalLock(clipdata); if (!lock) { GlobalFree(clipdata); sfree(data2); return; } memcpy(lock, data2, len); ((unsigned char *) lock)[len] = 0; GlobalUnlock(clipdata); if (OpenClipboard(hwnd)) { EmptyClipboard(); SetClipboardData(CF_TEXT, clipdata); CloseClipboard(); } else GlobalFree(clipdata); sfree(data2); } /* * Set up Help and see if we can find a help file. */ static void init_help(void) { #ifndef _WIN32_WCE char b[2048], *p, *q, *r; FILE *fp; /* * Find the executable file path, so we can look alongside * it for help files. Trim the filename off the end. */ GetModuleFileName(NULL, b, sizeof(b) - 1); r = b; p = strrchr(b, '\\'); if (p && p >= r) r = p+1; q = strrchr(b, ':'); if (q && q >= r) r = q+1; #ifndef NO_HTMLHELP /* * Try HTML Help first. */ strcpy(r, CHM_FILE_NAME); if ( (fp = fopen(b, "r")) != NULL) { fclose(fp); /* * We have a .CHM. See if we can use it. */ hh_dll = LoadLibrary("hhctrl.ocx"); if (hh_dll) { htmlhelp = (htmlhelp_t)GetProcAddress(hh_dll, "HtmlHelpA"); if (!htmlhelp) FreeLibrary(hh_dll); } if (htmlhelp) { help_path = dupstr(b); help_type = CHM; return; } } #endif /* NO_HTMLHELP */ /* * Now try old-style .HLP. */ strcpy(r, HELP_FILE_NAME); if ( (fp = fopen(b, "r")) != NULL) { fclose(fp); help_path = dupstr(b); help_type = HLP; /* * See if there's a .CNT file alongside it. */ strcpy(r, HELP_CNT_NAME); if ( (fp = fopen(b, "r")) != NULL) { fclose(fp); help_has_contents = TRUE; } else help_has_contents = FALSE; return; } help_type = NONE; /* didn't find any */ #endif } #ifndef _WIN32_WCE /* * Start Help. */ static void start_help(frontend *fe, const char *topic) { char *str = NULL; int cmd; switch (help_type) { case HLP: assert(help_path); if (topic) { str = snewn(10+strlen(topic), char); sprintf(str, "JI(`',`%s')", topic); cmd = HELP_COMMAND; } else if (help_has_contents) { cmd = HELP_FINDER; } else { cmd = HELP_CONTENTS; } WinHelp(fe->hwnd, help_path, cmd, (DWORD)str); fe->help_running = TRUE; break; case CHM: #ifndef NO_HTMLHELP assert(help_path); assert(htmlhelp); if (topic) { str = snewn(20 + strlen(topic) + strlen(help_path), char); sprintf(str, "%s::/%s.html>main", help_path, topic); } else { str = dupstr(help_path); } htmlhelp(fe->hwnd, str, HH_DISPLAY_TOPIC, 0); fe->help_running = TRUE; break; #endif /* NO_HTMLHELP */ case NONE: assert(!"This shouldn't happen"); break; } sfree(str); } /* * Stop Help on window cleanup. */ static void stop_help(frontend *fe) { if (fe->help_running) { switch (help_type) { case HLP: WinHelp(fe->hwnd, help_path, HELP_QUIT, 0); break; case CHM: #ifndef NO_HTMLHELP assert(htmlhelp); htmlhelp(NULL, NULL, HH_CLOSE_ALL, 0); break; #endif /* NO_HTMLHELP */ case NONE: assert(!"This shouldn't happen"); break; } fe->help_running = FALSE; } } #endif /* * Terminate Help on process exit. */ static void cleanup_help(void) { /* Nothing to do currently. * (If we were running HTML Help single-threaded, this is where we'd * call HH_UNINITIALIZE.) */ } static int get_statusbar_height(frontend *fe) { int sy; if (fe->statusbar) { RECT sr; GetWindowRect(fe->statusbar, &sr); sy = sr.bottom - sr.top; } else { sy = 0; } return sy; } static void adjust_statusbar(frontend *fe, RECT *r) { int sy; if (!fe->statusbar) return; sy = get_statusbar_height(fe); #ifndef _WIN32_WCE SetWindowPos(fe->statusbar, NULL, 0, r->bottom-r->top-sy, r->right-r->left, sy, SWP_NOZORDER); #endif } static void get_menu_size(HWND wh, RECT *r) { HMENU bar = GetMenu(wh); RECT rect; int i; SetRect(r, 0, 0, 0, 0); for (i = 0; i < GetMenuItemCount(bar); i++) { GetMenuItemRect(wh, bar, i, &rect); UnionRect(r, r, &rect); } } /* * Given a proposed new puzzle size (cx,cy), work out the actual * puzzle size that would be (px,py) and the window size including * furniture (wx,wy). */ static int check_window_resize(frontend *fe, int cx, int cy, int *px, int *py, int *wx, int *wy) { RECT r; int x, y, sy = get_statusbar_height(fe), changed = 0; /* disallow making window thinner than menu bar */ x = max(cx, fe->xmin); y = max(cy - sy, fe->ymin); /* * See if we actually got the window size we wanted, and adjust * the puzzle size if not. */ midend_size(fe->me, &x, &y, TRUE); if (x != cx || y != cy) { /* * Resize the window, now we know what size we _really_ * want it to be. */ r.left = r.top = 0; r.right = x; r.bottom = y + sy; AdjustWindowRectEx(&r, WINFLAGS, TRUE, 0); *wx = r.right - r.left; *wy = r.bottom - r.top; changed = 1; } *px = x; *py = y; fe->puzz_scale = (float)midend_tilesize(fe->me) / (float)fe->game->preferred_tilesize; return changed; } /* * Given the current window size, make sure it's sane for the * current puzzle and resize if necessary. */ static void check_window_size(frontend *fe, int *px, int *py) { RECT r; int wx, wy, cx, cy; GetClientRect(fe->hwnd, &r); cx = r.right - r.left; cy = r.bottom - r.top; if (check_window_resize(fe, cx, cy, px, py, &wx, &wy)) { #ifdef _WIN32_WCE SetWindowPos(fe->hwnd, NULL, 0, 0, wx, wy, SWP_NOMOVE | SWP_NOZORDER); #endif ; } GetClientRect(fe->hwnd, &r); adjust_statusbar(fe, &r); } static void get_max_puzzle_size(frontend *fe, int *x, int *y) { RECT r, sr; if (SystemParametersInfo(SPI_GETWORKAREA, 0, &sr, FALSE)) { *x = sr.right - sr.left; *y = sr.bottom - sr.top; r.left = 100; r.right = 200; r.top = 100; r.bottom = 200; AdjustWindowRectEx(&r, WINFLAGS, TRUE, 0); *x -= r.right - r.left - 100; *y -= r.bottom - r.top - 100; } else { *x = *y = INT_MAX; } if (fe->statusbar != NULL) { GetWindowRect(fe->statusbar, &sr); *y -= sr.bottom - sr.top; } } #ifdef _WIN32_WCE /* Toolbar buttons on the numeric pad */ static TBBUTTON tbNumpadButtons[] = { {0, IDM_KEYEMUL + '1', TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, -1}, {1, IDM_KEYEMUL + '2', TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, -1}, {2, IDM_KEYEMUL + '3', TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, -1}, {3, IDM_KEYEMUL + '4', TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, -1}, {4, IDM_KEYEMUL + '5', TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, -1}, {5, IDM_KEYEMUL + '6', TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, -1}, {6, IDM_KEYEMUL + '7', TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, -1}, {7, IDM_KEYEMUL + '8', TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, -1}, {8, IDM_KEYEMUL + '9', TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, -1}, {9, IDM_KEYEMUL + ' ', TBSTATE_ENABLED, TBSTYLE_BUTTON, 0, -1} }; #endif /* * Allocate a new frontend structure and create its main window. */ static frontend *frontend_new(HINSTANCE inst) { frontend *fe; const char *nogame = "Puzzles (no game selected)"; fe = snew(frontend); fe->inst = inst; fe->game = NULL; fe->me = NULL; fe->timer = 0; fe->hwnd = NULL; fe->help_running = FALSE; fe->drawstatus = NOTHING; fe->dr = NULL; fe->fontstart = 0; fe->fonts = NULL; fe->nfonts = fe->fontsize = 0; fe->colours = NULL; fe->brushes = NULL; fe->pens = NULL; fe->puzz_scale = 1.0; #ifdef _WIN32_WCE MultiByteToWideChar (CP_ACP, 0, nogame, -1, wGameName, 256); fe->hwnd = CreateWindowEx(0, wClassName, wGameName, WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, inst, NULL); { SHMENUBARINFO mbi; RECT rc, rcBar, rcTB, rcClient; memset (&mbi, 0, sizeof(SHMENUBARINFO)); mbi.cbSize = sizeof(SHMENUBARINFO); mbi.hwndParent = fe->hwnd; mbi.nToolBarId = IDR_MENUBAR1; mbi.hInstRes = inst; SHCreateMenuBar(&mbi); GetWindowRect(fe->hwnd, &rc); GetWindowRect(mbi.hwndMB, &rcBar); rc.bottom -= rcBar.bottom - rcBar.top; MoveWindow(fe->hwnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, FALSE); fe->numpad = NULL; } #else fe->hwnd = CreateWindowEx(0, CLASSNAME, nogame, WS_OVERLAPPEDWINDOW &~ (WS_MAXIMIZEBOX), CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, inst, NULL); if (!fe->hwnd) { DWORD lerr = GetLastError(); printf("no window: 0x%x\n", (unsigned)lerr); } #endif fe->gamemenu = NULL; fe->preset_menu = NULL; fe->statusbar = NULL; fe->bitmap = NULL; SetWindowLong(fe->hwnd, GWL_USERDATA, (LONG)fe); return fe; } static void savefile_write(void *wctx, void *buf, int len) { FILE *fp = (FILE *)wctx; fwrite(buf, 1, len, fp); } static int savefile_read(void *wctx, void *buf, int len) { FILE *fp = (FILE *)wctx; int ret; ret = fread(buf, 1, len, fp); return (ret == len); } /* * Create an appropriate midend structure to go in a puzzle window, * given a game type and/or a command-line argument. * * 'arg' can be either a game ID string (descriptive, random, or a * plain set of parameters) or the filename of a save file. The two * boolean flag arguments indicate which possibilities are * permissible. */ static midend *midend_for_new_game(frontend *fe, const game *cgame, char *arg, int maybe_game_id, int maybe_save_file, char **error) { midend *me = NULL; if (!arg) { if (me) midend_free(me); me = midend_new(fe, cgame, &win_drawing, fe); midend_new_game(me); } else { FILE *fp; char *err_param, *err_load; /* * See if arg is a valid filename of a save game file. */ err_load = NULL; if (maybe_save_file && (fp = fopen(arg, "r")) != NULL) { const game *loadgame; #ifdef COMBINED /* * Find out what kind of game is stored in the save * file; if we're going to end up loading that, it * will have to override our caller's judgment as to * what game to initialise our midend with. */ char *id_name; err_load = identify_game(&id_name, savefile_read, fp); if (!err_load) { int i; for (i = 0; i < gamecount; i++) if (!strcmp(id_name, gamelist[i]->name)) break; if (i == gamecount) { err_load = "Save file is for a game not supported by" " this program"; } else { loadgame = gamelist[i]; rewind(fp); /* go back to the start for actual load */ } } #else loadgame = cgame; #endif if (!err_load) { if (me) midend_free(me); me = midend_new(fe, loadgame, &win_drawing, fe); err_load = midend_deserialise(me, savefile_read, fp); } } else { err_load = "Unable to open file"; } if (maybe_game_id && (!maybe_save_file || err_load)) { /* * See if arg is a game description. */ if (me) midend_free(me); me = midend_new(fe, cgame, &win_drawing, fe); err_param = midend_game_id(me, arg); if (!err_param) { midend_new_game(me); } else { if (maybe_save_file) { *error = snewn(256 + strlen(arg) + strlen(err_param) + strlen(err_load), char); sprintf(*error, "Supplied argument \"%s\" is neither a" " game ID (%s) nor a save file (%s)", arg, err_param, err_load); } else { *error = dupstr(err_param); } midend_free(me); sfree(fe); return NULL; } } else if (err_load) { *error = dupstr(err_load); midend_free(me); sfree(fe); return NULL; } } return me; } static void populate_preset_menu(frontend *fe, struct preset_menu *menu, HMENU winmenu) { int i; for (i = 0; i < menu->n_entries; i++) { struct preset_menu_entry *entry = &menu->entries[i]; UINT_PTR id_or_sub; UINT flags = MF_ENABLED; if (entry->params) { id_or_sub = (UINT_PTR)(IDM_PRESETS + 0x10 * entry->id); fe->preset_menuitems[entry->id].which_menu = winmenu; fe->preset_menuitems[entry->id].item_index = GetMenuItemCount(winmenu); } else { HMENU winsubmenu = CreateMenu(); id_or_sub = (UINT_PTR)winsubmenu; flags |= MF_POPUP; populate_preset_menu(fe, entry->submenu, winsubmenu); } /* * FIXME: we ought to go through and do something with ampersands * here. */ #ifndef _WIN32_WCE AppendMenu(winmenu, flags, id_or_sub, entry->title); #else { TCHAR wName[255]; MultiByteToWideChar(CP_ACP, 0, entry->title, -1, wName, 255); AppendMenu(winmenu, flags, id_or_sub, wName); } #endif } } /* * Populate a frontend structure with a new midend structure, and * create any window furniture that it needs. * * Previously-allocated memory and window furniture will be freed by * this function. * */ static int fe_set_midend(frontend *fe, midend *me) { int x, y; RECT r; if (fe->me) midend_free(fe->me); fe->me = me; fe->game = midend_which_game(fe->me); { int i, ncolours; float *colours; colours = midend_colours(fe->me, &ncolours); if (fe->colours) sfree(fe->colours); if (fe->brushes) sfree(fe->brushes); if (fe->pens) sfree(fe->pens); fe->colours = snewn(ncolours, COLORREF); fe->brushes = snewn(ncolours, HBRUSH); fe->pens = snewn(ncolours, HPEN); for (i = 0; i < ncolours; i++) { fe->colours[i] = RGB(255 * colours[i*3+0], 255 * colours[i*3+1], 255 * colours[i*3+2]); fe->brushes[i] = CreateSolidBrush(fe->colours[i]); fe->pens[i] = CreatePen(PS_SOLID, 1, fe->colours[i]); } sfree(colours); } if (fe->statusbar) DestroyWindow(fe->statusbar); if (midend_wants_statusbar(fe->me)) { fe->statusbar = CreateWindowEx(0, STATUSCLASSNAME, TEXT(DEFAULT_STATUSBAR_TEXT), WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, /* status bar does these */ NULL, NULL, fe->inst, NULL); } else fe->statusbar = NULL; get_max_puzzle_size(fe, &x, &y); midend_size(fe->me, &x, &y, FALSE); r.left = r.top = 0; r.right = x; r.bottom = y; AdjustWindowRectEx(&r, WINFLAGS, TRUE, 0); #ifdef _WIN32_WCE if (fe->numpad) DestroyWindow(fe->numpad); if (fe->game->flags & REQUIRE_NUMPAD) { fe->numpad = CreateToolbarEx (fe->hwnd, WS_VISIBLE | WS_CHILD | CCS_NOPARENTALIGN | TBSTYLE_FLAT, 0, 10, fe->inst, IDR_PADTOOLBAR, tbNumpadButtons, sizeof (tbNumpadButtons) / sizeof (TBBUTTON), 0, 0, 14, 15, sizeof (TBBUTTON)); GetWindowRect(fe->numpad, &rcTB); GetClientRect(fe->hwnd, &rcClient); MoveWindow(fe->numpad, 0, rcClient.bottom - (rcTB.bottom - rcTB.top) - 1, rcClient.right, rcTB.bottom - rcTB.top, FALSE); SendMessage(fe->numpad, TB_SETINDENT, (rcClient.right - (10 * 21)) / 2, 0); } else { fe->numpad = NULL; } MultiByteToWideChar (CP_ACP, 0, fe->game->name, -1, wGameName, 256); SetWindowText(fe->hwnd, wGameName); #else SetWindowText(fe->hwnd, fe->game->name); #endif if (fe->statusbar) DestroyWindow(fe->statusbar); if (midend_wants_statusbar(fe->me)) { RECT sr; fe->statusbar = CreateWindowEx(0, STATUSCLASSNAME, TEXT("ooh"), WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, /* status bar does these */ fe->hwnd, NULL, fe->inst, NULL); #ifdef _WIN32_WCE /* Flat status bar looks better on the Pocket PC */ SendMessage(fe->statusbar, SB_SIMPLE, (WPARAM) TRUE, 0); SendMessage(fe->statusbar, SB_SETTEXT, (WPARAM) 255 | SBT_NOBORDERS, (LPARAM) L""); #endif /* * Now resize the window to take account of the status bar. */ GetWindowRect(fe->statusbar, &sr); GetWindowRect(fe->hwnd, &r); #ifndef _WIN32_WCE SetWindowPos(fe->hwnd, NULL, 0, 0, r.right - r.left, r.bottom - r.top + sr.bottom - sr.top, SWP_NOMOVE | SWP_NOZORDER); #endif } else { fe->statusbar = NULL; } { HMENU oldmenu = GetMenu(fe->hwnd); #ifndef _WIN32_WCE HMENU bar = CreateMenu(); HMENU menu = CreateMenu(); RECT menusize; AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT)menu, "&Game"); #else HMENU menu = SHGetSubMenu(SHFindMenuBar(fe->hwnd), ID_GAME); DeleteMenu(menu, 0, MF_BYPOSITION); #endif fe->gamemenu = menu; AppendMenu(menu, MF_ENABLED, IDM_NEW, TEXT("&New")); AppendMenu(menu, MF_ENABLED, IDM_RESTART, TEXT("&Restart")); #ifndef _WIN32_WCE /* ...here I run out of sensible accelerator characters. */ AppendMenu(menu, MF_ENABLED, IDM_DESC, TEXT("Speci&fic...")); AppendMenu(menu, MF_ENABLED, IDM_SEED, TEXT("Rando&m Seed...")); #endif if (!fe->preset_menu) { int i; fe->preset_menu = midend_get_presets( fe->me, &fe->n_preset_menuitems); fe->preset_menuitems = snewn(fe->n_preset_menuitems, struct preset_menuitemref); for (i = 0; i < fe->n_preset_menuitems; i++) fe->preset_menuitems[i].which_menu = NULL; } if (fe->preset_menu->n_entries > 0 || fe->game->can_configure) { #ifndef _WIN32_WCE HMENU sub = CreateMenu(); AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT)sub, "&Type"); #else HMENU sub = SHGetSubMenu(SHFindMenuBar(fe->hwnd), ID_TYPE); DeleteMenu(sub, 0, MF_BYPOSITION); #endif populate_preset_menu(fe, fe->preset_menu, sub); if (fe->game->can_configure) { AppendMenu(sub, MF_ENABLED, IDM_CONFIG, TEXT("&Custom...")); } fe->typemenu = sub; } else { fe->typemenu = INVALID_HANDLE_VALUE; } #ifdef COMBINED #ifdef _WIN32_WCE #error Windows CE does not support COMBINED build. #endif { HMENU games = CreateMenu(); int i; AppendMenu(menu, MF_SEPARATOR, 0, 0); AppendMenu(menu, MF_ENABLED|MF_POPUP, (UINT)games, "&Other"); for (i = 0; i < gamecount; i++) { if (strcmp(gamelist[i]->name, fe->game->name) != 0) { /* only include those games that aren't the same as the * game we're currently playing. */ AppendMenu(games, MF_ENABLED, IDM_GAMES + i, gamelist[i]->name); } } } #endif AppendMenu(menu, MF_SEPARATOR, 0, 0); #ifndef _WIN32_WCE AppendMenu(menu, MF_ENABLED, IDM_LOAD, TEXT("&Load...")); AppendMenu(menu, MF_ENABLED, IDM_SAVE, TEXT("&Save...")); AppendMenu(menu, MF_SEPARATOR, 0, 0); if (fe->game->can_print) { AppendMenu(menu, MF_ENABLED, IDM_PRINT, TEXT("&Print...")); AppendMenu(menu, MF_SEPARATOR, 0, 0); } #endif AppendMenu(menu, MF_ENABLED, IDM_UNDO, TEXT("Undo")); AppendMenu(menu, MF_ENABLED, IDM_REDO, TEXT("Redo")); #ifndef _WIN32_WCE if (fe->game->can_format_as_text_ever) { AppendMenu(menu, MF_SEPARATOR, 0, 0); AppendMenu(menu, MF_ENABLED, IDM_COPY, TEXT("&Copy")); } #endif if (fe->game->can_solve) { AppendMenu(menu, MF_SEPARATOR, 0, 0); AppendMenu(menu, MF_ENABLED, IDM_SOLVE, TEXT("Sol&ve")); } AppendMenu(menu, MF_SEPARATOR, 0, 0); #ifndef _WIN32_WCE AppendMenu(menu, MF_ENABLED, IDM_QUIT, TEXT("E&xit")); menu = CreateMenu(); AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT)menu, TEXT("&Help")); #endif AppendMenu(menu, MF_ENABLED, IDM_ABOUT, TEXT("&About")); #ifndef _WIN32_WCE if (help_type != NONE) { char *item; AppendMenu(menu, MF_SEPARATOR, 0, 0); AppendMenu(menu, MF_ENABLED, IDM_HELPC, TEXT("&Contents")); assert(fe->game->name); item = snewn(10+strlen(fe->game->name), char); /*ick*/ sprintf(item, "&Help on %s", fe->game->name); AppendMenu(menu, MF_ENABLED, IDM_GAMEHELP, item); sfree(item); } DestroyMenu(oldmenu); SetMenu(fe->hwnd, bar); get_menu_size(fe->hwnd, &menusize); fe->xmin = (menusize.right - menusize.left) + 25; #endif } if (fe->bitmap) DeleteObject(fe->bitmap); fe->bitmap = NULL; new_game_size(fe, fe->puzz_scale); /* initialises fe->bitmap */ return 0; } static void show_window(frontend *fe) { ShowWindow(fe->hwnd, SW_SHOWNORMAL); SetForegroundWindow(fe->hwnd); update_type_menu_tick(fe); update_copy_menu_greying(fe); midend_redraw(fe->me); } #ifdef _WIN32_WCE static HFONT dialog_title_font() { static HFONT hf = NULL; LOGFONT lf; if (hf) return hf; memset (&lf, 0, sizeof(LOGFONT)); lf.lfHeight = -11; /* - ((8 * GetDeviceCaps(hdc, LOGPIXELSY)) / 72) */ lf.lfWeight = FW_BOLD; wcscpy(lf.lfFaceName, TEXT("Tahoma")); return hf = CreateFontIndirect(&lf); } static void make_dialog_full_screen(HWND hwnd) { SHINITDLGINFO shidi; /* Make dialog full screen */ shidi.dwMask = SHIDIM_FLAGS; shidi.dwFlags = SHIDIF_DONEBUTTON | SHIDIF_SIZEDLGFULLSCREEN | SHIDIF_EMPTYMENU; shidi.hDlg = hwnd; SHInitDialog(&shidi); } #endif static int CALLBACK AboutDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { frontend *fe = (frontend *)GetWindowLong(hwnd, GWL_USERDATA); switch (msg) { case WM_INITDIALOG: #ifdef _WIN32_WCE { char title[256]; make_dialog_full_screen(hwnd); sprintf(title, "About %.250s", fe->game->name); SetDlgItemTextA(hwnd, IDC_ABOUT_CAPTION, title); SendDlgItemMessage(hwnd, IDC_ABOUT_CAPTION, WM_SETFONT, (WPARAM) dialog_title_font(), 0); SetDlgItemTextA(hwnd, IDC_ABOUT_GAME, fe->game->name); SetDlgItemTextA(hwnd, IDC_ABOUT_VERSION, ver); } #endif return TRUE; case WM_COMMAND: if (LOWORD(wParam) == IDOK) #ifdef _WIN32_WCE EndDialog(hwnd, 1); #else fe->dlg_done = 1; #endif return 0; case WM_CLOSE: #ifdef _WIN32_WCE EndDialog(hwnd, 1); #else fe->dlg_done = 1; #endif return 0; } return 0; } /* * Wrappers on midend_{get,set}_config, which extend the CFG_* * enumeration to add CFG_PRINT. */ static config_item *frontend_get_config(frontend *fe, int which, char **wintitle) { if (which < CFG_FRONTEND_SPECIFIC) { return midend_get_config(fe->me, which, wintitle); } else if (which == CFG_PRINT) { config_item *ret; int i; *wintitle = snewn(40 + strlen(fe->game->name), char); sprintf(*wintitle, "%s print setup", fe->game->name); ret = snewn(8, config_item); i = 0; ret[i].name = "Number of puzzles to print"; ret[i].type = C_STRING; ret[i].sval = dupstr("1"); ret[i].ival = 0; i++; ret[i].name = "Number of puzzles across the page"; ret[i].type = C_STRING; ret[i].sval = dupstr("1"); ret[i].ival = 0; i++; ret[i].name = "Number of puzzles down the page"; ret[i].type = C_STRING; ret[i].sval = dupstr("1"); ret[i].ival = 0; i++; ret[i].name = "Percentage of standard size"; ret[i].type = C_STRING; ret[i].sval = dupstr("100.0"); ret[i].ival = 0; i++; ret[i].name = "Include currently shown puzzle"; ret[i].type = C_BOOLEAN; ret[i].sval = NULL; ret[i].ival = TRUE; i++; ret[i].name = "Print solutions"; ret[i].type = C_BOOLEAN; ret[i].sval = NULL; ret[i].ival = FALSE; i++; if (fe->game->can_print_in_colour) { ret[i].name = "Print in colour"; ret[i].type = C_BOOLEAN; ret[i].sval = NULL; ret[i].ival = FALSE; i++; } ret[i].name = NULL; ret[i].type = C_END; ret[i].sval = NULL; ret[i].ival = 0; i++; return ret; } else { assert(!"We should never get here"); return NULL; } } static char *frontend_set_config(frontend *fe, int which, config_item *cfg) { if (which < CFG_FRONTEND_SPECIFIC) { return midend_set_config(fe->me, which, cfg); } else if (which == CFG_PRINT) { if ((fe->printcount = atoi(cfg[0].sval)) <= 0) return "Number of puzzles to print should be at least one"; if ((fe->printw = atoi(cfg[1].sval)) <= 0) return "Number of puzzles across the page should be at least one"; if ((fe->printh = atoi(cfg[2].sval)) <= 0) return "Number of puzzles down the page should be at least one"; if ((fe->printscale = (float)atof(cfg[3].sval)) <= 0) return "Print size should be positive"; fe->printcurr = cfg[4].ival; fe->printsolns = cfg[5].ival; fe->printcolour = fe->game->can_print_in_colour && cfg[6].ival; return NULL; } else { assert(!"We should never get here"); return "Internal error"; } } #ifdef _WIN32_WCE /* Separate version of mkctrl function for the Pocket PC. */ /* Control coordinates should be specified in dialog units. */ HWND mkctrl(frontend *fe, int x1, int x2, int y1, int y2, LPCTSTR wclass, int wstyle, int exstyle, const char *wtext, int wid) { RECT rc; TCHAR wwtext[256]; /* Convert dialog units into pixels */ rc.left = x1; rc.right = x2; rc.top = y1; rc.bottom = y2; MapDialogRect(fe->cfgbox, &rc); MultiByteToWideChar (CP_ACP, 0, wtext, -1, wwtext, 256); return CreateWindowEx(exstyle, wclass, wwtext, wstyle | WS_CHILD | WS_VISIBLE, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, fe->cfgbox, (HMENU) wid, fe->inst, NULL); } static void create_config_controls(frontend * fe) { int id, nctrls; int col1l, col1r, col2l, col2r, y; config_item *i; struct cfg_aux *j; HWND ctl; /* Control placement done in dialog units */ col1l = 4; col1r = 96; /* Label column */ col2l = 100; col2r = 154; /* Input column (edit boxes and combo boxes) */ /* * Count the controls so we can allocate cfgaux. */ for (nctrls = 0, i = fe->cfg; i->type != C_END; i++) nctrls++; fe->cfgaux = snewn(nctrls, struct cfg_aux); id = 1000; y = 22; /* Leave some room for the dialog title */ for (i = fe->cfg, j = fe->cfgaux; i->type != C_END; i++, j++) { switch (i->type) { case C_STRING: /* * Edit box with a label beside it. */ mkctrl(fe, col1l, col1r, y + 1, y + 11, TEXT("Static"), SS_LEFTNOWORDWRAP, 0, i->name, id++); mkctrl(fe, col2l, col2r, y, y + 12, TEXT("EDIT"), WS_BORDER | WS_TABSTOP | ES_AUTOHSCROLL, 0, "", (j->ctlid = id++)); SetDlgItemTextA(fe->cfgbox, j->ctlid, i->sval); break; case C_BOOLEAN: /* * Simple checkbox. */ mkctrl(fe, col1l, col2r, y + 1, y + 11, TEXT("BUTTON"), BS_NOTIFY | BS_AUTOCHECKBOX | WS_TABSTOP, 0, i->name, (j->ctlid = id++)); CheckDlgButton(fe->cfgbox, j->ctlid, (i->ival != 0)); break; case C_CHOICES: /* * Drop-down list with a label beside it. */ mkctrl(fe, col1l, col1r, y + 1, y + 11, TEXT("STATIC"), SS_LEFTNOWORDWRAP, 0, i->name, id++); ctl = mkctrl(fe, col2l, col2r, y, y + 48, TEXT("COMBOBOX"), WS_BORDER | WS_TABSTOP | CBS_DROPDOWNLIST | CBS_HASSTRINGS, 0, "", (j->ctlid = id++)); { char c, *p, *q, *str; p = i->sval; c = *p++; while (*p) { q = p; while (*q && *q != c) q++; str = snewn(q-p+1, char); strncpy(str, p, q-p); str[q-p] = '\0'; { TCHAR ws[50]; MultiByteToWideChar (CP_ACP, 0, str, -1, ws, 50); SendMessage(ctl, CB_ADDSTRING, 0, (LPARAM)ws); } sfree(str); if (*q) q++; p = q; } } SendMessage(ctl, CB_SETCURSEL, i->ival, 0); break; } y += 15; } } #endif static int CALLBACK ConfigDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { frontend *fe = (frontend *)GetWindowLong(hwnd, GWL_USERDATA); config_item *i; struct cfg_aux *j; switch (msg) { case WM_INITDIALOG: #ifdef _WIN32_WCE { char *title; fe = (frontend *) lParam; SetWindowLong(hwnd, GWL_USERDATA, lParam); fe->cfgbox = hwnd; fe->cfg = frontend_get_config(fe, fe->cfg_which, &title); make_dialog_full_screen(hwnd); SetDlgItemTextA(hwnd, IDC_CONFIG_CAPTION, title); SendDlgItemMessage(hwnd, IDC_CONFIG_CAPTION, WM_SETFONT, (WPARAM) dialog_title_font(), 0); create_config_controls(fe); } #endif return TRUE; case WM_COMMAND: /* * OK and Cancel are special cases. */ if ((LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)) { if (LOWORD(wParam) == IDOK) { char *err = frontend_set_config(fe, fe->cfg_which, fe->cfg); if (err) { MessageBox(hwnd, err, "Validation error", MB_ICONERROR | MB_OK); } else { #ifdef _WIN32_WCE EndDialog(hwnd, 2); #else fe->dlg_done = 2; #endif } } else { #ifdef _WIN32_WCE EndDialog(hwnd, 1); #else fe->dlg_done = 1; #endif } return 0; } /* * First find the control whose id this is. */ for (i = fe->cfg, j = fe->cfgaux; i->type != C_END; i++, j++) { if (j->ctlid == LOWORD(wParam)) break; } if (i->type == C_END) return 0; /* not our problem */ if (i->type == C_STRING && HIWORD(wParam) == EN_CHANGE) { char buffer[4096]; #ifdef _WIN32_WCE TCHAR wBuffer[4096]; GetDlgItemText(fe->cfgbox, j->ctlid, wBuffer, 4096); WideCharToMultiByte(CP_ACP, 0, wBuffer, -1, buffer, 4096, NULL, NULL); #else GetDlgItemText(fe->cfgbox, j->ctlid, buffer, lenof(buffer)); #endif buffer[lenof(buffer)-1] = '\0'; sfree(i->sval); i->sval = dupstr(buffer); } else if (i->type == C_BOOLEAN && (HIWORD(wParam) == BN_CLICKED || HIWORD(wParam) == BN_DBLCLK)) { i->ival = IsDlgButtonChecked(fe->cfgbox, j->ctlid); } else if (i->type == C_CHOICES && HIWORD(wParam) == CBN_SELCHANGE) { i->ival = SendDlgItemMessage(fe->cfgbox, j->ctlid, CB_GETCURSEL, 0, 0); } return 0; case WM_CLOSE: fe->dlg_done = 1; return 0; } return 0; } #ifndef _WIN32_WCE HWND mkctrl(frontend *fe, int x1, int x2, int y1, int y2, char *wclass, int wstyle, int exstyle, const char *wtext, int wid) { HWND ret; ret = CreateWindowEx(exstyle, wclass, wtext, wstyle | WS_CHILD | WS_VISIBLE, x1, y1, x2-x1, y2-y1, fe->cfgbox, (HMENU) wid, fe->inst, NULL); SendMessage(ret, WM_SETFONT, (WPARAM)fe->cfgfont, MAKELPARAM(TRUE, 0)); return ret; } #endif static void about(frontend *fe) { #ifdef _WIN32_WCE DialogBox(fe->inst, MAKEINTRESOURCE(IDD_ABOUT), fe->hwnd, AboutDlgProc); #else int i; WNDCLASS wc; MSG msg; TEXTMETRIC tm; HDC hdc; HFONT oldfont; SIZE size; int gm, id; int winwidth, winheight, y; int height, width, maxwid; const char *strings[16]; int lengths[16]; int nstrings = 0; char titlebuf[512]; sprintf(titlebuf, "About %.250s", fe->game->name); strings[nstrings++] = fe->game->name; strings[nstrings++] = "from Simon Tatham's Portable Puzzle Collection"; strings[nstrings++] = ver; wc.style = CS_DBLCLKS | CS_SAVEBITS; wc.lpfnWndProc = DefDlgProc; wc.cbClsExtra = 0; wc.cbWndExtra = DLGWINDOWEXTRA + 8; wc.hInstance = fe->inst; wc.hIcon = NULL; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH) (COLOR_BACKGROUND +1); wc.lpszMenuName = NULL; wc.lpszClassName = "GameAboutBox"; RegisterClass(&wc); hdc = GetDC(fe->hwnd); SetMapMode(hdc, MM_TEXT); fe->dlg_done = FALSE; fe->cfgfont = CreateFont(-MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72), 0, 0, 0, 0, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FF_SWISS, "MS Shell Dlg"); oldfont = SelectObject(hdc, fe->cfgfont); if (GetTextMetrics(hdc, &tm)) { height = tm.tmAscent + tm.tmDescent; width = tm.tmAveCharWidth; } else { height = width = 30; } /* * Figure out the layout of the About box by measuring the * length of each piece of text. */ maxwid = 0; winheight = height/2; for (i = 0; i < nstrings; i++) { if (GetTextExtentPoint32(hdc, strings[i], strlen(strings[i]), &size)) lengths[i] = size.cx; else lengths[i] = 0; /* *shrug* */ if (maxwid < lengths[i]) maxwid = lengths[i]; winheight += height * 3 / 2 + (height / 2); } winheight += height + height * 7 / 4; /* OK button */ winwidth = maxwid + 4*width; SelectObject(hdc, oldfont); ReleaseDC(fe->hwnd, hdc); /* * Create the dialog, now that we know its size. */ { RECT r, r2; r.left = r.top = 0; r.right = winwidth; r.bottom = winheight; AdjustWindowRectEx(&r, (WS_OVERLAPPEDWINDOW /*| DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU*/) &~ (WS_MAXIMIZEBOX | WS_OVERLAPPED), FALSE, 0); /* * Centre the dialog on its parent window. */ r.right -= r.left; r.bottom -= r.top; GetWindowRect(fe->hwnd, &r2); r.left = (r2.left + r2.right - r.right) / 2; r.top = (r2.top + r2.bottom - r.bottom) / 2; r.right += r.left; r.bottom += r.top; fe->cfgbox = CreateWindowEx(0, wc.lpszClassName, titlebuf, DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU, r.left, r.top, r.right-r.left, r.bottom-r.top, fe->hwnd, NULL, fe->inst, NULL); } SendMessage(fe->cfgbox, WM_SETFONT, (WPARAM)fe->cfgfont, FALSE); SetWindowLong(fe->cfgbox, GWL_USERDATA, (LONG)fe); SetWindowLong(fe->cfgbox, DWL_DLGPROC, (LONG)AboutDlgProc); id = 1000; y = height/2; for (i = 0; i < nstrings; i++) { int border = width*2 + (maxwid - lengths[i]) / 2; mkctrl(fe, border, border+lengths[i], y+height*1/8, y+height*9/8, "Static", 0, 0, strings[i], id++); y += height*3/2; assert(y < winheight); y += height/2; } y += height/2; /* extra space before OK */ mkctrl(fe, width*2, maxwid+width*2, y, y+height*7/4, "BUTTON", BS_PUSHBUTTON | WS_TABSTOP | BS_DEFPUSHBUTTON, 0, "OK", IDOK); SendMessage(fe->cfgbox, WM_INITDIALOG, 0, 0); EnableWindow(fe->hwnd, FALSE); ShowWindow(fe->cfgbox, SW_SHOWNORMAL); while ((gm=GetMessage(&msg, NULL, 0, 0)) > 0) { if (!IsDialogMessage(fe->cfgbox, &msg)) DispatchMessage(&msg); if (fe->dlg_done) break; } EnableWindow(fe->hwnd, TRUE); SetForegroundWindow(fe->hwnd); DestroyWindow(fe->cfgbox); DeleteObject(fe->cfgfont); #endif } static int get_config(frontend *fe, int which) { #ifdef _WIN32_WCE fe->cfg_which = which; return DialogBoxParam(fe->inst, MAKEINTRESOURCE(IDD_CONFIG), fe->hwnd, ConfigDlgProc, (LPARAM) fe) == 2; #else config_item *i; struct cfg_aux *j; char *title; WNDCLASS wc; MSG msg; TEXTMETRIC tm; HDC hdc; HFONT oldfont; SIZE size; HWND ctl; int gm, id, nctrls; int winwidth, winheight, col1l, col1r, col2l, col2r, y; int height, width, maxlabel, maxcheckbox; wc.style = CS_DBLCLKS | CS_SAVEBITS; wc.lpfnWndProc = DefDlgProc; wc.cbClsExtra = 0; wc.cbWndExtra = DLGWINDOWEXTRA + 8; wc.hInstance = fe->inst; wc.hIcon = NULL; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH) (COLOR_BACKGROUND +1); wc.lpszMenuName = NULL; wc.lpszClassName = "GameConfigBox"; RegisterClass(&wc); hdc = GetDC(fe->hwnd); SetMapMode(hdc, MM_TEXT); fe->dlg_done = FALSE; fe->cfgfont = CreateFont(-MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72), 0, 0, 0, 0, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FF_SWISS, "MS Shell Dlg"); oldfont = SelectObject(hdc, fe->cfgfont); if (GetTextMetrics(hdc, &tm)) { height = tm.tmAscent + tm.tmDescent; width = tm.tmAveCharWidth; } else { height = width = 30; } fe->cfg = frontend_get_config(fe, which, &title); fe->cfg_which = which; /* * Figure out the layout of the config box by measuring the * length of each piece of text. */ maxlabel = maxcheckbox = 0; winheight = height/2; for (i = fe->cfg; i->type != C_END; i++) { switch (i->type) { case C_STRING: case C_CHOICES: /* * Both these control types have a label filling only * the left-hand column of the box. */ if (GetTextExtentPoint32(hdc, i->name, strlen(i->name), &size) && maxlabel < size.cx) maxlabel = size.cx; winheight += height * 3 / 2 + (height / 2); break; case C_BOOLEAN: /* * Checkboxes take up the whole of the box width. */ if (GetTextExtentPoint32(hdc, i->name, strlen(i->name), &size) && maxcheckbox < size.cx) maxcheckbox = size.cx; winheight += height + (height / 2); break; } } winheight += height + height * 7 / 4; /* OK / Cancel buttons */ col1l = 2*width; col1r = col1l + maxlabel; col2l = col1r + 2*width; col2r = col2l + 30*width; if (col2r < col1l+2*height+maxcheckbox) col2r = col1l+2*height+maxcheckbox; winwidth = col2r + 2*width; SelectObject(hdc, oldfont); ReleaseDC(fe->hwnd, hdc); /* * Create the dialog, now that we know its size. */ { RECT r, r2; r.left = r.top = 0; r.right = winwidth; r.bottom = winheight; AdjustWindowRectEx(&r, (WS_OVERLAPPEDWINDOW /*| DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU*/) &~ (WS_MAXIMIZEBOX | WS_OVERLAPPED), FALSE, 0); /* * Centre the dialog on its parent window. */ r.right -= r.left; r.bottom -= r.top; GetWindowRect(fe->hwnd, &r2); r.left = (r2.left + r2.right - r.right) / 2; r.top = (r2.top + r2.bottom - r.bottom) / 2; r.right += r.left; r.bottom += r.top; fe->cfgbox = CreateWindowEx(0, wc.lpszClassName, title, DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU, r.left, r.top, r.right-r.left, r.bottom-r.top, fe->hwnd, NULL, fe->inst, NULL); sfree(title); } SendMessage(fe->cfgbox, WM_SETFONT, (WPARAM)fe->cfgfont, FALSE); SetWindowLong(fe->cfgbox, GWL_USERDATA, (LONG)fe); SetWindowLong(fe->cfgbox, DWL_DLGPROC, (LONG)ConfigDlgProc); /* * Count the controls so we can allocate cfgaux. */ for (nctrls = 0, i = fe->cfg; i->type != C_END; i++) nctrls++; fe->cfgaux = snewn(nctrls, struct cfg_aux); id = 1000; y = height/2; for (i = fe->cfg, j = fe->cfgaux; i->type != C_END; i++, j++) { switch (i->type) { case C_STRING: /* * Edit box with a label beside it. */ mkctrl(fe, col1l, col1r, y+height*1/8, y+height*9/8, "Static", 0, 0, i->name, id++); ctl = mkctrl(fe, col2l, col2r, y, y+height*3/2, "EDIT", WS_TABSTOP | ES_AUTOHSCROLL, WS_EX_CLIENTEDGE, "", (j->ctlid = id++)); SetWindowText(ctl, i->sval); y += height*3/2; break; case C_BOOLEAN: /* * Simple checkbox. */ mkctrl(fe, col1l, col2r, y, y+height, "BUTTON", BS_NOTIFY | BS_AUTOCHECKBOX | WS_TABSTOP, 0, i->name, (j->ctlid = id++)); CheckDlgButton(fe->cfgbox, j->ctlid, (i->ival != 0)); y += height; break; case C_CHOICES: /* * Drop-down list with a label beside it. */ mkctrl(fe, col1l, col1r, y+height*1/8, y+height*9/8, "STATIC", 0, 0, i->name, id++); ctl = mkctrl(fe, col2l, col2r, y, y+height*41/2, "COMBOBOX", WS_TABSTOP | CBS_DROPDOWNLIST | CBS_HASSTRINGS, WS_EX_CLIENTEDGE, "", (j->ctlid = id++)); { char c, *p, *q, *str; SendMessage(ctl, CB_RESETCONTENT, 0, 0); p = i->sval; c = *p++; while (*p) { q = p; while (*q && *q != c) q++; str = snewn(q-p+1, char); strncpy(str, p, q-p); str[q-p] = '\0'; SendMessage(ctl, CB_ADDSTRING, 0, (LPARAM)str); sfree(str); if (*q) q++; p = q; } } SendMessage(ctl, CB_SETCURSEL, i->ival, 0); y += height*3/2; break; } assert(y < winheight); y += height/2; } y += height/2; /* extra space before OK and Cancel */ mkctrl(fe, col1l, (col1l+col2r)/2-width, y, y+height*7/4, "BUTTON", BS_PUSHBUTTON | WS_TABSTOP | BS_DEFPUSHBUTTON, 0, "OK", IDOK); mkctrl(fe, (col1l+col2r)/2+width, col2r, y, y+height*7/4, "BUTTON", BS_PUSHBUTTON | WS_TABSTOP, 0, "Cancel", IDCANCEL); SendMessage(fe->cfgbox, WM_INITDIALOG, 0, 0); EnableWindow(fe->hwnd, FALSE); ShowWindow(fe->cfgbox, SW_SHOWNORMAL); while ((gm=GetMessage(&msg, NULL, 0, 0)) > 0) { if (!IsDialogMessage(fe->cfgbox, &msg)) DispatchMessage(&msg); if (fe->dlg_done) break; } EnableWindow(fe->hwnd, TRUE); SetForegroundWindow(fe->hwnd); DestroyWindow(fe->cfgbox); DeleteObject(fe->cfgfont); free_cfg(fe->cfg); sfree(fe->cfgaux); return (fe->dlg_done == 2); #endif } #ifdef _WIN32_WCE static void calculate_bitmap_position(frontend *fe, int x, int y) { /* Pocket PC - center the game in the full screen window */ int yMargin; RECT rcClient; GetClientRect(fe->hwnd, &rcClient); fe->bitmapPosition.left = (rcClient.right - x) / 2; yMargin = rcClient.bottom - y; if (fe->numpad != NULL) { RECT rcPad; GetWindowRect(fe->numpad, &rcPad); yMargin -= rcPad.bottom - rcPad.top; } if (fe->statusbar != NULL) { RECT rcStatus; GetWindowRect(fe->statusbar, &rcStatus); yMargin -= rcStatus.bottom - rcStatus.top; } fe->bitmapPosition.top = yMargin / 2; fe->bitmapPosition.right = fe->bitmapPosition.left + x; fe->bitmapPosition.bottom = fe->bitmapPosition.top + y; } #else static void calculate_bitmap_position(frontend *fe, int x, int y) { /* Plain Windows - position the game in the upper-left corner */ fe->bitmapPosition.left = 0; fe->bitmapPosition.top = 0; fe->bitmapPosition.right = fe->bitmapPosition.left + x; fe->bitmapPosition.bottom = fe->bitmapPosition.top + y; } #endif static void new_bitmap(frontend *fe, int x, int y) { HDC hdc; if (fe->bitmap) DeleteObject(fe->bitmap); hdc = GetDC(fe->hwnd); fe->bitmap = CreateCompatibleBitmap(hdc, x, y); calculate_bitmap_position(fe, x, y); ReleaseDC(fe->hwnd, hdc); } static void new_game_size(frontend *fe, float scale) { RECT r, sr; int x, y; get_max_puzzle_size(fe, &x, &y); midend_size(fe->me, &x, &y, FALSE); if (scale != 1.0) { x = (int)((float)x * fe->puzz_scale); y = (int)((float)y * fe->puzz_scale); midend_size(fe->me, &x, &y, TRUE); } fe->ymin = (fe->xmin * y) / x; r.left = r.top = 0; r.right = x; r.bottom = y; AdjustWindowRectEx(&r, WINFLAGS, TRUE, 0); if (fe->statusbar != NULL) { GetWindowRect(fe->statusbar, &sr); } else { sr.left = sr.right = sr.top = sr.bottom = 0; } #ifndef _WIN32_WCE SetWindowPos(fe->hwnd, NULL, 0, 0, r.right - r.left, r.bottom - r.top + sr.bottom - sr.top, SWP_NOMOVE | SWP_NOZORDER); #endif check_window_size(fe, &x, &y); #ifndef _WIN32_WCE if (fe->statusbar != NULL) SetWindowPos(fe->statusbar, NULL, 0, y, x, sr.bottom - sr.top, SWP_NOZORDER); #endif new_bitmap(fe, x, y); #ifdef _WIN32_WCE InvalidateRect(fe->hwnd, NULL, TRUE); #endif midend_redraw(fe->me); } /* * Given a proposed new window rect, work out the resulting * difference in client size (from current), and use to try * and resize the puzzle, returning (wx,wy) as the actual * new window size. */ static void adjust_game_size(frontend *fe, RECT *proposed, int isedge, int *wx_r, int *wy_r) { RECT cr, wr; int nx, ny, xdiff, ydiff, wx, wy; /* Work out the current window sizing, and thus the * difference in size we're asking for. */ GetClientRect(fe->hwnd, &cr); wr = cr; AdjustWindowRectEx(&wr, WINFLAGS, TRUE, 0); xdiff = (proposed->right - proposed->left) - (wr.right - wr.left); ydiff = (proposed->bottom - proposed->top) - (wr.bottom - wr.top); if (isedge) { /* These next four lines work around the fact that midend_size * is happy to shrink _but not grow_ if you change one dimension * but not the other. */ if (xdiff > 0 && ydiff == 0) ydiff = (xdiff * (wr.right - wr.left)) / (wr.bottom - wr.top); if (xdiff == 0 && ydiff > 0) xdiff = (ydiff * (wr.bottom - wr.top)) / (wr.right - wr.left); } if (check_window_resize(fe, (cr.right - cr.left) + xdiff, (cr.bottom - cr.top) + ydiff, &nx, &ny, &wx, &wy)) { new_bitmap(fe, nx, ny); midend_force_redraw(fe->me); } else { /* reset size to current window size */ wx = wr.right - wr.left; wy = wr.bottom - wr.top; } /* Re-fetch rectangle; size limits mean we might not have * taken it quite to the mouse drag positions. */ GetClientRect(fe->hwnd, &cr); adjust_statusbar(fe, &cr); *wx_r = wx; *wy_r = wy; } static void update_type_menu_tick(frontend *fe) { int total, n, i; if (fe->typemenu == INVALID_HANDLE_VALUE) return; n = midend_which_preset(fe->me); for (i = 0; i < fe->n_preset_menuitems; i++) { if (fe->preset_menuitems[i].which_menu) { int flag = (i == n ? MF_CHECKED : MF_UNCHECKED); CheckMenuItem(fe->preset_menuitems[i].which_menu, fe->preset_menuitems[i].item_index, MF_BYPOSITION | flag); } } if (fe->game->can_configure) { int flag = (n < 0 ? MF_CHECKED : MF_UNCHECKED); /* "Custom" menu item is at the bottom of the top-level Type menu */ total = GetMenuItemCount(fe->typemenu); CheckMenuItem(fe->typemenu, total - 1, MF_BYPOSITION | flag); } DrawMenuBar(fe->hwnd); } static void update_copy_menu_greying(frontend *fe) { UINT enable = (midend_can_format_as_text_now(fe->me) ? MF_ENABLED : MF_GRAYED); EnableMenuItem(fe->gamemenu, IDM_COPY, MF_BYCOMMAND | enable); } static void new_game_type(frontend *fe) { midend_new_game(fe->me); new_game_size(fe, 1.0); update_type_menu_tick(fe); update_copy_menu_greying(fe); } static int is_alt_pressed(void) { BYTE keystate[256]; int r = GetKeyboardState(keystate); if (!r) return FALSE; if (keystate[VK_MENU] & 0x80) return TRUE; if (keystate[VK_RMENU] & 0x80) return TRUE; return FALSE; } static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { frontend *fe = (frontend *)GetWindowLong(hwnd, GWL_USERDATA); int cmd; switch (message) { case WM_CLOSE: DestroyWindow(hwnd); return 0; case WM_COMMAND: #ifdef _WIN32_WCE /* Numeric pad sends WM_COMMAND messages */ if ((wParam >= IDM_KEYEMUL) && (wParam < IDM_KEYEMUL + 256)) { midend_process_key(fe->me, 0, 0, wParam - IDM_KEYEMUL); } #endif cmd = wParam & ~0xF; /* low 4 bits reserved to Windows */ switch (cmd) { case IDM_NEW: if (!midend_process_key(fe->me, 0, 0, 'n')) PostQuitMessage(0); break; case IDM_RESTART: midend_restart_game(fe->me); break; case IDM_UNDO: if (!midend_process_key(fe->me, 0, 0, 'u')) PostQuitMessage(0); break; case IDM_REDO: if (!midend_process_key(fe->me, 0, 0, '\x12')) PostQuitMessage(0); break; case IDM_COPY: { char *text = midend_text_format(fe->me); if (text) write_clip(hwnd, text); else MessageBeep(MB_ICONWARNING); sfree(text); } break; case IDM_SOLVE: { char *msg = midend_solve(fe->me); if (msg) MessageBox(hwnd, msg, "Unable to solve", MB_ICONERROR | MB_OK); } break; case IDM_QUIT: if (!midend_process_key(fe->me, 0, 0, 'q')) PostQuitMessage(0); break; case IDM_CONFIG: if (get_config(fe, CFG_SETTINGS)) new_game_type(fe); break; case IDM_SEED: if (get_config(fe, CFG_SEED)) new_game_type(fe); break; case IDM_DESC: if (get_config(fe, CFG_DESC)) new_game_type(fe); break; case IDM_PRINT: if (get_config(fe, CFG_PRINT)) print(fe); break; case IDM_ABOUT: about(fe); break; case IDM_LOAD: case IDM_SAVE: { OPENFILENAME of; char filename[FILENAME_MAX]; int ret; memset(&of, 0, sizeof(of)); of.hwndOwner = hwnd; of.lpstrFilter = "All Files (*.*)\0*\0\0\0"; of.lpstrCustomFilter = NULL; of.nFilterIndex = 1; of.lpstrFile = filename; filename[0] = '\0'; of.nMaxFile = lenof(filename); of.lpstrFileTitle = NULL; of.lpstrTitle = (cmd == IDM_SAVE ? "Enter name of game file to save" : "Enter name of saved game file to load"); of.Flags = 0; #ifdef OPENFILENAME_SIZE_VERSION_400 of.lStructSize = OPENFILENAME_SIZE_VERSION_400; #else of.lStructSize = sizeof(of); #endif of.lpstrInitialDir = NULL; if (cmd == IDM_SAVE) ret = GetSaveFileName(&of); else ret = GetOpenFileName(&of); if (ret) { if (cmd == IDM_SAVE) { FILE *fp; if ((fp = fopen(filename, "r")) != NULL) { char buf[256 + FILENAME_MAX]; fclose(fp); /* file exists */ sprintf(buf, "Are you sure you want to overwrite" " the file \"%.*s\"?", FILENAME_MAX, filename); if (MessageBox(hwnd, buf, "Question", MB_YESNO | MB_ICONQUESTION) != IDYES) break; } fp = fopen(filename, "w"); if (!fp) { MessageBox(hwnd, "Unable to open save file", "Error", MB_ICONERROR | MB_OK); break; } midend_serialise(fe->me, savefile_write, fp); fclose(fp); } else { FILE *fp = fopen(filename, "r"); char *err = NULL; midend *me = fe->me; #ifdef COMBINED char *id_name; #endif if (!fp) { MessageBox(hwnd, "Unable to open saved game file", "Error", MB_ICONERROR | MB_OK); break; } #ifdef COMBINED /* * This save file might be from a different * game. */ err = identify_game(&id_name, savefile_read, fp); if (!err) { int i; for (i = 0; i < gamecount; i++) if (!strcmp(id_name, gamelist[i]->name)) break; if (i == gamecount) { err = "Save file is for a game not " "supported by this program"; } else { me = midend_for_new_game(fe, gamelist[i], NULL, FALSE, FALSE, &err); rewind(fp); /* for the actual load */ } sfree(id_name); } #endif if (!err) err = midend_deserialise(me, savefile_read, fp); fclose(fp); if (err) { MessageBox(hwnd, err, "Error", MB_ICONERROR|MB_OK); break; } if (fe->me != me) fe_set_midend(fe, me); new_game_size(fe, 1.0); } } } break; #ifndef _WIN32_WCE case IDM_HELPC: start_help(fe, NULL); break; case IDM_GAMEHELP: assert(help_type != NONE); start_help(fe, help_type == CHM ? fe->game->htmlhelp_topic : fe->game->winhelp_topic); break; #endif default: #ifdef COMBINED if (wParam >= IDM_GAMES && wParam < (IDM_GAMES + (WPARAM)gamecount)) { int p = wParam - IDM_GAMES; char *error = NULL; fe_set_midend(fe, midend_for_new_game(fe, gamelist[p], NULL, FALSE, FALSE, &error)); sfree(error); } else #endif { game_params *preset = preset_menu_lookup_by_id( fe->preset_menu, ((wParam &~ 0xF) - IDM_PRESETS) / 0x10); if (preset) { midend_set_params(fe->me, preset); new_game_type(fe); } } break; } break; case WM_DESTROY: #ifndef _WIN32_WCE stop_help(fe); #endif frontend_free(fe); PostQuitMessage(0); return 0; case WM_PAINT: { PAINTSTRUCT p; HDC hdc, hdc2; HBITMAP prevbm; RECT rcDest; hdc = BeginPaint(hwnd, &p); hdc2 = CreateCompatibleDC(hdc); prevbm = SelectObject(hdc2, fe->bitmap); #ifdef _WIN32_WCE FillRect(hdc, &(p.rcPaint), (HBRUSH) GetStockObject(WHITE_BRUSH)); #endif IntersectRect(&rcDest, &(fe->bitmapPosition), &(p.rcPaint)); BitBlt(hdc, rcDest.left, rcDest.top, rcDest.right - rcDest.left, rcDest.bottom - rcDest.top, hdc2, rcDest.left - fe->bitmapPosition.left, rcDest.top - fe->bitmapPosition.top, SRCCOPY); SelectObject(hdc2, prevbm); DeleteDC(hdc2); EndPaint(hwnd, &p); } return 0; case WM_KEYDOWN: { int key = -1; BYTE keystate[256]; int r = GetKeyboardState(keystate); int shift = (r && (keystate[VK_SHIFT] & 0x80)) ? MOD_SHFT : 0; int ctrl = (r && (keystate[VK_CONTROL] & 0x80)) ? MOD_CTRL : 0; switch (wParam) { case VK_LEFT: if (!(lParam & 0x01000000)) key = MOD_NUM_KEYPAD | '4'; else key = shift | ctrl | CURSOR_LEFT; break; case VK_RIGHT: if (!(lParam & 0x01000000)) key = MOD_NUM_KEYPAD | '6'; else key = shift | ctrl | CURSOR_RIGHT; break; case VK_UP: if (!(lParam & 0x01000000)) key = MOD_NUM_KEYPAD | '8'; else key = shift | ctrl | CURSOR_UP; break; case VK_DOWN: if (!(lParam & 0x01000000)) key = MOD_NUM_KEYPAD | '2'; else key = shift | ctrl | CURSOR_DOWN; break; /* * Diagonal keys on the numeric keypad. */ case VK_PRIOR: if (!(lParam & 0x01000000)) key = MOD_NUM_KEYPAD | '9'; break; case VK_NEXT: if (!(lParam & 0x01000000)) key = MOD_NUM_KEYPAD | '3'; break; case VK_HOME: if (!(lParam & 0x01000000)) key = MOD_NUM_KEYPAD | '7'; break; case VK_END: if (!(lParam & 0x01000000)) key = MOD_NUM_KEYPAD | '1'; break; case VK_INSERT: if (!(lParam & 0x01000000)) key = MOD_NUM_KEYPAD | '0'; break; case VK_CLEAR: if (!(lParam & 0x01000000)) key = MOD_NUM_KEYPAD | '5'; break; /* * Numeric keypad keys with Num Lock on. */ case VK_NUMPAD4: key = MOD_NUM_KEYPAD | '4'; break; case VK_NUMPAD6: key = MOD_NUM_KEYPAD | '6'; break; case VK_NUMPAD8: key = MOD_NUM_KEYPAD | '8'; break; case VK_NUMPAD2: key = MOD_NUM_KEYPAD | '2'; break; case VK_NUMPAD5: key = MOD_NUM_KEYPAD | '5'; break; case VK_NUMPAD9: key = MOD_NUM_KEYPAD | '9'; break; case VK_NUMPAD3: key = MOD_NUM_KEYPAD | '3'; break; case VK_NUMPAD7: key = MOD_NUM_KEYPAD | '7'; break; case VK_NUMPAD1: key = MOD_NUM_KEYPAD | '1'; break; case VK_NUMPAD0: key = MOD_NUM_KEYPAD | '0'; break; } if (key != -1) { if (!midend_process_key(fe->me, 0, 0, key)) PostQuitMessage(0); } else { MSG m; m.hwnd = hwnd; m.message = WM_KEYDOWN; m.wParam = wParam; m.lParam = lParam & 0xdfff; TranslateMessage(&m); } } break; case WM_LBUTTONDOWN: case WM_RBUTTONDOWN: case WM_MBUTTONDOWN: { int button; /* * Shift-clicks count as middle-clicks, since otherwise * two-button Windows users won't have any kind of * middle click to use. */ if (message == WM_MBUTTONDOWN || (wParam & MK_SHIFT)) button = MIDDLE_BUTTON; else if (message == WM_RBUTTONDOWN || is_alt_pressed()) button = RIGHT_BUTTON; else #ifndef _WIN32_WCE button = LEFT_BUTTON; #else if ((fe->game->flags & REQUIRE_RBUTTON) == 0) button = LEFT_BUTTON; else { SHRGINFO shrgi; shrgi.cbSize = sizeof(SHRGINFO); shrgi.hwndClient = hwnd; shrgi.ptDown.x = (signed short)LOWORD(lParam); shrgi.ptDown.y = (signed short)HIWORD(lParam); shrgi.dwFlags = SHRG_RETURNCMD; if (GN_CONTEXTMENU == SHRecognizeGesture(&shrgi)) button = RIGHT_BUTTON; else button = LEFT_BUTTON; } #endif if (!midend_process_key(fe->me, (signed short)LOWORD(lParam) - fe->bitmapPosition.left, (signed short)HIWORD(lParam) - fe->bitmapPosition.top, button)) PostQuitMessage(0); SetCapture(hwnd); } break; case WM_LBUTTONUP: case WM_RBUTTONUP: case WM_MBUTTONUP: { int button; /* * Shift-clicks count as middle-clicks, since otherwise * two-button Windows users won't have any kind of * middle click to use. */ if (message == WM_MBUTTONUP || (wParam & MK_SHIFT)) button = MIDDLE_RELEASE; else if (message == WM_RBUTTONUP || is_alt_pressed()) button = RIGHT_RELEASE; else button = LEFT_RELEASE; if (!midend_process_key(fe->me, (signed short)LOWORD(lParam) - fe->bitmapPosition.left, (signed short)HIWORD(lParam) - fe->bitmapPosition.top, button)) PostQuitMessage(0); ReleaseCapture(); } break; case WM_MOUSEMOVE: { int button; if (wParam & (MK_MBUTTON | MK_SHIFT)) button = MIDDLE_DRAG; else if (wParam & MK_RBUTTON || is_alt_pressed()) button = RIGHT_DRAG; else button = LEFT_DRAG; if (!midend_process_key(fe->me, (signed short)LOWORD(lParam) - fe->bitmapPosition.left, (signed short)HIWORD(lParam) - fe->bitmapPosition.top, button)) PostQuitMessage(0); } break; case WM_CHAR: if (!midend_process_key(fe->me, 0, 0, (unsigned char)wParam)) PostQuitMessage(0); return 0; case WM_TIMER: if (fe->timer) { DWORD now = GetTickCount(); float elapsed = (float) (now - fe->timer_last_tickcount) * 0.001F; midend_timer(fe->me, elapsed); fe->timer_last_tickcount = now; } return 0; #ifndef _WIN32_WCE case WM_SIZING: { RECT *sr = (RECT *)lParam; int wx, wy, isedge = 0; if (wParam == WMSZ_TOP || wParam == WMSZ_RIGHT || wParam == WMSZ_BOTTOM || wParam == WMSZ_LEFT) isedge = 1; adjust_game_size(fe, sr, isedge, &wx, &wy); /* Given the window size the puzzles constrain * us to, work out which edge we should be moving. */ if (wParam == WMSZ_TOP || wParam == WMSZ_TOPLEFT || wParam == WMSZ_TOPRIGHT) { sr->top = sr->bottom - wy; } else { sr->bottom = sr->top + wy; } if (wParam == WMSZ_LEFT || wParam == WMSZ_TOPLEFT || wParam == WMSZ_BOTTOMLEFT) { sr->left = sr->right - wx; } else { sr->right = sr->left + wx; } return TRUE; } break; #endif } return DefWindowProc(hwnd, message, wParam, lParam); } #ifdef _WIN32_WCE static int FindPreviousInstance() { /* Check if application is running. If it's running then focus on the window */ HWND hOtherWnd = NULL; hOtherWnd = FindWindow (wGameName, wGameName); if (hOtherWnd) { SetForegroundWindow (hOtherWnd); return TRUE; } return FALSE; } #endif /* * Split a complete command line into argc/argv, attempting to do it * exactly the same way the Visual Studio C library would do it (so * that our console utilities, which receive argc and argv already * broken apart by the C library, will have their command lines * processed in the same way as the GUI utilities which get a whole * command line and must call this function). * * Does not modify the input command line. * * The final parameter (argstart) is used to return a second array * of char * pointers, the same length as argv, each one pointing * at the start of the corresponding element of argv in the * original command line. So if you get half way through processing * your command line in argc/argv form and then decide you want to * treat the rest as a raw string, you can. If you don't want to, * `argstart' can be safely left NULL. */ void split_into_argv(char *cmdline, int *argc, char ***argv, char ***argstart) { char *p; char *outputline, *q; char **outputargv, **outputargstart; int outputargc; /* * These argument-breaking rules apply to Visual Studio 7, which * is currently the compiler expected to be used for the Windows * port of my puzzles. Visual Studio 10 has different rules, * lacking the curious mod 3 behaviour of consecutive quotes * described below; I presume they fixed a bug. As and when we * migrate to a newer compiler, we'll have to adjust this to * match; however, for the moment we faithfully imitate in our GUI * utilities what our CLI utilities can't be prevented from doing. * * When I investigated this, at first glance the rules appeared to * be: * * - Single quotes are not special characters. * * - Double quotes are removed, but within them spaces cease * to be special. * * - Backslashes are _only_ special when a sequence of them * appear just before a double quote. In this situation, * they are treated like C backslashes: so \" just gives a * literal quote, \\" gives a literal backslash and then * opens or closes a double-quoted segment, \\\" gives a * literal backslash and then a literal quote, \\\\" gives * two literal backslashes and then opens/closes a * double-quoted segment, and so forth. Note that this * behaviour is identical inside and outside double quotes. * * - Two successive double quotes become one literal double * quote, but only _inside_ a double-quoted segment. * Outside, they just form an empty double-quoted segment * (which may cause an empty argument word). * * - That only leaves the interesting question of what happens * when one or more backslashes precedes two or more double * quotes, starting inside a double-quoted string. And the * answer to that appears somewhat bizarre. Here I tabulate * number of backslashes (across the top) against number of * quotes (down the left), and indicate how many backslashes * are output, how many quotes are output, and whether a * quoted segment is open at the end of the sequence: * * backslashes * * 0 1 2 3 4 * * 0 0,0,y | 1,0,y 2,0,y 3,0,y 4,0,y * --------+----------------------------- * 1 0,0,n | 0,1,y 1,0,n 1,1,y 2,0,n * q 2 0,1,n | 0,1,n 1,1,n 1,1,n 2,1,n * u 3 0,1,y | 0,2,n 1,1,y 1,2,n 2,1,y * o 4 0,1,n | 0,2,y 1,1,n 1,2,y 2,1,n * t 5 0,2,n | 0,2,n 1,2,n 1,2,n 2,2,n * e 6 0,2,y | 0,3,n 1,2,y 1,3,n 2,2,y * s 7 0,2,n | 0,3,y 1,2,n 1,3,y 2,2,n * 8 0,3,n | 0,3,n 1,3,n 1,3,n 2,3,n * 9 0,3,y | 0,4,n 1,3,y 1,4,n 2,3,y * 10 0,3,n | 0,4,y 1,3,n 1,4,y 2,3,n * 11 0,4,n | 0,4,n 1,4,n 1,4,n 2,4,n * * * [Test fragment was of the form "a\\\"""b c" d.] * * There is very weird mod-3 behaviour going on here in the * number of quotes, and it even applies when there aren't any * backslashes! How ghastly. * * With a bit of thought, this extremely odd diagram suddenly * coalesced itself into a coherent, if still ghastly, model of * how things work: * * - As before, backslashes are only special when one or more * of them appear contiguously before at least one double * quote. In this situation the backslashes do exactly what * you'd expect: each one quotes the next thing in front of * it, so you end up with n/2 literal backslashes (if n is * even) or (n-1)/2 literal backslashes and a literal quote * (if n is odd). In the latter case the double quote * character right after the backslashes is used up. * * - After that, any remaining double quotes are processed. A * string of contiguous unescaped double quotes has a mod-3 * behaviour: * * * inside a quoted segment, a quote ends the segment. * * _immediately_ after ending a quoted segment, a quote * simply produces a literal quote. * * otherwise, outside a quoted segment, a quote begins a * quoted segment. * * So, for example, if we started inside a quoted segment * then two contiguous quotes would close the segment and * produce a literal quote; three would close the segment, * produce a literal quote, and open a new segment. If we * started outside a quoted segment, then two contiguous * quotes would open and then close a segment, producing no * output (but potentially creating a zero-length argument); * but three quotes would open and close a segment and then * produce a literal quote. */ /* * First deal with the simplest of all special cases: if there * aren't any arguments, return 0,NULL,NULL. */ while (*cmdline && isspace(*cmdline)) cmdline++; if (!*cmdline) { if (argc) *argc = 0; if (argv) *argv = NULL; if (argstart) *argstart = NULL; return; } /* * This will guaranteeably be big enough; we can realloc it * down later. */ outputline = snewn(1+strlen(cmdline), char); outputargv = snewn(strlen(cmdline)+1 / 2, char *); outputargstart = snewn(strlen(cmdline)+1 / 2, char *); p = cmdline; q = outputline; outputargc = 0; while (*p) { int quote; /* Skip whitespace searching for start of argument. */ while (*p && isspace(*p)) p++; if (!*p) break; /* We have an argument; start it. */ outputargv[outputargc] = q; outputargstart[outputargc] = p; outputargc++; quote = 0; /* Copy data into the argument until it's finished. */ while (*p) { if (!quote && isspace(*p)) break; /* argument is finished */ if (*p == '"' || *p == '\\') { /* * We have a sequence of zero or more backslashes * followed by a sequence of zero or more quotes. * Count up how many of each, and then deal with * them as appropriate. */ int i, slashes = 0, quotes = 0; while (*p == '\\') slashes++, p++; while (*p == '"') quotes++, p++; if (!quotes) { /* * Special case: if there are no quotes, * slashes are not special at all, so just copy * n slashes to the output string. */ while (slashes--) *q++ = '\\'; } else { /* Slashes annihilate in pairs. */ while (slashes >= 2) slashes -= 2, *q++ = '\\'; /* One remaining slash takes out the first quote. */ if (slashes) quotes--, *q++ = '"'; if (quotes > 0) { /* Outside a quote segment, a quote starts one. */ if (!quote) quotes--, quote = 1; /* Now we produce (n+1)/3 literal quotes... */ for (i = 3; i <= quotes+1; i += 3) *q++ = '"'; /* ... and end in a quote segment iff 3 divides n. */ quote = (quotes % 3 == 0); } } } else { *q++ = *p++; } } /* At the end of an argument, just append a trailing NUL. */ *q++ = '\0'; } outputargv = sresize(outputargv, outputargc, char *); outputargstart = sresize(outputargstart, outputargc, char *); if (argc) *argc = outputargc; if (argv) *argv = outputargv; else sfree(outputargv); if (argstart) *argstart = outputargstart; else sfree(outputargstart); } int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { MSG msg; char *error = NULL; const game *gg; frontend *fe; midend *me; int argc; char **argv; split_into_argv(cmdline, &argc, &argv, NULL); #ifdef _WIN32_WCE MultiByteToWideChar (CP_ACP, 0, CLASSNAME, -1, wClassName, 256); if (FindPreviousInstance ()) return 0; #endif InitCommonControls(); if (!prev) { WNDCLASS wndclass; wndclass.style = 0; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = inst; wndclass.hIcon = LoadIcon(inst, MAKEINTRESOURCE(200)); #ifndef _WIN32_WCE if (!wndclass.hIcon) /* in case resource file is absent */ wndclass.hIcon = LoadIcon(inst, IDI_APPLICATION); #endif wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = NULL; wndclass.lpszMenuName = NULL; #ifdef _WIN32_WCE wndclass.lpszClassName = wClassName; #else wndclass.lpszClassName = CLASSNAME; #endif RegisterClass(&wndclass); } while (*cmdline && isspace((unsigned char)*cmdline)) cmdline++; init_help(); #ifdef COMBINED gg = gamelist[0]; if (argc > 0) { int i; for (i = 0; i < gamecount; i++) { const char *p = gamelist[i]->name; char *q = argv[0]; while (*p && *q) { if (isspace((unsigned char)*p)) { while (*q && isspace((unsigned char)*q)) q++; } else { if (tolower((unsigned char)*p) != tolower((unsigned char)*q)) break; q++; } p++; } if (!*p) { gg = gamelist[i]; --argc; ++argv; break; } } } #else gg = &thegame; #endif fe = frontend_new(inst); me = midend_for_new_game(fe, gg, argc > 0 ? argv[0] : NULL, TRUE, TRUE, &error); if (!me) { char buf[128]; #ifdef COMBINED sprintf(buf, "Puzzles Error"); #else sprintf(buf, "%.100s Error", gg->name); #endif MessageBox(NULL, error, buf, MB_OK|MB_ICONERROR); sfree(error); return 1; } fe_set_midend(fe, me); show_window(fe); while (GetMessage(&msg, NULL, 0, 0)) { DispatchMessage(&msg); } DestroyWindow(fe->hwnd); cleanup_help(); return msg.wParam; } /* vim: set shiftwidth=4 tabstop=8: */ puzzles-20170606.272beef/version.c0000644000175000017500000000011613115373615015520 0ustar simonsimon/* * Puzzles version numbering. */ #include "version.h" char ver[] = VER; puzzles-20170606.272beef/untangle.c0000644000175000017500000010772513115373615015666 0ustar simonsimon/* * untangle.c: Game about planar graphs. You are given a graph * represented by points and straight lines, with some lines * crossing; your task is to drag the points into a configuration * where none of the lines cross. * * Cloned from a Flash game called `Planarity', by John Tantalo. * at the time of writing * this. The Flash game had a fixed set of levels; my added value, * as usual, is automatic generation of random games to order. */ /* * TODO: * * - This puzzle, perhaps uniquely among the collection, could use * support for non-aspect-ratio-preserving resizes. This would * require some sort of fairly large redesign, unfortunately (since * it would invalidate the basic assumption that puzzles' size * requirements are adequately expressed by a single scalar tile * size), and probably complicate the rest of the puzzles' API as a * result. So I'm not sure I really want to do it. * * - It would be nice if we could somehow auto-detect a real `long * long' type on the host platform and use it in place of my * hand-hacked int64s. It'd be faster and more reliable. */ #include #include #include #include #include #include #include "puzzles.h" #include "tree234.h" #define CIRCLE_RADIUS 6 #define DRAG_THRESHOLD (CIRCLE_RADIUS * 2) #define PREFERRED_TILESIZE 64 #define FLASH_TIME 0.30F #define ANIM_TIME 0.13F #define SOLVEANIM_TIME 0.50F enum { COL_SYSBACKGROUND, COL_BACKGROUND, COL_LINE, #ifdef SHOW_CROSSINGS COL_CROSSEDLINE, #endif COL_OUTLINE, COL_POINT, COL_DRAGPOINT, COL_NEIGHBOUR, COL_FLASH1, COL_FLASH2, NCOLOURS }; typedef struct point { /* * Points are stored using rational coordinates, with the same * denominator for both coordinates. */ long x, y, d; } point; typedef struct edge { /* * This structure is implicitly associated with a particular * point set, so all it has to do is to store two point * indices. It is required to store them in the order (lower, * higher), i.e. a < b always. */ int a, b; } edge; struct game_params { int n; /* number of points */ }; struct graph { int refcount; /* for deallocation */ tree234 *edges; /* stores `edge' structures */ }; struct game_state { game_params params; int w, h; /* extent of coordinate system only */ point *pts; #ifdef SHOW_CROSSINGS int *crosses; /* mark edges which are crossed */ #endif struct graph *graph; int completed, cheated, just_solved; }; static int edgecmpC(const void *av, const void *bv) { const edge *a = (const edge *)av; const edge *b = (const edge *)bv; if (a->a < b->a) return -1; else if (a->a > b->a) return +1; else if (a->b < b->b) return -1; else if (a->b > b->b) return +1; return 0; } static int edgecmp(void *av, void *bv) { return edgecmpC(av, bv); } static game_params *default_params(void) { game_params *ret = snew(game_params); ret->n = 10; return ret; } static int game_fetch_preset(int i, char **name, game_params **params) { game_params *ret; int n; char buf[80]; switch (i) { case 0: n = 6; break; case 1: n = 10; break; case 2: n = 15; break; case 3: n = 20; break; case 4: n = 25; break; default: return FALSE; } sprintf(buf, "%d points", n); *name = dupstr(buf); *params = ret = snew(game_params); ret->n = n; return TRUE; } static void free_params(game_params *params) { sfree(params); } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } static void decode_params(game_params *params, char const *string) { params->n = atoi(string); } static char *encode_params(const game_params *params, int full) { char buf[80]; sprintf(buf, "%d", params->n); return dupstr(buf); } static config_item *game_configure(const game_params *params) { config_item *ret; char buf[80]; ret = snewn(3, config_item); ret[0].name = "Number of points"; ret[0].type = C_STRING; sprintf(buf, "%d", params->n); ret[0].sval = dupstr(buf); ret[0].ival = 0; ret[1].name = NULL; ret[1].type = C_END; ret[1].sval = NULL; ret[1].ival = 0; return ret; } static game_params *custom_params(const config_item *cfg) { game_params *ret = snew(game_params); ret->n = atoi(cfg[0].sval); return ret; } static char *validate_params(const game_params *params, int full) { if (params->n < 4) return "Number of points must be at least four"; return NULL; } /* ---------------------------------------------------------------------- * Small number of 64-bit integer arithmetic operations, to prevent * integer overflow at the very core of cross(). */ typedef struct { long hi; unsigned long lo; } int64; #define greater64(i,j) ( (i).hi>(j).hi || ((i).hi==(j).hi && (i).lo>(j).lo)) #define sign64(i) ((i).hi < 0 ? -1 : (i).hi==0 && (i).lo==0 ? 0 : +1) static int64 mulu32to64(unsigned long x, unsigned long y) { unsigned long a, b, c, d, t; int64 ret; a = (x & 0xFFFF) * (y & 0xFFFF); b = (x & 0xFFFF) * (y >> 16); c = (x >> 16) * (y & 0xFFFF); d = (x >> 16) * (y >> 16); ret.lo = a; ret.hi = d + (b >> 16) + (c >> 16); t = (b & 0xFFFF) << 16; ret.lo += t; if (ret.lo < t) ret.hi++; t = (c & 0xFFFF) << 16; ret.lo += t; if (ret.lo < t) ret.hi++; #ifdef DIAGNOSTIC_VIA_LONGLONG assert(((unsigned long long)ret.hi << 32) + ret.lo == (unsigned long long)x * y); #endif return ret; } static int64 mul32to64(long x, long y) { int sign = +1; int64 ret; #ifdef DIAGNOSTIC_VIA_LONGLONG long long realret = (long long)x * y; #endif if (x < 0) x = -x, sign = -sign; if (y < 0) y = -y, sign = -sign; ret = mulu32to64(x, y); if (sign < 0) { ret.hi = -ret.hi; ret.lo = -ret.lo; if (ret.lo) ret.hi--; } #ifdef DIAGNOSTIC_VIA_LONGLONG assert(((unsigned long long)ret.hi << 32) + ret.lo == realret); #endif return ret; } static int64 dotprod64(long a, long b, long p, long q) { int64 ab, pq; ab = mul32to64(a, b); pq = mul32to64(p, q); ab.hi += pq.hi; ab.lo += pq.lo; if (ab.lo < pq.lo) ab.hi++; return ab; } /* * Determine whether the line segments between a1 and a2, and * between b1 and b2, intersect. We count it as an intersection if * any of the endpoints lies _on_ the other line. */ static int cross(point a1, point a2, point b1, point b2) { long b1x, b1y, b2x, b2y, px, py; int64 d1, d2, d3; /* * The condition for crossing is that b1 and b2 are on opposite * sides of the line a1-a2, and vice versa. We determine this * by taking the dot product of b1-a1 with a vector * perpendicular to a2-a1, and similarly with b2-a1, and seeing * if they have different signs. */ /* * Construct the vector b1-a1. We don't have to worry too much * about the denominator, because we're only going to check the * sign of this vector; we just need to get the numerator * right. */ b1x = b1.x * a1.d - a1.x * b1.d; b1y = b1.y * a1.d - a1.y * b1.d; /* Now construct b2-a1, and a vector perpendicular to a2-a1, * in the same way. */ b2x = b2.x * a1.d - a1.x * b2.d; b2y = b2.y * a1.d - a1.y * b2.d; px = a1.y * a2.d - a2.y * a1.d; py = a2.x * a1.d - a1.x * a2.d; /* Take the dot products. Here we resort to 64-bit arithmetic. */ d1 = dotprod64(b1x, px, b1y, py); d2 = dotprod64(b2x, px, b2y, py); /* If they have the same non-zero sign, the lines do not cross. */ if ((sign64(d1) > 0 && sign64(d2) > 0) || (sign64(d1) < 0 && sign64(d2) < 0)) return FALSE; /* * If the dot products are both exactly zero, then the two line * segments are collinear. At this point the intersection * condition becomes whether or not they overlap within their * line. */ if (sign64(d1) == 0 && sign64(d2) == 0) { /* Construct the vector a2-a1. */ px = a2.x * a1.d - a1.x * a2.d; py = a2.y * a1.d - a1.y * a2.d; /* Determine the dot products of b1-a1 and b2-a1 with this. */ d1 = dotprod64(b1x, px, b1y, py); d2 = dotprod64(b2x, px, b2y, py); /* If they're both strictly negative, the lines do not cross. */ if (sign64(d1) < 0 && sign64(d2) < 0) return FALSE; /* Otherwise, take the dot product of a2-a1 with itself. If * the other two dot products both exceed this, the lines do * not cross. */ d3 = dotprod64(px, px, py, py); if (greater64(d1, d3) && greater64(d2, d3)) return FALSE; } /* * We've eliminated the only important special case, and we * have determined that b1 and b2 are on opposite sides of the * line a1-a2. Now do the same thing the other way round and * we're done. */ b1x = a1.x * b1.d - b1.x * a1.d; b1y = a1.y * b1.d - b1.y * a1.d; b2x = a2.x * b1.d - b1.x * a2.d; b2y = a2.y * b1.d - b1.y * a2.d; px = b1.y * b2.d - b2.y * b1.d; py = b2.x * b1.d - b1.x * b2.d; d1 = dotprod64(b1x, px, b1y, py); d2 = dotprod64(b2x, px, b2y, py); if ((sign64(d1) > 0 && sign64(d2) > 0) || (sign64(d1) < 0 && sign64(d2) < 0)) return FALSE; /* * The lines must cross. */ return TRUE; } static unsigned long squarert(unsigned long n) { unsigned long d, a, b, di; d = n; a = 0; b = 1L << 30; /* largest available power of 4 */ do { a >>= 1; di = 2*a + b; if (di <= d) { d -= di; a += b; } b >>= 2; } while (b); return a; } /* * Our solutions are arranged on a square grid big enough that n * points occupy about 1/POINTDENSITY of the grid. */ #define POINTDENSITY 3 #define MAXDEGREE 4 #define COORDLIMIT(n) squarert((n) * POINTDENSITY) static void addedge(tree234 *edges, int a, int b) { edge *e = snew(edge); assert(a != b); e->a = min(a, b); e->b = max(a, b); add234(edges, e); } static int isedge(tree234 *edges, int a, int b) { edge e; assert(a != b); e.a = min(a, b); e.b = max(a, b); return find234(edges, &e, NULL) != NULL; } typedef struct vertex { int param; int vindex; } vertex; static int vertcmpC(const void *av, const void *bv) { const vertex *a = (vertex *)av; const vertex *b = (vertex *)bv; if (a->param < b->param) return -1; else if (a->param > b->param) return +1; else if (a->vindex < b->vindex) return -1; else if (a->vindex > b->vindex) return +1; return 0; } static int vertcmp(void *av, void *bv) { return vertcmpC(av, bv); } /* * Construct point coordinates for n points arranged in a circle, * within the bounding box (0,0) to (w,w). */ static void make_circle(point *pts, int n, int w) { long d, r, c, i; /* * First, decide on a denominator. Although in principle it * would be nice to set this really high so as to finely * distinguish all the points on the circle, I'm going to set * it at a fixed size to prevent integer overflow problems. */ d = PREFERRED_TILESIZE; /* * Leave a little space outside the circle. */ c = d * w / 2; r = d * w * 3 / 7; /* * Place the points. */ for (i = 0; i < n; i++) { double angle = i * 2 * PI / n; double x = r * sin(angle), y = - r * cos(angle); pts[i].x = (long)(c + x + 0.5); pts[i].y = (long)(c + y + 0.5); pts[i].d = d; } } static char *new_game_desc(const game_params *params, random_state *rs, char **aux, int interactive) { int n = params->n, i; long w, h, j, k, m; point *pts, *pts2; long *tmp; tree234 *edges, *vertices; edge *e, *e2; vertex *v, *vs, *vlist; char *ret; w = h = COORDLIMIT(n); /* * Choose n points from this grid. */ pts = snewn(n, point); tmp = snewn(w*h, long); for (i = 0; i < w*h; i++) tmp[i] = i; shuffle(tmp, w*h, sizeof(*tmp), rs); for (i = 0; i < n; i++) { pts[i].x = tmp[i] % w; pts[i].y = tmp[i] / w; pts[i].d = 1; } sfree(tmp); /* * Now start adding edges between the points. * * At all times, we attempt to add an edge to the lowest-degree * vertex we currently have, and we try the other vertices as * candidate second endpoints in order of distance from this * one. We stop as soon as we find an edge which * * (a) does not increase any vertex's degree beyond MAXDEGREE * (b) does not cross any existing edges * (c) does not intersect any actual point. */ vs = snewn(n, vertex); vertices = newtree234(vertcmp); for (i = 0; i < n; i++) { v = vs + i; v->param = 0; /* in this tree, param is the degree */ v->vindex = i; add234(vertices, v); } edges = newtree234(edgecmp); vlist = snewn(n, vertex); while (1) { int added = FALSE; for (i = 0; i < n; i++) { v = index234(vertices, i); j = v->vindex; if (v->param >= MAXDEGREE) break; /* nothing left to add! */ /* * Sort the other vertices into order of their distance * from this one. Don't bother looking below i, because * we've already tried those edges the other way round. * Also here we rule out target vertices with too high * a degree, and (of course) ones to which we already * have an edge. */ m = 0; for (k = i+1; k < n; k++) { vertex *kv = index234(vertices, k); int ki = kv->vindex; int dx, dy; if (kv->param >= MAXDEGREE || isedge(edges, ki, j)) continue; vlist[m].vindex = ki; dx = pts[ki].x - pts[j].x; dy = pts[ki].y - pts[j].y; vlist[m].param = dx*dx + dy*dy; m++; } qsort(vlist, m, sizeof(*vlist), vertcmpC); for (k = 0; k < m; k++) { int p; int ki = vlist[k].vindex; /* * Check to see whether this edge intersects any * existing edge or point. */ for (p = 0; p < n; p++) if (p != ki && p != j && cross(pts[ki], pts[j], pts[p], pts[p])) break; if (p < n) continue; for (p = 0; (e = index234(edges, p)) != NULL; p++) if (e->a != ki && e->a != j && e->b != ki && e->b != j && cross(pts[ki], pts[j], pts[e->a], pts[e->b])) break; if (e) continue; /* * We're done! Add this edge, modify the degrees of * the two vertices involved, and break. */ addedge(edges, j, ki); added = TRUE; del234(vertices, vs+j); vs[j].param++; add234(vertices, vs+j); del234(vertices, vs+ki); vs[ki].param++; add234(vertices, vs+ki); break; } if (k < m) break; } if (!added) break; /* we're done. */ } /* * That's our graph. Now shuffle the points, making sure that * they come out with at least one crossed line when arranged * in a circle (so that the puzzle isn't immediately solved!). */ tmp = snewn(n, long); for (i = 0; i < n; i++) tmp[i] = i; pts2 = snewn(n, point); make_circle(pts2, n, w); while (1) { shuffle(tmp, n, sizeof(*tmp), rs); for (i = 0; (e = index234(edges, i)) != NULL; i++) { for (j = i+1; (e2 = index234(edges, j)) != NULL; j++) { if (e2->a == e->a || e2->a == e->b || e2->b == e->a || e2->b == e->b) continue; if (cross(pts2[tmp[e2->a]], pts2[tmp[e2->b]], pts2[tmp[e->a]], pts2[tmp[e->b]])) break; } if (e2) break; } if (e) break; /* we've found a crossing */ } /* * We're done. Now encode the graph in a string format. Let's * use a comma-separated list of dash-separated vertex number * pairs, numbered from zero. We'll sort the list to prevent * side channels. */ ret = NULL; { char *sep; char buf[80]; int retlen; edge *ea; retlen = 0; m = count234(edges); ea = snewn(m, edge); for (i = 0; (e = index234(edges, i)) != NULL; i++) { assert(i < m); ea[i].a = min(tmp[e->a], tmp[e->b]); ea[i].b = max(tmp[e->a], tmp[e->b]); retlen += 1 + sprintf(buf, "%d-%d", ea[i].a, ea[i].b); } assert(i == m); qsort(ea, m, sizeof(*ea), edgecmpC); ret = snewn(retlen, char); sep = ""; k = 0; for (i = 0; i < m; i++) { k += sprintf(ret + k, "%s%d-%d", sep, ea[i].a, ea[i].b); sep = ","; } assert(k < retlen); sfree(ea); } /* * Encode the solution we started with as an aux_info string. */ { char buf[80]; char *auxstr; int auxlen; auxlen = 2; /* leading 'S' and trailing '\0' */ for (i = 0; i < n; i++) { j = tmp[i]; pts2[j] = pts[i]; if (pts2[j].d & 1) { pts2[j].x *= 2; pts2[j].y *= 2; pts2[j].d *= 2; } pts2[j].x += pts2[j].d / 2; pts2[j].y += pts2[j].d / 2; auxlen += sprintf(buf, ";P%d:%ld,%ld/%ld", i, pts2[j].x, pts2[j].y, pts2[j].d); } k = 0; auxstr = snewn(auxlen, char); auxstr[k++] = 'S'; for (i = 0; i < n; i++) k += sprintf(auxstr+k, ";P%d:%ld,%ld/%ld", i, pts2[i].x, pts2[i].y, pts2[i].d); assert(k < auxlen); *aux = auxstr; } sfree(pts2); sfree(tmp); sfree(vlist); freetree234(vertices); sfree(vs); while ((e = delpos234(edges, 0)) != NULL) sfree(e); freetree234(edges); sfree(pts); return ret; } static char *validate_desc(const game_params *params, const char *desc) { int a, b; while (*desc) { a = atoi(desc); if (a < 0 || a >= params->n) return "Number out of range in game description"; while (*desc && isdigit((unsigned char)*desc)) desc++; if (*desc != '-') return "Expected '-' after number in game description"; desc++; /* eat dash */ b = atoi(desc); if (b < 0 || b >= params->n) return "Number out of range in game description"; while (*desc && isdigit((unsigned char)*desc)) desc++; if (*desc) { if (*desc != ',') return "Expected ',' after number in game description"; desc++; /* eat comma */ } } return NULL; } static void mark_crossings(game_state *state) { int ok = TRUE; int i, j; edge *e, *e2; #ifdef SHOW_CROSSINGS for (i = 0; (e = index234(state->graph->edges, i)) != NULL; i++) state->crosses[i] = FALSE; #endif /* * Check correctness: for every pair of edges, see whether they * cross. */ for (i = 0; (e = index234(state->graph->edges, i)) != NULL; i++) { for (j = i+1; (e2 = index234(state->graph->edges, j)) != NULL; j++) { if (e2->a == e->a || e2->a == e->b || e2->b == e->a || e2->b == e->b) continue; if (cross(state->pts[e2->a], state->pts[e2->b], state->pts[e->a], state->pts[e->b])) { ok = FALSE; #ifdef SHOW_CROSSINGS state->crosses[i] = state->crosses[j] = TRUE; #else goto done; /* multi-level break - sorry */ #endif } } } /* * e == NULL if we've gone through all the edge pairs * without finding a crossing. */ #ifndef SHOW_CROSSINGS done: #endif if (ok) state->completed = TRUE; } static game_state *new_game(midend *me, const game_params *params, const char *desc) { int n = params->n; game_state *state = snew(game_state); int a, b; state->params = *params; state->w = state->h = COORDLIMIT(n); state->pts = snewn(n, point); make_circle(state->pts, n, state->w); state->graph = snew(struct graph); state->graph->refcount = 1; state->graph->edges = newtree234(edgecmp); state->completed = state->cheated = state->just_solved = FALSE; while (*desc) { a = atoi(desc); assert(a >= 0 && a < params->n); while (*desc && isdigit((unsigned char)*desc)) desc++; assert(*desc == '-'); desc++; /* eat dash */ b = atoi(desc); assert(b >= 0 && b < params->n); while (*desc && isdigit((unsigned char)*desc)) desc++; if (*desc) { assert(*desc == ','); desc++; /* eat comma */ } addedge(state->graph->edges, a, b); } #ifdef SHOW_CROSSINGS state->crosses = snewn(count234(state->graph->edges), int); mark_crossings(state); /* sets up `crosses' and `completed' */ #endif return state; } static game_state *dup_game(const game_state *state) { int n = state->params.n; game_state *ret = snew(game_state); ret->params = state->params; ret->w = state->w; ret->h = state->h; ret->pts = snewn(n, point); memcpy(ret->pts, state->pts, n * sizeof(point)); ret->graph = state->graph; ret->graph->refcount++; ret->completed = state->completed; ret->cheated = state->cheated; ret->just_solved = state->just_solved; #ifdef SHOW_CROSSINGS ret->crosses = snewn(count234(ret->graph->edges), int); memcpy(ret->crosses, state->crosses, count234(ret->graph->edges) * sizeof(int)); #endif return ret; } static void free_game(game_state *state) { if (--state->graph->refcount <= 0) { edge *e; while ((e = delpos234(state->graph->edges, 0)) != NULL) sfree(e); freetree234(state->graph->edges); sfree(state->graph); } sfree(state->pts); sfree(state); } static char *solve_game(const game_state *state, const game_state *currstate, const char *aux, char **error) { int n = state->params.n; int matrix[4]; point *pts; int i, j, besti; float bestd; char buf[80], *ret; int retlen, retsize; if (!aux) { *error = "Solution not known for this puzzle"; return NULL; } /* * Decode the aux_info to get the original point positions. */ pts = snewn(n, point); aux++; /* eat 'S' */ for (i = 0; i < n; i++) { int p, k; long x, y, d; int ret = sscanf(aux, ";P%d:%ld,%ld/%ld%n", &p, &x, &y, &d, &k); if (ret != 4 || p != i) { *error = "Internal error: aux_info badly formatted"; sfree(pts); return NULL; } pts[i].x = x; pts[i].y = y; pts[i].d = d; aux += k; } /* * Now go through eight possible symmetries of the point set. * For each one, work out the sum of the Euclidean distances * between the points' current positions and their new ones. * * We're squaring distances here, which means we're at risk of * integer overflow. Fortunately, there's no real need to be * massively careful about rounding errors, since this is a * non-essential bit of the code; so I'll just work in floats * internally. */ besti = -1; bestd = 0.0F; for (i = 0; i < 8; i++) { float d; matrix[0] = matrix[1] = matrix[2] = matrix[3] = 0; matrix[i & 1] = (i & 2) ? +1 : -1; matrix[3-(i&1)] = (i & 4) ? +1 : -1; d = 0.0F; for (j = 0; j < n; j++) { float px = (float)pts[j].x / pts[j].d; float py = (float)pts[j].y / pts[j].d; float sx = (float)currstate->pts[j].x / currstate->pts[j].d; float sy = (float)currstate->pts[j].y / currstate->pts[j].d; float cx = (float)currstate->w / 2; float cy = (float)currstate->h / 2; float ox, oy, dx, dy; px -= cx; py -= cy; ox = matrix[0] * px + matrix[1] * py; oy = matrix[2] * px + matrix[3] * py; ox += cx; oy += cy; dx = ox - sx; dy = oy - sy; d += dx*dx + dy*dy; } if (besti < 0 || bestd > d) { besti = i; bestd = d; } } assert(besti >= 0); /* * Now we know which symmetry is closest to the points' current * positions. Use it. */ matrix[0] = matrix[1] = matrix[2] = matrix[3] = 0; matrix[besti & 1] = (besti & 2) ? +1 : -1; matrix[3-(besti&1)] = (besti & 4) ? +1 : -1; retsize = 256; ret = snewn(retsize, char); retlen = 0; ret[retlen++] = 'S'; ret[retlen] = '\0'; for (i = 0; i < n; i++) { float px = (float)pts[i].x / pts[i].d; float py = (float)pts[i].y / pts[i].d; float cx = (float)currstate->w / 2; float cy = (float)currstate->h / 2; float ox, oy; int extra; px -= cx; py -= cy; ox = matrix[0] * px + matrix[1] * py; oy = matrix[2] * px + matrix[3] * py; ox += cx; oy += cy; /* * Use a fixed denominator of 2, because we know the * original points were on an integer grid offset by 1/2. */ pts[i].d = 2; ox *= pts[i].d; oy *= pts[i].d; pts[i].x = (long)(ox + 0.5F); pts[i].y = (long)(oy + 0.5F); extra = sprintf(buf, ";P%d:%ld,%ld/%ld", i, pts[i].x, pts[i].y, pts[i].d); if (retlen + extra >= retsize) { retsize = retlen + extra + 256; ret = sresize(ret, retsize, char); } strcpy(ret + retlen, buf); retlen += extra; } sfree(pts); return ret; } static int game_can_format_as_text_now(const game_params *params) { return TRUE; } static char *game_text_format(const game_state *state) { return NULL; } struct game_ui { int dragpoint; /* point being dragged; -1 if none */ point newpoint; /* where it's been dragged to so far */ int just_dragged; /* reset in game_changed_state */ int just_moved; /* _set_ in game_changed_state */ float anim_length; }; static game_ui *new_ui(const game_state *state) { game_ui *ui = snew(game_ui); ui->dragpoint = -1; ui->just_moved = ui->just_dragged = FALSE; return ui; } static void free_ui(game_ui *ui) { sfree(ui); } static char *encode_ui(const game_ui *ui) { return NULL; } static void decode_ui(game_ui *ui, const char *encoding) { } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { ui->dragpoint = -1; ui->just_moved = ui->just_dragged; ui->just_dragged = FALSE; } struct game_drawstate { long tilesize; int bg, dragpoint; long *x, *y; }; static char *interpret_move(const game_state *state, game_ui *ui, const game_drawstate *ds, int x, int y, int button) { int n = state->params.n; if (IS_MOUSE_DOWN(button)) { int i, best; long bestd; /* * Begin drag. We drag the vertex _nearest_ to the pointer, * just in case one is nearly on top of another and we want * to drag the latter. However, we drag nothing at all if * the nearest vertex is outside DRAG_THRESHOLD. */ best = -1; bestd = 0; for (i = 0; i < n; i++) { long px = state->pts[i].x * ds->tilesize / state->pts[i].d; long py = state->pts[i].y * ds->tilesize / state->pts[i].d; long dx = px - x; long dy = py - y; long d = dx*dx + dy*dy; if (best == -1 || bestd > d) { best = i; bestd = d; } } if (bestd <= DRAG_THRESHOLD * DRAG_THRESHOLD) { ui->dragpoint = best; ui->newpoint.x = x; ui->newpoint.y = y; ui->newpoint.d = ds->tilesize; return ""; } } else if (IS_MOUSE_DRAG(button) && ui->dragpoint >= 0) { ui->newpoint.x = x; ui->newpoint.y = y; ui->newpoint.d = ds->tilesize; return ""; } else if (IS_MOUSE_RELEASE(button) && ui->dragpoint >= 0) { int p = ui->dragpoint; char buf[80]; ui->dragpoint = -1; /* terminate drag, no matter what */ /* * First, see if we're within range. The user can cancel a * drag by dragging the point right off the window. */ if (ui->newpoint.x < 0 || ui->newpoint.x >= (long)state->w*ui->newpoint.d || ui->newpoint.y < 0 || ui->newpoint.y >= (long)state->h*ui->newpoint.d) return ""; /* * We aren't cancelling the drag. Construct a move string * indicating where this point is going to. */ sprintf(buf, "P%d:%ld,%ld/%ld", p, ui->newpoint.x, ui->newpoint.y, ui->newpoint.d); ui->just_dragged = TRUE; return dupstr(buf); } return NULL; } static game_state *execute_move(const game_state *state, const char *move) { int n = state->params.n; int p, k; long x, y, d; game_state *ret = dup_game(state); ret->just_solved = FALSE; while (*move) { if (*move == 'S') { move++; if (*move == ';') move++; ret->cheated = ret->just_solved = TRUE; } if (*move == 'P' && sscanf(move+1, "%d:%ld,%ld/%ld%n", &p, &x, &y, &d, &k) == 4 && p >= 0 && p < n && d > 0) { ret->pts[p].x = x; ret->pts[p].y = y; ret->pts[p].d = d; move += k+1; if (*move == ';') move++; } else { free_game(ret); return NULL; } } mark_crossings(ret); return ret; } /* ---------------------------------------------------------------------- * Drawing routines. */ static void game_compute_size(const game_params *params, int tilesize, int *x, int *y) { *x = *y = COORDLIMIT(params->n) * tilesize; } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { ds->tilesize = tilesize; } static float *game_colours(frontend *fe, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float); /* * COL_BACKGROUND is what we use as the normal background colour. * Unusually, though, it isn't colour #0: COL_SYSBACKGROUND, a bit * darker, takes that place. This means that if the user resizes * an Untangle window so as to change its aspect ratio, the * still-square playable area will be distinguished from the dead * space around it. */ game_mkhighlight(fe, ret, COL_BACKGROUND, -1, COL_SYSBACKGROUND); ret[COL_LINE * 3 + 0] = 0.0F; ret[COL_LINE * 3 + 1] = 0.0F; ret[COL_LINE * 3 + 2] = 0.0F; #ifdef SHOW_CROSSINGS ret[COL_CROSSEDLINE * 3 + 0] = 1.0F; ret[COL_CROSSEDLINE * 3 + 1] = 0.0F; ret[COL_CROSSEDLINE * 3 + 2] = 0.0F; #endif ret[COL_OUTLINE * 3 + 0] = 0.0F; ret[COL_OUTLINE * 3 + 1] = 0.0F; ret[COL_OUTLINE * 3 + 2] = 0.0F; ret[COL_POINT * 3 + 0] = 0.0F; ret[COL_POINT * 3 + 1] = 0.0F; ret[COL_POINT * 3 + 2] = 1.0F; ret[COL_DRAGPOINT * 3 + 0] = 1.0F; ret[COL_DRAGPOINT * 3 + 1] = 1.0F; ret[COL_DRAGPOINT * 3 + 2] = 1.0F; ret[COL_NEIGHBOUR * 3 + 0] = 1.0F; ret[COL_NEIGHBOUR * 3 + 1] = 0.0F; ret[COL_NEIGHBOUR * 3 + 2] = 0.0F; ret[COL_FLASH1 * 3 + 0] = 0.5F; ret[COL_FLASH1 * 3 + 1] = 0.5F; ret[COL_FLASH1 * 3 + 2] = 0.5F; ret[COL_FLASH2 * 3 + 0] = 1.0F; ret[COL_FLASH2 * 3 + 1] = 1.0F; ret[COL_FLASH2 * 3 + 2] = 1.0F; *ncolours = NCOLOURS; return ret; } static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { struct game_drawstate *ds = snew(struct game_drawstate); int i; ds->tilesize = 0; ds->x = snewn(state->params.n, long); ds->y = snewn(state->params.n, long); for (i = 0; i < state->params.n; i++) ds->x[i] = ds->y[i] = -1; ds->bg = -1; ds->dragpoint = -1; return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { sfree(ds->y); sfree(ds->x); sfree(ds); } static point mix(point a, point b, float distance) { point ret; ret.d = a.d * b.d; ret.x = (long)(a.x * b.d + distance * (b.x * a.d - a.x * b.d)); ret.y = (long)(a.y * b.d + distance * (b.y * a.d - a.y * b.d)); return ret; } static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float animtime, float flashtime) { int w, h; edge *e; int i, j; int bg, points_moved; /* * There's no terribly sensible way to do partial redraws of * this game, so I'm going to have to resort to redrawing the * whole thing every time. */ if (flashtime == 0) bg = COL_BACKGROUND; else if ((int)(flashtime * 4 / FLASH_TIME) % 2 == 0) bg = COL_FLASH1; else bg = COL_FLASH2; /* * To prevent excessive spinning on redraw during a completion * flash, we first check to see if _either_ the flash * background colour has changed _or_ at least one point has * moved _or_ a drag has begun or ended, and abandon the redraw * if neither is the case. * * Also in this loop we work out the coordinates of all the * points for this redraw. */ points_moved = FALSE; for (i = 0; i < state->params.n; i++) { point p = state->pts[i]; long x, y; if (ui->dragpoint == i) p = ui->newpoint; if (oldstate) p = mix(oldstate->pts[i], p, animtime / ui->anim_length); x = p.x * ds->tilesize / p.d; y = p.y * ds->tilesize / p.d; if (ds->x[i] != x || ds->y[i] != y) points_moved = TRUE; ds->x[i] = x; ds->y[i] = y; } if (ds->bg == bg && ds->dragpoint == ui->dragpoint && !points_moved) return; /* nothing to do */ ds->dragpoint = ui->dragpoint; ds->bg = bg; game_compute_size(&state->params, ds->tilesize, &w, &h); draw_rect(dr, 0, 0, w, h, bg); /* * Draw the edges. */ for (i = 0; (e = index234(state->graph->edges, i)) != NULL; i++) { draw_line(dr, ds->x[e->a], ds->y[e->a], ds->x[e->b], ds->y[e->b], #ifdef SHOW_CROSSINGS (oldstate?oldstate:state)->crosses[i] ? COL_CROSSEDLINE : #endif COL_LINE); } /* * Draw the points. * * When dragging, we should not only vary the colours, but * leave the point being dragged until last. */ for (j = 0; j < 3; j++) { int thisc = (j == 0 ? COL_POINT : j == 1 ? COL_NEIGHBOUR : COL_DRAGPOINT); for (i = 0; i < state->params.n; i++) { int c; if (ui->dragpoint == i) { c = COL_DRAGPOINT; } else if (ui->dragpoint >= 0 && isedge(state->graph->edges, ui->dragpoint, i)) { c = COL_NEIGHBOUR; } else { c = COL_POINT; } if (c == thisc) { #ifdef VERTEX_NUMBERS draw_circle(dr, ds->x[i], ds->y[i], DRAG_THRESHOLD, bg, bg); { char buf[80]; sprintf(buf, "%d", i); draw_text(dr, ds->x[i], ds->y[i], FONT_VARIABLE, DRAG_THRESHOLD*3/2, ALIGN_VCENTRE|ALIGN_HCENTRE, c, buf); } #else draw_circle(dr, ds->x[i], ds->y[i], CIRCLE_RADIUS, c, COL_OUTLINE); #endif } } } draw_update(dr, 0, 0, w, h); } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { if (ui->just_moved) return 0.0F; if ((dir < 0 ? oldstate : newstate)->just_solved) ui->anim_length = SOLVEANIM_TIME; else ui->anim_length = ANIM_TIME; return ui->anim_length; } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { if (!oldstate->completed && newstate->completed && !oldstate->cheated && !newstate->cheated) return FLASH_TIME; return 0.0F; } static int game_status(const game_state *state) { return state->completed ? +1 : 0; } static int game_timing_state(const game_state *state, game_ui *ui) { return TRUE; } static void game_print_size(const game_params *params, float *x, float *y) { } static void game_print(drawing *dr, const game_state *state, int tilesize) { } #ifdef COMBINED #define thegame untangle #endif const struct game thegame = { "Untangle", "games.untangle", "untangle", default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, TRUE, solve_game, FALSE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, PREFERRED_TILESIZE, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, FALSE, FALSE, game_print_size, game_print, FALSE, /* wants_statusbar */ FALSE, game_timing_state, SOLVE_ANIMATES, /* flags */ }; puzzles-20170606.272beef/unruly.c0000644000175000017500000016225313115373615015404 0ustar simonsimon/* * unruly.c: Implementation for Binary Puzzles. * (C) 2012 Lennard Sprong * Created for Simon Tatham's Portable Puzzle Collection * See LICENCE for licence details * * Objective of the game: Fill the grid with zeros and ones, with the * following rules: * - There can't be a run of three or more equal numbers. * - Each row and column contains an equal amount of zeros and ones. * * This puzzle type is known under several names, including * Tohu-Wa-Vohu, One and Two and Binairo. * * Some variants include an extra constraint, stating that no two rows or two * columns may contain the same exact sequence of zeros and ones. * This rule is rarely used, so it is not enabled in the default presets * (but it can be selected via the Custom configurer). * * More information: * http://www.janko.at/Raetsel/Tohu-Wa-Vohu/index.htm */ /* * Possible future improvements: * * More solver cleverness * * - a counting-based deduction in which you find groups of squares * which must each contain at least one of a given colour, plus * other squares which are already known to be that colour, and see * if you have any squares left over when you've worked out where * they all have to be. This is a generalisation of the current * check_near_complete: where that only covers rows with three * unfilled squares, this would handle more, such as * 0 . . 1 0 1 . . 0 . * in which each of the two-square gaps must contain a 0, and there * are three 0s placed, and that means the rightmost square can't * be a 0. * * - an 'Unreasonable' difficulty level, supporting recursion and * backtracking. */ #include #include #include #include #include #include #include "puzzles.h" #ifdef STANDALONE_SOLVER int solver_verbose = FALSE; #endif enum { COL_BACKGROUND, COL_GRID, COL_EMPTY, /* * When editing this enum, maintain the invariants * COL_n_HIGHLIGHT = COL_n + 1 * COL_n_LOWLIGHT = COL_n + 2 */ COL_0, COL_0_HIGHLIGHT, COL_0_LOWLIGHT, COL_1, COL_1_HIGHLIGHT, COL_1_LOWLIGHT, COL_CURSOR, COL_ERROR, NCOLOURS }; struct game_params { int w2, h2; /* full grid width and height respectively */ int unique; /* should row and column patterns be unique? */ int diff; }; #define DIFFLIST(A) \ A(EASY,Easy, e) \ A(NORMAL,Normal, n) \ #define ENUM(upper,title,lower) DIFF_ ## upper, #define TITLE(upper,title,lower) #title, #define ENCODE(upper,title,lower) #lower #define CONFIG(upper,title,lower) ":" #title enum { DIFFLIST(ENUM) DIFFCOUNT }; static char const *const unruly_diffnames[] = { DIFFLIST(TITLE) }; static char const unruly_diffchars[] = DIFFLIST(ENCODE); #define DIFFCONFIG DIFFLIST(CONFIG) const static struct game_params unruly_presets[] = { { 8, 8, FALSE, DIFF_EASY}, { 8, 8, FALSE, DIFF_NORMAL}, {10, 10, FALSE, DIFF_EASY}, {10, 10, FALSE, DIFF_NORMAL}, {14, 14, FALSE, DIFF_EASY}, {14, 14, FALSE, DIFF_NORMAL} }; #define DEFAULT_PRESET 0 enum { EMPTY, N_ONE, N_ZERO, BOGUS }; #define FE_HOR_ROW_LEFT 0x0001 #define FE_HOR_ROW_MID 0x0003 #define FE_HOR_ROW_RIGHT 0x0002 #define FE_VER_ROW_TOP 0x0004 #define FE_VER_ROW_MID 0x000C #define FE_VER_ROW_BOTTOM 0x0008 #define FE_COUNT 0x0010 #define FE_ROW_MATCH 0x0020 #define FE_COL_MATCH 0x0040 #define FF_ONE 0x0080 #define FF_ZERO 0x0100 #define FF_CURSOR 0x0200 #define FF_FLASH1 0x0400 #define FF_FLASH2 0x0800 #define FF_IMMUTABLE 0x1000 struct game_state { int w2, h2; int unique; char *grid; unsigned char *immutable; int completed, cheated; }; static game_params *default_params(void) { game_params *ret = snew(game_params); *ret = unruly_presets[DEFAULT_PRESET]; /* structure copy */ return ret; } static int game_fetch_preset(int i, char **name, game_params **params) { game_params *ret; char buf[80]; if (i < 0 || i >= lenof(unruly_presets)) return FALSE; ret = snew(game_params); *ret = unruly_presets[i]; /* structure copy */ sprintf(buf, "%dx%d %s", ret->w2, ret->h2, unruly_diffnames[ret->diff]); *name = dupstr(buf); *params = ret; return TRUE; } static void free_params(game_params *params) { sfree(params); } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } static void decode_params(game_params *params, char const *string) { char const *p = string; params->unique = FALSE; params->w2 = atoi(p); while (*p && isdigit((unsigned char)*p)) p++; if (*p == 'x') { p++; params->h2 = atoi(p); while (*p && isdigit((unsigned char)*p)) p++; } else { params->h2 = params->w2; } if (*p == 'u') { p++; params->unique = TRUE; } if (*p == 'd') { int i; p++; params->diff = DIFFCOUNT + 1; /* ...which is invalid */ if (*p) { for (i = 0; i < DIFFCOUNT; i++) { if (*p == unruly_diffchars[i]) params->diff = i; } p++; } } } static char *encode_params(const game_params *params, int full) { char buf[80]; sprintf(buf, "%dx%d", params->w2, params->h2); if (params->unique) strcat(buf, "u"); if (full) sprintf(buf + strlen(buf), "d%c", unruly_diffchars[params->diff]); return dupstr(buf); } static config_item *game_configure(const game_params *params) { config_item *ret; char buf[80]; ret = snewn(5, config_item); ret[0].name = "Width"; ret[0].type = C_STRING; sprintf(buf, "%d", params->w2); ret[0].sval = dupstr(buf); ret[0].ival = 0; ret[1].name = "Height"; ret[1].type = C_STRING; sprintf(buf, "%d", params->h2); ret[1].sval = dupstr(buf); ret[1].ival = 0; ret[2].name = "Unique rows and columns"; ret[2].type = C_BOOLEAN; ret[2].ival = params->unique; ret[3].name = "Difficulty"; ret[3].type = C_CHOICES; ret[3].sval = DIFFCONFIG; ret[3].ival = params->diff; ret[4].name = NULL; ret[4].type = C_END; ret[4].sval = NULL; ret[4].ival = 0; return ret; } static game_params *custom_params(const config_item *cfg) { game_params *ret = snew(game_params); ret->w2 = atoi(cfg[0].sval); ret->h2 = atoi(cfg[1].sval); ret->unique = cfg[2].ival; ret->diff = cfg[3].ival; return ret; } static char *validate_params(const game_params *params, int full) { if ((params->w2 & 1) || (params->h2 & 1)) return "Width and height must both be even"; if (params->w2 < 6 || params->h2 < 6) return "Width and height must be at least 6"; if (params->unique) { static const long A177790[] = { /* * The nth element of this array gives the number of * distinct possible Unruly rows of length 2n (that is, * containing exactly n 1s and n 0s and not containing * three consecutive elements the same) for as long as * those numbers fit in a 32-bit signed int. * * So in unique-rows mode, if the puzzle width is 2n, then * the height must be at most (this array)[n], and vice * versa. * * This is sequence A177790 in the Online Encyclopedia of * Integer Sequences: http://oeis.org/A177790 */ 1L, 2L, 6L, 14L, 34L, 84L, 208L, 518L, 1296L, 3254L, 8196L, 20700L, 52404L, 132942L, 337878L, 860142L, 2192902L, 5598144L, 14308378L, 36610970L, 93770358L, 240390602L, 616787116L, 1583765724L }; if (params->w2 < 2*lenof(A177790) && params->h2 > A177790[params->w2/2]) { return "Puzzle is too tall for unique-rows mode"; } if (params->h2 < 2*lenof(A177790) && params->w2 > A177790[params->h2/2]) { return "Puzzle is too long for unique-rows mode"; } } if (params->diff >= DIFFCOUNT) return "Unknown difficulty rating"; return NULL; } static char *validate_desc(const game_params *params, const char *desc) { int w2 = params->w2, h2 = params->h2; int s = w2 * h2; const char *p = desc; int pos = 0; while (*p) { if (*p >= 'a' && *p < 'z') pos += 1 + (*p - 'a'); else if (*p >= 'A' && *p < 'Z') pos += 1 + (*p - 'A'); else if (*p == 'Z' || *p == 'z') pos += 25; else return "Description contains invalid characters"; ++p; } if (pos < s+1) return "Description too short"; if (pos > s+1) return "Description too long"; return NULL; } static game_state *blank_state(int w2, int h2, int unique) { game_state *state = snew(game_state); int s = w2 * h2; state->w2 = w2; state->h2 = h2; state->unique = unique; state->grid = snewn(s, char); state->immutable = snewn(s, unsigned char); memset(state->grid, EMPTY, s); memset(state->immutable, FALSE, s); state->completed = state->cheated = FALSE; return state; } static game_state *new_game(midend *me, const game_params *params, const char *desc) { int w2 = params->w2, h2 = params->h2; int s = w2 * h2; game_state *state = blank_state(w2, h2, params->unique); const char *p = desc; int pos = 0; while (*p) { if (*p >= 'a' && *p < 'z') { pos += (*p - 'a'); if (pos < s) { state->grid[pos] = N_ZERO; state->immutable[pos] = TRUE; } pos++; } else if (*p >= 'A' && *p < 'Z') { pos += (*p - 'A'); if (pos < s) { state->grid[pos] = N_ONE; state->immutable[pos] = TRUE; } pos++; } else if (*p == 'Z' || *p == 'z') { pos += 25; } else assert(!"Description contains invalid characters"); ++p; } assert(pos == s+1); return state; } static game_state *dup_game(const game_state *state) { int w2 = state->w2, h2 = state->h2; int s = w2 * h2; game_state *ret = blank_state(w2, h2, state->unique); memcpy(ret->grid, state->grid, s); memcpy(ret->immutable, state->immutable, s); ret->completed = state->completed; ret->cheated = state->cheated; return ret; } static void free_game(game_state *state) { sfree(state->grid); sfree(state->immutable); sfree(state); } static int game_can_format_as_text_now(const game_params *params) { return TRUE; } static char *game_text_format(const game_state *state) { int w2 = state->w2, h2 = state->h2; int lr = w2*2 + 1; char *ret = snewn(lr * h2 + 1, char); char *p = ret; int x, y; for (y = 0; y < h2; y++) { for (x = 0; x < w2; x++) { /* Place number */ char c = state->grid[y * w2 + x]; *p++ = (c == N_ONE ? '1' : c == N_ZERO ? '0' : '.'); *p++ = ' '; } /* End line */ *p++ = '\n'; } /* End with NUL */ *p++ = '\0'; return ret; } /* ****** * * Solver * * ****** */ struct unruly_scratch { int *ones_rows; int *ones_cols; int *zeros_rows; int *zeros_cols; }; static void unruly_solver_update_remaining(const game_state *state, struct unruly_scratch *scratch) { int w2 = state->w2, h2 = state->h2; int x, y; /* Reset all scratch data */ memset(scratch->ones_rows, 0, h2 * sizeof(int)); memset(scratch->ones_cols, 0, w2 * sizeof(int)); memset(scratch->zeros_rows, 0, h2 * sizeof(int)); memset(scratch->zeros_cols, 0, w2 * sizeof(int)); for (x = 0; x < w2; x++) for (y = 0; y < h2; y++) { if (state->grid[y * w2 + x] == N_ONE) { scratch->ones_rows[y]++; scratch->ones_cols[x]++; } else if (state->grid[y * w2 + x] == N_ZERO) { scratch->zeros_rows[y]++; scratch->zeros_cols[x]++; } } } static struct unruly_scratch *unruly_new_scratch(const game_state *state) { int w2 = state->w2, h2 = state->h2; struct unruly_scratch *ret = snew(struct unruly_scratch); ret->ones_rows = snewn(h2, int); ret->ones_cols = snewn(w2, int); ret->zeros_rows = snewn(h2, int); ret->zeros_cols = snewn(w2, int); unruly_solver_update_remaining(state, ret); return ret; } static void unruly_free_scratch(struct unruly_scratch *scratch) { sfree(scratch->ones_rows); sfree(scratch->ones_cols); sfree(scratch->zeros_rows); sfree(scratch->zeros_cols); sfree(scratch); } static int unruly_solver_check_threes(game_state *state, int *rowcount, int *colcount, int horizontal, char check, char block) { int w2 = state->w2, h2 = state->h2; int dx = horizontal ? 1 : 0, dy = 1 - dx; int sx = dx, sy = dy; int ex = w2 - dx, ey = h2 - dy; int x, y; int ret = 0; /* Check for any three squares which almost form three in a row */ for (y = sy; y < ey; y++) { for (x = sx; x < ex; x++) { int i1 = (y-dy) * w2 + (x-dx); int i2 = y * w2 + x; int i3 = (y+dy) * w2 + (x+dx); if (state->grid[i1] == check && state->grid[i2] == check && state->grid[i3] == EMPTY) { ret++; #ifdef STANDALONE_SOLVER if (solver_verbose) { printf("Solver: %i,%i and %i,%i confirm %c at %i,%i\n", i1 % w2, i1 / w2, i2 % w2, i2 / w2, (block == N_ONE ? '1' : '0'), i3 % w2, i3 / w2); } #endif state->grid[i3] = block; rowcount[i3 / w2]++; colcount[i3 % w2]++; } if (state->grid[i1] == check && state->grid[i2] == EMPTY && state->grid[i3] == check) { ret++; #ifdef STANDALONE_SOLVER if (solver_verbose) { printf("Solver: %i,%i and %i,%i confirm %c at %i,%i\n", i1 % w2, i1 / w2, i3 % w2, i3 / w2, (block == N_ONE ? '1' : '0'), i2 % w2, i2 / w2); } #endif state->grid[i2] = block; rowcount[i2 / w2]++; colcount[i2 % w2]++; } if (state->grid[i1] == EMPTY && state->grid[i2] == check && state->grid[i3] == check) { ret++; #ifdef STANDALONE_SOLVER if (solver_verbose) { printf("Solver: %i,%i and %i,%i confirm %c at %i,%i\n", i2 % w2, i2 / w2, i3 % w2, i3 / w2, (block == N_ONE ? '1' : '0'), i1 % w2, i1 / w2); } #endif state->grid[i1] = block; rowcount[i1 / w2]++; colcount[i1 % w2]++; } } } return ret; } static int unruly_solver_check_all_threes(game_state *state, struct unruly_scratch *scratch) { int ret = 0; ret += unruly_solver_check_threes(state, scratch->zeros_rows, scratch->zeros_cols, TRUE, N_ONE, N_ZERO); ret += unruly_solver_check_threes(state, scratch->ones_rows, scratch->ones_cols, TRUE, N_ZERO, N_ONE); ret += unruly_solver_check_threes(state, scratch->zeros_rows, scratch->zeros_cols, FALSE, N_ONE, N_ZERO); ret += unruly_solver_check_threes(state, scratch->ones_rows, scratch->ones_cols, FALSE, N_ZERO, N_ONE); return ret; } static int unruly_solver_check_uniques(game_state *state, int *rowcount, int horizontal, char check, char block, struct unruly_scratch *scratch) { int w2 = state->w2, h2 = state->h2; int rmult = (horizontal ? w2 : 1); int cmult = (horizontal ? 1 : w2); int nr = (horizontal ? h2 : w2); int nc = (horizontal ? w2 : h2); int max = nc / 2; int r, r2, c; int ret = 0; /* * Find each row that has max entries of type 'check', and see if * all those entries match those in any row with max-1 entries. If * so, set the last non-matching entry of the latter row to ensure * that it's different. */ for (r = 0; r < nr; r++) { if (rowcount[r] != max) continue; for (r2 = 0; r2 < nr; r2++) { int nmatch = 0, nonmatch = -1; if (rowcount[r2] != max-1) continue; for (c = 0; c < nc; c++) { if (state->grid[r*rmult + c*cmult] == check) { if (state->grid[r2*rmult + c*cmult] == check) nmatch++; else nonmatch = c; } } if (nmatch == max-1) { int i1 = r2 * rmult + nonmatch * cmult; assert(nonmatch != -1); if (state->grid[i1] == block) continue; assert(state->grid[i1] == EMPTY); #ifdef STANDALONE_SOLVER if (solver_verbose) { printf("Solver: matching %s %i, %i gives %c at %i,%i\n", horizontal ? "rows" : "cols", r, r2, (block == N_ONE ? '1' : '0'), i1 % w2, i1 / w2); } #endif state->grid[i1] = block; if (block == N_ONE) { scratch->ones_rows[i1 / w2]++; scratch->ones_cols[i1 % w2]++; } else { scratch->zeros_rows[i1 / w2]++; scratch->zeros_cols[i1 % w2]++; } ret++; } } } return ret; } static int unruly_solver_check_all_uniques(game_state *state, struct unruly_scratch *scratch) { int ret = 0; ret += unruly_solver_check_uniques(state, scratch->ones_rows, TRUE, N_ONE, N_ZERO, scratch); ret += unruly_solver_check_uniques(state, scratch->zeros_rows, TRUE, N_ZERO, N_ONE, scratch); ret += unruly_solver_check_uniques(state, scratch->ones_cols, FALSE, N_ONE, N_ZERO, scratch); ret += unruly_solver_check_uniques(state, scratch->zeros_cols, FALSE, N_ZERO, N_ONE, scratch); return ret; } static int unruly_solver_fill_row(game_state *state, int i, int horizontal, int *rowcount, int *colcount, char fill) { int ret = 0; int w2 = state->w2, h2 = state->h2; int j; #ifdef STANDALONE_SOLVER if (solver_verbose) { printf("Solver: Filling %s %i with %c:", (horizontal ? "Row" : "Col"), i, (fill == N_ZERO ? '0' : '1')); } #endif /* Place a number in every empty square in a row/column */ for (j = 0; j < (horizontal ? w2 : h2); j++) { int p = (horizontal ? i * w2 + j : j * w2 + i); if (state->grid[p] == EMPTY) { #ifdef STANDALONE_SOLVER if (solver_verbose) { printf(" (%i,%i)", (horizontal ? j : i), (horizontal ? i : j)); } #endif ret++; state->grid[p] = fill; rowcount[(horizontal ? i : j)]++; colcount[(horizontal ? j : i)]++; } } #ifdef STANDALONE_SOLVER if (solver_verbose) { printf("\n"); } #endif return ret; } static int unruly_solver_check_complete_nums(game_state *state, int *complete, int horizontal, int *rowcount, int *colcount, char fill) { int w2 = state->w2, h2 = state->h2; int count = (horizontal ? h2 : w2); /* number of rows to check */ int target = (horizontal ? w2 : h2) / 2; /* target number of 0s/1s */ int *other = (horizontal ? rowcount : colcount); int ret = 0; int i; /* Check for completed rows/cols for one number, then fill in the rest */ for (i = 0; i < count; i++) { if (complete[i] == target && other[i] < target) { #ifdef STANDALONE_SOLVER if (solver_verbose) { printf("Solver: Row %i satisfied for %c\n", i, (fill != N_ZERO ? '0' : '1')); } #endif ret += unruly_solver_fill_row(state, i, horizontal, rowcount, colcount, fill); } } return ret; } static int unruly_solver_check_all_complete_nums(game_state *state, struct unruly_scratch *scratch) { int ret = 0; ret += unruly_solver_check_complete_nums(state, scratch->ones_rows, TRUE, scratch->zeros_rows, scratch->zeros_cols, N_ZERO); ret += unruly_solver_check_complete_nums(state, scratch->ones_cols, FALSE, scratch->zeros_rows, scratch->zeros_cols, N_ZERO); ret += unruly_solver_check_complete_nums(state, scratch->zeros_rows, TRUE, scratch->ones_rows, scratch->ones_cols, N_ONE); ret += unruly_solver_check_complete_nums(state, scratch->zeros_cols, FALSE, scratch->ones_rows, scratch->ones_cols, N_ONE); return ret; } static int unruly_solver_check_near_complete(game_state *state, int *complete, int horizontal, int *rowcount, int *colcount, char fill) { int w2 = state->w2, h2 = state->h2; int w = w2/2, h = h2/2; int dx = horizontal ? 1 : 0, dy = 1 - dx; int sx = dx, sy = dy; int ex = w2 - dx, ey = h2 - dy; int x, y; int ret = 0; /* * This function checks for a row with one Y remaining, then looks * for positions that could cause the remaining squares in the row * to make 3 X's in a row. Example: * * Consider the following row: * 1 1 0 . . . * If the last 1 was placed in the last square, the remaining * squares would be 0: * 1 1 0 0 0 1 * This violates the 3 in a row rule. We now know that the last 1 * shouldn't be in the last cell. * 1 1 0 . . 0 */ /* Check for any two blank and one filled square */ for (y = sy; y < ey; y++) { /* One type must have 1 remaining, the other at least 2 */ if (horizontal && (complete[y] < w - 1 || rowcount[y] > w - 2)) continue; for (x = sx; x < ex; x++) { int i, i1, i2, i3; if (!horizontal && (complete[x] < h - 1 || colcount[x] > h - 2)) continue; i = (horizontal ? y : x); i1 = (y-dy) * w2 + (x-dx); i2 = y * w2 + x; i3 = (y+dy) * w2 + (x+dx); if (state->grid[i1] == fill && state->grid[i2] == EMPTY && state->grid[i3] == EMPTY) { /* * Temporarily fill the empty spaces with something else. * This avoids raising the counts for the row and column */ state->grid[i2] = BOGUS; state->grid[i3] = BOGUS; #ifdef STANDALONE_SOLVER if (solver_verbose) { printf("Solver: Row %i nearly satisfied for %c\n", i, (fill != N_ZERO ? '0' : '1')); } #endif ret += unruly_solver_fill_row(state, i, horizontal, rowcount, colcount, fill); state->grid[i2] = EMPTY; state->grid[i3] = EMPTY; } else if (state->grid[i1] == EMPTY && state->grid[i2] == fill && state->grid[i3] == EMPTY) { state->grid[i1] = BOGUS; state->grid[i3] = BOGUS; #ifdef STANDALONE_SOLVER if (solver_verbose) { printf("Solver: Row %i nearly satisfied for %c\n", i, (fill != N_ZERO ? '0' : '1')); } #endif ret += unruly_solver_fill_row(state, i, horizontal, rowcount, colcount, fill); state->grid[i1] = EMPTY; state->grid[i3] = EMPTY; } else if (state->grid[i1] == EMPTY && state->grid[i2] == EMPTY && state->grid[i3] == fill) { state->grid[i1] = BOGUS; state->grid[i2] = BOGUS; #ifdef STANDALONE_SOLVER if (solver_verbose) { printf("Solver: Row %i nearly satisfied for %c\n", i, (fill != N_ZERO ? '0' : '1')); } #endif ret += unruly_solver_fill_row(state, i, horizontal, rowcount, colcount, fill); state->grid[i1] = EMPTY; state->grid[i2] = EMPTY; } else if (state->grid[i1] == EMPTY && state->grid[i2] == EMPTY && state->grid[i3] == EMPTY) { state->grid[i1] = BOGUS; state->grid[i2] = BOGUS; state->grid[i3] = BOGUS; #ifdef STANDALONE_SOLVER if (solver_verbose) { printf("Solver: Row %i nearly satisfied for %c\n", i, (fill != N_ZERO ? '0' : '1')); } #endif ret += unruly_solver_fill_row(state, i, horizontal, rowcount, colcount, fill); state->grid[i1] = EMPTY; state->grid[i2] = EMPTY; state->grid[i3] = EMPTY; } } } return ret; } static int unruly_solver_check_all_near_complete(game_state *state, struct unruly_scratch *scratch) { int ret = 0; ret += unruly_solver_check_near_complete(state, scratch->ones_rows, TRUE, scratch->zeros_rows, scratch->zeros_cols, N_ZERO); ret += unruly_solver_check_near_complete(state, scratch->ones_cols, FALSE, scratch->zeros_rows, scratch->zeros_cols, N_ZERO); ret += unruly_solver_check_near_complete(state, scratch->zeros_rows, TRUE, scratch->ones_rows, scratch->ones_cols, N_ONE); ret += unruly_solver_check_near_complete(state, scratch->zeros_cols, FALSE, scratch->ones_rows, scratch->ones_cols, N_ONE); return ret; } static int unruly_validate_rows(const game_state *state, int horizontal, char check, int *errors) { int w2 = state->w2, h2 = state->h2; int dx = horizontal ? 1 : 0, dy = 1 - dx; int sx = dx, sy = dy; int ex = w2 - dx, ey = h2 - dy; int x, y; int ret = 0; int err1 = (horizontal ? FE_HOR_ROW_LEFT : FE_VER_ROW_TOP); int err2 = (horizontal ? FE_HOR_ROW_MID : FE_VER_ROW_MID); int err3 = (horizontal ? FE_HOR_ROW_RIGHT : FE_VER_ROW_BOTTOM); /* Check for any three in a row, and mark errors accordingly (if * required) */ for (y = sy; y < ey; y++) { for (x = sx; x < ex; x++) { int i1 = (y-dy) * w2 + (x-dx); int i2 = y * w2 + x; int i3 = (y+dy) * w2 + (x+dx); if (state->grid[i1] == check && state->grid[i2] == check && state->grid[i3] == check) { ret++; if (errors) { errors[i1] |= err1; errors[i2] |= err2; errors[i3] |= err3; } } } } return ret; } static int unruly_validate_unique(const game_state *state, int horizontal, int *errors) { int w2 = state->w2, h2 = state->h2; int rmult = (horizontal ? w2 : 1); int cmult = (horizontal ? 1 : w2); int nr = (horizontal ? h2 : w2); int nc = (horizontal ? w2 : h2); int err = (horizontal ? FE_ROW_MATCH : FE_COL_MATCH); int r, r2, c; int ret = 0; /* Check for any two full rows matching exactly, and mark errors * accordingly (if required) */ for (r = 0; r < nr; r++) { int nfull = 0; for (c = 0; c < nc; c++) if (state->grid[r*rmult + c*cmult] != EMPTY) nfull++; if (nfull != nc) continue; for (r2 = r+1; r2 < nr; r2++) { int match = TRUE; for (c = 0; c < nc; c++) if (state->grid[r*rmult + c*cmult] != state->grid[r2*rmult + c*cmult]) match = FALSE; if (match) { if (errors) { for (c = 0; c < nc; c++) { errors[r*rmult + c*cmult] |= err; errors[r2*rmult + c*cmult] |= err; } } ret++; } } } return ret; } static int unruly_validate_all_rows(const game_state *state, int *errors) { int errcount = 0; errcount += unruly_validate_rows(state, TRUE, N_ONE, errors); errcount += unruly_validate_rows(state, FALSE, N_ONE, errors); errcount += unruly_validate_rows(state, TRUE, N_ZERO, errors); errcount += unruly_validate_rows(state, FALSE, N_ZERO, errors); if (state->unique) { errcount += unruly_validate_unique(state, TRUE, errors); errcount += unruly_validate_unique(state, FALSE, errors); } if (errcount) return -1; return 0; } static int unruly_validate_counts(const game_state *state, struct unruly_scratch *scratch, int *errors) { int w2 = state->w2, h2 = state->h2; int w = w2/2, h = h2/2; char below = FALSE; char above = FALSE; int i; /* See if all rows/columns are satisfied. If one is exceeded, * mark it as an error (if required) */ char hasscratch = TRUE; if (!scratch) { scratch = unruly_new_scratch(state); hasscratch = FALSE; } for (i = 0; i < w2; i++) { if (scratch->ones_cols[i] < h) below = TRUE; if (scratch->zeros_cols[i] < h) below = TRUE; if (scratch->ones_cols[i] > h) { above = TRUE; if (errors) errors[2*h2 + i] = TRUE; } else if (errors) errors[2*h2 + i] = FALSE; if (scratch->zeros_cols[i] > h) { above = TRUE; if (errors) errors[2*h2 + w2 + i] = TRUE; } else if (errors) errors[2*h2 + w2 + i] = FALSE; } for (i = 0; i < h2; i++) { if (scratch->ones_rows[i] < w) below = TRUE; if (scratch->zeros_rows[i] < w) below = TRUE; if (scratch->ones_rows[i] > w) { above = TRUE; if (errors) errors[i] = TRUE; } else if (errors) errors[i] = FALSE; if (scratch->zeros_rows[i] > w) { above = TRUE; if (errors) errors[h2 + i] = TRUE; } else if (errors) errors[h2 + i] = FALSE; } if (!hasscratch) unruly_free_scratch(scratch); return (above ? -1 : below ? 1 : 0); } static int unruly_solve_game(game_state *state, struct unruly_scratch *scratch, int diff) { int done, maxdiff = -1; while (TRUE) { done = 0; /* Check for impending 3's */ done += unruly_solver_check_all_threes(state, scratch); /* Keep using the simpler techniques while they produce results */ if (done) { if (maxdiff < DIFF_EASY) maxdiff = DIFF_EASY; continue; } /* Check for completed rows */ done += unruly_solver_check_all_complete_nums(state, scratch); if (done) { if (maxdiff < DIFF_EASY) maxdiff = DIFF_EASY; continue; } /* Check for impending failures of row/column uniqueness, if * it's enabled in this game mode */ if (state->unique) { done += unruly_solver_check_all_uniques(state, scratch); if (done) { if (maxdiff < DIFF_EASY) maxdiff = DIFF_EASY; continue; } } /* Normal techniques */ if (diff < DIFF_NORMAL) break; /* Check for nearly completed rows */ done += unruly_solver_check_all_near_complete(state, scratch); if (done) { if (maxdiff < DIFF_NORMAL) maxdiff = DIFF_NORMAL; continue; } break; } return maxdiff; } static char *solve_game(const game_state *state, const game_state *currstate, const char *aux, char **error) { game_state *solved = dup_game(state); struct unruly_scratch *scratch = unruly_new_scratch(solved); char *ret = NULL; int result; unruly_solve_game(solved, scratch, DIFFCOUNT); result = unruly_validate_counts(solved, scratch, NULL); if (unruly_validate_all_rows(solved, NULL) == -1) result = -1; if (result == 0) { int w2 = solved->w2, h2 = solved->h2; int s = w2 * h2; char *p; int i; ret = snewn(s + 2, char); p = ret; *p++ = 'S'; for (i = 0; i < s; i++) *p++ = (solved->grid[i] == N_ONE ? '1' : '0'); *p++ = '\0'; } else if (result == 1) *error = "No solution found."; else if (result == -1) *error = "Puzzle is invalid."; free_game(solved); unruly_free_scratch(scratch); return ret; } /* ********* * * Generator * * ********* */ static int unruly_fill_game(game_state *state, struct unruly_scratch *scratch, random_state *rs) { int w2 = state->w2, h2 = state->h2; int s = w2 * h2; int i, j; int *spaces; #ifdef STANDALONE_SOLVER if (solver_verbose) { printf("Generator: Attempt to fill grid\n"); } #endif /* Generate random array of spaces */ spaces = snewn(s, int); for (i = 0; i < s; i++) spaces[i] = i; shuffle(spaces, s, sizeof(*spaces), rs); /* * Construct a valid filled grid by repeatedly picking an unfilled * space and fill it, then calling the solver to fill in any * spaces forced by the change. */ for (j = 0; j < s; j++) { i = spaces[j]; if (state->grid[i] != EMPTY) continue; if (random_upto(rs, 2)) { state->grid[i] = N_ONE; scratch->ones_rows[i / w2]++; scratch->ones_cols[i % w2]++; } else { state->grid[i] = N_ZERO; scratch->zeros_rows[i / w2]++; scratch->zeros_cols[i % w2]++; } unruly_solve_game(state, scratch, DIFFCOUNT); } sfree(spaces); if (unruly_validate_all_rows(state, NULL) != 0 || unruly_validate_counts(state, scratch, NULL) != 0) return FALSE; return TRUE; } static char *new_game_desc(const game_params *params, random_state *rs, char **aux, int interactive) { #ifdef STANDALONE_SOLVER char *debug; int temp_verbose = FALSE; #endif int w2 = params->w2, h2 = params->h2; int s = w2 * h2; int *spaces; int i, j, run; char *ret, *p; game_state *state; struct unruly_scratch *scratch; int attempts = 0; while (1) { while (TRUE) { attempts++; state = blank_state(w2, h2, params->unique); scratch = unruly_new_scratch(state); if (unruly_fill_game(state, scratch, rs)) break; free_game(state); unruly_free_scratch(scratch); } #ifdef STANDALONE_SOLVER if (solver_verbose) { printf("Puzzle generated in %i attempts\n", attempts); debug = game_text_format(state); fputs(debug, stdout); sfree(debug); temp_verbose = solver_verbose; solver_verbose = FALSE; } #endif unruly_free_scratch(scratch); /* Generate random array of spaces */ spaces = snewn(s, int); for (i = 0; i < s; i++) spaces[i] = i; shuffle(spaces, s, sizeof(*spaces), rs); /* * Winnow the clues by starting from our filled grid, repeatedly * picking a filled space and emptying it, as long as the solver * reports that the puzzle can still be solved after doing so. */ for (j = 0; j < s; j++) { char c; game_state *solver; i = spaces[j]; c = state->grid[i]; state->grid[i] = EMPTY; solver = dup_game(state); scratch = unruly_new_scratch(state); unruly_solve_game(solver, scratch, params->diff); if (unruly_validate_counts(solver, scratch, NULL) != 0) state->grid[i] = c; free_game(solver); unruly_free_scratch(scratch); } sfree(spaces); #ifdef STANDALONE_SOLVER if (temp_verbose) { solver_verbose = TRUE; printf("Final puzzle:\n"); debug = game_text_format(state); fputs(debug, stdout); sfree(debug); } #endif /* * See if the game has accidentally come out too easy. */ if (params->diff > 0) { int ok; game_state *solver; solver = dup_game(state); scratch = unruly_new_scratch(state); unruly_solve_game(solver, scratch, params->diff - 1); ok = unruly_validate_counts(solver, scratch, NULL); free_game(solver); unruly_free_scratch(scratch); if (ok) break; } else { /* * Puzzles of the easiest difficulty can't be too easy. */ break; } } /* Encode description */ ret = snewn(s + 1, char); p = ret; run = 0; for (i = 0; i < s+1; i++) { if (i == s || state->grid[i] == N_ZERO) { while (run > 24) { *p++ = 'z'; run -= 25; } *p++ = 'a' + run; run = 0; } else if (state->grid[i] == N_ONE) { while (run > 24) { *p++ = 'Z'; run -= 25; } *p++ = 'A' + run; run = 0; } else { run++; } } *p = '\0'; free_game(state); return ret; } /* ************** * * User Interface * * ************** */ struct game_ui { int cx, cy; char cursor; }; static game_ui *new_ui(const game_state *state) { game_ui *ret = snew(game_ui); ret->cx = ret->cy = 0; ret->cursor = FALSE; return ret; } static void free_ui(game_ui *ui) { sfree(ui); } static char *encode_ui(const game_ui *ui) { return NULL; } static void decode_ui(game_ui *ui, const char *encoding) { } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { } struct game_drawstate { int tilesize; int w2, h2; int started; int *gridfs; int *rowfs; int *grid; }; static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { struct game_drawstate *ds = snew(struct game_drawstate); int w2 = state->w2, h2 = state->h2; int s = w2 * h2; int i; ds->tilesize = 0; ds->w2 = w2; ds->h2 = h2; ds->started = FALSE; ds->gridfs = snewn(s, int); ds->rowfs = snewn(2 * (w2 + h2), int); ds->grid = snewn(s, int); for (i = 0; i < s; i++) ds->grid[i] = -1; return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { sfree(ds->gridfs); sfree(ds->rowfs); sfree(ds->grid); sfree(ds); } #define COORD(x) ( (x) * ds->tilesize + ds->tilesize/2 ) #define FROMCOORD(x) ( ((x)-(ds->tilesize/2)) / ds->tilesize ) static char *interpret_move(const game_state *state, game_ui *ui, const game_drawstate *ds, int ox, int oy, int button) { int hx = ui->cx; int hy = ui->cy; int gx = FROMCOORD(ox); int gy = FROMCOORD(oy); int w2 = state->w2, h2 = state->h2; button &= ~MOD_MASK; /* Mouse click */ if (button == LEFT_BUTTON || button == RIGHT_BUTTON || button == MIDDLE_BUTTON) { if (ox >= (ds->tilesize / 2) && gx < w2 && oy >= (ds->tilesize / 2) && gy < h2) { hx = gx; hy = gy; ui->cursor = FALSE; } else return NULL; } /* Keyboard move */ if (IS_CURSOR_MOVE(button)) { move_cursor(button, &ui->cx, &ui->cy, w2, h2, 0); ui->cursor = TRUE; return ""; } /* Place one */ if ((ui->cursor && (button == CURSOR_SELECT || button == CURSOR_SELECT2 || button == '\b' || button == '0' || button == '1' || button == '2')) || button == LEFT_BUTTON || button == RIGHT_BUTTON || button == MIDDLE_BUTTON) { char buf[80]; char c, i; if (state->immutable[hy * w2 + hx]) return NULL; c = '-'; i = state->grid[hy * w2 + hx]; if (button == '0' || button == '2') c = '0'; else if (button == '1') c = '1'; else if (button == MIDDLE_BUTTON) c = '-'; /* Cycle through options */ else if (button == CURSOR_SELECT2 || button == RIGHT_BUTTON) c = (i == EMPTY ? '0' : i == N_ZERO ? '1' : '-'); else if (button == CURSOR_SELECT || button == LEFT_BUTTON) c = (i == EMPTY ? '1' : i == N_ONE ? '0' : '-'); if (state->grid[hy * w2 + hx] == (c == '0' ? N_ZERO : c == '1' ? N_ONE : EMPTY)) return NULL; /* don't put no-ops on the undo chain */ sprintf(buf, "P%c,%d,%d", c, hx, hy); return dupstr(buf); } return NULL; } static game_state *execute_move(const game_state *state, const char *move) { int w2 = state->w2, h2 = state->h2; int s = w2 * h2; int x, y, i; char c; game_state *ret; if (move[0] == 'S') { const char *p; ret = dup_game(state); p = move + 1; for (i = 0; i < s; i++) { if (!*p || !(*p == '1' || *p == '0')) { free_game(ret); return NULL; } ret->grid[i] = (*p == '1' ? N_ONE : N_ZERO); p++; } ret->completed = ret->cheated = TRUE; return ret; } else if (move[0] == 'P' && sscanf(move + 1, "%c,%d,%d", &c, &x, &y) == 3 && x >= 0 && x < w2 && y >= 0 && y < h2 && (c == '-' || c == '0' || c == '1')) { ret = dup_game(state); i = y * w2 + x; if (state->immutable[i]) { free_game(ret); return NULL; } ret->grid[i] = (c == '1' ? N_ONE : c == '0' ? N_ZERO : EMPTY); if (!ret->completed && unruly_validate_counts(ret, NULL, NULL) == 0 && (unruly_validate_all_rows(ret, NULL) == 0)) ret->completed = TRUE; return ret; } return NULL; } /* ---------------------------------------------------------------------- * Drawing routines. */ static void game_compute_size(const game_params *params, int tilesize, int *x, int *y) { *x = tilesize * (params->w2 + 1); *y = tilesize * (params->h2 + 1); } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { ds->tilesize = tilesize; } static float *game_colours(frontend *fe, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float); int i; frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]); for (i = 0; i < 3; i++) { ret[COL_1 * 3 + i] = 0.2F; ret[COL_1_HIGHLIGHT * 3 + i] = 0.4F; ret[COL_1_LOWLIGHT * 3 + i] = 0.0F; ret[COL_0 * 3 + i] = 0.95F; ret[COL_0_HIGHLIGHT * 3 + i] = 1.0F; ret[COL_0_LOWLIGHT * 3 + i] = 0.9F; ret[COL_EMPTY * 3 + i] = 0.5F; ret[COL_GRID * 3 + i] = 0.3F; } game_mkhighlight_specific(fe, ret, COL_0, COL_0_HIGHLIGHT, COL_0_LOWLIGHT); game_mkhighlight_specific(fe, ret, COL_1, COL_1_HIGHLIGHT, COL_1_LOWLIGHT); ret[COL_ERROR * 3 + 0] = 1.0F; ret[COL_ERROR * 3 + 1] = 0.0F; ret[COL_ERROR * 3 + 2] = 0.0F; ret[COL_CURSOR * 3 + 0] = 0.0F; ret[COL_CURSOR * 3 + 1] = 0.7F; ret[COL_CURSOR * 3 + 2] = 0.0F; *ncolours = NCOLOURS; return ret; } static void unruly_draw_err_rectangle(drawing *dr, int x, int y, int w, int h, int tilesize) { double thick = tilesize / 10; double margin = tilesize / 20; draw_rect(dr, x+margin, y+margin, w-2*margin, thick, COL_ERROR); draw_rect(dr, x+margin, y+margin, thick, h-2*margin, COL_ERROR); draw_rect(dr, x+margin, y+h-margin-thick, w-2*margin, thick, COL_ERROR); draw_rect(dr, x+w-margin-thick, y+margin, thick, h-2*margin, COL_ERROR); } static void unruly_draw_tile(drawing *dr, int x, int y, int tilesize, int tile) { clip(dr, x, y, tilesize, tilesize); /* Draw the grid edge first, so the tile can overwrite it */ draw_rect(dr, x, y, tilesize, tilesize, COL_GRID); /* Background of the tile */ { int val = (tile & FF_ZERO ? 0 : tile & FF_ONE ? 2 : 1); val = (val == 0 ? COL_0 : val == 2 ? COL_1 : COL_EMPTY); if ((tile & (FF_FLASH1 | FF_FLASH2)) && (val == COL_0 || val == COL_1)) { val += (tile & FF_FLASH1 ? 1 : 2); } draw_rect(dr, x, y, tilesize-1, tilesize-1, val); if ((val == COL_0 || val == COL_1) && (tile & FF_IMMUTABLE)) { draw_rect(dr, x + tilesize/6, y + tilesize/6, tilesize - 2*(tilesize/6) - 2, 1, val + 2); draw_rect(dr, x + tilesize/6, y + tilesize/6, 1, tilesize - 2*(tilesize/6) - 2, val + 2); draw_rect(dr, x + tilesize/6 + 1, y + tilesize - tilesize/6 - 2, tilesize - 2*(tilesize/6) - 2, 1, val + 1); draw_rect(dr, x + tilesize - tilesize/6 - 2, y + tilesize/6 + 1, 1, tilesize - 2*(tilesize/6) - 2, val + 1); } } /* 3-in-a-row errors */ if (tile & (FE_HOR_ROW_LEFT | FE_HOR_ROW_RIGHT)) { int left = x, right = x + tilesize - 1; if ((tile & FE_HOR_ROW_LEFT)) right += tilesize/2; if ((tile & FE_HOR_ROW_RIGHT)) left -= tilesize/2; unruly_draw_err_rectangle(dr, left, y, right-left, tilesize-1, tilesize); } if (tile & (FE_VER_ROW_TOP | FE_VER_ROW_BOTTOM)) { int top = y, bottom = y + tilesize - 1; if ((tile & FE_VER_ROW_TOP)) bottom += tilesize/2; if ((tile & FE_VER_ROW_BOTTOM)) top -= tilesize/2; unruly_draw_err_rectangle(dr, x, top, tilesize-1, bottom-top, tilesize); } /* Count errors */ if (tile & FE_COUNT) { draw_text(dr, x + tilesize/2, y + tilesize/2, FONT_VARIABLE, tilesize/2, ALIGN_HCENTRE | ALIGN_VCENTRE, COL_ERROR, "!"); } /* Row-match errors */ if (tile & FE_ROW_MATCH) { draw_rect(dr, x, y+tilesize/2-tilesize/12, tilesize, 2*(tilesize/12), COL_ERROR); } if (tile & FE_COL_MATCH) { draw_rect(dr, x+tilesize/2-tilesize/12, y, 2*(tilesize/12), tilesize, COL_ERROR); } /* Cursor rectangle */ if (tile & FF_CURSOR) { draw_rect(dr, x, y, tilesize/12, tilesize-1, COL_CURSOR); draw_rect(dr, x, y, tilesize-1, tilesize/12, COL_CURSOR); draw_rect(dr, x+tilesize-1-tilesize/12, y, tilesize/12, tilesize-1, COL_CURSOR); draw_rect(dr, x, y+tilesize-1-tilesize/12, tilesize-1, tilesize/12, COL_CURSOR); } unclip(dr); draw_update(dr, x, y, tilesize, tilesize); } #define TILE_SIZE (ds->tilesize) #define DEFAULT_TILE_SIZE 32 #define FLASH_FRAME 0.12F #define FLASH_TIME (FLASH_FRAME * 3) static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float animtime, float flashtime) { int w2 = state->w2, h2 = state->h2; int s = w2 * h2; int flash; int x, y, i; if (!ds->started) { /* Main window background */ draw_rect(dr, 0, 0, TILE_SIZE * (w2+1), TILE_SIZE * (h2+1), COL_BACKGROUND); /* Outer edge of grid */ draw_rect(dr, COORD(0)-TILE_SIZE/10, COORD(0)-TILE_SIZE/10, TILE_SIZE*w2 + 2*(TILE_SIZE/10) - 1, TILE_SIZE*h2 + 2*(TILE_SIZE/10) - 1, COL_GRID); draw_update(dr, 0, 0, TILE_SIZE * (w2+1), TILE_SIZE * (h2+1)); ds->started = TRUE; } flash = 0; if (flashtime > 0) flash = (int)(flashtime / FLASH_FRAME) == 1 ? FF_FLASH2 : FF_FLASH1; for (i = 0; i < s; i++) ds->gridfs[i] = 0; unruly_validate_all_rows(state, ds->gridfs); for (i = 0; i < 2 * (h2 + w2); i++) ds->rowfs[i] = 0; unruly_validate_counts(state, NULL, ds->rowfs); for (y = 0; y < h2; y++) { for (x = 0; x < w2; x++) { int tile; i = y * w2 + x; tile = ds->gridfs[i]; if (state->grid[i] == N_ONE) { tile |= FF_ONE; if (ds->rowfs[y] || ds->rowfs[2*h2 + x]) tile |= FE_COUNT; } else if (state->grid[i] == N_ZERO) { tile |= FF_ZERO; if (ds->rowfs[h2 + y] || ds->rowfs[2*h2 + w2 + x]) tile |= FE_COUNT; } tile |= flash; if (state->immutable[i]) tile |= FF_IMMUTABLE; if (ui->cursor && ui->cx == x && ui->cy == y) tile |= FF_CURSOR; if (ds->grid[i] != tile) { ds->grid[i] = tile; unruly_draw_tile(dr, COORD(x), COORD(y), TILE_SIZE, tile); } } } } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return 0.0F; } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { if (!oldstate->completed && newstate->completed && !oldstate->cheated && !newstate->cheated) return FLASH_TIME; return 0.0F; } static int game_status(const game_state *state) { return state->completed ? +1 : 0; } static int game_timing_state(const game_state *state, game_ui *ui) { return TRUE; } static void game_print_size(const game_params *params, float *x, float *y) { int pw, ph; /* Using 7mm squares */ game_compute_size(params, 700, &pw, &ph); *x = pw / 100.0F; *y = ph / 100.0F; } static void game_print(drawing *dr, const game_state *state, int tilesize) { int w2 = state->w2, h2 = state->h2; int x, y; int ink = print_mono_colour(dr, 0); for (y = 0; y < h2; y++) for (x = 0; x < w2; x++) { int tx = x * tilesize + (tilesize / 2); int ty = y * tilesize + (tilesize / 2); /* Draw the border */ int coords[8]; coords[0] = tx; coords[1] = ty - 1; coords[2] = tx + tilesize; coords[3] = ty - 1; coords[4] = tx + tilesize; coords[5] = ty + tilesize - 1; coords[6] = tx; coords[7] = ty + tilesize - 1; draw_polygon(dr, coords, 4, -1, ink); if (state->grid[y * w2 + x] == N_ONE) draw_rect(dr, tx, ty, tilesize, tilesize, ink); else if (state->grid[y * w2 + x] == N_ZERO) draw_circle(dr, tx + tilesize/2, ty + tilesize/2, tilesize/12, ink, ink); } } #ifdef COMBINED #define thegame unruly #endif const struct game thegame = { "Unruly", "games.unruly", "unruly", default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, TRUE, solve_game, TRUE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, DEFAULT_TILE_SIZE, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, TRUE, FALSE, game_print_size, game_print, FALSE, /* wants_statusbar */ FALSE, game_timing_state, 0, /* flags */ }; /* ***************** * * Standalone solver * * ***************** */ #ifdef STANDALONE_SOLVER #include #include /* Most of the standalone solver code was copied from unequal.c and singles.c */ const char *quis; static void usage_exit(const char *msg) { if (msg) fprintf(stderr, "%s: %s\n", quis, msg); fprintf(stderr, "Usage: %s [-v] [--seed SEED] | [game_id [game_id ...]]\n", quis); exit(1); } int main(int argc, char *argv[]) { random_state *rs; time_t seed = time(NULL); game_params *params = NULL; char *id = NULL, *desc = NULL, *err; quis = argv[0]; while (--argc > 0) { char *p = *++argv; if (!strcmp(p, "--seed")) { if (argc == 0) usage_exit("--seed needs an argument"); seed = (time_t) atoi(*++argv); argc--; } else if (!strcmp(p, "-v")) solver_verbose = TRUE; else if (*p == '-') usage_exit("unrecognised option"); else id = p; } if (id) { desc = strchr(id, ':'); if (desc) *desc++ = '\0'; params = default_params(); decode_params(params, id); err = validate_params(params, TRUE); if (err) { fprintf(stderr, "Parameters are invalid\n"); fprintf(stderr, "%s: %s", argv[0], err); exit(1); } } if (!desc) { char *desc_gen, *aux; rs = random_new((void *) &seed, sizeof(time_t)); if (!params) params = default_params(); printf("Generating puzzle with parameters %s\n", encode_params(params, TRUE)); desc_gen = new_game_desc(params, rs, &aux, FALSE); if (!solver_verbose) { char *fmt = game_text_format(new_game(NULL, params, desc_gen)); fputs(fmt, stdout); sfree(fmt); } printf("Game ID: %s\n", desc_gen); } else { game_state *input; struct unruly_scratch *scratch; int maxdiff, errcode; err = validate_desc(params, desc); if (err) { fprintf(stderr, "Description is invalid\n"); fprintf(stderr, "%s", err); exit(1); } input = new_game(NULL, params, desc); scratch = unruly_new_scratch(input); maxdiff = unruly_solve_game(input, scratch, DIFFCOUNT); errcode = unruly_validate_counts(input, scratch, NULL); if (unruly_validate_all_rows(input, NULL) == -1) errcode = -1; if (errcode != -1) { char *fmt = game_text_format(input); fputs(fmt, stdout); sfree(fmt); if (maxdiff < 0) printf("Difficulty: already solved!\n"); else printf("Difficulty: %s\n", unruly_diffnames[maxdiff]); } if (errcode == 1) printf("No solution found.\n"); else if (errcode == -1) printf("Puzzle is invalid.\n"); free_game(input); unruly_free_scratch(scratch); } return 0; } #endif puzzles-20170606.272beef/unequal.c0000644000175000017500000020320313115373615015507 0ustar simonsimon/* * unequal.c * * Implementation of 'Futoshiki', a puzzle featured in the Guardian. * * TTD: * add multiple-links-on-same-col/row solver nous * Optimise set solver to use bit operations instead * * Guardian puzzles of note: * #1: 5:0,0L,0L,0,0,0R,0,0L,0D,0L,0R,0,2,0D,0,0,0,0,0,0,0U,0,0,0,0U, * #2: 5:0,0,0,4L,0L,0,2LU,0L,0U,0,0,0U,0,0,0,0,0D,0,3LRUD,0,0R,3,0L,0,0, * #3: (reprint of #2) * #4: * #5: 5:0,0,0,0,0,0,2,0U,3U,0U,0,0,3,0,0,0,3,0D,4,0,0,0L,0R,0,0, * #6: 5:0D,0L,0,0R,0,0,0D,0,3,0D,0,0R,0,0R,0D,0U,0L,0,1,2,0,0,0U,0,0L, */ #include #include #include #include #include #include #include "puzzles.h" #include "latin.h" /* contains typedef for digit */ /* ---------------------------------------------------------- * Constant and structure definitions */ #define FLASH_TIME 0.4F #define PREFERRED_TILE_SIZE 32 #define TILE_SIZE (ds->tilesize) #define GAP_SIZE (TILE_SIZE/2) #define SQUARE_SIZE (TILE_SIZE + GAP_SIZE) #define BORDER (TILE_SIZE / 2) #define COORD(x) ( (x) * SQUARE_SIZE + BORDER ) #define FROMCOORD(x) ( ((x) - BORDER + SQUARE_SIZE) / SQUARE_SIZE - 1 ) #define GRID(p,w,x,y) ((p)->w[((y)*(p)->order)+(x)]) #define GRID3(p,w,x,y,z) ((p)->w[ (((x)*(p)->order+(y))*(p)->order+(z)) ]) #define HINT(p,x,y,n) GRID3(p, hints, x, y, n) enum { COL_BACKGROUND, COL_GRID, COL_TEXT, COL_GUESS, COL_ERROR, COL_PENCIL, COL_HIGHLIGHT, COL_LOWLIGHT, COL_SPENT = COL_LOWLIGHT, NCOLOURS }; struct game_params { int order; /* Size of latin square */ int diff; /* Difficulty */ int adjacent; /* Puzzle indicators are 'adjacent number' not 'greater-than'. */ }; #define F_IMMUTABLE 1 /* passed in as game description */ #define F_ADJ_UP 2 #define F_ADJ_RIGHT 4 #define F_ADJ_DOWN 8 #define F_ADJ_LEFT 16 #define F_ERROR 32 #define F_ERROR_UP 64 #define F_ERROR_RIGHT 128 #define F_ERROR_DOWN 256 #define F_ERROR_LEFT 512 #define F_SPENT_UP 1024 #define F_SPENT_RIGHT 2048 #define F_SPENT_DOWN 4096 #define F_SPENT_LEFT 8192 #define ADJ_TO_SPENT(x) ((x) << 9) #define F_ERROR_MASK (F_ERROR|F_ERROR_UP|F_ERROR_RIGHT|F_ERROR_DOWN|F_ERROR_LEFT) struct game_state { int order, completed, cheated, adjacent; digit *nums; /* actual numbers (size order^2) */ unsigned char *hints; /* remaining possiblities (size order^3) */ unsigned int *flags; /* flags (size order^2) */ }; /* ---------------------------------------------------------- * Game parameters and presets */ /* Steal the method from map.c for difficulty levels. */ #define DIFFLIST(A) \ A(LATIN,Trivial,NULL,t) \ A(EASY,Easy,solver_easy, e) \ A(SET,Tricky,solver_set, k) \ A(EXTREME,Extreme,NULL,x) \ A(RECURSIVE,Recursive,NULL,r) #define ENUM(upper,title,func,lower) DIFF_ ## upper, #define TITLE(upper,title,func,lower) #title, #define ENCODE(upper,title,func,lower) #lower #define CONFIG(upper,title,func,lower) ":" #title enum { DIFFLIST(ENUM) DIFFCOUNT, DIFF_IMPOSSIBLE = diff_impossible, DIFF_AMBIGUOUS = diff_ambiguous, DIFF_UNFINISHED = diff_unfinished }; static char const *const unequal_diffnames[] = { DIFFLIST(TITLE) }; static char const unequal_diffchars[] = DIFFLIST(ENCODE); #define DIFFCONFIG DIFFLIST(CONFIG) #define DEFAULT_PRESET 0 const static struct game_params unequal_presets[] = { { 4, DIFF_EASY, 0 }, { 5, DIFF_EASY, 0 }, { 5, DIFF_SET, 0 }, { 5, DIFF_SET, 1 }, { 5, DIFF_EXTREME, 0 }, { 6, DIFF_EASY, 0 }, { 6, DIFF_SET, 0 }, { 6, DIFF_SET, 1 }, { 6, DIFF_EXTREME, 0 }, { 7, DIFF_SET, 0 }, { 7, DIFF_SET, 1 }, { 7, DIFF_EXTREME, 0 } }; static int game_fetch_preset(int i, char **name, game_params **params) { game_params *ret; char buf[80]; if (i < 0 || i >= lenof(unequal_presets)) return FALSE; ret = snew(game_params); *ret = unequal_presets[i]; /* structure copy */ sprintf(buf, "%s: %dx%d %s", ret->adjacent ? "Adjacent" : "Unequal", ret->order, ret->order, unequal_diffnames[ret->diff]); *name = dupstr(buf); *params = ret; return TRUE; } static game_params *default_params(void) { game_params *ret; char *name; if (!game_fetch_preset(DEFAULT_PRESET, &name, &ret)) return NULL; sfree(name); return ret; } static void free_params(game_params *params) { sfree(params); } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } static void decode_params(game_params *ret, char const *string) { char const *p = string; ret->order = atoi(p); while (*p && isdigit((unsigned char)*p)) p++; if (*p == 'a') { p++; ret->adjacent = 1; } else ret->adjacent = 0; if (*p == 'd') { int i; p++; ret->diff = DIFFCOUNT+1; /* ...which is invalid */ if (*p) { for (i = 0; i < DIFFCOUNT; i++) { if (*p == unequal_diffchars[i]) ret->diff = i; } p++; } } } static char *encode_params(const game_params *params, int full) { char ret[80]; sprintf(ret, "%d", params->order); if (params->adjacent) sprintf(ret + strlen(ret), "a"); if (full) sprintf(ret + strlen(ret), "d%c", unequal_diffchars[params->diff]); return dupstr(ret); } static config_item *game_configure(const game_params *params) { config_item *ret; char buf[80]; ret = snewn(4, config_item); ret[0].name = "Mode"; ret[0].type = C_CHOICES; ret[0].sval = ":Unequal:Adjacent"; ret[0].ival = params->adjacent; ret[1].name = "Size (s*s)"; ret[1].type = C_STRING; sprintf(buf, "%d", params->order); ret[1].sval = dupstr(buf); ret[1].ival = 0; ret[2].name = "Difficulty"; ret[2].type = C_CHOICES; ret[2].sval = DIFFCONFIG; ret[2].ival = params->diff; ret[3].name = NULL; ret[3].type = C_END; ret[3].sval = NULL; ret[3].ival = 0; return ret; } static game_params *custom_params(const config_item *cfg) { game_params *ret = snew(game_params); ret->adjacent = cfg[0].ival; ret->order = atoi(cfg[1].sval); ret->diff = cfg[2].ival; return ret; } static char *validate_params(const game_params *params, int full) { if (params->order < 3 || params->order > 32) return "Order must be between 3 and 32"; if (params->diff >= DIFFCOUNT) return "Unknown difficulty rating"; if (params->order < 5 && params->adjacent && params->diff >= DIFF_SET) return "Order must be at least 5 for Adjacent puzzles of this difficulty."; return NULL; } /* ---------------------------------------------------------- * Various utility functions */ static const struct { unsigned int f, fo, fe; int dx, dy; char c, ac; } adjthan[] = { { F_ADJ_UP, F_ADJ_DOWN, F_ERROR_UP, 0, -1, '^', '-' }, { F_ADJ_RIGHT, F_ADJ_LEFT, F_ERROR_RIGHT, 1, 0, '>', '|' }, { F_ADJ_DOWN, F_ADJ_UP, F_ERROR_DOWN, 0, 1, 'v', '-' }, { F_ADJ_LEFT, F_ADJ_RIGHT, F_ERROR_LEFT, -1, 0, '<', '|' } }; static game_state *blank_game(int order, int adjacent) { game_state *state = snew(game_state); int o2 = order*order, o3 = o2*order; state->order = order; state->adjacent = adjacent; state->completed = state->cheated = 0; state->nums = snewn(o2, digit); state->hints = snewn(o3, unsigned char); state->flags = snewn(o2, unsigned int); memset(state->nums, 0, o2 * sizeof(digit)); memset(state->hints, 0, o3); memset(state->flags, 0, o2 * sizeof(unsigned int)); return state; } static game_state *dup_game(const game_state *state) { game_state *ret = blank_game(state->order, state->adjacent); int o2 = state->order*state->order, o3 = o2*state->order; memcpy(ret->nums, state->nums, o2 * sizeof(digit)); memcpy(ret->hints, state->hints, o3); memcpy(ret->flags, state->flags, o2 * sizeof(unsigned int)); return ret; } static void free_game(game_state *state) { sfree(state->nums); sfree(state->hints); sfree(state->flags); sfree(state); } #define CHECKG(x,y) grid[(y)*o+(x)] /* Returns 0 if it finds an error, 1 otherwise. */ static int check_num_adj(digit *grid, game_state *state, int x, int y, int me) { unsigned int f = GRID(state, flags, x, y); int ret = 1, i, o = state->order; for (i = 0; i < 4; i++) { int dx = adjthan[i].dx, dy = adjthan[i].dy, n, dn; if (x+dx < 0 || x+dx >= o || y+dy < 0 || y+dy >= o) continue; n = CHECKG(x, y); dn = CHECKG(x+dx, y+dy); assert (n != 0); if (dn == 0) continue; if (state->adjacent) { int gd = abs(n-dn); if ((f & adjthan[i].f) && (gd != 1)) { debug(("check_adj error (%d,%d):%d should be | (%d,%d):%d", x, y, n, x+dx, y+dy, dn)); if (me) GRID(state, flags, x, y) |= adjthan[i].fe; ret = 0; } if (!(f & adjthan[i].f) && (gd == 1)) { debug(("check_adj error (%d,%d):%d should not be | (%d,%d):%d", x, y, n, x+dx, y+dy, dn)); if (me) GRID(state, flags, x, y) |= adjthan[i].fe; ret = 0; } } else { if ((f & adjthan[i].f) && (n <= dn)) { debug(("check_adj error (%d,%d):%d not > (%d,%d):%d", x, y, n, x+dx, y+dy, dn)); if (me) GRID(state, flags, x, y) |= adjthan[i].fe; ret = 0; } } } return ret; } /* Returns 0 if it finds an error, 1 otherwise. */ static int check_num_error(digit *grid, game_state *state, int x, int y, int mark_errors) { int o = state->order; int xx, yy, val = CHECKG(x,y), ret = 1; assert(val != 0); /* check for dups in same column. */ for (yy = 0; yy < state->order; yy++) { if (yy == y) continue; if (CHECKG(x,yy) == val) ret = 0; } /* check for dups in same row. */ for (xx = 0; xx < state->order; xx++) { if (xx == x) continue; if (CHECKG(xx,y) == val) ret = 0; } if (!ret) { debug(("check_num_error (%d,%d) duplicate %d", x, y, val)); if (mark_errors) GRID(state, flags, x, y) |= F_ERROR; } return ret; } /* Returns: -1 for 'wrong' * 0 for 'incomplete' * 1 for 'complete and correct' */ static int check_complete(digit *grid, game_state *state, int mark_errors) { int x, y, ret = 1, o = state->order; if (mark_errors) assert(grid == state->nums); for (x = 0; x < state->order; x++) { for (y = 0; y < state->order; y++) { if (mark_errors) GRID(state, flags, x, y) &= ~F_ERROR_MASK; if (grid[y*o+x] == 0) { ret = 0; } else { if (!check_num_error(grid, state, x, y, mark_errors)) ret = -1; if (!check_num_adj(grid, state, x, y, mark_errors)) ret = -1; } } } if (ret == 1 && latin_check(grid, o)) ret = -1; return ret; } static char n2c(digit n, int order) { if (n == 0) return ' '; if (order < 10) { if (n < 10) return '0' + n; } else { if (n < 11) return '0' + n-1; n -= 11; if (n <= 26) return 'A' + n; } return '?'; } /* should be 'digit', but includes -1 for 'not a digit'. * Includes keypresses (0 especially) for interpret_move. */ static int c2n(int c, int order) { if (c < 0 || c > 0xff) return -1; if (c == ' ' || c == '\b') return 0; if (order < 10) { if (c >= '0' && c <= '9') return (int)(c - '0'); } else { if (c >= '0' && c <= '9') return (int)(c - '0' + 1); if (c >= 'A' && c <= 'Z') return (int)(c - 'A' + 11); if (c >= 'a' && c <= 'z') return (int)(c - 'a' + 11); } return -1; } static int game_can_format_as_text_now(const game_params *params) { return TRUE; } static char *game_text_format(const game_state *state) { int x, y, len, n; char *ret, *p; len = (state->order*2) * (state->order*2-1) + 1; ret = snewn(len, char); p = ret; for (y = 0; y < state->order; y++) { for (x = 0; x < state->order; x++) { n = GRID(state, nums, x, y); *p++ = n > 0 ? n2c(n, state->order) : '.'; if (x < (state->order-1)) { if (state->adjacent) { *p++ = (GRID(state, flags, x, y) & F_ADJ_RIGHT) ? '|' : ' '; } else { if (GRID(state, flags, x, y) & F_ADJ_RIGHT) *p++ = '>'; else if (GRID(state, flags, x+1, y) & F_ADJ_LEFT) *p++ = '<'; else *p++ = ' '; } } } *p++ = '\n'; if (y < (state->order-1)) { for (x = 0; x < state->order; x++) { if (state->adjacent) { *p++ = (GRID(state, flags, x, y) & F_ADJ_DOWN) ? '-' : ' '; } else { if (GRID(state, flags, x, y) & F_ADJ_DOWN) *p++ = 'v'; else if (GRID(state, flags, x, y+1) & F_ADJ_UP) *p++ = '^'; else *p++ = ' '; } if (x < state->order-1) *p++ = ' '; } *p++ = '\n'; } } *p++ = '\0'; assert(p - ret == len); return ret; } #ifdef STANDALONE_SOLVER static void game_debug(game_state *state) { char *dbg = game_text_format(state); printf("%s", dbg); sfree(dbg); } #endif /* ---------------------------------------------------------- * Solver. */ struct solver_link { int len, gx, gy, lx, ly; }; struct solver_ctx { game_state *state; int nlinks, alinks; struct solver_link *links; }; static void solver_add_link(struct solver_ctx *ctx, int gx, int gy, int lx, int ly, int len) { if (ctx->alinks < ctx->nlinks+1) { ctx->alinks = ctx->alinks*2 + 1; /*debug(("resizing ctx->links, new size %d", ctx->alinks));*/ ctx->links = sresize(ctx->links, ctx->alinks, struct solver_link); } ctx->links[ctx->nlinks].gx = gx; ctx->links[ctx->nlinks].gy = gy; ctx->links[ctx->nlinks].lx = lx; ctx->links[ctx->nlinks].ly = ly; ctx->links[ctx->nlinks].len = len; ctx->nlinks++; /*debug(("Adding new link: len %d (%d,%d) < (%d,%d), nlinks now %d", len, lx, ly, gx, gy, ctx->nlinks));*/ } static struct solver_ctx *new_ctx(game_state *state) { struct solver_ctx *ctx = snew(struct solver_ctx); int o = state->order; int i, x, y; unsigned int f; ctx->nlinks = ctx->alinks = 0; ctx->links = NULL; ctx->state = state; if (state->adjacent) return ctx; /* adjacent mode doesn't use links. */ for (x = 0; x < o; x++) { for (y = 0; y < o; y++) { f = GRID(state, flags, x, y); for (i = 0; i < 4; i++) { if (f & adjthan[i].f) solver_add_link(ctx, x, y, x+adjthan[i].dx, y+adjthan[i].dy, 1); } } } return ctx; } static void *clone_ctx(void *vctx) { struct solver_ctx *ctx = (struct solver_ctx *)vctx; return new_ctx(ctx->state); } static void free_ctx(void *vctx) { struct solver_ctx *ctx = (struct solver_ctx *)vctx; if (ctx->links) sfree(ctx->links); sfree(ctx); } static void solver_nminmax(struct latin_solver *solver, int x, int y, int *min_r, int *max_r, unsigned char **ns_r) { int o = solver->o, min = o, max = 0, n; unsigned char *ns; assert(x >= 0 && y >= 0 && x < o && y < o); ns = solver->cube + cubepos(x,y,1); if (grid(x,y) > 0) { min = max = grid(x,y)-1; } else { for (n = 0; n < o; n++) { if (ns[n]) { if (n > max) max = n; if (n < min) min = n; } } } if (min_r) *min_r = min; if (max_r) *max_r = max; if (ns_r) *ns_r = ns; } static int solver_links(struct latin_solver *solver, void *vctx) { struct solver_ctx *ctx = (struct solver_ctx *)vctx; int i, j, lmin, gmax, nchanged = 0; unsigned char *gns, *lns; struct solver_link *link; for (i = 0; i < ctx->nlinks; i++) { link = &ctx->links[i]; solver_nminmax(solver, link->gx, link->gy, NULL, &gmax, &gns); solver_nminmax(solver, link->lx, link->ly, &lmin, NULL, &lns); for (j = 0; j < solver->o; j++) { /* For the 'greater' end of the link, discount all numbers * too small to satisfy the inequality. */ if (gns[j]) { if (j < (lmin+link->len)) { #ifdef STANDALONE_SOLVER if (solver_show_working) { printf("%*slink elimination, (%d,%d) > (%d,%d):\n", solver_recurse_depth*4, "", link->gx+1, link->gy+1, link->lx+1, link->ly+1); printf("%*s ruling out %d at (%d,%d)\n", solver_recurse_depth*4, "", j+1, link->gx+1, link->gy+1); } #endif cube(link->gx, link->gy, j+1) = FALSE; nchanged++; } } /* For the 'lesser' end of the link, discount all numbers * too large to satisfy inequality. */ if (lns[j]) { if (j > (gmax-link->len)) { #ifdef STANDALONE_SOLVER if (solver_show_working) { printf("%*slink elimination, (%d,%d) > (%d,%d):\n", solver_recurse_depth*4, "", link->gx+1, link->gy+1, link->lx+1, link->ly+1); printf("%*s ruling out %d at (%d,%d)\n", solver_recurse_depth*4, "", j+1, link->lx+1, link->ly+1); } #endif cube(link->lx, link->ly, j+1) = FALSE; nchanged++; } } } } return nchanged; } static int solver_adjacent(struct latin_solver *solver, void *vctx) { struct solver_ctx *ctx = (struct solver_ctx *)vctx; int nchanged = 0, x, y, i, n, o = solver->o, nx, ny, gd; /* Update possible values based on known values and adjacency clues. */ for (x = 0; x < o; x++) { for (y = 0; y < o; y++) { if (grid(x, y) == 0) continue; /* We have a definite number here. Make sure that any * adjacent possibles reflect the adjacent/non-adjacent clue. */ for (i = 0; i < 4; i++) { int isadjacent = (GRID(ctx->state, flags, x, y) & adjthan[i].f); nx = x + adjthan[i].dx, ny = y + adjthan[i].dy; if (nx < 0 || ny < 0 || nx >= o || ny >= o) continue; for (n = 0; n < o; n++) { /* Continue past numbers the adjacent square _could_ be, * given the clue we have. */ gd = abs((n+1) - grid(x, y)); if (isadjacent && (gd == 1)) continue; if (!isadjacent && (gd != 1)) continue; if (cube(nx, ny, n+1) == FALSE) continue; /* already discounted this possibility. */ #ifdef STANDALONE_SOLVER if (solver_show_working) { printf("%*sadjacent elimination, (%d,%d):%d %s (%d,%d):\n", solver_recurse_depth*4, "", x+1, y+1, grid(x, y), isadjacent ? "|" : "!|", nx+1, ny+1); printf("%*s ruling out %d at (%d,%d)\n", solver_recurse_depth*4, "", n+1, nx+1, ny+1); } #endif cube(nx, ny, n+1) = FALSE; nchanged++; } } } } return nchanged; } static int solver_adjacent_set(struct latin_solver *solver, void *vctx) { struct solver_ctx *ctx = (struct solver_ctx *)vctx; int x, y, i, n, nn, o = solver->o, nx, ny, gd; int nchanged = 0, *scratch = snewn(o, int); /* Update possible values based on other possible values * of adjacent squares, and adjacency clues. */ for (x = 0; x < o; x++) { for (y = 0; y < o; y++) { for (i = 0; i < 4; i++) { int isadjacent = (GRID(ctx->state, flags, x, y) & adjthan[i].f); nx = x + adjthan[i].dx, ny = y + adjthan[i].dy; if (nx < 0 || ny < 0 || nx >= o || ny >= o) continue; /* We know the current possibles for the square (x,y) * and also the adjacency clue from (x,y) to (nx,ny). * Construct a maximum set of possibles for (nx,ny) * in scratch, based on these constraints... */ memset(scratch, 0, o*sizeof(int)); for (n = 0; n < o; n++) { if (cube(x, y, n+1) == FALSE) continue; for (nn = 0; nn < o; nn++) { if (n == nn) continue; gd = abs(nn - n); if (isadjacent && (gd != 1)) continue; if (!isadjacent && (gd == 1)) continue; scratch[nn] = 1; } } /* ...and remove any possibilities for (nx,ny) that are * currently set but are not indicated in scratch. */ for (n = 0; n < o; n++) { if (scratch[n] == 1) continue; if (cube(nx, ny, n+1) == FALSE) continue; #ifdef STANDALONE_SOLVER if (solver_show_working) { printf("%*sadjacent possible elimination, (%d,%d) %s (%d,%d):\n", solver_recurse_depth*4, "", x+1, y+1, isadjacent ? "|" : "!|", nx+1, ny+1); printf("%*s ruling out %d at (%d,%d)\n", solver_recurse_depth*4, "", n+1, nx+1, ny+1); } #endif cube(nx, ny, n+1) = FALSE; nchanged++; } } } } return nchanged; } static int solver_easy(struct latin_solver *solver, void *vctx) { struct solver_ctx *ctx = (struct solver_ctx *)vctx; if (ctx->state->adjacent) return solver_adjacent(solver, vctx); else return solver_links(solver, vctx); } static int solver_set(struct latin_solver *solver, void *vctx) { struct solver_ctx *ctx = (struct solver_ctx *)vctx; if (ctx->state->adjacent) return solver_adjacent_set(solver, vctx); else return 0; } #define SOLVER(upper,title,func,lower) func, static usersolver_t const unequal_solvers[] = { DIFFLIST(SOLVER) }; static int solver_state(game_state *state, int maxdiff) { struct solver_ctx *ctx = new_ctx(state); struct latin_solver solver; int diff; latin_solver_alloc(&solver, state->nums, state->order); diff = latin_solver_main(&solver, maxdiff, DIFF_LATIN, DIFF_SET, DIFF_EXTREME, DIFF_EXTREME, DIFF_RECURSIVE, unequal_solvers, ctx, clone_ctx, free_ctx); memcpy(state->hints, solver.cube, state->order*state->order*state->order); free_ctx(ctx); latin_solver_free(&solver); if (diff == DIFF_IMPOSSIBLE) return -1; if (diff == DIFF_UNFINISHED) return 0; if (diff == DIFF_AMBIGUOUS) return 2; return 1; } static game_state *solver_hint(const game_state *state, int *diff_r, int mindiff, int maxdiff) { game_state *ret = dup_game(state); int diff, r = 0; for (diff = mindiff; diff <= maxdiff; diff++) { r = solver_state(ret, diff); debug(("solver_state after %s %d", unequal_diffnames[diff], r)); if (r != 0) goto done; } done: if (diff_r) *diff_r = (r > 0) ? diff : -1; return ret; } /* ---------------------------------------------------------- * Game generation. */ static char *latin_desc(digit *sq, size_t order) { int o2 = order*order, i; char *soln = snewn(o2+2, char); soln[0] = 'S'; for (i = 0; i < o2; i++) soln[i+1] = n2c(sq[i], order); soln[o2+1] = '\0'; return soln; } /* returns non-zero if it placed (or could have placed) clue. */ static int gg_place_clue(game_state *state, int ccode, digit *latin, int checkonly) { int loc = ccode / 5, which = ccode % 5; int x = loc % state->order, y = loc / state->order; assert(loc < state->order*state->order); if (which == 4) { /* add number */ if (state->nums[loc] != 0) { #ifdef STANDALONE_SOLVER if (state->nums[loc] != latin[loc]) { printf("inconsistency for (%d,%d): state %d latin %d\n", x+1, y+1, state->nums[loc], latin[loc]); } #endif assert(state->nums[loc] == latin[loc]); return 0; } if (!checkonly) { state->nums[loc] = latin[loc]; } } else { /* add flag */ int lx, ly, lloc; if (state->adjacent) return 0; /* never add flag clues in adjacent mode (they're always all present) */ if (state->flags[loc] & adjthan[which].f) return 0; /* already has flag. */ lx = x + adjthan[which].dx; ly = y + adjthan[which].dy; if (lx < 0 || ly < 0 || lx >= state->order || ly >= state->order) return 0; /* flag compares to off grid */ lloc = loc + adjthan[which].dx + adjthan[which].dy*state->order; if (latin[loc] <= latin[lloc]) return 0; /* flag would be incorrect */ if (!checkonly) { state->flags[loc] |= adjthan[which].f; } } return 1; } /* returns non-zero if it removed (or could have removed) the clue. */ static int gg_remove_clue(game_state *state, int ccode, int checkonly) { int loc = ccode / 5, which = ccode % 5; #ifdef STANDALONE_SOLVER int x = loc % state->order, y = loc / state->order; #endif assert(loc < state->order*state->order); if (which == 4) { /* remove number. */ if (state->nums[loc] == 0) return 0; if (!checkonly) { #ifdef STANDALONE_SOLVER if (solver_show_working) printf("gg_remove_clue: removing %d at (%d,%d)", state->nums[loc], x+1, y+1); #endif state->nums[loc] = 0; } } else { /* remove flag */ if (state->adjacent) return 0; /* never remove clues in adjacent mode. */ if (!(state->flags[loc] & adjthan[which].f)) return 0; if (!checkonly) { #ifdef STANDALONE_SOLVER if (solver_show_working) printf("gg_remove_clue: removing %c at (%d,%d)", adjthan[which].c, x+1, y+1); #endif state->flags[loc] &= ~adjthan[which].f; } } return 1; } static int gg_best_clue(game_state *state, int *scratch, digit *latin) { int ls = state->order * state->order * 5; int maxposs = 0, minclues = 5, best = -1, i, j; int nposs, nclues, loc; #ifdef STANDALONE_SOLVER if (solver_show_working) { game_debug(state); latin_solver_debug(state->hints, state->order); } #endif for (i = ls; i-- > 0 ;) { if (!gg_place_clue(state, scratch[i], latin, 1)) continue; loc = scratch[i] / 5; for (j = nposs = 0; j < state->order; j++) { if (state->hints[loc*state->order + j]) nposs++; } for (j = nclues = 0; j < 4; j++) { if (state->flags[loc] & adjthan[j].f) nclues++; } if ((nposs > maxposs) || (nposs == maxposs && nclues < minclues)) { best = i; maxposs = nposs; minclues = nclues; #ifdef STANDALONE_SOLVER if (solver_show_working) { int x = loc % state->order, y = loc / state->order; printf("gg_best_clue: b%d (%d,%d) new best [%d poss, %d clues].\n", best, x+1, y+1, nposs, nclues); } #endif } } /* if we didn't solve, we must have 1 clue to place! */ assert(best != -1); return best; } #ifdef STANDALONE_SOLVER int maxtries; #define MAXTRIES maxtries #else #define MAXTRIES 50 #endif int gg_solved; static int game_assemble(game_state *new, int *scratch, digit *latin, int difficulty) { game_state *copy = dup_game(new); int best; if (difficulty >= DIFF_RECURSIVE) { /* We mustn't use any solver that might guess answers; * if it guesses wrongly but solves, gg_place_clue will * get mighty confused. We will always trim clues down * (making it more difficult) in game_strip, which doesn't * have this problem. */ difficulty = DIFF_RECURSIVE-1; } #ifdef STANDALONE_SOLVER if (solver_show_working) { game_debug(new); latin_solver_debug(new->hints, new->order); } #endif while(1) { gg_solved++; if (solver_state(copy, difficulty) == 1) break; best = gg_best_clue(copy, scratch, latin); gg_place_clue(new, scratch[best], latin, 0); gg_place_clue(copy, scratch[best], latin, 0); } free_game(copy); #ifdef STANDALONE_SOLVER if (solver_show_working) { char *dbg = game_text_format(new); printf("game_assemble: done, %d solver iterations:\n%s\n", gg_solved, dbg); sfree(dbg); } #endif return 0; } static void game_strip(game_state *new, int *scratch, digit *latin, int difficulty) { int o = new->order, o2 = o*o, lscratch = o2*5, i; game_state *copy = blank_game(new->order, new->adjacent); /* For each symbol (if it exists in new), try and remove it and * solve again; if we couldn't solve without it put it back. */ for (i = 0; i < lscratch; i++) { if (!gg_remove_clue(new, scratch[i], 0)) continue; memcpy(copy->nums, new->nums, o2 * sizeof(digit)); memcpy(copy->flags, new->flags, o2 * sizeof(unsigned int)); gg_solved++; if (solver_state(copy, difficulty) != 1) { /* put clue back, we can't solve without it. */ int ret = gg_place_clue(new, scratch[i], latin, 0); assert(ret == 1); } else { #ifdef STANDALONE_SOLVER if (solver_show_working) printf("game_strip: clue was redundant."); #endif } } free_game(copy); #ifdef STANDALONE_SOLVER if (solver_show_working) { char *dbg = game_text_format(new); debug(("game_strip: done, %d solver iterations.", gg_solved)); debug(("%s", dbg)); sfree(dbg); } #endif } static void add_adjacent_flags(game_state *state, digit *latin) { int x, y, o = state->order; /* All clues in adjacent mode are always present (the only variables are * the numbers). This adds all the flags to state based on the supplied * latin square. */ for (y = 0; y < o; y++) { for (x = 0; x < o; x++) { if (x < (o-1) && (abs(latin[y*o+x] - latin[y*o+x+1]) == 1)) { GRID(state, flags, x, y) |= F_ADJ_RIGHT; GRID(state, flags, x+1, y) |= F_ADJ_LEFT; } if (y < (o-1) && (abs(latin[y*o+x] - latin[(y+1)*o+x]) == 1)) { GRID(state, flags, x, y) |= F_ADJ_DOWN; GRID(state, flags, x, y+1) |= F_ADJ_UP; } } } } static char *new_game_desc(const game_params *params_in, random_state *rs, char **aux, int interactive) { game_params params_copy = *params_in; /* structure copy */ game_params *params = ¶ms_copy; digit *sq = NULL; int i, x, y, retlen, k, nsol; int o2 = params->order * params->order, ntries = 1; int *scratch, lscratch = o2*5; char *ret, buf[80]; game_state *state = blank_game(params->order, params->adjacent); /* Generate a list of 'things to strip' (randomised later) */ scratch = snewn(lscratch, int); /* Put the numbers (4 mod 5) before the inequalities (0-3 mod 5) */ for (i = 0; i < lscratch; i++) scratch[i] = (i%o2)*5 + 4 - (i/o2); generate: #ifdef STANDALONE_SOLVER if (solver_show_working) printf("new_game_desc: generating %s puzzle, ntries so far %d\n", unequal_diffnames[params->diff], ntries); #endif if (sq) sfree(sq); sq = latin_generate(params->order, rs); latin_debug(sq, params->order); /* Separately shuffle the numeric and inequality clues */ shuffle(scratch, lscratch/5, sizeof(int), rs); shuffle(scratch+lscratch/5, 4*lscratch/5, sizeof(int), rs); memset(state->nums, 0, o2 * sizeof(digit)); memset(state->flags, 0, o2 * sizeof(unsigned int)); if (state->adjacent) { /* All adjacency flags are always present. */ add_adjacent_flags(state, sq); } gg_solved = 0; if (game_assemble(state, scratch, sq, params->diff) < 0) goto generate; game_strip(state, scratch, sq, params->diff); if (params->diff > 0) { game_state *copy = dup_game(state); nsol = solver_state(copy, params->diff-1); free_game(copy); if (nsol > 0) { #ifdef STANDALONE_SOLVER if (solver_show_working) printf("game_assemble: puzzle as generated is too easy.\n"); #endif if (ntries < MAXTRIES) { ntries++; goto generate; } #ifdef STANDALONE_SOLVER if (solver_show_working) printf("Unable to generate %s %dx%d after %d attempts.\n", unequal_diffnames[params->diff], params->order, params->order, MAXTRIES); #endif params->diff--; } } #ifdef STANDALONE_SOLVER if (solver_show_working) printf("new_game_desc: generated %s puzzle; %d attempts (%d solver).\n", unequal_diffnames[params->diff], ntries, gg_solved); #endif ret = NULL; retlen = 0; for (y = 0; y < params->order; y++) { for (x = 0; x < params->order; x++) { unsigned int f = GRID(state, flags, x, y); k = sprintf(buf, "%d%s%s%s%s,", GRID(state, nums, x, y), (f & F_ADJ_UP) ? "U" : "", (f & F_ADJ_RIGHT) ? "R" : "", (f & F_ADJ_DOWN) ? "D" : "", (f & F_ADJ_LEFT) ? "L" : ""); ret = sresize(ret, retlen + k + 1, char); strcpy(ret + retlen, buf); retlen += k; } } *aux = latin_desc(sq, params->order); free_game(state); sfree(sq); sfree(scratch); return ret; } static game_state *load_game(const game_params *params, const char *desc, char **why_r) { game_state *state = blank_game(params->order, params->adjacent); const char *p = desc; int i = 0, n, o = params->order, x, y; char *why = NULL; while (*p) { while (*p >= 'a' && *p <= 'z') { i += *p - 'a' + 1; p++; } if (i >= o*o) { why = "Too much data to fill grid"; goto fail; } if (*p < '0' || *p > '9') { why = "Expecting number in game description"; goto fail; } n = atoi(p); if (n < 0 || n > o) { why = "Out-of-range number in game description"; goto fail; } state->nums[i] = (digit)n; while (*p >= '0' && *p <= '9') p++; /* skip number */ if (state->nums[i] != 0) state->flags[i] |= F_IMMUTABLE; /* === number set by game description */ while (*p == 'U' || *p == 'R' || *p == 'D' || *p == 'L') { switch (*p) { case 'U': state->flags[i] |= F_ADJ_UP; break; case 'R': state->flags[i] |= F_ADJ_RIGHT; break; case 'D': state->flags[i] |= F_ADJ_DOWN; break; case 'L': state->flags[i] |= F_ADJ_LEFT; break; default: why = "Expecting flag URDL in game description"; goto fail; } p++; } i++; if (i < o*o && *p != ',') { why = "Missing separator"; goto fail; } if (*p == ',') p++; } if (i < o*o) { why = "Not enough data to fill grid"; goto fail; } i = 0; for (y = 0; y < o; y++) { for (x = 0; x < o; x++) { for (n = 0; n < 4; n++) { if (GRID(state, flags, x, y) & adjthan[n].f) { int nx = x + adjthan[n].dx; int ny = y + adjthan[n].dy; /* a flag must not point us off the grid. */ if (nx < 0 || ny < 0 || nx >= o || ny >= o) { why = "Flags go off grid"; goto fail; } if (params->adjacent) { /* if one cell is adjacent to another, the other must * also be adjacent to the first. */ if (!(GRID(state, flags, nx, ny) & adjthan[n].fo)) { why = "Flags contradicting each other"; goto fail; } } else { /* if one cell is GT another, the other must _not_ also * be GT the first. */ if (GRID(state, flags, nx, ny) & adjthan[n].fo) { why = "Flags contradicting each other"; goto fail; } } } } } } return state; fail: free_game(state); if (why_r) *why_r = why; return NULL; } static game_state *new_game(midend *me, const game_params *params, const char *desc) { game_state *state = load_game(params, desc, NULL); if (!state) { assert("Unable to load ?validated game."); return NULL; } return state; } static char *validate_desc(const game_params *params, const char *desc) { char *why = NULL; game_state *dummy = load_game(params, desc, &why); if (dummy) { free_game(dummy); assert(!why); } else assert(why); return why; } static char *solve_game(const game_state *state, const game_state *currstate, const char *aux, char **error) { game_state *solved; int r; char *ret = NULL; if (aux) return dupstr(aux); solved = dup_game(state); for (r = 0; r < state->order*state->order; r++) { if (!(solved->flags[r] & F_IMMUTABLE)) solved->nums[r] = 0; } r = solver_state(solved, DIFFCOUNT-1); /* always use full solver */ if (r > 0) ret = latin_desc(solved->nums, solved->order); free_game(solved); return ret; } /* ---------------------------------------------------------- * Game UI input processing. */ struct game_ui { int hx, hy; /* as for solo.c, highlight pos */ int hshow, hpencil, hcursor; /* show state, type, and ?cursor. */ }; static game_ui *new_ui(const game_state *state) { game_ui *ui = snew(game_ui); ui->hx = ui->hy = 0; ui->hpencil = ui->hshow = ui->hcursor = 0; return ui; } static void free_ui(game_ui *ui) { sfree(ui); } static char *encode_ui(const game_ui *ui) { return NULL; } static void decode_ui(game_ui *ui, const char *encoding) { } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { /* See solo.c; if we were pencil-mode highlighting and * somehow a square has just been properly filled, cancel * pencil mode. */ if (ui->hshow && ui->hpencil && !ui->hcursor && GRID(newstate, nums, ui->hx, ui->hy) != 0) { ui->hshow = 0; } } struct game_drawstate { int tilesize, order, started, adjacent; digit *nums; /* copy of nums, o^2 */ unsigned char *hints; /* copy of hints, o^3 */ unsigned int *flags; /* o^2 */ int hx, hy, hshow, hpencil; /* as for game_ui. */ int hflash; }; static char *interpret_move(const game_state *state, game_ui *ui, const game_drawstate *ds, int ox, int oy, int button) { int x = FROMCOORD(ox), y = FROMCOORD(oy), n; char buf[80]; int shift_or_control = button & (MOD_SHFT | MOD_CTRL); button &= ~MOD_MASK; if (x >= 0 && x < ds->order && y >= 0 && y < ds->order && IS_MOUSE_DOWN(button)) { if (oy - COORD(y) > TILE_SIZE && ox - COORD(x) > TILE_SIZE) return NULL; if (oy - COORD(y) > TILE_SIZE) { if (GRID(state, flags, x, y) & F_ADJ_DOWN) sprintf(buf, "F%d,%d,%d", x, y, F_SPENT_DOWN); else if (y + 1 < ds->order && GRID(state, flags, x, y + 1) & F_ADJ_UP) sprintf(buf, "F%d,%d,%d", x, y + 1, F_SPENT_UP); else return NULL; return dupstr(buf); } if (ox - COORD(x) > TILE_SIZE) { if (GRID(state, flags, x, y) & F_ADJ_RIGHT) sprintf(buf, "F%d,%d,%d", x, y, F_SPENT_RIGHT); else if (x + 1 < ds->order && GRID(state, flags, x + 1, y) & F_ADJ_LEFT) sprintf(buf, "F%d,%d,%d", x + 1, y, F_SPENT_LEFT); else return NULL; return dupstr(buf); } if (button == LEFT_BUTTON) { /* normal highlighting for non-immutable squares */ if (GRID(state, flags, x, y) & F_IMMUTABLE) ui->hshow = 0; else if (x == ui->hx && y == ui->hy && ui->hshow && ui->hpencil == 0) ui->hshow = 0; else { ui->hx = x; ui->hy = y; ui->hpencil = 0; ui->hshow = 1; } ui->hcursor = 0; return ""; } if (button == RIGHT_BUTTON) { /* pencil highlighting for non-filled squares */ if (GRID(state, nums, x, y) != 0) ui->hshow = 0; else if (x == ui->hx && y == ui->hy && ui->hshow && ui->hpencil) ui->hshow = 0; else { ui->hx = x; ui->hy = y; ui->hpencil = 1; ui->hshow = 1; } ui->hcursor = 0; return ""; } } if (IS_CURSOR_MOVE(button)) { if (shift_or_control) { int nx = ui->hx, ny = ui->hy, i, self; move_cursor(button, &nx, &ny, ds->order, ds->order, FALSE); ui->hshow = ui->hcursor = 1; for (i = 0; i < 4 && (nx != ui->hx + adjthan[i].dx || ny != ui->hy + adjthan[i].dy); ++i); if (i == 4) return ""; /* invalid direction, i.e. out of the board */ if (!(GRID(state, flags, ui->hx, ui->hy) & adjthan[i].f || GRID(state, flags, nx, ny ) & adjthan[i].fo)) return ""; /* no clue to toggle */ if (state->adjacent) self = (adjthan[i].dx >= 0 && adjthan[i].dy >= 0); else self = (GRID(state, flags, ui->hx, ui->hy) & adjthan[i].f); if (self) sprintf(buf, "F%d,%d,%d", ui->hx, ui->hy, ADJ_TO_SPENT(adjthan[i].f)); else sprintf(buf, "F%d,%d,%d", nx, ny, ADJ_TO_SPENT(adjthan[i].fo)); return dupstr(buf); } else { move_cursor(button, &ui->hx, &ui->hy, ds->order, ds->order, FALSE); ui->hshow = ui->hcursor = 1; return ""; } } if (ui->hshow && IS_CURSOR_SELECT(button)) { ui->hpencil = 1 - ui->hpencil; ui->hcursor = 1; return ""; } n = c2n(button, state->order); if (ui->hshow && n >= 0 && n <= ds->order) { debug(("button %d, cbutton %d", button, (int)((char)button))); debug(("n %d, h (%d,%d) p %d flags 0x%x nums %d", n, ui->hx, ui->hy, ui->hpencil, GRID(state, flags, ui->hx, ui->hy), GRID(state, nums, ui->hx, ui->hy))); if (GRID(state, flags, ui->hx, ui->hy) & F_IMMUTABLE) return NULL; /* can't edit immutable square (!) */ if (ui->hpencil && GRID(state, nums, ui->hx, ui->hy) > 0) return NULL; /* can't change hints on filled square (!) */ sprintf(buf, "%c%d,%d,%d", (char)(ui->hpencil && n > 0 ? 'P' : 'R'), ui->hx, ui->hy, n); if (!ui->hcursor) ui->hshow = 0; return dupstr(buf); } if (button == 'H' || button == 'h') return dupstr("H"); if (button == 'M' || button == 'm') return dupstr("M"); return NULL; } static game_state *execute_move(const game_state *state, const char *move) { game_state *ret = NULL; int x, y, n, i, rc; debug(("execute_move: %s", move)); if ((move[0] == 'P' || move[0] == 'R') && sscanf(move+1, "%d,%d,%d", &x, &y, &n) == 3 && x >= 0 && x < state->order && y >= 0 && y < state->order && n >= 0 && n <= state->order) { ret = dup_game(state); if (move[0] == 'P' && n > 0) HINT(ret, x, y, n-1) = !HINT(ret, x, y, n-1); else { GRID(ret, nums, x, y) = n; for (i = 0; i < state->order; i++) HINT(ret, x, y, i) = 0; /* real change to grid; check for completion */ if (!ret->completed && check_complete(ret->nums, ret, 1) > 0) ret->completed = TRUE; } return ret; } else if (move[0] == 'S') { const char *p; ret = dup_game(state); ret->completed = ret->cheated = TRUE; p = move+1; for (i = 0; i < state->order*state->order; i++) { n = c2n((int)*p, state->order); if (!*p || n <= 0 || n > state->order) goto badmove; ret->nums[i] = n; p++; } if (*p) goto badmove; rc = check_complete(ret->nums, ret, 1); assert(rc > 0); return ret; } else if (move[0] == 'M') { ret = dup_game(state); for (x = 0; x < state->order; x++) { for (y = 0; y < state->order; y++) { for (n = 0; n < state->order; n++) { HINT(ret, x, y, n) = 1; } } } return ret; } else if (move[0] == 'H') { return solver_hint(state, NULL, DIFF_EASY, DIFF_EASY); } else if (move[0] == 'F' && sscanf(move+1, "%d,%d,%d", &x, &y, &n) == 3 && x >= 0 && x < state->order && y >= 0 && y < state->order) { ret = dup_game(state); GRID(ret, flags, x, y) ^= n; return ret; } badmove: if (ret) free_game(ret); return NULL; } /* ---------------------------------------------------------------------- * Drawing/printing routines. */ #define DRAW_SIZE (TILE_SIZE*ds->order + GAP_SIZE*(ds->order-1) + BORDER*2) static void game_compute_size(const game_params *params, int tilesize, int *x, int *y) { /* Ick: fake up `ds->tilesize' for macro expansion purposes */ struct { int tilesize, order; } ads, *ds = &ads; ads.tilesize = tilesize; ads.order = params->order; *x = *y = DRAW_SIZE; } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { ds->tilesize = tilesize; } static float *game_colours(frontend *fe, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float); int i; game_mkhighlight(fe, ret, COL_BACKGROUND, COL_HIGHLIGHT, COL_LOWLIGHT); for (i = 0; i < 3; i++) { ret[COL_TEXT * 3 + i] = 0.0F; ret[COL_GRID * 3 + i] = 0.5F; } /* Lots of these were taken from solo.c. */ ret[COL_GUESS * 3 + 0] = 0.0F; ret[COL_GUESS * 3 + 1] = 0.6F * ret[COL_BACKGROUND * 3 + 1]; ret[COL_GUESS * 3 + 2] = 0.0F; ret[COL_ERROR * 3 + 0] = 1.0F; ret[COL_ERROR * 3 + 1] = 0.0F; ret[COL_ERROR * 3 + 2] = 0.0F; ret[COL_PENCIL * 3 + 0] = 0.5F * ret[COL_BACKGROUND * 3 + 0]; ret[COL_PENCIL * 3 + 1] = 0.5F * ret[COL_BACKGROUND * 3 + 1]; ret[COL_PENCIL * 3 + 2] = ret[COL_BACKGROUND * 3 + 2]; *ncolours = NCOLOURS; return ret; } static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { struct game_drawstate *ds = snew(struct game_drawstate); int o2 = state->order*state->order, o3 = o2*state->order; ds->tilesize = 0; ds->order = state->order; ds->adjacent = state->adjacent; ds->nums = snewn(o2, digit); ds->hints = snewn(o3, unsigned char); ds->flags = snewn(o2, unsigned int); memset(ds->nums, 0, o2*sizeof(digit)); memset(ds->hints, 0, o3); memset(ds->flags, 0, o2*sizeof(unsigned int)); ds->hx = ds->hy = 0; ds->started = ds->hshow = ds->hpencil = ds->hflash = 0; return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { sfree(ds->nums); sfree(ds->hints); sfree(ds->flags); sfree(ds); } static void draw_gt(drawing *dr, int ox, int oy, int dx1, int dy1, int dx2, int dy2, int col) { int coords[12]; int xdx = (dx1+dx2 ? 0 : 1), xdy = (dx1+dx2 ? 1 : 0); coords[0] = ox + xdx; coords[1] = oy + xdy; coords[2] = ox + xdx + dx1; coords[3] = oy + xdy + dy1; coords[4] = ox + xdx + dx1 + dx2; coords[5] = oy + xdy + dy1 + dy2; coords[6] = ox - xdx + dx1 + dx2; coords[7] = oy - xdy + dy1 + dy2; coords[8] = ox - xdx + dx1; coords[9] = oy - xdy + dy1; coords[10] = ox - xdx; coords[11] = oy - xdy; draw_polygon(dr, coords, 6, col, col); } #define COLOUR(direction) (f & (F_ERROR_##direction) ? COL_ERROR : \ f & (F_SPENT_##direction) ? COL_SPENT : fg) static void draw_gts(drawing *dr, game_drawstate *ds, int ox, int oy, unsigned int f, int bg, int fg) { int g = GAP_SIZE, g2 = (g+1)/2, g4 = (g+1)/4; /* Draw all the greater-than signs emanating from this tile. */ if (f & F_ADJ_UP) { if (bg >= 0) draw_rect(dr, ox, oy - g, TILE_SIZE, g, bg); draw_gt(dr, ox+g2, oy-g4, g2, -g2, g2, g2, COLOUR(UP)); draw_update(dr, ox, oy-g, TILE_SIZE, g); } if (f & F_ADJ_RIGHT) { if (bg >= 0) draw_rect(dr, ox + TILE_SIZE, oy, g, TILE_SIZE, bg); draw_gt(dr, ox+TILE_SIZE+g4, oy+g2, g2, g2, -g2, g2, COLOUR(RIGHT)); draw_update(dr, ox+TILE_SIZE, oy, g, TILE_SIZE); } if (f & F_ADJ_DOWN) { if (bg >= 0) draw_rect(dr, ox, oy + TILE_SIZE, TILE_SIZE, g, bg); draw_gt(dr, ox+g2, oy+TILE_SIZE+g4, g2, g2, g2, -g2, COLOUR(DOWN)); draw_update(dr, ox, oy+TILE_SIZE, TILE_SIZE, g); } if (f & F_ADJ_LEFT) { if (bg >= 0) draw_rect(dr, ox - g, oy, g, TILE_SIZE, bg); draw_gt(dr, ox-g4, oy+g2, -g2, g2, g2, g2, COLOUR(LEFT)); draw_update(dr, ox-g, oy, g, TILE_SIZE); } } static void draw_adjs(drawing *dr, game_drawstate *ds, int ox, int oy, unsigned int f, int bg, int fg) { int g = GAP_SIZE, g38 = 3*(g+1)/8, g4 = (g+1)/4; /* Draw all the adjacency bars relevant to this tile; we only have * to worry about F_ADJ_RIGHT and F_ADJ_DOWN. * * If we _only_ have the error flag set (i.e. it's not supposed to be * adjacent, but adjacent numbers were entered) draw an outline red bar. */ if (f & (F_ADJ_RIGHT|F_ERROR_RIGHT)) { if (f & F_ADJ_RIGHT) { draw_rect(dr, ox+TILE_SIZE+g38, oy, g4, TILE_SIZE, COLOUR(RIGHT)); } else { draw_rect_outline(dr, ox+TILE_SIZE+g38, oy, g4, TILE_SIZE, COL_ERROR); } } else if (bg >= 0) { draw_rect(dr, ox+TILE_SIZE+g38, oy, g4, TILE_SIZE, bg); } draw_update(dr, ox+TILE_SIZE, oy, g, TILE_SIZE); if (f & (F_ADJ_DOWN|F_ERROR_DOWN)) { if (f & F_ADJ_DOWN) { draw_rect(dr, ox, oy+TILE_SIZE+g38, TILE_SIZE, g4, COLOUR(DOWN)); } else { draw_rect_outline(dr, ox, oy+TILE_SIZE+g38, TILE_SIZE, g4, COL_ERROR); } } else if (bg >= 0) { draw_rect(dr, ox, oy+TILE_SIZE+g38, TILE_SIZE, g4, bg); } draw_update(dr, ox, oy+TILE_SIZE, TILE_SIZE, g); } static void draw_furniture(drawing *dr, game_drawstate *ds, const game_state *state, const game_ui *ui, int x, int y, int hflash) { int ox = COORD(x), oy = COORD(y), bg, hon; unsigned int f = GRID(state, flags, x, y); bg = hflash ? COL_HIGHLIGHT : COL_BACKGROUND; hon = (ui->hshow && x == ui->hx && y == ui->hy); /* Clear square. */ draw_rect(dr, ox, oy, TILE_SIZE, TILE_SIZE, (hon && !ui->hpencil) ? COL_HIGHLIGHT : bg); /* Draw the highlight (pencil or full), if we're the highlight */ if (hon && ui->hpencil) { int coords[6]; coords[0] = ox; coords[1] = oy; coords[2] = ox + TILE_SIZE/2; coords[3] = oy; coords[4] = ox; coords[5] = oy + TILE_SIZE/2; draw_polygon(dr, coords, 3, COL_HIGHLIGHT, COL_HIGHLIGHT); } /* Draw the square outline (which is the cursor, if we're the cursor). */ draw_rect_outline(dr, ox, oy, TILE_SIZE, TILE_SIZE, COL_GRID); draw_update(dr, ox, oy, TILE_SIZE, TILE_SIZE); /* Draw the adjacent clue signs. */ if (ds->adjacent) draw_adjs(dr, ds, ox, oy, f, COL_BACKGROUND, COL_GRID); else draw_gts(dr, ds, ox, oy, f, COL_BACKGROUND, COL_TEXT); } static void draw_num(drawing *dr, game_drawstate *ds, int x, int y) { int ox = COORD(x), oy = COORD(y); unsigned int f = GRID(ds,flags,x,y); char str[2]; /* (can assume square has just been cleared) */ /* Draw number, choosing appropriate colour */ str[0] = n2c(GRID(ds, nums, x, y), ds->order); str[1] = '\0'; draw_text(dr, ox + TILE_SIZE/2, oy + TILE_SIZE/2, FONT_VARIABLE, 3*TILE_SIZE/4, ALIGN_VCENTRE | ALIGN_HCENTRE, (f & F_IMMUTABLE) ? COL_TEXT : (f & F_ERROR) ? COL_ERROR : COL_GUESS, str); } static void draw_hints(drawing *dr, game_drawstate *ds, int x, int y) { int ox = COORD(x), oy = COORD(y); int nhints, i, j, hw, hh, hmax, fontsz; char str[2]; /* (can assume square has just been cleared) */ /* Draw hints; steal ingenious algorithm (basically) * from solo.c:draw_number() */ for (i = nhints = 0; i < ds->order; i++) { if (HINT(ds, x, y, i)) nhints++; } for (hw = 1; hw * hw < nhints; hw++); if (hw < 3) hw = 3; hh = (nhints + hw - 1) / hw; if (hh < 2) hh = 2; hmax = max(hw, hh); fontsz = TILE_SIZE/(hmax*(11-hmax)/8); for (i = j = 0; i < ds->order; i++) { if (HINT(ds,x,y,i)) { int hx = j % hw, hy = j / hw; str[0] = n2c(i+1, ds->order); str[1] = '\0'; draw_text(dr, ox + (4*hx+3) * TILE_SIZE / (4*hw+2), oy + (4*hy+3) * TILE_SIZE / (4*hh+2), FONT_VARIABLE, fontsz, ALIGN_VCENTRE | ALIGN_HCENTRE, COL_PENCIL, str); j++; } } } static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float animtime, float flashtime) { int x, y, i, hchanged = 0, stale, hflash = 0; debug(("highlight old (%d,%d), new (%d,%d)", ds->hx, ds->hy, ui->hx, ui->hy)); if (flashtime > 0 && (flashtime <= FLASH_TIME/3 || flashtime >= FLASH_TIME*2/3)) hflash = 1; if (!ds->started) { draw_rect(dr, 0, 0, DRAW_SIZE, DRAW_SIZE, COL_BACKGROUND); draw_update(dr, 0, 0, DRAW_SIZE, DRAW_SIZE); } if (ds->hx != ui->hx || ds->hy != ui->hy || ds->hshow != ui->hshow || ds->hpencil != ui->hpencil) hchanged = 1; for (x = 0; x < ds->order; x++) { for (y = 0; y < ds->order; y++) { if (!ds->started) stale = 1; else if (hflash != ds->hflash) stale = 1; else stale = 0; if (hchanged) { if ((x == ui->hx && y == ui->hy) || (x == ds->hx && y == ds->hy)) stale = 1; } if (GRID(state, nums, x, y) != GRID(ds, nums, x, y)) { GRID(ds, nums, x, y) = GRID(state, nums, x, y); stale = 1; } if (GRID(state, flags, x, y) != GRID(ds, flags, x, y)) { GRID(ds, flags, x, y) = GRID(state, flags, x, y); stale = 1; } if (GRID(ds, nums, x, y) == 0) { /* We're not a number square (therefore we might * display hints); do we need to update? */ for (i = 0; i < ds->order; i++) { if (HINT(state, x, y, i) != HINT(ds, x, y, i)) { HINT(ds, x, y, i) = HINT(state, x, y, i); stale = 1; } } } if (stale) { draw_furniture(dr, ds, state, ui, x, y, hflash); if (GRID(ds, nums, x, y) > 0) draw_num(dr, ds, x, y); else draw_hints(dr, ds, x, y); } } } ds->hx = ui->hx; ds->hy = ui->hy; ds->hshow = ui->hshow; ds->hpencil = ui->hpencil; ds->started = 1; ds->hflash = hflash; } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return 0.0F; } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { if (!oldstate->completed && newstate->completed && !oldstate->cheated && !newstate->cheated) return FLASH_TIME; return 0.0F; } static int game_status(const game_state *state) { return state->completed ? +1 : 0; } static int game_timing_state(const game_state *state, game_ui *ui) { return TRUE; } static void game_print_size(const game_params *params, float *x, float *y) { int pw, ph; /* 10mm squares by default, roughly the same as Grauniad. */ game_compute_size(params, 1000, &pw, &ph); *x = pw / 100.0F; *y = ph / 100.0F; } static void game_print(drawing *dr, const game_state *state, int tilesize) { int ink = print_mono_colour(dr, 0); int x, y, o = state->order, ox, oy, n; char str[2]; /* Ick: fake up `ds->tilesize' for macro expansion purposes */ game_drawstate ads, *ds = &ads; game_set_size(dr, ds, NULL, tilesize); print_line_width(dr, 2 * TILE_SIZE / 40); /* Squares, numbers, gt signs */ for (y = 0; y < o; y++) { for (x = 0; x < o; x++) { ox = COORD(x); oy = COORD(y); n = GRID(state, nums, x, y); draw_rect_outline(dr, ox, oy, TILE_SIZE, TILE_SIZE, ink); str[0] = n ? n2c(n, state->order) : ' '; str[1] = '\0'; draw_text(dr, ox + TILE_SIZE/2, oy + TILE_SIZE/2, FONT_VARIABLE, TILE_SIZE/2, ALIGN_VCENTRE | ALIGN_HCENTRE, ink, str); if (state->adjacent) draw_adjs(dr, ds, ox, oy, GRID(state, flags, x, y), -1, ink); else draw_gts(dr, ds, ox, oy, GRID(state, flags, x, y), -1, ink); } } } /* ---------------------------------------------------------------------- * Housekeeping. */ #ifdef COMBINED #define thegame unequal #endif const struct game thegame = { "Unequal", "games.unequal", "unequal", default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, TRUE, solve_game, TRUE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, PREFERRED_TILE_SIZE, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, TRUE, FALSE, game_print_size, game_print, FALSE, /* wants_statusbar */ FALSE, game_timing_state, REQUIRE_RBUTTON | REQUIRE_NUMPAD, /* flags */ }; /* ---------------------------------------------------------------------- * Standalone solver. */ #ifdef STANDALONE_SOLVER #include #include const char *quis = NULL; #if 0 /* currently unused */ static void debug_printf(char *fmt, ...) { char buf[4096]; va_list ap; va_start(ap, fmt); vsprintf(buf, fmt, ap); puts(buf); va_end(ap); } static void game_printf(game_state *state) { char *dbg = game_text_format(state); printf("%s", dbg); sfree(dbg); } static void game_printf_wide(game_state *state) { int x, y, i, n; for (y = 0; y < state->order; y++) { for (x = 0; x < state->order; x++) { n = GRID(state, nums, x, y); for (i = 0; i < state->order; i++) { if (n > 0) printf("%c", n2c(n, state->order)); else if (HINT(state, x, y, i)) printf("%c", n2c(i+1, state->order)); else printf("."); } printf(" "); } printf("\n"); } printf("\n"); } #endif static void pdiff(int diff) { if (diff == DIFF_IMPOSSIBLE) printf("Game is impossible.\n"); else if (diff == DIFF_UNFINISHED) printf("Game has incomplete.\n"); else if (diff == DIFF_AMBIGUOUS) printf("Game has multiple solutions.\n"); else printf("Game has difficulty %s.\n", unequal_diffnames[diff]); } static int solve(game_params *p, char *desc, int debug) { game_state *state = new_game(NULL, p, desc); struct solver_ctx *ctx = new_ctx(state); struct latin_solver solver; int diff; solver_show_working = debug; game_debug(state); latin_solver_alloc(&solver, state->nums, state->order); diff = latin_solver_main(&solver, DIFF_RECURSIVE, DIFF_LATIN, DIFF_SET, DIFF_EXTREME, DIFF_EXTREME, DIFF_RECURSIVE, unequal_solvers, ctx, clone_ctx, free_ctx); free_ctx(ctx); latin_solver_free(&solver); if (debug) pdiff(diff); game_debug(state); free_game(state); return diff; } static void check(game_params *p) { char *msg = validate_params(p, 1); if (msg) { fprintf(stderr, "%s: %s", quis, msg); exit(1); } } static int gen(game_params *p, random_state *rs, int debug) { char *desc, *aux; int diff; check(p); solver_show_working = debug; desc = new_game_desc(p, rs, &aux, 0); diff = solve(p, desc, debug); sfree(aux); sfree(desc); return diff; } static void soak(game_params *p, random_state *rs) { time_t tt_start, tt_now, tt_last; char *aux, *desc; game_state *st; int n = 0, neasy = 0, realdiff = p->diff; check(p); solver_show_working = 0; maxtries = 1; tt_start = tt_now = time(NULL); printf("Soak-generating an %s %dx%d grid, difficulty %s.\n", p->adjacent ? "adjacent" : "unequal", p->order, p->order, unequal_diffnames[p->diff]); while (1) { p->diff = realdiff; desc = new_game_desc(p, rs, &aux, 0); st = new_game(NULL, p, desc); solver_state(st, DIFF_RECURSIVE); free_game(st); sfree(aux); sfree(desc); n++; if (realdiff != p->diff) neasy++; tt_last = time(NULL); if (tt_last > tt_now) { tt_now = tt_last; printf("%d total, %3.1f/s; %d/%2.1f%% easy, %3.1f/s good.\n", n, (double)n / ((double)tt_now - tt_start), neasy, (double)neasy*100.0/(double)n, (double)(n - neasy) / ((double)tt_now - tt_start)); } } } static void usage_exit(const char *msg) { if (msg) fprintf(stderr, "%s: %s\n", quis, msg); fprintf(stderr, "Usage: %s [--seed SEED] --soak | [game_id [game_id ...]]\n", quis); exit(1); } int main(int argc, const char *argv[]) { random_state *rs; time_t seed = time(NULL); int do_soak = 0, diff; game_params *p; maxtries = 50; quis = argv[0]; while (--argc > 0) { const char *p = *++argv; if (!strcmp(p, "--soak")) do_soak = 1; else if (!strcmp(p, "--seed")) { if (argc == 0) usage_exit("--seed needs an argument"); seed = (time_t)atoi(*++argv); argc--; } else if (*p == '-') usage_exit("unrecognised option"); else break; } rs = random_new((void*)&seed, sizeof(time_t)); if (do_soak == 1) { if (argc != 1) usage_exit("only one argument for --soak"); p = default_params(); decode_params(p, *argv); soak(p, rs); } else if (argc > 0) { int i; for (i = 0; i < argc; i++) { const char *id = *argv++; char *desc = strchr(id, ':'), *err; p = default_params(); if (desc) { *desc++ = '\0'; decode_params(p, id); err = validate_desc(p, desc); if (err) { fprintf(stderr, "%s: %s\n", quis, err); exit(1); } solve(p, desc, 1); } else { decode_params(p, id); diff = gen(p, rs, 1); } } } else { while(1) { p = default_params(); p->order = random_upto(rs, 7) + 3; p->diff = random_upto(rs, 4); diff = gen(p, rs, 0); pdiff(diff); } } return 0; } #endif /* vim: set shiftwidth=4 tabstop=8: */ puzzles-20170606.272beef/undead.c0000644000175000017500000026311113115373615015301 0ustar simonsimon/* * undead: Implementation of Haunted Mirror Mazes * * http://www.janko.at/Raetsel/Spukschloss/index.htm * * Puzzle definition is the total number of each monster type, the * grid definition, and the list of sightings (clockwise, starting * from top left corner) * * Example: (Janko puzzle No. 1, * http://www.janko.at/Raetsel/Spukschloss/001.a.htm ) * * Ghosts: 0 Vampires: 2 Zombies: 6 * * 2 1 1 1 * 1 \ \ . / 2 * 0 \ . / . 2 * 0 / . / . 2 * 3 . . . \ 2 * 3 3 2 2 * * would be encoded into: * 4x4:0,2,6,LLaRLaRaRaRdL,2,1,1,1,2,2,2,2,2,2,3,3,3,0,0,1 * * Additionally, the game description can contain monsters fixed at a * certain grid position. The internal generator does not (yet) use * this feature, but this is needed to enter puzzles like Janko No. * 14, which is encoded as: * 8x5:12,12,0,LaRbLaRaLaRLbRaVaVaGRaRaRaLbLaRbRLb,0,2,0,2,2,1,2,1,3,1,0,1,8,4,3,0,0,2,3,2,7,2,1,6,2,1 * */ #include #include #include #include #include #include #include "puzzles.h" enum { COL_BACKGROUND, COL_GRID, COL_TEXT, COL_ERROR, COL_HIGHLIGHT, COL_FLASH, COL_GHOST, COL_ZOMBIE, COL_VAMPIRE, COL_DONE, NCOLOURS }; #define DIFFLIST(A) \ A(EASY,Easy,e) \ A(NORMAL,Normal,n) \ A(TRICKY,Tricky,t) #define ENUM(upper,title,lower) DIFF_ ## upper, #define TITLE(upper,title,lower) #title, #define ENCODE(upper,title,lower) #lower #define CONFIG(upper,title,lower) ":" #title enum { DIFFLIST(ENUM) DIFFCOUNT }; static char const *const undead_diffnames[] = { DIFFLIST(TITLE) "(count)" }; static char const undead_diffchars[] = DIFFLIST(ENCODE); #define DIFFCONFIG DIFFLIST(CONFIG) struct game_params { int w; /* Grid width */ int h; /* Grid height */ int diff; /* Puzzle difficulty */ }; static const struct game_params undead_presets[] = { { 4, 4, DIFF_EASY }, { 4, 4, DIFF_NORMAL }, { 4, 4, DIFF_TRICKY }, { 5, 5, DIFF_EASY }, { 5, 5, DIFF_NORMAL }, { 5, 5, DIFF_TRICKY }, { 7, 7, DIFF_EASY }, { 7, 7, DIFF_NORMAL } }; #define DEFAULT_PRESET 1 static game_params *default_params(void) { game_params *ret = snew(game_params); *ret = undead_presets[DEFAULT_PRESET]; return ret; } static int game_fetch_preset(int i, char **name, game_params **params) { game_params *ret; char buf[64]; if (i < 0 || i >= lenof(undead_presets)) return FALSE; ret = default_params(); *ret = undead_presets[i]; /* struct copy */ *params = ret; sprintf(buf, "%dx%d %s", undead_presets[i].w, undead_presets[i].h, undead_diffnames[undead_presets[i].diff]); *name = dupstr(buf); return TRUE; } static void free_params(game_params *params) { sfree(params); } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } static void decode_params(game_params *params, char const *string) { params->w = params->h = atoi(string); while (*string && isdigit((unsigned char) *string)) ++string; if (*string == 'x') { string++; params->h = atoi(string); while (*string && isdigit((unsigned char)*string)) string++; } params->diff = DIFF_NORMAL; if (*string == 'd') { int i; string++; for (i = 0; i < DIFFCOUNT; i++) if (*string == undead_diffchars[i]) params->diff = i; if (*string) string++; } return; } static char *encode_params(const game_params *params, int full) { char buf[256]; sprintf(buf, "%dx%d", params->w, params->h); if (full) sprintf(buf + strlen(buf), "d%c", undead_diffchars[params->diff]); return dupstr(buf); } static config_item *game_configure(const game_params *params) { config_item *ret; char buf[64]; ret = snewn(4, config_item); ret[0].name = "Width"; ret[0].type = C_STRING; sprintf(buf, "%d", params->w); ret[0].sval = dupstr(buf); ret[0].ival = 0; ret[1].name = "Height"; ret[1].type = C_STRING; sprintf(buf, "%d", params->h); ret[1].sval = dupstr(buf); ret[1].ival = 0; ret[2].name = "Difficulty"; ret[2].type = C_CHOICES; ret[2].sval = DIFFCONFIG; ret[2].ival = params->diff; ret[3].name = NULL; ret[3].type = C_END; ret[3].sval = NULL; ret[3].ival = 0; return ret; } static game_params *custom_params(const config_item *cfg) { game_params *ret = snew(game_params); ret->w = atoi(cfg[0].sval); ret->h = atoi(cfg[1].sval); ret->diff = cfg[2].ival; return ret; } static char *validate_params(const game_params *params, int full) { if ((params->w * params->h ) > 54) return "Grid is too big"; if (params->w < 3) return "Width must be at least 3"; if (params->h < 3) return "Height must be at least 3"; if (params->diff >= DIFFCOUNT) return "Unknown difficulty rating"; return NULL; } /* --------------------------------------------------------------- */ /* Game state allocation, deallocation. */ struct path { int length; int *p; int grid_start; int grid_end; int num_monsters; int *mapping; int sightings_start; int sightings_end; int *xy; }; struct game_common { int refcount; struct game_params params; int wh; int num_ghosts,num_vampires,num_zombies,num_total; int num_paths; struct path *paths; int *grid; int *xinfo; int *fixed; int solved; }; struct game_state { struct game_common *common; int *guess; unsigned char *pencils; unsigned char *cell_errors; unsigned char *hint_errors; unsigned char *hints_done; unsigned char count_errors[3]; int solved; int cheated; }; static game_state *new_state(const game_params *params) { int i; game_state *state = snew(game_state); state->common = snew(struct game_common); state->common->refcount = 1; state->common->params.w = params->w; state->common->params.h = params->h; state->common->params.diff = params->diff; state->common->wh = (state->common->params.w +2) * (state->common->params.h +2); state->common->num_ghosts = 0; state->common->num_vampires = 0; state->common->num_zombies = 0; state->common->num_total = 0; state->common->grid = snewn(state->common->wh, int); state->common->xinfo = snewn(state->common->wh, int); state->common->fixed = NULL; state->common->solved = FALSE; state->common->num_paths = state->common->params.w + state->common->params.h; state->common->paths = snewn(state->common->num_paths, struct path); for (i=0;icommon->num_paths;i++) { state->common->paths[i].length = 0; state->common->paths[i].grid_start = -1; state->common->paths[i].grid_end = -1; state->common->paths[i].num_monsters = 0; state->common->paths[i].sightings_start = 0; state->common->paths[i].sightings_end = 0; state->common->paths[i].p = snewn(state->common->wh,int); state->common->paths[i].xy = snewn(state->common->wh,int); state->common->paths[i].mapping = snewn(state->common->wh,int); } state->guess = NULL; state->pencils = NULL; state->cell_errors = snewn(state->common->wh, unsigned char); for (i=0;icommon->wh;i++) state->cell_errors[i] = FALSE; state->hint_errors = snewn(2*state->common->num_paths, unsigned char); for (i=0;i<2*state->common->num_paths;i++) state->hint_errors[i] = FALSE; state->hints_done = snewn(2 * state->common->num_paths, unsigned char); memset(state->hints_done, 0, 2 * state->common->num_paths * sizeof(unsigned char)); for (i=0;i<3;i++) state->count_errors[i] = FALSE; state->solved = FALSE; state->cheated = FALSE; return state; } static game_state *dup_game(const game_state *state) { game_state *ret = snew(game_state); ret->common = state->common; ret->common->refcount++; if (state->guess != NULL) { ret->guess = snewn(ret->common->num_total,int); memcpy(ret->guess, state->guess, ret->common->num_total*sizeof(int)); } else ret->guess = NULL; if (state->pencils != NULL) { ret->pencils = snewn(ret->common->num_total,unsigned char); memcpy(ret->pencils, state->pencils, ret->common->num_total*sizeof(unsigned char)); } else ret->pencils = NULL; if (state->cell_errors != NULL) { ret->cell_errors = snewn(ret->common->wh,unsigned char); memcpy(ret->cell_errors, state->cell_errors, ret->common->wh*sizeof(unsigned char)); } else ret->cell_errors = NULL; if (state->hint_errors != NULL) { ret->hint_errors = snewn(2*ret->common->num_paths,unsigned char); memcpy(ret->hint_errors, state->hint_errors, 2*ret->common->num_paths*sizeof(unsigned char)); } else ret->hint_errors = NULL; if (state->hints_done != NULL) { ret->hints_done = snewn(2 * state->common->num_paths, unsigned char); memcpy(ret->hints_done, state->hints_done, 2 * state->common->num_paths * sizeof(unsigned char)); } else ret->hints_done = NULL; ret->count_errors[0] = state->count_errors[0]; ret->count_errors[1] = state->count_errors[1]; ret->count_errors[2] = state->count_errors[2]; ret->solved = state->solved; ret->cheated = state->cheated; return ret; } static void free_game(game_state *state) { int i; state->common->refcount--; if (state->common->refcount == 0) { for (i=0;icommon->num_paths;i++) { sfree(state->common->paths[i].mapping); sfree(state->common->paths[i].xy); sfree(state->common->paths[i].p); } sfree(state->common->paths); sfree(state->common->xinfo); sfree(state->common->grid); if (state->common->fixed != NULL) sfree(state->common->fixed); sfree(state->common); } if (state->hints_done != NULL) sfree(state->hints_done); if (state->hint_errors != NULL) sfree(state->hint_errors); if (state->cell_errors != NULL) sfree(state->cell_errors); if (state->pencils != NULL) sfree(state->pencils); if (state->guess != NULL) sfree(state->guess); sfree(state); return; } /* --------------------------------------------------------------- */ /* Puzzle generator */ /* cell states */ enum { CELL_EMPTY, CELL_MIRROR_L, CELL_MIRROR_R, CELL_GHOST, CELL_VAMPIRE, CELL_ZOMBIE, CELL_UNDEF }; /* grid walk directions */ enum { DIRECTION_NONE, DIRECTION_UP, DIRECTION_RIGHT, DIRECTION_LEFT, DIRECTION_DOWN }; int range2grid(int rangeno, int width, int height, int *x, int *y) { if (rangeno < 0) { *x = 0; *y = 0; return DIRECTION_NONE; } if (rangeno < width) { *x = rangeno+1; *y = 0; return DIRECTION_DOWN; } rangeno = rangeno - width; if (rangeno < height) { *x = width+1; *y = rangeno+1; return DIRECTION_LEFT; } rangeno = rangeno - height; if (rangeno < width) { *x = width-rangeno; *y = height+1; return DIRECTION_UP; } rangeno = rangeno - width; if (rangeno < height) { *x = 0; *y = height-rangeno; return DIRECTION_RIGHT; } *x = 0; *y = 0; return DIRECTION_NONE; } int grid2range(int x, int y, int w, int h) { if (x>0 && x0 && yw+1 || y<0 || y>h+1) return -1; if ((x == 0 || x==w+1) && (y==0 || y==h+1)) return -1; if (y==0) return x-1; if (x==(w+1)) return y-1+w; if (y==(h+1)) return 2*w + h - x; return 2*(w+h) - y; } void make_paths(game_state *state) { int i; int count = 0; for (i=0;i<2*(state->common->params.w + state->common->params.h);i++) { int x,y,dir; int j,k,num_monsters; int found; int c,p; found = FALSE; /* Check whether inverse path is already in list */ for (j=0;jcommon->paths[j].grid_end) { found = TRUE; break; } } if (found) continue; /* We found a new path through the mirror maze */ state->common->paths[count].grid_start = i; dir = range2grid(i, state->common->params.w, state->common->params.h,&x,&y); state->common->paths[count].sightings_start = state->common->grid[x+y*(state->common->params.w +2)]; while (TRUE) { int c,r; if (dir == DIRECTION_DOWN) y++; else if (dir == DIRECTION_LEFT) x--; else if (dir == DIRECTION_UP) y--; else if (dir == DIRECTION_RIGHT) x++; r = grid2range(x, y, state->common->params.w, state->common->params.h); if (r != -1) { state->common->paths[count].grid_end = r; state->common->paths[count].sightings_end = state->common->grid[x+y*(state->common->params.w +2)]; break; } c = state->common->grid[x+y*(state->common->params.w+2)]; state->common->paths[count].xy[state->common->paths[count].length] = x+y*(state->common->params.w+2); if (c == CELL_MIRROR_L) { state->common->paths[count].p[state->common->paths[count].length] = -1; if (dir == DIRECTION_DOWN) dir = DIRECTION_RIGHT; else if (dir == DIRECTION_LEFT) dir = DIRECTION_UP; else if (dir == DIRECTION_UP) dir = DIRECTION_LEFT; else if (dir == DIRECTION_RIGHT) dir = DIRECTION_DOWN; } else if (c == CELL_MIRROR_R) { state->common->paths[count].p[state->common->paths[count].length] = -1; if (dir == DIRECTION_DOWN) dir = DIRECTION_LEFT; else if (dir == DIRECTION_LEFT) dir = DIRECTION_DOWN; else if (dir == DIRECTION_UP) dir = DIRECTION_RIGHT; else if (dir == DIRECTION_RIGHT) dir = DIRECTION_UP; } else { state->common->paths[count].p[state->common->paths[count].length] = state->common->xinfo[x+y*(state->common->params.w+2)]; } state->common->paths[count].length++; } /* Count unique monster entries in each path */ state->common->paths[count].num_monsters = 0; for (j=0;jcommon->num_total;j++) { num_monsters = 0; for (k=0;kcommon->paths[count].length;k++) if (state->common->paths[count].p[k] == j) num_monsters++; if (num_monsters > 0) state->common->paths[count].num_monsters++; } /* Generate mapping vector */ c = 0; for (p=0;pcommon->paths[count].length;p++) { int m; m = state->common->paths[count].p[p]; if (m == -1) continue; found = FALSE; for (j=0; jcommon->paths[count].mapping[j] == m) found = TRUE; if (!found) state->common->paths[count].mapping[c++] = m; } count++; } return; } struct guess { int length; int *guess; int *possible; }; int next_list(struct guess *g, int pos) { if (pos == 0) { if ((g->guess[pos] == 1 && g->possible[pos] == 1) || (g->guess[pos] == 2 && (g->possible[pos] == 3 || g->possible[pos] == 2)) || g->guess[pos] == 4) return FALSE; if (g->guess[pos] == 1 && (g->possible[pos] == 3 || g->possible[pos] == 7)) { g->guess[pos] = 2; return TRUE; } if (g->guess[pos] == 1 && g->possible[pos] == 5) { g->guess[pos] = 4; return TRUE; } if (g->guess[pos] == 2 && (g->possible[pos] == 6 || g->possible[pos] == 7)) { g->guess[pos] = 4; return TRUE; } } if (g->guess[pos] == 1) { if (g->possible[pos] == 1) { return next_list(g,pos-1); } if (g->possible[pos] == 3 || g->possible[pos] == 7) { g->guess[pos] = 2; return TRUE; } if (g->possible[pos] == 5) { g->guess[pos] = 4; return TRUE; } } if (g->guess[pos] == 2) { if (g->possible[pos] == 2) { return next_list(g,pos-1); } if (g->possible[pos] == 3) { g->guess[pos] = 1; return next_list(g,pos-1); } if (g->possible[pos] == 6 || g->possible[pos] == 7) { g->guess[pos] = 4; return TRUE; } } if (g->guess[pos] == 4) { if (g->possible[pos] == 5 || g->possible[pos] == 7) { g->guess[pos] = 1; return next_list(g,pos-1); } if (g->possible[pos] == 6) { g->guess[pos] = 2; return next_list(g,pos-1); } if (g->possible[pos] == 4) { return next_list(g,pos-1); } } return FALSE; } void get_unique(game_state *state, int counter, random_state *rs) { int p,i,c,pathlimit,count_uniques; struct guess path_guess; int *view_count; struct entry { struct entry *link; int *guess; int start_view; int end_view; }; struct { struct entry *head; struct entry *node; } views, single_views, test_views; struct entry test_entry; path_guess.length = state->common->paths[counter].num_monsters; path_guess.guess = snewn(path_guess.length,int); path_guess.possible = snewn(path_guess.length,int); for (i=0;iguess[state->common->paths[counter].mapping[p]]; switch (path_guess.possible[p]) { case 1: path_guess.guess[p] = 1; break; case 2: path_guess.guess[p] = 2; break; case 3: path_guess.guess[p] = 1; break; case 4: path_guess.guess[p] = 4; break; case 5: path_guess.guess[p] = 1; break; case 6: path_guess.guess[p] = 2; break; case 7: path_guess.guess[p] = 1; break; } } views.head = NULL; views.node = NULL; pathlimit = state->common->paths[counter].length + 1; view_count = snewn(pathlimit*pathlimit, int); for (i = 0; i < pathlimit*pathlimit; i++) view_count[i] = 0; do { int mirror, start_view, end_view; mirror = FALSE; start_view = 0; for (p=0;pcommon->paths[counter].length;p++) { if (state->common->paths[counter].p[p] == -1) mirror = TRUE; else { for (i=0;icommon->paths[counter].p[p] == state->common->paths[counter].mapping[i]) { if (path_guess.guess[i] == 1 && mirror == TRUE) start_view++; if (path_guess.guess[i] == 2 && mirror == FALSE) start_view++; if (path_guess.guess[i] == 4) start_view++; break; } } } } mirror = FALSE; end_view = 0; for (p=state->common->paths[counter].length-1;p>=0;p--) { if (state->common->paths[counter].p[p] == -1) mirror = TRUE; else { for (i=0;icommon->paths[counter].p[p] == state->common->paths[counter].mapping[i]) { if (path_guess.guess[i] == 1 && mirror == TRUE) end_view++; if (path_guess.guess[i] == 2 && mirror == FALSE) end_view++; if (path_guess.guess[i] == 4) end_view++; break; } } } } assert(start_view >= 0 && start_view < pathlimit); assert(end_view >= 0 && end_view < pathlimit); i = start_view * pathlimit + end_view; view_count[i]++; if (view_count[i] == 1) { views.node = snewn(1,struct entry); views.node->link = views.head; views.node->guess = snewn(path_guess.length,int); views.head = views.node; views.node->start_view = start_view; views.node->end_view = end_view; memcpy(views.node->guess, path_guess.guess, path_guess.length*sizeof(int)); } } while (next_list(&path_guess, path_guess.length-1)); /* extract single entries from view list */ test_views.head = views.head; test_views.node = views.node; test_entry.guess = snewn(path_guess.length,int); single_views.head = NULL; single_views.node = NULL; count_uniques = 0; while (test_views.head != NULL) { test_views.node = test_views.head; test_views.head = test_views.head->link; i = test_views.node->start_view * pathlimit + test_views.node->end_view; if (view_count[i] == 1) { single_views.node = snewn(1,struct entry); single_views.node->link = single_views.head; single_views.node->guess = snewn(path_guess.length,int); single_views.head = single_views.node; single_views.node->start_view = test_views.node->start_view; single_views.node->end_view = test_views.node->end_view; memcpy(single_views.node->guess, test_views.node->guess, path_guess.length*sizeof(int)); count_uniques++; } } sfree(view_count); if (count_uniques > 0) { test_entry.start_view = 0; test_entry.end_view = 0; /* Choose one unique guess per random */ /* While we are busy with looping through single_views, we * conveniently free the linked list single_view */ c = random_upto(rs,count_uniques); while(single_views.head != NULL) { single_views.node = single_views.head; single_views.head = single_views.head->link; if (c-- == 0) { memcpy(test_entry.guess, single_views.node->guess, path_guess.length*sizeof(int)); test_entry.start_view = single_views.node->start_view; test_entry.end_view = single_views.node->end_view; } sfree(single_views.node->guess); sfree(single_views.node); } /* Modify state_guess according to path_guess.mapping */ for (i=0;iguess[state->common->paths[counter].mapping[i]] = test_entry.guess[i]; } sfree(test_entry.guess); while (views.head != NULL) { views.node = views.head; views.head = views.head->link; sfree(views.node->guess); sfree(views.node); } sfree(path_guess.possible); sfree(path_guess.guess); return; } int count_monsters(game_state *state, int *cGhost, int *cVampire, int *cZombie) { int cNone; int i; *cGhost = *cVampire = *cZombie = cNone = 0; for (i=0;icommon->num_total;i++) { if (state->guess[i] == 1) (*cGhost)++; else if (state->guess[i] == 2) (*cVampire)++; else if (state->guess[i] == 4) (*cZombie)++; else cNone++; } return cNone; } int check_numbers(game_state *state, int *guess) { int valid; int i; int count_ghosts, count_vampires, count_zombies; count_ghosts = count_vampires = count_zombies = 0; for (i=0;icommon->num_total;i++) { if (guess[i] == 1) count_ghosts++; if (guess[i] == 2) count_vampires++; if (guess[i] == 4) count_zombies++; } valid = TRUE; if (count_ghosts > state->common->num_ghosts) valid = FALSE; if (count_vampires > state->common->num_vampires) valid = FALSE; if (count_zombies > state->common->num_zombies) valid = FALSE; return valid; } int check_solution(int *g, struct path path) { int i; int mirror; int count; count = 0; mirror = FALSE; for (i=0;i=0;i--) { if (path.p[i] == -1) mirror = TRUE; else { if (g[path.p[i]] == 1 && mirror) count++; else if (g[path.p[i]] == 2 && !mirror) count++; else if (g[path.p[i]] == 4) count++; } } if (count != path.sightings_end) return FALSE; return TRUE; } int solve_iterative(game_state *state, struct path *paths) { int solved; int p,i,j,count; int *guess; int *possible; struct guess loop; solved = TRUE; loop.length = state->common->num_total; guess = snewn(state->common->num_total,int); possible = snewn(state->common->num_total,int); for (i=0;icommon->num_total;i++) { guess[i] = state->guess[i]; possible[i] = 0; } for (p=0;pcommon->num_paths;p++) { if (paths[p].num_monsters > 0) { loop.length = paths[p].num_monsters; loop.guess = snewn(paths[p].num_monsters,int); loop.possible = snewn(paths[p].num_monsters,int); for (i=0;iguess[paths[p].mapping[i]]) { case 1: loop.guess[i] = 1; break; case 2: loop.guess[i] = 2; break; case 3: loop.guess[i] = 1; break; case 4: loop.guess[i] = 4; break; case 5: loop.guess[i] = 1; break; case 6: loop.guess[i] = 2; break; case 7: loop.guess[i] = 1; break; } loop.possible[i] = state->guess[paths[p].mapping[i]]; possible[paths[p].mapping[i]] = 0; } while(TRUE) { for (i=0;icommon->num_total;i++) { guess[i] = state->guess[i]; } count = 0; for (i=0;iguess[paths[p].mapping[i]] &= possible[paths[p].mapping[i]]; sfree(loop.possible); sfree(loop.guess); } } for (i=0;icommon->num_total;i++) { if (state->guess[i] == 3 || state->guess[i] == 5 || state->guess[i] == 6 || state->guess[i] == 7) { solved = FALSE; break; } } sfree(possible); sfree(guess); return solved; } int solve_bruteforce(game_state *state, struct path *paths) { int solved, correct; int number_solutions; int p,i; struct guess loop; loop.guess = snewn(state->common->num_total,int); loop.possible = snewn(state->common->num_total,int); for (i=0;icommon->num_total;i++) { loop.possible[i] = state->guess[i]; switch (state->guess[i]) { case 1: loop.guess[i] = 1; break; case 2: loop.guess[i] = 2; break; case 3: loop.guess[i] = 1; break; case 4: loop.guess[i] = 4; break; case 5: loop.guess[i] = 1; break; case 6: loop.guess[i] = 2; break; case 7: loop.guess[i] = 1; break; } } solved = FALSE; number_solutions = 0; while (TRUE) { correct = TRUE; if (!check_numbers(state,loop.guess)) correct = FALSE; else for (p=0;pcommon->num_paths;p++) if (!check_solution(loop.guess,paths[p])) { correct = FALSE; break; } if (correct) { number_solutions++; solved = TRUE; if(number_solutions > 1) { solved = FALSE; break; } for (i=0;icommon->num_total;i++) state->guess[i] = loop.guess[i]; } if (!next_list(&loop,state->common->num_total -1)) { break; } } sfree(loop.possible); sfree(loop.guess); return solved; } int path_cmp(const void *a, const void *b) { const struct path *pa = (const struct path *)a; const struct path *pb = (const struct path *)b; return pa->num_monsters - pb->num_monsters; } static char *new_game_desc(const game_params *params, random_state *rs, char **aux, int interactive) { int i,count,c,w,h,r,p,g; game_state *new; /* Variables for puzzle generation algorithm */ int filling; int max_length; int count_ghosts, count_vampires, count_zombies; int abort; float ratio; /* Variables for solver algorithm */ int solved_iterative, solved_bruteforce, contains_inconsistency, count_ambiguous; int iterative_depth; int *old_guess; /* Variables for game description generation */ int x,y; char *e; char *desc; i = 0; while (TRUE) { new = new_state(params); abort = FALSE; /* Fill grid with random mirrors and (later to be populated) * empty monster cells */ count = 0; for (h=1;hcommon->params.h+1;h++) for (w=1;wcommon->params.w+1;w++) { c = random_upto(rs,5); if (c >= 2) { new->common->grid[w+h*(new->common->params.w+2)] = CELL_EMPTY; new->common->xinfo[w+h*(new->common->params.w+2)] = count++; } else if (c == 0) { new->common->grid[w+h*(new->common->params.w+2)] = CELL_MIRROR_L; new->common->xinfo[w+h*(new->common->params.w+2)] = -1; } else { new->common->grid[w+h*(new->common->params.w+2)] = CELL_MIRROR_R; new->common->xinfo[w+h*(new->common->params.w+2)] = -1; } } new->common->num_total = count; /* Total number of monsters in maze */ /* Puzzle is boring if it has too few monster cells. Discard * grid, make new grid */ if (new->common->num_total <= 4) { free_game(new); continue; } /* Monsters / Mirrors ratio should be balanced */ ratio = (float)new->common->num_total / (float)(new->common->params.w * new->common->params.h); if (ratio < 0.48 || ratio > 0.78) { free_game(new); continue; } /* Assign clue identifiers */ for (r=0;r<2*(new->common->params.w+new->common->params.h);r++) { int x,y,gridno; gridno = range2grid(r,new->common->params.w,new->common->params.h, &x,&y); new->common->grid[x+y*(new->common->params.w +2)] = gridno; new->common->xinfo[x+y*(new->common->params.w +2)] = 0; } /* The four corners don't matter at all for the game. Set them * all to zero, just to have a nice data structure */ new->common->grid[0] = 0; new->common->xinfo[0] = 0; new->common->grid[new->common->params.w+1] = 0; new->common->xinfo[new->common->params.w+1] = 0; new->common->grid[new->common->params.w+1 + (new->common->params.h+1)*(new->common->params.w+2)] = 0; new->common->xinfo[new->common->params.w+1 + (new->common->params.h+1)*(new->common->params.w+2)] = 0; new->common->grid[(new->common->params.h+1)*(new->common->params.w+2)] = 0; new->common->xinfo[(new->common->params.h+1)*(new->common->params.w+2)] = 0; /* Initialize solution vector */ new->guess = snewn(new->common->num_total,int); for (g=0;gcommon->num_total;g++) new->guess[g] = 7; /* Initialize fixed flag from common. Not needed for the * puzzle generator; initialize it for having clean code */ new->common->fixed = snewn(new->common->num_total,int); for (g=0;gcommon->num_total;g++) new->common->fixed[g] = FALSE; /* paths generation */ make_paths(new); /* Grid is invalid if max. path length > threshold. Discard * grid, make new one */ switch (new->common->params.diff) { case DIFF_EASY: max_length = min(new->common->params.w,new->common->params.h) + 1; break; case DIFF_NORMAL: max_length = (max(new->common->params.w,new->common->params.h) * 3) / 2; break; case DIFF_TRICKY: max_length = 9; break; default: max_length = 9; break; } for (p=0;pcommon->num_paths;p++) { if (new->common->paths[p].num_monsters > max_length) { abort = TRUE; } } if (abort) { free_game(new); continue; } qsort(new->common->paths, new->common->num_paths, sizeof(struct path), path_cmp); /* Grid monster initialization */ /* For easy puzzles, we try to fill nearly the whole grid with unique solution paths (up to 2) For more difficult puzzles, we fill only roughly half the grid, and choose random monsters for the rest For hard puzzles, we fill even less paths with unique solutions */ switch (new->common->params.diff) { case DIFF_EASY: filling = 2; break; case DIFF_NORMAL: filling = min( (new->common->params.w+new->common->params.h) , (new->common->num_total)/2 ); break; case DIFF_TRICKY: filling = max( (new->common->params.w+new->common->params.h) , (new->common->num_total)/2 ); break; default: filling = 0; break; } count = 0; while ( (count_monsters(new, &count_ghosts, &count_vampires, &count_zombies)) > filling) { if ((count) >= new->common->num_paths) break; if (new->common->paths[count].num_monsters == 0) { count++; continue; } get_unique(new,count,rs); count++; } /* Fill any remaining ambiguous entries with random monsters */ for(g=0;gcommon->num_total;g++) { if (new->guess[g] == 7) { r = random_upto(rs,3); new->guess[g] = (r == 0) ? 1 : ( (r == 1) ? 2 : 4 ); } } /* Determine all hints */ count_monsters(new, &new->common->num_ghosts, &new->common->num_vampires, &new->common->num_zombies); /* Puzzle is trivial if it has only one type of monster. Discard. */ if ((new->common->num_ghosts == 0 && new->common->num_vampires == 0) || (new->common->num_ghosts == 0 && new->common->num_zombies == 0) || (new->common->num_vampires == 0 && new->common->num_zombies == 0)) { free_game(new); continue; } /* Discard puzzle if difficulty Tricky, and it has only 1 * member of any monster type */ if (new->common->params.diff == DIFF_TRICKY && (new->common->num_ghosts <= 1 || new->common->num_vampires <= 1 || new->common->num_zombies <= 1)) { free_game(new); continue; } for (w=1;wcommon->params.w+1;w++) for (h=1;hcommon->params.h+1;h++) { c = new->common->xinfo[w+h*(new->common->params.w+2)]; if (c >= 0) { if (new->guess[c] == 1) new->common->grid[w+h*(new->common->params.w+2)] = CELL_GHOST; if (new->guess[c] == 2) new->common->grid[w+h*(new->common->params.w+2)] = CELL_VAMPIRE; if (new->guess[c] == 4) new->common->grid[w+h*(new->common->params.w+2)] = CELL_ZOMBIE; } } /* Prepare path information needed by the solver (containing all hints) */ for (p=0;pcommon->num_paths;p++) { int mirror,x,y; new->common->paths[p].sightings_start = 0; new->common->paths[p].sightings_end = 0; mirror = FALSE; for (g=0;gcommon->paths[p].length;g++) { if (new->common->paths[p].p[g] == -1) mirror = TRUE; else { if (new->guess[new->common->paths[p].p[g]] == 1 && mirror == TRUE) (new->common->paths[p].sightings_start)++; else if (new->guess[new->common->paths[p].p[g]] == 2 && mirror == FALSE) (new->common->paths[p].sightings_start)++; else if (new->guess[new->common->paths[p].p[g]] == 4) (new->common->paths[p].sightings_start)++; } } mirror = FALSE; for (g=new->common->paths[p].length-1;g>=0;g--) { if (new->common->paths[p].p[g] == -1) mirror = TRUE; else { if (new->guess[new->common->paths[p].p[g]] == 1 && mirror == TRUE) (new->common->paths[p].sightings_end)++; else if (new->guess[new->common->paths[p].p[g]] == 2 && mirror == FALSE) (new->common->paths[p].sightings_end)++; else if (new->guess[new->common->paths[p].p[g]] == 4) (new->common->paths[p].sightings_end)++; } } range2grid(new->common->paths[p].grid_start, new->common->params.w,new->common->params.h,&x,&y); new->common->grid[x+y*(new->common->params.w +2)] = new->common->paths[p].sightings_start; range2grid(new->common->paths[p].grid_end, new->common->params.w,new->common->params.h,&x,&y); new->common->grid[x+y*(new->common->params.w +2)] = new->common->paths[p].sightings_end; } /* Try to solve the puzzle with the iterative solver */ old_guess = snewn(new->common->num_total,int); for (p=0;pcommon->num_total;p++) { new->guess[p] = 7; old_guess[p] = 7; } iterative_depth = 0; solved_iterative = FALSE; contains_inconsistency = FALSE; count_ambiguous = 0; while (TRUE) { int no_change; no_change = TRUE; solved_iterative = solve_iterative(new,new->common->paths); iterative_depth++; for (p=0;pcommon->num_total;p++) { if (new->guess[p] != old_guess[p]) no_change = FALSE; old_guess[p] = new->guess[p]; if (new->guess[p] == 0) contains_inconsistency = TRUE; } if (solved_iterative || no_change) break; } /* If necessary, try to solve the puzzle with the brute-force solver */ solved_bruteforce = FALSE; if (new->common->params.diff != DIFF_EASY && !solved_iterative && !contains_inconsistency) { for (p=0;pcommon->num_total;p++) if (new->guess[p] != 1 && new->guess[p] != 2 && new->guess[p] != 4) count_ambiguous++; solved_bruteforce = solve_bruteforce(new, new->common->paths); } /* Determine puzzle difficulty level */ if (new->common->params.diff == DIFF_EASY && solved_iterative && iterative_depth <= 3 && !contains_inconsistency) { /* printf("Puzzle level: EASY Level %d Ratio %f Ambiguous %d (Found after %i tries)\n",iterative_depth, ratio, count_ambiguous, i); */ break; } if (new->common->params.diff == DIFF_NORMAL && ((solved_iterative && iterative_depth > 3) || (solved_bruteforce && count_ambiguous < 4)) && !contains_inconsistency) { /* printf("Puzzle level: NORMAL Level %d Ratio %f Ambiguous %d (Found after %d tries)\n", iterative_depth, ratio, count_ambiguous, i); */ break; } if (new->common->params.diff == DIFF_TRICKY && solved_bruteforce && iterative_depth > 0 && count_ambiguous >= 4 && !contains_inconsistency) { /* printf("Puzzle level: TRICKY Level %d Ratio %f Ambiguous %d (Found after %d tries)\n", iterative_depth, ratio, count_ambiguous, i); */ break; } /* If puzzle is not solvable or does not satisfy the desired * difficulty level, free memory and start from scratch */ sfree(old_guess); free_game(new); i++; } /* We have a valid puzzle! */ desc = snewn(10 + new->common->wh + 6*(new->common->params.w + new->common->params.h), char); e = desc; /* Encode monster counts */ e += sprintf(e, "%d,", new->common->num_ghosts); e += sprintf(e, "%d,", new->common->num_vampires); e += sprintf(e, "%d,", new->common->num_zombies); /* Encode grid */ count = 0; for (y=1;ycommon->params.h+1;y++) for (x=1;xcommon->params.w+1;x++) { c = new->common->grid[x+y*(new->common->params.w+2)]; if (count > 25) { *e++ = 'z'; count -= 26; } if (c != CELL_MIRROR_L && c != CELL_MIRROR_R) { count++; } else if (c == CELL_MIRROR_L) { if (count > 0) *e++ = (count-1 + 'a'); *e++ = 'L'; count = 0; } else { if (count > 0) *e++ = (count-1 + 'a'); *e++ = 'R'; count = 0; } } if (count > 0) *e++ = (count-1 + 'a'); /* Encode hints */ for (p=0;p<2*(new->common->params.w + new->common->params.h);p++) { range2grid(p,new->common->params.w,new->common->params.h,&x,&y); e += sprintf(e, ",%d", new->common->grid[x+y*(new->common->params.w+2)]); } *e++ = '\0'; desc = sresize(desc, e - desc, char); sfree(old_guess); free_game(new); return desc; } void num2grid(int num, int width, int height, int *x, int *y) { *x = 1+(num%width); *y = 1+(num/width); return; } static game_state *new_game(midend *me, const game_params *params, const char *desc) { int i; int n; int count; game_state *state = new_state(params); state->common->num_ghosts = atoi(desc); while (*desc && isdigit((unsigned char)*desc)) desc++; desc++; state->common->num_vampires = atoi(desc); while (*desc && isdigit((unsigned char)*desc)) desc++; desc++; state->common->num_zombies = atoi(desc); while (*desc && isdigit((unsigned char)*desc)) desc++; desc++; state->common->num_total = state->common->num_ghosts + state->common->num_vampires + state->common->num_zombies; state->guess = snewn(state->common->num_total,int); state->pencils = snewn(state->common->num_total,unsigned char); state->common->fixed = snewn(state->common->num_total,int); for (i=0;icommon->num_total;i++) { state->guess[i] = 7; state->pencils[i] = 0; state->common->fixed[i] = FALSE; } for (i=0;icommon->wh;i++) state->cell_errors[i] = FALSE; for (i=0;i<2*state->common->num_paths;i++) state->hint_errors[i] = FALSE; for (i=0;i<3;i++) state->count_errors[i] = FALSE; count = 0; n = 0; while (*desc != ',') { int c; int x,y; if (*desc == 'L') { num2grid(n,state->common->params.w,state->common->params.h,&x,&y); state->common->grid[x+y*(state->common->params.w +2)] = CELL_MIRROR_L; state->common->xinfo[x+y*(state->common->params.w+2)] = -1; n++; } else if (*desc == 'R') { num2grid(n,state->common->params.w,state->common->params.h,&x,&y); state->common->grid[x+y*(state->common->params.w +2)] = CELL_MIRROR_R; state->common->xinfo[x+y*(state->common->params.w+2)] = -1; n++; } else if (*desc == 'G') { num2grid(n,state->common->params.w,state->common->params.h,&x,&y); state->common->grid[x+y*(state->common->params.w +2)] = CELL_GHOST; state->common->xinfo[x+y*(state->common->params.w+2)] = count; state->guess[count] = 1; state->common->fixed[count++] = TRUE; n++; } else if (*desc == 'V') { num2grid(n,state->common->params.w,state->common->params.h,&x,&y); state->common->grid[x+y*(state->common->params.w +2)] = CELL_VAMPIRE; state->common->xinfo[x+y*(state->common->params.w+2)] = count; state->guess[count] = 2; state->common->fixed[count++] = TRUE; n++; } else if (*desc == 'Z') { num2grid(n,state->common->params.w,state->common->params.h,&x,&y); state->common->grid[x+y*(state->common->params.w +2)] = CELL_ZOMBIE; state->common->xinfo[x+y*(state->common->params.w+2)] = count; state->guess[count] = 4; state->common->fixed[count++] = TRUE; n++; } else { c = *desc - ('a' -1); while (c-- > 0) { num2grid(n,state->common->params.w,state->common->params.h,&x,&y); state->common->grid[x+y*(state->common->params.w +2)] = CELL_EMPTY; state->common->xinfo[x+y*(state->common->params.w+2)] = count; state->guess[count] = 7; state->common->fixed[count++] = FALSE; n++; } } desc++; } desc++; for (i=0;i<2*(state->common->params.w + state->common->params.h);i++) { int x,y; int sights; sights = atoi(desc); while (*desc && isdigit((unsigned char)*desc)) desc++; desc++; range2grid(i,state->common->params.w,state->common->params.h,&x,&y); state->common->grid[x+y*(state->common->params.w +2)] = sights; state->common->xinfo[x+y*(state->common->params.w +2)] = -2; } state->common->grid[0] = 0; state->common->xinfo[0] = -2; state->common->grid[state->common->params.w+1] = 0; state->common->xinfo[state->common->params.w+1] = -2; state->common->grid[state->common->params.w+1 + (state->common->params.h+1)*(state->common->params.w+2)] = 0; state->common->xinfo[state->common->params.w+1 + (state->common->params.h+1)*(state->common->params.w+2)] = -2; state->common->grid[(state->common->params.h+1)*(state->common->params.w+2)] = 0; state->common->xinfo[(state->common->params.h+1)*(state->common->params.w+2)] = -2; make_paths(state); qsort(state->common->paths, state->common->num_paths, sizeof(struct path), path_cmp); return state; } static char *validate_desc(const game_params *params, const char *desc) { int i; int w = params->w, h = params->h; int wh = w*h; int area; int monsters; int monster_count; const char *desc_s = desc; for (i=0;i<3;i++) { if (!*desc) return "Faulty game description"; while (*desc && isdigit((unsigned char)*desc)) { desc++; } if (*desc != ',') return "Invalid character in number list"; desc++; } desc = desc_s; area = monsters = monster_count = 0; for (i=0;i<3;i++) { monster_count += atoi(desc); while (*desc && isdigit((unsigned char)*desc)) desc++; desc++; } while (*desc && *desc != ',') { if (*desc >= 'a' && *desc <= 'z') { area += *desc - 'a' +1; monsters += *desc - 'a' +1; } else if (*desc == 'G' || *desc == 'V' || *desc == 'Z') { area++; monsters++; } else if (*desc == 'L' || *desc == 'R') { area++; } else return "Invalid character in grid specification"; desc++; } if (area < wh) return "Not enough data to fill grid"; else if (area > wh) return "Too much data to fill grid"; if (monsters != monster_count) return "Monster numbers do not match grid spaces"; for (i = 0; i < 2*(w+h); i++) { if (!*desc) return "Not enough numbers given after grid specification"; else if (*desc != ',') return "Invalid character in number list"; desc++; while (*desc && isdigit((unsigned char)*desc)) { desc++; } } if (*desc) return "Unexpected additional data at end of game description"; return NULL; } static char *solve_game(const game_state *state_start, const game_state *currstate, const char *aux, char **error) { int p; int *old_guess; int iterative_depth; int solved_iterative, solved_bruteforce, contains_inconsistency, count_ambiguous; int i; char *move, *c; game_state *solve_state = dup_game(currstate); old_guess = snewn(solve_state->common->num_total,int); for (p=0;pcommon->num_total;p++) { if (solve_state->common->fixed[p]) { old_guess[p] = solve_state->guess[p] = state_start->guess[p]; } else { old_guess[p] = solve_state->guess[p] = 7; } } iterative_depth = 0; solved_iterative = FALSE; contains_inconsistency = FALSE; count_ambiguous = 0; /* Try to solve the puzzle with the iterative solver */ while (TRUE) { int no_change; no_change = TRUE; solved_iterative = solve_iterative(solve_state,solve_state->common->paths); iterative_depth++; for (p=0;pcommon->num_total;p++) { if (solve_state->guess[p] != old_guess[p]) no_change = FALSE; old_guess[p] = solve_state->guess[p]; if (solve_state->guess[p] == 0) contains_inconsistency = TRUE; } if (solved_iterative || no_change || contains_inconsistency) break; } if (contains_inconsistency) { *error = "Puzzle is inconsistent"; sfree(old_guess); free_game(solve_state); return NULL; } /* If necessary, try to solve the puzzle with the brute-force solver */ solved_bruteforce = FALSE; if (!solved_iterative) { for (p=0;pcommon->num_total;p++) if (solve_state->guess[p] != 1 && solve_state->guess[p] != 2 && solve_state->guess[p] != 4) count_ambiguous++; solved_bruteforce = solve_bruteforce(solve_state, solve_state->common->paths); } if (!solved_iterative && !solved_bruteforce) { *error = "Puzzle is unsolvable"; sfree(old_guess); free_game(solve_state); return NULL; } /* printf("Puzzle solved at level %s, iterations %d, ambiguous %d\n", (solved_bruteforce ? "TRICKY" : "NORMAL"), iterative_depth, count_ambiguous); */ move = snewn(solve_state->common->num_total * 4 +2, char); c = move; *c++='S'; for (i = 0; i < solve_state->common->num_total; i++) { if (solve_state->guess[i] == 1) c += sprintf(c, ";G%d", i); if (solve_state->guess[i] == 2) c += sprintf(c, ";V%d", i); if (solve_state->guess[i] == 4) c += sprintf(c, ";Z%d", i); } *c++ = '\0'; move = sresize(move, c - move, char); sfree(old_guess); free_game(solve_state); return move; } static int game_can_format_as_text_now(const game_params *params) { return TRUE; } static char *game_text_format(const game_state *state) { int w,h,c,r,xi,g; char *ret; char buf[120]; ret = snewn(50 + 6*(state->common->params.w +2) + 6*(state->common->params.h+2) + 3*(state->common->params.w * state->common->params.h), char); sprintf(ret,"G: %d V: %d Z: %d\n\n",state->common->num_ghosts, state->common->num_vampires, state->common->num_zombies); for (h=0;hcommon->params.h+2;h++) { for (w=0;wcommon->params.w+2;w++) { c = state->common->grid[w+h*(state->common->params.w+2)]; xi = state->common->xinfo[w+h*(state->common->params.w+2)]; r = grid2range(w,h,state->common->params.w,state->common->params.h); if (r != -1) { sprintf(buf,"%2d", c); strcat(ret,buf); } else if (c == CELL_MIRROR_L) { sprintf(buf," \\"); strcat(ret,buf); } else if (c == CELL_MIRROR_R) { sprintf(buf," /"); strcat(ret,buf); } else if (xi >= 0) { g = state->guess[xi]; if (g == 1) { sprintf(buf," G"); strcat(ret,buf); } else if (g == 2) { sprintf(buf," V"); strcat(ret,buf); } else if (g == 4) { sprintf(buf," Z"); strcat(ret,buf); } else { sprintf(buf," ."); strcat(ret,buf); } } else { sprintf(buf," "); strcat(ret,buf); } } sprintf(buf,"\n"); strcat(ret,buf); } return ret; } struct game_ui { int hx, hy; /* as for solo.c, highlight pos */ int hshow, hpencil, hcursor; /* show state, type, and ?cursor. */ int ascii; }; static game_ui *new_ui(const game_state *state) { game_ui *ui = snew(game_ui); ui->hx = ui->hy = 0; ui->hpencil = ui->hshow = ui->hcursor = 0; ui->ascii = FALSE; return ui; } static void free_ui(game_ui *ui) { sfree(ui); return; } static char *encode_ui(const game_ui *ui) { return NULL; } static void decode_ui(game_ui *ui, const char *encoding) { return; } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { /* See solo.c; if we were pencil-mode highlighting and * somehow a square has just been properly filled, cancel * pencil mode. */ if (ui->hshow && ui->hpencil && !ui->hcursor) { int g = newstate->guess[newstate->common->xinfo[ui->hx + ui->hy*(newstate->common->params.w+2)]]; if (g == 1 || g == 2 || g == 4) ui->hshow = 0; } } struct game_drawstate { int tilesize, started, solved; int w, h; int *monsters; unsigned char *pencils; unsigned char count_errors[3]; unsigned char *cell_errors; unsigned char *hint_errors; unsigned char *hints_done; int hx, hy, hshow, hpencil; /* as for game_ui. */ int hflash; int ascii; }; static int is_clue(const game_state *state, int x, int y) { int h = state->common->params.h, w = state->common->params.w; if (((x == 0 || x == w + 1) && y > 0 && y <= h) || ((y == 0 || y == h + 1) && x > 0 && x <= w)) return TRUE; return FALSE; } static int clue_index(const game_state *state, int x, int y) { int h = state->common->params.h, w = state->common->params.w; if (y == 0) return x - 1; else if (x == w + 1) return w + y - 1; else if (y == h + 1) return 2 * w + h - x; else if (x == 0) return 2 * (w + h) - y; return -1; } #define TILESIZE (ds->tilesize) #define BORDER (TILESIZE/4) static char *interpret_move(const game_state *state, game_ui *ui, const game_drawstate *ds, int x, int y, int button) { int gx,gy; int g,xi; char buf[80]; gx = ((x-BORDER-1) / TILESIZE ); gy = ((y-BORDER-2) / TILESIZE ) - 1; if (button == 'a' || button == 'A') { ui->ascii = !ui->ascii; return ""; } if (button == 'm' || button == 'M') { return dupstr("M"); } if (ui->hshow == 1 && ui->hpencil == 0) { xi = state->common->xinfo[ui->hx + ui->hy*(state->common->params.w+2)]; if (xi >= 0 && !state->common->fixed[xi]) { if (button == 'g' || button == 'G' || button == '1') { if (!ui->hcursor) ui->hshow = 0; sprintf(buf,"G%d",xi); return dupstr(buf); } if (button == 'v' || button == 'V' || button == '2') { if (!ui->hcursor) ui->hshow = 0; sprintf(buf,"V%d",xi); return dupstr(buf); } if (button == 'z' || button == 'Z' || button == '3') { if (!ui->hcursor) ui->hshow = 0; sprintf(buf,"Z%d",xi); return dupstr(buf); } if (button == 'e' || button == 'E' || button == CURSOR_SELECT2 || button == '0' || button == '\b' ) { if (!ui->hcursor) ui->hshow = 0; sprintf(buf,"E%d",xi); return dupstr(buf); } } } if (IS_CURSOR_MOVE(button)) { if (ui->hx == 0 && ui->hy == 0) { ui->hx = 1; ui->hy = 1; } else switch (button) { case CURSOR_UP: ui->hy -= (ui->hy > 1) ? 1 : 0; break; case CURSOR_DOWN: ui->hy += (ui->hy < ds->h) ? 1 : 0; break; case CURSOR_RIGHT: ui->hx += (ui->hx < ds->w) ? 1 : 0; break; case CURSOR_LEFT: ui->hx -= (ui->hx > 1) ? 1 : 0; break; } ui->hshow = ui->hcursor = 1; return ""; } if (ui->hshow && button == CURSOR_SELECT) { ui->hpencil = 1 - ui->hpencil; ui->hcursor = 1; return ""; } if (ui->hshow == 1 && ui->hpencil == 1) { xi = state->common->xinfo[ui->hx + ui->hy*(state->common->params.w+2)]; if (xi >= 0 && !state->common->fixed[xi]) { if (button == 'g' || button == 'G' || button == '1') { sprintf(buf,"g%d",xi); if (!ui->hcursor) ui->hpencil = ui->hshow = 0; return dupstr(buf); } if (button == 'v' || button == 'V' || button == '2') { sprintf(buf,"v%d",xi); if (!ui->hcursor) ui->hpencil = ui->hshow = 0; return dupstr(buf); } if (button == 'z' || button == 'Z' || button == '3') { sprintf(buf,"z%d",xi); if (!ui->hcursor) ui->hpencil = ui->hshow = 0; return dupstr(buf); } if (button == 'e' || button == 'E' || button == CURSOR_SELECT2 || button == '0' || button == '\b') { sprintf(buf,"E%d",xi); if (!ui->hcursor) ui->hpencil = ui->hshow = 0; return dupstr(buf); } } } if (gx > 0 && gx < ds->w+1 && gy > 0 && gy < ds->h+1) { xi = state->common->xinfo[gx+gy*(state->common->params.w+2)]; if (xi >= 0 && !state->common->fixed[xi]) { g = state->guess[xi]; if (ui->hshow == 0) { if (button == LEFT_BUTTON) { ui->hshow = 1; ui->hpencil = 0; ui->hcursor = 0; ui->hx = gx; ui->hy = gy; return ""; } else if (button == RIGHT_BUTTON && g == 7) { ui->hshow = 1; ui->hpencil = 1; ui->hcursor = 0; ui->hx = gx; ui->hy = gy; return ""; } } else if (ui->hshow == 1) { if (button == LEFT_BUTTON) { if (ui->hpencil == 0) { if (gx == ui->hx && gy == ui->hy) { ui->hshow = 0; ui->hpencil = 0; ui->hcursor = 0; ui->hx = 0; ui->hy = 0; return ""; } else { ui->hshow = 1; ui->hpencil = 0; ui->hcursor = 0; ui->hx = gx; ui->hy = gy; return ""; } } else { ui->hshow = 1; ui->hpencil = 0; ui->hcursor = 0; ui->hx = gx; ui->hy = gy; return ""; } } else if (button == RIGHT_BUTTON) { if (ui->hpencil == 0 && g == 7) { ui->hshow = 1; ui->hpencil = 1; ui->hcursor = 0; ui->hx = gx; ui->hy = gy; return ""; } else { if (gx == ui->hx && gy == ui->hy) { ui->hshow = 0; ui->hpencil = 0; ui->hcursor = 0; ui->hx = 0; ui->hy = 0; return ""; } else if (g == 7) { ui->hshow = 1; ui->hpencil = 1; ui->hcursor = 0; ui->hx = gx; ui->hy = gy; return ""; } } } } } } else if (button == LEFT_BUTTON) { if (is_clue(state, gx, gy)) { sprintf(buf, "D%d,%d", gx, gy); return dupstr(buf); } } return NULL; } int check_numbers_draw(game_state *state, int *guess) { int valid, filled; int i,x,y,xy; int count_ghosts, count_vampires, count_zombies; count_ghosts = count_vampires = count_zombies = 0; for (i=0;icommon->num_total;i++) { if (guess[i] == 1) count_ghosts++; if (guess[i] == 2) count_vampires++; if (guess[i] == 4) count_zombies++; } valid = TRUE; filled = (count_ghosts + count_vampires + count_zombies >= state->common->num_total); if (count_ghosts > state->common->num_ghosts || (filled && count_ghosts != state->common->num_ghosts) ) { valid = FALSE; state->count_errors[0] = TRUE; for (x=1;xcommon->params.w+1;x++) for (y=1;ycommon->params.h+1;y++) { xy = x+y*(state->common->params.w+2); if (state->common->xinfo[xy] >= 0 && guess[state->common->xinfo[xy]] == 1) state->cell_errors[xy] = TRUE; } } if (count_vampires > state->common->num_vampires || (filled && count_vampires != state->common->num_vampires) ) { valid = FALSE; state->count_errors[1] = TRUE; for (x=1;xcommon->params.w+1;x++) for (y=1;ycommon->params.h+1;y++) { xy = x+y*(state->common->params.w+2); if (state->common->xinfo[xy] >= 0 && guess[state->common->xinfo[xy]] == 2) state->cell_errors[xy] = TRUE; } } if (count_zombies > state->common->num_zombies || (filled && count_zombies != state->common->num_zombies) ) { valid = FALSE; state->count_errors[2] = TRUE; for (x=1;xcommon->params.w+1;x++) for (y=1;ycommon->params.h+1;y++) { xy = x+y*(state->common->params.w+2); if (state->common->xinfo[xy] >= 0 && guess[state->common->xinfo[xy]] == 4) state->cell_errors[xy] = TRUE; } } return valid; } int check_path_solution(game_state *state, int p) { int i; int mirror; int count; int correct; int unfilled; count = 0; mirror = FALSE; correct = TRUE; unfilled = 0; for (i=0;icommon->paths[p].length;i++) { if (state->common->paths[p].p[i] == -1) mirror = TRUE; else { if (state->guess[state->common->paths[p].p[i]] == 1 && mirror) count++; else if (state->guess[state->common->paths[p].p[i]] == 2 && !mirror) count++; else if (state->guess[state->common->paths[p].p[i]] == 4) count++; else if (state->guess[state->common->paths[p].p[i]] == 7) unfilled++; } } if (count > state->common->paths[p].sightings_start || count + unfilled < state->common->paths[p].sightings_start) { correct = FALSE; state->hint_errors[state->common->paths[p].grid_start] = TRUE; } count = 0; mirror = FALSE; unfilled = 0; for (i=state->common->paths[p].length-1;i>=0;i--) { if (state->common->paths[p].p[i] == -1) mirror = TRUE; else { if (state->guess[state->common->paths[p].p[i]] == 1 && mirror) count++; else if (state->guess[state->common->paths[p].p[i]] == 2 && !mirror) count++; else if (state->guess[state->common->paths[p].p[i]] == 4) count++; else if (state->guess[state->common->paths[p].p[i]] == 7) unfilled++; } } if (count > state->common->paths[p].sightings_end || count + unfilled < state->common->paths[p].sightings_end) { correct = FALSE; state->hint_errors[state->common->paths[p].grid_end] = TRUE; } if (!correct) { for (i=0;icommon->paths[p].length;i++) state->cell_errors[state->common->paths[p].xy[i]] = TRUE; } return correct; } static game_state *execute_move(const game_state *state, const char *move) { int x,y,n,p,i; char c; int correct; int solver; game_state *ret = dup_game(state); solver = FALSE; while (*move) { c = *move; if (c == 'S') { move++; solver = TRUE; } if (c == 'G' || c == 'V' || c == 'Z' || c == 'E' || c == 'g' || c == 'v' || c == 'z') { move++; sscanf(move, "%d%n", &x, &n); if (c == 'G') ret->guess[x] = 1; if (c == 'V') ret->guess[x] = 2; if (c == 'Z') ret->guess[x] = 4; if (c == 'E') { ret->guess[x] = 7; ret->pencils[x] = 0; } if (c == 'g') ret->pencils[x] ^= 1; if (c == 'v') ret->pencils[x] ^= 2; if (c == 'z') ret->pencils[x] ^= 4; move += n; } if (c == 'D' && sscanf(move + 1, "%d,%d%n", &x, &y, &n) == 2 && is_clue(ret, x, y)) { ret->hints_done[clue_index(ret, x, y)] ^= 1; move += n + 1; } if (c == 'M') { /* * Fill in absolutely all pencil marks in unfilled * squares, for those who like to play by the rigorous * approach of starting off in that state and eliminating * things. */ for (i = 0; i < ret->common->wh; i++) if (ret->guess[i] == 7) ret->pencils[i] = 7; move++; } if (*move == ';') move++; } correct = TRUE; for (i=0;icommon->wh;i++) ret->cell_errors[i] = FALSE; for (i=0;i<2*ret->common->num_paths;i++) ret->hint_errors[i] = FALSE; for (i=0;i<3;i++) ret->count_errors[i] = FALSE; if (!check_numbers_draw(ret,ret->guess)) correct = FALSE; for (p=0;pcommon->num_paths;p++) if (!check_path_solution(ret,p)) correct = FALSE; for (i=0;icommon->num_total;i++) if (!(ret->guess[i] == 1 || ret->guess[i] == 2 || ret->guess[i] == 4)) correct = FALSE; if (correct && !solver) ret->solved = TRUE; if (solver) ret->cheated = TRUE; return ret; } /* ---------------------------------------------------------------------- * Drawing routines. */ #define PREFERRED_TILE_SIZE 64 static void game_compute_size(const game_params *params, int tilesize, int *x, int *y) { /* Ick: fake up `ds->tilesize' for macro expansion purposes */ struct { int tilesize; } ads, *ds = &ads; ads.tilesize = tilesize; *x = 2*BORDER+(params->w+2)*TILESIZE; *y = 2*BORDER+(params->h+3)*TILESIZE; return; } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { ds->tilesize = tilesize; return; } #define COLOUR(ret, i, r, g, b) ((ret[3*(i)+0] = (r)), (ret[3*(i)+1] = (g)), (ret[3*(i)+2] = (b))) static float *game_colours(frontend *fe, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float); frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]); ret[COL_GRID * 3 + 0] = 0.0F; ret[COL_GRID * 3 + 1] = 0.0F; ret[COL_GRID * 3 + 2] = 0.0F; ret[COL_TEXT * 3 + 0] = 0.0F; ret[COL_TEXT * 3 + 1] = 0.0F; ret[COL_TEXT * 3 + 2] = 0.0F; ret[COL_ERROR * 3 + 0] = 1.0F; ret[COL_ERROR * 3 + 1] = 0.0F; ret[COL_ERROR * 3 + 2] = 0.0F; ret[COL_HIGHLIGHT * 3 + 0] = 0.78F * ret[COL_BACKGROUND * 3 + 0]; ret[COL_HIGHLIGHT * 3 + 1] = 0.78F * ret[COL_BACKGROUND * 3 + 1]; ret[COL_HIGHLIGHT * 3 + 2] = 0.78F * ret[COL_BACKGROUND * 3 + 2]; ret[COL_FLASH * 3 + 0] = 1.0F; ret[COL_FLASH * 3 + 1] = 1.0F; ret[COL_FLASH * 3 + 2] = 1.0F; ret[COL_GHOST * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] * 0.5F; ret[COL_GHOST * 3 + 1] = ret[COL_BACKGROUND * 3 + 0]; ret[COL_GHOST * 3 + 2] = ret[COL_BACKGROUND * 3 + 0]; ret[COL_ZOMBIE * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] * 0.5F; ret[COL_ZOMBIE * 3 + 1] = ret[COL_BACKGROUND * 3 + 0]; ret[COL_ZOMBIE * 3 + 2] = ret[COL_BACKGROUND * 3 + 0] * 0.5F; ret[COL_VAMPIRE * 3 + 0] = ret[COL_BACKGROUND * 3 + 0]; ret[COL_VAMPIRE * 3 + 1] = ret[COL_BACKGROUND * 3 + 0] * 0.9F; ret[COL_VAMPIRE * 3 + 2] = ret[COL_BACKGROUND * 3 + 0] * 0.9F; ret[COL_DONE * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] / 1.5F; ret[COL_DONE * 3 + 1] = ret[COL_BACKGROUND * 3 + 1] / 1.5F; ret[COL_DONE * 3 + 2] = ret[COL_BACKGROUND * 3 + 2] / 1.5F; *ncolours = NCOLOURS; return ret; } static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { int i; struct game_drawstate *ds = snew(struct game_drawstate); ds->tilesize = 0; ds->started = ds->solved = FALSE; ds->w = state->common->params.w; ds->h = state->common->params.h; ds->ascii = FALSE; ds->count_errors[0] = FALSE; ds->count_errors[1] = FALSE; ds->count_errors[2] = FALSE; ds->monsters = snewn(state->common->num_total,int); for (i=0;i<(state->common->num_total);i++) ds->monsters[i] = 7; ds->pencils = snewn(state->common->num_total,unsigned char); for (i=0;icommon->num_total;i++) ds->pencils[i] = 0; ds->cell_errors = snewn(state->common->wh,unsigned char); for (i=0;icommon->wh;i++) ds->cell_errors[i] = FALSE; ds->hint_errors = snewn(2*state->common->num_paths,unsigned char); for (i=0;i<2*state->common->num_paths;i++) ds->hint_errors[i] = FALSE; ds->hints_done = snewn(2 * state->common->num_paths, unsigned char); memset(ds->hints_done, 0, 2 * state->common->num_paths * sizeof(unsigned char)); ds->hshow = ds->hpencil = ds->hflash = 0; ds->hx = ds->hy = 0; return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { sfree(ds->hints_done); sfree(ds->hint_errors); sfree(ds->cell_errors); sfree(ds->pencils); sfree(ds->monsters); sfree(ds); return; } static void draw_cell_background(drawing *dr, game_drawstate *ds, const game_state *state, const game_ui *ui, int x, int y) { int hon; int dx,dy; dx = BORDER+(x* ds->tilesize)+(TILESIZE/2); dy = BORDER+(y* ds->tilesize)+(TILESIZE/2)+TILESIZE; hon = (ui->hshow && x == ui->hx && y == ui->hy); draw_rect(dr,dx-(TILESIZE/2)+1,dy-(TILESIZE/2)+1,TILESIZE-1,TILESIZE-1,(hon && !ui->hpencil) ? COL_HIGHLIGHT : COL_BACKGROUND); if (hon && ui->hpencil) { int coords[6]; coords[0] = dx-(TILESIZE/2)+1; coords[1] = dy-(TILESIZE/2)+1; coords[2] = coords[0] + TILESIZE/2; coords[3] = coords[1]; coords[4] = coords[0]; coords[5] = coords[1] + TILESIZE/2; draw_polygon(dr, coords, 3, COL_HIGHLIGHT, COL_HIGHLIGHT); } draw_update(dr,dx-(TILESIZE/2)+1,dy-(TILESIZE/2)+1,TILESIZE-1,TILESIZE-1); return; } static void draw_circle_or_point(drawing *dr, int cx, int cy, int radius, int colour) { if (radius > 0) draw_circle(dr, cx, cy, radius, colour, colour); else draw_rect(dr, cx, cy, 1, 1, colour); } static void draw_monster(drawing *dr, game_drawstate *ds, int x, int y, int tilesize, int hflash, int monster) { int black = (hflash ? COL_FLASH : COL_TEXT); if (monster == 1) { /* ghost */ int poly[80], i, j; clip(dr,x-(tilesize/2)+2,y-(tilesize/2)+2,tilesize-3,tilesize/2+1); draw_circle(dr,x,y,2*tilesize/5, COL_GHOST,black); unclip(dr); i = 0; poly[i++] = x - 2*tilesize/5; poly[i++] = y-2; poly[i++] = x - 2*tilesize/5; poly[i++] = y + 2*tilesize/5; for (j = 0; j < 3; j++) { int total = (2*tilesize/5) * 2; int before = total * j / 3; int after = total * (j+1) / 3; int mid = (before + after) / 2; poly[i++] = x - 2*tilesize/5 + mid; poly[i++] = y + 2*tilesize/5 - (total / 6); poly[i++] = x - 2*tilesize/5 + after; poly[i++] = y + 2*tilesize/5; } poly[i++] = x + 2*tilesize/5; poly[i++] = y-2; clip(dr,x-(tilesize/2)+2,y,tilesize-3,tilesize-(tilesize/2)-1); draw_polygon(dr, poly, i/2, COL_GHOST, black); unclip(dr); draw_circle(dr,x-tilesize/6,y-tilesize/12,tilesize/10, COL_BACKGROUND,black); draw_circle(dr,x+tilesize/6,y-tilesize/12,tilesize/10, COL_BACKGROUND,black); draw_circle_or_point(dr,x-tilesize/6+1+tilesize/48,y-tilesize/12, tilesize/48,black); draw_circle_or_point(dr,x+tilesize/6+1+tilesize/48,y-tilesize/12, tilesize/48,black); } else if (monster == 2) { /* vampire */ int poly[80], i; clip(dr,x-(tilesize/2)+2,y-(tilesize/2)+2,tilesize-3,tilesize/2); draw_circle(dr,x,y,2*tilesize/5,black,black); unclip(dr); clip(dr,x-(tilesize/2)+2,y-(tilesize/2)+2,tilesize/2+1,tilesize/2); draw_circle(dr,x-tilesize/7,y,2*tilesize/5-tilesize/7, COL_VAMPIRE,black); unclip(dr); clip(dr,x,y-(tilesize/2)+2,tilesize/2+1,tilesize/2); draw_circle(dr,x+tilesize/7,y,2*tilesize/5-tilesize/7, COL_VAMPIRE,black); unclip(dr); clip(dr,x-(tilesize/2)+2,y,tilesize-3,tilesize/2); draw_circle(dr,x,y,2*tilesize/5, COL_VAMPIRE,black); unclip(dr); draw_circle(dr, x-tilesize/7, y-tilesize/16, tilesize/16, COL_BACKGROUND, black); draw_circle(dr, x+tilesize/7, y-tilesize/16, tilesize/16, COL_BACKGROUND, black); draw_circle_or_point(dr, x-tilesize/7, y-tilesize/16, tilesize/48, black); draw_circle_or_point(dr, x+tilesize/7, y-tilesize/16, tilesize/48, black); clip(dr, x-(tilesize/2)+2, y+tilesize/8, tilesize-3, tilesize/4); i = 0; poly[i++] = x-3*tilesize/16; poly[i++] = y+1*tilesize/8; poly[i++] = x-2*tilesize/16; poly[i++] = y+7*tilesize/24; poly[i++] = x-1*tilesize/16; poly[i++] = y+1*tilesize/8; draw_polygon(dr, poly, i/2, COL_BACKGROUND, black); i = 0; poly[i++] = x+3*tilesize/16; poly[i++] = y+1*tilesize/8; poly[i++] = x+2*tilesize/16; poly[i++] = y+7*tilesize/24; poly[i++] = x+1*tilesize/16; poly[i++] = y+1*tilesize/8; draw_polygon(dr, poly, i/2, COL_BACKGROUND, black); draw_circle(dr, x, y-tilesize/5, 2*tilesize/5, COL_VAMPIRE, black); unclip(dr); } else if (monster == 4) { /* zombie */ draw_circle(dr,x,y,2*tilesize/5, COL_ZOMBIE,black); draw_line(dr, x-tilesize/7-tilesize/16, y-tilesize/12-tilesize/16, x-tilesize/7+tilesize/16, y-tilesize/12+tilesize/16, black); draw_line(dr, x-tilesize/7+tilesize/16, y-tilesize/12-tilesize/16, x-tilesize/7-tilesize/16, y-tilesize/12+tilesize/16, black); draw_line(dr, x+tilesize/7-tilesize/16, y-tilesize/12-tilesize/16, x+tilesize/7+tilesize/16, y-tilesize/12+tilesize/16, black); draw_line(dr, x+tilesize/7+tilesize/16, y-tilesize/12-tilesize/16, x+tilesize/7-tilesize/16, y-tilesize/12+tilesize/16, black); clip(dr, x-tilesize/5, y+tilesize/6, 2*tilesize/5+1, tilesize/2); draw_circle(dr, x-tilesize/15, y+tilesize/6, tilesize/12, COL_BACKGROUND, black); unclip(dr); draw_line(dr, x-tilesize/5, y+tilesize/6, x+tilesize/5, y+tilesize/6, black); } draw_update(dr,x-(tilesize/2)+2,y-(tilesize/2)+2,tilesize-3,tilesize-3); } static void draw_monster_count(drawing *dr, game_drawstate *ds, const game_state *state, int c, int hflash) { int dx,dy; char buf[8]; char bufm[8]; dy = TILESIZE/4; dx = BORDER+(ds->w+2)*TILESIZE/2+TILESIZE/4; switch (c) { case 0: sprintf(buf,"%d",state->common->num_ghosts); sprintf(bufm,"G"); dx -= 3*TILESIZE/2; break; case 1: sprintf(buf,"%d",state->common->num_vampires); sprintf(bufm,"V"); break; case 2: sprintf(buf,"%d",state->common->num_zombies); sprintf(bufm,"Z"); dx += 3*TILESIZE/2; break; } draw_rect(dr, dx-2*TILESIZE/3, dy, 3*TILESIZE/2, TILESIZE, COL_BACKGROUND); if (!ds->ascii) { draw_monster(dr, ds, dx-TILESIZE/3, dy+TILESIZE/2, 2*TILESIZE/3, hflash, 1<count_errors[c] ? COL_ERROR : hflash ? COL_FLASH : COL_TEXT), buf); draw_update(dr, dx-2*TILESIZE/3, dy, 3*TILESIZE/2, TILESIZE); return; } static void draw_path_hint(drawing *dr, game_drawstate *ds, const struct game_params *params, int hint_index, int hflash, int hint) { int x, y, color, dx, dy, text_dx, text_dy, text_size; char buf[4]; if (ds->hint_errors[hint_index]) color = COL_ERROR; else if (hflash) color = COL_FLASH; else if (ds->hints_done[hint_index]) color = COL_DONE; else color = COL_TEXT; range2grid(hint_index, params->w, params->h, &x, &y); /* Upper-left corner of the "tile" */ dx = BORDER + x * TILESIZE; dy = BORDER + y * TILESIZE + TILESIZE; /* Center of the "tile" */ text_dx = dx + TILESIZE / 2; text_dy = dy + TILESIZE / 2; /* Avoid wiping out the borders of the puzzle */ dx += 2; dy += 2; text_size = TILESIZE - 3; sprintf(buf,"%d", hint); draw_rect(dr, dx, dy, text_size, text_size, COL_BACKGROUND); draw_text(dr, text_dx, text_dy, FONT_FIXED, TILESIZE / 2, ALIGN_HCENTRE | ALIGN_VCENTRE, color, buf); draw_update(dr, dx, dy, text_size, text_size); return; } static void draw_mirror(drawing *dr, game_drawstate *ds, const game_state *state, int x, int y, int hflash, int mirror) { int dx,dy,mx1,my1,mx2,my2; dx = BORDER+(x* ds->tilesize)+(TILESIZE/2); dy = BORDER+(y* ds->tilesize)+(TILESIZE/2)+TILESIZE; if (mirror == CELL_MIRROR_L) { mx1 = dx-(TILESIZE/4); my1 = dy-(TILESIZE/4); mx2 = dx+(TILESIZE/4); my2 = dy+(TILESIZE/4); } else { mx1 = dx-(TILESIZE/4); my1 = dy+(TILESIZE/4); mx2 = dx+(TILESIZE/4); my2 = dy-(TILESIZE/4); } draw_thick_line(dr,(float)(TILESIZE/16),mx1,my1,mx2,my2, hflash ? COL_FLASH : COL_TEXT); draw_update(dr,dx-(TILESIZE/2)+1,dy-(TILESIZE/2)+1,TILESIZE-1,TILESIZE-1); return; } static void draw_big_monster(drawing *dr, game_drawstate *ds, const game_state *state, int x, int y, int hflash, int monster) { int dx,dy; char buf[10]; dx = BORDER+(x* ds->tilesize)+(TILESIZE/2); dy = BORDER+(y* ds->tilesize)+(TILESIZE/2)+TILESIZE; if (ds->ascii) { if (monster == 1) sprintf(buf,"G"); else if (monster == 2) sprintf(buf,"V"); else if (monster == 4) sprintf(buf,"Z"); else sprintf(buf," "); draw_text(dr,dx,dy,FONT_FIXED,TILESIZE/2,ALIGN_HCENTRE|ALIGN_VCENTRE, hflash ? COL_FLASH : COL_TEXT,buf); draw_update(dr,dx-(TILESIZE/2)+2,dy-(TILESIZE/2)+2,TILESIZE-3, TILESIZE-3); } else { draw_monster(dr, ds, dx, dy, 3*TILESIZE/4, hflash, monster); } return; } static void draw_pencils(drawing *dr, game_drawstate *ds, const game_state *state, int x, int y, int pencil) { int dx, dy; int monsters[4]; int i, j, px, py; char buf[10]; dx = BORDER+(x* ds->tilesize)+(TILESIZE/4); dy = BORDER+(y* ds->tilesize)+(TILESIZE/4)+TILESIZE; for (i = 0, j = 1; j < 8; j *= 2) if (pencil & j) monsters[i++] = j; while (i < 4) monsters[i++] = 0; for (py = 0; py < 2; py++) for (px = 0; px < 2; px++) if (monsters[py*2+px]) { if (!ds->ascii) { draw_monster(dr, ds, dx + TILESIZE/2 * px, dy + TILESIZE/2 * py, TILESIZE/2, 0, monsters[py*2+px]); } else { switch (monsters[py*2+px]) { case 1: sprintf(buf,"G"); break; case 2: sprintf(buf,"V"); break; case 4: sprintf(buf,"Z"); break; } draw_text(dr,dx + TILESIZE/2 * px,dy + TILESIZE/2 * py, FONT_FIXED,TILESIZE/4,ALIGN_HCENTRE|ALIGN_VCENTRE, COL_TEXT,buf); } } draw_update(dr,dx-(TILESIZE/4)+2,dy-(TILESIZE/4)+2, (TILESIZE/2)-3,(TILESIZE/2)-3); return; } #define FLASH_TIME 0.7F static int is_hint_stale(const game_drawstate *ds, int hflash, const game_state *state, int index) { int ret = FALSE; if (!ds->started) ret = TRUE; if (ds->hflash != hflash) ret = TRUE; if (ds->hint_errors[index] != state->hint_errors[index]) { ds->hint_errors[index] = state->hint_errors[index]; ret = TRUE; } if (ds->hints_done[index] != state->hints_done[index]) { ds->hints_done[index] = state->hints_done[index]; ret = TRUE; } return ret; } static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float animtime, float flashtime) { int i,j,x,y,xy; int stale, xi, c, hflash, hchanged, changed_ascii; hflash = (int)(flashtime * 5 / FLASH_TIME) % 2; /* Draw static grid components at startup */ if (!ds->started) { draw_rect(dr, 0, 0, 2*BORDER+(ds->w+2)*TILESIZE, 2*BORDER+(ds->h+3)*TILESIZE, COL_BACKGROUND); draw_rect(dr, BORDER+TILESIZE-1, BORDER+2*TILESIZE-1, (ds->w)*TILESIZE +3, (ds->h)*TILESIZE +3, COL_GRID); for (i=0;iw;i++) for (j=0;jh;j++) draw_rect(dr, BORDER+(ds->tilesize*(i+1))+1, BORDER+(ds->tilesize*(j+2))+1, ds->tilesize-1, ds->tilesize-1, COL_BACKGROUND); draw_update(dr, 0, 0, 2*BORDER+(ds->w+2)*TILESIZE, 2*BORDER+(ds->h+3)*TILESIZE); } hchanged = FALSE; if (ds->hx != ui->hx || ds->hy != ui->hy || ds->hshow != ui->hshow || ds->hpencil != ui->hpencil) hchanged = TRUE; if (ds->ascii != ui->ascii) { ds->ascii = ui->ascii; changed_ascii = TRUE; } else changed_ascii = FALSE; /* Draw monster count hints */ for (i=0;i<3;i++) { stale = FALSE; if (!ds->started) stale = TRUE; if (ds->hflash != hflash) stale = TRUE; if (changed_ascii) stale = TRUE; if (ds->count_errors[i] != state->count_errors[i]) { stale = TRUE; ds->count_errors[i] = state->count_errors[i]; } if (stale) { draw_monster_count(dr, ds, state, i, hflash); } } /* Draw path count hints */ for (i=0;icommon->num_paths;i++) { struct path *path = &state->common->paths[i]; if (is_hint_stale(ds, hflash, state, path->grid_start)) { draw_path_hint(dr, ds, &state->common->params, path->grid_start, hflash, path->sightings_start); } if (is_hint_stale(ds, hflash, state, path->grid_end)) { draw_path_hint(dr, ds, &state->common->params, path->grid_end, hflash, path->sightings_end); } } /* Draw puzzle grid contents */ for (x = 1; x < ds->w+1; x++) for (y = 1; y < ds->h+1; y++) { stale = FALSE; xy = x+y*(state->common->params.w+2); xi = state->common->xinfo[xy]; c = state->common->grid[xy]; if (!ds->started) stale = TRUE; if (ds->hflash != hflash) stale = TRUE; if (changed_ascii) stale = TRUE; if (hchanged) { if ((x == ui->hx && y == ui->hy) || (x == ds->hx && y == ds->hy)) stale = TRUE; } if (xi >= 0 && (state->guess[xi] != ds->monsters[xi]) ) { stale = TRUE; ds->monsters[xi] = state->guess[xi]; } if (xi >= 0 && (state->pencils[xi] != ds->pencils[xi]) ) { stale = TRUE; ds->pencils[xi] = state->pencils[xi]; } if (state->cell_errors[xy] != ds->cell_errors[xy]) { stale = TRUE; ds->cell_errors[xy] = state->cell_errors[xy]; } if (stale) { draw_cell_background(dr, ds, state, ui, x, y); if (xi < 0) draw_mirror(dr, ds, state, x, y, hflash, c); else if (state->guess[xi] == 1 || state->guess[xi] == 2 || state->guess[xi] == 4) draw_big_monster(dr, ds, state, x, y, hflash, state->guess[xi]); else draw_pencils(dr, ds, state, x, y, state->pencils[xi]); } } ds->hx = ui->hx; ds->hy = ui->hy; ds->hshow = ui->hshow; ds->hpencil = ui->hpencil; ds->hflash = hflash; ds->started = TRUE; return; } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return 0.0F; } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return (!oldstate->solved && newstate->solved && !oldstate->cheated && !newstate->cheated) ? FLASH_TIME : 0.0F; } static int game_status(const game_state *state) { return state->solved; } static int game_timing_state(const game_state *state, game_ui *ui) { return TRUE; } static void game_print_size(const game_params *params, float *x, float *y) { } static void game_print(drawing *dr, const game_state *state, int tilesize) { } #ifdef COMBINED #define thegame undead #endif const struct game thegame = { "Undead", "games.undead", "undead", default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, TRUE, solve_game, TRUE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, PREFERRED_TILE_SIZE, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, FALSE, FALSE, game_print_size, game_print, FALSE, /* wants_statusbar */ FALSE, game_timing_state, 0, /* flags */ }; puzzles-20170606.272beef/twiddle.c0000644000175000017500000010715713115373615015504 0ustar simonsimon/* * twiddle.c: Puzzle involving rearranging a grid of squares by * rotating subsquares. Adapted and generalised from a * door-unlocking puzzle in Metroid Prime 2 (the one in the Main * Gyro Chamber). */ #include #include #include #include #include #include #include "puzzles.h" #define PREFERRED_TILE_SIZE 48 #define TILE_SIZE (ds->tilesize) #define BORDER (TILE_SIZE / 2) #define HIGHLIGHT_WIDTH (TILE_SIZE / 20) #define COORD(x) ( (x) * TILE_SIZE + BORDER ) #define FROMCOORD(x) ( ((x) - BORDER + TILE_SIZE) / TILE_SIZE - 1 ) #define ANIM_PER_BLKSIZE_UNIT 0.13F #define FLASH_FRAME 0.13F enum { COL_BACKGROUND, COL_TEXT, COL_HIGHLIGHT, COL_HIGHLIGHT_GENTLE, COL_LOWLIGHT, COL_LOWLIGHT_GENTLE, COL_HIGHCURSOR, COL_LOWCURSOR, NCOLOURS }; struct game_params { int w, h, n; int rowsonly; int orientable; int movetarget; }; struct game_state { int w, h, n; int orientable; int *grid; int completed; int used_solve; /* used to suppress completion flash */ int movecount, movetarget; int lastx, lasty, lastr; /* coordinates of last rotation */ }; static game_params *default_params(void) { game_params *ret = snew(game_params); ret->w = ret->h = 3; ret->n = 2; ret->rowsonly = ret->orientable = FALSE; ret->movetarget = 0; return ret; } static void free_params(game_params *params) { sfree(params); } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } static int game_fetch_preset(int i, char **name, game_params **params) { static struct { char *title; game_params params; } presets[] = { { "3x3 rows only", { 3, 3, 2, TRUE, FALSE } }, { "3x3 normal", { 3, 3, 2, FALSE, FALSE } }, { "3x3 orientable", { 3, 3, 2, FALSE, TRUE } }, { "4x4 normal", { 4, 4, 2, FALSE } }, { "4x4 orientable", { 4, 4, 2, FALSE, TRUE } }, { "4x4, rotating 3x3 blocks", { 4, 4, 3, FALSE } }, { "5x5, rotating 3x3 blocks", { 5, 5, 3, FALSE } }, { "6x6, rotating 4x4 blocks", { 6, 6, 4, FALSE } }, }; if (i < 0 || i >= lenof(presets)) return FALSE; *name = dupstr(presets[i].title); *params = dup_params(&presets[i].params); return TRUE; } static void decode_params(game_params *ret, char const *string) { ret->w = ret->h = atoi(string); ret->n = 2; ret->rowsonly = ret->orientable = FALSE; ret->movetarget = 0; while (*string && isdigit((unsigned char)*string)) string++; if (*string == 'x') { string++; ret->h = atoi(string); while (*string && isdigit((unsigned char)*string)) string++; } if (*string == 'n') { string++; ret->n = atoi(string); while (*string && isdigit((unsigned char)*string)) string++; } while (*string) { if (*string == 'r') { ret->rowsonly = TRUE; } else if (*string == 'o') { ret->orientable = TRUE; } else if (*string == 'm') { string++; ret->movetarget = atoi(string); while (string[1] && isdigit((unsigned char)string[1])) string++; } string++; } } static char *encode_params(const game_params *params, int full) { char buf[256]; sprintf(buf, "%dx%dn%d%s%s", params->w, params->h, params->n, params->rowsonly ? "r" : "", params->orientable ? "o" : ""); /* Shuffle limit is part of the limited parameters, because we have to * supply the target move count. */ if (params->movetarget) sprintf(buf + strlen(buf), "m%d", params->movetarget); return dupstr(buf); } static config_item *game_configure(const game_params *params) { config_item *ret; char buf[80]; ret = snewn(7, config_item); ret[0].name = "Width"; ret[0].type = C_STRING; sprintf(buf, "%d", params->w); ret[0].sval = dupstr(buf); ret[0].ival = 0; ret[1].name = "Height"; ret[1].type = C_STRING; sprintf(buf, "%d", params->h); ret[1].sval = dupstr(buf); ret[1].ival = 0; ret[2].name = "Rotating block size"; ret[2].type = C_STRING; sprintf(buf, "%d", params->n); ret[2].sval = dupstr(buf); ret[2].ival = 0; ret[3].name = "One number per row"; ret[3].type = C_BOOLEAN; ret[3].sval = NULL; ret[3].ival = params->rowsonly; ret[4].name = "Orientation matters"; ret[4].type = C_BOOLEAN; ret[4].sval = NULL; ret[4].ival = params->orientable; ret[5].name = "Number of shuffling moves"; ret[5].type = C_STRING; sprintf(buf, "%d", params->movetarget); ret[5].sval = dupstr(buf); ret[5].ival = 0; ret[6].name = NULL; ret[6].type = C_END; ret[6].sval = NULL; ret[6].ival = 0; return ret; } static game_params *custom_params(const config_item *cfg) { game_params *ret = snew(game_params); ret->w = atoi(cfg[0].sval); ret->h = atoi(cfg[1].sval); ret->n = atoi(cfg[2].sval); ret->rowsonly = cfg[3].ival; ret->orientable = cfg[4].ival; ret->movetarget = atoi(cfg[5].sval); return ret; } static char *validate_params(const game_params *params, int full) { if (params->n < 2) return "Rotating block size must be at least two"; if (params->w < params->n) return "Width must be at least the rotating block size"; if (params->h < params->n) return "Height must be at least the rotating block size"; return NULL; } /* * This function actually performs a rotation on a grid. The `x' * and `y' coordinates passed in are the coordinates of the _top * left corner_ of the rotated region. (Using the centre would have * involved half-integers and been annoyingly fiddly. Clicking in * the centre is good for a user interface, but too inconvenient to * use internally.) */ static void do_rotate(int *grid, int w, int h, int n, int orientable, int x, int y, int dir) { int i, j; assert(x >= 0 && x+n <= w); assert(y >= 0 && y+n <= h); dir &= 3; if (dir == 0) return; /* nothing to do */ grid += y*w+x; /* translate region to top corner */ /* * If we were leaving the result of the rotation in a separate * grid, the simple thing to do would be to loop over each * square within the rotated region and assign it from its * source square. However, to do it in place without taking * O(n^2) memory, we need to be marginally more clever. What * I'm going to do is loop over about one _quarter_ of the * rotated region and permute each element within that quarter * with its rotational coset. * * The size of the region I need to loop over is (n+1)/2 by * n/2, which is an obvious exact quarter for even n and is a * rectangle for odd n. (For odd n, this technique leaves out * one element of the square, which is of course the central * one that never moves anyway.) */ for (i = 0; i < (n+1)/2; i++) { for (j = 0; j < n/2; j++) { int k; int g[4]; int p[4]; p[0] = j*w+i; p[1] = i*w+(n-j-1); p[2] = (n-j-1)*w+(n-i-1); p[3] = (n-i-1)*w+j; for (k = 0; k < 4; k++) g[k] = grid[p[k]]; for (k = 0; k < 4; k++) { int v = g[(k+dir) & 3]; if (orientable) v ^= ((v+dir) ^ v) & 3; /* alter orientation */ grid[p[k]] = v; } } } /* * Don't forget the orientation on the centre square, if n is * odd. */ if (orientable && (n & 1)) { int v = grid[n/2*(w+1)]; v ^= ((v+dir) ^ v) & 3; /* alter orientation */ grid[n/2*(w+1)] = v; } } static int grid_complete(int *grid, int wh, int orientable) { int ok = TRUE; int i; for (i = 1; i < wh; i++) if (grid[i] < grid[i-1]) ok = FALSE; if (orientable) { for (i = 0; i < wh; i++) if (grid[i] & 3) ok = FALSE; } return ok; } static char *new_game_desc(const game_params *params, random_state *rs, char **aux, int interactive) { int *grid; int w = params->w, h = params->h, n = params->n, wh = w*h; int i; char *ret; int retlen; int total_moves; /* * Set up a solved grid. */ grid = snewn(wh, int); for (i = 0; i < wh; i++) grid[i] = ((params->rowsonly ? i/w : i) + 1) * 4; /* * Shuffle it. This game is complex enough that I don't feel up * to analysing its full symmetry properties (particularly at * n=4 and above!), so I'm going to do it the pedestrian way * and simply shuffle the grid by making a long sequence of * randomly chosen moves. */ total_moves = params->movetarget; if (!total_moves) /* Add a random move to avoid parity issues. */ total_moves = w*h*n*n*2 + random_upto(rs, 2); do { int *prevmoves; int rw, rh; /* w/h of rotation centre space */ rw = w - n + 1; rh = h - n + 1; prevmoves = snewn(rw * rh, int); for (i = 0; i < rw * rh; i++) prevmoves[i] = 0; for (i = 0; i < total_moves; i++) { int x, y, r, oldtotal, newtotal, dx, dy; do { x = random_upto(rs, w - n + 1); y = random_upto(rs, h - n + 1); r = 2 * random_upto(rs, 2) - 1; /* * See if any previous rotations has happened at * this point which nothing has overlapped since. * If so, ensure we haven't either undone a * previous move or repeated one so many times that * it turns into fewer moves in the inverse * direction (i.e. three identical rotations). */ oldtotal = prevmoves[y*rw+x]; newtotal = oldtotal + r; /* * Special case here for w==h==n, in which case * there is actually no way to _avoid_ all moves * repeating or undoing previous ones. */ } while ((w != n || h != n) && (abs(newtotal) < abs(oldtotal) || abs(newtotal) > 2)); do_rotate(grid, w, h, n, params->orientable, x, y, r); /* * Log the rotation we've just performed at this point, * for inversion detection in the next move. * * Also zero a section of the prevmoves array, because * any rotation area which _overlaps_ this one is now * entirely safe to perform further moves in. * * Two rotation areas overlap if their top left * coordinates differ by strictly less than n in both * directions */ prevmoves[y*rw+x] += r; for (dy = -n+1; dy <= n-1; dy++) { if (y + dy < 0 || y + dy >= rh) continue; for (dx = -n+1; dx <= n-1; dx++) { if (x + dx < 0 || x + dx >= rw) continue; if (dx == 0 && dy == 0) continue; prevmoves[(y+dy)*rw+(x+dx)] = 0; } } } sfree(prevmoves); } while (grid_complete(grid, wh, params->orientable)); /* * Now construct the game description, by describing the grid * as a simple sequence of integers. They're comma-separated, * unless the puzzle is orientable in which case they're * separated by orientation letters `u', `d', `l' and `r'. */ ret = NULL; retlen = 0; for (i = 0; i < wh; i++) { char buf[80]; int k; k = sprintf(buf, "%d%c", grid[i] / 4, (char)(params->orientable ? "uldr"[grid[i] & 3] : ',')); ret = sresize(ret, retlen + k + 1, char); strcpy(ret + retlen, buf); retlen += k; } if (!params->orientable) ret[retlen-1] = '\0'; /* delete last comma */ sfree(grid); return ret; } static char *validate_desc(const game_params *params, const char *desc) { const char *p; int w = params->w, h = params->h, wh = w*h; int i; p = desc; for (i = 0; i < wh; i++) { if (*p < '0' || *p > '9') return "Not enough numbers in string"; while (*p >= '0' && *p <= '9') p++; if (!params->orientable && i < wh-1) { if (*p != ',') return "Expected comma after number"; } else if (params->orientable && i < wh) { if (*p != 'l' && *p != 'r' && *p != 'u' && *p != 'd') return "Expected orientation letter after number"; } else if (i == wh-1 && *p) { return "Excess junk at end of string"; } if (*p) p++; /* eat comma */ } return NULL; } static game_state *new_game(midend *me, const game_params *params, const char *desc) { game_state *state = snew(game_state); int w = params->w, h = params->h, n = params->n, wh = w*h; int i; const char *p; state->w = w; state->h = h; state->n = n; state->orientable = params->orientable; state->completed = 0; state->used_solve = FALSE; state->movecount = 0; state->movetarget = params->movetarget; state->lastx = state->lasty = state->lastr = -1; state->grid = snewn(wh, int); p = desc; for (i = 0; i < wh; i++) { state->grid[i] = 4 * atoi(p); while (*p >= '0' && *p <= '9') p++; if (*p) { if (params->orientable) { switch (*p) { case 'l': state->grid[i] |= 1; break; case 'd': state->grid[i] |= 2; break; case 'r': state->grid[i] |= 3; break; } } p++; } } return state; } static game_state *dup_game(const game_state *state) { game_state *ret = snew(game_state); ret->w = state->w; ret->h = state->h; ret->n = state->n; ret->orientable = state->orientable; ret->completed = state->completed; ret->movecount = state->movecount; ret->movetarget = state->movetarget; ret->lastx = state->lastx; ret->lasty = state->lasty; ret->lastr = state->lastr; ret->used_solve = state->used_solve; ret->grid = snewn(ret->w * ret->h, int); memcpy(ret->grid, state->grid, ret->w * ret->h * sizeof(int)); return ret; } static void free_game(game_state *state) { sfree(state->grid); sfree(state); } static int compare_int(const void *av, const void *bv) { const int *a = (const int *)av; const int *b = (const int *)bv; if (*a < *b) return -1; else if (*a > *b) return +1; else return 0; } static char *solve_game(const game_state *state, const game_state *currstate, const char *aux, char **error) { return dupstr("S"); } static int game_can_format_as_text_now(const game_params *params) { return TRUE; } static char *game_text_format(const game_state *state) { char *ret, *p, buf[80]; int i, x, y, col, o, maxlen; /* * First work out how many characters we need to display each * number. We're pretty flexible on grid contents here, so we * have to scan the entire grid. */ col = 0; for (i = 0; i < state->w * state->h; i++) { x = sprintf(buf, "%d", state->grid[i] / 4); if (col < x) col = x; } o = (state->orientable ? 1 : 0); /* * Now we know the exact total size of the grid we're going to * produce: it's got h rows, each containing w lots of col+o, * w-1 spaces and a trailing newline. */ maxlen = state->h * state->w * (col+o+1); ret = snewn(maxlen+1, char); p = ret; for (y = 0; y < state->h; y++) { for (x = 0; x < state->w; x++) { int v = state->grid[state->w*y+x]; sprintf(buf, "%*d", col, v/4); memcpy(p, buf, col); p += col; if (o) *p++ = "^"[v & 3]; if (x+1 == state->w) *p++ = '\n'; else *p++ = ' '; } } assert(p - ret == maxlen); *p = '\0'; return ret; } struct game_ui { int cur_x, cur_y; int cur_visible; }; static game_ui *new_ui(const game_state *state) { game_ui *ui = snew(game_ui); ui->cur_x = 0; ui->cur_y = 0; ui->cur_visible = FALSE; return ui; } static void free_ui(game_ui *ui) { sfree(ui); } static char *encode_ui(const game_ui *ui) { return NULL; } static void decode_ui(game_ui *ui, const char *encoding) { } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { } struct game_drawstate { int started; int w, h, bgcolour; int *grid; int tilesize; int cur_x, cur_y; }; static char *interpret_move(const game_state *state, game_ui *ui, const game_drawstate *ds, int x, int y, int button) { int w = state->w, h = state->h, n = state->n /* , wh = w*h */; char buf[80]; int dir; button = button & (~MOD_MASK | MOD_NUM_KEYPAD); if (IS_CURSOR_MOVE(button)) { if (button == CURSOR_LEFT && ui->cur_x > 0) ui->cur_x--; if (button == CURSOR_RIGHT && (ui->cur_x+n) < (w)) ui->cur_x++; if (button == CURSOR_UP && ui->cur_y > 0) ui->cur_y--; if (button == CURSOR_DOWN && (ui->cur_y+n) < (h)) ui->cur_y++; ui->cur_visible = 1; return ""; } if (button == LEFT_BUTTON || button == RIGHT_BUTTON) { /* * Determine the coordinates of the click. We offset by n-1 * half-blocks so that the user must click at the centre of * a rotation region rather than at the corner. */ x -= (n-1) * TILE_SIZE / 2; y -= (n-1) * TILE_SIZE / 2; x = FROMCOORD(x); y = FROMCOORD(y); dir = (button == LEFT_BUTTON ? 1 : -1); if (x < 0 || x > w-n || y < 0 || y > h-n) return NULL; ui->cur_visible = 0; } else if (IS_CURSOR_SELECT(button)) { if (ui->cur_visible) { x = ui->cur_x; y = ui->cur_y; dir = (button == CURSOR_SELECT2) ? -1 : +1; } else { ui->cur_visible = 1; return ""; } } else if (button == 'a' || button == 'A' || button==MOD_NUM_KEYPAD+'7') { x = y = 0; dir = (button == 'A' ? -1 : +1); } else if (button == 'b' || button == 'B' || button==MOD_NUM_KEYPAD+'9') { x = w-n; y = 0; dir = (button == 'B' ? -1 : +1); } else if (button == 'c' || button == 'C' || button==MOD_NUM_KEYPAD+'1') { x = 0; y = h-n; dir = (button == 'C' ? -1 : +1); } else if (button == 'd' || button == 'D' || button==MOD_NUM_KEYPAD+'3') { x = w-n; y = h-n; dir = (button == 'D' ? -1 : +1); } else if (button==MOD_NUM_KEYPAD+'8' && (w-n) % 2 == 0) { x = (w-n) / 2; y = 0; dir = +1; } else if (button==MOD_NUM_KEYPAD+'2' && (w-n) % 2 == 0) { x = (w-n) / 2; y = h-n; dir = +1; } else if (button==MOD_NUM_KEYPAD+'4' && (h-n) % 2 == 0) { x = 0; y = (h-n) / 2; dir = +1; } else if (button==MOD_NUM_KEYPAD+'6' && (h-n) % 2 == 0) { x = w-n; y = (h-n) / 2; dir = +1; } else if (button==MOD_NUM_KEYPAD+'5' && (w-n) % 2 == 0 && (h-n) % 2 == 0){ x = (w-n) / 2; y = (h-n) / 2; dir = +1; } else { return NULL; /* no move to be made */ } /* * If we reach here, we have a valid move. */ sprintf(buf, "M%d,%d,%d", x, y, dir); return dupstr(buf); } static game_state *execute_move(const game_state *from, const char *move) { game_state *ret; int w = from->w, h = from->h, n = from->n, wh = w*h; int x, y, dir; if (!strcmp(move, "S")) { int i; ret = dup_game(from); /* * Simply replace the grid with a solved one. For this game, * this isn't a useful operation for actually telling the user * what they should have done, but it is useful for * conveniently being able to get hold of a clean state from * which to practise manoeuvres. */ qsort(ret->grid, ret->w*ret->h, sizeof(int), compare_int); for (i = 0; i < ret->w*ret->h; i++) ret->grid[i] &= ~3; ret->used_solve = TRUE; ret->completed = ret->movecount = 1; return ret; } if (move[0] != 'M' || sscanf(move+1, "%d,%d,%d", &x, &y, &dir) != 3 || x < 0 || y < 0 || x > from->w - n || y > from->h - n) return NULL; /* can't parse this move string */ ret = dup_game(from); ret->movecount++; do_rotate(ret->grid, w, h, n, ret->orientable, x, y, dir); ret->lastx = x; ret->lasty = y; ret->lastr = dir; /* * See if the game has been completed. To do this we simply * test that the grid contents are in increasing order. */ if (!ret->completed && grid_complete(ret->grid, wh, ret->orientable)) ret->completed = ret->movecount; return ret; } /* ---------------------------------------------------------------------- * Drawing routines. */ static void game_compute_size(const game_params *params, int tilesize, int *x, int *y) { /* Ick: fake up `ds->tilesize' for macro expansion purposes */ struct { int tilesize; } ads, *ds = &ads; ads.tilesize = tilesize; *x = TILE_SIZE * params->w + 2 * BORDER; *y = TILE_SIZE * params->h + 2 * BORDER; } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { ds->tilesize = tilesize; } static float *game_colours(frontend *fe, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float); int i; game_mkhighlight(fe, ret, COL_BACKGROUND, COL_HIGHLIGHT, COL_LOWLIGHT); /* cursor is light-background with a red tinge. */ ret[COL_HIGHCURSOR * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] * 1.0F; ret[COL_HIGHCURSOR * 3 + 1] = ret[COL_BACKGROUND * 3 + 1] * 0.5F; ret[COL_HIGHCURSOR * 3 + 2] = ret[COL_BACKGROUND * 3 + 2] * 0.5F; for (i = 0; i < 3; i++) { ret[COL_HIGHLIGHT_GENTLE * 3 + i] = ret[COL_BACKGROUND * 3 + i] * 1.1F; ret[COL_LOWLIGHT_GENTLE * 3 + i] = ret[COL_BACKGROUND * 3 + i] * 0.9F; ret[COL_TEXT * 3 + i] = 0.0; ret[COL_LOWCURSOR * 3 + i] = ret[COL_HIGHCURSOR * 3 + i] * 0.6F; } *ncolours = NCOLOURS; return ret; } static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { struct game_drawstate *ds = snew(struct game_drawstate); int i; ds->started = FALSE; ds->w = state->w; ds->h = state->h; ds->bgcolour = COL_BACKGROUND; ds->grid = snewn(ds->w*ds->h, int); ds->tilesize = 0; /* haven't decided yet */ for (i = 0; i < ds->w*ds->h; i++) ds->grid[i] = -1; ds->cur_x = ds->cur_y = -state->n; return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { sfree(ds->grid); sfree(ds); } struct rotation { int cx, cy, cw, ch; /* clip region */ int ox, oy; /* rotation origin */ float c, s; /* cos and sin of rotation angle */ int lc, rc, tc, bc; /* colours of tile edges */ }; static void rotate(int *xy, struct rotation *rot) { if (rot) { float xf = (float)xy[0] - rot->ox, yf = (float)xy[1] - rot->oy; float xf2, yf2; xf2 = rot->c * xf + rot->s * yf; yf2 = - rot->s * xf + rot->c * yf; xy[0] = (int)(xf2 + rot->ox + 0.5); /* round to nearest */ xy[1] = (int)(yf2 + rot->oy + 0.5); /* round to nearest */ } } #define CUR_TOP 1 #define CUR_RIGHT 2 #define CUR_BOTTOM 4 #define CUR_LEFT 8 static void draw_tile(drawing *dr, game_drawstate *ds, const game_state *state, int x, int y, int tile, int flash_colour, struct rotation *rot, unsigned cedges) { int coords[8]; char str[40]; /* * If we've been passed a rotation region but we're drawing a * tile which is outside it, we must draw it normally. This can * occur if we're cleaning up after a completion flash while a * new move is also being made. */ if (rot && (x < rot->cx || y < rot->cy || x >= rot->cx+rot->cw || y >= rot->cy+rot->ch)) rot = NULL; if (rot) clip(dr, rot->cx, rot->cy, rot->cw, rot->ch); /* * We must draw each side of the tile's highlight separately, * because in some cases (during rotation) they will all need * to be different colours. */ /* The centre point is common to all sides. */ coords[4] = x + TILE_SIZE / 2; coords[5] = y + TILE_SIZE / 2; rotate(coords+4, rot); /* Right side. */ coords[0] = x + TILE_SIZE - 1; coords[1] = y + TILE_SIZE - 1; rotate(coords+0, rot); coords[2] = x + TILE_SIZE - 1; coords[3] = y; rotate(coords+2, rot); draw_polygon(dr, coords, 3, rot ? rot->rc : COL_LOWLIGHT, rot ? rot->rc : (cedges & CUR_RIGHT) ? COL_LOWCURSOR : COL_LOWLIGHT); /* Bottom side. */ coords[2] = x; coords[3] = y + TILE_SIZE - 1; rotate(coords+2, rot); draw_polygon(dr, coords, 3, rot ? rot->bc : COL_LOWLIGHT, rot ? rot->bc : (cedges & CUR_BOTTOM) ? COL_LOWCURSOR : COL_LOWLIGHT); /* Left side. */ coords[0] = x; coords[1] = y; rotate(coords+0, rot); draw_polygon(dr, coords, 3, rot ? rot->lc : COL_HIGHLIGHT, rot ? rot->lc : (cedges & CUR_LEFT) ? COL_HIGHCURSOR : COL_HIGHLIGHT); /* Top side. */ coords[2] = x + TILE_SIZE - 1; coords[3] = y; rotate(coords+2, rot); draw_polygon(dr, coords, 3, rot ? rot->tc : COL_HIGHLIGHT, rot ? rot->tc : (cedges & CUR_TOP) ? COL_HIGHCURSOR : COL_HIGHLIGHT); /* * Now the main blank area in the centre of the tile. */ if (rot) { coords[0] = x + HIGHLIGHT_WIDTH; coords[1] = y + HIGHLIGHT_WIDTH; rotate(coords+0, rot); coords[2] = x + HIGHLIGHT_WIDTH; coords[3] = y + TILE_SIZE - 1 - HIGHLIGHT_WIDTH; rotate(coords+2, rot); coords[4] = x + TILE_SIZE - 1 - HIGHLIGHT_WIDTH; coords[5] = y + TILE_SIZE - 1 - HIGHLIGHT_WIDTH; rotate(coords+4, rot); coords[6] = x + TILE_SIZE - 1 - HIGHLIGHT_WIDTH; coords[7] = y + HIGHLIGHT_WIDTH; rotate(coords+6, rot); draw_polygon(dr, coords, 4, flash_colour, flash_colour); } else { draw_rect(dr, x + HIGHLIGHT_WIDTH, y + HIGHLIGHT_WIDTH, TILE_SIZE - 2*HIGHLIGHT_WIDTH, TILE_SIZE - 2*HIGHLIGHT_WIDTH, flash_colour); } /* * Next, the triangles for orientation. */ if (state->orientable) { int xdx, xdy, ydx, ydy; int cx, cy, displ, displ2; switch (tile & 3) { case 0: xdx = 1, xdy = 0; ydx = 0, ydy = 1; break; case 1: xdx = 0, xdy = -1; ydx = 1, ydy = 0; break; case 2: xdx = -1, xdy = 0; ydx = 0, ydy = -1; break; default /* case 3 */: xdx = 0, xdy = 1; ydx = -1, ydy = 0; break; } cx = x + TILE_SIZE / 2; cy = y + TILE_SIZE / 2; displ = TILE_SIZE / 2 - HIGHLIGHT_WIDTH - 2; displ2 = TILE_SIZE / 3 - HIGHLIGHT_WIDTH; coords[0] = cx - displ * xdx + displ2 * ydx; coords[1] = cy - displ * xdy + displ2 * ydy; rotate(coords+0, rot); coords[2] = cx + displ * xdx + displ2 * ydx; coords[3] = cy + displ * xdy + displ2 * ydy; rotate(coords+2, rot); coords[4] = cx - displ * ydx; coords[5] = cy - displ * ydy; rotate(coords+4, rot); draw_polygon(dr, coords, 3, COL_LOWLIGHT_GENTLE, COL_LOWLIGHT_GENTLE); } coords[0] = x + TILE_SIZE/2; coords[1] = y + TILE_SIZE/2; rotate(coords+0, rot); sprintf(str, "%d", tile / 4); draw_text(dr, coords[0], coords[1], FONT_VARIABLE, TILE_SIZE/3, ALIGN_VCENTRE | ALIGN_HCENTRE, COL_TEXT, str); if (rot) unclip(dr); draw_update(dr, x, y, TILE_SIZE, TILE_SIZE); } static int highlight_colour(float angle) { int colours[32] = { COL_LOWLIGHT, COL_LOWLIGHT_GENTLE, COL_LOWLIGHT_GENTLE, COL_LOWLIGHT_GENTLE, COL_HIGHLIGHT_GENTLE, COL_HIGHLIGHT_GENTLE, COL_HIGHLIGHT_GENTLE, COL_HIGHLIGHT, COL_HIGHLIGHT, COL_HIGHLIGHT, COL_HIGHLIGHT, COL_HIGHLIGHT, COL_HIGHLIGHT, COL_HIGHLIGHT, COL_HIGHLIGHT, COL_HIGHLIGHT, COL_HIGHLIGHT, COL_HIGHLIGHT_GENTLE, COL_HIGHLIGHT_GENTLE, COL_HIGHLIGHT_GENTLE, COL_LOWLIGHT_GENTLE, COL_LOWLIGHT_GENTLE, COL_LOWLIGHT_GENTLE, COL_LOWLIGHT, COL_LOWLIGHT, COL_LOWLIGHT, COL_LOWLIGHT, COL_LOWLIGHT, COL_LOWLIGHT, COL_LOWLIGHT, COL_LOWLIGHT, COL_LOWLIGHT, }; return colours[(int)((angle + 2*PI) / (PI/16)) & 31]; } static float game_anim_length_real(const game_state *oldstate, const game_state *newstate, int dir, const game_ui *ui) { /* * Our game_anim_length doesn't need to modify its game_ui, so * this is the real function which declares ui as const. We must * wrap this for the backend structure with a version that has ui * non-const, but we still need this version to call from within * game_redraw which only has a const ui available. */ return (float)(ANIM_PER_BLKSIZE_UNIT * sqrt(newstate->n-1)); } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return game_anim_length_real(oldstate, newstate, dir, ui); } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { if (!oldstate->completed && newstate->completed && !oldstate->used_solve && !newstate->used_solve) return 2 * FLASH_FRAME; else return 0.0F; } static int game_status(const game_state *state) { return state->completed ? +1 : 0; } static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float animtime, float flashtime) { int i, bgcolour; struct rotation srot, *rot; int lastx = -1, lasty = -1, lastr = -1; int cx, cy, cmoved = 0, n = state->n; cx = ui->cur_visible ? ui->cur_x : -state->n; cy = ui->cur_visible ? ui->cur_y : -state->n; if (cx != ds->cur_x || cy != ds->cur_y) cmoved = 1; if (flashtime > 0) { int frame = (int)(flashtime / FLASH_FRAME); bgcolour = (frame % 2 ? COL_LOWLIGHT : COL_HIGHLIGHT); } else bgcolour = COL_BACKGROUND; if (!ds->started) { int coords[10]; draw_rect(dr, 0, 0, TILE_SIZE * state->w + 2 * BORDER, TILE_SIZE * state->h + 2 * BORDER, COL_BACKGROUND); draw_update(dr, 0, 0, TILE_SIZE * state->w + 2 * BORDER, TILE_SIZE * state->h + 2 * BORDER); /* * Recessed area containing the whole puzzle. */ coords[0] = COORD(state->w) + HIGHLIGHT_WIDTH - 1; coords[1] = COORD(state->h) + HIGHLIGHT_WIDTH - 1; coords[2] = COORD(state->w) + HIGHLIGHT_WIDTH - 1; coords[3] = COORD(0) - HIGHLIGHT_WIDTH; coords[4] = coords[2] - TILE_SIZE; coords[5] = coords[3] + TILE_SIZE; coords[8] = COORD(0) - HIGHLIGHT_WIDTH; coords[9] = COORD(state->h) + HIGHLIGHT_WIDTH - 1; coords[6] = coords[8] + TILE_SIZE; coords[7] = coords[9] - TILE_SIZE; draw_polygon(dr, coords, 5, COL_HIGHLIGHT, COL_HIGHLIGHT); coords[1] = COORD(0) - HIGHLIGHT_WIDTH; coords[0] = COORD(0) - HIGHLIGHT_WIDTH; draw_polygon(dr, coords, 5, COL_LOWLIGHT, COL_LOWLIGHT); ds->started = TRUE; } /* * If we're drawing any rotated tiles, sort out the rotation * parameters, and also zap the rotation region to the * background colour before doing anything else. */ if (oldstate) { float angle; float anim_max = game_anim_length_real(oldstate, state, dir, ui); if (dir > 0) { lastx = state->lastx; lasty = state->lasty; lastr = state->lastr; } else { lastx = oldstate->lastx; lasty = oldstate->lasty; lastr = -oldstate->lastr; } rot = &srot; rot->cx = COORD(lastx); rot->cy = COORD(lasty); rot->cw = rot->ch = TILE_SIZE * state->n; rot->ox = rot->cx + rot->cw/2; rot->oy = rot->cy + rot->ch/2; angle = (float)((-PI/2 * lastr) * (1.0 - animtime / anim_max)); rot->c = (float)cos(angle); rot->s = (float)sin(angle); /* * Sort out the colours of the various sides of the tile. */ rot->lc = highlight_colour((float)PI + angle); rot->rc = highlight_colour(angle); rot->tc = highlight_colour((float)(PI/2.0) + angle); rot->bc = highlight_colour((float)(-PI/2.0) + angle); draw_rect(dr, rot->cx, rot->cy, rot->cw, rot->ch, bgcolour); } else rot = NULL; /* * Now draw each tile. */ for (i = 0; i < state->w * state->h; i++) { int t, cc = 0; int tx = i % state->w, ty = i / state->w; /* * Figure out what should be displayed at this location. * Usually it will be state->grid[i], unless we're in the * middle of animating an actual rotation and this cell is * within the rotation region, in which case we set -1 * (always display). */ if (oldstate && lastx >= 0 && lasty >= 0 && tx >= lastx && tx < lastx + state->n && ty >= lasty && ty < lasty + state->n) t = -1; else t = state->grid[i]; if (cmoved) { /* cursor has moved (or changed visibility)... */ if (tx == cx || tx == cx+n-1 || ty == cy || ty == cy+n-1) cc = 1; /* ...we're on new cursor, redraw */ if (tx == ds->cur_x || tx == ds->cur_x+n-1 || ty == ds->cur_y || ty == ds->cur_y+n-1) cc = 1; /* ...we were on old cursor, redraw */ } if (ds->bgcolour != bgcolour || /* always redraw when flashing */ ds->grid[i] != t || ds->grid[i] == -1 || t == -1 || cc) { int x = COORD(tx), y = COORD(ty); unsigned cedges = 0; if (tx == cx && ty >= cy && ty <= cy+n-1) cedges |= CUR_LEFT; if (ty == cy && tx >= cx && tx <= cx+n-1) cedges |= CUR_TOP; if (tx == cx+n-1 && ty >= cy && ty <= cy+n-1) cedges |= CUR_RIGHT; if (ty == cy+n-1 && tx >= cx && tx <= cx+n-1) cedges |= CUR_BOTTOM; draw_tile(dr, ds, state, x, y, state->grid[i], bgcolour, rot, cedges); ds->grid[i] = t; } } ds->bgcolour = bgcolour; ds->cur_x = cx; ds->cur_y = cy; /* * Update the status bar. */ { char statusbuf[256]; /* * Don't show the new status until we're also showing the * new _state_ - after the game animation is complete. */ if (oldstate) state = oldstate; if (state->used_solve) sprintf(statusbuf, "Moves since auto-solve: %d", state->movecount - state->completed); else { sprintf(statusbuf, "%sMoves: %d", (state->completed ? "COMPLETED! " : ""), (state->completed ? state->completed : state->movecount)); if (state->movetarget) sprintf(statusbuf+strlen(statusbuf), " (target %d)", state->movetarget); } status_bar(dr, statusbuf); } } static int game_timing_state(const game_state *state, game_ui *ui) { return TRUE; } static void game_print_size(const game_params *params, float *x, float *y) { } static void game_print(drawing *dr, const game_state *state, int tilesize) { } #ifdef COMBINED #define thegame twiddle #endif const struct game thegame = { "Twiddle", "games.twiddle", "twiddle", default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, TRUE, solve_game, TRUE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, PREFERRED_TILE_SIZE, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, FALSE, FALSE, game_print_size, game_print, TRUE, /* wants_statusbar */ FALSE, game_timing_state, 0, /* flags */ }; /* vim: set shiftwidth=4 tabstop=8: */ puzzles-20170606.272beef/tree234.c0000644000175000017500000017537013115373615015242 0ustar simonsimon/* * tree234.c: reasonably generic counted 2-3-4 tree routines. * * This file is copyright 1999-2001 Simon Tatham. * * 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 SIMON TATHAM BE LIABLE FOR * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include #include #include "tree234.h" #include "puzzles.h" /* for smalloc/sfree */ #ifdef TEST #define LOG(x) (printf x) #define smalloc malloc #define srealloc realloc #define sfree free #else #define LOG(x) #endif typedef struct node234_Tag node234; struct tree234_Tag { node234 *root; cmpfn234 cmp; }; struct node234_Tag { node234 *parent; node234 *kids[4]; int counts[4]; void *elems[3]; }; /* * Create a 2-3-4 tree. */ tree234 *newtree234(cmpfn234 cmp) { tree234 *ret = snew(tree234); LOG(("created tree %p\n", ret)); ret->root = NULL; ret->cmp = cmp; return ret; } /* * Free a 2-3-4 tree (not including freeing the elements). */ static void freenode234(node234 *n) { if (!n) return; freenode234(n->kids[0]); freenode234(n->kids[1]); freenode234(n->kids[2]); freenode234(n->kids[3]); sfree(n); } void freetree234(tree234 *t) { freenode234(t->root); sfree(t); } /* * Internal function to count a node. */ static int countnode234(node234 *n) { int count = 0; int i; if (!n) return 0; for (i = 0; i < 4; i++) count += n->counts[i]; for (i = 0; i < 3; i++) if (n->elems[i]) count++; return count; } /* * Count the elements in a tree. */ int count234(tree234 *t) { if (t->root) return countnode234(t->root); else return 0; } /* * Propagate a node overflow up a tree until it stops. Returns 0 or * 1, depending on whether the root had to be split or not. */ static int add234_insert(node234 *left, void *e, node234 *right, node234 **root, node234 *n, int ki) { int lcount, rcount; /* * We need to insert the new left/element/right set in n at * child position ki. */ lcount = countnode234(left); rcount = countnode234(right); while (n) { LOG((" at %p: %p/%d \"%s\" %p/%d \"%s\" %p/%d \"%s\" %p/%d\n", n, n->kids[0], n->counts[0], n->elems[0], n->kids[1], n->counts[1], n->elems[1], n->kids[2], n->counts[2], n->elems[2], n->kids[3], n->counts[3])); LOG((" need to insert %p/%d \"%s\" %p/%d at position %d\n", left, lcount, e, right, rcount, ki)); if (n->elems[1] == NULL) { /* * Insert in a 2-node; simple. */ if (ki == 0) { LOG((" inserting on left of 2-node\n")); n->kids[2] = n->kids[1]; n->counts[2] = n->counts[1]; n->elems[1] = n->elems[0]; n->kids[1] = right; n->counts[1] = rcount; n->elems[0] = e; n->kids[0] = left; n->counts[0] = lcount; } else { /* ki == 1 */ LOG((" inserting on right of 2-node\n")); n->kids[2] = right; n->counts[2] = rcount; n->elems[1] = e; n->kids[1] = left; n->counts[1] = lcount; } if (n->kids[0]) n->kids[0]->parent = n; if (n->kids[1]) n->kids[1]->parent = n; if (n->kids[2]) n->kids[2]->parent = n; LOG((" done\n")); break; } else if (n->elems[2] == NULL) { /* * Insert in a 3-node; simple. */ if (ki == 0) { LOG((" inserting on left of 3-node\n")); n->kids[3] = n->kids[2]; n->counts[3] = n->counts[2]; n->elems[2] = n->elems[1]; n->kids[2] = n->kids[1]; n->counts[2] = n->counts[1]; n->elems[1] = n->elems[0]; n->kids[1] = right; n->counts[1] = rcount; n->elems[0] = e; n->kids[0] = left; n->counts[0] = lcount; } else if (ki == 1) { LOG((" inserting in middle of 3-node\n")); n->kids[3] = n->kids[2]; n->counts[3] = n->counts[2]; n->elems[2] = n->elems[1]; n->kids[2] = right; n->counts[2] = rcount; n->elems[1] = e; n->kids[1] = left; n->counts[1] = lcount; } else { /* ki == 2 */ LOG((" inserting on right of 3-node\n")); n->kids[3] = right; n->counts[3] = rcount; n->elems[2] = e; n->kids[2] = left; n->counts[2] = lcount; } if (n->kids[0]) n->kids[0]->parent = n; if (n->kids[1]) n->kids[1]->parent = n; if (n->kids[2]) n->kids[2]->parent = n; if (n->kids[3]) n->kids[3]->parent = n; LOG((" done\n")); break; } else { node234 *m = snew(node234); m->parent = n->parent; LOG((" splitting a 4-node; created new node %p\n", m)); /* * Insert in a 4-node; split into a 2-node and a * 3-node, and move focus up a level. * * I don't think it matters which way round we put the * 2 and the 3. For simplicity, we'll put the 3 first * always. */ if (ki == 0) { m->kids[0] = left; m->counts[0] = lcount; m->elems[0] = e; m->kids[1] = right; m->counts[1] = rcount; m->elems[1] = n->elems[0]; m->kids[2] = n->kids[1]; m->counts[2] = n->counts[1]; e = n->elems[1]; n->kids[0] = n->kids[2]; n->counts[0] = n->counts[2]; n->elems[0] = n->elems[2]; n->kids[1] = n->kids[3]; n->counts[1] = n->counts[3]; } else if (ki == 1) { m->kids[0] = n->kids[0]; m->counts[0] = n->counts[0]; m->elems[0] = n->elems[0]; m->kids[1] = left; m->counts[1] = lcount; m->elems[1] = e; m->kids[2] = right; m->counts[2] = rcount; e = n->elems[1]; n->kids[0] = n->kids[2]; n->counts[0] = n->counts[2]; n->elems[0] = n->elems[2]; n->kids[1] = n->kids[3]; n->counts[1] = n->counts[3]; } else if (ki == 2) { m->kids[0] = n->kids[0]; m->counts[0] = n->counts[0]; m->elems[0] = n->elems[0]; m->kids[1] = n->kids[1]; m->counts[1] = n->counts[1]; m->elems[1] = n->elems[1]; m->kids[2] = left; m->counts[2] = lcount; /* e = e; */ n->kids[0] = right; n->counts[0] = rcount; n->elems[0] = n->elems[2]; n->kids[1] = n->kids[3]; n->counts[1] = n->counts[3]; } else { /* ki == 3 */ m->kids[0] = n->kids[0]; m->counts[0] = n->counts[0]; m->elems[0] = n->elems[0]; m->kids[1] = n->kids[1]; m->counts[1] = n->counts[1]; m->elems[1] = n->elems[1]; m->kids[2] = n->kids[2]; m->counts[2] = n->counts[2]; n->kids[0] = left; n->counts[0] = lcount; n->elems[0] = e; n->kids[1] = right; n->counts[1] = rcount; e = n->elems[2]; } m->kids[3] = n->kids[3] = n->kids[2] = NULL; m->counts[3] = n->counts[3] = n->counts[2] = 0; m->elems[2] = n->elems[2] = n->elems[1] = NULL; if (m->kids[0]) m->kids[0]->parent = m; if (m->kids[1]) m->kids[1]->parent = m; if (m->kids[2]) m->kids[2]->parent = m; if (n->kids[0]) n->kids[0]->parent = n; if (n->kids[1]) n->kids[1]->parent = n; LOG((" left (%p): %p/%d \"%s\" %p/%d \"%s\" %p/%d\n", m, m->kids[0], m->counts[0], m->elems[0], m->kids[1], m->counts[1], m->elems[1], m->kids[2], m->counts[2])); LOG((" right (%p): %p/%d \"%s\" %p/%d\n", n, n->kids[0], n->counts[0], n->elems[0], n->kids[1], n->counts[1])); left = m; lcount = countnode234(left); right = n; rcount = countnode234(right); } if (n->parent) ki = (n->parent->kids[0] == n ? 0 : n->parent->kids[1] == n ? 1 : n->parent->kids[2] == n ? 2 : 3); n = n->parent; } /* * If we've come out of here by `break', n will still be * non-NULL and all we need to do is go back up the tree * updating counts. If we've come here because n is NULL, we * need to create a new root for the tree because the old one * has just split into two. */ if (n) { while (n->parent) { int count = countnode234(n); int childnum; childnum = (n->parent->kids[0] == n ? 0 : n->parent->kids[1] == n ? 1 : n->parent->kids[2] == n ? 2 : 3); n->parent->counts[childnum] = count; n = n->parent; } return 0; /* root unchanged */ } else { LOG((" root is overloaded, split into two\n")); (*root) = snew(node234); (*root)->kids[0] = left; (*root)->counts[0] = lcount; (*root)->elems[0] = e; (*root)->kids[1] = right; (*root)->counts[1] = rcount; (*root)->elems[1] = NULL; (*root)->kids[2] = NULL; (*root)->counts[2] = 0; (*root)->elems[2] = NULL; (*root)->kids[3] = NULL; (*root)->counts[3] = 0; (*root)->parent = NULL; if ((*root)->kids[0]) (*root)->kids[0]->parent = (*root); if ((*root)->kids[1]) (*root)->kids[1]->parent = (*root); LOG((" new root is %p/%d \"%s\" %p/%d\n", (*root)->kids[0], (*root)->counts[0], (*root)->elems[0], (*root)->kids[1], (*root)->counts[1])); return 1; /* root moved */ } } /* * Add an element e to a 2-3-4 tree t. Returns e on success, or if * an existing element compares equal, returns that. */ static void *add234_internal(tree234 *t, void *e, int index) { node234 *n; int ki; void *orig_e = e; int c; LOG(("adding element \"%s\" to tree %p\n", e, t)); if (t->root == NULL) { t->root = snew(node234); t->root->elems[1] = t->root->elems[2] = NULL; t->root->kids[0] = t->root->kids[1] = NULL; t->root->kids[2] = t->root->kids[3] = NULL; t->root->counts[0] = t->root->counts[1] = 0; t->root->counts[2] = t->root->counts[3] = 0; t->root->parent = NULL; t->root->elems[0] = e; LOG((" created root %p\n", t->root)); return orig_e; } n = t->root; while (n) { LOG((" node %p: %p/%d \"%s\" %p/%d \"%s\" %p/%d \"%s\" %p/%d\n", n, n->kids[0], n->counts[0], n->elems[0], n->kids[1], n->counts[1], n->elems[1], n->kids[2], n->counts[2], n->elems[2], n->kids[3], n->counts[3])); if (index >= 0) { if (!n->kids[0]) { /* * Leaf node. We want to insert at kid position * equal to the index: * * 0 A 1 B 2 C 3 */ ki = index; } else { /* * Internal node. We always descend through it (add * always starts at the bottom, never in the * middle). */ if (index <= n->counts[0]) { ki = 0; } else if (index -= n->counts[0] + 1, index <= n->counts[1]) { ki = 1; } else if (index -= n->counts[1] + 1, index <= n->counts[2]) { ki = 2; } else if (index -= n->counts[2] + 1, index <= n->counts[3]) { ki = 3; } else return NULL; /* error: index out of range */ } } else { if ((c = t->cmp(e, n->elems[0])) < 0) ki = 0; else if (c == 0) return n->elems[0]; /* already exists */ else if (n->elems[1] == NULL || (c = t->cmp(e, n->elems[1])) < 0) ki = 1; else if (c == 0) return n->elems[1]; /* already exists */ else if (n->elems[2] == NULL || (c = t->cmp(e, n->elems[2])) < 0) ki = 2; else if (c == 0) return n->elems[2]; /* already exists */ else ki = 3; } LOG((" moving to child %d (%p)\n", ki, n->kids[ki])); if (!n->kids[ki]) break; n = n->kids[ki]; } add234_insert(NULL, e, NULL, &t->root, n, ki); return orig_e; } void *add234(tree234 *t, void *e) { if (!t->cmp) /* tree is unsorted */ return NULL; return add234_internal(t, e, -1); } void *addpos234(tree234 *t, void *e, int index) { if (index < 0 || /* index out of range */ t->cmp) /* tree is sorted */ return NULL; /* return failure */ return add234_internal(t, e, index); /* this checks the upper bound */ } /* * Look up the element at a given numeric index in a 2-3-4 tree. * Returns NULL if the index is out of range. */ void *index234(tree234 *t, int index) { node234 *n; if (!t->root) return NULL; /* tree is empty */ if (index < 0 || index >= countnode234(t->root)) return NULL; /* out of range */ n = t->root; while (n) { if (index < n->counts[0]) n = n->kids[0]; else if (index -= n->counts[0] + 1, index < 0) return n->elems[0]; else if (index < n->counts[1]) n = n->kids[1]; else if (index -= n->counts[1] + 1, index < 0) return n->elems[1]; else if (index < n->counts[2]) n = n->kids[2]; else if (index -= n->counts[2] + 1, index < 0) return n->elems[2]; else n = n->kids[3]; } /* We shouldn't ever get here. I wonder how we did. */ return NULL; } /* * Find an element e in a sorted 2-3-4 tree t. Returns NULL if not * found. e is always passed as the first argument to cmp, so cmp * can be an asymmetric function if desired. cmp can also be passed * as NULL, in which case the compare function from the tree proper * will be used. */ void *findrelpos234(tree234 *t, void *e, cmpfn234 cmp, int relation, int *index) { node234 *n; void *ret; int c; int idx, ecount, kcount, cmpret; if (t->root == NULL) return NULL; if (cmp == NULL) cmp = t->cmp; n = t->root; /* * Attempt to find the element itself. */ idx = 0; ecount = -1; /* * Prepare a fake `cmp' result if e is NULL. */ cmpret = 0; if (e == NULL) { assert(relation == REL234_LT || relation == REL234_GT); if (relation == REL234_LT) cmpret = +1; /* e is a max: always greater */ else if (relation == REL234_GT) cmpret = -1; /* e is a min: always smaller */ } while (1) { for (kcount = 0; kcount < 4; kcount++) { if (kcount >= 3 || n->elems[kcount] == NULL || (c = cmpret ? cmpret : cmp(e, n->elems[kcount])) < 0) { break; } if (n->kids[kcount]) idx += n->counts[kcount]; if (c == 0) { ecount = kcount; break; } idx++; } if (ecount >= 0) break; if (n->kids[kcount]) n = n->kids[kcount]; else break; } if (ecount >= 0) { /* * We have found the element we're looking for. It's * n->elems[ecount], at tree index idx. If our search * relation is EQ, LE or GE we can now go home. */ if (relation != REL234_LT && relation != REL234_GT) { if (index) *index = idx; return n->elems[ecount]; } /* * Otherwise, we'll do an indexed lookup for the previous * or next element. (It would be perfectly possible to * implement these search types in a non-counted tree by * going back up from where we are, but far more fiddly.) */ if (relation == REL234_LT) idx--; else idx++; } else { /* * We've found our way to the bottom of the tree and we * know where we would insert this node if we wanted to: * we'd put it in in place of the (empty) subtree * n->kids[kcount], and it would have index idx * * But the actual element isn't there. So if our search * relation is EQ, we're doomed. */ if (relation == REL234_EQ) return NULL; /* * Otherwise, we must do an index lookup for index idx-1 * (if we're going left - LE or LT) or index idx (if we're * going right - GE or GT). */ if (relation == REL234_LT || relation == REL234_LE) { idx--; } } /* * We know the index of the element we want; just call index234 * to do the rest. This will return NULL if the index is out of * bounds, which is exactly what we want. */ ret = index234(t, idx); if (ret && index) *index = idx; return ret; } void *find234(tree234 *t, void *e, cmpfn234 cmp) { return findrelpos234(t, e, cmp, REL234_EQ, NULL); } void *findrel234(tree234 *t, void *e, cmpfn234 cmp, int relation) { return findrelpos234(t, e, cmp, relation, NULL); } void *findpos234(tree234 *t, void *e, cmpfn234 cmp, int *index) { return findrelpos234(t, e, cmp, REL234_EQ, index); } /* * Tree transformation used in delete and split: move a subtree * right, from child ki of a node to the next child. Update k and * index so that they still point to the same place in the * transformed tree. Assumes the destination child is not full, and * that the source child does have a subtree to spare. Can cope if * the destination child is undersized. * * . C . . B . * / \ -> / \ * [more] a A b B c d D e [more] a A b c C d D e * * . C . . B . * / \ -> / \ * [more] a A b B c d [more] a A b c C d */ static void trans234_subtree_right(node234 *n, int ki, int *k, int *index) { node234 *src, *dest; int i, srclen, adjust; src = n->kids[ki]; dest = n->kids[ki+1]; LOG((" trans234_subtree_right(%p, %d):\n", n, ki)); LOG((" parent %p: %p/%d \"%s\" %p/%d \"%s\" %p/%d \"%s\" %p/%d\n", n, n->kids[0], n->counts[0], n->elems[0], n->kids[1], n->counts[1], n->elems[1], n->kids[2], n->counts[2], n->elems[2], n->kids[3], n->counts[3])); LOG((" src %p: %p/%d \"%s\" %p/%d \"%s\" %p/%d \"%s\" %p/%d\n", src, src->kids[0], src->counts[0], src->elems[0], src->kids[1], src->counts[1], src->elems[1], src->kids[2], src->counts[2], src->elems[2], src->kids[3], src->counts[3])); LOG((" dest %p: %p/%d \"%s\" %p/%d \"%s\" %p/%d \"%s\" %p/%d\n", dest, dest->kids[0], dest->counts[0], dest->elems[0], dest->kids[1], dest->counts[1], dest->elems[1], dest->kids[2], dest->counts[2], dest->elems[2], dest->kids[3], dest->counts[3])); /* * Move over the rest of the destination node to make space. */ dest->kids[3] = dest->kids[2]; dest->counts[3] = dest->counts[2]; dest->elems[2] = dest->elems[1]; dest->kids[2] = dest->kids[1]; dest->counts[2] = dest->counts[1]; dest->elems[1] = dest->elems[0]; dest->kids[1] = dest->kids[0]; dest->counts[1] = dest->counts[0]; /* which element to move over */ i = (src->elems[2] ? 2 : src->elems[1] ? 1 : 0); dest->elems[0] = n->elems[ki]; n->elems[ki] = src->elems[i]; src->elems[i] = NULL; dest->kids[0] = src->kids[i+1]; dest->counts[0] = src->counts[i+1]; src->kids[i+1] = NULL; src->counts[i+1] = 0; if (dest->kids[0]) dest->kids[0]->parent = dest; adjust = dest->counts[0] + 1; n->counts[ki] -= adjust; n->counts[ki+1] += adjust; srclen = n->counts[ki]; if (k) { LOG((" before: k,index = %d,%d\n", (*k), (*index))); if ((*k) == ki && (*index) > srclen) { (*index) -= srclen + 1; (*k)++; } else if ((*k) == ki+1) { (*index) += adjust; } LOG((" after: k,index = %d,%d\n", (*k), (*index))); } LOG((" parent %p: %p/%d \"%s\" %p/%d \"%s\" %p/%d \"%s\" %p/%d\n", n, n->kids[0], n->counts[0], n->elems[0], n->kids[1], n->counts[1], n->elems[1], n->kids[2], n->counts[2], n->elems[2], n->kids[3], n->counts[3])); LOG((" src %p: %p/%d \"%s\" %p/%d \"%s\" %p/%d \"%s\" %p/%d\n", src, src->kids[0], src->counts[0], src->elems[0], src->kids[1], src->counts[1], src->elems[1], src->kids[2], src->counts[2], src->elems[2], src->kids[3], src->counts[3])); LOG((" dest %p: %p/%d \"%s\" %p/%d \"%s\" %p/%d \"%s\" %p/%d\n", dest, dest->kids[0], dest->counts[0], dest->elems[0], dest->kids[1], dest->counts[1], dest->elems[1], dest->kids[2], dest->counts[2], dest->elems[2], dest->kids[3], dest->counts[3])); } /* * Tree transformation used in delete and split: move a subtree * left, from child ki of a node to the previous child. Update k * and index so that they still point to the same place in the * transformed tree. Assumes the destination child is not full, and * that the source child does have a subtree to spare. Can cope if * the destination child is undersized. * * . B . . C . * / \ -> / \ * a A b c C d D e [more] a A b B c d D e [more] * * . A . . B . * / \ -> / \ * a b B c C d [more] a A b c C d [more] */ static void trans234_subtree_left(node234 *n, int ki, int *k, int *index) { node234 *src, *dest; int i, adjust; src = n->kids[ki]; dest = n->kids[ki-1]; LOG((" trans234_subtree_left(%p, %d):\n", n, ki)); LOG((" parent %p: %p/%d \"%s\" %p/%d \"%s\" %p/%d \"%s\" %p/%d\n", n, n->kids[0], n->counts[0], n->elems[0], n->kids[1], n->counts[1], n->elems[1], n->kids[2], n->counts[2], n->elems[2], n->kids[3], n->counts[3])); LOG((" dest %p: %p/%d \"%s\" %p/%d \"%s\" %p/%d \"%s\" %p/%d\n", dest, dest->kids[0], dest->counts[0], dest->elems[0], dest->kids[1], dest->counts[1], dest->elems[1], dest->kids[2], dest->counts[2], dest->elems[2], dest->kids[3], dest->counts[3])); LOG((" src %p: %p/%d \"%s\" %p/%d \"%s\" %p/%d \"%s\" %p/%d\n", src, src->kids[0], src->counts[0], src->elems[0], src->kids[1], src->counts[1], src->elems[1], src->kids[2], src->counts[2], src->elems[2], src->kids[3], src->counts[3])); /* where in dest to put it */ i = (dest->elems[1] ? 2 : dest->elems[0] ? 1 : 0); dest->elems[i] = n->elems[ki-1]; n->elems[ki-1] = src->elems[0]; dest->kids[i+1] = src->kids[0]; dest->counts[i+1] = src->counts[0]; if (dest->kids[i+1]) dest->kids[i+1]->parent = dest; /* * Move over the rest of the source node. */ src->kids[0] = src->kids[1]; src->counts[0] = src->counts[1]; src->elems[0] = src->elems[1]; src->kids[1] = src->kids[2]; src->counts[1] = src->counts[2]; src->elems[1] = src->elems[2]; src->kids[2] = src->kids[3]; src->counts[2] = src->counts[3]; src->elems[2] = NULL; src->kids[3] = NULL; src->counts[3] = 0; adjust = dest->counts[i+1] + 1; n->counts[ki] -= adjust; n->counts[ki-1] += adjust; if (k) { LOG((" before: k,index = %d,%d\n", (*k), (*index))); if ((*k) == ki) { (*index) -= adjust; if ((*index) < 0) { (*index) += n->counts[ki-1] + 1; (*k)--; } } LOG((" after: k,index = %d,%d\n", (*k), (*index))); } LOG((" parent %p: %p/%d \"%s\" %p/%d \"%s\" %p/%d \"%s\" %p/%d\n", n, n->kids[0], n->counts[0], n->elems[0], n->kids[1], n->counts[1], n->elems[1], n->kids[2], n->counts[2], n->elems[2], n->kids[3], n->counts[3])); LOG((" dest %p: %p/%d \"%s\" %p/%d \"%s\" %p/%d \"%s\" %p/%d\n", dest, dest->kids[0], dest->counts[0], dest->elems[0], dest->kids[1], dest->counts[1], dest->elems[1], dest->kids[2], dest->counts[2], dest->elems[2], dest->kids[3], dest->counts[3])); LOG((" src %p: %p/%d \"%s\" %p/%d \"%s\" %p/%d \"%s\" %p/%d\n", src, src->kids[0], src->counts[0], src->elems[0], src->kids[1], src->counts[1], src->elems[1], src->kids[2], src->counts[2], src->elems[2], src->kids[3], src->counts[3])); } /* * Tree transformation used in delete and split: merge child nodes * ki and ki+1 of a node. Update k and index so that they still * point to the same place in the transformed tree. Assumes both * children _are_ sufficiently small. * * . B . . * / \ -> | * a A b c C d a A b B c C d * * This routine can also cope with either child being undersized: * * . A . . * / \ -> | * a b B c a A b B c * * . A . . * / \ -> | * a b B c C d a A b B c C d */ static void trans234_subtree_merge(node234 *n, int ki, int *k, int *index) { node234 *left, *right; int i, leftlen, rightlen, lsize, rsize; left = n->kids[ki]; leftlen = n->counts[ki]; right = n->kids[ki+1]; rightlen = n->counts[ki+1]; LOG((" trans234_subtree_merge(%p, %d):\n", n, ki)); LOG((" parent %p: %p/%d \"%s\" %p/%d \"%s\" %p/%d \"%s\" %p/%d\n", n, n->kids[0], n->counts[0], n->elems[0], n->kids[1], n->counts[1], n->elems[1], n->kids[2], n->counts[2], n->elems[2], n->kids[3], n->counts[3])); LOG((" left %p: %p/%d \"%s\" %p/%d \"%s\" %p/%d \"%s\" %p/%d\n", left, left->kids[0], left->counts[0], left->elems[0], left->kids[1], left->counts[1], left->elems[1], left->kids[2], left->counts[2], left->elems[2], left->kids[3], left->counts[3])); LOG((" right %p: %p/%d \"%s\" %p/%d \"%s\" %p/%d \"%s\" %p/%d\n", right, right->kids[0], right->counts[0], right->elems[0], right->kids[1], right->counts[1], right->elems[1], right->kids[2], right->counts[2], right->elems[2], right->kids[3], right->counts[3])); assert(!left->elems[2] && !right->elems[2]); /* neither is large! */ lsize = (left->elems[1] ? 2 : left->elems[0] ? 1 : 0); rsize = (right->elems[1] ? 2 : right->elems[0] ? 1 : 0); left->elems[lsize] = n->elems[ki]; for (i = 0; i < rsize+1; i++) { left->kids[lsize+1+i] = right->kids[i]; left->counts[lsize+1+i] = right->counts[i]; if (left->kids[lsize+1+i]) left->kids[lsize+1+i]->parent = left; if (i < rsize) left->elems[lsize+1+i] = right->elems[i]; } n->counts[ki] += rightlen + 1; sfree(right); /* * Move the rest of n up by one. */ for (i = ki+1; i < 3; i++) { n->kids[i] = n->kids[i+1]; n->counts[i] = n->counts[i+1]; } for (i = ki; i < 2; i++) { n->elems[i] = n->elems[i+1]; } n->kids[3] = NULL; n->counts[3] = 0; n->elems[2] = NULL; if (k) { LOG((" before: k,index = %d,%d\n", (*k), (*index))); if ((*k) == ki+1) { (*k)--; (*index) += leftlen + 1; } else if ((*k) > ki+1) { (*k)--; } LOG((" after: k,index = %d,%d\n", (*k), (*index))); } LOG((" parent %p: %p/%d \"%s\" %p/%d \"%s\" %p/%d \"%s\" %p/%d\n", n, n->kids[0], n->counts[0], n->elems[0], n->kids[1], n->counts[1], n->elems[1], n->kids[2], n->counts[2], n->elems[2], n->kids[3], n->counts[3])); LOG((" merged %p: %p/%d \"%s\" %p/%d \"%s\" %p/%d \"%s\" %p/%d\n", left, left->kids[0], left->counts[0], left->elems[0], left->kids[1], left->counts[1], left->elems[1], left->kids[2], left->counts[2], left->elems[2], left->kids[3], left->counts[3])); } /* * Delete an element e in a 2-3-4 tree. Does not free the element, * merely removes all links to it from the tree nodes. */ static void *delpos234_internal(tree234 *t, int index) { node234 *n; void *retval; int ki, i; retval = NULL; n = t->root; /* by assumption this is non-NULL */ LOG(("deleting item %d from tree %p\n", index, t)); while (1) { node234 *sub; LOG((" node %p: %p/%d \"%s\" %p/%d \"%s\" %p/%d \"%s\" %p/%d index=%d\n", n, n->kids[0], n->counts[0], n->elems[0], n->kids[1], n->counts[1], n->elems[1], n->kids[2], n->counts[2], n->elems[2], n->kids[3], n->counts[3], index)); if (index <= n->counts[0]) { ki = 0; } else if (index -= n->counts[0]+1, index <= n->counts[1]) { ki = 1; } else if (index -= n->counts[1]+1, index <= n->counts[2]) { ki = 2; } else if (index -= n->counts[2]+1, index <= n->counts[3]) { ki = 3; } else { assert(0); /* can't happen */ } if (!n->kids[0]) break; /* n is a leaf node; we're here! */ /* * Check to see if we've found our target element. If so, * we must choose a new target (we'll use the old target's * successor, which will be in a leaf), move it into the * place of the old one, continue down to the leaf and * delete the old copy of the new target. */ if (index == n->counts[ki]) { node234 *m; LOG((" found element in internal node, index %d\n", ki)); assert(n->elems[ki]); /* must be a kid _before_ an element */ ki++; index = 0; for (m = n->kids[ki]; m->kids[0]; m = m->kids[0]) continue; LOG((" replacing with element \"%s\" from leaf node %p\n", m->elems[0], m)); retval = n->elems[ki-1]; n->elems[ki-1] = m->elems[0]; } /* * Recurse down to subtree ki. If it has only one element, * we have to do some transformation to start with. */ LOG((" moving to subtree %d\n", ki)); sub = n->kids[ki]; if (!sub->elems[1]) { LOG((" subtree has only one element!\n")); if (ki > 0 && n->kids[ki-1]->elems[1]) { /* * Child ki has only one element, but child * ki-1 has two or more. So we need to move a * subtree from ki-1 to ki. */ trans234_subtree_right(n, ki-1, &ki, &index); } else if (ki < 3 && n->kids[ki+1] && n->kids[ki+1]->elems[1]) { /* * Child ki has only one element, but ki+1 has * two or more. Move a subtree from ki+1 to ki. */ trans234_subtree_left(n, ki+1, &ki, &index); } else { /* * ki is small with only small neighbours. Pick a * neighbour and merge with it. */ trans234_subtree_merge(n, ki>0 ? ki-1 : ki, &ki, &index); sub = n->kids[ki]; if (!n->elems[0]) { /* * The root is empty and needs to be * removed. */ LOG((" shifting root!\n")); t->root = sub; sub->parent = NULL; sfree(n); n = NULL; } } } if (n) n->counts[ki]--; n = sub; } /* * Now n is a leaf node, and ki marks the element number we * want to delete. We've already arranged for the leaf to be * bigger than minimum size, so let's just go to it. */ assert(!n->kids[0]); if (!retval) retval = n->elems[ki]; for (i = ki; i < 2 && n->elems[i+1]; i++) n->elems[i] = n->elems[i+1]; n->elems[i] = NULL; /* * It's just possible that we have reduced the leaf to zero * size. This can only happen if it was the root - so destroy * it and make the tree empty. */ if (!n->elems[0]) { LOG((" removed last element in tree, destroying empty root\n")); assert(n == t->root); sfree(n); t->root = NULL; } return retval; /* finished! */ } void *delpos234(tree234 *t, int index) { if (index < 0 || index >= countnode234(t->root)) return NULL; return delpos234_internal(t, index); } void *del234(tree234 *t, void *e) { int index; if (!findrelpos234(t, e, NULL, REL234_EQ, &index)) return NULL; /* it wasn't in there anyway */ return delpos234_internal(t, index); /* it's there; delete it. */ } /* * Join two subtrees together with a separator element between * them, given their relative height. * * (Height<0 means the left tree is shorter, >0 means the right * tree is shorter, =0 means (duh) they're equal.) * * It is assumed that any checks needed on the ordering criterion * have _already_ been done. * * The value returned in `height' is 0 or 1 depending on whether the * resulting tree is the same height as the original larger one, or * one higher. */ static node234 *join234_internal(node234 *left, void *sep, node234 *right, int *height) { node234 *root, *node; int relht = *height; int ki; LOG((" join: joining %p \"%s\" %p, relative height is %d\n", left, sep, right, relht)); if (relht == 0) { /* * The trees are the same height. Create a new one-element * root containing the separator and pointers to the two * nodes. */ node234 *newroot; newroot = snew(node234); newroot->kids[0] = left; newroot->counts[0] = countnode234(left); newroot->elems[0] = sep; newroot->kids[1] = right; newroot->counts[1] = countnode234(right); newroot->elems[1] = NULL; newroot->kids[2] = NULL; newroot->counts[2] = 0; newroot->elems[2] = NULL; newroot->kids[3] = NULL; newroot->counts[3] = 0; newroot->parent = NULL; if (left) left->parent = newroot; if (right) right->parent = newroot; *height = 1; LOG((" join: same height, brand new root\n")); return newroot; } /* * This now works like the addition algorithm on the larger * tree. We're replacing a single kid pointer with two kid * pointers separated by an element; if that causes the node to * overload, we split it in two, move a separator element up to * the next node, and repeat. */ if (relht < 0) { /* * Left tree is shorter. Search down the right tree to find * the pointer we're inserting at. */ node = root = right; while (++relht < 0) { node = node->kids[0]; } ki = 0; right = node->kids[ki]; } else { /* * Right tree is shorter; search down the left to find the * pointer we're inserting at. */ node = root = left; while (--relht > 0) { if (node->elems[2]) node = node->kids[3]; else if (node->elems[1]) node = node->kids[2]; else node = node->kids[1]; } if (node->elems[2]) ki = 3; else if (node->elems[1]) ki = 2; else ki = 1; left = node->kids[ki]; } /* * Now proceed as for addition. */ *height = add234_insert(left, sep, right, &root, node, ki); return root; } static int height234(tree234 *t) { int level = 0; node234 *n = t->root; while (n) { level++; n = n->kids[0]; } return level; } tree234 *join234(tree234 *t1, tree234 *t2) { int size2 = countnode234(t2->root); if (size2 > 0) { void *element; int relht; if (t1->cmp) { element = index234(t2, 0); element = findrelpos234(t1, element, NULL, REL234_GE, NULL); if (element) return NULL; } element = delpos234(t2, 0); relht = height234(t1) - height234(t2); t1->root = join234_internal(t1->root, element, t2->root, &relht); t2->root = NULL; } return t1; } tree234 *join234r(tree234 *t1, tree234 *t2) { int size1 = countnode234(t1->root); if (size1 > 0) { void *element; int relht; if (t2->cmp) { element = index234(t1, size1-1); element = findrelpos234(t2, element, NULL, REL234_LE, NULL); if (element) return NULL; } element = delpos234(t1, size1-1); relht = height234(t1) - height234(t2); t2->root = join234_internal(t1->root, element, t2->root, &relht); t1->root = NULL; } return t2; } /* * Split out the first elements in a tree and return a * pointer to the root node. Leave the root node of the remainder * in t. */ static node234 *split234_internal(tree234 *t, int index) { node234 *halves[2] = { NULL, NULL }, *n, *sib, *sub; node234 *lparent, *rparent; int ki, pki, i, half, lcount, rcount; n = t->root; LOG(("splitting tree %p at point %d\n", t, index)); /* * Easy special cases. After this we have also dealt completely * with the empty-tree case and we can assume the root exists. */ if (index == 0) /* return nothing */ return NULL; if (index == countnode234(t->root)) { /* return the whole tree */ node234 *ret = t->root; t->root = NULL; return ret; } /* * Search down the tree to find the split point. */ halves[0] = halves[1] = NULL; lparent = rparent = NULL; pki = -1; while (n) { LOG((" node %p: %p/%d \"%s\" %p/%d \"%s\" %p/%d \"%s\" %p/%d index=%d\n", n, n->kids[0], n->counts[0], n->elems[0], n->kids[1], n->counts[1], n->elems[1], n->kids[2], n->counts[2], n->elems[2], n->kids[3], n->counts[3], index)); lcount = index; rcount = countnode234(n) - lcount; if (index <= n->counts[0]) { ki = 0; } else if (index -= n->counts[0]+1, index <= n->counts[1]) { ki = 1; } else if (index -= n->counts[1]+1, index <= n->counts[2]) { ki = 2; } else { index -= n->counts[2]+1; ki = 3; } LOG((" splitting at subtree %d\n", ki)); sub = n->kids[ki]; LOG((" splitting at child index %d\n", ki)); /* * Split the node, put halves[0] on the right of the left * one and halves[1] on the left of the right one, put the * new node pointers in halves[0] and halves[1], and go up * a level. */ sib = snew(node234); for (i = 0; i < 3; i++) { if (i+ki < 3 && n->elems[i+ki]) { sib->elems[i] = n->elems[i+ki]; sib->kids[i+1] = n->kids[i+ki+1]; if (sib->kids[i+1]) sib->kids[i+1]->parent = sib; sib->counts[i+1] = n->counts[i+ki+1]; n->elems[i+ki] = NULL; n->kids[i+ki+1] = NULL; n->counts[i+ki+1] = 0; } else { sib->elems[i] = NULL; sib->kids[i+1] = NULL; sib->counts[i+1] = 0; } } if (lparent) { lparent->kids[pki] = n; lparent->counts[pki] = lcount; n->parent = lparent; rparent->kids[0] = sib; rparent->counts[0] = rcount; sib->parent = rparent; } else { halves[0] = n; n->parent = NULL; halves[1] = sib; sib->parent = NULL; } lparent = n; rparent = sib; pki = ki; LOG((" left node %p: %p/%d \"%s\" %p/%d \"%s\" %p/%d \"%s\" %p/%d\n", n, n->kids[0], n->counts[0], n->elems[0], n->kids[1], n->counts[1], n->elems[1], n->kids[2], n->counts[2], n->elems[2], n->kids[3], n->counts[3])); LOG((" right node %p: %p/%d \"%s\" %p/%d \"%s\" %p/%d \"%s\" %p/%d\n", sib, sib->kids[0], sib->counts[0], sib->elems[0], sib->kids[1], sib->counts[1], sib->elems[1], sib->kids[2], sib->counts[2], sib->elems[2], sib->kids[3], sib->counts[3])); n = sub; } /* * We've come off the bottom here, so we've successfully split * the tree into two equally high subtrees. The only problem is * that some of the nodes down the fault line will be smaller * than the minimum permitted size. (Since this is a 2-3-4 * tree, that means they'll be zero-element one-child nodes.) */ LOG((" fell off bottom, lroot is %p, rroot is %p\n", halves[0], halves[1])); assert(halves[0] != NULL); assert(halves[1] != NULL); lparent->counts[pki] = rparent->counts[0] = 0; lparent->kids[pki] = rparent->kids[0] = NULL; /* * So now we go back down the tree from each of the two roots, * fixing up undersize nodes. */ for (half = 0; half < 2; half++) { /* * Remove the root if it's undersize (it will contain only * one child pointer, so just throw it away and replace it * with its child). This might happen several times. */ while (halves[half] && !halves[half]->elems[0]) { LOG((" root %p is undersize, throwing away\n", halves[half])); halves[half] = halves[half]->kids[0]; sfree(halves[half]->parent); halves[half]->parent = NULL; LOG((" new root is %p\n", halves[half])); } n = halves[half]; while (n) { void (*toward)(node234 *n, int ki, int *k, int *index); int ni, merge; /* * Now we have a potentially undersize node on the * right (if half==0) or left (if half==1). Sort it * out, by merging with a neighbour or by transferring * subtrees over. At this time we must also ensure that * nodes are bigger than minimum, in case we need an * element to merge two nodes below. */ LOG((" node %p: %p/%d \"%s\" %p/%d \"%s\" %p/%d \"%s\" %p/%d\n", n, n->kids[0], n->counts[0], n->elems[0], n->kids[1], n->counts[1], n->elems[1], n->kids[2], n->counts[2], n->elems[2], n->kids[3], n->counts[3])); if (half == 1) { ki = 0; /* the kid we're interested in */ ni = 1; /* the neighbour */ merge = 0; /* for merge: leftmost of the two */ toward = trans234_subtree_left; } else { ki = (n->kids[3] ? 3 : n->kids[2] ? 2 : 1); ni = ki-1; merge = ni; toward = trans234_subtree_right; } sub = n->kids[ki]; if (sub && !sub->elems[1]) { /* * This node is undersized or minimum-size. If we * can merge it with its neighbour, we do so; * otherwise we must be able to transfer subtrees * over to it until it is greater than minimum * size. */ int undersized = (!sub->elems[0]); LOG((" child %d is %ssize\n", ki, undersized ? "under" : "minimum-")); LOG((" neighbour is %s\n", n->kids[ni]->elems[2] ? "large" : n->kids[ni]->elems[1] ? "medium" : "small")); if (!n->kids[ni]->elems[1] || (undersized && !n->kids[ni]->elems[2])) { /* * Neighbour is small, or possibly neighbour is * medium and we are undersize. */ trans234_subtree_merge(n, merge, NULL, NULL); sub = n->kids[merge]; if (!n->elems[0]) { /* * n is empty, and hence must have been the * root and needs to be removed. */ assert(!n->parent); LOG((" shifting root!\n")); halves[half] = sub; halves[half]->parent = NULL; sfree(n); } } else { /* Neighbour is big enough to move trees over. */ toward(n, ni, NULL, NULL); if (undersized) toward(n, ni, NULL, NULL); } } n = sub; } } t->root = halves[1]; return halves[0]; } tree234 *splitpos234(tree234 *t, int index, int before) { tree234 *ret; node234 *n; int count; count = countnode234(t->root); if (index < 0 || index > count) return NULL; /* error */ ret = newtree234(t->cmp); n = split234_internal(t, index); if (before) { /* We want to return the ones before the index. */ ret->root = n; } else { /* * We want to keep the ones before the index and return the * ones after. */ ret->root = t->root; t->root = n; } return ret; } tree234 *split234(tree234 *t, void *e, cmpfn234 cmp, int rel) { int before; int index; assert(rel != REL234_EQ); if (rel == REL234_GT || rel == REL234_GE) { before = 1; rel = (rel == REL234_GT ? REL234_LE : REL234_LT); } else { before = 0; } if (!findrelpos234(t, e, cmp, rel, &index)) index = 0; return splitpos234(t, index+1, before); } static node234 *copynode234(node234 *n, copyfn234 copyfn, void *copyfnstate) { int i; node234 *n2 = snew(node234); for (i = 0; i < 3; i++) { if (n->elems[i] && copyfn) n2->elems[i] = copyfn(copyfnstate, n->elems[i]); else n2->elems[i] = n->elems[i]; } for (i = 0; i < 4; i++) { if (n->kids[i]) { n2->kids[i] = copynode234(n->kids[i], copyfn, copyfnstate); n2->kids[i]->parent = n2; } else { n2->kids[i] = NULL; } n2->counts[i] = n->counts[i]; } return n2; } tree234 *copytree234(tree234 *t, copyfn234 copyfn, void *copyfnstate) { tree234 *t2; t2 = newtree234(t->cmp); if (t->root) { t2->root = copynode234(t->root, copyfn, copyfnstate); t2->root->parent = NULL; } else t2->root = NULL; return t2; } #ifdef TEST /* * Test code for the 2-3-4 tree. This code maintains an alternative * representation of the data in the tree, in an array (using the * obvious and slow insert and delete functions). After each tree * operation, the verify() function is called, which ensures all * the tree properties are preserved: * - node->child->parent always equals node * - tree->root->parent always equals NULL * - number of kids == 0 or number of elements + 1; * - tree has the same depth everywhere * - every node has at least one element * - subtree element counts are accurate * - any NULL kid pointer is accompanied by a zero count * - in a sorted tree: ordering property between elements of a * node and elements of its children is preserved * and also ensures the list represented by the tree is the same * list it should be. (This last check also doubly verifies the * ordering properties, because the `same list it should be' is by * definition correctly ordered. It also ensures all nodes are * distinct, because the enum functions would get caught in a loop * if not.) */ #include #include #define srealloc realloc /* * Error reporting function. */ void error(char *fmt, ...) { va_list ap; printf("ERROR: "); va_start(ap, fmt); vfprintf(stdout, fmt, ap); va_end(ap); printf("\n"); } /* The array representation of the data. */ void **array; int arraylen, arraysize; cmpfn234 cmp; /* The tree representation of the same data. */ tree234 *tree; /* * Routines to provide a diagnostic printout of a tree. Currently * relies on every element in the tree being a one-character string * :-) */ typedef struct { char **levels; } dispctx; int dispnode(node234 *n, int level, dispctx *ctx) { if (level == 0) { int xpos = strlen(ctx->levels[0]); int len; if (n->elems[2]) len = sprintf(ctx->levels[0]+xpos, " %s%s%s", n->elems[0], n->elems[1], n->elems[2]); else if (n->elems[1]) len = sprintf(ctx->levels[0]+xpos, " %s%s", n->elems[0], n->elems[1]); else len = sprintf(ctx->levels[0]+xpos, " %s", n->elems[0]); return xpos + 1 + (len-1) / 2; } else { int xpos[4], nkids; int nodelen, mypos, myleft, x, i; xpos[0] = dispnode(n->kids[0], level-3, ctx); xpos[1] = dispnode(n->kids[1], level-3, ctx); nkids = 2; if (n->kids[2]) { xpos[2] = dispnode(n->kids[2], level-3, ctx); nkids = 3; } if (n->kids[3]) { xpos[3] = dispnode(n->kids[3], level-3, ctx); nkids = 4; } if (nkids == 4) mypos = (xpos[1] + xpos[2]) / 2; else if (nkids == 3) mypos = xpos[1]; else mypos = (xpos[0] + xpos[1]) / 2; nodelen = nkids * 2 - 1; myleft = mypos - ((nodelen-1)/2); assert(myleft >= xpos[0]); assert(myleft + nodelen-1 <= xpos[nkids-1]); x = strlen(ctx->levels[level]); while (x <= xpos[0] && x < myleft) ctx->levels[level][x++] = ' '; while (x < myleft) ctx->levels[level][x++] = '_'; if (nkids==4) x += sprintf(ctx->levels[level]+x, ".%s.%s.%s.", n->elems[0], n->elems[1], n->elems[2]); else if (nkids==3) x += sprintf(ctx->levels[level]+x, ".%s.%s.", n->elems[0], n->elems[1]); else x += sprintf(ctx->levels[level]+x, ".%s.", n->elems[0]); while (x < xpos[nkids-1]) ctx->levels[level][x++] = '_'; ctx->levels[level][x] = '\0'; x = strlen(ctx->levels[level-1]); for (i = 0; i < nkids; i++) { int rpos, pos; rpos = xpos[i]; if (i > 0 && i < nkids-1) pos = myleft + 2*i; else pos = rpos; if (rpos < pos) rpos++; while (x < pos && x < rpos) ctx->levels[level-1][x++] = ' '; if (x == pos) ctx->levels[level-1][x++] = '|'; while (x < pos || x < rpos) ctx->levels[level-1][x++] = '_'; if (x == pos) ctx->levels[level-1][x++] = '|'; } ctx->levels[level-1][x] = '\0'; x = strlen(ctx->levels[level-2]); for (i = 0; i < nkids; i++) { int rpos = xpos[i]; while (x < rpos) ctx->levels[level-2][x++] = ' '; ctx->levels[level-2][x++] = '|'; } ctx->levels[level-2][x] = '\0'; return mypos; } } void disptree(tree234 *t) { dispctx ctx; char *leveldata; int width = count234(t); int ht = height234(t) * 3 - 2; int i; if (!t->root) { printf("[empty tree]\n"); } leveldata = smalloc(ht * (width+2)); ctx.levels = smalloc(ht * sizeof(char *)); for (i = 0; i < ht; i++) { ctx.levels[i] = leveldata + i * (width+2); ctx.levels[i][0] = '\0'; } (void) dispnode(t->root, ht-1, &ctx); for (i = ht; i-- ;) printf("%s\n", ctx.levels[i]); sfree(ctx.levels); sfree(leveldata); } typedef struct { int treedepth; int elemcount; } chkctx; int chknode(chkctx *ctx, int level, node234 *node, void *lowbound, void *highbound) { int nkids, nelems; int i; int count; /* Count the non-NULL kids. */ for (nkids = 0; nkids < 4 && node->kids[nkids]; nkids++); /* Ensure no kids beyond the first NULL are non-NULL. */ for (i = nkids; i < 4; i++) if (node->kids[i]) { error("node %p: nkids=%d but kids[%d] non-NULL", node, nkids, i); } else if (node->counts[i]) { error("node %p: kids[%d] NULL but count[%d]=%d nonzero", node, i, i, node->counts[i]); } /* Count the non-NULL elements. */ for (nelems = 0; nelems < 3 && node->elems[nelems]; nelems++); /* Ensure no elements beyond the first NULL are non-NULL. */ for (i = nelems; i < 3; i++) if (node->elems[i]) { error("node %p: nelems=%d but elems[%d] non-NULL", node, nelems, i); } if (nkids == 0) { /* * If nkids==0, this is a leaf node; verify that the tree * depth is the same everywhere. */ if (ctx->treedepth < 0) ctx->treedepth = level; /* we didn't know the depth yet */ else if (ctx->treedepth != level) error("node %p: leaf at depth %d, previously seen depth %d", node, level, ctx->treedepth); } else { /* * If nkids != 0, then it should be nelems+1, unless nelems * is 0 in which case nkids should also be 0 (and so we * shouldn't be in this condition at all). */ int shouldkids = (nelems ? nelems+1 : 0); if (nkids != shouldkids) { error("node %p: %d elems should mean %d kids but has %d", node, nelems, shouldkids, nkids); } } /* * nelems should be at least 1. */ if (nelems == 0) { error("node %p: no elems", node, nkids); } /* * Add nelems to the running element count of the whole tree. */ ctx->elemcount += nelems; /* * Check ordering property: all elements should be strictly > * lowbound, strictly < highbound, and strictly < each other in * sequence. (lowbound and highbound are NULL at edges of tree * - both NULL at root node - and NULL is considered to be < * everything and > everything. IYSWIM.) */ if (cmp) { for (i = -1; i < nelems; i++) { void *lower = (i == -1 ? lowbound : node->elems[i]); void *higher = (i+1 == nelems ? highbound : node->elems[i+1]); if (lower && higher && cmp(lower, higher) >= 0) { error("node %p: kid comparison [%d=%s,%d=%s] failed", node, i, lower, i+1, higher); } } } /* * Check parent pointers: all non-NULL kids should have a * parent pointer coming back to this node. */ for (i = 0; i < nkids; i++) if (node->kids[i]->parent != node) { error("node %p kid %d: parent ptr is %p not %p", node, i, node->kids[i]->parent, node); } /* * Now (finally!) recurse into subtrees. */ count = nelems; for (i = 0; i < nkids; i++) { void *lower = (i == 0 ? lowbound : node->elems[i-1]); void *higher = (i >= nelems ? highbound : node->elems[i]); int subcount = chknode(ctx, level+1, node->kids[i], lower, higher); if (node->counts[i] != subcount) { error("node %p kid %d: count says %d, subtree really has %d", node, i, node->counts[i], subcount); } count += subcount; } return count; } void verifytree(tree234 *tree, void **array, int arraylen) { chkctx ctx; int i; void *p; ctx.treedepth = -1; /* depth unknown yet */ ctx.elemcount = 0; /* no elements seen yet */ /* * Verify validity of tree properties. */ if (tree->root) { if (tree->root->parent != NULL) error("root->parent is %p should be null", tree->root->parent); chknode(&ctx, 0, tree->root, NULL, NULL); } printf("tree depth: %d\n", ctx.treedepth); /* * Enumerate the tree and ensure it matches up to the array. */ for (i = 0; NULL != (p = index234(tree, i)); i++) { if (i >= arraylen) error("tree contains more than %d elements", arraylen); if (array[i] != p) error("enum at position %d: array says %s, tree says %s", i, array[i], p); } if (ctx.elemcount != i) { error("tree really contains %d elements, enum gave %d", ctx.elemcount, i); } if (i < arraylen) { error("enum gave only %d elements, array has %d", i, arraylen); } i = count234(tree); if (ctx.elemcount != i) { error("tree really contains %d elements, count234 gave %d", ctx.elemcount, i); } } void verify(void) { verifytree(tree, array, arraylen); } void internal_addtest(void *elem, int index, void *realret) { int i, j; void *retval; if (arraysize < arraylen+1) { arraysize = arraylen+1+256; array = (array == NULL ? smalloc(arraysize*sizeof(*array)) : srealloc(array, arraysize*sizeof(*array))); } i = index; /* now i points to the first element >= elem */ retval = elem; /* expect elem returned (success) */ for (j = arraylen; j > i; j--) array[j] = array[j-1]; array[i] = elem; /* add elem to array */ arraylen++; if (realret != retval) { error("add: retval was %p expected %p", realret, retval); } verify(); } void addtest(void *elem) { int i; void *realret; realret = add234(tree, elem); i = 0; while (i < arraylen && cmp(elem, array[i]) > 0) i++; if (i < arraylen && !cmp(elem, array[i])) { void *retval = array[i]; /* expect that returned not elem */ if (realret != retval) { error("add: retval was %p expected %p", realret, retval); } } else internal_addtest(elem, i, realret); } void addpostest(void *elem, int i) { void *realret; realret = addpos234(tree, elem, i); internal_addtest(elem, i, realret); } void delpostest(int i) { int index = i; void *elem = array[i], *ret; /* i points to the right element */ while (i < arraylen-1) { array[i] = array[i+1]; i++; } arraylen--; /* delete elem from array */ if (tree->cmp) ret = del234(tree, elem); else ret = delpos234(tree, index); if (ret != elem) { error("del returned %p, expected %p", ret, elem); } verify(); } void deltest(void *elem) { int i; i = 0; while (i < arraylen && cmp(elem, array[i]) > 0) i++; if (i >= arraylen || cmp(elem, array[i]) != 0) return; /* don't do it! */ delpostest(i); } /* A sample data set and test utility. Designed for pseudo-randomness, * and yet repeatability. */ /* * This random number generator uses the `portable implementation' * given in ANSI C99 draft N869. It assumes `unsigned' is 32 bits; * change it if not. */ int randomnumber(unsigned *seed) { *seed *= 1103515245; *seed += 12345; return ((*seed) / 65536) % 32768; } int mycmp(void *av, void *bv) { char const *a = (char const *)av; char const *b = (char const *)bv; return strcmp(a, b); } char *strings[] = { "0", "2", "3", "I", "K", "d", "H", "J", "Q", "N", "n", "q", "j", "i", "7", "G", "F", "D", "b", "x", "g", "B", "e", "v", "V", "T", "f", "E", "S", "8", "A", "k", "X", "p", "C", "R", "a", "o", "r", "O", "Z", "u", "6", "1", "w", "L", "P", "M", "c", "U", "h", "9", "t", "5", "W", "Y", "m", "s", "l", "4", #if 0 "a", "ab", "absque", "coram", "de", "palam", "clam", "cum", "ex", "e", "sine", "tenus", "pro", "prae", "banana", "carrot", "cabbage", "broccoli", "onion", "zebra", "penguin", "blancmange", "pangolin", "whale", "hedgehog", "giraffe", "peanut", "bungee", "foo", "bar", "baz", "quux", "murfl", "spoo", "breen", "flarn", "octothorpe", "snail", "tiger", "elephant", "octopus", "warthog", "armadillo", "aardvark", "wyvern", "dragon", "elf", "dwarf", "orc", "goblin", "pixie", "basilisk", "warg", "ape", "lizard", "newt", "shopkeeper", "wand", "ring", "amulet" #endif }; #define NSTR lenof(strings) void findtest(void) { static const int rels[] = { REL234_EQ, REL234_GE, REL234_LE, REL234_LT, REL234_GT }; static const char *const relnames[] = { "EQ", "GE", "LE", "LT", "GT" }; int i, j, rel, index; char *p, *ret, *realret, *realret2; int lo, hi, mid, c; for (i = 0; i < (int)NSTR; i++) { p = strings[i]; for (j = 0; j < (int)(sizeof(rels)/sizeof(*rels)); j++) { rel = rels[j]; lo = 0; hi = arraylen-1; while (lo <= hi) { mid = (lo + hi) / 2; c = strcmp(p, array[mid]); if (c < 0) hi = mid-1; else if (c > 0) lo = mid+1; else break; } if (c == 0) { if (rel == REL234_LT) ret = (mid > 0 ? array[--mid] : NULL); else if (rel == REL234_GT) ret = (mid < arraylen-1 ? array[++mid] : NULL); else ret = array[mid]; } else { assert(lo == hi+1); if (rel == REL234_LT || rel == REL234_LE) { mid = hi; ret = (hi >= 0 ? array[hi] : NULL); } else if (rel == REL234_GT || rel == REL234_GE) { mid = lo; ret = (lo < arraylen ? array[lo] : NULL); } else ret = NULL; } realret = findrelpos234(tree, p, NULL, rel, &index); if (realret != ret) { error("find(\"%s\",%s) gave %s should be %s", p, relnames[j], realret, ret); } if (realret && index != mid) { error("find(\"%s\",%s) gave %d should be %d", p, relnames[j], index, mid); } if (realret && rel == REL234_EQ) { realret2 = index234(tree, index); if (realret2 != realret) { error("find(\"%s\",%s) gave %s(%d) but %d -> %s", p, relnames[j], realret, index, index, realret2); } } #if 0 printf("find(\"%s\",%s) gave %s(%d)\n", p, relnames[j], realret, index); #endif } } realret = findrelpos234(tree, NULL, NULL, REL234_GT, &index); if (arraylen && (realret != array[0] || index != 0)) { error("find(NULL,GT) gave %s(%d) should be %s(0)", realret, index, array[0]); } else if (!arraylen && (realret != NULL)) { error("find(NULL,GT) gave %s(%d) should be NULL", realret, index); } realret = findrelpos234(tree, NULL, NULL, REL234_LT, &index); if (arraylen && (realret != array[arraylen-1] || index != arraylen-1)) { error("find(NULL,LT) gave %s(%d) should be %s(0)", realret, index, array[arraylen-1]); } else if (!arraylen && (realret != NULL)) { error("find(NULL,LT) gave %s(%d) should be NULL", realret, index); } } void splittest(tree234 *tree, void **array, int arraylen) { int i; tree234 *tree3, *tree4; for (i = 0; i <= arraylen; i++) { tree3 = copytree234(tree, NULL, NULL); tree4 = splitpos234(tree3, i, 0); verifytree(tree3, array, i); verifytree(tree4, array+i, arraylen-i); join234(tree3, tree4); freetree234(tree4); /* left empty by join */ verifytree(tree3, array, arraylen); freetree234(tree3); } } int main(void) { int in[NSTR]; int i, j, k; int tworoot, tmplen; unsigned seed = 0; tree234 *tree2, *tree3, *tree4; int c; setvbuf(stdout, NULL, _IOLBF, 0); for (i = 0; i < (int)NSTR; i++) in[i] = 0; array = NULL; arraylen = arraysize = 0; tree = newtree234(mycmp); cmp = mycmp; verify(); for (i = 0; i < 10000; i++) { j = randomnumber(&seed); j %= NSTR; printf("trial: %d\n", i); if (in[j]) { printf("deleting %s (%d)\n", strings[j], j); deltest(strings[j]); in[j] = 0; } else { printf("adding %s (%d)\n", strings[j], j); addtest(strings[j]); in[j] = 1; } disptree(tree); findtest(); } while (arraylen > 0) { j = randomnumber(&seed); j %= arraylen; deltest(array[j]); } freetree234(tree); /* * Now try an unsorted tree. We don't really need to test * delpos234 because we know del234 is based on it, so it's * already been tested in the above sorted-tree code; but for * completeness we'll use it to tear down our unsorted tree * once we've built it. */ tree = newtree234(NULL); cmp = NULL; verify(); for (i = 0; i < 1000; i++) { printf("trial: %d\n", i); j = randomnumber(&seed); j %= NSTR; k = randomnumber(&seed); k %= count234(tree)+1; printf("adding string %s at index %d\n", strings[j], k); addpostest(strings[j], k); } /* * While we have this tree in its full form, we'll take a copy * of it to use in split and join testing. */ tree2 = copytree234(tree, NULL, NULL); verifytree(tree2, array, arraylen);/* check the copy is accurate */ /* * Split tests. Split the tree at every possible point and * check the resulting subtrees. */ tworoot = (!tree2->root->elems[1]);/* see if it has a 2-root */ splittest(tree2, array, arraylen); /* * Now do the split test again, but on a tree that has a 2-root * (if the previous one didn't) or doesn't (if the previous one * did). */ tmplen = arraylen; while ((!tree2->root->elems[1]) == tworoot) { delpos234(tree2, --tmplen); } printf("now trying splits on second tree\n"); splittest(tree2, array, tmplen); freetree234(tree2); /* * Back to the main testing of uncounted trees. */ while (count234(tree) > 0) { printf("cleanup: tree size %d\n", count234(tree)); j = randomnumber(&seed); j %= count234(tree); printf("deleting string %s from index %d\n", (char *)array[j], j); delpostest(j); } freetree234(tree); /* * Finally, do some testing on split/join on _sorted_ trees. At * the same time, we'll be testing split on very small trees. */ tree = newtree234(mycmp); cmp = mycmp; arraylen = 0; for (i = 0; i < 17; i++) { tree2 = copytree234(tree, NULL, NULL); splittest(tree2, array, arraylen); freetree234(tree2); if (i < 16) addtest(strings[i]); } freetree234(tree); /* * Test silly cases of join: join(emptytree, emptytree), and * also ensure join correctly spots when sorted trees fail the * ordering constraint. */ tree = newtree234(mycmp); tree2 = newtree234(mycmp); tree3 = newtree234(mycmp); tree4 = newtree234(mycmp); assert(mycmp(strings[0], strings[1]) < 0); /* just in case :-) */ add234(tree2, strings[1]); add234(tree4, strings[0]); array[0] = strings[0]; array[1] = strings[1]; verifytree(tree, array, 0); verifytree(tree2, array+1, 1); verifytree(tree3, array, 0); verifytree(tree4, array, 1); /* * So: * - join(tree,tree3) should leave both tree and tree3 unchanged. * - joinr(tree,tree2) should leave both tree and tree2 unchanged. * - join(tree4,tree3) should leave both tree3 and tree4 unchanged. * - join(tree, tree2) should move the element from tree2 to tree. * - joinr(tree4, tree3) should move the element from tree4 to tree3. * - join(tree,tree3) should return NULL and leave both unchanged. * - join(tree3,tree) should work and create a bigger tree in tree3. */ assert(tree == join234(tree, tree3)); verifytree(tree, array, 0); verifytree(tree3, array, 0); assert(tree2 == join234r(tree, tree2)); verifytree(tree, array, 0); verifytree(tree2, array+1, 1); assert(tree4 == join234(tree4, tree3)); verifytree(tree3, array, 0); verifytree(tree4, array, 1); assert(tree == join234(tree, tree2)); verifytree(tree, array+1, 1); verifytree(tree2, array, 0); assert(tree3 == join234r(tree4, tree3)); verifytree(tree3, array, 1); verifytree(tree4, array, 0); assert(NULL == join234(tree, tree3)); verifytree(tree, array+1, 1); verifytree(tree3, array, 1); assert(tree3 == join234(tree3, tree)); verifytree(tree3, array, 2); verifytree(tree, array, 0); return 0; } #endif #if 0 /* sorted list of strings might be useful */ { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", } #endif puzzles-20170606.272beef/tracks.c0000644000175000017500000024457513115373615015345 0ustar simonsimon/* * Implementation of 'Train Tracks', a puzzle from the Times on Saturday. * * "Lay tracks to enable the train to travel from village A to village B. * The numbers indicate how many sections of rail go in each row and * column. There are only straight rails and curved rails. The track * cannot cross itself." * * Puzzles: * #9 8x8:d9s5c6zgAa,1,4,1,4,4,3,S3,5,2,2,4,S5,3,3,5,1 * #112 8x8:w6x5mAa,1,3,1,4,6,4,S4,3,3,4,5,2,4,2,S5,1 * #113 8x8:gCx5xAf,1,S4,2,5,4,6,2,3,4,2,5,2,S4,4,5,1 * #114 8x8:p5fAzkAb,1,6,3,3,3,S6,2,3,5,4,S3,3,5,1,5,1 * #115 8x8:zi9d5tAb,1,3,4,5,3,S4,2,4,2,6,2,3,6,S3,3,1 */ #include #include #include #include #include #include #include "puzzles.h" /* --- Game parameters --- */ /* * Difficulty levels. I do some macro ickery here to ensure that my * enum and the various forms of my name list always match up. */ #define DIFFLIST(A) \ A(EASY,Easy,e) \ A(TRICKY,Tricky,t) #define ENUM(upper,title,lower) DIFF_ ## upper, #define TITLE(upper,title,lower) #title, #define ENCODE(upper,title,lower) #lower #define CONFIG(upper,title,lower) ":" #title enum { DIFFLIST(ENUM) DIFFCOUNT }; static char const *const tracks_diffnames[] = { DIFFLIST(TITLE) }; static char const tracks_diffchars[] = DIFFLIST(ENCODE); #define DIFFCONFIG DIFFLIST(CONFIG) struct game_params { int w, h, diff, single_ones; }; static game_params *default_params(void) { game_params *ret = snew(game_params); ret->w = ret->h = 8; ret->diff = DIFF_TRICKY; ret->single_ones = TRUE; return ret; } static const struct game_params tracks_presets[] = { {8, 8, DIFF_EASY, 1}, {8, 8, DIFF_TRICKY, 1}, {10, 8, DIFF_EASY, 1}, {10, 8, DIFF_TRICKY, 1 }, {10, 10, DIFF_EASY, 1}, {10, 10, DIFF_TRICKY, 1}, {15, 10, DIFF_EASY, 1}, {15, 10, DIFF_TRICKY, 1}, {15, 15, DIFF_EASY, 1}, {15, 15, DIFF_TRICKY, 1}, }; static int game_fetch_preset(int i, char **name, game_params **params) { game_params *ret; char str[80]; if (i < 0 || i >= lenof(tracks_presets)) return FALSE; ret = snew(game_params); *ret = tracks_presets[i]; sprintf(str, "%dx%d %s", ret->w, ret->h, tracks_diffnames[ret->diff]); *name = dupstr(str); *params = ret; return TRUE; } static void free_params(game_params *params) { sfree(params); } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } static void decode_params(game_params *params, char const *string) { params->w = params->h = atoi(string); while (*string && isdigit((unsigned char)*string)) string++; if (*string == 'x') { string++; params->h = atoi(string); while (*string && isdigit((unsigned char)*string)) string++; } if (*string == 'd') { int i; string++; params->diff = DIFF_TRICKY; for (i = 0; i < DIFFCOUNT; i++) if (*string == tracks_diffchars[i]) params->diff = i; if (*string) string++; } params->single_ones = TRUE; if (*string == 'o') { params->single_ones = FALSE; string++; } } static char *encode_params(const game_params *params, int full) { char buf[120]; sprintf(buf, "%dx%d", params->w, params->h); if (full) sprintf(buf + strlen(buf), "d%c%s", tracks_diffchars[params->diff], params->single_ones ? "" : "o"); return dupstr(buf); } static config_item *game_configure(const game_params *params) { config_item *ret; char buf[80]; ret = snewn(5, config_item); ret[0].name = "Width"; ret[0].type = C_STRING; sprintf(buf, "%d", params->w); ret[0].sval = dupstr(buf); ret[0].ival = 0; ret[1].name = "Height"; ret[1].type = C_STRING; sprintf(buf, "%d", params->h); ret[1].sval = dupstr(buf); ret[1].ival = 0; ret[2].name = "Difficulty"; ret[2].type = C_CHOICES; ret[2].sval = DIFFCONFIG; ret[2].ival = params->diff; ret[3].name = "Disallow consecutive 1 clues"; ret[3].type = C_BOOLEAN; ret[3].ival = params->single_ones; ret[4].name = NULL; ret[4].type = C_END; ret[4].sval = NULL; ret[4].ival = 0; return ret; } static game_params *custom_params(const config_item *cfg) { game_params *ret = snew(game_params); ret->w = atoi(cfg[0].sval); ret->h = atoi(cfg[1].sval); ret->diff = cfg[2].ival; ret->single_ones = cfg[3].ival; return ret; } static char *validate_params(const game_params *params, int full) { /* * Generating anything under 4x4 runs into trouble of one kind * or another. */ if (params->w < 4 || params->h < 4) return "Width and height must both be at least four"; return NULL; } /* --- Game state --- */ /* flag usage copied from pearl */ #define R 1 #define U 2 #define L 4 #define D 8 #define MOVECHAR(m) ((m==R)?'R':(m==U)?'U':(m==L)?'L':(m==D)?'D':'?') #define DX(d) ( ((d)==R) - ((d)==L) ) #define DY(d) ( ((d)==D) - ((d)==U) ) #define F(d) (((d << 2) | (d >> 2)) & 0xF) #define C(d) (((d << 3) | (d >> 1)) & 0xF) #define A(d) (((d << 1) | (d >> 3)) & 0xF) #define LR (L | R) #define RL (R | L) #define UD (U | D) #define DU (D | U) #define LU (L | U) #define UL (U | L) #define LD (L | D) #define DL (D | L) #define RU (R | U) #define UR (U | R) #define RD (R | D) #define DR (D | R) #define ALLDIR 15 #define BLANK 0 #define UNKNOWN 15 int nbits[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 }; /* square grid flags */ #define S_TRACK 1 /* a track passes through this square (--> 2 edges) */ #define S_NOTRACK 2 /* no track passes through this square */ #define S_ERROR 4 #define S_CLUE 8 #define S_MARK 16 #define S_TRACK_SHIFT 16 /* U/D/L/R flags for edge track indicators */ #define S_NOTRACK_SHIFT 20 /* U/D/L/R flags for edge no-track indicators */ /* edge grid flags */ #define E_TRACK 1 /* a track passes through this edge */ #define E_NOTRACK 2 /* no track passes through this edge */ struct numbers { int refcount; int *numbers; /* sz w+h */ int row_s, col_s; /* stations: TODO think about multiple lines (for bigger grids)? */ }; #define INGRID(state, gx, gy) ((gx) >= 0 && (gx) < (state)->p.w && \ (gy) >= 0 && (gy) < (state)->p.h) struct game_state { game_params p; unsigned int *sflags; /* size w*h */ struct numbers *numbers; int *num_errors; /* size w+h */ int completed, used_solve, impossible; }; /* Return the four directions in which a particular edge flag is set, around a square. */ int S_E_DIRS(const game_state *state, int sx, int sy, unsigned int eflag) { return (state->sflags[sy*state->p.w+sx] >> ((eflag == E_TRACK) ? S_TRACK_SHIFT : S_NOTRACK_SHIFT)) & ALLDIR; } /* Count the number of a particular edge flag around a grid square. */ int S_E_COUNT(const game_state *state, int sx, int sy, unsigned int eflag) { return nbits[S_E_DIRS(state, sx, sy, eflag)]; } /* Return the two flags (E_TRACK and/or E_NOTRACK) set on a specific * edge of a square. */ unsigned S_E_FLAGS(const game_state *state, int sx, int sy, int d) { unsigned f = state->sflags[sy*state->p.w+sx]; int t = (f & (d << S_TRACK_SHIFT)), nt = (f & (d << S_NOTRACK_SHIFT)); return (t ? E_TRACK : 0) | (nt ? E_NOTRACK : 0); } int S_E_ADJ(const game_state *state, int sx, int sy, int d, int *ax, int *ay, unsigned int *ad) { if (d == L && sx > 0) { *ax = sx-1; *ay = sy; *ad = R; return 1; } if (d == R && sx < state->p.w-1) { *ax = sx+1; *ay = sy; *ad = L; return 1; } if (d == U && sy > 0) { *ax = sx; *ay = sy-1; *ad = D; return 1; } if (d == D && sy < state->p.h-1) { *ax = sx; *ay = sy+1; *ad = U; return 1; } return 0; } /* Sets flag (E_TRACK or E_NOTRACK) on a given edge of a square. */ void S_E_SET(game_state *state, int sx, int sy, int d, unsigned int eflag) { unsigned shift = (eflag == E_TRACK) ? S_TRACK_SHIFT : S_NOTRACK_SHIFT, ad; int ax, ay; state->sflags[sy*state->p.w+sx] |= (d << shift); if (S_E_ADJ(state, sx, sy, d, &ax, &ay, &ad)) { state->sflags[ay*state->p.w+ax] |= (ad << shift); } } /* Clears flag (E_TRACK or E_NOTRACK) on a given edge of a square. */ void S_E_CLEAR(game_state *state, int sx, int sy, int d, unsigned int eflag) { unsigned shift = (eflag == E_TRACK) ? S_TRACK_SHIFT : S_NOTRACK_SHIFT, ad; int ax, ay; state->sflags[sy*state->p.w+sx] &= ~(d << shift); if (S_E_ADJ(state, sx, sy, d, &ax, &ay, &ad)) { state->sflags[ay*state->p.w+ax] &= ~(ad << shift); } } static void clear_game(game_state *state) { int w = state->p.w, h = state->p.h; memset(state->sflags, 0, w*h * sizeof(unsigned int)); memset(state->numbers->numbers, 0, (w+h) * sizeof(int)); state->numbers->col_s = state->numbers->row_s = -1; memset(state->num_errors, 0, (w+h) * sizeof(int)); state->completed = state->used_solve = state->impossible = FALSE; } static game_state *blank_game(const game_params *params) { game_state *state = snew(game_state); int w = params->w, h = params->h; state->p = *params; state->sflags = snewn(w*h, unsigned int); state->numbers = snew(struct numbers); state->numbers->refcount = 1; state->numbers->numbers = snewn(w+h, int); state->num_errors = snewn(w+h, int); clear_game(state); return state; } static void copy_game_flags(const game_state *src, game_state *dest) { int w = src->p.w, h = src->p.h; memcpy(dest->sflags, src->sflags, w*h*sizeof(unsigned int)); } static game_state *dup_game(const game_state *state) { int w = state->p.w, h = state->p.h; game_state *ret = snew(game_state); ret->p = state->p; /* structure copy */ ret->sflags = snewn(w*h, unsigned int); copy_game_flags(state, ret); ret->numbers = state->numbers; state->numbers->refcount++; ret->num_errors = snewn(w+h, int); memcpy(ret->num_errors, state->num_errors, (w+h)*sizeof(int)); ret->completed = state->completed; ret->used_solve = state->used_solve; ret->impossible = state->impossible; return ret; } static void free_game(game_state *state) { if (--state->numbers->refcount <= 0) { sfree(state->numbers->numbers); sfree(state->numbers); } sfree(state->num_errors); sfree(state->sflags); sfree(state); } #define NDIRS 4 const unsigned int dirs_const[] = { U, D, L, R }; static unsigned int find_direction(game_state *state, random_state *rs, int x, int y) { int i, nx, ny, w=state->p.w, h=state->p.h; unsigned int dirs[NDIRS]; memcpy(dirs, dirs_const, sizeof(dirs)); shuffle(dirs, NDIRS, sizeof(*dirs), rs); for (i = 0; i < NDIRS; i++) { nx = x + DX(dirs[i]); ny = y + DY(dirs[i]); if (nx >= 0 && nx < w && ny == h) { /* off the bottom of the board: we've finished the path. */ return dirs[i]; } else if (!INGRID(state, nx, ny)) { /* off the board: can't move here */ continue; } else if (S_E_COUNT(state, nx, ny, E_TRACK) > 0) { /* already tracks here: can't move */ continue; } return dirs[i]; } return 0; /* no possible directions left. */ } static int check_completion(game_state *state, int mark); static void lay_path(game_state *state, random_state *rs) { int px, py, w=state->p.w, h=state->p.h; unsigned int d; start: clear_game(state); /* pick a random entry point, lay its left edge */ state->numbers->row_s = py = random_upto(rs, h); px = 0; S_E_SET(state, px, py, L, E_TRACK); while (INGRID(state, px, py)) { d = find_direction(state, rs, px, py); if (d == 0) goto start; /* nowhere else to go, restart */ S_E_SET(state, px, py, d, E_TRACK); px += DX(d); py += DY(d); } /* double-check we got to the right place */ assert(px >= 0 && px < w && py == h); state->numbers->col_s = px; } static int tracks_solve(game_state *state, int diff); static void debug_state(game_state *state, const char *what); /* Clue-setting algorithm: - first lay clues randomly until it's soluble - then remove clues randomly if removing them doesn't affect solubility - We start with two clues, one at each path entrance. More details: - start with an array of all square i positions - if the grid is already soluble by a level easier than we've requested, go back and make a new grid - if the grid is already soluble by our requested difficulty level, skip the clue-laying step - count the number of flags the solver managed to place, remember this. - to lay clues: - shuffle the i positions - for each possible clue position: - copy the solved board, strip it - take the next position, add a clue there on the copy - try and solve the copy - if it's soluble by a level easier than we've requested, continue (on to next clue position: putting a clue here makes it too easy) - if it's soluble by our difficulty level, we're done: - put the clue flag into the solved board - go to strip-clues. - if the solver didn't manage to place any more flags, continue (on to next clue position: putting a clue here didn't help he solver) - otherwise put the clue flag in the original board, and go on to the next clue position - if we get here and we've not solved it yet, we never will (did we really fill _all_ the clues in?!). Go back and make a new grid. - to strip clues: - shuffle the i positions - for each possible clue position: - if the solved grid doesn't have a clue here, skip - copy the solved board, remove this clue, strip it - try and solve the copy - assert that it is not soluble by a level easier than we've requested - (because this should never happen) - if this is (still) soluble by our difficulty level: - remove this clue from the solved board, it's redundant (with the other clues) - that should be it. */ static game_state *copy_and_strip(const game_state *state, game_state *ret, int flipcluei) { int i, j, w = state->p.w, h = state->p.h; copy_game_flags(state, ret); /* Add/remove a clue before stripping, if required */ if (flipcluei != -1) ret->sflags[flipcluei] ^= S_CLUE; /* All squares that are not clue squares have square track info erased, and some edge flags.. */ for (i = 0; i < w*h; i++) { if (!(ret->sflags[i] & S_CLUE)) { ret->sflags[i] &= ~(S_TRACK|S_NOTRACK|S_ERROR|S_MARK); for (j = 0; j < 4; j++) { unsigned f = 1<sflags[yy*w+xx] & S_CLUE)) { /* only erase an edge flag if neither side of the edge is S_CLUE. */ S_E_CLEAR(ret, i%w, i/w, f, E_TRACK); S_E_CLEAR(ret, i%w, i/w, f, E_NOTRACK); } } } } return ret; } static int solve_progress(const game_state *state) { int i, w = state->p.w, h = state->p.h, progress = 0; /* Work out how many flags the solver managed to set (either TRACK or NOTRACK) and return this as a progress measure, to check whether a partially-solved board gets any further than a previous partially- solved board. */ for (i = 0; i < w*h; i++) { if (state->sflags[i] & S_TRACK) progress++; if (state->sflags[i] & S_NOTRACK) progress++; progress += S_E_COUNT(state, i%w, i/w, E_TRACK); progress += S_E_COUNT(state, i%w, i/w, E_NOTRACK); } return progress; } static int check_phantom_moves(const game_state *state) { int x, y, i; /* Check that this state won't show 'phantom moves' at the start of the * game: squares which have multiple edge flags set but no clue flag * cause a piece of track to appear that isn't on a clue square. */ for (x = 0; x < state->p.w; x++) { for (y = 0; y < state->p.h; y++) { i = y*state->p.w+x; if (state->sflags[i] & S_CLUE) continue; if (S_E_COUNT(state, x, y, E_TRACK) > 1) return 1; /* found one! */ } } return 0; } static int add_clues(game_state *state, random_state *rs, int diff) { int i, j, pi, w = state->p.w, h = state->p.h, progress, ret = 0, sr; int *positions = snewn(w*h, int), npositions = 0; int *nedges_previous_solve = snewn(w*h, int); game_state *scratch = dup_game(state); debug_state(state, "gen: Initial board"); debug(("gen: Adding clues...")); /* set up the shuffly-position grid for later, used for adding clues: * we only bother adding clues where any edges are set. */ for (i = 0; i < w*h; i++) { if (S_E_DIRS(state, i%w, i/w, E_TRACK) != 0) { positions[npositions++] = i; } nedges_previous_solve[i] = 0; } /* First, check whether the puzzle is already either too easy, or just right */ scratch = copy_and_strip(state, scratch, -1); if (diff > 0) { sr = tracks_solve(scratch, diff-1); if (sr < 0) assert(!"Generator should not have created impossible puzzle"); if (sr > 0) { ret = -1; /* already too easy, even without adding clues. */ debug(("gen: ...already too easy, need new board.")); goto done; } } sr = tracks_solve(scratch, diff); if (sr < 0) assert(!"Generator should not have created impossible puzzle"); if (sr > 0) { ret = 1; /* already soluble without any extra clues. */ debug(("gen: ...soluble without clues, nothing to do.")); goto done; } debug_state(scratch, "gen: Initial part-solved state: "); progress = solve_progress(scratch); debug(("gen: Initial solve progress is %d", progress)); /* First, lay clues until we're soluble. */ shuffle(positions, npositions, sizeof(int), rs); for (pi = 0; pi < npositions; pi++) { i = positions[pi]; /* pick a random position */ if (state->sflags[i] & S_CLUE) continue; /* already a clue here (entrance location?) */ if (nedges_previous_solve[i] == 2) continue; /* no point putting a clue here, we could solve both edges with the previous set of clues */ /* set a clue in that position (on a copy of the board) and test solubility */ scratch = copy_and_strip(state, scratch, i); if (check_phantom_moves(scratch)) continue; /* adding a clue here would add phantom track */ if (diff > 0) { if (tracks_solve(scratch, diff-1) > 0) { continue; /* adding a clue here makes it too easy */ } } if (tracks_solve(scratch, diff) > 0) { /* we're now soluble (and we weren't before): add this clue, and then start stripping clues */ debug(("gen: ...adding clue at (%d,%d), now soluble", i%w, i/w)); state->sflags[i] |= S_CLUE; goto strip_clues; } if (solve_progress(scratch) > progress) { /* We've made more progress solving: add this clue, then. */ progress = solve_progress(scratch); debug(("gen: ... adding clue at (%d,%d), new progress %d", i%w, i/w, progress)); state->sflags[i] |= S_CLUE; for (j = 0; j < w*h; j++) nedges_previous_solve[j] = S_E_COUNT(scratch, j%w, j/w, E_TRACK); } } /* If we got here we didn't ever manage to make the puzzle soluble (without making it too easily soluble, that is): give up. */ debug(("gen: Unable to make soluble with clues, need new board.")); ret = -1; goto done; strip_clues: debug(("gen: Stripping clues.")); /* Now, strip redundant clues (i.e. those without which the puzzle is still soluble) */ shuffle(positions, npositions, sizeof(int), rs); for (pi = 0; pi < npositions; pi++) { i = positions[pi]; /* pick a random position */ if (!(state->sflags[i] & S_CLUE)) continue; /* no clue here to strip */ if ((i%w == 0 && i/w == state->numbers->row_s) || (i/w == (h-1) && i%w == state->numbers->col_s)) continue; /* don't strip clues at entrance/exit */ scratch = copy_and_strip(state, scratch, i); if (check_phantom_moves(scratch)) continue; /* removing a clue here would add phantom track */ if (tracks_solve(scratch, diff) > 0) { debug(("gen: ... removing clue at (%d,%d), still soluble without it", i%w, i/w)); state->sflags[i] &= ~S_CLUE; /* still soluble without this clue. */ } } debug(("gen: Finished stripping clues.")); ret = 1; done: sfree(positions); free_game(scratch); return ret; } static char *new_game_desc(const game_params *params, random_state *rs, char **aux, int interactive) { int i, j, w = params->w, h = params->h, x, y, ret; game_state *state; char *desc, *p; game_params adjusted_params; /* * 4x4 Tricky cannot be generated, so fall back to Easy. */ if (w == 4 && h == 4 && params->diff > DIFF_EASY) { adjusted_params = *params; /* structure copy */ adjusted_params.diff = DIFF_EASY; params = &adjusted_params; } state = blank_game(params); /* --- lay the random path */ newpath: lay_path(state, rs); for (x = 0; x < w; x++) { for (y = 0; y < h; y++) { if (S_E_COUNT(state, x, y, E_TRACK) > 0) { state->sflags[y*w + x] |= S_TRACK; } if ((x == 0 && y == state->numbers->row_s) || (y == (h-1) && x == state->numbers->col_s)) { state->sflags[y*w + x] |= S_CLUE; } } } /* --- Update the clue numbers based on the tracks we have generated. */ for (x = 0; x < w; x++) { for (y = 0; y < h; y++) { if (state->sflags[y*w + x] & S_TRACK) { state->numbers->numbers[x]++; state->numbers->numbers[y+w]++; } } } for (i = 0; i < w+h; i++) { if (state->numbers->numbers[i] == 0) goto newpath; /* too boring */ } if (params->single_ones) { int last_was_one = 1, is_one; /* (disallow 1 clue at entry point) */ for (i = 0; i < w+h; i++) { is_one = (state->numbers->numbers[i] == 1); if (is_one && last_was_one) goto newpath; /* disallow consecutive 1 clues. */ last_was_one = is_one; } if (state->numbers->numbers[w+h-1] == 1) goto newpath; /* (disallow 1 clue at exit point) */ } /* --- Add clues to make a soluble puzzle */ ret = add_clues(state, rs, params->diff); if (ret != 1) goto newpath; /* couldn't make it soluble, or too easy */ /* --- Generate the game desc based on the generated grid. */ desc = snewn(w*h*3 + (w+h)*5, char); for (i = j = 0; i < w*h; i++) { if (!(state->sflags[i] & S_CLUE) && j > 0 && desc[j-1] >= 'a' && desc[j-1] < 'z') desc[j-1]++; else if (!(state->sflags[i] & S_CLUE)) desc[j++] = 'a'; else { unsigned int f = S_E_DIRS(state, i%w, i/w, E_TRACK); desc[j++] = (f < 10) ? ('0' + f) : ('A' + (f-10)); } } p = desc + j; for (x = 0; x < w; x++) { p += sprintf(p, ",%s%d", x == state->numbers->col_s ? "S" : "", state->numbers->numbers[x]); } for (y = 0; y < h; y++) { p += sprintf(p, ",%s%d", y == state->numbers->row_s ? "S" : "", state->numbers->numbers[y+w]); } *p++ = '\0'; ret = tracks_solve(state, DIFFCOUNT); assert(ret >= 0); free_game(state); debug(("new_game_desc: %s", desc)); return desc; } static char *validate_desc(const game_params *params, const char *desc) { int i = 0, w = params->w, h = params->h, in = 0, out = 0; while (*desc) { unsigned int f = 0; if (*desc >= '0' && *desc <= '9') f = (*desc - '0'); else if (*desc >= 'A' && *desc <= 'F') f = (*desc - 'A' + 10); else if (*desc >= 'a' && *desc <= 'z') i += *desc - 'a'; else return "Game description contained unexpected characters"; if (f != 0) { if (nbits[f] != 2) return "Clue did not provide 2 direction flags"; } i++; desc++; if (i == w*h) break; } for (i = 0; i < w+h; i++) { if (!*desc) return "Not enough numbers given after grid specification"; else if (*desc != ',') return "Invalid character in number list"; desc++; if (*desc == 'S') { if (i < w) out++; else in++; desc++; } while (*desc && isdigit((unsigned char)*desc)) desc++; } if (in != 1 || out != 1) return "Puzzle must have one entrance and one exit"; if (*desc) return "Unexpected additional character at end of game description"; return NULL; } static game_state *new_game(midend *me, const game_params *params, const char *desc) { game_state *state = blank_game(params); int w = params->w, h = params->h, i = 0; while (*desc) { unsigned int f = 0; if (*desc >= '0' && *desc <= '9') f = (*desc - '0'); else if (*desc >= 'A' && *desc <= 'F') f = (*desc - 'A' + 10); else if (*desc >= 'a' && *desc <= 'z') i += *desc - 'a'; if (f != 0) { int x = i % w, y = i / w; assert(f < 16); assert(nbits[f] == 2); state->sflags[i] |= (S_TRACK | S_CLUE); if (f & U) S_E_SET(state, x, y, U, E_TRACK); if (f & D) S_E_SET(state, x, y, D, E_TRACK); if (f & L) S_E_SET(state, x, y, L, E_TRACK); if (f & R) S_E_SET(state, x, y, R, E_TRACK); } i++; desc++; if (i == w*h) break; } for (i = 0; i < w+h; i++) { assert(*desc == ','); desc++; if (*desc == 'S') { if (i < w) state->numbers->col_s = i; else state->numbers->row_s = i-w; desc++; } state->numbers->numbers[i] = atoi(desc); while (*desc && isdigit((unsigned char)*desc)) desc++; } assert(!*desc); return state; } static int solve_set_sflag(game_state *state, int x, int y, unsigned int f, const char *why) { int w = state->p.w, i = y*w + x; if (state->sflags[i] & f) return 0; debug(("solve: square (%d,%d) -> %s: %s", x, y, (f == S_TRACK ? "TRACK" : "NOTRACK"), why)); if (state->sflags[i] & (f == S_TRACK ? S_NOTRACK : S_TRACK)) { debug(("solve: opposite flag already set there, marking IMPOSSIBLE")); state->impossible = TRUE; } state->sflags[i] |= f; return 1; } static int solve_set_eflag(game_state *state, int x, int y, int d, unsigned int f, const char *why) { int sf = S_E_FLAGS(state, x, y, d); if (sf & f) return 0; debug(("solve: edge (%d,%d)/%c -> %s: %s", x, y, (d == U) ? 'U' : (d == D) ? 'D' : (d == L) ? 'L' : 'R', (f == S_TRACK ? "TRACK" : "NOTRACK"), why)); if (sf & (f == E_TRACK ? E_NOTRACK : E_TRACK)) { debug(("solve: opposite flag already set there, marking IMPOSSIBLE")); state->impossible = TRUE; } S_E_SET(state, x, y, d, f); return 1; } static int solve_update_flags(game_state *state) { int x, y, i, w = state->p.w, h = state->p.h, did = 0; for (x = 0; x < w; x++) { for (y = 0; y < h; y++) { /* If a square is NOTRACK, all four edges must be. */ if (state->sflags[y*w + x] & S_NOTRACK) { for (i = 0; i < 4; i++) { unsigned int d = 1<= 3) { did += solve_set_sflag(state, x, y, S_NOTRACK, "square has >2 NOTRACK edges"); } /* If any edge around a square is TRACK, the square is. */ if (S_E_COUNT(state, x, y, E_TRACK) > 0) { did += solve_set_sflag(state, x, y, S_TRACK, "square has TRACK edge"); } /* If a square is TRACK and 2 edges are NOTRACK, the other two edges must be TRACK. */ if ((state->sflags[y*w + x] & S_TRACK) && (S_E_COUNT(state, x, y, E_NOTRACK) == 2) && (S_E_COUNT(state, x, y, E_TRACK) < 2)) { for (i = 0; i < 4; i++) { unsigned int d = 1<sflags[y*w + x] & S_TRACK) && (S_E_COUNT(state, x, y, E_TRACK) == 2) && (S_E_COUNT(state, x, y, E_NOTRACK) < 2)) { for (i = 0; i < 4; i++) { unsigned int d = 1<p.h, w = state->p.w; for (n = 0, i = col; n < h; n++, i += w) { if (state->sflags[i] & f) c++; } return c; } static int solve_count_row(game_state *state, int row, unsigned int f) { int i, n, c = 0, w = state->p.w; for (n = 0, i = w*row; n < state->p.w; n++, i++) { if (state->sflags[i] & f) c++; } return c; } static int solve_count_clues_sub(game_state *state, int si, int id, int n, int target, const char *what) { int ctrack = 0, cnotrack = 0, did = 0, j, i, w = state->p.w; for (j = 0, i = si; j < n; j++, i += id) { if (state->sflags[i] & S_TRACK) ctrack++; if (state->sflags[i] & S_NOTRACK) cnotrack++; } if (ctrack == target) { /* everything that's not S_TRACK must be S_NOTRACK. */ for (j = 0, i = si; j < n; j++, i += id) { if (!(state->sflags[i] & S_TRACK)) did += solve_set_sflag(state, i%w, i/w, S_NOTRACK, what); } } if (cnotrack == (n-target)) { /* everything that's not S_NOTRACK must be S_TRACK. */ for (j = 0, i = si; j < n; j++, i += id) { if (!(state->sflags[i] & S_NOTRACK)) did += solve_set_sflag(state, i%w, i/w, S_TRACK, what); } } return did; } static int solve_count_clues(game_state *state) { int w = state->p.w, h = state->p.h, x, y, target, did = 0; for (x = 0; x < w; x++) { target = state->numbers->numbers[x]; did += solve_count_clues_sub(state, x, w, h, target, "col count"); } for (y = 0; y < h; y++) { target = state->numbers->numbers[w+y]; did += solve_count_clues_sub(state, y*w, 1, w, target, "row count"); } return did; } static int solve_check_single_sub(game_state *state, int si, int id, int n, int target, unsigned int perpf, const char *what) { int ctrack = 0, nperp = 0, did = 0, j, i, w = state->p.w; int n1edge = 0, i1edge = 0, ox, oy, x, y; unsigned int impossible = 0; /* For rows or columns which only have one more square to put a track in, we know the only way a new track section could be there would be to run perpendicular to the track (otherwise we'd need at least two free squares). So, if there is nowhere we can run perpendicular to the track (e.g. because we're on an edge) we know the extra track section much be on one end of an existing section. */ for (j = 0, i = si; j < n; j++, i += id) { if (state->sflags[i] & S_TRACK) ctrack++; impossible = S_E_DIRS(state, i%w, i/w, E_NOTRACK); if ((perpf & impossible) == 0) nperp++; if (S_E_COUNT(state, i%w, i/w, E_TRACK) <= 1) { n1edge++; i1edge = i; } } if (ctrack != (target-1)) return 0; if (nperp > 0 || n1edge != 1) return 0; debug(("check_single from (%d,%d): 1 match from (%d,%d)", si%w, si/w, i1edge%w, i1edge/w)); /* We have a match: anything that's more than 1 away from this square cannot now contain a track. */ ox = i1edge%w; oy = i1edge/w; for (j = 0, i = si; j < n; j++, i += id) { x = i%w; y = i/w; if (abs(ox-x) > 1 || abs(oy-y) > 1) { if (!(state->sflags[i] & S_TRACK)) did += solve_set_sflag(state, x, y, S_NOTRACK, what); } } return did; } static int solve_check_single(game_state *state) { int w = state->p.w, h = state->p.h, x, y, target, did = 0; for (x = 0; x < w; x++) { target = state->numbers->numbers[x]; did += solve_check_single_sub(state, x, w, h, target, R|L, "single on col"); } for (y = 0; y < h; y++) { target = state->numbers->numbers[w+y]; did += solve_check_single_sub(state, y*w, 1, w, target, U|D, "single on row"); } return did; } static int solve_check_loose_sub(game_state *state, int si, int id, int n, int target, unsigned int perpf, const char *what) { int nperp = 0, nloose = 0, e2count = 0, did = 0, i, j, k; int w = state->p.w; unsigned int parf = ALLDIR & (~perpf); for (j = 0, i = si; j < n; j++, i += id) { int fcount = S_E_COUNT(state, i%w, i/w, E_TRACK); if (fcount == 2) e2count++; /* this cell has 2 definite edges */ state->sflags[i] &= ~S_MARK; if (fcount == 1 && (parf & S_E_DIRS(state, i%w, i/w, E_TRACK))) { nloose++; /* this cell has a loose end (single flag set parallel to the direction of this row/column) */ state->sflags[i] |= S_MARK; /* mark loose ends */ } if (fcount != 2 && !(perpf & S_E_DIRS(state, i%w, i/w, E_NOTRACK))) nperp++; /* we could lay perpendicular across this cell */ } if (nloose > (target - e2count)) { debug(("check %s from (%d,%d): more loose (%d) than empty (%d), IMPOSSIBLE", what, si%w, si/w, nloose, target-e2count)); state->impossible = TRUE; } if (nloose > 0 && nloose == (target - e2count)) { debug(("check %s from (%d,%d): nloose = empty (%d), forcing loners out.", what, si%w, si/w, nloose)); for (j = 0, i = si; j < n; j++, i += id) { if (!(state->sflags[i] & S_MARK)) continue; /* skip non-loose ends */ if (j > 0 && state->sflags[i-id] & S_MARK) continue; /* next to other loose end, could join up */ if (j < (n-1) && state->sflags[i+id] & S_MARK) continue; /* ditto */ for (k = 0; k < 4; k++) { if ((parf & (1<sflags[i] & S_MARK)) continue; /* skip non-loose ends */ for (k = 0; k < 4; k++) { if (parf & (1<p.w, h = state->p.h, x, y, target, did = 0; for (x = 0; x < w; x++) { target = state->numbers->numbers[x]; did += solve_check_loose_sub(state, x, w, h, target, R|L, "loose on col"); } for (y = 0; y < h; y++) { target = state->numbers->numbers[w+y]; did += solve_check_loose_sub(state, y*w, 1, w, target, U|D, "loose on row"); } return did; } static int solve_check_loop_sub(game_state *state, int x, int y, int dir, int *dsf, int startc, int endc) { int w = state->p.w, h = state->p.h, i = y*w+x, j, k, satisfied = 1; j = (y+DY(dir))*w + (x+DX(dir)); assert(i < w*h && j < w*h); if ((state->sflags[i] & S_TRACK) && (state->sflags[j] & S_TRACK) && !(S_E_DIRS(state, x, y, E_TRACK) & dir) && !(S_E_DIRS(state, x, y, E_NOTRACK) & dir)) { int ic = dsf_canonify(dsf, i), jc = dsf_canonify(dsf, j); if (ic == jc) { return solve_set_eflag(state, x, y, dir, E_NOTRACK, "would close loop"); } if ((ic == startc && jc == endc) || (ic == endc && jc == startc)) { debug(("Adding link at (%d,%d) would join start to end", x, y)); /* We mustn't join the start to the end if: - there are other bits of track that aren't attached to either end - the clues are not fully satisfied yet */ for (k = 0; k < w*h; k++) { if (state->sflags[k] & S_TRACK && dsf_canonify(dsf, k) != startc && dsf_canonify(dsf, k) != endc) { return solve_set_eflag(state, x, y, dir, E_NOTRACK, "joins start to end but misses tracks"); } } for (k = 0; k < w; k++) { int target = state->numbers->numbers[k]; int ntracks = solve_count_col(state, k, S_TRACK); if (ntracks < target) satisfied = 0; } for (k = 0; k < h; k++) { int target = state->numbers->numbers[w+k]; int ntracks = solve_count_row(state, k, S_TRACK); if (ntracks < target) satisfied = 0; } if (!satisfied) { return solve_set_eflag(state, x, y, dir, E_NOTRACK, "joins start to end with incomplete clues"); } } } return 0; } static int solve_check_loop(game_state *state) { int w = state->p.w, h = state->p.h, x, y, i, j, did = 0; int *dsf, startc, endc; /* TODO eventually we should pull this out into a solver struct and keep it updated as we connect squares. For now we recreate it every time we try this particular solver step. */ dsf = snewn(w*h, int); dsf_init(dsf, w*h); /* Work out the connectedness of the current loop set. */ for (x = 0; x < w; x++) { for (y = 0; y < h; y++) { i = y*w + x; if (x < (w-1) && S_E_DIRS(state, x, y, E_TRACK) & R) { /* connection to the right... */ j = y*w + (x+1); assert(i < w*h && j < w*h); dsf_merge(dsf, i, j); } if (y < (h-1) && S_E_DIRS(state, x, y, E_TRACK) & D) { /* connection down... */ j = (y+1)*w + x; assert(i < w*h && j < w*h); dsf_merge(dsf, i, j); } /* NB no need to check up and left because they'll have been checked by the other side. */ } } startc = dsf_canonify(dsf, state->numbers->row_s*w); endc = dsf_canonify(dsf, (h-1)*w+state->numbers->col_s); /* Now look at all adjacent squares that are both S_TRACK: if connecting any of them would complete a loop (i.e. they're both the same dsf class already) then that edge must be NOTRACK. */ for (x = 0; x < w; x++) { for (y = 0; y < h; y++) { if (x < (w-1)) did += solve_check_loop_sub(state, x, y, R, dsf, startc, endc); if (y < (h-1)) did += solve_check_loop_sub(state, x, y, D, dsf, startc, endc); } } sfree(dsf); return did; } static void solve_discount_edge(game_state *state, int x, int y, int d) { if (S_E_DIRS(state, x, y, E_TRACK) & d) { assert(state->sflags[y*state->p.w + x] & S_CLUE); return; /* (only) clue squares can have outer edges set. */ } solve_set_eflag(state, x, y, d, E_NOTRACK, "outer edge"); } static int tracks_solve(game_state *state, int diff) { int didsth, x, y, w = state->p.w, h = state->p.h; debug(("solve...")); state->impossible = FALSE; /* Set all the outer border edges as no-track. */ for (x = 0; x < w; x++) { solve_discount_edge(state, x, 0, U); solve_discount_edge(state, x, h-1, D); } for (y = 0; y < h; y++) { solve_discount_edge(state, 0, y, L); solve_discount_edge(state, w-1, y, R); } while (1) { didsth = 0; didsth += solve_update_flags(state); didsth += solve_count_clues(state); didsth += solve_check_loop(state); if (diff >= DIFF_TRICKY) { didsth += solve_check_single(state); didsth += solve_check_loose_ends(state); } if (!didsth || state->impossible) break; } return state->impossible ? -1 : check_completion(state, FALSE) ? 1 : 0; } static char *move_string_diff(const game_state *before, const game_state *after, int issolve) { int w = after->p.w, h = after->p.h, i, j; char *move = snewn(w*h*40, char), *p = move; const char *sep = ""; unsigned int otf, ntf, onf, nnf; if (issolve) { *p++ = 'S'; sep = ";"; } for (i = 0; i < w*h; i++) { otf = S_E_DIRS(before, i%w, i/w, E_TRACK); ntf = S_E_DIRS(after, i%w, i/w, E_TRACK); onf = S_E_DIRS(before, i%w, i/w, E_NOTRACK); nnf = S_E_DIRS(after, i%w, i/w, E_NOTRACK); for (j = 0; j < 4; j++) { unsigned df = 1<sflags[i] & S_NOTRACK) != (after->sflags[i] & S_NOTRACK)) { p += sprintf(p, "%s%cS%d,%d", sep, (after->sflags[i] & S_NOTRACK) ? 'N' : 'n', i%w, i/w); sep = ";"; } if ((before->sflags[i] & S_TRACK) != (after->sflags[i] & S_TRACK)) { p += sprintf(p, "%s%cS%d,%d", sep, (after->sflags[i] & S_TRACK) ? 'T' : 't', i%w, i/w); sep = ";"; } } *p++ = '\0'; move = sresize(move, p - move, char); return move; } static char *solve_game(const game_state *state, const game_state *currstate, const char *aux, char **error) { game_state *solved; int ret; char *move; solved = dup_game(currstate); ret = tracks_solve(solved, DIFFCOUNT); if (ret < 1) { free_game(solved); solved = dup_game(state); ret = tracks_solve(solved, DIFFCOUNT); } if (ret < 1) { *error = "Unable to find solution"; move = NULL; } else { move = move_string_diff(currstate, solved, TRUE); } free_game(solved); return move; } static int game_can_format_as_text_now(const game_params *params) { return TRUE; } static char *game_text_format(const game_state *state) { char *ret, *p; int x, y, len, w = state->p.w, h = state->p.h; len = ((w*2) + 4) * ((h*2)+4) + 2; ret = snewn(len+1, char); p = ret; /* top line: column clues */ *p++ = ' '; *p++ = ' '; for (x = 0; x < w; x++) { *p++ = (state->numbers->numbers[x] < 10 ? '0' + state->numbers->numbers[x] : 'A' + state->numbers->numbers[x] - 10); *p++ = ' '; } *p++ = '\n'; /* second line: top edge */ *p++ = ' '; *p++ = '+'; for (x = 0; x < w*2-1; x++) *p++ = '-'; *p++ = '+'; *p++ = '\n'; /* grid rows: one line of squares, one line of edges. */ for (y = 0; y < h; y++) { /* grid square line */ *p++ = (y == state->numbers->row_s) ? 'A' : ' '; *p++ = (y == state->numbers->row_s) ? '-' : '|'; for (x = 0; x < w; x++) { unsigned int f = S_E_DIRS(state, x, y, E_TRACK); if (state->sflags[y*w+x] & S_CLUE) *p++ = 'C'; else if (f == LU || f == RD) *p++ = '/'; else if (f == LD || f == RU) *p++ = '\\'; else if (f == UD) *p++ = '|'; else if (f == RL) *p++ = '-'; else if (state->sflags[y*w+x] & S_NOTRACK) *p++ = 'x'; else *p++ = ' '; if (x < w-1) { *p++ = (f & R) ? '-' : ' '; } else *p++ = '|'; } *p++ = (state->numbers->numbers[w+y] < 10 ? '0' + state->numbers->numbers[w+y] : 'A' + state->numbers->numbers[w+y] - 10); *p++ = '\n'; if (y == h-1) continue; /* edges line */ *p++ = ' '; *p++ = '|'; for (x = 0; x < w; x++) { unsigned int f = S_E_DIRS(state, x, y, E_TRACK); *p++ = (f & D) ? '|' : ' '; *p++ = (x < w-1) ? ' ' : '|'; } *p++ = '\n'; } /* next line: bottom edge */ *p++ = ' '; *p++ = '+'; for (x = 0; x < w*2-1; x++) *p++ = (x == state->numbers->col_s*2) ? '|' : '-'; *p++ = '+'; *p++ = '\n'; /* final line: bottom clue */ *p++ = ' '; *p++ = ' '; for (x = 0; x < w*2-1; x++) *p++ = (x == state->numbers->col_s*2) ? 'B' : ' '; *p++ = '\n'; *p = '\0'; return ret; } static void debug_state(game_state *state, const char *what) { char *sstring = game_text_format(state); debug(("%s: %s", what, sstring)); sfree(sstring); } static void dsf_update_completion(game_state *state, int ax, int ay, char dir, int *dsf) { int w = state->p.w, ai = ay*w+ax, bx, by, bi; if (!(S_E_DIRS(state, ax, ay, E_TRACK) & dir)) return; bx = ax + DX(dir); by = ay + DY(dir); if (!INGRID(state, bx, by)) return; bi = by*w+bx; dsf_merge(dsf, ai, bi); } struct tracks_neighbour_ctx { game_state *state; int i, n, neighbours[4]; }; static int tracks_neighbour(int vertex, void *vctx) { struct tracks_neighbour_ctx *ctx = (struct tracks_neighbour_ctx *)vctx; if (vertex >= 0) { game_state *state = ctx->state; int w = state->p.w, x = vertex % w, y = vertex / w; int dirs = S_E_DIRS(state, x, y, E_TRACK); int j; ctx->i = ctx->n = 0; for (j = 0; j < 4; j++) { int dir = 1<neighbours[ctx->n++] = ny * w + nx; } } } if (ctx->i < ctx->n) return ctx->neighbours[ctx->i++]; else return -1; } static int check_completion(game_state *state, int mark) { int w = state->p.w, h = state->p.h, x, y, i, target, ret = TRUE; int ntrack, nnotrack, ntrackcomplete; int *dsf, pathclass; struct findloopstate *fls; struct tracks_neighbour_ctx ctx; if (mark) { for (i = 0; i < w+h; i++) { state->num_errors[i] = 0; } for (i = 0; i < w*h; i++) { state->sflags[i] &= ~S_ERROR; if (S_E_COUNT(state, i%w, i/w, E_TRACK) > 0) { if (S_E_COUNT(state, i%w, i/w, E_TRACK) > 2) { ret = FALSE; state->sflags[i] |= S_ERROR; } } } } /* A cell is 'complete', for the purposes of marking the game as * finished, if it has two edges marked as TRACK. But it only has * to have one edge marked as TRACK, or be filled in as trackful * without any specific edges known, to count towards checking * row/column clue errors. */ for (x = 0; x < w; x++) { target = state->numbers->numbers[x]; ntrack = nnotrack = ntrackcomplete = 0; for (y = 0; y < h; y++) { if (S_E_COUNT(state, x, y, E_TRACK) > 0 || state->sflags[y*w+x] & S_TRACK) ntrack++; if (S_E_COUNT(state, x, y, E_TRACK) == 2) ntrackcomplete++; if (state->sflags[y*w+x] & S_NOTRACK) nnotrack++; } if (mark) { if (ntrack > target || nnotrack > (h-target)) { debug(("col %d error: target %d, track %d, notrack %d", x, target, ntrack, nnotrack)); state->num_errors[x] = 1; ret = FALSE; } } if (ntrackcomplete != target) ret = FALSE; } for (y = 0; y < h; y++) { target = state->numbers->numbers[w+y]; ntrack = nnotrack = ntrackcomplete = 0; for (x = 0; x < w; x++) { if (S_E_COUNT(state, x, y, E_TRACK) > 0 || state->sflags[y*w+x] & S_TRACK) ntrack++; if (S_E_COUNT(state, x, y, E_TRACK) == 2) ntrackcomplete++; if (state->sflags[y*w+x] & S_NOTRACK) nnotrack++; } if (mark) { if (ntrack > target || nnotrack > (w-target)) { debug(("row %d error: target %d, track %d, notrack %d", y, target, ntrack, nnotrack)); state->num_errors[w+y] = 1; ret = FALSE; } } if (ntrackcomplete != target) ret = FALSE; } dsf = snewn(w*h, int); dsf_init(dsf, w*h); for (x = 0; x < w; x++) { for (y = 0; y < h; y++) { dsf_update_completion(state, x, y, R, dsf); dsf_update_completion(state, x, y, D, dsf); } } fls = findloop_new_state(w*h); ctx.state = state; if (findloop_run(fls, w*h, tracks_neighbour, &ctx)) { debug(("loop detected, not complete")); ret = FALSE; /* no loop allowed */ if (mark) { for (x = 0; x < w; x++) { for (y = 0; y < h; y++) { int u, v; u = y*w + x; for (v = tracks_neighbour(u, &ctx); v >= 0; v = tracks_neighbour(-1, &ctx)) if (findloop_is_loop_edge(fls, u, v)) state->sflags[y*w+x] |= S_ERROR; } } } } findloop_free_state(fls); if (mark) { pathclass = dsf_canonify(dsf, state->numbers->row_s*w); if (pathclass == dsf_canonify(dsf, (h-1)*w + state->numbers->col_s)) { /* We have a continuous path between the entrance and the exit: any other path must be in error. */ for (i = 0; i < w*h; i++) { if ((dsf_canonify(dsf, i) != pathclass) && ((state->sflags[i] & S_TRACK) || (S_E_COUNT(state, i%w, i/w, E_TRACK) > 0))) { ret = FALSE; state->sflags[i] |= S_ERROR; } } } else { /* If we _don't_ have such a path, then certainly the game * can't be in a winning state. So even if we're not * highlighting any _errors_, we certainly shouldn't * return true. */ ret = FALSE; } } if (mark) state->completed = ret; sfree(dsf); return ret; } /* Code borrowed from Pearl. */ struct game_ui { int dragging, clearing, notrack; int drag_sx, drag_sy, drag_ex, drag_ey; /* drag start and end grid coords */ int clickx, clicky; /* pixel position of initial click */ int curx, cury; /* grid position of keyboard cursor; uses half-size grid */ int cursor_active; /* TRUE iff cursor is shown */ }; static game_ui *new_ui(const game_state *state) { game_ui *ui = snew(game_ui); ui->clearing = ui->notrack = ui->dragging = 0; ui->drag_sx = ui->drag_sy = ui->drag_ex = ui->drag_ey = -1; ui->cursor_active = FALSE; ui->curx = ui->cury = 1; return ui; } static void free_ui(game_ui *ui) { sfree(ui); } static char *encode_ui(const game_ui *ui) { return NULL; } static void decode_ui(game_ui *ui, const char *encoding) { } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { } #define PREFERRED_TILE_SIZE 30 #define HALFSZ (ds->sz6*3) #define THIRDSZ (ds->sz6*2) #define TILE_SIZE (ds->sz6*6) #define BORDER (TILE_SIZE/8) #define BORDER_WIDTH (max(TILE_SIZE / 32, 1)) #define COORD(x) ( (x+1) * TILE_SIZE + BORDER ) #define CENTERED_COORD(x) ( COORD(x) + TILE_SIZE/2 ) #define FROMCOORD(x) ( ((x) < BORDER) ? -1 : ( ((x) - BORDER) / TILE_SIZE) - 1 ) #define DS_DSHIFT 4 /* R/U/L/D shift, for drag-in-progress flags */ #define DS_ERROR (1 << 8) #define DS_CLUE (1 << 9) #define DS_NOTRACK (1 << 10) #define DS_FLASH (1 << 11) #define DS_CURSOR (1 << 12) /* cursor in square (centre, or on edge) */ #define DS_TRACK (1 << 13) #define DS_CLEARING (1 << 14) #define DS_NSHIFT 16 /* R/U/L/D shift, for no-track edge flags */ #define DS_CSHIFT 20 /* R/U/L/D shift, for cursor-on-edge */ struct game_drawstate { int sz6; int started; int w, h, sz; unsigned int *flags, *flags_drag; int *num_errors; }; static void update_ui_drag(const game_state *state, game_ui *ui, int gx, int gy) { int w = state->p.w, h = state->p.h; int dx = abs(ui->drag_sx - gx), dy = abs(ui->drag_sy - gy); if (dy == 0) { ui->drag_ex = gx < 0 ? 0 : gx >= w ? w-1 : gx; ui->drag_ey = ui->drag_sy; ui->dragging = TRUE; } else if (dx == 0) { ui->drag_ex = ui->drag_sx; ui->drag_ey = gy < 0 ? 0 : gy >= h ? h-1 : gy; ui->dragging = TRUE; } else { ui->drag_ex = ui->drag_sx; ui->drag_ey = ui->drag_sy; ui->dragging = FALSE; } } static int ui_can_flip_edge(const game_state *state, int x, int y, int dir, int notrack) { int w = state->p.w /*, h = state->shared->h, sz = state->shared->sz */; int x2 = x + DX(dir); int y2 = y + DY(dir); unsigned int sf1, sf2, ef; if (!INGRID(state, x, y) || !INGRID(state, x2, y2)) return FALSE; sf1 = state->sflags[y*w + x]; sf2 = state->sflags[y2*w + x2]; if ( !notrack && ((sf1 & S_CLUE) || (sf2 & S_CLUE)) ) return FALSE; ef = S_E_FLAGS(state, x, y, dir); if (notrack) { /* if we're going to _set_ NOTRACK (i.e. the flag is currently unset), make sure the edge is not already set to TRACK. The adjacent squares could be set to TRACK, because we don't know which edges the general square setting refers to. */ if (!(ef & E_NOTRACK) && (ef & E_TRACK)) return FALSE; } else { if (!(ef & E_TRACK)) { /* if we're going to _set_ TRACK, make sure neither adjacent square nor the edge itself is already set to NOTRACK. */ if ((sf1 & S_NOTRACK) || (sf2 & S_NOTRACK) || (ef & E_NOTRACK)) return FALSE; /* if we're going to _set_ TRACK, make sure neither adjacent square has 2 track flags already. */ if ((S_E_COUNT(state, x, y, E_TRACK) >= 2) || (S_E_COUNT(state, x2, y2, E_TRACK) >= 2)) return FALSE; } } return TRUE; } static int ui_can_flip_square(const game_state *state, int x, int y, int notrack) { int w = state->p.w, trackc; unsigned sf; if (!INGRID(state, x, y)) return FALSE; sf = state->sflags[y*w+x]; trackc = S_E_COUNT(state, x, y, E_TRACK); if (sf & S_CLUE) return FALSE; if (notrack) { /* If we're setting S_NOTRACK, we cannot have either S_TRACK or any E_TRACK. */ if (!(sf & S_NOTRACK) && ((sf & S_TRACK) || (trackc > 0))) return FALSE; } else { /* If we're setting S_TRACK, we cannot have any S_NOTRACK (we could have E_NOTRACK, though, because one or two wouldn't rule out a track) */ if (!(sf & S_TRACK) && (sf & S_NOTRACK)) return FALSE; } return TRUE; } static char *edge_flip_str(const game_state *state, int x, int y, int dir, int notrack, char *buf) { unsigned ef = S_E_FLAGS(state, x, y, dir); char c; if (notrack) c = (ef & E_NOTRACK) ? 'n' : 'N'; else c = (ef & E_TRACK) ? 't' : 'T'; sprintf(buf, "%c%c%d,%d", c, MOVECHAR(dir), x, y); return dupstr(buf); } static char *square_flip_str(const game_state *state, int x, int y, int notrack, char *buf) { unsigned f = state->sflags[y*state->p.w+x]; char c; if (notrack) c = (f & E_NOTRACK) ? 'n' : 'N'; else c = (f & E_TRACK) ? 't' : 'T'; sprintf(buf, "%cS%d,%d", c, x, y); return dupstr(buf); } #define SIGN(x) ((x<0) ? -1 : (x>0)) static game_state *copy_and_apply_drag(const game_state *state, const game_ui *ui) { game_state *after = dup_game(state); int x1, y1, x2, y2, x, y, w = state->p.w; unsigned f = ui->notrack ? S_NOTRACK : S_TRACK, ff; x1 = min(ui->drag_sx, ui->drag_ex); x2 = max(ui->drag_sx, ui->drag_ex); y1 = min(ui->drag_sy, ui->drag_ey); y2 = max(ui->drag_sy, ui->drag_ey); /* actually either x1 == x2, or y1 == y2, but it's easier just to code the nested loop. */ for (x = x1; x <= x2; x++) { for (y = y1; y <= y2; y++) { ff = state->sflags[y*w+x]; if (ui->clearing && !(ff & f)) continue; /* nothing to do, clearing and already clear */ else if (!ui->clearing && (ff & f)) continue; /* nothing to do, setting and already set */ else if (ui_can_flip_square(state, x, y, ui->notrack)) after->sflags[y*w+x] ^= f; } } return after; } #define KEY_DIRECTION(btn) (\ (btn) == CURSOR_DOWN ? D : (btn) == CURSOR_UP ? U :\ (btn) == CURSOR_LEFT ? L : R) static char *interpret_move(const game_state *state, game_ui *ui, const game_drawstate *ds, int x, int y, int button) { int w = state->p.w, h = state->p.h, direction; int gx = FROMCOORD(x), gy = FROMCOORD(y); char tmpbuf[80]; /* --- mouse operations --- */ if (IS_MOUSE_DOWN(button)) { ui->cursor_active = FALSE; ui->dragging = FALSE; if (!INGRID(state, gx, gy)) { /* can't drag from off grid */ return NULL; } if (button == RIGHT_BUTTON) { ui->notrack = TRUE; ui->clearing = state->sflags[gy*w+gx] & S_NOTRACK; } else { ui->notrack = FALSE; ui->clearing = state->sflags[gy*w+gx] & S_TRACK; } ui->clickx = x; ui->clicky = y; ui->drag_sx = ui->drag_ex = gx; ui->drag_sy = ui->drag_ey = gy; return ""; } if (IS_MOUSE_DRAG(button)) { ui->cursor_active = FALSE; update_ui_drag(state, ui, gx, gy); return ""; } if (IS_MOUSE_RELEASE(button)) { ui->cursor_active = FALSE; if (ui->dragging && (ui->drag_sx != ui->drag_ex || ui->drag_sy != ui->drag_ey)) { game_state *dragged = copy_and_apply_drag(state, ui); char *ret = move_string_diff(state, dragged, FALSE); ui->dragging = 0; free_game(dragged); return ret; } else { int cx, cy; /* We might still have been dragging (and just done a one- * square drag): cancel drag, so undo doesn't make it like * a drag-in-progress. */ ui->dragging = 0; /* Click (or tiny drag). Work out which edge we were * closest to. */ /* * We process clicks based on the mouse-down location, * because that's more natural for a user to carefully * control than the mouse-up. */ x = ui->clickx; y = ui->clicky; cx = CENTERED_COORD(gx); cy = CENTERED_COORD(gy); if (!INGRID(state, gx, gy) || FROMCOORD(x) != gx || FROMCOORD(y) != gy) return ""; if (max(abs(x-cx),abs(y-cy)) < TILE_SIZE/4) { if (ui_can_flip_square(state, gx, gy, button == RIGHT_RELEASE)) return square_flip_str(state, gx, gy, button == RIGHT_RELEASE, tmpbuf); return ""; } else { if (abs(x-cx) < abs(y-cy)) { /* Closest to top/bottom edge. */ direction = (y < cy) ? U : D; } else { /* Closest to left/right edge. */ direction = (x < cx) ? L : R; } if (ui_can_flip_edge(state, gx, gy, direction, button == RIGHT_RELEASE)) return edge_flip_str(state, gx, gy, direction, button == RIGHT_RELEASE, tmpbuf); else return ""; } } } /* --- cursor/keyboard operations --- */ if (IS_CURSOR_MOVE(button)) { int dx = (button == CURSOR_LEFT) ? -1 : ((button == CURSOR_RIGHT) ? +1 : 0); int dy = (button == CURSOR_DOWN) ? +1 : ((button == CURSOR_UP) ? -1 : 0); if (!ui->cursor_active) { ui->cursor_active = TRUE; return ""; } ui->curx = ui->curx + dx; ui->cury = ui->cury + dy; if ((ui->curx % 2 == 0) && (ui->cury % 2 == 0)) { /* disallow cursor on square corners: centres and edges only */ ui->curx += dx; ui->cury += dy; } ui->curx = min(max(ui->curx, 1), 2*w-1); ui->cury = min(max(ui->cury, 1), 2*h-1); return ""; } if (IS_CURSOR_SELECT(button)) { if (!ui->cursor_active) { ui->cursor_active = TRUE; return ""; } /* click on square corner does nothing (shouldn't get here) */ if ((ui->curx % 2) == 0 && (ui->cury % 2 == 0)) return ""; gx = ui->curx / 2; gy = ui->cury / 2; direction = ((ui->curx % 2) == 0) ? L : ((ui->cury % 2) == 0) ? U : 0; if (direction && ui_can_flip_edge(state, gx, gy, direction, button == CURSOR_SELECT2)) return edge_flip_str(state, gx, gy, direction, button == CURSOR_SELECT2, tmpbuf); else if (!direction && ui_can_flip_square(state, gx, gy, button == CURSOR_SELECT2)) return square_flip_str(state, gx, gy, button == CURSOR_SELECT2, tmpbuf); return ""; } #if 0 /* helps to debug the solver */ if (button == 'H' || button == 'h') return dupstr("H"); #endif return NULL; } static game_state *execute_move(const game_state *state, const char *move) { int w = state->p.w, x, y, n, i; char c, d; unsigned f; game_state *ret = dup_game(state); /* this is breaking the bank on GTK, which vsprintf's into a fixed-size buffer * which is 4096 bytes long. vsnprintf needs a feature-test macro to use, faff. */ /*debug(("move: %s\n", move));*/ while (*move) { c = *move; if (c == 'S') { ret->used_solve = TRUE; move++; } else if (c == 'T' || c == 't' || c == 'N' || c == 'n') { /* set track, clear track; set notrack, clear notrack */ move++; if (sscanf(move, "%c%d,%d%n", &d, &x, &y, &n) != 3) goto badmove; if (!INGRID(state, x, y)) goto badmove; f = (c == 'T' || c == 't') ? S_TRACK : S_NOTRACK; if (d == 'S') { if (c == 'T' || c == 'N') ret->sflags[y*w+x] |= f; else ret->sflags[y*w+x] &= ~f; } else if (d == 'U' || d == 'D' || d == 'L' || d == 'R') { for (i = 0; i < 4; i++) { unsigned df = 1<tilesize' for macro expansion purposes */ struct { int sz6; } ads, *ds = &ads; ads.sz6 = tilesize/6; *x = (params->w+2) * TILE_SIZE + 2 * BORDER; *y = (params->h+2) * TILE_SIZE + 2 * BORDER; } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { ds->sz6 = tilesize/6; } enum { COL_BACKGROUND, COL_LOWLIGHT, COL_HIGHLIGHT, COL_TRACK_BACKGROUND = COL_LOWLIGHT, COL_GRID, COL_CLUE, COL_CURSOR, COL_TRACK, COL_TRACK_CLUE, COL_SLEEPER, COL_DRAGON, COL_DRAGOFF, COL_ERROR, COL_FLASH, NCOLOURS }; static float *game_colours(frontend *fe, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float); int i; game_mkhighlight(fe, ret, COL_BACKGROUND, COL_HIGHLIGHT, COL_LOWLIGHT); for (i = 0; i < 3; i++) { ret[COL_TRACK_CLUE * 3 + i] = 0.0F; ret[COL_TRACK * 3 + i] = 0.5F; ret[COL_CLUE * 3 + i] = 0.0F; ret[COL_GRID * 3 + i] = 0.75F; ret[COL_CURSOR * 3 + i] = 0.6F; } ret[COL_SLEEPER * 3 + 0] = 0.5F; ret[COL_SLEEPER * 3 + 1] = 0.4F; ret[COL_SLEEPER * 3 + 2] = 0.1F; ret[COL_ERROR * 3 + 0] = 1.0F; ret[COL_ERROR * 3 + 1] = 0.0F; ret[COL_ERROR * 3 + 2] = 0.0F; ret[COL_DRAGON * 3 + 0] = 0.0F; ret[COL_DRAGON * 3 + 1] = 0.0F; ret[COL_DRAGON * 3 + 2] = 1.0F; ret[COL_DRAGOFF * 3 + 0] = 0.8F; ret[COL_DRAGOFF * 3 + 1] = 0.8F; ret[COL_DRAGOFF * 3 + 2] = 1.0F; ret[COL_FLASH * 3 + 0] = 1.0F; ret[COL_FLASH * 3 + 1] = 1.0F; ret[COL_FLASH * 3 + 2] = 1.0F; *ncolours = NCOLOURS; return ret; } static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { struct game_drawstate *ds = snew(struct game_drawstate); int i; ds->sz6 = 0; ds->started = FALSE; ds->w = state->p.w; ds->h = state->p.h; ds->sz = ds->w*ds->h; ds->flags = snewn(ds->sz, unsigned int); ds->flags_drag = snewn(ds->sz, unsigned int); for (i = 0; i < ds->sz; i++) ds->flags[i] = ds->flags_drag[i] = 0; ds->num_errors = snewn(ds->w+ds->h, int); for (i = 0; i < ds->w+ds->h; i++) ds->num_errors[i] = 0; return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { sfree(ds->flags); sfree(ds->flags_drag); sfree(ds->num_errors); sfree(ds); } static void draw_circle_sleepers(drawing *dr, game_drawstate *ds, float cx, float cy, float r2, float thickness, int c) { float qr6 = (float)PI/12, qr3 = (float)PI/6, th, x1, y1, x2, y2; float t6 = THIRDSZ/2.0F, r1 = t6; int i; for (i = 0; i < 12; i++) { th = qr6 + (i*qr3); x1 = r1*(float)cos(th); x2 = r2*(float)cos(th); y1 = r1*(float)sin(th); y2 = r2*(float)sin(th); draw_thick_line(dr, thickness, cx+x1, cy+y1, cx+x2, cy+y2, c); } } static void draw_thick_circle_outline(drawing *dr, float thickness, float cx, float cy, float r, int colour) { float circ4 = 0.5F * (float)PI * r, ang, x1, y1, x2, y2; int i, nseg; nseg = (int)(circ4 / 4.0F)*4; /* ensure a quarter-circle has a whole #segs */ ang = 2.0F*(float)PI / nseg; for (i = 0; i < nseg; i++) { float th = ang * i, th2 = ang * (i+1); x1 = cx + r*(float)cos(th); x2 = cx + r*(float)cos(th2); y1 = cy + r*(float)sin(th); y2 = cy + r*(float)sin(th2); debug(("circ outline: x=%.2f -> %.2f, thick=%.2f", x1, x2, thickness)); draw_thick_line(dr, thickness, x1, y1, x2, y2, colour); } } static void draw_tracks_specific(drawing *dr, game_drawstate *ds, int x, int y, unsigned int flags, int ctrack, int csleeper) { float ox = (float)COORD(x), oy = (float)COORD(y), cx, cy; float t1 = (float)TILE_SIZE, t3 = TILE_SIZE/3.0F, t6 = TILE_SIZE/6.0F; int d, i; float thick_track = TILE_SIZE/8.0F, thick_sleeper = TILE_SIZE/12.0F; if (flags == LR) { for (i = 1; i <= 7; i+=2) { cx = ox + TILE_SIZE/8.0F*i; draw_thick_line(dr, thick_sleeper, cx, oy+t6, cx, oy+t6+2*t3, csleeper); } draw_thick_line(dr, thick_track, ox, oy + t3, ox + TILE_SIZE, oy + t3, ctrack); draw_thick_line(dr, thick_track, ox, oy + 2*t3, ox + TILE_SIZE, oy + 2*t3, ctrack); return; } if (flags == UD) { for (i = 1; i <= 7; i+=2) { cy = oy + TILE_SIZE/8.0F*i; draw_thick_line(dr, thick_sleeper, ox+t6, cy, ox+t6+2*t3, cy, csleeper); } debug(("vert line: x=%.2f, thick=%.2f", ox + t3, thick_track)); draw_thick_line(dr, thick_track, ox + t3, oy, ox + t3, oy + TILE_SIZE, ctrack); draw_thick_line(dr, thick_track, ox + 2*t3, oy, ox + 2*t3, oy + TILE_SIZE, ctrack); return; } if (flags == UL || flags == DL || flags == UR || flags == DR) { cx = (flags & L) ? ox : ox + TILE_SIZE; cy = (flags & U) ? oy : oy + TILE_SIZE; draw_circle_sleepers(dr, ds, cx, cy, (float)(5*t6), thick_sleeper, csleeper); draw_thick_circle_outline(dr, thick_track, (float)cx, (float)cy, 2*t3, ctrack); draw_thick_circle_outline(dr, thick_track, (float)cx, (float)cy, t3, ctrack); return; } for (d = 1; d < 16; d *= 2) { float ox1 = 0, ox2 = 0, oy1 = 0, oy2 = 0; if (!(flags & d)) continue; for (i = 1; i <= 2; i++) { if (d == L) { ox1 = 0; ox2 = thick_track; oy1 = oy2 = i*t3; } else if (d == R) { ox1 = t1; ox2 = t1 - thick_track; oy1 = oy2 = i*t3; } else if (d == U) { ox1 = ox2 = i*t3; oy1 = 0; oy2 = thick_track; } else if (d == D) { ox1 = ox2 = i*t3; oy1 = t1; oy2 = t1 - thick_track; } draw_thick_line(dr, thick_track, ox+ox1, oy+oy1, ox+ox2, oy+oy2, ctrack); } } } static unsigned int best_bits(unsigned int flags, unsigned int flags_drag, int *col) { int nb_orig = nbits[flags & ALLDIR], nb_drag = nbits[flags_drag & ALLDIR]; if (nb_orig > nb_drag) { *col = COL_DRAGOFF; return flags & ALLDIR; } else if (nb_orig < nb_drag) { *col = COL_DRAGON; return flags_drag & ALLDIR; } return flags & ALLDIR; /* same number of bits: no special colour. */ } static void draw_square(drawing *dr, game_drawstate *ds, int x, int y, unsigned int flags, unsigned int flags_drag) { int t2 = HALFSZ, t16 = HALFSZ/4, off; int ox = COORD(x), oy = COORD(y), cx = ox + t2, cy = oy + t2, d, c; int bg = (flags & DS_TRACK) ? COL_TRACK_BACKGROUND : COL_BACKGROUND; unsigned int flags_best; assert(dr); /* Clip to the grid square. */ clip(dr, ox, oy, TILE_SIZE, TILE_SIZE); /* Clear the square. */ best_bits((flags & DS_TRACK) == DS_TRACK, (flags_drag & DS_TRACK) == DS_TRACK, &bg); draw_rect(dr, ox, oy, TILE_SIZE, TILE_SIZE, bg); /* Draw outline of grid square */ draw_line(dr, ox, oy, COORD(x+1), oy, COL_GRID); draw_line(dr, ox, oy, ox, COORD(y+1), COL_GRID); /* More outlines for clue squares. */ if (flags & DS_CURSOR) { int curx, cury, curw, curh; off = t16; curx = ox + off; cury = oy + off; curw = curh = TILE_SIZE - (2*off) + 1; if (flags & (U << DS_CSHIFT)) { cury = oy - off; curh = 2*off + 1; } else if (flags & (D << DS_CSHIFT)) { cury = oy + TILE_SIZE - off; curh = 2*off + 1; } else if (flags & (L << DS_CSHIFT)) { curx = ox - off; curw = 2*off + 1; } else if (flags & (R << DS_CSHIFT)) { curx = ox + TILE_SIZE - off; curw = 2*off + 1; } draw_rect_outline(dr, curx, cury, curw, curh, COL_GRID); } /* Draw tracks themselves */ c = (flags & DS_ERROR) ? COL_ERROR : (flags & DS_FLASH) ? COL_FLASH : (flags & DS_CLUE) ? COL_TRACK_CLUE : COL_TRACK; flags_best = best_bits(flags, flags_drag, &c); draw_tracks_specific(dr, ds, x, y, flags_best, c, COL_SLEEPER); /* Draw no-track marks, if present, in square and on edges. */ c = COL_TRACK; flags_best = best_bits((flags & DS_NOTRACK) == DS_NOTRACK, (flags_drag & DS_NOTRACK) == DS_NOTRACK, &c); if (flags_best) { off = HALFSZ/2; draw_line(dr, cx - off, cy - off, cx + off, cy + off, c); draw_line(dr, cx - off, cy + off, cx + off, cy - off, c); } c = COL_TRACK; flags_best = best_bits(flags >> DS_NSHIFT, flags_drag >> DS_NSHIFT, &c); for (d = 1; d < 16; d *= 2) { off = t16; cx = ox + t2; cy = oy + t2; if (flags_best & d) { cx += (d == R) ? t2 : (d == L) ? -t2 : 0; cy += (d == D) ? t2 : (d == U) ? -t2 : 0; draw_line(dr, cx - off, cy - off, cx + off, cy + off, c); draw_line(dr, cx - off, cy + off, cx + off, cy - off, c); } } unclip(dr); draw_update(dr, ox, oy, TILE_SIZE, TILE_SIZE); } static void draw_clue(drawing *dr, game_drawstate *ds, int w, int clue, int i, int col) { int cx, cy, tsz = TILE_SIZE/2; char buf[20]; if (i < w) { cx = CENTERED_COORD(i); cy = CENTERED_COORD(-1); } else { cx = CENTERED_COORD(w); cy = CENTERED_COORD(i-w); } draw_rect(dr, cx - tsz + BORDER, cy - tsz + BORDER, TILE_SIZE - BORDER, TILE_SIZE - BORDER, COL_BACKGROUND); sprintf(buf, "%d", clue); draw_text(dr, cx, cy, FONT_VARIABLE, tsz, ALIGN_VCENTRE|ALIGN_HCENTRE, col, buf); draw_update(dr, cx - tsz, cy - tsz, TILE_SIZE, TILE_SIZE); } static void draw_loop_ends(drawing *dr, game_drawstate *ds, const game_state *state, int c) { int tsz = TILE_SIZE/2; draw_text(dr, CENTERED_COORD(-1), CENTERED_COORD(state->numbers->row_s), FONT_VARIABLE, tsz, ALIGN_VCENTRE|ALIGN_HCENTRE, c, "A"); draw_text(dr, CENTERED_COORD(state->numbers->col_s), CENTERED_COORD(state->p.h), FONT_VARIABLE, tsz, ALIGN_VCENTRE|ALIGN_HCENTRE, c, "B"); } static unsigned int s2d_flags(const game_state *state, int x, int y, const game_ui *ui) { unsigned int f; int w = state->p.w; f = S_E_DIRS(state, x, y, E_TRACK); f |= (S_E_DIRS(state, x, y, E_NOTRACK) << DS_NSHIFT); if (state->sflags[y*w+x] & S_ERROR) f |= DS_ERROR; if (state->sflags[y*w+x] & S_CLUE) f |= DS_CLUE; if (state->sflags[y*w+x] & S_NOTRACK) f |= DS_NOTRACK; if ((state->sflags[y*w+x] & S_TRACK) || (S_E_COUNT(state, x, y, E_TRACK) > 0)) f |= DS_TRACK; if (ui->cursor_active) { if (ui->curx >= x*2 && ui->curx <= (x+1)*2 && ui->cury >= y*2 && ui->cury <= (y+1)*2) { f |= DS_CURSOR; if (ui->curx == x*2) f |= (L << DS_CSHIFT); if (ui->curx == (x+1)*2) f |= (R << DS_CSHIFT); if (ui->cury == y*2) f |= (U << DS_CSHIFT); if (ui->cury == (y+1)*2) f |= (D << DS_CSHIFT); } } return f; } static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float animtime, float flashtime) { int i, x, y, force = 0, flashing = 0, w = ds->w, h = ds->h; game_state *drag_state = NULL; if (!ds->started) { /* * The initial contents of the window are not guaranteed and * can vary with front ends. To be on the safe side, all games * should start by drawing a big background-colour rectangle * covering the whole window. */ draw_rect(dr, 0, 0, (w+2)*TILE_SIZE + 2*BORDER, (h+2)*TILE_SIZE + 2*BORDER, COL_BACKGROUND); draw_loop_ends(dr, ds, state, COL_CLUE); draw_line(dr, COORD(ds->w), COORD(0), COORD(ds->w), COORD(ds->h), COL_GRID); draw_line(dr, COORD(0), COORD(ds->h), COORD(ds->w), COORD(ds->h), COL_GRID); draw_update(dr, 0, 0, (w+2)*TILE_SIZE + 2*BORDER, (h+2)*TILE_SIZE + 2*BORDER); ds->started = TRUE; force = 1; } for (i = 0; i < w+h; i++) { if (force || (state->num_errors[i] != ds->num_errors[i])) { ds->num_errors[i] = state->num_errors[i]; draw_clue(dr, ds, w, state->numbers->numbers[i], i, ds->num_errors[i] ? COL_ERROR : COL_CLUE); } } if (flashtime > 0 && (flashtime <= FLASH_TIME/3 || flashtime >= FLASH_TIME*2/3)) flashing = DS_FLASH; if (ui->dragging) drag_state = copy_and_apply_drag(state, ui); for (x = 0; x < w; x++) { for (y = 0; y < h; y++) { unsigned int f, f_d; f = s2d_flags(state, x, y, ui) | flashing; f_d = drag_state ? s2d_flags(drag_state, x, y, ui) : f; if (f != ds->flags[y*w+x] || f_d != ds->flags_drag[y*w+x] || force) { ds->flags[y*w+x] = f; ds->flags_drag[y*w+x] = f_d; draw_square(dr, ds, x, y, f, f_d); } } } if (drag_state) free_game(drag_state); } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return 0.0F; } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { if (!oldstate->completed && newstate->completed && !newstate->used_solve) return FLASH_TIME; else return 0.0F; } static int game_status(const game_state *state) { return state->completed ? +1 : 0; } static int game_timing_state(const game_state *state, game_ui *ui) { return TRUE; } static void game_print_size(const game_params *params, float *x, float *y) { int pw, ph; /* The Times uses 7mm squares */ game_compute_size(params, 700, &pw, &ph); *x = pw / 100.0F; *y = ph / 100.0F; } static void game_print(drawing *dr, const game_state *state, int tilesize) { int w = state->p.w, h = state->p.h; int black = print_mono_colour(dr, 0), grey = print_grey_colour(dr, 0.5F); int x, y, i; /* Ick: fake up `ds->tilesize' for macro expansion purposes */ game_drawstate ads, *ds = &ads; game_set_size(dr, ds, NULL, tilesize); /* Grid, then border (second so it is on top) */ print_line_width(dr, TILE_SIZE / 24); for (x = 1; x < w; x++) draw_line(dr, COORD(x), COORD(0), COORD(x), COORD(h), grey); for (y = 1; y < h; y++) draw_line(dr, COORD(0), COORD(y), COORD(w), COORD(y), grey); print_line_width(dr, TILE_SIZE / 16); draw_rect_outline(dr, COORD(0), COORD(0), w*TILE_SIZE, h*TILE_SIZE, black); print_line_width(dr, TILE_SIZE / 24); /* clue numbers, and loop ends */ for (i = 0; i < w+h; i++) draw_clue(dr, ds, w, state->numbers->numbers[i], i, black); draw_loop_ends(dr, ds, state, black); /* clue tracks / solution */ for (x = 0; x < w; x++) { for (y = 0; y < h; y++) { clip(dr, COORD(x), COORD(y), TILE_SIZE, TILE_SIZE); draw_tracks_specific(dr, ds, x, y, S_E_DIRS(state, x, y, E_TRACK), black, grey); unclip(dr); } } } #ifdef COMBINED #define thegame tracks #endif const struct game thegame = { "Train Tracks", "games.tracks", "tracks", default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, TRUE, solve_game, TRUE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, PREFERRED_TILE_SIZE, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, TRUE, FALSE, game_print_size, game_print, FALSE, /* wants_statusbar */ FALSE, game_timing_state, 0, /* flags */ }; /* vim: set shiftwidth=4 tabstop=8: */ puzzles-20170606.272beef/towers.c0000644000175000017500000014720713115373615015373 0ustar simonsimon/* * towers.c: the puzzle also known as 'Skyscrapers'. * * Possible future work: * * - Relax the upper bound on grid size at 9? * + I'd need TOCHAR and FROMCHAR macros a bit like group's, to * be used wherever this code has +'0' or -'0' * + the pencil marks in the drawstate would need a separate * word to live in * + the clues outside the grid would have to cope with being * multi-digit, meaning in particular that the text formatting * would become more unpleasant * + most importantly, though, the solver just isn't fast * enough. Even at size 9 it can't really do the solver_hard * factorial-time enumeration at a sensible rate. Easy puzzles * higher than that would be possible, but more latin-squarey * than skyscrapery, as it were. */ #include #include #include #include #include #include #include "puzzles.h" #include "latin.h" /* * Difficulty levels. I do some macro ickery here to ensure that my * enum and the various forms of my name list always match up. */ #define DIFFLIST(A) \ A(EASY,Easy,solver_easy,e) \ A(HARD,Hard,solver_hard,h) \ A(EXTREME,Extreme,NULL,x) \ A(UNREASONABLE,Unreasonable,NULL,u) #define ENUM(upper,title,func,lower) DIFF_ ## upper, #define TITLE(upper,title,func,lower) #title, #define ENCODE(upper,title,func,lower) #lower #define CONFIG(upper,title,func,lower) ":" #title enum { DIFFLIST(ENUM) DIFFCOUNT }; static char const *const towers_diffnames[] = { DIFFLIST(TITLE) }; static char const towers_diffchars[] = DIFFLIST(ENCODE); #define DIFFCONFIG DIFFLIST(CONFIG) enum { COL_BACKGROUND, COL_GRID, COL_USER, COL_HIGHLIGHT, COL_ERROR, COL_PENCIL, COL_DONE, NCOLOURS }; struct game_params { int w, diff; }; struct clues { int refcount; int w; /* * An array of 4w integers, of which: * - the first w run across the top * - the next w across the bottom * - the third w down the left * - the last w down the right. */ int *clues; /* * An array of w*w digits. */ digit *immutable; }; /* * Macros to compute clue indices and coordinates. */ #define STARTSTEP(start, step, index, w) do { \ if (index < w) \ start = index, step = w; \ else if (index < 2*w) \ start = (w-1)*w+(index-w), step = -w; \ else if (index < 3*w) \ start = w*(index-2*w), step = 1; \ else \ start = w*(index-3*w)+(w-1), step = -1; \ } while (0) #define CSTARTSTEP(start, step, index, w) \ STARTSTEP(start, step, (((index)+2*w)%(4*w)), w) #define CLUEPOS(x, y, index, w) do { \ if (index < w) \ x = index, y = -1; \ else if (index < 2*w) \ x = index-w, y = w; \ else if (index < 3*w) \ x = -1, y = index-2*w; \ else \ x = w, y = index-3*w; \ } while (0) #ifdef STANDALONE_SOLVER static const char *const cluepos[] = { "above column", "below column", "left of row", "right of row" }; #endif struct game_state { game_params par; struct clues *clues; unsigned char *clues_done; digit *grid; int *pencil; /* bitmaps using bits 1<<1..1<w = 5; ret->diff = DIFF_EASY; return ret; } const static struct game_params towers_presets[] = { { 4, DIFF_EASY }, { 5, DIFF_EASY }, { 5, DIFF_HARD }, { 6, DIFF_EASY }, { 6, DIFF_HARD }, { 6, DIFF_EXTREME }, { 6, DIFF_UNREASONABLE }, }; static int game_fetch_preset(int i, char **name, game_params **params) { game_params *ret; char buf[80]; if (i < 0 || i >= lenof(towers_presets)) return FALSE; ret = snew(game_params); *ret = towers_presets[i]; /* structure copy */ sprintf(buf, "%dx%d %s", ret->w, ret->w, towers_diffnames[ret->diff]); *name = dupstr(buf); *params = ret; return TRUE; } static void free_params(game_params *params) { sfree(params); } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } static void decode_params(game_params *params, char const *string) { char const *p = string; params->w = atoi(p); while (*p && isdigit((unsigned char)*p)) p++; if (*p == 'd') { int i; p++; params->diff = DIFFCOUNT+1; /* ...which is invalid */ if (*p) { for (i = 0; i < DIFFCOUNT; i++) { if (*p == towers_diffchars[i]) params->diff = i; } p++; } } } static char *encode_params(const game_params *params, int full) { char ret[80]; sprintf(ret, "%d", params->w); if (full) sprintf(ret + strlen(ret), "d%c", towers_diffchars[params->diff]); return dupstr(ret); } static config_item *game_configure(const game_params *params) { config_item *ret; char buf[80]; ret = snewn(3, config_item); ret[0].name = "Grid size"; ret[0].type = C_STRING; sprintf(buf, "%d", params->w); ret[0].sval = dupstr(buf); ret[0].ival = 0; ret[1].name = "Difficulty"; ret[1].type = C_CHOICES; ret[1].sval = DIFFCONFIG; ret[1].ival = params->diff; ret[2].name = NULL; ret[2].type = C_END; ret[2].sval = NULL; ret[2].ival = 0; return ret; } static game_params *custom_params(const config_item *cfg) { game_params *ret = snew(game_params); ret->w = atoi(cfg[0].sval); ret->diff = cfg[1].ival; return ret; } static char *validate_params(const game_params *params, int full) { if (params->w < 3 || params->w > 9) return "Grid size must be between 3 and 9"; if (params->diff >= DIFFCOUNT) return "Unknown difficulty rating"; return NULL; } /* ---------------------------------------------------------------------- * Solver. */ struct solver_ctx { int w, diff; int started; int *clues; long *iscratch; int *dscratch; }; static int solver_easy(struct latin_solver *solver, void *vctx) { struct solver_ctx *ctx = (struct solver_ctx *)vctx; int w = ctx->w; int c, i, j, n, m, furthest; int start, step, cstart, cstep, clue, pos, cpos; int ret = 0; #ifdef STANDALONE_SOLVER char prefix[256]; #endif if (!ctx->started) { ctx->started = TRUE; /* * One-off loop to help get started: when a pair of facing * clues sum to w+1, it must mean that the row consists of * two increasing sequences back to back, so we can * immediately place the highest digit by knowing the * lengths of those two sequences. */ for (c = 0; c < 3*w; c = (c == w-1 ? 2*w : c+1)) { int c2 = c + w; if (ctx->clues[c] && ctx->clues[c2] && ctx->clues[c] + ctx->clues[c2] == w+1) { STARTSTEP(start, step, c, w); CSTARTSTEP(cstart, cstep, c, w); pos = start + (ctx->clues[c]-1)*step; cpos = cstart + (ctx->clues[c]-1)*cstep; if (solver->cube[cpos*w+w-1]) { #ifdef STANDALONE_SOLVER if (solver_show_working) { printf("%*sfacing clues on %s %d are maximal:\n", solver_recurse_depth*4, "", c>=2*w ? "row" : "column", c % w + 1); printf("%*s placing %d at (%d,%d)\n", solver_recurse_depth*4, "", w, pos%w+1, pos/w+1); } #endif latin_solver_place(solver, pos%w, pos/w, w); ret = 1; } else { ret = -1; } } } if (ret) return ret; } /* * Go over every clue doing reasonably simple heuristic * deductions. */ for (c = 0; c < 4*w; c++) { clue = ctx->clues[c]; if (!clue) continue; STARTSTEP(start, step, c, w); CSTARTSTEP(cstart, cstep, c, w); /* Find the location of each number in the row. */ for (i = 0; i < w; i++) ctx->dscratch[i] = w; for (i = 0; i < w; i++) if (solver->grid[start+i*step]) ctx->dscratch[solver->grid[start+i*step]-1] = i; n = m = 0; furthest = w; for (i = w; i >= 1; i--) { if (ctx->dscratch[i-1] == w) { break; } else if (ctx->dscratch[i-1] < furthest) { furthest = ctx->dscratch[i-1]; m = i; n++; } } if (clue == n+1 && furthest > 1) { #ifdef STANDALONE_SOLVER if (solver_show_working) sprintf(prefix, "%*sclue %s %d is nearly filled:\n", solver_recurse_depth*4, "", cluepos[c/w], c%w+1); else prefix[0] = '\0'; /* placate optimiser */ #endif /* * We can already see an increasing sequence of the very * highest numbers, of length one less than that * specified in the clue. All of those numbers _must_ be * part of the clue sequence, so the number right next * to the clue must be the final one - i.e. it must be * bigger than any of the numbers between it and m. This * allows us to rule out small numbers in that square. * * (This is a generalisation of the obvious deduction * that when you see a clue saying 1, it must be right * next to the largest possible number; and similarly, * when you see a clue saying 2 opposite that, it must * be right next to the second-largest.) */ j = furthest-1; /* number of small numbers we can rule out */ for (i = 1; i <= w && j > 0; i++) { if (ctx->dscratch[i-1] < w && ctx->dscratch[i-1] >= furthest) continue; /* skip this number, it's elsewhere */ j--; if (solver->cube[cstart*w+i-1]) { #ifdef STANDALONE_SOLVER if (solver_show_working) { printf("%s%*s ruling out %d at (%d,%d)\n", prefix, solver_recurse_depth*4, "", i, start%w+1, start/w+1); prefix[0] = '\0'; } #endif solver->cube[cstart*w+i-1] = 0; ret = 1; } } } if (ret) return ret; #ifdef STANDALONE_SOLVER if (solver_show_working) sprintf(prefix, "%*slower bounds for clue %s %d:\n", solver_recurse_depth*4, "", cluepos[c/w], c%w+1); else prefix[0] = '\0'; /* placate optimiser */ #endif i = 0; for (n = w; n > 0; n--) { /* * The largest number cannot occur in the first (clue-1) * squares of the row, or else there wouldn't be space * for a sufficiently long increasing sequence which it * terminated. The second-largest number (not counting * any that are known to be on the far side of a larger * number and hence excluded from this sequence) cannot * occur in the first (clue-2) squares, similarly, and * so on. */ if (ctx->dscratch[n-1] < w) { for (m = n+1; m < w; m++) if (ctx->dscratch[m] < ctx->dscratch[n-1]) break; if (m < w) continue; /* this number doesn't count */ } for (j = 0; j < clue - i - 1; j++) if (solver->cube[(cstart + j*cstep)*w+n-1]) { #ifdef STANDALONE_SOLVER if (solver_show_working) { int pos = start+j*step; printf("%s%*s ruling out %d at (%d,%d)\n", prefix, solver_recurse_depth*4, "", n, pos%w+1, pos/w+1); prefix[0] = '\0'; } #endif solver->cube[(cstart + j*cstep)*w+n-1] = 0; ret = 1; } i++; } } if (ret) return ret; return 0; } static int solver_hard(struct latin_solver *solver, void *vctx) { struct solver_ctx *ctx = (struct solver_ctx *)vctx; int w = ctx->w; int c, i, j, n, best, clue, start, step, ret; long bitmap; #ifdef STANDALONE_SOLVER char prefix[256]; #endif /* * Go over every clue analysing all possibilities. */ for (c = 0; c < 4*w; c++) { clue = ctx->clues[c]; if (!clue) continue; CSTARTSTEP(start, step, c, w); for (i = 0; i < w; i++) ctx->iscratch[i] = 0; /* * Instead of a tedious physical recursion, I iterate in the * scratch array through all possibilities. At any given * moment, i indexes the element of the box that will next * be incremented. */ i = 0; ctx->dscratch[i] = 0; best = n = 0; bitmap = 0; while (1) { if (i < w) { /* * Find the next valid value for cell i. */ int limit = (n == clue ? best : w); int pos = start + step * i; for (j = ctx->dscratch[i] + 1; j <= limit; j++) { if (bitmap & (1L << j)) continue; /* used this one already */ if (!solver->cube[pos*w+j-1]) continue; /* ruled out already */ /* Found one. */ break; } if (j > limit) { /* No valid values left; drop back. */ i--; if (i < 0) break; /* overall iteration is finished */ bitmap &= ~(1L << ctx->dscratch[i]); if (ctx->dscratch[i] == best) { n--; best = 0; for (j = 0; j < i; j++) if (best < ctx->dscratch[j]) best = ctx->dscratch[j]; } } else { /* Got a valid value; store it and move on. */ bitmap |= 1L << j; ctx->dscratch[i++] = j; if (j > best) { best = j; n++; } ctx->dscratch[i] = 0; } } else { if (n == clue) { for (j = 0; j < w; j++) ctx->iscratch[j] |= 1L << ctx->dscratch[j]; } i--; bitmap &= ~(1L << ctx->dscratch[i]); if (ctx->dscratch[i] == best) { n--; best = 0; for (j = 0; j < i; j++) if (best < ctx->dscratch[j]) best = ctx->dscratch[j]; } } } #ifdef STANDALONE_SOLVER if (solver_show_working) sprintf(prefix, "%*sexhaustive analysis of clue %s %d:\n", solver_recurse_depth*4, "", cluepos[c/w], c%w+1); else prefix[0] = '\0'; /* placate optimiser */ #endif ret = 0; for (i = 0; i < w; i++) { int pos = start + step * i; for (j = 1; j <= w; j++) { if (solver->cube[pos*w+j-1] && !(ctx->iscratch[i] & (1L << j))) { #ifdef STANDALONE_SOLVER if (solver_show_working) { printf("%s%*s ruling out %d at (%d,%d)\n", prefix, solver_recurse_depth*4, "", j, pos/w+1, pos%w+1); prefix[0] = '\0'; } #endif solver->cube[pos*w+j-1] = 0; ret = 1; } } /* * Once we find one clue we can do something with in * this way, revert to trying easier deductions, so as * not to generate solver diagnostics that make the * problem look harder than it is. */ if (ret) return ret; } } return 0; } #define SOLVER(upper,title,func,lower) func, static usersolver_t const towers_solvers[] = { DIFFLIST(SOLVER) }; static int solver(int w, int *clues, digit *soln, int maxdiff) { int ret; struct solver_ctx ctx; ctx.w = w; ctx.diff = maxdiff; ctx.clues = clues; ctx.started = FALSE; ctx.iscratch = snewn(w, long); ctx.dscratch = snewn(w+1, int); ret = latin_solver(soln, w, maxdiff, DIFF_EASY, DIFF_HARD, DIFF_EXTREME, DIFF_EXTREME, DIFF_UNREASONABLE, towers_solvers, &ctx, NULL, NULL); sfree(ctx.iscratch); sfree(ctx.dscratch); return ret; } /* ---------------------------------------------------------------------- * Grid generation. */ static char *new_game_desc(const game_params *params, random_state *rs, char **aux, int interactive) { int w = params->w, a = w*w; digit *grid, *soln, *soln2; int *clues, *order; int i, ret; int diff = params->diff; char *desc, *p; /* * Difficulty exceptions: some combinations of size and * difficulty cannot be satisfied, because all puzzles of at * most that difficulty are actually even easier. * * Remember to re-test this whenever a change is made to the * solver logic! * * I tested it using the following shell command: for d in e h x u; do for i in {3..9}; do echo -n "./towers --generate 1 ${i}d${d}: " perl -e 'alarm 30; exec @ARGV' ./towers --generate 1 ${i}d${d} >/dev/null \ && echo ok done done * Of course, it's better to do that after taking the exceptions * _out_, so as to detect exceptions that should be removed as * well as those which should be added. */ if (diff > DIFF_HARD && w <= 3) diff = DIFF_HARD; grid = NULL; clues = snewn(4*w, int); soln = snewn(a, digit); soln2 = snewn(a, digit); order = snewn(max(4*w,a), int); while (1) { /* * Construct a latin square to be the solution. */ sfree(grid); grid = latin_generate(w, rs); /* * Fill in the clues. */ for (i = 0; i < 4*w; i++) { int start, step, j, k, best; STARTSTEP(start, step, i, w); k = best = 0; for (j = 0; j < w; j++) { if (grid[start+j*step] > best) { best = grid[start+j*step]; k++; } } clues[i] = k; } /* * Remove the grid numbers and then the clues, one by one, * for as long as the game remains soluble at the given * difficulty. */ memcpy(soln, grid, a); if (diff == DIFF_EASY && w <= 5) { /* * Special case: for Easy-mode grids that are small * enough, it's nice to be able to find completely empty * grids. */ memset(soln2, 0, a); ret = solver(w, clues, soln2, diff); if (ret > diff) continue; } for (i = 0; i < a; i++) order[i] = i; shuffle(order, a, sizeof(*order), rs); for (i = 0; i < a; i++) { int j = order[i]; memcpy(soln2, grid, a); soln2[j] = 0; ret = solver(w, clues, soln2, diff); if (ret <= diff) grid[j] = 0; } if (diff > DIFF_EASY) { /* leave all clues on Easy mode */ for (i = 0; i < 4*w; i++) order[i] = i; shuffle(order, 4*w, sizeof(*order), rs); for (i = 0; i < 4*w; i++) { int j = order[i]; int clue = clues[j]; memcpy(soln2, grid, a); clues[j] = 0; ret = solver(w, clues, soln2, diff); if (ret > diff) clues[j] = clue; } } /* * See if the game can be solved at the specified difficulty * level, but not at the one below. */ memcpy(soln2, grid, a); ret = solver(w, clues, soln2, diff); if (ret != diff) continue; /* go round again */ /* * We've got a usable puzzle! */ break; } /* * Encode the puzzle description. */ desc = snewn(40*a, char); p = desc; for (i = 0; i < 4*w; i++) { if (i) *p++ = '/'; if (clues[i]) p += sprintf(p, "%d", clues[i]); } for (i = 0; i < a; i++) if (grid[i]) break; if (i < a) { int run = 0; *p++ = ','; for (i = 0; i <= a; i++) { int n = (i < a ? grid[i] : -1); if (!n) run++; else { if (run) { while (run > 0) { int thisrun = min(run, 26); *p++ = thisrun - 1 + 'a'; run -= thisrun; } } else { /* * If there's a number in the very top left or * bottom right, there's no point putting an * unnecessary _ before or after it. */ if (i > 0 && n > 0) *p++ = '_'; } if (n > 0) p += sprintf(p, "%d", n); run = 0; } } } *p++ = '\0'; desc = sresize(desc, p - desc, char); /* * Encode the solution. */ *aux = snewn(a+2, char); (*aux)[0] = 'S'; for (i = 0; i < a; i++) (*aux)[i+1] = '0' + soln[i]; (*aux)[a+1] = '\0'; sfree(grid); sfree(clues); sfree(soln); sfree(soln2); sfree(order); return desc; } /* ---------------------------------------------------------------------- * Gameplay. */ static char *validate_desc(const game_params *params, const char *desc) { int w = params->w, a = w*w; const char *p = desc; int i, clue; /* * Verify that the right number of clues are given, and that * they're in range. */ for (i = 0; i < 4*w; i++) { if (!*p) return "Too few clues for grid size"; if (i > 0) { if (*p != '/') return "Expected commas between clues"; p++; } if (isdigit((unsigned char)*p)) { clue = atoi(p); while (*p && isdigit((unsigned char)*p)) p++; if (clue <= 0 || clue > w) return "Clue number out of range"; } } if (*p == '/') return "Too many clues for grid size"; if (*p == ',') { /* * Verify that the right amount of grid data is given, and * that any grid elements provided are in range. */ int squares = 0; p++; while (*p) { int c = *p++; if (c >= 'a' && c <= 'z') { squares += c - 'a' + 1; } else if (c == '_') { /* do nothing */; } else if (c > '0' && c <= '9') { int val = atoi(p-1); if (val < 1 || val > w) return "Out-of-range number in grid description"; squares++; while (*p && isdigit((unsigned char)*p)) p++; } else return "Invalid character in game description"; } if (squares < a) return "Not enough data to fill grid"; if (squares > a) return "Too much data to fit in grid"; } return NULL; } static game_state *new_game(midend *me, const game_params *params, const char *desc) { int w = params->w, a = w*w; game_state *state = snew(game_state); const char *p = desc; int i; state->par = *params; /* structure copy */ state->clues = snew(struct clues); state->clues->refcount = 1; state->clues->w = w; state->clues->clues = snewn(4*w, int); state->clues->immutable = snewn(a, digit); state->grid = snewn(a, digit); state->clues_done = snewn(4*w, unsigned char); state->pencil = snewn(a, int); for (i = 0; i < a; i++) { state->grid[i] = 0; state->pencil[i] = 0; } memset(state->clues->immutable, 0, a); memset(state->clues_done, 0, 4*w*sizeof(unsigned char)); for (i = 0; i < 4*w; i++) { if (i > 0) { assert(*p == '/'); p++; } if (*p && isdigit((unsigned char)*p)) { state->clues->clues[i] = atoi(p); while (*p && isdigit((unsigned char)*p)) p++; } else state->clues->clues[i] = 0; } if (*p == ',') { int pos = 0; p++; while (*p) { int c = *p++; if (c >= 'a' && c <= 'z') { pos += c - 'a' + 1; } else if (c == '_') { /* do nothing */; } else if (c > '0' && c <= '9') { int val = atoi(p-1); assert(val >= 1 && val <= w); assert(pos < a); state->grid[pos] = state->clues->immutable[pos] = val; pos++; while (*p && isdigit((unsigned char)*p)) p++; } else assert(!"Corrupt game description"); } assert(pos == a); } assert(!*p); state->completed = state->cheated = FALSE; return state; } static game_state *dup_game(const game_state *state) { int w = state->par.w, a = w*w; game_state *ret = snew(game_state); ret->par = state->par; /* structure copy */ ret->clues = state->clues; ret->clues->refcount++; ret->grid = snewn(a, digit); ret->pencil = snewn(a, int); ret->clues_done = snewn(4*w, unsigned char); memcpy(ret->grid, state->grid, a*sizeof(digit)); memcpy(ret->pencil, state->pencil, a*sizeof(int)); memcpy(ret->clues_done, state->clues_done, 4*w*sizeof(unsigned char)); ret->completed = state->completed; ret->cheated = state->cheated; return ret; } static void free_game(game_state *state) { sfree(state->grid); sfree(state->pencil); sfree(state->clues_done); if (--state->clues->refcount <= 0) { sfree(state->clues->immutable); sfree(state->clues->clues); sfree(state->clues); } sfree(state); } static char *solve_game(const game_state *state, const game_state *currstate, const char *aux, char **error) { int w = state->par.w, a = w*w; int i, ret; digit *soln; char *out; if (aux) return dupstr(aux); soln = snewn(a, digit); memcpy(soln, state->clues->immutable, a); ret = solver(w, state->clues->clues, soln, DIFFCOUNT-1); if (ret == diff_impossible) { *error = "No solution exists for this puzzle"; out = NULL; } else if (ret == diff_ambiguous) { *error = "Multiple solutions exist for this puzzle"; out = NULL; } else { out = snewn(a+2, char); out[0] = 'S'; for (i = 0; i < a; i++) out[i+1] = '0' + soln[i]; out[a+1] = '\0'; } sfree(soln); return out; } static int game_can_format_as_text_now(const game_params *params) { return TRUE; } static char *game_text_format(const game_state *state) { int w = state->par.w /* , a = w*w */; char *ret; char *p; int x, y; int total; /* * We have: * - a top clue row, consisting of three spaces, then w clue * digits with spaces between (total 2*w+3 chars including * newline) * - a blank line (one newline) * - w main rows, consisting of a left clue digit, two spaces, * w grid digits with spaces between, two spaces and a right * clue digit (total 2*w+6 chars each including newline) * - a blank line (one newline) * - a bottom clue row (same as top clue row) * - terminating NUL. * * Total size is therefore 2*(2*w+3) + 2 + w*(2*w+6) + 1 * = 2w^2+10w+9. */ total = 2*w*w + 10*w + 9; ret = snewn(total, char); p = ret; /* Top clue row. */ *p++ = ' '; *p++ = ' '; for (x = 0; x < w; x++) { *p++ = ' '; *p++ = (state->clues->clues[x] ? '0' + state->clues->clues[x] : ' '); } *p++ = '\n'; /* Blank line. */ *p++ = '\n'; /* Main grid. */ for (y = 0; y < w; y++) { *p++ = (state->clues->clues[y+2*w] ? '0' + state->clues->clues[y+2*w] : ' '); *p++ = ' '; for (x = 0; x < w; x++) { *p++ = ' '; *p++ = (state->grid[y*w+x] ? '0' + state->grid[y*w+x] : ' '); } *p++ = ' '; *p++ = ' '; *p++ = (state->clues->clues[y+3*w] ? '0' + state->clues->clues[y+3*w] : ' '); *p++ = '\n'; } /* Blank line. */ *p++ = '\n'; /* Bottom clue row. */ *p++ = ' '; *p++ = ' '; for (x = 0; x < w; x++) { *p++ = ' '; *p++ = (state->clues->clues[x+w] ? '0' + state->clues->clues[x+w] : ' '); } *p++ = '\n'; *p++ = '\0'; assert(p == ret + total); return ret; } struct game_ui { /* * These are the coordinates of the currently highlighted * square on the grid, if hshow = 1. */ int hx, hy; /* * This indicates whether the current highlight is a * pencil-mark one or a real one. */ int hpencil; /* * This indicates whether or not we're showing the highlight * (used to be hx = hy = -1); important so that when we're * using the cursor keys it doesn't keep coming back at a * fixed position. When hshow = 1, pressing a valid number * or letter key or Space will enter that number or letter in the grid. */ int hshow; /* * This indicates whether we're using the highlight as a cursor; * it means that it doesn't vanish on a keypress, and that it is * allowed on immutable squares. */ int hcursor; }; static game_ui *new_ui(const game_state *state) { game_ui *ui = snew(game_ui); ui->hx = ui->hy = 0; ui->hpencil = ui->hshow = ui->hcursor = 0; return ui; } static void free_ui(game_ui *ui) { sfree(ui); } static char *encode_ui(const game_ui *ui) { return NULL; } static void decode_ui(game_ui *ui, const char *encoding) { } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { int w = newstate->par.w; /* * We prevent pencil-mode highlighting of a filled square, unless * we're using the cursor keys. So if the user has just filled in * a square which we had a pencil-mode highlight in (by Undo, or * by Redo, or by Solve), then we cancel the highlight. */ if (ui->hshow && ui->hpencil && !ui->hcursor && newstate->grid[ui->hy * w + ui->hx] != 0) { ui->hshow = 0; } } #define PREFERRED_TILESIZE 48 #define TILESIZE (ds->tilesize) #define BORDER (TILESIZE * 9 / 8) #define COORD(x) ((x)*TILESIZE + BORDER) #define FROMCOORD(x) (((x)+(TILESIZE-BORDER)) / TILESIZE - 1) /* These always return positive values, though y offsets are actually -ve */ #define X_3D_DISP(height, w) ((height) * TILESIZE / (8 * (w))) #define Y_3D_DISP(height, w) ((height) * TILESIZE / (4 * (w))) #define FLASH_TIME 0.4F #define DF_PENCIL_SHIFT 16 #define DF_CLUE_DONE 0x10000 #define DF_ERROR 0x8000 #define DF_HIGHLIGHT 0x4000 #define DF_HIGHLIGHT_PENCIL 0x2000 #define DF_IMMUTABLE 0x1000 #define DF_PLAYAREA 0x0800 #define DF_DIGIT_MASK 0x00FF struct game_drawstate { int tilesize; int three_d; /* default 3D graphics are user-disableable */ int started; long *tiles; /* (w+2)*(w+2) temp space */ long *drawn; /* (w+2)*(w+2)*4: current drawn data */ int *errtmp; }; static int check_errors(const game_state *state, int *errors) { int w = state->par.w /*, a = w*w */; int W = w+2, A = W*W; /* the errors array is (w+2) square */ int *clues = state->clues->clues; digit *grid = state->grid; int i, x, y, errs = FALSE; int tmp[32]; assert(w < lenof(tmp)); if (errors) for (i = 0; i < A; i++) errors[i] = 0; for (y = 0; y < w; y++) { unsigned long mask = 0, errmask = 0; for (x = 0; x < w; x++) { unsigned long bit = 1UL << grid[y*w+x]; errmask |= (mask & bit); mask |= bit; } if (mask != (1L << (w+1)) - (1L << 1)) { errs = TRUE; errmask &= ~1UL; if (errors) { for (x = 0; x < w; x++) if (errmask & (1UL << grid[y*w+x])) errors[(y+1)*W+(x+1)] = TRUE; } } } for (x = 0; x < w; x++) { unsigned long mask = 0, errmask = 0; for (y = 0; y < w; y++) { unsigned long bit = 1UL << grid[y*w+x]; errmask |= (mask & bit); mask |= bit; } if (mask != (1 << (w+1)) - (1 << 1)) { errs = TRUE; errmask &= ~1UL; if (errors) { for (y = 0; y < w; y++) if (errmask & (1UL << grid[y*w+x])) errors[(y+1)*W+(x+1)] = TRUE; } } } for (i = 0; i < 4*w; i++) { int start, step, j, n, best; STARTSTEP(start, step, i, w); if (!clues[i]) continue; best = n = 0; for (j = 0; j < w; j++) { int number = grid[start+j*step]; if (!number) break; /* can't tell what happens next */ if (number > best) { best = number; n++; } } if (n > clues[i] || (best == w && n < clues[i]) || (best < w && n == clues[i])) { if (errors) { int x, y; CLUEPOS(x, y, i, w); errors[(y+1)*W+(x+1)] = TRUE; } errs = TRUE; } } return errs; } static int clue_index(const game_state *state, int x, int y) { int w = state->par.w; if (x == -1 || x == w) return w * (x == -1 ? 2 : 3) + y; else if (y == -1 || y == w) return (y == -1 ? 0 : w) + x; return -1; } static int is_clue(const game_state *state, int x, int y) { int w = state->par.w; if (((x == -1 || x == w) && y >= 0 && y < w) || ((y == -1 || y == w) && x >= 0 && x < w)) { if (state->clues->clues[clue_index(state, x, y)] & DF_DIGIT_MASK) return TRUE; } return FALSE; } static char *interpret_move(const game_state *state, game_ui *ui, const game_drawstate *ds, int x, int y, int button) { int w = state->par.w; int shift_or_control = button & (MOD_SHFT | MOD_CTRL); int tx, ty; char buf[80]; button &= ~MOD_MASK; tx = FROMCOORD(x); ty = FROMCOORD(y); if (ds->three_d) { /* * In 3D mode, just locating the mouse click in the natural * square grid may not be sufficient to tell which tower the * user clicked on. Investigate the _tops_ of the nearby * towers to see if a click on one grid square was actually * a click on a tower protruding into that region from * another. */ int dx, dy; for (dy = 0; dy <= 1; dy++) for (dx = 0; dx >= -1; dx--) { int cx = tx + dx, cy = ty + dy; if (cx >= 0 && cx < w && cy >= 0 && cy < w) { int height = state->grid[cy*w+cx]; int bx = COORD(cx), by = COORD(cy); int ox = bx + X_3D_DISP(height, w); int oy = by - Y_3D_DISP(height, w); if (/* on top face? */ (x - ox >= 0 && x - ox < TILESIZE && y - oy >= 0 && y - oy < TILESIZE) || /* in triangle between top-left corners? */ (ox > bx && x >= bx && x <= ox && y <= by && (by-y) * (ox-bx) <= (by-oy) * (x-bx)) || /* in triangle between bottom-right corners? */ (ox > bx && x >= bx+TILESIZE && x <= ox+TILESIZE && y >= oy+TILESIZE && (by-y+TILESIZE)*(ox-bx) >= (by-oy)*(x-bx-TILESIZE))) { tx = cx; ty = cy; } } } } if (tx >= 0 && tx < w && ty >= 0 && ty < w) { if (button == LEFT_BUTTON) { if (tx == ui->hx && ty == ui->hy && ui->hshow && ui->hpencil == 0) { ui->hshow = 0; } else { ui->hx = tx; ui->hy = ty; ui->hshow = !state->clues->immutable[ty*w+tx]; ui->hpencil = 0; } ui->hcursor = 0; return ""; /* UI activity occurred */ } if (button == RIGHT_BUTTON) { /* * Pencil-mode highlighting for non filled squares. */ if (state->grid[ty*w+tx] == 0) { if (tx == ui->hx && ty == ui->hy && ui->hshow && ui->hpencil) { ui->hshow = 0; } else { ui->hpencil = 1; ui->hx = tx; ui->hy = ty; ui->hshow = 1; } } else { ui->hshow = 0; } ui->hcursor = 0; return ""; /* UI activity occurred */ } } else if (button == LEFT_BUTTON) { if (is_clue(state, tx, ty)) { sprintf(buf, "%c%d,%d", 'D', tx, ty); return dupstr(buf); } } if (IS_CURSOR_MOVE(button)) { if (shift_or_control) { int x = ui->hx, y = ui->hy; switch (button) { case CURSOR_LEFT: x = -1; break; case CURSOR_RIGHT: x = w; break; case CURSOR_UP: y = -1; break; case CURSOR_DOWN: y = w; break; } if (is_clue(state, x, y)) { sprintf(buf, "%c%d,%d", 'D', x, y); return dupstr(buf); } return NULL; } move_cursor(button, &ui->hx, &ui->hy, w, w, 0); ui->hshow = ui->hcursor = 1; return ""; } if (ui->hshow && (button == CURSOR_SELECT)) { ui->hpencil = 1 - ui->hpencil; ui->hcursor = 1; return ""; } if (ui->hshow && ((button >= '0' && button <= '9' && button - '0' <= w) || button == CURSOR_SELECT2 || button == '\b')) { int n = button - '0'; if (button == CURSOR_SELECT2 || button == '\b') n = 0; /* * Can't make pencil marks in a filled square. This can only * become highlighted if we're using cursor keys. */ if (ui->hpencil && state->grid[ui->hy*w+ui->hx]) return NULL; /* * Can't do anything to an immutable square. */ if (state->clues->immutable[ui->hy*w+ui->hx]) return NULL; sprintf(buf, "%c%d,%d,%d", (char)(ui->hpencil && n > 0 ? 'P' : 'R'), ui->hx, ui->hy, n); if (!ui->hcursor) ui->hshow = 0; return dupstr(buf); } if (button == 'M' || button == 'm') return dupstr("M"); return NULL; } static game_state *execute_move(const game_state *from, const char *move) { int w = from->par.w, a = w*w; game_state *ret = dup_game(from); int x, y, i, n; if (move[0] == 'S') { ret->completed = ret->cheated = TRUE; for (i = 0; i < a; i++) { if (move[i+1] < '1' || move[i+1] > '0'+w) goto badmove; ret->grid[i] = move[i+1] - '0'; ret->pencil[i] = 0; } if (move[a+1] != '\0') goto badmove; return ret; } else if ((move[0] == 'P' || move[0] == 'R') && sscanf(move+1, "%d,%d,%d", &x, &y, &n) == 3 && x >= 0 && x < w && y >= 0 && y < w && n >= 0 && n <= w) { if (from->clues->immutable[y*w+x]) goto badmove; if (move[0] == 'P' && n > 0) { ret->pencil[y*w+x] ^= 1L << n; } else { ret->grid[y*w+x] = n; ret->pencil[y*w+x] = 0; if (!ret->completed && !check_errors(ret, NULL)) ret->completed = TRUE; } return ret; } else if (move[0] == 'M') { /* * Fill in absolutely all pencil marks everywhere. (I * wouldn't use this for actual play, but it's a handy * starting point when following through a set of * diagnostics output by the standalone solver.) */ for (i = 0; i < a; i++) { if (!ret->grid[i]) ret->pencil[i] = (1L << (w+1)) - (1L << 1); } return ret; } else if (move[0] == 'D' && sscanf(move+1, "%d,%d", &x, &y) == 2 && is_clue(from, x, y)) { int index = clue_index(from, x, y); ret->clues_done[index] = !ret->clues_done[index]; return ret; } badmove: /* couldn't parse move string */ free_game(ret); return NULL; } /* ---------------------------------------------------------------------- * Drawing routines. */ #define SIZE(w) ((w) * TILESIZE + 2*BORDER) static void game_compute_size(const game_params *params, int tilesize, int *x, int *y) { /* Ick: fake up `ds->tilesize' for macro expansion purposes */ struct { int tilesize; } ads, *ds = &ads; ads.tilesize = tilesize; *x = *y = SIZE(params->w); } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { ds->tilesize = tilesize; } static float *game_colours(frontend *fe, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float); frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]); ret[COL_GRID * 3 + 0] = 0.0F; ret[COL_GRID * 3 + 1] = 0.0F; ret[COL_GRID * 3 + 2] = 0.0F; ret[COL_USER * 3 + 0] = 0.0F; ret[COL_USER * 3 + 1] = 0.6F * ret[COL_BACKGROUND * 3 + 1]; ret[COL_USER * 3 + 2] = 0.0F; ret[COL_HIGHLIGHT * 3 + 0] = 0.78F * ret[COL_BACKGROUND * 3 + 0]; ret[COL_HIGHLIGHT * 3 + 1] = 0.78F * ret[COL_BACKGROUND * 3 + 1]; ret[COL_HIGHLIGHT * 3 + 2] = 0.78F * ret[COL_BACKGROUND * 3 + 2]; ret[COL_ERROR * 3 + 0] = 1.0F; ret[COL_ERROR * 3 + 1] = 0.0F; ret[COL_ERROR * 3 + 2] = 0.0F; ret[COL_PENCIL * 3 + 0] = 0.5F * ret[COL_BACKGROUND * 3 + 0]; ret[COL_PENCIL * 3 + 1] = 0.5F * ret[COL_BACKGROUND * 3 + 1]; ret[COL_PENCIL * 3 + 2] = ret[COL_BACKGROUND * 3 + 2]; ret[COL_DONE * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] / 1.5F; ret[COL_DONE * 3 + 1] = ret[COL_BACKGROUND * 3 + 1] / 1.5F; ret[COL_DONE * 3 + 2] = ret[COL_BACKGROUND * 3 + 2] / 1.5F; *ncolours = NCOLOURS; return ret; } static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { int w = state->par.w /*, a = w*w */; struct game_drawstate *ds = snew(struct game_drawstate); int i; ds->tilesize = 0; ds->three_d = !getenv("TOWERS_2D"); ds->started = FALSE; ds->tiles = snewn((w+2)*(w+2), long); ds->drawn = snewn((w+2)*(w+2)*4, long); for (i = 0; i < (w+2)*(w+2)*4; i++) ds->drawn[i] = -1; ds->errtmp = snewn((w+2)*(w+2), int); return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { sfree(ds->errtmp); sfree(ds->tiles); sfree(ds->drawn); sfree(ds); } static void draw_tile(drawing *dr, game_drawstate *ds, struct clues *clues, int x, int y, long tile) { int w = clues->w /* , a = w*w */; int tx, ty, bg; char str[64]; tx = COORD(x); ty = COORD(y); bg = (tile & DF_HIGHLIGHT) ? COL_HIGHLIGHT : COL_BACKGROUND; /* draw tower */ if (ds->three_d && (tile & DF_PLAYAREA) && (tile & DF_DIGIT_MASK)) { int coords[8]; int xoff = X_3D_DISP(tile & DF_DIGIT_MASK, w); int yoff = Y_3D_DISP(tile & DF_DIGIT_MASK, w); /* left face of tower */ coords[0] = tx; coords[1] = ty - 1; coords[2] = tx; coords[3] = ty + TILESIZE - 1; coords[4] = coords[2] + xoff; coords[5] = coords[3] - yoff; coords[6] = coords[0] + xoff; coords[7] = coords[1] - yoff; draw_polygon(dr, coords, 4, bg, COL_GRID); /* bottom face of tower */ coords[0] = tx + TILESIZE; coords[1] = ty + TILESIZE - 1; coords[2] = tx; coords[3] = ty + TILESIZE - 1; coords[4] = coords[2] + xoff; coords[5] = coords[3] - yoff; coords[6] = coords[0] + xoff; coords[7] = coords[1] - yoff; draw_polygon(dr, coords, 4, bg, COL_GRID); /* now offset all subsequent drawing to the top of the tower */ tx += xoff; ty -= yoff; } /* erase background */ draw_rect(dr, tx, ty, TILESIZE, TILESIZE, bg); /* pencil-mode highlight */ if (tile & DF_HIGHLIGHT_PENCIL) { int coords[6]; coords[0] = tx; coords[1] = ty; coords[2] = tx+TILESIZE/2; coords[3] = ty; coords[4] = tx; coords[5] = ty+TILESIZE/2; draw_polygon(dr, coords, 3, COL_HIGHLIGHT, COL_HIGHLIGHT); } /* draw box outline */ if (tile & DF_PLAYAREA) { int coords[8]; coords[0] = tx; coords[1] = ty - 1; coords[2] = tx + TILESIZE; coords[3] = ty - 1; coords[4] = tx + TILESIZE; coords[5] = ty + TILESIZE - 1; coords[6] = tx; coords[7] = ty + TILESIZE - 1; draw_polygon(dr, coords, 4, -1, COL_GRID); } /* new number needs drawing? */ if (tile & DF_DIGIT_MASK) { int color; str[1] = '\0'; str[0] = (tile & DF_DIGIT_MASK) + '0'; if (tile & DF_ERROR) color = COL_ERROR; else if (tile & DF_CLUE_DONE) color = COL_DONE; else if (x < 0 || y < 0 || x >= w || y >= w) color = COL_GRID; else if (tile & DF_IMMUTABLE) color = COL_GRID; else color = COL_USER; draw_text(dr, tx + TILESIZE/2, ty + TILESIZE/2, FONT_VARIABLE, (tile & DF_PLAYAREA ? TILESIZE/2 : TILESIZE*2/5), ALIGN_VCENTRE | ALIGN_HCENTRE, color, str); } else { int i, j, npencil; int pl, pr, pt, pb; float bestsize; int pw, ph, minph, pbest, fontsize; /* Count the pencil marks required. */ for (i = 1, npencil = 0; i <= w; i++) if (tile & (1L << (i + DF_PENCIL_SHIFT))) npencil++; if (npencil) { minph = 2; /* * Determine the bounding rectangle within which we're going * to put the pencil marks. */ /* Start with the whole square, minus space for impinging towers */ pl = tx + (ds->three_d ? X_3D_DISP(w,w) : 0); pr = tx + TILESIZE; pt = ty; pb = ty + TILESIZE - (ds->three_d ? Y_3D_DISP(w,w) : 0); /* * We arrange our pencil marks in a grid layout, with * the number of rows and columns adjusted to allow the * maximum font size. * * So now we work out what the grid size ought to be. */ bestsize = 0.0; pbest = 0; /* Minimum */ for (pw = 3; pw < max(npencil,4); pw++) { float fw, fh, fs; ph = (npencil + pw - 1) / pw; ph = max(ph, minph); fw = (pr - pl) / (float)pw; fh = (pb - pt) / (float)ph; fs = min(fw, fh); if (fs > bestsize) { bestsize = fs; pbest = pw; } } assert(pbest > 0); pw = pbest; ph = (npencil + pw - 1) / pw; ph = max(ph, minph); /* * Now we've got our grid dimensions, work out the pixel * size of a grid element, and round it to the nearest * pixel. (We don't want rounding errors to make the * grid look uneven at low pixel sizes.) */ fontsize = min((pr - pl) / pw, (pb - pt) / ph); /* * Centre the resulting figure in the square. */ pl = pl + (pr - pl - fontsize * pw) / 2; pt = pt + (pb - pt - fontsize * ph) / 2; /* * Now actually draw the pencil marks. */ for (i = 1, j = 0; i <= w; i++) if (tile & (1L << (i + DF_PENCIL_SHIFT))) { int dx = j % pw, dy = j / pw; str[1] = '\0'; str[0] = i + '0'; draw_text(dr, pl + fontsize * (2*dx+1) / 2, pt + fontsize * (2*dy+1) / 2, FONT_VARIABLE, fontsize, ALIGN_VCENTRE | ALIGN_HCENTRE, COL_PENCIL, str); j++; } } } } static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float animtime, float flashtime) { int w = state->par.w /*, a = w*w */; int i, x, y; if (!ds->started) { /* * The initial contents of the window are not guaranteed and * can vary with front ends. To be on the safe side, all * games should start by drawing a big background-colour * rectangle covering the whole window. */ draw_rect(dr, 0, 0, SIZE(w), SIZE(w), COL_BACKGROUND); draw_update(dr, 0, 0, SIZE(w), SIZE(w)); ds->started = TRUE; } check_errors(state, ds->errtmp); /* * Work out what data each tile should contain. */ for (i = 0; i < (w+2)*(w+2); i++) ds->tiles[i] = 0; /* completely blank square */ /* The clue squares... */ for (i = 0; i < 4*w; i++) { long tile = state->clues->clues[i]; CLUEPOS(x, y, i, w); if (ds->errtmp[(y+1)*(w+2)+(x+1)]) tile |= DF_ERROR; else if (state->clues_done[i]) tile |= DF_CLUE_DONE; ds->tiles[(y+1)*(w+2)+(x+1)] = tile; } /* ... and the main grid. */ for (y = 0; y < w; y++) { for (x = 0; x < w; x++) { long tile = DF_PLAYAREA; if (state->grid[y*w+x]) tile |= state->grid[y*w+x]; else tile |= (long)state->pencil[y*w+x] << DF_PENCIL_SHIFT; if (ui->hshow && ui->hx == x && ui->hy == y) tile |= (ui->hpencil ? DF_HIGHLIGHT_PENCIL : DF_HIGHLIGHT); if (state->clues->immutable[y*w+x]) tile |= DF_IMMUTABLE; if (flashtime > 0 && (flashtime <= FLASH_TIME/3 || flashtime >= FLASH_TIME*2/3)) tile |= DF_HIGHLIGHT; /* completion flash */ if (ds->errtmp[(y+1)*(w+2)+(x+1)]) tile |= DF_ERROR; ds->tiles[(y+1)*(w+2)+(x+1)] = tile; } } /* * Now actually draw anything that needs to be changed. */ for (y = 0; y < w+2; y++) { for (x = 0; x < w+2; x++) { long tl, tr, bl, br; int i = y*(w+2)+x; tr = ds->tiles[y*(w+2)+x]; tl = (x == 0 ? 0 : ds->tiles[y*(w+2)+(x-1)]); br = (y == w+1 ? 0 : ds->tiles[(y+1)*(w+2)+x]); bl = (x == 0 || y == w+1 ? 0 : ds->tiles[(y+1)*(w+2)+(x-1)]); if (ds->drawn[i*4] != tl || ds->drawn[i*4+1] != tr || ds->drawn[i*4+2] != bl || ds->drawn[i*4+3] != br) { clip(dr, COORD(x-1), COORD(y-1), TILESIZE, TILESIZE); draw_tile(dr, ds, state->clues, x-1, y-1, tr); if (x > 0) draw_tile(dr, ds, state->clues, x-2, y-1, tl); if (y <= w) draw_tile(dr, ds, state->clues, x-1, y, br); if (x > 0 && y <= w) draw_tile(dr, ds, state->clues, x-2, y, bl); unclip(dr); draw_update(dr, COORD(x-1), COORD(y-1), TILESIZE, TILESIZE); ds->drawn[i*4] = tl; ds->drawn[i*4+1] = tr; ds->drawn[i*4+2] = bl; ds->drawn[i*4+3] = br; } } } } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return 0.0F; } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { if (!oldstate->completed && newstate->completed && !oldstate->cheated && !newstate->cheated) return FLASH_TIME; return 0.0F; } static int game_status(const game_state *state) { return state->completed ? +1 : 0; } static int game_timing_state(const game_state *state, game_ui *ui) { if (state->completed) return FALSE; return TRUE; } static void game_print_size(const game_params *params, float *x, float *y) { int pw, ph; /* * We use 9mm squares by default, like Solo. */ game_compute_size(params, 900, &pw, &ph); *x = pw / 100.0F; *y = ph / 100.0F; } static void game_print(drawing *dr, const game_state *state, int tilesize) { int w = state->par.w; int ink = print_mono_colour(dr, 0); int i, x, y; /* Ick: fake up `ds->tilesize' for macro expansion purposes */ game_drawstate ads, *ds = &ads; game_set_size(dr, ds, NULL, tilesize); /* * Border. */ print_line_width(dr, 3 * TILESIZE / 40); draw_rect_outline(dr, BORDER, BORDER, w*TILESIZE, w*TILESIZE, ink); /* * Main grid. */ for (x = 1; x < w; x++) { print_line_width(dr, TILESIZE / 40); draw_line(dr, BORDER+x*TILESIZE, BORDER, BORDER+x*TILESIZE, BORDER+w*TILESIZE, ink); } for (y = 1; y < w; y++) { print_line_width(dr, TILESIZE / 40); draw_line(dr, BORDER, BORDER+y*TILESIZE, BORDER+w*TILESIZE, BORDER+y*TILESIZE, ink); } /* * Clues. */ for (i = 0; i < 4*w; i++) { char str[128]; if (!state->clues->clues[i]) continue; CLUEPOS(x, y, i, w); sprintf (str, "%d", state->clues->clues[i]); draw_text(dr, BORDER + x*TILESIZE + TILESIZE/2, BORDER + y*TILESIZE + TILESIZE/2, FONT_VARIABLE, TILESIZE/2, ALIGN_VCENTRE | ALIGN_HCENTRE, ink, str); } /* * Numbers for the solution, if any. */ for (y = 0; y < w; y++) for (x = 0; x < w; x++) if (state->grid[y*w+x]) { char str[2]; str[1] = '\0'; str[0] = state->grid[y*w+x] + '0'; draw_text(dr, BORDER + x*TILESIZE + TILESIZE/2, BORDER + y*TILESIZE + TILESIZE/2, FONT_VARIABLE, TILESIZE/2, ALIGN_VCENTRE | ALIGN_HCENTRE, ink, str); } } #ifdef COMBINED #define thegame towers #endif const struct game thegame = { "Towers", "games.towers", "towers", default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, TRUE, solve_game, TRUE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, PREFERRED_TILESIZE, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, TRUE, FALSE, game_print_size, game_print, FALSE, /* wants_statusbar */ FALSE, game_timing_state, REQUIRE_RBUTTON | REQUIRE_NUMPAD, /* flags */ }; #ifdef STANDALONE_SOLVER #include int main(int argc, char **argv) { game_params *p; game_state *s; char *id = NULL, *desc, *err; int grade = FALSE; int ret, diff, really_show_working = FALSE; while (--argc > 0) { char *p = *++argv; if (!strcmp(p, "-v")) { really_show_working = TRUE; } else if (!strcmp(p, "-g")) { grade = TRUE; } else if (*p == '-') { fprintf(stderr, "%s: unrecognised option `%s'\n", argv[0], p); return 1; } else { id = p; } } if (!id) { fprintf(stderr, "usage: %s [-g | -v] \n", argv[0]); return 1; } desc = strchr(id, ':'); if (!desc) { fprintf(stderr, "%s: game id expects a colon in it\n", argv[0]); return 1; } *desc++ = '\0'; p = default_params(); decode_params(p, id); err = validate_desc(p, desc); if (err) { fprintf(stderr, "%s: %s\n", argv[0], err); return 1; } s = new_game(NULL, p, desc); /* * When solving an Easy puzzle, we don't want to bother the * user with Hard-level deductions. For this reason, we grade * the puzzle internally before doing anything else. */ ret = -1; /* placate optimiser */ solver_show_working = FALSE; for (diff = 0; diff < DIFFCOUNT; diff++) { memcpy(s->grid, s->clues->immutable, p->w * p->w); ret = solver(p->w, s->clues->clues, s->grid, diff); if (ret <= diff) break; } if (diff == DIFFCOUNT) { if (grade) printf("Difficulty rating: ambiguous\n"); else printf("Unable to find a unique solution\n"); } else { if (grade) { if (ret == diff_impossible) printf("Difficulty rating: impossible (no solution exists)\n"); else printf("Difficulty rating: %s\n", towers_diffnames[ret]); } else { solver_show_working = really_show_working; memcpy(s->grid, s->clues->immutable, p->w * p->w); ret = solver(p->w, s->clues->clues, s->grid, diff); if (ret != diff) printf("Puzzle is inconsistent\n"); else fputs(game_text_format(s), stdout); } } return 0; } #endif /* vim: set shiftwidth=4 tabstop=8: */ puzzles-20170606.272beef/tents.c0000644000175000017500000024265013115373615015203 0ustar simonsimon/* * tents.c: Puzzle involving placing tents next to trees subject to * some confusing conditions. * * TODO: * * - it might be nice to make setter-provided tent/nontent clues * inviolable? * * on the other hand, this would introduce considerable extra * complexity and size into the game state; also inviolable * clues would have to be marked as such somehow, in an * intrusive and annoying manner. Since they're never * generated by _my_ generator, I'm currently more inclined * not to bother. * * - more difficult levels at the top end? * * for example, sometimes we can deduce that two BLANKs in * the same row are each adjacent to the same unattached tree * and to nothing else, implying that they can't both be * tents; this enables us to rule out some extra combinations * in the row-based deduction loop, and hence deduce more * from the number in that row than we could otherwise do. * * that by itself doesn't seem worth implementing a new * difficulty level for, but if I can find a few more things * like that then it might become worthwhile. * * I wonder if there's a sensible heuristic for where to * guess which would make a recursive solver viable? */ #include #include #include #include #include #include #include "puzzles.h" #include "maxflow.h" /* * Design discussion * ----------------- * * The rules of this puzzle as available on the WWW are poorly * specified. The bits about tents having to be orthogonally * adjacent to trees, tents not being even diagonally adjacent to * one another, and the number of tents in each row and column * being given are simple enough; the difficult bit is the * tent-to-tree matching. * * Some sources use simplistic wordings such as `each tree is * exactly connected to only one tent', which is extremely unclear: * it's easy to read erroneously as `each tree is _orthogonally * adjacent_ to exactly one tent', which is definitely incorrect. * Even the most coherent sources I've found don't do a much better * job of stating the rule. * * A more precise statement of the rule is that it must be possible * to find a bijection f between tents and trees such that each * tree T is orthogonally adjacent to the tent f(T), but that a * tent is permitted to be adjacent to other trees in addition to * its own. This slightly non-obvious criterion is what gives this * puzzle most of its subtlety. * * However, there's a particularly subtle ambiguity left over. Is * the bijection between tents and trees required to be _unique_? * In other words, is that bijection conceptually something the * player should be able to exhibit as part of the solution (even * if they aren't actually required to do so)? Or is it sufficient * to have a unique _placement_ of the tents which gives rise to at * least one suitable bijection? * * The puzzle shown to the right of this .T. 2 *T* 2 * paragraph illustrates the problem. There T.T 0 -> T-T 0 * are two distinct bijections available. .T. 2 *T* 2 * The answer to the above question will * determine whether it's a valid puzzle. 202 202 * * This is an important question, because it affects both the * player and the generator. Eventually I found all the instances * of this puzzle I could Google up, solved them all by hand, and * verified that in all cases the tree/tent matching was uniquely * determined given the tree and tent positions. Therefore, the * puzzle as implemented in this source file takes the following * policy: * * - When checking a user-supplied solution for correctness, only * verify that there exists _at least_ one matching. * - When generating a puzzle, enforce that there must be * _exactly_ one. * * Algorithmic implications * ------------------------ * * Another way of phrasing the tree/tent matching criterion is to * say that the bipartite adjacency graph between trees and tents * has a perfect matching. That is, if you construct a graph which * has a vertex per tree and a vertex per tent, and an edge between * any tree and tent which are orthogonally adjacent, it is * possible to find a set of N edges of that graph (where N is the * number of trees and also the number of tents) which between them * connect every tree to every tent. * * The most efficient known algorithms for finding such a matching * given a graph, as far as I'm aware, are the Munkres assignment * algorithm (also known as the Hungarian algorithm) and the * Ford-Fulkerson algorithm (for finding optimal flows in * networks). Each of these takes O(N^3) running time; so we're * talking O(N^3) time to verify any candidate solution to this * puzzle. That's just about OK if you're doing it once per mouse * click (and in fact not even that, since the sensible thing to do * is check all the _other_ puzzle criteria and only wade into this * quagmire if none are violated); but if the solver had to keep * doing N^3 work internally, then it would probably end up with * more like N^5 or N^6 running time, and grid generation would * become very clunky. * * Fortunately, I've been able to prove a very useful property of * _unique_ perfect matchings, by adapting the proof of Hall's * Marriage Theorem. For those unaware of Hall's Theorem, I'll * recap it and its proof: it states that a bipartite graph * contains a perfect matching iff every set of vertices on the * left side of the graph have a neighbourhood _at least_ as big on * the right. * * This condition is obviously satisfied if a perfect matching does * exist; each left-side node has a distinct right-side node which * is the one assigned to it by the matching, and thus any set of n * left vertices must have a combined neighbourhood containing at * least the n corresponding right vertices, and possibly others * too. Alternatively, imagine if you had (say) three left-side * nodes all of which were connected to only two right-side nodes * between them: any perfect matching would have to assign one of * those two right nodes to each of the three left nodes, and still * give the three left nodes a different right node each. This is * of course impossible. * * To prove the converse (that if every subset of left vertices * satisfies the Hall condition then a perfect matching exists), * consider trying to find a proper subset of the left vertices * which _exactly_ satisfies the Hall condition: that is, its right * neighbourhood is precisely the same size as it. If we can find * such a subset, then we can split the bipartite graph into two * smaller ones: one consisting of the left subset and its right * neighbourhood, the other consisting of everything else. Edges * from the left side of the former graph to the right side of the * latter do not exist, by construction; edges from the right side * of the former to the left of the latter cannot be part of any * perfect matching because otherwise the left subset would not be * left with enough distinct right vertices to connect to (this is * exactly the same deduction used in Solo's set analysis). You can * then prove (left as an exercise) that both these smaller graphs * still satisfy the Hall condition, and therefore the proof will * follow by induction. * * There's one other possibility, which is the case where _no_ * proper subset of the left vertices has a right neighbourhood of * exactly the same size. That is, every left subset has a strictly * _larger_ right neighbourhood. In this situation, we can simply * remove an _arbitrary_ edge from the graph. This cannot reduce * the size of any left subset's right neighbourhood by more than * one, so if all neighbourhoods were strictly bigger than they * needed to be initially, they must now still be _at least as big_ * as they need to be. So we can keep throwing out arbitrary edges * until we find a set which exactly satisfies the Hall condition, * and then proceed as above. [] * * That's Hall's theorem. I now build on this by examining the * circumstances in which a bipartite graph can have a _unique_ * perfect matching. It is clear that in the second case, where no * left subset exactly satisfies the Hall condition and so we can * remove an arbitrary edge, there cannot be a unique perfect * matching: given one perfect matching, we choose our arbitrary * removed edge to be one of those contained in it, and then we can * still find a perfect matching in the remaining graph, which will * be a distinct perfect matching in the original. * * So it is a necessary condition for a unique perfect matching * that there must be at least one proper left subset which * _exactly_ satisfies the Hall condition. But now consider the * smaller graph constructed by taking that left subset and its * neighbourhood: if the graph as a whole had a unique perfect * matching, then so must this smaller one, which means we can find * a proper left subset _again_, and so on. Repeating this process * must eventually reduce us to a graph with only one left-side * vertex (so there are no proper subsets at all); this vertex must * be connected to only one right-side vertex, and hence must be so * in the original graph as well (by construction). So we can * discard this vertex pair from the graph, and any other edges * that involved it (which will by construction be from other left * vertices only), and the resulting smaller graph still has a * unique perfect matching which means we can do the same thing * again. * * In other words, given any bipartite graph with a unique perfect * matching, we can find that matching by the following extremely * simple algorithm: * * - Find a left-side vertex which is only connected to one * right-side vertex. * - Assign those vertices to one another, and therefore discard * any other edges connecting to that right vertex. * - Repeat until all vertices have been matched. * * This algorithm can be run in O(V+E) time (where V is the number * of vertices and E is the number of edges in the graph), and the * only way it can fail is if there is not a unique perfect * matching (either because there is no matching at all, or because * it isn't unique; but it can't distinguish those cases). * * Thus, the internal solver in this source file can be confident * that if the tree/tent matching is uniquely determined by the * tree and tent positions, it can find it using only this kind of * obvious and simple operation: assign a tree to a tent if it * cannot possibly belong to any other tent, and vice versa. If the * solver were _only_ trying to determine the matching, even that * `vice versa' wouldn't be required; but it can come in handy when * not all the tents have been placed yet. I can therefore be * reasonably confident that as long as my solver doesn't need to * cope with grids that have a non-unique matching, it will also * not need to do anything complicated like set analysis between * trees and tents. */ /* * In standalone solver mode, `verbose' is a variable which can be * set by command-line option; in debugging mode it's simply always * true. */ #if defined STANDALONE_SOLVER #define SOLVER_DIAGNOSTICS int verbose = FALSE; #elif defined SOLVER_DIAGNOSTICS #define verbose TRUE #endif /* * Difficulty levels. I do some macro ickery here to ensure that my * enum and the various forms of my name list always match up. */ #define DIFFLIST(A) \ A(EASY,Easy,e) \ A(TRICKY,Tricky,t) #define ENUM(upper,title,lower) DIFF_ ## upper, #define TITLE(upper,title,lower) #title, #define ENCODE(upper,title,lower) #lower #define CONFIG(upper,title,lower) ":" #title enum { DIFFLIST(ENUM) DIFFCOUNT }; static char const *const tents_diffnames[] = { DIFFLIST(TITLE) }; static char const tents_diffchars[] = DIFFLIST(ENCODE); #define DIFFCONFIG DIFFLIST(CONFIG) enum { COL_BACKGROUND, COL_GRID, COL_GRASS, COL_TREETRUNK, COL_TREELEAF, COL_TENT, COL_ERROR, COL_ERRTEXT, COL_ERRTRUNK, NCOLOURS }; enum { BLANK, TREE, TENT, NONTENT, MAGIC }; struct game_params { int w, h; int diff; }; struct numbers { int refcount; int *numbers; }; struct game_state { game_params p; char *grid; struct numbers *numbers; int completed, used_solve; }; static game_params *default_params(void) { game_params *ret = snew(game_params); ret->w = ret->h = 8; ret->diff = DIFF_EASY; return ret; } static const struct game_params tents_presets[] = { {8, 8, DIFF_EASY}, {8, 8, DIFF_TRICKY}, {10, 10, DIFF_EASY}, {10, 10, DIFF_TRICKY}, {15, 15, DIFF_EASY}, {15, 15, DIFF_TRICKY}, }; static int game_fetch_preset(int i, char **name, game_params **params) { game_params *ret; char str[80]; if (i < 0 || i >= lenof(tents_presets)) return FALSE; ret = snew(game_params); *ret = tents_presets[i]; sprintf(str, "%dx%d %s", ret->w, ret->h, tents_diffnames[ret->diff]); *name = dupstr(str); *params = ret; return TRUE; } static void free_params(game_params *params) { sfree(params); } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } static void decode_params(game_params *params, char const *string) { params->w = params->h = atoi(string); while (*string && isdigit((unsigned char)*string)) string++; if (*string == 'x') { string++; params->h = atoi(string); while (*string && isdigit((unsigned char)*string)) string++; } if (*string == 'd') { int i; string++; for (i = 0; i < DIFFCOUNT; i++) if (*string == tents_diffchars[i]) params->diff = i; if (*string) string++; } } static char *encode_params(const game_params *params, int full) { char buf[120]; sprintf(buf, "%dx%d", params->w, params->h); if (full) sprintf(buf + strlen(buf), "d%c", tents_diffchars[params->diff]); return dupstr(buf); } static config_item *game_configure(const game_params *params) { config_item *ret; char buf[80]; ret = snewn(4, config_item); ret[0].name = "Width"; ret[0].type = C_STRING; sprintf(buf, "%d", params->w); ret[0].sval = dupstr(buf); ret[0].ival = 0; ret[1].name = "Height"; ret[1].type = C_STRING; sprintf(buf, "%d", params->h); ret[1].sval = dupstr(buf); ret[1].ival = 0; ret[2].name = "Difficulty"; ret[2].type = C_CHOICES; ret[2].sval = DIFFCONFIG; ret[2].ival = params->diff; ret[3].name = NULL; ret[3].type = C_END; ret[3].sval = NULL; ret[3].ival = 0; return ret; } static game_params *custom_params(const config_item *cfg) { game_params *ret = snew(game_params); ret->w = atoi(cfg[0].sval); ret->h = atoi(cfg[1].sval); ret->diff = cfg[2].ival; return ret; } static char *validate_params(const game_params *params, int full) { /* * Generating anything under 4x4 runs into trouble of one kind * or another. */ if (params->w < 4 || params->h < 4) return "Width and height must both be at least four"; return NULL; } /* * Scratch space for solver. */ enum { N, U, L, R, D, MAXDIR }; /* link directions */ #define dx(d) ( ((d)==R) - ((d)==L) ) #define dy(d) ( ((d)==D) - ((d)==U) ) #define F(d) ( U + D - (d) ) struct solver_scratch { char *links; /* mapping between trees and tents */ int *locs; char *place, *mrows, *trows; }; static struct solver_scratch *new_scratch(int w, int h) { struct solver_scratch *ret = snew(struct solver_scratch); ret->links = snewn(w*h, char); ret->locs = snewn(max(w, h), int); ret->place = snewn(max(w, h), char); ret->mrows = snewn(3 * max(w, h), char); ret->trows = snewn(3 * max(w, h), char); return ret; } static void free_scratch(struct solver_scratch *sc) { sfree(sc->trows); sfree(sc->mrows); sfree(sc->place); sfree(sc->locs); sfree(sc->links); sfree(sc); } /* * Solver. Returns 0 for impossibility, 1 for success, 2 for * ambiguity or failure to converge. */ static int tents_solve(int w, int h, const char *grid, int *numbers, char *soln, struct solver_scratch *sc, int diff) { int x, y, d, i, j; char *mrow, *trow, *trow1, *trow2; /* * Set up solver data. */ memset(sc->links, N, w*h); /* * Set up solution array. */ memcpy(soln, grid, w*h); /* * Main solver loop. */ while (1) { int done_something = FALSE; /* * Any tent which has only one unattached tree adjacent to * it can be tied to that tree. */ for (y = 0; y < h; y++) for (x = 0; x < w; x++) if (soln[y*w+x] == TENT && !sc->links[y*w+x]) { int linkd = 0; for (d = 1; d < MAXDIR; d++) { int x2 = x + dx(d), y2 = y + dy(d); if (x2 >= 0 && x2 < w && y2 >= 0 && y2 < h && soln[y2*w+x2] == TREE && !sc->links[y2*w+x2]) { if (linkd) break; /* found more than one */ else linkd = d; } } if (d == MAXDIR && linkd == 0) { #ifdef SOLVER_DIAGNOSTICS if (verbose) printf("tent at %d,%d cannot link to anything\n", x, y); #endif return 0; /* no solution exists */ } else if (d == MAXDIR) { int x2 = x + dx(linkd), y2 = y + dy(linkd); #ifdef SOLVER_DIAGNOSTICS if (verbose) printf("tent at %d,%d can only link to tree at" " %d,%d\n", x, y, x2, y2); #endif sc->links[y*w+x] = linkd; sc->links[y2*w+x2] = F(linkd); done_something = TRUE; } } if (done_something) continue; if (diff < 0) break; /* don't do anything else! */ /* * Mark a blank square as NONTENT if it is not orthogonally * adjacent to any unmatched tree. */ for (y = 0; y < h; y++) for (x = 0; x < w; x++) if (soln[y*w+x] == BLANK) { int can_be_tent = FALSE; for (d = 1; d < MAXDIR; d++) { int x2 = x + dx(d), y2 = y + dy(d); if (x2 >= 0 && x2 < w && y2 >= 0 && y2 < h && soln[y2*w+x2] == TREE && !sc->links[y2*w+x2]) can_be_tent = TRUE; } if (!can_be_tent) { #ifdef SOLVER_DIAGNOSTICS if (verbose) printf("%d,%d cannot be a tent (no adjacent" " unmatched tree)\n", x, y); #endif soln[y*w+x] = NONTENT; done_something = TRUE; } } if (done_something) continue; /* * Mark a blank square as NONTENT if it is (perhaps * diagonally) adjacent to any other tent. */ for (y = 0; y < h; y++) for (x = 0; x < w; x++) if (soln[y*w+x] == BLANK) { int dx, dy, imposs = FALSE; for (dy = -1; dy <= +1; dy++) for (dx = -1; dx <= +1; dx++) if (dy || dx) { int x2 = x + dx, y2 = y + dy; if (x2 >= 0 && x2 < w && y2 >= 0 && y2 < h && soln[y2*w+x2] == TENT) imposs = TRUE; } if (imposs) { #ifdef SOLVER_DIAGNOSTICS if (verbose) printf("%d,%d cannot be a tent (adjacent tent)\n", x, y); #endif soln[y*w+x] = NONTENT; done_something = TRUE; } } if (done_something) continue; /* * Any tree which has exactly one {unattached tent, BLANK} * adjacent to it must have its tent in that square. */ for (y = 0; y < h; y++) for (x = 0; x < w; x++) if (soln[y*w+x] == TREE && !sc->links[y*w+x]) { int linkd = 0, linkd2 = 0, nd = 0; for (d = 1; d < MAXDIR; d++) { int x2 = x + dx(d), y2 = y + dy(d); if (!(x2 >= 0 && x2 < w && y2 >= 0 && y2 < h)) continue; if (soln[y2*w+x2] == BLANK || (soln[y2*w+x2] == TENT && !sc->links[y2*w+x2])) { if (linkd) linkd2 = d; else linkd = d; nd++; } } if (nd == 0) { #ifdef SOLVER_DIAGNOSTICS if (verbose) printf("tree at %d,%d cannot link to anything\n", x, y); #endif return 0; /* no solution exists */ } else if (nd == 1) { int x2 = x + dx(linkd), y2 = y + dy(linkd); #ifdef SOLVER_DIAGNOSTICS if (verbose) printf("tree at %d,%d can only link to tent at" " %d,%d\n", x, y, x2, y2); #endif soln[y2*w+x2] = TENT; sc->links[y*w+x] = linkd; sc->links[y2*w+x2] = F(linkd); done_something = TRUE; } else if (nd == 2 && (!dx(linkd) != !dx(linkd2)) && diff >= DIFF_TRICKY) { /* * If there are two possible places where * this tree's tent can go, and they are * diagonally separated rather than being * on opposite sides of the tree, then the * square (other than the tree square) * which is adjacent to both of them must * be a non-tent. */ int x2 = x + dx(linkd) + dx(linkd2); int y2 = y + dy(linkd) + dy(linkd2); assert(x2 >= 0 && x2 < w && y2 >= 0 && y2 < h); if (soln[y2*w+x2] == BLANK) { #ifdef SOLVER_DIAGNOSTICS if (verbose) printf("possible tent locations for tree at" " %d,%d rule out tent at %d,%d\n", x, y, x2, y2); #endif soln[y2*w+x2] = NONTENT; done_something = TRUE; } } } if (done_something) continue; /* * If localised deductions about the trees and tents * themselves haven't helped us, it's time to resort to the * numbers round the grid edge. For each row and column, we * go through all possible combinations of locations for * the unplaced tents, rule out any which have adjacent * tents, and spot any square which is given the same state * by all remaining combinations. */ for (i = 0; i < w+h; i++) { int start, step, len, start1, start2, n, k; if (i < w) { /* * This is the number for a column. */ start = i; step = w; len = h; if (i > 0) start1 = start - 1; else start1 = -1; if (i+1 < w) start2 = start + 1; else start2 = -1; } else { /* * This is the number for a row. */ start = (i-w)*w; step = 1; len = w; if (i > w) start1 = start - w; else start1 = -1; if (i+1 < w+h) start2 = start + w; else start2 = -1; } if (diff < DIFF_TRICKY) { /* * In Easy mode, we don't look at the effect of one * row on the next (i.e. ruling out a square if all * possibilities for an adjacent row place a tent * next to it). */ start1 = start2 = -1; } k = numbers[i]; /* * Count and store the locations of the free squares, * and also count the number of tents already placed. */ n = 0; for (j = 0; j < len; j++) { if (soln[start+j*step] == TENT) k--; /* one fewer tent to place */ else if (soln[start+j*step] == BLANK) sc->locs[n++] = j; } if (n == 0) continue; /* nothing left to do here */ /* * Now we know we're placing k tents in n squares. Set * up the first possibility. */ for (j = 0; j < n; j++) sc->place[j] = (j < k ? TENT : NONTENT); /* * We're aiming to find squares in this row which are * invariant over all valid possibilities. Thus, we * maintain the current state of that invariance. We * start everything off at MAGIC to indicate that it * hasn't been set up yet. */ mrow = sc->mrows; trow = sc->trows; trow1 = sc->trows + len; trow2 = sc->trows + 2*len; memset(mrow, MAGIC, 3*len); /* * And iterate over all possibilities. */ while (1) { int p, valid; /* * See if this possibility is valid. The only way * it can fail to be valid is if it contains two * adjacent tents. (Other forms of invalidity, such * as containing a tent adjacent to one already * placed, will have been dealt with already by * other parts of the solver.) */ valid = TRUE; for (j = 0; j+1 < n; j++) if (sc->place[j] == TENT && sc->place[j+1] == TENT && sc->locs[j+1] == sc->locs[j]+1) { valid = FALSE; break; } if (valid) { /* * Merge this valid combination into mrow. */ memset(trow, MAGIC, len); memset(trow+len, BLANK, 2*len); for (j = 0; j < n; j++) { trow[sc->locs[j]] = sc->place[j]; if (sc->place[j] == TENT) { int jj; for (jj = sc->locs[j]-1; jj <= sc->locs[j]+1; jj++) if (jj >= 0 && jj < len) trow1[jj] = trow2[jj] = NONTENT; } } for (j = 0; j < 3*len; j++) { if (trow[j] == MAGIC) continue; if (mrow[j] == MAGIC || mrow[j] == trow[j]) { /* * Either this is the first valid * placement we've found at all, or * this square's contents are * consistent with every previous valid * combination. */ mrow[j] = trow[j]; } else { /* * This square's contents fail to match * what they were in a different * combination, so we cannot deduce * anything about this square. */ mrow[j] = BLANK; } } } /* * Find the next combination of k choices from n. * We do this by finding the rightmost tent which * can be moved one place right, doing so, and * shunting all tents to the right of that as far * left as they can go. */ p = 0; for (j = n-1; j > 0; j--) { if (sc->place[j] == TENT) p++; if (sc->place[j] == NONTENT && sc->place[j-1] == TENT) { sc->place[j-1] = NONTENT; sc->place[j] = TENT; while (p--) sc->place[++j] = TENT; while (++j < n) sc->place[j] = NONTENT; break; } } if (j <= 0) break; /* we've finished */ } /* * It's just possible that _no_ placement was valid, in * which case we have an internally inconsistent * puzzle. */ if (mrow[sc->locs[0]] == MAGIC) return 0; /* inconsistent */ /* * Now go through mrow and see if there's anything * we've deduced which wasn't already mentioned in soln. */ for (j = 0; j < len; j++) { int whichrow; for (whichrow = 0; whichrow < 3; whichrow++) { char *mthis = mrow + whichrow * len; int tstart = (whichrow == 0 ? start : whichrow == 1 ? start1 : start2); if (tstart >= 0 && mthis[j] != MAGIC && mthis[j] != BLANK && soln[tstart+j*step] == BLANK) { int pos = tstart+j*step; #ifdef SOLVER_DIAGNOSTICS if (verbose) printf("%s %d forces %s at %d,%d\n", step==1 ? "row" : "column", step==1 ? start/w : start, mthis[j] == TENT ? "tent" : "non-tent", pos % w, pos / w); #endif soln[pos] = mthis[j]; done_something = TRUE; } } } } if (done_something) continue; if (!done_something) break; } /* * The solver has nothing further it can do. Return 1 if both * soln and sc->links are completely filled in, or 2 otherwise. */ for (y = 0; y < h; y++) for (x = 0; x < w; x++) { if (soln[y*w+x] == BLANK) return 2; if (soln[y*w+x] != NONTENT && sc->links[y*w+x] == 0) return 2; } return 1; } static char *new_game_desc(const game_params *params_in, random_state *rs, char **aux, int interactive) { game_params params_copy = *params_in; /* structure copy */ game_params *params = ¶ms_copy; int w = params->w, h = params->h; int ntrees = w * h / 5; char *grid = snewn(w*h, char); char *puzzle = snewn(w*h, char); int *numbers = snewn(w+h, int); char *soln = snewn(w*h, char); int *temp = snewn(2*w*h, int); int maxedges = ntrees*4 + w*h; int *edges = snewn(2*maxedges, int); int *capacity = snewn(maxedges, int); int *flow = snewn(maxedges, int); struct solver_scratch *sc = new_scratch(w, h); char *ret, *p; int i, j, nedges; /* * Since this puzzle has many global deductions and doesn't * permit limited clue sets, generating grids for this puzzle * is hard enough that I see no better option than to simply * generate a solution and see if it's unique and has the * required difficulty. This turns out to be computationally * plausible as well. * * We chose our tree count (hence also tent count) by dividing * the total grid area by five above. Why five? Well, w*h/4 is * the maximum number of tents you can _possibly_ fit into the * grid without violating the separation criterion, and to * achieve that you are constrained to a very small set of * possible layouts (the obvious one with a tent at every * (even,even) coordinate, and trivial variations thereon). So * if we reduce the tent count a bit more, we enable more * random-looking placement; 5 turns out to be a plausible * figure which yields sensible puzzles. Increasing the tent * count would give puzzles whose solutions were too regimented * and could be solved by the use of that knowledge (and would * also take longer to find a viable placement); decreasing it * would make the grids emptier and more boring. * * Actually generating a grid is a matter of first placing the * tents, and then placing the trees by the use of maxflow * (finding a distinct square adjacent to every tent). We do it * this way round because otherwise satisfying the tent * separation condition would become onerous: most randomly * chosen tent layouts do not satisfy this condition, so we'd * have gone to a lot of work before finding that a candidate * layout was unusable. Instead, we place the tents first and * ensure they meet the separation criterion _before_ doing * lots of computation; this works much better. * * The maxflow algorithm is not randomised, so employed naively * it would give rise to grids with clear structure and * directional bias. Hence, I assign the network nodes as seen * by maxflow to be a _random_ permutation of the squares of * the grid, so that any bias shown by maxflow towards * low-numbered nodes is turned into a random bias. * * This generation strategy can fail at many points, including * as early as tent placement (if you get a bad random order in * which to greedily try the grid squares, you won't even * manage to find enough mutually non-adjacent squares to put * the tents in). Then it can fail if maxflow doesn't manage to * find a good enough matching (i.e. the tent placements don't * admit any adequate tree placements); and finally it can fail * if the solver finds that the problem has the wrong * difficulty (including being actually non-unique). All of * these, however, are insufficiently frequent to cause * trouble. */ if (params->diff > DIFF_EASY && params->w <= 4 && params->h <= 4) params->diff = DIFF_EASY; /* downgrade to prevent tight loop */ while (1) { /* * Arrange the grid squares into a random order. */ for (i = 0; i < w*h; i++) temp[i] = i; shuffle(temp, w*h, sizeof(*temp), rs); /* * The first `ntrees' entries in temp which we can get * without making two tents adjacent will be the tent * locations. */ memset(grid, BLANK, w*h); j = ntrees; for (i = 0; i < w*h && j > 0; i++) { int x = temp[i] % w, y = temp[i] / w; int dy, dx, ok = TRUE; for (dy = -1; dy <= +1; dy++) for (dx = -1; dx <= +1; dx++) if (x+dx >= 0 && x+dx < w && y+dy >= 0 && y+dy < h && grid[(y+dy)*w+(x+dx)] == TENT) ok = FALSE; if (ok) { grid[temp[i]] = TENT; j--; } } if (j > 0) continue; /* couldn't place all the tents */ /* * Now we build up the list of graph edges. */ nedges = 0; for (i = 0; i < w*h; i++) { if (grid[temp[i]] == TENT) { for (j = 0; j < w*h; j++) { if (grid[temp[j]] != TENT) { int xi = temp[i] % w, yi = temp[i] / w; int xj = temp[j] % w, yj = temp[j] / w; if (abs(xi-xj) + abs(yi-yj) == 1) { edges[nedges*2] = i; edges[nedges*2+1] = j; capacity[nedges] = 1; nedges++; } } } } else { /* * Special node w*h is the sink node; any non-tent node * has an edge going to it. */ edges[nedges*2] = i; edges[nedges*2+1] = w*h; capacity[nedges] = 1; nedges++; } } /* * Special node w*h+1 is the source node, with an edge going to * every tent. */ for (i = 0; i < w*h; i++) { if (grid[temp[i]] == TENT) { edges[nedges*2] = w*h+1; edges[nedges*2+1] = i; capacity[nedges] = 1; nedges++; } } assert(nedges <= maxedges); /* * Now we're ready to call the maxflow algorithm to place the * trees. */ j = maxflow(w*h+2, w*h+1, w*h, nedges, edges, capacity, flow, NULL); if (j < ntrees) continue; /* couldn't place all the trees */ /* * We've placed the trees. Now we need to work out _where_ * we've placed them, which is a matter of reading back out * from the `flow' array. */ for (i = 0; i < nedges; i++) { if (edges[2*i] < w*h && edges[2*i+1] < w*h && flow[i] > 0) grid[temp[edges[2*i+1]]] = TREE; } /* * I think it looks ugly if there isn't at least one of * _something_ (tent or tree) in each row and each column * of the grid. This doesn't give any information away * since a completely empty row/column is instantly obvious * from the clues (it has no trees and a zero). */ for (i = 0; i < w; i++) { for (j = 0; j < h; j++) { if (grid[j*w+i] != BLANK) break; /* found something in this column */ } if (j == h) break; /* found empty column */ } if (i < w) continue; /* a column was empty */ for (j = 0; j < h; j++) { for (i = 0; i < w; i++) { if (grid[j*w+i] != BLANK) break; /* found something in this row */ } if (i == w) break; /* found empty row */ } if (j < h) continue; /* a row was empty */ /* * Now set up the numbers round the edge. */ for (i = 0; i < w; i++) { int n = 0; for (j = 0; j < h; j++) if (grid[j*w+i] == TENT) n++; numbers[i] = n; } for (i = 0; i < h; i++) { int n = 0; for (j = 0; j < w; j++) if (grid[i*w+j] == TENT) n++; numbers[w+i] = n; } /* * And now actually solve the puzzle, to see whether it's * unique and has the required difficulty. */ for (i = 0; i < w*h; i++) puzzle[i] = grid[i] == TREE ? TREE : BLANK; i = tents_solve(w, h, puzzle, numbers, soln, sc, params->diff-1); j = tents_solve(w, h, puzzle, numbers, soln, sc, params->diff); /* * We expect solving with difficulty params->diff to have * succeeded (otherwise the problem is too hard), and * solving with diff-1 to have failed (otherwise it's too * easy). */ if (i == 2 && j == 1) break; } /* * That's it. Encode as a game ID. */ ret = snewn((w+h)*40 + ntrees + (w*h)/26 + 1, char); p = ret; j = 0; for (i = 0; i <= w*h; i++) { int c = (i < w*h ? grid[i] == TREE : 1); if (c) { *p++ = (j == 0 ? '_' : j-1 + 'a'); j = 0; } else { j++; while (j > 25) { *p++ = 'z'; j -= 25; } } } for (i = 0; i < w+h; i++) p += sprintf(p, ",%d", numbers[i]); *p++ = '\0'; ret = sresize(ret, p - ret, char); /* * And encode the solution as an aux_info. */ *aux = snewn(ntrees * 40, char); p = *aux; *p++ = 'S'; for (i = 0; i < w*h; i++) if (grid[i] == TENT) p += sprintf(p, ";T%d,%d", i%w, i/w); *p++ = '\0'; *aux = sresize(*aux, p - *aux, char); free_scratch(sc); sfree(flow); sfree(capacity); sfree(edges); sfree(temp); sfree(soln); sfree(numbers); sfree(puzzle); sfree(grid); return ret; } static char *validate_desc(const game_params *params, const char *desc) { int w = params->w, h = params->h; int area, i; area = 0; while (*desc && *desc != ',') { if (*desc == '_') area++; else if (*desc >= 'a' && *desc < 'z') area += *desc - 'a' + 2; else if (*desc == 'z') area += 25; else if (*desc == '!' || *desc == '-') /* do nothing */; else return "Invalid character in grid specification"; desc++; } if (area < w * h + 1) return "Not enough data to fill grid"; else if (area > w * h + 1) return "Too much data to fill grid"; for (i = 0; i < w+h; i++) { if (!*desc) return "Not enough numbers given after grid specification"; else if (*desc != ',') return "Invalid character in number list"; desc++; while (*desc && isdigit((unsigned char)*desc)) desc++; } if (*desc) return "Unexpected additional data at end of game description"; return NULL; } static game_state *new_game(midend *me, const game_params *params, const char *desc) { int w = params->w, h = params->h; game_state *state = snew(game_state); int i; state->p = *params; /* structure copy */ state->grid = snewn(w*h, char); state->numbers = snew(struct numbers); state->numbers->refcount = 1; state->numbers->numbers = snewn(w+h, int); state->completed = state->used_solve = FALSE; i = 0; memset(state->grid, BLANK, w*h); while (*desc) { int run, type; type = TREE; if (*desc == '_') run = 0; else if (*desc >= 'a' && *desc < 'z') run = *desc - ('a'-1); else if (*desc == 'z') { run = 25; type = BLANK; } else { assert(*desc == '!' || *desc == '-'); run = -1; type = (*desc == '!' ? TENT : NONTENT); } desc++; i += run; assert(i >= 0 && i <= w*h); if (i == w*h) { assert(type == TREE); break; } else { if (type != BLANK) state->grid[i++] = type; } } for (i = 0; i < w+h; i++) { assert(*desc == ','); desc++; state->numbers->numbers[i] = atoi(desc); while (*desc && isdigit((unsigned char)*desc)) desc++; } assert(!*desc); return state; } static game_state *dup_game(const game_state *state) { int w = state->p.w, h = state->p.h; game_state *ret = snew(game_state); ret->p = state->p; /* structure copy */ ret->grid = snewn(w*h, char); memcpy(ret->grid, state->grid, w*h); ret->numbers = state->numbers; state->numbers->refcount++; ret->completed = state->completed; ret->used_solve = state->used_solve; return ret; } static void free_game(game_state *state) { if (--state->numbers->refcount <= 0) { sfree(state->numbers->numbers); sfree(state->numbers); } sfree(state->grid); sfree(state); } static char *solve_game(const game_state *state, const game_state *currstate, const char *aux, char **error) { int w = state->p.w, h = state->p.h; if (aux) { /* * If we already have the solution, save ourselves some * time. */ return dupstr(aux); } else { struct solver_scratch *sc = new_scratch(w, h); char *soln; int ret; char *move, *p; int i; soln = snewn(w*h, char); ret = tents_solve(w, h, state->grid, state->numbers->numbers, soln, sc, DIFFCOUNT-1); free_scratch(sc); if (ret != 1) { sfree(soln); if (ret == 0) *error = "This puzzle is not self-consistent"; else *error = "Unable to find a unique solution for this puzzle"; return NULL; } /* * Construct a move string which turns the current state * into the solved state. */ move = snewn(w*h * 40, char); p = move; *p++ = 'S'; for (i = 0; i < w*h; i++) if (soln[i] == TENT) p += sprintf(p, ";T%d,%d", i%w, i/w); *p++ = '\0'; move = sresize(move, p - move, char); sfree(soln); return move; } } static int game_can_format_as_text_now(const game_params *params) { return params->w <= 1998 && params->h <= 1998; /* 999 tents */ } static char *game_text_format(const game_state *state) { int w = state->p.w, h = state->p.h, r, c; int cw = 4, ch = 2, gw = (w+1)*cw + 2, gh = (h+1)*ch + 1, len = gw * gh; char *board = snewn(len + 1, char); sprintf(board, "%*s\n", len - 2, ""); for (r = 0; r <= h; ++r) { for (c = 0; c <= w; ++c) { int cell = r*ch*gw + cw*c, center = cell + gw*ch/2 + cw/2; int i = r*w + c, n = 1000; if (r == h && c == w) /* NOP */; else if (c == w) n = state->numbers->numbers[w + r]; else if (r == h) n = state->numbers->numbers[c]; else switch (state->grid[i]) { case BLANK: board[center] = '.'; break; case TREE: board[center] = 'T'; break; case TENT: memcpy(board + center - 1, "//\\", 3); break; case NONTENT: break; default: memcpy(board + center - 1, "wtf", 3); } if (n < 100) { board[center] = '0' + n % 10; if (n >= 10) board[center - 1] = '0' + n / 10; } else if (n < 1000) { board[center + 1] = '0' + n % 10; board[center] = '0' + n / 10 % 10; board[center - 1] = '0' + n / 100; } board[cell] = '+'; memset(board + cell + 1, '-', cw - 1); for (i = 1; i < ch; ++i) board[cell + i*gw] = '|'; } for (c = 0; c < ch; ++c) { board[(r*ch+c)*gw + gw - 2] = c == 0 ? '+' : r < h ? '|' : ' '; board[(r*ch+c)*gw + gw - 1] = '\n'; } } memset(board + len - gw, '-', gw - 2 - cw); for (c = 0; c <= w; ++c) board[len - gw + cw*c] = '+'; return board; } struct game_ui { int dsx, dsy; /* coords of drag start */ int dex, dey; /* coords of drag end */ int drag_button; /* -1 for none, or a button code */ int drag_ok; /* dragged off the window, to cancel */ int cx, cy, cdisp; /* cursor position, and ?display. */ }; static game_ui *new_ui(const game_state *state) { game_ui *ui = snew(game_ui); ui->dsx = ui->dsy = -1; ui->dex = ui->dey = -1; ui->drag_button = -1; ui->drag_ok = FALSE; ui->cx = ui->cy = ui->cdisp = 0; return ui; } static void free_ui(game_ui *ui) { sfree(ui); } static char *encode_ui(const game_ui *ui) { return NULL; } static void decode_ui(game_ui *ui, const char *encoding) { } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { } struct game_drawstate { int tilesize; int started; game_params p; int *drawn, *numbersdrawn; int cx, cy; /* last-drawn cursor pos, or (-1,-1) if absent. */ }; #define PREFERRED_TILESIZE 32 #define TILESIZE (ds->tilesize) #define TLBORDER (TILESIZE/2) #define BRBORDER (TILESIZE*3/2) #define COORD(x) ( (x) * TILESIZE + TLBORDER ) #define FROMCOORD(x) ( ((x) - TLBORDER + TILESIZE) / TILESIZE - 1 ) #define FLASH_TIME 0.30F static int drag_xform(const game_ui *ui, int x, int y, int v) { int xmin, ymin, xmax, ymax; xmin = min(ui->dsx, ui->dex); xmax = max(ui->dsx, ui->dex); ymin = min(ui->dsy, ui->dey); ymax = max(ui->dsy, ui->dey); #ifndef STYLUS_BASED /* * Left-dragging has no effect, so we treat a left-drag as a * single click on dsx,dsy. */ if (ui->drag_button == LEFT_BUTTON) { xmin = xmax = ui->dsx; ymin = ymax = ui->dsy; } #endif if (x < xmin || x > xmax || y < ymin || y > ymax) return v; /* no change outside drag area */ if (v == TREE) return v; /* trees are inviolate always */ if (xmin == xmax && ymin == ymax) { /* * Results of a simple click. Left button sets blanks to * tents; right button sets blanks to non-tents; either * button clears a non-blank square. * If stylus-based however, it loops instead. */ if (ui->drag_button == LEFT_BUTTON) #ifdef STYLUS_BASED v = (v == BLANK ? TENT : (v == TENT ? NONTENT : BLANK)); else v = (v == BLANK ? NONTENT : (v == NONTENT ? TENT : BLANK)); #else v = (v == BLANK ? TENT : BLANK); else v = (v == BLANK ? NONTENT : BLANK); #endif } else { /* * Results of a drag. Left-dragging has no effect. * Right-dragging sets all blank squares to non-tents and * has no effect on anything else. */ if (ui->drag_button == RIGHT_BUTTON) v = (v == BLANK ? NONTENT : v); else #ifdef STYLUS_BASED v = (v == BLANK ? NONTENT : v); #else /* do nothing */; #endif } return v; } static char *interpret_move(const game_state *state, game_ui *ui, const game_drawstate *ds, int x, int y, int button) { int w = state->p.w, h = state->p.h; char tmpbuf[80]; int shift = button & MOD_SHFT, control = button & MOD_CTRL; button &= ~MOD_MASK; if (button == LEFT_BUTTON || button == RIGHT_BUTTON) { x = FROMCOORD(x); y = FROMCOORD(y); if (x < 0 || y < 0 || x >= w || y >= h) return NULL; ui->drag_button = button; ui->dsx = ui->dex = x; ui->dsy = ui->dey = y; ui->drag_ok = TRUE; ui->cdisp = 0; return ""; /* ui updated */ } if ((IS_MOUSE_DRAG(button) || IS_MOUSE_RELEASE(button)) && ui->drag_button > 0) { int xmin, ymin, xmax, ymax; char *buf, *sep; int buflen, bufsize, tmplen; x = FROMCOORD(x); y = FROMCOORD(y); if (x < 0 || y < 0 || x >= w || y >= h) { ui->drag_ok = FALSE; } else { /* * Drags are limited to one row or column. Hence, we * work out which coordinate is closer to the drag * start, and move it _to_ the drag start. */ if (abs(x - ui->dsx) < abs(y - ui->dsy)) x = ui->dsx; else y = ui->dsy; ui->dex = x; ui->dey = y; ui->drag_ok = TRUE; } if (IS_MOUSE_DRAG(button)) return ""; /* ui updated */ /* * The drag has been released. Enact it. */ if (!ui->drag_ok) { ui->drag_button = -1; return ""; /* drag was just cancelled */ } xmin = min(ui->dsx, ui->dex); xmax = max(ui->dsx, ui->dex); ymin = min(ui->dsy, ui->dey); ymax = max(ui->dsy, ui->dey); assert(0 <= xmin && xmin <= xmax && xmax < w); assert(0 <= ymin && ymin <= ymax && ymax < h); buflen = 0; bufsize = 256; buf = snewn(bufsize, char); sep = ""; for (y = ymin; y <= ymax; y++) for (x = xmin; x <= xmax; x++) { int v = drag_xform(ui, x, y, state->grid[y*w+x]); if (state->grid[y*w+x] != v) { tmplen = sprintf(tmpbuf, "%s%c%d,%d", sep, (int)(v == BLANK ? 'B' : v == TENT ? 'T' : 'N'), x, y); sep = ";"; if (buflen + tmplen >= bufsize) { bufsize = buflen + tmplen + 256; buf = sresize(buf, bufsize, char); } strcpy(buf+buflen, tmpbuf); buflen += tmplen; } } ui->drag_button = -1; /* drag is terminated */ if (buflen == 0) { sfree(buf); return ""; /* ui updated (drag was terminated) */ } else { buf[buflen] = '\0'; return buf; } } if (IS_CURSOR_MOVE(button)) { ui->cdisp = 1; if (shift || control) { int len = 0, i, indices[2]; indices[0] = ui->cx + w * ui->cy; move_cursor(button, &ui->cx, &ui->cy, w, h, 0); indices[1] = ui->cx + w * ui->cy; /* NONTENTify all unique traversed eligible squares */ for (i = 0; i <= (indices[0] != indices[1]); ++i) if (state->grid[indices[i]] == BLANK || (control && state->grid[indices[i]] == TENT)) { len += sprintf(tmpbuf + len, "%sN%d,%d", len ? ";" : "", indices[i] % w, indices[i] / w); assert(len < lenof(tmpbuf)); } tmpbuf[len] = '\0'; if (len) return dupstr(tmpbuf); } else move_cursor(button, &ui->cx, &ui->cy, w, h, 0); return ""; } if (ui->cdisp) { char rep = 0; int v = state->grid[ui->cy*w+ui->cx]; if (v != TREE) { #ifdef SINGLE_CURSOR_SELECT if (button == CURSOR_SELECT) /* SELECT cycles T, N, B */ rep = v == BLANK ? 'T' : v == TENT ? 'N' : 'B'; #else if (button == CURSOR_SELECT) rep = v == BLANK ? 'T' : 'B'; else if (button == CURSOR_SELECT2) rep = v == BLANK ? 'N' : 'B'; else if (button == 'T' || button == 'N' || button == 'B') rep = (char)button; #endif } if (rep) { sprintf(tmpbuf, "%c%d,%d", (int)rep, ui->cx, ui->cy); return dupstr(tmpbuf); } } else if (IS_CURSOR_SELECT(button)) { ui->cdisp = 1; return ""; } return NULL; } static game_state *execute_move(const game_state *state, const char *move) { int w = state->p.w, h = state->p.h; char c; int x, y, m, n, i, j; game_state *ret = dup_game(state); while (*move) { c = *move; if (c == 'S') { int i; ret->used_solve = TRUE; /* * Set all non-tree squares to NONTENT. The rest of the * solve move will fill the tents in over the top. */ for (i = 0; i < w*h; i++) if (ret->grid[i] != TREE) ret->grid[i] = NONTENT; move++; } else if (c == 'B' || c == 'T' || c == 'N') { move++; if (sscanf(move, "%d,%d%n", &x, &y, &n) != 2 || x < 0 || y < 0 || x >= w || y >= h) { free_game(ret); return NULL; } if (ret->grid[y*w+x] == TREE) { free_game(ret); return NULL; } ret->grid[y*w+x] = (c == 'B' ? BLANK : c == 'T' ? TENT : NONTENT); move += n; } else { free_game(ret); return NULL; } if (*move == ';') move++; else if (*move) { free_game(ret); return NULL; } } /* * Check for completion. */ for (i = n = m = 0; i < w*h; i++) { if (ret->grid[i] == TENT) n++; else if (ret->grid[i] == TREE) m++; } if (n == m) { int nedges, maxedges, *edges, *capacity, *flow; /* * We have the right number of tents, which is a * precondition for the game being complete. Now check that * the numbers add up. */ for (i = 0; i < w; i++) { n = 0; for (j = 0; j < h; j++) if (ret->grid[j*w+i] == TENT) n++; if (ret->numbers->numbers[i] != n) goto completion_check_done; } for (i = 0; i < h; i++) { n = 0; for (j = 0; j < w; j++) if (ret->grid[i*w+j] == TENT) n++; if (ret->numbers->numbers[w+i] != n) goto completion_check_done; } /* * Also, check that no two tents are adjacent. */ for (y = 0; y < h; y++) for (x = 0; x < w; x++) { if (x+1 < w && ret->grid[y*w+x] == TENT && ret->grid[y*w+x+1] == TENT) goto completion_check_done; if (y+1 < h && ret->grid[y*w+x] == TENT && ret->grid[(y+1)*w+x] == TENT) goto completion_check_done; if (x+1 < w && y+1 < h) { if (ret->grid[y*w+x] == TENT && ret->grid[(y+1)*w+(x+1)] == TENT) goto completion_check_done; if (ret->grid[(y+1)*w+x] == TENT && ret->grid[y*w+(x+1)] == TENT) goto completion_check_done; } } /* * OK; we have the right number of tents, they match the * numeric clues, and they satisfy the non-adjacency * criterion. Finally, we need to verify that they can be * placed in a one-to-one matching with the trees such that * every tent is orthogonally adjacent to its tree. * * This bit is where the hard work comes in: we have to do * it by finding such a matching using maxflow. * * So we construct a network with one special source node, * one special sink node, one node per tent, and one node * per tree. */ maxedges = 6 * m; edges = snewn(2 * maxedges, int); capacity = snewn(maxedges, int); flow = snewn(maxedges, int); nedges = 0; /* * Node numbering: * * 0..w*h trees/tents * w*h source * w*h+1 sink */ for (y = 0; y < h; y++) for (x = 0; x < w; x++) if (ret->grid[y*w+x] == TREE) { int d; /* * Here we use the direction enum declared for * the solver. We make use of the fact that the * directions are declared in the order * U,L,R,D, meaning that we go through the four * neighbours of any square in numerically * increasing order. */ for (d = 1; d < MAXDIR; d++) { int x2 = x + dx(d), y2 = y + dy(d); if (x2 >= 0 && x2 < w && y2 >= 0 && y2 < h && ret->grid[y2*w+x2] == TENT) { assert(nedges < maxedges); edges[nedges*2] = y*w+x; edges[nedges*2+1] = y2*w+x2; capacity[nedges] = 1; nedges++; } } } else if (ret->grid[y*w+x] == TENT) { assert(nedges < maxedges); edges[nedges*2] = y*w+x; edges[nedges*2+1] = w*h+1; /* edge going to sink */ capacity[nedges] = 1; nedges++; } for (y = 0; y < h; y++) for (x = 0; x < w; x++) if (ret->grid[y*w+x] == TREE) { assert(nedges < maxedges); edges[nedges*2] = w*h; /* edge coming from source */ edges[nedges*2+1] = y*w+x; capacity[nedges] = 1; nedges++; } n = maxflow(w*h+2, w*h, w*h+1, nedges, edges, capacity, flow, NULL); sfree(flow); sfree(capacity); sfree(edges); if (n != m) goto completion_check_done; /* * We haven't managed to fault the grid on any count. Score! */ ret->completed = TRUE; } completion_check_done: return ret; } /* ---------------------------------------------------------------------- * Drawing routines. */ static void game_compute_size(const game_params *params, int tilesize, int *x, int *y) { /* fool the macros */ struct dummy { int tilesize; } dummy, *ds = &dummy; dummy.tilesize = tilesize; *x = TLBORDER + BRBORDER + TILESIZE * params->w; *y = TLBORDER + BRBORDER + TILESIZE * params->h; } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { ds->tilesize = tilesize; } static float *game_colours(frontend *fe, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float); frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]); ret[COL_GRID * 3 + 0] = 0.0F; ret[COL_GRID * 3 + 1] = 0.0F; ret[COL_GRID * 3 + 2] = 0.0F; ret[COL_GRASS * 3 + 0] = 0.7F; ret[COL_GRASS * 3 + 1] = 1.0F; ret[COL_GRASS * 3 + 2] = 0.5F; ret[COL_TREETRUNK * 3 + 0] = 0.6F; ret[COL_TREETRUNK * 3 + 1] = 0.4F; ret[COL_TREETRUNK * 3 + 2] = 0.0F; ret[COL_TREELEAF * 3 + 0] = 0.0F; ret[COL_TREELEAF * 3 + 1] = 0.7F; ret[COL_TREELEAF * 3 + 2] = 0.0F; ret[COL_TENT * 3 + 0] = 0.8F; ret[COL_TENT * 3 + 1] = 0.7F; ret[COL_TENT * 3 + 2] = 0.0F; ret[COL_ERROR * 3 + 0] = 1.0F; ret[COL_ERROR * 3 + 1] = 0.0F; ret[COL_ERROR * 3 + 2] = 0.0F; ret[COL_ERRTEXT * 3 + 0] = 1.0F; ret[COL_ERRTEXT * 3 + 1] = 1.0F; ret[COL_ERRTEXT * 3 + 2] = 1.0F; ret[COL_ERRTRUNK * 3 + 0] = 0.6F; ret[COL_ERRTRUNK * 3 + 1] = 0.0F; ret[COL_ERRTRUNK * 3 + 2] = 0.0F; *ncolours = NCOLOURS; return ret; } static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { int w = state->p.w, h = state->p.h; struct game_drawstate *ds = snew(struct game_drawstate); int i; ds->tilesize = 0; ds->started = FALSE; ds->p = state->p; /* structure copy */ ds->drawn = snewn(w*h, int); for (i = 0; i < w*h; i++) ds->drawn[i] = MAGIC; ds->numbersdrawn = snewn(w+h, int); for (i = 0; i < w+h; i++) ds->numbersdrawn[i] = 2; ds->cx = ds->cy = -1; return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { sfree(ds->drawn); sfree(ds->numbersdrawn); sfree(ds); } enum { ERR_ADJ_TOPLEFT = 4, ERR_ADJ_TOP, ERR_ADJ_TOPRIGHT, ERR_ADJ_LEFT, ERR_ADJ_RIGHT, ERR_ADJ_BOTLEFT, ERR_ADJ_BOT, ERR_ADJ_BOTRIGHT, ERR_OVERCOMMITTED }; static int *find_errors(const game_state *state, char *grid) { int w = state->p.w, h = state->p.h; int *ret = snewn(w*h + w + h, int); int *tmp = snewn(w*h*2, int), *dsf = tmp + w*h; int x, y; /* * This function goes through a grid and works out where to * highlight play errors in red. The aim is that it should * produce at least one error highlight for any complete grid * (or complete piece of grid) violating a puzzle constraint, so * that a grid containing no BLANK squares is either a win or is * marked up in some way that indicates why not. * * So it's easy enough to highlight errors in the numeric clues * - just light up any row or column number which is not * fulfilled - and it's just as easy to highlight adjacent * tents. The difficult bit is highlighting failures in the * tent/tree matching criterion. * * A natural approach would seem to be to apply the maxflow * algorithm to find the tent/tree matching; if this fails, it * must necessarily terminate with a min-cut which can be * reinterpreted as some set of trees which have too few tents * between them (or vice versa). However, it's bad for * localising errors, because it's not easy to make the * algorithm narrow down to the _smallest_ such set of trees: if * trees A and B have only one tent between them, for instance, * it might perfectly well highlight not only A and B but also * trees C and D which are correctly matched on the far side of * the grid, on the grounds that those four trees between them * have only three tents. * * Also, that approach fares badly when you introduce the * additional requirement that incomplete grids should have * errors highlighted only when they can be proved to be errors * - so that trees should not be marked as having too few tents * if there are enough BLANK squares remaining around them that * could be turned into the missing tents (to do so would be * patronising, since the overwhelming likelihood is not that * the player has forgotten to put a tree there but that they * have merely not put one there _yet_). However, tents with too * few trees can be marked immediately, since those are * definitely player error. * * So I adopt an alternative approach, which is to consider the * bipartite adjacency graph between trees and tents * ('bipartite' in the sense that for these purposes I * deliberately ignore two adjacent trees or two adjacent * tents), divide that graph up into its connected components * using a dsf, and look for components which contain different * numbers of trees and tents. This allows me to highlight * groups of tents with too few trees between them immediately, * and then in order to find groups of trees with too few tents * I redo the same process but counting BLANKs as potential * tents (so that the only trees highlighted are those * surrounded by enough NONTENTs to make it impossible to give * them enough tents). * * However, this technique is incomplete: it is not a sufficient * condition for the existence of a perfect matching that every * connected component of the graph has the same number of tents * and trees. An example of a graph which satisfies the latter * condition but still has no perfect matching is * * A B C * | / ,/| * | / ,'/ | * | / ,' / | * |/,' / | * 1 2 3 * * which can be realised in Tents as * * B * A 1 C 2 * 3 * * The matching-error highlighter described above will not mark * this construction as erroneous. However, something else will: * the three tents in the above diagram (let us suppose A,B,C * are the tents, though it doesn't matter which) contain two * diagonally adjacent pairs. So there will be _an_ error * highlighted for the above layout, even though not all types * of error will be highlighted. * * And in fact we can prove that this will always be the case: * that the shortcomings of the matching-error highlighter will * always be made up for by the easy tent adjacency highlighter. * * Lemma: Let G be a bipartite graph between n trees and n * tents, which is connected, and in which no tree has degree * more than two (but a tent may). Then G has a perfect matching. * * (Note: in the statement and proof of the Lemma I will * consistently use 'tree' to indicate a type of graph vertex as * opposed to a tent, and not to indicate a tree in the graph- * theoretic sense.) * * Proof: * * If we can find a tent of degree 1 joined to a tree of degree * 2, then any perfect matching must pair that tent with that * tree. Hence, we can remove both, leaving a smaller graph G' * which still satisfies all the conditions of the Lemma, and * which has a perfect matching iff G does. * * So, wlog, we may assume G contains no tent of degree 1 joined * to a tree of degree 2; if it does, we can reduce it as above. * * If G has no tent of degree 1 at all, then every tent has * degree at least two, so there are at least 2n edges in the * graph. But every tree has degree at most two, so there are at * most 2n edges. Hence there must be exactly 2n edges, so every * tree and every tent must have degree exactly two, which means * that the whole graph consists of a single loop (by * connectedness), and therefore certainly has a perfect * matching. * * Alternatively, if G does have a tent of degree 1 but it is * not connected to a tree of degree 2, then the tree it is * connected to must have degree 1 - and, by connectedness, that * must mean that that tent and that tree between them form the * entire graph. This trivial graph has a trivial perfect * matching. [] * * That proves the lemma. Hence, in any case where the matching- * error highlighter fails to highlight an erroneous component * (because it has the same number of tents as trees, but they * cannot be matched up), the above lemma tells us that there * must be a tree with degree more than 2, i.e. a tree * orthogonally adjacent to at least three tents. But in that * case, there must be some pair of those three tents which are * diagonally adjacent to each other, so the tent-adjacency * highlighter will necessarily show an error. So any filled * layout in Tents which is not a correct solution to the puzzle * must have _some_ error highlighted by the subroutine below. * * (Of course it would be nicer if we could highlight all * errors: in the above example layout, we would like to * highlight tents A,B as having too few trees between them, and * trees 2,3 as having too few tents, in addition to marking the * adjacency problems. But I can't immediately think of any way * to find the smallest sets of such tents and trees without an * O(2^N) loop over all subsets of a given component.) */ /* * ret[0] through to ret[w*h-1] give error markers for the grid * squares. After that, ret[w*h] to ret[w*h+w-1] give error * markers for the column numbers, and ret[w*h+w] to * ret[w*h+w+h-1] for the row numbers. */ /* * Spot tent-adjacency violations. */ for (x = 0; x < w*h; x++) ret[x] = 0; for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { if (y+1 < h && x+1 < w && ((grid[y*w+x] == TENT && grid[(y+1)*w+(x+1)] == TENT) || (grid[(y+1)*w+x] == TENT && grid[y*w+(x+1)] == TENT))) { ret[y*w+x] |= 1 << ERR_ADJ_BOTRIGHT; ret[(y+1)*w+x] |= 1 << ERR_ADJ_TOPRIGHT; ret[y*w+(x+1)] |= 1 << ERR_ADJ_BOTLEFT; ret[(y+1)*w+(x+1)] |= 1 << ERR_ADJ_TOPLEFT; } if (y+1 < h && grid[y*w+x] == TENT && grid[(y+1)*w+x] == TENT) { ret[y*w+x] |= 1 << ERR_ADJ_BOT; ret[(y+1)*w+x] |= 1 << ERR_ADJ_TOP; } if (x+1 < w && grid[y*w+x] == TENT && grid[y*w+(x+1)] == TENT) { ret[y*w+x] |= 1 << ERR_ADJ_RIGHT; ret[y*w+(x+1)] |= 1 << ERR_ADJ_LEFT; } } } /* * Spot numeric clue violations. */ for (x = 0; x < w; x++) { int tents = 0, maybetents = 0; for (y = 0; y < h; y++) { if (grid[y*w+x] == TENT) tents++; else if (grid[y*w+x] == BLANK) maybetents++; } ret[w*h+x] = (tents > state->numbers->numbers[x] || tents + maybetents < state->numbers->numbers[x]); } for (y = 0; y < h; y++) { int tents = 0, maybetents = 0; for (x = 0; x < w; x++) { if (grid[y*w+x] == TENT) tents++; else if (grid[y*w+x] == BLANK) maybetents++; } ret[w*h+w+y] = (tents > state->numbers->numbers[w+y] || tents + maybetents < state->numbers->numbers[w+y]); } /* * Identify groups of tents with too few trees between them, * which we do by constructing the connected components of the * bipartite adjacency graph between tents and trees * ('bipartite' in the sense that we deliberately ignore * adjacency between tents or between trees), and highlighting * all the tents in any component which has a smaller tree * count. */ dsf_init(dsf, w*h); /* Construct the equivalence classes. */ for (y = 0; y < h; y++) { for (x = 0; x < w-1; x++) { if ((grid[y*w+x] == TREE && grid[y*w+x+1] == TENT) || (grid[y*w+x] == TENT && grid[y*w+x+1] == TREE)) dsf_merge(dsf, y*w+x, y*w+x+1); } } for (y = 0; y < h-1; y++) { for (x = 0; x < w; x++) { if ((grid[y*w+x] == TREE && grid[(y+1)*w+x] == TENT) || (grid[y*w+x] == TENT && grid[(y+1)*w+x] == TREE)) dsf_merge(dsf, y*w+x, (y+1)*w+x); } } /* Count up the tent/tree difference in each one. */ for (x = 0; x < w*h; x++) tmp[x] = 0; for (x = 0; x < w*h; x++) { y = dsf_canonify(dsf, x); if (grid[x] == TREE) tmp[y]++; else if (grid[x] == TENT) tmp[y]--; } /* And highlight any tent belonging to an equivalence class with * a score less than zero. */ for (x = 0; x < w*h; x++) { y = dsf_canonify(dsf, x); if (grid[x] == TENT && tmp[y] < 0) ret[x] |= 1 << ERR_OVERCOMMITTED; } /* * Identify groups of trees with too few tents between them. * This is done similarly, except that we now count BLANK as * equivalent to TENT, i.e. we only highlight such trees when * the user hasn't even left _room_ to provide tents for them * all. (Otherwise, we'd highlight all trees red right at the * start of the game, before the user had done anything wrong!) */ #define TENT(x) ((x)==TENT || (x)==BLANK) dsf_init(dsf, w*h); /* Construct the equivalence classes. */ for (y = 0; y < h; y++) { for (x = 0; x < w-1; x++) { if ((grid[y*w+x] == TREE && TENT(grid[y*w+x+1])) || (TENT(grid[y*w+x]) && grid[y*w+x+1] == TREE)) dsf_merge(dsf, y*w+x, y*w+x+1); } } for (y = 0; y < h-1; y++) { for (x = 0; x < w; x++) { if ((grid[y*w+x] == TREE && TENT(grid[(y+1)*w+x])) || (TENT(grid[y*w+x]) && grid[(y+1)*w+x] == TREE)) dsf_merge(dsf, y*w+x, (y+1)*w+x); } } /* Count up the tent/tree difference in each one. */ for (x = 0; x < w*h; x++) tmp[x] = 0; for (x = 0; x < w*h; x++) { y = dsf_canonify(dsf, x); if (grid[x] == TREE) tmp[y]++; else if (TENT(grid[x])) tmp[y]--; } /* And highlight any tree belonging to an equivalence class with * a score more than zero. */ for (x = 0; x < w*h; x++) { y = dsf_canonify(dsf, x); if (grid[x] == TREE && tmp[y] > 0) ret[x] |= 1 << ERR_OVERCOMMITTED; } #undef TENT sfree(tmp); return ret; } static void draw_err_adj(drawing *dr, game_drawstate *ds, int x, int y) { int coords[8]; int yext, xext; /* * Draw a diamond. */ coords[0] = x - TILESIZE*2/5; coords[1] = y; coords[2] = x; coords[3] = y - TILESIZE*2/5; coords[4] = x + TILESIZE*2/5; coords[5] = y; coords[6] = x; coords[7] = y + TILESIZE*2/5; draw_polygon(dr, coords, 4, COL_ERROR, COL_GRID); /* * Draw an exclamation mark in the diamond. This turns out to * look unpleasantly off-centre if done via draw_text, so I do * it by hand on the basis that exclamation marks aren't that * difficult to draw... */ xext = TILESIZE/16; yext = TILESIZE*2/5 - (xext*2+2); draw_rect(dr, x-xext, y-yext, xext*2+1, yext*2+1 - (xext*3), COL_ERRTEXT); draw_rect(dr, x-xext, y+yext-xext*2+1, xext*2+1, xext*2, COL_ERRTEXT); } static void draw_tile(drawing *dr, game_drawstate *ds, int x, int y, int v, int cur, int printing) { int err; int tx = COORD(x), ty = COORD(y); int cx = tx + TILESIZE/2, cy = ty + TILESIZE/2; err = v & ~15; v &= 15; clip(dr, tx, ty, TILESIZE, TILESIZE); if (!printing) { draw_rect(dr, tx, ty, TILESIZE, TILESIZE, COL_GRID); draw_rect(dr, tx+1, ty+1, TILESIZE-1, TILESIZE-1, (v == BLANK ? COL_BACKGROUND : COL_GRASS)); } if (v == TREE) { int i; (printing ? draw_rect_outline : draw_rect) (dr, cx-TILESIZE/15, ty+TILESIZE*3/10, 2*(TILESIZE/15)+1, (TILESIZE*9/10 - TILESIZE*3/10), (err & (1<p.w, h = state->p.h; int x, y, flashing; int cx = -1, cy = -1; int cmoved = 0; char *tmpgrid; int *errors; if (ui) { if (ui->cdisp) { cx = ui->cx; cy = ui->cy; } if (cx != ds->cx || cy != ds->cy) cmoved = 1; } if (printing || !ds->started) { if (!printing) { int ww, wh; game_compute_size(&state->p, TILESIZE, &ww, &wh); draw_rect(dr, 0, 0, ww, wh, COL_BACKGROUND); draw_update(dr, 0, 0, ww, wh); ds->started = TRUE; } if (printing) print_line_width(dr, TILESIZE/64); /* * Draw the grid. */ for (y = 0; y <= h; y++) draw_line(dr, COORD(0), COORD(y), COORD(w), COORD(y), COL_GRID); for (x = 0; x <= w; x++) draw_line(dr, COORD(x), COORD(0), COORD(x), COORD(h), COL_GRID); } if (flashtime > 0) flashing = (int)(flashtime * 3 / FLASH_TIME) != 1; else flashing = FALSE; /* * Find errors. For this we use _part_ of the information from a * currently active drag: we transform dsx,dsy but not anything * else. (This seems to strike a good compromise between having * the error highlights respond instantly to single clicks, but * not giving constant feedback during a right-drag.) */ if (ui && ui->drag_button >= 0) { tmpgrid = snewn(w*h, char); memcpy(tmpgrid, state->grid, w*h); tmpgrid[ui->dsy * w + ui->dsx] = drag_xform(ui, ui->dsx, ui->dsy, tmpgrid[ui->dsy * w + ui->dsx]); errors = find_errors(state, tmpgrid); sfree(tmpgrid); } else { errors = find_errors(state, state->grid); } /* * Draw the grid. */ for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { int v = state->grid[y*w+x]; int credraw = 0; /* * We deliberately do not take drag_ok into account * here, because user feedback suggests that it's * marginally nicer not to have the drag effects * flickering on and off disconcertingly. */ if (ui && ui->drag_button >= 0) v = drag_xform(ui, x, y, v); if (flashing && (v == TREE || v == TENT)) v = NONTENT; if (cmoved) { if ((x == cx && y == cy) || (x == ds->cx && y == ds->cy)) credraw = 1; } v |= errors[y*w+x]; if (printing || ds->drawn[y*w+x] != v || credraw) { draw_tile(dr, ds, x, y, v, (x == cx && y == cy), printing); if (!printing) ds->drawn[y*w+x] = v; } } } /* * Draw (or redraw, if their error-highlighted state has * changed) the numbers. */ for (x = 0; x < w; x++) { if (printing || ds->numbersdrawn[x] != errors[w*h+x]) { char buf[80]; draw_rect(dr, COORD(x), COORD(h)+1, TILESIZE, BRBORDER-1, COL_BACKGROUND); sprintf(buf, "%d", state->numbers->numbers[x]); draw_text(dr, COORD(x) + TILESIZE/2, COORD(h+1), FONT_VARIABLE, TILESIZE/2, ALIGN_HCENTRE|ALIGN_VNORMAL, (errors[w*h+x] ? COL_ERROR : COL_GRID), buf); draw_update(dr, COORD(x), COORD(h)+1, TILESIZE, BRBORDER-1); if (!printing) ds->numbersdrawn[x] = errors[w*h+x]; } } for (y = 0; y < h; y++) { if (printing || ds->numbersdrawn[w+y] != errors[w*h+w+y]) { char buf[80]; draw_rect(dr, COORD(w)+1, COORD(y), BRBORDER-1, TILESIZE, COL_BACKGROUND); sprintf(buf, "%d", state->numbers->numbers[w+y]); draw_text(dr, COORD(w+1), COORD(y) + TILESIZE/2, FONT_VARIABLE, TILESIZE/2, ALIGN_HRIGHT|ALIGN_VCENTRE, (errors[w*h+w+y] ? COL_ERROR : COL_GRID), buf); draw_update(dr, COORD(w)+1, COORD(y), BRBORDER-1, TILESIZE); if (!printing) ds->numbersdrawn[w+y] = errors[w*h+w+y]; } } if (cmoved) { ds->cx = cx; ds->cy = cy; } sfree(errors); } static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float animtime, float flashtime) { int_redraw(dr, ds, oldstate, state, dir, ui, animtime, flashtime, FALSE); } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return 0.0F; } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { if (!oldstate->completed && newstate->completed && !oldstate->used_solve && !newstate->used_solve) return FLASH_TIME; return 0.0F; } static int game_status(const game_state *state) { return state->completed ? +1 : 0; } static int game_timing_state(const game_state *state, game_ui *ui) { return TRUE; } static void game_print_size(const game_params *params, float *x, float *y) { int pw, ph; /* * I'll use 6mm squares by default. */ game_compute_size(params, 600, &pw, &ph); *x = pw / 100.0F; *y = ph / 100.0F; } static void game_print(drawing *dr, const game_state *state, int tilesize) { int c; /* Ick: fake up `ds->tilesize' for macro expansion purposes */ game_drawstate ads, *ds = &ads; game_set_size(dr, ds, NULL, tilesize); c = print_mono_colour(dr, 1); assert(c == COL_BACKGROUND); c = print_mono_colour(dr, 0); assert(c == COL_GRID); c = print_mono_colour(dr, 1); assert(c == COL_GRASS); c = print_mono_colour(dr, 0); assert(c == COL_TREETRUNK); c = print_mono_colour(dr, 0); assert(c == COL_TREELEAF); c = print_mono_colour(dr, 0); assert(c == COL_TENT); int_redraw(dr, ds, NULL, state, +1, NULL, 0.0F, 0.0F, TRUE); } #ifdef COMBINED #define thegame tents #endif const struct game thegame = { "Tents", "games.tents", "tents", default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, TRUE, solve_game, TRUE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, PREFERRED_TILESIZE, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, TRUE, FALSE, game_print_size, game_print, FALSE, /* wants_statusbar */ FALSE, game_timing_state, REQUIRE_RBUTTON, /* flags */ }; #ifdef STANDALONE_SOLVER #include int main(int argc, char **argv) { game_params *p; game_state *s, *s2; char *id = NULL, *desc, *err; int grade = FALSE; int ret, diff, really_verbose = FALSE; struct solver_scratch *sc; while (--argc > 0) { char *p = *++argv; if (!strcmp(p, "-v")) { really_verbose = TRUE; } else if (!strcmp(p, "-g")) { grade = TRUE; } else if (*p == '-') { fprintf(stderr, "%s: unrecognised option `%s'\n", argv[0], p); return 1; } else { id = p; } } if (!id) { fprintf(stderr, "usage: %s [-g | -v] \n", argv[0]); return 1; } desc = strchr(id, ':'); if (!desc) { fprintf(stderr, "%s: game id expects a colon in it\n", argv[0]); return 1; } *desc++ = '\0'; p = default_params(); decode_params(p, id); err = validate_desc(p, desc); if (err) { fprintf(stderr, "%s: %s\n", argv[0], err); return 1; } s = new_game(NULL, p, desc); s2 = new_game(NULL, p, desc); sc = new_scratch(p->w, p->h); /* * When solving an Easy puzzle, we don't want to bother the * user with Hard-level deductions. For this reason, we grade * the puzzle internally before doing anything else. */ ret = -1; /* placate optimiser */ for (diff = 0; diff < DIFFCOUNT; diff++) { ret = tents_solve(p->w, p->h, s->grid, s->numbers->numbers, s2->grid, sc, diff); if (ret < 2) break; } if (diff == DIFFCOUNT) { if (grade) printf("Difficulty rating: too hard to solve internally\n"); else printf("Unable to find a unique solution\n"); } else { if (grade) { if (ret == 0) printf("Difficulty rating: impossible (no solution exists)\n"); else if (ret == 1) printf("Difficulty rating: %s\n", tents_diffnames[diff]); } else { verbose = really_verbose; ret = tents_solve(p->w, p->h, s->grid, s->numbers->numbers, s2->grid, sc, diff); if (ret == 0) printf("Puzzle is inconsistent\n"); else fputs(game_text_format(s2), stdout); } } return 0; } #endif /* vim: set shiftwidth=4 tabstop=8: */ puzzles-20170606.272beef/tdq.c0000644000175000017500000000367113115373615014634 0ustar simonsimon/* * tdq.c: implement a 'to-do queue', a simple de-duplicating to-do * list mechanism. */ #include #include "puzzles.h" /* * Implementation: a tdq consists of a circular buffer of size n * storing the integers currently in the queue, plus an array of n * booleans indicating whether each integer is already there. * * Using a circular buffer of size n to store between 0 and n items * inclusive has an obvious failure mode: if the input and output * pointers are the same, how do you know whether that means the * buffer is full or empty? * * In this application we have a simple way to tell: in the former * case, the flags array is all 1s, and in the latter case it's all * 0s. So we could spot that case and check, say, flags[0]. * * However, it's even easier to simply determine whether the queue is * non-empty by testing flags[buffer[op]] - that way we don't even * _have_ to compare ip against op. */ struct tdq { int n; int *queue; int ip, op; /* in pointer, out pointer */ char *flags; }; tdq *tdq_new(int n) { int i; tdq *tdq = snew(struct tdq); tdq->queue = snewn(n, int); tdq->flags = snewn(n, char); for (i = 0; i < n; i++) { tdq->queue[i] = 0; tdq->flags[i] = 0; } tdq->n = n; tdq->ip = tdq->op = 0; return tdq; } void tdq_free(tdq *tdq) { sfree(tdq->queue); sfree(tdq->flags); sfree(tdq); } void tdq_add(tdq *tdq, int k) { assert((unsigned)k < (unsigned)tdq->n); if (!tdq->flags[k]) { tdq->queue[tdq->ip] = k; tdq->flags[k] = 1; if (++tdq->ip == tdq->n) tdq->ip = 0; } } int tdq_remove(tdq *tdq) { int ret = tdq->queue[tdq->op]; if (!tdq->flags[ret]) return -1; tdq->flags[ret] = 0; if (++tdq->op == tdq->n) tdq->op = 0; return ret; } void tdq_fill(tdq *tdq) { int i; for (i = 0; i < tdq->n; i++) tdq_add(tdq, i); } puzzles-20170606.272beef/solo.c0000644000175000017500000047336613115373615015034 0ustar simonsimon/* * solo.c: the number-placing puzzle most popularly known as `Sudoku'. * * TODO: * * - reports from users are that `Trivial'-mode puzzles are still * rather hard compared to newspapers' easy ones, so some better * low-end difficulty grading would be nice * + it's possible that really easy puzzles always have * _several_ things you can do, so don't make you hunt too * hard for the one deduction you can currently make * + it's also possible that easy puzzles require fewer * cross-eliminations: perhaps there's a higher incidence of * things you can deduce by looking only at (say) rows, * rather than things you have to check both rows and columns * for * + but really, what I need to do is find some really easy * puzzles and _play_ them, to see what's actually easy about * them * + while I'm revamping this area, filling in the _last_ * number in a nearly-full row or column should certainly be * permitted even at the lowest difficulty level. * + also Owen noticed that `Basic' grids requiring numeric * elimination are actually very hard, so I wonder if a * difficulty gradation between that and positional- * elimination-only might be in order * + but it's not good to have _too_ many difficulty levels, or * it'll take too long to randomly generate a given level. * * - it might still be nice to do some prioritisation on the * removal of numbers from the grid * + one possibility is to try to minimise the maximum number * of filled squares in any block, which in particular ought * to enforce never leaving a completely filled block in the * puzzle as presented. * * - alternative interface modes * + sudoku.com's Windows program has a palette of possible * entries; you select a palette entry first and then click * on the square you want it to go in, thus enabling * mouse-only play. Useful for PDAs! I don't think it's * actually incompatible with the current highlight-then-type * approach: you _either_ highlight a palette entry and then * click, _or_ you highlight a square and then type. At most * one thing is ever highlighted at a time, so there's no way * to confuse the two. * + then again, I don't actually like sudoku.com's interface; * it's too much like a paint package whereas I prefer to * think of Solo as a text editor. * + another PDA-friendly possibility is a drag interface: * _drag_ numbers from the palette into the grid squares. * Thought experiments suggest I'd prefer that to the * sudoku.com approach, but I haven't actually tried it. */ /* * Solo puzzles need to be square overall (since each row and each * column must contain one of every digit), but they need not be * subdivided the same way internally. I am going to adopt a * convention whereby I _always_ refer to `r' as the number of rows * of _big_ divisions, and `c' as the number of columns of _big_ * divisions. Thus, a 2c by 3r puzzle looks something like this: * * 4 5 1 | 2 6 3 * 6 3 2 | 5 4 1 * ------+------ (Of course, you can't subdivide it the other way * 1 4 5 | 6 3 2 or you'll get clashes; observe that the 4 in the * 3 2 6 | 4 1 5 top left would conflict with the 4 in the second * ------+------ box down on the left-hand side.) * 5 1 4 | 3 2 6 * 2 6 3 | 1 5 4 * * The need for a strong naming convention should now be clear: * each small box is two rows of digits by three columns, while the * overall puzzle has three rows of small boxes by two columns. So * I will (hopefully) consistently use `r' to denote the number of * rows _of small boxes_ (here 3), which is also the number of * columns of digits in each small box; and `c' vice versa (here * 2). * * I'm also going to choose arbitrarily to list c first wherever * possible: the above is a 2x3 puzzle, not a 3x2 one. */ #include #include #include #include #include #include #ifdef STANDALONE_SOLVER #include int solver_show_working, solver_recurse_depth; #endif #include "puzzles.h" /* * To save space, I store digits internally as unsigned char. This * imposes a hard limit of 255 on the order of the puzzle. Since * even a 5x5 takes unacceptably long to generate, I don't see this * as a serious limitation unless something _really_ impressive * happens in computing technology; but here's a typedef anyway for * general good practice. */ typedef unsigned char digit; #define ORDER_MAX 255 #define PREFERRED_TILE_SIZE 48 #define TILE_SIZE (ds->tilesize) #define BORDER (TILE_SIZE / 2) #define GRIDEXTRA max((TILE_SIZE / 32),1) #define FLASH_TIME 0.4F enum { SYMM_NONE, SYMM_ROT2, SYMM_ROT4, SYMM_REF2, SYMM_REF2D, SYMM_REF4, SYMM_REF4D, SYMM_REF8 }; enum { DIFF_BLOCK, DIFF_SIMPLE, DIFF_INTERSECT, DIFF_SET, DIFF_EXTREME, DIFF_RECURSIVE, DIFF_AMBIGUOUS, DIFF_IMPOSSIBLE }; enum { DIFF_KSINGLE, DIFF_KMINMAX, DIFF_KSUMS, DIFF_KINTERSECT }; enum { COL_BACKGROUND, COL_XDIAGONALS, COL_GRID, COL_CLUE, COL_USER, COL_HIGHLIGHT, COL_ERROR, COL_PENCIL, COL_KILLER, NCOLOURS }; /* * To determine all possible ways to reach a given sum by adding two or * three numbers from 1..9, each of which occurs exactly once in the sum, * these arrays contain a list of bitmasks for each sum value, where if * bit N is set, it means that N occurs in the sum. Each list is * terminated by a zero if it is shorter than the size of the array. */ #define MAX_2SUMS 5 #define MAX_3SUMS 8 #define MAX_4SUMS 12 unsigned long sum_bits2[18][MAX_2SUMS]; unsigned long sum_bits3[25][MAX_3SUMS]; unsigned long sum_bits4[31][MAX_4SUMS]; static int find_sum_bits(unsigned long *array, int idx, int value_left, int addends_left, int min_addend, unsigned long bitmask_so_far) { int i; assert(addends_left >= 2); for (i = min_addend; i < value_left; i++) { unsigned long new_bitmask = bitmask_so_far | (1L << i); assert(bitmask_so_far != new_bitmask); if (addends_left == 2) { int j = value_left - i; if (j <= i) break; if (j > 9) continue; array[idx++] = new_bitmask | (1L << j); } else idx = find_sum_bits(array, idx, value_left - i, addends_left - 1, i + 1, new_bitmask); } return idx; } static void precompute_sum_bits(void) { int i; for (i = 3; i < 31; i++) { int j; if (i < 18) { j = find_sum_bits(sum_bits2[i], 0, i, 2, 1, 0); assert (j <= MAX_2SUMS); if (j < MAX_2SUMS) sum_bits2[i][j] = 0; } if (i < 25) { j = find_sum_bits(sum_bits3[i], 0, i, 3, 1, 0); assert (j <= MAX_3SUMS); if (j < MAX_3SUMS) sum_bits3[i][j] = 0; } j = find_sum_bits(sum_bits4[i], 0, i, 4, 1, 0); assert (j <= MAX_4SUMS); if (j < MAX_4SUMS) sum_bits4[i][j] = 0; } } struct game_params { /* * For a square puzzle, `c' and `r' indicate the puzzle * parameters as described above. * * A jigsaw-style puzzle is indicated by r==1, in which case c * can be whatever it likes (there is no constraint on * compositeness - a 7x7 jigsaw sudoku makes perfect sense). */ int c, r, symm, diff, kdiff; int xtype; /* require all digits in X-diagonals */ int killer; }; struct block_structure { int refcount; /* * For text formatting, we do need c and r here. */ int c, r, area; /* * For any square index, whichblock[i] gives its block index. * * For 0 <= b,i < cr, blocks[b][i] gives the index of the ith * square in block b. nr_squares[b] gives the number of squares * in block b (also the number of valid elements in blocks[b]). * * blocks_data holds the data pointed to by blocks. * * nr_squares may be NULL for block structures where all blocks are * the same size. */ int *whichblock, **blocks, *nr_squares, *blocks_data; int nr_blocks, max_nr_squares; #ifdef STANDALONE_SOLVER /* * Textual descriptions of each block. For normal Sudoku these * are of the form "(1,3)"; for jigsaw they are "starting at * (5,7)". So the sensible usage in both cases is to say * "elimination within block %s" with one of these strings. * * Only blocknames itself needs individually freeing; it's all * one block. */ char **blocknames; #endif }; struct game_state { /* * For historical reasons, I use `cr' to denote the overall * width/height of the puzzle. It was a natural notation when * all puzzles were divided into blocks in a grid, but doesn't * really make much sense given jigsaw puzzles. However, the * obvious `n' is heavily used in the solver to describe the * index of a number being placed, so `cr' will have to stay. */ int cr; struct block_structure *blocks; struct block_structure *kblocks; /* Blocks for killer puzzles. */ int xtype, killer; digit *grid, *kgrid; unsigned char *pencil; /* c*r*c*r elements */ unsigned char *immutable; /* marks which digits are clues */ int completed, cheated; }; static game_params *default_params(void) { game_params *ret = snew(game_params); ret->c = ret->r = 3; ret->xtype = FALSE; ret->killer = FALSE; ret->symm = SYMM_ROT2; /* a plausible default */ ret->diff = DIFF_BLOCK; /* so is this */ ret->kdiff = DIFF_KINTERSECT; /* so is this */ return ret; } static void free_params(game_params *params) { sfree(params); } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } static int game_fetch_preset(int i, char **name, game_params **params) { static struct { char *title; game_params params; } presets[] = { { "2x2 Trivial", { 2, 2, SYMM_ROT2, DIFF_BLOCK, DIFF_KMINMAX, FALSE, FALSE } }, { "2x3 Basic", { 2, 3, SYMM_ROT2, DIFF_SIMPLE, DIFF_KMINMAX, FALSE, FALSE } }, { "3x3 Trivial", { 3, 3, SYMM_ROT2, DIFF_BLOCK, DIFF_KMINMAX, FALSE, FALSE } }, { "3x3 Basic", { 3, 3, SYMM_ROT2, DIFF_SIMPLE, DIFF_KMINMAX, FALSE, FALSE } }, { "3x3 Basic X", { 3, 3, SYMM_ROT2, DIFF_SIMPLE, DIFF_KMINMAX, TRUE } }, { "3x3 Intermediate", { 3, 3, SYMM_ROT2, DIFF_INTERSECT, DIFF_KMINMAX, FALSE, FALSE } }, { "3x3 Advanced", { 3, 3, SYMM_ROT2, DIFF_SET, DIFF_KMINMAX, FALSE, FALSE } }, { "3x3 Advanced X", { 3, 3, SYMM_ROT2, DIFF_SET, DIFF_KMINMAX, TRUE } }, { "3x3 Extreme", { 3, 3, SYMM_ROT2, DIFF_EXTREME, DIFF_KMINMAX, FALSE, FALSE } }, { "3x3 Unreasonable", { 3, 3, SYMM_ROT2, DIFF_RECURSIVE, DIFF_KMINMAX, FALSE, FALSE } }, { "3x3 Killer", { 3, 3, SYMM_NONE, DIFF_BLOCK, DIFF_KINTERSECT, FALSE, TRUE } }, { "9 Jigsaw Basic", { 9, 1, SYMM_ROT2, DIFF_SIMPLE, DIFF_KMINMAX, FALSE, FALSE } }, { "9 Jigsaw Basic X", { 9, 1, SYMM_ROT2, DIFF_SIMPLE, DIFF_KMINMAX, TRUE } }, { "9 Jigsaw Advanced", { 9, 1, SYMM_ROT2, DIFF_SET, DIFF_KMINMAX, FALSE, FALSE } }, #ifndef SLOW_SYSTEM { "3x4 Basic", { 3, 4, SYMM_ROT2, DIFF_SIMPLE, DIFF_KMINMAX, FALSE, FALSE } }, { "4x4 Basic", { 4, 4, SYMM_ROT2, DIFF_SIMPLE, DIFF_KMINMAX, FALSE, FALSE } }, #endif }; if (i < 0 || i >= lenof(presets)) return FALSE; *name = dupstr(presets[i].title); *params = dup_params(&presets[i].params); return TRUE; } static void decode_params(game_params *ret, char const *string) { int seen_r = FALSE; ret->c = ret->r = atoi(string); ret->xtype = FALSE; ret->killer = FALSE; while (*string && isdigit((unsigned char)*string)) string++; if (*string == 'x') { string++; ret->r = atoi(string); seen_r = TRUE; while (*string && isdigit((unsigned char)*string)) string++; } while (*string) { if (*string == 'j') { string++; if (seen_r) ret->c *= ret->r; ret->r = 1; } else if (*string == 'x') { string++; ret->xtype = TRUE; } else if (*string == 'k') { string++; ret->killer = TRUE; } else if (*string == 'r' || *string == 'm' || *string == 'a') { int sn, sc, sd; sc = *string++; if (sc == 'm' && *string == 'd') { sd = TRUE; string++; } else { sd = FALSE; } sn = atoi(string); while (*string && isdigit((unsigned char)*string)) string++; if (sc == 'm' && sn == 8) ret->symm = SYMM_REF8; if (sc == 'm' && sn == 4) ret->symm = sd ? SYMM_REF4D : SYMM_REF4; if (sc == 'm' && sn == 2) ret->symm = sd ? SYMM_REF2D : SYMM_REF2; if (sc == 'r' && sn == 4) ret->symm = SYMM_ROT4; if (sc == 'r' && sn == 2) ret->symm = SYMM_ROT2; if (sc == 'a') ret->symm = SYMM_NONE; } else if (*string == 'd') { string++; if (*string == 't') /* trivial */ string++, ret->diff = DIFF_BLOCK; else if (*string == 'b') /* basic */ string++, ret->diff = DIFF_SIMPLE; else if (*string == 'i') /* intermediate */ string++, ret->diff = DIFF_INTERSECT; else if (*string == 'a') /* advanced */ string++, ret->diff = DIFF_SET; else if (*string == 'e') /* extreme */ string++, ret->diff = DIFF_EXTREME; else if (*string == 'u') /* unreasonable */ string++, ret->diff = DIFF_RECURSIVE; } else string++; /* eat unknown character */ } } static char *encode_params(const game_params *params, int full) { char str[80]; if (params->r > 1) sprintf(str, "%dx%d", params->c, params->r); else sprintf(str, "%dj", params->c); if (params->xtype) strcat(str, "x"); if (params->killer) strcat(str, "k"); if (full) { switch (params->symm) { case SYMM_REF8: strcat(str, "m8"); break; case SYMM_REF4: strcat(str, "m4"); break; case SYMM_REF4D: strcat(str, "md4"); break; case SYMM_REF2: strcat(str, "m2"); break; case SYMM_REF2D: strcat(str, "md2"); break; case SYMM_ROT4: strcat(str, "r4"); break; /* case SYMM_ROT2: strcat(str, "r2"); break; [default] */ case SYMM_NONE: strcat(str, "a"); break; } switch (params->diff) { /* case DIFF_BLOCK: strcat(str, "dt"); break; [default] */ case DIFF_SIMPLE: strcat(str, "db"); break; case DIFF_INTERSECT: strcat(str, "di"); break; case DIFF_SET: strcat(str, "da"); break; case DIFF_EXTREME: strcat(str, "de"); break; case DIFF_RECURSIVE: strcat(str, "du"); break; } } return dupstr(str); } static config_item *game_configure(const game_params *params) { config_item *ret; char buf[80]; ret = snewn(8, config_item); ret[0].name = "Columns of sub-blocks"; ret[0].type = C_STRING; sprintf(buf, "%d", params->c); ret[0].sval = dupstr(buf); ret[0].ival = 0; ret[1].name = "Rows of sub-blocks"; ret[1].type = C_STRING; sprintf(buf, "%d", params->r); ret[1].sval = dupstr(buf); ret[1].ival = 0; ret[2].name = "\"X\" (require every number in each main diagonal)"; ret[2].type = C_BOOLEAN; ret[2].sval = NULL; ret[2].ival = params->xtype; ret[3].name = "Jigsaw (irregularly shaped sub-blocks)"; ret[3].type = C_BOOLEAN; ret[3].sval = NULL; ret[3].ival = (params->r == 1); ret[4].name = "Killer (digit sums)"; ret[4].type = C_BOOLEAN; ret[4].sval = NULL; ret[4].ival = params->killer; ret[5].name = "Symmetry"; ret[5].type = C_CHOICES; ret[5].sval = ":None:2-way rotation:4-way rotation:2-way mirror:" "2-way diagonal mirror:4-way mirror:4-way diagonal mirror:" "8-way mirror"; ret[5].ival = params->symm; ret[6].name = "Difficulty"; ret[6].type = C_CHOICES; ret[6].sval = ":Trivial:Basic:Intermediate:Advanced:Extreme:Unreasonable"; ret[6].ival = params->diff; ret[7].name = NULL; ret[7].type = C_END; ret[7].sval = NULL; ret[7].ival = 0; return ret; } static game_params *custom_params(const config_item *cfg) { game_params *ret = snew(game_params); ret->c = atoi(cfg[0].sval); ret->r = atoi(cfg[1].sval); ret->xtype = cfg[2].ival; if (cfg[3].ival) { ret->c *= ret->r; ret->r = 1; } ret->killer = cfg[4].ival; ret->symm = cfg[5].ival; ret->diff = cfg[6].ival; ret->kdiff = DIFF_KINTERSECT; return ret; } static char *validate_params(const game_params *params, int full) { if (params->c < 2) return "Both dimensions must be at least 2"; if (params->c > ORDER_MAX || params->r > ORDER_MAX) return "Dimensions greater than "STR(ORDER_MAX)" are not supported"; if ((params->c * params->r) > 31) return "Unable to support more than 31 distinct symbols in a puzzle"; if (params->killer && params->c * params->r > 9) return "Killer puzzle dimensions must be smaller than 10."; return NULL; } /* * ---------------------------------------------------------------------- * Block structure functions. */ static struct block_structure *alloc_block_structure(int c, int r, int area, int max_nr_squares, int nr_blocks) { int i; struct block_structure *b = snew(struct block_structure); b->refcount = 1; b->nr_blocks = nr_blocks; b->max_nr_squares = max_nr_squares; b->c = c; b->r = r; b->area = area; b->whichblock = snewn(area, int); b->blocks_data = snewn(nr_blocks * max_nr_squares, int); b->blocks = snewn(nr_blocks, int *); b->nr_squares = snewn(nr_blocks, int); for (i = 0; i < nr_blocks; i++) b->blocks[i] = b->blocks_data + i*max_nr_squares; #ifdef STANDALONE_SOLVER b->blocknames = (char **)smalloc(c*r*(sizeof(char *)+80)); for (i = 0; i < c * r; i++) b->blocknames[i] = NULL; #endif return b; } static void free_block_structure(struct block_structure *b) { if (--b->refcount == 0) { sfree(b->whichblock); sfree(b->blocks); sfree(b->blocks_data); #ifdef STANDALONE_SOLVER sfree(b->blocknames); #endif sfree(b->nr_squares); sfree(b); } } static struct block_structure *dup_block_structure(struct block_structure *b) { struct block_structure *nb; int i; nb = alloc_block_structure(b->c, b->r, b->area, b->max_nr_squares, b->nr_blocks); memcpy(nb->nr_squares, b->nr_squares, b->nr_blocks * sizeof *b->nr_squares); memcpy(nb->whichblock, b->whichblock, b->area * sizeof *b->whichblock); memcpy(nb->blocks_data, b->blocks_data, b->nr_blocks * b->max_nr_squares * sizeof *b->blocks_data); for (i = 0; i < b->nr_blocks; i++) nb->blocks[i] = nb->blocks_data + i*nb->max_nr_squares; #ifdef STANDALONE_SOLVER memcpy(nb->blocknames, b->blocknames, b->c * b->r *(sizeof(char *)+80)); { int i; for (i = 0; i < b->c * b->r; i++) if (b->blocknames[i] == NULL) nb->blocknames[i] = NULL; else nb->blocknames[i] = ((char *)nb->blocknames) + (b->blocknames[i] - (char *)b->blocknames); } #endif return nb; } static void split_block(struct block_structure *b, int *squares, int nr_squares) { int i, j; int previous_block = b->whichblock[squares[0]]; int newblock = b->nr_blocks; assert(b->max_nr_squares >= nr_squares); assert(b->nr_squares[previous_block] > nr_squares); b->nr_blocks++; b->blocks_data = sresize(b->blocks_data, b->nr_blocks * b->max_nr_squares, int); b->nr_squares = sresize(b->nr_squares, b->nr_blocks, int); sfree(b->blocks); b->blocks = snewn(b->nr_blocks, int *); for (i = 0; i < b->nr_blocks; i++) b->blocks[i] = b->blocks_data + i*b->max_nr_squares; for (i = 0; i < nr_squares; i++) { assert(b->whichblock[squares[i]] == previous_block); b->whichblock[squares[i]] = newblock; b->blocks[newblock][i] = squares[i]; } for (i = j = 0; i < b->nr_squares[previous_block]; i++) { int k; int sq = b->blocks[previous_block][i]; for (k = 0; k < nr_squares; k++) if (squares[k] == sq) break; if (k == nr_squares) b->blocks[previous_block][j++] = sq; } b->nr_squares[previous_block] -= nr_squares; b->nr_squares[newblock] = nr_squares; } static void remove_from_block(struct block_structure *blocks, int b, int n) { int i, j; blocks->whichblock[n] = -1; for (i = j = 0; i < blocks->nr_squares[b]; i++) if (blocks->blocks[b][i] != n) blocks->blocks[b][j++] = blocks->blocks[b][i]; assert(j+1 == i); blocks->nr_squares[b]--; } /* ---------------------------------------------------------------------- * Solver. * * This solver is used for two purposes: * + to check solubility of a grid as we gradually remove numbers * from it * + to solve an externally generated puzzle when the user selects * `Solve'. * * It supports a variety of specific modes of reasoning. By * enabling or disabling subsets of these modes we can arrange a * range of difficulty levels. */ /* * Modes of reasoning currently supported: * * - Positional elimination: a number must go in a particular * square because all the other empty squares in a given * row/col/blk are ruled out. * * - Killer minmax elimination: for killer-type puzzles, a number * is impossible if choosing it would cause the sum in a killer * region to be guaranteed to be too large or too small. * * - Numeric elimination: a square must have a particular number * in because all the other numbers that could go in it are * ruled out. * * - Intersectional analysis: given two domains which overlap * (hence one must be a block, and the other can be a row or * col), if the possible locations for a particular number in * one of the domains can be narrowed down to the overlap, then * that number can be ruled out everywhere but the overlap in * the other domain too. * * - Set elimination: if there is a subset of the empty squares * within a domain such that the union of the possible numbers * in that subset has the same size as the subset itself, then * those numbers can be ruled out everywhere else in the domain. * (For example, if there are five empty squares and the * possible numbers in each are 12, 23, 13, 134 and 1345, then * the first three empty squares form such a subset: the numbers * 1, 2 and 3 _must_ be in those three squares in some * permutation, and hence we can deduce none of them can be in * the fourth or fifth squares.) * + You can also see this the other way round, concentrating * on numbers rather than squares: if there is a subset of * the unplaced numbers within a domain such that the union * of all their possible positions has the same size as the * subset itself, then all other numbers can be ruled out for * those positions. However, it turns out that this is * exactly equivalent to the first formulation at all times: * there is a 1-1 correspondence between suitable subsets of * the unplaced numbers and suitable subsets of the unfilled * places, found by taking the _complement_ of the union of * the numbers' possible positions (or the spaces' possible * contents). * * - Forcing chains (see comment for solver_forcing().) * * - Recursion. If all else fails, we pick one of the currently * most constrained empty squares and take a random guess at its * contents, then continue solving on that basis and see if we * get any further. */ struct solver_usage { int cr; struct block_structure *blocks, *kblocks, *extra_cages; /* * We set up a cubic array, indexed by x, y and digit; each * element of this array is TRUE or FALSE according to whether * or not that digit _could_ in principle go in that position. * * The way to index this array is cube[(y*cr+x)*cr+n-1]; there * are macros below to help with this. */ unsigned char *cube; /* * This is the grid in which we write down our final * deductions. y-coordinates in here are _not_ transformed. */ digit *grid; /* * For killer-type puzzles, kclues holds the secondary clue for * each cage. For derived cages, the clue is in extra_clues. */ digit *kclues, *extra_clues; /* * Now we keep track, at a slightly higher level, of what we * have yet to work out, to prevent doing the same deduction * many times. */ /* row[y*cr+n-1] TRUE if digit n has been placed in row y */ unsigned char *row; /* col[x*cr+n-1] TRUE if digit n has been placed in row x */ unsigned char *col; /* blk[i*cr+n-1] TRUE if digit n has been placed in block i */ unsigned char *blk; /* diag[i*cr+n-1] TRUE if digit n has been placed in diagonal i */ unsigned char *diag; /* diag 0 is \, 1 is / */ int *regions; int nr_regions; int **sq2region; }; #define cubepos2(xy,n) ((xy)*usage->cr+(n)-1) #define cubepos(x,y,n) cubepos2((y)*usage->cr+(x),n) #define cube(x,y,n) (usage->cube[cubepos(x,y,n)]) #define cube2(xy,n) (usage->cube[cubepos2(xy,n)]) #define ondiag0(xy) ((xy) % (cr+1) == 0) #define ondiag1(xy) ((xy) % (cr-1) == 0 && (xy) > 0 && (xy) < cr*cr-1) #define diag0(i) ((i) * (cr+1)) #define diag1(i) ((i+1) * (cr-1)) /* * Function called when we are certain that a particular square has * a particular number in it. The y-coordinate passed in here is * transformed. */ static void solver_place(struct solver_usage *usage, int x, int y, int n) { int cr = usage->cr; int sqindex = y*cr+x; int i, bi; assert(cube(x,y,n)); /* * Rule out all other numbers in this square. */ for (i = 1; i <= cr; i++) if (i != n) cube(x,y,i) = FALSE; /* * Rule out this number in all other positions in the row. */ for (i = 0; i < cr; i++) if (i != y) cube(x,i,n) = FALSE; /* * Rule out this number in all other positions in the column. */ for (i = 0; i < cr; i++) if (i != x) cube(i,y,n) = FALSE; /* * Rule out this number in all other positions in the block. */ bi = usage->blocks->whichblock[sqindex]; for (i = 0; i < cr; i++) { int bp = usage->blocks->blocks[bi][i]; if (bp != sqindex) cube2(bp,n) = FALSE; } /* * Enter the number in the result grid. */ usage->grid[sqindex] = n; /* * Cross out this number from the list of numbers left to place * in its row, its column and its block. */ usage->row[y*cr+n-1] = usage->col[x*cr+n-1] = usage->blk[bi*cr+n-1] = TRUE; if (usage->diag) { if (ondiag0(sqindex)) { for (i = 0; i < cr; i++) if (diag0(i) != sqindex) cube2(diag0(i),n) = FALSE; usage->diag[n-1] = TRUE; } if (ondiag1(sqindex)) { for (i = 0; i < cr; i++) if (diag1(i) != sqindex) cube2(diag1(i),n) = FALSE; usage->diag[cr+n-1] = TRUE; } } } #if defined STANDALONE_SOLVER && defined __GNUC__ /* * Forward-declare the functions taking printf-like format arguments * with __attribute__((format)) so as to ensure the argument syntax * gets debugged. */ struct solver_scratch; static int solver_elim(struct solver_usage *usage, int *indices, char *fmt, ...) __attribute__((format(printf,3,4))); static int solver_intersect(struct solver_usage *usage, int *indices1, int *indices2, char *fmt, ...) __attribute__((format(printf,4,5))); static int solver_set(struct solver_usage *usage, struct solver_scratch *scratch, int *indices, char *fmt, ...) __attribute__((format(printf,4,5))); #endif static int solver_elim(struct solver_usage *usage, int *indices #ifdef STANDALONE_SOLVER , char *fmt, ... #endif ) { int cr = usage->cr; int fpos, m, i; /* * Count the number of set bits within this section of the * cube. */ m = 0; fpos = -1; for (i = 0; i < cr; i++) if (usage->cube[indices[i]]) { fpos = indices[i]; m++; } if (m == 1) { int x, y, n; assert(fpos >= 0); n = 1 + fpos % cr; x = fpos / cr; y = x / cr; x %= cr; if (!usage->grid[y*cr+x]) { #ifdef STANDALONE_SOLVER if (solver_show_working) { va_list ap; printf("%*s", solver_recurse_depth*4, ""); va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); printf(":\n%*s placing %d at (%d,%d)\n", solver_recurse_depth*4, "", n, 1+x, 1+y); } #endif solver_place(usage, x, y, n); return +1; } } else if (m == 0) { #ifdef STANDALONE_SOLVER if (solver_show_working) { va_list ap; printf("%*s", solver_recurse_depth*4, ""); va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); printf(":\n%*s no possibilities available\n", solver_recurse_depth*4, ""); } #endif return -1; } return 0; } static int solver_intersect(struct solver_usage *usage, int *indices1, int *indices2 #ifdef STANDALONE_SOLVER , char *fmt, ... #endif ) { int cr = usage->cr; int ret, i, j; /* * Loop over the first domain and see if there's any set bit * not also in the second. */ for (i = j = 0; i < cr; i++) { int p = indices1[i]; while (j < cr && indices2[j] < p) j++; if (usage->cube[p]) { if (j < cr && indices2[j] == p) continue; /* both domains contain this index */ else return 0; /* there is, so we can't deduce */ } } /* * We have determined that all set bits in the first domain are * within its overlap with the second. So loop over the second * domain and remove all set bits that aren't also in that * overlap; return +1 iff we actually _did_ anything. */ ret = 0; for (i = j = 0; i < cr; i++) { int p = indices2[i]; while (j < cr && indices1[j] < p) j++; if (usage->cube[p] && (j >= cr || indices1[j] != p)) { #ifdef STANDALONE_SOLVER if (solver_show_working) { int px, py, pn; if (!ret) { va_list ap; printf("%*s", solver_recurse_depth*4, ""); va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); printf(":\n"); } pn = 1 + p % cr; px = p / cr; py = px / cr; px %= cr; printf("%*s ruling out %d at (%d,%d)\n", solver_recurse_depth*4, "", pn, 1+px, 1+py); } #endif ret = +1; /* we did something */ usage->cube[p] = 0; } } return ret; } struct solver_scratch { unsigned char *grid, *rowidx, *colidx, *set; int *neighbours, *bfsqueue; int *indexlist, *indexlist2; #ifdef STANDALONE_SOLVER int *bfsprev; #endif }; static int solver_set(struct solver_usage *usage, struct solver_scratch *scratch, int *indices #ifdef STANDALONE_SOLVER , char *fmt, ... #endif ) { int cr = usage->cr; int i, j, n, count; unsigned char *grid = scratch->grid; unsigned char *rowidx = scratch->rowidx; unsigned char *colidx = scratch->colidx; unsigned char *set = scratch->set; /* * We are passed a cr-by-cr matrix of booleans. Our first job * is to winnow it by finding any definite placements - i.e. * any row with a solitary 1 - and discarding that row and the * column containing the 1. */ memset(rowidx, TRUE, cr); memset(colidx, TRUE, cr); for (i = 0; i < cr; i++) { int count = 0, first = -1; for (j = 0; j < cr; j++) if (usage->cube[indices[i*cr+j]]) first = j, count++; /* * If count == 0, then there's a row with no 1s at all and * the puzzle is internally inconsistent. However, we ought * to have caught this already during the simpler reasoning * methods, so we can safely fail an assertion if we reach * this point here. */ assert(count > 0); if (count == 1) rowidx[i] = colidx[first] = FALSE; } /* * Convert each of rowidx/colidx from a list of 0s and 1s to a * list of the indices of the 1s. */ for (i = j = 0; i < cr; i++) if (rowidx[i]) rowidx[j++] = i; n = j; for (i = j = 0; i < cr; i++) if (colidx[i]) colidx[j++] = i; assert(n == j); /* * And create the smaller matrix. */ for (i = 0; i < n; i++) for (j = 0; j < n; j++) grid[i*cr+j] = usage->cube[indices[rowidx[i]*cr+colidx[j]]]; /* * Having done that, we now have a matrix in which every row * has at least two 1s in. Now we search to see if we can find * a rectangle of zeroes (in the set-theoretic sense of * `rectangle', i.e. a subset of rows crossed with a subset of * columns) whose width and height add up to n. */ memset(set, 0, n); count = 0; while (1) { /* * We have a candidate set. If its size is <=1 or >=n-1 * then we move on immediately. */ if (count > 1 && count < n-1) { /* * The number of rows we need is n-count. See if we can * find that many rows which each have a zero in all * the positions listed in `set'. */ int rows = 0; for (i = 0; i < n; i++) { int ok = TRUE; for (j = 0; j < n; j++) if (set[j] && grid[i*cr+j]) { ok = FALSE; break; } if (ok) rows++; } /* * We expect never to be able to get _more_ than * n-count suitable rows: this would imply that (for * example) there are four numbers which between them * have at most three possible positions, and hence it * indicates a faulty deduction before this point or * even a bogus clue. */ if (rows > n - count) { #ifdef STANDALONE_SOLVER if (solver_show_working) { va_list ap; printf("%*s", solver_recurse_depth*4, ""); va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); printf(":\n%*s contradiction reached\n", solver_recurse_depth*4, ""); } #endif return -1; } if (rows >= n - count) { int progress = FALSE; /* * We've got one! Now, for each row which _doesn't_ * satisfy the criterion, eliminate all its set * bits in the positions _not_ listed in `set'. * Return +1 (meaning progress has been made) if we * successfully eliminated anything at all. * * This involves referring back through * rowidx/colidx in order to work out which actual * positions in the cube to meddle with. */ for (i = 0; i < n; i++) { int ok = TRUE; for (j = 0; j < n; j++) if (set[j] && grid[i*cr+j]) { ok = FALSE; break; } if (!ok) { for (j = 0; j < n; j++) if (!set[j] && grid[i*cr+j]) { int fpos = indices[rowidx[i]*cr+colidx[j]]; #ifdef STANDALONE_SOLVER if (solver_show_working) { int px, py, pn; if (!progress) { va_list ap; printf("%*s", solver_recurse_depth*4, ""); va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); printf(":\n"); } pn = 1 + fpos % cr; px = fpos / cr; py = px / cr; px %= cr; printf("%*s ruling out %d at (%d,%d)\n", solver_recurse_depth*4, "", pn, 1+px, 1+py); } #endif progress = TRUE; usage->cube[fpos] = FALSE; } } } if (progress) { return +1; } } } /* * Binary increment: change the rightmost 0 to a 1, and * change all 1s to the right of it to 0s. */ i = n; while (i > 0 && set[i-1]) set[--i] = 0, count--; if (i > 0) set[--i] = 1, count++; else break; /* done */ } return 0; } /* * Look for forcing chains. A forcing chain is a path of * pairwise-exclusive squares (i.e. each pair of adjacent squares * in the path are in the same row, column or block) with the * following properties: * * (a) Each square on the path has precisely two possible numbers. * * (b) Each pair of squares which are adjacent on the path share * at least one possible number in common. * * (c) Each square in the middle of the path shares _both_ of its * numbers with at least one of its neighbours (not the same * one with both neighbours). * * These together imply that at least one of the possible number * choices at one end of the path forces _all_ the rest of the * numbers along the path. In order to make real use of this, we * need further properties: * * (c) Ruling out some number N from the square at one end of the * path forces the square at the other end to take the same * number N. * * (d) The two end squares are both in line with some third * square. * * (e) That third square currently has N as a possibility. * * If we can find all of that lot, we can deduce that at least one * of the two ends of the forcing chain has number N, and that * therefore the mutually adjacent third square does not. * * To find forcing chains, we're going to start a bfs at each * suitable square, once for each of its two possible numbers. */ static int solver_forcing(struct solver_usage *usage, struct solver_scratch *scratch) { int cr = usage->cr; int *bfsqueue = scratch->bfsqueue; #ifdef STANDALONE_SOLVER int *bfsprev = scratch->bfsprev; #endif unsigned char *number = scratch->grid; int *neighbours = scratch->neighbours; int x, y; for (y = 0; y < cr; y++) for (x = 0; x < cr; x++) { int count, t, n; /* * If this square doesn't have exactly two candidate * numbers, don't try it. * * In this loop we also sum the candidate numbers, * which is a nasty hack to allow us to quickly find * `the other one' (since we will shortly know there * are exactly two). */ for (count = t = 0, n = 1; n <= cr; n++) if (cube(x, y, n)) count++, t += n; if (count != 2) continue; /* * Now attempt a bfs for each candidate. */ for (n = 1; n <= cr; n++) if (cube(x, y, n)) { int orign, currn, head, tail; /* * Begin a bfs. */ orign = n; memset(number, cr+1, cr*cr); head = tail = 0; bfsqueue[tail++] = y*cr+x; #ifdef STANDALONE_SOLVER bfsprev[y*cr+x] = -1; #endif number[y*cr+x] = t - n; while (head < tail) { int xx, yy, nneighbours, xt, yt, i; xx = bfsqueue[head++]; yy = xx / cr; xx %= cr; currn = number[yy*cr+xx]; /* * Find neighbours of yy,xx. */ nneighbours = 0; for (yt = 0; yt < cr; yt++) neighbours[nneighbours++] = yt*cr+xx; for (xt = 0; xt < cr; xt++) neighbours[nneighbours++] = yy*cr+xt; xt = usage->blocks->whichblock[yy*cr+xx]; for (yt = 0; yt < cr; yt++) neighbours[nneighbours++] = usage->blocks->blocks[xt][yt]; if (usage->diag) { int sqindex = yy*cr+xx; if (ondiag0(sqindex)) { for (i = 0; i < cr; i++) neighbours[nneighbours++] = diag0(i); } if (ondiag1(sqindex)) { for (i = 0; i < cr; i++) neighbours[nneighbours++] = diag1(i); } } /* * Try visiting each of those neighbours. */ for (i = 0; i < nneighbours; i++) { int cc, tt, nn; xt = neighbours[i] % cr; yt = neighbours[i] / cr; /* * We need this square to not be * already visited, and to include * currn as a possible number. */ if (number[yt*cr+xt] <= cr) continue; if (!cube(xt, yt, currn)) continue; /* * Don't visit _this_ square a second * time! */ if (xt == xx && yt == yy) continue; /* * To continue with the bfs, we need * this square to have exactly two * possible numbers. */ for (cc = tt = 0, nn = 1; nn <= cr; nn++) if (cube(xt, yt, nn)) cc++, tt += nn; if (cc == 2) { bfsqueue[tail++] = yt*cr+xt; #ifdef STANDALONE_SOLVER bfsprev[yt*cr+xt] = yy*cr+xx; #endif number[yt*cr+xt] = tt - currn; } /* * One other possibility is that this * might be the square in which we can * make a real deduction: if it's * adjacent to x,y, and currn is equal * to the original number we ruled out. */ if (currn == orign && (xt == x || yt == y || (usage->blocks->whichblock[yt*cr+xt] == usage->blocks->whichblock[y*cr+x]) || (usage->diag && ((ondiag0(yt*cr+xt) && ondiag0(y*cr+x)) || (ondiag1(yt*cr+xt) && ondiag1(y*cr+x)))))) { #ifdef STANDALONE_SOLVER if (solver_show_working) { char *sep = ""; int xl, yl; printf("%*sforcing chain, %d at ends of ", solver_recurse_depth*4, "", orign); xl = xx; yl = yy; while (1) { printf("%s(%d,%d)", sep, 1+xl, 1+yl); xl = bfsprev[yl*cr+xl]; if (xl < 0) break; yl = xl / cr; xl %= cr; sep = "-"; } printf("\n%*s ruling out %d at (%d,%d)\n", solver_recurse_depth*4, "", orign, 1+xt, 1+yt); } #endif cube(xt, yt, orign) = FALSE; return 1; } } } } } return 0; } static int solver_killer_minmax(struct solver_usage *usage, struct block_structure *cages, digit *clues, int b #ifdef STANDALONE_SOLVER , const char *extra #endif ) { int cr = usage->cr; int i; int ret = 0; int nsquares = cages->nr_squares[b]; if (clues[b] == 0) return 0; for (i = 0; i < nsquares; i++) { int n, x = cages->blocks[b][i]; for (n = 1; n <= cr; n++) if (cube2(x, n)) { int maxval = 0, minval = 0; int j; for (j = 0; j < nsquares; j++) { int m; int y = cages->blocks[b][j]; if (i == j) continue; for (m = 1; m <= cr; m++) if (cube2(y, m)) { minval += m; break; } for (m = cr; m > 0; m--) if (cube2(y, m)) { maxval += m; break; } } if (maxval + n < clues[b]) { cube2(x, n) = FALSE; ret = 1; #ifdef STANDALONE_SOLVER if (solver_show_working) printf("%*s ruling out %d at (%d,%d) as too low %s\n", solver_recurse_depth*4, "killer minmax analysis", n, 1 + x%cr, 1 + x/cr, extra); #endif } if (minval + n > clues[b]) { cube2(x, n) = FALSE; ret = 1; #ifdef STANDALONE_SOLVER if (solver_show_working) printf("%*s ruling out %d at (%d,%d) as too high %s\n", solver_recurse_depth*4, "killer minmax analysis", n, 1 + x%cr, 1 + x/cr, extra); #endif } } } return ret; } static int solver_killer_sums(struct solver_usage *usage, int b, struct block_structure *cages, int clue, int cage_is_region #ifdef STANDALONE_SOLVER , const char *cage_type #endif ) { int cr = usage->cr; int i, ret, max_sums; int nsquares = cages->nr_squares[b]; unsigned long *sumbits, possible_addends; if (clue == 0) { assert(nsquares == 0); return 0; } assert(nsquares > 0); if (nsquares < 2 || nsquares > 4) return 0; if (!cage_is_region) { int known_row = -1, known_col = -1, known_block = -1; /* * Verify that the cage lies entirely within one region, * so that using the precomputed sums is valid. */ for (i = 0; i < nsquares; i++) { int x = cages->blocks[b][i]; assert(usage->grid[x] == 0); if (i == 0) { known_row = x/cr; known_col = x%cr; known_block = usage->blocks->whichblock[x]; } else { if (known_row != x/cr) known_row = -1; if (known_col != x%cr) known_col = -1; if (known_block != usage->blocks->whichblock[x]) known_block = -1; } } if (known_block == -1 && known_col == -1 && known_row == -1) return 0; } if (nsquares == 2) { if (clue < 3 || clue > 17) return -1; sumbits = sum_bits2[clue]; max_sums = MAX_2SUMS; } else if (nsquares == 3) { if (clue < 6 || clue > 24) return -1; sumbits = sum_bits3[clue]; max_sums = MAX_3SUMS; } else { if (clue < 10 || clue > 30) return -1; sumbits = sum_bits4[clue]; max_sums = MAX_4SUMS; } /* * For every possible way to get the sum, see if there is * one square in the cage that disallows all the required * addends. If we find one such square, this way to compute * the sum is impossible. */ possible_addends = 0; for (i = 0; i < max_sums; i++) { int j; unsigned long bits = sumbits[i]; if (bits == 0) break; for (j = 0; j < nsquares; j++) { int n; unsigned long square_bits = bits; int x = cages->blocks[b][j]; for (n = 1; n <= cr; n++) if (!cube2(x, n)) square_bits &= ~(1L << n); if (square_bits == 0) { break; } } if (j == nsquares) possible_addends |= bits; } /* * Now we know which addends can possibly be used to * compute the sum. Remove all other digits from the * set of possibilities. */ if (possible_addends == 0) return -1; ret = 0; for (i = 0; i < nsquares; i++) { int n; int x = cages->blocks[b][i]; for (n = 1; n <= cr; n++) { if (!cube2(x, n)) continue; if ((possible_addends & (1 << n)) == 0) { cube2(x, n) = FALSE; ret = 1; #ifdef STANDALONE_SOLVER if (solver_show_working) { printf("%*s using %s\n", solver_recurse_depth*4, "killer sums analysis", cage_type); printf("%*s ruling out %d at (%d,%d) due to impossible %d-sum\n", solver_recurse_depth*4, "", n, 1 + x%cr, 1 + x/cr, nsquares); } #endif } } } return ret; } static int filter_whole_cages(struct solver_usage *usage, int *squares, int n, int *filtered_sum) { int b, i, j, off; *filtered_sum = 0; /* First, filter squares with a clue. */ for (i = j = 0; i < n; i++) if (usage->grid[squares[i]]) *filtered_sum += usage->grid[squares[i]]; else squares[j++] = squares[i]; n = j; /* * Filter all cages that are covered entirely by the list of * squares. */ off = 0; for (b = 0; b < usage->kblocks->nr_blocks && off < n; b++) { int b_squares = usage->kblocks->nr_squares[b]; int matched = 0; if (b_squares == 0) continue; /* * Find all squares of block b that lie in our list, * and make them contiguous at off, which is the current position * in the output list. */ for (i = 0; i < b_squares; i++) { for (j = off; j < n; j++) if (squares[j] == usage->kblocks->blocks[b][i]) { int t = squares[off + matched]; squares[off + matched] = squares[j]; squares[j] = t; matched++; break; } } /* If so, filter out all squares of b from the list. */ if (matched != usage->kblocks->nr_squares[b]) { off += matched; continue; } memmove(squares + off, squares + off + matched, (n - off - matched) * sizeof *squares); n -= matched; *filtered_sum += usage->kclues[b]; } assert(off == n); return off; } static struct solver_scratch *solver_new_scratch(struct solver_usage *usage) { struct solver_scratch *scratch = snew(struct solver_scratch); int cr = usage->cr; scratch->grid = snewn(cr*cr, unsigned char); scratch->rowidx = snewn(cr, unsigned char); scratch->colidx = snewn(cr, unsigned char); scratch->set = snewn(cr, unsigned char); scratch->neighbours = snewn(5*cr, int); scratch->bfsqueue = snewn(cr*cr, int); #ifdef STANDALONE_SOLVER scratch->bfsprev = snewn(cr*cr, int); #endif scratch->indexlist = snewn(cr*cr, int); /* used for set elimination */ scratch->indexlist2 = snewn(cr, int); /* only used for intersect() */ return scratch; } static void solver_free_scratch(struct solver_scratch *scratch) { #ifdef STANDALONE_SOLVER sfree(scratch->bfsprev); #endif sfree(scratch->bfsqueue); sfree(scratch->neighbours); sfree(scratch->set); sfree(scratch->colidx); sfree(scratch->rowidx); sfree(scratch->grid); sfree(scratch->indexlist); sfree(scratch->indexlist2); sfree(scratch); } /* * Used for passing information about difficulty levels between the solver * and its callers. */ struct difficulty { /* Maximum levels allowed. */ int maxdiff, maxkdiff; /* Levels reached by the solver. */ int diff, kdiff; }; static void solver(int cr, struct block_structure *blocks, struct block_structure *kblocks, int xtype, digit *grid, digit *kgrid, struct difficulty *dlev) { struct solver_usage *usage; struct solver_scratch *scratch; int x, y, b, i, n, ret; int diff = DIFF_BLOCK; int kdiff = DIFF_KSINGLE; /* * Set up a usage structure as a clean slate (everything * possible). */ usage = snew(struct solver_usage); usage->cr = cr; usage->blocks = blocks; if (kblocks) { usage->kblocks = dup_block_structure(kblocks); usage->extra_cages = alloc_block_structure (kblocks->c, kblocks->r, cr * cr, cr, cr * cr); usage->extra_clues = snewn(cr*cr, digit); } else { usage->kblocks = usage->extra_cages = NULL; usage->extra_clues = NULL; } usage->cube = snewn(cr*cr*cr, unsigned char); usage->grid = grid; /* write straight back to the input */ if (kgrid) { int nclues; assert(kblocks); nclues = kblocks->nr_blocks; /* * Allow for expansion of the killer regions, the absolute * limit is obviously one region per square. */ usage->kclues = snewn(cr*cr, digit); for (i = 0; i < nclues; i++) { for (n = 0; n < kblocks->nr_squares[i]; n++) if (kgrid[kblocks->blocks[i][n]] != 0) usage->kclues[i] = kgrid[kblocks->blocks[i][n]]; assert(usage->kclues[i] > 0); } memset(usage->kclues + nclues, 0, cr*cr - nclues); } else { usage->kclues = NULL; } memset(usage->cube, TRUE, cr*cr*cr); usage->row = snewn(cr * cr, unsigned char); usage->col = snewn(cr * cr, unsigned char); usage->blk = snewn(cr * cr, unsigned char); memset(usage->row, FALSE, cr * cr); memset(usage->col, FALSE, cr * cr); memset(usage->blk, FALSE, cr * cr); if (xtype) { usage->diag = snewn(cr * 2, unsigned char); memset(usage->diag, FALSE, cr * 2); } else usage->diag = NULL; usage->nr_regions = cr * 3 + (xtype ? 2 : 0); usage->regions = snewn(cr * usage->nr_regions, int); usage->sq2region = snewn(cr * cr * 3, int *); for (n = 0; n < cr; n++) { for (i = 0; i < cr; i++) { x = n*cr+i; y = i*cr+n; b = usage->blocks->blocks[n][i]; usage->regions[cr*n*3 + i] = x; usage->regions[cr*n*3 + cr + i] = y; usage->regions[cr*n*3 + 2*cr + i] = b; usage->sq2region[x*3] = usage->regions + cr*n*3; usage->sq2region[y*3 + 1] = usage->regions + cr*n*3 + cr; usage->sq2region[b*3 + 2] = usage->regions + cr*n*3 + 2*cr; } } scratch = solver_new_scratch(usage); /* * Place all the clue numbers we are given. */ for (x = 0; x < cr; x++) for (y = 0; y < cr; y++) { int n = grid[y*cr+x]; if (n) { if (!cube(x,y,n)) { diff = DIFF_IMPOSSIBLE; goto got_result; } solver_place(usage, x, y, grid[y*cr+x]); } } /* * Now loop over the grid repeatedly trying all permitted modes * of reasoning. The loop terminates if we complete an * iteration without making any progress; we then return * failure or success depending on whether the grid is full or * not. */ while (1) { /* * I'd like to write `continue;' inside each of the * following loops, so that the solver returns here after * making some progress. However, I can't specify that I * want to continue an outer loop rather than the innermost * one, so I'm apologetically resorting to a goto. */ cont: /* * Blockwise positional elimination. */ for (b = 0; b < cr; b++) for (n = 1; n <= cr; n++) if (!usage->blk[b*cr+n-1]) { for (i = 0; i < cr; i++) scratch->indexlist[i] = cubepos2(usage->blocks->blocks[b][i],n); ret = solver_elim(usage, scratch->indexlist #ifdef STANDALONE_SOLVER , "positional elimination," " %d in block %s", n, usage->blocks->blocknames[b] #endif ); if (ret < 0) { diff = DIFF_IMPOSSIBLE; goto got_result; } else if (ret > 0) { diff = max(diff, DIFF_BLOCK); goto cont; } } if (usage->kclues != NULL) { int changed = FALSE; /* * First, bring the kblocks into a more useful form: remove * all filled-in squares, and reduce the sum by their values. * Walk in reverse order, since otherwise remove_from_block * can move element past our loop counter. */ for (b = 0; b < usage->kblocks->nr_blocks; b++) for (i = usage->kblocks->nr_squares[b] -1; i >= 0; i--) { int x = usage->kblocks->blocks[b][i]; int t = usage->grid[x]; if (t == 0) continue; remove_from_block(usage->kblocks, b, x); if (t > usage->kclues[b]) { diff = DIFF_IMPOSSIBLE; goto got_result; } usage->kclues[b] -= t; /* * Since cages are regions, this tells us something * about the other squares in the cage. */ for (n = 0; n < usage->kblocks->nr_squares[b]; n++) { cube2(usage->kblocks->blocks[b][n], t) = FALSE; } } /* * The most trivial kind of solver for killer puzzles: fill * single-square cages. */ for (b = 0; b < usage->kblocks->nr_blocks; b++) { int squares = usage->kblocks->nr_squares[b]; if (squares == 1) { int v = usage->kclues[b]; if (v < 1 || v > cr) { diff = DIFF_IMPOSSIBLE; goto got_result; } x = usage->kblocks->blocks[b][0] % cr; y = usage->kblocks->blocks[b][0] / cr; if (!cube(x, y, v)) { diff = DIFF_IMPOSSIBLE; goto got_result; } solver_place(usage, x, y, v); #ifdef STANDALONE_SOLVER if (solver_show_working) { printf("%*s placing %d at (%d,%d)\n", solver_recurse_depth*4, "killer single-square cage", v, 1 + x%cr, 1 + x/cr); } #endif changed = TRUE; } } if (changed) { kdiff = max(kdiff, DIFF_KSINGLE); goto cont; } } if (dlev->maxkdiff >= DIFF_KINTERSECT && usage->kclues != NULL) { int changed = FALSE; /* * Now, create the extra_cages information. Every full region * (row, column, or block) has the same sum total (45 for 3x3 * puzzles. After we try to cover these regions with cages that * lie entirely within them, any squares that remain must bring * the total to this known value, and so they form additional * cages which aren't immediately evident in the displayed form * of the puzzle. */ usage->extra_cages->nr_blocks = 0; for (i = 0; i < 3; i++) { for (n = 0; n < cr; n++) { int *region = usage->regions + cr*n*3 + i*cr; int sum = cr * (cr + 1) / 2; int nsquares = cr; int filtered; int n_extra = usage->extra_cages->nr_blocks; int *extra_list = usage->extra_cages->blocks[n_extra]; memcpy(extra_list, region, cr * sizeof *extra_list); nsquares = filter_whole_cages(usage, extra_list, nsquares, &filtered); sum -= filtered; if (nsquares == cr || nsquares == 0) continue; if (dlev->maxdiff >= DIFF_RECURSIVE) { if (sum <= 0) { dlev->diff = DIFF_IMPOSSIBLE; goto got_result; } } assert(sum > 0); if (nsquares == 1) { if (sum > cr) { diff = DIFF_IMPOSSIBLE; goto got_result; } x = extra_list[0] % cr; y = extra_list[0] / cr; if (!cube(x, y, sum)) { diff = DIFF_IMPOSSIBLE; goto got_result; } solver_place(usage, x, y, sum); changed = TRUE; #ifdef STANDALONE_SOLVER if (solver_show_working) { printf("%*s placing %d at (%d,%d)\n", solver_recurse_depth*4, "killer single-square deduced cage", sum, 1 + x, 1 + y); } #endif } b = usage->kblocks->whichblock[extra_list[0]]; for (x = 1; x < nsquares; x++) if (usage->kblocks->whichblock[extra_list[x]] != b) break; if (x == nsquares) { assert(usage->kblocks->nr_squares[b] > nsquares); split_block(usage->kblocks, extra_list, nsquares); assert(usage->kblocks->nr_squares[usage->kblocks->nr_blocks - 1] == nsquares); usage->kclues[usage->kblocks->nr_blocks - 1] = sum; usage->kclues[b] -= sum; } else { usage->extra_cages->nr_squares[n_extra] = nsquares; usage->extra_cages->nr_blocks++; usage->extra_clues[n_extra] = sum; } } } if (changed) { kdiff = max(kdiff, DIFF_KINTERSECT); goto cont; } } /* * Another simple killer-type elimination. For every square in a * cage, find the minimum and maximum possible sums of all the * other squares in the same cage, and rule out possibilities * for the given square based on whether they are guaranteed to * cause the sum to be either too high or too low. * This is a special case of trying all possible sums across a * region, which is a recursive algorithm. We should probably * implement it for a higher difficulty level. */ if (dlev->maxkdiff >= DIFF_KMINMAX && usage->kclues != NULL) { int changed = FALSE; for (b = 0; b < usage->kblocks->nr_blocks; b++) { int ret = solver_killer_minmax(usage, usage->kblocks, usage->kclues, b #ifdef STANDALONE_SOLVER , "" #endif ); if (ret < 0) { diff = DIFF_IMPOSSIBLE; goto got_result; } else if (ret > 0) changed = TRUE; } for (b = 0; b < usage->extra_cages->nr_blocks; b++) { int ret = solver_killer_minmax(usage, usage->extra_cages, usage->extra_clues, b #ifdef STANDALONE_SOLVER , "using deduced cages" #endif ); if (ret < 0) { diff = DIFF_IMPOSSIBLE; goto got_result; } else if (ret > 0) changed = TRUE; } if (changed) { kdiff = max(kdiff, DIFF_KMINMAX); goto cont; } } /* * Try to use knowledge of which numbers can be used to generate * a given sum. * This can only be used if a cage lies entirely within a region. */ if (dlev->maxkdiff >= DIFF_KSUMS && usage->kclues != NULL) { int changed = FALSE; for (b = 0; b < usage->kblocks->nr_blocks; b++) { int ret = solver_killer_sums(usage, b, usage->kblocks, usage->kclues[b], TRUE #ifdef STANDALONE_SOLVER , "regular clues" #endif ); if (ret > 0) { changed = TRUE; kdiff = max(kdiff, DIFF_KSUMS); } else if (ret < 0) { diff = DIFF_IMPOSSIBLE; goto got_result; } } for (b = 0; b < usage->extra_cages->nr_blocks; b++) { int ret = solver_killer_sums(usage, b, usage->extra_cages, usage->extra_clues[b], FALSE #ifdef STANDALONE_SOLVER , "deduced clues" #endif ); if (ret > 0) { changed = TRUE; kdiff = max(kdiff, DIFF_KSUMS); } else if (ret < 0) { diff = DIFF_IMPOSSIBLE; goto got_result; } } if (changed) goto cont; } if (dlev->maxdiff <= DIFF_BLOCK) break; /* * Row-wise positional elimination. */ for (y = 0; y < cr; y++) for (n = 1; n <= cr; n++) if (!usage->row[y*cr+n-1]) { for (x = 0; x < cr; x++) scratch->indexlist[x] = cubepos(x, y, n); ret = solver_elim(usage, scratch->indexlist #ifdef STANDALONE_SOLVER , "positional elimination," " %d in row %d", n, 1+y #endif ); if (ret < 0) { diff = DIFF_IMPOSSIBLE; goto got_result; } else if (ret > 0) { diff = max(diff, DIFF_SIMPLE); goto cont; } } /* * Column-wise positional elimination. */ for (x = 0; x < cr; x++) for (n = 1; n <= cr; n++) if (!usage->col[x*cr+n-1]) { for (y = 0; y < cr; y++) scratch->indexlist[y] = cubepos(x, y, n); ret = solver_elim(usage, scratch->indexlist #ifdef STANDALONE_SOLVER , "positional elimination," " %d in column %d", n, 1+x #endif ); if (ret < 0) { diff = DIFF_IMPOSSIBLE; goto got_result; } else if (ret > 0) { diff = max(diff, DIFF_SIMPLE); goto cont; } } /* * X-diagonal positional elimination. */ if (usage->diag) { for (n = 1; n <= cr; n++) if (!usage->diag[n-1]) { for (i = 0; i < cr; i++) scratch->indexlist[i] = cubepos2(diag0(i), n); ret = solver_elim(usage, scratch->indexlist #ifdef STANDALONE_SOLVER , "positional elimination," " %d in \\-diagonal", n #endif ); if (ret < 0) { diff = DIFF_IMPOSSIBLE; goto got_result; } else if (ret > 0) { diff = max(diff, DIFF_SIMPLE); goto cont; } } for (n = 1; n <= cr; n++) if (!usage->diag[cr+n-1]) { for (i = 0; i < cr; i++) scratch->indexlist[i] = cubepos2(diag1(i), n); ret = solver_elim(usage, scratch->indexlist #ifdef STANDALONE_SOLVER , "positional elimination," " %d in /-diagonal", n #endif ); if (ret < 0) { diff = DIFF_IMPOSSIBLE; goto got_result; } else if (ret > 0) { diff = max(diff, DIFF_SIMPLE); goto cont; } } } /* * Numeric elimination. */ for (x = 0; x < cr; x++) for (y = 0; y < cr; y++) if (!usage->grid[y*cr+x]) { for (n = 1; n <= cr; n++) scratch->indexlist[n-1] = cubepos(x, y, n); ret = solver_elim(usage, scratch->indexlist #ifdef STANDALONE_SOLVER , "numeric elimination at (%d,%d)", 1+x, 1+y #endif ); if (ret < 0) { diff = DIFF_IMPOSSIBLE; goto got_result; } else if (ret > 0) { diff = max(diff, DIFF_SIMPLE); goto cont; } } if (dlev->maxdiff <= DIFF_SIMPLE) break; /* * Intersectional analysis, rows vs blocks. */ for (y = 0; y < cr; y++) for (b = 0; b < cr; b++) for (n = 1; n <= cr; n++) { if (usage->row[y*cr+n-1] || usage->blk[b*cr+n-1]) continue; for (i = 0; i < cr; i++) { scratch->indexlist[i] = cubepos(i, y, n); scratch->indexlist2[i] = cubepos2(usage->blocks->blocks[b][i], n); } /* * solver_intersect() never returns -1. */ if (solver_intersect(usage, scratch->indexlist, scratch->indexlist2 #ifdef STANDALONE_SOLVER , "intersectional analysis," " %d in row %d vs block %s", n, 1+y, usage->blocks->blocknames[b] #endif ) || solver_intersect(usage, scratch->indexlist2, scratch->indexlist #ifdef STANDALONE_SOLVER , "intersectional analysis," " %d in block %s vs row %d", n, usage->blocks->blocknames[b], 1+y #endif )) { diff = max(diff, DIFF_INTERSECT); goto cont; } } /* * Intersectional analysis, columns vs blocks. */ for (x = 0; x < cr; x++) for (b = 0; b < cr; b++) for (n = 1; n <= cr; n++) { if (usage->col[x*cr+n-1] || usage->blk[b*cr+n-1]) continue; for (i = 0; i < cr; i++) { scratch->indexlist[i] = cubepos(x, i, n); scratch->indexlist2[i] = cubepos2(usage->blocks->blocks[b][i], n); } if (solver_intersect(usage, scratch->indexlist, scratch->indexlist2 #ifdef STANDALONE_SOLVER , "intersectional analysis," " %d in column %d vs block %s", n, 1+x, usage->blocks->blocknames[b] #endif ) || solver_intersect(usage, scratch->indexlist2, scratch->indexlist #ifdef STANDALONE_SOLVER , "intersectional analysis," " %d in block %s vs column %d", n, usage->blocks->blocknames[b], 1+x #endif )) { diff = max(diff, DIFF_INTERSECT); goto cont; } } if (usage->diag) { /* * Intersectional analysis, \-diagonal vs blocks. */ for (b = 0; b < cr; b++) for (n = 1; n <= cr; n++) { if (usage->diag[n-1] || usage->blk[b*cr+n-1]) continue; for (i = 0; i < cr; i++) { scratch->indexlist[i] = cubepos2(diag0(i), n); scratch->indexlist2[i] = cubepos2(usage->blocks->blocks[b][i], n); } if (solver_intersect(usage, scratch->indexlist, scratch->indexlist2 #ifdef STANDALONE_SOLVER , "intersectional analysis," " %d in \\-diagonal vs block %s", n, usage->blocks->blocknames[b] #endif ) || solver_intersect(usage, scratch->indexlist2, scratch->indexlist #ifdef STANDALONE_SOLVER , "intersectional analysis," " %d in block %s vs \\-diagonal", n, usage->blocks->blocknames[b] #endif )) { diff = max(diff, DIFF_INTERSECT); goto cont; } } /* * Intersectional analysis, /-diagonal vs blocks. */ for (b = 0; b < cr; b++) for (n = 1; n <= cr; n++) { if (usage->diag[cr+n-1] || usage->blk[b*cr+n-1]) continue; for (i = 0; i < cr; i++) { scratch->indexlist[i] = cubepos2(diag1(i), n); scratch->indexlist2[i] = cubepos2(usage->blocks->blocks[b][i], n); } if (solver_intersect(usage, scratch->indexlist, scratch->indexlist2 #ifdef STANDALONE_SOLVER , "intersectional analysis," " %d in /-diagonal vs block %s", n, usage->blocks->blocknames[b] #endif ) || solver_intersect(usage, scratch->indexlist2, scratch->indexlist #ifdef STANDALONE_SOLVER , "intersectional analysis," " %d in block %s vs /-diagonal", n, usage->blocks->blocknames[b] #endif )) { diff = max(diff, DIFF_INTERSECT); goto cont; } } } if (dlev->maxdiff <= DIFF_INTERSECT) break; /* * Blockwise set elimination. */ for (b = 0; b < cr; b++) { for (i = 0; i < cr; i++) for (n = 1; n <= cr; n++) scratch->indexlist[i*cr+n-1] = cubepos2(usage->blocks->blocks[b][i], n); ret = solver_set(usage, scratch, scratch->indexlist #ifdef STANDALONE_SOLVER , "set elimination, block %s", usage->blocks->blocknames[b] #endif ); if (ret < 0) { diff = DIFF_IMPOSSIBLE; goto got_result; } else if (ret > 0) { diff = max(diff, DIFF_SET); goto cont; } } /* * Row-wise set elimination. */ for (y = 0; y < cr; y++) { for (x = 0; x < cr; x++) for (n = 1; n <= cr; n++) scratch->indexlist[x*cr+n-1] = cubepos(x, y, n); ret = solver_set(usage, scratch, scratch->indexlist #ifdef STANDALONE_SOLVER , "set elimination, row %d", 1+y #endif ); if (ret < 0) { diff = DIFF_IMPOSSIBLE; goto got_result; } else if (ret > 0) { diff = max(diff, DIFF_SET); goto cont; } } /* * Column-wise set elimination. */ for (x = 0; x < cr; x++) { for (y = 0; y < cr; y++) for (n = 1; n <= cr; n++) scratch->indexlist[y*cr+n-1] = cubepos(x, y, n); ret = solver_set(usage, scratch, scratch->indexlist #ifdef STANDALONE_SOLVER , "set elimination, column %d", 1+x #endif ); if (ret < 0) { diff = DIFF_IMPOSSIBLE; goto got_result; } else if (ret > 0) { diff = max(diff, DIFF_SET); goto cont; } } if (usage->diag) { /* * \-diagonal set elimination. */ for (i = 0; i < cr; i++) for (n = 1; n <= cr; n++) scratch->indexlist[i*cr+n-1] = cubepos2(diag0(i), n); ret = solver_set(usage, scratch, scratch->indexlist #ifdef STANDALONE_SOLVER , "set elimination, \\-diagonal" #endif ); if (ret < 0) { diff = DIFF_IMPOSSIBLE; goto got_result; } else if (ret > 0) { diff = max(diff, DIFF_SET); goto cont; } /* * /-diagonal set elimination. */ for (i = 0; i < cr; i++) for (n = 1; n <= cr; n++) scratch->indexlist[i*cr+n-1] = cubepos2(diag1(i), n); ret = solver_set(usage, scratch, scratch->indexlist #ifdef STANDALONE_SOLVER , "set elimination, /-diagonal" #endif ); if (ret < 0) { diff = DIFF_IMPOSSIBLE; goto got_result; } else if (ret > 0) { diff = max(diff, DIFF_SET); goto cont; } } if (dlev->maxdiff <= DIFF_SET) break; /* * Row-vs-column set elimination on a single number. */ for (n = 1; n <= cr; n++) { for (y = 0; y < cr; y++) for (x = 0; x < cr; x++) scratch->indexlist[y*cr+x] = cubepos(x, y, n); ret = solver_set(usage, scratch, scratch->indexlist #ifdef STANDALONE_SOLVER , "positional set elimination, number %d", n #endif ); if (ret < 0) { diff = DIFF_IMPOSSIBLE; goto got_result; } else if (ret > 0) { diff = max(diff, DIFF_EXTREME); goto cont; } } /* * Forcing chains. */ if (solver_forcing(usage, scratch)) { diff = max(diff, DIFF_EXTREME); goto cont; } /* * If we reach here, we have made no deductions in this * iteration, so the algorithm terminates. */ break; } /* * Last chance: if we haven't fully solved the puzzle yet, try * recursing based on guesses for a particular square. We pick * one of the most constrained empty squares we can find, which * has the effect of pruning the search tree as much as * possible. */ if (dlev->maxdiff >= DIFF_RECURSIVE) { int best, bestcount; best = -1; bestcount = cr+1; for (y = 0; y < cr; y++) for (x = 0; x < cr; x++) if (!grid[y*cr+x]) { int count; /* * An unfilled square. Count the number of * possible digits in it. */ count = 0; for (n = 1; n <= cr; n++) if (cube(x,y,n)) count++; /* * We should have found any impossibilities * already, so this can safely be an assert. */ assert(count > 1); if (count < bestcount) { bestcount = count; best = y*cr+x; } } if (best != -1) { int i, j; digit *list, *ingrid, *outgrid; diff = DIFF_IMPOSSIBLE; /* no solution found yet */ /* * Attempt recursion. */ y = best / cr; x = best % cr; list = snewn(cr, digit); ingrid = snewn(cr * cr, digit); outgrid = snewn(cr * cr, digit); memcpy(ingrid, grid, cr * cr); /* Make a list of the possible digits. */ for (j = 0, n = 1; n <= cr; n++) if (cube(x,y,n)) list[j++] = n; #ifdef STANDALONE_SOLVER if (solver_show_working) { char *sep = ""; printf("%*srecursing on (%d,%d) [", solver_recurse_depth*4, "", x + 1, y + 1); for (i = 0; i < j; i++) { printf("%s%d", sep, list[i]); sep = " or "; } printf("]\n"); } #endif /* * And step along the list, recursing back into the * main solver at every stage. */ for (i = 0; i < j; i++) { memcpy(outgrid, ingrid, cr * cr); outgrid[y*cr+x] = list[i]; #ifdef STANDALONE_SOLVER if (solver_show_working) printf("%*sguessing %d at (%d,%d)\n", solver_recurse_depth*4, "", list[i], x + 1, y + 1); solver_recurse_depth++; #endif solver(cr, blocks, kblocks, xtype, outgrid, kgrid, dlev); #ifdef STANDALONE_SOLVER solver_recurse_depth--; if (solver_show_working) { printf("%*sretracting %d at (%d,%d)\n", solver_recurse_depth*4, "", list[i], x + 1, y + 1); } #endif /* * If we have our first solution, copy it into the * grid we will return. */ if (diff == DIFF_IMPOSSIBLE && dlev->diff != DIFF_IMPOSSIBLE) memcpy(grid, outgrid, cr*cr); if (dlev->diff == DIFF_AMBIGUOUS) diff = DIFF_AMBIGUOUS; else if (dlev->diff == DIFF_IMPOSSIBLE) /* do not change our return value */; else { /* the recursion turned up exactly one solution */ if (diff == DIFF_IMPOSSIBLE) diff = DIFF_RECURSIVE; else diff = DIFF_AMBIGUOUS; } /* * As soon as we've found more than one solution, * give up immediately. */ if (diff == DIFF_AMBIGUOUS) break; } sfree(outgrid); sfree(ingrid); sfree(list); } } else { /* * We're forbidden to use recursion, so we just see whether * our grid is fully solved, and return DIFF_IMPOSSIBLE * otherwise. */ for (y = 0; y < cr; y++) for (x = 0; x < cr; x++) if (!grid[y*cr+x]) diff = DIFF_IMPOSSIBLE; } got_result: dlev->diff = diff; dlev->kdiff = kdiff; #ifdef STANDALONE_SOLVER if (solver_show_working) printf("%*s%s found\n", solver_recurse_depth*4, "", diff == DIFF_IMPOSSIBLE ? "no solution" : diff == DIFF_AMBIGUOUS ? "multiple solutions" : "one solution"); #endif sfree(usage->sq2region); sfree(usage->regions); sfree(usage->cube); sfree(usage->row); sfree(usage->col); sfree(usage->blk); if (usage->kblocks) { free_block_structure(usage->kblocks); free_block_structure(usage->extra_cages); sfree(usage->extra_clues); } if (usage->kclues) sfree(usage->kclues); sfree(usage); solver_free_scratch(scratch); } /* ---------------------------------------------------------------------- * End of solver code. */ /* ---------------------------------------------------------------------- * Killer set generator. */ /* ---------------------------------------------------------------------- * Solo filled-grid generator. * * This grid generator works by essentially trying to solve a grid * starting from no clues, and not worrying that there's more than * one possible solution. Unfortunately, it isn't computationally * feasible to do this by calling the above solver with an empty * grid, because that one needs to allocate a lot of scratch space * at every recursion level. Instead, I have a much simpler * algorithm which I shamelessly copied from a Python solver * written by Andrew Wilkinson (which is GPLed, but I've reused * only ideas and no code). It mostly just does the obvious * recursive thing: pick an empty square, put one of the possible * digits in it, recurse until all squares are filled, backtrack * and change some choices if necessary. * * The clever bit is that every time it chooses which square to * fill in next, it does so by counting the number of _possible_ * numbers that can go in each square, and it prioritises so that * it picks a square with the _lowest_ number of possibilities. The * idea is that filling in lots of the obvious bits (particularly * any squares with only one possibility) will cut down on the list * of possibilities for other squares and hence reduce the enormous * search space as much as possible as early as possible. * * The use of bit sets implies that we support puzzles up to a size of * 32x32 (less if anyone finds a 16-bit machine to compile this on). */ /* * Internal data structure used in gridgen to keep track of * progress. */ struct gridgen_coord { int x, y, r; }; struct gridgen_usage { int cr; struct block_structure *blocks, *kblocks; /* grid is a copy of the input grid, modified as we go along */ digit *grid; /* * Bitsets. In each of them, bit n is set if digit n has been placed * in the corresponding region. row, col and blk are used for all * puzzles. cge is used only for killer puzzles, and diag is used * only for x-type puzzles. * All of these have cr entries, except diag which only has 2, * and cge, which has as many entries as kblocks. */ unsigned int *row, *col, *blk, *cge, *diag; /* This lists all the empty spaces remaining in the grid. */ struct gridgen_coord *spaces; int nspaces; /* If we need randomisation in the solve, this is our random state. */ random_state *rs; }; static void gridgen_place(struct gridgen_usage *usage, int x, int y, digit n) { unsigned int bit = 1 << n; int cr = usage->cr; usage->row[y] |= bit; usage->col[x] |= bit; usage->blk[usage->blocks->whichblock[y*cr+x]] |= bit; if (usage->cge) usage->cge[usage->kblocks->whichblock[y*cr+x]] |= bit; if (usage->diag) { if (ondiag0(y*cr+x)) usage->diag[0] |= bit; if (ondiag1(y*cr+x)) usage->diag[1] |= bit; } usage->grid[y*cr+x] = n; } static void gridgen_remove(struct gridgen_usage *usage, int x, int y, digit n) { unsigned int mask = ~(1 << n); int cr = usage->cr; usage->row[y] &= mask; usage->col[x] &= mask; usage->blk[usage->blocks->whichblock[y*cr+x]] &= mask; if (usage->cge) usage->cge[usage->kblocks->whichblock[y*cr+x]] &= mask; if (usage->diag) { if (ondiag0(y*cr+x)) usage->diag[0] &= mask; if (ondiag1(y*cr+x)) usage->diag[1] &= mask; } usage->grid[y*cr+x] = 0; } #define N_SINGLE 32 /* * The real recursive step in the generating function. * * Return values: 1 means solution found, 0 means no solution * found on this branch. */ static int gridgen_real(struct gridgen_usage *usage, digit *grid, int *steps) { int cr = usage->cr; int i, j, n, sx, sy, bestm, bestr, ret; int *digits; unsigned int used; /* * Firstly, check for completion! If there are no spaces left * in the grid, we have a solution. */ if (usage->nspaces == 0) return TRUE; /* * Next, abandon generation if we went over our steps limit. */ if (*steps <= 0) return FALSE; (*steps)--; /* * Otherwise, there must be at least one space. Find the most * constrained space, using the `r' field as a tie-breaker. */ bestm = cr+1; /* so that any space will beat it */ bestr = 0; used = ~0; i = sx = sy = -1; for (j = 0; j < usage->nspaces; j++) { int x = usage->spaces[j].x, y = usage->spaces[j].y; unsigned int used_xy; int m; m = usage->blocks->whichblock[y*cr+x]; used_xy = usage->row[y] | usage->col[x] | usage->blk[m]; if (usage->cge != NULL) used_xy |= usage->cge[usage->kblocks->whichblock[y*cr+x]]; if (usage->cge != NULL) used_xy |= usage->cge[usage->kblocks->whichblock[y*cr+x]]; if (usage->diag != NULL) { if (ondiag0(y*cr+x)) used_xy |= usage->diag[0]; if (ondiag1(y*cr+x)) used_xy |= usage->diag[1]; } /* * Find the number of digits that could go in this space. */ m = 0; for (n = 1; n <= cr; n++) { unsigned int bit = 1 << n; if ((used_xy & bit) == 0) m++; } if (m < bestm || (m == bestm && usage->spaces[j].r < bestr)) { bestm = m; bestr = usage->spaces[j].r; sx = x; sy = y; i = j; used = used_xy; } } /* * Swap that square into the final place in the spaces array, * so that decrementing nspaces will remove it from the list. */ if (i != usage->nspaces-1) { struct gridgen_coord t; t = usage->spaces[usage->nspaces-1]; usage->spaces[usage->nspaces-1] = usage->spaces[i]; usage->spaces[i] = t; } /* * Now we've decided which square to start our recursion at, * simply go through all possible values, shuffling them * randomly first if necessary. */ digits = snewn(bestm, int); j = 0; for (n = 1; n <= cr; n++) { unsigned int bit = 1 << n; if ((used & bit) == 0) digits[j++] = n; } if (usage->rs) shuffle(digits, j, sizeof(*digits), usage->rs); /* And finally, go through the digit list and actually recurse. */ ret = FALSE; for (i = 0; i < j; i++) { n = digits[i]; /* Update the usage structure to reflect the placing of this digit. */ gridgen_place(usage, sx, sy, n); usage->nspaces--; /* Call the solver recursively. Stop when we find a solution. */ if (gridgen_real(usage, grid, steps)) { ret = TRUE; break; } /* Revert the usage structure. */ gridgen_remove(usage, sx, sy, n); usage->nspaces++; } sfree(digits); return ret; } /* * Entry point to generator. You give it parameters and a starting * grid, which is simply an array of cr*cr digits. */ static int gridgen(int cr, struct block_structure *blocks, struct block_structure *kblocks, int xtype, digit *grid, random_state *rs, int maxsteps) { struct gridgen_usage *usage; int x, y, ret; /* * Clear the grid to start with. */ memset(grid, 0, cr*cr); /* * Create a gridgen_usage structure. */ usage = snew(struct gridgen_usage); usage->cr = cr; usage->blocks = blocks; usage->grid = grid; usage->row = snewn(cr, unsigned int); usage->col = snewn(cr, unsigned int); usage->blk = snewn(cr, unsigned int); if (kblocks != NULL) { usage->kblocks = kblocks; usage->cge = snewn(usage->kblocks->nr_blocks, unsigned int); memset(usage->cge, FALSE, kblocks->nr_blocks * sizeof *usage->cge); } else { usage->cge = NULL; } memset(usage->row, 0, cr * sizeof *usage->row); memset(usage->col, 0, cr * sizeof *usage->col); memset(usage->blk, 0, cr * sizeof *usage->blk); if (xtype) { usage->diag = snewn(2, unsigned int); memset(usage->diag, 0, 2 * sizeof *usage->diag); } else { usage->diag = NULL; } /* * Begin by filling in the whole top row with randomly chosen * numbers. This cannot introduce any bias or restriction on * the available grids, since we already know those numbers * are all distinct so all we're doing is choosing their * labels. */ for (x = 0; x < cr; x++) grid[x] = x+1; shuffle(grid, cr, sizeof(*grid), rs); for (x = 0; x < cr; x++) gridgen_place(usage, x, 0, grid[x]); usage->spaces = snewn(cr * cr, struct gridgen_coord); usage->nspaces = 0; usage->rs = rs; /* * Initialise the list of grid spaces, taking care to leave * out the row I've already filled in above. */ for (y = 1; y < cr; y++) { for (x = 0; x < cr; x++) { usage->spaces[usage->nspaces].x = x; usage->spaces[usage->nspaces].y = y; usage->spaces[usage->nspaces].r = random_bits(rs, 31); usage->nspaces++; } } /* * Run the real generator function. */ ret = gridgen_real(usage, grid, &maxsteps); /* * Clean up the usage structure now we have our answer. */ sfree(usage->spaces); sfree(usage->cge); sfree(usage->blk); sfree(usage->col); sfree(usage->row); sfree(usage); return ret; } /* ---------------------------------------------------------------------- * End of grid generator code. */ static int check_killer_cage_sum(struct block_structure *kblocks, digit *kgrid, digit *grid, int blk) { /* * Returns: -1 if the cage has any empty square; 0 if all squares * are full but the sum is wrong; +1 if all squares are full and * they have the right sum. * * Does not check uniqueness of numbers within the cage; that's * done elsewhere (because in error highlighting it needs to be * detected separately so as to flag the error in a visually * different way). */ int n_squares = kblocks->nr_squares[blk]; int sum = 0, clue = 0; int i; for (i = 0; i < n_squares; i++) { int xy = kblocks->blocks[blk][i]; if (grid[xy] == 0) return -1; sum += grid[xy]; if (kgrid[xy]) { assert(clue == 0); clue = kgrid[xy]; } } assert(clue != 0); return sum == clue; } /* * Check whether a grid contains a valid complete puzzle. */ static int check_valid(int cr, struct block_structure *blocks, struct block_structure *kblocks, digit *kgrid, int xtype, digit *grid) { unsigned char *used; int x, y, i, j, n; used = snewn(cr, unsigned char); /* * Check that each row contains precisely one of everything. */ for (y = 0; y < cr; y++) { memset(used, FALSE, cr); for (x = 0; x < cr; x++) if (grid[y*cr+x] > 0 && grid[y*cr+x] <= cr) used[grid[y*cr+x]-1] = TRUE; for (n = 0; n < cr; n++) if (!used[n]) { sfree(used); return FALSE; } } /* * Check that each column contains precisely one of everything. */ for (x = 0; x < cr; x++) { memset(used, FALSE, cr); for (y = 0; y < cr; y++) if (grid[y*cr+x] > 0 && grid[y*cr+x] <= cr) used[grid[y*cr+x]-1] = TRUE; for (n = 0; n < cr; n++) if (!used[n]) { sfree(used); return FALSE; } } /* * Check that each block contains precisely one of everything. */ for (i = 0; i < cr; i++) { memset(used, FALSE, cr); for (j = 0; j < cr; j++) if (grid[blocks->blocks[i][j]] > 0 && grid[blocks->blocks[i][j]] <= cr) used[grid[blocks->blocks[i][j]]-1] = TRUE; for (n = 0; n < cr; n++) if (!used[n]) { sfree(used); return FALSE; } } /* * Check that each Killer cage, if any, contains at most one of * everything. If we also know the clues for those cages (which we * might not, when this function is called early in puzzle * generation), we also check that they all have the right sum. */ if (kblocks) { for (i = 0; i < kblocks->nr_blocks; i++) { memset(used, FALSE, cr); for (j = 0; j < kblocks->nr_squares[i]; j++) if (grid[kblocks->blocks[i][j]] > 0 && grid[kblocks->blocks[i][j]] <= cr) { if (used[grid[kblocks->blocks[i][j]]-1]) { sfree(used); return FALSE; } used[grid[kblocks->blocks[i][j]]-1] = TRUE; } if (kgrid && check_killer_cage_sum(kblocks, kgrid, grid, i) != 1) { sfree(used); return FALSE; } } } /* * Check that each diagonal contains precisely one of everything. */ if (xtype) { memset(used, FALSE, cr); for (i = 0; i < cr; i++) if (grid[diag0(i)] > 0 && grid[diag0(i)] <= cr) used[grid[diag0(i)]-1] = TRUE; for (n = 0; n < cr; n++) if (!used[n]) { sfree(used); return FALSE; } for (i = 0; i < cr; i++) if (grid[diag1(i)] > 0 && grid[diag1(i)] <= cr) used[grid[diag1(i)]-1] = TRUE; for (n = 0; n < cr; n++) if (!used[n]) { sfree(used); return FALSE; } } sfree(used); return TRUE; } static int symmetries(const game_params *params, int x, int y, int *output, int s) { int c = params->c, r = params->r, cr = c*r; int i = 0; #define ADD(x,y) (*output++ = (x), *output++ = (y), i++) ADD(x, y); switch (s) { case SYMM_NONE: break; /* just x,y is all we need */ case SYMM_ROT2: ADD(cr - 1 - x, cr - 1 - y); break; case SYMM_ROT4: ADD(cr - 1 - y, x); ADD(y, cr - 1 - x); ADD(cr - 1 - x, cr - 1 - y); break; case SYMM_REF2: ADD(cr - 1 - x, y); break; case SYMM_REF2D: ADD(y, x); break; case SYMM_REF4: ADD(cr - 1 - x, y); ADD(x, cr - 1 - y); ADD(cr - 1 - x, cr - 1 - y); break; case SYMM_REF4D: ADD(y, x); ADD(cr - 1 - x, cr - 1 - y); ADD(cr - 1 - y, cr - 1 - x); break; case SYMM_REF8: ADD(cr - 1 - x, y); ADD(x, cr - 1 - y); ADD(cr - 1 - x, cr - 1 - y); ADD(y, x); ADD(y, cr - 1 - x); ADD(cr - 1 - y, x); ADD(cr - 1 - y, cr - 1 - x); break; } #undef ADD return i; } static char *encode_solve_move(int cr, digit *grid) { int i, len; char *ret, *p, *sep; /* * It's surprisingly easy to work out _exactly_ how long this * string needs to be. To decimal-encode all the numbers from 1 * to n: * * - every number has a units digit; total is n. * - all numbers above 9 have a tens digit; total is max(n-9,0). * - all numbers above 99 have a hundreds digit; total is max(n-99,0). * - and so on. */ len = 0; for (i = 1; i <= cr; i *= 10) len += max(cr - i + 1, 0); len += cr; /* don't forget the commas */ len *= cr; /* there are cr rows of these */ /* * Now len is one bigger than the total size of the * comma-separated numbers (because we counted an * additional leading comma). We need to have a leading S * and a trailing NUL, so we're off by one in total. */ len++; ret = snewn(len, char); p = ret; *p++ = 'S'; sep = ""; for (i = 0; i < cr*cr; i++) { p += sprintf(p, "%s%d", sep, grid[i]); sep = ","; } *p++ = '\0'; assert(p - ret == len); return ret; } static void dsf_to_blocks(int *dsf, struct block_structure *blocks, int min_expected, int max_expected) { int cr = blocks->c * blocks->r, area = cr * cr; int i, nb = 0; for (i = 0; i < area; i++) blocks->whichblock[i] = -1; for (i = 0; i < area; i++) { int j = dsf_canonify(dsf, i); if (blocks->whichblock[j] < 0) blocks->whichblock[j] = nb++; blocks->whichblock[i] = blocks->whichblock[j]; } assert(nb >= min_expected && nb <= max_expected); blocks->nr_blocks = nb; } static void make_blocks_from_whichblock(struct block_structure *blocks) { int i; for (i = 0; i < blocks->nr_blocks; i++) { blocks->blocks[i][blocks->max_nr_squares-1] = 0; blocks->nr_squares[i] = 0; } for (i = 0; i < blocks->area; i++) { int b = blocks->whichblock[i]; int j = blocks->blocks[b][blocks->max_nr_squares-1]++; assert(j < blocks->max_nr_squares); blocks->blocks[b][j] = i; blocks->nr_squares[b]++; } } static char *encode_block_structure_desc(char *p, struct block_structure *blocks) { int i, currrun = 0; int c = blocks->c, r = blocks->r, cr = c * r; /* * Encode the block structure. We do this by encoding * the pattern of dividing lines: first we iterate * over the cr*(cr-1) internal vertical grid lines in * ordinary reading order, then over the cr*(cr-1) * internal horizontal ones in transposed reading * order. * * We encode the number of non-lines between the * lines; _ means zero (two adjacent divisions), a * means 1, ..., y means 25, and z means 25 non-lines * _and no following line_ (so that za means 26, zb 27 * etc). */ for (i = 0; i <= 2*cr*(cr-1); i++) { int x, y, p0, p1, edge; if (i == 2*cr*(cr-1)) { edge = TRUE; /* terminating virtual edge */ } else { if (i < cr*(cr-1)) { y = i/(cr-1); x = i%(cr-1); p0 = y*cr+x; p1 = y*cr+x+1; } else { x = i/(cr-1) - cr; y = i%(cr-1); p0 = y*cr+x; p1 = (y+1)*cr+x; } edge = (blocks->whichblock[p0] != blocks->whichblock[p1]); } if (edge) { while (currrun > 25) *p++ = 'z', currrun -= 25; if (currrun) *p++ = 'a'-1 + currrun; else *p++ = '_'; currrun = 0; } else currrun++; } return p; } static char *encode_grid(char *desc, digit *grid, int area) { int run, i; char *p = desc; run = 0; for (i = 0; i <= area; i++) { int n = (i < area ? grid[i] : -1); if (!n) run++; else { if (run) { while (run > 0) { int c = 'a' - 1 + run; if (run > 26) c = 'z'; *p++ = c; run -= c - ('a' - 1); } } else { /* * If there's a number in the very top left or * bottom right, there's no point putting an * unnecessary _ before or after it. */ if (p > desc && n > 0) *p++ = '_'; } if (n > 0) p += sprintf(p, "%d", n); run = 0; } } return p; } /* * Conservatively stimate the number of characters required for * encoding a grid of a certain area. */ static int grid_encode_space (int area) { int t, count; for (count = 1, t = area; t > 26; t -= 26) count++; return count * area; } /* * Conservatively stimate the number of characters required for * encoding a given blocks structure. */ static int blocks_encode_space(struct block_structure *blocks) { int cr = blocks->c * blocks->r, area = cr * cr; return grid_encode_space(area); } static char *encode_puzzle_desc(const game_params *params, digit *grid, struct block_structure *blocks, digit *kgrid, struct block_structure *kblocks) { int c = params->c, r = params->r, cr = c*r; int area = cr*cr; char *p, *desc; int space; space = grid_encode_space(area) + 1; if (r == 1) space += blocks_encode_space(blocks) + 1; if (params->killer) { space += blocks_encode_space(kblocks) + 1; space += grid_encode_space(area) + 1; } desc = snewn(space, char); p = encode_grid(desc, grid, area); if (r == 1) { *p++ = ','; p = encode_block_structure_desc(p, blocks); } if (params->killer) { *p++ = ','; p = encode_block_structure_desc(p, kblocks); *p++ = ','; p = encode_grid(p, kgrid, area); } assert(p - desc < space); *p++ = '\0'; desc = sresize(desc, p - desc, char); return desc; } static void merge_blocks(struct block_structure *b, int n1, int n2) { int i; /* Move data towards the lower block number. */ if (n2 < n1) { int t = n2; n2 = n1; n1 = t; } /* Merge n2 into n1, and move the last block into n2's position. */ for (i = 0; i < b->nr_squares[n2]; i++) b->whichblock[b->blocks[n2][i]] = n1; memcpy(b->blocks[n1] + b->nr_squares[n1], b->blocks[n2], b->nr_squares[n2] * sizeof **b->blocks); b->nr_squares[n1] += b->nr_squares[n2]; n1 = b->nr_blocks - 1; if (n2 != n1) { memcpy(b->blocks[n2], b->blocks[n1], b->nr_squares[n1] * sizeof **b->blocks); for (i = 0; i < b->nr_squares[n1]; i++) b->whichblock[b->blocks[n1][i]] = n2; b->nr_squares[n2] = b->nr_squares[n1]; } b->nr_blocks = n1; } static int merge_some_cages(struct block_structure *b, int cr, int area, digit *grid, random_state *rs) { /* * Make a list of all the pairs of adjacent blocks. */ int i, j, k; struct pair { int b1, b2; } *pairs; int npairs; pairs = snewn(b->nr_blocks * b->nr_blocks, struct pair); npairs = 0; for (i = 0; i < b->nr_blocks; i++) { for (j = i+1; j < b->nr_blocks; j++) { /* * Rule the merger out of consideration if it's * obviously not viable. */ if (b->nr_squares[i] + b->nr_squares[j] > b->max_nr_squares) continue; /* we couldn't merge these anyway */ /* * See if these two blocks have a pair of squares * adjacent to each other. */ for (k = 0; k < b->nr_squares[i]; k++) { int xy = b->blocks[i][k]; int y = xy / cr, x = xy % cr; if ((y > 0 && b->whichblock[xy - cr] == j) || (y+1 < cr && b->whichblock[xy + cr] == j) || (x > 0 && b->whichblock[xy - 1] == j) || (x+1 < cr && b->whichblock[xy + 1] == j)) { /* * Yes! Add this pair to our list. */ pairs[npairs].b1 = i; pairs[npairs].b2 = j; break; } } } } /* * Now go through that list in random order until we find a pair * of blocks we can merge. */ while (npairs > 0) { int n1, n2; unsigned int digits_found; /* * Pick a random pair, and remove it from the list. */ i = random_upto(rs, npairs); n1 = pairs[i].b1; n2 = pairs[i].b2; if (i != npairs-1) pairs[i] = pairs[npairs-1]; npairs--; /* Guarantee that the merged cage would still be a region. */ digits_found = 0; for (i = 0; i < b->nr_squares[n1]; i++) digits_found |= 1 << grid[b->blocks[n1][i]]; for (i = 0; i < b->nr_squares[n2]; i++) if (digits_found & (1 << grid[b->blocks[n2][i]])) break; if (i != b->nr_squares[n2]) continue; /* * Got one! Do the merge. */ merge_blocks(b, n1, n2); sfree(pairs); return TRUE; } sfree(pairs); return FALSE; } static void compute_kclues(struct block_structure *cages, digit *kclues, digit *grid, int area) { int i; memset(kclues, 0, area * sizeof *kclues); for (i = 0; i < cages->nr_blocks; i++) { int j, sum = 0; for (j = 0; j < area; j++) if (cages->whichblock[j] == i) sum += grid[j]; for (j = 0; j < area; j++) if (cages->whichblock[j] == i) break; assert (j != area); kclues[j] = sum; } } static struct block_structure *gen_killer_cages(int cr, random_state *rs, int remove_singletons) { int nr; int x, y, area = cr * cr; int n_singletons = 0; struct block_structure *b = alloc_block_structure (1, cr, area, cr, area); for (x = 0; x < area; x++) b->whichblock[x] = -1; nr = 0; for (y = 0; y < cr; y++) for (x = 0; x < cr; x++) { int rnd; int xy = y*cr+x; if (b->whichblock[xy] != -1) continue; b->whichblock[xy] = nr; rnd = random_bits(rs, 4); if (xy + 1 < area && (rnd >= 4 || (!remove_singletons && rnd >= 1))) { int xy2 = xy + 1; if (x + 1 == cr || b->whichblock[xy2] != -1 || (xy + cr < area && random_bits(rs, 1) == 0)) xy2 = xy + cr; if (xy2 >= area) n_singletons++; else b->whichblock[xy2] = nr; } else n_singletons++; nr++; } b->nr_blocks = nr; make_blocks_from_whichblock(b); for (x = y = 0; x < b->nr_blocks; x++) if (b->nr_squares[x] == 1) y++; assert(y == n_singletons); if (n_singletons > 0 && remove_singletons) { int n; for (n = 0; n < b->nr_blocks;) { int xy, x, y, xy2, other; if (b->nr_squares[n] > 1) { n++; continue; } xy = b->blocks[n][0]; x = xy % cr; y = xy / cr; if (xy + 1 == area) xy2 = xy - 1; else if (x + 1 < cr && (y + 1 == cr || random_bits(rs, 1) == 0)) xy2 = xy + 1; else xy2 = xy + cr; other = b->whichblock[xy2]; if (b->nr_squares[other] == 1) n_singletons--; n_singletons--; merge_blocks(b, n, other); if (n < other) n++; } assert(n_singletons == 0); } return b; } static char *new_game_desc(const game_params *params, random_state *rs, char **aux, int interactive) { int c = params->c, r = params->r, cr = c*r; int area = cr*cr; struct block_structure *blocks, *kblocks; digit *grid, *grid2, *kgrid; struct xy { int x, y; } *locs; int nlocs; char *desc; int coords[16], ncoords; int x, y, i, j; struct difficulty dlev; precompute_sum_bits(); /* * Adjust the maximum difficulty level to be consistent with * the puzzle size: all 2x2 puzzles appear to be Trivial * (DIFF_BLOCK) so we cannot hold out for even a Basic * (DIFF_SIMPLE) one. */ dlev.maxdiff = params->diff; dlev.maxkdiff = params->kdiff; if (c == 2 && r == 2) dlev.maxdiff = DIFF_BLOCK; grid = snewn(area, digit); locs = snewn(area, struct xy); grid2 = snewn(area, digit); blocks = alloc_block_structure (c, r, area, cr, cr); kblocks = NULL; kgrid = (params->killer) ? snewn(area, digit) : NULL; #ifdef STANDALONE_SOLVER assert(!"This should never happen, so we don't need to create blocknames"); #endif /* * Loop until we get a grid of the required difficulty. This is * nasty, but it seems to be unpleasantly hard to generate * difficult grids otherwise. */ while (1) { /* * Generate a random solved state, starting by * constructing the block structure. */ if (r == 1) { /* jigsaw mode */ int *dsf = divvy_rectangle(cr, cr, cr, rs); dsf_to_blocks (dsf, blocks, cr, cr); sfree(dsf); } else { /* basic Sudoku mode */ for (y = 0; y < cr; y++) for (x = 0; x < cr; x++) blocks->whichblock[y*cr+x] = (y/c) * c + (x/r); } make_blocks_from_whichblock(blocks); if (params->killer) { if (kblocks) free_block_structure(kblocks); kblocks = gen_killer_cages(cr, rs, params->kdiff > DIFF_KSINGLE); } if (!gridgen(cr, blocks, kblocks, params->xtype, grid, rs, area*area)) continue; assert(check_valid(cr, blocks, kblocks, NULL, params->xtype, grid)); /* * Save the solved grid in aux. */ { /* * We might already have written *aux the last time we * went round this loop, in which case we should free * the old aux before overwriting it with the new one. */ if (*aux) { sfree(*aux); } *aux = encode_solve_move(cr, grid); } /* * Now we have a solved grid. For normal puzzles, we start removing * things from it while preserving solubility. Killer puzzles are * different: we just pass the empty grid to the solver, and use * the puzzle if it comes back solved. */ if (params->killer) { struct block_structure *good_cages = NULL; struct block_structure *last_cages = NULL; int ntries = 0; memcpy(grid2, grid, area); for (;;) { compute_kclues(kblocks, kgrid, grid2, area); memset(grid, 0, area * sizeof *grid); solver(cr, blocks, kblocks, params->xtype, grid, kgrid, &dlev); if (dlev.diff == dlev.maxdiff && dlev.kdiff == dlev.maxkdiff) { /* * We have one that matches our difficulty. Store it for * later, but keep going. */ if (good_cages) free_block_structure(good_cages); ntries = 0; good_cages = dup_block_structure(kblocks); if (!merge_some_cages(kblocks, cr, area, grid2, rs)) break; } else if (dlev.diff > dlev.maxdiff || dlev.kdiff > dlev.maxkdiff) { /* * Give up after too many tries and either use the good one we * found, or generate a new grid. */ if (++ntries > 50) break; /* * The difficulty level got too high. If we have a good * one, use it, otherwise go back to the last one that * was at a lower difficulty and restart the process from * there. */ if (good_cages != NULL) { free_block_structure(kblocks); kblocks = dup_block_structure(good_cages); if (!merge_some_cages(kblocks, cr, area, grid2, rs)) break; } else { if (last_cages == NULL) break; free_block_structure(kblocks); kblocks = last_cages; last_cages = NULL; } } else { if (last_cages) free_block_structure(last_cages); last_cages = dup_block_structure(kblocks); if (!merge_some_cages(kblocks, cr, area, grid2, rs)) break; } } if (last_cages) free_block_structure(last_cages); if (good_cages != NULL) { free_block_structure(kblocks); kblocks = good_cages; compute_kclues(kblocks, kgrid, grid2, area); memset(grid, 0, area * sizeof *grid); break; } continue; } /* * Find the set of equivalence classes of squares permitted * by the selected symmetry. We do this by enumerating all * the grid squares which have no symmetric companion * sorting lower than themselves. */ nlocs = 0; for (y = 0; y < cr; y++) for (x = 0; x < cr; x++) { int i = y*cr+x; int j; ncoords = symmetries(params, x, y, coords, params->symm); for (j = 0; j < ncoords; j++) if (coords[2*j+1]*cr+coords[2*j] < i) break; if (j == ncoords) { locs[nlocs].x = x; locs[nlocs].y = y; nlocs++; } } /* * Now shuffle that list. */ shuffle(locs, nlocs, sizeof(*locs), rs); /* * Now loop over the shuffled list and, for each element, * see whether removing that element (and its reflections) * from the grid will still leave the grid soluble. */ for (i = 0; i < nlocs; i++) { x = locs[i].x; y = locs[i].y; memcpy(grid2, grid, area); ncoords = symmetries(params, x, y, coords, params->symm); for (j = 0; j < ncoords; j++) grid2[coords[2*j+1]*cr+coords[2*j]] = 0; solver(cr, blocks, kblocks, params->xtype, grid2, kgrid, &dlev); if (dlev.diff <= dlev.maxdiff && (!params->killer || dlev.kdiff <= dlev.maxkdiff)) { for (j = 0; j < ncoords; j++) grid[coords[2*j+1]*cr+coords[2*j]] = 0; } } memcpy(grid2, grid, area); solver(cr, blocks, kblocks, params->xtype, grid2, kgrid, &dlev); if (dlev.diff == dlev.maxdiff && (!params->killer || dlev.kdiff == dlev.maxkdiff)) break; /* found one! */ } sfree(grid2); sfree(locs); /* * Now we have the grid as it will be presented to the user. * Encode it in a game desc. */ desc = encode_puzzle_desc(params, grid, blocks, kgrid, kblocks); sfree(grid); free_block_structure(blocks); if (params->killer) { free_block_structure(kblocks); sfree(kgrid); } return desc; } static const char *spec_to_grid(const char *desc, digit *grid, int area) { int i = 0; while (*desc && *desc != ',') { int n = *desc++; if (n >= 'a' && n <= 'z') { int run = n - 'a' + 1; assert(i + run <= area); while (run-- > 0) grid[i++] = 0; } else if (n == '_') { /* do nothing */; } else if (n > '0' && n <= '9') { assert(i < area); grid[i++] = atoi(desc-1); while (*desc >= '0' && *desc <= '9') desc++; } else { assert(!"We can't get here"); } } assert(i == area); return desc; } /* * Create a DSF from a spec found in *pdesc. Update this to point past the * end of the block spec, and return an error string or NULL if everything * is OK. The DSF is stored in *PDSF. */ static char *spec_to_dsf(const char **pdesc, int **pdsf, int cr, int area) { const char *desc = *pdesc; int pos = 0; int *dsf; *pdsf = dsf = snew_dsf(area); while (*desc && *desc != ',') { int c, adv; if (*desc == '_') c = 0; else if (*desc >= 'a' && *desc <= 'z') c = *desc - 'a' + 1; else { sfree(dsf); return "Invalid character in game description"; } desc++; adv = (c != 26); /* 'z' is a special case */ while (c-- > 0) { int p0, p1; /* * Non-edge; merge the two dsf classes on either * side of it. */ if (pos >= 2*cr*(cr-1)) { sfree(dsf); return "Too much data in block structure specification"; } if (pos < cr*(cr-1)) { int y = pos/(cr-1); int x = pos%(cr-1); p0 = y*cr+x; p1 = y*cr+x+1; } else { int x = pos/(cr-1) - cr; int y = pos%(cr-1); p0 = y*cr+x; p1 = (y+1)*cr+x; } dsf_merge(dsf, p0, p1); pos++; } if (adv) pos++; } *pdesc = desc; /* * When desc is exhausted, we expect to have gone exactly * one space _past_ the end of the grid, due to the dummy * edge at the end. */ if (pos != 2*cr*(cr-1)+1) { sfree(dsf); return "Not enough data in block structure specification"; } return NULL; } static char *validate_grid_desc(const char **pdesc, int range, int area) { const char *desc = *pdesc; int squares = 0; while (*desc && *desc != ',') { int n = *desc++; if (n >= 'a' && n <= 'z') { squares += n - 'a' + 1; } else if (n == '_') { /* do nothing */; } else if (n > '0' && n <= '9') { int val = atoi(desc-1); if (val < 1 || val > range) return "Out-of-range number in game description"; squares++; while (*desc >= '0' && *desc <= '9') desc++; } else return "Invalid character in game description"; } if (squares < area) return "Not enough data to fill grid"; if (squares > area) return "Too much data to fit in grid"; *pdesc = desc; return NULL; } static char *validate_block_desc(const char **pdesc, int cr, int area, int min_nr_blocks, int max_nr_blocks, int min_nr_squares, int max_nr_squares) { char *err; int *dsf; err = spec_to_dsf(pdesc, &dsf, cr, area); if (err) { return err; } if (min_nr_squares == max_nr_squares) { assert(min_nr_blocks == max_nr_blocks); assert(min_nr_blocks * min_nr_squares == area); } /* * Now we've got our dsf. Verify that it matches * expectations. */ { int *canons, *counts; int i, j, c, ncanons = 0; canons = snewn(max_nr_blocks, int); counts = snewn(max_nr_blocks, int); for (i = 0; i < area; i++) { j = dsf_canonify(dsf, i); for (c = 0; c < ncanons; c++) if (canons[c] == j) { counts[c]++; if (counts[c] > max_nr_squares) { sfree(dsf); sfree(canons); sfree(counts); return "A jigsaw block is too big"; } break; } if (c == ncanons) { if (ncanons >= max_nr_blocks) { sfree(dsf); sfree(canons); sfree(counts); return "Too many distinct jigsaw blocks"; } canons[ncanons] = j; counts[ncanons] = 1; ncanons++; } } if (ncanons < min_nr_blocks) { sfree(dsf); sfree(canons); sfree(counts); return "Not enough distinct jigsaw blocks"; } for (c = 0; c < ncanons; c++) { if (counts[c] < min_nr_squares) { sfree(dsf); sfree(canons); sfree(counts); return "A jigsaw block is too small"; } } sfree(canons); sfree(counts); } sfree(dsf); return NULL; } static char *validate_desc(const game_params *params, const char *desc) { int cr = params->c * params->r, area = cr*cr; char *err; err = validate_grid_desc(&desc, cr, area); if (err) return err; if (params->r == 1) { /* * Now we expect a suffix giving the jigsaw block * structure. Parse it and validate that it divides the * grid into the right number of regions which are the * right size. */ if (*desc != ',') return "Expected jigsaw block structure in game description"; desc++; err = validate_block_desc(&desc, cr, area, cr, cr, cr, cr); if (err) return err; } if (params->killer) { if (*desc != ',') return "Expected killer block structure in game description"; desc++; err = validate_block_desc(&desc, cr, area, cr, area, 2, cr); if (err) return err; if (*desc != ',') return "Expected killer clue grid in game description"; desc++; err = validate_grid_desc(&desc, cr * area, area); if (err) return err; } if (*desc) return "Unexpected data at end of game description"; return NULL; } static game_state *new_game(midend *me, const game_params *params, const char *desc) { game_state *state = snew(game_state); int c = params->c, r = params->r, cr = c*r, area = cr * cr; int i; precompute_sum_bits(); state->cr = cr; state->xtype = params->xtype; state->killer = params->killer; state->grid = snewn(area, digit); state->pencil = snewn(area * cr, unsigned char); memset(state->pencil, 0, area * cr); state->immutable = snewn(area, unsigned char); memset(state->immutable, FALSE, area); state->blocks = alloc_block_structure (c, r, area, cr, cr); if (params->killer) { state->kblocks = alloc_block_structure (c, r, area, cr, area); state->kgrid = snewn(area, digit); } else { state->kblocks = NULL; state->kgrid = NULL; } state->completed = state->cheated = FALSE; desc = spec_to_grid(desc, state->grid, area); for (i = 0; i < area; i++) if (state->grid[i] != 0) state->immutable[i] = TRUE; if (r == 1) { char *err; int *dsf; assert(*desc == ','); desc++; err = spec_to_dsf(&desc, &dsf, cr, area); assert(err == NULL); dsf_to_blocks(dsf, state->blocks, cr, cr); sfree(dsf); } else { int x, y; for (y = 0; y < cr; y++) for (x = 0; x < cr; x++) state->blocks->whichblock[y*cr+x] = (y/c) * c + (x/r); } make_blocks_from_whichblock(state->blocks); if (params->killer) { char *err; int *dsf; assert(*desc == ','); desc++; err = spec_to_dsf(&desc, &dsf, cr, area); assert(err == NULL); dsf_to_blocks(dsf, state->kblocks, cr, area); sfree(dsf); make_blocks_from_whichblock(state->kblocks); assert(*desc == ','); desc++; desc = spec_to_grid(desc, state->kgrid, area); } assert(!*desc); #ifdef STANDALONE_SOLVER /* * Set up the block names for solver diagnostic output. */ { char *p = (char *)(state->blocks->blocknames + cr); if (r == 1) { for (i = 0; i < area; i++) { int j = state->blocks->whichblock[i]; if (!state->blocks->blocknames[j]) { state->blocks->blocknames[j] = p; p += 1 + sprintf(p, "starting at (%d,%d)", 1 + i%cr, 1 + i/cr); } } } else { int bx, by; for (by = 0; by < r; by++) for (bx = 0; bx < c; bx++) { state->blocks->blocknames[by*c+bx] = p; p += 1 + sprintf(p, "(%d,%d)", bx+1, by+1); } } assert(p - (char *)state->blocks->blocknames < (int)(cr*(sizeof(char *)+80))); for (i = 0; i < cr; i++) assert(state->blocks->blocknames[i]); } #endif return state; } static game_state *dup_game(const game_state *state) { game_state *ret = snew(game_state); int cr = state->cr, area = cr * cr; ret->cr = state->cr; ret->xtype = state->xtype; ret->killer = state->killer; ret->blocks = state->blocks; ret->blocks->refcount++; ret->kblocks = state->kblocks; if (ret->kblocks) ret->kblocks->refcount++; ret->grid = snewn(area, digit); memcpy(ret->grid, state->grid, area); if (state->killer) { ret->kgrid = snewn(area, digit); memcpy(ret->kgrid, state->kgrid, area); } else ret->kgrid = NULL; ret->pencil = snewn(area * cr, unsigned char); memcpy(ret->pencil, state->pencil, area * cr); ret->immutable = snewn(area, unsigned char); memcpy(ret->immutable, state->immutable, area); ret->completed = state->completed; ret->cheated = state->cheated; return ret; } static void free_game(game_state *state) { free_block_structure(state->blocks); if (state->kblocks) free_block_structure(state->kblocks); sfree(state->immutable); sfree(state->pencil); sfree(state->grid); if (state->kgrid) sfree(state->kgrid); sfree(state); } static char *solve_game(const game_state *state, const game_state *currstate, const char *ai, char **error) { int cr = state->cr; char *ret; digit *grid; struct difficulty dlev; /* * If we already have the solution in ai, save ourselves some * time. */ if (ai) return dupstr(ai); grid = snewn(cr*cr, digit); memcpy(grid, state->grid, cr*cr); dlev.maxdiff = DIFF_RECURSIVE; dlev.maxkdiff = DIFF_KINTERSECT; solver(cr, state->blocks, state->kblocks, state->xtype, grid, state->kgrid, &dlev); *error = NULL; if (dlev.diff == DIFF_IMPOSSIBLE) *error = "No solution exists for this puzzle"; else if (dlev.diff == DIFF_AMBIGUOUS) *error = "Multiple solutions exist for this puzzle"; if (*error) { sfree(grid); return NULL; } ret = encode_solve_move(cr, grid); sfree(grid); return ret; } static char *grid_text_format(int cr, struct block_structure *blocks, int xtype, digit *grid) { int vmod, hmod; int x, y; int totallen, linelen, nlines; char *ret, *p, ch; /* * For non-jigsaw Sudoku, we format in the way we always have, * by having the digits unevenly spaced so that the dividing * lines can fit in: * * . . | . . * . . | . . * ----+---- * . . | . . * . . | . . * * For jigsaw puzzles, however, we must leave space between * _all_ pairs of digits for an optional dividing line, so we * have to move to the rather ugly * * . . . . * ------+------ * . . | . . * +---+ * . . | . | . * ------+ | * . . . | . * * We deal with both cases using the same formatting code; we * simply invent a vmod value such that there's a vertical * dividing line before column i iff i is divisible by vmod * (so it's r in the first case and 1 in the second), and hmod * likewise for horizontal dividing lines. */ if (blocks->r != 1) { vmod = blocks->r; hmod = blocks->c; } else { vmod = hmod = 1; } /* * Line length: we have cr digits, each with a space after it, * and (cr-1)/vmod dividing lines, each with a space after it. * The final space is replaced by a newline, but that doesn't * affect the length. */ linelen = 2*(cr + (cr-1)/vmod); /* * Number of lines: we have cr rows of digits, and (cr-1)/hmod * dividing rows. */ nlines = cr + (cr-1)/hmod; /* * Allocate the space. */ totallen = linelen * nlines; ret = snewn(totallen+1, char); /* leave room for terminating NUL */ /* * Write the text. */ p = ret; for (y = 0; y < cr; y++) { /* * Row of digits. */ for (x = 0; x < cr; x++) { /* * Digit. */ digit d = grid[y*cr+x]; if (d == 0) { /* * Empty space: we usually write a dot, but we'll * highlight spaces on the X-diagonals (in X mode) * by using underscores instead. */ if (xtype && (ondiag0(y*cr+x) || ondiag1(y*cr+x))) ch = '_'; else ch = '.'; } else if (d <= 9) { ch = '0' + d; } else { ch = 'a' + d-10; } *p++ = ch; if (x == cr-1) { *p++ = '\n'; continue; } *p++ = ' '; if ((x+1) % vmod) continue; /* * Optional dividing line. */ if (blocks->whichblock[y*cr+x] != blocks->whichblock[y*cr+x+1]) ch = '|'; else ch = ' '; *p++ = ch; *p++ = ' '; } if (y == cr-1 || (y+1) % hmod) continue; /* * Dividing row. */ for (x = 0; x < cr; x++) { int dwid; int tl, tr, bl, br; /* * Division between two squares. This varies * complicatedly in length. */ dwid = 2; /* digit and its following space */ if (x == cr-1) dwid--; /* no following space at end of line */ if (x > 0 && x % vmod == 0) dwid++; /* preceding space after a divider */ if (blocks->whichblock[y*cr+x] != blocks->whichblock[(y+1)*cr+x]) ch = '-'; else ch = ' '; while (dwid-- > 0) *p++ = ch; if (x == cr-1) { *p++ = '\n'; break; } if ((x+1) % vmod) continue; /* * Corner square. This is: * - a space if all four surrounding squares are in * the same block * - a vertical line if the two left ones are in one * block and the two right in another * - a horizontal line if the two top ones are in one * block and the two bottom in another * - a plus sign in all other cases. (If we had a * richer character set available we could break * this case up further by doing fun things with * line-drawing T-pieces.) */ tl = blocks->whichblock[y*cr+x]; tr = blocks->whichblock[y*cr+x+1]; bl = blocks->whichblock[(y+1)*cr+x]; br = blocks->whichblock[(y+1)*cr+x+1]; if (tl == tr && tr == bl && bl == br) ch = ' '; else if (tl == bl && tr == br) ch = '|'; else if (tl == tr && bl == br) ch = '-'; else ch = '+'; *p++ = ch; } } assert(p - ret == totallen); *p = '\0'; return ret; } static int game_can_format_as_text_now(const game_params *params) { /* * Formatting Killer puzzles as text is currently unsupported. I * can't think of any sensible way of doing it which doesn't * involve expanding the puzzle to such a large scale as to make * it unusable. */ if (params->killer) return FALSE; return TRUE; } static char *game_text_format(const game_state *state) { assert(!state->kblocks); return grid_text_format(state->cr, state->blocks, state->xtype, state->grid); } struct game_ui { /* * These are the coordinates of the currently highlighted * square on the grid, if hshow = 1. */ int hx, hy; /* * This indicates whether the current highlight is a * pencil-mark one or a real one. */ int hpencil; /* * This indicates whether or not we're showing the highlight * (used to be hx = hy = -1); important so that when we're * using the cursor keys it doesn't keep coming back at a * fixed position. When hshow = 1, pressing a valid number * or letter key or Space will enter that number or letter in the grid. */ int hshow; /* * This indicates whether we're using the highlight as a cursor; * it means that it doesn't vanish on a keypress, and that it is * allowed on immutable squares. */ int hcursor; }; static game_ui *new_ui(const game_state *state) { game_ui *ui = snew(game_ui); ui->hx = ui->hy = 0; ui->hpencil = ui->hshow = ui->hcursor = 0; return ui; } static void free_ui(game_ui *ui) { sfree(ui); } static char *encode_ui(const game_ui *ui) { return NULL; } static void decode_ui(game_ui *ui, const char *encoding) { } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { int cr = newstate->cr; /* * We prevent pencil-mode highlighting of a filled square, unless * we're using the cursor keys. So if the user has just filled in * a square which we had a pencil-mode highlight in (by Undo, or * by Redo, or by Solve), then we cancel the highlight. */ if (ui->hshow && ui->hpencil && !ui->hcursor && newstate->grid[ui->hy * cr + ui->hx] != 0) { ui->hshow = 0; } } struct game_drawstate { int started; int cr, xtype; int tilesize; digit *grid; unsigned char *pencil; unsigned char *hl; /* This is scratch space used within a single call to game_redraw. */ int nregions, *entered_items; }; static char *interpret_move(const game_state *state, game_ui *ui, const game_drawstate *ds, int x, int y, int button) { int cr = state->cr; int tx, ty; char buf[80]; button &= ~MOD_MASK; tx = (x + TILE_SIZE - BORDER) / TILE_SIZE - 1; ty = (y + TILE_SIZE - BORDER) / TILE_SIZE - 1; if (tx >= 0 && tx < cr && ty >= 0 && ty < cr) { if (button == LEFT_BUTTON) { if (state->immutable[ty*cr+tx]) { ui->hshow = 0; } else if (tx == ui->hx && ty == ui->hy && ui->hshow && ui->hpencil == 0) { ui->hshow = 0; } else { ui->hx = tx; ui->hy = ty; ui->hshow = 1; ui->hpencil = 0; } ui->hcursor = 0; return ""; /* UI activity occurred */ } if (button == RIGHT_BUTTON) { /* * Pencil-mode highlighting for non filled squares. */ if (state->grid[ty*cr+tx] == 0) { if (tx == ui->hx && ty == ui->hy && ui->hshow && ui->hpencil) { ui->hshow = 0; } else { ui->hpencil = 1; ui->hx = tx; ui->hy = ty; ui->hshow = 1; } } else { ui->hshow = 0; } ui->hcursor = 0; return ""; /* UI activity occurred */ } } if (IS_CURSOR_MOVE(button)) { move_cursor(button, &ui->hx, &ui->hy, cr, cr, 0); ui->hshow = ui->hcursor = 1; return ""; } if (ui->hshow && (button == CURSOR_SELECT)) { ui->hpencil = 1 - ui->hpencil; ui->hcursor = 1; return ""; } if (ui->hshow && ((button >= '0' && button <= '9' && button - '0' <= cr) || (button >= 'a' && button <= 'z' && button - 'a' + 10 <= cr) || (button >= 'A' && button <= 'Z' && button - 'A' + 10 <= cr) || button == CURSOR_SELECT2 || button == '\b')) { int n = button - '0'; if (button >= 'A' && button <= 'Z') n = button - 'A' + 10; if (button >= 'a' && button <= 'z') n = button - 'a' + 10; if (button == CURSOR_SELECT2 || button == '\b') n = 0; /* * Can't overwrite this square. This can only happen here * if we're using the cursor keys. */ if (state->immutable[ui->hy*cr+ui->hx]) return NULL; /* * Can't make pencil marks in a filled square. Again, this * can only become highlighted if we're using cursor keys. */ if (ui->hpencil && state->grid[ui->hy*cr+ui->hx]) return NULL; sprintf(buf, "%c%d,%d,%d", (char)(ui->hpencil && n > 0 ? 'P' : 'R'), ui->hx, ui->hy, n); if (!ui->hcursor) ui->hshow = 0; return dupstr(buf); } if (button == 'M' || button == 'm') return dupstr("M"); return NULL; } static game_state *execute_move(const game_state *from, const char *move) { int cr = from->cr; game_state *ret; int x, y, n; if (move[0] == 'S') { const char *p; ret = dup_game(from); ret->completed = ret->cheated = TRUE; p = move+1; for (n = 0; n < cr*cr; n++) { ret->grid[n] = atoi(p); if (!*p || ret->grid[n] < 1 || ret->grid[n] > cr) { free_game(ret); return NULL; } while (*p && isdigit((unsigned char)*p)) p++; if (*p == ',') p++; } return ret; } else if ((move[0] == 'P' || move[0] == 'R') && sscanf(move+1, "%d,%d,%d", &x, &y, &n) == 3 && x >= 0 && x < cr && y >= 0 && y < cr && n >= 0 && n <= cr) { ret = dup_game(from); if (move[0] == 'P' && n > 0) { int index = (y*cr+x) * cr + (n-1); ret->pencil[index] = !ret->pencil[index]; } else { ret->grid[y*cr+x] = n; memset(ret->pencil + (y*cr+x)*cr, 0, cr); /* * We've made a real change to the grid. Check to see * if the game has been completed. */ if (!ret->completed && check_valid( cr, ret->blocks, ret->kblocks, ret->kgrid, ret->xtype, ret->grid)) { ret->completed = TRUE; } } return ret; } else if (move[0] == 'M') { /* * Fill in absolutely all pencil marks in unfilled squares, * for those who like to play by the rigorous approach of * starting off in that state and eliminating things. */ ret = dup_game(from); for (y = 0; y < cr; y++) { for (x = 0; x < cr; x++) { if (!ret->grid[y*cr+x]) { memset(ret->pencil + (y*cr+x)*cr, 1, cr); } } } return ret; } else return NULL; /* couldn't parse move string */ } /* ---------------------------------------------------------------------- * Drawing routines. */ #define SIZE(cr) ((cr) * TILE_SIZE + 2*BORDER + 1) #define GETTILESIZE(cr, w) ( (double)(w-1) / (double)(cr+1) ) static void game_compute_size(const game_params *params, int tilesize, int *x, int *y) { /* Ick: fake up `ds->tilesize' for macro expansion purposes */ struct { int tilesize; } ads, *ds = &ads; ads.tilesize = tilesize; *x = SIZE(params->c * params->r); *y = SIZE(params->c * params->r); } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { ds->tilesize = tilesize; } static float *game_colours(frontend *fe, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float); frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]); ret[COL_XDIAGONALS * 3 + 0] = 0.9F * ret[COL_BACKGROUND * 3 + 0]; ret[COL_XDIAGONALS * 3 + 1] = 0.9F * ret[COL_BACKGROUND * 3 + 1]; ret[COL_XDIAGONALS * 3 + 2] = 0.9F * ret[COL_BACKGROUND * 3 + 2]; ret[COL_GRID * 3 + 0] = 0.0F; ret[COL_GRID * 3 + 1] = 0.0F; ret[COL_GRID * 3 + 2] = 0.0F; ret[COL_CLUE * 3 + 0] = 0.0F; ret[COL_CLUE * 3 + 1] = 0.0F; ret[COL_CLUE * 3 + 2] = 0.0F; ret[COL_USER * 3 + 0] = 0.0F; ret[COL_USER * 3 + 1] = 0.6F * ret[COL_BACKGROUND * 3 + 1]; ret[COL_USER * 3 + 2] = 0.0F; ret[COL_HIGHLIGHT * 3 + 0] = 0.78F * ret[COL_BACKGROUND * 3 + 0]; ret[COL_HIGHLIGHT * 3 + 1] = 0.78F * ret[COL_BACKGROUND * 3 + 1]; ret[COL_HIGHLIGHT * 3 + 2] = 0.78F * ret[COL_BACKGROUND * 3 + 2]; ret[COL_ERROR * 3 + 0] = 1.0F; ret[COL_ERROR * 3 + 1] = 0.0F; ret[COL_ERROR * 3 + 2] = 0.0F; ret[COL_PENCIL * 3 + 0] = 0.5F * ret[COL_BACKGROUND * 3 + 0]; ret[COL_PENCIL * 3 + 1] = 0.5F * ret[COL_BACKGROUND * 3 + 1]; ret[COL_PENCIL * 3 + 2] = ret[COL_BACKGROUND * 3 + 2]; ret[COL_KILLER * 3 + 0] = 0.5F * ret[COL_BACKGROUND * 3 + 0]; ret[COL_KILLER * 3 + 1] = 0.5F * ret[COL_BACKGROUND * 3 + 1]; ret[COL_KILLER * 3 + 2] = 0.1F * ret[COL_BACKGROUND * 3 + 2]; *ncolours = NCOLOURS; return ret; } static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { struct game_drawstate *ds = snew(struct game_drawstate); int cr = state->cr; ds->started = FALSE; ds->cr = cr; ds->xtype = state->xtype; ds->grid = snewn(cr*cr, digit); memset(ds->grid, cr+2, cr*cr); ds->pencil = snewn(cr*cr*cr, digit); memset(ds->pencil, 0, cr*cr*cr); ds->hl = snewn(cr*cr, unsigned char); memset(ds->hl, 0, cr*cr); /* * ds->entered_items needs one row of cr entries per entity in * which digits may not be duplicated. That's one for each row, * each column, each block, each diagonal, and each Killer cage. */ ds->nregions = cr*3 + 2; if (state->kblocks) ds->nregions += state->kblocks->nr_blocks; ds->entered_items = snewn(cr * ds->nregions, int); ds->tilesize = 0; /* not decided yet */ return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { sfree(ds->hl); sfree(ds->pencil); sfree(ds->grid); sfree(ds->entered_items); sfree(ds); } static void draw_number(drawing *dr, game_drawstate *ds, const game_state *state, int x, int y, int hl) { int cr = state->cr; int tx, ty, tw, th; int cx, cy, cw, ch; int col_killer = (hl & 32 ? COL_ERROR : COL_KILLER); char str[20]; if (ds->grid[y*cr+x] == state->grid[y*cr+x] && ds->hl[y*cr+x] == hl && !memcmp(ds->pencil+(y*cr+x)*cr, state->pencil+(y*cr+x)*cr, cr)) return; /* no change required */ tx = BORDER + x * TILE_SIZE + 1 + GRIDEXTRA; ty = BORDER + y * TILE_SIZE + 1 + GRIDEXTRA; cx = tx; cy = ty; cw = tw = TILE_SIZE-1-2*GRIDEXTRA; ch = th = TILE_SIZE-1-2*GRIDEXTRA; if (x > 0 && state->blocks->whichblock[y*cr+x] == state->blocks->whichblock[y*cr+x-1]) cx -= GRIDEXTRA, cw += GRIDEXTRA; if (x+1 < cr && state->blocks->whichblock[y*cr+x] == state->blocks->whichblock[y*cr+x+1]) cw += GRIDEXTRA; if (y > 0 && state->blocks->whichblock[y*cr+x] == state->blocks->whichblock[(y-1)*cr+x]) cy -= GRIDEXTRA, ch += GRIDEXTRA; if (y+1 < cr && state->blocks->whichblock[y*cr+x] == state->blocks->whichblock[(y+1)*cr+x]) ch += GRIDEXTRA; clip(dr, cx, cy, cw, ch); /* background needs erasing */ draw_rect(dr, cx, cy, cw, ch, ((hl & 15) == 1 ? COL_HIGHLIGHT : (ds->xtype && (ondiag0(y*cr+x) || ondiag1(y*cr+x))) ? COL_XDIAGONALS : COL_BACKGROUND)); /* * Draw the corners of thick lines in corner-adjacent squares, * which jut into this square by one pixel. */ if (x > 0 && y > 0 && state->blocks->whichblock[y*cr+x] != state->blocks->whichblock[(y-1)*cr+x-1]) draw_rect(dr, tx-GRIDEXTRA, ty-GRIDEXTRA, GRIDEXTRA, GRIDEXTRA, COL_GRID); if (x+1 < cr && y > 0 && state->blocks->whichblock[y*cr+x] != state->blocks->whichblock[(y-1)*cr+x+1]) draw_rect(dr, tx+TILE_SIZE-1-2*GRIDEXTRA, ty-GRIDEXTRA, GRIDEXTRA, GRIDEXTRA, COL_GRID); if (x > 0 && y+1 < cr && state->blocks->whichblock[y*cr+x] != state->blocks->whichblock[(y+1)*cr+x-1]) draw_rect(dr, tx-GRIDEXTRA, ty+TILE_SIZE-1-2*GRIDEXTRA, GRIDEXTRA, GRIDEXTRA, COL_GRID); if (x+1 < cr && y+1 < cr && state->blocks->whichblock[y*cr+x] != state->blocks->whichblock[(y+1)*cr+x+1]) draw_rect(dr, tx+TILE_SIZE-1-2*GRIDEXTRA, ty+TILE_SIZE-1-2*GRIDEXTRA, GRIDEXTRA, GRIDEXTRA, COL_GRID); /* pencil-mode highlight */ if ((hl & 15) == 2) { int coords[6]; coords[0] = cx; coords[1] = cy; coords[2] = cx+cw/2; coords[3] = cy; coords[4] = cx; coords[5] = cy+ch/2; draw_polygon(dr, coords, 3, COL_HIGHLIGHT, COL_HIGHLIGHT); } if (state->kblocks) { int t = GRIDEXTRA * 3; int kcx, kcy, kcw, kch; int kl, kt, kr, kb; int has_left = 0, has_right = 0, has_top = 0, has_bottom = 0; /* * In non-jigsaw mode, the Killer cages are placed at a * fixed offset from the outer edge of the cell dividing * lines, so that they look right whether those lines are * thick or thin. In jigsaw mode, however, doing this will * sometimes cause the cage outlines in adjacent squares to * fail to match up with each other, so we must offset a * fixed amount from the _centre_ of the cell dividing * lines. */ if (state->blocks->r == 1) { kcx = tx; kcy = ty; kcw = tw; kch = th; } else { kcx = cx; kcy = cy; kcw = cw; kch = ch; } kl = kcx - 1; kt = kcy - 1; kr = kcx + kcw; kb = kcy + kch; /* * First, draw the lines dividing this area from neighbouring * different areas. */ if (x == 0 || state->kblocks->whichblock[y*cr+x] != state->kblocks->whichblock[y*cr+x-1]) has_left = 1, kl += t; if (x+1 >= cr || state->kblocks->whichblock[y*cr+x] != state->kblocks->whichblock[y*cr+x+1]) has_right = 1, kr -= t; if (y == 0 || state->kblocks->whichblock[y*cr+x] != state->kblocks->whichblock[(y-1)*cr+x]) has_top = 1, kt += t; if (y+1 >= cr || state->kblocks->whichblock[y*cr+x] != state->kblocks->whichblock[(y+1)*cr+x]) has_bottom = 1, kb -= t; if (has_top) draw_line(dr, kl, kt, kr, kt, col_killer); if (has_bottom) draw_line(dr, kl, kb, kr, kb, col_killer); if (has_left) draw_line(dr, kl, kt, kl, kb, col_killer); if (has_right) draw_line(dr, kr, kt, kr, kb, col_killer); /* * Now, take care of the corners (just as for the normal borders). * We only need a corner if there wasn't a full edge. */ if (x > 0 && y > 0 && !has_left && !has_top && state->kblocks->whichblock[y*cr+x] != state->kblocks->whichblock[(y-1)*cr+x-1]) { draw_line(dr, kl, kt + t, kl + t, kt + t, col_killer); draw_line(dr, kl + t, kt, kl + t, kt + t, col_killer); } if (x+1 < cr && y > 0 && !has_right && !has_top && state->kblocks->whichblock[y*cr+x] != state->kblocks->whichblock[(y-1)*cr+x+1]) { draw_line(dr, kcx + kcw - t, kt + t, kcx + kcw, kt + t, col_killer); draw_line(dr, kcx + kcw - t, kt, kcx + kcw - t, kt + t, col_killer); } if (x > 0 && y+1 < cr && !has_left && !has_bottom && state->kblocks->whichblock[y*cr+x] != state->kblocks->whichblock[(y+1)*cr+x-1]) { draw_line(dr, kl, kcy + kch - t, kl + t, kcy + kch - t, col_killer); draw_line(dr, kl + t, kcy + kch - t, kl + t, kcy + kch, col_killer); } if (x+1 < cr && y+1 < cr && !has_right && !has_bottom && state->kblocks->whichblock[y*cr+x] != state->kblocks->whichblock[(y+1)*cr+x+1]) { draw_line(dr, kcx + kcw - t, kcy + kch - t, kcx + kcw - t, kcy + kch, col_killer); draw_line(dr, kcx + kcw - t, kcy + kch - t, kcx + kcw, kcy + kch - t, col_killer); } } if (state->killer && state->kgrid[y*cr+x]) { sprintf (str, "%d", state->kgrid[y*cr+x]); draw_text(dr, tx + GRIDEXTRA * 4, ty + GRIDEXTRA * 4 + TILE_SIZE/4, FONT_VARIABLE, TILE_SIZE/4, ALIGN_VNORMAL | ALIGN_HLEFT, col_killer, str); } /* new number needs drawing? */ if (state->grid[y*cr+x]) { str[1] = '\0'; str[0] = state->grid[y*cr+x] + '0'; if (str[0] > '9') str[0] += 'a' - ('9'+1); draw_text(dr, tx + TILE_SIZE/2, ty + TILE_SIZE/2, FONT_VARIABLE, TILE_SIZE/2, ALIGN_VCENTRE | ALIGN_HCENTRE, state->immutable[y*cr+x] ? COL_CLUE : (hl & 16) ? COL_ERROR : COL_USER, str); } else { int i, j, npencil; int pl, pr, pt, pb; float bestsize; int pw, ph, minph, pbest, fontsize; /* Count the pencil marks required. */ for (i = npencil = 0; i < cr; i++) if (state->pencil[(y*cr+x)*cr+i]) npencil++; if (npencil) { minph = 2; /* * Determine the bounding rectangle within which we're going * to put the pencil marks. */ /* Start with the whole square */ pl = tx + GRIDEXTRA; pr = pl + TILE_SIZE - GRIDEXTRA; pt = ty + GRIDEXTRA; pb = pt + TILE_SIZE - GRIDEXTRA; if (state->killer) { /* * Make space for the Killer cages. We do this * unconditionally, for uniformity between squares, * rather than making it depend on whether a Killer * cage edge is actually present on any given side. */ pl += GRIDEXTRA * 3; pr -= GRIDEXTRA * 3; pt += GRIDEXTRA * 3; pb -= GRIDEXTRA * 3; if (state->kgrid[y*cr+x] != 0) { /* Make further space for the Killer number. */ pt += TILE_SIZE/4; /* minph--; */ } } /* * We arrange our pencil marks in a grid layout, with * the number of rows and columns adjusted to allow the * maximum font size. * * So now we work out what the grid size ought to be. */ bestsize = 0.0; pbest = 0; /* Minimum */ for (pw = 3; pw < max(npencil,4); pw++) { float fw, fh, fs; ph = (npencil + pw - 1) / pw; ph = max(ph, minph); fw = (pr - pl) / (float)pw; fh = (pb - pt) / (float)ph; fs = min(fw, fh); if (fs > bestsize) { bestsize = fs; pbest = pw; } } assert(pbest > 0); pw = pbest; ph = (npencil + pw - 1) / pw; ph = max(ph, minph); /* * Now we've got our grid dimensions, work out the pixel * size of a grid element, and round it to the nearest * pixel. (We don't want rounding errors to make the * grid look uneven at low pixel sizes.) */ fontsize = min((pr - pl) / pw, (pb - pt) / ph); /* * Centre the resulting figure in the square. */ pl = tx + (TILE_SIZE - fontsize * pw) / 2; pt = ty + (TILE_SIZE - fontsize * ph) / 2; /* * And move it down a bit if it's collided with the * Killer cage number. */ if (state->killer && state->kgrid[y*cr+x] != 0) { pt = max(pt, ty + GRIDEXTRA * 3 + TILE_SIZE/4); } /* * Now actually draw the pencil marks. */ for (i = j = 0; i < cr; i++) if (state->pencil[(y*cr+x)*cr+i]) { int dx = j % pw, dy = j / pw; str[1] = '\0'; str[0] = i + '1'; if (str[0] > '9') str[0] += 'a' - ('9'+1); draw_text(dr, pl + fontsize * (2*dx+1) / 2, pt + fontsize * (2*dy+1) / 2, FONT_VARIABLE, fontsize, ALIGN_VCENTRE | ALIGN_HCENTRE, COL_PENCIL, str); j++; } } } unclip(dr); draw_update(dr, cx, cy, cw, ch); ds->grid[y*cr+x] = state->grid[y*cr+x]; memcpy(ds->pencil+(y*cr+x)*cr, state->pencil+(y*cr+x)*cr, cr); ds->hl[y*cr+x] = hl; } static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float animtime, float flashtime) { int cr = state->cr; int x, y; if (!ds->started) { /* * The initial contents of the window are not guaranteed * and can vary with front ends. To be on the safe side, * all games should start by drawing a big * background-colour rectangle covering the whole window. */ draw_rect(dr, 0, 0, SIZE(cr), SIZE(cr), COL_BACKGROUND); /* * Draw the grid. We draw it as a big thick rectangle of * COL_GRID initially; individual calls to draw_number() * will poke the right-shaped holes in it. */ draw_rect(dr, BORDER-GRIDEXTRA, BORDER-GRIDEXTRA, cr*TILE_SIZE+1+2*GRIDEXTRA, cr*TILE_SIZE+1+2*GRIDEXTRA, COL_GRID); } /* * This array is used to keep track of rows, columns and boxes * which contain a number more than once. */ for (x = 0; x < cr * ds->nregions; x++) ds->entered_items[x] = 0; for (x = 0; x < cr; x++) for (y = 0; y < cr; y++) { digit d = state->grid[y*cr+x]; if (d) { int box, kbox; /* Rows */ ds->entered_items[x*cr+d-1]++; /* Columns */ ds->entered_items[(y+cr)*cr+d-1]++; /* Blocks */ box = state->blocks->whichblock[y*cr+x]; ds->entered_items[(box+2*cr)*cr+d-1]++; /* Diagonals */ if (ds->xtype) { if (ondiag0(y*cr+x)) ds->entered_items[(3*cr)*cr+d-1]++; if (ondiag1(y*cr+x)) ds->entered_items[(3*cr+1)*cr+d-1]++; } /* Killer cages */ if (state->kblocks) { kbox = state->kblocks->whichblock[y*cr+x]; ds->entered_items[(kbox+3*cr+2)*cr+d-1]++; } } } /* * Draw any numbers which need redrawing. */ for (x = 0; x < cr; x++) { for (y = 0; y < cr; y++) { int highlight = 0; digit d = state->grid[y*cr+x]; if (flashtime > 0 && (flashtime <= FLASH_TIME/3 || flashtime >= FLASH_TIME*2/3)) highlight = 1; /* Highlight active input areas. */ if (x == ui->hx && y == ui->hy && ui->hshow) highlight = ui->hpencil ? 2 : 1; /* Mark obvious errors (ie, numbers which occur more than once * in a single row, column, or box). */ if (d && (ds->entered_items[x*cr+d-1] > 1 || ds->entered_items[(y+cr)*cr+d-1] > 1 || ds->entered_items[(state->blocks->whichblock[y*cr+x] +2*cr)*cr+d-1] > 1 || (ds->xtype && ((ondiag0(y*cr+x) && ds->entered_items[(3*cr)*cr+d-1] > 1) || (ondiag1(y*cr+x) && ds->entered_items[(3*cr+1)*cr+d-1]>1)))|| (state->kblocks && ds->entered_items[(state->kblocks->whichblock[y*cr+x] +3*cr+2)*cr+d-1] > 1))) highlight |= 16; if (d && state->kblocks) { if (check_killer_cage_sum( state->kblocks, state->kgrid, state->grid, state->kblocks->whichblock[y*cr+x]) == 0) highlight |= 32; } draw_number(dr, ds, state, x, y, highlight); } } /* * Update the _entire_ grid if necessary. */ if (!ds->started) { draw_update(dr, 0, 0, SIZE(cr), SIZE(cr)); ds->started = TRUE; } } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return 0.0F; } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { if (!oldstate->completed && newstate->completed && !oldstate->cheated && !newstate->cheated) return FLASH_TIME; return 0.0F; } static int game_status(const game_state *state) { return state->completed ? +1 : 0; } static int game_timing_state(const game_state *state, game_ui *ui) { if (state->completed) return FALSE; return TRUE; } static void game_print_size(const game_params *params, float *x, float *y) { int pw, ph; /* * I'll use 9mm squares by default. They should be quite big * for this game, because players will want to jot down no end * of pencil marks in the squares. */ game_compute_size(params, 900, &pw, &ph); *x = pw / 100.0F; *y = ph / 100.0F; } /* * Subfunction to draw the thick lines between cells. In order to do * this using the line-drawing rather than rectangle-drawing API (so * as to get line thicknesses to scale correctly) and yet have * correctly mitred joins between lines, we must do this by tracing * the boundary of each sub-block and drawing it in one go as a * single polygon. * * This subfunction is also reused with thinner dotted lines to * outline the Killer cages, this time offsetting the outline toward * the interior of the affected squares. */ static void outline_block_structure(drawing *dr, game_drawstate *ds, const game_state *state, struct block_structure *blocks, int ink, int inset) { int cr = state->cr; int *coords; int bi, i, n; int x, y, dx, dy, sx, sy, sdx, sdy; /* * Maximum perimeter of a k-omino is 2k+2. (Proof: start * with k unconnected squares, with total perimeter 4k. * Now repeatedly join two disconnected components * together into a larger one; every time you do so you * remove at least two unit edges, and you require k-1 of * these operations to create a single connected piece, so * you must have at most 4k-2(k-1) = 2k+2 unit edges left * afterwards.) */ coords = snewn(4*cr+4, int); /* 2k+2 points, 2 coords per point */ /* * Iterate over all the blocks. */ for (bi = 0; bi < blocks->nr_blocks; bi++) { if (blocks->nr_squares[bi] == 0) continue; /* * For each block, find a starting square within it * which has a boundary at the left. */ for (i = 0; i < cr; i++) { int j = blocks->blocks[bi][i]; if (j % cr == 0 || blocks->whichblock[j-1] != bi) break; } assert(i < cr); /* every block must have _some_ leftmost square */ x = blocks->blocks[bi][i] % cr; y = blocks->blocks[bi][i] / cr; dx = -1; dy = 0; /* * Now begin tracing round the perimeter. At all * times, (x,y) describes some square within the * block, and (x+dx,y+dy) is some adjacent square * outside it; so the edge between those two squares * is always an edge of the block. */ sx = x, sy = y, sdx = dx, sdy = dy; /* save starting position */ n = 0; do { int cx, cy, tx, ty, nin; /* * Advance to the next edge, by looking at the two * squares beyond it. If they're both outside the block, * we turn right (by leaving x,y the same and rotating * dx,dy clockwise); if they're both inside, we turn * left (by rotating dx,dy anticlockwise and contriving * to leave x+dx,y+dy unchanged); if one of each, we go * straight on (and may enforce by assertion that * they're one of each the _right_ way round). */ nin = 0; tx = x - dy + dx; ty = y + dx + dy; nin += (tx >= 0 && tx < cr && ty >= 0 && ty < cr && blocks->whichblock[ty*cr+tx] == bi); tx = x - dy; ty = y + dx; nin += (tx >= 0 && tx < cr && ty >= 0 && ty < cr && blocks->whichblock[ty*cr+tx] == bi); if (nin == 0) { /* * Turn right. */ int tmp; tmp = dx; dx = -dy; dy = tmp; } else if (nin == 2) { /* * Turn left. */ int tmp; x += dx; y += dy; tmp = dx; dx = dy; dy = -tmp; x -= dx; y -= dy; } else { /* * Go straight on. */ x -= dy; y += dx; } /* * Now enforce by assertion that we ended up * somewhere sensible. */ assert(x >= 0 && x < cr && y >= 0 && y < cr && blocks->whichblock[y*cr+x] == bi); assert(x+dx < 0 || x+dx >= cr || y+dy < 0 || y+dy >= cr || blocks->whichblock[(y+dy)*cr+(x+dx)] != bi); /* * Record the point we just went past at one end of the * edge. To do this, we translate (x,y) down and right * by half a unit (so they're describing a point in the * _centre_ of the square) and then translate back again * in a manner rotated by dy and dx. */ assert(n < 2*cr+2); cx = ((2*x+1) + dy + dx) / 2; cy = ((2*y+1) - dx + dy) / 2; coords[2*n+0] = BORDER + cx * TILE_SIZE; coords[2*n+1] = BORDER + cy * TILE_SIZE; coords[2*n+0] -= dx * inset; coords[2*n+1] -= dy * inset; if (nin == 0) { /* * We turned right, so inset this corner back along * the edge towards the centre of the square. */ coords[2*n+0] -= dy * inset; coords[2*n+1] += dx * inset; } else if (nin == 2) { /* * We turned left, so inset this corner further * _out_ along the edge into the next square. */ coords[2*n+0] += dy * inset; coords[2*n+1] -= dx * inset; } n++; } while (x != sx || y != sy || dx != sdx || dy != sdy); /* * That's our polygon; now draw it. */ draw_polygon(dr, coords, n, -1, ink); } sfree(coords); } static void game_print(drawing *dr, const game_state *state, int tilesize) { int cr = state->cr; int ink = print_mono_colour(dr, 0); int x, y; /* Ick: fake up `ds->tilesize' for macro expansion purposes */ game_drawstate ads, *ds = &ads; game_set_size(dr, ds, NULL, tilesize); /* * Border. */ print_line_width(dr, 3 * TILE_SIZE / 40); draw_rect_outline(dr, BORDER, BORDER, cr*TILE_SIZE, cr*TILE_SIZE, ink); /* * Highlight X-diagonal squares. */ if (state->xtype) { int i; int xhighlight = print_grey_colour(dr, 0.90F); for (i = 0; i < cr; i++) draw_rect(dr, BORDER + i*TILE_SIZE, BORDER + i*TILE_SIZE, TILE_SIZE, TILE_SIZE, xhighlight); for (i = 0; i < cr; i++) if (i*2 != cr-1) /* avoid redoing centre square, just for fun */ draw_rect(dr, BORDER + i*TILE_SIZE, BORDER + (cr-1-i)*TILE_SIZE, TILE_SIZE, TILE_SIZE, xhighlight); } /* * Main grid. */ for (x = 1; x < cr; x++) { print_line_width(dr, TILE_SIZE / 40); draw_line(dr, BORDER+x*TILE_SIZE, BORDER, BORDER+x*TILE_SIZE, BORDER+cr*TILE_SIZE, ink); } for (y = 1; y < cr; y++) { print_line_width(dr, TILE_SIZE / 40); draw_line(dr, BORDER, BORDER+y*TILE_SIZE, BORDER+cr*TILE_SIZE, BORDER+y*TILE_SIZE, ink); } /* * Thick lines between cells. */ print_line_width(dr, 3 * TILE_SIZE / 40); outline_block_structure(dr, ds, state, state->blocks, ink, 0); /* * Killer cages and their totals. */ if (state->kblocks) { print_line_width(dr, TILE_SIZE / 40); print_line_dotted(dr, TRUE); outline_block_structure(dr, ds, state, state->kblocks, ink, 5 * TILE_SIZE / 40); print_line_dotted(dr, FALSE); for (y = 0; y < cr; y++) for (x = 0; x < cr; x++) if (state->kgrid[y*cr+x]) { char str[20]; sprintf(str, "%d", state->kgrid[y*cr+x]); draw_text(dr, BORDER+x*TILE_SIZE + 7*TILE_SIZE/40, BORDER+y*TILE_SIZE + 16*TILE_SIZE/40, FONT_VARIABLE, TILE_SIZE/4, ALIGN_VNORMAL | ALIGN_HLEFT, ink, str); } } /* * Standard (non-Killer) clue numbers. */ for (y = 0; y < cr; y++) for (x = 0; x < cr; x++) if (state->grid[y*cr+x]) { char str[2]; str[1] = '\0'; str[0] = state->grid[y*cr+x] + '0'; if (str[0] > '9') str[0] += 'a' - ('9'+1); draw_text(dr, BORDER + x*TILE_SIZE + TILE_SIZE/2, BORDER + y*TILE_SIZE + TILE_SIZE/2, FONT_VARIABLE, TILE_SIZE/2, ALIGN_VCENTRE | ALIGN_HCENTRE, ink, str); } } #ifdef COMBINED #define thegame solo #endif const struct game thegame = { "Solo", "games.solo", "solo", default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, TRUE, solve_game, TRUE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, PREFERRED_TILE_SIZE, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, TRUE, FALSE, game_print_size, game_print, FALSE, /* wants_statusbar */ FALSE, game_timing_state, REQUIRE_RBUTTON | REQUIRE_NUMPAD, /* flags */ }; #ifdef STANDALONE_SOLVER int main(int argc, char **argv) { game_params *p; game_state *s; char *id = NULL, *desc, *err; int grade = FALSE; struct difficulty dlev; while (--argc > 0) { char *p = *++argv; if (!strcmp(p, "-v")) { solver_show_working = TRUE; } else if (!strcmp(p, "-g")) { grade = TRUE; } else if (*p == '-') { fprintf(stderr, "%s: unrecognised option `%s'\n", argv[0], p); return 1; } else { id = p; } } if (!id) { fprintf(stderr, "usage: %s [-g | -v] \n", argv[0]); return 1; } desc = strchr(id, ':'); if (!desc) { fprintf(stderr, "%s: game id expects a colon in it\n", argv[0]); return 1; } *desc++ = '\0'; p = default_params(); decode_params(p, id); err = validate_desc(p, desc); if (err) { fprintf(stderr, "%s: %s\n", argv[0], err); return 1; } s = new_game(NULL, p, desc); dlev.maxdiff = DIFF_RECURSIVE; dlev.maxkdiff = DIFF_KINTERSECT; solver(s->cr, s->blocks, s->kblocks, s->xtype, s->grid, s->kgrid, &dlev); if (grade) { printf("Difficulty rating: %s\n", dlev.diff==DIFF_BLOCK ? "Trivial (blockwise positional elimination only)": dlev.diff==DIFF_SIMPLE ? "Basic (row/column/number elimination required)": dlev.diff==DIFF_INTERSECT ? "Intermediate (intersectional analysis required)": dlev.diff==DIFF_SET ? "Advanced (set elimination required)": dlev.diff==DIFF_EXTREME ? "Extreme (complex non-recursive techniques required)": dlev.diff==DIFF_RECURSIVE ? "Unreasonable (guesswork and backtracking required)": dlev.diff==DIFF_AMBIGUOUS ? "Ambiguous (multiple solutions exist)": dlev.diff==DIFF_IMPOSSIBLE ? "Impossible (no solution exists)": "INTERNAL ERROR: unrecognised difficulty code"); if (p->killer) printf("Killer difficulty: %s\n", dlev.kdiff==DIFF_KSINGLE ? "Trivial (single square cages only)": dlev.kdiff==DIFF_KMINMAX ? "Simple (maximum sum analysis required)": dlev.kdiff==DIFF_KSUMS ? "Intermediate (sum possibilities)": dlev.kdiff==DIFF_KINTERSECT ? "Advanced (sum region intersections)": "INTERNAL ERROR: unrecognised difficulty code"); } else { printf("%s\n", grid_text_format(s->cr, s->blocks, s->xtype, s->grid)); } return 0; } #endif /* vim: set shiftwidth=4 tabstop=8: */ puzzles-20170606.272beef/slant.c0000644000175000017500000017327313115373615015173 0ustar simonsimon/* * slant.c: Puzzle from nikoli.co.jp involving drawing a diagonal * line through each square of a grid. */ /* * In this puzzle you have a grid of squares, each of which must * contain a diagonal line; you also have clue numbers placed at * _points_ of that grid, which means there's a (w+1) x (h+1) array * of possible clue positions. * * I'm therefore going to adopt a rigid convention throughout this * source file of using w and h for the dimensions of the grid of * squares, and W and H for the dimensions of the grid of points. * Thus, W == w+1 and H == h+1 always. * * Clue arrays will be W*H `signed char's, and the clue at each * point will be a number from 0 to 4, or -1 if there's no clue. * * Solution arrays will be W*H `signed char's, and the number at * each point will be +1 for a forward slash (/), -1 for a * backslash (\), and 0 for unknown. */ #include #include #include #include #include #include #include #include "puzzles.h" enum { COL_BACKGROUND, COL_GRID, COL_INK, COL_SLANT1, COL_SLANT2, COL_ERROR, COL_CURSOR, COL_FILLEDSQUARE, NCOLOURS }; /* * In standalone solver mode, `verbose' is a variable which can be * set by command-line option; in debugging mode it's simply always * true. */ #if defined STANDALONE_SOLVER #define SOLVER_DIAGNOSTICS int verbose = FALSE; #elif defined SOLVER_DIAGNOSTICS #define verbose TRUE #endif /* * Difficulty levels. I do some macro ickery here to ensure that my * enum and the various forms of my name list always match up. */ #define DIFFLIST(A) \ A(EASY,Easy,e) \ A(HARD,Hard,h) #define ENUM(upper,title,lower) DIFF_ ## upper, #define TITLE(upper,title,lower) #title, #define ENCODE(upper,title,lower) #lower #define CONFIG(upper,title,lower) ":" #title enum { DIFFLIST(ENUM) DIFFCOUNT }; static char const *const slant_diffnames[] = { DIFFLIST(TITLE) }; static char const slant_diffchars[] = DIFFLIST(ENCODE); #define DIFFCONFIG DIFFLIST(CONFIG) struct game_params { int w, h, diff; }; typedef struct game_clues { int w, h; signed char *clues; int *tmpdsf; int refcount; } game_clues; #define ERR_VERTEX 1 #define ERR_SQUARE 2 struct game_state { struct game_params p; game_clues *clues; signed char *soln; unsigned char *errors; int completed; int used_solve; /* used to suppress completion flash */ }; static game_params *default_params(void) { game_params *ret = snew(game_params); ret->w = ret->h = 8; ret->diff = DIFF_EASY; return ret; } static const struct game_params slant_presets[] = { {5, 5, DIFF_EASY}, {5, 5, DIFF_HARD}, {8, 8, DIFF_EASY}, {8, 8, DIFF_HARD}, {12, 10, DIFF_EASY}, {12, 10, DIFF_HARD}, }; static int game_fetch_preset(int i, char **name, game_params **params) { game_params *ret; char str[80]; if (i < 0 || i >= lenof(slant_presets)) return FALSE; ret = snew(game_params); *ret = slant_presets[i]; sprintf(str, "%dx%d %s", ret->w, ret->h, slant_diffnames[ret->diff]); *name = dupstr(str); *params = ret; return TRUE; } static void free_params(game_params *params) { sfree(params); } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } static void decode_params(game_params *ret, char const *string) { ret->w = ret->h = atoi(string); while (*string && isdigit((unsigned char)*string)) string++; if (*string == 'x') { string++; ret->h = atoi(string); while (*string && isdigit((unsigned char)*string)) string++; } if (*string == 'd') { int i; string++; for (i = 0; i < DIFFCOUNT; i++) if (*string == slant_diffchars[i]) ret->diff = i; if (*string) string++; } } static char *encode_params(const game_params *params, int full) { char data[256]; sprintf(data, "%dx%d", params->w, params->h); if (full) sprintf(data + strlen(data), "d%c", slant_diffchars[params->diff]); return dupstr(data); } static config_item *game_configure(const game_params *params) { config_item *ret; char buf[80]; ret = snewn(4, config_item); ret[0].name = "Width"; ret[0].type = C_STRING; sprintf(buf, "%d", params->w); ret[0].sval = dupstr(buf); ret[0].ival = 0; ret[1].name = "Height"; ret[1].type = C_STRING; sprintf(buf, "%d", params->h); ret[1].sval = dupstr(buf); ret[1].ival = 0; ret[2].name = "Difficulty"; ret[2].type = C_CHOICES; ret[2].sval = DIFFCONFIG; ret[2].ival = params->diff; ret[3].name = NULL; ret[3].type = C_END; ret[3].sval = NULL; ret[3].ival = 0; return ret; } static game_params *custom_params(const config_item *cfg) { game_params *ret = snew(game_params); ret->w = atoi(cfg[0].sval); ret->h = atoi(cfg[1].sval); ret->diff = cfg[2].ival; return ret; } static char *validate_params(const game_params *params, int full) { /* * (At least at the time of writing this comment) The grid * generator is actually capable of handling even zero grid * dimensions without crashing. Puzzles with a zero-area grid * are a bit boring, though, because they're already solved :-) * And puzzles with a dimension of 1 can't be made Hard, which * means the simplest thing is to forbid them altogether. */ if (params->w < 2 || params->h < 2) return "Width and height must both be at least two"; return NULL; } /* * Scratch space for solver. */ struct solver_scratch { /* * Disjoint set forest which tracks the connected sets of * points. */ int *connected; /* * Counts the number of possible exits from each connected set * of points. (That is, the number of possible _simultaneous_ * exits: an unconnected point labelled 2 has an exit count of * 2 even if all four possible edges are still under * consideration.) */ int *exits; /* * Tracks whether each connected set of points includes a * border point. */ unsigned char *border; /* * Another disjoint set forest. This one tracks _squares_ which * are known to slant in the same direction. */ int *equiv; /* * Stores slash values which we know for an equivalence class. * When we fill in a square, we set slashval[canonify(x)] to * the same value as soln[x], so that we can then spot other * squares equivalent to it and fill them in immediately via * their known equivalence. */ signed char *slashval; /* * Stores possible v-shapes. This array is w by h in size, but * not every bit of every entry is meaningful. The bits mean: * * - bit 0 for a square means that that square and the one to * its right might form a v-shape between them * - bit 1 for a square means that that square and the one to * its right might form a ^-shape between them * - bit 2 for a square means that that square and the one * below it might form a >-shape between them * - bit 3 for a square means that that square and the one * below it might form a <-shape between them * * Any starting 1 or 3 clue rules out four bits in this array * immediately; a 2 clue propagates any ruled-out bit past it * (if the two squares on one side of a 2 cannot be a v-shape, * then neither can the two on the other side be the same * v-shape); we can rule out further bits during play using * partially filled 2 clues; whenever a pair of squares is * known not to be _either_ kind of v-shape, we can mark them * as equivalent. */ unsigned char *vbitmap; /* * Useful to have this information automatically passed to * solver subroutines. (This pointer is not dynamically * allocated by new_scratch and free_scratch.) */ const signed char *clues; }; static struct solver_scratch *new_scratch(int w, int h) { int W = w+1, H = h+1; struct solver_scratch *ret = snew(struct solver_scratch); ret->connected = snewn(W*H, int); ret->exits = snewn(W*H, int); ret->border = snewn(W*H, unsigned char); ret->equiv = snewn(w*h, int); ret->slashval = snewn(w*h, signed char); ret->vbitmap = snewn(w*h, unsigned char); return ret; } static void free_scratch(struct solver_scratch *sc) { sfree(sc->vbitmap); sfree(sc->slashval); sfree(sc->equiv); sfree(sc->border); sfree(sc->exits); sfree(sc->connected); sfree(sc); } /* * Wrapper on dsf_merge() which updates the `exits' and `border' * arrays. */ static void merge_vertices(int *connected, struct solver_scratch *sc, int i, int j) { int exits = -1, border = FALSE; /* initialise to placate optimiser */ if (sc) { i = dsf_canonify(connected, i); j = dsf_canonify(connected, j); /* * We have used one possible exit from each of the two * classes. Thus, the viable exit count of the new class is * the sum of the old exit counts minus two. */ exits = sc->exits[i] + sc->exits[j] - 2; border = sc->border[i] || sc->border[j]; } dsf_merge(connected, i, j); if (sc) { i = dsf_canonify(connected, i); sc->exits[i] = exits; sc->border[i] = border; } } /* * Called when we have just blocked one way out of a particular * point. If that point is a non-clue point (thus has a variable * number of exits), we have therefore decreased its potential exit * count, so we must decrement the exit count for the group as a * whole. */ static void decr_exits(struct solver_scratch *sc, int i) { if (sc->clues[i] < 0) { i = dsf_canonify(sc->connected, i); sc->exits[i]--; } } static void fill_square(int w, int h, int x, int y, int v, signed char *soln, int *connected, struct solver_scratch *sc) { int W = w+1 /*, H = h+1 */; assert(x >= 0 && x < w && y >= 0 && y < h); if (soln[y*w+x] != 0) { return; /* do nothing */ } #ifdef SOLVER_DIAGNOSTICS if (verbose) printf(" placing %c in %d,%d\n", v == -1 ? '\\' : '/', x, y); #endif soln[y*w+x] = v; if (sc) { int c = dsf_canonify(sc->equiv, y*w+x); sc->slashval[c] = v; } if (v < 0) { merge_vertices(connected, sc, y*W+x, (y+1)*W+(x+1)); if (sc) { decr_exits(sc, y*W+(x+1)); decr_exits(sc, (y+1)*W+x); } } else { merge_vertices(connected, sc, y*W+(x+1), (y+1)*W+x); if (sc) { decr_exits(sc, y*W+x); decr_exits(sc, (y+1)*W+(x+1)); } } } static int vbitmap_clear(int w, int h, struct solver_scratch *sc, int x, int y, int vbits, char *reason, ...) { int done_something = FALSE; int vbit; for (vbit = 1; vbit <= 8; vbit <<= 1) if (vbits & sc->vbitmap[y*w+x] & vbit) { done_something = TRUE; #ifdef SOLVER_DIAGNOSTICS if (verbose) { va_list ap; printf("ruling out %c shape at (%d,%d)-(%d,%d) (", "!v^!>!!!<"[vbit], x, y, x+((vbit&0x3)!=0), y+((vbit&0xC)!=0)); va_start(ap, reason); vprintf(reason, ap); va_end(ap); printf(")\n"); } #endif sc->vbitmap[y*w+x] &= ~vbit; } return done_something; } /* * Solver. Returns 0 for impossibility, 1 for success, 2 for * ambiguity or failure to converge. */ static int slant_solve(int w, int h, const signed char *clues, signed char *soln, struct solver_scratch *sc, int difficulty) { int W = w+1, H = h+1; int x, y, i, j; int done_something; /* * Clear the output. */ memset(soln, 0, w*h); sc->clues = clues; /* * Establish a disjoint set forest for tracking connectedness * between grid points. */ dsf_init(sc->connected, W*H); /* * Establish a disjoint set forest for tracking which squares * are known to slant in the same direction. */ dsf_init(sc->equiv, w*h); /* * Clear the slashval array. */ memset(sc->slashval, 0, w*h); /* * Set up the vbitmap array. Initially all types of v are possible. */ memset(sc->vbitmap, 0xF, w*h); /* * Initialise the `exits' and `border' arrays. These are used * to do second-order loop avoidance: the dual of the no loops * constraint is that every point must be somehow connected to * the border of the grid (otherwise there would be a solid * loop around it which prevented this). * * I define a `dead end' to be a connected group of points * which contains no border point, and which can form at most * one new connection outside itself. Then I forbid placing an * edge so that it connects together two dead-end groups, since * this would yield a non-border-connected isolated subgraph * with no further scope to extend it. */ for (y = 0; y < H; y++) for (x = 0; x < W; x++) { if (y == 0 || y == H-1 || x == 0 || x == W-1) sc->border[y*W+x] = TRUE; else sc->border[y*W+x] = FALSE; if (clues[y*W+x] < 0) sc->exits[y*W+x] = 4; else sc->exits[y*W+x] = clues[y*W+x]; } /* * Repeatedly try to deduce something until we can't. */ do { done_something = FALSE; /* * Any clue point with the number of remaining lines equal * to zero or to the number of remaining undecided * neighbouring squares can be filled in completely. */ for (y = 0; y < H; y++) for (x = 0; x < W; x++) { struct { int pos, slash; } neighbours[4]; int nneighbours; int nu, nl, c, s, eq, eq2, last, meq, mj1, mj2; if ((c = clues[y*W+x]) < 0) continue; /* * We have a clue point. Start by listing its * neighbouring squares, in order around the point, * together with the type of slash that would be * required in that square to connect to the point. */ nneighbours = 0; if (x > 0 && y > 0) { neighbours[nneighbours].pos = (y-1)*w+(x-1); neighbours[nneighbours].slash = -1; nneighbours++; } if (x > 0 && y < h) { neighbours[nneighbours].pos = y*w+(x-1); neighbours[nneighbours].slash = +1; nneighbours++; } if (x < w && y < h) { neighbours[nneighbours].pos = y*w+x; neighbours[nneighbours].slash = -1; nneighbours++; } if (x < w && y > 0) { neighbours[nneighbours].pos = (y-1)*w+x; neighbours[nneighbours].slash = +1; nneighbours++; } /* * Count up the number of undecided neighbours, and * also the number of lines already present. * * If we're not on DIFF_EASY, then in this loop we * also track whether we've seen two adjacent empty * squares belonging to the same equivalence class * (meaning they have the same type of slash). If * so, we count them jointly as one line. */ nu = 0; nl = c; last = neighbours[nneighbours-1].pos; if (soln[last] == 0) eq = dsf_canonify(sc->equiv, last); else eq = -1; meq = mj1 = mj2 = -1; for (i = 0; i < nneighbours; i++) { j = neighbours[i].pos; s = neighbours[i].slash; if (soln[j] == 0) { nu++; /* undecided */ if (meq < 0 && difficulty > DIFF_EASY) { eq2 = dsf_canonify(sc->equiv, j); if (eq == eq2 && last != j) { /* * We've found an equivalent pair. * Mark it. This also inhibits any * further equivalence tracking * around this square, since we can * only handle one pair (and in * particular we want to avoid * being misled by two overlapping * equivalence pairs). */ meq = eq; mj1 = last; mj2 = j; nl--; /* count one line */ nu -= 2; /* and lose two undecideds */ } else eq = eq2; } } else { eq = -1; if (soln[j] == s) nl--; /* here's a line */ } last = j; } /* * Check the counts. */ if (nl < 0 || nl > nu) { /* * No consistent value for this at all! */ #ifdef SOLVER_DIAGNOSTICS if (verbose) printf("need %d / %d lines around clue point at %d,%d!\n", nl, nu, x, y); #endif return 0; /* impossible */ } if (nu > 0 && (nl == 0 || nl == nu)) { #ifdef SOLVER_DIAGNOSTICS if (verbose) { if (meq >= 0) printf("partially (since %d,%d == %d,%d) ", mj1%w, mj1/w, mj2%w, mj2/w); printf("%s around clue point at %d,%d\n", nl ? "filling" : "emptying", x, y); } #endif for (i = 0; i < nneighbours; i++) { j = neighbours[i].pos; s = neighbours[i].slash; if (soln[j] == 0 && j != mj1 && j != mj2) fill_square(w, h, j%w, j/w, (nl ? s : -s), soln, sc->connected, sc); } done_something = TRUE; } else if (nu == 2 && nl == 1 && difficulty > DIFF_EASY) { /* * If we have precisely two undecided squares * and precisely one line to place between * them, _and_ those squares are adjacent, then * we can mark them as equivalent to one * another. * * This even applies if meq >= 0: if we have a * 2 clue point and two of its neighbours are * already marked equivalent, we can indeed * mark the other two as equivalent. * * We don't bother with this on DIFF_EASY, * since we wouldn't have used the results * anyway. */ last = -1; for (i = 0; i < nneighbours; i++) { j = neighbours[i].pos; if (soln[j] == 0 && j != mj1 && j != mj2) { if (last < 0) last = i; else if (last == i-1 || (last == 0 && i == 3)) break; /* found a pair */ } } if (i < nneighbours) { int sv1, sv2; assert(last >= 0); /* * neighbours[last] and neighbours[i] are * the pair. Mark them equivalent. */ #ifdef SOLVER_DIAGNOSTICS if (verbose) { if (meq >= 0) printf("since %d,%d == %d,%d, ", mj1%w, mj1/w, mj2%w, mj2/w); } #endif mj1 = neighbours[last].pos; mj2 = neighbours[i].pos; #ifdef SOLVER_DIAGNOSTICS if (verbose) printf("clue point at %d,%d implies %d,%d == %d," "%d\n", x, y, mj1%w, mj1/w, mj2%w, mj2/w); #endif mj1 = dsf_canonify(sc->equiv, mj1); sv1 = sc->slashval[mj1]; mj2 = dsf_canonify(sc->equiv, mj2); sv2 = sc->slashval[mj2]; if (sv1 != 0 && sv2 != 0 && sv1 != sv2) { #ifdef SOLVER_DIAGNOSTICS if (verbose) printf("merged two equivalence classes with" " different slash values!\n"); #endif return 0; } sv1 = sv1 ? sv1 : sv2; dsf_merge(sc->equiv, mj1, mj2); mj1 = dsf_canonify(sc->equiv, mj1); sc->slashval[mj1] = sv1; } } } if (done_something) continue; /* * Failing that, we now apply the second condition, which * is that no square may be filled in such a way as to form * a loop. Also in this loop (since it's over squares * rather than points), we check slashval to see if we've * already filled in another square in the same equivalence * class. * * The slashval check is disabled on DIFF_EASY, as is dead * end avoidance. Only _immediate_ loop avoidance remains. */ for (y = 0; y < h; y++) for (x = 0; x < w; x++) { int fs, bs, v; int c1, c2; #ifdef SOLVER_DIAGNOSTICS char *reason = ""; #endif if (soln[y*w+x]) continue; /* got this one already */ fs = FALSE; bs = FALSE; if (difficulty > DIFF_EASY) v = sc->slashval[dsf_canonify(sc->equiv, y*w+x)]; else v = 0; /* * Try to rule out connectivity between (x,y) and * (x+1,y+1); if successful, we will deduce that we * must have a forward slash. */ c1 = dsf_canonify(sc->connected, y*W+x); c2 = dsf_canonify(sc->connected, (y+1)*W+(x+1)); if (c1 == c2) { fs = TRUE; #ifdef SOLVER_DIAGNOSTICS reason = "simple loop avoidance"; #endif } if (difficulty > DIFF_EASY && !sc->border[c1] && !sc->border[c2] && sc->exits[c1] <= 1 && sc->exits[c2] <= 1) { fs = TRUE; #ifdef SOLVER_DIAGNOSTICS reason = "dead end avoidance"; #endif } if (v == +1) { fs = TRUE; #ifdef SOLVER_DIAGNOSTICS reason = "equivalence to an already filled square"; #endif } /* * Now do the same between (x+1,y) and (x,y+1), to * see if we are required to have a backslash. */ c1 = dsf_canonify(sc->connected, y*W+(x+1)); c2 = dsf_canonify(sc->connected, (y+1)*W+x); if (c1 == c2) { bs = TRUE; #ifdef SOLVER_DIAGNOSTICS reason = "simple loop avoidance"; #endif } if (difficulty > DIFF_EASY && !sc->border[c1] && !sc->border[c2] && sc->exits[c1] <= 1 && sc->exits[c2] <= 1) { bs = TRUE; #ifdef SOLVER_DIAGNOSTICS reason = "dead end avoidance"; #endif } if (v == -1) { bs = TRUE; #ifdef SOLVER_DIAGNOSTICS reason = "equivalence to an already filled square"; #endif } if (fs && bs) { /* * No consistent value for this at all! */ #ifdef SOLVER_DIAGNOSTICS if (verbose) printf("%d,%d has no consistent slash!\n", x, y); #endif return 0; /* impossible */ } if (fs) { #ifdef SOLVER_DIAGNOSTICS if (verbose) printf("employing %s\n", reason); #endif fill_square(w, h, x, y, +1, soln, sc->connected, sc); done_something = TRUE; } else if (bs) { #ifdef SOLVER_DIAGNOSTICS if (verbose) printf("employing %s\n", reason); #endif fill_square(w, h, x, y, -1, soln, sc->connected, sc); done_something = TRUE; } } if (done_something) continue; /* * Now see what we can do with the vbitmap array. All * vbitmap deductions are disabled at Easy level. */ if (difficulty <= DIFF_EASY) continue; for (y = 0; y < h; y++) for (x = 0; x < w; x++) { int s, c; /* * Any line already placed in a square must rule * out any type of v which contradicts it. */ if ((s = soln[y*w+x]) != 0) { if (x > 0) done_something |= vbitmap_clear(w, h, sc, x-1, y, (s < 0 ? 0x1 : 0x2), "contradicts known edge at (%d,%d)",x,y); if (x+1 < w) done_something |= vbitmap_clear(w, h, sc, x, y, (s < 0 ? 0x2 : 0x1), "contradicts known edge at (%d,%d)",x,y); if (y > 0) done_something |= vbitmap_clear(w, h, sc, x, y-1, (s < 0 ? 0x4 : 0x8), "contradicts known edge at (%d,%d)",x,y); if (y+1 < h) done_something |= vbitmap_clear(w, h, sc, x, y, (s < 0 ? 0x8 : 0x4), "contradicts known edge at (%d,%d)",x,y); } /* * If both types of v are ruled out for a pair of * adjacent squares, mark them as equivalent. */ if (x+1 < w && !(sc->vbitmap[y*w+x] & 0x3)) { int n1 = y*w+x, n2 = y*w+(x+1); if (dsf_canonify(sc->equiv, n1) != dsf_canonify(sc->equiv, n2)) { dsf_merge(sc->equiv, n1, n2); done_something = TRUE; #ifdef SOLVER_DIAGNOSTICS if (verbose) printf("(%d,%d) and (%d,%d) must be equivalent" " because both v-shapes are ruled out\n", x, y, x+1, y); #endif } } if (y+1 < h && !(sc->vbitmap[y*w+x] & 0xC)) { int n1 = y*w+x, n2 = (y+1)*w+x; if (dsf_canonify(sc->equiv, n1) != dsf_canonify(sc->equiv, n2)) { dsf_merge(sc->equiv, n1, n2); done_something = TRUE; #ifdef SOLVER_DIAGNOSTICS if (verbose) printf("(%d,%d) and (%d,%d) must be equivalent" " because both v-shapes are ruled out\n", x, y, x, y+1); #endif } } /* * The remaining work in this loop only works * around non-edge clue points. */ if (y == 0 || x == 0) continue; if ((c = clues[y*W+x]) < 0) continue; /* * x,y marks a clue point not on the grid edge. See * if this clue point allows us to rule out any v * shapes. */ if (c == 1) { /* * A 1 clue can never have any v shape pointing * at it. */ done_something |= vbitmap_clear(w, h, sc, x-1, y-1, 0x5, "points at 1 clue at (%d,%d)", x, y); done_something |= vbitmap_clear(w, h, sc, x-1, y, 0x2, "points at 1 clue at (%d,%d)", x, y); done_something |= vbitmap_clear(w, h, sc, x, y-1, 0x8, "points at 1 clue at (%d,%d)", x, y); } else if (c == 3) { /* * A 3 clue can never have any v shape pointing * away from it. */ done_something |= vbitmap_clear(w, h, sc, x-1, y-1, 0xA, "points away from 3 clue at (%d,%d)", x, y); done_something |= vbitmap_clear(w, h, sc, x-1, y, 0x1, "points away from 3 clue at (%d,%d)", x, y); done_something |= vbitmap_clear(w, h, sc, x, y-1, 0x4, "points away from 3 clue at (%d,%d)", x, y); } else if (c == 2) { /* * If a 2 clue has any kind of v ruled out on * one side of it, the same v is ruled out on * the other side. */ done_something |= vbitmap_clear(w, h, sc, x-1, y-1, (sc->vbitmap[(y )*w+(x-1)] & 0x3) ^ 0x3, "propagated by 2 clue at (%d,%d)", x, y); done_something |= vbitmap_clear(w, h, sc, x-1, y-1, (sc->vbitmap[(y-1)*w+(x )] & 0xC) ^ 0xC, "propagated by 2 clue at (%d,%d)", x, y); done_something |= vbitmap_clear(w, h, sc, x-1, y, (sc->vbitmap[(y-1)*w+(x-1)] & 0x3) ^ 0x3, "propagated by 2 clue at (%d,%d)", x, y); done_something |= vbitmap_clear(w, h, sc, x, y-1, (sc->vbitmap[(y-1)*w+(x-1)] & 0xC) ^ 0xC, "propagated by 2 clue at (%d,%d)", x, y); } #undef CLEARBITS } } while (done_something); /* * Solver can make no more progress. See if the grid is full. */ for (i = 0; i < w*h; i++) if (!soln[i]) return 2; /* failed to converge */ return 1; /* success */ } /* * Filled-grid generator. */ static void slant_generate(int w, int h, signed char *soln, random_state *rs) { int W = w+1, H = h+1; int x, y, i; int *connected, *indices; /* * Clear the output. */ memset(soln, 0, w*h); /* * Establish a disjoint set forest for tracking connectedness * between grid points. */ connected = snew_dsf(W*H); /* * Prepare a list of the squares in the grid, and fill them in * in a random order. */ indices = snewn(w*h, int); for (i = 0; i < w*h; i++) indices[i] = i; shuffle(indices, w*h, sizeof(*indices), rs); /* * Fill in each one in turn. */ for (i = 0; i < w*h; i++) { int fs, bs, v; y = indices[i] / w; x = indices[i] % w; fs = (dsf_canonify(connected, y*W+x) == dsf_canonify(connected, (y+1)*W+(x+1))); bs = (dsf_canonify(connected, (y+1)*W+x) == dsf_canonify(connected, y*W+(x+1))); /* * It isn't possible to get into a situation where we * aren't allowed to place _either_ type of slash in a * square. Thus, filled-grid generation never has to * backtrack. * * Proof (thanks to Gareth Taylor): * * If it were possible, it would have to be because there * was an existing path (not using this square) between the * top-left and bottom-right corners of this square, and * another between the other two. These two paths would * have to cross at some point. * * Obviously they can't cross in the middle of a square, so * they must cross by sharing a point in common. But this * isn't possible either: if you chessboard-colour all the * points on the grid, you find that any continuous * diagonal path is entirely composed of points of the same * colour. And one of our two hypothetical paths is between * two black points, and the other is between two white * points - therefore they can have no point in common. [] */ assert(!(fs && bs)); v = fs ? +1 : bs ? -1 : 2 * random_upto(rs, 2) - 1; fill_square(w, h, x, y, v, soln, connected, NULL); } sfree(indices); sfree(connected); } static char *new_game_desc(const game_params *params, random_state *rs, char **aux, int interactive) { int w = params->w, h = params->h, W = w+1, H = h+1; signed char *soln, *tmpsoln, *clues; int *clueindices; struct solver_scratch *sc; int x, y, v, i, j; char *desc; soln = snewn(w*h, signed char); tmpsoln = snewn(w*h, signed char); clues = snewn(W*H, signed char); clueindices = snewn(W*H, int); sc = new_scratch(w, h); do { /* * Create the filled grid. */ slant_generate(w, h, soln, rs); /* * Fill in the complete set of clues. */ for (y = 0; y < H; y++) for (x = 0; x < W; x++) { v = 0; if (x > 0 && y > 0 && soln[(y-1)*w+(x-1)] == -1) v++; if (x > 0 && y < h && soln[y*w+(x-1)] == +1) v++; if (x < w && y > 0 && soln[(y-1)*w+x] == +1) v++; if (x < w && y < h && soln[y*w+x] == -1) v++; clues[y*W+x] = v; } /* * With all clue points filled in, all puzzles are easy: we can * simply process the clue points in lexicographic order, and * at each clue point we will always have at most one square * undecided, which we can then fill in uniquely. */ assert(slant_solve(w, h, clues, tmpsoln, sc, DIFF_EASY) == 1); /* * Remove as many clues as possible while retaining solubility. * * In DIFF_HARD mode, we prioritise the removal of obvious * starting points (4s, 0s, border 2s and corner 1s), on * the grounds that having as few of these as possible * seems like a good thing. In particular, we can often get * away without _any_ completely obvious starting points, * which is even better. */ for (i = 0; i < W*H; i++) clueindices[i] = i; shuffle(clueindices, W*H, sizeof(*clueindices), rs); for (j = 0; j < 2; j++) { for (i = 0; i < W*H; i++) { int pass, yb, xb; y = clueindices[i] / W; x = clueindices[i] % W; v = clues[y*W+x]; /* * Identify which pass we should process this point * in. If it's an obvious start point, _or_ we're * in DIFF_EASY, then it goes in pass 0; otherwise * pass 1. */ xb = (x == 0 || x == W-1); yb = (y == 0 || y == H-1); if (params->diff == DIFF_EASY || v == 4 || v == 0 || (v == 2 && (xb||yb)) || (v == 1 && xb && yb)) pass = 0; else pass = 1; if (pass == j) { clues[y*W+x] = -1; if (slant_solve(w, h, clues, tmpsoln, sc, params->diff) != 1) clues[y*W+x] = v; /* put it back */ } } } /* * And finally, verify that the grid is of _at least_ the * requested difficulty, by running the solver one level * down and verifying that it can't manage it. */ } while (params->diff > 0 && slant_solve(w, h, clues, tmpsoln, sc, params->diff - 1) <= 1); /* * Now we have the clue set as it will be presented to the * user. Encode it in a game desc. */ { char *p; int run, i; desc = snewn(W*H+1, char); p = desc; run = 0; for (i = 0; i <= W*H; i++) { int n = (i < W*H ? clues[i] : -2); if (n == -1) run++; else { if (run) { while (run > 0) { int c = 'a' - 1 + run; if (run > 26) c = 'z'; *p++ = c; run -= c - ('a' - 1); } } if (n >= 0) *p++ = '0' + n; run = 0; } } assert(p - desc <= W*H); *p++ = '\0'; desc = sresize(desc, p - desc, char); } /* * Encode the solution as an aux_info. */ { char *auxbuf; *aux = auxbuf = snewn(w*h+1, char); for (i = 0; i < w*h; i++) auxbuf[i] = soln[i] < 0 ? '\\' : '/'; auxbuf[w*h] = '\0'; } free_scratch(sc); sfree(clueindices); sfree(clues); sfree(tmpsoln); sfree(soln); return desc; } static char *validate_desc(const game_params *params, const char *desc) { int w = params->w, h = params->h, W = w+1, H = h+1; int area = W*H; int squares = 0; while (*desc) { int n = *desc++; if (n >= 'a' && n <= 'z') { squares += n - 'a' + 1; } else if (n >= '0' && n <= '4') { squares++; } else return "Invalid character in game description"; } if (squares < area) return "Not enough data to fill grid"; if (squares > area) return "Too much data to fit in grid"; return NULL; } static game_state *new_game(midend *me, const game_params *params, const char *desc) { int w = params->w, h = params->h, W = w+1, H = h+1; game_state *state = snew(game_state); int area = W*H; int squares = 0; state->p = *params; state->soln = snewn(w*h, signed char); memset(state->soln, 0, w*h); state->completed = state->used_solve = FALSE; state->errors = snewn(W*H, unsigned char); memset(state->errors, 0, W*H); state->clues = snew(game_clues); state->clues->w = w; state->clues->h = h; state->clues->clues = snewn(W*H, signed char); state->clues->refcount = 1; state->clues->tmpdsf = snewn(W*H*2+W+H, int); memset(state->clues->clues, -1, W*H); while (*desc) { int n = *desc++; if (n >= 'a' && n <= 'z') { squares += n - 'a' + 1; } else if (n >= '0' && n <= '4') { state->clues->clues[squares++] = n - '0'; } else assert(!"can't get here"); } assert(squares == area); return state; } static game_state *dup_game(const game_state *state) { int w = state->p.w, h = state->p.h, W = w+1, H = h+1; game_state *ret = snew(game_state); ret->p = state->p; ret->clues = state->clues; ret->clues->refcount++; ret->completed = state->completed; ret->used_solve = state->used_solve; ret->soln = snewn(w*h, signed char); memcpy(ret->soln, state->soln, w*h); ret->errors = snewn(W*H, unsigned char); memcpy(ret->errors, state->errors, W*H); return ret; } static void free_game(game_state *state) { sfree(state->errors); sfree(state->soln); assert(state->clues); if (--state->clues->refcount <= 0) { sfree(state->clues->clues); sfree(state->clues->tmpdsf); sfree(state->clues); } sfree(state); } /* * Utility function to return the current degree of a vertex. If * `anti' is set, it returns the number of filled-in edges * surrounding the point which _don't_ connect to it; thus 4 minus * its anti-degree is the maximum degree it could have if all the * empty spaces around it were filled in. * * (Yes, _4_ minus its anti-degree even if it's a border vertex.) * * If ret > 0, *sx and *sy are set to the coordinates of one of the * squares that contributed to it. */ static int vertex_degree(int w, int h, signed char *soln, int x, int y, int anti, int *sx, int *sy) { int ret = 0; assert(x >= 0 && x <= w && y >= 0 && y <= h); if (x > 0 && y > 0 && soln[(y-1)*w+(x-1)] - anti < 0) { if (sx) *sx = x-1; if (sy) *sy = y-1; ret++; } if (x > 0 && y < h && soln[y*w+(x-1)] + anti > 0) { if (sx) *sx = x-1; if (sy) *sy = y; ret++; } if (x < w && y > 0 && soln[(y-1)*w+x] + anti > 0) { if (sx) *sx = x; if (sy) *sy = y-1; ret++; } if (x < w && y < h && soln[y*w+x] - anti < 0) { if (sx) *sx = x; if (sy) *sy = y; ret++; } return anti ? 4 - ret : ret; } struct slant_neighbour_ctx { const game_state *state; int i, n, neighbours[4]; }; static int slant_neighbour(int vertex, void *vctx) { struct slant_neighbour_ctx *ctx = (struct slant_neighbour_ctx *)vctx; if (vertex >= 0) { int w = ctx->state->p.w, h = ctx->state->p.h, W = w+1; int x = vertex % W, y = vertex / W; ctx->n = ctx->i = 0; if (x < w && y < h && ctx->state->soln[y*w+x] < 0) ctx->neighbours[ctx->n++] = (y+1)*W+(x+1); if (x > 0 && y > 0 && ctx->state->soln[(y-1)*w+(x-1)] < 0) ctx->neighbours[ctx->n++] = (y-1)*W+(x-1); if (x > 0 && y < h && ctx->state->soln[y*w+(x-1)] > 0) ctx->neighbours[ctx->n++] = (y+1)*W+(x-1); if (x < w && y > 0 && ctx->state->soln[(y-1)*w+x] > 0) ctx->neighbours[ctx->n++] = (y-1)*W+(x+1); } if (ctx->i < ctx->n) return ctx->neighbours[ctx->i++]; else return -1; } static int check_completion(game_state *state) { int w = state->p.w, h = state->p.h, W = w+1, H = h+1; int x, y, err = FALSE; memset(state->errors, 0, W*H); /* * Detect and error-highlight loops in the grid. */ { struct findloopstate *fls = findloop_new_state(W*H); struct slant_neighbour_ctx ctx; ctx.state = state; if (findloop_run(fls, W*H, slant_neighbour, &ctx)) err = TRUE; for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { int u, v; if (state->soln[y*w+x] == 0) { continue; } else if (state->soln[y*w+x] > 0) { u = y*W+(x+1); v = (y+1)*W+x; } else { u = (y+1)*W+(x+1); v = y*W+x; } if (findloop_is_loop_edge(fls, u, v)) state->errors[y*W+x] |= ERR_SQUARE; } } findloop_free_state(fls); } /* * Now go through and check the degree of each clue vertex, and * mark it with ERR_VERTEX if it cannot be fulfilled. */ for (y = 0; y < H; y++) for (x = 0; x < W; x++) { int c; if ((c = state->clues->clues[y*W+x]) < 0) continue; /* * Check to see if there are too many connections to * this vertex _or_ too many non-connections. Either is * grounds for marking the vertex as erroneous. */ if (vertex_degree(w, h, state->soln, x, y, FALSE, NULL, NULL) > c || vertex_degree(w, h, state->soln, x, y, TRUE, NULL, NULL) > 4-c) { state->errors[y*W+x] |= ERR_VERTEX; err = TRUE; } } /* * Now our actual victory condition is that (a) none of the * above code marked anything as erroneous, and (b) every * square has an edge in it. */ if (err) return FALSE; for (y = 0; y < h; y++) for (x = 0; x < w; x++) if (state->soln[y*w+x] == 0) return FALSE; return TRUE; } static char *solve_game(const game_state *state, const game_state *currstate, const char *aux, char **error) { int w = state->p.w, h = state->p.h; signed char *soln; int bs, ret; int free_soln = FALSE; char *move, buf[80]; int movelen, movesize; int x, y; if (aux) { /* * If we already have the solution, save ourselves some * time. */ soln = (signed char *)aux; bs = (signed char)'\\'; free_soln = FALSE; } else { struct solver_scratch *sc = new_scratch(w, h); soln = snewn(w*h, signed char); bs = -1; ret = slant_solve(w, h, state->clues->clues, soln, sc, DIFF_HARD); free_scratch(sc); if (ret != 1) { sfree(soln); if (ret == 0) *error = "This puzzle is not self-consistent"; else *error = "Unable to find a unique solution for this puzzle"; return NULL; } free_soln = TRUE; } /* * Construct a move string which turns the current state into * the solved state. */ movesize = 256; move = snewn(movesize, char); movelen = 0; move[movelen++] = 'S'; move[movelen] = '\0'; for (y = 0; y < h; y++) for (x = 0; x < w; x++) { int v = (soln[y*w+x] == bs ? -1 : +1); if (state->soln[y*w+x] != v) { int len = sprintf(buf, ";%c%d,%d", (int)(v < 0 ? '\\' : '/'), x, y); if (movelen + len >= movesize) { movesize = movelen + len + 256; move = sresize(move, movesize, char); } strcpy(move + movelen, buf); movelen += len; } } if (free_soln) sfree(soln); return move; } static int game_can_format_as_text_now(const game_params *params) { return TRUE; } static char *game_text_format(const game_state *state) { int w = state->p.w, h = state->p.h, W = w+1, H = h+1; int x, y, len; char *ret, *p; /* * There are h+H rows of w+W columns. */ len = (h+H) * (w+W+1) + 1; ret = snewn(len, char); p = ret; for (y = 0; y < H; y++) { for (x = 0; x < W; x++) { if (state->clues->clues[y*W+x] >= 0) *p++ = state->clues->clues[y*W+x] + '0'; else *p++ = '+'; if (x < w) *p++ = '-'; } *p++ = '\n'; if (y < h) { for (x = 0; x < W; x++) { *p++ = '|'; if (x < w) { if (state->soln[y*w+x] != 0) *p++ = (state->soln[y*w+x] < 0 ? '\\' : '/'); else *p++ = ' '; } } *p++ = '\n'; } } *p++ = '\0'; assert(p - ret == len); return ret; } struct game_ui { int cur_x, cur_y, cur_visible; }; static game_ui *new_ui(const game_state *state) { game_ui *ui = snew(game_ui); ui->cur_x = ui->cur_y = ui->cur_visible = 0; return ui; } static void free_ui(game_ui *ui) { sfree(ui); } static char *encode_ui(const game_ui *ui) { return NULL; } static void decode_ui(game_ui *ui, const char *encoding) { } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { } #define PREFERRED_TILESIZE 32 #define TILESIZE (ds->tilesize) #define BORDER TILESIZE #define CLUE_RADIUS (TILESIZE / 3) #define CLUE_TEXTSIZE (TILESIZE / 2) #define COORD(x) ( (x) * TILESIZE + BORDER ) #define FROMCOORD(x) ( ((x) - BORDER + TILESIZE) / TILESIZE - 1 ) #define FLASH_TIME 0.30F /* * Bit fields in the `grid' and `todraw' elements of the drawstate. */ #define BACKSLASH 0x00000001L #define FORWSLASH 0x00000002L #define L_T 0x00000004L #define ERR_L_T 0x00000008L #define L_B 0x00000010L #define ERR_L_B 0x00000020L #define T_L 0x00000040L #define ERR_T_L 0x00000080L #define T_R 0x00000100L #define ERR_T_R 0x00000200L #define C_TL 0x00000400L #define ERR_C_TL 0x00000800L #define FLASH 0x00001000L #define ERRSLASH 0x00002000L #define ERR_TL 0x00004000L #define ERR_TR 0x00008000L #define ERR_BL 0x00010000L #define ERR_BR 0x00020000L #define CURSOR 0x00040000L struct game_drawstate { int tilesize; int started; long *grid; long *todraw; }; static char *interpret_move(const game_state *state, game_ui *ui, const game_drawstate *ds, int x, int y, int button) { int w = state->p.w, h = state->p.h; int v; char buf[80]; enum { CLOCKWISE, ANTICLOCKWISE, NONE } action = NONE; if (button == LEFT_BUTTON || button == RIGHT_BUTTON) { /* * This is an utterly awful hack which I should really sort out * by means of a proper configuration mechanism. One Slant * player has observed that they prefer the mouse buttons to * function exactly the opposite way round, so here's a * mechanism for environment-based configuration. I cache the * result in a global variable - yuck! - to avoid repeated * lookups. */ { static int swap_buttons = -1; if (swap_buttons < 0) { char *env = getenv("SLANT_SWAP_BUTTONS"); swap_buttons = (env && (env[0] == 'y' || env[0] == 'Y')); } if (swap_buttons) { if (button == LEFT_BUTTON) button = RIGHT_BUTTON; else button = LEFT_BUTTON; } } action = (button == LEFT_BUTTON) ? CLOCKWISE : ANTICLOCKWISE; x = FROMCOORD(x); y = FROMCOORD(y); if (x < 0 || y < 0 || x >= w || y >= h) return NULL; ui->cur_visible = 0; } else if (IS_CURSOR_SELECT(button)) { if (!ui->cur_visible) { ui->cur_visible = 1; return ""; } x = ui->cur_x; y = ui->cur_y; action = (button == CURSOR_SELECT2) ? ANTICLOCKWISE : CLOCKWISE; } else if (IS_CURSOR_MOVE(button)) { move_cursor(button, &ui->cur_x, &ui->cur_y, w, h, 0); ui->cur_visible = 1; return ""; } else if (button == '\\' || button == '\b' || button == '/') { int x = ui->cur_x, y = ui->cur_y; if (button == ("\\" "\b" "/")[state->soln[y*w + x] + 1]) return NULL; sprintf(buf, "%c%d,%d", button == '\b' ? 'C' : button, x, y); return dupstr(buf); } if (action != NONE) { if (action == CLOCKWISE) { /* * Left-clicking cycles blank -> \ -> / -> blank. */ v = state->soln[y*w+x] - 1; if (v == -2) v = +1; } else { /* * Right-clicking cycles blank -> / -> \ -> blank. */ v = state->soln[y*w+x] + 1; if (v == +2) v = -1; } sprintf(buf, "%c%d,%d", (int)(v==-1 ? '\\' : v==+1 ? '/' : 'C'), x, y); return dupstr(buf); } return NULL; } static game_state *execute_move(const game_state *state, const char *move) { int w = state->p.w, h = state->p.h; char c; int x, y, n; game_state *ret = dup_game(state); while (*move) { c = *move; if (c == 'S') { ret->used_solve = TRUE; move++; } else if (c == '\\' || c == '/' || c == 'C') { move++; if (sscanf(move, "%d,%d%n", &x, &y, &n) != 2 || x < 0 || y < 0 || x >= w || y >= h) { free_game(ret); return NULL; } ret->soln[y*w+x] = (c == '\\' ? -1 : c == '/' ? +1 : 0); move += n; } else { free_game(ret); return NULL; } if (*move == ';') move++; else if (*move) { free_game(ret); return NULL; } } /* * We never clear the `completed' flag, but we must always * re-run the completion check because it also highlights * errors in the grid. */ ret->completed = check_completion(ret) || ret->completed; return ret; } /* ---------------------------------------------------------------------- * Drawing routines. */ static void game_compute_size(const game_params *params, int tilesize, int *x, int *y) { /* fool the macros */ struct dummy { int tilesize; } dummy, *ds = &dummy; dummy.tilesize = tilesize; *x = 2 * BORDER + params->w * TILESIZE + 1; *y = 2 * BORDER + params->h * TILESIZE + 1; } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { ds->tilesize = tilesize; } static float *game_colours(frontend *fe, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float); /* CURSOR colour is a background highlight. */ game_mkhighlight(fe, ret, COL_BACKGROUND, COL_CURSOR, -1); ret[COL_FILLEDSQUARE * 3 + 0] = ret[COL_BACKGROUND * 3 + 0]; ret[COL_FILLEDSQUARE * 3 + 1] = ret[COL_BACKGROUND * 3 + 1]; ret[COL_FILLEDSQUARE * 3 + 2] = ret[COL_BACKGROUND * 3 + 2]; ret[COL_GRID * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] * 0.7F; ret[COL_GRID * 3 + 1] = ret[COL_BACKGROUND * 3 + 1] * 0.7F; ret[COL_GRID * 3 + 2] = ret[COL_BACKGROUND * 3 + 2] * 0.7F; ret[COL_INK * 3 + 0] = 0.0F; ret[COL_INK * 3 + 1] = 0.0F; ret[COL_INK * 3 + 2] = 0.0F; ret[COL_SLANT1 * 3 + 0] = 0.0F; ret[COL_SLANT1 * 3 + 1] = 0.0F; ret[COL_SLANT1 * 3 + 2] = 0.0F; ret[COL_SLANT2 * 3 + 0] = 0.0F; ret[COL_SLANT2 * 3 + 1] = 0.0F; ret[COL_SLANT2 * 3 + 2] = 0.0F; ret[COL_ERROR * 3 + 0] = 1.0F; ret[COL_ERROR * 3 + 1] = 0.0F; ret[COL_ERROR * 3 + 2] = 0.0F; *ncolours = NCOLOURS; return ret; } static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { int w = state->p.w, h = state->p.h; int i; struct game_drawstate *ds = snew(struct game_drawstate); ds->tilesize = 0; ds->started = FALSE; ds->grid = snewn((w+2)*(h+2), long); ds->todraw = snewn((w+2)*(h+2), long); for (i = 0; i < (w+2)*(h+2); i++) ds->grid[i] = ds->todraw[i] = -1; return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { sfree(ds->todraw); sfree(ds->grid); sfree(ds); } static void draw_clue(drawing *dr, game_drawstate *ds, int x, int y, long v, long err, int bg, int colour) { char p[2]; int ccol = colour >= 0 ? colour : ((x ^ y) & 1) ? COL_SLANT1 : COL_SLANT2; int tcol = colour >= 0 ? colour : err ? COL_ERROR : COL_INK; if (v < 0) return; p[0] = (char)v + '0'; p[1] = '\0'; draw_circle(dr, COORD(x), COORD(y), CLUE_RADIUS, bg >= 0 ? bg : COL_BACKGROUND, ccol); draw_text(dr, COORD(x), COORD(y), FONT_VARIABLE, CLUE_TEXTSIZE, ALIGN_VCENTRE|ALIGN_HCENTRE, tcol, p); } static void draw_tile(drawing *dr, game_drawstate *ds, game_clues *clues, int x, int y, long v) { int w = clues->w, h = clues->h, W = w+1 /*, H = h+1 */; int chesscolour = (x ^ y) & 1; int fscol = chesscolour ? COL_SLANT2 : COL_SLANT1; int bscol = chesscolour ? COL_SLANT1 : COL_SLANT2; clip(dr, COORD(x), COORD(y), TILESIZE, TILESIZE); draw_rect(dr, COORD(x), COORD(y), TILESIZE, TILESIZE, (v & FLASH) ? COL_GRID : (v & CURSOR) ? COL_CURSOR : (v & (BACKSLASH | FORWSLASH)) ? COL_FILLEDSQUARE : COL_BACKGROUND); /* * Draw the grid lines. */ if (x >= 0 && x < w && y >= 0) draw_rect(dr, COORD(x), COORD(y), TILESIZE+1, 1, COL_GRID); if (x >= 0 && x < w && y < h) draw_rect(dr, COORD(x), COORD(y+1), TILESIZE+1, 1, COL_GRID); if (y >= 0 && y < h && x >= 0) draw_rect(dr, COORD(x), COORD(y), 1, TILESIZE+1, COL_GRID); if (y >= 0 && y < h && x < w) draw_rect(dr, COORD(x+1), COORD(y), 1, TILESIZE+1, COL_GRID); if (x == -1 && y == -1) draw_rect(dr, COORD(x+1), COORD(y+1), 1, 1, COL_GRID); if (x == -1 && y == h) draw_rect(dr, COORD(x+1), COORD(y), 1, 1, COL_GRID); if (x == w && y == -1) draw_rect(dr, COORD(x), COORD(y+1), 1, 1, COL_GRID); if (x == w && y == h) draw_rect(dr, COORD(x), COORD(y), 1, 1, COL_GRID); /* * Draw the slash. */ if (v & BACKSLASH) { int scol = (v & ERRSLASH) ? COL_ERROR : bscol; draw_line(dr, COORD(x), COORD(y), COORD(x+1), COORD(y+1), scol); draw_line(dr, COORD(x)+1, COORD(y), COORD(x+1), COORD(y+1)-1, scol); draw_line(dr, COORD(x), COORD(y)+1, COORD(x+1)-1, COORD(y+1), scol); } else if (v & FORWSLASH) { int scol = (v & ERRSLASH) ? COL_ERROR : fscol; draw_line(dr, COORD(x+1), COORD(y), COORD(x), COORD(y+1), scol); draw_line(dr, COORD(x+1)-1, COORD(y), COORD(x), COORD(y+1)-1, scol); draw_line(dr, COORD(x+1), COORD(y)+1, COORD(x)+1, COORD(y+1), scol); } /* * Draw dots on the grid corners that appear if a slash is in a * neighbouring cell. */ if (v & (L_T | BACKSLASH)) draw_rect(dr, COORD(x), COORD(y)+1, 1, 1, (v & ERR_L_T ? COL_ERROR : bscol)); if (v & (L_B | FORWSLASH)) draw_rect(dr, COORD(x), COORD(y+1)-1, 1, 1, (v & ERR_L_B ? COL_ERROR : fscol)); if (v & (T_L | BACKSLASH)) draw_rect(dr, COORD(x)+1, COORD(y), 1, 1, (v & ERR_T_L ? COL_ERROR : bscol)); if (v & (T_R | FORWSLASH)) draw_rect(dr, COORD(x+1)-1, COORD(y), 1, 1, (v & ERR_T_R ? COL_ERROR : fscol)); if (v & (C_TL | BACKSLASH)) draw_rect(dr, COORD(x), COORD(y), 1, 1, (v & ERR_C_TL ? COL_ERROR : bscol)); /* * And finally the clues at the corners. */ if (x >= 0 && y >= 0) draw_clue(dr, ds, x, y, clues->clues[y*W+x], v & ERR_TL, -1, -1); if (x < w && y >= 0) draw_clue(dr, ds, x+1, y, clues->clues[y*W+(x+1)], v & ERR_TR, -1, -1); if (x >= 0 && y < h) draw_clue(dr, ds, x, y+1, clues->clues[(y+1)*W+x], v & ERR_BL, -1, -1); if (x < w && y < h) draw_clue(dr, ds, x+1, y+1, clues->clues[(y+1)*W+(x+1)], v & ERR_BR, -1, -1); unclip(dr); draw_update(dr, COORD(x), COORD(y), TILESIZE, TILESIZE); } static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float animtime, float flashtime) { int w = state->p.w, h = state->p.h, W = w+1, H = h+1; int x, y; int flashing; if (flashtime > 0) flashing = (int)(flashtime * 3 / FLASH_TIME) != 1; else flashing = FALSE; if (!ds->started) { int ww, wh; game_compute_size(&state->p, TILESIZE, &ww, &wh); draw_rect(dr, 0, 0, ww, wh, COL_BACKGROUND); draw_update(dr, 0, 0, ww, wh); ds->started = TRUE; } /* * Loop over the grid and work out where all the slashes are. * We need to do this because a slash in one square affects the * drawing of the next one along. */ for (y = -1; y <= h; y++) for (x = -1; x <= w; x++) { if (x >= 0 && x < w && y >= 0 && y < h) ds->todraw[(y+1)*(w+2)+(x+1)] = flashing ? FLASH : 0; else ds->todraw[(y+1)*(w+2)+(x+1)] = 0; } for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { int err = state->errors[y*W+x] & ERR_SQUARE; if (state->soln[y*w+x] < 0) { ds->todraw[(y+1)*(w+2)+(x+1)] |= BACKSLASH; ds->todraw[(y+2)*(w+2)+(x+1)] |= T_R; ds->todraw[(y+1)*(w+2)+(x+2)] |= L_B; ds->todraw[(y+2)*(w+2)+(x+2)] |= C_TL; if (err) { ds->todraw[(y+1)*(w+2)+(x+1)] |= ERRSLASH | ERR_T_L | ERR_L_T | ERR_C_TL; ds->todraw[(y+2)*(w+2)+(x+1)] |= ERR_T_R; ds->todraw[(y+1)*(w+2)+(x+2)] |= ERR_L_B; ds->todraw[(y+2)*(w+2)+(x+2)] |= ERR_C_TL; } } else if (state->soln[y*w+x] > 0) { ds->todraw[(y+1)*(w+2)+(x+1)] |= FORWSLASH; ds->todraw[(y+1)*(w+2)+(x+2)] |= L_T | C_TL; ds->todraw[(y+2)*(w+2)+(x+1)] |= T_L | C_TL; if (err) { ds->todraw[(y+1)*(w+2)+(x+1)] |= ERRSLASH | ERR_L_B | ERR_T_R; ds->todraw[(y+1)*(w+2)+(x+2)] |= ERR_L_T | ERR_C_TL; ds->todraw[(y+2)*(w+2)+(x+1)] |= ERR_T_L | ERR_C_TL; } } if (ui->cur_visible && ui->cur_x == x && ui->cur_y == y) ds->todraw[(y+1)*(w+2)+(x+1)] |= CURSOR; } } for (y = 0; y < H; y++) for (x = 0; x < W; x++) if (state->errors[y*W+x] & ERR_VERTEX) { ds->todraw[y*(w+2)+x] |= ERR_BR; ds->todraw[y*(w+2)+(x+1)] |= ERR_BL; ds->todraw[(y+1)*(w+2)+x] |= ERR_TR; ds->todraw[(y+1)*(w+2)+(x+1)] |= ERR_TL; } /* * Now go through and draw the grid squares. */ for (y = -1; y <= h; y++) { for (x = -1; x <= w; x++) { if (ds->todraw[(y+1)*(w+2)+(x+1)] != ds->grid[(y+1)*(w+2)+(x+1)]) { draw_tile(dr, ds, state->clues, x, y, ds->todraw[(y+1)*(w+2)+(x+1)]); ds->grid[(y+1)*(w+2)+(x+1)] = ds->todraw[(y+1)*(w+2)+(x+1)]; } } } } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return 0.0F; } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { if (!oldstate->completed && newstate->completed && !oldstate->used_solve && !newstate->used_solve) return FLASH_TIME; return 0.0F; } static int game_status(const game_state *state) { return state->completed ? +1 : 0; } static int game_timing_state(const game_state *state, game_ui *ui) { return TRUE; } static void game_print_size(const game_params *params, float *x, float *y) { int pw, ph; /* * I'll use 6mm squares by default. */ game_compute_size(params, 600, &pw, &ph); *x = pw / 100.0F; *y = ph / 100.0F; } static void game_print(drawing *dr, const game_state *state, int tilesize) { int w = state->p.w, h = state->p.h, W = w+1; int ink = print_mono_colour(dr, 0); int paper = print_mono_colour(dr, 1); int x, y; /* Ick: fake up `ds->tilesize' for macro expansion purposes */ game_drawstate ads, *ds = &ads; game_set_size(dr, ds, NULL, tilesize); /* * Border. */ print_line_width(dr, TILESIZE / 16); draw_rect_outline(dr, COORD(0), COORD(0), w*TILESIZE, h*TILESIZE, ink); /* * Grid. */ print_line_width(dr, TILESIZE / 24); for (x = 1; x < w; x++) draw_line(dr, COORD(x), COORD(0), COORD(x), COORD(h), ink); for (y = 1; y < h; y++) draw_line(dr, COORD(0), COORD(y), COORD(w), COORD(y), ink); /* * Solution. */ print_line_width(dr, TILESIZE / 12); for (y = 0; y < h; y++) for (x = 0; x < w; x++) if (state->soln[y*w+x]) { int ly, ry; /* * To prevent nasty line-ending artefacts at * corners, I'll do something slightly cunning * here. */ clip(dr, COORD(x), COORD(y), TILESIZE, TILESIZE); if (state->soln[y*w+x] < 0) ly = y-1, ry = y+2; else ry = y-1, ly = y+2; draw_line(dr, COORD(x-1), COORD(ly), COORD(x+2), COORD(ry), ink); unclip(dr); } /* * Clues. */ print_line_width(dr, TILESIZE / 24); for (y = 0; y <= h; y++) for (x = 0; x <= w; x++) draw_clue(dr, ds, x, y, state->clues->clues[y*W+x], FALSE, paper, ink); } #ifdef COMBINED #define thegame slant #endif const struct game thegame = { "Slant", "games.slant", "slant", default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, TRUE, solve_game, TRUE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, PREFERRED_TILESIZE, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, TRUE, FALSE, game_print_size, game_print, FALSE, /* wants_statusbar */ FALSE, game_timing_state, 0, /* flags */ }; #ifdef STANDALONE_SOLVER #include int main(int argc, char **argv) { game_params *p; game_state *s; char *id = NULL, *desc, *err; int grade = FALSE; int ret, diff, really_verbose = FALSE; struct solver_scratch *sc; while (--argc > 0) { char *p = *++argv; if (!strcmp(p, "-v")) { really_verbose = TRUE; } else if (!strcmp(p, "-g")) { grade = TRUE; } else if (*p == '-') { fprintf(stderr, "%s: unrecognised option `%s'\n", argv[0], p); return 1; } else { id = p; } } if (!id) { fprintf(stderr, "usage: %s [-g | -v] \n", argv[0]); return 1; } desc = strchr(id, ':'); if (!desc) { fprintf(stderr, "%s: game id expects a colon in it\n", argv[0]); return 1; } *desc++ = '\0'; p = default_params(); decode_params(p, id); err = validate_desc(p, desc); if (err) { fprintf(stderr, "%s: %s\n", argv[0], err); return 1; } s = new_game(NULL, p, desc); sc = new_scratch(p->w, p->h); /* * When solving an Easy puzzle, we don't want to bother the * user with Hard-level deductions. For this reason, we grade * the puzzle internally before doing anything else. */ ret = -1; /* placate optimiser */ for (diff = 0; diff < DIFFCOUNT; diff++) { ret = slant_solve(p->w, p->h, s->clues->clues, s->soln, sc, diff); if (ret < 2) break; } if (diff == DIFFCOUNT) { if (grade) printf("Difficulty rating: harder than Hard, or ambiguous\n"); else printf("Unable to find a unique solution\n"); } else { if (grade) { if (ret == 0) printf("Difficulty rating: impossible (no solution exists)\n"); else if (ret == 1) printf("Difficulty rating: %s\n", slant_diffnames[diff]); } else { verbose = really_verbose; ret = slant_solve(p->w, p->h, s->clues->clues, s->soln, sc, diff); if (ret == 0) printf("Puzzle is inconsistent\n"); else fputs(game_text_format(s), stdout); } } return 0; } #endif /* vim: set shiftwidth=4 tabstop=8: */ puzzles-20170606.272beef/sixteen.c0000644000175000017500000007401713115373615015525 0ustar simonsimon/* * sixteen.c: `16-puzzle', a sliding-tiles jigsaw which differs * from the 15-puzzle in that you toroidally rotate a row or column * at a time. */ #include #include #include #include #include #include #include "puzzles.h" #define PREFERRED_TILE_SIZE 48 #define TILE_SIZE (ds->tilesize) #define BORDER TILE_SIZE #define HIGHLIGHT_WIDTH (TILE_SIZE / 20) #define COORD(x) ( (x) * TILE_SIZE + BORDER ) #define FROMCOORD(x) ( ((x) - BORDER + 2*TILE_SIZE) / TILE_SIZE - 2 ) #define ANIM_TIME 0.13F #define FLASH_FRAME 0.13F #define X(state, i) ( (i) % (state)->w ) #define Y(state, i) ( (i) / (state)->w ) #define C(state, x, y) ( (y) * (state)->w + (x) ) #define TILE_CURSOR(i, state, x, y) ((i) == C((state), (x), (y)) && \ 0 <= (x) && (x) < (state)->w && \ 0 <= (y) && (y) < (state)->h) enum { COL_BACKGROUND, COL_TEXT, COL_HIGHLIGHT, COL_LOWLIGHT, NCOLOURS }; struct game_params { int w, h; int movetarget; }; struct game_state { int w, h, n; int *tiles; int completed; int used_solve; /* used to suppress completion flash */ int movecount, movetarget; int last_movement_sense; }; static game_params *default_params(void) { game_params *ret = snew(game_params); ret->w = ret->h = 4; ret->movetarget = 0; return ret; } static int game_fetch_preset(int i, char **name, game_params **params) { game_params *ret; int w, h; char buf[80]; switch (i) { case 0: w = 3, h = 3; break; case 1: w = 4, h = 3; break; case 2: w = 4, h = 4; break; case 3: w = 5, h = 4; break; case 4: w = 5, h = 5; break; default: return FALSE; } sprintf(buf, "%dx%d", w, h); *name = dupstr(buf); *params = ret = snew(game_params); ret->w = w; ret->h = h; ret->movetarget = 0; return TRUE; } static void free_params(game_params *params) { sfree(params); } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } static void decode_params(game_params *ret, char const *string) { ret->w = ret->h = atoi(string); ret->movetarget = 0; while (*string && isdigit((unsigned char)*string)) string++; if (*string == 'x') { string++; ret->h = atoi(string); while (*string && isdigit((unsigned char)*string)) string++; } if (*string == 'm') { string++; ret->movetarget = atoi(string); while (*string && isdigit((unsigned char)*string)) string++; } } static char *encode_params(const game_params *params, int full) { char data[256]; sprintf(data, "%dx%d", params->w, params->h); /* Shuffle limit is part of the limited parameters, because we have to * supply the target move count. */ if (params->movetarget) sprintf(data + strlen(data), "m%d", params->movetarget); return dupstr(data); } static config_item *game_configure(const game_params *params) { config_item *ret; char buf[80]; ret = snewn(4, config_item); ret[0].name = "Width"; ret[0].type = C_STRING; sprintf(buf, "%d", params->w); ret[0].sval = dupstr(buf); ret[0].ival = 0; ret[1].name = "Height"; ret[1].type = C_STRING; sprintf(buf, "%d", params->h); ret[1].sval = dupstr(buf); ret[1].ival = 0; ret[2].name = "Number of shuffling moves"; ret[2].type = C_STRING; sprintf(buf, "%d", params->movetarget); ret[2].sval = dupstr(buf); ret[2].ival = 0; ret[3].name = NULL; ret[3].type = C_END; ret[3].sval = NULL; ret[3].ival = 0; return ret; } static game_params *custom_params(const config_item *cfg) { game_params *ret = snew(game_params); ret->w = atoi(cfg[0].sval); ret->h = atoi(cfg[1].sval); ret->movetarget = atoi(cfg[2].sval); return ret; } static char *validate_params(const game_params *params, int full) { if (params->w < 2 || params->h < 2) return "Width and height must both be at least two"; return NULL; } static int perm_parity(int *perm, int n) { int i, j, ret; ret = 0; for (i = 0; i < n-1; i++) for (j = i+1; j < n; j++) if (perm[i] > perm[j]) ret = !ret; return ret; } static char *new_game_desc(const game_params *params, random_state *rs, char **aux, int interactive) { int stop, n, i, x; int x1, x2, p1, p2; int *tiles, *used; char *ret; int retlen; n = params->w * params->h; tiles = snewn(n, int); if (params->movetarget) { int prevoffset = -1; int max = (params->w > params->h ? params->w : params->h); int *prevmoves = snewn(max, int); /* * Shuffle the old-fashioned way, by making a series of * single moves on the grid. */ for (i = 0; i < n; i++) tiles[i] = i; for (i = 0; i < params->movetarget; i++) { int start, offset, len, direction, index; int j, tmp; /* * Choose a move to make. We can choose from any row * or any column. */ while (1) { j = random_upto(rs, params->w + params->h); if (j < params->w) { /* Column. */ index = j; start = j; offset = params->w; len = params->h; } else { /* Row. */ index = j - params->w; start = index * params->w; offset = 1; len = params->w; } direction = -1 + 2 * random_upto(rs, 2); /* * To at least _try_ to avoid boring cases, check * that this move doesn't directly undo a previous * one, or repeat it so many times as to turn it * into fewer moves in the opposite direction. (For * example, in a row of length 4, we're allowed to * move it the same way twice, but not three * times.) * * We track this for each individual row/column, * and clear all the counters as soon as a * perpendicular move is made. This isn't perfect * (it _can't_ guaranteeably be perfect - there * will always come a move count beyond which a * shorter solution will be possible than the one * which constructed the position) but it should * sort out all the obvious cases. */ if (offset == prevoffset) { tmp = prevmoves[index] + direction; if (abs(2*tmp) > len || abs(tmp) < abs(prevmoves[index])) continue; } /* If we didn't `continue', we've found an OK move to make. */ if (offset != prevoffset) { int i; for (i = 0; i < max; i++) prevmoves[i] = 0; prevoffset = offset; } prevmoves[index] += direction; break; } /* * Make the move. */ if (direction < 0) { start += (len-1) * offset; offset = -offset; } tmp = tiles[start]; for (j = 0; j+1 < len; j++) tiles[start + j*offset] = tiles[start + (j+1)*offset]; tiles[start + (len-1) * offset] = tmp; } sfree(prevmoves); } else { used = snewn(n, int); for (i = 0; i < n; i++) { tiles[i] = -1; used[i] = FALSE; } /* * If both dimensions are odd, there is a parity * constraint. */ if (params->w & params->h & 1) stop = 2; else stop = 0; /* * Place everything except (possibly) the last two tiles. */ for (x = 0, i = n; i > stop; i--) { int k = i > 1 ? random_upto(rs, i) : 0; int j; for (j = 0; j < n; j++) if (!used[j] && (k-- == 0)) break; assert(j < n && !used[j]); used[j] = TRUE; while (tiles[x] >= 0) x++; assert(x < n); tiles[x] = j; } if (stop) { /* * Find the last two locations, and the last two * pieces. */ while (tiles[x] >= 0) x++; assert(x < n); x1 = x; x++; while (tiles[x] >= 0) x++; assert(x < n); x2 = x; for (i = 0; i < n; i++) if (!used[i]) break; p1 = i; for (i = p1+1; i < n; i++) if (!used[i]) break; p2 = i; /* * Try the last two tiles one way round. If that fails, * swap them. */ tiles[x1] = p1; tiles[x2] = p2; if (perm_parity(tiles, n) != 0) { tiles[x1] = p2; tiles[x2] = p1; assert(perm_parity(tiles, n) == 0); } } sfree(used); } /* * Now construct the game description, by describing the tile * array as a simple sequence of comma-separated integers. */ ret = NULL; retlen = 0; for (i = 0; i < n; i++) { char buf[80]; int k; k = sprintf(buf, "%d,", tiles[i]+1); ret = sresize(ret, retlen + k + 1, char); strcpy(ret + retlen, buf); retlen += k; } ret[retlen-1] = '\0'; /* delete last comma */ sfree(tiles); return ret; } static char *validate_desc(const game_params *params, const char *desc) { const char *p; char *err; int i, area; int *used; area = params->w * params->h; p = desc; err = NULL; used = snewn(area, int); for (i = 0; i < area; i++) used[i] = FALSE; for (i = 0; i < area; i++) { const char *q = p; int n; if (*p < '0' || *p > '9') { err = "Not enough numbers in string"; goto leave; } while (*p >= '0' && *p <= '9') p++; if (i < area-1 && *p != ',') { err = "Expected comma after number"; goto leave; } else if (i == area-1 && *p) { err = "Excess junk at end of string"; goto leave; } n = atoi(q); if (n < 1 || n > area) { err = "Number out of range"; goto leave; } if (used[n-1]) { err = "Number used twice"; goto leave; } used[n-1] = TRUE; if (*p) p++; /* eat comma */ } leave: sfree(used); return err; } static game_state *new_game(midend *me, const game_params *params, const char *desc) { game_state *state = snew(game_state); int i; const char *p; state->w = params->w; state->h = params->h; state->n = params->w * params->h; state->tiles = snewn(state->n, int); p = desc; i = 0; for (i = 0; i < state->n; i++) { assert(*p); state->tiles[i] = atoi(p); while (*p && *p != ',') p++; if (*p) p++; /* eat comma */ } assert(!*p); state->completed = state->movecount = 0; state->movetarget = params->movetarget; state->used_solve = FALSE; state->last_movement_sense = 0; return state; } static game_state *dup_game(const game_state *state) { game_state *ret = snew(game_state); ret->w = state->w; ret->h = state->h; ret->n = state->n; ret->tiles = snewn(state->w * state->h, int); memcpy(ret->tiles, state->tiles, state->w * state->h * sizeof(int)); ret->completed = state->completed; ret->movecount = state->movecount; ret->movetarget = state->movetarget; ret->used_solve = state->used_solve; ret->last_movement_sense = state->last_movement_sense; return ret; } static void free_game(game_state *state) { sfree(state->tiles); sfree(state); } static char *solve_game(const game_state *state, const game_state *currstate, const char *aux, char **error) { return dupstr("S"); } static int game_can_format_as_text_now(const game_params *params) { return TRUE; } static char *game_text_format(const game_state *state) { char *ret, *p, buf[80]; int x, y, col, maxlen; /* * First work out how many characters we need to display each * number. */ col = sprintf(buf, "%d", state->n); /* * Now we know the exact total size of the grid we're going to * produce: it's got h rows, each containing w lots of col, w-1 * spaces and a trailing newline. */ maxlen = state->h * state->w * (col+1); ret = snewn(maxlen+1, char); p = ret; for (y = 0; y < state->h; y++) { for (x = 0; x < state->w; x++) { int v = state->tiles[state->w*y+x]; sprintf(buf, "%*d", col, v); memcpy(p, buf, col); p += col; if (x+1 == state->w) *p++ = '\n'; else *p++ = ' '; } } assert(p - ret == maxlen); *p = '\0'; return ret; } enum cursor_mode { unlocked, lock_tile, lock_position }; struct game_ui { int cur_x, cur_y; int cur_visible; enum cursor_mode cur_mode; }; static game_ui *new_ui(const game_state *state) { game_ui *ui = snew(game_ui); ui->cur_x = 0; ui->cur_y = 0; ui->cur_visible = FALSE; ui->cur_mode = unlocked; return ui; } static void free_ui(game_ui *ui) { sfree(ui); } static char *encode_ui(const game_ui *ui) { return NULL; } static void decode_ui(game_ui *ui, const char *encoding) { } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { } struct game_drawstate { int started; int w, h, bgcolour; int *tiles; int tilesize; int cur_x, cur_y; }; static char *interpret_move(const game_state *state, game_ui *ui, const game_drawstate *ds, int x, int y, int button) { int cx = -1, cy = -1, dx, dy; char buf[80]; int shift = button & MOD_SHFT, control = button & MOD_CTRL, pad = button & MOD_NUM_KEYPAD; button &= ~MOD_MASK; if (IS_CURSOR_MOVE(button) || pad) { if (!ui->cur_visible) { ui->cur_visible = 1; return ""; } if (control || shift || ui->cur_mode) { int x = ui->cur_x, y = ui->cur_y, xwrap = x, ywrap = y; if (x < 0 || x >= state->w || y < 0 || y >= state->h) return NULL; move_cursor(button | pad, &x, &y, state->w, state->h, FALSE); move_cursor(button | pad, &xwrap, &ywrap, state->w, state->h, TRUE); if (x != xwrap) { sprintf(buf, "R%d,%c1", y, x ? '+' : '-'); } else if (y != ywrap) { sprintf(buf, "C%d,%c1", x, y ? '+' : '-'); } else if (x == ui->cur_x) sprintf(buf, "C%d,%d", x, y - ui->cur_y); else sprintf(buf, "R%d,%d", y, x - ui->cur_x); if (control || (!shift && ui->cur_mode == lock_tile)) { ui->cur_x = xwrap; ui->cur_y = ywrap; } return dupstr(buf); } else { int x = ui->cur_x + 1, y = ui->cur_y + 1; move_cursor(button | pad, &x, &y, state->w + 2, state->h + 2, FALSE); if (x == 0 && y == 0) { int t = ui->cur_x; ui->cur_x = ui->cur_y; ui->cur_y = t; } else if (x == 0 && y == state->h + 1) { int t = ui->cur_x; ui->cur_x = (state->h - 1) - ui->cur_y; ui->cur_y = (state->h - 1) - t; } else if (x == state->w + 1 && y == 0) { int t = ui->cur_x; ui->cur_x = (state->w - 1) - ui->cur_y; ui->cur_y = (state->w - 1) - t; } else if (x == state->w + 1 && y == state->h + 1) { int t = ui->cur_x; ui->cur_x = state->w - state->h + ui->cur_y; ui->cur_y = state->h - state->w + t; } else { ui->cur_x = x - 1; ui->cur_y = y - 1; } ui->cur_visible = 1; return ""; } } if (button == LEFT_BUTTON || button == RIGHT_BUTTON) { cx = FROMCOORD(x); cy = FROMCOORD(y); ui->cur_visible = 0; } else if (IS_CURSOR_SELECT(button)) { if (ui->cur_visible) { if (ui->cur_x == -1 || ui->cur_x == state->w || ui->cur_y == -1 || ui->cur_y == state->h) { cx = ui->cur_x; cy = ui->cur_y; } else { const enum cursor_mode m = (button == CURSOR_SELECT2 ? lock_position : lock_tile); ui->cur_mode = (ui->cur_mode == m ? unlocked : m); return ""; } } else { ui->cur_visible = 1; return ""; } } else { return NULL; } if (cx == -1 && cy >= 0 && cy < state->h) dx = -1, dy = 0; else if (cx == state->w && cy >= 0 && cy < state->h) dx = +1, dy = 0; else if (cy == -1 && cx >= 0 && cx < state->w) dy = -1, dx = 0; else if (cy == state->h && cx >= 0 && cx < state->w) dy = +1, dx = 0; else return ""; /* invalid click location */ /* reverse direction if right hand button is pressed */ if (button == RIGHT_BUTTON || button == CURSOR_SELECT2) { dx = -dx; dy = -dy; } if (dx) sprintf(buf, "R%d,%d", cy, dx); else sprintf(buf, "C%d,%d", cx, dy); return dupstr(buf); } static game_state *execute_move(const game_state *from, const char *move) { int cx, cy, dx, dy; int tx, ty, n; game_state *ret; if (!strcmp(move, "S")) { int i; ret = dup_game(from); /* * Simply replace the grid with a solved one. For this game, * this isn't a useful operation for actually telling the user * what they should have done, but it is useful for * conveniently being able to get hold of a clean state from * which to practise manoeuvres. */ for (i = 0; i < ret->n; i++) ret->tiles[i] = i+1; ret->used_solve = TRUE; ret->completed = ret->movecount = 1; return ret; } if (move[0] == 'R' && sscanf(move+1, "%d,%d", &cy, &dx) == 2 && cy >= 0 && cy < from->h) { cx = dy = 0; n = from->w; } else if (move[0] == 'C' && sscanf(move+1, "%d,%d", &cx, &dy) == 2 && cx >= 0 && cx < from->w) { cy = dx = 0; n = from->h; } else return NULL; ret = dup_game(from); do { tx = (cx - dx + from->w) % from->w; ty = (cy - dy + from->h) % from->h; ret->tiles[C(ret, cx, cy)] = from->tiles[C(from, tx, ty)]; cx = tx; cy = ty; } while (--n > 0); ret->movecount++; ret->last_movement_sense = dx+dy; /* * See if the game has been completed. */ if (!ret->completed) { ret->completed = ret->movecount; for (n = 0; n < ret->n; n++) if (ret->tiles[n] != n+1) ret->completed = FALSE; } return ret; } /* ---------------------------------------------------------------------- * Drawing routines. */ static void game_compute_size(const game_params *params, int tilesize, int *x, int *y) { /* Ick: fake up `ds->tilesize' for macro expansion purposes */ struct { int tilesize; } ads, *ds = &ads; ads.tilesize = tilesize; *x = TILE_SIZE * params->w + 2 * BORDER; *y = TILE_SIZE * params->h + 2 * BORDER; } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { ds->tilesize = tilesize; } static float *game_colours(frontend *fe, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float); int i; game_mkhighlight(fe, ret, COL_BACKGROUND, COL_HIGHLIGHT, COL_LOWLIGHT); for (i = 0; i < 3; i++) ret[COL_TEXT * 3 + i] = 0.0; *ncolours = NCOLOURS; return ret; } static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { struct game_drawstate *ds = snew(struct game_drawstate); int i; ds->started = FALSE; ds->w = state->w; ds->h = state->h; ds->bgcolour = COL_BACKGROUND; ds->tiles = snewn(ds->w*ds->h, int); ds->tilesize = 0; /* haven't decided yet */ for (i = 0; i < ds->w*ds->h; i++) ds->tiles[i] = -1; ds->cur_x = ds->cur_y = -1; return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { sfree(ds->tiles); sfree(ds); } static void draw_tile(drawing *dr, game_drawstate *ds, const game_state *state, int x, int y, int tile, int flash_colour) { if (tile == 0) { draw_rect(dr, x, y, TILE_SIZE, TILE_SIZE, flash_colour); } else { int coords[6]; char str[40]; coords[0] = x + TILE_SIZE - 1; coords[1] = y + TILE_SIZE - 1; coords[2] = x + TILE_SIZE - 1; coords[3] = y; coords[4] = x; coords[5] = y + TILE_SIZE - 1; draw_polygon(dr, coords, 3, COL_LOWLIGHT, COL_LOWLIGHT); coords[0] = x; coords[1] = y; draw_polygon(dr, coords, 3, COL_HIGHLIGHT, COL_HIGHLIGHT); draw_rect(dr, x + HIGHLIGHT_WIDTH, y + HIGHLIGHT_WIDTH, TILE_SIZE - 2*HIGHLIGHT_WIDTH, TILE_SIZE - 2*HIGHLIGHT_WIDTH, flash_colour); sprintf(str, "%d", tile); draw_text(dr, x + TILE_SIZE/2, y + TILE_SIZE/2, FONT_VARIABLE, TILE_SIZE/3, ALIGN_VCENTRE | ALIGN_HCENTRE, COL_TEXT, str); } draw_update(dr, x, y, TILE_SIZE, TILE_SIZE); } static void draw_arrow(drawing *dr, game_drawstate *ds, int x, int y, int xdx, int xdy, int cur) { int coords[14]; int ydy = -xdx, ydx = xdy; #define POINT(n, xx, yy) ( \ coords[2*(n)+0] = x + (xx)*xdx + (yy)*ydx, \ coords[2*(n)+1] = y + (xx)*xdy + (yy)*ydy) POINT(0, TILE_SIZE / 2, 3 * TILE_SIZE / 4); /* top of arrow */ POINT(1, 3 * TILE_SIZE / 4, TILE_SIZE / 2); /* right corner */ POINT(2, 5 * TILE_SIZE / 8, TILE_SIZE / 2); /* right concave */ POINT(3, 5 * TILE_SIZE / 8, TILE_SIZE / 4); /* bottom right */ POINT(4, 3 * TILE_SIZE / 8, TILE_SIZE / 4); /* bottom left */ POINT(5, 3 * TILE_SIZE / 8, TILE_SIZE / 2); /* left concave */ POINT(6, TILE_SIZE / 4, TILE_SIZE / 2); /* left corner */ draw_polygon(dr, coords, 7, cur ? COL_HIGHLIGHT : COL_LOWLIGHT, COL_TEXT); } static void draw_arrow_for_cursor(drawing *dr, game_drawstate *ds, int cur_x, int cur_y, int cur) { if (cur_x == -1 && cur_y == -1) return; /* 'no cursur here */ else if (cur_x == -1) /* LH column. */ draw_arrow(dr, ds, COORD(0), COORD(cur_y+1), 0, -1, cur); else if (cur_x == ds->w) /* RH column */ draw_arrow(dr, ds, COORD(ds->w), COORD(cur_y), 0, +1, cur); else if (cur_y == -1) /* Top row */ draw_arrow(dr, ds, COORD(cur_x), COORD(0), +1, 0, cur); else if (cur_y == ds->h) /* Bottom row */ draw_arrow(dr, ds, COORD(cur_x+1), COORD(ds->h), -1, 0, cur); else return; draw_update(dr, COORD(cur_x), COORD(cur_y), TILE_SIZE, TILE_SIZE); } static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float animtime, float flashtime) { int i, bgcolour; int cur_x = -1, cur_y = -1; if (flashtime > 0) { int frame = (int)(flashtime / FLASH_FRAME); bgcolour = (frame % 2 ? COL_LOWLIGHT : COL_HIGHLIGHT); } else bgcolour = COL_BACKGROUND; if (!ds->started) { int coords[10]; draw_rect(dr, 0, 0, TILE_SIZE * state->w + 2 * BORDER, TILE_SIZE * state->h + 2 * BORDER, COL_BACKGROUND); draw_update(dr, 0, 0, TILE_SIZE * state->w + 2 * BORDER, TILE_SIZE * state->h + 2 * BORDER); /* * Recessed area containing the whole puzzle. */ coords[0] = COORD(state->w) + HIGHLIGHT_WIDTH - 1; coords[1] = COORD(state->h) + HIGHLIGHT_WIDTH - 1; coords[2] = COORD(state->w) + HIGHLIGHT_WIDTH - 1; coords[3] = COORD(0) - HIGHLIGHT_WIDTH; coords[4] = coords[2] - TILE_SIZE; coords[5] = coords[3] + TILE_SIZE; coords[8] = COORD(0) - HIGHLIGHT_WIDTH; coords[9] = COORD(state->h) + HIGHLIGHT_WIDTH - 1; coords[6] = coords[8] + TILE_SIZE; coords[7] = coords[9] - TILE_SIZE; draw_polygon(dr, coords, 5, COL_HIGHLIGHT, COL_HIGHLIGHT); coords[1] = COORD(0) - HIGHLIGHT_WIDTH; coords[0] = COORD(0) - HIGHLIGHT_WIDTH; draw_polygon(dr, coords, 5, COL_LOWLIGHT, COL_LOWLIGHT); /* * Arrows for making moves. */ for (i = 0; i < state->w; i++) { draw_arrow(dr, ds, COORD(i), COORD(0), +1, 0, 0); draw_arrow(dr, ds, COORD(i+1), COORD(state->h), -1, 0, 0); } for (i = 0; i < state->h; i++) { draw_arrow(dr, ds, COORD(state->w), COORD(i), 0, +1, 0); draw_arrow(dr, ds, COORD(0), COORD(i+1), 0, -1, 0); } ds->started = TRUE; } /* * Cursor (highlighted arrow around edge) */ if (ui->cur_visible) { cur_x = ui->cur_x; cur_y = ui->cur_y; } if (cur_x != ds->cur_x || cur_y != ds->cur_y) { /* Cursor has changed; redraw two (prev and curr) arrows. */ draw_arrow_for_cursor(dr, ds, cur_x, cur_y, 1); draw_arrow_for_cursor(dr, ds, ds->cur_x, ds->cur_y, 0); } /* * Now draw each tile. */ clip(dr, COORD(0), COORD(0), TILE_SIZE*state->w, TILE_SIZE*state->h); for (i = 0; i < state->n; i++) { int t, t0; /* * Figure out what should be displayed at this * location. It's either a simple tile, or it's a * transition between two tiles (in which case we say * -1 because it must always be drawn). */ if (oldstate && oldstate->tiles[i] != state->tiles[i]) t = -1; else t = state->tiles[i]; t0 = t; if (ds->bgcolour != bgcolour || /* always redraw when flashing */ ds->tiles[i] != t || ds->tiles[i] == -1 || t == -1 || ((ds->cur_x != cur_x || ds->cur_y != cur_y) && /* cursor moved */ (TILE_CURSOR(i, state, ds->cur_x, ds->cur_y) || TILE_CURSOR(i, state, cur_x, cur_y)))) { int x, y, x2, y2; /* * Figure out what to _actually_ draw, and where to * draw it. */ if (t == -1) { int x0, y0, x1, y1, dx, dy; int j; float c; int sense; if (dir < 0) { assert(oldstate); sense = -oldstate->last_movement_sense; } else { sense = state->last_movement_sense; } t = state->tiles[i]; /* * FIXME: must be prepared to draw a double * tile in some situations. */ /* * Find the coordinates of this tile in the old and * new states. */ x1 = COORD(X(state, i)); y1 = COORD(Y(state, i)); for (j = 0; j < oldstate->n; j++) if (oldstate->tiles[j] == state->tiles[i]) break; assert(j < oldstate->n); x0 = COORD(X(state, j)); y0 = COORD(Y(state, j)); dx = (x1 - x0); if (dx != 0 && dx != TILE_SIZE * sense) { dx = (dx < 0 ? dx + TILE_SIZE * state->w : dx - TILE_SIZE * state->w); assert(abs(dx) == TILE_SIZE); } dy = (y1 - y0); if (dy != 0 && dy != TILE_SIZE * sense) { dy = (dy < 0 ? dy + TILE_SIZE * state->h : dy - TILE_SIZE * state->h); assert(abs(dy) == TILE_SIZE); } c = (animtime / ANIM_TIME); if (c < 0.0F) c = 0.0F; if (c > 1.0F) c = 1.0F; x = x0 + (int)(c * dx); y = y0 + (int)(c * dy); x2 = x1 - dx + (int)(c * dx); y2 = y1 - dy + (int)(c * dy); } else { x = COORD(X(state, i)); y = COORD(Y(state, i)); x2 = y2 = -1; } draw_tile(dr, ds, state, x, y, t, (x2 == -1 && TILE_CURSOR(i, state, cur_x, cur_y)) ? COL_LOWLIGHT : bgcolour); if (x2 != -1 || y2 != -1) draw_tile(dr, ds, state, x2, y2, t, bgcolour); } ds->tiles[i] = t0; } ds->cur_x = cur_x; ds->cur_y = cur_y; unclip(dr); ds->bgcolour = bgcolour; /* * Update the status bar. */ { char statusbuf[256]; /* * Don't show the new status until we're also showing the * new _state_ - after the game animation is complete. */ if (oldstate) state = oldstate; if (state->used_solve) sprintf(statusbuf, "Moves since auto-solve: %d", state->movecount - state->completed); else { sprintf(statusbuf, "%sMoves: %d", (state->completed ? "COMPLETED! " : ""), (state->completed ? state->completed : state->movecount)); if (state->movetarget) sprintf(statusbuf+strlen(statusbuf), " (target %d)", state->movetarget); } status_bar(dr, statusbuf); } } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return ANIM_TIME; } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { if (!oldstate->completed && newstate->completed && !oldstate->used_solve && !newstate->used_solve) return 2 * FLASH_FRAME; else return 0.0F; } static int game_status(const game_state *state) { return state->completed ? +1 : 0; } static int game_timing_state(const game_state *state, game_ui *ui) { return TRUE; } static void game_print_size(const game_params *params, float *x, float *y) { } static void game_print(drawing *dr, const game_state *state, int tilesize) { } #ifdef COMBINED #define thegame sixteen #endif const struct game thegame = { "Sixteen", "games.sixteen", "sixteen", default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, TRUE, solve_game, TRUE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, PREFERRED_TILE_SIZE, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, FALSE, FALSE, game_print_size, game_print, TRUE, /* wants_statusbar */ FALSE, game_timing_state, 0, /* flags */ }; /* vim: set shiftwidth=4 tabstop=8: */ puzzles-20170606.272beef/singles.c0000644000175000017500000017071313115373615015512 0ustar simonsimon/* * singles.c: implementation of Hitori ('let me alone') from Nikoli. * * Make single-get able to fetch a specific puzzle ID from menneske.no? * * www.menneske.no solving methods: * * Done: * SC: if you circle a cell, any cells in same row/col with same no --> black * -- solver_op_circle * SB: if you make a cell black, any cells around it --> white * -- solver_op_blacken * ST: 3 identical cells in row, centre is white and outer two black. * SP: 2 identical cells with single-cell gap, middle cell is white. * -- solver_singlesep (both ST and SP) * PI: if you have a pair of same number in row/col, any other * cells of same number must be black. * -- solve_doubles * CC: if you have a black on edge one cell away from corner, cell * on edge diag. adjacent must be white. * CE: if you have 2 black cells of triangle on edge, third cell must * be white. * QM: if you have 3 black cells of diagonal square in middle, fourth * cell must be white. * -- solve_allblackbutone (CC, CE, and QM). * QC: a corner with 4 identical numbers (or 2 and 2) must have the * corner cell (and cell diagonal to that) black. * TC: a corner with 3 identical numbers (with the L either way) * must have the apex of L black, and other two white. * DC: a corner with 2 identical numbers in domino can set a white * cell along wall. * -- solve_corners (QC, TC, DC) * IP: pair with one-offset-pair force whites by offset pair * -- solve_offsetpair * MC: any cells diag. adjacent to black cells that would split board * into separate white regions must be white. * -- solve_removesplits * * Still to do: * * TEP: 3 pairs of dominos parallel to side, can mark 4 white cells * alongside. * DEP: 2 pairs of dominos parallel to side, can mark 2 white cells. * FI: if you have two sets of double-cells packed together, singles * in that row/col must be white (qv. PI) * QuM: four identical cells (or 2 and 2) in middle of grid only have * two possible solutions each. * FDE: doubles one row/column away from edge can force a white cell. * FDM: doubles in centre (next to bits of diag. square) can force a white cell. * MP: two pairs with same number between force number to black. * CnC: if circling a cell leads to impossible board, cell is black. * MC: if we have two possiblilities, can we force a white circle? * */ #include #include #include #include #include #include #include "puzzles.h" #include "latin.h" #ifdef STANDALONE_SOLVER int verbose = 0; #endif #define PREFERRED_TILE_SIZE 32 #define TILE_SIZE (ds->tilesize) #define BORDER (TILE_SIZE / 2) #define CRAD ((TILE_SIZE / 2) - 1) #define TEXTSZ ((14*CRAD/10) - 1) /* 2 * sqrt(2) of CRAD */ #define COORD(x) ( (x) * TILE_SIZE + BORDER ) #define FROMCOORD(x) ( ((x) - BORDER + TILE_SIZE) / TILE_SIZE - 1 ) #define INGRID(s,x,y) ((x) >= 0 && (x) < (s)->w && (y) >= 0 && (y) < (s)->h) #define FLASH_TIME 0.7F enum { COL_BACKGROUND, COL_HIGHLIGHT, COL_LOWLIGHT, COL_BLACK, COL_WHITE, COL_BLACKNUM, COL_GRID, COL_CURSOR, COL_ERROR, NCOLOURS }; struct game_params { int w, h, diff; }; #define F_BLACK 0x1 #define F_CIRCLE 0x2 #define F_ERROR 0x4 #define F_SCRATCH 0x8 struct game_state { int w, h, n, o; /* n = w*h; o = max(w, h) */ int completed, used_solve, impossible; int *nums; /* size w*h */ unsigned int *flags; /* size w*h */ }; /* top, right, bottom, left */ static const int dxs[4] = { 0, 1, 0, -1 }; static const int dys[4] = { -1, 0, 1, 0 }; /* --- Game parameters and preset functions --- */ #define DIFFLIST(A) \ A(EASY,Easy,e) \ A(TRICKY,Tricky,k) #define ENUM(upper,title,lower) DIFF_ ## upper, #define TITLE(upper,title,lower) #title, #define ENCODE(upper,title,lower) #lower #define CONFIG(upper,title,lower) ":" #title enum { DIFFLIST(ENUM) DIFF_MAX, DIFF_ANY }; static char const *const singles_diffnames[] = { DIFFLIST(TITLE) }; static char const singles_diffchars[] = DIFFLIST(ENCODE); #define DIFFCOUNT lenof(singles_diffchars) #define DIFFCONFIG DIFFLIST(CONFIG) static game_params *default_params(void) { game_params *ret = snew(game_params); ret->w = ret->h = 5; ret->diff = DIFF_EASY; return ret; } static const struct game_params singles_presets[] = { { 5, 5, DIFF_EASY }, { 5, 5, DIFF_TRICKY }, { 6, 6, DIFF_EASY }, { 6, 6, DIFF_TRICKY }, { 8, 8, DIFF_EASY }, { 8, 8, DIFF_TRICKY }, { 10, 10, DIFF_EASY }, { 10, 10, DIFF_TRICKY }, { 12, 12, DIFF_EASY }, { 12, 12, DIFF_TRICKY } }; static int game_fetch_preset(int i, char **name, game_params **params) { game_params *ret; char buf[80]; if (i < 0 || i >= lenof(singles_presets)) return FALSE; ret = default_params(); *ret = singles_presets[i]; *params = ret; sprintf(buf, "%dx%d %s", ret->w, ret->h, singles_diffnames[ret->diff]); *name = dupstr(buf); return TRUE; } static void free_params(game_params *params) { sfree(params); } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } static void decode_params(game_params *ret, char const *string) { char const *p = string; int i; ret->w = ret->h = atoi(p); while (*p && isdigit((unsigned char)*p)) p++; if (*p == 'x') { p++; ret->h = atoi(p); while (*p && isdigit((unsigned char)*p)) p++; } if (*p == 'd') { ret->diff = DIFF_MAX; /* which is invalid */ p++; for (i = 0; i < DIFFCOUNT; i++) { if (*p == singles_diffchars[i]) ret->diff = i; } p++; } } static char *encode_params(const game_params *params, int full) { char data[256]; if (full) sprintf(data, "%dx%dd%c", params->w, params->h, singles_diffchars[params->diff]); else sprintf(data, "%dx%d", params->w, params->h); return dupstr(data); } static config_item *game_configure(const game_params *params) { config_item *ret; char buf[80]; ret = snewn(4, config_item); ret[0].name = "Width"; ret[0].type = C_STRING; sprintf(buf, "%d", params->w); ret[0].sval = dupstr(buf); ret[0].ival = 0; ret[1].name = "Height"; ret[1].type = C_STRING; sprintf(buf, "%d", params->h); ret[1].sval = dupstr(buf); ret[1].ival = 0; ret[2].name = "Difficulty"; ret[2].type = C_CHOICES; ret[2].sval = DIFFCONFIG; ret[2].ival = params->diff; ret[3].name = NULL; ret[3].type = C_END; ret[3].sval = NULL; ret[3].ival = 0; return ret; } static game_params *custom_params(const config_item *cfg) { game_params *ret = snew(game_params); ret->w = atoi(cfg[0].sval); ret->h = atoi(cfg[1].sval); ret->diff = cfg[2].ival; return ret; } static char *validate_params(const game_params *params, int full) { if (params->w < 2 || params->h < 2) return "Width and neight must be at least two"; if (params->w > 10+26+26 || params->h > 10+26+26) return "Puzzle is too large"; if (full) { if (params->diff < 0 || params->diff >= DIFF_MAX) return "Unknown difficulty rating"; } return NULL; } /* --- Game description string generation and unpicking --- */ static game_state *blank_game(int w, int h) { game_state *state = snew(game_state); memset(state, 0, sizeof(game_state)); state->w = w; state->h = h; state->n = w*h; state->o = max(w,h); state->completed = state->used_solve = state->impossible = 0; state->nums = snewn(state->n, int); state->flags = snewn(state->n, unsigned int); memset(state->nums, 0, state->n*sizeof(int)); memset(state->flags, 0, state->n*sizeof(unsigned int)); return state; } static game_state *dup_game(const game_state *state) { game_state *ret = blank_game(state->w, state->h); ret->completed = state->completed; ret->used_solve = state->used_solve; ret->impossible = state->impossible; memcpy(ret->nums, state->nums, state->n*sizeof(int)); memcpy(ret->flags, state->flags, state->n*sizeof(unsigned int)); return ret; } static void free_game(game_state *state) { sfree(state->nums); sfree(state->flags); sfree(state); } static char n2c(int num) { if (num < 10) return '0' + num; else if (num < 10+26) return 'a' + num - 10; else return 'A' + num - 10 - 26; return '?'; } static int c2n(char c) { if (isdigit((unsigned char)c)) return (int)(c - '0'); else if (c >= 'a' && c <= 'z') return (int)(c - 'a' + 10); else if (c >= 'A' && c <= 'Z') return (int)(c - 'A' + 10 + 26); return -1; } static void unpick_desc(const game_params *params, const char *desc, game_state **sout, char **mout) { game_state *state = blank_game(params->w, params->h); char *msg = NULL; int num = 0, i = 0; if (strlen(desc) != state->n) { msg = "Game description is wrong length"; goto done; } for (i = 0; i < state->n; i++) { num = c2n(desc[i]); if (num <= 0 || num > state->o) { msg = "Game description contains unexpected characters"; goto done; } state->nums[i] = num; } done: if (msg) { /* sth went wrong. */ if (mout) *mout = msg; free_game(state); } else { if (mout) *mout = NULL; if (sout) *sout = state; else free_game(state); } } static char *generate_desc(game_state *state, int issolve) { char *ret = snewn(state->n+1+(issolve?1:0), char); int i, p=0; if (issolve) ret[p++] = 'S'; for (i = 0; i < state->n; i++) ret[p++] = n2c(state->nums[i]); ret[p] = '\0'; return ret; } /* --- Useful game functions (completion, etc.) --- */ static int game_can_format_as_text_now(const game_params *params) { return TRUE; } static char *game_text_format(const game_state *state) { int len, x, y, i; char *ret, *p; len = (state->w)*2; /* one row ... */ len = len * (state->h*2); /* ... h rows, including gaps ... */ len += 1; /* ... final NL */ p = ret = snewn(len, char); for (y = 0; y < state->h; y++) { for (x = 0; x < state->w; x++) { i = y*state->w + x; if (x > 0) *p++ = ' '; *p++ = (state->flags[i] & F_BLACK) ? '*' : n2c(state->nums[i]); } *p++ = '\n'; for (x = 0; x < state->w; x++) { i = y*state->w + x; if (x > 0) *p++ = ' '; *p++ = (state->flags[i] & F_CIRCLE) ? '~' : ' '; } *p++ = '\n'; } *p++ = '\0'; assert(p - ret == len); return ret; } static void debug_state(const char *desc, game_state *state) { char *dbg = game_text_format(state); debug(("%s:\n%s", desc, dbg)); sfree(dbg); } static void connect_if_same(game_state *state, int *dsf, int i1, int i2) { int c1, c2; if ((state->flags[i1] & F_BLACK) != (state->flags[i2] & F_BLACK)) return; c1 = dsf_canonify(dsf, i1); c2 = dsf_canonify(dsf, i2); dsf_merge(dsf, c1, c2); } static void connect_dsf(game_state *state, int *dsf) { int x, y, i; /* Construct a dsf array for connected blocks; connections * tracked to right and down. */ dsf_init(dsf, state->n); for (x = 0; x < state->w; x++) { for (y = 0; y < state->h; y++) { i = y*state->w + x; if (x < state->w-1) connect_if_same(state, dsf, i, i+1); /* right */ if (y < state->h-1) connect_if_same(state, dsf, i, i+state->w); /* down */ } } } #define CC_MARK_ERRORS 1 #define CC_MUST_FILL 2 static int check_rowcol(game_state *state, int starti, int di, int sz, unsigned flags) { int nerr = 0, n, m, i, j; /* if any circled numbers have identical non-circled numbers on * same row/column, error (non-circled) * if any circled numbers in same column are same number, highlight them. * if any rows/columns have >1 of same number, not complete. */ for (n = 0, i = starti; n < sz; n++, i += di) { if (state->flags[i] & F_BLACK) continue; for (m = n+1, j = i+di; m < sz; m++, j += di) { if (state->flags[j] & F_BLACK) continue; if (state->nums[i] != state->nums[j]) continue; nerr++; /* ok, we have two numbers the same in a row. */ if (!(flags & CC_MARK_ERRORS)) continue; /* If we have two circles in the same row around * two identical numbers, they are _both_ wrong. */ if ((state->flags[i] & F_CIRCLE) && (state->flags[j] & F_CIRCLE)) { state->flags[i] |= F_ERROR; state->flags[j] |= F_ERROR; } /* Otherwise, if we have a circle, any other identical * numbers in that row are obviously wrong. We don't * highlight this, however, since it makes the process * of solving the puzzle too easy (you circle a number * and it promptly tells you which numbers to blacken! */ #if 0 else if (state->flags[i] & F_CIRCLE) state->flags[j] |= F_ERROR; else if (state->flags[j] & F_CIRCLE) state->flags[i] |= F_ERROR; #endif } } return nerr; } static int check_complete(game_state *state, unsigned flags) { int *dsf = snewn(state->n, int); int x, y, i, error = 0, nwhite, w = state->w, h = state->h; if (flags & CC_MARK_ERRORS) { for (i = 0; i < state->n; i++) state->flags[i] &= ~F_ERROR; } connect_dsf(state, dsf); /* If we're the solver we need the grid all to be definitively * black or definitively white (i.e. circled) otherwise the solver * has found an ambiguous grid. */ if (flags & CC_MUST_FILL) { for (i = 0; i < state->n; i++) { if (!(state->flags[i] & F_BLACK) && !(state->flags[i] & F_CIRCLE)) error += 1; } } /* Mark any black squares in groups of >1 as errors. * Count number of white squares. */ nwhite = 0; for (i = 0; i < state->n; i++) { if (state->flags[i] & F_BLACK) { if (dsf_size(dsf, i) > 1) { error += 1; if (flags & CC_MARK_ERRORS) state->flags[i] |= F_ERROR; } } else nwhite += 1; } /* Check attributes of white squares, row- and column-wise. */ for (x = 0; x < w; x++) /* check cols from (x,0) */ error += check_rowcol(state, x, w, h, flags); for (y = 0; y < h; y++) /* check rows from (0,y) */ error += check_rowcol(state, y*w, 1, w, flags); /* If there's more than one white region, pick the largest one to * be the canonical one (arbitrarily tie-breaking towards lower * array indices), and mark all the others as erroneous. */ { int largest = 0, canonical = -1; for (i = 0; i < state->n; i++) if (!(state->flags[i] & F_BLACK)) { int size = dsf_size(dsf, i); if (largest < size) { largest = size; canonical = i; } } if (largest < nwhite) { for (i = 0; i < state->n; i++) if (!(state->flags[i] & F_BLACK) && dsf_canonify(dsf, i) != canonical) { error += 1; if (flags & CC_MARK_ERRORS) state->flags[i] |= F_ERROR; } } } sfree(dsf); return (error > 0) ? 0 : 1; } static char *game_state_diff(const game_state *src, const game_state *dst, int issolve) { char *ret = NULL, buf[80], c; int retlen = 0, x, y, i, k; unsigned int fmask = F_BLACK | F_CIRCLE; assert(src->n == dst->n); if (issolve) { ret = sresize(ret, 3, char); ret[0] = 'S'; ret[1] = ';'; ret[2] = '\0'; retlen += 2; } for (x = 0; x < dst->w; x++) { for (y = 0; y < dst->h; y++) { i = y*dst->w + x; if ((src->flags[i] & fmask) != (dst->flags[i] & fmask)) { assert((dst->flags[i] & fmask) != fmask); if (dst->flags[i] & F_BLACK) c = 'B'; else if (dst->flags[i] & F_CIRCLE) c = 'C'; else c = 'E'; k = sprintf(buf, "%c%d,%d;", (int)c, x, y); ret = sresize(ret, retlen + k + 1, char); strcpy(ret + retlen, buf); retlen += k; } } } return ret; } /* --- Solver --- */ enum { BLACK, CIRCLE }; struct solver_op { int x, y, op; /* op one of BLACK or CIRCLE. */ const char *desc; /* must be non-malloced. */ }; struct solver_state { struct solver_op *ops; int n_ops, n_alloc; int *scratch; }; static struct solver_state *solver_state_new(game_state *state) { struct solver_state *ss = snew(struct solver_state); ss->ops = NULL; ss->n_ops = ss->n_alloc = 0; ss->scratch = snewn(state->n, int); return ss; } static void solver_state_free(struct solver_state *ss) { sfree(ss->scratch); if (ss->ops) sfree(ss->ops); sfree(ss); } static void solver_op_add(struct solver_state *ss, int x, int y, int op, const char *desc) { struct solver_op *sop; if (ss->n_alloc < ss->n_ops + 1) { ss->n_alloc = (ss->n_alloc + 1) * 2; ss->ops = sresize(ss->ops, ss->n_alloc, struct solver_op); } sop = &(ss->ops[ss->n_ops++]); sop->x = x; sop->y = y; sop->op = op; sop->desc = desc; debug(("added solver op %s ('%s') at (%d,%d)\n", op == BLACK ? "BLACK" : "CIRCLE", desc, x, y)); } static void solver_op_circle(game_state *state, struct solver_state *ss, int x, int y) { int i = y*state->w + x; if (!INGRID(state, x, y)) return; if (state->flags[i] & F_BLACK) { debug(("... solver wants to add auto-circle on black (%d,%d)\n", x, y)); state->impossible = 1; return; } /* Only add circle op if it's not already circled. */ if (!(state->flags[i] & F_CIRCLE)) { solver_op_add(ss, x, y, CIRCLE, "SB - adjacent to black square"); } } static void solver_op_blacken(game_state *state, struct solver_state *ss, int x, int y, int num) { int i = y*state->w + x; if (!INGRID(state, x, y)) return; if (state->nums[i] != num) return; if (state->flags[i] & F_CIRCLE) { debug(("... solver wants to add auto-black on circled(%d,%d)\n", x, y)); state->impossible = 1; return; } /* Only add black op if it's not already black. */ if (!(state->flags[i] & F_BLACK)) { solver_op_add(ss, x, y, BLACK, "SC - number on same row/col as circled"); } } static int solver_ops_do(game_state *state, struct solver_state *ss) { int next_op = 0, i, x, y, n_ops = 0; struct solver_op op; /* Care here: solver_op_* may call solver_op_add which may extend the * ss->n_ops. */ while (next_op < ss->n_ops) { op = ss->ops[next_op++]; /* copy this away, it may get reallocated. */ i = op.y*state->w + op.x; if (op.op == BLACK) { if (state->flags[i] & F_CIRCLE) { debug(("Solver wants to blacken circled square (%d,%d)!\n", op.x, op.y)); state->impossible = 1; return n_ops; } if (!(state->flags[i] & F_BLACK)) { debug(("... solver adding black at (%d,%d): %s\n", op.x, op.y, op.desc)); #ifdef STANDALONE_SOLVER if (verbose) printf("Adding black at (%d,%d): %s\n", op.x, op.y, op.desc); #endif state->flags[i] |= F_BLACK; /*debug_state("State after adding black", state);*/ n_ops++; solver_op_circle(state, ss, op.x-1, op.y); solver_op_circle(state, ss, op.x+1, op.y); solver_op_circle(state, ss, op.x, op.y-1); solver_op_circle(state, ss, op.x, op.y+1); } } else { if (state->flags[i] & F_BLACK) { debug(("Solver wants to circle blackened square (%d,%d)!\n", op.x, op.y)); state->impossible = 1; return n_ops; } if (!(state->flags[i] & F_CIRCLE)) { debug(("... solver adding circle at (%d,%d): %s\n", op.x, op.y, op.desc)); #ifdef STANDALONE_SOLVER if (verbose) printf("Adding circle at (%d,%d): %s\n", op.x, op.y, op.desc); #endif state->flags[i] |= F_CIRCLE; /*debug_state("State after adding circle", state);*/ n_ops++; for (x = 0; x < state->w; x++) { if (x != op.x) solver_op_blacken(state, ss, x, op.y, state->nums[i]); } for (y = 0; y < state->h; y++) { if (y != op.y) solver_op_blacken(state, ss, op.x, y, state->nums[i]); } } } } ss->n_ops = 0; return n_ops; } /* If the grid has two identical numbers with one cell between them, the inner * cell _must_ be white (and thus circled); (at least) one of the two must be * black (since they're in the same column or row) and thus the middle cell is * next to a black cell. */ static int solve_singlesep(game_state *state, struct solver_state *ss) { int x, y, i, ir, irr, id, idd, n_ops = ss->n_ops; for (x = 0; x < state->w; x++) { for (y = 0; y < state->h; y++) { i = y*state->w + x; /* Cell two to our right? */ ir = i + 1; irr = ir + 1; if (x < (state->w-2) && state->nums[i] == state->nums[irr] && !(state->flags[ir] & F_CIRCLE)) { solver_op_add(ss, x+1, y, CIRCLE, "SP/ST - between identical nums"); } /* Cell two below us? */ id = i + state->w; idd = id + state->w; if (y < (state->h-2) && state->nums[i] == state->nums[idd] && !(state->flags[id] & F_CIRCLE)) { solver_op_add(ss, x, y+1, CIRCLE, "SP/ST - between identical nums"); } } } return ss->n_ops - n_ops; } /* If we have two identical numbers next to each other (in a row or column), * any other identical numbers in that column must be black. */ static int solve_doubles(game_state *state, struct solver_state *ss) { int x, y, i, ii, n_ops = ss->n_ops, xy; for (y = 0, i = 0; y < state->h; y++) { for (x = 0; x < state->w; x++, i++) { assert(i == y*state->w+x); if (state->flags[i] & F_BLACK) continue; ii = i+1; /* check cell to our right. */ if (x < (state->w-1) && !(state->flags[ii] & F_BLACK) && state->nums[i] == state->nums[ii]) { for (xy = 0; xy < state->w; xy++) { if (xy == x || xy == (x+1)) continue; if (state->nums[y*state->w + xy] == state->nums[i] && !(state->flags[y*state->w + xy] & F_BLACK)) solver_op_add(ss, xy, y, BLACK, "PI - same row as pair"); } } ii = i+state->w; /* check cell below us */ if (y < (state->h-1) && !(state->flags[ii] & F_BLACK) && state->nums[i] == state->nums[ii]) { for (xy = 0; xy < state->h; xy++) { if (xy == y || xy == (y+1)) continue; if (state->nums[xy*state->w + x] == state->nums[i] && !(state->flags[xy*state->w + x] & F_BLACK)) solver_op_add(ss, x, xy, BLACK, "PI - same col as pair"); } } } } return ss->n_ops - n_ops; } /* If a white square has all-but-one possible adjacent squares black, the * one square left over must be white. */ static int solve_allblackbutone(game_state *state, struct solver_state *ss) { int x, y, i, n_ops = ss->n_ops, xd, yd, id, ifree; int dis[4], d; dis[0] = -state->w; dis[1] = 1; dis[2] = state->w; dis[3] = -1; for (y = 0, i = 0; y < state->h; y++) { for (x = 0; x < state->w; x++, i++) { assert(i == y*state->w+x); if (state->flags[i] & F_BLACK) continue; ifree = -1; for (d = 0; d < 4; d++) { xd = x + dxs[d]; yd = y + dys[d]; id = i + dis[d]; if (!INGRID(state, xd, yd)) continue; if (state->flags[id] & F_CIRCLE) goto skip; /* this cell already has a way out */ if (!(state->flags[id] & F_BLACK)) { if (ifree != -1) goto skip; /* this cell has >1 white cell around it. */ ifree = id; } } if (ifree != -1) solver_op_add(ss, ifree%state->w, ifree/state->w, CIRCLE, "CC/CE/QM: white cell with single non-black around it"); else { debug(("White cell with no escape at (%d,%d)\n", x, y)); state->impossible = 1; return 0; } skip: ; } } return ss->n_ops - n_ops; } /* If we have 4 numbers the same in a 2x2 corner, the far corner and the * diagonally-adjacent square must both be black. * If we have 3 numbers the same in a 2x2 corner, the apex of the L * thus formed must be black. * If we have 2 numbers the same in a 2x2 corner, the non-same cell * one away from the corner must be white. */ static void solve_corner(game_state *state, struct solver_state *ss, int x, int y, int dx, int dy) { int is[4], ns[4], xx, yy, w = state->w; for (yy = 0; yy < 2; yy++) { for (xx = 0; xx < 2; xx++) { is[yy*2+xx] = (y + dy*yy) * w + (x + dx*xx); ns[yy*2+xx] = state->nums[is[yy*2+xx]]; } } /* order is now (corner, side 1, side 2, inner) */ if (ns[0] == ns[1] && ns[0] == ns[2] && ns[0] == ns[3]) { solver_op_add(ss, is[0]%w, is[0]/w, BLACK, "QC: corner with 4 matching"); solver_op_add(ss, is[3]%w, is[3]/w, BLACK, "QC: corner with 4 matching"); } else if (ns[0] == ns[1] && ns[0] == ns[2]) { /* corner and 2 sides: apex is corner. */ solver_op_add(ss, is[0]%w, is[0]/w, BLACK, "TC: corner apex from 3 matching"); } else if (ns[1] == ns[2] && ns[1] == ns[3]) { /* side, side, fourth: apex is fourth. */ solver_op_add(ss, is[3]%w, is[3]/w, BLACK, "TC: inside apex from 3 matching"); } else if (ns[0] == ns[1] || ns[1] == ns[3]) { /* either way here we match the non-identical side. */ solver_op_add(ss, is[2]%w, is[2]/w, CIRCLE, "DC: corner with 2 matching"); } else if (ns[0] == ns[2] || ns[2] == ns[3]) { /* ditto */ solver_op_add(ss, is[1]%w, is[1]/w, CIRCLE, "DC: corner with 2 matching"); } } static int solve_corners(game_state *state, struct solver_state *ss) { int n_ops = ss->n_ops; solve_corner(state, ss, 0, 0, 1, 1); solve_corner(state, ss, state->w-1, 0, -1, 1); solve_corner(state, ss, state->w-1, state->h-1, -1, -1); solve_corner(state, ss, 0, state->h-1, 1, -1); return ss->n_ops - n_ops; } /* If you have the following situation: * ... * ...x A x x y A x... * ...x B x x B y x... * ... * then both squares marked 'y' must be white. One of the left-most A or B must * be white (since two side-by-side black cells are disallowed), which means * that the corresponding right-most A or B must be black (since you can't * have two of the same number on one line); thus, the adjacent squares * to that right-most A or B must be white, which include the two marked 'y' * in either case. * Obviously this works in any row or column. It also works if A == B. * It doesn't work for the degenerate case: * ...x A A x x * ...x B y x x * where the square marked 'y' isn't necessarily white (consider the left-most A * is black). * * */ static void solve_offsetpair_pair(game_state *state, struct solver_state *ss, int x1, int y1, int x2, int y2) { int ox, oy, w = state->w, ax, ay, an, d, dx[2], dy[2], dn, xd, yd; if (x1 == x2) { /* same column */ ox = 1; oy = 0; } else { assert(y1 == y2); ox = 0; oy = 1; } /* We try adjacent to (x1,y1) and the two diag. adjacent to (x2, y2). * We expect to be called twice, once each way around. */ ax = x1+ox; ay = y1+oy; assert(INGRID(state, ax, ay)); an = state->nums[ay*w + ax]; dx[0] = x2 + ox + oy; dx[1] = x2 + ox - oy; dy[0] = y2 + oy + ox; dy[1] = y2 + oy - ox; for (d = 0; d < 2; d++) { if (INGRID(state, dx[d], dy[d]) && (dx[d] != ax || dy[d] != ay)) { /* The 'dx != ax || dy != ay' removes the degenerate case, * mentioned above. */ dn = state->nums[dy[d]*w + dx[d]]; if (an == dn) { /* We have a match; so (WLOG) the 'A' marked above are at * (x1,y1) and (x2,y2), and the 'B' are at (ax,ay) and (dx,dy). */ debug(("Found offset-pair: %d at (%d,%d) and (%d,%d)\n", state->nums[y1*w + x1], x1, y1, x2, y2)); debug((" and: %d at (%d,%d) and (%d,%d)\n", an, ax, ay, dx[d], dy[d])); xd = dx[d] - x2; yd = dy[d] - y2; solver_op_add(ss, x2 + xd, y2, CIRCLE, "IP: next to offset-pair"); solver_op_add(ss, x2, y2 + yd, CIRCLE, "IP: next to offset-pair"); } } } } static int solve_offsetpair(game_state *state, struct solver_state *ss) { int n_ops = ss->n_ops, x, xx, y, yy, n1, n2; for (x = 0; x < state->w-1; x++) { for (y = 0; y < state->h; y++) { n1 = state->nums[y*state->w + x]; for (yy = y+1; yy < state->h; yy++) { n2 = state->nums[yy*state->w + x]; if (n1 == n2) { solve_offsetpair_pair(state, ss, x, y, x, yy); solve_offsetpair_pair(state, ss, x, yy, x, y); } } } } for (y = 0; y < state->h-1; y++) { for (x = 0; x < state->w; x++) { n1 = state->nums[y*state->w + x]; for (xx = x+1; xx < state->w; xx++) { n2 = state->nums[y*state->w + xx]; if (n1 == n2) { solve_offsetpair_pair(state, ss, x, y, xx, y); solve_offsetpair_pair(state, ss, xx, y, x, y); } } } } return ss->n_ops - n_ops; } static int solve_hassinglewhiteregion(game_state *state, struct solver_state *ss) { int i, j, nwhite = 0, lwhite = -1, szwhite, start, end, next, a, d, x, y; for (i = 0; i < state->n; i++) { if (!(state->flags[i] & F_BLACK)) { nwhite++; lwhite = i; } state->flags[i] &= ~F_SCRATCH; } if (lwhite == -1) { debug(("solve_hassinglewhite: no white squares found!\n")); state->impossible = 1; return 0; } /* We don't use connect_dsf here; it's too slow, and there's a quicker * algorithm if all we want is the size of one region. */ /* Having written this, this algorithm is only about 5% faster than * using a dsf. */ memset(ss->scratch, -1, state->n * sizeof(int)); ss->scratch[0] = lwhite; state->flags[lwhite] |= F_SCRATCH; start = 0; end = next = 1; while (start < end) { for (a = start; a < end; a++) { i = ss->scratch[a]; assert(i != -1); for (d = 0; d < 4; d++) { x = (i % state->w) + dxs[d]; y = (i / state->w) + dys[d]; j = y*state->w + x; if (!INGRID(state, x, y)) continue; if (state->flags[j] & (F_BLACK | F_SCRATCH)) continue; ss->scratch[next++] = j; state->flags[j] |= F_SCRATCH; } } start = end; end = next; } szwhite = next; return (szwhite == nwhite) ? 1 : 0; } static void solve_removesplits_check(game_state *state, struct solver_state *ss, int x, int y) { int i = y*state->w + x, issingle; if (!INGRID(state, x, y)) return; if ((state->flags[i] & F_CIRCLE) || (state->flags[i] & F_BLACK)) return; /* If putting a black square at (x,y) would make the white region * non-contiguous, it must be circled. */ state->flags[i] |= F_BLACK; issingle = solve_hassinglewhiteregion(state, ss); state->flags[i] &= ~F_BLACK; if (!issingle) solver_op_add(ss, x, y, CIRCLE, "MC: black square here would split white region"); } /* For all black squares, search in squares diagonally adjacent to see if * we can rule out putting a black square there (because it would make the * white region non-contiguous). */ /* This function is likely to be somewhat slow. */ static int solve_removesplits(game_state *state, struct solver_state *ss) { int i, x, y, n_ops = ss->n_ops; if (!solve_hassinglewhiteregion(state, ss)) { debug(("solve_removesplits: white region is not contiguous at start!\n")); state->impossible = 1; return 0; } for (i = 0; i < state->n; i++) { if (!(state->flags[i] & F_BLACK)) continue; x = i%state->w; y = i/state->w; solve_removesplits_check(state, ss, x-1, y-1); solve_removesplits_check(state, ss, x+1, y-1); solve_removesplits_check(state, ss, x+1, y+1); solve_removesplits_check(state, ss, x-1, y+1); } return ss->n_ops - n_ops; } /* * This function performs a solver step that isn't implicit in the rules * of the game and is thus treated somewhat differently. * * It marks cells whose number does not exist elsewhere in its row/column * with circles. As it happens the game generator here does mean that this * is always correct, but it's a solving method that people should not have * to rely upon (except in the hidden 'sneaky' difficulty setting) and so * all grids at 'tricky' and above are checked to make sure that the grid * is no easier if this solving step is performed beforehand. * * Calling with ss=NULL just returns the number of sneaky deductions that * would have been made. */ static int solve_sneaky(game_state *state, struct solver_state *ss) { int i, ii, x, xx, y, yy, nunique = 0; /* Clear SCRATCH flags. */ for (i = 0; i < state->n; i++) state->flags[i] &= ~F_SCRATCH; for (x = 0; x < state->w; x++) { for (y = 0; y < state->h; y++) { i = y*state->w + x; /* Check for duplicate numbers on our row, mark (both) if so */ for (xx = x; xx < state->w; xx++) { ii = y*state->w + xx; if (i == ii) continue; if (state->nums[i] == state->nums[ii]) { state->flags[i] |= F_SCRATCH; state->flags[ii] |= F_SCRATCH; } } /* Check for duplicate numbers on our col, mark (both) if so */ for (yy = y; yy < state->h; yy++) { ii = yy*state->w + x; if (i == ii) continue; if (state->nums[i] == state->nums[ii]) { state->flags[i] |= F_SCRATCH; state->flags[ii] |= F_SCRATCH; } } } } /* Any cell with no marking has no duplicates on its row or column: * set its CIRCLE. */ for (i = 0; i < state->n; i++) { if (!(state->flags[i] & F_SCRATCH)) { if (ss) solver_op_add(ss, i%state->w, i/state->w, CIRCLE, "SNEAKY: only one of its number in row and col"); nunique += 1; } else state->flags[i] &= ~F_SCRATCH; } return nunique; } static int solve_specific(game_state *state, int diff, int sneaky) { struct solver_state *ss = solver_state_new(state); if (sneaky) solve_sneaky(state, ss); /* Some solver operations we only have to perform once -- * they're only based on the numbers available, and not black * squares or circles which may be added later. */ solve_singlesep(state, ss); /* never sets impossible */ solve_doubles(state, ss); /* ditto */ solve_corners(state, ss); /* ditto */ if (diff >= DIFF_TRICKY) solve_offsetpair(state, ss); /* ditto */ while (1) { if (ss->n_ops > 0) solver_ops_do(state, ss); if (state->impossible) break; if (solve_allblackbutone(state, ss) > 0) continue; if (state->impossible) break; if (diff >= DIFF_TRICKY) { if (solve_removesplits(state, ss) > 0) continue; if (state->impossible) break; } break; } solver_state_free(ss); return state->impossible ? -1 : check_complete(state, CC_MUST_FILL); } static char *solve_game(const game_state *state, const game_state *currstate, const char *aux, char **error) { game_state *solved = dup_game(currstate); char *move = NULL; if (solve_specific(solved, DIFF_ANY, 0) > 0) goto solved; free_game(solved); solved = dup_game(state); if (solve_specific(solved, DIFF_ANY, 0) > 0) goto solved; free_game(solved); *error = "Unable to solve puzzle."; return NULL; solved: move = game_state_diff(currstate, solved, 1); free_game(solved); return move; } /* --- Game generation --- */ /* A correctly completed Hitori board is essentially a latin square * (no duplicated numbers in any row or column) with black squares * added such that no black square touches another, and the white * squares make a contiguous region. * * So we can generate it by: * constructing a latin square * adding black squares at random (minding the constraints) * altering the numbers under the new black squares such that the solver gets a headstart working out where they are. */ static int new_game_is_good(const game_params *params, game_state *state, game_state *tosolve) { int sret, sret_easy = 0; memcpy(tosolve->nums, state->nums, state->n * sizeof(int)); memset(tosolve->flags, 0, state->n * sizeof(unsigned int)); tosolve->completed = tosolve->impossible = 0; /* * We try and solve it twice, once at our requested difficulty level * (ensuring it's soluble at all) and once at the level below (if * it exists), which we hope to fail: if you can also solve it at * the level below then it's too easy and we have to try again. * * With this puzzle in particular there's an extra finesse, which is * that we check that the generated puzzle isn't too easy _with * an extra solver step first_, which is the 'sneaky' mode of deductions * (asserting that any number which fulfils the latin-square rules * on its row/column must be white). This is an artefact of the * generation process and not implicit in the rules, so we don't want * people to be able to use it to make the puzzle easier. */ assert(params->diff < DIFF_MAX); sret = solve_specific(tosolve, params->diff, 0); if (params->diff > DIFF_EASY) { memset(tosolve->flags, 0, state->n * sizeof(unsigned int)); tosolve->completed = tosolve->impossible = 0; /* this is the only time the 'sneaky' flag is set to 1. */ sret_easy = solve_specific(tosolve, params->diff-1, 1); } if (sret <= 0 || sret_easy > 0) { debug(("Generated puzzle %s at chosen difficulty %s\n", sret <= 0 ? "insoluble" : "too easy", singles_diffnames[params->diff])); return 0; } return 1; } #define MAXTRIES 20 static int best_black_col(game_state *state, random_state *rs, int *scratch, int i, int *rownums, int *colnums) { int w = state->w, x = i%w, y = i/w, j, o = state->o; /* Randomise the list of numbers to try. */ for (i = 0; i < o; i++) scratch[i] = i; shuffle(scratch, o, sizeof(int), rs); /* Try each number in turn, first giving preference to removing * latin-square characteristics (i.e. those numbers which only * occur once in a row/column). The '&&' here, although intuitively * wrong, results in a smaller number of 'sneaky' deductions on * solvable boards. */ for (i = 0; i < o; i++) { j = scratch[i] + 1; if (rownums[y*o + j-1] == 1 && colnums[x*o + j-1] == 1) goto found; } /* Then try each number in turn returning the first one that's * not actually unique in its row/column (see comment below) */ for (i = 0; i < o; i++) { j = scratch[i] + 1; if (rownums[y*o + j-1] != 0 || colnums[x*o + j-1] != 0) goto found; } assert(!"unable to place number under black cell."); return 0; found: /* Update column and row counts assuming this number will be placed. */ rownums[y*o + j-1] += 1; colnums[x*o + j-1] += 1; return j; } static char *new_game_desc(const game_params *params, random_state *rs, char **aux, int interactive) { game_state *state = blank_game(params->w, params->h); game_state *tosolve = blank_game(params->w, params->h); int i, j, *scratch, *rownums, *colnums, x, y, ntries; int w = state->w, h = state->h, o = state->o; char *ret; digit *latin; struct solver_state *ss = solver_state_new(state); scratch = snewn(state->n, int); rownums = snewn(h*o, int); colnums = snewn(w*o, int); generate: ss->n_ops = 0; debug(("Starting game generation, size %dx%d\n", w, h)); memset(state->flags, 0, state->n*sizeof(unsigned int)); /* First, generate the latin rectangle. * The order of this, o, is max(w,h). */ latin = latin_generate_rect(w, h, rs); for (i = 0; i < state->n; i++) state->nums[i] = (int)latin[i]; sfree(latin); debug_state("State after latin square", state); /* Add black squares at random, using bits of solver as we go (to lay * white squares), until we can lay no more blacks. */ for (i = 0; i < state->n; i++) scratch[i] = i; shuffle(scratch, state->n, sizeof(int), rs); for (j = 0; j < state->n; j++) { i = scratch[j]; if ((state->flags[i] & F_CIRCLE) || (state->flags[i] & F_BLACK)) { debug(("generator skipping (%d,%d): %s\n", i%w, i/w, (state->flags[i] & F_CIRCLE) ? "CIRCLE" : "BLACK")); continue; /* solver knows this must be one or the other already. */ } /* Add a random black cell... */ solver_op_add(ss, i%w, i/w, BLACK, "Generator: adding random black cell"); solver_ops_do(state, ss); /* ... and do as well as we know how to lay down whites that are now forced. */ solve_allblackbutone(state, ss); solver_ops_do(state, ss); solve_removesplits(state, ss); solver_ops_do(state, ss); if (state->impossible) { debug(("generator made impossible, restarting...\n")); goto generate; } } debug_state("State after adding blacks", state); /* Now we know which squares are white and which are black, we lay numbers * under black squares at random, except that the number must appear in * white cells at least once more in the same column or row as that [black] * square. That's necessary to avoid multiple solutions, where blackening * squares in the finished puzzle becomes optional. We use two arrays: * * rownums[ROW * o + NUM-1] is the no. of white cells containing NUM in y=ROW * colnums[COL * o + NUM-1] is the no. of white cells containing NUM in x=COL */ memset(rownums, 0, h*o * sizeof(int)); memset(colnums, 0, w*o * sizeof(int)); for (i = 0; i < state->n; i++) { if (state->flags[i] & F_BLACK) continue; j = state->nums[i]; x = i%w; y = i/w; rownums[y * o + j-1] += 1; colnums[x * o + j-1] += 1; } ntries = 0; randomise: for (i = 0; i < state->n; i++) { if (!(state->flags[i] & F_BLACK)) continue; state->nums[i] = best_black_col(state, rs, scratch, i, rownums, colnums); } debug_state("State after adding numbers", state); /* DIFF_ANY just returns whatever we first generated, for testing purposes. */ if (params->diff != DIFF_ANY && !new_game_is_good(params, state, tosolve)) { ntries++; if (ntries > MAXTRIES) { debug(("Ran out of randomisation attempts, re-generating.\n")); goto generate; } debug(("Re-randomising numbers under black squares.\n")); goto randomise; } ret = generate_desc(state, 0); free_game(tosolve); free_game(state); solver_state_free(ss); sfree(scratch); sfree(rownums); sfree(colnums); return ret; } static char *validate_desc(const game_params *params, const char *desc) { char *ret = NULL; unpick_desc(params, desc, NULL, &ret); return ret; } static game_state *new_game(midend *me, const game_params *params, const char *desc) { game_state *state = NULL; unpick_desc(params, desc, &state, NULL); if (!state) assert(!"new_game failed to unpick"); return state; } /* --- Game UI and move routines --- */ struct game_ui { int cx, cy, cshow; int show_black_nums; }; static game_ui *new_ui(const game_state *state) { game_ui *ui = snew(game_ui); ui->cx = ui->cy = ui->cshow = 0; ui->show_black_nums = 0; return ui; } static void free_ui(game_ui *ui) { sfree(ui); } static char *encode_ui(const game_ui *ui) { return NULL; } static void decode_ui(game_ui *ui, const char *encoding) { } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { if (!oldstate->completed && newstate->completed) ui->cshow = 0; } #define DS_BLACK 0x1 #define DS_CIRCLE 0x2 #define DS_CURSOR 0x4 #define DS_BLACK_NUM 0x8 #define DS_ERROR 0x10 #define DS_FLASH 0x20 #define DS_IMPOSSIBLE 0x40 struct game_drawstate { int tilesize, started, solved; int w, h, n; unsigned int *flags; }; static char *interpret_move(const game_state *state, game_ui *ui, const game_drawstate *ds, int mx, int my, int button) { char buf[80], c; int i, x = FROMCOORD(mx), y = FROMCOORD(my); enum { NONE, TOGGLE_BLACK, TOGGLE_CIRCLE, UI } action = NONE; if (IS_CURSOR_MOVE(button)) { move_cursor(button, &ui->cx, &ui->cy, state->w, state->h, 1); ui->cshow = 1; action = UI; } else if (IS_CURSOR_SELECT(button)) { x = ui->cx; y = ui->cy; if (!ui->cshow) { action = UI; ui->cshow = 1; } if (button == CURSOR_SELECT) { action = TOGGLE_BLACK; } else if (button == CURSOR_SELECT2) { action = TOGGLE_CIRCLE; } } else if (IS_MOUSE_DOWN(button)) { if (ui->cshow) { ui->cshow = 0; action = UI; } if (!INGRID(state, x, y)) { ui->show_black_nums = 1 - ui->show_black_nums; action = UI; /* this wants to be a per-game option. */ } else if (button == LEFT_BUTTON) { action = TOGGLE_BLACK; } else if (button == RIGHT_BUTTON) { action = TOGGLE_CIRCLE; } } if (action == UI) return ""; if (action == TOGGLE_BLACK || action == TOGGLE_CIRCLE) { i = y * state->w + x; if (state->flags[i] & (F_BLACK | F_CIRCLE)) c = 'E'; else c = (action == TOGGLE_BLACK) ? 'B' : 'C'; sprintf(buf, "%c%d,%d", (int)c, x, y); return dupstr(buf); } return NULL; } static game_state *execute_move(const game_state *state, const char *move) { game_state *ret = dup_game(state); int x, y, i, n; debug(("move: %s\n", move)); while (*move) { char c = *move; if (c == 'B' || c == 'C' || c == 'E') { move++; if (sscanf(move, "%d,%d%n", &x, &y, &n) != 2 || !INGRID(state, x, y)) goto badmove; i = y*ret->w + x; ret->flags[i] &= ~(F_CIRCLE | F_BLACK); /* empty first, always. */ if (c == 'B') ret->flags[i] |= F_BLACK; else if (c == 'C') ret->flags[i] |= F_CIRCLE; move += n; } else if (c == 'S') { move++; ret->used_solve = 1; } else goto badmove; if (*move == ';') move++; else if (*move) goto badmove; } if (check_complete(ret, CC_MARK_ERRORS)) ret->completed = 1; return ret; badmove: free_game(ret); return NULL; } /* ---------------------------------------------------------------------- * Drawing routines. */ static void game_compute_size(const game_params *params, int tilesize, int *x, int *y) { /* Ick: fake up `ds->tilesize' for macro expansion purposes */ struct { int tilesize; } ads, *ds = &ads; ads.tilesize = tilesize; *x = TILE_SIZE * params->w + 2 * BORDER; *y = TILE_SIZE * params->h + 2 * BORDER; } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { ds->tilesize = tilesize; } static float *game_colours(frontend *fe, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float); int i; game_mkhighlight(fe, ret, COL_BACKGROUND, COL_HIGHLIGHT, COL_LOWLIGHT); for (i = 0; i < 3; i++) { ret[COL_BLACK * 3 + i] = 0.0F; ret[COL_BLACKNUM * 3 + i] = 0.4F; ret[COL_WHITE * 3 + i] = 1.0F; ret[COL_GRID * 3 + i] = ret[COL_LOWLIGHT * 3 + i]; } ret[COL_CURSOR * 3 + 0] = 0.2F; ret[COL_CURSOR * 3 + 1] = 0.8F; ret[COL_CURSOR * 3 + 2] = 0.0F; ret[COL_ERROR * 3 + 0] = 1.0F; ret[COL_ERROR * 3 + 1] = 0.0F; ret[COL_ERROR * 3 + 2] = 0.0F; *ncolours = NCOLOURS; return ret; } static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { struct game_drawstate *ds = snew(struct game_drawstate); ds->tilesize = ds->started = ds->solved = 0; ds->w = state->w; ds->h = state->h; ds->n = state->n; ds->flags = snewn(state->n, unsigned int); memset(ds->flags, 0, state->n*sizeof(unsigned int)); return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { sfree(ds->flags); sfree(ds); } static void tile_redraw(drawing *dr, game_drawstate *ds, int x, int y, int num, unsigned int f) { int tcol, bg, dnum, cx, cy, tsz; char buf[32]; if (f & DS_BLACK) { bg = (f & DS_ERROR) ? COL_ERROR : COL_BLACK; tcol = COL_BLACKNUM; dnum = (f & DS_BLACK_NUM) ? 1 : 0; } else { bg = (f & DS_FLASH) ? COL_LOWLIGHT : COL_BACKGROUND; tcol = (f & DS_ERROR) ? COL_ERROR : COL_BLACK; dnum = 1; } cx = x + TILE_SIZE/2; cy = y + TILE_SIZE/2; draw_rect(dr, x, y, TILE_SIZE, TILE_SIZE, bg); draw_rect_outline(dr, x, y, TILE_SIZE, TILE_SIZE, (f & DS_IMPOSSIBLE) ? COL_ERROR : COL_GRID); if (f & DS_CIRCLE) { draw_circle(dr, cx, cy, CRAD, tcol, tcol); draw_circle(dr, cx, cy, CRAD-1, bg, tcol); } if (dnum) { sprintf(buf, "%d", num); if (strlen(buf) == 1) tsz = TEXTSZ; else tsz = (CRAD*2 - 1) / strlen(buf); draw_text(dr, cx, cy, FONT_VARIABLE, tsz, ALIGN_VCENTRE | ALIGN_HCENTRE, tcol, buf); } if (f & DS_CURSOR) draw_rect_corners(dr, cx, cy, TEXTSZ/2, COL_CURSOR); draw_update(dr, x, y, TILE_SIZE, TILE_SIZE); } static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float animtime, float flashtime) { int x, y, i, flash; unsigned int f; flash = (int)(flashtime * 5 / FLASH_TIME) % 2; if (!ds->started) { int wsz = TILE_SIZE * state->w + 2 * BORDER; int hsz = TILE_SIZE * state->h + 2 * BORDER; draw_rect(dr, 0, 0, wsz, hsz, COL_BACKGROUND); draw_rect_outline(dr, COORD(0)-1, COORD(0)-1, TILE_SIZE * state->w + 2, TILE_SIZE * state->h + 2, COL_GRID); draw_update(dr, 0, 0, wsz, hsz); } for (x = 0; x < state->w; x++) { for (y = 0; y < state->h; y++) { i = y*state->w + x; f = 0; if (flash) f |= DS_FLASH; if (state->impossible) f |= DS_IMPOSSIBLE; if (ui->cshow && x == ui->cx && y == ui->cy) f |= DS_CURSOR; if (state->flags[i] & F_BLACK) { f |= DS_BLACK; if (ui->show_black_nums) f |= DS_BLACK_NUM; } if (state->flags[i] & F_CIRCLE) f |= DS_CIRCLE; if (state->flags[i] & F_ERROR) f |= DS_ERROR; if (!ds->started || ds->flags[i] != f) { tile_redraw(dr, ds, COORD(x), COORD(y), state->nums[i], f); ds->flags[i] = f; } } } ds->started = 1; } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return 0.0F; } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { if (!oldstate->completed && newstate->completed && !newstate->used_solve) return FLASH_TIME; return 0.0F; } static int game_status(const game_state *state) { return state->completed ? +1 : 0; } static int game_timing_state(const game_state *state, game_ui *ui) { return TRUE; } static void game_print_size(const game_params *params, float *x, float *y) { int pw, ph; /* 8mm squares by default. */ game_compute_size(params, 800, &pw, &ph); *x = pw / 100.0F; *y = ph / 100.0F; } static void game_print(drawing *dr, const game_state *state, int tilesize) { int ink = print_mono_colour(dr, 0); int paper = print_mono_colour(dr, 1); int x, y, ox, oy, i; char buf[32]; /* Ick: fake up `ds->tilesize' for macro expansion purposes */ game_drawstate ads, *ds = &ads; game_set_size(dr, ds, NULL, tilesize); print_line_width(dr, 2 * TILE_SIZE / 40); for (x = 0; x < state->w; x++) { for (y = 0; y < state->h; y++) { ox = COORD(x); oy = COORD(y); i = y*state->w+x; if (state->flags[i] & F_BLACK) { draw_rect(dr, ox, oy, TILE_SIZE, TILE_SIZE, ink); } else { draw_rect_outline(dr, ox, oy, TILE_SIZE, TILE_SIZE, ink); if (state->flags[i] & DS_CIRCLE) draw_circle(dr, ox+TILE_SIZE/2, oy+TILE_SIZE/2, CRAD, paper, ink); sprintf(buf, "%d", state->nums[i]); draw_text(dr, ox+TILE_SIZE/2, oy+TILE_SIZE/2, FONT_VARIABLE, TEXTSZ/strlen(buf), ALIGN_VCENTRE | ALIGN_HCENTRE, ink, buf); } } } } #ifdef COMBINED #define thegame singles #endif const struct game thegame = { "Singles", "games.singles", "singles", default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, TRUE, solve_game, TRUE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, PREFERRED_TILE_SIZE, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, TRUE, FALSE, game_print_size, game_print, FALSE, /* wants_statusbar */ FALSE, game_timing_state, REQUIRE_RBUTTON, /* flags */ }; #ifdef STANDALONE_SOLVER #include #include static void start_soak(game_params *p, random_state *rs) { time_t tt_start, tt_now, tt_last; char *desc, *aux; game_state *s; int i, n = 0, ndiff[DIFF_MAX], diff, sret, nblack = 0, nsneaky = 0; tt_start = tt_now = time(NULL); printf("Soak-testing a %dx%d grid.\n", p->w, p->h); p->diff = DIFF_ANY; memset(ndiff, 0, DIFF_MAX * sizeof(int)); while (1) { n++; desc = new_game_desc(p, rs, &aux, 0); s = new_game(NULL, p, desc); nsneaky += solve_sneaky(s, NULL); for (diff = 0; diff < DIFF_MAX; diff++) { memset(s->flags, 0, s->n * sizeof(unsigned int)); s->completed = s->impossible = 0; sret = solve_specific(s, diff, 0); if (sret > 0) { ndiff[diff]++; break; } else if (sret < 0) fprintf(stderr, "Impossible! %s\n", desc); } for (i = 0; i < s->n; i++) { if (s->flags[i] & F_BLACK) nblack++; } free_game(s); sfree(desc); tt_last = time(NULL); if (tt_last > tt_now) { tt_now = tt_last; printf("%d total, %3.1f/s, bl/sn %3.1f%%/%3.1f%%: ", n, (double)n / ((double)tt_now - tt_start), ((double)nblack * 100.0) / (double)(n * p->w * p->h), ((double)nsneaky * 100.0) / (double)(n * p->w * p->h)); for (diff = 0; diff < DIFF_MAX; diff++) { if (diff > 0) printf(", "); printf("%d (%3.1f%%) %s", ndiff[diff], (double)ndiff[diff] * 100.0 / (double)n, singles_diffnames[diff]); } printf("\n"); } } } int main(int argc, char **argv) { char *id = NULL, *desc, *desc_gen = NULL, *tgame, *err, *aux; game_state *s = NULL; game_params *p = NULL; int soln, soak = 0, ret = 1; time_t seed = time(NULL); random_state *rs = NULL; setvbuf(stdout, NULL, _IONBF, 0); while (--argc > 0) { char *p = *++argv; if (!strcmp(p, "-v")) { verbose = 1; } else if (!strcmp(p, "--soak")) { soak = 1; } else if (!strcmp(p, "--seed")) { if (argc == 0) { fprintf(stderr, "%s: --seed needs an argument", argv[0]); goto done; } seed = (time_t)atoi(*++argv); argc--; } else if (*p == '-') { fprintf(stderr, "%s: unrecognised option `%s'\n", argv[0], p); return 1; } else { id = p; } } rs = random_new((void*)&seed, sizeof(time_t)); if (!id) { fprintf(stderr, "usage: %s [-v] [--soak] | \n", argv[0]); goto done; } desc = strchr(id, ':'); if (desc) *desc++ = '\0'; p = default_params(); decode_params(p, id); err = validate_params(p, 1); if (err) { fprintf(stderr, "%s: %s", argv[0], err); goto done; } if (soak) { if (desc) { fprintf(stderr, "%s: --soak only needs params, not game desc.\n", argv[0]); goto done; } start_soak(p, rs); } else { if (!desc) desc = desc_gen = new_game_desc(p, rs, &aux, 0); err = validate_desc(p, desc); if (err) { fprintf(stderr, "%s: %s\n", argv[0], err); free_params(p); goto done; } s = new_game(NULL, p, desc); if (verbose) { tgame = game_text_format(s); fputs(tgame, stdout); sfree(tgame); } soln = solve_specific(s, DIFF_ANY, 0); tgame = game_text_format(s); fputs(tgame, stdout); sfree(tgame); printf("Game was %s.\n\n", soln < 0 ? "impossible" : soln > 0 ? "solved" : "not solved"); } ret = 0; done: if (desc_gen) sfree(desc_gen); if (p) free_params(p); if (s) free_game(s); if (rs) random_free(rs); return ret; } #endif /* vim: set shiftwidth=4 tabstop=8: */ puzzles-20170606.272beef/signpost.c0000644000175000017500000022406013115373615015707 0ustar simonsimon/* * signpost.c: implementation of the janko game 'arrow path' */ #include #include #include #include #include #include #include "puzzles.h" #define PREFERRED_TILE_SIZE 48 #define TILE_SIZE (ds->tilesize) #define BLITTER_SIZE TILE_SIZE #define BORDER (TILE_SIZE / 2) #define COORD(x) ( (x) * TILE_SIZE + BORDER ) #define FROMCOORD(x) ( ((x) - BORDER + TILE_SIZE) / TILE_SIZE - 1 ) #define INGRID(s,x,y) ((x) >= 0 && (x) < (s)->w && (y) >= 0 && (y) < (s)->h) #define FLASH_SPIN 0.7F #define NBACKGROUNDS 16 enum { COL_BACKGROUND, COL_HIGHLIGHT, COL_LOWLIGHT, COL_GRID, COL_CURSOR, COL_ERROR, COL_DRAG_ORIGIN, COL_ARROW, COL_ARROW_BG_DIM, COL_NUMBER, COL_NUMBER_SET, COL_NUMBER_SET_MID, COL_B0, /* background colours */ COL_M0 = COL_B0 + 1*NBACKGROUNDS, /* mid arrow colours */ COL_D0 = COL_B0 + 2*NBACKGROUNDS, /* dim arrow colours */ COL_X0 = COL_B0 + 3*NBACKGROUNDS, /* dim arrow colours */ NCOLOURS = COL_B0 + 4*NBACKGROUNDS }; struct game_params { int w, h; int force_corner_start; }; enum { DIR_N = 0, DIR_NE, DIR_E, DIR_SE, DIR_S, DIR_SW, DIR_W, DIR_NW, DIR_MAX }; static const char *dirstrings[8] = { "N ", "NE", "E ", "SE", "S ", "SW", "W ", "NW" }; static const int dxs[DIR_MAX] = { 0, 1, 1, 1, 0, -1, -1, -1 }; static const int dys[DIR_MAX] = { -1, -1, 0, 1, 1, 1, 0, -1 }; #define DIR_OPPOSITE(d) ((d+4)%8) struct game_state { int w, h, n; int completed, used_solve, impossible; int *dirs; /* direction enums, size n */ int *nums; /* numbers, size n */ unsigned int *flags; /* flags, size n */ int *next, *prev; /* links to other cell indexes, size n (-1 absent) */ int *dsf; /* connects regions with a dsf. */ int *numsi; /* for each number, which index is it in? (-1 absent) */ }; #define FLAG_IMMUTABLE 1 #define FLAG_ERROR 2 /* --- Generally useful functions --- */ #define ISREALNUM(state, num) ((num) > 0 && (num) <= (state)->n) static int whichdir(int fromx, int fromy, int tox, int toy) { int i, dx, dy; dx = tox - fromx; dy = toy - fromy; if (dx && dy && abs(dx) != abs(dy)) return -1; if (dx) dx = dx / abs(dx); /* limit to (-1, 0, 1) */ if (dy) dy = dy / abs(dy); /* ditto */ for (i = 0; i < DIR_MAX; i++) { if (dx == dxs[i] && dy == dys[i]) return i; } return -1; } static int whichdiri(game_state *state, int fromi, int toi) { int w = state->w; return whichdir(fromi%w, fromi/w, toi%w, toi/w); } static int ispointing(const game_state *state, int fromx, int fromy, int tox, int toy) { int w = state->w, dir = state->dirs[fromy*w+fromx]; /* (by convention) squares do not point to themselves. */ if (fromx == tox && fromy == toy) return 0; /* the final number points to nothing. */ if (state->nums[fromy*w + fromx] == state->n) return 0; while (1) { if (!INGRID(state, fromx, fromy)) return 0; if (fromx == tox && fromy == toy) return 1; fromx += dxs[dir]; fromy += dys[dir]; } return 0; /* not reached */ } static int ispointingi(game_state *state, int fromi, int toi) { int w = state->w; return ispointing(state, fromi%w, fromi/w, toi%w, toi/w); } /* Taking the number 'num', work out the gap between it and the next * available number up or down (depending on d). Return 1 if the region * at (x,y) will fit in that gap, or 0 otherwise. */ static int move_couldfit(const game_state *state, int num, int d, int x, int y) { int n, gap, i = y*state->w+x, sz; assert(d != 0); /* The 'gap' is the number of missing numbers in the grid between * our number and the next one in the sequence (up or down), or * the end of the sequence (if we happen not to have 1/n present) */ for (n = num + d, gap = 0; ISREALNUM(state, n) && state->numsi[n] == -1; n += d, gap++) ; /* empty loop */ if (gap == 0) { /* no gap, so the only allowable move is that that directly * links the two numbers. */ n = state->nums[i]; return (n == num+d) ? 0 : 1; } if (state->prev[i] == -1 && state->next[i] == -1) return 1; /* single unconnected square, always OK */ sz = dsf_size(state->dsf, i); return (sz > gap) ? 0 : 1; } static int isvalidmove(const game_state *state, int clever, int fromx, int fromy, int tox, int toy) { int w = state->w, from = fromy*w+fromx, to = toy*w+tox; int nfrom, nto; if (!INGRID(state, fromx, fromy) || !INGRID(state, tox, toy)) return 0; /* can only move where we point */ if (!ispointing(state, fromx, fromy, tox, toy)) return 0; nfrom = state->nums[from]; nto = state->nums[to]; /* can't move _from_ the preset final number, or _to_ the preset 1. */ if (((nfrom == state->n) && (state->flags[from] & FLAG_IMMUTABLE)) || ((nto == 1) && (state->flags[to] & FLAG_IMMUTABLE))) return 0; /* can't create a new connection between cells in the same region * as that would create a loop. */ if (dsf_canonify(state->dsf, from) == dsf_canonify(state->dsf, to)) return 0; /* if both cells are actual numbers, can't drag if we're not * one digit apart. */ if (ISREALNUM(state, nfrom) && ISREALNUM(state, nto)) { if (nfrom != nto-1) return 0; } else if (clever && ISREALNUM(state, nfrom)) { if (!move_couldfit(state, nfrom, +1, tox, toy)) return 0; } else if (clever && ISREALNUM(state, nto)) { if (!move_couldfit(state, nto, -1, fromx, fromy)) return 0; } return 1; } static void makelink(game_state *state, int from, int to) { if (state->next[from] != -1) state->prev[state->next[from]] = -1; state->next[from] = to; if (state->prev[to] != -1) state->next[state->prev[to]] = -1; state->prev[to] = from; } static int game_can_format_as_text_now(const game_params *params) { if (params->w * params->h >= 100) return 0; return 1; } static char *game_text_format(const game_state *state) { int len = state->h * 2 * (4*state->w + 1) + state->h + 2; int x, y, i, num, n, set; char *ret, *p; p = ret = snewn(len, char); for (y = 0; y < state->h; y++) { for (x = 0; x < state->h; x++) { i = y*state->w+x; *p++ = dirstrings[state->dirs[i]][0]; *p++ = dirstrings[state->dirs[i]][1]; *p++ = (state->flags[i] & FLAG_IMMUTABLE) ? 'I' : ' '; *p++ = ' '; } *p++ = '\n'; for (x = 0; x < state->h; x++) { i = y*state->w+x; num = state->nums[i]; if (num == 0) { *p++ = ' '; *p++ = ' '; *p++ = ' '; } else { n = num % (state->n+1); set = num / (state->n+1); assert(n <= 99); /* two digits only! */ if (set != 0) *p++ = set+'a'-1; *p++ = (n >= 10) ? ('0' + (n/10)) : ' '; *p++ = '0' + (n%10); if (set == 0) *p++ = ' '; } *p++ = ' '; } *p++ = '\n'; *p++ = '\n'; } *p++ = '\0'; return ret; } static void debug_state(const char *desc, game_state *state) { #ifdef DEBUGGING char *dbg; if (state->n >= 100) { debug(("[ no game_text_format for this size ]")); return; } dbg = game_text_format(state); debug(("%s\n%s", desc, dbg)); sfree(dbg); #endif } static void strip_nums(game_state *state) { int i; for (i = 0; i < state->n; i++) { if (!(state->flags[i] & FLAG_IMMUTABLE)) state->nums[i] = 0; } memset(state->next, -1, state->n*sizeof(int)); memset(state->prev, -1, state->n*sizeof(int)); memset(state->numsi, -1, (state->n+1)*sizeof(int)); dsf_init(state->dsf, state->n); } static int check_nums(game_state *orig, game_state *copy, int only_immutable) { int i, ret = 1; assert(copy->n == orig->n); for (i = 0; i < copy->n; i++) { if (only_immutable && !(copy->flags[i] & FLAG_IMMUTABLE)) continue; assert(copy->nums[i] >= 0); assert(copy->nums[i] <= copy->n); if (copy->nums[i] != orig->nums[i]) { debug(("check_nums: (%d,%d) copy=%d, orig=%d.", i%orig->w, i/orig->w, copy->nums[i], orig->nums[i])); ret = 0; } } return ret; } /* --- Game parameter/presets functions --- */ static game_params *default_params(void) { game_params *ret = snew(game_params); ret->w = ret->h = 4; ret->force_corner_start = 1; return ret; } static const struct game_params signpost_presets[] = { { 4, 4, 1 }, { 4, 4, 0 }, { 5, 5, 1 }, { 5, 5, 0 }, { 6, 6, 1 }, { 7, 7, 1 } }; static int game_fetch_preset(int i, char **name, game_params **params) { game_params *ret; char buf[80]; if (i < 0 || i >= lenof(signpost_presets)) return FALSE; ret = default_params(); *ret = signpost_presets[i]; *params = ret; sprintf(buf, "%dx%d%s", ret->w, ret->h, ret->force_corner_start ? "" : ", free ends"); *name = dupstr(buf); return TRUE; } static void free_params(game_params *params) { sfree(params); } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } static void decode_params(game_params *ret, char const *string) { ret->w = ret->h = atoi(string); while (*string && isdigit((unsigned char)*string)) string++; if (*string == 'x') { string++; ret->h = atoi(string); while (*string && isdigit((unsigned char)*string)) string++; } ret->force_corner_start = 0; if (*string == 'c') { string++; ret->force_corner_start = 1; } } static char *encode_params(const game_params *params, int full) { char data[256]; if (full) sprintf(data, "%dx%d%s", params->w, params->h, params->force_corner_start ? "c" : ""); else sprintf(data, "%dx%d", params->w, params->h); return dupstr(data); } static config_item *game_configure(const game_params *params) { config_item *ret; char buf[80]; ret = snewn(4, config_item); ret[0].name = "Width"; ret[0].type = C_STRING; sprintf(buf, "%d", params->w); ret[0].sval = dupstr(buf); ret[0].ival = 0; ret[1].name = "Height"; ret[1].type = C_STRING; sprintf(buf, "%d", params->h); ret[1].sval = dupstr(buf); ret[1].ival = 0; ret[2].name = "Start and end in corners"; ret[2].type = C_BOOLEAN; ret[2].sval = NULL; ret[2].ival = params->force_corner_start; ret[3].name = NULL; ret[3].type = C_END; ret[3].sval = NULL; ret[3].ival = 0; return ret; } static game_params *custom_params(const config_item *cfg) { game_params *ret = snew(game_params); ret->w = atoi(cfg[0].sval); ret->h = atoi(cfg[1].sval); ret->force_corner_start = cfg[2].ival; return ret; } static char *validate_params(const game_params *params, int full) { if (params->w < 1) return "Width must be at least one"; if (params->h < 1) return "Height must be at least one"; if (full && params->w == 1 && params->h == 1) /* The UI doesn't let us move these from unsolved to solved, * so we disallow generating (but not playing) them. */ return "Width and height cannot both be one"; return NULL; } /* --- Game description string generation and unpicking --- */ static void blank_game_into(game_state *state) { memset(state->dirs, 0, state->n*sizeof(int)); memset(state->nums, 0, state->n*sizeof(int)); memset(state->flags, 0, state->n*sizeof(unsigned int)); memset(state->next, -1, state->n*sizeof(int)); memset(state->prev, -1, state->n*sizeof(int)); memset(state->numsi, -1, (state->n+1)*sizeof(int)); } static game_state *blank_game(int w, int h) { game_state *state = snew(game_state); memset(state, 0, sizeof(game_state)); state->w = w; state->h = h; state->n = w*h; state->dirs = snewn(state->n, int); state->nums = snewn(state->n, int); state->flags = snewn(state->n, unsigned int); state->next = snewn(state->n, int); state->prev = snewn(state->n, int); state->dsf = snew_dsf(state->n); state->numsi = snewn(state->n+1, int); blank_game_into(state); return state; } static void dup_game_to(game_state *to, const game_state *from) { to->completed = from->completed; to->used_solve = from->used_solve; to->impossible = from->impossible; memcpy(to->dirs, from->dirs, to->n*sizeof(int)); memcpy(to->flags, from->flags, to->n*sizeof(unsigned int)); memcpy(to->nums, from->nums, to->n*sizeof(int)); memcpy(to->next, from->next, to->n*sizeof(int)); memcpy(to->prev, from->prev, to->n*sizeof(int)); memcpy(to->dsf, from->dsf, to->n*sizeof(int)); memcpy(to->numsi, from->numsi, (to->n+1)*sizeof(int)); } static game_state *dup_game(const game_state *state) { game_state *ret = blank_game(state->w, state->h); dup_game_to(ret, state); return ret; } static void free_game(game_state *state) { sfree(state->dirs); sfree(state->nums); sfree(state->flags); sfree(state->next); sfree(state->prev); sfree(state->dsf); sfree(state->numsi); sfree(state); } static void unpick_desc(const game_params *params, const char *desc, game_state **sout, char **mout) { game_state *state = blank_game(params->w, params->h); char *msg = NULL, c; int num = 0, i = 0; while (*desc) { if (i >= state->n) { msg = "Game description longer than expected"; goto done; } c = *desc; if (isdigit((unsigned char)c)) { num = (num*10) + (int)(c-'0'); if (num > state->n) { msg = "Number too large"; goto done; } } else if ((c-'a') >= 0 && (c-'a') < DIR_MAX) { state->nums[i] = num; state->flags[i] = num ? FLAG_IMMUTABLE : 0; num = 0; state->dirs[i] = c - 'a'; i++; } else if (!*desc) { msg = "Game description shorter than expected"; goto done; } else { msg = "Game description contains unexpected characters"; goto done; } desc++; } if (i < state->n) { msg = "Game description shorter than expected"; goto done; } done: if (msg) { /* sth went wrong. */ if (mout) *mout = msg; free_game(state); } else { if (mout) *mout = NULL; if (sout) *sout = state; else free_game(state); } } static char *generate_desc(game_state *state, int issolve) { char *ret, buf[80]; int retlen, i, k; ret = NULL; retlen = 0; if (issolve) { ret = sresize(ret, 2, char); ret[0] = 'S'; ret[1] = '\0'; retlen += 1; } for (i = 0; i < state->n; i++) { if (state->nums[i]) k = sprintf(buf, "%d%c", state->nums[i], (int)(state->dirs[i]+'a')); else k = sprintf(buf, "%c", (int)(state->dirs[i]+'a')); ret = sresize(ret, retlen + k + 1, char); strcpy(ret + retlen, buf); retlen += k; } return ret; } /* --- Game generation --- */ /* Fills in preallocated arrays ai (indices) and ad (directions) * showing all non-numbered cells adjacent to index i, returns length */ /* This function has been somewhat optimised... */ static int cell_adj(game_state *state, int i, int *ai, int *ad) { int n = 0, a, x, y, sx, sy, dx, dy, newi; int w = state->w, h = state->h; sx = i % w; sy = i / w; for (a = 0; a < DIR_MAX; a++) { x = sx; y = sy; dx = dxs[a]; dy = dys[a]; while (1) { x += dx; y += dy; if (x < 0 || y < 0 || x >= w || y >= h) break; newi = y*w + x; if (state->nums[newi] == 0) { ai[n] = newi; ad[n] = a; n++; } } } return n; } static int new_game_fill(game_state *state, random_state *rs, int headi, int taili) { int nfilled, an, ret = 0, j; int *aidx, *adir; aidx = snewn(state->n, int); adir = snewn(state->n, int); debug(("new_game_fill: headi=%d, taili=%d.", headi, taili)); memset(state->nums, 0, state->n*sizeof(int)); state->nums[headi] = 1; state->nums[taili] = state->n; state->dirs[taili] = 0; nfilled = 2; assert(state->n > 1); while (nfilled < state->n) { /* Try and expand _from_ headi; keep going if there's only one * place to go to. */ an = cell_adj(state, headi, aidx, adir); do { if (an == 0) goto done; j = random_upto(rs, an); state->dirs[headi] = adir[j]; state->nums[aidx[j]] = state->nums[headi] + 1; nfilled++; headi = aidx[j]; an = cell_adj(state, headi, aidx, adir); } while (an == 1); if (nfilled == state->n) break; /* Try and expand _to_ taili; keep going if there's only one * place to go to. */ an = cell_adj(state, taili, aidx, adir); do { if (an == 0) goto done; j = random_upto(rs, an); state->dirs[aidx[j]] = DIR_OPPOSITE(adir[j]); state->nums[aidx[j]] = state->nums[taili] - 1; nfilled++; taili = aidx[j]; an = cell_adj(state, taili, aidx, adir); } while (an == 1); } /* If we get here we have headi and taili set but unconnected * by direction: we need to set headi's direction so as to point * at taili. */ state->dirs[headi] = whichdiri(state, headi, taili); /* it could happen that our last two weren't in line; if that's the * case, we have to start again. */ if (state->dirs[headi] != -1) ret = 1; done: sfree(aidx); sfree(adir); return ret; } /* Better generator: with the 'generate, sprinkle numbers, solve, * repeat' algorithm we're _never_ generating anything greater than * 6x6, and spending all of our time in new_game_fill (and very little * in solve_state). * * So, new generator steps: * generate the grid, at random (same as now). Numbers 1 and N get immutable flag immediately. * squirrel that away for the solved state. * * (solve:) Try and solve it. * If we solved it, we're done: * generate the description from current immutable numbers, * free stuff that needs freeing, * return description + solved state. * If we didn't solve it: * count #tiles in state we've made deductions about. * while (1): * randomise a scratch array. * for each index in scratch (in turn): * if the cell isn't empty, continue (through scratch array) * set number + immutable in state. * try and solve state. * if we've solved it, we're done. * otherwise, count #tiles. If it's more than we had before: * good, break from this loop and re-randomise. * otherwise (number didn't help): * remove number and try next in scratch array. * if we've got to the end of the scratch array, no luck: free everything we need to, and go back to regenerate the grid. */ static int solve_state(game_state *state); static void debug_desc(const char *what, game_state *state) { #if DEBUGGING { char *desc = generate_desc(state, 0); debug(("%s game state: %dx%d:%s", what, state->w, state->h, desc)); sfree(desc); } #endif } /* Expects a fully-numbered game_state on input, and makes sure * FLAG_IMMUTABLE is only set on those numbers we need to solve * (as for a real new-game); returns 1 if it managed * this (such that it could solve it), or 0 if not. */ static int new_game_strip(game_state *state, random_state *rs) { int *scratch, i, j, ret = 1; game_state *copy = dup_game(state); debug(("new_game_strip.")); strip_nums(copy); debug_desc("Stripped", copy); if (solve_state(copy) > 0) { debug(("new_game_strip: soluble immediately after strip.")); free_game(copy); return 1; } scratch = snewn(state->n, int); for (i = 0; i < state->n; i++) scratch[i] = i; shuffle(scratch, state->n, sizeof(int), rs); /* This is scungy. It might just be quick enough. * It goes through, adding set numbers in empty squares * until either we run out of empty squares (in the one * we're half-solving) or else we solve it properly. * NB that we run the entire solver each time, which * strips the grid beforehand; we will save time if we * avoid that. */ for (i = 0; i < state->n; i++) { j = scratch[i]; if (copy->nums[j] > 0 && copy->nums[j] <= state->n) continue; /* already solved to a real number here. */ assert(state->nums[j] <= state->n); debug(("new_game_strip: testing add IMMUTABLE number %d at square (%d,%d).", state->nums[j], j%state->w, j/state->w)); copy->nums[j] = state->nums[j]; copy->flags[j] |= FLAG_IMMUTABLE; state->flags[j] |= FLAG_IMMUTABLE; debug_state("Copy of state: ", copy); strip_nums(copy); if (solve_state(copy) > 0) goto solved; assert(check_nums(state, copy, 1)); } ret = 0; goto done; solved: debug(("new_game_strip: now solved.")); /* Since we added basically at random, try now to remove numbers * and see if we can still solve it; if we can (still), really * remove the number. Make sure we don't remove the anchor numbers * 1 and N. */ for (i = 0; i < state->n; i++) { j = scratch[i]; if ((state->flags[j] & FLAG_IMMUTABLE) && (state->nums[j] != 1 && state->nums[j] != state->n)) { debug(("new_game_strip: testing remove IMMUTABLE number %d at square (%d,%d).", state->nums[j], j%state->w, j/state->w)); state->flags[j] &= ~FLAG_IMMUTABLE; dup_game_to(copy, state); strip_nums(copy); if (solve_state(copy) > 0) { assert(check_nums(state, copy, 0)); debug(("new_game_strip: OK, removing number")); } else { assert(state->nums[j] <= state->n); debug(("new_game_strip: cannot solve, putting IMMUTABLE back.")); copy->nums[j] = state->nums[j]; state->flags[j] |= FLAG_IMMUTABLE; } } } done: debug(("new_game_strip: %ssuccessful.", ret ? "" : "not ")); sfree(scratch); free_game(copy); return ret; } static char *new_game_desc(const game_params *params, random_state *rs, char **aux, int interactive) { game_state *state = blank_game(params->w, params->h); char *ret; int headi, taili; /* this shouldn't happen (validate_params), but let's play it safe */ if (params->w == 1 && params->h == 1) return dupstr("1a"); generate: blank_game_into(state); /* keep trying until we fill successfully. */ do { if (params->force_corner_start) { headi = 0; taili = state->n-1; } else { do { headi = random_upto(rs, state->n); taili = random_upto(rs, state->n); } while (headi == taili); } } while (!new_game_fill(state, rs, headi, taili)); debug_state("Filled game:", state); assert(state->nums[headi] <= state->n); assert(state->nums[taili] <= state->n); state->flags[headi] |= FLAG_IMMUTABLE; state->flags[taili] |= FLAG_IMMUTABLE; /* This will have filled in directions and _all_ numbers. * Store the game definition for this, as the solved-state. */ if (!new_game_strip(state, rs)) { goto generate; } strip_nums(state); { game_state *tosolve = dup_game(state); assert(solve_state(tosolve) > 0); free_game(tosolve); } ret = generate_desc(state, 0); free_game(state); return ret; } static char *validate_desc(const game_params *params, const char *desc) { char *ret = NULL; unpick_desc(params, desc, NULL, &ret); return ret; } /* --- Linked-list and numbers array --- */ /* Assuming numbers are always up-to-date, there are only four possibilities * for regions changing after a single valid move: * * 1) two differently-coloured regions being combined (the resulting colouring * should be based on the larger of the two regions) * 2) a numbered region having a single number added to the start (the * region's colour will remain, and the numbers will shift by 1) * 3) a numbered region having a single number added to the end (the * region's colour and numbering remains as-is) * 4) two unnumbered squares being joined (will pick the smallest unused set * of colours to use for the new region). * * There should never be any complications with regions containing 3 colours * being combined, since two of those colours should have been merged on a * previous move. * * Most of the complications are in ensuring we don't accidentally set two * regions with the same colour (e.g. if a region was split). If this happens * we always try and give the largest original portion the original colour. */ #define COLOUR(a) ((a) / (state->n+1)) #define START(c) ((c) * (state->n+1)) struct head_meta { int i; /* position */ int sz; /* size of region */ int start; /* region start number preferred, or 0 if !preference */ int preference; /* 0 if we have no preference (and should just pick one) */ const char *why; }; static void head_number(game_state *state, int i, struct head_meta *head) { int off = 0, ss, j = i, c, n, sz; /* Insist we really were passed the head of a chain. */ assert(state->prev[i] == -1 && state->next[i] != -1); head->i = i; head->sz = dsf_size(state->dsf, i); head->why = NULL; /* Search through this chain looking for real numbers, checking that * they match up (if there are more than one). */ head->preference = 0; while (j != -1) { if (state->flags[j] & FLAG_IMMUTABLE) { ss = state->nums[j] - off; if (!head->preference) { head->start = ss; head->preference = 1; head->why = "contains cell with immutable number"; } else if (head->start != ss) { debug(("head_number: chain with non-sequential numbers!")); state->impossible = 1; } } off++; j = state->next[j]; assert(j != i); /* we have created a loop, obviously wrong */ } if (head->preference) goto done; if (state->nums[i] == 0 && state->nums[state->next[i]] > state->n) { /* (probably) empty cell onto the head of a coloured region: * make sure we start at a 0 offset. */ head->start = START(COLOUR(state->nums[state->next[i]])); head->preference = 1; head->why = "adding blank cell to head of numbered region"; } else if (state->nums[i] <= state->n) { /* if we're 0 we're probably just blank -- but even if we're a * (real) numbered region, we don't have an immutable number * in it (any more) otherwise it'd have been caught above, so * reassign the colour. */ head->start = 0; head->preference = 0; head->why = "lowest available colour group"; } else { c = COLOUR(state->nums[i]); n = 1; sz = dsf_size(state->dsf, i); j = i; while (state->next[j] != -1) { j = state->next[j]; if (state->nums[j] == 0 && state->next[j] == -1) { head->start = START(c); head->preference = 1; head->why = "adding blank cell to end of numbered region"; goto done; } if (COLOUR(state->nums[j]) == c) n++; else { int start_alternate = START(COLOUR(state->nums[j])); if (n < (sz - n)) { head->start = start_alternate; head->preference = 1; head->why = "joining two coloured regions, swapping to larger colour"; } else { head->start = START(c); head->preference = 1; head->why = "joining two coloured regions, taking largest"; } goto done; } } /* If we got here then we may have split a region into * two; make sure we don't assign a colour we've already used. */ if (c == 0) { /* not convinced this shouldn't be an assertion failure here. */ head->start = 0; head->preference = 0; } else { head->start = START(c); head->preference = 1; } head->why = "got to end of coloured region"; } done: assert(head->why != NULL); if (head->preference) debug(("Chain at (%d,%d) numbered for preference at %d (colour %d): %s.", head->i%state->w, head->i/state->w, head->start, COLOUR(head->start), head->why)); else debug(("Chain at (%d,%d) using next available colour: %s.", head->i%state->w, head->i/state->w, head->why)); } #if 0 static void debug_numbers(game_state *state) { int i, w=state->w; for (i = 0; i < state->n; i++) { debug(("(%d,%d) --> (%d,%d) --> (%d,%d)", state->prev[i]==-1 ? -1 : state->prev[i]%w, state->prev[i]==-1 ? -1 : state->prev[i]/w, i%w, i/w, state->next[i]==-1 ? -1 : state->next[i]%w, state->next[i]==-1 ? -1 : state->next[i]/w)); } w = w+1; } #endif static void connect_numbers(game_state *state) { int i, di, dni; dsf_init(state->dsf, state->n); for (i = 0; i < state->n; i++) { if (state->next[i] != -1) { assert(state->prev[state->next[i]] == i); di = dsf_canonify(state->dsf, i); dni = dsf_canonify(state->dsf, state->next[i]); if (di == dni) { debug(("connect_numbers: chain forms a loop.")); state->impossible = 1; } dsf_merge(state->dsf, di, dni); } } } static int compare_heads(const void *a, const void *b) { struct head_meta *ha = (struct head_meta *)a; struct head_meta *hb = (struct head_meta *)b; /* Heads with preferred colours first... */ if (ha->preference && !hb->preference) return -1; if (hb->preference && !ha->preference) return 1; /* ...then heads with low colours first... */ if (ha->start < hb->start) return -1; if (ha->start > hb->start) return 1; /* ... then large regions first... */ if (ha->sz > hb->sz) return -1; if (ha->sz < hb->sz) return 1; /* ... then position. */ if (ha->i > hb->i) return -1; if (ha->i < hb->i) return 1; return 0; } static int lowest_start(game_state *state, struct head_meta *heads, int nheads) { int n, c; /* NB start at 1: colour 0 is real numbers */ for (c = 1; c < state->n; c++) { for (n = 0; n < nheads; n++) { if (COLOUR(heads[n].start) == c) goto used; } return c; used: ; } assert(!"No available colours!"); return 0; } static void update_numbers(game_state *state) { int i, j, n, nnum, nheads; struct head_meta *heads = snewn(state->n, struct head_meta); for (n = 0; n < state->n; n++) state->numsi[n] = -1; for (i = 0; i < state->n; i++) { if (state->flags[i] & FLAG_IMMUTABLE) { assert(state->nums[i] > 0); assert(state->nums[i] <= state->n); state->numsi[state->nums[i]] = i; } else if (state->prev[i] == -1 && state->next[i] == -1) state->nums[i] = 0; } connect_numbers(state); /* Construct an array of the heads of all current regions, together * with their preferred colours. */ nheads = 0; for (i = 0; i < state->n; i++) { /* Look for a cell that is the start of a chain * (has a next but no prev). */ if (state->prev[i] != -1 || state->next[i] == -1) continue; head_number(state, i, &heads[nheads++]); } /* Sort that array: * - heads with preferred colours first, then * - heads with low colours first, then * - large regions first */ qsort(heads, nheads, sizeof(struct head_meta), compare_heads); /* Remove duplicate-coloured regions. */ for (n = nheads-1; n >= 0; n--) { /* order is important! */ if ((n != 0) && (heads[n].start == heads[n-1].start)) { /* We have a duplicate-coloured region: since we're * sorted in size order and this is not the first * of its colour it's not the largest: recolour it. */ heads[n].start = START(lowest_start(state, heads, nheads)); heads[n].preference = -1; /* '-1' means 'was duplicate' */ } else if (!heads[n].preference) { assert(heads[n].start == 0); heads[n].start = START(lowest_start(state, heads, nheads)); } } debug(("Region colouring after duplicate removal:")); for (n = 0; n < nheads; n++) { debug((" Chain at (%d,%d) sz %d numbered at %d (colour %d): %s%s", heads[n].i % state->w, heads[n].i / state->w, heads[n].sz, heads[n].start, COLOUR(heads[n].start), heads[n].why, heads[n].preference == 0 ? " (next available)" : heads[n].preference < 0 ? " (duplicate, next available)" : "")); nnum = heads[n].start; j = heads[n].i; while (j != -1) { if (!(state->flags[j] & FLAG_IMMUTABLE)) { if (nnum > 0 && nnum <= state->n) state->numsi[nnum] = j; state->nums[j] = nnum; } nnum++; j = state->next[j]; assert(j != heads[n].i); /* loop?! */ } } /*debug_numbers(state);*/ sfree(heads); } static int check_completion(game_state *state, int mark_errors) { int n, j, k, error = 0, complete; /* NB This only marks errors that are possible to perpetrate with * the current UI in interpret_move. Things like forming loops in * linked sections and having numbers not add up should be forbidden * by the code elsewhere, so we don't bother marking those (because * it would add lots of tricky drawing code for very little gain). */ if (mark_errors) { for (j = 0; j < state->n; j++) state->flags[j] &= ~FLAG_ERROR; } /* Search for repeated numbers. */ for (j = 0; j < state->n; j++) { if (state->nums[j] > 0 && state->nums[j] <= state->n) { for (k = j+1; k < state->n; k++) { if (state->nums[k] == state->nums[j]) { if (mark_errors) { state->flags[j] |= FLAG_ERROR; state->flags[k] |= FLAG_ERROR; } error = 1; } } } } /* Search and mark numbers n not pointing to n+1; if any numbers * are missing we know we've not completed. */ complete = 1; for (n = 1; n < state->n; n++) { if (state->numsi[n] == -1 || state->numsi[n+1] == -1) complete = 0; else if (!ispointingi(state, state->numsi[n], state->numsi[n+1])) { if (mark_errors) { state->flags[state->numsi[n]] |= FLAG_ERROR; state->flags[state->numsi[n+1]] |= FLAG_ERROR; } error = 1; } else { /* make sure the link is explicitly made here; for instance, this * is nice if the user drags from 2 out (making 3) and a 4 is also * visible; this ensures that the link from 3 to 4 is also made. */ if (mark_errors) makelink(state, state->numsi[n], state->numsi[n+1]); } } /* Search and mark numbers less than 0, or 0 with links. */ for (n = 1; n < state->n; n++) { if ((state->nums[n] < 0) || (state->nums[n] == 0 && (state->next[n] != -1 || state->prev[n] != -1))) { error = 1; if (mark_errors) state->flags[n] |= FLAG_ERROR; } } if (error) return 0; return complete; } static game_state *new_game(midend *me, const game_params *params, const char *desc) { game_state *state = NULL; unpick_desc(params, desc, &state, NULL); if (!state) assert(!"new_game failed to unpick"); update_numbers(state); check_completion(state, 1); /* update any auto-links */ return state; } /* --- Solver --- */ /* If a tile has a single tile it can link _to_, or there's only a single * location that can link to a given tile, fill that link in. */ static int solve_single(game_state *state, game_state *copy, int *from) { int i, j, sx, sy, x, y, d, poss, w=state->w, nlinks = 0; /* The from array is a list of 'which square can link _to_ us'; * we start off with from as '-1' (meaning 'not found'); if we find * something that can link to us it is set to that index, and then if * we find another we set it to -2. */ memset(from, -1, state->n*sizeof(int)); /* poss is 'can I link to anything' with the same meanings. */ for (i = 0; i < state->n; i++) { if (state->next[i] != -1) continue; if (state->nums[i] == state->n) continue; /* no next from last no. */ d = state->dirs[i]; poss = -1; sx = x = i%w; sy = y = i/w; while (1) { x += dxs[d]; y += dys[d]; if (!INGRID(state, x, y)) break; if (!isvalidmove(state, 1, sx, sy, x, y)) continue; /* can't link to somewhere with a back-link we would have to * break (the solver just doesn't work like this). */ j = y*w+x; if (state->prev[j] != -1) continue; if (state->nums[i] > 0 && state->nums[j] > 0 && state->nums[i] <= state->n && state->nums[j] <= state->n && state->nums[j] == state->nums[i]+1) { debug(("Solver: forcing link through existing consecutive numbers.")); poss = j; from[j] = i; break; } /* if there's been a valid move already, we have to move on; * we can't make any deductions here. */ poss = (poss == -1) ? j : -2; /* Modify the from array as described above (which is enumerating * what points to 'j' in a similar way). */ from[j] = (from[j] == -1) ? i : -2; } if (poss == -2) { /*debug(("Solver: (%d,%d) has multiple possible next squares.", sx, sy));*/ ; } else if (poss == -1) { debug(("Solver: nowhere possible for (%d,%d) to link to.", sx, sy)); copy->impossible = 1; return -1; } else { debug(("Solver: linking (%d,%d) to only possible next (%d,%d).", sx, sy, poss%w, poss/w)); makelink(copy, i, poss); nlinks++; } } for (i = 0; i < state->n; i++) { if (state->prev[i] != -1) continue; if (state->nums[i] == 1) continue; /* no prev from 1st no. */ x = i%w; y = i/w; if (from[i] == -1) { debug(("Solver: nowhere possible to link to (%d,%d)", x, y)); copy->impossible = 1; return -1; } else if (from[i] == -2) { /*debug(("Solver: (%d,%d) has multiple possible prev squares.", x, y));*/ ; } else { debug(("Solver: linking only possible prev (%d,%d) to (%d,%d).", from[i]%w, from[i]/w, x, y)); makelink(copy, from[i], i); nlinks++; } } return nlinks; } /* Returns 1 if we managed to solve it, 0 otherwise. */ static int solve_state(game_state *state) { game_state *copy = dup_game(state); int *scratch = snewn(state->n, int), ret; debug_state("Before solver: ", state); while (1) { update_numbers(state); if (solve_single(state, copy, scratch)) { dup_game_to(state, copy); if (state->impossible) break; else continue; } break; } free_game(copy); sfree(scratch); update_numbers(state); ret = state->impossible ? -1 : check_completion(state, 0); debug(("Solver finished: %s", ret < 0 ? "impossible" : ret > 0 ? "solved" : "not solved")); debug_state("After solver: ", state); return ret; } static char *solve_game(const game_state *state, const game_state *currstate, const char *aux, char **error) { game_state *tosolve; char *ret = NULL; int result; tosolve = dup_game(currstate); result = solve_state(tosolve); if (result > 0) ret = generate_desc(tosolve, 1); free_game(tosolve); if (ret) return ret; tosolve = dup_game(state); result = solve_state(tosolve); if (result < 0) *error = "Puzzle is impossible."; else if (result == 0) *error = "Unable to solve puzzle."; else ret = generate_desc(tosolve, 1); free_game(tosolve); return ret; } /* --- UI and move routines. --- */ struct game_ui { int cx, cy, cshow; int dragging, drag_is_from; int sx, sy; /* grid coords of start cell */ int dx, dy; /* pixel coords of drag posn */ }; static game_ui *new_ui(const game_state *state) { game_ui *ui = snew(game_ui); /* NB: if this is ever changed to as to require more than a structure * copy to clone, there's code that needs fixing in game_redraw too. */ ui->cx = ui->cy = ui->cshow = 0; ui->dragging = 0; ui->sx = ui->sy = ui->dx = ui->dy = 0; return ui; } static void free_ui(game_ui *ui) { sfree(ui); } static char *encode_ui(const game_ui *ui) { return NULL; } static void decode_ui(game_ui *ui, const char *encoding) { } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { if (!oldstate->completed && newstate->completed) ui->cshow = ui->dragging = 0; } struct game_drawstate { int tilesize, started, solved; int w, h, n; int *nums, *dirp; unsigned int *f; double angle_offset; int dragging, dx, dy; blitter *dragb; }; static char *interpret_move(const game_state *state, game_ui *ui, const game_drawstate *ds, int mx, int my, int button) { int x = FROMCOORD(mx), y = FROMCOORD(my), w = state->w; char buf[80]; if (IS_CURSOR_MOVE(button)) { move_cursor(button, &ui->cx, &ui->cy, state->w, state->h, 0); ui->cshow = 1; if (ui->dragging) { ui->dx = COORD(ui->cx) + TILE_SIZE/2; ui->dy = COORD(ui->cy) + TILE_SIZE/2; } return ""; } else if (IS_CURSOR_SELECT(button)) { if (!ui->cshow) ui->cshow = 1; else if (ui->dragging) { ui->dragging = FALSE; if (ui->sx == ui->cx && ui->sy == ui->cy) return ""; if (ui->drag_is_from) { if (!isvalidmove(state, 0, ui->sx, ui->sy, ui->cx, ui->cy)) return ""; sprintf(buf, "L%d,%d-%d,%d", ui->sx, ui->sy, ui->cx, ui->cy); } else { if (!isvalidmove(state, 0, ui->cx, ui->cy, ui->sx, ui->sy)) return ""; sprintf(buf, "L%d,%d-%d,%d", ui->cx, ui->cy, ui->sx, ui->sy); } return dupstr(buf); } else { ui->dragging = TRUE; ui->sx = ui->cx; ui->sy = ui->cy; ui->dx = COORD(ui->cx) + TILE_SIZE/2; ui->dy = COORD(ui->cy) + TILE_SIZE/2; ui->drag_is_from = (button == CURSOR_SELECT) ? 1 : 0; } return ""; } if (IS_MOUSE_DOWN(button)) { if (ui->cshow) { ui->cshow = ui->dragging = 0; } assert(!ui->dragging); if (!INGRID(state, x, y)) return NULL; if (button == LEFT_BUTTON) { /* disallow dragging from the final number. */ if ((state->nums[y*w+x] == state->n) && (state->flags[y*w+x] & FLAG_IMMUTABLE)) return NULL; } else if (button == RIGHT_BUTTON) { /* disallow dragging to the first number. */ if ((state->nums[y*w+x] == 1) && (state->flags[y*w+x] & FLAG_IMMUTABLE)) return NULL; } ui->dragging = TRUE; ui->drag_is_from = (button == LEFT_BUTTON) ? 1 : 0; ui->sx = x; ui->sy = y; ui->dx = mx; ui->dy = my; ui->cshow = 0; return ""; } else if (IS_MOUSE_DRAG(button) && ui->dragging) { ui->dx = mx; ui->dy = my; return ""; } else if (IS_MOUSE_RELEASE(button) && ui->dragging) { ui->dragging = FALSE; if (ui->sx == x && ui->sy == y) return ""; /* single click */ if (!INGRID(state, x, y)) { int si = ui->sy*w+ui->sx; if (state->prev[si] == -1 && state->next[si] == -1) return ""; sprintf(buf, "%c%d,%d", (int)(ui->drag_is_from ? 'C' : 'X'), ui->sx, ui->sy); return dupstr(buf); } if (ui->drag_is_from) { if (!isvalidmove(state, 0, ui->sx, ui->sy, x, y)) return ""; sprintf(buf, "L%d,%d-%d,%d", ui->sx, ui->sy, x, y); } else { if (!isvalidmove(state, 0, x, y, ui->sx, ui->sy)) return ""; sprintf(buf, "L%d,%d-%d,%d", x, y, ui->sx, ui->sy); } return dupstr(buf); } /* else if (button == 'H' || button == 'h') return dupstr("H"); */ else if ((button == 'x' || button == 'X') && ui->cshow) { int si = ui->cy*w + ui->cx; if (state->prev[si] == -1 && state->next[si] == -1) return ""; sprintf(buf, "%c%d,%d", (int)((button == 'x') ? 'C' : 'X'), ui->cx, ui->cy); return dupstr(buf); } return NULL; } static void unlink_cell(game_state *state, int si) { debug(("Unlinking (%d,%d).", si%state->w, si/state->w)); if (state->prev[si] != -1) { debug((" ... removing prev link from (%d,%d).", state->prev[si]%state->w, state->prev[si]/state->w)); state->next[state->prev[si]] = -1; state->prev[si] = -1; } if (state->next[si] != -1) { debug((" ... removing next link to (%d,%d).", state->next[si]%state->w, state->next[si]/state->w)); state->prev[state->next[si]] = -1; state->next[si] = -1; } } static game_state *execute_move(const game_state *state, const char *move) { game_state *ret = NULL; int sx, sy, ex, ey, si, ei, w = state->w; char c; debug(("move: %s", move)); if (move[0] == 'S') { game_params p; game_state *tmp; char *valid; int i; p.w = state->w; p.h = state->h; valid = validate_desc(&p, move+1); if (valid) { debug(("execute_move: move not valid: %s", valid)); return NULL; } ret = dup_game(state); tmp = new_game(NULL, &p, move+1); for (i = 0; i < state->n; i++) { ret->prev[i] = tmp->prev[i]; ret->next[i] = tmp->next[i]; } free_game(tmp); ret->used_solve = 1; } else if (sscanf(move, "L%d,%d-%d,%d", &sx, &sy, &ex, &ey) == 4) { if (!isvalidmove(state, 0, sx, sy, ex, ey)) return NULL; ret = dup_game(state); si = sy*w+sx; ei = ey*w+ex; makelink(ret, si, ei); } else if (sscanf(move, "%c%d,%d", &c, &sx, &sy) == 3) { int sset; if (c != 'C' && c != 'X') return NULL; if (!INGRID(state, sx, sy)) return NULL; si = sy*w+sx; if (state->prev[si] == -1 && state->next[si] == -1) return NULL; ret = dup_game(state); sset = state->nums[si] / (state->n+1); if (c == 'C' || (c == 'X' && sset == 0)) { /* Unlink the single cell we dragged from the board. */ unlink_cell(ret, si); } else { int i, set; for (i = 0; i < state->n; i++) { /* Unlink all cells in the same set as the one we dragged * from the board. */ if (state->nums[i] == 0) continue; set = state->nums[i] / (state->n+1); if (set != sset) continue; unlink_cell(ret, i); } } } else if (strcmp(move, "H") == 0) { ret = dup_game(state); solve_state(ret); } if (ret) { update_numbers(ret); if (check_completion(ret, 1)) ret->completed = 1; } return ret; } /* ---------------------------------------------------------------------- * Drawing routines. */ static void game_compute_size(const game_params *params, int tilesize, int *x, int *y) { /* Ick: fake up `ds->tilesize' for macro expansion purposes */ struct { int tilesize, order; } ads, *ds = &ads; ads.tilesize = tilesize; *x = TILE_SIZE * params->w + 2 * BORDER; *y = TILE_SIZE * params->h + 2 * BORDER; } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { ds->tilesize = tilesize; assert(TILE_SIZE > 0); assert(!ds->dragb); ds->dragb = blitter_new(dr, BLITTER_SIZE, BLITTER_SIZE); } /* Colours chosen from the webby palette to work as a background to black text, * W then some plausible approximation to pastelly ROYGBIV; we then interpolate * between consecutive pairs to give another 8 (and then the drawing routine * will reuse backgrounds). */ static const unsigned long bgcols[8] = { 0xffffff, /* white */ 0xffa07a, /* lightsalmon */ 0x98fb98, /* green */ 0x7fffd4, /* aquamarine */ 0x9370db, /* medium purple */ 0xffa500, /* orange */ 0x87cefa, /* lightskyblue */ 0xffff00, /* yellow */ }; static float *game_colours(frontend *fe, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float); int c, i; game_mkhighlight(fe, ret, COL_BACKGROUND, COL_HIGHLIGHT, COL_LOWLIGHT); for (i = 0; i < 3; i++) { ret[COL_NUMBER * 3 + i] = 0.0F; ret[COL_ARROW * 3 + i] = 0.0F; ret[COL_CURSOR * 3 + i] = ret[COL_BACKGROUND * 3 + i] / 2.0F; ret[COL_GRID * 3 + i] = ret[COL_BACKGROUND * 3 + i] / 1.3F; } ret[COL_NUMBER_SET * 3 + 0] = 0.0F; ret[COL_NUMBER_SET * 3 + 1] = 0.0F; ret[COL_NUMBER_SET * 3 + 2] = 0.9F; ret[COL_ERROR * 3 + 0] = 1.0F; ret[COL_ERROR * 3 + 1] = 0.0F; ret[COL_ERROR * 3 + 2] = 0.0F; ret[COL_DRAG_ORIGIN * 3 + 0] = 0.2F; ret[COL_DRAG_ORIGIN * 3 + 1] = 1.0F; ret[COL_DRAG_ORIGIN * 3 + 2] = 0.2F; for (c = 0; c < 8; c++) { ret[(COL_B0 + c) * 3 + 0] = (float)((bgcols[c] & 0xff0000) >> 16) / 256.0F; ret[(COL_B0 + c) * 3 + 1] = (float)((bgcols[c] & 0xff00) >> 8) / 256.0F; ret[(COL_B0 + c) * 3 + 2] = (float)((bgcols[c] & 0xff)) / 256.0F; } for (c = 0; c < 8; c++) { for (i = 0; i < 3; i++) { ret[(COL_B0 + 8 + c) * 3 + i] = (ret[(COL_B0 + c) * 3 + i] + ret[(COL_B0 + c + 1) * 3 + i]) / 2.0F; } } #define average(r,a,b,w) do { \ for (i = 0; i < 3; i++) \ ret[(r)*3+i] = ret[(a)*3+i] + w * (ret[(b)*3+i] - ret[(a)*3+i]); \ } while (0) average(COL_ARROW_BG_DIM, COL_BACKGROUND, COL_ARROW, 0.1F); average(COL_NUMBER_SET_MID, COL_B0, COL_NUMBER_SET, 0.3F); for (c = 0; c < NBACKGROUNDS; c++) { /* I assume here that COL_ARROW and COL_NUMBER are the same. * Otherwise I'd need two sets of COL_M*. */ average(COL_M0 + c, COL_B0 + c, COL_NUMBER, 0.3F); average(COL_D0 + c, COL_B0 + c, COL_NUMBER, 0.1F); average(COL_X0 + c, COL_BACKGROUND, COL_B0 + c, 0.5F); } *ncolours = NCOLOURS; return ret; } static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { struct game_drawstate *ds = snew(struct game_drawstate); int i; ds->tilesize = ds->started = ds->solved = 0; ds->w = state->w; ds->h = state->h; ds->n = state->n; ds->nums = snewn(state->n, int); ds->dirp = snewn(state->n, int); ds->f = snewn(state->n, unsigned int); for (i = 0; i < state->n; i++) { ds->nums[i] = 0; ds->dirp[i] = -1; ds->f[i] = 0; } ds->angle_offset = 0.0F; ds->dragging = ds->dx = ds->dy = 0; ds->dragb = NULL; return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { sfree(ds->nums); sfree(ds->dirp); sfree(ds->f); if (ds->dragb) blitter_free(dr, ds->dragb); sfree(ds); } /* cx, cy are top-left corner. sz is the 'radius' of the arrow. * ang is in radians, clockwise from 0 == straight up. */ static void draw_arrow(drawing *dr, int cx, int cy, int sz, double ang, int cfill, int cout) { int coords[14]; int xdx, ydx, xdy, ydy, xdx3, xdy3; double s = sin(ang), c = cos(ang); xdx3 = (int)(sz * (c/3 + 1) + 0.5) - sz; xdy3 = (int)(sz * (s/3 + 1) + 0.5) - sz; xdx = (int)(sz * (c + 1) + 0.5) - sz; xdy = (int)(sz * (s + 1) + 0.5) - sz; ydx = -xdy; ydy = xdx; coords[2*0 + 0] = cx - ydx; coords[2*0 + 1] = cy - ydy; coords[2*1 + 0] = cx + xdx; coords[2*1 + 1] = cy + xdy; coords[2*2 + 0] = cx + xdx3; coords[2*2 + 1] = cy + xdy3; coords[2*3 + 0] = cx + xdx3 + ydx; coords[2*3 + 1] = cy + xdy3 + ydy; coords[2*4 + 0] = cx - xdx3 + ydx; coords[2*4 + 1] = cy - xdy3 + ydy; coords[2*5 + 0] = cx - xdx3; coords[2*5 + 1] = cy - xdy3; coords[2*6 + 0] = cx - xdx; coords[2*6 + 1] = cy - xdy; draw_polygon(dr, coords, 7, cfill, cout); } static void draw_arrow_dir(drawing *dr, int cx, int cy, int sz, int dir, int cfill, int cout, double angle_offset) { double ang = 2.0 * PI * (double)dir / 8.0 + angle_offset; draw_arrow(dr, cx, cy, sz, ang, cfill, cout); } /* cx, cy are centre coordinates.. */ static void draw_star(drawing *dr, int cx, int cy, int rad, int npoints, int cfill, int cout, double angle_offset) { int *coords, n; double a, r; assert(npoints > 0); coords = snewn(npoints * 2 * 2, int); for (n = 0; n < npoints * 2; n++) { a = 2.0 * PI * ((double)n / ((double)npoints * 2.0)) + angle_offset; r = (n % 2) ? (double)rad/2.0 : (double)rad; /* We're rotating the point at (0, -r) by a degrees */ coords[2*n+0] = cx + (int)( r * sin(a)); coords[2*n+1] = cy + (int)(-r * cos(a)); } draw_polygon(dr, coords, npoints*2, cfill, cout); sfree(coords); } static int num2col(game_drawstate *ds, int num) { int set = num / (ds->n+1); if (num <= 0 || set == 0) return COL_B0; return COL_B0 + 1 + ((set-1) % 15); } #define ARROW_HALFSZ (7 * TILE_SIZE / 32) #define F_CUR 0x001 /* Cursor on this tile. */ #define F_DRAG_SRC 0x002 /* Tile is source of a drag. */ #define F_ERROR 0x004 /* Tile marked in error. */ #define F_IMMUTABLE 0x008 /* Tile (number) is immutable. */ #define F_ARROW_POINT 0x010 /* Tile points to other tile */ #define F_ARROW_INPOINT 0x020 /* Other tile points in here. */ #define F_DIM 0x040 /* Tile is dim */ static void tile_redraw(drawing *dr, game_drawstate *ds, int tx, int ty, int dir, int dirp, int num, unsigned int f, double angle_offset, int print_ink) { int cb = TILE_SIZE / 16, textsz; char buf[20]; int arrowcol, sarrowcol, setcol, textcol; int acx, acy, asz, empty = 0; if (num == 0 && !(f & F_ARROW_POINT) && !(f & F_ARROW_INPOINT)) { empty = 1; /* * We don't display text in empty cells: typically these are * signified by num=0. However, in some cases a cell could * have had the number 0 assigned to it if the user made an * error (e.g. tried to connect a chain of length 5 to the * immutable number 4) so we _do_ display the 0 if the cell * has a link in or a link out. */ } /* Calculate colours. */ if (print_ink >= 0) { /* * We're printing, so just do everything in black. */ arrowcol = textcol = print_ink; setcol = sarrowcol = -1; /* placate optimiser */ } else { setcol = empty ? COL_BACKGROUND : num2col(ds, num); #define dim(fg,bg) ( \ (bg)==COL_BACKGROUND ? COL_ARROW_BG_DIM : \ (bg) + COL_D0 - COL_B0 \ ) #define mid(fg,bg) ( \ (fg)==COL_NUMBER_SET ? COL_NUMBER_SET_MID : \ (bg) + COL_M0 - COL_B0 \ ) #define dimbg(bg) ( \ (bg)==COL_BACKGROUND ? COL_BACKGROUND : \ (bg) + COL_X0 - COL_B0 \ ) if (f & F_DRAG_SRC) arrowcol = COL_DRAG_ORIGIN; else if (f & F_DIM) arrowcol = dim(COL_ARROW, setcol); else if (f & F_ARROW_POINT) arrowcol = mid(COL_ARROW, setcol); else arrowcol = COL_ARROW; if ((f & F_ERROR) && !(f & F_IMMUTABLE)) textcol = COL_ERROR; else { if (f & F_IMMUTABLE) textcol = COL_NUMBER_SET; else textcol = COL_NUMBER; if (f & F_DIM) textcol = dim(textcol, setcol); else if (((f & F_ARROW_POINT) || num==ds->n) && ((f & F_ARROW_INPOINT) || num==1)) textcol = mid(textcol, setcol); } if (f & F_DIM) sarrowcol = dim(COL_ARROW, setcol); else sarrowcol = COL_ARROW; } /* Clear tile background */ if (print_ink < 0) { draw_rect(dr, tx, ty, TILE_SIZE, TILE_SIZE, (f & F_DIM) ? dimbg(setcol) : setcol); } /* Draw large (outwards-pointing) arrow. */ asz = ARROW_HALFSZ; /* 'radius' of arrow/star. */ acx = tx+TILE_SIZE/2+asz; /* centre x */ acy = ty+TILE_SIZE/2+asz; /* centre y */ if (num == ds->n && (f & F_IMMUTABLE)) draw_star(dr, acx, acy, asz, 5, arrowcol, arrowcol, angle_offset); else draw_arrow_dir(dr, acx, acy, asz, dir, arrowcol, arrowcol, angle_offset); if (print_ink < 0 && (f & F_CUR)) draw_rect_corners(dr, acx, acy, asz+1, COL_CURSOR); /* Draw dot iff this tile requires a predecessor and doesn't have one. */ if (print_ink < 0) { acx = tx+TILE_SIZE/2-asz; acy = ty+TILE_SIZE/2+asz; if (!(f & F_ARROW_INPOINT) && num != 1) { draw_circle(dr, acx, acy, asz / 4, sarrowcol, sarrowcol); } } /* Draw text (number or set). */ if (!empty) { int set = (num <= 0) ? 0 : num / (ds->n+1); char *p = buf; if (set == 0 || num <= 0) { sprintf(buf, "%d", num); } else { int n = num % (ds->n+1); p += sizeof(buf) - 1; if (n != 0) { sprintf(buf, "+%d", n); /* Just to get the length... */ p -= strlen(buf); sprintf(p, "+%d", n); } else { *p = '\0'; } do { set--; p--; *p = (char)((set % 26)+'a'); set /= 26; } while (set); } textsz = min(2*asz, (TILE_SIZE - 2 * cb) / (int)strlen(p)); draw_text(dr, tx + cb, ty + TILE_SIZE/4, FONT_VARIABLE, textsz, ALIGN_VCENTRE | ALIGN_HLEFT, textcol, p); } if (print_ink < 0) { draw_rect_outline(dr, tx, ty, TILE_SIZE, TILE_SIZE, COL_GRID); draw_update(dr, tx, ty, TILE_SIZE, TILE_SIZE); } } static void draw_drag_indicator(drawing *dr, game_drawstate *ds, const game_state *state, const game_ui *ui, int validdrag) { int dir, w = ds->w, acol = COL_ARROW; int fx = FROMCOORD(ui->dx), fy = FROMCOORD(ui->dy); double ang; if (validdrag) { /* If we could move here, lock the arrow to the appropriate direction. */ dir = ui->drag_is_from ? state->dirs[ui->sy*w+ui->sx] : state->dirs[fy*w+fx]; ang = (2.0 * PI * dir) / 8.0; /* similar to calculation in draw_arrow_dir. */ } else { /* Draw an arrow pointing away from/towards the origin cell. */ int ox = COORD(ui->sx) + TILE_SIZE/2, oy = COORD(ui->sy) + TILE_SIZE/2; double tana, offset; double xdiff = abs(ox - ui->dx), ydiff = abs(oy - ui->dy); if (xdiff == 0) { ang = (oy > ui->dy) ? 0.0F : PI; } else if (ydiff == 0) { ang = (ox > ui->dx) ? 3.0F*PI/2.0F : PI/2.0F; } else { if (ui->dx > ox && ui->dy < oy) { tana = xdiff / ydiff; offset = 0.0F; } else if (ui->dx > ox && ui->dy > oy) { tana = ydiff / xdiff; offset = PI/2.0F; } else if (ui->dx < ox && ui->dy > oy) { tana = xdiff / ydiff; offset = PI; } else { tana = ydiff / xdiff; offset = 3.0F * PI / 2.0F; } ang = atan(tana) + offset; } if (!ui->drag_is_from) ang += PI; /* point to origin, not away from. */ } draw_arrow(dr, ui->dx, ui->dy, ARROW_HALFSZ, ang, acol, acol); } static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float animtime, float flashtime) { int x, y, i, w = ds->w, dirp, force = 0; unsigned int f; double angle_offset = 0.0; game_state *postdrop = NULL; if (flashtime > 0.0F) angle_offset = 2.0 * PI * (flashtime / FLASH_SPIN); if (angle_offset != ds->angle_offset) { ds->angle_offset = angle_offset; force = 1; } if (ds->dragging) { assert(ds->dragb); blitter_load(dr, ds->dragb, ds->dx, ds->dy); draw_update(dr, ds->dx, ds->dy, BLITTER_SIZE, BLITTER_SIZE); ds->dragging = FALSE; } /* If an in-progress drag would make a valid move if finished, we * reflect that move in the board display. We let interpret_move do * most of the heavy lifting for us: we have to copy the game_ui so * as not to stomp on the real UI's drag state. */ if (ui->dragging) { game_ui uicopy = *ui; char *movestr = interpret_move(state, &uicopy, ds, ui->dx, ui->dy, LEFT_RELEASE); if (movestr != NULL && strcmp(movestr, "") != 0) { postdrop = execute_move(state, movestr); sfree(movestr); state = postdrop; } } if (!ds->started) { int aw = TILE_SIZE * state->w; int ah = TILE_SIZE * state->h; draw_rect(dr, 0, 0, aw + 2 * BORDER, ah + 2 * BORDER, COL_BACKGROUND); draw_rect_outline(dr, BORDER - 1, BORDER - 1, aw + 2, ah + 2, COL_GRID); draw_update(dr, 0, 0, aw + 2 * BORDER, ah + 2 * BORDER); } for (x = 0; x < state->w; x++) { for (y = 0; y < state->h; y++) { i = y*w + x; f = 0; dirp = -1; if (ui->cshow && x == ui->cx && y == ui->cy) f |= F_CUR; if (ui->dragging) { if (x == ui->sx && y == ui->sy) f |= F_DRAG_SRC; else if (ui->drag_is_from) { if (!ispointing(state, ui->sx, ui->sy, x, y)) f |= F_DIM; } else { if (!ispointing(state, x, y, ui->sx, ui->sy)) f |= F_DIM; } } if (state->impossible || state->nums[i] < 0 || state->flags[i] & FLAG_ERROR) f |= F_ERROR; if (state->flags[i] & FLAG_IMMUTABLE) f |= F_IMMUTABLE; if (state->next[i] != -1) f |= F_ARROW_POINT; if (state->prev[i] != -1) { /* Currently the direction here is from our square _back_ * to its previous. We could change this to give the opposite * sense to the direction. */ f |= F_ARROW_INPOINT; dirp = whichdir(x, y, state->prev[i]%w, state->prev[i]/w); } if (state->nums[i] != ds->nums[i] || f != ds->f[i] || dirp != ds->dirp[i] || force || !ds->started) { int sign; { /* * Trivial and foolish configurable option done on * purest whim. With this option enabled, the * victory flash is done by rotating each square * in the opposite direction from its immediate * neighbours, so that they behave like a field of * interlocking gears. With it disabled, they all * rotate in the same direction. Choose for * yourself which is more brain-twisting :-) */ static int gear_mode = -1; if (gear_mode < 0) { char *env = getenv("SIGNPOST_GEARS"); gear_mode = (env && (env[0] == 'y' || env[0] == 'Y')); } if (gear_mode) sign = 1 - 2 * ((x ^ y) & 1); else sign = 1; } tile_redraw(dr, ds, BORDER + x * TILE_SIZE, BORDER + y * TILE_SIZE, state->dirs[i], dirp, state->nums[i], f, sign * angle_offset, -1); ds->nums[i] = state->nums[i]; ds->f[i] = f; ds->dirp[i] = dirp; } } } if (ui->dragging) { ds->dragging = TRUE; ds->dx = ui->dx - BLITTER_SIZE/2; ds->dy = ui->dy - BLITTER_SIZE/2; blitter_save(dr, ds->dragb, ds->dx, ds->dy); draw_drag_indicator(dr, ds, state, ui, postdrop ? 1 : 0); } if (postdrop) free_game(postdrop); if (!ds->started) ds->started = TRUE; } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return 0.0F; } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { if (!oldstate->completed && newstate->completed && !newstate->used_solve) return FLASH_SPIN; else return 0.0F; } static int game_status(const game_state *state) { return state->completed ? +1 : 0; } static int game_timing_state(const game_state *state, game_ui *ui) { return TRUE; } static void game_print_size(const game_params *params, float *x, float *y) { int pw, ph; game_compute_size(params, 1300, &pw, &ph); *x = pw / 100.0F; *y = ph / 100.0F; } static void game_print(drawing *dr, const game_state *state, int tilesize) { int ink = print_mono_colour(dr, 0); int x, y; /* Fake up just enough of a drawstate */ game_drawstate ads, *ds = &ads; ds->tilesize = tilesize; ds->n = state->n; /* * Border and grid. */ print_line_width(dr, TILE_SIZE / 40); for (x = 1; x < state->w; x++) draw_line(dr, COORD(x), COORD(0), COORD(x), COORD(state->h), ink); for (y = 1; y < state->h; y++) draw_line(dr, COORD(0), COORD(y), COORD(state->w), COORD(y), ink); print_line_width(dr, 2*TILE_SIZE / 40); draw_rect_outline(dr, COORD(0), COORD(0), TILE_SIZE*state->w, TILE_SIZE*state->h, ink); /* * Arrows and numbers. */ print_line_width(dr, 0); for (y = 0; y < state->h; y++) for (x = 0; x < state->w; x++) tile_redraw(dr, ds, COORD(x), COORD(y), state->dirs[y*state->w+x], 0, state->nums[y*state->w+x], 0, 0.0, ink); } #ifdef COMBINED #define thegame signpost #endif const struct game thegame = { "Signpost", "games.signpost", "signpost", default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, TRUE, solve_game, TRUE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, PREFERRED_TILE_SIZE, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, TRUE, FALSE, game_print_size, game_print, FALSE, /* wants_statusbar */ FALSE, game_timing_state, REQUIRE_RBUTTON, /* flags */ }; #ifdef STANDALONE_SOLVER #include #include const char *quis = NULL; int verbose = 0; void usage(FILE *out) { fprintf(out, "usage: %s [--stdin] [--soak] [--seed SEED] |\n", quis); } static void cycle_seed(char **seedstr, random_state *rs) { char newseed[16]; int j; newseed[15] = '\0'; newseed[0] = '1' + (char)random_upto(rs, 9); for (j = 1; j < 15; j++) newseed[j] = '0' + (char)random_upto(rs, 10); sfree(*seedstr); *seedstr = dupstr(newseed); } static void start_soak(game_params *p, char *seedstr) { time_t tt_start, tt_now, tt_last; char *desc, *aux; random_state *rs; long n = 0, nnums = 0, i; game_state *state; tt_start = tt_now = time(NULL); printf("Soak-generating a %dx%d grid.\n", p->w, p->h); while (1) { rs = random_new(seedstr, strlen(seedstr)); desc = thegame.new_desc(p, rs, &aux, 0); state = thegame.new_game(NULL, p, desc); for (i = 0; i < state->n; i++) { if (state->flags[i] & FLAG_IMMUTABLE) nnums++; } thegame.free_game(state); sfree(desc); cycle_seed(&seedstr, rs); random_free(rs); n++; tt_last = time(NULL); if (tt_last > tt_now) { tt_now = tt_last; printf("%ld total, %3.1f/s, %3.1f nums/grid (%3.1f%%).\n", n, (double)n / ((double)tt_now - tt_start), (double)nnums / (double)n, ((double)nnums * 100.0) / ((double)n * (double)p->w * (double)p->h) ); } } } static void process_desc(char *id) { char *desc, *err, *solvestr; game_params *p; game_state *s; printf("%s\n ", id); desc = strchr(id, ':'); if (!desc) { fprintf(stderr, "%s: expecting game description.", quis); exit(1); } *desc++ = '\0'; p = thegame.default_params(); thegame.decode_params(p, id); err = thegame.validate_params(p, 1); if (err) { fprintf(stderr, "%s: %s", quis, err); thegame.free_params(p); return; } err = thegame.validate_desc(p, desc); if (err) { fprintf(stderr, "%s: %s\nDescription: %s\n", quis, err, desc); thegame.free_params(p); return; } s = thegame.new_game(NULL, p, desc); solvestr = thegame.solve(s, s, NULL, &err); if (!solvestr) fprintf(stderr, "%s\n", err); else printf("Puzzle is soluble.\n"); thegame.free_game(s); thegame.free_params(p); } int main(int argc, const char *argv[]) { char *id = NULL, *desc, *err, *aux = NULL; int soak = 0, verbose = 0, stdin_desc = 0, n = 1, i; char *seedstr = NULL, newseed[16]; setvbuf(stdout, NULL, _IONBF, 0); quis = argv[0]; while (--argc > 0) { char *p = (char*)(*++argv); if (!strcmp(p, "-v") || !strcmp(p, "--verbose")) verbose = 1; else if (!strcmp(p, "--stdin")) stdin_desc = 1; else if (!strcmp(p, "-e") || !strcmp(p, "--seed")) { seedstr = dupstr(*++argv); argc--; } else if (!strcmp(p, "-n") || !strcmp(p, "--number")) { n = atoi(*++argv); argc--; } else if (!strcmp(p, "-s") || !strcmp(p, "--soak")) { soak = 1; } else if (*p == '-') { fprintf(stderr, "%s: unrecognised option `%s'\n", argv[0], p); usage(stderr); exit(1); } else { id = p; } } sprintf(newseed, "%lu", (unsigned long) time(NULL)); seedstr = dupstr(newseed); if (id || !stdin_desc) { if (id && strchr(id, ':')) { /* Parameters and description passed on cmd-line: * try and solve it. */ process_desc(id); } else { /* No description passed on cmd-line: decode parameters * (with optional seed too) */ game_params *p = thegame.default_params(); if (id) { char *cmdseed = strchr(id, '#'); if (cmdseed) { *cmdseed++ = '\0'; sfree(seedstr); seedstr = dupstr(cmdseed); } thegame.decode_params(p, id); } err = thegame.validate_params(p, 1); if (err) { fprintf(stderr, "%s: %s", quis, err); thegame.free_params(p); exit(1); } /* We have a set of valid parameters; either soak with it * or generate a single game description and print to stdout. */ if (soak) start_soak(p, seedstr); else { char *pstring = thegame.encode_params(p, 0); for (i = 0; i < n; i++) { random_state *rs = random_new(seedstr, strlen(seedstr)); if (verbose) printf("%s#%s\n", pstring, seedstr); desc = thegame.new_desc(p, rs, &aux, 0); printf("%s:%s\n", pstring, desc); sfree(desc); cycle_seed(&seedstr, rs); random_free(rs); } sfree(pstring); } thegame.free_params(p); } } if (stdin_desc) { char buf[4096]; while (fgets(buf, sizeof(buf), stdin)) { buf[strcspn(buf, "\r\n")] = '\0'; process_desc(buf); } } sfree(seedstr); return 0; } #endif /* vim: set shiftwidth=4 tabstop=8: */ puzzles-20170606.272beef/samegame.c0000644000175000017500000014026613115373615015625 0ustar simonsimon/* * 'same game' -- try to remove all the coloured squares by * selecting regions of contiguous colours. */ /* * TODO on grid generation: * * - Generation speed could still be improved. * * 15x10c3 is the only really difficult one of the existing * presets. The others are all either small enough, or have * the great flexibility given by four colours, that they * don't take long at all. * * I still suspect many problems arise from separate * subareas. I wonder if we can also somehow prioritise left- * or rightmost insertions so as to avoid area splitting at * all where feasible? It's not easy, though, because the * current shuffle-then-try-all-options approach to move * choice doesn't leave room for `soft' probabilistic * prioritisation: we either try all class A moves before any * class B ones, or we don't. * * - The current generation algorithm inserts exactly two squares * at a time, with a single exception at the beginning of * generation for grids of odd overall size. An obvious * extension would be to permit larger inverse moves during * generation. * * this might reduce the number of failed generations by * making the insertion algorithm more flexible * * on the other hand, it would be significantly more complex * * if I do this I'll need to take out the odd-subarea * avoidance * * a nice feature of the current algorithm is that the * computer's `intended' solution always receives the minimum * possible score, so that pretty much the player's entire * score represents how much better they did than the * computer. * * - Is it possible we can _temporarily_ tolerate neighbouring * squares of the same colour, until we've finished setting up * our inverse move? * * or perhaps even not choose the colour of our inserted * region until we have finished placing it, and _then_ look * at what colours border on it? * * I don't think this is currently meaningful unless we're * placing more than a domino at a time. * * - possibly write out a full solution so that Solve can somehow * show it step by step? * * aux_info would have to encode the click points * * solve_game() would have to encode not only those click * points but also give a move string which reconstructed the * initial state * * the game_state would include a pointer to a solution move * list, plus an index into that list * * game_changed_state would auto-select the next move if * handed a new state which had a solution move list active * * execute_move, if passed such a state as input, would check * to see whether the move being made was the same as the one * stated by the solution, and if so would advance the move * index. Failing that it would return a game_state without a * solution move list active at all. */ #include #include #include #include #include #include #include "puzzles.h" #define TILE_INNER (ds->tileinner) #define TILE_GAP (ds->tilegap) #define TILE_SIZE (TILE_INNER + TILE_GAP) #define PREFERRED_TILE_SIZE 32 #define BORDER (TILE_SIZE / 2) #define HIGHLIGHT_WIDTH 2 #define FLASH_FRAME 0.13F #define COORD(x) ( (x) * TILE_SIZE + BORDER ) #define FROMCOORD(x) ( ((x) - BORDER + TILE_SIZE) / TILE_SIZE - 1 ) #define X(state, i) ( (i) % (state)->params.w ) #define Y(state, i) ( (i) / (state)->params.w ) #define C(state, x, y) ( (y) * (state)->w + (x) ) enum { COL_BACKGROUND, COL_1, COL_2, COL_3, COL_4, COL_5, COL_6, COL_7, COL_8, COL_9, COL_IMPOSSIBLE, COL_SEL, COL_HIGHLIGHT, COL_LOWLIGHT, NCOLOURS }; /* scoresub is 1 or 2 (for (n-1)^2 or (n-2)^2) */ struct game_params { int w, h, ncols, scoresub; int soluble; /* choose generation algorithm */ }; /* These flags must be unique across all uses; in the game_state, * the game_ui, and the drawstate (as they all get combined in the * drawstate). */ #define TILE_COLMASK 0x00ff #define TILE_SELECTED 0x0100 /* used in ui and drawstate */ #define TILE_JOINRIGHT 0x0200 /* used in drawstate */ #define TILE_JOINDOWN 0x0400 /* used in drawstate */ #define TILE_JOINDIAG 0x0800 /* used in drawstate */ #define TILE_HASSEL 0x1000 /* used in drawstate */ #define TILE_IMPOSSIBLE 0x2000 /* used in drawstate */ #define TILE(gs,x,y) ((gs)->tiles[(gs)->params.w*(y)+(x)]) #define COL(gs,x,y) (TILE(gs,x,y) & TILE_COLMASK) #define ISSEL(gs,x,y) (TILE(gs,x,y) & TILE_SELECTED) #define SWAPTILE(gs,x1,y1,x2,y2) do { \ int t = TILE(gs,x1,y1); \ TILE(gs,x1,y1) = TILE(gs,x2,y2); \ TILE(gs,x2,y2) = t; \ } while (0) static int npoints(const game_params *params, int nsel) { int sdiff = nsel - params->scoresub; return (sdiff > 0) ? sdiff * sdiff : 0; } struct game_state { struct game_params params; int n; int *tiles; /* colour only */ int score; int complete, impossible; }; static game_params *default_params(void) { game_params *ret = snew(game_params); ret->w = 5; ret->h = 5; ret->ncols = 3; ret->scoresub = 2; ret->soluble = TRUE; return ret; } static const struct game_params samegame_presets[] = { { 5, 5, 3, 2, TRUE }, { 10, 5, 3, 2, TRUE }, #ifdef SLOW_SYSTEM { 10, 10, 3, 2, TRUE }, #else { 15, 10, 3, 2, TRUE }, #endif { 15, 10, 4, 2, TRUE }, { 20, 15, 4, 2, TRUE } }; static int game_fetch_preset(int i, char **name, game_params **params) { game_params *ret; char str[80]; if (i < 0 || i >= lenof(samegame_presets)) return FALSE; ret = snew(game_params); *ret = samegame_presets[i]; sprintf(str, "%dx%d, %d colours", ret->w, ret->h, ret->ncols); *name = dupstr(str); *params = ret; return TRUE; } static void free_params(game_params *params) { sfree(params); } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } static void decode_params(game_params *params, char const *string) { char const *p = string; params->w = atoi(p); while (*p && isdigit((unsigned char)*p)) p++; if (*p == 'x') { p++; params->h = atoi(p); while (*p && isdigit((unsigned char)*p)) p++; } else { params->h = params->w; } if (*p == 'c') { p++; params->ncols = atoi(p); while (*p && isdigit((unsigned char)*p)) p++; } else { params->ncols = 3; } if (*p == 's') { p++; params->scoresub = atoi(p); while (*p && isdigit((unsigned char)*p)) p++; } else { params->scoresub = 2; } if (*p == 'r') { p++; params->soluble = FALSE; } } static char *encode_params(const game_params *params, int full) { char ret[80]; sprintf(ret, "%dx%dc%ds%d%s", params->w, params->h, params->ncols, params->scoresub, full && !params->soluble ? "r" : ""); return dupstr(ret); } static config_item *game_configure(const game_params *params) { config_item *ret; char buf[80]; ret = snewn(6, config_item); ret[0].name = "Width"; ret[0].type = C_STRING; sprintf(buf, "%d", params->w); ret[0].sval = dupstr(buf); ret[0].ival = 0; ret[1].name = "Height"; ret[1].type = C_STRING; sprintf(buf, "%d", params->h); ret[1].sval = dupstr(buf); ret[1].ival = 0; ret[2].name = "No. of colours"; ret[2].type = C_STRING; sprintf(buf, "%d", params->ncols); ret[2].sval = dupstr(buf); ret[2].ival = 0; ret[3].name = "Scoring system"; ret[3].type = C_CHOICES; ret[3].sval = ":(n-1)^2:(n-2)^2"; ret[3].ival = params->scoresub-1; ret[4].name = "Ensure solubility"; ret[4].type = C_BOOLEAN; ret[4].sval = NULL; ret[4].ival = params->soluble; ret[5].name = NULL; ret[5].type = C_END; ret[5].sval = NULL; ret[5].ival = 0; return ret; } static game_params *custom_params(const config_item *cfg) { game_params *ret = snew(game_params); ret->w = atoi(cfg[0].sval); ret->h = atoi(cfg[1].sval); ret->ncols = atoi(cfg[2].sval); ret->scoresub = cfg[3].ival + 1; ret->soluble = cfg[4].ival; return ret; } static char *validate_params(const game_params *params, int full) { if (params->w < 1 || params->h < 1) return "Width and height must both be positive"; if (params->ncols > 9) return "Maximum of 9 colours"; if (params->soluble) { if (params->ncols < 3) return "Number of colours must be at least three"; if (params->w * params->h <= 1) return "Grid area must be greater than 1"; } else { if (params->ncols < 2) return "Number of colours must be at least three"; /* ...and we must make sure we can generate at least 2 squares * of each colour so it's theoretically soluble. */ if ((params->w * params->h) < (params->ncols * 2)) return "Too many colours makes given grid size impossible"; } if ((params->scoresub < 1) || (params->scoresub > 2)) return "Scoring system not recognised"; return NULL; } /* * Guaranteed-soluble grid generator. */ static void gen_grid(int w, int h, int nc, int *grid, random_state *rs) { int wh = w*h, tc = nc+1; int i, j, k, c, x, y, pos, n; int *list, *grid2; int ok, failures = 0; /* * We'll use `list' to track the possible places to put our * next insertion. There are up to h places to insert in each * column: in a column of height n there are n+1 places because * we can insert at the very bottom or the very top, but a * column of height h can't have anything at all inserted in it * so we have up to h in each column. Likewise, with n columns * present there are n+1 places to fit a new one in between but * we can't insert a column if there are already w; so there * are a maximum of w new columns too. Total is wh + w. */ list = snewn(wh + w, int); grid2 = snewn(wh, int); do { /* * Start with two or three squares - depending on parity of w*h * - of a random colour. */ for (i = 0; i < wh; i++) grid[i] = 0; j = 2 + (wh % 2); c = 1 + random_upto(rs, nc); if (j <= w) { for (i = 0; i < j; i++) grid[(h-1)*w+i] = c; } else { assert(j <= h); for (i = 0; i < j; i++) grid[(h-1-i)*w] = c; } /* * Now repeatedly insert a two-square blob in the grid, of * whatever colour will go at the position we chose. */ while (1) { n = 0; /* * Build up a list of insertion points. Each point is * encoded as y*w+x; insertion points between columns are * encoded as h*w+x. */ if (grid[wh - 1] == 0) { /* * The final column is empty, so we can insert new * columns. */ for (i = 0; i < w; i++) { list[n++] = wh + i; if (grid[(h-1)*w + i] == 0) break; } } /* * Now look for places to insert within columns. */ for (i = 0; i < w; i++) { if (grid[(h-1)*w+i] == 0) break; /* no more columns */ if (grid[i] != 0) continue; /* this column is full */ for (j = h; j-- > 0 ;) { list[n++] = j*w+i; if (grid[j*w+i] == 0) break; /* this column is exhausted */ } } if (n == 0) break; /* we're done */ #ifdef GENERATION_DIAGNOSTICS printf("initial grid:\n"); { int x,y; for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { if (grid[y*w+x] == 0) printf("-"); else printf("%d", grid[y*w+x]); } printf("\n"); } } #endif /* * Now go through the list one element at a time in * random order, and actually attempt to insert * something there. */ while (n-- > 0) { int dirs[4], ndirs, dir; i = random_upto(rs, n+1); pos = list[i]; list[i] = list[n]; x = pos % w; y = pos / w; memcpy(grid2, grid, wh * sizeof(int)); if (y == h) { /* * Insert a column at position x. */ for (i = w-1; i > x; i--) for (j = 0; j < h; j++) grid2[j*w+i] = grid2[j*w+(i-1)]; /* * Clear the new column. */ for (j = 0; j < h; j++) grid2[j*w+x] = 0; /* * Decrement y so that our first square is actually * inserted _in_ the grid rather than just below it. */ y--; } /* * Insert a square within column x at position y. */ for (i = 0; i+1 <= y; i++) grid2[i*w+x] = grid2[(i+1)*w+x]; #ifdef GENERATION_DIAGNOSTICS printf("trying at n=%d (%d,%d)\n", n, x, y); grid2[y*w+x] = tc; { int x,y; for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { if (grid2[y*w+x] == 0) printf("-"); else if (grid2[y*w+x] <= nc) printf("%d", grid2[y*w+x]); else printf("*"); } printf("\n"); } } #endif /* * Pick our square colour so that it doesn't match any * of its neighbours. */ { int wrongcol[4], nwrong = 0; /* * List the neighbouring colours. */ if (x > 0) wrongcol[nwrong++] = grid2[y*w+(x-1)]; if (x+1 < w) wrongcol[nwrong++] = grid2[y*w+(x+1)]; if (y > 0) wrongcol[nwrong++] = grid2[(y-1)*w+x]; if (y+1 < h) wrongcol[nwrong++] = grid2[(y+1)*w+x]; /* * Eliminate duplicates. We can afford a shoddy * algorithm here because the problem size is * bounded. */ for (i = j = 0 ;; i++) { int pos = -1, min = 0; if (j > 0) min = wrongcol[j-1]; for (k = i; k < nwrong; k++) if (wrongcol[k] > min && (pos == -1 || wrongcol[k] < wrongcol[pos])) pos = k; if (pos >= 0) { int v = wrongcol[pos]; wrongcol[pos] = wrongcol[j]; wrongcol[j++] = v; } else break; } nwrong = j; /* * If no colour will go here, stop trying. */ if (nwrong == nc) continue; /* * Otherwise, pick a colour from the remaining * ones. */ c = 1 + random_upto(rs, nc - nwrong); for (i = 0; i < nwrong; i++) { if (c >= wrongcol[i]) c++; else break; } } /* * Place the new square. * * Although I've _chosen_ the new region's colour * (so that we can check adjacency), I'm going to * actually place it as an invalid colour (tc) * until I'm sure it's viable. This is so that I * can conveniently check that I really have made a * _valid_ inverse move later on. */ #ifdef GENERATION_DIAGNOSTICS printf("picked colour %d\n", c); #endif grid2[y*w+x] = tc; /* * Now attempt to extend it in one of three ways: left, * right or up. */ ndirs = 0; if (x > 0 && grid2[y*w+(x-1)] != c && grid2[x-1] == 0 && (y+1 >= h || grid2[(y+1)*w+(x-1)] != c) && (y+1 >= h || grid2[(y+1)*w+(x-1)] != 0) && (x <= 1 || grid2[y*w+(x-2)] != c)) dirs[ndirs++] = -1; /* left */ if (x+1 < w && grid2[y*w+(x+1)] != c && grid2[x+1] == 0 && (y+1 >= h || grid2[(y+1)*w+(x+1)] != c) && (y+1 >= h || grid2[(y+1)*w+(x+1)] != 0) && (x+2 >= w || grid2[y*w+(x+2)] != c)) dirs[ndirs++] = +1; /* right */ if (y > 0 && grid2[x] == 0 && (x <= 0 || grid2[(y-1)*w+(x-1)] != c) && (x+1 >= w || grid2[(y-1)*w+(x+1)] != c)) { /* * We add this possibility _twice_, so that the * probability of placing a vertical domino is * about the same as that of a horizontal. This * should yield less bias in the generated * grids. */ dirs[ndirs++] = 0; /* up */ dirs[ndirs++] = 0; /* up */ } if (ndirs == 0) continue; dir = dirs[random_upto(rs, ndirs)]; #ifdef GENERATION_DIAGNOSTICS printf("picked dir %d\n", dir); #endif /* * Insert a square within column (x+dir) at position y. */ for (i = 0; i+1 <= y; i++) grid2[i*w+x+dir] = grid2[(i+1)*w+x+dir]; grid2[y*w+x+dir] = tc; /* * See if we've divided the remaining grid squares * into sub-areas. If so, we need every sub-area to * have an even area or we won't be able to * complete generation. * * If the height is odd and not all columns are * present, we can increase the area of a subarea * by adding a new column in it, so in that * situation we don't mind having as many odd * subareas as there are spare columns. * * If the height is even, we can't fix it at all. */ { int nerrs = 0, nfix = 0; k = 0; /* current subarea size */ for (i = 0; i < w; i++) { if (grid2[(h-1)*w+i] == 0) { if (h % 2) nfix++; continue; } for (j = 0; j < h && grid2[j*w+i] == 0; j++); assert(j < h); if (j == 0) { /* * End of previous subarea. */ if (k % 2) nerrs++; k = 0; } else { k += j; } } if (k % 2) nerrs++; if (nerrs > nfix) continue; /* try a different placement */ } /* * We've made a move. Verify that it is a valid * move and that if made it would indeed yield the * previous grid state. The criteria are: * * (a) removing all the squares of colour tc (and * shuffling the columns up etc) from grid2 * would yield grid * (b) no square of colour tc is adjacent to one * of colour c * (c) all the squares of colour tc form a single * connected component * * We verify the latter property at the same time * as checking that removing all the tc squares * would yield the previous grid. Then we colour * the tc squares in colour c by breadth-first * search, which conveniently permits us to test * that they're all connected. */ { int x1, x2, y1, y2; int ok = TRUE; int fillstart = -1, ntc = 0; #ifdef GENERATION_DIAGNOSTICS { int x,y; printf("testing move (new, old):\n"); for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { if (grid2[y*w+x] == 0) printf("-"); else if (grid2[y*w+x] <= nc) printf("%d", grid2[y*w+x]); else printf("*"); } printf(" "); for (x = 0; x < w; x++) { if (grid[y*w+x] == 0) printf("-"); else printf("%d", grid[y*w+x]); } printf("\n"); } } #endif for (x1 = x2 = 0; x2 < w; x2++) { int usedcol = FALSE; for (y1 = y2 = h-1; y2 >= 0; y2--) { if (grid2[y2*w+x2] == tc) { ntc++; if (fillstart == -1) fillstart = y2*w+x2; if ((y2+1 < h && grid2[(y2+1)*w+x2] == c) || (y2-1 >= 0 && grid2[(y2-1)*w+x2] == c) || (x2+1 < w && grid2[y2*w+x2+1] == c) || (x2-1 >= 0 && grid2[y2*w+x2-1] == c)) { #ifdef GENERATION_DIAGNOSTICS printf("adjacency failure at %d,%d\n", x2, y2); #endif ok = FALSE; } continue; } if (grid2[y2*w+x2] == 0) break; usedcol = TRUE; if (grid2[y2*w+x2] != grid[y1*w+x1]) { #ifdef GENERATION_DIAGNOSTICS printf("matching failure at %d,%d vs %d,%d\n", x2, y2, x1, y1); #endif ok = FALSE; } y1--; } /* * If we've reached the top of the column * in grid2, verify that we've also reached * the top of the column in `grid'. */ if (usedcol) { while (y1 >= 0) { if (grid[y1*w+x1] != 0) { #ifdef GENERATION_DIAGNOSTICS printf("junk at column top (%d,%d)\n", x1, y1); #endif ok = FALSE; } y1--; } } if (!ok) break; if (usedcol) x1++; } if (!ok) { assert(!"This should never happen"); /* * If this game is compiled NDEBUG so that * the assertion doesn't bring it to a * crashing halt, the only thing we can do * is to give up, loop round again, and * hope to randomly avoid making whatever * type of move just caused this failure. */ continue; } /* * Now use bfs to fill in the tc section as * colour c. We use `list' to store the set of * squares we have to process. */ i = j = 0; assert(fillstart >= 0); list[i++] = fillstart; #ifdef OUTPUT_SOLUTION printf("M"); #endif while (j < i) { k = list[j]; x = k % w; y = k / w; #ifdef OUTPUT_SOLUTION printf("%s%d", j ? "," : "", k); #endif j++; assert(grid2[k] == tc); grid2[k] = c; if (x > 0 && grid2[k-1] == tc) list[i++] = k-1; if (x+1 < w && grid2[k+1] == tc) list[i++] = k+1; if (y > 0 && grid2[k-w] == tc) list[i++] = k-w; if (y+1 < h && grid2[k+w] == tc) list[i++] = k+w; } #ifdef OUTPUT_SOLUTION printf("\n"); #endif /* * Check that we've filled the same number of * tc squares as we originally found. */ assert(j == ntc); } memcpy(grid, grid2, wh * sizeof(int)); break; /* done it! */ } #ifdef GENERATION_DIAGNOSTICS { int x,y; printf("n=%d\n", n); for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { if (grid[y*w+x] == 0) printf("-"); else printf("%d", grid[y*w+x]); } printf("\n"); } } #endif if (n < 0) break; } ok = TRUE; for (i = 0; i < wh; i++) if (grid[i] == 0) { ok = FALSE; failures++; #if defined GENERATION_DIAGNOSTICS || defined SHOW_INCOMPLETE { int x,y; printf("incomplete grid:\n"); for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { if (grid[y*w+x] == 0) printf("-"); else printf("%d", grid[y*w+x]); } printf("\n"); } } #endif break; } } while (!ok); #if defined GENERATION_DIAGNOSTICS || defined COUNT_FAILURES printf("%d failures\n", failures); #endif #ifdef GENERATION_DIAGNOSTICS { int x,y; printf("final grid:\n"); for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { printf("%d", grid[y*w+x]); } printf("\n"); } } #endif sfree(grid2); sfree(list); } /* * Not-guaranteed-soluble grid generator; kept as a legacy, and in * case someone finds the slightly odd quality of the guaranteed- * soluble grids to be aesthetically displeasing or finds its CPU * utilisation to be excessive. */ static void gen_grid_random(int w, int h, int nc, int *grid, random_state *rs) { int i, j, c; int n = w * h; for (i = 0; i < n; i++) grid[i] = 0; /* * Our sole concession to not gratuitously generating insoluble * grids is to ensure we have at least two of every colour. */ for (c = 1; c <= nc; c++) { for (j = 0; j < 2; j++) { do { i = (int)random_upto(rs, n); } while (grid[i] != 0); grid[i] = c; } } /* * Fill in the rest of the grid at random. */ for (i = 0; i < n; i++) { if (grid[i] == 0) grid[i] = (int)random_upto(rs, nc)+1; } } static char *new_game_desc(const game_params *params, random_state *rs, char **aux, int interactive) { char *ret; int n, i, retlen, *tiles; n = params->w * params->h; tiles = snewn(n, int); if (params->soluble) gen_grid(params->w, params->h, params->ncols, tiles, rs); else gen_grid_random(params->w, params->h, params->ncols, tiles, rs); ret = NULL; retlen = 0; for (i = 0; i < n; i++) { char buf[80]; int k; k = sprintf(buf, "%d,", tiles[i]); ret = sresize(ret, retlen + k + 1, char); strcpy(ret + retlen, buf); retlen += k; } ret[retlen-1] = '\0'; /* delete last comma */ sfree(tiles); return ret; } static char *validate_desc(const game_params *params, const char *desc) { int area = params->w * params->h, i; const char *p = desc; for (i = 0; i < area; i++) { const char *q = p; int n; if (!isdigit((unsigned char)*p)) return "Not enough numbers in string"; while (isdigit((unsigned char)*p)) p++; if (i < area-1 && *p != ',') return "Expected comma after number"; else if (i == area-1 && *p) return "Excess junk at end of string"; n = atoi(q); if (n < 0 || n > params->ncols) return "Colour out of range"; if (*p) p++; /* eat comma */ } return NULL; } static game_state *new_game(midend *me, const game_params *params, const char *desc) { game_state *state = snew(game_state); const char *p = desc; int i; state->params = *params; /* struct copy */ state->n = state->params.w * state->params.h; state->tiles = snewn(state->n, int); for (i = 0; i < state->n; i++) { assert(*p); state->tiles[i] = atoi(p); while (*p && *p != ',') p++; if (*p) p++; /* eat comma */ } state->complete = state->impossible = 0; state->score = 0; return state; } static game_state *dup_game(const game_state *state) { game_state *ret = snew(game_state); *ret = *state; /* structure copy, except... */ ret->tiles = snewn(state->n, int); memcpy(ret->tiles, state->tiles, state->n * sizeof(int)); return ret; } static void free_game(game_state *state) { sfree(state->tiles); sfree(state); } static char *solve_game(const game_state *state, const game_state *currstate, const char *aux, char **error) { return NULL; } static int game_can_format_as_text_now(const game_params *params) { return TRUE; } static char *game_text_format(const game_state *state) { char *ret, *p; int x, y, maxlen; maxlen = state->params.h * (state->params.w + 1); ret = snewn(maxlen+1, char); p = ret; for (y = 0; y < state->params.h; y++) { for (x = 0; x < state->params.w; x++) { int t = TILE(state,x,y); if (t <= 0) *p++ = ' '; else if (t < 10) *p++ = '0'+t; else *p++ = 'a'+(t-10); } *p++ = '\n'; } assert(p - ret == maxlen); *p = '\0'; return ret; } struct game_ui { struct game_params params; int *tiles; /* selected-ness only */ int nselected; int xsel, ysel, displaysel; }; static game_ui *new_ui(const game_state *state) { game_ui *ui = snew(game_ui); ui->params = state->params; /* structure copy */ ui->tiles = snewn(state->n, int); memset(ui->tiles, 0, state->n*sizeof(int)); ui->nselected = 0; ui->xsel = ui->ysel = ui->displaysel = 0; return ui; } static void free_ui(game_ui *ui) { sfree(ui->tiles); sfree(ui); } static char *encode_ui(const game_ui *ui) { return NULL; } static void decode_ui(game_ui *ui, const char *encoding) { } static void sel_clear(game_ui *ui, const game_state *state) { int i; for (i = 0; i < state->n; i++) ui->tiles[i] &= ~TILE_SELECTED; ui->nselected = 0; } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { sel_clear(ui, newstate); /* * If the game state has just changed into an unplayable one * (either completed or impossible), we vanish the keyboard- * control cursor. */ if (newstate->complete || newstate->impossible) ui->displaysel = 0; } static char *sel_movedesc(game_ui *ui, const game_state *state) { int i; char *ret, *sep, buf[80]; int retlen, retsize; retsize = 256; ret = snewn(retsize, char); retlen = 0; ret[retlen++] = 'M'; sep = ""; for (i = 0; i < state->n; i++) { if (ui->tiles[i] & TILE_SELECTED) { sprintf(buf, "%s%d", sep, i); sep = ","; if (retlen + (int)strlen(buf) >= retsize) { retsize = retlen + strlen(buf) + 256; ret = sresize(ret, retsize, char); } strcpy(ret + retlen, buf); retlen += strlen(buf); ui->tiles[i] &= ~TILE_SELECTED; } } ui->nselected = 0; assert(retlen < retsize); ret[retlen++] = '\0'; return sresize(ret, retlen, char); } static void sel_expand(game_ui *ui, const game_state *state, int tx, int ty) { int ns = 1, nadded, x, y, c; TILE(ui,tx,ty) |= TILE_SELECTED; do { nadded = 0; for (x = 0; x < state->params.w; x++) { for (y = 0; y < state->params.h; y++) { if (x == tx && y == ty) continue; if (ISSEL(ui,x,y)) continue; c = COL(state,x,y); if ((x > 0) && ISSEL(ui,x-1,y) && COL(state,x-1,y) == c) { TILE(ui,x,y) |= TILE_SELECTED; nadded++; continue; } if ((x+1 < state->params.w) && ISSEL(ui,x+1,y) && COL(state,x+1,y) == c) { TILE(ui,x,y) |= TILE_SELECTED; nadded++; continue; } if ((y > 0) && ISSEL(ui,x,y-1) && COL(state,x,y-1) == c) { TILE(ui,x,y) |= TILE_SELECTED; nadded++; continue; } if ((y+1 < state->params.h) && ISSEL(ui,x,y+1) && COL(state,x,y+1) == c) { TILE(ui,x,y) |= TILE_SELECTED; nadded++; continue; } } } ns += nadded; } while (nadded > 0); if (ns > 1) { ui->nselected = ns; } else { sel_clear(ui, state); } } static int sg_emptycol(game_state *ret, int x) { int y; for (y = 0; y < ret->params.h; y++) { if (COL(ret,x,y)) return 0; } return 1; } static void sg_snuggle(game_state *ret) { int x,y, ndone; /* make all unsupported tiles fall down. */ do { ndone = 0; for (x = 0; x < ret->params.w; x++) { for (y = ret->params.h-1; y > 0; y--) { if (COL(ret,x,y) != 0) continue; if (COL(ret,x,y-1) != 0) { SWAPTILE(ret,x,y,x,y-1); ndone++; } } } } while (ndone); /* shuffle all columns as far left as they can go. */ do { ndone = 0; for (x = 0; x < ret->params.w-1; x++) { if (sg_emptycol(ret,x) && !sg_emptycol(ret,x+1)) { ndone++; for (y = 0; y < ret->params.h; y++) { SWAPTILE(ret,x,y,x+1,y); } } } } while (ndone); } static void sg_check(game_state *ret) { int x,y, complete = 1, impossible = 1; for (x = 0; x < ret->params.w; x++) { for (y = 0; y < ret->params.h; y++) { if (COL(ret,x,y) == 0) continue; complete = 0; if (x+1 < ret->params.w) { if (COL(ret,x,y) == COL(ret,x+1,y)) impossible = 0; } if (y+1 < ret->params.h) { if (COL(ret,x,y) == COL(ret,x,y+1)) impossible = 0; } } } ret->complete = complete; ret->impossible = impossible; } struct game_drawstate { int started, bgcolour; int tileinner, tilegap; int *tiles; /* contains colour and SELECTED. */ }; static char *interpret_move(const game_state *state, game_ui *ui, const game_drawstate *ds, int x, int y, int button) { int tx, ty; char *ret = ""; ui->displaysel = 0; if (button == RIGHT_BUTTON || button == LEFT_BUTTON) { tx = FROMCOORD(x); ty= FROMCOORD(y); } else if (IS_CURSOR_MOVE(button)) { int dx = 0, dy = 0; ui->displaysel = 1; dx = (button == CURSOR_LEFT) ? -1 : ((button == CURSOR_RIGHT) ? +1 : 0); dy = (button == CURSOR_DOWN) ? +1 : ((button == CURSOR_UP) ? -1 : 0); ui->xsel = (ui->xsel + state->params.w + dx) % state->params.w; ui->ysel = (ui->ysel + state->params.h + dy) % state->params.h; return ret; } else if (IS_CURSOR_SELECT(button)) { ui->displaysel = 1; tx = ui->xsel; ty = ui->ysel; } else return NULL; if (tx < 0 || tx >= state->params.w || ty < 0 || ty >= state->params.h) return NULL; if (COL(state, tx, ty) == 0) return NULL; if (ISSEL(ui,tx,ty)) { if (button == RIGHT_BUTTON || button == CURSOR_SELECT2) sel_clear(ui, state); else ret = sel_movedesc(ui, state); } else { sel_clear(ui, state); /* might be no-op */ sel_expand(ui, state, tx, ty); } return ret; } static game_state *execute_move(const game_state *from, const char *move) { int i, n; game_state *ret; if (move[0] == 'M') { ret = dup_game(from); n = 0; move++; while (*move) { i = atoi(move); if (i < 0 || i >= ret->n) { free_game(ret); return NULL; } n++; ret->tiles[i] = 0; while (*move && isdigit((unsigned char)*move)) move++; if (*move == ',') move++; } ret->score += npoints(&ret->params, n); sg_snuggle(ret); /* shifts blanks down and to the left */ sg_check(ret); /* checks for completeness or impossibility */ return ret; } else return NULL; /* couldn't parse move string */ } /* ---------------------------------------------------------------------- * Drawing routines. */ static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { ds->tilegap = 2; ds->tileinner = tilesize - ds->tilegap; } static void game_compute_size(const game_params *params, int tilesize, int *x, int *y) { /* Ick: fake up tile size variables for macro expansion purposes */ game_drawstate ads, *ds = &ads; game_set_size(NULL, ds, params, tilesize); *x = TILE_SIZE * params->w + 2 * BORDER - TILE_GAP; *y = TILE_SIZE * params->h + 2 * BORDER - TILE_GAP; } static float *game_colours(frontend *fe, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float); frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]); ret[COL_1 * 3 + 0] = 0.0F; ret[COL_1 * 3 + 1] = 0.0F; ret[COL_1 * 3 + 2] = 1.0F; ret[COL_2 * 3 + 0] = 0.0F; ret[COL_2 * 3 + 1] = 0.5F; ret[COL_2 * 3 + 2] = 0.0F; ret[COL_3 * 3 + 0] = 1.0F; ret[COL_3 * 3 + 1] = 0.0F; ret[COL_3 * 3 + 2] = 0.0F; ret[COL_4 * 3 + 0] = 1.0F; ret[COL_4 * 3 + 1] = 1.0F; ret[COL_4 * 3 + 2] = 0.0F; ret[COL_5 * 3 + 0] = 1.0F; ret[COL_5 * 3 + 1] = 0.0F; ret[COL_5 * 3 + 2] = 1.0F; ret[COL_6 * 3 + 0] = 0.0F; ret[COL_6 * 3 + 1] = 1.0F; ret[COL_6 * 3 + 2] = 1.0F; ret[COL_7 * 3 + 0] = 0.5F; ret[COL_7 * 3 + 1] = 0.5F; ret[COL_7 * 3 + 2] = 1.0F; ret[COL_8 * 3 + 0] = 0.5F; ret[COL_8 * 3 + 1] = 1.0F; ret[COL_8 * 3 + 2] = 0.5F; ret[COL_9 * 3 + 0] = 1.0F; ret[COL_9 * 3 + 1] = 0.5F; ret[COL_9 * 3 + 2] = 0.5F; ret[COL_IMPOSSIBLE * 3 + 0] = 0.0F; ret[COL_IMPOSSIBLE * 3 + 1] = 0.0F; ret[COL_IMPOSSIBLE * 3 + 2] = 0.0F; ret[COL_SEL * 3 + 0] = 1.0F; ret[COL_SEL * 3 + 1] = 1.0F; ret[COL_SEL * 3 + 2] = 1.0F; ret[COL_HIGHLIGHT * 3 + 0] = 1.0F; ret[COL_HIGHLIGHT * 3 + 1] = 1.0F; ret[COL_HIGHLIGHT * 3 + 2] = 1.0F; ret[COL_LOWLIGHT * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] * 2.0F / 3.0F; ret[COL_LOWLIGHT * 3 + 1] = ret[COL_BACKGROUND * 3 + 1] * 2.0F / 3.0F; ret[COL_LOWLIGHT * 3 + 2] = ret[COL_BACKGROUND * 3 + 2] * 2.0F / 3.0F; *ncolours = NCOLOURS; return ret; } static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { struct game_drawstate *ds = snew(struct game_drawstate); int i; ds->started = 0; ds->tileinner = ds->tilegap = 0; /* not decided yet */ ds->tiles = snewn(state->n, int); ds->bgcolour = -1; for (i = 0; i < state->n; i++) ds->tiles[i] = -1; return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { sfree(ds->tiles); sfree(ds); } /* Drawing routing for the tile at (x,y) is responsible for drawing * itself and the gaps to its right and below. If we're the same colour * as the tile to our right, then we fill in the gap; ditto below, and if * both then we fill the teeny tiny square in the corner as well. */ static void tile_redraw(drawing *dr, game_drawstate *ds, int x, int y, int dright, int dbelow, int tile, int bgcolour) { int outer = bgcolour, inner = outer, col = tile & TILE_COLMASK; if (col) { if (tile & TILE_IMPOSSIBLE) { outer = col; inner = COL_IMPOSSIBLE; } else if (tile & TILE_SELECTED) { outer = COL_SEL; inner = col; } else { outer = inner = col; } } draw_rect(dr, COORD(x), COORD(y), TILE_INNER, TILE_INNER, outer); draw_rect(dr, COORD(x)+TILE_INNER/4, COORD(y)+TILE_INNER/4, TILE_INNER/2, TILE_INNER/2, inner); if (dright) draw_rect(dr, COORD(x)+TILE_INNER, COORD(y), TILE_GAP, TILE_INNER, (tile & TILE_JOINRIGHT) ? outer : bgcolour); if (dbelow) draw_rect(dr, COORD(x), COORD(y)+TILE_INNER, TILE_INNER, TILE_GAP, (tile & TILE_JOINDOWN) ? outer : bgcolour); if (dright && dbelow) draw_rect(dr, COORD(x)+TILE_INNER, COORD(y)+TILE_INNER, TILE_GAP, TILE_GAP, (tile & TILE_JOINDIAG) ? outer : bgcolour); if (tile & TILE_HASSEL) { int sx = COORD(x)+2, sy = COORD(y)+2, ssz = TILE_INNER-5; int scol = (outer == COL_SEL) ? COL_LOWLIGHT : COL_HIGHLIGHT; draw_line(dr, sx, sy, sx+ssz, sy, scol); draw_line(dr, sx+ssz, sy, sx+ssz, sy+ssz, scol); draw_line(dr, sx+ssz, sy+ssz, sx, sy+ssz, scol); draw_line(dr, sx, sy+ssz, sx, sy, scol); } draw_update(dr, COORD(x), COORD(y), TILE_SIZE, TILE_SIZE); } static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float animtime, float flashtime) { int bgcolour, x, y; /* This was entirely cloned from fifteen.c; it should probably be * moved into some generic 'draw-recessed-rectangle' utility fn. */ if (!ds->started) { int coords[10]; draw_rect(dr, 0, 0, TILE_SIZE * state->params.w + 2 * BORDER, TILE_SIZE * state->params.h + 2 * BORDER, COL_BACKGROUND); draw_update(dr, 0, 0, TILE_SIZE * state->params.w + 2 * BORDER, TILE_SIZE * state->params.h + 2 * BORDER); /* * Recessed area containing the whole puzzle. */ coords[0] = COORD(state->params.w) + HIGHLIGHT_WIDTH - 1 - TILE_GAP; coords[1] = COORD(state->params.h) + HIGHLIGHT_WIDTH - 1 - TILE_GAP; coords[2] = COORD(state->params.w) + HIGHLIGHT_WIDTH - 1 - TILE_GAP; coords[3] = COORD(0) - HIGHLIGHT_WIDTH; coords[4] = coords[2] - TILE_SIZE; coords[5] = coords[3] + TILE_SIZE; coords[8] = COORD(0) - HIGHLIGHT_WIDTH; coords[9] = COORD(state->params.h) + HIGHLIGHT_WIDTH - 1 - TILE_GAP; coords[6] = coords[8] + TILE_SIZE; coords[7] = coords[9] - TILE_SIZE; draw_polygon(dr, coords, 5, COL_HIGHLIGHT, COL_HIGHLIGHT); coords[1] = COORD(0) - HIGHLIGHT_WIDTH; coords[0] = COORD(0) - HIGHLIGHT_WIDTH; draw_polygon(dr, coords, 5, COL_LOWLIGHT, COL_LOWLIGHT); ds->started = 1; } if (flashtime > 0.0) { int frame = (int)(flashtime / FLASH_FRAME); bgcolour = (frame % 2 ? COL_LOWLIGHT : COL_HIGHLIGHT); } else bgcolour = COL_BACKGROUND; for (x = 0; x < state->params.w; x++) { for (y = 0; y < state->params.h; y++) { int i = (state->params.w * y) + x; int col = COL(state,x,y), tile = col; int dright = (x+1 < state->params.w); int dbelow = (y+1 < state->params.h); tile |= ISSEL(ui,x,y); if (state->impossible) tile |= TILE_IMPOSSIBLE; if (dright && COL(state,x+1,y) == col) tile |= TILE_JOINRIGHT; if (dbelow && COL(state,x,y+1) == col) tile |= TILE_JOINDOWN; if ((tile & TILE_JOINRIGHT) && (tile & TILE_JOINDOWN) && COL(state,x+1,y+1) == col) tile |= TILE_JOINDIAG; if (ui->displaysel && ui->xsel == x && ui->ysel == y) tile |= TILE_HASSEL; /* For now we're never expecting oldstate at all (because we have * no animation); when we do we might well want to be looking * at the tile colours from oldstate, not state. */ if ((oldstate && COL(oldstate,x,y) != col) || (ds->bgcolour != bgcolour) || (tile != ds->tiles[i])) { tile_redraw(dr, ds, x, y, dright, dbelow, tile, bgcolour); ds->tiles[i] = tile; } } } ds->bgcolour = bgcolour; { char status[255], score[80]; sprintf(score, "Score: %d", state->score); if (state->complete) sprintf(status, "COMPLETE! %s", score); else if (state->impossible) sprintf(status, "Cannot move! %s", score); else if (ui->nselected) sprintf(status, "%s Selected: %d (%d)", score, ui->nselected, npoints(&state->params, ui->nselected)); else sprintf(status, "%s", score); status_bar(dr, status); } } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return 0.0F; } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { if ((!oldstate->complete && newstate->complete) || (!oldstate->impossible && newstate->impossible)) return 2 * FLASH_FRAME; else return 0.0F; } static int game_status(const game_state *state) { /* * Dead-end situations are assumed to be rescuable by Undo, so we * don't bother to identify them and return -1. */ return state->complete ? +1 : 0; } static int game_timing_state(const game_state *state, game_ui *ui) { return TRUE; } static void game_print_size(const game_params *params, float *x, float *y) { } static void game_print(drawing *dr, const game_state *state, int tilesize) { } #ifdef COMBINED #define thegame samegame #endif const struct game thegame = { "Same Game", "games.samegame", "samegame", default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, FALSE, solve_game, TRUE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, PREFERRED_TILE_SIZE, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, FALSE, FALSE, game_print_size, game_print, TRUE, /* wants_statusbar */ FALSE, game_timing_state, 0, /* flags */ }; puzzles-20170606.272beef/rect.c0000644000175000017500000026740413115373615015007 0ustar simonsimon/* * rect.c: Puzzle from nikoli.co.jp. You have a square grid with * numbers in some squares; you must divide the square grid up into * variously sized rectangles, such that every rectangle contains * exactly one numbered square and the area of each rectangle is * equal to the number contained in it. */ /* * TODO: * * - Improve singleton removal. * + It would be nice to limit the size of the generated * rectangles in accordance with existing constraints such as * the maximum rectangle size and the one about not * generating a rectangle the full width or height of the * grid. * + This could be achieved by making a less random choice * about which of the available options to use. * + Alternatively, we could create our rectangle and then * split it up. */ #include #include #include #include #include #include #include "puzzles.h" enum { COL_BACKGROUND, COL_CORRECT, COL_LINE, COL_TEXT, COL_GRID, COL_DRAG, COL_DRAGERASE, COL_CURSOR, NCOLOURS }; struct game_params { int w, h; float expandfactor; int unique; }; #define INDEX(state, x, y) (((y) * (state)->w) + (x)) #define index(state, a, x, y) ((a) [ INDEX(state,x,y) ]) #define grid(state,x,y) index(state, (state)->grid, x, y) #define vedge(state,x,y) index(state, (state)->vedge, x, y) #define hedge(state,x,y) index(state, (state)->hedge, x, y) #define CRANGE(state,x,y,dx,dy) ( (x) >= dx && (x) < (state)->w && \ (y) >= dy && (y) < (state)->h ) #define RANGE(state,x,y) CRANGE(state,x,y,0,0) #define HRANGE(state,x,y) CRANGE(state,x,y,0,1) #define VRANGE(state,x,y) CRANGE(state,x,y,1,0) #define PREFERRED_TILE_SIZE 24 #define TILE_SIZE (ds->tilesize) #ifdef SMALL_SCREEN #define BORDER (2) #else #define BORDER (TILE_SIZE * 3 / 4) #endif #define CORNER_TOLERANCE 0.15F #define CENTRE_TOLERANCE 0.15F #define FLASH_TIME 0.13F #define COORD(x) ( (x) * TILE_SIZE + BORDER ) #define FROMCOORD(x) ( ((x) - BORDER) / TILE_SIZE ) struct game_state { int w, h; int *grid; /* contains the numbers */ unsigned char *vedge; /* (w+1) x h */ unsigned char *hedge; /* w x (h+1) */ int completed, cheated; unsigned char *correct; }; static game_params *default_params(void) { game_params *ret = snew(game_params); ret->w = ret->h = 7; ret->expandfactor = 0.0F; ret->unique = TRUE; return ret; } static int game_fetch_preset(int i, char **name, game_params **params) { game_params *ret; int w, h; char buf[80]; switch (i) { case 0: w = 7, h = 7; break; case 1: w = 9, h = 9; break; case 2: w = 11, h = 11; break; case 3: w = 13, h = 13; break; case 4: w = 15, h = 15; break; #ifndef SMALL_SCREEN case 5: w = 17, h = 17; break; case 6: w = 19, h = 19; break; #endif default: return FALSE; } sprintf(buf, "%dx%d", w, h); *name = dupstr(buf); *params = ret = snew(game_params); ret->w = w; ret->h = h; ret->expandfactor = 0.0F; ret->unique = TRUE; return TRUE; } static void free_params(game_params *params) { sfree(params); } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } static void decode_params(game_params *ret, char const *string) { ret->w = ret->h = atoi(string); while (*string && isdigit((unsigned char)*string)) string++; if (*string == 'x') { string++; ret->h = atoi(string); while (*string && isdigit((unsigned char)*string)) string++; } if (*string == 'e') { string++; ret->expandfactor = (float)atof(string); while (*string && (*string == '.' || isdigit((unsigned char)*string))) string++; } if (*string == 'a') { string++; ret->unique = FALSE; } } static char *encode_params(const game_params *params, int full) { char data[256]; sprintf(data, "%dx%d", params->w, params->h); if (full && params->expandfactor) sprintf(data + strlen(data), "e%g", params->expandfactor); if (full && !params->unique) strcat(data, "a"); return dupstr(data); } static config_item *game_configure(const game_params *params) { config_item *ret; char buf[80]; ret = snewn(5, config_item); ret[0].name = "Width"; ret[0].type = C_STRING; sprintf(buf, "%d", params->w); ret[0].sval = dupstr(buf); ret[0].ival = 0; ret[1].name = "Height"; ret[1].type = C_STRING; sprintf(buf, "%d", params->h); ret[1].sval = dupstr(buf); ret[1].ival = 0; ret[2].name = "Expansion factor"; ret[2].type = C_STRING; sprintf(buf, "%g", params->expandfactor); ret[2].sval = dupstr(buf); ret[2].ival = 0; ret[3].name = "Ensure unique solution"; ret[3].type = C_BOOLEAN; ret[3].sval = NULL; ret[3].ival = params->unique; ret[4].name = NULL; ret[4].type = C_END; ret[4].sval = NULL; ret[4].ival = 0; return ret; } static game_params *custom_params(const config_item *cfg) { game_params *ret = snew(game_params); ret->w = atoi(cfg[0].sval); ret->h = atoi(cfg[1].sval); ret->expandfactor = (float)atof(cfg[2].sval); ret->unique = cfg[3].ival; return ret; } static char *validate_params(const game_params *params, int full) { if (params->w <= 0 || params->h <= 0) return "Width and height must both be greater than zero"; if (params->w*params->h < 2) return "Grid area must be greater than one"; if (params->expandfactor < 0.0F) return "Expansion factor may not be negative"; return NULL; } struct point { int x, y; }; struct rect { int x, y; int w, h; }; struct rectlist { struct rect *rects; int n; }; struct numberdata { int area; int npoints; struct point *points; }; /* ---------------------------------------------------------------------- * Solver for Rectangles games. * * This solver is souped up beyond the needs of actually _solving_ * a puzzle. It is also designed to cope with uncertainty about * where the numbers have been placed. This is because I run it on * my generated grids _before_ placing the numbers, and have it * tell me where I need to place the numbers to ensure a unique * solution. */ static void remove_rect_placement(int w, int h, struct rectlist *rectpositions, int *overlaps, int rectnum, int placement) { int x, y, xx, yy; #ifdef SOLVER_DIAGNOSTICS printf("ruling out rect %d placement at %d,%d w=%d h=%d\n", rectnum, rectpositions[rectnum].rects[placement].x, rectpositions[rectnum].rects[placement].y, rectpositions[rectnum].rects[placement].w, rectpositions[rectnum].rects[placement].h); #endif /* * Decrement each entry in the overlaps array to reflect the * removal of this rectangle placement. */ for (yy = 0; yy < rectpositions[rectnum].rects[placement].h; yy++) { y = yy + rectpositions[rectnum].rects[placement].y; for (xx = 0; xx < rectpositions[rectnum].rects[placement].w; xx++) { x = xx + rectpositions[rectnum].rects[placement].x; assert(overlaps[(rectnum * h + y) * w + x] != 0); if (overlaps[(rectnum * h + y) * w + x] > 0) overlaps[(rectnum * h + y) * w + x]--; } } /* * Remove the placement from the list of positions for that * rectangle, by interchanging it with the one on the end. */ if (placement < rectpositions[rectnum].n - 1) { struct rect t; t = rectpositions[rectnum].rects[rectpositions[rectnum].n - 1]; rectpositions[rectnum].rects[rectpositions[rectnum].n - 1] = rectpositions[rectnum].rects[placement]; rectpositions[rectnum].rects[placement] = t; } rectpositions[rectnum].n--; } static void remove_number_placement(int w, int h, struct numberdata *number, int index, int *rectbyplace) { /* * Remove the entry from the rectbyplace array. */ rectbyplace[number->points[index].y * w + number->points[index].x] = -1; /* * Remove the placement from the list of candidates for that * number, by interchanging it with the one on the end. */ if (index < number->npoints - 1) { struct point t; t = number->points[number->npoints - 1]; number->points[number->npoints - 1] = number->points[index]; number->points[index] = t; } number->npoints--; } /* * Returns 0 for failure to solve due to inconsistency; 1 for * success; 2 for failure to complete a solution due to either * ambiguity or it being too difficult. */ static int rect_solver(int w, int h, int nrects, struct numberdata *numbers, unsigned char *hedge, unsigned char *vedge, random_state *rs) { struct rectlist *rectpositions; int *overlaps, *rectbyplace, *workspace; int i, ret; /* * Start by setting up a list of candidate positions for each * rectangle. */ rectpositions = snewn(nrects, struct rectlist); for (i = 0; i < nrects; i++) { int rw, rh, area = numbers[i].area; int j, minx, miny, maxx, maxy; struct rect *rlist; int rlistn, rlistsize; /* * For each rectangle, begin by finding the bounding * rectangle of its candidate number placements. */ maxx = maxy = -1; minx = w; miny = h; for (j = 0; j < numbers[i].npoints; j++) { if (minx > numbers[i].points[j].x) minx = numbers[i].points[j].x; if (miny > numbers[i].points[j].y) miny = numbers[i].points[j].y; if (maxx < numbers[i].points[j].x) maxx = numbers[i].points[j].x; if (maxy < numbers[i].points[j].y) maxy = numbers[i].points[j].y; } /* * Now loop over all possible rectangle placements * overlapping a point within that bounding rectangle; * ensure each one actually contains a candidate number * placement, and add it to the list. */ rlist = NULL; rlistn = rlistsize = 0; for (rw = 1; rw <= area && rw <= w; rw++) { int x, y; if (area % rw) continue; rh = area / rw; if (rh > h) continue; for (y = miny - rh + 1; y <= maxy; y++) { if (y < 0 || y+rh > h) continue; for (x = minx - rw + 1; x <= maxx; x++) { if (x < 0 || x+rw > w) continue; /* * See if we can find a candidate number * placement within this rectangle. */ for (j = 0; j < numbers[i].npoints; j++) if (numbers[i].points[j].x >= x && numbers[i].points[j].x < x+rw && numbers[i].points[j].y >= y && numbers[i].points[j].y < y+rh) break; if (j < numbers[i].npoints) { /* * Add this to the list of candidate * placements for this rectangle. */ if (rlistn >= rlistsize) { rlistsize = rlistn + 32; rlist = sresize(rlist, rlistsize, struct rect); } rlist[rlistn].x = x; rlist[rlistn].y = y; rlist[rlistn].w = rw; rlist[rlistn].h = rh; #ifdef SOLVER_DIAGNOSTICS printf("rect %d [area %d]: candidate position at" " %d,%d w=%d h=%d\n", i, area, x, y, rw, rh); #endif rlistn++; } } } } rectpositions[i].rects = rlist; rectpositions[i].n = rlistn; } /* * Next, construct a multidimensional array tracking how many * candidate positions for each rectangle overlap each square. * * Indexing of this array is by the formula * * overlaps[(rectindex * h + y) * w + x] * * A positive or zero value indicates what it sounds as if it * should; -1 indicates that this square _cannot_ be part of * this rectangle; and -2 indicates that it _definitely_ is * (which is distinct from 1, because one might very well know * that _if_ square S is part of rectangle R then it must be * because R is placed in a certain position without knowing * that it definitely _is_). */ overlaps = snewn(nrects * w * h, int); memset(overlaps, 0, nrects * w * h * sizeof(int)); for (i = 0; i < nrects; i++) { int j; for (j = 0; j < rectpositions[i].n; j++) { int xx, yy; for (yy = 0; yy < rectpositions[i].rects[j].h; yy++) for (xx = 0; xx < rectpositions[i].rects[j].w; xx++) overlaps[(i * h + yy+rectpositions[i].rects[j].y) * w + xx+rectpositions[i].rects[j].x]++; } } /* * Also we want an array covering the grid once, to make it * easy to figure out which squares are candidate number * placements for which rectangles. (The existence of this * single array assumes that no square starts off as a * candidate number placement for more than one rectangle. This * assumption is justified, because this solver is _either_ * used to solve real problems - in which case there is a * single placement for every number - _or_ used to decide on * number placements for a new puzzle, in which case each * number's placements are confined to the intended position of * the rectangle containing that number.) */ rectbyplace = snewn(w * h, int); for (i = 0; i < w*h; i++) rectbyplace[i] = -1; for (i = 0; i < nrects; i++) { int j; for (j = 0; j < numbers[i].npoints; j++) { int x = numbers[i].points[j].x; int y = numbers[i].points[j].y; assert(rectbyplace[y * w + x] == -1); rectbyplace[y * w + x] = i; } } workspace = snewn(nrects, int); /* * Now run the actual deduction loop. */ while (1) { int done_something = FALSE; #ifdef SOLVER_DIAGNOSTICS printf("starting deduction loop\n"); for (i = 0; i < nrects; i++) { printf("rect %d overlaps:\n", i); { int x, y; for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { printf("%3d", overlaps[(i * h + y) * w + x]); } printf("\n"); } } } printf("rectbyplace:\n"); { int x, y; for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { printf("%3d", rectbyplace[y * w + x]); } printf("\n"); } } #endif /* * Housekeeping. Look for rectangles whose number has only * one candidate position left, and mark that square as * known if it isn't already. */ for (i = 0; i < nrects; i++) { if (numbers[i].npoints == 1) { int x = numbers[i].points[0].x; int y = numbers[i].points[0].y; if (overlaps[(i * h + y) * w + x] >= -1) { int j; if (overlaps[(i * h + y) * w + x] <= 0) { ret = 0; /* inconsistency */ goto cleanup; } #ifdef SOLVER_DIAGNOSTICS printf("marking %d,%d as known for rect %d" " (sole remaining number position)\n", x, y, i); #endif for (j = 0; j < nrects; j++) overlaps[(j * h + y) * w + x] = -1; overlaps[(i * h + y) * w + x] = -2; } } } /* * Now look at the intersection of all possible placements * for each rectangle, and mark all squares in that * intersection as known for that rectangle if they aren't * already. */ for (i = 0; i < nrects; i++) { int minx, miny, maxx, maxy, xx, yy, j; minx = miny = 0; maxx = w; maxy = h; for (j = 0; j < rectpositions[i].n; j++) { int x = rectpositions[i].rects[j].x; int y = rectpositions[i].rects[j].y; int w = rectpositions[i].rects[j].w; int h = rectpositions[i].rects[j].h; if (minx < x) minx = x; if (miny < y) miny = y; if (maxx > x+w) maxx = x+w; if (maxy > y+h) maxy = y+h; } for (yy = miny; yy < maxy; yy++) for (xx = minx; xx < maxx; xx++) if (overlaps[(i * h + yy) * w + xx] >= -1) { if (overlaps[(i * h + yy) * w + xx] <= 0) { ret = 0; /* inconsistency */ goto cleanup; } #ifdef SOLVER_DIAGNOSTICS printf("marking %d,%d as known for rect %d" " (intersection of all placements)\n", xx, yy, i); #endif for (j = 0; j < nrects; j++) overlaps[(j * h + yy) * w + xx] = -1; overlaps[(i * h + yy) * w + xx] = -2; } } /* * Rectangle-focused deduction. Look at each rectangle in * turn and try to rule out some of its candidate * placements. */ for (i = 0; i < nrects; i++) { int j; for (j = 0; j < rectpositions[i].n; j++) { int xx, yy, k; int del = FALSE; for (k = 0; k < nrects; k++) workspace[k] = 0; for (yy = 0; yy < rectpositions[i].rects[j].h; yy++) { int y = yy + rectpositions[i].rects[j].y; for (xx = 0; xx < rectpositions[i].rects[j].w; xx++) { int x = xx + rectpositions[i].rects[j].x; if (overlaps[(i * h + y) * w + x] == -1) { /* * This placement overlaps a square * which is _known_ to be part of * another rectangle. Therefore we must * rule it out. */ #ifdef SOLVER_DIAGNOSTICS printf("rect %d placement at %d,%d w=%d h=%d " "contains %d,%d which is known-other\n", i, rectpositions[i].rects[j].x, rectpositions[i].rects[j].y, rectpositions[i].rects[j].w, rectpositions[i].rects[j].h, x, y); #endif del = TRUE; } if (rectbyplace[y * w + x] != -1) { /* * This placement overlaps one of the * candidate number placements for some * rectangle. Count it. */ workspace[rectbyplace[y * w + x]]++; } } } if (!del) { /* * If we haven't ruled this placement out * already, see if it overlaps _all_ of the * candidate number placements for any * rectangle. If so, we can rule it out. */ for (k = 0; k < nrects; k++) if (k != i && workspace[k] == numbers[k].npoints) { #ifdef SOLVER_DIAGNOSTICS printf("rect %d placement at %d,%d w=%d h=%d " "contains all number points for rect %d\n", i, rectpositions[i].rects[j].x, rectpositions[i].rects[j].y, rectpositions[i].rects[j].w, rectpositions[i].rects[j].h, k); #endif del = TRUE; break; } /* * Failing that, see if it overlaps at least * one of the candidate number placements for * itself! (This might not be the case if one * of those number placements has been removed * recently.). */ if (!del && workspace[i] == 0) { #ifdef SOLVER_DIAGNOSTICS printf("rect %d placement at %d,%d w=%d h=%d " "contains none of its own number points\n", i, rectpositions[i].rects[j].x, rectpositions[i].rects[j].y, rectpositions[i].rects[j].w, rectpositions[i].rects[j].h); #endif del = TRUE; } } if (del) { remove_rect_placement(w, h, rectpositions, overlaps, i, j); j--; /* don't skip over next placement */ done_something = TRUE; } } } /* * Square-focused deduction. Look at each square not marked * as known, and see if there are any which can only be * part of a single rectangle. */ { int x, y, n, index; for (y = 0; y < h; y++) for (x = 0; x < w; x++) { /* Known squares are marked as <0 everywhere, so we only need * to check the overlaps entry for rect 0. */ if (overlaps[y * w + x] < 0) continue; /* known already */ n = 0; index = -1; for (i = 0; i < nrects; i++) if (overlaps[(i * h + y) * w + x] > 0) n++, index = i; if (n == 1) { int j; /* * Now we can rule out all placements for * rectangle `index' which _don't_ contain * square x,y. */ #ifdef SOLVER_DIAGNOSTICS printf("square %d,%d can only be in rectangle %d\n", x, y, index); #endif for (j = 0; j < rectpositions[index].n; j++) { struct rect *r = &rectpositions[index].rects[j]; if (x >= r->x && x < r->x + r->w && y >= r->y && y < r->y + r->h) continue; /* this one is OK */ remove_rect_placement(w, h, rectpositions, overlaps, index, j); j--; /* don't skip over next placement */ done_something = TRUE; } } } } /* * If we've managed to deduce anything by normal means, * loop round again and see if there's more to be done. * Only if normal deduction has completely failed us should * we now move on to narrowing down the possible number * placements. */ if (done_something) continue; /* * Now we have done everything we can with the current set * of number placements. So we need to winnow the number * placements so as to narrow down the possibilities. We do * this by searching for a candidate placement (of _any_ * rectangle) which overlaps a candidate placement of the * number for some other rectangle. */ if (rs) { struct rpn { int rect; int placement; int number; } *rpns = NULL; size_t nrpns = 0, rpnsize = 0; int j; for (i = 0; i < nrects; i++) { for (j = 0; j < rectpositions[i].n; j++) { int xx, yy; for (yy = 0; yy < rectpositions[i].rects[j].h; yy++) { int y = yy + rectpositions[i].rects[j].y; for (xx = 0; xx < rectpositions[i].rects[j].w; xx++) { int x = xx + rectpositions[i].rects[j].x; if (rectbyplace[y * w + x] >= 0 && rectbyplace[y * w + x] != i) { /* * Add this to the list of * winnowing possibilities. */ if (nrpns >= rpnsize) { rpnsize = rpnsize * 3 / 2 + 32; rpns = sresize(rpns, rpnsize, struct rpn); } rpns[nrpns].rect = i; rpns[nrpns].placement = j; rpns[nrpns].number = rectbyplace[y * w + x]; nrpns++; } } } } } #ifdef SOLVER_DIAGNOSTICS printf("%d candidate rect placements we could eliminate\n", nrpns); #endif if (nrpns > 0) { /* * Now choose one of these unwanted rectangle * placements, and eliminate it. */ int index = random_upto(rs, nrpns); int k, m; struct rpn rpn = rpns[index]; struct rect r; sfree(rpns); i = rpn.rect; j = rpn.placement; k = rpn.number; r = rectpositions[i].rects[j]; /* * We rule out placement j of rectangle i by means * of removing all of rectangle k's candidate * number placements which do _not_ overlap it. * This will ensure that it is eliminated during * the next pass of rectangle-focused deduction. */ #ifdef SOLVER_DIAGNOSTICS printf("ensuring number for rect %d is within" " rect %d's placement at %d,%d w=%d h=%d\n", k, i, r.x, r.y, r.w, r.h); #endif for (m = 0; m < numbers[k].npoints; m++) { int x = numbers[k].points[m].x; int y = numbers[k].points[m].y; if (x < r.x || x >= r.x + r.w || y < r.y || y >= r.y + r.h) { #ifdef SOLVER_DIAGNOSTICS printf("eliminating number for rect %d at %d,%d\n", k, x, y); #endif remove_number_placement(w, h, &numbers[k], m, rectbyplace); m--; /* don't skip the next one */ done_something = TRUE; } } } } if (!done_something) { #ifdef SOLVER_DIAGNOSTICS printf("terminating deduction loop\n"); #endif break; } } cleanup: ret = 1; for (i = 0; i < nrects; i++) { #ifdef SOLVER_DIAGNOSTICS printf("rect %d has %d possible placements\n", i, rectpositions[i].n); #endif if (rectpositions[i].n <= 0) { ret = 0; /* inconsistency */ } else if (rectpositions[i].n > 1) { ret = 2; /* remaining uncertainty */ } else if (hedge && vedge) { /* * Place the rectangle in its only possible position. */ int x, y; struct rect *r = &rectpositions[i].rects[0]; for (y = 0; y < r->h; y++) { if (r->x > 0) vedge[(r->y+y) * w + r->x] = 1; if (r->x+r->w < w) vedge[(r->y+y) * w + r->x+r->w] = 1; } for (x = 0; x < r->w; x++) { if (r->y > 0) hedge[r->y * w + r->x+x] = 1; if (r->y+r->h < h) hedge[(r->y+r->h) * w + r->x+x] = 1; } } } /* * Free up all allocated storage. */ sfree(workspace); sfree(rectbyplace); sfree(overlaps); for (i = 0; i < nrects; i++) sfree(rectpositions[i].rects); sfree(rectpositions); return ret; } /* ---------------------------------------------------------------------- * Grid generation code. */ /* * This function does one of two things. If passed r==NULL, it * counts the number of possible rectangles which cover the given * square, and returns it in *n. If passed r!=NULL then it _reads_ * *n to find an index, counts the possible rectangles until it * reaches the nth, and writes it into r. * * `scratch' is expected to point to an array of 2 * params->w * ints, used internally as scratch space (and passed in like this * to avoid re-allocating and re-freeing it every time round a * tight loop). */ static void enum_rects(game_params *params, int *grid, struct rect *r, int *n, int sx, int sy, int *scratch) { int rw, rh, mw, mh; int x, y, dx, dy; int maxarea, realmaxarea; int index = 0; int *top, *bottom; /* * Maximum rectangle area is 1/6 of total grid size, unless * this means we can't place any rectangles at all in which * case we set it to 2 at minimum. */ maxarea = params->w * params->h / 6; if (maxarea < 2) maxarea = 2; /* * Scan the grid to find the limits of the region within which * any rectangle containing this point must fall. This will * save us trawling the inside of every rectangle later on to * see if it contains any used squares. */ top = scratch; bottom = scratch + params->w; for (dy = -1; dy <= +1; dy += 2) { int *array = (dy == -1 ? top : bottom); for (dx = -1; dx <= +1; dx += 2) { for (x = sx; x >= 0 && x < params->w; x += dx) { array[x] = -2 * params->h * dy; for (y = sy; y >= 0 && y < params->h; y += dy) { if (index(params, grid, x, y) == -1 && (x == sx || dy*y <= dy*array[x-dx])) array[x] = y; else break; } } } } /* * Now scan again to work out the largest rectangles we can fit * in the grid, so that we can terminate the following loops * early once we get down to not having much space left in the * grid. */ realmaxarea = 0; for (x = 0; x < params->w; x++) { int x2; rh = bottom[x] - top[x] + 1; if (rh <= 0) continue; /* no rectangles can start here */ dx = (x > sx ? -1 : +1); for (x2 = x; x2 >= 0 && x2 < params->w; x2 += dx) if (bottom[x2] < bottom[x] || top[x2] > top[x]) break; rw = abs(x2 - x); if (realmaxarea < rw * rh) realmaxarea = rw * rh; } if (realmaxarea > maxarea) realmaxarea = maxarea; /* * Rectangles which go right the way across the grid are * boring, although they can't be helped in the case of * extremely small grids. (Also they might be generated later * on by the singleton-removal process; we can't help that.) */ mw = params->w - 1; if (mw < 3) mw++; mh = params->h - 1; if (mh < 3) mh++; for (rw = 1; rw <= mw; rw++) for (rh = 1; rh <= mh; rh++) { if (rw * rh > realmaxarea) continue; if (rw * rh == 1) continue; for (x = max(sx - rw + 1, 0); x <= min(sx, params->w - rw); x++) for (y = max(sy - rh + 1, 0); y <= min(sy, params->h - rh); y++) { /* * Check this rectangle against the region we * defined above. */ if (top[x] <= y && top[x+rw-1] <= y && bottom[x] >= y+rh-1 && bottom[x+rw-1] >= y+rh-1) { if (r && index == *n) { r->x = x; r->y = y; r->w = rw; r->h = rh; return; } index++; } } } assert(!r); *n = index; } static void place_rect(game_params *params, int *grid, struct rect r) { int idx = INDEX(params, r.x, r.y); int x, y; for (x = r.x; x < r.x+r.w; x++) for (y = r.y; y < r.y+r.h; y++) { index(params, grid, x, y) = idx; } #ifdef GENERATION_DIAGNOSTICS printf(" placing rectangle at (%d,%d) size %d x %d\n", r.x, r.y, r.w, r.h); #endif } static struct rect find_rect(game_params *params, int *grid, int x, int y) { int idx, w, h; struct rect r; /* * Find the top left of the rectangle. */ idx = index(params, grid, x, y); if (idx < 0) { r.x = x; r.y = y; r.w = r.h = 1; return r; /* 1x1 singleton here */ } y = idx / params->w; x = idx % params->w; /* * Find the width and height of the rectangle. */ for (w = 1; (x+w < params->w && index(params,grid,x+w,y)==idx); w++); for (h = 1; (y+h < params->h && index(params,grid,x,y+h)==idx); h++); r.x = x; r.y = y; r.w = w; r.h = h; return r; } #ifdef GENERATION_DIAGNOSTICS static void display_grid(game_params *params, int *grid, int *numbers, int all) { unsigned char *egrid = snewn((params->w*2+3) * (params->h*2+3), unsigned char); int x, y; int r = (params->w*2+3); memset(egrid, 0, (params->w*2+3) * (params->h*2+3)); for (x = 0; x < params->w; x++) for (y = 0; y < params->h; y++) { int i = index(params, grid, x, y); if (x == 0 || index(params, grid, x-1, y) != i) egrid[(2*y+2) * r + (2*x+1)] = 1; if (x == params->w-1 || index(params, grid, x+1, y) != i) egrid[(2*y+2) * r + (2*x+3)] = 1; if (y == 0 || index(params, grid, x, y-1) != i) egrid[(2*y+1) * r + (2*x+2)] = 1; if (y == params->h-1 || index(params, grid, x, y+1) != i) egrid[(2*y+3) * r + (2*x+2)] = 1; } for (y = 1; y < 2*params->h+2; y++) { for (x = 1; x < 2*params->w+2; x++) { if (!((y|x)&1)) { int k = numbers ? index(params, numbers, x/2-1, y/2-1) : 0; if (k || (all && numbers)) printf("%2d", k); else printf(" "); } else if (!((y&x)&1)) { int v = egrid[y*r+x]; if ((y&1) && v) v = '-'; if ((x&1) && v) v = '|'; if (!v) v = ' '; putchar(v); if (!(x&1)) putchar(v); } else { int c, d = 0; if (egrid[y*r+(x+1)]) d |= 1; if (egrid[(y-1)*r+x]) d |= 2; if (egrid[y*r+(x-1)]) d |= 4; if (egrid[(y+1)*r+x]) d |= 8; c = " ??+?-++?+|+++++"[d]; putchar(c); if (!(x&1)) putchar(c); } } putchar('\n'); } sfree(egrid); } #endif static char *new_game_desc(const game_params *params_in, random_state *rs, char **aux, int interactive) { game_params params_copy = *params_in; /* structure copy */ game_params *params = ¶ms_copy; int *grid, *numbers = NULL; int x, y, y2, y2last, yx, run, i, nsquares; char *desc, *p; int *enum_rects_scratch; game_params params2real, *params2 = ¶ms2real; while (1) { /* * Set up the smaller width and height which we will use to * generate the base grid. */ params2->w = (int)((float)params->w / (1.0F + params->expandfactor)); if (params2->w < 2 && params->w >= 2) params2->w = 2; params2->h = (int)((float)params->h / (1.0F + params->expandfactor)); if (params2->h < 2 && params->h >= 2) params2->h = 2; grid = snewn(params2->w * params2->h, int); enum_rects_scratch = snewn(2 * params2->w, int); nsquares = 0; for (y = 0; y < params2->h; y++) for (x = 0; x < params2->w; x++) { index(params2, grid, x, y) = -1; nsquares++; } /* * Place rectangles until we can't any more. We do this by * finding a square we haven't yet covered, and randomly * choosing a rectangle to cover it. */ while (nsquares > 0) { int square = random_upto(rs, nsquares); int n; struct rect r; x = params2->w; y = params2->h; for (y = 0; y < params2->h; y++) { for (x = 0; x < params2->w; x++) { if (index(params2, grid, x, y) == -1 && square-- == 0) break; } if (x < params2->w) break; } assert(x < params2->w && y < params2->h); /* * Now see how many rectangles fit around this one. */ enum_rects(params2, grid, NULL, &n, x, y, enum_rects_scratch); if (!n) { /* * There are no possible rectangles covering this * square, meaning it must be a singleton. Mark it * -2 so we know not to keep trying. */ index(params2, grid, x, y) = -2; nsquares--; } else { /* * Pick one at random. */ n = random_upto(rs, n); enum_rects(params2, grid, &r, &n, x, y, enum_rects_scratch); /* * Place it. */ place_rect(params2, grid, r); nsquares -= r.w * r.h; } } sfree(enum_rects_scratch); /* * Deal with singleton spaces remaining in the grid, one by * one. * * We do this by making a local change to the layout. There are * several possibilities: * * +-----+-----+ Here, we can remove the singleton by * | | | extending the 1x2 rectangle below it * +--+--+-----+ into a 1x3. * | | | | * | +--+ | * | | | | * | | | | * | | | | * +--+--+-----+ * * +--+--+--+ Here, that trick doesn't work: there's no * | | | 1 x n rectangle with the singleton at one * | | | end. Instead, we extend a 1 x n rectangle * | | | _out_ from the singleton, shaving a layer * +--+--+ | off the end of another rectangle. So if we * | | | | extended up, we'd make our singleton part * | +--+--+ of a 1x3 and generate a 1x2 where the 2x2 * | | | used to be; or we could extend right into * +--+-----+ a 2x1, turning the 1x3 into a 1x2. * * +-----+--+ Here, we can't even do _that_, since any * | | | direction we choose to extend the singleton * +--+--+ | will produce a new singleton as a result of * | | | | truncating one of the size-2 rectangles. * | +--+--+ Fortunately, this case can _only_ occur when * | | | a singleton is surrounded by four size-2s * +--+-----+ in this fashion; so instead we can simply * replace the whole section with a single 3x3. */ for (x = 0; x < params2->w; x++) { for (y = 0; y < params2->h; y++) { if (index(params2, grid, x, y) < 0) { int dirs[4], ndirs; #ifdef GENERATION_DIAGNOSTICS display_grid(params2, grid, NULL, FALSE); printf("singleton at %d,%d\n", x, y); #endif /* * Check in which directions we can feasibly extend * the singleton. We can extend in a particular * direction iff either: * * - the rectangle on that side of the singleton * is not 2x1, and we are at one end of the edge * of it we are touching * * - it is 2x1 but we are on its short side. * * FIXME: we could plausibly choose between these * based on the sizes of the rectangles they would * create? */ ndirs = 0; if (x < params2->w-1) { struct rect r = find_rect(params2, grid, x+1, y); if ((r.w * r.h > 2 && (r.y==y || r.y+r.h-1==y)) || r.h==1) dirs[ndirs++] = 1; /* right */ } if (y > 0) { struct rect r = find_rect(params2, grid, x, y-1); if ((r.w * r.h > 2 && (r.x==x || r.x+r.w-1==x)) || r.w==1) dirs[ndirs++] = 2; /* up */ } if (x > 0) { struct rect r = find_rect(params2, grid, x-1, y); if ((r.w * r.h > 2 && (r.y==y || r.y+r.h-1==y)) || r.h==1) dirs[ndirs++] = 4; /* left */ } if (y < params2->h-1) { struct rect r = find_rect(params2, grid, x, y+1); if ((r.w * r.h > 2 && (r.x==x || r.x+r.w-1==x)) || r.w==1) dirs[ndirs++] = 8; /* down */ } if (ndirs > 0) { int which, dir; struct rect r1, r2; memset(&r1, 0, sizeof(struct rect)); memset(&r2, 0, sizeof(struct rect)); which = random_upto(rs, ndirs); dir = dirs[which]; switch (dir) { case 1: /* right */ assert(x < params2->w+1); #ifdef GENERATION_DIAGNOSTICS printf("extending right\n"); #endif r1 = find_rect(params2, grid, x+1, y); r2.x = x; r2.y = y; r2.w = 1 + r1.w; r2.h = 1; if (r1.y == y) r1.y++; r1.h--; break; case 2: /* up */ assert(y > 0); #ifdef GENERATION_DIAGNOSTICS printf("extending up\n"); #endif r1 = find_rect(params2, grid, x, y-1); r2.x = x; r2.y = r1.y; r2.w = 1; r2.h = 1 + r1.h; if (r1.x == x) r1.x++; r1.w--; break; case 4: /* left */ assert(x > 0); #ifdef GENERATION_DIAGNOSTICS printf("extending left\n"); #endif r1 = find_rect(params2, grid, x-1, y); r2.x = r1.x; r2.y = y; r2.w = 1 + r1.w; r2.h = 1; if (r1.y == y) r1.y++; r1.h--; break; case 8: /* down */ assert(y < params2->h+1); #ifdef GENERATION_DIAGNOSTICS printf("extending down\n"); #endif r1 = find_rect(params2, grid, x, y+1); r2.x = x; r2.y = y; r2.w = 1; r2.h = 1 + r1.h; if (r1.x == x) r1.x++; r1.w--; break; default: /* should never happen */ assert(!"invalid direction"); } if (r1.h > 0 && r1.w > 0) place_rect(params2, grid, r1); place_rect(params2, grid, r2); } else { #ifndef NDEBUG /* * Sanity-check that there really is a 3x3 * rectangle surrounding this singleton and it * contains absolutely everything we could * possibly need. */ { int xx, yy; assert(x > 0 && x < params2->w-1); assert(y > 0 && y < params2->h-1); for (xx = x-1; xx <= x+1; xx++) for (yy = y-1; yy <= y+1; yy++) { struct rect r = find_rect(params2,grid,xx,yy); assert(r.x >= x-1); assert(r.y >= y-1); assert(r.x+r.w-1 <= x+1); assert(r.y+r.h-1 <= y+1); } } #endif #ifdef GENERATION_DIAGNOSTICS printf("need the 3x3 trick\n"); #endif /* * FIXME: If the maximum rectangle area for * this grid is less than 9, we ought to * subdivide the 3x3 in some fashion. There are * five other possibilities: * * - a 6 and a 3 * - a 4, a 3 and a 2 * - three 3s * - a 3 and three 2s (two different arrangements). */ { struct rect r; r.x = x-1; r.y = y-1; r.w = r.h = 3; place_rect(params2, grid, r); } } } } } /* * We have now constructed a grid of the size specified in * params2. Now we extend it into a grid of the size specified * in params. We do this in two passes: we extend it vertically * until it's the right height, then we transpose it, then * extend it vertically again (getting it effectively the right * width), then finally transpose again. */ for (i = 0; i < 2; i++) { int *grid2, *expand, *where; game_params params3real, *params3 = ¶ms3real; #ifdef GENERATION_DIAGNOSTICS printf("before expansion:\n"); display_grid(params2, grid, NULL, TRUE); #endif /* * Set up the new grid. */ grid2 = snewn(params2->w * params->h, int); expand = snewn(params2->h-1, int); where = snewn(params2->w, int); params3->w = params2->w; params3->h = params->h; /* * Decide which horizontal edges are going to get expanded, * and by how much. */ for (y = 0; y < params2->h-1; y++) expand[y] = 0; for (y = params2->h; y < params->h; y++) { x = random_upto(rs, params2->h-1); expand[x]++; } #ifdef GENERATION_DIAGNOSTICS printf("expand[] = {"); for (y = 0; y < params2->h-1; y++) printf(" %d", expand[y]); printf(" }\n"); #endif /* * Perform the expansion. The way this works is that we * alternately: * * - copy a row from grid into grid2 * * - invent some number of additional rows in grid2 where * there was previously only a horizontal line between * rows in grid, and make random decisions about where * among these to place each rectangle edge that ran * along this line. */ for (y = y2 = y2last = 0; y < params2->h; y++) { /* * Copy a single line from row y of grid into row y2 of * grid2. */ for (x = 0; x < params2->w; x++) { int val = index(params2, grid, x, y); if (val / params2->w == y && /* rect starts on this line */ (y2 == 0 || /* we're at the very top, or... */ index(params3, grid2, x, y2-1) / params3->w < y2last /* this rect isn't already started */)) index(params3, grid2, x, y2) = INDEX(params3, val % params2->w, y2); else index(params3, grid2, x, y2) = index(params3, grid2, x, y2-1); } /* * If that was the last line, terminate the loop early. */ if (++y2 == params3->h) break; y2last = y2; /* * Invent some number of additional lines. First walk * along this line working out where to put all the * edges that coincide with it. */ yx = -1; for (x = 0; x < params2->w; x++) { if (index(params2, grid, x, y) != index(params2, grid, x, y+1)) { /* * This is a horizontal edge, so it needs * placing. */ if (x == 0 || (index(params2, grid, x-1, y) != index(params2, grid, x, y) && index(params2, grid, x-1, y+1) != index(params2, grid, x, y+1))) { /* * Here we have the chance to make a new * decision. */ yx = random_upto(rs, expand[y]+1); } else { /* * Here we just reuse the previous value of * yx. */ } } else yx = -1; where[x] = yx; } for (yx = 0; yx < expand[y]; yx++) { /* * Invent a single row. For each square in the row, * we copy the grid entry from the square above it, * unless we're starting the new rectangle here. */ for (x = 0; x < params2->w; x++) { if (yx == where[x]) { int val = index(params2, grid, x, y+1); val %= params2->w; val = INDEX(params3, val, y2); index(params3, grid2, x, y2) = val; } else index(params3, grid2, x, y2) = index(params3, grid2, x, y2-1); } y2++; } } sfree(expand); sfree(where); #ifdef GENERATION_DIAGNOSTICS printf("after expansion:\n"); display_grid(params3, grid2, NULL, TRUE); #endif /* * Transpose. */ params2->w = params3->h; params2->h = params3->w; sfree(grid); grid = snewn(params2->w * params2->h, int); for (x = 0; x < params2->w; x++) for (y = 0; y < params2->h; y++) { int idx1 = INDEX(params2, x, y); int idx2 = INDEX(params3, y, x); int tmp; tmp = grid2[idx2]; tmp = (tmp % params3->w) * params2->w + (tmp / params3->w); grid[idx1] = tmp; } sfree(grid2); { int tmp; tmp = params->w; params->w = params->h; params->h = tmp; } #ifdef GENERATION_DIAGNOSTICS printf("after transposition:\n"); display_grid(params2, grid, NULL, TRUE); #endif } /* * Run the solver to narrow down the possible number * placements. */ { struct numberdata *nd; int nnumbers, i, ret; /* Count the rectangles. */ nnumbers = 0; for (y = 0; y < params->h; y++) { for (x = 0; x < params->w; x++) { int idx = INDEX(params, x, y); if (index(params, grid, x, y) == idx) nnumbers++; } } nd = snewn(nnumbers, struct numberdata); /* Now set up each number's candidate position list. */ i = 0; for (y = 0; y < params->h; y++) { for (x = 0; x < params->w; x++) { int idx = INDEX(params, x, y); if (index(params, grid, x, y) == idx) { struct rect r = find_rect(params, grid, x, y); int j, k, m; nd[i].area = r.w * r.h; nd[i].npoints = nd[i].area; nd[i].points = snewn(nd[i].npoints, struct point); m = 0; for (j = 0; j < r.h; j++) for (k = 0; k < r.w; k++) { nd[i].points[m].x = k + r.x; nd[i].points[m].y = j + r.y; m++; } assert(m == nd[i].npoints); i++; } } } if (params->unique) ret = rect_solver(params->w, params->h, nnumbers, nd, NULL, NULL, rs); else ret = 1; /* allow any number placement at all */ if (ret == 1) { /* * Now place the numbers according to the solver's * recommendations. */ numbers = snewn(params->w * params->h, int); for (y = 0; y < params->h; y++) for (x = 0; x < params->w; x++) { index(params, numbers, x, y) = 0; } for (i = 0; i < nnumbers; i++) { int idx = random_upto(rs, nd[i].npoints); int x = nd[i].points[idx].x; int y = nd[i].points[idx].y; index(params,numbers,x,y) = nd[i].area; } } /* * Clean up. */ for (i = 0; i < nnumbers; i++) sfree(nd[i].points); sfree(nd); /* * If we've succeeded, then terminate the loop. */ if (ret == 1) break; } /* * Give up and go round again. */ sfree(grid); } /* * Store the solution in aux. */ { char *ai; int len; len = 2 + (params->w-1)*params->h + (params->h-1)*params->w; ai = snewn(len, char); ai[0] = 'S'; p = ai+1; for (y = 0; y < params->h; y++) for (x = 1; x < params->w; x++) *p++ = (index(params, grid, x, y) != index(params, grid, x-1, y) ? '1' : '0'); for (y = 1; y < params->h; y++) for (x = 0; x < params->w; x++) *p++ = (index(params, grid, x, y) != index(params, grid, x, y-1) ? '1' : '0'); assert(p - ai == len-1); *p = '\0'; *aux = ai; } #ifdef GENERATION_DIAGNOSTICS display_grid(params, grid, numbers, FALSE); #endif desc = snewn(11 * params->w * params->h, char); p = desc; run = 0; for (i = 0; i <= params->w * params->h; i++) { int n = (i < params->w * params->h ? numbers[i] : -1); if (!n) run++; else { if (run) { while (run > 0) { int c = 'a' - 1 + run; if (run > 26) c = 'z'; *p++ = c; run -= c - ('a' - 1); } } else { /* * If there's a number in the very top left or * bottom right, there's no point putting an * unnecessary _ before or after it. */ if (p > desc && n > 0) *p++ = '_'; } if (n > 0) p += sprintf(p, "%d", n); run = 0; } } *p = '\0'; sfree(grid); sfree(numbers); return desc; } static char *validate_desc(const game_params *params, const char *desc) { int area = params->w * params->h; int squares = 0; while (*desc) { int n = *desc++; if (n >= 'a' && n <= 'z') { squares += n - 'a' + 1; } else if (n == '_') { /* do nothing */; } else if (n > '0' && n <= '9') { squares++; while (*desc >= '0' && *desc <= '9') desc++; } else return "Invalid character in game description"; } if (squares < area) return "Not enough data to fill grid"; if (squares > area) return "Too much data to fit in grid"; return NULL; } static unsigned char *get_correct(game_state *state) { unsigned char *ret; int x, y; ret = snewn(state->w * state->h, unsigned char); memset(ret, 0xFF, state->w * state->h); for (x = 0; x < state->w; x++) for (y = 0; y < state->h; y++) if (index(state,ret,x,y) == 0xFF) { int rw, rh; int xx, yy; int num, area, valid; /* * Find a rectangle starting at this point. */ rw = 1; while (x+rw < state->w && !vedge(state,x+rw,y)) rw++; rh = 1; while (y+rh < state->h && !hedge(state,x,y+rh)) rh++; /* * We know what the dimensions of the rectangle * should be if it's there at all. Find out if we * really have a valid rectangle. */ valid = TRUE; /* Check the horizontal edges. */ for (xx = x; xx < x+rw; xx++) { for (yy = y; yy <= y+rh; yy++) { int e = !HRANGE(state,xx,yy) || hedge(state,xx,yy); int ec = (yy == y || yy == y+rh); if (e != ec) valid = FALSE; } } /* Check the vertical edges. */ for (yy = y; yy < y+rh; yy++) { for (xx = x; xx <= x+rw; xx++) { int e = !VRANGE(state,xx,yy) || vedge(state,xx,yy); int ec = (xx == x || xx == x+rw); if (e != ec) valid = FALSE; } } /* * If this is not a valid rectangle with no other * edges inside it, we just mark this square as not * complete and proceed to the next square. */ if (!valid) { index(state, ret, x, y) = 0; continue; } /* * We have a rectangle. Now see what its area is, * and how many numbers are in it. */ num = 0; area = 0; for (xx = x; xx < x+rw; xx++) { for (yy = y; yy < y+rh; yy++) { area++; if (grid(state,xx,yy)) { if (num > 0) valid = FALSE; /* two numbers */ num = grid(state,xx,yy); } } } if (num != area) valid = FALSE; /* * Now fill in the whole rectangle based on the * value of `valid'. */ for (xx = x; xx < x+rw; xx++) { for (yy = y; yy < y+rh; yy++) { index(state, ret, xx, yy) = valid; } } } return ret; } static game_state *new_game(midend *me, const game_params *params, const char *desc) { game_state *state = snew(game_state); int x, y, i, area; state->w = params->w; state->h = params->h; area = state->w * state->h; state->grid = snewn(area, int); state->vedge = snewn(area, unsigned char); state->hedge = snewn(area, unsigned char); state->completed = state->cheated = FALSE; i = 0; while (*desc) { int n = *desc++; if (n >= 'a' && n <= 'z') { int run = n - 'a' + 1; assert(i + run <= area); while (run-- > 0) state->grid[i++] = 0; } else if (n == '_') { /* do nothing */; } else if (n > '0' && n <= '9') { assert(i < area); state->grid[i++] = atoi(desc-1); while (*desc >= '0' && *desc <= '9') desc++; } else { assert(!"We can't get here"); } } assert(i == area); for (y = 0; y < state->h; y++) for (x = 0; x < state->w; x++) vedge(state,x,y) = hedge(state,x,y) = 0; state->correct = get_correct(state); return state; } static game_state *dup_game(const game_state *state) { game_state *ret = snew(game_state); ret->w = state->w; ret->h = state->h; ret->vedge = snewn(state->w * state->h, unsigned char); ret->hedge = snewn(state->w * state->h, unsigned char); ret->grid = snewn(state->w * state->h, int); ret->correct = snewn(ret->w * ret->h, unsigned char); ret->completed = state->completed; ret->cheated = state->cheated; memcpy(ret->grid, state->grid, state->w * state->h * sizeof(int)); memcpy(ret->vedge, state->vedge, state->w*state->h*sizeof(unsigned char)); memcpy(ret->hedge, state->hedge, state->w*state->h*sizeof(unsigned char)); memcpy(ret->correct, state->correct, state->w*state->h*sizeof(unsigned char)); return ret; } static void free_game(game_state *state) { sfree(state->grid); sfree(state->vedge); sfree(state->hedge); sfree(state->correct); sfree(state); } static char *solve_game(const game_state *state, const game_state *currstate, const char *ai, char **error) { unsigned char *vedge, *hedge; int x, y, len; char *ret, *p; int i, j, n; struct numberdata *nd; if (ai) return dupstr(ai); /* * Attempt the in-built solver. */ /* Set up each number's (very short) candidate position list. */ for (i = n = 0; i < state->h * state->w; i++) if (state->grid[i]) n++; nd = snewn(n, struct numberdata); for (i = j = 0; i < state->h * state->w; i++) if (state->grid[i]) { nd[j].area = state->grid[i]; nd[j].npoints = 1; nd[j].points = snewn(1, struct point); nd[j].points[0].x = i % state->w; nd[j].points[0].y = i / state->w; j++; } assert(j == n); vedge = snewn(state->w * state->h, unsigned char); hedge = snewn(state->w * state->h, unsigned char); memset(vedge, 0, state->w * state->h); memset(hedge, 0, state->w * state->h); rect_solver(state->w, state->h, n, nd, hedge, vedge, NULL); /* * Clean up. */ for (i = 0; i < n; i++) sfree(nd[i].points); sfree(nd); len = 2 + (state->w-1)*state->h + (state->h-1)*state->w; ret = snewn(len, char); p = ret; *p++ = 'S'; for (y = 0; y < state->h; y++) for (x = 1; x < state->w; x++) *p++ = vedge[y*state->w+x] ? '1' : '0'; for (y = 1; y < state->h; y++) for (x = 0; x < state->w; x++) *p++ = hedge[y*state->w+x] ? '1' : '0'; *p++ = '\0'; assert(p - ret == len); sfree(vedge); sfree(hedge); return ret; } static int game_can_format_as_text_now(const game_params *params) { return TRUE; } static char *game_text_format(const game_state *state) { char *ret, *p, buf[80]; int i, x, y, col, maxlen; /* * First determine the number of spaces required to display a * number. We'll use at least two, because one looks a bit * silly. */ col = 2; for (i = 0; i < state->w * state->h; i++) { x = sprintf(buf, "%d", state->grid[i]); if (col < x) col = x; } /* * Now we know the exact total size of the grid we're going to * produce: it's got 2*h+1 rows, each containing w lots of col, * w+1 boundary characters and a trailing newline. */ maxlen = (2*state->h+1) * (state->w * (col+1) + 2); ret = snewn(maxlen+1, char); p = ret; for (y = 0; y <= 2*state->h; y++) { for (x = 0; x <= 2*state->w; x++) { if (x & y & 1) { /* * Display a number. */ int v = grid(state, x/2, y/2); if (v) sprintf(buf, "%*d", col, v); else sprintf(buf, "%*s", col, ""); memcpy(p, buf, col); p += col; } else if (x & 1) { /* * Display a horizontal edge or nothing. */ int h = (y==0 || y==2*state->h ? 1 : HRANGE(state, x/2, y/2) && hedge(state, x/2, y/2)); int i; if (h) h = '-'; else h = ' '; for (i = 0; i < col; i++) *p++ = h; } else if (y & 1) { /* * Display a vertical edge or nothing. */ int v = (x==0 || x==2*state->w ? 1 : VRANGE(state, x/2, y/2) && vedge(state, x/2, y/2)); if (v) *p++ = '|'; else *p++ = ' '; } else { /* * Display a corner, or a vertical edge, or a * horizontal edge, or nothing. */ int hl = (y==0 || y==2*state->h ? 1 : HRANGE(state, (x-1)/2, y/2) && hedge(state, (x-1)/2, y/2)); int hr = (y==0 || y==2*state->h ? 1 : HRANGE(state, (x+1)/2, y/2) && hedge(state, (x+1)/2, y/2)); int vu = (x==0 || x==2*state->w ? 1 : VRANGE(state, x/2, (y-1)/2) && vedge(state, x/2, (y-1)/2)); int vd = (x==0 || x==2*state->w ? 1 : VRANGE(state, x/2, (y+1)/2) && vedge(state, x/2, (y+1)/2)); if (!hl && !hr && !vu && !vd) *p++ = ' '; else if (hl && hr && !vu && !vd) *p++ = '-'; else if (!hl && !hr && vu && vd) *p++ = '|'; else *p++ = '+'; } } *p++ = '\n'; } assert(p - ret == maxlen); *p = '\0'; return ret; } struct game_ui { /* * These coordinates are 2 times the obvious grid coordinates. * Hence, the top left of the grid is (0,0), the grid point to * the right of that is (2,0), the one _below that_ is (2,2) * and so on. This is so that we can specify a drag start point * on an edge (one odd coordinate) or in the middle of a square * (two odd coordinates) rather than always at a corner. * * -1,-1 means no drag is in progress. */ int drag_start_x; int drag_start_y; int drag_end_x; int drag_end_y; /* * This flag is set as soon as a dragging action moves the * mouse pointer away from its starting point, so that even if * the pointer _returns_ to its starting point the action is * treated as a small drag rather than a click. */ int dragged; /* This flag is set if we're doing an erase operation (i.e. * removing edges in the centre of the rectangle without altering * the outlines). */ int erasing; /* * These are the co-ordinates of the top-left and bottom-right squares * in the drag box, respectively, or -1 otherwise. */ int x1; int y1; int x2; int y2; /* * These are the coordinates of a cursor, whether it's visible, and * whether it was used to start a drag. */ int cur_x, cur_y, cur_visible, cur_dragging; }; static void reset_ui(game_ui *ui) { ui->drag_start_x = -1; ui->drag_start_y = -1; ui->drag_end_x = -1; ui->drag_end_y = -1; ui->x1 = -1; ui->y1 = -1; ui->x2 = -1; ui->y2 = -1; ui->dragged = FALSE; } static game_ui *new_ui(const game_state *state) { game_ui *ui = snew(game_ui); reset_ui(ui); ui->erasing = FALSE; ui->cur_x = ui->cur_y = ui->cur_visible = ui->cur_dragging = 0; return ui; } static void free_ui(game_ui *ui) { sfree(ui); } static char *encode_ui(const game_ui *ui) { return NULL; } static void decode_ui(game_ui *ui, const char *encoding) { } static void coord_round(float x, float y, int *xr, int *yr) { float xs, ys, xv, yv, dx, dy, dist; /* * Find the nearest square-centre. */ xs = (float)floor(x) + 0.5F; ys = (float)floor(y) + 0.5F; /* * And find the nearest grid vertex. */ xv = (float)floor(x + 0.5F); yv = (float)floor(y + 0.5F); /* * We allocate clicks in parts of the grid square to either * corners, edges or square centres, as follows: * * +--+--------+--+ * | | | | * +--+ +--+ * | `. ,' | * | +--+ | * | | | | * | +--+ | * | ,' `. | * +--+ +--+ * | | | | * +--+--------+--+ * * (Not to scale!) * * In other words: we measure the square distance (i.e. * max(dx,dy)) from the click to the nearest corner, and if * it's within CORNER_TOLERANCE then we return a corner click. * We measure the square distance from the click to the nearest * centre, and if that's within CENTRE_TOLERANCE we return a * centre click. Failing that, we find which of the two edge * centres is nearer to the click and return that edge. */ /* * Check for corner click. */ dx = (float)fabs(x - xv); dy = (float)fabs(y - yv); dist = (dx > dy ? dx : dy); if (dist < CORNER_TOLERANCE) { *xr = 2 * (int)xv; *yr = 2 * (int)yv; } else { /* * Check for centre click. */ dx = (float)fabs(x - xs); dy = (float)fabs(y - ys); dist = (dx > dy ? dx : dy); if (dist < CENTRE_TOLERANCE) { *xr = 1 + 2 * (int)xs; *yr = 1 + 2 * (int)ys; } else { /* * Failing both of those, see which edge we're closer to. * Conveniently, this is simply done by testing the relative * magnitude of dx and dy (which are currently distances from * the square centre). */ if (dx > dy) { /* Vertical edge: x-coord of corner, * y-coord of square centre. */ *xr = 2 * (int)xv; *yr = 1 + 2 * (int)floor(ys); } else { /* Horizontal edge: x-coord of square centre, * y-coord of corner. */ *xr = 1 + 2 * (int)floor(xs); *yr = 2 * (int)yv; } } } } /* * Returns TRUE if it has made any change to the grid. */ static int grid_draw_rect(const game_state *state, unsigned char *hedge, unsigned char *vedge, int c, int really, int outline, int x1, int y1, int x2, int y2) { int x, y; int changed = FALSE; /* * Draw horizontal edges of rectangles. */ for (x = x1; x < x2; x++) for (y = y1; y <= y2; y++) if (HRANGE(state,x,y)) { int val = index(state,hedge,x,y); if (y == y1 || y == y2) { if (!outline) continue; val = c; } else if (c == 1) val = 0; changed = changed || (index(state,hedge,x,y) != val); if (really) index(state,hedge,x,y) = val; } /* * Draw vertical edges of rectangles. */ for (y = y1; y < y2; y++) for (x = x1; x <= x2; x++) if (VRANGE(state,x,y)) { int val = index(state,vedge,x,y); if (x == x1 || x == x2) { if (!outline) continue; val = c; } else if (c == 1) val = 0; changed = changed || (index(state,vedge,x,y) != val); if (really) index(state,vedge,x,y) = val; } return changed; } static int ui_draw_rect(const game_state *state, const game_ui *ui, unsigned char *hedge, unsigned char *vedge, int c, int really, int outline) { return grid_draw_rect(state, hedge, vedge, c, really, outline, ui->x1, ui->y1, ui->x2, ui->y2); } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { } struct game_drawstate { int started; int w, h, tilesize; unsigned long *visible; }; static char *interpret_move(const game_state *from, game_ui *ui, const game_drawstate *ds, int x, int y, int button) { int xc, yc; int startdrag = FALSE, enddrag = FALSE, active = FALSE, erasing = FALSE; char buf[80], *ret; button &= ~MOD_MASK; coord_round(FROMCOORD((float)x), FROMCOORD((float)y), &xc, &yc); if (button == LEFT_BUTTON || button == RIGHT_BUTTON) { if (ui->drag_start_x >= 0 && ui->cur_dragging) reset_ui(ui); /* cancel keyboard dragging */ startdrag = TRUE; ui->cur_visible = ui->cur_dragging = FALSE; active = TRUE; erasing = (button == RIGHT_BUTTON); } else if (button == LEFT_RELEASE || button == RIGHT_RELEASE) { /* We assert we should have had a LEFT_BUTTON first. */ if (ui->cur_visible) { ui->cur_visible = FALSE; active = TRUE; } assert(!ui->cur_dragging); enddrag = TRUE; erasing = (button == RIGHT_RELEASE); } else if (IS_CURSOR_MOVE(button)) { move_cursor(button, &ui->cur_x, &ui->cur_y, from->w, from->h, 0); ui->cur_visible = TRUE; active = TRUE; if (!ui->cur_dragging) return ""; coord_round((float)ui->cur_x + 0.5F, (float)ui->cur_y + 0.5F, &xc, &yc); } else if (IS_CURSOR_SELECT(button)) { if (ui->drag_start_x >= 0 && !ui->cur_dragging) { /* * If a mouse drag is in progress, ignore attempts to * start a keyboard one. */ return NULL; } if (!ui->cur_visible) { assert(!ui->cur_dragging); ui->cur_visible = TRUE; return ""; } coord_round((float)ui->cur_x + 0.5F, (float)ui->cur_y + 0.5F, &xc, &yc); erasing = (button == CURSOR_SELECT2); if (ui->cur_dragging) { ui->cur_dragging = FALSE; enddrag = TRUE; active = TRUE; } else { ui->cur_dragging = TRUE; startdrag = TRUE; active = TRUE; } } else if (button == '\b' || button == 27) { if (!ui->cur_dragging) { ui->cur_visible = FALSE; } else { assert(ui->cur_visible); reset_ui(ui); /* cancel keyboard dragging */ ui->cur_dragging = FALSE; } return ""; } else if (button != LEFT_DRAG && button != RIGHT_DRAG) { return NULL; } if (startdrag && xc >= 0 && xc <= 2*from->w && yc >= 0 && yc <= 2*from->h) { ui->drag_start_x = xc; ui->drag_start_y = yc; ui->drag_end_x = -1; ui->drag_end_y = -1; ui->dragged = FALSE; ui->erasing = erasing; active = TRUE; } if (ui->drag_start_x >= 0 && (xc != ui->drag_end_x || yc != ui->drag_end_y)) { int t; if (ui->drag_end_x != -1 && ui->drag_end_y != -1) ui->dragged = TRUE; ui->drag_end_x = xc; ui->drag_end_y = yc; active = TRUE; if (xc >= 0 && xc <= 2*from->w && yc >= 0 && yc <= 2*from->h) { ui->x1 = ui->drag_start_x; ui->x2 = ui->drag_end_x; if (ui->x2 < ui->x1) { t = ui->x1; ui->x1 = ui->x2; ui->x2 = t; } ui->y1 = ui->drag_start_y; ui->y2 = ui->drag_end_y; if (ui->y2 < ui->y1) { t = ui->y1; ui->y1 = ui->y2; ui->y2 = t; } ui->x1 = ui->x1 / 2; /* rounds down */ ui->x2 = (ui->x2+1) / 2; /* rounds up */ ui->y1 = ui->y1 / 2; /* rounds down */ ui->y2 = (ui->y2+1) / 2; /* rounds up */ } else { ui->x1 = -1; ui->y1 = -1; ui->x2 = -1; ui->y2 = -1; } } ret = NULL; if (enddrag && (ui->drag_start_x >= 0)) { if (xc >= 0 && xc <= 2*from->w && yc >= 0 && yc <= 2*from->h && erasing == ui->erasing) { if (ui->dragged) { if (ui_draw_rect(from, ui, from->hedge, from->vedge, 1, FALSE, !ui->erasing)) { sprintf(buf, "%c%d,%d,%d,%d", (int)(ui->erasing ? 'E' : 'R'), ui->x1, ui->y1, ui->x2 - ui->x1, ui->y2 - ui->y1); ret = dupstr(buf); } } else { if ((xc & 1) && !(yc & 1) && HRANGE(from,xc/2,yc/2)) { sprintf(buf, "H%d,%d", xc/2, yc/2); ret = dupstr(buf); } if ((yc & 1) && !(xc & 1) && VRANGE(from,xc/2,yc/2)) { sprintf(buf, "V%d,%d", xc/2, yc/2); ret = dupstr(buf); } } } reset_ui(ui); active = TRUE; } if (ret) return ret; /* a move has been made */ else if (active) return ""; /* UI activity has occurred */ else return NULL; } static game_state *execute_move(const game_state *from, const char *move) { game_state *ret; int x1, y1, x2, y2, mode; if (move[0] == 'S') { const char *p = move+1; int x, y; ret = dup_game(from); ret->cheated = TRUE; for (y = 0; y < ret->h; y++) for (x = 1; x < ret->w; x++) { vedge(ret, x, y) = (*p == '1'); if (*p) p++; } for (y = 1; y < ret->h; y++) for (x = 0; x < ret->w; x++) { hedge(ret, x, y) = (*p == '1'); if (*p) p++; } sfree(ret->correct); ret->correct = get_correct(ret); return ret; } else if ((move[0] == 'R' || move[0] == 'E') && sscanf(move+1, "%d,%d,%d,%d", &x1, &y1, &x2, &y2) == 4 && x1 >= 0 && x2 >= 0 && x1+x2 <= from->w && y1 >= 0 && y2 >= 0 && y1+y2 <= from->h) { x2 += x1; y2 += y1; mode = move[0]; } else if ((move[0] == 'H' || move[0] == 'V') && sscanf(move+1, "%d,%d", &x1, &y1) == 2 && (move[0] == 'H' ? HRANGE(from, x1, y1) : VRANGE(from, x1, y1))) { mode = move[0]; } else return NULL; /* can't parse move string */ ret = dup_game(from); if (mode == 'R' || mode == 'E') { grid_draw_rect(ret, ret->hedge, ret->vedge, 1, TRUE, mode == 'R', x1, y1, x2, y2); } else if (mode == 'H') { hedge(ret,x1,y1) = !hedge(ret,x1,y1); } else if (mode == 'V') { vedge(ret,x1,y1) = !vedge(ret,x1,y1); } sfree(ret->correct); ret->correct = get_correct(ret); /* * We've made a real change to the grid. Check to see * if the game has been completed. */ if (!ret->completed) { int x, y, ok; ok = TRUE; for (x = 0; x < ret->w; x++) for (y = 0; y < ret->h; y++) if (!index(ret, ret->correct, x, y)) ok = FALSE; if (ok) ret->completed = TRUE; } return ret; } /* ---------------------------------------------------------------------- * Drawing routines. */ #define CORRECT (1L<<16) #define CURSOR (1L<<17) #define COLOUR(k) ( (k)==1 ? COL_LINE : (k)==2 ? COL_DRAG : COL_DRAGERASE ) #define MAX4(x,y,z,w) ( max(max(x,y),max(z,w)) ) static void game_compute_size(const game_params *params, int tilesize, int *x, int *y) { /* Ick: fake up `ds->tilesize' for macro expansion purposes */ struct { int tilesize; } ads, *ds = &ads; ads.tilesize = tilesize; *x = params->w * TILE_SIZE + 2*BORDER + 1; *y = params->h * TILE_SIZE + 2*BORDER + 1; } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { ds->tilesize = tilesize; } static float *game_colours(frontend *fe, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float); frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]); ret[COL_GRID * 3 + 0] = 0.5F * ret[COL_BACKGROUND * 3 + 0]; ret[COL_GRID * 3 + 1] = 0.5F * ret[COL_BACKGROUND * 3 + 1]; ret[COL_GRID * 3 + 2] = 0.5F * ret[COL_BACKGROUND * 3 + 2]; ret[COL_DRAG * 3 + 0] = 1.0F; ret[COL_DRAG * 3 + 1] = 0.0F; ret[COL_DRAG * 3 + 2] = 0.0F; ret[COL_DRAGERASE * 3 + 0] = 0.2F; ret[COL_DRAGERASE * 3 + 1] = 0.2F; ret[COL_DRAGERASE * 3 + 2] = 1.0F; ret[COL_CORRECT * 3 + 0] = 0.75F * ret[COL_BACKGROUND * 3 + 0]; ret[COL_CORRECT * 3 + 1] = 0.75F * ret[COL_BACKGROUND * 3 + 1]; ret[COL_CORRECT * 3 + 2] = 0.75F * ret[COL_BACKGROUND * 3 + 2]; ret[COL_LINE * 3 + 0] = 0.0F; ret[COL_LINE * 3 + 1] = 0.0F; ret[COL_LINE * 3 + 2] = 0.0F; ret[COL_TEXT * 3 + 0] = 0.0F; ret[COL_TEXT * 3 + 1] = 0.0F; ret[COL_TEXT * 3 + 2] = 0.0F; ret[COL_CURSOR * 3 + 0] = 1.0F; ret[COL_CURSOR * 3 + 1] = 0.5F; ret[COL_CURSOR * 3 + 2] = 0.5F; *ncolours = NCOLOURS; return ret; } static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { struct game_drawstate *ds = snew(struct game_drawstate); int i; ds->started = FALSE; ds->w = state->w; ds->h = state->h; ds->visible = snewn(ds->w * ds->h, unsigned long); ds->tilesize = 0; /* not decided yet */ for (i = 0; i < ds->w * ds->h; i++) ds->visible[i] = 0xFFFF; return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { sfree(ds->visible); sfree(ds); } static void draw_tile(drawing *dr, game_drawstate *ds, const game_state *state, int x, int y, unsigned char *hedge, unsigned char *vedge, unsigned char *corners, unsigned long bgflags) { int cx = COORD(x), cy = COORD(y); char str[80]; draw_rect(dr, cx, cy, TILE_SIZE+1, TILE_SIZE+1, COL_GRID); draw_rect(dr, cx+1, cy+1, TILE_SIZE-1, TILE_SIZE-1, (bgflags & CURSOR) ? COL_CURSOR : (bgflags & CORRECT) ? COL_CORRECT : COL_BACKGROUND); if (grid(state,x,y)) { sprintf(str, "%d", grid(state,x,y)); draw_text(dr, cx+TILE_SIZE/2, cy+TILE_SIZE/2, FONT_VARIABLE, TILE_SIZE/2, ALIGN_HCENTRE | ALIGN_VCENTRE, COL_TEXT, str); } /* * Draw edges. */ if (!HRANGE(state,x,y) || index(state,hedge,x,y)) draw_rect(dr, cx, cy, TILE_SIZE+1, 2, HRANGE(state,x,y) ? COLOUR(index(state,hedge,x,y)) : COL_LINE); if (!HRANGE(state,x,y+1) || index(state,hedge,x,y+1)) draw_rect(dr, cx, cy+TILE_SIZE-1, TILE_SIZE+1, 2, HRANGE(state,x,y+1) ? COLOUR(index(state,hedge,x,y+1)) : COL_LINE); if (!VRANGE(state,x,y) || index(state,vedge,x,y)) draw_rect(dr, cx, cy, 2, TILE_SIZE+1, VRANGE(state,x,y) ? COLOUR(index(state,vedge,x,y)) : COL_LINE); if (!VRANGE(state,x+1,y) || index(state,vedge,x+1,y)) draw_rect(dr, cx+TILE_SIZE-1, cy, 2, TILE_SIZE+1, VRANGE(state,x+1,y) ? COLOUR(index(state,vedge,x+1,y)) : COL_LINE); /* * Draw corners. */ if (index(state,corners,x,y)) draw_rect(dr, cx, cy, 2, 2, COLOUR(index(state,corners,x,y))); if (x+1 < state->w && index(state,corners,x+1,y)) draw_rect(dr, cx+TILE_SIZE-1, cy, 2, 2, COLOUR(index(state,corners,x+1,y))); if (y+1 < state->h && index(state,corners,x,y+1)) draw_rect(dr, cx, cy+TILE_SIZE-1, 2, 2, COLOUR(index(state,corners,x,y+1))); if (x+1 < state->w && y+1 < state->h && index(state,corners,x+1,y+1)) draw_rect(dr, cx+TILE_SIZE-1, cy+TILE_SIZE-1, 2, 2, COLOUR(index(state,corners,x+1,y+1))); draw_update(dr, cx, cy, TILE_SIZE+1, TILE_SIZE+1); } static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float animtime, float flashtime) { int x, y; unsigned char *hedge, *vedge, *corners; if (ui->dragged) { hedge = snewn(state->w*state->h, unsigned char); vedge = snewn(state->w*state->h, unsigned char); memcpy(hedge, state->hedge, state->w*state->h); memcpy(vedge, state->vedge, state->w*state->h); ui_draw_rect(state, ui, hedge, vedge, ui->erasing ? 3 : 2, TRUE, TRUE); } else { hedge = state->hedge; vedge = state->vedge; } corners = snewn(state->w * state->h, unsigned char); memset(corners, 0, state->w * state->h); for (x = 0; x < state->w; x++) for (y = 0; y < state->h; y++) { if (x > 0) { int e = index(state, vedge, x, y); if (index(state,corners,x,y) < e) index(state,corners,x,y) = e; if (y+1 < state->h && index(state,corners,x,y+1) < e) index(state,corners,x,y+1) = e; } if (y > 0) { int e = index(state, hedge, x, y); if (index(state,corners,x,y) < e) index(state,corners,x,y) = e; if (x+1 < state->w && index(state,corners,x+1,y) < e) index(state,corners,x+1,y) = e; } } if (!ds->started) { draw_rect(dr, 0, 0, state->w * TILE_SIZE + 2*BORDER + 1, state->h * TILE_SIZE + 2*BORDER + 1, COL_BACKGROUND); draw_rect(dr, COORD(0)-1, COORD(0)-1, ds->w*TILE_SIZE+3, ds->h*TILE_SIZE+3, COL_LINE); ds->started = TRUE; draw_update(dr, 0, 0, state->w * TILE_SIZE + 2*BORDER + 1, state->h * TILE_SIZE + 2*BORDER + 1); } for (x = 0; x < state->w; x++) for (y = 0; y < state->h; y++) { unsigned long c = 0; if (HRANGE(state,x,y)) c |= index(state,hedge,x,y); if (HRANGE(state,x,y+1)) c |= index(state,hedge,x,y+1) << 2; if (VRANGE(state,x,y)) c |= index(state,vedge,x,y) << 4; if (VRANGE(state,x+1,y)) c |= index(state,vedge,x+1,y) << 6; c |= index(state,corners,x,y) << 8; if (x+1 < state->w) c |= index(state,corners,x+1,y) << 10; if (y+1 < state->h) c |= index(state,corners,x,y+1) << 12; if (x+1 < state->w && y+1 < state->h) /* cast to prevent 2<<14 sign-extending on promotion to long */ c |= (unsigned long)index(state,corners,x+1,y+1) << 14; if (index(state, state->correct, x, y) && !flashtime) c |= CORRECT; if (ui->cur_visible && ui->cur_x == x && ui->cur_y == y) c |= CURSOR; if (index(ds,ds->visible,x,y) != c) { draw_tile(dr, ds, state, x, y, hedge, vedge, corners, (c & (CORRECT|CURSOR)) ); index(ds,ds->visible,x,y) = c; } } { char buf[256]; if (ui->dragged && ui->x1 >= 0 && ui->y1 >= 0 && ui->x2 >= 0 && ui->y2 >= 0) { sprintf(buf, "%dx%d ", ui->x2-ui->x1, ui->y2-ui->y1); } else { buf[0] = '\0'; } if (state->cheated) strcat(buf, "Auto-solved."); else if (state->completed) strcat(buf, "COMPLETED!"); status_bar(dr, buf); } if (hedge != state->hedge) { sfree(hedge); sfree(vedge); } sfree(corners); } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return 0.0F; } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { if (!oldstate->completed && newstate->completed && !oldstate->cheated && !newstate->cheated) return FLASH_TIME; return 0.0F; } static int game_status(const game_state *state) { return state->completed ? +1 : 0; } static int game_timing_state(const game_state *state, game_ui *ui) { return TRUE; } static void game_print_size(const game_params *params, float *x, float *y) { int pw, ph; /* * I'll use 5mm squares by default. */ game_compute_size(params, 500, &pw, &ph); *x = pw / 100.0F; *y = ph / 100.0F; } static void game_print(drawing *dr, const game_state *state, int tilesize) { int w = state->w, h = state->h; int ink = print_mono_colour(dr, 0); int x, y; /* Ick: fake up `ds->tilesize' for macro expansion purposes */ game_drawstate ads, *ds = &ads; game_set_size(dr, ds, NULL, tilesize); /* * Border. */ print_line_width(dr, TILE_SIZE / 10); draw_rect_outline(dr, COORD(0), COORD(0), w*TILE_SIZE, h*TILE_SIZE, ink); /* * Grid. We have to make the grid lines particularly thin, * because users will be drawing lines _along_ them and we want * those lines to be visible. */ print_line_width(dr, TILE_SIZE / 256); for (x = 1; x < w; x++) draw_line(dr, COORD(x), COORD(0), COORD(x), COORD(h), ink); for (y = 1; y < h; y++) draw_line(dr, COORD(0), COORD(y), COORD(w), COORD(y), ink); /* * Solution. */ print_line_width(dr, TILE_SIZE / 10); for (y = 0; y <= h; y++) for (x = 0; x <= w; x++) { if (HRANGE(state,x,y) && hedge(state,x,y)) draw_line(dr, COORD(x), COORD(y), COORD(x+1), COORD(y), ink); if (VRANGE(state,x,y) && vedge(state,x,y)) draw_line(dr, COORD(x), COORD(y), COORD(x), COORD(y+1), ink); } /* * Clues. */ for (y = 0; y < h; y++) for (x = 0; x < w; x++) if (grid(state,x,y)) { char str[80]; sprintf(str, "%d", grid(state,x,y)); draw_text(dr, COORD(x)+TILE_SIZE/2, COORD(y)+TILE_SIZE/2, FONT_VARIABLE, TILE_SIZE/2, ALIGN_HCENTRE | ALIGN_VCENTRE, ink, str); } } #ifdef COMBINED #define thegame rect #endif const struct game thegame = { "Rectangles", "games.rectangles", "rect", default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, TRUE, solve_game, TRUE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, PREFERRED_TILE_SIZE, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, TRUE, FALSE, game_print_size, game_print, TRUE, /* wants_statusbar */ FALSE, game_timing_state, 0, /* flags */ }; /* vim: set shiftwidth=4 tabstop=8: */ puzzles-20170606.272beef/range.c0000644000175000017500000015670413115373615015146 0ustar simonsimon/* * range.c: implementation of the Nikoli game 'Kurodoko' / 'Kuromasu'. */ /* * Puzzle rules: the player is given a WxH grid of white squares, some * of which contain numbers. The goal is to paint some of the squares * black, such that: * * - no cell (err, cell = square) with a number is painted black * - no black cells have an adjacent (horz/vert) black cell * - the white cells are all connected (through other white cells) * - if a cell contains a number n, let h and v be the lengths of the * maximal horizontal and vertical white sequences containing that * cell. Then n must equal h + v - 1. */ /* example instance with its encoding and textual representation, both * solved and unsolved (made by thegame.solve and thegame.text_format) * * +--+--+--+--+--+--+--+ * | | | | | 7| | | * +--+--+--+--+--+--+--+ * | 3| | | | | | 8| * +--+--+--+--+--+--+--+ * | | | | | | 5| | * +--+--+--+--+--+--+--+ * | | | 7| | 7| | | * +--+--+--+--+--+--+--+ * | |13| | | | | | * +--+--+--+--+--+--+--+ * | 4| | | | | | 8| * +--+--+--+--+--+--+--+ * | | | 4| | | | | * +--+--+--+--+--+--+--+ * * 7x7:d7b3e8e5c7a7c13e4d8b4d * * +--+--+--+--+--+--+--+ * |..|..|..|..| 7|..|..| * +--+--+--+--+--+--+--+ * | 3|..|##|..|##|..| 8| * +--+--+--+--+--+--+--+ * |##|..|..|##|..| 5|..| * +--+--+--+--+--+--+--+ * |..|..| 7|..| 7|##|..| * +--+--+--+--+--+--+--+ * |..|13|..|..|..|..|..| * +--+--+--+--+--+--+--+ * | 4|..|##|..|##|..| 8| * +--+--+--+--+--+--+--+ * |##|..| 4|..|..|##|..| * +--+--+--+--+--+--+--+ */ #include #include #include #include #include #include #include "puzzles.h" #include #define setmember(obj, field) ( (obj) . field = field ) static char *nfmtstr(int n, char *fmt, ...) { va_list va; char *ret = snewn(n+1, char); va_start(va, fmt); vsprintf(ret, fmt, va); va_end(va); return ret; } #define SWAP(type, lvar1, lvar2) do { \ type tmp = (lvar1); \ (lvar1) = (lvar2); \ (lvar2) = tmp; \ } while (0) /* ---------------------------------------------------------------------- * Game parameters, presets, states */ typedef signed char puzzle_size; struct game_params { puzzle_size w; puzzle_size h; }; struct game_state { struct game_params params; unsigned int has_cheated: 1; unsigned int was_solved: 1; puzzle_size *grid; }; #define DEFAULT_PRESET 0 static struct game_params range_presets[] = {{9, 6}, {12, 8}, {13, 9}, {16, 11}}; /* rationale: I want all four combinations of {odd/even, odd/even}, as * they play out differently with respect to two-way symmetry. I also * want them to be generated relatively fast yet still be large enough * to be entertaining for a decent amount of time, and I want them to * make good use of monitor real estate (the typical screen resolution * is why I do 13x9 and not 9x13). */ static game_params *default_params(void) { game_params *ret = snew(game_params); *ret = range_presets[DEFAULT_PRESET]; /* structure copy */ return ret; } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } static int game_fetch_preset(int i, char **name, game_params **params) { game_params *ret; if (i < 0 || i >= lenof(range_presets)) return FALSE; ret = default_params(); *ret = range_presets[i]; /* struct copy */ *params = ret; *name = nfmtstr(40, "%d x %d", range_presets[i].w, range_presets[i].h); return TRUE; } static void free_params(game_params *params) { sfree(params); } static void decode_params(game_params *params, char const *string) { /* FIXME check for puzzle_size overflow and decoding issues */ params->w = params->h = atoi(string); while (*string && isdigit((unsigned char) *string)) ++string; if (*string == 'x') { string++; params->h = atoi(string); while (*string && isdigit((unsigned char)*string)) string++; } } static char *encode_params(const game_params *params, int full) { char str[80]; sprintf(str, "%dx%d", params->w, params->h); return dupstr(str); } static config_item *game_configure(const game_params *params) { config_item *ret; ret = snewn(3, config_item); ret[0].name = "Width"; ret[0].type = C_STRING; ret[0].sval = nfmtstr(10, "%d", params->w); ret[0].ival = 0; ret[1].name = "Height"; ret[1].type = C_STRING; ret[1].sval = nfmtstr(10, "%d", params->h); ret[1].ival = 0; ret[2].name = NULL; ret[2].type = C_END; ret[2].sval = NULL; ret[2].ival = 0; return ret; } static game_params *custom_params(const config_item *configuration) { game_params *ret = snew(game_params); ret->w = atoi(configuration[0].sval); ret->h = atoi(configuration[1].sval); return ret; } #define memdup(dst, src, n, type) do { \ dst = snewn(n, type); \ memcpy(dst, src, n * sizeof (type)); \ } while (0) static game_state *dup_game(const game_state *state) { game_state *ret = snew(game_state); int const n = state->params.w * state->params.h; *ret = *state; /* structure copy */ /* copy the poin_tee_, set a new value of the poin_ter_ */ memdup(ret->grid, state->grid, n, puzzle_size); return ret; } static void free_game(game_state *state) { sfree(state->grid); sfree(state); } /* ---------------------------------------------------------------------- * The solver subsystem. * * The solver is used for two purposes: * - To solve puzzles when the user selects `Solve'. * - To test solubility of a grid as clues are being removed from it * during the puzzle generation. * * It supports the following ways of reasoning: * * - A cell adjacent to a black cell must be white. * * - If painting a square black would bisect the white regions, that * square is white (by finding biconnected components' cut points) * * - A cell with number n, covering at most k white squares in three * directions must white-cover n-k squares in the last direction. * * - A cell with number n known to cover k squares, if extending the * cover by one square in a given direction causes the cell to * cover _more_ than n squares, that extension cell must be black. * * (either if the square already covers n, or if it extends into a * chunk of size > n - k) * * - Recursion. Pick any cell and see if this leads to either a * contradiction or a solution (and then act appropriately). * * * TODO: * * (propagation upper limit) * - If one has two numbers on the same line, the smaller limits the * larger. Example: in |b|_|_|8|4|_|_|b|, only two _'s can be both * white and connected to the "8" cell; so that cell will propagate * at least four cells orthogonally to the displayed line (which is * better than the current "at least 2"). * * (propagation upper limit) * - cells can't propagate into other cells if doing so exceeds that * number. Example: in |b|4|.|.|2|b|, at most one _ can be white; * otherwise, the |2| would have too many reaching white cells. * * (propagation lower and upper limit) * - `Full Combo': in each four directions d_1 ... d_4, find a set of * possible propagation distances S_1 ... S_4. For each i=1..4, * for each x in S_i: if not exists (y, z, w) in the other sets * such that (x+y+z+w+1 == clue value): then remove x from S_i. * Repeat until this stabilizes. If any cell would contradict */ #define idx(i, j, w) ((i)*(w) + (j)) #define out_of_bounds(r, c, w, h) \ ((r) < 0 || (r) >= h || (c) < 0 || (c) >= w) typedef struct square { puzzle_size r, c; } square; enum {BLACK = -2, WHITE, EMPTY}; /* white is for pencil marks, empty is undecided */ static int const dr[4] = {+1, 0, -1, 0}; static int const dc[4] = { 0, +1, 0, -1}; static int const cursors[4] = /* must match dr and dc */ {CURSOR_DOWN, CURSOR_RIGHT, CURSOR_UP, CURSOR_LEFT}; typedef struct move { square square; unsigned int colour: 1; } move; enum {M_BLACK = 0, M_WHITE = 1}; typedef move *(reasoning)(game_state *state, int nclues, const square *clues, move *buf); static reasoning solver_reasoning_not_too_big; static reasoning solver_reasoning_adjacency; static reasoning solver_reasoning_connectedness; static reasoning solver_reasoning_recursion; enum { DIFF_NOT_TOO_BIG, DIFF_ADJACENCY, DIFF_CONNECTEDNESS, DIFF_RECURSION }; static move *solve_internal(const game_state *state, move *base, int diff); static char *solve_game(const game_state *orig, const game_state *curpos, const char *aux, char **error) { int const n = orig->params.w * orig->params.h; move *const base = snewn(n, move); move *moves = solve_internal(orig, base, DIFF_RECURSION); char *ret = NULL; if (moves != NULL) { int const k = moves - base; char *str = ret = snewn(15*k + 2, char); char colour[2] = "BW"; move *it; *str++ = 'S'; *str = '\0'; for (it = base; it < moves; ++it) str += sprintf(str, "%c,%d,%d", colour[it->colour], it->square.r, it->square.c); } else *error = "This puzzle instance contains a contradiction"; sfree(base); return ret; } static square *find_clues(const game_state *state, int *ret_nclues); static move *do_solve(game_state *state, int nclues, const square *clues, move *move_buffer, int difficulty); /* new_game_desc entry point in the solver subsystem */ static move *solve_internal(const game_state *state, move *base, int diff) { int nclues; square *const clues = find_clues(state, &nclues); game_state *dup = dup_game(state); move *const moves = do_solve(dup, nclues, clues, base, diff); free_game(dup); sfree(clues); return moves; } static reasoning *const reasonings[] = { solver_reasoning_not_too_big, solver_reasoning_adjacency, solver_reasoning_connectedness, solver_reasoning_recursion }; static move *do_solve(game_state *state, int nclues, const square *clues, move *move_buffer, int difficulty) { struct move *buf = move_buffer, *oldbuf; int i; do { oldbuf = buf; for (i = 0; i < lenof(reasonings) && i <= difficulty; ++i) { /* only recurse if all else fails */ if (i == DIFF_RECURSION && buf > oldbuf) continue; buf = (*reasonings[i])(state, nclues, clues, buf); if (buf == NULL) return NULL; } } while (buf > oldbuf); return buf; } #define MASK(n) (1 << ((n) + 2)) static int runlength(puzzle_size r, puzzle_size c, puzzle_size dr, puzzle_size dc, const game_state *state, int colourmask) { int const w = state->params.w, h = state->params.h; int sz = 0; while (TRUE) { int cell = idx(r, c, w); if (out_of_bounds(r, c, w, h)) break; if (state->grid[cell] > 0) { if (!(colourmask & ~(MASK(BLACK) | MASK(WHITE) | MASK(EMPTY)))) break; } else if (!(MASK(state->grid[cell]) & colourmask)) break; ++sz; r += dr; c += dc; } return sz; } static void solver_makemove(puzzle_size r, puzzle_size c, int colour, game_state *state, move **buffer_ptr) { int const cell = idx(r, c, state->params.w); if (out_of_bounds(r, c, state->params.w, state->params.h)) return; if (state->grid[cell] != EMPTY) return; setmember((*buffer_ptr)->square, r); setmember((*buffer_ptr)->square, c); setmember(**buffer_ptr, colour); ++*buffer_ptr; state->grid[cell] = (colour == M_BLACK ? BLACK : WHITE); } static move *solver_reasoning_adjacency(game_state *state, int nclues, const square *clues, move *buf) { int r, c, i; for (r = 0; r < state->params.h; ++r) for (c = 0; c < state->params.w; ++c) { int const cell = idx(r, c, state->params.w); if (state->grid[cell] != BLACK) continue; for (i = 0; i < 4; ++i) solver_makemove(r + dr[i], c + dc[i], M_WHITE, state, &buf); } return buf; } enum {NOT_VISITED = -1}; static int dfs_biconnect_visit(puzzle_size r, puzzle_size c, game_state *state, square *dfs_parent, int *dfs_depth, move **buf); static move *solver_reasoning_connectedness(game_state *state, int nclues, const square *clues, move *buf) { int const w = state->params.w, h = state->params.h, n = w * h; square *const dfs_parent = snewn(n, square); int *const dfs_depth = snewn(n, int); int i; for (i = 0; i < n; ++i) { dfs_parent[i].r = NOT_VISITED; dfs_depth[i] = -n; } for (i = 0; i < n && state->grid[i] == BLACK; ++i); dfs_parent[i].r = i / w; dfs_parent[i].c = i % w; /* `dfs root`.parent == `dfs root` */ dfs_depth[i] = 0; dfs_biconnect_visit(i / w, i % w, state, dfs_parent, dfs_depth, &buf); sfree(dfs_parent); sfree(dfs_depth); return buf; } /* returns the `lowpoint` of (r, c) */ static int dfs_biconnect_visit(puzzle_size r, puzzle_size c, game_state *state, square *dfs_parent, int *dfs_depth, move **buf) { const puzzle_size w = state->params.w, h = state->params.h; int const i = idx(r, c, w), mydepth = dfs_depth[i]; int lowpoint = mydepth, j, nchildren = 0; for (j = 0; j < 4; ++j) { const puzzle_size rr = r + dr[j], cc = c + dc[j]; int const cell = idx(rr, cc, w); if (out_of_bounds(rr, cc, w, h)) continue; if (state->grid[cell] == BLACK) continue; if (dfs_parent[cell].r == NOT_VISITED) { int child_lowpoint; dfs_parent[cell].r = r; dfs_parent[cell].c = c; dfs_depth[cell] = mydepth + 1; child_lowpoint = dfs_biconnect_visit(rr, cc, state, dfs_parent, dfs_depth, buf); if (child_lowpoint >= mydepth && mydepth > 0) solver_makemove(r, c, M_WHITE, state, buf); lowpoint = min(lowpoint, child_lowpoint); ++nchildren; } else if (rr != dfs_parent[i].r || cc != dfs_parent[i].c) { lowpoint = min(lowpoint, dfs_depth[cell]); } } if (mydepth == 0 && nchildren >= 2) solver_makemove(r, c, M_WHITE, state, buf); return lowpoint; } static move *solver_reasoning_not_too_big(game_state *state, int nclues, const square *clues, move *buf) { int const w = state->params.w, runmasks[4] = { ~(MASK(BLACK) | MASK(EMPTY)), MASK(EMPTY), ~(MASK(BLACK) | MASK(EMPTY)), ~(MASK(BLACK)) }; enum {RUN_WHITE, RUN_EMPTY, RUN_BEYOND, RUN_SPACE}; int i, runlengths[4][4]; for (i = 0; i < nclues; ++i) { int j, k, whites, space; const puzzle_size row = clues[i].r, col = clues[i].c; int const clue = state->grid[idx(row, col, w)]; for (j = 0; j < 4; ++j) { puzzle_size r = row + dr[j], c = col + dc[j]; runlengths[RUN_SPACE][j] = 0; for (k = 0; k <= RUN_SPACE; ++k) { int l = runlength(r, c, dr[j], dc[j], state, runmasks[k]); if (k < RUN_SPACE) { runlengths[k][j] = l; r += dr[j] * l; c += dc[j] * l; } runlengths[RUN_SPACE][j] += l; } } whites = 1; for (j = 0; j < 4; ++j) whites += runlengths[RUN_WHITE][j]; for (j = 0; j < 4; ++j) { int const delta = 1 + runlengths[RUN_WHITE][j]; const puzzle_size r = row + delta * dr[j]; const puzzle_size c = col + delta * dc[j]; if (whites == clue) { solver_makemove(r, c, M_BLACK, state, &buf); continue; } if (runlengths[RUN_EMPTY][j] == 1 && whites + runlengths[RUN_EMPTY][j] + runlengths[RUN_BEYOND][j] > clue) { solver_makemove(r, c, M_BLACK, state, &buf); continue; } if (whites + runlengths[RUN_EMPTY][j] + runlengths[RUN_BEYOND][j] > clue) { runlengths[RUN_SPACE][j] = runlengths[RUN_WHITE][j] + runlengths[RUN_EMPTY][j] - 1; if (runlengths[RUN_EMPTY][j] == 1) solver_makemove(r, c, M_BLACK, state, &buf); } } space = 1; for (j = 0; j < 4; ++j) space += runlengths[RUN_SPACE][j]; for (j = 0; j < 4; ++j) { puzzle_size r = row + dr[j], c = col + dc[j]; int k = space - runlengths[RUN_SPACE][j]; if (k >= clue) continue; for (; k < clue; ++k, r += dr[j], c += dc[j]) solver_makemove(r, c, M_WHITE, state, &buf); } } return buf; } static move *solver_reasoning_recursion(game_state *state, int nclues, const square *clues, move *buf) { int const w = state->params.w, n = w * state->params.h; int cell, colour; for (cell = 0; cell < n; ++cell) { int const r = cell / w, c = cell % w; int i; game_state *newstate; move *recursive_result; if (state->grid[cell] != EMPTY) continue; /* FIXME: add enum alias for smallest and largest (or N) */ for (colour = M_BLACK; colour <= M_WHITE; ++colour) { newstate = dup_game(state); newstate->grid[cell] = colour; recursive_result = do_solve(newstate, nclues, clues, buf, DIFF_RECURSION); free_game(newstate); if (recursive_result == NULL) { solver_makemove(r, c, M_BLACK + M_WHITE - colour, state, &buf); return buf; } for (i = 0; i < n && newstate->grid[i] != EMPTY; ++i); if (i == n) return buf; } } return buf; } static square *find_clues(const game_state *state, int *ret_nclues) { int r, c, i, nclues = 0; square *ret = snewn(state->params.w * state->params.h, struct square); for (i = r = 0; r < state->params.h; ++r) for (c = 0; c < state->params.w; ++c, ++i) if (state->grid[i] > 0) { ret[nclues].r = r; ret[nclues].c = c; ++nclues; } *ret_nclues = nclues; return sresize(ret, nclues + (nclues == 0), square); } /* ---------------------------------------------------------------------- * Puzzle generation * * Generating kurodoko instances is rather straightforward: * * - Start with a white grid and add black squares at randomly chosen * locations, unless colouring that square black would violate * either the adjacency or connectedness constraints. * * - For each white square, compute the number it would contain if it * were given as a clue. * * - From a starting point of "give _every_ white square as a clue", * for each white square (in a random order), see if the board is * solvable when that square is not given as a clue. If not, don't * give it as a clue, otherwise do. * * This never fails, but it's only _almost_ what I do. The real final * step is this: * * - From a starting point of "give _every_ white square as a clue", * first remove all clues that are two-way rotationally symmetric * to a black square. If this leaves the puzzle unsolvable, throw * it out and try again. Otherwise, remove all _pairs_ of clues * (that are rotationally symmetric) which can be removed without * rendering the puzzle unsolvable. * * This can fail even if one only removes the black and symmetric * clues; indeed it happens often (avg. once or twice per puzzle) when * generating 1xN instances. (If you add black cells they must be in * the end, and if you only add one, it's ambiguous where). */ /* forward declarations of internal calls */ static void newdesc_choose_black_squares(game_state *state, const int *shuffle_1toN); static void newdesc_compute_clues(game_state *state); static int newdesc_strip_clues(game_state *state, int *shuffle_1toN); static char *newdesc_encode_game_description(int n, puzzle_size *grid); static char *new_game_desc(const game_params *params, random_state *rs, char **aux, int interactive) { int const w = params->w, h = params->h, n = w * h; puzzle_size *const grid = snewn(n, puzzle_size); int *const shuffle_1toN = snewn(n, int); int i, clues_removed; char *encoding; game_state state; state.params = *params; state.grid = grid; interactive = 0; /* I don't need it, I shouldn't use it*/ for (i = 0; i < n; ++i) shuffle_1toN[i] = i; while (TRUE) { shuffle(shuffle_1toN, n, sizeof (int), rs); newdesc_choose_black_squares(&state, shuffle_1toN); newdesc_compute_clues(&state); shuffle(shuffle_1toN, n, sizeof (int), rs); clues_removed = newdesc_strip_clues(&state, shuffle_1toN); if (clues_removed < 0) continue; else break; } encoding = newdesc_encode_game_description(n, grid); sfree(grid); sfree(shuffle_1toN); return encoding; } static int dfs_count_white(game_state *state, int cell); static void newdesc_choose_black_squares(game_state *state, const int *shuffle_1toN) { int const w = state->params.w, h = state->params.h, n = w * h; int k, any_white_cell, n_black_cells; for (k = 0; k < n; ++k) state->grid[k] = WHITE; any_white_cell = shuffle_1toN[n - 1]; n_black_cells = 0; /* I like the puzzles that result from n / 3, but maybe this * could be made a (generation, i.e. non-full) parameter? */ for (k = 0; k < n / 3; ++k) { int const i = shuffle_1toN[k], c = i % w, r = i / w; int j; for (j = 0; j < 4; ++j) { int const rr = r + dr[j], cc = c + dc[j], cell = idx(rr, cc, w); /* if you're out of bounds, we skip you */ if (out_of_bounds(rr, cc, w, h)) continue; if (state->grid[cell] == BLACK) break; /* I can't be black */ } if (j < 4) continue; /* I have black neighbour: I'm white */ state->grid[i] = BLACK; ++n_black_cells; j = dfs_count_white(state, any_white_cell); if (j + n_black_cells < n) { state->grid[i] = WHITE; --n_black_cells; } } } static void newdesc_compute_clues(game_state *state) { int const w = state->params.w, h = state->params.h; int r, c; for (r = 0; r < h; ++r) { int run_size = 0, c, cc; for (c = 0; c <= w; ++c) { if (c == w || state->grid[idx(r, c, w)] == BLACK) { for (cc = c - run_size; cc < c; ++cc) state->grid[idx(r, cc, w)] += run_size; run_size = 0; } else ++run_size; } } for (c = 0; c < w; ++c) { int run_size = 0, r, rr; for (r = 0; r <= h; ++r) { if (r == h || state->grid[idx(r, c, w)] == BLACK) { for (rr = r - run_size; rr < r; ++rr) state->grid[idx(rr, c, w)] += run_size; run_size = 0; } else ++run_size; } } } #define rotate(x) (n - 1 - (x)) static int newdesc_strip_clues(game_state *state, int *shuffle_1toN) { int const w = state->params.w, n = w * state->params.h; move *const move_buffer = snewn(n, move); move *buf; game_state *dupstate; /* * do a partition/pivot of shuffle_1toN into three groups: * (1) squares rotationally-symmetric to (3) * (2) squares not in (1) or (3) * (3) black squares * * They go from [0, left), [left, right) and [right, n) in * shuffle_1toN (and from there into state->grid[ ]) * * Then, remove clues from the grid one by one in shuffle_1toN * order, until the solver becomes unhappy. If we didn't remove * all of (1), return (-1). Else, we're happy. */ /* do the partition */ int clues_removed, k = 0, left = 0, right = n; for (;; ++k) { while (k < right && state->grid[shuffle_1toN[k]] == BLACK) { --right; SWAP(int, shuffle_1toN[right], shuffle_1toN[k]); assert(state->grid[shuffle_1toN[right]] == BLACK); } if (k >= right) break; assert (k >= left); if (state->grid[rotate(shuffle_1toN[k])] == BLACK) { SWAP(int, shuffle_1toN[k], shuffle_1toN[left]); ++left; } assert (state->grid[rotate(shuffle_1toN[k])] != BLACK || k == left - 1); } for (k = 0; k < left; ++k) { assert (state->grid[rotate(shuffle_1toN[k])] == BLACK); state->grid[shuffle_1toN[k]] = EMPTY; } for (k = left; k < right; ++k) { assert (state->grid[rotate(shuffle_1toN[k])] != BLACK); assert (state->grid[shuffle_1toN[k]] != BLACK); } for (k = right; k < n; ++k) { assert (state->grid[shuffle_1toN[k]] == BLACK); state->grid[shuffle_1toN[k]] = EMPTY; } clues_removed = (left - 0) + (n - right); dupstate = dup_game(state); buf = solve_internal(dupstate, move_buffer, DIFF_RECURSION - 1); free_game(dupstate); if (buf - move_buffer < clues_removed) { /* branch prediction: I don't think I'll go here */ clues_removed = -1; goto ret; } for (k = left; k < right; ++k) { const int i = shuffle_1toN[k], j = rotate(i); int const clue = state->grid[i], clue_rot = state->grid[j]; if (clue == BLACK) continue; state->grid[i] = state->grid[j] = EMPTY; dupstate = dup_game(state); buf = solve_internal(dupstate, move_buffer, DIFF_RECURSION - 1); free_game(dupstate); clues_removed += 2 - (i == j); /* if i is the center square, then i == (j = rotate(i)) * when i and j are one, removing i and j removes only one */ if (buf - move_buffer == clues_removed) continue; /* if the solver is sound, refilling all removed clues means * we have filled all squares, i.e. solved the puzzle. */ state->grid[i] = clue; state->grid[j] = clue_rot; clues_removed -= 2 - (i == j); } ret: sfree(move_buffer); return clues_removed; } static int dfs_count_rec(puzzle_size *grid, int r, int c, int w, int h) { int const cell = idx(r, c, w); if (out_of_bounds(r, c, w, h)) return 0; if (grid[cell] != WHITE) return 0; grid[cell] = EMPTY; return 1 + dfs_count_rec(grid, r + 0, c + 1, w, h) + dfs_count_rec(grid, r + 0, c - 1, w, h) + dfs_count_rec(grid, r + 1, c + 0, w, h) + dfs_count_rec(grid, r - 1, c + 0, w, h); } static int dfs_count_white(game_state *state, int cell) { int const w = state->params.w, h = state->params.h, n = w * h; int const r = cell / w, c = cell % w; int i, k = dfs_count_rec(state->grid, r, c, w, h); for (i = 0; i < n; ++i) if (state->grid[i] == EMPTY) state->grid[i] = WHITE; return k; } static char *validate_params(const game_params *params, int full) { int const w = params->w, h = params->h; if (w < 1) return "Error: width is less than 1"; if (h < 1) return "Error: height is less than 1"; if (w * h < 1) return "Error: size is less than 1"; if (w + h - 1 > SCHAR_MAX) return "Error: w + h is too big"; /* I might be unable to store clues in my puzzle_size *grid; */ if (full) { if (w == 2 && h == 2) return "Error: can't create 2x2 puzzles"; if (w == 1 && h == 2) return "Error: can't create 1x2 puzzles"; if (w == 2 && h == 1) return "Error: can't create 2x1 puzzles"; if (w == 1 && h == 1) return "Error: can't create 1x1 puzzles"; } return NULL; } /* Definition: a puzzle instance is _good_ if: * - it has a unique solution * - the solver can find this solution without using recursion * - the solution contains at least one black square * - the clues are 2-way rotationally symmetric * * (the idea being: the generator can not output any _bad_ puzzles) * * Theorem: validate_params, when full != 0, discards exactly the set * of parameters for which there are _no_ good puzzle instances. * * Proof: it's an immediate consequence of the five lemmas below. * * Observation: not only do puzzles on non-tiny grids exist, the * generator is pretty fast about coming up with them. On my pre-2004 * desktop box, it generates 100 puzzles on the highest preset (16x11) * in 8.383 seconds, or <= 0.1 second per puzzle. * * ---------------------------------------------------------------------- * * Lemma: On a 1x1 grid, there are no good puzzles. * * Proof: the one square can't be a clue because at least one square * is black. But both a white square and a black square satisfy the * solution criteria, so the puzzle is ambiguous (and hence bad). * * Lemma: On a 1x2 grid, there are no good puzzles. * * Proof: let's name the squares l and r. Note that there can be at * most one black square, or adjacency is violated. By assumption at * least one square is black, so let's call that one l. By clue * symmetry, neither l nor r can be given as a clue, so the puzzle * instance is blank and thus ambiguous. * * Corollary: On a 2x1 grid, there are no good puzzles. * Proof: rotate the above proof 90 degrees ;-) * * ---------------------------------------------------------------------- * * Lemma: On a 2x2 grid, there are no soluble puzzles with 2-way * rotational symmetric clues and at least one black square. * * Proof: Let's name the squares a, b, c, and d, with a and b on the * top row, a and c in the left column. Let's consider the case where * a is black. Then no other square can be black: b and c would both * violate the adjacency constraint; d would disconnect b from c. * * So exactly one square is black (and by 4-way rotation symmetry of * the 2x2 square, it doesn't matter which one, so let's stick to a). * By 2-way rotational symmetry of the clues and the rule about not * painting numbers black, neither a nor d can be clues. A blank * puzzle would be ambiguous, so one of {b, c} is a clue; by symmetry, * so is the other one. * * It is readily seen that their clue value is 2. But "a is black" * and "d is black" are both valid solutions in this case, so the * puzzle is ambiguous (and hence bad). * * ---------------------------------------------------------------------- * * Lemma: On a wxh grid with w, h >= 1 and (w > 2 or h > 2), there is * at least one good puzzle. * * Proof: assume that w > h (otherwise rotate the proof again). Paint * the top left and bottom right corners black, and fill a clue into * all the other squares. Present this board to the solver code (or * player, hypothetically), except with the two black squares as blank * squares. * * For an Nx1 puzzle, observe that every clue is N - 2, and there are * N - 2 of them in one connected sequence, so the remaining two * squares can be deduced to be black, which solves the puzzle. * * For any other puzzle, let j be a cell in the same row as a black * cell, but not in the same column (such a cell doesn't exist in 2x3 * puzzles, but we assume w > h and such cells exist in 3x2 puzzles). * * Note that the number of cells in axis parallel `rays' going out * from j exceeds j's clue value by one. Only one such cell is a * non-clue, so it must be black. Similarly for the other corner (let * j' be a cell in the same row as the _other_ black cell, but not in * the same column as _any_ black cell; repeat this argument at j'). * * This fills the grid and satisfies all clues and the adjacency * constraint and doesn't paint on top of any clues. All that is left * to see is connectedness. * * Observe that the white cells in each column form a single connected * `run', and each column contains a white cell adjacent to a white * cell in the column to the right, if that column exists. * * Thus, any cell in the left-most column can reach any other cell: * first go to the target column (by repeatedly going to the cell in * your current column that lets you go right, then going right), then * go up or down to the desired cell. * * As reachability is symmetric (in undirected graphs) and transitive, * any cell can reach any left-column cell, and from there any other * cell. */ /* ---------------------------------------------------------------------- * Game encoding and decoding */ #define NDIGITS_BASE '!' static char *newdesc_encode_game_description(int area, puzzle_size *grid) { char *desc = NULL; int desclen = 0, descsize = 0; int run, i; run = 0; for (i = 0; i <= area; i++) { int n = (i < area ? grid[i] : -1); if (!n) run++; else { if (descsize < desclen + 40) { descsize = desclen * 3 / 2 + 40; desc = sresize(desc, descsize, char); } if (run) { while (run > 0) { int c = 'a' - 1 + run; if (run > 26) c = 'z'; desc[desclen++] = c; run -= c - ('a' - 1); } } else { /* * If there's a number in the very top left or * bottom right, there's no point putting an * unnecessary _ before or after it. */ if (desclen > 0 && n > 0) desc[desclen++] = '_'; } if (n > 0) desclen += sprintf(desc+desclen, "%d", n); run = 0; } } desc[desclen] = '\0'; return desc; } static char *validate_desc(const game_params *params, const char *desc) { int const n = params->w * params->h; int squares = 0; int range = params->w + params->h - 1; /* maximum cell value */ while (*desc && *desc != ',') { int c = *desc++; if (c >= 'a' && c <= 'z') { squares += c - 'a' + 1; } else if (c == '_') { /* do nothing */; } else if (c > '0' && c <= '9') { int val = atoi(desc-1); if (val < 1 || val > range) return "Out-of-range number in game description"; squares++; while (*desc >= '0' && *desc <= '9') desc++; } else return "Invalid character in game description"; } if (squares < n) return "Not enough data to fill grid"; if (squares > n) return "Too much data to fit in grid"; return NULL; } static game_state *new_game(midend *me, const game_params *params, const char *desc) { int i; const char *p; int const n = params->w * params->h; game_state *state = snew(game_state); me = NULL; /* I don't need it, I shouldn't use it */ state->params = *params; /* structure copy */ state->grid = snewn(n, puzzle_size); p = desc; i = 0; while (i < n && *p) { int c = *p++; if (c >= 'a' && c <= 'z') { int squares = c - 'a' + 1; while (squares--) state->grid[i++] = 0; } else if (c == '_') { /* do nothing */; } else if (c > '0' && c <= '9') { int val = atoi(p-1); assert(val >= 1 && val <= params->w+params->h-1); state->grid[i++] = val; while (*p >= '0' && *p <= '9') p++; } } assert(i == n); state->has_cheated = FALSE; state->was_solved = FALSE; return state; } /* ---------------------------------------------------------------------- * User interface: ascii */ static int game_can_format_as_text_now(const game_params *params) { return TRUE; } static char *game_text_format(const game_state *state) { int r, c, i, w_string, h_string, n_string; char cellsize; char *ret, *buf, *gridline; int const w = state->params.w, h = state->params.h; cellsize = 0; /* or may be used uninitialized */ for (c = 0; c < w; ++c) { for (r = 0; r < h; ++r) { puzzle_size k = state->grid[idx(r, c, w)]; int d; for (d = 0; k; k /= 10, ++d); cellsize = max(cellsize, d); } } ++cellsize; w_string = w * cellsize + 2; /* "|%d|%d|...|\n" */ h_string = 2 * h + 1; /* "+--+--+...+\n%s\n+--+--+...+\n" */ n_string = w_string * h_string; gridline = snewn(w_string + 1, char); /* +1: NUL terminator */ memset(gridline, '-', w_string); for (c = 0; c <= w; ++c) gridline[c * cellsize] = '+'; gridline[w_string - 1] = '\n'; gridline[w_string - 0] = '\0'; buf = ret = snewn(n_string + 1, char); /* +1: NUL terminator */ for (i = r = 0; r < h; ++r) { memcpy(buf, gridline, w_string); buf += w_string; for (c = 0; c < w; ++c, ++i) { char ch; switch (state->grid[i]) { case BLACK: ch = '#'; break; case WHITE: ch = '.'; break; case EMPTY: ch = ' '; break; default: buf += sprintf(buf, "|%*d", cellsize - 1, state->grid[i]); continue; } *buf++ = '|'; memset(buf, ch, cellsize - 1); buf += cellsize - 1; } buf += sprintf(buf, "|\n"); } memcpy(buf, gridline, w_string); buf += w_string; assert (buf - ret == n_string); *buf = '\0'; sfree(gridline); return ret; } /* ---------------------------------------------------------------------- * User interfaces: interactive */ struct game_ui { puzzle_size r, c; /* cursor position */ unsigned int cursor_show: 1; }; static game_ui *new_ui(const game_state *state) { struct game_ui *ui = snew(game_ui); ui->r = ui->c = 0; ui->cursor_show = FALSE; return ui; } static void free_ui(game_ui *ui) { sfree(ui); } static char *encode_ui(const game_ui *ui) { return NULL; } static void decode_ui(game_ui *ui, const char *encoding) { } typedef struct drawcell { puzzle_size value; unsigned int error: 1; unsigned int cursor: 1; unsigned int flash: 1; } drawcell; struct game_drawstate { int tilesize; drawcell *grid; unsigned int started: 1; }; #define TILESIZE (ds->tilesize) #define BORDER (TILESIZE / 2) #define COORD(x) ((x) * TILESIZE + BORDER) #define FROMCOORD(x) (((x) - BORDER) / TILESIZE) static char *interpret_move(const game_state *state, game_ui *ui, const game_drawstate *ds, int x, int y, int button) { enum {none, forwards, backwards, hint}; int const w = state->params.w, h = state->params.h; int r = ui->r, c = ui->c, action = none, cell; int shift = button & MOD_SHFT; button &= ~shift; if (IS_CURSOR_SELECT(button) && !ui->cursor_show) return NULL; if (IS_MOUSE_DOWN(button)) { r = FROMCOORD(y + TILESIZE) - 1; /* or (x, y) < TILESIZE) */ c = FROMCOORD(x + TILESIZE) - 1; /* are considered inside */ if (out_of_bounds(r, c, w, h)) return NULL; ui->r = r; ui->c = c; ui->cursor_show = FALSE; } if (button == LEFT_BUTTON || button == RIGHT_BUTTON) { /* * Utterly awful hack, exactly analogous to the one in Slant, * to configure the left and right mouse buttons the opposite * way round. * * The original puzzle submitter thought it would be more * useful to have the left button turn an empty square into a * dotted one, on the grounds that that was what you did most * often; I (SGT) felt instinctively that the left button * ought to place black squares and the right button place * dots, on the grounds that that was consistent with many * other puzzles in which the left button fills in the data * used by the solution checker while the right button places * pencil marks for the user's convenience. * * My first beta-player wasn't sure either, so I thought I'd * pre-emptively put in a 'configuration' mechanism just in * case. */ { static int swap_buttons = -1; if (swap_buttons < 0) { char *env = getenv("RANGE_SWAP_BUTTONS"); swap_buttons = (env && (env[0] == 'y' || env[0] == 'Y')); } if (swap_buttons) { if (button == LEFT_BUTTON) button = RIGHT_BUTTON; else button = LEFT_BUTTON; } } } switch (button) { case CURSOR_SELECT : case LEFT_BUTTON: action = backwards; break; case CURSOR_SELECT2: case RIGHT_BUTTON: action = forwards; break; case 'h': case 'H' : action = hint; break; case CURSOR_UP: case CURSOR_DOWN: case CURSOR_LEFT: case CURSOR_RIGHT: if (ui->cursor_show) { int i; for (i = 0; i < 4 && cursors[i] != button; ++i); assert (i < 4); if (shift) { int pre_r = r, pre_c = c, do_pre, do_post; cell = state->grid[idx(r, c, state->params.w)]; do_pre = (cell == EMPTY); if (out_of_bounds(ui->r + dr[i], ui->c + dc[i], w, h)) { if (do_pre) return nfmtstr(40, "W,%d,%d", pre_r, pre_c); else return NULL; } ui->r += dr[i]; ui->c += dc[i]; cell = state->grid[idx(ui->r, ui->c, state->params.w)]; do_post = (cell == EMPTY); /* (do_pre ? "..." : "") concat (do_post ? "..." : "") */ if (do_pre && do_post) return nfmtstr(80, "W,%d,%dW,%d,%d", pre_r, pre_c, ui->r, ui->c); else if (do_pre) return nfmtstr(40, "W,%d,%d", pre_r, pre_c); else if (do_post) return nfmtstr(40, "W,%d,%d", ui->r, ui->c); else return ""; } else if (!out_of_bounds(ui->r + dr[i], ui->c + dc[i], w, h)) { ui->r += dr[i]; ui->c += dc[i]; } } else ui->cursor_show = TRUE; return ""; } if (action == hint) { move *end, *buf = snewn(state->params.w * state->params.h, struct move); char *ret = NULL; end = solve_internal(state, buf, DIFF_RECURSION); if (end != NULL && end > buf) { ret = nfmtstr(40, "%c,%d,%d", buf->colour == M_BLACK ? 'B' : 'W', buf->square.r, buf->square.c); /* We used to set a flag here in the game_ui indicating * that the player had used the hint function. I (SGT) * retired it, on grounds of consistency with other games * (most of these games will still flash to indicate * completion if you solved and undid it, so why not if * you got a hint?) and because the flash is as much about * checking you got it all right than about congratulating * you on a job well done. */ } sfree(buf); return ret; } cell = state->grid[idx(r, c, state->params.w)]; if (cell > 0) return NULL; if (action == forwards) switch (cell) { case EMPTY: return nfmtstr(40, "W,%d,%d", r, c); case WHITE: return nfmtstr(40, "B,%d,%d", r, c); case BLACK: return nfmtstr(40, "E,%d,%d", r, c); } else if (action == backwards) switch (cell) { case BLACK: return nfmtstr(40, "W,%d,%d", r, c); case WHITE: return nfmtstr(40, "E,%d,%d", r, c); case EMPTY: return nfmtstr(40, "B,%d,%d", r, c); } return NULL; } static int find_errors(const game_state *state, int *report) { int const w = state->params.w, h = state->params.h, n = w * h; int *dsf; int r, c, i; int nblack = 0, any_white_cell = -1; game_state *dup = dup_game(state); for (i = r = 0; r < h; ++r) for (c = 0; c < w; ++c, ++i) { switch (state->grid[i]) { case BLACK: { int j; ++nblack; for (j = 0; j < 4; ++j) { int const rr = r + dr[j], cc = c + dc[j]; if (out_of_bounds(rr, cc, w, h)) continue; if (state->grid[idx(rr, cc, w)] != BLACK) continue; if (!report) goto found_error; report[i] = TRUE; break; } } break; default: { int j, runs; for (runs = 1, j = 0; j < 4; ++j) { int const rr = r + dr[j], cc = c + dc[j]; runs += runlength(rr, cc, dr[j], dc[j], state, ~MASK(BLACK)); } if (!report) { if (runs != state->grid[i]) goto found_error; } else if (runs < state->grid[i]) report[i] = TRUE; else { for (runs = 1, j = 0; j < 4; ++j) { int const rr = r + dr[j], cc = c + dc[j]; runs += runlength(rr, cc, dr[j], dc[j], state, ~(MASK(BLACK) | MASK(EMPTY))); } if (runs > state->grid[i]) report[i] = TRUE; } } /* note: fallthrough _into_ these cases */ case EMPTY: case WHITE: any_white_cell = i; } } /* * Check that all the white cells form a single connected component. */ dsf = snew_dsf(n); for (r = 0; r < h-1; ++r) for (c = 0; c < w; ++c) if (state->grid[r*w+c] != BLACK && state->grid[(r+1)*w+c] != BLACK) dsf_merge(dsf, r*w+c, (r+1)*w+c); for (r = 0; r < h; ++r) for (c = 0; c < w-1; ++c) if (state->grid[r*w+c] != BLACK && state->grid[r*w+(c+1)] != BLACK) dsf_merge(dsf, r*w+c, r*w+(c+1)); if (nblack + dsf_size(dsf, any_white_cell) < n) { int biggest, canonical; if (!report) { sfree(dsf); goto found_error; } /* * Report this error by choosing one component to be the * canonical one (we pick the largest, arbitrarily * tie-breaking towards lower array indices) and highlighting * as an error any square in a different component. */ canonical = -1; biggest = 0; for (i = 0; i < n; ++i) if (state->grid[i] != BLACK) { int size = dsf_size(dsf, i); if (size > biggest) { biggest = size; canonical = dsf_canonify(dsf, i); } } for (i = 0; i < n; ++i) if (state->grid[i] != BLACK && dsf_canonify(dsf, i) != canonical) report[i] = TRUE; } sfree(dsf); free_game(dup); return FALSE; /* if report != NULL, this is ignored */ found_error: free_game(dup); return TRUE; } static game_state *execute_move(const game_state *state, const char *move) { signed int r, c, value, nchars, ntok; signed char what_to_do; game_state *ret; assert (move); ret = dup_game(state); if (*move == 'S') { ++move; ret->has_cheated = ret->was_solved = TRUE; } for (; *move; move += nchars) { ntok = sscanf(move, "%c,%d,%d%n", &what_to_do, &r, &c, &nchars); if (ntok < 3) goto failure; switch (what_to_do) { case 'W': value = WHITE; break; case 'E': value = EMPTY; break; case 'B': value = BLACK; break; default: goto failure; } if (out_of_bounds(r, c, ret->params.w, ret->params.h)) goto failure; ret->grid[idx(r, c, ret->params.w)] = value; } if (ret->was_solved == FALSE) ret->was_solved = !find_errors(ret, NULL); return ret; failure: free_game(ret); return NULL; } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return 0.0F; } #define FLASH_TIME 0.7F static float game_flash_length(const game_state *from, const game_state *to, int dir, game_ui *ui) { if (!from->was_solved && to->was_solved && !to->has_cheated) return FLASH_TIME; return 0.0F; } static int game_status(const game_state *state) { return state->was_solved ? +1 : 0; } /* ---------------------------------------------------------------------- * Drawing routines. */ #define PREFERRED_TILE_SIZE 32 enum { COL_BACKGROUND = 0, COL_GRID, COL_BLACK = COL_GRID, COL_TEXT = COL_GRID, COL_USER = COL_GRID, COL_ERROR, COL_LOWLIGHT, COL_HIGHLIGHT = COL_ERROR, /* mkhighlight needs it, I don't */ COL_CURSOR = COL_LOWLIGHT, NCOLOURS }; static void game_compute_size(const game_params *params, int tilesize, int *x, int *y) { *x = (1 + params->w) * tilesize; *y = (1 + params->h) * tilesize; } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { ds->tilesize = tilesize; } #define COLOUR(ret, i, r, g, b) \ ((ret[3*(i)+0] = (r)), (ret[3*(i)+1] = (g)), (ret[3*(i)+2] = (b))) static float *game_colours(frontend *fe, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float); game_mkhighlight(fe, ret, COL_BACKGROUND, COL_HIGHLIGHT, COL_LOWLIGHT); COLOUR(ret, COL_GRID, 0.0F, 0.0F, 0.0F); COLOUR(ret, COL_ERROR, 1.0F, 0.0F, 0.0F); *ncolours = NCOLOURS; return ret; } static drawcell makecell(puzzle_size value, int error, int cursor, int flash) { drawcell ret; setmember(ret, value); setmember(ret, error); setmember(ret, cursor); setmember(ret, flash); return ret; } static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { int const w = state->params.w, h = state->params.h, n = w * h; struct game_drawstate *ds = snew(struct game_drawstate); int i; ds->tilesize = 0; ds->started = FALSE; ds->grid = snewn(n, drawcell); for (i = 0; i < n; ++i) ds->grid[i] = makecell(w + h, FALSE, FALSE, FALSE); return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { sfree(ds->grid); sfree(ds); } #define cmpmember(a, b, field) ((a) . field == (b) . field) static int cell_eq(drawcell a, drawcell b) { return cmpmember(a, b, value) && cmpmember(a, b, error) && cmpmember(a, b, cursor) && cmpmember(a, b, flash); } static void draw_cell(drawing *dr, game_drawstate *ds, int r, int c, drawcell cell); static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float animtime, float flashtime) { int const w = state->params.w, h = state->params.h, n = w * h; int const wpx = (w+1) * ds->tilesize, hpx = (h+1) * ds->tilesize; int const flash = ((int) (flashtime * 5 / FLASH_TIME)) % 2; int r, c, i; int *errors = snewn(n, int); memset(errors, FALSE, n * sizeof (int)); find_errors(state, errors); assert (oldstate == NULL); /* only happens if animating moves */ if (!ds->started) { ds->started = TRUE; draw_rect(dr, 0, 0, wpx, hpx, COL_BACKGROUND); draw_update(dr, 0, 0, wpx, hpx); } for (i = r = 0; r < h; ++r) { for (c = 0; c < w; ++c, ++i) { drawcell cell = makecell(state->grid[i], errors[i], FALSE, flash); if (r == ui->r && c == ui->c && ui->cursor_show) cell.cursor = TRUE; if (!cell_eq(cell, ds->grid[i])) { draw_cell(dr, ds, r, c, cell); ds->grid[i] = cell; } } } sfree(errors); } static void draw_cell(drawing *draw, game_drawstate *ds, int r, int c, drawcell cell) { int const ts = ds->tilesize; int const y = BORDER + ts * r, x = BORDER + ts * c; int const tx = x + (ts / 2), ty = y + (ts / 2); int const dotsz = (ds->tilesize + 9) / 10; int const colour = (cell.value == BLACK ? cell.error ? COL_ERROR : COL_BLACK : cell.flash || cell.cursor ? COL_LOWLIGHT : COL_BACKGROUND); draw_rect_outline(draw, x, y, ts + 1, ts + 1, COL_GRID); draw_rect (draw, x + 1, y + 1, ts - 1, ts - 1, colour); if (cell.error) draw_rect_outline(draw, x + 1, y + 1, ts - 1, ts - 1, COL_ERROR); switch (cell.value) { case WHITE: draw_rect(draw, tx - dotsz / 2, ty - dotsz / 2, dotsz, dotsz, cell.error ? COL_ERROR : COL_USER); case BLACK: case EMPTY: break; default: { int const colour = (cell.error ? COL_ERROR : COL_GRID); char *msg = nfmtstr(10, "%d", cell.value); draw_text(draw, tx, ty, FONT_VARIABLE, ts * 3 / 5, ALIGN_VCENTRE | ALIGN_HCENTRE, colour, msg); sfree(msg); } } draw_update(draw, x, y, ts + 1, ts + 1); } static int game_timing_state(const game_state *state, game_ui *ui) { puts("warning: game_timing_state was called (this shouldn't happen)"); return FALSE; /* the (non-existing) timer should not be running */ } /* ---------------------------------------------------------------------- * User interface: print */ static void game_print_size(const game_params *params, float *x, float *y) { int print_width, print_height; game_compute_size(params, 800, &print_width, &print_height); *x = print_width / 100.0F; *y = print_height / 100.0F; } static void game_print(drawing *dr, const game_state *state, int tilesize) { int const w = state->params.w, h = state->params.h; game_drawstate ds_obj, *ds = &ds_obj; int r, c, i, colour; ds->tilesize = tilesize; colour = print_mono_colour(dr, 1); assert(colour == COL_BACKGROUND); colour = print_mono_colour(dr, 0); assert(colour == COL_GRID); colour = print_mono_colour(dr, 1); assert(colour == COL_ERROR); colour = print_mono_colour(dr, 0); assert(colour == COL_LOWLIGHT); colour = print_mono_colour(dr, 0); assert(colour == NCOLOURS); for (i = r = 0; r < h; ++r) for (c = 0; c < w; ++c, ++i) draw_cell(dr, ds, r, c, makecell(state->grid[i], FALSE, FALSE, FALSE)); print_line_width(dr, 3 * tilesize / 40); draw_rect_outline(dr, BORDER, BORDER, w*TILESIZE, h*TILESIZE, COL_GRID); } /* And that's about it ;-) **************************************************/ #ifdef COMBINED #define thegame range #endif struct game const thegame = { "Range", "games.range", "range", default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, TRUE, solve_game, TRUE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, PREFERRED_TILE_SIZE, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, TRUE, FALSE, game_print_size, game_print, FALSE, /* wants_statusbar */ FALSE, game_timing_state, 0, /* flags */ }; puzzles-20170606.272beef/random.c0000644000175000017500000001775713115373615015336 0ustar simonsimon/* * random.c: Internal random number generator, guaranteed to work * the same way on all platforms. Used when generating an initial * game state from a random game seed; required to ensure that game * seeds can be exchanged between versions of a puzzle compiled for * different platforms. * * The generator is based on SHA-1. This is almost certainly * overkill, but I had the SHA-1 code kicking around and it was * easier to reuse it than to do anything else! */ #include #include #include #include "puzzles.h" /* ---------------------------------------------------------------------- * Core SHA algorithm: processes 16-word blocks into a message digest. */ #define rol(x,y) ( ((x) << (y)) | (((uint32)x) >> (32-y)) ) static void SHA_Core_Init(uint32 h[5]) { h[0] = 0x67452301; h[1] = 0xefcdab89; h[2] = 0x98badcfe; h[3] = 0x10325476; h[4] = 0xc3d2e1f0; } static void SHATransform(uint32 * digest, uint32 * block) { uint32 w[80]; uint32 a, b, c, d, e; int t; for (t = 0; t < 16; t++) w[t] = block[t]; for (t = 16; t < 80; t++) { uint32 tmp = w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16]; w[t] = rol(tmp, 1); } a = digest[0]; b = digest[1]; c = digest[2]; d = digest[3]; e = digest[4]; for (t = 0; t < 20; t++) { uint32 tmp = rol(a, 5) + ((b & c) | (d & ~b)) + e + w[t] + 0x5a827999; e = d; d = c; c = rol(b, 30); b = a; a = tmp; } for (t = 20; t < 40; t++) { uint32 tmp = rol(a, 5) + (b ^ c ^ d) + e + w[t] + 0x6ed9eba1; e = d; d = c; c = rol(b, 30); b = a; a = tmp; } for (t = 40; t < 60; t++) { uint32 tmp = rol(a, 5) + ((b & c) | (b & d) | (c & d)) + e + w[t] + 0x8f1bbcdc; e = d; d = c; c = rol(b, 30); b = a; a = tmp; } for (t = 60; t < 80; t++) { uint32 tmp = rol(a, 5) + (b ^ c ^ d) + e + w[t] + 0xca62c1d6; e = d; d = c; c = rol(b, 30); b = a; a = tmp; } digest[0] += a; digest[1] += b; digest[2] += c; digest[3] += d; digest[4] += e; } /* ---------------------------------------------------------------------- * Outer SHA algorithm: take an arbitrary length byte string, * convert it into 16-word blocks with the prescribed padding at * the end, and pass those blocks to the core SHA algorithm. */ void SHA_Init(SHA_State * s) { SHA_Core_Init(s->h); s->blkused = 0; s->lenhi = s->lenlo = 0; } void SHA_Bytes(SHA_State * s, const void *p, int len) { unsigned char *q = (unsigned char *) p; uint32 wordblock[16]; uint32 lenw = len; int i; /* * Update the length field. */ s->lenlo += lenw; s->lenhi += (s->lenlo < lenw); if (s->blkused && s->blkused + len < 64) { /* * Trivial case: just add to the block. */ memcpy(s->block + s->blkused, q, len); s->blkused += len; } else { /* * We must complete and process at least one block. */ while (s->blkused + len >= 64) { memcpy(s->block + s->blkused, q, 64 - s->blkused); q += 64 - s->blkused; len -= 64 - s->blkused; /* Now process the block. Gather bytes big-endian into words */ for (i = 0; i < 16; i++) { wordblock[i] = (((uint32) s->block[i * 4 + 0]) << 24) | (((uint32) s->block[i * 4 + 1]) << 16) | (((uint32) s->block[i * 4 + 2]) << 8) | (((uint32) s->block[i * 4 + 3]) << 0); } SHATransform(s->h, wordblock); s->blkused = 0; } memcpy(s->block, q, len); s->blkused = len; } } void SHA_Final(SHA_State * s, unsigned char *output) { int i; int pad; unsigned char c[64]; uint32 lenhi, lenlo; if (s->blkused >= 56) pad = 56 + 64 - s->blkused; else pad = 56 - s->blkused; lenhi = (s->lenhi << 3) | (s->lenlo >> (32 - 3)); lenlo = (s->lenlo << 3); memset(c, 0, pad); c[0] = 0x80; SHA_Bytes(s, &c, pad); c[0] = (unsigned char)((lenhi >> 24) & 0xFF); c[1] = (unsigned char)((lenhi >> 16) & 0xFF); c[2] = (unsigned char)((lenhi >> 8) & 0xFF); c[3] = (unsigned char)((lenhi >> 0) & 0xFF); c[4] = (unsigned char)((lenlo >> 24) & 0xFF); c[5] = (unsigned char)((lenlo >> 16) & 0xFF); c[6] = (unsigned char)((lenlo >> 8) & 0xFF); c[7] = (unsigned char)((lenlo >> 0) & 0xFF); SHA_Bytes(s, &c, 8); for (i = 0; i < 5; i++) { output[i * 4] = (unsigned char)((s->h[i] >> 24) & 0xFF); output[i * 4 + 1] = (unsigned char)((s->h[i] >> 16) & 0xFF); output[i * 4 + 2] = (unsigned char)((s->h[i] >> 8) & 0xFF); output[i * 4 + 3] = (unsigned char)((s->h[i]) & 0xFF); } } void SHA_Simple(const void *p, int len, unsigned char *output) { SHA_State s; SHA_Init(&s); SHA_Bytes(&s, p, len); SHA_Final(&s, output); } /* ---------------------------------------------------------------------- * The random number generator. */ struct random_state { unsigned char seedbuf[40]; unsigned char databuf[20]; int pos; }; random_state *random_new(const char *seed, int len) { random_state *state; state = snew(random_state); SHA_Simple(seed, len, state->seedbuf); SHA_Simple(state->seedbuf, 20, state->seedbuf + 20); SHA_Simple(state->seedbuf, 40, state->databuf); state->pos = 0; return state; } random_state *random_copy(random_state *tocopy) { random_state *result; result = snew(random_state); memcpy(result->seedbuf, tocopy->seedbuf, sizeof(result->seedbuf)); memcpy(result->databuf, tocopy->databuf, sizeof(result->databuf)); result->pos = tocopy->pos; return result; } unsigned long random_bits(random_state *state, int bits) { unsigned long ret = 0; int n; for (n = 0; n < bits; n += 8) { if (state->pos >= 20) { int i; for (i = 0; i < 20; i++) { if (state->seedbuf[i] != 0xFF) { state->seedbuf[i]++; break; } else state->seedbuf[i] = 0; } SHA_Simple(state->seedbuf, 40, state->databuf); state->pos = 0; } ret = (ret << 8) | state->databuf[state->pos++]; } /* * `(1 << bits) - 1' is not good enough, since if bits==32 on a * 32-bit machine, behaviour is undefined and Intel has a nasty * habit of shifting left by zero instead. We'll shift by * bits-1 and then separately shift by one. */ ret &= (1 << (bits-1)) * 2 - 1; return ret; } unsigned long random_upto(random_state *state, unsigned long limit) { int bits = 0; unsigned long max, divisor, data; while ((limit >> bits) != 0) bits++; bits += 3; assert(bits < 32); max = 1L << bits; divisor = max / limit; max = limit * divisor; do { data = random_bits(state, bits); } while (data >= max); return data / divisor; } void random_free(random_state *state) { sfree(state); } char *random_state_encode(random_state *state) { char retbuf[256]; int len = 0, i; for (i = 0; i < lenof(state->seedbuf); i++) len += sprintf(retbuf+len, "%02x", state->seedbuf[i]); for (i = 0; i < lenof(state->databuf); i++) len += sprintf(retbuf+len, "%02x", state->databuf[i]); len += sprintf(retbuf+len, "%02x", state->pos); return dupstr(retbuf); } random_state *random_state_decode(const char *input) { random_state *state; int pos, byte, digits; state = snew(random_state); memset(state->seedbuf, 0, sizeof(state->seedbuf)); memset(state->databuf, 0, sizeof(state->databuf)); state->pos = 0; byte = digits = 0; pos = 0; while (*input) { int v = *input++; if (v >= '0' && v <= '9') v = v - '0'; else if (v >= 'A' && v <= 'F') v = v - 'A' + 10; else if (v >= 'a' && v <= 'f') v = v - 'a' + 10; else v = 0; byte = (byte << 4) | v; digits++; if (digits == 2) { /* * We have a byte. Put it somewhere. */ if (pos < lenof(state->seedbuf)) state->seedbuf[pos++] = byte; else if (pos < lenof(state->seedbuf) + lenof(state->databuf)) state->databuf[pos++ - lenof(state->seedbuf)] = byte; else if (pos == lenof(state->seedbuf) + lenof(state->databuf) && byte <= lenof(state->databuf)) state->pos = byte; byte = digits = 0; } } return state; } puzzles-20170606.272beef/ps.c0000644000175000017500000002576013115373615014471 0ustar simonsimon/* * ps.c: PostScript printing functions. */ #include #include #include #include #include "puzzles.h" #define ROOT2 1.414213562 struct psdata { FILE *fp; int colour; int ytop; int clipped; float hatchthick, hatchspace; int gamewidth, gameheight; drawing *drawing; }; static void ps_printf(psdata *ps, char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(ps->fp, fmt, ap); va_end(ap); } static void ps_fill(psdata *ps, int colour) { int hatch; float r, g, b; print_get_colour(ps->drawing, colour, ps->colour, &hatch, &r, &g, &b); if (hatch < 0) { if (ps->colour) ps_printf(ps, "%g %g %g setrgbcolor fill\n", r, g, b); else ps_printf(ps, "%g setgray fill\n", r); } else { /* Clip to the region. */ ps_printf(ps, "gsave clip\n"); /* Hatch the entire game printing area. */ ps_printf(ps, "newpath\n"); if (hatch == HATCH_VERT || hatch == HATCH_PLUS) ps_printf(ps, "0 %g %d {\n" " 0 moveto 0 %d rlineto\n" "} for\n", ps->hatchspace, ps->gamewidth, ps->gameheight); if (hatch == HATCH_HORIZ || hatch == HATCH_PLUS) ps_printf(ps, "0 %g %d {\n" " 0 exch moveto %d 0 rlineto\n" "} for\n", ps->hatchspace, ps->gameheight, ps->gamewidth); if (hatch == HATCH_SLASH || hatch == HATCH_X) ps_printf(ps, "%d %g %d {\n" " 0 moveto %d dup rlineto\n" "} for\n", -ps->gameheight, ps->hatchspace * ROOT2, ps->gamewidth, max(ps->gamewidth, ps->gameheight)); if (hatch == HATCH_BACKSLASH || hatch == HATCH_X) ps_printf(ps, "0 %g %d {\n" " 0 moveto %d neg dup neg rlineto\n" "} for\n", ps->hatchspace * ROOT2, ps->gamewidth+ps->gameheight, max(ps->gamewidth, ps->gameheight)); ps_printf(ps, "0 setgray %g setlinewidth stroke grestore\n", ps->hatchthick); } } static void ps_setcolour_internal(psdata *ps, int colour, char *suffix) { int hatch; float r, g, b; print_get_colour(ps->drawing, colour, ps->colour, &hatch, &r, &g, &b); /* * Stroking in hatched colours is not permitted. */ assert(hatch < 0); if (ps->colour) ps_printf(ps, "%g %g %g setrgbcolor%s\n", r, g, b, suffix); else ps_printf(ps, "%g setgray%s\n", r, suffix); } static void ps_setcolour(psdata *ps, int colour) { ps_setcolour_internal(ps, colour, ""); } static void ps_stroke(psdata *ps, int colour) { ps_setcolour_internal(ps, colour, " stroke"); } static void ps_draw_text(void *handle, int x, int y, int fonttype, int fontsize, int align, int colour, char *text) { psdata *ps = (psdata *)handle; y = ps->ytop - y; ps_setcolour(ps, colour); ps_printf(ps, "/%s findfont %d scalefont setfont\n", fonttype == FONT_FIXED ? "Courier-L1" : "Helvetica-L1", fontsize); if (align & ALIGN_VCENTRE) { ps_printf(ps, "newpath 0 0 moveto (X) true charpath flattenpath" " pathbbox\n" "3 -1 roll add 2 div %d exch sub %d exch moveto pop pop\n", y, x); } else { ps_printf(ps, "%d %d moveto\n", x, y); } ps_printf(ps, "("); while (*text) { if (*text == '\\' || *text == '(' || *text == ')') ps_printf(ps, "\\"); ps_printf(ps, "%c", *text); text++; } ps_printf(ps, ") "); if (align & (ALIGN_HCENTRE | ALIGN_HRIGHT)) ps_printf(ps, "dup stringwidth pop %sneg 0 rmoveto show\n", (align & ALIGN_HCENTRE) ? "2 div " : ""); else ps_printf(ps, "show\n"); } static void ps_draw_rect(void *handle, int x, int y, int w, int h, int colour) { psdata *ps = (psdata *)handle; y = ps->ytop - y; /* * Offset by half a pixel for the exactness requirement. */ ps_printf(ps, "newpath %g %g moveto %d 0 rlineto 0 %d rlineto" " %d 0 rlineto closepath\n", x - 0.5, y + 0.5, w, -h, -w); ps_fill(ps, colour); } static void ps_draw_line(void *handle, int x1, int y1, int x2, int y2, int colour) { psdata *ps = (psdata *)handle; y1 = ps->ytop - y1; y2 = ps->ytop - y2; ps_printf(ps, "newpath %d %d moveto %d %d lineto\n", x1, y1, x2, y2); ps_stroke(ps, colour); } static void ps_draw_polygon(void *handle, int *coords, int npoints, int fillcolour, int outlinecolour) { psdata *ps = (psdata *)handle; int i; ps_printf(ps, "newpath %d %d moveto\n", coords[0], ps->ytop - coords[1]); for (i = 1; i < npoints; i++) ps_printf(ps, "%d %d lineto\n", coords[i*2], ps->ytop - coords[i*2+1]); ps_printf(ps, "closepath\n"); if (fillcolour >= 0) { ps_printf(ps, "gsave\n"); ps_fill(ps, fillcolour); ps_printf(ps, "grestore\n"); } ps_stroke(ps, outlinecolour); } static void ps_draw_circle(void *handle, int cx, int cy, int radius, int fillcolour, int outlinecolour) { psdata *ps = (psdata *)handle; cy = ps->ytop - cy; ps_printf(ps, "newpath %d %d %d 0 360 arc closepath\n", cx, cy, radius); if (fillcolour >= 0) { ps_printf(ps, "gsave\n"); ps_fill(ps, fillcolour); ps_printf(ps, "grestore\n"); } ps_stroke(ps, outlinecolour); } static void ps_unclip(void *handle) { psdata *ps = (psdata *)handle; assert(ps->clipped); ps_printf(ps, "grestore\n"); ps->clipped = FALSE; } static void ps_clip(void *handle, int x, int y, int w, int h) { psdata *ps = (psdata *)handle; if (ps->clipped) ps_unclip(ps); y = ps->ytop - y; /* * Offset by half a pixel for the exactness requirement. */ ps_printf(ps, "gsave\n"); ps_printf(ps, "newpath %g %g moveto %d 0 rlineto 0 %d rlineto" " %d 0 rlineto closepath\n", x - 0.5, y + 0.5, w, -h, -w); ps_printf(ps, "clip\n"); ps->clipped = TRUE; } static void ps_line_width(void *handle, float width) { psdata *ps = (psdata *)handle; ps_printf(ps, "%g setlinewidth\n", width); } static void ps_line_dotted(void *handle, int dotted) { psdata *ps = (psdata *)handle; if (dotted) { ps_printf(ps, "[ currentlinewidth 3 mul ] 0 setdash\n"); } else { ps_printf(ps, "[ ] 0 setdash\n"); } } static char *ps_text_fallback(void *handle, const char *const *strings, int nstrings) { /* * We can handle anything in ISO 8859-1, and we'll manually * translate it out of UTF-8 for the purpose. */ int i, maxlen; char *ret; maxlen = 0; for (i = 0; i < nstrings; i++) { int len = strlen(strings[i]); if (maxlen < len) maxlen = len; } ret = snewn(maxlen + 1, char); for (i = 0; i < nstrings; i++) { const char *p = strings[i]; char *q = ret; while (*p) { int c = (unsigned char)*p++; if (c < 0x80) { *q++ = c; /* ASCII */ } else if ((c == 0xC2 || c == 0xC3) && (*p & 0xC0) == 0x80) { *q++ = (c << 6) | (*p++ & 0x3F); /* top half of 8859-1 */ } else { break; } } if (!*p) { *q = '\0'; return ret; } } assert(!"Should never reach here"); return NULL; } static void ps_begin_doc(void *handle, int pages) { psdata *ps = (psdata *)handle; fputs("%!PS-Adobe-3.0\n", ps->fp); fputs("%%Creator: Simon Tatham's Portable Puzzle Collection\n", ps->fp); fputs("%%DocumentData: Clean7Bit\n", ps->fp); fputs("%%LanguageLevel: 1\n", ps->fp); fprintf(ps->fp, "%%%%Pages: %d\n", pages); fputs("%%DocumentNeededResources:\n", ps->fp); fputs("%%+ font Helvetica\n", ps->fp); fputs("%%+ font Courier\n", ps->fp); fputs("%%EndComments\n", ps->fp); fputs("%%BeginSetup\n", ps->fp); fputs("%%IncludeResource: font Helvetica\n", ps->fp); fputs("%%IncludeResource: font Courier\n", ps->fp); fputs("%%EndSetup\n", ps->fp); fputs("%%BeginProlog\n", ps->fp); /* * Re-encode Helvetica and Courier into ISO-8859-1, which gives * us times and divide signs - and also (according to the * Language Reference Manual) a bonus in that the ASCII '-' code * point now points to a minus sign instead of a hyphen. */ fputs("/Helvetica findfont " /* get the font dictionary */ "dup maxlength dict dup begin " /* create and open a new dict */ "exch " /* move the original font to top of stack */ "{1 index /FID ne {def} {pop pop} ifelse} forall " /* copy everything except FID */ "/Encoding ISOLatin1Encoding def " /* set the thing we actually wanted to change */ "/FontName /Helvetica-L1 def " /* set a new font name */ "FontName end exch definefont" /* and define the font */ "\n", ps->fp); fputs("/Courier findfont " /* get the font dictionary */ "dup maxlength dict dup begin " /* create and open a new dict */ "exch " /* move the original font to top of stack */ "{1 index /FID ne {def} {pop pop} ifelse} forall " /* copy everything except FID */ "/Encoding ISOLatin1Encoding def " /* set the thing we actually wanted to change */ "/FontName /Courier-L1 def " /* set a new font name */ "FontName end exch definefont" /* and define the font */ "\n", ps->fp); fputs("%%EndProlog\n", ps->fp); } static void ps_begin_page(void *handle, int number) { psdata *ps = (psdata *)handle; fprintf(ps->fp, "%%%%Page: %d %d\ngsave save\n%g dup scale\n", number, number, 72.0 / 25.4); } static void ps_begin_puzzle(void *handle, float xm, float xc, float ym, float yc, int pw, int ph, float wmm) { psdata *ps = (psdata *)handle; fprintf(ps->fp, "gsave\n" "clippath flattenpath pathbbox pop pop translate\n" "clippath flattenpath pathbbox 4 2 roll pop pop\n" "exch %g mul %g add exch dup %g mul %g add sub translate\n" "%g dup scale\n" "0 -%d translate\n", xm, xc, ym, yc, wmm/pw, ph); ps->ytop = ph; ps->clipped = FALSE; ps->gamewidth = pw; ps->gameheight = ph; ps->hatchthick = 0.2 * pw / wmm; ps->hatchspace = 1.0 * pw / wmm; } static void ps_end_puzzle(void *handle) { psdata *ps = (psdata *)handle; fputs("grestore\n", ps->fp); } static void ps_end_page(void *handle, int number) { psdata *ps = (psdata *)handle; fputs("restore grestore showpage\n", ps->fp); } static void ps_end_doc(void *handle) { psdata *ps = (psdata *)handle; fputs("%%EOF\n", ps->fp); } static const struct drawing_api ps_drawing = { ps_draw_text, ps_draw_rect, ps_draw_line, ps_draw_polygon, ps_draw_circle, NULL /* draw_update */, ps_clip, ps_unclip, NULL /* start_draw */, NULL /* end_draw */, NULL /* status_bar */, NULL /* blitter_new */, NULL /* blitter_free */, NULL /* blitter_save */, NULL /* blitter_load */, ps_begin_doc, ps_begin_page, ps_begin_puzzle, ps_end_puzzle, ps_end_page, ps_end_doc, ps_line_width, ps_line_dotted, ps_text_fallback, }; psdata *ps_init(FILE *outfile, int colour) { psdata *ps = snew(psdata); ps->fp = outfile; ps->colour = colour; ps->ytop = 0; ps->clipped = FALSE; ps->hatchthick = ps->hatchspace = ps->gamewidth = ps->gameheight = 0; ps->drawing = drawing_new(&ps_drawing, NULL, ps); return ps; } void ps_free(psdata *ps) { drawing_free(ps->drawing); sfree(ps); } drawing *ps_drawing_api(psdata *ps) { return ps->drawing; } puzzles-20170606.272beef/printing.c0000644000175000017500000001441613115373615015675 0ustar simonsimon/* * printing.c: Cross-platform printing manager. Handles document * setup and layout. */ #include "puzzles.h" struct puzzle { const game *game; game_params *par; game_state *st; game_state *st2; }; struct document { int pw, ph; int npuzzles; struct puzzle *puzzles; int puzzlesize; int got_solns; float *colwid, *rowht; float userscale; }; /* * Create a new print document. pw and ph are the layout * parameters: they state how many puzzles will be printed across * the page, and down the page. */ document *document_new(int pw, int ph, float userscale) { document *doc = snew(document); doc->pw = pw; doc->ph = ph; doc->puzzles = NULL; doc->puzzlesize = doc->npuzzles = 0; doc->got_solns = FALSE; doc->colwid = snewn(pw, float); doc->rowht = snewn(ph, float); doc->userscale = userscale; return doc; } /* * Free a document structure, whether it's been printed or not. */ void document_free(document *doc) { int i; for (i = 0; i < doc->npuzzles; i++) { doc->puzzles[i].game->free_params(doc->puzzles[i].par); doc->puzzles[i].game->free_game(doc->puzzles[i].st); if (doc->puzzles[i].st2) doc->puzzles[i].game->free_game(doc->puzzles[i].st2); } sfree(doc->colwid); sfree(doc->rowht); sfree(doc->puzzles); sfree(doc); } /* * Called from midend.c to add a puzzle to be printed. Provides a * game_params (for initial layout computation), a game_state, and * optionally a second game_state to be printed in parallel on * another sheet (typically the solution to the first game_state). */ void document_add_puzzle(document *doc, const game *game, game_params *par, game_state *st, game_state *st2) { if (doc->npuzzles >= doc->puzzlesize) { doc->puzzlesize += 32; doc->puzzles = sresize(doc->puzzles, doc->puzzlesize, struct puzzle); } doc->puzzles[doc->npuzzles].game = game; doc->puzzles[doc->npuzzles].par = par; doc->puzzles[doc->npuzzles].st = st; doc->puzzles[doc->npuzzles].st2 = st2; doc->npuzzles++; if (st2) doc->got_solns = TRUE; } static void get_puzzle_size(document *doc, struct puzzle *pz, float *w, float *h, float *scale) { float ww, hh, ourscale; /* Get the preferred size of the game, in mm. */ pz->game->print_size(pz->par, &ww, &hh); /* Adjust for user-supplied scale factor. */ ourscale = doc->userscale; /* * FIXME: scale it down here if it's too big for the page size. * Rather than do complicated things involving scaling all * columns down in proportion, the simplest approach seems to * me to be to scale down until the game fits within one evenly * divided cell of the page (i.e. width/pw by height/ph). * * In order to do this step we need the page size available. */ *scale = ourscale; *w = ww * ourscale; *h = hh * ourscale; } /* * Having accumulated a load of puzzles, actually do the printing. */ void document_print(document *doc, drawing *dr) { int ppp; /* puzzles per page */ int pages, passes; int page, pass; int pageno; ppp = doc->pw * doc->ph; pages = (doc->npuzzles + ppp - 1) / ppp; passes = (doc->got_solns ? 2 : 1); print_begin_doc(dr, pages * passes); pageno = 1; for (pass = 0; pass < passes; pass++) { for (page = 0; page < pages; page++) { int i, n, offset; float colsum, rowsum; print_begin_page(dr, pageno); offset = page * ppp; n = min(ppp, doc->npuzzles - offset); for (i = 0; i < doc->pw; i++) doc->colwid[i] = 0; for (i = 0; i < doc->ph; i++) doc->rowht[i] = 0; /* * Lay the page out by computing all the puzzle sizes. */ for (i = 0; i < n; i++) { struct puzzle *pz = doc->puzzles + offset + i; int x = i % doc->pw, y = i / doc->pw; float w, h, scale; get_puzzle_size(doc, pz, &w, &h, &scale); /* Update the maximum width/height of this column. */ doc->colwid[x] = max(doc->colwid[x], w); doc->rowht[y] = max(doc->rowht[y], h); } /* * Add up the maximum column/row widths to get the * total amount of space used up by puzzles on the * page. We will use this to compute gutter widths. */ colsum = 0.0; for (i = 0; i < doc->pw; i++) colsum += doc->colwid[i]; rowsum = 0.0; for (i = 0; i < doc->ph; i++) rowsum += doc->rowht[i]; /* * Now do the printing. */ for (i = 0; i < n; i++) { struct puzzle *pz = doc->puzzles + offset + i; int x = i % doc->pw, y = i / doc->pw, j; float w, h, scale, xm, xc, ym, yc; int pixw, pixh, tilesize; if (pass == 1 && !pz->st2) continue; /* nothing to do */ /* * The total amount of gutter space is the page * width minus colsum. This is divided into pw+1 * gutters, so the amount of horizontal gutter * space appearing to the left of this puzzle * column is * * (width-colsum) * (x+1)/(pw+1) * = width * (x+1)/(pw+1) - (colsum * (x+1)/(pw+1)) */ xm = (float)(x+1) / (doc->pw + 1); xc = -xm * colsum; /* And similarly for y. */ ym = (float)(y+1) / (doc->ph + 1); yc = -ym * rowsum; /* * However, the amount of space to the left of this * puzzle isn't just gutter space: we must also * count the widths of all the previous columns. */ for (j = 0; j < x; j++) xc += doc->colwid[j]; /* And similarly for rows. */ for (j = 0; j < y; j++) yc += doc->rowht[j]; /* * Now we adjust for this _specific_ puzzle, which * means centring it within the cell we've just * computed. */ get_puzzle_size(doc, pz, &w, &h, &scale); xc += (doc->colwid[x] - w) / 2; yc += (doc->rowht[y] - h) / 2; /* * And now we know where and how big we want to * print the puzzle, just go ahead and do so. For * the moment I'll pick a standard pixel tile size * of 512. * * (FIXME: would it be better to pick this value * with reference to the printer resolution? Or * permit each game to choose its own?) */ tilesize = 512; pz->game->compute_size(pz->par, tilesize, &pixw, &pixh); print_begin_puzzle(dr, xm, xc, ym, yc, pixw, pixh, w, scale); pz->game->print(dr, pass == 0 ? pz->st : pz->st2, tilesize); print_end_puzzle(dr); } print_end_page(dr, pageno); pageno++; } } print_end_doc(dr); } puzzles-20170606.272beef/penrose.c0000644000175000017500000003755613115373615015530 0ustar simonsimon/* penrose.c * * Penrose tile generator. * * Uses half-tile technique outlined on: * * http://tartarus.org/simon/20110412-penrose/penrose.xhtml */ #include #include #include #include #include "puzzles.h" /* for malloc routines, and PI */ #include "penrose.h" /* ------------------------------------------------------- * 36-degree basis vector arithmetic routines. */ /* Imagine drawing a * ten-point 'clock face' like this: * * -E * -D | A * \ | / * -C. \ | / ,B * `-._\|/_,-' * ,-' /|\ `-. * -B' / | \ `C * / | \ * -A | D * E * * In case the ASCII art isn't clear, those are supposed to be ten * vectors of length 1, all sticking out from the origin at equal * angular spacing (hence 36 degrees). Our basis vectors are A,B,C,D (I * choose them to be symmetric about the x-axis so that the final * translation into 2d coordinates will also be symmetric, which I * think will avoid minor rounding uglinesses), so our vector * representation sets * * A = (1,0,0,0) * B = (0,1,0,0) * C = (0,0,1,0) * D = (0,0,0,1) * * The fifth vector E looks at first glance as if it needs to be * another basis vector, but in fact it doesn't, because it can be * represented in terms of the other four. Imagine starting from the * origin and following the path -A, +B, -C, +D: you'll find you've * traced four sides of a pentagram, and ended up one E-vector away * from the origin. So we have * * E = (-1,1,-1,1) * * This tells us that we can rotate any vector in this system by 36 * degrees: if we start with a*A + b*B + c*C + d*D, we want to end up * with a*B + b*C + c*D + d*E, and we substitute our identity for E to * turn that into a*B + b*C + c*D + d*(-A+B-C+D). In other words, * * rotate_one_notch_clockwise(a,b,c,d) = (-d, d+a, -d+b, d+c) * * and you can verify for yourself that applying that operation * repeatedly starting with (1,0,0,0) cycles round ten vectors and * comes back to where it started. * * The other operation that may be required is to construct vectors * with lengths that are multiples of phi. That can be done by * observing that the vector C-B is parallel to E and has length 1/phi, * and the vector D-A is parallel to E and has length phi. So this * tells us that given any vector, we can construct one which points in * the same direction and is 1/phi or phi times its length, like this: * * divide_by_phi(vector) = rotate(vector, 2) - rotate(vector, 3) * multiply_by_phi(vector) = rotate(vector, 1) - rotate(vector, 4) * * where rotate(vector, n) means applying the above * rotate_one_notch_clockwise primitive n times. Expanding out the * applications of rotate gives the following direct representation in * terms of the vector coordinates: * * divide_by_phi(a,b,c,d) = (b-d, c+d-b, a+b-c, c-a) * multiply_by_phi(a,b,c,d) = (a+b-d, c+d, a+b, c+d-a) * * and you can verify for yourself that those two operations are * inverses of each other (as you'd hope!). * * Having done all of this, testing for equality between two vectors is * a trivial matter of comparing the four integer coordinates. (Which * it _wouldn't_ have been if we'd kept E as a fifth basis vector, * because then (-1,1,-1,1,0) and (0,0,0,0,1) would have had to be * considered identical. So leaving E out is vital.) */ struct vector { int a, b, c, d; }; static vector v_origin(void) { vector v; v.a = v.b = v.c = v.d = 0; return v; } /* We start with a unit vector of B: this means we can easily * draw an isoceles triangle centred on the X axis. */ #ifdef TEST_VECTORS static vector v_unit(void) { vector v; v.b = 1; v.a = v.c = v.d = 0; return v; } #endif #define COS54 0.5877852 #define SIN54 0.8090169 #define COS18 0.9510565 #define SIN18 0.3090169 /* These two are a bit rough-and-ready for now. Note that B/C are * 18 degrees from the x-axis, and A/D are 54 degrees. */ double v_x(vector *vs, int i) { return (vs[i].a + vs[i].d) * COS54 + (vs[i].b + vs[i].c) * COS18; } double v_y(vector *vs, int i) { return (vs[i].a - vs[i].d) * SIN54 + (vs[i].b - vs[i].c) * SIN18; } static vector v_trans(vector v, vector trans) { v.a += trans.a; v.b += trans.b; v.c += trans.c; v.d += trans.d; return v; } static vector v_rotate_36(vector v) { vector vv; vv.a = -v.d; vv.b = v.d + v.a; vv.c = -v.d + v.b; vv.d = v.d + v.c; return vv; } static vector v_rotate(vector v, int ang) { int i; assert((ang % 36) == 0); while (ang < 0) ang += 360; ang = 360-ang; for (i = 0; i < (ang/36); i++) v = v_rotate_36(v); return v; } #ifdef TEST_VECTORS static vector v_scale(vector v, int sc) { v.a *= sc; v.b *= sc; v.c *= sc; v.d *= sc; return v; } #endif static vector v_growphi(vector v) { vector vv; vv.a = v.a + v.b - v.d; vv.b = v.c + v.d; vv.c = v.a + v.b; vv.d = v.c + v.d - v.a; return vv; } static vector v_shrinkphi(vector v) { vector vv; vv.a = v.b - v.d; vv.b = v.c + v.d - v.b; vv.c = v.a + v.b - v.c; vv.d = v.c - v.a; return vv; } #ifdef TEST_VECTORS static const char *v_debug(vector v) { static char buf[255]; sprintf(buf, "(%d,%d,%d,%d)[%2.2f,%2.2f]", v.a, v.b, v.c, v.d, v_x(&v,0), v_y(&v,0)); return buf; } #endif /* ------------------------------------------------------- * Tiling routines. */ static vector xform_coord(vector vo, int shrink, vector vtrans, int ang) { if (shrink < 0) vo = v_shrinkphi(vo); else if (shrink > 0) vo = v_growphi(vo); vo = v_rotate(vo, ang); vo = v_trans(vo, vtrans); return vo; } #define XFORM(n,o,s,a) vs[(n)] = xform_coord(v_edge, (s), vs[(o)], (a)) static int penrose_p2_small(penrose_state *state, int depth, int flip, vector v_orig, vector v_edge); static int penrose_p2_large(penrose_state *state, int depth, int flip, vector v_orig, vector v_edge) { vector vv_orig, vv_edge; #ifdef DEBUG_PENROSE { vector vs[3]; vs[0] = v_orig; XFORM(1, 0, 0, 0); XFORM(2, 0, 0, -36*flip); state->new_tile(state, vs, 3, depth); } #endif if (flip > 0) { vector vs[4]; vs[0] = v_orig; XFORM(1, 0, 0, -36); XFORM(2, 0, 0, 0); XFORM(3, 0, 0, 36); state->new_tile(state, vs, 4, depth); } if (depth >= state->max_depth) return 0; vv_orig = v_trans(v_orig, v_rotate(v_edge, -36*flip)); vv_edge = v_rotate(v_edge, 108*flip); penrose_p2_small(state, depth+1, flip, v_orig, v_shrinkphi(v_edge)); penrose_p2_large(state, depth+1, flip, vv_orig, v_shrinkphi(vv_edge)); penrose_p2_large(state, depth+1, -flip, vv_orig, v_shrinkphi(vv_edge)); return 0; } static int penrose_p2_small(penrose_state *state, int depth, int flip, vector v_orig, vector v_edge) { vector vv_orig; #ifdef DEBUG_PENROSE { vector vs[3]; vs[0] = v_orig; XFORM(1, 0, 0, 0); XFORM(2, 0, -1, -36*flip); state->new_tile(state, vs, 3, depth); } #endif if (flip > 0) { vector vs[4]; vs[0] = v_orig; XFORM(1, 0, 0, -72); XFORM(2, 0, -1, -36); XFORM(3, 0, 0, 0); state->new_tile(state, vs, 4, depth); } if (depth >= state->max_depth) return 0; vv_orig = v_trans(v_orig, v_edge); penrose_p2_large(state, depth+1, -flip, v_orig, v_shrinkphi(v_rotate(v_edge, -36*flip))); penrose_p2_small(state, depth+1, flip, vv_orig, v_shrinkphi(v_rotate(v_edge, -144*flip))); return 0; } static int penrose_p3_small(penrose_state *state, int depth, int flip, vector v_orig, vector v_edge); static int penrose_p3_large(penrose_state *state, int depth, int flip, vector v_orig, vector v_edge) { vector vv_orig; #ifdef DEBUG_PENROSE { vector vs[3]; vs[0] = v_orig; XFORM(1, 0, 1, 0); XFORM(2, 0, 0, -36*flip); state->new_tile(state, vs, 3, depth); } #endif if (flip > 0) { vector vs[4]; vs[0] = v_orig; XFORM(1, 0, 0, -36); XFORM(2, 0, 1, 0); XFORM(3, 0, 0, 36); state->new_tile(state, vs, 4, depth); } if (depth >= state->max_depth) return 0; vv_orig = v_trans(v_orig, v_edge); penrose_p3_large(state, depth+1, -flip, vv_orig, v_shrinkphi(v_rotate(v_edge, 180))); penrose_p3_small(state, depth+1, flip, vv_orig, v_shrinkphi(v_rotate(v_edge, -108*flip))); vv_orig = v_trans(v_orig, v_growphi(v_edge)); penrose_p3_large(state, depth+1, flip, vv_orig, v_shrinkphi(v_rotate(v_edge, -144*flip))); return 0; } static int penrose_p3_small(penrose_state *state, int depth, int flip, vector v_orig, vector v_edge) { vector vv_orig; #ifdef DEBUG_PENROSE { vector vs[3]; vs[0] = v_orig; XFORM(1, 0, 0, 0); XFORM(2, 0, 0, -36*flip); state->new_tile(state, vs, 3, depth); } #endif if (flip > 0) { vector vs[4]; vs[0] = v_orig; XFORM(1, 0, 0, -36); XFORM(3, 0, 0, 0); XFORM(2, 3, 0, -36); state->new_tile(state, vs, 4, depth); } if (depth >= state->max_depth) return 0; /* NB these two are identical to the first two of p3_large. */ vv_orig = v_trans(v_orig, v_edge); penrose_p3_large(state, depth+1, -flip, vv_orig, v_shrinkphi(v_rotate(v_edge, 180))); penrose_p3_small(state, depth+1, flip, vv_orig, v_shrinkphi(v_rotate(v_edge, -108*flip))); return 0; } /* ------------------------------------------------------- * Utility routines. */ double penrose_side_length(double start_size, int depth) { return start_size / pow(PHI, depth); } void penrose_count_tiles(int depth, int *nlarge, int *nsmall) { /* Steal sgt's fibonacci thingummy. */ } /* * It turns out that an acute isosceles triangle with sides in ratio 1:phi:phi * has an incentre which is conveniently 2*phi^-2 of the way from the apex to * the base. Why's that convenient? Because: if we situate the incentre of the * triangle at the origin, then we can place the apex at phi^-2 * (B+C), and * the other two vertices at apex-B and apex-C respectively. So that's an acute * triangle with its long sides of unit length, covering a circle about the * origin of radius 1-(2*phi^-2), which is conveniently enough phi^-3. * * (later mail: this is an overestimate by about 5%) */ int penrose(penrose_state *state, int which, int angle) { vector vo = v_origin(); vector vb = v_origin(); vo.b = vo.c = -state->start_size; vo = v_shrinkphi(v_shrinkphi(vo)); vb.b = state->start_size; vo = v_rotate(vo, angle); vb = v_rotate(vb, angle); if (which == PENROSE_P2) return penrose_p2_large(state, 0, 1, vo, vb); else return penrose_p3_small(state, 0, 1, vo, vb); } /* * We're asked for a MxN grid, which just means a tiling fitting into roughly * an MxN space in some kind of reasonable unit - say, the side length of the * two-arrow edges of the tiles. By some reasoning in a previous email, that * means we want to pick some subarea of a circle of radius 3.11*sqrt(M^2+N^2). * To cover that circle, we need to subdivide a triangle large enough that it * contains a circle of that radius. * * Hence: start with those three vectors marking triangle vertices, scale them * all up by phi repeatedly until the radius of the inscribed circle gets * bigger than the target, and then recurse into that triangle with the same * recursion depth as the number of times you scaled up. That will give you * tiles of unit side length, covering a circle big enough that if you randomly * choose an orientation and coordinates within the circle, you'll be able to * get any valid piece of Penrose tiling of size MxN. */ #define INCIRCLE_RADIUS 0.22426 /* phi^-3 less 5%: see above */ void penrose_calculate_size(int which, int tilesize, int w, int h, double *required_radius, int *start_size, int *depth) { double rradius, size; int n = 0; /* * Fudge factor to scale P2 and P3 tilings differently. This * doesn't seem to have much relevance to questions like the * average number of tiles per unit area; it's just aesthetic. */ if (which == PENROSE_P2) tilesize = tilesize * 3 / 2; else tilesize = tilesize * 5 / 4; rradius = tilesize * 3.11 * sqrt((double)(w*w + h*h)); size = tilesize; while ((size * INCIRCLE_RADIUS) < rradius) { n++; size = size * PHI; } *start_size = (int)size; *depth = n; *required_radius = rradius; } /* ------------------------------------------------------- * Test code. */ #ifdef TEST_PENROSE #include #include int show_recursion = 0; int ntiles, nfinal; int test_cb(penrose_state *state, vector *vs, int n, int depth) { int i, xoff = 0, yoff = 0; double l = penrose_side_length(state->start_size, depth); double rball = l / 10.0; const char *col; ntiles++; if (state->max_depth == depth) { col = n == 4 ? "black" : "green"; nfinal++; } else { if (!show_recursion) return 0; col = n == 4 ? "red" : "blue"; } if (n != 4) yoff = state->start_size; printf("\n", col, col); printf("", v_x(vs, 0) + xoff, v_y(vs, 0) + yoff, rball, rball, col); return 0; } void usage_exit(void) { fprintf(stderr, "Usage: penrose-test [--recursion] P2|P3 SIZE DEPTH\n"); exit(1); } int main(int argc, char *argv[]) { penrose_state ps; int which = 0; while (--argc > 0) { char *p = *++argv; if (!strcmp(p, "-h") || !strcmp(p, "--help")) { usage_exit(); } else if (!strcmp(p, "--recursion")) { show_recursion = 1; } else if (*p == '-') { fprintf(stderr, "Unrecognised option '%s'\n", p); exit(1); } else { break; } } if (argc < 3) usage_exit(); if (strcmp(argv[0], "P2") == 0) which = PENROSE_P2; else if (strcmp(argv[0], "P3") == 0) which = PENROSE_P3; else usage_exit(); ps.start_size = atoi(argv[1]); ps.max_depth = atoi(argv[2]); ps.new_tile = test_cb; ntiles = nfinal = 0; printf("\ \n\ \n\ \n\ \n\n"); printf("\n"); penrose(&ps, which); printf("\n"); printf("\n", ntiles, nfinal); printf(""); return 0; } #endif #ifdef TEST_VECTORS static void dbgv(const char *msg, vector v) { printf("%s: %s\n", msg, v_debug(v)); } int main(int argc, const char *argv[]) { vector v = v_unit(); dbgv("unit vector", v); v = v_rotate(v, 36); dbgv("rotated 36", v); v = v_scale(v, 2); dbgv("scaled x2", v); v = v_shrinkphi(v); dbgv("shrunk phi", v); v = v_rotate(v, -36); dbgv("rotated -36", v); return 0; } #endif /* vim: set shiftwidth=4 tabstop=8: */ puzzles-20170606.272beef/pegs.c0000644000175000017500000010476013115373615015003 0ustar simonsimon/* * pegs.c: the classic Peg Solitaire game. */ #include #include #include #include #include #include #include "puzzles.h" #include "tree234.h" #define GRID_HOLE 0 #define GRID_PEG 1 #define GRID_OBST 2 #define GRID_CURSOR 10 #define GRID_JUMPING 20 enum { COL_BACKGROUND, COL_HIGHLIGHT, COL_LOWLIGHT, COL_PEG, COL_CURSOR, NCOLOURS }; /* * Grid shapes. I do some macro ickery here to ensure that my enum * and the various forms of my name list always match up. */ #define TYPELIST(A) \ A(CROSS,Cross,cross) \ A(OCTAGON,Octagon,octagon) \ A(RANDOM,Random,random) #define ENUM(upper,title,lower) TYPE_ ## upper, #define TITLE(upper,title,lower) #title, #define LOWER(upper,title,lower) #lower, #define CONFIG(upper,title,lower) ":" #title enum { TYPELIST(ENUM) TYPECOUNT }; static char const *const pegs_titletypes[] = { TYPELIST(TITLE) }; static char const *const pegs_lowertypes[] = { TYPELIST(LOWER) }; #define TYPECONFIG TYPELIST(CONFIG) #define FLASH_FRAME 0.13F struct game_params { int w, h; int type; }; struct game_state { int w, h; int completed; unsigned char *grid; }; static game_params *default_params(void) { game_params *ret = snew(game_params); ret->w = ret->h = 7; ret->type = TYPE_CROSS; return ret; } static const struct game_params pegs_presets[] = { {7, 7, TYPE_CROSS}, {7, 7, TYPE_OCTAGON}, {5, 5, TYPE_RANDOM}, {7, 7, TYPE_RANDOM}, {9, 9, TYPE_RANDOM}, }; static int game_fetch_preset(int i, char **name, game_params **params) { game_params *ret; char str[80]; if (i < 0 || i >= lenof(pegs_presets)) return FALSE; ret = snew(game_params); *ret = pegs_presets[i]; strcpy(str, pegs_titletypes[ret->type]); if (ret->type == TYPE_RANDOM) sprintf(str + strlen(str), " %dx%d", ret->w, ret->h); *name = dupstr(str); *params = ret; return TRUE; } static void free_params(game_params *params) { sfree(params); } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } static void decode_params(game_params *params, char const *string) { char const *p = string; int i; params->w = atoi(p); while (*p && isdigit((unsigned char)*p)) p++; if (*p == 'x') { p++; params->h = atoi(p); while (*p && isdigit((unsigned char)*p)) p++; } else { params->h = params->w; } for (i = 0; i < lenof(pegs_lowertypes); i++) if (!strcmp(p, pegs_lowertypes[i])) params->type = i; } static char *encode_params(const game_params *params, int full) { char str[80]; sprintf(str, "%dx%d", params->w, params->h); if (full) { assert(params->type >= 0 && params->type < lenof(pegs_lowertypes)); strcat(str, pegs_lowertypes[params->type]); } return dupstr(str); } static config_item *game_configure(const game_params *params) { config_item *ret = snewn(4, config_item); char buf[80]; ret[0].name = "Width"; ret[0].type = C_STRING; sprintf(buf, "%d", params->w); ret[0].sval = dupstr(buf); ret[0].ival = 0; ret[1].name = "Height"; ret[1].type = C_STRING; sprintf(buf, "%d", params->h); ret[1].sval = dupstr(buf); ret[1].ival = 0; ret[2].name = "Board type"; ret[2].type = C_CHOICES; ret[2].sval = TYPECONFIG; ret[2].ival = params->type; ret[3].name = NULL; ret[3].type = C_END; ret[3].sval = NULL; ret[3].ival = 0; return ret; } static game_params *custom_params(const config_item *cfg) { game_params *ret = snew(game_params); ret->w = atoi(cfg[0].sval); ret->h = atoi(cfg[1].sval); ret->type = cfg[2].ival; return ret; } static char *validate_params(const game_params *params, int full) { if (full && (params->w <= 3 || params->h <= 3)) return "Width and height must both be greater than three"; /* * It might be possible to implement generalisations of Cross * and Octagon, but only if I can find a proof that they're all * soluble. For the moment, therefore, I'm going to disallow * them at any size other than the standard one. */ if (full && (params->type == TYPE_CROSS || params->type == TYPE_OCTAGON)) { if (params->w != 7 || params->h != 7) return "This board type is only supported at 7x7"; } return NULL; } /* ---------------------------------------------------------------------- * Beginning of code to generate random Peg Solitaire boards. * * This procedure is done with no aesthetic judgment, no effort at * symmetry, no difficulty grading and generally no finesse * whatsoever. We simply begin with an empty board containing a * single peg, and repeatedly make random reverse moves until it's * plausibly full. This typically yields a scrappy haphazard mess * with several holes, an uneven shape, and no redeeming features * except guaranteed solubility. * * My only concessions to sophistication are (a) to repeat the * generation process until I at least get a grid that touches * every edge of the specified board size, and (b) to try when * selecting moves to reuse existing space rather than expanding * into new space (so that non-rectangular board shape becomes a * factor during play). */ struct move { /* * x,y are the start point of the move during generation (hence * its endpoint during normal play). * * dx,dy are the direction of the move during generation. * Absolute value 1. Hence, for example, x=3,y=5,dx=1,dy=0 * means that the move during generation starts at (3,5) and * ends at (5,5), and vice versa during normal play. */ int x, y, dx, dy; /* * cost is 0, 1 or 2, depending on how many GRID_OBSTs we must * turn into GRID_HOLEs to play this move. */ int cost; }; static int movecmp(void *av, void *bv) { struct move *a = (struct move *)av; struct move *b = (struct move *)bv; if (a->y < b->y) return -1; else if (a->y > b->y) return +1; if (a->x < b->x) return -1; else if (a->x > b->x) return +1; if (a->dy < b->dy) return -1; else if (a->dy > b->dy) return +1; if (a->dx < b->dx) return -1; else if (a->dx > b->dx) return +1; return 0; } static int movecmpcost(void *av, void *bv) { struct move *a = (struct move *)av; struct move *b = (struct move *)bv; if (a->cost < b->cost) return -1; else if (a->cost > b->cost) return +1; return movecmp(av, bv); } struct movetrees { tree234 *bymove, *bycost; }; static void update_moves(unsigned char *grid, int w, int h, int x, int y, struct movetrees *trees) { struct move move; int dir, pos; /* * There are twelve moves that can include (x,y): three in each * of four directions. Check each one to see if it's possible. */ for (dir = 0; dir < 4; dir++) { int dx, dy; if (dir & 1) dx = 0, dy = dir - 2; else dy = 0, dx = dir - 1; assert(abs(dx) + abs(dy) == 1); for (pos = 0; pos < 3; pos++) { int v1, v2, v3; move.dx = dx; move.dy = dy; move.x = x - pos*dx; move.y = y - pos*dy; if (move.x < 0 || move.x >= w || move.y < 0 || move.y >= h) continue; /* completely invalid move */ if (move.x+2*move.dx < 0 || move.x+2*move.dx >= w || move.y+2*move.dy < 0 || move.y+2*move.dy >= h) continue; /* completely invalid move */ v1 = grid[move.y * w + move.x]; v2 = grid[(move.y+move.dy) * w + (move.x+move.dx)]; v3 = grid[(move.y+2*move.dy)*w + (move.x+2*move.dx)]; if (v1 == GRID_PEG && v2 != GRID_PEG && v3 != GRID_PEG) { struct move *m; move.cost = (v2 == GRID_OBST) + (v3 == GRID_OBST); /* * This move is possible. See if it's already in * the tree. */ m = find234(trees->bymove, &move, NULL); if (m && m->cost != move.cost) { /* * It's in the tree but listed with the wrong * cost. Remove the old version. */ #ifdef GENERATION_DIAGNOSTICS printf("correcting %d%+d,%d%+d at cost %d\n", m->x, m->dx, m->y, m->dy, m->cost); #endif del234(trees->bymove, m); del234(trees->bycost, m); sfree(m); m = NULL; } if (!m) { struct move *m, *m2; m = snew(struct move); *m = move; m2 = add234(trees->bymove, m); m2 = add234(trees->bycost, m); assert(m2 == m); #ifdef GENERATION_DIAGNOSTICS printf("adding %d%+d,%d%+d at cost %d\n", move.x, move.dx, move.y, move.dy, move.cost); #endif } else { #ifdef GENERATION_DIAGNOSTICS printf("not adding %d%+d,%d%+d at cost %d\n", move.x, move.dx, move.y, move.dy, move.cost); #endif } } else { /* * This move is impossible. If it is already in the * tree, delete it. * * (We make use here of the fact that del234 * doesn't have to be passed a pointer to the * _actual_ element it's deleting: it merely needs * one that compares equal to it, and it will * return the one it deletes.) */ struct move *m = del234(trees->bymove, &move); #ifdef GENERATION_DIAGNOSTICS printf("%sdeleting %d%+d,%d%+d\n", m ? "" : "not ", move.x, move.dx, move.y, move.dy); #endif if (m) { del234(trees->bycost, m); sfree(m); } } } } } static void pegs_genmoves(unsigned char *grid, int w, int h, random_state *rs) { struct movetrees atrees, *trees = &atrees; struct move *m; int x, y, i, nmoves; trees->bymove = newtree234(movecmp); trees->bycost = newtree234(movecmpcost); for (y = 0; y < h; y++) for (x = 0; x < w; x++) if (grid[y*w+x] == GRID_PEG) update_moves(grid, w, h, x, y, trees); nmoves = 0; while (1) { int limit, maxcost, index; struct move mtmp, move, *m; /* * See how many moves we can make at zero cost. Make one, * if possible. Failing that, make a one-cost move, and * then a two-cost one. * * After filling at least half the input grid, we no longer * accept cost-2 moves: if that's our only option, we give * up and finish. */ mtmp.y = h+1; maxcost = (nmoves < w*h/2 ? 2 : 1); m = NULL; /* placate optimiser */ for (mtmp.cost = 0; mtmp.cost <= maxcost; mtmp.cost++) { limit = -1; m = findrelpos234(trees->bycost, &mtmp, NULL, REL234_LT, &limit); #ifdef GENERATION_DIAGNOSTICS printf("%d moves available with cost %d\n", limit+1, mtmp.cost); #endif if (m) break; } if (!m) break; index = random_upto(rs, limit+1); move = *(struct move *)index234(trees->bycost, index); #ifdef GENERATION_DIAGNOSTICS printf("selecting move %d%+d,%d%+d at cost %d\n", move.x, move.dx, move.y, move.dy, move.cost); #endif grid[move.y * w + move.x] = GRID_HOLE; grid[(move.y+move.dy) * w + (move.x+move.dx)] = GRID_PEG; grid[(move.y+2*move.dy)*w + (move.x+2*move.dx)] = GRID_PEG; for (i = 0; i <= 2; i++) { int tx = move.x + i*move.dx; int ty = move.y + i*move.dy; update_moves(grid, w, h, tx, ty, trees); } nmoves++; } while ((m = delpos234(trees->bymove, 0)) != NULL) { del234(trees->bycost, m); sfree(m); } freetree234(trees->bymove); freetree234(trees->bycost); } static void pegs_generate(unsigned char *grid, int w, int h, random_state *rs) { while (1) { int x, y, extremes; memset(grid, GRID_OBST, w*h); grid[(h/2) * w + (w/2)] = GRID_PEG; #ifdef GENERATION_DIAGNOSTICS printf("beginning move selection\n"); #endif pegs_genmoves(grid, w, h, rs); #ifdef GENERATION_DIAGNOSTICS printf("finished move selection\n"); #endif extremes = 0; for (y = 0; y < h; y++) { if (grid[y*w+0] != GRID_OBST) extremes |= 1; if (grid[y*w+w-1] != GRID_OBST) extremes |= 2; } for (x = 0; x < w; x++) { if (grid[0*w+x] != GRID_OBST) extremes |= 4; if (grid[(h-1)*w+x] != GRID_OBST) extremes |= 8; } if (extremes == 15) break; #ifdef GENERATION_DIAGNOSTICS printf("insufficient extent; trying again\n"); #endif } #ifdef GENERATION_DIAGNOSTICS fflush(stdout); #endif } /* ---------------------------------------------------------------------- * End of board generation code. Now for the client code which uses * it as part of the puzzle. */ static char *new_game_desc(const game_params *params, random_state *rs, char **aux, int interactive) { int w = params->w, h = params->h; unsigned char *grid; char *ret; int i; grid = snewn(w*h, unsigned char); if (params->type == TYPE_RANDOM) { pegs_generate(grid, w, h, rs); } else { int x, y, cx, cy, v; for (y = 0; y < h; y++) for (x = 0; x < w; x++) { v = GRID_OBST; /* placate optimiser */ switch (params->type) { case TYPE_CROSS: cx = abs(x - w/2); cy = abs(y - h/2); if (cx == 0 && cy == 0) v = GRID_HOLE; else if (cx > 1 && cy > 1) v = GRID_OBST; else v = GRID_PEG; break; case TYPE_OCTAGON: cx = abs(x - w/2); cy = abs(y - h/2); if (cx + cy > 1 + max(w,h)/2) v = GRID_OBST; else v = GRID_PEG; break; } grid[y*w+x] = v; } if (params->type == TYPE_OCTAGON) { /* * The octagonal (European) solitaire layout is * actually _insoluble_ with the starting hole at the * centre. Here's a proof: * * Colour the squares of the board diagonally in * stripes of three different colours, which I'll call * A, B and C. So the board looks like this: * * A B C * A B C A B * A B C A B C A * B C A B C A B * C A B C A B C * B C A B C * A B C * * Suppose we keep running track of the number of pegs * occuping each colour of square. This colouring has * the property that any valid move whatsoever changes * all three of those counts by one (two of them go * down and one goes up), which means that the _parity_ * of every count flips on every move. * * If the centre square starts off unoccupied, then * there are twelve pegs on each colour and all three * counts start off even; therefore, after 35 moves all * three counts would have to be odd, which isn't * possible if there's only one peg left. [] * * This proof works just as well if the starting hole * is _any_ of the thirteen positions labelled B. Also, * we can stripe the board in the opposite direction * and rule out any square labelled B in that colouring * as well. This leaves: * * Y n Y * n n Y n n * Y n n Y n n Y * n Y Y n Y Y n * Y n n Y n n Y * n n Y n n * Y n Y * * where the ns are squares we've proved insoluble, and * the Ys are the ones remaining. * * That doesn't prove all those starting positions to * be soluble, of course; they're merely the ones we * _haven't_ proved to be impossible. Nevertheless, it * turns out that they are all soluble, so when the * user requests an Octagon board the simplest thing is * to pick one of these at random. * * Rather than picking equiprobably from those twelve * positions, we'll pick equiprobably from the three * equivalence classes */ switch (random_upto(rs, 3)) { case 0: /* Remove a random corner piece. */ { int dx, dy; dx = random_upto(rs, 2) * 2 - 1; /* +1 or -1 */ dy = random_upto(rs, 2) * 2 - 1; /* +1 or -1 */ if (random_upto(rs, 2)) dy *= 3; else dx *= 3; grid[(3+dy)*w+(3+dx)] = GRID_HOLE; } break; case 1: /* Remove a random piece two from the centre. */ { int dx, dy; dx = 2 * (random_upto(rs, 2) * 2 - 1); if (random_upto(rs, 2)) dy = 0; else dy = dx, dx = 0; grid[(3+dy)*w+(3+dx)] = GRID_HOLE; } break; default /* case 2 */: /* Remove a random piece one from the centre. */ { int dx, dy; dx = random_upto(rs, 2) * 2 - 1; if (random_upto(rs, 2)) dy = 0; else dy = dx, dx = 0; grid[(3+dy)*w+(3+dx)] = GRID_HOLE; } break; } } } /* * Encode a game description which is simply a long list of P * for peg, H for hole or O for obstacle. */ ret = snewn(w*h+1, char); for (i = 0; i < w*h; i++) ret[i] = (grid[i] == GRID_PEG ? 'P' : grid[i] == GRID_HOLE ? 'H' : 'O'); ret[w*h] = '\0'; sfree(grid); return ret; } static char *validate_desc(const game_params *params, const char *desc) { int len = params->w * params->h; if (len != strlen(desc)) return "Game description is wrong length"; if (len != strspn(desc, "PHO")) return "Invalid character in game description"; return NULL; } static game_state *new_game(midend *me, const game_params *params, const char *desc) { int w = params->w, h = params->h; game_state *state = snew(game_state); int i; state->w = w; state->h = h; state->completed = 0; state->grid = snewn(w*h, unsigned char); for (i = 0; i < w*h; i++) state->grid[i] = (desc[i] == 'P' ? GRID_PEG : desc[i] == 'H' ? GRID_HOLE : GRID_OBST); return state; } static game_state *dup_game(const game_state *state) { int w = state->w, h = state->h; game_state *ret = snew(game_state); ret->w = state->w; ret->h = state->h; ret->completed = state->completed; ret->grid = snewn(w*h, unsigned char); memcpy(ret->grid, state->grid, w*h); return ret; } static void free_game(game_state *state) { sfree(state->grid); sfree(state); } static char *solve_game(const game_state *state, const game_state *currstate, const char *aux, char **error) { return NULL; } static int game_can_format_as_text_now(const game_params *params) { return TRUE; } static char *game_text_format(const game_state *state) { int w = state->w, h = state->h; int x, y; char *ret; ret = snewn((w+1)*h + 1, char); for (y = 0; y < h; y++) { for (x = 0; x < w; x++) ret[y*(w+1)+x] = (state->grid[y*w+x] == GRID_HOLE ? '-' : state->grid[y*w+x] == GRID_PEG ? '*' : ' '); ret[y*(w+1)+w] = '\n'; } ret[h*(w+1)] = '\0'; return ret; } struct game_ui { int dragging; /* boolean: is a drag in progress? */ int sx, sy; /* grid coords of drag start cell */ int dx, dy; /* pixel coords of current drag posn */ int cur_x, cur_y, cur_visible, cur_jumping; }; static game_ui *new_ui(const game_state *state) { game_ui *ui = snew(game_ui); int x, y, v; ui->sx = ui->sy = ui->dx = ui->dy = 0; ui->dragging = FALSE; ui->cur_visible = ui->cur_jumping = 0; /* make sure we start the cursor somewhere on the grid. */ for (x = 0; x < state->w; x++) { for (y = 0; y < state->h; y++) { v = state->grid[y*state->w+x]; if (v == GRID_PEG || v == GRID_HOLE) { ui->cur_x = x; ui->cur_y = y; goto found; } } } assert(!"new_ui found nowhere for cursor"); found: return ui; } static void free_ui(game_ui *ui) { sfree(ui); } static char *encode_ui(const game_ui *ui) { return NULL; } static void decode_ui(game_ui *ui, const char *encoding) { } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { /* * Cancel a drag, in case the source square has become * unoccupied. */ ui->dragging = FALSE; } #define PREFERRED_TILE_SIZE 33 #define TILESIZE (ds->tilesize) #define BORDER (TILESIZE / 2) #define HIGHLIGHT_WIDTH (TILESIZE / 16) #define COORD(x) ( BORDER + (x) * TILESIZE ) #define FROMCOORD(x) ( ((x) + TILESIZE - BORDER) / TILESIZE - 1 ) struct game_drawstate { int tilesize; blitter *drag_background; int dragging, dragx, dragy; int w, h; unsigned char *grid; int started; int bgcolour; }; static char *interpret_move(const game_state *state, game_ui *ui, const game_drawstate *ds, int x, int y, int button) { int w = state->w, h = state->h; char buf[80]; if (button == LEFT_BUTTON) { int tx, ty; /* * Left button down: we attempt to start a drag. */ /* * There certainly shouldn't be a current drag in progress, * unless the midend failed to send us button events in * order; it has a responsibility to always get that right, * so we can legitimately punish it by failing an * assertion. */ assert(!ui->dragging); tx = FROMCOORD(x); ty = FROMCOORD(y); if (tx >= 0 && tx < w && ty >= 0 && ty < h && state->grid[ty*w+tx] == GRID_PEG) { ui->dragging = TRUE; ui->sx = tx; ui->sy = ty; ui->dx = x; ui->dy = y; ui->cur_visible = ui->cur_jumping = 0; return ""; /* ui modified */ } } else if (button == LEFT_DRAG && ui->dragging) { /* * Mouse moved; just move the peg being dragged. */ ui->dx = x; ui->dy = y; return ""; /* ui modified */ } else if (button == LEFT_RELEASE && ui->dragging) { int tx, ty, dx, dy; /* * Button released. Identify the target square of the drag, * see if it represents a valid move, and if so make it. */ ui->dragging = FALSE; /* cancel the drag no matter what */ tx = FROMCOORD(x); ty = FROMCOORD(y); if (tx < 0 || tx >= w || ty < 0 || ty >= h) return ""; /* target out of range */ dx = tx - ui->sx; dy = ty - ui->sy; if (max(abs(dx),abs(dy)) != 2 || min(abs(dx),abs(dy)) != 0) return ""; /* move length was wrong */ dx /= 2; dy /= 2; if (state->grid[ty*w+tx] != GRID_HOLE || state->grid[(ty-dy)*w+(tx-dx)] != GRID_PEG || state->grid[ui->sy*w+ui->sx] != GRID_PEG) return ""; /* grid contents were invalid */ /* * We have a valid move. Encode it simply as source and * destination coordinate pairs. */ sprintf(buf, "%d,%d-%d,%d", ui->sx, ui->sy, tx, ty); return dupstr(buf); } else if (IS_CURSOR_MOVE(button)) { if (!ui->cur_jumping) { /* Not jumping; move cursor as usual, making sure we don't * leave the gameboard (which may be an irregular shape) */ int cx = ui->cur_x, cy = ui->cur_y; move_cursor(button, &cx, &cy, w, h, 0); ui->cur_visible = 1; if (state->grid[cy*w+cx] == GRID_HOLE || state->grid[cy*w+cx] == GRID_PEG) { ui->cur_x = cx; ui->cur_y = cy; } return ""; } else { int dx, dy, mx, my, jx, jy; /* We're jumping; if the requested direction has a hole, and * there's a peg in the way, */ assert(state->grid[ui->cur_y*w+ui->cur_x] == GRID_PEG); dx = (button == CURSOR_RIGHT) ? 1 : (button == CURSOR_LEFT) ? -1 : 0; dy = (button == CURSOR_DOWN) ? 1 : (button == CURSOR_UP) ? -1 : 0; mx = ui->cur_x+dx; my = ui->cur_y+dy; jx = mx+dx; jy = my+dy; ui->cur_jumping = 0; /* reset, whatever. */ if (jx >= 0 && jy >= 0 && jx < w && jy < h && state->grid[my*w+mx] == GRID_PEG && state->grid[jy*w+jx] == GRID_HOLE) { /* Move cursor to the jumped-to location (this felt more * natural while playtesting) */ sprintf(buf, "%d,%d-%d,%d", ui->cur_x, ui->cur_y, jx, jy); ui->cur_x = jx; ui->cur_y = jy; return dupstr(buf); } return ""; } } else if (IS_CURSOR_SELECT(button)) { if (!ui->cur_visible) { ui->cur_visible = 1; return ""; } if (ui->cur_jumping) { ui->cur_jumping = 0; return ""; } if (state->grid[ui->cur_y*w+ui->cur_x] == GRID_PEG) { /* cursor is on peg: next arrow-move wil jump. */ ui->cur_jumping = 1; return ""; } return NULL; } return NULL; } static game_state *execute_move(const game_state *state, const char *move) { int w = state->w, h = state->h; int sx, sy, tx, ty; game_state *ret; if (sscanf(move, "%d,%d-%d,%d", &sx, &sy, &tx, &ty) == 4) { int mx, my, dx, dy; if (sx < 0 || sx >= w || sy < 0 || sy >= h) return NULL; /* source out of range */ if (tx < 0 || tx >= w || ty < 0 || ty >= h) return NULL; /* target out of range */ dx = tx - sx; dy = ty - sy; if (max(abs(dx),abs(dy)) != 2 || min(abs(dx),abs(dy)) != 0) return NULL; /* move length was wrong */ mx = sx + dx/2; my = sy + dy/2; if (state->grid[sy*w+sx] != GRID_PEG || state->grid[my*w+mx] != GRID_PEG || state->grid[ty*w+tx] != GRID_HOLE) return NULL; /* grid contents were invalid */ ret = dup_game(state); ret->grid[sy*w+sx] = GRID_HOLE; ret->grid[my*w+mx] = GRID_HOLE; ret->grid[ty*w+tx] = GRID_PEG; /* * Opinion varies on whether getting to a single peg counts as * completing the game, or whether that peg has to be at a * specific location (central in the classic cross game, for * instance). For now we take the former, rather lax position. */ if (!ret->completed) { int count = 0, i; for (i = 0; i < w*h; i++) if (ret->grid[i] == GRID_PEG) count++; if (count == 1) ret->completed = 1; } return ret; } return NULL; } /* ---------------------------------------------------------------------- * Drawing routines. */ static void game_compute_size(const game_params *params, int tilesize, int *x, int *y) { /* Ick: fake up `ds->tilesize' for macro expansion purposes */ struct { int tilesize; } ads, *ds = &ads; ads.tilesize = tilesize; *x = TILESIZE * params->w + 2 * BORDER; *y = TILESIZE * params->h + 2 * BORDER; } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { ds->tilesize = tilesize; assert(TILESIZE > 0); assert(!ds->drag_background); /* set_size is never called twice */ ds->drag_background = blitter_new(dr, TILESIZE, TILESIZE); } static float *game_colours(frontend *fe, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float); game_mkhighlight(fe, ret, COL_BACKGROUND, COL_HIGHLIGHT, COL_LOWLIGHT); ret[COL_PEG * 3 + 0] = 0.0F; ret[COL_PEG * 3 + 1] = 0.0F; ret[COL_PEG * 3 + 2] = 1.0F; ret[COL_CURSOR * 3 + 0] = 0.5F; ret[COL_CURSOR * 3 + 1] = 0.5F; ret[COL_CURSOR * 3 + 2] = 1.0F; *ncolours = NCOLOURS; return ret; } static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { int w = state->w, h = state->h; struct game_drawstate *ds = snew(struct game_drawstate); ds->tilesize = 0; /* not decided yet */ /* We can't allocate the blitter rectangle for the drag background * until we know what size to make it. */ ds->drag_background = NULL; ds->dragging = FALSE; ds->w = w; ds->h = h; ds->grid = snewn(w*h, unsigned char); memset(ds->grid, 255, w*h); ds->started = FALSE; ds->bgcolour = -1; return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { if (ds->drag_background) blitter_free(dr, ds->drag_background); sfree(ds->grid); sfree(ds); } static void draw_tile(drawing *dr, game_drawstate *ds, int x, int y, int v, int bgcolour) { int cursor = 0, jumping = 0, bg; if (bgcolour >= 0) { draw_rect(dr, x, y, TILESIZE, TILESIZE, bgcolour); } if (v >= GRID_JUMPING) { jumping = 1; v -= GRID_JUMPING; } if (v >= GRID_CURSOR) { cursor = 1; v -= GRID_CURSOR; } if (v == GRID_HOLE) { bg = cursor ? COL_HIGHLIGHT : COL_LOWLIGHT; assert(!jumping); /* can't jump from a hole! */ draw_circle(dr, x+TILESIZE/2, y+TILESIZE/2, TILESIZE/4, bg, bg); } else if (v == GRID_PEG) { bg = (cursor || jumping) ? COL_CURSOR : COL_PEG; draw_circle(dr, x+TILESIZE/2, y+TILESIZE/2, TILESIZE/3, bg, bg); bg = (!cursor || jumping) ? COL_PEG : COL_CURSOR; draw_circle(dr, x+TILESIZE/2, y+TILESIZE/2, TILESIZE/4, bg, bg); } draw_update(dr, x, y, TILESIZE, TILESIZE); } static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float animtime, float flashtime) { int w = state->w, h = state->h; int x, y; int bgcolour; if (flashtime > 0) { int frame = (int)(flashtime / FLASH_FRAME); bgcolour = (frame % 2 ? COL_LOWLIGHT : COL_HIGHLIGHT); } else bgcolour = COL_BACKGROUND; /* * Erase the sprite currently being dragged, if any. */ if (ds->dragging) { assert(ds->drag_background); blitter_load(dr, ds->drag_background, ds->dragx, ds->dragy); draw_update(dr, ds->dragx, ds->dragy, TILESIZE, TILESIZE); ds->dragging = FALSE; } if (!ds->started) { draw_rect(dr, 0, 0, TILESIZE * state->w + 2 * BORDER, TILESIZE * state->h + 2 * BORDER, COL_BACKGROUND); /* * Draw relief marks around all the squares that aren't * GRID_OBST. */ for (y = 0; y < h; y++) for (x = 0; x < w; x++) if (state->grid[y*w+x] != GRID_OBST) { /* * First pass: draw the full relief square. */ int coords[6]; coords[0] = COORD(x+1) + HIGHLIGHT_WIDTH - 1; coords[1] = COORD(y) - HIGHLIGHT_WIDTH; coords[2] = COORD(x) - HIGHLIGHT_WIDTH; coords[3] = COORD(y+1) + HIGHLIGHT_WIDTH - 1; coords[4] = COORD(x) - HIGHLIGHT_WIDTH; coords[5] = COORD(y) - HIGHLIGHT_WIDTH; draw_polygon(dr, coords, 3, COL_HIGHLIGHT, COL_HIGHLIGHT); coords[4] = COORD(x+1) + HIGHLIGHT_WIDTH - 1; coords[5] = COORD(y+1) + HIGHLIGHT_WIDTH - 1; draw_polygon(dr, coords, 3, COL_LOWLIGHT, COL_LOWLIGHT); } for (y = 0; y < h; y++) for (x = 0; x < w; x++) if (state->grid[y*w+x] != GRID_OBST) { /* * Second pass: draw everything but the two * diagonal corners. */ draw_rect(dr, COORD(x) - HIGHLIGHT_WIDTH, COORD(y) - HIGHLIGHT_WIDTH, TILESIZE + HIGHLIGHT_WIDTH, TILESIZE + HIGHLIGHT_WIDTH, COL_HIGHLIGHT); draw_rect(dr, COORD(x), COORD(y), TILESIZE + HIGHLIGHT_WIDTH, TILESIZE + HIGHLIGHT_WIDTH, COL_LOWLIGHT); } for (y = 0; y < h; y++) for (x = 0; x < w; x++) if (state->grid[y*w+x] != GRID_OBST) { /* * Third pass: draw a trapezium on each edge. */ int coords[8]; int dx, dy, s, sn, c; for (dx = 0; dx < 2; dx++) { dy = 1 - dx; for (s = 0; s < 2; s++) { sn = 2*s - 1; c = s ? COL_LOWLIGHT : COL_HIGHLIGHT; coords[0] = COORD(x) + (s*dx)*(TILESIZE-1); coords[1] = COORD(y) + (s*dy)*(TILESIZE-1); coords[2] = COORD(x) + (s*dx+dy)*(TILESIZE-1); coords[3] = COORD(y) + (s*dy+dx)*(TILESIZE-1); coords[4] = coords[2] - HIGHLIGHT_WIDTH * (dy-sn*dx); coords[5] = coords[3] - HIGHLIGHT_WIDTH * (dx-sn*dy); coords[6] = coords[0] + HIGHLIGHT_WIDTH * (dy+sn*dx); coords[7] = coords[1] + HIGHLIGHT_WIDTH * (dx+sn*dy); draw_polygon(dr, coords, 4, c, c); } } } for (y = 0; y < h; y++) for (x = 0; x < w; x++) if (state->grid[y*w+x] != GRID_OBST) { /* * Second pass: draw everything but the two * diagonal corners. */ draw_rect(dr, COORD(x), COORD(y), TILESIZE, TILESIZE, COL_BACKGROUND); } ds->started = TRUE; draw_update(dr, 0, 0, TILESIZE * state->w + 2 * BORDER, TILESIZE * state->h + 2 * BORDER); } /* * Loop over the grid redrawing anything that looks as if it * needs it. */ for (y = 0; y < h; y++) for (x = 0; x < w; x++) { int v; v = state->grid[y*w+x]; /* * Blank the source of a drag so it looks as if the * user picked the peg up physically. */ if (ui->dragging && ui->sx == x && ui->sy == y && v == GRID_PEG) v = GRID_HOLE; if (ui->cur_visible && ui->cur_x == x && ui->cur_y == y) v += ui->cur_jumping ? GRID_JUMPING : GRID_CURSOR; if (v != GRID_OBST && (bgcolour != ds->bgcolour || /* always redraw when flashing */ v != ds->grid[y*w+x])) { draw_tile(dr, ds, COORD(x), COORD(y), v, bgcolour); ds->grid[y*w+x] = v; } } /* * Draw the dragging sprite if any. */ if (ui->dragging) { ds->dragging = TRUE; ds->dragx = ui->dx - TILESIZE/2; ds->dragy = ui->dy - TILESIZE/2; blitter_save(dr, ds->drag_background, ds->dragx, ds->dragy); draw_tile(dr, ds, ds->dragx, ds->dragy, GRID_PEG, -1); } ds->bgcolour = bgcolour; } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return 0.0F; } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { if (!oldstate->completed && newstate->completed) return 2 * FLASH_FRAME; else return 0.0F; } static int game_status(const game_state *state) { /* * Dead-end situations are assumed to be rescuable by Undo, so we * don't bother to identify them and return -1. */ return state->completed ? +1 : 0; } static int game_timing_state(const game_state *state, game_ui *ui) { return TRUE; } static void game_print_size(const game_params *params, float *x, float *y) { } static void game_print(drawing *dr, const game_state *state, int tilesize) { } #ifdef COMBINED #define thegame pegs #endif const struct game thegame = { "Pegs", "games.pegs", "pegs", default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, FALSE, solve_game, TRUE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, PREFERRED_TILE_SIZE, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, FALSE, FALSE, game_print_size, game_print, FALSE, /* wants_statusbar */ FALSE, game_timing_state, 0, /* flags */ }; /* vim: set shiftwidth=4 tabstop=8: */ puzzles-20170606.272beef/pearl.c0000644000175000017500000024257013115373615015152 0ustar simonsimon/* * pearl.c: Nikoli's `Masyu' puzzle. */ /* * TODO: * * - The current keyboard cursor mechanism works well on ordinary PC * keyboards, but for platforms with only arrow keys and a select * button or two, we may at some point need a simpler one which can * handle 'x' markings without needing shift keys. For instance, a * cursor with twice the grid resolution, so that it can range * across face centres, edge centres and vertices; 'clicks' on face * centres begin a drag as currently, clicks on edges toggle * markings, and clicks on vertices are ignored (but it would be * too confusing not to let the cursor rest on them). But I'm * pretty sure that would be less pleasant to play on a full * keyboard, so probably a #ifdef would be the thing. * * - Generation is still pretty slow, due to difficulty coming up in * the first place with a loop that makes a soluble puzzle even * with all possible clues filled in. * + A possible alternative strategy to further tuning of the * existing loop generator would be to throw the entire * mechanism out and instead write a different generator from * scratch which evolves the solution along with the puzzle: * place a few clues, nail down a bit of the loop, place another * clue, nail down some more, etc. However, I don't have a * detailed plan for any such mechanism, so it may be a pipe * dream. */ #include #include #include #include #include #include #include "puzzles.h" #include "grid.h" #include "loopgen.h" #define SWAP(i,j) do { int swaptmp = (i); (i) = (j); (j) = swaptmp; } while (0) #define NOCLUE 0 #define CORNER 1 #define STRAIGHT 2 #define R 1 #define U 2 #define L 4 #define D 8 #define DX(d) ( ((d)==R) - ((d)==L) ) #define DY(d) ( ((d)==D) - ((d)==U) ) #define F(d) (((d << 2) | (d >> 2)) & 0xF) #define C(d) (((d << 3) | (d >> 1)) & 0xF) #define A(d) (((d << 1) | (d >> 3)) & 0xF) #define LR (L | R) #define RL (R | L) #define UD (U | D) #define DU (D | U) #define LU (L | U) #define UL (U | L) #define LD (L | D) #define DL (D | L) #define RU (R | U) #define UR (U | R) #define RD (R | D) #define DR (D | R) #define BLANK 0 #define UNKNOWN 15 #define bLR (1 << LR) #define bRL (1 << RL) #define bUD (1 << UD) #define bDU (1 << DU) #define bLU (1 << LU) #define bUL (1 << UL) #define bLD (1 << LD) #define bDL (1 << DL) #define bRU (1 << RU) #define bUR (1 << UR) #define bRD (1 << RD) #define bDR (1 << DR) #define bBLANK (1 << BLANK) enum { COL_BACKGROUND, COL_HIGHLIGHT, COL_LOWLIGHT, COL_CURSOR_BACKGROUND = COL_LOWLIGHT, COL_BLACK, COL_WHITE, COL_ERROR, COL_GRID, COL_FLASH, COL_DRAGON, COL_DRAGOFF, NCOLOURS }; /* Macro ickery copied from slant.c */ #define DIFFLIST(A) \ A(EASY,Easy,e) \ A(TRICKY,Tricky,t) #define ENUM(upper,title,lower) DIFF_ ## upper, #define TITLE(upper,title,lower) #title, #define ENCODE(upper,title,lower) #lower #define CONFIG(upper,title,lower) ":" #title enum { DIFFLIST(ENUM) DIFFCOUNT }; static char const *const pearl_diffnames[] = { DIFFLIST(TITLE) "(count)" }; static char const pearl_diffchars[] = DIFFLIST(ENCODE); #define DIFFCONFIG DIFFLIST(CONFIG) struct game_params { int w, h; int difficulty; int nosolve; /* XXX remove me! */ }; struct shared_state { int w, h, sz; char *clues; /* size w*h */ int refcnt; }; #define INGRID(state, gx, gy) ((gx) >= 0 && (gx) < (state)->shared->w && \ (gy) >= 0 && (gy) < (state)->shared->h) struct game_state { struct shared_state *shared; char *lines; /* size w*h: lines placed */ char *errors; /* size w*h: errors detected */ char *marks; /* size w*h: 'no line here' marks placed. */ int completed, used_solve; }; #define DEFAULT_PRESET 3 static const struct game_params pearl_presets[] = { {6, 6, DIFF_EASY}, {6, 6, DIFF_TRICKY}, {8, 8, DIFF_EASY}, {8, 8, DIFF_TRICKY}, {10, 10, DIFF_EASY}, {10, 10, DIFF_TRICKY}, {12, 8, DIFF_EASY}, {12, 8, DIFF_TRICKY}, }; static game_params *default_params(void) { game_params *ret = snew(game_params); *ret = pearl_presets[DEFAULT_PRESET]; ret->nosolve = FALSE; return ret; } static int game_fetch_preset(int i, char **name, game_params **params) { game_params *ret; char buf[64]; if (i < 0 || i >= lenof(pearl_presets)) return FALSE; ret = default_params(); *ret = pearl_presets[i]; /* struct copy */ *params = ret; sprintf(buf, "%dx%d %s", pearl_presets[i].w, pearl_presets[i].h, pearl_diffnames[pearl_presets[i].difficulty]); *name = dupstr(buf); return TRUE; } static void free_params(game_params *params) { sfree(params); } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } static void decode_params(game_params *ret, char const *string) { ret->w = ret->h = atoi(string); while (*string && isdigit((unsigned char) *string)) ++string; if (*string == 'x') { string++; ret->h = atoi(string); while (*string && isdigit((unsigned char)*string)) string++; } ret->difficulty = DIFF_EASY; if (*string == 'd') { int i; string++; for (i = 0; i < DIFFCOUNT; i++) if (*string == pearl_diffchars[i]) ret->difficulty = i; if (*string) string++; } ret->nosolve = FALSE; if (*string == 'n') { ret->nosolve = TRUE; string++; } } static char *encode_params(const game_params *params, int full) { char buf[256]; sprintf(buf, "%dx%d", params->w, params->h); if (full) sprintf(buf + strlen(buf), "d%c%s", pearl_diffchars[params->difficulty], params->nosolve ? "n" : ""); return dupstr(buf); } static config_item *game_configure(const game_params *params) { config_item *ret; char buf[64]; ret = snewn(5, config_item); ret[0].name = "Width"; ret[0].type = C_STRING; sprintf(buf, "%d", params->w); ret[0].sval = dupstr(buf); ret[0].ival = 0; ret[1].name = "Height"; ret[1].type = C_STRING; sprintf(buf, "%d", params->h); ret[1].sval = dupstr(buf); ret[1].ival = 0; ret[2].name = "Difficulty"; ret[2].type = C_CHOICES; ret[2].sval = DIFFCONFIG; ret[2].ival = params->difficulty; ret[3].name = "Allow unsoluble"; ret[3].type = C_BOOLEAN; ret[3].sval = NULL; ret[3].ival = params->nosolve; ret[4].name = NULL; ret[4].type = C_END; ret[4].sval = NULL; ret[4].ival = 0; return ret; } static game_params *custom_params(const config_item *cfg) { game_params *ret = snew(game_params); ret->w = atoi(cfg[0].sval); ret->h = atoi(cfg[1].sval); ret->difficulty = cfg[2].ival; ret->nosolve = cfg[3].ival; return ret; } static char *validate_params(const game_params *params, int full) { if (params->w < 5) return "Width must be at least five"; if (params->h < 5) return "Height must be at least five"; if (params->difficulty < 0 || params->difficulty >= DIFFCOUNT) return "Unknown difficulty level"; return NULL; } /* ---------------------------------------------------------------------- * Solver. */ int pearl_solve(int w, int h, char *clues, char *result, int difficulty, int partial) { int W = 2*w+1, H = 2*h+1; short *workspace; int *dsf, *dsfsize; int x, y, b, d; int ret = -1; /* * workspace[(2*y+1)*W+(2*x+1)] indicates the possible nature * of the square (x,y), as a logical OR of bitfields. * * workspace[(2*y)*W+(2*x+1)], for x odd and y even, indicates * whether the horizontal edge between (x,y) and (x+1,y) is * connected (1), disconnected (2) or unknown (3). * * workspace[(2*y+1)*W+(2*x)], indicates the same about the * vertical edge between (x,y) and (x,y+1). * * Initially, every square is considered capable of being in * any of the seven possible states (two straights, four * corners and empty), except those corresponding to clue * squares which are more restricted. * * Initially, all edges are unknown, except the ones around the * grid border which are known to be disconnected. */ workspace = snewn(W*H, short); for (x = 0; x < W*H; x++) workspace[x] = 0; /* Square states */ for (y = 0; y < h; y++) for (x = 0; x < w; x++) switch (clues[y*w+x]) { case CORNER: workspace[(2*y+1)*W+(2*x+1)] = bLU|bLD|bRU|bRD; break; case STRAIGHT: workspace[(2*y+1)*W+(2*x+1)] = bLR|bUD; break; default: workspace[(2*y+1)*W+(2*x+1)] = bLR|bUD|bLU|bLD|bRU|bRD|bBLANK; break; } /* Horizontal edges */ for (y = 0; y <= h; y++) for (x = 0; x < w; x++) workspace[(2*y)*W+(2*x+1)] = (y==0 || y==h ? 2 : 3); /* Vertical edges */ for (y = 0; y < h; y++) for (x = 0; x <= w; x++) workspace[(2*y+1)*W+(2*x)] = (x==0 || x==w ? 2 : 3); /* * We maintain a dsf of connected squares, together with a * count of the size of each equivalence class. */ dsf = snewn(w*h, int); dsfsize = snewn(w*h, int); /* * Now repeatedly try to find something we can do. */ while (1) { int done_something = FALSE; #ifdef SOLVER_DIAGNOSTICS for (y = 0; y < H; y++) { for (x = 0; x < W; x++) printf("%*x", (x&1) ? 5 : 2, workspace[y*W+x]); printf("\n"); } #endif /* * Go through the square state words, and discard any * square state which is inconsistent with known facts * about the edges around the square. */ for (y = 0; y < h; y++) for (x = 0; x < w; x++) { for (b = 0; b < 0xD; b++) if (workspace[(2*y+1)*W+(2*x+1)] & (1<= 0) { /* * This square state would form * a loop on equivalence class * e. Measure the size of that * loop, and see if it's a * shortcut. */ int loopsize = dsfsize[e]; if (e != ae) loopsize++;/* add the square itself */ if (loopsize < nonblanks) { /* * It is! Mark this square * state invalid. */ workspace[y*W+x] &= ~(1<= 0); return ret; } /* ---------------------------------------------------------------------- * Loop generator. */ /* * We use the loop generator code from loopy, hard-coding to a square * grid of the appropriate size. Knowing the grid layout and the tile * size we can shrink that to our small grid and then make our line * layout from the face colour info. * * We provide a bias function to the loop generator which tries to * bias in favour of loops with more scope for Pearl black clues. This * seems to improve the success rate of the puzzle generator, in that * such loops have a better chance of being soluble with all valid * clues put in. */ struct pearl_loopgen_bias_ctx { /* * Our bias function counts the number of 'black clue' corners * (i.e. corners adjacent to two straights) in both the * BLACK/nonBLACK and WHITE/nonWHITE boundaries. In order to do * this, we must: * * - track the edges that are part of each of those loops * - track the types of vertex in each loop (corner, straight, * none) * - track the current black-clue status of each vertex in each * loop. * * Each of these chunks of data is updated incrementally from the * previous one, to avoid slowdown due to the bias function * rescanning the whole grid every time it's called. * * So we need a lot of separate arrays, plus a tdq for each one, * and we must repeat it all twice for the BLACK and WHITE * boundaries. */ struct pearl_loopgen_bias_ctx_boundary { int colour; /* FACE_WHITE or FACE_BLACK */ char *edges; /* is each edge part of the loop? */ tdq *edges_todo; char *vertextypes; /* bits 0-3 == outgoing edge bitmap; * bit 4 set iff corner clue. * Hence, 0 means non-vertex; * nonzero but bit 4 zero = straight. */ int *neighbour[2]; /* indices of neighbour vertices in loop */ tdq *vertextypes_todo; char *blackclues; /* is each vertex a black clue site? */ tdq *blackclues_todo; } boundaries[2]; /* boundaries[0]=WHITE, [1]=BLACK */ char *faces; /* remember last-seen colour of each face */ tdq *faces_todo; int score; grid *g; }; int pearl_loopgen_bias(void *vctx, char *board, int face) { struct pearl_loopgen_bias_ctx *ctx = (struct pearl_loopgen_bias_ctx *)vctx; grid *g = ctx->g; int oldface, newface; int i, j, k; tdq_add(ctx->faces_todo, face); while ((j = tdq_remove(ctx->faces_todo)) >= 0) { oldface = ctx->faces[j]; ctx->faces[j] = newface = board[j]; for (i = 0; i < 2; i++) { struct pearl_loopgen_bias_ctx_boundary *b = &ctx->boundaries[i]; int c = b->colour; /* * If the face has changed either from or to colour c, we need * to reprocess the edges for this boundary. */ if (oldface == c || newface == c) { grid_face *f = &g->faces[face]; for (k = 0; k < f->order; k++) tdq_add(b->edges_todo, f->edges[k] - g->edges); } } } for (i = 0; i < 2; i++) { struct pearl_loopgen_bias_ctx_boundary *b = &ctx->boundaries[i]; int c = b->colour; /* * Go through the to-do list of edges. For each edge, decide * anew whether it's part of this boundary or not. Any edge * that changes state has to have both its endpoints put on * the vertextypes_todo list. */ while ((j = tdq_remove(b->edges_todo)) >= 0) { grid_edge *e = &g->edges[j]; int fc1 = e->face1 ? board[e->face1 - g->faces] : FACE_BLACK; int fc2 = e->face2 ? board[e->face2 - g->faces] : FACE_BLACK; int oldedge = b->edges[j]; int newedge = (fc1==c) ^ (fc2==c); if (oldedge != newedge) { b->edges[j] = newedge; tdq_add(b->vertextypes_todo, e->dot1 - g->dots); tdq_add(b->vertextypes_todo, e->dot2 - g->dots); } } /* * Go through the to-do list of vertices whose types need * refreshing. For each one, decide whether it's a corner, a * straight, or a vertex not in the loop, and in the former * two cases also work out the indices of its neighbour * vertices along the loop. Any vertex that changes state must * be put back on the to-do list for deciding if it's a black * clue site, and so must its two new neighbours _and_ its two * old neighbours. */ while ((j = tdq_remove(b->vertextypes_todo)) >= 0) { grid_dot *d = &g->dots[j]; int neighbours[2], type = 0, n = 0; for (k = 0; k < d->order; k++) { grid_edge *e = d->edges[k]; grid_dot *d2 = (e->dot1 == d ? e->dot2 : e->dot1); /* dir == 0,1,2,3 for an edge going L,U,R,D */ int dir = (d->y == d2->y) + 2*(d->x+d->y > d2->x+d2->y); int ei = e - g->edges; if (b->edges[ei]) { type |= 1 << dir; neighbours[n] = d2 - g->dots; n++; } } /* * Decide if it's a corner, and set the corner flag if so. */ if (type != 0 && type != 0x5 && type != 0xA) type |= 0x10; if (type != b->vertextypes[j]) { /* * Recompute old neighbours, if any. */ if (b->vertextypes[j]) { tdq_add(b->blackclues_todo, b->neighbour[0][j]); tdq_add(b->blackclues_todo, b->neighbour[1][j]); } /* * Recompute this vertex. */ tdq_add(b->blackclues_todo, j); b->vertextypes[j] = type; /* * Recompute new neighbours, if any. */ if (b->vertextypes[j]) { b->neighbour[0][j] = neighbours[0]; b->neighbour[1][j] = neighbours[1]; tdq_add(b->blackclues_todo, b->neighbour[0][j]); tdq_add(b->blackclues_todo, b->neighbour[1][j]); } } } /* * Go through the list of vertices which we must check to see * if they're black clue sites. Each one is a black clue site * iff it is a corner and its loop neighbours are non-corners. * Adjust the running total of black clues we've counted. */ while ((j = tdq_remove(b->blackclues_todo)) >= 0) { ctx->score -= b->blackclues[j]; b->blackclues[j] = ((b->vertextypes[j] & 0x10) && !((b->vertextypes[b->neighbour[0][j]] | b->vertextypes[b->neighbour[1][j]]) & 0x10)); ctx->score += b->blackclues[j]; } } return ctx->score; } void pearl_loopgen(int w, int h, char *lines, random_state *rs) { grid *g = grid_new(GRID_SQUARE, w-1, h-1, NULL); char *board = snewn(g->num_faces, char); int i, s = g->tilesize; struct pearl_loopgen_bias_ctx biasctx; memset(lines, 0, w*h); /* * Initialise the context for the bias function. Initially we fill * all the to-do lists, so that the first call will scan * everything; thereafter the lists stay empty so we make * incremental changes. */ biasctx.g = g; biasctx.faces = snewn(g->num_faces, char); biasctx.faces_todo = tdq_new(g->num_faces); tdq_fill(biasctx.faces_todo); biasctx.score = 0; memset(biasctx.faces, FACE_GREY, g->num_faces); for (i = 0; i < 2; i++) { biasctx.boundaries[i].edges = snewn(g->num_edges, char); memset(biasctx.boundaries[i].edges, 0, g->num_edges); biasctx.boundaries[i].edges_todo = tdq_new(g->num_edges); tdq_fill(biasctx.boundaries[i].edges_todo); biasctx.boundaries[i].vertextypes = snewn(g->num_dots, char); memset(biasctx.boundaries[i].vertextypes, 0, g->num_dots); biasctx.boundaries[i].neighbour[0] = snewn(g->num_dots, int); biasctx.boundaries[i].neighbour[1] = snewn(g->num_dots, int); biasctx.boundaries[i].vertextypes_todo = tdq_new(g->num_dots); tdq_fill(biasctx.boundaries[i].vertextypes_todo); biasctx.boundaries[i].blackclues = snewn(g->num_dots, char); memset(biasctx.boundaries[i].blackclues, 0, g->num_dots); biasctx.boundaries[i].blackclues_todo = tdq_new(g->num_dots); tdq_fill(biasctx.boundaries[i].blackclues_todo); } biasctx.boundaries[0].colour = FACE_WHITE; biasctx.boundaries[1].colour = FACE_BLACK; generate_loop(g, board, rs, pearl_loopgen_bias, &biasctx); sfree(biasctx.faces); tdq_free(biasctx.faces_todo); for (i = 0; i < 2; i++) { sfree(biasctx.boundaries[i].edges); tdq_free(biasctx.boundaries[i].edges_todo); sfree(biasctx.boundaries[i].vertextypes); sfree(biasctx.boundaries[i].neighbour[0]); sfree(biasctx.boundaries[i].neighbour[1]); tdq_free(biasctx.boundaries[i].vertextypes_todo); sfree(biasctx.boundaries[i].blackclues); tdq_free(biasctx.boundaries[i].blackclues_todo); } for (i = 0; i < g->num_edges; i++) { grid_edge *e = g->edges + i; enum face_colour c1 = FACE_COLOUR(e->face1); enum face_colour c2 = FACE_COLOUR(e->face2); assert(c1 != FACE_GREY); assert(c2 != FACE_GREY); if (c1 != c2) { /* This grid edge is on the loop: lay line along it */ int x1 = e->dot1->x/s, y1 = e->dot1->y/s; int x2 = e->dot2->x/s, y2 = e->dot2->y/s; /* (x1,y1) and (x2,y2) are now in our grid coords (0-w,0-h). */ if (x1 == x2) { if (y1 > y2) SWAP(y1,y2); assert(y1+1 == y2); lines[y1*w+x1] |= D; lines[y2*w+x1] |= U; } else if (y1 == y2) { if (x1 > x2) SWAP(x1,x2); assert(x1+1 == x2); lines[y1*w+x1] |= R; lines[y1*w+x2] |= L; } else assert(!"grid with diagonal coords?!"); } } grid_free(g); sfree(board); #if defined LOOPGEN_DIAGNOSTICS && !defined GENERATION_DIAGNOSTICS printf("as returned:\n"); for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { int type = lines[y*w+x]; char s[5], *p = s; if (type & L) *p++ = 'L'; if (type & R) *p++ = 'R'; if (type & U) *p++ = 'U'; if (type & D) *p++ = 'D'; *p = '\0'; printf("%3s", s); } printf("\n"); } printf("\n"); #endif } static int new_clues(const game_params *params, random_state *rs, char *clues, char *grid) { int w = params->w, h = params->h, diff = params->difficulty; int ngen = 0, x, y, d, ret, i; /* * Difficulty exception: 5x5 Tricky is not generable (the * generator will spin forever trying) and so we fudge it to Easy. */ if (w == 5 && h == 5 && diff > DIFF_EASY) diff = DIFF_EASY; while (1) { ngen++; pearl_loopgen(w, h, grid, rs); #ifdef GENERATION_DIAGNOSTICS printf("grid array:\n"); for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { int type = grid[y*w+x]; char s[5], *p = s; if (type & L) *p++ = 'L'; if (type & R) *p++ = 'R'; if (type & U) *p++ = 'U'; if (type & D) *p++ = 'D'; *p = '\0'; printf("%2s ", s); } printf("\n"); } printf("\n"); #endif /* * Set up the maximal clue array. */ for (y = 0; y < h; y++) for (x = 0; x < w; x++) { int type = grid[y*w+x]; clues[y*w+x] = NOCLUE; if ((bLR|bUD) & (1 << type)) { /* * This is a straight; see if it's a viable * candidate for a straight clue. It qualifies if * at least one of the squares it connects to is a * corner. */ for (d = 1; d <= 8; d += d) if (type & d) { int xx = x + DX(d), yy = y + DY(d); assert(xx >= 0 && xx < w && yy >= 0 && yy < h); if ((bLU|bLD|bRU|bRD) & (1 << grid[yy*w+xx])) break; } if (d <= 8) /* we found one */ clues[y*w+x] = STRAIGHT; } else if ((bLU|bLD|bRU|bRD) & (1 << type)) { /* * This is a corner; see if it's a viable candidate * for a corner clue. It qualifies if all the * squares it connects to are straights. */ for (d = 1; d <= 8; d += d) if (type & d) { int xx = x + DX(d), yy = y + DY(d); assert(xx >= 0 && xx < w && yy >= 0 && yy < h); if (!((bLR|bUD) & (1 << grid[yy*w+xx]))) break; } if (d > 8) /* we didn't find a counterexample */ clues[y*w+x] = CORNER; } } #ifdef GENERATION_DIAGNOSTICS printf("clue array:\n"); for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { printf("%c", " *O"[(unsigned char)clues[y*w+x]]); } printf("\n"); } printf("\n"); #endif if (!params->nosolve) { int *cluespace, *straights, *corners; int nstraights, ncorners, nstraightpos, ncornerpos; /* * See if we can solve the puzzle just like this. */ ret = pearl_solve(w, h, clues, grid, diff, FALSE); assert(ret > 0); /* shouldn't be inconsistent! */ if (ret != 1) continue; /* go round and try again */ /* * Check this puzzle isn't too easy. */ if (diff > DIFF_EASY) { ret = pearl_solve(w, h, clues, grid, diff-1, FALSE); assert(ret > 0); if (ret == 1) continue; /* too easy: try again */ } /* * Now shuffle the grid points and gradually remove the * clues to find a minimal set which still leaves the * puzzle soluble. * * We preferentially attempt to remove whichever type of * clue is currently most numerous, to combat a general * tendency of plain random generation to bias in favour * of many white clues and few black. * * 'nstraights' and 'ncorners' count the number of clues * of each type currently remaining in the grid; * 'nstraightpos' and 'ncornerpos' count the clues of each * type we have left to try to remove. (Clues which we * have tried and failed to remove are counted by the * former but not the latter.) */ cluespace = snewn(w*h, int); straights = cluespace; nstraightpos = 0; for (i = 0; i < w*h; i++) if (clues[i] == STRAIGHT) straights[nstraightpos++] = i; corners = straights + nstraightpos; ncornerpos = 0; for (i = 0; i < w*h; i++) if (clues[i] == STRAIGHT) corners[ncornerpos++] = i; nstraights = nstraightpos; ncorners = ncornerpos; shuffle(straights, nstraightpos, sizeof(*straights), rs); shuffle(corners, ncornerpos, sizeof(*corners), rs); while (nstraightpos > 0 || ncornerpos > 0) { int cluepos; int clue; /* * Decide which clue to try to remove next. If both * types are available, we choose whichever kind is * currently overrepresented; otherwise we take * whatever we can get. */ if (nstraightpos > 0 && ncornerpos > 0) { if (nstraights >= ncorners) cluepos = straights[--nstraightpos]; else cluepos = straights[--ncornerpos]; } else { if (nstraightpos > 0) cluepos = straights[--nstraightpos]; else cluepos = straights[--ncornerpos]; } y = cluepos / w; x = cluepos % w; clue = clues[y*w+x]; clues[y*w+x] = 0; /* try removing this clue */ ret = pearl_solve(w, h, clues, grid, diff, FALSE); assert(ret > 0); if (ret != 1) clues[y*w+x] = clue; /* oops, put it back again */ } sfree(cluespace); } #ifdef FINISHED_PUZZLE printf("clue array:\n"); for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { printf("%c", " *O"[(unsigned char)clues[y*w+x]]); } printf("\n"); } printf("\n"); #endif break; /* got it */ } debug(("%d %dx%d loops before finished puzzle.\n", ngen, w, h)); return ngen; } static char *new_game_desc(const game_params *params, random_state *rs, char **aux, int interactive) { char *grid, *clues; char *desc; int w = params->w, h = params->h, i, j; grid = snewn(w*h, char); clues = snewn(w*h, char); new_clues(params, rs, clues, grid); desc = snewn(w * h + 1, char); for (i = j = 0; i < w*h; i++) { if (clues[i] == NOCLUE && j > 0 && desc[j-1] >= 'a' && desc[j-1] < 'z') desc[j-1]++; else if (clues[i] == NOCLUE) desc[j++] = 'a'; else if (clues[i] == CORNER) desc[j++] = 'B'; else if (clues[i] == STRAIGHT) desc[j++] = 'W'; } desc[j] = '\0'; *aux = snewn(w*h+1, char); for (i = 0; i < w*h; i++) (*aux)[i] = (grid[i] < 10) ? (grid[i] + '0') : (grid[i] + 'A' - 10); (*aux)[w*h] = '\0'; sfree(grid); sfree(clues); return desc; } static char *validate_desc(const game_params *params, const char *desc) { int i, sizesofar; const int totalsize = params->w * params->h; sizesofar = 0; for (i = 0; desc[i]; i++) { if (desc[i] >= 'a' && desc[i] <= 'z') sizesofar += desc[i] - 'a' + 1; else if (desc[i] == 'B' || desc[i] == 'W') sizesofar++; else return "unrecognised character in string"; } if (sizesofar > totalsize) return "string too long"; else if (sizesofar < totalsize) return "string too short"; return NULL; } static game_state *new_game(midend *me, const game_params *params, const char *desc) { game_state *state = snew(game_state); int i, j, sz = params->w*params->h; state->completed = state->used_solve = FALSE; state->shared = snew(struct shared_state); state->shared->w = params->w; state->shared->h = params->h; state->shared->sz = sz; state->shared->refcnt = 1; state->shared->clues = snewn(sz, char); for (i = j = 0; desc[i]; i++) { assert(j < sz); if (desc[i] >= 'a' && desc[i] <= 'z') { int n = desc[i] - 'a' + 1; assert(j + n <= sz); while (n-- > 0) state->shared->clues[j++] = NOCLUE; } else if (desc[i] == 'B') { state->shared->clues[j++] = CORNER; } else if (desc[i] == 'W') { state->shared->clues[j++] = STRAIGHT; } } state->lines = snewn(sz, char); state->errors = snewn(sz, char); state->marks = snewn(sz, char); for (i = 0; i < sz; i++) state->lines[i] = state->errors[i] = state->marks[i] = BLANK; return state; } static game_state *dup_game(const game_state *state) { game_state *ret = snew(game_state); int sz = state->shared->sz, i; ret->shared = state->shared; ret->completed = state->completed; ret->used_solve = state->used_solve; ++ret->shared->refcnt; ret->lines = snewn(sz, char); ret->errors = snewn(sz, char); ret->marks = snewn(sz, char); for (i = 0; i < sz; i++) { ret->lines[i] = state->lines[i]; ret->errors[i] = state->errors[i]; ret->marks[i] = state->marks[i]; } return ret; } static void free_game(game_state *state) { assert(state); if (--state->shared->refcnt == 0) { sfree(state->shared->clues); sfree(state->shared); } sfree(state->lines); sfree(state->errors); sfree(state->marks); sfree(state); } static char nbits[16] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 }; #define NBITS(l) ( ((l) < 0 || (l) > 15) ? 4 : nbits[l] ) #define ERROR_CLUE 16 static void dsf_update_completion(game_state *state, int ax, int ay, char dir, int *dsf) { int w = state->shared->w /*, h = state->shared->h */; int ac = ay*w+ax, bx, by, bc; if (!(state->lines[ac] & dir)) return; /* no link */ bx = ax + DX(dir); by = ay + DY(dir); assert(INGRID(state, bx, by)); /* should not have a link off grid */ bc = by*w+bx; assert(state->lines[bc] & F(dir)); /* should have reciprocal link */ if (!(state->lines[bc] & F(dir))) return; dsf_merge(dsf, ac, bc); } static void check_completion(game_state *state, int mark) { int w = state->shared->w, h = state->shared->h, x, y, i, d; int had_error = FALSE; int *dsf, *component_state; int nsilly, nloop, npath, largest_comp, largest_size, total_pathsize; enum { COMP_NONE, COMP_LOOP, COMP_PATH, COMP_SILLY, COMP_EMPTY }; if (mark) { for (i = 0; i < w*h; i++) { state->errors[i] = 0; } } #define ERROR(x,y,e) do { had_error = TRUE; if (mark) state->errors[(y)*w+(x)] |= (e); } while(0) /* * Analyse the solution into loops, paths and stranger things. * Basic strategy here is all the same as in Loopy - see the big * comment in loopy.c's check_completion() - and for exactly the * same reasons, since Loopy and Pearl have basically the same * form of expected solution. */ dsf = snew_dsf(w*h); /* Build the dsf. */ for (x = 0; x < w; x++) { for (y = 0; y < h; y++) { dsf_update_completion(state, x, y, R, dsf); dsf_update_completion(state, x, y, D, dsf); } } /* Initialise a state variable for each connected component. */ component_state = snewn(w*h, int); for (i = 0; i < w*h; i++) { if (dsf_canonify(dsf, i) == i) component_state[i] = COMP_LOOP; else component_state[i] = COMP_NONE; } /* * Classify components, and mark errors where a square has more * than two line segments. */ for (x = 0; x < w; x++) { for (y = 0; y < h; y++) { int type = state->lines[y*w+x]; int degree = NBITS(type); int comp = dsf_canonify(dsf, y*w+x); if (degree > 2) { ERROR(x,y,type); component_state[comp] = COMP_SILLY; } else if (degree == 0) { component_state[comp] = COMP_EMPTY; } else if (degree == 1) { if (component_state[comp] != COMP_SILLY) component_state[comp] = COMP_PATH; } } } /* Count the components, and find the largest sensible one. */ nsilly = nloop = npath = 0; total_pathsize = 0; largest_comp = largest_size = -1; for (i = 0; i < w*h; i++) { if (component_state[i] == COMP_SILLY) { nsilly++; } else if (component_state[i] == COMP_PATH) { total_pathsize += dsf_size(dsf, i); npath = 1; } else if (component_state[i] == COMP_LOOP) { int this_size; nloop++; if ((this_size = dsf_size(dsf, i)) > largest_size) { largest_comp = i; largest_size = this_size; } } } if (largest_size < total_pathsize) { largest_comp = -1; /* means the paths */ largest_size = total_pathsize; } if (nloop > 0 && nloop + npath > 1) { /* * If there are at least two sensible components including at * least one loop, highlight every sensible component that is * not the largest one. */ for (i = 0; i < w*h; i++) { int comp = dsf_canonify(dsf, i); if ((component_state[comp] == COMP_PATH && -1 != largest_comp) || (component_state[comp] == COMP_LOOP && comp != largest_comp)) ERROR(i%w, i/w, state->lines[i]); } } /* Now we've finished with the dsf and component states. The only * thing we'll need to remember later on is whether all edges were * part of a single loop, for which our counter variables * nsilly,nloop,npath are enough. */ sfree(component_state); sfree(dsf); /* * Check that no clues are contradicted. This code is similar to * the code that sets up the maximal clue array for any given * loop. */ for (x = 0; x < w; x++) { for (y = 0; y < h; y++) { int type = state->lines[y*w+x]; if (state->shared->clues[y*w+x] == CORNER) { /* Supposed to be a corner: will find a contradiction if * it actually contains a straight line, or if it touches any * corners. */ if ((bLR|bUD) & (1 << type)) { ERROR(x,y,ERROR_CLUE); /* actually straight */ } for (d = 1; d <= 8; d += d) if (type & d) { int xx = x + DX(d), yy = y + DY(d); if (!INGRID(state, xx, yy)) { ERROR(x,y,d); /* leads off grid */ } else { if ((bLU|bLD|bRU|bRD) & (1 << state->lines[yy*w+xx])) { ERROR(x,y,ERROR_CLUE); /* touches corner */ } } } } else if (state->shared->clues[y*w+x] == STRAIGHT) { /* Supposed to be straight: will find a contradiction if * it actually contains a corner, or if it only touches * straight lines. */ if ((bLU|bLD|bRU|bRD) & (1 << type)) { ERROR(x,y,ERROR_CLUE); /* actually a corner */ } i = 0; for (d = 1; d <= 8; d += d) if (type & d) { int xx = x + DX(d), yy = y + DY(d); if (!INGRID(state, xx, yy)) { ERROR(x,y,d); /* leads off grid */ } else { if ((bLR|bUD) & (1 << state->lines[yy*w+xx])) i++; /* a straight */ } } if (i >= 2 && NBITS(type) >= 2) { ERROR(x,y,ERROR_CLUE); /* everything touched is straight */ } } } } if (nloop == 1 && nsilly == 0 && npath == 0) { /* * If there's exactly one loop (so that the puzzle is at least * potentially complete), we need to ensure it hasn't left any * clue out completely. */ for (x = 0; x < w; x++) { for (y = 0; y < h; y++) { if (state->lines[y*w+x] == BLANK) { if (state->shared->clues[y*w+x] != NOCLUE) { /* the loop doesn't include this clue square! */ ERROR(x, y, ERROR_CLUE); } } } } /* * But if not, then we're done! */ if (!had_error) state->completed = TRUE; } } /* completion check: * * - no clues must be contradicted (highlight clue itself in error if so) * - if there is a closed loop it must include every line segment laid * - if there's a smaller closed loop then highlight whole loop as error * - no square must have more than 2 lines radiating from centre point * (highlight all lines in that square as error if so) */ static char *solve_for_diff(game_state *state, char *old_lines, char *new_lines) { int w = state->shared->w, h = state->shared->h, i; char *move = snewn(w*h*40, char), *p = move; *p++ = 'S'; for (i = 0; i < w*h; i++) { if (old_lines[i] != new_lines[i]) { p += sprintf(p, ";R%d,%d,%d", new_lines[i], i%w, i/w); } } *p++ = '\0'; move = sresize(move, p - move, char); return move; } static char *solve_game(const game_state *state, const game_state *currstate, const char *aux, char **error) { game_state *solved = dup_game(state); int i, ret, sz = state->shared->sz; char *move; if (aux) { for (i = 0; i < sz; i++) { if (aux[i] >= '0' && aux[i] <= '9') solved->lines[i] = aux[i] - '0'; else if (aux[i] >= 'A' && aux[i] <= 'F') solved->lines[i] = aux[i] - 'A' + 10; else { *error = "invalid char in aux"; move = NULL; goto done; } } ret = 1; } else { /* Try to solve with present (half-solved) state first: if there's no * solution from there go back to original state. */ ret = pearl_solve(currstate->shared->w, currstate->shared->h, currstate->shared->clues, solved->lines, DIFFCOUNT, FALSE); if (ret < 1) ret = pearl_solve(state->shared->w, state->shared->h, state->shared->clues, solved->lines, DIFFCOUNT, FALSE); } if (ret < 1) { *error = "Unable to find solution"; move = NULL; } else { move = solve_for_diff(solved, currstate->lines, solved->lines); } done: free_game(solved); return move; } static int game_can_format_as_text_now(const game_params *params) { return TRUE; } static char *game_text_format(const game_state *state) { int w = state->shared->w, h = state->shared->h, cw = 4, ch = 2; int gw = cw*(w-1) + 2, gh = ch*(h-1) + 1, len = gw * gh, r, c, j; char *board = snewn(len + 1, char); assert(board); memset(board, ' ', len); for (r = 0; r < h; ++r) { for (c = 0; c < w; ++c) { int i = r*w + c, cell = r*ch*gw + c*cw; board[cell] = "+BW"[(unsigned char)state->shared->clues[i]]; if (c < w - 1 && (state->lines[i] & R || state->lines[i+1] & L)) memset(board + cell + 1, '-', cw - 1); if (r < h - 1 && (state->lines[i] & D || state->lines[i+w] & U)) for (j = 1; j < ch; ++j) board[cell + j*gw] = '|'; if (c < w - 1 && (state->marks[i] & R || state->marks[i+1] & L)) board[cell + cw/2] = 'x'; if (r < h - 1 && (state->marks[i] & D || state->marks[i+w] & U)) board[cell + (ch/2 * gw)] = 'x'; } for (j = 0; j < (r == h - 1 ? 1 : ch); ++j) board[r*ch*gw + (gw - 1) + j*gw] = '\n'; } board[len] = '\0'; return board; } struct game_ui { int *dragcoords; /* list of (y*w+x) coords in drag so far */ int ndragcoords; /* number of entries in dragcoords. * 0 = click but no drag yet. -1 = no drag at all */ int clickx, clicky; /* pixel position of initial click */ int curx, cury; /* grid position of keyboard cursor */ int cursor_active; /* TRUE iff cursor is shown */ }; static game_ui *new_ui(const game_state *state) { game_ui *ui = snew(game_ui); int sz = state->shared->sz; ui->ndragcoords = -1; ui->dragcoords = snewn(sz, int); ui->cursor_active = FALSE; ui->curx = ui->cury = 0; return ui; } static void free_ui(game_ui *ui) { sfree(ui->dragcoords); sfree(ui); } static char *encode_ui(const game_ui *ui) { return NULL; } static void decode_ui(game_ui *ui, const char *encoding) { } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { } #define PREFERRED_TILE_SIZE 31 #define HALFSZ (ds->halfsz) #define TILE_SIZE (ds->halfsz*2 + 1) #define BORDER ((get_gui_style() == GUI_LOOPY) ? (TILE_SIZE/8) : (TILE_SIZE/2)) #define BORDER_WIDTH (max(TILE_SIZE / 32, 1)) #define COORD(x) ( (x) * TILE_SIZE + BORDER ) #define CENTERED_COORD(x) ( COORD(x) + TILE_SIZE/2 ) #define FROMCOORD(x) ( ((x) < BORDER) ? -1 : ( ((x) - BORDER) / TILE_SIZE) ) #define DS_ESHIFT 4 /* R/U/L/D shift, for error flags */ #define DS_DSHIFT 8 /* R/U/L/D shift, for drag-in-progress flags */ #define DS_MSHIFT 12 /* shift for no-line mark */ #define DS_ERROR_CLUE (1 << 20) #define DS_FLASH (1 << 21) #define DS_CURSOR (1 << 22) enum { GUI_MASYU, GUI_LOOPY }; static int get_gui_style(void) { static int gui_style = -1; if (gui_style == -1) { char *env = getenv("PEARL_GUI_LOOPY"); if (env && (env[0] == 'y' || env[0] == 'Y')) gui_style = GUI_LOOPY; else gui_style = GUI_MASYU; } return gui_style; } struct game_drawstate { int halfsz; int started; int w, h, sz; unsigned int *lflags; /* size w*h */ char *draglines; /* size w*h; lines flipped by current drag */ }; static void update_ui_drag(const game_state *state, game_ui *ui, int gx, int gy) { int /* sz = state->shared->sz, */ w = state->shared->w; int i, ox, oy, pos; int lastpos; if (!INGRID(state, gx, gy)) return; /* square is outside grid */ if (ui->ndragcoords < 0) return; /* drag not in progress anyway */ pos = gy * w + gx; lastpos = ui->dragcoords[ui->ndragcoords > 0 ? ui->ndragcoords-1 : 0]; if (pos == lastpos) return; /* same square as last visited one */ /* Drag confirmed, if it wasn't already. */ if (ui->ndragcoords == 0) ui->ndragcoords = 1; /* * Dragging the mouse into a square that's already been visited by * the drag path so far has the effect of truncating the path back * to that square, so a player can back out part of an uncommitted * drag without having to let go of the mouse. */ for (i = 0; i < ui->ndragcoords; i++) if (pos == ui->dragcoords[i]) { ui->ndragcoords = i+1; return; } /* * Otherwise, dragging the mouse into a square that's a rook-move * away from the last one on the path extends the path. */ oy = ui->dragcoords[ui->ndragcoords-1] / w; ox = ui->dragcoords[ui->ndragcoords-1] % w; if (ox == gx || oy == gy) { int dx = (gx < ox ? -1 : gx > ox ? +1 : 0); int dy = (gy < oy ? -1 : gy > oy ? +1 : 0); int dir = (dy>0 ? D : dy<0 ? U : dx>0 ? R : L); while (ox != gx || oy != gy) { /* * If the drag attempts to cross a 'no line here' mark, * stop there. We physically don't allow the user to drag * over those marks. */ if (state->marks[oy*w+ox] & dir) break; ox += dx; oy += dy; ui->dragcoords[ui->ndragcoords++] = oy * w + ox; } } /* * Failing that, we do nothing at all: if the user has dragged * diagonally across the board, they'll just have to return the * mouse to the last known position and do whatever they meant to * do again, more slowly and clearly. */ } /* * Routine shared between interpret_move and game_redraw to work out * the intended effect of a drag path on the grid. * * Call it in a loop, like this: * * int clearing = TRUE; * for (i = 0; i < ui->ndragcoords - 1; i++) { * int sx, sy, dx, dy, dir, oldstate, newstate; * interpret_ui_drag(state, ui, &clearing, i, &sx, &sy, &dx, &dy, * &dir, &oldstate, &newstate); * * [do whatever is needed to handle the fact that the drag * wants the edge from sx,sy to dx,dy (heading in direction * 'dir' at the sx,sy end) to be changed from state oldstate * to state newstate, each of which equals either 0 or dir] * } */ static void interpret_ui_drag(const game_state *state, const game_ui *ui, int *clearing, int i, int *sx, int *sy, int *dx, int *dy, int *dir, int *oldstate, int *newstate) { int w = state->shared->w; int sp = ui->dragcoords[i], dp = ui->dragcoords[i+1]; *sy = sp/w; *sx = sp%w; *dy = dp/w; *dx = dp%w; *dir = (*dy>*sy ? D : *dy<*sy ? U : *dx>*sx ? R : L); *oldstate = state->lines[sp] & *dir; if (*oldstate) { /* * The edge we've dragged over was previously * present. Set it to absent, unless we've already * stopped doing that. */ *newstate = *clearing ? 0 : *dir; } else { /* * The edge we've dragged over was previously * absent. Set it to present, and cancel the * 'clearing' flag so that all subsequent edges in * the drag are set rather than cleared. */ *newstate = *dir; *clearing = FALSE; } } static char *mark_in_direction(const game_state *state, int x, int y, int dir, int primary, char *buf) { int w = state->shared->w /*, h = state->shared->h, sz = state->shared->sz */; int x2 = x + DX(dir); int y2 = y + DY(dir); int dir2 = F(dir); char ch = primary ? 'F' : 'M', *other; if (!INGRID(state, x, y) || !INGRID(state, x2, y2)) return ""; /* disallow laying a mark over a line, or vice versa. */ other = primary ? state->marks : state->lines; if (other[y*w+x] & dir || other[y2*w+x2] & dir2) return ""; sprintf(buf, "%c%d,%d,%d;%c%d,%d,%d", ch, dir, x, y, ch, dir2, x2, y2); return dupstr(buf); } #define KEY_DIRECTION(btn) (\ (btn) == CURSOR_DOWN ? D : (btn) == CURSOR_UP ? U :\ (btn) == CURSOR_LEFT ? L : R) static char *interpret_move(const game_state *state, game_ui *ui, const game_drawstate *ds, int x, int y, int button) { int w = state->shared->w, h = state->shared->h /*, sz = state->shared->sz */; int gx = FROMCOORD(x), gy = FROMCOORD(y), i; int release = FALSE; char tmpbuf[80]; int shift = button & MOD_SHFT, control = button & MOD_CTRL; button &= ~MOD_MASK; if (IS_MOUSE_DOWN(button)) { ui->cursor_active = FALSE; if (!INGRID(state, gx, gy)) { ui->ndragcoords = -1; return NULL; } ui->clickx = x; ui->clicky = y; ui->dragcoords[0] = gy * w + gx; ui->ndragcoords = 0; /* will be 1 once drag is confirmed */ return ""; } if (button == LEFT_DRAG && ui->ndragcoords >= 0) { update_ui_drag(state, ui, gx, gy); return ""; } if (IS_MOUSE_RELEASE(button)) release = TRUE; if (IS_CURSOR_MOVE(button)) { if (!ui->cursor_active) { ui->cursor_active = TRUE; } else if (control | shift) { char *move; if (ui->ndragcoords > 0) return NULL; ui->ndragcoords = -1; move = mark_in_direction(state, ui->curx, ui->cury, KEY_DIRECTION(button), control, tmpbuf); if (control && !shift && *move) move_cursor(button, &ui->curx, &ui->cury, w, h, FALSE); return move; } else { move_cursor(button, &ui->curx, &ui->cury, w, h, FALSE); if (ui->ndragcoords >= 0) update_ui_drag(state, ui, ui->curx, ui->cury); } return ""; } if (IS_CURSOR_SELECT(button)) { if (!ui->cursor_active) { ui->cursor_active = TRUE; return ""; } else if (button == CURSOR_SELECT) { if (ui->ndragcoords == -1) { ui->ndragcoords = 0; ui->dragcoords[0] = ui->cury * w + ui->curx; ui->clickx = CENTERED_COORD(ui->curx); ui->clicky = CENTERED_COORD(ui->cury); return ""; } else release = TRUE; } else if (button == CURSOR_SELECT2 && ui->ndragcoords >= 0) { ui->ndragcoords = -1; return ""; } } if (button == 27 || button == '\b') { ui->ndragcoords = -1; return ""; } if (release) { if (ui->ndragcoords > 0) { /* End of a drag: process the cached line data. */ int buflen = 0, bufsize = 256, tmplen; char *buf = NULL; const char *sep = ""; int clearing = TRUE; for (i = 0; i < ui->ndragcoords - 1; i++) { int sx, sy, dx, dy, dir, oldstate, newstate; interpret_ui_drag(state, ui, &clearing, i, &sx, &sy, &dx, &dy, &dir, &oldstate, &newstate); if (oldstate != newstate) { if (!buf) buf = snewn(bufsize, char); tmplen = sprintf(tmpbuf, "%sF%d,%d,%d;F%d,%d,%d", sep, dir, sx, sy, F(dir), dx, dy); if (buflen + tmplen >= bufsize) { bufsize = (buflen + tmplen) * 5 / 4 + 256; buf = sresize(buf, bufsize, char); } strcpy(buf + buflen, tmpbuf); buflen += tmplen; sep = ";"; } } ui->ndragcoords = -1; return buf ? buf : ""; } else if (ui->ndragcoords == 0) { /* Click (or tiny drag). Work out which edge we were * closest to. */ int cx, cy; ui->ndragcoords = -1; /* * We process clicks based on the mouse-down location, * because that's more natural for a user to carefully * control than the mouse-up. */ x = ui->clickx; y = ui->clicky; gx = FROMCOORD(x); gy = FROMCOORD(y); cx = CENTERED_COORD(gx); cy = CENTERED_COORD(gy); if (!INGRID(state, gx, gy)) return ""; if (max(abs(x-cx),abs(y-cy)) < TILE_SIZE/4) { /* TODO closer to centre of grid: process as a cell click not an edge click. */ return ""; } else { int direction; if (abs(x-cx) < abs(y-cy)) { /* Closest to top/bottom edge. */ direction = (y < cy) ? U : D; } else { /* Closest to left/right edge. */ direction = (x < cx) ? L : R; } return mark_in_direction(state, gx, gy, direction, (button == LEFT_RELEASE), tmpbuf); } } } if (button == 'H' || button == 'h') return dupstr("H"); return NULL; } static game_state *execute_move(const game_state *state, const char *move) { int w = state->shared->w, h = state->shared->h; char c; int x, y, l, n; game_state *ret = dup_game(state); debug(("move: %s\n", move)); while (*move) { c = *move; if (c == 'S') { ret->used_solve = TRUE; move++; } else if (c == 'L' || c == 'N' || c == 'R' || c == 'F' || c == 'M') { /* 'line' or 'noline' or 'replace' or 'flip' or 'mark' */ move++; if (sscanf(move, "%d,%d,%d%n", &l, &x, &y, &n) != 3) goto badmove; if (!INGRID(state, x, y)) goto badmove; if (l < 0 || l > 15) goto badmove; if (c == 'L') ret->lines[y*w + x] |= (char)l; else if (c == 'N') ret->lines[y*w + x] &= ~((char)l); else if (c == 'R') { ret->lines[y*w + x] = (char)l; ret->marks[y*w + x] &= ~((char)l); /* erase marks too */ } else if (c == 'F') ret->lines[y*w + x] ^= (char)l; else if (c == 'M') ret->marks[y*w + x] ^= (char)l; /* * If we ended up trying to lay a line _over_ a mark, * that's a failed move: interpret_move() should have * ensured we never received a move string like that in * the first place. */ if ((ret->lines[y*w + x] & (char)l) && (ret->marks[y*w + x] & (char)l)) goto badmove; move += n; } else if (strcmp(move, "H") == 0) { pearl_solve(ret->shared->w, ret->shared->h, ret->shared->clues, ret->lines, DIFFCOUNT, TRUE); for (n = 0; n < w*h; n++) ret->marks[n] &= ~ret->lines[n]; /* erase marks too */ move++; } else { goto badmove; } if (*move == ';') move++; else if (*move) goto badmove; } check_completion(ret, TRUE); return ret; badmove: free_game(ret); return NULL; } /* ---------------------------------------------------------------------- * Drawing routines. */ #define FLASH_TIME 0.5F static void game_compute_size(const game_params *params, int tilesize, int *x, int *y) { /* Ick: fake up `ds->tilesize' for macro expansion purposes */ struct { int halfsz; } ads, *ds = &ads; ads.halfsz = (tilesize-1)/2; *x = (params->w) * TILE_SIZE + 2 * BORDER; *y = (params->h) * TILE_SIZE + 2 * BORDER; } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { ds->halfsz = (tilesize-1)/2; } static float *game_colours(frontend *fe, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float); int i; game_mkhighlight(fe, ret, COL_BACKGROUND, COL_HIGHLIGHT, COL_LOWLIGHT); for (i = 0; i < 3; i++) { ret[COL_BLACK * 3 + i] = 0.0F; ret[COL_WHITE * 3 + i] = 1.0F; ret[COL_GRID * 3 + i] = 0.4F; } ret[COL_ERROR * 3 + 0] = 1.0F; ret[COL_ERROR * 3 + 1] = 0.0F; ret[COL_ERROR * 3 + 2] = 0.0F; ret[COL_DRAGON * 3 + 0] = 0.0F; ret[COL_DRAGON * 3 + 1] = 0.0F; ret[COL_DRAGON * 3 + 2] = 1.0F; ret[COL_DRAGOFF * 3 + 0] = 0.8F; ret[COL_DRAGOFF * 3 + 1] = 0.8F; ret[COL_DRAGOFF * 3 + 2] = 1.0F; ret[COL_FLASH * 3 + 0] = 1.0F; ret[COL_FLASH * 3 + 1] = 1.0F; ret[COL_FLASH * 3 + 2] = 1.0F; *ncolours = NCOLOURS; return ret; } static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { struct game_drawstate *ds = snew(struct game_drawstate); int i; ds->halfsz = 0; ds->started = FALSE; ds->w = state->shared->w; ds->h = state->shared->h; ds->sz = state->shared->sz; ds->lflags = snewn(ds->sz, unsigned int); for (i = 0; i < ds->sz; i++) ds->lflags[i] = 0; ds->draglines = snewn(ds->sz, char); return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { sfree(ds->draglines); sfree(ds->lflags); sfree(ds); } static void draw_lines_specific(drawing *dr, game_drawstate *ds, int x, int y, unsigned int lflags, unsigned int shift, int c) { int ox = COORD(x), oy = COORD(y); int t2 = HALFSZ, t16 = HALFSZ/4; int cx = ox + t2, cy = oy + t2; int d; /* Draw each of the four directions, where laid (or error, or drag, etc.) */ for (d = 1; d < 16; d *= 2) { int xoff = t2 * DX(d), yoff = t2 * DY(d); int xnudge = abs(t16 * DX(C(d))), ynudge = abs(t16 * DY(C(d))); if ((lflags >> shift) & d) { int lx = cx + ((xoff < 0) ? xoff : 0) - xnudge; int ly = cy + ((yoff < 0) ? yoff : 0) - ynudge; if (c == COL_DRAGOFF && !(lflags & d)) continue; if (c == COL_DRAGON && (lflags & d)) continue; draw_rect(dr, lx, ly, abs(xoff)+2*xnudge+1, abs(yoff)+2*ynudge+1, c); /* end cap */ draw_rect(dr, cx - t16, cy - t16, 2*t16+1, 2*t16+1, c); } } } static void draw_square(drawing *dr, game_drawstate *ds, const game_ui *ui, int x, int y, unsigned int lflags, char clue) { int ox = COORD(x), oy = COORD(y); int t2 = HALFSZ, t16 = HALFSZ/4; int cx = ox + t2, cy = oy + t2; int d; assert(dr); /* Clip to the grid square. */ clip(dr, ox, oy, TILE_SIZE, TILE_SIZE); /* Clear the square. */ draw_rect(dr, ox, oy, TILE_SIZE, TILE_SIZE, (lflags & DS_CURSOR) ? COL_CURSOR_BACKGROUND : COL_BACKGROUND); if (get_gui_style() == GUI_LOOPY) { /* Draw small dot, underneath any lines. */ draw_circle(dr, cx, cy, t16, COL_GRID, COL_GRID); } else { /* Draw outline of grid square */ draw_line(dr, ox, oy, COORD(x+1), oy, COL_GRID); draw_line(dr, ox, oy, ox, COORD(y+1), COL_GRID); } /* Draw grid: either thin gridlines, or no-line marks. * We draw these first because the thick laid lines should be on top. */ for (d = 1; d < 16; d *= 2) { int xoff = t2 * DX(d), yoff = t2 * DY(d); if ((x == 0 && d == L) || (y == 0 && d == U) || (x == ds->w-1 && d == R) || (y == ds->h-1 && d == D)) continue; /* no gridlines out to the border. */ if ((lflags >> DS_MSHIFT) & d) { /* either a no-line mark ... */ int mx = cx + xoff, my = cy + yoff, msz = t16; draw_line(dr, mx-msz, my-msz, mx+msz, my+msz, COL_BLACK); draw_line(dr, mx-msz, my+msz, mx+msz, my-msz, COL_BLACK); } else { if (get_gui_style() == GUI_LOOPY) { /* draw grid lines connecting centre of cells */ draw_line(dr, cx, cy, cx+xoff, cy+yoff, COL_GRID); } } } /* Draw each of the four directions, where laid (or error, or drag, etc.) * Order is important here, specifically for the eventual colours of the * exposed end caps. */ draw_lines_specific(dr, ds, x, y, lflags, 0, (lflags & DS_FLASH ? COL_FLASH : COL_BLACK)); draw_lines_specific(dr, ds, x, y, lflags, DS_ESHIFT, COL_ERROR); draw_lines_specific(dr, ds, x, y, lflags, DS_DSHIFT, COL_DRAGOFF); draw_lines_specific(dr, ds, x, y, lflags, DS_DSHIFT, COL_DRAGON); /* Draw a clue, if present */ if (clue != NOCLUE) { int c = (lflags & DS_FLASH) ? COL_FLASH : (clue == STRAIGHT) ? COL_WHITE : COL_BLACK; if (lflags & DS_ERROR_CLUE) /* draw a bigger 'error' clue circle. */ draw_circle(dr, cx, cy, TILE_SIZE*3/8, COL_ERROR, COL_ERROR); draw_circle(dr, cx, cy, TILE_SIZE/4, c, COL_BLACK); } unclip(dr); draw_update(dr, ox, oy, TILE_SIZE, TILE_SIZE); } static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float animtime, float flashtime) { int w = state->shared->w, h = state->shared->h, sz = state->shared->sz; int x, y, force = 0, flashing = 0; if (!ds->started) { /* * The initial contents of the window are not guaranteed and * can vary with front ends. To be on the safe side, all games * should start by drawing a big background-colour rectangle * covering the whole window. */ draw_rect(dr, 0, 0, w*TILE_SIZE + 2*BORDER, h*TILE_SIZE + 2*BORDER, COL_BACKGROUND); if (get_gui_style() == GUI_MASYU) { /* * Smaller black rectangle which is the main grid. */ draw_rect(dr, BORDER - BORDER_WIDTH, BORDER - BORDER_WIDTH, w*TILE_SIZE + 2*BORDER_WIDTH + 1, h*TILE_SIZE + 2*BORDER_WIDTH + 1, COL_GRID); } draw_update(dr, 0, 0, w*TILE_SIZE + 2*BORDER, h*TILE_SIZE + 2*BORDER); ds->started = TRUE; force = 1; } if (flashtime > 0 && (flashtime <= FLASH_TIME/3 || flashtime >= FLASH_TIME*2/3)) flashing = DS_FLASH; memset(ds->draglines, 0, sz); if (ui->ndragcoords > 0) { int i, clearing = TRUE; for (i = 0; i < ui->ndragcoords - 1; i++) { int sx, sy, dx, dy, dir, oldstate, newstate; interpret_ui_drag(state, ui, &clearing, i, &sx, &sy, &dx, &dy, &dir, &oldstate, &newstate); ds->draglines[sy*w+sx] ^= (oldstate ^ newstate); ds->draglines[dy*w+dx] ^= (F(oldstate) ^ F(newstate)); } } for (x = 0; x < w; x++) { for (y = 0; y < h; y++) { unsigned int f = (unsigned int)state->lines[y*w+x]; unsigned int eline = (unsigned int)(state->errors[y*w+x] & (R|U|L|D)); f |= eline << DS_ESHIFT; f |= ((unsigned int)ds->draglines[y*w+x]) << DS_DSHIFT; f |= ((unsigned int)state->marks[y*w+x]) << DS_MSHIFT; if (state->errors[y*w+x] & ERROR_CLUE) f |= DS_ERROR_CLUE; f |= flashing; if (ui->cursor_active && x == ui->curx && y == ui->cury) f |= DS_CURSOR; if (f != ds->lflags[y*w+x] || force) { ds->lflags[y*w+x] = f; draw_square(dr, ds, ui, x, y, f, state->shared->clues[y*w+x]); } } } } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return 0.0F; } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { if (!oldstate->completed && newstate->completed && !oldstate->used_solve && !newstate->used_solve) return FLASH_TIME; else return 0.0F; } static int game_status(const game_state *state) { return state->completed ? +1 : 0; } static int game_timing_state(const game_state *state, game_ui *ui) { return TRUE; } static void game_print_size(const game_params *params, float *x, float *y) { int pw, ph; /* * I'll use 6mm squares by default. */ game_compute_size(params, 600, &pw, &ph); *x = pw / 100.0F; *y = ph / 100.0F; } static void game_print(drawing *dr, const game_state *state, int tilesize) { int w = state->shared->w, h = state->shared->h, x, y; int black = print_mono_colour(dr, 0); int white = print_mono_colour(dr, 1); /* No GUI_LOOPY here: only use the familiar masyu style. */ /* Ick: fake up `ds->tilesize' for macro expansion purposes */ game_drawstate *ds = game_new_drawstate(dr, state); game_set_size(dr, ds, NULL, tilesize); /* Draw grid outlines (black). */ for (x = 0; x <= w; x++) draw_line(dr, COORD(x), COORD(0), COORD(x), COORD(h), black); for (y = 0; y <= h; y++) draw_line(dr, COORD(0), COORD(y), COORD(w), COORD(y), black); for (x = 0; x < w; x++) { for (y = 0; y < h; y++) { int cx = COORD(x) + HALFSZ, cy = COORD(y) + HALFSZ; int clue = state->shared->clues[y*w+x]; draw_lines_specific(dr, ds, x, y, state->lines[y*w+x], 0, black); if (clue != NOCLUE) { int c = (clue == CORNER) ? black : white; draw_circle(dr, cx, cy, TILE_SIZE/4, c, black); } } } game_free_drawstate(dr, ds); } #ifdef COMBINED #define thegame pearl #endif const struct game thegame = { "Pearl", "games.pearl", "pearl", default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, TRUE, solve_game, TRUE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, PREFERRED_TILE_SIZE, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, TRUE, FALSE, game_print_size, game_print, FALSE, /* wants_statusbar */ FALSE, game_timing_state, 0, /* flags */ }; #ifdef STANDALONE_SOLVER #include #include const char *quis = NULL; static void usage(FILE *out) { fprintf(out, "usage: %s \n", quis); } static void pnum(int n, int ntot, const char *desc) { printf("%2.1f%% (%d) %s", (double)n*100.0 / (double)ntot, n, desc); } static void start_soak(game_params *p, random_state *rs, int nsecs) { time_t tt_start, tt_now, tt_last; int n = 0, nsolved = 0, nimpossible = 0, ret; char *grid, *clues; tt_start = tt_last = time(NULL); /* Currently this generates puzzles of any difficulty (trying to solve it * on the maximum difficulty level and not checking it's not too easy). */ printf("Soak-testing a %dx%d grid (any difficulty)", p->w, p->h); if (nsecs > 0) printf(" for %d seconds", nsecs); printf(".\n"); p->nosolve = TRUE; grid = snewn(p->w*p->h, char); clues = snewn(p->w*p->h, char); while (1) { n += new_clues(p, rs, clues, grid); /* should be 1, with nosolve */ ret = pearl_solve(p->w, p->h, clues, grid, DIFF_TRICKY, FALSE); if (ret <= 0) nimpossible++; if (ret == 1) nsolved++; tt_now = time(NULL); if (tt_now > tt_last) { tt_last = tt_now; printf("%d total, %3.1f/s, ", n, (double)n / ((double)tt_now - tt_start)); pnum(nsolved, n, "solved"); printf(", "); printf("%3.1f/s", (double)nsolved / ((double)tt_now - tt_start)); if (nimpossible > 0) pnum(nimpossible, n, "impossible"); printf("\n"); } if (nsecs > 0 && (tt_now - tt_start) > nsecs) { printf("\n"); break; } } sfree(grid); sfree(clues); } int main(int argc, const char *argv[]) { game_params *p = NULL; random_state *rs = NULL; time_t seed = time(NULL); char *id = NULL, *err; setvbuf(stdout, NULL, _IONBF, 0); quis = argv[0]; while (--argc > 0) { char *p = (char*)(*++argv); if (!strcmp(p, "-e") || !strcmp(p, "--seed")) { seed = atoi(*++argv); argc--; } else if (*p == '-') { fprintf(stderr, "%s: unrecognised option `%s'\n", argv[0], p); usage(stderr); exit(1); } else { id = p; } } rs = random_new((void*)&seed, sizeof(time_t)); p = default_params(); if (id) { if (strchr(id, ':')) { fprintf(stderr, "soak takes params only.\n"); goto done; } decode_params(p, id); err = validate_params(p, 1); if (err) { fprintf(stderr, "%s: %s", argv[0], err); goto done; } start_soak(p, rs, 0); /* run forever */ } else { int i; for (i = 5; i <= 12; i++) { p->w = p->h = i; start_soak(p, rs, 5); } } done: free_params(p); random_free(rs); return 0; } #endif /* vim: set shiftwidth=4 tabstop=8: */ puzzles-20170606.272beef/pattern.c0000644000175000017500000020044613115373615015520 0ustar simonsimon/* * pattern.c: the pattern-reconstruction game known as `nonograms'. */ #include #include #include #include #include #include #include "puzzles.h" enum { COL_BACKGROUND, COL_EMPTY, COL_FULL, COL_TEXT, COL_UNKNOWN, COL_GRID, COL_CURSOR, COL_ERROR, NCOLOURS }; #define PREFERRED_TILE_SIZE 24 #define TILE_SIZE (ds->tilesize) #define BORDER (3 * TILE_SIZE / 4) #define TLBORDER(d) ( (d) / 5 + 2 ) #define GUTTER (TILE_SIZE / 2) #define FROMCOORD(d, x) \ ( ((x) - (BORDER + GUTTER + TILE_SIZE * TLBORDER(d))) / TILE_SIZE ) #define SIZE(d) (2*BORDER + GUTTER + TILE_SIZE * (TLBORDER(d) + (d))) #define GETTILESIZE(d, w) ((double)w / (2.0 + (double)TLBORDER(d) + (double)(d))) #define TOCOORD(d, x) (BORDER + GUTTER + TILE_SIZE * (TLBORDER(d) + (x))) struct game_params { int w, h; }; #define GRID_UNKNOWN 2 #define GRID_FULL 1 #define GRID_EMPTY 0 typedef struct game_state_common { /* Parts of the game state that don't change during play. */ int w, h; int rowsize; int *rowdata, *rowlen; unsigned char *immutable; int refcount; } game_state_common; struct game_state { game_state_common *common; unsigned char *grid; int completed, cheated; }; #define FLASH_TIME 0.13F static game_params *default_params(void) { game_params *ret = snew(game_params); ret->w = ret->h = 15; return ret; } static const struct game_params pattern_presets[] = { {10, 10}, {15, 15}, {20, 20}, #ifndef SLOW_SYSTEM {25, 25}, {30, 30}, #endif }; static int game_fetch_preset(int i, char **name, game_params **params) { game_params *ret; char str[80]; if (i < 0 || i >= lenof(pattern_presets)) return FALSE; ret = snew(game_params); *ret = pattern_presets[i]; sprintf(str, "%dx%d", ret->w, ret->h); *name = dupstr(str); *params = ret; return TRUE; } static void free_params(game_params *params) { sfree(params); } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } static void decode_params(game_params *ret, char const *string) { char const *p = string; ret->w = atoi(p); while (*p && isdigit((unsigned char)*p)) p++; if (*p == 'x') { p++; ret->h = atoi(p); while (*p && isdigit((unsigned char)*p)) p++; } else { ret->h = ret->w; } } static char *encode_params(const game_params *params, int full) { char ret[400]; int len; len = sprintf(ret, "%dx%d", params->w, params->h); assert(len < lenof(ret)); ret[len] = '\0'; return dupstr(ret); } static config_item *game_configure(const game_params *params) { config_item *ret; char buf[80]; ret = snewn(3, config_item); ret[0].name = "Width"; ret[0].type = C_STRING; sprintf(buf, "%d", params->w); ret[0].sval = dupstr(buf); ret[0].ival = 0; ret[1].name = "Height"; ret[1].type = C_STRING; sprintf(buf, "%d", params->h); ret[1].sval = dupstr(buf); ret[1].ival = 0; ret[2].name = NULL; ret[2].type = C_END; ret[2].sval = NULL; ret[2].ival = 0; return ret; } static game_params *custom_params(const config_item *cfg) { game_params *ret = snew(game_params); ret->w = atoi(cfg[0].sval); ret->h = atoi(cfg[1].sval); return ret; } static char *validate_params(const game_params *params, int full) { if (params->w <= 0 || params->h <= 0) return "Width and height must both be greater than zero"; return NULL; } /* ---------------------------------------------------------------------- * Puzzle generation code. * * For this particular puzzle, it seemed important to me to ensure * a unique solution. I do this the brute-force way, by having a * solver algorithm alongside the generator, and repeatedly * generating a random grid until I find one whose solution is * unique. It turns out that this isn't too onerous on a modern PC * provided you keep grid size below around 30. Any offers of * better algorithms, however, will be very gratefully received. * * Another annoyance of this approach is that it limits the * available puzzles to those solvable by the algorithm I've used. * My algorithm only ever considers a single row or column at any * one time, which means it's incapable of solving the following * difficult example (found by Bella Image around 1995/6, when she * and I were both doing maths degrees): * * 2 1 2 1 * * +--+--+--+--+ * 1 1 | | | | | * +--+--+--+--+ * 2 | | | | | * +--+--+--+--+ * 1 | | | | | * +--+--+--+--+ * 1 | | | | | * +--+--+--+--+ * * Obviously this cannot be solved by a one-row-or-column-at-a-time * algorithm (it would require at least one row or column reading * `2 1', `1 2', `3' or `4' to get started). However, it can be * proved to have a unique solution: if the top left square were * empty, then the only option for the top row would be to fill the * two squares in the 1 columns, which would imply the squares * below those were empty, leaving no place for the 2 in the second * row. Contradiction. Hence the top left square is full, and the * unique solution follows easily from that starting point. * * (The game ID for this puzzle is 4x4:2/1/2/1/1.1/2/1/1 , in case * it's useful to anyone.) */ #ifndef STANDALONE_PICTURE_GENERATOR static int float_compare(const void *av, const void *bv) { const float *a = (const float *)av; const float *b = (const float *)bv; if (*a < *b) return -1; else if (*a > *b) return +1; else return 0; } static void generate(random_state *rs, int w, int h, unsigned char *retgrid) { float *fgrid; float *fgrid2; int step, i, j; float threshold; fgrid = snewn(w*h, float); for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { fgrid[i*w+j] = random_upto(rs, 100000000UL) / 100000000.F; } } /* * The above gives a completely random splattering of black and * white cells. We want to gently bias this in favour of _some_ * reasonably thick areas of white and black, while retaining * some randomness and fine detail. * * So we evolve the starting grid using a cellular automaton. * Currently, I'm doing something very simple indeed, which is * to set each square to the average of the surrounding nine * cells (or the average of fewer, if we're on a corner). */ for (step = 0; step < 1; step++) { fgrid2 = snewn(w*h, float); for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { float sx, xbar; int n, p, q; /* * Compute the average of the surrounding cells. */ n = 0; sx = 0.F; for (p = -1; p <= +1; p++) { for (q = -1; q <= +1; q++) { if (i+p < 0 || i+p >= h || j+q < 0 || j+q >= w) continue; /* * An additional special case not mentioned * above: if a grid dimension is 2xn then * we do not average across that dimension * at all. Otherwise a 2x2 grid would * contain four identical squares. */ if ((h==2 && p!=0) || (w==2 && q!=0)) continue; n++; sx += fgrid[(i+p)*w+(j+q)]; } } xbar = sx / n; fgrid2[i*w+j] = xbar; } } sfree(fgrid); fgrid = fgrid2; } fgrid2 = snewn(w*h, float); memcpy(fgrid2, fgrid, w*h*sizeof(float)); qsort(fgrid2, w*h, sizeof(float), float_compare); threshold = fgrid2[w*h/2]; sfree(fgrid2); for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { retgrid[i*w+j] = (fgrid[i*w+j] >= threshold ? GRID_FULL : GRID_EMPTY); } } sfree(fgrid); } #endif static int compute_rowdata(int *ret, unsigned char *start, int len, int step) { int i, n; n = 0; for (i = 0; i < len; i++) { if (start[i*step] == GRID_FULL) { int runlen = 1; while (i+runlen < len && start[(i+runlen)*step] == GRID_FULL) runlen++; ret[n++] = runlen; i += runlen; } if (i < len && start[i*step] == GRID_UNKNOWN) return -1; } return n; } #define UNKNOWN 0 #define BLOCK 1 #define DOT 2 #define STILL_UNKNOWN 3 #ifdef STANDALONE_SOLVER int verbose = FALSE; #endif static int do_recurse(unsigned char *known, unsigned char *deduced, unsigned char *row, unsigned char *minpos_done, unsigned char *maxpos_done, unsigned char *minpos_ok, unsigned char *maxpos_ok, int *data, int len, int freespace, int ndone, int lowest) { int i, j, k; /* This algorithm basically tries all possible ways the given rows of * black blocks can be laid out in the row/column being examined. * Special care is taken to avoid checking the tail of a row/column * if the same conditions have already been checked during this recursion * The algorithm also takes care to cut its losses as soon as an * invalid (partial) solution is detected. */ if (data[ndone]) { if (lowest >= minpos_done[ndone] && lowest <= maxpos_done[ndone]) { if (lowest >= minpos_ok[ndone] && lowest <= maxpos_ok[ndone]) { for (i=0; i= minpos_ok[ndone] && lowest <= maxpos_ok[ndone]; } else { if (lowest < minpos_done[ndone]) minpos_done[ndone] = lowest; if (lowest > maxpos_done[ndone]) maxpos_done[ndone] = lowest; } for (i=0; i<=freespace; i++) { j = lowest; for (k=0; k maxpos_ok[ndone]) maxpos_ok[ndone] = lowest + i; if (lowest + i > maxpos_done[ndone]) maxpos_done[ndone] = lowest + i; } next_iter: j++; } return lowest >= minpos_ok[ndone] && lowest <= maxpos_ok[ndone]; } else { for (i=lowest; i= 0 && known[i] == DOT; i--) freespace--; if (rowlen == 0) { memset(deduced, DOT, len); } else { do_recurse(known, deduced, row, minpos_done, maxpos_done, minpos_ok, maxpos_ok, data, len, freespace, 0, 0); } done_any = FALSE; for (i=0; i "); for (i = 0; i < len; i++) putchar(start[i*step] == BLOCK ? '#' : start[i*step] == DOT ? '.' : '?'); putchar('\n'); } #endif return done_any; } static int solve_puzzle(const game_state *state, unsigned char *grid, int w, int h, unsigned char *matrix, unsigned char *workspace, unsigned int *changed_h, unsigned int *changed_w, int *rowdata #ifdef STANDALONE_SOLVER , int cluewid #else , int dummy #endif ) { int i, j, ok, max; int max_h, max_w; assert((state!=NULL && state->common->rowdata!=NULL) ^ (grid!=NULL)); max = max(w, h); memset(matrix, 0, w*h); if (state) { for (i=0; icommon->immutable[i]) matrix[i] = state->grid[i]; } } /* For each column, compute how many squares can be deduced * from just the row-data and initial clues. * Later, changed_* will hold how many squares were changed * in every row/column in the previous iteration * Changed_* is used to choose the next rows / cols to re-examine */ for (i=0; icommon->rowdata) { memcpy(rowdata, state->common->rowdata + state->common->rowsize*(w+i), max*sizeof(int)); rowlen = state->common->rowlen[w+i]; } else { rowlen = compute_rowdata(rowdata, grid+i*w, w, 1); } rowdata[rowlen] = 0; if (rowlen == 0) { changed_h[i] = w; } else { for (j=0, freespace=w+1; rowdata[j]; j++) freespace -= rowdata[j] + 1; for (j=0, changed_h[i]=0; rowdata[j]; j++) if (rowdata[j] > freespace) changed_h[i] += rowdata[j] - freespace; } for (j = 0; j < w; j++) if (matrix[i*w+j]) changed_h[i]++; } for (i=0,max_h=0; i max_h) max_h = changed_h[i]; for (i=0; icommon->rowdata) { memcpy(rowdata, state->common->rowdata + state->common->rowsize*i, max*sizeof(int)); rowlen = state->common->rowlen[i]; } else { rowlen = compute_rowdata(rowdata, grid+i, h, w); } rowdata[rowlen] = 0; if (rowlen == 0) { changed_w[i] = h; } else { for (j=0, freespace=h+1; rowdata[j]; j++) freespace -= rowdata[j] + 1; for (j=0, changed_w[i]=0; rowdata[j]; j++) if (rowdata[j] > freespace) changed_w[i] += rowdata[j] - freespace; } for (j = 0; j < h; j++) if (matrix[j*w+i]) changed_w[i]++; } for (i=0,max_w=0; i max_w) max_w = changed_w[i]; /* Solve the puzzle. * Process rows/columns individually. Deductions involving more than one * row and/or column at a time are not supported. * Take care to only process rows/columns which have been changed since they * were previously processed. * Also, prioritize rows/columns which have had the most changes since their * previous processing, as they promise the greatest benefit. * Extremely rectangular grids (e.g. 10x20, 15x40, etc.) are not treated specially. */ do { for (; max_h && max_h >= max_w; max_h--) { for (i=0; i= max_h) { if (state && state->common->rowdata) { memcpy(rowdata, state->common->rowdata + state->common->rowsize*(w+i), max*sizeof(int)); rowdata[state->common->rowlen[w+i]] = 0; } else { rowdata[compute_rowdata(rowdata, grid+i*w, w, 1)] = 0; } do_row(workspace, workspace+max, workspace+2*max, workspace+3*max, workspace+4*max, workspace+5*max, workspace+6*max, matrix+i*w, w, 1, rowdata, changed_w #ifdef STANDALONE_SOLVER , "row", i+1, cluewid #endif ); changed_h[i] = 0; } } for (i=0,max_w=0; i max_w) max_w = changed_w[i]; } for (; max_w && max_w >= max_h; max_w--) { for (i=0; i= max_w) { if (state && state->common->rowdata) { memcpy(rowdata, state->common->rowdata + state->common->rowsize*i, max*sizeof(int)); rowdata[state->common->rowlen[i]] = 0; } else { rowdata[compute_rowdata(rowdata, grid+i, h, w)] = 0; } do_row(workspace, workspace+max, workspace+2*max, workspace+3*max, workspace+4*max, workspace+5*max, workspace+6*max, matrix+i, h, w, rowdata, changed_h #ifdef STANDALONE_SOLVER , "col", i+1, cluewid #endif ); changed_w[i] = 0; } } for (i=0,max_h=0; i max_h) max_h = changed_h[i]; } } while (max_h>0 || max_w>0); ok = TRUE; for (i=0; i 2) { for (i = 0; i < h; i++) { int colours = 0; for (j = 0; j < w; j++) colours |= (grid[i*w+j] == GRID_FULL ? 2 : 1); if (colours != 3) ok = FALSE; } } if (h > 2) { for (j = 0; j < w; j++) { int colours = 0; for (i = 0; i < h; i++) colours |= (grid[i*w+j] == GRID_FULL ? 2 : 1); if (colours != 3) ok = FALSE; } } if (!ok) continue; ok = solve_puzzle(NULL, grid, w, h, matrix, workspace, changed_h, changed_w, rowdata, 0); } while (!ok); sfree(matrix); sfree(workspace); sfree(changed_h); sfree(changed_w); sfree(rowdata); return grid; } #endif #ifdef STANDALONE_PICTURE_GENERATOR unsigned char *picture; #endif static char *new_game_desc(const game_params *params, random_state *rs, char **aux, int interactive) { unsigned char *grid; int i, j, max, rowlen, *rowdata; char intbuf[80], *desc; int desclen, descpos; #ifdef STANDALONE_PICTURE_GENERATOR game_state *state; int *index; #endif max = max(params->w, params->h); #ifdef STANDALONE_PICTURE_GENERATOR /* * Fixed input picture. */ grid = snewn(params->w * params->h, unsigned char); memcpy(grid, picture, params->w * params->h); /* * Now winnow the immutable square set as far as possible. */ state = snew(game_state); state->grid = grid; state->common = snew(game_state_common); state->common->rowdata = NULL; state->common->immutable = snewn(params->w * params->h, unsigned char); memset(state->common->immutable, 1, params->w * params->h); index = snewn(params->w * params->h, int); for (i = 0; i < params->w * params->h; i++) index[i] = i; shuffle(index, params->w * params->h, sizeof(*index), rs); { unsigned char *matrix = snewn(params->w*params->h, unsigned char); unsigned char *workspace = snewn(max*7, unsigned char); unsigned int *changed_h = snewn(max+1, unsigned int); unsigned int *changed_w = snewn(max+1, unsigned int); int *rowdata = snewn(max+1, int); for (i = 0; i < params->w * params->h; i++) { state->common->immutable[index[i]] = 0; if (!solve_puzzle(state, grid, params->w, params->h, matrix, workspace, changed_h, changed_w, rowdata, 0)) state->common->immutable[index[i]] = 1; } sfree(workspace); sfree(changed_h); sfree(changed_w); sfree(rowdata); sfree(matrix); } #else grid = generate_soluble(rs, params->w, params->h); #endif rowdata = snewn(max, int); /* * Save the solved game in aux. */ if (aux) { char *ai = snewn(params->w * params->h + 2, char); /* * String format is exactly the same as a solve move, so we * can just dupstr this in solve_game(). */ ai[0] = 'S'; for (i = 0; i < params->w * params->h; i++) ai[i+1] = grid[i] ? '1' : '0'; ai[params->w * params->h + 1] = '\0'; *aux = ai; } /* * Seed is a slash-separated list of row contents; each row * contents section is a dot-separated list of integers. Row * contents are listed in the order (columns left to right, * then rows top to bottom). * * Simplest way to handle memory allocation is to make two * passes, first computing the seed size and then writing it * out. */ desclen = 0; for (i = 0; i < params->w + params->h; i++) { if (i < params->w) rowlen = compute_rowdata(rowdata, grid+i, params->h, params->w); else rowlen = compute_rowdata(rowdata, grid+(i-params->w)*params->w, params->w, 1); if (rowlen > 0) { for (j = 0; j < rowlen; j++) { desclen += 1 + sprintf(intbuf, "%d", rowdata[j]); } } else { desclen++; } } desc = snewn(desclen, char); descpos = 0; for (i = 0; i < params->w + params->h; i++) { if (i < params->w) rowlen = compute_rowdata(rowdata, grid+i, params->h, params->w); else rowlen = compute_rowdata(rowdata, grid+(i-params->w)*params->w, params->w, 1); if (rowlen > 0) { for (j = 0; j < rowlen; j++) { int len = sprintf(desc+descpos, "%d", rowdata[j]); if (j+1 < rowlen) desc[descpos + len] = '.'; else desc[descpos + len] = '/'; descpos += len+1; } } else { desc[descpos++] = '/'; } } assert(descpos == desclen); assert(desc[desclen-1] == '/'); desc[desclen-1] = '\0'; #ifdef STANDALONE_PICTURE_GENERATOR for (i = 0; i < params->w * params->h; i++) if (state->common->immutable[i]) break; if (i < params->w * params->h) { /* * At least one immutable square, so we need a suffix. */ int run; desc = sresize(desc, desclen + params->w * params->h + 3, char); desc[descpos-1] = ','; run = 0; for (i = 0; i < params->w * params->h; i++) { if (!state->common->immutable[i]) { run++; if (run == 25) { desc[descpos++] = 'z'; run = 0; } } else { desc[descpos++] = run + (grid[i] == GRID_FULL ? 'A' : 'a'); run = 0; } } if (run > 0) desc[descpos++] = run + 'a'; desc[descpos] = '\0'; } sfree(state->common->immutable); sfree(state->common); sfree(state); #endif sfree(rowdata); sfree(grid); return desc; } static char *validate_desc(const game_params *params, const char *desc) { int i, n, rowspace; const char *p; for (i = 0; i < params->w + params->h; i++) { if (i < params->w) rowspace = params->h + 1; else rowspace = params->w + 1; if (*desc && isdigit((unsigned char)*desc)) { do { p = desc; while (*desc && isdigit((unsigned char)*desc)) desc++; n = atoi(p); rowspace -= n+1; if (rowspace < 0) { if (i < params->w) return "at least one column contains more numbers than will fit"; else return "at least one row contains more numbers than will fit"; } } while (*desc++ == '.'); } else { desc++; /* expect a slash immediately */ } if (desc[-1] == '/') { if (i+1 == params->w + params->h) return "too many row/column specifications"; } else if (desc[-1] == '\0' || desc[-1] == ',') { if (i+1 < params->w + params->h) return "too few row/column specifications"; } else return "unrecognised character in game specification"; } if (desc[-1] == ',') { /* * Optional extra piece of game description which fills in * some grid squares as extra clues. */ i = 0; while (i < params->w * params->h) { int c = (unsigned char)*desc++; if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { int len = tolower(c) - 'a'; i += len; if (len < 25 && i < params->w*params->h) i++; if (i > params->w * params->h) { return "too much data in clue-squares section"; } } else if (!c) { return "too little data in clue-squares section"; } else { return "unrecognised character in clue-squares section"; } } if (*desc) { return "too much data in clue-squares section"; } } return NULL; } static game_state *new_game(midend *me, const game_params *params, const char *desc) { int i; const char *p; game_state *state = snew(game_state); state->common = snew(game_state_common); state->common->refcount = 1; state->common->w = params->w; state->common->h = params->h; state->grid = snewn(state->common->w * state->common->h, unsigned char); memset(state->grid, GRID_UNKNOWN, state->common->w * state->common->h); state->common->immutable = snewn(state->common->w * state->common->h, unsigned char); memset(state->common->immutable, 0, state->common->w * state->common->h); state->common->rowsize = max(state->common->w, state->common->h); state->common->rowdata = snewn(state->common->rowsize * (state->common->w + state->common->h), int); state->common->rowlen = snewn(state->common->w + state->common->h, int); state->completed = state->cheated = FALSE; for (i = 0; i < params->w + params->h; i++) { state->common->rowlen[i] = 0; if (*desc && isdigit((unsigned char)*desc)) { do { p = desc; while (*desc && isdigit((unsigned char)*desc)) desc++; state->common->rowdata[state->common->rowsize * i + state->common->rowlen[i]++] = atoi(p); } while (*desc++ == '.'); } else { desc++; /* expect a slash immediately */ } } if (desc[-1] == ',') { /* * Optional extra piece of game description which fills in * some grid squares as extra clues. */ i = 0; while (i < params->w * params->h) { int c = (unsigned char)*desc++; int full = isupper(c), len = tolower(c) - 'a'; i += len; if (len < 25 && i < params->w*params->h) { state->grid[i] = full ? GRID_FULL : GRID_EMPTY; state->common->immutable[i] = TRUE; i++; } } } return state; } static game_state *dup_game(const game_state *state) { game_state *ret = snew(game_state); ret->common = state->common; ret->common->refcount++; ret->grid = snewn(ret->common->w * ret->common->h, unsigned char); memcpy(ret->grid, state->grid, ret->common->w * ret->common->h); ret->completed = state->completed; ret->cheated = state->cheated; return ret; } static void free_game(game_state *state) { if (--state->common->refcount == 0) { sfree(state->common->rowdata); sfree(state->common->rowlen); sfree(state->common->immutable); sfree(state->common); } sfree(state->grid); sfree(state); } static char *solve_game(const game_state *state, const game_state *currstate, const char *ai, char **error) { unsigned char *matrix; int w = state->common->w, h = state->common->h; int i; char *ret; int max, ok; unsigned char *workspace; unsigned int *changed_h, *changed_w; int *rowdata; /* * If we already have the solved state in ai, copy it out. */ if (ai) return dupstr(ai); max = max(w, h); matrix = snewn(w*h, unsigned char); workspace = snewn(max*7, unsigned char); changed_h = snewn(max+1, unsigned int); changed_w = snewn(max+1, unsigned int); rowdata = snewn(max+1, int); ok = solve_puzzle(state, NULL, w, h, matrix, workspace, changed_h, changed_w, rowdata, 0); sfree(workspace); sfree(changed_h); sfree(changed_w); sfree(rowdata); if (!ok) { sfree(matrix); *error = "Solving algorithm cannot complete this puzzle"; return NULL; } ret = snewn(w*h+2, char); ret[0] = 'S'; for (i = 0; i < w*h; i++) { assert(matrix[i] == BLOCK || matrix[i] == DOT); ret[i+1] = (matrix[i] == BLOCK ? '1' : '0'); } ret[w*h+1] = '\0'; sfree(matrix); return ret; } static int game_can_format_as_text_now(const game_params *params) { return TRUE; } static char *game_text_format(const game_state *state) { int w = state->common->w, h = state->common->h, i, j; int left_gap = 0, top_gap = 0, ch = 2, cw = 1, limit = 1; int len, topleft, lw, lh, gw, gh; /* {line,grid}_{width,height} */ char *board, *buf; for (i = 0; i < w; ++i) { top_gap = max(top_gap, state->common->rowlen[i]); for (j = 0; j < state->common->rowlen[i]; ++j) while (state->common->rowdata[i*state->common->rowsize + j] >= limit) { ++cw; limit *= 10; } } for (i = 0; i < h; ++i) { int rowlen = 0, predecessors = FALSE; for (j = 0; j < state->common->rowlen[i+w]; ++j) { int copy = state->common->rowdata[(i+w)*state->common->rowsize + j]; rowlen += predecessors; predecessors = TRUE; do ++rowlen; while (copy /= 10); } left_gap = max(left_gap, rowlen); } cw = max(cw, 3); gw = w*cw + 2; gh = h*ch + 1; lw = gw + left_gap; lh = gh + top_gap; len = lw * lh; topleft = lw * top_gap + left_gap; board = snewn(len + 1, char); sprintf(board, "%*s\n", len - 2, ""); for (i = 0; i < lh; ++i) { board[lw - 1 + i*lw] = '\n'; if (i < top_gap) continue; board[lw - 2 + i*lw] = ((i - top_gap) % ch ? '|' : '+'); } for (i = 0; i < w; ++i) { for (j = 0; j < state->common->rowlen[i]; ++j) { int cell = topleft + i*cw + 1 + lw*(j - state->common->rowlen[i]); int nch = sprintf(board + cell, "%*d", cw - 1, state->common->rowdata[i*state->common->rowsize + j]); board[cell + nch] = ' '; /* de-NUL-ify */ } } buf = snewn(left_gap, char); for (i = 0; i < h; ++i) { char *p = buf, *start = board + top_gap*lw + left_gap + (i*ch+1)*lw; for (j = 0; j < state->common->rowlen[i+w]; ++j) { if (p > buf) *p++ = ' '; p += sprintf(p, "%d", state->common->rowdata[(i+w)*state->common->rowsize + j]); } memcpy(start - (p - buf), buf, p - buf); } for (i = 0; i < w; ++i) { for (j = 0; j < h; ++j) { int cell = topleft + i*cw + j*ch*lw; int center = cell + cw/2 + (ch/2)*lw; int dx, dy; board[cell] = 0 ? center : '+'; for (dx = 1; dx < cw; ++dx) board[cell + dx] = '-'; for (dy = 1; dy < ch; ++dy) board[cell + dy*lw] = '|'; if (state->grid[i*w+j] == GRID_UNKNOWN) continue; for (dx = 1; dx < cw; ++dx) for (dy = 1; dy < ch; ++dy) board[cell + dx + dy*lw] = state->grid[i*w+j] == GRID_FULL ? '#' : '.'; } } memcpy(board + topleft + h*ch*lw, board + topleft, gw - 1); sfree(buf); return board; } struct game_ui { int dragging; int drag_start_x; int drag_start_y; int drag_end_x; int drag_end_y; int drag, release, state; int cur_x, cur_y, cur_visible; }; static game_ui *new_ui(const game_state *state) { game_ui *ret; ret = snew(game_ui); ret->dragging = FALSE; ret->cur_x = ret->cur_y = ret->cur_visible = 0; return ret; } static void free_ui(game_ui *ui) { sfree(ui); } static char *encode_ui(const game_ui *ui) { return NULL; } static void decode_ui(game_ui *ui, const char *encoding) { } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { } struct game_drawstate { int started; int w, h; int tilesize; unsigned char *visible, *numcolours; int cur_x, cur_y; }; static char *interpret_move(const game_state *state, game_ui *ui, const game_drawstate *ds, int x, int y, int button) { int control = button & MOD_CTRL, shift = button & MOD_SHFT; button &= ~MOD_MASK; x = FROMCOORD(state->common->w, x); y = FROMCOORD(state->common->h, y); if (x >= 0 && x < state->common->w && y >= 0 && y < state->common->h && (button == LEFT_BUTTON || button == RIGHT_BUTTON || button == MIDDLE_BUTTON)) { #ifdef STYLUS_BASED int currstate = state->grid[y * state->common->w + x]; #endif ui->dragging = TRUE; if (button == LEFT_BUTTON) { ui->drag = LEFT_DRAG; ui->release = LEFT_RELEASE; #ifdef STYLUS_BASED ui->state = (currstate + 2) % 3; /* FULL -> EMPTY -> UNKNOWN */ #else ui->state = GRID_FULL; #endif } else if (button == RIGHT_BUTTON) { ui->drag = RIGHT_DRAG; ui->release = RIGHT_RELEASE; #ifdef STYLUS_BASED ui->state = (currstate + 1) % 3; /* EMPTY -> FULL -> UNKNOWN */ #else ui->state = GRID_EMPTY; #endif } else /* if (button == MIDDLE_BUTTON) */ { ui->drag = MIDDLE_DRAG; ui->release = MIDDLE_RELEASE; ui->state = GRID_UNKNOWN; } ui->drag_start_x = ui->drag_end_x = x; ui->drag_start_y = ui->drag_end_y = y; ui->cur_visible = 0; return ""; /* UI activity occurred */ } if (ui->dragging && button == ui->drag) { /* * There doesn't seem much point in allowing a rectangle * drag; people will generally only want to drag a single * horizontal or vertical line, so we make that easy by * snapping to it. * * Exception: if we're _middle_-button dragging to tag * things as UNKNOWN, we may well want to trash an entire * area and start over! */ if (ui->state != GRID_UNKNOWN) { if (abs(x - ui->drag_start_x) > abs(y - ui->drag_start_y)) y = ui->drag_start_y; else x = ui->drag_start_x; } if (x < 0) x = 0; if (y < 0) y = 0; if (x >= state->common->w) x = state->common->w - 1; if (y >= state->common->h) y = state->common->h - 1; ui->drag_end_x = x; ui->drag_end_y = y; return ""; /* UI activity occurred */ } if (ui->dragging && button == ui->release) { int x1, x2, y1, y2, xx, yy; int move_needed = FALSE; x1 = min(ui->drag_start_x, ui->drag_end_x); x2 = max(ui->drag_start_x, ui->drag_end_x); y1 = min(ui->drag_start_y, ui->drag_end_y); y2 = max(ui->drag_start_y, ui->drag_end_y); for (yy = y1; yy <= y2; yy++) for (xx = x1; xx <= x2; xx++) if (!state->common->immutable[yy * state->common->w + xx] && state->grid[yy * state->common->w + xx] != ui->state) move_needed = TRUE; ui->dragging = FALSE; if (move_needed) { char buf[80]; sprintf(buf, "%c%d,%d,%d,%d", (char)(ui->state == GRID_FULL ? 'F' : ui->state == GRID_EMPTY ? 'E' : 'U'), x1, y1, x2-x1+1, y2-y1+1); return dupstr(buf); } else return ""; /* UI activity occurred */ } if (IS_CURSOR_MOVE(button)) { int x = ui->cur_x, y = ui->cur_y, newstate; char buf[80]; move_cursor(button, &ui->cur_x, &ui->cur_y, state->common->w, state->common->h, 0); ui->cur_visible = 1; if (!control && !shift) return ""; newstate = control ? shift ? GRID_UNKNOWN : GRID_FULL : GRID_EMPTY; if (state->grid[y * state->common->w + x] == newstate && state->grid[ui->cur_y * state->common->w + ui->cur_x] == newstate) return ""; sprintf(buf, "%c%d,%d,%d,%d", control ? shift ? 'U' : 'F' : 'E', min(x, ui->cur_x), min(y, ui->cur_y), abs(x - ui->cur_x) + 1, abs(y - ui->cur_y) + 1); return dupstr(buf); } if (IS_CURSOR_SELECT(button)) { int currstate = state->grid[ui->cur_y * state->common->w + ui->cur_x]; int newstate; char buf[80]; if (!ui->cur_visible) { ui->cur_visible = 1; return ""; } if (button == CURSOR_SELECT2) newstate = currstate == GRID_UNKNOWN ? GRID_EMPTY : currstate == GRID_EMPTY ? GRID_FULL : GRID_UNKNOWN; else newstate = currstate == GRID_UNKNOWN ? GRID_FULL : currstate == GRID_FULL ? GRID_EMPTY : GRID_UNKNOWN; sprintf(buf, "%c%d,%d,%d,%d", (char)(newstate == GRID_FULL ? 'F' : newstate == GRID_EMPTY ? 'E' : 'U'), ui->cur_x, ui->cur_y, 1, 1); return dupstr(buf); } return NULL; } static game_state *execute_move(const game_state *from, const char *move) { game_state *ret; int x1, x2, y1, y2, xx, yy; int val; if (move[0] == 'S' && strlen(move) == from->common->w * from->common->h + 1) { int i; ret = dup_game(from); for (i = 0; i < ret->common->w * ret->common->h; i++) ret->grid[i] = (move[i+1] == '1' ? GRID_FULL : GRID_EMPTY); ret->completed = ret->cheated = TRUE; return ret; } else if ((move[0] == 'F' || move[0] == 'E' || move[0] == 'U') && sscanf(move+1, "%d,%d,%d,%d", &x1, &y1, &x2, &y2) == 4 && x1 >= 0 && x2 >= 0 && x1+x2 <= from->common->w && y1 >= 0 && y2 >= 0 && y1+y2 <= from->common->h) { x2 += x1; y2 += y1; val = (move[0] == 'F' ? GRID_FULL : move[0] == 'E' ? GRID_EMPTY : GRID_UNKNOWN); ret = dup_game(from); for (yy = y1; yy < y2; yy++) for (xx = x1; xx < x2; xx++) if (!ret->common->immutable[yy * ret->common->w + xx]) ret->grid[yy * ret->common->w + xx] = val; /* * An actual change, so check to see if we've completed the * game. */ if (!ret->completed) { int *rowdata = snewn(ret->common->rowsize, int); int i, len; ret->completed = TRUE; for (i=0; icommon->w; i++) { len = compute_rowdata(rowdata, ret->grid+i, ret->common->h, ret->common->w); if (len != ret->common->rowlen[i] || memcmp(ret->common->rowdata+i*ret->common->rowsize, rowdata, len * sizeof(int))) { ret->completed = FALSE; break; } } for (i=0; icommon->h; i++) { len = compute_rowdata(rowdata, ret->grid+i*ret->common->w, ret->common->w, 1); if (len != ret->common->rowlen[i+ret->common->w] || memcmp(ret->common->rowdata + (i+ret->common->w)*ret->common->rowsize, rowdata, len * sizeof(int))) { ret->completed = FALSE; break; } } sfree(rowdata); } return ret; } else return NULL; } /* ---------------------------------------------------------------------- * Error-checking during gameplay. */ /* * The difficulty in error-checking Pattern is to make the error check * _weak_ enough. The most obvious way would be to check each row and * column by calling (a modified form of) do_row() to recursively * analyse the row contents against the clue set and see if the * GRID_UNKNOWNs could be filled in in any way that would end up * correct. However, this turns out to be such a strong error check as * to constitute a spoiler in many situations: you make a typo while * trying to fill in one row, and not only does the row light up to * indicate an error, but several columns crossed by the move also * light up and draw your attention to deductions you hadn't even * noticed you could make. * * So instead I restrict error-checking to 'complete runs' within a * row, by which I mean contiguous sequences of GRID_FULL bounded at * both ends by either GRID_EMPTY or the ends of the row. We identify * all the complete runs in a row, and verify that _those_ are * consistent with the row's clue list. Sequences of complete runs * separated by solid GRID_EMPTY are required to match contiguous * sequences in the clue list, whereas if there's at least one * GRID_UNKNOWN between any two complete runs then those two need not * be contiguous in the clue list. * * To simplify the edge cases, I pretend that the clue list for the * row is extended with a 0 at each end, and I also pretend that the * grid data for the row is extended with a GRID_EMPTY and a * zero-length run at each end. This permits the contiguity checker to * handle the fiddly end effects (e.g. if the first contiguous * sequence of complete runs in the grid matches _something_ in the * clue list but not at the beginning, this is allowable iff there's a * GRID_UNKNOWN before the first one) with minimal faff, since the end * effects just drop out as special cases of the normal inter-run * handling (in this code the above case is not 'at the end of the * clue list' at all, but between the implicit initial zero run and * the first nonzero one). * * We must also be a little careful about how we search for a * contiguous sequence of runs. In the clue list (1 1 2 1 2 3), * suppose we see a GRID_UNKNOWN and then a length-1 run. We search * for 1 in the clue list and find it at the very beginning. But now * suppose we find a length-2 run with no GRID_UNKNOWN before it. We * can't naively look at the next clue from the 1 we found, because * that'll be the second 1 and won't match. Instead, we must backtrack * by observing that the 2 we've just found must be contiguous with * the 1 we've already seen, so we search for the sequence (1 2) and * find it starting at the second 1. Now if we see a 3, we must * rethink again and search for (1 2 3). */ struct errcheck_state { /* * rowdata and rowlen point at the clue data for this row in the * game state. */ int *rowdata; int rowlen; /* * rowpos indicates the lowest position where it would be valid to * see our next run length. It might be equal to rowlen, * indicating that the next run would have to be the terminating 0. */ int rowpos; /* * ncontig indicates how many runs we've seen in a contiguous * block. This is taken into account when searching for the next * run we find, unless ncontig is zeroed out first by encountering * a GRID_UNKNOWN. */ int ncontig; }; static int errcheck_found_run(struct errcheck_state *es, int r) { /* Macro to handle the pretence that rowdata has a 0 at each end */ #define ROWDATA(k) ((k)<0 || (k)>=es->rowlen ? 0 : es->rowdata[(k)]) /* * See if we can find this new run length at a position where it * also matches the last 'ncontig' runs we've seen. */ int i, newpos; for (newpos = es->rowpos; newpos <= es->rowlen; newpos++) { if (ROWDATA(newpos) != r) goto notfound; for (i = 1; i <= es->ncontig; i++) if (ROWDATA(newpos - i) != ROWDATA(es->rowpos - i)) goto notfound; es->rowpos = newpos+1; es->ncontig++; return TRUE; notfound:; } return FALSE; #undef ROWDATA } static int check_errors(const game_state *state, int i) { int start, step, end, j; int val, runlen; struct errcheck_state aes, *es = &aes; es->rowlen = state->common->rowlen[i]; es->rowdata = state->common->rowdata + state->common->rowsize * i; /* Pretend that we've already encountered the initial zero run */ es->ncontig = 1; es->rowpos = 0; if (i < state->common->w) { start = i; step = state->common->w; end = start + step * state->common->h; } else { start = (i - state->common->w) * state->common->w; step = 1; end = start + step * state->common->w; } runlen = -1; for (j = start - step; j <= end; j += step) { if (j < start || j == end) val = GRID_EMPTY; else val = state->grid[j]; if (val == GRID_UNKNOWN) { runlen = -1; es->ncontig = 0; } else if (val == GRID_FULL) { if (runlen >= 0) runlen++; } else if (val == GRID_EMPTY) { if (runlen > 0) { if (!errcheck_found_run(es, runlen)) return TRUE; /* error! */ } runlen = 0; } } /* Signal end-of-row by sending errcheck_found_run the terminating * zero run, which will be marked as contiguous with the previous * run if and only if there hasn't been a GRID_UNKNOWN before. */ if (!errcheck_found_run(es, 0)) return TRUE; /* error at the last minute! */ return FALSE; /* no error */ } /* ---------------------------------------------------------------------- * Drawing routines. */ static void game_compute_size(const game_params *params, int tilesize, int *x, int *y) { /* Ick: fake up `ds->tilesize' for macro expansion purposes */ struct { int tilesize; } ads, *ds = &ads; ads.tilesize = tilesize; *x = SIZE(params->w); *y = SIZE(params->h); } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { ds->tilesize = tilesize; } static float *game_colours(frontend *fe, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float); int i; frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]); for (i = 0; i < 3; i++) { ret[COL_GRID * 3 + i] = 0.3F; ret[COL_UNKNOWN * 3 + i] = 0.5F; ret[COL_TEXT * 3 + i] = 0.0F; ret[COL_FULL * 3 + i] = 0.0F; ret[COL_EMPTY * 3 + i] = 1.0F; } ret[COL_CURSOR * 3 + 0] = 1.0F; ret[COL_CURSOR * 3 + 1] = 0.25F; ret[COL_CURSOR * 3 + 2] = 0.25F; ret[COL_ERROR * 3 + 0] = 1.0F; ret[COL_ERROR * 3 + 1] = 0.0F; ret[COL_ERROR * 3 + 2] = 0.0F; *ncolours = NCOLOURS; return ret; } static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { struct game_drawstate *ds = snew(struct game_drawstate); ds->started = FALSE; ds->w = state->common->w; ds->h = state->common->h; ds->visible = snewn(ds->w * ds->h, unsigned char); ds->tilesize = 0; /* not decided yet */ memset(ds->visible, 255, ds->w * ds->h); ds->numcolours = snewn(ds->w + ds->h, unsigned char); memset(ds->numcolours, 255, ds->w + ds->h); ds->cur_x = ds->cur_y = 0; return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { sfree(ds->visible); sfree(ds); } static void grid_square(drawing *dr, game_drawstate *ds, int y, int x, int state, int cur) { int xl, xr, yt, yb, dx, dy, dw, dh; draw_rect(dr, TOCOORD(ds->w, x), TOCOORD(ds->h, y), TILE_SIZE, TILE_SIZE, COL_GRID); xl = (x % 5 == 0 ? 1 : 0); yt = (y % 5 == 0 ? 1 : 0); xr = (x % 5 == 4 || x == ds->w-1 ? 1 : 0); yb = (y % 5 == 4 || y == ds->h-1 ? 1 : 0); dx = TOCOORD(ds->w, x) + 1 + xl; dy = TOCOORD(ds->h, y) + 1 + yt; dw = TILE_SIZE - xl - xr - 1; dh = TILE_SIZE - yt - yb - 1; draw_rect(dr, dx, dy, dw, dh, (state == GRID_FULL ? COL_FULL : state == GRID_EMPTY ? COL_EMPTY : COL_UNKNOWN)); if (cur) { draw_rect_outline(dr, dx, dy, dw, dh, COL_CURSOR); draw_rect_outline(dr, dx+1, dy+1, dw-2, dh-2, COL_CURSOR); } draw_update(dr, TOCOORD(ds->w, x), TOCOORD(ds->h, y), TILE_SIZE, TILE_SIZE); } /* * Draw the numbers for a single row or column. */ static void draw_numbers(drawing *dr, game_drawstate *ds, const game_state *state, int i, int erase, int colour) { int rowlen = state->common->rowlen[i]; int *rowdata = state->common->rowdata + state->common->rowsize * i; int nfit; int j; if (erase) { if (i < state->common->w) { draw_rect(dr, TOCOORD(state->common->w, i), 0, TILE_SIZE, BORDER + TLBORDER(state->common->h) * TILE_SIZE, COL_BACKGROUND); } else { draw_rect(dr, 0, TOCOORD(state->common->h, i - state->common->w), BORDER + TLBORDER(state->common->w) * TILE_SIZE, TILE_SIZE, COL_BACKGROUND); } } /* * Normally I space the numbers out by the same distance as the * tile size. However, if there are more numbers than available * spaces, I have to squash them up a bit. */ if (i < state->common->w) nfit = TLBORDER(state->common->h); else nfit = TLBORDER(state->common->w); nfit = max(rowlen, nfit) - 1; assert(nfit > 0); for (j = 0; j < rowlen; j++) { int x, y; char str[80]; if (i < state->common->w) { x = TOCOORD(state->common->w, i); y = BORDER + TILE_SIZE * (TLBORDER(state->common->h)-1); y -= ((rowlen-j-1)*TILE_SIZE) * (TLBORDER(state->common->h)-1) / nfit; } else { y = TOCOORD(state->common->h, i - state->common->w); x = BORDER + TILE_SIZE * (TLBORDER(state->common->w)-1); x -= ((rowlen-j-1)*TILE_SIZE) * (TLBORDER(state->common->w)-1) / nfit; } sprintf(str, "%d", rowdata[j]); draw_text(dr, x+TILE_SIZE/2, y+TILE_SIZE/2, FONT_VARIABLE, TILE_SIZE/2, ALIGN_HCENTRE | ALIGN_VCENTRE, colour, str); } if (i < state->common->w) { draw_update(dr, TOCOORD(state->common->w, i), 0, TILE_SIZE, BORDER + TLBORDER(state->common->h) * TILE_SIZE); } else { draw_update(dr, 0, TOCOORD(state->common->h, i - state->common->w), BORDER + TLBORDER(state->common->w) * TILE_SIZE, TILE_SIZE); } } static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float animtime, float flashtime) { int i, j; int x1, x2, y1, y2; int cx, cy, cmoved; if (!ds->started) { /* * The initial contents of the window are not guaranteed * and can vary with front ends. To be on the safe side, * all games should start by drawing a big background- * colour rectangle covering the whole window. */ draw_rect(dr, 0, 0, SIZE(ds->w), SIZE(ds->h), COL_BACKGROUND); /* * Draw the grid outline. */ draw_rect(dr, TOCOORD(ds->w, 0) - 1, TOCOORD(ds->h, 0) - 1, ds->w * TILE_SIZE + 3, ds->h * TILE_SIZE + 3, COL_GRID); ds->started = TRUE; draw_update(dr, 0, 0, SIZE(ds->w), SIZE(ds->h)); } if (ui->dragging) { x1 = min(ui->drag_start_x, ui->drag_end_x); x2 = max(ui->drag_start_x, ui->drag_end_x); y1 = min(ui->drag_start_y, ui->drag_end_y); y2 = max(ui->drag_start_y, ui->drag_end_y); } else { x1 = x2 = y1 = y2 = -1; /* placate gcc warnings */ } if (ui->cur_visible) { cx = ui->cur_x; cy = ui->cur_y; } else { cx = cy = -1; } cmoved = (cx != ds->cur_x || cy != ds->cur_y); /* * Now draw any grid squares which have changed since last * redraw. */ for (i = 0; i < ds->h; i++) { for (j = 0; j < ds->w; j++) { int val, cc = 0; /* * Work out what state this square should be drawn in, * taking any current drag operation into account. */ if (ui->dragging && x1 <= j && j <= x2 && y1 <= i && i <= y2 && !state->common->immutable[i * state->common->w + j]) val = ui->state; else val = state->grid[i * state->common->w + j]; if (cmoved) { /* the cursor has moved; if we were the old or * the new cursor position we need to redraw. */ if (j == cx && i == cy) cc = 1; if (j == ds->cur_x && i == ds->cur_y) cc = 1; } /* * Briefly invert everything twice during a completion * flash. */ if (flashtime > 0 && (flashtime <= FLASH_TIME/3 || flashtime >= FLASH_TIME*2/3) && val != GRID_UNKNOWN) val = (GRID_FULL ^ GRID_EMPTY) ^ val; if (ds->visible[i * ds->w + j] != val || cc) { grid_square(dr, ds, i, j, val, (j == cx && i == cy)); ds->visible[i * ds->w + j] = val; } } } ds->cur_x = cx; ds->cur_y = cy; /* * Redraw any numbers which have changed their colour due to error * indication. */ for (i = 0; i < state->common->w + state->common->h; i++) { int colour = check_errors(state, i) ? COL_ERROR : COL_TEXT; if (ds->numcolours[i] != colour) { draw_numbers(dr, ds, state, i, TRUE, colour); ds->numcolours[i] = colour; } } } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return 0.0F; } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { if (!oldstate->completed && newstate->completed && !oldstate->cheated && !newstate->cheated) return FLASH_TIME; return 0.0F; } static int game_status(const game_state *state) { return state->completed ? +1 : 0; } static int game_timing_state(const game_state *state, game_ui *ui) { return TRUE; } static void game_print_size(const game_params *params, float *x, float *y) { int pw, ph; /* * I'll use 5mm squares by default. */ game_compute_size(params, 500, &pw, &ph); *x = pw / 100.0F; *y = ph / 100.0F; } static void game_print(drawing *dr, const game_state *state, int tilesize) { int w = state->common->w, h = state->common->h; int ink = print_mono_colour(dr, 0); int x, y, i; /* Ick: fake up `ds->tilesize' for macro expansion purposes */ game_drawstate ads, *ds = &ads; game_set_size(dr, ds, NULL, tilesize); /* * Border. */ print_line_width(dr, TILE_SIZE / 16); draw_rect_outline(dr, TOCOORD(w, 0), TOCOORD(h, 0), w*TILE_SIZE, h*TILE_SIZE, ink); /* * Grid. */ for (x = 1; x < w; x++) { print_line_width(dr, TILE_SIZE / (x % 5 ? 128 : 24)); draw_line(dr, TOCOORD(w, x), TOCOORD(h, 0), TOCOORD(w, x), TOCOORD(h, h), ink); } for (y = 1; y < h; y++) { print_line_width(dr, TILE_SIZE / (y % 5 ? 128 : 24)); draw_line(dr, TOCOORD(w, 0), TOCOORD(h, y), TOCOORD(w, w), TOCOORD(h, y), ink); } /* * Clues. */ for (i = 0; i < state->common->w + state->common->h; i++) draw_numbers(dr, ds, state, i, FALSE, ink); /* * Solution. */ print_line_width(dr, TILE_SIZE / 128); for (y = 0; y < h; y++) for (x = 0; x < w; x++) { if (state->grid[y*w+x] == GRID_FULL) draw_rect(dr, TOCOORD(w, x), TOCOORD(h, y), TILE_SIZE, TILE_SIZE, ink); else if (state->grid[y*w+x] == GRID_EMPTY) draw_circle(dr, TOCOORD(w, x) + TILE_SIZE/2, TOCOORD(h, y) + TILE_SIZE/2, TILE_SIZE/12, ink, ink); } } #ifdef COMBINED #define thegame pattern #endif const struct game thegame = { "Pattern", "games.pattern", "pattern", default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, TRUE, solve_game, TRUE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, PREFERRED_TILE_SIZE, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, TRUE, FALSE, game_print_size, game_print, FALSE, /* wants_statusbar */ FALSE, game_timing_state, REQUIRE_RBUTTON, /* flags */ }; #ifdef STANDALONE_SOLVER int main(int argc, char **argv) { game_params *p; game_state *s; char *id = NULL, *desc, *err; while (--argc > 0) { char *p = *++argv; if (*p == '-') { if (!strcmp(p, "-v")) { verbose = TRUE; } else { fprintf(stderr, "%s: unrecognised option `%s'\n", argv[0], p); return 1; } } else { id = p; } } if (!id) { fprintf(stderr, "usage: %s \n", argv[0]); return 1; } desc = strchr(id, ':'); if (!desc) { fprintf(stderr, "%s: game id expects a colon in it\n", argv[0]); return 1; } *desc++ = '\0'; p = default_params(); decode_params(p, id); err = validate_desc(p, desc); if (err) { fprintf(stderr, "%s: %s\n", argv[0], err); return 1; } s = new_game(NULL, p, desc); { int w = p->w, h = p->h, i, j, max, cluewid = 0; unsigned char *matrix, *workspace; unsigned int *changed_h, *changed_w; int *rowdata; matrix = snewn(w*h, unsigned char); max = max(w, h); workspace = snewn(max*7, unsigned char); changed_h = snewn(max+1, unsigned int); changed_w = snewn(max+1, unsigned int); rowdata = snewn(max+1, int); if (verbose) { int thiswid; /* * Work out the maximum text width of the clue numbers * in a row or column, so we can print the solver's * working in a nicely lined up way. */ for (i = 0; i < (w+h); i++) { char buf[80]; for (thiswid = -1, j = 0; j < s->common->rowlen[i]; j++) thiswid += sprintf (buf, " %d", s->common->rowdata[s->common->rowsize*i+j]); if (cluewid < thiswid) cluewid = thiswid; } } solve_puzzle(s, NULL, w, h, matrix, workspace, changed_h, changed_w, rowdata, cluewid); for (i = 0; i < h; i++) { for (j = 0; j < w; j++) { int c = (matrix[i*w+j] == UNKNOWN ? '?' : matrix[i*w+j] == BLOCK ? '#' : matrix[i*w+j] == DOT ? '.' : '!'); putchar(c); } printf("\n"); } } return 0; } #endif #ifdef STANDALONE_PICTURE_GENERATOR /* * Main program for the standalone picture generator. To use it, * simply provide it with an XBM-format bitmap file (note XBM, not * XPM) on standard input, and it will output a game ID in return. * For example: * * $ ./patternpicture < calligraphic-A.xbm * 15x15:2/4/2/2/2/3/3/3.1/3.1/3.1/11/14/12/6/1/2/2/3/4/5/1.3/2.3/1.3/2.3/1.4/9/1.1.3/2.2.3/5.4/3.2 * * That looks easy, of course - all the program has done is to count * up the clue numbers! But in fact, it's done more than that: it's * also checked that the result is uniquely soluble from just the * numbers. If it hadn't been, then it would have also left some * filled squares in the playing area as extra clues. * * $ ./patternpicture < cube.xbm * 15x15:10/2.1/1.1.1/1.1.1/1.1.1/1.1.1/1.1.1/1.1.1/1.1.1/1.10/1.1.1/1.1.1/1.1.1/2.1/10/10/1.2/1.1.1/1.1.1/1.1.1/10.1/1.1.1/1.1.1/1.1.1/1.1.1/1.1.1/1.1.1/1.1.1/1.2/10,TNINzzzzGNzw * * This enables a reasonably convenient design workflow for coming up * with pictorial Pattern puzzles which _are_ uniquely soluble without * those inelegant pre-filled squares. Fire up a bitmap editor (X11 * bitmap(1) is good enough), save a trial .xbm, and then test it by * running a command along the lines of * * $ ./pattern $(./patternpicture < test.xbm) * * If the resulting window pops up with some pre-filled squares, then * that tells you which parts of the image are giving rise to * ambiguities, so try making tweaks in those areas, try the test * command again, and see if it helps. Once you have a design for * which the Pattern starting grid comes out empty, there's your game * ID. */ #include int main(int argc, char **argv) { game_params *par; char *params, *desc; random_state *rs; time_t seed = time(NULL); char buf[4096]; int i; int x, y; par = default_params(); if (argc > 1) decode_params(par, argv[1]); /* get difficulty */ par->w = par->h = -1; /* * Now read an XBM file from standard input. This is simple and * hacky and will do very little error detection, so don't feed * it bogus data. */ picture = NULL; x = y = 0; while (fgets(buf, sizeof(buf), stdin)) { buf[strcspn(buf, "\r\n")] = '\0'; if (!strncmp(buf, "#define", 7)) { /* * Lines starting `#define' give the width and height. */ char *num = buf + strlen(buf); char *symend; while (num > buf && isdigit((unsigned char)num[-1])) num--; symend = num; while (symend > buf && isspace((unsigned char)symend[-1])) symend--; if (symend-5 >= buf && !strncmp(symend-5, "width", 5)) par->w = atoi(num); else if (symend-6 >= buf && !strncmp(symend-6, "height", 6)) par->h = atoi(num); } else { /* * Otherwise, break the string up into words and take * any word of the form `0x' plus hex digits to be a * byte. */ char *p, *wordstart; if (!picture) { if (par->w < 0 || par->h < 0) { printf("failed to read width and height\n"); return 1; } picture = snewn(par->w * par->h, unsigned char); for (i = 0; i < par->w * par->h; i++) picture[i] = GRID_UNKNOWN; } p = buf; while (*p) { while (*p && (*p == ',' || isspace((unsigned char)*p))) p++; wordstart = p; while (*p && !(*p == ',' || *p == '}' || isspace((unsigned char)*p))) p++; if (*p) *p++ = '\0'; if (wordstart[0] == '0' && (wordstart[1] == 'x' || wordstart[1] == 'X') && !wordstart[2 + strspn(wordstart+2, "0123456789abcdefABCDEF")]) { unsigned long byte = strtoul(wordstart+2, NULL, 16); for (i = 0; i < 8; i++) { int bit = (byte >> i) & 1; if (y < par->h && x < par->w) picture[y * par->w + x] = bit ? GRID_FULL : GRID_EMPTY; x++; } if (x >= par->w) { x = 0; y++; } } } } } for (i = 0; i < par->w * par->h; i++) if (picture[i] == GRID_UNKNOWN) { fprintf(stderr, "failed to read enough bitmap data\n"); return 1; } rs = random_new((void*)&seed, sizeof(time_t)); desc = new_game_desc(par, rs, NULL, FALSE); params = encode_params(par, FALSE); printf("%s:%s\n", params, desc); sfree(desc); sfree(params); free_params(par); random_free(rs); return 0; } #endif /* vim: set shiftwidth=4 tabstop=8: */ puzzles-20170606.272beef/palisade.c0000644000175000017500000012355613115373615015633 0ustar simonsimon/* -*- indent-tabs-mode: nil; tab-width: 1000 -*- */ /* * palisade.c: Nikoli's `Five Cells' puzzle. * * See http://nikoli.co.jp/en/puzzles/five_cells.html */ /* TODO: * * - better solver: implement the sketched-out deductions * * - improve the victory flash? * - the LINE_NOs look ugly against COL_FLASH. * - white-blink the edges (instead), a la loopy? */ #include #include #include #include #include #include #include "puzzles.h" #define setmem(ptr, byte, len) memset((ptr), (byte), (len) * sizeof (ptr)[0]) #define scopy(dst, src, len) memcpy((dst), (src), (len) * sizeof (dst)[0]) #define dupmem(p, n) memcpy(smalloc(n * sizeof (*p)), p, n * sizeof (*p)) #define snewa(ptr, len) (ptr) = smalloc((len) * sizeof (*ptr)) #define clone(ptr) (dupmem((ptr), 1)) static char *string(int n, const char *fmt, ...) { va_list va; char *ret; int m; va_start(va, fmt); m = vsprintf(snewa(ret, n + 1), fmt, va); va_end(va); if (m > n) fatal("memory corruption"); return ret; } struct game_params { int w, h, k; }; typedef char clue; typedef unsigned char borderflag; typedef struct shared_state { game_params params; clue *clues; int refcount; } shared_state; struct game_state { shared_state *shared; borderflag *borders; /* length w*h */ unsigned int completed: 1; unsigned int cheated: 1; }; #define DEFAULT_PRESET 0 static struct game_params presets[] = { {5, 5, 5}, {8, 6, 6}, {10, 8, 8}, {15, 12, 10} /* I definitely want 5x5n5 since that gives "Five Cells" its name. * But how about the others? By which criteria do I choose? */ }; static game_params *default_params(void) { return clone(&presets[DEFAULT_PRESET]); } static int game_fetch_preset(int i, char **name, game_params **params) { if (i < 0 || i >= lenof(presets)) return FALSE; *params = clone(&presets[i]); *name = string(60, "%d x %d, regions of size %d", presets[i].w, presets[i].h, presets[i].k); return TRUE; } static void free_params(game_params *params) { sfree(params); } static game_params *dup_params(const game_params *params) { return clone(params); } static void decode_params(game_params *params, char const *string) { params->w = params->h = params->k = atoi(string); while (*string && isdigit((unsigned char)*string)) ++string; if (*string == 'x') { params->h = atoi(++string); while (*string && isdigit((unsigned char)*string)) ++string; } if (*string == 'n') params->k = atoi(++string); } static char *encode_params(const game_params *params, int full) { return string(40, "%dx%dn%d", params->w, params->h, params->k); } #define CONFIG(i, nm, ty, iv, sv) \ (ret[i].name = nm, ret[i].type = ty, ret[i].ival = iv, ret[i].sval = sv) static config_item *game_configure(const game_params *params) { config_item *ret = snewn(4, config_item); CONFIG(0, "Width", C_STRING, 0, string(20, "%d", params->w)); CONFIG(1, "Height", C_STRING, 0, string(20, "%d", params->h)); CONFIG(2, "Region size", C_STRING, 0, string(20, "%d", params->k)); CONFIG(3, NULL, C_END, 0, NULL); return ret; } static game_params *custom_params(const config_item *cfg) { game_params *params = snew(game_params); params->w = atoi(cfg[0].sval); params->h = atoi(cfg[1].sval); params->k = atoi(cfg[2].sval); return params; } /* +---+ << The one possible domino (up to symmetry). +---+---+ * | 3 | | 3 | 3 | * | | If two dominos are adjacent as depicted here >> +---+---+ * | 3 | then it's ambiguous whether the edge between | 3 | 3 | * +---+ the dominos is horizontal or vertical. +---+---+ */ static char *validate_params(const game_params *params, int full) { int w = params->w, h = params->h, k = params->k, wh = w * h; if (k < 1) return "Region size must be at least one"; if (w < 1) return "Width must be at least one"; if (h < 1) return "Height must be at least one"; if (wh % k) return "Region size must divide grid area"; if (!full) return NULL; /* succeed partial validation */ /* MAYBE FIXME: we (just?) don't have the UI for winning these. */ if (k == wh) return "Region size must be less than the grid area"; assert (k < wh); /* or wh % k != 0 */ if (k == 2 && w != 1 && h != 1) return "Region size can't be two unless width or height is one"; return NULL; /* succeed full validation */ } /* --- Solver ------------------------------------------------------- */ /* the solver may write at will to these arrays, but shouldn't free them */ /* it's up to the client to dup/free as needed */ typedef struct solver_ctx { const game_params *params; /* also in shared_state */ clue *clues; /* also in shared_state */ borderflag *borders; /* also in game_state */ int *dsf; /* particular to the solver */ } solver_ctx; /* Deductions: * * - If two adjacent clues do not have a border between them, this * gives a lower limit on the size of their region (which is also an * upper limit if both clues are 3). Rule out any non-border which * would make its region either too large or too small. * * - If a clue, k, is adjacent to k borders or (4 - k) non-borders, * the remaining edges incident to the clue are readily decided. * * - If a region has only one other region (e.g. square) to grow into * and it's not of full size yet, grow it into that one region. * * - If two regions are adjacent and their combined size would be too * large, put an edge between them. * * - If a border is adjacent to two non-borders, its last vertex-mate * must also be a border. If a maybe-border is adjacent to three * nonborders, the maybe-border is a non-border. * * - If a clue square is adjacent to several squares belonging to the * same region, and enabling (disabling) those borders would violate * the clue, those borders must be disabled (enabled). * * - If there's a path crossing only non-borders between two squares, * the maybe-border between them is a non-border. * (This is implicitly computed in the dsf representation) */ /* TODO deductions: * * If a vertex is adjacent to a LINE_YES and (4-3)*LINE_NO, at least * one of the last two edges are LINE_YES. If they're adjacent to a * 1, then the other two edges incident to that 1 are LINE_NO. * * For each square: set all as unknown, then for each k-omino and each * way of placing it on that square, if that way is consistent with * the board, mark its edges and interior as possible LINE_YES and * LINE_NO, respectively. When all k-ominos are through, see what * isn't possible and remove those impossibilities from the board. * (Sounds pretty nasty for k > 4 or so.) * * A black-bordered subregion must have a size divisible by k. So, * draw a graph with one node per dsf component and edges between * those dsf components which have adjacent squares. Identify cut * vertices and edges. If a cut-vertex-delimited component contains a * number of squares not divisible by k, cut vertex not included, then * the cut vertex must belong to the component. If it has exactly one * edge _out_ of the component, the line(s) corresponding to that edge * are all LINE_YES (i.e. a BORDER()). * (This sounds complicated, but visually it is rather easy.) * * [Look at loopy and see how the at-least/-most k out of m edges * thing is done. See how it is propagated across multiple squares.] */ #define EMPTY (~0) #define BIT(i) (1 << (i)) #define BORDER(i) BIT(i) #define BORDER_U BORDER(0) #define BORDER_R BORDER(1) #define BORDER_D BORDER(2) #define BORDER_L BORDER(3) #define FLIP(i) ((i) ^ 2) #define BORDER_MASK (BORDER_U|BORDER_R|BORDER_D|BORDER_L) #define DISABLED(border) ((border) << 4) #define UNDISABLED(border) ((border) >> 4) static const int dx[4] = { 0, +1, 0, -1}; static const int dy[4] = {-1, 0, +1, 0}; static const int bitcount[16] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4}; /* bitcount[x & BORDER_MASK] == number of enabled borders */ #define COMPUTE_J (-1) static void connect(solver_ctx *ctx, int i, int j) { dsf_merge(ctx->dsf, i, j); } static int connected(solver_ctx *ctx, int i, int j, int dir) { if (j == COMPUTE_J) j = i + dx[dir] + ctx->params->w*dy[dir]; return dsf_canonify(ctx->dsf, i) == dsf_canonify(ctx->dsf, j); } static void disconnect(solver_ctx *ctx, int i, int j, int dir) { if (j == COMPUTE_J) j = i + dx[dir] + ctx->params->w*dy[dir]; ctx->borders[i] |= BORDER(dir); ctx->borders[j] |= BORDER(FLIP(dir)); } static int disconnected(solver_ctx *ctx, int i, int j, int dir) { assert (j == COMPUTE_J || j == i + dx[dir] + ctx->params->w*dy[dir]); return ctx->borders[i] & BORDER(dir); } static int maybe(solver_ctx *ctx, int i, int j, int dir) { assert (j == COMPUTE_J || j == i + dx[dir] + ctx->params->w*dy[dir]); return !disconnected(ctx, i, j, dir) && !connected(ctx, i, j, dir); /* the ordering is important: disconnected works for invalid * squares (i.e. out of bounds), connected doesn't. */ } static void solver_connected_clues_versus_region_size(solver_ctx *ctx) { int w = ctx->params->w, h = ctx->params->h, wh = w*h, i, dir; /* If i is connected to j and i has borders with p of the * remaining three squares and j with q of the remaining three * squares, then the region has size at least 1+(3-p) + 1+(3-q). * If p = q = 3 then the region has size exactly 2. */ for (i = 0; i < wh; ++i) { if (ctx->clues[i] == EMPTY) continue; for (dir = 0; dir < 4; ++dir) { int j = i + dx[dir] + w*dy[dir]; if (disconnected(ctx, i, j, dir)) continue; if (ctx->clues[j] == EMPTY) continue; if ((8 - ctx->clues[i] - ctx->clues[j] > ctx->params->k) || (ctx->clues[i] == 3 && ctx->clues[j] == 3 && ctx->params->k != 2)) { disconnect(ctx, i, j, dir); /* changed = TRUE, but this is a one-shot... */ } } } } static int solver_number_exhausted(solver_ctx *ctx) { int w = ctx->params->w, h = ctx->params->h, wh = w*h, i, dir, off; int changed = FALSE; for (i = 0; i < wh; ++i) { if (ctx->clues[i] == EMPTY) continue; if (bitcount[(ctx->borders[i] & BORDER_MASK)] == ctx->clues[i]) { for (dir = 0; dir < 4; ++dir) { int j = i + dx[dir] + w*dy[dir]; if (!maybe(ctx, i, j, dir)) continue; connect(ctx, i, j); changed = TRUE; } continue; } for (off = dir = 0; dir < 4; ++dir) { int j = i + dx[dir] + w*dy[dir]; if (!disconnected(ctx, i, j, dir) && connected(ctx, i, j, dir)) ++off; /* ^^^ bounds checking before ^^^^^ */ } if (ctx->clues[i] == 4 - off) for (dir = 0; dir < 4; ++dir) { int j = i + dx[dir] + w*dy[dir]; if (!maybe(ctx, i, j, dir)) continue; disconnect(ctx, i, j, dir); changed = TRUE; } } return changed; } static int solver_not_too_big(solver_ctx *ctx) { int w = ctx->params->w, h = ctx->params->h, wh = w*h, i, dir; int changed = FALSE; for (i = 0; i < wh; ++i) { int size = dsf_size(ctx->dsf, i); for (dir = 0; dir < 4; ++dir) { int j = i + dx[dir] + w*dy[dir]; if (!maybe(ctx, i, j, dir)) continue; if (size + dsf_size(ctx->dsf, j) <= ctx->params->k) continue; disconnect(ctx, i, j, dir); changed = TRUE; } } return changed; } static int solver_not_too_small(solver_ctx *ctx) { int w = ctx->params->w, h = ctx->params->h, wh = w*h, i, dir; int *outs, k = ctx->params->k, ci, changed = FALSE; snewa(outs, wh); setmem(outs, -1, wh); for (i = 0; i < wh; ++i) { ci = dsf_canonify(ctx->dsf, i); if (dsf_size(ctx->dsf, ci) == k) continue; for (dir = 0; dir < 4; ++dir) { int j = i + dx[dir] + w*dy[dir]; if (!maybe(ctx, i, j, dir)) continue; if (outs[ci] == -1) outs[ci] = dsf_canonify(ctx->dsf, j); else if (outs[ci] != dsf_canonify(ctx->dsf, j)) outs[ci] = -2; } } for (i = 0; i < wh; ++i) { int j = outs[i]; if (i != dsf_canonify(ctx->dsf, i)) continue; if (j < 0) continue; connect(ctx, i, j); /* only one place for i to grow */ changed = TRUE; } sfree(outs); return changed; } static int solver_no_dangling_edges(solver_ctx *ctx) { int w = ctx->params->w, h = ctx->params->h, r, c; int changed = FALSE; /* for each vertex */ for (r = 1; r < h; ++r) for (c = 1; c < w; ++c) { int i = r * w + c, j = i - w - 1, noline = 0, dir; int squares[4], e = -1, f = -1, de = -1, df = -1; /* feels hacky: I align these with BORDER_[U0 R1 D2 L3] */ squares[1] = squares[2] = j; squares[0] = squares[3] = i; /* for each edge adjacent to the vertex */ for (dir = 0; dir < 4; ++dir) if (!connected(ctx, squares[dir], COMPUTE_J, dir)) { df = dir; f = squares[df]; if (e != -1) continue; e = f; de = df; } else ++noline; if (4 - noline == 1) { assert (e != -1); disconnect(ctx, e, COMPUTE_J, de); changed = TRUE; continue; } if (4 - noline != 2) continue; assert (e != -1); assert (f != -1); if (ctx->borders[e] & BORDER(de)) { if (!(ctx->borders[f] & BORDER(df))) { disconnect(ctx, f, COMPUTE_J, df); changed = TRUE; } } else if (ctx->borders[f] & BORDER(df)) { disconnect(ctx, e, COMPUTE_J, de); changed = TRUE; } } return changed; } static int solver_equivalent_edges(solver_ctx *ctx) { int w = ctx->params->w, h = ctx->params->h, wh = w*h, i, dirj; int changed = FALSE; /* if a square is adjacent to two connected squares, the two * borders (i,j) and (i,k) are either both on or both off. */ for (i = 0; i < wh; ++i) { int n_on = 0, n_off = 0; if (ctx->clues[i] < 1 || ctx->clues[i] > 3) continue; if (ctx->clues[i] == 2 /* don't need it otherwise */) for (dirj = 0; dirj < 4; ++dirj) { int j = i + dx[dirj] + w*dy[dirj]; if (disconnected(ctx, i, j, dirj)) ++n_on; else if (connected(ctx, i, j, dirj)) ++n_off; } for (dirj = 0; dirj < 4; ++dirj) { int j = i + dx[dirj] + w*dy[dirj], dirk; if (!maybe(ctx, i, j, dirj)) continue; for (dirk = dirj + 1; dirk < 4; ++dirk) { int k = i + dx[dirk] + w*dy[dirk]; if (!maybe(ctx, i, k, dirk)) continue; if (!connected(ctx, j, k, -1)) continue; if (n_on + 2 > ctx->clues[i]) { connect(ctx, i, j); connect(ctx, i, k); changed = TRUE; } else if (n_off + 2 > 4 - ctx->clues[i]) { disconnect(ctx, i, j, dirj); disconnect(ctx, i, k, dirk); changed = TRUE; } } } } return changed; } #define UNVISITED 6 /* build connected components in `dsf', along the lines of `borders'. */ static void dfs_dsf(int i, int w, borderflag *border, int *dsf, int black) { int dir; for (dir = 0; dir < 4; ++dir) { int ii = i + dx[dir] + w*dy[dir], bdir = BORDER(dir); if (black ? (border[i] & bdir) : !(border[i] & DISABLED(bdir))) continue; if (dsf[ii] != UNVISITED) continue; dsf_merge(dsf, i, ii); dfs_dsf(ii, w, border, dsf, black); } } static int is_solved(const game_params *params, clue *clues, borderflag *border) { int w = params->w, h = params->h, wh = w*h, k = params->k; int i, x, y; int *dsf = snew_dsf(wh); assert (dsf[0] == UNVISITED); /* check: UNVISITED and dsf.c match up */ /* * A game is solved if: * * - the borders drawn on the grid divide it into connected * components such that every square is in a component of the * correct size * - the borders also satisfy the clue set */ for (i = 0; i < wh; ++i) { if (dsf[i] == UNVISITED) dfs_dsf(i, params->w, border, dsf, TRUE); if (dsf_size(dsf, i) != k) goto error; if (clues[i] == EMPTY) continue; if (clues[i] != bitcount[border[i] & BORDER_MASK]) goto error; } /* * ... and thirdly: * * - there are no *stray* borders, in that every border is * actually part of the division between two components. * Otherwise you could cheat by finding a subdivision which did * not *exceed* any clue square's counter, and then adding a * few extra edges. */ for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { if (x+1 < w && (border[y*w+x] & BORDER_R) && dsf_canonify(dsf, y*w+x) == dsf_canonify(dsf, y*w+(x+1))) goto error; if (y+1 < h && (border[y*w+x] & BORDER_D) && dsf_canonify(dsf, y*w+x) == dsf_canonify(dsf, (y+1)*w+x)) goto error; } } sfree(dsf); return TRUE; error: sfree(dsf); return FALSE; } static int solver(const game_params *params, clue *clues, borderflag *borders) { int w = params->w, h = params->h, wh = w*h, changed; solver_ctx ctx; ctx.params = params; ctx.clues = clues; ctx.borders = borders; ctx.dsf = snew_dsf(wh); solver_connected_clues_versus_region_size(&ctx); /* idempotent */ do { changed = FALSE; changed |= solver_number_exhausted(&ctx); changed |= solver_not_too_big(&ctx); changed |= solver_not_too_small(&ctx); changed |= solver_no_dangling_edges(&ctx); changed |= solver_equivalent_edges(&ctx); } while (changed); sfree(ctx.dsf); return is_solved(params, clues, borders); } /* --- Generator ---------------------------------------------------- */ static void init_borders(int w, int h, borderflag *borders) { int r, c; setmem(borders, 0, w*h); for (c = 0; c < w; ++c) { borders[c] |= BORDER_U; borders[w*h-1 - c] |= BORDER_D; } for (r = 0; r < h; ++r) { borders[r*w] |= BORDER_L; borders[w*h-1 - r*w] |= BORDER_R; } } #define OUT_OF_BOUNDS(x, y, w, h) \ ((x) < 0 || (x) >= (w) || (y) < 0 || (y) >= (h)) #define xshuffle(ptr, len, rs) shuffle((ptr), (len), sizeof (ptr)[0], (rs)) static char *new_game_desc(const game_params *params, random_state *rs, char **aux, int interactive) { int w = params->w, h = params->h, wh = w*h, k = params->k; clue *numbers = snewn(wh + 1, clue), *p; borderflag *rim = snewn(wh, borderflag); borderflag *scratch_borders = snewn(wh, borderflag); char *soln = snewa(*aux, wh + 2); int *shuf = snewn(wh, int); int *dsf = NULL, i, r, c; int attempts = 0; for (i = 0; i < wh; ++i) shuf[i] = i; xshuffle(shuf, wh, rs); init_borders(w, h, rim); assert (!('@' & BORDER_MASK)); *soln++ = 'S'; soln[wh] = '\0'; do { ++attempts; setmem(soln, '@', wh); sfree(dsf); dsf = divvy_rectangle(w, h, k, rs); for (r = 0; r < h; ++r) for (c = 0; c < w; ++c) { int i = r * w + c, dir; numbers[i] = 0; for (dir = 0; dir < 4; ++dir) { int rr = r + dy[dir], cc = c + dx[dir], ii = rr * w + cc; if (OUT_OF_BOUNDS(cc, rr, w, h) || dsf_canonify(dsf, i) != dsf_canonify(dsf, ii)) { ++numbers[i]; soln[i] |= BORDER(dir); } } } scopy(scratch_borders, rim, wh); } while (!solver(params, numbers, scratch_borders)); for (i = 0; i < wh; ++i) { int j = shuf[i]; clue copy = numbers[j]; scopy(scratch_borders, rim, wh); numbers[j] = EMPTY; /* strip away unnecssary clues */ if (!solver(params, numbers, scratch_borders)) numbers[j] = copy; } numbers[wh] = '\0'; sfree(scratch_borders); sfree(rim); sfree(shuf); sfree(dsf); p = numbers; r = 0; for (i = 0; i < wh; ++i) { if (numbers[i] != EMPTY) { while (r) { while (r > 26) { *p++ = 'z'; r -= 26; } *p++ = 'a'-1 + r; r = 0; } *p++ = '0' + numbers[i]; } else ++r; } *p++ = '\0'; return sresize(numbers, p - numbers, clue); } static char *validate_desc(const game_params *params, const char *desc) { int w = params->w, h = params->h, wh = w*h, squares = 0; for (/* nop */; *desc; ++desc) { if (islower((unsigned char)*desc)) { squares += *desc - 'a' + 1; } else if (isdigit((unsigned char)*desc)) { if (*desc > '4') { static char buf[] = "Invalid (too large) number: '5'"; assert (isdigit((unsigned char)buf[lenof(buf) - 3])); buf[lenof(buf) - 3] = *desc; /* ... or 6, 7, 8, 9 :-) */ return buf; } ++squares; } else if (isprint((unsigned char)*desc)) { static char buf[] = "Invalid character in data: '?'"; buf[lenof(buf) - 3] = *desc; return buf; } else return "Invalid (unprintable) character in data"; } if (squares > wh) return "Data describes too many squares"; return NULL; } static game_state *new_game(midend *me, const game_params *params, const char *desc) { int w = params->w, h = params->h, wh = w*h, i; game_state *state = snew(game_state); state->shared = snew(shared_state); state->shared->refcount = 1; state->shared->params = *params; /* struct copy */ snewa(state->shared->clues, wh); setmem(state->shared->clues, EMPTY, wh); for (i = 0; *desc; ++desc) { if (isdigit((unsigned char)*desc)) state->shared->clues[i++] = *desc - '0'; else if (isalpha((unsigned char)*desc)) i += *desc - 'a' + 1; } snewa(state->borders, wh); init_borders(w, h, state->borders); state->completed = (params->k == wh); state->cheated = FALSE; return state; } static game_state *dup_game(const game_state *state) { int wh = state->shared->params.w * state->shared->params.h; game_state *ret = snew(game_state); ret->borders = dupmem(state->borders, wh); ret->shared = state->shared; ++ret->shared->refcount; ret->completed = state->completed; ret->cheated = state->cheated; return ret; } static void free_game(game_state *state) { if (--state->shared->refcount == 0) { sfree(state->shared->clues); sfree(state->shared); } sfree(state->borders); sfree(state); } static char *solve_game(const game_state *state, const game_state *currstate, const char *aux, char **error) { int w = state->shared->params.w, h = state->shared->params.h, wh = w*h; borderflag *move; if (aux) return dupstr(aux); snewa(move, wh + 2); move[0] = 'S'; init_borders(w, h, move + 1); move[wh + 1] = '\0'; if (solver(&state->shared->params, state->shared->clues, move + 1)) { int i; for (i = 0; i < wh; i++) move[i+1] |= '@'; /* turn into sensible ASCII */ return (char *) move; } *error = "Sorry, I can't solve this puzzle"; sfree(move); return NULL; { /* compile-time-assert (borderflag is-a-kind-of char). * * depends on zero-size arrays being disallowed. GCC says * ISO C forbids this, pointing to [-Werror=edantic]. Also, * it depends on type-checking of (obviously) dead code. */ borderflag b[sizeof (borderflag) == sizeof (char)]; char c = b[0]; b[0] = c; /* we could at least in principle put this anywhere, but it * seems silly to not put it where the assumption is used. */ } } static int game_can_format_as_text_now(const game_params *params) { return TRUE; } static char *game_text_format(const game_state *state) { int w = state->shared->params.w, h = state->shared->params.h, r, c; int cw = 4, ch = 2, gw = cw*w + 2, gh = ch * h + 1, len = gw * gh; char *board; setmem(snewa(board, len + 1), ' ', len); for (r = 0; r < h; ++r) { for (c = 0; c < w; ++c) { int cell = r*ch*gw + cw*c, center = cell + gw*ch/2 + cw/2; int i = r * w + c, clue = state->shared->clues[i]; if (clue != EMPTY) board[center] = '0' + clue; board[cell] = '+'; if (state->borders[i] & BORDER_U) setmem(board + cell + 1, '-', cw - 1); else if (state->borders[i] & DISABLED(BORDER_U)) board[cell + cw / 2] = 'x'; if (state->borders[i] & BORDER_L) board[cell + gw] = '|'; else if (state->borders[i] & DISABLED(BORDER_L)) board[cell + gw] = 'x'; } for (c = 0; c < ch; ++c) { board[(r*ch + c)*gw + gw - 2] = c ? '|' : '+'; board[(r*ch + c)*gw + gw - 1] = '\n'; } } scopy(board + len - gw, board, gw); board[len] = '\0'; return board; } struct game_ui { int x, y; unsigned int show: 1; }; static game_ui *new_ui(const game_state *state) { game_ui *ui = snew(game_ui); ui->x = ui->y = 0; ui->show = FALSE; return ui; } static void free_ui(game_ui *ui) { sfree(ui); } static char *encode_ui(const game_ui *ui) { return NULL; } static void decode_ui(game_ui *ui, const char *encoding) { assert (encoding == NULL); } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { } typedef unsigned short dsflags; struct game_drawstate { int tilesize; dsflags *grid; }; #define TILESIZE (ds->tilesize) #define MARGIN (ds->tilesize / 2) #define WIDTH (1 + (TILESIZE >= 16) + (TILESIZE >= 32) + (TILESIZE >= 64)) #define CENTER ((ds->tilesize / 2) + WIDTH/2) #define FROMCOORD(x) (((x) - MARGIN) / TILESIZE) enum {MAYBE_LEFT, MAYBE_RIGHT, ON_LEFT, ON_RIGHT, OFF_LEFT, OFF_RIGHT}; static char *interpret_move(const game_state *state, game_ui *ui, const game_drawstate *ds, int x, int y, int button) { int w = state->shared->params.w, h = state->shared->params.h; int control = button & MOD_CTRL, shift = button & MOD_SHFT; button &= ~MOD_MASK; if (button == LEFT_BUTTON || button == RIGHT_BUTTON) { int gx = FROMCOORD(x), gy = FROMCOORD(y), possible = BORDER_MASK; int px = (x - MARGIN) % TILESIZE, py = (y - MARGIN) % TILESIZE; int hx, hy, dir, i; if (OUT_OF_BOUNDS(gx, gy, w, h)) return NULL; ui->x = gx; ui->y = gy; /* find edge closest to click point */ possible &=~ (2*px < TILESIZE ? BORDER_R : BORDER_L); possible &=~ (2*py < TILESIZE ? BORDER_D : BORDER_U); px = min(px, TILESIZE - px); py = min(py, TILESIZE - py); possible &=~ (px < py ? (BORDER_U|BORDER_D) : (BORDER_L|BORDER_R)); for (dir = 0; dir < 4 && BORDER(dir) != possible; ++dir); if (dir == 4) return NULL; /* there's not exactly one such edge */ hx = gx + dx[dir]; hy = gy + dy[dir]; if (OUT_OF_BOUNDS(hx, hy, w, h)) return NULL; ui->show = FALSE; i = gy * w + gx; switch ((button == RIGHT_BUTTON) | ((state->borders[i] & BORDER(dir)) >> dir << 1) | ((state->borders[i] & DISABLED(BORDER(dir))) >> dir >> 2)) { case MAYBE_LEFT: case ON_LEFT: case ON_RIGHT: return string(80, "F%d,%d,%dF%d,%d,%d", gx, gy, BORDER(dir), hx, hy, BORDER(FLIP(dir))); case MAYBE_RIGHT: case OFF_LEFT: case OFF_RIGHT: return string(80, "F%d,%d,%dF%d,%d,%d", gx, gy, DISABLED(BORDER(dir)), hx, hy, DISABLED(BORDER(FLIP(dir)))); } } if (IS_CURSOR_MOVE(button)) { ui->show = TRUE; if (control || shift) { borderflag flag = 0, newflag; int dir, i = ui->y * w + ui->x; x = ui->x; y = ui->y; move_cursor(button, &x, &y, w, h, FALSE); if (OUT_OF_BOUNDS(x, y, w, h)) return NULL; for (dir = 0; dir < 4; ++dir) if (dx[dir] == x - ui->x && dy[dir] == y - ui->y) break; if (dir == 4) return NULL; /* how the ... ?! */ if (control) flag |= BORDER(dir); if (shift) flag |= DISABLED(BORDER(dir)); newflag = state->borders[i] ^ flag; if (newflag & BORDER(dir) && newflag & DISABLED(BORDER(dir))) return NULL; newflag = 0; if (control) newflag |= BORDER(FLIP(dir)); if (shift) newflag |= DISABLED(BORDER(FLIP(dir))); return string(80, "F%d,%d,%dF%d,%d,%d", ui->x, ui->y, flag, x, y, newflag); } else { move_cursor(button, &ui->x, &ui->y, w, h, FALSE); return ""; } } return NULL; } static game_state *execute_move(const game_state *state, const char *move) { int w = state->shared->params.w, h = state->shared->params.h, wh = w * h; game_state *ret = dup_game(state); int nchars, x, y, flag; if (*move == 'S') { int i; ++move; for (i = 0; i < wh && move[i]; ++i) ret->borders[i] = (move[i] & BORDER_MASK) | DISABLED(~move[i] & BORDER_MASK); if (i < wh || move[i]) return NULL; /* leaks `ret', then we die */ ret->cheated = ret->completed = TRUE; return ret; } while (sscanf(move, "F%d,%d,%d%n", &x, &y, &flag, &nchars) == 3 && !OUT_OF_BOUNDS(x, y, w, h)) { move += nchars; ret->borders[y*w + x] ^= flag; } if (*move) return NULL; /* leaks `ret', then we die */ if (!ret->completed) ret->completed = is_solved(&ret->shared->params, ret->shared->clues, ret->borders); return ret; } /* --- Drawing routines --------------------------------------------- */ static void game_compute_size(const game_params *params, int tilesize, int *x, int *y) { *x = (params->w + 1) * tilesize; *y = (params->h + 1) * tilesize; } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { ds->tilesize = tilesize; } enum { COL_BACKGROUND, COL_FLASH, COL_GRID, COL_CLUE = COL_GRID, COL_LINE_YES = COL_GRID, COL_LINE_MAYBE, COL_LINE_NO, COL_ERROR, NCOLOURS }; #define COLOUR(i, r, g, b) \ ((ret[3*(i)+0] = (r)), (ret[3*(i)+1] = (g)), (ret[3*(i)+2] = (b))) #define DARKER 0.9F static float *game_colours(frontend *fe, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float); game_mkhighlight(fe, ret, COL_BACKGROUND, -1, COL_FLASH); COLOUR(COL_GRID, 0.0F, 0.0F, 0.0F); /* black */ COLOUR(COL_ERROR, 1.0F, 0.0F, 0.0F); /* red */ COLOUR(COL_LINE_MAYBE, /* yellow */ ret[COL_BACKGROUND*3 + 0] * DARKER, ret[COL_BACKGROUND*3 + 1] * DARKER, 0.0F); COLOUR(COL_LINE_NO, ret[COL_BACKGROUND*3 + 0] * DARKER, ret[COL_BACKGROUND*3 + 1] * DARKER, ret[COL_BACKGROUND*3 + 2] * DARKER); *ncolours = NCOLOURS; return ret; } #undef COLOUR #define BORDER_ERROR(x) ((x) << 8) #define F_ERROR_U BORDER_ERROR(BORDER_U) /* BIT( 8) */ #define F_ERROR_R BORDER_ERROR(BORDER_R) /* BIT( 9) */ #define F_ERROR_D BORDER_ERROR(BORDER_D) /* BIT(10) */ #define F_ERROR_L BORDER_ERROR(BORDER_L) /* BIT(11) */ #define F_ERROR_CLUE BIT(12) #define F_FLASH BIT(13) #define F_CURSOR BIT(14) static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { struct game_drawstate *ds = snew(struct game_drawstate); ds->tilesize = 0; ds->grid = NULL; return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { sfree(ds->grid); sfree(ds); } #define COLOUR(border) \ (flags & BORDER_ERROR((border)) ? COL_ERROR : \ flags & (border) ? COL_LINE_YES : \ flags & DISABLED((border)) ? COL_LINE_NO : \ COL_LINE_MAYBE) static void draw_tile(drawing *dr, game_drawstate *ds, int r, int c, dsflags flags, int clue) { int x = MARGIN + TILESIZE * c, y = MARGIN + TILESIZE * r; clip(dr, x, y, TILESIZE + WIDTH, TILESIZE + WIDTH); /* { */ draw_rect(dr, x + WIDTH, y + WIDTH, TILESIZE - WIDTH, TILESIZE - WIDTH, (flags & F_FLASH ? COL_FLASH : COL_BACKGROUND)); if (flags & F_CURSOR) draw_rect_corners(dr, x + CENTER, y + CENTER, TILESIZE / 3, COL_GRID); if (clue != EMPTY) { char buf[2]; buf[0] = '0' + clue; buf[1] = '\0'; draw_text(dr, x + CENTER, y + CENTER, FONT_VARIABLE, TILESIZE / 2, ALIGN_VCENTRE | ALIGN_HCENTRE, (flags & F_ERROR_CLUE ? COL_ERROR : COL_CLUE), buf); } #define ts TILESIZE #define w WIDTH draw_rect(dr, x + w, y, ts - w, w, COLOUR(BORDER_U)); draw_rect(dr, x + ts, y + w, w, ts - w, COLOUR(BORDER_R)); draw_rect(dr, x + w, y + ts, ts - w, w, COLOUR(BORDER_D)); draw_rect(dr, x, y + w, w, ts - w, COLOUR(BORDER_L)); #undef ts #undef w unclip(dr); /* } */ draw_update(dr, x, y, TILESIZE + WIDTH, TILESIZE + WIDTH); } #define FLASH_TIME 0.7F static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float animtime, float flashtime) { int w = state->shared->params.w, h = state->shared->params.h, wh = w*h; int r, c, i, flash = ((int) (flashtime * 5 / FLASH_TIME)) % 2; int *black_border_dsf = snew_dsf(wh), *yellow_border_dsf = snew_dsf(wh); int k = state->shared->params.k; if (!ds->grid) { char buf[40]; int bgw = (w+1) * ds->tilesize, bgh = (h+1) * ds->tilesize; draw_rect(dr, 0, 0, bgw, bgh, COL_BACKGROUND); for (r = 0; r <= h; ++r) for (c = 0; c <= w; ++c) draw_rect(dr, MARGIN + TILESIZE * c, MARGIN + TILESIZE * r, WIDTH, WIDTH, COL_GRID); draw_update(dr, 0, 0, bgw, bgh); snewa(ds->grid, wh); setmem(ds->grid, ~0, wh); sprintf(buf, "Region size: %d", state->shared->params.k); status_bar(dr, buf); } for (i = 0; i < wh; ++i) { if (black_border_dsf[i] == UNVISITED) dfs_dsf(i, w, state->borders, black_border_dsf, TRUE); if (yellow_border_dsf[i] == UNVISITED) dfs_dsf(i, w, state->borders, yellow_border_dsf, FALSE); } for (r = 0; r < h; ++r) for (c = 0; c < w; ++c) { int i = r * w + c, clue = state->shared->clues[i], flags, dir; int on = bitcount[state->borders[i] & BORDER_MASK]; int off = bitcount[(state->borders[i] >> 4) & BORDER_MASK]; flags = state->borders[i]; if (flash) flags |= F_FLASH; if (clue != EMPTY && (on > clue || clue > 4 - off)) flags |= F_ERROR_CLUE; if (ui->show && ui->x == c && ui->y == r) flags |= F_CURSOR; /* border errors */ for (dir = 0; dir < 4; ++dir) { int rr = r + dy[dir], cc = c + dx[dir], ii = rr * w + cc; if (OUT_OF_BOUNDS(cc, rr, w, h)) continue; /* we draw each border twice, except the outermost * big border, so we have to check for errors on * both sides of each border.*/ if (/* region too large */ ((dsf_size(yellow_border_dsf, i) > k || dsf_size(yellow_border_dsf, ii) > k) && (dsf_canonify(yellow_border_dsf, i) != dsf_canonify(yellow_border_dsf, ii))) || /* region too small */ ((dsf_size(black_border_dsf, i) < k || dsf_size(black_border_dsf, ii) < k) && dsf_canonify(black_border_dsf, i) != dsf_canonify(black_border_dsf, ii)) || /* dangling borders within a single region */ ((state->borders[i] & BORDER(dir)) && /* we know it's a single region because there's a * path crossing no border from i to ii... */ (dsf_canonify(yellow_border_dsf, i) == dsf_canonify(yellow_border_dsf, ii) || /* or because any such border would be an error */ (dsf_size(black_border_dsf, i) <= k && dsf_canonify(black_border_dsf, i) == dsf_canonify(black_border_dsf, ii))))) flags |= BORDER_ERROR(BORDER(dir)); } if (flags == ds->grid[i]) continue; ds->grid[i] = flags; draw_tile(dr, ds, r, c, ds->grid[i], clue); } sfree(black_border_dsf); sfree(yellow_border_dsf); } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return 0.0F; } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { if (newstate->completed && !newstate->cheated && !oldstate->completed) return FLASH_TIME; return 0.0F; } static int game_status(const game_state *state) { return state->completed ? +1 : 0; } static int game_timing_state(const game_state *state, game_ui *ui) { assert (!"this shouldn't get called"); return 0; /* placate optimiser */ } static void game_print_size(const game_params *params, float *x, float *y) { int pw, ph; game_compute_size(params, 700, &pw, &ph); /* 7mm, like loopy */ *x = pw / 100.0F; *y = ph / 100.0F; } static void print_line(drawing *dr, int x1, int y1, int x2, int y2, int colour, int full) { if (!full) { int i, subdivisions = 8; for (i = 1; i < subdivisions; ++i) { int x = (x1 * (subdivisions - i) + x2 * i) / subdivisions; int y = (y1 * (subdivisions - i) + y2 * i) / subdivisions; draw_circle(dr, x, y, 3, colour, colour); } } else draw_line(dr, x1, y1, x2, y2, colour); } static void game_print(drawing *dr, const game_state *state, int tilesize) { int w = state->shared->params.w, h = state->shared->params.h; int ink = print_mono_colour(dr, 0); game_drawstate for_tilesize_macros, *ds = &for_tilesize_macros; int r, c; ds->tilesize = tilesize; for (r = 0; r < h; ++r) for (c = 0; c < w; ++c) { int x = MARGIN + TILESIZE * c, y = MARGIN + TILESIZE * r; int i = r * w + c, clue = state->shared->clues[i]; if (clue != EMPTY) { char buf[2]; buf[0] = '0' + clue; buf[1] = '\0'; draw_text(dr, x + CENTER, y + CENTER, FONT_VARIABLE, TILESIZE / 2, ALIGN_VCENTRE | ALIGN_HCENTRE, ink, buf); } #define ts TILESIZE #define FULL(DIR) (state->borders[i] & (BORDER_ ## DIR)) print_line(dr, x, y, x + ts, y, ink, FULL(U)); print_line(dr, x + ts, y, x + ts, y + ts, ink, FULL(R)); print_line(dr, x, y + ts, x + ts, y + ts, ink, FULL(D)); print_line(dr, x, y, x, y + ts, ink, FULL(L)); #undef ts #undef FULL } for (r = 1; r < h; ++r) for (c = 1; c < w; ++c) { int j = r * w + c, i = j - 1 - w; int x = MARGIN + TILESIZE * c, y = MARGIN + TILESIZE * r; if (state->borders[i] & (BORDER_D|BORDER_R)) continue; if (state->borders[j] & (BORDER_U|BORDER_L)) continue; draw_circle(dr, x, y, 3, ink, ink); } } #ifdef COMBINED #define thegame palisade #endif const struct game thegame = { "Palisade", "games.palisade", "palisade", default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, TRUE, solve_game, TRUE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, 48, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, TRUE, FALSE, game_print_size, game_print, TRUE, /* wants_statusbar */ FALSE, game_timing_state, 0, /* flags */ }; puzzles-20170606.272beef/obfusc.c0000644000175000017500000000573113115373615015324 0ustar simonsimon/* * Stand-alone tool to access the Puzzles obfuscation algorithm. * * To deobfuscate, use "obfusc -d": * * obfusc -d reads binary data from stdin, writes to stdout * obfusc -d works on the given hex string instead of stdin * obfusc -d -h writes a hex string instead of binary to stdout * * To obfuscate, "obfusc -e": * * obfusc -e reads binary from stdin, writes hex to stdout * obfusc -e works on the given hex string instead of stdin * obfusc -e -b writes binary instead of text to stdout * * The default output format is hex for -e and binary for -d * because that's the way obfuscation is generally used in * Puzzles. Either of -b and -h can always be specified to set it * explicitly. * * Data read from standard input is assumed always to be binary; * data provided on the command line is taken to be hex. */ #include #include #include #include #include #include "puzzles.h" int main(int argc, char **argv) { enum { BINARY, DEFAULT, HEX } outputmode = DEFAULT; char *inhex = NULL; unsigned char *data; int datalen; int decode = -1; int doing_opts = TRUE; while (--argc > 0) { char *p = *++argv; if (doing_opts && *p == '-') { if (!strcmp(p, "--")) { doing_opts = 0; continue; } p++; while (*p) { switch (*p) { case 'e': decode = 0; break; case 'd': decode = 1; break; case 'b': outputmode = BINARY; break; case 'h': outputmode = HEX; break; default: fprintf(stderr, "obfusc: unrecognised option '-%c'\n", *p); return 1; } p++; } } else { if (!inhex) { inhex = p; } else { fprintf(stderr, "obfusc: expected at most one argument\n"); return 1; } } } if (decode < 0) { fprintf(stderr, "usage: obfusc < -e | -d > [ -b | -h ] [hex data]\n"); return 0; } if (outputmode == DEFAULT) outputmode = (decode ? BINARY : HEX); if (inhex) { datalen = strlen(inhex) / 2; data = hex2bin(inhex, datalen); } else { int datasize = 4096; datalen = 0; data = snewn(datasize, unsigned char); while (1) { int ret = fread(data + datalen, 1, datasize - datalen, stdin); if (ret < 0) { fprintf(stderr, "obfusc: read: %s\n", strerror(errno)); return 1; } else if (ret == 0) { break; } else { datalen += ret; if (datasize - datalen < 4096) { datasize = datalen * 5 / 4 + 4096; data = sresize(data, datasize, unsigned char); } } } } obfuscate_bitmap(data, datalen * 8, decode); if (outputmode == BINARY) { int ret = fwrite(data, 1, datalen, stdout); if (ret < 0) { fprintf(stderr, "obfusc: write: %s\n", strerror(errno)); return 1; } } else { int i; for (i = 0; i < datalen; i++) printf("%02x", data[i]); printf("\n"); } return 0; } puzzles-20170606.272beef/nullgame.c0000644000175000017500000001452613115373615015651 0ustar simonsimon/* * nullgame.c [FIXME]: Template defining the null game (in which no * moves are permitted and nothing is ever drawn). This file exists * solely as a basis for constructing new game definitions - it * helps to have something which will compile from the word go and * merely doesn't _do_ very much yet. * * Parts labelled FIXME actually want _removing_ (e.g. the dummy * field in each of the required data structures, and this entire * comment itself) when converting this source file into one * describing a real game. */ #include #include #include #include #include #include #include "puzzles.h" enum { COL_BACKGROUND, NCOLOURS }; struct game_params { int FIXME; }; struct game_state { int FIXME; }; static game_params *default_params(void) { game_params *ret = snew(game_params); ret->FIXME = 0; return ret; } static int game_fetch_preset(int i, char **name, game_params **params) { return FALSE; } static void free_params(game_params *params) { sfree(params); } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } static void decode_params(game_params *params, char const *string) { } static char *encode_params(const game_params *params, int full) { return dupstr("FIXME"); } static config_item *game_configure(const game_params *params) { return NULL; } static game_params *custom_params(const config_item *cfg) { return NULL; } static char *validate_params(const game_params *params, int full) { return NULL; } static char *new_game_desc(const game_params *params, random_state *rs, char **aux, int interactive) { return dupstr("FIXME"); } static char *validate_desc(const game_params *params, const char *desc) { return NULL; } static game_state *new_game(midend *me, const game_params *params, const char *desc) { game_state *state = snew(game_state); state->FIXME = 0; return state; } static game_state *dup_game(const game_state *state) { game_state *ret = snew(game_state); ret->FIXME = state->FIXME; return ret; } static void free_game(game_state *state) { sfree(state); } static char *solve_game(const game_state *state, const game_state *currstate, const char *aux, char **error) { return NULL; } static int game_can_format_as_text_now(const game_params *params) { return TRUE; } static char *game_text_format(const game_state *state) { return NULL; } static game_ui *new_ui(const game_state *state) { return NULL; } static void free_ui(game_ui *ui) { } static char *encode_ui(const game_ui *ui) { return NULL; } static void decode_ui(game_ui *ui, const char *encoding) { } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { } struct game_drawstate { int tilesize; int FIXME; }; static char *interpret_move(const game_state *state, game_ui *ui, const game_drawstate *ds, int x, int y, int button) { return NULL; } static game_state *execute_move(const game_state *state, const char *move) { return NULL; } /* ---------------------------------------------------------------------- * Drawing routines. */ static void game_compute_size(const game_params *params, int tilesize, int *x, int *y) { *x = *y = 10 * tilesize; /* FIXME */ } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { ds->tilesize = tilesize; } static float *game_colours(frontend *fe, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float); frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]); *ncolours = NCOLOURS; return ret; } static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { struct game_drawstate *ds = snew(struct game_drawstate); ds->tilesize = 0; ds->FIXME = 0; return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { sfree(ds); } static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float animtime, float flashtime) { /* * The initial contents of the window are not guaranteed and * can vary with front ends. To be on the safe side, all games * should start by drawing a big background-colour rectangle * covering the whole window. */ draw_rect(dr, 0, 0, 10*ds->tilesize, 10*ds->tilesize, COL_BACKGROUND); draw_update(dr, 0, 0, 10*ds->tilesize, 10*ds->tilesize); } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return 0.0F; } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return 0.0F; } static int game_status(const game_state *state) { return 0; } static int game_timing_state(const game_state *state, game_ui *ui) { return TRUE; } static void game_print_size(const game_params *params, float *x, float *y) { } static void game_print(drawing *dr, const game_state *state, int tilesize) { } #ifdef COMBINED #define thegame nullgame #endif const struct game thegame = { "Null Game", NULL, NULL, default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, FALSE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, FALSE, solve_game, FALSE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, 20 /* FIXME */, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, FALSE, FALSE, game_print_size, game_print, FALSE, /* wants_statusbar */ FALSE, game_timing_state, 0, /* flags */ }; puzzles-20170606.272beef/nullfe.c0000644000175000017500000000534013115373615015324 0ustar simonsimon/* * nullfe.c: Null front-end code containing a bunch of boring stub * functions. Used to ensure successful linking when building the * various stand-alone solver binaries. */ #include #include "puzzles.h" void frontend_default_colour(frontend *fe, float *output) {} void draw_text(drawing *dr, int x, int y, int fonttype, int fontsize, int align, int colour, char *text) {} void draw_rect(drawing *dr, int x, int y, int w, int h, int colour) {} void draw_line(drawing *dr, int x1, int y1, int x2, int y2, int colour) {} void draw_thick_line(drawing *dr, float thickness, float x1, float y1, float x2, float y2, int colour) {} void draw_polygon(drawing *dr, int *coords, int npoints, int fillcolour, int outlinecolour) {} void draw_circle(drawing *dr, int cx, int cy, int radius, int fillcolour, int outlinecolour) {} char *text_fallback(drawing *dr, const char *const *strings, int nstrings) { return dupstr(strings[0]); } void clip(drawing *dr, int x, int y, int w, int h) {} void unclip(drawing *dr) {} void start_draw(drawing *dr) {} void draw_update(drawing *dr, int x, int y, int w, int h) {} void end_draw(drawing *dr) {} blitter *blitter_new(drawing *dr, int w, int h) {return NULL;} void blitter_free(drawing *dr, blitter *bl) {} void blitter_save(drawing *dr, blitter *bl, int x, int y) {} void blitter_load(drawing *dr, blitter *bl, int x, int y) {} int print_mono_colour(drawing *dr, int grey) { return 0; } int print_grey_colour(drawing *dr, float grey) { return 0; } int print_hatched_colour(drawing *dr, int hatch) { return 0; } int print_rgb_mono_colour(drawing *dr, float r, float g, float b, int grey) { return 0; } int print_rgb_grey_colour(drawing *dr, float r, float g, float b, float grey) { return 0; } int print_rgb_hatched_colour(drawing *dr, float r, float g, float b, int hatch) { return 0; } void print_line_width(drawing *dr, int width) {} void print_line_dotted(drawing *dr, int dotted) {} void midend_supersede_game_desc(midend *me, char *desc, char *privdesc) {} void status_bar(drawing *dr, char *text) {} struct preset_menu *preset_menu_new(void) {return NULL;} struct preset_menu *preset_menu_add_submenu(struct preset_menu *parent, char *title) {return NULL;} void preset_menu_add_preset(struct preset_menu *parent, char *title, game_params *params) {} void fatal(char *fmt, ...) { va_list ap; fprintf(stderr, "fatal error: "); va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, "\n"); exit(1); } #ifdef DEBUGGING void debug_printf(char *fmt, ...) { va_list ap; va_start(ap, fmt); vfprintf(stdout, fmt, ap); va_end(ap); } #endif puzzles-20170606.272beef/no-icon.c0000644000175000017500000000027713115373615015405 0ustar simonsimon /* * Dummy source file which replaces the files generated in the * `icons' subdirectory, when they're absent. */ const char *const *const xpm_icons[] = { 0 }; const int n_xpm_icons = 0; puzzles-20170606.272beef/netslide.c0000644000175000017500000015650013115373615015653 0ustar simonsimon/* * netslide.c: cross between Net and Sixteen, courtesy of Richard * Boulton. */ #include #include #include #include #include #include #include "puzzles.h" #include "tree234.h" #define MATMUL(xr,yr,m,x,y) do { \ float rx, ry, xx = (x), yy = (y), *mat = (m); \ rx = mat[0] * xx + mat[2] * yy; \ ry = mat[1] * xx + mat[3] * yy; \ (xr) = rx; (yr) = ry; \ } while (0) /* Direction and other bitfields */ #define R 0x01 #define U 0x02 #define L 0x04 #define D 0x08 #define FLASHING 0x10 #define ACTIVE 0x20 /* Corner flags go in the barriers array */ #define RU 0x10 #define UL 0x20 #define LD 0x40 #define DR 0x80 /* Get tile at given coordinate */ #define T(state, x, y) ( (y) * (state)->width + (x) ) /* Rotations: Anticlockwise, Clockwise, Flip, general rotate */ #define A(x) ( (((x) & 0x07) << 1) | (((x) & 0x08) >> 3) ) #define C(x) ( (((x) & 0x0E) >> 1) | (((x) & 0x01) << 3) ) #define F(x) ( (((x) & 0x0C) >> 2) | (((x) & 0x03) << 2) ) #define ROT(x, n) ( ((n)&3) == 0 ? (x) : \ ((n)&3) == 1 ? A(x) : \ ((n)&3) == 2 ? F(x) : C(x) ) /* X and Y displacements */ #define X(x) ( (x) == R ? +1 : (x) == L ? -1 : 0 ) #define Y(x) ( (x) == D ? +1 : (x) == U ? -1 : 0 ) /* Bit count */ #define COUNT(x) ( (((x) & 0x08) >> 3) + (((x) & 0x04) >> 2) + \ (((x) & 0x02) >> 1) + ((x) & 0x01) ) #define PREFERRED_TILE_SIZE 48 #define TILE_SIZE (ds->tilesize) #define BORDER TILE_SIZE #define TILE_BORDER 1 #define WINDOW_OFFSET 0 #define ANIM_TIME 0.13F #define FLASH_FRAME 0.07F enum { COL_BACKGROUND, COL_FLASHING, COL_BORDER, COL_WIRE, COL_ENDPOINT, COL_POWERED, COL_BARRIER, COL_LOWLIGHT, COL_TEXT, NCOLOURS }; struct game_params { int width; int height; int wrapping; float barrier_probability; int movetarget; }; struct game_state { int width, height, cx, cy, wrapping, completed; int used_solve; int move_count, movetarget; /* position (row or col number, starting at 0) of last move. */ int last_move_row, last_move_col; /* direction of last move: +1 or -1 */ int last_move_dir; unsigned char *tiles; unsigned char *barriers; }; #define OFFSET(x2,y2,x1,y1,dir,state) \ ( (x2) = ((x1) + (state)->width + X((dir))) % (state)->width, \ (y2) = ((y1) + (state)->height + Y((dir))) % (state)->height) #define index(state, a, x, y) ( a[(y) * (state)->width + (x)] ) #define tile(state, x, y) index(state, (state)->tiles, x, y) #define barrier(state, x, y) index(state, (state)->barriers, x, y) struct xyd { int x, y, direction; }; static int xyd_cmp(void *av, void *bv) { struct xyd *a = (struct xyd *)av; struct xyd *b = (struct xyd *)bv; if (a->x < b->x) return -1; if (a->x > b->x) return +1; if (a->y < b->y) return -1; if (a->y > b->y) return +1; if (a->direction < b->direction) return -1; if (a->direction > b->direction) return +1; return 0; } static struct xyd *new_xyd(int x, int y, int direction) { struct xyd *xyd = snew(struct xyd); xyd->x = x; xyd->y = y; xyd->direction = direction; return xyd; } static void slide_col(game_state *state, int dir, int col); static void slide_col_int(int w, int h, unsigned char *tiles, int dir, int col); static void slide_row(game_state *state, int dir, int row); static void slide_row_int(int w, int h, unsigned char *tiles, int dir, int row); /* ---------------------------------------------------------------------- * Manage game parameters. */ static game_params *default_params(void) { game_params *ret = snew(game_params); ret->width = 3; ret->height = 3; ret->wrapping = FALSE; ret->barrier_probability = 1.0; ret->movetarget = 0; return ret; } static const struct { int x, y, wrap, bprob; const char* desc; } netslide_presets[] = { {3, 3, FALSE, 1, " easy"}, {3, 3, FALSE, 0, " medium"}, {3, 3, TRUE, 0, " hard"}, {4, 4, FALSE, 1, " easy"}, {4, 4, FALSE, 0, " medium"}, {4, 4, TRUE, 0, " hard"}, {5, 5, FALSE, 1, " easy"}, {5, 5, FALSE, 0, " medium"}, {5, 5, TRUE, 0, " hard"}, }; static int game_fetch_preset(int i, char **name, game_params **params) { game_params *ret; char str[80]; if (i < 0 || i >= lenof(netslide_presets)) return FALSE; ret = snew(game_params); ret->width = netslide_presets[i].x; ret->height = netslide_presets[i].y; ret->wrapping = netslide_presets[i].wrap; ret->barrier_probability = (float)netslide_presets[i].bprob; ret->movetarget = 0; sprintf(str, "%dx%d%s", ret->width, ret->height, netslide_presets[i].desc); *name = dupstr(str); *params = ret; return TRUE; } static void free_params(game_params *params) { sfree(params); } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } static void decode_params(game_params *ret, char const *string) { char const *p = string; ret->wrapping = FALSE; ret->barrier_probability = 0.0; ret->movetarget = 0; ret->width = atoi(p); while (*p && isdigit((unsigned char)*p)) p++; if (*p == 'x') { p++; ret->height = atoi(p); while (*p && isdigit((unsigned char)*p)) p++; if ( (ret->wrapping = (*p == 'w')) != 0 ) p++; if (*p == 'b') { ret->barrier_probability = (float)atof(++p); while (*p && (isdigit((unsigned char)*p) || *p == '.')) p++; } if (*p == 'm') { ret->movetarget = atoi(++p); } } else { ret->height = ret->width; } } static char *encode_params(const game_params *params, int full) { char ret[400]; int len; len = sprintf(ret, "%dx%d", params->width, params->height); if (params->wrapping) ret[len++] = 'w'; if (full && params->barrier_probability) len += sprintf(ret+len, "b%g", params->barrier_probability); /* Shuffle limit is part of the limited parameters, because we have to * provide the target move count. */ if (params->movetarget) len += sprintf(ret+len, "m%d", params->movetarget); assert(len < lenof(ret)); ret[len] = '\0'; return dupstr(ret); } static config_item *game_configure(const game_params *params) { config_item *ret; char buf[80]; ret = snewn(6, config_item); ret[0].name = "Width"; ret[0].type = C_STRING; sprintf(buf, "%d", params->width); ret[0].sval = dupstr(buf); ret[0].ival = 0; ret[1].name = "Height"; ret[1].type = C_STRING; sprintf(buf, "%d", params->height); ret[1].sval = dupstr(buf); ret[1].ival = 0; ret[2].name = "Walls wrap around"; ret[2].type = C_BOOLEAN; ret[2].sval = NULL; ret[2].ival = params->wrapping; ret[3].name = "Barrier probability"; ret[3].type = C_STRING; sprintf(buf, "%g", params->barrier_probability); ret[3].sval = dupstr(buf); ret[3].ival = 0; ret[4].name = "Number of shuffling moves"; ret[4].type = C_STRING; sprintf(buf, "%d", params->movetarget); ret[4].sval = dupstr(buf); ret[4].ival = 0; ret[5].name = NULL; ret[5].type = C_END; ret[5].sval = NULL; ret[5].ival = 0; return ret; } static game_params *custom_params(const config_item *cfg) { game_params *ret = snew(game_params); ret->width = atoi(cfg[0].sval); ret->height = atoi(cfg[1].sval); ret->wrapping = cfg[2].ival; ret->barrier_probability = (float)atof(cfg[3].sval); ret->movetarget = atoi(cfg[4].sval); return ret; } static char *validate_params(const game_params *params, int full) { if (params->width <= 1 || params->height <= 1) return "Width and height must both be greater than one"; if (params->barrier_probability < 0) return "Barrier probability may not be negative"; if (params->barrier_probability > 1) return "Barrier probability may not be greater than 1"; return NULL; } /* ---------------------------------------------------------------------- * Randomly select a new game description. */ static char *new_game_desc(const game_params *params, random_state *rs, char **aux, int interactive) { tree234 *possibilities, *barriertree; int w, h, x, y, cx, cy, nbarriers; unsigned char *tiles, *barriers; char *desc, *p; w = params->width; h = params->height; tiles = snewn(w * h, unsigned char); memset(tiles, 0, w * h); barriers = snewn(w * h, unsigned char); memset(barriers, 0, w * h); cx = w / 2; cy = h / 2; /* * Construct the unshuffled grid. * * To do this, we simply start at the centre point, repeatedly * choose a random possibility out of the available ways to * extend a used square into an unused one, and do it. After * extending the third line out of a square, we remove the * fourth from the possibilities list to avoid any full-cross * squares (which would make the game too easy because they * only have one orientation). * * The slightly worrying thing is the avoidance of full-cross * squares. Can this cause our unsophisticated construction * algorithm to paint itself into a corner, by getting into a * situation where there are some unreached squares and the * only way to reach any of them is to extend a T-piece into a * full cross? * * Answer: no it can't, and here's a proof. * * Any contiguous group of such unreachable squares must be * surrounded on _all_ sides by T-pieces pointing away from the * group. (If not, then there is a square which can be extended * into one of the `unreachable' ones, and so it wasn't * unreachable after all.) In particular, this implies that * each contiguous group of unreachable squares must be * rectangular in shape (any deviation from that yields a * non-T-piece next to an `unreachable' square). * * So we have a rectangle of unreachable squares, with T-pieces * forming a solid border around the rectangle. The corners of * that border must be connected (since every tile connects all * the lines arriving in it), and therefore the border must * form a closed loop around the rectangle. * * But this can't have happened in the first place, since we * _know_ we've avoided creating closed loops! Hence, no such * situation can ever arise, and the naive grid construction * algorithm will guaranteeably result in a complete grid * containing no unreached squares, no full crosses _and_ no * closed loops. [] */ possibilities = newtree234(xyd_cmp); if (cx+1 < w) add234(possibilities, new_xyd(cx, cy, R)); if (cy-1 >= 0) add234(possibilities, new_xyd(cx, cy, U)); if (cx-1 >= 0) add234(possibilities, new_xyd(cx, cy, L)); if (cy+1 < h) add234(possibilities, new_xyd(cx, cy, D)); while (count234(possibilities) > 0) { int i; struct xyd *xyd; int x1, y1, d1, x2, y2, d2, d; /* * Extract a randomly chosen possibility from the list. */ i = random_upto(rs, count234(possibilities)); xyd = delpos234(possibilities, i); x1 = xyd->x; y1 = xyd->y; d1 = xyd->direction; sfree(xyd); OFFSET(x2, y2, x1, y1, d1, params); d2 = F(d1); #ifdef GENERATION_DIAGNOSTICS printf("picked (%d,%d,%c) <-> (%d,%d,%c)\n", x1, y1, "0RU3L567D9abcdef"[d1], x2, y2, "0RU3L567D9abcdef"[d2]); #endif /* * Make the connection. (We should be moving to an as yet * unused tile.) */ index(params, tiles, x1, y1) |= d1; assert(index(params, tiles, x2, y2) == 0); index(params, tiles, x2, y2) |= d2; /* * If we have created a T-piece, remove its last * possibility. */ if (COUNT(index(params, tiles, x1, y1)) == 3) { struct xyd xyd1, *xydp; xyd1.x = x1; xyd1.y = y1; xyd1.direction = 0x0F ^ index(params, tiles, x1, y1); xydp = find234(possibilities, &xyd1, NULL); if (xydp) { #ifdef GENERATION_DIAGNOSTICS printf("T-piece; removing (%d,%d,%c)\n", xydp->x, xydp->y, "0RU3L567D9abcdef"[xydp->direction]); #endif del234(possibilities, xydp); sfree(xydp); } } /* * Remove all other possibilities that were pointing at the * tile we've just moved into. */ for (d = 1; d < 0x10; d <<= 1) { int x3, y3, d3; struct xyd xyd1, *xydp; OFFSET(x3, y3, x2, y2, d, params); d3 = F(d); xyd1.x = x3; xyd1.y = y3; xyd1.direction = d3; xydp = find234(possibilities, &xyd1, NULL); if (xydp) { #ifdef GENERATION_DIAGNOSTICS printf("Loop avoidance; removing (%d,%d,%c)\n", xydp->x, xydp->y, "0RU3L567D9abcdef"[xydp->direction]); #endif del234(possibilities, xydp); sfree(xydp); } } /* * Add new possibilities to the list for moving _out_ of * the tile we have just moved into. */ for (d = 1; d < 0x10; d <<= 1) { int x3, y3; if (d == d2) continue; /* we've got this one already */ if (!params->wrapping) { if (d == U && y2 == 0) continue; if (d == D && y2 == h-1) continue; if (d == L && x2 == 0) continue; if (d == R && x2 == w-1) continue; } OFFSET(x3, y3, x2, y2, d, params); if (index(params, tiles, x3, y3)) continue; /* this would create a loop */ #ifdef GENERATION_DIAGNOSTICS printf("New frontier; adding (%d,%d,%c)\n", x2, y2, "0RU3L567D9abcdef"[d]); #endif add234(possibilities, new_xyd(x2, y2, d)); } } /* Having done that, we should have no possibilities remaining. */ assert(count234(possibilities) == 0); freetree234(possibilities); /* * Now compute a list of the possible barrier locations. */ barriertree = newtree234(xyd_cmp); for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { if (!(index(params, tiles, x, y) & R) && (params->wrapping || x < w-1)) add234(barriertree, new_xyd(x, y, R)); if (!(index(params, tiles, x, y) & D) && (params->wrapping || y < h-1)) add234(barriertree, new_xyd(x, y, D)); } } /* * Save the unshuffled grid in aux. */ { char *solution; int i; /* * String format is exactly the same as a solve move, so we * can just dupstr this in solve_game(). */ solution = snewn(w * h + 2, char); solution[0] = 'S'; for (i = 0; i < w * h; i++) solution[i+1] = "0123456789abcdef"[tiles[i] & 0xF]; solution[w*h+1] = '\0'; *aux = solution; } /* * Now shuffle the grid. * FIXME - this simply does a set of random moves to shuffle the pieces, * although we make a token effort to avoid boring cases by avoiding moves * that directly undo the previous one, or that repeat so often as to * turn into fewer moves. * * A better way would be to number all the pieces, generate a placement * for all the numbers as for "sixteen", observing parity constraints if * neccessary, and then place the pieces according to their numbering. * BUT - I'm not sure if this will work, since we disallow movement of * the middle row and column. */ { int i; int cols = w - 1; int rows = h - 1; int moves = params->movetarget; int prevdir = -1, prevrowcol = -1, nrepeats = 0; if (!moves) moves = cols * rows * 2; for (i = 0; i < moves; /* incremented conditionally */) { /* Choose a direction: 0,1,2,3 = up, right, down, left. */ int dir = random_upto(rs, 4); int rowcol; if (dir % 2 == 0) { int col = random_upto(rs, cols); if (col >= cx) col += 1; /* avoid centre */ if (col == prevrowcol) { if (dir == 2-prevdir) continue; /* undoes last move */ else if (dir == prevdir && (nrepeats+1)*2 > h) continue; /* makes fewer moves */ } slide_col_int(w, h, tiles, 1 - dir, col); rowcol = col; } else { int row = random_upto(rs, rows); if (row >= cy) row += 1; /* avoid centre */ if (row == prevrowcol) { if (dir == 4-prevdir) continue; /* undoes last move */ else if (dir == prevdir && (nrepeats+1)*2 > w) continue; /* makes fewer moves */ } slide_row_int(w, h, tiles, 2 - dir, row); rowcol = row; } if (dir == prevdir && rowcol == prevrowcol) nrepeats++; else nrepeats = 1; prevdir = dir; prevrowcol = rowcol; i++; /* if we got here, the move was accepted */ } } /* * And now choose barrier locations. (We carefully do this * _after_ shuffling, so that changing the barrier rate in the * params while keeping the random seed the same will give the * same shuffled grid and _only_ change the barrier locations. * Also the way we choose barrier locations, by repeatedly * choosing one possibility from the list until we have enough, * is designed to ensure that raising the barrier rate while * keeping the seed the same will provide a superset of the * previous barrier set - i.e. if you ask for 10 barriers, and * then decide that's still too hard and ask for 20, you'll get * the original 10 plus 10 more, rather than getting 20 new * ones and the chance of remembering your first 10.) */ nbarriers = (int)(params->barrier_probability * count234(barriertree)); assert(nbarriers >= 0 && nbarriers <= count234(barriertree)); while (nbarriers > 0) { int i; struct xyd *xyd; int x1, y1, d1, x2, y2, d2; /* * Extract a randomly chosen barrier from the list. */ i = random_upto(rs, count234(barriertree)); xyd = delpos234(barriertree, i); assert(xyd != NULL); x1 = xyd->x; y1 = xyd->y; d1 = xyd->direction; sfree(xyd); OFFSET(x2, y2, x1, y1, d1, params); d2 = F(d1); index(params, barriers, x1, y1) |= d1; index(params, barriers, x2, y2) |= d2; nbarriers--; } /* * Clean up the rest of the barrier list. */ { struct xyd *xyd; while ( (xyd = delpos234(barriertree, 0)) != NULL) sfree(xyd); freetree234(barriertree); } /* * Finally, encode the grid into a string game description. * * My syntax is extremely simple: each square is encoded as a * hex digit in which bit 0 means a connection on the right, * bit 1 means up, bit 2 left and bit 3 down. (i.e. the same * encoding as used internally). Each digit is followed by * optional barrier indicators: `v' means a vertical barrier to * the right of it, and `h' means a horizontal barrier below * it. */ desc = snewn(w * h * 3 + 1, char); p = desc; for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { *p++ = "0123456789abcdef"[index(params, tiles, x, y)]; if ((params->wrapping || x < w-1) && (index(params, barriers, x, y) & R)) *p++ = 'v'; if ((params->wrapping || y < h-1) && (index(params, barriers, x, y) & D)) *p++ = 'h'; } } assert(p - desc <= w*h*3); *p = '\0'; sfree(tiles); sfree(barriers); return desc; } static char *validate_desc(const game_params *params, const char *desc) { int w = params->width, h = params->height; int i; for (i = 0; i < w*h; i++) { if (*desc >= '0' && *desc <= '9') /* OK */; else if (*desc >= 'a' && *desc <= 'f') /* OK */; else if (*desc >= 'A' && *desc <= 'F') /* OK */; else if (!*desc) return "Game description shorter than expected"; else return "Game description contained unexpected character"; desc++; while (*desc == 'h' || *desc == 'v') desc++; } if (*desc) return "Game description longer than expected"; return NULL; } /* ---------------------------------------------------------------------- * Construct an initial game state, given a description and parameters. */ static game_state *new_game(midend *me, const game_params *params, const char *desc) { game_state *state; int w, h, x, y; assert(params->width > 0 && params->height > 0); assert(params->width > 1 || params->height > 1); /* * Create a blank game state. */ state = snew(game_state); w = state->width = params->width; h = state->height = params->height; state->cx = state->width / 2; state->cy = state->height / 2; state->wrapping = params->wrapping; state->movetarget = params->movetarget; state->completed = 0; state->used_solve = FALSE; state->move_count = 0; state->last_move_row = -1; state->last_move_col = -1; state->last_move_dir = 0; state->tiles = snewn(state->width * state->height, unsigned char); memset(state->tiles, 0, state->width * state->height); state->barriers = snewn(state->width * state->height, unsigned char); memset(state->barriers, 0, state->width * state->height); /* * Parse the game description into the grid. */ for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { if (*desc >= '0' && *desc <= '9') tile(state, x, y) = *desc - '0'; else if (*desc >= 'a' && *desc <= 'f') tile(state, x, y) = *desc - 'a' + 10; else if (*desc >= 'A' && *desc <= 'F') tile(state, x, y) = *desc - 'A' + 10; if (*desc) desc++; while (*desc == 'h' || *desc == 'v') { int x2, y2, d1, d2; if (*desc == 'v') d1 = R; else d1 = D; OFFSET(x2, y2, x, y, d1, state); d2 = F(d1); barrier(state, x, y) |= d1; barrier(state, x2, y2) |= d2; desc++; } } } /* * Set up border barriers if this is a non-wrapping game. */ if (!state->wrapping) { for (x = 0; x < state->width; x++) { barrier(state, x, 0) |= U; barrier(state, x, state->height-1) |= D; } for (y = 0; y < state->height; y++) { barrier(state, 0, y) |= L; barrier(state, state->width-1, y) |= R; } } /* * Set up the barrier corner flags, for drawing barriers * prettily when they meet. */ for (y = 0; y < state->height; y++) { for (x = 0; x < state->width; x++) { int dir; for (dir = 1; dir < 0x10; dir <<= 1) { int dir2 = A(dir); int x1, y1, x2, y2, x3, y3; int corner = FALSE; if (!(barrier(state, x, y) & dir)) continue; if (barrier(state, x, y) & dir2) corner = TRUE; x1 = x + X(dir), y1 = y + Y(dir); if (x1 >= 0 && x1 < state->width && y1 >= 0 && y1 < state->height && (barrier(state, x1, y1) & dir2)) corner = TRUE; x2 = x + X(dir2), y2 = y + Y(dir2); if (x2 >= 0 && x2 < state->width && y2 >= 0 && y2 < state->height && (barrier(state, x2, y2) & dir)) corner = TRUE; if (corner) { barrier(state, x, y) |= (dir << 4); if (x1 >= 0 && x1 < state->width && y1 >= 0 && y1 < state->height) barrier(state, x1, y1) |= (A(dir) << 4); if (x2 >= 0 && x2 < state->width && y2 >= 0 && y2 < state->height) barrier(state, x2, y2) |= (C(dir) << 4); x3 = x + X(dir) + X(dir2), y3 = y + Y(dir) + Y(dir2); if (x3 >= 0 && x3 < state->width && y3 >= 0 && y3 < state->height) barrier(state, x3, y3) |= (F(dir) << 4); } } } } return state; } static game_state *dup_game(const game_state *state) { game_state *ret; ret = snew(game_state); ret->width = state->width; ret->height = state->height; ret->cx = state->cx; ret->cy = state->cy; ret->wrapping = state->wrapping; ret->movetarget = state->movetarget; ret->completed = state->completed; ret->used_solve = state->used_solve; ret->move_count = state->move_count; ret->last_move_row = state->last_move_row; ret->last_move_col = state->last_move_col; ret->last_move_dir = state->last_move_dir; ret->tiles = snewn(state->width * state->height, unsigned char); memcpy(ret->tiles, state->tiles, state->width * state->height); ret->barriers = snewn(state->width * state->height, unsigned char); memcpy(ret->barriers, state->barriers, state->width * state->height); return ret; } static void free_game(game_state *state) { sfree(state->tiles); sfree(state->barriers); sfree(state); } static char *solve_game(const game_state *state, const game_state *currstate, const char *aux, char **error) { if (!aux) { *error = "Solution not known for this puzzle"; return NULL; } return dupstr(aux); } static int game_can_format_as_text_now(const game_params *params) { return TRUE; } static char *game_text_format(const game_state *state) { return NULL; } /* ---------------------------------------------------------------------- * Utility routine. */ /* * Compute which squares are reachable from the centre square, as a * quick visual aid to determining how close the game is to * completion. This is also a simple way to tell if the game _is_ * completed - just call this function and see whether every square * is marked active. * * squares in the moving_row and moving_col are always inactive - this * is so that "current" doesn't appear to jump across moving lines. */ static unsigned char *compute_active(const game_state *state, int moving_row, int moving_col) { unsigned char *active; tree234 *todo; struct xyd *xyd; active = snewn(state->width * state->height, unsigned char); memset(active, 0, state->width * state->height); /* * We only store (x,y) pairs in todo, but it's easier to reuse * xyd_cmp and just store direction 0 every time. */ todo = newtree234(xyd_cmp); index(state, active, state->cx, state->cy) = ACTIVE; add234(todo, new_xyd(state->cx, state->cy, 0)); while ( (xyd = delpos234(todo, 0)) != NULL) { int x1, y1, d1, x2, y2, d2; x1 = xyd->x; y1 = xyd->y; sfree(xyd); for (d1 = 1; d1 < 0x10; d1 <<= 1) { OFFSET(x2, y2, x1, y1, d1, state); d2 = F(d1); /* * If the next tile in this direction is connected to * us, and there isn't a barrier in the way, and it * isn't already marked active, then mark it active and * add it to the to-examine list. */ if ((x2 != moving_col && y2 != moving_row) && (tile(state, x1, y1) & d1) && (tile(state, x2, y2) & d2) && !(barrier(state, x1, y1) & d1) && !index(state, active, x2, y2)) { index(state, active, x2, y2) = ACTIVE; add234(todo, new_xyd(x2, y2, 0)); } } } /* Now we expect the todo list to have shrunk to zero size. */ assert(count234(todo) == 0); freetree234(todo); return active; } struct game_ui { int cur_x, cur_y; int cur_visible; }; static game_ui *new_ui(const game_state *state) { game_ui *ui = snew(game_ui); ui->cur_x = 0; ui->cur_y = -1; ui->cur_visible = FALSE; return ui; } static void free_ui(game_ui *ui) { sfree(ui); } static char *encode_ui(const game_ui *ui) { return NULL; } static void decode_ui(game_ui *ui, const char *encoding) { } /* ---------------------------------------------------------------------- * Process a move. */ static void slide_row_int(int w, int h, unsigned char *tiles, int dir, int row) { int x = dir > 0 ? -1 : w; int tx = x + dir; int n = w - 1; unsigned char endtile = tiles[row * w + tx]; do { x = tx; tx = (x + dir + w) % w; tiles[row * w + x] = tiles[row * w + tx]; } while (--n > 0); tiles[row * w + tx] = endtile; } static void slide_col_int(int w, int h, unsigned char *tiles, int dir, int col) { int y = dir > 0 ? -1 : h; int ty = y + dir; int n = h - 1; unsigned char endtile = tiles[ty * w + col]; do { y = ty; ty = (y + dir + h) % h; tiles[y * w + col] = tiles[ty * w + col]; } while (--n > 0); tiles[ty * w + col] = endtile; } static void slide_row(game_state *state, int dir, int row) { slide_row_int(state->width, state->height, state->tiles, dir, row); } static void slide_col(game_state *state, int dir, int col) { slide_col_int(state->width, state->height, state->tiles, dir, col); } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { } struct game_drawstate { int started; int width, height; int tilesize; unsigned char *visible; int cur_x, cur_y; }; static char *interpret_move(const game_state *state, game_ui *ui, const game_drawstate *ds, int x, int y, int button) { int cx, cy; int dx, dy; char buf[80]; button &= ~MOD_MASK; if (IS_CURSOR_MOVE(button)) { int cpos, diff = 0; cpos = c2pos(state->width, state->height, ui->cur_x, ui->cur_y); diff = c2diff(state->width, state->height, ui->cur_x, ui->cur_y, button); if (diff != 0) { do { /* we might have to do this more than once to skip missing arrows */ cpos += diff; pos2c(state->width, state->height, cpos, &ui->cur_x, &ui->cur_y); } while (ui->cur_x == state->cx || ui->cur_y == state->cy); } ui->cur_visible = 1; return ""; } if (button == LEFT_BUTTON || button == RIGHT_BUTTON) { cx = (x - (BORDER + WINDOW_OFFSET + TILE_BORDER) + 2*TILE_SIZE) / TILE_SIZE - 2; cy = (y - (BORDER + WINDOW_OFFSET + TILE_BORDER) + 2*TILE_SIZE) / TILE_SIZE - 2; ui->cur_visible = 0; } else if (IS_CURSOR_SELECT(button)) { if (ui->cur_visible) { cx = ui->cur_x; cy = ui->cur_y; } else { /* 'click' when cursor is invisible just makes cursor visible. */ ui->cur_visible = 1; return ""; } } else return NULL; if (cy >= 0 && cy < state->height && cy != state->cy) { if (cx == -1) dx = +1; else if (cx == state->width) dx = -1; else return NULL; dy = 0; } else if (cx >= 0 && cx < state->width && cx != state->cx) { if (cy == -1) dy = +1; else if (cy == state->height) dy = -1; else return NULL; dx = 0; } else return NULL; /* reverse direction if right hand button is pressed */ if (button == RIGHT_BUTTON) { dx = -dx; dy = -dy; } if (dx == 0) sprintf(buf, "C%d,%d", cx, dy); else sprintf(buf, "R%d,%d", cy, dx); return dupstr(buf); } static game_state *execute_move(const game_state *from, const char *move) { game_state *ret; int c, d, col; if ((move[0] == 'C' || move[0] == 'R') && sscanf(move+1, "%d,%d", &c, &d) == 2 && c >= 0 && c < (move[0] == 'C' ? from->width : from->height)) { col = (move[0] == 'C'); } else if (move[0] == 'S' && strlen(move) == from->width * from->height + 1) { int i; ret = dup_game(from); ret->used_solve = TRUE; ret->completed = ret->move_count = 1; for (i = 0; i < from->width * from->height; i++) { c = move[i+1]; if (c >= '0' && c <= '9') c -= '0'; else if (c >= 'A' && c <= 'F') c -= 'A' - 10; else if (c >= 'a' && c <= 'f') c -= 'a' - 10; else { free_game(ret); return NULL; } ret->tiles[i] = c; } return ret; } else return NULL; /* can't parse move string */ ret = dup_game(from); if (col) slide_col(ret, d, c); else slide_row(ret, d, c); ret->move_count++; ret->last_move_row = col ? -1 : c; ret->last_move_col = col ? c : -1; ret->last_move_dir = d; /* * See if the game has been completed. */ if (!ret->completed) { unsigned char *active = compute_active(ret, -1, -1); int x1, y1; int complete = TRUE; for (x1 = 0; x1 < ret->width; x1++) for (y1 = 0; y1 < ret->height; y1++) if (!index(ret, active, x1, y1)) { complete = FALSE; goto break_label; /* break out of two loops at once */ } break_label: sfree(active); if (complete) ret->completed = ret->move_count; } return ret; } /* ---------------------------------------------------------------------- * Routines for drawing the game position on the screen. */ static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { game_drawstate *ds = snew(game_drawstate); ds->started = FALSE; ds->width = state->width; ds->height = state->height; ds->visible = snewn(state->width * state->height, unsigned char); ds->tilesize = 0; /* not decided yet */ memset(ds->visible, 0xFF, state->width * state->height); ds->cur_x = ds->cur_y = -1; return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { sfree(ds->visible); sfree(ds); } static void game_compute_size(const game_params *params, int tilesize, int *x, int *y) { /* Ick: fake up `ds->tilesize' for macro expansion purposes */ struct { int tilesize; } ads, *ds = &ads; ads.tilesize = tilesize; *x = BORDER * 2 + WINDOW_OFFSET * 2 + TILE_SIZE * params->width + TILE_BORDER; *y = BORDER * 2 + WINDOW_OFFSET * 2 + TILE_SIZE * params->height + TILE_BORDER; } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { ds->tilesize = tilesize; } static float *game_colours(frontend *fe, int *ncolours) { float *ret; ret = snewn(NCOLOURS * 3, float); *ncolours = NCOLOURS; /* * Basic background colour is whatever the front end thinks is * a sensible default. */ frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]); /* * Wires are black. */ ret[COL_WIRE * 3 + 0] = 0.0F; ret[COL_WIRE * 3 + 1] = 0.0F; ret[COL_WIRE * 3 + 2] = 0.0F; /* * Powered wires and powered endpoints are cyan. */ ret[COL_POWERED * 3 + 0] = 0.0F; ret[COL_POWERED * 3 + 1] = 1.0F; ret[COL_POWERED * 3 + 2] = 1.0F; /* * Barriers are red. */ ret[COL_BARRIER * 3 + 0] = 1.0F; ret[COL_BARRIER * 3 + 1] = 0.0F; ret[COL_BARRIER * 3 + 2] = 0.0F; /* * Unpowered endpoints are blue. */ ret[COL_ENDPOINT * 3 + 0] = 0.0F; ret[COL_ENDPOINT * 3 + 1] = 0.0F; ret[COL_ENDPOINT * 3 + 2] = 1.0F; /* * Tile borders are a darker grey than the background. */ ret[COL_BORDER * 3 + 0] = 0.5F * ret[COL_BACKGROUND * 3 + 0]; ret[COL_BORDER * 3 + 1] = 0.5F * ret[COL_BACKGROUND * 3 + 1]; ret[COL_BORDER * 3 + 2] = 0.5F * ret[COL_BACKGROUND * 3 + 2]; /* * Flashing tiles are a grey in between those two. */ ret[COL_FLASHING * 3 + 0] = 0.75F * ret[COL_BACKGROUND * 3 + 0]; ret[COL_FLASHING * 3 + 1] = 0.75F * ret[COL_BACKGROUND * 3 + 1]; ret[COL_FLASHING * 3 + 2] = 0.75F * ret[COL_BACKGROUND * 3 + 2]; ret[COL_LOWLIGHT * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] * 0.8F; ret[COL_LOWLIGHT * 3 + 1] = ret[COL_BACKGROUND * 3 + 1] * 0.8F; ret[COL_LOWLIGHT * 3 + 2] = ret[COL_BACKGROUND * 3 + 2] * 0.8F; ret[COL_TEXT * 3 + 0] = 0.0; ret[COL_TEXT * 3 + 1] = 0.0; ret[COL_TEXT * 3 + 2] = 0.0; return ret; } static void draw_filled_line(drawing *dr, int x1, int y1, int x2, int y2, int colour) { draw_line(dr, x1-1, y1, x2-1, y2, COL_WIRE); draw_line(dr, x1+1, y1, x2+1, y2, COL_WIRE); draw_line(dr, x1, y1-1, x2, y2-1, COL_WIRE); draw_line(dr, x1, y1+1, x2, y2+1, COL_WIRE); draw_line(dr, x1, y1, x2, y2, colour); } static void draw_rect_coords(drawing *dr, int x1, int y1, int x2, int y2, int colour) { int mx = (x1 < x2 ? x1 : x2); int my = (y1 < y2 ? y1 : y2); int dx = (x2 + x1 - 2*mx + 1); int dy = (y2 + y1 - 2*my + 1); draw_rect(dr, mx, my, dx, dy, colour); } static void draw_barrier_corner(drawing *dr, game_drawstate *ds, int x, int y, int dir, int phase) { int bx = BORDER + WINDOW_OFFSET + TILE_SIZE * x; int by = BORDER + WINDOW_OFFSET + TILE_SIZE * y; int x1, y1, dx, dy, dir2; dir >>= 4; dir2 = A(dir); dx = X(dir) + X(dir2); dy = Y(dir) + Y(dir2); x1 = (dx > 0 ? TILE_SIZE+TILE_BORDER-1 : 0); y1 = (dy > 0 ? TILE_SIZE+TILE_BORDER-1 : 0); if (phase == 0) { draw_rect_coords(dr, bx+x1, by+y1, bx+x1-TILE_BORDER*dx, by+y1-(TILE_BORDER-1)*dy, COL_WIRE); draw_rect_coords(dr, bx+x1, by+y1, bx+x1-(TILE_BORDER-1)*dx, by+y1-TILE_BORDER*dy, COL_WIRE); } else { draw_rect_coords(dr, bx+x1, by+y1, bx+x1-(TILE_BORDER-1)*dx, by+y1-(TILE_BORDER-1)*dy, COL_BARRIER); } } static void draw_barrier(drawing *dr, game_drawstate *ds, int x, int y, int dir, int phase) { int bx = BORDER + WINDOW_OFFSET + TILE_SIZE * x; int by = BORDER + WINDOW_OFFSET + TILE_SIZE * y; int x1, y1, w, h; x1 = (X(dir) > 0 ? TILE_SIZE : X(dir) == 0 ? TILE_BORDER : 0); y1 = (Y(dir) > 0 ? TILE_SIZE : Y(dir) == 0 ? TILE_BORDER : 0); w = (X(dir) ? TILE_BORDER : TILE_SIZE - TILE_BORDER); h = (Y(dir) ? TILE_BORDER : TILE_SIZE - TILE_BORDER); if (phase == 0) { draw_rect(dr, bx+x1-X(dir), by+y1-Y(dir), w, h, COL_WIRE); } else { draw_rect(dr, bx+x1, by+y1, w, h, COL_BARRIER); } } static void draw_tile(drawing *dr, game_drawstate *ds, const game_state *state, int x, int y, int tile, float xshift, float yshift) { int bx = BORDER + WINDOW_OFFSET + TILE_SIZE * x + (int)(xshift * TILE_SIZE); int by = BORDER + WINDOW_OFFSET + TILE_SIZE * y + (int)(yshift * TILE_SIZE); float cx, cy, ex, ey; int dir, col; /* * When we draw a single tile, we must draw everything up to * and including the borders around the tile. This means that * if the neighbouring tiles have connections to those borders, * we must draw those connections on the borders themselves. * * This would be terribly fiddly if we ever had to draw a tile * while its neighbour was in mid-rotate, because we'd have to * arrange to _know_ that the neighbour was being rotated and * hence had an anomalous effect on the redraw of this tile. * Fortunately, the drawing algorithm avoids ever calling us in * this circumstance: we're either drawing lots of straight * tiles at game start or after a move is complete, or we're * repeatedly drawing only the rotating tile. So no problem. */ /* * So. First blank the tile out completely: draw a big * rectangle in border colour, and a smaller rectangle in * background colour to fill it in. */ draw_rect(dr, bx, by, TILE_SIZE+TILE_BORDER, TILE_SIZE+TILE_BORDER, COL_BORDER); draw_rect(dr, bx+TILE_BORDER, by+TILE_BORDER, TILE_SIZE-TILE_BORDER, TILE_SIZE-TILE_BORDER, tile & FLASHING ? COL_FLASHING : COL_BACKGROUND); /* * Draw the wires. */ cx = cy = TILE_BORDER + (TILE_SIZE-TILE_BORDER) / 2.0F - 0.5F; col = (tile & ACTIVE ? COL_POWERED : COL_WIRE); for (dir = 1; dir < 0x10; dir <<= 1) { if (tile & dir) { ex = (TILE_SIZE - TILE_BORDER - 1.0F) / 2.0F * X(dir); ey = (TILE_SIZE - TILE_BORDER - 1.0F) / 2.0F * Y(dir); draw_filled_line(dr, bx+(int)cx, by+(int)cy, bx+(int)(cx+ex), by+(int)(cy+ey), COL_WIRE); } } for (dir = 1; dir < 0x10; dir <<= 1) { if (tile & dir) { ex = (TILE_SIZE - TILE_BORDER - 1.0F) / 2.0F * X(dir); ey = (TILE_SIZE - TILE_BORDER - 1.0F) / 2.0F * Y(dir); draw_line(dr, bx+(int)cx, by+(int)cy, bx+(int)(cx+ex), by+(int)(cy+ey), col); } } /* * Draw the box in the middle. We do this in blue if the tile * is an unpowered endpoint, in cyan if the tile is a powered * endpoint, in black if the tile is the centrepiece, and * otherwise not at all. */ col = -1; if (x == state->cx && y == state->cy) col = COL_WIRE; else if (COUNT(tile) == 1) { col = (tile & ACTIVE ? COL_POWERED : COL_ENDPOINT); } if (col >= 0) { int i, points[8]; points[0] = +1; points[1] = +1; points[2] = +1; points[3] = -1; points[4] = -1; points[5] = -1; points[6] = -1; points[7] = +1; for (i = 0; i < 8; i += 2) { ex = (TILE_SIZE * 0.24F) * points[i]; ey = (TILE_SIZE * 0.24F) * points[i+1]; points[i] = bx+(int)(cx+ex); points[i+1] = by+(int)(cy+ey); } draw_polygon(dr, points, 4, col, COL_WIRE); } /* * Draw the points on the border if other tiles are connected * to us. */ for (dir = 1; dir < 0x10; dir <<= 1) { int dx, dy, px, py, lx, ly, vx, vy, ox, oy; dx = X(dir); dy = Y(dir); ox = x + dx; oy = y + dy; if (ox < 0 || ox >= state->width || oy < 0 || oy >= state->height) continue; if (!(tile(state, ox, oy) & F(dir))) continue; px = bx + (int)(dx>0 ? TILE_SIZE + TILE_BORDER - 1 : dx<0 ? 0 : cx); py = by + (int)(dy>0 ? TILE_SIZE + TILE_BORDER - 1 : dy<0 ? 0 : cy); lx = dx * (TILE_BORDER-1); ly = dy * (TILE_BORDER-1); vx = (dy ? 1 : 0); vy = (dx ? 1 : 0); if (xshift == 0.0 && yshift == 0.0 && (tile & dir)) { /* * If we are fully connected to the other tile, we must * draw right across the tile border. (We can use our * own ACTIVE state to determine what colour to do this * in: if we are fully connected to the other tile then * the two ACTIVE states will be the same.) */ draw_rect_coords(dr, px-vx, py-vy, px+lx+vx, py+ly+vy, COL_WIRE); draw_rect_coords(dr, px, py, px+lx, py+ly, (tile & ACTIVE) ? COL_POWERED : COL_WIRE); } else { /* * The other tile extends into our border, but isn't * actually connected to us. Just draw a single black * dot. */ draw_rect_coords(dr, px, py, px, py, COL_WIRE); } } draw_update(dr, bx, by, TILE_SIZE+TILE_BORDER, TILE_SIZE+TILE_BORDER); } static void draw_tile_barriers(drawing *dr, game_drawstate *ds, const game_state *state, int x, int y) { int phase; int dir; int bx = BORDER + WINDOW_OFFSET + TILE_SIZE * x; int by = BORDER + WINDOW_OFFSET + TILE_SIZE * y; /* * Draw barrier corners, and then barriers. */ for (phase = 0; phase < 2; phase++) { for (dir = 1; dir < 0x10; dir <<= 1) if (barrier(state, x, y) & (dir << 4)) draw_barrier_corner(dr, ds, x, y, dir << 4, phase); for (dir = 1; dir < 0x10; dir <<= 1) if (barrier(state, x, y) & dir) draw_barrier(dr, ds, x, y, dir, phase); } draw_update(dr, bx, by, TILE_SIZE+TILE_BORDER, TILE_SIZE+TILE_BORDER); } static void draw_arrow(drawing *dr, game_drawstate *ds, int x, int y, int xdx, int xdy, int cur) { int coords[14]; int ydy = -xdx, ydx = xdy; x = x * TILE_SIZE + BORDER + WINDOW_OFFSET; y = y * TILE_SIZE + BORDER + WINDOW_OFFSET; #define POINT(n, xx, yy) ( \ coords[2*(n)+0] = x + (xx)*xdx + (yy)*ydx, \ coords[2*(n)+1] = y + (xx)*xdy + (yy)*ydy) POINT(0, TILE_SIZE / 2, 3 * TILE_SIZE / 4); /* top of arrow */ POINT(1, 3 * TILE_SIZE / 4, TILE_SIZE / 2); /* right corner */ POINT(2, 5 * TILE_SIZE / 8, TILE_SIZE / 2); /* right concave */ POINT(3, 5 * TILE_SIZE / 8, TILE_SIZE / 4); /* bottom right */ POINT(4, 3 * TILE_SIZE / 8, TILE_SIZE / 4); /* bottom left */ POINT(5, 3 * TILE_SIZE / 8, TILE_SIZE / 2); /* left concave */ POINT(6, TILE_SIZE / 4, TILE_SIZE / 2); /* left corner */ draw_polygon(dr, coords, 7, cur ? COL_POWERED : COL_LOWLIGHT, COL_TEXT); } static void draw_arrow_for_cursor(drawing *dr, game_drawstate *ds, int cur_x, int cur_y, int cur) { if (cur_x == -1 && cur_y == -1) return; /* 'no cursur here */ else if (cur_x == -1) /* LH column. */ draw_arrow(dr, ds, 0, cur_y+1, 0, -1, cur); else if (cur_x == ds->width) /* RH column */ draw_arrow(dr, ds, ds->width, cur_y, 0, +1, cur); else if (cur_y == -1) /* Top row */ draw_arrow(dr, ds, cur_x, 0, +1, 0, cur); else if (cur_y == ds->height) /* Bottom row */ draw_arrow(dr, ds, cur_x+1, ds->height, -1, 0, cur); else assert(!"Invalid cursor position"); draw_update(dr, cur_x * TILE_SIZE + BORDER + WINDOW_OFFSET, cur_y * TILE_SIZE + BORDER + WINDOW_OFFSET, TILE_SIZE, TILE_SIZE); } static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float t, float ft) { int x, y, frame; unsigned char *active; float xshift = 0.0; float yshift = 0.0; int cur_x = -1, cur_y = -1; /* * Clear the screen and draw the exterior barrier lines if this * is our first call. */ if (!ds->started) { int phase; ds->started = TRUE; draw_rect(dr, 0, 0, BORDER * 2 + WINDOW_OFFSET * 2 + TILE_SIZE * state->width + TILE_BORDER, BORDER * 2 + WINDOW_OFFSET * 2 + TILE_SIZE * state->height + TILE_BORDER, COL_BACKGROUND); draw_update(dr, 0, 0, BORDER * 2 + WINDOW_OFFSET*2 + TILE_SIZE*state->width + TILE_BORDER, BORDER * 2 + WINDOW_OFFSET*2 + TILE_SIZE*state->height + TILE_BORDER); for (phase = 0; phase < 2; phase++) { for (x = 0; x < ds->width; x++) { if (barrier(state, x, 0) & UL) draw_barrier_corner(dr, ds, x, -1, LD, phase); if (barrier(state, x, 0) & RU) draw_barrier_corner(dr, ds, x, -1, DR, phase); if (barrier(state, x, 0) & U) draw_barrier(dr, ds, x, -1, D, phase); if (barrier(state, x, ds->height-1) & DR) draw_barrier_corner(dr, ds, x, ds->height, RU, phase); if (barrier(state, x, ds->height-1) & LD) draw_barrier_corner(dr, ds, x, ds->height, UL, phase); if (barrier(state, x, ds->height-1) & D) draw_barrier(dr, ds, x, ds->height, U, phase); } for (y = 0; y < ds->height; y++) { if (barrier(state, 0, y) & UL) draw_barrier_corner(dr, ds, -1, y, RU, phase); if (barrier(state, 0, y) & LD) draw_barrier_corner(dr, ds, -1, y, DR, phase); if (barrier(state, 0, y) & L) draw_barrier(dr, ds, -1, y, R, phase); if (barrier(state, ds->width-1, y) & RU) draw_barrier_corner(dr, ds, ds->width, y, UL, phase); if (barrier(state, ds->width-1, y) & DR) draw_barrier_corner(dr, ds, ds->width, y, LD, phase); if (barrier(state, ds->width-1, y) & R) draw_barrier(dr, ds, ds->width, y, L, phase); } } /* * Arrows for making moves. */ for (x = 0; x < ds->width; x++) { if (x == state->cx) continue; draw_arrow(dr, ds, x, 0, +1, 0, 0); draw_arrow(dr, ds, x+1, ds->height, -1, 0, 0); } for (y = 0; y < ds->height; y++) { if (y == state->cy) continue; draw_arrow(dr, ds, ds->width, y, 0, +1, 0); draw_arrow(dr, ds, 0, y+1, 0, -1, 0); } } if (ui->cur_visible) { cur_x = ui->cur_x; cur_y = ui->cur_y; } if (cur_x != ds->cur_x || cur_y != ds->cur_y) { /* Cursor has changed; redraw two (prev and curr) arrows. */ assert(cur_x != state->cx && cur_y != state->cy); draw_arrow_for_cursor(dr, ds, cur_x, cur_y, 1); draw_arrow_for_cursor(dr, ds, ds->cur_x, ds->cur_y, 0); ds->cur_x = cur_x; ds->cur_y = cur_y; } /* Check if this is an undo. If so, we will need to run any animation * backwards. */ if (oldstate && oldstate->move_count > state->move_count) { const game_state * tmpstate = state; state = oldstate; oldstate = tmpstate; t = ANIM_TIME - t; } if (oldstate && (t < ANIM_TIME)) { /* * We're animating a slide, of row/column number * state->last_move_pos, in direction * state->last_move_dir */ xshift = state->last_move_row == -1 ? 0.0F : (1 - t / ANIM_TIME) * state->last_move_dir; yshift = state->last_move_col == -1 ? 0.0F : (1 - t / ANIM_TIME) * state->last_move_dir; } frame = -1; if (ft > 0) { /* * We're animating a completion flash. Find which frame * we're at. */ frame = (int)(ft / FLASH_FRAME); } /* * Draw any tile which differs from the way it was last drawn. */ if (xshift != 0.0 || yshift != 0.0) { active = compute_active(state, state->last_move_row, state->last_move_col); } else { active = compute_active(state, -1, -1); } clip(dr, BORDER + WINDOW_OFFSET, BORDER + WINDOW_OFFSET, TILE_SIZE * state->width + TILE_BORDER, TILE_SIZE * state->height + TILE_BORDER); for (x = 0; x < ds->width; x++) for (y = 0; y < ds->height; y++) { unsigned char c = tile(state, x, y) | index(state, active, x, y); /* * In a completion flash, we adjust the FLASHING bit * depending on our distance from the centre point and * the frame number. */ if (frame >= 0) { int xdist, ydist, dist; xdist = (x < state->cx ? state->cx - x : x - state->cx); ydist = (y < state->cy ? state->cy - y : y - state->cy); dist = (xdist > ydist ? xdist : ydist); if (frame >= dist && frame < dist+4) { int flash = (frame - dist) & 1; flash = flash ? FLASHING : 0; c = (c &~ FLASHING) | flash; } } if (index(state, ds->visible, x, y) != c || index(state, ds->visible, x, y) == 0xFF || (x == state->last_move_col || y == state->last_move_row)) { float xs = (y == state->last_move_row ? xshift : (float)0.0); float ys = (x == state->last_move_col ? yshift : (float)0.0); draw_tile(dr, ds, state, x, y, c, xs, ys); if (xs < 0 && x == 0) draw_tile(dr, ds, state, state->width, y, c, xs, ys); else if (xs > 0 && x == state->width - 1) draw_tile(dr, ds, state, -1, y, c, xs, ys); else if (ys < 0 && y == 0) draw_tile(dr, ds, state, x, state->height, c, xs, ys); else if (ys > 0 && y == state->height - 1) draw_tile(dr, ds, state, x, -1, c, xs, ys); if (x == state->last_move_col || y == state->last_move_row) index(state, ds->visible, x, y) = 0xFF; else index(state, ds->visible, x, y) = c; } } for (x = 0; x < ds->width; x++) for (y = 0; y < ds->height; y++) draw_tile_barriers(dr, ds, state, x, y); unclip(dr); /* * Update the status bar. */ { char statusbuf[256]; int i, n, a; n = state->width * state->height; for (i = a = 0; i < n; i++) if (active[i]) a++; if (state->used_solve) sprintf(statusbuf, "Moves since auto-solve: %d", state->move_count - state->completed); else sprintf(statusbuf, "%sMoves: %d", (state->completed ? "COMPLETED! " : ""), (state->completed ? state->completed : state->move_count)); if (state->movetarget) sprintf(statusbuf + strlen(statusbuf), " (target %d)", state->movetarget); sprintf(statusbuf + strlen(statusbuf), " Active: %d/%d", a, n); status_bar(dr, statusbuf); } sfree(active); } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return ANIM_TIME; } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { /* * If the game has just been completed, we display a completion * flash. */ if (!oldstate->completed && newstate->completed && !oldstate->used_solve && !newstate->used_solve) { int size; size = 0; if (size < newstate->cx+1) size = newstate->cx+1; if (size < newstate->cy+1) size = newstate->cy+1; if (size < newstate->width - newstate->cx) size = newstate->width - newstate->cx; if (size < newstate->height - newstate->cy) size = newstate->height - newstate->cy; return FLASH_FRAME * (size+4); } return 0.0F; } static int game_status(const game_state *state) { return state->completed ? +1 : 0; } static int game_timing_state(const game_state *state, game_ui *ui) { return FALSE; } static void game_print_size(const game_params *params, float *x, float *y) { } static void game_print(drawing *dr, const game_state *state, int tilesize) { } #ifdef COMBINED #define thegame netslide #endif const struct game thegame = { "Netslide", "games.netslide", "netslide", default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, TRUE, solve_game, FALSE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, PREFERRED_TILE_SIZE, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, FALSE, FALSE, game_print_size, game_print, TRUE, /* wants_statusbar */ FALSE, game_timing_state, 0, /* flags */ }; /* vim: set shiftwidth=4 tabstop=8: */ puzzles-20170606.272beef/net.c0000644000175000017500000027546213115373615014643 0ustar simonsimon/* * net.c: Net game. */ #include #include #include #include #include #include #include "puzzles.h" #include "tree234.h" /* * The standard user interface for Net simply has left- and * right-button mouse clicks in a square rotate it one way or the * other. We also provide, by #ifdef, a separate interface based on * rotational dragging motions. I initially developed this for the * Mac on the basis that it might work better than the click * interface with only one mouse button available, but in fact * found it to be quite strange and unintuitive. Apparently it * works better on stylus-driven platforms such as Palm and * PocketPC, though, so we enable it by default there. */ #ifdef STYLUS_BASED #define USE_DRAGGING #endif #define MATMUL(xr,yr,m,x,y) do { \ float rx, ry, xx = (x), yy = (y), *mat = (m); \ rx = mat[0] * xx + mat[2] * yy; \ ry = mat[1] * xx + mat[3] * yy; \ (xr) = rx; (yr) = ry; \ } while (0) /* Direction and other bitfields */ #define R 0x01 #define U 0x02 #define L 0x04 #define D 0x08 #define LOCKED 0x10 #define ACTIVE 0x20 #define RLOOP (R << 6) #define ULOOP (U << 6) #define LLOOP (L << 6) #define DLOOP (D << 6) #define LOOP(dir) ((dir) << 6) /* Rotations: Anticlockwise, Clockwise, Flip, general rotate */ #define A(x) ( (((x) & 0x07) << 1) | (((x) & 0x08) >> 3) ) #define C(x) ( (((x) & 0x0E) >> 1) | (((x) & 0x01) << 3) ) #define F(x) ( (((x) & 0x0C) >> 2) | (((x) & 0x03) << 2) ) #define ROT(x, n) ( ((n)&3) == 0 ? (x) : \ ((n)&3) == 1 ? A(x) : \ ((n)&3) == 2 ? F(x) : C(x) ) /* X and Y displacements */ #define X(x) ( (x) == R ? +1 : (x) == L ? -1 : 0 ) #define Y(x) ( (x) == D ? +1 : (x) == U ? -1 : 0 ) /* Bit count */ #define COUNT(x) ( (((x) & 0x08) >> 3) + (((x) & 0x04) >> 2) + \ (((x) & 0x02) >> 1) + ((x) & 0x01) ) #define PREFERRED_TILE_SIZE 32 #define TILE_SIZE (ds->tilesize) #define TILE_BORDER 1 #ifdef SMALL_SCREEN #define WINDOW_OFFSET 4 #else #define WINDOW_OFFSET 16 #endif #define ROTATE_TIME 0.13F #define FLASH_FRAME 0.07F /* Transform physical coords to game coords using game_drawstate ds */ #define GX(x) (((x) + ds->org_x) % ds->width) #define GY(y) (((y) + ds->org_y) % ds->height) /* ...and game coords to physical coords */ #define RX(x) (((x) + ds->width - ds->org_x) % ds->width) #define RY(y) (((y) + ds->height - ds->org_y) % ds->height) enum { COL_BACKGROUND, COL_LOCKED, COL_BORDER, COL_WIRE, COL_ENDPOINT, COL_POWERED, COL_BARRIER, COL_LOOP, NCOLOURS }; struct game_params { int width; int height; int wrapping; int unique; float barrier_probability; }; struct game_state { int width, height, wrapping, completed; int last_rotate_x, last_rotate_y, last_rotate_dir; int used_solve; unsigned char *tiles; unsigned char *barriers; }; #define OFFSETWH(x2,y2,x1,y1,dir,width,height) \ ( (x2) = ((x1) + width + X((dir))) % width, \ (y2) = ((y1) + height + Y((dir))) % height) #define OFFSET(x2,y2,x1,y1,dir,state) \ OFFSETWH(x2,y2,x1,y1,dir,(state)->width,(state)->height) #define index(state, a, x, y) ( a[(y) * (state)->width + (x)] ) #define tile(state, x, y) index(state, (state)->tiles, x, y) #define barrier(state, x, y) index(state, (state)->barriers, x, y) struct xyd { int x, y, direction; }; static int xyd_cmp(const void *av, const void *bv) { const struct xyd *a = (const struct xyd *)av; const struct xyd *b = (const struct xyd *)bv; if (a->x < b->x) return -1; if (a->x > b->x) return +1; if (a->y < b->y) return -1; if (a->y > b->y) return +1; if (a->direction < b->direction) return -1; if (a->direction > b->direction) return +1; return 0; } static int xyd_cmp_nc(void *av, void *bv) { return xyd_cmp(av, bv); } static struct xyd *new_xyd(int x, int y, int direction) { struct xyd *xyd = snew(struct xyd); xyd->x = x; xyd->y = y; xyd->direction = direction; return xyd; } /* ---------------------------------------------------------------------- * Manage game parameters. */ static game_params *default_params(void) { game_params *ret = snew(game_params); ret->width = 5; ret->height = 5; ret->wrapping = FALSE; ret->unique = TRUE; ret->barrier_probability = 0.0; return ret; } static const struct game_params net_presets[] = { {5, 5, FALSE, TRUE, 0.0}, {7, 7, FALSE, TRUE, 0.0}, {9, 9, FALSE, TRUE, 0.0}, {11, 11, FALSE, TRUE, 0.0}, #ifndef SMALL_SCREEN {13, 11, FALSE, TRUE, 0.0}, #endif {5, 5, TRUE, TRUE, 0.0}, {7, 7, TRUE, TRUE, 0.0}, {9, 9, TRUE, TRUE, 0.0}, {11, 11, TRUE, TRUE, 0.0}, #ifndef SMALL_SCREEN {13, 11, TRUE, TRUE, 0.0}, #endif }; static int game_fetch_preset(int i, char **name, game_params **params) { game_params *ret; char str[80]; if (i < 0 || i >= lenof(net_presets)) return FALSE; ret = snew(game_params); *ret = net_presets[i]; sprintf(str, "%dx%d%s", ret->width, ret->height, ret->wrapping ? " wrapping" : ""); *name = dupstr(str); *params = ret; return TRUE; } static void free_params(game_params *params) { sfree(params); } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } static void decode_params(game_params *ret, char const *string) { char const *p = string; ret->width = atoi(p); while (*p && isdigit((unsigned char)*p)) p++; if (*p == 'x') { p++; ret->height = atoi(p); while (*p && isdigit((unsigned char)*p)) p++; } else { ret->height = ret->width; } while (*p) { if (*p == 'w') { p++; ret->wrapping = TRUE; } else if (*p == 'b') { p++; ret->barrier_probability = (float)atof(p); while (*p && (*p == '.' || isdigit((unsigned char)*p))) p++; } else if (*p == 'a') { p++; ret->unique = FALSE; } else p++; /* skip any other gunk */ } } static char *encode_params(const game_params *params, int full) { char ret[400]; int len; len = sprintf(ret, "%dx%d", params->width, params->height); if (params->wrapping) ret[len++] = 'w'; if (full && params->barrier_probability) len += sprintf(ret+len, "b%g", params->barrier_probability); if (full && !params->unique) ret[len++] = 'a'; assert(len < lenof(ret)); ret[len] = '\0'; return dupstr(ret); } static config_item *game_configure(const game_params *params) { config_item *ret; char buf[80]; ret = snewn(6, config_item); ret[0].name = "Width"; ret[0].type = C_STRING; sprintf(buf, "%d", params->width); ret[0].sval = dupstr(buf); ret[0].ival = 0; ret[1].name = "Height"; ret[1].type = C_STRING; sprintf(buf, "%d", params->height); ret[1].sval = dupstr(buf); ret[1].ival = 0; ret[2].name = "Walls wrap around"; ret[2].type = C_BOOLEAN; ret[2].sval = NULL; ret[2].ival = params->wrapping; ret[3].name = "Barrier probability"; ret[3].type = C_STRING; sprintf(buf, "%g", params->barrier_probability); ret[3].sval = dupstr(buf); ret[3].ival = 0; ret[4].name = "Ensure unique solution"; ret[4].type = C_BOOLEAN; ret[4].sval = NULL; ret[4].ival = params->unique; ret[5].name = NULL; ret[5].type = C_END; ret[5].sval = NULL; ret[5].ival = 0; return ret; } static game_params *custom_params(const config_item *cfg) { game_params *ret = snew(game_params); ret->width = atoi(cfg[0].sval); ret->height = atoi(cfg[1].sval); ret->wrapping = cfg[2].ival; ret->barrier_probability = (float)atof(cfg[3].sval); ret->unique = cfg[4].ival; return ret; } static char *validate_params(const game_params *params, int full) { if (params->width <= 0 || params->height <= 0) return "Width and height must both be greater than zero"; if (params->width <= 1 && params->height <= 1) return "At least one of width and height must be greater than one"; if (params->barrier_probability < 0) return "Barrier probability may not be negative"; if (params->barrier_probability > 1) return "Barrier probability may not be greater than 1"; /* * Specifying either grid dimension as 2 in a wrapping puzzle * makes it actually impossible to ensure a unique puzzle * solution. * * Proof: * * Without loss of generality, let us assume the puzzle _width_ * is 2, so we can conveniently discuss rows without having to * say `rows/columns' all the time. (The height may be 2 as * well, but that doesn't matter.) * * In each row, there are two edges between tiles: the inner * edge (running down the centre of the grid) and the outer * edge (the identified left and right edges of the grid). * * Lemma: In any valid 2xn puzzle there must be at least one * row in which _exactly one_ of the inner edge and outer edge * is connected. * * Proof: No row can have _both_ inner and outer edges * connected, because this would yield a loop. So the only * other way to falsify the lemma is for every row to have * _neither_ the inner nor outer edge connected. But this * means there is no connection at all between the left and * right columns of the puzzle, so there are two disjoint * subgraphs, which is also disallowed. [] * * Given such a row, it is always possible to make the * disconnected edge connected and the connected edge * disconnected without changing the state of any other edge. * (This is easily seen by case analysis on the various tiles: * left-pointing and right-pointing endpoints can be exchanged, * likewise T-pieces, and a corner piece can select its * horizontal connectivity independently of its vertical.) This * yields a distinct valid solution. * * Thus, for _every_ row in which exactly one of the inner and * outer edge is connected, there are two valid states for that * row, and hence the total number of solutions of the puzzle * is at least 2^(number of such rows), and in particular is at * least 2 since there must be at least one such row. [] */ if (full && params->unique && params->wrapping && (params->width == 2 || params->height == 2)) return "No wrapping puzzle with a width or height of 2 can have" " a unique solution"; return NULL; } /* ---------------------------------------------------------------------- * Solver used to assure solution uniqueness during generation. */ /* * Test cases I used while debugging all this were * * ./net --generate 1 13x11w#12300 * which expands under the non-unique grid generation rules to * 13x11w:5eaade1bd222664436d5e2965c12656b1129dd825219e3274d558d5eb2dab5da18898e571d5a2987be79746bd95726c597447d6da96188c513add829da7681da954db113d3cd244 * and has two ambiguous areas. * * An even better one is * 13x11w#507896411361192 * which expands to * 13x11w:b7125b1aec598eb31bd58d82572bc11494e5dee4e8db2bdd29b88d41a16bdd996d2996ddec8c83741a1e8674e78328ba71737b8894a9271b1cd1399453d1952e43951d9b712822e * and has an ambiguous area _and_ a situation where loop avoidance * is a necessary deductive technique. * * Then there's * 48x25w#820543338195187 * becoming * 48x25w:255989d14cdd185deaa753a93821a12edc1ab97943ac127e2685d7b8b3c48861b2192416139212b316eddd35de43714ebc7628d753db32e596284d9ec52c5a7dc1b4c811a655117d16dc28921b2b4161352cab1d89d18bc836b8b891d55ea4622a1251861b5bc9a8aa3e5bcd745c95229ca6c3b5e21d5832d397e917325793d7eb442dc351b2db2a52ba8e1651642275842d8871d5534aabc6d5b741aaa2d48ed2a7dbbb3151ddb49d5b9a7ed1ab98ee75d613d656dbba347bc514c84556b43a9bc65a3256ead792488b862a9d2a8a39b4255a4949ed7dbd79443292521265896b4399c95ede89d7c8c797a6a57791a849adea489359a158aa12e5dacce862b8333b7ebea7d344d1a3c53198864b73a9dedde7b663abb1b539e1e8853b1b7edb14a2a17ebaae4dbe63598a2e7e9a2dbdad415bc1d8cb88cbab5a8c82925732cd282e641ea3bd7d2c6e776de9117a26be86deb7c82c89524b122cb9397cd1acd2284e744ea62b9279bae85479ababe315c3ac29c431333395b24e6a1e3c43a2da42d4dce84aadd5b154aea555eaddcbd6e527d228c19388d9b424d94214555a7edbdeebe569d4a56dc51a86bd9963e377bb74752bd5eaa5761ba545e297b62a1bda46ab4aee423ad6c661311783cc18786d4289236563cb4a75ec67d481c14814994464cd1b87396dee63e5ab6e952cc584baa1d4c47cb557ec84dbb63d487c8728118673a166846dd3a4ebc23d6cb9c5827d96b4556e91899db32b517eda815ae271a8911bd745447121dc8d321557bc2a435ebec1bbac35b1a291669451174e6aa2218a4a9c5a6ca31ebc45d84e3a82c121e9ced7d55e9a * which has a spot (far right) where slightly more complex loop * avoidance is required. */ struct todo { unsigned char *marked; int *buffer; int buflen; int head, tail; }; static struct todo *todo_new(int maxsize) { struct todo *todo = snew(struct todo); todo->marked = snewn(maxsize, unsigned char); memset(todo->marked, 0, maxsize); todo->buflen = maxsize + 1; todo->buffer = snewn(todo->buflen, int); todo->head = todo->tail = 0; return todo; } static void todo_free(struct todo *todo) { sfree(todo->marked); sfree(todo->buffer); sfree(todo); } static void todo_add(struct todo *todo, int index) { if (todo->marked[index]) return; /* already on the list */ todo->marked[index] = TRUE; todo->buffer[todo->tail++] = index; if (todo->tail == todo->buflen) todo->tail = 0; } static int todo_get(struct todo *todo) { int ret; if (todo->head == todo->tail) return -1; /* list is empty */ ret = todo->buffer[todo->head++]; if (todo->head == todo->buflen) todo->head = 0; todo->marked[ret] = FALSE; return ret; } static int net_solver(int w, int h, unsigned char *tiles, unsigned char *barriers, int wrapping) { unsigned char *tilestate; unsigned char *edgestate; int *deadends; int *equivalence; struct todo *todo; int i, j, x, y; int area; int done_something; /* * Set up the solver's data structures. */ /* * tilestate stores the possible orientations of each tile. * There are up to four of these, so we'll index the array in * fours. tilestate[(y * w + x) * 4] and its three successive * members give the possible orientations, clearing to 255 from * the end as things are ruled out. * * In this loop we also count up the area of the grid (which is * not _necessarily_ equal to w*h, because there might be one * or more blank squares present. This will never happen in a * grid generated _by_ this program, but it's worth keeping the * solver as general as possible.) */ tilestate = snewn(w * h * 4, unsigned char); area = 0; for (i = 0; i < w*h; i++) { tilestate[i * 4] = tiles[i] & 0xF; for (j = 1; j < 4; j++) { if (tilestate[i * 4 + j - 1] == 255 || A(tilestate[i * 4 + j - 1]) == tilestate[i * 4]) tilestate[i * 4 + j] = 255; else tilestate[i * 4 + j] = A(tilestate[i * 4 + j - 1]); } if (tiles[i] != 0) area++; } /* * edgestate stores the known state of each edge. It is 0 for * unknown, 1 for open (connected) and 2 for closed (not * connected). * * In principle we need only worry about each edge once each, * but in fact it's easier to track each edge twice so that we * can reference it from either side conveniently. Also I'm * going to allocate _five_ bytes per tile, rather than the * obvious four, so that I can index edgestate[(y*w+x) * 5 + d] * where d is 1,2,4,8 and they never overlap. */ edgestate = snewn((w * h - 1) * 5 + 9, unsigned char); memset(edgestate, 0, (w * h - 1) * 5 + 9); /* * deadends tracks which edges have dead ends on them. It is * indexed by tile and direction: deadends[(y*w+x) * 5 + d] * tells you whether heading out of tile (x,y) in direction d * can reach a limited amount of the grid. Values are area+1 * (no dead end known) or less than that (can reach _at most_ * this many other tiles by heading this way out of this tile). */ deadends = snewn((w * h - 1) * 5 + 9, int); for (i = 0; i < (w * h - 1) * 5 + 9; i++) deadends[i] = area+1; /* * equivalence tracks which sets of tiles are known to be * connected to one another, so we can avoid creating loops by * linking together tiles which are already linked through * another route. * * This is a disjoint set forest structure: equivalence[i] * contains the index of another member of the equivalence * class containing i, or contains i itself for precisely one * member in each such class. To find a representative member * of the equivalence class containing i, you keep replacing i * with equivalence[i] until it stops changing; then you go * _back_ along the same path and point everything on it * directly at the representative member so as to speed up * future searches. Then you test equivalence between tiles by * finding the representative of each tile and seeing if * they're the same; and you create new equivalence (merge * classes) by finding the representative of each tile and * setting equivalence[one]=the_other. */ equivalence = snew_dsf(w * h); /* * On a non-wrapping grid, we instantly know that all the edges * round the edge are closed. */ if (!wrapping) { for (i = 0; i < w; i++) { edgestate[i * 5 + 2] = edgestate[((h-1) * w + i) * 5 + 8] = 2; } for (i = 0; i < h; i++) { edgestate[(i * w + w-1) * 5 + 1] = edgestate[(i * w) * 5 + 4] = 2; } } /* * If we have barriers available, we can mark those edges as * closed too. */ if (barriers) { for (y = 0; y < h; y++) for (x = 0; x < w; x++) { int d; for (d = 1; d <= 8; d += d) { if (barriers[y*w+x] & d) { int x2, y2; /* * In principle the barrier list should already * contain each barrier from each side, but * let's not take chances with our internal * consistency. */ OFFSETWH(x2, y2, x, y, d, w, h); edgestate[(y*w+x) * 5 + d] = 2; edgestate[(y2*w+x2) * 5 + F(d)] = 2; } } } } /* * Since most deductions made by this solver are local (the * exception is loop avoidance, where joining two tiles * together on one side of the grid can theoretically permit a * fresh deduction on the other), we can address the scaling * problem inherent in iterating repeatedly over the entire * grid by instead working with a to-do list. */ todo = todo_new(w * h); /* * Main deductive loop. */ done_something = TRUE; /* prevent instant termination! */ while (1) { int index; /* * Take a tile index off the todo list and process it. */ index = todo_get(todo); if (index == -1) { /* * If we have run out of immediate things to do, we * have no choice but to scan the whole grid for * longer-range things we've missed. Hence, I now add * every square on the grid back on to the to-do list. * I also set `done_something' to FALSE at this point; * if we later come back here and find it still FALSE, * we will know we've scanned the entire grid without * finding anything new to do, and we can terminate. */ if (!done_something) break; for (i = 0; i < w*h; i++) todo_add(todo, i); done_something = FALSE; index = todo_get(todo); } y = index / w; x = index % w; { int d, ourclass = dsf_canonify(equivalence, y*w+x); int deadendmax[9]; deadendmax[1] = deadendmax[2] = deadendmax[4] = deadendmax[8] = 0; for (i = j = 0; i < 4 && tilestate[(y*w+x) * 4 + i] != 255; i++) { int valid; int nnondeadends, nondeadends[4], deadendtotal; int nequiv, equiv[5]; int val = tilestate[(y*w+x) * 4 + i]; valid = TRUE; nnondeadends = deadendtotal = 0; equiv[0] = ourclass; nequiv = 1; for (d = 1; d <= 8; d += d) { /* * Immediately rule out this orientation if it * conflicts with any known edge. */ if ((edgestate[(y*w+x) * 5 + d] == 1 && !(val & d)) || (edgestate[(y*w+x) * 5 + d] == 2 && (val & d))) valid = FALSE; if (val & d) { /* * Count up the dead-end statistics. */ if (deadends[(y*w+x) * 5 + d] <= area) { deadendtotal += deadends[(y*w+x) * 5 + d]; } else { nondeadends[nnondeadends++] = d; } /* * Ensure we aren't linking to any tiles, * through edges not already known to be * open, which create a loop. */ if (edgestate[(y*w+x) * 5 + d] == 0) { int c, k, x2, y2; OFFSETWH(x2, y2, x, y, d, w, h); c = dsf_canonify(equivalence, y2*w+x2); for (k = 0; k < nequiv; k++) if (c == equiv[k]) break; if (k == nequiv) equiv[nequiv++] = c; else valid = FALSE; } } } if (nnondeadends == 0) { /* * If this orientation links together dead-ends * with a total area of less than the entire * grid, it is invalid. * * (We add 1 to deadendtotal because of the * tile itself, of course; one tile linking * dead ends of size 2 and 3 forms a subnetwork * with a total area of 6, not 5.) */ if (deadendtotal > 0 && deadendtotal+1 < area) valid = FALSE; } else if (nnondeadends == 1) { /* * If this orientation links together one or * more dead-ends with precisely one * non-dead-end, then we may have to mark that * non-dead-end as a dead end going the other * way. However, it depends on whether all * other orientations share the same property. */ deadendtotal++; if (deadendmax[nondeadends[0]] < deadendtotal) deadendmax[nondeadends[0]] = deadendtotal; } else { /* * If this orientation links together two or * more non-dead-ends, then we can rule out the * possibility of putting in new dead-end * markings in those directions. */ int k; for (k = 0; k < nnondeadends; k++) deadendmax[nondeadends[k]] = area+1; } if (valid) tilestate[(y*w+x) * 4 + j++] = val; #ifdef SOLVER_DIAGNOSTICS else printf("ruling out orientation %x at %d,%d\n", val, x, y); #endif } assert(j > 0); /* we can't lose _all_ possibilities! */ if (j < i) { done_something = TRUE; /* * We have ruled out at least one tile orientation. * Make sure the rest are blanked. */ while (j < 4) tilestate[(y*w+x) * 4 + j++] = 255; } /* * Now go through the tile orientations again and see * if we've deduced anything new about any edges. */ { int a, o; a = 0xF; o = 0; for (i = 0; i < 4 && tilestate[(y*w+x) * 4 + i] != 255; i++) { a &= tilestate[(y*w+x) * 4 + i]; o |= tilestate[(y*w+x) * 4 + i]; } for (d = 1; d <= 8; d += d) if (edgestate[(y*w+x) * 5 + d] == 0) { int x2, y2, d2; OFFSETWH(x2, y2, x, y, d, w, h); d2 = F(d); if (a & d) { /* This edge is open in all orientations. */ #ifdef SOLVER_DIAGNOSTICS printf("marking edge %d,%d:%d open\n", x, y, d); #endif edgestate[(y*w+x) * 5 + d] = 1; edgestate[(y2*w+x2) * 5 + d2] = 1; dsf_merge(equivalence, y*w+x, y2*w+x2); done_something = TRUE; todo_add(todo, y2*w+x2); } else if (!(o & d)) { /* This edge is closed in all orientations. */ #ifdef SOLVER_DIAGNOSTICS printf("marking edge %d,%d:%d closed\n", x, y, d); #endif edgestate[(y*w+x) * 5 + d] = 2; edgestate[(y2*w+x2) * 5 + d2] = 2; done_something = TRUE; todo_add(todo, y2*w+x2); } } } /* * Now check the dead-end markers and see if any of * them has lowered from the real ones. */ for (d = 1; d <= 8; d += d) { int x2, y2, d2; OFFSETWH(x2, y2, x, y, d, w, h); d2 = F(d); if (deadendmax[d] > 0 && deadends[(y2*w+x2) * 5 + d2] > deadendmax[d]) { #ifdef SOLVER_DIAGNOSTICS printf("setting dead end value %d,%d:%d to %d\n", x2, y2, d2, deadendmax[d]); #endif deadends[(y2*w+x2) * 5 + d2] = deadendmax[d]; done_something = TRUE; todo_add(todo, y2*w+x2); } } } } /* * Mark all completely determined tiles as locked. */ j = TRUE; for (i = 0; i < w*h; i++) { if (tilestate[i * 4 + 1] == 255) { assert(tilestate[i * 4 + 0] != 255); tiles[i] = tilestate[i * 4] | LOCKED; } else { tiles[i] &= ~LOCKED; j = FALSE; } } /* * Free up working space. */ todo_free(todo); sfree(tilestate); sfree(edgestate); sfree(deadends); sfree(equivalence); return j; } /* ---------------------------------------------------------------------- * Randomly select a new game description. */ /* * Function to randomly perturb an ambiguous section in a grid, to * attempt to ensure unique solvability. */ static void perturb(int w, int h, unsigned char *tiles, int wrapping, random_state *rs, int startx, int starty, int startd) { struct xyd *perimeter, *perim2, *loop[2], looppos[2]; int nperim, perimsize, nloop[2], loopsize[2]; int x, y, d, i; /* * We know that the tile at (startx,starty) is part of an * ambiguous section, and we also know that its neighbour in * direction startd is fully specified. We begin by tracing all * the way round the ambiguous area. */ nperim = perimsize = 0; perimeter = NULL; x = startx; y = starty; d = startd; #ifdef PERTURB_DIAGNOSTICS printf("perturb %d,%d:%d\n", x, y, d); #endif do { int x2, y2, d2; if (nperim >= perimsize) { perimsize = perimsize * 3 / 2 + 32; perimeter = sresize(perimeter, perimsize, struct xyd); } perimeter[nperim].x = x; perimeter[nperim].y = y; perimeter[nperim].direction = d; nperim++; #ifdef PERTURB_DIAGNOSTICS printf("perimeter: %d,%d:%d\n", x, y, d); #endif /* * First, see if we can simply turn left from where we are * and find another locked square. */ d2 = A(d); OFFSETWH(x2, y2, x, y, d2, w, h); if ((!wrapping && (abs(x2-x) > 1 || abs(y2-y) > 1)) || (tiles[y2*w+x2] & LOCKED)) { d = d2; } else { /* * Failing that, step left into the new square and look * in front of us. */ x = x2; y = y2; OFFSETWH(x2, y2, x, y, d, w, h); if ((wrapping || (abs(x2-x) <= 1 && abs(y2-y) <= 1)) && !(tiles[y2*w+x2] & LOCKED)) { /* * And failing _that_, we're going to have to step * forward into _that_ square and look right at the * same locked square as we started with. */ x = x2; y = y2; d = C(d); } } } while (x != startx || y != starty || d != startd); /* * Our technique for perturbing this ambiguous area is to * search round its edge for a join we can make: that is, an * edge on the perimeter which is (a) not currently connected, * and (b) connecting it would not yield a full cross on either * side. Then we make that join, search round the network to * find the loop thus constructed, and sever the loop at a * randomly selected other point. */ perim2 = snewn(nperim, struct xyd); memcpy(perim2, perimeter, nperim * sizeof(struct xyd)); /* Shuffle the perimeter, so as to search it without directional bias. */ shuffle(perim2, nperim, sizeof(*perim2), rs); for (i = 0; i < nperim; i++) { int x2, y2; x = perim2[i].x; y = perim2[i].y; d = perim2[i].direction; OFFSETWH(x2, y2, x, y, d, w, h); if (!wrapping && (abs(x2-x) > 1 || abs(y2-y) > 1)) continue; /* can't link across non-wrapping border */ if (tiles[y*w+x] & d) continue; /* already linked in this direction! */ if (((tiles[y*w+x] | d) & 15) == 15) continue; /* can't turn this tile into a cross */ if (((tiles[y2*w+x2] | F(d)) & 15) == 15) continue; /* can't turn other tile into a cross */ /* * We've found the point at which we're going to make a new * link. */ #ifdef PERTURB_DIAGNOSTICS printf("linking %d,%d:%d\n", x, y, d); #endif tiles[y*w+x] |= d; tiles[y2*w+x2] |= F(d); break; } sfree(perim2); if (i == nperim) { sfree(perimeter); return; /* nothing we can do! */ } /* * Now we've constructed a new link, we need to find the entire * loop of which it is a part. * * In principle, this involves doing a complete search round * the network. However, I anticipate that in the vast majority * of cases the loop will be quite small, so what I'm going to * do is make _two_ searches round the network in parallel, one * keeping its metaphorical hand on the left-hand wall while * the other keeps its hand on the right. As soon as one of * them gets back to its starting point, I abandon the other. */ for (i = 0; i < 2; i++) { loopsize[i] = nloop[i] = 0; loop[i] = NULL; looppos[i].x = x; looppos[i].y = y; looppos[i].direction = d; } while (1) { for (i = 0; i < 2; i++) { int x2, y2, j; x = looppos[i].x; y = looppos[i].y; d = looppos[i].direction; OFFSETWH(x2, y2, x, y, d, w, h); /* * Add this path segment to the loop, unless it exactly * reverses the previous one on the loop in which case * we take it away again. */ #ifdef PERTURB_DIAGNOSTICS printf("looppos[%d] = %d,%d:%d\n", i, x, y, d); #endif if (nloop[i] > 0 && loop[i][nloop[i]-1].x == x2 && loop[i][nloop[i]-1].y == y2 && loop[i][nloop[i]-1].direction == F(d)) { #ifdef PERTURB_DIAGNOSTICS printf("removing path segment %d,%d:%d from loop[%d]\n", x2, y2, F(d), i); #endif nloop[i]--; } else { if (nloop[i] >= loopsize[i]) { loopsize[i] = loopsize[i] * 3 / 2 + 32; loop[i] = sresize(loop[i], loopsize[i], struct xyd); } #ifdef PERTURB_DIAGNOSTICS printf("adding path segment %d,%d:%d to loop[%d]\n", x, y, d, i); #endif loop[i][nloop[i]++] = looppos[i]; } #ifdef PERTURB_DIAGNOSTICS printf("tile at new location is %x\n", tiles[y2*w+x2] & 0xF); #endif d = F(d); for (j = 0; j < 4; j++) { if (i == 0) d = A(d); else d = C(d); #ifdef PERTURB_DIAGNOSTICS printf("trying dir %d\n", d); #endif if (tiles[y2*w+x2] & d) { looppos[i].x = x2; looppos[i].y = y2; looppos[i].direction = d; break; } } assert(j < 4); assert(nloop[i] > 0); if (looppos[i].x == loop[i][0].x && looppos[i].y == loop[i][0].y && looppos[i].direction == loop[i][0].direction) { #ifdef PERTURB_DIAGNOSTICS printf("loop %d finished tracking\n", i); #endif /* * Having found our loop, we now sever it at a * randomly chosen point - absolutely any will do - * which is not the one we joined it at to begin * with. Conveniently, the one we joined it at is * loop[i][0], so we just avoid that one. */ j = random_upto(rs, nloop[i]-1) + 1; x = loop[i][j].x; y = loop[i][j].y; d = loop[i][j].direction; OFFSETWH(x2, y2, x, y, d, w, h); tiles[y*w+x] &= ~d; tiles[y2*w+x2] &= ~F(d); break; } } if (i < 2) break; } sfree(loop[0]); sfree(loop[1]); /* * Finally, we must mark the entire disputed section as locked, * to prevent the perturb function being called on it multiple * times. * * To do this, we _sort_ the perimeter of the area. The * existing xyd_cmp function will arrange things into columns * for us, in such a way that each column has the edges in * vertical order. Then we can work down each column and fill * in all the squares between an up edge and a down edge. */ qsort(perimeter, nperim, sizeof(struct xyd), xyd_cmp); x = y = -1; for (i = 0; i <= nperim; i++) { if (i == nperim || perimeter[i].x > x) { /* * Fill in everything from the last Up edge to the * bottom of the grid, if necessary. */ if (x != -1) { while (y < h) { #ifdef PERTURB_DIAGNOSTICS printf("resolved: locking tile %d,%d\n", x, y); #endif tiles[y * w + x] |= LOCKED; y++; } x = y = -1; } if (i == nperim) break; x = perimeter[i].x; y = 0; } if (perimeter[i].direction == U) { x = perimeter[i].x; y = perimeter[i].y; } else if (perimeter[i].direction == D) { /* * Fill in everything from the last Up edge to here. */ assert(x == perimeter[i].x && y <= perimeter[i].y); while (y <= perimeter[i].y) { #ifdef PERTURB_DIAGNOSTICS printf("resolved: locking tile %d,%d\n", x, y); #endif tiles[y * w + x] |= LOCKED; y++; } x = y = -1; } } sfree(perimeter); } static int *compute_loops_inner(int w, int h, int wrapping, const unsigned char *tiles, const unsigned char *barriers); static char *new_game_desc(const game_params *params, random_state *rs, char **aux, int interactive) { tree234 *possibilities, *barriertree; int w, h, x, y, cx, cy, nbarriers; unsigned char *tiles, *barriers; char *desc, *p; w = params->width; h = params->height; cx = w / 2; cy = h / 2; tiles = snewn(w * h, unsigned char); barriers = snewn(w * h, unsigned char); begin_generation: memset(tiles, 0, w * h); memset(barriers, 0, w * h); /* * Construct the unshuffled grid. * * To do this, we simply start at the centre point, repeatedly * choose a random possibility out of the available ways to * extend a used square into an unused one, and do it. After * extending the third line out of a square, we remove the * fourth from the possibilities list to avoid any full-cross * squares (which would make the game too easy because they * only have one orientation). * * The slightly worrying thing is the avoidance of full-cross * squares. Can this cause our unsophisticated construction * algorithm to paint itself into a corner, by getting into a * situation where there are some unreached squares and the * only way to reach any of them is to extend a T-piece into a * full cross? * * Answer: no it can't, and here's a proof. * * Any contiguous group of such unreachable squares must be * surrounded on _all_ sides by T-pieces pointing away from the * group. (If not, then there is a square which can be extended * into one of the `unreachable' ones, and so it wasn't * unreachable after all.) In particular, this implies that * each contiguous group of unreachable squares must be * rectangular in shape (any deviation from that yields a * non-T-piece next to an `unreachable' square). * * So we have a rectangle of unreachable squares, with T-pieces * forming a solid border around the rectangle. The corners of * that border must be connected (since every tile connects all * the lines arriving in it), and therefore the border must * form a closed loop around the rectangle. * * But this can't have happened in the first place, since we * _know_ we've avoided creating closed loops! Hence, no such * situation can ever arise, and the naive grid construction * algorithm will guaranteeably result in a complete grid * containing no unreached squares, no full crosses _and_ no * closed loops. [] */ possibilities = newtree234(xyd_cmp_nc); if (cx+1 < w) add234(possibilities, new_xyd(cx, cy, R)); if (cy-1 >= 0) add234(possibilities, new_xyd(cx, cy, U)); if (cx-1 >= 0) add234(possibilities, new_xyd(cx, cy, L)); if (cy+1 < h) add234(possibilities, new_xyd(cx, cy, D)); while (count234(possibilities) > 0) { int i; struct xyd *xyd; int x1, y1, d1, x2, y2, d2, d; /* * Extract a randomly chosen possibility from the list. */ i = random_upto(rs, count234(possibilities)); xyd = delpos234(possibilities, i); x1 = xyd->x; y1 = xyd->y; d1 = xyd->direction; sfree(xyd); OFFSET(x2, y2, x1, y1, d1, params); d2 = F(d1); #ifdef GENERATION_DIAGNOSTICS printf("picked (%d,%d,%c) <-> (%d,%d,%c)\n", x1, y1, "0RU3L567D9abcdef"[d1], x2, y2, "0RU3L567D9abcdef"[d2]); #endif /* * Make the connection. (We should be moving to an as yet * unused tile.) */ index(params, tiles, x1, y1) |= d1; assert(index(params, tiles, x2, y2) == 0); index(params, tiles, x2, y2) |= d2; /* * If we have created a T-piece, remove its last * possibility. */ if (COUNT(index(params, tiles, x1, y1)) == 3) { struct xyd xyd1, *xydp; xyd1.x = x1; xyd1.y = y1; xyd1.direction = 0x0F ^ index(params, tiles, x1, y1); xydp = find234(possibilities, &xyd1, NULL); if (xydp) { #ifdef GENERATION_DIAGNOSTICS printf("T-piece; removing (%d,%d,%c)\n", xydp->x, xydp->y, "0RU3L567D9abcdef"[xydp->direction]); #endif del234(possibilities, xydp); sfree(xydp); } } /* * Remove all other possibilities that were pointing at the * tile we've just moved into. */ for (d = 1; d < 0x10; d <<= 1) { int x3, y3, d3; struct xyd xyd1, *xydp; OFFSET(x3, y3, x2, y2, d, params); d3 = F(d); xyd1.x = x3; xyd1.y = y3; xyd1.direction = d3; xydp = find234(possibilities, &xyd1, NULL); if (xydp) { #ifdef GENERATION_DIAGNOSTICS printf("Loop avoidance; removing (%d,%d,%c)\n", xydp->x, xydp->y, "0RU3L567D9abcdef"[xydp->direction]); #endif del234(possibilities, xydp); sfree(xydp); } } /* * Add new possibilities to the list for moving _out_ of * the tile we have just moved into. */ for (d = 1; d < 0x10; d <<= 1) { int x3, y3; if (d == d2) continue; /* we've got this one already */ if (!params->wrapping) { if (d == U && y2 == 0) continue; if (d == D && y2 == h-1) continue; if (d == L && x2 == 0) continue; if (d == R && x2 == w-1) continue; } OFFSET(x3, y3, x2, y2, d, params); if (index(params, tiles, x3, y3)) continue; /* this would create a loop */ #ifdef GENERATION_DIAGNOSTICS printf("New frontier; adding (%d,%d,%c)\n", x2, y2, "0RU3L567D9abcdef"[d]); #endif add234(possibilities, new_xyd(x2, y2, d)); } } /* Having done that, we should have no possibilities remaining. */ assert(count234(possibilities) == 0); freetree234(possibilities); if (params->unique) { int prevn = -1; /* * Run the solver to check unique solubility. */ while (!net_solver(w, h, tiles, NULL, params->wrapping)) { int n = 0; /* * We expect (in most cases) that most of the grid will * be uniquely specified already, and the remaining * ambiguous sections will be small and separate. So * our strategy is to find each individual such * section, and perform a perturbation on the network * in that area. */ for (y = 0; y < h; y++) for (x = 0; x < w; x++) { if (x+1 < w && ((tiles[y*w+x] ^ tiles[y*w+x+1]) & LOCKED)) { n++; if (tiles[y*w+x] & LOCKED) perturb(w, h, tiles, params->wrapping, rs, x+1, y, L); else perturb(w, h, tiles, params->wrapping, rs, x, y, R); } if (y+1 < h && ((tiles[y*w+x] ^ tiles[(y+1)*w+x]) & LOCKED)) { n++; if (tiles[y*w+x] & LOCKED) perturb(w, h, tiles, params->wrapping, rs, x, y+1, U); else perturb(w, h, tiles, params->wrapping, rs, x, y, D); } } /* * Now n counts the number of ambiguous sections we * have fiddled with. If we haven't managed to decrease * it from the last time we ran the solver, give up and * regenerate the entire grid. */ if (prevn != -1 && prevn <= n) goto begin_generation; /* (sorry) */ prevn = n; } /* * The solver will have left a lot of LOCKED bits lying * around in the tiles array. Remove them. */ for (x = 0; x < w*h; x++) tiles[x] &= ~LOCKED; } /* * Now compute a list of the possible barrier locations. */ barriertree = newtree234(xyd_cmp_nc); for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { if (!(index(params, tiles, x, y) & R) && (params->wrapping || x < w-1)) add234(barriertree, new_xyd(x, y, R)); if (!(index(params, tiles, x, y) & D) && (params->wrapping || y < h-1)) add234(barriertree, new_xyd(x, y, D)); } } /* * Save the unshuffled grid in aux. */ { char *solution; int i; solution = snewn(w * h + 1, char); for (i = 0; i < w * h; i++) solution[i] = "0123456789abcdef"[tiles[i] & 0xF]; solution[w*h] = '\0'; *aux = solution; } /* * Now shuffle the grid. * * In order to avoid accidentally generating an already-solved * grid, we will reshuffle as necessary to ensure that at least * one edge has a mismatched connection. * * This can always be done, since validate_params() enforces a * grid area of at least 2 and our generator never creates * either type of rotationally invariant tile (cross and * blank). Hence there must be at least one edge separating * distinct tiles, and it must be possible to find orientations * of those tiles such that one tile is trying to connect * through that edge and the other is not. * * (We could be more subtle, and allow the shuffle to generate * a grid in which all tiles match up locally and the only * criterion preventing the grid from being already solved is * connectedness. However, that would take more effort, and * it's easier to simply make sure every grid is _obviously_ * not solved.) * * We also require that our shuffle produces no loops in the * initial grid state, because it's a bit rude to light up a 'HEY, * YOU DID SOMETHING WRONG!' indicator when the user hasn't even * had a chance to do _anything_ yet. This also is possible just * by retrying the whole shuffle on failure, because it's clear * that at least one non-solved shuffle with no loops must exist. * (Proof: take the _solved_ state of the puzzle, and rotate one * endpoint.) */ while (1) { int mismatches, prev_loopsquares, this_loopsquares, i; int *loops; shuffle: for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { int orig = index(params, tiles, x, y); int rot = random_upto(rs, 4); index(params, tiles, x, y) = ROT(orig, rot); } } /* * Check for loops, and try to fix them by reshuffling just * the squares involved. */ prev_loopsquares = w*h+1; while (1) { loops = compute_loops_inner(w, h, params->wrapping, tiles, NULL); this_loopsquares = 0; for (i = 0; i < w*h; i++) { if (loops[i]) { int orig = tiles[i]; int rot = random_upto(rs, 4); tiles[i] = ROT(orig, rot); this_loopsquares++; } } sfree(loops); if (this_loopsquares > prev_loopsquares) { /* * We're increasing rather than reducing the number of * loops. Give up and go back to the full shuffle. */ goto shuffle; } if (this_loopsquares == 0) break; prev_loopsquares = this_loopsquares; } mismatches = 0; /* * I can't even be bothered to check for mismatches across * a wrapping edge, so I'm just going to enforce that there * must be a mismatch across a non-wrapping edge, which is * still always possible. */ for (y = 0; y < h; y++) for (x = 0; x < w; x++) { if (x+1 < w && ((ROT(index(params, tiles, x, y), 2) ^ index(params, tiles, x+1, y)) & L)) mismatches++; if (y+1 < h && ((ROT(index(params, tiles, x, y), 2) ^ index(params, tiles, x, y+1)) & U)) mismatches++; } if (mismatches == 0) continue; /* OK. */ break; } /* * And now choose barrier locations. (We carefully do this * _after_ shuffling, so that changing the barrier rate in the * params while keeping the random seed the same will give the * same shuffled grid and _only_ change the barrier locations. * Also the way we choose barrier locations, by repeatedly * choosing one possibility from the list until we have enough, * is designed to ensure that raising the barrier rate while * keeping the seed the same will provide a superset of the * previous barrier set - i.e. if you ask for 10 barriers, and * then decide that's still too hard and ask for 20, you'll get * the original 10 plus 10 more, rather than getting 20 new * ones and the chance of remembering your first 10.) */ nbarriers = (int)(params->barrier_probability * count234(barriertree)); assert(nbarriers >= 0 && nbarriers <= count234(barriertree)); while (nbarriers > 0) { int i; struct xyd *xyd; int x1, y1, d1, x2, y2, d2; /* * Extract a randomly chosen barrier from the list. */ i = random_upto(rs, count234(barriertree)); xyd = delpos234(barriertree, i); assert(xyd != NULL); x1 = xyd->x; y1 = xyd->y; d1 = xyd->direction; sfree(xyd); OFFSET(x2, y2, x1, y1, d1, params); d2 = F(d1); index(params, barriers, x1, y1) |= d1; index(params, barriers, x2, y2) |= d2; nbarriers--; } /* * Clean up the rest of the barrier list. */ { struct xyd *xyd; while ( (xyd = delpos234(barriertree, 0)) != NULL) sfree(xyd); freetree234(barriertree); } /* * Finally, encode the grid into a string game description. * * My syntax is extremely simple: each square is encoded as a * hex digit in which bit 0 means a connection on the right, * bit 1 means up, bit 2 left and bit 3 down. (i.e. the same * encoding as used internally). Each digit is followed by * optional barrier indicators: `v' means a vertical barrier to * the right of it, and `h' means a horizontal barrier below * it. */ desc = snewn(w * h * 3 + 1, char); p = desc; for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { *p++ = "0123456789abcdef"[index(params, tiles, x, y)]; if ((params->wrapping || x < w-1) && (index(params, barriers, x, y) & R)) *p++ = 'v'; if ((params->wrapping || y < h-1) && (index(params, barriers, x, y) & D)) *p++ = 'h'; } } assert(p - desc <= w*h*3); *p = '\0'; sfree(tiles); sfree(barriers); return desc; } static char *validate_desc(const game_params *params, const char *desc) { int w = params->width, h = params->height; int i; for (i = 0; i < w*h; i++) { if (*desc >= '0' && *desc <= '9') /* OK */; else if (*desc >= 'a' && *desc <= 'f') /* OK */; else if (*desc >= 'A' && *desc <= 'F') /* OK */; else if (!*desc) return "Game description shorter than expected"; else return "Game description contained unexpected character"; desc++; while (*desc == 'h' || *desc == 'v') desc++; } if (*desc) return "Game description longer than expected"; return NULL; } /* ---------------------------------------------------------------------- * Construct an initial game state, given a description and parameters. */ static game_state *new_game(midend *me, const game_params *params, const char *desc) { game_state *state; int w, h, x, y; assert(params->width > 0 && params->height > 0); assert(params->width > 1 || params->height > 1); /* * Create a blank game state. */ state = snew(game_state); w = state->width = params->width; h = state->height = params->height; state->wrapping = params->wrapping; state->last_rotate_dir = state->last_rotate_x = state->last_rotate_y = 0; state->completed = state->used_solve = FALSE; state->tiles = snewn(state->width * state->height, unsigned char); memset(state->tiles, 0, state->width * state->height); state->barriers = snewn(state->width * state->height, unsigned char); memset(state->barriers, 0, state->width * state->height); /* * Parse the game description into the grid. */ for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { if (*desc >= '0' && *desc <= '9') tile(state, x, y) = *desc - '0'; else if (*desc >= 'a' && *desc <= 'f') tile(state, x, y) = *desc - 'a' + 10; else if (*desc >= 'A' && *desc <= 'F') tile(state, x, y) = *desc - 'A' + 10; if (*desc) desc++; while (*desc == 'h' || *desc == 'v') { int x2, y2, d1, d2; if (*desc == 'v') d1 = R; else d1 = D; OFFSET(x2, y2, x, y, d1, state); d2 = F(d1); barrier(state, x, y) |= d1; barrier(state, x2, y2) |= d2; desc++; } } } /* * Set up border barriers if this is a non-wrapping game. */ if (!state->wrapping) { for (x = 0; x < state->width; x++) { barrier(state, x, 0) |= U; barrier(state, x, state->height-1) |= D; } for (y = 0; y < state->height; y++) { barrier(state, 0, y) |= L; barrier(state, state->width-1, y) |= R; } } else { /* * We check whether this is de-facto a non-wrapping game * despite the parameters, in case we were passed the * description of a non-wrapping game. This is so that we * can change some aspects of the UI behaviour. */ state->wrapping = FALSE; for (x = 0; x < state->width; x++) if (!(barrier(state, x, 0) & U) || !(barrier(state, x, state->height-1) & D)) state->wrapping = TRUE; for (y = 0; y < state->height; y++) if (!(barrier(state, 0, y) & L) || !(barrier(state, state->width-1, y) & R)) state->wrapping = TRUE; } return state; } static game_state *dup_game(const game_state *state) { game_state *ret; ret = snew(game_state); ret->width = state->width; ret->height = state->height; ret->wrapping = state->wrapping; ret->completed = state->completed; ret->used_solve = state->used_solve; ret->last_rotate_dir = state->last_rotate_dir; ret->last_rotate_x = state->last_rotate_x; ret->last_rotate_y = state->last_rotate_y; ret->tiles = snewn(state->width * state->height, unsigned char); memcpy(ret->tiles, state->tiles, state->width * state->height); ret->barriers = snewn(state->width * state->height, unsigned char); memcpy(ret->barriers, state->barriers, state->width * state->height); return ret; } static void free_game(game_state *state) { sfree(state->tiles); sfree(state->barriers); sfree(state); } static char *solve_game(const game_state *state, const game_state *currstate, const char *aux, char **error) { unsigned char *tiles; char *ret; int retlen, retsize; int i; tiles = snewn(state->width * state->height, unsigned char); if (!aux) { /* * Run the internal solver on the provided grid. This might * not yield a complete solution. */ memcpy(tiles, state->tiles, state->width * state->height); net_solver(state->width, state->height, tiles, state->barriers, state->wrapping); } else { for (i = 0; i < state->width * state->height; i++) { int c = aux[i]; if (c >= '0' && c <= '9') tiles[i] = c - '0'; else if (c >= 'a' && c <= 'f') tiles[i] = c - 'a' + 10; else if (c >= 'A' && c <= 'F') tiles[i] = c - 'A' + 10; tiles[i] |= LOCKED; } } /* * Now construct a string which can be passed to execute_move() * to transform the current grid into the solved one. */ retsize = 256; ret = snewn(retsize, char); retlen = 0; ret[retlen++] = 'S'; for (i = 0; i < state->width * state->height; i++) { int from = currstate->tiles[i], to = tiles[i]; int ft = from & (R|L|U|D), tt = to & (R|L|U|D); int x = i % state->width, y = i / state->width; int chr = '\0'; char buf[80], *p = buf; if (from == to) continue; /* nothing needs doing at all */ /* * To transform this tile into the desired tile: first * unlock the tile if it's locked, then rotate it if * necessary, then lock it if necessary. */ if (from & LOCKED) p += sprintf(p, ";L%d,%d", x, y); if (tt == A(ft)) chr = 'A'; else if (tt == C(ft)) chr = 'C'; else if (tt == F(ft)) chr = 'F'; else { assert(tt == ft); chr = '\0'; } if (chr) p += sprintf(p, ";%c%d,%d", chr, x, y); if (to & LOCKED) p += sprintf(p, ";L%d,%d", x, y); if (p > buf) { if (retlen + (p - buf) >= retsize) { retsize = retlen + (p - buf) + 512; ret = sresize(ret, retsize, char); } memcpy(ret+retlen, buf, p - buf); retlen += p - buf; } } assert(retlen < retsize); ret[retlen] = '\0'; ret = sresize(ret, retlen+1, char); sfree(tiles); return ret; } static int game_can_format_as_text_now(const game_params *params) { return TRUE; } static char *game_text_format(const game_state *state) { return NULL; } /* ---------------------------------------------------------------------- * Utility routine. */ /* * Compute which squares are reachable from the centre square, as a * quick visual aid to determining how close the game is to * completion. This is also a simple way to tell if the game _is_ * completed - just call this function and see whether every square * is marked active. */ static unsigned char *compute_active(const game_state *state, int cx, int cy) { unsigned char *active; tree234 *todo; struct xyd *xyd; active = snewn(state->width * state->height, unsigned char); memset(active, 0, state->width * state->height); /* * We only store (x,y) pairs in todo, but it's easier to reuse * xyd_cmp and just store direction 0 every time. */ todo = newtree234(xyd_cmp_nc); index(state, active, cx, cy) = ACTIVE; add234(todo, new_xyd(cx, cy, 0)); while ( (xyd = delpos234(todo, 0)) != NULL) { int x1, y1, d1, x2, y2, d2; x1 = xyd->x; y1 = xyd->y; sfree(xyd); for (d1 = 1; d1 < 0x10; d1 <<= 1) { OFFSET(x2, y2, x1, y1, d1, state); d2 = F(d1); /* * If the next tile in this direction is connected to * us, and there isn't a barrier in the way, and it * isn't already marked active, then mark it active and * add it to the to-examine list. */ if ((tile(state, x1, y1) & d1) && (tile(state, x2, y2) & d2) && !(barrier(state, x1, y1) & d1) && !index(state, active, x2, y2)) { index(state, active, x2, y2) = ACTIVE; add234(todo, new_xyd(x2, y2, 0)); } } } /* Now we expect the todo list to have shrunk to zero size. */ assert(count234(todo) == 0); freetree234(todo); return active; } struct net_neighbour_ctx { int w, h; const unsigned char *tiles, *barriers; int i, n, neighbours[4]; }; static int net_neighbour(int vertex, void *vctx) { struct net_neighbour_ctx *ctx = (struct net_neighbour_ctx *)vctx; if (vertex >= 0) { int x = vertex % ctx->w, y = vertex / ctx->w; int tile, dir, x1, y1, v1; ctx->i = ctx->n = 0; tile = ctx->tiles[vertex]; if (ctx->barriers) tile &= ~ctx->barriers[vertex]; for (dir = 1; dir < 0x10; dir <<= 1) { if (!(tile & dir)) continue; OFFSETWH(x1, y1, x, y, dir, ctx->w, ctx->h); v1 = y1 * ctx->w + x1; if (ctx->tiles[v1] & F(dir)) ctx->neighbours[ctx->n++] = v1; } } if (ctx->i < ctx->n) return ctx->neighbours[ctx->i++]; else return -1; } static int *compute_loops_inner(int w, int h, int wrapping, const unsigned char *tiles, const unsigned char *barriers) { struct net_neighbour_ctx ctx; struct findloopstate *fls; int *loops; int x, y; fls = findloop_new_state(w*h); ctx.w = w; ctx.h = h; ctx.tiles = tiles; ctx.barriers = barriers; findloop_run(fls, w*h, net_neighbour, &ctx); loops = snewn(w*h, int); for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { int x1, y1, dir; int flags = 0; for (dir = 1; dir < 0x10; dir <<= 1) { if ((tiles[y*w+x] & dir) && !(barriers && (barriers[y*w+x] & dir))) { OFFSETWH(x1, y1, x, y, dir, w, h); if ((tiles[y1*w+x1] & F(dir)) && findloop_is_loop_edge(fls, y*w+x, y1*w+x1)) flags |= LOOP(dir); } } loops[y*w+x] = flags; } } findloop_free_state(fls); return loops; } static int *compute_loops(const game_state *state) { return compute_loops_inner(state->width, state->height, state->wrapping, state->tiles, state->barriers); } struct game_ui { int org_x, org_y; /* origin */ int cx, cy; /* source tile (game coordinates) */ int cur_x, cur_y; int cur_visible; random_state *rs; /* used for jumbling */ #ifdef USE_DRAGGING int dragtilex, dragtiley, dragstartx, dragstarty, dragged; #endif }; static game_ui *new_ui(const game_state *state) { void *seed; int seedsize; game_ui *ui = snew(game_ui); ui->org_x = ui->org_y = 0; ui->cur_x = ui->cx = state->width / 2; ui->cur_y = ui->cy = state->height / 2; ui->cur_visible = FALSE; get_random_seed(&seed, &seedsize); ui->rs = random_new(seed, seedsize); sfree(seed); return ui; } static void free_ui(game_ui *ui) { random_free(ui->rs); sfree(ui); } static char *encode_ui(const game_ui *ui) { char buf[120]; /* * We preserve the origin and centre-point coordinates over a * serialise. */ sprintf(buf, "O%d,%d;C%d,%d", ui->org_x, ui->org_y, ui->cx, ui->cy); return dupstr(buf); } static void decode_ui(game_ui *ui, const char *encoding) { sscanf(encoding, "O%d,%d;C%d,%d", &ui->org_x, &ui->org_y, &ui->cx, &ui->cy); } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { } struct game_drawstate { int started; int width, height; int org_x, org_y; int tilesize; int *visible; }; /* ---------------------------------------------------------------------- * Process a move. */ static char *interpret_move(const game_state *state, game_ui *ui, const game_drawstate *ds, int x, int y, int button) { char *nullret; int tx = -1, ty = -1, dir = 0; int shift = button & MOD_SHFT, ctrl = button & MOD_CTRL; enum { NONE, ROTATE_LEFT, ROTATE_180, ROTATE_RIGHT, TOGGLE_LOCK, JUMBLE, MOVE_ORIGIN, MOVE_SOURCE, MOVE_ORIGIN_AND_SOURCE, MOVE_CURSOR } action; button &= ~MOD_MASK; nullret = NULL; action = NONE; if (button == LEFT_BUTTON || button == MIDDLE_BUTTON || #ifdef USE_DRAGGING button == LEFT_DRAG || button == LEFT_RELEASE || button == RIGHT_DRAG || button == RIGHT_RELEASE || #endif button == RIGHT_BUTTON) { if (ui->cur_visible) { ui->cur_visible = FALSE; nullret = ""; } /* * The button must have been clicked on a valid tile. */ x -= WINDOW_OFFSET + TILE_BORDER; y -= WINDOW_OFFSET + TILE_BORDER; if (x < 0 || y < 0) return nullret; tx = x / TILE_SIZE; ty = y / TILE_SIZE; if (tx >= state->width || ty >= state->height) return nullret; /* Transform from physical to game coords */ tx = (tx + ui->org_x) % state->width; ty = (ty + ui->org_y) % state->height; if (x % TILE_SIZE >= TILE_SIZE - TILE_BORDER || y % TILE_SIZE >= TILE_SIZE - TILE_BORDER) return nullret; #ifdef USE_DRAGGING if (button == MIDDLE_BUTTON #ifdef STYLUS_BASED || button == RIGHT_BUTTON /* with a stylus, `right-click' locks */ #endif ) { /* * Middle button never drags: it only toggles the lock. */ action = TOGGLE_LOCK; } else if (button == LEFT_BUTTON #ifndef STYLUS_BASED || button == RIGHT_BUTTON /* (see above) */ #endif ) { /* * Otherwise, we note down the start point for a drag. */ ui->dragtilex = tx; ui->dragtiley = ty; ui->dragstartx = x % TILE_SIZE; ui->dragstarty = y % TILE_SIZE; ui->dragged = FALSE; return nullret; /* no actual action */ } else if (button == LEFT_DRAG #ifndef STYLUS_BASED || button == RIGHT_DRAG #endif ) { /* * Find the new drag point and see if it necessitates a * rotation. */ int x0,y0, xA,yA, xC,yC, xF,yF; int mx, my; int d0, dA, dC, dF, dmin; tx = ui->dragtilex; ty = ui->dragtiley; mx = x - (ui->dragtilex * TILE_SIZE); my = y - (ui->dragtiley * TILE_SIZE); x0 = ui->dragstartx; y0 = ui->dragstarty; xA = ui->dragstarty; yA = TILE_SIZE-1 - ui->dragstartx; xF = TILE_SIZE-1 - ui->dragstartx; yF = TILE_SIZE-1 - ui->dragstarty; xC = TILE_SIZE-1 - ui->dragstarty; yC = ui->dragstartx; d0 = (mx-x0)*(mx-x0) + (my-y0)*(my-y0); dA = (mx-xA)*(mx-xA) + (my-yA)*(my-yA); dF = (mx-xF)*(mx-xF) + (my-yF)*(my-yF); dC = (mx-xC)*(mx-xC) + (my-yC)*(my-yC); dmin = min(min(d0,dA),min(dF,dC)); if (d0 == dmin) { return nullret; } else if (dF == dmin) { action = ROTATE_180; ui->dragstartx = xF; ui->dragstarty = yF; ui->dragged = TRUE; } else if (dA == dmin) { action = ROTATE_LEFT; ui->dragstartx = xA; ui->dragstarty = yA; ui->dragged = TRUE; } else /* dC == dmin */ { action = ROTATE_RIGHT; ui->dragstartx = xC; ui->dragstarty = yC; ui->dragged = TRUE; } } else if (button == LEFT_RELEASE #ifndef STYLUS_BASED || button == RIGHT_RELEASE #endif ) { if (!ui->dragged) { /* * There was a click but no perceptible drag: * revert to single-click behaviour. */ tx = ui->dragtilex; ty = ui->dragtiley; if (button == LEFT_RELEASE) action = ROTATE_LEFT; else action = ROTATE_RIGHT; } else return nullret; /* no action */ } #else /* USE_DRAGGING */ action = (button == LEFT_BUTTON ? ROTATE_LEFT : button == RIGHT_BUTTON ? ROTATE_RIGHT : TOGGLE_LOCK); #endif /* USE_DRAGGING */ } else if (IS_CURSOR_MOVE(button)) { switch (button) { case CURSOR_UP: dir = U; break; case CURSOR_DOWN: dir = D; break; case CURSOR_LEFT: dir = L; break; case CURSOR_RIGHT: dir = R; break; default: return nullret; } if (shift && ctrl) action = MOVE_ORIGIN_AND_SOURCE; else if (shift) action = MOVE_ORIGIN; else if (ctrl) action = MOVE_SOURCE; else action = MOVE_CURSOR; } else if (button == 'a' || button == 's' || button == 'd' || button == 'A' || button == 'S' || button == 'D' || button == 'f' || button == 'F' || IS_CURSOR_SELECT(button)) { tx = ui->cur_x; ty = ui->cur_y; if (button == 'a' || button == 'A' || button == CURSOR_SELECT) action = ROTATE_LEFT; else if (button == 's' || button == 'S' || button == CURSOR_SELECT2) action = TOGGLE_LOCK; else if (button == 'd' || button == 'D') action = ROTATE_RIGHT; else if (button == 'f' || button == 'F') action = ROTATE_180; ui->cur_visible = TRUE; } else if (button == 'j' || button == 'J') { /* XXX should we have some mouse control for this? */ action = JUMBLE; } else return nullret; /* * The middle button locks or unlocks a tile. (A locked tile * cannot be turned, and is visually marked as being locked. * This is a convenience for the player, so that once they are * sure which way round a tile goes, they can lock it and thus * avoid forgetting later on that they'd already done that one; * and the locking also prevents them turning the tile by * accident. If they change their mind, another middle click * unlocks it.) */ if (action == TOGGLE_LOCK) { char buf[80]; sprintf(buf, "L%d,%d", tx, ty); return dupstr(buf); } else if (action == ROTATE_LEFT || action == ROTATE_RIGHT || action == ROTATE_180) { char buf[80]; /* * The left and right buttons have no effect if clicked on a * locked tile. */ if (tile(state, tx, ty) & LOCKED) return nullret; /* * Otherwise, turn the tile one way or the other. Left button * turns anticlockwise; right button turns clockwise. */ sprintf(buf, "%c%d,%d", (int)(action == ROTATE_LEFT ? 'A' : action == ROTATE_RIGHT ? 'C' : 'F'), tx, ty); return dupstr(buf); } else if (action == JUMBLE) { /* * Jumble all unlocked tiles to random orientations. */ int jx, jy, maxlen; char *ret, *p; /* * Maximum string length assumes no int can be converted to * decimal and take more than 11 digits! */ maxlen = state->width * state->height * 25 + 3; ret = snewn(maxlen, char); p = ret; *p++ = 'J'; for (jy = 0; jy < state->height; jy++) { for (jx = 0; jx < state->width; jx++) { if (!(tile(state, jx, jy) & LOCKED)) { int rot = random_upto(ui->rs, 4); if (rot) { p += sprintf(p, ";%c%d,%d", "AFC"[rot-1], jx, jy); } } } } *p++ = '\0'; assert(p - ret < maxlen); ret = sresize(ret, p - ret, char); return ret; } else if (action == MOVE_ORIGIN || action == MOVE_SOURCE || action == MOVE_ORIGIN_AND_SOURCE || action == MOVE_CURSOR) { assert(dir != 0); if (action == MOVE_ORIGIN || action == MOVE_ORIGIN_AND_SOURCE) { if (state->wrapping) { OFFSET(ui->org_x, ui->org_y, ui->org_x, ui->org_y, dir, state); } else return nullret; /* disallowed for non-wrapping grids */ } if (action == MOVE_SOURCE || action == MOVE_ORIGIN_AND_SOURCE) { OFFSET(ui->cx, ui->cy, ui->cx, ui->cy, dir, state); } if (action == MOVE_CURSOR) { OFFSET(ui->cur_x, ui->cur_y, ui->cur_x, ui->cur_y, dir, state); ui->cur_visible = TRUE; } return ""; } else { return NULL; } } static game_state *execute_move(const game_state *from, const char *move) { game_state *ret; int tx = -1, ty = -1, n, noanim, orig; ret = dup_game(from); if (move[0] == 'J' || move[0] == 'S') { if (move[0] == 'S') ret->used_solve = TRUE; move++; if (*move == ';') move++; noanim = TRUE; } else noanim = FALSE; ret->last_rotate_dir = 0; /* suppress animation */ ret->last_rotate_x = ret->last_rotate_y = 0; while (*move) { if ((move[0] == 'A' || move[0] == 'C' || move[0] == 'F' || move[0] == 'L') && sscanf(move+1, "%d,%d%n", &tx, &ty, &n) >= 2 && tx >= 0 && tx < from->width && ty >= 0 && ty < from->height) { orig = tile(ret, tx, ty); if (move[0] == 'A') { tile(ret, tx, ty) = A(orig); if (!noanim) ret->last_rotate_dir = +1; } else if (move[0] == 'F') { tile(ret, tx, ty) = F(orig); if (!noanim) ret->last_rotate_dir = +2; /* + for sake of argument */ } else if (move[0] == 'C') { tile(ret, tx, ty) = C(orig); if (!noanim) ret->last_rotate_dir = -1; } else { assert(move[0] == 'L'); tile(ret, tx, ty) ^= LOCKED; } move += 1 + n; if (*move == ';') move++; } else { free_game(ret); return NULL; } } if (!noanim) { if (tx == -1 || ty == -1) { free_game(ret); return NULL; } ret->last_rotate_x = tx; ret->last_rotate_y = ty; } /* * Check whether the game has been completed. * * For this purpose it doesn't matter where the source square is, * because we can start from anywhere (or, at least, any square * that's non-empty!), and correctly determine whether the game is * completed. */ { unsigned char *active; int pos; int complete = TRUE; for (pos = 0; pos < ret->width * ret->height; pos++) if (ret->tiles[pos] & 0xF) break; if (pos < ret->width * ret->height) { active = compute_active(ret, pos % ret->width, pos / ret->width); for (pos = 0; pos < ret->width * ret->height; pos++) if ((ret->tiles[pos] & 0xF) && !active[pos]) { complete = FALSE; break; } sfree(active); } if (complete) ret->completed = TRUE; } return ret; } /* ---------------------------------------------------------------------- * Routines for drawing the game position on the screen. */ static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { game_drawstate *ds = snew(game_drawstate); int i; ds->started = FALSE; ds->width = state->width; ds->height = state->height; ds->org_x = ds->org_y = -1; ds->visible = snewn(state->width * state->height, int); ds->tilesize = 0; /* undecided yet */ for (i = 0; i < state->width * state->height; i++) ds->visible[i] = -1; return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { sfree(ds->visible); sfree(ds); } static void game_compute_size(const game_params *params, int tilesize, int *x, int *y) { *x = WINDOW_OFFSET * 2 + tilesize * params->width + TILE_BORDER; *y = WINDOW_OFFSET * 2 + tilesize * params->height + TILE_BORDER; } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { ds->tilesize = tilesize; } static float *game_colours(frontend *fe, int *ncolours) { float *ret; ret = snewn(NCOLOURS * 3, float); *ncolours = NCOLOURS; /* * Basic background colour is whatever the front end thinks is * a sensible default. */ frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]); /* * Wires are black. */ ret[COL_WIRE * 3 + 0] = 0.0F; ret[COL_WIRE * 3 + 1] = 0.0F; ret[COL_WIRE * 3 + 2] = 0.0F; /* * Powered wires and powered endpoints are cyan. */ ret[COL_POWERED * 3 + 0] = 0.0F; ret[COL_POWERED * 3 + 1] = 1.0F; ret[COL_POWERED * 3 + 2] = 1.0F; /* * Barriers are red. */ ret[COL_BARRIER * 3 + 0] = 1.0F; ret[COL_BARRIER * 3 + 1] = 0.0F; ret[COL_BARRIER * 3 + 2] = 0.0F; /* * Highlighted loops are red as well. */ ret[COL_LOOP * 3 + 0] = 1.0F; ret[COL_LOOP * 3 + 1] = 0.0F; ret[COL_LOOP * 3 + 2] = 0.0F; /* * Unpowered endpoints are blue. */ ret[COL_ENDPOINT * 3 + 0] = 0.0F; ret[COL_ENDPOINT * 3 + 1] = 0.0F; ret[COL_ENDPOINT * 3 + 2] = 1.0F; /* * Tile borders are a darker grey than the background. */ ret[COL_BORDER * 3 + 0] = 0.5F * ret[COL_BACKGROUND * 3 + 0]; ret[COL_BORDER * 3 + 1] = 0.5F * ret[COL_BACKGROUND * 3 + 1]; ret[COL_BORDER * 3 + 2] = 0.5F * ret[COL_BACKGROUND * 3 + 2]; /* * Locked tiles are a grey in between those two. */ ret[COL_LOCKED * 3 + 0] = 0.75F * ret[COL_BACKGROUND * 3 + 0]; ret[COL_LOCKED * 3 + 1] = 0.75F * ret[COL_BACKGROUND * 3 + 1]; ret[COL_LOCKED * 3 + 2] = 0.75F * ret[COL_BACKGROUND * 3 + 2]; return ret; } static void draw_filled_line(drawing *dr, int x1, int y1, int x2, int y2, int colour) { draw_line(dr, x1-1, y1, x2-1, y2, COL_WIRE); draw_line(dr, x1+1, y1, x2+1, y2, COL_WIRE); draw_line(dr, x1, y1-1, x2, y2-1, COL_WIRE); draw_line(dr, x1, y1+1, x2, y2+1, COL_WIRE); draw_line(dr, x1, y1, x2, y2, colour); } static void draw_rect_coords(drawing *dr, int x1, int y1, int x2, int y2, int colour) { int mx = (x1 < x2 ? x1 : x2); int my = (y1 < y2 ? y1 : y2); int dx = (x2 + x1 - 2*mx + 1); int dy = (y2 + y1 - 2*my + 1); draw_rect(dr, mx, my, dx, dy, colour); } /* * draw_barrier_corner() and draw_barrier() are passed physical coords */ static void draw_barrier_corner(drawing *dr, game_drawstate *ds, int x, int y, int dx, int dy, int phase) { int bx = WINDOW_OFFSET + TILE_SIZE * x; int by = WINDOW_OFFSET + TILE_SIZE * y; int x1, y1; x1 = (dx > 0 ? TILE_SIZE+TILE_BORDER-1 : 0); y1 = (dy > 0 ? TILE_SIZE+TILE_BORDER-1 : 0); if (phase == 0) { draw_rect_coords(dr, bx+x1+dx, by+y1, bx+x1-TILE_BORDER*dx, by+y1-(TILE_BORDER-1)*dy, COL_WIRE); draw_rect_coords(dr, bx+x1, by+y1+dy, bx+x1-(TILE_BORDER-1)*dx, by+y1-TILE_BORDER*dy, COL_WIRE); } else { draw_rect_coords(dr, bx+x1, by+y1, bx+x1-(TILE_BORDER-1)*dx, by+y1-(TILE_BORDER-1)*dy, COL_BARRIER); } } static void draw_barrier(drawing *dr, game_drawstate *ds, int x, int y, int dir, int phase) { int bx = WINDOW_OFFSET + TILE_SIZE * x; int by = WINDOW_OFFSET + TILE_SIZE * y; int x1, y1, w, h; x1 = (X(dir) > 0 ? TILE_SIZE : X(dir) == 0 ? TILE_BORDER : 0); y1 = (Y(dir) > 0 ? TILE_SIZE : Y(dir) == 0 ? TILE_BORDER : 0); w = (X(dir) ? TILE_BORDER : TILE_SIZE - TILE_BORDER); h = (Y(dir) ? TILE_BORDER : TILE_SIZE - TILE_BORDER); if (phase == 0) { draw_rect(dr, bx+x1-X(dir), by+y1-Y(dir), w, h, COL_WIRE); } else { draw_rect(dr, bx+x1, by+y1, w, h, COL_BARRIER); } } /* * draw_tile() is passed physical coordinates */ static void draw_tile(drawing *dr, const game_state *state, game_drawstate *ds, int x, int y, int tile, int src, float angle, int cursor) { int bx = WINDOW_OFFSET + TILE_SIZE * x; int by = WINDOW_OFFSET + TILE_SIZE * y; float matrix[4]; float cx, cy, ex, ey, tx, ty; int dir, col, phase; /* * When we draw a single tile, we must draw everything up to * and including the borders around the tile. This means that * if the neighbouring tiles have connections to those borders, * we must draw those connections on the borders themselves. */ clip(dr, bx, by, TILE_SIZE+TILE_BORDER, TILE_SIZE+TILE_BORDER); /* * So. First blank the tile out completely: draw a big * rectangle in border colour, and a smaller rectangle in * background colour to fill it in. */ draw_rect(dr, bx, by, TILE_SIZE+TILE_BORDER, TILE_SIZE+TILE_BORDER, COL_BORDER); draw_rect(dr, bx+TILE_BORDER, by+TILE_BORDER, TILE_SIZE-TILE_BORDER, TILE_SIZE-TILE_BORDER, tile & LOCKED ? COL_LOCKED : COL_BACKGROUND); /* * Draw an inset outline rectangle as a cursor, in whichever of * COL_LOCKED and COL_BACKGROUND we aren't currently drawing * in. */ if (cursor) { draw_line(dr, bx+TILE_SIZE/8, by+TILE_SIZE/8, bx+TILE_SIZE/8, by+TILE_SIZE-TILE_SIZE/8, tile & LOCKED ? COL_BACKGROUND : COL_LOCKED); draw_line(dr, bx+TILE_SIZE/8, by+TILE_SIZE/8, bx+TILE_SIZE-TILE_SIZE/8, by+TILE_SIZE/8, tile & LOCKED ? COL_BACKGROUND : COL_LOCKED); draw_line(dr, bx+TILE_SIZE-TILE_SIZE/8, by+TILE_SIZE/8, bx+TILE_SIZE-TILE_SIZE/8, by+TILE_SIZE-TILE_SIZE/8, tile & LOCKED ? COL_BACKGROUND : COL_LOCKED); draw_line(dr, bx+TILE_SIZE/8, by+TILE_SIZE-TILE_SIZE/8, bx+TILE_SIZE-TILE_SIZE/8, by+TILE_SIZE-TILE_SIZE/8, tile & LOCKED ? COL_BACKGROUND : COL_LOCKED); } /* * Set up the rotation matrix. */ matrix[0] = (float)cos(angle * PI / 180.0); matrix[1] = (float)-sin(angle * PI / 180.0); matrix[2] = (float)sin(angle * PI / 180.0); matrix[3] = (float)cos(angle * PI / 180.0); /* * Draw the wires. */ cx = cy = TILE_BORDER + (TILE_SIZE-TILE_BORDER) / 2.0F - 0.5F; col = (tile & ACTIVE ? COL_POWERED : COL_WIRE); for (dir = 1; dir < 0x10; dir <<= 1) { if (tile & dir) { ex = (TILE_SIZE - TILE_BORDER - 1.0F) / 2.0F * X(dir); ey = (TILE_SIZE - TILE_BORDER - 1.0F) / 2.0F * Y(dir); MATMUL(tx, ty, matrix, ex, ey); draw_filled_line(dr, bx+(int)cx, by+(int)cy, bx+(int)(cx+tx), by+(int)(cy+ty), COL_WIRE); } } for (dir = 1; dir < 0x10; dir <<= 1) { if (tile & dir) { ex = (TILE_SIZE - TILE_BORDER - 1.0F) / 2.0F * X(dir); ey = (TILE_SIZE - TILE_BORDER - 1.0F) / 2.0F * Y(dir); MATMUL(tx, ty, matrix, ex, ey); draw_line(dr, bx+(int)cx, by+(int)cy, bx+(int)(cx+tx), by+(int)(cy+ty), (tile & LOOP(dir)) ? COL_LOOP : col); } } /* If we've drawn any loop-highlighted arms, make sure the centre * point is loop-coloured rather than a later arm overwriting it. */ if (tile & (RLOOP | ULOOP | LLOOP | DLOOP)) draw_rect(dr, bx+(int)cx, by+(int)cy, 1, 1, COL_LOOP); /* * Draw the box in the middle. We do this in blue if the tile * is an unpowered endpoint, in cyan if the tile is a powered * endpoint, in black if the tile is the centrepiece, and * otherwise not at all. */ col = -1; if (src) col = COL_WIRE; else if (COUNT(tile) == 1) { col = (tile & ACTIVE ? COL_POWERED : COL_ENDPOINT); } if (col >= 0) { int i, points[8]; points[0] = +1; points[1] = +1; points[2] = +1; points[3] = -1; points[4] = -1; points[5] = -1; points[6] = -1; points[7] = +1; for (i = 0; i < 8; i += 2) { ex = (TILE_SIZE * 0.24F) * points[i]; ey = (TILE_SIZE * 0.24F) * points[i+1]; MATMUL(tx, ty, matrix, ex, ey); points[i] = bx+(int)(cx+tx); points[i+1] = by+(int)(cy+ty); } draw_polygon(dr, points, 4, col, COL_WIRE); } /* * Draw the points on the border if other tiles are connected * to us. */ for (dir = 1; dir < 0x10; dir <<= 1) { int dx, dy, px, py, lx, ly, vx, vy, ox, oy; dx = X(dir); dy = Y(dir); ox = x + dx; oy = y + dy; if (ox < 0 || ox >= state->width || oy < 0 || oy >= state->height) continue; if (!(tile(state, GX(ox), GY(oy)) & F(dir))) continue; px = bx + (int)(dx>0 ? TILE_SIZE + TILE_BORDER - 1 : dx<0 ? 0 : cx); py = by + (int)(dy>0 ? TILE_SIZE + TILE_BORDER - 1 : dy<0 ? 0 : cy); lx = dx * (TILE_BORDER-1); ly = dy * (TILE_BORDER-1); vx = (dy ? 1 : 0); vy = (dx ? 1 : 0); if (angle == 0.0 && (tile & dir)) { /* * If we are fully connected to the other tile, we must * draw right across the tile border. (We can use our * own ACTIVE state to determine what colour to do this * in: if we are fully connected to the other tile then * the two ACTIVE states will be the same.) */ draw_rect_coords(dr, px-vx, py-vy, px+lx+vx, py+ly+vy, COL_WIRE); draw_rect_coords(dr, px, py, px+lx, py+ly, ((tile & LOOP(dir)) ? COL_LOOP : (tile & ACTIVE) ? COL_POWERED : COL_WIRE)); } else { /* * The other tile extends into our border, but isn't * actually connected to us. Just draw a single black * dot. */ draw_rect_coords(dr, px, py, px, py, COL_WIRE); } } /* * Draw barrier corners, and then barriers. */ for (phase = 0; phase < 2; phase++) { for (dir = 1; dir < 0x10; dir <<= 1) { int x1, y1, corner = FALSE; /* * If at least one barrier terminates at the corner * between dir and A(dir), draw a barrier corner. */ if (barrier(state, GX(x), GY(y)) & (dir | A(dir))) { corner = TRUE; } else { /* * Only count barriers terminating at this corner * if they're physically next to the corner. (That * is, if they've wrapped round from the far side * of the screen, they don't count.) */ x1 = x + X(dir); y1 = y + Y(dir); if (x1 >= 0 && x1 < state->width && y1 >= 0 && y1 < state->height && (barrier(state, GX(x1), GY(y1)) & A(dir))) { corner = TRUE; } else { x1 = x + X(A(dir)); y1 = y + Y(A(dir)); if (x1 >= 0 && x1 < state->width && y1 >= 0 && y1 < state->height && (barrier(state, GX(x1), GY(y1)) & dir)) corner = TRUE; } } if (corner) { /* * At least one barrier terminates here. Draw a * corner. */ draw_barrier_corner(dr, ds, x, y, X(dir)+X(A(dir)), Y(dir)+Y(A(dir)), phase); } } for (dir = 1; dir < 0x10; dir <<= 1) if (barrier(state, GX(x), GY(y)) & dir) draw_barrier(dr, ds, x, y, dir, phase); } unclip(dr); draw_update(dr, bx, by, TILE_SIZE+TILE_BORDER, TILE_SIZE+TILE_BORDER); } static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float t, float ft) { int x, y, tx, ty, frame, last_rotate_dir, moved_origin = FALSE; unsigned char *active; int *loops; float angle = 0.0; /* * Clear the screen, and draw the exterior barrier lines, if * this is our first call or if the origin has changed. */ if (!ds->started || ui->org_x != ds->org_x || ui->org_y != ds->org_y) { int phase; ds->started = TRUE; draw_rect(dr, 0, 0, WINDOW_OFFSET * 2 + TILE_SIZE * state->width + TILE_BORDER, WINDOW_OFFSET * 2 + TILE_SIZE * state->height + TILE_BORDER, COL_BACKGROUND); ds->org_x = ui->org_x; ds->org_y = ui->org_y; moved_origin = TRUE; draw_update(dr, 0, 0, WINDOW_OFFSET*2 + TILE_SIZE*state->width + TILE_BORDER, WINDOW_OFFSET*2 + TILE_SIZE*state->height + TILE_BORDER); for (phase = 0; phase < 2; phase++) { for (x = 0; x < ds->width; x++) { if (x+1 < ds->width) { if (barrier(state, GX(x), GY(0)) & R) draw_barrier_corner(dr, ds, x, -1, +1, +1, phase); if (barrier(state, GX(x), GY(ds->height-1)) & R) draw_barrier_corner(dr, ds, x, ds->height, +1, -1, phase); } if (barrier(state, GX(x), GY(0)) & U) { draw_barrier_corner(dr, ds, x, -1, -1, +1, phase); draw_barrier_corner(dr, ds, x, -1, +1, +1, phase); draw_barrier(dr, ds, x, -1, D, phase); } if (barrier(state, GX(x), GY(ds->height-1)) & D) { draw_barrier_corner(dr, ds, x, ds->height, -1, -1, phase); draw_barrier_corner(dr, ds, x, ds->height, +1, -1, phase); draw_barrier(dr, ds, x, ds->height, U, phase); } } for (y = 0; y < ds->height; y++) { if (y+1 < ds->height) { if (barrier(state, GX(0), GY(y)) & D) draw_barrier_corner(dr, ds, -1, y, +1, +1, phase); if (barrier(state, GX(ds->width-1), GY(y)) & D) draw_barrier_corner(dr, ds, ds->width, y, -1, +1, phase); } if (barrier(state, GX(0), GY(y)) & L) { draw_barrier_corner(dr, ds, -1, y, +1, -1, phase); draw_barrier_corner(dr, ds, -1, y, +1, +1, phase); draw_barrier(dr, ds, -1, y, R, phase); } if (barrier(state, GX(ds->width-1), GY(y)) & R) { draw_barrier_corner(dr, ds, ds->width, y, -1, -1, phase); draw_barrier_corner(dr, ds, ds->width, y, -1, +1, phase); draw_barrier(dr, ds, ds->width, y, L, phase); } } } } tx = ty = -1; last_rotate_dir = dir==-1 ? oldstate->last_rotate_dir : state->last_rotate_dir; if (oldstate && (t < ROTATE_TIME) && last_rotate_dir) { /* * We're animating a single tile rotation. Find the turning * tile. */ tx = (dir==-1 ? oldstate->last_rotate_x : state->last_rotate_x); ty = (dir==-1 ? oldstate->last_rotate_y : state->last_rotate_y); angle = last_rotate_dir * dir * 90.0F * (t / ROTATE_TIME); state = oldstate; } frame = -1; if (ft > 0) { /* * We're animating a completion flash. Find which frame * we're at. */ frame = (int)(ft / FLASH_FRAME); } /* * Draw any tile which differs from the way it was last drawn. */ active = compute_active(state, ui->cx, ui->cy); loops = compute_loops(state); for (x = 0; x < ds->width; x++) for (y = 0; y < ds->height; y++) { int c = tile(state, GX(x), GY(y)) | index(state, active, GX(x), GY(y)) | index(state, loops, GX(x), GY(y)); int is_src = GX(x) == ui->cx && GY(y) == ui->cy; int is_anim = GX(x) == tx && GY(y) == ty; int is_cursor = ui->cur_visible && GX(x) == ui->cur_x && GY(y) == ui->cur_y; /* * In a completion flash, we adjust the LOCKED bit * depending on our distance from the centre point and * the frame number. */ if (frame >= 0) { int rcx = RX(ui->cx), rcy = RY(ui->cy); int xdist, ydist, dist; xdist = (x < rcx ? rcx - x : x - rcx); ydist = (y < rcy ? rcy - y : y - rcy); dist = (xdist > ydist ? xdist : ydist); if (frame >= dist && frame < dist+4) { int lock = (frame - dist) & 1; lock = lock ? LOCKED : 0; c = (c &~ LOCKED) | lock; } } if (moved_origin || index(state, ds->visible, x, y) != c || index(state, ds->visible, x, y) == -1 || is_src || is_anim || is_cursor) { draw_tile(dr, state, ds, x, y, c, is_src, (is_anim ? angle : 0.0F), is_cursor); if (is_src || is_anim || is_cursor) index(state, ds->visible, x, y) = -1; else index(state, ds->visible, x, y) = c; } } /* * Update the status bar. */ { char statusbuf[256], *p; int i, n, n2, a; int complete = FALSE; p = statusbuf; *p = '\0'; /* ensure even an empty status string is terminated */ if (state->used_solve) { p += sprintf(p, "Auto-solved. "); complete = TRUE; } else if (state->completed) { p += sprintf(p, "COMPLETED! "); complete = TRUE; } /* * Omit the 'Active: n/N' counter completely if the source * tile is a completely empty one, because then the active * count can't help but read '1'. */ if (tile(state, ui->cx, ui->cy) & 0xF) { n = state->width * state->height; for (i = a = n2 = 0; i < n; i++) { if (active[i]) a++; if (state->tiles[i] & 0xF) n2++; } /* * Also, if we're displaying a completion indicator and * the game is still in its completed state (i.e. every * tile is active), we might as well omit this too. */ if (!complete || a < n2) p += sprintf(p, "Active: %d/%d", a, n2); } status_bar(dr, statusbuf); } sfree(active); sfree(loops); } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { int last_rotate_dir; /* * Don't animate if last_rotate_dir is zero. */ last_rotate_dir = dir==-1 ? oldstate->last_rotate_dir : newstate->last_rotate_dir; if (last_rotate_dir) return ROTATE_TIME; return 0.0F; } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { /* * If the game has just been completed, we display a completion * flash. */ if (!oldstate->completed && newstate->completed && !oldstate->used_solve && !newstate->used_solve) { int size = 0; if (size < newstate->width) size = newstate->width; if (size < newstate->height) size = newstate->height; return FLASH_FRAME * (size+4); } return 0.0F; } static int game_status(const game_state *state) { return state->completed ? +1 : 0; } static int game_timing_state(const game_state *state, game_ui *ui) { return TRUE; } static void game_print_size(const game_params *params, float *x, float *y) { int pw, ph; /* * I'll use 8mm squares by default. */ game_compute_size(params, 800, &pw, &ph); *x = pw / 100.0F; *y = ph / 100.0F; } static void draw_diagram(drawing *dr, game_drawstate *ds, int x, int y, int topleft, int v, int drawlines, int ink) { int tx, ty, cx, cy, r, br, k, thick; tx = WINDOW_OFFSET + TILE_SIZE * x; ty = WINDOW_OFFSET + TILE_SIZE * y; /* * Find our centre point. */ if (topleft) { cx = tx + (v & L ? TILE_SIZE / 4 : TILE_SIZE / 6); cy = ty + (v & U ? TILE_SIZE / 4 : TILE_SIZE / 6); r = TILE_SIZE / 8; br = TILE_SIZE / 32; } else { cx = tx + TILE_SIZE / 2; cy = ty + TILE_SIZE / 2; r = TILE_SIZE / 2; br = TILE_SIZE / 8; } thick = r / 20; /* * Draw the square block if we have an endpoint. */ if (v == 1 || v == 2 || v == 4 || v == 8) draw_rect(dr, cx - br, cy - br, br*2, br*2, ink); /* * Draw each radial line. */ if (drawlines) { for (k = 1; k < 16; k *= 2) if (v & k) { int x1 = min(cx, cx + (r-thick) * X(k)); int x2 = max(cx, cx + (r-thick) * X(k)); int y1 = min(cy, cy + (r-thick) * Y(k)); int y2 = max(cy, cy + (r-thick) * Y(k)); draw_rect(dr, x1 - thick, y1 - thick, (x2 - x1) + 2*thick, (y2 - y1) + 2*thick, ink); } } } static void game_print(drawing *dr, const game_state *state, int tilesize) { int w = state->width, h = state->height; int ink = print_mono_colour(dr, 0); int x, y; /* Ick: fake up `ds->tilesize' for macro expansion purposes */ game_drawstate ads, *ds = &ads; game_set_size(dr, ds, NULL, tilesize); /* * Border. */ print_line_width(dr, TILE_SIZE / (state->wrapping ? 128 : 12)); draw_rect_outline(dr, WINDOW_OFFSET, WINDOW_OFFSET, TILE_SIZE * w, TILE_SIZE * h, ink); /* * Grid. */ print_line_width(dr, TILE_SIZE / 128); for (x = 1; x < w; x++) draw_line(dr, WINDOW_OFFSET + TILE_SIZE * x, WINDOW_OFFSET, WINDOW_OFFSET + TILE_SIZE * x, WINDOW_OFFSET + TILE_SIZE * h, ink); for (y = 1; y < h; y++) draw_line(dr, WINDOW_OFFSET, WINDOW_OFFSET + TILE_SIZE * y, WINDOW_OFFSET + TILE_SIZE * w, WINDOW_OFFSET + TILE_SIZE * y, ink); /* * Barriers. */ for (y = 0; y <= h; y++) for (x = 0; x <= w; x++) { int b = barrier(state, x % w, y % h); if (x < w && (b & U)) draw_rect(dr, WINDOW_OFFSET + TILE_SIZE * x - TILE_SIZE/24, WINDOW_OFFSET + TILE_SIZE * y - TILE_SIZE/24, TILE_SIZE + TILE_SIZE/24 * 2, TILE_SIZE/24 * 2, ink); if (y < h && (b & L)) draw_rect(dr, WINDOW_OFFSET + TILE_SIZE * x - TILE_SIZE/24, WINDOW_OFFSET + TILE_SIZE * y - TILE_SIZE/24, TILE_SIZE/24 * 2, TILE_SIZE + TILE_SIZE/24 * 2, ink); } /* * Grid contents. */ for (y = 0; y < h; y++) for (x = 0; x < w; x++) { int vx, v = tile(state, x, y); int locked = v & LOCKED; v &= 0xF; /* * Rotate into a standard orientation for the top left * corner diagram. */ vx = v; while (vx != 0 && vx != 15 && vx != 1 && vx != 9 && vx != 13 && vx != 5) vx = A(vx); /* * Draw the top left corner diagram. */ draw_diagram(dr, ds, x, y, TRUE, vx, TRUE, ink); /* * Draw the real solution diagram, if we're doing so. */ draw_diagram(dr, ds, x, y, FALSE, v, locked, ink); } } #ifdef COMBINED #define thegame net #endif const struct game thegame = { "Net", "games.net", "net", default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, TRUE, solve_game, FALSE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, PREFERRED_TILE_SIZE, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, TRUE, FALSE, game_print_size, game_print, TRUE, /* wants_statusbar */ FALSE, game_timing_state, 0, /* flags */ }; puzzles-20170606.272beef/nestedvm.c0000644000175000017500000002433713115373615015673 0ustar simonsimon/* * nestedvm.c: NestedVM front end for my puzzle collection. */ #include #include #include #include #include #include #include #include #include "puzzles.h" extern void _pause(); extern int _call_java(int cmd, int arg1, int arg2, int arg3); void fatal(char *fmt, ...) { va_list ap; fprintf(stderr, "fatal error: "); va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, "\n"); exit(1); } struct frontend { // TODO kill unneeded members! midend *me; int timer_active; struct timeval last_time; config_item *cfg; int cfg_which, cfgret; int ox, oy, w, h; }; static frontend *_fe; void get_random_seed(void **randseed, int *randseedsize) { struct timeval *tvp = snew(struct timeval); gettimeofday(tvp, NULL); *randseed = (void *)tvp; *randseedsize = sizeof(struct timeval); } void frontend_default_colour(frontend *fe, float *output) { output[0] = output[1]= output[2] = 0.8f; } void nestedvm_status_bar(void *handle, char *text) { _call_java(4,0,(int)text,0); } void nestedvm_start_draw(void *handle) { frontend *fe = (frontend *)handle; _call_java(5, 0, fe->w, fe->h); _call_java(4, 1, fe->ox, fe->oy); } void nestedvm_clip(void *handle, int x, int y, int w, int h) { frontend *fe = (frontend *)handle; _call_java(5, w, h, 0); _call_java(4, 3, x + fe->ox, y + fe->oy); } void nestedvm_unclip(void *handle) { frontend *fe = (frontend *)handle; _call_java(4, 4, fe->ox, fe->oy); } void nestedvm_draw_text(void *handle, int x, int y, int fonttype, int fontsize, int align, int colour, char *text) { frontend *fe = (frontend *)handle; _call_java(5, x + fe->ox, y + fe->oy, (fonttype == FONT_FIXED ? 0x10 : 0x0) | align); _call_java(7, fontsize, colour, (int)text); } void nestedvm_draw_rect(void *handle, int x, int y, int w, int h, int colour) { frontend *fe = (frontend *)handle; _call_java(5, w, h, colour); _call_java(4, 5, x + fe->ox, y + fe->oy); } void nestedvm_draw_line(void *handle, int x1, int y1, int x2, int y2, int colour) { frontend *fe = (frontend *)handle; _call_java(5, x2 + fe->ox, y2 + fe->oy, colour); _call_java(4, 6, x1 + fe->ox, y1 + fe->oy); } void nestedvm_draw_poly(void *handle, int *coords, int npoints, int fillcolour, int outlinecolour) { frontend *fe = (frontend *)handle; int i; _call_java(4, 7, npoints, 0); for (i = 0; i < npoints; i++) { _call_java(6, i, coords[i*2] + fe->ox, coords[i*2+1] + fe->oy); } _call_java(4, 8, outlinecolour, fillcolour); } void nestedvm_draw_circle(void *handle, int cx, int cy, int radius, int fillcolour, int outlinecolour) { frontend *fe = (frontend *)handle; _call_java(5, cx+fe->ox, cy+fe->oy, radius); _call_java(4, 9, outlinecolour, fillcolour); } struct blitter { int handle, w, h, x, y; }; blitter *nestedvm_blitter_new(void *handle, int w, int h) { blitter *bl = snew(blitter); bl->handle = -1; bl->w = w; bl->h = h; return bl; } void nestedvm_blitter_free(void *handle, blitter *bl) { if (bl->handle != -1) _call_java(4, 11, bl->handle, 0); sfree(bl); } void nestedvm_blitter_save(void *handle, blitter *bl, int x, int y) { frontend *fe = (frontend *)handle; if (bl->handle == -1) bl->handle = _call_java(4,10,bl->w, bl->h); bl->x = x; bl->y = y; _call_java(8, bl->handle, x + fe->ox, y + fe->oy); } void nestedvm_blitter_load(void *handle, blitter *bl, int x, int y) { frontend *fe = (frontend *)handle; assert(bl->handle != -1); if (x == BLITTER_FROMSAVED && y == BLITTER_FROMSAVED) { x = bl->x; y = bl->y; } _call_java(9, bl->handle, x + fe->ox, y + fe->oy); } void nestedvm_end_draw(void *handle) { _call_java(4,2,0,0); } char *nestedvm_text_fallback(void *handle, const char *const *strings, int nstrings) { /* * We assume Java can cope with any UTF-8 likely to be emitted * by a puzzle. */ return dupstr(strings[0]); } const struct drawing_api nestedvm_drawing = { nestedvm_draw_text, nestedvm_draw_rect, nestedvm_draw_line, nestedvm_draw_poly, nestedvm_draw_circle, NULL, // draw_update, nestedvm_clip, nestedvm_unclip, nestedvm_start_draw, nestedvm_end_draw, nestedvm_status_bar, nestedvm_blitter_new, nestedvm_blitter_free, nestedvm_blitter_save, nestedvm_blitter_load, NULL, NULL, NULL, NULL, NULL, NULL, /* {begin,end}_{doc,page,puzzle} */ NULL, NULL, /* line_width, line_dotted */ nestedvm_text_fallback, }; int jcallback_key_event(int x, int y, int keyval) { frontend *fe = (frontend *)_fe; if (fe->ox == -1) return 1; if (keyval >= 0 && !midend_process_key(fe->me, x - fe->ox, y - fe->oy, keyval)) return 42; return 1; } int jcallback_resize(int width, int height) { frontend *fe = (frontend *)_fe; int x, y; x = width; y = height; midend_size(fe->me, &x, &y, TRUE); fe->ox = (width - x) / 2; fe->oy = (height - y) / 2; fe->w = x; fe->h = y; midend_force_redraw(fe->me); return 0; } int jcallback_timer_func() { frontend *fe = (frontend *)_fe; if (fe->timer_active) { struct timeval now; float elapsed; gettimeofday(&now, NULL); elapsed = ((now.tv_usec - fe->last_time.tv_usec) * 0.000001F + (now.tv_sec - fe->last_time.tv_sec)); midend_timer(fe->me, elapsed); /* may clear timer_active */ fe->last_time = now; } return fe->timer_active; } void deactivate_timer(frontend *fe) { if (fe->timer_active) _call_java(4, 13, 0, 0); fe->timer_active = FALSE; } void activate_timer(frontend *fe) { if (!fe->timer_active) { _call_java(4, 12, 0, 0); gettimeofday(&fe->last_time, NULL); } fe->timer_active = TRUE; } void jcallback_config_ok() { frontend *fe = (frontend *)_fe; char *err; err = midend_set_config(fe->me, fe->cfg_which, fe->cfg); if (err) _call_java(2, (int) "Error", (int)err, 1); else { fe->cfgret = TRUE; } } void jcallback_config_set_string(int item_ptr, int char_ptr) { config_item *i = (config_item *)item_ptr; char* newval = (char*) char_ptr; sfree(i->sval); i->sval = dupstr(newval); free(newval); } void jcallback_config_set_boolean(int item_ptr, int selected) { config_item *i = (config_item *)item_ptr; i->ival = selected != 0 ? TRUE : FALSE; } void jcallback_config_set_choice(int item_ptr, int selected) { config_item *i = (config_item *)item_ptr; i->ival = selected; } static int get_config(frontend *fe, int which) { char *title; config_item *i; fe->cfg = midend_get_config(fe->me, which, &title); fe->cfg_which = which; fe->cfgret = FALSE; _call_java(10, (int)title, 0, 0); for (i = fe->cfg; i->type != C_END; i++) { _call_java(5, (int)i, i->type, (int)i->name); _call_java(11, (int)i->sval, i->ival, 0); } _call_java(12,0,0,0); free_cfg(fe->cfg); return fe->cfgret; } int jcallback_menu_key_event(int key) { frontend *fe = (frontend *)_fe; if (!midend_process_key(fe->me, 0, 0, key)) return 42; return 0; } static void resize_fe(frontend *fe) { int x, y; x = INT_MAX; y = INT_MAX; midend_size(fe->me, &x, &y, FALSE); _call_java(3, x, y, 0); } int jcallback_preset_event(int ptr_game_params) { frontend *fe = (frontend *)_fe; game_params *params = (game_params *)ptr_game_params; midend_set_params(fe->me, params); midend_new_game(fe->me); resize_fe(fe); _call_java(13, midend_which_preset(fe->me), 0, 0); return 0; } int jcallback_solve_event() { frontend *fe = (frontend *)_fe; char *msg; msg = midend_solve(fe->me); if (msg) _call_java(2, (int) "Error", (int)msg, 1); return 0; } int jcallback_restart_event() { frontend *fe = (frontend *)_fe; midend_restart_game(fe->me); return 0; } int jcallback_config_event(int which) { frontend *fe = (frontend *)_fe; _call_java(13, midend_which_preset(fe->me), 0, 0); if (!get_config(fe, which)) return 0; midend_new_game(fe->me); resize_fe(fe); _call_java(13, midend_which_preset(fe->me), 0, 0); return 0; } int jcallback_about_event() { char titlebuf[256]; char textbuf[1024]; sprintf(titlebuf, "About %.200s", thegame.name); sprintf(textbuf, "%.200s\n\n" "from Simon Tatham's Portable Puzzle Collection\n\n" "%.500s", thegame.name, ver); _call_java(2, (int)&titlebuf, (int)&textbuf, 0); return 0; } void preset_menu_populate(struct preset_menu *menu, int menuid) { int i; for (i = 0; i < menu->n_entries; i++) { struct preset_menu_entry *entry = &menu->entries[i]; if (entry->params) { _call_java(5, (int)entry->params, 0, 0); _call_java(1, (int)entry->title, menuid, entry->id); } else { _call_java(5, 0, 0, 0); _call_java(1, (int)entry->title, menuid, entry->id); preset_menu_populate(entry->submenu, entry->id); } } } int main(int argc, char **argv) { int i, n; float* colours; _fe = snew(frontend); _fe->timer_active = FALSE; _fe->me = midend_new(_fe, &thegame, &nestedvm_drawing, _fe); if (argc > 1) midend_game_id(_fe->me, argv[1]); /* ignore failure */ midend_new_game(_fe->me); { struct preset_menu *menu; int nids, topmenu; menu = midend_get_presets(_fe->me, &nids); topmenu = _call_java(1, 0, nids, 0); preset_menu_populate(menu, topmenu); } colours = midend_colours(_fe->me, &n); _fe->ox = -1; _call_java(0, (int)thegame.name, (thegame.can_configure ? 1 : 0) | (midend_wants_statusbar(_fe->me) ? 2 : 0) | (thegame.can_solve ? 4 : 0), n); for (i = 0; i < n; i++) { _call_java(1024+ i, (int)(colours[i*3] * 0xFF), (int)(colours[i*3+1] * 0xFF), (int)(colours[i*3+2] * 0xFF)); } resize_fe(_fe); _call_java(13, midend_which_preset(_fe->me), 0, 0); // Now pause the vm. The VM will be call()ed when // an input event occurs. _pause(); // shut down when the VM is resumed. deactivate_timer(_fe); midend_free(_fe->me); return 0; } puzzles-20170606.272beef/misc.c0000644000175000017500000002565013115373615015000 0ustar simonsimon/* * misc.c: Miscellaneous helpful functions. */ #include #include #include #include #include "puzzles.h" void free_cfg(config_item *cfg) { config_item *i; for (i = cfg; i->type != C_END; i++) if (i->type == C_STRING) sfree(i->sval); sfree(cfg); } /* * The Mines (among others) game descriptions contain the location of every * mine, and can therefore be used to cheat. * * It would be pointless to attempt to _prevent_ this form of * cheating by encrypting the description, since Mines is * open-source so anyone can find out the encryption key. However, * I think it is worth doing a bit of gentle obfuscation to prevent * _accidental_ spoilers: if you happened to note that the game ID * starts with an F, for example, you might be unable to put the * knowledge of those mines out of your mind while playing. So, * just as discussions of film endings are rot13ed to avoid * spoiling it for people who don't want to be told, we apply a * keyless, reversible, but visually completely obfuscatory masking * function to the mine bitmap. */ void obfuscate_bitmap(unsigned char *bmp, int bits, int decode) { int bytes, firsthalf, secondhalf; struct step { unsigned char *seedstart; int seedlen; unsigned char *targetstart; int targetlen; } steps[2]; int i, j; /* * My obfuscation algorithm is similar in concept to the OAEP * encoding used in some forms of RSA. Here's a specification * of it: * * + We have a `masking function' which constructs a stream of * pseudorandom bytes from a seed of some number of input * bytes. * * + We pad out our input bit stream to a whole number of * bytes by adding up to 7 zero bits on the end. (In fact * the bitmap passed as input to this function will already * have had this done in practice.) * * + We divide the _byte_ stream exactly in half, rounding the * half-way position _down_. So an 81-bit input string, for * example, rounds up to 88 bits or 11 bytes, and then * dividing by two gives 5 bytes in the first half and 6 in * the second half. * * + We generate a mask from the second half of the bytes, and * XOR it over the first half. * * + We generate a mask from the (encoded) first half of the * bytes, and XOR it over the second half. Any null bits at * the end which were added as padding are cleared back to * zero even if this operation would have made them nonzero. * * To de-obfuscate, the steps are precisely the same except * that the final two are reversed. * * Finally, our masking function. Given an input seed string of * bytes, the output mask consists of concatenating the SHA-1 * hashes of the seed string and successive decimal integers, * starting from 0. */ bytes = (bits + 7) / 8; firsthalf = bytes / 2; secondhalf = bytes - firsthalf; steps[decode ? 1 : 0].seedstart = bmp + firsthalf; steps[decode ? 1 : 0].seedlen = secondhalf; steps[decode ? 1 : 0].targetstart = bmp; steps[decode ? 1 : 0].targetlen = firsthalf; steps[decode ? 0 : 1].seedstart = bmp; steps[decode ? 0 : 1].seedlen = firsthalf; steps[decode ? 0 : 1].targetstart = bmp + firsthalf; steps[decode ? 0 : 1].targetlen = secondhalf; for (i = 0; i < 2; i++) { SHA_State base, final; unsigned char digest[20]; char numberbuf[80]; int digestpos = 20, counter = 0; SHA_Init(&base); SHA_Bytes(&base, steps[i].seedstart, steps[i].seedlen); for (j = 0; j < steps[i].targetlen; j++) { if (digestpos >= 20) { sprintf(numberbuf, "%d", counter++); final = base; SHA_Bytes(&final, numberbuf, strlen(numberbuf)); SHA_Final(&final, digest); digestpos = 0; } steps[i].targetstart[j] ^= digest[digestpos++]; } /* * Mask off the pad bits in the final byte after both steps. */ if (bits % 8) bmp[bits / 8] &= 0xFF & (0xFF00 >> (bits % 8)); } } /* err, yeah, these two pretty much rely on unsigned char being 8 bits. * Platforms where this is not the case probably have bigger problems * than just making these two work, though... */ char *bin2hex(const unsigned char *in, int inlen) { char *ret = snewn(inlen*2 + 1, char), *p = ret; int i; for (i = 0; i < inlen*2; i++) { int v = in[i/2]; if (i % 2 == 0) v >>= 4; *p++ = "0123456789abcdef"[v & 0xF]; } *p = '\0'; return ret; } unsigned char *hex2bin(const char *in, int outlen) { unsigned char *ret = snewn(outlen, unsigned char); int i; memset(ret, 0, outlen*sizeof(unsigned char)); for (i = 0; i < outlen*2; i++) { int c = in[i]; int v; assert(c != 0); if (c >= '0' && c <= '9') v = c - '0'; else if (c >= 'a' && c <= 'f') v = c - 'a' + 10; else if (c >= 'A' && c <= 'F') v = c - 'A' + 10; else v = 0; ret[i / 2] |= v << (4 * (1 - (i % 2))); } return ret; } void game_mkhighlight_specific(frontend *fe, float *ret, int background, int highlight, int lowlight) { float max; int i; /* * Drop the background colour so that the highlight is * noticeably brighter than it while still being under 1. */ max = ret[background*3]; for (i = 1; i < 3; i++) if (ret[background*3+i] > max) max = ret[background*3+i]; if (max * 1.2F > 1.0F) { for (i = 0; i < 3; i++) ret[background*3+i] /= (max * 1.2F); } for (i = 0; i < 3; i++) { if (highlight >= 0) ret[highlight * 3 + i] = ret[background * 3 + i] * 1.2F; if (lowlight >= 0) ret[lowlight * 3 + i] = ret[background * 3 + i] * 0.8F; } } void game_mkhighlight(frontend *fe, float *ret, int background, int highlight, int lowlight) { frontend_default_colour(fe, &ret[background * 3]); game_mkhighlight_specific(fe, ret, background, highlight, lowlight); } static void memswap(void *av, void *bv, int size) { char tmpbuf[512]; char *a = av, *b = bv; while (size > 0) { int thislen = min(size, sizeof(tmpbuf)); memcpy(tmpbuf, a, thislen); memcpy(a, b, thislen); memcpy(b, tmpbuf, thislen); a += thislen; b += thislen; size -= thislen; } } void shuffle(void *array, int nelts, int eltsize, random_state *rs) { char *carray = (char *)array; int i; for (i = nelts; i-- > 1 ;) { int j = random_upto(rs, i+1); if (j != i) memswap(carray + eltsize * i, carray + eltsize * j, eltsize); } } void draw_rect_outline(drawing *dr, int x, int y, int w, int h, int colour) { int x0 = x, x1 = x+w-1, y0 = y, y1 = y+h-1; int coords[8]; coords[0] = x0; coords[1] = y0; coords[2] = x0; coords[3] = y1; coords[4] = x1; coords[5] = y1; coords[6] = x1; coords[7] = y0; draw_polygon(dr, coords, 4, -1, colour); } void draw_rect_corners(drawing *dr, int cx, int cy, int r, int col) { draw_line(dr, cx - r, cy - r, cx - r, cy - r/2, col); draw_line(dr, cx - r, cy - r, cx - r/2, cy - r, col); draw_line(dr, cx - r, cy + r, cx - r, cy + r/2, col); draw_line(dr, cx - r, cy + r, cx - r/2, cy + r, col); draw_line(dr, cx + r, cy - r, cx + r, cy - r/2, col); draw_line(dr, cx + r, cy - r, cx + r/2, cy - r, col); draw_line(dr, cx + r, cy + r, cx + r, cy + r/2, col); draw_line(dr, cx + r, cy + r, cx + r/2, cy + r, col); } void move_cursor(int button, int *x, int *y, int maxw, int maxh, int wrap) { int dx = 0, dy = 0; switch (button) { case CURSOR_UP: dy = -1; break; case CURSOR_DOWN: dy = 1; break; case CURSOR_RIGHT: dx = 1; break; case CURSOR_LEFT: dx = -1; break; default: return; } if (wrap) { *x = (*x + dx + maxw) % maxw; *y = (*y + dy + maxh) % maxh; } else { *x = min(max(*x+dx, 0), maxw - 1); *y = min(max(*y+dy, 0), maxh - 1); } } /* Used in netslide.c and sixteen.c for cursor movement around edge. */ int c2pos(int w, int h, int cx, int cy) { if (cy == -1) return cx; /* top row, 0 .. w-1 (->) */ else if (cx == w) return w + cy; /* R col, w .. w+h -1 (v) */ else if (cy == h) return w + h + (w-cx-1); /* bottom row, w+h .. w+h+w-1 (<-) */ else if (cx == -1) return w + h + w + (h-cy-1); /* L col, w+h+w .. w+h+w+h-1 (^) */ assert(!"invalid cursor pos!"); return -1; /* not reached */ } int c2diff(int w, int h, int cx, int cy, int button) { int diff = 0; assert(IS_CURSOR_MOVE(button)); /* Obvious moves around edge. */ if (cy == -1) diff = (button == CURSOR_RIGHT) ? +1 : (button == CURSOR_LEFT) ? -1 : diff; if (cy == h) diff = (button == CURSOR_RIGHT) ? -1 : (button == CURSOR_LEFT) ? +1 : diff; if (cx == -1) diff = (button == CURSOR_UP) ? +1 : (button == CURSOR_DOWN) ? -1 : diff; if (cx == w) diff = (button == CURSOR_UP) ? -1 : (button == CURSOR_DOWN) ? +1 : diff; if (button == CURSOR_LEFT && cx == w && (cy == 0 || cy == h-1)) diff = (cy == 0) ? -1 : +1; if (button == CURSOR_RIGHT && cx == -1 && (cy == 0 || cy == h-1)) diff = (cy == 0) ? +1 : -1; if (button == CURSOR_DOWN && cy == -1 && (cx == 0 || cx == w-1)) diff = (cx == 0) ? -1 : +1; if (button == CURSOR_UP && cy == h && (cx == 0 || cx == w-1)) diff = (cx == 0) ? +1 : -1; debug(("cx,cy = %d,%d; w%d h%d, diff = %d", cx, cy, w, h, diff)); return diff; } void pos2c(int w, int h, int pos, int *cx, int *cy) { int max = w+h+w+h; pos = (pos + max) % max; if (pos < w) { *cx = pos; *cy = -1; return; } pos -= w; if (pos < h) { *cx = w; *cy = pos; return; } pos -= h; if (pos < w) { *cx = w-pos-1; *cy = h; return; } pos -= w; if (pos < h) { *cx = -1; *cy = h-pos-1; return; } assert(!"invalid pos, huh?"); /* limited by % above! */ } void draw_text_outline(drawing *dr, int x, int y, int fonttype, int fontsize, int align, int text_colour, int outline_colour, char *text) { if (outline_colour > -1) { draw_text(dr, x-1, y, fonttype, fontsize, align, outline_colour, text); draw_text(dr, x+1, y, fonttype, fontsize, align, outline_colour, text); draw_text(dr, x, y-1, fonttype, fontsize, align, outline_colour, text); draw_text(dr, x, y+1, fonttype, fontsize, align, outline_colour, text); } draw_text(dr, x, y, fonttype, fontsize, align, text_colour, text); } /* kludge for sprintf() in Rockbox not supporting "%-8.8s" */ void copy_left_justified(char *buf, size_t sz, const char *str) { size_t len = strlen(str); assert(sz > 0); memset(buf, ' ', sz - 1); assert(len <= sz - 1); memcpy(buf, str, len); buf[sz - 1] = 0; } /* vim: set shiftwidth=4 tabstop=8: */ puzzles-20170606.272beef/mines.c0000644000175000017500000024605313115373615015162 0ustar simonsimon/* * mines.c: Minesweeper clone with sophisticated grid generation. * * Still TODO: * * - think about configurably supporting question marks. Once, * that is, we've thought about configurability in general! */ #include #include #include #include #include #include #include "tree234.h" #include "puzzles.h" enum { COL_BACKGROUND, COL_BACKGROUND2, COL_1, COL_2, COL_3, COL_4, COL_5, COL_6, COL_7, COL_8, COL_MINE, COL_BANG, COL_CROSS, COL_FLAG, COL_FLAGBASE, COL_QUERY, COL_HIGHLIGHT, COL_LOWLIGHT, COL_WRONGNUMBER, COL_CURSOR, NCOLOURS }; #define PREFERRED_TILE_SIZE 20 #define TILE_SIZE (ds->tilesize) #ifdef SMALL_SCREEN #define BORDER 8 #else #define BORDER (TILE_SIZE * 3 / 2) #endif #define HIGHLIGHT_WIDTH (TILE_SIZE / 10) #define OUTER_HIGHLIGHT_WIDTH (BORDER / 10) #define COORD(x) ( (x) * TILE_SIZE + BORDER ) #define FROMCOORD(x) ( ((x) - BORDER + TILE_SIZE) / TILE_SIZE - 1 ) #define FLASH_FRAME 0.13F struct game_params { int w, h, n; int unique; }; struct mine_layout { /* * This structure is shared between all the game_states for a * given instance of the puzzle, so we reference-count it. */ int refcount; char *mines; /* * If we haven't yet actually generated the mine layout, here's * all the data we will need to do so. */ int n, unique; random_state *rs; midend *me; /* to give back the new game desc */ }; struct game_state { int w, h, n, dead, won; int used_solve; struct mine_layout *layout; /* real mine positions */ signed char *grid; /* player knowledge */ /* * Each item in the `grid' array is one of the following values: * * - 0 to 8 mean the square is open and has a surrounding mine * count. * * - -1 means the square is marked as a mine. * * - -2 means the square is unknown. * * - -3 means the square is marked with a question mark * (FIXME: do we even want to bother with this?). * * - 64 means the square has had a mine revealed when the game * was lost. * * - 65 means the square had a mine revealed and this was the * one the player hits. * * - 66 means the square has a crossed-out mine because the * player had incorrectly marked it. */ }; static game_params *default_params(void) { game_params *ret = snew(game_params); ret->w = ret->h = 9; ret->n = 10; ret->unique = TRUE; return ret; } static const struct game_params mines_presets[] = { {9, 9, 10, TRUE}, {9, 9, 35, TRUE}, {16, 16, 40, TRUE}, {16, 16, 99, TRUE}, #ifndef SMALL_SCREEN {30, 16, 99, TRUE}, {30, 16, 170, TRUE}, #endif }; static int game_fetch_preset(int i, char **name, game_params **params) { game_params *ret; char str[80]; if (i < 0 || i >= lenof(mines_presets)) return FALSE; ret = snew(game_params); *ret = mines_presets[i]; sprintf(str, "%dx%d, %d mines", ret->w, ret->h, ret->n); *name = dupstr(str); *params = ret; return TRUE; } static void free_params(game_params *params) { sfree(params); } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } static void decode_params(game_params *params, char const *string) { char const *p = string; params->w = atoi(p); while (*p && isdigit((unsigned char)*p)) p++; if (*p == 'x') { p++; params->h = atoi(p); while (*p && isdigit((unsigned char)*p)) p++; } else { params->h = params->w; } if (*p == 'n') { p++; params->n = atoi(p); while (*p && (*p == '.' || isdigit((unsigned char)*p))) p++; } else { params->n = params->w * params->h / 10; } while (*p) { if (*p == 'a') { p++; params->unique = FALSE; } else p++; /* skip any other gunk */ } } static char *encode_params(const game_params *params, int full) { char ret[400]; int len; len = sprintf(ret, "%dx%d", params->w, params->h); /* * Mine count is a generation-time parameter, since it can be * deduced from the mine bitmap! */ if (full) len += sprintf(ret+len, "n%d", params->n); if (full && !params->unique) ret[len++] = 'a'; assert(len < lenof(ret)); ret[len] = '\0'; return dupstr(ret); } static config_item *game_configure(const game_params *params) { config_item *ret; char buf[80]; ret = snewn(5, config_item); ret[0].name = "Width"; ret[0].type = C_STRING; sprintf(buf, "%d", params->w); ret[0].sval = dupstr(buf); ret[0].ival = 0; ret[1].name = "Height"; ret[1].type = C_STRING; sprintf(buf, "%d", params->h); ret[1].sval = dupstr(buf); ret[1].ival = 0; ret[2].name = "Mines"; ret[2].type = C_STRING; sprintf(buf, "%d", params->n); ret[2].sval = dupstr(buf); ret[2].ival = 0; ret[3].name = "Ensure solubility"; ret[3].type = C_BOOLEAN; ret[3].sval = NULL; ret[3].ival = params->unique; ret[4].name = NULL; ret[4].type = C_END; ret[4].sval = NULL; ret[4].ival = 0; return ret; } static game_params *custom_params(const config_item *cfg) { game_params *ret = snew(game_params); ret->w = atoi(cfg[0].sval); ret->h = atoi(cfg[1].sval); ret->n = atoi(cfg[2].sval); if (strchr(cfg[2].sval, '%')) ret->n = ret->n * (ret->w * ret->h) / 100; ret->unique = cfg[3].ival; return ret; } static char *validate_params(const game_params *params, int full) { /* * Lower limit on grid size: each dimension must be at least 3. * 1 is theoretically workable if rather boring, but 2 is a * real problem: there is often _no_ way to generate a uniquely * solvable 2xn Mines grid. You either run into two mines * blocking the way and no idea what's behind them, or one mine * and no way to know which of the two rows it's in. If the * mine count is even you can create a soluble grid by packing * all the mines at one end (so what when you hit a two-mine * wall there are only as many covered squares left as there * are mines); but if it's odd, you are doomed, because you * _have_ to have a gap somewhere which you can't determine the * position of. */ if (full && params->unique && (params->w <= 2 || params->h <= 2)) return "Width and height must both be greater than two"; if (params->n > params->w * params->h - 9) return "Too many mines for grid size"; /* * FIXME: Need more constraints here. Not sure what the * sensible limits for Minesweeper actually are. The limits * probably ought to change, however, depending on uniqueness. */ return NULL; } /* ---------------------------------------------------------------------- * Minesweeper solver, used to ensure the generated grids are * solvable without having to take risks. */ /* * Count the bits in a word. Only needs to cope with 16 bits. */ static int bitcount16(int inword) { unsigned int word = inword; word = ((word & 0xAAAA) >> 1) + (word & 0x5555); word = ((word & 0xCCCC) >> 2) + (word & 0x3333); word = ((word & 0xF0F0) >> 4) + (word & 0x0F0F); word = ((word & 0xFF00) >> 8) + (word & 0x00FF); return (int)word; } /* * We use a tree234 to store a large number of small localised * sets, each with a mine count. We also keep some of those sets * linked together into a to-do list. */ struct set { short x, y, mask, mines; int todo; struct set *prev, *next; }; static int setcmp(void *av, void *bv) { struct set *a = (struct set *)av; struct set *b = (struct set *)bv; if (a->y < b->y) return -1; else if (a->y > b->y) return +1; else if (a->x < b->x) return -1; else if (a->x > b->x) return +1; else if (a->mask < b->mask) return -1; else if (a->mask > b->mask) return +1; else return 0; } struct setstore { tree234 *sets; struct set *todo_head, *todo_tail; }; static struct setstore *ss_new(void) { struct setstore *ss = snew(struct setstore); ss->sets = newtree234(setcmp); ss->todo_head = ss->todo_tail = NULL; return ss; } /* * Take two input sets, in the form (x,y,mask). Munge the first by * taking either its intersection with the second or its difference * with the second. Return the new mask part of the first set. */ static int setmunge(int x1, int y1, int mask1, int x2, int y2, int mask2, int diff) { /* * Adjust the second set so that it has the same x,y * coordinates as the first. */ if (abs(x2-x1) >= 3 || abs(y2-y1) >= 3) { mask2 = 0; } else { while (x2 > x1) { mask2 &= ~(4|32|256); mask2 <<= 1; x2--; } while (x2 < x1) { mask2 &= ~(1|8|64); mask2 >>= 1; x2++; } while (y2 > y1) { mask2 &= ~(64|128|256); mask2 <<= 3; y2--; } while (y2 < y1) { mask2 &= ~(1|2|4); mask2 >>= 3; y2++; } } /* * Invert the second set if `diff' is set (we're after A &~ B * rather than A & B). */ if (diff) mask2 ^= 511; /* * Now all that's left is a logical AND. */ return mask1 & mask2; } static void ss_add_todo(struct setstore *ss, struct set *s) { if (s->todo) return; /* already on it */ #ifdef SOLVER_DIAGNOSTICS printf("adding set on todo list: %d,%d %03x %d\n", s->x, s->y, s->mask, s->mines); #endif s->prev = ss->todo_tail; if (s->prev) s->prev->next = s; else ss->todo_head = s; ss->todo_tail = s; s->next = NULL; s->todo = TRUE; } static void ss_add(struct setstore *ss, int x, int y, int mask, int mines) { struct set *s; assert(mask != 0); /* * Normalise so that x and y are genuinely the bounding * rectangle. */ while (!(mask & (1|8|64))) mask >>= 1, x++; while (!(mask & (1|2|4))) mask >>= 3, y++; /* * Create a set structure and add it to the tree. */ s = snew(struct set); s->x = x; s->y = y; s->mask = mask; s->mines = mines; s->todo = FALSE; if (add234(ss->sets, s) != s) { /* * This set already existed! Free it and return. */ sfree(s); return; } /* * We've added a new set to the tree, so put it on the todo * list. */ ss_add_todo(ss, s); } static void ss_remove(struct setstore *ss, struct set *s) { struct set *next = s->next, *prev = s->prev; #ifdef SOLVER_DIAGNOSTICS printf("removing set %d,%d %03x\n", s->x, s->y, s->mask); #endif /* * Remove s from the todo list. */ if (prev) prev->next = next; else if (s == ss->todo_head) ss->todo_head = next; if (next) next->prev = prev; else if (s == ss->todo_tail) ss->todo_tail = prev; s->todo = FALSE; /* * Remove s from the tree. */ del234(ss->sets, s); /* * Destroy the actual set structure. */ sfree(s); } /* * Return a dynamically allocated list of all the sets which * overlap a provided input set. */ static struct set **ss_overlap(struct setstore *ss, int x, int y, int mask) { struct set **ret = NULL; int nret = 0, retsize = 0; int xx, yy; for (xx = x-3; xx < x+3; xx++) for (yy = y-3; yy < y+3; yy++) { struct set stmp, *s; int pos; /* * Find the first set with these top left coordinates. */ stmp.x = xx; stmp.y = yy; stmp.mask = 0; if (findrelpos234(ss->sets, &stmp, NULL, REL234_GE, &pos)) { while ((s = index234(ss->sets, pos)) != NULL && s->x == xx && s->y == yy) { /* * This set potentially overlaps the input one. * Compute the intersection to see if they * really overlap, and add it to the list if * so. */ if (setmunge(x, y, mask, s->x, s->y, s->mask, FALSE)) { /* * There's an overlap. */ if (nret >= retsize) { retsize = nret + 32; ret = sresize(ret, retsize, struct set *); } ret[nret++] = s; } pos++; } } } ret = sresize(ret, nret+1, struct set *); ret[nret] = NULL; return ret; } /* * Get an element from the head of the set todo list. */ static struct set *ss_todo(struct setstore *ss) { if (ss->todo_head) { struct set *ret = ss->todo_head; ss->todo_head = ret->next; if (ss->todo_head) ss->todo_head->prev = NULL; else ss->todo_tail = NULL; ret->next = ret->prev = NULL; ret->todo = FALSE; return ret; } else { return NULL; } } struct squaretodo { int *next; int head, tail; }; static void std_add(struct squaretodo *std, int i) { if (std->tail >= 0) std->next[std->tail] = i; else std->head = i; std->tail = i; std->next[i] = -1; } typedef int (*open_cb)(void *, int, int); static void known_squares(int w, int h, struct squaretodo *std, signed char *grid, open_cb open, void *openctx, int x, int y, int mask, int mine) { int xx, yy, bit; bit = 1; for (yy = 0; yy < 3; yy++) for (xx = 0; xx < 3; xx++) { if (mask & bit) { int i = (y + yy) * w + (x + xx); /* * It's possible that this square is _already_ * known, in which case we don't try to add it to * the list twice. */ if (grid[i] == -2) { if (mine) { grid[i] = -1; /* and don't open it! */ } else { grid[i] = open(openctx, x + xx, y + yy); assert(grid[i] != -1); /* *bang* */ } std_add(std, i); } } bit <<= 1; } } /* * This is data returned from the `perturb' function. It details * which squares have become mines and which have become clear. The * solver is (of course) expected to honourably not use that * knowledge directly, but to efficently adjust its internal data * structures and proceed based on only the information it * legitimately has. */ struct perturbation { int x, y; int delta; /* +1 == become a mine; -1 == cleared */ }; struct perturbations { int n; struct perturbation *changes; }; /* * Main solver entry point. You give it a grid of existing * knowledge (-1 for a square known to be a mine, 0-8 for empty * squares with a given number of neighbours, -2 for completely * unknown), plus a function which you can call to open new squares * once you're confident of them. It fills in as much more of the * grid as it can. * * Return value is: * * - -1 means deduction stalled and nothing could be done * - 0 means deduction succeeded fully * - >0 means deduction succeeded but some number of perturbation * steps were required; the exact return value is the number of * perturb calls. */ typedef struct perturbations *(*perturb_cb) (void *, signed char *, int, int, int); static int minesolve(int w, int h, int n, signed char *grid, open_cb open, perturb_cb perturb, void *ctx, random_state *rs) { struct setstore *ss = ss_new(); struct set **list; struct squaretodo astd, *std = &astd; int x, y, i, j; int nperturbs = 0; /* * Set up a linked list of squares with known contents, so that * we can process them one by one. */ std->next = snewn(w*h, int); std->head = std->tail = -1; /* * Initialise that list with all known squares in the input * grid. */ for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { i = y*w+x; if (grid[i] != -2) std_add(std, i); } } /* * Main deductive loop. */ while (1) { int done_something = FALSE; struct set *s; /* * If there are any known squares on the todo list, process * them and construct a set for each. */ while (std->head != -1) { i = std->head; #ifdef SOLVER_DIAGNOSTICS printf("known square at %d,%d [%d]\n", i%w, i/w, grid[i]); #endif std->head = std->next[i]; if (std->head == -1) std->tail = -1; x = i % w; y = i / w; if (grid[i] >= 0) { int dx, dy, mines, bit, val; #ifdef SOLVER_DIAGNOSTICS printf("creating set around this square\n"); #endif /* * Empty square. Construct the set of non-known squares * around this one, and determine its mine count. */ mines = grid[i]; bit = 1; val = 0; for (dy = -1; dy <= +1; dy++) { for (dx = -1; dx <= +1; dx++) { #ifdef SOLVER_DIAGNOSTICS printf("grid %d,%d = %d\n", x+dx, y+dy, grid[i+dy*w+dx]); #endif if (x+dx < 0 || x+dx >= w || y+dy < 0 || y+dy >= h) /* ignore this one */; else if (grid[i+dy*w+dx] == -1) mines--; else if (grid[i+dy*w+dx] == -2) val |= bit; bit <<= 1; } } if (val) ss_add(ss, x-1, y-1, val, mines); } /* * Now, whether the square is empty or full, we must * find any set which contains it and replace it with * one which does not. */ { #ifdef SOLVER_DIAGNOSTICS printf("finding sets containing known square %d,%d\n", x, y); #endif list = ss_overlap(ss, x, y, 1); for (j = 0; list[j]; j++) { int newmask, newmines; s = list[j]; /* * Compute the mask for this set minus the * newly known square. */ newmask = setmunge(s->x, s->y, s->mask, x, y, 1, TRUE); /* * Compute the new mine count. */ newmines = s->mines - (grid[i] == -1); /* * Insert the new set into the collection, * unless it's been whittled right down to * nothing. */ if (newmask) ss_add(ss, s->x, s->y, newmask, newmines); /* * Destroy the old one; it is actually obsolete. */ ss_remove(ss, s); } sfree(list); } /* * Marking a fresh square as known certainly counts as * doing something. */ done_something = TRUE; } /* * Now pick a set off the to-do list and attempt deductions * based on it. */ if ((s = ss_todo(ss)) != NULL) { #ifdef SOLVER_DIAGNOSTICS printf("set to do: %d,%d %03x %d\n", s->x, s->y, s->mask, s->mines); #endif /* * Firstly, see if this set has a mine count of zero or * of its own cardinality. */ if (s->mines == 0 || s->mines == bitcount16(s->mask)) { /* * If so, we can immediately mark all the squares * in the set as known. */ #ifdef SOLVER_DIAGNOSTICS printf("easy\n"); #endif known_squares(w, h, std, grid, open, ctx, s->x, s->y, s->mask, (s->mines != 0)); /* * Having done that, we need do nothing further * with this set; marking all the squares in it as * known will eventually eliminate it, and will * also permit further deductions about anything * that overlaps it. */ continue; } /* * Failing that, we now search through all the sets * which overlap this one. */ list = ss_overlap(ss, s->x, s->y, s->mask); for (j = 0; list[j]; j++) { struct set *s2 = list[j]; int swing, s2wing, swc, s2wc; /* * Find the non-overlapping parts s2-s and s-s2, * and their cardinalities. * * I'm going to refer to these parts as `wings' * surrounding the central part common to both * sets. The `s wing' is s-s2; the `s2 wing' is * s2-s. */ swing = setmunge(s->x, s->y, s->mask, s2->x, s2->y, s2->mask, TRUE); s2wing = setmunge(s2->x, s2->y, s2->mask, s->x, s->y, s->mask, TRUE); swc = bitcount16(swing); s2wc = bitcount16(s2wing); /* * If one set has more mines than the other, and * the number of extra mines is equal to the * cardinality of that set's wing, then we can mark * every square in the wing as a known mine, and * every square in the other wing as known clear. */ if (swc == s->mines - s2->mines || s2wc == s2->mines - s->mines) { known_squares(w, h, std, grid, open, ctx, s->x, s->y, swing, (swc == s->mines - s2->mines)); known_squares(w, h, std, grid, open, ctx, s2->x, s2->y, s2wing, (s2wc == s2->mines - s->mines)); continue; } /* * Failing that, see if one set is a subset of the * other. If so, we can divide up the mine count of * the larger set between the smaller set and its * complement, even if neither smaller set ends up * being immediately clearable. */ if (swc == 0 && s2wc != 0) { /* s is a subset of s2. */ assert(s2->mines > s->mines); ss_add(ss, s2->x, s2->y, s2wing, s2->mines - s->mines); } else if (s2wc == 0 && swc != 0) { /* s2 is a subset of s. */ assert(s->mines > s2->mines); ss_add(ss, s->x, s->y, swing, s->mines - s2->mines); } } sfree(list); /* * In this situation we have definitely done * _something_, even if it's only reducing the size of * our to-do list. */ done_something = TRUE; } else if (n >= 0) { /* * We have nothing left on our todo list, which means * all localised deductions have failed. Our next step * is to resort to global deduction based on the total * mine count. This is computationally expensive * compared to any of the above deductions, which is * why we only ever do it when all else fails, so that * hopefully it won't have to happen too often. * * If you pass n<0 into this solver, that informs it * that you do not know the total mine count, so it * won't even attempt these deductions. */ int minesleft, squaresleft; int nsets, setused[10], cursor; /* * Start by scanning the current grid state to work out * how many unknown squares we still have, and how many * mines are to be placed in them. */ squaresleft = 0; minesleft = n; for (i = 0; i < w*h; i++) { if (grid[i] == -1) minesleft--; else if (grid[i] == -2) squaresleft++; } #ifdef SOLVER_DIAGNOSTICS printf("global deduction time: squaresleft=%d minesleft=%d\n", squaresleft, minesleft); for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { int v = grid[y*w+x]; if (v == -1) putchar('*'); else if (v == -2) putchar('?'); else if (v == 0) putchar('-'); else putchar('0' + v); } putchar('\n'); } #endif /* * If there _are_ no unknown squares, we have actually * finished. */ if (squaresleft == 0) { assert(minesleft == 0); break; } /* * First really simple case: if there are no more mines * left, or if there are exactly as many mines left as * squares to play them in, then it's all easy. */ if (minesleft == 0 || minesleft == squaresleft) { for (i = 0; i < w*h; i++) if (grid[i] == -2) known_squares(w, h, std, grid, open, ctx, i % w, i / w, 1, minesleft != 0); continue; /* now go back to main deductive loop */ } /* * Failing that, we have to do some _real_ work. * Ideally what we do here is to try every single * combination of the currently available sets, in an * attempt to find a disjoint union (i.e. a set of * squares with a known mine count between them) such * that the remaining unknown squares _not_ contained * in that union either contain no mines or are all * mines. * * Actually enumerating all 2^n possibilities will get * a bit slow for large n, so I artificially cap this * recursion at n=10 to avoid too much pain. */ nsets = count234(ss->sets); if (nsets <= lenof(setused)) { /* * Doing this with actual recursive function calls * would get fiddly because a load of local * variables from this function would have to be * passed down through the recursion. So instead * I'm going to use a virtual recursion within this * function. The way this works is: * * - we have an array `setused', such that * setused[n] is 0 or 1 depending on whether set * n is currently in the union we are * considering. * * - we have a value `cursor' which indicates how * much of `setused' we have so far filled in. * It's conceptually the recursion depth. * * We begin by setting `cursor' to zero. Then: * * - if cursor can advance, we advance it by one. * We set the value in `setused' that it went * past to 1 if that set is disjoint from * anything else currently in `setused', or to 0 * otherwise. * * - If cursor cannot advance because it has * reached the end of the setused list, then we * have a maximal disjoint union. Check to see * whether its mine count has any useful * properties. If so, mark all the squares not * in the union as known and terminate. * * - If cursor has reached the end of setused and * the algorithm _hasn't_ terminated, back * cursor up to the nearest 1, turn it into a 0 * and advance cursor just past it. * * - If we attempt to back up to the nearest 1 and * there isn't one at all, then we have gone * through all disjoint unions of sets in the * list and none of them has been helpful, so we * give up. */ struct set *sets[lenof(setused)]; for (i = 0; i < nsets; i++) sets[i] = index234(ss->sets, i); cursor = 0; while (1) { if (cursor < nsets) { int ok = TRUE; /* See if any existing set overlaps this one. */ for (i = 0; i < cursor; i++) if (setused[i] && setmunge(sets[cursor]->x, sets[cursor]->y, sets[cursor]->mask, sets[i]->x, sets[i]->y, sets[i]->mask, FALSE)) { ok = FALSE; break; } if (ok) { /* * We're adding this set to our union, * so adjust minesleft and squaresleft * appropriately. */ minesleft -= sets[cursor]->mines; squaresleft -= bitcount16(sets[cursor]->mask); } setused[cursor++] = ok; } else { #ifdef SOLVER_DIAGNOSTICS printf("trying a set combination with %d %d\n", squaresleft, minesleft); #endif /* SOLVER_DIAGNOSTICS */ /* * We've reached the end. See if we've got * anything interesting. */ if (squaresleft > 0 && (minesleft == 0 || minesleft == squaresleft)) { /* * We have! There is at least one * square not contained within the set * union we've just found, and we can * deduce that either all such squares * are mines or all are not (depending * on whether minesleft==0). So now all * we have to do is actually go through * the grid, find those squares, and * mark them. */ for (i = 0; i < w*h; i++) if (grid[i] == -2) { int outside = TRUE; y = i / w; x = i % w; for (j = 0; j < nsets; j++) if (setused[j] && setmunge(sets[j]->x, sets[j]->y, sets[j]->mask, x, y, 1, FALSE)) { outside = FALSE; break; } if (outside) known_squares(w, h, std, grid, open, ctx, x, y, 1, minesleft != 0); } done_something = TRUE; break; /* return to main deductive loop */ } /* * If we reach here, then this union hasn't * done us any good, so move on to the * next. Backtrack cursor to the nearest 1, * change it to a 0 and continue. */ while (--cursor >= 0 && !setused[cursor]); if (cursor >= 0) { assert(setused[cursor]); /* * We're removing this set from our * union, so re-increment minesleft and * squaresleft. */ minesleft += sets[cursor]->mines; squaresleft += bitcount16(sets[cursor]->mask); setused[cursor++] = 0; } else { /* * We've backtracked all the way to the * start without finding a single 1, * which means that our virtual * recursion is complete and nothing * helped. */ break; } } } } } if (done_something) continue; #ifdef SOLVER_DIAGNOSTICS /* * Dump the current known state of the grid. */ printf("solver ran out of steam, ret=%d, grid:\n", nperturbs); for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { int v = grid[y*w+x]; if (v == -1) putchar('*'); else if (v == -2) putchar('?'); else if (v == 0) putchar('-'); else putchar('0' + v); } putchar('\n'); } { struct set *s; for (i = 0; (s = index234(ss->sets, i)) != NULL; i++) printf("remaining set: %d,%d %03x %d\n", s->x, s->y, s->mask, s->mines); } #endif /* * Now we really are at our wits' end as far as solving * this grid goes. Our only remaining option is to call * a perturb function and ask it to modify the grid to * make it easier. */ if (perturb) { struct perturbations *ret; struct set *s; nperturbs++; /* * Choose a set at random from the current selection, * and ask the perturb function to either fill or empty * it. * * If we have no sets at all, we must give up. */ if (count234(ss->sets) == 0) { #ifdef SOLVER_DIAGNOSTICS printf("perturbing on entire unknown set\n"); #endif ret = perturb(ctx, grid, 0, 0, 0); } else { s = index234(ss->sets, random_upto(rs, count234(ss->sets))); #ifdef SOLVER_DIAGNOSTICS printf("perturbing on set %d,%d %03x\n", s->x, s->y, s->mask); #endif ret = perturb(ctx, grid, s->x, s->y, s->mask); } if (ret) { assert(ret->n > 0); /* otherwise should have been NULL */ /* * A number of squares have been fiddled with, and * the returned structure tells us which. Adjust * the mine count in any set which overlaps one of * those squares, and put them back on the to-do * list. Also, if the square itself is marked as a * known non-mine, put it back on the squares-to-do * list. */ for (i = 0; i < ret->n; i++) { #ifdef SOLVER_DIAGNOSTICS printf("perturbation %s mine at %d,%d\n", ret->changes[i].delta > 0 ? "added" : "removed", ret->changes[i].x, ret->changes[i].y); #endif if (ret->changes[i].delta < 0 && grid[ret->changes[i].y*w+ret->changes[i].x] != -2) { std_add(std, ret->changes[i].y*w+ret->changes[i].x); } list = ss_overlap(ss, ret->changes[i].x, ret->changes[i].y, 1); for (j = 0; list[j]; j++) { list[j]->mines += ret->changes[i].delta; ss_add_todo(ss, list[j]); } sfree(list); } /* * Now free the returned data. */ sfree(ret->changes); sfree(ret); #ifdef SOLVER_DIAGNOSTICS /* * Dump the current known state of the grid. */ printf("state after perturbation:\n"); for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { int v = grid[y*w+x]; if (v == -1) putchar('*'); else if (v == -2) putchar('?'); else if (v == 0) putchar('-'); else putchar('0' + v); } putchar('\n'); } { struct set *s; for (i = 0; (s = index234(ss->sets, i)) != NULL; i++) printf("remaining set: %d,%d %03x %d\n", s->x, s->y, s->mask, s->mines); } #endif /* * And now we can go back round the deductive loop. */ continue; } } /* * If we get here, even that didn't work (either we didn't * have a perturb function or it returned failure), so we * give up entirely. */ break; } /* * See if we've got any unknown squares left. */ for (y = 0; y < h; y++) for (x = 0; x < w; x++) if (grid[y*w+x] == -2) { nperturbs = -1; /* failed to complete */ break; } /* * Free the set list and square-todo list. */ { struct set *s; while ((s = delpos234(ss->sets, 0)) != NULL) sfree(s); freetree234(ss->sets); sfree(ss); sfree(std->next); } return nperturbs; } /* ---------------------------------------------------------------------- * Grid generator which uses the above solver. */ struct minectx { char *grid; int w, h; int sx, sy; int allow_big_perturbs; random_state *rs; }; static int mineopen(void *vctx, int x, int y) { struct minectx *ctx = (struct minectx *)vctx; int i, j, n; assert(x >= 0 && x < ctx->w && y >= 0 && y < ctx->h); if (ctx->grid[y * ctx->w + x]) return -1; /* *bang* */ n = 0; for (i = -1; i <= +1; i++) { if (x + i < 0 || x + i >= ctx->w) continue; for (j = -1; j <= +1; j++) { if (y + j < 0 || y + j >= ctx->h) continue; if (i == 0 && j == 0) continue; if (ctx->grid[(y+j) * ctx->w + (x+i)]) n++; } } return n; } /* Structure used internally to mineperturb(). */ struct square { int x, y, type, random; }; static int squarecmp(const void *av, const void *bv) { const struct square *a = (const struct square *)av; const struct square *b = (const struct square *)bv; if (a->type < b->type) return -1; else if (a->type > b->type) return +1; else if (a->random < b->random) return -1; else if (a->random > b->random) return +1; else if (a->y < b->y) return -1; else if (a->y > b->y) return +1; else if (a->x < b->x) return -1; else if (a->x > b->x) return +1; return 0; } /* * Normally this function is passed an (x,y,mask) set description. * On occasions, though, there is no _localised_ set being used, * and the set being perturbed is supposed to be the entirety of * the unreachable area. This is signified by the special case * mask==0: in this case, anything labelled -2 in the grid is part * of the set. * * Allowing perturbation in this special case appears to make it * guaranteeably possible to generate a workable grid for any mine * density, but they tend to be a bit boring, with mines packed * densely into far corners of the grid and the remainder being * less dense than one might like. Therefore, to improve overall * grid quality I disable this feature for the first few attempts, * and fall back to it after no useful grid has been generated. */ static struct perturbations *mineperturb(void *vctx, signed char *grid, int setx, int sety, int mask) { struct minectx *ctx = (struct minectx *)vctx; struct square *sqlist; int x, y, dx, dy, i, n, nfull, nempty; struct square **tofill, **toempty, **todo; int ntofill, ntoempty, ntodo, dtodo, dset; struct perturbations *ret; int *setlist; if (!mask && !ctx->allow_big_perturbs) return NULL; /* * Make a list of all the squares in the grid which we can * possibly use. This list should be in preference order, which * means * * - first, unknown squares on the boundary of known space * - next, unknown squares beyond that boundary * - as a very last resort, known squares, but not within one * square of the starting position. * * Each of these sections needs to be shuffled independently. * We do this by preparing list of all squares and then sorting * it with a random secondary key. */ sqlist = snewn(ctx->w * ctx->h, struct square); n = 0; for (y = 0; y < ctx->h; y++) for (x = 0; x < ctx->w; x++) { /* * If this square is too near the starting position, * don't put it on the list at all. */ if (abs(y - ctx->sy) <= 1 && abs(x - ctx->sx) <= 1) continue; /* * If this square is in the input set, also don't put * it on the list! */ if ((mask == 0 && grid[y*ctx->w+x] == -2) || (x >= setx && x < setx + 3 && y >= sety && y < sety + 3 && mask & (1 << ((y-sety)*3+(x-setx))))) continue; sqlist[n].x = x; sqlist[n].y = y; if (grid[y*ctx->w+x] != -2) { sqlist[n].type = 3; /* known square */ } else { /* * Unknown square. Examine everything around it and * see if it borders on any known squares. If it * does, it's class 1, otherwise it's 2. */ sqlist[n].type = 2; for (dy = -1; dy <= +1; dy++) for (dx = -1; dx <= +1; dx++) if (x+dx >= 0 && x+dx < ctx->w && y+dy >= 0 && y+dy < ctx->h && grid[(y+dy)*ctx->w+(x+dx)] != -2) { sqlist[n].type = 1; break; } } /* * Finally, a random number to cause qsort to * shuffle within each group. */ sqlist[n].random = random_bits(ctx->rs, 31); n++; } qsort(sqlist, n, sizeof(struct square), squarecmp); /* * Now count up the number of full and empty squares in the set * we've been provided. */ nfull = nempty = 0; if (mask) { for (dy = 0; dy < 3; dy++) for (dx = 0; dx < 3; dx++) if (mask & (1 << (dy*3+dx))) { assert(setx+dx <= ctx->w); assert(sety+dy <= ctx->h); if (ctx->grid[(sety+dy)*ctx->w+(setx+dx)]) nfull++; else nempty++; } } else { for (y = 0; y < ctx->h; y++) for (x = 0; x < ctx->w; x++) if (grid[y*ctx->w+x] == -2) { if (ctx->grid[y*ctx->w+x]) nfull++; else nempty++; } } /* * Now go through our sorted list until we find either `nfull' * empty squares, or `nempty' full squares; these will be * swapped with the appropriate squares in the set to either * fill or empty the set while keeping the same number of mines * overall. */ ntofill = ntoempty = 0; if (mask) { tofill = snewn(9, struct square *); toempty = snewn(9, struct square *); } else { tofill = snewn(ctx->w * ctx->h, struct square *); toempty = snewn(ctx->w * ctx->h, struct square *); } for (i = 0; i < n; i++) { struct square *sq = &sqlist[i]; if (ctx->grid[sq->y * ctx->w + sq->x]) toempty[ntoempty++] = sq; else tofill[ntofill++] = sq; if (ntofill == nfull || ntoempty == nempty) break; } /* * If we haven't found enough empty squares outside the set to * empty it into _or_ enough full squares outside it to fill it * up with, we'll have to settle for doing only a partial job. * In this case we choose to always _fill_ the set (because * this case will tend to crop up when we're working with very * high mine densities and the only way to get a solvable grid * is going to be to pack most of the mines solidly around the * edges). So now our job is to make a list of the empty * squares in the set, and shuffle that list so that we fill a * random selection of them. */ if (ntofill != nfull && ntoempty != nempty) { int k; assert(ntoempty != 0); setlist = snewn(ctx->w * ctx->h, int); i = 0; if (mask) { for (dy = 0; dy < 3; dy++) for (dx = 0; dx < 3; dx++) if (mask & (1 << (dy*3+dx))) { assert(setx+dx <= ctx->w); assert(sety+dy <= ctx->h); if (!ctx->grid[(sety+dy)*ctx->w+(setx+dx)]) setlist[i++] = (sety+dy)*ctx->w+(setx+dx); } } else { for (y = 0; y < ctx->h; y++) for (x = 0; x < ctx->w; x++) if (grid[y*ctx->w+x] == -2) { if (!ctx->grid[y*ctx->w+x]) setlist[i++] = y*ctx->w+x; } } assert(i > ntoempty); /* * Now pick `ntoempty' items at random from the list. */ for (k = 0; k < ntoempty; k++) { int index = k + random_upto(ctx->rs, i - k); int tmp; tmp = setlist[k]; setlist[k] = setlist[index]; setlist[index] = tmp; } } else setlist = NULL; /* * Now we're pretty much there. We need to either * (a) put a mine in each of the empty squares in the set, and * take one out of each square in `toempty' * (b) take a mine out of each of the full squares in the set, * and put one in each square in `tofill' * depending on which one we've found enough squares to do. * * So we start by constructing our list of changes to return to * the solver, so that it can update its data structures * efficiently rather than having to rescan the whole grid. */ ret = snew(struct perturbations); if (ntofill == nfull) { todo = tofill; ntodo = ntofill; dtodo = +1; dset = -1; sfree(toempty); } else { /* * (We also fall into this case if we've constructed a * setlist.) */ todo = toempty; ntodo = ntoempty; dtodo = -1; dset = +1; sfree(tofill); } ret->n = 2 * ntodo; ret->changes = snewn(ret->n, struct perturbation); for (i = 0; i < ntodo; i++) { ret->changes[i].x = todo[i]->x; ret->changes[i].y = todo[i]->y; ret->changes[i].delta = dtodo; } /* now i == ntodo */ if (setlist) { int j; assert(todo == toempty); for (j = 0; j < ntoempty; j++) { ret->changes[i].x = setlist[j] % ctx->w; ret->changes[i].y = setlist[j] / ctx->w; ret->changes[i].delta = dset; i++; } sfree(setlist); } else if (mask) { for (dy = 0; dy < 3; dy++) for (dx = 0; dx < 3; dx++) if (mask & (1 << (dy*3+dx))) { int currval = (ctx->grid[(sety+dy)*ctx->w+(setx+dx)] ? +1 : -1); if (dset == -currval) { ret->changes[i].x = setx + dx; ret->changes[i].y = sety + dy; ret->changes[i].delta = dset; i++; } } } else { for (y = 0; y < ctx->h; y++) for (x = 0; x < ctx->w; x++) if (grid[y*ctx->w+x] == -2) { int currval = (ctx->grid[y*ctx->w+x] ? +1 : -1); if (dset == -currval) { ret->changes[i].x = x; ret->changes[i].y = y; ret->changes[i].delta = dset; i++; } } } assert(i == ret->n); sfree(sqlist); sfree(todo); /* * Having set up the precise list of changes we're going to * make, we now simply make them and return. */ for (i = 0; i < ret->n; i++) { int delta; x = ret->changes[i].x; y = ret->changes[i].y; delta = ret->changes[i].delta; /* * Check we're not trying to add an existing mine or remove * an absent one. */ assert((delta < 0) ^ (ctx->grid[y*ctx->w+x] == 0)); /* * Actually make the change. */ ctx->grid[y*ctx->w+x] = (delta > 0); /* * Update any numbers already present in the grid. */ for (dy = -1; dy <= +1; dy++) for (dx = -1; dx <= +1; dx++) if (x+dx >= 0 && x+dx < ctx->w && y+dy >= 0 && y+dy < ctx->h && grid[(y+dy)*ctx->w+(x+dx)] != -2) { if (dx == 0 && dy == 0) { /* * The square itself is marked as known in * the grid. Mark it as a mine if it's a * mine, or else work out its number. */ if (delta > 0) { grid[y*ctx->w+x] = -1; } else { int dx2, dy2, minecount = 0; for (dy2 = -1; dy2 <= +1; dy2++) for (dx2 = -1; dx2 <= +1; dx2++) if (x+dx2 >= 0 && x+dx2 < ctx->w && y+dy2 >= 0 && y+dy2 < ctx->h && ctx->grid[(y+dy2)*ctx->w+(x+dx2)]) minecount++; grid[y*ctx->w+x] = minecount; } } else { if (grid[(y+dy)*ctx->w+(x+dx)] >= 0) grid[(y+dy)*ctx->w+(x+dx)] += delta; } } } #ifdef GENERATION_DIAGNOSTICS { int yy, xx; printf("grid after perturbing:\n"); for (yy = 0; yy < ctx->h; yy++) { for (xx = 0; xx < ctx->w; xx++) { int v = ctx->grid[yy*ctx->w+xx]; if (yy == ctx->sy && xx == ctx->sx) { assert(!v); putchar('S'); } else if (v) { putchar('*'); } else { putchar('-'); } } putchar('\n'); } printf("\n"); } #endif return ret; } static char *minegen(int w, int h, int n, int x, int y, int unique, random_state *rs) { char *ret = snewn(w*h, char); int success; int ntries = 0; do { success = FALSE; ntries++; memset(ret, 0, w*h); /* * Start by placing n mines, none of which is at x,y or within * one square of it. */ { int *tmp = snewn(w*h, int); int i, j, k, nn; /* * Write down the list of possible mine locations. */ k = 0; for (i = 0; i < h; i++) for (j = 0; j < w; j++) if (abs(i - y) > 1 || abs(j - x) > 1) tmp[k++] = i*w+j; /* * Now pick n off the list at random. */ nn = n; while (nn-- > 0) { i = random_upto(rs, k); ret[tmp[i]] = 1; tmp[i] = tmp[--k]; } sfree(tmp); } #ifdef GENERATION_DIAGNOSTICS { int yy, xx; printf("grid after initial generation:\n"); for (yy = 0; yy < h; yy++) { for (xx = 0; xx < w; xx++) { int v = ret[yy*w+xx]; if (yy == y && xx == x) { assert(!v); putchar('S'); } else if (v) { putchar('*'); } else { putchar('-'); } } putchar('\n'); } printf("\n"); } #endif /* * Now set up a results grid to run the solver in, and a * context for the solver to open squares. Then run the solver * repeatedly; if the number of perturb steps ever goes up or * it ever returns -1, give up completely. * * We bypass this bit if we're not after a unique grid. */ if (unique) { signed char *solvegrid = snewn(w*h, signed char); struct minectx actx, *ctx = &actx; int solveret, prevret = -2; ctx->grid = ret; ctx->w = w; ctx->h = h; ctx->sx = x; ctx->sy = y; ctx->rs = rs; ctx->allow_big_perturbs = (ntries > 100); while (1) { memset(solvegrid, -2, w*h); solvegrid[y*w+x] = mineopen(ctx, x, y); assert(solvegrid[y*w+x] == 0); /* by deliberate arrangement */ solveret = minesolve(w, h, n, solvegrid, mineopen, mineperturb, ctx, rs); if (solveret < 0 || (prevret >= 0 && solveret >= prevret)) { success = FALSE; break; } else if (solveret == 0) { success = TRUE; break; } } sfree(solvegrid); } else { success = TRUE; } } while (!success); return ret; } static char *describe_layout(char *grid, int area, int x, int y, int obfuscate) { char *ret, *p; unsigned char *bmp; int i; /* * Set up the mine bitmap and obfuscate it. */ bmp = snewn((area + 7) / 8, unsigned char); memset(bmp, 0, (area + 7) / 8); for (i = 0; i < area; i++) { if (grid[i]) bmp[i / 8] |= 0x80 >> (i % 8); } if (obfuscate) obfuscate_bitmap(bmp, area, FALSE); /* * Now encode the resulting bitmap in hex. We can work to * nibble rather than byte granularity, since the obfuscation * function guarantees to return a bit string of the same * length as its input. */ ret = snewn((area+3)/4 + 100, char); p = ret + sprintf(ret, "%d,%d,%s", x, y, obfuscate ? "m" : "u"); /* 'm' == masked */ for (i = 0; i < (area+3)/4; i++) { int v = bmp[i/2]; if (i % 2 == 0) v >>= 4; *p++ = "0123456789abcdef"[v & 0xF]; } *p = '\0'; sfree(bmp); return ret; } static char *new_mine_layout(int w, int h, int n, int x, int y, int unique, random_state *rs, char **game_desc) { char *grid; #ifdef TEST_OBFUSCATION static int tested_obfuscation = FALSE; if (!tested_obfuscation) { /* * A few simple test vectors for the obfuscator. * * First test: the 28-bit stream 1234567. This divides up * into 1234 and 567[0]. The SHA of 56 70 30 (appending * "0") is 15ce8ab946640340bbb99f3f48fd2c45d1a31d30. Thus, * we XOR the 16-bit string 15CE into the input 1234 to get * 07FA. Next, we SHA that with "0": the SHA of 07 FA 30 is * 3370135c5e3da4fed937adc004a79533962b6391. So we XOR the * 12-bit string 337 into the input 567 to get 650. Thus * our output is 07FA650. */ { unsigned char bmp1[] = "\x12\x34\x56\x70"; obfuscate_bitmap(bmp1, 28, FALSE); printf("test 1 encode: %s\n", memcmp(bmp1, "\x07\xfa\x65\x00", 4) ? "failed" : "passed"); obfuscate_bitmap(bmp1, 28, TRUE); printf("test 1 decode: %s\n", memcmp(bmp1, "\x12\x34\x56\x70", 4) ? "failed" : "passed"); } /* * Second test: a long string to make sure we switch from * one SHA to the next correctly. My input string this time * is simply fifty bytes of zeroes. */ { unsigned char bmp2[50]; unsigned char bmp2a[50]; memset(bmp2, 0, 50); memset(bmp2a, 0, 50); obfuscate_bitmap(bmp2, 50 * 8, FALSE); /* * SHA of twenty-five zero bytes plus "0" is * b202c07b990c01f6ff2d544707f60e506019b671. SHA of * twenty-five zero bytes plus "1" is * fcb1d8b5a2f6b592fe6780b36aa9d65dd7aa6db9. Thus our * first half becomes * b202c07b990c01f6ff2d544707f60e506019b671fcb1d8b5a2. * * SHA of that lot plus "0" is * 10b0af913db85d37ca27f52a9f78bba3a80030db. SHA of the * same string plus "1" is * 3d01d8df78e76d382b8106f480135a1bc751d725. So the * second half becomes * 10b0af913db85d37ca27f52a9f78bba3a80030db3d01d8df78. */ printf("test 2 encode: %s\n", memcmp(bmp2, "\xb2\x02\xc0\x7b\x99\x0c\x01\xf6\xff\x2d\x54" "\x47\x07\xf6\x0e\x50\x60\x19\xb6\x71\xfc\xb1\xd8" "\xb5\xa2\x10\xb0\xaf\x91\x3d\xb8\x5d\x37\xca\x27" "\xf5\x2a\x9f\x78\xbb\xa3\xa8\x00\x30\xdb\x3d\x01" "\xd8\xdf\x78", 50) ? "failed" : "passed"); obfuscate_bitmap(bmp2, 50 * 8, TRUE); printf("test 2 decode: %s\n", memcmp(bmp2, bmp2a, 50) ? "failed" : "passed"); } } #endif grid = minegen(w, h, n, x, y, unique, rs); if (game_desc) *game_desc = describe_layout(grid, w * h, x, y, TRUE); return grid; } static char *new_game_desc(const game_params *params, random_state *rs, char **aux, int interactive) { /* * We generate the coordinates of an initial click even if they * aren't actually used. This has the effect of harmonising the * random number usage between interactive and batch use: if * you use `mines --generate' with an explicit random seed, you * should get exactly the same results as if you type the same * random seed into the interactive game and click in the same * initial location. (Of course you won't get the same grid if * you click in a _different_ initial location, but there's * nothing to be done about that.) */ int x = random_upto(rs, params->w); int y = random_upto(rs, params->h); if (!interactive) { /* * For batch-generated grids, pre-open one square. */ char *grid; char *desc; grid = new_mine_layout(params->w, params->h, params->n, x, y, params->unique, rs, &desc); sfree(grid); return desc; } else { char *rsdesc, *desc; rsdesc = random_state_encode(rs); desc = snewn(strlen(rsdesc) + 100, char); sprintf(desc, "r%d,%c,%s", params->n, (char)(params->unique ? 'u' : 'a'), rsdesc); sfree(rsdesc); return desc; } } static char *validate_desc(const game_params *params, const char *desc) { int wh = params->w * params->h; int x, y; if (*desc == 'r') { desc++; if (!*desc || !isdigit((unsigned char)*desc)) return "No initial mine count in game description"; while (*desc && isdigit((unsigned char)*desc)) desc++; /* skip over mine count */ if (*desc != ',') return "No ',' after initial x-coordinate in game description"; desc++; if (*desc != 'u' && *desc != 'a') return "No uniqueness specifier in game description"; desc++; if (*desc != ',') return "No ',' after uniqueness specifier in game description"; /* now ignore the rest */ } else { if (*desc && isdigit((unsigned char)*desc)) { x = atoi(desc); if (x < 0 || x >= params->w) return "Initial x-coordinate was out of range"; while (*desc && isdigit((unsigned char)*desc)) desc++; /* skip over x coordinate */ if (*desc != ',') return "No ',' after initial x-coordinate in game description"; desc++; /* eat comma */ if (!*desc || !isdigit((unsigned char)*desc)) return "No initial y-coordinate in game description"; y = atoi(desc); if (y < 0 || y >= params->h) return "Initial y-coordinate was out of range"; while (*desc && isdigit((unsigned char)*desc)) desc++; /* skip over y coordinate */ if (*desc != ',') return "No ',' after initial y-coordinate in game description"; desc++; /* eat comma */ } /* eat `m' for `masked' or `u' for `unmasked', if present */ if (*desc == 'm' || *desc == 'u') desc++; /* now just check length of remainder */ if (strlen(desc) != (wh+3)/4) return "Game description is wrong length"; } return NULL; } static int open_square(game_state *state, int x, int y) { int w = state->w, h = state->h; int xx, yy, nmines, ncovered; if (!state->layout->mines) { /* * We have a preliminary game in which the mine layout * hasn't been generated yet. Generate it based on the * initial click location. */ char *desc, *privdesc; state->layout->mines = new_mine_layout(w, h, state->layout->n, x, y, state->layout->unique, state->layout->rs, &desc); /* * Find the trailing substring of the game description * corresponding to just the mine layout; we will use this * as our second `private' game ID for serialisation. */ privdesc = desc; while (*privdesc && isdigit((unsigned char)*privdesc)) privdesc++; if (*privdesc == ',') privdesc++; while (*privdesc && isdigit((unsigned char)*privdesc)) privdesc++; if (*privdesc == ',') privdesc++; assert(*privdesc == 'm'); midend_supersede_game_desc(state->layout->me, desc, privdesc); sfree(desc); random_free(state->layout->rs); state->layout->rs = NULL; } if (state->layout->mines[y*w+x]) { /* * The player has landed on a mine. Bad luck. Expose the * mine that killed them, but not the rest (in case they * want to Undo and carry on playing). */ state->dead = TRUE; state->grid[y*w+x] = 65; return -1; } /* * Otherwise, the player has opened a safe square. Mark it to-do. */ state->grid[y*w+x] = -10; /* `todo' value internal to this func */ /* * Now go through the grid finding all `todo' values and * opening them. Every time one of them turns out to have no * neighbouring mines, we add all its unopened neighbours to * the list as well. * * FIXME: We really ought to be able to do this better than * using repeated N^2 scans of the grid. */ while (1) { int done_something = FALSE; for (yy = 0; yy < h; yy++) for (xx = 0; xx < w; xx++) if (state->grid[yy*w+xx] == -10) { int dx, dy, v; assert(!state->layout->mines[yy*w+xx]); v = 0; for (dx = -1; dx <= +1; dx++) for (dy = -1; dy <= +1; dy++) if (xx+dx >= 0 && xx+dx < state->w && yy+dy >= 0 && yy+dy < state->h && state->layout->mines[(yy+dy)*w+(xx+dx)]) v++; state->grid[yy*w+xx] = v; if (v == 0) { for (dx = -1; dx <= +1; dx++) for (dy = -1; dy <= +1; dy++) if (xx+dx >= 0 && xx+dx < state->w && yy+dy >= 0 && yy+dy < state->h && state->grid[(yy+dy)*w+(xx+dx)] == -2) state->grid[(yy+dy)*w+(xx+dx)] = -10; } done_something = TRUE; } if (!done_something) break; } /* * Finally, scan the grid and see if exactly as many squares * are still covered as there are mines. If so, set the `won' * flag and fill in mine markers on all covered squares. */ nmines = ncovered = 0; for (yy = 0; yy < h; yy++) for (xx = 0; xx < w; xx++) { if (state->grid[yy*w+xx] < 0) ncovered++; if (state->layout->mines[yy*w+xx]) nmines++; } assert(ncovered >= nmines); if (ncovered == nmines) { for (yy = 0; yy < h; yy++) for (xx = 0; xx < w; xx++) { if (state->grid[yy*w+xx] < 0) state->grid[yy*w+xx] = -1; } state->won = TRUE; } return 0; } static game_state *new_game(midend *me, const game_params *params, const char *desc) { game_state *state = snew(game_state); int i, wh, x, y, masked; unsigned char *bmp; state->w = params->w; state->h = params->h; state->n = params->n; state->dead = state->won = FALSE; state->used_solve = FALSE; wh = state->w * state->h; state->layout = snew(struct mine_layout); memset(state->layout, 0, sizeof(struct mine_layout)); state->layout->refcount = 1; state->grid = snewn(wh, signed char); memset(state->grid, -2, wh); if (*desc == 'r') { desc++; state->layout->n = atoi(desc); while (*desc && isdigit((unsigned char)*desc)) desc++; /* skip over mine count */ if (*desc) desc++; /* eat comma */ if (*desc == 'a') state->layout->unique = FALSE; else state->layout->unique = TRUE; desc++; if (*desc) desc++; /* eat comma */ state->layout->mines = NULL; state->layout->rs = random_state_decode(desc); state->layout->me = me; } else { state->layout->rs = NULL; state->layout->me = NULL; state->layout->mines = snewn(wh, char); if (*desc && isdigit((unsigned char)*desc)) { x = atoi(desc); while (*desc && isdigit((unsigned char)*desc)) desc++; /* skip over x coordinate */ if (*desc) desc++; /* eat comma */ y = atoi(desc); while (*desc && isdigit((unsigned char)*desc)) desc++; /* skip over y coordinate */ if (*desc) desc++; /* eat comma */ } else { x = y = -1; } if (*desc == 'm') { masked = TRUE; desc++; } else { if (*desc == 'u') desc++; /* * We permit game IDs to be entered by hand without the * masking transformation. */ masked = FALSE; } bmp = snewn((wh + 7) / 8, unsigned char); memset(bmp, 0, (wh + 7) / 8); for (i = 0; i < (wh+3)/4; i++) { int c = desc[i]; int v; assert(c != 0); /* validate_desc should have caught */ if (c >= '0' && c <= '9') v = c - '0'; else if (c >= 'a' && c <= 'f') v = c - 'a' + 10; else if (c >= 'A' && c <= 'F') v = c - 'A' + 10; else v = 0; bmp[i / 2] |= v << (4 * (1 - (i % 2))); } if (masked) obfuscate_bitmap(bmp, wh, TRUE); memset(state->layout->mines, 0, wh); for (i = 0; i < wh; i++) { if (bmp[i / 8] & (0x80 >> (i % 8))) state->layout->mines[i] = 1; } if (x >= 0 && y >= 0) open_square(state, x, y); sfree(bmp); } return state; } static game_state *dup_game(const game_state *state) { game_state *ret = snew(game_state); ret->w = state->w; ret->h = state->h; ret->n = state->n; ret->dead = state->dead; ret->won = state->won; ret->used_solve = state->used_solve; ret->layout = state->layout; ret->layout->refcount++; ret->grid = snewn(ret->w * ret->h, signed char); memcpy(ret->grid, state->grid, ret->w * ret->h); return ret; } static void free_game(game_state *state) { if (--state->layout->refcount <= 0) { sfree(state->layout->mines); if (state->layout->rs) random_free(state->layout->rs); sfree(state->layout); } sfree(state->grid); sfree(state); } static char *solve_game(const game_state *state, const game_state *currstate, const char *aux, char **error) { if (!state->layout->mines) { *error = "Game has not been started yet"; return NULL; } return dupstr("S"); } static int game_can_format_as_text_now(const game_params *params) { return TRUE; } static char *game_text_format(const game_state *state) { char *ret; int x, y; ret = snewn((state->w + 1) * state->h + 1, char); for (y = 0; y < state->h; y++) { for (x = 0; x < state->w; x++) { int v = state->grid[y*state->w+x]; if (v == 0) v = '-'; else if (v >= 1 && v <= 8) v = '0' + v; else if (v == -1) v = '*'; else if (v == -2 || v == -3) v = '?'; else if (v >= 64) v = '!'; ret[y * (state->w+1) + x] = v; } ret[y * (state->w+1) + state->w] = '\n'; } ret[(state->w + 1) * state->h] = '\0'; return ret; } struct game_ui { int hx, hy, hradius; /* for mouse-down highlights */ int validradius; int flash_is_death; int deaths, completed; int cur_x, cur_y, cur_visible; }; static game_ui *new_ui(const game_state *state) { game_ui *ui = snew(game_ui); ui->hx = ui->hy = -1; ui->hradius = ui->validradius = 0; ui->deaths = 0; ui->completed = FALSE; ui->flash_is_death = FALSE; /* *shrug* */ ui->cur_x = ui->cur_y = ui->cur_visible = 0; return ui; } static void free_ui(game_ui *ui) { sfree(ui); } static char *encode_ui(const game_ui *ui) { char buf[80]; /* * The deaths counter and completion status need preserving * across a serialisation. */ sprintf(buf, "D%d", ui->deaths); if (ui->completed) strcat(buf, "C"); return dupstr(buf); } static void decode_ui(game_ui *ui, const char *encoding) { int p= 0; sscanf(encoding, "D%d%n", &ui->deaths, &p); if (encoding[p] == 'C') ui->completed = TRUE; } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { if (newstate->won) ui->completed = TRUE; } struct game_drawstate { int w, h, started, tilesize, bg; signed char *grid; /* * Items in this `grid' array have all the same values as in * the game_state grid, and in addition: * * - -10 means the tile was drawn `specially' as a result of a * flash, so it will always need redrawing. * * - -22 and -23 mean the tile is highlighted for a possible * click. */ int cur_x, cur_y; /* -1, -1 for no cursor displayed. */ }; static char *interpret_move(const game_state *from, game_ui *ui, const game_drawstate *ds, int x, int y, int button) { int cx, cy; char buf[256]; if (from->dead || from->won) return NULL; /* no further moves permitted */ cx = FROMCOORD(x); cy = FROMCOORD(y); if (IS_CURSOR_MOVE(button)) { move_cursor(button, &ui->cur_x, &ui->cur_y, from->w, from->h, 0); ui->cur_visible = 1; return ""; } if (IS_CURSOR_SELECT(button)) { int v = from->grid[ui->cur_y * from->w + ui->cur_x]; if (!ui->cur_visible) { ui->cur_visible = 1; return ""; } if (button == CURSOR_SELECT2) { /* As for RIGHT_BUTTON; only works on covered square. */ if (v != -2 && v != -1) return NULL; sprintf(buf, "F%d,%d", ui->cur_x, ui->cur_y); return dupstr(buf); } /* Otherwise, treat as LEFT_BUTTON, for a single square. */ if (v == -2 || v == -3) { if (from->layout->mines && from->layout->mines[ui->cur_y * from->w + ui->cur_x]) ui->deaths++; sprintf(buf, "O%d,%d", ui->cur_x, ui->cur_y); return dupstr(buf); } cx = ui->cur_x; cy = ui->cur_y; ui->validradius = 1; goto uncover; } if (button == LEFT_BUTTON || button == LEFT_DRAG || button == MIDDLE_BUTTON || button == MIDDLE_DRAG) { if (cx < 0 || cx >= from->w || cy < 0 || cy >= from->h) return NULL; /* * Mouse-downs and mouse-drags just cause highlighting * updates. */ ui->hx = cx; ui->hy = cy; ui->hradius = (from->grid[cy*from->w+cx] >= 0 ? 1 : 0); if (button == LEFT_BUTTON) ui->validradius = ui->hradius; else if (button == MIDDLE_BUTTON) ui->validradius = 1; ui->cur_visible = 0; return ""; } if (button == RIGHT_BUTTON) { if (cx < 0 || cx >= from->w || cy < 0 || cy >= from->h) return NULL; /* * Right-clicking only works on a covered square, and it * toggles between -1 (marked as mine) and -2 (not marked * as mine). * * FIXME: question marks. */ if (from->grid[cy * from->w + cx] != -2 && from->grid[cy * from->w + cx] != -1) return NULL; sprintf(buf, "F%d,%d", cx, cy); return dupstr(buf); } if (button == LEFT_RELEASE || button == MIDDLE_RELEASE) { ui->hx = ui->hy = -1; ui->hradius = 0; /* * At this stage we must never return NULL: we have adjusted * the ui, so at worst we return "". */ if (cx < 0 || cx >= from->w || cy < 0 || cy >= from->h) return ""; /* * Left-clicking on a covered square opens a tile. Not * permitted if the tile is marked as a mine, for safety. * (Unmark it and _then_ open it.) */ if (button == LEFT_RELEASE && (from->grid[cy * from->w + cx] == -2 || from->grid[cy * from->w + cx] == -3) && ui->validradius == 0) { /* Check if you've killed yourself. */ if (from->layout->mines && from->layout->mines[cy * from->w + cx]) ui->deaths++; sprintf(buf, "O%d,%d", cx, cy); return dupstr(buf); } goto uncover; } return NULL; uncover: { /* * Left-clicking or middle-clicking on an uncovered tile: * first we check to see if the number of mine markers * surrounding the tile is equal to its mine count, and if * so then we open all other surrounding squares. */ if (from->grid[cy * from->w + cx] > 0 && ui->validradius == 1) { int dy, dx, n; /* Count mine markers. */ n = 0; for (dy = -1; dy <= +1; dy++) for (dx = -1; dx <= +1; dx++) if (cx+dx >= 0 && cx+dx < from->w && cy+dy >= 0 && cy+dy < from->h) { if (from->grid[(cy+dy)*from->w+(cx+dx)] == -1) n++; } if (n == from->grid[cy * from->w + cx]) { /* * Now see if any of the squares we're clearing * contains a mine (which will happen iff you've * incorrectly marked the mines around the clicked * square). If so, we open _just_ those squares, to * reveal as little additional information as we * can. */ char *p = buf; char *sep = ""; for (dy = -1; dy <= +1; dy++) for (dx = -1; dx <= +1; dx++) if (cx+dx >= 0 && cx+dx < from->w && cy+dy >= 0 && cy+dy < from->h) { if (from->grid[(cy+dy)*from->w+(cx+dx)] != -1 && from->layout->mines && from->layout->mines[(cy+dy)*from->w+(cx+dx)]) { p += sprintf(p, "%sO%d,%d", sep, cx+dx, cy+dy); sep = ";"; } } if (p > buf) { ui->deaths++; } else { sprintf(buf, "C%d,%d", cx, cy); } return dupstr(buf); } } return ""; } } static game_state *execute_move(const game_state *from, const char *move) { int cy, cx; game_state *ret; if (!strcmp(move, "S")) { int yy, xx; ret = dup_game(from); if (!ret->dead) { /* * If the player is still alive at the moment of pressing * Solve, expose the entire grid as if it were a completed * solution. */ for (yy = 0; yy < ret->h; yy++) for (xx = 0; xx < ret->w; xx++) { if (ret->layout->mines[yy*ret->w+xx]) { ret->grid[yy*ret->w+xx] = -1; } else { int dx, dy, v; v = 0; for (dx = -1; dx <= +1; dx++) for (dy = -1; dy <= +1; dy++) if (xx+dx >= 0 && xx+dx < ret->w && yy+dy >= 0 && yy+dy < ret->h && ret->layout->mines[(yy+dy)*ret->w+(xx+dx)]) v++; ret->grid[yy*ret->w+xx] = v; } } } else { /* * If the player pressed Solve _after dying_, show a full * corrections grid in the style of standard Minesweeper. * Players who don't like Mines's behaviour on death of * only showing the mine that killed you (so that in case * of a typo you can undo and carry on without the rest of * the grid being spoiled) can use this to get the display * that ordinary Minesweeper would have given them. */ for (yy = 0; yy < ret->h; yy++) for (xx = 0; xx < ret->w; xx++) { int pos = yy*ret->w+xx; if ((ret->grid[pos] == -2 || ret->grid[pos] == -3) && ret->layout->mines[pos]) { ret->grid[pos] = 64; } else if (ret->grid[pos] == -1 && !ret->layout->mines[pos]) { ret->grid[pos] = 66; } } } ret->used_solve = TRUE; return ret; } else { ret = dup_game(from); while (*move) { if (move[0] == 'F' && sscanf(move+1, "%d,%d", &cx, &cy) == 2 && cx >= 0 && cx < from->w && cy >= 0 && cy < from->h) { ret->grid[cy * from->w + cx] ^= (-2 ^ -1); } else if (move[0] == 'O' && sscanf(move+1, "%d,%d", &cx, &cy) == 2 && cx >= 0 && cx < from->w && cy >= 0 && cy < from->h) { open_square(ret, cx, cy); } else if (move[0] == 'C' && sscanf(move+1, "%d,%d", &cx, &cy) == 2 && cx >= 0 && cx < from->w && cy >= 0 && cy < from->h) { int dx, dy; for (dy = -1; dy <= +1; dy++) for (dx = -1; dx <= +1; dx++) if (cx+dx >= 0 && cx+dx < ret->w && cy+dy >= 0 && cy+dy < ret->h && (ret->grid[(cy+dy)*ret->w+(cx+dx)] == -2 || ret->grid[(cy+dy)*ret->w+(cx+dx)] == -3)) open_square(ret, cx+dx, cy+dy); } else { free_game(ret); return NULL; } while (*move && *move != ';') move++; if (*move) move++; } return ret; } } /* ---------------------------------------------------------------------- * Drawing routines. */ static void game_compute_size(const game_params *params, int tilesize, int *x, int *y) { /* Ick: fake up `ds->tilesize' for macro expansion purposes */ struct { int tilesize; } ads, *ds = &ads; ads.tilesize = tilesize; *x = BORDER * 2 + TILE_SIZE * params->w; *y = BORDER * 2 + TILE_SIZE * params->h; } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { ds->tilesize = tilesize; } static float *game_colours(frontend *fe, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float); frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]); ret[COL_BACKGROUND2 * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] * 19.0F / 20.0F; ret[COL_BACKGROUND2 * 3 + 1] = ret[COL_BACKGROUND * 3 + 1] * 19.0F / 20.0F; ret[COL_BACKGROUND2 * 3 + 2] = ret[COL_BACKGROUND * 3 + 2] * 19.0F / 20.0F; ret[COL_1 * 3 + 0] = 0.0F; ret[COL_1 * 3 + 1] = 0.0F; ret[COL_1 * 3 + 2] = 1.0F; ret[COL_2 * 3 + 0] = 0.0F; ret[COL_2 * 3 + 1] = 0.5F; ret[COL_2 * 3 + 2] = 0.0F; ret[COL_3 * 3 + 0] = 1.0F; ret[COL_3 * 3 + 1] = 0.0F; ret[COL_3 * 3 + 2] = 0.0F; ret[COL_4 * 3 + 0] = 0.0F; ret[COL_4 * 3 + 1] = 0.0F; ret[COL_4 * 3 + 2] = 0.5F; ret[COL_5 * 3 + 0] = 0.5F; ret[COL_5 * 3 + 1] = 0.0F; ret[COL_5 * 3 + 2] = 0.0F; ret[COL_6 * 3 + 0] = 0.0F; ret[COL_6 * 3 + 1] = 0.5F; ret[COL_6 * 3 + 2] = 0.5F; ret[COL_7 * 3 + 0] = 0.0F; ret[COL_7 * 3 + 1] = 0.0F; ret[COL_7 * 3 + 2] = 0.0F; ret[COL_8 * 3 + 0] = 0.5F; ret[COL_8 * 3 + 1] = 0.5F; ret[COL_8 * 3 + 2] = 0.5F; ret[COL_MINE * 3 + 0] = 0.0F; ret[COL_MINE * 3 + 1] = 0.0F; ret[COL_MINE * 3 + 2] = 0.0F; ret[COL_BANG * 3 + 0] = 1.0F; ret[COL_BANG * 3 + 1] = 0.0F; ret[COL_BANG * 3 + 2] = 0.0F; ret[COL_CROSS * 3 + 0] = 1.0F; ret[COL_CROSS * 3 + 1] = 0.0F; ret[COL_CROSS * 3 + 2] = 0.0F; ret[COL_FLAG * 3 + 0] = 1.0F; ret[COL_FLAG * 3 + 1] = 0.0F; ret[COL_FLAG * 3 + 2] = 0.0F; ret[COL_FLAGBASE * 3 + 0] = 0.0F; ret[COL_FLAGBASE * 3 + 1] = 0.0F; ret[COL_FLAGBASE * 3 + 2] = 0.0F; ret[COL_QUERY * 3 + 0] = 0.0F; ret[COL_QUERY * 3 + 1] = 0.0F; ret[COL_QUERY * 3 + 2] = 0.0F; ret[COL_HIGHLIGHT * 3 + 0] = 1.0F; ret[COL_HIGHLIGHT * 3 + 1] = 1.0F; ret[COL_HIGHLIGHT * 3 + 2] = 1.0F; ret[COL_LOWLIGHT * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] * 2.0F / 3.0F; ret[COL_LOWLIGHT * 3 + 1] = ret[COL_BACKGROUND * 3 + 1] * 2.0F / 3.0F; ret[COL_LOWLIGHT * 3 + 2] = ret[COL_BACKGROUND * 3 + 2] * 2.0F / 3.0F; ret[COL_WRONGNUMBER * 3 + 0] = 1.0F; ret[COL_WRONGNUMBER * 3 + 1] = 0.6F; ret[COL_WRONGNUMBER * 3 + 2] = 0.6F; /* Red tinge to a light colour, for the cursor. */ ret[COL_CURSOR * 3 + 0] = ret[COL_HIGHLIGHT * 3 + 0]; ret[COL_CURSOR * 3 + 1] = ret[COL_HIGHLIGHT * 3 + 0] / 2.0F; ret[COL_CURSOR * 3 + 2] = ret[COL_HIGHLIGHT * 3 + 0] / 2.0F; *ncolours = NCOLOURS; return ret; } static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { struct game_drawstate *ds = snew(struct game_drawstate); ds->w = state->w; ds->h = state->h; ds->started = FALSE; ds->tilesize = 0; /* not decided yet */ ds->grid = snewn(ds->w * ds->h, signed char); ds->bg = -1; ds->cur_x = ds->cur_y = -1; memset(ds->grid, -99, ds->w * ds->h); return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { sfree(ds->grid); sfree(ds); } static void draw_tile(drawing *dr, game_drawstate *ds, int x, int y, int v, int bg) { if (v < 0) { int coords[12]; int hl = 0; if (v == -22 || v == -23) { v += 20; /* * Omit the highlights in this case. */ draw_rect(dr, x, y, TILE_SIZE, TILE_SIZE, bg == COL_BACKGROUND ? COL_BACKGROUND2 : bg); draw_line(dr, x, y, x + TILE_SIZE - 1, y, COL_LOWLIGHT); draw_line(dr, x, y, x, y + TILE_SIZE - 1, COL_LOWLIGHT); } else { /* * Draw highlights to indicate the square is covered. */ coords[0] = x + TILE_SIZE - 1; coords[1] = y + TILE_SIZE - 1; coords[2] = x + TILE_SIZE - 1; coords[3] = y; coords[4] = x; coords[5] = y + TILE_SIZE - 1; draw_polygon(dr, coords, 3, COL_LOWLIGHT ^ hl, COL_LOWLIGHT ^ hl); coords[0] = x; coords[1] = y; draw_polygon(dr, coords, 3, COL_HIGHLIGHT ^ hl, COL_HIGHLIGHT ^ hl); draw_rect(dr, x + HIGHLIGHT_WIDTH, y + HIGHLIGHT_WIDTH, TILE_SIZE - 2*HIGHLIGHT_WIDTH, TILE_SIZE - 2*HIGHLIGHT_WIDTH, bg); } if (v == -1) { /* * Draw a flag. */ #define SETCOORD(n, dx, dy) do { \ coords[(n)*2+0] = x + (int)(TILE_SIZE * (dx)); \ coords[(n)*2+1] = y + (int)(TILE_SIZE * (dy)); \ } while (0) SETCOORD(0, 0.6F, 0.35F); SETCOORD(1, 0.6F, 0.7F); SETCOORD(2, 0.8F, 0.8F); SETCOORD(3, 0.25F, 0.8F); SETCOORD(4, 0.55F, 0.7F); SETCOORD(5, 0.55F, 0.35F); draw_polygon(dr, coords, 6, COL_FLAGBASE, COL_FLAGBASE); SETCOORD(0, 0.6F, 0.2F); SETCOORD(1, 0.6F, 0.5F); SETCOORD(2, 0.2F, 0.35F); draw_polygon(dr, coords, 3, COL_FLAG, COL_FLAG); #undef SETCOORD } else if (v == -3) { /* * Draw a question mark. */ draw_text(dr, x + TILE_SIZE / 2, y + TILE_SIZE / 2, FONT_VARIABLE, TILE_SIZE * 6 / 8, ALIGN_VCENTRE | ALIGN_HCENTRE, COL_QUERY, "?"); } } else { /* * Clear the square to the background colour, and draw thin * grid lines along the top and left. * * Exception is that for value 65 (mine we've just trodden * on), we clear the square to COL_BANG. */ if (v & 32) { bg = COL_WRONGNUMBER; v &= ~32; } draw_rect(dr, x, y, TILE_SIZE, TILE_SIZE, (v == 65 ? COL_BANG : bg == COL_BACKGROUND ? COL_BACKGROUND2 : bg)); draw_line(dr, x, y, x + TILE_SIZE - 1, y, COL_LOWLIGHT); draw_line(dr, x, y, x, y + TILE_SIZE - 1, COL_LOWLIGHT); if (v > 0 && v <= 8) { /* * Mark a number. */ char str[2]; str[0] = v + '0'; str[1] = '\0'; draw_text(dr, x + TILE_SIZE / 2, y + TILE_SIZE / 2, FONT_VARIABLE, TILE_SIZE * 7 / 8, ALIGN_VCENTRE | ALIGN_HCENTRE, (COL_1 - 1) + v, str); } else if (v >= 64) { /* * Mark a mine. */ { int cx = x + TILE_SIZE / 2; int cy = y + TILE_SIZE / 2; int r = TILE_SIZE / 2 - 3; draw_circle(dr, cx, cy, 5*r/6, COL_MINE, COL_MINE); draw_rect(dr, cx - r/6, cy - r, 2*(r/6)+1, 2*r+1, COL_MINE); draw_rect(dr, cx - r, cy - r/6, 2*r+1, 2*(r/6)+1, COL_MINE); draw_rect(dr, cx-r/3, cy-r/3, r/3, r/4, COL_HIGHLIGHT); } if (v == 66) { /* * Cross through the mine. */ int dx; for (dx = -1; dx <= +1; dx++) { draw_line(dr, x + 3 + dx, y + 2, x + TILE_SIZE - 3 + dx, y + TILE_SIZE - 2, COL_CROSS); draw_line(dr, x + TILE_SIZE - 3 + dx, y + 2, x + 3 + dx, y + TILE_SIZE - 2, COL_CROSS); } } } } draw_update(dr, x, y, TILE_SIZE, TILE_SIZE); } static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float animtime, float flashtime) { int x, y; int mines, markers, bg; int cx = -1, cy = -1, cmoved; if (flashtime) { int frame = (int)(flashtime / FLASH_FRAME); if (frame % 2) bg = (ui->flash_is_death ? COL_BACKGROUND : COL_LOWLIGHT); else bg = (ui->flash_is_death ? COL_BANG : COL_HIGHLIGHT); } else bg = COL_BACKGROUND; if (!ds->started) { int coords[10]; draw_rect(dr, 0, 0, TILE_SIZE * state->w + 2 * BORDER, TILE_SIZE * state->h + 2 * BORDER, COL_BACKGROUND); draw_update(dr, 0, 0, TILE_SIZE * state->w + 2 * BORDER, TILE_SIZE * state->h + 2 * BORDER); /* * Recessed area containing the whole puzzle. */ coords[0] = COORD(state->w) + OUTER_HIGHLIGHT_WIDTH - 1; coords[1] = COORD(state->h) + OUTER_HIGHLIGHT_WIDTH - 1; coords[2] = COORD(state->w) + OUTER_HIGHLIGHT_WIDTH - 1; coords[3] = COORD(0) - OUTER_HIGHLIGHT_WIDTH; coords[4] = coords[2] - TILE_SIZE; coords[5] = coords[3] + TILE_SIZE; coords[8] = COORD(0) - OUTER_HIGHLIGHT_WIDTH; coords[9] = COORD(state->h) + OUTER_HIGHLIGHT_WIDTH - 1; coords[6] = coords[8] + TILE_SIZE; coords[7] = coords[9] - TILE_SIZE; draw_polygon(dr, coords, 5, COL_HIGHLIGHT, COL_HIGHLIGHT); coords[1] = COORD(0) - OUTER_HIGHLIGHT_WIDTH; coords[0] = COORD(0) - OUTER_HIGHLIGHT_WIDTH; draw_polygon(dr, coords, 5, COL_LOWLIGHT, COL_LOWLIGHT); ds->started = TRUE; } if (ui->cur_visible) cx = ui->cur_x; if (ui->cur_visible) cy = ui->cur_y; cmoved = (cx != ds->cur_x || cy != ds->cur_y); /* * Now draw the tiles. Also in this loop, count up the number * of mines and mine markers. */ mines = markers = 0; for (y = 0; y < ds->h; y++) for (x = 0; x < ds->w; x++) { int v = state->grid[y*ds->w+x], cc = 0; if (v == -1) markers++; if (state->layout->mines && state->layout->mines[y*ds->w+x]) mines++; if (v >= 0 && v <= 8) { /* * Count up the flags around this tile, and if * there are too _many_, highlight the tile. */ int dx, dy, flags = 0; for (dy = -1; dy <= +1; dy++) for (dx = -1; dx <= +1; dx++) { int nx = x+dx, ny = y+dy; if (nx >= 0 && nx < ds->w && ny >= 0 && ny < ds->h && state->grid[ny*ds->w+nx] == -1) flags++; } if (flags > v) v |= 32; } if ((v == -2 || v == -3) && (abs(x-ui->hx) <= ui->hradius && abs(y-ui->hy) <= ui->hradius)) v -= 20; if (cmoved && /* if cursor has moved, force redraw of curr and prev pos */ ((x == cx && y == cy) || (x == ds->cur_x && y == ds->cur_y))) cc = 1; if (ds->grid[y*ds->w+x] != v || bg != ds->bg || cc) { draw_tile(dr, ds, COORD(x), COORD(y), v, (x == cx && y == cy) ? COL_CURSOR : bg); ds->grid[y*ds->w+x] = v; } } ds->bg = bg; ds->cur_x = cx; ds->cur_y = cy; if (!state->layout->mines) mines = state->layout->n; /* * Update the status bar. */ { char statusbar[512]; if (state->dead) { sprintf(statusbar, "DEAD!"); } else if (state->won) { if (state->used_solve) sprintf(statusbar, "Auto-solved."); else sprintf(statusbar, "COMPLETED!"); } else { sprintf(statusbar, "Marked: %d / %d", markers, mines); } if (ui->deaths) sprintf(statusbar + strlen(statusbar), " Deaths: %d", ui->deaths); status_bar(dr, statusbar); } } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return 0.0F; } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { if (oldstate->used_solve || newstate->used_solve) return 0.0F; if (dir > 0 && !oldstate->dead && !oldstate->won) { if (newstate->dead) { ui->flash_is_death = TRUE; return 3 * FLASH_FRAME; } if (newstate->won) { ui->flash_is_death = FALSE; return 2 * FLASH_FRAME; } } return 0.0F; } static int game_status(const game_state *state) { /* * We report the game as lost only if the player has used the * Solve function to reveal all the mines. Otherwise, we assume * they'll undo and continue play. */ return state->won ? (state->used_solve ? -1 : +1) : 0; } static int game_timing_state(const game_state *state, game_ui *ui) { if (state->dead || state->won || ui->completed || !state->layout->mines) return FALSE; return TRUE; } static void game_print_size(const game_params *params, float *x, float *y) { } static void game_print(drawing *dr, const game_state *state, int tilesize) { } #ifdef COMBINED #define thegame mines #endif const struct game thegame = { "Mines", "games.mines", "mines", default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, TRUE, solve_game, TRUE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, PREFERRED_TILE_SIZE, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, FALSE, FALSE, game_print_size, game_print, TRUE, /* wants_statusbar */ TRUE, game_timing_state, BUTTON_BEATS(LEFT_BUTTON, RIGHT_BUTTON) | REQUIRE_RBUTTON, }; #ifdef STANDALONE_OBFUSCATOR /* * Vaguely useful stand-alone program which translates between * obfuscated and clear Mines game descriptions. Pass in a game * description on the command line, and if it's clear it will be * obfuscated and vice versa. The output text should also be a * valid game ID describing the same game. Like this: * * $ ./mineobfusc 9x9:4,4,mb071b49fbd1cb6a0d5868 * 9x9:4,4,004000007c00010022080 * $ ./mineobfusc 9x9:4,4,004000007c00010022080 * 9x9:4,4,mb071b49fbd1cb6a0d5868 */ int main(int argc, char **argv) { game_params *p; game_state *s; char *id = NULL, *desc, *err; int y, x; while (--argc > 0) { char *p = *++argv; if (*p == '-') { fprintf(stderr, "%s: unrecognised option `%s'\n", argv[0], p); return 1; } else { id = p; } } if (!id) { fprintf(stderr, "usage: %s \n", argv[0]); return 1; } desc = strchr(id, ':'); if (!desc) { fprintf(stderr, "%s: game id expects a colon in it\n", argv[0]); return 1; } *desc++ = '\0'; p = default_params(); decode_params(p, id); err = validate_desc(p, desc); if (err) { fprintf(stderr, "%s: %s\n", argv[0], err); return 1; } s = new_game(NULL, p, desc); x = atoi(desc); while (*desc && *desc != ',') desc++; if (*desc) desc++; y = atoi(desc); while (*desc && *desc != ',') desc++; if (*desc) desc++; printf("%s:%s\n", id, describe_layout(s->layout->mines, p->w * p->h, x, y, (*desc != 'm'))); return 0; } #endif /* vim: set shiftwidth=4 tabstop=8: */ puzzles-20170606.272beef/midend.c0000644000175000017500000020155613115373615015306 0ustar simonsimon/* * midend.c: general middle fragment sitting between the * platform-specific front end and game-specific back end. * Maintains a move list, takes care of Undo and Redo commands, and * processes standard keystrokes for undo/redo/new/quit. */ #include #include #include #include #include #include "puzzles.h" enum { DEF_PARAMS, DEF_SEED, DEF_DESC }; /* for midend_game_id_int */ enum { NEWGAME, MOVE, SOLVE, RESTART };/* for midend_state_entry.movetype */ #define special(type) ( (type) != MOVE ) struct midend_state_entry { game_state *state; char *movestr; int movetype; }; struct midend { frontend *frontend; random_state *random; const game *ourgame; struct preset_menu *preset_menu; char **encoded_presets; /* for midend_which_preset to check against */ int n_encoded_presets; /* * `desc' and `privdesc' deserve a comment. * * `desc' is the game description as presented to the user when * they ask for Game -> Specific. `privdesc', if non-NULL, is a * different game description used to reconstruct the initial * game_state when de-serialising. If privdesc is NULL, `desc' * is used for both. * * For almost all games, `privdesc' is NULL and never used. The * exception (as usual) is Mines: the initial game state has no * squares open at all, but after the first click `desc' is * rewritten to describe a game state with an initial click and * thus a bunch of squares open. If we used that desc to * serialise and deserialise, then the initial game state after * deserialisation would look unlike the initial game state * beforehand, and worse still execute_move() might fail on the * attempted first click. So `privdesc' is also used in this * case, to provide a game description describing the same * fixed mine layout _but_ no initial click. (These game IDs * may also be typed directly into Mines if you like.) */ char *desc, *privdesc, *seedstr; char *aux_info; enum { GOT_SEED, GOT_DESC, GOT_NOTHING } genmode; int nstates, statesize, statepos; struct midend_state_entry *states; game_params *params, *curparams; game_drawstate *drawstate; game_ui *ui; game_state *oldstate; float anim_time, anim_pos; float flash_time, flash_pos; int dir; int timing; float elapsed; char *laststatus; drawing *drawing; int pressed_mouse_button; int preferred_tilesize, tilesize, winwidth, winheight; void (*game_id_change_notify_function)(void *); void *game_id_change_notify_ctx; }; #define ensure(me) do { \ if ((me)->nstates >= (me)->statesize) { \ (me)->statesize = (me)->nstates + 128; \ (me)->states = sresize((me)->states, (me)->statesize, \ struct midend_state_entry); \ } \ } while (0) void midend_reset_tilesize(midend *me) { me->preferred_tilesize = me->ourgame->preferred_tilesize; { /* * Allow an environment-based override for the default tile * size by defining a variable along the lines of * `NET_TILESIZE=15'. */ char buf[80], *e; int j, k, ts; sprintf(buf, "%s_TILESIZE", me->ourgame->name); for (j = k = 0; buf[j]; j++) if (!isspace((unsigned char)buf[j])) buf[k++] = toupper((unsigned char)buf[j]); buf[k] = '\0'; if ((e = getenv(buf)) != NULL && sscanf(e, "%d", &ts) == 1 && ts > 0) me->preferred_tilesize = ts; } } midend *midend_new(frontend *fe, const game *ourgame, const drawing_api *drapi, void *drhandle) { midend *me = snew(midend); void *randseed; int randseedsize; get_random_seed(&randseed, &randseedsize); me->frontend = fe; me->ourgame = ourgame; me->random = random_new(randseed, randseedsize); me->nstates = me->statesize = me->statepos = 0; me->states = NULL; me->params = ourgame->default_params(); me->game_id_change_notify_function = NULL; me->game_id_change_notify_ctx = NULL; /* * Allow environment-based changing of the default settings by * defining a variable along the lines of `NET_DEFAULT=25x25w' * in which the value is an encoded parameter string. */ { char buf[80], *e; int j, k; sprintf(buf, "%s_DEFAULT", me->ourgame->name); for (j = k = 0; buf[j]; j++) if (!isspace((unsigned char)buf[j])) buf[k++] = toupper((unsigned char)buf[j]); buf[k] = '\0'; if ((e = getenv(buf)) != NULL) me->ourgame->decode_params(me->params, e); } me->curparams = NULL; me->desc = me->privdesc = NULL; me->seedstr = NULL; me->aux_info = NULL; me->genmode = GOT_NOTHING; me->drawstate = NULL; me->oldstate = NULL; me->preset_menu = NULL; me->anim_time = me->anim_pos = 0.0F; me->flash_time = me->flash_pos = 0.0F; me->dir = 0; me->ui = NULL; me->pressed_mouse_button = 0; me->laststatus = NULL; me->timing = FALSE; me->elapsed = 0.0F; me->tilesize = me->winwidth = me->winheight = 0; if (drapi) me->drawing = drawing_new(drapi, me, drhandle); else me->drawing = NULL; midend_reset_tilesize(me); sfree(randseed); return me; } const game *midend_which_game(midend *me) { return me->ourgame; } static void midend_purge_states(midend *me) { while (me->nstates > me->statepos) { me->ourgame->free_game(me->states[--me->nstates].state); if (me->states[me->nstates].movestr) sfree(me->states[me->nstates].movestr); } } static void midend_free_game(midend *me) { while (me->nstates > 0) { me->nstates--; me->ourgame->free_game(me->states[me->nstates].state); sfree(me->states[me->nstates].movestr); } if (me->drawstate) me->ourgame->free_drawstate(me->drawing, me->drawstate); } static void midend_free_preset_menu(midend *me, struct preset_menu *menu) { if (menu) { int i; for (i = 0; i < menu->n_entries; i++) { sfree(menu->entries[i].title); if (menu->entries[i].params) me->ourgame->free_params(menu->entries[i].params); midend_free_preset_menu(me, menu->entries[i].submenu); } sfree(menu->entries); sfree(menu); } } void midend_free(midend *me) { midend_free_game(me); if (me->drawing) drawing_free(me->drawing); random_free(me->random); sfree(me->states); sfree(me->desc); sfree(me->privdesc); sfree(me->seedstr); sfree(me->aux_info); me->ourgame->free_params(me->params); midend_free_preset_menu(me, me->preset_menu); if (me->ui) me->ourgame->free_ui(me->ui); if (me->curparams) me->ourgame->free_params(me->curparams); sfree(me->laststatus); sfree(me); } static void midend_size_new_drawstate(midend *me) { /* * Don't even bother, if we haven't worked out our tile size * anyway yet. */ if (me->tilesize > 0) { me->ourgame->compute_size(me->params, me->tilesize, &me->winwidth, &me->winheight); me->ourgame->set_size(me->drawing, me->drawstate, me->params, me->tilesize); } } void midend_size(midend *me, int *x, int *y, int user_size) { int min, max; int rx, ry; /* * We can't set the size on the same drawstate twice. So if * we've already sized one drawstate, we must throw it away and * create a new one. */ if (me->drawstate && me->tilesize > 0) { me->ourgame->free_drawstate(me->drawing, me->drawstate); me->drawstate = me->ourgame->new_drawstate(me->drawing, me->states[0].state); } /* * Find the tile size that best fits within the given space. If * `user_size' is TRUE, we must actually find the _largest_ such * tile size, in order to get as close to the user's explicit * request as possible; otherwise, we bound above at the game's * preferred tile size, so that the game gets what it wants * provided that this doesn't break the constraint from the * front-end (which is likely to be a screen size or similar). */ if (user_size) { max = 1; do { max *= 2; me->ourgame->compute_size(me->params, max, &rx, &ry); } while (rx <= *x && ry <= *y); } else max = me->preferred_tilesize + 1; min = 1; /* * Now binary-search between min and max. We're looking for a * boundary rather than a value: the point at which tile sizes * stop fitting within the given dimensions. Thus, we stop when * max and min differ by exactly 1. */ while (max - min > 1) { int mid = (max + min) / 2; me->ourgame->compute_size(me->params, mid, &rx, &ry); if (rx <= *x && ry <= *y) min = mid; else max = mid; } /* * Now `min' is a valid size, and `max' isn't. So use `min'. */ me->tilesize = min; if (user_size) /* If the user requested a change in size, make it permanent. */ me->preferred_tilesize = me->tilesize; midend_size_new_drawstate(me); *x = me->winwidth; *y = me->winheight; } int midend_tilesize(midend *me) { return me->tilesize; } void midend_set_params(midend *me, game_params *params) { me->ourgame->free_params(me->params); me->params = me->ourgame->dup_params(params); } game_params *midend_get_params(midend *me) { return me->ourgame->dup_params(me->params); } static void midend_set_timer(midend *me) { me->timing = (me->ourgame->is_timed && me->ourgame->timing_state(me->states[me->statepos-1].state, me->ui)); if (me->timing || me->flash_time || me->anim_time) activate_timer(me->frontend); else deactivate_timer(me->frontend); } void midend_force_redraw(midend *me) { if (me->drawstate) me->ourgame->free_drawstate(me->drawing, me->drawstate); me->drawstate = me->ourgame->new_drawstate(me->drawing, me->states[0].state); midend_size_new_drawstate(me); midend_redraw(me); } void midend_new_game(midend *me) { midend_stop_anim(me); midend_free_game(me); assert(me->nstates == 0); if (me->genmode == GOT_DESC) { me->genmode = GOT_NOTHING; } else { random_state *rs; if (me->genmode == GOT_SEED) { me->genmode = GOT_NOTHING; } else { /* * Generate a new random seed. 15 digits comes to about * 48 bits, which should be more than enough. * * I'll avoid putting a leading zero on the number, * just in case it confuses anybody who thinks it's * processed as an integer rather than a string. */ char newseed[16]; int i; newseed[15] = '\0'; newseed[0] = '1' + (char)random_upto(me->random, 9); for (i = 1; i < 15; i++) newseed[i] = '0' + (char)random_upto(me->random, 10); sfree(me->seedstr); me->seedstr = dupstr(newseed); if (me->curparams) me->ourgame->free_params(me->curparams); me->curparams = me->ourgame->dup_params(me->params); } sfree(me->desc); sfree(me->privdesc); sfree(me->aux_info); me->aux_info = NULL; rs = random_new(me->seedstr, strlen(me->seedstr)); /* * If this midend has been instantiated without providing a * drawing API, it is non-interactive. This means that it's * being used for bulk game generation, and hence we should * pass the non-interactive flag to new_desc. */ me->desc = me->ourgame->new_desc(me->curparams, rs, &me->aux_info, (me->drawing != NULL)); me->privdesc = NULL; random_free(rs); } ensure(me); /* * It might seem a bit odd that we're using me->params to * create the initial game state, rather than me->curparams * which is better tailored to this specific game and which we * always know. * * It's supposed to be an invariant in the midend that * me->params and me->curparams differ in no aspect that is * important after generation (i.e. after new_desc()). By * deliberately passing the _less_ specific of these two * parameter sets, we provoke play-time misbehaviour in the * case where a game has failed to encode a play-time parameter * in the non-full version of encode_params(). */ me->states[me->nstates].state = me->ourgame->new_game(me, me->params, me->desc); /* * As part of our commitment to self-testing, test the aux * string to make sure nothing ghastly went wrong. */ if (me->ourgame->can_solve && me->aux_info) { game_state *s; char *msg, *movestr; msg = NULL; movestr = me->ourgame->solve(me->states[0].state, me->states[0].state, me->aux_info, &msg); assert(movestr && !msg); s = me->ourgame->execute_move(me->states[0].state, movestr); assert(s); me->ourgame->free_game(s); sfree(movestr); } me->states[me->nstates].movestr = NULL; me->states[me->nstates].movetype = NEWGAME; me->nstates++; me->statepos = 1; me->drawstate = me->ourgame->new_drawstate(me->drawing, me->states[0].state); midend_size_new_drawstate(me); me->elapsed = 0.0F; me->flash_pos = me->flash_time = 0.0F; me->anim_pos = me->anim_time = 0.0F; if (me->ui) me->ourgame->free_ui(me->ui); me->ui = me->ourgame->new_ui(me->states[0].state); midend_set_timer(me); me->pressed_mouse_button = 0; if (me->game_id_change_notify_function) me->game_id_change_notify_function(me->game_id_change_notify_ctx); } int midend_can_undo(midend *me) { return (me->statepos > 1); } int midend_can_redo(midend *me) { return (me->statepos < me->nstates); } static int midend_undo(midend *me) { if (me->statepos > 1) { if (me->ui) me->ourgame->changed_state(me->ui, me->states[me->statepos-1].state, me->states[me->statepos-2].state); me->statepos--; me->dir = -1; return 1; } else return 0; } static int midend_redo(midend *me) { if (me->statepos < me->nstates) { if (me->ui) me->ourgame->changed_state(me->ui, me->states[me->statepos-1].state, me->states[me->statepos].state); me->statepos++; me->dir = +1; return 1; } else return 0; } static void midend_finish_move(midend *me) { float flashtime; /* * We do not flash if the later of the two states is special. * This covers both forward Solve moves and backward (undone) * Restart moves. */ if ((me->oldstate || me->statepos > 1) && ((me->dir > 0 && !special(me->states[me->statepos-1].movetype)) || (me->dir < 0 && me->statepos < me->nstates && !special(me->states[me->statepos].movetype)))) { flashtime = me->ourgame->flash_length(me->oldstate ? me->oldstate : me->states[me->statepos-2].state, me->states[me->statepos-1].state, me->oldstate ? me->dir : +1, me->ui); if (flashtime > 0) { me->flash_pos = 0.0F; me->flash_time = flashtime; } } if (me->oldstate) me->ourgame->free_game(me->oldstate); me->oldstate = NULL; me->anim_pos = me->anim_time = 0; me->dir = 0; midend_set_timer(me); } void midend_stop_anim(midend *me) { if (me->oldstate || me->anim_time != 0) { midend_finish_move(me); midend_redraw(me); } } void midend_restart_game(midend *me) { game_state *s; assert(me->statepos >= 1); if (me->statepos == 1) return; /* no point doing anything at all! */ /* * During restart, we reconstruct the game from the (public) * game description rather than from states[0], because that * way Mines gets slightly more sensible behaviour (restart * goes to _after_ the first click so you don't have to * remember where you clicked). */ s = me->ourgame->new_game(me, me->params, me->desc); /* * Now enter the restarted state as the next move. */ midend_stop_anim(me); midend_purge_states(me); ensure(me); me->states[me->nstates].state = s; me->states[me->nstates].movestr = dupstr(me->desc); me->states[me->nstates].movetype = RESTART; me->statepos = ++me->nstates; if (me->ui) me->ourgame->changed_state(me->ui, me->states[me->statepos-2].state, me->states[me->statepos-1].state); me->flash_pos = me->flash_time = 0.0F; midend_finish_move(me); midend_redraw(me); midend_set_timer(me); } static int midend_really_process_key(midend *me, int x, int y, int button) { game_state *oldstate = me->ourgame->dup_game(me->states[me->statepos - 1].state); int type = MOVE, gottype = FALSE, ret = 1; float anim_time; game_state *s; char *movestr; movestr = me->ourgame->interpret_move(me->states[me->statepos-1].state, me->ui, me->drawstate, x, y, button); if (!movestr) { if (button == 'n' || button == 'N' || button == '\x0E') { midend_new_game(me); midend_redraw(me); goto done; /* never animate */ } else if (button == 'u' || button == 'U' || button == '\x1A' || button == '\x1F') { midend_stop_anim(me); type = me->states[me->statepos-1].movetype; gottype = TRUE; if (!midend_undo(me)) goto done; } else if (button == 'r' || button == 'R' || button == '\x12' || button == '\x19') { midend_stop_anim(me); if (!midend_redo(me)) goto done; } else if (button == '\x13' && me->ourgame->can_solve) { if (midend_solve(me)) goto done; } else if (button == 'q' || button == 'Q' || button == '\x11') { ret = 0; goto done; } else goto done; } else { if (!*movestr) s = me->states[me->statepos-1].state; else { s = me->ourgame->execute_move(me->states[me->statepos-1].state, movestr); assert(s != NULL); } if (s == me->states[me->statepos-1].state) { /* * make_move() is allowed to return its input state to * indicate that although no move has been made, the UI * state has been updated and a redraw is called for. */ midend_redraw(me); midend_set_timer(me); goto done; } else if (s) { midend_stop_anim(me); midend_purge_states(me); ensure(me); assert(movestr != NULL); me->states[me->nstates].state = s; me->states[me->nstates].movestr = movestr; me->states[me->nstates].movetype = MOVE; me->statepos = ++me->nstates; me->dir = +1; if (me->ui) me->ourgame->changed_state(me->ui, me->states[me->statepos-2].state, me->states[me->statepos-1].state); } else { goto done; } } if (!gottype) type = me->states[me->statepos-1].movetype; /* * See if this move requires an animation. */ if (special(type) && !(type == SOLVE && (me->ourgame->flags & SOLVE_ANIMATES))) { anim_time = 0; } else { anim_time = me->ourgame->anim_length(oldstate, me->states[me->statepos-1].state, me->dir, me->ui); } me->oldstate = oldstate; oldstate = NULL; if (anim_time > 0) { me->anim_time = anim_time; } else { me->anim_time = 0.0; midend_finish_move(me); } me->anim_pos = 0.0; midend_redraw(me); midend_set_timer(me); done: if (oldstate) me->ourgame->free_game(oldstate); return ret; } int midend_process_key(midend *me, int x, int y, int button) { int ret = 1; /* * Harmonise mouse drag and release messages. * * Some front ends might accidentally switch from sending, say, * RIGHT_DRAG messages to sending LEFT_DRAG, half way through a * drag. (This can happen on the Mac, for example, since * RIGHT_DRAG is usually done using Command+drag, and if the * user accidentally releases Command half way through the drag * then there will be trouble.) * * It would be an O(number of front ends) annoyance to fix this * in the front ends, but an O(number of back ends) annoyance * to have each game capable of dealing with it. Therefore, we * fix it _here_ in the common midend code so that it only has * to be done once. * * The possible ways in which things can go screwy in the front * end are: * * - in a system containing multiple physical buttons button * presses can inadvertently overlap. We can see ABab (caps * meaning button-down and lowercase meaning button-up) when * the user had semantically intended AaBb. * * - in a system where one button is simulated by means of a * modifier key and another button, buttons can mutate * between press and release (possibly during drag). So we * can see Ab instead of Aa. * * Definite requirements are: * * - button _presses_ must never be invented or destroyed. If * the user presses two buttons in succession, the button * presses must be transferred to the backend unchanged. So * if we see AaBb , that's fine; if we see ABab (the button * presses inadvertently overlapped) we must somehow * `correct' it to AaBb. * * - every mouse action must end up looking like a press, zero * or more drags, then a release. This allows back ends to * make the _assumption_ that incoming mouse data will be * sane in this regard, and not worry about the details. * * So my policy will be: * * - treat any button-up as a button-up for the currently * pressed button, or ignore it if there is no currently * pressed button. * * - treat any drag as a drag for the currently pressed * button, or ignore it if there is no currently pressed * button. * * - if we see a button-down while another button is currently * pressed, invent a button-up for the first one and then * pass the button-down through as before. * * 2005-05-31: An addendum to the above. Some games might want * a `priority order' among buttons, such that if one button is * pressed while another is down then a fixed one of the * buttons takes priority no matter what order they're pressed * in. Mines, in particular, wants to treat a left+right click * like a left click for the benefit of users of other * implementations. So the last of the above points is modified * in the presence of an (optional) button priority order. * * A further addition: we translate certain keyboard presses to * cursor key 'select' buttons, so that a) frontends don't have * to translate these themselves (like they do for CURSOR_UP etc), * and b) individual games don't have to hard-code button presses * of '\n' etc for keyboard-based cursors. The choice of buttons * here could eventually be controlled by a runtime configuration * option. */ if (IS_MOUSE_DRAG(button) || IS_MOUSE_RELEASE(button)) { if (me->pressed_mouse_button) { if (IS_MOUSE_DRAG(button)) { button = me->pressed_mouse_button + (LEFT_DRAG - LEFT_BUTTON); } else { button = me->pressed_mouse_button + (LEFT_RELEASE - LEFT_BUTTON); } } else return ret; /* ignore it */ } else if (IS_MOUSE_DOWN(button) && me->pressed_mouse_button) { /* * If the new button has lower priority than the old one, * don't bother doing this. */ if (me->ourgame->flags & BUTTON_BEATS(me->pressed_mouse_button, button)) return ret; /* just ignore it */ /* * Fabricate a button-up for the previously pressed button. */ ret = ret && midend_really_process_key (me, x, y, (me->pressed_mouse_button + (LEFT_RELEASE - LEFT_BUTTON))); } /* * Translate keyboard presses to cursor selection. */ if (button == '\n' || button == '\r') button = CURSOR_SELECT; if (button == ' ') button = CURSOR_SELECT2; /* * Normalise both backspace characters (8 and 127) to \b. Easier * to do this once, here, than to require all front ends to * carefully generate the same one - now each front end can * generate whichever is easiest. */ if (button == '\177') button = '\b'; /* * Now send on the event we originally received. */ ret = ret && midend_really_process_key(me, x, y, button); /* * And update the currently pressed button. */ if (IS_MOUSE_RELEASE(button)) me->pressed_mouse_button = 0; else if (IS_MOUSE_DOWN(button)) me->pressed_mouse_button = button; return ret; } void midend_redraw(midend *me) { assert(me->drawing); if (me->statepos > 0 && me->drawstate) { start_draw(me->drawing); if (me->oldstate && me->anim_time > 0 && me->anim_pos < me->anim_time) { assert(me->dir != 0); me->ourgame->redraw(me->drawing, me->drawstate, me->oldstate, me->states[me->statepos-1].state, me->dir, me->ui, me->anim_pos, me->flash_pos); } else { me->ourgame->redraw(me->drawing, me->drawstate, NULL, me->states[me->statepos-1].state, +1 /*shrug*/, me->ui, 0.0, me->flash_pos); } end_draw(me->drawing); } } /* * Nasty hacky function used to implement the --redo option in * gtk.c. Only used for generating the puzzles' icons. */ void midend_freeze_timer(midend *me, float tprop) { me->anim_pos = me->anim_time * tprop; midend_redraw(me); deactivate_timer(me->frontend); } void midend_timer(midend *me, float tplus) { int need_redraw = (me->anim_time > 0 || me->flash_time > 0); me->anim_pos += tplus; if (me->anim_pos >= me->anim_time || me->anim_time == 0 || !me->oldstate) { if (me->anim_time > 0) midend_finish_move(me); } me->flash_pos += tplus; if (me->flash_pos >= me->flash_time || me->flash_time == 0) { me->flash_pos = me->flash_time = 0; } if (need_redraw) midend_redraw(me); if (me->timing) { float oldelapsed = me->elapsed; me->elapsed += tplus; if ((int)oldelapsed != (int)me->elapsed) status_bar(me->drawing, me->laststatus ? me->laststatus : ""); } midend_set_timer(me); } float *midend_colours(midend *me, int *ncolours) { float *ret; ret = me->ourgame->colours(me->frontend, ncolours); { int i; /* * Allow environment-based overrides for the standard * colours by defining variables along the lines of * `NET_COLOUR_4=6000c0'. */ for (i = 0; i < *ncolours; i++) { char buf[80], *e; unsigned int r, g, b; int j, k; sprintf(buf, "%s_COLOUR_%d", me->ourgame->name, i); for (j = k = 0; buf[j]; j++) if (!isspace((unsigned char)buf[j])) buf[k++] = toupper((unsigned char)buf[j]); buf[k] = '\0'; if ((e = getenv(buf)) != NULL && sscanf(e, "%2x%2x%2x", &r, &g, &b) == 3) { ret[i*3 + 0] = r / 255.0F; ret[i*3 + 1] = g / 255.0F; ret[i*3 + 2] = b / 255.0F; } } } return ret; } struct preset_menu *preset_menu_new(void) { struct preset_menu *menu = snew(struct preset_menu); menu->n_entries = 0; menu->entries_size = 0; menu->entries = NULL; return menu; } static struct preset_menu_entry *preset_menu_add(struct preset_menu *menu, char *title) { struct preset_menu_entry *toret; if (menu->n_entries >= menu->entries_size) { menu->entries_size = menu->n_entries * 5 / 4 + 10; menu->entries = sresize(menu->entries, menu->entries_size, struct preset_menu_entry); } toret = &menu->entries[menu->n_entries++]; toret->title = title; toret->params = NULL; toret->submenu = NULL; return toret; } struct preset_menu *preset_menu_add_submenu(struct preset_menu *parent, char *title) { struct preset_menu_entry *entry = preset_menu_add(parent, title); entry->submenu = preset_menu_new(); return entry->submenu; } void preset_menu_add_preset(struct preset_menu *parent, char *title, game_params *params) { struct preset_menu_entry *entry = preset_menu_add(parent, title); entry->params = params; } game_params *preset_menu_lookup_by_id(struct preset_menu *menu, int id) { int i; game_params *retd; for (i = 0; i < menu->n_entries; i++) { if (id == menu->entries[i].id) return menu->entries[i].params; if (menu->entries[i].submenu && (retd = preset_menu_lookup_by_id( menu->entries[i].submenu, id)) != NULL) return retd; } return NULL; } static char *preset_menu_add_from_user_env( midend *me, struct preset_menu *menu, char *p, int top_level) { while (*p) { char *name, *val; game_params *preset; name = p; while (*p && *p != ':') p++; if (*p) *p++ = '\0'; val = p; while (*p && *p != ':') p++; if (*p) *p++ = '\0'; if (!strcmp(val, "#")) { /* * Special case: either open a new submenu with the given * title, or terminate the current submenu. */ if (*name) { struct preset_menu *submenu = preset_menu_add_submenu(menu, dupstr(name)); p = preset_menu_add_from_user_env(me, submenu, p, FALSE); } else { /* * If we get a 'close submenu' indication at the top * level, there's not much we can do but quietly * ignore it. */ if (!top_level) return p; } continue; } preset = me->ourgame->default_params(); me->ourgame->decode_params(preset, val); if (me->ourgame->validate_params(preset, TRUE)) { /* Drop this one from the list. */ me->ourgame->free_params(preset); continue; } preset_menu_add_preset(menu, dupstr(name), preset); } return p; } static void preset_menu_alloc_ids(midend *me, struct preset_menu *menu) { int i; for (i = 0; i < menu->n_entries; i++) menu->entries[i].id = me->n_encoded_presets++; for (i = 0; i < menu->n_entries; i++) if (menu->entries[i].submenu) preset_menu_alloc_ids(me, menu->entries[i].submenu); } static void preset_menu_encode_params(midend *me, struct preset_menu *menu) { int i; for (i = 0; i < menu->n_entries; i++) { if (menu->entries[i].params) { me->encoded_presets[menu->entries[i].id] = me->ourgame->encode_params(menu->entries[i].params, TRUE); } else { preset_menu_encode_params(me, menu->entries[i].submenu); } } } struct preset_menu *midend_get_presets(midend *me, int *id_limit) { int i; if (me->preset_menu) return me->preset_menu; #if 0 /* Expect the game to implement exactly one of the two preset APIs */ assert(me->ourgame->fetch_preset || me->ourgame->preset_menu); assert(!(me->ourgame->fetch_preset && me->ourgame->preset_menu)); #endif if (me->ourgame->fetch_preset) { char *name; game_params *preset; /* Simple one-level menu */ assert(!me->ourgame->preset_menu); me->preset_menu = preset_menu_new(); for (i = 0; me->ourgame->fetch_preset(i, &name, &preset); i++) preset_menu_add_preset(me->preset_menu, name, preset); } else { /* Hierarchical menu provided by the game backend */ me->preset_menu = me->ourgame->preset_menu(); } { /* * Allow user extensions to the preset list by defining an * environment variable _PRESETS whose value is a * colon-separated list of items, alternating between textual * titles in the menu and encoded parameter strings. For * example, "SOLO_PRESETS=2x3 Advanced:2x3da" would define * just one additional preset for Solo. */ char buf[80], *e; int j, k; sprintf(buf, "%s_PRESETS", me->ourgame->name); for (j = k = 0; buf[j]; j++) if (!isspace((unsigned char)buf[j])) buf[k++] = toupper((unsigned char)buf[j]); buf[k] = '\0'; if ((e = getenv(buf)) != NULL) { e = dupstr(e); preset_menu_add_from_user_env(me, me->preset_menu, e, TRUE); sfree(e); } } /* * Finalise the menu: allocate an integer id to each entry, and * store string encodings of the presets' parameters in * me->encoded_presets. */ me->n_encoded_presets = 0; preset_menu_alloc_ids(me, me->preset_menu); me->encoded_presets = snewn(me->n_encoded_presets, char *); for (i = 0; i < me->n_encoded_presets; i++) me->encoded_presets[i] = NULL; preset_menu_encode_params(me, me->preset_menu); if (id_limit) *id_limit = me->n_encoded_presets; return me->preset_menu; } int midend_which_preset(midend *me) { char *encoding = me->ourgame->encode_params(me->params, TRUE); int i, ret; ret = -1; for (i = 0; i < me->n_encoded_presets; i++) if (me->encoded_presets[i] && !strcmp(encoding, me->encoded_presets[i])) { ret = i; break; } sfree(encoding); return ret; } int midend_wants_statusbar(midend *me) { return me->ourgame->wants_statusbar; } void midend_request_id_changes(midend *me, void (*notify)(void *), void *ctx) { me->game_id_change_notify_function = notify; me->game_id_change_notify_ctx = ctx; } void midend_supersede_game_desc(midend *me, char *desc, char *privdesc) { sfree(me->desc); sfree(me->privdesc); me->desc = dupstr(desc); me->privdesc = privdesc ? dupstr(privdesc) : NULL; if (me->game_id_change_notify_function) me->game_id_change_notify_function(me->game_id_change_notify_ctx); } config_item *midend_get_config(midend *me, int which, char **wintitle) { char *titlebuf, *parstr, *rest; config_item *ret; char sep; assert(wintitle); titlebuf = snewn(40 + strlen(me->ourgame->name), char); switch (which) { case CFG_SETTINGS: sprintf(titlebuf, "%s configuration", me->ourgame->name); *wintitle = titlebuf; return me->ourgame->configure(me->params); case CFG_SEED: case CFG_DESC: if (!me->curparams) { sfree(titlebuf); return NULL; } sprintf(titlebuf, "%s %s selection", me->ourgame->name, which == CFG_SEED ? "random" : "game"); *wintitle = titlebuf; ret = snewn(2, config_item); ret[0].type = C_STRING; if (which == CFG_SEED) ret[0].name = "Game random seed"; else ret[0].name = "Game ID"; ret[0].ival = 0; /* * For CFG_DESC the text going in here will be a string * encoding of the restricted parameters, plus a colon, * plus the game description. For CFG_SEED it will be the * full parameters, plus a hash, plus the random seed data. * Either of these is a valid full game ID (although only * the former is likely to persist across many code * changes). */ parstr = me->ourgame->encode_params(me->curparams, which == CFG_SEED); assert(parstr); if (which == CFG_DESC) { rest = me->desc ? me->desc : ""; sep = ':'; } else { rest = me->seedstr ? me->seedstr : ""; sep = '#'; } ret[0].sval = snewn(strlen(parstr) + strlen(rest) + 2, char); sprintf(ret[0].sval, "%s%c%s", parstr, sep, rest); sfree(parstr); ret[1].type = C_END; ret[1].name = ret[1].sval = NULL; ret[1].ival = 0; return ret; } assert(!"We shouldn't be here"); return NULL; } static char *midend_game_id_int(midend *me, char *id, int defmode) { char *error, *par, *desc, *seed; game_params *newcurparams, *newparams, *oldparams1, *oldparams2; int free_params; seed = strchr(id, '#'); desc = strchr(id, ':'); if (desc && (!seed || desc < seed)) { /* * We have a colon separating parameters from game * description. So `par' now points to the parameters * string, and `desc' to the description string. */ *desc++ = '\0'; par = id; seed = NULL; } else if (seed && (!desc || seed < desc)) { /* * We have a hash separating parameters from random seed. * So `par' now points to the parameters string, and `seed' * to the seed string. */ *seed++ = '\0'; par = id; desc = NULL; } else { /* * We only have one string. Depending on `defmode', we take * it to be either parameters, seed or description. */ if (defmode == DEF_SEED) { seed = id; par = desc = NULL; } else if (defmode == DEF_DESC) { desc = id; par = seed = NULL; } else { par = id; seed = desc = NULL; } } /* * We must be reasonably careful here not to modify anything in * `me' until we have finished validating things. This function * must either return an error and do nothing to the midend, or * return success and do everything; nothing in between is * acceptable. */ newcurparams = newparams = oldparams1 = oldparams2 = NULL; if (par) { /* * The params string may underspecify the game parameters, so * we must first initialise newcurparams with a full set of * params from somewhere else before we decode_params the * input string over the top. * * But which set? It depends on what other data we have. * * If we've been given a _descriptive_ game id, then that may * well underspecify by design, e.g. Solo game descriptions * often start just '3x3:' without specifying one of Solo's * difficulty settings, because it isn't necessary once a game * has been generated (and you might not even know it, if * you're manually transcribing a game description). In that * situation, I've always felt that the best thing to set the * difficulty to (for use if the user hits 'New Game' after * pasting in that game id) is whatever it was previously set * to. That is, we use whatever is already in me->params as * the basis for our decoding of this input string. * * A random-seed based game id, however, should use the real, * built-in default params, and not even check the * _DEFAULT environment setting, because when people * paste each other random seeds - whether it's two users * arranging to generate the same game at the same time to * race solving them, or a user sending a bug report upstream * - the whole point is for the random game id to always be * interpreted the same way, even if it does underspecify. * * A parameter string typed in on its own, with no seed _or_ * description, gets treated the same way as a random seed, * because again I think the most likely reason for doing that * is to have a portable representation of a set of params. */ if (desc) { newcurparams = me->ourgame->dup_params(me->params); } else { newcurparams = me->ourgame->default_params(); } me->ourgame->decode_params(newcurparams, par); error = me->ourgame->validate_params(newcurparams, desc == NULL); if (error) { me->ourgame->free_params(newcurparams); return error; } oldparams1 = me->curparams; /* * Now filter only the persistent parts of this state into * the long-term params structure, unless we've _only_ * received a params string in which case the whole lot is * persistent. */ oldparams2 = me->params; if (seed || desc) { char *tmpstr; newparams = me->ourgame->dup_params(me->params); tmpstr = me->ourgame->encode_params(newcurparams, FALSE); me->ourgame->decode_params(newparams, tmpstr); sfree(tmpstr); } else { newparams = me->ourgame->dup_params(newcurparams); } free_params = TRUE; } else { newcurparams = me->curparams; newparams = me->params; free_params = FALSE; } if (desc) { error = me->ourgame->validate_desc(newparams, desc); if (error) { if (free_params) { if (newcurparams) me->ourgame->free_params(newcurparams); if (newparams) me->ourgame->free_params(newparams); } return error; } } /* * Now we've got past all possible error points. Update the * midend itself. */ me->params = newparams; me->curparams = newcurparams; if (oldparams1) me->ourgame->free_params(oldparams1); if (oldparams2) me->ourgame->free_params(oldparams2); sfree(me->desc); sfree(me->privdesc); me->desc = me->privdesc = NULL; sfree(me->seedstr); me->seedstr = NULL; if (desc) { me->desc = dupstr(desc); me->genmode = GOT_DESC; sfree(me->aux_info); me->aux_info = NULL; } if (seed) { me->seedstr = dupstr(seed); me->genmode = GOT_SEED; } return NULL; } char *midend_game_id(midend *me, char *id) { return midend_game_id_int(me, id, DEF_PARAMS); } char *midend_get_game_id(midend *me) { char *parstr, *ret; parstr = me->ourgame->encode_params(me->curparams, FALSE); assert(parstr); assert(me->desc); ret = snewn(strlen(parstr) + strlen(me->desc) + 2, char); sprintf(ret, "%s:%s", parstr, me->desc); sfree(parstr); return ret; } char *midend_get_random_seed(midend *me) { char *parstr, *ret; if (!me->seedstr) return NULL; parstr = me->ourgame->encode_params(me->curparams, TRUE); assert(parstr); ret = snewn(strlen(parstr) + strlen(me->seedstr) + 2, char); sprintf(ret, "%s#%s", parstr, me->seedstr); sfree(parstr); return ret; } char *midend_set_config(midend *me, int which, config_item *cfg) { char *error; game_params *params; switch (which) { case CFG_SETTINGS: params = me->ourgame->custom_params(cfg); error = me->ourgame->validate_params(params, TRUE); if (error) { me->ourgame->free_params(params); return error; } me->ourgame->free_params(me->params); me->params = params; break; case CFG_SEED: case CFG_DESC: error = midend_game_id_int(me, cfg[0].sval, (which == CFG_SEED ? DEF_SEED : DEF_DESC)); if (error) return error; break; } return NULL; } int midend_can_format_as_text_now(midend *me) { if (me->ourgame->can_format_as_text_ever) return me->ourgame->can_format_as_text_now(me->params); else return FALSE; } char *midend_text_format(midend *me) { if (me->ourgame->can_format_as_text_ever && me->statepos > 0 && me->ourgame->can_format_as_text_now(me->params)) return me->ourgame->text_format(me->states[me->statepos-1].state); else return NULL; } char *midend_solve(midend *me) { game_state *s; char *msg, *movestr; if (!me->ourgame->can_solve) return "This game does not support the Solve operation"; if (me->statepos < 1) return "No game set up to solve"; /* _shouldn't_ happen! */ msg = NULL; movestr = me->ourgame->solve(me->states[0].state, me->states[me->statepos-1].state, me->aux_info, &msg); if (!movestr) { if (!msg) msg = "Solve operation failed"; /* _shouldn't_ happen, but can */ return msg; } s = me->ourgame->execute_move(me->states[me->statepos-1].state, movestr); assert(s); /* * Now enter the solved state as the next move. */ midend_stop_anim(me); midend_purge_states(me); ensure(me); me->states[me->nstates].state = s; me->states[me->nstates].movestr = movestr; me->states[me->nstates].movetype = SOLVE; me->statepos = ++me->nstates; if (me->ui) me->ourgame->changed_state(me->ui, me->states[me->statepos-2].state, me->states[me->statepos-1].state); me->dir = +1; if (me->ourgame->flags & SOLVE_ANIMATES) { me->oldstate = me->ourgame->dup_game(me->states[me->statepos-2].state); me->anim_time = me->ourgame->anim_length(me->states[me->statepos-2].state, me->states[me->statepos-1].state, +1, me->ui); me->anim_pos = 0.0; } else { me->anim_time = 0.0; midend_finish_move(me); } if (me->drawing) midend_redraw(me); midend_set_timer(me); return NULL; } int midend_status(midend *me) { /* * We should probably never be called when the state stack has no * states on it at all - ideally, midends should never be left in * that state for long enough to get put down and forgotten about. * But if we are, I think we return _true_ - pedantically speaking * a midend in that state is 'vacuously solved', and more * practically, a user whose midend has been left in that state * probably _does_ want the 'new game' option to be prominent. */ if (me->statepos == 0) return +1; return me->ourgame->status(me->states[me->statepos-1].state); } char *midend_rewrite_statusbar(midend *me, char *text) { /* * An important special case is that we are occasionally called * with our own laststatus, to update the timer. */ if (me->laststatus != text) { sfree(me->laststatus); me->laststatus = dupstr(text); } if (me->ourgame->is_timed) { char timebuf[100], *ret; int min, sec; sec = (int)me->elapsed; min = sec / 60; sec %= 60; sprintf(timebuf, "[%d:%02d] ", min, sec); ret = snewn(strlen(timebuf) + strlen(text) + 1, char); strcpy(ret, timebuf); strcat(ret, text); return ret; } else { return dupstr(text); } } #define SERIALISE_MAGIC "Simon Tatham's Portable Puzzle Collection" #define SERIALISE_VERSION "1" void midend_serialise(midend *me, void (*write)(void *ctx, void *buf, int len), void *wctx) { int i; /* * Each line of the save file contains three components. First * exactly 8 characters of header word indicating what type of * data is contained on the line; then a colon followed by a * decimal integer giving the length of the main string on the * line; then a colon followed by the string itself (exactly as * many bytes as previously specified, no matter what they * contain). Then a newline (of reasonably flexible form). */ #define wr(h,s) do { \ char hbuf[80]; \ char *str = (s); \ char lbuf[9]; \ copy_left_justified(lbuf, sizeof(lbuf), h); \ sprintf(hbuf, "%s:%d:", lbuf, (int)strlen(str)); \ write(wctx, hbuf, strlen(hbuf)); \ write(wctx, str, strlen(str)); \ write(wctx, "\n", 1); \ } while (0) /* * Magic string identifying the file, and version number of the * file format. */ wr("SAVEFILE", SERIALISE_MAGIC); wr("VERSION", SERIALISE_VERSION); /* * The game name. (Copied locally to avoid const annoyance.) */ { char *s = dupstr(me->ourgame->name); wr("GAME", s); sfree(s); } /* * The current long-term parameters structure, in full. */ if (me->params) { char *s = me->ourgame->encode_params(me->params, TRUE); wr("PARAMS", s); sfree(s); } /* * The current short-term parameters structure, in full. */ if (me->curparams) { char *s = me->ourgame->encode_params(me->curparams, TRUE); wr("CPARAMS", s); sfree(s); } /* * The current game description, the privdesc, and the random seed. */ if (me->seedstr) wr("SEED", me->seedstr); if (me->desc) wr("DESC", me->desc); if (me->privdesc) wr("PRIVDESC", me->privdesc); /* * The game's aux_info. We obfuscate this to prevent spoilers * (people are likely to run `head' or similar on a saved game * file simply to find out what it is, and don't necessarily * want to be told the answer to the puzzle!) */ if (me->aux_info) { unsigned char *s1; char *s2; int len; len = strlen(me->aux_info); s1 = snewn(len, unsigned char); memcpy(s1, me->aux_info, len); obfuscate_bitmap(s1, len*8, FALSE); s2 = bin2hex(s1, len); wr("AUXINFO", s2); sfree(s2); sfree(s1); } /* * Any required serialisation of the game_ui. */ if (me->ui) { char *s = me->ourgame->encode_ui(me->ui); if (s) { wr("UI", s); sfree(s); } } /* * The game time, if it's a timed game. */ if (me->ourgame->is_timed) { char buf[80]; sprintf(buf, "%g", me->elapsed); wr("TIME", buf); } /* * The length of, and position in, the states list. */ { char buf[80]; sprintf(buf, "%d", me->nstates); wr("NSTATES", buf); sprintf(buf, "%d", me->statepos); wr("STATEPOS", buf); } /* * For each state after the initial one (which we know is * constructed from either privdesc or desc), enough * information for execute_move() to reconstruct it from the * previous one. */ for (i = 1; i < me->nstates; i++) { assert(me->states[i].movetype != NEWGAME); /* only state 0 */ switch (me->states[i].movetype) { case MOVE: wr("MOVE", me->states[i].movestr); break; case SOLVE: wr("SOLVE", me->states[i].movestr); break; case RESTART: wr("RESTART", me->states[i].movestr); break; } } #undef wr } /* * This function returns NULL on success, or an error message. */ char *midend_deserialise(midend *me, int (*read)(void *ctx, void *buf, int len), void *rctx) { int nstates = 0, statepos = -1, gotstates = 0; int started = FALSE; int i; char *val = NULL; /* Initially all errors give the same report */ char *ret = "Data does not appear to be a saved game file"; /* * We construct all the new state in local variables while we * check its sanity. Only once we have finished reading the * serialised data and detected no errors at all do we start * modifying stuff in the midend passed in. */ char *seed = NULL, *parstr = NULL, *desc = NULL, *privdesc = NULL; char *auxinfo = NULL, *uistr = NULL, *cparstr = NULL; float elapsed = 0.0F; game_params *params = NULL, *cparams = NULL; game_ui *ui = NULL; struct midend_state_entry *states = NULL; /* * Loop round and round reading one key/value pair at a time * from the serialised stream, until we have enough game states * to finish. */ while (nstates <= 0 || statepos < 0 || gotstates < nstates-1) { char key[9], c; int len; do { if (!read(rctx, key, 1)) { /* unexpected EOF */ goto cleanup; } } while (key[0] == '\r' || key[0] == '\n'); if (!read(rctx, key+1, 8)) { /* unexpected EOF */ goto cleanup; } if (key[8] != ':') { if (started) ret = "Data was incorrectly formatted for a saved game file"; goto cleanup; } len = strcspn(key, ": "); assert(len <= 8); key[len] = '\0'; len = 0; while (1) { if (!read(rctx, &c, 1)) { /* unexpected EOF */ goto cleanup; } if (c == ':') { break; } else if (c >= '0' && c <= '9') { len = (len * 10) + (c - '0'); } else { if (started) ret = "Data was incorrectly formatted for a" " saved game file"; goto cleanup; } } val = snewn(len+1, char); if (!read(rctx, val, len)) { if (started) goto cleanup; } val[len] = '\0'; if (!started) { if (strcmp(key, "SAVEFILE") || strcmp(val, SERIALISE_MAGIC)) { /* ret already has the right message in it */ goto cleanup; } /* Now most errors are this one, unless otherwise specified */ ret = "Saved data ended unexpectedly"; started = TRUE; } else { if (!strcmp(key, "VERSION")) { if (strcmp(val, SERIALISE_VERSION)) { ret = "Cannot handle this version of the saved game" " file format"; goto cleanup; } } else if (!strcmp(key, "GAME")) { if (strcmp(val, me->ourgame->name)) { ret = "Save file is from a different game"; goto cleanup; } } else if (!strcmp(key, "PARAMS")) { sfree(parstr); parstr = val; val = NULL; } else if (!strcmp(key, "CPARAMS")) { sfree(cparstr); cparstr = val; val = NULL; } else if (!strcmp(key, "SEED")) { sfree(seed); seed = val; val = NULL; } else if (!strcmp(key, "DESC")) { sfree(desc); desc = val; val = NULL; } else if (!strcmp(key, "PRIVDESC")) { sfree(privdesc); privdesc = val; val = NULL; } else if (!strcmp(key, "AUXINFO")) { unsigned char *tmp; int len = strlen(val) / 2; /* length in bytes */ tmp = hex2bin(val, len); obfuscate_bitmap(tmp, len*8, TRUE); sfree(auxinfo); auxinfo = snewn(len + 1, char); memcpy(auxinfo, tmp, len); auxinfo[len] = '\0'; sfree(tmp); } else if (!strcmp(key, "UI")) { sfree(uistr); uistr = val; val = NULL; } else if (!strcmp(key, "TIME")) { elapsed = (float)atof(val); } else if (!strcmp(key, "NSTATES")) { nstates = atoi(val); if (nstates <= 0) { ret = "Number of states in save file was negative"; goto cleanup; } if (states) { ret = "Two state counts provided in save file"; goto cleanup; } states = snewn(nstates, struct midend_state_entry); for (i = 0; i < nstates; i++) { states[i].state = NULL; states[i].movestr = NULL; states[i].movetype = NEWGAME; } } else if (!strcmp(key, "STATEPOS")) { statepos = atoi(val); } else if (!strcmp(key, "MOVE")) { gotstates++; states[gotstates].movetype = MOVE; states[gotstates].movestr = val; val = NULL; } else if (!strcmp(key, "SOLVE")) { gotstates++; states[gotstates].movetype = SOLVE; states[gotstates].movestr = val; val = NULL; } else if (!strcmp(key, "RESTART")) { gotstates++; states[gotstates].movetype = RESTART; states[gotstates].movestr = val; val = NULL; } } sfree(val); val = NULL; } params = me->ourgame->default_params(); me->ourgame->decode_params(params, parstr); if (me->ourgame->validate_params(params, TRUE)) { ret = "Long-term parameters in save file are invalid"; goto cleanup; } cparams = me->ourgame->default_params(); me->ourgame->decode_params(cparams, cparstr); if (me->ourgame->validate_params(cparams, FALSE)) { ret = "Short-term parameters in save file are invalid"; goto cleanup; } if (seed && me->ourgame->validate_params(cparams, TRUE)) { /* * The seed's no use with this version, but we can perfectly * well use the rest of the data. */ sfree(seed); seed = NULL; } if (!desc) { ret = "Game description in save file is missing"; goto cleanup; } else if (me->ourgame->validate_desc(params, desc)) { ret = "Game description in save file is invalid"; goto cleanup; } if (privdesc && me->ourgame->validate_desc(params, privdesc)) { ret = "Game private description in save file is invalid"; goto cleanup; } if (statepos < 0 || statepos >= nstates) { ret = "Game position in save file is out of range"; } states[0].state = me->ourgame->new_game(me, params, privdesc ? privdesc : desc); for (i = 1; i < nstates; i++) { assert(states[i].movetype != NEWGAME); switch (states[i].movetype) { case MOVE: case SOLVE: states[i].state = me->ourgame->execute_move(states[i-1].state, states[i].movestr); if (states[i].state == NULL) { ret = "Save file contained an invalid move"; goto cleanup; } break; case RESTART: if (me->ourgame->validate_desc(params, states[i].movestr)) { ret = "Save file contained an invalid restart move"; goto cleanup; } states[i].state = me->ourgame->new_game(me, params, states[i].movestr); break; } } ui = me->ourgame->new_ui(states[0].state); me->ourgame->decode_ui(ui, uistr); /* * Now we've run out of possible error conditions, so we're * ready to start overwriting the real data in the current * midend. We'll do this by swapping things with the local * variables, so that the same cleanup code will free the old * stuff. */ { char *tmp; tmp = me->desc; me->desc = desc; desc = tmp; tmp = me->privdesc; me->privdesc = privdesc; privdesc = tmp; tmp = me->seedstr; me->seedstr = seed; seed = tmp; tmp = me->aux_info; me->aux_info = auxinfo; auxinfo = tmp; } me->genmode = GOT_NOTHING; me->statesize = nstates; nstates = me->nstates; me->nstates = me->statesize; { struct midend_state_entry *tmp; tmp = me->states; me->states = states; states = tmp; } me->statepos = statepos; { game_params *tmp; tmp = me->params; me->params = params; params = tmp; tmp = me->curparams; me->curparams = cparams; cparams = tmp; } me->oldstate = NULL; me->anim_time = me->anim_pos = me->flash_time = me->flash_pos = 0.0F; me->dir = 0; { game_ui *tmp; tmp = me->ui; me->ui = ui; ui = tmp; } me->elapsed = elapsed; me->pressed_mouse_button = 0; midend_set_timer(me); if (me->drawstate) me->ourgame->free_drawstate(me->drawing, me->drawstate); me->drawstate = me->ourgame->new_drawstate(me->drawing, me->states[me->statepos-1].state); midend_size_new_drawstate(me); ret = NULL; /* success! */ cleanup: sfree(val); sfree(seed); sfree(parstr); sfree(cparstr); sfree(desc); sfree(privdesc); sfree(auxinfo); sfree(uistr); if (params) me->ourgame->free_params(params); if (cparams) me->ourgame->free_params(cparams); if (ui) me->ourgame->free_ui(ui); if (states) { int i; for (i = 0; i < nstates; i++) { if (states[i].state) me->ourgame->free_game(states[i].state); sfree(states[i].movestr); } sfree(states); } return ret; } /* * This function examines a saved game file just far enough to * determine which game type it contains. It returns NULL on success * and the game name string in 'name' (which will be dynamically * allocated and should be caller-freed), or an error message on * failure. */ char *identify_game(char **name, int (*read)(void *ctx, void *buf, int len), void *rctx) { int nstates = 0, statepos = -1, gotstates = 0; int started = FALSE; char *val = NULL; /* Initially all errors give the same report */ char *ret = "Data does not appear to be a saved game file"; *name = NULL; /* * Loop round and round reading one key/value pair at a time from * the serialised stream, until we've found the game name. */ while (nstates <= 0 || statepos < 0 || gotstates < nstates-1) { char key[9], c; int len; do { if (!read(rctx, key, 1)) { /* unexpected EOF */ goto cleanup; } } while (key[0] == '\r' || key[0] == '\n'); if (!read(rctx, key+1, 8)) { /* unexpected EOF */ goto cleanup; } if (key[8] != ':') { if (started) ret = "Data was incorrectly formatted for a saved game file"; goto cleanup; } len = strcspn(key, ": "); assert(len <= 8); key[len] = '\0'; len = 0; while (1) { if (!read(rctx, &c, 1)) { /* unexpected EOF */ goto cleanup; } if (c == ':') { break; } else if (c >= '0' && c <= '9') { len = (len * 10) + (c - '0'); } else { if (started) ret = "Data was incorrectly formatted for a" " saved game file"; goto cleanup; } } val = snewn(len+1, char); if (!read(rctx, val, len)) { if (started) goto cleanup; } val[len] = '\0'; if (!started) { if (strcmp(key, "SAVEFILE") || strcmp(val, SERIALISE_MAGIC)) { /* ret already has the right message in it */ goto cleanup; } /* Now most errors are this one, unless otherwise specified */ ret = "Saved data ended unexpectedly"; started = TRUE; } else { if (!strcmp(key, "VERSION")) { if (strcmp(val, SERIALISE_VERSION)) { ret = "Cannot handle this version of the saved game" " file format"; goto cleanup; } } else if (!strcmp(key, "GAME")) { *name = dupstr(val); ret = NULL; goto cleanup; } } sfree(val); val = NULL; } cleanup: sfree(val); return ret; } char *midend_print_puzzle(midend *me, document *doc, int with_soln) { game_state *soln = NULL; if (me->statepos < 1) return "No game set up to print";/* _shouldn't_ happen! */ if (with_soln) { char *msg, *movestr; if (!me->ourgame->can_solve) return "This game does not support the Solve operation"; msg = "Solve operation failed";/* game _should_ overwrite on error */ movestr = me->ourgame->solve(me->states[0].state, me->states[me->statepos-1].state, me->aux_info, &msg); if (!movestr) return msg; soln = me->ourgame->execute_move(me->states[me->statepos-1].state, movestr); assert(soln); sfree(movestr); } else soln = NULL; /* * This call passes over ownership of the two game_states and * the game_params. Hence we duplicate the ones we want to * keep, and we don't have to bother freeing soln if it was * non-NULL. */ document_add_puzzle(doc, me->ourgame, me->ourgame->dup_params(me->curparams), me->ourgame->dup_game(me->states[0].state), soln); return NULL; } puzzles-20170606.272beef/maxflow.c0000644000175000017500000002373513115373615015524 0ustar simonsimon/* * Edmonds-Karp algorithm for finding a maximum flow and minimum * cut in a network. Almost identical to the Ford-Fulkerson * algorithm, but apparently using breadth-first search to find the * _shortest_ augmenting path is a good way to guarantee * termination and ensure the time complexity is not dependent on * the actual value of the maximum flow. I don't understand why * that should be, but it's claimed on the Internet that it's been * proved, and that's good enough for me. I prefer BFS to DFS * anyway :-) */ #include #include #include #include "maxflow.h" #include "puzzles.h" /* for snewn/sfree */ int maxflow_with_scratch(void *scratch, int nv, int source, int sink, int ne, const int *edges, const int *backedges, const int *capacity, int *flow, int *cut) { int *todo = (int *)scratch; int *prev = todo + nv; int *firstedge = todo + 2*nv; int *firstbackedge = todo + 3*nv; int i, j, head, tail, from, to; int totalflow; /* * Scan the edges array to find the index of the first edge * from each node. */ j = 0; for (i = 0; i < ne; i++) while (j <= edges[2*i]) firstedge[j++] = i; while (j < nv) firstedge[j++] = ne; assert(j == nv); /* * Scan the backedges array to find the index of the first edge * _to_ each node. */ j = 0; for (i = 0; i < ne; i++) while (j <= edges[2*backedges[i]+1]) firstbackedge[j++] = i; while (j < nv) firstbackedge[j++] = ne; assert(j == nv); /* * Start the flow off at zero on every edge. */ for (i = 0; i < ne; i++) flow[i] = 0; totalflow = 0; /* * Repeatedly look for an augmenting path, and follow it. */ while (1) { /* * Set up the prev array. */ for (i = 0; i < nv; i++) prev[i] = -1; /* * Initialise the to-do list for BFS. */ head = tail = 0; todo[tail++] = source; /* * Now do the BFS loop. */ while (head < tail && prev[sink] <= 0) { from = todo[head++]; /* * Try all the forward edges out of node `from'. For a * forward edge to be valid, it must have flow * currently less than its capacity. */ for (i = firstedge[from]; i < ne && edges[2*i] == from; i++) { to = edges[2*i+1]; if (to == source || prev[to] >= 0) continue; if (capacity[i] >= 0 && flow[i] >= capacity[i]) continue; /* * This is a valid augmenting edge. Visit node `to'. */ prev[to] = 2*i; todo[tail++] = to; } /* * Try all the backward edges into node `from'. For a * backward edge to be valid, it must have flow * currently greater than zero. */ for (i = firstbackedge[from]; j = backedges[i], i < ne && edges[2*j+1]==from; i++) { to = edges[2*j]; if (to == source || prev[to] >= 0) continue; if (flow[j] <= 0) continue; /* * This is a valid augmenting edge. Visit node `to'. */ prev[to] = 2*j+1; todo[tail++] = to; } } /* * If prev[sink] is non-null, we have found an augmenting * path. */ if (prev[sink] >= 0) { int max; /* * Work backwards along the path figuring out the * maximum flow we can add. */ to = sink; max = -1; while (to != source) { int spare; /* * Find the edge we're currently moving along. */ i = prev[to]; from = edges[i]; assert(from != to); /* * Determine the spare capacity of this edge. */ if (i & 1) spare = flow[i / 2]; /* backward edge */ else if (capacity[i / 2] >= 0) spare = capacity[i / 2] - flow[i / 2]; /* forward edge */ else spare = -1; /* unlimited forward edge */ assert(spare != 0); if (max < 0 || (spare >= 0 && spare < max)) max = spare; to = from; } /* * Fail an assertion if max is still < 0, i.e. there is * an entirely unlimited path from source to sink. Also * max should not _be_ zero, because by construction * this _should_ be an augmenting path. */ assert(max > 0); /* * Now work backwards along the path again, this time * actually adjusting the flow. */ to = sink; while (to != source) { /* * Find the edge we're currently moving along. */ i = prev[to]; from = edges[i]; assert(from != to); /* * Adjust the edge. */ if (i & 1) flow[i / 2] -= max; /* backward edge */ else flow[i / 2] += max; /* forward edge */ to = from; } /* * And adjust the overall flow counter. */ totalflow += max; continue; } /* * If we reach here, we have failed to find an augmenting * path, which means we're done. Output the `cut' array if * required, and leave. */ if (cut) { for (i = 0; i < nv; i++) { if (i == source || prev[i] >= 0) cut[i] = 0; else cut[i] = 1; } } return totalflow; } } int maxflow_scratch_size(int nv) { return (nv * 4) * sizeof(int); } void maxflow_setup_backedges(int ne, const int *edges, int *backedges) { int i, n; for (i = 0; i < ne; i++) backedges[i] = i; /* * We actually can't use the C qsort() function, because we'd * need to pass `edges' as a context parameter to its * comparator function. So instead I'm forced to implement my * own sorting algorithm internally, which is a pest. I'll use * heapsort, because I like it. */ #define LESS(i,j) ( (edges[2*(i)+1] < edges[2*(j)+1]) || \ (edges[2*(i)+1] == edges[2*(j)+1] && \ edges[2*(i)] < edges[2*(j)]) ) #define PARENT(n) ( ((n)-1)/2 ) #define LCHILD(n) ( 2*(n)+1 ) #define RCHILD(n) ( 2*(n)+2 ) #define SWAP(i,j) do { int swaptmp = (i); (i) = (j); (j) = swaptmp; } while (0) /* * Phase 1: build the heap. We want the _largest_ element at * the top. */ n = 0; while (n < ne) { n++; /* * Swap element n with its parent repeatedly to preserve * the heap property. */ i = n-1; while (i > 0) { int p = PARENT(i); if (LESS(backedges[p], backedges[i])) { SWAP(backedges[p], backedges[i]); i = p; } else break; } } /* * Phase 2: repeatedly remove the largest element and stick it * at the top of the array. */ while (n > 0) { /* * The largest element is at position 0. Put it at the top, * and swap the arbitrary element from that position into * position 0. */ n--; SWAP(backedges[0], backedges[n]); /* * Now repeatedly move that arbitrary element down the heap * by swapping it with the more suitable of its children. */ i = 0; while (1) { int lc, rc; lc = LCHILD(i); rc = RCHILD(i); if (lc >= n) break; /* we've hit bottom */ if (rc >= n) { /* * Special case: there is only one child to check. */ if (LESS(backedges[i], backedges[lc])) SWAP(backedges[i], backedges[lc]); /* _Now_ we've hit bottom. */ break; } else { /* * The common case: there are two children and we * must check them both. */ if (LESS(backedges[i], backedges[lc]) || LESS(backedges[i], backedges[rc])) { /* * Pick the more appropriate child to swap with * (i.e. the one which would want to be the * parent if one were above the other - as one * is about to be). */ if (LESS(backedges[lc], backedges[rc])) { SWAP(backedges[i], backedges[rc]); i = rc; } else { SWAP(backedges[i], backedges[lc]); i = lc; } } else { /* This element is in the right place; we're done. */ break; } } } } #undef LESS #undef PARENT #undef LCHILD #undef RCHILD #undef SWAP } int maxflow(int nv, int source, int sink, int ne, const int *edges, const int *capacity, int *flow, int *cut) { void *scratch; int *backedges; int size; int ret; /* * Allocate the space. */ size = ne * sizeof(int) + maxflow_scratch_size(nv); backedges = smalloc(size); if (!backedges) return -1; scratch = backedges + ne; /* * Set up the backedges array. */ maxflow_setup_backedges(ne, edges, backedges); /* * Call the main function. */ ret = maxflow_with_scratch(scratch, nv, source, sink, ne, edges, backedges, capacity, flow, cut); /* * Free the scratch space. */ sfree(backedges); /* * And we're done. */ return ret; } #ifdef TESTMODE #define MAXEDGES 256 #define MAXVERTICES 128 #define ADDEDGE(i,j) do{edges[ne*2] = (i); edges[ne*2+1] = (j); ne++;}while(0) int compare_edge(const void *av, const void *bv) { const int *a = (const int *)av; const int *b = (const int *)bv; if (a[0] < b[0]) return -1; else if (a[0] > b[0]) return +1; else if (a[1] < b[1]) return -1; else if (a[1] > b[1]) return +1; else return 0; } int main(void) { int edges[MAXEDGES*2], ne, nv; int capacity[MAXEDGES], flow[MAXEDGES], cut[MAXVERTICES]; int source, sink, p, q, i, j, ret; /* * Use this algorithm to find a maximal complete matching in a * bipartite graph. */ ne = 0; nv = 0; source = nv++; p = nv; nv += 5; q = nv; nv += 5; sink = nv++; for (i = 0; i < 5; i++) { capacity[ne] = 1; ADDEDGE(source, p+i); } for (i = 0; i < 5; i++) { capacity[ne] = 1; ADDEDGE(q+i, sink); } j = ne; capacity[ne] = 1; ADDEDGE(p+0,q+0); capacity[ne] = 1; ADDEDGE(p+1,q+0); capacity[ne] = 1; ADDEDGE(p+1,q+1); capacity[ne] = 1; ADDEDGE(p+2,q+1); capacity[ne] = 1; ADDEDGE(p+2,q+2); capacity[ne] = 1; ADDEDGE(p+3,q+2); capacity[ne] = 1; ADDEDGE(p+3,q+3); capacity[ne] = 1; ADDEDGE(p+4,q+3); /* capacity[ne] = 1; ADDEDGE(p+2,q+4); */ qsort(edges, ne, 2*sizeof(int), compare_edge); ret = maxflow(nv, source, sink, ne, edges, capacity, flow, cut); printf("ret = %d\n", ret); for (i = 0; i < ne; i++) printf("flow %d: %d -> %d\n", flow[i], edges[2*i], edges[2*i+1]); for (i = 0; i < nv; i++) if (cut[i] == 0) printf("difficult set includes %d\n", i); return 0; } #endif puzzles-20170606.272beef/map.c0000644000175000017500000026136413115373615014626 0ustar simonsimon/* * map.c: Game involving four-colouring a map. */ /* * TODO: * * - clue marking * - better four-colouring algorithm? */ #include #include #include #include #include #include #include "puzzles.h" /* * In standalone solver mode, `verbose' is a variable which can be * set by command-line option; in debugging mode it's simply always * true. */ #if defined STANDALONE_SOLVER #define SOLVER_DIAGNOSTICS int verbose = FALSE; #elif defined SOLVER_DIAGNOSTICS #define verbose TRUE #endif /* * I don't seriously anticipate wanting to change the number of * colours used in this game, but it doesn't cost much to use a * #define just in case :-) */ #define FOUR 4 #define THREE (FOUR-1) #define FIVE (FOUR+1) #define SIX (FOUR+2) /* * Ghastly run-time configuration option, just for Gareth (again). */ static int flash_type = -1; static float flash_length; /* * Difficulty levels. I do some macro ickery here to ensure that my * enum and the various forms of my name list always match up. */ #define DIFFLIST(A) \ A(EASY,Easy,e) \ A(NORMAL,Normal,n) \ A(HARD,Hard,h) \ A(RECURSE,Unreasonable,u) #define ENUM(upper,title,lower) DIFF_ ## upper, #define TITLE(upper,title,lower) #title, #define ENCODE(upper,title,lower) #lower #define CONFIG(upper,title,lower) ":" #title enum { DIFFLIST(ENUM) DIFFCOUNT }; static char const *const map_diffnames[] = { DIFFLIST(TITLE) }; static char const map_diffchars[] = DIFFLIST(ENCODE); #define DIFFCONFIG DIFFLIST(CONFIG) enum { TE, BE, LE, RE }; /* top/bottom/left/right edges */ enum { COL_BACKGROUND, COL_GRID, COL_0, COL_1, COL_2, COL_3, COL_ERROR, COL_ERRTEXT, NCOLOURS }; struct game_params { int w, h, n, diff; }; struct map { int refcount; int *map; int *graph; int n; int ngraph; int *immutable; int *edgex, *edgey; /* position of a point on each edge */ int *regionx, *regiony; /* position of a point in each region */ }; struct game_state { game_params p; struct map *map; int *colouring, *pencil; int completed, cheated; }; static game_params *default_params(void) { game_params *ret = snew(game_params); #ifdef PORTRAIT_SCREEN ret->w = 16; ret->h = 18; #else ret->w = 20; ret->h = 15; #endif ret->n = 30; ret->diff = DIFF_NORMAL; return ret; } static const struct game_params map_presets[] = { #ifdef PORTRAIT_SCREEN {16, 18, 30, DIFF_EASY}, {16, 18, 30, DIFF_NORMAL}, {16, 18, 30, DIFF_HARD}, {16, 18, 30, DIFF_RECURSE}, {25, 30, 75, DIFF_NORMAL}, {25, 30, 75, DIFF_HARD}, #else {20, 15, 30, DIFF_EASY}, {20, 15, 30, DIFF_NORMAL}, {20, 15, 30, DIFF_HARD}, {20, 15, 30, DIFF_RECURSE}, {30, 25, 75, DIFF_NORMAL}, {30, 25, 75, DIFF_HARD}, #endif }; static int game_fetch_preset(int i, char **name, game_params **params) { game_params *ret; char str[80]; if (i < 0 || i >= lenof(map_presets)) return FALSE; ret = snew(game_params); *ret = map_presets[i]; sprintf(str, "%dx%d, %d regions, %s", ret->w, ret->h, ret->n, map_diffnames[ret->diff]); *name = dupstr(str); *params = ret; return TRUE; } static void free_params(game_params *params) { sfree(params); } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } static void decode_params(game_params *params, char const *string) { char const *p = string; params->w = atoi(p); while (*p && isdigit((unsigned char)*p)) p++; if (*p == 'x') { p++; params->h = atoi(p); while (*p && isdigit((unsigned char)*p)) p++; } else { params->h = params->w; } if (*p == 'n') { p++; params->n = atoi(p); while (*p && (*p == '.' || isdigit((unsigned char)*p))) p++; } else { params->n = params->w * params->h / 8; } if (*p == 'd') { int i; p++; for (i = 0; i < DIFFCOUNT; i++) if (*p == map_diffchars[i]) params->diff = i; if (*p) p++; } } static char *encode_params(const game_params *params, int full) { char ret[400]; sprintf(ret, "%dx%dn%d", params->w, params->h, params->n); if (full) sprintf(ret + strlen(ret), "d%c", map_diffchars[params->diff]); return dupstr(ret); } static config_item *game_configure(const game_params *params) { config_item *ret; char buf[80]; ret = snewn(5, config_item); ret[0].name = "Width"; ret[0].type = C_STRING; sprintf(buf, "%d", params->w); ret[0].sval = dupstr(buf); ret[0].ival = 0; ret[1].name = "Height"; ret[1].type = C_STRING; sprintf(buf, "%d", params->h); ret[1].sval = dupstr(buf); ret[1].ival = 0; ret[2].name = "Regions"; ret[2].type = C_STRING; sprintf(buf, "%d", params->n); ret[2].sval = dupstr(buf); ret[2].ival = 0; ret[3].name = "Difficulty"; ret[3].type = C_CHOICES; ret[3].sval = DIFFCONFIG; ret[3].ival = params->diff; ret[4].name = NULL; ret[4].type = C_END; ret[4].sval = NULL; ret[4].ival = 0; return ret; } static game_params *custom_params(const config_item *cfg) { game_params *ret = snew(game_params); ret->w = atoi(cfg[0].sval); ret->h = atoi(cfg[1].sval); ret->n = atoi(cfg[2].sval); ret->diff = cfg[3].ival; return ret; } static char *validate_params(const game_params *params, int full) { if (params->w < 2 || params->h < 2) return "Width and height must be at least two"; if (params->n < 5) return "Must have at least five regions"; if (params->n > params->w * params->h) return "Too many regions to fit in grid"; return NULL; } /* ---------------------------------------------------------------------- * Cumulative frequency table functions. */ /* * Initialise a cumulative frequency table. (Hardly worth writing * this function; all it does is to initialise everything in the * array to zero.) */ static void cf_init(int *table, int n) { int i; for (i = 0; i < n; i++) table[i] = 0; } /* * Increment the count of symbol `sym' by `count'. */ static void cf_add(int *table, int n, int sym, int count) { int bit; bit = 1; while (sym != 0) { if (sym & bit) { table[sym] += count; sym &= ~bit; } bit <<= 1; } table[0] += count; } /* * Cumulative frequency lookup: return the total count of symbols * with value less than `sym'. */ static int cf_clookup(int *table, int n, int sym) { int bit, index, limit, count; if (sym == 0) return 0; assert(0 < sym && sym <= n); count = table[0]; /* start with the whole table size */ bit = 1; while (bit < n) bit <<= 1; limit = n; while (bit > 0) { /* * Find the least number with its lowest set bit in this * position which is greater than or equal to sym. */ index = ((sym + bit - 1) &~ (bit * 2 - 1)) + bit; if (index < limit) { count -= table[index]; limit = index; } bit >>= 1; } return count; } /* * Single frequency lookup: return the count of symbol `sym'. */ static int cf_slookup(int *table, int n, int sym) { int count, bit; assert(0 <= sym && sym < n); count = table[sym]; for (bit = 1; sym+bit < n && !(sym & bit); bit <<= 1) count -= table[sym+bit]; return count; } /* * Return the largest symbol index such that the cumulative * frequency up to that symbol is less than _or equal to_ count. */ static int cf_whichsym(int *table, int n, int count) { int bit, sym, top; assert(count >= 0 && count < table[0]); bit = 1; while (bit < n) bit <<= 1; sym = 0; top = table[0]; while (bit > 0) { if (sym+bit < n) { if (count >= top - table[sym+bit]) sym += bit; else top -= table[sym+bit]; } bit >>= 1; } return sym; } /* ---------------------------------------------------------------------- * Map generation. * * FIXME: this isn't entirely optimal at present, because it * inherently prioritises growing the largest region since there * are more squares adjacent to it. This acts as a destabilising * influence leading to a few large regions and mostly small ones. * It might be better to do it some other way. */ #define WEIGHT_INCREASED 2 /* for increased perimeter */ #define WEIGHT_DECREASED 4 /* for decreased perimeter */ #define WEIGHT_UNCHANGED 3 /* for unchanged perimeter */ /* * Look at a square and decide which colours can be extended into * it. * * If called with index < 0, it adds together one of * WEIGHT_INCREASED, WEIGHT_DECREASED or WEIGHT_UNCHANGED for each * colour that has a valid extension (according to the effect that * it would have on the perimeter of the region being extended) and * returns the overall total. * * If called with index >= 0, it returns one of the possible * colours depending on the value of index, in such a way that the * number of possible inputs which would give rise to a given * return value correspond to the weight of that value. */ static int extend_options(int w, int h, int n, int *map, int x, int y, int index) { int c, i, dx, dy; int col[8]; int total = 0; if (map[y*w+x] >= 0) { assert(index < 0); return 0; /* can't do this square at all */ } /* * Fetch the eight neighbours of this square, in order around * the square. */ for (dy = -1; dy <= +1; dy++) for (dx = -1; dx <= +1; dx++) { int index = (dy < 0 ? 6-dx : dy > 0 ? 2+dx : 2*(1+dx)); if (x+dx >= 0 && x+dx < w && y+dy >= 0 && y+dy < h) col[index] = map[(y+dy)*w+(x+dx)]; else col[index] = -1; } /* * Iterate over each colour that might be feasible. * * FIXME: this routine currently has O(n) running time. We * could turn it into O(FOUR) by only bothering to iterate over * the colours mentioned in the four neighbouring squares. */ for (c = 0; c < n; c++) { int count, neighbours, runs; /* * One of the even indices of col (representing the * orthogonal neighbours of this square) must be equal to * c, or else this square is not adjacent to region c and * obviously cannot become an extension of it at this time. */ neighbours = 0; for (i = 0; i < 8; i += 2) if (col[i] == c) neighbours++; if (!neighbours) continue; /* * Now we know this square is adjacent to region c. The * next question is, would extending it cause the region to * become non-simply-connected? If so, we mustn't do it. * * We determine this by looking around col to see if we can * find more than one separate run of colour c. */ runs = 0; for (i = 0; i < 8; i++) if (col[i] == c && col[(i+1) & 7] != c) runs++; if (runs > 1) continue; assert(runs == 1); /* * This square is a possibility. Determine its effect on * the region's perimeter (computed from the number of * orthogonal neighbours - 1 means a perimeter increase, 3 * a decrease, 2 no change; 4 is impossible because the * region would already not be simply connected) and we're * done. */ assert(neighbours > 0 && neighbours < 4); count = (neighbours == 1 ? WEIGHT_INCREASED : neighbours == 2 ? WEIGHT_UNCHANGED : WEIGHT_DECREASED); total += count; if (index >= 0 && index < count) return c; else index -= count; } assert(index < 0); return total; } static void genmap(int w, int h, int n, int *map, random_state *rs) { int wh = w*h; int x, y, i, k; int *tmp; assert(n <= wh); tmp = snewn(wh, int); /* * Clear the map, and set up `tmp' as a list of grid indices. */ for (i = 0; i < wh; i++) { map[i] = -1; tmp[i] = i; } /* * Place the region seeds by selecting n members from `tmp'. */ k = wh; for (i = 0; i < n; i++) { int j = random_upto(rs, k); map[tmp[j]] = i; tmp[j] = tmp[--k]; } /* * Re-initialise `tmp' as a cumulative frequency table. This * will store the number of possible region colours we can * extend into each square. */ cf_init(tmp, wh); /* * Go through the grid and set up the initial cumulative * frequencies. */ for (y = 0; y < h; y++) for (x = 0; x < w; x++) cf_add(tmp, wh, y*w+x, extend_options(w, h, n, map, x, y, -1)); /* * Now repeatedly choose a square we can extend a region into, * and do so. */ while (tmp[0] > 0) { int k = random_upto(rs, tmp[0]); int sq; int colour; int xx, yy; sq = cf_whichsym(tmp, wh, k); k -= cf_clookup(tmp, wh, sq); x = sq % w; y = sq / w; colour = extend_options(w, h, n, map, x, y, k); map[sq] = colour; /* * Re-scan the nine cells around the one we've just * modified. */ for (yy = max(y-1, 0); yy < min(y+2, h); yy++) for (xx = max(x-1, 0); xx < min(x+2, w); xx++) { cf_add(tmp, wh, yy*w+xx, -cf_slookup(tmp, wh, yy*w+xx) + extend_options(w, h, n, map, xx, yy, -1)); } } /* * Finally, go through and normalise the region labels into * order, meaning that indistinguishable maps are actually * identical. */ for (i = 0; i < n; i++) tmp[i] = -1; k = 0; for (i = 0; i < wh; i++) { assert(map[i] >= 0); if (tmp[map[i]] < 0) tmp[map[i]] = k++; map[i] = tmp[map[i]]; } sfree(tmp); } /* ---------------------------------------------------------------------- * Functions to handle graphs. */ /* * Having got a map in a square grid, convert it into a graph * representation. */ static int gengraph(int w, int h, int n, int *map, int *graph) { int i, j, x, y; /* * Start by setting the graph up as an adjacency matrix. We'll * turn it into a list later. */ for (i = 0; i < n*n; i++) graph[i] = 0; /* * Iterate over the map looking for all adjacencies. */ for (y = 0; y < h; y++) for (x = 0; x < w; x++) { int v, vx, vy; v = map[y*w+x]; if (x+1 < w && (vx = map[y*w+(x+1)]) != v) graph[v*n+vx] = graph[vx*n+v] = 1; if (y+1 < h && (vy = map[(y+1)*w+x]) != v) graph[v*n+vy] = graph[vy*n+v] = 1; } /* * Turn the matrix into a list. */ for (i = j = 0; i < n*n; i++) if (graph[i]) graph[j++] = i; return j; } static int graph_edge_index(int *graph, int n, int ngraph, int i, int j) { int v = i*n+j; int top, bot, mid; bot = -1; top = ngraph; while (top - bot > 1) { mid = (top + bot) / 2; if (graph[mid] == v) return mid; else if (graph[mid] < v) bot = mid; else top = mid; } return -1; } #define graph_adjacent(graph, n, ngraph, i, j) \ (graph_edge_index((graph), (n), (ngraph), (i), (j)) >= 0) static int graph_vertex_start(int *graph, int n, int ngraph, int i) { int v = i*n; int top, bot, mid; bot = -1; top = ngraph; while (top - bot > 1) { mid = (top + bot) / 2; if (graph[mid] < v) bot = mid; else top = mid; } return top; } /* ---------------------------------------------------------------------- * Generate a four-colouring of a graph. * * FIXME: it would be nice if we could convert this recursion into * pseudo-recursion using some sort of explicit stack array, for * the sake of the Palm port and its limited stack. */ static int fourcolour_recurse(int *graph, int n, int ngraph, int *colouring, int *scratch, random_state *rs) { int nfree, nvert, start, i, j, k, c, ci; int cs[FOUR]; /* * Find the smallest number of free colours in any uncoloured * vertex, and count the number of such vertices. */ nfree = FIVE; /* start off bigger than FOUR! */ nvert = 0; for (i = 0; i < n; i++) if (colouring[i] < 0 && scratch[i*FIVE+FOUR] <= nfree) { if (nfree > scratch[i*FIVE+FOUR]) { nfree = scratch[i*FIVE+FOUR]; nvert = 0; } nvert++; } /* * If there aren't any uncoloured vertices at all, we're done. */ if (nvert == 0) return TRUE; /* we've got a colouring! */ /* * Pick a random vertex in that set. */ j = random_upto(rs, nvert); for (i = 0; i < n; i++) if (colouring[i] < 0 && scratch[i*FIVE+FOUR] == nfree) if (j-- == 0) break; assert(i < n); start = graph_vertex_start(graph, n, ngraph, i); /* * Loop over the possible colours for i, and recurse for each * one. */ ci = 0; for (c = 0; c < FOUR; c++) if (scratch[i*FIVE+c] == 0) cs[ci++] = c; shuffle(cs, ci, sizeof(*cs), rs); while (ci-- > 0) { c = cs[ci]; /* * Fill in this colour. */ colouring[i] = c; /* * Update the scratch space to reflect a new neighbour * of this colour for each neighbour of vertex i. */ for (j = start; j < ngraph && graph[j] < n*(i+1); j++) { k = graph[j] - i*n; if (scratch[k*FIVE+c] == 0) scratch[k*FIVE+FOUR]--; scratch[k*FIVE+c]++; } /* * Recurse. */ if (fourcolour_recurse(graph, n, ngraph, colouring, scratch, rs)) return TRUE; /* got one! */ /* * If that didn't work, clean up and try again with a * different colour. */ for (j = start; j < ngraph && graph[j] < n*(i+1); j++) { k = graph[j] - i*n; scratch[k*FIVE+c]--; if (scratch[k*FIVE+c] == 0) scratch[k*FIVE+FOUR]++; } colouring[i] = -1; } /* * If we reach here, we were unable to find a colouring at all. * (This doesn't necessarily mean the Four Colour Theorem is * violated; it might just mean we've gone down a dead end and * need to back up and look somewhere else. It's only an FCT * violation if we get all the way back up to the top level and * still fail.) */ return FALSE; } static void fourcolour(int *graph, int n, int ngraph, int *colouring, random_state *rs) { int *scratch; int i; /* * For each vertex and each colour, we store the number of * neighbours that have that colour. Also, we store the number * of free colours for the vertex. */ scratch = snewn(n * FIVE, int); for (i = 0; i < n * FIVE; i++) scratch[i] = (i % FIVE == FOUR ? FOUR : 0); /* * Clear the colouring to start with. */ for (i = 0; i < n; i++) colouring[i] = -1; i = fourcolour_recurse(graph, n, ngraph, colouring, scratch, rs); assert(i); /* by the Four Colour Theorem :-) */ sfree(scratch); } /* ---------------------------------------------------------------------- * Non-recursive solver. */ struct solver_scratch { unsigned char *possible; /* bitmap of colours for each region */ int *graph; int n; int ngraph; int *bfsqueue; int *bfscolour; #ifdef SOLVER_DIAGNOSTICS int *bfsprev; #endif int depth; }; static struct solver_scratch *new_scratch(int *graph, int n, int ngraph) { struct solver_scratch *sc; sc = snew(struct solver_scratch); sc->graph = graph; sc->n = n; sc->ngraph = ngraph; sc->possible = snewn(n, unsigned char); sc->depth = 0; sc->bfsqueue = snewn(n, int); sc->bfscolour = snewn(n, int); #ifdef SOLVER_DIAGNOSTICS sc->bfsprev = snewn(n, int); #endif return sc; } static void free_scratch(struct solver_scratch *sc) { sfree(sc->possible); sfree(sc->bfsqueue); sfree(sc->bfscolour); #ifdef SOLVER_DIAGNOSTICS sfree(sc->bfsprev); #endif sfree(sc); } /* * Count the bits in a word. Only needs to cope with FOUR bits. */ static int bitcount(int word) { assert(FOUR <= 4); /* or this needs changing */ word = ((word & 0xA) >> 1) + (word & 0x5); word = ((word & 0xC) >> 2) + (word & 0x3); return word; } #ifdef SOLVER_DIAGNOSTICS static const char colnames[FOUR] = { 'R', 'Y', 'G', 'B' }; #endif static int place_colour(struct solver_scratch *sc, int *colouring, int index, int colour #ifdef SOLVER_DIAGNOSTICS , char *verb #endif ) { int *graph = sc->graph, n = sc->n, ngraph = sc->ngraph; int j, k; if (!(sc->possible[index] & (1 << colour))) { #ifdef SOLVER_DIAGNOSTICS if (verbose) printf("%*scannot place %c in region %d\n", 2*sc->depth, "", colnames[colour], index); #endif return FALSE; /* can't do it */ } sc->possible[index] = 1 << colour; colouring[index] = colour; #ifdef SOLVER_DIAGNOSTICS if (verbose) printf("%*s%s %c in region %d\n", 2*sc->depth, "", verb, colnames[colour], index); #endif /* * Rule out this colour from all the region's neighbours. */ for (j = graph_vertex_start(graph, n, ngraph, index); j < ngraph && graph[j] < n*(index+1); j++) { k = graph[j] - index*n; #ifdef SOLVER_DIAGNOSTICS if (verbose && (sc->possible[k] & (1 << colour))) printf("%*s ruling out %c in region %d\n", 2*sc->depth, "", colnames[colour], k); #endif sc->possible[k] &= ~(1 << colour); } return TRUE; } #ifdef SOLVER_DIAGNOSTICS static char *colourset(char *buf, int set) { int i; char *p = buf; char *sep = ""; for (i = 0; i < FOUR; i++) if (set & (1 << i)) { p += sprintf(p, "%s%c", sep, colnames[i]); sep = ","; } return buf; } #endif /* * Returns 0 for impossible, 1 for success, 2 for failure to * converge (i.e. puzzle is either ambiguous or just too * difficult). */ static int map_solver(struct solver_scratch *sc, int *graph, int n, int ngraph, int *colouring, int difficulty) { int i; if (sc->depth == 0) { /* * Initialise scratch space. */ for (i = 0; i < n; i++) sc->possible[i] = (1 << FOUR) - 1; /* * Place clues. */ for (i = 0; i < n; i++) if (colouring[i] >= 0) { if (!place_colour(sc, colouring, i, colouring[i] #ifdef SOLVER_DIAGNOSTICS , "initial clue:" #endif )) { #ifdef SOLVER_DIAGNOSTICS if (verbose) printf("%*sinitial clue set is inconsistent\n", 2*sc->depth, ""); #endif return 0; /* the clues aren't even consistent! */ } } } /* * Now repeatedly loop until we find nothing further to do. */ while (1) { int done_something = FALSE; if (difficulty < DIFF_EASY) break; /* can't do anything at all! */ /* * Simplest possible deduction: find a region with only one * possible colour. */ for (i = 0; i < n; i++) if (colouring[i] < 0) { int p = sc->possible[i]; if (p == 0) { #ifdef SOLVER_DIAGNOSTICS if (verbose) printf("%*sregion %d has no possible colours left\n", 2*sc->depth, "", i); #endif return 0; /* puzzle is inconsistent */ } if ((p & (p-1)) == 0) { /* p is a power of two */ int c, ret; for (c = 0; c < FOUR; c++) if (p == (1 << c)) break; assert(c < FOUR); ret = place_colour(sc, colouring, i, c #ifdef SOLVER_DIAGNOSTICS , "placing" #endif ); /* * place_colour() can only fail if colour c was not * even a _possibility_ for region i, and we're * pretty sure it was because we checked before * calling place_colour(). So we can safely assert * here rather than having to return a nice * friendly error code. */ assert(ret); done_something = TRUE; } } if (done_something) continue; if (difficulty < DIFF_NORMAL) break; /* can't do anything harder */ /* * Failing that, go up one level. Look for pairs of regions * which (a) both have the same pair of possible colours, * (b) are adjacent to one another, (c) are adjacent to the * same region, and (d) that region still thinks it has one * or both of those possible colours. * * Simplest way to do this is by going through the graph * edge by edge, so that we start with property (b) and * then look for (a) and finally (c) and (d). */ for (i = 0; i < ngraph; i++) { int j1 = graph[i] / n, j2 = graph[i] % n; int j, k, v, v2; #ifdef SOLVER_DIAGNOSTICS int started = FALSE; #endif if (j1 > j2) continue; /* done it already, other way round */ if (colouring[j1] >= 0 || colouring[j2] >= 0) continue; /* they're not undecided */ if (sc->possible[j1] != sc->possible[j2]) continue; /* they don't have the same possibles */ v = sc->possible[j1]; /* * See if v contains exactly two set bits. */ v2 = v & -v; /* find lowest set bit */ v2 = v & ~v2; /* clear it */ if (v2 == 0 || (v2 & (v2-1)) != 0) /* not power of 2 */ continue; /* * We've found regions j1 and j2 satisfying properties * (a) and (b): they have two possible colours between * them, and since they're adjacent to one another they * must use _both_ those colours between them. * Therefore, if they are both adjacent to any other * region then that region cannot be either colour. * * Go through the neighbours of j1 and see if any are * shared with j2. */ for (j = graph_vertex_start(graph, n, ngraph, j1); j < ngraph && graph[j] < n*(j1+1); j++) { k = graph[j] - j1*n; if (graph_adjacent(graph, n, ngraph, k, j2) && (sc->possible[k] & v)) { #ifdef SOLVER_DIAGNOSTICS if (verbose) { char buf[80]; if (!started) printf("%*sadjacent regions %d,%d share colours" " %s\n", 2*sc->depth, "", j1, j2, colourset(buf, v)); started = TRUE; printf("%*s ruling out %s in region %d\n",2*sc->depth, "", colourset(buf, sc->possible[k] & v), k); } #endif sc->possible[k] &= ~v; done_something = TRUE; } } } if (done_something) continue; if (difficulty < DIFF_HARD) break; /* can't do anything harder */ /* * Right; now we get creative. Now we're going to look for * `forcing chains'. A forcing chain is a path through the * graph with the following properties: * * (a) Each vertex on the path has precisely two possible * colours. * * (b) Each pair of vertices which are adjacent on the * path share at least one possible colour in common. * * (c) Each vertex in the middle of the path shares _both_ * of its colours with at least one of its neighbours * (not the same one with both neighbours). * * These together imply that at least one of the possible * colour choices at one end of the path forces _all_ the * rest of the colours along the path. In order to make * real use of this, we need further properties: * * (c) Ruling out some colour C from the vertex at one end * of the path forces the vertex at the other end to * take colour C. * * (d) The two end vertices are mutually adjacent to some * third vertex. * * (e) That third vertex currently has C as a possibility. * * If we can find all of that lot, we can deduce that at * least one of the two ends of the forcing chain has * colour C, and that therefore the mutually adjacent third * vertex does not. * * To find forcing chains, we're going to start a bfs at * each suitable vertex of the graph, once for each of its * two possible colours. */ for (i = 0; i < n; i++) { int c; if (colouring[i] >= 0 || bitcount(sc->possible[i]) != 2) continue; for (c = 0; c < FOUR; c++) if (sc->possible[i] & (1 << c)) { int j, k, gi, origc, currc, head, tail; /* * Try a bfs from this vertex, ruling out * colour c. * * Within this loop, we work in colour bitmaps * rather than actual colours, because * converting back and forth is a needless * computational expense. */ origc = 1 << c; for (j = 0; j < n; j++) { sc->bfscolour[j] = -1; #ifdef SOLVER_DIAGNOSTICS sc->bfsprev[j] = -1; #endif } head = tail = 0; sc->bfsqueue[tail++] = i; sc->bfscolour[i] = sc->possible[i] &~ origc; while (head < tail) { j = sc->bfsqueue[head++]; currc = sc->bfscolour[j]; /* * Try neighbours of j. */ for (gi = graph_vertex_start(graph, n, ngraph, j); gi < ngraph && graph[gi] < n*(j+1); gi++) { k = graph[gi] - j*n; /* * To continue with the bfs in vertex * k, we need k to be * (a) not already visited * (b) have two possible colours * (c) those colours include currc. */ if (sc->bfscolour[k] < 0 && colouring[k] < 0 && bitcount(sc->possible[k]) == 2 && (sc->possible[k] & currc)) { sc->bfsqueue[tail++] = k; sc->bfscolour[k] = sc->possible[k] &~ currc; #ifdef SOLVER_DIAGNOSTICS sc->bfsprev[k] = j; #endif } /* * One other possibility is that k * might be the region in which we can * make a real deduction: if it's * adjacent to i, contains currc as a * possibility, and currc is equal to * the original colour we ruled out. */ if (currc == origc && graph_adjacent(graph, n, ngraph, k, i) && (sc->possible[k] & currc)) { #ifdef SOLVER_DIAGNOSTICS if (verbose) { char buf[80], *sep = ""; int r; printf("%*sforcing chain, colour %s, ", 2*sc->depth, "", colourset(buf, origc)); for (r = j; r != -1; r = sc->bfsprev[r]) { printf("%s%d", sep, r); sep = "-"; } printf("\n%*s ruling out %s in region" " %d\n", 2*sc->depth, "", colourset(buf, origc), k); } #endif sc->possible[k] &= ~origc; done_something = TRUE; } } } assert(tail <= n); } } if (!done_something) break; } /* * See if we've got a complete solution, and return if so. */ for (i = 0; i < n; i++) if (colouring[i] < 0) break; if (i == n) { #ifdef SOLVER_DIAGNOSTICS if (verbose) printf("%*sone solution found\n", 2*sc->depth, ""); #endif return 1; /* success! */ } /* * If recursion is not permissible, we now give up. */ if (difficulty < DIFF_RECURSE) { #ifdef SOLVER_DIAGNOSTICS if (verbose) printf("%*sunable to proceed further without recursion\n", 2*sc->depth, ""); #endif return 2; /* unable to complete */ } /* * Now we've got to do something recursive. So first hunt for a * currently-most-constrained region. */ { int best, bestc; struct solver_scratch *rsc; int *subcolouring, *origcolouring; int ret, subret; int we_already_got_one; best = -1; bestc = FIVE; for (i = 0; i < n; i++) if (colouring[i] < 0) { int p = sc->possible[i]; enum { compile_time_assertion = 1 / (FOUR <= 4) }; int c; /* Count the set bits. */ c = (p & 5) + ((p >> 1) & 5); c = (c & 3) + ((c >> 2) & 3); assert(c > 1); /* or colouring[i] would be >= 0 */ if (c < bestc) { best = i; bestc = c; } } assert(best >= 0); /* or we'd be solved already */ #ifdef SOLVER_DIAGNOSTICS if (verbose) printf("%*srecursing on region %d\n", 2*sc->depth, "", best); #endif /* * Now iterate over the possible colours for this region. */ rsc = new_scratch(graph, n, ngraph); rsc->depth = sc->depth + 1; origcolouring = snewn(n, int); memcpy(origcolouring, colouring, n * sizeof(int)); subcolouring = snewn(n, int); we_already_got_one = FALSE; ret = 0; for (i = 0; i < FOUR; i++) { if (!(sc->possible[best] & (1 << i))) continue; memcpy(rsc->possible, sc->possible, n); memcpy(subcolouring, origcolouring, n * sizeof(int)); place_colour(rsc, subcolouring, best, i #ifdef SOLVER_DIAGNOSTICS , "trying" #endif ); subret = map_solver(rsc, graph, n, ngraph, subcolouring, difficulty); #ifdef SOLVER_DIAGNOSTICS if (verbose) { printf("%*sretracting %c in region %d; found %s\n", 2*sc->depth, "", colnames[i], best, subret == 0 ? "no solutions" : subret == 1 ? "one solution" : "multiple solutions"); } #endif /* * If this possibility turned up more than one valid * solution, or if it turned up one and we already had * one, we're definitely ambiguous. */ if (subret == 2 || (subret == 1 && we_already_got_one)) { ret = 2; break; } /* * If this possibility turned up one valid solution and * it's the first we've seen, copy it into the output. */ if (subret == 1) { memcpy(colouring, subcolouring, n * sizeof(int)); we_already_got_one = TRUE; ret = 1; } /* * Otherwise, this guess led to a contradiction, so we * do nothing. */ } sfree(origcolouring); sfree(subcolouring); free_scratch(rsc); #ifdef SOLVER_DIAGNOSTICS if (verbose && sc->depth == 0) { printf("%*s%s found\n", 2*sc->depth, "", ret == 0 ? "no solutions" : ret == 1 ? "one solution" : "multiple solutions"); } #endif return ret; } } /* ---------------------------------------------------------------------- * Game generation main function. */ static char *new_game_desc(const game_params *params, random_state *rs, char **aux, int interactive) { struct solver_scratch *sc = NULL; int *map, *graph, ngraph, *colouring, *colouring2, *regions; int i, j, w, h, n, solveret, cfreq[FOUR]; int wh; int mindiff, tries; #ifdef GENERATION_DIAGNOSTICS int x, y; #endif char *ret, buf[80]; int retlen, retsize; w = params->w; h = params->h; n = params->n; wh = w*h; *aux = NULL; map = snewn(wh, int); graph = snewn(n*n, int); colouring = snewn(n, int); colouring2 = snewn(n, int); regions = snewn(n, int); /* * This is the minimum difficulty below which we'll completely * reject a map design. Normally we set this to one below the * requested difficulty, ensuring that we have the right * result. However, for particularly dense maps or maps with * particularly few regions it might not be possible to get the * desired difficulty, so we will eventually drop this down to * -1 to indicate that any old map will do. */ mindiff = params->diff; tries = 50; while (1) { /* * Create the map. */ genmap(w, h, n, map, rs); #ifdef GENERATION_DIAGNOSTICS for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { int v = map[y*w+x]; if (v >= 62) putchar('!'); else if (v >= 36) putchar('a' + v-36); else if (v >= 10) putchar('A' + v-10); else putchar('0' + v); } putchar('\n'); } #endif /* * Convert the map into a graph. */ ngraph = gengraph(w, h, n, map, graph); #ifdef GENERATION_DIAGNOSTICS for (i = 0; i < ngraph; i++) printf("%d-%d\n", graph[i]/n, graph[i]%n); #endif /* * Colour the map. */ fourcolour(graph, n, ngraph, colouring, rs); #ifdef GENERATION_DIAGNOSTICS for (i = 0; i < n; i++) printf("%d: %d\n", i, colouring[i]); for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { int v = colouring[map[y*w+x]]; if (v >= 36) putchar('a' + v-36); else if (v >= 10) putchar('A' + v-10); else putchar('0' + v); } putchar('\n'); } #endif /* * Encode the solution as an aux string. */ if (*aux) /* in case we've come round again */ sfree(*aux); retlen = retsize = 0; ret = NULL; for (i = 0; i < n; i++) { int len; if (colouring[i] < 0) continue; len = sprintf(buf, "%s%d:%d", i ? ";" : "S;", colouring[i], i); if (retlen + len >= retsize) { retsize = retlen + len + 256; ret = sresize(ret, retsize, char); } strcpy(ret + retlen, buf); retlen += len; } *aux = ret; /* * Remove the region colours one by one, keeping * solubility. Also ensure that there always remains at * least one region of every colour, so that the user can * drag from somewhere. */ for (i = 0; i < FOUR; i++) cfreq[i] = 0; for (i = 0; i < n; i++) { regions[i] = i; cfreq[colouring[i]]++; } for (i = 0; i < FOUR; i++) if (cfreq[i] == 0) continue; shuffle(regions, n, sizeof(*regions), rs); if (sc) free_scratch(sc); sc = new_scratch(graph, n, ngraph); for (i = 0; i < n; i++) { j = regions[i]; if (cfreq[colouring[j]] == 1) continue; /* can't remove last region of colour */ memcpy(colouring2, colouring, n*sizeof(int)); colouring2[j] = -1; solveret = map_solver(sc, graph, n, ngraph, colouring2, params->diff); assert(solveret >= 0); /* mustn't be impossible! */ if (solveret == 1) { cfreq[colouring[j]]--; colouring[j] = -1; } } #ifdef GENERATION_DIAGNOSTICS for (i = 0; i < n; i++) if (colouring[i] >= 0) { if (i >= 62) putchar('!'); else if (i >= 36) putchar('a' + i-36); else if (i >= 10) putchar('A' + i-10); else putchar('0' + i); printf(": %d\n", colouring[i]); } #endif /* * Finally, check that the puzzle is _at least_ as hard as * required, and indeed that it isn't already solved. * (Calling map_solver with negative difficulty ensures the * latter - if a solver which _does nothing_ can solve it, * it's too easy!) */ memcpy(colouring2, colouring, n*sizeof(int)); if (map_solver(sc, graph, n, ngraph, colouring2, mindiff - 1) == 1) { /* * Drop minimum difficulty if necessary. */ if (mindiff > 0 && (n < 9 || n > 2*wh/3)) { if (tries-- <= 0) mindiff = 0; /* give up and go for Easy */ } continue; } break; } /* * Encode as a game ID. We do this by: * * - first going along the horizontal edges row by row, and * then the vertical edges column by column * - encoding the lengths of runs of edges and runs of * non-edges * - the decoder will reconstitute the region boundaries from * this and automatically number them the same way we did * - then we encode the initial region colours in a Slant-like * fashion (digits 0-3 interspersed with letters giving * lengths of runs of empty spaces). */ retlen = retsize = 0; ret = NULL; { int run, pv; /* * Start with a notional non-edge, so that there'll be an * explicit `a' to distinguish the case where we start with * an edge. */ run = 1; pv = 0; for (i = 0; i < w*(h-1) + (w-1)*h; i++) { int x, y, dx, dy, v; if (i < w*(h-1)) { /* Horizontal edge. */ y = i / w; x = i % w; dx = 0; dy = 1; } else { /* Vertical edge. */ x = (i - w*(h-1)) / h; y = (i - w*(h-1)) % h; dx = 1; dy = 0; } if (retlen + 10 >= retsize) { retsize = retlen + 256; ret = sresize(ret, retsize, char); } v = (map[y*w+x] != map[(y+dy)*w+(x+dx)]); if (pv != v) { ret[retlen++] = 'a'-1 + run; run = 1; pv = v; } else { /* * 'z' is a special case in this encoding. Rather * than meaning a run of 26 and a state switch, it * means a run of 25 and _no_ state switch, because * otherwise there'd be no way to encode runs of * more than 26. */ if (run == 25) { ret[retlen++] = 'z'; run = 0; } run++; } } ret[retlen++] = 'a'-1 + run; ret[retlen++] = ','; run = 0; for (i = 0; i < n; i++) { if (retlen + 10 >= retsize) { retsize = retlen + 256; ret = sresize(ret, retsize, char); } if (colouring[i] < 0) { /* * In _this_ encoding, 'z' is a run of 26, since * there's no implicit state switch after each run. * Confusingly different, but more compact. */ if (run == 26) { ret[retlen++] = 'z'; run = 0; } run++; } else { if (run > 0) ret[retlen++] = 'a'-1 + run; ret[retlen++] = '0' + colouring[i]; run = 0; } } if (run > 0) ret[retlen++] = 'a'-1 + run; ret[retlen] = '\0'; assert(retlen < retsize); } free_scratch(sc); sfree(regions); sfree(colouring2); sfree(colouring); sfree(graph); sfree(map); return ret; } static char *parse_edge_list(const game_params *params, const char **desc, int *map) { int w = params->w, h = params->h, wh = w*h, n = params->n; int i, k, pos, state; const char *p = *desc; dsf_init(map+wh, wh); pos = -1; state = 0; /* * Parse the game description to get the list of edges, and * build up a disjoint set forest as we go (by identifying * pairs of squares whenever the edge list shows a non-edge). */ while (*p && *p != ',') { if (*p < 'a' || *p > 'z') return "Unexpected character in edge list"; if (*p == 'z') k = 25; else k = *p - 'a' + 1; while (k-- > 0) { int x, y, dx, dy; if (pos < 0) { pos++; continue; } else if (pos < w*(h-1)) { /* Horizontal edge. */ y = pos / w; x = pos % w; dx = 0; dy = 1; } else if (pos < 2*wh-w-h) { /* Vertical edge. */ x = (pos - w*(h-1)) / h; y = (pos - w*(h-1)) % h; dx = 1; dy = 0; } else return "Too much data in edge list"; if (!state) dsf_merge(map+wh, y*w+x, (y+dy)*w+(x+dx)); pos++; } if (*p != 'z') state = !state; p++; } assert(pos <= 2*wh-w-h); if (pos < 2*wh-w-h) return "Too little data in edge list"; /* * Now go through again and allocate region numbers. */ pos = 0; for (i = 0; i < wh; i++) map[i] = -1; for (i = 0; i < wh; i++) { k = dsf_canonify(map+wh, i); if (map[k] < 0) map[k] = pos++; map[i] = map[k]; } if (pos != n) return "Edge list defines the wrong number of regions"; *desc = p; return NULL; } static char *validate_desc(const game_params *params, const char *desc) { int w = params->w, h = params->h, wh = w*h, n = params->n; int area; int *map; char *ret; map = snewn(2*wh, int); ret = parse_edge_list(params, &desc, map); sfree(map); if (ret) return ret; if (*desc != ',') return "Expected comma before clue list"; desc++; /* eat comma */ area = 0; while (*desc) { if (*desc >= '0' && *desc < '0'+FOUR) area++; else if (*desc >= 'a' && *desc <= 'z') area += *desc - 'a' + 1; else return "Unexpected character in clue list"; desc++; } if (area < n) return "Too little data in clue list"; else if (area > n) return "Too much data in clue list"; return NULL; } static game_state *new_game(midend *me, const game_params *params, const char *desc) { int w = params->w, h = params->h, wh = w*h, n = params->n; int i, pos; const char *p; game_state *state = snew(game_state); state->p = *params; state->colouring = snewn(n, int); for (i = 0; i < n; i++) state->colouring[i] = -1; state->pencil = snewn(n, int); for (i = 0; i < n; i++) state->pencil[i] = 0; state->completed = state->cheated = FALSE; state->map = snew(struct map); state->map->refcount = 1; state->map->map = snewn(wh*4, int); state->map->graph = snewn(n*n, int); state->map->n = n; state->map->immutable = snewn(n, int); for (i = 0; i < n; i++) state->map->immutable[i] = FALSE; p = desc; { char *ret; ret = parse_edge_list(params, &p, state->map->map); assert(!ret); } /* * Set up the other three quadrants in `map'. */ for (i = wh; i < 4*wh; i++) state->map->map[i] = state->map->map[i % wh]; assert(*p == ','); p++; /* * Now process the clue list. */ pos = 0; while (*p) { if (*p >= '0' && *p < '0'+FOUR) { state->colouring[pos] = *p - '0'; state->map->immutable[pos] = TRUE; pos++; } else { assert(*p >= 'a' && *p <= 'z'); pos += *p - 'a' + 1; } p++; } assert(pos == n); state->map->ngraph = gengraph(w, h, n, state->map->map, state->map->graph); /* * Attempt to smooth out some of the more jagged region * outlines by the judicious use of diagonally divided squares. */ { random_state *rs = random_new(desc, strlen(desc)); int *squares = snewn(wh, int); int done_something; for (i = 0; i < wh; i++) squares[i] = i; shuffle(squares, wh, sizeof(*squares), rs); do { done_something = FALSE; for (i = 0; i < wh; i++) { int y = squares[i] / w, x = squares[i] % w; int c = state->map->map[y*w+x]; int tc, bc, lc, rc; if (x == 0 || x == w-1 || y == 0 || y == h-1) continue; if (state->map->map[TE * wh + y*w+x] != state->map->map[BE * wh + y*w+x]) continue; tc = state->map->map[BE * wh + (y-1)*w+x]; bc = state->map->map[TE * wh + (y+1)*w+x]; lc = state->map->map[RE * wh + y*w+(x-1)]; rc = state->map->map[LE * wh + y*w+(x+1)]; /* * If this square is adjacent on two sides to one * region and on the other two sides to the other * region, and is itself one of the two regions, we can * adjust it so that it's a diagonal. */ if (tc != bc && (tc == c || bc == c)) { if ((lc == tc && rc == bc) || (lc == bc && rc == tc)) { state->map->map[TE * wh + y*w+x] = tc; state->map->map[BE * wh + y*w+x] = bc; state->map->map[LE * wh + y*w+x] = lc; state->map->map[RE * wh + y*w+x] = rc; done_something = TRUE; } } } } while (done_something); sfree(squares); random_free(rs); } /* * Analyse the map to find a canonical line segment * corresponding to each edge, and a canonical point * corresponding to each region. The former are where we'll * eventually put error markers; the latter are where we'll put * per-region flags such as numbers (when in diagnostic mode). */ { int *bestx, *besty, *an, pass; float *ax, *ay, *best; ax = snewn(state->map->ngraph + n, float); ay = snewn(state->map->ngraph + n, float); an = snewn(state->map->ngraph + n, int); bestx = snewn(state->map->ngraph + n, int); besty = snewn(state->map->ngraph + n, int); best = snewn(state->map->ngraph + n, float); for (i = 0; i < state->map->ngraph + n; i++) { bestx[i] = besty[i] = -1; best[i] = (float)(2*(w+h)+1); ax[i] = ay[i] = 0.0F; an[i] = 0; } /* * We make two passes over the map, finding all the line * segments separating regions and all the suitable points * within regions. In the first pass, we compute the * _average_ x and y coordinate of all the points in a * given class; in the second pass, for each such average * point, we find the candidate closest to it and call that * canonical. * * Line segments are considered to have coordinates in * their centre. Thus, at least one coordinate for any line * segment is always something-and-a-half; so we store our * coordinates as twice their normal value. */ for (pass = 0; pass < 2; pass++) { int x, y; for (y = 0; y < h; y++) for (x = 0; x < w; x++) { int ex[4], ey[4], ea[4], eb[4], en = 0; /* * Look for an edge to the right of this * square, an edge below it, and an edge in the * middle of it. Also look to see if the point * at the bottom right of this square is on an * edge (and isn't a place where more than two * regions meet). */ if (x+1 < w) { /* right edge */ ea[en] = state->map->map[RE * wh + y*w+x]; eb[en] = state->map->map[LE * wh + y*w+(x+1)]; ex[en] = (x+1)*2; ey[en] = y*2+1; en++; } if (y+1 < h) { /* bottom edge */ ea[en] = state->map->map[BE * wh + y*w+x]; eb[en] = state->map->map[TE * wh + (y+1)*w+x]; ex[en] = x*2+1; ey[en] = (y+1)*2; en++; } /* diagonal edge */ ea[en] = state->map->map[TE * wh + y*w+x]; eb[en] = state->map->map[BE * wh + y*w+x]; ex[en] = x*2+1; ey[en] = y*2+1; en++; if (x+1 < w && y+1 < h) { /* bottom right corner */ int oct[8], othercol, nchanges; oct[0] = state->map->map[RE * wh + y*w+x]; oct[1] = state->map->map[LE * wh + y*w+(x+1)]; oct[2] = state->map->map[BE * wh + y*w+(x+1)]; oct[3] = state->map->map[TE * wh + (y+1)*w+(x+1)]; oct[4] = state->map->map[LE * wh + (y+1)*w+(x+1)]; oct[5] = state->map->map[RE * wh + (y+1)*w+x]; oct[6] = state->map->map[TE * wh + (y+1)*w+x]; oct[7] = state->map->map[BE * wh + y*w+x]; othercol = -1; nchanges = 0; for (i = 0; i < 8; i++) { if (oct[i] != oct[0]) { if (othercol < 0) othercol = oct[i]; else if (othercol != oct[i]) break; /* three colours at this point */ } if (oct[i] != oct[(i+1) & 7]) nchanges++; } /* * Now if there are exactly two regions at * this point (not one, and not three or * more), and only two changes around the * loop, then this is a valid place to put * an error marker. */ if (i == 8 && othercol >= 0 && nchanges == 2) { ea[en] = oct[0]; eb[en] = othercol; ex[en] = (x+1)*2; ey[en] = (y+1)*2; en++; } /* * If there's exactly _one_ region at this * point, on the other hand, it's a valid * place to put a region centre. */ if (othercol < 0) { ea[en] = eb[en] = oct[0]; ex[en] = (x+1)*2; ey[en] = (y+1)*2; en++; } } /* * Now process the points we've found, one by * one. */ for (i = 0; i < en; i++) { int emin = min(ea[i], eb[i]); int emax = max(ea[i], eb[i]); int gindex; if (emin != emax) { /* Graph edge */ gindex = graph_edge_index(state->map->graph, n, state->map->ngraph, emin, emax); } else { /* Region number */ gindex = state->map->ngraph + emin; } assert(gindex >= 0); if (pass == 0) { /* * In pass 0, accumulate the values * we'll use to compute the average * positions. */ ax[gindex] += ex[i]; ay[gindex] += ey[i]; an[gindex] += 1; } else { /* * In pass 1, work out whether this * point is closer to the average than * the last one we've seen. */ float dx, dy, d; assert(an[gindex] > 0); dx = ex[i] - ax[gindex]; dy = ey[i] - ay[gindex]; d = (float)sqrt(dx*dx + dy*dy); if (d < best[gindex]) { best[gindex] = d; bestx[gindex] = ex[i]; besty[gindex] = ey[i]; } } } } if (pass == 0) { for (i = 0; i < state->map->ngraph + n; i++) if (an[i] > 0) { ax[i] /= an[i]; ay[i] /= an[i]; } } } state->map->edgex = snewn(state->map->ngraph, int); state->map->edgey = snewn(state->map->ngraph, int); memcpy(state->map->edgex, bestx, state->map->ngraph * sizeof(int)); memcpy(state->map->edgey, besty, state->map->ngraph * sizeof(int)); state->map->regionx = snewn(n, int); state->map->regiony = snewn(n, int); memcpy(state->map->regionx, bestx + state->map->ngraph, n*sizeof(int)); memcpy(state->map->regiony, besty + state->map->ngraph, n*sizeof(int)); for (i = 0; i < state->map->ngraph; i++) if (state->map->edgex[i] < 0) { /* Find the other representation of this edge. */ int e = state->map->graph[i]; int iprime = graph_edge_index(state->map->graph, n, state->map->ngraph, e%n, e/n); assert(state->map->edgex[iprime] >= 0); state->map->edgex[i] = state->map->edgex[iprime]; state->map->edgey[i] = state->map->edgey[iprime]; } sfree(ax); sfree(ay); sfree(an); sfree(best); sfree(bestx); sfree(besty); } return state; } static game_state *dup_game(const game_state *state) { game_state *ret = snew(game_state); ret->p = state->p; ret->colouring = snewn(state->p.n, int); memcpy(ret->colouring, state->colouring, state->p.n * sizeof(int)); ret->pencil = snewn(state->p.n, int); memcpy(ret->pencil, state->pencil, state->p.n * sizeof(int)); ret->map = state->map; ret->map->refcount++; ret->completed = state->completed; ret->cheated = state->cheated; return ret; } static void free_game(game_state *state) { if (--state->map->refcount <= 0) { sfree(state->map->map); sfree(state->map->graph); sfree(state->map->immutable); sfree(state->map->edgex); sfree(state->map->edgey); sfree(state->map->regionx); sfree(state->map->regiony); sfree(state->map); } sfree(state->pencil); sfree(state->colouring); sfree(state); } static char *solve_game(const game_state *state, const game_state *currstate, const char *aux, char **error) { if (!aux) { /* * Use the solver. */ int *colouring; struct solver_scratch *sc; int sret; int i; char *ret, buf[80]; int retlen, retsize; colouring = snewn(state->map->n, int); memcpy(colouring, state->colouring, state->map->n * sizeof(int)); sc = new_scratch(state->map->graph, state->map->n, state->map->ngraph); sret = map_solver(sc, state->map->graph, state->map->n, state->map->ngraph, colouring, DIFFCOUNT-1); free_scratch(sc); if (sret != 1) { sfree(colouring); if (sret == 0) *error = "Puzzle is inconsistent"; else *error = "Unable to find a unique solution for this puzzle"; return NULL; } retsize = 64; ret = snewn(retsize, char); strcpy(ret, "S"); retlen = 1; for (i = 0; i < state->map->n; i++) { int len; assert(colouring[i] >= 0); if (colouring[i] == currstate->colouring[i]) continue; assert(!state->map->immutable[i]); len = sprintf(buf, ";%d:%d", colouring[i], i); if (retlen + len >= retsize) { retsize = retlen + len + 256; ret = sresize(ret, retsize, char); } strcpy(ret + retlen, buf); retlen += len; } sfree(colouring); return ret; } return dupstr(aux); } static int game_can_format_as_text_now(const game_params *params) { return TRUE; } static char *game_text_format(const game_state *state) { return NULL; } struct game_ui { /* * drag_colour: * * - -2 means no drag currently active. * - >=0 means we're dragging a solid colour. * - -1 means we're dragging a blank space, and drag_pencil * might or might not add some pencil-mark stipples to that. */ int drag_colour; int drag_pencil; int dragx, dragy; int show_numbers; int cur_x, cur_y, cur_visible, cur_moved, cur_lastmove; }; static game_ui *new_ui(const game_state *state) { game_ui *ui = snew(game_ui); ui->dragx = ui->dragy = -1; ui->drag_colour = -2; ui->drag_pencil = 0; ui->show_numbers = FALSE; ui->cur_x = ui->cur_y = ui->cur_visible = ui->cur_moved = 0; ui->cur_lastmove = 0; return ui; } static void free_ui(game_ui *ui) { sfree(ui); } static char *encode_ui(const game_ui *ui) { return NULL; } static void decode_ui(game_ui *ui, const char *encoding) { } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { } struct game_drawstate { int tilesize; unsigned long *drawn, *todraw; int started; int dragx, dragy, drag_visible; blitter *bl; }; /* Flags in `drawn'. */ #define ERR_BASE 0x00800000L #define ERR_MASK 0xFF800000L #define PENCIL_T_BASE 0x00080000L #define PENCIL_T_MASK 0x00780000L #define PENCIL_B_BASE 0x00008000L #define PENCIL_B_MASK 0x00078000L #define PENCIL_MASK 0x007F8000L #define SHOW_NUMBERS 0x00004000L #define TILESIZE (ds->tilesize) #define BORDER (TILESIZE) #define COORD(x) ( (x) * TILESIZE + BORDER ) #define FROMCOORD(x) ( ((x) - BORDER + TILESIZE) / TILESIZE - 1 ) /* * EPSILON_FOO are epsilons added to absolute cursor position by * cursor movement, such that in pathological cases (e.g. a very * small diamond-shaped area) it's relatively easy to select the * region you wanted. */ #define EPSILON_X(button) (((button) == CURSOR_RIGHT) ? +1 : \ ((button) == CURSOR_LEFT) ? -1 : 0) #define EPSILON_Y(button) (((button) == CURSOR_DOWN) ? +1 : \ ((button) == CURSOR_UP) ? -1 : 0) static int region_from_coords(const game_state *state, const game_drawstate *ds, int x, int y) { int w = state->p.w, h = state->p.h, wh = w*h /*, n = state->p.n */; int tx = FROMCOORD(x), ty = FROMCOORD(y); int dx = x - COORD(tx), dy = y - COORD(ty); int quadrant; if (tx < 0 || tx >= w || ty < 0 || ty >= h) return -1; /* border */ quadrant = 2 * (dx > dy) + (TILESIZE - dx > dy); quadrant = (quadrant == 0 ? BE : quadrant == 1 ? LE : quadrant == 2 ? RE : TE); return state->map->map[quadrant * wh + ty*w+tx]; } static char *interpret_move(const game_state *state, game_ui *ui, const game_drawstate *ds, int x, int y, int button) { char *bufp, buf[256]; int alt_button; /* * Enable or disable numeric labels on regions. */ if (button == 'l' || button == 'L') { ui->show_numbers = !ui->show_numbers; return ""; } if (IS_CURSOR_MOVE(button)) { move_cursor(button, &ui->cur_x, &ui->cur_y, state->p.w, state->p.h, 0); ui->cur_visible = 1; ui->cur_moved = 1; ui->cur_lastmove = button; ui->dragx = COORD(ui->cur_x) + TILESIZE/2 + EPSILON_X(button); ui->dragy = COORD(ui->cur_y) + TILESIZE/2 + EPSILON_Y(button); return ""; } if (IS_CURSOR_SELECT(button)) { if (!ui->cur_visible) { ui->dragx = COORD(ui->cur_x) + TILESIZE/2 + EPSILON_X(ui->cur_lastmove); ui->dragy = COORD(ui->cur_y) + TILESIZE/2 + EPSILON_Y(ui->cur_lastmove); ui->cur_visible = 1; return ""; } if (ui->drag_colour == -2) { /* not currently cursor-dragging, start. */ int r = region_from_coords(state, ds, ui->dragx, ui->dragy); if (r >= 0) { ui->drag_colour = state->colouring[r]; ui->drag_pencil = (ui->drag_colour >= 0) ? 0 : state->pencil[r]; } else { ui->drag_colour = -1; ui->drag_pencil = 0; } ui->cur_moved = 0; return ""; } else { /* currently cursor-dragging; drop the colour in the new region. */ x = COORD(ui->cur_x) + TILESIZE/2 + EPSILON_X(ui->cur_lastmove); y = COORD(ui->cur_y) + TILESIZE/2 + EPSILON_Y(ui->cur_lastmove); alt_button = (button == CURSOR_SELECT2) ? 1 : 0; /* Double-select removes current colour. */ if (!ui->cur_moved) ui->drag_colour = -1; goto drag_dropped; } } if (button == LEFT_BUTTON || button == RIGHT_BUTTON) { int r = region_from_coords(state, ds, x, y); if (r >= 0) { ui->drag_colour = state->colouring[r]; ui->drag_pencil = state->pencil[r]; if (ui->drag_colour >= 0) ui->drag_pencil = 0; /* should be already, but double-check */ } else { ui->drag_colour = -1; ui->drag_pencil = 0; } ui->dragx = x; ui->dragy = y; ui->cur_visible = 0; return ""; } if ((button == LEFT_DRAG || button == RIGHT_DRAG) && ui->drag_colour > -2) { ui->dragx = x; ui->dragy = y; return ""; } if ((button == LEFT_RELEASE || button == RIGHT_RELEASE) && ui->drag_colour > -2) { alt_button = (button == RIGHT_RELEASE) ? 1 : 0; goto drag_dropped; } return NULL; drag_dropped: { int r = region_from_coords(state, ds, x, y); int c = ui->drag_colour; int p = ui->drag_pencil; int oldp; /* * Cancel the drag, whatever happens. */ ui->drag_colour = -2; if (r < 0) return ""; /* drag into border; do nothing else */ if (state->map->immutable[r]) return ""; /* can't change this region */ if (state->colouring[r] == c && state->pencil[r] == p) return ""; /* don't _need_ to change this region */ if (alt_button) { if (state->colouring[r] >= 0) { /* Can't pencil on a coloured region */ return ""; } else if (c >= 0) { /* Right-dragging from colour to blank toggles one pencil */ p = state->pencil[r] ^ (1 << c); c = -1; } /* Otherwise, right-dragging from blank to blank is equivalent * to left-dragging. */ } bufp = buf; oldp = state->pencil[r]; if (c != state->colouring[r]) { bufp += sprintf(bufp, ";%c:%d", (int)(c < 0 ? 'C' : '0' + c), r); if (c >= 0) oldp = 0; } if (p != oldp) { int i; for (i = 0; i < FOUR; i++) if ((oldp ^ p) & (1 << i)) bufp += sprintf(bufp, ";p%c:%d", (int)('0' + i), r); } return dupstr(buf+1); /* ignore first semicolon */ } } static game_state *execute_move(const game_state *state, const char *move) { int n = state->p.n; game_state *ret = dup_game(state); int c, k, adv, i; while (*move) { int pencil = FALSE; c = *move; if (c == 'p') { pencil = TRUE; c = *++move; } if ((c == 'C' || (c >= '0' && c < '0'+FOUR)) && sscanf(move+1, ":%d%n", &k, &adv) == 1 && k >= 0 && k < state->p.n) { move += 1 + adv; if (pencil) { if (ret->colouring[k] >= 0) { free_game(ret); return NULL; } if (c == 'C') ret->pencil[k] = 0; else ret->pencil[k] ^= 1 << (c - '0'); } else { ret->colouring[k] = (c == 'C' ? -1 : c - '0'); ret->pencil[k] = 0; } } else if (*move == 'S') { move++; ret->cheated = TRUE; } else { free_game(ret); return NULL; } if (*move && *move != ';') { free_game(ret); return NULL; } if (*move) move++; } /* * Check for completion. */ if (!ret->completed) { int ok = TRUE; for (i = 0; i < n; i++) if (ret->colouring[i] < 0) { ok = FALSE; break; } if (ok) { for (i = 0; i < ret->map->ngraph; i++) { int j = ret->map->graph[i] / n; int k = ret->map->graph[i] % n; if (ret->colouring[j] == ret->colouring[k]) { ok = FALSE; break; } } } if (ok) ret->completed = TRUE; } return ret; } /* ---------------------------------------------------------------------- * Drawing routines. */ static void game_compute_size(const game_params *params, int tilesize, int *x, int *y) { /* Ick: fake up `ds->tilesize' for macro expansion purposes */ struct { int tilesize; } ads, *ds = &ads; ads.tilesize = tilesize; *x = params->w * TILESIZE + 2 * BORDER + 1; *y = params->h * TILESIZE + 2 * BORDER + 1; } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { ds->tilesize = tilesize; assert(!ds->bl); /* set_size is never called twice */ ds->bl = blitter_new(dr, TILESIZE+3, TILESIZE+3); } const float map_colours[FOUR][3] = { #ifdef VIVID_COLOURS /* Use more vivid colours (e.g. on the Pocket PC) */ {0.75F, 0.25F, 0.25F}, {0.3F, 0.7F, 0.3F}, {0.3F, 0.3F, 0.7F}, {0.85F, 0.85F, 0.1F}, #else {0.7F, 0.5F, 0.4F}, {0.8F, 0.7F, 0.4F}, {0.5F, 0.6F, 0.4F}, {0.55F, 0.45F, 0.35F}, #endif }; const int map_hatching[FOUR] = { HATCH_VERT, HATCH_SLASH, HATCH_HORIZ, HATCH_BACKSLASH }; static float *game_colours(frontend *fe, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float); frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]); ret[COL_GRID * 3 + 0] = 0.0F; ret[COL_GRID * 3 + 1] = 0.0F; ret[COL_GRID * 3 + 2] = 0.0F; memcpy(ret + COL_0 * 3, map_colours[0], 3 * sizeof(float)); memcpy(ret + COL_1 * 3, map_colours[1], 3 * sizeof(float)); memcpy(ret + COL_2 * 3, map_colours[2], 3 * sizeof(float)); memcpy(ret + COL_3 * 3, map_colours[3], 3 * sizeof(float)); ret[COL_ERROR * 3 + 0] = 1.0F; ret[COL_ERROR * 3 + 1] = 0.0F; ret[COL_ERROR * 3 + 2] = 0.0F; ret[COL_ERRTEXT * 3 + 0] = 1.0F; ret[COL_ERRTEXT * 3 + 1] = 1.0F; ret[COL_ERRTEXT * 3 + 2] = 1.0F; *ncolours = NCOLOURS; return ret; } static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { struct game_drawstate *ds = snew(struct game_drawstate); int i; ds->tilesize = 0; ds->drawn = snewn(state->p.w * state->p.h, unsigned long); for (i = 0; i < state->p.w * state->p.h; i++) ds->drawn[i] = 0xFFFFL; ds->todraw = snewn(state->p.w * state->p.h, unsigned long); ds->started = FALSE; ds->bl = NULL; ds->drag_visible = FALSE; ds->dragx = ds->dragy = -1; return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { sfree(ds->drawn); sfree(ds->todraw); if (ds->bl) blitter_free(dr, ds->bl); sfree(ds); } static void draw_error(drawing *dr, game_drawstate *ds, int x, int y) { int coords[8]; int yext, xext; /* * Draw a diamond. */ coords[0] = x - TILESIZE*2/5; coords[1] = y; coords[2] = x; coords[3] = y - TILESIZE*2/5; coords[4] = x + TILESIZE*2/5; coords[5] = y; coords[6] = x; coords[7] = y + TILESIZE*2/5; draw_polygon(dr, coords, 4, COL_ERROR, COL_GRID); /* * Draw an exclamation mark in the diamond. This turns out to * look unpleasantly off-centre if done via draw_text, so I do * it by hand on the basis that exclamation marks aren't that * difficult to draw... */ xext = TILESIZE/16; yext = TILESIZE*2/5 - (xext*2+2); draw_rect(dr, x-xext, y-yext, xext*2+1, yext*2+1 - (xext*3), COL_ERRTEXT); draw_rect(dr, x-xext, y+yext-xext*2+1, xext*2+1, xext*2, COL_ERRTEXT); } static void draw_square(drawing *dr, game_drawstate *ds, const game_params *params, struct map *map, int x, int y, unsigned long v) { int w = params->w, h = params->h, wh = w*h; int tv, bv, xo, yo, i, j, oldj; unsigned long errs, pencil, show_numbers; errs = v & ERR_MASK; v &= ~ERR_MASK; pencil = v & PENCIL_MASK; v &= ~PENCIL_MASK; show_numbers = v & SHOW_NUMBERS; v &= ~SHOW_NUMBERS; tv = v / FIVE; bv = v % FIVE; clip(dr, COORD(x), COORD(y), TILESIZE, TILESIZE); /* * Draw the region colour. */ draw_rect(dr, COORD(x), COORD(y), TILESIZE, TILESIZE, (tv == FOUR ? COL_BACKGROUND : COL_0 + tv)); /* * Draw the second region colour, if this is a diagonally * divided square. */ if (map->map[TE * wh + y*w+x] != map->map[BE * wh + y*w+x]) { int coords[6]; coords[0] = COORD(x)-1; coords[1] = COORD(y+1)+1; if (map->map[LE * wh + y*w+x] == map->map[TE * wh + y*w+x]) coords[2] = COORD(x+1)+1; else coords[2] = COORD(x)-1; coords[3] = COORD(y)-1; coords[4] = COORD(x+1)+1; coords[5] = COORD(y+1)+1; draw_polygon(dr, coords, 3, (bv == FOUR ? COL_BACKGROUND : COL_0 + bv), COL_GRID); } /* * Draw `pencil marks'. Currently we arrange these in a square * formation, which means we may be in trouble if the value of * FOUR changes later... */ assert(FOUR == 4); for (yo = 0; yo < 4; yo++) for (xo = 0; xo < 4; xo++) { int te = map->map[TE * wh + y*w+x]; int e, ee, c; e = (yo < xo && yo < 3-xo ? TE : yo > xo && yo > 3-xo ? BE : xo < 2 ? LE : RE); ee = map->map[e * wh + y*w+x]; if (xo != (yo * 2 + 1) % 5) continue; c = yo; if (!(pencil & ((ee == te ? PENCIL_T_BASE : PENCIL_B_BASE) << c))) continue; if (yo == xo && (map->map[TE * wh + y*w+x] != map->map[LE * wh + y*w+x])) continue; /* avoid TL-BR diagonal line */ if (yo == 3-xo && (map->map[TE * wh + y*w+x] != map->map[RE * wh + y*w+x])) continue; /* avoid BL-TR diagonal line */ draw_circle(dr, COORD(x) + (xo+1)*TILESIZE/5, COORD(y) + (yo+1)*TILESIZE/5, TILESIZE/7, COL_0 + c, COL_0 + c); } /* * Draw the grid lines, if required. */ if (x <= 0 || map->map[RE*wh+y*w+(x-1)] != map->map[LE*wh+y*w+x]) draw_rect(dr, COORD(x), COORD(y), 1, TILESIZE, COL_GRID); if (y <= 0 || map->map[BE*wh+(y-1)*w+x] != map->map[TE*wh+y*w+x]) draw_rect(dr, COORD(x), COORD(y), TILESIZE, 1, COL_GRID); if (x <= 0 || y <= 0 || map->map[RE*wh+(y-1)*w+(x-1)] != map->map[TE*wh+y*w+x] || map->map[BE*wh+(y-1)*w+(x-1)] != map->map[LE*wh+y*w+x]) draw_rect(dr, COORD(x), COORD(y), 1, 1, COL_GRID); /* * Draw error markers. */ for (yo = 0; yo < 3; yo++) for (xo = 0; xo < 3; xo++) if (errs & (ERR_BASE << (yo*3+xo))) draw_error(dr, ds, (COORD(x)*2+TILESIZE*xo)/2, (COORD(y)*2+TILESIZE*yo)/2); /* * Draw region numbers, if desired. */ if (show_numbers) { oldj = -1; for (i = 0; i < 2; i++) { j = map->map[(i?BE:TE)*wh+y*w+x]; if (oldj == j) continue; oldj = j; xo = map->regionx[j] - 2*x; yo = map->regiony[j] - 2*y; if (xo >= 0 && xo <= 2 && yo >= 0 && yo <= 2) { char buf[80]; sprintf(buf, "%d", j); draw_text(dr, (COORD(x)*2+TILESIZE*xo)/2, (COORD(y)*2+TILESIZE*yo)/2, FONT_VARIABLE, 3*TILESIZE/5, ALIGN_HCENTRE|ALIGN_VCENTRE, COL_GRID, buf); } } } unclip(dr); draw_update(dr, COORD(x), COORD(y), TILESIZE, TILESIZE); } static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float animtime, float flashtime) { int w = state->p.w, h = state->p.h, wh = w*h, n = state->p.n; int x, y, i; int flash; if (ds->drag_visible) { blitter_load(dr, ds->bl, ds->dragx, ds->dragy); draw_update(dr, ds->dragx, ds->dragy, TILESIZE + 3, TILESIZE + 3); ds->drag_visible = FALSE; } /* * The initial contents of the window are not guaranteed and * can vary with front ends. To be on the safe side, all games * should start by drawing a big background-colour rectangle * covering the whole window. */ if (!ds->started) { int ww, wh; game_compute_size(&state->p, TILESIZE, &ww, &wh); draw_rect(dr, 0, 0, ww, wh, COL_BACKGROUND); draw_rect(dr, COORD(0), COORD(0), w*TILESIZE+1, h*TILESIZE+1, COL_GRID); draw_update(dr, 0, 0, ww, wh); ds->started = TRUE; } if (flashtime) { if (flash_type == 1) flash = (int)(flashtime * FOUR / flash_length); else flash = 1 + (int)(flashtime * THREE / flash_length); } else flash = -1; /* * Set up the `todraw' array. */ for (y = 0; y < h; y++) for (x = 0; x < w; x++) { int tv = state->colouring[state->map->map[TE * wh + y*w+x]]; int bv = state->colouring[state->map->map[BE * wh + y*w+x]]; unsigned long v; if (tv < 0) tv = FOUR; if (bv < 0) bv = FOUR; if (flash >= 0) { if (flash_type == 1) { if (tv == flash) tv = FOUR; if (bv == flash) bv = FOUR; } else if (flash_type == 2) { if (flash % 2) tv = bv = FOUR; } else { if (tv != FOUR) tv = (tv + flash) % FOUR; if (bv != FOUR) bv = (bv + flash) % FOUR; } } v = tv * FIVE + bv; /* * Add pencil marks. */ for (i = 0; i < FOUR; i++) { if (state->colouring[state->map->map[TE * wh + y*w+x]] < 0 && (state->pencil[state->map->map[TE * wh + y*w+x]] & (1<colouring[state->map->map[BE * wh + y*w+x]] < 0 && (state->pencil[state->map->map[BE * wh + y*w+x]] & (1<show_numbers) v |= SHOW_NUMBERS; ds->todraw[y*w+x] = v; } /* * Add error markers to the `todraw' array. */ for (i = 0; i < state->map->ngraph; i++) { int v1 = state->map->graph[i] / n; int v2 = state->map->graph[i] % n; int xo, yo; if (state->colouring[v1] < 0 || state->colouring[v2] < 0) continue; if (state->colouring[v1] != state->colouring[v2]) continue; x = state->map->edgex[i]; y = state->map->edgey[i]; xo = x % 2; x /= 2; yo = y % 2; y /= 2; ds->todraw[y*w+x] |= ERR_BASE << (yo*3+xo); if (xo == 0) { assert(x > 0); ds->todraw[y*w+(x-1)] |= ERR_BASE << (yo*3+2); } if (yo == 0) { assert(y > 0); ds->todraw[(y-1)*w+x] |= ERR_BASE << (2*3+xo); } if (xo == 0 && yo == 0) { assert(x > 0 && y > 0); ds->todraw[(y-1)*w+(x-1)] |= ERR_BASE << (2*3+2); } } /* * Now actually draw everything. */ for (y = 0; y < h; y++) for (x = 0; x < w; x++) { unsigned long v = ds->todraw[y*w+x]; if (ds->drawn[y*w+x] != v) { draw_square(dr, ds, &state->p, state->map, x, y, v); ds->drawn[y*w+x] = v; } } /* * Draw the dragged colour blob if any. */ if ((ui->drag_colour > -2) || ui->cur_visible) { int bg, iscur = 0; if (ui->drag_colour >= 0) bg = COL_0 + ui->drag_colour; else if (ui->drag_colour == -1) { bg = COL_BACKGROUND; } else { int r = region_from_coords(state, ds, ui->dragx, ui->dragy); int c = (r < 0) ? -1 : state->colouring[r]; assert(ui->cur_visible); /*bg = COL_GRID;*/ bg = (c < 0) ? COL_BACKGROUND : COL_0 + c; iscur = 1; } ds->dragx = ui->dragx - TILESIZE/2 - 2; ds->dragy = ui->dragy - TILESIZE/2 - 2; blitter_save(dr, ds->bl, ds->dragx, ds->dragy); draw_circle(dr, ui->dragx, ui->dragy, iscur ? TILESIZE/4 : TILESIZE/2, bg, COL_GRID); for (i = 0; i < FOUR; i++) if (ui->drag_pencil & (1 << i)) draw_circle(dr, ui->dragx + ((i*4+2)%10-3) * TILESIZE/10, ui->dragy + (i*2-3) * TILESIZE/10, TILESIZE/8, COL_0 + i, COL_0 + i); draw_update(dr, ds->dragx, ds->dragy, TILESIZE + 3, TILESIZE + 3); ds->drag_visible = TRUE; } } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return 0.0F; } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { if (!oldstate->completed && newstate->completed && !oldstate->cheated && !newstate->cheated) { if (flash_type < 0) { char *env = getenv("MAP_ALTERNATIVE_FLASH"); if (env) flash_type = atoi(env); else flash_type = 0; flash_length = (flash_type == 1 ? 0.50F : 0.30F); } return flash_length; } else return 0.0F; } static int game_status(const game_state *state) { return state->completed ? +1 : 0; } static int game_timing_state(const game_state *state, game_ui *ui) { return TRUE; } static void game_print_size(const game_params *params, float *x, float *y) { int pw, ph; /* * I'll use 4mm squares by default, I think. Simplest way to * compute this size is to compute the pixel puzzle size at a * given tile size and then scale. */ game_compute_size(params, 400, &pw, &ph); *x = pw / 100.0F; *y = ph / 100.0F; } static void game_print(drawing *dr, const game_state *state, int tilesize) { int w = state->p.w, h = state->p.h, wh = w*h, n = state->p.n; int ink, c[FOUR], i; int x, y, r; int *coords, ncoords, coordsize; /* Ick: fake up `ds->tilesize' for macro expansion purposes */ struct { int tilesize; } ads, *ds = &ads; /* We can't call game_set_size() here because we don't want a blitter */ ads.tilesize = tilesize; ink = print_mono_colour(dr, 0); for (i = 0; i < FOUR; i++) c[i] = print_rgb_hatched_colour(dr, map_colours[i][0], map_colours[i][1], map_colours[i][2], map_hatching[i]); coordsize = 0; coords = NULL; print_line_width(dr, TILESIZE / 16); /* * Draw a single filled polygon around each region. */ for (r = 0; r < n; r++) { int octants[8], lastdir, d1, d2, ox, oy; /* * Start by finding a point on the region boundary. Any * point will do. To do this, we'll search for a square * containing the region and then decide which corner of it * to use. */ x = w; for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { if (state->map->map[wh*0+y*w+x] == r || state->map->map[wh*1+y*w+x] == r || state->map->map[wh*2+y*w+x] == r || state->map->map[wh*3+y*w+x] == r) break; } if (x < w) break; } assert(y < h && x < w); /* we must have found one somewhere */ /* * This is the first square in lexicographic order which * contains part of this region. Therefore, one of the top * two corners of the square must be what we're after. The * only case in which it isn't the top left one is if the * square is diagonally divided and the region is in the * bottom right half. */ if (state->map->map[wh*TE+y*w+x] != r && state->map->map[wh*LE+y*w+x] != r) x++; /* could just as well have done y++ */ /* * Now we have a point on the region boundary. Trace around * the region until we come back to this point, * accumulating coordinates for a polygon draw operation as * we go. */ lastdir = -1; ox = x; oy = y; ncoords = 0; do { /* * There are eight possible directions we could head in * from here. We identify them by octant numbers, and * we also use octant numbers to identify the spaces * between them: * * 6 7 0 * \ 7|0 / * \ | / * 6 \|/ 1 * 5-----+-----1 * 5 /|\ 2 * / | \ * / 4|3 \ * 4 3 2 */ octants[0] = x0 ? state->map->map[wh*LE+(y-1)*w+x] : -1; octants[1] = x0 ? state->map->map[wh*BE+(y-1)*w+x] : -1; octants[2] = xmap->map[wh*TE+y*w+x] : -1; octants[3] = xmap->map[wh*LE+y*w+x] : -1; octants[4] = x>0 && ymap->map[wh*RE+y*w+(x-1)] : -1; octants[5] = x>0 && ymap->map[wh*TE+y*w+(x-1)] : -1; octants[6] = x>0 && y>0 ? state->map->map[wh*BE+(y-1)*w+(x-1)] :-1; octants[7] = x>0 && y>0 ? state->map->map[wh*RE+(y-1)*w+(x-1)] :-1; d1 = d2 = -1; for (i = 0; i < 8; i++) if ((octants[i] == r) ^ (octants[(i+1)%8] == r)) { assert(d2 == -1); if (d1 == -1) d1 = i; else d2 = i; } assert(d1 != -1 && d2 != -1); if (d1 == lastdir) d1 = d2; /* * Now we're heading in direction d1. Save the current * coordinates. */ if (ncoords + 2 > coordsize) { coordsize += 128; coords = sresize(coords, coordsize, int); } coords[ncoords++] = COORD(x); coords[ncoords++] = COORD(y); /* * Compute the new coordinates. */ x += (d1 % 4 == 3 ? 0 : d1 < 4 ? +1 : -1); y += (d1 % 4 == 1 ? 0 : d1 > 1 && d1 < 5 ? +1 : -1); assert(x >= 0 && x <= w && y >= 0 && y <= h); lastdir = d1 ^ 4; } while (x != ox || y != oy); draw_polygon(dr, coords, ncoords/2, state->colouring[r] >= 0 ? c[state->colouring[r]] : -1, ink); } sfree(coords); } #ifdef COMBINED #define thegame map #endif const struct game thegame = { "Map", "games.map", "map", default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, TRUE, solve_game, FALSE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, 20, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, TRUE, TRUE, game_print_size, game_print, FALSE, /* wants_statusbar */ FALSE, game_timing_state, 0, /* flags */ }; #ifdef STANDALONE_SOLVER int main(int argc, char **argv) { game_params *p; game_state *s; char *id = NULL, *desc, *err; int grade = FALSE; int ret, diff, really_verbose = FALSE; struct solver_scratch *sc; int i; while (--argc > 0) { char *p = *++argv; if (!strcmp(p, "-v")) { really_verbose = TRUE; } else if (!strcmp(p, "-g")) { grade = TRUE; } else if (*p == '-') { fprintf(stderr, "%s: unrecognised option `%s'\n", argv[0], p); return 1; } else { id = p; } } if (!id) { fprintf(stderr, "usage: %s [-g | -v] \n", argv[0]); return 1; } desc = strchr(id, ':'); if (!desc) { fprintf(stderr, "%s: game id expects a colon in it\n", argv[0]); return 1; } *desc++ = '\0'; p = default_params(); decode_params(p, id); err = validate_desc(p, desc); if (err) { fprintf(stderr, "%s: %s\n", argv[0], err); return 1; } s = new_game(NULL, p, desc); sc = new_scratch(s->map->graph, s->map->n, s->map->ngraph); /* * When solving an Easy puzzle, we don't want to bother the * user with Hard-level deductions. For this reason, we grade * the puzzle internally before doing anything else. */ ret = -1; /* placate optimiser */ for (diff = 0; diff < DIFFCOUNT; diff++) { for (i = 0; i < s->map->n; i++) if (!s->map->immutable[i]) s->colouring[i] = -1; ret = map_solver(sc, s->map->graph, s->map->n, s->map->ngraph, s->colouring, diff); if (ret < 2) break; } if (diff == DIFFCOUNT) { if (grade) printf("Difficulty rating: harder than Hard, or ambiguous\n"); else printf("Unable to find a unique solution\n"); } else { if (grade) { if (ret == 0) printf("Difficulty rating: impossible (no solution exists)\n"); else if (ret == 1) printf("Difficulty rating: %s\n", map_diffnames[diff]); } else { verbose = really_verbose; for (i = 0; i < s->map->n; i++) if (!s->map->immutable[i]) s->colouring[i] = -1; ret = map_solver(sc, s->map->graph, s->map->n, s->map->ngraph, s->colouring, diff); if (ret == 0) printf("Puzzle is inconsistent\n"); else { int col = 0; for (i = 0; i < s->map->n; i++) { printf("%5d <- %c%c", i, colnames[s->colouring[i]], (col < 6 && i+1 < s->map->n ? ' ' : '\n')); if (++col == 7) col = 0; } } } } return 0; } #endif /* vim: set shiftwidth=4 tabstop=8: */ puzzles-20170606.272beef/malloc.c0000644000175000017500000000173713115373615015314 0ustar simonsimon/* * malloc.c: safe wrappers around malloc, realloc, free, strdup */ #include #include #include "puzzles.h" /* * smalloc should guarantee to return a useful pointer - Halibut * can do nothing except die when it's out of memory anyway. */ void *smalloc(size_t size) { void *p; p = malloc(size); if (!p) fatal("out of memory"); return p; } /* * sfree should guaranteeably deal gracefully with freeing NULL */ void sfree(void *p) { if (p) { free(p); } } /* * srealloc should guaranteeably be able to realloc NULL */ void *srealloc(void *p, size_t size) { void *q; if (p) { q = realloc(p, size); } else { q = malloc(size); } if (!q) fatal("out of memory"); return q; } /* * dupstr is like strdup, but with the never-return-NULL property * of smalloc (and also reliably defined in all environments :-) */ char *dupstr(const char *s) { char *r = smalloc(1+strlen(s)); strcpy(r,s); return r; } puzzles-20170606.272beef/magnets.c0000644000175000017500000022717013115373615015504 0ustar simonsimon/* * magnets.c: implementation of janko.at 'magnets puzzle' game. * * http://64.233.179.104/translate_c?hl=en&u=http://www.janko.at/Raetsel/Magnete/Beispiel.htm * * Puzzle definition is just the size, and then the list of + (across then * down) and - (across then down) present, then domino edges. * * An example: * * + 2 0 1 * +-----+ * 1|+ -| |1 * |-+-+ | * 0|-|#| |1 * | +-+-| * 2|+|- +|1 * +-----+ * 1 2 0 - * * 3x3:201,102,120,111,LRTT*BBLR * * 'Zotmeister' examples: * 5x5:.2..1,3..1.,.2..2,2..2.,LRLRTTLRTBBT*BTTBLRBBLRLR * 9x9:3.51...33,.2..23.13,..33.33.2,12...5.3.,**TLRTLR*,*TBLRBTLR,TBLRLRBTT,BLRTLRTBB,LRTB*TBLR,LRBLRBLRT,TTTLRLRTB,BBBTLRTB*,*LRBLRB** * * Janko 6x6 with solution: * 6x6:322223,323132,232223,232223,LRTLRTTTBLRBBBTTLRLRBBLRTTLRTTBBLRBB * * janko 8x8: * 8x8:34131323,23131334,43122323,21332243,LRTLRLRT,LRBTTTTB,LRTBBBBT,TTBTLRTB,BBTBTTBT,TTBTBBTB,BBTBLRBT,LRBLRLRB */ #include #include #include #include #include #include #include "puzzles.h" #ifdef STANDALONE_SOLVER int verbose = 0; #endif enum { COL_BACKGROUND, COL_HIGHLIGHT, COL_LOWLIGHT, COL_TEXT, COL_ERROR, COL_CURSOR, COL_DONE, COL_NEUTRAL, COL_NEGATIVE, COL_POSITIVE, COL_NOT, NCOLOURS }; /* Cell states. */ enum { EMPTY = 0, NEUTRAL = EMPTY, POSITIVE = 1, NEGATIVE = 2 }; #if defined DEBUGGING || defined STANDALONE_SOLVER static const char *cellnames[3] = { "neutral", "positive", "negative" }; #define NAME(w) ( ((w) < 0 || (w) > 2) ? "(out of range)" : cellnames[(w)] ) #endif #define GRID2CHAR(g) ( ((g) >= 0 && (g) <= 2) ? ".+-"[(g)] : '?' ) #define CHAR2GRID(c) ( (c) == '+' ? POSITIVE : (c) == '-' ? NEGATIVE : NEUTRAL ) #define INGRID(s,x,y) ((x) >= 0 && (x) < (s)->w && (y) >= 0 && (y) < (s)->h) #define OPPOSITE(x) ( ((x)*2) % 3 ) /* 0 --> 0, 1 --> 2, 2 --> 4 --> 1 */ #define FLASH_TIME 0.7F /* Macro ickery copied from slant.c */ #define DIFFLIST(A) \ A(EASY,Easy,e) \ A(TRICKY,Tricky,t) #define ENUM(upper,title,lower) DIFF_ ## upper, #define TITLE(upper,title,lower) #title, #define ENCODE(upper,title,lower) #lower #define CONFIG(upper,title,lower) ":" #title enum { DIFFLIST(ENUM) DIFFCOUNT }; static char const *const magnets_diffnames[] = { DIFFLIST(TITLE) "(count)" }; static char const magnets_diffchars[] = DIFFLIST(ENCODE); #define DIFFCONFIG DIFFLIST(CONFIG) /* --------------------------------------------------------------- */ /* Game parameter functions. */ struct game_params { int w, h, diff, stripclues; }; #define DEFAULT_PRESET 2 static const struct game_params magnets_presets[] = { {6, 5, DIFF_EASY, 0}, {6, 5, DIFF_TRICKY, 0}, {6, 5, DIFF_TRICKY, 1}, {8, 7, DIFF_EASY, 0}, {8, 7, DIFF_TRICKY, 0}, {8, 7, DIFF_TRICKY, 1}, {10, 9, DIFF_TRICKY, 0}, {10, 9, DIFF_TRICKY, 1} }; static game_params *default_params(void) { game_params *ret = snew(game_params); *ret = magnets_presets[DEFAULT_PRESET]; return ret; } static int game_fetch_preset(int i, char **name, game_params **params) { game_params *ret; char buf[64]; if (i < 0 || i >= lenof(magnets_presets)) return FALSE; ret = default_params(); *ret = magnets_presets[i]; /* struct copy */ *params = ret; sprintf(buf, "%dx%d %s%s", magnets_presets[i].w, magnets_presets[i].h, magnets_diffnames[magnets_presets[i].diff], magnets_presets[i].stripclues ? ", strip clues" : ""); *name = dupstr(buf); return TRUE; } static void free_params(game_params *params) { sfree(params); } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } static void decode_params(game_params *ret, char const *string) { ret->w = ret->h = atoi(string); while (*string && isdigit((unsigned char) *string)) ++string; if (*string == 'x') { string++; ret->h = atoi(string); while (*string && isdigit((unsigned char)*string)) string++; } ret->diff = DIFF_EASY; if (*string == 'd') { int i; string++; for (i = 0; i < DIFFCOUNT; i++) if (*string == magnets_diffchars[i]) ret->diff = i; if (*string) string++; } ret->stripclues = 0; if (*string == 'S') { string++; ret->stripclues = 1; } } static char *encode_params(const game_params *params, int full) { char buf[256]; sprintf(buf, "%dx%d", params->w, params->h); if (full) sprintf(buf + strlen(buf), "d%c%s", magnets_diffchars[params->diff], params->stripclues ? "S" : ""); return dupstr(buf); } static config_item *game_configure(const game_params *params) { config_item *ret; char buf[64]; ret = snewn(5, config_item); ret[0].name = "Width"; ret[0].type = C_STRING; sprintf(buf, "%d", params->w); ret[0].sval = dupstr(buf); ret[0].ival = 0; ret[1].name = "Height"; ret[1].type = C_STRING; sprintf(buf, "%d", params->h); ret[1].sval = dupstr(buf); ret[1].ival = 0; ret[2].name = "Difficulty"; ret[2].type = C_CHOICES; ret[2].sval = DIFFCONFIG; ret[2].ival = params->diff; ret[3].name = "Strip clues"; ret[3].type = C_BOOLEAN; ret[3].sval = NULL; ret[3].ival = params->stripclues; ret[4].name = NULL; ret[4].type = C_END; ret[4].sval = NULL; ret[4].ival = 0; return ret; } static game_params *custom_params(const config_item *cfg) { game_params *ret = snew(game_params); ret->w = atoi(cfg[0].sval); ret->h = atoi(cfg[1].sval); ret->diff = cfg[2].ival; ret->stripclues = cfg[3].ival; return ret; } static char *validate_params(const game_params *params, int full) { if (params->w < 2) return "Width must be at least one"; if (params->h < 2) return "Height must be at least one"; if (params->diff < 0 || params->diff >= DIFFCOUNT) return "Unknown difficulty level"; return NULL; } /* --------------------------------------------------------------- */ /* Game state allocation, deallocation. */ struct game_common { int *dominoes; /* size w*h, dominoes[i] points to other end of domino. */ int *rowcount; /* size 3*h, array of [plus, minus, neutral] counts */ int *colcount; /* size 3*w, ditto */ int refcount; }; #define GS_ERROR 1 #define GS_SET 2 #define GS_NOTPOSITIVE 4 #define GS_NOTNEGATIVE 8 #define GS_NOTNEUTRAL 16 #define GS_MARK 32 #define GS_NOTMASK (GS_NOTPOSITIVE|GS_NOTNEGATIVE|GS_NOTNEUTRAL) #define NOTFLAG(w) ( (w) == NEUTRAL ? GS_NOTNEUTRAL : \ (w) == POSITIVE ? GS_NOTPOSITIVE : \ (w) == NEGATIVE ? GS_NOTNEGATIVE : \ 0 ) #define POSSIBLE(f,w) (!(state->flags[(f)] & NOTFLAG(w))) struct game_state { int w, h, wh; int *grid; /* size w*h, for cell state (pos/neg) */ unsigned int *flags; /* size w*h */ int solved, completed, numbered; unsigned char *counts_done; struct game_common *common; /* domino layout never changes. */ }; static void clear_state(game_state *ret) { int i; ret->solved = ret->completed = ret->numbered = 0; memset(ret->common->rowcount, 0, ret->h*3*sizeof(int)); memset(ret->common->colcount, 0, ret->w*3*sizeof(int)); memset(ret->counts_done, 0, (ret->h + ret->w) * 2 * sizeof(unsigned char)); for (i = 0; i < ret->wh; i++) { ret->grid[i] = EMPTY; ret->flags[i] = 0; ret->common->dominoes[i] = i; } } static game_state *new_state(int w, int h) { game_state *ret = snew(game_state); memset(ret, 0, sizeof(game_state)); ret->w = w; ret->h = h; ret->wh = w*h; ret->grid = snewn(ret->wh, int); ret->flags = snewn(ret->wh, unsigned int); ret->counts_done = snewn((ret->h + ret->w) * 2, unsigned char); ret->common = snew(struct game_common); ret->common->refcount = 1; ret->common->dominoes = snewn(ret->wh, int); ret->common->rowcount = snewn(ret->h*3, int); ret->common->colcount = snewn(ret->w*3, int); clear_state(ret); return ret; } static game_state *dup_game(const game_state *src) { game_state *dest = snew(game_state); dest->w = src->w; dest->h = src->h; dest->wh = src->wh; dest->solved = src->solved; dest->completed = src->completed; dest->numbered = src->numbered; dest->common = src->common; dest->common->refcount++; dest->grid = snewn(dest->wh, int); memcpy(dest->grid, src->grid, dest->wh*sizeof(int)); dest->counts_done = snewn((dest->h + dest->w) * 2, unsigned char); memcpy(dest->counts_done, src->counts_done, (dest->h + dest->w) * 2 * sizeof(unsigned char)); dest->flags = snewn(dest->wh, unsigned int); memcpy(dest->flags, src->flags, dest->wh*sizeof(unsigned int)); return dest; } static void free_game(game_state *state) { state->common->refcount--; if (state->common->refcount == 0) { sfree(state->common->dominoes); sfree(state->common->rowcount); sfree(state->common->colcount); sfree(state->common); } sfree(state->counts_done); sfree(state->flags); sfree(state->grid); sfree(state); } /* --------------------------------------------------------------- */ /* Game generation and reading. */ /* For a game of size w*h the game description is: * w-sized string of column + numbers (L-R), or '.' for none * semicolon * h-sized string of row + numbers (T-B), or '.' * semicolon * w-sized string of column - numbers (L-R), or '.' * semicolon * h-sized string of row - numbers (T-B), or '.' * semicolon * w*h-sized string of 'L', 'R', 'U', 'D' for domino associations, * or '*' for a black singleton square. * * for a total length of 2w + 2h + wh + 4. */ static char n2c(int num) { /* XXX cloned from singles.c */ if (num == -1) return '.'; if (num < 10) return '0' + num; else if (num < 10+26) return 'a' + num - 10; else return 'A' + num - 10 - 26; return '?'; } static int c2n(char c) { /* XXX cloned from singles.c */ if (isdigit((unsigned char)c)) return (int)(c - '0'); else if (c >= 'a' && c <= 'z') return (int)(c - 'a' + 10); else if (c >= 'A' && c <= 'Z') return (int)(c - 'A' + 10 + 26); return -1; } static const char *readrow(const char *desc, int n, int *array, int off, const char **prob) { int i, num; char c; for (i = 0; i < n; i++) { c = *desc++; if (c == 0) goto badchar; if (c == '.') num = -1; else { num = c2n(c); if (num < 0) goto badchar; } array[i*3+off] = num; } c = *desc++; if (c != ',') goto badchar; return desc; badchar: *prob = (c == 0) ? "Game description too short" : "Game description contained unexpected characters"; return NULL; } static game_state *new_game_int(const game_params *params, const char *desc, const char **prob) { game_state *state = new_state(params->w, params->h); int x, y, idx, *count; char c; *prob = NULL; /* top row, left-to-right */ desc = readrow(desc, state->w, state->common->colcount, POSITIVE, prob); if (*prob) goto done; /* left column, top-to-bottom */ desc = readrow(desc, state->h, state->common->rowcount, POSITIVE, prob); if (*prob) goto done; /* bottom row, left-to-right */ desc = readrow(desc, state->w, state->common->colcount, NEGATIVE, prob); if (*prob) goto done; /* right column, top-to-bottom */ desc = readrow(desc, state->h, state->common->rowcount, NEGATIVE, prob); if (*prob) goto done; /* Add neutral counts (== size - pos - neg) to columns and rows. * Any singleton cells will just be treated as permanently neutral. */ count = state->common->colcount; for (x = 0; x < state->w; x++) { if (count[x*3+POSITIVE] < 0 || count[x*3+NEGATIVE] < 0) count[x*3+NEUTRAL] = -1; else { count[x*3+NEUTRAL] = state->h - count[x*3+POSITIVE] - count[x*3+NEGATIVE]; if (count[x*3+NEUTRAL] < 0) { *prob = "Column counts inconsistent"; goto done; } } } count = state->common->rowcount; for (y = 0; y < state->h; y++) { if (count[y*3+POSITIVE] < 0 || count[y*3+NEGATIVE] < 0) count[y*3+NEUTRAL] = -1; else { count[y*3+NEUTRAL] = state->w - count[y*3+POSITIVE] - count[y*3+NEGATIVE]; if (count[y*3+NEUTRAL] < 0) { *prob = "Row counts inconsistent"; goto done; } } } for (y = 0; y < state->h; y++) { for (x = 0; x < state->w; x++) { idx = y*state->w + x; nextchar: c = *desc++; if (c == 'L') /* this square is LHS of a domino */ state->common->dominoes[idx] = idx+1; else if (c == 'R') /* ... RHS of a domino */ state->common->dominoes[idx] = idx-1; else if (c == 'T') /* ... top of a domino */ state->common->dominoes[idx] = idx+state->w; else if (c == 'B') /* ... bottom of a domino */ state->common->dominoes[idx] = idx-state->w; else if (c == '*') /* singleton */ state->common->dominoes[idx] = idx; else if (c == ',') /* spacer, ignore */ goto nextchar; else goto badchar; } } /* Check dominoes as input are sensibly consistent * (i.e. each end points to the other) */ for (idx = 0; idx < state->wh; idx++) { if (state->common->dominoes[idx] < 0 || state->common->dominoes[idx] > state->wh || state->common->dominoes[state->common->dominoes[idx]] != idx) { *prob = "Domino descriptions inconsistent"; goto done; } if (state->common->dominoes[idx] == idx) { state->grid[idx] = NEUTRAL; state->flags[idx] |= GS_SET; } } /* Success. */ state->numbered = 1; goto done; badchar: *prob = (c == 0) ? "Game description too short" : "Game description contained unexpected characters"; done: if (*prob) { free_game(state); return NULL; } return state; } static char *validate_desc(const game_params *params, const char *desc) { const char *prob; game_state *st = new_game_int(params, desc, &prob); if (!st) return (char*)prob; free_game(st); return NULL; } static game_state *new_game(midend *me, const game_params *params, const char *desc) { const char *prob; game_state *st = new_game_int(params, desc, &prob); assert(st); return st; } static char *generate_desc(game_state *new) { int x, y, idx, other, w = new->w, h = new->h; char *desc = snewn(new->wh + 2*(w + h) + 5, char), *p = desc; for (x = 0; x < w; x++) *p++ = n2c(new->common->colcount[x*3+POSITIVE]); *p++ = ','; for (y = 0; y < h; y++) *p++ = n2c(new->common->rowcount[y*3+POSITIVE]); *p++ = ','; for (x = 0; x < w; x++) *p++ = n2c(new->common->colcount[x*3+NEGATIVE]); *p++ = ','; for (y = 0; y < h; y++) *p++ = n2c(new->common->rowcount[y*3+NEGATIVE]); *p++ = ','; for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { idx = y*w + x; other = new->common->dominoes[idx]; if (other == idx) *p++ = '*'; else if (other == idx+1) *p++ = 'L'; else if (other == idx-1) *p++ = 'R'; else if (other == idx+w) *p++ = 'T'; else if (other == idx-w) *p++ = 'B'; else assert(!"mad domino orientation"); } } *p = '\0'; return desc; } static void game_text_hborder(const game_state *state, char **p_r) { char *p = *p_r; int x; *p++ = ' '; *p++ = '+'; for (x = 0; x < state->w*2-1; x++) *p++ = '-'; *p++ = '+'; *p++ = '\n'; *p_r = p; } static int game_can_format_as_text_now(const game_params *params) { return TRUE; } static char *game_text_format(const game_state *state) { int len, x, y, i; char *ret, *p; len = ((state->w*2)+4) * ((state->h*2)+4) + 2; p = ret = snewn(len, char); /* top row: '+' then column totals for plus. */ *p++ = '+'; for (x = 0; x < state->w; x++) { *p++ = ' '; *p++ = n2c(state->common->colcount[x*3+POSITIVE]); } *p++ = '\n'; /* top border. */ game_text_hborder(state, &p); for (y = 0; y < state->h; y++) { *p++ = n2c(state->common->rowcount[y*3+POSITIVE]); *p++ = '|'; for (x = 0; x < state->w; x++) { i = y*state->w+x; *p++ = state->common->dominoes[i] == i ? '#' : state->grid[i] == POSITIVE ? '+' : state->grid[i] == NEGATIVE ? '-' : state->flags[i] & GS_SET ? '*' : ' '; if (x < (state->w-1)) *p++ = state->common->dominoes[i] == i+1 ? ' ' : '|'; } *p++ = '|'; *p++ = n2c(state->common->rowcount[y*3+NEGATIVE]); *p++ = '\n'; if (y < (state->h-1)) { *p++ = ' '; *p++ = '|'; for (x = 0; x < state->w; x++) { i = y*state->w+x; *p++ = state->common->dominoes[i] == i+state->w ? ' ' : '-'; if (x < (state->w-1)) *p++ = '+'; } *p++ = '|'; *p++ = '\n'; } } /* bottom border. */ game_text_hborder(state, &p); /* bottom row: column totals for minus then '-'. */ *p++ = ' '; for (x = 0; x < state->w; x++) { *p++ = ' '; *p++ = n2c(state->common->colcount[x*3+NEGATIVE]); } *p++ = ' '; *p++ = '-'; *p++ = '\n'; *p++ = '\0'; return ret; } static void game_debug(game_state *state, const char *desc) { char *fmt = game_text_format(state); debug(("%s:\n%s\n", desc, fmt)); sfree(fmt); } enum { ROW, COLUMN }; typedef struct rowcol { int i, di, n, roworcol, num; int *targets; const char *name; } rowcol; static rowcol mkrowcol(const game_state *state, int num, int roworcol) { rowcol rc; rc.roworcol = roworcol; rc.num = num; if (roworcol == ROW) { rc.i = num * state->w; rc.di = 1; rc.n = state->w; rc.targets = &(state->common->rowcount[num*3]); rc.name = "row"; } else if (roworcol == COLUMN) { rc.i = num; rc.di = state->w; rc.n = state->h; rc.targets = &(state->common->colcount[num*3]); rc.name = "column"; } else { assert(!"unknown roworcol"); } return rc; } static int count_rowcol(const game_state *state, int num, int roworcol, int which) { int i, count = 0; rowcol rc = mkrowcol(state, num, roworcol); for (i = 0; i < rc.n; i++, rc.i += rc.di) { if (which < 0) { if (state->grid[rc.i] == EMPTY && !(state->flags[rc.i] & GS_SET)) count++; } else if (state->grid[rc.i] == which) count++; } return count; } static void check_rowcol(game_state *state, int num, int roworcol, int which, int *wrong, int *incomplete) { int count, target = mkrowcol(state, num, roworcol).targets[which]; if (target == -1) return; /* no number to check against. */ count = count_rowcol(state, num, roworcol, which); if (count < target) *incomplete = 1; if (count > target) *wrong = 1; } static int check_completion(game_state *state) { int i, j, x, y, idx, w = state->w, h = state->h; int which = POSITIVE, wrong = 0, incomplete = 0; /* Check row and column counts for magnets. */ for (which = POSITIVE, j = 0; j < 2; which = OPPOSITE(which), j++) { for (i = 0; i < w; i++) check_rowcol(state, i, COLUMN, which, &wrong, &incomplete); for (i = 0; i < h; i++) check_rowcol(state, i, ROW, which, &wrong, &incomplete); } /* Check each domino has been filled, and that we don't have * touching identical terminals. */ for (i = 0; i < state->wh; i++) state->flags[i] &= ~GS_ERROR; for (x = 0; x < w; x++) { for (y = 0; y < h; y++) { idx = y*w + x; if (state->common->dominoes[idx] == idx) continue; /* no domino here */ if (!(state->flags[idx] & GS_SET)) incomplete = 1; which = state->grid[idx]; if (which != NEUTRAL) { #define CHECK(xx,yy) do { \ if (INGRID(state,xx,yy) && \ (state->grid[(yy)*w+(xx)] == which)) { \ wrong = 1; \ state->flags[(yy)*w+(xx)] |= GS_ERROR; \ state->flags[y*w+x] |= GS_ERROR; \ } \ } while(0) CHECK(x,y-1); CHECK(x,y+1); CHECK(x-1,y); CHECK(x+1,y); #undef CHECK } } } return wrong ? -1 : incomplete ? 0 : 1; } static const int dx[4] = {-1, 1, 0, 0}; static const int dy[4] = {0, 0, -1, 1}; static void solve_clearflags(game_state *state) { int i; for (i = 0; i < state->wh; i++) { state->flags[i] &= ~GS_NOTMASK; if (state->common->dominoes[i] != i) state->flags[i] &= ~GS_SET; } } /* Knowing a given cell cannot be a certain colour also tells us * something about the other cell in that domino. */ static int solve_unflag(game_state *state, int i, int which, const char *why, rowcol *rc) { int ii, ret = 0; #if defined DEBUGGING || defined STANDALONE_SOLVER int w = state->w; #endif assert(i >= 0 && i < state->wh); ii = state->common->dominoes[i]; if (ii == i) return 0; if (rc) debug(("solve_unflag: (%d,%d) for %s %d", i%w, i/w, rc->name, rc->num)); if ((state->flags[i] & GS_SET) && (state->grid[i] == which)) { debug(("solve_unflag: (%d,%d) already %s, cannot unflag (for %s).", i%w, i/w, NAME(which), why)); return -1; } if ((state->flags[ii] & GS_SET) && (state->grid[ii] == OPPOSITE(which))) { debug(("solve_unflag: (%d,%d) opposite already %s, cannot unflag (for %s).", ii%w, ii/w, NAME(OPPOSITE(which)), why)); return -1; } if (POSSIBLE(i, which)) { state->flags[i] |= NOTFLAG(which); ret++; debug(("solve_unflag: (%d,%d) CANNOT be %s (%s)", i%w, i/w, NAME(which), why)); } if (POSSIBLE(ii, OPPOSITE(which))) { state->flags[ii] |= NOTFLAG(OPPOSITE(which)); ret++; debug(("solve_unflag: (%d,%d) CANNOT be %s (%s, other half)", ii%w, ii/w, NAME(OPPOSITE(which)), why)); } #ifdef STANDALONE_SOLVER if (verbose && ret) { printf("(%d,%d)", i%w, i/w); if (rc) printf(" in %s %d", rc->name, rc->num); printf(" cannot be %s (%s); opposite (%d,%d) not %s.\n", NAME(which), why, ii%w, ii/w, NAME(OPPOSITE(which))); } #endif return ret; } static int solve_unflag_surrounds(game_state *state, int i, int which) { int x = i%state->w, y = i/state->w, xx, yy, j, ii; assert(INGRID(state, x, y)); for (j = 0; j < 4; j++) { xx = x+dx[j]; yy = y+dy[j]; if (!INGRID(state, xx, yy)) continue; ii = yy*state->w+xx; if (solve_unflag(state, ii, which, "adjacent to set cell", NULL) < 0) return -1; } return 0; } /* Sets a cell to a particular colour, and also perform other * housekeeping around that. */ static int solve_set(game_state *state, int i, int which, const char *why, rowcol *rc) { int ii; #if defined DEBUGGING || defined STANDALONE_SOLVER int w = state->w; #endif ii = state->common->dominoes[i]; if (state->flags[i] & GS_SET) { if (state->grid[i] == which) { return 0; /* was already set and held, do nothing. */ } else { debug(("solve_set: (%d,%d) is held and %s, cannot set to %s", i%w, i/w, NAME(state->grid[i]), NAME(which))); return -1; } } if ((state->flags[ii] & GS_SET) && state->grid[ii] != OPPOSITE(which)) { debug(("solve_set: (%d,%d) opposite is held and %s, cannot set to %s", ii%w, ii/w, NAME(state->grid[ii]), NAME(OPPOSITE(which)))); return -1; } if (!POSSIBLE(i, which)) { debug(("solve_set: (%d,%d) NOT %s, cannot set.", i%w, i/w, NAME(which))); return -1; } if (!POSSIBLE(ii, OPPOSITE(which))) { debug(("solve_set: (%d,%d) NOT %s, cannot set (%d,%d).", ii%w, ii/w, NAME(OPPOSITE(which)), i%w, i/w)); return -1; } #ifdef STANDALONE_SOLVER if (verbose) { printf("(%d,%d)", i%w, i/w); if (rc) printf(" in %s %d", rc->name, rc->num); printf(" set to %s (%s), opposite (%d,%d) set to %s.\n", NAME(which), why, ii%w, ii/w, NAME(OPPOSITE(which))); } #endif if (rc) debug(("solve_set: (%d,%d) for %s %d", i%w, i/w, rc->name, rc->num)); debug(("solve_set: (%d,%d) setting to %s (%s), surrounds first:", i%w, i/w, NAME(which), why)); if (which != NEUTRAL) { if (solve_unflag_surrounds(state, i, which) < 0) return -1; if (solve_unflag_surrounds(state, ii, OPPOSITE(which)) < 0) return -1; } state->grid[i] = which; state->grid[ii] = OPPOSITE(which); state->flags[i] |= GS_SET; state->flags[ii] |= GS_SET; debug(("solve_set: (%d,%d) set to %s (%s)", i%w, i/w, NAME(which), why)); return 1; } /* counts should be int[4]. */ static void solve_counts(game_state *state, rowcol rc, int *counts, int *unset) { int i, j, which; assert(counts); for (i = 0; i < 4; i++) { counts[i] = 0; if (unset) unset[i] = 0; } for (i = rc.i, j = 0; j < rc.n; i += rc.di, j++) { if (state->flags[i] & GS_SET) { assert(state->grid[i] < 3); counts[state->grid[i]]++; } else if (unset) { for (which = 0; which <= 2; which++) { if (POSSIBLE(i, which)) unset[which]++; } } } } static int solve_checkfull(game_state *state, rowcol rc, int *counts) { int starti = rc.i, j, which, didsth = 0, target; int unset[4]; assert(state->numbered); /* only useful (should only be called) if numbered. */ solve_counts(state, rc, counts, unset); for (which = 0; which <= 2; which++) { target = rc.targets[which]; if (target == -1) continue; /*debug(("%s %d for %s: target %d, count %d, unset %d", rc.name, rc.num, NAME(which), target, counts[which], unset[which]));*/ if (target < counts[which]) { debug(("%s %d has too many (%d) %s squares (target %d), impossible!", rc.name, rc.num, counts[which], NAME(which), target)); return -1; } if (target == counts[which]) { /* We have the correct no. of the colour in this row/column * already; unflag all the rest. */ for (rc.i = starti, j = 0; j < rc.n; rc.i += rc.di, j++) { if (state->flags[rc.i] & GS_SET) continue; if (!POSSIBLE(rc.i, which)) continue; if (solve_unflag(state, rc.i, which, "row/col full", &rc) < 0) return -1; didsth = 1; } } else if ((target - counts[which]) == unset[which]) { /* We need all the remaining unset squares for this colour; * set them all. */ for (rc.i = starti, j = 0; j < rc.n; rc.i += rc.di, j++) { if (state->flags[rc.i] & GS_SET) continue; if (!POSSIBLE(rc.i, which)) continue; if (solve_set(state, rc.i, which, "row/col needs all unset", &rc) < 0) return -1; didsth = 1; } } } return didsth; } static int solve_startflags(game_state *state) { int x, y, i; for (x = 0; x < state->w; x++) { for (y = 0; y < state->h; y++) { i = y*state->w+x; if (state->common->dominoes[i] == i) continue; if (state->grid[i] != NEUTRAL || state->flags[i] & GS_SET) { if (solve_set(state, i, state->grid[i], "initial set-and-hold", NULL) < 0) return -1; } } } return 0; } typedef int (*rowcolfn)(game_state *state, rowcol rc, int *counts); static int solve_rowcols(game_state *state, rowcolfn fn) { int x, y, didsth = 0, ret; rowcol rc; int counts[4]; for (x = 0; x < state->w; x++) { rc = mkrowcol(state, x, COLUMN); solve_counts(state, rc, counts, NULL); ret = fn(state, rc, counts); if (ret < 0) return ret; didsth += ret; } for (y = 0; y < state->h; y++) { rc = mkrowcol(state, y, ROW); solve_counts(state, rc, counts, NULL); ret = fn(state, rc, counts); if (ret < 0) return ret; didsth += ret; } return didsth; } static int solve_force(game_state *state) { int i, which, didsth = 0; unsigned long f; for (i = 0; i < state->wh; i++) { if (state->flags[i] & GS_SET) continue; if (state->common->dominoes[i] == i) continue; f = state->flags[i] & GS_NOTMASK; which = -1; if (f == (GS_NOTPOSITIVE|GS_NOTNEGATIVE)) which = NEUTRAL; if (f == (GS_NOTPOSITIVE|GS_NOTNEUTRAL)) which = NEGATIVE; if (f == (GS_NOTNEGATIVE|GS_NOTNEUTRAL)) which = POSITIVE; if (which != -1) { if (solve_set(state, i, which, "forced by flags", NULL) < 0) return -1; didsth = 1; } } return didsth; } static int solve_neither(game_state *state) { int i, j, didsth = 0; for (i = 0; i < state->wh; i++) { if (state->flags[i] & GS_SET) continue; j = state->common->dominoes[i]; if (i == j) continue; if (((state->flags[i] & GS_NOTPOSITIVE) && (state->flags[j] & GS_NOTPOSITIVE)) || ((state->flags[i] & GS_NOTNEGATIVE) && (state->flags[j] & GS_NOTNEGATIVE))) { if (solve_set(state, i, NEUTRAL, "neither tile magnet", NULL) < 0) return -1; didsth = 1; } } return didsth; } static int solve_advancedfull(game_state *state, rowcol rc, int *counts) { int i, j, nfound = 0, clearpos = 0, clearneg = 0, ret = 0; /* For this row/col, look for a domino entirely within the row where * both ends can only be + or - (but isn't held). * The +/- counts can thus be decremented by 1 each, and the 'unset' * count by 2. * * Once that's done for all such dominoes (and they're marked), try * and made usual deductions about rest of the row based on new totals. */ if (rc.targets[POSITIVE] == -1 && rc.targets[NEGATIVE] == -1) return 0; /* don't have a target for either colour, nothing to do. */ if ((rc.targets[POSITIVE] >= 0 && counts[POSITIVE] == rc.targets[POSITIVE]) && (rc.targets[NEGATIVE] >= 0 && counts[NEGATIVE] == rc.targets[NEGATIVE])) return 0; /* both colours are full up already, nothing to do. */ for (i = rc.i, j = 0; j < rc.n; i += rc.di, j++) state->flags[i] &= ~GS_MARK; for (i = rc.i, j = 0; j < rc.n; i += rc.di, j++) { if (state->flags[i] & GS_SET) continue; /* We're looking for a domino in our row/col, thus if * dominoes[i] -> i+di we've found one. */ if (state->common->dominoes[i] != i+rc.di) continue; /* We need both squares of this domino to be either + or - * (i.e. both NOTNEUTRAL only). */ if (((state->flags[i] & GS_NOTMASK) != GS_NOTNEUTRAL) || ((state->flags[i+rc.di] & GS_NOTMASK) != GS_NOTNEUTRAL)) continue; debug(("Domino in %s %d at (%d,%d) must be polarised.", rc.name, rc.num, i%state->w, i/state->w)); state->flags[i] |= GS_MARK; state->flags[i+rc.di] |= GS_MARK; nfound++; } if (nfound == 0) return 0; /* nfound is #dominoes we matched, which will all be marked. */ counts[POSITIVE] += nfound; counts[NEGATIVE] += nfound; if (rc.targets[POSITIVE] >= 0 && counts[POSITIVE] == rc.targets[POSITIVE]) { debug(("%s %d has now filled POSITIVE:", rc.name, rc.num)); clearpos = 1; } if (rc.targets[NEGATIVE] >= 0 && counts[NEGATIVE] == rc.targets[NEGATIVE]) { debug(("%s %d has now filled NEGATIVE:", rc.name, rc.num)); clearneg = 1; } if (!clearpos && !clearneg) return 0; for (i = rc.i, j = 0; j < rc.n; i += rc.di, j++) { if (state->flags[i] & GS_SET) continue; if (state->flags[i] & GS_MARK) continue; if (clearpos && !(state->flags[i] & GS_NOTPOSITIVE)) { if (solve_unflag(state, i, POSITIVE, "row/col full (+ve) [tricky]", &rc) < 0) return -1; ret++; } if (clearneg && !(state->flags[i] & GS_NOTNEGATIVE)) { if (solve_unflag(state, i, NEGATIVE, "row/col full (-ve) [tricky]", &rc) < 0) return -1; ret++; } } return ret; } /* If we only have one neutral still to place on a row/column then no dominoes entirely in that row/column can be neutral. */ static int solve_nonneutral(game_state *state, rowcol rc, int *counts) { int i, j, ret = 0; if (rc.targets[NEUTRAL] != counts[NEUTRAL]+1) return 0; for (i = rc.i, j = 0; j < rc.n; i += rc.di, j++) { if (state->flags[i] & GS_SET) continue; if (state->common->dominoes[i] != i+rc.di) continue; if (!(state->flags[i] & GS_NOTNEUTRAL)) { if (solve_unflag(state, i, NEUTRAL, "single neutral in row/col [tricky]", &rc) < 0) return -1; ret++; } } return ret; } /* If we need to fill all unfilled cells with +-, and we need 1 more of * one than the other, and we have a single odd-numbered region of unfilled * cells, that odd-numbered region must start and end with the extra number. */ static int solve_oddlength(game_state *state, rowcol rc, int *counts) { int i, j, ret = 0, extra, tpos, tneg; int start = -1, length = 0, inempty = 0, startodd = -1; /* need zero neutral cells still to find... */ if (rc.targets[NEUTRAL] != counts[NEUTRAL]) return 0; /* ...and #positive and #negative to differ by one. */ tpos = rc.targets[POSITIVE] - counts[POSITIVE]; tneg = rc.targets[NEGATIVE] - counts[NEGATIVE]; if (tpos == tneg+1) extra = POSITIVE; else if (tneg == tpos+1) extra = NEGATIVE; else return 0; for (i = rc.i, j = 0; j < rc.n; i += rc.di, j++) { if (state->flags[i] & GS_SET) { if (inempty) { if (length % 2) { /* we've just finished an odd-length section. */ if (startodd != -1) goto twoodd; startodd = start; } inempty = 0; } } else { if (inempty) length++; else { start = i; length = 1; inempty = 1; } } } if (inempty && (length % 2)) { if (startodd != -1) goto twoodd; startodd = start; } if (startodd != -1) ret = solve_set(state, startodd, extra, "odd-length section start", &rc); return ret; twoodd: debug(("%s %d has >1 odd-length sections, starting at %d,%d and %d,%d.", rc.name, rc.num, startodd%state->w, startodd/state->w, start%state->w, start/state->w)); return 0; } /* Count the number of remaining empty dominoes in any row/col. * If that number is equal to the #remaining positive, * or to the #remaining negative, no empty cells can be neutral. */ static int solve_countdominoes_neutral(game_state *state, rowcol rc, int *counts) { int i, j, ndom = 0, nonn = 0, ret = 0; if ((rc.targets[POSITIVE] == -1) && (rc.targets[NEGATIVE] == -1)) return 0; /* need at least one target to compare. */ for (i = rc.i, j = 0; j < rc.n; i += rc.di, j++) { if (state->flags[i] & GS_SET) continue; assert(state->grid[i] == EMPTY); /* Skip solo cells, or second cell in domino. */ if ((state->common->dominoes[i] == i) || (state->common->dominoes[i] == i-rc.di)) continue; ndom++; } if ((rc.targets[POSITIVE] != -1) && (rc.targets[POSITIVE]-counts[POSITIVE] == ndom)) nonn = 1; if ((rc.targets[NEGATIVE] != -1) && (rc.targets[NEGATIVE]-counts[NEGATIVE] == ndom)) nonn = 1; if (!nonn) return 0; for (i = rc.i, j = 0; j < rc.n; i += rc.di, j++) { if (state->flags[i] & GS_SET) continue; if (!(state->flags[i] & GS_NOTNEUTRAL)) { if (solve_unflag(state, i, NEUTRAL, "all dominoes +/- [tricky]", &rc) < 0) return -1; ret++; } } return ret; } static int solve_domino_count(game_state *state, rowcol rc, int i, int which) { int nposs = 0; /* Skip solo cells or 2nd in domino. */ if ((state->common->dominoes[i] == i) || (state->common->dominoes[i] == i-rc.di)) return 0; if (state->flags[i] & GS_SET) return 0; if (POSSIBLE(i, which)) nposs++; if (state->common->dominoes[i] == i+rc.di) { /* second cell of domino is on our row: test that too. */ if (POSSIBLE(i+rc.di, which)) nposs++; } return nposs; } /* Count number of dominoes we could put each of + and - into. If it is equal * to the #left, any domino we can only put + or - in one cell of must have it. */ static int solve_countdominoes_nonneutral(game_state *state, rowcol rc, int *counts) { int which, w, i, j, ndom = 0, didsth = 0, toset; for (which = POSITIVE, w = 0; w < 2; which = OPPOSITE(which), w++) { if (rc.targets[which] == -1) continue; for (i = rc.i, j = 0; j < rc.n; i += rc.di, j++) { if (solve_domino_count(state, rc, i, which) > 0) ndom++; } if ((rc.targets[which] - counts[which]) != ndom) continue; for (i = rc.i, j = 0; j < rc.n; i += rc.di, j++) { if (solve_domino_count(state, rc, i, which) == 1) { if (POSSIBLE(i, which)) toset = i; else { /* paranoia, should have been checked by solve_domino_count. */ assert(state->common->dominoes[i] == i+rc.di); assert(POSSIBLE(i+rc.di, which)); toset = i+rc.di; } if (solve_set(state, toset, which, "all empty dominoes need +/- [tricky]", &rc) < 0) return -1; didsth++; } } } return didsth; } /* danger, evil macro. can't use the do { ... } while(0) trick because * the continue breaks. */ #define SOLVE_FOR_ROWCOLS(fn) \ ret = solve_rowcols(state, fn); \ if (ret < 0) { debug(("%s said impossible, cannot solve", #fn)); return -1; } \ if (ret > 0) continue static int solve_state(game_state *state, int diff) { int ret; debug(("solve_state, difficulty %s", magnets_diffnames[diff])); solve_clearflags(state); if (solve_startflags(state) < 0) return -1; while (1) { ret = solve_force(state); if (ret > 0) continue; if (ret < 0) return -1; ret = solve_neither(state); if (ret > 0) continue; if (ret < 0) return -1; SOLVE_FOR_ROWCOLS(solve_checkfull); SOLVE_FOR_ROWCOLS(solve_oddlength); if (diff < DIFF_TRICKY) break; SOLVE_FOR_ROWCOLS(solve_advancedfull); SOLVE_FOR_ROWCOLS(solve_nonneutral); SOLVE_FOR_ROWCOLS(solve_countdominoes_neutral); SOLVE_FOR_ROWCOLS(solve_countdominoes_nonneutral); /* more ... */ break; } return check_completion(state); } static char *game_state_diff(const game_state *src, const game_state *dst, int issolve) { char *ret = NULL, buf[80], c; int retlen = 0, x, y, i, k; assert(src->w == dst->w && src->h == dst->h); if (issolve) { ret = sresize(ret, 3, char); ret[0] = 'S'; ret[1] = ';'; ret[2] = '\0'; retlen += 2; } for (x = 0; x < dst->w; x++) { for (y = 0; y < dst->h; y++) { i = y*dst->w+x; if (src->common->dominoes[i] == i) continue; #define APPEND do { \ ret = sresize(ret, retlen + k + 1, char); \ strcpy(ret + retlen, buf); \ retlen += k; \ } while(0) if ((src->grid[i] != dst->grid[i]) || ((src->flags[i] & GS_SET) != (dst->flags[i] & GS_SET))) { if (dst->grid[i] == EMPTY && !(dst->flags[i] & GS_SET)) c = ' '; else c = GRID2CHAR(dst->grid[i]); k = sprintf(buf, "%c%d,%d;", (int)c, x, y); APPEND; } } } debug(("game_state_diff returns %s", ret)); return ret; } static void solve_from_aux(const game_state *state, const char *aux) { int i; assert(strlen(aux) == state->wh); for (i = 0; i < state->wh; i++) { state->grid[i] = CHAR2GRID(aux[i]); state->flags[i] |= GS_SET; } } static char *solve_game(const game_state *state, const game_state *currstate, const char *aux, char **error) { game_state *solved = dup_game(currstate); char *move = NULL; int ret; if (aux && strlen(aux) == state->wh) { solve_from_aux(solved, aux); goto solved; } if (solve_state(solved, DIFFCOUNT) > 0) goto solved; free_game(solved); solved = dup_game(state); ret = solve_state(solved, DIFFCOUNT); if (ret > 0) goto solved; free_game(solved); *error = (ret < 0) ? "Puzzle is impossible." : "Unable to solve puzzle."; return NULL; solved: move = game_state_diff(currstate, solved, 1); free_game(solved); return move; } static int solve_unnumbered(game_state *state) { int i, ret; while (1) { ret = solve_force(state); if (ret > 0) continue; if (ret < 0) return -1; ret = solve_neither(state); if (ret > 0) continue; if (ret < 0) return -1; break; } for (i = 0; i < state->wh; i++) { if (!(state->flags[i] & GS_SET)) return 0; } return 1; } static int lay_dominoes(game_state *state, random_state *rs, int *scratch) { int n, i, ret = 0, nlaid = 0, n_initial_neutral; for (i = 0; i < state->wh; i++) { scratch[i] = i; state->grid[i] = EMPTY; state->flags[i] = (state->common->dominoes[i] == i) ? GS_SET : 0; } shuffle(scratch, state->wh, sizeof(int), rs); n_initial_neutral = (state->wh > 100) ? 5 : (state->wh / 10); for (n = 0; n < state->wh; n++) { /* Find a space ... */ i = scratch[n]; if (state->flags[i] & GS_SET) continue; /* already laid here. */ /* ...and lay a domino if we can. */ debug(("Laying domino at i:%d, (%d,%d)\n", i, i%state->w, i/state->w)); /* The choice of which type of domino to lay here leads to subtle differences * in the sorts of boards that get produced. Too much bias towards magnets * leads to games that are too easy. * * Currently, it lays a small set of dominoes at random as neutral, and * then lays the rest preferring to be magnets -- however, if the * current layout is such that a magnet won't go there, then it lays * another neutral. * * The number of initially neutral dominoes is limited as grids get bigger: * too many neutral dominoes invariably ends up with insoluble puzzle at * this size, and the positioning process means it'll always end up laying * more than the initial 5 anyway. */ /* We should always be able to lay a neutral anywhere. */ assert(!(state->flags[i] & GS_NOTNEUTRAL)); if (n < n_initial_neutral) { debug((" ...laying neutral\n")); ret = solve_set(state, i, NEUTRAL, "layout initial neutral", NULL); } else { debug((" ... preferring magnet\n")); if (!(state->flags[i] & GS_NOTPOSITIVE)) ret = solve_set(state, i, POSITIVE, "layout", NULL); else if (!(state->flags[i] & GS_NOTNEGATIVE)) ret = solve_set(state, i, NEGATIVE, "layout", NULL); else ret = solve_set(state, i, NEUTRAL, "layout", NULL); } if (!ret) { debug(("Unable to lay anything at (%d,%d), giving up.", i%state->w, i/state->w)); ret = -1; break; } nlaid++; ret = solve_unnumbered(state); if (ret == -1) debug(("solve_unnumbered decided impossible.\n")); if (ret != 0) break; } debug(("Laid %d dominoes, total %d dominoes.\n", nlaid, state->wh/2)); game_debug(state, "Final layout"); return ret; } static void gen_game(game_state *new, random_state *rs) { int ret, x, y, val; int *scratch = snewn(new->wh, int); #ifdef STANDALONE_SOLVER if (verbose) printf("Generating new game...\n"); #endif clear_state(new); sfree(new->common->dominoes); /* bit grotty. */ new->common->dominoes = domino_layout(new->w, new->h, rs); do { ret = lay_dominoes(new, rs, scratch); } while(ret == -1); /* for each cell, update colcount/rowcount as appropriate. */ memset(new->common->colcount, 0, new->w*3*sizeof(int)); memset(new->common->rowcount, 0, new->h*3*sizeof(int)); for (x = 0; x < new->w; x++) { for (y = 0; y < new->h; y++) { val = new->grid[y*new->w+x]; new->common->colcount[x*3+val]++; new->common->rowcount[y*3+val]++; } } new->numbered = 1; sfree(scratch); } static void generate_aux(game_state *new, char *aux) { int i; for (i = 0; i < new->wh; i++) aux[i] = GRID2CHAR(new->grid[i]); aux[new->wh] = '\0'; } static int check_difficulty(const game_params *params, game_state *new, random_state *rs) { int *scratch, *grid_correct, slen, i; memset(new->grid, EMPTY, new->wh*sizeof(int)); if (params->diff > DIFF_EASY) { /* If this is too easy, return. */ if (solve_state(new, params->diff-1) > 0) { debug(("Puzzle is too easy.")); return -1; } } if (solve_state(new, params->diff) <= 0) { debug(("Puzzle is not soluble at requested difficulty.")); return -1; } if (!params->stripclues) return 0; /* Copy the correct grid away. */ grid_correct = snewn(new->wh, int); memcpy(grid_correct, new->grid, new->wh*sizeof(int)); /* Create shuffled array of side-clue locations. */ slen = new->w*2 + new->h*2; scratch = snewn(slen, int); for (i = 0; i < slen; i++) scratch[i] = i; shuffle(scratch, slen, sizeof(int), rs); /* For each clue, check whether removing it makes the puzzle unsoluble; * put it back if so. */ for (i = 0; i < slen; i++) { int num = scratch[i], which, roworcol, target, targetn, ret; rowcol rc; /* work out which clue we meant. */ if (num < new->w+new->h) { which = POSITIVE; } else { which = NEGATIVE; num -= new->w+new->h; } if (num < new->w) { roworcol = COLUMN; } else { roworcol = ROW; num -= new->w; } /* num is now the row/column index in question. */ rc = mkrowcol(new, num, roworcol); /* Remove clue, storing original... */ target = rc.targets[which]; targetn = rc.targets[NEUTRAL]; rc.targets[which] = -1; rc.targets[NEUTRAL] = -1; /* ...and see if we can still solve it. */ game_debug(new, "removed clue, new board:"); memset(new->grid, EMPTY, new->wh * sizeof(int)); ret = solve_state(new, params->diff); assert(ret != -1); if (ret == 0 || memcmp(new->grid, grid_correct, new->wh*sizeof(int)) != 0) { /* We made it ambiguous: put clue back. */ debug(("...now impossible/different, put clue back.")); rc.targets[which] = target; rc.targets[NEUTRAL] = targetn; } } sfree(scratch); sfree(grid_correct); return 0; } static char *new_game_desc(const game_params *params, random_state *rs, char **aux_r, int interactive) { game_state *new = new_state(params->w, params->h); char *desc, *aux = snewn(new->wh+1, char); do { gen_game(new, rs); generate_aux(new, aux); } while (check_difficulty(params, new, rs) < 0); /* now we're complete, generate the description string * and an aux_info for the completed game. */ desc = generate_desc(new); free_game(new); *aux_r = aux; return desc; } struct game_ui { int cur_x, cur_y, cur_visible; }; static game_ui *new_ui(const game_state *state) { game_ui *ui = snew(game_ui); ui->cur_x = ui->cur_y = 0; ui->cur_visible = 0; return ui; } static void free_ui(game_ui *ui) { sfree(ui); } static char *encode_ui(const game_ui *ui) { return NULL; } static void decode_ui(game_ui *ui, const char *encoding) { } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { if (!oldstate->completed && newstate->completed) ui->cur_visible = 0; } struct game_drawstate { int tilesize, started, solved; int w, h; unsigned long *what; /* size w*h */ unsigned long *colwhat, *rowwhat; /* size 3*w, 3*h */ }; #define DS_WHICH_MASK 0xf #define DS_ERROR 0x10 #define DS_CURSOR 0x20 #define DS_SET 0x40 #define DS_NOTPOS 0x80 #define DS_NOTNEG 0x100 #define DS_NOTNEU 0x200 #define DS_FLASH 0x400 #define PREFERRED_TILE_SIZE 32 #define TILE_SIZE (ds->tilesize) #define BORDER (TILE_SIZE / 8) #define COORD(x) ( (x+1) * TILE_SIZE + BORDER ) #define FROMCOORD(x) ( (x - BORDER) / TILE_SIZE - 1 ) static int is_clue(const game_state *state, int x, int y) { int h = state->h, w = state->w; if (((x == -1 || x == w) && y >= 0 && y < h) || ((y == -1 || y == h) && x >= 0 && x < w)) return TRUE; return FALSE; } static int clue_index(const game_state *state, int x, int y) { int h = state->h, w = state->w; if (y == -1) return x; else if (x == w) return w + y; else if (y == h) return 2 * w + h - x - 1; else if (x == -1) return 2 * (w + h) - y - 1; return -1; } static char *interpret_move(const game_state *state, game_ui *ui, const game_drawstate *ds, int x, int y, int button) { int gx = FROMCOORD(x), gy = FROMCOORD(y), idx, curr; char *nullret = NULL, buf[80], movech; enum { CYCLE_MAGNET, CYCLE_NEUTRAL } action; if (IS_CURSOR_MOVE(button)) { move_cursor(button, &ui->cur_x, &ui->cur_y, state->w, state->h, 0); ui->cur_visible = 1; return ""; } else if (IS_CURSOR_SELECT(button)) { if (!ui->cur_visible) { ui->cur_visible = 1; return ""; } action = (button == CURSOR_SELECT) ? CYCLE_MAGNET : CYCLE_NEUTRAL; gx = ui->cur_x; gy = ui->cur_y; } else if (INGRID(state, gx, gy) && (button == LEFT_BUTTON || button == RIGHT_BUTTON)) { if (ui->cur_visible) { ui->cur_visible = 0; nullret = ""; } action = (button == LEFT_BUTTON) ? CYCLE_MAGNET : CYCLE_NEUTRAL; } else if (button == LEFT_BUTTON && is_clue(state, gx, gy)) { sprintf(buf, "D%d,%d", gx, gy); return dupstr(buf); } else return NULL; idx = gy * state->w + gx; if (state->common->dominoes[idx] == idx) return nullret; curr = state->grid[idx]; if (action == CYCLE_MAGNET) { /* ... empty --> positive --> negative --> empty ... */ if (state->grid[idx] == NEUTRAL && state->flags[idx] & GS_SET) return nullret; /* can't cycle a magnet from a neutral. */ movech = (curr == EMPTY) ? '+' : (curr == POSITIVE) ? '-' : ' '; } else if (action == CYCLE_NEUTRAL) { /* ... empty -> neutral -> !neutral --> empty ... */ if (state->grid[idx] != NEUTRAL) return nullret; /* can't cycle through neutral from a magnet. */ /* All of these are grid == EMPTY == NEUTRAL; it twiddles * combinations of flags. */ if (state->flags[idx] & GS_SET) /* neutral */ movech = '?'; else if (state->flags[idx] & GS_NOTNEUTRAL) /* !neutral */ movech = ' '; else movech = '.'; } else { assert(!"unknown action"); movech = 0; /* placate optimiser */ } sprintf(buf, "%c%d,%d", movech, gx, gy); return dupstr(buf); } static game_state *execute_move(const game_state *state, const char *move) { game_state *ret = dup_game(state); int x, y, n, idx, idx2; char c; if (!*move) goto badmove; while (*move) { c = *move++; if (c == 'S') { ret->solved = TRUE; n = 0; } else if (c == '+' || c == '-' || c == '.' || c == ' ' || c == '?') { if ((sscanf(move, "%d,%d%n", &x, &y, &n) != 2) || !INGRID(state, x, y)) goto badmove; idx = y*state->w + x; idx2 = state->common->dominoes[idx]; if (idx == idx2) goto badmove; ret->flags[idx] &= ~GS_NOTMASK; ret->flags[idx2] &= ~GS_NOTMASK; if (c == ' ' || c == '?') { ret->grid[idx] = EMPTY; ret->grid[idx2] = EMPTY; ret->flags[idx] &= ~GS_SET; ret->flags[idx2] &= ~GS_SET; if (c == '?') { ret->flags[idx] |= GS_NOTNEUTRAL; ret->flags[idx2] |= GS_NOTNEUTRAL; } } else { ret->grid[idx] = CHAR2GRID(c); ret->grid[idx2] = OPPOSITE(CHAR2GRID(c)); ret->flags[idx] |= GS_SET; ret->flags[idx2] |= GS_SET; } } else if (c == 'D' && sscanf(move, "%d,%d%n", &x, &y, &n) == 2 && is_clue(ret, x, y)) { ret->counts_done[clue_index(ret, x, y)] ^= 1; } else goto badmove; move += n; if (*move == ';') move++; else if (*move) goto badmove; } if (check_completion(ret) == 1) ret->completed = 1; return ret; badmove: free_game(ret); return NULL; } /* ---------------------------------------------------------------------- * Drawing routines. */ static void game_compute_size(const game_params *params, int tilesize, int *x, int *y) { /* Ick: fake up `ds->tilesize' for macro expansion purposes */ struct { int tilesize; } ads, *ds = &ads; ads.tilesize = tilesize; *x = TILE_SIZE * (params->w+2) + 2 * BORDER; *y = TILE_SIZE * (params->h+2) + 2 * BORDER; } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { ds->tilesize = tilesize; } static float *game_colours(frontend *fe, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float); int i; game_mkhighlight(fe, ret, COL_BACKGROUND, COL_HIGHLIGHT, COL_LOWLIGHT); for (i = 0; i < 3; i++) { ret[COL_TEXT * 3 + i] = 0.0F; ret[COL_NEGATIVE * 3 + i] = 0.0F; ret[COL_CURSOR * 3 + i] = 0.9F; ret[COL_DONE * 3 + i] = ret[COL_BACKGROUND * 3 + i] / 1.5F; } ret[COL_POSITIVE * 3 + 0] = 0.8F; ret[COL_POSITIVE * 3 + 1] = 0.0F; ret[COL_POSITIVE * 3 + 2] = 0.0F; ret[COL_NEUTRAL * 3 + 0] = 0.10F; ret[COL_NEUTRAL * 3 + 1] = 0.60F; ret[COL_NEUTRAL * 3 + 2] = 0.10F; ret[COL_ERROR * 3 + 0] = 1.0F; ret[COL_ERROR * 3 + 1] = 0.0F; ret[COL_ERROR * 3 + 2] = 0.0F; ret[COL_NOT * 3 + 0] = 0.2F; ret[COL_NOT * 3 + 1] = 0.2F; ret[COL_NOT * 3 + 2] = 1.0F; *ncolours = NCOLOURS; return ret; } static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { struct game_drawstate *ds = snew(struct game_drawstate); ds->tilesize = ds->started = ds->solved = 0; ds->w = state->w; ds->h = state->h; ds->what = snewn(state->wh, unsigned long); memset(ds->what, 0, state->wh*sizeof(unsigned long)); ds->colwhat = snewn(state->w*3, unsigned long); memset(ds->colwhat, 0, state->w*3*sizeof(unsigned long)); ds->rowwhat = snewn(state->h*3, unsigned long); memset(ds->rowwhat, 0, state->h*3*sizeof(unsigned long)); return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { sfree(ds->colwhat); sfree(ds->rowwhat); sfree(ds->what); sfree(ds); } static void draw_num(drawing *dr, game_drawstate *ds, int rowcol, int which, int idx, int colbg, int col, int num) { char buf[32]; int cx, cy, tsz; if (num < 0) return; sprintf(buf, "%d", num); tsz = (strlen(buf) == 1) ? (7*TILE_SIZE/10) : (9*TILE_SIZE/10)/strlen(buf); if (rowcol == ROW) { cx = BORDER; if (which == NEGATIVE) cx += TILE_SIZE * (ds->w+1); cy = BORDER + TILE_SIZE * (idx+1); } else { cx = BORDER + TILE_SIZE * (idx+1); cy = BORDER; if (which == NEGATIVE) cy += TILE_SIZE * (ds->h+1); } draw_rect(dr, cx, cy, TILE_SIZE, TILE_SIZE, colbg); draw_text(dr, cx + TILE_SIZE/2, cy + TILE_SIZE/2, FONT_VARIABLE, tsz, ALIGN_VCENTRE | ALIGN_HCENTRE, col, buf); draw_update(dr, cx, cy, TILE_SIZE, TILE_SIZE); } static void draw_sym(drawing *dr, game_drawstate *ds, int x, int y, int which, int col) { int cx = COORD(x), cy = COORD(y); int ccx = cx + TILE_SIZE/2, ccy = cy + TILE_SIZE/2; int roff = TILE_SIZE/4, rsz = 2*roff+1; int soff = TILE_SIZE/16, ssz = 2*soff+1; if (which == POSITIVE || which == NEGATIVE) { draw_rect(dr, ccx - roff, ccy - soff, rsz, ssz, col); if (which == POSITIVE) draw_rect(dr, ccx - soff, ccy - roff, ssz, rsz, col); } else if (col == COL_NOT) { /* not-a-neutral is a blue question mark. */ char qu[2] = { '?', 0 }; draw_text(dr, ccx, ccy, FONT_VARIABLE, 7*TILE_SIZE/10, ALIGN_VCENTRE | ALIGN_HCENTRE, col, qu); } else { draw_line(dr, ccx - roff, ccy - roff, ccx + roff, ccy + roff, col); draw_line(dr, ccx + roff, ccy - roff, ccx - roff, ccy + roff, col); } } enum { TYPE_L, TYPE_R, TYPE_T, TYPE_B, TYPE_BLANK }; /* NOT responsible for redrawing background or updating. */ static void draw_tile_col(drawing *dr, game_drawstate *ds, int *dominoes, int x, int y, int which, int bg, int fg, int perc) { int cx = COORD(x), cy = COORD(y), i, other, type = TYPE_BLANK; int gutter, radius, coffset; /* gutter is TSZ/16 for 100%, 8*TSZ/16 (TSZ/2) for 0% */ gutter = (TILE_SIZE / 16) + ((100 - perc) * (7*TILE_SIZE / 16))/100; radius = (perc * (TILE_SIZE / 8)) / 100; coffset = gutter + radius; i = y*ds->w + x; other = dominoes[i]; if (other == i) return; else if (other == i+1) type = TYPE_L; else if (other == i-1) type = TYPE_R; else if (other == i+ds->w) type = TYPE_T; else if (other == i-ds->w) type = TYPE_B; else assert(!"mad domino orientation"); /* domino drawing shamelessly stolen from dominosa.c. */ if (type == TYPE_L || type == TYPE_T) draw_circle(dr, cx+coffset, cy+coffset, radius, bg, bg); if (type == TYPE_R || type == TYPE_T) draw_circle(dr, cx+TILE_SIZE-1-coffset, cy+coffset, radius, bg, bg); if (type == TYPE_L || type == TYPE_B) draw_circle(dr, cx+coffset, cy+TILE_SIZE-1-coffset, radius, bg, bg); if (type == TYPE_R || type == TYPE_B) draw_circle(dr, cx+TILE_SIZE-1-coffset, cy+TILE_SIZE-1-coffset, radius, bg, bg); for (i = 0; i < 2; i++) { int x1, y1, x2, y2; x1 = cx + (i ? gutter : coffset); y1 = cy + (i ? coffset : gutter); x2 = cx + TILE_SIZE-1 - (i ? gutter : coffset); y2 = cy + TILE_SIZE-1 - (i ? coffset : gutter); if (type == TYPE_L) x2 = cx + TILE_SIZE; else if (type == TYPE_R) x1 = cx; else if (type == TYPE_T) y2 = cy + TILE_SIZE ; else if (type == TYPE_B) y1 = cy; draw_rect(dr, x1, y1, x2-x1+1, y2-y1+1, bg); } if (fg != -1) draw_sym(dr, ds, x, y, which, fg); } static void draw_tile(drawing *dr, game_drawstate *ds, int *dominoes, int x, int y, unsigned long flags) { int cx = COORD(x), cy = COORD(y), bg, fg, perc = 100; int which = flags & DS_WHICH_MASK; flags &= ~DS_WHICH_MASK; draw_rect(dr, cx, cy, TILE_SIZE, TILE_SIZE, COL_BACKGROUND); if (flags & DS_CURSOR) bg = COL_CURSOR; /* off-white white for cursor */ else if (which == POSITIVE) bg = COL_POSITIVE; else if (which == NEGATIVE) bg = COL_NEGATIVE; else if (flags & DS_SET) bg = COL_NEUTRAL; /* green inner for neutral cells */ else bg = COL_LOWLIGHT; /* light grey for empty cells. */ if (which == EMPTY && !(flags & DS_SET)) { int notwhich = -1; fg = -1; /* don't draw cross unless actually set as neutral. */ if (flags & DS_NOTPOS) notwhich = POSITIVE; if (flags & DS_NOTNEG) notwhich = NEGATIVE; if (flags & DS_NOTNEU) notwhich = NEUTRAL; if (notwhich != -1) { which = notwhich; fg = COL_NOT; } } else fg = (flags & DS_ERROR) ? COL_ERROR : (flags & DS_CURSOR) ? COL_TEXT : COL_BACKGROUND; draw_rect(dr, cx, cy, TILE_SIZE, TILE_SIZE, COL_BACKGROUND); if (flags & DS_FLASH) { int bordercol = COL_HIGHLIGHT; draw_tile_col(dr, ds, dominoes, x, y, which, bordercol, -1, perc); perc = 3*perc/4; } draw_tile_col(dr, ds, dominoes, x, y, which, bg, fg, perc); draw_update(dr, cx, cy, TILE_SIZE, TILE_SIZE); } static int get_count_color(const game_state *state, int rowcol, int which, int index, int target) { int idx; int count = count_rowcol(state, index, rowcol, which); if ((count > target) || (count < target && !count_rowcol(state, index, rowcol, -1))) { return COL_ERROR; } else if (rowcol == COLUMN) { idx = clue_index(state, index, which == POSITIVE ? -1 : state->h); } else { idx = clue_index(state, which == POSITIVE ? -1 : state->w, index); } if (state->counts_done[idx]) { return COL_DONE; } return COL_TEXT; } static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float animtime, float flashtime) { int x, y, w = state->w, h = state->h, which, i, j, flash; flash = (int)(flashtime * 5 / FLASH_TIME) % 2; if (!ds->started) { /* draw background, corner +-. */ draw_rect(dr, 0, 0, TILE_SIZE * (w+2) + 2 * BORDER, TILE_SIZE * (h+2) + 2 * BORDER, COL_BACKGROUND); draw_sym(dr, ds, -1, -1, POSITIVE, COL_TEXT); draw_sym(dr, ds, state->w, state->h, NEGATIVE, COL_TEXT); draw_update(dr, 0, 0, TILE_SIZE * (ds->w+2) + 2 * BORDER, TILE_SIZE * (ds->h+2) + 2 * BORDER); } /* Draw grid */ for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { int idx = y*w+x; unsigned long c = state->grid[idx]; if (state->flags[idx] & GS_ERROR) c |= DS_ERROR; if (state->flags[idx] & GS_SET) c |= DS_SET; if (x == ui->cur_x && y == ui->cur_y && ui->cur_visible) c |= DS_CURSOR; if (flash) c |= DS_FLASH; if (state->flags[idx] & GS_NOTPOSITIVE) c |= DS_NOTPOS; if (state->flags[idx] & GS_NOTNEGATIVE) c |= DS_NOTNEG; if (state->flags[idx] & GS_NOTNEUTRAL) c |= DS_NOTNEU; if (ds->what[idx] != c || !ds->started) { draw_tile(dr, ds, state->common->dominoes, x, y, c); ds->what[idx] = c; } } } /* Draw counts around side */ for (which = POSITIVE, j = 0; j < 2; which = OPPOSITE(which), j++) { for (i = 0; i < w; i++) { int index = i * 3 + which; int target = state->common->colcount[index]; int color = get_count_color(state, COLUMN, which, i, target); if (color != ds->colwhat[index] || !ds->started) { draw_num(dr, ds, COLUMN, which, i, COL_BACKGROUND, color, target); ds->colwhat[index] = color; } } for (i = 0; i < h; i++) { int index = i * 3 + which; int target = state->common->rowcount[index]; int color = get_count_color(state, ROW, which, i, target); if (color != ds->rowwhat[index] || !ds->started) { draw_num(dr, ds, ROW, which, i, COL_BACKGROUND, color, target); ds->rowwhat[index] = color; } } } ds->started = 1; } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return 0.0F; } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { if (!oldstate->completed && newstate->completed && !oldstate->solved && !newstate->solved) return FLASH_TIME; return 0.0F; } static int game_status(const game_state *state) { return state->completed ? +1 : 0; } static int game_timing_state(const game_state *state, game_ui *ui) { return TRUE; } static void game_print_size(const game_params *params, float *x, float *y) { int pw, ph; /* * I'll use 6mm squares by default. */ game_compute_size(params, 600, &pw, &ph); *x = pw / 100.0F; *y = ph / 100.0F; } static void game_print(drawing *dr, const game_state *state, int tilesize) { int w = state->w, h = state->h; int ink = print_mono_colour(dr, 0); int paper = print_mono_colour(dr, 1); int x, y, which, i, j; /* Ick: fake up `ds->tilesize' for macro expansion purposes */ game_drawstate ads, *ds = &ads; game_set_size(dr, ds, NULL, tilesize); ds->w = w; ds->h = h; /* Border. */ print_line_width(dr, TILE_SIZE/12); /* Numbers and +/- for corners. */ draw_sym(dr, ds, -1, -1, POSITIVE, ink); draw_sym(dr, ds, state->w, state->h, NEGATIVE, ink); for (which = POSITIVE, j = 0; j < 2; which = OPPOSITE(which), j++) { for (i = 0; i < w; i++) { draw_num(dr, ds, COLUMN, which, i, paper, ink, state->common->colcount[i*3+which]); } for (i = 0; i < h; i++) { draw_num(dr, ds, ROW, which, i, paper, ink, state->common->rowcount[i*3+which]); } } /* Dominoes. */ for (x = 0; x < w; x++) { for (y = 0; y < h; y++) { i = y*state->w + x; if (state->common->dominoes[i] == i+1 || state->common->dominoes[i] == i+w) { int dx = state->common->dominoes[i] == i+1 ? 2 : 1; int dy = 3 - dx; int xx, yy; int cx = COORD(x), cy = COORD(y); print_line_width(dr, 0); /* Ink the domino */ for (yy = 0; yy < 2; yy++) for (xx = 0; xx < 2; xx++) draw_circle(dr, cx+xx*dx*TILE_SIZE+(1-2*xx)*3*TILE_SIZE/16, cy+yy*dy*TILE_SIZE+(1-2*yy)*3*TILE_SIZE/16, TILE_SIZE/8, ink, ink); draw_rect(dr, cx + TILE_SIZE/16, cy + 3*TILE_SIZE/16, dx*TILE_SIZE - 2*(TILE_SIZE/16), dy*TILE_SIZE - 6*(TILE_SIZE/16), ink); draw_rect(dr, cx + 3*TILE_SIZE/16, cy + TILE_SIZE/16, dx*TILE_SIZE - 6*(TILE_SIZE/16), dy*TILE_SIZE - 2*(TILE_SIZE/16), ink); /* Un-ink the domino interior */ for (yy = 0; yy < 2; yy++) for (xx = 0; xx < 2; xx++) draw_circle(dr, cx+xx*dx*TILE_SIZE+(1-2*xx)*3*TILE_SIZE/16, cy+yy*dy*TILE_SIZE+(1-2*yy)*3*TILE_SIZE/16, 3*TILE_SIZE/32, paper, paper); draw_rect(dr, cx + 3*TILE_SIZE/32, cy + 3*TILE_SIZE/16, dx*TILE_SIZE - 2*(3*TILE_SIZE/32), dy*TILE_SIZE - 6*(TILE_SIZE/16), paper); draw_rect(dr, cx + 3*TILE_SIZE/16, cy + 3*TILE_SIZE/32, dx*TILE_SIZE - 6*(TILE_SIZE/16), dy*TILE_SIZE - 2*(3*TILE_SIZE/32), paper); } } } /* Grid symbols (solution). */ for (x = 0; x < w; x++) { for (y = 0; y < h; y++) { i = y*state->w + x; if ((state->grid[i] != NEUTRAL) || (state->flags[i] & GS_SET)) draw_sym(dr, ds, x, y, state->grid[i], ink); } } } #ifdef COMBINED #define thegame magnets #endif const struct game thegame = { "Magnets", "games.magnets", "magnets", default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, TRUE, solve_game, TRUE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, PREFERRED_TILE_SIZE, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, TRUE, FALSE, game_print_size, game_print, FALSE, /* wants_statusbar */ FALSE, game_timing_state, REQUIRE_RBUTTON, /* flags */ }; #ifdef STANDALONE_SOLVER #include #include const char *quis = NULL; int csv = 0; void usage(FILE *out) { fprintf(out, "usage: %s [-v] [--print] |\n", quis); } void doprint(game_state *state) { char *fmt = game_text_format(state); printf("%s", fmt); sfree(fmt); } static void pnum(int n, int ntot, const char *desc) { printf("%2.1f%% (%d) %s", (double)n*100.0 / (double)ntot, n, desc); } static void start_soak(game_params *p, random_state *rs) { time_t tt_start, tt_now, tt_last; char *aux; game_state *s, *s2; int n = 0, nsolved = 0, nimpossible = 0, ntricky = 0, ret, i; long nn, nn_total = 0, nn_solved = 0, nn_tricky = 0; tt_start = tt_now = time(NULL); if (csv) printf("time, w, h, #generated, #solved, #tricky, #impossible, " "#neutral, #neutral/solved, #neutral/tricky\n"); else printf("Soak-testing a %dx%d grid.\n", p->w, p->h); s = new_state(p->w, p->h); aux = snewn(s->wh+1, char); while (1) { gen_game(s, rs); nn = 0; for (i = 0; i < s->wh; i++) { if (s->grid[i] == NEUTRAL) nn++; } generate_aux(s, aux); memset(s->grid, EMPTY, s->wh * sizeof(int)); s2 = dup_game(s); ret = solve_state(s, DIFFCOUNT); n++; nn_total += nn; if (ret > 0) { nsolved++; nn_solved += nn; if (solve_state(s2, DIFF_EASY) <= 0) { ntricky++; nn_tricky += nn; } } else if (ret < 0) { char *desc = generate_desc(s); solve_from_aux(s, aux); printf("Game considered impossible:\n %dx%d:%s\n", p->w, p->h, desc); sfree(desc); doprint(s); nimpossible++; } free_game(s2); tt_last = time(NULL); if (tt_last > tt_now) { tt_now = tt_last; if (csv) { printf("%d,%d,%d, %d,%d,%d,%d, %ld,%ld,%ld\n", (int)(tt_now - tt_start), p->w, p->h, n, nsolved, ntricky, nimpossible, nn_total, nn_solved, nn_tricky); } else { printf("%d total, %3.1f/s, ", n, (double)n / ((double)tt_now - tt_start)); pnum(nsolved, n, "solved"); printf(", "); pnum(ntricky, n, "tricky"); if (nimpossible > 0) pnum(nimpossible, n, "impossible"); printf("\n"); printf(" overall %3.1f%% neutral (%3.1f%% for solved, %3.1f%% for tricky)\n", (double)(nn_total * 100) / (double)(p->w * p->h * n), (double)(nn_solved * 100) / (double)(p->w * p->h * nsolved), (double)(nn_tricky * 100) / (double)(p->w * p->h * ntricky)); } } } free_game(s); sfree(aux); } int main(int argc, const char *argv[]) { int print = 0, soak = 0, solved = 0, ret; char *id = NULL, *desc, *desc_gen = NULL, *err, *aux = NULL; game_state *s = NULL; game_params *p = NULL; random_state *rs = NULL; time_t seed = time(NULL); setvbuf(stdout, NULL, _IONBF, 0); quis = argv[0]; while (--argc > 0) { char *p = (char*)(*++argv); if (!strcmp(p, "-v") || !strcmp(p, "--verbose")) { verbose = 1; } else if (!strcmp(p, "--csv")) { csv = 1; } else if (!strcmp(p, "-e") || !strcmp(p, "--seed")) { seed = atoi(*++argv); argc--; } else if (!strcmp(p, "-p") || !strcmp(p, "--print")) { print = 1; } else if (!strcmp(p, "-s") || !strcmp(p, "--soak")) { soak = 1; } else if (*p == '-') { fprintf(stderr, "%s: unrecognised option `%s'\n", argv[0], p); usage(stderr); exit(1); } else { id = p; } } rs = random_new((void*)&seed, sizeof(time_t)); if (!id) { fprintf(stderr, "usage: %s [-v] [--soak] | \n", argv[0]); goto done; } desc = strchr(id, ':'); if (desc) *desc++ = '\0'; p = default_params(); decode_params(p, id); err = validate_params(p, 1); if (err) { fprintf(stderr, "%s: %s", argv[0], err); goto done; } if (soak) { if (desc) { fprintf(stderr, "%s: --soak needs parameters, not description.\n", quis); goto done; } start_soak(p, rs); goto done; } if (!desc) desc = desc_gen = new_game_desc(p, rs, &aux, 0); err = validate_desc(p, desc); if (err) { fprintf(stderr, "%s: %s\nDescription: %s\n", quis, err, desc); goto done; } s = new_game(NULL, p, desc); printf("%s:%s (seed %ld)\n", id, desc, (long)seed); if (aux) { /* We just generated this ourself. */ if (verbose || print) { doprint(s); solve_from_aux(s, aux); solved = 1; } } else { doprint(s); verbose = 1; ret = solve_state(s, DIFFCOUNT); if (ret < 0) printf("Puzzle is impossible.\n"); else if (ret == 0) printf("Puzzle is ambiguous.\n"); else printf("Puzzle was solved.\n"); verbose = 0; solved = 1; } if (solved) doprint(s); done: if (desc_gen) sfree(desc_gen); if (p) free_params(p); if (s) free_game(s); if (rs) random_free(rs); if (aux) sfree(aux); return 0; } #endif /* vim: set shiftwidth=4 tabstop=8: */ puzzles-20170606.272beef/loopy.c0000644000175000017500000036714313115373615015215 0ustar simonsimon/* * loopy.c: * * An implementation of the Nikoli game 'Loop the loop'. * (c) Mike Pinna, 2005, 2006 * Substantially rewritten to allowing for more general types of grid. * (c) Lambros Lambrou 2008 * * vim: set shiftwidth=4 :set textwidth=80: */ /* * Possible future solver enhancements: * * - There's an interesting deductive technique which makes use * of topology rather than just graph theory. Each _face_ in * the grid is either inside or outside the loop; you can tell * that two faces are on the same side of the loop if they're * separated by a LINE_NO (or, more generally, by a path * crossing no LINE_UNKNOWNs and an even number of LINE_YESes), * and on the opposite side of the loop if they're separated by * a LINE_YES (or an odd number of LINE_YESes and no * LINE_UNKNOWNs). Oh, and any face separated from the outside * of the grid by a LINE_YES or a LINE_NO is on the inside or * outside respectively. So if you can track this for all * faces, you figure out the state of the line between a pair * once their relative insideness is known. * + The way I envisage this working is simply to keep an edsf * of all _faces_, which indicates whether they're on * opposite sides of the loop from one another. We also * include a special entry in the edsf for the infinite * exterior "face". * + So, the simple way to do this is to just go through the * edges: every time we see an edge in a state other than * LINE_UNKNOWN which separates two faces that aren't in the * same edsf class, we can rectify that by merging the * classes. Then, conversely, an edge in LINE_UNKNOWN state * which separates two faces that _are_ in the same edsf * class can immediately have its state determined. * + But you can go one better, if you're prepared to loop * over all _pairs_ of edges. Suppose we have edges A and B, * which respectively separate faces A1,A2 and B1,B2. * Suppose that A,B are in the same edge-edsf class and that * A1,B1 (wlog) are in the same face-edsf class; then we can * immediately place A2,B2 into the same face-edsf class (as * each other, not as A1 and A2) one way round or the other. * And conversely again, if A1,B1 are in the same face-edsf * class and so are A2,B2, then we can put A,B into the same * face-edsf class. * * Of course, this deduction requires a quadratic-time * loop over all pairs of edges in the grid, so it should * be reserved until there's nothing easier left to be * done. * * - The generalised grid support has made me (SGT) notice a * possible extension to the loop-avoidance code. When you have * a path of connected edges such that no other edges at all * are incident on any vertex in the middle of the path - or, * alternatively, such that any such edges are already known to * be LINE_NO - then you know those edges are either all * LINE_YES or all LINE_NO. Hence you can mentally merge the * entire path into a single long curly edge for the purposes * of loop avoidance, and look directly at whether or not the * extreme endpoints of the path are connected by some other * route. I find this coming up fairly often when I play on the * octagonal grid setting, so it might be worth implementing in * the solver. * * - (Just a speed optimisation.) Consider some todo list queue where every * time we modify something we mark it for consideration by other bits of * the solver, to save iteration over things that have already been done. */ #include #include #include #include #include #include #include #include "puzzles.h" #include "tree234.h" #include "grid.h" #include "loopgen.h" /* Debugging options */ /* #define DEBUG_CACHES #define SHOW_WORKING #define DEBUG_DLINES */ /* ---------------------------------------------------------------------- * Struct, enum and function declarations */ enum { COL_BACKGROUND, COL_FOREGROUND, COL_LINEUNKNOWN, COL_HIGHLIGHT, COL_MISTAKE, COL_SATISFIED, COL_FAINT, NCOLOURS }; struct game_state { grid *game_grid; /* ref-counted (internally) */ /* Put -1 in a face that doesn't get a clue */ signed char *clues; /* Array of line states, to store whether each line is * YES, NO or UNKNOWN */ char *lines; unsigned char *line_errors; int exactly_one_loop; int solved; int cheated; /* Used in game_text_format(), so that it knows what type of * grid it's trying to render as ASCII text. */ int grid_type; }; enum solver_status { SOLVER_SOLVED, /* This is the only solution the solver could find */ SOLVER_MISTAKE, /* This is definitely not a solution */ SOLVER_AMBIGUOUS, /* This _might_ be an ambiguous solution */ SOLVER_INCOMPLETE /* This may be a partial solution */ }; /* ------ Solver state ------ */ typedef struct solver_state { game_state *state; enum solver_status solver_status; /* NB looplen is the number of dots that are joined together at a point, ie a * looplen of 1 means there are no lines to a particular dot */ int *looplen; /* Difficulty level of solver. Used by solver functions that want to * vary their behaviour depending on the requested difficulty level. */ int diff; /* caches */ char *dot_yes_count; char *dot_no_count; char *face_yes_count; char *face_no_count; char *dot_solved, *face_solved; int *dotdsf; /* Information for Normal level deductions: * For each dline, store a bitmask for whether we know: * (bit 0) at least one is YES * (bit 1) at most one is YES */ char *dlines; /* Hard level information */ int *linedsf; } solver_state; /* * Difficulty levels. I do some macro ickery here to ensure that my * enum and the various forms of my name list always match up. */ #define DIFFLIST(A) \ A(EASY,Easy,e) \ A(NORMAL,Normal,n) \ A(TRICKY,Tricky,t) \ A(HARD,Hard,h) #define ENUM(upper,title,lower) DIFF_ ## upper, #define TITLE(upper,title,lower) #title, #define ENCODE(upper,title,lower) #lower #define CONFIG(upper,title,lower) ":" #title enum { DIFFLIST(ENUM) DIFF_MAX }; static char const *const diffnames[] = { DIFFLIST(TITLE) }; static char const diffchars[] = DIFFLIST(ENCODE); #define DIFFCONFIG DIFFLIST(CONFIG) /* * Solver routines, sorted roughly in order of computational cost. * The solver will run the faster deductions first, and slower deductions are * only invoked when the faster deductions are unable to make progress. * Each function is associated with a difficulty level, so that the generated * puzzles are solvable by applying only the functions with the chosen * difficulty level or lower. */ #define SOLVERLIST(A) \ A(trivial_deductions, DIFF_EASY) \ A(dline_deductions, DIFF_NORMAL) \ A(linedsf_deductions, DIFF_HARD) \ A(loop_deductions, DIFF_EASY) #define SOLVER_FN_DECL(fn,diff) static int fn(solver_state *); #define SOLVER_FN(fn,diff) &fn, #define SOLVER_DIFF(fn,diff) diff, SOLVERLIST(SOLVER_FN_DECL) static int (*(solver_fns[]))(solver_state *) = { SOLVERLIST(SOLVER_FN) }; static int const solver_diffs[] = { SOLVERLIST(SOLVER_DIFF) }; static const int NUM_SOLVERS = sizeof(solver_diffs)/sizeof(*solver_diffs); struct game_params { int w, h; int diff; int type; }; /* line_drawstate is the same as line_state, but with the extra ERROR * possibility. The drawing code copies line_state to line_drawstate, * except in the case that the line is an error. */ enum line_state { LINE_YES, LINE_UNKNOWN, LINE_NO }; enum line_drawstate { DS_LINE_YES, DS_LINE_UNKNOWN, DS_LINE_NO, DS_LINE_ERROR }; #define OPP(line_state) \ (2 - line_state) struct game_drawstate { int started; int tilesize; int flashing; int *textx, *texty; char *lines; char *clue_error; char *clue_satisfied; }; static char *validate_desc(const game_params *params, const char *desc); static int dot_order(const game_state* state, int i, char line_type); static int face_order(const game_state* state, int i, char line_type); static solver_state *solve_game_rec(const solver_state *sstate); #ifdef DEBUG_CACHES static void check_caches(const solver_state* sstate); #else #define check_caches(s) #endif /* * Grid type config options available in Loopy. * * Annoyingly, we have to use an enum here which doesn't match up * exactly to the grid-type enum in grid.h. Values in params->types * are given by names such as LOOPY_GRID_SQUARE, which shouldn't be * confused with GRID_SQUARE which is the value you pass to grid_new() * and friends. So beware! * * (This is partly for historical reasons - Loopy's version of the * enum is encoded in game parameter strings, so we keep it for * backwards compatibility. But also, we need to store additional data * here alongside each enum value, such as names for the presets menu, * which isn't stored in grid.h; so we have to have our own list macro * here anyway, and C doesn't make it easy to enforce that that lines * up exactly with grid.h.) * * Do not add values to this list _except_ at the end, or old game ids * will stop working! */ #define GRIDLIST(A) \ A("Squares",SQUARE,3,3) \ A("Triangular",TRIANGULAR,3,3) \ A("Honeycomb",HONEYCOMB,3,3) \ A("Snub-Square",SNUBSQUARE,3,3) \ A("Cairo",CAIRO,3,4) \ A("Great-Hexagonal",GREATHEXAGONAL,3,3) \ A("Octagonal",OCTAGONAL,3,3) \ A("Kites",KITE,3,3) \ A("Floret",FLORET,1,2) \ A("Dodecagonal",DODECAGONAL,2,2) \ A("Great-Dodecagonal",GREATDODECAGONAL,2,2) \ A("Penrose (kite/dart)",PENROSE_P2,3,3) \ A("Penrose (rhombs)",PENROSE_P3,3,3) \ A("Great-Great-Dodecagonal",GREATGREATDODECAGONAL,2,2) \ /* end of list */ #define GRID_NAME(title,type,amin,omin) title, #define GRID_CONFIG(title,type,amin,omin) ":" title #define GRID_LOOPYTYPE(title,type,amin,omin) LOOPY_GRID_ ## type, #define GRID_GRIDTYPE(title,type,amin,omin) GRID_ ## type, #define GRID_SIZES(title,type,amin,omin) \ {amin, omin, \ "Width and height for this grid type must both be at least " #amin, \ "At least one of width and height for this grid type must be at least " #omin,}, enum { GRIDLIST(GRID_LOOPYTYPE) }; static char const *const gridnames[] = { GRIDLIST(GRID_NAME) }; #define GRID_CONFIGS GRIDLIST(GRID_CONFIG) static grid_type grid_types[] = { GRIDLIST(GRID_GRIDTYPE) }; #define NUM_GRID_TYPES (sizeof(grid_types) / sizeof(grid_types[0])) static const struct { int amin, omin; char *aerr, *oerr; } grid_size_limits[] = { GRIDLIST(GRID_SIZES) }; /* Generates a (dynamically allocated) new grid, according to the * type and size requested in params. Does nothing if the grid is already * generated. */ static grid *loopy_generate_grid(const game_params *params, const char *grid_desc) { return grid_new(grid_types[params->type], params->w, params->h, grid_desc); } /* ---------------------------------------------------------------------- * Preprocessor magic */ /* General constants */ #define PREFERRED_TILE_SIZE 32 #define BORDER(tilesize) ((tilesize) / 2) #define FLASH_TIME 0.5F #define BIT_SET(field, bit) ((field) & (1<<(bit))) #define SET_BIT(field, bit) (BIT_SET(field, bit) ? FALSE : \ ((field) |= (1<<(bit)), TRUE)) #define CLEAR_BIT(field, bit) (BIT_SET(field, bit) ? \ ((field) &= ~(1<<(bit)), TRUE) : FALSE) #define CLUE2CHAR(c) \ ((c < 0) ? ' ' : c < 10 ? c + '0' : c - 10 + 'A') /* ---------------------------------------------------------------------- * General struct manipulation and other straightforward code */ static game_state *dup_game(const game_state *state) { game_state *ret = snew(game_state); ret->game_grid = state->game_grid; ret->game_grid->refcount++; ret->solved = state->solved; ret->cheated = state->cheated; ret->clues = snewn(state->game_grid->num_faces, signed char); memcpy(ret->clues, state->clues, state->game_grid->num_faces); ret->lines = snewn(state->game_grid->num_edges, char); memcpy(ret->lines, state->lines, state->game_grid->num_edges); ret->line_errors = snewn(state->game_grid->num_edges, unsigned char); memcpy(ret->line_errors, state->line_errors, state->game_grid->num_edges); ret->exactly_one_loop = state->exactly_one_loop; ret->grid_type = state->grid_type; return ret; } static void free_game(game_state *state) { if (state) { grid_free(state->game_grid); sfree(state->clues); sfree(state->lines); sfree(state->line_errors); sfree(state); } } static solver_state *new_solver_state(const game_state *state, int diff) { int i; int num_dots = state->game_grid->num_dots; int num_faces = state->game_grid->num_faces; int num_edges = state->game_grid->num_edges; solver_state *ret = snew(solver_state); ret->state = dup_game(state); ret->solver_status = SOLVER_INCOMPLETE; ret->diff = diff; ret->dotdsf = snew_dsf(num_dots); ret->looplen = snewn(num_dots, int); for (i = 0; i < num_dots; i++) { ret->looplen[i] = 1; } ret->dot_solved = snewn(num_dots, char); ret->face_solved = snewn(num_faces, char); memset(ret->dot_solved, FALSE, num_dots); memset(ret->face_solved, FALSE, num_faces); ret->dot_yes_count = snewn(num_dots, char); memset(ret->dot_yes_count, 0, num_dots); ret->dot_no_count = snewn(num_dots, char); memset(ret->dot_no_count, 0, num_dots); ret->face_yes_count = snewn(num_faces, char); memset(ret->face_yes_count, 0, num_faces); ret->face_no_count = snewn(num_faces, char); memset(ret->face_no_count, 0, num_faces); if (diff < DIFF_NORMAL) { ret->dlines = NULL; } else { ret->dlines = snewn(2*num_edges, char); memset(ret->dlines, 0, 2*num_edges); } if (diff < DIFF_HARD) { ret->linedsf = NULL; } else { ret->linedsf = snew_dsf(state->game_grid->num_edges); } return ret; } static void free_solver_state(solver_state *sstate) { if (sstate) { free_game(sstate->state); sfree(sstate->dotdsf); sfree(sstate->looplen); sfree(sstate->dot_solved); sfree(sstate->face_solved); sfree(sstate->dot_yes_count); sfree(sstate->dot_no_count); sfree(sstate->face_yes_count); sfree(sstate->face_no_count); /* OK, because sfree(NULL) is a no-op */ sfree(sstate->dlines); sfree(sstate->linedsf); sfree(sstate); } } static solver_state *dup_solver_state(const solver_state *sstate) { game_state *state = sstate->state; int num_dots = state->game_grid->num_dots; int num_faces = state->game_grid->num_faces; int num_edges = state->game_grid->num_edges; solver_state *ret = snew(solver_state); ret->state = state = dup_game(sstate->state); ret->solver_status = sstate->solver_status; ret->diff = sstate->diff; ret->dotdsf = snewn(num_dots, int); ret->looplen = snewn(num_dots, int); memcpy(ret->dotdsf, sstate->dotdsf, num_dots * sizeof(int)); memcpy(ret->looplen, sstate->looplen, num_dots * sizeof(int)); ret->dot_solved = snewn(num_dots, char); ret->face_solved = snewn(num_faces, char); memcpy(ret->dot_solved, sstate->dot_solved, num_dots); memcpy(ret->face_solved, sstate->face_solved, num_faces); ret->dot_yes_count = snewn(num_dots, char); memcpy(ret->dot_yes_count, sstate->dot_yes_count, num_dots); ret->dot_no_count = snewn(num_dots, char); memcpy(ret->dot_no_count, sstate->dot_no_count, num_dots); ret->face_yes_count = snewn(num_faces, char); memcpy(ret->face_yes_count, sstate->face_yes_count, num_faces); ret->face_no_count = snewn(num_faces, char); memcpy(ret->face_no_count, sstate->face_no_count, num_faces); if (sstate->dlines) { ret->dlines = snewn(2*num_edges, char); memcpy(ret->dlines, sstate->dlines, 2*num_edges); } else { ret->dlines = NULL; } if (sstate->linedsf) { ret->linedsf = snewn(num_edges, int); memcpy(ret->linedsf, sstate->linedsf, num_edges * sizeof(int)); } else { ret->linedsf = NULL; } return ret; } static game_params *default_params(void) { game_params *ret = snew(game_params); #ifdef SLOW_SYSTEM ret->h = 7; ret->w = 7; #else ret->h = 10; ret->w = 10; #endif ret->diff = DIFF_EASY; ret->type = 0; return ret; } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } static const game_params loopy_presets_top[] = { #ifdef SMALL_SCREEN { 7, 7, DIFF_EASY, LOOPY_GRID_SQUARE }, { 7, 7, DIFF_NORMAL, LOOPY_GRID_SQUARE }, { 7, 7, DIFF_HARD, LOOPY_GRID_SQUARE }, { 7, 7, DIFF_HARD, LOOPY_GRID_TRIANGULAR }, { 5, 5, DIFF_HARD, LOOPY_GRID_SNUBSQUARE }, { 7, 7, DIFF_HARD, LOOPY_GRID_CAIRO }, { 5, 5, DIFF_HARD, LOOPY_GRID_KITE }, { 6, 6, DIFF_HARD, LOOPY_GRID_PENROSE_P2 }, { 6, 6, DIFF_HARD, LOOPY_GRID_PENROSE_P3 }, #else { 7, 7, DIFF_EASY, LOOPY_GRID_SQUARE }, { 10, 10, DIFF_EASY, LOOPY_GRID_SQUARE }, { 7, 7, DIFF_NORMAL, LOOPY_GRID_SQUARE }, { 10, 10, DIFF_NORMAL, LOOPY_GRID_SQUARE }, { 7, 7, DIFF_HARD, LOOPY_GRID_SQUARE }, { 10, 10, DIFF_HARD, LOOPY_GRID_SQUARE }, { 12, 10, DIFF_HARD, LOOPY_GRID_TRIANGULAR }, { 7, 7, DIFF_HARD, LOOPY_GRID_SNUBSQUARE }, { 9, 9, DIFF_HARD, LOOPY_GRID_CAIRO }, { 5, 5, DIFF_HARD, LOOPY_GRID_KITE }, { 10, 10, DIFF_HARD, LOOPY_GRID_PENROSE_P2 }, { 10, 10, DIFF_HARD, LOOPY_GRID_PENROSE_P3 }, #endif }; static const game_params loopy_presets_more[] = { #ifdef SMALL_SCREEN { 7, 7, DIFF_HARD, LOOPY_GRID_HONEYCOMB }, { 5, 4, DIFF_HARD, LOOPY_GRID_GREATHEXAGONAL }, { 5, 5, DIFF_HARD, LOOPY_GRID_OCTAGONAL }, { 3, 3, DIFF_HARD, LOOPY_GRID_FLORET }, { 3, 3, DIFF_HARD, LOOPY_GRID_DODECAGONAL }, { 3, 3, DIFF_HARD, LOOPY_GRID_GREATDODECAGONAL }, { 3, 2, DIFF_HARD, LOOPY_GRID_GREATGREATDODECAGONAL }, #else { 10, 10, DIFF_HARD, LOOPY_GRID_HONEYCOMB }, { 5, 4, DIFF_HARD, LOOPY_GRID_GREATHEXAGONAL }, { 7, 7, DIFF_HARD, LOOPY_GRID_OCTAGONAL }, { 5, 5, DIFF_HARD, LOOPY_GRID_FLORET }, { 5, 4, DIFF_HARD, LOOPY_GRID_DODECAGONAL }, { 5, 4, DIFF_HARD, LOOPY_GRID_GREATDODECAGONAL }, { 5, 3, DIFF_HARD, LOOPY_GRID_GREATGREATDODECAGONAL }, #endif }; static void preset_menu_add_preset_with_title(struct preset_menu *menu, const game_params *params) { char buf[80]; game_params *dup_params; sprintf(buf, "%dx%d %s - %s", params->h, params->w, gridnames[params->type], diffnames[params->diff]); dup_params = snew(game_params); *dup_params = *params; preset_menu_add_preset(menu, dupstr(buf), dup_params); } static struct preset_menu *game_preset_menu(void) { struct preset_menu *top, *more; int i; top = preset_menu_new(); for (i = 0; i < lenof(loopy_presets_top); i++) preset_menu_add_preset_with_title(top, &loopy_presets_top[i]); more = preset_menu_add_submenu(top, dupstr("More...")); for (i = 0; i < lenof(loopy_presets_more); i++) preset_menu_add_preset_with_title(more, &loopy_presets_more[i]); return top; } static void free_params(game_params *params) { sfree(params); } static void decode_params(game_params *params, char const *string) { params->h = params->w = atoi(string); params->diff = DIFF_EASY; while (*string && isdigit((unsigned char)*string)) string++; if (*string == 'x') { string++; params->h = atoi(string); while (*string && isdigit((unsigned char)*string)) string++; } if (*string == 't') { string++; params->type = atoi(string); while (*string && isdigit((unsigned char)*string)) string++; } if (*string == 'd') { int i; string++; for (i = 0; i < DIFF_MAX; i++) if (*string == diffchars[i]) params->diff = i; if (*string) string++; } } static char *encode_params(const game_params *params, int full) { char str[80]; sprintf(str, "%dx%dt%d", params->w, params->h, params->type); if (full) sprintf(str + strlen(str), "d%c", diffchars[params->diff]); return dupstr(str); } static config_item *game_configure(const game_params *params) { config_item *ret; char buf[80]; ret = snewn(5, config_item); ret[0].name = "Width"; ret[0].type = C_STRING; sprintf(buf, "%d", params->w); ret[0].sval = dupstr(buf); ret[0].ival = 0; ret[1].name = "Height"; ret[1].type = C_STRING; sprintf(buf, "%d", params->h); ret[1].sval = dupstr(buf); ret[1].ival = 0; ret[2].name = "Grid type"; ret[2].type = C_CHOICES; ret[2].sval = GRID_CONFIGS; ret[2].ival = params->type; ret[3].name = "Difficulty"; ret[3].type = C_CHOICES; ret[3].sval = DIFFCONFIG; ret[3].ival = params->diff; ret[4].name = NULL; ret[4].type = C_END; ret[4].sval = NULL; ret[4].ival = 0; return ret; } static game_params *custom_params(const config_item *cfg) { game_params *ret = snew(game_params); ret->w = atoi(cfg[0].sval); ret->h = atoi(cfg[1].sval); ret->type = cfg[2].ival; ret->diff = cfg[3].ival; return ret; } static char *validate_params(const game_params *params, int full) { if (params->type < 0 || params->type >= NUM_GRID_TYPES) return "Illegal grid type"; if (params->w < grid_size_limits[params->type].amin || params->h < grid_size_limits[params->type].amin) return grid_size_limits[params->type].aerr; if (params->w < grid_size_limits[params->type].omin && params->h < grid_size_limits[params->type].omin) return grid_size_limits[params->type].oerr; /* * This shouldn't be able to happen at all, since decode_params * and custom_params will never generate anything that isn't * within range. */ assert(params->diff < DIFF_MAX); return NULL; } /* Returns a newly allocated string describing the current puzzle */ static char *state_to_text(const game_state *state) { grid *g = state->game_grid; char *retval; int num_faces = g->num_faces; char *description = snewn(num_faces + 1, char); char *dp = description; int empty_count = 0; int i; for (i = 0; i < num_faces; i++) { if (state->clues[i] < 0) { if (empty_count > 25) { dp += sprintf(dp, "%c", (int)(empty_count + 'a' - 1)); empty_count = 0; } empty_count++; } else { if (empty_count) { dp += sprintf(dp, "%c", (int)(empty_count + 'a' - 1)); empty_count = 0; } dp += sprintf(dp, "%c", (int)CLUE2CHAR(state->clues[i])); } } if (empty_count) dp += sprintf(dp, "%c", (int)(empty_count + 'a' - 1)); retval = dupstr(description); sfree(description); return retval; } #define GRID_DESC_SEP '_' /* Splits up a (optional) grid_desc from the game desc. Returns the * grid_desc (which needs freeing) and updates the desc pointer to * start of real desc, or returns NULL if no desc. */ static char *extract_grid_desc(const char **desc) { char *sep = strchr(*desc, GRID_DESC_SEP), *gd; int gd_len; if (!sep) return NULL; gd_len = sep - (*desc); gd = snewn(gd_len+1, char); memcpy(gd, *desc, gd_len); gd[gd_len] = '\0'; *desc = sep+1; return gd; } /* We require that the params pass the test in validate_params and that the * description fills the entire game area */ static char *validate_desc(const game_params *params, const char *desc) { int count = 0; grid *g; char *grid_desc, *ret; /* It's pretty inefficient to do this just for validation. All we need to * know is the precise number of faces. */ grid_desc = extract_grid_desc(&desc); ret = grid_validate_desc(grid_types[params->type], params->w, params->h, grid_desc); if (ret) return ret; g = loopy_generate_grid(params, grid_desc); if (grid_desc) sfree(grid_desc); for (; *desc; ++desc) { if ((*desc >= '0' && *desc <= '9') || (*desc >= 'A' && *desc <= 'Z')) { count++; continue; } if (*desc >= 'a') { count += *desc - 'a' + 1; continue; } return "Unknown character in description"; } if (count < g->num_faces) return "Description too short for board size"; if (count > g->num_faces) return "Description too long for board size"; grid_free(g); return NULL; } /* Sums the lengths of the numbers in range [0,n) */ /* See equivalent function in solo.c for justification of this. */ static int len_0_to_n(int n) { int len = 1; /* Counting 0 as a bit of a special case */ int i; for (i = 1; i < n; i *= 10) { len += max(n - i, 0); } return len; } static char *encode_solve_move(const game_state *state) { int len; char *ret, *p; int i; int num_edges = state->game_grid->num_edges; /* This is going to return a string representing the moves needed to set * every line in a grid to be the same as the ones in 'state'. The exact * length of this string is predictable. */ len = 1; /* Count the 'S' prefix */ /* Numbers in all lines */ len += len_0_to_n(num_edges); /* For each line we also have a letter */ len += num_edges; ret = snewn(len + 1, char); p = ret; p += sprintf(p, "S"); for (i = 0; i < num_edges; i++) { switch (state->lines[i]) { case LINE_YES: p += sprintf(p, "%dy", i); break; case LINE_NO: p += sprintf(p, "%dn", i); break; } } /* No point in doing sums like that if they're going to be wrong */ assert(strlen(ret) <= (size_t)len); return ret; } static game_ui *new_ui(const game_state *state) { return NULL; } static void free_ui(game_ui *ui) { } static char *encode_ui(const game_ui *ui) { return NULL; } static void decode_ui(game_ui *ui, const char *encoding) { } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { } static void game_compute_size(const game_params *params, int tilesize, int *x, int *y) { int grid_width, grid_height, rendered_width, rendered_height; int g_tilesize; grid_compute_size(grid_types[params->type], params->w, params->h, &g_tilesize, &grid_width, &grid_height); /* multiply first to minimise rounding error on integer division */ rendered_width = grid_width * tilesize / g_tilesize; rendered_height = grid_height * tilesize / g_tilesize; *x = rendered_width + 2 * BORDER(tilesize) + 1; *y = rendered_height + 2 * BORDER(tilesize) + 1; } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { ds->tilesize = tilesize; } static float *game_colours(frontend *fe, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float); frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]); ret[COL_FOREGROUND * 3 + 0] = 0.0F; ret[COL_FOREGROUND * 3 + 1] = 0.0F; ret[COL_FOREGROUND * 3 + 2] = 0.0F; /* * We want COL_LINEUNKNOWN to be a yellow which is a bit darker * than the background. (I previously set it to 0.8,0.8,0, but * found that this went badly with the 0.8,0.8,0.8 favoured as a * background by the Java frontend.) */ ret[COL_LINEUNKNOWN * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] * 0.9F; ret[COL_LINEUNKNOWN * 3 + 1] = ret[COL_BACKGROUND * 3 + 1] * 0.9F; ret[COL_LINEUNKNOWN * 3 + 2] = 0.0F; ret[COL_HIGHLIGHT * 3 + 0] = 1.0F; ret[COL_HIGHLIGHT * 3 + 1] = 1.0F; ret[COL_HIGHLIGHT * 3 + 2] = 1.0F; ret[COL_MISTAKE * 3 + 0] = 1.0F; ret[COL_MISTAKE * 3 + 1] = 0.0F; ret[COL_MISTAKE * 3 + 2] = 0.0F; ret[COL_SATISFIED * 3 + 0] = 0.0F; ret[COL_SATISFIED * 3 + 1] = 0.0F; ret[COL_SATISFIED * 3 + 2] = 0.0F; /* We want the faint lines to be a bit darker than the background. * Except if the background is pretty dark already; then it ought to be a * bit lighter. Oy vey. */ ret[COL_FAINT * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] * 0.9F; ret[COL_FAINT * 3 + 1] = ret[COL_BACKGROUND * 3 + 1] * 0.9F; ret[COL_FAINT * 3 + 2] = ret[COL_BACKGROUND * 3 + 2] * 0.9F; *ncolours = NCOLOURS; return ret; } static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { struct game_drawstate *ds = snew(struct game_drawstate); int num_faces = state->game_grid->num_faces; int num_edges = state->game_grid->num_edges; int i; ds->tilesize = 0; ds->started = 0; ds->lines = snewn(num_edges, char); ds->clue_error = snewn(num_faces, char); ds->clue_satisfied = snewn(num_faces, char); ds->textx = snewn(num_faces, int); ds->texty = snewn(num_faces, int); ds->flashing = 0; memset(ds->lines, LINE_UNKNOWN, num_edges); memset(ds->clue_error, 0, num_faces); memset(ds->clue_satisfied, 0, num_faces); for (i = 0; i < num_faces; i++) ds->textx[i] = ds->texty[i] = -1; return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { sfree(ds->textx); sfree(ds->texty); sfree(ds->clue_error); sfree(ds->clue_satisfied); sfree(ds->lines); sfree(ds); } static int game_timing_state(const game_state *state, game_ui *ui) { return TRUE; } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return 0.0F; } static int game_can_format_as_text_now(const game_params *params) { if (params->type != 0) return FALSE; return TRUE; } static char *game_text_format(const game_state *state) { int w, h, W, H; int x, y, i; int cell_size; char *ret; grid *g = state->game_grid; grid_face *f; assert(state->grid_type == 0); /* Work out the basic size unit */ f = g->faces; /* first face */ assert(f->order == 4); /* The dots are ordered clockwise, so the two opposite * corners are guaranteed to span the square */ cell_size = abs(f->dots[0]->x - f->dots[2]->x); w = (g->highest_x - g->lowest_x) / cell_size; h = (g->highest_y - g->lowest_y) / cell_size; /* Create a blank "canvas" to "draw" on */ W = 2 * w + 2; H = 2 * h + 1; ret = snewn(W * H + 1, char); for (y = 0; y < H; y++) { for (x = 0; x < W-1; x++) { ret[y*W + x] = ' '; } ret[y*W + W-1] = '\n'; } ret[H*W] = '\0'; /* Fill in edge info */ for (i = 0; i < g->num_edges; i++) { grid_edge *e = g->edges + i; /* Cell coordinates, from (0,0) to (w-1,h-1) */ int x1 = (e->dot1->x - g->lowest_x) / cell_size; int x2 = (e->dot2->x - g->lowest_x) / cell_size; int y1 = (e->dot1->y - g->lowest_y) / cell_size; int y2 = (e->dot2->y - g->lowest_y) / cell_size; /* Midpoint, in canvas coordinates (canvas coordinates are just twice * cell coordinates) */ x = x1 + x2; y = y1 + y2; switch (state->lines[i]) { case LINE_YES: ret[y*W + x] = (y1 == y2) ? '-' : '|'; break; case LINE_NO: ret[y*W + x] = 'x'; break; case LINE_UNKNOWN: break; /* already a space */ default: assert(!"Illegal line state"); } } /* Fill in clues */ for (i = 0; i < g->num_faces; i++) { int x1, x2, y1, y2; f = g->faces + i; assert(f->order == 4); /* Cell coordinates, from (0,0) to (w-1,h-1) */ x1 = (f->dots[0]->x - g->lowest_x) / cell_size; x2 = (f->dots[2]->x - g->lowest_x) / cell_size; y1 = (f->dots[0]->y - g->lowest_y) / cell_size; y2 = (f->dots[2]->y - g->lowest_y) / cell_size; /* Midpoint, in canvas coordinates */ x = x1 + x2; y = y1 + y2; ret[y*W + x] = CLUE2CHAR(state->clues[i]); } return ret; } /* ---------------------------------------------------------------------- * Debug code */ #ifdef DEBUG_CACHES static void check_caches(const solver_state* sstate) { int i; const game_state *state = sstate->state; const grid *g = state->game_grid; for (i = 0; i < g->num_dots; i++) { assert(dot_order(state, i, LINE_YES) == sstate->dot_yes_count[i]); assert(dot_order(state, i, LINE_NO) == sstate->dot_no_count[i]); } for (i = 0; i < g->num_faces; i++) { assert(face_order(state, i, LINE_YES) == sstate->face_yes_count[i]); assert(face_order(state, i, LINE_NO) == sstate->face_no_count[i]); } } #if 0 #define check_caches(s) \ do { \ fprintf(stderr, "check_caches at line %d\n", __LINE__); \ check_caches(s); \ } while (0) #endif #endif /* DEBUG_CACHES */ /* ---------------------------------------------------------------------- * Solver utility functions */ /* Sets the line (with index i) to the new state 'line_new', and updates * the cached counts of any affected faces and dots. * Returns TRUE if this actually changed the line's state. */ static int solver_set_line(solver_state *sstate, int i, enum line_state line_new #ifdef SHOW_WORKING , const char *reason #endif ) { game_state *state = sstate->state; grid *g; grid_edge *e; assert(line_new != LINE_UNKNOWN); check_caches(sstate); if (state->lines[i] == line_new) { return FALSE; /* nothing changed */ } state->lines[i] = line_new; #ifdef SHOW_WORKING fprintf(stderr, "solver: set line [%d] to %s (%s)\n", i, line_new == LINE_YES ? "YES" : "NO", reason); #endif g = state->game_grid; e = g->edges + i; /* Update the cache for both dots and both faces affected by this. */ if (line_new == LINE_YES) { sstate->dot_yes_count[e->dot1 - g->dots]++; sstate->dot_yes_count[e->dot2 - g->dots]++; if (e->face1) { sstate->face_yes_count[e->face1 - g->faces]++; } if (e->face2) { sstate->face_yes_count[e->face2 - g->faces]++; } } else { sstate->dot_no_count[e->dot1 - g->dots]++; sstate->dot_no_count[e->dot2 - g->dots]++; if (e->face1) { sstate->face_no_count[e->face1 - g->faces]++; } if (e->face2) { sstate->face_no_count[e->face2 - g->faces]++; } } check_caches(sstate); return TRUE; } #ifdef SHOW_WORKING #define solver_set_line(a, b, c) \ solver_set_line(a, b, c, __FUNCTION__) #endif /* * Merge two dots due to the existence of an edge between them. * Updates the dsf tracking equivalence classes, and keeps track of * the length of path each dot is currently a part of. * Returns TRUE if the dots were already linked, ie if they are part of a * closed loop, and false otherwise. */ static int merge_dots(solver_state *sstate, int edge_index) { int i, j, len; grid *g = sstate->state->game_grid; grid_edge *e = g->edges + edge_index; i = e->dot1 - g->dots; j = e->dot2 - g->dots; i = dsf_canonify(sstate->dotdsf, i); j = dsf_canonify(sstate->dotdsf, j); if (i == j) { return TRUE; } else { len = sstate->looplen[i] + sstate->looplen[j]; dsf_merge(sstate->dotdsf, i, j); i = dsf_canonify(sstate->dotdsf, i); sstate->looplen[i] = len; return FALSE; } } /* Merge two lines because the solver has deduced that they must be either * identical or opposite. Returns TRUE if this is new information, otherwise * FALSE. */ static int merge_lines(solver_state *sstate, int i, int j, int inverse #ifdef SHOW_WORKING , const char *reason #endif ) { int inv_tmp; assert(i < sstate->state->game_grid->num_edges); assert(j < sstate->state->game_grid->num_edges); i = edsf_canonify(sstate->linedsf, i, &inv_tmp); inverse ^= inv_tmp; j = edsf_canonify(sstate->linedsf, j, &inv_tmp); inverse ^= inv_tmp; edsf_merge(sstate->linedsf, i, j, inverse); #ifdef SHOW_WORKING if (i != j) { fprintf(stderr, "%s [%d] [%d] %s(%s)\n", __FUNCTION__, i, j, inverse ? "inverse " : "", reason); } #endif return (i != j); } #ifdef SHOW_WORKING #define merge_lines(a, b, c, d) \ merge_lines(a, b, c, d, __FUNCTION__) #endif /* Count the number of lines of a particular type currently going into the * given dot. */ static int dot_order(const game_state* state, int dot, char line_type) { int n = 0; grid *g = state->game_grid; grid_dot *d = g->dots + dot; int i; for (i = 0; i < d->order; i++) { grid_edge *e = d->edges[i]; if (state->lines[e - g->edges] == line_type) ++n; } return n; } /* Count the number of lines of a particular type currently surrounding the * given face */ static int face_order(const game_state* state, int face, char line_type) { int n = 0; grid *g = state->game_grid; grid_face *f = g->faces + face; int i; for (i = 0; i < f->order; i++) { grid_edge *e = f->edges[i]; if (state->lines[e - g->edges] == line_type) ++n; } return n; } /* Set all lines bordering a dot of type old_type to type new_type * Return value tells caller whether this function actually did anything */ static int dot_setall(solver_state *sstate, int dot, char old_type, char new_type) { int retval = FALSE, r; game_state *state = sstate->state; grid *g; grid_dot *d; int i; if (old_type == new_type) return FALSE; g = state->game_grid; d = g->dots + dot; for (i = 0; i < d->order; i++) { int line_index = d->edges[i] - g->edges; if (state->lines[line_index] == old_type) { r = solver_set_line(sstate, line_index, new_type); assert(r == TRUE); retval = TRUE; } } return retval; } /* Set all lines bordering a face of type old_type to type new_type */ static int face_setall(solver_state *sstate, int face, char old_type, char new_type) { int retval = FALSE, r; game_state *state = sstate->state; grid *g; grid_face *f; int i; if (old_type == new_type) return FALSE; g = state->game_grid; f = g->faces + face; for (i = 0; i < f->order; i++) { int line_index = f->edges[i] - g->edges; if (state->lines[line_index] == old_type) { r = solver_set_line(sstate, line_index, new_type); assert(r == TRUE); retval = TRUE; } } return retval; } /* ---------------------------------------------------------------------- * Loop generation and clue removal */ static void add_full_clues(game_state *state, random_state *rs) { signed char *clues = state->clues; grid *g = state->game_grid; char *board = snewn(g->num_faces, char); int i; generate_loop(g, board, rs, NULL, NULL); /* Fill out all the clues by initialising to 0, then iterating over * all edges and incrementing each clue as we find edges that border * between BLACK/WHITE faces. While we're at it, we verify that the * algorithm does work, and there aren't any GREY faces still there. */ memset(clues, 0, g->num_faces); for (i = 0; i < g->num_edges; i++) { grid_edge *e = g->edges + i; grid_face *f1 = e->face1; grid_face *f2 = e->face2; enum face_colour c1 = FACE_COLOUR(f1); enum face_colour c2 = FACE_COLOUR(f2); assert(c1 != FACE_GREY); assert(c2 != FACE_GREY); if (c1 != c2) { if (f1) clues[f1 - g->faces]++; if (f2) clues[f2 - g->faces]++; } } sfree(board); } static int game_has_unique_soln(const game_state *state, int diff) { int ret; solver_state *sstate_new; solver_state *sstate = new_solver_state((game_state *)state, diff); sstate_new = solve_game_rec(sstate); assert(sstate_new->solver_status != SOLVER_MISTAKE); ret = (sstate_new->solver_status == SOLVER_SOLVED); free_solver_state(sstate_new); free_solver_state(sstate); return ret; } /* Remove clues one at a time at random. */ static game_state *remove_clues(game_state *state, random_state *rs, int diff) { int *face_list; int num_faces = state->game_grid->num_faces; game_state *ret = dup_game(state), *saved_ret; int n; /* We need to remove some clues. We'll do this by forming a list of all * available clues, shuffling it, then going along one at a * time clearing each clue in turn for which doing so doesn't render the * board unsolvable. */ face_list = snewn(num_faces, int); for (n = 0; n < num_faces; ++n) { face_list[n] = n; } shuffle(face_list, num_faces, sizeof(int), rs); for (n = 0; n < num_faces; ++n) { saved_ret = dup_game(ret); ret->clues[face_list[n]] = -1; if (game_has_unique_soln(ret, diff)) { free_game(saved_ret); } else { free_game(ret); ret = saved_ret; } } sfree(face_list); return ret; } static char *new_game_desc(const game_params *params, random_state *rs, char **aux, int interactive) { /* solution and description both use run-length encoding in obvious ways */ char *retval, *game_desc, *grid_desc; grid *g; game_state *state = snew(game_state); game_state *state_new; grid_desc = grid_new_desc(grid_types[params->type], params->w, params->h, rs); state->game_grid = g = loopy_generate_grid(params, grid_desc); state->clues = snewn(g->num_faces, signed char); state->lines = snewn(g->num_edges, char); state->line_errors = snewn(g->num_edges, unsigned char); state->exactly_one_loop = FALSE; state->grid_type = params->type; newboard_please: memset(state->lines, LINE_UNKNOWN, g->num_edges); memset(state->line_errors, 0, g->num_edges); state->solved = state->cheated = FALSE; /* Get a new random solvable board with all its clues filled in. Yes, this * can loop for ever if the params are suitably unfavourable, but * preventing games smaller than 4x4 seems to stop this happening */ do { add_full_clues(state, rs); } while (!game_has_unique_soln(state, params->diff)); state_new = remove_clues(state, rs, params->diff); free_game(state); state = state_new; if (params->diff > 0 && game_has_unique_soln(state, params->diff-1)) { #ifdef SHOW_WORKING fprintf(stderr, "Rejecting board, it is too easy\n"); #endif goto newboard_please; } game_desc = state_to_text(state); free_game(state); if (grid_desc) { retval = snewn(strlen(grid_desc) + 1 + strlen(game_desc) + 1, char); sprintf(retval, "%s%c%s", grid_desc, (int)GRID_DESC_SEP, game_desc); sfree(grid_desc); sfree(game_desc); } else { retval = game_desc; } assert(!validate_desc(params, retval)); return retval; } static game_state *new_game(midend *me, const game_params *params, const char *desc) { int i; game_state *state = snew(game_state); int empties_to_make = 0; int n,n2; const char *dp; char *grid_desc; grid *g; int num_faces, num_edges; grid_desc = extract_grid_desc(&desc); state->game_grid = g = loopy_generate_grid(params, grid_desc); if (grid_desc) sfree(grid_desc); dp = desc; num_faces = g->num_faces; num_edges = g->num_edges; state->clues = snewn(num_faces, signed char); state->lines = snewn(num_edges, char); state->line_errors = snewn(num_edges, unsigned char); state->exactly_one_loop = FALSE; state->solved = state->cheated = FALSE; state->grid_type = params->type; for (i = 0; i < num_faces; i++) { if (empties_to_make) { empties_to_make--; state->clues[i] = -1; continue; } assert(*dp); n = *dp - '0'; n2 = *dp - 'A' + 10; if (n >= 0 && n < 10) { state->clues[i] = n; } else if (n2 >= 10 && n2 < 36) { state->clues[i] = n2; } else { n = *dp - 'a' + 1; assert(n > 0); state->clues[i] = -1; empties_to_make = n - 1; } ++dp; } memset(state->lines, LINE_UNKNOWN, num_edges); memset(state->line_errors, 0, num_edges); return state; } /* Calculates the line_errors data, and checks if the current state is a * solution */ static int check_completion(game_state *state) { grid *g = state->game_grid; int i, ret; int *dsf, *component_state; int nsilly, nloop, npath, largest_comp, largest_size, total_pathsize; enum { COMP_NONE, COMP_LOOP, COMP_PATH, COMP_SILLY, COMP_EMPTY }; memset(state->line_errors, 0, g->num_edges); /* * Find loops in the grid, and determine whether the puzzle is * solved. * * Loopy is a bit more complicated than most puzzles that care * about loop detection. In most of them, loops are simply * _forbidden_; so the obviously right way to do * error-highlighting during play is to light up a graph edge red * iff it is part of a loop, which is exactly what the centralised * findloop.c makes easy. * * But Loopy is unusual in that you're _supposed_ to be making a * loop - and yet _some_ loops are not the right loop. So we need * to be more discriminating, by identifying loops one by one and * then thinking about which ones to highlight, and so findloop.c * isn't quite the right tool for the job in this case. * * Worse still, consider situations in which the grid contains a * loop and also some non-loop edges: there are some cases like * this in which the user's intuitive expectation would be to * highlight the loop (if you're only about half way through the * puzzle and have accidentally made a little loop in some corner * of the grid), and others in which they'd be more likely to * expect you to highlight the non-loop edges (if you've just * closed off a whole loop that you thought was the entire * solution, but forgot some disconnected edges in a corner * somewhere). So while it's easy enough to check whether the * solution is _right_, highlighting the wrong parts is a tricky * problem for this puzzle! * * I'd quite like, in some situations, to identify the largest * loop among the player's YES edges, and then light up everything * other than that. But finding the longest cycle in a graph is an * NP-complete problem (because, in particular, it must return a * Hamilton cycle if one exists). * * However, I think we can make the problem tractable by * exercising the Puzzles principle that it isn't absolutely * necessary to highlight _all_ errors: the key point is that by * the time the user has filled in the whole grid, they should * either have seen a completion flash, or have _some_ error * highlight showing them why the solution isn't right. So in * principle it would be *just about* good enough to highlight * just one error in the whole grid, if there was really no better * way. But we'd like to highlight as many errors as possible. * * In this case, I think the simple approach is to make use of the * fact that no vertex may have degree > 2, and that's really * simple to detect. So the plan goes like this: * * - Form the dsf of connected components of the graph vertices. * * - Highlight an error at any vertex with degree > 2. (It so * happens that we do this by lighting up all the edges * incident to that vertex, but that's an output detail.) * * - Any component that contains such a vertex is now excluded * from further consideration, because it already has a * highlight. * * - The remaining components have no vertex with degree > 2, and * hence they all consist of either a simple loop, or a simple * path with two endpoints. * * - For these purposes, group together all the paths and imagine * them to be a single component (because in most normal * situations the player will gradually build up the solution * _not_ all in one connected segment, but as lots of separate * little path pieces that gradually connect to each other). * * - After doing that, if there is exactly one (sensible) * component - be it a collection of paths or a loop - then * highlight no further edge errors. (The former case is normal * during play, and the latter is a potentially solved puzzle.) * * - Otherwise, find the largest of the sensible components, * leave that one unhighlighted, and light the rest up in red. */ dsf = snew_dsf(g->num_dots); /* Build the dsf. */ for (i = 0; i < g->num_edges; i++) { if (state->lines[i] == LINE_YES) { grid_edge *e = g->edges + i; int d1 = e->dot1 - g->dots, d2 = e->dot2 - g->dots; dsf_merge(dsf, d1, d2); } } /* Initialise a state variable for each connected component. */ component_state = snewn(g->num_dots, int); for (i = 0; i < g->num_dots; i++) { if (dsf_canonify(dsf, i) == i) component_state[i] = COMP_LOOP; else component_state[i] = COMP_NONE; } /* Check for dots with degree > 3. Here we also spot dots of * degree 1 in which the user has marked all the non-edges as * LINE_NO, because those are also clear vertex-level errors, so * we give them the same treatment of excluding their connected * component from the subsequent loop analysis. */ for (i = 0; i < g->num_dots; i++) { int comp = dsf_canonify(dsf, i); int yes = dot_order(state, i, LINE_YES); int unknown = dot_order(state, i, LINE_UNKNOWN); if ((yes == 1 && unknown == 0) || (yes >= 3)) { /* violation, so mark all YES edges as errors */ grid_dot *d = g->dots + i; int j; for (j = 0; j < d->order; j++) { int e = d->edges[j] - g->edges; if (state->lines[e] == LINE_YES) state->line_errors[e] = TRUE; } /* And mark this component as not worthy of further * consideration. */ component_state[comp] = COMP_SILLY; } else if (yes == 0) { /* A completely isolated dot must also be excluded it from * the subsequent loop highlighting pass, but we tag it * with a different enum value to avoid it counting * towards the components that inhibit returning a win * status. */ component_state[comp] = COMP_EMPTY; } else if (yes == 1) { /* A dot with degree 1 that didn't fall into the 'clearly * erroneous' case above indicates that this connected * component will be a path rather than a loop - unless * something worse elsewhere in the component has * classified it as silly. */ if (component_state[comp] != COMP_SILLY) component_state[comp] = COMP_PATH; } } /* Count up the components. Also, find the largest sensible * component. (Tie-breaking condition is derived from the order of * vertices in the grid data structure, which is fairly arbitrary * but at least stays stable throughout the game.) */ nsilly = nloop = npath = 0; total_pathsize = 0; largest_comp = largest_size = -1; for (i = 0; i < g->num_dots; i++) { if (component_state[i] == COMP_SILLY) { nsilly++; } else if (component_state[i] == COMP_PATH) { total_pathsize += dsf_size(dsf, i); npath = 1; } else if (component_state[i] == COMP_LOOP) { int this_size; nloop++; if ((this_size = dsf_size(dsf, i)) > largest_size) { largest_comp = i; largest_size = this_size; } } } if (largest_size < total_pathsize) { largest_comp = -1; /* means the paths */ largest_size = total_pathsize; } if (nloop > 0 && nloop + npath > 1) { /* * If there are at least two sensible components including at * least one loop, highlight all edges in every sensible * component that is not the largest one. */ for (i = 0; i < g->num_edges; i++) { if (state->lines[i] == LINE_YES) { grid_edge *e = g->edges + i; int d1 = e->dot1 - g->dots; /* either endpoint is good enough */ int comp = dsf_canonify(dsf, d1); if ((component_state[comp] == COMP_PATH && -1 != largest_comp) || (component_state[comp] == COMP_LOOP && comp != largest_comp)) state->line_errors[i] = TRUE; } } } if (nloop == 1 && npath == 0 && nsilly == 0) { /* * If there is exactly one component and it is a loop, then * the puzzle is potentially complete, so check the clues. */ ret = TRUE; for (i = 0; i < g->num_faces; i++) { int c = state->clues[i]; if (c >= 0 && face_order(state, i, LINE_YES) != c) { ret = FALSE; break; } } /* * Also, whether or not the puzzle is actually complete, set * the flag that says this game_state has exactly one loop and * nothing else, which will be used to vary the semantics of * clue highlighting at display time. */ state->exactly_one_loop = TRUE; } else { ret = FALSE; state->exactly_one_loop = FALSE; } sfree(component_state); sfree(dsf); return ret; } /* ---------------------------------------------------------------------- * Solver logic * * Our solver modes operate as follows. Each mode also uses the modes above it. * * Easy Mode * Just implement the rules of the game. * * Normal and Tricky Modes * For each (adjacent) pair of lines through each dot we store a bit for * whether at least one of them is on and whether at most one is on. (If we * know both or neither is on that's already stored more directly.) * * Advanced Mode * Use edsf data structure to make equivalence classes of lines that are * known identical to or opposite to one another. */ /* DLines: * For general grids, we consider "dlines" to be pairs of lines joined * at a dot. The lines must be adjacent around the dot, so we can think of * a dline as being a dot+face combination. Or, a dot+edge combination where * the second edge is taken to be the next clockwise edge from the dot. * Original loopy code didn't have this extra restriction of the lines being * adjacent. From my tests with square grids, this extra restriction seems to * take little, if anything, away from the quality of the puzzles. * A dline can be uniquely identified by an edge/dot combination, given that * a dline-pair always goes clockwise around its common dot. The edge/dot * combination can be represented by an edge/bool combination - if bool is * TRUE, use edge->dot1 else use edge->dot2. So the total number of dlines is * exactly twice the number of edges in the grid - although the dlines * spanning the infinite face are not all that useful to the solver. * Note that, by convention, a dline goes clockwise around its common dot, * which means the dline goes anti-clockwise around its common face. */ /* Helper functions for obtaining an index into an array of dlines, given * various information. We assume the grid layout conventions about how * the various lists are interleaved - see grid_make_consistent() for * details. */ /* i points to the first edge of the dline pair, reading clockwise around * the dot. */ static int dline_index_from_dot(grid *g, grid_dot *d, int i) { grid_edge *e = d->edges[i]; int ret; #ifdef DEBUG_DLINES grid_edge *e2; int i2 = i+1; if (i2 == d->order) i2 = 0; e2 = d->edges[i2]; #endif ret = 2 * (e - g->edges) + ((e->dot1 == d) ? 1 : 0); #ifdef DEBUG_DLINES printf("dline_index_from_dot: d=%d,i=%d, edges [%d,%d] - %d\n", (int)(d - g->dots), i, (int)(e - g->edges), (int)(e2 - g->edges), ret); #endif return ret; } /* i points to the second edge of the dline pair, reading clockwise around * the face. That is, the edges of the dline, starting at edge{i}, read * anti-clockwise around the face. By layout conventions, the common dot * of the dline will be f->dots[i] */ static int dline_index_from_face(grid *g, grid_face *f, int i) { grid_edge *e = f->edges[i]; grid_dot *d = f->dots[i]; int ret; #ifdef DEBUG_DLINES grid_edge *e2; int i2 = i - 1; if (i2 < 0) i2 += f->order; e2 = f->edges[i2]; #endif ret = 2 * (e - g->edges) + ((e->dot1 == d) ? 1 : 0); #ifdef DEBUG_DLINES printf("dline_index_from_face: f=%d,i=%d, edges [%d,%d] - %d\n", (int)(f - g->faces), i, (int)(e - g->edges), (int)(e2 - g->edges), ret); #endif return ret; } static int is_atleastone(const char *dline_array, int index) { return BIT_SET(dline_array[index], 0); } static int set_atleastone(char *dline_array, int index) { return SET_BIT(dline_array[index], 0); } static int is_atmostone(const char *dline_array, int index) { return BIT_SET(dline_array[index], 1); } static int set_atmostone(char *dline_array, int index) { return SET_BIT(dline_array[index], 1); } static void array_setall(char *array, char from, char to, int len) { char *p = array, *p_old = p; int len_remaining = len; while ((p = memchr(p, from, len_remaining))) { *p = to; len_remaining -= p - p_old; p_old = p; } } /* Helper, called when doing dline dot deductions, in the case where we * have 4 UNKNOWNs, and two of them (adjacent) have *exactly* one YES between * them (because of dline atmostone/atleastone). * On entry, edge points to the first of these two UNKNOWNs. This function * will find the opposite UNKNOWNS (if they are adjacent to one another) * and set their corresponding dline to atleastone. (Setting atmostone * already happens in earlier dline deductions) */ static int dline_set_opp_atleastone(solver_state *sstate, grid_dot *d, int edge) { game_state *state = sstate->state; grid *g = state->game_grid; int N = d->order; int opp, opp2; for (opp = 0; opp < N; opp++) { int opp_dline_index; if (opp == edge || opp == edge+1 || opp == edge-1) continue; if (opp == 0 && edge == N-1) continue; if (opp == N-1 && edge == 0) continue; opp2 = opp + 1; if (opp2 == N) opp2 = 0; /* Check if opp, opp2 point to LINE_UNKNOWNs */ if (state->lines[d->edges[opp] - g->edges] != LINE_UNKNOWN) continue; if (state->lines[d->edges[opp2] - g->edges] != LINE_UNKNOWN) continue; /* Found opposite UNKNOWNS and they're next to each other */ opp_dline_index = dline_index_from_dot(g, d, opp); return set_atleastone(sstate->dlines, opp_dline_index); } return FALSE; } /* Set pairs of lines around this face which are known to be identical, to * the given line_state */ static int face_setall_identical(solver_state *sstate, int face_index, enum line_state line_new) { /* can[dir] contains the canonical line associated with the line in * direction dir from the square in question. Similarly inv[dir] is * whether or not the line in question is inverse to its canonical * element. */ int retval = FALSE; game_state *state = sstate->state; grid *g = state->game_grid; grid_face *f = g->faces + face_index; int N = f->order; int i, j; int can1, can2, inv1, inv2; for (i = 0; i < N; i++) { int line1_index = f->edges[i] - g->edges; if (state->lines[line1_index] != LINE_UNKNOWN) continue; for (j = i + 1; j < N; j++) { int line2_index = f->edges[j] - g->edges; if (state->lines[line2_index] != LINE_UNKNOWN) continue; /* Found two UNKNOWNS */ can1 = edsf_canonify(sstate->linedsf, line1_index, &inv1); can2 = edsf_canonify(sstate->linedsf, line2_index, &inv2); if (can1 == can2 && inv1 == inv2) { solver_set_line(sstate, line1_index, line_new); solver_set_line(sstate, line2_index, line_new); } } } return retval; } /* Given a dot or face, and a count of LINE_UNKNOWNs, find them and * return the edge indices into e. */ static void find_unknowns(game_state *state, grid_edge **edge_list, /* Edge list to search (from a face or a dot) */ int expected_count, /* Number of UNKNOWNs (comes from solver's cache) */ int *e /* Returned edge indices */) { int c = 0; grid *g = state->game_grid; while (c < expected_count) { int line_index = *edge_list - g->edges; if (state->lines[line_index] == LINE_UNKNOWN) { e[c] = line_index; c++; } ++edge_list; } } /* If we have a list of edges, and we know whether the number of YESs should * be odd or even, and there are only a few UNKNOWNs, we can do some simple * linedsf deductions. This can be used for both face and dot deductions. * Returns the difficulty level of the next solver that should be used, * or DIFF_MAX if no progress was made. */ static int parity_deductions(solver_state *sstate, grid_edge **edge_list, /* Edge list (from a face or a dot) */ int total_parity, /* Expected number of YESs modulo 2 (either 0 or 1) */ int unknown_count) { game_state *state = sstate->state; int diff = DIFF_MAX; int *linedsf = sstate->linedsf; if (unknown_count == 2) { /* Lines are known alike/opposite, depending on inv. */ int e[2]; find_unknowns(state, edge_list, 2, e); if (merge_lines(sstate, e[0], e[1], total_parity)) diff = min(diff, DIFF_HARD); } else if (unknown_count == 3) { int e[3]; int can[3]; /* canonical edges */ int inv[3]; /* whether can[x] is inverse to e[x] */ find_unknowns(state, edge_list, 3, e); can[0] = edsf_canonify(linedsf, e[0], inv); can[1] = edsf_canonify(linedsf, e[1], inv+1); can[2] = edsf_canonify(linedsf, e[2], inv+2); if (can[0] == can[1]) { if (solver_set_line(sstate, e[2], (total_parity^inv[0]^inv[1]) ? LINE_YES : LINE_NO)) diff = min(diff, DIFF_EASY); } if (can[0] == can[2]) { if (solver_set_line(sstate, e[1], (total_parity^inv[0]^inv[2]) ? LINE_YES : LINE_NO)) diff = min(diff, DIFF_EASY); } if (can[1] == can[2]) { if (solver_set_line(sstate, e[0], (total_parity^inv[1]^inv[2]) ? LINE_YES : LINE_NO)) diff = min(diff, DIFF_EASY); } } else if (unknown_count == 4) { int e[4]; int can[4]; /* canonical edges */ int inv[4]; /* whether can[x] is inverse to e[x] */ find_unknowns(state, edge_list, 4, e); can[0] = edsf_canonify(linedsf, e[0], inv); can[1] = edsf_canonify(linedsf, e[1], inv+1); can[2] = edsf_canonify(linedsf, e[2], inv+2); can[3] = edsf_canonify(linedsf, e[3], inv+3); if (can[0] == can[1]) { if (merge_lines(sstate, e[2], e[3], total_parity^inv[0]^inv[1])) diff = min(diff, DIFF_HARD); } else if (can[0] == can[2]) { if (merge_lines(sstate, e[1], e[3], total_parity^inv[0]^inv[2])) diff = min(diff, DIFF_HARD); } else if (can[0] == can[3]) { if (merge_lines(sstate, e[1], e[2], total_parity^inv[0]^inv[3])) diff = min(diff, DIFF_HARD); } else if (can[1] == can[2]) { if (merge_lines(sstate, e[0], e[3], total_parity^inv[1]^inv[2])) diff = min(diff, DIFF_HARD); } else if (can[1] == can[3]) { if (merge_lines(sstate, e[0], e[2], total_parity^inv[1]^inv[3])) diff = min(diff, DIFF_HARD); } else if (can[2] == can[3]) { if (merge_lines(sstate, e[0], e[1], total_parity^inv[2]^inv[3])) diff = min(diff, DIFF_HARD); } } return diff; } /* * These are the main solver functions. * * Their return values are diff values corresponding to the lowest mode solver * that would notice the work that they have done. For example if the normal * mode solver adds actual lines or crosses, it will return DIFF_EASY as the * easy mode solver might be able to make progress using that. It doesn't make * sense for one of them to return a diff value higher than that of the * function itself. * * Each function returns the lowest value it can, as early as possible, in * order to try and pass as much work as possible back to the lower level * solvers which progress more quickly. */ /* PROPOSED NEW DESIGN: * We have a work queue consisting of 'events' notifying us that something has * happened that a particular solver mode might be interested in. For example * the hard mode solver might do something that helps the normal mode solver at * dot [x,y] in which case it will enqueue an event recording this fact. Then * we pull events off the work queue, and hand each in turn to the solver that * is interested in them. If a solver reports that it failed we pass the same * event on to progressively more advanced solvers and the loop detector. Once * we've exhausted an event, or it has helped us progress, we drop it and * continue to the next one. The events are sorted first in order of solver * complexity (easy first) then order of insertion (oldest first). * Once we run out of events we loop over each permitted solver in turn * (easiest first) until either a deduction is made (and an event therefore * emerges) or no further deductions can be made (in which case we've failed). * * QUESTIONS: * * How do we 'loop over' a solver when both dots and squares are concerned. * Answer: first all squares then all dots. */ static int trivial_deductions(solver_state *sstate) { int i, current_yes, current_no; game_state *state = sstate->state; grid *g = state->game_grid; int diff = DIFF_MAX; /* Per-face deductions */ for (i = 0; i < g->num_faces; i++) { grid_face *f = g->faces + i; if (sstate->face_solved[i]) continue; current_yes = sstate->face_yes_count[i]; current_no = sstate->face_no_count[i]; if (current_yes + current_no == f->order) { sstate->face_solved[i] = TRUE; continue; } if (state->clues[i] < 0) continue; /* * This code checks whether the numeric clue on a face is so * large as to permit all its remaining LINE_UNKNOWNs to be * filled in as LINE_YES, or alternatively so small as to * permit them all to be filled in as LINE_NO. */ if (state->clues[i] < current_yes) { sstate->solver_status = SOLVER_MISTAKE; return DIFF_EASY; } if (state->clues[i] == current_yes) { if (face_setall(sstate, i, LINE_UNKNOWN, LINE_NO)) diff = min(diff, DIFF_EASY); sstate->face_solved[i] = TRUE; continue; } if (f->order - state->clues[i] < current_no) { sstate->solver_status = SOLVER_MISTAKE; return DIFF_EASY; } if (f->order - state->clues[i] == current_no) { if (face_setall(sstate, i, LINE_UNKNOWN, LINE_YES)) diff = min(diff, DIFF_EASY); sstate->face_solved[i] = TRUE; continue; } if (f->order - state->clues[i] == current_no + 1 && f->order - current_yes - current_no > 2) { /* * One small refinement to the above: we also look for any * adjacent pair of LINE_UNKNOWNs around the face with * some LINE_YES incident on it from elsewhere. If we find * one, then we know that pair of LINE_UNKNOWNs can't * _both_ be LINE_YES, and hence that pushes us one line * closer to being able to determine all the rest. */ int j, k, e1, e2, e, d; for (j = 0; j < f->order; j++) { e1 = f->edges[j] - g->edges; e2 = f->edges[j+1 < f->order ? j+1 : 0] - g->edges; if (g->edges[e1].dot1 == g->edges[e2].dot1 || g->edges[e1].dot1 == g->edges[e2].dot2) { d = g->edges[e1].dot1 - g->dots; } else { assert(g->edges[e1].dot2 == g->edges[e2].dot1 || g->edges[e1].dot2 == g->edges[e2].dot2); d = g->edges[e1].dot2 - g->dots; } if (state->lines[e1] == LINE_UNKNOWN && state->lines[e2] == LINE_UNKNOWN) { for (k = 0; k < g->dots[d].order; k++) { int e = g->dots[d].edges[k] - g->edges; if (state->lines[e] == LINE_YES) goto found; /* multi-level break */ } } } continue; found: /* * If we get here, we've found such a pair of edges, and * they're e1 and e2. */ for (j = 0; j < f->order; j++) { e = f->edges[j] - g->edges; if (state->lines[e] == LINE_UNKNOWN && e != e1 && e != e2) { int r = solver_set_line(sstate, e, LINE_YES); assert(r); diff = min(diff, DIFF_EASY); } } } } check_caches(sstate); /* Per-dot deductions */ for (i = 0; i < g->num_dots; i++) { grid_dot *d = g->dots + i; int yes, no, unknown; if (sstate->dot_solved[i]) continue; yes = sstate->dot_yes_count[i]; no = sstate->dot_no_count[i]; unknown = d->order - yes - no; if (yes == 0) { if (unknown == 0) { sstate->dot_solved[i] = TRUE; } else if (unknown == 1) { dot_setall(sstate, i, LINE_UNKNOWN, LINE_NO); diff = min(diff, DIFF_EASY); sstate->dot_solved[i] = TRUE; } } else if (yes == 1) { if (unknown == 0) { sstate->solver_status = SOLVER_MISTAKE; return DIFF_EASY; } else if (unknown == 1) { dot_setall(sstate, i, LINE_UNKNOWN, LINE_YES); diff = min(diff, DIFF_EASY); } } else if (yes == 2) { if (unknown > 0) { dot_setall(sstate, i, LINE_UNKNOWN, LINE_NO); diff = min(diff, DIFF_EASY); } sstate->dot_solved[i] = TRUE; } else { sstate->solver_status = SOLVER_MISTAKE; return DIFF_EASY; } } check_caches(sstate); return diff; } static int dline_deductions(solver_state *sstate) { game_state *state = sstate->state; grid *g = state->game_grid; char *dlines = sstate->dlines; int i; int diff = DIFF_MAX; /* ------ Face deductions ------ */ /* Given a set of dline atmostone/atleastone constraints, need to figure * out if we can deduce any further info. For more general faces than * squares, this turns out to be a tricky problem. * The approach taken here is to define (per face) NxN matrices: * "maxs" and "mins". * The entries maxs(j,k) and mins(j,k) define the upper and lower limits * for the possible number of edges that are YES between positions j and k * going clockwise around the face. Can think of j and k as marking dots * around the face (recall the labelling scheme: edge0 joins dot0 to dot1, * edge1 joins dot1 to dot2 etc). * Trivially, mins(j,j) = maxs(j,j) = 0, and we don't even bother storing * these. mins(j,j+1) and maxs(j,j+1) are determined by whether edge{j} * is YES, NO or UNKNOWN. mins(j,j+2) and maxs(j,j+2) are related to * the dline atmostone/atleastone status for edges j and j+1. * * Then we calculate the remaining entries recursively. We definitely * know that * mins(j,k) >= { mins(j,u) + mins(u,k) } for any u between j and k. * This is because any valid placement of YESs between j and k must give * a valid placement between j and u, and also between u and k. * I believe it's sufficient to use just the two values of u: * j+1 and j+2. Seems to work well in practice - the bounds we compute * are rigorous, even if they might not be best-possible. * * Once we have maxs and mins calculated, we can make inferences about * each dline{j,j+1} by looking at the possible complementary edge-counts * mins(j+2,j) and maxs(j+2,j) and comparing these with the face clue. * As well as dlines, we can make similar inferences about single edges. * For example, consider a pentagon with clue 3, and we know at most one * of (edge0, edge1) is YES, and at most one of (edge2, edge3) is YES. * We could then deduce edge4 is YES, because maxs(0,4) would be 2, so * that final edge would have to be YES to make the count up to 3. */ /* Much quicker to allocate arrays on the stack than the heap, so * define the largest possible face size, and base our array allocations * on that. We check this with an assertion, in case someone decides to * make a grid which has larger faces than this. Note, this algorithm * could get quite expensive if there are many large faces. */ #define MAX_FACE_SIZE 12 for (i = 0; i < g->num_faces; i++) { int maxs[MAX_FACE_SIZE][MAX_FACE_SIZE]; int mins[MAX_FACE_SIZE][MAX_FACE_SIZE]; grid_face *f = g->faces + i; int N = f->order; int j,m; int clue = state->clues[i]; assert(N <= MAX_FACE_SIZE); if (sstate->face_solved[i]) continue; if (clue < 0) continue; /* Calculate the (j,j+1) entries */ for (j = 0; j < N; j++) { int edge_index = f->edges[j] - g->edges; int dline_index; enum line_state line1 = state->lines[edge_index]; enum line_state line2; int tmp; int k = j + 1; if (k >= N) k = 0; maxs[j][k] = (line1 == LINE_NO) ? 0 : 1; mins[j][k] = (line1 == LINE_YES) ? 1 : 0; /* Calculate the (j,j+2) entries */ dline_index = dline_index_from_face(g, f, k); edge_index = f->edges[k] - g->edges; line2 = state->lines[edge_index]; k++; if (k >= N) k = 0; /* max */ tmp = 2; if (line1 == LINE_NO) tmp--; if (line2 == LINE_NO) tmp--; if (tmp == 2 && is_atmostone(dlines, dline_index)) tmp = 1; maxs[j][k] = tmp; /* min */ tmp = 0; if (line1 == LINE_YES) tmp++; if (line2 == LINE_YES) tmp++; if (tmp == 0 && is_atleastone(dlines, dline_index)) tmp = 1; mins[j][k] = tmp; } /* Calculate the (j,j+m) entries for m between 3 and N-1 */ for (m = 3; m < N; m++) { for (j = 0; j < N; j++) { int k = j + m; int u = j + 1; int v = j + 2; int tmp; if (k >= N) k -= N; if (u >= N) u -= N; if (v >= N) v -= N; maxs[j][k] = maxs[j][u] + maxs[u][k]; mins[j][k] = mins[j][u] + mins[u][k]; tmp = maxs[j][v] + maxs[v][k]; maxs[j][k] = min(maxs[j][k], tmp); tmp = mins[j][v] + mins[v][k]; mins[j][k] = max(mins[j][k], tmp); } } /* See if we can make any deductions */ for (j = 0; j < N; j++) { int k; grid_edge *e = f->edges[j]; int line_index = e - g->edges; int dline_index; if (state->lines[line_index] != LINE_UNKNOWN) continue; k = j + 1; if (k >= N) k = 0; /* minimum YESs in the complement of this edge */ if (mins[k][j] > clue) { sstate->solver_status = SOLVER_MISTAKE; return DIFF_EASY; } if (mins[k][j] == clue) { /* setting this edge to YES would make at least * (clue+1) edges - contradiction */ solver_set_line(sstate, line_index, LINE_NO); diff = min(diff, DIFF_EASY); } if (maxs[k][j] < clue - 1) { sstate->solver_status = SOLVER_MISTAKE; return DIFF_EASY; } if (maxs[k][j] == clue - 1) { /* Only way to satisfy the clue is to set edge{j} as YES */ solver_set_line(sstate, line_index, LINE_YES); diff = min(diff, DIFF_EASY); } /* More advanced deduction that allows propagation along diagonal * chains of faces connected by dots, for example, 3-2-...-2-3 * in square grids. */ if (sstate->diff >= DIFF_TRICKY) { /* Now see if we can make dline deduction for edges{j,j+1} */ e = f->edges[k]; if (state->lines[e - g->edges] != LINE_UNKNOWN) /* Only worth doing this for an UNKNOWN,UNKNOWN pair. * Dlines where one of the edges is known, are handled in the * dot-deductions */ continue; dline_index = dline_index_from_face(g, f, k); k++; if (k >= N) k = 0; /* minimum YESs in the complement of this dline */ if (mins[k][j] > clue - 2) { /* Adding 2 YESs would break the clue */ if (set_atmostone(dlines, dline_index)) diff = min(diff, DIFF_NORMAL); } /* maximum YESs in the complement of this dline */ if (maxs[k][j] < clue) { /* Adding 2 NOs would mean not enough YESs */ if (set_atleastone(dlines, dline_index)) diff = min(diff, DIFF_NORMAL); } } } } if (diff < DIFF_NORMAL) return diff; /* ------ Dot deductions ------ */ for (i = 0; i < g->num_dots; i++) { grid_dot *d = g->dots + i; int N = d->order; int yes, no, unknown; int j; if (sstate->dot_solved[i]) continue; yes = sstate->dot_yes_count[i]; no = sstate->dot_no_count[i]; unknown = N - yes - no; for (j = 0; j < N; j++) { int k; int dline_index; int line1_index, line2_index; enum line_state line1, line2; k = j + 1; if (k >= N) k = 0; dline_index = dline_index_from_dot(g, d, j); line1_index = d->edges[j] - g->edges; line2_index = d->edges[k] - g->edges; line1 = state->lines[line1_index]; line2 = state->lines[line2_index]; /* Infer dline state from line state */ if (line1 == LINE_NO || line2 == LINE_NO) { if (set_atmostone(dlines, dline_index)) diff = min(diff, DIFF_NORMAL); } if (line1 == LINE_YES || line2 == LINE_YES) { if (set_atleastone(dlines, dline_index)) diff = min(diff, DIFF_NORMAL); } /* Infer line state from dline state */ if (is_atmostone(dlines, dline_index)) { if (line1 == LINE_YES && line2 == LINE_UNKNOWN) { solver_set_line(sstate, line2_index, LINE_NO); diff = min(diff, DIFF_EASY); } if (line2 == LINE_YES && line1 == LINE_UNKNOWN) { solver_set_line(sstate, line1_index, LINE_NO); diff = min(diff, DIFF_EASY); } } if (is_atleastone(dlines, dline_index)) { if (line1 == LINE_NO && line2 == LINE_UNKNOWN) { solver_set_line(sstate, line2_index, LINE_YES); diff = min(diff, DIFF_EASY); } if (line2 == LINE_NO && line1 == LINE_UNKNOWN) { solver_set_line(sstate, line1_index, LINE_YES); diff = min(diff, DIFF_EASY); } } /* Deductions that depend on the numbers of lines. * Only bother if both lines are UNKNOWN, otherwise the * easy-mode solver (or deductions above) would have taken * care of it. */ if (line1 != LINE_UNKNOWN || line2 != LINE_UNKNOWN) continue; if (yes == 0 && unknown == 2) { /* Both these unknowns must be identical. If we know * atmostone or atleastone, we can make progress. */ if (is_atmostone(dlines, dline_index)) { solver_set_line(sstate, line1_index, LINE_NO); solver_set_line(sstate, line2_index, LINE_NO); diff = min(diff, DIFF_EASY); } if (is_atleastone(dlines, dline_index)) { solver_set_line(sstate, line1_index, LINE_YES); solver_set_line(sstate, line2_index, LINE_YES); diff = min(diff, DIFF_EASY); } } if (yes == 1) { if (set_atmostone(dlines, dline_index)) diff = min(diff, DIFF_NORMAL); if (unknown == 2) { if (set_atleastone(dlines, dline_index)) diff = min(diff, DIFF_NORMAL); } } /* More advanced deduction that allows propagation along diagonal * chains of faces connected by dots, for example: 3-2-...-2-3 * in square grids. */ if (sstate->diff >= DIFF_TRICKY) { /* If we have atleastone set for this dline, infer * atmostone for each "opposite" dline (that is, each * dline without edges in common with this one). * Again, this test is only worth doing if both these * lines are UNKNOWN. For if one of these lines were YES, * the (yes == 1) test above would kick in instead. */ if (is_atleastone(dlines, dline_index)) { int opp; for (opp = 0; opp < N; opp++) { int opp_dline_index; if (opp == j || opp == j+1 || opp == j-1) continue; if (j == 0 && opp == N-1) continue; if (j == N-1 && opp == 0) continue; opp_dline_index = dline_index_from_dot(g, d, opp); if (set_atmostone(dlines, opp_dline_index)) diff = min(diff, DIFF_NORMAL); } if (yes == 0 && is_atmostone(dlines, dline_index)) { /* This dline has *exactly* one YES and there are no * other YESs. This allows more deductions. */ if (unknown == 3) { /* Third unknown must be YES */ for (opp = 0; opp < N; opp++) { int opp_index; if (opp == j || opp == k) continue; opp_index = d->edges[opp] - g->edges; if (state->lines[opp_index] == LINE_UNKNOWN) { solver_set_line(sstate, opp_index, LINE_YES); diff = min(diff, DIFF_EASY); } } } else if (unknown == 4) { /* Exactly one of opposite UNKNOWNS is YES. We've * already set atmostone, so set atleastone as * well. */ if (dline_set_opp_atleastone(sstate, d, j)) diff = min(diff, DIFF_NORMAL); } } } } } } return diff; } static int linedsf_deductions(solver_state *sstate) { game_state *state = sstate->state; grid *g = state->game_grid; char *dlines = sstate->dlines; int i; int diff = DIFF_MAX; int diff_tmp; /* ------ Face deductions ------ */ /* A fully-general linedsf deduction seems overly complicated * (I suspect the problem is NP-complete, though in practice it might just * be doable because faces are limited in size). * For simplicity, we only consider *pairs* of LINE_UNKNOWNS that are * known to be identical. If setting them both to YES (or NO) would break * the clue, set them to NO (or YES). */ for (i = 0; i < g->num_faces; i++) { int N, yes, no, unknown; int clue; if (sstate->face_solved[i]) continue; clue = state->clues[i]; if (clue < 0) continue; N = g->faces[i].order; yes = sstate->face_yes_count[i]; if (yes + 1 == clue) { if (face_setall_identical(sstate, i, LINE_NO)) diff = min(diff, DIFF_EASY); } no = sstate->face_no_count[i]; if (no + 1 == N - clue) { if (face_setall_identical(sstate, i, LINE_YES)) diff = min(diff, DIFF_EASY); } /* Reload YES count, it might have changed */ yes = sstate->face_yes_count[i]; unknown = N - no - yes; /* Deductions with small number of LINE_UNKNOWNs, based on overall * parity of lines. */ diff_tmp = parity_deductions(sstate, g->faces[i].edges, (clue - yes) % 2, unknown); diff = min(diff, diff_tmp); } /* ------ Dot deductions ------ */ for (i = 0; i < g->num_dots; i++) { grid_dot *d = g->dots + i; int N = d->order; int j; int yes, no, unknown; /* Go through dlines, and do any dline<->linedsf deductions wherever * we find two UNKNOWNS. */ for (j = 0; j < N; j++) { int dline_index = dline_index_from_dot(g, d, j); int line1_index; int line2_index; int can1, can2, inv1, inv2; int j2; line1_index = d->edges[j] - g->edges; if (state->lines[line1_index] != LINE_UNKNOWN) continue; j2 = j + 1; if (j2 == N) j2 = 0; line2_index = d->edges[j2] - g->edges; if (state->lines[line2_index] != LINE_UNKNOWN) continue; /* Infer dline flags from linedsf */ can1 = edsf_canonify(sstate->linedsf, line1_index, &inv1); can2 = edsf_canonify(sstate->linedsf, line2_index, &inv2); if (can1 == can2 && inv1 != inv2) { /* These are opposites, so set dline atmostone/atleastone */ if (set_atmostone(dlines, dline_index)) diff = min(diff, DIFF_NORMAL); if (set_atleastone(dlines, dline_index)) diff = min(diff, DIFF_NORMAL); continue; } /* Infer linedsf from dline flags */ if (is_atmostone(dlines, dline_index) && is_atleastone(dlines, dline_index)) { if (merge_lines(sstate, line1_index, line2_index, 1)) diff = min(diff, DIFF_HARD); } } /* Deductions with small number of LINE_UNKNOWNs, based on overall * parity of lines. */ yes = sstate->dot_yes_count[i]; no = sstate->dot_no_count[i]; unknown = N - yes - no; diff_tmp = parity_deductions(sstate, d->edges, yes % 2, unknown); diff = min(diff, diff_tmp); } /* ------ Edge dsf deductions ------ */ /* If the state of a line is known, deduce the state of its canonical line * too, and vice versa. */ for (i = 0; i < g->num_edges; i++) { int can, inv; enum line_state s; can = edsf_canonify(sstate->linedsf, i, &inv); if (can == i) continue; s = sstate->state->lines[can]; if (s != LINE_UNKNOWN) { if (solver_set_line(sstate, i, inv ? OPP(s) : s)) diff = min(diff, DIFF_EASY); } else { s = sstate->state->lines[i]; if (s != LINE_UNKNOWN) { if (solver_set_line(sstate, can, inv ? OPP(s) : s)) diff = min(diff, DIFF_EASY); } } } return diff; } static int loop_deductions(solver_state *sstate) { int edgecount = 0, clues = 0, satclues = 0, sm1clues = 0; game_state *state = sstate->state; grid *g = state->game_grid; int shortest_chainlen = g->num_dots; int loop_found = FALSE; int dots_connected; int progress = FALSE; int i; /* * Go through the grid and update for all the new edges. * Since merge_dots() is idempotent, the simplest way to * do this is just to update for _all_ the edges. * Also, while we're here, we count the edges. */ for (i = 0; i < g->num_edges; i++) { if (state->lines[i] == LINE_YES) { loop_found |= merge_dots(sstate, i); edgecount++; } } /* * Count the clues, count the satisfied clues, and count the * satisfied-minus-one clues. */ for (i = 0; i < g->num_faces; i++) { int c = state->clues[i]; if (c >= 0) { int o = sstate->face_yes_count[i]; if (o == c) satclues++; else if (o == c-1) sm1clues++; clues++; } } for (i = 0; i < g->num_dots; ++i) { dots_connected = sstate->looplen[dsf_canonify(sstate->dotdsf, i)]; if (dots_connected > 1) shortest_chainlen = min(shortest_chainlen, dots_connected); } assert(sstate->solver_status == SOLVER_INCOMPLETE); if (satclues == clues && shortest_chainlen == edgecount) { sstate->solver_status = SOLVER_SOLVED; /* This discovery clearly counts as progress, even if we haven't * just added any lines or anything */ progress = TRUE; goto finished_loop_deductionsing; } /* * Now go through looking for LINE_UNKNOWN edges which * connect two dots that are already in the same * equivalence class. If we find one, test to see if the * loop it would create is a solution. */ for (i = 0; i < g->num_edges; i++) { grid_edge *e = g->edges + i; int d1 = e->dot1 - g->dots; int d2 = e->dot2 - g->dots; int eqclass, val; if (state->lines[i] != LINE_UNKNOWN) continue; eqclass = dsf_canonify(sstate->dotdsf, d1); if (eqclass != dsf_canonify(sstate->dotdsf, d2)) continue; val = LINE_NO; /* loop is bad until proven otherwise */ /* * This edge would form a loop. Next * question: how long would the loop be? * Would it equal the total number of edges * (plus the one we'd be adding if we added * it)? */ if (sstate->looplen[eqclass] == edgecount + 1) { int sm1_nearby; /* * This edge would form a loop which * took in all the edges in the entire * grid. So now we need to work out * whether it would be a valid solution * to the puzzle, which means we have to * check if it satisfies all the clues. * This means that every clue must be * either satisfied or satisfied-minus- * 1, and also that the number of * satisfied-minus-1 clues must be at * most two and they must lie on either * side of this edge. */ sm1_nearby = 0; if (e->face1) { int f = e->face1 - g->faces; int c = state->clues[f]; if (c >= 0 && sstate->face_yes_count[f] == c - 1) sm1_nearby++; } if (e->face2) { int f = e->face2 - g->faces; int c = state->clues[f]; if (c >= 0 && sstate->face_yes_count[f] == c - 1) sm1_nearby++; } if (sm1clues == sm1_nearby && sm1clues + satclues == clues) { val = LINE_YES; /* loop is good! */ } } /* * Right. Now we know that adding this edge * would form a loop, and we know whether * that loop would be a viable solution or * not. * * If adding this edge produces a solution, * then we know we've found _a_ solution but * we don't know that it's _the_ solution - * if it were provably the solution then * we'd have deduced this edge some time ago * without the need to do loop detection. So * in this state we return SOLVER_AMBIGUOUS, * which has the effect that hitting Solve * on a user-provided puzzle will fill in a * solution but using the solver to * construct new puzzles won't consider this * a reasonable deduction for the user to * make. */ progress = solver_set_line(sstate, i, val); assert(progress == TRUE); if (val == LINE_YES) { sstate->solver_status = SOLVER_AMBIGUOUS; goto finished_loop_deductionsing; } } finished_loop_deductionsing: return progress ? DIFF_EASY : DIFF_MAX; } /* This will return a dynamically allocated solver_state containing the (more) * solved grid */ static solver_state *solve_game_rec(const solver_state *sstate_start) { solver_state *sstate; /* Index of the solver we should call next. */ int i = 0; /* As a speed-optimisation, we avoid re-running solvers that we know * won't make any progress. This happens when a high-difficulty * solver makes a deduction that can only help other high-difficulty * solvers. * For example: if a new 'dline' flag is set by dline_deductions, the * trivial_deductions solver cannot do anything with this information. * If we've already run the trivial_deductions solver (because it's * earlier in the list), there's no point running it again. * * Therefore: if a solver is earlier in the list than "threshold_index", * we don't bother running it if it's difficulty level is less than * "threshold_diff". */ int threshold_diff = 0; int threshold_index = 0; sstate = dup_solver_state(sstate_start); check_caches(sstate); while (i < NUM_SOLVERS) { if (sstate->solver_status == SOLVER_MISTAKE) return sstate; if (sstate->solver_status == SOLVER_SOLVED || sstate->solver_status == SOLVER_AMBIGUOUS) { /* solver finished */ break; } if ((solver_diffs[i] >= threshold_diff || i >= threshold_index) && solver_diffs[i] <= sstate->diff) { /* current_solver is eligible, so use it */ int next_diff = solver_fns[i](sstate); if (next_diff != DIFF_MAX) { /* solver made progress, so use new thresholds and * start again at top of list. */ threshold_diff = next_diff; threshold_index = i; i = 0; continue; } } /* current_solver is ineligible, or failed to make progress, so * go to the next solver in the list */ i++; } if (sstate->solver_status == SOLVER_SOLVED || sstate->solver_status == SOLVER_AMBIGUOUS) { /* s/LINE_UNKNOWN/LINE_NO/g */ array_setall(sstate->state->lines, LINE_UNKNOWN, LINE_NO, sstate->state->game_grid->num_edges); return sstate; } return sstate; } static char *solve_game(const game_state *state, const game_state *currstate, const char *aux, char **error) { char *soln = NULL; solver_state *sstate, *new_sstate; sstate = new_solver_state(state, DIFF_MAX); new_sstate = solve_game_rec(sstate); if (new_sstate->solver_status == SOLVER_SOLVED) { soln = encode_solve_move(new_sstate->state); } else if (new_sstate->solver_status == SOLVER_AMBIGUOUS) { soln = encode_solve_move(new_sstate->state); /**error = "Solver found ambiguous solutions"; */ } else { soln = encode_solve_move(new_sstate->state); /**error = "Solver failed"; */ } free_solver_state(new_sstate); free_solver_state(sstate); return soln; } /* ---------------------------------------------------------------------- * Drawing and mouse-handling */ static char *interpret_move(const game_state *state, game_ui *ui, const game_drawstate *ds, int x, int y, int button) { grid *g = state->game_grid; grid_edge *e; int i; char *movebuf; int movelen, movesize; char button_char = ' '; enum line_state old_state; button &= ~MOD_MASK; /* Convert mouse-click (x,y) to grid coordinates */ x -= BORDER(ds->tilesize); y -= BORDER(ds->tilesize); x = x * g->tilesize / ds->tilesize; y = y * g->tilesize / ds->tilesize; x += g->lowest_x; y += g->lowest_y; e = grid_nearest_edge(g, x, y); if (e == NULL) return NULL; i = e - g->edges; /* I think it's only possible to play this game with mouse clicks, sorry */ /* Maybe will add mouse drag support some time */ old_state = state->lines[i]; switch (button) { case LEFT_BUTTON: switch (old_state) { case LINE_UNKNOWN: button_char = 'y'; break; case LINE_YES: #ifdef STYLUS_BASED button_char = 'n'; break; #endif case LINE_NO: button_char = 'u'; break; } break; case MIDDLE_BUTTON: button_char = 'u'; break; case RIGHT_BUTTON: switch (old_state) { case LINE_UNKNOWN: button_char = 'n'; break; case LINE_NO: #ifdef STYLUS_BASED button_char = 'y'; break; #endif case LINE_YES: button_char = 'u'; break; } break; default: return NULL; } movelen = 0; movesize = 80; movebuf = snewn(movesize, char); movelen = sprintf(movebuf, "%d%c", i, (int)button_char); { static enum { OFF, FIXED, ADAPTIVE, DUNNO } autofollow = DUNNO; if (autofollow == DUNNO) { const char *env = getenv("LOOPY_AUTOFOLLOW"); if (env && !strcmp(env, "off")) autofollow = OFF; else if (env && !strcmp(env, "fixed")) autofollow = FIXED; else if (env && !strcmp(env, "adaptive")) autofollow = ADAPTIVE; else autofollow = OFF; } if (autofollow != OFF) { int dotid; for (dotid = 0; dotid < 2; dotid++) { grid_dot *dot = (dotid == 0 ? e->dot1 : e->dot2); grid_edge *e_this = e; while (1) { int j, n_found; grid_edge *e_next = NULL; for (j = n_found = 0; j < dot->order; j++) { grid_edge *e_candidate = dot->edges[j]; int i_candidate = e_candidate - g->edges; if (e_candidate != e_this && (autofollow == FIXED || state->lines[i] == LINE_NO || state->lines[i_candidate] != LINE_NO)) { e_next = e_candidate; n_found++; } } if (n_found != 1 || state->lines[e_next - g->edges] != state->lines[i]) break; if (e_next == e) { /* * Special case: we might have come all the * way round a loop and found our way back to * the same edge we started from. In that * situation, we must terminate not only this * while loop, but the 'for' outside it that * was tracing in both directions from the * starting edge, because if we let it trace * in the second direction then we'll only * find ourself traversing the same loop in * the other order and generate an encoded * move string that mentions the same set of * edges twice. */ goto autofollow_done; } dot = (e_next->dot1 != dot ? e_next->dot1 : e_next->dot2); if (movelen > movesize - 40) { movesize = movesize * 5 / 4 + 128; movebuf = sresize(movebuf, movesize, char); } e_this = e_next; movelen += sprintf(movebuf+movelen, "%d%c", (int)(e_this - g->edges), button_char); } } autofollow_done:; } } return sresize(movebuf, movelen+1, char); } static game_state *execute_move(const game_state *state, const char *move) { int i; game_state *newstate = dup_game(state); if (move[0] == 'S') { move++; newstate->cheated = TRUE; } while (*move) { i = atoi(move); if (i < 0 || i >= newstate->game_grid->num_edges) goto fail; move += strspn(move, "1234567890"); switch (*(move++)) { case 'y': newstate->lines[i] = LINE_YES; break; case 'n': newstate->lines[i] = LINE_NO; break; case 'u': newstate->lines[i] = LINE_UNKNOWN; break; default: goto fail; } } /* * Check for completion. */ if (check_completion(newstate)) newstate->solved = TRUE; return newstate; fail: free_game(newstate); return NULL; } /* ---------------------------------------------------------------------- * Drawing routines. */ /* Convert from grid coordinates to screen coordinates */ static void grid_to_screen(const game_drawstate *ds, const grid *g, int grid_x, int grid_y, int *x, int *y) { *x = grid_x - g->lowest_x; *y = grid_y - g->lowest_y; *x = *x * ds->tilesize / g->tilesize; *y = *y * ds->tilesize / g->tilesize; *x += BORDER(ds->tilesize); *y += BORDER(ds->tilesize); } /* Returns (into x,y) position of centre of face for rendering the text clue. */ static void face_text_pos(const game_drawstate *ds, const grid *g, grid_face *f, int *xret, int *yret) { int faceindex = f - g->faces; /* * Return the cached position for this face, if we've already * worked it out. */ if (ds->textx[faceindex] >= 0) { *xret = ds->textx[faceindex]; *yret = ds->texty[faceindex]; return; } /* * Otherwise, use the incentre computed by grid.c and convert it * to screen coordinates. */ grid_find_incentre(f); grid_to_screen(ds, g, f->ix, f->iy, &ds->textx[faceindex], &ds->texty[faceindex]); *xret = ds->textx[faceindex]; *yret = ds->texty[faceindex]; } static void face_text_bbox(game_drawstate *ds, grid *g, grid_face *f, int *x, int *y, int *w, int *h) { int xx, yy; face_text_pos(ds, g, f, &xx, &yy); /* There seems to be a certain amount of trial-and-error involved * in working out the correct bounding-box for the text. */ *x = xx - ds->tilesize/4 - 1; *y = yy - ds->tilesize/4 - 3; *w = ds->tilesize/2 + 2; *h = ds->tilesize/2 + 5; } static void game_redraw_clue(drawing *dr, game_drawstate *ds, const game_state *state, int i) { grid *g = state->game_grid; grid_face *f = g->faces + i; int x, y; char c[20]; sprintf(c, "%d", state->clues[i]); face_text_pos(ds, g, f, &x, &y); draw_text(dr, x, y, FONT_VARIABLE, ds->tilesize/2, ALIGN_VCENTRE | ALIGN_HCENTRE, ds->clue_error[i] ? COL_MISTAKE : ds->clue_satisfied[i] ? COL_SATISFIED : COL_FOREGROUND, c); } static void edge_bbox(game_drawstate *ds, grid *g, grid_edge *e, int *x, int *y, int *w, int *h) { int x1 = e->dot1->x; int y1 = e->dot1->y; int x2 = e->dot2->x; int y2 = e->dot2->y; int xmin, xmax, ymin, ymax; grid_to_screen(ds, g, x1, y1, &x1, &y1); grid_to_screen(ds, g, x2, y2, &x2, &y2); /* Allow extra margin for dots, and thickness of lines */ xmin = min(x1, x2) - 2; xmax = max(x1, x2) + 2; ymin = min(y1, y2) - 2; ymax = max(y1, y2) + 2; *x = xmin; *y = ymin; *w = xmax - xmin + 1; *h = ymax - ymin + 1; } static void dot_bbox(game_drawstate *ds, grid *g, grid_dot *d, int *x, int *y, int *w, int *h) { int x1, y1; grid_to_screen(ds, g, d->x, d->y, &x1, &y1); *x = x1 - 2; *y = y1 - 2; *w = 5; *h = 5; } static const int loopy_line_redraw_phases[] = { COL_FAINT, COL_LINEUNKNOWN, COL_FOREGROUND, COL_HIGHLIGHT, COL_MISTAKE }; #define NPHASES lenof(loopy_line_redraw_phases) static void game_redraw_line(drawing *dr, game_drawstate *ds, const game_state *state, int i, int phase) { grid *g = state->game_grid; grid_edge *e = g->edges + i; int x1, x2, y1, y2; int line_colour; if (state->line_errors[i]) line_colour = COL_MISTAKE; else if (state->lines[i] == LINE_UNKNOWN) line_colour = COL_LINEUNKNOWN; else if (state->lines[i] == LINE_NO) line_colour = COL_FAINT; else if (ds->flashing) line_colour = COL_HIGHLIGHT; else line_colour = COL_FOREGROUND; if (line_colour != loopy_line_redraw_phases[phase]) return; /* Convert from grid to screen coordinates */ grid_to_screen(ds, g, e->dot1->x, e->dot1->y, &x1, &y1); grid_to_screen(ds, g, e->dot2->x, e->dot2->y, &x2, &y2); if (line_colour == COL_FAINT) { static int draw_faint_lines = -1; if (draw_faint_lines < 0) { char *env = getenv("LOOPY_FAINT_LINES"); draw_faint_lines = (!env || (env[0] == 'y' || env[0] == 'Y')); } if (draw_faint_lines) draw_line(dr, x1, y1, x2, y2, line_colour); } else { draw_thick_line(dr, 3.0, x1 + 0.5, y1 + 0.5, x2 + 0.5, y2 + 0.5, line_colour); } } static void game_redraw_dot(drawing *dr, game_drawstate *ds, const game_state *state, int i) { grid *g = state->game_grid; grid_dot *d = g->dots + i; int x, y; grid_to_screen(ds, g, d->x, d->y, &x, &y); draw_circle(dr, x, y, 2, COL_FOREGROUND, COL_FOREGROUND); } static int boxes_intersect(int x0, int y0, int w0, int h0, int x1, int y1, int w1, int h1) { /* * Two intervals intersect iff neither is wholly on one side of * the other. Two boxes intersect iff their horizontal and * vertical intervals both intersect. */ return (x0 < x1+w1 && x1 < x0+w0 && y0 < y1+h1 && y1 < y0+h0); } static void game_redraw_in_rect(drawing *dr, game_drawstate *ds, const game_state *state, int x, int y, int w, int h) { grid *g = state->game_grid; int i, phase; int bx, by, bw, bh; clip(dr, x, y, w, h); draw_rect(dr, x, y, w, h, COL_BACKGROUND); for (i = 0; i < g->num_faces; i++) { if (state->clues[i] >= 0) { face_text_bbox(ds, g, &g->faces[i], &bx, &by, &bw, &bh); if (boxes_intersect(x, y, w, h, bx, by, bw, bh)) game_redraw_clue(dr, ds, state, i); } } for (phase = 0; phase < NPHASES; phase++) { for (i = 0; i < g->num_edges; i++) { edge_bbox(ds, g, &g->edges[i], &bx, &by, &bw, &bh); if (boxes_intersect(x, y, w, h, bx, by, bw, bh)) game_redraw_line(dr, ds, state, i, phase); } } for (i = 0; i < g->num_dots; i++) { dot_bbox(ds, g, &g->dots[i], &bx, &by, &bw, &bh); if (boxes_intersect(x, y, w, h, bx, by, bw, bh)) game_redraw_dot(dr, ds, state, i); } unclip(dr); draw_update(dr, x, y, w, h); } static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float animtime, float flashtime) { #define REDRAW_OBJECTS_LIMIT 16 /* Somewhat arbitrary tradeoff */ grid *g = state->game_grid; int border = BORDER(ds->tilesize); int i; int flash_changed; int redraw_everything = FALSE; int edges[REDRAW_OBJECTS_LIMIT], nedges = 0; int faces[REDRAW_OBJECTS_LIMIT], nfaces = 0; /* Redrawing is somewhat involved. * * An update can theoretically affect an arbitrary number of edges * (consider, for example, completing or breaking a cycle which doesn't * satisfy all the clues -- we'll switch many edges between error and * normal states). On the other hand, redrawing the whole grid takes a * while, making the game feel sluggish, and many updates are actually * quite well localized. * * This redraw algorithm attempts to cope with both situations gracefully * and correctly. For localized changes, we set a clip rectangle, fill * it with background, and then redraw (a plausible but conservative * guess at) the objects which intersect the rectangle; if several * objects need redrawing, we'll do them individually. However, if lots * of objects are affected, we'll just redraw everything. * * The reason for all of this is that it's just not safe to do the redraw * piecemeal. If you try to draw an antialiased diagonal line over * itself, you get a slightly thicker antialiased diagonal line, which * looks rather ugly after a while. * * So, we take two passes over the grid. The first attempts to work out * what needs doing, and the second actually does it. */ if (!ds->started) { redraw_everything = TRUE; /* * But we must still go through the upcoming loops, so that we * set up stuff in ds correctly for the initial redraw. */ } /* First, trundle through the faces. */ for (i = 0; i < g->num_faces; i++) { grid_face *f = g->faces + i; int sides = f->order; int yes_order, no_order; int clue_mistake; int clue_satisfied; int n = state->clues[i]; if (n < 0) continue; yes_order = face_order(state, i, LINE_YES); if (state->exactly_one_loop) { /* * Special case: if the set of LINE_YES edges in the grid * consists of exactly one loop and nothing else, then we * switch to treating LINE_UNKNOWN the same as LINE_NO for * purposes of clue checking. * * This is because some people like to play Loopy without * using the right-click, i.e. never setting anything to * LINE_NO. Without this special case, if a person playing * in that style fills in what they think is a correct * solution loop but in fact it has an underfilled clue, * then we will display no victory flash and also no error * highlight explaining why not. With this special case, * we light up underfilled clues at the instant the loop * is closed. (Of course, *overfilled* clues are fine * either way.) * * (It might still be considered unfortunate that we can't * warn this style of player any earlier, if they make a * mistake very near the beginning which doesn't show up * until they close the last edge of the loop. One other * thing we _could_ do here is to treat any LINE_UNKNOWN * as LINE_NO if either of its endpoints has yes-degree 2, * reflecting the fact that setting that line to YES would * be an obvious error. But I don't think even that could * catch _all_ clue errors in a timely manner; I think * there are some that won't be displayed until the loop * is filled in, even so, and there's no way to avoid that * with complete reliability except to switch to being a * player who sets things to LINE_NO.) */ no_order = sides - yes_order; } else { no_order = face_order(state, i, LINE_NO); } clue_mistake = (yes_order > n || no_order > (sides-n)); clue_satisfied = (yes_order == n && no_order == (sides-n)); if (clue_mistake != ds->clue_error[i] || clue_satisfied != ds->clue_satisfied[i]) { ds->clue_error[i] = clue_mistake; ds->clue_satisfied[i] = clue_satisfied; if (nfaces == REDRAW_OBJECTS_LIMIT) redraw_everything = TRUE; else faces[nfaces++] = i; } } /* Work out what the flash state needs to be. */ if (flashtime > 0 && (flashtime <= FLASH_TIME/3 || flashtime >= FLASH_TIME*2/3)) { flash_changed = !ds->flashing; ds->flashing = TRUE; } else { flash_changed = ds->flashing; ds->flashing = FALSE; } /* Now, trundle through the edges. */ for (i = 0; i < g->num_edges; i++) { char new_ds = state->line_errors[i] ? DS_LINE_ERROR : state->lines[i]; if (new_ds != ds->lines[i] || (flash_changed && state->lines[i] == LINE_YES)) { ds->lines[i] = new_ds; if (nedges == REDRAW_OBJECTS_LIMIT) redraw_everything = TRUE; else edges[nedges++] = i; } } /* Pass one is now done. Now we do the actual drawing. */ if (redraw_everything) { int grid_width = g->highest_x - g->lowest_x; int grid_height = g->highest_y - g->lowest_y; int w = grid_width * ds->tilesize / g->tilesize; int h = grid_height * ds->tilesize / g->tilesize; game_redraw_in_rect(dr, ds, state, 0, 0, w + 2*border + 1, h + 2*border + 1); } else { /* Right. Now we roll up our sleeves. */ for (i = 0; i < nfaces; i++) { grid_face *f = g->faces + faces[i]; int x, y, w, h; face_text_bbox(ds, g, f, &x, &y, &w, &h); game_redraw_in_rect(dr, ds, state, x, y, w, h); } for (i = 0; i < nedges; i++) { grid_edge *e = g->edges + edges[i]; int x, y, w, h; edge_bbox(ds, g, e, &x, &y, &w, &h); game_redraw_in_rect(dr, ds, state, x, y, w, h); } } ds->started = TRUE; } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { if (!oldstate->solved && newstate->solved && !oldstate->cheated && !newstate->cheated) { return FLASH_TIME; } return 0.0F; } static int game_status(const game_state *state) { return state->solved ? +1 : 0; } static void game_print_size(const game_params *params, float *x, float *y) { int pw, ph; /* * I'll use 7mm "squares" by default. */ game_compute_size(params, 700, &pw, &ph); *x = pw / 100.0F; *y = ph / 100.0F; } static void game_print(drawing *dr, const game_state *state, int tilesize) { int ink = print_mono_colour(dr, 0); int i; game_drawstate ads, *ds = &ads; grid *g = state->game_grid; ds->tilesize = tilesize; ds->textx = snewn(g->num_faces, int); ds->texty = snewn(g->num_faces, int); for (i = 0; i < g->num_faces; i++) ds->textx[i] = ds->texty[i] = -1; for (i = 0; i < g->num_dots; i++) { int x, y; grid_to_screen(ds, g, g->dots[i].x, g->dots[i].y, &x, &y); draw_circle(dr, x, y, ds->tilesize / 15, ink, ink); } /* * Clues. */ for (i = 0; i < g->num_faces; i++) { grid_face *f = g->faces + i; int clue = state->clues[i]; if (clue >= 0) { char c[20]; int x, y; sprintf(c, "%d", state->clues[i]); face_text_pos(ds, g, f, &x, &y); draw_text(dr, x, y, FONT_VARIABLE, ds->tilesize / 2, ALIGN_VCENTRE | ALIGN_HCENTRE, ink, c); } } /* * Lines. */ for (i = 0; i < g->num_edges; i++) { int thickness = (state->lines[i] == LINE_YES) ? 30 : 150; grid_edge *e = g->edges + i; int x1, y1, x2, y2; grid_to_screen(ds, g, e->dot1->x, e->dot1->y, &x1, &y1); grid_to_screen(ds, g, e->dot2->x, e->dot2->y, &x2, &y2); if (state->lines[i] == LINE_YES) { /* (dx, dy) points from (x1, y1) to (x2, y2). * The line is then "fattened" in a perpendicular * direction to create a thin rectangle. */ double d = sqrt(SQ((double)x1 - x2) + SQ((double)y1 - y2)); double dx = (x2 - x1) / d; double dy = (y2 - y1) / d; int points[8]; dx = (dx * ds->tilesize) / thickness; dy = (dy * ds->tilesize) / thickness; points[0] = x1 + (int)dy; points[1] = y1 - (int)dx; points[2] = x1 - (int)dy; points[3] = y1 + (int)dx; points[4] = x2 - (int)dy; points[5] = y2 + (int)dx; points[6] = x2 + (int)dy; points[7] = y2 - (int)dx; draw_polygon(dr, points, 4, ink, ink); } else { /* Draw a dotted line */ int divisions = 6; int j; for (j = 1; j < divisions; j++) { /* Weighted average */ int x = (x1 * (divisions -j) + x2 * j) / divisions; int y = (y1 * (divisions -j) + y2 * j) / divisions; draw_circle(dr, x, y, ds->tilesize / thickness, ink, ink); } } } sfree(ds->textx); sfree(ds->texty); } #ifdef COMBINED #define thegame loopy #endif const struct game thegame = { "Loopy", "games.loopy", "loopy", default_params, NULL, game_preset_menu, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, 1, solve_game, TRUE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, PREFERRED_TILE_SIZE, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, TRUE, FALSE, game_print_size, game_print, FALSE /* wants_statusbar */, FALSE, game_timing_state, 0, /* mouse_priorities */ }; #ifdef STANDALONE_SOLVER /* * Half-hearted standalone solver. It can't output the solution to * anything but a square puzzle, and it can't log the deductions * it makes either. But it can solve square puzzles, and more * importantly it can use its solver to grade the difficulty of * any puzzle you give it. */ #include int main(int argc, char **argv) { game_params *p; game_state *s; char *id = NULL, *desc, *err; int grade = FALSE; int ret, diff; #if 0 /* verbose solver not supported here (yet) */ int really_verbose = FALSE; #endif while (--argc > 0) { char *p = *++argv; #if 0 /* verbose solver not supported here (yet) */ if (!strcmp(p, "-v")) { really_verbose = TRUE; } else #endif if (!strcmp(p, "-g")) { grade = TRUE; } else if (*p == '-') { fprintf(stderr, "%s: unrecognised option `%s'\n", argv[0], p); return 1; } else { id = p; } } if (!id) { fprintf(stderr, "usage: %s [-g | -v] \n", argv[0]); return 1; } desc = strchr(id, ':'); if (!desc) { fprintf(stderr, "%s: game id expects a colon in it\n", argv[0]); return 1; } *desc++ = '\0'; p = default_params(); decode_params(p, id); err = validate_desc(p, desc); if (err) { fprintf(stderr, "%s: %s\n", argv[0], err); return 1; } s = new_game(NULL, p, desc); /* * When solving an Easy puzzle, we don't want to bother the * user with Hard-level deductions. For this reason, we grade * the puzzle internally before doing anything else. */ ret = -1; /* placate optimiser */ for (diff = 0; diff < DIFF_MAX; diff++) { solver_state *sstate_new; solver_state *sstate = new_solver_state((game_state *)s, diff); sstate_new = solve_game_rec(sstate); if (sstate_new->solver_status == SOLVER_MISTAKE) ret = 0; else if (sstate_new->solver_status == SOLVER_SOLVED) ret = 1; else ret = 2; free_solver_state(sstate_new); free_solver_state(sstate); if (ret < 2) break; } if (diff == DIFF_MAX) { if (grade) printf("Difficulty rating: harder than Hard, or ambiguous\n"); else printf("Unable to find a unique solution\n"); } else { if (grade) { if (ret == 0) printf("Difficulty rating: impossible (no solution exists)\n"); else if (ret == 1) printf("Difficulty rating: %s\n", diffnames[diff]); } else { solver_state *sstate_new; solver_state *sstate = new_solver_state((game_state *)s, diff); /* If we supported a verbose solver, we'd set verbosity here */ sstate_new = solve_game_rec(sstate); if (sstate_new->solver_status == SOLVER_MISTAKE) printf("Puzzle is inconsistent\n"); else { assert(sstate_new->solver_status == SOLVER_SOLVED); if (s->grid_type == 0) { fputs(game_text_format(sstate_new->state), stdout); } else { printf("Unable to output non-square grids\n"); } } free_solver_state(sstate_new); free_solver_state(sstate); } } return 0; } #endif /* vim: set shiftwidth=4 tabstop=8: */ puzzles-20170606.272beef/loopgen.c0000644000175000017500000005304413115373615015506 0ustar simonsimon/* * loopgen.c: loop generation functions for grid.[ch]. */ #include #include #include #include #include #include #include #include "puzzles.h" #include "tree234.h" #include "grid.h" #include "loopgen.h" /* We're going to store lists of current candidate faces for colouring black * or white. * Each face gets a 'score', which tells us how adding that face right * now would affect the curliness of the solution loop. We're trying to * maximise that quantity so will bias our random selection of faces to * colour those with high scores */ struct face_score { int white_score; int black_score; unsigned long random; /* No need to store a grid_face* here. The 'face_scores' array will * be a list of 'face_score' objects, one for each face of the grid, so * the position (index) within the 'face_scores' array will determine * which face corresponds to a particular face_score. * Having a single 'face_scores' array for all faces simplifies memory * management, and probably improves performance, because we don't have to * malloc/free each individual face_score, and we don't have to maintain * a mapping from grid_face* pointers to face_score* pointers. */ }; static int generic_sort_cmpfn(void *v1, void *v2, size_t offset) { struct face_score *f1 = v1; struct face_score *f2 = v2; int r; r = *(int *)((char *)f2 + offset) - *(int *)((char *)f1 + offset); if (r) { return r; } if (f1->random < f2->random) return -1; else if (f1->random > f2->random) return 1; /* * It's _just_ possible that two faces might have been given * the same random value. In that situation, fall back to * comparing based on the positions within the face_scores list. * This introduces a tiny directional bias, but not a significant one. */ return f1 - f2; } static int white_sort_cmpfn(void *v1, void *v2) { return generic_sort_cmpfn(v1, v2, offsetof(struct face_score,white_score)); } static int black_sort_cmpfn(void *v1, void *v2) { return generic_sort_cmpfn(v1, v2, offsetof(struct face_score,black_score)); } /* 'board' is an array of enum face_colour, indicating which faces are * currently black/white/grey. 'colour' is FACE_WHITE or FACE_BLACK. * Returns whether it's legal to colour the given face with this colour. */ static int can_colour_face(grid *g, char* board, int face_index, enum face_colour colour) { int i, j; grid_face *test_face = g->faces + face_index; grid_face *starting_face, *current_face; grid_dot *starting_dot; int transitions; int current_state, s; /* booleans: equal or not-equal to 'colour' */ int found_same_coloured_neighbour = FALSE; assert(board[face_index] != colour); /* Can only consider a face for colouring if it's adjacent to a face * with the same colour. */ for (i = 0; i < test_face->order; i++) { grid_edge *e = test_face->edges[i]; grid_face *f = (e->face1 == test_face) ? e->face2 : e->face1; if (FACE_COLOUR(f) == colour) { found_same_coloured_neighbour = TRUE; break; } } if (!found_same_coloured_neighbour) return FALSE; /* Need to avoid creating a loop of faces of this colour around some * differently-coloured faces. * Also need to avoid meeting a same-coloured face at a corner, with * other-coloured faces in between. Here's a simple test that (I believe) * takes care of both these conditions: * * Take the circular path formed by this face's edges, and inflate it * slightly outwards. Imagine walking around this path and consider * the faces that you visit in sequence. This will include all faces * touching the given face, either along an edge or just at a corner. * Count the number of 'colour'/not-'colour' transitions you encounter, as * you walk along the complete loop. This will obviously turn out to be * an even number. * If 0, we're either in the middle of an "island" of this colour (should * be impossible as we're not supposed to create black or white loops), * or we're about to start a new island - also not allowed. * If 4 or greater, there are too many separate coloured regions touching * this face, and colouring it would create a loop or a corner-violation. * The only allowed case is when the count is exactly 2. */ /* i points to a dot around the test face. * j points to a face around the i^th dot. * The current face will always be: * test_face->dots[i]->faces[j] * We assume dots go clockwise around the test face, * and faces go clockwise around dots. */ /* * The end condition is slightly fiddly. In sufficiently strange * degenerate grids, our test face may be adjacent to the same * other face multiple times (typically if it's the exterior * face). Consider this, in particular: * * +--+ * | | * +--+--+ * | | | * +--+--+ * * The bottom left face there is adjacent to the exterior face * twice, so we can't just terminate our iteration when we reach * the same _face_ we started at. Furthermore, we can't * condition on having the same (i,j) pair either, because * several (i,j) pairs identify the bottom left contiguity with * the exterior face! We canonicalise the (i,j) pair by taking * one step around before we set the termination tracking. */ i = j = 0; current_face = test_face->dots[0]->faces[0]; if (current_face == test_face) { j = 1; current_face = test_face->dots[0]->faces[1]; } transitions = 0; current_state = (FACE_COLOUR(current_face) == colour); starting_dot = NULL; starting_face = NULL; while (TRUE) { /* Advance to next face. * Need to loop here because it might take several goes to * find it. */ while (TRUE) { j++; if (j == test_face->dots[i]->order) j = 0; if (test_face->dots[i]->faces[j] == test_face) { /* Advance to next dot round test_face, then * find current_face around new dot * and advance to the next face clockwise */ i++; if (i == test_face->order) i = 0; for (j = 0; j < test_face->dots[i]->order; j++) { if (test_face->dots[i]->faces[j] == current_face) break; } /* Must actually find current_face around new dot, * or else something's wrong with the grid. */ assert(j != test_face->dots[i]->order); /* Found, so advance to next face and try again */ } else { break; } } /* (i,j) are now advanced to next face */ current_face = test_face->dots[i]->faces[j]; s = (FACE_COLOUR(current_face) == colour); if (!starting_dot) { starting_dot = test_face->dots[i]; starting_face = current_face; current_state = s; } else { if (s != current_state) { ++transitions; current_state = s; if (transitions > 2) break; } if (test_face->dots[i] == starting_dot && current_face == starting_face) break; } } return (transitions == 2) ? TRUE : FALSE; } /* Count the number of neighbours of 'face', having colour 'colour' */ static int face_num_neighbours(grid *g, char *board, grid_face *face, enum face_colour colour) { int colour_count = 0; int i; grid_face *f; grid_edge *e; for (i = 0; i < face->order; i++) { e = face->edges[i]; f = (e->face1 == face) ? e->face2 : e->face1; if (FACE_COLOUR(f) == colour) ++colour_count; } return colour_count; } /* The 'score' of a face reflects its current desirability for selection * as the next face to colour white or black. We want to encourage moving * into grey areas and increasing loopiness, so we give scores according to * how many of the face's neighbours are currently coloured the same as the * proposed colour. */ static int face_score(grid *g, char *board, grid_face *face, enum face_colour colour) { /* Simple formula: score = 0 - num. same-coloured neighbours, * so a higher score means fewer same-coloured neighbours. */ return -face_num_neighbours(g, board, face, colour); } /* * Generate a new complete random closed loop for the given grid. * * The method is to generate a WHITE/BLACK colouring of all the faces, * such that the WHITE faces will define the inside of the path, and the * BLACK faces define the outside. * To do this, we initially colour all faces GREY. The infinite space outside * the grid is coloured BLACK, and we choose a random face to colour WHITE. * Then we gradually grow the BLACK and the WHITE regions, eliminating GREY * faces, until the grid is filled with BLACK/WHITE. As we grow the regions, * we avoid creating loops of a single colour, to preserve the topological * shape of the WHITE and BLACK regions. * We also try to make the boundary as loopy and twisty as possible, to avoid * generating paths that are uninteresting. * The algorithm works by choosing a BLACK/WHITE colour, then choosing a GREY * face that can be coloured with that colour (without violating the * topological shape of that region). It's not obvious, but I think this * algorithm is guaranteed to terminate without leaving any GREY faces behind. * Indeed, if there are any GREY faces at all, both the WHITE and BLACK * regions can be grown. * This is checked using assert()ions, and I haven't seen any failures yet. * * Hand-wavy proof: imagine what can go wrong... * * Could the white faces get completely cut off by the black faces, and still * leave some grey faces remaining? * No, because then the black faces would form a loop around both the white * faces and the grey faces, which is disallowed because we continually * maintain the correct topological shape of the black region. * Similarly, the black faces can never get cut off by the white faces. That * means both the WHITE and BLACK regions always have some room to grow into * the GREY regions. * Could it be that we can't colour some GREY face, because there are too many * WHITE/BLACK transitions as we walk round the face? (see the * can_colour_face() function for details) * No. Imagine otherwise, and we see WHITE/BLACK/WHITE/BLACK as we walk * around the face. The two WHITE faces would be connected by a WHITE path, * and the BLACK faces would be connected by a BLACK path. These paths would * have to cross, which is impossible. * Another thing that could go wrong: perhaps we can't find any GREY face to * colour WHITE, because it would create a loop-violation or a corner-violation * with the other WHITE faces? * This is a little bit tricky to prove impossible. Imagine you have such a * GREY face (that is, if you coloured it WHITE, you would create a WHITE loop * or corner violation). * That would cut all the non-white area into two blobs. One of those blobs * must be free of BLACK faces (because the BLACK stuff is a connected blob). * So we have a connected GREY area, completely surrounded by WHITE * (including the GREY face we've tentatively coloured WHITE). * A well-known result in graph theory says that you can always find a GREY * face whose removal leaves the remaining GREY area connected. And it says * there are at least two such faces, so we can always choose the one that * isn't the "tentative" GREY face. Colouring that face WHITE leaves * everything nice and connected, including that "tentative" GREY face which * acts as a gateway to the rest of the non-WHITE grid. */ void generate_loop(grid *g, char *board, random_state *rs, loopgen_bias_fn_t bias, void *biasctx) { int i, j; int num_faces = g->num_faces; struct face_score *face_scores; /* Array of face_score objects */ struct face_score *fs; /* Points somewhere in the above list */ struct grid_face *cur_face; tree234 *lightable_faces_sorted; tree234 *darkable_faces_sorted; int *face_list; int do_random_pass; /* Make a board */ memset(board, FACE_GREY, num_faces); /* Create and initialise the list of face_scores */ face_scores = snewn(num_faces, struct face_score); for (i = 0; i < num_faces; i++) { face_scores[i].random = random_bits(rs, 31); face_scores[i].black_score = face_scores[i].white_score = 0; } /* Colour a random, finite face white. The infinite face is implicitly * coloured black. Together, they will seed the random growth process * for the black and white areas. */ i = random_upto(rs, num_faces); board[i] = FACE_WHITE; /* We need a way of favouring faces that will increase our loopiness. * We do this by maintaining a list of all candidate faces sorted by * their score and choose randomly from that with appropriate skew. * In order to avoid consistently biasing towards particular faces, we * need the sort order _within_ each group of scores to be completely * random. But it would be abusing the hospitality of the tree234 data * structure if our comparison function were nondeterministic :-). So with * each face we associate a random number that does not change during a * particular run of the generator, and use that as a secondary sort key. * Yes, this means we will be biased towards particular random faces in * any one run but that doesn't actually matter. */ lightable_faces_sorted = newtree234(white_sort_cmpfn); darkable_faces_sorted = newtree234(black_sort_cmpfn); /* Initialise the lists of lightable and darkable faces. This is * slightly different from the code inside the while-loop, because we need * to check every face of the board (the grid structure does not keep a * list of the infinite face's neighbours). */ for (i = 0; i < num_faces; i++) { grid_face *f = g->faces + i; struct face_score *fs = face_scores + i; if (board[i] != FACE_GREY) continue; /* We need the full colourability check here, it's not enough simply * to check neighbourhood. On some grids, a neighbour of the infinite * face is not necessarily darkable. */ if (can_colour_face(g, board, i, FACE_BLACK)) { fs->black_score = face_score(g, board, f, FACE_BLACK); add234(darkable_faces_sorted, fs); } if (can_colour_face(g, board, i, FACE_WHITE)) { fs->white_score = face_score(g, board, f, FACE_WHITE); add234(lightable_faces_sorted, fs); } } /* Colour faces one at a time until no more faces are colourable. */ while (TRUE) { enum face_colour colour; tree234 *faces_to_pick; int c_lightable = count234(lightable_faces_sorted); int c_darkable = count234(darkable_faces_sorted); if (c_lightable == 0 && c_darkable == 0) { /* No more faces we can use at all. */ break; } assert(c_lightable != 0 && c_darkable != 0); /* Choose a colour, and colour the best available face * with that colour. */ colour = random_upto(rs, 2) ? FACE_WHITE : FACE_BLACK; if (colour == FACE_WHITE) faces_to_pick = lightable_faces_sorted; else faces_to_pick = darkable_faces_sorted; if (bias) { /* * Go through all the candidate faces and pick the one the * bias function likes best, breaking ties using the * ordering in our tree234 (which is why we replace only * if score > bestscore, not >=). */ int j, k; struct face_score *best = NULL; int score, bestscore = 0; for (j = 0; (fs = (struct face_score *)index234(faces_to_pick, j))!=NULL; j++) { assert(fs); k = fs - face_scores; assert(board[k] == FACE_GREY); board[k] = colour; score = bias(biasctx, board, k); board[k] = FACE_GREY; bias(biasctx, board, k); /* let bias know we put it back */ if (!best || score > bestscore) { bestscore = score; best = fs; } } fs = best; } else { fs = (struct face_score *)index234(faces_to_pick, 0); } assert(fs); i = fs - face_scores; assert(board[i] == FACE_GREY); board[i] = colour; if (bias) bias(biasctx, board, i); /* notify bias function of the change */ /* Remove this newly-coloured face from the lists. These lists should * only contain grey faces. */ del234(lightable_faces_sorted, fs); del234(darkable_faces_sorted, fs); /* Remember which face we've just coloured */ cur_face = g->faces + i; /* The face we've just coloured potentially affects the colourability * and the scores of any neighbouring faces (touching at a corner or * edge). So the search needs to be conducted around all faces * touching the one we've just lit. Iterate over its corners, then * over each corner's faces. For each such face, we remove it from * the lists, recalculate any scores, then add it back to the lists * (depending on whether it is lightable, darkable or both). */ for (i = 0; i < cur_face->order; i++) { grid_dot *d = cur_face->dots[i]; for (j = 0; j < d->order; j++) { grid_face *f = d->faces[j]; int fi; /* face index of f */ if (f == NULL) continue; if (f == cur_face) continue; /* If the face is already coloured, it won't be on our * lightable/darkable lists anyway, so we can skip it without * bothering with the removal step. */ if (FACE_COLOUR(f) != FACE_GREY) continue; /* Find the face index and face_score* corresponding to f */ fi = f - g->faces; fs = face_scores + fi; /* Remove from lightable list if it's in there. We do this, * even if it is still lightable, because the score might * be different, and we need to remove-then-add to maintain * correct sort order. */ del234(lightable_faces_sorted, fs); if (can_colour_face(g, board, fi, FACE_WHITE)) { fs->white_score = face_score(g, board, f, FACE_WHITE); add234(lightable_faces_sorted, fs); } /* Do the same for darkable list. */ del234(darkable_faces_sorted, fs); if (can_colour_face(g, board, fi, FACE_BLACK)) { fs->black_score = face_score(g, board, f, FACE_BLACK); add234(darkable_faces_sorted, fs); } } } } /* Clean up */ freetree234(lightable_faces_sorted); freetree234(darkable_faces_sorted); sfree(face_scores); /* The next step requires a shuffled list of all faces */ face_list = snewn(num_faces, int); for (i = 0; i < num_faces; ++i) { face_list[i] = i; } shuffle(face_list, num_faces, sizeof(int), rs); /* The above loop-generation algorithm can often leave large clumps * of faces of one colour. In extreme cases, the resulting path can be * degenerate and not very satisfying to solve. * This next step alleviates this problem: * Go through the shuffled list, and flip the colour of any face we can * legally flip, and which is adjacent to only one face of the opposite * colour - this tends to grow 'tendrils' into any clumps. * Repeat until we can find no more faces to flip. This will * eventually terminate, because each flip increases the loop's * perimeter, which cannot increase for ever. * The resulting path will have maximal loopiness (in the sense that it * cannot be improved "locally". Unfortunately, this allows a player to * make some illicit deductions. To combat this (and make the path more * interesting), we do one final pass making random flips. */ /* Set to TRUE for final pass */ do_random_pass = FALSE; while (TRUE) { /* Remember whether a flip occurred during this pass */ int flipped = FALSE; for (i = 0; i < num_faces; ++i) { int j = face_list[i]; enum face_colour opp = (board[j] == FACE_WHITE) ? FACE_BLACK : FACE_WHITE; if (can_colour_face(g, board, j, opp)) { grid_face *face = g->faces +j; if (do_random_pass) { /* final random pass */ if (!random_upto(rs, 10)) board[j] = opp; } else { /* normal pass - flip when neighbour count is 1 */ if (face_num_neighbours(g, board, face, opp) == 1) { board[j] = opp; flipped = TRUE; } } } } if (do_random_pass) break; if (!flipped) do_random_pass = TRUE; } sfree(face_list); } puzzles-20170606.272beef/list.c0000644000175000017500000000211313115375145015005 0ustar simonsimon/* * list.c: List of pointers to puzzle structures, for monolithic * platforms. * * This file is automatically generated by mkfiles.pl. Do not edit * it directly, or the changes will be lost next time mkfiles.pl runs. * Instead, edit Recipe and/or its *.R subfiles. */ #include "puzzles.h" #define GAMELIST(A) \ A(blackbox) \ A(bridges) \ A(cube) \ A(dominosa) \ A(fifteen) \ A(filling) \ A(flip) \ A(flood) \ A(galaxies) \ A(guess) \ A(inertia) \ A(keen) \ A(lightup) \ A(loopy) \ A(magnets) \ A(map) \ A(mines) \ A(net) \ A(netslide) \ A(palisade) \ A(pattern) \ A(pearl) \ A(pegs) \ A(range) \ A(rect) \ A(samegame) \ A(signpost) \ A(singles) \ A(sixteen) \ A(slant) \ A(solo) \ A(tents) \ A(towers) \ A(tracks) \ A(twiddle) \ A(undead) \ A(unequal) \ A(unruly) \ A(untangle) \ #define DECL(x) extern const game x; #define REF(x) &x, GAMELIST(DECL) const game *gamelist[] = { GAMELIST(REF) }; const int gamecount = lenof(gamelist); puzzles-20170606.272beef/lightup.c0000644000175000017500000022423313115373615015517 0ustar simonsimon/* * lightup.c: Implementation of the Nikoli game 'Light Up'. * * Possible future solver enhancements: * * - In a situation where two clues are diagonally adjacent, you can * deduce bounds on the number of lights shared between them. For * instance, suppose a 3 clue is diagonally adjacent to a 1 clue: * of the two squares adjacent to both clues, at least one must be * a light (or the 3 would be unsatisfiable) and yet at most one * must be a light (or the 1 would be overcommitted), so in fact * _exactly_ one must be a light, and hence the other two squares * adjacent to the 3 must also be lights and the other two adjacent * to the 1 must not. Likewise if the 3 is replaced with a 2 but * one of its other two squares is known not to be a light, and so * on. * * - In a situation where two clues are orthogonally separated (not * necessarily directly adjacent), you may be able to deduce * something about the squares that align with each other. For * instance, suppose two clues are vertically adjacent. Consider * the pair of squares A,B horizontally adjacent to the top clue, * and the pair C,D horizontally adjacent to the bottom clue. * Assuming no intervening obstacles, A and C align with each other * and hence at most one of them can be a light, and B and D * likewise, so we must have at most two lights between the four * squares. So if the clues indicate that there are at _least_ two * lights in those four squares because the top clue requires at * least one of AB to be a light and the bottom one requires at * least one of CD, then we can in fact deduce that there are * _exactly_ two lights between the four squares, and fill in the * other squares adjacent to each clue accordingly. For instance, * if both clues are 3s, then we instantly deduce that all four of * the squares _vertically_ adjacent to the two clues must be * lights. (For that to happen, of course, there'd also have to be * a black square in between the clues, so the two inner lights * don't light each other.) * * - I haven't thought it through carefully, but there's always the * possibility that both of the above deductions are special cases * of some more general pattern which can be made computationally * feasible... */ #include #include #include #include #include #include #include "puzzles.h" /* * In standalone solver mode, `verbose' is a variable which can be * set by command-line option; in debugging mode it's simply always * true. */ #if defined STANDALONE_SOLVER #define SOLVER_DIAGNOSTICS int verbose = 0; #undef debug #define debug(x) printf x #elif defined SOLVER_DIAGNOSTICS #define verbose 2 #endif /* --- Constants, structure definitions, etc. --- */ #define PREFERRED_TILE_SIZE 32 #define TILE_SIZE (ds->tilesize) #define BORDER (TILE_SIZE / 2) #define TILE_RADIUS (ds->crad) #define COORD(x) ( (x) * TILE_SIZE + BORDER ) #define FROMCOORD(x) ( ((x) - BORDER + TILE_SIZE) / TILE_SIZE - 1 ) #define FLASH_TIME 0.30F enum { COL_BACKGROUND, COL_GRID, COL_BLACK, /* black */ COL_LIGHT, /* white */ COL_LIT, /* yellow */ COL_ERROR, /* red */ COL_CURSOR, NCOLOURS }; enum { SYMM_NONE, SYMM_REF2, SYMM_ROT2, SYMM_REF4, SYMM_ROT4, SYMM_MAX }; #define DIFFCOUNT 2 struct game_params { int w, h; int blackpc; /* %age of black squares */ int symm; int difficulty; /* 0 to DIFFCOUNT */ }; #define F_BLACK 1 /* flags for black squares */ #define F_NUMBERED 2 /* it has a number attached */ #define F_NUMBERUSED 4 /* this number was useful for solving */ /* flags for non-black squares */ #define F_IMPOSSIBLE 8 /* can't put a light here */ #define F_LIGHT 16 #define F_MARK 32 struct game_state { int w, h, nlights; int *lights; /* For black squares, (optionally) the number of surrounding lights. For non-black squares, the number of times it's lit. size h*w*/ unsigned int *flags; /* size h*w */ int completed, used_solve; }; #define GRID(gs,grid,x,y) (gs->grid[(y)*((gs)->w) + (x)]) /* A ll_data holds information about which lights would be lit by * a particular grid location's light (or conversely, which locations * could light a specific other location). */ /* most things should consider this struct opaque. */ typedef struct { int ox,oy; int minx, maxx, miny, maxy; int include_origin; } ll_data; /* Macro that executes 'block' once per light in lld, including * the origin if include_origin is specified. 'block' can use * lx and ly as the coords. */ #define FOREACHLIT(lld,block) do { \ int lx,ly; \ ly = (lld)->oy; \ for (lx = (lld)->minx; lx <= (lld)->maxx; lx++) { \ if (lx == (lld)->ox) continue; \ block \ } \ lx = (lld)->ox; \ for (ly = (lld)->miny; ly <= (lld)->maxy; ly++) { \ if (!(lld)->include_origin && ly == (lld)->oy) continue; \ block \ } \ } while(0) typedef struct { struct { int x, y; unsigned int f; } points[4]; int npoints; } surrounds; /* Fills in (doesn't allocate) a surrounds structure with the grid locations * around a given square, taking account of the edges. */ static void get_surrounds(const game_state *state, int ox, int oy, surrounds *s) { assert(ox >= 0 && ox < state->w && oy >= 0 && oy < state->h); s->npoints = 0; #define ADDPOINT(cond,nx,ny) do {\ if (cond) { \ s->points[s->npoints].x = (nx); \ s->points[s->npoints].y = (ny); \ s->points[s->npoints].f = 0; \ s->npoints++; \ } } while(0) ADDPOINT(ox > 0, ox-1, oy); ADDPOINT(ox < (state->w-1), ox+1, oy); ADDPOINT(oy > 0, ox, oy-1); ADDPOINT(oy < (state->h-1), ox, oy+1); } /* --- Game parameter functions --- */ #define DEFAULT_PRESET 0 const struct game_params lightup_presets[] = { { 7, 7, 20, SYMM_ROT4, 0 }, { 7, 7, 20, SYMM_ROT4, 1 }, { 7, 7, 20, SYMM_ROT4, 2 }, { 10, 10, 20, SYMM_ROT2, 0 }, { 10, 10, 20, SYMM_ROT2, 1 }, #ifdef SLOW_SYSTEM { 12, 12, 20, SYMM_ROT2, 0 }, { 12, 12, 20, SYMM_ROT2, 1 }, #else { 10, 10, 20, SYMM_ROT2, 2 }, { 14, 14, 20, SYMM_ROT2, 0 }, { 14, 14, 20, SYMM_ROT2, 1 }, { 14, 14, 20, SYMM_ROT2, 2 } #endif }; static game_params *default_params(void) { game_params *ret = snew(game_params); *ret = lightup_presets[DEFAULT_PRESET]; return ret; } static int game_fetch_preset(int i, char **name, game_params **params) { game_params *ret; char buf[80]; if (i < 0 || i >= lenof(lightup_presets)) return FALSE; ret = default_params(); *ret = lightup_presets[i]; *params = ret; sprintf(buf, "%dx%d %s", ret->w, ret->h, ret->difficulty == 2 ? "hard" : ret->difficulty == 1 ? "tricky" : "easy"); *name = dupstr(buf); return TRUE; } static void free_params(game_params *params) { sfree(params); } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } #define EATNUM(x) do { \ (x) = atoi(string); \ while (*string && isdigit((unsigned char)*string)) string++; \ } while(0) static void decode_params(game_params *params, char const *string) { EATNUM(params->w); if (*string == 'x') { string++; EATNUM(params->h); } if (*string == 'b') { string++; EATNUM(params->blackpc); } if (*string == 's') { string++; EATNUM(params->symm); } else { /* cope with user input such as '18x10' by ensuring symmetry * is not selected by default to be incompatible with dimensions */ if (params->symm == SYMM_ROT4 && params->w != params->h) params->symm = SYMM_ROT2; } params->difficulty = 0; /* cope with old params */ if (*string == 'r') { params->difficulty = 2; string++; } if (*string == 'd') { string++; EATNUM(params->difficulty); } } static char *encode_params(const game_params *params, int full) { char buf[80]; if (full) { sprintf(buf, "%dx%db%ds%dd%d", params->w, params->h, params->blackpc, params->symm, params->difficulty); } else { sprintf(buf, "%dx%d", params->w, params->h); } return dupstr(buf); } static config_item *game_configure(const game_params *params) { config_item *ret; char buf[80]; ret = snewn(6, config_item); ret[0].name = "Width"; ret[0].type = C_STRING; sprintf(buf, "%d", params->w); ret[0].sval = dupstr(buf); ret[0].ival = 0; ret[1].name = "Height"; ret[1].type = C_STRING; sprintf(buf, "%d", params->h); ret[1].sval = dupstr(buf); ret[1].ival = 0; ret[2].name = "%age of black squares"; ret[2].type = C_STRING; sprintf(buf, "%d", params->blackpc); ret[2].sval = dupstr(buf); ret[2].ival = 0; ret[3].name = "Symmetry"; ret[3].type = C_CHOICES; ret[3].sval = ":None" ":2-way mirror:2-way rotational" ":4-way mirror:4-way rotational"; ret[3].ival = params->symm; ret[4].name = "Difficulty"; ret[4].type = C_CHOICES; ret[4].sval = ":Easy:Tricky:Hard"; ret[4].ival = params->difficulty; ret[5].name = NULL; ret[5].type = C_END; ret[5].sval = NULL; ret[5].ival = 0; return ret; } static game_params *custom_params(const config_item *cfg) { game_params *ret = snew(game_params); ret->w = atoi(cfg[0].sval); ret->h = atoi(cfg[1].sval); ret->blackpc = atoi(cfg[2].sval); ret->symm = cfg[3].ival; ret->difficulty = cfg[4].ival; return ret; } static char *validate_params(const game_params *params, int full) { if (params->w < 2 || params->h < 2) return "Width and height must be at least 2"; if (full) { if (params->blackpc < 5 || params->blackpc > 100) return "Percentage of black squares must be between 5% and 100%"; if (params->w != params->h) { if (params->symm == SYMM_ROT4) return "4-fold symmetry is only available with square grids"; } if (params->symm < 0 || params->symm >= SYMM_MAX) return "Unknown symmetry type"; if (params->difficulty < 0 || params->difficulty > DIFFCOUNT) return "Unknown difficulty level"; } return NULL; } /* --- Game state construction/freeing helper functions --- */ static game_state *new_state(const game_params *params) { game_state *ret = snew(game_state); ret->w = params->w; ret->h = params->h; ret->lights = snewn(ret->w * ret->h, int); ret->nlights = 0; memset(ret->lights, 0, ret->w * ret->h * sizeof(int)); ret->flags = snewn(ret->w * ret->h, unsigned int); memset(ret->flags, 0, ret->w * ret->h * sizeof(unsigned int)); ret->completed = ret->used_solve = 0; return ret; } static game_state *dup_game(const game_state *state) { game_state *ret = snew(game_state); ret->w = state->w; ret->h = state->h; ret->lights = snewn(ret->w * ret->h, int); memcpy(ret->lights, state->lights, ret->w * ret->h * sizeof(int)); ret->nlights = state->nlights; ret->flags = snewn(ret->w * ret->h, unsigned int); memcpy(ret->flags, state->flags, ret->w * ret->h * sizeof(unsigned int)); ret->completed = state->completed; ret->used_solve = state->used_solve; return ret; } static void free_game(game_state *state) { sfree(state->lights); sfree(state->flags); sfree(state); } static void debug_state(game_state *state) { int x, y; char c = '?'; for (y = 0; y < state->h; y++) { for (x = 0; x < state->w; x++) { c = '.'; if (GRID(state, flags, x, y) & F_BLACK) { if (GRID(state, flags, x, y) & F_NUMBERED) c = GRID(state, lights, x, y) + '0'; else c = '#'; } else { if (GRID(state, flags, x, y) & F_LIGHT) c = 'O'; else if (GRID(state, flags, x, y) & F_IMPOSSIBLE) c = 'X'; } debug(("%c", (int)c)); } debug((" ")); for (x = 0; x < state->w; x++) { if (GRID(state, flags, x, y) & F_BLACK) c = '#'; else { c = (GRID(state, flags, x, y) & F_LIGHT) ? 'A' : 'a'; c += GRID(state, lights, x, y); } debug(("%c", (int)c)); } debug(("\n")); } } /* --- Game completion test routines. --- */ /* These are split up because occasionally functions are only * interested in one particular aspect. */ /* Returns non-zero if all grid spaces are lit. */ static int grid_lit(game_state *state) { int x, y; for (x = 0; x < state->w; x++) { for (y = 0; y < state->h; y++) { if (GRID(state,flags,x,y) & F_BLACK) continue; if (GRID(state,lights,x,y) == 0) return 0; } } return 1; } /* Returns non-zero if any lights are lit by other lights. */ static int grid_overlap(game_state *state) { int x, y; for (x = 0; x < state->w; x++) { for (y = 0; y < state->h; y++) { if (!(GRID(state, flags, x, y) & F_LIGHT)) continue; if (GRID(state, lights, x, y) > 1) return 1; } } return 0; } static int number_wrong(const game_state *state, int x, int y) { surrounds s; int i, n, empty, lights = GRID(state, lights, x, y); /* * This function computes the display hint for a number: we * turn the number red if it is definitely wrong. This means * that either * * (a) it has too many lights around it, or * (b) it would have too few lights around it even if all the * plausible squares (not black, lit or F_IMPOSSIBLE) were * filled with lights. */ assert(GRID(state, flags, x, y) & F_NUMBERED); get_surrounds(state, x, y, &s); empty = n = 0; for (i = 0; i < s.npoints; i++) { if (GRID(state,flags,s.points[i].x,s.points[i].y) & F_LIGHT) { n++; continue; } if (GRID(state,flags,s.points[i].x,s.points[i].y) & F_BLACK) continue; if (GRID(state,flags,s.points[i].x,s.points[i].y) & F_IMPOSSIBLE) continue; if (GRID(state,lights,s.points[i].x,s.points[i].y)) continue; empty++; } return (n > lights || (n + empty < lights)); } static int number_correct(game_state *state, int x, int y) { surrounds s; int n = 0, i, lights = GRID(state, lights, x, y); assert(GRID(state, flags, x, y) & F_NUMBERED); get_surrounds(state, x, y, &s); for (i = 0; i < s.npoints; i++) { if (GRID(state,flags,s.points[i].x,s.points[i].y) & F_LIGHT) n++; } return (n == lights) ? 1 : 0; } /* Returns non-zero if any numbers add up incorrectly. */ static int grid_addsup(game_state *state) { int x, y; for (x = 0; x < state->w; x++) { for (y = 0; y < state->h; y++) { if (!(GRID(state, flags, x, y) & F_NUMBERED)) continue; if (!number_correct(state, x, y)) return 0; } } return 1; } static int grid_correct(game_state *state) { if (grid_lit(state) && !grid_overlap(state) && grid_addsup(state)) return 1; return 0; } /* --- Board initial setup (blacks, lights, numbers) --- */ static void clean_board(game_state *state, int leave_blacks) { int x,y; for (x = 0; x < state->w; x++) { for (y = 0; y < state->h; y++) { if (leave_blacks) GRID(state, flags, x, y) &= F_BLACK; else GRID(state, flags, x, y) = 0; GRID(state, lights, x, y) = 0; } } state->nlights = 0; } static void set_blacks(game_state *state, const game_params *params, random_state *rs) { int x, y, degree = 0, rotate = 0, nblack; int rh, rw, i; int wodd = (state->w % 2) ? 1 : 0; int hodd = (state->h % 2) ? 1 : 0; int xs[4], ys[4]; switch (params->symm) { case SYMM_NONE: degree = 1; rotate = 0; break; case SYMM_ROT2: degree = 2; rotate = 1; break; case SYMM_REF2: degree = 2; rotate = 0; break; case SYMM_ROT4: degree = 4; rotate = 1; break; case SYMM_REF4: degree = 4; rotate = 0; break; default: assert(!"Unknown symmetry type"); } if (params->symm == SYMM_ROT4 && (state->h != state->w)) assert(!"4-fold symmetry unavailable without square grid"); if (degree == 4) { rw = state->w/2; rh = state->h/2; if (!rotate) rw += wodd; /* ... but see below. */ rh += hodd; } else if (degree == 2) { rw = state->w; rh = state->h/2; rh += hodd; } else { rw = state->w; rh = state->h; } /* clear, then randomise, required region. */ clean_board(state, 0); nblack = (rw * rh * params->blackpc) / 100; for (i = 0; i < nblack; i++) { do { x = random_upto(rs,rw); y = random_upto(rs,rh); } while (GRID(state,flags,x,y) & F_BLACK); GRID(state, flags, x, y) |= F_BLACK; } /* Copy required region. */ if (params->symm == SYMM_NONE) return; for (x = 0; x < rw; x++) { for (y = 0; y < rh; y++) { if (degree == 4) { xs[0] = x; ys[0] = y; xs[1] = state->w - 1 - (rotate ? y : x); ys[1] = rotate ? x : y; xs[2] = rotate ? (state->w - 1 - x) : x; ys[2] = state->h - 1 - y; xs[3] = rotate ? y : (state->w - 1 - x); ys[3] = state->h - 1 - (rotate ? x : y); } else { xs[0] = x; ys[0] = y; xs[1] = rotate ? (state->w - 1 - x) : x; ys[1] = state->h - 1 - y; } for (i = 1; i < degree; i++) { GRID(state, flags, xs[i], ys[i]) = GRID(state, flags, xs[0], ys[0]); } } } /* SYMM_ROT4 misses the middle square above; fix that here. */ if (degree == 4 && rotate && wodd && (random_upto(rs,100) <= (unsigned int)params->blackpc)) GRID(state,flags, state->w/2 + wodd - 1, state->h/2 + hodd - 1) |= F_BLACK; #ifdef SOLVER_DIAGNOSTICS if (verbose) debug_state(state); #endif } /* Fills in (does not allocate) a ll_data with all the tiles that would * be illuminated by a light at point (ox,oy). If origin=1 then the * origin is included in this list. */ static void list_lights(game_state *state, int ox, int oy, int origin, ll_data *lld) { int x,y; lld->ox = lld->minx = lld->maxx = ox; lld->oy = lld->miny = lld->maxy = oy; lld->include_origin = origin; y = oy; for (x = ox-1; x >= 0; x--) { if (GRID(state, flags, x, y) & F_BLACK) break; if (x < lld->minx) lld->minx = x; } for (x = ox+1; x < state->w; x++) { if (GRID(state, flags, x, y) & F_BLACK) break; if (x > lld->maxx) lld->maxx = x; } x = ox; for (y = oy-1; y >= 0; y--) { if (GRID(state, flags, x, y) & F_BLACK) break; if (y < lld->miny) lld->miny = y; } for (y = oy+1; y < state->h; y++) { if (GRID(state, flags, x, y) & F_BLACK) break; if (y > lld->maxy) lld->maxy = y; } } /* Makes sure a light is the given state, editing the lights table to suit the * new state if necessary. */ static void set_light(game_state *state, int ox, int oy, int on) { ll_data lld; int diff = 0; assert(!(GRID(state,flags,ox,oy) & F_BLACK)); if (!on && GRID(state,flags,ox,oy) & F_LIGHT) { diff = -1; GRID(state,flags,ox,oy) &= ~F_LIGHT; state->nlights--; } else if (on && !(GRID(state,flags,ox,oy) & F_LIGHT)) { diff = 1; GRID(state,flags,ox,oy) |= F_LIGHT; state->nlights++; } if (diff != 0) { list_lights(state,ox,oy,1,&lld); FOREACHLIT(&lld, GRID(state,lights,lx,ly) += diff; ); } } /* Returns 1 if removing a light at (x,y) would cause a square to go dark. */ static int check_dark(game_state *state, int x, int y) { ll_data lld; list_lights(state, x, y, 1, &lld); FOREACHLIT(&lld, if (GRID(state,lights,lx,ly) == 1) { return 1; } ); return 0; } /* Sets up an initial random correct position (i.e. every * space lit, and no lights lit by other lights) by filling the * grid with lights and then removing lights one by one at random. */ static void place_lights(game_state *state, random_state *rs) { int i, x, y, n, *numindices, wh = state->w*state->h; ll_data lld; numindices = snewn(wh, int); for (i = 0; i < wh; i++) numindices[i] = i; shuffle(numindices, wh, sizeof(*numindices), rs); /* Place a light on all grid squares without lights. */ for (x = 0; x < state->w; x++) { for (y = 0; y < state->h; y++) { GRID(state, flags, x, y) &= ~F_MARK; /* we use this later. */ if (GRID(state, flags, x, y) & F_BLACK) continue; set_light(state, x, y, 1); } } for (i = 0; i < wh; i++) { y = numindices[i] / state->w; x = numindices[i] % state->w; if (!(GRID(state, flags, x, y) & F_LIGHT)) continue; if (GRID(state, flags, x, y) & F_MARK) continue; list_lights(state, x, y, 0, &lld); /* If we're not lighting any lights ourself, don't remove anything. */ n = 0; FOREACHLIT(&lld, if (GRID(state,flags,lx,ly) & F_LIGHT) { n += 1; } ); if (n == 0) continue; /* [1] */ /* Check whether removing lights we're lighting would cause anything * to go dark. */ n = 0; FOREACHLIT(&lld, if (GRID(state,flags,lx,ly) & F_LIGHT) { n += check_dark(state,lx,ly); } ); if (n == 0) { /* No, it wouldn't, so we can remove them all. */ FOREACHLIT(&lld, set_light(state,lx,ly, 0); ); GRID(state,flags,x,y) |= F_MARK; } if (!grid_overlap(state)) { sfree(numindices); return; /* we're done. */ } assert(grid_lit(state)); } /* could get here if the line at [1] continue'd out of the loop. */ if (grid_overlap(state)) { debug_state(state); assert(!"place_lights failed to resolve overlapping lights!"); } sfree(numindices); } /* Fills in all black squares with numbers of adjacent lights. */ static void place_numbers(game_state *state) { int x, y, i, n; surrounds s; for (x = 0; x < state->w; x++) { for (y = 0; y < state->h; y++) { if (!(GRID(state,flags,x,y) & F_BLACK)) continue; get_surrounds(state, x, y, &s); n = 0; for (i = 0; i < s.npoints; i++) { if (GRID(state,flags,s.points[i].x, s.points[i].y) & F_LIGHT) n++; } GRID(state,flags,x,y) |= F_NUMBERED; GRID(state,lights,x,y) = n; } } } /* --- Actual solver, with helper subroutines. --- */ static void tsl_callback(game_state *state, int lx, int ly, int *x, int *y, int *n) { if (GRID(state,flags,lx,ly) & F_IMPOSSIBLE) return; if (GRID(state,lights,lx,ly) > 0) return; *x = lx; *y = ly; (*n)++; } static int try_solve_light(game_state *state, int ox, int oy, unsigned int flags, int lights) { ll_data lld; int sx = 0, sy = 0, n = 0; if (lights > 0) return 0; if (flags & F_BLACK) return 0; /* We have an unlit square; count how many ways there are left to * place a light that lights us (including this square); if only * one, we must put a light there. Squares that could light us * are, of course, the same as the squares we would light... */ list_lights(state, ox, oy, 1, &lld); FOREACHLIT(&lld, { tsl_callback(state, lx, ly, &sx, &sy, &n); }); if (n == 1) { set_light(state, sx, sy, 1); #ifdef SOLVER_DIAGNOSTICS debug(("(%d,%d) can only be lit from (%d,%d); setting to LIGHT\n", ox,oy,sx,sy)); if (verbose) debug_state(state); #endif return 1; } return 0; } static int could_place_light(unsigned int flags, int lights) { if (flags & (F_BLACK | F_IMPOSSIBLE)) return 0; return (lights > 0) ? 0 : 1; } static int could_place_light_xy(game_state *state, int x, int y) { int lights = GRID(state,lights,x,y); unsigned int flags = GRID(state,flags,x,y); return (could_place_light(flags, lights)) ? 1 : 0; } /* For a given number square, determine whether we have enough info * to unambiguously place its lights. */ static int try_solve_number(game_state *state, int nx, int ny, unsigned int nflags, int nlights) { surrounds s; int x, y, nl, ns, i, ret = 0, lights; unsigned int flags; if (!(nflags & F_NUMBERED)) return 0; nl = nlights; get_surrounds(state,nx,ny,&s); ns = s.npoints; /* nl is no. of lights we need to place, ns is no. of spaces we * have to place them in. Try and narrow these down, and mark * points we can ignore later. */ for (i = 0; i < s.npoints; i++) { x = s.points[i].x; y = s.points[i].y; flags = GRID(state,flags,x,y); lights = GRID(state,lights,x,y); if (flags & F_LIGHT) { /* light here already; one less light for one less place. */ nl--; ns--; s.points[i].f |= F_MARK; } else if (!could_place_light(flags, lights)) { ns--; s.points[i].f |= F_MARK; } } if (ns == 0) return 0; /* nowhere to put anything. */ if (nl == 0) { /* we have placed all lights we need to around here; all remaining * surrounds are therefore IMPOSSIBLE. */ GRID(state,flags,nx,ny) |= F_NUMBERUSED; for (i = 0; i < s.npoints; i++) { if (!(s.points[i].f & F_MARK)) { GRID(state,flags,s.points[i].x,s.points[i].y) |= F_IMPOSSIBLE; ret = 1; } } #ifdef SOLVER_DIAGNOSTICS printf("Clue at (%d,%d) full; setting unlit to IMPOSSIBLE.\n", nx,ny); if (verbose) debug_state(state); #endif } else if (nl == ns) { /* we have as many lights to place as spaces; fill them all. */ GRID(state,flags,nx,ny) |= F_NUMBERUSED; for (i = 0; i < s.npoints; i++) { if (!(s.points[i].f & F_MARK)) { set_light(state, s.points[i].x,s.points[i].y, 1); ret = 1; } } #ifdef SOLVER_DIAGNOSTICS printf("Clue at (%d,%d) trivial; setting unlit to LIGHT.\n", nx,ny); if (verbose) debug_state(state); #endif } return ret; } struct setscratch { int x, y; int n; }; #define SCRATCHSZ (state->w+state->h) /* New solver algorithm: overlapping sets can add IMPOSSIBLE flags. * Algorithm thanks to Simon: * * (a) Any square where you can place a light has a set of squares * which would become non-lights as a result. (This includes * squares lit by the first square, and can also include squares * adjacent to the same clue square if the new light is the last * one around that clue.) Call this MAKESDARK(x,y) with (x,y) being * the square you place a light. * (b) Any unlit square has a set of squares on which you could place * a light to illuminate it. (Possibly including itself, of * course.) This set of squares has the property that _at least * one_ of them must contain a light. Sets of this type also arise * from clue squares. Call this MAKESLIGHT(x,y), again with (x,y) * the square you would place a light. * (c) If there exists (dx,dy) and (lx,ly) such that MAKESDARK(dx,dy) is * a superset of MAKESLIGHT(lx,ly), this implies that placing a light at * (dx,dy) would either leave no remaining way to illuminate a certain * square, or would leave no remaining way to fulfill a certain clue * (at lx,ly). In either case, a light can be ruled out at that position. * * So, we construct all possible MAKESLIGHT sets, both from unlit squares * and clue squares, and then we look for plausible MAKESDARK sets that include * our (lx,ly) to see if we can find a (dx,dy) to rule out. By the time we have * constructed the MAKESLIGHT set we don't care about (lx,ly), just the set * members. * * Once we have such a set, Simon came up with a Cunning Plan to find * the most sensible MAKESDARK candidate: * * (a) for each square S in your set X, find all the squares which _would_ * rule it out. That means any square which would light S, plus * any square adjacent to the same clue square as S (provided * that clue square has only one remaining light to be placed). * It's not hard to make this list. Don't do anything with this * data at the moment except _count_ the squares. * (b) Find the square S_min in the original set which has the * _smallest_ number of other squares which would rule it out. * (c) Find all the squares that rule out S_min (it's probably * better to recompute this than to have stored it during step * (a), since the CPU requirement is modest but the storage * cost would get ugly.) For each of these squares, see if it * rules out everything else in the set X. Any which does can * be marked as not-a-light. * */ typedef void (*trl_cb)(game_state *state, int dx, int dy, struct setscratch *scratch, int n, void *ctx); static void try_rule_out(game_state *state, int x, int y, struct setscratch *scratch, int n, trl_cb cb, void *ctx); static void trl_callback_search(game_state *state, int dx, int dy, struct setscratch *scratch, int n, void *ignored) { int i; #ifdef SOLVER_DIAGNOSTICS if (verbose) debug(("discount cb: light at (%d,%d)\n", dx, dy)); #endif for (i = 0; i < n; i++) { if (dx == scratch[i].x && dy == scratch[i].y) { scratch[i].n = 1; return; } } } static void trl_callback_discount(game_state *state, int dx, int dy, struct setscratch *scratch, int n, void *ctx) { int *didsth = (int *)ctx; int i; if (GRID(state,flags,dx,dy) & F_IMPOSSIBLE) { #ifdef SOLVER_DIAGNOSTICS debug(("Square at (%d,%d) already impossible.\n", dx,dy)); #endif return; } /* Check whether a light at (dx,dy) rules out everything * in scratch, and mark (dx,dy) as IMPOSSIBLE if it does. * We can use try_rule_out for this as well, as the set of * squares which would rule out (x,y) is the same as the * set of squares which (x,y) would rule out. */ #ifdef SOLVER_DIAGNOSTICS if (verbose) debug(("Checking whether light at (%d,%d) rules out everything in scratch.\n", dx, dy)); #endif for (i = 0; i < n; i++) scratch[i].n = 0; try_rule_out(state, dx, dy, scratch, n, trl_callback_search, NULL); for (i = 0; i < n; i++) { if (scratch[i].n == 0) return; } /* The light ruled out everything in scratch. Yay. */ GRID(state,flags,dx,dy) |= F_IMPOSSIBLE; #ifdef SOLVER_DIAGNOSTICS debug(("Set reduction discounted square at (%d,%d):\n", dx,dy)); if (verbose) debug_state(state); #endif *didsth = 1; } static void trl_callback_incn(game_state *state, int dx, int dy, struct setscratch *scratch, int n, void *ctx) { struct setscratch *s = (struct setscratch *)ctx; s->n++; } static void try_rule_out(game_state *state, int x, int y, struct setscratch *scratch, int n, trl_cb cb, void *ctx) { /* XXX Find all the squares which would rule out (x,y); anything * that would light it as well as squares adjacent to same clues * as X assuming that clue only has one remaining light. * Call the callback with each square. */ ll_data lld; surrounds s, ss; int i, j, curr_lights, tot_lights; /* Find all squares that would rule out a light at (x,y) and call trl_cb * with them: anything that would light (x,y)... */ list_lights(state, x, y, 0, &lld); FOREACHLIT(&lld, { if (could_place_light_xy(state, lx, ly)) { cb(state, lx, ly, scratch, n, ctx); } }); /* ... as well as any empty space (that isn't x,y) next to any clue square * next to (x,y) that only has one light left to place. */ get_surrounds(state, x, y, &s); for (i = 0; i < s.npoints; i++) { if (!(GRID(state,flags,s.points[i].x,s.points[i].y) & F_NUMBERED)) continue; /* we have an adjacent clue square; find /its/ surrounds * and count the remaining lights it needs. */ get_surrounds(state,s.points[i].x,s.points[i].y,&ss); curr_lights = 0; for (j = 0; j < ss.npoints; j++) { if (GRID(state,flags,ss.points[j].x,ss.points[j].y) & F_LIGHT) curr_lights++; } tot_lights = GRID(state, lights, s.points[i].x, s.points[i].y); /* We have a clue with tot_lights to fill, and curr_lights currently * around it. If adding a light at (x,y) fills up the clue (i.e. * curr_lights + 1 = tot_lights) then we need to discount all other * unlit squares around the clue. */ if ((curr_lights + 1) == tot_lights) { for (j = 0; j < ss.npoints; j++) { int lx = ss.points[j].x, ly = ss.points[j].y; if (lx == x && ly == y) continue; if (could_place_light_xy(state, lx, ly)) cb(state, lx, ly, scratch, n, ctx); } } } } #ifdef SOLVER_DIAGNOSTICS static void debug_scratch(const char *msg, struct setscratch *scratch, int n) { int i; debug(("%s scratch (%d elements):\n", msg, n)); for (i = 0; i < n; i++) { debug((" (%d,%d) n%d\n", scratch[i].x, scratch[i].y, scratch[i].n)); } } #endif static int discount_set(game_state *state, struct setscratch *scratch, int n) { int i, besti, bestn, didsth = 0; #ifdef SOLVER_DIAGNOSTICS if (verbose > 1) debug_scratch("discount_set", scratch, n); #endif if (n == 0) return 0; for (i = 0; i < n; i++) { try_rule_out(state, scratch[i].x, scratch[i].y, scratch, n, trl_callback_incn, (void*)&(scratch[i])); } #ifdef SOLVER_DIAGNOSTICS if (verbose > 1) debug_scratch("discount_set after count", scratch, n); #endif besti = -1; bestn = SCRATCHSZ; for (i = 0; i < n; i++) { if (scratch[i].n < bestn) { bestn = scratch[i].n; besti = i; } } #ifdef SOLVER_DIAGNOSTICS if (verbose > 1) debug(("best square (%d,%d) with n%d.\n", scratch[besti].x, scratch[besti].y, scratch[besti].n)); #endif try_rule_out(state, scratch[besti].x, scratch[besti].y, scratch, n, trl_callback_discount, (void*)&didsth); #ifdef SOLVER_DIAGNOSTICS if (didsth) debug((" [from square (%d,%d)]\n", scratch[besti].x, scratch[besti].y)); #endif return didsth; } static void discount_clear(game_state *state, struct setscratch *scratch, int *n) { *n = 0; memset(scratch, 0, SCRATCHSZ * sizeof(struct setscratch)); } static void unlit_cb(game_state *state, int lx, int ly, struct setscratch *scratch, int *n) { if (could_place_light_xy(state, lx, ly)) { scratch[*n].x = lx; scratch[*n].y = ly; (*n)++; } } /* Construct a MAKESLIGHT set from an unlit square. */ static int discount_unlit(game_state *state, int x, int y, struct setscratch *scratch) { ll_data lld; int n, didsth; #ifdef SOLVER_DIAGNOSTICS if (verbose) debug(("Trying to discount for unlit square at (%d,%d).\n", x, y)); if (verbose > 1) debug_state(state); #endif discount_clear(state, scratch, &n); list_lights(state, x, y, 1, &lld); FOREACHLIT(&lld, { unlit_cb(state, lx, ly, scratch, &n); }); didsth = discount_set(state, scratch, n); #ifdef SOLVER_DIAGNOSTICS if (didsth) debug((" [from unlit square at (%d,%d)].\n", x, y)); #endif return didsth; } /* Construct a series of MAKESLIGHT sets from a clue square. * for a clue square with N remaining spaces that must contain M lights, every * subset of size N-M+1 of those N spaces forms such a set. */ static int discount_clue(game_state *state, int x, int y, struct setscratch *scratch) { int slen, m = GRID(state, lights, x, y), n, i, didsth = 0, lights; unsigned int flags; surrounds s, sempty; combi_ctx *combi; if (m == 0) return 0; #ifdef SOLVER_DIAGNOSTICS if (verbose) debug(("Trying to discount for sets at clue (%d,%d).\n", x, y)); if (verbose > 1) debug_state(state); #endif /* m is no. of lights still to place; starts off at the clue value * and decreases when we find a light already down. * n is no. of spaces left; starts off at 0 and goes up when we find * a plausible space. */ get_surrounds(state, x, y, &s); memset(&sempty, 0, sizeof(surrounds)); for (i = 0; i < s.npoints; i++) { int lx = s.points[i].x, ly = s.points[i].y; flags = GRID(state,flags,lx,ly); lights = GRID(state,lights,lx,ly); if (flags & F_LIGHT) m--; if (could_place_light(flags, lights)) { sempty.points[sempty.npoints].x = lx; sempty.points[sempty.npoints].y = ly; sempty.npoints++; } } n = sempty.npoints; /* sempty is now a surrounds of only blank squares. */ if (n == 0) return 0; /* clue is full already. */ if (m < 0 || m > n) return 0; /* become impossible. */ combi = new_combi(n - m + 1, n); while (next_combi(combi)) { discount_clear(state, scratch, &slen); for (i = 0; i < combi->r; i++) { scratch[slen].x = sempty.points[combi->a[i]].x; scratch[slen].y = sempty.points[combi->a[i]].y; slen++; } if (discount_set(state, scratch, slen)) didsth = 1; } free_combi(combi); #ifdef SOLVER_DIAGNOSTICS if (didsth) debug((" [from clue at (%d,%d)].\n", x, y)); #endif return didsth; } #define F_SOLVE_FORCEUNIQUE 1 #define F_SOLVE_DISCOUNTSETS 2 #define F_SOLVE_ALLOWRECURSE 4 static unsigned int flags_from_difficulty(int difficulty) { unsigned int sflags = F_SOLVE_FORCEUNIQUE; assert(difficulty <= DIFFCOUNT); if (difficulty >= 1) sflags |= F_SOLVE_DISCOUNTSETS; if (difficulty >= 2) sflags |= F_SOLVE_ALLOWRECURSE; return sflags; } #define MAXRECURSE 5 static int solve_sub(game_state *state, unsigned int solve_flags, int depth, int *maxdepth) { unsigned int flags; int x, y, didstuff, ncanplace, lights; int bestx, besty, n, bestn, copy_soluble, self_soluble, ret, maxrecurse = 0; game_state *scopy; ll_data lld; struct setscratch *sscratch = NULL; #ifdef SOLVER_DIAGNOSTICS printf("solve_sub: depth = %d\n", depth); #endif if (maxdepth && *maxdepth < depth) *maxdepth = depth; if (solve_flags & F_SOLVE_ALLOWRECURSE) maxrecurse = MAXRECURSE; while (1) { if (grid_overlap(state)) { /* Our own solver, from scratch, should never cause this to happen * (assuming a soluble grid). However, if we're trying to solve * from a half-completed *incorrect* grid this might occur; we * just return the 'no solutions' code in this case. */ ret = 0; goto done; } if (grid_correct(state)) { ret = 1; goto done; } ncanplace = 0; didstuff = 0; /* These 2 loops, and the functions they call, are the critical loops * for timing; any optimisations should look here first. */ for (x = 0; x < state->w; x++) { for (y = 0; y < state->h; y++) { flags = GRID(state,flags,x,y); lights = GRID(state,lights,x,y); ncanplace += could_place_light(flags, lights); if (try_solve_light(state, x, y, flags, lights)) didstuff = 1; if (try_solve_number(state, x, y, flags, lights)) didstuff = 1; } } if (didstuff) continue; if (!ncanplace) { /* nowhere to put a light, puzzle is unsoluble. */ ret = 0; goto done; } if (solve_flags & F_SOLVE_DISCOUNTSETS) { if (!sscratch) sscratch = snewn(SCRATCHSZ, struct setscratch); /* Try a more cunning (and more involved) way... more details above. */ for (x = 0; x < state->w; x++) { for (y = 0; y < state->h; y++) { flags = GRID(state,flags,x,y); lights = GRID(state,lights,x,y); if (!(flags & F_BLACK) && lights == 0) { if (discount_unlit(state, x, y, sscratch)) { didstuff = 1; goto reduction_success; } } else if (flags & F_NUMBERED) { if (discount_clue(state, x, y, sscratch)) { didstuff = 1; goto reduction_success; } } } } } reduction_success: if (didstuff) continue; /* We now have to make a guess; we have places to put lights but * no definite idea about where they can go. */ if (depth >= maxrecurse) { /* mustn't delve any deeper. */ ret = -1; goto done; } /* Of all the squares that we could place a light, pick the one * that would light the most currently unlit squares. */ /* This heuristic was just plucked from the air; there may well be * a more efficient way of choosing a square to flip to minimise * recursion. */ bestn = 0; bestx = besty = -1; /* suyb */ for (x = 0; x < state->w; x++) { for (y = 0; y < state->h; y++) { flags = GRID(state,flags,x,y); lights = GRID(state,lights,x,y); if (!could_place_light(flags, lights)) continue; n = 0; list_lights(state, x, y, 1, &lld); FOREACHLIT(&lld, { if (GRID(state,lights,lx,ly) == 0) n++; }); if (n > bestn) { bestn = n; bestx = x; besty = y; } } } assert(bestn > 0); assert(bestx >= 0 && besty >= 0); /* Now we've chosen a plausible (x,y), try to solve it once as 'lit' * and once as 'impossible'; we need to make one copy to do this. */ scopy = dup_game(state); #ifdef SOLVER_DIAGNOSTICS debug(("Recursing #1: trying (%d,%d) as IMPOSSIBLE\n", bestx, besty)); #endif GRID(state,flags,bestx,besty) |= F_IMPOSSIBLE; self_soluble = solve_sub(state, solve_flags, depth+1, maxdepth); if (!(solve_flags & F_SOLVE_FORCEUNIQUE) && self_soluble > 0) { /* we didn't care about finding all solutions, and we just * found one; return with it immediately. */ free_game(scopy); ret = self_soluble; goto done; } #ifdef SOLVER_DIAGNOSTICS debug(("Recursing #2: trying (%d,%d) as LIGHT\n", bestx, besty)); #endif set_light(scopy, bestx, besty, 1); copy_soluble = solve_sub(scopy, solve_flags, depth+1, maxdepth); /* If we wanted a unique solution but we hit our recursion limit * (on either branch) then we have to assume we didn't find possible * extra solutions, and return 'not soluble'. */ if ((solve_flags & F_SOLVE_FORCEUNIQUE) && ((copy_soluble < 0) || (self_soluble < 0))) { ret = -1; /* Make sure that whether or not it was self or copy (or both) that * were soluble, that we return a solved state in self. */ } else if (copy_soluble <= 0) { /* copy wasn't soluble; keep self state and return that result. */ ret = self_soluble; } else if (self_soluble <= 0) { /* copy solved and we didn't, so copy in copy's (now solved) * flags and light state. */ memcpy(state->lights, scopy->lights, scopy->w * scopy->h * sizeof(int)); memcpy(state->flags, scopy->flags, scopy->w * scopy->h * sizeof(unsigned int)); ret = copy_soluble; } else { ret = copy_soluble + self_soluble; } free_game(scopy); goto done; } done: if (sscratch) sfree(sscratch); #ifdef SOLVER_DIAGNOSTICS if (ret < 0) debug(("solve_sub: depth = %d returning, ran out of recursion.\n", depth)); else debug(("solve_sub: depth = %d returning, %d solutions.\n", depth, ret)); #endif return ret; } /* Fills in the (possibly partially-complete) game_state as far as it can, * returning the number of possible solutions. If it returns >0 then the * game_state will be in a solved state, but you won't know which one. */ static int dosolve(game_state *state, int solve_flags, int *maxdepth) { int x, y, nsol; for (x = 0; x < state->w; x++) { for (y = 0; y < state->h; y++) { GRID(state,flags,x,y) &= ~F_NUMBERUSED; } } nsol = solve_sub(state, solve_flags, 0, maxdepth); return nsol; } static int strip_unused_nums(game_state *state) { int x,y,n=0; for (x = 0; x < state->w; x++) { for (y = 0; y < state->h; y++) { if ((GRID(state,flags,x,y) & F_NUMBERED) && !(GRID(state,flags,x,y) & F_NUMBERUSED)) { GRID(state,flags,x,y) &= ~F_NUMBERED; GRID(state,lights,x,y) = 0; n++; } } } debug(("Stripped %d unused numbers.\n", n)); return n; } static void unplace_lights(game_state *state) { int x,y; for (x = 0; x < state->w; x++) { for (y = 0; y < state->h; y++) { if (GRID(state,flags,x,y) & F_LIGHT) set_light(state,x,y,0); GRID(state,flags,x,y) &= ~F_IMPOSSIBLE; GRID(state,flags,x,y) &= ~F_NUMBERUSED; } } } static int puzzle_is_good(game_state *state, int difficulty) { int nsol, mdepth = 0; unsigned int sflags = flags_from_difficulty(difficulty); unplace_lights(state); #ifdef SOLVER_DIAGNOSTICS debug(("Trying to solve with difficulty %d (0x%x):\n", difficulty, sflags)); if (verbose) debug_state(state); #endif nsol = dosolve(state, sflags, &mdepth); /* if we wanted an easy puzzle, make sure we didn't need recursion. */ if (!(sflags & F_SOLVE_ALLOWRECURSE) && mdepth > 0) { debug(("Ignoring recursive puzzle.\n")); return 0; } debug(("%d solutions found.\n", nsol)); if (nsol <= 0) return 0; if (nsol > 1) return 0; return 1; } /* --- New game creation and user input code. --- */ /* The basic algorithm here is to generate the most complex grid possible * while honouring two restrictions: * * * we require a unique solution, and * * either we require solubility with no recursion (!params->recurse) * * or we require some recursion. (params->recurse). * * The solver helpfully keeps track of the numbers it needed to use to * get its solution, so we use that to remove an initial set of numbers * and check we still satsify our requirements (on uniqueness and * non-recursiveness, if applicable; we don't check explicit recursiveness * until the end). * * Then we try to remove all numbers in a random order, and see if we * still satisfy requirements (putting them back if we didn't). * * Removing numbers will always, in general terms, make a puzzle require * more recursion but it may also mean a puzzle becomes non-unique. * * Once we're done, if we wanted a recursive puzzle but the most difficult * puzzle we could come up with was non-recursive, we give up and try a new * grid. */ #define MAX_GRIDGEN_TRIES 20 static char *new_game_desc(const game_params *params_in, random_state *rs, char **aux, int interactive) { game_params params_copy = *params_in; /* structure copy */ game_params *params = ¶ms_copy; game_state *news = new_state(params), *copys; int i, j, run, x, y, wh = params->w*params->h, num; char *ret, *p; int *numindices; /* Construct a shuffled list of grid positions; we only * do this once, because if it gets used more than once it'll * be on a different grid layout. */ numindices = snewn(wh, int); for (j = 0; j < wh; j++) numindices[j] = j; shuffle(numindices, wh, sizeof(*numindices), rs); while (1) { for (i = 0; i < MAX_GRIDGEN_TRIES; i++) { set_blacks(news, params, rs); /* also cleans board. */ /* set up lights and then the numbers, and remove the lights */ place_lights(news, rs); debug(("Generating initial grid.\n")); place_numbers(news); if (!puzzle_is_good(news, params->difficulty)) continue; /* Take a copy, remove numbers we didn't use and check there's * still a unique solution; if so, use the copy subsequently. */ copys = dup_game(news); strip_unused_nums(copys); if (!puzzle_is_good(copys, params->difficulty)) { debug(("Stripped grid is not good, reverting.\n")); free_game(copys); } else { free_game(news); news = copys; } /* Go through grid removing numbers at random one-by-one and * trying to solve again; if it ceases to be good put the number back. */ for (j = 0; j < wh; j++) { y = numindices[j] / params->w; x = numindices[j] % params->w; if (!(GRID(news, flags, x, y) & F_NUMBERED)) continue; num = GRID(news, lights, x, y); GRID(news, lights, x, y) = 0; GRID(news, flags, x, y) &= ~F_NUMBERED; if (!puzzle_is_good(news, params->difficulty)) { GRID(news, lights, x, y) = num; GRID(news, flags, x, y) |= F_NUMBERED; } else debug(("Removed (%d,%d) still soluble.\n", x, y)); } if (params->difficulty > 0) { /* Was the maximally-difficult puzzle difficult enough? * Check we can't solve it with a more simplistic solver. */ if (puzzle_is_good(news, params->difficulty-1)) { debug(("Maximally-hard puzzle still not hard enough, skipping.\n")); continue; } } goto goodpuzzle; } /* Couldn't generate a good puzzle in however many goes. Ramp up the * %age of black squares (if we didn't already have lots; in which case * why couldn't we generate a puzzle?) and try again. */ if (params->blackpc < 90) params->blackpc += 5; debug(("New black layout %d%%.\n", params->blackpc)); } goodpuzzle: /* Game is encoded as a long string one character per square; * 'S' is a space * 'B' is a black square with no number * '0', '1', '2', '3', '4' is a black square with a number. */ ret = snewn((params->w * params->h) + 1, char); p = ret; run = 0; for (y = 0; y < params->h; y++) { for (x = 0; x < params->w; x++) { if (GRID(news,flags,x,y) & F_BLACK) { if (run) { *p++ = ('a'-1) + run; run = 0; } if (GRID(news,flags,x,y) & F_NUMBERED) *p++ = '0' + GRID(news,lights,x,y); else *p++ = 'B'; } else { if (run == 26) { *p++ = ('a'-1) + run; run = 0; } run++; } } } if (run) { *p++ = ('a'-1) + run; run = 0; } *p = '\0'; assert(p - ret <= params->w * params->h); free_game(news); sfree(numindices); return ret; } static char *validate_desc(const game_params *params, const char *desc) { int i; for (i = 0; i < params->w*params->h; i++) { if (*desc >= '0' && *desc <= '4') /* OK */; else if (*desc == 'B') /* OK */; else if (*desc >= 'a' && *desc <= 'z') i += *desc - 'a'; /* and the i++ will add another one */ else if (!*desc) return "Game description shorter than expected"; else return "Game description contained unexpected character"; desc++; } if (*desc || i > params->w*params->h) return "Game description longer than expected"; return NULL; } static game_state *new_game(midend *me, const game_params *params, const char *desc) { game_state *ret = new_state(params); int x,y; int run = 0; for (y = 0; y < params->h; y++) { for (x = 0; x < params->w; x++) { char c = '\0'; if (run == 0) { c = *desc++; assert(c != 'S'); if (c >= 'a' && c <= 'z') run = c - 'a' + 1; } if (run > 0) { c = 'S'; run--; } switch (c) { case '0': case '1': case '2': case '3': case '4': GRID(ret,flags,x,y) |= F_NUMBERED; GRID(ret,lights,x,y) = (c - '0'); /* run-on... */ case 'B': GRID(ret,flags,x,y) |= F_BLACK; break; case 'S': /* empty square */ break; default: assert(!"Malformed desc."); break; } } } if (*desc) assert(!"Over-long desc."); return ret; } static char *solve_game(const game_state *state, const game_state *currstate, const char *aux, char **error) { game_state *solved; char *move = NULL, buf[80]; int movelen, movesize, x, y, len; unsigned int oldflags, solvedflags, sflags; /* We don't care here about non-unique puzzles; if the * user entered one themself then I doubt they care. */ sflags = F_SOLVE_ALLOWRECURSE | F_SOLVE_DISCOUNTSETS; /* Try and solve from where we are now (for non-unique * puzzles this may produce a different answer). */ solved = dup_game(currstate); if (dosolve(solved, sflags, NULL) > 0) goto solved; free_game(solved); /* That didn't work; try solving from the clean puzzle. */ solved = dup_game(state); if (dosolve(solved, sflags, NULL) > 0) goto solved; *error = "Unable to find a solution to this puzzle."; goto done; solved: movesize = 256; move = snewn(movesize, char); movelen = 0; move[movelen++] = 'S'; move[movelen] = '\0'; for (x = 0; x < currstate->w; x++) { for (y = 0; y < currstate->h; y++) { len = 0; oldflags = GRID(currstate, flags, x, y); solvedflags = GRID(solved, flags, x, y); if ((oldflags & F_LIGHT) != (solvedflags & F_LIGHT)) len = sprintf(buf, ";L%d,%d", x, y); else if ((oldflags & F_IMPOSSIBLE) != (solvedflags & F_IMPOSSIBLE)) len = sprintf(buf, ";I%d,%d", x, y); if (len) { if (movelen + len >= movesize) { movesize = movelen + len + 256; move = sresize(move, movesize, char); } strcpy(move + movelen, buf); movelen += len; } } } done: free_game(solved); return move; } static int game_can_format_as_text_now(const game_params *params) { return TRUE; } /* 'borrowed' from slant.c, mainly. I could have printed it one * character per cell (like debug_state) but that comes out tiny. * 'L' is used for 'light here' because 'O' looks too much like '0' * (black square with no surrounding lights). */ static char *game_text_format(const game_state *state) { int w = state->w, h = state->h, W = w+1, H = h+1; int x, y, len, lights; unsigned int flags; char *ret, *p; len = (h+H) * (w+W+1) + 1; ret = snewn(len, char); p = ret; for (y = 0; y < H; y++) { for (x = 0; x < W; x++) { *p++ = '+'; if (x < w) *p++ = '-'; } *p++ = '\n'; if (y < h) { for (x = 0; x < W; x++) { *p++ = '|'; if (x < w) { /* actual interesting bit. */ flags = GRID(state, flags, x, y); lights = GRID(state, lights, x, y); if (flags & F_BLACK) { if (flags & F_NUMBERED) *p++ = '0' + lights; else *p++ = '#'; } else { if (flags & F_LIGHT) *p++ = 'L'; else if (flags & F_IMPOSSIBLE) *p++ = 'x'; else if (lights > 0) *p++ = '.'; else *p++ = ' '; } } } *p++ = '\n'; } } *p++ = '\0'; assert(p - ret == len); return ret; } struct game_ui { int cur_x, cur_y, cur_visible; }; static game_ui *new_ui(const game_state *state) { game_ui *ui = snew(game_ui); ui->cur_x = ui->cur_y = ui->cur_visible = 0; return ui; } static void free_ui(game_ui *ui) { sfree(ui); } static char *encode_ui(const game_ui *ui) { /* nothing to encode. */ return NULL; } static void decode_ui(game_ui *ui, const char *encoding) { /* nothing to decode. */ } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { if (newstate->completed) ui->cur_visible = 0; } #define DF_BLACK 1 /* black square */ #define DF_NUMBERED 2 /* black square with number */ #define DF_LIT 4 /* display (white) square lit up */ #define DF_LIGHT 8 /* display light in square */ #define DF_OVERLAP 16 /* display light as overlapped */ #define DF_CURSOR 32 /* display cursor */ #define DF_NUMBERWRONG 64 /* display black numbered square as error. */ #define DF_FLASH 128 /* background flash is on. */ #define DF_IMPOSSIBLE 256 /* display non-light little square */ struct game_drawstate { int tilesize, crad; int w, h; unsigned int *flags; /* width * height */ int started; }; /* Believe it or not, this empty = "" hack is needed to get around a bug in * the prc-tools gcc when optimisation is turned on; before, it produced: lightup-sect.c: In function `interpret_move': lightup-sect.c:1416: internal error--unrecognizable insn: (insn 582 580 583 (set (reg:SI 134) (pc)) -1 (nil) (nil)) */ static char *interpret_move(const game_state *state, game_ui *ui, const game_drawstate *ds, int x, int y, int button) { enum { NONE, FLIP_LIGHT, FLIP_IMPOSSIBLE } action = NONE; int cx = -1, cy = -1; unsigned int flags; char buf[80], *nullret = NULL, *empty = "", c; if (button == LEFT_BUTTON || button == RIGHT_BUTTON) { if (ui->cur_visible) nullret = empty; ui->cur_visible = 0; cx = FROMCOORD(x); cy = FROMCOORD(y); action = (button == LEFT_BUTTON) ? FLIP_LIGHT : FLIP_IMPOSSIBLE; } else if (IS_CURSOR_SELECT(button) || button == 'i' || button == 'I' || button == ' ' || button == '\r' || button == '\n') { if (ui->cur_visible) { /* Only allow cursor-effect operations if the cursor is visible * (otherwise you have no idea which square it might be affecting) */ cx = ui->cur_x; cy = ui->cur_y; action = (button == 'i' || button == 'I' || button == CURSOR_SELECT2) ? FLIP_IMPOSSIBLE : FLIP_LIGHT; } ui->cur_visible = 1; } else if (IS_CURSOR_MOVE(button)) { move_cursor(button, &ui->cur_x, &ui->cur_y, state->w, state->h, 0); ui->cur_visible = 1; nullret = empty; } else return NULL; switch (action) { case FLIP_LIGHT: case FLIP_IMPOSSIBLE: if (cx < 0 || cy < 0 || cx >= state->w || cy >= state->h) return nullret; flags = GRID(state, flags, cx, cy); if (flags & F_BLACK) return nullret; if (action == FLIP_LIGHT) { #ifdef STYLUS_BASED if (flags & F_IMPOSSIBLE || flags & F_LIGHT) c = 'I'; else c = 'L'; #else if (flags & F_IMPOSSIBLE) return nullret; c = 'L'; #endif } else { #ifdef STYLUS_BASED if (flags & F_IMPOSSIBLE || flags & F_LIGHT) c = 'L'; else c = 'I'; #else if (flags & F_LIGHT) return nullret; c = 'I'; #endif } sprintf(buf, "%c%d,%d", (int)c, cx, cy); break; case NONE: return nullret; default: assert(!"Shouldn't get here!"); } return dupstr(buf); } static game_state *execute_move(const game_state *state, const char *move) { game_state *ret = dup_game(state); int x, y, n, flags; char c; if (!*move) goto badmove; while (*move) { c = *move; if (c == 'S') { ret->used_solve = TRUE; move++; } else if (c == 'L' || c == 'I') { move++; if (sscanf(move, "%d,%d%n", &x, &y, &n) != 2 || x < 0 || y < 0 || x >= ret->w || y >= ret->h) goto badmove; flags = GRID(ret, flags, x, y); if (flags & F_BLACK) goto badmove; /* LIGHT and IMPOSSIBLE are mutually exclusive. */ if (c == 'L') { GRID(ret, flags, x, y) &= ~F_IMPOSSIBLE; set_light(ret, x, y, (flags & F_LIGHT) ? 0 : 1); } else { set_light(ret, x, y, 0); GRID(ret, flags, x, y) ^= F_IMPOSSIBLE; } move += n; } else goto badmove; if (*move == ';') move++; else if (*move) goto badmove; } if (grid_correct(ret)) ret->completed = 1; return ret; badmove: free_game(ret); return NULL; } /* ---------------------------------------------------------------------- * Drawing routines. */ /* XXX entirely cloned from fifteen.c; separate out? */ static void game_compute_size(const game_params *params, int tilesize, int *x, int *y) { /* Ick: fake up `ds->tilesize' for macro expansion purposes */ struct { int tilesize; } ads, *ds = &ads; ads.tilesize = tilesize; *x = TILE_SIZE * params->w + 2 * BORDER; *y = TILE_SIZE * params->h + 2 * BORDER; } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { ds->tilesize = tilesize; ds->crad = 3*(tilesize-1)/8; } static float *game_colours(frontend *fe, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float); int i; frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]); for (i = 0; i < 3; i++) { ret[COL_BLACK * 3 + i] = 0.0F; ret[COL_LIGHT * 3 + i] = 1.0F; ret[COL_CURSOR * 3 + i] = ret[COL_BACKGROUND * 3 + i] / 2.0F; ret[COL_GRID * 3 + i] = ret[COL_BACKGROUND * 3 + i] / 1.5F; } ret[COL_ERROR * 3 + 0] = 1.0F; ret[COL_ERROR * 3 + 1] = 0.25F; ret[COL_ERROR * 3 + 2] = 0.25F; ret[COL_LIT * 3 + 0] = 1.0F; ret[COL_LIT * 3 + 1] = 1.0F; ret[COL_LIT * 3 + 2] = 0.0F; *ncolours = NCOLOURS; return ret; } static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { struct game_drawstate *ds = snew(struct game_drawstate); int i; ds->tilesize = ds->crad = 0; ds->w = state->w; ds->h = state->h; ds->flags = snewn(ds->w*ds->h, unsigned int); for (i = 0; i < ds->w*ds->h; i++) ds->flags[i] = -1; ds->started = 0; return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { sfree(ds->flags); sfree(ds); } /* At some stage we should put these into a real options struct. * Note that tile_redraw has no #ifdeffery; it relies on tile_flags not * to put those flags in. */ #define HINT_LIGHTS #define HINT_OVERLAPS #define HINT_NUMBERS static unsigned int tile_flags(game_drawstate *ds, const game_state *state, const game_ui *ui, int x, int y, int flashing) { unsigned int flags = GRID(state, flags, x, y); int lights = GRID(state, lights, x, y); unsigned int ret = 0; if (flashing) ret |= DF_FLASH; if (ui && ui->cur_visible && x == ui->cur_x && y == ui->cur_y) ret |= DF_CURSOR; if (flags & F_BLACK) { ret |= DF_BLACK; if (flags & F_NUMBERED) { #ifdef HINT_NUMBERS if (number_wrong(state, x, y)) ret |= DF_NUMBERWRONG; #endif ret |= DF_NUMBERED; } } else { #ifdef HINT_LIGHTS if (lights > 0) ret |= DF_LIT; #endif if (flags & F_LIGHT) { ret |= DF_LIGHT; #ifdef HINT_OVERLAPS if (lights > 1) ret |= DF_OVERLAP; #endif } if (flags & F_IMPOSSIBLE) ret |= DF_IMPOSSIBLE; } return ret; } static void tile_redraw(drawing *dr, game_drawstate *ds, const game_state *state, int x, int y) { unsigned int ds_flags = GRID(ds, flags, x, y); int dx = COORD(x), dy = COORD(y); int lit = (ds_flags & DF_FLASH) ? COL_GRID : COL_LIT; if (ds_flags & DF_BLACK) { draw_rect(dr, dx, dy, TILE_SIZE, TILE_SIZE, COL_BLACK); if (ds_flags & DF_NUMBERED) { int ccol = (ds_flags & DF_NUMBERWRONG) ? COL_ERROR : COL_LIGHT; char str[32]; /* We know that this won't change over the course of the game * so it's OK to ignore this when calculating whether or not * to redraw the tile. */ sprintf(str, "%d", GRID(state, lights, x, y)); draw_text(dr, dx + TILE_SIZE/2, dy + TILE_SIZE/2, FONT_VARIABLE, TILE_SIZE*3/5, ALIGN_VCENTRE | ALIGN_HCENTRE, ccol, str); } } else { draw_rect(dr, dx, dy, TILE_SIZE, TILE_SIZE, (ds_flags & DF_LIT) ? lit : COL_BACKGROUND); draw_rect_outline(dr, dx, dy, TILE_SIZE, TILE_SIZE, COL_GRID); if (ds_flags & DF_LIGHT) { int lcol = (ds_flags & DF_OVERLAP) ? COL_ERROR : COL_LIGHT; draw_circle(dr, dx + TILE_SIZE/2, dy + TILE_SIZE/2, TILE_RADIUS, lcol, COL_BLACK); } else if ((ds_flags & DF_IMPOSSIBLE)) { static int draw_blobs_when_lit = -1; if (draw_blobs_when_lit < 0) { char *env = getenv("LIGHTUP_LIT_BLOBS"); draw_blobs_when_lit = (!env || (env[0] == 'y' || env[0] == 'Y')); } if (!(ds_flags & DF_LIT) || draw_blobs_when_lit) { int rlen = TILE_SIZE / 4; draw_rect(dr, dx + TILE_SIZE/2 - rlen/2, dy + TILE_SIZE/2 - rlen/2, rlen, rlen, COL_BLACK); } } } if (ds_flags & DF_CURSOR) { int coff = TILE_SIZE/8; draw_rect_outline(dr, dx + coff, dy + coff, TILE_SIZE - coff*2, TILE_SIZE - coff*2, COL_CURSOR); } draw_update(dr, dx, dy, TILE_SIZE, TILE_SIZE); } static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float animtime, float flashtime) { int flashing = FALSE; int x,y; if (flashtime) flashing = (int)(flashtime * 3 / FLASH_TIME) != 1; if (!ds->started) { draw_rect(dr, 0, 0, TILE_SIZE * ds->w + 2 * BORDER, TILE_SIZE * ds->h + 2 * BORDER, COL_BACKGROUND); draw_rect_outline(dr, COORD(0)-1, COORD(0)-1, TILE_SIZE * ds->w + 2, TILE_SIZE * ds->h + 2, COL_GRID); draw_update(dr, 0, 0, TILE_SIZE * ds->w + 2 * BORDER, TILE_SIZE * ds->h + 2 * BORDER); ds->started = 1; } for (x = 0; x < ds->w; x++) { for (y = 0; y < ds->h; y++) { unsigned int ds_flags = tile_flags(ds, state, ui, x, y, flashing); if (ds_flags != GRID(ds, flags, x, y)) { GRID(ds, flags, x, y) = ds_flags; tile_redraw(dr, ds, state, x, y); } } } } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return 0.0F; } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { if (!oldstate->completed && newstate->completed && !oldstate->used_solve && !newstate->used_solve) return FLASH_TIME; return 0.0F; } static int game_status(const game_state *state) { return state->completed ? +1 : 0; } static int game_timing_state(const game_state *state, game_ui *ui) { return TRUE; } static void game_print_size(const game_params *params, float *x, float *y) { int pw, ph; /* * I'll use 6mm squares by default. */ game_compute_size(params, 600, &pw, &ph); *x = pw / 100.0F; *y = ph / 100.0F; } static void game_print(drawing *dr, const game_state *state, int tilesize) { int w = state->w, h = state->h; int ink = print_mono_colour(dr, 0); int paper = print_mono_colour(dr, 1); int x, y; /* Ick: fake up `ds->tilesize' for macro expansion purposes */ game_drawstate ads, *ds = &ads; game_set_size(dr, ds, NULL, tilesize); /* * Border. */ print_line_width(dr, TILE_SIZE / 16); draw_rect_outline(dr, COORD(0), COORD(0), TILE_SIZE * w, TILE_SIZE * h, ink); /* * Grid. */ print_line_width(dr, TILE_SIZE / 24); for (x = 1; x < w; x++) draw_line(dr, COORD(x), COORD(0), COORD(x), COORD(h), ink); for (y = 1; y < h; y++) draw_line(dr, COORD(0), COORD(y), COORD(w), COORD(y), ink); /* * Grid contents. */ for (y = 0; y < h; y++) for (x = 0; x < w; x++) { unsigned int ds_flags = tile_flags(ds, state, NULL, x, y, FALSE); int dx = COORD(x), dy = COORD(y); if (ds_flags & DF_BLACK) { draw_rect(dr, dx, dy, TILE_SIZE, TILE_SIZE, ink); if (ds_flags & DF_NUMBERED) { char str[32]; sprintf(str, "%d", GRID(state, lights, x, y)); draw_text(dr, dx + TILE_SIZE/2, dy + TILE_SIZE/2, FONT_VARIABLE, TILE_SIZE*3/5, ALIGN_VCENTRE | ALIGN_HCENTRE, paper, str); } } else if (ds_flags & DF_LIGHT) { draw_circle(dr, dx + TILE_SIZE/2, dy + TILE_SIZE/2, TILE_RADIUS, -1, ink); } } } #ifdef COMBINED #define thegame lightup #endif const struct game thegame = { "Light Up", "games.lightup", "lightup", default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, TRUE, solve_game, TRUE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, PREFERRED_TILE_SIZE, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, TRUE, FALSE, game_print_size, game_print, FALSE, /* wants_statusbar */ FALSE, game_timing_state, 0, /* flags */ }; #ifdef STANDALONE_SOLVER int main(int argc, char **argv) { game_params *p; game_state *s; char *id = NULL, *desc, *err, *result; int nsol, diff, really_verbose = 0; unsigned int sflags; while (--argc > 0) { char *p = *++argv; if (!strcmp(p, "-v")) { really_verbose++; } else if (*p == '-') { fprintf(stderr, "%s: unrecognised option `%s'\n", argv[0], p); return 1; } else { id = p; } } if (!id) { fprintf(stderr, "usage: %s [-v] \n", argv[0]); return 1; } desc = strchr(id, ':'); if (!desc) { fprintf(stderr, "%s: game id expects a colon in it\n", argv[0]); return 1; } *desc++ = '\0'; p = default_params(); decode_params(p, id); err = validate_desc(p, desc); if (err) { fprintf(stderr, "%s: %s\n", argv[0], err); return 1; } s = new_game(NULL, p, desc); /* Run the solvers easiest to hardest until we find one that * can solve our puzzle. If it's soluble we know that the * hardest (recursive) solver will always find the solution. */ nsol = sflags = 0; for (diff = 0; diff <= DIFFCOUNT; diff++) { printf("\nSolving with difficulty %d.\n", diff); sflags = flags_from_difficulty(diff); unplace_lights(s); nsol = dosolve(s, sflags, NULL); if (nsol == 1) break; } printf("\n"); if (nsol == 0) { printf("Puzzle has no solution.\n"); } else if (nsol < 0) { printf("Unable to find a unique solution.\n"); } else if (nsol > 1) { printf("Puzzle has multiple solutions.\n"); } else { verbose = really_verbose; unplace_lights(s); printf("Puzzle has difficulty %d: solving...\n", diff); dosolve(s, sflags, NULL); /* sflags from last successful solve */ result = game_text_format(s); printf("%s", result); sfree(result); } return 0; } #endif /* vim: set shiftwidth=4 tabstop=8: */ puzzles-20170606.272beef/laydomino.c0000644000175000017500000002101213115373615016024 0ustar simonsimon/* * laydomino.c: code for performing a domino (2x1 tile) layout of * a given area of code. */ #include #include #include #include "puzzles.h" /* * This function returns an array size w x h representing a grid: * each grid[i] = j, where j is the other end of a 2x1 domino. * If w*h is odd, one square will remain referring to itself. */ int *domino_layout(int w, int h, random_state *rs) { int *grid, *grid2, *list; int wh = w*h; /* * Allocate space in which to lay the grid out. */ grid = snewn(wh, int); grid2 = snewn(wh, int); list = snewn(2*wh, int); domino_layout_prealloc(w, h, rs, grid, grid2, list); sfree(grid2); sfree(list); return grid; } /* * As for domino_layout, but with preallocated buffers. * grid and grid2 should be size w*h, and list size 2*w*h. */ void domino_layout_prealloc(int w, int h, random_state *rs, int *grid, int *grid2, int *list) { int i, j, k, m, wh = w*h, todo, done; /* * To begin with, set grid[i] = i for all i to indicate * that all squares are currently singletons. Later we'll * set grid[i] to be the index of the other end of the * domino on i. */ for (i = 0; i < wh; i++) grid[i] = i; /* * Now prepare a list of the possible domino locations. There * are w*(h-1) possible vertical locations, and (w-1)*h * horizontal ones, for a total of 2*wh - h - w. * * I'm going to denote the vertical domino placement with * its top in square i as 2*i, and the horizontal one with * its left half in square i as 2*i+1. */ k = 0; for (j = 0; j < h-1; j++) for (i = 0; i < w; i++) list[k++] = 2 * (j*w+i); /* vertical positions */ for (j = 0; j < h; j++) for (i = 0; i < w-1; i++) list[k++] = 2 * (j*w+i) + 1; /* horizontal positions */ assert(k == 2*wh - h - w); /* * Shuffle the list. */ shuffle(list, k, sizeof(*list), rs); /* * Work down the shuffled list, placing a domino everywhere * we can. */ for (i = 0; i < k; i++) { int horiz, xy, xy2; horiz = list[i] % 2; xy = list[i] / 2; xy2 = xy + (horiz ? 1 : w); if (grid[xy] == xy && grid[xy2] == xy2) { /* * We can place this domino. Do so. */ grid[xy] = xy2; grid[xy2] = xy; } } #ifdef GENERATION_DIAGNOSTICS printf("generated initial layout\n"); #endif /* * Now we've placed as many dominoes as we can immediately * manage. There will be squares remaining, but they'll be * singletons. So loop round and deal with the singletons * two by two. */ while (1) { #ifdef GENERATION_DIAGNOSTICS for (j = 0; j < h; j++) { for (i = 0; i < w; i++) { int xy = j*w+i; int v = grid[xy]; int c = (v == xy+1 ? '[' : v == xy-1 ? ']' : v == xy+w ? 'n' : v == xy-w ? 'U' : '.'); putchar(c); } putchar('\n'); } putchar('\n'); #endif /* * Our strategy is: * * First find a singleton square. * * Then breadth-first search out from the starting * square. From that square (and any others we reach on * the way), examine all four neighbours of the square. * If one is an end of a domino, we move to the _other_ * end of that domino before looking at neighbours * again. When we encounter another singleton on this * search, stop. * * This will give us a path of adjacent squares such * that all but the two ends are covered in dominoes. * So we can now shuffle every domino on the path up by * one. * * (Chessboard colours are mathematically important * here: we always end up pairing each singleton with a * singleton of the other colour. However, we never * have to track this manually, since it's * automatically taken care of by the fact that we * always make an even number of orthogonal moves.) */ k = 0; for (j = 0; j < wh; j++) { if (grid[j] == j) { k++; i = j; /* start BFS here. */ } } if (k == (wh % 2)) break; /* if area is even, we have no more singletons; if area is odd, we have one singleton. either way, we're done. */ #ifdef GENERATION_DIAGNOSTICS printf("starting b.f.s. at singleton %d\n", i); #endif /* * Set grid2 to -1 everywhere. It will hold our * distance-from-start values, and also our * backtracking data, during the b.f.s. */ for (j = 0; j < wh; j++) grid2[j] = -1; grid2[i] = 0; /* starting square has distance zero */ /* * Start our to-do list of squares. It'll live in * `list'; since the b.f.s can cover every square at * most once there is no need for it to be circular. * We'll just have two counters tracking the end of the * list and the squares we've already dealt with. */ done = 0; todo = 1; list[0] = i; /* * Now begin the b.f.s. loop. */ while (done < todo) { int d[4], nd, x, y; i = list[done++]; #ifdef GENERATION_DIAGNOSTICS printf("b.f.s. iteration from %d\n", i); #endif x = i % w; y = i / w; nd = 0; if (x > 0) d[nd++] = i - 1; if (x+1 < w) d[nd++] = i + 1; if (y > 0) d[nd++] = i - w; if (y+1 < h) d[nd++] = i + w; /* * To avoid directional bias, process the * neighbours of this square in a random order. */ shuffle(d, nd, sizeof(*d), rs); for (j = 0; j < nd; j++) { k = d[j]; if (grid[k] == k) { #ifdef GENERATION_DIAGNOSTICS printf("found neighbouring singleton %d\n", k); #endif grid2[k] = i; break; /* found a target singleton! */ } /* * We're moving through a domino here, so we * have two entries in grid2 to fill with * useful data. In grid[k] - the square * adjacent to where we came from - I'm going * to put the address _of_ the square we came * from. In the other end of the domino - the * square from which we will continue the * search - I'm going to put the distance. */ m = grid[k]; if (grid2[m] < 0 || grid2[m] > grid2[i]+1) { #ifdef GENERATION_DIAGNOSTICS printf("found neighbouring domino %d/%d\n", k, m); #endif grid2[m] = grid2[i]+1; grid2[k] = i; /* * And since we've now visited a new * domino, add m to the to-do list. */ assert(todo < wh); list[todo++] = m; } } if (j < nd) { i = k; #ifdef GENERATION_DIAGNOSTICS printf("terminating b.f.s. loop, i = %d\n", i); #endif break; } i = -1; /* just in case the loop terminates */ } /* * We expect this b.f.s. to have found us a target * square. */ assert(i >= 0); /* * Now we can follow the trail back to our starting * singleton, re-laying dominoes as we go. */ while (1) { j = grid2[i]; assert(j >= 0 && j < wh); k = grid[j]; grid[i] = j; grid[j] = i; #ifdef GENERATION_DIAGNOSTICS printf("filling in domino %d/%d (next %d)\n", i, j, k); #endif if (j == k) break; /* we've reached the other singleton */ i = k; } #ifdef GENERATION_DIAGNOSTICS printf("fixup path completed\n"); #endif } } /* vim: set shiftwidth=4 :set textwidth=80: */ puzzles-20170606.272beef/latin.c0000644000175000017500000011663413115373615015157 0ustar simonsimon#include #include #include #include "puzzles.h" #include "tree234.h" #include "maxflow.h" #ifdef STANDALONE_LATIN_TEST #define STANDALONE_SOLVER #endif #include "latin.h" /* -------------------------------------------------------- * Solver. */ static int latin_solver_top(struct latin_solver *solver, int maxdiff, int diff_simple, int diff_set_0, int diff_set_1, int diff_forcing, int diff_recursive, usersolver_t const *usersolvers, void *ctx, ctxnew_t ctxnew, ctxfree_t ctxfree); #ifdef STANDALONE_SOLVER int solver_show_working, solver_recurse_depth; #endif /* * Function called when we are certain that a particular square has * a particular number in it. The y-coordinate passed in here is * transformed. */ void latin_solver_place(struct latin_solver *solver, int x, int y, int n) { int i, o = solver->o; assert(n <= o); assert(cube(x,y,n)); /* * Rule out all other numbers in this square. */ for (i = 1; i <= o; i++) if (i != n) cube(x,y,i) = FALSE; /* * Rule out this number in all other positions in the row. */ for (i = 0; i < o; i++) if (i != y) cube(x,i,n) = FALSE; /* * Rule out this number in all other positions in the column. */ for (i = 0; i < o; i++) if (i != x) cube(i,y,n) = FALSE; /* * Enter the number in the result grid. */ solver->grid[y*o+x] = n; /* * Cross out this number from the list of numbers left to place * in its row, its column and its block. */ solver->row[y*o+n-1] = solver->col[x*o+n-1] = TRUE; } int latin_solver_elim(struct latin_solver *solver, int start, int step #ifdef STANDALONE_SOLVER , char *fmt, ... #endif ) { int o = solver->o; #ifdef STANDALONE_SOLVER char **names = solver->names; #endif int fpos, m, i; /* * Count the number of set bits within this section of the * cube. */ m = 0; fpos = -1; for (i = 0; i < o; i++) if (solver->cube[start+i*step]) { fpos = start+i*step; m++; } if (m == 1) { int x, y, n; assert(fpos >= 0); n = 1 + fpos % o; y = fpos / o; x = y / o; y %= o; if (!solver->grid[y*o+x]) { #ifdef STANDALONE_SOLVER if (solver_show_working) { va_list ap; printf("%*s", solver_recurse_depth*4, ""); va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); printf(":\n%*s placing %s at (%d,%d)\n", solver_recurse_depth*4, "", names[n-1], x+1, y+1); } #endif latin_solver_place(solver, x, y, n); return +1; } } else if (m == 0) { #ifdef STANDALONE_SOLVER if (solver_show_working) { va_list ap; printf("%*s", solver_recurse_depth*4, ""); va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); printf(":\n%*s no possibilities available\n", solver_recurse_depth*4, ""); } #endif return -1; } return 0; } struct latin_solver_scratch { unsigned char *grid, *rowidx, *colidx, *set; int *neighbours, *bfsqueue; #ifdef STANDALONE_SOLVER int *bfsprev; #endif }; int latin_solver_set(struct latin_solver *solver, struct latin_solver_scratch *scratch, int start, int step1, int step2 #ifdef STANDALONE_SOLVER , char *fmt, ... #endif ) { int o = solver->o; #ifdef STANDALONE_SOLVER char **names = solver->names; #endif int i, j, n, count; unsigned char *grid = scratch->grid; unsigned char *rowidx = scratch->rowidx; unsigned char *colidx = scratch->colidx; unsigned char *set = scratch->set; /* * We are passed a o-by-o matrix of booleans. Our first job * is to winnow it by finding any definite placements - i.e. * any row with a solitary 1 - and discarding that row and the * column containing the 1. */ memset(rowidx, TRUE, o); memset(colidx, TRUE, o); for (i = 0; i < o; i++) { int count = 0, first = -1; for (j = 0; j < o; j++) if (solver->cube[start+i*step1+j*step2]) first = j, count++; if (count == 0) return -1; if (count == 1) rowidx[i] = colidx[first] = FALSE; } /* * Convert each of rowidx/colidx from a list of 0s and 1s to a * list of the indices of the 1s. */ for (i = j = 0; i < o; i++) if (rowidx[i]) rowidx[j++] = i; n = j; for (i = j = 0; i < o; i++) if (colidx[i]) colidx[j++] = i; assert(n == j); /* * And create the smaller matrix. */ for (i = 0; i < n; i++) for (j = 0; j < n; j++) grid[i*o+j] = solver->cube[start+rowidx[i]*step1+colidx[j]*step2]; /* * Having done that, we now have a matrix in which every row * has at least two 1s in. Now we search to see if we can find * a rectangle of zeroes (in the set-theoretic sense of * `rectangle', i.e. a subset of rows crossed with a subset of * columns) whose width and height add up to n. */ memset(set, 0, n); count = 0; while (1) { /* * We have a candidate set. If its size is <=1 or >=n-1 * then we move on immediately. */ if (count > 1 && count < n-1) { /* * The number of rows we need is n-count. See if we can * find that many rows which each have a zero in all * the positions listed in `set'. */ int rows = 0; for (i = 0; i < n; i++) { int ok = TRUE; for (j = 0; j < n; j++) if (set[j] && grid[i*o+j]) { ok = FALSE; break; } if (ok) rows++; } /* * We expect never to be able to get _more_ than * n-count suitable rows: this would imply that (for * example) there are four numbers which between them * have at most three possible positions, and hence it * indicates a faulty deduction before this point or * even a bogus clue. */ if (rows > n - count) { #ifdef STANDALONE_SOLVER if (solver_show_working) { va_list ap; printf("%*s", solver_recurse_depth*4, ""); va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); printf(":\n%*s contradiction reached\n", solver_recurse_depth*4, ""); } #endif return -1; } if (rows >= n - count) { int progress = FALSE; /* * We've got one! Now, for each row which _doesn't_ * satisfy the criterion, eliminate all its set * bits in the positions _not_ listed in `set'. * Return +1 (meaning progress has been made) if we * successfully eliminated anything at all. * * This involves referring back through * rowidx/colidx in order to work out which actual * positions in the cube to meddle with. */ for (i = 0; i < n; i++) { int ok = TRUE; for (j = 0; j < n; j++) if (set[j] && grid[i*o+j]) { ok = FALSE; break; } if (!ok) { for (j = 0; j < n; j++) if (!set[j] && grid[i*o+j]) { int fpos = (start+rowidx[i]*step1+ colidx[j]*step2); #ifdef STANDALONE_SOLVER if (solver_show_working) { int px, py, pn; if (!progress) { va_list ap; printf("%*s", solver_recurse_depth*4, ""); va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); printf(":\n"); } pn = 1 + fpos % o; py = fpos / o; px = py / o; py %= o; printf("%*s ruling out %s at (%d,%d)\n", solver_recurse_depth*4, "", names[pn-1], px+1, py+1); } #endif progress = TRUE; solver->cube[fpos] = FALSE; } } } if (progress) { return +1; } } } /* * Binary increment: change the rightmost 0 to a 1, and * change all 1s to the right of it to 0s. */ i = n; while (i > 0 && set[i-1]) set[--i] = 0, count--; if (i > 0) set[--i] = 1, count++; else break; /* done */ } return 0; } /* * Look for forcing chains. A forcing chain is a path of * pairwise-exclusive squares (i.e. each pair of adjacent squares * in the path are in the same row, column or block) with the * following properties: * * (a) Each square on the path has precisely two possible numbers. * * (b) Each pair of squares which are adjacent on the path share * at least one possible number in common. * * (c) Each square in the middle of the path shares _both_ of its * numbers with at least one of its neighbours (not the same * one with both neighbours). * * These together imply that at least one of the possible number * choices at one end of the path forces _all_ the rest of the * numbers along the path. In order to make real use of this, we * need further properties: * * (c) Ruling out some number N from the square at one end * of the path forces the square at the other end to * take number N. * * (d) The two end squares are both in line with some third * square. * * (e) That third square currently has N as a possibility. * * If we can find all of that lot, we can deduce that at least one * of the two ends of the forcing chain has number N, and that * therefore the mutually adjacent third square does not. * * To find forcing chains, we're going to start a bfs at each * suitable square, once for each of its two possible numbers. */ int latin_solver_forcing(struct latin_solver *solver, struct latin_solver_scratch *scratch) { int o = solver->o; #ifdef STANDALONE_SOLVER char **names = solver->names; #endif int *bfsqueue = scratch->bfsqueue; #ifdef STANDALONE_SOLVER int *bfsprev = scratch->bfsprev; #endif unsigned char *number = scratch->grid; int *neighbours = scratch->neighbours; int x, y; for (y = 0; y < o; y++) for (x = 0; x < o; x++) { int count, t, n; /* * If this square doesn't have exactly two candidate * numbers, don't try it. * * In this loop we also sum the candidate numbers, * which is a nasty hack to allow us to quickly find * `the other one' (since we will shortly know there * are exactly two). */ for (count = t = 0, n = 1; n <= o; n++) if (cube(x, y, n)) count++, t += n; if (count != 2) continue; /* * Now attempt a bfs for each candidate. */ for (n = 1; n <= o; n++) if (cube(x, y, n)) { int orign, currn, head, tail; /* * Begin a bfs. */ orign = n; memset(number, o+1, o*o); head = tail = 0; bfsqueue[tail++] = y*o+x; #ifdef STANDALONE_SOLVER bfsprev[y*o+x] = -1; #endif number[y*o+x] = t - n; while (head < tail) { int xx, yy, nneighbours, xt, yt, i; xx = bfsqueue[head++]; yy = xx / o; xx %= o; currn = number[yy*o+xx]; /* * Find neighbours of yy,xx. */ nneighbours = 0; for (yt = 0; yt < o; yt++) neighbours[nneighbours++] = yt*o+xx; for (xt = 0; xt < o; xt++) neighbours[nneighbours++] = yy*o+xt; /* * Try visiting each of those neighbours. */ for (i = 0; i < nneighbours; i++) { int cc, tt, nn; xt = neighbours[i] % o; yt = neighbours[i] / o; /* * We need this square to not be * already visited, and to include * currn as a possible number. */ if (number[yt*o+xt] <= o) continue; if (!cube(xt, yt, currn)) continue; /* * Don't visit _this_ square a second * time! */ if (xt == xx && yt == yy) continue; /* * To continue with the bfs, we need * this square to have exactly two * possible numbers. */ for (cc = tt = 0, nn = 1; nn <= o; nn++) if (cube(xt, yt, nn)) cc++, tt += nn; if (cc == 2) { bfsqueue[tail++] = yt*o+xt; #ifdef STANDALONE_SOLVER bfsprev[yt*o+xt] = yy*o+xx; #endif number[yt*o+xt] = tt - currn; } /* * One other possibility is that this * might be the square in which we can * make a real deduction: if it's * adjacent to x,y, and currn is equal * to the original number we ruled out. */ if (currn == orign && (xt == x || yt == y)) { #ifdef STANDALONE_SOLVER if (solver_show_working) { char *sep = ""; int xl, yl; printf("%*sforcing chain, %s at ends of ", solver_recurse_depth*4, "", names[orign-1]); xl = xx; yl = yy; while (1) { printf("%s(%d,%d)", sep, xl+1, yl+1); xl = bfsprev[yl*o+xl]; if (xl < 0) break; yl = xl / o; xl %= o; sep = "-"; } printf("\n%*s ruling out %s at (%d,%d)\n", solver_recurse_depth*4, "", names[orign-1], xt+1, yt+1); } #endif cube(xt, yt, orign) = FALSE; return 1; } } } } } return 0; } struct latin_solver_scratch *latin_solver_new_scratch(struct latin_solver *solver) { struct latin_solver_scratch *scratch = snew(struct latin_solver_scratch); int o = solver->o; scratch->grid = snewn(o*o, unsigned char); scratch->rowidx = snewn(o, unsigned char); scratch->colidx = snewn(o, unsigned char); scratch->set = snewn(o, unsigned char); scratch->neighbours = snewn(3*o, int); scratch->bfsqueue = snewn(o*o, int); #ifdef STANDALONE_SOLVER scratch->bfsprev = snewn(o*o, int); #endif return scratch; } void latin_solver_free_scratch(struct latin_solver_scratch *scratch) { #ifdef STANDALONE_SOLVER sfree(scratch->bfsprev); #endif sfree(scratch->bfsqueue); sfree(scratch->neighbours); sfree(scratch->set); sfree(scratch->colidx); sfree(scratch->rowidx); sfree(scratch->grid); sfree(scratch); } void latin_solver_alloc(struct latin_solver *solver, digit *grid, int o) { int x, y; solver->o = o; solver->cube = snewn(o*o*o, unsigned char); solver->grid = grid; /* write straight back to the input */ memset(solver->cube, TRUE, o*o*o); solver->row = snewn(o*o, unsigned char); solver->col = snewn(o*o, unsigned char); memset(solver->row, FALSE, o*o); memset(solver->col, FALSE, o*o); for (x = 0; x < o; x++) for (y = 0; y < o; y++) if (grid[y*o+x]) latin_solver_place(solver, x, y, grid[y*o+x]); #ifdef STANDALONE_SOLVER solver->names = NULL; #endif } void latin_solver_free(struct latin_solver *solver) { sfree(solver->cube); sfree(solver->row); sfree(solver->col); } int latin_solver_diff_simple(struct latin_solver *solver) { int x, y, n, ret, o = solver->o; #ifdef STANDALONE_SOLVER char **names = solver->names; #endif /* * Row-wise positional elimination. */ for (y = 0; y < o; y++) for (n = 1; n <= o; n++) if (!solver->row[y*o+n-1]) { ret = latin_solver_elim(solver, cubepos(0,y,n), o*o #ifdef STANDALONE_SOLVER , "positional elimination," " %s in row %d", names[n-1], y+1 #endif ); if (ret != 0) return ret; } /* * Column-wise positional elimination. */ for (x = 0; x < o; x++) for (n = 1; n <= o; n++) if (!solver->col[x*o+n-1]) { ret = latin_solver_elim(solver, cubepos(x,0,n), o #ifdef STANDALONE_SOLVER , "positional elimination," " %s in column %d", names[n-1], x+1 #endif ); if (ret != 0) return ret; } /* * Numeric elimination. */ for (x = 0; x < o; x++) for (y = 0; y < o; y++) if (!solver->grid[y*o+x]) { ret = latin_solver_elim(solver, cubepos(x,y,1), 1 #ifdef STANDALONE_SOLVER , "numeric elimination at (%d,%d)", x+1, y+1 #endif ); if (ret != 0) return ret; } return 0; } int latin_solver_diff_set(struct latin_solver *solver, struct latin_solver_scratch *scratch, int extreme) { int x, y, n, ret, o = solver->o; #ifdef STANDALONE_SOLVER char **names = solver->names; #endif if (!extreme) { /* * Row-wise set elimination. */ for (y = 0; y < o; y++) { ret = latin_solver_set(solver, scratch, cubepos(0,y,1), o*o, 1 #ifdef STANDALONE_SOLVER , "set elimination, row %d", y+1 #endif ); if (ret != 0) return ret; } /* * Column-wise set elimination. */ for (x = 0; x < o; x++) { ret = latin_solver_set(solver, scratch, cubepos(x,0,1), o, 1 #ifdef STANDALONE_SOLVER , "set elimination, column %d", x+1 #endif ); if (ret != 0) return ret; } } else { /* * Row-vs-column set elimination on a single number * (much tricker for a human to do!) */ for (n = 1; n <= o; n++) { ret = latin_solver_set(solver, scratch, cubepos(0,0,n), o*o, o #ifdef STANDALONE_SOLVER , "positional set elimination on %s", names[n-1] #endif ); if (ret != 0) return ret; } } return 0; } /* * Returns: * 0 for 'didn't do anything' implying it was already solved. * -1 for 'impossible' (no solution) * 1 for 'single solution' * >1 for 'multiple solutions' (you don't get to know how many, and * the first such solution found will be set. * * and this function may well assert if given an impossible board. */ static int latin_solver_recurse (struct latin_solver *solver, int diff_simple, int diff_set_0, int diff_set_1, int diff_forcing, int diff_recursive, usersolver_t const *usersolvers, void *ctx, ctxnew_t ctxnew, ctxfree_t ctxfree) { int best, bestcount; int o = solver->o, x, y, n; #ifdef STANDALONE_SOLVER char **names = solver->names; #endif best = -1; bestcount = o+1; for (y = 0; y < o; y++) for (x = 0; x < o; x++) if (!solver->grid[y*o+x]) { int count; /* * An unfilled square. Count the number of * possible digits in it. */ count = 0; for (n = 1; n <= o; n++) if (cube(x,y,n)) count++; /* * We should have found any impossibilities * already, so this can safely be an assert. */ assert(count > 1); if (count < bestcount) { bestcount = count; best = y*o+x; } } if (best == -1) /* we were complete already. */ return 0; else { int i, j; digit *list, *ingrid, *outgrid; int diff = diff_impossible; /* no solution found yet */ /* * Attempt recursion. */ y = best / o; x = best % o; list = snewn(o, digit); ingrid = snewn(o*o, digit); outgrid = snewn(o*o, digit); memcpy(ingrid, solver->grid, o*o); /* Make a list of the possible digits. */ for (j = 0, n = 1; n <= o; n++) if (cube(x,y,n)) list[j++] = n; #ifdef STANDALONE_SOLVER if (solver_show_working) { char *sep = ""; printf("%*srecursing on (%d,%d) [", solver_recurse_depth*4, "", x+1, y+1); for (i = 0; i < j; i++) { printf("%s%s", sep, names[list[i]-1]); sep = " or "; } printf("]\n"); } #endif /* * And step along the list, recursing back into the * main solver at every stage. */ for (i = 0; i < j; i++) { int ret; void *newctx; struct latin_solver subsolver; memcpy(outgrid, ingrid, o*o); outgrid[y*o+x] = list[i]; #ifdef STANDALONE_SOLVER if (solver_show_working) printf("%*sguessing %s at (%d,%d)\n", solver_recurse_depth*4, "", names[list[i]-1], x+1, y+1); solver_recurse_depth++; #endif if (ctxnew) { newctx = ctxnew(ctx); } else { newctx = ctx; } latin_solver_alloc(&subsolver, outgrid, o); #ifdef STANDALONE_SOLVER subsolver.names = solver->names; #endif ret = latin_solver_top(&subsolver, diff_recursive, diff_simple, diff_set_0, diff_set_1, diff_forcing, diff_recursive, usersolvers, newctx, ctxnew, ctxfree); latin_solver_free(&subsolver); if (ctxnew) ctxfree(newctx); #ifdef STANDALONE_SOLVER solver_recurse_depth--; if (solver_show_working) { printf("%*sretracting %s at (%d,%d)\n", solver_recurse_depth*4, "", names[list[i]-1], x+1, y+1); } #endif /* we recurse as deep as we can, so we should never find * find ourselves giving up on a puzzle without declaring it * impossible. */ assert(ret != diff_unfinished); /* * If we have our first solution, copy it into the * grid we will return. */ if (diff == diff_impossible && ret != diff_impossible) memcpy(solver->grid, outgrid, o*o); if (ret == diff_ambiguous) diff = diff_ambiguous; else if (ret == diff_impossible) /* do not change our return value */; else { /* the recursion turned up exactly one solution */ if (diff == diff_impossible) diff = diff_recursive; else diff = diff_ambiguous; } /* * As soon as we've found more than one solution, * give up immediately. */ if (diff == diff_ambiguous) break; } sfree(outgrid); sfree(ingrid); sfree(list); if (diff == diff_impossible) return -1; else if (diff == diff_ambiguous) return 2; else { assert(diff == diff_recursive); return 1; } } } static int latin_solver_top(struct latin_solver *solver, int maxdiff, int diff_simple, int diff_set_0, int diff_set_1, int diff_forcing, int diff_recursive, usersolver_t const *usersolvers, void *ctx, ctxnew_t ctxnew, ctxfree_t ctxfree) { struct latin_solver_scratch *scratch = latin_solver_new_scratch(solver); int ret, diff = diff_simple; assert(maxdiff <= diff_recursive); /* * Now loop over the grid repeatedly trying all permitted modes * of reasoning. The loop terminates if we complete an * iteration without making any progress; we then return * failure or success depending on whether the grid is full or * not. */ while (1) { int i; cont: latin_solver_debug(solver->cube, solver->o); for (i = 0; i <= maxdiff; i++) { if (usersolvers[i]) ret = usersolvers[i](solver, ctx); else ret = 0; if (ret == 0 && i == diff_simple) ret = latin_solver_diff_simple(solver); if (ret == 0 && i == diff_set_0) ret = latin_solver_diff_set(solver, scratch, 0); if (ret == 0 && i == diff_set_1) ret = latin_solver_diff_set(solver, scratch, 1); if (ret == 0 && i == diff_forcing) ret = latin_solver_forcing(solver, scratch); if (ret < 0) { diff = diff_impossible; goto got_result; } else if (ret > 0) { diff = max(diff, i); goto cont; } } /* * If we reach here, we have made no deductions in this * iteration, so the algorithm terminates. */ break; } /* * Last chance: if we haven't fully solved the puzzle yet, try * recursing based on guesses for a particular square. We pick * one of the most constrained empty squares we can find, which * has the effect of pruning the search tree as much as * possible. */ if (maxdiff == diff_recursive) { int nsol = latin_solver_recurse(solver, diff_simple, diff_set_0, diff_set_1, diff_forcing, diff_recursive, usersolvers, ctx, ctxnew, ctxfree); if (nsol < 0) diff = diff_impossible; else if (nsol == 1) diff = diff_recursive; else if (nsol > 1) diff = diff_ambiguous; /* if nsol == 0 then we were complete anyway * (and thus don't need to change diff) */ } else { /* * We're forbidden to use recursion, so we just see whether * our grid is fully solved, and return diff_unfinished * otherwise. */ int x, y, o = solver->o; for (y = 0; y < o; y++) for (x = 0; x < o; x++) if (!solver->grid[y*o+x]) diff = diff_unfinished; } got_result: #ifdef STANDALONE_SOLVER if (solver_show_working) printf("%*s%s found\n", solver_recurse_depth*4, "", diff == diff_impossible ? "no solution (impossible)" : diff == diff_unfinished ? "no solution (unfinished)" : diff == diff_ambiguous ? "multiple solutions" : "one solution"); #endif latin_solver_free_scratch(scratch); return diff; } int latin_solver_main(struct latin_solver *solver, int maxdiff, int diff_simple, int diff_set_0, int diff_set_1, int diff_forcing, int diff_recursive, usersolver_t const *usersolvers, void *ctx, ctxnew_t ctxnew, ctxfree_t ctxfree) { int diff; #ifdef STANDALONE_SOLVER int o = solver->o; char *text = NULL, **names = NULL; #endif #ifdef STANDALONE_SOLVER if (!solver->names) { char *p; int i; text = snewn(40 * o, char); p = text; solver->names = snewn(o, char *); for (i = 0; i < o; i++) { solver->names[i] = p; p += 1 + sprintf(p, "%d", i+1); } } #endif diff = latin_solver_top(solver, maxdiff, diff_simple, diff_set_0, diff_set_1, diff_forcing, diff_recursive, usersolvers, ctx, ctxnew, ctxfree); #ifdef STANDALONE_SOLVER sfree(names); sfree(text); #endif return diff; } int latin_solver(digit *grid, int o, int maxdiff, int diff_simple, int diff_set_0, int diff_set_1, int diff_forcing, int diff_recursive, usersolver_t const *usersolvers, void *ctx, ctxnew_t ctxnew, ctxfree_t ctxfree) { struct latin_solver solver; int diff; latin_solver_alloc(&solver, grid, o); diff = latin_solver_main(&solver, maxdiff, diff_simple, diff_set_0, diff_set_1, diff_forcing, diff_recursive, usersolvers, ctx, ctxnew, ctxfree); latin_solver_free(&solver); return diff; } void latin_solver_debug(unsigned char *cube, int o) { #ifdef STANDALONE_SOLVER if (solver_show_working > 1) { struct latin_solver ls, *solver = &ls; char *dbg; int x, y, i, c = 0; ls.cube = cube; ls.o = o; /* for cube() to work */ dbg = snewn(3*o*o*o, char); for (y = 0; y < o; y++) { for (x = 0; x < o; x++) { for (i = 1; i <= o; i++) { if (cube(x,y,i)) dbg[c++] = i + '0'; else dbg[c++] = '.'; } dbg[c++] = ' '; } dbg[c++] = '\n'; } dbg[c++] = '\n'; dbg[c++] = '\0'; printf("%s", dbg); sfree(dbg); } #endif } void latin_debug(digit *sq, int o) { #ifdef STANDALONE_SOLVER if (solver_show_working) { int x, y; for (y = 0; y < o; y++) { for (x = 0; x < o; x++) { printf("%2d ", sq[y*o+x]); } printf("\n"); } printf("\n"); } #endif } /* -------------------------------------------------------- * Generation. */ digit *latin_generate(int o, random_state *rs) { digit *sq; int *edges, *backedges, *capacity, *flow; void *scratch; int ne, scratchsize; int i, j, k; digit *row, *col, *numinv, *num; /* * To efficiently generate a latin square in such a way that * all possible squares are possible outputs from the function, * we make use of a theorem which states that any r x n latin * rectangle, with r < n, can be extended into an (r+1) x n * latin rectangle. In other words, we can reliably generate a * latin square row by row, by at every stage writing down any * row at all which doesn't conflict with previous rows, and * the theorem guarantees that we will never have to backtrack. * * To find a viable row at each stage, we can make use of the * support functions in maxflow.c. */ sq = snewn(o*o, digit); /* * In case this method of generation introduces a really subtle * top-to-bottom directional bias, we'll generate the rows in * random order. */ row = snewn(o, digit); col = snewn(o, digit); numinv = snewn(o, digit); num = snewn(o, digit); for (i = 0; i < o; i++) row[i] = i; shuffle(row, i, sizeof(*row), rs); /* * Set up the infrastructure for the maxflow algorithm. */ scratchsize = maxflow_scratch_size(o * 2 + 2); scratch = smalloc(scratchsize); backedges = snewn(o*o + 2*o, int); edges = snewn((o*o + 2*o) * 2, int); capacity = snewn(o*o + 2*o, int); flow = snewn(o*o + 2*o, int); /* Set up the edge array, and the initial capacities. */ ne = 0; for (i = 0; i < o; i++) { /* Each LHS vertex is connected to all RHS vertices. */ for (j = 0; j < o; j++) { edges[ne*2] = i; edges[ne*2+1] = j+o; /* capacity for this edge is set later on */ ne++; } } for (i = 0; i < o; i++) { /* Each RHS vertex is connected to the distinguished sink vertex. */ edges[ne*2] = i+o; edges[ne*2+1] = o*2+1; capacity[ne] = 1; ne++; } for (i = 0; i < o; i++) { /* And the distinguished source vertex connects to each LHS vertex. */ edges[ne*2] = o*2; edges[ne*2+1] = i; capacity[ne] = 1; ne++; } assert(ne == o*o + 2*o); /* Now set up backedges. */ maxflow_setup_backedges(ne, edges, backedges); /* * Now generate each row of the latin square. */ for (i = 0; i < o; i++) { /* * To prevent maxflow from behaving deterministically, we * separately permute the columns and the digits for the * purposes of the algorithm, differently for every row. */ for (j = 0; j < o; j++) col[j] = num[j] = j; shuffle(col, j, sizeof(*col), rs); shuffle(num, j, sizeof(*num), rs); /* We need the num permutation in both forward and inverse forms. */ for (j = 0; j < o; j++) numinv[num[j]] = j; /* * Set up the capacities for the maxflow run, by examining * the existing latin square. */ for (j = 0; j < o*o; j++) capacity[j] = 1; for (j = 0; j < i; j++) for (k = 0; k < o; k++) { int n = num[sq[row[j]*o + col[k]] - 1]; capacity[k*o+n] = 0; } /* * Run maxflow. */ j = maxflow_with_scratch(scratch, o*2+2, 2*o, 2*o+1, ne, edges, backedges, capacity, flow, NULL); assert(j == o); /* by the above theorem, this must have succeeded */ /* * And examine the flow array to pick out the new row of * the latin square. */ for (j = 0; j < o; j++) { for (k = 0; k < o; k++) { if (flow[j*o+k]) break; } assert(k < o); sq[row[i]*o + col[j]] = numinv[k] + 1; } } /* * Done. Free our internal workspaces... */ sfree(flow); sfree(capacity); sfree(edges); sfree(backedges); sfree(scratch); sfree(numinv); sfree(num); sfree(col); sfree(row); /* * ... and return our completed latin square. */ return sq; } digit *latin_generate_rect(int w, int h, random_state *rs) { int o = max(w, h), x, y; digit *latin, *latin_rect; latin = latin_generate(o, rs); latin_rect = snewn(w*h, digit); for (x = 0; x < w; x++) { for (y = 0; y < h; y++) { latin_rect[y*w + x] = latin[y*o + x]; } } sfree(latin); return latin_rect; } /* -------------------------------------------------------- * Checking. */ typedef struct lcparams { digit elt; int count; } lcparams; static int latin_check_cmp(void *v1, void *v2) { lcparams *lc1 = (lcparams *)v1; lcparams *lc2 = (lcparams *)v2; if (lc1->elt < lc2->elt) return -1; if (lc1->elt > lc2->elt) return 1; return 0; } #define ELT(sq,x,y) (sq[((y)*order)+(x)]) /* returns non-zero if sq is not a latin square. */ int latin_check(digit *sq, int order) { tree234 *dict = newtree234(latin_check_cmp); int c, r; int ret = 0; lcparams *lcp, lc, *aret; /* Use a tree234 as a simple hash table, go through the square * adding elements as we go or incrementing their counts. */ for (c = 0; c < order; c++) { for (r = 0; r < order; r++) { lc.elt = ELT(sq, c, r); lc.count = 0; lcp = find234(dict, &lc, NULL); if (!lcp) { lcp = snew(lcparams); lcp->elt = ELT(sq, c, r); lcp->count = 1; aret = add234(dict, lcp); assert(aret == lcp); } else { lcp->count++; } } } /* There should be precisely 'order' letters in the alphabet, * each occurring 'order' times (making the OxO tree) */ if (count234(dict) != order) ret = 1; else { for (c = 0; (lcp = index234(dict, c)) != NULL; c++) { if (lcp->count != order) ret = 1; } } for (c = 0; (lcp = index234(dict, c)) != NULL; c++) sfree(lcp); freetree234(dict); return ret; } /* -------------------------------------------------------- * Testing (and printing). */ #ifdef STANDALONE_LATIN_TEST #include #include const char *quis; static void latin_print(digit *sq, int order) { int x, y; for (y = 0; y < order; y++) { for (x = 0; x < order; x++) { printf("%2u ", ELT(sq, x, y)); } printf("\n"); } printf("\n"); } static void gen(int order, random_state *rs, int debug) { digit *sq; solver_show_working = debug; sq = latin_generate(order, rs); latin_print(sq, order); if (latin_check(sq, order)) { fprintf(stderr, "Square is not a latin square!"); exit(1); } sfree(sq); } void test_soak(int order, random_state *rs) { digit *sq; int n = 0; time_t tt_start, tt_now, tt_last; solver_show_working = 0; tt_now = tt_start = time(NULL); while(1) { sq = latin_generate(order, rs); sfree(sq); n++; tt_last = time(NULL); if (tt_last > tt_now) { tt_now = tt_last; printf("%d total, %3.1f/s\n", n, (double)n / (double)(tt_now - tt_start)); } } } void usage_exit(const char *msg) { if (msg) fprintf(stderr, "%s: %s\n", quis, msg); fprintf(stderr, "Usage: %s [--seed SEED] --soak | [game_id [game_id ...]]\n", quis); exit(1); } int main(int argc, char *argv[]) { int i, soak = 0; random_state *rs; time_t seed = time(NULL); quis = argv[0]; while (--argc > 0) { const char *p = *++argv; if (!strcmp(p, "--soak")) soak = 1; else if (!strcmp(p, "--seed")) { if (argc == 0) usage_exit("--seed needs an argument"); seed = (time_t)atoi(*++argv); argc--; } else if (*p == '-') usage_exit("unrecognised option"); else break; /* finished options */ } rs = random_new((void*)&seed, sizeof(time_t)); if (soak == 1) { if (argc != 1) usage_exit("only one argument for --soak"); test_soak(atoi(*argv), rs); } else { if (argc > 0) { for (i = 0; i < argc; i++) { gen(atoi(*argv++), rs, 1); } } else { while (1) { i = random_upto(rs, 20) + 1; gen(i, rs, 0); } } } random_free(rs); return 0; } #endif /* vim: set shiftwidth=4 tabstop=8: */ puzzles-20170606.272beef/keen.c0000644000175000017500000017712313115373615014772 0ustar simonsimon/* * keen.c: an implementation of the Times's 'KenKen' puzzle, and * also of Nikoli's very similar 'Inshi No Heya' puzzle. */ #include #include #include #include #include #include #include "puzzles.h" #include "latin.h" /* * Difficulty levels. I do some macro ickery here to ensure that my * enum and the various forms of my name list always match up. */ #define DIFFLIST(A) \ A(EASY,Easy,solver_easy,e) \ A(NORMAL,Normal,solver_normal,n) \ A(HARD,Hard,solver_hard,h) \ A(EXTREME,Extreme,NULL,x) \ A(UNREASONABLE,Unreasonable,NULL,u) #define ENUM(upper,title,func,lower) DIFF_ ## upper, #define TITLE(upper,title,func,lower) #title, #define ENCODE(upper,title,func,lower) #lower #define CONFIG(upper,title,func,lower) ":" #title enum { DIFFLIST(ENUM) DIFFCOUNT }; static char const *const keen_diffnames[] = { DIFFLIST(TITLE) }; static char const keen_diffchars[] = DIFFLIST(ENCODE); #define DIFFCONFIG DIFFLIST(CONFIG) /* * Clue notation. Important here that ADD and MUL come before SUB * and DIV, and that DIV comes last. */ #define C_ADD 0x00000000L #define C_MUL 0x20000000L #define C_SUB 0x40000000L #define C_DIV 0x60000000L #define CMASK 0x60000000L #define CUNIT 0x20000000L /* * Maximum size of any clue block. Very large ones are annoying in UI * terms (if they're multiplicative you end up with too many digits to * fit in the square) and also in solver terms (too many possibilities * to iterate over). */ #define MAXBLK 6 enum { COL_BACKGROUND, COL_GRID, COL_USER, COL_HIGHLIGHT, COL_ERROR, COL_PENCIL, NCOLOURS }; struct game_params { int w, diff, multiplication_only; }; struct clues { int refcount; int w; int *dsf; long *clues; }; struct game_state { game_params par; struct clues *clues; digit *grid; int *pencil; /* bitmaps using bits 1<<1..1<w = 6; ret->diff = DIFF_NORMAL; ret->multiplication_only = FALSE; return ret; } const static struct game_params keen_presets[] = { { 4, DIFF_EASY, FALSE }, { 5, DIFF_EASY, FALSE }, { 5, DIFF_EASY, TRUE }, { 6, DIFF_EASY, FALSE }, { 6, DIFF_NORMAL, FALSE }, { 6, DIFF_NORMAL, TRUE }, { 6, DIFF_HARD, FALSE }, { 6, DIFF_EXTREME, FALSE }, { 6, DIFF_UNREASONABLE, FALSE }, { 9, DIFF_NORMAL, FALSE }, }; static int game_fetch_preset(int i, char **name, game_params **params) { game_params *ret; char buf[80]; if (i < 0 || i >= lenof(keen_presets)) return FALSE; ret = snew(game_params); *ret = keen_presets[i]; /* structure copy */ sprintf(buf, "%dx%d %s%s", ret->w, ret->w, keen_diffnames[ret->diff], ret->multiplication_only ? ", multiplication only" : ""); *name = dupstr(buf); *params = ret; return TRUE; } static void free_params(game_params *params) { sfree(params); } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } static void decode_params(game_params *params, char const *string) { char const *p = string; params->w = atoi(p); while (*p && isdigit((unsigned char)*p)) p++; if (*p == 'd') { int i; p++; params->diff = DIFFCOUNT+1; /* ...which is invalid */ if (*p) { for (i = 0; i < DIFFCOUNT; i++) { if (*p == keen_diffchars[i]) params->diff = i; } p++; } } if (*p == 'm') { p++; params->multiplication_only = TRUE; } } static char *encode_params(const game_params *params, int full) { char ret[80]; sprintf(ret, "%d", params->w); if (full) sprintf(ret + strlen(ret), "d%c%s", keen_diffchars[params->diff], params->multiplication_only ? "m" : ""); return dupstr(ret); } static config_item *game_configure(const game_params *params) { config_item *ret; char buf[80]; ret = snewn(4, config_item); ret[0].name = "Grid size"; ret[0].type = C_STRING; sprintf(buf, "%d", params->w); ret[0].sval = dupstr(buf); ret[0].ival = 0; ret[1].name = "Difficulty"; ret[1].type = C_CHOICES; ret[1].sval = DIFFCONFIG; ret[1].ival = params->diff; ret[2].name = "Multiplication only"; ret[2].type = C_BOOLEAN; ret[2].sval = NULL; ret[2].ival = params->multiplication_only; ret[3].name = NULL; ret[3].type = C_END; ret[3].sval = NULL; ret[3].ival = 0; return ret; } static game_params *custom_params(const config_item *cfg) { game_params *ret = snew(game_params); ret->w = atoi(cfg[0].sval); ret->diff = cfg[1].ival; ret->multiplication_only = cfg[2].ival; return ret; } static char *validate_params(const game_params *params, int full) { if (params->w < 3 || params->w > 9) return "Grid size must be between 3 and 9"; if (params->diff >= DIFFCOUNT) return "Unknown difficulty rating"; return NULL; } /* ---------------------------------------------------------------------- * Solver. */ struct solver_ctx { int w, diff; int nboxes; int *boxes, *boxlist, *whichbox; long *clues; digit *soln; digit *dscratch; int *iscratch; }; static void solver_clue_candidate(struct solver_ctx *ctx, int diff, int box) { int w = ctx->w; int n = ctx->boxes[box+1] - ctx->boxes[box]; int j; /* * This function is called from the main clue-based solver * routine when we discover a candidate layout for a given clue * box consistent with everything we currently know about the * digit constraints in that box. We expect to find the digits * of the candidate layout in ctx->dscratch, and we update * ctx->iscratch as appropriate. * * The contents of ctx->iscratch are completely different * depending on whether diff == DIFF_HARD or not. This function * uses iscratch completely differently between the two cases, and * the code in solver_common() which consumes the result must * likewise have an if statement with completely different * branches for the two cases. * * In DIFF_EASY and DIFF_NORMAL modes, the valid entries in * ctx->iscratch are 0,...,n-1, and each of those entries * ctx->iscratch[i] gives a bitmap of the possible digits in the * ith square of the clue box currently under consideration. So * each entry of iscratch starts off as an empty bitmap, and we * set bits in it as possible layouts for the clue box are * considered (and the difference between DIFF_EASY and * DIFF_NORMAL is just that in DIFF_EASY mode we deliberately set * more bits than absolutely necessary, hence restricting our own * knowledge). * * But in DIFF_HARD mode, the valid entries are 0,...,2*w-1 (at * least outside *this* function - inside this function, we also * use 2*w,...,4*w-1 as scratch space in the loop below); the * first w of those give the possible digits in the intersection * of the current clue box with each column of the puzzle, and the * next w do the same for each row. In this mode, each iscratch * entry starts off as a _full_ bitmap, and in this function we * _clear_ bits for digits that are absent from a given row or * column in each candidate layout, so that the only bits which * remain set are those for digits which have to appear in a given * row/column no matter how the clue box is laid out. */ if (diff == DIFF_EASY) { unsigned mask = 0; /* * Easy-mode clue deductions: we do not record information * about which squares take which values, so we amalgamate * all the values in dscratch and OR them all into * everywhere. */ for (j = 0; j < n; j++) mask |= 1 << ctx->dscratch[j]; for (j = 0; j < n; j++) ctx->iscratch[j] |= mask; } else if (diff == DIFF_NORMAL) { /* * Normal-mode deductions: we process the information in * dscratch in the obvious way. */ for (j = 0; j < n; j++) ctx->iscratch[j] |= 1 << ctx->dscratch[j]; } else if (diff == DIFF_HARD) { /* * Hard-mode deductions: instead of ruling things out * _inside_ the clue box, we look for numbers which occur in * a given row or column in all candidate layouts, and rule * them out of all squares in that row or column that * _aren't_ part of this clue box. */ int *sq = ctx->boxlist + ctx->boxes[box]; for (j = 0; j < 2*w; j++) ctx->iscratch[2*w+j] = 0; for (j = 0; j < n; j++) { int x = sq[j] / w, y = sq[j] % w; ctx->iscratch[2*w+x] |= 1 << ctx->dscratch[j]; ctx->iscratch[3*w+y] |= 1 << ctx->dscratch[j]; } for (j = 0; j < 2*w; j++) ctx->iscratch[j] &= ctx->iscratch[2*w+j]; } } static int solver_common(struct latin_solver *solver, void *vctx, int diff) { struct solver_ctx *ctx = (struct solver_ctx *)vctx; int w = ctx->w; int box, i, j, k; int ret = 0, total; /* * Iterate over each clue box and deduce what we can. */ for (box = 0; box < ctx->nboxes; box++) { int *sq = ctx->boxlist + ctx->boxes[box]; int n = ctx->boxes[box+1] - ctx->boxes[box]; long value = ctx->clues[box] & ~CMASK; long op = ctx->clues[box] & CMASK; /* * Initialise ctx->iscratch for this clue box. At different * difficulty levels we must initialise a different amount of * it to different things; see the comments in * solver_clue_candidate explaining what each version does. */ if (diff == DIFF_HARD) { for (i = 0; i < 2*w; i++) ctx->iscratch[i] = (1 << (w+1)) - (1 << 1); } else { for (i = 0; i < n; i++) ctx->iscratch[i] = 0; } switch (op) { case C_SUB: case C_DIV: /* * These two clue types must always apply to a box of * area 2. Also, the two digits in these boxes can never * be the same (because any domino must have its two * squares in either the same row or the same column). * So we simply iterate over all possibilities for the * two squares (both ways round), rule out any which are * inconsistent with the digit constraints we already * have, and update the digit constraints with any new * information thus garnered. */ assert(n == 2); for (i = 1; i <= w; i++) { j = (op == C_SUB ? i + value : i * value); if (j > w) break; /* (i,j) is a valid digit pair. Try it both ways round. */ if (solver->cube[sq[0]*w+i-1] && solver->cube[sq[1]*w+j-1]) { ctx->dscratch[0] = i; ctx->dscratch[1] = j; solver_clue_candidate(ctx, diff, box); } if (solver->cube[sq[0]*w+j-1] && solver->cube[sq[1]*w+i-1]) { ctx->dscratch[0] = j; ctx->dscratch[1] = i; solver_clue_candidate(ctx, diff, box); } } break; case C_ADD: case C_MUL: /* * For these clue types, I have no alternative but to go * through all possible number combinations. * * Instead of a tedious physical recursion, I iterate in * the scratch array through all possibilities. At any * given moment, i indexes the element of the box that * will next be incremented. */ i = 0; ctx->dscratch[i] = 0; total = value; /* start with the identity */ while (1) { if (i < n) { /* * Find the next valid value for cell i. */ for (j = ctx->dscratch[i] + 1; j <= w; j++) { if (op == C_ADD ? (total < j) : (total % j != 0)) continue; /* this one won't fit */ if (!solver->cube[sq[i]*w+j-1]) continue; /* this one is ruled out already */ for (k = 0; k < i; k++) if (ctx->dscratch[k] == j && (sq[k] % w == sq[i] % w || sq[k] / w == sq[i] / w)) break; /* clashes with another row/col */ if (k < i) continue; /* Found one. */ break; } if (j > w) { /* No valid values left; drop back. */ i--; if (i < 0) break; /* overall iteration is finished */ if (op == C_ADD) total += ctx->dscratch[i]; else total *= ctx->dscratch[i]; } else { /* Got a valid value; store it and move on. */ ctx->dscratch[i++] = j; if (op == C_ADD) total -= j; else total /= j; ctx->dscratch[i] = 0; } } else { if (total == (op == C_ADD ? 0 : 1)) solver_clue_candidate(ctx, diff, box); i--; if (op == C_ADD) total += ctx->dscratch[i]; else total *= ctx->dscratch[i]; } } break; } /* * Do deductions based on the information we've now * accumulated in ctx->iscratch. See the comments above in * solver_clue_candidate explaining what data is left in here, * and how it differs between DIFF_HARD and lower difficulty * levels (hence the big if statement here). */ if (diff < DIFF_HARD) { #ifdef STANDALONE_SOLVER char prefix[256]; if (solver_show_working) sprintf(prefix, "%*susing clue at (%d,%d):\n", solver_recurse_depth*4, "", sq[0]/w+1, sq[0]%w+1); else prefix[0] = '\0'; /* placate optimiser */ #endif for (i = 0; i < n; i++) for (j = 1; j <= w; j++) { if (solver->cube[sq[i]*w+j-1] && !(ctx->iscratch[i] & (1 << j))) { #ifdef STANDALONE_SOLVER if (solver_show_working) { printf("%s%*s ruling out %d at (%d,%d)\n", prefix, solver_recurse_depth*4, "", j, sq[i]/w+1, sq[i]%w+1); prefix[0] = '\0'; } #endif solver->cube[sq[i]*w+j-1] = 0; ret = 1; } } } else { #ifdef STANDALONE_SOLVER char prefix[256]; if (solver_show_working) sprintf(prefix, "%*susing clue at (%d,%d):\n", solver_recurse_depth*4, "", sq[0]/w+1, sq[0]%w+1); else prefix[0] = '\0'; /* placate optimiser */ #endif for (i = 0; i < 2*w; i++) { int start = (i < w ? i*w : i-w); int step = (i < w ? 1 : w); for (j = 1; j <= w; j++) if (ctx->iscratch[i] & (1 << j)) { #ifdef STANDALONE_SOLVER char prefix2[256]; if (solver_show_working) sprintf(prefix2, "%*s this clue requires %d in" " %s %d:\n", solver_recurse_depth*4, "", j, i < w ? "column" : "row", i%w+1); else prefix2[0] = '\0'; /* placate optimiser */ #endif for (k = 0; k < w; k++) { int pos = start + k*step; if (ctx->whichbox[pos] != box && solver->cube[pos*w+j-1]) { #ifdef STANDALONE_SOLVER if (solver_show_working) { printf("%s%s%*s ruling out %d at (%d,%d)\n", prefix, prefix2, solver_recurse_depth*4, "", j, pos/w+1, pos%w+1); prefix[0] = prefix2[0] = '\0'; } #endif solver->cube[pos*w+j-1] = 0; ret = 1; } } } } /* * Once we find one block we can do something with in * this way, revert to trying easier deductions, so as * not to generate solver diagnostics that make the * problem look harder than it is. (We have to do this * for the Hard deductions but not the Easy/Normal ones, * because only the Hard deductions are cross-box.) */ if (ret) return ret; } } return ret; } static int solver_easy(struct latin_solver *solver, void *vctx) { /* * Omit the EASY deductions when solving at NORMAL level, since * the NORMAL deductions are a superset of them anyway and it * saves on time and confusing solver diagnostics. * * Note that this breaks the natural semantics of the return * value of latin_solver. Without this hack, you could determine * a puzzle's difficulty in one go by trying to solve it at * maximum difficulty and seeing what difficulty value was * returned; but with this hack, solving an Easy puzzle on * Normal difficulty will typically return Normal. Hence the * uses of the solver to determine difficulty are all arranged * so as to double-check by re-solving at the next difficulty * level down and making sure it failed. */ struct solver_ctx *ctx = (struct solver_ctx *)vctx; if (ctx->diff > DIFF_EASY) return 0; return solver_common(solver, vctx, DIFF_EASY); } static int solver_normal(struct latin_solver *solver, void *vctx) { return solver_common(solver, vctx, DIFF_NORMAL); } static int solver_hard(struct latin_solver *solver, void *vctx) { return solver_common(solver, vctx, DIFF_HARD); } #define SOLVER(upper,title,func,lower) func, static usersolver_t const keen_solvers[] = { DIFFLIST(SOLVER) }; static int solver(int w, int *dsf, long *clues, digit *soln, int maxdiff) { int a = w*w; struct solver_ctx ctx; int ret; int i, j, n, m; ctx.w = w; ctx.soln = soln; ctx.diff = maxdiff; /* * Transform the dsf-formatted clue list into one over which we * can iterate more easily. * * Also transpose the x- and y-coordinates at this point, * because the 'cube' array in the general Latin square solver * puts x first (oops). */ for (ctx.nboxes = i = 0; i < a; i++) if (dsf_canonify(dsf, i) == i) ctx.nboxes++; ctx.boxlist = snewn(a, int); ctx.boxes = snewn(ctx.nboxes+1, int); ctx.clues = snewn(ctx.nboxes, long); ctx.whichbox = snewn(a, int); for (n = m = i = 0; i < a; i++) if (dsf_canonify(dsf, i) == i) { ctx.clues[n] = clues[i]; ctx.boxes[n] = m; for (j = 0; j < a; j++) if (dsf_canonify(dsf, j) == i) { ctx.boxlist[m++] = (j % w) * w + (j / w); /* transpose */ ctx.whichbox[ctx.boxlist[m-1]] = n; } n++; } assert(n == ctx.nboxes); assert(m == a); ctx.boxes[n] = m; ctx.dscratch = snewn(a+1, digit); ctx.iscratch = snewn(max(a+1, 4*w), int); ret = latin_solver(soln, w, maxdiff, DIFF_EASY, DIFF_HARD, DIFF_EXTREME, DIFF_EXTREME, DIFF_UNREASONABLE, keen_solvers, &ctx, NULL, NULL); sfree(ctx.dscratch); sfree(ctx.iscratch); sfree(ctx.whichbox); sfree(ctx.boxlist); sfree(ctx.boxes); sfree(ctx.clues); return ret; } /* ---------------------------------------------------------------------- * Grid generation. */ static char *encode_block_structure(char *p, int w, int *dsf) { int i, currrun = 0; char *orig, *q, *r, c; orig = p; /* * Encode the block structure. We do this by encoding the * pattern of dividing lines: first we iterate over the w*(w-1) * internal vertical grid lines in ordinary reading order, then * over the w*(w-1) internal horizontal ones in transposed * reading order. * * We encode the number of non-lines between the lines; _ means * zero (two adjacent divisions), a means 1, ..., y means 25, * and z means 25 non-lines _and no following line_ (so that za * means 26, zb 27 etc). */ for (i = 0; i <= 2*w*(w-1); i++) { int x, y, p0, p1, edge; if (i == 2*w*(w-1)) { edge = TRUE; /* terminating virtual edge */ } else { if (i < w*(w-1)) { y = i/(w-1); x = i%(w-1); p0 = y*w+x; p1 = y*w+x+1; } else { x = i/(w-1) - w; y = i%(w-1); p0 = y*w+x; p1 = (y+1)*w+x; } edge = (dsf_canonify(dsf, p0) != dsf_canonify(dsf, p1)); } if (edge) { while (currrun > 25) *p++ = 'z', currrun -= 25; if (currrun) *p++ = 'a'-1 + currrun; else *p++ = '_'; currrun = 0; } else currrun++; } /* * Now go through and compress the string by replacing runs of * the same letter with a single copy of that letter followed by * a repeat count, where that makes it shorter. (This puzzle * seems to generate enough long strings of _ to make this a * worthwhile step.) */ for (q = r = orig; r < p ;) { *q++ = c = *r; for (i = 0; r+i < p && r[i] == c; i++); r += i; if (i == 2) { *q++ = c; } else if (i > 2) { q += sprintf(q, "%d", i); } } return q; } static char *parse_block_structure(const char **p, int w, int *dsf) { int a = w*w; int pos = 0; int repc = 0, repn = 0; dsf_init(dsf, a); while (**p && (repn > 0 || **p != ',')) { int c, adv; if (repn > 0) { repn--; c = repc; } else if (**p == '_' || (**p >= 'a' && **p <= 'z')) { c = (**p == '_' ? 0 : **p - 'a' + 1); (*p)++; if (**p && isdigit((unsigned char)**p)) { repc = c; repn = atoi(*p)-1; while (**p && isdigit((unsigned char)**p)) (*p)++; } } else return "Invalid character in game description"; adv = (c != 25); /* 'z' is a special case */ while (c-- > 0) { int p0, p1; /* * Non-edge; merge the two dsf classes on either * side of it. */ if (pos >= 2*w*(w-1)) return "Too much data in block structure specification"; if (pos < w*(w-1)) { int y = pos/(w-1); int x = pos%(w-1); p0 = y*w+x; p1 = y*w+x+1; } else { int x = pos/(w-1) - w; int y = pos%(w-1); p0 = y*w+x; p1 = (y+1)*w+x; } dsf_merge(dsf, p0, p1); pos++; } if (adv) { pos++; if (pos > 2*w*(w-1)+1) return "Too much data in block structure specification"; } } /* * When desc is exhausted, we expect to have gone exactly * one space _past_ the end of the grid, due to the dummy * edge at the end. */ if (pos != 2*w*(w-1)+1) return "Not enough data in block structure specification"; return NULL; } static char *new_game_desc(const game_params *params, random_state *rs, char **aux, int interactive) { int w = params->w, a = w*w; digit *grid, *soln; int *order, *revorder, *singletons, *dsf; long *clues, *cluevals; int i, j, k, n, x, y, ret; int diff = params->diff; char *desc, *p; /* * Difficulty exceptions: 3x3 puzzles at difficulty Hard or * higher are currently not generable - the generator will spin * forever looking for puzzles of the appropriate difficulty. We * dial each of these down to the next lower difficulty. * * Remember to re-test this whenever a change is made to the * solver logic! * * I tested it using the following shell command: for d in e n h x u; do for i in {3..9}; do echo ./keen --generate 1 ${i}d${d} perl -e 'alarm 30; exec @ARGV' ./keen --generate 5 ${i}d${d} >/dev/null \ || echo broken done done * Of course, it's better to do that after taking the exceptions * _out_, so as to detect exceptions that should be removed as * well as those which should be added. */ if (w == 3 && diff > DIFF_NORMAL) diff = DIFF_NORMAL; grid = NULL; order = snewn(a, int); revorder = snewn(a, int); singletons = snewn(a, int); dsf = snew_dsf(a); clues = snewn(a, long); cluevals = snewn(a, long); soln = snewn(a, digit); while (1) { /* * First construct a latin square to be the solution. */ sfree(grid); grid = latin_generate(w, rs); /* * Divide the grid into arbitrarily sized blocks, but so as * to arrange plenty of dominoes which can be SUB/DIV clues. * We do this by first placing dominoes at random for a * while, then tying the remaining singletons one by one * into neighbouring blocks. */ for (i = 0; i < a; i++) order[i] = i; shuffle(order, a, sizeof(*order), rs); for (i = 0; i < a; i++) revorder[order[i]] = i; for (i = 0; i < a; i++) singletons[i] = TRUE; dsf_init(dsf, a); /* Place dominoes. */ for (i = 0; i < a; i++) { if (singletons[i]) { int best = -1; x = i % w; y = i / w; if (x > 0 && singletons[i-1] && (best == -1 || revorder[i-1] < revorder[best])) best = i-1; if (x+1 < w && singletons[i+1] && (best == -1 || revorder[i+1] < revorder[best])) best = i+1; if (y > 0 && singletons[i-w] && (best == -1 || revorder[i-w] < revorder[best])) best = i-w; if (y+1 < w && singletons[i+w] && (best == -1 || revorder[i+w] < revorder[best])) best = i+w; /* * When we find a potential domino, we place it with * probability 3/4, which seems to strike a decent * balance between plenty of dominoes and leaving * enough singletons to make interesting larger * shapes. */ if (best >= 0 && random_upto(rs, 4)) { singletons[i] = singletons[best] = FALSE; dsf_merge(dsf, i, best); } } } /* Fold in singletons. */ for (i = 0; i < a; i++) { if (singletons[i]) { int best = -1; x = i % w; y = i / w; if (x > 0 && dsf_size(dsf, i-1) < MAXBLK && (best == -1 || revorder[i-1] < revorder[best])) best = i-1; if (x+1 < w && dsf_size(dsf, i+1) < MAXBLK && (best == -1 || revorder[i+1] < revorder[best])) best = i+1; if (y > 0 && dsf_size(dsf, i-w) < MAXBLK && (best == -1 || revorder[i-w] < revorder[best])) best = i-w; if (y+1 < w && dsf_size(dsf, i+w) < MAXBLK && (best == -1 || revorder[i+w] < revorder[best])) best = i+w; if (best >= 0) { singletons[i] = singletons[best] = FALSE; dsf_merge(dsf, i, best); } } } /* Quit and start again if we have any singletons left over * which we weren't able to do anything at all with. */ for (i = 0; i < a; i++) if (singletons[i]) break; if (i < a) continue; /* * Decide what would be acceptable clues for each block. * * Blocks larger than 2 have free choice of ADD or MUL; * blocks of size 2 can be anything in principle (except * that they can only be DIV if the two numbers have an * integer quotient, of course), but we rule out (or try to * avoid) some clues because they're of low quality. * * Hence, we iterate once over the grid, stopping at the * canonical element of every >2 block and the _non_- * canonical element of every 2-block; the latter means that * we can make our decision about a 2-block in the knowledge * of both numbers in it. * * We reuse the 'singletons' array (finished with in the * above loop) to hold information about which blocks are * suitable for what. */ #define F_ADD 0x01 #define F_SUB 0x02 #define F_MUL 0x04 #define F_DIV 0x08 #define BAD_SHIFT 4 for (i = 0; i < a; i++) { singletons[i] = 0; j = dsf_canonify(dsf, i); k = dsf_size(dsf, j); if (params->multiplication_only) singletons[j] = F_MUL; else if (j == i && k > 2) { singletons[j] |= F_ADD | F_MUL; } else if (j != i && k == 2) { /* Fetch the two numbers and sort them into order. */ int p = grid[j], q = grid[i], v; if (p < q) { int t = p; p = q; q = t; } /* * Addition clues are always allowed, but we try to * avoid sums of 3, 4, (2w-1) and (2w-2) if we can, * because they're too easy - they only leave one * option for the pair of numbers involved. */ v = p + q; if (v > 4 && v < 2*w-2) singletons[j] |= F_ADD; else singletons[j] |= F_ADD << BAD_SHIFT; /* * Multiplication clues: above Normal difficulty, we * prefer (but don't absolutely insist on) clues of * this type which leave multiple options open. */ v = p * q; n = 0; for (k = 1; k <= w; k++) if (v % k == 0 && v / k <= w && v / k != k) n++; if (n <= 2 && diff > DIFF_NORMAL) singletons[j] |= F_MUL << BAD_SHIFT; else singletons[j] |= F_MUL; /* * Subtraction: we completely avoid a difference of * w-1. */ v = p - q; if (v < w-1) singletons[j] |= F_SUB; /* * Division: for a start, the quotient must be an * integer or the clue type is impossible. Also, we * never use quotients strictly greater than w/2, * because they're not only too easy but also * inelegant. */ if (p % q == 0 && 2 * (p / q) <= w) singletons[j] |= F_DIV; } } /* * Actually choose a clue for each block, trying to keep the * numbers of each type even, and starting with the * preferred candidates for each type where possible. * * I'm sure there should be a faster algorithm for doing * this, but I can't be bothered: O(N^2) is good enough when * N is at most the number of dominoes that fits into a 9x9 * square. */ shuffle(order, a, sizeof(*order), rs); for (i = 0; i < a; i++) clues[i] = 0; while (1) { int done_something = FALSE; for (k = 0; k < 4; k++) { long clue; int good, bad; switch (k) { case 0: clue = C_DIV; good = F_DIV; break; case 1: clue = C_SUB; good = F_SUB; break; case 2: clue = C_MUL; good = F_MUL; break; default /* case 3 */ : clue = C_ADD; good = F_ADD; break; } for (i = 0; i < a; i++) { j = order[i]; if (singletons[j] & good) { clues[j] = clue; singletons[j] = 0; break; } } if (i == a) { /* didn't find a nice one, use a nasty one */ bad = good << BAD_SHIFT; for (i = 0; i < a; i++) { j = order[i]; if (singletons[j] & bad) { clues[j] = clue; singletons[j] = 0; break; } } } if (i < a) done_something = TRUE; } if (!done_something) break; } #undef F_ADD #undef F_SUB #undef F_MUL #undef F_DIV #undef BAD_SHIFT /* * Having chosen the clue types, calculate the clue values. */ for (i = 0; i < a; i++) { j = dsf_canonify(dsf, i); if (j == i) { cluevals[j] = grid[i]; } else { switch (clues[j]) { case C_ADD: cluevals[j] += grid[i]; break; case C_MUL: cluevals[j] *= grid[i]; break; case C_SUB: cluevals[j] = abs(cluevals[j] - grid[i]); break; case C_DIV: { int d1 = cluevals[j], d2 = grid[i]; if (d1 == 0 || d2 == 0) cluevals[j] = 0; else cluevals[j] = d2/d1 + d1/d2;/* one is 0 :-) */ } break; } } } for (i = 0; i < a; i++) { j = dsf_canonify(dsf, i); if (j == i) { clues[j] |= cluevals[j]; } } /* * See if the game can be solved at the specified difficulty * level, but not at the one below. */ if (diff > 0) { memset(soln, 0, a); ret = solver(w, dsf, clues, soln, diff-1); if (ret <= diff-1) continue; } memset(soln, 0, a); ret = solver(w, dsf, clues, soln, diff); if (ret != diff) continue; /* go round again */ /* * I wondered if at this point it would be worth trying to * merge adjacent blocks together, to make the puzzle * gradually more difficult if it's currently easier than * specced, increasing the chance of a given generation run * being successful. * * It doesn't seem to be critical for the generation speed, * though, so for the moment I'm leaving it out. */ /* * We've got a usable puzzle! */ break; } /* * Encode the puzzle description. */ desc = snewn(40*a, char); p = desc; p = encode_block_structure(p, w, dsf); *p++ = ','; for (i = 0; i < a; i++) { j = dsf_canonify(dsf, i); if (j == i) { switch (clues[j] & CMASK) { case C_ADD: *p++ = 'a'; break; case C_SUB: *p++ = 's'; break; case C_MUL: *p++ = 'm'; break; case C_DIV: *p++ = 'd'; break; } p += sprintf(p, "%ld", clues[j] & ~CMASK); } } *p++ = '\0'; desc = sresize(desc, p - desc, char); /* * Encode the solution. */ assert(memcmp(soln, grid, a) == 0); *aux = snewn(a+2, char); (*aux)[0] = 'S'; for (i = 0; i < a; i++) (*aux)[i+1] = '0' + soln[i]; (*aux)[a+1] = '\0'; sfree(grid); sfree(order); sfree(revorder); sfree(singletons); sfree(dsf); sfree(clues); sfree(cluevals); sfree(soln); return desc; } /* ---------------------------------------------------------------------- * Gameplay. */ static char *validate_desc(const game_params *params, const char *desc) { int w = params->w, a = w*w; int *dsf; char *ret; const char *p = desc; int i; /* * Verify that the block structure makes sense. */ dsf = snew_dsf(a); ret = parse_block_structure(&p, w, dsf); if (ret) { sfree(dsf); return ret; } if (*p != ',') return "Expected ',' after block structure description"; p++; /* * Verify that the right number of clues are given, and that SUB * and DIV clues don't apply to blocks of the wrong size. */ for (i = 0; i < a; i++) { if (dsf_canonify(dsf, i) == i) { if (*p == 'a' || *p == 'm') { /* these clues need no validation */ } else if (*p == 'd' || *p == 's') { if (dsf_size(dsf, i) != 2) return "Subtraction and division blocks must have area 2"; } else if (!*p) { return "Too few clues for block structure"; } else { return "Unrecognised clue type"; } p++; while (*p && isdigit((unsigned char)*p)) p++; } } if (*p) return "Too many clues for block structure"; return NULL; } static game_state *new_game(midend *me, const game_params *params, const char *desc) { int w = params->w, a = w*w; game_state *state = snew(game_state); const char *p = desc; int i; state->par = *params; /* structure copy */ state->clues = snew(struct clues); state->clues->refcount = 1; state->clues->w = w; state->clues->dsf = snew_dsf(a); parse_block_structure(&p, w, state->clues->dsf); assert(*p == ','); p++; state->clues->clues = snewn(a, long); for (i = 0; i < a; i++) { if (dsf_canonify(state->clues->dsf, i) == i) { long clue = 0; switch (*p) { case 'a': clue = C_ADD; break; case 'm': clue = C_MUL; break; case 's': clue = C_SUB; assert(dsf_size(state->clues->dsf, i) == 2); break; case 'd': clue = C_DIV; assert(dsf_size(state->clues->dsf, i) == 2); break; default: assert(!"Bad description in new_game"); } p++; clue |= atol(p); while (*p && isdigit((unsigned char)*p)) p++; state->clues->clues[i] = clue; } else state->clues->clues[i] = 0; } state->grid = snewn(a, digit); state->pencil = snewn(a, int); for (i = 0; i < a; i++) { state->grid[i] = 0; state->pencil[i] = 0; } state->completed = state->cheated = FALSE; return state; } static game_state *dup_game(const game_state *state) { int w = state->par.w, a = w*w; game_state *ret = snew(game_state); ret->par = state->par; /* structure copy */ ret->clues = state->clues; ret->clues->refcount++; ret->grid = snewn(a, digit); ret->pencil = snewn(a, int); memcpy(ret->grid, state->grid, a*sizeof(digit)); memcpy(ret->pencil, state->pencil, a*sizeof(int)); ret->completed = state->completed; ret->cheated = state->cheated; return ret; } static void free_game(game_state *state) { sfree(state->grid); sfree(state->pencil); if (--state->clues->refcount <= 0) { sfree(state->clues->dsf); sfree(state->clues->clues); sfree(state->clues); } sfree(state); } static char *solve_game(const game_state *state, const game_state *currstate, const char *aux, char **error) { int w = state->par.w, a = w*w; int i, ret; digit *soln; char *out; if (aux) return dupstr(aux); soln = snewn(a, digit); memset(soln, 0, a); ret = solver(w, state->clues->dsf, state->clues->clues, soln, DIFFCOUNT-1); if (ret == diff_impossible) { *error = "No solution exists for this puzzle"; out = NULL; } else if (ret == diff_ambiguous) { *error = "Multiple solutions exist for this puzzle"; out = NULL; } else { out = snewn(a+2, char); out[0] = 'S'; for (i = 0; i < a; i++) out[i+1] = '0' + soln[i]; out[a+1] = '\0'; } sfree(soln); return out; } static int game_can_format_as_text_now(const game_params *params) { return TRUE; } static char *game_text_format(const game_state *state) { return NULL; } struct game_ui { /* * These are the coordinates of the currently highlighted * square on the grid, if hshow = 1. */ int hx, hy; /* * This indicates whether the current highlight is a * pencil-mark one or a real one. */ int hpencil; /* * This indicates whether or not we're showing the highlight * (used to be hx = hy = -1); important so that when we're * using the cursor keys it doesn't keep coming back at a * fixed position. When hshow = 1, pressing a valid number * or letter key or Space will enter that number or letter in the grid. */ int hshow; /* * This indicates whether we're using the highlight as a cursor; * it means that it doesn't vanish on a keypress, and that it is * allowed on immutable squares. */ int hcursor; }; static game_ui *new_ui(const game_state *state) { game_ui *ui = snew(game_ui); ui->hx = ui->hy = 0; ui->hpencil = ui->hshow = ui->hcursor = 0; return ui; } static void free_ui(game_ui *ui) { sfree(ui); } static char *encode_ui(const game_ui *ui) { return NULL; } static void decode_ui(game_ui *ui, const char *encoding) { } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { int w = newstate->par.w; /* * We prevent pencil-mode highlighting of a filled square, unless * we're using the cursor keys. So if the user has just filled in * a square which we had a pencil-mode highlight in (by Undo, or * by Redo, or by Solve), then we cancel the highlight. */ if (ui->hshow && ui->hpencil && !ui->hcursor && newstate->grid[ui->hy * w + ui->hx] != 0) { ui->hshow = 0; } } #define PREFERRED_TILESIZE 48 #define TILESIZE (ds->tilesize) #define BORDER (TILESIZE / 2) #define GRIDEXTRA max((TILESIZE / 32),1) #define COORD(x) ((x)*TILESIZE + BORDER) #define FROMCOORD(x) (((x)+(TILESIZE-BORDER)) / TILESIZE - 1) #define FLASH_TIME 0.4F #define DF_PENCIL_SHIFT 16 #define DF_ERR_LATIN 0x8000 #define DF_ERR_CLUE 0x4000 #define DF_HIGHLIGHT 0x2000 #define DF_HIGHLIGHT_PENCIL 0x1000 #define DF_DIGIT_MASK 0x000F struct game_drawstate { int tilesize; int started; long *tiles; long *errors; char *minus_sign, *times_sign, *divide_sign; }; static int check_errors(const game_state *state, long *errors) { int w = state->par.w, a = w*w; int i, j, x, y, errs = FALSE; long *cluevals; int *full; cluevals = snewn(a, long); full = snewn(a, int); if (errors) for (i = 0; i < a; i++) { errors[i] = 0; full[i] = TRUE; } for (i = 0; i < a; i++) { long clue; j = dsf_canonify(state->clues->dsf, i); if (j == i) { cluevals[i] = state->grid[i]; } else { clue = state->clues->clues[j] & CMASK; switch (clue) { case C_ADD: cluevals[j] += state->grid[i]; break; case C_MUL: cluevals[j] *= state->grid[i]; break; case C_SUB: cluevals[j] = abs(cluevals[j] - state->grid[i]); break; case C_DIV: { int d1 = min(cluevals[j], state->grid[i]); int d2 = max(cluevals[j], state->grid[i]); if (d1 == 0 || d2 % d1 != 0) cluevals[j] = 0; else cluevals[j] = d2 / d1; } break; } } if (!state->grid[i]) full[j] = FALSE; } for (i = 0; i < a; i++) { j = dsf_canonify(state->clues->dsf, i); if (j == i) { if ((state->clues->clues[j] & ~CMASK) != cluevals[i]) { errs = TRUE; if (errors && full[j]) errors[j] |= DF_ERR_CLUE; } } } sfree(cluevals); sfree(full); for (y = 0; y < w; y++) { int mask = 0, errmask = 0; for (x = 0; x < w; x++) { int bit = 1 << state->grid[y*w+x]; errmask |= (mask & bit); mask |= bit; } if (mask != (1 << (w+1)) - (1 << 1)) { errs = TRUE; errmask &= ~1; if (errors) { for (x = 0; x < w; x++) if (errmask & (1 << state->grid[y*w+x])) errors[y*w+x] |= DF_ERR_LATIN; } } } for (x = 0; x < w; x++) { int mask = 0, errmask = 0; for (y = 0; y < w; y++) { int bit = 1 << state->grid[y*w+x]; errmask |= (mask & bit); mask |= bit; } if (mask != (1 << (w+1)) - (1 << 1)) { errs = TRUE; errmask &= ~1; if (errors) { for (y = 0; y < w; y++) if (errmask & (1 << state->grid[y*w+x])) errors[y*w+x] |= DF_ERR_LATIN; } } } return errs; } static char *interpret_move(const game_state *state, game_ui *ui, const game_drawstate *ds, int x, int y, int button) { int w = state->par.w; int tx, ty; char buf[80]; button &= ~MOD_MASK; tx = FROMCOORD(x); ty = FROMCOORD(y); if (tx >= 0 && tx < w && ty >= 0 && ty < w) { if (button == LEFT_BUTTON) { if (tx == ui->hx && ty == ui->hy && ui->hshow && ui->hpencil == 0) { ui->hshow = 0; } else { ui->hx = tx; ui->hy = ty; ui->hshow = 1; ui->hpencil = 0; } ui->hcursor = 0; return ""; /* UI activity occurred */ } if (button == RIGHT_BUTTON) { /* * Pencil-mode highlighting for non filled squares. */ if (state->grid[ty*w+tx] == 0) { if (tx == ui->hx && ty == ui->hy && ui->hshow && ui->hpencil) { ui->hshow = 0; } else { ui->hpencil = 1; ui->hx = tx; ui->hy = ty; ui->hshow = 1; } } else { ui->hshow = 0; } ui->hcursor = 0; return ""; /* UI activity occurred */ } } if (IS_CURSOR_MOVE(button)) { move_cursor(button, &ui->hx, &ui->hy, w, w, 0); ui->hshow = ui->hcursor = 1; return ""; } if (ui->hshow && (button == CURSOR_SELECT)) { ui->hpencil = 1 - ui->hpencil; ui->hcursor = 1; return ""; } if (ui->hshow && ((button >= '0' && button <= '9' && button - '0' <= w) || button == CURSOR_SELECT2 || button == '\b')) { int n = button - '0'; if (button == CURSOR_SELECT2 || button == '\b') n = 0; /* * Can't make pencil marks in a filled square. This can only * become highlighted if we're using cursor keys. */ if (ui->hpencil && state->grid[ui->hy*w+ui->hx]) return NULL; sprintf(buf, "%c%d,%d,%d", (char)(ui->hpencil && n > 0 ? 'P' : 'R'), ui->hx, ui->hy, n); if (!ui->hcursor) ui->hshow = 0; return dupstr(buf); } if (button == 'M' || button == 'm') return dupstr("M"); return NULL; } static game_state *execute_move(const game_state *from, const char *move) { int w = from->par.w, a = w*w; game_state *ret; int x, y, i, n; if (move[0] == 'S') { ret = dup_game(from); ret->completed = ret->cheated = TRUE; for (i = 0; i < a; i++) { if (move[i+1] < '1' || move[i+1] > '0'+w) { free_game(ret); return NULL; } ret->grid[i] = move[i+1] - '0'; ret->pencil[i] = 0; } if (move[a+1] != '\0') { free_game(ret); return NULL; } return ret; } else if ((move[0] == 'P' || move[0] == 'R') && sscanf(move+1, "%d,%d,%d", &x, &y, &n) == 3 && x >= 0 && x < w && y >= 0 && y < w && n >= 0 && n <= w) { ret = dup_game(from); if (move[0] == 'P' && n > 0) { ret->pencil[y*w+x] ^= 1 << n; } else { ret->grid[y*w+x] = n; ret->pencil[y*w+x] = 0; if (!ret->completed && !check_errors(ret, NULL)) ret->completed = TRUE; } return ret; } else if (move[0] == 'M') { /* * Fill in absolutely all pencil marks everywhere. (I * wouldn't use this for actual play, but it's a handy * starting point when following through a set of * diagnostics output by the standalone solver.) */ ret = dup_game(from); for (i = 0; i < a; i++) { if (!ret->grid[i]) ret->pencil[i] = (1 << (w+1)) - (1 << 1); } return ret; } else return NULL; /* couldn't parse move string */ } /* ---------------------------------------------------------------------- * Drawing routines. */ #define SIZE(w) ((w) * TILESIZE + 2*BORDER) static void game_compute_size(const game_params *params, int tilesize, int *x, int *y) { /* Ick: fake up `ds->tilesize' for macro expansion purposes */ struct { int tilesize; } ads, *ds = &ads; ads.tilesize = tilesize; *x = *y = SIZE(params->w); } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { ds->tilesize = tilesize; } static float *game_colours(frontend *fe, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float); frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]); ret[COL_GRID * 3 + 0] = 0.0F; ret[COL_GRID * 3 + 1] = 0.0F; ret[COL_GRID * 3 + 2] = 0.0F; ret[COL_USER * 3 + 0] = 0.0F; ret[COL_USER * 3 + 1] = 0.6F * ret[COL_BACKGROUND * 3 + 1]; ret[COL_USER * 3 + 2] = 0.0F; ret[COL_HIGHLIGHT * 3 + 0] = 0.78F * ret[COL_BACKGROUND * 3 + 0]; ret[COL_HIGHLIGHT * 3 + 1] = 0.78F * ret[COL_BACKGROUND * 3 + 1]; ret[COL_HIGHLIGHT * 3 + 2] = 0.78F * ret[COL_BACKGROUND * 3 + 2]; ret[COL_ERROR * 3 + 0] = 1.0F; ret[COL_ERROR * 3 + 1] = 0.0F; ret[COL_ERROR * 3 + 2] = 0.0F; ret[COL_PENCIL * 3 + 0] = 0.5F * ret[COL_BACKGROUND * 3 + 0]; ret[COL_PENCIL * 3 + 1] = 0.5F * ret[COL_BACKGROUND * 3 + 1]; ret[COL_PENCIL * 3 + 2] = ret[COL_BACKGROUND * 3 + 2]; *ncolours = NCOLOURS; return ret; } static const char *const minus_signs[] = { "\xE2\x88\x92", "-" }; static const char *const times_signs[] = { "\xC3\x97", "*" }; static const char *const divide_signs[] = { "\xC3\xB7", "/" }; static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { int w = state->par.w, a = w*w; struct game_drawstate *ds = snew(struct game_drawstate); int i; ds->tilesize = 0; ds->started = FALSE; ds->tiles = snewn(a, long); for (i = 0; i < a; i++) ds->tiles[i] = -1; ds->errors = snewn(a, long); ds->minus_sign = text_fallback(dr, minus_signs, lenof(minus_signs)); ds->times_sign = text_fallback(dr, times_signs, lenof(times_signs)); ds->divide_sign = text_fallback(dr, divide_signs, lenof(divide_signs)); return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { sfree(ds->tiles); sfree(ds->errors); sfree(ds->minus_sign); sfree(ds->times_sign); sfree(ds->divide_sign); sfree(ds); } static void draw_tile(drawing *dr, game_drawstate *ds, struct clues *clues, int x, int y, long tile, int only_one_op) { int w = clues->w /* , a = w*w */; int tx, ty, tw, th; int cx, cy, cw, ch; char str[64]; tx = BORDER + x * TILESIZE + 1 + GRIDEXTRA; ty = BORDER + y * TILESIZE + 1 + GRIDEXTRA; cx = tx; cy = ty; cw = tw = TILESIZE-1-2*GRIDEXTRA; ch = th = TILESIZE-1-2*GRIDEXTRA; if (x > 0 && dsf_canonify(clues->dsf, y*w+x) == dsf_canonify(clues->dsf, y*w+x-1)) cx -= GRIDEXTRA, cw += GRIDEXTRA; if (x+1 < w && dsf_canonify(clues->dsf, y*w+x) == dsf_canonify(clues->dsf, y*w+x+1)) cw += GRIDEXTRA; if (y > 0 && dsf_canonify(clues->dsf, y*w+x) == dsf_canonify(clues->dsf, (y-1)*w+x)) cy -= GRIDEXTRA, ch += GRIDEXTRA; if (y+1 < w && dsf_canonify(clues->dsf, y*w+x) == dsf_canonify(clues->dsf, (y+1)*w+x)) ch += GRIDEXTRA; clip(dr, cx, cy, cw, ch); /* background needs erasing */ draw_rect(dr, cx, cy, cw, ch, (tile & DF_HIGHLIGHT) ? COL_HIGHLIGHT : COL_BACKGROUND); /* pencil-mode highlight */ if (tile & DF_HIGHLIGHT_PENCIL) { int coords[6]; coords[0] = cx; coords[1] = cy; coords[2] = cx+cw/2; coords[3] = cy; coords[4] = cx; coords[5] = cy+ch/2; draw_polygon(dr, coords, 3, COL_HIGHLIGHT, COL_HIGHLIGHT); } /* * Draw the corners of thick lines in corner-adjacent squares, * which jut into this square by one pixel. */ if (x > 0 && y > 0 && dsf_canonify(clues->dsf, y*w+x) != dsf_canonify(clues->dsf, (y-1)*w+x-1)) draw_rect(dr, tx-GRIDEXTRA, ty-GRIDEXTRA, GRIDEXTRA, GRIDEXTRA, COL_GRID); if (x+1 < w && y > 0 && dsf_canonify(clues->dsf, y*w+x) != dsf_canonify(clues->dsf, (y-1)*w+x+1)) draw_rect(dr, tx+TILESIZE-1-2*GRIDEXTRA, ty-GRIDEXTRA, GRIDEXTRA, GRIDEXTRA, COL_GRID); if (x > 0 && y+1 < w && dsf_canonify(clues->dsf, y*w+x) != dsf_canonify(clues->dsf, (y+1)*w+x-1)) draw_rect(dr, tx-GRIDEXTRA, ty+TILESIZE-1-2*GRIDEXTRA, GRIDEXTRA, GRIDEXTRA, COL_GRID); if (x+1 < w && y+1 < w && dsf_canonify(clues->dsf, y*w+x) != dsf_canonify(clues->dsf, (y+1)*w+x+1)) draw_rect(dr, tx+TILESIZE-1-2*GRIDEXTRA, ty+TILESIZE-1-2*GRIDEXTRA, GRIDEXTRA, GRIDEXTRA, COL_GRID); /* Draw the box clue. */ if (dsf_canonify(clues->dsf, y*w+x) == y*w+x) { long clue = clues->clues[y*w+x]; long cluetype = clue & CMASK, clueval = clue & ~CMASK; int size = dsf_size(clues->dsf, y*w+x); /* * Special case of clue-drawing: a box with only one square * is written as just the number, with no operation, because * it doesn't matter whether the operation is ADD or MUL. * The generation code above should never produce puzzles * containing such a thing - I think they're inelegant - but * it's possible to type in game IDs from elsewhere, so I * want to display them right if so. */ sprintf (str, "%ld%s", clueval, (size == 1 || only_one_op ? "" : cluetype == C_ADD ? "+" : cluetype == C_SUB ? ds->minus_sign : cluetype == C_MUL ? ds->times_sign : /* cluetype == C_DIV ? */ ds->divide_sign)); draw_text(dr, tx + GRIDEXTRA * 2, ty + GRIDEXTRA * 2 + TILESIZE/4, FONT_VARIABLE, TILESIZE/4, ALIGN_VNORMAL | ALIGN_HLEFT, (tile & DF_ERR_CLUE ? COL_ERROR : COL_GRID), str); } /* new number needs drawing? */ if (tile & DF_DIGIT_MASK) { str[1] = '\0'; str[0] = (tile & DF_DIGIT_MASK) + '0'; draw_text(dr, tx + TILESIZE/2, ty + TILESIZE/2, FONT_VARIABLE, TILESIZE/2, ALIGN_VCENTRE | ALIGN_HCENTRE, (tile & DF_ERR_LATIN) ? COL_ERROR : COL_USER, str); } else { int i, j, npencil; int pl, pr, pt, pb; float bestsize; int pw, ph, minph, pbest, fontsize; /* Count the pencil marks required. */ for (i = 1, npencil = 0; i <= w; i++) if (tile & (1L << (i + DF_PENCIL_SHIFT))) npencil++; if (npencil) { minph = 2; /* * Determine the bounding rectangle within which we're going * to put the pencil marks. */ /* Start with the whole square */ pl = tx + GRIDEXTRA; pr = pl + TILESIZE - GRIDEXTRA; pt = ty + GRIDEXTRA; pb = pt + TILESIZE - GRIDEXTRA; if (dsf_canonify(clues->dsf, y*w+x) == y*w+x) { /* * Make space for the clue text. */ pt += TILESIZE/4; /* minph--; */ } /* * We arrange our pencil marks in a grid layout, with * the number of rows and columns adjusted to allow the * maximum font size. * * So now we work out what the grid size ought to be. */ bestsize = 0.0; pbest = 0; /* Minimum */ for (pw = 3; pw < max(npencil,4); pw++) { float fw, fh, fs; ph = (npencil + pw - 1) / pw; ph = max(ph, minph); fw = (pr - pl) / (float)pw; fh = (pb - pt) / (float)ph; fs = min(fw, fh); if (fs > bestsize) { bestsize = fs; pbest = pw; } } assert(pbest > 0); pw = pbest; ph = (npencil + pw - 1) / pw; ph = max(ph, minph); /* * Now we've got our grid dimensions, work out the pixel * size of a grid element, and round it to the nearest * pixel. (We don't want rounding errors to make the * grid look uneven at low pixel sizes.) */ fontsize = min((pr - pl) / pw, (pb - pt) / ph); /* * Centre the resulting figure in the square. */ pl = tx + (TILESIZE - fontsize * pw) / 2; pt = ty + (TILESIZE - fontsize * ph) / 2; /* * And move it down a bit if it's collided with some * clue text. */ if (dsf_canonify(clues->dsf, y*w+x) == y*w+x) { pt = max(pt, ty + GRIDEXTRA * 3 + TILESIZE/4); } /* * Now actually draw the pencil marks. */ for (i = 1, j = 0; i <= w; i++) if (tile & (1L << (i + DF_PENCIL_SHIFT))) { int dx = j % pw, dy = j / pw; str[1] = '\0'; str[0] = i + '0'; draw_text(dr, pl + fontsize * (2*dx+1) / 2, pt + fontsize * (2*dy+1) / 2, FONT_VARIABLE, fontsize, ALIGN_VCENTRE | ALIGN_HCENTRE, COL_PENCIL, str); j++; } } } unclip(dr); draw_update(dr, cx, cy, cw, ch); } static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float animtime, float flashtime) { int w = state->par.w /*, a = w*w */; int x, y; if (!ds->started) { /* * The initial contents of the window are not guaranteed and * can vary with front ends. To be on the safe side, all * games should start by drawing a big background-colour * rectangle covering the whole window. */ draw_rect(dr, 0, 0, SIZE(w), SIZE(w), COL_BACKGROUND); /* * Big containing rectangle. */ draw_rect(dr, COORD(0) - GRIDEXTRA, COORD(0) - GRIDEXTRA, w*TILESIZE+1+GRIDEXTRA*2, w*TILESIZE+1+GRIDEXTRA*2, COL_GRID); draw_update(dr, 0, 0, SIZE(w), SIZE(w)); ds->started = TRUE; } check_errors(state, ds->errors); for (y = 0; y < w; y++) { for (x = 0; x < w; x++) { long tile = 0L; if (state->grid[y*w+x]) tile = state->grid[y*w+x]; else tile = (long)state->pencil[y*w+x] << DF_PENCIL_SHIFT; if (ui->hshow && ui->hx == x && ui->hy == y) tile |= (ui->hpencil ? DF_HIGHLIGHT_PENCIL : DF_HIGHLIGHT); if (flashtime > 0 && (flashtime <= FLASH_TIME/3 || flashtime >= FLASH_TIME*2/3)) tile |= DF_HIGHLIGHT; /* completion flash */ tile |= ds->errors[y*w+x]; if (ds->tiles[y*w+x] != tile) { ds->tiles[y*w+x] = tile; draw_tile(dr, ds, state->clues, x, y, tile, state->par.multiplication_only); } } } } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return 0.0F; } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { if (!oldstate->completed && newstate->completed && !oldstate->cheated && !newstate->cheated) return FLASH_TIME; return 0.0F; } static int game_status(const game_state *state) { return state->completed ? +1 : 0; } static int game_timing_state(const game_state *state, game_ui *ui) { if (state->completed) return FALSE; return TRUE; } static void game_print_size(const game_params *params, float *x, float *y) { int pw, ph; /* * We use 9mm squares by default, like Solo. */ game_compute_size(params, 900, &pw, &ph); *x = pw / 100.0F; *y = ph / 100.0F; } /* * Subfunction to draw the thick lines between cells. In order to do * this using the line-drawing rather than rectangle-drawing API (so * as to get line thicknesses to scale correctly) and yet have * correctly mitred joins between lines, we must do this by tracing * the boundary of each sub-block and drawing it in one go as a * single polygon. */ static void outline_block_structure(drawing *dr, game_drawstate *ds, int w, int *dsf, int ink) { int a = w*w; int *coords; int i, n; int x, y, dx, dy, sx, sy, sdx, sdy; coords = snewn(4*a, int); /* * Iterate over all the blocks. */ for (i = 0; i < a; i++) { if (dsf_canonify(dsf, i) != i) continue; /* * For each block, we need a starting square within it which * has a boundary at the left. Conveniently, we have one * right here, by construction. */ x = i % w; y = i / w; dx = -1; dy = 0; /* * Now begin tracing round the perimeter. At all * times, (x,y) describes some square within the * block, and (x+dx,y+dy) is some adjacent square * outside it; so the edge between those two squares * is always an edge of the block. */ sx = x, sy = y, sdx = dx, sdy = dy; /* save starting position */ n = 0; do { int cx, cy, tx, ty, nin; /* * Advance to the next edge, by looking at the two * squares beyond it. If they're both outside the block, * we turn right (by leaving x,y the same and rotating * dx,dy clockwise); if they're both inside, we turn * left (by rotating dx,dy anticlockwise and contriving * to leave x+dx,y+dy unchanged); if one of each, we go * straight on (and may enforce by assertion that * they're one of each the _right_ way round). */ nin = 0; tx = x - dy + dx; ty = y + dx + dy; nin += (tx >= 0 && tx < w && ty >= 0 && ty < w && dsf_canonify(dsf, ty*w+tx) == i); tx = x - dy; ty = y + dx; nin += (tx >= 0 && tx < w && ty >= 0 && ty < w && dsf_canonify(dsf, ty*w+tx) == i); if (nin == 0) { /* * Turn right. */ int tmp; tmp = dx; dx = -dy; dy = tmp; } else if (nin == 2) { /* * Turn left. */ int tmp; x += dx; y += dy; tmp = dx; dx = dy; dy = -tmp; x -= dx; y -= dy; } else { /* * Go straight on. */ x -= dy; y += dx; } /* * Now enforce by assertion that we ended up * somewhere sensible. */ assert(x >= 0 && x < w && y >= 0 && y < w && dsf_canonify(dsf, y*w+x) == i); assert(x+dx < 0 || x+dx >= w || y+dy < 0 || y+dy >= w || dsf_canonify(dsf, (y+dy)*w+(x+dx)) != i); /* * Record the point we just went past at one end of the * edge. To do this, we translate (x,y) down and right * by half a unit (so they're describing a point in the * _centre_ of the square) and then translate back again * in a manner rotated by dy and dx. */ assert(n < 2*w+2); cx = ((2*x+1) + dy + dx) / 2; cy = ((2*y+1) - dx + dy) / 2; coords[2*n+0] = BORDER + cx * TILESIZE; coords[2*n+1] = BORDER + cy * TILESIZE; n++; } while (x != sx || y != sy || dx != sdx || dy != sdy); /* * That's our polygon; now draw it. */ draw_polygon(dr, coords, n, -1, ink); } sfree(coords); } static void game_print(drawing *dr, const game_state *state, int tilesize) { int w = state->par.w; int ink = print_mono_colour(dr, 0); int x, y; char *minus_sign, *times_sign, *divide_sign; /* Ick: fake up `ds->tilesize' for macro expansion purposes */ game_drawstate ads, *ds = &ads; game_set_size(dr, ds, NULL, tilesize); minus_sign = text_fallback(dr, minus_signs, lenof(minus_signs)); times_sign = text_fallback(dr, times_signs, lenof(times_signs)); divide_sign = text_fallback(dr, divide_signs, lenof(divide_signs)); /* * Border. */ print_line_width(dr, 3 * TILESIZE / 40); draw_rect_outline(dr, BORDER, BORDER, w*TILESIZE, w*TILESIZE, ink); /* * Main grid. */ for (x = 1; x < w; x++) { print_line_width(dr, TILESIZE / 40); draw_line(dr, BORDER+x*TILESIZE, BORDER, BORDER+x*TILESIZE, BORDER+w*TILESIZE, ink); } for (y = 1; y < w; y++) { print_line_width(dr, TILESIZE / 40); draw_line(dr, BORDER, BORDER+y*TILESIZE, BORDER+w*TILESIZE, BORDER+y*TILESIZE, ink); } /* * Thick lines between cells. */ print_line_width(dr, 3 * TILESIZE / 40); outline_block_structure(dr, ds, w, state->clues->dsf, ink); /* * Clues. */ for (y = 0; y < w; y++) for (x = 0; x < w; x++) if (dsf_canonify(state->clues->dsf, y*w+x) == y*w+x) { long clue = state->clues->clues[y*w+x]; long cluetype = clue & CMASK, clueval = clue & ~CMASK; int size = dsf_size(state->clues->dsf, y*w+x); char str[64]; /* * As in the drawing code, we omit the operator for * blocks of area 1. */ sprintf (str, "%ld%s", clueval, (size == 1 ? "" : cluetype == C_ADD ? "+" : cluetype == C_SUB ? minus_sign : cluetype == C_MUL ? times_sign : /* cluetype == C_DIV ? */ divide_sign)); draw_text(dr, BORDER+x*TILESIZE + 5*TILESIZE/80, BORDER+y*TILESIZE + 20*TILESIZE/80, FONT_VARIABLE, TILESIZE/4, ALIGN_VNORMAL | ALIGN_HLEFT, ink, str); } /* * Numbers for the solution, if any. */ for (y = 0; y < w; y++) for (x = 0; x < w; x++) if (state->grid[y*w+x]) { char str[2]; str[1] = '\0'; str[0] = state->grid[y*w+x] + '0'; draw_text(dr, BORDER + x*TILESIZE + TILESIZE/2, BORDER + y*TILESIZE + TILESIZE/2, FONT_VARIABLE, TILESIZE/2, ALIGN_VCENTRE | ALIGN_HCENTRE, ink, str); } sfree(minus_sign); sfree(times_sign); sfree(divide_sign); } #ifdef COMBINED #define thegame keen #endif const struct game thegame = { "Keen", "games.keen", "keen", default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, TRUE, solve_game, FALSE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, PREFERRED_TILESIZE, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, TRUE, FALSE, game_print_size, game_print, FALSE, /* wants_statusbar */ FALSE, game_timing_state, REQUIRE_RBUTTON | REQUIRE_NUMPAD, /* flags */ }; #ifdef STANDALONE_SOLVER #include int main(int argc, char **argv) { game_params *p; game_state *s; char *id = NULL, *desc, *err; int grade = FALSE; int ret, diff, really_show_working = FALSE; while (--argc > 0) { char *p = *++argv; if (!strcmp(p, "-v")) { really_show_working = TRUE; } else if (!strcmp(p, "-g")) { grade = TRUE; } else if (*p == '-') { fprintf(stderr, "%s: unrecognised option `%s'\n", argv[0], p); return 1; } else { id = p; } } if (!id) { fprintf(stderr, "usage: %s [-g | -v] \n", argv[0]); return 1; } desc = strchr(id, ':'); if (!desc) { fprintf(stderr, "%s: game id expects a colon in it\n", argv[0]); return 1; } *desc++ = '\0'; p = default_params(); decode_params(p, id); err = validate_desc(p, desc); if (err) { fprintf(stderr, "%s: %s\n", argv[0], err); return 1; } s = new_game(NULL, p, desc); /* * When solving an Easy puzzle, we don't want to bother the * user with Hard-level deductions. For this reason, we grade * the puzzle internally before doing anything else. */ ret = -1; /* placate optimiser */ solver_show_working = FALSE; for (diff = 0; diff < DIFFCOUNT; diff++) { memset(s->grid, 0, p->w * p->w); ret = solver(p->w, s->clues->dsf, s->clues->clues, s->grid, diff); if (ret <= diff) break; } if (diff == DIFFCOUNT) { if (grade) printf("Difficulty rating: ambiguous\n"); else printf("Unable to find a unique solution\n"); } else { if (grade) { if (ret == diff_impossible) printf("Difficulty rating: impossible (no solution exists)\n"); else printf("Difficulty rating: %s\n", keen_diffnames[ret]); } else { solver_show_working = really_show_working; memset(s->grid, 0, p->w * p->w); ret = solver(p->w, s->clues->dsf, s->clues->clues, s->grid, diff); if (ret != diff) printf("Puzzle is inconsistent\n"); else { /* * We don't have a game_text_format for this game, * so we have to output the solution manually. */ int x, y; for (y = 0; y < p->w; y++) { for (x = 0; x < p->w; x++) { printf("%s%c", x>0?" ":"", '0' + s->grid[y*p->w+x]); } putchar('\n'); } } } } return 0; } #endif /* vim: set shiftwidth=4 tabstop=8: */ puzzles-20170606.272beef/inertia.c0000644000175000017500000016030113115373615015471 0ustar simonsimon/* * inertia.c: Game involving navigating round a grid picking up * gems. * * Game rules and basic generator design by Ben Olmstead. * This re-implementation was written by Simon Tatham. */ #include #include #include #include #include #include #include "puzzles.h" /* Used in the game_state */ #define BLANK 'b' #define GEM 'g' #define MINE 'm' #define STOP 's' #define WALL 'w' /* Used in the game IDs */ #define START 'S' /* Used in the game generation */ #define POSSGEM 'G' /* Used only in the game_drawstate*/ #define UNDRAWN '?' #define DIRECTIONS 8 #define DP1 (DIRECTIONS+1) #define DX(dir) ( (dir) & 3 ? (((dir) & 7) > 4 ? -1 : +1) : 0 ) #define DY(dir) ( DX((dir)+6) ) /* * Lvalue macro which expects x and y to be in range. */ #define LV_AT(w, h, grid, x, y) ( (grid)[(y)*(w)+(x)] ) /* * Rvalue macro which can cope with x and y being out of range. */ #define AT(w, h, grid, x, y) ( (x)<0 || (x)>=(w) || (y)<0 || (y)>=(h) ? \ WALL : LV_AT(w, h, grid, x, y) ) enum { COL_BACKGROUND, COL_OUTLINE, COL_HIGHLIGHT, COL_LOWLIGHT, COL_PLAYER, COL_DEAD_PLAYER, COL_MINE, COL_GEM, COL_WALL, COL_HINT, NCOLOURS }; struct game_params { int w, h; }; typedef struct soln { int refcount; int len; unsigned char *list; } soln; struct game_state { game_params p; int px, py; int gems; char *grid; int distance_moved; int dead; int cheated; int solnpos; soln *soln; }; static game_params *default_params(void) { game_params *ret = snew(game_params); ret->w = 10; #ifdef PORTRAIT_SCREEN ret->h = 10; #else ret->h = 8; #endif return ret; } static void free_params(game_params *params) { sfree(params); } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } static const struct game_params inertia_presets[] = { #ifdef PORTRAIT_SCREEN { 10, 10 }, { 12, 12 }, { 16, 16 }, #else { 10, 8 }, { 15, 12 }, { 20, 16 }, #endif }; static int game_fetch_preset(int i, char **name, game_params **params) { game_params p, *ret; char *retname; char namebuf[80]; if (i < 0 || i >= lenof(inertia_presets)) return FALSE; p = inertia_presets[i]; ret = dup_params(&p); sprintf(namebuf, "%dx%d", ret->w, ret->h); retname = dupstr(namebuf); *params = ret; *name = retname; return TRUE; } static void decode_params(game_params *params, char const *string) { params->w = params->h = atoi(string); while (*string && isdigit((unsigned char)*string)) string++; if (*string == 'x') { string++; params->h = atoi(string); } } static char *encode_params(const game_params *params, int full) { char data[256]; sprintf(data, "%dx%d", params->w, params->h); return dupstr(data); } static config_item *game_configure(const game_params *params) { config_item *ret; char buf[80]; ret = snewn(3, config_item); ret[0].name = "Width"; ret[0].type = C_STRING; sprintf(buf, "%d", params->w); ret[0].sval = dupstr(buf); ret[0].ival = 0; ret[1].name = "Height"; ret[1].type = C_STRING; sprintf(buf, "%d", params->h); ret[1].sval = dupstr(buf); ret[1].ival = 0; ret[2].name = NULL; ret[2].type = C_END; ret[2].sval = NULL; ret[2].ival = 0; return ret; } static game_params *custom_params(const config_item *cfg) { game_params *ret = snew(game_params); ret->w = atoi(cfg[0].sval); ret->h = atoi(cfg[1].sval); return ret; } static char *validate_params(const game_params *params, int full) { /* * Avoid completely degenerate cases which only have one * row/column. We probably could generate completable puzzles * of that shape, but they'd be forced to be extremely boring * and at large sizes would take a while to happen upon at * random as well. */ if (params->w < 2 || params->h < 2) return "Width and height must both be at least two"; /* * The grid construction algorithm creates 1/5 as many gems as * grid squares, and must create at least one gem to have an * actual puzzle. However, an area-five grid is ruled out by * the above constraint, so the practical minimum is six. */ if (params->w * params->h < 6) return "Grid area must be at least six squares"; return NULL; } /* ---------------------------------------------------------------------- * Solver used by grid generator. */ struct solver_scratch { unsigned char *reachable_from, *reachable_to; int *positions; }; static struct solver_scratch *new_scratch(int w, int h) { struct solver_scratch *sc = snew(struct solver_scratch); sc->reachable_from = snewn(w * h * DIRECTIONS, unsigned char); sc->reachable_to = snewn(w * h * DIRECTIONS, unsigned char); sc->positions = snewn(w * h * DIRECTIONS, int); return sc; } static void free_scratch(struct solver_scratch *sc) { sfree(sc->reachable_from); sfree(sc->reachable_to); sfree(sc->positions); sfree(sc); } static int can_go(int w, int h, char *grid, int x1, int y1, int dir1, int x2, int y2, int dir2) { /* * Returns TRUE if we can transition directly from (x1,y1) * going in direction dir1, to (x2,y2) going in direction dir2. */ /* * If we're actually in the middle of an unoccupyable square, * we cannot make any move. */ if (AT(w, h, grid, x1, y1) == WALL || AT(w, h, grid, x1, y1) == MINE) return FALSE; /* * If a move is capable of stopping at x1,y1,dir1, and x2,y2 is * the same coordinate as x1,y1, then we can make the * transition (by stopping and changing direction). * * For this to be the case, we have to either have a wall * beyond x1,y1,dir1, or have a stop on x1,y1. */ if (x2 == x1 && y2 == y1 && (AT(w, h, grid, x1, y1) == STOP || AT(w, h, grid, x1, y1) == START || AT(w, h, grid, x1+DX(dir1), y1+DY(dir1)) == WALL)) return TRUE; /* * If a move is capable of continuing here, then x1,y1,dir1 can * move one space further on. */ if (x2 == x1+DX(dir1) && y2 == y1+DY(dir1) && dir1 == dir2 && (AT(w, h, grid, x2, y2) == BLANK || AT(w, h, grid, x2, y2) == GEM || AT(w, h, grid, x2, y2) == STOP || AT(w, h, grid, x2, y2) == START)) return TRUE; /* * That's it. */ return FALSE; } static int find_gem_candidates(int w, int h, char *grid, struct solver_scratch *sc) { int wh = w*h; int head, tail; int sx, sy, gx, gy, gd, pass, possgems; /* * This function finds all the candidate gem squares, which are * precisely those squares which can be picked up on a loop * from the starting point back to the starting point. Doing * this may involve passing through such a square in the middle * of a move; so simple breadth-first search over the _squares_ * of the grid isn't quite adequate, because it might be that * we can only reach a gem from the start by moving over it in * one direction, but can only return to the start if we were * moving over it in another direction. * * Instead, we BFS over a space which mentions each grid square * eight times - once for each direction. We also BFS twice: * once to find out what square+direction pairs we can reach * _from_ the start point, and once to find out what pairs we * can reach the start point from. Then a square is reachable * if any of the eight directions for that square has both * flags set. */ memset(sc->reachable_from, 0, wh * DIRECTIONS); memset(sc->reachable_to, 0, wh * DIRECTIONS); /* * Find the starting square. */ sx = -1; /* placate optimiser */ for (sy = 0; sy < h; sy++) { for (sx = 0; sx < w; sx++) if (AT(w, h, grid, sx, sy) == START) break; if (sx < w) break; } assert(sy < h); for (pass = 0; pass < 2; pass++) { unsigned char *reachable = (pass == 0 ? sc->reachable_from : sc->reachable_to); int sign = (pass == 0 ? +1 : -1); int dir; #ifdef SOLVER_DIAGNOSTICS printf("starting pass %d\n", pass); #endif /* * `head' and `tail' are indices within sc->positions which * track the list of board positions left to process. */ head = tail = 0; for (dir = 0; dir < DIRECTIONS; dir++) { int index = (sy*w+sx)*DIRECTIONS+dir; sc->positions[tail++] = index; reachable[index] = TRUE; #ifdef SOLVER_DIAGNOSTICS printf("starting point %d,%d,%d\n", sx, sy, dir); #endif } /* * Now repeatedly pick an element off the list and process * it. */ while (head < tail) { int index = sc->positions[head++]; int dir = index % DIRECTIONS; int x = (index / DIRECTIONS) % w; int y = index / (w * DIRECTIONS); int n, x2, y2, d2, i2; #ifdef SOLVER_DIAGNOSTICS printf("processing point %d,%d,%d\n", x, y, dir); #endif /* * The places we attempt to switch to here are: * - each possible direction change (all the other * directions in this square) * - one step further in the direction we're going (or * one step back, if we're in the reachable_to pass). */ for (n = -1; n < DIRECTIONS; n++) { if (n < 0) { x2 = x + sign * DX(dir); y2 = y + sign * DY(dir); d2 = dir; } else { x2 = x; y2 = y; d2 = n; } i2 = (y2*w+x2)*DIRECTIONS+d2; if (x2 >= 0 && x2 < w && y2 >= 0 && y2 < h && !reachable[i2]) { int ok; #ifdef SOLVER_DIAGNOSTICS printf(" trying point %d,%d,%d", x2, y2, d2); #endif if (pass == 0) ok = can_go(w, h, grid, x, y, dir, x2, y2, d2); else ok = can_go(w, h, grid, x2, y2, d2, x, y, dir); #ifdef SOLVER_DIAGNOSTICS printf(" - %sok\n", ok ? "" : "not "); #endif if (ok) { sc->positions[tail++] = i2; reachable[i2] = TRUE; } } } } } /* * And that should be it. Now all we have to do is find the * squares for which there exists _some_ direction such that * the square plus that direction form a tuple which is both * reachable from the start and reachable to the start. */ possgems = 0; for (gy = 0; gy < h; gy++) for (gx = 0; gx < w; gx++) if (AT(w, h, grid, gx, gy) == BLANK) { for (gd = 0; gd < DIRECTIONS; gd++) { int index = (gy*w+gx)*DIRECTIONS+gd; if (sc->reachable_from[index] && sc->reachable_to[index]) { #ifdef SOLVER_DIAGNOSTICS printf("space at %d,%d is reachable via" " direction %d\n", gx, gy, gd); #endif LV_AT(w, h, grid, gx, gy) = POSSGEM; possgems++; break; } } } return possgems; } /* ---------------------------------------------------------------------- * Grid generation code. */ static char *gengrid(int w, int h, random_state *rs) { int wh = w*h; char *grid = snewn(wh+1, char); struct solver_scratch *sc = new_scratch(w, h); int maxdist_threshold, tries; maxdist_threshold = 2; tries = 0; while (1) { int i, j; int possgems; int *dist, *list, head, tail, maxdist; /* * We're going to fill the grid with the five basic piece * types in about 1/5 proportion. For the moment, though, * we leave out the gems, because we'll put those in * _after_ we run the solver to tell us where the viable * locations are. */ i = 0; for (j = 0; j < wh/5; j++) grid[i++] = WALL; for (j = 0; j < wh/5; j++) grid[i++] = STOP; for (j = 0; j < wh/5; j++) grid[i++] = MINE; assert(i < wh); grid[i++] = START; while (i < wh) grid[i++] = BLANK; shuffle(grid, wh, sizeof(*grid), rs); /* * Find the viable gem locations, and immediately give up * and try again if there aren't enough of them. */ possgems = find_gem_candidates(w, h, grid, sc); if (possgems < wh/5) continue; /* * We _could_ now select wh/5 of the POSSGEMs and set them * to GEM, and have a viable level. However, there's a * chance that a large chunk of the level will turn out to * be unreachable, so first we test for that. * * We do this by finding the largest distance from any * square to the nearest POSSGEM, by breadth-first search. * If this is above a critical threshold, we abort and try * again. * * (This search is purely geometric, without regard to * walls and long ways round.) */ dist = sc->positions; list = sc->positions + wh; for (i = 0; i < wh; i++) dist[i] = -1; head = tail = 0; for (i = 0; i < wh; i++) if (grid[i] == POSSGEM) { dist[i] = 0; list[tail++] = i; } maxdist = 0; while (head < tail) { int pos, x, y, d; pos = list[head++]; if (maxdist < dist[pos]) maxdist = dist[pos]; x = pos % w; y = pos / w; for (d = 0; d < DIRECTIONS; d++) { int x2, y2, p2; x2 = x + DX(d); y2 = y + DY(d); if (x2 >= 0 && x2 < w && y2 >= 0 && y2 < h) { p2 = y2*w+x2; if (dist[p2] < 0) { dist[p2] = dist[pos] + 1; list[tail++] = p2; } } } } assert(head == wh && tail == wh); /* * Now abandon this grid and go round again if maxdist is * above the required threshold. * * We can safely start the threshold as low as 2. As we * accumulate failed generation attempts, we gradually * raise it as we get more desperate. */ if (maxdist > maxdist_threshold) { tries++; if (tries == 50) { maxdist_threshold++; tries = 0; } continue; } /* * Now our reachable squares are plausibly evenly * distributed over the grid. I'm not actually going to * _enforce_ that I place the gems in such a way as not to * increase that maxdist value; I'm now just going to trust * to the RNG to pick a sensible subset of the POSSGEMs. */ j = 0; for (i = 0; i < wh; i++) if (grid[i] == POSSGEM) list[j++] = i; shuffle(list, j, sizeof(*list), rs); for (i = 0; i < j; i++) grid[list[i]] = (i < wh/5 ? GEM : BLANK); break; } free_scratch(sc); grid[wh] = '\0'; return grid; } static char *new_game_desc(const game_params *params, random_state *rs, char **aux, int interactive) { return gengrid(params->w, params->h, rs); } static char *validate_desc(const game_params *params, const char *desc) { int w = params->w, h = params->h, wh = w*h; int starts = 0, gems = 0, i; for (i = 0; i < wh; i++) { if (!desc[i]) return "Not enough data to fill grid"; if (desc[i] != WALL && desc[i] != START && desc[i] != STOP && desc[i] != GEM && desc[i] != MINE && desc[i] != BLANK) return "Unrecognised character in game description"; if (desc[i] == START) starts++; if (desc[i] == GEM) gems++; } if (desc[i]) return "Too much data to fill grid"; if (starts < 1) return "No starting square specified"; if (starts > 1) return "More than one starting square specified"; if (gems < 1) return "No gems specified"; return NULL; } static game_state *new_game(midend *me, const game_params *params, const char *desc) { int w = params->w, h = params->h, wh = w*h; int i; game_state *state = snew(game_state); state->p = *params; /* structure copy */ state->grid = snewn(wh, char); assert(strlen(desc) == wh); memcpy(state->grid, desc, wh); state->px = state->py = -1; state->gems = 0; for (i = 0; i < wh; i++) { if (state->grid[i] == START) { state->grid[i] = STOP; state->px = i % w; state->py = i / w; } else if (state->grid[i] == GEM) { state->gems++; } } assert(state->gems > 0); assert(state->px >= 0 && state->py >= 0); state->distance_moved = 0; state->dead = FALSE; state->cheated = FALSE; state->solnpos = 0; state->soln = NULL; return state; } static game_state *dup_game(const game_state *state) { int w = state->p.w, h = state->p.h, wh = w*h; game_state *ret = snew(game_state); ret->p = state->p; ret->px = state->px; ret->py = state->py; ret->gems = state->gems; ret->grid = snewn(wh, char); ret->distance_moved = state->distance_moved; ret->dead = FALSE; memcpy(ret->grid, state->grid, wh); ret->cheated = state->cheated; ret->soln = state->soln; if (ret->soln) ret->soln->refcount++; ret->solnpos = state->solnpos; return ret; } static void free_game(game_state *state) { if (state->soln && --state->soln->refcount == 0) { sfree(state->soln->list); sfree(state->soln); } sfree(state->grid); sfree(state); } /* * Internal function used by solver. */ static int move_goes_to(int w, int h, char *grid, int x, int y, int d) { int dr; /* * See where we'd get to if we made this move. */ dr = -1; /* placate optimiser */ while (1) { if (AT(w, h, grid, x+DX(d), y+DY(d)) == WALL) { dr = DIRECTIONS; /* hit a wall, so end up stationary */ break; } x += DX(d); y += DY(d); if (AT(w, h, grid, x, y) == STOP) { dr = DIRECTIONS; /* hit a stop, so end up stationary */ break; } if (AT(w, h, grid, x, y) == GEM) { dr = d; /* hit a gem, so we're still moving */ break; } if (AT(w, h, grid, x, y) == MINE) return -1; /* hit a mine, so move is invalid */ } assert(dr >= 0); return (y*w+x)*DP1+dr; } static int compare_integers(const void *av, const void *bv) { const int *a = (const int *)av; const int *b = (const int *)bv; if (*a < *b) return -1; else if (*a > *b) return +1; else return 0; } static char *solve_game(const game_state *state, const game_state *currstate, const char *aux, char **error) { int w = currstate->p.w, h = currstate->p.h, wh = w*h; int *nodes, *nodeindex, *edges, *backedges, *edgei, *backedgei, *circuit; int nedges; int *dist, *dist2, *list; int *unvisited; int circuitlen, circuitsize; int head, tail, pass, i, j, n, x, y, d, dd; char *err, *soln, *p; /* * Before anything else, deal with the special case in which * all the gems are already collected. */ for (i = 0; i < wh; i++) if (currstate->grid[i] == GEM) break; if (i == wh) { *error = "Game is already solved"; return NULL; } /* * Solving Inertia is a question of first building up the graph * of where you can get to from where, and secondly finding a * tour of the graph which takes in every gem. * * This is of course a close cousin of the travelling salesman * problem, which is NP-complete; so I rather doubt that any * _optimal_ tour can be found in plausible time. Hence I'll * restrict myself to merely finding a not-too-bad one. * * First construct the graph, by bfsing out move by move from * the current player position. Graph vertices will be * - every endpoint of a move (place the ball can be * stationary) * - every gem (place the ball can go through in motion). * Vertices of this type have an associated direction, since * if a gem can be collected by sliding through it in two * different directions it doesn't follow that you can * change direction at it. * * I'm going to refer to a non-directional vertex as * (y*w+x)*DP1+DIRECTIONS, and a directional one as * (y*w+x)*DP1+d. */ /* * nodeindex[] maps node codes as shown above to numeric * indices in the nodes[] array. */ nodeindex = snewn(DP1*wh, int); for (i = 0; i < DP1*wh; i++) nodeindex[i] = -1; /* * Do the bfs to find all the interesting graph nodes. */ nodes = snewn(DP1*wh, int); head = tail = 0; nodes[tail] = (currstate->py * w + currstate->px) * DP1 + DIRECTIONS; nodeindex[nodes[0]] = tail; tail++; while (head < tail) { int nc = nodes[head++], nnc; d = nc % DP1; /* * Plot all possible moves from this node. If the node is * directed, there's only one. */ for (dd = 0; dd < DIRECTIONS; dd++) { x = nc / DP1; y = x / w; x %= w; if (d < DIRECTIONS && d != dd) continue; nnc = move_goes_to(w, h, currstate->grid, x, y, dd); if (nnc >= 0 && nnc != nc) { if (nodeindex[nnc] < 0) { nodes[tail] = nnc; nodeindex[nnc] = tail; tail++; } } } } n = head; /* * Now we know how many nodes we have, allocate the edge array * and go through setting up the edges. */ edges = snewn(DIRECTIONS*n, int); edgei = snewn(n+1, int); nedges = 0; for (i = 0; i < n; i++) { int nc = nodes[i]; edgei[i] = nedges; d = nc % DP1; x = nc / DP1; y = x / w; x %= w; for (dd = 0; dd < DIRECTIONS; dd++) { int nnc; if (d >= DIRECTIONS || d == dd) { nnc = move_goes_to(w, h, currstate->grid, x, y, dd); if (nnc >= 0 && nnc != nc) edges[nedges++] = nodeindex[nnc]; } } } edgei[n] = nedges; /* * Now set up the backedges array. */ backedges = snewn(nedges, int); backedgei = snewn(n+1, int); for (i = j = 0; i < nedges; i++) { while (j+1 < n && i >= edgei[j+1]) j++; backedges[i] = edges[i] * n + j; } qsort(backedges, nedges, sizeof(int), compare_integers); backedgei[0] = 0; for (i = j = 0; i < nedges; i++) { int k = backedges[i] / n; backedges[i] %= n; while (j < k) backedgei[++j] = i; } backedgei[n] = nedges; /* * Set up the initial tour. At all times, our tour is a circuit * of graph vertices (which may, and probably will often, * repeat vertices). To begin with, it's got exactly one vertex * in it, which is the player's current starting point. */ circuitsize = 256; circuit = snewn(circuitsize, int); circuitlen = 0; circuit[circuitlen++] = 0; /* node index 0 is the starting posn */ /* * Track which gems are as yet unvisited. */ unvisited = snewn(wh, int); for (i = 0; i < wh; i++) unvisited[i] = FALSE; for (i = 0; i < wh; i++) if (currstate->grid[i] == GEM) unvisited[i] = TRUE; /* * Allocate space for doing bfses inside the main loop. */ dist = snewn(n, int); dist2 = snewn(n, int); list = snewn(n, int); err = NULL; soln = NULL; /* * Now enter the main loop, in each iteration of which we * extend the tour to take in an as yet uncollected gem. */ while (1) { int target, n1, n2, bestdist, extralen, targetpos; #ifdef TSP_DIAGNOSTICS printf("circuit is"); for (i = 0; i < circuitlen; i++) { int nc = nodes[circuit[i]]; printf(" (%d,%d,%d)", nc/DP1%w, nc/(DP1*w), nc%DP1); } printf("\n"); printf("moves are "); x = nodes[circuit[0]] / DP1 % w; y = nodes[circuit[0]] / DP1 / w; for (i = 1; i < circuitlen; i++) { int x2, y2, dx, dy; if (nodes[circuit[i]] % DP1 != DIRECTIONS) continue; x2 = nodes[circuit[i]] / DP1 % w; y2 = nodes[circuit[i]] / DP1 / w; dx = (x2 > x ? +1 : x2 < x ? -1 : 0); dy = (y2 > y ? +1 : y2 < y ? -1 : 0); for (d = 0; d < DIRECTIONS; d++) if (DX(d) == dx && DY(d) == dy) printf("%c", "89632147"[d]); x = x2; y = y2; } printf("\n"); #endif /* * First, start a pair of bfses at _every_ vertex currently * in the tour, and extend them outwards to find the * nearest as yet unreached gem vertex. * * This is largely a heuristic: we could pick _any_ doubly * reachable node here and still get a valid tour as * output. I hope that picking a nearby one will result in * generally good tours. */ for (pass = 0; pass < 2; pass++) { int *ep = (pass == 0 ? edges : backedges); int *ei = (pass == 0 ? edgei : backedgei); int *dp = (pass == 0 ? dist : dist2); head = tail = 0; for (i = 0; i < n; i++) dp[i] = -1; for (i = 0; i < circuitlen; i++) { int ni = circuit[i]; if (dp[ni] < 0) { dp[ni] = 0; list[tail++] = ni; } } while (head < tail) { int ni = list[head++]; for (i = ei[ni]; i < ei[ni+1]; i++) { int ti = ep[i]; if (ti >= 0 && dp[ti] < 0) { dp[ti] = dp[ni] + 1; list[tail++] = ti; } } } } /* Now find the nearest unvisited gem. */ bestdist = -1; target = -1; for (i = 0; i < n; i++) { if (unvisited[nodes[i] / DP1] && dist[i] >= 0 && dist2[i] >= 0) { int thisdist = dist[i] + dist2[i]; if (bestdist < 0 || bestdist > thisdist) { bestdist = thisdist; target = i; } } } if (target < 0) { /* * If we get to here, we haven't found a gem we can get * at all, which means we terminate this loop. */ break; } /* * Now we have a graph vertex at list[tail-1] which is an * unvisited gem. We want to add that vertex to our tour. * So we run two more breadth-first searches: one starting * from that vertex and following forward edges, and * another starting from the same vertex and following * backward edges. This allows us to determine, for each * node on the current tour, how quickly we can get both to * and from the target vertex from that node. */ #ifdef TSP_DIAGNOSTICS printf("target node is %d (%d,%d,%d)\n", target, nodes[target]/DP1%w, nodes[target]/DP1/w, nodes[target]%DP1); #endif for (pass = 0; pass < 2; pass++) { int *ep = (pass == 0 ? edges : backedges); int *ei = (pass == 0 ? edgei : backedgei); int *dp = (pass == 0 ? dist : dist2); for (i = 0; i < n; i++) dp[i] = -1; head = tail = 0; dp[target] = 0; list[tail++] = target; while (head < tail) { int ni = list[head++]; for (i = ei[ni]; i < ei[ni+1]; i++) { int ti = ep[i]; if (ti >= 0 && dp[ti] < 0) { dp[ti] = dp[ni] + 1; /*printf("pass %d: set dist of vertex %d to %d (via %d)\n", pass, ti, dp[ti], ni);*/ list[tail++] = ti; } } } } /* * Now for every node n, dist[n] gives the length of the * shortest path from the target vertex to n, and dist2[n] * gives the length of the shortest path from n to the * target vertex. * * Our next step is to search linearly along the tour to * find the optimum place to insert a trip to the target * vertex and back. Our two options are either * (a) to find two adjacent vertices A,B in the tour and * replace the edge A->B with the path A->target->B * (b) to find a single vertex X in the tour and replace * it with the complete round trip X->target->X. * We do whichever takes the fewest moves. */ n1 = n2 = -1; bestdist = -1; for (i = 0; i < circuitlen; i++) { int thisdist; /* * Try a round trip from vertex i. */ if (dist[circuit[i]] >= 0 && dist2[circuit[i]] >= 0) { thisdist = dist[circuit[i]] + dist2[circuit[i]]; if (bestdist < 0 || thisdist < bestdist) { bestdist = thisdist; n1 = n2 = i; } } /* * Try a trip from vertex i via target to vertex i+1. */ if (i+1 < circuitlen && dist2[circuit[i]] >= 0 && dist[circuit[i+1]] >= 0) { thisdist = dist2[circuit[i]] + dist[circuit[i+1]]; if (bestdist < 0 || thisdist < bestdist) { bestdist = thisdist; n1 = i; n2 = i+1; } } } if (bestdist < 0) { /* * We couldn't find a round trip taking in this gem _at * all_. Give up. */ err = "Unable to find a solution from this starting point"; break; } #ifdef TSP_DIAGNOSTICS printf("insertion point: n1=%d, n2=%d, dist=%d\n", n1, n2, bestdist); #endif #ifdef TSP_DIAGNOSTICS printf("circuit before lengthening is"); for (i = 0; i < circuitlen; i++) { printf(" %d", circuit[i]); } printf("\n"); #endif /* * Now actually lengthen the tour to take in this round * trip. */ extralen = dist2[circuit[n1]] + dist[circuit[n2]]; if (n1 != n2) extralen--; circuitlen += extralen; if (circuitlen >= circuitsize) { circuitsize = circuitlen + 256; circuit = sresize(circuit, circuitsize, int); } memmove(circuit + n2 + extralen, circuit + n2, (circuitlen - n2 - extralen) * sizeof(int)); n2 += extralen; #ifdef TSP_DIAGNOSTICS printf("circuit in middle of lengthening is"); for (i = 0; i < circuitlen; i++) { printf(" %d", circuit[i]); } printf("\n"); #endif /* * Find the shortest-path routes to and from the target, * and write them into the circuit. */ targetpos = n1 + dist2[circuit[n1]]; assert(targetpos - dist2[circuit[n1]] == n1); assert(targetpos + dist[circuit[n2]] == n2); for (pass = 0; pass < 2; pass++) { int dir = (pass == 0 ? -1 : +1); int *ep = (pass == 0 ? backedges : edges); int *ei = (pass == 0 ? backedgei : edgei); int *dp = (pass == 0 ? dist : dist2); int nn = (pass == 0 ? n2 : n1); int ni = circuit[nn], ti, dest = nn; while (1) { circuit[dest] = ni; if (dp[ni] == 0) break; dest += dir; ti = -1; /*printf("pass %d: looking at vertex %d\n", pass, ni);*/ for (i = ei[ni]; i < ei[ni+1]; i++) { ti = ep[i]; if (ti >= 0 && dp[ti] == dp[ni] - 1) break; } assert(i < ei[ni+1] && ti >= 0); ni = ti; } } #ifdef TSP_DIAGNOSTICS printf("circuit after lengthening is"); for (i = 0; i < circuitlen; i++) { printf(" %d", circuit[i]); } printf("\n"); #endif /* * Finally, mark all gems that the new piece of circuit * passes through as visited. */ for (i = n1; i <= n2; i++) { int pos = nodes[circuit[i]] / DP1; assert(pos >= 0 && pos < wh); unvisited[pos] = FALSE; } } #ifdef TSP_DIAGNOSTICS printf("before reduction, moves are "); x = nodes[circuit[0]] / DP1 % w; y = nodes[circuit[0]] / DP1 / w; for (i = 1; i < circuitlen; i++) { int x2, y2, dx, dy; if (nodes[circuit[i]] % DP1 != DIRECTIONS) continue; x2 = nodes[circuit[i]] / DP1 % w; y2 = nodes[circuit[i]] / DP1 / w; dx = (x2 > x ? +1 : x2 < x ? -1 : 0); dy = (y2 > y ? +1 : y2 < y ? -1 : 0); for (d = 0; d < DIRECTIONS; d++) if (DX(d) == dx && DY(d) == dy) printf("%c", "89632147"[d]); x = x2; y = y2; } printf("\n"); #endif /* * That's got a basic solution. Now optimise it by removing * redundant sections of the circuit: it's entirely possible * that a piece of circuit we carefully inserted at one stage * to collect a gem has become pointless because the steps * required to collect some _later_ gem necessarily passed * through the same one. * * So first we go through and work out how many times each gem * is collected. Then we look for maximal sections of circuit * which are redundant in the sense that their removal would * not reduce any gem's collection count to zero, and replace * each one with a bfs-derived fastest path between their * endpoints. */ while (1) { int oldlen = circuitlen; int dir; for (dir = +1; dir >= -1; dir -= 2) { for (i = 0; i < wh; i++) unvisited[i] = 0; for (i = 0; i < circuitlen; i++) { int xy = nodes[circuit[i]] / DP1; if (currstate->grid[xy] == GEM) unvisited[xy]++; } /* * If there's any gem we didn't end up visiting at all, * give up. */ for (i = 0; i < wh; i++) { if (currstate->grid[i] == GEM && unvisited[i] == 0) { err = "Unable to find a solution from this starting point"; break; } } if (i < wh) break; for (i = j = (dir > 0 ? 0 : circuitlen-1); i < circuitlen && i >= 0; i += dir) { int xy = nodes[circuit[i]] / DP1; if (currstate->grid[xy] == GEM && unvisited[xy] > 1) { unvisited[xy]--; } else if (currstate->grid[xy] == GEM || i == circuitlen-1) { /* * circuit[i] collects a gem for the only time, * or is the last node in the circuit. * Therefore it cannot be removed; so we now * want to replace the path from circuit[j] to * circuit[i] with a bfs-shortest path. */ int p, q, k, dest, ni, ti, thisdist; /* * Set up the upper and lower bounds of the * reduced section. */ p = min(i, j); q = max(i, j); #ifdef TSP_DIAGNOSTICS printf("optimising section from %d - %d\n", p, q); #endif for (k = 0; k < n; k++) dist[k] = -1; head = tail = 0; dist[circuit[p]] = 0; list[tail++] = circuit[p]; while (head < tail && dist[circuit[q]] < 0) { int ni = list[head++]; for (k = edgei[ni]; k < edgei[ni+1]; k++) { int ti = edges[k]; if (ti >= 0 && dist[ti] < 0) { dist[ti] = dist[ni] + 1; list[tail++] = ti; } } } thisdist = dist[circuit[q]]; assert(thisdist >= 0 && thisdist <= q-p); memmove(circuit+p+thisdist, circuit+q, (circuitlen - q) * sizeof(int)); circuitlen -= q-p; q = p + thisdist; circuitlen += q-p; if (dir > 0) i = q; /* resume loop from the right place */ #ifdef TSP_DIAGNOSTICS printf("new section runs from %d - %d\n", p, q); #endif dest = q; assert(dest >= 0); ni = circuit[q]; while (1) { /* printf("dest=%d circuitlen=%d ni=%d dist[ni]=%d\n", dest, circuitlen, ni, dist[ni]); */ circuit[dest] = ni; if (dist[ni] == 0) break; dest--; ti = -1; for (k = backedgei[ni]; k < backedgei[ni+1]; k++) { ti = backedges[k]; if (ti >= 0 && dist[ti] == dist[ni] - 1) break; } assert(k < backedgei[ni+1] && ti >= 0); ni = ti; } /* * Now re-increment the visit counts for the * new path. */ while (++p < q) { int xy = nodes[circuit[p]] / DP1; if (currstate->grid[xy] == GEM) unvisited[xy]++; } j = i; #ifdef TSP_DIAGNOSTICS printf("during reduction, circuit is"); for (k = 0; k < circuitlen; k++) { int nc = nodes[circuit[k]]; printf(" (%d,%d,%d)", nc/DP1%w, nc/(DP1*w), nc%DP1); } printf("\n"); printf("moves are "); x = nodes[circuit[0]] / DP1 % w; y = nodes[circuit[0]] / DP1 / w; for (k = 1; k < circuitlen; k++) { int x2, y2, dx, dy; if (nodes[circuit[k]] % DP1 != DIRECTIONS) continue; x2 = nodes[circuit[k]] / DP1 % w; y2 = nodes[circuit[k]] / DP1 / w; dx = (x2 > x ? +1 : x2 < x ? -1 : 0); dy = (y2 > y ? +1 : y2 < y ? -1 : 0); for (d = 0; d < DIRECTIONS; d++) if (DX(d) == dx && DY(d) == dy) printf("%c", "89632147"[d]); x = x2; y = y2; } printf("\n"); #endif } } #ifdef TSP_DIAGNOSTICS printf("after reduction, moves are "); x = nodes[circuit[0]] / DP1 % w; y = nodes[circuit[0]] / DP1 / w; for (i = 1; i < circuitlen; i++) { int x2, y2, dx, dy; if (nodes[circuit[i]] % DP1 != DIRECTIONS) continue; x2 = nodes[circuit[i]] / DP1 % w; y2 = nodes[circuit[i]] / DP1 / w; dx = (x2 > x ? +1 : x2 < x ? -1 : 0); dy = (y2 > y ? +1 : y2 < y ? -1 : 0); for (d = 0; d < DIRECTIONS; d++) if (DX(d) == dx && DY(d) == dy) printf("%c", "89632147"[d]); x = x2; y = y2; } printf("\n"); #endif } /* * If we've managed an entire reduction pass in each * direction and not made the solution any shorter, we're * _really_ done. */ if (circuitlen == oldlen) break; } /* * Encode the solution as a move string. */ if (!err) { soln = snewn(circuitlen+2, char); p = soln; *p++ = 'S'; x = nodes[circuit[0]] / DP1 % w; y = nodes[circuit[0]] / DP1 / w; for (i = 1; i < circuitlen; i++) { int x2, y2, dx, dy; if (nodes[circuit[i]] % DP1 != DIRECTIONS) continue; x2 = nodes[circuit[i]] / DP1 % w; y2 = nodes[circuit[i]] / DP1 / w; dx = (x2 > x ? +1 : x2 < x ? -1 : 0); dy = (y2 > y ? +1 : y2 < y ? -1 : 0); for (d = 0; d < DIRECTIONS; d++) if (DX(d) == dx && DY(d) == dy) { *p++ = '0' + d; break; } assert(d < DIRECTIONS); x = x2; y = y2; } *p++ = '\0'; assert(p - soln < circuitlen+2); } sfree(list); sfree(dist); sfree(dist2); sfree(unvisited); sfree(circuit); sfree(backedgei); sfree(backedges); sfree(edgei); sfree(edges); sfree(nodeindex); sfree(nodes); if (err) *error = err; return soln; } static int game_can_format_as_text_now(const game_params *params) { return TRUE; } static char *game_text_format(const game_state *state) { int w = state->p.w, h = state->p.h, r, c; int cw = 4, ch = 2, gw = cw*w + 2, gh = ch * h + 1, len = gw * gh; char *board = snewn(len + 1, char); sprintf(board, "%*s+\n", len - 2, ""); for (r = 0; r < h; ++r) { for (c = 0; c < w; ++c) { int cell = r*ch*gw + cw*c, center = cell + gw*ch/2 + cw/2; int i = r*w + c; switch (state->grid[i]) { case BLANK: break; case GEM: board[center] = 'o'; break; case MINE: board[center] = 'M'; break; case STOP: board[center-1] = '('; board[center+1] = ')'; break; case WALL: memset(board + center - 1, 'X', 3); } if (r == state->py && c == state->px) { if (!state->dead) board[center] = '@'; else memcpy(board + center - 1, ":-(", 3); } board[cell] = '+'; memset(board + cell + 1, '-', cw - 1); for (i = 1; i < ch; ++i) board[cell + i*gw] = '|'; } for (c = 0; c < ch; ++c) { board[(r*ch+c)*gw + gw - 2] = "|+"[!c]; board[(r*ch+c)*gw + gw - 1] = '\n'; } } memset(board + len - gw, '-', gw - 2); for (c = 0; c < w; ++c) board[len - gw + cw*c] = '+'; return board; } struct game_ui { float anim_length; int flashtype; int deaths; int just_made_move; int just_died; }; static game_ui *new_ui(const game_state *state) { game_ui *ui = snew(game_ui); ui->anim_length = 0.0F; ui->flashtype = 0; ui->deaths = 0; ui->just_made_move = FALSE; ui->just_died = FALSE; return ui; } static void free_ui(game_ui *ui) { sfree(ui); } static char *encode_ui(const game_ui *ui) { char buf[80]; /* * The deaths counter needs preserving across a serialisation. */ sprintf(buf, "D%d", ui->deaths); return dupstr(buf); } static void decode_ui(game_ui *ui, const char *encoding) { int p = 0; sscanf(encoding, "D%d%n", &ui->deaths, &p); } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { /* * Increment the deaths counter. We only do this if * ui->just_made_move is set (redoing a suicide move doesn't * kill you _again_), and also we only do it if the game wasn't * already completed (once you're finished, you can play). */ if (!oldstate->dead && newstate->dead && ui->just_made_move && oldstate->gems) { ui->deaths++; ui->just_died = TRUE; } else { ui->just_died = FALSE; } ui->just_made_move = FALSE; } struct game_drawstate { game_params p; int tilesize; int started; unsigned short *grid; blitter *player_background; int player_bg_saved, pbgx, pbgy; }; #define PREFERRED_TILESIZE 32 #define TILESIZE (ds->tilesize) #ifdef SMALL_SCREEN #define BORDER (TILESIZE / 4) #else #define BORDER (TILESIZE) #endif #define HIGHLIGHT_WIDTH (TILESIZE / 10) #define COORD(x) ( (x) * TILESIZE + BORDER ) #define FROMCOORD(x) ( ((x) - BORDER + TILESIZE) / TILESIZE - 1 ) static char *interpret_move(const game_state *state, game_ui *ui, const game_drawstate *ds, int x, int y, int button) { int w = state->p.w, h = state->p.h /*, wh = w*h */; int dir; char buf[80]; dir = -1; if (button == LEFT_BUTTON) { /* * Mouse-clicking near the target point (or, more * accurately, in the appropriate octant) is an alternative * way to input moves. */ if (FROMCOORD(x) != state->px || FROMCOORD(y) != state->py) { int dx, dy; float angle; dx = FROMCOORD(x) - state->px; dy = FROMCOORD(y) - state->py; /* I pass dx,dy rather than dy,dx so that the octants * end up the right way round. */ angle = atan2(dx, -dy); angle = (angle + (PI/8)) / (PI/4); assert(angle > -16.0F); dir = (int)(angle + 16.0F) & 7; } } else if (button == CURSOR_UP || button == (MOD_NUM_KEYPAD | '8')) dir = 0; else if (button == CURSOR_DOWN || button == (MOD_NUM_KEYPAD | '2')) dir = 4; else if (button == CURSOR_LEFT || button == (MOD_NUM_KEYPAD | '4')) dir = 6; else if (button == CURSOR_RIGHT || button == (MOD_NUM_KEYPAD | '6')) dir = 2; else if (button == (MOD_NUM_KEYPAD | '7')) dir = 7; else if (button == (MOD_NUM_KEYPAD | '1')) dir = 5; else if (button == (MOD_NUM_KEYPAD | '9')) dir = 1; else if (button == (MOD_NUM_KEYPAD | '3')) dir = 3; else if (IS_CURSOR_SELECT(button) && state->soln && state->solnpos < state->soln->len) dir = state->soln->list[state->solnpos]; if (dir < 0) return NULL; /* * Reject the move if we can't make it at all due to a wall * being in the way. */ if (AT(w, h, state->grid, state->px+DX(dir), state->py+DY(dir)) == WALL) return NULL; /* * Reject the move if we're dead! */ if (state->dead) return NULL; /* * Otherwise, we can make the move. All we need to specify is * the direction. */ ui->just_made_move = TRUE; sprintf(buf, "%d", dir); return dupstr(buf); } static void install_new_solution(game_state *ret, const char *move) { int i; soln *sol; assert (*move == 'S'); ++move; sol = snew(soln); sol->len = strlen(move); sol->list = snewn(sol->len, unsigned char); for (i = 0; i < sol->len; ++i) sol->list[i] = move[i] - '0'; if (ret->soln && --ret->soln->refcount == 0) { sfree(ret->soln->list); sfree(ret->soln); } ret->soln = sol; sol->refcount = 1; ret->cheated = TRUE; ret->solnpos = 0; } static void discard_solution(game_state *ret) { --ret->soln->refcount; assert(ret->soln->refcount > 0); /* ret has a soln-pointing dup */ ret->soln = NULL; ret->solnpos = 0; } static game_state *execute_move(const game_state *state, const char *move) { int w = state->p.w, h = state->p.h /*, wh = w*h */; int dir; game_state *ret; if (*move == 'S') { /* * This is a solve move, so we don't actually _change_ the * grid but merely set up a stored solution path. */ ret = dup_game(state); install_new_solution(ret, move); return ret; } dir = atoi(move); if (dir < 0 || dir >= DIRECTIONS) return NULL; /* huh? */ if (state->dead) return NULL; if (AT(w, h, state->grid, state->px+DX(dir), state->py+DY(dir)) == WALL) return NULL; /* wall in the way! */ /* * Now make the move. */ ret = dup_game(state); ret->distance_moved = 0; while (1) { ret->px += DX(dir); ret->py += DY(dir); ret->distance_moved++; if (AT(w, h, ret->grid, ret->px, ret->py) == GEM) { LV_AT(w, h, ret->grid, ret->px, ret->py) = BLANK; ret->gems--; } if (AT(w, h, ret->grid, ret->px, ret->py) == MINE) { ret->dead = TRUE; break; } if (AT(w, h, ret->grid, ret->px, ret->py) == STOP || AT(w, h, ret->grid, ret->px+DX(dir), ret->py+DY(dir)) == WALL) break; } if (ret->soln) { if (ret->dead || ret->gems == 0) discard_solution(ret); else if (ret->soln->list[ret->solnpos] == dir) { ++ret->solnpos; assert(ret->solnpos < ret->soln->len); /* or gems == 0 */ assert(!ret->dead); /* or not a solution */ } else { char *error = NULL, *soln = solve_game(NULL, ret, NULL, &error); if (!error) { install_new_solution(ret, soln); sfree(soln); } else discard_solution(ret); } } return ret; } /* ---------------------------------------------------------------------- * Drawing routines. */ static void game_compute_size(const game_params *params, int tilesize, int *x, int *y) { /* Ick: fake up `ds->tilesize' for macro expansion purposes */ struct { int tilesize; } ads, *ds = &ads; ads.tilesize = tilesize; *x = 2 * BORDER + 1 + params->w * TILESIZE; *y = 2 * BORDER + 1 + params->h * TILESIZE; } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { ds->tilesize = tilesize; assert(!ds->player_background); /* set_size is never called twice */ assert(!ds->player_bg_saved); ds->player_background = blitter_new(dr, TILESIZE, TILESIZE); } static float *game_colours(frontend *fe, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float); int i; game_mkhighlight(fe, ret, COL_BACKGROUND, COL_HIGHLIGHT, COL_LOWLIGHT); ret[COL_OUTLINE * 3 + 0] = 0.0F; ret[COL_OUTLINE * 3 + 1] = 0.0F; ret[COL_OUTLINE * 3 + 2] = 0.0F; ret[COL_PLAYER * 3 + 0] = 0.0F; ret[COL_PLAYER * 3 + 1] = 1.0F; ret[COL_PLAYER * 3 + 2] = 0.0F; ret[COL_DEAD_PLAYER * 3 + 0] = 1.0F; ret[COL_DEAD_PLAYER * 3 + 1] = 0.0F; ret[COL_DEAD_PLAYER * 3 + 2] = 0.0F; ret[COL_MINE * 3 + 0] = 0.0F; ret[COL_MINE * 3 + 1] = 0.0F; ret[COL_MINE * 3 + 2] = 0.0F; ret[COL_GEM * 3 + 0] = 0.6F; ret[COL_GEM * 3 + 1] = 1.0F; ret[COL_GEM * 3 + 2] = 1.0F; for (i = 0; i < 3; i++) { ret[COL_WALL * 3 + i] = (3 * ret[COL_BACKGROUND * 3 + i] + 1 * ret[COL_HIGHLIGHT * 3 + i]) / 4; } ret[COL_HINT * 3 + 0] = 1.0F; ret[COL_HINT * 3 + 1] = 1.0F; ret[COL_HINT * 3 + 2] = 0.0F; *ncolours = NCOLOURS; return ret; } static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { int w = state->p.w, h = state->p.h, wh = w*h; struct game_drawstate *ds = snew(struct game_drawstate); int i; ds->tilesize = 0; /* We can't allocate the blitter rectangle for the player background * until we know what size to make it. */ ds->player_background = NULL; ds->player_bg_saved = FALSE; ds->pbgx = ds->pbgy = -1; ds->p = state->p; /* structure copy */ ds->started = FALSE; ds->grid = snewn(wh, unsigned short); for (i = 0; i < wh; i++) ds->grid[i] = UNDRAWN; return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { if (ds->player_background) blitter_free(dr, ds->player_background); sfree(ds->grid); sfree(ds); } static void draw_player(drawing *dr, game_drawstate *ds, int x, int y, int dead, int hintdir) { if (dead) { int coords[DIRECTIONS*4]; int d; for (d = 0; d < DIRECTIONS; d++) { float x1, y1, x2, y2, x3, y3, len; x1 = DX(d); y1 = DY(d); len = sqrt(x1*x1+y1*y1); x1 /= len; y1 /= len; x3 = DX(d+1); y3 = DY(d+1); len = sqrt(x3*x3+y3*y3); x3 /= len; y3 /= len; x2 = (x1+x3) / 4; y2 = (y1+y3) / 4; coords[d*4+0] = x + TILESIZE/2 + (int)((TILESIZE*3/7) * x1); coords[d*4+1] = y + TILESIZE/2 + (int)((TILESIZE*3/7) * y1); coords[d*4+2] = x + TILESIZE/2 + (int)((TILESIZE*3/7) * x2); coords[d*4+3] = y + TILESIZE/2 + (int)((TILESIZE*3/7) * y2); } draw_polygon(dr, coords, DIRECTIONS*2, COL_DEAD_PLAYER, COL_OUTLINE); } else { draw_circle(dr, x + TILESIZE/2, y + TILESIZE/2, TILESIZE/3, COL_PLAYER, COL_OUTLINE); } if (!dead && hintdir >= 0) { float scale = (DX(hintdir) && DY(hintdir) ? 0.8F : 1.0F); int ax = (TILESIZE*2/5) * scale * DX(hintdir); int ay = (TILESIZE*2/5) * scale * DY(hintdir); int px = -ay, py = ax; int ox = x + TILESIZE/2, oy = y + TILESIZE/2; int coords[14], *c; c = coords; *c++ = ox + px/9; *c++ = oy + py/9; *c++ = ox + px/9 + ax*2/3; *c++ = oy + py/9 + ay*2/3; *c++ = ox + px/3 + ax*2/3; *c++ = oy + py/3 + ay*2/3; *c++ = ox + ax; *c++ = oy + ay; *c++ = ox - px/3 + ax*2/3; *c++ = oy - py/3 + ay*2/3; *c++ = ox - px/9 + ax*2/3; *c++ = oy - py/9 + ay*2/3; *c++ = ox - px/9; *c++ = oy - py/9; draw_polygon(dr, coords, 7, COL_HINT, COL_OUTLINE); } draw_update(dr, x, y, TILESIZE, TILESIZE); } #define FLASH_DEAD 0x100 #define FLASH_WIN 0x200 #define FLASH_MASK 0x300 static void draw_tile(drawing *dr, game_drawstate *ds, int x, int y, int v) { int tx = COORD(x), ty = COORD(y); int bg = (v & FLASH_DEAD ? COL_DEAD_PLAYER : v & FLASH_WIN ? COL_HIGHLIGHT : COL_BACKGROUND); v &= ~FLASH_MASK; clip(dr, tx+1, ty+1, TILESIZE-1, TILESIZE-1); draw_rect(dr, tx+1, ty+1, TILESIZE-1, TILESIZE-1, bg); if (v == WALL) { int coords[6]; coords[0] = tx + TILESIZE; coords[1] = ty + TILESIZE; coords[2] = tx + TILESIZE; coords[3] = ty + 1; coords[4] = tx + 1; coords[5] = ty + TILESIZE; draw_polygon(dr, coords, 3, COL_LOWLIGHT, COL_LOWLIGHT); coords[0] = tx + 1; coords[1] = ty + 1; draw_polygon(dr, coords, 3, COL_HIGHLIGHT, COL_HIGHLIGHT); draw_rect(dr, tx + 1 + HIGHLIGHT_WIDTH, ty + 1 + HIGHLIGHT_WIDTH, TILESIZE - 2*HIGHLIGHT_WIDTH, TILESIZE - 2*HIGHLIGHT_WIDTH, COL_WALL); } else if (v == MINE) { int cx = tx + TILESIZE / 2; int cy = ty + TILESIZE / 2; int r = TILESIZE / 2 - 3; draw_circle(dr, cx, cy, 5*r/6, COL_MINE, COL_MINE); draw_rect(dr, cx - r/6, cy - r, 2*(r/6)+1, 2*r+1, COL_MINE); draw_rect(dr, cx - r, cy - r/6, 2*r+1, 2*(r/6)+1, COL_MINE); draw_rect(dr, cx-r/3, cy-r/3, r/3, r/4, COL_HIGHLIGHT); } else if (v == STOP) { draw_circle(dr, tx + TILESIZE/2, ty + TILESIZE/2, TILESIZE*3/7, -1, COL_OUTLINE); draw_rect(dr, tx + TILESIZE*3/7, ty+1, TILESIZE - 2*(TILESIZE*3/7) + 1, TILESIZE-1, bg); draw_rect(dr, tx+1, ty + TILESIZE*3/7, TILESIZE-1, TILESIZE - 2*(TILESIZE*3/7) + 1, bg); } else if (v == GEM) { int coords[8]; coords[0] = tx+TILESIZE/2; coords[1] = ty+TILESIZE/2-TILESIZE*5/14; coords[2] = tx+TILESIZE/2-TILESIZE*5/14; coords[3] = ty+TILESIZE/2; coords[4] = tx+TILESIZE/2; coords[5] = ty+TILESIZE/2+TILESIZE*5/14; coords[6] = tx+TILESIZE/2+TILESIZE*5/14; coords[7] = ty+TILESIZE/2; draw_polygon(dr, coords, 4, COL_GEM, COL_OUTLINE); } unclip(dr); draw_update(dr, tx, ty, TILESIZE, TILESIZE); } #define BASE_ANIM_LENGTH 0.1F #define FLASH_LENGTH 0.3F static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float animtime, float flashtime) { int w = state->p.w, h = state->p.h /*, wh = w*h */; int x, y; float ap; int player_dist; int flashtype; int gems, deaths; char status[256]; if (flashtime && !((int)(flashtime * 3 / FLASH_LENGTH) % 2)) flashtype = ui->flashtype; else flashtype = 0; /* * Erase the player sprite. */ if (ds->player_bg_saved) { assert(ds->player_background); blitter_load(dr, ds->player_background, ds->pbgx, ds->pbgy); draw_update(dr, ds->pbgx, ds->pbgy, TILESIZE, TILESIZE); ds->player_bg_saved = FALSE; } /* * Initialise a fresh drawstate. */ if (!ds->started) { int wid, ht; /* * Blank out the window initially. */ game_compute_size(&ds->p, TILESIZE, &wid, &ht); draw_rect(dr, 0, 0, wid, ht, COL_BACKGROUND); draw_update(dr, 0, 0, wid, ht); /* * Draw the grid lines. */ for (y = 0; y <= h; y++) draw_line(dr, COORD(0), COORD(y), COORD(w), COORD(y), COL_LOWLIGHT); for (x = 0; x <= w; x++) draw_line(dr, COORD(x), COORD(0), COORD(x), COORD(h), COL_LOWLIGHT); ds->started = TRUE; } /* * If we're in the process of animating a move, let's start by * working out how far the player has moved from their _older_ * state. */ if (oldstate) { ap = animtime / ui->anim_length; player_dist = ap * (dir > 0 ? state : oldstate)->distance_moved; } else { player_dist = 0; ap = 0.0F; } /* * Draw the grid contents. * * We count the gems as we go round this loop, for the purposes * of the status bar. Of course we have a gems counter in the * game_state already, but if we do the counting in this loop * then it tracks gems being picked up in a sliding move, and * updates one by one. */ gems = 0; for (y = 0; y < h; y++) for (x = 0; x < w; x++) { unsigned short v = (unsigned char)state->grid[y*w+x]; /* * Special case: if the player is in the process of * moving over a gem, we draw the gem iff they haven't * gone past it yet. */ if (oldstate && oldstate->grid[y*w+x] != state->grid[y*w+x]) { /* * Compute the distance from this square to the * original player position. */ int dist = max(abs(x - oldstate->px), abs(y - oldstate->py)); /* * If the player has reached here, use the new grid * element. Otherwise use the old one. */ if (player_dist < dist) v = oldstate->grid[y*w+x]; else v = state->grid[y*w+x]; } /* * Special case: erase the mine the dead player is * sitting on. Only at the end of the move. */ if (v == MINE && !oldstate && state->dead && x == state->px && y == state->py) v = BLANK; if (v == GEM) gems++; v |= flashtype; if (ds->grid[y*w+x] != v) { draw_tile(dr, ds, x, y, v); ds->grid[y*w+x] = v; } } /* * Gem counter in the status bar. We replace it with * `COMPLETED!' when it reaches zero ... or rather, when the * _current state_'s gem counter is zero. (Thus, `Gems: 0' is * shown between the collection of the last gem and the * completion of the move animation that did it.) */ if (state->dead && (!oldstate || oldstate->dead)) { sprintf(status, "DEAD!"); } else if (state->gems || (oldstate && oldstate->gems)) { if (state->cheated) sprintf(status, "Auto-solver used. "); else *status = '\0'; sprintf(status + strlen(status), "Gems: %d", gems); } else if (state->cheated) { sprintf(status, "Auto-solved."); } else { sprintf(status, "COMPLETED!"); } /* We subtract one from the visible death counter if we're still * animating the move at the end of which the death took place. */ deaths = ui->deaths; if (oldstate && ui->just_died) { assert(deaths > 0); deaths--; } if (deaths) sprintf(status + strlen(status), " Deaths: %d", deaths); status_bar(dr, status); /* * Draw the player sprite. */ assert(!ds->player_bg_saved); assert(ds->player_background); { int ox, oy, nx, ny; nx = COORD(state->px); ny = COORD(state->py); if (oldstate) { ox = COORD(oldstate->px); oy = COORD(oldstate->py); } else { ox = nx; oy = ny; } ds->pbgx = ox + ap * (nx - ox); ds->pbgy = oy + ap * (ny - oy); } blitter_save(dr, ds->player_background, ds->pbgx, ds->pbgy); draw_player(dr, ds, ds->pbgx, ds->pbgy, (state->dead && !oldstate), (!oldstate && state->soln ? state->soln->list[state->solnpos] : -1)); ds->player_bg_saved = TRUE; } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { int dist; if (dir > 0) dist = newstate->distance_moved; else dist = oldstate->distance_moved; ui->anim_length = sqrt(dist) * BASE_ANIM_LENGTH; return ui->anim_length; } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { if (!oldstate->dead && newstate->dead) { ui->flashtype = FLASH_DEAD; return FLASH_LENGTH; } else if (oldstate->gems && !newstate->gems) { ui->flashtype = FLASH_WIN; return FLASH_LENGTH; } return 0.0F; } static int game_status(const game_state *state) { /* * We never report the game as lost, on the grounds that if the * player has died they're quite likely to want to undo and carry * on. */ return state->gems == 0 ? +1 : 0; } static int game_timing_state(const game_state *state, game_ui *ui) { return TRUE; } static void game_print_size(const game_params *params, float *x, float *y) { } static void game_print(drawing *dr, const game_state *state, int tilesize) { } #ifdef COMBINED #define thegame inertia #endif const struct game thegame = { "Inertia", "games.inertia", "inertia", default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, TRUE, solve_game, TRUE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, PREFERRED_TILESIZE, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, FALSE, FALSE, game_print_size, game_print, TRUE, /* wants_statusbar */ FALSE, game_timing_state, 0, /* flags */ }; puzzles-20170606.272beef/guess.c0000644000175000017500000013145213115373615015171 0ustar simonsimon/* * guess.c: Mastermind clone. */ #include #include #include #include #include #include #include "puzzles.h" #define FLASH_FRAME 0.5F enum { COL_BACKGROUND, COL_FRAME, COL_CURSOR, COL_FLASH, COL_HOLD, COL_EMPTY, /* must be COL_1 - 1 */ COL_1, COL_2, COL_3, COL_4, COL_5, COL_6, COL_7, COL_8, COL_9, COL_10, COL_CORRECTPLACE, COL_CORRECTCOLOUR, NCOLOURS }; struct game_params { int ncolours, npegs, nguesses; int allow_blank, allow_multiple; }; #define FEEDBACK_CORRECTPLACE 1 #define FEEDBACK_CORRECTCOLOUR 2 typedef struct pegrow { int npegs; int *pegs; /* 0 is 'empty' */ int *feedback; /* may well be unused */ } *pegrow; struct game_state { game_params params; pegrow *guesses; /* length params->nguesses */ int *holds; pegrow solution; int next_go; /* from 0 to nguesses-1; if next_go == nguesses then they've lost. */ int solved; /* +1 = win, -1 = lose, 0 = still playing */ }; static game_params *default_params(void) { game_params *ret = snew(game_params); /* AFAIK this is the canonical Mastermind ruleset. */ ret->ncolours = 6; ret->npegs = 4; ret->nguesses = 10; ret->allow_blank = 0; ret->allow_multiple = 1; return ret; } static void free_params(game_params *params) { sfree(params); } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } static const struct { char *name; game_params params; } guess_presets[] = { {"Standard", {6, 4, 10, FALSE, TRUE}}, {"Super", {8, 5, 12, FALSE, TRUE}}, }; static int game_fetch_preset(int i, char **name, game_params **params) { if (i < 0 || i >= lenof(guess_presets)) return FALSE; *name = dupstr(guess_presets[i].name); /* * get round annoying const issues */ { game_params tmp = guess_presets[i].params; *params = dup_params(&tmp); } return TRUE; } static void decode_params(game_params *params, char const *string) { char const *p = string; game_params *defs = default_params(); *params = *defs; free_params(defs); while (*p) { switch (*p++) { case 'c': params->ncolours = atoi(p); while (*p && isdigit((unsigned char)*p)) p++; break; case 'p': params->npegs = atoi(p); while (*p && isdigit((unsigned char)*p)) p++; break; case 'g': params->nguesses = atoi(p); while (*p && isdigit((unsigned char)*p)) p++; break; case 'b': params->allow_blank = 1; break; case 'B': params->allow_blank = 0; break; case 'm': params->allow_multiple = 1; break; case 'M': params->allow_multiple = 0; break; default: ; } } } static char *encode_params(const game_params *params, int full) { char data[256]; sprintf(data, "c%dp%dg%d%s%s", params->ncolours, params->npegs, params->nguesses, params->allow_blank ? "b" : "B", params->allow_multiple ? "m" : "M"); return dupstr(data); } static config_item *game_configure(const game_params *params) { config_item *ret; char buf[80]; ret = snewn(6, config_item); ret[0].name = "Colours"; ret[0].type = C_STRING; sprintf(buf, "%d", params->ncolours); ret[0].sval = dupstr(buf); ret[0].ival = 0; ret[1].name = "Pegs per guess"; ret[1].type = C_STRING; sprintf(buf, "%d", params->npegs); ret[1].sval = dupstr(buf); ret[1].ival = 0; ret[2].name = "Guesses"; ret[2].type = C_STRING; sprintf(buf, "%d", params->nguesses); ret[2].sval = dupstr(buf); ret[2].ival = 0; ret[3].name = "Allow blanks"; ret[3].type = C_BOOLEAN; ret[3].sval = NULL; ret[3].ival = params->allow_blank; ret[4].name = "Allow duplicates"; ret[4].type = C_BOOLEAN; ret[4].sval = NULL; ret[4].ival = params->allow_multiple; ret[5].name = NULL; ret[5].type = C_END; ret[5].sval = NULL; ret[5].ival = 0; return ret; } static game_params *custom_params(const config_item *cfg) { game_params *ret = snew(game_params); ret->ncolours = atoi(cfg[0].sval); ret->npegs = atoi(cfg[1].sval); ret->nguesses = atoi(cfg[2].sval); ret->allow_blank = cfg[3].ival; ret->allow_multiple = cfg[4].ival; return ret; } static char *validate_params(const game_params *params, int full) { if (params->ncolours < 2 || params->npegs < 2) return "Trivial solutions are uninteresting"; /* NB as well as the no. of colours we define, max(ncolours) must * also fit in an unsigned char; see new_game_desc. */ if (params->ncolours > 10) return "Too many colours"; if (params->nguesses < 1) return "Must have at least one guess"; if (!params->allow_multiple && params->ncolours < params->npegs) return "Disallowing multiple colours requires at least as many colours as pegs"; return NULL; } static pegrow new_pegrow(int npegs) { pegrow pegs = snew(struct pegrow); pegs->npegs = npegs; pegs->pegs = snewn(pegs->npegs, int); memset(pegs->pegs, 0, pegs->npegs * sizeof(int)); pegs->feedback = snewn(pegs->npegs, int); memset(pegs->feedback, 0, pegs->npegs * sizeof(int)); return pegs; } static pegrow dup_pegrow(pegrow pegs) { pegrow newpegs = new_pegrow(pegs->npegs); memcpy(newpegs->pegs, pegs->pegs, newpegs->npegs * sizeof(int)); memcpy(newpegs->feedback, pegs->feedback, newpegs->npegs * sizeof(int)); return newpegs; } static void invalidate_pegrow(pegrow pegs) { memset(pegs->pegs, -1, pegs->npegs * sizeof(int)); memset(pegs->feedback, -1, pegs->npegs * sizeof(int)); } static void free_pegrow(pegrow pegs) { sfree(pegs->pegs); sfree(pegs->feedback); sfree(pegs); } static char *new_game_desc(const game_params *params, random_state *rs, char **aux, int interactive) { unsigned char *bmp = snewn(params->npegs, unsigned char); char *ret; int i, c; pegrow colcount = new_pegrow(params->ncolours); for (i = 0; i < params->npegs; i++) { newcol: c = random_upto(rs, params->ncolours); if (!params->allow_multiple && colcount->pegs[c]) goto newcol; colcount->pegs[c]++; bmp[i] = (unsigned char)(c+1); } obfuscate_bitmap(bmp, params->npegs*8, FALSE); ret = bin2hex(bmp, params->npegs); sfree(bmp); free_pegrow(colcount); return ret; } static char *validate_desc(const game_params *params, const char *desc) { unsigned char *bmp; int i; /* desc is just an (obfuscated) bitmap of the solution; check that * it's the correct length and (when unobfuscated) contains only * sensible colours. */ if (strlen(desc) != params->npegs * 2) return "Game description is wrong length"; bmp = hex2bin(desc, params->npegs); obfuscate_bitmap(bmp, params->npegs*8, TRUE); for (i = 0; i < params->npegs; i++) { if (bmp[i] < 1 || bmp[i] > params->ncolours) { sfree(bmp); return "Game description is corrupted"; } } sfree(bmp); return NULL; } static game_state *new_game(midend *me, const game_params *params, const char *desc) { game_state *state = snew(game_state); unsigned char *bmp; int i; state->params = *params; state->guesses = snewn(params->nguesses, pegrow); for (i = 0; i < params->nguesses; i++) state->guesses[i] = new_pegrow(params->npegs); state->holds = snewn(params->npegs, int); state->solution = new_pegrow(params->npegs); bmp = hex2bin(desc, params->npegs); obfuscate_bitmap(bmp, params->npegs*8, TRUE); for (i = 0; i < params->npegs; i++) state->solution->pegs[i] = (int)bmp[i]; sfree(bmp); memset(state->holds, 0, sizeof(int) * params->npegs); state->next_go = state->solved = 0; return state; } static game_state *dup_game(const game_state *state) { game_state *ret = snew(game_state); int i; *ret = *state; ret->guesses = snewn(state->params.nguesses, pegrow); for (i = 0; i < state->params.nguesses; i++) ret->guesses[i] = dup_pegrow(state->guesses[i]); ret->holds = snewn(state->params.npegs, int); memcpy(ret->holds, state->holds, sizeof(int) * state->params.npegs); ret->solution = dup_pegrow(state->solution); return ret; } static void free_game(game_state *state) { int i; free_pegrow(state->solution); for (i = 0; i < state->params.nguesses; i++) free_pegrow(state->guesses[i]); sfree(state->holds); sfree(state->guesses); sfree(state); } static char *solve_game(const game_state *state, const game_state *currstate, const char *aux, char **error) { return dupstr("S"); } static int game_can_format_as_text_now(const game_params *params) { return TRUE; } static char *game_text_format(const game_state *state) { return NULL; } static int is_markable(const game_params *params, pegrow pegs) { int i, nset = 0, nrequired, ret = 0; pegrow colcount = new_pegrow(params->ncolours); nrequired = params->allow_blank ? 1 : params->npegs; for (i = 0; i < params->npegs; i++) { int c = pegs->pegs[i]; if (c > 0) { colcount->pegs[c-1]++; nset++; } } if (nset < nrequired) goto done; if (!params->allow_multiple) { for (i = 0; i < params->ncolours; i++) { if (colcount->pegs[i] > 1) goto done; } } ret = 1; done: free_pegrow(colcount); return ret; } struct game_ui { game_params params; pegrow curr_pegs; /* half-finished current move */ int *holds; int colour_cur; /* position of up-down colour picker cursor */ int peg_cur; /* position of left-right peg picker cursor */ int display_cur, markable; int drag_col, drag_x, drag_y; /* x and y are *center* of peg! */ int drag_opeg; /* peg index, if dragged from a peg (from current guess), otherwise -1 */ int show_labels; /* label the colours with letters */ pegrow hint; }; static game_ui *new_ui(const game_state *state) { game_ui *ui = snew(game_ui); memset(ui, 0, sizeof(game_ui)); ui->params = state->params; /* structure copy */ ui->curr_pegs = new_pegrow(state->params.npegs); ui->holds = snewn(state->params.npegs, int); memset(ui->holds, 0, sizeof(int)*state->params.npegs); ui->drag_opeg = -1; return ui; } static void free_ui(game_ui *ui) { if (ui->hint) free_pegrow(ui->hint); free_pegrow(ui->curr_pegs); sfree(ui->holds); sfree(ui); } static char *encode_ui(const game_ui *ui) { char *ret, *p, *sep; int i; /* * For this game it's worth storing the contents of the current * guess, and the current set of holds. */ ret = snewn(40 * ui->curr_pegs->npegs, char); p = ret; sep = ""; for (i = 0; i < ui->curr_pegs->npegs; i++) { p += sprintf(p, "%s%d%s", sep, ui->curr_pegs->pegs[i], ui->holds[i] ? "_" : ""); sep = ","; } *p++ = '\0'; assert(p - ret < 40 * ui->curr_pegs->npegs); return sresize(ret, p - ret, char); } static void decode_ui(game_ui *ui, const char *encoding) { int i; const char *p = encoding; for (i = 0; i < ui->curr_pegs->npegs; i++) { ui->curr_pegs->pegs[i] = atoi(p); while (*p && isdigit((unsigned char)*p)) p++; if (*p == '_') { /* NB: old versions didn't store holds */ ui->holds[i] = 1; p++; } else ui->holds[i] = 0; if (*p == ',') p++; } ui->markable = is_markable(&ui->params, ui->curr_pegs); } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { int i; if (newstate->next_go < oldstate->next_go) { sfree(ui->hint); ui->hint = NULL; } /* Implement holds, clear other pegs. * This does something that is arguably the Right Thing even * for undo. */ for (i = 0; i < newstate->solution->npegs; i++) { if (newstate->solved) ui->holds[i] = 0; else ui->holds[i] = newstate->holds[i]; if (newstate->solved || (newstate->next_go == 0) || !ui->holds[i]) { ui->curr_pegs->pegs[i] = 0; } else ui->curr_pegs->pegs[i] = newstate->guesses[newstate->next_go-1]->pegs[i]; } ui->markable = is_markable(&newstate->params, ui->curr_pegs); /* Clean up cursor position */ if (!ui->markable && ui->peg_cur == newstate->solution->npegs) ui->peg_cur--; } #define PEGSZ (ds->pegsz) #define PEGOFF (ds->pegsz + ds->gapsz) #define HINTSZ (ds->hintsz) #define HINTOFF (ds->hintsz + ds->gapsz) #define GAP (ds->gapsz) #define CGAP (ds->gapsz / 2) #define PEGRAD (ds->pegrad) #define HINTRAD (ds->hintrad) #define COL_OX (ds->colx) #define COL_OY (ds->coly) #define COL_X(c) (COL_OX) #define COL_Y(c) (COL_OY + (c)*PEGOFF) #define COL_W PEGOFF #define COL_H (ds->colours->npegs*PEGOFF) #define GUESS_OX (ds->guessx) #define GUESS_OY (ds->guessy) #define GUESS_X(g,p) (GUESS_OX + (p)*PEGOFF) #define GUESS_Y(g,p) (GUESS_OY + (g)*PEGOFF) #define GUESS_W (ds->solution->npegs*PEGOFF) #define GUESS_H (ds->nguesses*PEGOFF) #define HINT_OX (GUESS_OX + GUESS_W + ds->gapsz) #define HINT_OY (GUESS_OY + (PEGSZ - HINTOFF - HINTSZ) / 2) #define HINT_X(g) HINT_OX #define HINT_Y(g) (HINT_OY + (g)*PEGOFF) #define HINT_W ((ds->hintw*HINTOFF) - GAP) #define HINT_H GUESS_H #define SOLN_OX GUESS_OX #define SOLN_OY (GUESS_OY + GUESS_H + ds->gapsz + 2) #define SOLN_W GUESS_W #define SOLN_H PEGOFF struct game_drawstate { int nguesses; pegrow *guesses; /* same size as state->guesses */ pegrow solution; /* only displayed if state->solved */ pegrow colours; /* length ncolours, not npegs */ int pegsz, hintsz, gapsz; /* peg size (diameter), etc. */ int pegrad, hintrad; /* radius of peg, hint */ int border; int colx, coly; /* origin of colours vertical bar */ int guessx, guessy; /* origin of guesses */ int solnx, solny; /* origin of solution */ int hintw; /* no. of hint tiles we're wide per row */ int w, h, started, solved; int next_go; blitter *blit_peg; int drag_col, blit_ox, blit_oy; }; static void set_peg(const game_params *params, game_ui *ui, int peg, int col) { ui->curr_pegs->pegs[peg] = col; ui->markable = is_markable(params, ui->curr_pegs); } static int mark_pegs(pegrow guess, const pegrow solution, int ncols) { int nc_place = 0, nc_colour = 0, i, j; assert(guess && solution && (guess->npegs == solution->npegs)); for (i = 0; i < guess->npegs; i++) { if (guess->pegs[i] == solution->pegs[i]) nc_place++; } /* slight bit of cleverness: we have the following formula, from * http://mathworld.wolfram.com/Mastermind.html that gives: * * nc_colour = sum(colours, min(#solution, #guess)) - nc_place * * I think this is due to Knuth. */ for (i = 1; i <= ncols; i++) { int n_guess = 0, n_solution = 0; for (j = 0; j < guess->npegs; j++) { if (guess->pegs[j] == i) n_guess++; if (solution->pegs[j] == i) n_solution++; } nc_colour += min(n_guess, n_solution); } nc_colour -= nc_place; debug(("mark_pegs, %d pegs, %d right place, %d right colour", guess->npegs, nc_place, nc_colour)); assert((nc_colour + nc_place) <= guess->npegs); memset(guess->feedback, 0, guess->npegs*sizeof(int)); for (i = 0, j = 0; i < nc_place; i++) guess->feedback[j++] = FEEDBACK_CORRECTPLACE; for (i = 0; i < nc_colour; i++) guess->feedback[j++] = FEEDBACK_CORRECTCOLOUR; return nc_place; } static char *encode_move(const game_state *from, game_ui *ui) { char *buf, *p, *sep; int len, i; len = ui->curr_pegs->npegs * 20 + 2; buf = snewn(len, char); p = buf; *p++ = 'G'; sep = ""; for (i = 0; i < ui->curr_pegs->npegs; i++) { p += sprintf(p, "%s%d%s", sep, ui->curr_pegs->pegs[i], ui->holds[i] ? "_" : ""); sep = ","; } *p++ = '\0'; assert(p - buf <= len); buf = sresize(buf, len, char); return buf; } static void compute_hint(const game_state *state, game_ui *ui) { /* Suggest the lexicographically first row consistent with all * previous feedback. This is not only a useful hint, but also * a reasonable strategy if applied consistently. If the user * uses hints in every turn, they may be able to intuit this * strategy, or one similar to it. I (Jonas Kölker) came up * with something close to it without seeing it in action. */ /* Some performance characteristics: I want to ask for each n, * how many solutions are guessed in exactly n guesses if you * use the hint in each turn. * * With 4 pegs and 6 colours you get the following histogram: * * 1 guesses: 1 solution * 2 guesses: 4 solutions * 3 guesses: 25 solutions * 4 guesses: 108 solutions * 5 guesses: 305 solutions * 6 guesses: 602 solutions * 7 guesses: 196 solutions * 8 guesses: 49 solutions * 9 guesses: 6 solutions * (note: the tenth guess is never necessary.) * * With 5 pegs and 8 colours you get the following histogram: * * 1 guesses: 1 solution * 2 guesses: 5 solutions * 3 guesses: 43 solutions * 4 guesses: 278 solutions * 5 guesses: 1240 solutions * 6 guesses: 3515 solutions * 7 guesses: 7564 solutions * 8 guesses: 14086 solutions * 9 guesses: 4614 solutions * 10 guesses: 1239 solutions * 11 guesses: 175 solutions * 12 guesses: 7 solutions * 13 guesses: 1 solution * * The solution which takes too many guesses is {8, 8, 5, 6, 7}. * The game ID is c8p5g12Bm:4991e5e41a. */ int mincolour = 1, maxcolour = 0, i, j; /* For large values of npegs and ncolours, the lexicographically * next guess make take a while to find. Finding upper and * lower limits on which colours we have to consider will speed * this up, as will caching our progress from one invocation to * the next. The latter strategy works, since if we have ruled * out a candidate we will never reverse this judgment in the * light of new information. Removing information, i.e. undo, * will require us to backtrack somehow. We backtrack by fully * forgetting our progress (and recomputing it if required). */ for (i = 0; i < state->next_go; ++i) for (j = 0; j < state->params.npegs; ++j) if (state->guesses[i]->pegs[j] > maxcolour) maxcolour = state->guesses[i]->pegs[j]; maxcolour = min(maxcolour + 1, state->params.ncolours); increase_mincolour: for (i = 0; i < state->next_go; ++i) { if (state->guesses[i]->feedback[0]) goto next_iteration; for (j = 0; j < state->params.npegs; ++j) if (state->guesses[i]->pegs[j] != mincolour) goto next_iteration; ++mincolour; goto increase_mincolour; next_iteration: ; } if (!ui->hint) { ui->hint = new_pegrow(state->params.npegs); for (i = 0; i < state->params.npegs; ++i) ui->hint->pegs[i] = 1; } while (ui->hint->pegs[0] <= state->params.ncolours) { for (i = 0; i < state->next_go; ++i) { mark_pegs(ui->hint, state->guesses[i], maxcolour); for (j = 0; j < state->params.npegs; ++j) if (ui->hint->feedback[j] != state->guesses[i]->feedback[j]) goto increment_pegrow; } /* a valid guess was found; install it and return */ for (i = 0; i < state->params.npegs; ++i) ui->curr_pegs->pegs[i] = ui->hint->pegs[i]; ui->markable = TRUE; ui->peg_cur = state->params.npegs; ui->display_cur = 1; return; increment_pegrow: for (i = ui->hint->npegs; ++ui->hint->pegs[--i], i && ui->hint->pegs[i] > maxcolour; ui->hint->pegs[i] = mincolour); } /* No solution is compatible with the given hints. Impossible! */ /* (hack new_game_desc to create invalid solutions to get here) */ /* For some values of npegs and ncolours, the hinting function takes a * long time to complete. To visually indicate completion with failure, * should it ever happen, update the ui in some trivial way. This gives * the user a sense of broken(ish)ness and futility. */ if (!ui->display_cur) { ui->display_cur = 1; } else if (state->params.npegs == 1) { ui->display_cur = 0; } else { ui->peg_cur = (ui->peg_cur + 1) % state->params.npegs; } } static char *interpret_move(const game_state *from, game_ui *ui, const game_drawstate *ds, int x, int y, int button) { int over_col = 0; /* one-indexed */ int over_guess = -1; /* zero-indexed */ int over_past_guess_y = -1; /* zero-indexed */ int over_past_guess_x = -1; /* zero-indexed */ int over_hint = 0; /* zero or one */ char *ret = NULL; int guess_ox = GUESS_X(from->next_go, 0); int guess_oy = GUESS_Y(from->next_go, 0); /* * Enable or disable labels on colours. */ if (button == 'l' || button == 'L') { ui->show_labels = !ui->show_labels; return ""; } if (from->solved) return NULL; if (x >= COL_OX && x < (COL_OX + COL_W) && y >= COL_OY && y < (COL_OY + COL_H)) { over_col = ((y - COL_OY) / PEGOFF) + 1; assert(over_col >= 1 && over_col <= ds->colours->npegs); } else if (x >= guess_ox && y >= guess_oy && y < (guess_oy + GUESS_H)) { if (x < (guess_ox + GUESS_W)) { over_guess = (x - guess_ox) / PEGOFF; assert(over_guess >= 0 && over_guess < ds->solution->npegs); } else { over_hint = 1; } } else if (x >= guess_ox && x < (guess_ox + GUESS_W) && y >= GUESS_OY && y < guess_oy) { over_past_guess_y = (y - GUESS_OY) / PEGOFF; over_past_guess_x = (x - guess_ox) / PEGOFF; assert(over_past_guess_y >= 0 && over_past_guess_y < from->next_go); assert(over_past_guess_x >= 0 && over_past_guess_x < ds->solution->npegs); } debug(("make_move: over_col %d, over_guess %d, over_hint %d," " over_past_guess (%d,%d)", over_col, over_guess, over_hint, over_past_guess_x, over_past_guess_y)); assert(ds->blit_peg); /* mouse input */ if (button == LEFT_BUTTON) { if (over_col > 0) { ui->drag_col = over_col; ui->drag_opeg = -1; debug(("Start dragging from colours")); } else if (over_guess > -1) { int col = ui->curr_pegs->pegs[over_guess]; if (col) { ui->drag_col = col; ui->drag_opeg = over_guess; debug(("Start dragging from a guess")); } } else if (over_past_guess_y > -1) { int col = from->guesses[over_past_guess_y]->pegs[over_past_guess_x]; if (col) { ui->drag_col = col; ui->drag_opeg = -1; debug(("Start dragging from a past guess")); } } if (ui->drag_col) { ui->drag_x = x; ui->drag_y = y; debug(("Start dragging, col = %d, (%d,%d)", ui->drag_col, ui->drag_x, ui->drag_y)); ret = ""; } } else if (button == LEFT_DRAG && ui->drag_col) { ui->drag_x = x; ui->drag_y = y; debug(("Keep dragging, (%d,%d)", ui->drag_x, ui->drag_y)); ret = ""; } else if (button == LEFT_RELEASE && ui->drag_col) { if (over_guess > -1) { debug(("Dropping colour %d onto guess peg %d", ui->drag_col, over_guess)); set_peg(&from->params, ui, over_guess, ui->drag_col); } else { if (ui->drag_opeg > -1) { debug(("Removing colour %d from peg %d", ui->drag_col, ui->drag_opeg)); set_peg(&from->params, ui, ui->drag_opeg, 0); } } ui->drag_col = 0; ui->drag_opeg = -1; ui->display_cur = 0; debug(("Stop dragging.")); ret = ""; } else if (button == RIGHT_BUTTON) { if (over_guess > -1) { /* we use ths feedback in the game_ui to signify * 'carry this peg to the next guess as well'. */ ui->holds[over_guess] = 1 - ui->holds[over_guess]; ret = ""; } } else if (button == LEFT_RELEASE && over_hint && ui->markable) { /* NB this won't trigger if on the end of a drag; that's on * purpose, in case you drop by mistake... */ ret = encode_move(from, ui); } /* keyboard input */ if (button == CURSOR_UP || button == CURSOR_DOWN) { ui->display_cur = 1; if (button == CURSOR_DOWN && (ui->colour_cur+1) < from->params.ncolours) ui->colour_cur++; if (button == CURSOR_UP && ui->colour_cur > 0) ui->colour_cur--; ret = ""; } else if (button == 'h' || button == 'H' || button == '?') { compute_hint(from, ui); ret = ""; } else if (button == CURSOR_LEFT || button == CURSOR_RIGHT) { int maxcur = from->params.npegs; if (ui->markable) maxcur++; ui->display_cur = 1; if (button == CURSOR_RIGHT && (ui->peg_cur+1) < maxcur) ui->peg_cur++; if (button == CURSOR_LEFT && ui->peg_cur > 0) ui->peg_cur--; ret = ""; } else if (IS_CURSOR_SELECT(button)) { ui->display_cur = 1; if (ui->peg_cur == from->params.npegs) { ret = encode_move(from, ui); } else { set_peg(&from->params, ui, ui->peg_cur, ui->colour_cur+1); ret = ""; } } else if (button == 'D' || button == 'd' || button == '\b') { ui->display_cur = 1; set_peg(&from->params, ui, ui->peg_cur, 0); ret = ""; } else if (button == CURSOR_SELECT2) { if (ui->peg_cur == from->params.npegs) return NULL; ui->display_cur = 1; ui->holds[ui->peg_cur] = 1 - ui->holds[ui->peg_cur]; ret = ""; } return ret; } static game_state *execute_move(const game_state *from, const char *move) { int i, nc_place; game_state *ret; const char *p; if (!strcmp(move, "S")) { ret = dup_game(from); ret->solved = -1; return ret; } else if (move[0] == 'G') { p = move+1; ret = dup_game(from); for (i = 0; i < from->solution->npegs; i++) { int val = atoi(p); int min_colour = from->params.allow_blank? 0 : 1; if (val < min_colour || val > from->params.ncolours) { free_game(ret); return NULL; } ret->guesses[from->next_go]->pegs[i] = atoi(p); while (*p && isdigit((unsigned char)*p)) p++; if (*p == '_') { ret->holds[i] = 1; p++; } else ret->holds[i] = 0; if (*p == ',') p++; } nc_place = mark_pegs(ret->guesses[from->next_go], ret->solution, ret->params.ncolours); if (nc_place == ret->solution->npegs) { ret->solved = +1; /* win! */ } else { ret->next_go = from->next_go + 1; if (ret->next_go >= ret->params.nguesses) ret->solved = -1; /* lose, meaning we show the pegs. */ } return ret; } else return NULL; } /* ---------------------------------------------------------------------- * Drawing routines. */ #define PEG_PREFER_SZ 32 /* next three are multipliers for pegsz. It will look much nicer if * (2*PEG_HINT) + PEG_GAP = 1.0 as the hints are formatted like that. */ #define PEG_GAP 0.10 #define PEG_HINT 0.35 #define BORDER 0.5 static void game_compute_size(const game_params *params, int tilesize, int *x, int *y) { double hmul, vmul_c, vmul_g, vmul; int hintw = (params->npegs+1)/2; hmul = BORDER * 2.0 + /* border */ 1.0 * 2.0 + /* vertical colour bar */ 1.0 * params->npegs + /* guess pegs */ PEG_GAP * params->npegs + /* guess gaps */ PEG_HINT * hintw + /* hint pegs */ PEG_GAP * (hintw - 1); /* hint gaps */ vmul_c = BORDER * 2.0 + /* border */ 1.0 * params->ncolours + /* colour pegs */ PEG_GAP * (params->ncolours - 1); /* colour gaps */ vmul_g = BORDER * 2.0 + /* border */ 1.0 * (params->nguesses + 1) + /* guesses plus solution */ PEG_GAP * (params->nguesses + 1); /* gaps plus gap above soln */ vmul = max(vmul_c, vmul_g); *x = (int)ceil((double)tilesize * hmul); *y = (int)ceil((double)tilesize * vmul); } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { int colh, guessh; ds->pegsz = tilesize; ds->hintsz = (int)((double)ds->pegsz * PEG_HINT); ds->gapsz = (int)((double)ds->pegsz * PEG_GAP); ds->border = (int)((double)ds->pegsz * BORDER); ds->pegrad = (ds->pegsz -1)/2; /* radius of peg to fit in pegsz (which is 2r+1) */ ds->hintrad = (ds->hintsz-1)/2; colh = ((ds->pegsz + ds->gapsz) * params->ncolours) - ds->gapsz; guessh = ((ds->pegsz + ds->gapsz) * params->nguesses); /* guesses */ guessh += ds->gapsz + ds->pegsz; /* solution */ game_compute_size(params, tilesize, &ds->w, &ds->h); ds->colx = ds->border; ds->coly = (ds->h - colh) / 2; ds->guessx = ds->solnx = ds->border + ds->pegsz * 2; /* border + colours */ ds->guessy = (ds->h - guessh) / 2; ds->solny = ds->guessy + ((ds->pegsz + ds->gapsz) * params->nguesses) + ds->gapsz; assert(ds->pegsz > 0); assert(!ds->blit_peg); /* set_size is never called twice */ ds->blit_peg = blitter_new(dr, ds->pegsz+2, ds->pegsz+2); } static float *game_colours(frontend *fe, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float), max; int i; frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]); /* red */ ret[COL_1 * 3 + 0] = 1.0F; ret[COL_1 * 3 + 1] = 0.0F; ret[COL_1 * 3 + 2] = 0.0F; /* yellow */ ret[COL_2 * 3 + 0] = 1.0F; ret[COL_2 * 3 + 1] = 1.0F; ret[COL_2 * 3 + 2] = 0.0F; /* green */ ret[COL_3 * 3 + 0] = 0.0F; ret[COL_3 * 3 + 1] = 1.0F; ret[COL_3 * 3 + 2] = 0.0F; /* blue */ ret[COL_4 * 3 + 0] = 0.2F; ret[COL_4 * 3 + 1] = 0.3F; ret[COL_4 * 3 + 2] = 1.0F; /* orange */ ret[COL_5 * 3 + 0] = 1.0F; ret[COL_5 * 3 + 1] = 0.5F; ret[COL_5 * 3 + 2] = 0.0F; /* purple */ ret[COL_6 * 3 + 0] = 0.5F; ret[COL_6 * 3 + 1] = 0.0F; ret[COL_6 * 3 + 2] = 0.7F; /* brown */ ret[COL_7 * 3 + 0] = 0.5F; ret[COL_7 * 3 + 1] = 0.3F; ret[COL_7 * 3 + 2] = 0.3F; /* light blue */ ret[COL_8 * 3 + 0] = 0.4F; ret[COL_8 * 3 + 1] = 0.8F; ret[COL_8 * 3 + 2] = 1.0F; /* light green */ ret[COL_9 * 3 + 0] = 0.7F; ret[COL_9 * 3 + 1] = 1.0F; ret[COL_9 * 3 + 2] = 0.7F; /* pink */ ret[COL_10 * 3 + 0] = 1.0F; ret[COL_10 * 3 + 1] = 0.6F; ret[COL_10 * 3 + 2] = 1.0F; ret[COL_FRAME * 3 + 0] = 0.0F; ret[COL_FRAME * 3 + 1] = 0.0F; ret[COL_FRAME * 3 + 2] = 0.0F; ret[COL_CURSOR * 3 + 0] = 0.0F; ret[COL_CURSOR * 3 + 1] = 0.0F; ret[COL_CURSOR * 3 + 2] = 0.0F; ret[COL_FLASH * 3 + 0] = 0.5F; ret[COL_FLASH * 3 + 1] = 1.0F; ret[COL_FLASH * 3 + 2] = 1.0F; ret[COL_HOLD * 3 + 0] = 1.0F; ret[COL_HOLD * 3 + 1] = 0.5F; ret[COL_HOLD * 3 + 2] = 0.5F; ret[COL_CORRECTPLACE*3 + 0] = 0.0F; ret[COL_CORRECTPLACE*3 + 1] = 0.0F; ret[COL_CORRECTPLACE*3 + 2] = 0.0F; ret[COL_CORRECTCOLOUR*3 + 0] = 1.0F; ret[COL_CORRECTCOLOUR*3 + 1] = 1.0F; ret[COL_CORRECTCOLOUR*3 + 2] = 1.0F; /* We want to make sure we can distinguish COL_CORRECTCOLOUR * (which we hard-code as white) from COL_BACKGROUND (which * could default to white on some platforms). * Code borrowed from fifteen.c. */ max = ret[COL_BACKGROUND*3]; for (i = 1; i < 3; i++) if (ret[COL_BACKGROUND*3+i] > max) max = ret[COL_BACKGROUND*3+i]; if (max * 1.2F > 1.0F) { for (i = 0; i < 3; i++) ret[COL_BACKGROUND*3+i] /= (max * 1.2F); } /* We also want to be able to tell the difference between BACKGROUND * and EMPTY, for similar distinguishing-hint reasons. */ ret[COL_EMPTY * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] * 2.0F / 3.0F; ret[COL_EMPTY * 3 + 1] = ret[COL_BACKGROUND * 3 + 1] * 2.0F / 3.0F; ret[COL_EMPTY * 3 + 2] = ret[COL_BACKGROUND * 3 + 2] * 2.0F / 3.0F; *ncolours = NCOLOURS; return ret; } static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { struct game_drawstate *ds = snew(struct game_drawstate); int i; memset(ds, 0, sizeof(struct game_drawstate)); ds->guesses = snewn(state->params.nguesses, pegrow); ds->nguesses = state->params.nguesses; for (i = 0; i < state->params.nguesses; i++) { ds->guesses[i] = new_pegrow(state->params.npegs); invalidate_pegrow(ds->guesses[i]); } ds->solution = new_pegrow(state->params.npegs); invalidate_pegrow(ds->solution); ds->colours = new_pegrow(state->params.ncolours); invalidate_pegrow(ds->colours); ds->hintw = (state->params.npegs+1)/2; /* must round up */ ds->blit_peg = NULL; return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { int i; if (ds->blit_peg) blitter_free(dr, ds->blit_peg); free_pegrow(ds->colours); free_pegrow(ds->solution); for (i = 0; i < ds->nguesses; i++) free_pegrow(ds->guesses[i]); sfree(ds->guesses); sfree(ds); } static void draw_peg(drawing *dr, game_drawstate *ds, int cx, int cy, int moving, int labelled, int col) { /* * Some platforms antialias circles, which means we shouldn't * overwrite a circle of one colour with a circle of another * colour without erasing the background first. However, if the * peg is the one being dragged, we don't erase the background * because we _want_ it to alpha-blend nicely into whatever's * behind it. */ if (!moving) draw_rect(dr, cx-CGAP, cy-CGAP, PEGSZ+CGAP*2, PEGSZ+CGAP*2, COL_BACKGROUND); if (PEGRAD > 0) { draw_circle(dr, cx+PEGRAD, cy+PEGRAD, PEGRAD, COL_EMPTY + col, (col ? COL_FRAME : COL_EMPTY)); } else draw_rect(dr, cx, cy, PEGSZ, PEGSZ, COL_EMPTY + col); if (labelled && col) { char buf[2]; buf[0] = 'a'-1 + col; buf[1] = '\0'; draw_text(dr, cx+PEGRAD, cy+PEGRAD, FONT_VARIABLE, PEGRAD, ALIGN_HCENTRE|ALIGN_VCENTRE, COL_FRAME, buf); } draw_update(dr, cx-CGAP, cy-CGAP, PEGSZ+CGAP*2, PEGSZ+CGAP*2); } static void draw_cursor(drawing *dr, game_drawstate *ds, int x, int y) { draw_circle(dr, x+PEGRAD, y+PEGRAD, PEGRAD+CGAP, -1, COL_CURSOR); draw_update(dr, x-CGAP, y-CGAP, PEGSZ+CGAP*2, PEGSZ+CGAP*2); } static void guess_redraw(drawing *dr, game_drawstate *ds, int guess, pegrow src, int *holds, int cur_col, int force, int labelled) { pegrow dest; int rowx, rowy, i, scol; if (guess == -1) { dest = ds->solution; rowx = SOLN_OX; rowy = SOLN_OY; } else { dest = ds->guesses[guess]; rowx = GUESS_X(guess,0); rowy = GUESS_Y(guess,0); } if (src) assert(src->npegs == dest->npegs); for (i = 0; i < dest->npegs; i++) { scol = src ? src->pegs[i] : 0; if (i == cur_col) scol |= 0x1000; if (holds && holds[i]) scol |= 0x2000; if (labelled) scol |= 0x4000; if ((dest->pegs[i] != scol) || force) { draw_peg(dr, ds, rowx + PEGOFF * i, rowy, FALSE, labelled, scol &~ 0x7000); /* * Hold marker. */ draw_rect(dr, rowx + PEGOFF * i, rowy + PEGSZ + ds->gapsz/2, PEGSZ, 2, (scol & 0x2000 ? COL_HOLD : COL_BACKGROUND)); draw_update(dr, rowx + PEGOFF * i, rowy + PEGSZ + ds->gapsz/2, PEGSZ, 2); if (scol & 0x1000) draw_cursor(dr, ds, rowx + PEGOFF * i, rowy); } dest->pegs[i] = scol; } } static void hint_redraw(drawing *dr, game_drawstate *ds, int guess, pegrow src, int force, int cursor, int markable) { pegrow dest = ds->guesses[guess]; int rowx, rowy, i, scol, col, hintlen; int need_redraw; int emptycol = (markable ? COL_FLASH : COL_EMPTY); if (src) assert(src->npegs == dest->npegs); hintlen = (dest->npegs + 1)/2; /* * Because of the possible presence of the cursor around this * entire section, we redraw all or none of it but never part. */ need_redraw = FALSE; for (i = 0; i < dest->npegs; i++) { scol = src ? src->feedback[i] : 0; if (i == 0 && cursor) scol |= 0x1000; if (i == 0 && markable) scol |= 0x2000; if ((scol != dest->feedback[i]) || force) { need_redraw = TRUE; } dest->feedback[i] = scol; } if (need_redraw) { int hinth = HINTSZ + GAP + HINTSZ; int hx,hy,hw,hh; hx = HINT_X(guess)-GAP; hy = HINT_Y(guess)-GAP; hw = HINT_W+GAP*2; hh = hinth+GAP*2; /* erase a large background rectangle */ draw_rect(dr, hx, hy, hw, hh, COL_BACKGROUND); for (i = 0; i < dest->npegs; i++) { scol = src ? src->feedback[i] : 0; col = ((scol == FEEDBACK_CORRECTPLACE) ? COL_CORRECTPLACE : (scol == FEEDBACK_CORRECTCOLOUR) ? COL_CORRECTCOLOUR : emptycol); rowx = HINT_X(guess); rowy = HINT_Y(guess); if (i < hintlen) { rowx += HINTOFF * i; } else { rowx += HINTOFF * (i - hintlen); rowy += HINTOFF; } if (HINTRAD > 0) { draw_circle(dr, rowx+HINTRAD, rowy+HINTRAD, HINTRAD, col, (col == emptycol ? emptycol : COL_FRAME)); } else { draw_rect(dr, rowx, rowy, HINTSZ, HINTSZ, col); } } if (cursor) { int x1,y1,x2,y2; x1 = hx + CGAP; y1 = hy + CGAP; x2 = hx + hw - CGAP; y2 = hy + hh - CGAP; draw_line(dr, x1, y1, x2, y1, COL_CURSOR); draw_line(dr, x2, y1, x2, y2, COL_CURSOR); draw_line(dr, x2, y2, x1, y2, COL_CURSOR); draw_line(dr, x1, y2, x1, y1, COL_CURSOR); } draw_update(dr, hx, hy, hw, hh); } } static void currmove_redraw(drawing *dr, game_drawstate *ds, int guess, int col) { int ox = GUESS_X(guess, 0), oy = GUESS_Y(guess, 0), off = PEGSZ/4; draw_rect(dr, ox-off-1, oy, 2, PEGSZ, col); draw_update(dr, ox-off-1, oy, 2, PEGSZ); } static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float animtime, float flashtime) { int i, new_move; new_move = (state->next_go != ds->next_go) || !ds->started; if (!ds->started) { draw_rect(dr, 0, 0, ds->w, ds->h, COL_BACKGROUND); draw_rect(dr, SOLN_OX, SOLN_OY - ds->gapsz - 1, SOLN_W, 2, COL_FRAME); draw_update(dr, 0, 0, ds->w, ds->h); } if (ds->drag_col != 0) { debug(("Loading from blitter.")); blitter_load(dr, ds->blit_peg, ds->blit_ox, ds->blit_oy); draw_update(dr, ds->blit_ox, ds->blit_oy, PEGSZ, PEGSZ); } /* draw the colours */ for (i = 0; i < state->params.ncolours; i++) { int val = i+1; if (ui->display_cur && ui->colour_cur == i) val |= 0x1000; if (ui->show_labels) val |= 0x2000; if (ds->colours->pegs[i] != val) { draw_peg(dr, ds, COL_X(i), COL_Y(i), FALSE, ui->show_labels, i+1); if (val & 0x1000) draw_cursor(dr, ds, COL_X(i), COL_Y(i)); ds->colours->pegs[i] = val; } } /* draw the guesses (so far) and the hints * (in reverse order to avoid trampling holds, and postponing the * next_go'th to not overrender the top of the circular cursor) */ for (i = state->params.nguesses - 1; i >= 0; i--) { if (i < state->next_go || state->solved) { /* this info is stored in the game_state already */ guess_redraw(dr, ds, i, state->guesses[i], NULL, -1, 0, ui->show_labels); hint_redraw(dr, ds, i, state->guesses[i], i == (state->next_go-1) ? 1 : 0, FALSE, FALSE); } else if (i > state->next_go) { /* we've not got here yet; it's blank. */ guess_redraw(dr, ds, i, NULL, NULL, -1, 0, ui->show_labels); hint_redraw(dr, ds, i, NULL, 0, FALSE, FALSE); } } if (!state->solved) { /* this is the one we're on; the (incomplete) guess is stored in * the game_ui. */ guess_redraw(dr, ds, state->next_go, ui->curr_pegs, ui->holds, ui->display_cur ? ui->peg_cur : -1, 0, ui->show_labels); hint_redraw(dr, ds, state->next_go, NULL, 1, ui->display_cur && ui->peg_cur == state->params.npegs, ui->markable); } /* draw the 'current move' and 'able to mark' sign. */ if (new_move) currmove_redraw(dr, ds, ds->next_go, COL_BACKGROUND); if (!state->solved) currmove_redraw(dr, ds, state->next_go, COL_HOLD); /* draw the solution (or the big rectangle) */ if ((!state->solved ^ !ds->solved) || !ds->started) { draw_rect(dr, SOLN_OX, SOLN_OY, SOLN_W, SOLN_H, state->solved ? COL_BACKGROUND : COL_EMPTY); draw_update(dr, SOLN_OX, SOLN_OY, SOLN_W, SOLN_H); } if (state->solved) guess_redraw(dr, ds, -1, state->solution, NULL, -1, !ds->solved, ui->show_labels); ds->solved = state->solved; ds->next_go = state->next_go; /* if ui->drag_col != 0, save the screen to the blitter, * draw the peg where we saved, and set ds->drag_* == ui->drag_*. */ if (ui->drag_col != 0) { int ox = ui->drag_x - (PEGSZ/2); int oy = ui->drag_y - (PEGSZ/2); ds->blit_ox = ox - 1; ds->blit_oy = oy - 1; debug(("Saving to blitter at (%d,%d)", ds->blit_ox, ds->blit_oy)); blitter_save(dr, ds->blit_peg, ds->blit_ox, ds->blit_oy); draw_peg(dr, ds, ox, oy, TRUE, ui->show_labels, ui->drag_col); } ds->drag_col = ui->drag_col; ds->started = 1; } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return 0.0F; } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return 0.0F; } static int game_status(const game_state *state) { /* * We return nonzero whenever the solution has been revealed, even * (on spoiler grounds) if it wasn't guessed correctly. The * correct return value from this function is already in * state->solved. */ return state->solved; } static int game_timing_state(const game_state *state, game_ui *ui) { return TRUE; } static void game_print_size(const game_params *params, float *x, float *y) { } static void game_print(drawing *dr, const game_state *state, int tilesize) { } #ifdef COMBINED #define thegame guess #endif const struct game thegame = { "Guess", "games.guess", "guess", default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, TRUE, solve_game, FALSE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, PEG_PREFER_SZ, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, FALSE, FALSE, game_print_size, game_print, FALSE, /* wants_statusbar */ FALSE, game_timing_state, 0, /* flags */ }; /* vim: set shiftwidth=4 tabstop=8: */ puzzles-20170606.272beef/gtk.c0000644000175000017500000027211113115373615014626 0ustar simonsimon/* * gtk.c: GTK front end for my puzzle collection. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "puzzles.h" #if GTK_CHECK_VERSION(2,0,0) # define USE_PANGO # ifdef PANGO_VERSION_CHECK # if PANGO_VERSION_CHECK(1,8,0) # define HAVE_SENSIBLE_ABSOLUTE_SIZE_FUNCTION # endif # endif #endif #if !GTK_CHECK_VERSION(2,4,0) # define OLD_FILESEL #endif #if GTK_CHECK_VERSION(2,8,0) # define USE_CAIRO # if GTK_CHECK_VERSION(3,0,0) || defined(GDK_DISABLE_DEPRECATED) # define USE_CAIRO_WITHOUT_PIXMAP # endif #endif #if GTK_CHECK_VERSION(3,0,0) /* The old names are still more concise! */ #define gtk_hbox_new(x,y) gtk_box_new(GTK_ORIENTATION_HORIZONTAL,y) #define gtk_vbox_new(x,y) gtk_box_new(GTK_ORIENTATION_VERTICAL,y) /* GTK 3 has retired stock button labels */ #define LABEL_OK "_OK" #define LABEL_CANCEL "_Cancel" #define LABEL_NO "_No" #define LABEL_YES "_Yes" #define LABEL_SAVE "_Save" #define LABEL_OPEN "_Open" #define gtk_button_new_with_our_label gtk_button_new_with_mnemonic #else #define LABEL_OK GTK_STOCK_OK #define LABEL_CANCEL GTK_STOCK_CANCEL #define LABEL_NO GTK_STOCK_NO #define LABEL_YES GTK_STOCK_YES #define LABEL_SAVE GTK_STOCK_SAVE #define LABEL_OPEN GTK_STOCK_OPEN #define gtk_button_new_with_our_label gtk_button_new_from_stock #endif /* #undef USE_CAIRO */ /* #define NO_THICK_LINE */ #ifdef DEBUGGING static FILE *debug_fp = NULL; void dputs(char *buf) { if (!debug_fp) { debug_fp = fopen("debug.log", "w"); } fputs(buf, stderr); if (debug_fp) { fputs(buf, debug_fp); fflush(debug_fp); } } void debug_printf(char *fmt, ...) { char buf[4096]; va_list ap; va_start(ap, fmt); vsprintf(buf, fmt, ap); dputs(buf); va_end(ap); } #endif /* ---------------------------------------------------------------------- * Error reporting functions used elsewhere. */ void fatal(char *fmt, ...) { va_list ap; fprintf(stderr, "fatal error: "); va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); fprintf(stderr, "\n"); exit(1); } /* ---------------------------------------------------------------------- * GTK front end to puzzles. */ static void changed_preset(frontend *fe); struct font { #ifdef USE_PANGO PangoFontDescription *desc; #else GdkFont *font; #endif int type; int size; }; /* * This structure holds all the data relevant to a single window. * In principle this would allow us to open multiple independent * puzzle windows, although I can't currently see any real point in * doing so. I'm just coding cleanly because there's no * particularly good reason not to. */ struct frontend { GtkWidget *window; GtkAccelGroup *accelgroup; GtkWidget *area; GtkWidget *statusbar; GtkWidget *menubar; #if GTK_CHECK_VERSION(3,20,0) GtkCssProvider *css_provider; #endif guint statusctx; int w, h; midend *me; #ifdef USE_CAIRO const float *colours; cairo_t *cr; cairo_surface_t *image; #ifndef USE_CAIRO_WITHOUT_PIXMAP GdkPixmap *pixmap; #endif GdkColor background; /* for painting outside puzzle area */ #else GdkPixmap *pixmap; GdkGC *gc; GdkColor *colours; GdkColormap *colmap; int backgroundindex; /* which of colours[] is background */ #endif int ncolours; int bbox_l, bbox_r, bbox_u, bbox_d; int timer_active, timer_id; struct timeval last_time; struct font *fonts; int nfonts, fontsize; config_item *cfg; int cfg_which, cfgret; GtkWidget *cfgbox; void *paste_data; int paste_data_len; int pw, ph; /* pixmap size (w, h are area size) */ int ox, oy; /* offset of pixmap in drawing area */ #ifdef OLD_FILESEL char *filesel_name; #endif GSList *preset_radio; int preset_threaded; GtkWidget *preset_custom; GtkWidget *copy_menu_item; #if !GTK_CHECK_VERSION(3,0,0) int drawing_area_shrink_pending; int menubar_is_local; #endif }; struct blitter { #ifdef USE_CAIRO cairo_surface_t *image; #else GdkPixmap *pixmap; #endif int w, h, x, y; }; void get_random_seed(void **randseed, int *randseedsize) { struct timeval *tvp = snew(struct timeval); gettimeofday(tvp, NULL); *randseed = (void *)tvp; *randseedsize = sizeof(struct timeval); } void frontend_default_colour(frontend *fe, float *output) { #if !GTK_CHECK_VERSION(3,0,0) /* * Use the widget style's default background colour as the * background for the puzzle drawing area. */ GdkColor col = gtk_widget_get_style(fe->window)->bg[GTK_STATE_NORMAL]; output[0] = col.red / 65535.0; output[1] = col.green / 65535.0; output[2] = col.blue / 65535.0; #else /* * GTK 3 has decided that there's no such thing as a 'default * background colour' any more, because widget styles might set * the background to something more complicated like a background * image. We don't want to get into overlaying our entire puzzle * on an arbitrary background image, so we'll just make up a * reasonable shade of grey. */ output[0] = output[1] = output[2] = 0.9F; #endif } void gtk_status_bar(void *handle, char *text) { frontend *fe = (frontend *)handle; assert(fe->statusbar); gtk_statusbar_pop(GTK_STATUSBAR(fe->statusbar), fe->statusctx); gtk_statusbar_push(GTK_STATUSBAR(fe->statusbar), fe->statusctx, text); } /* ---------------------------------------------------------------------- * Cairo drawing functions. */ #ifdef USE_CAIRO static void setup_drawing(frontend *fe) { fe->cr = cairo_create(fe->image); cairo_set_antialias(fe->cr, CAIRO_ANTIALIAS_GRAY); cairo_set_line_width(fe->cr, 1.0); cairo_set_line_cap(fe->cr, CAIRO_LINE_CAP_SQUARE); cairo_set_line_join(fe->cr, CAIRO_LINE_JOIN_ROUND); } static void teardown_drawing(frontend *fe) { cairo_destroy(fe->cr); fe->cr = NULL; #ifndef USE_CAIRO_WITHOUT_PIXMAP { cairo_t *cr = gdk_cairo_create(fe->pixmap); cairo_set_source_surface(cr, fe->image, 0, 0); cairo_rectangle(cr, fe->bbox_l - 1, fe->bbox_u - 1, fe->bbox_r - fe->bbox_l + 2, fe->bbox_d - fe->bbox_u + 2); cairo_fill(cr); cairo_destroy(cr); } #endif } static void snaffle_colours(frontend *fe) { fe->colours = midend_colours(fe->me, &fe->ncolours); } static void set_colour(frontend *fe, int colour) { cairo_set_source_rgb(fe->cr, fe->colours[3*colour + 0], fe->colours[3*colour + 1], fe->colours[3*colour + 2]); } static void set_window_background(frontend *fe, int colour) { #if GTK_CHECK_VERSION(3,20,0) char css_buf[512]; sprintf(css_buf, ".background { " "background-color: #%02x%02x%02x; }", (unsigned)(fe->colours[3*colour + 0] * 255), (unsigned)(fe->colours[3*colour + 1] * 255), (unsigned)(fe->colours[3*colour + 2] * 255)); if (!fe->css_provider) fe->css_provider = gtk_css_provider_new(); if (!gtk_css_provider_load_from_data( GTK_CSS_PROVIDER(fe->css_provider), css_buf, -1, NULL)) assert(0 && "Couldn't load CSS"); gtk_style_context_add_provider( gtk_widget_get_style_context(fe->window), GTK_STYLE_PROVIDER(fe->css_provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); gtk_style_context_add_provider( gtk_widget_get_style_context(fe->area), GTK_STYLE_PROVIDER(fe->css_provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); #elif GTK_CHECK_VERSION(3,0,0) GdkRGBA rgba; rgba.red = fe->colours[3*colour + 0]; rgba.green = fe->colours[3*colour + 1]; rgba.blue = fe->colours[3*colour + 2]; rgba.alpha = 1.0; gdk_window_set_background_rgba(gtk_widget_get_window(fe->area), &rgba); gdk_window_set_background_rgba(gtk_widget_get_window(fe->window), &rgba); #else GdkColormap *colmap; colmap = gdk_colormap_get_system(); fe->background.red = fe->colours[3*colour + 0] * 65535; fe->background.green = fe->colours[3*colour + 1] * 65535; fe->background.blue = fe->colours[3*colour + 2] * 65535; if (!gdk_colormap_alloc_color(colmap, &fe->background, FALSE, FALSE)) { g_error("couldn't allocate background (#%02x%02x%02x)\n", fe->background.red >> 8, fe->background.green >> 8, fe->background.blue >> 8); } gdk_window_set_background(gtk_widget_get_window(fe->area), &fe->background); gdk_window_set_background(gtk_widget_get_window(fe->window), &fe->background); #endif } static PangoLayout *make_pango_layout(frontend *fe) { return (pango_cairo_create_layout(fe->cr)); } static void draw_pango_layout(frontend *fe, PangoLayout *layout, int x, int y) { cairo_move_to(fe->cr, x, y); pango_cairo_show_layout(fe->cr, layout); } static void save_screenshot_png(frontend *fe, const char *screenshot_file) { cairo_surface_write_to_png(fe->image, screenshot_file); } static void do_clip(frontend *fe, int x, int y, int w, int h) { cairo_new_path(fe->cr); cairo_rectangle(fe->cr, x, y, w, h); cairo_clip(fe->cr); } static void do_unclip(frontend *fe) { cairo_reset_clip(fe->cr); } static void do_draw_rect(frontend *fe, int x, int y, int w, int h) { cairo_save(fe->cr); cairo_new_path(fe->cr); cairo_set_antialias(fe->cr, CAIRO_ANTIALIAS_NONE); cairo_rectangle(fe->cr, x, y, w, h); cairo_fill(fe->cr); cairo_restore(fe->cr); } static void do_draw_line(frontend *fe, int x1, int y1, int x2, int y2) { cairo_new_path(fe->cr); cairo_move_to(fe->cr, x1 + 0.5, y1 + 0.5); cairo_line_to(fe->cr, x2 + 0.5, y2 + 0.5); cairo_stroke(fe->cr); } static void do_draw_thick_line(frontend *fe, float thickness, float x1, float y1, float x2, float y2) { cairo_save(fe->cr); cairo_set_line_width(fe->cr, thickness); cairo_new_path(fe->cr); cairo_move_to(fe->cr, x1, y1); cairo_line_to(fe->cr, x2, y2); cairo_stroke(fe->cr); cairo_restore(fe->cr); } static void do_draw_poly(frontend *fe, int *coords, int npoints, int fillcolour, int outlinecolour) { int i; cairo_new_path(fe->cr); for (i = 0; i < npoints; i++) cairo_line_to(fe->cr, coords[i*2] + 0.5, coords[i*2 + 1] + 0.5); cairo_close_path(fe->cr); if (fillcolour >= 0) { set_colour(fe, fillcolour); cairo_fill_preserve(fe->cr); } assert(outlinecolour >= 0); set_colour(fe, outlinecolour); cairo_stroke(fe->cr); } static void do_draw_circle(frontend *fe, int cx, int cy, int radius, int fillcolour, int outlinecolour) { cairo_new_path(fe->cr); cairo_arc(fe->cr, cx + 0.5, cy + 0.5, radius, 0, 2*PI); cairo_close_path(fe->cr); /* Just in case... */ if (fillcolour >= 0) { set_colour(fe, fillcolour); cairo_fill_preserve(fe->cr); } assert(outlinecolour >= 0); set_colour(fe, outlinecolour); cairo_stroke(fe->cr); } static void setup_blitter(blitter *bl, int w, int h) { bl->image = cairo_image_surface_create(CAIRO_FORMAT_RGB24, w, h); } static void teardown_blitter(blitter *bl) { cairo_surface_destroy(bl->image); } static void do_blitter_save(frontend *fe, blitter *bl, int x, int y) { cairo_t *cr = cairo_create(bl->image); cairo_set_source_surface(cr, fe->image, -x, -y); cairo_paint(cr); cairo_destroy(cr); } static void do_blitter_load(frontend *fe, blitter *bl, int x, int y) { cairo_set_source_surface(fe->cr, bl->image, x, y); cairo_paint(fe->cr); } static void clear_backing_store(frontend *fe) { fe->image = NULL; } static void wipe_and_maybe_destroy_cairo(frontend *fe, cairo_t *cr, int destroy) { cairo_set_source_rgb(cr, fe->colours[0], fe->colours[1], fe->colours[2]); cairo_paint(cr); if (destroy) cairo_destroy(cr); } static void setup_backing_store(frontend *fe) { #ifndef USE_CAIRO_WITHOUT_PIXMAP fe->pixmap = gdk_pixmap_new(gtk_widget_get_window(fe->area), fe->pw, fe->ph, -1); #endif fe->image = cairo_image_surface_create(CAIRO_FORMAT_RGB24, fe->pw, fe->ph); wipe_and_maybe_destroy_cairo(fe, cairo_create(fe->image), TRUE); #ifndef USE_CAIRO_WITHOUT_PIXMAP wipe_and_maybe_destroy_cairo(fe, gdk_cairo_create(fe->pixmap), TRUE); #endif #if GTK_CHECK_VERSION(3,22,0) { GdkWindow *gdkwin; cairo_region_t *region; GdkDrawingContext *drawctx; cairo_t *cr; gdkwin = gtk_widget_get_window(fe->area); region = gdk_window_get_clip_region(gdkwin); drawctx = gdk_window_begin_draw_frame(gdkwin, region); cr = gdk_drawing_context_get_cairo_context(drawctx); wipe_and_maybe_destroy_cairo(fe, cr, FALSE); gdk_window_end_draw_frame(gdkwin, drawctx); cairo_region_destroy(region); } #else wipe_and_maybe_destroy_cairo( fe, gdk_cairo_create(gtk_widget_get_window(fe->area)), TRUE); #endif } static int backing_store_ok(frontend *fe) { return (!!fe->image); } static void teardown_backing_store(frontend *fe) { cairo_surface_destroy(fe->image); #ifndef USE_CAIRO_WITHOUT_PIXMAP gdk_pixmap_unref(fe->pixmap); #endif fe->image = NULL; } #endif /* ---------------------------------------------------------------------- * GDK drawing functions. */ #ifndef USE_CAIRO static void setup_drawing(frontend *fe) { fe->gc = gdk_gc_new(fe->area->window); } static void teardown_drawing(frontend *fe) { gdk_gc_unref(fe->gc); fe->gc = NULL; } static void snaffle_colours(frontend *fe) { int i, ncolours; float *colours; gboolean *success; fe->colmap = gdk_colormap_get_system(); colours = midend_colours(fe->me, &ncolours); fe->ncolours = ncolours; fe->colours = snewn(ncolours, GdkColor); for (i = 0; i < ncolours; i++) { fe->colours[i].red = colours[i*3] * 0xFFFF; fe->colours[i].green = colours[i*3+1] * 0xFFFF; fe->colours[i].blue = colours[i*3+2] * 0xFFFF; } success = snewn(ncolours, gboolean); gdk_colormap_alloc_colors(fe->colmap, fe->colours, ncolours, FALSE, FALSE, success); for (i = 0; i < ncolours; i++) { if (!success[i]) { g_error("couldn't allocate colour %d (#%02x%02x%02x)\n", i, fe->colours[i].red >> 8, fe->colours[i].green >> 8, fe->colours[i].blue >> 8); } } } static void set_window_background(frontend *fe, int colour) { fe->backgroundindex = colour; gdk_window_set_background(fe->area->window, &fe->colours[colour]); gdk_window_set_background(fe->window->window, &fe->colours[colour]); } static void set_colour(frontend *fe, int colour) { gdk_gc_set_foreground(fe->gc, &fe->colours[colour]); } #ifdef USE_PANGO static PangoLayout *make_pango_layout(frontend *fe) { return (pango_layout_new(gtk_widget_get_pango_context(fe->area))); } static void draw_pango_layout(frontend *fe, PangoLayout *layout, int x, int y) { gdk_draw_layout(fe->pixmap, fe->gc, x, y, layout); } #endif static void save_screenshot_png(frontend *fe, const char *screenshot_file) { GdkPixbuf *pb; GError *gerror = NULL; midend_redraw(fe->me); pb = gdk_pixbuf_get_from_drawable(NULL, fe->pixmap, NULL, 0, 0, 0, 0, -1, -1); gdk_pixbuf_save(pb, screenshot_file, "png", &gerror, NULL); } static void do_clip(frontend *fe, int x, int y, int w, int h) { GdkRectangle rect; rect.x = x; rect.y = y; rect.width = w; rect.height = h; gdk_gc_set_clip_rectangle(fe->gc, &rect); } static void do_unclip(frontend *fe) { GdkRectangle rect; rect.x = 0; rect.y = 0; rect.width = fe->w; rect.height = fe->h; gdk_gc_set_clip_rectangle(fe->gc, &rect); } static void do_draw_rect(frontend *fe, int x, int y, int w, int h) { gdk_draw_rectangle(fe->pixmap, fe->gc, 1, x, y, w, h); } static void do_draw_line(frontend *fe, int x1, int y1, int x2, int y2) { gdk_draw_line(fe->pixmap, fe->gc, x1, y1, x2, y2); } static void do_draw_thick_line(frontend *fe, float thickness, float x1, float y1, float x2, float y2) { GdkGCValues save; gdk_gc_get_values(fe->gc, &save); gdk_gc_set_line_attributes(fe->gc, thickness, GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_BEVEL); gdk_draw_line(fe->pixmap, fe->gc, x1, y1, x2, y2); gdk_gc_set_line_attributes(fe->gc, save.line_width, save.line_style, save.cap_style, save.join_style); } static void do_draw_poly(frontend *fe, int *coords, int npoints, int fillcolour, int outlinecolour) { GdkPoint *points = snewn(npoints, GdkPoint); int i; for (i = 0; i < npoints; i++) { points[i].x = coords[i*2]; points[i].y = coords[i*2+1]; } if (fillcolour >= 0) { set_colour(fe, fillcolour); gdk_draw_polygon(fe->pixmap, fe->gc, TRUE, points, npoints); } assert(outlinecolour >= 0); set_colour(fe, outlinecolour); /* * In principle we ought to be able to use gdk_draw_polygon for * the outline as well. In fact, it turns out to interact badly * with a clipping region, for no terribly obvious reason, so I * draw the outline as a sequence of lines instead. */ for (i = 0; i < npoints; i++) gdk_draw_line(fe->pixmap, fe->gc, points[i].x, points[i].y, points[(i+1)%npoints].x, points[(i+1)%npoints].y); sfree(points); } static void do_draw_circle(frontend *fe, int cx, int cy, int radius, int fillcolour, int outlinecolour) { if (fillcolour >= 0) { set_colour(fe, fillcolour); gdk_draw_arc(fe->pixmap, fe->gc, TRUE, cx - radius, cy - radius, 2 * radius, 2 * radius, 0, 360 * 64); } assert(outlinecolour >= 0); set_colour(fe, outlinecolour); gdk_draw_arc(fe->pixmap, fe->gc, FALSE, cx - radius, cy - radius, 2 * radius, 2 * radius, 0, 360 * 64); } static void setup_blitter(blitter *bl, int w, int h) { /* * We can't create the pixmap right now, because fe->window * might not yet exist. So we just cache w and h and create it * during the firs call to blitter_save. */ bl->pixmap = NULL; } static void teardown_blitter(blitter *bl) { if (bl->pixmap) gdk_pixmap_unref(bl->pixmap); } static void do_blitter_save(frontend *fe, blitter *bl, int x, int y) { if (!bl->pixmap) bl->pixmap = gdk_pixmap_new(fe->area->window, bl->w, bl->h, -1); gdk_draw_pixmap(bl->pixmap, fe->area->style->fg_gc[GTK_WIDGET_STATE(fe->area)], fe->pixmap, x, y, 0, 0, bl->w, bl->h); } static void do_blitter_load(frontend *fe, blitter *bl, int x, int y) { assert(bl->pixmap); gdk_draw_pixmap(fe->pixmap, fe->area->style->fg_gc[GTK_WIDGET_STATE(fe->area)], bl->pixmap, 0, 0, x, y, bl->w, bl->h); } static void clear_backing_store(frontend *fe) { fe->pixmap = NULL; } static void setup_backing_store(frontend *fe) { GdkGC *gc; fe->pixmap = gdk_pixmap_new(fe->area->window, fe->pw, fe->ph, -1); gc = gdk_gc_new(fe->area->window); gdk_gc_set_foreground(gc, &fe->colours[0]); gdk_draw_rectangle(fe->pixmap, gc, 1, 0, 0, fe->pw, fe->ph); gdk_draw_rectangle(fe->area->window, gc, 1, 0, 0, fe->w, fe->h); gdk_gc_unref(gc); } static int backing_store_ok(frontend *fe) { return (!!fe->pixmap); } static void teardown_backing_store(frontend *fe) { gdk_pixmap_unref(fe->pixmap); fe->pixmap = NULL; } #endif #ifndef USE_CAIRO_WITHOUT_PIXMAP static void repaint_rectangle(frontend *fe, GtkWidget *widget, int x, int y, int w, int h) { GdkGC *gc = gdk_gc_new(gtk_widget_get_window(widget)); #ifdef USE_CAIRO gdk_gc_set_foreground(gc, &fe->background); #else gdk_gc_set_foreground(gc, &fe->colours[fe->backgroundindex]); #endif if (x < fe->ox) { gdk_draw_rectangle(gtk_widget_get_window(widget), gc, TRUE, x, y, fe->ox - x, h); w -= (fe->ox - x); x = fe->ox; } if (y < fe->oy) { gdk_draw_rectangle(gtk_widget_get_window(widget), gc, TRUE, x, y, w, fe->oy - y); h -= (fe->oy - y); y = fe->oy; } if (w > fe->pw) { gdk_draw_rectangle(gtk_widget_get_window(widget), gc, TRUE, x + fe->pw, y, w - fe->pw, h); w = fe->pw; } if (h > fe->ph) { gdk_draw_rectangle(gtk_widget_get_window(widget), gc, TRUE, x, y + fe->ph, w, h - fe->ph); h = fe->ph; } gdk_draw_pixmap(gtk_widget_get_window(widget), gc, fe->pixmap, x - fe->ox, y - fe->oy, x, y, w, h); gdk_gc_unref(gc); } #endif /* ---------------------------------------------------------------------- * Pango font functions. */ #ifdef USE_PANGO static void add_font(frontend *fe, int index, int fonttype, int fontsize) { /* * Use Pango to find the closest match to the requested * font. */ PangoFontDescription *fd; fd = pango_font_description_new(); /* `Monospace' and `Sans' are meta-families guaranteed to exist */ pango_font_description_set_family(fd, fonttype == FONT_FIXED ? "Monospace" : "Sans"); pango_font_description_set_weight(fd, PANGO_WEIGHT_BOLD); /* * I found some online Pango documentation which * described a function called * pango_font_description_set_absolute_size(), which is * _exactly_ what I want here. Unfortunately, none of * my local Pango installations have it (presumably * they're too old), so I'm going to have to hack round * it by figuring out the point size myself. This * limits me to X and probably also breaks in later * Pango installations, so ideally I should add another * CHECK_VERSION type ifdef and use set_absolute_size * where available. All very annoying. */ #ifdef HAVE_SENSIBLE_ABSOLUTE_SIZE_FUNCTION pango_font_description_set_absolute_size(fd, PANGO_SCALE*fontsize); #else { Display *d = GDK_DISPLAY(); int s = DefaultScreen(d); double resolution = (PANGO_SCALE * 72.27 / 25.4) * ((double) DisplayWidthMM(d, s) / DisplayWidth (d, s)); pango_font_description_set_size(fd, resolution * fontsize); } #endif fe->fonts[index].desc = fd; } static void align_and_draw_text(frontend *fe, int index, int align, int x, int y, const char *text) { PangoLayout *layout; PangoRectangle rect; layout = make_pango_layout(fe); /* * Create a layout. */ pango_layout_set_font_description(layout, fe->fonts[index].desc); pango_layout_set_text(layout, text, strlen(text)); pango_layout_get_pixel_extents(layout, NULL, &rect); if (align & ALIGN_VCENTRE) rect.y -= rect.height / 2; else rect.y -= rect.height; if (align & ALIGN_HCENTRE) rect.x -= rect.width / 2; else if (align & ALIGN_HRIGHT) rect.x -= rect.width; draw_pango_layout(fe, layout, rect.x + x, rect.y + y); g_object_unref(layout); } #endif /* ---------------------------------------------------------------------- * Old-fashioned font functions. */ #ifndef USE_PANGO static void add_font(int index, int fonttype, int fontsize) { /* * In GTK 1.2, I don't know of any plausible way to * pick a suitable font, so I'm just going to be * tedious. */ fe->fonts[i].font = gdk_font_load(fonttype == FONT_FIXED ? "fixed" : "variable"); } static void align_and_draw_text(int index, int align, int x, int y, const char *text) { int lb, rb, wid, asc, desc; /* * Measure vertical string extents with respect to the same * string always... */ gdk_string_extents(fe->fonts[i].font, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", &lb, &rb, &wid, &asc, &desc); if (align & ALIGN_VCENTRE) y += asc - (asc+desc)/2; else y += asc; /* * ... but horizontal extents with respect to the provided * string. This means that multiple pieces of text centred * on the same y-coordinate don't have different baselines. */ gdk_string_extents(fe->fonts[i].font, text, &lb, &rb, &wid, &asc, &desc); if (align & ALIGN_HCENTRE) x -= wid / 2; else if (align & ALIGN_HRIGHT) x -= wid; /* * Actually draw the text. */ gdk_draw_string(fe->pixmap, fe->fonts[i].font, fe->gc, x, y, text); } #endif /* ---------------------------------------------------------------------- * The exported drawing functions. */ void gtk_start_draw(void *handle) { frontend *fe = (frontend *)handle; fe->bbox_l = fe->w; fe->bbox_r = 0; fe->bbox_u = fe->h; fe->bbox_d = 0; setup_drawing(fe); } void gtk_clip(void *handle, int x, int y, int w, int h) { frontend *fe = (frontend *)handle; do_clip(fe, x, y, w, h); } void gtk_unclip(void *handle) { frontend *fe = (frontend *)handle; do_unclip(fe); } void gtk_draw_text(void *handle, int x, int y, int fonttype, int fontsize, int align, int colour, char *text) { frontend *fe = (frontend *)handle; int i; /* * Find or create the font. */ for (i = 0; i < fe->nfonts; i++) if (fe->fonts[i].type == fonttype && fe->fonts[i].size == fontsize) break; if (i == fe->nfonts) { if (fe->fontsize <= fe->nfonts) { fe->fontsize = fe->nfonts + 10; fe->fonts = sresize(fe->fonts, fe->fontsize, struct font); } fe->nfonts++; fe->fonts[i].type = fonttype; fe->fonts[i].size = fontsize; add_font(fe, i, fonttype, fontsize); } /* * Do the job. */ set_colour(fe, colour); align_and_draw_text(fe, i, align, x, y, text); } void gtk_draw_rect(void *handle, int x, int y, int w, int h, int colour) { frontend *fe = (frontend *)handle; set_colour(fe, colour); do_draw_rect(fe, x, y, w, h); } void gtk_draw_line(void *handle, int x1, int y1, int x2, int y2, int colour) { frontend *fe = (frontend *)handle; set_colour(fe, colour); do_draw_line(fe, x1, y1, x2, y2); } void gtk_draw_thick_line(void *handle, float thickness, float x1, float y1, float x2, float y2, int colour) { frontend *fe = (frontend *)handle; set_colour(fe, colour); do_draw_thick_line(fe, thickness, x1, y1, x2, y2); } void gtk_draw_poly(void *handle, int *coords, int npoints, int fillcolour, int outlinecolour) { frontend *fe = (frontend *)handle; do_draw_poly(fe, coords, npoints, fillcolour, outlinecolour); } void gtk_draw_circle(void *handle, int cx, int cy, int radius, int fillcolour, int outlinecolour) { frontend *fe = (frontend *)handle; do_draw_circle(fe, cx, cy, radius, fillcolour, outlinecolour); } blitter *gtk_blitter_new(void *handle, int w, int h) { blitter *bl = snew(blitter); setup_blitter(bl, w, h); bl->w = w; bl->h = h; return bl; } void gtk_blitter_free(void *handle, blitter *bl) { teardown_blitter(bl); sfree(bl); } void gtk_blitter_save(void *handle, blitter *bl, int x, int y) { frontend *fe = (frontend *)handle; do_blitter_save(fe, bl, x, y); bl->x = x; bl->y = y; } void gtk_blitter_load(void *handle, blitter *bl, int x, int y) { frontend *fe = (frontend *)handle; if (x == BLITTER_FROMSAVED && y == BLITTER_FROMSAVED) { x = bl->x; y = bl->y; } do_blitter_load(fe, bl, x, y); } void gtk_draw_update(void *handle, int x, int y, int w, int h) { frontend *fe = (frontend *)handle; if (fe->bbox_l > x ) fe->bbox_l = x ; if (fe->bbox_r < x+w) fe->bbox_r = x+w; if (fe->bbox_u > y ) fe->bbox_u = y ; if (fe->bbox_d < y+h) fe->bbox_d = y+h; } void gtk_end_draw(void *handle) { frontend *fe = (frontend *)handle; teardown_drawing(fe); if (fe->bbox_l < fe->bbox_r && fe->bbox_u < fe->bbox_d) { #ifdef USE_CAIRO_WITHOUT_PIXMAP gtk_widget_queue_draw_area(fe->area, fe->bbox_l - 1 + fe->ox, fe->bbox_u - 1 + fe->oy, fe->bbox_r - fe->bbox_l + 2, fe->bbox_d - fe->bbox_u + 2); #else repaint_rectangle(fe, fe->area, fe->bbox_l - 1 + fe->ox, fe->bbox_u - 1 + fe->oy, fe->bbox_r - fe->bbox_l + 2, fe->bbox_d - fe->bbox_u + 2); #endif } } #ifdef USE_PANGO char *gtk_text_fallback(void *handle, const char *const *strings, int nstrings) { /* * We assume Pango can cope with any UTF-8 likely to be emitted * by a puzzle. */ return dupstr(strings[0]); } #endif const struct drawing_api gtk_drawing = { gtk_draw_text, gtk_draw_rect, gtk_draw_line, gtk_draw_poly, gtk_draw_circle, gtk_draw_update, gtk_clip, gtk_unclip, gtk_start_draw, gtk_end_draw, gtk_status_bar, gtk_blitter_new, gtk_blitter_free, gtk_blitter_save, gtk_blitter_load, NULL, NULL, NULL, NULL, NULL, NULL, /* {begin,end}_{doc,page,puzzle} */ NULL, NULL, /* line_width, line_dotted */ #ifdef USE_PANGO gtk_text_fallback, #else NULL, #endif #ifdef NO_THICK_LINE NULL, #else gtk_draw_thick_line, #endif }; static void destroy(GtkWidget *widget, gpointer data) { frontend *fe = (frontend *)data; deactivate_timer(fe); midend_free(fe->me); gtk_main_quit(); } static gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) { frontend *fe = (frontend *)data; int keyval; int shift = (event->state & GDK_SHIFT_MASK) ? MOD_SHFT : 0; int ctrl = (event->state & GDK_CONTROL_MASK) ? MOD_CTRL : 0; if (!backing_store_ok(fe)) return TRUE; #if !GTK_CHECK_VERSION(2,0,0) /* Gtk 1.2 passes a key event to this function even if it's also * defined as an accelerator. * Gtk 2 doesn't do this, and this function appears not to exist there. */ if (fe->accelgroup && gtk_accel_group_get_entry(fe->accelgroup, event->keyval, event->state)) return TRUE; #endif /* Handle mnemonics. */ if (gtk_window_activate_key(GTK_WINDOW(fe->window), event)) return TRUE; if (event->keyval == GDK_KEY_Up) keyval = shift | ctrl | CURSOR_UP; else if (event->keyval == GDK_KEY_KP_Up || event->keyval == GDK_KEY_KP_8) keyval = MOD_NUM_KEYPAD | '8'; else if (event->keyval == GDK_KEY_Down) keyval = shift | ctrl | CURSOR_DOWN; else if (event->keyval == GDK_KEY_KP_Down || event->keyval == GDK_KEY_KP_2) keyval = MOD_NUM_KEYPAD | '2'; else if (event->keyval == GDK_KEY_Left) keyval = shift | ctrl | CURSOR_LEFT; else if (event->keyval == GDK_KEY_KP_Left || event->keyval == GDK_KEY_KP_4) keyval = MOD_NUM_KEYPAD | '4'; else if (event->keyval == GDK_KEY_Right) keyval = shift | ctrl | CURSOR_RIGHT; else if (event->keyval == GDK_KEY_KP_Right || event->keyval == GDK_KEY_KP_6) keyval = MOD_NUM_KEYPAD | '6'; else if (event->keyval == GDK_KEY_KP_Home || event->keyval == GDK_KEY_KP_7) keyval = MOD_NUM_KEYPAD | '7'; else if (event->keyval == GDK_KEY_KP_End || event->keyval == GDK_KEY_KP_1) keyval = MOD_NUM_KEYPAD | '1'; else if (event->keyval == GDK_KEY_KP_Page_Up || event->keyval == GDK_KEY_KP_9) keyval = MOD_NUM_KEYPAD | '9'; else if (event->keyval == GDK_KEY_KP_Page_Down || event->keyval == GDK_KEY_KP_3) keyval = MOD_NUM_KEYPAD | '3'; else if (event->keyval == GDK_KEY_KP_Insert || event->keyval == GDK_KEY_KP_0) keyval = MOD_NUM_KEYPAD | '0'; else if (event->keyval == GDK_KEY_KP_Begin || event->keyval == GDK_KEY_KP_5) keyval = MOD_NUM_KEYPAD | '5'; else if (event->keyval == GDK_KEY_BackSpace || event->keyval == GDK_KEY_Delete || event->keyval == GDK_KEY_KP_Delete) keyval = '\177'; else if (event->string[0] && !event->string[1]) keyval = (unsigned char)event->string[0]; else keyval = -1; if (keyval >= 0 && !midend_process_key(fe->me, 0, 0, keyval)) gtk_widget_destroy(fe->window); return TRUE; } static gint button_event(GtkWidget *widget, GdkEventButton *event, gpointer data) { frontend *fe = (frontend *)data; int button; if (!backing_store_ok(fe)) return TRUE; if (event->type != GDK_BUTTON_PRESS && event->type != GDK_BUTTON_RELEASE) return TRUE; if (event->button == 2 || (event->state & GDK_SHIFT_MASK)) button = MIDDLE_BUTTON; else if (event->button == 3 || (event->state & GDK_MOD1_MASK)) button = RIGHT_BUTTON; else if (event->button == 1) button = LEFT_BUTTON; else if (event->button == 8 && event->type == GDK_BUTTON_PRESS) button = 'u'; else if (event->button == 9 && event->type == GDK_BUTTON_PRESS) button = 'r'; else return FALSE; /* don't even know what button! */ if (event->type == GDK_BUTTON_RELEASE && button >= LEFT_BUTTON) button += LEFT_RELEASE - LEFT_BUTTON; if (!midend_process_key(fe->me, event->x - fe->ox, event->y - fe->oy, button)) gtk_widget_destroy(fe->window); return TRUE; } static gint motion_event(GtkWidget *widget, GdkEventMotion *event, gpointer data) { frontend *fe = (frontend *)data; int button; if (!backing_store_ok(fe)) return TRUE; if (event->state & (GDK_BUTTON2_MASK | GDK_SHIFT_MASK)) button = MIDDLE_DRAG; else if (event->state & GDK_BUTTON1_MASK) button = LEFT_DRAG; else if (event->state & GDK_BUTTON3_MASK) button = RIGHT_DRAG; else return FALSE; /* don't even know what button! */ if (!midend_process_key(fe->me, event->x - fe->ox, event->y - fe->oy, button)) gtk_widget_destroy(fe->window); #if GTK_CHECK_VERSION(2,12,0) gdk_event_request_motions(event); #else gdk_window_get_pointer(gtk_widget_get_window(widget), NULL, NULL, NULL); #endif return TRUE; } #if GTK_CHECK_VERSION(3,0,0) static gint draw_area(GtkWidget *widget, cairo_t *cr, gpointer data) { frontend *fe = (frontend *)data; GdkRectangle dirtyrect; gdk_cairo_get_clip_rectangle(cr, &dirtyrect); cairo_set_source_surface(cr, fe->image, fe->ox, fe->oy); cairo_rectangle(cr, dirtyrect.x, dirtyrect.y, dirtyrect.width, dirtyrect.height); cairo_fill(cr); return TRUE; } #else static gint expose_area(GtkWidget *widget, GdkEventExpose *event, gpointer data) { frontend *fe = (frontend *)data; if (backing_store_ok(fe)) { #ifdef USE_CAIRO_WITHOUT_PIXMAP cairo_t *cr = gdk_cairo_create(gtk_widget_get_window(widget)); cairo_set_source_surface(cr, fe->image, fe->ox, fe->oy); cairo_rectangle(cr, event->area.x, event->area.y, event->area.width, event->area.height); cairo_fill(cr); cairo_destroy(cr); #else repaint_rectangle(fe, widget, event->area.x, event->area.y, event->area.width, event->area.height); #endif } return TRUE; } #endif static gint map_window(GtkWidget *widget, GdkEvent *event, gpointer data) { frontend *fe = (frontend *)data; /* * Apparently we need to do this because otherwise the status * bar will fail to update immediately. Annoying, but there we * go. */ gtk_widget_queue_draw(fe->window); return TRUE; } static gint configure_area(GtkWidget *widget, GdkEventConfigure *event, gpointer data) { frontend *fe = (frontend *)data; int x, y; int oldw = fe->w, oldpw = fe->pw, oldh = fe->h, oldph = fe->ph; x = event->width; y = event->height; fe->w = x; fe->h = y; midend_size(fe->me, &x, &y, TRUE); fe->pw = x; fe->ph = y; fe->ox = (fe->w - fe->pw) / 2; fe->oy = (fe->h - fe->ph) / 2; if (oldw != fe->w || oldpw != fe->pw || oldh != fe->h || oldph != fe->ph || !backing_store_ok(fe)) { if (backing_store_ok(fe)) teardown_backing_store(fe); setup_backing_store(fe); } midend_force_redraw(fe->me); return TRUE; } static gint timer_func(gpointer data) { frontend *fe = (frontend *)data; if (fe->timer_active) { struct timeval now; float elapsed; gettimeofday(&now, NULL); elapsed = ((now.tv_usec - fe->last_time.tv_usec) * 0.000001F + (now.tv_sec - fe->last_time.tv_sec)); midend_timer(fe->me, elapsed); /* may clear timer_active */ fe->last_time = now; } return fe->timer_active; } void deactivate_timer(frontend *fe) { if (!fe) return; /* can happen due to --generate */ if (fe->timer_active) g_source_remove(fe->timer_id); fe->timer_active = FALSE; } void activate_timer(frontend *fe) { if (!fe) return; /* can happen due to --generate */ if (!fe->timer_active) { fe->timer_id = g_timeout_add(20, timer_func, fe); gettimeofday(&fe->last_time, NULL); } fe->timer_active = TRUE; } static void window_destroy(GtkWidget *widget, gpointer data) { gtk_main_quit(); } static int win_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data) { GObject *cancelbutton = G_OBJECT(data); /* * `Escape' effectively clicks the cancel button */ if (event->keyval == GDK_KEY_Escape) { g_signal_emit_by_name(cancelbutton, "clicked"); return TRUE; } return FALSE; } enum { MB_OK, MB_YESNO }; static void align_label(GtkLabel *label, double x, double y) { #if GTK_CHECK_VERSION(3,16,0) gtk_label_set_xalign(label, x); gtk_label_set_yalign(label, y); #elif GTK_CHECK_VERSION(3,14,0) gtk_widget_set_halign(GTK_WIDGET(label), x == 0 ? GTK_ALIGN_START : x == 1 ? GTK_ALIGN_END : GTK_ALIGN_CENTER); gtk_widget_set_valign(GTK_WIDGET(label), y == 0 ? GTK_ALIGN_START : y == 1 ? GTK_ALIGN_END : GTK_ALIGN_CENTER); #else gtk_misc_set_alignment(GTK_MISC(label), x, y); #endif } #if GTK_CHECK_VERSION(3,0,0) int message_box(GtkWidget *parent, char *title, char *msg, int centre, int type) { GtkWidget *window; gint ret; window = gtk_message_dialog_new (GTK_WINDOW(parent), (GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT), (type == MB_OK ? GTK_MESSAGE_INFO : GTK_MESSAGE_QUESTION), (type == MB_OK ? GTK_BUTTONS_OK : GTK_BUTTONS_YES_NO), "%s", msg); gtk_window_set_title(GTK_WINDOW(window), title); ret = gtk_dialog_run(GTK_DIALOG(window)); gtk_widget_destroy(window); return (type == MB_OK ? TRUE : (ret == GTK_RESPONSE_YES)); } #else /* GTK_CHECK_VERSION(3,0,0) */ static void msgbox_button_clicked(GtkButton *button, gpointer data) { GtkWidget *window = GTK_WIDGET(data); int v, *ip; ip = (int *)g_object_get_data(G_OBJECT(window), "user-data"); v = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(button), "user-data")); *ip = v; gtk_widget_destroy(GTK_WIDGET(data)); } int message_box(GtkWidget *parent, char *title, char *msg, int centre, int type) { GtkWidget *window, *hbox, *text, *button; char *titles; int i, def, cancel; window = gtk_dialog_new(); text = gtk_label_new(msg); align_label(GTK_LABEL(text), 0.0, 0.0); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), text, FALSE, FALSE, 20); gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(window))), hbox, FALSE, FALSE, 20); gtk_widget_show(text); gtk_widget_show(hbox); gtk_window_set_title(GTK_WINDOW(window), title); gtk_label_set_line_wrap(GTK_LABEL(text), TRUE); if (type == MB_OK) { titles = LABEL_OK "\0"; def = cancel = 0; } else { assert(type == MB_YESNO); titles = LABEL_NO "\0" LABEL_YES "\0"; def = 1; cancel = 0; } i = 0; while (*titles) { button = gtk_button_new_with_our_label(titles); gtk_box_pack_end (GTK_BOX(gtk_dialog_get_action_area(GTK_DIALOG(window))), button, FALSE, FALSE, 0); gtk_widget_show(button); if (i == def) { gtk_widget_set_can_default(button, TRUE); gtk_window_set_default(GTK_WINDOW(window), button); } if (i == cancel) { g_signal_connect(G_OBJECT(window), "key_press_event", G_CALLBACK(win_key_press), button); } g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(msgbox_button_clicked), window); g_object_set_data(G_OBJECT(button), "user-data", GINT_TO_POINTER(i)); titles += strlen(titles)+1; i++; } g_object_set_data(G_OBJECT(window), "user-data", &i); g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(window_destroy), NULL); gtk_window_set_modal(GTK_WINDOW(window), TRUE); gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(parent)); /* set_transient_window_pos(parent, window); */ gtk_widget_show(window); i = -1; gtk_main(); return (type == MB_YESNO ? i == 1 : TRUE); } #endif /* GTK_CHECK_VERSION(3,0,0) */ void error_box(GtkWidget *parent, char *msg) { message_box(parent, "Error", msg, FALSE, MB_OK); } static void config_ok_button_clicked(GtkButton *button, gpointer data) { frontend *fe = (frontend *)data; char *err; err = midend_set_config(fe->me, fe->cfg_which, fe->cfg); if (err) error_box(fe->cfgbox, err); else { fe->cfgret = TRUE; gtk_widget_destroy(fe->cfgbox); changed_preset(fe); } } static void config_cancel_button_clicked(GtkButton *button, gpointer data) { frontend *fe = (frontend *)data; gtk_widget_destroy(fe->cfgbox); } static int editbox_key(GtkWidget *widget, GdkEventKey *event, gpointer data) { /* * GtkEntry has a nasty habit of eating the Return key, which * is unhelpful since it doesn't actually _do_ anything with it * (it calls gtk_widget_activate, but our edit boxes never need * activating). So I catch Return before GtkEntry sees it, and * pass it straight on to the parent widget. Effect: hitting * Return in an edit box will now activate the default button * in the dialog just like it will everywhere else. */ if (event->keyval == GDK_KEY_Return && gtk_widget_get_parent(widget) != NULL) { gint return_val; g_signal_stop_emission_by_name(G_OBJECT(widget), "key_press_event"); g_signal_emit_by_name(G_OBJECT(gtk_widget_get_parent(widget)), "key_press_event", event, &return_val); return return_val; } return FALSE; } static void editbox_changed(GtkEditable *ed, gpointer data) { config_item *i = (config_item *)data; sfree(i->sval); i->sval = dupstr(gtk_entry_get_text(GTK_ENTRY(ed))); } static void button_toggled(GtkToggleButton *tb, gpointer data) { config_item *i = (config_item *)data; i->ival = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tb)); } static void droplist_sel(GtkComboBox *combo, gpointer data) { config_item *i = (config_item *)data; i->ival = gtk_combo_box_get_active(combo); } static int get_config(frontend *fe, int which) { GtkWidget *w, *table, *cancel; GtkBox *content_box, *button_box; char *title; config_item *i; int y; fe->cfg = midend_get_config(fe->me, which, &title); fe->cfg_which = which; fe->cfgret = FALSE; #if GTK_CHECK_VERSION(3,0,0) /* GtkDialog isn't quite flexible enough */ fe->cfgbox = gtk_window_new(GTK_WINDOW_TOPLEVEL); content_box = GTK_BOX(gtk_vbox_new(FALSE, 8)); g_object_set(G_OBJECT(content_box), "margin", 8, (const char *)NULL); gtk_widget_show(GTK_WIDGET(content_box)); gtk_container_add(GTK_CONTAINER(fe->cfgbox), GTK_WIDGET(content_box)); button_box = GTK_BOX(gtk_hbox_new(FALSE, 8)); gtk_widget_show(GTK_WIDGET(button_box)); gtk_box_pack_end(content_box, GTK_WIDGET(button_box), FALSE, FALSE, 0); { GtkWidget *sep = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL); gtk_widget_show(sep); gtk_box_pack_end(content_box, sep, FALSE, FALSE, 0); } #else fe->cfgbox = gtk_dialog_new(); content_box = GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(fe->cfgbox))); button_box = GTK_BOX(gtk_dialog_get_action_area(GTK_DIALOG(fe->cfgbox))); #endif gtk_window_set_title(GTK_WINDOW(fe->cfgbox), title); sfree(title); w = gtk_button_new_with_our_label(LABEL_CANCEL); gtk_box_pack_end(button_box, w, FALSE, FALSE, 0); gtk_widget_show(w); g_signal_connect(G_OBJECT(w), "clicked", G_CALLBACK(config_cancel_button_clicked), fe); cancel = w; w = gtk_button_new_with_our_label(LABEL_OK); gtk_box_pack_end(button_box, w, FALSE, FALSE, 0); gtk_widget_show(w); gtk_widget_set_can_default(w, TRUE); gtk_window_set_default(GTK_WINDOW(fe->cfgbox), w); g_signal_connect(G_OBJECT(w), "clicked", G_CALLBACK(config_ok_button_clicked), fe); #if GTK_CHECK_VERSION(3,0,0) table = gtk_grid_new(); #else table = gtk_table_new(1, 2, FALSE); #endif y = 0; gtk_box_pack_start(content_box, table, FALSE, FALSE, 0); gtk_widget_show(table); for (i = fe->cfg; i->type != C_END; i++) { #if !GTK_CHECK_VERSION(3,0,0) gtk_table_resize(GTK_TABLE(table), y+1, 2); #endif switch (i->type) { case C_STRING: /* * Edit box with a label beside it. */ w = gtk_label_new(i->name); align_label(GTK_LABEL(w), 0.0, 0.5); #if GTK_CHECK_VERSION(3,0,0) gtk_grid_attach(GTK_GRID(table), w, 0, y, 1, 1); #else gtk_table_attach(GTK_TABLE(table), w, 0, 1, y, y+1, GTK_SHRINK | GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 3, 3); #endif gtk_widget_show(w); w = gtk_entry_new(); #if GTK_CHECK_VERSION(3,0,0) gtk_grid_attach(GTK_GRID(table), w, 1, y, 1, 1); g_object_set(G_OBJECT(w), "hexpand", TRUE, (const char *)NULL); #else gtk_table_attach(GTK_TABLE(table), w, 1, 2, y, y+1, GTK_EXPAND | GTK_SHRINK | GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 3, 3); #endif gtk_entry_set_text(GTK_ENTRY(w), i->sval); g_signal_connect(G_OBJECT(w), "changed", G_CALLBACK(editbox_changed), i); g_signal_connect(G_OBJECT(w), "key_press_event", G_CALLBACK(editbox_key), NULL); gtk_widget_show(w); break; case C_BOOLEAN: /* * Simple checkbox. */ w = gtk_check_button_new_with_label(i->name); g_signal_connect(G_OBJECT(w), "toggled", G_CALLBACK(button_toggled), i); #if GTK_CHECK_VERSION(3,0,0) gtk_grid_attach(GTK_GRID(table), w, 0, y, 2, 1); g_object_set(G_OBJECT(w), "hexpand", TRUE, (const char *)NULL); #else gtk_table_attach(GTK_TABLE(table), w, 0, 2, y, y+1, GTK_EXPAND | GTK_SHRINK | GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 3, 3); #endif gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), i->ival); gtk_widget_show(w); break; case C_CHOICES: /* * Drop-down list (GtkComboBox). */ w = gtk_label_new(i->name); align_label(GTK_LABEL(w), 0.0, 0.5); #if GTK_CHECK_VERSION(3,0,0) gtk_grid_attach(GTK_GRID(table), w, 0, y, 1, 1); #else gtk_table_attach(GTK_TABLE(table), w, 0, 1, y, y+1, GTK_SHRINK | GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL , 3, 3); #endif gtk_widget_show(w); { int c; char *p, *q, *name; GtkListStore *model; GtkCellRenderer *cr; GtkTreeIter iter; model = gtk_list_store_new(1, G_TYPE_STRING); c = *i->sval; p = i->sval+1; while (*p) { q = p; while (*q && *q != c) q++; name = snewn(q-p+1, char); strncpy(name, p, q-p); name[q-p] = '\0'; if (*q) q++; /* eat delimiter */ gtk_list_store_append(model, &iter); gtk_list_store_set(model, &iter, 0, name, -1); p = q; } w = gtk_combo_box_new_with_model(GTK_TREE_MODEL(model)); gtk_combo_box_set_active(GTK_COMBO_BOX(w), i->ival); cr = gtk_cell_renderer_text_new(); gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(w), cr, TRUE); gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(w), cr, "text", 0, NULL); g_signal_connect(G_OBJECT(w), "changed", G_CALLBACK(droplist_sel), i); } #if GTK_CHECK_VERSION(3,0,0) gtk_grid_attach(GTK_GRID(table), w, 1, y, 1, 1); g_object_set(G_OBJECT(w), "hexpand", TRUE, (const char *)NULL); #else gtk_table_attach(GTK_TABLE(table), w, 1, 2, y, y+1, GTK_EXPAND | GTK_SHRINK | GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 3, 3); #endif gtk_widget_show(w); break; } y++; } g_signal_connect(G_OBJECT(fe->cfgbox), "destroy", G_CALLBACK(window_destroy), NULL); g_signal_connect(G_OBJECT(fe->cfgbox), "key_press_event", G_CALLBACK(win_key_press), cancel); gtk_window_set_modal(GTK_WINDOW(fe->cfgbox), TRUE); gtk_window_set_transient_for(GTK_WINDOW(fe->cfgbox), GTK_WINDOW(fe->window)); /* set_transient_window_pos(fe->window, fe->cfgbox); */ gtk_widget_show(fe->cfgbox); gtk_main(); free_cfg(fe->cfg); return fe->cfgret; } static void menu_key_event(GtkMenuItem *menuitem, gpointer data) { frontend *fe = (frontend *)data; int key = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menuitem), "user-data")); if (!midend_process_key(fe->me, 0, 0, key)) gtk_widget_destroy(fe->window); } static void get_size(frontend *fe, int *px, int *py) { int x, y; /* * Currently I don't want to make the GTK port scale large * puzzles to fit on the screen. This is because X does permit * extremely large windows and many window managers provide a * means of navigating round them, and the users I consulted * before deciding said that they'd rather have enormous puzzle * windows spanning multiple screen pages than have them * shrunk. I could change my mind later or introduce * configurability; this would be the place to do so, by * replacing the initial values of x and y with the screen * dimensions. */ x = INT_MAX; y = INT_MAX; midend_size(fe->me, &x, &y, FALSE); *px = x; *py = y; } #if !GTK_CHECK_VERSION(2,0,0) #define gtk_window_resize(win, x, y) \ gdk_window_resize(GTK_WIDGET(win)->window, x, y) #endif /* * Called when any other code in this file has changed the * selected game parameters. */ static void changed_preset(frontend *fe) { int n = midend_which_preset(fe->me); fe->preset_threaded = TRUE; if (n < 0 && fe->preset_custom) { gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM(fe->preset_custom), TRUE); } else { GSList *gs = fe->preset_radio; GSList *found = NULL; for (gs = fe->preset_radio; gs; gs = gs->next) { struct preset_menu_entry *entry = (struct preset_menu_entry *)g_object_get_data( G_OBJECT(gs->data), "user-data"); if (entry && entry->id != n) gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM(gs->data), FALSE); else found = gs; } if (found) gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM(found->data), FALSE); } fe->preset_threaded = FALSE; /* * Update the greying on the Copy menu option. */ if (fe->copy_menu_item) { int enabled = midend_can_format_as_text_now(fe->me); gtk_widget_set_sensitive(fe->copy_menu_item, enabled); } } #if !GTK_CHECK_VERSION(3,0,0) static gboolean not_size_allocated_yet(GtkWidget *w) { /* * This function tests whether a widget has not yet taken up space * on the screen which it will occupy in future. (Therefore, it * returns true only if the widget does exist but does not have a * size allocation. A null widget is already taking up all the * space it ever will.) */ if (!w) return FALSE; /* nonexistent widgets aren't a problem */ #if GTK_CHECK_VERSION(2,18,0) /* skip if no gtk_widget_get_allocation */ { GtkAllocation a; gtk_widget_get_allocation(w, &a); if (a.height == 0 || a.width == 0) return TRUE; /* widget exists but has no size yet */ } #endif return FALSE; } static void try_shrink_drawing_area(frontend *fe) { if (fe->drawing_area_shrink_pending && (!fe->menubar_is_local || !not_size_allocated_yet(fe->menubar)) && !not_size_allocated_yet(fe->statusbar)) { /* * In order to permit the user to resize the window smaller as * well as bigger, we call this function after the window size * has ended up where we want it. This shouldn't shrink the * window immediately; it just arranges that the next time the * user tries to shrink it, they can. * * However, at puzzle creation time, we defer the first of * these operations until after the menu bar and status bar * are actually visible. On Ubuntu 12.04 I've found that these * can take a while to be displayed, and that it's a mistake * to reduce the drawing area's size allocation before they've * turned up or else the drawing area makes room for them by * shrinking to less than the size we intended. */ gtk_drawing_area_size(GTK_DRAWING_AREA(fe->area), 1, 1); fe->drawing_area_shrink_pending = FALSE; } } #endif /* !GTK_CHECK_VERSION(3,0,0) */ static gint configure_window(GtkWidget *widget, GdkEventConfigure *event, gpointer data) { #if !GTK_CHECK_VERSION(3,0,0) /* * When the main puzzle window changes size, it might be because * the menu bar or status bar has turned up after starting off * absent, in which case we should have another go at enacting a * pending shrink of the drawing area. */ frontend *fe = (frontend *)data; try_shrink_drawing_area(fe); #endif return FALSE; } #if GTK_CHECK_VERSION(3,0,0) static int window_extra_height(frontend *fe) { int ret = 0; if (fe->menubar) { GtkRequisition req; gtk_widget_get_preferred_size(fe->menubar, &req, NULL); ret += req.height; } if (fe->statusbar) { GtkRequisition req; gtk_widget_get_preferred_size(fe->statusbar, &req, NULL); ret += req.height; } return ret; } #endif static void resize_fe(frontend *fe) { int x, y; get_size(fe, &x, &y); #if GTK_CHECK_VERSION(3,0,0) gtk_window_resize(GTK_WINDOW(fe->window), x, y + window_extra_height(fe)); #else fe->drawing_area_shrink_pending = FALSE; gtk_drawing_area_size(GTK_DRAWING_AREA(fe->area), x, y); { GtkRequisition req; gtk_widget_size_request(GTK_WIDGET(fe->window), &req); gtk_window_resize(GTK_WINDOW(fe->window), req.width, req.height); } fe->drawing_area_shrink_pending = TRUE; try_shrink_drawing_area(fe); #endif } static void menu_preset_event(GtkMenuItem *menuitem, gpointer data) { frontend *fe = (frontend *)data; struct preset_menu_entry *entry = (struct preset_menu_entry *)g_object_get_data( G_OBJECT(menuitem), "user-data"); if (fe->preset_threaded || (GTK_IS_CHECK_MENU_ITEM(menuitem) && !gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem)))) return; midend_set_params(fe->me, entry->params); midend_new_game(fe->me); changed_preset(fe); resize_fe(fe); midend_redraw(fe->me); } GdkAtom compound_text_atom, utf8_string_atom; int paste_initialised = FALSE; static void set_selection(frontend *fe, GdkAtom selection) { if (!paste_initialised) { compound_text_atom = gdk_atom_intern("COMPOUND_TEXT", FALSE); utf8_string_atom = gdk_atom_intern("UTF8_STRING", FALSE); paste_initialised = TRUE; } /* * For this simple application we can safely assume that the * data passed to this function is pure ASCII, which means we * can return precisely the same stuff for types STRING, * COMPOUND_TEXT or UTF8_STRING. */ if (gtk_selection_owner_set(fe->area, selection, CurrentTime)) { gtk_selection_clear_targets(fe->area, selection); gtk_selection_add_target(fe->area, selection, GDK_SELECTION_TYPE_STRING, 1); gtk_selection_add_target(fe->area, selection, compound_text_atom, 1); gtk_selection_add_target(fe->area, selection, utf8_string_atom, 1); } } void write_clip(frontend *fe, char *data) { if (fe->paste_data) sfree(fe->paste_data); fe->paste_data = data; fe->paste_data_len = strlen(data); set_selection(fe, GDK_SELECTION_PRIMARY); set_selection(fe, GDK_SELECTION_CLIPBOARD); } void selection_get(GtkWidget *widget, GtkSelectionData *seldata, guint info, guint time_stamp, gpointer data) { frontend *fe = (frontend *)data; gtk_selection_data_set(seldata, gtk_selection_data_get_target(seldata), 8, fe->paste_data, fe->paste_data_len); } gint selection_clear(GtkWidget *widget, GdkEventSelection *seldata, gpointer data) { frontend *fe = (frontend *)data; if (fe->paste_data) sfree(fe->paste_data); fe->paste_data = NULL; fe->paste_data_len = 0; return TRUE; } static void menu_copy_event(GtkMenuItem *menuitem, gpointer data) { frontend *fe = (frontend *)data; char *text; text = midend_text_format(fe->me); if (text) { write_clip(fe, text); } else { gdk_beep(); } } #ifdef OLD_FILESEL static void filesel_ok(GtkButton *button, gpointer data) { frontend *fe = (frontend *)data; gpointer filesel = g_object_get_data(G_OBJECT(button), "user-data"); const char *name = gtk_file_selection_get_filename(GTK_FILE_SELECTION(filesel)); fe->filesel_name = dupstr(name); } static char *file_selector(frontend *fe, char *title, int save) { GtkWidget *filesel = gtk_file_selection_new(title); fe->filesel_name = NULL; gtk_window_set_modal(GTK_WINDOW(filesel), TRUE); g_object_set_data (G_OBJECT(GTK_FILE_SELECTION(filesel)->ok_button), "user-data", (gpointer)filesel); g_signal_connect (G_OBJECT(GTK_FILE_SELECTION(filesel)->ok_button), "clicked", G_CALLBACK(filesel_ok), fe); g_signal_connect_swapped (G_OBJECT(GTK_FILE_SELECTION(filesel)->ok_button), "clicked", G_CALLBACK(gtk_widget_destroy), (gpointer)filesel); g_signal_connect_object (G_OBJECT(GTK_FILE_SELECTION(filesel)->cancel_button), "clicked", G_CALLBACK(gtk_widget_destroy), (gpointer)filesel); g_signal_connect(G_OBJECT(filesel), "destroy", G_CALLBACK(window_destroy), NULL); gtk_widget_show(filesel); gtk_window_set_transient_for(GTK_WINDOW(filesel), GTK_WINDOW(fe->window)); gtk_main(); return fe->filesel_name; } #else static char *file_selector(frontend *fe, char *title, int save) { char *filesel_name = NULL; GtkWidget *filesel = gtk_file_chooser_dialog_new(title, GTK_WINDOW(fe->window), save ? GTK_FILE_CHOOSER_ACTION_SAVE : GTK_FILE_CHOOSER_ACTION_OPEN, LABEL_CANCEL, GTK_RESPONSE_CANCEL, save ? LABEL_SAVE : LABEL_OPEN, GTK_RESPONSE_ACCEPT, NULL); if (gtk_dialog_run(GTK_DIALOG(filesel)) == GTK_RESPONSE_ACCEPT) { char *name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(filesel)); filesel_name = dupstr(name); g_free(name); } gtk_widget_destroy(filesel); return filesel_name; } #endif struct savefile_write_ctx { FILE *fp; int error; }; static void savefile_write(void *wctx, void *buf, int len) { struct savefile_write_ctx *ctx = (struct savefile_write_ctx *)wctx; if (fwrite(buf, 1, len, ctx->fp) < len) ctx->error = errno; } static int savefile_read(void *wctx, void *buf, int len) { FILE *fp = (FILE *)wctx; int ret; ret = fread(buf, 1, len, fp); return (ret == len); } static void menu_save_event(GtkMenuItem *menuitem, gpointer data) { frontend *fe = (frontend *)data; char *name; name = file_selector(fe, "Enter name of game file to save", TRUE); if (name) { FILE *fp; if ((fp = fopen(name, "r")) != NULL) { char buf[256 + FILENAME_MAX]; fclose(fp); /* file exists */ sprintf(buf, "Are you sure you want to overwrite the" " file \"%.*s\"?", FILENAME_MAX, name); if (!message_box(fe->window, "Question", buf, TRUE, MB_YESNO)) goto free_and_return; } fp = fopen(name, "w"); if (!fp) { error_box(fe->window, "Unable to open save file"); goto free_and_return; } { struct savefile_write_ctx ctx; ctx.fp = fp; ctx.error = 0; midend_serialise(fe->me, savefile_write, &ctx); fclose(fp); if (ctx.error) { char boxmsg[512]; sprintf(boxmsg, "Error writing save file: %.400s", strerror(errno)); error_box(fe->window, boxmsg); goto free_and_return; } } free_and_return: sfree(name); } } static void menu_load_event(GtkMenuItem *menuitem, gpointer data) { frontend *fe = (frontend *)data; char *name, *err; name = file_selector(fe, "Enter name of saved game file to load", FALSE); if (name) { FILE *fp = fopen(name, "r"); sfree(name); if (!fp) { error_box(fe->window, "Unable to open saved game file"); return; } err = midend_deserialise(fe->me, savefile_read, fp); fclose(fp); if (err) { error_box(fe->window, err); return; } changed_preset(fe); resize_fe(fe); midend_redraw(fe->me); } } static void menu_solve_event(GtkMenuItem *menuitem, gpointer data) { frontend *fe = (frontend *)data; char *msg; msg = midend_solve(fe->me); if (msg) error_box(fe->window, msg); } static void menu_restart_event(GtkMenuItem *menuitem, gpointer data) { frontend *fe = (frontend *)data; midend_restart_game(fe->me); } static void menu_config_event(GtkMenuItem *menuitem, gpointer data) { frontend *fe = (frontend *)data; int which = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(menuitem), "user-data")); if (fe->preset_threaded || (GTK_IS_CHECK_MENU_ITEM(menuitem) && !gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(menuitem)))) return; changed_preset(fe); /* Put the old preset back! */ if (!get_config(fe, which)) return; midend_new_game(fe->me); resize_fe(fe); midend_redraw(fe->me); } static void menu_about_event(GtkMenuItem *menuitem, gpointer data) { frontend *fe = (frontend *)data; #if GTK_CHECK_VERSION(3,0,0) extern char *const *const xpm_icons[]; extern const int n_xpm_icons; GdkPixbuf *icon = gdk_pixbuf_new_from_xpm_data ((const gchar **)xpm_icons[n_xpm_icons-1]); gtk_show_about_dialog (GTK_WINDOW(fe->window), "program-name", thegame.name, "version", ver, "comments", "Part of Simon Tatham's Portable Puzzle Collection", "logo", icon, (const gchar *)NULL); g_object_unref(G_OBJECT(icon)); #else char titlebuf[256]; char textbuf[1024]; sprintf(titlebuf, "About %.200s", thegame.name); sprintf(textbuf, "%.200s\n\n" "from Simon Tatham's Portable Puzzle Collection\n\n" "%.500s", thegame.name, ver); message_box(fe->window, titlebuf, textbuf, TRUE, MB_OK); #endif } static GtkWidget *add_menu_item_with_key(frontend *fe, GtkContainer *cont, char *text, int key) { GtkWidget *menuitem = gtk_menu_item_new_with_label(text); int keyqual; gtk_container_add(cont, menuitem); g_object_set_data(G_OBJECT(menuitem), "user-data", GINT_TO_POINTER(key)); g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(menu_key_event), fe); switch (key & ~0x1F) { case 0x00: key += 0x60; keyqual = GDK_CONTROL_MASK; break; case 0x40: key += 0x20; keyqual = GDK_SHIFT_MASK; break; default: keyqual = 0; break; } gtk_widget_add_accelerator(menuitem, "activate", fe->accelgroup, key, keyqual, GTK_ACCEL_VISIBLE); gtk_widget_show(menuitem); return menuitem; } static void add_menu_separator(GtkContainer *cont) { GtkWidget *menuitem = gtk_menu_item_new(); gtk_container_add(cont, menuitem); gtk_widget_show(menuitem); } static void populate_gtk_preset_menu(frontend *fe, struct preset_menu *menu, GtkWidget *gtkmenu) { int i; for (i = 0; i < menu->n_entries; i++) { struct preset_menu_entry *entry = &menu->entries[i]; GtkWidget *menuitem; if (entry->params) { menuitem = gtk_radio_menu_item_new_with_label( fe->preset_radio, entry->title); fe->preset_radio = gtk_radio_menu_item_get_group( GTK_RADIO_MENU_ITEM(menuitem)); g_object_set_data(G_OBJECT(menuitem), "user-data", entry); g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(menu_preset_event), fe); } else { GtkWidget *submenu; menuitem = gtk_menu_item_new_with_label(entry->title); submenu = gtk_menu_new(); gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu); populate_gtk_preset_menu(fe, entry->submenu, submenu); } gtk_container_add(GTK_CONTAINER(gtkmenu), menuitem); gtk_widget_show(menuitem); } } enum { ARG_EITHER, ARG_SAVE, ARG_ID }; /* for argtype */ static frontend *new_window(char *arg, int argtype, char **error) { frontend *fe; GtkBox *vbox, *hbox; GtkWidget *menu, *menuitem; GList *iconlist; int x, y, n; char errbuf[1024]; extern char *const *const xpm_icons[]; extern const int n_xpm_icons; struct preset_menu *preset_menu; fe = snew(frontend); #if GTK_CHECK_VERSION(3,20,0) fe->css_provider = NULL; #endif fe->timer_active = FALSE; fe->timer_id = -1; fe->me = midend_new(fe, &thegame, >k_drawing, fe); if (arg) { char *err; FILE *fp; errbuf[0] = '\0'; switch (argtype) { case ARG_ID: err = midend_game_id(fe->me, arg); if (!err) midend_new_game(fe->me); else sprintf(errbuf, "Invalid game ID: %.800s", err); break; case ARG_SAVE: fp = fopen(arg, "r"); if (!fp) { sprintf(errbuf, "Error opening file: %.800s", strerror(errno)); } else { err = midend_deserialise(fe->me, savefile_read, fp); if (err) sprintf(errbuf, "Invalid save file: %.800s", err); fclose(fp); } break; default /*case ARG_EITHER*/: /* * First try treating the argument as a game ID. */ err = midend_game_id(fe->me, arg); if (!err) { /* * It's a valid game ID. */ midend_new_game(fe->me); } else { FILE *fp = fopen(arg, "r"); if (!fp) { sprintf(errbuf, "Supplied argument is neither a game ID (%.400s)" " nor a save file (%.400s)", err, strerror(errno)); } else { err = midend_deserialise(fe->me, savefile_read, fp); if (err) sprintf(errbuf, "%.800s", err); fclose(fp); } } break; } if (*errbuf) { *error = dupstr(errbuf); midend_free(fe->me); sfree(fe); return NULL; } } else { midend_new_game(fe->me); } #if !GTK_CHECK_VERSION(3,0,0) { /* * try_shrink_drawing_area() will do some fiddling with the * window size request (see comment in that function) after * all the bits and pieces such as the menu bar and status bar * have appeared in the puzzle window. * * However, on Unity systems, the menu bar _doesn't_ appear in * the puzzle window, because the Unity shell hijacks it into * the menu bar at the very top of the screen. We therefore * try to detect that situation here, so that we don't sit * here forever waiting for a menu bar. */ const char prop[] = "gtk-shell-shows-menubar"; GtkSettings *settings = gtk_settings_get_default(); if (!g_object_class_find_property(G_OBJECT_GET_CLASS(settings), prop)) { fe->menubar_is_local = TRUE; } else { int unity_mode; g_object_get(gtk_settings_get_default(), prop, &unity_mode, (const gchar *)NULL); fe->menubar_is_local = !unity_mode; } } #endif fe->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(fe->window), thegame.name); vbox = GTK_BOX(gtk_vbox_new(FALSE, 0)); gtk_container_add(GTK_CONTAINER(fe->window), GTK_WIDGET(vbox)); gtk_widget_show(GTK_WIDGET(vbox)); fe->accelgroup = gtk_accel_group_new(); gtk_window_add_accel_group(GTK_WINDOW(fe->window), fe->accelgroup); hbox = GTK_BOX(gtk_hbox_new(FALSE, 0)); gtk_box_pack_start(vbox, GTK_WIDGET(hbox), FALSE, FALSE, 0); gtk_widget_show(GTK_WIDGET(hbox)); fe->menubar = gtk_menu_bar_new(); gtk_box_pack_start(hbox, fe->menubar, TRUE, TRUE, 0); gtk_widget_show(fe->menubar); menuitem = gtk_menu_item_new_with_mnemonic("_Game"); gtk_container_add(GTK_CONTAINER(fe->menubar), menuitem); gtk_widget_show(menuitem); menu = gtk_menu_new(); gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menu); add_menu_item_with_key(fe, GTK_CONTAINER(menu), "New", 'n'); menuitem = gtk_menu_item_new_with_label("Restart"); gtk_container_add(GTK_CONTAINER(menu), menuitem); g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(menu_restart_event), fe); gtk_widget_show(menuitem); menuitem = gtk_menu_item_new_with_label("Specific..."); g_object_set_data(G_OBJECT(menuitem), "user-data", GINT_TO_POINTER(CFG_DESC)); gtk_container_add(GTK_CONTAINER(menu), menuitem); g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(menu_config_event), fe); gtk_widget_show(menuitem); menuitem = gtk_menu_item_new_with_label("Random Seed..."); g_object_set_data(G_OBJECT(menuitem), "user-data", GINT_TO_POINTER(CFG_SEED)); gtk_container_add(GTK_CONTAINER(menu), menuitem); g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(menu_config_event), fe); gtk_widget_show(menuitem); fe->preset_radio = NULL; fe->preset_custom = NULL; fe->preset_threaded = FALSE; preset_menu = midend_get_presets(fe->me, NULL); if (preset_menu->n_entries > 0 || thegame.can_configure) { GtkWidget *submenu; menuitem = gtk_menu_item_new_with_mnemonic("_Type"); gtk_container_add(GTK_CONTAINER(fe->menubar), menuitem); gtk_widget_show(menuitem); submenu = gtk_menu_new(); gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), submenu); populate_gtk_preset_menu(fe, preset_menu, submenu); if (thegame.can_configure) { menuitem = fe->preset_custom = gtk_radio_menu_item_new_with_label(fe->preset_radio, "Custom..."); fe->preset_radio = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(menuitem)); gtk_container_add(GTK_CONTAINER(submenu), menuitem); g_object_set_data(G_OBJECT(menuitem), "user-data", GINT_TO_POINTER(CFG_SETTINGS)); g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(menu_config_event), fe); gtk_widget_show(menuitem); } } add_menu_separator(GTK_CONTAINER(menu)); menuitem = gtk_menu_item_new_with_label("Load..."); gtk_container_add(GTK_CONTAINER(menu), menuitem); g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(menu_load_event), fe); gtk_widget_show(menuitem); menuitem = gtk_menu_item_new_with_label("Save..."); gtk_container_add(GTK_CONTAINER(menu), menuitem); g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(menu_save_event), fe); gtk_widget_show(menuitem); #ifndef STYLUS_BASED add_menu_separator(GTK_CONTAINER(menu)); add_menu_item_with_key(fe, GTK_CONTAINER(menu), "Undo", 'u'); add_menu_item_with_key(fe, GTK_CONTAINER(menu), "Redo", 'r'); #endif if (thegame.can_format_as_text_ever) { add_menu_separator(GTK_CONTAINER(menu)); menuitem = gtk_menu_item_new_with_label("Copy"); gtk_container_add(GTK_CONTAINER(menu), menuitem); g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(menu_copy_event), fe); gtk_widget_show(menuitem); fe->copy_menu_item = menuitem; } else { fe->copy_menu_item = NULL; } if (thegame.can_solve) { add_menu_separator(GTK_CONTAINER(menu)); menuitem = gtk_menu_item_new_with_label("Solve"); gtk_container_add(GTK_CONTAINER(menu), menuitem); g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(menu_solve_event), fe); gtk_widget_show(menuitem); } add_menu_separator(GTK_CONTAINER(menu)); add_menu_item_with_key(fe, GTK_CONTAINER(menu), "Exit", 'q'); menuitem = gtk_menu_item_new_with_mnemonic("_Help"); gtk_container_add(GTK_CONTAINER(fe->menubar), menuitem); gtk_widget_show(menuitem); menu = gtk_menu_new(); gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem), menu); menuitem = gtk_menu_item_new_with_label("About"); gtk_container_add(GTK_CONTAINER(menu), menuitem); g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(menu_about_event), fe); gtk_widget_show(menuitem); #ifdef STYLUS_BASED menuitem=gtk_button_new_with_mnemonic("_Redo"); g_object_set_data(G_OBJECT(menuitem), "user-data", GINT_TO_POINTER((int)('r'))); g_signal_connect(G_OBJECT(menuitem), "clicked", G_CALLBACK(menu_key_event), fe); gtk_box_pack_end(hbox, menuitem, FALSE, FALSE, 0); gtk_widget_show(menuitem); menuitem=gtk_button_new_with_mnemonic("_Undo"); g_object_set_data(G_OBJECT(menuitem), "user-data", GINT_TO_POINTER((int)('u'))); g_signal_connect(G_OBJECT(menuitem), "clicked", G_CALLBACK(menu_key_event), fe); gtk_box_pack_end(hbox, menuitem, FALSE, FALSE, 0); gtk_widget_show(menuitem); if (thegame.flags & REQUIRE_NUMPAD) { hbox = GTK_BOX(gtk_hbox_new(FALSE, 0)); gtk_box_pack_start(vbox, GTK_WIDGET(hbox), FALSE, FALSE, 0); gtk_widget_show(GTK_WIDGET(hbox)); *((int*)errbuf)=0; errbuf[1]='\0'; for(errbuf[0]='0';errbuf[0]<='9';errbuf[0]++) { menuitem=gtk_button_new_with_label(errbuf); g_object_set_data(G_OBJECT(menuitem), "user-data", GINT_TO_POINTER((int)(errbuf[0]))); g_signal_connect(G_OBJECT(menuitem), "clicked", G_CALLBACK(menu_key_event), fe); gtk_box_pack_start(hbox, menuitem, TRUE, TRUE, 0); gtk_widget_show(menuitem); } } #endif /* STYLUS_BASED */ changed_preset(fe); snaffle_colours(fe); if (midend_wants_statusbar(fe->me)) { GtkWidget *viewport; GtkRequisition req; viewport = gtk_viewport_new(NULL, NULL); gtk_viewport_set_shadow_type(GTK_VIEWPORT(viewport), GTK_SHADOW_NONE); fe->statusbar = gtk_statusbar_new(); gtk_container_add(GTK_CONTAINER(viewport), fe->statusbar); gtk_widget_show(viewport); gtk_box_pack_end(vbox, viewport, FALSE, FALSE, 0); gtk_widget_show(fe->statusbar); fe->statusctx = gtk_statusbar_get_context_id (GTK_STATUSBAR(fe->statusbar), "game"); gtk_statusbar_push(GTK_STATUSBAR(fe->statusbar), fe->statusctx, DEFAULT_STATUSBAR_TEXT); #if GTK_CHECK_VERSION(3,0,0) gtk_widget_get_preferred_size(fe->statusbar, &req, NULL); #else gtk_widget_size_request(fe->statusbar, &req); #endif gtk_widget_set_size_request(viewport, -1, req.height); } else fe->statusbar = NULL; fe->area = gtk_drawing_area_new(); #if GTK_CHECK_VERSION(2,0,0) && !GTK_CHECK_VERSION(3,0,0) gtk_widget_set_double_buffered(fe->area, FALSE); #endif { GdkGeometry geom; geom.base_width = 0; #if GTK_CHECK_VERSION(3,0,0) geom.base_height = window_extra_height(fe); gtk_window_set_geometry_hints(GTK_WINDOW(fe->window), NULL, &geom, GDK_HINT_BASE_SIZE); #else geom.base_height = 0; gtk_window_set_geometry_hints(GTK_WINDOW(fe->window), fe->area, &geom, GDK_HINT_BASE_SIZE); #endif } fe->w = -1; fe->h = -1; get_size(fe, &x, &y); #if GTK_CHECK_VERSION(3,0,0) gtk_window_set_default_size(GTK_WINDOW(fe->window), x, y + window_extra_height(fe)); #else fe->drawing_area_shrink_pending = FALSE; gtk_drawing_area_size(GTK_DRAWING_AREA(fe->area), x, y); #endif gtk_box_pack_end(vbox, fe->area, TRUE, TRUE, 0); clear_backing_store(fe); fe->fonts = NULL; fe->nfonts = fe->fontsize = 0; fe->paste_data = NULL; fe->paste_data_len = 0; g_signal_connect(G_OBJECT(fe->window), "destroy", G_CALLBACK(destroy), fe); g_signal_connect(G_OBJECT(fe->window), "key_press_event", G_CALLBACK(key_event), fe); g_signal_connect(G_OBJECT(fe->area), "button_press_event", G_CALLBACK(button_event), fe); g_signal_connect(G_OBJECT(fe->area), "button_release_event", G_CALLBACK(button_event), fe); g_signal_connect(G_OBJECT(fe->area), "motion_notify_event", G_CALLBACK(motion_event), fe); g_signal_connect(G_OBJECT(fe->area), "selection_get", G_CALLBACK(selection_get), fe); g_signal_connect(G_OBJECT(fe->area), "selection_clear_event", G_CALLBACK(selection_clear), fe); #if GTK_CHECK_VERSION(3,0,0) g_signal_connect(G_OBJECT(fe->area), "draw", G_CALLBACK(draw_area), fe); #else g_signal_connect(G_OBJECT(fe->area), "expose_event", G_CALLBACK(expose_area), fe); #endif g_signal_connect(G_OBJECT(fe->window), "map_event", G_CALLBACK(map_window), fe); g_signal_connect(G_OBJECT(fe->area), "configure_event", G_CALLBACK(configure_area), fe); g_signal_connect(G_OBJECT(fe->window), "configure_event", G_CALLBACK(configure_window), fe); gtk_widget_add_events(GTK_WIDGET(fe->area), GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK); if (n_xpm_icons) { gtk_window_set_icon(GTK_WINDOW(fe->window), gdk_pixbuf_new_from_xpm_data ((const gchar **)xpm_icons[0])); iconlist = NULL; for (n = 0; n < n_xpm_icons; n++) { iconlist = g_list_append(iconlist, gdk_pixbuf_new_from_xpm_data((const gchar **) xpm_icons[n])); } gtk_window_set_icon_list(GTK_WINDOW(fe->window), iconlist); } gtk_widget_show(fe->area); gtk_widget_show(fe->window); #if !GTK_CHECK_VERSION(3,0,0) fe->drawing_area_shrink_pending = TRUE; try_shrink_drawing_area(fe); #endif set_window_background(fe, 0); return fe; } char *fgetline(FILE *fp) { char *ret = snewn(512, char); int size = 512, len = 0; while (fgets(ret + len, size - len, fp)) { len += strlen(ret + len); if (ret[len-1] == '\n') break; /* got a newline, we're done */ size = len + 512; ret = sresize(ret, size, char); } if (len == 0) { /* first fgets returned NULL */ sfree(ret); return NULL; } ret[len] = '\0'; return ret; } static void list_presets_from_menu(struct preset_menu *menu) { int i; for (i = 0; i < menu->n_entries; i++) { if (menu->entries[i].params) { char *paramstr = thegame.encode_params( menu->entries[i].params, TRUE); printf("%s %s\n", paramstr, menu->entries[i].title); sfree(paramstr); } else { list_presets_from_menu(menu->entries[i].submenu); } } } int main(int argc, char **argv) { char *pname = argv[0]; char *error; int ngenerate = 0, print = FALSE, px = 1, py = 1; int time_generation = FALSE, test_solve = FALSE, list_presets = FALSE; int soln = FALSE, colour = FALSE; float scale = 1.0F; float redo_proportion = 0.0F; char *savefile = NULL, *savesuffix = NULL; char *arg = NULL; int argtype = ARG_EITHER; char *screenshot_file = NULL; int doing_opts = TRUE; int ac = argc; char **av = argv; char errbuf[500]; /* * Command line parsing in this function is rather fiddly, * because GTK wants to have a go at argc/argv _first_ - and * yet we can't let it, because gtk_init() will bomb out if it * can't open an X display, whereas in fact we want to permit * our --generate and --print modes to run without an X * display. * * So what we do is: * - we parse the command line ourselves, without modifying * argc/argv * - if we encounter an error which might plausibly be the * result of a GTK command line (i.e. not detailed errors in * particular options of ours) we store the error message * and terminate parsing. * - if we got enough out of the command line to know it * specifies a non-X mode of operation, we either display * the stored error and return failure, or if there is no * stored error we do the non-X operation and return * success. * - otherwise, we go straight to gtk_init(). */ errbuf[0] = '\0'; while (--ac > 0) { char *p = *++av; if (doing_opts && !strcmp(p, "--version")) { printf("%s, from Simon Tatham's Portable Puzzle Collection\n%s\n", thegame.name, ver); return 0; } else if (doing_opts && !strcmp(p, "--generate")) { if (--ac > 0) { ngenerate = atoi(*++av); if (!ngenerate) { fprintf(stderr, "%s: '--generate' expected a number\n", pname); return 1; } } else ngenerate = 1; } else if (doing_opts && !strcmp(p, "--time-generation")) { time_generation = TRUE; } else if (doing_opts && !strcmp(p, "--test-solve")) { test_solve = TRUE; } else if (doing_opts && !strcmp(p, "--list-presets")) { list_presets = TRUE; } else if (doing_opts && !strcmp(p, "--save")) { if (--ac > 0) { savefile = *++av; } else { fprintf(stderr, "%s: '--save' expected a filename\n", pname); return 1; } } else if (doing_opts && (!strcmp(p, "--save-suffix") || !strcmp(p, "--savesuffix"))) { if (--ac > 0) { savesuffix = *++av; } else { fprintf(stderr, "%s: '--save-suffix' expected a filename\n", pname); return 1; } } else if (doing_opts && !strcmp(p, "--print")) { if (!thegame.can_print) { fprintf(stderr, "%s: this game does not support printing\n", pname); return 1; } print = TRUE; if (--ac > 0) { char *dim = *++av; if (sscanf(dim, "%dx%d", &px, &py) != 2) { fprintf(stderr, "%s: unable to parse argument '%s' to " "'--print'\n", pname, dim); return 1; } } else { px = py = 1; } } else if (doing_opts && !strcmp(p, "--scale")) { if (--ac > 0) { scale = atof(*++av); } else { fprintf(stderr, "%s: no argument supplied to '--scale'\n", pname); return 1; } } else if (doing_opts && !strcmp(p, "--redo")) { /* * This is an internal option which I don't expect * users to have any particular use for. The effect of * --redo is that once the game has been loaded and * initialised, the next move in the redo chain is * replayed, and the game screen is redrawn part way * through the making of the move. This is only * meaningful if there _is_ a next move in the redo * chain, which means in turn that this option is only * useful if you're also passing a save file on the * command line. * * This option is used by the script which generates * the puzzle icons and website screenshots, and I * don't imagine it's useful for anything else. * (Unless, I suppose, users don't like my screenshots * and want to generate their own in the same way for * some repackaged version of the puzzles.) */ if (--ac > 0) { redo_proportion = atof(*++av); } else { fprintf(stderr, "%s: no argument supplied to '--redo'\n", pname); return 1; } } else if (doing_opts && !strcmp(p, "--screenshot")) { /* * Another internal option for the icon building * script. This causes a screenshot of the central * drawing area (i.e. not including the menu bar or * status bar) to be saved to a PNG file once the * window has been drawn, and then the application * quits immediately. */ if (--ac > 0) { screenshot_file = *++av; } else { fprintf(stderr, "%s: no argument supplied to '--screenshot'\n", pname); return 1; } } else if (doing_opts && (!strcmp(p, "--with-solutions") || !strcmp(p, "--with-solution") || !strcmp(p, "--with-solns") || !strcmp(p, "--with-soln") || !strcmp(p, "--solutions") || !strcmp(p, "--solution") || !strcmp(p, "--solns") || !strcmp(p, "--soln"))) { soln = TRUE; } else if (doing_opts && !strcmp(p, "--colour")) { if (!thegame.can_print_in_colour) { fprintf(stderr, "%s: this game does not support colour" " printing\n", pname); return 1; } colour = TRUE; } else if (doing_opts && !strcmp(p, "--load")) { argtype = ARG_SAVE; } else if (doing_opts && !strcmp(p, "--game")) { argtype = ARG_ID; } else if (doing_opts && !strcmp(p, "--")) { doing_opts = FALSE; } else if (!doing_opts || p[0] != '-') { if (arg) { fprintf(stderr, "%s: more than one argument supplied\n", pname); return 1; } arg = p; } else { sprintf(errbuf, "%.100s: unrecognised option '%.100s'\n", pname, p); break; } } /* * Special standalone mode for generating puzzle IDs on the * command line. Useful for generating puzzles to be printed * out and solved offline (for puzzles where that even makes * sense - Solo, for example, is a lot more pencil-and-paper * friendly than Twiddle!) * * Usage: * * --generate [ []] * * , if present, is the number of puzzle IDs to generate. * , if present, is the same type of parameter string * you would pass to the puzzle when running it in GUI mode, * including optional extras such as the expansion factor in * Rectangles and the difficulty level in Solo. * * If you specify , you must also specify (although * you may specify it to be 1). Sorry; that was the * simplest-to-parse command-line syntax I came up with. */ if (ngenerate > 0 || print || savefile || savesuffix) { int i, n = 1; midend *me; char *id; document *doc = NULL; /* * If we're in this branch, we should display any pending * error message from the command line, since GTK isn't going * to take another crack at making sense of it. */ if (*errbuf) { fputs(errbuf, stderr); return 1; } n = ngenerate; me = midend_new(NULL, &thegame, NULL, NULL); i = 0; if (savefile && !savesuffix) savesuffix = ""; if (!savefile && savesuffix) savefile = ""; if (print) doc = document_new(px, py, scale); /* * In this loop, we either generate a game ID or read one * from stdin depending on whether we're in generate mode; * then we either write it to stdout or print it, depending * on whether we're in print mode. Thus, this loop handles * generate-to-stdout, print-from-stdin and generate-and- * immediately-print modes. * * (It could also handle a copy-stdin-to-stdout mode, * although there's currently no combination of options * which will cause this loop to be activated in that mode. * It wouldn't be _entirely_ pointless, though, because * stdin could contain bare params strings or random-seed * IDs, and stdout would contain nothing but fully * generated descriptive game IDs.) */ while (ngenerate == 0 || i < n) { char *pstr, *err, *seed; struct rusage before, after; if (ngenerate == 0) { pstr = fgetline(stdin); if (!pstr) break; pstr[strcspn(pstr, "\r\n")] = '\0'; } else { if (arg) { pstr = snewn(strlen(arg) + 40, char); strcpy(pstr, arg); if (i > 0 && strchr(arg, '#')) sprintf(pstr + strlen(pstr), "-%d", i); } else pstr = NULL; } if (pstr) { err = midend_game_id(me, pstr); if (err) { fprintf(stderr, "%s: error parsing '%s': %s\n", pname, pstr, err); return 1; } } if (time_generation) getrusage(RUSAGE_SELF, &before); midend_new_game(me); seed = midend_get_random_seed(me); if (time_generation) { double elapsed; getrusage(RUSAGE_SELF, &after); elapsed = (after.ru_utime.tv_sec - before.ru_utime.tv_sec); elapsed += (after.ru_utime.tv_usec - before.ru_utime.tv_usec) / 1000000.0; printf("%s %s: %.6f\n", thegame.name, seed, elapsed); } if (test_solve && thegame.can_solve) { /* * Now destroy the aux_info in the midend, by means of * re-entering the same game id, and then try to solve * it. */ char *game_id, *err; game_id = midend_get_game_id(me); err = midend_game_id(me, game_id); if (err) { fprintf(stderr, "%s %s: game id re-entry error: %s\n", thegame.name, seed, err); return 1; } midend_new_game(me); sfree(game_id); err = midend_solve(me); /* * If the solve operation returned the error "Solution * not known for this puzzle", that's OK, because that * just means it's a puzzle for which we don't have an * algorithmic solver and hence can't solve it without * the aux_info, e.g. Netslide. Any other error is a * problem, though. */ if (err && strcmp(err, "Solution not known for this puzzle")) { fprintf(stderr, "%s %s: solve error: %s\n", thegame.name, seed, err); return 1; } } sfree(pstr); sfree(seed); if (doc) { err = midend_print_puzzle(me, doc, soln); if (err) { fprintf(stderr, "%s: error in printing: %s\n", pname, err); return 1; } } if (savefile) { struct savefile_write_ctx ctx; char *realname = snewn(40 + strlen(savefile) + strlen(savesuffix), char); sprintf(realname, "%s%d%s", savefile, i, savesuffix); if (soln) { char *err = midend_solve(me); if (err) { fprintf(stderr, "%s: unable to show solution: %s\n", realname, err); return 1; } } ctx.fp = fopen(realname, "w"); if (!ctx.fp) { fprintf(stderr, "%s: open: %s\n", realname, strerror(errno)); return 1; } ctx.error = 0; midend_serialise(me, savefile_write, &ctx); if (ctx.error) { fprintf(stderr, "%s: write: %s\n", realname, strerror(ctx.error)); return 1; } if (fclose(ctx.fp)) { fprintf(stderr, "%s: close: %s\n", realname, strerror(errno)); return 1; } sfree(realname); } if (!doc && !savefile && !time_generation) { id = midend_get_game_id(me); puts(id); sfree(id); } i++; } if (doc) { psdata *ps = ps_init(stdout, colour); document_print(doc, ps_drawing_api(ps)); document_free(doc); ps_free(ps); } midend_free(me); return 0; } else if (list_presets) { /* * Another specialist mode which causes the puzzle to list the * game_params strings for all its preset configurations. */ midend *me; struct preset_menu *menu; me = midend_new(NULL, &thegame, NULL, NULL); menu = midend_get_presets(me, NULL); list_presets_from_menu(menu); midend_free(me); return 0; } else { frontend *fe; gtk_init(&argc, &argv); fe = new_window(arg, argtype, &error); if (!fe) { fprintf(stderr, "%s: %s\n", pname, error); return 1; } if (screenshot_file) { /* * Some puzzles will not redraw their entire area if * given a partially completed animation, which means * we must redraw now and _then_ redraw again after * freezing the move timer. */ midend_force_redraw(fe->me); } if (redo_proportion) { /* Start a redo. */ midend_process_key(fe->me, 0, 0, 'r'); /* And freeze the timer at the specified position. */ midend_freeze_timer(fe->me, redo_proportion); } if (screenshot_file) { save_screenshot_png(fe, screenshot_file); exit(0); } gtk_main(); } return 0; } puzzles-20170606.272beef/grid.c0000644000175000017500000033774613115373615015006 0ustar simonsimon/* * (c) Lambros Lambrou 2008 * * Code for working with general grids, which can be any planar graph * with faces, edges and vertices (dots). Includes generators for a few * types of grid, including square, hexagonal, triangular and others. */ #include #include #include #include #include #include #include #include "puzzles.h" #include "tree234.h" #include "grid.h" #include "penrose.h" /* Debugging options */ /* #define DEBUG_GRID */ /* ---------------------------------------------------------------------- * Deallocate or dereference a grid */ void grid_free(grid *g) { assert(g->refcount); g->refcount--; if (g->refcount == 0) { int i; for (i = 0; i < g->num_faces; i++) { sfree(g->faces[i].dots); sfree(g->faces[i].edges); } for (i = 0; i < g->num_dots; i++) { sfree(g->dots[i].faces); sfree(g->dots[i].edges); } sfree(g->faces); sfree(g->edges); sfree(g->dots); sfree(g); } } /* Used by the other grid generators. Create a brand new grid with nothing * initialised (all lists are NULL) */ static grid *grid_empty(void) { grid *g = snew(grid); g->faces = NULL; g->edges = NULL; g->dots = NULL; g->num_faces = g->num_edges = g->num_dots = 0; g->refcount = 1; g->lowest_x = g->lowest_y = g->highest_x = g->highest_y = 0; return g; } /* Helper function to calculate perpendicular distance from * a point P to a line AB. A and B mustn't be equal here. * * Well-known formula for area A of a triangle: * / 1 1 1 \ * 2A = determinant of matrix | px ax bx | * \ py ay by / * * Also well-known: 2A = base * height * = perpendicular distance * line-length. * * Combining gives: distance = determinant / line-length(a,b) */ static double point_line_distance(long px, long py, long ax, long ay, long bx, long by) { long det = ax*by - bx*ay + bx*py - px*by + px*ay - ax*py; double len; det = max(det, -det); len = sqrt(SQ(ax - bx) + SQ(ay - by)); return det / len; } /* Determine nearest edge to where the user clicked. * (x, y) is the clicked location, converted to grid coordinates. * Returns the nearest edge, or NULL if no edge is reasonably * near the position. * * Just judging edges by perpendicular distance is not quite right - * the edge might be "off to one side". So we insist that the triangle * with (x,y) has acute angles at the edge's dots. * * edge1 * *---------*------ * | * | *(x,y) * edge2 | * | edge2 is OK, but edge1 is not, even though * | edge1 is perpendicularly closer to (x,y) * * * */ grid_edge *grid_nearest_edge(grid *g, int x, int y) { grid_edge *best_edge; double best_distance = 0; int i; best_edge = NULL; for (i = 0; i < g->num_edges; i++) { grid_edge *e = &g->edges[i]; long e2; /* squared length of edge */ long a2, b2; /* squared lengths of other sides */ double dist; /* See if edge e is eligible - the triangle must have acute angles * at the edge's dots. * Pythagoras formula h^2 = a^2 + b^2 detects right-angles, * so detect acute angles by testing for h^2 < a^2 + b^2 */ e2 = SQ((long)e->dot1->x - (long)e->dot2->x) + SQ((long)e->dot1->y - (long)e->dot2->y); a2 = SQ((long)e->dot1->x - (long)x) + SQ((long)e->dot1->y - (long)y); b2 = SQ((long)e->dot2->x - (long)x) + SQ((long)e->dot2->y - (long)y); if (a2 >= e2 + b2) continue; if (b2 >= e2 + a2) continue; /* e is eligible so far. Now check the edge is reasonably close * to where the user clicked. Don't want to toggle an edge if the * click was way off the grid. * There is room for experimentation here. We could check the * perpendicular distance is within a certain fraction of the length * of the edge. That amounts to testing a rectangular region around * the edge. * Alternatively, we could check that the angle at the point is obtuse. * That would amount to testing a circular region with the edge as * diameter. */ dist = point_line_distance((long)x, (long)y, (long)e->dot1->x, (long)e->dot1->y, (long)e->dot2->x, (long)e->dot2->y); /* Is dist more than half edge length ? */ if (4 * SQ(dist) > e2) continue; if (best_edge == NULL || dist < best_distance) { best_edge = e; best_distance = dist; } } return best_edge; } /* ---------------------------------------------------------------------- * Grid generation */ #ifdef SVG_GRID #define SVG_DOTS 1 #define SVG_EDGES 2 #define SVG_FACES 4 #define FACE_COLOUR "red" #define EDGE_COLOUR "blue" #define DOT_COLOUR "black" static void grid_output_svg(FILE *fp, grid *g, int which) { int i, j; fprintf(fp,"\ \n\ \n\ \n\ \n\n"); if (which & SVG_FACES) { fprintf(fp, "\n"); for (i = 0; i < g->num_faces; i++) { grid_face *f = g->faces + i; fprintf(fp, "order; j++) { grid_dot *d = f->dots[j]; fprintf(fp, "%s%d,%d", (j == 0) ? "" : " ", d->x, d->y); } fprintf(fp, "\" style=\"fill: %s; fill-opacity: 0.2; stroke: %s\" />\n", FACE_COLOUR, FACE_COLOUR); } fprintf(fp, "\n"); } if (which & SVG_EDGES) { fprintf(fp, "\n"); for (i = 0; i < g->num_edges; i++) { grid_edge *e = g->edges + i; grid_dot *d1 = e->dot1, *d2 = e->dot2; fprintf(fp, "\n", d1->x, d1->y, d2->x, d2->y, EDGE_COLOUR); } fprintf(fp, "\n"); } if (which & SVG_DOTS) { fprintf(fp, "\n"); for (i = 0; i < g->num_dots; i++) { grid_dot *d = g->dots + i; fprintf(fp, "", d->x, d->y, g->tilesize/20, g->tilesize/20, DOT_COLOUR); } fprintf(fp, "\n"); } fprintf(fp, "\n"); } #endif #ifdef SVG_GRID #include static void grid_try_svg(grid *g, int which) { char *svg = getenv("PUZZLES_SVG_GRID"); if (svg) { FILE *svgf = fopen(svg, "w"); if (svgf) { grid_output_svg(svgf, g, which); fclose(svgf); } else { fprintf(stderr, "Unable to open file `%s': %s", svg, strerror(errno)); } } } #endif /* Show the basic grid information, before doing grid_make_consistent */ static void grid_debug_basic(grid *g) { /* TODO: Maybe we should generate an SVG image of the dots and lines * of the grid here, before grid_make_consistent. * Would help with debugging grid generation. */ #ifdef DEBUG_GRID int i; printf("--- Basic Grid Data ---\n"); for (i = 0; i < g->num_faces; i++) { grid_face *f = g->faces + i; printf("Face %d: dots[", i); int j; for (j = 0; j < f->order; j++) { grid_dot *d = f->dots[j]; printf("%s%d", j ? "," : "", (int)(d - g->dots)); } printf("]\n"); } #endif #ifdef SVG_GRID grid_try_svg(g, SVG_FACES); #endif } /* Show the derived grid information, computed by grid_make_consistent */ static void grid_debug_derived(grid *g) { #ifdef DEBUG_GRID /* edges */ int i; printf("--- Derived Grid Data ---\n"); for (i = 0; i < g->num_edges; i++) { grid_edge *e = g->edges + i; printf("Edge %d: dots[%d,%d] faces[%d,%d]\n", i, (int)(e->dot1 - g->dots), (int)(e->dot2 - g->dots), e->face1 ? (int)(e->face1 - g->faces) : -1, e->face2 ? (int)(e->face2 - g->faces) : -1); } /* faces */ for (i = 0; i < g->num_faces; i++) { grid_face *f = g->faces + i; int j; printf("Face %d: faces[", i); for (j = 0; j < f->order; j++) { grid_edge *e = f->edges[j]; grid_face *f2 = (e->face1 == f) ? e->face2 : e->face1; printf("%s%d", j ? "," : "", f2 ? (int)(f2 - g->faces) : -1); } printf("]\n"); } /* dots */ for (i = 0; i < g->num_dots; i++) { grid_dot *d = g->dots + i; int j; printf("Dot %d: dots[", i); for (j = 0; j < d->order; j++) { grid_edge *e = d->edges[j]; grid_dot *d2 = (e->dot1 == d) ? e->dot2 : e->dot1; printf("%s%d", j ? "," : "", (int)(d2 - g->dots)); } printf("] faces["); for (j = 0; j < d->order; j++) { grid_face *f = d->faces[j]; printf("%s%d", j ? "," : "", f ? (int)(f - g->faces) : -1); } printf("]\n"); } #endif #ifdef SVG_GRID grid_try_svg(g, SVG_DOTS | SVG_EDGES | SVG_FACES); #endif } /* Helper function for building incomplete-edges list in * grid_make_consistent() */ static int grid_edge_bydots_cmpfn(void *v1, void *v2) { grid_edge *a = v1; grid_edge *b = v2; grid_dot *da, *db; /* Pointer subtraction is valid here, because all dots point into the * same dot-list (g->dots). * Edges are not "normalised" - the 2 dots could be stored in any order, * so we need to take this into account when comparing edges. */ /* Compare first dots */ da = (a->dot1 < a->dot2) ? a->dot1 : a->dot2; db = (b->dot1 < b->dot2) ? b->dot1 : b->dot2; if (da != db) return db - da; /* Compare last dots */ da = (a->dot1 < a->dot2) ? a->dot2 : a->dot1; db = (b->dot1 < b->dot2) ? b->dot2 : b->dot1; if (da != db) return db - da; return 0; } /* * 'Vigorously trim' a grid, by which I mean deleting any isolated or * uninteresting faces. By which, in turn, I mean: ensure that the * grid is composed solely of faces adjacent to at least one * 'landlocked' dot (i.e. one not in contact with the infinite * exterior face), and that all those dots are in a single connected * component. * * This function operates on, and returns, a grid satisfying the * preconditions to grid_make_consistent() rather than the * postconditions. (So call it first.) */ static void grid_trim_vigorously(grid *g) { int *dotpairs, *faces, *dots; int *dsf; int i, j, k, size, newfaces, newdots; /* * First construct a matrix in which each ordered pair of dots is * mapped to the index of the face in which those dots occur in * that order. */ dotpairs = snewn(g->num_dots * g->num_dots, int); for (i = 0; i < g->num_dots; i++) for (j = 0; j < g->num_dots; j++) dotpairs[i*g->num_dots+j] = -1; for (i = 0; i < g->num_faces; i++) { grid_face *f = g->faces + i; int dot0 = f->dots[f->order-1] - g->dots; for (j = 0; j < f->order; j++) { int dot1 = f->dots[j] - g->dots; dotpairs[dot0 * g->num_dots + dot1] = i; dot0 = dot1; } } /* * Now we can identify landlocked dots: they're the ones all of * whose edges have a mirror-image counterpart in this matrix. */ dots = snewn(g->num_dots, int); for (i = 0; i < g->num_dots; i++) { dots[i] = TRUE; for (j = 0; j < g->num_dots; j++) { if ((dotpairs[i*g->num_dots+j] >= 0) ^ (dotpairs[j*g->num_dots+i] >= 0)) dots[i] = FALSE; /* non-duplicated edge: coastal dot */ } } /* * Now identify connected pairs of landlocked dots, and form a dsf * unifying them. */ dsf = snew_dsf(g->num_dots); for (i = 0; i < g->num_dots; i++) for (j = 0; j < i; j++) if (dots[i] && dots[j] && dotpairs[i*g->num_dots+j] >= 0 && dotpairs[j*g->num_dots+i] >= 0) dsf_merge(dsf, i, j); /* * Now look for the largest component. */ size = 0; j = -1; for (i = 0; i < g->num_dots; i++) { int newsize; if (dots[i] && dsf_canonify(dsf, i) == i && (newsize = dsf_size(dsf, i)) > size) { j = i; size = newsize; } } /* * Work out which faces we're going to keep (precisely those with * at least one dot in the same connected component as j) and * which dots (those required by any face we're keeping). * * At this point we reuse the 'dots' array to indicate the dots * we're keeping, rather than the ones that are landlocked. */ faces = snewn(g->num_faces, int); for (i = 0; i < g->num_faces; i++) faces[i] = 0; for (i = 0; i < g->num_dots; i++) dots[i] = 0; for (i = 0; i < g->num_faces; i++) { grid_face *f = g->faces + i; int keep = FALSE; for (k = 0; k < f->order; k++) if (dsf_canonify(dsf, f->dots[k] - g->dots) == j) keep = TRUE; if (keep) { faces[i] = TRUE; for (k = 0; k < f->order; k++) dots[f->dots[k]-g->dots] = TRUE; } } /* * Work out the new indices of those faces and dots, when we * compact the arrays containing them. */ for (i = newfaces = 0; i < g->num_faces; i++) faces[i] = (faces[i] ? newfaces++ : -1); for (i = newdots = 0; i < g->num_dots; i++) dots[i] = (dots[i] ? newdots++ : -1); /* * Free the dynamically allocated 'dots' pointer lists in faces * we're going to discard. */ for (i = 0; i < g->num_faces; i++) if (faces[i] < 0) sfree(g->faces[i].dots); /* * Go through and compact the arrays. */ for (i = 0; i < g->num_dots; i++) if (dots[i] >= 0) { grid_dot *dnew = g->dots + dots[i], *dold = g->dots + i; *dnew = *dold; /* structure copy */ } for (i = 0; i < g->num_faces; i++) if (faces[i] >= 0) { grid_face *fnew = g->faces + faces[i], *fold = g->faces + i; *fnew = *fold; /* structure copy */ for (j = 0; j < fnew->order; j++) { /* * Reindex the dots in this face. */ k = fnew->dots[j] - g->dots; fnew->dots[j] = g->dots + dots[k]; } } g->num_faces = newfaces; g->num_dots = newdots; sfree(dotpairs); sfree(dsf); sfree(dots); sfree(faces); } /* Input: grid has its dots and faces initialised: * - dots have (optionally) x and y coordinates, but no edges or faces * (pointers are NULL). * - edges not initialised at all * - faces initialised and know which dots they have (but no edges yet). The * dots around each face are assumed to be clockwise. * * Output: grid is complete and valid with all relationships defined. */ static void grid_make_consistent(grid *g) { int i; tree234 *incomplete_edges; grid_edge *next_new_edge; /* Where new edge will go into g->edges */ grid_debug_basic(g); /* ====== Stage 1 ====== * Generate edges */ /* We know how many dots and faces there are, so we can find the exact * number of edges from Euler's polyhedral formula: F + V = E + 2 . * We use "-1", not "-2" here, because Euler's formula includes the * infinite face, which we don't count. */ g->num_edges = g->num_faces + g->num_dots - 1; g->edges = snewn(g->num_edges, grid_edge); next_new_edge = g->edges; /* Iterate over faces, and over each face's dots, generating edges as we * go. As we find each new edge, we can immediately fill in the edge's * dots, but only one of the edge's faces. Later on in the iteration, we * will find the same edge again (unless it's on the border), but we will * know the other face. * For efficiency, maintain a list of the incomplete edges, sorted by * their dots. */ incomplete_edges = newtree234(grid_edge_bydots_cmpfn); for (i = 0; i < g->num_faces; i++) { grid_face *f = g->faces + i; int j; for (j = 0; j < f->order; j++) { grid_edge e; /* fake edge for searching */ grid_edge *edge_found; int j2 = j + 1; if (j2 == f->order) j2 = 0; e.dot1 = f->dots[j]; e.dot2 = f->dots[j2]; /* Use del234 instead of find234, because we always want to * remove the edge if found */ edge_found = del234(incomplete_edges, &e); if (edge_found) { /* This edge already added, so fill out missing face. * Edge is already removed from incomplete_edges. */ edge_found->face2 = f; } else { assert(next_new_edge - g->edges < g->num_edges); next_new_edge->dot1 = e.dot1; next_new_edge->dot2 = e.dot2; next_new_edge->face1 = f; next_new_edge->face2 = NULL; /* potentially infinite face */ add234(incomplete_edges, next_new_edge); ++next_new_edge; } } } freetree234(incomplete_edges); /* ====== Stage 2 ====== * For each face, build its edge list. */ /* Allocate space for each edge list. Can do this, because each face's * edge-list is the same size as its dot-list. */ for (i = 0; i < g->num_faces; i++) { grid_face *f = g->faces + i; int j; f->edges = snewn(f->order, grid_edge*); /* Preload with NULLs, to help detect potential bugs. */ for (j = 0; j < f->order; j++) f->edges[j] = NULL; } /* Iterate over each edge, and over both its faces. Add this edge to * the face's edge-list, after finding where it should go in the * sequence. */ for (i = 0; i < g->num_edges; i++) { grid_edge *e = g->edges + i; int j; for (j = 0; j < 2; j++) { grid_face *f = j ? e->face2 : e->face1; int k, k2; if (f == NULL) continue; /* Find one of the dots around the face */ for (k = 0; k < f->order; k++) { if (f->dots[k] == e->dot1) break; /* found dot1 */ } assert(k != f->order); /* Must find the dot around this face */ /* Labelling scheme: as we walk clockwise around the face, * starting at dot0 (f->dots[0]), we hit: * (dot0), edge0, dot1, edge1, dot2,... * * 0 * 0-----1 * | * |1 * | * 3-----2 * 2 * * Therefore, edgeK joins dotK and dot{K+1} */ /* Around this face, either the next dot or the previous dot * must be e->dot2. Otherwise the edge is wrong. */ k2 = k + 1; if (k2 == f->order) k2 = 0; if (f->dots[k2] == e->dot2) { /* dot1(k) and dot2(k2) go clockwise around this face, so add * this edge at position k (see diagram). */ assert(f->edges[k] == NULL); f->edges[k] = e; continue; } /* Try previous dot */ k2 = k - 1; if (k2 == -1) k2 = f->order - 1; if (f->dots[k2] == e->dot2) { /* dot1(k) and dot2(k2) go anticlockwise around this face. */ assert(f->edges[k2] == NULL); f->edges[k2] = e; continue; } assert(!"Grid broken: bad edge-face relationship"); } } /* ====== Stage 3 ====== * For each dot, build its edge-list and face-list. */ /* We don't know how many edges/faces go around each dot, so we can't * allocate the right space for these lists. Pre-compute the sizes by * iterating over each edge and recording a tally against each dot. */ for (i = 0; i < g->num_dots; i++) { g->dots[i].order = 0; } for (i = 0; i < g->num_edges; i++) { grid_edge *e = g->edges + i; ++(e->dot1->order); ++(e->dot2->order); } /* Now we have the sizes, pre-allocate the edge and face lists. */ for (i = 0; i < g->num_dots; i++) { grid_dot *d = g->dots + i; int j; assert(d->order >= 2); /* sanity check */ d->edges = snewn(d->order, grid_edge*); d->faces = snewn(d->order, grid_face*); for (j = 0; j < d->order; j++) { d->edges[j] = NULL; d->faces[j] = NULL; } } /* For each dot, need to find a face that touches it, so we can seed * the edge-face-edge-face process around each dot. */ for (i = 0; i < g->num_faces; i++) { grid_face *f = g->faces + i; int j; for (j = 0; j < f->order; j++) { grid_dot *d = f->dots[j]; d->faces[0] = f; } } /* Each dot now has a face in its first slot. Generate the remaining * faces and edges around the dot, by searching both clockwise and * anticlockwise from the first face. Need to do both directions, * because of the possibility of hitting the infinite face, which * blocks progress. But there's only one such face, so we will * succeed in finding every edge and face this way. */ for (i = 0; i < g->num_dots; i++) { grid_dot *d = g->dots + i; int current_face1 = 0; /* ascends clockwise */ int current_face2 = 0; /* descends anticlockwise */ /* Labelling scheme: as we walk clockwise around the dot, starting * at face0 (d->faces[0]), we hit: * (face0), edge0, face1, edge1, face2,... * * 0 * | * 0 | 1 * | * -----d-----1 * | * | 2 * | * 2 * * So, for example, face1 should be joined to edge0 and edge1, * and those edges should appear in an anticlockwise sense around * that face (see diagram). */ /* clockwise search */ while (TRUE) { grid_face *f = d->faces[current_face1]; grid_edge *e; int j; assert(f != NULL); /* find dot around this face */ for (j = 0; j < f->order; j++) { if (f->dots[j] == d) break; } assert(j != f->order); /* must find dot */ /* Around f, required edge is anticlockwise from the dot. See * the other labelling scheme higher up, for why we subtract 1 * from j. */ j--; if (j == -1) j = f->order - 1; e = f->edges[j]; d->edges[current_face1] = e; /* set edge */ current_face1++; if (current_face1 == d->order) break; else { /* set face */ d->faces[current_face1] = (e->face1 == f) ? e->face2 : e->face1; if (d->faces[current_face1] == NULL) break; /* cannot progress beyond infinite face */ } } /* If the clockwise search made it all the way round, don't need to * bother with the anticlockwise search. */ if (current_face1 == d->order) continue; /* this dot is complete, move on to next dot */ /* anticlockwise search */ while (TRUE) { grid_face *f = d->faces[current_face2]; grid_edge *e; int j; assert(f != NULL); /* find dot around this face */ for (j = 0; j < f->order; j++) { if (f->dots[j] == d) break; } assert(j != f->order); /* must find dot */ /* Around f, required edge is clockwise from the dot. */ e = f->edges[j]; current_face2--; if (current_face2 == -1) current_face2 = d->order - 1; d->edges[current_face2] = e; /* set edge */ /* set face */ if (current_face2 == current_face1) break; d->faces[current_face2] = (e->face1 == f) ? e->face2 : e->face1; /* There's only 1 infinite face, so we must get all the way * to current_face1 before we hit it. */ assert(d->faces[current_face2]); } } /* ====== Stage 4 ====== * Compute other grid settings */ /* Bounding rectangle */ for (i = 0; i < g->num_dots; i++) { grid_dot *d = g->dots + i; if (i == 0) { g->lowest_x = g->highest_x = d->x; g->lowest_y = g->highest_y = d->y; } else { g->lowest_x = min(g->lowest_x, d->x); g->highest_x = max(g->highest_x, d->x); g->lowest_y = min(g->lowest_y, d->y); g->highest_y = max(g->highest_y, d->y); } } grid_debug_derived(g); } /* Helpers for making grid-generation easier. These functions are only * intended for use during grid generation. */ /* Comparison function for the (tree234) sorted dot list */ static int grid_point_cmp_fn(void *v1, void *v2) { grid_dot *p1 = v1; grid_dot *p2 = v2; if (p1->y != p2->y) return p2->y - p1->y; else return p2->x - p1->x; } /* Add a new face to the grid, with its dot list allocated. * Assumes there's enough space allocated for the new face in grid->faces */ static void grid_face_add_new(grid *g, int face_size) { int i; grid_face *new_face = g->faces + g->num_faces; new_face->order = face_size; new_face->dots = snewn(face_size, grid_dot*); for (i = 0; i < face_size; i++) new_face->dots[i] = NULL; new_face->edges = NULL; new_face->has_incentre = FALSE; g->num_faces++; } /* Assumes dot list has enough space */ static grid_dot *grid_dot_add_new(grid *g, int x, int y) { grid_dot *new_dot = g->dots + g->num_dots; new_dot->order = 0; new_dot->edges = NULL; new_dot->faces = NULL; new_dot->x = x; new_dot->y = y; g->num_dots++; return new_dot; } /* Retrieve a dot with these (x,y) coordinates. Either return an existing dot * in the dot_list, or add a new dot to the grid (and the dot_list) and * return that. * Assumes g->dots has enough capacity allocated */ static grid_dot *grid_get_dot(grid *g, tree234 *dot_list, int x, int y) { grid_dot test, *ret; test.order = 0; test.edges = NULL; test.faces = NULL; test.x = x; test.y = y; ret = find234(dot_list, &test, NULL); if (ret) return ret; ret = grid_dot_add_new(g, x, y); add234(dot_list, ret); return ret; } /* Sets the last face of the grid to include this dot, at this position * around the face. Assumes num_faces is at least 1 (a new face has * previously been added, with the required number of dots allocated) */ static void grid_face_set_dot(grid *g, grid_dot *d, int position) { grid_face *last_face = g->faces + g->num_faces - 1; last_face->dots[position] = d; } /* * Helper routines for grid_find_incentre. */ static int solve_2x2_matrix(double mx[4], double vin[2], double vout[2]) { double inv[4]; double det; det = (mx[0]*mx[3] - mx[1]*mx[2]); if (det == 0) return FALSE; inv[0] = mx[3] / det; inv[1] = -mx[1] / det; inv[2] = -mx[2] / det; inv[3] = mx[0] / det; vout[0] = inv[0]*vin[0] + inv[1]*vin[1]; vout[1] = inv[2]*vin[0] + inv[3]*vin[1]; return TRUE; } static int solve_3x3_matrix(double mx[9], double vin[3], double vout[3]) { double inv[9]; double det; det = (mx[0]*mx[4]*mx[8] + mx[1]*mx[5]*mx[6] + mx[2]*mx[3]*mx[7] - mx[0]*mx[5]*mx[7] - mx[1]*mx[3]*mx[8] - mx[2]*mx[4]*mx[6]); if (det == 0) return FALSE; inv[0] = (mx[4]*mx[8] - mx[5]*mx[7]) / det; inv[1] = (mx[2]*mx[7] - mx[1]*mx[8]) / det; inv[2] = (mx[1]*mx[5] - mx[2]*mx[4]) / det; inv[3] = (mx[5]*mx[6] - mx[3]*mx[8]) / det; inv[4] = (mx[0]*mx[8] - mx[2]*mx[6]) / det; inv[5] = (mx[2]*mx[3] - mx[0]*mx[5]) / det; inv[6] = (mx[3]*mx[7] - mx[4]*mx[6]) / det; inv[7] = (mx[1]*mx[6] - mx[0]*mx[7]) / det; inv[8] = (mx[0]*mx[4] - mx[1]*mx[3]) / det; vout[0] = inv[0]*vin[0] + inv[1]*vin[1] + inv[2]*vin[2]; vout[1] = inv[3]*vin[0] + inv[4]*vin[1] + inv[5]*vin[2]; vout[2] = inv[6]*vin[0] + inv[7]*vin[1] + inv[8]*vin[2]; return TRUE; } void grid_find_incentre(grid_face *f) { double xbest, ybest, bestdist; int i, j, k, m; grid_dot *edgedot1[3], *edgedot2[3]; grid_dot *dots[3]; int nedges, ndots; if (f->has_incentre) return; /* * Find the point in the polygon with the maximum distance to any * edge or corner. * * Such a point must exist which is in contact with at least three * edges and/or vertices. (Proof: if it's only in contact with two * edges and/or vertices, it can't even be at a _local_ maximum - * any such circle can always be expanded in some direction.) So * we iterate through all 3-subsets of the combined set of edges * and vertices; for each subset we generate one or two candidate * points that might be the incentre, and then we vet each one to * see if it's inside the polygon and what its maximum radius is. * * (There's one case which this algorithm will get noticeably * wrong, and that's when a continuum of equally good answers * exists due to parallel edges. Consider a long thin rectangle, * for instance, or a parallelogram. This algorithm will pick a * point near one end, and choose the end arbitrarily; obviously a * nicer point to choose would be in the centre. To fix this I * would have to introduce a special-case system which detected * parallel edges in advance, set aside all candidate points * generated using both edges in a parallel pair, and generated * some additional candidate points half way between them. Also, * of course, I'd have to cope with rounding error making such a * point look worse than one of its endpoints. So I haven't done * this for the moment, and will cross it if necessary when I come * to it.) * * We don't actually iterate literally over _edges_, in the sense * of grid_edge structures. Instead, we fill in edgedot1[] and * edgedot2[] with a pair of dots adjacent in the face's list of * vertices. This ensures that we get the edges in consistent * orientation, which we could not do from the grid structure * alone. (A moment's consideration of an order-3 vertex should * make it clear that if a notional arrow was written on each * edge, _at least one_ of the three faces bordering that vertex * would have to have the two arrows tip-to-tip or tail-to-tail * rather than tip-to-tail.) */ nedges = ndots = 0; bestdist = 0; xbest = ybest = 0; for (i = 0; i+2 < 2*f->order; i++) { if (i < f->order) { edgedot1[nedges] = f->dots[i]; edgedot2[nedges++] = f->dots[(i+1)%f->order]; } else dots[ndots++] = f->dots[i - f->order]; for (j = i+1; j+1 < 2*f->order; j++) { if (j < f->order) { edgedot1[nedges] = f->dots[j]; edgedot2[nedges++] = f->dots[(j+1)%f->order]; } else dots[ndots++] = f->dots[j - f->order]; for (k = j+1; k < 2*f->order; k++) { double cx[2], cy[2]; /* candidate positions */ int cn = 0; /* number of candidates */ if (k < f->order) { edgedot1[nedges] = f->dots[k]; edgedot2[nedges++] = f->dots[(k+1)%f->order]; } else dots[ndots++] = f->dots[k - f->order]; /* * Find a point, or pair of points, equidistant from * all the specified edges and/or vertices. */ if (nedges == 3) { /* * Three edges. This is a linear matrix equation: * each row of the matrix represents the fact that * the point (x,y) we seek is at distance r from * that edge, and we solve three of those * simultaneously to obtain x,y,r. (We ignore r.) */ double matrix[9], vector[3], vector2[3]; int m; for (m = 0; m < 3; m++) { int x1 = edgedot1[m]->x, x2 = edgedot2[m]->x; int y1 = edgedot1[m]->y, y2 = edgedot2[m]->y; int dx = x2-x1, dy = y2-y1; /* * ((x,y) - (x1,y1)) . (dy,-dx) = r |(dx,dy)| * * => x dy - y dx - r |(dx,dy)| = (x1 dy - y1 dx) */ matrix[3*m+0] = dy; matrix[3*m+1] = -dx; matrix[3*m+2] = -sqrt((double)dx*dx+(double)dy*dy); vector[m] = (double)x1*dy - (double)y1*dx; } if (solve_3x3_matrix(matrix, vector, vector2)) { cx[cn] = vector2[0]; cy[cn] = vector2[1]; cn++; } } else if (nedges == 2) { /* * Two edges and a dot. This will end up in a * quadratic equation. * * First, look at the two edges. Having our point * be some distance r from both of them gives rise * to a pair of linear equations in x,y,r of the * form * * (x-x1) dy - (y-y1) dx = r sqrt(dx^2+dy^2) * * We eliminate r between those equations to give * us a single linear equation in x,y describing * the locus of points equidistant from both lines * - i.e. the angle bisector. * * We then choose one of x,y to be a parameter t, * and derive linear formulae for x,y,r in terms * of t. This enables us to write down the * circular equation (x-xd)^2+(y-yd)^2=r^2 as a * quadratic in t; solving that and substituting * in for x,y gives us two candidate points. */ double eqs[2][4]; /* a,b,c,d : ax+by+cr=d */ double eq[3]; /* a,b,c: ax+by=c */ double xt[2], yt[2], rt[2]; /* a,b: {x,y,r}=at+b */ double q[3]; /* a,b,c: at^2+bt+c=0 */ double disc; /* Find equations of the two input lines. */ for (m = 0; m < 2; m++) { int x1 = edgedot1[m]->x, x2 = edgedot2[m]->x; int y1 = edgedot1[m]->y, y2 = edgedot2[m]->y; int dx = x2-x1, dy = y2-y1; eqs[m][0] = dy; eqs[m][1] = -dx; eqs[m][2] = -sqrt(dx*dx+dy*dy); eqs[m][3] = x1*dy - y1*dx; } /* Derive the angle bisector by eliminating r. */ eq[0] = eqs[0][0]*eqs[1][2] - eqs[1][0]*eqs[0][2]; eq[1] = eqs[0][1]*eqs[1][2] - eqs[1][1]*eqs[0][2]; eq[2] = eqs[0][3]*eqs[1][2] - eqs[1][3]*eqs[0][2]; /* Parametrise x and y in terms of some t. */ if (fabs(eq[0]) < fabs(eq[1])) { /* Parameter is x. */ xt[0] = 1; xt[1] = 0; yt[0] = -eq[0]/eq[1]; yt[1] = eq[2]/eq[1]; } else { /* Parameter is y. */ yt[0] = 1; yt[1] = 0; xt[0] = -eq[1]/eq[0]; xt[1] = eq[2]/eq[0]; } /* Find a linear representation of r using eqs[0]. */ rt[0] = -(eqs[0][0]*xt[0] + eqs[0][1]*yt[0])/eqs[0][2]; rt[1] = (eqs[0][3] - eqs[0][0]*xt[1] - eqs[0][1]*yt[1])/eqs[0][2]; /* Construct the quadratic equation. */ q[0] = -rt[0]*rt[0]; q[1] = -2*rt[0]*rt[1]; q[2] = -rt[1]*rt[1]; q[0] += xt[0]*xt[0]; q[1] += 2*xt[0]*(xt[1]-dots[0]->x); q[2] += (xt[1]-dots[0]->x)*(xt[1]-dots[0]->x); q[0] += yt[0]*yt[0]; q[1] += 2*yt[0]*(yt[1]-dots[0]->y); q[2] += (yt[1]-dots[0]->y)*(yt[1]-dots[0]->y); /* And solve it. */ disc = q[1]*q[1] - 4*q[0]*q[2]; if (disc >= 0) { double t; disc = sqrt(disc); t = (-q[1] + disc) / (2*q[0]); cx[cn] = xt[0]*t + xt[1]; cy[cn] = yt[0]*t + yt[1]; cn++; t = (-q[1] - disc) / (2*q[0]); cx[cn] = xt[0]*t + xt[1]; cy[cn] = yt[0]*t + yt[1]; cn++; } } else if (nedges == 1) { /* * Two dots and an edge. This one's another * quadratic equation. * * The point we want must lie on the perpendicular * bisector of the two dots; that much is obvious. * So we can construct a parametrisation of that * bisecting line, giving linear formulae for x,y * in terms of t. We can also express the distance * from the edge as such a linear formula. * * Then we set that equal to the radius of the * circle passing through the two points, which is * a Pythagoras exercise; that gives rise to a * quadratic in t, which we solve. */ double xt[2], yt[2], rt[2]; /* a,b: {x,y,r}=at+b */ double q[3]; /* a,b,c: at^2+bt+c=0 */ double disc; double halfsep; /* Find parametric formulae for x,y. */ { int x1 = dots[0]->x, x2 = dots[1]->x; int y1 = dots[0]->y, y2 = dots[1]->y; int dx = x2-x1, dy = y2-y1; double d = sqrt((double)dx*dx + (double)dy*dy); xt[1] = (x1+x2)/2.0; yt[1] = (y1+y2)/2.0; /* It's convenient if we have t at standard scale. */ xt[0] = -dy/d; yt[0] = dx/d; /* Also note down half the separation between * the dots, for use in computing the circle radius. */ halfsep = 0.5*d; } /* Find a parametric formula for r. */ { int x1 = edgedot1[0]->x, x2 = edgedot2[0]->x; int y1 = edgedot1[0]->y, y2 = edgedot2[0]->y; int dx = x2-x1, dy = y2-y1; double d = sqrt((double)dx*dx + (double)dy*dy); rt[0] = (xt[0]*dy - yt[0]*dx) / d; rt[1] = ((xt[1]-x1)*dy - (yt[1]-y1)*dx) / d; } /* Construct the quadratic equation. */ q[0] = rt[0]*rt[0]; q[1] = 2*rt[0]*rt[1]; q[2] = rt[1]*rt[1]; q[0] -= 1; q[2] -= halfsep*halfsep; /* And solve it. */ disc = q[1]*q[1] - 4*q[0]*q[2]; if (disc >= 0) { double t; disc = sqrt(disc); t = (-q[1] + disc) / (2*q[0]); cx[cn] = xt[0]*t + xt[1]; cy[cn] = yt[0]*t + yt[1]; cn++; t = (-q[1] - disc) / (2*q[0]); cx[cn] = xt[0]*t + xt[1]; cy[cn] = yt[0]*t + yt[1]; cn++; } } else if (nedges == 0) { /* * Three dots. This is another linear matrix * equation, this time with each row of the matrix * representing the perpendicular bisector between * two of the points. Of course we only need two * such lines to find their intersection, so we * need only solve a 2x2 matrix equation. */ double matrix[4], vector[2], vector2[2]; int m; for (m = 0; m < 2; m++) { int x1 = dots[m]->x, x2 = dots[m+1]->x; int y1 = dots[m]->y, y2 = dots[m+1]->y; int dx = x2-x1, dy = y2-y1; /* * ((x,y) - (x1,y1)) . (dx,dy) = 1/2 |(dx,dy)|^2 * * => 2x dx + 2y dy = dx^2+dy^2 + (2 x1 dx + 2 y1 dy) */ matrix[2*m+0] = 2*dx; matrix[2*m+1] = 2*dy; vector[m] = ((double)dx*dx + (double)dy*dy + 2.0*x1*dx + 2.0*y1*dy); } if (solve_2x2_matrix(matrix, vector, vector2)) { cx[cn] = vector2[0]; cy[cn] = vector2[1]; cn++; } } /* * Now go through our candidate points and see if any * of them are better than what we've got so far. */ for (m = 0; m < cn; m++) { double x = cx[m], y = cy[m]; /* * First, disqualify the point if it's not inside * the polygon, which we work out by counting the * edges to the right of the point. (For * tiebreaking purposes when edges start or end on * our y-coordinate or go right through it, we * consider our point to be offset by a small * _positive_ epsilon in both the x- and * y-direction.) */ int e, in = 0; for (e = 0; e < f->order; e++) { int xs = f->edges[e]->dot1->x; int xe = f->edges[e]->dot2->x; int ys = f->edges[e]->dot1->y; int ye = f->edges[e]->dot2->y; if ((y >= ys && y < ye) || (y >= ye && y < ys)) { /* * The line goes past our y-position. Now we need * to know if its x-coordinate when it does so is * to our right. * * The x-coordinate in question is mathematically * (y - ys) * (xe - xs) / (ye - ys), and we want * to know whether (x - xs) >= that. Of course we * avoid the division, so we can work in integers; * to do this we must multiply both sides of the * inequality by ye - ys, which means we must * first check that's not negative. */ int num = xe - xs, denom = ye - ys; if (denom < 0) { num = -num; denom = -denom; } if ((x - xs) * denom >= (y - ys) * num) in ^= 1; } } if (in) { #ifdef HUGE_VAL double mindist = HUGE_VAL; #else #ifdef DBL_MAX double mindist = DBL_MAX; #else #error No way to get maximum floating-point number. #endif #endif int e, d; /* * This point is inside the polygon, so now we check * its minimum distance to every edge and corner. * First the corners ... */ for (d = 0; d < f->order; d++) { int xp = f->dots[d]->x; int yp = f->dots[d]->y; double dx = x - xp, dy = y - yp; double dist = dx*dx + dy*dy; if (mindist > dist) mindist = dist; } /* * ... and now also check the perpendicular distance * to every edge, if the perpendicular lies between * the edge's endpoints. */ for (e = 0; e < f->order; e++) { int xs = f->edges[e]->dot1->x; int xe = f->edges[e]->dot2->x; int ys = f->edges[e]->dot1->y; int ye = f->edges[e]->dot2->y; /* * If s and e are our endpoints, and p our * candidate circle centre, the foot of a * perpendicular from p to the line se lies * between s and e if and only if (p-s).(e-s) lies * strictly between 0 and (e-s).(e-s). */ int edx = xe - xs, edy = ye - ys; double pdx = x - xs, pdy = y - ys; double pde = pdx * edx + pdy * edy; long ede = (long)edx * edx + (long)edy * edy; if (0 < pde && pde < ede) { /* * Yes, the nearest point on this edge is * closer than either endpoint, so we must * take it into account by measuring the * perpendicular distance to the edge and * checking its square against mindist. */ double pdre = pdx * edy - pdy * edx; double sqlen = pdre * pdre / ede; if (mindist > sqlen) mindist = sqlen; } } /* * Right. Now we know the biggest circle around this * point, so we can check it against bestdist. */ if (bestdist < mindist) { bestdist = mindist; xbest = x; ybest = y; } } } if (k < f->order) nedges--; else ndots--; } if (j < f->order) nedges--; else ndots--; } if (i < f->order) nedges--; else ndots--; } assert(bestdist > 0); f->has_incentre = TRUE; f->ix = xbest + 0.5; /* round to nearest */ f->iy = ybest + 0.5; } /* ------ Generate various types of grid ------ */ /* General method is to generate faces, by calculating their dot coordinates. * As new faces are added, we keep track of all the dots so we can tell when * a new face reuses an existing dot. For example, two squares touching at an * edge would generate six unique dots: four dots from the first face, then * two additional dots for the second face, because we detect the other two * dots have already been taken up. This list is stored in a tree234 * called "points". No extra memory-allocation needed here - we store the * actual grid_dot* pointers, which all point into the g->dots list. * For this reason, we have to calculate coordinates in such a way as to * eliminate any rounding errors, so we can detect when a dot on one * face precisely lands on a dot of a different face. No floating-point * arithmetic here! */ #define SQUARE_TILESIZE 20 static void grid_size_square(int width, int height, int *tilesize, int *xextent, int *yextent) { int a = SQUARE_TILESIZE; *tilesize = a; *xextent = width * a; *yextent = height * a; } static grid *grid_new_square(int width, int height, const char *desc) { int x, y; /* Side length */ int a = SQUARE_TILESIZE; /* Upper bounds - don't have to be exact */ int max_faces = width * height; int max_dots = (width + 1) * (height + 1); tree234 *points; grid *g = grid_empty(); g->tilesize = a; g->faces = snewn(max_faces, grid_face); g->dots = snewn(max_dots, grid_dot); points = newtree234(grid_point_cmp_fn); /* generate square faces */ for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { grid_dot *d; /* face position */ int px = a * x; int py = a * y; grid_face_add_new(g, 4); d = grid_get_dot(g, points, px, py); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px + a, py); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px + a, py + a); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, px, py + a); grid_face_set_dot(g, d, 3); } } freetree234(points); assert(g->num_faces <= max_faces); assert(g->num_dots <= max_dots); grid_make_consistent(g); return g; } #define HONEY_TILESIZE 45 /* Vector for side of hexagon - ratio is close to sqrt(3) */ #define HONEY_A 15 #define HONEY_B 26 static void grid_size_honeycomb(int width, int height, int *tilesize, int *xextent, int *yextent) { int a = HONEY_A; int b = HONEY_B; *tilesize = HONEY_TILESIZE; *xextent = (3 * a * (width-1)) + 4*a; *yextent = (2 * b * (height-1)) + 3*b; } static grid *grid_new_honeycomb(int width, int height, const char *desc) { int x, y; int a = HONEY_A; int b = HONEY_B; /* Upper bounds - don't have to be exact */ int max_faces = width * height; int max_dots = 2 * (width + 1) * (height + 1); tree234 *points; grid *g = grid_empty(); g->tilesize = HONEY_TILESIZE; g->faces = snewn(max_faces, grid_face); g->dots = snewn(max_dots, grid_dot); points = newtree234(grid_point_cmp_fn); /* generate hexagonal faces */ for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { grid_dot *d; /* face centre */ int cx = 3 * a * x; int cy = 2 * b * y; if (x % 2) cy += b; grid_face_add_new(g, 6); d = grid_get_dot(g, points, cx - a, cy - b); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, cx + a, cy - b); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, cx + 2*a, cy); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, cx + a, cy + b); grid_face_set_dot(g, d, 3); d = grid_get_dot(g, points, cx - a, cy + b); grid_face_set_dot(g, d, 4); d = grid_get_dot(g, points, cx - 2*a, cy); grid_face_set_dot(g, d, 5); } } freetree234(points); assert(g->num_faces <= max_faces); assert(g->num_dots <= max_dots); grid_make_consistent(g); return g; } #define TRIANGLE_TILESIZE 18 /* Vector for side of triangle - ratio is close to sqrt(3) */ #define TRIANGLE_VEC_X 15 #define TRIANGLE_VEC_Y 26 static void grid_size_triangular(int width, int height, int *tilesize, int *xextent, int *yextent) { int vec_x = TRIANGLE_VEC_X; int vec_y = TRIANGLE_VEC_Y; *tilesize = TRIANGLE_TILESIZE; *xextent = (width+1) * 2 * vec_x; *yextent = height * vec_y; } static char *grid_validate_desc_triangular(grid_type type, int width, int height, const char *desc) { /* * Triangular grids: an absent description is valid (indicating * the old-style approach which had 'ears', i.e. triangles * connected to only one other face, at some grid corners), and so * is a description reading just "0" (indicating the new-style * approach in which those ears are trimmed off). Anything else is * illegal. */ if (!desc || !strcmp(desc, "0")) return NULL; return "Unrecognised grid description."; } /* Doesn't use the previous method of generation, it pre-dates it! * A triangular grid is just about simple enough to do by "brute force" */ static grid *grid_new_triangular(int width, int height, const char *desc) { int x,y; int version = (desc == NULL ? -1 : atoi(desc)); /* Vector for side of triangle - ratio is close to sqrt(3) */ int vec_x = TRIANGLE_VEC_X; int vec_y = TRIANGLE_VEC_Y; int index; /* convenient alias */ int w = width + 1; grid *g = grid_empty(); g->tilesize = TRIANGLE_TILESIZE; if (version == -1) { /* * Old-style triangular grid generation, preserved as-is for * backwards compatibility with old game ids, in which it's * just a little asymmetric and there are 'ears' (faces linked * to only one other face) at two grid corners. * * Example old-style game ids, which should still work, and in * which you should see the ears in the TL/BR corners on the * first one and in the TL/BL corners on the second: * * 5x5t1:2c2a1a2a201a1a1a1112a1a2b1211f0b21a2a2a0a * 5x6t1:a022a212h1a1d1a12c2b11a012b1a20d1a0a12e */ g->num_faces = width * height * 2; g->num_dots = (width + 1) * (height + 1); g->faces = snewn(g->num_faces, grid_face); g->dots = snewn(g->num_dots, grid_dot); /* generate dots */ index = 0; for (y = 0; y <= height; y++) { for (x = 0; x <= width; x++) { grid_dot *d = g->dots + index; /* odd rows are offset to the right */ d->order = 0; d->edges = NULL; d->faces = NULL; d->x = x * 2 * vec_x + ((y % 2) ? vec_x : 0); d->y = y * vec_y; index++; } } /* generate faces */ index = 0; for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { /* initialise two faces for this (x,y) */ grid_face *f1 = g->faces + index; grid_face *f2 = f1 + 1; f1->edges = NULL; f1->order = 3; f1->dots = snewn(f1->order, grid_dot*); f1->has_incentre = FALSE; f2->edges = NULL; f2->order = 3; f2->dots = snewn(f2->order, grid_dot*); f2->has_incentre = FALSE; /* face descriptions depend on whether the row-number is * odd or even */ if (y % 2) { f1->dots[0] = g->dots + y * w + x; f1->dots[1] = g->dots + (y + 1) * w + x + 1; f1->dots[2] = g->dots + (y + 1) * w + x; f2->dots[0] = g->dots + y * w + x; f2->dots[1] = g->dots + y * w + x + 1; f2->dots[2] = g->dots + (y + 1) * w + x + 1; } else { f1->dots[0] = g->dots + y * w + x; f1->dots[1] = g->dots + y * w + x + 1; f1->dots[2] = g->dots + (y + 1) * w + x; f2->dots[0] = g->dots + y * w + x + 1; f2->dots[1] = g->dots + (y + 1) * w + x + 1; f2->dots[2] = g->dots + (y + 1) * w + x; } index += 2; } } } else { /* * New-style approach, in which there are never any 'ears', * and if height is even then the grid is nicely 4-way * symmetric. * * Example new-style grids: * * 5x5t1:0_21120b11a1a01a1a00c1a0b211021c1h1a2a1a0a * 5x6t1:0_a1212c22c2a02a2f22a0c12a110d0e1c0c0a101121a1 */ tree234 *points = newtree234(grid_point_cmp_fn); /* Upper bounds - don't have to be exact */ int max_faces = height * (2*width+1); int max_dots = (height+1) * (width+1) * 4; g->faces = snewn(max_faces, grid_face); g->dots = snewn(max_dots, grid_dot); for (y = 0; y < height; y++) { /* * Each row contains (width+1) triangles one way up, and * (width) triangles the other way up. Which way up is * which varies with parity of y. Also, the dots around * each face will flip direction with parity of y, so we * set up n1 and n2 to cope with that easily. */ int y0, y1, n1, n2; y0 = y1 = y * vec_y; if (y % 2) { y1 += vec_y; n1 = 2; n2 = 1; } else { y0 += vec_y; n1 = 1; n2 = 2; } for (x = 0; x <= width; x++) { int x0 = 2*x * vec_x, x1 = x0 + vec_x, x2 = x1 + vec_x; /* * If the grid has odd height, then we skip the first * and last triangles on this row, otherwise they'll * end up as ears. */ if (height % 2 == 1 && y == height-1 && (x == 0 || x == width)) continue; grid_face_add_new(g, 3); grid_face_set_dot(g, grid_get_dot(g, points, x0, y0), 0); grid_face_set_dot(g, grid_get_dot(g, points, x1, y1), n1); grid_face_set_dot(g, grid_get_dot(g, points, x2, y0), n2); } for (x = 0; x < width; x++) { int x0 = (2*x+1) * vec_x, x1 = x0 + vec_x, x2 = x1 + vec_x; grid_face_add_new(g, 3); grid_face_set_dot(g, grid_get_dot(g, points, x0, y1), 0); grid_face_set_dot(g, grid_get_dot(g, points, x1, y0), n2); grid_face_set_dot(g, grid_get_dot(g, points, x2, y1), n1); } } freetree234(points); assert(g->num_faces <= max_faces); assert(g->num_dots <= max_dots); } grid_make_consistent(g); return g; } #define SNUBSQUARE_TILESIZE 18 /* Vector for side of triangle - ratio is close to sqrt(3) */ #define SNUBSQUARE_A 15 #define SNUBSQUARE_B 26 static void grid_size_snubsquare(int width, int height, int *tilesize, int *xextent, int *yextent) { int a = SNUBSQUARE_A; int b = SNUBSQUARE_B; *tilesize = SNUBSQUARE_TILESIZE; *xextent = (a+b) * (width-1) + a + b; *yextent = (a+b) * (height-1) + a + b; } static grid *grid_new_snubsquare(int width, int height, const char *desc) { int x, y; int a = SNUBSQUARE_A; int b = SNUBSQUARE_B; /* Upper bounds - don't have to be exact */ int max_faces = 3 * width * height; int max_dots = 2 * (width + 1) * (height + 1); tree234 *points; grid *g = grid_empty(); g->tilesize = SNUBSQUARE_TILESIZE; g->faces = snewn(max_faces, grid_face); g->dots = snewn(max_dots, grid_dot); points = newtree234(grid_point_cmp_fn); for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { grid_dot *d; /* face position */ int px = (a + b) * x; int py = (a + b) * y; /* generate square faces */ grid_face_add_new(g, 4); if ((x + y) % 2) { d = grid_get_dot(g, points, px + a, py); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px + a + b, py + a); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px + b, py + a + b); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, px, py + b); grid_face_set_dot(g, d, 3); } else { d = grid_get_dot(g, points, px + b, py); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px + a + b, py + b); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px + a, py + a + b); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, px, py + a); grid_face_set_dot(g, d, 3); } /* generate up/down triangles */ if (x > 0) { grid_face_add_new(g, 3); if ((x + y) % 2) { d = grid_get_dot(g, points, px + a, py); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px, py + b); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px - a, py); grid_face_set_dot(g, d, 2); } else { d = grid_get_dot(g, points, px, py + a); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px + a, py + a + b); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px - a, py + a + b); grid_face_set_dot(g, d, 2); } } /* generate left/right triangles */ if (y > 0) { grid_face_add_new(g, 3); if ((x + y) % 2) { d = grid_get_dot(g, points, px + a, py); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px + a + b, py - a); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px + a + b, py + a); grid_face_set_dot(g, d, 2); } else { d = grid_get_dot(g, points, px, py - a); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px + b, py); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px, py + a); grid_face_set_dot(g, d, 2); } } } } freetree234(points); assert(g->num_faces <= max_faces); assert(g->num_dots <= max_dots); grid_make_consistent(g); return g; } #define CAIRO_TILESIZE 40 /* Vector for side of pentagon - ratio is close to (4+sqrt(7))/3 */ #define CAIRO_A 14 #define CAIRO_B 31 static void grid_size_cairo(int width, int height, int *tilesize, int *xextent, int *yextent) { int b = CAIRO_B; /* a unused in determining grid size. */ *tilesize = CAIRO_TILESIZE; *xextent = 2*b*(width-1) + 2*b; *yextent = 2*b*(height-1) + 2*b; } static grid *grid_new_cairo(int width, int height, const char *desc) { int x, y; int a = CAIRO_A; int b = CAIRO_B; /* Upper bounds - don't have to be exact */ int max_faces = 2 * width * height; int max_dots = 3 * (width + 1) * (height + 1); tree234 *points; grid *g = grid_empty(); g->tilesize = CAIRO_TILESIZE; g->faces = snewn(max_faces, grid_face); g->dots = snewn(max_dots, grid_dot); points = newtree234(grid_point_cmp_fn); for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { grid_dot *d; /* cell position */ int px = 2 * b * x; int py = 2 * b * y; /* horizontal pentagons */ if (y > 0) { grid_face_add_new(g, 5); if ((x + y) % 2) { d = grid_get_dot(g, points, px + a, py - b); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px + 2*b - a, py - b); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px + 2*b, py); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, px + b, py + a); grid_face_set_dot(g, d, 3); d = grid_get_dot(g, points, px, py); grid_face_set_dot(g, d, 4); } else { d = grid_get_dot(g, points, px, py); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px + b, py - a); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px + 2*b, py); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, px + 2*b - a, py + b); grid_face_set_dot(g, d, 3); d = grid_get_dot(g, points, px + a, py + b); grid_face_set_dot(g, d, 4); } } /* vertical pentagons */ if (x > 0) { grid_face_add_new(g, 5); if ((x + y) % 2) { d = grid_get_dot(g, points, px, py); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px + b, py + a); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px + b, py + 2*b - a); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, px, py + 2*b); grid_face_set_dot(g, d, 3); d = grid_get_dot(g, points, px - a, py + b); grid_face_set_dot(g, d, 4); } else { d = grid_get_dot(g, points, px, py); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px + a, py + b); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px, py + 2*b); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, px - b, py + 2*b - a); grid_face_set_dot(g, d, 3); d = grid_get_dot(g, points, px - b, py + a); grid_face_set_dot(g, d, 4); } } } } freetree234(points); assert(g->num_faces <= max_faces); assert(g->num_dots <= max_dots); grid_make_consistent(g); return g; } #define GREATHEX_TILESIZE 18 /* Vector for side of triangle - ratio is close to sqrt(3) */ #define GREATHEX_A 15 #define GREATHEX_B 26 static void grid_size_greathexagonal(int width, int height, int *tilesize, int *xextent, int *yextent) { int a = GREATHEX_A; int b = GREATHEX_B; *tilesize = GREATHEX_TILESIZE; *xextent = (3*a + b) * (width-1) + 4*a; *yextent = (2*a + 2*b) * (height-1) + 3*b + a; } static grid *grid_new_greathexagonal(int width, int height, const char *desc) { int x, y; int a = GREATHEX_A; int b = GREATHEX_B; /* Upper bounds - don't have to be exact */ int max_faces = 6 * (width + 1) * (height + 1); int max_dots = 6 * width * height; tree234 *points; grid *g = grid_empty(); g->tilesize = GREATHEX_TILESIZE; g->faces = snewn(max_faces, grid_face); g->dots = snewn(max_dots, grid_dot); points = newtree234(grid_point_cmp_fn); for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { grid_dot *d; /* centre of hexagon */ int px = (3*a + b) * x; int py = (2*a + 2*b) * y; if (x % 2) py += a + b; /* hexagon */ grid_face_add_new(g, 6); d = grid_get_dot(g, points, px - a, py - b); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px + a, py - b); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px + 2*a, py); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, px + a, py + b); grid_face_set_dot(g, d, 3); d = grid_get_dot(g, points, px - a, py + b); grid_face_set_dot(g, d, 4); d = grid_get_dot(g, points, px - 2*a, py); grid_face_set_dot(g, d, 5); /* square below hexagon */ if (y < height - 1) { grid_face_add_new(g, 4); d = grid_get_dot(g, points, px - a, py + b); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px + a, py + b); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px + a, py + 2*a + b); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, px - a, py + 2*a + b); grid_face_set_dot(g, d, 3); } /* square below right */ if ((x < width - 1) && (((x % 2) == 0) || (y < height - 1))) { grid_face_add_new(g, 4); d = grid_get_dot(g, points, px + 2*a, py); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px + 2*a + b, py + a); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px + a + b, py + a + b); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, px + a, py + b); grid_face_set_dot(g, d, 3); } /* square below left */ if ((x > 0) && (((x % 2) == 0) || (y < height - 1))) { grid_face_add_new(g, 4); d = grid_get_dot(g, points, px - 2*a, py); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px - a, py + b); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px - a - b, py + a + b); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, px - 2*a - b, py + a); grid_face_set_dot(g, d, 3); } /* Triangle below right */ if ((x < width - 1) && (y < height - 1)) { grid_face_add_new(g, 3); d = grid_get_dot(g, points, px + a, py + b); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px + a + b, py + a + b); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px + a, py + 2*a + b); grid_face_set_dot(g, d, 2); } /* Triangle below left */ if ((x > 0) && (y < height - 1)) { grid_face_add_new(g, 3); d = grid_get_dot(g, points, px - a, py + b); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px - a, py + 2*a + b); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px - a - b, py + a + b); grid_face_set_dot(g, d, 2); } } } freetree234(points); assert(g->num_faces <= max_faces); assert(g->num_dots <= max_dots); grid_make_consistent(g); return g; } #define OCTAGONAL_TILESIZE 40 /* b/a approx sqrt(2) */ #define OCTAGONAL_A 29 #define OCTAGONAL_B 41 static void grid_size_octagonal(int width, int height, int *tilesize, int *xextent, int *yextent) { int a = OCTAGONAL_A; int b = OCTAGONAL_B; *tilesize = OCTAGONAL_TILESIZE; *xextent = (2*a + b) * width; *yextent = (2*a + b) * height; } static grid *grid_new_octagonal(int width, int height, const char *desc) { int x, y; int a = OCTAGONAL_A; int b = OCTAGONAL_B; /* Upper bounds - don't have to be exact */ int max_faces = 2 * width * height; int max_dots = 4 * (width + 1) * (height + 1); tree234 *points; grid *g = grid_empty(); g->tilesize = OCTAGONAL_TILESIZE; g->faces = snewn(max_faces, grid_face); g->dots = snewn(max_dots, grid_dot); points = newtree234(grid_point_cmp_fn); for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { grid_dot *d; /* cell position */ int px = (2*a + b) * x; int py = (2*a + b) * y; /* octagon */ grid_face_add_new(g, 8); d = grid_get_dot(g, points, px + a, py); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px + a + b, py); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px + 2*a + b, py + a); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, px + 2*a + b, py + a + b); grid_face_set_dot(g, d, 3); d = grid_get_dot(g, points, px + a + b, py + 2*a + b); grid_face_set_dot(g, d, 4); d = grid_get_dot(g, points, px + a, py + 2*a + b); grid_face_set_dot(g, d, 5); d = grid_get_dot(g, points, px, py + a + b); grid_face_set_dot(g, d, 6); d = grid_get_dot(g, points, px, py + a); grid_face_set_dot(g, d, 7); /* diamond */ if ((x > 0) && (y > 0)) { grid_face_add_new(g, 4); d = grid_get_dot(g, points, px, py - a); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px + a, py); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px, py + a); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, px - a, py); grid_face_set_dot(g, d, 3); } } } freetree234(points); assert(g->num_faces <= max_faces); assert(g->num_dots <= max_dots); grid_make_consistent(g); return g; } #define KITE_TILESIZE 40 /* b/a approx sqrt(3) */ #define KITE_A 15 #define KITE_B 26 static void grid_size_kites(int width, int height, int *tilesize, int *xextent, int *yextent) { int a = KITE_A; int b = KITE_B; *tilesize = KITE_TILESIZE; *xextent = 4*b * width + 2*b; *yextent = 6*a * (height-1) + 8*a; } static grid *grid_new_kites(int width, int height, const char *desc) { int x, y; int a = KITE_A; int b = KITE_B; /* Upper bounds - don't have to be exact */ int max_faces = 6 * width * height; int max_dots = 6 * (width + 1) * (height + 1); tree234 *points; grid *g = grid_empty(); g->tilesize = KITE_TILESIZE; g->faces = snewn(max_faces, grid_face); g->dots = snewn(max_dots, grid_dot); points = newtree234(grid_point_cmp_fn); for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { grid_dot *d; /* position of order-6 dot */ int px = 4*b * x; int py = 6*a * y; if (y % 2) px += 2*b; /* kite pointing up-left */ grid_face_add_new(g, 4); d = grid_get_dot(g, points, px, py); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px + 2*b, py); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px + 2*b, py + 2*a); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, px + b, py + 3*a); grid_face_set_dot(g, d, 3); /* kite pointing up */ grid_face_add_new(g, 4); d = grid_get_dot(g, points, px, py); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px + b, py + 3*a); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px, py + 4*a); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, px - b, py + 3*a); grid_face_set_dot(g, d, 3); /* kite pointing up-right */ grid_face_add_new(g, 4); d = grid_get_dot(g, points, px, py); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px - b, py + 3*a); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px - 2*b, py + 2*a); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, px - 2*b, py); grid_face_set_dot(g, d, 3); /* kite pointing down-right */ grid_face_add_new(g, 4); d = grid_get_dot(g, points, px, py); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px - 2*b, py); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px - 2*b, py - 2*a); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, px - b, py - 3*a); grid_face_set_dot(g, d, 3); /* kite pointing down */ grid_face_add_new(g, 4); d = grid_get_dot(g, points, px, py); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px - b, py - 3*a); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px, py - 4*a); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, px + b, py - 3*a); grid_face_set_dot(g, d, 3); /* kite pointing down-left */ grid_face_add_new(g, 4); d = grid_get_dot(g, points, px, py); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px + b, py - 3*a); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px + 2*b, py - 2*a); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, px + 2*b, py); grid_face_set_dot(g, d, 3); } } freetree234(points); assert(g->num_faces <= max_faces); assert(g->num_dots <= max_dots); grid_make_consistent(g); return g; } #define FLORET_TILESIZE 150 /* -py/px is close to tan(30 - atan(sqrt(3)/9)) * using py=26 makes everything lean to the left, rather than right */ #define FLORET_PX 75 #define FLORET_PY -26 static void grid_size_floret(int width, int height, int *tilesize, int *xextent, int *yextent) { int px = FLORET_PX, py = FLORET_PY; /* |( 75, -26)| = 79.43 */ int qx = 4*px/5, qy = -py*2; /* |( 60, 52)| = 79.40 */ int ry = qy-py; /* rx unused in determining grid size. */ *tilesize = FLORET_TILESIZE; *xextent = (6*px+3*qx)/2 * (width-1) + 4*qx + 2*px; *yextent = (5*qy-4*py) * (height-1) + 4*qy + 2*ry; } static grid *grid_new_floret(int width, int height, const char *desc) { int x, y; /* Vectors for sides; weird numbers needed to keep puzzle aligned with window * -py/px is close to tan(30 - atan(sqrt(3)/9)) * using py=26 makes everything lean to the left, rather than right */ int px = FLORET_PX, py = FLORET_PY; /* |( 75, -26)| = 79.43 */ int qx = 4*px/5, qy = -py*2; /* |( 60, 52)| = 79.40 */ int rx = qx-px, ry = qy-py; /* |(-15, 78)| = 79.38 */ /* Upper bounds - don't have to be exact */ int max_faces = 6 * width * height; int max_dots = 9 * (width + 1) * (height + 1); tree234 *points; grid *g = grid_empty(); g->tilesize = FLORET_TILESIZE; g->faces = snewn(max_faces, grid_face); g->dots = snewn(max_dots, grid_dot); points = newtree234(grid_point_cmp_fn); /* generate pentagonal faces */ for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { grid_dot *d; /* face centre */ int cx = (6*px+3*qx)/2 * x; int cy = (4*py-5*qy) * y; if (x % 2) cy -= (4*py-5*qy)/2; else if (y && y == height-1) continue; /* make better looking grids? try 3x3 for instance */ grid_face_add_new(g, 5); d = grid_get_dot(g, points, cx , cy ); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, cx+2*rx , cy+2*ry ); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, cx+2*rx+qx, cy+2*ry+qy); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, cx+2*qx+rx, cy+2*qy+ry); grid_face_set_dot(g, d, 3); d = grid_get_dot(g, points, cx+2*qx , cy+2*qy ); grid_face_set_dot(g, d, 4); grid_face_add_new(g, 5); d = grid_get_dot(g, points, cx , cy ); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, cx+2*qx , cy+2*qy ); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, cx+2*qx+px, cy+2*qy+py); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, cx+2*px+qx, cy+2*py+qy); grid_face_set_dot(g, d, 3); d = grid_get_dot(g, points, cx+2*px , cy+2*py ); grid_face_set_dot(g, d, 4); grid_face_add_new(g, 5); d = grid_get_dot(g, points, cx , cy ); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, cx+2*px , cy+2*py ); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, cx+2*px-rx, cy+2*py-ry); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, cx-2*rx+px, cy-2*ry+py); grid_face_set_dot(g, d, 3); d = grid_get_dot(g, points, cx-2*rx , cy-2*ry ); grid_face_set_dot(g, d, 4); grid_face_add_new(g, 5); d = grid_get_dot(g, points, cx , cy ); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, cx-2*rx , cy-2*ry ); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, cx-2*rx-qx, cy-2*ry-qy); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, cx-2*qx-rx, cy-2*qy-ry); grid_face_set_dot(g, d, 3); d = grid_get_dot(g, points, cx-2*qx , cy-2*qy ); grid_face_set_dot(g, d, 4); grid_face_add_new(g, 5); d = grid_get_dot(g, points, cx , cy ); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, cx-2*qx , cy-2*qy ); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, cx-2*qx-px, cy-2*qy-py); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, cx-2*px-qx, cy-2*py-qy); grid_face_set_dot(g, d, 3); d = grid_get_dot(g, points, cx-2*px , cy-2*py ); grid_face_set_dot(g, d, 4); grid_face_add_new(g, 5); d = grid_get_dot(g, points, cx , cy ); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, cx-2*px , cy-2*py ); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, cx-2*px+rx, cy-2*py+ry); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, cx+2*rx-px, cy+2*ry-py); grid_face_set_dot(g, d, 3); d = grid_get_dot(g, points, cx+2*rx , cy+2*ry ); grid_face_set_dot(g, d, 4); } } freetree234(points); assert(g->num_faces <= max_faces); assert(g->num_dots <= max_dots); grid_make_consistent(g); return g; } /* DODEC_* are used for dodecagonal and great-dodecagonal grids. */ #define DODEC_TILESIZE 26 /* Vector for side of triangle - ratio is close to sqrt(3) */ #define DODEC_A 15 #define DODEC_B 26 static void grid_size_dodecagonal(int width, int height, int *tilesize, int *xextent, int *yextent) { int a = DODEC_A; int b = DODEC_B; *tilesize = DODEC_TILESIZE; *xextent = (4*a + 2*b) * (width-1) + 3*(2*a + b); *yextent = (3*a + 2*b) * (height-1) + 2*(2*a + b); } static grid *grid_new_dodecagonal(int width, int height, const char *desc) { int x, y; int a = DODEC_A; int b = DODEC_B; /* Upper bounds - don't have to be exact */ int max_faces = 3 * width * height; int max_dots = 14 * width * height; tree234 *points; grid *g = grid_empty(); g->tilesize = DODEC_TILESIZE; g->faces = snewn(max_faces, grid_face); g->dots = snewn(max_dots, grid_dot); points = newtree234(grid_point_cmp_fn); for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { grid_dot *d; /* centre of dodecagon */ int px = (4*a + 2*b) * x; int py = (3*a + 2*b) * y; if (y % 2) px += 2*a + b; /* dodecagon */ grid_face_add_new(g, 12); d = grid_get_dot(g, points, px + ( a ), py - (2*a + b)); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px + ( a + b), py - ( a + b)); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px + (2*a + b), py - ( a )); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, px + (2*a + b), py + ( a )); grid_face_set_dot(g, d, 3); d = grid_get_dot(g, points, px + ( a + b), py + ( a + b)); grid_face_set_dot(g, d, 4); d = grid_get_dot(g, points, px + ( a ), py + (2*a + b)); grid_face_set_dot(g, d, 5); d = grid_get_dot(g, points, px - ( a ), py + (2*a + b)); grid_face_set_dot(g, d, 6); d = grid_get_dot(g, points, px - ( a + b), py + ( a + b)); grid_face_set_dot(g, d, 7); d = grid_get_dot(g, points, px - (2*a + b), py + ( a )); grid_face_set_dot(g, d, 8); d = grid_get_dot(g, points, px - (2*a + b), py - ( a )); grid_face_set_dot(g, d, 9); d = grid_get_dot(g, points, px - ( a + b), py - ( a + b)); grid_face_set_dot(g, d, 10); d = grid_get_dot(g, points, px - ( a ), py - (2*a + b)); grid_face_set_dot(g, d, 11); /* triangle below dodecagon */ if ((y < height - 1 && (x < width - 1 || !(y % 2)) && (x > 0 || (y % 2)))) { grid_face_add_new(g, 3); d = grid_get_dot(g, points, px + a, py + (2*a + b)); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px , py + (2*a + 2*b)); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px - a, py + (2*a + b)); grid_face_set_dot(g, d, 2); } /* triangle above dodecagon */ if ((y && (x < width - 1 || !(y % 2)) && (x > 0 || (y % 2)))) { grid_face_add_new(g, 3); d = grid_get_dot(g, points, px - a, py - (2*a + b)); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px , py - (2*a + 2*b)); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px + a, py - (2*a + b)); grid_face_set_dot(g, d, 2); } } } freetree234(points); assert(g->num_faces <= max_faces); assert(g->num_dots <= max_dots); grid_make_consistent(g); return g; } static void grid_size_greatdodecagonal(int width, int height, int *tilesize, int *xextent, int *yextent) { int a = DODEC_A; int b = DODEC_B; *tilesize = DODEC_TILESIZE; *xextent = (6*a + 2*b) * (width-1) + 2*(2*a + b) + 3*a + b; *yextent = (3*a + 3*b) * (height-1) + 2*(2*a + b); } static grid *grid_new_greatdodecagonal(int width, int height, const char *desc) { int x, y; /* Vector for side of triangle - ratio is close to sqrt(3) */ int a = DODEC_A; int b = DODEC_B; /* Upper bounds - don't have to be exact */ int max_faces = 30 * width * height; int max_dots = 200 * width * height; tree234 *points; grid *g = grid_empty(); g->tilesize = DODEC_TILESIZE; g->faces = snewn(max_faces, grid_face); g->dots = snewn(max_dots, grid_dot); points = newtree234(grid_point_cmp_fn); for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { grid_dot *d; /* centre of dodecagon */ int px = (6*a + 2*b) * x; int py = (3*a + 3*b) * y; if (y % 2) px += 3*a + b; /* dodecagon */ grid_face_add_new(g, 12); d = grid_get_dot(g, points, px + ( a ), py - (2*a + b)); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px + ( a + b), py - ( a + b)); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px + (2*a + b), py - ( a )); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, px + (2*a + b), py + ( a )); grid_face_set_dot(g, d, 3); d = grid_get_dot(g, points, px + ( a + b), py + ( a + b)); grid_face_set_dot(g, d, 4); d = grid_get_dot(g, points, px + ( a ), py + (2*a + b)); grid_face_set_dot(g, d, 5); d = grid_get_dot(g, points, px - ( a ), py + (2*a + b)); grid_face_set_dot(g, d, 6); d = grid_get_dot(g, points, px - ( a + b), py + ( a + b)); grid_face_set_dot(g, d, 7); d = grid_get_dot(g, points, px - (2*a + b), py + ( a )); grid_face_set_dot(g, d, 8); d = grid_get_dot(g, points, px - (2*a + b), py - ( a )); grid_face_set_dot(g, d, 9); d = grid_get_dot(g, points, px - ( a + b), py - ( a + b)); grid_face_set_dot(g, d, 10); d = grid_get_dot(g, points, px - ( a ), py - (2*a + b)); grid_face_set_dot(g, d, 11); /* hexagon below dodecagon */ if (y < height - 1 && (x < width - 1 || !(y % 2)) && (x > 0 || (y % 2))) { grid_face_add_new(g, 6); d = grid_get_dot(g, points, px + a, py + (2*a + b)); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px + 2*a, py + (2*a + 2*b)); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px + a, py + (2*a + 3*b)); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, px - a, py + (2*a + 3*b)); grid_face_set_dot(g, d, 3); d = grid_get_dot(g, points, px - 2*a, py + (2*a + 2*b)); grid_face_set_dot(g, d, 4); d = grid_get_dot(g, points, px - a, py + (2*a + b)); grid_face_set_dot(g, d, 5); } /* hexagon above dodecagon */ if (y && (x < width - 1 || !(y % 2)) && (x > 0 || (y % 2))) { grid_face_add_new(g, 6); d = grid_get_dot(g, points, px - a, py - (2*a + b)); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px - 2*a, py - (2*a + 2*b)); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px - a, py - (2*a + 3*b)); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, px + a, py - (2*a + 3*b)); grid_face_set_dot(g, d, 3); d = grid_get_dot(g, points, px + 2*a, py - (2*a + 2*b)); grid_face_set_dot(g, d, 4); d = grid_get_dot(g, points, px + a, py - (2*a + b)); grid_face_set_dot(g, d, 5); } /* square on right of dodecagon */ if (x < width - 1) { grid_face_add_new(g, 4); d = grid_get_dot(g, points, px + 2*a + b, py - a); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px + 4*a + b, py - a); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px + 4*a + b, py + a); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, px + 2*a + b, py + a); grid_face_set_dot(g, d, 3); } /* square on top right of dodecagon */ if (y && (x < width - 1 || !(y % 2))) { grid_face_add_new(g, 4); d = grid_get_dot(g, points, px + ( a ), py - (2*a + b)); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px + (2*a ), py - (2*a + 2*b)); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px + (2*a + b), py - ( a + 2*b)); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, px + ( a + b), py - ( a + b)); grid_face_set_dot(g, d, 3); } /* square on top left of dodecagon */ if (y && (x || (y % 2))) { grid_face_add_new(g, 4); d = grid_get_dot(g, points, px - ( a + b), py - ( a + b)); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px - (2*a + b), py - ( a + 2*b)); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px - (2*a ), py - (2*a + 2*b)); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, px - ( a ), py - (2*a + b)); grid_face_set_dot(g, d, 3); } } } freetree234(points); assert(g->num_faces <= max_faces); assert(g->num_dots <= max_dots); grid_make_consistent(g); return g; } static void grid_size_greatgreatdodecagonal(int width, int height, int *tilesize, int *xextent, int *yextent) { int a = DODEC_A; int b = DODEC_B; *tilesize = DODEC_TILESIZE; *xextent = (4*a + 4*b) * (width-1) + 2*(2*a + b) + 2*a + 2*b; *yextent = (6*a + 2*b) * (height-1) + 2*(2*a + b); } static grid *grid_new_greatgreatdodecagonal(int width, int height, const char *desc) { int x, y; /* Vector for side of triangle - ratio is close to sqrt(3) */ int a = DODEC_A; int b = DODEC_B; /* Upper bounds - don't have to be exact */ int max_faces = 50 * width * height; int max_dots = 300 * width * height; tree234 *points; grid *g = grid_empty(); g->tilesize = DODEC_TILESIZE; g->faces = snewn(max_faces, grid_face); g->dots = snewn(max_dots, grid_dot); points = newtree234(grid_point_cmp_fn); for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { grid_dot *d; /* centre of dodecagon */ int px = (4*a + 4*b) * x; int py = (6*a + 2*b) * y; if (y % 2) px += 2*a + 2*b; /* dodecagon */ grid_face_add_new(g, 12); d = grid_get_dot(g, points, px + ( a ), py - (2*a + b)); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px + ( a + b), py - ( a + b)); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px + (2*a + b), py - ( a )); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, px + (2*a + b), py + ( a )); grid_face_set_dot(g, d, 3); d = grid_get_dot(g, points, px + ( a + b), py + ( a + b)); grid_face_set_dot(g, d, 4); d = grid_get_dot(g, points, px + ( a ), py + (2*a + b)); grid_face_set_dot(g, d, 5); d = grid_get_dot(g, points, px - ( a ), py + (2*a + b)); grid_face_set_dot(g, d, 6); d = grid_get_dot(g, points, px - ( a + b), py + ( a + b)); grid_face_set_dot(g, d, 7); d = grid_get_dot(g, points, px - (2*a + b), py + ( a )); grid_face_set_dot(g, d, 8); d = grid_get_dot(g, points, px - (2*a + b), py - ( a )); grid_face_set_dot(g, d, 9); d = grid_get_dot(g, points, px - ( a + b), py - ( a + b)); grid_face_set_dot(g, d, 10); d = grid_get_dot(g, points, px - ( a ), py - (2*a + b)); grid_face_set_dot(g, d, 11); /* hexagon on top right of dodecagon */ if (y && (x < width - 1 || !(y % 2))) { grid_face_add_new(g, 6); d = grid_get_dot(g, points, px + (a + 2*b), py - (4*a + b)); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px + (a + 2*b), py - (2*a + b)); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px + (a + b), py - ( a + b)); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, px + (a ), py - (2*a + b)); grid_face_set_dot(g, d, 3); d = grid_get_dot(g, points, px + (a ), py - (4*a + b)); grid_face_set_dot(g, d, 4); d = grid_get_dot(g, points, px + (a + b), py - (5*a + b)); grid_face_set_dot(g, d, 5); } /* hexagon on right of dodecagon*/ if (x < width - 1) { grid_face_add_new(g, 6); d = grid_get_dot(g, points, px + (2*a + 3*b), py - a); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px + (2*a + 3*b), py + a); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px + (2*a + 2*b), py + 2*a); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, px + (2*a + b), py + a); grid_face_set_dot(g, d, 3); d = grid_get_dot(g, points, px + (2*a + b), py - a); grid_face_set_dot(g, d, 4); d = grid_get_dot(g, points, px + (2*a + 2*b), py - 2*a); grid_face_set_dot(g, d, 5); } /* hexagon on bottom right of dodecagon */ if ((y < height - 1) && (x < width - 1 || !(y % 2))) { grid_face_add_new(g, 6); d = grid_get_dot(g, points, px + (a + 2*b), py + (2*a + b)); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px + (a + 2*b), py + (4*a + b)); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px + (a + b), py + (5*a + b)); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, px + (a ), py + (4*a + b)); grid_face_set_dot(g, d, 3); d = grid_get_dot(g, points, px + (a ), py + (2*a + b)); grid_face_set_dot(g, d, 4); d = grid_get_dot(g, points, px + (a + b), py + ( a + b)); grid_face_set_dot(g, d, 5); } /* square on top right of dodecagon */ if (y && (x < width - 1 )) { grid_face_add_new(g, 4); d = grid_get_dot(g, points, px + ( a + 2*b), py - (2*a + b)); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px + (2*a + 2*b), py - (2*a )); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px + (2*a + b), py - ( a )); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, px + ( a + b), py - ( a + b)); grid_face_set_dot(g, d, 3); } /* square on bottom right of dodecagon */ if ((y < height - 1) && (x < width - 1 )) { grid_face_add_new(g, 4); d = grid_get_dot(g, points, px + (2*a + 2*b), py + (2*a )); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px + ( a + 2*b), py + (2*a + b)); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px + ( a + b), py + ( a + b)); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, px + (2*a + b), py + ( a )); grid_face_set_dot(g, d, 3); } /* square below dodecagon */ if ((y < height - 1) && (x < width - 1 || !(y % 2)) && (x > 0 || (y % 2))) { grid_face_add_new(g, 4); d = grid_get_dot(g, points, px + a, py + (2*a + b)); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px + a, py + (4*a + b)); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px - a, py + (4*a + b)); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, px - a, py + (2*a + b)); grid_face_set_dot(g, d, 3); } /* square on bottom left of dodecagon */ if (x && (y < height - 1)) { grid_face_add_new(g, 4); d = grid_get_dot(g, points, px - (2*a + b), py + ( a )); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px - ( a + b), py + ( a + b)); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px - ( a + 2*b), py + (2*a + b)); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, px - (2*a + 2*b), py + (2*a )); grid_face_set_dot(g, d, 3); } /* square on top left of dodecagon */ if (x && y) { grid_face_add_new(g, 4); d = grid_get_dot(g, points, px - ( a + b), py - ( a + b)); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px - (2*a + b), py - ( a )); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px - (2*a + 2*b), py - (2*a )); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, px - ( a + 2*b), py - (2*a + b)); grid_face_set_dot(g, d, 3); } /* square above dodecagon */ if (y && (x < width - 1 || !(y % 2)) && (x > 0 || (y % 2))) { grid_face_add_new(g, 4); d = grid_get_dot(g, points, px + a, py - (4*a + b)); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px + a, py - (2*a + b)); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px - a, py - (2*a + b)); grid_face_set_dot(g, d, 2); d = grid_get_dot(g, points, px - a, py - (4*a + b)); grid_face_set_dot(g, d, 3); } /* upper triangle (v) */ if (y && (x < width - 1)) { grid_face_add_new(g, 3); d = grid_get_dot(g, points, px + (3*a + 2*b), py - (2*a + b)); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px + (2*a + 2*b), py - (2*a )); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px + ( a + 2*b), py - (2*a + b)); grid_face_set_dot(g, d, 2); } /* lower triangle (^) */ if ((y < height - 1) && (x < width - 1)) { grid_face_add_new(g, 3); d = grid_get_dot(g, points, px + (3*a + 2*b), py + (2*a + b)); grid_face_set_dot(g, d, 0); d = grid_get_dot(g, points, px + ( a + 2*b), py + (2*a + b)); grid_face_set_dot(g, d, 1); d = grid_get_dot(g, points, px + (2*a + 2*b), py + (2*a )); grid_face_set_dot(g, d, 2); } } } freetree234(points); assert(g->num_faces <= max_faces); assert(g->num_dots <= max_dots); grid_make_consistent(g); return g; } typedef struct setface_ctx { int xmin, xmax, ymin, ymax; grid *g; tree234 *points; } setface_ctx; static double round_int_nearest_away(double r) { return (r > 0.0) ? floor(r + 0.5) : ceil(r - 0.5); } static int set_faces(penrose_state *state, vector *vs, int n, int depth) { setface_ctx *sf_ctx = (setface_ctx *)state->ctx; int i; int xs[4], ys[4]; if (depth < state->max_depth) return 0; #ifdef DEBUG_PENROSE if (n != 4) return 0; /* triangles are sent as debugging. */ #endif for (i = 0; i < n; i++) { double tx = v_x(vs, i), ty = v_y(vs, i); xs[i] = (int)round_int_nearest_away(tx); ys[i] = (int)round_int_nearest_away(ty); if (xs[i] < sf_ctx->xmin || xs[i] > sf_ctx->xmax) return 0; if (ys[i] < sf_ctx->ymin || ys[i] > sf_ctx->ymax) return 0; } grid_face_add_new(sf_ctx->g, n); debug(("penrose: new face l=%f gen=%d...", penrose_side_length(state->start_size, depth), depth)); for (i = 0; i < n; i++) { grid_dot *d = grid_get_dot(sf_ctx->g, sf_ctx->points, xs[i], ys[i]); grid_face_set_dot(sf_ctx->g, d, i); debug((" ... dot 0x%x (%d,%d) (was %2.2f,%2.2f)", d, d->x, d->y, v_x(vs, i), v_y(vs, i))); } return 0; } #define PENROSE_TILESIZE 100 static void grid_size_penrose(int width, int height, int *tilesize, int *xextent, int *yextent) { int l = PENROSE_TILESIZE; *tilesize = l; *xextent = l * width; *yextent = l * height; } static grid *grid_new_penrose(int width, int height, int which, const char *desc); /* forward reference */ static char *grid_new_desc_penrose(grid_type type, int width, int height, random_state *rs) { int tilesize = PENROSE_TILESIZE, startsz, depth, xoff, yoff, aoff; double outer_radius; int inner_radius; char gd[255]; int which = (type == GRID_PENROSE_P2 ? PENROSE_P2 : PENROSE_P3); grid *g; while (1) { /* We want to produce a random bit of penrose tiling, so we * calculate a random offset (within the patch that penrose.c * calculates for us) and an angle (multiple of 36) to rotate * the patch. */ penrose_calculate_size(which, tilesize, width, height, &outer_radius, &startsz, &depth); /* Calculate radius of (circumcircle of) patch, subtract from * radius calculated. */ inner_radius = (int)(outer_radius - sqrt(width*width + height*height)); /* Pick a random offset (the easy way: choose within outer * square, discarding while it's outside the circle) */ do { xoff = random_upto(rs, 2*inner_radius) - inner_radius; yoff = random_upto(rs, 2*inner_radius) - inner_radius; } while (sqrt(xoff*xoff+yoff*yoff) > inner_radius); aoff = random_upto(rs, 360/36) * 36; debug(("grid_desc: ts %d, %dx%d patch, orad %2.2f irad %d", tilesize, width, height, outer_radius, inner_radius)); debug((" -> xoff %d yoff %d aoff %d", xoff, yoff, aoff)); sprintf(gd, "G%d,%d,%d", xoff, yoff, aoff); /* * Now test-generate our grid, to make sure it actually * produces something. */ g = grid_new_penrose(width, height, which, gd); if (g) { grid_free(g); break; } /* If not, go back to the top of this while loop and try again * with a different random offset. */ } return dupstr(gd); } static char *grid_validate_desc_penrose(grid_type type, int width, int height, const char *desc) { int tilesize = PENROSE_TILESIZE, startsz, depth, xoff, yoff, aoff, inner_radius; double outer_radius; int which = (type == GRID_PENROSE_P2 ? PENROSE_P2 : PENROSE_P3); grid *g; if (!desc) return "Missing grid description string."; penrose_calculate_size(which, tilesize, width, height, &outer_radius, &startsz, &depth); inner_radius = (int)(outer_radius - sqrt(width*width + height*height)); if (sscanf(desc, "G%d,%d,%d", &xoff, &yoff, &aoff) != 3) return "Invalid format grid description string."; if (sqrt(xoff*xoff + yoff*yoff) > inner_radius) return "Patch offset out of bounds."; if ((aoff % 36) != 0 || aoff < 0 || aoff >= 360) return "Angle offset out of bounds."; /* * Test-generate to ensure these parameters don't end us up with * no grid at all. */ g = grid_new_penrose(width, height, which, desc); if (!g) return "Patch coordinates do not identify a usable grid fragment"; grid_free(g); return NULL; } /* * We're asked for a grid of a particular size, and we generate enough * of the tiling so we can be sure to have enough random grid from which * to pick. */ static grid *grid_new_penrose(int width, int height, int which, const char *desc) { int max_faces, max_dots, tilesize = PENROSE_TILESIZE; int xsz, ysz, xoff, yoff, aoff; double rradius; tree234 *points; grid *g; penrose_state ps; setface_ctx sf_ctx; penrose_calculate_size(which, tilesize, width, height, &rradius, &ps.start_size, &ps.max_depth); debug(("penrose: w%d h%d, tile size %d, start size %d, depth %d", width, height, tilesize, ps.start_size, ps.max_depth)); ps.new_tile = set_faces; ps.ctx = &sf_ctx; max_faces = (width*3) * (height*3); /* somewhat paranoid... */ max_dots = max_faces * 4; /* ditto... */ g = grid_empty(); g->tilesize = tilesize; g->faces = snewn(max_faces, grid_face); g->dots = snewn(max_dots, grid_dot); points = newtree234(grid_point_cmp_fn); memset(&sf_ctx, 0, sizeof(sf_ctx)); sf_ctx.g = g; sf_ctx.points = points; if (desc != NULL) { if (sscanf(desc, "G%d,%d,%d", &xoff, &yoff, &aoff) != 3) assert(!"Invalid grid description."); } else { xoff = yoff = aoff = 0; } xsz = width * tilesize; ysz = height * tilesize; sf_ctx.xmin = xoff - xsz/2; sf_ctx.xmax = xoff + xsz/2; sf_ctx.ymin = yoff - ysz/2; sf_ctx.ymax = yoff + ysz/2; debug(("penrose: centre (%f, %f) xsz %f ysz %f", 0.0, 0.0, xsz, ysz)); debug(("penrose: x range (%f --> %f), y range (%f --> %f)", sf_ctx.xmin, sf_ctx.xmax, sf_ctx.ymin, sf_ctx.ymax)); penrose(&ps, which, aoff); freetree234(points); assert(g->num_faces <= max_faces); assert(g->num_dots <= max_dots); debug(("penrose: %d faces total (equivalent to %d wide by %d high)", g->num_faces, g->num_faces/height, g->num_faces/width)); /* * Return NULL if we ended up with an empty grid, either because * the initial generation was over too small a rectangle to * encompass any face or because grid_trim_vigorously ended up * removing absolutely everything. */ if (g->num_faces == 0 || g->num_dots == 0) { grid_free(g); return NULL; } grid_trim_vigorously(g); if (g->num_faces == 0 || g->num_dots == 0) { grid_free(g); return NULL; } grid_make_consistent(g); /* * Centre the grid in its originally promised rectangle. */ g->lowest_x -= ((sf_ctx.xmax - sf_ctx.xmin) - (g->highest_x - g->lowest_x)) / 2; g->highest_x = g->lowest_x + (sf_ctx.xmax - sf_ctx.xmin); g->lowest_y -= ((sf_ctx.ymax - sf_ctx.ymin) - (g->highest_y - g->lowest_y)) / 2; g->highest_y = g->lowest_y + (sf_ctx.ymax - sf_ctx.ymin); return g; } static void grid_size_penrose_p2_kite(int width, int height, int *tilesize, int *xextent, int *yextent) { grid_size_penrose(width, height, tilesize, xextent, yextent); } static void grid_size_penrose_p3_thick(int width, int height, int *tilesize, int *xextent, int *yextent) { grid_size_penrose(width, height, tilesize, xextent, yextent); } static grid *grid_new_penrose_p2_kite(int width, int height, const char *desc) { return grid_new_penrose(width, height, PENROSE_P2, desc); } static grid *grid_new_penrose_p3_thick(int width, int height, const char *desc) { return grid_new_penrose(width, height, PENROSE_P3, desc); } /* ----------- End of grid generators ------------- */ #define FNNEW(upper,lower) &grid_new_ ## lower, #define FNSZ(upper,lower) &grid_size_ ## lower, static grid *(*(grid_news[]))(int, int, const char*) = { GRIDGEN_LIST(FNNEW) }; static void(*(grid_sizes[]))(int, int, int*, int*, int*) = { GRIDGEN_LIST(FNSZ) }; char *grid_new_desc(grid_type type, int width, int height, random_state *rs) { if (type == GRID_PENROSE_P2 || type == GRID_PENROSE_P3) { return grid_new_desc_penrose(type, width, height, rs); } else if (type == GRID_TRIANGULAR) { return dupstr("0"); /* up-to-date version of triangular grid */ } else { return NULL; } } char *grid_validate_desc(grid_type type, int width, int height, const char *desc) { if (type == GRID_PENROSE_P2 || type == GRID_PENROSE_P3) { return grid_validate_desc_penrose(type, width, height, desc); } else if (type == GRID_TRIANGULAR) { return grid_validate_desc_triangular(type, width, height, desc); } else { if (desc != NULL) return "Grid description strings not used with this grid type"; return NULL; } } grid *grid_new(grid_type type, int width, int height, const char *desc) { char *err = grid_validate_desc(type, width, height, desc); if (err) assert(!"Invalid grid description."); return grid_news[type](width, height, desc); } void grid_compute_size(grid_type type, int width, int height, int *tilesize, int *xextent, int *yextent) { grid_sizes[type](width, height, tilesize, xextent, yextent); } /* ----------- End of grid helpers ------------- */ /* vim: set shiftwidth=4 tabstop=8: */ puzzles-20170606.272beef/galaxies.c0000644000175000017500000035336313115373615015647 0ustar simonsimon/* * galaxies.c: implementation of 'Tentai Show' from Nikoli, * also sometimes called 'Spiral Galaxies'. * * Notes: * * Grid is stored as size (2n-1), holding edges as well as spaces * (and thus vertices too, at edge intersections). * * Any dot will thus be positioned at one of our grid points, * which saves any faffing with half-of-a-square stuff. * * Edges have on/off state; obviously the actual edges of the * board are fixed to on, and everything else starts as off. * * TTD: * Cleverer solver * Think about how to display remote groups of tiles? * * Bugs: * * Notable puzzle IDs: * * Nikoli's example [web site has wrong highlighting] * (at http://www.nikoli.co.jp/en/puzzles/astronomical_show/): * 5x5:eBbbMlaBbOEnf * * The 'spiral galaxies puzzles are NP-complete' paper * (at http://www.stetson.edu/~efriedma/papers/spiral.pdf): * 7x7:chpgdqqqoezdddki * * Puzzle competition pdf examples * (at http://www.puzzleratings.org/Yurekli2006puz.pdf): * 6x6:EDbaMucCohbrecEi * 10x10:beFbufEEzowDlxldibMHezBQzCdcFzjlci * 13x13:dCemIHFFkJajjgDfdbdBzdzEgjccoPOcztHjBczLDjczqktJjmpreivvNcggFi * */ #include #include #include #include #include #include #include "puzzles.h" #ifdef DEBUGGING #define solvep debug #else int solver_show_working; #define solvep(x) do { if (solver_show_working) { printf x; } } while(0) #endif #ifdef STANDALONE_PICTURE_GENERATOR /* * Dirty hack to enable the generator to construct a game ID which * solves to a specified black-and-white bitmap. We define a global * variable here which gives the desired colour of each square, and * we arrange that the grid generator never merges squares of * different colours. * * The bitmap as stored here is a simple int array (at these sizes * it isn't worth doing fiddly bit-packing). picture[y*w+x] is 1 * iff the pixel at (x,y) is intended to be black. * * (It might be nice to be able to specify some pixels as * don't-care, to give the generator more leeway. But that might be * fiddly.) */ static int *picture; #endif enum { COL_BACKGROUND, COL_WHITEBG, COL_BLACKBG, COL_WHITEDOT, COL_BLACKDOT, COL_GRID, COL_EDGE, COL_ARROW, COL_CURSOR, NCOLOURS }; #define DIFFLIST(A) \ A(NORMAL,Normal,n) \ A(UNREASONABLE,Unreasonable,u) #define ENUM(upper,title,lower) DIFF_ ## upper, #define TITLE(upper,title,lower) #title, #define ENCODE(upper,title,lower) #lower #define CONFIG(upper,title,lower) ":" #title enum { DIFFLIST(ENUM) DIFF_IMPOSSIBLE, DIFF_AMBIGUOUS, DIFF_UNFINISHED, DIFF_MAX }; static char const *const galaxies_diffnames[] = { DIFFLIST(TITLE) "Impossible", "Ambiguous", "Unfinished" }; static char const galaxies_diffchars[] = DIFFLIST(ENCODE); #define DIFFCONFIG DIFFLIST(CONFIG) struct game_params { /* X and Y is the area of the board as seen by * the user, not the (2n+1) area the game uses. */ int w, h, diff; }; enum { s_tile, s_edge, s_vertex }; #define F_DOT 1 /* there's a dot here */ #define F_EDGE_SET 2 /* the edge is set */ #define F_TILE_ASSOC 4 /* this tile is associated with a dot. */ #define F_DOT_BLACK 8 /* (ui only) dot is black. */ #define F_MARK 16 /* scratch flag */ #define F_REACHABLE 32 #define F_SCRATCH 64 #define F_MULTIPLE 128 #define F_DOT_HOLD 256 #define F_GOOD 512 typedef struct space { int x, y; /* its position */ int type; unsigned int flags; int dotx, doty; /* if flags & F_TILE_ASSOC */ int nassoc; /* if flags & F_DOT */ } space; #define INGRID(s,x,y) ((x) >= 0 && (y) >= 0 && \ (x) < (state)->sx && (y) < (state)->sy) #define INUI(s,x,y) ((x) > 0 && (y) > 0 && \ (x) < ((state)->sx-1) && (y) < ((state)->sy-1)) #define GRID(s,g,x,y) ((s)->g[((y)*(s)->sx)+(x)]) #define SPACE(s,x,y) GRID(s,grid,x,y) struct game_state { int w, h; /* size from params */ int sx, sy; /* allocated size, (2x-1)*(2y-1) */ space *grid; int completed, used_solve; int ndots; space **dots; midend *me; /* to call supersede_game_desc */ int cdiff; /* difficulty of current puzzle (for status bar), or -1 if stale. */ }; static int check_complete(const game_state *state, int *dsf, int *colours); static int solver_state(game_state *state, int maxdiff); static int solver_obvious(game_state *state); static int solver_obvious_dot(game_state *state, space *dot); static space *space_opposite_dot(const game_state *state, const space *sp, const space *dot); static space *tile_opposite(const game_state *state, const space *sp); /* ---------------------------------------------------------- * Game parameters and presets */ /* make up some sensible default sizes */ #define DEFAULT_PRESET 0 static const game_params galaxies_presets[] = { { 7, 7, DIFF_NORMAL }, { 7, 7, DIFF_UNREASONABLE }, { 10, 10, DIFF_NORMAL }, { 15, 15, DIFF_NORMAL }, }; static int game_fetch_preset(int i, char **name, game_params **params) { game_params *ret; char buf[80]; if (i < 0 || i >= lenof(galaxies_presets)) return FALSE; ret = snew(game_params); *ret = galaxies_presets[i]; /* structure copy */ sprintf(buf, "%dx%d %s", ret->w, ret->h, galaxies_diffnames[ret->diff]); if (name) *name = dupstr(buf); *params = ret; return TRUE; } static game_params *default_params(void) { game_params *ret; game_fetch_preset(DEFAULT_PRESET, NULL, &ret); return ret; } static void free_params(game_params *params) { sfree(params); } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } static void decode_params(game_params *params, char const *string) { params->h = params->w = atoi(string); params->diff = DIFF_NORMAL; while (*string && isdigit((unsigned char)*string)) string++; if (*string == 'x') { string++; params->h = atoi(string); while (*string && isdigit((unsigned char)*string)) string++; } if (*string == 'd') { int i; string++; for (i = 0; i <= DIFF_UNREASONABLE; i++) if (*string == galaxies_diffchars[i]) params->diff = i; if (*string) string++; } } static char *encode_params(const game_params *params, int full) { char str[80]; sprintf(str, "%dx%d", params->w, params->h); if (full) sprintf(str + strlen(str), "d%c", galaxies_diffchars[params->diff]); return dupstr(str); } static config_item *game_configure(const game_params *params) { config_item *ret; char buf[80]; ret = snewn(4, config_item); ret[0].name = "Width"; ret[0].type = C_STRING; sprintf(buf, "%d", params->w); ret[0].sval = dupstr(buf); ret[0].ival = 0; ret[1].name = "Height"; ret[1].type = C_STRING; sprintf(buf, "%d", params->h); ret[1].sval = dupstr(buf); ret[1].ival = 0; ret[2].name = "Difficulty"; ret[2].type = C_CHOICES; ret[2].sval = DIFFCONFIG; ret[2].ival = params->diff; ret[3].name = NULL; ret[3].type = C_END; ret[3].sval = NULL; ret[3].ival = 0; return ret; } static game_params *custom_params(const config_item *cfg) { game_params *ret = snew(game_params); ret->w = atoi(cfg[0].sval); ret->h = atoi(cfg[1].sval); ret->diff = cfg[2].ival; return ret; } static char *validate_params(const game_params *params, int full) { if (params->w < 3 || params->h < 3) return "Width and height must both be at least 3"; /* * This shouldn't be able to happen at all, since decode_params * and custom_params will never generate anything that isn't * within range. */ assert(params->diff <= DIFF_UNREASONABLE); return NULL; } /* ---------------------------------------------------------- * Game utility functions. */ static void add_dot(space *space) { assert(!(space->flags & F_DOT)); space->flags |= F_DOT; space->nassoc = 0; } static void remove_dot(space *space) { assert(space->flags & F_DOT); space->flags &= ~F_DOT; } static void remove_assoc(const game_state *state, space *tile) { if (tile->flags & F_TILE_ASSOC) { SPACE(state, tile->dotx, tile->doty).nassoc--; tile->flags &= ~F_TILE_ASSOC; tile->dotx = -1; tile->doty = -1; } } static void remove_assoc_with_opposite(game_state *state, space *tile) { space *opposite; if (!(tile->flags & F_TILE_ASSOC)) { return; } opposite = tile_opposite(state, tile); remove_assoc(state, tile); if (opposite != NULL && opposite != tile) { remove_assoc(state, opposite); } } static void add_assoc(const game_state *state, space *tile, space *dot) { remove_assoc(state, tile); #ifdef STANDALONE_PICTURE_GENERATOR if (picture) assert(!picture[(tile->y/2) * state->w + (tile->x/2)] == !(dot->flags & F_DOT_BLACK)); #endif tile->flags |= F_TILE_ASSOC; tile->dotx = dot->x; tile->doty = dot->y; dot->nassoc++; /*debug(("add_assoc sp %d %d --> dot %d,%d, new nassoc %d.\n", tile->x, tile->y, dot->x, dot->y, dot->nassoc));*/ } static void add_assoc_with_opposite(game_state *state, space *tile, space *dot) { int *colors; space *opposite = space_opposite_dot(state, tile, dot); if (opposite == NULL) { return; } if (opposite->flags & F_DOT) { return; } colors = snewn(state->w * state->h, int); check_complete(state, NULL, colors); if (colors[(tile->y - 1)/2 * state->w + (tile->x - 1)/2]) { sfree(colors); return; } if (colors[(opposite->y - 1)/2 * state->w + (opposite->x - 1)/2]) { sfree(colors); return; } sfree(colors); remove_assoc_with_opposite(state, tile); add_assoc(state, tile, dot); remove_assoc_with_opposite(state, opposite); add_assoc(state, opposite, dot); } static space *sp2dot(const game_state *state, int x, int y) { space *sp = &SPACE(state, x, y); if (!(sp->flags & F_TILE_ASSOC)) return NULL; return &SPACE(state, sp->dotx, sp->doty); } #define IS_VERTICAL_EDGE(x) ((x % 2) == 0) static int game_can_format_as_text_now(const game_params *params) { return TRUE; } static char *game_text_format(const game_state *state) { int maxlen = (state->sx+1)*state->sy, x, y; char *ret, *p; space *sp; ret = snewn(maxlen+1, char); p = ret; for (y = 0; y < state->sy; y++) { for (x = 0; x < state->sx; x++) { sp = &SPACE(state, x, y); if (sp->flags & F_DOT) *p++ = 'o'; #if 0 else if (sp->flags & (F_REACHABLE|F_MULTIPLE|F_MARK)) *p++ = (sp->flags & F_MULTIPLE) ? 'M' : (sp->flags & F_REACHABLE) ? 'R' : 'X'; #endif else { switch (sp->type) { case s_tile: if (sp->flags & F_TILE_ASSOC) { space *dot = sp2dot(state, sp->x, sp->y); if (dot && dot->flags & F_DOT) *p++ = (dot->flags & F_DOT_BLACK) ? 'B' : 'W'; else *p++ = '?'; /* association with not-a-dot. */ } else *p++ = ' '; break; case s_vertex: *p++ = '+'; break; case s_edge: if (sp->flags & F_EDGE_SET) *p++ = (IS_VERTICAL_EDGE(x)) ? '|' : '-'; else *p++ = ' '; break; default: assert(!"shouldn't get here!"); } } } *p++ = '\n'; } assert(p - ret == maxlen); *p = '\0'; return ret; } static void dbg_state(const game_state *state) { #ifdef DEBUGGING char *temp = game_text_format(state); debug(("%s\n", temp)); sfree(temp); #endif } /* Space-enumeration callbacks should all return 1 for 'progress made', * -1 for 'impossible', and 0 otherwise. */ typedef int (*space_cb)(game_state *state, space *sp, void *ctx); #define IMPOSSIBLE_QUITS 1 static int foreach_sub(game_state *state, space_cb cb, unsigned int f, void *ctx, int startx, int starty) { int x, y, progress = 0, impossible = 0, ret; space *sp; for (y = starty; y < state->sy; y += 2) { sp = &SPACE(state, startx, y); for (x = startx; x < state->sx; x += 2) { ret = cb(state, sp, ctx); if (ret == -1) { if (f & IMPOSSIBLE_QUITS) return -1; impossible = -1; } else if (ret == 1) { progress = 1; } sp += 2; } } return impossible ? -1 : progress; } static int foreach_tile(game_state *state, space_cb cb, unsigned int f, void *ctx) { return foreach_sub(state, cb, f, ctx, 1, 1); } static int foreach_edge(game_state *state, space_cb cb, unsigned int f, void *ctx) { int ret1, ret2; ret1 = foreach_sub(state, cb, f, ctx, 0, 1); ret2 = foreach_sub(state, cb, f, ctx, 1, 0); if (ret1 == -1 || ret2 == -1) return -1; return (ret1 || ret2) ? 1 : 0; } #if 0 static int foreach_vertex(game_state *state, space_cb cb, unsigned int f, void *ctx) { return foreach_sub(state, cb, f, ctx, 0, 0); } #endif #if 0 static int is_same_assoc(game_state *state, int x1, int y1, int x2, int y2) { space *s1, *s2; if (!INGRID(state, x1, y1) || !INGRID(state, x2, y2)) return 0; s1 = &SPACE(state, x1, y1); s2 = &SPACE(state, x2, y2); assert(s1->type == s_tile && s2->type == s_tile); if ((s1->flags & F_TILE_ASSOC) && (s2->flags & F_TILE_ASSOC) && s1->dotx == s2->dotx && s1->doty == s2->doty) return 1; return 0; /* 0 if not same or not both associated. */ } #endif #if 0 static int edges_into_vertex(game_state *state, int x, int y) { int dx, dy, nx, ny, count = 0; assert(SPACE(state, x, y).type == s_vertex); for (dx = -1; dx <= 1; dx++) { for (dy = -1; dy <= 1; dy++) { if (dx != 0 && dy != 0) continue; if (dx == 0 && dy == 0) continue; nx = x+dx; ny = y+dy; if (!INGRID(state, nx, ny)) continue; assert(SPACE(state, nx, ny).type == s_edge); if (SPACE(state, nx, ny).flags & F_EDGE_SET) count++; } } return count; } #endif static space *space_opposite_dot(const game_state *state, const space *sp, const space *dot) { int dx, dy, tx, ty; space *sp2; dx = sp->x - dot->x; dy = sp->y - dot->y; tx = dot->x - dx; ty = dot->y - dy; if (!INGRID(state, tx, ty)) return NULL; sp2 = &SPACE(state, tx, ty); assert(sp2->type == sp->type); return sp2; } static space *tile_opposite(const game_state *state, const space *sp) { space *dot; assert(sp->flags & F_TILE_ASSOC); dot = &SPACE(state, sp->dotx, sp->doty); return space_opposite_dot(state, sp, dot); } static int dotfortile(game_state *state, space *tile, space *dot) { space *tile_opp = space_opposite_dot(state, tile, dot); if (!tile_opp) return 0; /* opposite would be off grid */ if (tile_opp->flags & F_TILE_ASSOC && (tile_opp->dotx != dot->x || tile_opp->doty != dot->y)) return 0; /* opposite already associated with diff. dot */ return 1; } static void adjacencies(game_state *state, space *sp, space **a1s, space **a2s) { int dxs[4] = {-1, 1, 0, 0}, dys[4] = {0, 0, -1, 1}; int n, x, y; /* this function needs optimising. */ for (n = 0; n < 4; n++) { x = sp->x+dxs[n]; y = sp->y+dys[n]; if (INGRID(state, x, y)) { a1s[n] = &SPACE(state, x, y); x += dxs[n]; y += dys[n]; if (INGRID(state, x, y)) a2s[n] = &SPACE(state, x, y); else a2s[n] = NULL; } else { a1s[n] = a2s[n] = NULL; } } } static int outline_tile_fordot(game_state *state, space *tile, int mark) { space *tadj[4], *eadj[4]; int i, didsth = 0, edge, same; assert(tile->type == s_tile); adjacencies(state, tile, eadj, tadj); for (i = 0; i < 4; i++) { if (!eadj[i]) continue; edge = (eadj[i]->flags & F_EDGE_SET) ? 1 : 0; if (tadj[i]) { if (!(tile->flags & F_TILE_ASSOC)) same = (tadj[i]->flags & F_TILE_ASSOC) ? 0 : 1; else same = ((tadj[i]->flags & F_TILE_ASSOC) && tile->dotx == tadj[i]->dotx && tile->doty == tadj[i]->doty) ? 1 : 0; } else same = 0; if (!edge && !same) { if (mark) eadj[i]->flags |= F_EDGE_SET; didsth = 1; } else if (edge && same) { if (mark) eadj[i]->flags &= ~F_EDGE_SET; didsth = 1; } } return didsth; } static void tiles_from_edge(game_state *state, space *sp, space **ts) { int xs[2], ys[2]; if (IS_VERTICAL_EDGE(sp->x)) { xs[0] = sp->x-1; ys[0] = sp->y; xs[1] = sp->x+1; ys[1] = sp->y; } else { xs[0] = sp->x; ys[0] = sp->y-1; xs[1] = sp->x; ys[1] = sp->y+1; } ts[0] = INGRID(state, xs[0], ys[0]) ? &SPACE(state, xs[0], ys[0]) : NULL; ts[1] = INGRID(state, xs[1], ys[1]) ? &SPACE(state, xs[1], ys[1]) : NULL; } /* Returns a move string for use by 'solve', including the initial * 'S' if issolve is true. */ static char *diff_game(const game_state *src, const game_state *dest, int issolve) { int movelen = 0, movesize = 256, x, y, len; char *move = snewn(movesize, char), buf[80], *sep = ""; char achar = issolve ? 'a' : 'A'; space *sps, *spd; assert(src->sx == dest->sx && src->sy == dest->sy); if (issolve) { move[movelen++] = 'S'; sep = ";"; } move[movelen] = '\0'; for (x = 0; x < src->sx; x++) { for (y = 0; y < src->sy; y++) { sps = &SPACE(src, x, y); spd = &SPACE(dest, x, y); assert(sps->type == spd->type); len = 0; if (sps->type == s_tile) { if ((sps->flags & F_TILE_ASSOC) && (spd->flags & F_TILE_ASSOC)) { if (sps->dotx != spd->dotx || sps->doty != spd->doty) /* Both associated; change association, if different */ len = sprintf(buf, "%s%c%d,%d,%d,%d", sep, (int)achar, x, y, spd->dotx, spd->doty); } else if (sps->flags & F_TILE_ASSOC) /* Only src associated; remove. */ len = sprintf(buf, "%sU%d,%d", sep, x, y); else if (spd->flags & F_TILE_ASSOC) /* Only dest associated; add. */ len = sprintf(buf, "%s%c%d,%d,%d,%d", sep, (int)achar, x, y, spd->dotx, spd->doty); } else if (sps->type == s_edge) { if ((sps->flags & F_EDGE_SET) != (spd->flags & F_EDGE_SET)) /* edge flags are different; flip them. */ len = sprintf(buf, "%sE%d,%d", sep, x, y); } if (len) { if (movelen + len >= movesize) { movesize = movelen + len + 256; move = sresize(move, movesize, char); } strcpy(move + movelen, buf); movelen += len; sep = ";"; } } } debug(("diff_game src then dest:\n")); dbg_state(src); dbg_state(dest); debug(("diff string %s\n", move)); return move; } /* Returns 1 if a dot here would not be too close to any other dots * (and would avoid other game furniture). */ static int dot_is_possible(game_state *state, space *sp, int allow_assoc) { int bx = 0, by = 0, dx, dy; space *adj; #ifdef STANDALONE_PICTURE_GENERATOR int col = -1; #endif switch (sp->type) { case s_tile: bx = by = 1; break; case s_edge: if (IS_VERTICAL_EDGE(sp->x)) { bx = 2; by = 1; } else { bx = 1; by = 2; } break; case s_vertex: bx = by = 2; break; } for (dx = -bx; dx <= bx; dx++) { for (dy = -by; dy <= by; dy++) { if (!INGRID(state, sp->x+dx, sp->y+dy)) continue; adj = &SPACE(state, sp->x+dx, sp->y+dy); #ifdef STANDALONE_PICTURE_GENERATOR /* * Check that all the squares we're looking at have the * same colour. */ if (picture) { if (adj->type == s_tile) { int c = picture[(adj->y / 2) * state->w + (adj->x / 2)]; if (col < 0) col = c; if (c != col) return 0; /* colour mismatch */ } } #endif if (!allow_assoc && (adj->flags & F_TILE_ASSOC)) return 0; if (dx != 0 || dy != 0) { /* Other than our own square, no dots nearby. */ if (adj->flags & (F_DOT)) return 0; } /* We don't want edges within our rectangle * (but don't care about edges on the edge) */ if (abs(dx) < bx && abs(dy) < by && adj->flags & F_EDGE_SET) return 0; } } return 1; } /* ---------------------------------------------------------- * Game generation, structure creation, and descriptions. */ static game_state *blank_game(int w, int h) { game_state *state = snew(game_state); int x, y; state->w = w; state->h = h; state->sx = (w*2)+1; state->sy = (h*2)+1; state->grid = snewn(state->sx * state->sy, space); state->completed = state->used_solve = 0; for (x = 0; x < state->sx; x++) { for (y = 0; y < state->sy; y++) { space *sp = &SPACE(state, x, y); memset(sp, 0, sizeof(space)); sp->x = x; sp->y = y; if ((x % 2) == 0 && (y % 2) == 0) sp->type = s_vertex; else if ((x % 2) == 0 || (y % 2) == 0) { sp->type = s_edge; if (x == 0 || y == 0 || x == state->sx-1 || y == state->sy-1) sp->flags |= F_EDGE_SET; } else sp->type = s_tile; } } state->ndots = 0; state->dots = NULL; state->me = NULL; /* filled in by new_game. */ state->cdiff = -1; return state; } static void game_update_dots(game_state *state) { int i, n, sz = state->sx * state->sy; if (state->dots) sfree(state->dots); state->ndots = 0; for (i = 0; i < sz; i++) { if (state->grid[i].flags & F_DOT) state->ndots++; } state->dots = snewn(state->ndots, space *); n = 0; for (i = 0; i < sz; i++) { if (state->grid[i].flags & F_DOT) state->dots[n++] = &state->grid[i]; } } static void clear_game(game_state *state, int cleardots) { int x, y; /* don't erase edge flags around outline! */ for (x = 1; x < state->sx-1; x++) { for (y = 1; y < state->sy-1; y++) { if (cleardots) SPACE(state, x, y).flags = 0; else SPACE(state, x, y).flags &= (F_DOT|F_DOT_BLACK); } } if (cleardots) game_update_dots(state); } static game_state *dup_game(const game_state *state) { game_state *ret = blank_game(state->w, state->h); ret->completed = state->completed; ret->used_solve = state->used_solve; memcpy(ret->grid, state->grid, ret->sx*ret->sy*sizeof(space)); game_update_dots(ret); ret->me = state->me; ret->cdiff = state->cdiff; return ret; } static void free_game(game_state *state) { if (state->dots) sfree(state->dots); sfree(state->grid); sfree(state); } /* Game description is a sequence of letters representing the number * of spaces (a = 0, y = 24) before the next dot; a-y for a white dot, * and A-Y for a black dot. 'z' is 25 spaces (and no dot). * * I know it's a bitch to generate by hand, so we provide * an edit mode. */ static char *encode_game(game_state *state) { char *desc, *p; int run, x, y, area; unsigned int f; area = (state->sx-2) * (state->sy-2); desc = snewn(area, char); p = desc; run = 0; for (y = 1; y < state->sy-1; y++) { for (x = 1; x < state->sx-1; x++) { f = SPACE(state, x, y).flags; /* a/A is 0 spaces between, b/B is 1 space, ... * y/Y is 24 spaces, za/zA is 25 spaces, ... * It's easier to count from 0 because we then * don't have to special-case the top left-hand corner * (which could be a dot with 0 spaces before it). */ if (!(f & F_DOT)) run++; else { while (run > 24) { *p++ = 'z'; run -= 25; } *p++ = ((f & F_DOT_BLACK) ? 'A' : 'a') + run; run = 0; } } } assert(p - desc < area); *p++ = '\0'; desc = sresize(desc, p - desc, char); return desc; } struct movedot { int op; space *olddot, *newdot; }; enum { MD_CHECK, MD_MOVE }; static int movedot_cb(game_state *state, space *tile, void *vctx) { struct movedot *md = (struct movedot *)vctx; space *newopp = NULL; assert(tile->type == s_tile); assert(md->olddot && md->newdot); if (!(tile->flags & F_TILE_ASSOC)) return 0; if (tile->dotx != md->olddot->x || tile->doty != md->olddot->y) return 0; newopp = space_opposite_dot(state, tile, md->newdot); switch (md->op) { case MD_CHECK: /* If the tile is associated with the old dot, check its * opposite wrt the _new_ dot is empty or same assoc. */ if (!newopp) return -1; /* no new opposite */ if (newopp->flags & F_TILE_ASSOC) { if (newopp->dotx != md->olddot->x || newopp->doty != md->olddot->y) return -1; /* associated, but wrong dot. */ } #ifdef STANDALONE_PICTURE_GENERATOR if (picture) { /* * Reject if either tile and the dot don't match in colour. */ if (!(picture[(tile->y/2) * state->w + (tile->x/2)]) ^ !(md->newdot->flags & F_DOT_BLACK)) return -1; if (!(picture[(newopp->y/2) * state->w + (newopp->x/2)]) ^ !(md->newdot->flags & F_DOT_BLACK)) return -1; } #endif break; case MD_MOVE: /* Move dot associations: anything that was associated * with the old dot, and its opposite wrt the new dot, * become associated with the new dot. */ assert(newopp); debug(("Associating %d,%d and %d,%d with new dot %d,%d.\n", tile->x, tile->y, newopp->x, newopp->y, md->newdot->x, md->newdot->y)); add_assoc(state, tile, md->newdot); add_assoc(state, newopp, md->newdot); return 1; /* we did something! */ } return 0; } /* For the given dot, first see if we could expand it into all the given * extra spaces (by checking for empty spaces on the far side), and then * see if we can move the dot to shift the CoG to include the new spaces. */ static int dot_expand_or_move(game_state *state, space *dot, space **toadd, int nadd) { space *tileopp; int i, ret, nnew, cx, cy; struct movedot md; debug(("dot_expand_or_move: %d tiles for dot %d,%d\n", nadd, dot->x, dot->y)); for (i = 0; i < nadd; i++) debug(("dot_expand_or_move: dot %d,%d\n", toadd[i]->x, toadd[i]->y)); assert(dot->flags & F_DOT); #ifdef STANDALONE_PICTURE_GENERATOR if (picture) { /* * Reject the expansion totally if any of the new tiles are * the wrong colour. */ for (i = 0; i < nadd; i++) { if (!(picture[(toadd[i]->y/2) * state->w + (toadd[i]->x/2)]) ^ !(dot->flags & F_DOT_BLACK)) return 0; } } #endif /* First off, could we just expand the current dot's tile to cover * the space(s) passed in and their opposites? */ for (i = 0; i < nadd; i++) { tileopp = space_opposite_dot(state, toadd[i], dot); if (!tileopp) goto noexpand; if (tileopp->flags & F_TILE_ASSOC) goto noexpand; #ifdef STANDALONE_PICTURE_GENERATOR if (picture) { /* * The opposite tiles have to be the right colour as well. */ if (!(picture[(tileopp->y/2) * state->w + (tileopp->x/2)]) ^ !(dot->flags & F_DOT_BLACK)) goto noexpand; } #endif } /* OK, all spaces have valid empty opposites: associate spaces and * opposites with our dot. */ for (i = 0; i < nadd; i++) { tileopp = space_opposite_dot(state, toadd[i], dot); add_assoc(state, toadd[i], dot); add_assoc(state, tileopp, dot); debug(("Added associations %d,%d and %d,%d --> %d,%d\n", toadd[i]->x, toadd[i]->y, tileopp->x, tileopp->y, dot->x, dot->y)); dbg_state(state); } return 1; noexpand: /* Otherwise, try to move dot so as to encompass given spaces: */ /* first, calculate the 'centre of gravity' of the new dot. */ nnew = dot->nassoc + nadd; /* number of tiles assoc. with new dot. */ cx = dot->x * dot->nassoc; cy = dot->y * dot->nassoc; for (i = 0; i < nadd; i++) { cx += toadd[i]->x; cy += toadd[i]->y; } /* If the CoG isn't a whole number, it's not possible. */ if ((cx % nnew) != 0 || (cy % nnew) != 0) { debug(("Unable to move dot %d,%d, CoG not whole number.\n", dot->x, dot->y)); return 0; } cx /= nnew; cy /= nnew; /* Check whether all spaces in the old tile would have a good * opposite wrt the new dot. */ md.olddot = dot; md.newdot = &SPACE(state, cx, cy); md.op = MD_CHECK; ret = foreach_tile(state, movedot_cb, IMPOSSIBLE_QUITS, &md); if (ret == -1) { debug(("Unable to move dot %d,%d, new dot not symmetrical.\n", dot->x, dot->y)); return 0; } /* Also check whether all spaces we're adding would have a good * opposite wrt the new dot. */ for (i = 0; i < nadd; i++) { tileopp = space_opposite_dot(state, toadd[i], md.newdot); if (tileopp && (tileopp->flags & F_TILE_ASSOC) && (tileopp->dotx != dot->x || tileopp->doty != dot->y)) { tileopp = NULL; } if (!tileopp) { debug(("Unable to move dot %d,%d, new dot not symmetrical.\n", dot->x, dot->y)); return 0; } #ifdef STANDALONE_PICTURE_GENERATOR if (picture) { if (!(picture[(tileopp->y/2) * state->w + (tileopp->x/2)]) ^ !(dot->flags & F_DOT_BLACK)) return 0; } #endif } /* If we've got here, we're ok. First, associate all of 'toadd' * with the _old_ dot (so they'll get fixed up, with their opposites, * in the next step). */ for (i = 0; i < nadd; i++) { debug(("Associating to-add %d,%d with old dot %d,%d.\n", toadd[i]->x, toadd[i]->y, dot->x, dot->y)); add_assoc(state, toadd[i], dot); } /* Finally, move the dot and fix up all the old associations. */ debug(("Moving dot at %d,%d to %d,%d\n", dot->x, dot->y, md.newdot->x, md.newdot->y)); { #ifdef STANDALONE_PICTURE_GENERATOR int f = dot->flags & F_DOT_BLACK; #endif remove_dot(dot); add_dot(md.newdot); #ifdef STANDALONE_PICTURE_GENERATOR md.newdot->flags |= f; #endif } md.op = MD_MOVE; ret = foreach_tile(state, movedot_cb, 0, &md); assert(ret == 1); dbg_state(state); return 1; } /* Hard-code to a max. of 2x2 squares, for speed (less malloc) */ #define MAX_TOADD 4 #define MAX_OUTSIDE 8 #define MAX_TILE_PERC 20 static int generate_try_block(game_state *state, random_state *rs, int x1, int y1, int x2, int y2) { int x, y, nadd = 0, nout = 0, i, maxsz; space *sp, *toadd[MAX_TOADD], *outside[MAX_OUTSIDE], *dot; if (!INGRID(state, x1, y1) || !INGRID(state, x2, y2)) return 0; /* We limit the maximum size of tiles to be ~2*sqrt(area); so, * a 5x5 grid shouldn't have anything >10 tiles, a 20x20 grid * nothing >40 tiles. */ maxsz = (int)sqrt((double)(state->w * state->h)) * 2; debug(("generate_try_block, maxsz %d\n", maxsz)); /* Make a static list of the spaces; if any space is already * associated then quit immediately. */ for (x = x1; x <= x2; x += 2) { for (y = y1; y <= y2; y += 2) { assert(nadd < MAX_TOADD); sp = &SPACE(state, x, y); assert(sp->type == s_tile); if (sp->flags & F_TILE_ASSOC) return 0; toadd[nadd++] = sp; } } /* Make a list of the spaces outside of our block, and shuffle it. */ #define OUTSIDE(x, y) do { \ if (INGRID(state, (x), (y))) { \ assert(nout < MAX_OUTSIDE); \ outside[nout++] = &SPACE(state, (x), (y)); \ } \ } while(0) for (x = x1; x <= x2; x += 2) { OUTSIDE(x, y1-2); OUTSIDE(x, y2+2); } for (y = y1; y <= y2; y += 2) { OUTSIDE(x1-2, y); OUTSIDE(x2+2, y); } shuffle(outside, nout, sizeof(space *), rs); for (i = 0; i < nout; i++) { if (!(outside[i]->flags & F_TILE_ASSOC)) continue; dot = &SPACE(state, outside[i]->dotx, outside[i]->doty); if (dot->nassoc >= maxsz) { debug(("Not adding to dot %d,%d, large enough (%d) already.\n", dot->x, dot->y, dot->nassoc)); continue; } if (dot_expand_or_move(state, dot, toadd, nadd)) return 1; } return 0; } #ifdef STANDALONE_SOLVER int maxtries; #define MAXTRIES maxtries #else #define MAXTRIES 50 #endif #define GP_DOTS 1 static void generate_pass(game_state *state, random_state *rs, int *scratch, int perc, unsigned int flags) { int sz = state->sx*state->sy, nspc, i, ret; shuffle(scratch, sz, sizeof(int), rs); /* This bug took me a, er, little while to track down. On PalmOS, * which has 16-bit signed ints, puzzles over about 9x9 started * failing to generate because the nspc calculation would start * to overflow, causing the dots not to be filled in properly. */ nspc = (int)(((long)perc * (long)sz) / 100L); debug(("generate_pass: %d%% (%d of %dx%d) squares, flags 0x%x\n", perc, nspc, state->sx, state->sy, flags)); for (i = 0; i < nspc; i++) { space *sp = &state->grid[scratch[i]]; int x1 = sp->x, y1 = sp->y, x2 = sp->x, y2 = sp->y; if (sp->type == s_edge) { if (IS_VERTICAL_EDGE(sp->x)) { x1--; x2++; } else { y1--; y2++; } } if (sp->type != s_vertex) { /* heuristic; expanding from vertices tends to generate lots of * too-big regions of tiles. */ if (generate_try_block(state, rs, x1, y1, x2, y2)) continue; /* we expanded successfully. */ } if (!(flags & GP_DOTS)) continue; if ((sp->type == s_edge) && (i % 2)) { debug(("Omitting edge %d,%d as half-of.\n", sp->x, sp->y)); continue; } /* If we've got here we might want to put a dot down. Check * if we can, and add one if so. */ if (dot_is_possible(state, sp, 0)) { add_dot(sp); #ifdef STANDALONE_PICTURE_GENERATOR if (picture) { if (picture[(sp->y/2) * state->w + (sp->x/2)]) sp->flags |= F_DOT_BLACK; } #endif ret = solver_obvious_dot(state, sp); assert(ret != -1); debug(("Added dot (and obvious associations) at %d,%d\n", sp->x, sp->y)); dbg_state(state); } } dbg_state(state); } static char *new_game_desc(const game_params *params, random_state *rs, char **aux, int interactive) { game_state *state = blank_game(params->w, params->h), *copy; char *desc; int *scratch, sz = state->sx*state->sy, i; int diff, ntries = 0, cc; /* Random list of squares to try and process, one-by-one. */ scratch = snewn(sz, int); for (i = 0; i < sz; i++) scratch[i] = i; generate: clear_game(state, 1); ntries++; /* generate_pass(state, rs, scratch, 10, GP_DOTS); */ /* generate_pass(state, rs, scratch, 100, 0); */ generate_pass(state, rs, scratch, 100, GP_DOTS); game_update_dots(state); if (state->ndots == 1) goto generate; #ifdef DEBUGGING { char *tmp = encode_game(state); debug(("new_game_desc state %dx%d:%s\n", params->w, params->h, tmp)); sfree(tmp); } #endif for (i = 0; i < state->sx*state->sy; i++) if (state->grid[i].type == s_tile) outline_tile_fordot(state, &state->grid[i], TRUE); cc = check_complete(state, NULL, NULL); assert(cc); copy = dup_game(state); clear_game(copy, 0); dbg_state(copy); diff = solver_state(copy, params->diff); free_game(copy); assert(diff != DIFF_IMPOSSIBLE); if (diff != params->diff) { /* * We'll grudgingly accept a too-easy puzzle, but we must * _not_ permit a too-hard one (one which the solver * couldn't handle at all). */ if (diff > params->diff || ntries < MAXTRIES) goto generate; } #ifdef STANDALONE_PICTURE_GENERATOR /* * Postprocessing pass to prevent excessive numbers of adjacent * singletons. Iterate over all edges in random shuffled order; * for each edge that separates two regions, investigate * whether removing that edge and merging the regions would * still yield a valid and soluble puzzle. (The two regions * must also be the same colour, of course.) If so, do it. * * This postprocessing pass is slow (due to repeated solver * invocations), and seems to be unnecessary during normal * unconstrained game generation. However, when generating a * game under colour constraints, excessive singletons seem to * turn up more often, so it's worth doing this. */ { int *posns, nposns; int i, j, newdiff; game_state *copy2; nposns = params->w * (params->h+1) + params->h * (params->w+1); posns = snewn(nposns, int); for (i = j = 0; i < state->sx*state->sy; i++) if (state->grid[i].type == s_edge) posns[j++] = i; assert(j == nposns); shuffle(posns, nposns, sizeof(*posns), rs); for (i = 0; i < nposns; i++) { int x, y, x0, y0, x1, y1, cx, cy, cn, cx0, cy0, cx1, cy1, tx, ty; space *s0, *s1, *ts, *d0, *d1, *dn; int ok; /* Coordinates of edge space */ x = posns[i] % state->sx; y = posns[i] / state->sx; /* Coordinates of square spaces on either side of edge */ x0 = ((x+1) & ~1) - 1; /* round down to next odd number */ y0 = ((y+1) & ~1) - 1; x1 = 2*x-x0; /* and reflect about x to get x1 */ y1 = 2*y-y0; if (!INGRID(state, x0, y0) || !INGRID(state, x1, y1)) continue; /* outermost edge of grid */ s0 = &SPACE(state, x0, y0); s1 = &SPACE(state, x1, y1); assert(s0->type == s_tile && s1->type == s_tile); if (s0->dotx == s1->dotx && s0->doty == s1->doty) continue; /* tiles _already_ owned by same dot */ d0 = &SPACE(state, s0->dotx, s0->doty); d1 = &SPACE(state, s1->dotx, s1->doty); if ((d0->flags ^ d1->flags) & F_DOT_BLACK) continue; /* different colours: cannot merge */ /* * Work out where the centre of gravity of the new * region would be. */ cx = d0->nassoc * d0->x + d1->nassoc * d1->x; cy = d0->nassoc * d0->y + d1->nassoc * d1->y; cn = d0->nassoc + d1->nassoc; if (cx % cn || cy % cn) continue; /* CoG not at integer coordinates */ cx /= cn; cy /= cn; assert(INUI(state, cx, cy)); /* * Ensure that the CoG would actually be _in_ the new * region, by verifying that all its surrounding tiles * belong to one or other of our two dots. */ cx0 = ((cx+1) & ~1) - 1; /* round down to next odd number */ cy0 = ((cy+1) & ~1) - 1; cx1 = 2*cx-cx0; /* and reflect about cx to get cx1 */ cy1 = 2*cy-cy0; ok = TRUE; for (ty = cy0; ty <= cy1; ty += 2) for (tx = cx0; tx <= cx1; tx += 2) { ts = &SPACE(state, tx, ty); assert(ts->type == s_tile); if ((ts->dotx != d0->x || ts->doty != d0->y) && (ts->dotx != d1->x || ts->doty != d1->y)) ok = FALSE; } if (!ok) continue; /* * Verify that for every tile in either source region, * that tile's image in the new CoG is also in one of * the two source regions. */ for (ty = 1; ty < state->sy; ty += 2) { for (tx = 1; tx < state->sx; tx += 2) { int tx1, ty1; ts = &SPACE(state, tx, ty); assert(ts->type == s_tile); if ((ts->dotx != d0->x || ts->doty != d0->y) && (ts->dotx != d1->x || ts->doty != d1->y)) continue; /* not part of these tiles anyway */ tx1 = 2*cx-tx; ty1 = 2*cy-ty; if (!INGRID(state, tx1, ty1)) { ok = FALSE; break; } ts = &SPACE(state, cx+cx-tx, cy+cy-ty); if ((ts->dotx != d0->x || ts->doty != d0->y) && (ts->dotx != d1->x || ts->doty != d1->y)) { ok = FALSE; break; } } if (!ok) break; } if (!ok) continue; /* * Now we're clear to attempt the merge. We take a copy * of the game state first, so we can revert it easily * if the resulting puzzle turns out to have become * insoluble. */ copy2 = dup_game(state); remove_dot(d0); remove_dot(d1); dn = &SPACE(state, cx, cy); add_dot(dn); dn->flags |= (d0->flags & F_DOT_BLACK); for (ty = 1; ty < state->sy; ty += 2) { for (tx = 1; tx < state->sx; tx += 2) { ts = &SPACE(state, tx, ty); assert(ts->type == s_tile); if ((ts->dotx != d0->x || ts->doty != d0->y) && (ts->dotx != d1->x || ts->doty != d1->y)) continue; /* not part of these tiles anyway */ add_assoc(state, ts, dn); } } copy = dup_game(state); clear_game(copy, 0); dbg_state(copy); newdiff = solver_state(copy, params->diff); free_game(copy); if (diff == newdiff) { /* Still just as soluble. Let the merge stand. */ free_game(copy2); } else { /* Became insoluble. Revert. */ free_game(state); state = copy2; } } sfree(posns); } #endif desc = encode_game(state); #ifndef STANDALONE_SOLVER debug(("new_game_desc generated: \n")); dbg_state(state); #endif free_game(state); sfree(scratch); return desc; } static int dots_too_close(game_state *state) { /* Quick-and-dirty check, using half the solver: * solver_obvious will only fail if the dots are * too close together, so dot-proximity associations * overlap. */ game_state *tmp = dup_game(state); int ret = solver_obvious(tmp); free_game(tmp); return (ret == -1) ? 1 : 0; } static game_state *load_game(const game_params *params, const char *desc, char **why_r) { game_state *state = blank_game(params->w, params->h); char *why = NULL; int i, x, y, n; unsigned int df; i = 0; while (*desc) { n = *desc++; if (n == 'z') { i += 25; continue; } if (n >= 'a' && n <= 'y') { i += n - 'a'; df = 0; } else if (n >= 'A' && n <= 'Y') { i += n - 'A'; df = F_DOT_BLACK; } else { why = "Invalid characters in game description"; goto fail; } /* if we got here we incremented i and have a dot to add. */ y = (i / (state->sx-2)) + 1; x = (i % (state->sx-2)) + 1; if (!INUI(state, x, y)) { why = "Too much data to fit in grid"; goto fail; } add_dot(&SPACE(state, x, y)); SPACE(state, x, y).flags |= df; i++; } game_update_dots(state); if (dots_too_close(state)) { why = "Dots too close together"; goto fail; } return state; fail: free_game(state); if (why_r) *why_r = why; return NULL; } static char *validate_desc(const game_params *params, const char *desc) { char *why = NULL; game_state *dummy = load_game(params, desc, &why); if (dummy) { free_game(dummy); assert(!why); } else assert(why); return why; } static game_state *new_game(midend *me, const game_params *params, const char *desc) { game_state *state = load_game(params, desc, NULL); if (!state) { assert("Unable to load ?validated game."); return NULL; } #ifdef EDITOR state->me = me; #endif return state; } /* ---------------------------------------------------------- * Solver and all its little wizards. */ int solver_recurse_depth; typedef struct solver_ctx { game_state *state; int sz; /* state->sx * state->sy */ space **scratch; /* size sz */ } solver_ctx; static solver_ctx *new_solver(game_state *state) { solver_ctx *sctx = snew(solver_ctx); sctx->state = state; sctx->sz = state->sx*state->sy; sctx->scratch = snewn(sctx->sz, space *); return sctx; } static void free_solver(solver_ctx *sctx) { sfree(sctx->scratch); sfree(sctx); } /* Solver ideas so far: * * For any empty space, work out how many dots it could associate * with: * it needs line-of-sight * it needs an empty space on the far side * any adjacent lines need corresponding line possibilities. */ /* The solver_ctx should keep a list of dot positions, for quicker looping. * * Solver techniques, in order of difficulty: * obvious adjacency to dots * transferring tiles to opposite side * transferring lines to opposite side * one possible dot for a given tile based on opposite availability * tile with 3 definite edges next to an associated tile must associate with same dot. * * one possible dot for a given tile based on line-of-sight */ static int solver_add_assoc(game_state *state, space *tile, int dx, int dy, const char *why) { space *dot, *tile_opp; dot = &SPACE(state, dx, dy); tile_opp = space_opposite_dot(state, tile, dot); assert(tile->type == s_tile); if (tile->flags & F_TILE_ASSOC) { if ((tile->dotx != dx) || (tile->doty != dy)) { solvep(("%*sSet %d,%d --> %d,%d (%s) impossible; " "already --> %d,%d.\n", solver_recurse_depth*4, "", tile->x, tile->y, dx, dy, why, tile->dotx, tile->doty)); return -1; } return 0; /* no-op */ } if (!tile_opp) { solvep(("%*s%d,%d --> %d,%d impossible, no opposite tile.\n", solver_recurse_depth*4, "", tile->x, tile->y, dx, dy)); return -1; } if (tile_opp->flags & F_TILE_ASSOC && (tile_opp->dotx != dx || tile_opp->doty != dy)) { solvep(("%*sSet %d,%d --> %d,%d (%s) impossible; " "opposite already --> %d,%d.\n", solver_recurse_depth*4, "", tile->x, tile->y, dx, dy, why, tile_opp->dotx, tile_opp->doty)); return -1; } add_assoc(state, tile, dot); add_assoc(state, tile_opp, dot); solvep(("%*sSetting %d,%d --> %d,%d (%s).\n", solver_recurse_depth*4, "", tile->x, tile->y,dx, dy, why)); solvep(("%*sSetting %d,%d --> %d,%d (%s, opposite).\n", solver_recurse_depth*4, "", tile_opp->x, tile_opp->y, dx, dy, why)); return 1; } static int solver_obvious_dot(game_state *state, space *dot) { int dx, dy, ret, didsth = 0; space *tile; debug(("%*ssolver_obvious_dot for %d,%d.\n", solver_recurse_depth*4, "", dot->x, dot->y)); assert(dot->flags & F_DOT); for (dx = -1; dx <= 1; dx++) { for (dy = -1; dy <= 1; dy++) { if (!INGRID(state, dot->x+dx, dot->y+dy)) continue; tile = &SPACE(state, dot->x+dx, dot->y+dy); if (tile->type == s_tile) { ret = solver_add_assoc(state, tile, dot->x, dot->y, "next to dot"); if (ret < 0) return -1; if (ret > 0) didsth = 1; } } } return didsth; } static int solver_obvious(game_state *state) { int i, didsth = 0, ret; debug(("%*ssolver_obvious.\n", solver_recurse_depth*4, "")); for (i = 0; i < state->ndots; i++) { ret = solver_obvious_dot(state, state->dots[i]); if (ret < 0) return -1; if (ret > 0) didsth = 1; } return didsth; } static int solver_lines_opposite_cb(game_state *state, space *edge, void *ctx) { int didsth = 0, n, dx, dy; space *tiles[2], *tile_opp, *edge_opp; assert(edge->type == s_edge); tiles_from_edge(state, edge, tiles); /* if tiles[0] && tiles[1] && they're both associated * and they're both associated with different dots, * ensure the line is set. */ if (!(edge->flags & F_EDGE_SET) && tiles[0] && tiles[1] && (tiles[0]->flags & F_TILE_ASSOC) && (tiles[1]->flags & F_TILE_ASSOC) && (tiles[0]->dotx != tiles[1]->dotx || tiles[0]->doty != tiles[1]->doty)) { /* No edge, but the two adjacent tiles are both * associated with different dots; add the edge. */ solvep(("%*sSetting edge %d,%d - tiles different dots.\n", solver_recurse_depth*4, "", edge->x, edge->y)); edge->flags |= F_EDGE_SET; didsth = 1; } if (!(edge->flags & F_EDGE_SET)) return didsth; for (n = 0; n < 2; n++) { if (!tiles[n]) continue; assert(tiles[n]->type == s_tile); if (!(tiles[n]->flags & F_TILE_ASSOC)) continue; tile_opp = tile_opposite(state, tiles[n]); if (!tile_opp) { solvep(("%*simpossible: edge %d,%d has assoc. tile %d,%d" " with no opposite.\n", solver_recurse_depth*4, "", edge->x, edge->y, tiles[n]->x, tiles[n]->y)); /* edge of tile has no opposite edge (off grid?); * this is impossible. */ return -1; } dx = tiles[n]->x - edge->x; dy = tiles[n]->y - edge->y; assert(INGRID(state, tile_opp->x+dx, tile_opp->y+dy)); edge_opp = &SPACE(state, tile_opp->x+dx, tile_opp->y+dy); if (!(edge_opp->flags & F_EDGE_SET)) { solvep(("%*sSetting edge %d,%d as opposite %d,%d\n", solver_recurse_depth*4, "", tile_opp->x-dx, tile_opp->y-dy, edge->x, edge->y)); edge_opp->flags |= F_EDGE_SET; didsth = 1; } } return didsth; } static int solver_spaces_oneposs_cb(game_state *state, space *tile, void *ctx) { int n, eset, ret; space *edgeadj[4], *tileadj[4]; int dotx, doty; assert(tile->type == s_tile); if (tile->flags & F_TILE_ASSOC) return 0; adjacencies(state, tile, edgeadj, tileadj); /* Empty tile. If each edge is either set, or associated with * the same dot, we must also associate with dot. */ eset = 0; dotx = -1; doty = -1; for (n = 0; n < 4; n++) { assert(edgeadj[n]); assert(edgeadj[n]->type == s_edge); if (edgeadj[n]->flags & F_EDGE_SET) { eset++; } else { assert(tileadj[n]); assert(tileadj[n]->type == s_tile); /* If an adjacent tile is empty we can't make any deductions.*/ if (!(tileadj[n]->flags & F_TILE_ASSOC)) return 0; /* If an adjacent tile is assoc. with a different dot * we can't make any deductions. */ if (dotx != -1 && doty != -1 && (tileadj[n]->dotx != dotx || tileadj[n]->doty != doty)) return 0; dotx = tileadj[n]->dotx; doty = tileadj[n]->doty; } } if (eset == 4) { solvep(("%*simpossible: empty tile %d,%d has 4 edges\n", solver_recurse_depth*4, "", tile->x, tile->y)); return -1; } assert(dotx != -1 && doty != -1); ret = solver_add_assoc(state, tile, dotx, doty, "rest are edges"); if (ret == -1) return -1; assert(ret != 0); /* really should have done something. */ return 1; } /* Improved algorithm for tracking line-of-sight from dots, and not spaces. * * The solver_ctx already stores a list of dots: the algorithm proceeds by * expanding outwards from each dot in turn, expanding first to the boundary * of its currently-connected tile and then to all empty tiles that could see * it. Empty tiles will be flagged with a 'can see dot ' sticker. * * Expansion will happen by (symmetrically opposite) pairs of squares; if * a square hasn't an opposite number there's no point trying to expand through * it. Empty tiles will therefore also be tagged in pairs. * * If an empty tile already has a 'can see dot ' tag from a previous dot, * it (and its partner) gets untagged (or, rather, a 'can see two dots' tag) * because we're looking for single-dot possibilities. * * Once we've gone through all the dots, any which still have a 'can see dot' * tag get associated with that dot (because it must have been the only one); * any without any tag (i.e. that could see _no_ dots) cause an impossibility * marked. * * The expansion will happen each time with a stored list of (space *) pairs, * rather than a mark-and-sweep idea; that's horrifically inefficient. * * expansion algorithm: * * * allocate list of (space *) the size of s->sx*s->sy. * * allocate second grid for (flags, dotx, doty) size of sx*sy. * * clear second grid (flags = 0, all dotx and doty = 0) * flags: F_REACHABLE, F_MULTIPLE * * * * for each dot, start with one pair of tiles that are associated with it -- * * vertex --> (dx+1, dy+1), (dx-1, dy-1) * * edge --> (adj1, adj2) * * tile --> (tile, tile) ??? * * mark that pair of tiles with F_MARK, clear all other F_MARKs. * * add two tiles to start of list. * * set start = 0, end = next = 2 * * from (start to end-1, step 2) { * * we have two tiles (t1, t2), opposites wrt our dot. * * for each (at1) sensible adjacent tile to t1 (i.e. not past an edge): * * work out at2 as the opposite to at1 * * assert at1 and at2 have the same F_MARK values. * * if at1 & F_MARK ignore it (we've been there on a previous sweep) * * if either are associated with a different dot * * mark both with F_MARK (so we ignore them later) * * otherwise (assoc. with our dot, or empty): * * mark both with F_MARK * * add their space * values to the end of the list, set next += 2. * } * * if (end == next) * * we didn't add any new squares; exit the loop. * else * * set start = next+1, end = next. go round again * * We've finished expanding from the dot. Now, for each square we have * in our list (--> each square with F_MARK): * * if the tile is empty: * * if F_REACHABLE was already set * * set F_MULTIPLE * * otherwise * * set F_REACHABLE, set dotx and doty to our dot. * * Then, continue the whole thing for each dot in turn. * * Once we've done for each dot, go through the entire grid looking for * empty tiles: for each empty tile: * if F_REACHABLE and not F_MULTIPLE, set that dot (and its double) * if !F_REACHABLE, return as impossible. * */ /* Returns 1 if this tile is either already associated with this dot, * or blank. */ static int solver_expand_checkdot(space *tile, space *dot) { if (!(tile->flags & F_TILE_ASSOC)) return 1; if (tile->dotx == dot->x && tile->doty == dot->y) return 1; return 0; } static void solver_expand_fromdot(game_state *state, space *dot, solver_ctx *sctx) { int i, j, x, y, start, end, next; space *sp; /* Clear the grid of the (space) flags we'll use. */ /* This is well optimised; analysis showed that: for (i = 0; i < sctx->sz; i++) state->grid[i].flags &= ~F_MARK; took up ~85% of the total function time! */ for (y = 1; y < state->sy; y += 2) { sp = &SPACE(state, 1, y); for (x = 1; x < state->sx; x += 2, sp += 2) sp->flags &= ~F_MARK; } /* Seed the list of marked squares with two that must be associated * with our dot (possibly the same space) */ if (dot->type == s_tile) { sctx->scratch[0] = sctx->scratch[1] = dot; } else if (dot->type == s_edge) { tiles_from_edge(state, dot, sctx->scratch); } else if (dot->type == s_vertex) { /* pick two of the opposite ones arbitrarily. */ sctx->scratch[0] = &SPACE(state, dot->x-1, dot->y-1); sctx->scratch[1] = &SPACE(state, dot->x+1, dot->y+1); } assert(sctx->scratch[0]->flags & F_TILE_ASSOC); assert(sctx->scratch[1]->flags & F_TILE_ASSOC); sctx->scratch[0]->flags |= F_MARK; sctx->scratch[1]->flags |= F_MARK; debug(("%*sexpand from dot %d,%d seeded with %d,%d and %d,%d.\n", solver_recurse_depth*4, "", dot->x, dot->y, sctx->scratch[0]->x, sctx->scratch[0]->y, sctx->scratch[1]->x, sctx->scratch[1]->y)); start = 0; end = 2; next = 2; expand: debug(("%*sexpand: start %d, end %d, next %d\n", solver_recurse_depth*4, "", start, end, next)); for (i = start; i < end; i += 2) { space *t1 = sctx->scratch[i]/*, *t2 = sctx->scratch[i+1]*/; space *edges[4], *tileadj[4], *tileadj2; adjacencies(state, t1, edges, tileadj); for (j = 0; j < 4; j++) { assert(edges[j]); if (edges[j]->flags & F_EDGE_SET) continue; assert(tileadj[j]); if (tileadj[j]->flags & F_MARK) continue; /* seen before. */ /* We have a tile adjacent to t1; find its opposite. */ tileadj2 = space_opposite_dot(state, tileadj[j], dot); if (!tileadj2) { debug(("%*sMarking %d,%d, no opposite.\n", solver_recurse_depth*4, "", tileadj[j]->x, tileadj[j]->y)); tileadj[j]->flags |= F_MARK; continue; /* no opposite, so mark for next time. */ } /* If the tile had an opposite we should have either seen both of * these, or neither of these, before. */ assert(!(tileadj2->flags & F_MARK)); if (solver_expand_checkdot(tileadj[j], dot) && solver_expand_checkdot(tileadj2, dot)) { /* Both tiles could associate with this dot; add them to * our list. */ debug(("%*sAdding %d,%d and %d,%d to possibles list.\n", solver_recurse_depth*4, "", tileadj[j]->x, tileadj[j]->y, tileadj2->x, tileadj2->y)); sctx->scratch[next++] = tileadj[j]; sctx->scratch[next++] = tileadj2; } /* Either way, we've seen these tiles already so mark them. */ debug(("%*sMarking %d,%d and %d,%d.\n", solver_recurse_depth*4, "", tileadj[j]->x, tileadj[j]->y, tileadj2->x, tileadj2->y)); tileadj[j]->flags |= F_MARK; tileadj2->flags |= F_MARK; } } if (next > end) { /* We added more squares; go back and try again. */ start = end; end = next; goto expand; } /* We've expanded as far as we can go. Now we update the main flags * on all tiles we've expanded into -- if they were empty, we have * found possible associations for this dot. */ for (i = 0; i < end; i++) { if (sctx->scratch[i]->flags & F_TILE_ASSOC) continue; if (sctx->scratch[i]->flags & F_REACHABLE) { /* This is (at least) the second dot this tile could * associate with. */ debug(("%*sempty tile %d,%d could assoc. other dot %d,%d\n", solver_recurse_depth*4, "", sctx->scratch[i]->x, sctx->scratch[i]->y, dot->x, dot->y)); sctx->scratch[i]->flags |= F_MULTIPLE; } else { /* This is the first (possibly only) dot. */ debug(("%*sempty tile %d,%d could assoc. 1st dot %d,%d\n", solver_recurse_depth*4, "", sctx->scratch[i]->x, sctx->scratch[i]->y, dot->x, dot->y)); sctx->scratch[i]->flags |= F_REACHABLE; sctx->scratch[i]->dotx = dot->x; sctx->scratch[i]->doty = dot->y; } } dbg_state(state); } static int solver_expand_postcb(game_state *state, space *tile, void *ctx) { assert(tile->type == s_tile); if (tile->flags & F_TILE_ASSOC) return 0; if (!(tile->flags & F_REACHABLE)) { solvep(("%*simpossible: space (%d,%d) can reach no dots.\n", solver_recurse_depth*4, "", tile->x, tile->y)); return -1; } if (tile->flags & F_MULTIPLE) return 0; return solver_add_assoc(state, tile, tile->dotx, tile->doty, "single possible dot after expansion"); } static int solver_expand_dots(game_state *state, solver_ctx *sctx) { int i; for (i = 0; i < sctx->sz; i++) state->grid[i].flags &= ~(F_REACHABLE|F_MULTIPLE); for (i = 0; i < state->ndots; i++) solver_expand_fromdot(state, state->dots[i], sctx); return foreach_tile(state, solver_expand_postcb, IMPOSSIBLE_QUITS, sctx); } struct recurse_ctx { space *best; int bestn; }; static int solver_recurse_cb(game_state *state, space *tile, void *ctx) { struct recurse_ctx *rctx = (struct recurse_ctx *)ctx; int i, n = 0; assert(tile->type == s_tile); if (tile->flags & F_TILE_ASSOC) return 0; /* We're unassociated: count up all the dots we could associate with. */ for (i = 0; i < state->ndots; i++) { if (dotfortile(state, tile, state->dots[i])) n++; } if (n > rctx->bestn) { rctx->bestn = n; rctx->best = tile; } return 0; } #define MAXRECURSE 5 static int solver_recurse(game_state *state, int maxdiff) { int diff = DIFF_IMPOSSIBLE, ret, n, gsz = state->sx * state->sy; space *ingrid, *outgrid = NULL, *bestopp; struct recurse_ctx rctx; if (solver_recurse_depth >= MAXRECURSE) { solvep(("Limiting recursion to %d, returning.", MAXRECURSE)); return DIFF_UNFINISHED; } /* Work out the cell to recurse on; go through all unassociated tiles * and find which one has the most possible dots it could associate * with. */ rctx.best = NULL; rctx.bestn = 0; foreach_tile(state, solver_recurse_cb, 0, &rctx); if (rctx.bestn == 0) return DIFF_IMPOSSIBLE; /* or assert? */ assert(rctx.best); solvep(("%*sRecursing around %d,%d, with %d possible dots.\n", solver_recurse_depth*4, "", rctx.best->x, rctx.best->y, rctx.bestn)); #ifdef STANDALONE_SOLVER solver_recurse_depth++; #endif ingrid = snewn(gsz, space); memcpy(ingrid, state->grid, gsz * sizeof(space)); for (n = 0; n < state->ndots; n++) { memcpy(state->grid, ingrid, gsz * sizeof(space)); if (!dotfortile(state, rctx.best, state->dots[n])) continue; /* set cell (temporarily) pointing to that dot. */ solver_add_assoc(state, rctx.best, state->dots[n]->x, state->dots[n]->y, "Attempting for recursion"); ret = solver_state(state, maxdiff); if (diff == DIFF_IMPOSSIBLE && ret != DIFF_IMPOSSIBLE) { /* we found our first solved grid; copy it away. */ assert(!outgrid); outgrid = snewn(gsz, space); memcpy(outgrid, state->grid, gsz * sizeof(space)); } /* reset cell back to unassociated. */ bestopp = tile_opposite(state, rctx.best); assert(bestopp && bestopp->flags & F_TILE_ASSOC); remove_assoc(state, rctx.best); remove_assoc(state, bestopp); if (ret == DIFF_AMBIGUOUS || ret == DIFF_UNFINISHED) diff = ret; else if (ret == DIFF_IMPOSSIBLE) /* no change */; else { /* precisely one solution */ if (diff == DIFF_IMPOSSIBLE) diff = DIFF_UNREASONABLE; else diff = DIFF_AMBIGUOUS; } /* if we've found >1 solution, or ran out of recursion, * give up immediately. */ if (diff == DIFF_AMBIGUOUS || diff == DIFF_UNFINISHED) break; } #ifdef STANDALONE_SOLVER solver_recurse_depth--; #endif if (outgrid) { /* we found (at least one) soln; copy it back to state */ memcpy(state->grid, outgrid, gsz * sizeof(space)); sfree(outgrid); } sfree(ingrid); return diff; } static int solver_state(game_state *state, int maxdiff) { solver_ctx *sctx = new_solver(state); int ret, diff = DIFF_NORMAL; #ifdef STANDALONE_PICTURE_GENERATOR /* hack, hack: set picture to NULL during solving so that add_assoc * won't complain when we attempt recursive guessing and guess wrong */ int *savepic = picture; picture = NULL; #endif ret = solver_obvious(state); if (ret < 0) { diff = DIFF_IMPOSSIBLE; goto got_result; } #define CHECKRET(d) do { \ if (ret < 0) { diff = DIFF_IMPOSSIBLE; goto got_result; } \ if (ret > 0) { diff = max(diff, (d)); goto cont; } \ } while(0) while (1) { cont: ret = foreach_edge(state, solver_lines_opposite_cb, IMPOSSIBLE_QUITS, sctx); CHECKRET(DIFF_NORMAL); ret = foreach_tile(state, solver_spaces_oneposs_cb, IMPOSSIBLE_QUITS, sctx); CHECKRET(DIFF_NORMAL); ret = solver_expand_dots(state, sctx); CHECKRET(DIFF_NORMAL); if (maxdiff <= DIFF_NORMAL) break; /* harder still? */ /* if we reach here, we've made no deductions, so we terminate. */ break; } if (check_complete(state, NULL, NULL)) goto got_result; diff = (maxdiff >= DIFF_UNREASONABLE) ? solver_recurse(state, maxdiff) : DIFF_UNFINISHED; got_result: free_solver(sctx); #ifndef STANDALONE_SOLVER debug(("solver_state ends, diff %s:\n", galaxies_diffnames[diff])); dbg_state(state); #endif #ifdef STANDALONE_PICTURE_GENERATOR picture = savepic; #endif return diff; } #ifndef EDITOR static char *solve_game(const game_state *state, const game_state *currstate, const char *aux, char **error) { game_state *tosolve; char *ret; int i; int diff; tosolve = dup_game(currstate); diff = solver_state(tosolve, DIFF_UNREASONABLE); if (diff != DIFF_UNFINISHED && diff != DIFF_IMPOSSIBLE) { debug(("solve_game solved with current state.\n")); goto solved; } free_game(tosolve); tosolve = dup_game(state); diff = solver_state(tosolve, DIFF_UNREASONABLE); if (diff != DIFF_UNFINISHED && diff != DIFF_IMPOSSIBLE) { debug(("solve_game solved with original state.\n")); goto solved; } free_game(tosolve); return NULL; solved: /* * Clear tile associations: the solution will only include the * edges. */ for (i = 0; i < tosolve->sx*tosolve->sy; i++) tosolve->grid[i].flags &= ~F_TILE_ASSOC; ret = diff_game(currstate, tosolve, 1); free_game(tosolve); return ret; } #endif /* ---------------------------------------------------------- * User interface. */ struct game_ui { int dragging; int dx, dy; /* pixel coords of drag pos. */ int dotx, doty; /* grid coords of dot we're dragging from. */ int srcx, srcy; /* grid coords of drag start */ int cur_x, cur_y, cur_visible; }; static game_ui *new_ui(const game_state *state) { game_ui *ui = snew(game_ui); ui->dragging = FALSE; ui->cur_x = ui->cur_y = 1; ui->cur_visible = 0; return ui; } static void free_ui(game_ui *ui) { sfree(ui); } static char *encode_ui(const game_ui *ui) { return NULL; } static void decode_ui(game_ui *ui, const char *encoding) { } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { } #define FLASH_TIME 0.15F #define PREFERRED_TILE_SIZE 32 #define TILE_SIZE (ds->tilesize) #define DOT_SIZE (TILE_SIZE / 4) #define EDGE_THICKNESS (max(TILE_SIZE / 16, 2)) #define BORDER TILE_SIZE #define COORD(x) ( (x) * TILE_SIZE + BORDER ) #define SCOORD(x) ( ((x) * TILE_SIZE)/2 + BORDER ) #define FROMCOORD(x) ( ((x) - BORDER) / TILE_SIZE ) #define DRAW_WIDTH (BORDER * 2 + ds->w * TILE_SIZE) #define DRAW_HEIGHT (BORDER * 2 + ds->h * TILE_SIZE) #define CURSOR_SIZE DOT_SIZE struct game_drawstate { int started; int w, h; int tilesize; unsigned long *grid; int *dx, *dy; blitter *bl; blitter *blmirror; int dragging, dragx, dragy; int *colour_scratch; int cx, cy, cur_visible; blitter *cur_bl; }; #define CORNER_TOLERANCE 0.15F #define CENTRE_TOLERANCE 0.15F /* * Round FP coordinates to the centre of the nearest edge. */ #ifndef EDITOR static void coord_round_to_edge(float x, float y, int *xr, int *yr) { float xs, ys, xv, yv, dx, dy; /* * Find the nearest square-centre. */ xs = (float)floor(x) + 0.5F; ys = (float)floor(y) + 0.5F; /* * Find the nearest grid vertex. */ xv = (float)floor(x + 0.5F); yv = (float)floor(y + 0.5F); /* * Determine whether the horizontal or vertical edge from that * vertex alongside that square is closer to us, by comparing * distances from the square cente. */ dx = (float)fabs(x - xs); dy = (float)fabs(y - ys); if (dx > dy) { /* Vertical edge: x-coord of corner, * y-coord of square centre. */ *xr = 2 * (int)xv; *yr = 1 + 2 * (int)floor(ys); } else { /* Horizontal edge: x-coord of square centre, * y-coord of corner. */ *xr = 1 + 2 * (int)floor(xs); *yr = 2 * (int)yv; } } #endif #ifdef EDITOR static char *interpret_move(const game_state *state, game_ui *ui, const game_drawstate *ds, int x, int y, int button) { char buf[80]; int px, py; space *sp; px = 2*FROMCOORD((float)x) + 0.5; py = 2*FROMCOORD((float)y) + 0.5; state->cdiff = -1; if (button == 'C' || button == 'c') return dupstr("C"); if (button == 'S' || button == 's') { char *ret; game_state *tmp = dup_game(state); state->cdiff = solver_state(tmp, DIFF_UNREASONABLE-1); ret = diff_game(state, tmp, 0); free_game(tmp); return ret; } if (button == LEFT_BUTTON || button == RIGHT_BUTTON) { if (!INUI(state, px, py)) return NULL; sp = &SPACE(state, px, py); if (!dot_is_possible(state, sp, 1)) return NULL; sprintf(buf, "%c%d,%d", (char)((button == LEFT_BUTTON) ? 'D' : 'd'), px, py); return dupstr(buf); } return NULL; } #else static char *interpret_move(const game_state *state, game_ui *ui, const game_drawstate *ds, int x, int y, int button) { /* UI operations (play mode): * * Toggle edge (set/unset) (left-click on edge) * Associate space with dot (left-drag from dot) * Unassociate space (left-drag from space off grid) * Autofill lines around shape? (right-click?) * * (edit mode; will clear all lines/associations) * * Add or remove dot (left-click) */ char buf[80]; const char *sep = ""; int px, py; space *sp, *dot; buf[0] = '\0'; if (button == 'H' || button == 'h') { char *ret; game_state *tmp = dup_game(state); solver_obvious(tmp); ret = diff_game(state, tmp, 0); free_game(tmp); return ret; } if (button == LEFT_BUTTON) { ui->cur_visible = 0; coord_round_to_edge(FROMCOORD((float)x), FROMCOORD((float)y), &px, &py); if (!INUI(state, px, py)) return NULL; sp = &SPACE(state, px, py); assert(sp->type == s_edge); { sprintf(buf, "E%d,%d", px, py); return dupstr(buf); } } else if (button == RIGHT_BUTTON) { int px1, py1; ui->cur_visible = 0; px = (int)(2*FROMCOORD((float)x) + 0.5); py = (int)(2*FROMCOORD((float)y) + 0.5); dot = NULL; /* * If there's a dot anywhere nearby, we pick up an arrow * pointing at that dot. */ for (py1 = py-1; py1 <= py+1; py1++) for (px1 = px-1; px1 <= px+1; px1++) { if (px1 >= 0 && px1 < state->sx && py1 >= 0 && py1 < state->sy && x >= SCOORD(px1-1) && x < SCOORD(px1+1) && y >= SCOORD(py1-1) && y < SCOORD(py1+1) && SPACE(state, px1, py1).flags & F_DOT) { /* * Found a dot. Begin a drag from it. */ dot = &SPACE(state, px1, py1); ui->srcx = px1; ui->srcy = py1; goto done; /* multi-level break */ } } /* * Otherwise, find the nearest _square_, and pick up the * same arrow as it's got on it, if any. */ if (!dot) { px = 2*FROMCOORD(x+TILE_SIZE) - 1; py = 2*FROMCOORD(y+TILE_SIZE) - 1; if (px >= 0 && px < state->sx && py >= 0 && py < state->sy) { sp = &SPACE(state, px, py); if (sp->flags & F_TILE_ASSOC) { dot = &SPACE(state, sp->dotx, sp->doty); ui->srcx = px; ui->srcy = py; } } } done: /* * Now, if we've managed to find a dot, begin a drag. */ if (dot) { ui->dragging = TRUE; ui->dx = x; ui->dy = y; ui->dotx = dot->x; ui->doty = dot->y; return ""; } } else if (button == RIGHT_DRAG && ui->dragging) { /* just move the drag coords. */ ui->dx = x; ui->dy = y; return ""; } else if (button == RIGHT_RELEASE && ui->dragging) { ui->dragging = FALSE; /* * Drags are always targeted at a single square. */ px = 2*FROMCOORD(x+TILE_SIZE) - 1; py = 2*FROMCOORD(y+TILE_SIZE) - 1; /* * Dragging an arrow on to the same square it started from * is a null move; just update the ui and finish. */ if (px == ui->srcx && py == ui->srcy) return ""; /* * Otherwise, we remove the arrow from its starting * square if we didn't start from a dot... */ if ((ui->srcx != ui->dotx || ui->srcy != ui->doty) && SPACE(state, ui->srcx, ui->srcy).flags & F_TILE_ASSOC) { sprintf(buf + strlen(buf), "%sU%d,%d", sep, ui->srcx, ui->srcy); sep = ";"; } /* * ... and if the square we're moving it _to_ is valid, we * add one there instead. */ if (INUI(state, px, py)) { sp = &SPACE(state, px, py); if (!(sp->flags & F_DOT)) sprintf(buf + strlen(buf), "%sA%d,%d,%d,%d", sep, px, py, ui->dotx, ui->doty); } if (buf[0]) return dupstr(buf); else return ""; } else if (IS_CURSOR_MOVE(button)) { move_cursor(button, &ui->cur_x, &ui->cur_y, state->sx-1, state->sy-1, 0); if (ui->cur_x < 1) ui->cur_x = 1; if (ui->cur_y < 1) ui->cur_y = 1; ui->cur_visible = 1; if (ui->dragging) { ui->dx = SCOORD(ui->cur_x); ui->dy = SCOORD(ui->cur_y); } return ""; } else if (IS_CURSOR_SELECT(button)) { if (!ui->cur_visible) { ui->cur_visible = 1; return ""; } sp = &SPACE(state, ui->cur_x, ui->cur_y); if (ui->dragging) { ui->dragging = FALSE; if ((ui->srcx != ui->dotx || ui->srcy != ui->doty) && SPACE(state, ui->srcx, ui->srcy).flags & F_TILE_ASSOC) { sprintf(buf, "%sU%d,%d", sep, ui->srcx, ui->srcy); sep = ";"; } if (sp->type == s_tile && !(sp->flags & F_DOT) && !(sp->flags & F_TILE_ASSOC)) { sprintf(buf + strlen(buf), "%sA%d,%d,%d,%d", sep, ui->cur_x, ui->cur_y, ui->dotx, ui->doty); } return dupstr(buf); } else if (sp->flags & F_DOT) { ui->dragging = TRUE; ui->dx = SCOORD(ui->cur_x); ui->dy = SCOORD(ui->cur_y); ui->dotx = ui->srcx = ui->cur_x; ui->doty = ui->srcy = ui->cur_y; return ""; } else if (sp->flags & F_TILE_ASSOC) { assert(sp->type == s_tile); ui->dragging = TRUE; ui->dx = SCOORD(ui->cur_x); ui->dy = SCOORD(ui->cur_y); ui->dotx = sp->dotx; ui->doty = sp->doty; ui->srcx = ui->cur_x; ui->srcy = ui->cur_y; return ""; } else if (sp->type == s_edge) { sprintf(buf, "E%d,%d", ui->cur_x, ui->cur_y); return dupstr(buf); } } return NULL; } #endif static int check_complete(const game_state *state, int *dsf, int *colours) { int w = state->w, h = state->h; int x, y, i, ret; int free_dsf; struct sqdata { int minx, miny, maxx, maxy; int cx, cy; int valid, colour; } *sqdata; if (!dsf) { dsf = snew_dsf(w*h); free_dsf = TRUE; } else { dsf_init(dsf, w*h); free_dsf = FALSE; } /* * During actual game play, completion checking is done on the * basis of the edges rather than the square associations. So * first we must go through the grid figuring out the connected * components into which the edges divide it. */ for (y = 0; y < h; y++) for (x = 0; x < w; x++) { if (y+1 < h && !(SPACE(state, 2*x+1, 2*y+2).flags & F_EDGE_SET)) dsf_merge(dsf, y*w+x, (y+1)*w+x); if (x+1 < w && !(SPACE(state, 2*x+2, 2*y+1).flags & F_EDGE_SET)) dsf_merge(dsf, y*w+x, y*w+(x+1)); } /* * That gives us our connected components. Now, for each * component, decide whether it's _valid_. A valid component is * one which: * * - is 180-degree rotationally symmetric * - has a dot at its centre of symmetry * - has no other dots anywhere within it (including on its * boundary) * - contains no internal edges (i.e. edges separating two * squares which are both part of the component). */ /* * First, go through the grid finding the bounding box of each * component. */ sqdata = snewn(w*h, struct sqdata); for (i = 0; i < w*h; i++) { sqdata[i].minx = w+1; sqdata[i].miny = h+1; sqdata[i].maxx = sqdata[i].maxy = -1; sqdata[i].valid = FALSE; } for (y = 0; y < h; y++) for (x = 0; x < w; x++) { i = dsf_canonify(dsf, y*w+x); if (sqdata[i].minx > x) sqdata[i].minx = x; if (sqdata[i].maxx < x) sqdata[i].maxx = x; if (sqdata[i].miny > y) sqdata[i].miny = y; if (sqdata[i].maxy < y) sqdata[i].maxy = y; sqdata[i].valid = TRUE; } /* * Now we're in a position to loop over each actual component * and figure out where its centre of symmetry has to be if * it's anywhere. */ for (i = 0; i < w*h; i++) if (sqdata[i].valid) { int cx, cy; cx = sqdata[i].cx = sqdata[i].minx + sqdata[i].maxx + 1; cy = sqdata[i].cy = sqdata[i].miny + sqdata[i].maxy + 1; if (!(SPACE(state, sqdata[i].cx, sqdata[i].cy).flags & F_DOT)) sqdata[i].valid = FALSE; /* no dot at centre of symmetry */ if (dsf_canonify(dsf, (cy-1)/2*w+(cx-1)/2) != i || dsf_canonify(dsf, (cy)/2*w+(cx-1)/2) != i || dsf_canonify(dsf, (cy-1)/2*w+(cx)/2) != i || dsf_canonify(dsf, (cy)/2*w+(cx)/2) != i) sqdata[i].valid = FALSE; /* dot at cx,cy isn't ours */ if (SPACE(state, sqdata[i].cx, sqdata[i].cy).flags & F_DOT_BLACK) sqdata[i].colour = 2; else sqdata[i].colour = 1; } /* * Now we loop over the whole grid again, this time finding * extraneous dots (any dot which wholly or partially overlaps * a square and is not at the centre of symmetry of that * square's component disqualifies the component from validity) * and extraneous edges (any edge separating two squares * belonging to the same component also disqualifies that * component). */ for (y = 1; y < state->sy-1; y++) for (x = 1; x < state->sx-1; x++) { space *sp = &SPACE(state, x, y); if (sp->flags & F_DOT) { /* * There's a dot here. Use it to disqualify any * component which deserves it. */ int cx, cy; for (cy = (y-1) >> 1; cy <= y >> 1; cy++) for (cx = (x-1) >> 1; cx <= x >> 1; cx++) { i = dsf_canonify(dsf, cy*w+cx); if (x != sqdata[i].cx || y != sqdata[i].cy) sqdata[i].valid = FALSE; } } if (sp->flags & F_EDGE_SET) { /* * There's an edge here. Use it to disqualify a * component if necessary. */ int cx1 = (x-1) >> 1, cx2 = x >> 1; int cy1 = (y-1) >> 1, cy2 = y >> 1; assert((cx1==cx2) ^ (cy1==cy2)); i = dsf_canonify(dsf, cy1*w+cx1); if (i == dsf_canonify(dsf, cy2*w+cx2)) sqdata[i].valid = FALSE; } } /* * And finally we test rotational symmetry: for each square in * the grid, find which component it's in, test that that * component also has a square in the symmetric position, and * disqualify it if it doesn't. */ for (y = 0; y < h; y++) for (x = 0; x < w; x++) { int x2, y2; i = dsf_canonify(dsf, y*w+x); x2 = sqdata[i].cx - 1 - x; y2 = sqdata[i].cy - 1 - y; if (i != dsf_canonify(dsf, y2*w+x2)) sqdata[i].valid = FALSE; } /* * That's it. We now have all the connected components marked * as valid or not valid. So now we return a `colours' array if * we were asked for one, and also we return an overall * true/false value depending on whether _every_ square in the * grid is part of a valid component. */ ret = TRUE; for (i = 0; i < w*h; i++) { int ci = dsf_canonify(dsf, i); int thisok = sqdata[ci].valid; if (colours) colours[i] = thisok ? sqdata[ci].colour : 0; ret = ret && thisok; } sfree(sqdata); if (free_dsf) sfree(dsf); return ret; } static game_state *execute_move(const game_state *state, const char *move) { int x, y, ax, ay, n, dx, dy; game_state *ret = dup_game(state); space *sp, *dot; int currently_solving = FALSE; debug(("%s\n", move)); while (*move) { char c = *move; if (c == 'E' || c == 'U' || c == 'M' #ifdef EDITOR || c == 'D' || c == 'd' #endif ) { move++; if (sscanf(move, "%d,%d%n", &x, &y, &n) != 2 || !INUI(ret, x, y)) goto badmove; sp = &SPACE(ret, x, y); #ifdef EDITOR if (c == 'D' || c == 'd') { unsigned int currf, newf, maskf; if (!dot_is_possible(ret, sp, 1)) goto badmove; newf = F_DOT | (c == 'd' ? F_DOT_BLACK : 0); currf = GRID(ret, grid, x, y).flags; maskf = F_DOT | F_DOT_BLACK; /* if we clicked 'white dot': * white --> empty, empty --> white, black --> white. * if we clicked 'black dot': * black --> empty, empty --> black, white --> black. */ if (currf & maskf) { sp->flags &= ~maskf; if ((currf & maskf) != newf) sp->flags |= newf; } else sp->flags |= newf; sp->nassoc = 0; /* edit-mode disallows associations. */ game_update_dots(ret); } else #endif if (c == 'E') { if (sp->type != s_edge) goto badmove; sp->flags ^= F_EDGE_SET; } else if (c == 'U') { if (sp->type != s_tile || !(sp->flags & F_TILE_ASSOC)) goto badmove; /* The solver doesn't assume we'll mirror things */ if (currently_solving) remove_assoc(ret, sp); else remove_assoc_with_opposite(ret, sp); } else if (c == 'M') { if (!(sp->flags & F_DOT)) goto badmove; sp->flags ^= F_DOT_HOLD; } move += n; } else if (c == 'A' || c == 'a') { move++; if (sscanf(move, "%d,%d,%d,%d%n", &x, &y, &ax, &ay, &n) != 4 || x < 1 || y < 1 || x >= (ret->sx-1) || y >= (ret->sy-1) || ax < 1 || ay < 1 || ax >= (ret->sx-1) || ay >= (ret->sy-1)) goto badmove; dot = &GRID(ret, grid, ax, ay); if (!(dot->flags & F_DOT))goto badmove; if (dot->flags & F_DOT_HOLD) goto badmove; for (dx = -1; dx <= 1; dx++) { for (dy = -1; dy <= 1; dy++) { sp = &GRID(ret, grid, x+dx, y+dy); if (sp->type != s_tile) continue; if (sp->flags & F_TILE_ASSOC) { space *dot = &SPACE(ret, sp->dotx, sp->doty); if (dot->flags & F_DOT_HOLD) continue; } /* The solver doesn't assume we'll mirror things */ if (currently_solving) add_assoc(ret, sp, dot); else add_assoc_with_opposite(ret, sp, dot); } } move += n; #ifdef EDITOR } else if (c == 'C') { move++; clear_game(ret, 1); #endif } else if (c == 'S') { move++; ret->used_solve = 1; currently_solving = TRUE; } else goto badmove; if (*move == ';') move++; else if (*move) goto badmove; } if (check_complete(ret, NULL, NULL)) ret->completed = 1; return ret; badmove: free_game(ret); return NULL; } /* ---------------------------------------------------------------------- * Drawing routines. */ /* Lines will be much smaller size than squares; say, 1/8 the size? * * Need a 'top-left corner of location XxY' to take this into account; * alternaticaly, that could give the middle of that location, and the * drawing code would just know the expected dimensions. * * We also need something to take a click and work out what it was * we were interested in. Clicking on vertices is required because * we may want to drag from them, for example. */ static void game_compute_size(const game_params *params, int sz, int *x, int *y) { struct { int tilesize, w, h; } ads, *ds = &ads; ds->tilesize = sz; ds->w = params->w; ds->h = params->h; *x = DRAW_WIDTH; *y = DRAW_HEIGHT; } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int sz) { ds->tilesize = sz; assert(TILE_SIZE > 0); assert(!ds->bl); ds->bl = blitter_new(dr, TILE_SIZE, TILE_SIZE); assert(!ds->blmirror); ds->blmirror = blitter_new(dr, TILE_SIZE, TILE_SIZE); assert(!ds->cur_bl); ds->cur_bl = blitter_new(dr, TILE_SIZE, TILE_SIZE); } static float *game_colours(frontend *fe, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float); int i; /* * We call game_mkhighlight to ensure the background colour * isn't completely white. We don't actually use the high- and * lowlight colours it generates. */ game_mkhighlight(fe, ret, COL_BACKGROUND, COL_WHITEBG, COL_BLACKBG); for (i = 0; i < 3; i++) { /* * Currently, white dots and white-background squares are * both pure white. */ ret[COL_WHITEDOT * 3 + i] = 1.0F; ret[COL_WHITEBG * 3 + i] = 1.0F; /* * But black-background squares are a dark grey, whereas * black dots are really black. */ ret[COL_BLACKDOT * 3 + i] = 0.0F; ret[COL_BLACKBG * 3 + i] = ret[COL_BACKGROUND * 3 + i] * 0.3F; /* * In unfilled squares, we draw a faint gridwork. */ ret[COL_GRID * 3 + i] = ret[COL_BACKGROUND * 3 + i] * 0.8F; /* * Edges and arrows are filled in in pure black. */ ret[COL_EDGE * 3 + i] = 0.0F; ret[COL_ARROW * 3 + i] = 0.0F; } #ifdef EDITOR /* tinge the edit background to bluey */ ret[COL_BACKGROUND * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] * 0.8F; ret[COL_BACKGROUND * 3 + 1] = ret[COL_BACKGROUND * 3 + 0] * 0.8F; ret[COL_BACKGROUND * 3 + 2] = min(ret[COL_BACKGROUND * 3 + 0] * 1.4F, 1.0F); #endif ret[COL_CURSOR * 3 + 0] = min(ret[COL_BACKGROUND * 3 + 0] * 1.4F, 1.0F); ret[COL_CURSOR * 3 + 1] = ret[COL_BACKGROUND * 3 + 0] * 0.8F; ret[COL_CURSOR * 3 + 2] = ret[COL_BACKGROUND * 3 + 0] * 0.8F; *ncolours = NCOLOURS; return ret; } static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { struct game_drawstate *ds = snew(struct game_drawstate); int i; ds->started = 0; ds->w = state->w; ds->h = state->h; ds->grid = snewn(ds->w*ds->h, unsigned long); for (i = 0; i < ds->w*ds->h; i++) ds->grid[i] = 0xFFFFFFFFUL; ds->dx = snewn(ds->w*ds->h, int); ds->dy = snewn(ds->w*ds->h, int); ds->bl = NULL; ds->blmirror = NULL; ds->dragging = FALSE; ds->dragx = ds->dragy = 0; ds->colour_scratch = snewn(ds->w * ds->h, int); ds->cur_bl = NULL; ds->cx = ds->cy = 0; ds->cur_visible = 0; return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { if (ds->cur_bl) blitter_free(dr, ds->cur_bl); sfree(ds->colour_scratch); if (ds->blmirror) blitter_free(dr, ds->blmirror); if (ds->bl) blitter_free(dr, ds->bl); sfree(ds->dx); sfree(ds->dy); sfree(ds->grid); sfree(ds); } #define DRAW_EDGE_L 0x0001 #define DRAW_EDGE_R 0x0002 #define DRAW_EDGE_U 0x0004 #define DRAW_EDGE_D 0x0008 #define DRAW_CORNER_UL 0x0010 #define DRAW_CORNER_UR 0x0020 #define DRAW_CORNER_DL 0x0040 #define DRAW_CORNER_DR 0x0080 #define DRAW_WHITE 0x0100 #define DRAW_BLACK 0x0200 #define DRAW_ARROW 0x0400 #define DRAW_CURSOR 0x0800 #define DOT_SHIFT_C 12 #define DOT_SHIFT_M 2 #define DOT_WHITE 1UL #define DOT_BLACK 2UL /* * Draw an arrow centred on (cx,cy), pointing in the direction * (ddx,ddy). (I.e. pointing at the point (cx+ddx, cy+ddy). */ static void draw_arrow(drawing *dr, game_drawstate *ds, int cx, int cy, int ddx, int ddy, int col) { float vlen = (float)sqrt(ddx*ddx+ddy*ddy); float xdx = ddx/vlen, xdy = ddy/vlen; float ydx = -xdy, ydy = xdx; int e1x = cx + (int)(xdx*TILE_SIZE/3), e1y = cy + (int)(xdy*TILE_SIZE/3); int e2x = cx - (int)(xdx*TILE_SIZE/3), e2y = cy - (int)(xdy*TILE_SIZE/3); int adx = (int)((ydx-xdx)*TILE_SIZE/8), ady = (int)((ydy-xdy)*TILE_SIZE/8); int adx2 = (int)((-ydx-xdx)*TILE_SIZE/8), ady2 = (int)((-ydy-xdy)*TILE_SIZE/8); draw_line(dr, e1x, e1y, e2x, e2y, col); draw_line(dr, e1x, e1y, e1x+adx, e1y+ady, col); draw_line(dr, e1x, e1y, e1x+adx2, e1y+ady2, col); } static void draw_square(drawing *dr, game_drawstate *ds, int x, int y, unsigned long flags, int ddx, int ddy) { int lx = COORD(x), ly = COORD(y); int dx, dy; int gridcol; clip(dr, lx, ly, TILE_SIZE, TILE_SIZE); /* * Draw the tile background. */ draw_rect(dr, lx, ly, TILE_SIZE, TILE_SIZE, (flags & DRAW_WHITE ? COL_WHITEBG : flags & DRAW_BLACK ? COL_BLACKBG : COL_BACKGROUND)); /* * Draw the grid. */ gridcol = (flags & DRAW_BLACK ? COL_BLACKDOT : COL_GRID); draw_rect(dr, lx, ly, 1, TILE_SIZE, gridcol); draw_rect(dr, lx, ly, TILE_SIZE, 1, gridcol); /* * Draw the arrow, if present, or the cursor, if here. */ if (flags & DRAW_ARROW) draw_arrow(dr, ds, lx + TILE_SIZE/2, ly + TILE_SIZE/2, ddx, ddy, (flags & DRAW_CURSOR) ? COL_CURSOR : COL_ARROW); else if (flags & DRAW_CURSOR) draw_rect_outline(dr, lx + TILE_SIZE/2 - CURSOR_SIZE, ly + TILE_SIZE/2 - CURSOR_SIZE, 2*CURSOR_SIZE+1, 2*CURSOR_SIZE+1, COL_CURSOR); /* * Draw the edges. */ if (flags & DRAW_EDGE_L) draw_rect(dr, lx, ly, EDGE_THICKNESS, TILE_SIZE, COL_EDGE); if (flags & DRAW_EDGE_R) draw_rect(dr, lx + TILE_SIZE - EDGE_THICKNESS + 1, ly, EDGE_THICKNESS - 1, TILE_SIZE, COL_EDGE); if (flags & DRAW_EDGE_U) draw_rect(dr, lx, ly, TILE_SIZE, EDGE_THICKNESS, COL_EDGE); if (flags & DRAW_EDGE_D) draw_rect(dr, lx, ly + TILE_SIZE - EDGE_THICKNESS + 1, TILE_SIZE, EDGE_THICKNESS - 1, COL_EDGE); if (flags & DRAW_CORNER_UL) draw_rect(dr, lx, ly, EDGE_THICKNESS, EDGE_THICKNESS, COL_EDGE); if (flags & DRAW_CORNER_UR) draw_rect(dr, lx + TILE_SIZE - EDGE_THICKNESS + 1, ly, EDGE_THICKNESS - 1, EDGE_THICKNESS, COL_EDGE); if (flags & DRAW_CORNER_DL) draw_rect(dr, lx, ly + TILE_SIZE - EDGE_THICKNESS + 1, EDGE_THICKNESS, EDGE_THICKNESS - 1, COL_EDGE); if (flags & DRAW_CORNER_DR) draw_rect(dr, lx + TILE_SIZE - EDGE_THICKNESS + 1, ly + TILE_SIZE - EDGE_THICKNESS + 1, EDGE_THICKNESS - 1, EDGE_THICKNESS - 1, COL_EDGE); /* * Draw the dots. */ for (dy = 0; dy < 3; dy++) for (dx = 0; dx < 3; dx++) { int dotval = (flags >> (DOT_SHIFT_C + DOT_SHIFT_M*(dy*3+dx))); dotval &= (1 << DOT_SHIFT_M)-1; if (dotval) draw_circle(dr, lx+dx*TILE_SIZE/2, ly+dy*TILE_SIZE/2, DOT_SIZE, (dotval == 1 ? COL_WHITEDOT : COL_BLACKDOT), COL_BLACKDOT); } unclip(dr); draw_update(dr, lx, ly, TILE_SIZE, TILE_SIZE); } static void calculate_opposite_point(const game_ui *ui, const game_drawstate *ds, const int x, const int y, int *oppositex, int *oppositey) { /* oppositex - dotx = dotx - x <=> oppositex = 2 * dotx - x */ *oppositex = 2 * SCOORD(ui->dotx) - x; *oppositey = 2 * SCOORD(ui->doty) - y; } static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float animtime, float flashtime) { int w = ds->w, h = ds->h; int x, y, flashing = FALSE; int oppx, oppy; if (flashtime > 0) { int frame = (int)(flashtime / FLASH_TIME); flashing = (frame % 2 == 0); } if (ds->dragging) { assert(ds->bl); assert(ds->blmirror); calculate_opposite_point(ui, ds, ds->dragx + TILE_SIZE/2, ds->dragy + TILE_SIZE/2, &oppx, &oppy); oppx -= TILE_SIZE/2; oppy -= TILE_SIZE/2; blitter_load(dr, ds->bl, ds->dragx, ds->dragy); draw_update(dr, ds->dragx, ds->dragy, TILE_SIZE, TILE_SIZE); blitter_load(dr, ds->blmirror, oppx, oppy); draw_update(dr, oppx, oppy, TILE_SIZE, TILE_SIZE); ds->dragging = FALSE; } if (ds->cur_visible) { assert(ds->cur_bl); blitter_load(dr, ds->cur_bl, ds->cx, ds->cy); draw_update(dr, ds->cx, ds->cy, CURSOR_SIZE*2+1, CURSOR_SIZE*2+1); ds->cur_visible = FALSE; } if (!ds->started) { draw_rect(dr, 0, 0, DRAW_WIDTH, DRAW_HEIGHT, COL_BACKGROUND); draw_rect(dr, BORDER - EDGE_THICKNESS + 1, BORDER - EDGE_THICKNESS + 1, w*TILE_SIZE + EDGE_THICKNESS*2 - 1, h*TILE_SIZE + EDGE_THICKNESS*2 - 1, COL_EDGE); draw_update(dr, 0, 0, DRAW_WIDTH, DRAW_HEIGHT); ds->started = TRUE; } check_complete(state, NULL, ds->colour_scratch); for (y = 0; y < h; y++) for (x = 0; x < w; x++) { unsigned long flags = 0; int ddx = 0, ddy = 0; space *sp, *opp; int dx, dy; /* * Set up the flags for this square. Firstly, see if we * have edges. */ if (SPACE(state, x*2, y*2+1).flags & F_EDGE_SET) flags |= DRAW_EDGE_L; if (SPACE(state, x*2+2, y*2+1).flags & F_EDGE_SET) flags |= DRAW_EDGE_R; if (SPACE(state, x*2+1, y*2).flags & F_EDGE_SET) flags |= DRAW_EDGE_U; if (SPACE(state, x*2+1, y*2+2).flags & F_EDGE_SET) flags |= DRAW_EDGE_D; /* * Also, mark corners of neighbouring edges. */ if ((x > 0 && SPACE(state, x*2-1, y*2).flags & F_EDGE_SET) || (y > 0 && SPACE(state, x*2, y*2-1).flags & F_EDGE_SET)) flags |= DRAW_CORNER_UL; if ((x+1 < w && SPACE(state, x*2+3, y*2).flags & F_EDGE_SET) || (y > 0 && SPACE(state, x*2+2, y*2-1).flags & F_EDGE_SET)) flags |= DRAW_CORNER_UR; if ((x > 0 && SPACE(state, x*2-1, y*2+2).flags & F_EDGE_SET) || (y+1 < h && SPACE(state, x*2, y*2+3).flags & F_EDGE_SET)) flags |= DRAW_CORNER_DL; if ((x+1 < w && SPACE(state, x*2+3, y*2+2).flags & F_EDGE_SET) || (y+1 < h && SPACE(state, x*2+2, y*2+3).flags & F_EDGE_SET)) flags |= DRAW_CORNER_DR; /* * If this square is part of a valid region, paint it * that region's colour. Exception: if we're flashing, * everything goes briefly back to background colour. */ sp = &SPACE(state, x*2+1, y*2+1); if (sp->flags & F_TILE_ASSOC) { opp = tile_opposite(state, sp); } else { opp = NULL; } if (ds->colour_scratch[y*w+x] && !flashing) { flags |= (ds->colour_scratch[y*w+x] == 2 ? DRAW_BLACK : DRAW_WHITE); } /* * If this square is associated with a dot but it isn't * part of a valid region, draw an arrow in it pointing * in the direction of that dot. * * Exception: if this is the source point of an active * drag, we don't draw the arrow. */ if ((sp->flags & F_TILE_ASSOC) && !ds->colour_scratch[y*w+x]) { if (ui->dragging && ui->srcx == x*2+1 && ui->srcy == y*2+1) { /* tile is the source, don't do it */ } else if (ui->dragging && opp && ui->srcx == opp->x && ui->srcy == opp->y) { /* opposite tile is the source, don't do it */ } else if (sp->doty != y*2+1 || sp->dotx != x*2+1) { flags |= DRAW_ARROW; ddy = sp->doty - (y*2+1); ddx = sp->dotx - (x*2+1); } } /* * Now go through the nine possible places we could * have dots. */ for (dy = 0; dy < 3; dy++) for (dx = 0; dx < 3; dx++) { sp = &SPACE(state, x*2+dx, y*2+dy); if (sp->flags & F_DOT) { unsigned long dotval = (sp->flags & F_DOT_BLACK ? DOT_BLACK : DOT_WHITE); flags |= dotval << (DOT_SHIFT_C + DOT_SHIFT_M*(dy*3+dx)); } } /* * Now work out if we have to draw a cursor for this square; * cursors-on-lines are taken care of below. */ if (ui->cur_visible && ui->cur_x == x*2+1 && ui->cur_y == y*2+1 && !(SPACE(state, x*2+1, y*2+1).flags & F_DOT)) flags |= DRAW_CURSOR; /* * Now we have everything we're going to need. Draw the * square. */ if (ds->grid[y*w+x] != flags || ds->dx[y*w+x] != ddx || ds->dy[y*w+x] != ddy) { draw_square(dr, ds, x, y, flags, ddx, ddy); ds->grid[y*w+x] = flags; ds->dx[y*w+x] = ddx; ds->dy[y*w+x] = ddy; } } /* * Draw a cursor. This secondary blitter is much less invasive than trying * to fix up all of the rest of the code with sufficient flags to be able to * display this sensibly. */ if (ui->cur_visible) { space *sp = &SPACE(state, ui->cur_x, ui->cur_y); ds->cur_visible = TRUE; ds->cx = SCOORD(ui->cur_x) - CURSOR_SIZE; ds->cy = SCOORD(ui->cur_y) - CURSOR_SIZE; blitter_save(dr, ds->cur_bl, ds->cx, ds->cy); if (sp->flags & F_DOT) { /* draw a red dot (over the top of whatever would be there already) */ draw_circle(dr, SCOORD(ui->cur_x), SCOORD(ui->cur_y), DOT_SIZE, COL_CURSOR, COL_BLACKDOT); } else if (sp->type != s_tile) { /* draw an edge/vertex square; tile cursors are dealt with above. */ int dx = (ui->cur_x % 2) ? CURSOR_SIZE : CURSOR_SIZE/3; int dy = (ui->cur_y % 2) ? CURSOR_SIZE : CURSOR_SIZE/3; int x1 = SCOORD(ui->cur_x)-dx, y1 = SCOORD(ui->cur_y)-dy; int xs = dx*2+1, ys = dy*2+1; draw_rect(dr, x1, y1, xs, ys, COL_CURSOR); } draw_update(dr, ds->cx, ds->cy, CURSOR_SIZE*2+1, CURSOR_SIZE*2+1); } if (ui->dragging) { ds->dragging = TRUE; ds->dragx = ui->dx - TILE_SIZE/2; ds->dragy = ui->dy - TILE_SIZE/2; calculate_opposite_point(ui, ds, ui->dx, ui->dy, &oppx, &oppy); blitter_save(dr, ds->bl, ds->dragx, ds->dragy); blitter_save(dr, ds->blmirror, oppx - TILE_SIZE/2, oppy - TILE_SIZE/2); draw_arrow(dr, ds, ui->dx, ui->dy, SCOORD(ui->dotx) - ui->dx, SCOORD(ui->doty) - ui->dy, COL_ARROW); draw_arrow(dr, ds, oppx, oppy, SCOORD(ui->dotx) - oppx, SCOORD(ui->doty) - oppy, COL_ARROW); } #ifdef EDITOR { char buf[256]; if (state->cdiff != -1) sprintf(buf, "Puzzle is %s.", galaxies_diffnames[state->cdiff]); else buf[0] = '\0'; status_bar(dr, buf); } #endif } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return 0.0F; } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { if ((!oldstate->completed && newstate->completed) && !(newstate->used_solve)) return 3 * FLASH_TIME; else return 0.0F; } static int game_status(const game_state *state) { return state->completed ? +1 : 0; } static int game_timing_state(const game_state *state, game_ui *ui) { return TRUE; } #ifndef EDITOR static void game_print_size(const game_params *params, float *x, float *y) { int pw, ph; /* * 8mm squares by default. (There isn't all that much detail * that needs to go in each square.) */ game_compute_size(params, 800, &pw, &ph); *x = pw / 100.0F; *y = ph / 100.0F; } static void game_print(drawing *dr, const game_state *state, int sz) { int w = state->w, h = state->h; int white, black, blackish; int x, y, i, j; int *colours, *dsf; int *coords = NULL; int ncoords = 0, coordsize = 0; /* Ick: fake up `ds->tilesize' for macro expansion purposes */ game_drawstate ads, *ds = &ads; ds->tilesize = sz; white = print_mono_colour(dr, 1); black = print_mono_colour(dr, 0); blackish = print_hatched_colour(dr, HATCH_X); /* * Get the completion information. */ dsf = snewn(w * h, int); colours = snewn(w * h, int); check_complete(state, dsf, colours); /* * Draw the grid. */ print_line_width(dr, TILE_SIZE / 64); for (x = 1; x < w; x++) draw_line(dr, COORD(x), COORD(0), COORD(x), COORD(h), black); for (y = 1; y < h; y++) draw_line(dr, COORD(0), COORD(y), COORD(w), COORD(y), black); /* * Shade the completed regions. Just in case any particular * printing platform deals badly with adjacent * similarly-hatched regions, we'll fill each one as a single * polygon. */ for (i = 0; i < w*h; i++) { j = dsf_canonify(dsf, i); if (colours[j] != 0) { int dx, dy, t; /* * This is the first square we've run into belonging to * this polyomino, which means an edge of the polyomino * is certain to be to our left. (After we finish * tracing round it, we'll set the colours[] entry to * zero to prevent accidentally doing it again.) */ x = i % w; y = i / w; dx = -1; dy = 0; ncoords = 0; while (1) { /* * We are currently sitting on square (x,y), which * we know to be in our polyomino, and we also know * that (x+dx,y+dy) is not. The way I visualise * this is that we're standing to the right of a * boundary line, stretching our left arm out to * point to the exterior square on the far side. */ /* * First, check if we've gone round the entire * polyomino. */ if (ncoords > 0 && (x == i%w && y == i/w && dx == -1 && dy == 0)) break; /* * Add to our coordinate list the coordinate * backwards and to the left of where we are. */ if (ncoords + 2 > coordsize) { coordsize = (ncoords * 3 / 2) + 64; coords = sresize(coords, coordsize, int); } coords[ncoords++] = COORD((2*x+1 + dx + dy) / 2); coords[ncoords++] = COORD((2*y+1 + dy - dx) / 2); /* * Follow the edge round. If the square directly in * front of us is not part of the polyomino, we * turn right; if it is and so is the square in * front of (x+dx,y+dy), we turn left; otherwise we * go straight on. */ if (x-dy < 0 || x-dy >= w || y+dx < 0 || y+dx >= h || dsf_canonify(dsf, (y+dx)*w+(x-dy)) != j) { /* Turn right. */ t = dx; dx = -dy; dy = t; } else if (x+dx-dy >= 0 && x+dx-dy < w && y+dy+dx >= 0 && y+dy+dx < h && dsf_canonify(dsf, (y+dy+dx)*w+(x+dx-dy)) == j) { /* Turn left. */ x += dx; y += dy; t = dx; dx = dy; dy = -t; x -= dx; y -= dy; } else { /* Straight on. */ x -= dy; y += dx; } } /* * Now we have our polygon complete, so fill it. */ draw_polygon(dr, coords, ncoords/2, colours[j] == 2 ? blackish : -1, black); /* * And mark this polyomino as done. */ colours[j] = 0; } } /* * Draw the edges. */ for (y = 0; y <= h; y++) for (x = 0; x <= w; x++) { if (x < w && SPACE(state, x*2+1, y*2).flags & F_EDGE_SET) draw_rect(dr, COORD(x)-EDGE_THICKNESS, COORD(y)-EDGE_THICKNESS, EDGE_THICKNESS * 2 + TILE_SIZE, EDGE_THICKNESS * 2, black); if (y < h && SPACE(state, x*2, y*2+1).flags & F_EDGE_SET) draw_rect(dr, COORD(x)-EDGE_THICKNESS, COORD(y)-EDGE_THICKNESS, EDGE_THICKNESS * 2, EDGE_THICKNESS * 2 + TILE_SIZE, black); } /* * Draw the dots. */ for (y = 0; y <= 2*h; y++) for (x = 0; x <= 2*w; x++) if (SPACE(state, x, y).flags & F_DOT) { draw_circle(dr, (int)COORD(x/2.0), (int)COORD(y/2.0), DOT_SIZE, (SPACE(state, x, y).flags & F_DOT_BLACK ? black : white), black); } sfree(dsf); sfree(colours); sfree(coords); } #endif #ifdef COMBINED #define thegame galaxies #endif const struct game thegame = { "Galaxies", "games.galaxies", "galaxies", default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, #ifdef EDITOR FALSE, NULL, #else TRUE, solve_game, #endif TRUE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, PREFERRED_TILE_SIZE, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, #ifdef EDITOR FALSE, FALSE, NULL, NULL, TRUE, /* wants_statusbar */ #else TRUE, FALSE, game_print_size, game_print, FALSE, /* wants_statusbar */ #endif FALSE, game_timing_state, REQUIRE_RBUTTON, /* flags */ }; #ifdef STANDALONE_SOLVER const char *quis; #include static void usage_exit(const char *msg) { if (msg) fprintf(stderr, "%s: %s\n", quis, msg); fprintf(stderr, "Usage: %s [--seed SEED] --soak | [game_id [game_id ...]]\n", quis); exit(1); } static void dump_state(game_state *state) { char *temp = game_text_format(state); printf("%s\n", temp); sfree(temp); } static int gen(game_params *p, random_state *rs, int debug) { char *desc; int diff; game_state *state; #ifndef DEBUGGING solver_show_working = debug; #endif printf("Generating a %dx%d %s puzzle.\n", p->w, p->h, galaxies_diffnames[p->diff]); desc = new_game_desc(p, rs, NULL, 0); state = new_game(NULL, p, desc); dump_state(state); diff = solver_state(state, DIFF_UNREASONABLE); printf("Generated %s game %dx%d:%s\n", galaxies_diffnames[diff], p->w, p->h, desc); dump_state(state); free_game(state); sfree(desc); return diff; } static void soak(game_params *p, random_state *rs) { time_t tt_start, tt_now, tt_last; char *desc; game_state *st; int diff, n = 0, i, diffs[DIFF_MAX], ndots = 0, nspaces = 0; #ifndef DEBUGGING solver_show_working = 0; #endif tt_start = tt_now = time(NULL); for (i = 0; i < DIFF_MAX; i++) diffs[i] = 0; maxtries = 1; printf("Soak-generating a %dx%d grid, max. diff %s.\n", p->w, p->h, galaxies_diffnames[p->diff]); printf(" ["); for (i = 0; i < DIFF_MAX; i++) printf("%s%s", (i == 0) ? "" : ", ", galaxies_diffnames[i]); printf("]\n"); while (1) { desc = new_game_desc(p, rs, NULL, 0); st = new_game(NULL, p, desc); diff = solver_state(st, p->diff); nspaces += st->w*st->h; for (i = 0; i < st->sx*st->sy; i++) if (st->grid[i].flags & F_DOT) ndots++; free_game(st); sfree(desc); diffs[diff]++; n++; tt_last = time(NULL); if (tt_last > tt_now) { tt_now = tt_last; printf("%d total, %3.1f/s, [", n, (double)n / ((double)tt_now - tt_start)); for (i = 0; i < DIFF_MAX; i++) printf("%s%.1f%%", (i == 0) ? "" : ", ", 100.0 * ((double)diffs[i] / (double)n)); printf("], %.1f%% dots\n", 100.0 * ((double)ndots / (double)nspaces)); } } } int main(int argc, char **argv) { game_params *p; char *id = NULL, *desc, *err; game_state *s; int diff, do_soak = 0, verbose = 0; random_state *rs; time_t seed = time(NULL); quis = argv[0]; while (--argc > 0) { char *p = *++argv; if (!strcmp(p, "-v")) { verbose = 1; } else if (!strcmp(p, "--seed")) { if (argc == 0) usage_exit("--seed needs an argument"); seed = (time_t)atoi(*++argv); argc--; } else if (!strcmp(p, "--soak")) { do_soak = 1; } else if (*p == '-') { usage_exit("unrecognised option"); } else { id = p; } } maxtries = 50; p = default_params(); rs = random_new((void*)&seed, sizeof(time_t)); if (do_soak) { if (!id) usage_exit("need one argument for --soak"); decode_params(p, *argv); soak(p, rs); return 0; } if (!id) { while (1) { p->w = random_upto(rs, 15) + 3; p->h = random_upto(rs, 15) + 3; p->diff = random_upto(rs, DIFF_UNREASONABLE); diff = gen(p, rs, 0); } return 0; } desc = strchr(id, ':'); if (!desc) { decode_params(p, id); gen(p, rs, verbose); } else { #ifndef DEBUGGING solver_show_working = 1; #endif *desc++ = '\0'; decode_params(p, id); err = validate_desc(p, desc); if (err) { fprintf(stderr, "%s: %s\n", argv[0], err); exit(1); } s = new_game(NULL, p, desc); diff = solver_state(s, DIFF_UNREASONABLE); dump_state(s); printf("Puzzle is %s.\n", galaxies_diffnames[diff]); free_game(s); } free_params(p); return 0; } #endif #ifdef STANDALONE_PICTURE_GENERATOR /* * Main program for the standalone picture generator. To use it, * simply provide it with an XBM-format bitmap file (note XBM, not * XPM) on standard input, and it will output a game ID in return. * For example: * * $ ./galaxiespicture < badly-drawn-cat.xbm * 11x11:eloMBLzFeEzLNMWifhaWYdDbixCymBbBMLoDdewGg * * If you want a puzzle with a non-standard difficulty level, pass * a partial parameters string as a command-line argument (e.g. * `./galaxiespicture du < foo.xbm', where `du' is the same suffix * which if it appeared in a random-seed game ID would set the * difficulty level to Unreasonable). However, be aware that if the * generator fails to produce an adequately difficult puzzle too * many times then it will give up and return an easier one (just * as it does during normal GUI play). To be sure you really have * the difficulty you asked for, use galaxiessolver to * double-check. * * (Perhaps I ought to include an option to make this standalone * generator carry on looping until it really does get the right * difficulty. Hmmm.) */ #include int main(int argc, char **argv) { game_params *par; char *params, *desc; random_state *rs; time_t seed = time(NULL); char buf[4096]; int i; int x, y; par = default_params(); if (argc > 1) decode_params(par, argv[1]); /* get difficulty */ par->w = par->h = -1; /* * Now read an XBM file from standard input. This is simple and * hacky and will do very little error detection, so don't feed * it bogus data. */ picture = NULL; x = y = 0; while (fgets(buf, sizeof(buf), stdin)) { buf[strcspn(buf, "\r\n")] = '\0'; if (!strncmp(buf, "#define", 7)) { /* * Lines starting `#define' give the width and height. */ char *num = buf + strlen(buf); char *symend; while (num > buf && isdigit((unsigned char)num[-1])) num--; symend = num; while (symend > buf && isspace((unsigned char)symend[-1])) symend--; if (symend-5 >= buf && !strncmp(symend-5, "width", 5)) par->w = atoi(num); else if (symend-6 >= buf && !strncmp(symend-6, "height", 6)) par->h = atoi(num); } else { /* * Otherwise, break the string up into words and take * any word of the form `0x' plus hex digits to be a * byte. */ char *p, *wordstart; if (!picture) { if (par->w < 0 || par->h < 0) { printf("failed to read width and height\n"); return 1; } picture = snewn(par->w * par->h, int); for (i = 0; i < par->w * par->h; i++) picture[i] = -1; } p = buf; while (*p) { while (*p && (*p == ',' || isspace((unsigned char)*p))) p++; wordstart = p; while (*p && !(*p == ',' || *p == '}' || isspace((unsigned char)*p))) p++; if (*p) *p++ = '\0'; if (wordstart[0] == '0' && (wordstart[1] == 'x' || wordstart[1] == 'X') && !wordstart[2 + strspn(wordstart+2, "0123456789abcdefABCDEF")]) { unsigned long byte = strtoul(wordstart+2, NULL, 16); for (i = 0; i < 8; i++) { int bit = (byte >> i) & 1; if (y < par->h && x < par->w) picture[y * par->w + x] = bit; x++; } if (x >= par->w) { x = 0; y++; } } } } } for (i = 0; i < par->w * par->h; i++) if (picture[i] < 0) { fprintf(stderr, "failed to read enough bitmap data\n"); return 1; } rs = random_new((void*)&seed, sizeof(time_t)); desc = new_game_desc(par, rs, NULL, FALSE); params = encode_params(par, FALSE); printf("%s:%s\n", params, desc); sfree(desc); sfree(params); free_params(par); random_free(rs); return 0; } #endif /* vim: set shiftwidth=4 tabstop=8: */ puzzles-20170606.272beef/flood.c0000644000175000017500000011214113115373615015140 0ustar simonsimon/* * flood.c: puzzle in which you make a grid all the same colour by * repeatedly flood-filling the top left corner, and try to do so in * as few moves as possible. */ /* * Possible further work: * * - UI: perhaps we should only permit clicking on regions that can * actually be reached by the next flood-fill - i.e. a click is * only interpreted as a move if it would cause the clicked-on * square to become part of the controlled area. This provides a * hint in cases where you mistakenly thought that would happen, * and protects you against typos in cases where you just * mis-aimed. * * - UI: perhaps mark the fill square in some way? Or even mark the * whole connected component _containing_ the fill square. Pro: * that would make it easier to tell apart cases where almost all * the yellow squares in the grid are part of the target component * (hence, yellow is _done_ and you never have to fill in that * colour again) from cases where there's still one yellow square * that's only diagonally adjacent and hence will need coming back * to. Con: but it would almost certainly be ugly. */ #include #include #include #include #include #include #include #include "puzzles.h" enum { COL_BACKGROUND, COL_SEPARATOR, COL_1, COL_2, COL_3, COL_4, COL_5, COL_6, COL_7, COL_8, COL_9, COL_10, COL_HIGHLIGHT, COL_LOWLIGHT, NCOLOURS }; struct game_params { int w, h; int colours; int leniency; }; /* Just in case I want to make this changeable later, I'll put the * coordinates of the flood-fill point here so that it'll be easy to * find everywhere later that has to change. */ #define FILLX 0 #define FILLY 0 typedef struct soln { int refcount; int nmoves; char *moves; } soln; struct game_state { int w, h, colours; int moves, movelimit; int complete; char *grid; int cheated; int solnpos; soln *soln; }; static game_params *default_params(void) { game_params *ret = snew(game_params); ret->w = ret->h = 12; ret->colours = 6; ret->leniency = 5; return ret; } static const struct { struct game_params preset; const char *name; } flood_presets[] = { /* Default 12x12 size, three difficulty levels. */ {{12, 12, 6, 5}, "12x12 Easy"}, {{12, 12, 6, 2}, "12x12 Medium"}, {{12, 12, 6, 0}, "12x12 Hard"}, /* Larger puzzles, leaving off Easy in the expectation that people * wanting a bigger grid will have played it enough to find Easy * easy. */ {{16, 16, 6, 2}, "16x16 Medium"}, {{16, 16, 6, 0}, "16x16 Hard"}, /* A couple of different colour counts. It seems generally not too * hard with fewer colours (probably because fewer choices), so no * extra moves for these modes. */ {{12, 12, 3, 0}, "12x12, 3 colours"}, {{12, 12, 4, 0}, "12x12, 4 colours"}, }; static int game_fetch_preset(int i, char **name, game_params **params) { game_params *ret; if (i < 0 || i >= lenof(flood_presets)) return FALSE; ret = snew(game_params); *ret = flood_presets[i].preset; *name = dupstr(flood_presets[i].name); *params = ret; return TRUE; } static void free_params(game_params *params) { sfree(params); } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } static void decode_params(game_params *ret, char const *string) { ret->w = ret->h = atoi(string); while (*string && isdigit((unsigned char)*string)) string++; if (*string == 'x') { string++; ret->h = atoi(string); while (*string && isdigit((unsigned char)*string)) string++; } while (*string) { if (*string == 'c') { string++; ret->colours = atoi(string); while (string[1] && isdigit((unsigned char)string[1])) string++; } else if (*string == 'm') { string++; ret->leniency = atoi(string); while (string[1] && isdigit((unsigned char)string[1])) string++; } string++; } } static char *encode_params(const game_params *params, int full) { char buf[256]; sprintf(buf, "%dx%d", params->w, params->h); if (full) sprintf(buf + strlen(buf), "c%dm%d", params->colours, params->leniency); return dupstr(buf); } static config_item *game_configure(const game_params *params) { config_item *ret; char buf[80]; ret = snewn(5, config_item); ret[0].name = "Width"; ret[0].type = C_STRING; sprintf(buf, "%d", params->w); ret[0].sval = dupstr(buf); ret[0].ival = 0; ret[1].name = "Height"; ret[1].type = C_STRING; sprintf(buf, "%d", params->h); ret[1].sval = dupstr(buf); ret[1].ival = 0; ret[2].name = "Colours"; ret[2].type = C_STRING; sprintf(buf, "%d", params->colours); ret[2].sval = dupstr(buf); ret[2].ival = 0; ret[3].name = "Extra moves permitted"; ret[3].type = C_STRING; sprintf(buf, "%d", params->leniency); ret[3].sval = dupstr(buf); ret[3].ival = 0; ret[4].name = NULL; ret[4].type = C_END; ret[4].sval = NULL; ret[4].ival = 0; return ret; } static game_params *custom_params(const config_item *cfg) { game_params *ret = snew(game_params); ret->w = atoi(cfg[0].sval); ret->h = atoi(cfg[1].sval); ret->colours = atoi(cfg[2].sval); ret->leniency = atoi(cfg[3].sval); return ret; } static char *validate_params(const game_params *params, int full) { if (params->w < 2 && params->h < 2) return "Grid must contain at least two squares"; if (params->colours < 3 || params->colours > 10) return "Must have between 3 and 10 colours"; if (params->leniency < 0) return "Leniency must be non-negative"; return NULL; } #if 0 /* * Bodge to permit varying the recursion depth for testing purposes. To test two Floods against each other: paste <(./flood.1 --generate 100 12x12c6m0#12345 | cut -f2 -d,) <(./flood.2 --generate 100 12x12c6m0#12345 | cut -f2 -d,) | awk '{print $2-$1}' | sort -n | uniq -c | awk '{print $2,$1}' | tee z and then run gnuplot and plot "z". */ static int rdepth = 0; #define RECURSION_DEPTH (rdepth) void check_recursion_depth(void) { if (!rdepth) { const char *depthstr = getenv("FLOOD_DEPTH"); rdepth = depthstr ? atoi(depthstr) : 1; rdepth = rdepth > 0 ? rdepth : 1; } } #else /* * Last time I empirically checked this, depth 3 was a noticeable * improvement on 2, but 4 only negligibly better than 3. */ #define RECURSION_DEPTH 3 #define check_recursion_depth() (void)0 #endif struct solver_scratch { int *queue[2]; int *dist; char *grid, *grid2; char *rgrids; }; static struct solver_scratch *new_scratch(int w, int h) { int wh = w*h; struct solver_scratch *scratch = snew(struct solver_scratch); check_recursion_depth(); scratch->queue[0] = snewn(wh, int); scratch->queue[1] = snewn(wh, int); scratch->dist = snewn(wh, int); scratch->grid = snewn(wh, char); scratch->grid2 = snewn(wh, char); scratch->rgrids = snewn(wh * RECURSION_DEPTH, char); return scratch; } static void free_scratch(struct solver_scratch *scratch) { sfree(scratch->queue[0]); sfree(scratch->queue[1]); sfree(scratch->dist); sfree(scratch->grid); sfree(scratch->grid2); sfree(scratch->rgrids); sfree(scratch); } #if 0 /* Diagnostic routines you can uncomment if you need them */ void dump_grid(int w, int h, const char *grid, const char *titlefmt, ...) { int x, y; if (titlefmt) { va_list ap; va_start(ap, titlefmt); vprintf(titlefmt, ap); va_end(ap); printf(":\n"); } else { printf("Grid:\n"); } for (y = 0; y < h; y++) { printf(" "); for (x = 0; x < w; x++) { printf("%1x", grid[y*w+x]); } printf("\n"); } } void dump_dist(int w, int h, const int *dists, const char *titlefmt, ...) { int x, y; if (titlefmt) { va_list ap; va_start(ap, titlefmt); vprintf(titlefmt, ap); va_end(ap); printf(":\n"); } else { printf("Distances:\n"); } for (y = 0; y < h; y++) { printf(" "); for (x = 0; x < w; x++) { printf("%3d", dists[y*w+x]); } printf("\n"); } } #endif /* * Search a grid to find the most distant square(s). Return their * distance and the number of them, and also the number of squares in * the current controlled set (i.e. at distance zero). */ static void search(int w, int h, char *grid, int x0, int y0, struct solver_scratch *scratch, int *rdist, int *rnumber, int *rcontrol) { int wh = w*h; int i, qcurr, qhead, qtail, qnext, currdist, remaining; for (i = 0; i < wh; i++) scratch->dist[i] = -1; scratch->queue[0][0] = y0*w+x0; scratch->queue[1][0] = y0*w+x0; scratch->dist[y0*w+x0] = 0; currdist = 0; qcurr = 0; qtail = 0; qhead = 1; qnext = 1; remaining = wh - 1; while (1) { if (qtail == qhead) { /* Switch queues. */ if (currdist == 0) *rcontrol = qhead; currdist++; qcurr ^= 1; /* switch queues */ qhead = qnext; qtail = 0; qnext = 0; #if 0 printf("switch queue, new dist %d, queue %d\n", currdist, qhead); #endif } else if (remaining == 0 && qnext == 0) { break; } else { int pos = scratch->queue[qcurr][qtail++]; int y = pos / w; int x = pos % w; #if 0 printf("checking neighbours of %d,%d\n", x, y); #endif int dir; for (dir = 0; dir < 4; dir++) { int y1 = y + (dir == 1 ? 1 : dir == 3 ? -1 : 0); int x1 = x + (dir == 0 ? 1 : dir == 2 ? -1 : 0); if (0 <= x1 && x1 < w && 0 <= y1 && y1 < h) { int pos1 = y1*w+x1; #if 0 printf("trying %d,%d: colours %d-%d dist %d\n", x1, y1, grid[pos], grid[pos1], scratch->dist[pos]); #endif if (scratch->dist[pos1] == -1 && ((grid[pos1] == grid[pos] && scratch->dist[pos] == currdist) || (grid[pos1] != grid[pos] && scratch->dist[pos] == currdist - 1))) { #if 0 printf("marking %d,%d dist %d\n", x1, y1, currdist); #endif scratch->queue[qcurr][qhead++] = pos1; scratch->queue[qcurr^1][qnext++] = pos1; scratch->dist[pos1] = currdist; remaining--; } } } } } *rdist = currdist; *rnumber = qhead; if (currdist == 0) *rcontrol = qhead; } /* * Enact a flood-fill move on a grid. */ static void fill(int w, int h, char *grid, int x0, int y0, char newcolour, int *queue) { char oldcolour; int qhead, qtail; oldcolour = grid[y0*w+x0]; assert(oldcolour != newcolour); grid[y0*w+x0] = newcolour; queue[0] = y0*w+x0; qtail = 0; qhead = 1; while (qtail < qhead) { int pos = queue[qtail++]; int y = pos / w; int x = pos % w; int dir; for (dir = 0; dir < 4; dir++) { int y1 = y + (dir == 1 ? 1 : dir == 3 ? -1 : 0); int x1 = x + (dir == 0 ? 1 : dir == 2 ? -1 : 0); if (0 <= x1 && x1 < w && 0 <= y1 && y1 < h) { int pos1 = y1*w+x1; if (grid[pos1] == oldcolour) { grid[pos1] = newcolour; queue[qhead++] = pos1; } } } } } /* * Detect a completed grid. */ static int completed(int w, int h, char *grid) { int wh = w*h; int i; for (i = 1; i < wh; i++) if (grid[i] != grid[0]) return FALSE; return TRUE; } /* * Try out every possible move on a grid, and choose whichever one * reduced the result of search() by the most. */ static char choosemove_recurse(int w, int h, char *grid, int x0, int y0, int maxmove, struct solver_scratch *scratch, int depth, int *rbestdist, int *rbestnumber, int *rbestcontrol) { int wh = w*h; char move, bestmove; int dist, number, control, bestdist, bestnumber, bestcontrol; char *tmpgrid; assert(0 <= depth && depth < RECURSION_DEPTH); tmpgrid = scratch->rgrids + depth*wh; bestdist = wh + 1; bestnumber = 0; bestcontrol = 0; bestmove = -1; #if 0 dump_grid(w, h, grid, "before choosemove_recurse %d", depth); #endif for (move = 0; move < maxmove; move++) { if (grid[y0*w+x0] == move) continue; memcpy(tmpgrid, grid, wh * sizeof(*grid)); fill(w, h, tmpgrid, x0, y0, move, scratch->queue[0]); if (completed(w, h, tmpgrid)) { /* * A move that wins is immediately the best, so stop * searching. Record what depth of recursion that happened * at, so that higher levels will choose a move that gets * to a winning position sooner. */ *rbestdist = -1; *rbestnumber = depth; *rbestcontrol = wh; return move; } if (depth < RECURSION_DEPTH-1) { choosemove_recurse(w, h, tmpgrid, x0, y0, maxmove, scratch, depth+1, &dist, &number, &control); } else { #if 0 dump_grid(w, h, tmpgrid, "after move %d at depth %d", move, depth); #endif search(w, h, tmpgrid, x0, y0, scratch, &dist, &number, &control); #if 0 dump_dist(w, h, scratch->dist, "after move %d at depth %d", move, depth); printf("move %d at depth %d: %d at %d\n", depth, move, number, dist); #endif } if (dist < bestdist || (dist == bestdist && (number < bestnumber || (number == bestnumber && (control > bestcontrol))))) { bestdist = dist; bestnumber = number; bestcontrol = control; bestmove = move; } } #if 0 printf("best at depth %d was %d (%d at %d, %d controlled)\n", depth, bestmove, bestnumber, bestdist, bestcontrol); #endif *rbestdist = bestdist; *rbestnumber = bestnumber; *rbestcontrol = bestcontrol; return bestmove; } static char choosemove(int w, int h, char *grid, int x0, int y0, int maxmove, struct solver_scratch *scratch) { int tmp0, tmp1, tmp2; return choosemove_recurse(w, h, grid, x0, y0, maxmove, scratch, 0, &tmp0, &tmp1, &tmp2); } static char *new_game_desc(const game_params *params, random_state *rs, char **aux, int interactive) { int w = params->w, h = params->h, wh = w*h; int i, moves; char *desc; struct solver_scratch *scratch; scratch = new_scratch(w, h); /* * Invent a random grid. */ for (i = 0; i < wh; i++) scratch->grid[i] = random_upto(rs, params->colours); /* * Run the solver, and count how many moves it uses. */ memcpy(scratch->grid2, scratch->grid, wh * sizeof(*scratch->grid2)); moves = 0; check_recursion_depth(); while (!completed(w, h, scratch->grid2)) { char move = choosemove(w, h, scratch->grid2, FILLX, FILLY, params->colours, scratch); fill(w, h, scratch->grid2, FILLX, FILLY, move, scratch->queue[0]); moves++; } /* * Adjust for difficulty. */ moves += params->leniency; /* * Encode the game id. */ desc = snewn(wh + 40, char); for (i = 0; i < wh; i++) { char colour = scratch->grid[i]; char textcolour = (colour > 9 ? 'A' : '0') + colour; desc[i] = textcolour; } sprintf(desc+i, ",%d", moves); free_scratch(scratch); return desc; } static char *validate_desc(const game_params *params, const char *desc) { int w = params->w, h = params->h, wh = w*h; int i; for (i = 0; i < wh; i++) { char c = *desc++; if (c == 0) return "Not enough data in grid description"; if (c >= '0' && c <= '9') c -= '0'; else if (c >= 'A' && c <= 'Z') c = 10 + (c - 'A'); else return "Bad character in grid description"; if ((unsigned)c >= params->colours) return "Colour out of range in grid description"; } if (*desc != ',') return "Expected ',' after grid description"; desc++; if (desc[strspn(desc, "0123456789")]) return "Badly formatted move limit after grid description"; return NULL; } static game_state *new_game(midend *me, const game_params *params, const char *desc) { int w = params->w, h = params->h, wh = w*h; game_state *state = snew(game_state); int i; state->w = w; state->h = h; state->colours = params->colours; state->moves = 0; state->grid = snewn(wh, char); for (i = 0; i < wh; i++) { char c = *desc++; assert(c); if (c >= '0' && c <= '9') c -= '0'; else if (c >= 'A' && c <= 'Z') c = 10 + (c - 'A'); else assert(!"bad colour"); state->grid[i] = c; } assert(*desc == ','); desc++; state->movelimit = atoi(desc); state->complete = FALSE; state->cheated = FALSE; state->solnpos = 0; state->soln = NULL; return state; } static game_state *dup_game(const game_state *state) { game_state *ret = snew(game_state); ret->w = state->w; ret->h = state->h; ret->colours = state->colours; ret->moves = state->moves; ret->movelimit = state->movelimit; ret->complete = state->complete; ret->grid = snewn(state->w * state->h, char); memcpy(ret->grid, state->grid, state->w * state->h * sizeof(*ret->grid)); ret->cheated = state->cheated; ret->soln = state->soln; if (ret->soln) ret->soln->refcount++; ret->solnpos = state->solnpos; return ret; } static void free_game(game_state *state) { if (state->soln && --state->soln->refcount == 0) { sfree(state->soln->moves); sfree(state->soln); } sfree(state->grid); sfree(state); } static char *solve_game(const game_state *state, const game_state *currstate, const char *aux, char **error) { int w = state->w, h = state->h, wh = w*h; char *moves, *ret, *p; int i, len, nmoves; char buf[256]; struct solver_scratch *scratch; if (currstate->complete) { *error = "Puzzle is already solved"; return NULL; } /* * Find the best solution our solver can give. */ moves = snewn(wh, char); /* sure to be enough */ nmoves = 0; scratch = new_scratch(w, h); memcpy(scratch->grid2, currstate->grid, wh * sizeof(*scratch->grid2)); check_recursion_depth(); while (!completed(w, h, scratch->grid2)) { char move = choosemove(w, h, scratch->grid2, FILLX, FILLY, currstate->colours, scratch); fill(w, h, scratch->grid2, FILLX, FILLY, move, scratch->queue[0]); assert(nmoves < wh); moves[nmoves++] = move; } free_scratch(scratch); /* * Encode it as a move string. */ len = 1; /* trailing NUL */ for (i = 0; i < nmoves; i++) len += sprintf(buf, ",%d", moves[i]); ret = snewn(len, char); p = ret; for (i = 0; i < nmoves; i++) p += sprintf(p, "%c%d", (i==0 ? 'S' : ','), moves[i]); assert(p - ret == len - 1); sfree(moves); return ret; } static int game_can_format_as_text_now(const game_params *params) { return TRUE; } static char *game_text_format(const game_state *state) { int w = state->w, h = state->h; char *ret, *p; int x, y, len; len = h * (w+1); /* +1 for newline after each row */ ret = snewn(len+1, char); /* and +1 for terminating \0 */ p = ret; for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { char colour = state->grid[y*w+x]; char textcolour = (colour > 9 ? 'A' : '0') + colour; *p++ = textcolour; } *p++ = '\n'; } assert(p - ret == len); *p = '\0'; return ret; } struct game_ui { int cursor_visible; int cx, cy; enum { VICTORY, DEFEAT } flash_type; }; static game_ui *new_ui(const game_state *state) { struct game_ui *ui = snew(struct game_ui); ui->cursor_visible = FALSE; ui->cx = FILLX; ui->cy = FILLY; return ui; } static void free_ui(game_ui *ui) { sfree(ui); } static char *encode_ui(const game_ui *ui) { return NULL; } static void decode_ui(game_ui *ui, const char *encoding) { } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { } struct game_drawstate { int started; int tilesize; int *grid; }; #define TILESIZE (ds->tilesize) #define PREFERRED_TILESIZE 32 #define BORDER (TILESIZE / 2) #define SEP_WIDTH (TILESIZE / 32) #define CURSOR_INSET (TILESIZE / 8) #define HIGHLIGHT_WIDTH (TILESIZE / 10) #define COORD(x) ( (x) * TILESIZE + BORDER ) #define FROMCOORD(x) ( ((x) - BORDER + TILESIZE) / TILESIZE - 1 ) #define VICTORY_FLASH_FRAME 0.03F #define DEFEAT_FLASH_FRAME 0.10F static char *interpret_move(const game_state *state, game_ui *ui, const game_drawstate *ds, int x, int y, int button) { int w = state->w, h = state->h; int tx = -1, ty = -1, move = -1; if (button == LEFT_BUTTON) { tx = FROMCOORD(x); ty = FROMCOORD(y); ui->cursor_visible = FALSE; } else if (button == CURSOR_LEFT && ui->cx > 0) { ui->cx--; ui->cursor_visible = TRUE; return ""; } else if (button == CURSOR_RIGHT && ui->cx+1 < w) { ui->cx++; ui->cursor_visible = TRUE; return ""; } else if (button == CURSOR_UP && ui->cy > 0) { ui->cy--; ui->cursor_visible = TRUE; return ""; } else if (button == CURSOR_DOWN && ui->cy+1 < h) { ui->cy++; ui->cursor_visible = TRUE; return ""; } else if (button == CURSOR_SELECT) { tx = ui->cx; ty = ui->cy; } else if (button == CURSOR_SELECT2 && state->soln && state->solnpos < state->soln->nmoves) { move = state->soln->moves[state->solnpos]; } else { return NULL; } if (tx >= 0 && tx < w && ty >= 0 && ty < h && state->grid[0] != state->grid[ty*w+tx]) move = state->grid[ty*w+tx]; if (move >= 0 && !state->complete) { char buf[256]; sprintf(buf, "M%d", move); return dupstr(buf); } return NULL; } static game_state *execute_move(const game_state *state, const char *move) { game_state *ret; int c; if (move[0] == 'M' && sscanf(move+1, "%d", &c) == 1 && c >= 0 && !state->complete) { int *queue = snewn(state->w * state->h, int); ret = dup_game(state); fill(ret->w, ret->h, ret->grid, FILLX, FILLY, c, queue); ret->moves++; ret->complete = completed(ret->w, ret->h, ret->grid); if (ret->soln) { /* * If this move is the correct next one in the stored * solution path, advance solnpos. */ if (c == ret->soln->moves[ret->solnpos] && ret->solnpos+1 < ret->soln->nmoves) { ret->solnpos++; } else { /* * Otherwise, the user has strayed from the path or * else the path has come to an end; either way, the * path is no longer valid. */ ret->soln->refcount--; assert(ret->soln->refcount > 0);/* `state' at least still exists */ ret->soln = NULL; ret->solnpos = 0; } } sfree(queue); return ret; } else if (*move == 'S') { soln *sol; const char *p; int i; /* * This is a solve move, so we don't actually _change_ the * grid but merely set up a stored solution path. */ move++; sol = snew(soln); sol->nmoves = 1; for (p = move; *p; p++) { if (*p == ',') sol->nmoves++; } sol->moves = snewn(sol->nmoves, char); for (i = 0, p = move; i < sol->nmoves; i++) { assert(*p); sol->moves[i] = atoi(p); p += strspn(p, "0123456789"); if (*p) { assert(*p == ','); p++; } } ret = dup_game(state); ret->cheated = TRUE; if (ret->soln && --ret->soln->refcount == 0) { sfree(ret->soln->moves); sfree(ret->soln); } ret->soln = sol; ret->solnpos = 0; sol->refcount = 1; return ret; } return NULL; } /* ---------------------------------------------------------------------- * Drawing routines. */ static void game_compute_size(const game_params *params, int tilesize, int *x, int *y) { /* Ick: fake up `ds->tilesize' for macro expansion purposes */ struct { int tilesize; } ads, *ds = &ads; ads.tilesize = tilesize; *x = BORDER * 2 + TILESIZE * params->w; *y = BORDER * 2 + TILESIZE * params->h; } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { ds->tilesize = tilesize; } static float *game_colours(frontend *fe, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float); game_mkhighlight(fe, ret, COL_BACKGROUND, COL_HIGHLIGHT, COL_LOWLIGHT); ret[COL_SEPARATOR * 3 + 0] = 0.0F; ret[COL_SEPARATOR * 3 + 1] = 0.0F; ret[COL_SEPARATOR * 3 + 2] = 0.0F; /* red */ ret[COL_1 * 3 + 0] = 1.0F; ret[COL_1 * 3 + 1] = 0.0F; ret[COL_1 * 3 + 2] = 0.0F; /* yellow */ ret[COL_2 * 3 + 0] = 1.0F; ret[COL_2 * 3 + 1] = 1.0F; ret[COL_2 * 3 + 2] = 0.0F; /* green */ ret[COL_3 * 3 + 0] = 0.0F; ret[COL_3 * 3 + 1] = 1.0F; ret[COL_3 * 3 + 2] = 0.0F; /* blue */ ret[COL_4 * 3 + 0] = 0.2F; ret[COL_4 * 3 + 1] = 0.3F; ret[COL_4 * 3 + 2] = 1.0F; /* orange */ ret[COL_5 * 3 + 0] = 1.0F; ret[COL_5 * 3 + 1] = 0.5F; ret[COL_5 * 3 + 2] = 0.0F; /* purple */ ret[COL_6 * 3 + 0] = 0.5F; ret[COL_6 * 3 + 1] = 0.0F; ret[COL_6 * 3 + 2] = 0.7F; /* brown */ ret[COL_7 * 3 + 0] = 0.5F; ret[COL_7 * 3 + 1] = 0.3F; ret[COL_7 * 3 + 2] = 0.3F; /* light blue */ ret[COL_8 * 3 + 0] = 0.4F; ret[COL_8 * 3 + 1] = 0.8F; ret[COL_8 * 3 + 2] = 1.0F; /* light green */ ret[COL_9 * 3 + 0] = 0.7F; ret[COL_9 * 3 + 1] = 1.0F; ret[COL_9 * 3 + 2] = 0.7F; /* pink */ ret[COL_10 * 3 + 0] = 1.0F; ret[COL_10 * 3 + 1] = 0.6F; ret[COL_10 * 3 + 2] = 1.0F; *ncolours = NCOLOURS; return ret; } static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { struct game_drawstate *ds = snew(struct game_drawstate); int w = state->w, h = state->h, wh = w*h; int i; ds->started = FALSE; ds->tilesize = 0; ds->grid = snewn(wh, int); for (i = 0; i < wh; i++) ds->grid[i] = -1; return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { sfree(ds->grid); sfree(ds); } #define BORDER_L 0x001 #define BORDER_R 0x002 #define BORDER_U 0x004 #define BORDER_D 0x008 #define CORNER_UL 0x010 #define CORNER_UR 0x020 #define CORNER_DL 0x040 #define CORNER_DR 0x080 #define CURSOR 0x100 #define BADFLASH 0x200 #define SOLNNEXT 0x400 #define COLOUR_SHIFT 11 static void draw_tile(drawing *dr, game_drawstate *ds, int x, int y, int tile) { int colour; int tx = COORD(x), ty = COORD(y); colour = tile >> COLOUR_SHIFT; if (tile & BADFLASH) colour = COL_SEPARATOR; else colour += COL_1; draw_rect(dr, tx, ty, TILESIZE, TILESIZE, colour); if (tile & BORDER_L) draw_rect(dr, tx, ty, SEP_WIDTH, TILESIZE, COL_SEPARATOR); if (tile & BORDER_R) draw_rect(dr, tx + TILESIZE - SEP_WIDTH, ty, SEP_WIDTH, TILESIZE, COL_SEPARATOR); if (tile & BORDER_U) draw_rect(dr, tx, ty, TILESIZE, SEP_WIDTH, COL_SEPARATOR); if (tile & BORDER_D) draw_rect(dr, tx, ty + TILESIZE - SEP_WIDTH, TILESIZE, SEP_WIDTH, COL_SEPARATOR); if (tile & CORNER_UL) draw_rect(dr, tx, ty, SEP_WIDTH, SEP_WIDTH, COL_SEPARATOR); if (tile & CORNER_UR) draw_rect(dr, tx + TILESIZE - SEP_WIDTH, ty, SEP_WIDTH, SEP_WIDTH, COL_SEPARATOR); if (tile & CORNER_DL) draw_rect(dr, tx, ty + TILESIZE - SEP_WIDTH, SEP_WIDTH, SEP_WIDTH, COL_SEPARATOR); if (tile & CORNER_DR) draw_rect(dr, tx + TILESIZE - SEP_WIDTH, ty + TILESIZE - SEP_WIDTH, SEP_WIDTH, SEP_WIDTH, COL_SEPARATOR); if (tile & CURSOR) draw_rect_outline(dr, tx + CURSOR_INSET, ty + CURSOR_INSET, TILESIZE - 1 - CURSOR_INSET * 2, TILESIZE - 1 - CURSOR_INSET * 2, COL_SEPARATOR); if (tile & SOLNNEXT) { draw_circle(dr, tx + TILESIZE/2, ty + TILESIZE/2, TILESIZE/6, COL_SEPARATOR, COL_SEPARATOR); } draw_update(dr, tx, ty, TILESIZE, TILESIZE); } static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float animtime, float flashtime) { int w = state->w, h = state->h, wh = w*h; int x, y, flashframe, solnmove; char *grid; /* This was entirely cloned from fifteen.c; it should probably be * moved into some generic 'draw-recessed-rectangle' utility fn. */ if (!ds->started) { int coords[10]; draw_rect(dr, 0, 0, TILESIZE * w + 2 * BORDER, TILESIZE * h + 2 * BORDER, COL_BACKGROUND); draw_update(dr, 0, 0, TILESIZE * w + 2 * BORDER, TILESIZE * h + 2 * BORDER); /* * Recessed area containing the whole puzzle. */ coords[0] = COORD(w) + HIGHLIGHT_WIDTH - 1; coords[1] = COORD(h) + HIGHLIGHT_WIDTH - 1; coords[2] = COORD(w) + HIGHLIGHT_WIDTH - 1; coords[3] = COORD(0) - HIGHLIGHT_WIDTH; coords[4] = coords[2] - TILESIZE; coords[5] = coords[3] + TILESIZE; coords[8] = COORD(0) - HIGHLIGHT_WIDTH; coords[9] = COORD(h) + HIGHLIGHT_WIDTH - 1; coords[6] = coords[8] + TILESIZE; coords[7] = coords[9] - TILESIZE; draw_polygon(dr, coords, 5, COL_HIGHLIGHT, COL_HIGHLIGHT); coords[1] = COORD(0) - HIGHLIGHT_WIDTH; coords[0] = COORD(0) - HIGHLIGHT_WIDTH; draw_polygon(dr, coords, 5, COL_LOWLIGHT, COL_LOWLIGHT); draw_rect(dr, COORD(0) - SEP_WIDTH, COORD(0) - SEP_WIDTH, TILESIZE * w + 2 * SEP_WIDTH, TILESIZE * h + 2 * SEP_WIDTH, COL_SEPARATOR); ds->started = 1; } if (flashtime > 0) { float frame = (ui->flash_type == VICTORY ? VICTORY_FLASH_FRAME : DEFEAT_FLASH_FRAME); flashframe = (int)(flashtime / frame); } else { flashframe = -1; } grid = snewn(wh, char); memcpy(grid, state->grid, wh * sizeof(*grid)); if (state->soln && state->solnpos < state->soln->nmoves) { int i, *queue; /* * Highlight as 'next auto-solver move' every square of the * target colour which is adjacent to the currently controlled * region. We do this by first enacting the actual move, then * flood-filling again in a nonexistent colour, and finally * reverting to the original grid anything in the new colour * that was part of the original controlled region. Then * regions coloured in the dummy colour should be displayed as * soln_move with the SOLNNEXT flag. */ solnmove = state->soln->moves[state->solnpos]; queue = snewn(wh, int); fill(w, h, grid, FILLX, FILLY, solnmove, queue); fill(w, h, grid, FILLX, FILLY, state->colours, queue); sfree(queue); for (i = 0; i < wh; i++) if (grid[i] == state->colours && state->grid[i] != solnmove) grid[i] = state->grid[i]; } else { solnmove = 0; /* placate optimiser */ } if (flashframe >= 0 && ui->flash_type == VICTORY) { /* * Modify the display grid by superimposing our rainbow flash * on it. */ for (x = 0; x < w; x++) { for (y = 0; y < h; y++) { int flashpos = flashframe - (abs(x - FILLX) + abs(y - FILLY)); if (flashpos >= 0 && flashpos < state->colours) grid[y*w+x] = flashpos; } } } for (x = 0; x < w; x++) { for (y = 0; y < h; y++) { int pos = y*w+x; int tile; if (grid[pos] == state->colours) { tile = (solnmove << COLOUR_SHIFT) | SOLNNEXT; } else { tile = (int)grid[pos] << COLOUR_SHIFT; } if (x == 0 || grid[pos-1] != grid[pos]) tile |= BORDER_L; if (x==w-1 || grid[pos+1] != grid[pos]) tile |= BORDER_R; if (y == 0 || grid[pos-w] != grid[pos]) tile |= BORDER_U; if (y==h-1 || grid[pos+w] != grid[pos]) tile |= BORDER_D; if (x == 0 || y == 0 || grid[pos-w-1] != grid[pos]) tile |= CORNER_UL; if (x==w-1 || y == 0 || grid[pos-w+1] != grid[pos]) tile |= CORNER_UR; if (x == 0 || y==h-1 || grid[pos+w-1] != grid[pos]) tile |= CORNER_DL; if (x==w-1 || y==h-1 || grid[pos+w+1] != grid[pos]) tile |= CORNER_DR; if (ui->cursor_visible && ui->cx == x && ui->cy == y) tile |= CURSOR; if (flashframe >= 0 && ui->flash_type == DEFEAT && flashframe != 1) tile |= BADFLASH; if (ds->grid[pos] != tile) { draw_tile(dr, ds, x, y, tile); ds->grid[pos] = tile; } } } sfree(grid); { char status[255]; sprintf(status, "%s%d / %d moves", (state->complete && state->moves <= state->movelimit ? (state->cheated ? "Auto-solved. " : "COMPLETED! ") : state->moves >= state->movelimit ? "FAILED! " : state->cheated ? "Auto-solver used. " : ""), state->moves, state->movelimit); status_bar(dr, status); } } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return 0.0F; } static int game_status(const game_state *state) { if (state->complete && state->moves <= state->movelimit) { return +1; /* victory! */ } else if (state->moves >= state->movelimit) { return -1; /* defeat */ } else { return 0; /* still playing */ } } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { if (dir == +1) { int old_status = game_status(oldstate); int new_status = game_status(newstate); if (old_status != new_status) { assert(old_status == 0); if (new_status == +1) { int frames = newstate->w + newstate->h + newstate->colours - 2; ui->flash_type = VICTORY; return VICTORY_FLASH_FRAME * frames; } else { ui->flash_type = DEFEAT; return DEFEAT_FLASH_FRAME * 3; } } } return 0.0F; } static int game_timing_state(const game_state *state, game_ui *ui) { return TRUE; } static void game_print_size(const game_params *params, float *x, float *y) { } static void game_print(drawing *dr, const game_state *state, int tilesize) { } #ifdef COMBINED #define thegame flood #endif const struct game thegame = { "Flood", "games.flood", "flood", default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, TRUE, solve_game, TRUE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, PREFERRED_TILESIZE, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, FALSE, FALSE, game_print_size, game_print, TRUE, /* wants_statusbar */ FALSE, game_timing_state, 0, /* flags */ }; puzzles-20170606.272beef/flip.c0000644000175000017500000011052613115373615014774 0ustar simonsimon/* * flip.c: Puzzle involving lighting up all the squares on a grid, * where each click toggles an overlapping set of lights. */ #include #include #include #include #include #include #include "puzzles.h" #include "tree234.h" enum { COL_BACKGROUND, COL_WRONG, COL_RIGHT, COL_GRID, COL_DIAG, COL_HINT, COL_CURSOR, NCOLOURS }; #define PREFERRED_TILE_SIZE 48 #define TILE_SIZE (ds->tilesize) #define BORDER (TILE_SIZE / 2) #define COORD(x) ( (x) * TILE_SIZE + BORDER ) #define FROMCOORD(x) ( ((x) - BORDER + TILE_SIZE) / TILE_SIZE - 1 ) #define ANIM_TIME 0.25F #define FLASH_FRAME 0.07F /* * Possible ways to decide which lights are toggled by each click. * Essentially, each of these describes a means of inventing a * matrix over GF(2). */ enum { CROSSES, RANDOM }; struct game_params { int w, h; int matrix_type; }; /* * This structure is shared between all the game_states describing * a particular game, so it's reference-counted. */ struct matrix { int refcount; unsigned char *matrix; /* array of (w*h) by (w*h) */ }; struct game_state { int w, h; int moves, completed, cheated, hints_active; unsigned char *grid; /* array of w*h */ struct matrix *matrix; }; static game_params *default_params(void) { game_params *ret = snew(game_params); ret->w = ret->h = 5; ret->matrix_type = CROSSES; return ret; } static const struct game_params flip_presets[] = { {3, 3, CROSSES}, {4, 4, CROSSES}, {5, 5, CROSSES}, {3, 3, RANDOM}, {4, 4, RANDOM}, {5, 5, RANDOM}, }; static int game_fetch_preset(int i, char **name, game_params **params) { game_params *ret; char str[80]; if (i < 0 || i >= lenof(flip_presets)) return FALSE; ret = snew(game_params); *ret = flip_presets[i]; sprintf(str, "%dx%d %s", ret->w, ret->h, ret->matrix_type == CROSSES ? "Crosses" : "Random"); *name = dupstr(str); *params = ret; return TRUE; } static void free_params(game_params *params) { sfree(params); } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } static void decode_params(game_params *ret, char const *string) { ret->w = ret->h = atoi(string); while (*string && isdigit((unsigned char)*string)) string++; if (*string == 'x') { string++; ret->h = atoi(string); while (*string && isdigit((unsigned char)*string)) string++; } if (*string == 'r') { string++; ret->matrix_type = RANDOM; } else if (*string == 'c') { string++; ret->matrix_type = CROSSES; } } static char *encode_params(const game_params *params, int full) { char data[256]; sprintf(data, "%dx%d%s", params->w, params->h, !full ? "" : params->matrix_type == CROSSES ? "c" : "r"); return dupstr(data); } static config_item *game_configure(const game_params *params) { config_item *ret = snewn(4, config_item); char buf[80]; ret[0].name = "Width"; ret[0].type = C_STRING; sprintf(buf, "%d", params->w); ret[0].sval = dupstr(buf); ret[0].ival = 0; ret[1].name = "Height"; ret[1].type = C_STRING; sprintf(buf, "%d", params->h); ret[1].sval = dupstr(buf); ret[1].ival = 0; ret[2].name = "Shape type"; ret[2].type = C_CHOICES; ret[2].sval = ":Crosses:Random"; ret[2].ival = params->matrix_type; ret[3].name = NULL; ret[3].type = C_END; ret[3].sval = NULL; ret[3].ival = 0; return ret; } static game_params *custom_params(const config_item *cfg) { game_params *ret = snew(game_params); ret->w = atoi(cfg[0].sval); ret->h = atoi(cfg[1].sval); ret->matrix_type = cfg[2].ival; return ret; } static char *validate_params(const game_params *params, int full) { if (params->w <= 0 || params->h <= 0) return "Width and height must both be greater than zero"; return NULL; } static char *encode_bitmap(unsigned char *bmp, int len) { int slen = (len + 3) / 4; char *ret; int i; ret = snewn(slen + 1, char); for (i = 0; i < slen; i++) { int j, v; v = 0; for (j = 0; j < 4; j++) if (i*4+j < len && bmp[i*4+j]) v |= 8 >> j; ret[i] = "0123456789abcdef"[v]; } ret[slen] = '\0'; return ret; } static void decode_bitmap(unsigned char *bmp, int len, const char *hex) { int slen = (len + 3) / 4; int i; for (i = 0; i < slen; i++) { int j, v, c = hex[i]; if (c >= '0' && c <= '9') v = c - '0'; else if (c >= 'A' && c <= 'F') v = c - 'A' + 10; else if (c >= 'a' && c <= 'f') v = c - 'a' + 10; else v = 0; /* shouldn't happen */ for (j = 0; j < 4; j++) { if (i*4+j < len) { if (v & (8 >> j)) bmp[i*4+j] = 1; else bmp[i*4+j] = 0; } } } } /* * Structure used during random matrix generation, and a compare * function to permit storage in a tree234. */ struct sq { int cx, cy; /* coords of click square */ int x, y; /* coords of output square */ /* * Number of click squares which currently affect this output * square. */ int coverage; /* * Number of output squares currently affected by this click * square. */ int ominosize; }; #define SORT(field) do { \ if (a->field < b->field) \ return -1; \ else if (a->field > b->field) \ return +1; \ } while (0) /* * Compare function for choosing the next square to add. We must * sort by coverage, then by omino size, then everything else. */ static int sqcmp_pick(void *av, void *bv) { struct sq *a = (struct sq *)av; struct sq *b = (struct sq *)bv; SORT(coverage); SORT(ominosize); SORT(cy); SORT(cx); SORT(y); SORT(x); return 0; } /* * Compare function for adjusting the coverage figures after a * change. We sort first by coverage and output square, then by * everything else. */ static int sqcmp_cov(void *av, void *bv) { struct sq *a = (struct sq *)av; struct sq *b = (struct sq *)bv; SORT(coverage); SORT(y); SORT(x); SORT(ominosize); SORT(cy); SORT(cx); return 0; } /* * Compare function for adjusting the omino sizes after a change. * We sort first by omino size and input square, then by everything * else. */ static int sqcmp_osize(void *av, void *bv) { struct sq *a = (struct sq *)av; struct sq *b = (struct sq *)bv; SORT(ominosize); SORT(cy); SORT(cx); SORT(coverage); SORT(y); SORT(x); return 0; } static void addsq(tree234 *t, int w, int h, int cx, int cy, int x, int y, unsigned char *matrix) { int wh = w * h; struct sq *sq; int i; if (x < 0 || x >= w || y < 0 || y >= h) return; if (abs(x-cx) > 1 || abs(y-cy) > 1) return; if (matrix[(cy*w+cx) * wh + y*w+x]) return; sq = snew(struct sq); sq->cx = cx; sq->cy = cy; sq->x = x; sq->y = y; sq->coverage = sq->ominosize = 0; for (i = 0; i < wh; i++) { if (matrix[i * wh + y*w+x]) sq->coverage++; if (matrix[(cy*w+cx) * wh + i]) sq->ominosize++; } if (add234(t, sq) != sq) sfree(sq); /* already there */ } static void addneighbours(tree234 *t, int w, int h, int cx, int cy, int x, int y, unsigned char *matrix) { addsq(t, w, h, cx, cy, x-1, y, matrix); addsq(t, w, h, cx, cy, x+1, y, matrix); addsq(t, w, h, cx, cy, x, y-1, matrix); addsq(t, w, h, cx, cy, x, y+1, matrix); } static char *new_game_desc(const game_params *params, random_state *rs, char **aux, int interactive) { int w = params->w, h = params->h, wh = w * h; int i, j; unsigned char *matrix, *grid; char *mbmp, *gbmp, *ret; matrix = snewn(wh * wh, unsigned char); grid = snewn(wh, unsigned char); /* * First set up the matrix. */ switch (params->matrix_type) { case CROSSES: for (i = 0; i < wh; i++) { int ix = i % w, iy = i / w; for (j = 0; j < wh; j++) { int jx = j % w, jy = j / w; if (abs(jx - ix) + abs(jy - iy) <= 1) matrix[i*wh+j] = 1; else matrix[i*wh+j] = 0; } } break; case RANDOM: while (1) { tree234 *pick, *cov, *osize; int limit; pick = newtree234(sqcmp_pick); cov = newtree234(sqcmp_cov); osize = newtree234(sqcmp_osize); memset(matrix, 0, wh * wh); for (i = 0; i < wh; i++) { matrix[i*wh+i] = 1; } for (i = 0; i < wh; i++) { int ix = i % w, iy = i / w; addneighbours(pick, w, h, ix, iy, ix, iy, matrix); addneighbours(cov, w, h, ix, iy, ix, iy, matrix); addneighbours(osize, w, h, ix, iy, ix, iy, matrix); } /* * Repeatedly choose a square to add to the matrix, * until we have enough. I'll arbitrarily choose our * limit to be the same as the total number of set bits * in the crosses matrix. */ limit = 4*wh - 2*(w+h); /* centre squares already present */ while (limit-- > 0) { struct sq *sq, *sq2, sqlocal; int k; /* * Find the lowest element in the pick tree. */ sq = index234(pick, 0); /* * Find the highest element with the same coverage * and omino size, by setting all other elements to * lots. */ sqlocal = *sq; sqlocal.cx = sqlocal.cy = sqlocal.x = sqlocal.y = wh; sq = findrelpos234(pick, &sqlocal, NULL, REL234_LT, &k); assert(sq != 0); /* * Pick at random from all elements up to k of the * pick tree. */ k = random_upto(rs, k+1); sq = delpos234(pick, k); del234(cov, sq); del234(osize, sq); /* * Add this square to the matrix. */ matrix[(sq->cy * w + sq->cx) * wh + (sq->y * w + sq->x)] = 1; /* * Correct the matrix coverage field of any sq * which points at this output square. */ sqlocal = *sq; sqlocal.cx = sqlocal.cy = sqlocal.ominosize = -1; while ((sq2 = findrel234(cov, &sqlocal, NULL, REL234_GT)) != NULL && sq2->coverage == sq->coverage && sq2->x == sq->x && sq2->y == sq->y) { del234(pick, sq2); del234(cov, sq2); del234(osize, sq2); sq2->coverage++; add234(pick, sq2); add234(cov, sq2); add234(osize, sq2); } /* * Correct the omino size field of any sq which * points at this input square. */ sqlocal = *sq; sqlocal.x = sqlocal.y = sqlocal.coverage = -1; while ((sq2 = findrel234(osize, &sqlocal, NULL, REL234_GT)) != NULL && sq2->ominosize == sq->ominosize && sq2->cx == sq->cx && sq2->cy == sq->cy) { del234(pick, sq2); del234(cov, sq2); del234(osize, sq2); sq2->ominosize++; add234(pick, sq2); add234(cov, sq2); add234(osize, sq2); } /* * The sq we actually picked out of the tree is * finished with; but its neighbours now need to * appear. */ addneighbours(pick, w,h, sq->cx,sq->cy, sq->x,sq->y, matrix); addneighbours(cov, w,h, sq->cx,sq->cy, sq->x,sq->y, matrix); addneighbours(osize, w,h, sq->cx,sq->cy, sq->x,sq->y, matrix); sfree(sq); } /* * Free all remaining sq structures. */ { struct sq *sq; while ((sq = delpos234(pick, 0)) != NULL) sfree(sq); } freetree234(pick); freetree234(cov); freetree234(osize); /* * Finally, check to see if any two matrix rows are * exactly identical. If so, this is not an acceptable * matrix, and we give up and go round again. * * I haven't been immediately able to think of a * plausible means of algorithmically avoiding this * situation (by, say, making a small perturbation to * an offending matrix), so for the moment I'm just * going to deal with it by throwing the whole thing * away. I suspect this will lead to scalability * problems (since most of the things happening in * these matrices are local, the chance of _some_ * neighbourhood having two identical regions will * increase with the grid area), but so far this puzzle * seems to be really hard at large sizes so I'm not * massively worried yet. Anyone needs this done * better, they're welcome to submit a patch. */ for (i = 0; i < wh; i++) { for (j = 0; j < wh; j++) if (i != j && !memcmp(matrix + i * wh, matrix + j * wh, wh)) break; if (j < wh) break; } if (i == wh) break; /* no matches found */ } break; } /* * Now invent a random initial set of lights. * * At first glance it looks as if it might be quite difficult * to choose equiprobably from all soluble light sets. After * all, soluble light sets are those in the image space of the * transformation matrix; so first we'd have to identify that * space and its dimension, then pick a random coordinate for * each basis vector and recombine. Lot of fiddly matrix * algebra there. * * However, vector spaces are nicely orthogonal and relieve us * of all that difficulty. For every point in the image space, * there are precisely as many points in the input space that * map to it as there are elements in the kernel of the * transformation matrix (because adding any kernel element to * the input does not change the output, and because any two * inputs mapping to the same output must differ by an element * of the kernel because that's what the kernel _is_); and * these cosets are all disjoint (obviously, since no input * point can map to more than one output point) and cover the * whole space (equally obviously, because no input point can * map to fewer than one output point!). * * So the input space contains the same number of points for * each point in the output space; thus, we can simply choose * equiprobably from elements of the _input_ space, and filter * the result through the transformation matrix in the obvious * way, and we thereby guarantee to choose equiprobably from * all the output points. Phew! */ while (1) { memset(grid, 0, wh); for (i = 0; i < wh; i++) { int v = random_upto(rs, 2); if (v) { for (j = 0; j < wh; j++) grid[j] ^= matrix[i*wh+j]; } } /* * Ensure we don't have the starting state already! */ for (i = 0; i < wh; i++) if (grid[i]) break; if (i < wh) break; } /* * Now encode the matrix and the starting grid as a game * description. We'll do this by concatenating two great big * hex bitmaps. */ mbmp = encode_bitmap(matrix, wh*wh); gbmp = encode_bitmap(grid, wh); ret = snewn(strlen(mbmp) + strlen(gbmp) + 2, char); sprintf(ret, "%s,%s", mbmp, gbmp); sfree(mbmp); sfree(gbmp); sfree(matrix); sfree(grid); return ret; } static char *validate_desc(const game_params *params, const char *desc) { int w = params->w, h = params->h, wh = w * h; int mlen = (wh*wh+3)/4, glen = (wh+3)/4; if (strspn(desc, "0123456789abcdefABCDEF") != mlen) return "Matrix description is wrong length"; if (desc[mlen] != ',') return "Expected comma after matrix description"; if (strspn(desc+mlen+1, "0123456789abcdefABCDEF") != glen) return "Grid description is wrong length"; if (desc[mlen+1+glen]) return "Unexpected data after grid description"; return NULL; } static game_state *new_game(midend *me, const game_params *params, const char *desc) { int w = params->w, h = params->h, wh = w * h; int mlen = (wh*wh+3)/4; game_state *state = snew(game_state); state->w = w; state->h = h; state->completed = FALSE; state->cheated = FALSE; state->hints_active = FALSE; state->moves = 0; state->matrix = snew(struct matrix); state->matrix->refcount = 1; state->matrix->matrix = snewn(wh*wh, unsigned char); decode_bitmap(state->matrix->matrix, wh*wh, desc); state->grid = snewn(wh, unsigned char); decode_bitmap(state->grid, wh, desc + mlen + 1); return state; } static game_state *dup_game(const game_state *state) { game_state *ret = snew(game_state); ret->w = state->w; ret->h = state->h; ret->completed = state->completed; ret->cheated = state->cheated; ret->hints_active = state->hints_active; ret->moves = state->moves; ret->matrix = state->matrix; state->matrix->refcount++; ret->grid = snewn(ret->w * ret->h, unsigned char); memcpy(ret->grid, state->grid, ret->w * ret->h); return ret; } static void free_game(game_state *state) { sfree(state->grid); if (--state->matrix->refcount <= 0) { sfree(state->matrix->matrix); sfree(state->matrix); } sfree(state); } static void rowxor(unsigned char *row1, unsigned char *row2, int len) { int i; for (i = 0; i < len; i++) row1[i] ^= row2[i]; } static char *solve_game(const game_state *state, const game_state *currstate, const char *aux, char **error) { int w = state->w, h = state->h, wh = w * h; unsigned char *equations, *solution, *shortest; int *und, nund; int rowsdone, colsdone; int i, j, k, len, bestlen; char *ret; /* * Set up a list of simultaneous equations. Each one is of * length (wh+1) and has wh coefficients followed by a value. */ equations = snewn((wh + 1) * wh, unsigned char); for (i = 0; i < wh; i++) { for (j = 0; j < wh; j++) equations[i * (wh+1) + j] = currstate->matrix->matrix[j*wh+i]; equations[i * (wh+1) + wh] = currstate->grid[i] & 1; } /* * Perform Gaussian elimination over GF(2). */ rowsdone = colsdone = 0; nund = 0; und = snewn(wh, int); do { /* * Find the leftmost column which has a 1 in it somewhere * outside the first `rowsdone' rows. */ j = -1; for (i = colsdone; i < wh; i++) { for (j = rowsdone; j < wh; j++) if (equations[j * (wh+1) + i]) break; if (j < wh) break; /* found one */ /* * This is a column which will not have an equation * controlling it. Mark it as undetermined. */ und[nund++] = i; } /* * If there wasn't one, then we've finished: all remaining * equations are of the form 0 = constant. Check to see if * any of them wants 0 to be equal to 1; this is the * condition which indicates an insoluble problem * (therefore _hopefully_ one typed in by a user!). */ if (i == wh) { for (j = rowsdone; j < wh; j++) if (equations[j * (wh+1) + wh]) { *error = "No solution exists for this position"; sfree(equations); sfree(und); return NULL; } break; } /* * We've found a 1. It's in column i, and the topmost 1 in * that column is in row j. Do a row-XOR to move it up to * the topmost row if it isn't already there. */ assert(j != -1); if (j > rowsdone) rowxor(equations + rowsdone*(wh+1), equations + j*(wh+1), wh+1); /* * Do row-XORs to eliminate that 1 from all rows below the * topmost row. */ for (j = rowsdone + 1; j < wh; j++) if (equations[j*(wh+1) + i]) rowxor(equations + j*(wh+1), equations + rowsdone*(wh+1), wh+1); /* * Mark this row and column as done. */ rowsdone++; colsdone = i+1; /* * If we've done all the rows, terminate. */ } while (rowsdone < wh); /* * If we reach here, we have the ability to produce a solution. * So we go through _all_ possible solutions (each * corresponding to a set of arbitrary choices of those * components not directly determined by an equation), and pick * one requiring the smallest number of flips. */ solution = snewn(wh, unsigned char); shortest = snewn(wh, unsigned char); memset(solution, 0, wh); bestlen = wh + 1; while (1) { /* * Find a solution based on the current values of the * undetermined variables. */ for (j = rowsdone; j-- ;) { int v; /* * Find the leftmost set bit in this equation. */ for (i = 0; i < wh; i++) if (equations[j * (wh+1) + i]) break; assert(i < wh); /* there must have been one! */ /* * Compute this variable using the rest. */ v = equations[j * (wh+1) + wh]; for (k = i+1; k < wh; k++) if (equations[j * (wh+1) + k]) v ^= solution[k]; solution[i] = v; } /* * Compare this solution to the current best one, and * replace the best one if this one is shorter. */ len = 0; for (i = 0; i < wh; i++) if (solution[i]) len++; if (len < bestlen) { bestlen = len; memcpy(shortest, solution, wh); } /* * Now increment the binary number given by the * undetermined variables: turn all 1s into 0s until we see * a 0, at which point we turn it into a 1. */ for (i = 0; i < nund; i++) { solution[und[i]] = !solution[und[i]]; if (solution[und[i]]) break; } /* * If we didn't find a 0 at any point, we have wrapped * round and are back at the start, i.e. we have enumerated * all solutions. */ if (i == nund) break; } /* * We have a solution. Produce a move string encoding the * solution. */ ret = snewn(wh + 2, char); ret[0] = 'S'; for (i = 0; i < wh; i++) ret[i+1] = shortest[i] ? '1' : '0'; ret[wh+1] = '\0'; sfree(shortest); sfree(solution); sfree(equations); sfree(und); return ret; } static int game_can_format_as_text_now(const game_params *params) { return TRUE; } #define RIGHT 1 #define DOWN gw static char *game_text_format(const game_state *state) { int w = state->w, h = state->h, wh = w*h, r, c, dx, dy; int cw = 4, ch = 4, gw = w * cw + 2, gh = h * ch + 1, len = gw * gh; char *board = snewn(len + 1, char); memset(board, ' ', len - 1); for (r = 0; r < h; ++r) { for (c = 0; c < w; ++c) { int cell = r*ch*gw + c*cw, center = cell+(ch/2)*DOWN + cw/2*RIGHT; char flip = (state->grid[r*w + c] & 1) ? '#' : '.'; for (dy = -1 + (r == 0); dy <= 1 - (r == h - 1); ++dy) for (dx = -1 + (c == 0); dx <= 1 - (c == w - 1); ++dx) if (state->matrix->matrix[(r*w+c)*wh + ((r+dy)*w + c+dx)]) board[center + dy*DOWN + dx*RIGHT] = flip; board[cell] = '+'; for (dx = 1; dx < cw; ++dx) board[cell+dx*RIGHT] = '-'; for (dy = 1; dy < ch; ++dy) board[cell+dy*DOWN] = '|'; } board[r*ch*gw + gw - 2] = '+'; board[r*ch*gw + gw - 1] = '\n'; for (dy = 1; dy < ch; ++dy) { board[r*ch*gw + gw - 2 + dy*DOWN] = '|'; board[r*ch*gw + gw - 1 + dy*DOWN] = '\n'; } } memset(board + len - gw, '-', gw - 2); for (c = 0; c <= w; ++c) board[len - gw + cw*c] = '+'; board[len - 1] = '\n'; board[len] = '\0'; return board; } #undef RIGHT #undef DOWN struct game_ui { int cx, cy, cdraw; }; static game_ui *new_ui(const game_state *state) { game_ui *ui = snew(game_ui); ui->cx = ui->cy = ui->cdraw = 0; return ui; } static void free_ui(game_ui *ui) { sfree(ui); } static char *encode_ui(const game_ui *ui) { return NULL; } static void decode_ui(game_ui *ui, const char *encoding) { } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { } struct game_drawstate { int w, h, started; unsigned char *tiles; int tilesize; }; static char *interpret_move(const game_state *state, game_ui *ui, const game_drawstate *ds, int x, int y, int button) { int w = state->w, h = state->h, wh = w * h; char buf[80], *nullret = NULL; if (button == LEFT_BUTTON || IS_CURSOR_SELECT(button)) { int tx, ty; if (button == LEFT_BUTTON) { tx = FROMCOORD(x), ty = FROMCOORD(y); ui->cdraw = 0; } else { tx = ui->cx; ty = ui->cy; ui->cdraw = 1; } nullret = ""; if (tx >= 0 && tx < w && ty >= 0 && ty < h) { /* * It's just possible that a manually entered game ID * will have at least one square do nothing whatsoever. * If so, we avoid encoding a move at all. */ int i = ty*w+tx, j, makemove = FALSE; for (j = 0; j < wh; j++) { if (state->matrix->matrix[i*wh+j]) makemove = TRUE; } if (makemove) { sprintf(buf, "M%d,%d", tx, ty); return dupstr(buf); } else { return NULL; } } } else if (IS_CURSOR_MOVE(button)) { int dx = 0, dy = 0; switch (button) { case CURSOR_UP: dy = -1; break; case CURSOR_DOWN: dy = 1; break; case CURSOR_RIGHT: dx = 1; break; case CURSOR_LEFT: dx = -1; break; default: assert(!"shouldn't get here"); } ui->cx += dx; ui->cy += dy; ui->cx = min(max(ui->cx, 0), state->w - 1); ui->cy = min(max(ui->cy, 0), state->h - 1); ui->cdraw = 1; nullret = ""; } return nullret; } static game_state *execute_move(const game_state *from, const char *move) { int w = from->w, h = from->h, wh = w * h; game_state *ret; int x, y; if (move[0] == 'S' && strlen(move) == wh+1) { int i; ret = dup_game(from); ret->hints_active = TRUE; ret->cheated = TRUE; for (i = 0; i < wh; i++) { ret->grid[i] &= ~2; if (move[i+1] != '0') ret->grid[i] |= 2; } return ret; } else if (move[0] == 'M' && sscanf(move+1, "%d,%d", &x, &y) == 2 && x >= 0 && x < w && y >= 0 && y < h) { int i, j, done; ret = dup_game(from); if (!ret->completed) ret->moves++; i = y * w + x; done = TRUE; for (j = 0; j < wh; j++) { ret->grid[j] ^= ret->matrix->matrix[i*wh+j]; if (ret->grid[j] & 1) done = FALSE; } ret->grid[i] ^= 2; /* toggle hint */ if (done) { ret->completed = TRUE; ret->hints_active = FALSE; } return ret; } else return NULL; /* can't parse move string */ } /* ---------------------------------------------------------------------- * Drawing routines. */ static void game_compute_size(const game_params *params, int tilesize, int *x, int *y) { /* Ick: fake up `ds->tilesize' for macro expansion purposes */ struct { int tilesize; } ads, *ds = &ads; ads.tilesize = tilesize; *x = TILE_SIZE * params->w + 2 * BORDER; *y = TILE_SIZE * params->h + 2 * BORDER; } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { ds->tilesize = tilesize; } static float *game_colours(frontend *fe, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float); frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]); ret[COL_WRONG * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] / 3; ret[COL_WRONG * 3 + 1] = ret[COL_BACKGROUND * 3 + 1] / 3; ret[COL_WRONG * 3 + 2] = ret[COL_BACKGROUND * 3 + 2] / 3; ret[COL_RIGHT * 3 + 0] = 1.0F; ret[COL_RIGHT * 3 + 1] = 1.0F; ret[COL_RIGHT * 3 + 2] = 1.0F; ret[COL_GRID * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] / 1.5F; ret[COL_GRID * 3 + 1] = ret[COL_BACKGROUND * 3 + 1] / 1.5F; ret[COL_GRID * 3 + 2] = ret[COL_BACKGROUND * 3 + 2] / 1.5F; ret[COL_DIAG * 3 + 0] = ret[COL_GRID * 3 + 0]; ret[COL_DIAG * 3 + 1] = ret[COL_GRID * 3 + 1]; ret[COL_DIAG * 3 + 2] = ret[COL_GRID * 3 + 2]; ret[COL_HINT * 3 + 0] = 1.0F; ret[COL_HINT * 3 + 1] = 0.0F; ret[COL_HINT * 3 + 2] = 0.0F; ret[COL_CURSOR * 3 + 0] = 0.8F; ret[COL_CURSOR * 3 + 1] = 0.0F; ret[COL_CURSOR * 3 + 2] = 0.0F; *ncolours = NCOLOURS; return ret; } static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { struct game_drawstate *ds = snew(struct game_drawstate); int i; ds->started = FALSE; ds->w = state->w; ds->h = state->h; ds->tiles = snewn(ds->w*ds->h, unsigned char); ds->tilesize = 0; /* haven't decided yet */ for (i = 0; i < ds->w*ds->h; i++) ds->tiles[i] = -1; return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { sfree(ds->tiles); sfree(ds); } static void draw_tile(drawing *dr, game_drawstate *ds, const game_state *state, int x, int y, int tile, int anim, float animtime) { int w = ds->w, h = ds->h, wh = w * h; int bx = x * TILE_SIZE + BORDER, by = y * TILE_SIZE + BORDER; int i, j, dcol = (tile & 4) ? COL_CURSOR : COL_DIAG; clip(dr, bx+1, by+1, TILE_SIZE-1, TILE_SIZE-1); draw_rect(dr, bx+1, by+1, TILE_SIZE-1, TILE_SIZE-1, anim ? COL_BACKGROUND : tile & 1 ? COL_WRONG : COL_RIGHT); if (anim) { /* * Draw a polygon indicating that the square is diagonally * flipping over. */ int coords[8], colour; coords[0] = bx + TILE_SIZE; coords[1] = by; coords[2] = bx + (int)((float)TILE_SIZE * animtime); coords[3] = by + (int)((float)TILE_SIZE * animtime); coords[4] = bx; coords[5] = by + TILE_SIZE; coords[6] = bx + TILE_SIZE - (int)((float)TILE_SIZE * animtime); coords[7] = by + TILE_SIZE - (int)((float)TILE_SIZE * animtime); colour = (tile & 1 ? COL_WRONG : COL_RIGHT); if (animtime < 0.5) colour = COL_WRONG + COL_RIGHT - colour; draw_polygon(dr, coords, 4, colour, COL_GRID); } /* * Draw a little diagram in the tile which indicates which * surrounding tiles flip when this one is clicked. */ for (i = 0; i < h; i++) for (j = 0; j < w; j++) if (state->matrix->matrix[(y*w+x)*wh + i*w+j]) { int ox = j - x, oy = i - y; int td = TILE_SIZE / 16; int cx = (bx + TILE_SIZE/2) + (2 * ox - 1) * td; int cy = (by + TILE_SIZE/2) + (2 * oy - 1) * td; if (ox == 0 && oy == 0) draw_rect(dr, cx, cy, 2*td+1, 2*td+1, dcol); else { draw_line(dr, cx, cy, cx+2*td, cy, dcol); draw_line(dr, cx, cy+2*td, cx+2*td, cy+2*td, dcol); draw_line(dr, cx, cy, cx, cy+2*td, dcol); draw_line(dr, cx+2*td, cy, cx+2*td, cy+2*td, dcol); } } /* * Draw a hint rectangle if required. */ if (tile & 2) { int x1 = bx + TILE_SIZE / 20, x2 = bx + TILE_SIZE - TILE_SIZE / 20; int y1 = by + TILE_SIZE / 20, y2 = by + TILE_SIZE - TILE_SIZE / 20; int i = 3; while (i--) { draw_line(dr, x1, y1, x2, y1, COL_HINT); draw_line(dr, x1, y2, x2, y2, COL_HINT); draw_line(dr, x1, y1, x1, y2, COL_HINT); draw_line(dr, x2, y1, x2, y2, COL_HINT); x1++, y1++, x2--, y2--; } } unclip(dr); draw_update(dr, bx+1, by+1, TILE_SIZE-1, TILE_SIZE-1); } static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float animtime, float flashtime) { int w = ds->w, h = ds->h, wh = w * h; int i, flashframe; if (!ds->started) { draw_rect(dr, 0, 0, TILE_SIZE * w + 2 * BORDER, TILE_SIZE * h + 2 * BORDER, COL_BACKGROUND); /* * Draw the grid lines. */ for (i = 0; i <= w; i++) draw_line(dr, i * TILE_SIZE + BORDER, BORDER, i * TILE_SIZE + BORDER, h * TILE_SIZE + BORDER, COL_GRID); for (i = 0; i <= h; i++) draw_line(dr, BORDER, i * TILE_SIZE + BORDER, w * TILE_SIZE + BORDER, i * TILE_SIZE + BORDER, COL_GRID); draw_update(dr, 0, 0, TILE_SIZE * w + 2 * BORDER, TILE_SIZE * h + 2 * BORDER); ds->started = TRUE; } if (flashtime) flashframe = (int)(flashtime / FLASH_FRAME); else flashframe = -1; animtime /= ANIM_TIME; /* scale it so it goes from 0 to 1 */ for (i = 0; i < wh; i++) { int x = i % w, y = i / w; int fx, fy, fd; int v = state->grid[i]; int vv; if (flashframe >= 0) { fx = (w+1)/2 - min(x+1, w-x); fy = (h+1)/2 - min(y+1, h-y); fd = max(fx, fy); if (fd == flashframe) v |= 1; else if (fd == flashframe - 1) v &= ~1; } if (!state->hints_active) v &= ~2; if (ui->cdraw && ui->cx == x && ui->cy == y) v |= 4; if (oldstate && ((state->grid[i] ^ oldstate->grid[i]) &~ 2)) vv = 255; /* means `animated' */ else vv = v; if (ds->tiles[i] == 255 || vv == 255 || ds->tiles[i] != vv) { draw_tile(dr, ds, state, x, y, v, vv == 255, animtime); ds->tiles[i] = vv; } } { char buf[256]; sprintf(buf, "%sMoves: %d", (state->completed ? (state->cheated ? "Auto-solved. " : "COMPLETED! ") : (state->cheated ? "Auto-solver used. " : "")), state->moves); status_bar(dr, buf); } } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return ANIM_TIME; } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { if (!oldstate->completed && newstate->completed) return FLASH_FRAME * (max((newstate->w+1)/2, (newstate->h+1)/2)+1); return 0.0F; } static int game_status(const game_state *state) { return state->completed ? +1 : 0; } static int game_timing_state(const game_state *state, game_ui *ui) { return TRUE; } static void game_print_size(const game_params *params, float *x, float *y) { } static void game_print(drawing *dr, const game_state *state, int tilesize) { } #ifdef COMBINED #define thegame flip #endif const struct game thegame = { "Flip", "games.flip", "flip", default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, TRUE, solve_game, TRUE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, PREFERRED_TILE_SIZE, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, FALSE, FALSE, game_print_size, game_print, TRUE, /* wants_statusbar */ FALSE, game_timing_state, 0, /* flags */ }; puzzles-20170606.272beef/findloop.c0000644000175000017500000004706313115373615015661 0ustar simonsimon/* * Routine for finding loops in graphs, reusable across multiple * puzzles. * * The strategy is Tarjan's bridge-finding algorithm, which is * designed to list all edges whose removal would disconnect a * previously connected component of the graph. We're interested in * exactly the reverse - edges that are part of a loop in the graph * are precisely those which _wouldn't_ disconnect anything if removed * (individually) - but of course flipping the sense of the output is * easy. */ #include "puzzles.h" struct findloopstate { int parent, child, sibling, visited; int index, minindex, maxindex; int minreachable, maxreachable; int bridge; }; struct findloopstate *findloop_new_state(int nvertices) { /* * Allocate a findloopstate structure for each vertex, and one * extra one at the end which will be the overall root of a * 'super-tree', which links the whole graph together to make it * as easy as possible to iterate over all the connected * components. */ return snewn(nvertices + 1, struct findloopstate); } void findloop_free_state(struct findloopstate *state) { sfree(state); } int findloop_is_loop_edge(struct findloopstate *pv, int u, int v) { /* * Since the algorithm is intended for finding bridges, and a * bridge must be part of any spanning tree, it follows that there * is at most one bridge per vertex. * * Furthermore, by finding a _rooted_ spanning tree (so that each * bridge is a parent->child link), you can find an injection from * bridges to vertices (namely, map each bridge to the vertex at * its child end). * * So if the u-v edge is a bridge, then either v was u's parent * when the algorithm ran and we set pv[u].bridge = v, or vice * versa. */ return !(pv[u].bridge == v || pv[v].bridge == u); } int findloop_run(struct findloopstate *pv, int nvertices, neighbour_fn_t neighbour, void *ctx) { int u, v, w, root, index; int nbridges, nedges; root = nvertices; /* * First pass: organise the graph into a rooted spanning forest. * That is, a tree structure with a clear up/down orientation - * every node has exactly one parent (which may be 'root') and * zero or more children, and every parent-child link corresponds * to a graph edge. * * (A side effect of this is to find all the connected components, * which of course we could do less confusingly with a dsf - but * then we'd have to do that *and* build the tree, so it's less * effort to do it all at once.) */ for (v = 0; v <= nvertices; v++) { pv[v].parent = root; pv[v].child = -2; pv[v].sibling = -1; pv[v].visited = FALSE; } pv[root].child = -1; nedges = 0; debug(("------------- new find_loops, nvertices=%d\n", nvertices)); for (v = 0; v < nvertices; v++) { if (pv[v].parent == root) { /* * Found a new connected component. Enumerate and treeify * it. */ pv[v].sibling = pv[root].child; pv[root].child = v; debug(("%d is new child of root\n", v)); u = v; while (1) { if (!pv[u].visited) { pv[u].visited = TRUE; /* * Enumerate the neighbours of u, and any that are * as yet not in the tree structure (indicated by * child==-2, and distinct from the 'visited' * flag) become children of u. */ debug((" component pass: processing %d\n", u)); for (w = neighbour(u, ctx); w >= 0; w = neighbour(-1, ctx)) { debug((" edge %d-%d\n", u, w)); if (pv[w].child == -2) { debug((" -> new child\n")); pv[w].child = -1; pv[w].sibling = pv[u].child; pv[w].parent = u; pv[u].child = w; } /* While we're here, count the edges in the whole * graph, so that we can easily check at the end * whether all of them are bridges, i.e. whether * no loop exists at all. */ if (w > u) /* count each edge only in one direction */ nedges++; } /* * Now descend in depth-first search. */ if (pv[u].child >= 0) { u = pv[u].child; debug((" descending to %d\n", u)); continue; } } if (u == v) { debug((" back at %d, done this component\n", u)); break; } else if (pv[u].sibling >= 0) { u = pv[u].sibling; debug((" sideways to %d\n", u)); } else { u = pv[u].parent; debug((" ascending to %d\n", u)); } } } } /* * Second pass: index all the vertices in such a way that every * subtree has a contiguous range of indices. (Easily enough done, * by iterating through the tree structure we just built and * numbering its elements as if they were those of a sorted list.) * * For each vertex, we compute the min and max index of the * subtree starting there. * * (We index the vertices in preorder, per Tarjan's original * description, so that each vertex's min subtree index is its own * index; but that doesn't actually matter; either way round would * do. The important thing is that we have a simple arithmetic * criterion that tells us whether a vertex is in a given subtree * or not.) */ debug(("--- begin indexing pass\n")); index = 0; for (v = 0; v < nvertices; v++) pv[v].visited = FALSE; pv[root].visited = TRUE; u = pv[root].child; while (1) { if (!pv[u].visited) { pv[u].visited = TRUE; /* * Index this node. */ pv[u].minindex = pv[u].index = index; debug((" vertex %d <- index %d\n", u, index)); index++; /* * Now descend in depth-first search. */ if (pv[u].child >= 0) { u = pv[u].child; debug((" descending to %d\n", u)); continue; } } if (u == root) { debug((" back at %d, done indexing\n", u)); break; } /* * As we re-ascend to here from its children (or find that we * had no children to descend to in the first place), fill in * its maxindex field. */ pv[u].maxindex = index-1; debug((" vertex %d <- maxindex %d\n", u, pv[u].maxindex)); if (pv[u].sibling >= 0) { u = pv[u].sibling; debug((" sideways to %d\n", u)); } else { u = pv[u].parent; debug((" ascending to %d\n", u)); } } /* * We're ready to generate output now, so initialise the output * fields. */ for (v = 0; v < nvertices; v++) pv[v].bridge = -1; /* * Final pass: determine the min and max index of the vertices * reachable from every subtree, not counting the link back to * each vertex's parent. Then our criterion is: given a vertex u, * defining a subtree consisting of u and all its descendants, we * compare the range of vertex indices _in_ that subtree (which is * just the minindex and maxindex of u) with the range of vertex * indices in the _neighbourhood_ of the subtree (computed in this * final pass, and not counting u's own edge to its parent), and * if the latter includes anything outside the former, then there * must be some path from u to outside its subtree which does not * go through the parent edge - i.e. the edge from u to its parent * is part of a loop. */ debug(("--- begin min-max pass\n")); nbridges = 0; for (v = 0; v < nvertices; v++) pv[v].visited = FALSE; u = pv[root].child; pv[root].visited = TRUE; while (1) { if (!pv[u].visited) { pv[u].visited = TRUE; /* * Look for vertices reachable directly from u, including * u itself. */ debug((" processing vertex %d\n", u)); pv[u].minreachable = pv[u].maxreachable = pv[u].minindex; for (w = neighbour(u, ctx); w >= 0; w = neighbour(-1, ctx)) { debug((" edge %d-%d\n", u, w)); if (w != pv[u].parent) { int i = pv[w].index; if (pv[u].minreachable > i) pv[u].minreachable = i; if (pv[u].maxreachable < i) pv[u].maxreachable = i; } } debug((" initial min=%d max=%d\n", pv[u].minreachable, pv[u].maxreachable)); /* * Now descend in depth-first search. */ if (pv[u].child >= 0) { u = pv[u].child; debug((" descending to %d\n", u)); continue; } } if (u == root) { debug((" back at %d, done min-maxing\n", u)); break; } /* * As we re-ascend to this vertex, go back through its * immediate children and do a post-update of its min/max. */ for (v = pv[u].child; v >= 0; v = pv[v].sibling) { if (pv[u].minreachable > pv[v].minreachable) pv[u].minreachable = pv[v].minreachable; if (pv[u].maxreachable < pv[v].maxreachable) pv[u].maxreachable = pv[v].maxreachable; } debug((" postorder update of %d: min=%d max=%d (indices %d-%d)\n", u, pv[u].minreachable, pv[u].maxreachable, pv[u].minindex, pv[u].maxindex)); /* * And now we know whether each to our own parent is a bridge. */ if ((v = pv[u].parent) != root) { if (pv[u].minreachable >= pv[u].minindex && pv[u].maxreachable <= pv[u].maxindex) { /* Yes, it's a bridge. */ pv[u].bridge = v; nbridges++; debug((" %d-%d is a bridge\n", v, u)); } else { debug((" %d-%d is not a bridge\n", v, u)); } } if (pv[u].sibling >= 0) { u = pv[u].sibling; debug((" sideways to %d\n", u)); } else { u = pv[u].parent; debug((" ascending to %d\n", u)); } } debug(("finished, nedges=%d nbridges=%d\n", nedges, nbridges)); /* * Done. */ return nbridges < nedges; } /* * Appendix: the long and painful history of loop detection in these puzzles * ========================================================================= * * For interest, I thought I'd write up the five loop-finding methods * I've gone through before getting to this algorithm. It's a case * study in all the ways you can solve this particular problem * wrongly, and also how much effort you can waste by not managing to * find the existing solution in the literature :-( * * Vertex dsf * ---------- * * Initially, in puzzles where you need to not have any loops in the * solution graph, I detected them by using a dsf to track connected * components of vertices. Iterate over each edge unifying the two * vertices it connects; but before that, check if the two vertices * are _already_ known to be connected. If so, then the new edge is * providing a second path between them, i.e. a loop exists. * * That's adequate for automated solvers, where you just need to know * _whether_ a loop exists, so as to rule out that move and do * something else. But during play, you want to do better than that: * you want to _point out_ the loops with error highlighting. * * Graph pruning * ------------- * * So my second attempt worked by iteratively pruning the graph. Find * a vertex with degree 1; remove that edge; repeat until you can't * find such a vertex any more. This procedure will remove *every* * edge of the graph if and only if there were no loops; so if there * are any edges remaining, highlight them. * * This successfully highlights loops, but not _only_ loops. If the * graph contains a 'dumb-bell' shaped subgraph consisting of two * loops connected by a path, then we'll end up highlighting the * connecting path as well as the loops. That's not what we wanted. * * Vertex dsf with ad-hoc loop tracing * ----------------------------------- * * So my third attempt was to go back to the dsf strategy, only this * time, when you detect that a particular edge connects two * already-connected vertices (and hence is part of a loop), you try * to trace round that loop to highlight it - before adding the new * edge, search for a path between its endpoints among the edges the * algorithm has already visited, and when you find one (which you * must), highlight the loop consisting of that path plus the new * edge. * * This solves the dumb-bell problem - we definitely now cannot * accidentally highlight any edge that is *not* part of a loop. But * it's far from clear that we'll highlight *every* edge that *is* * part of a loop - what if there were multiple paths between the two * vertices? It would be difficult to guarantee that we'd always catch * every single one. * * On the other hand, it is at least guaranteed that we'll highlight * _something_ if any loop exists, and in other error highlighting * situations (see in particular the Tents connected component * analysis) I've been known to consider that sufficient. So this * version hung around for quite a while, until I had a better idea. * * Face dsf * -------- * * Round about the time Loopy was being revamped to include non-square * grids, I had a much cuter idea, making use of the fact that the * graph is planar, and hence has a concept of faces. * * In Loopy, there are really two graphs: the 'grid', consisting of * all the edges that the player *might* fill in, and the solution * graph of the edges the player actually *has* filled in. The * algorithm is: set up a dsf on the *faces* of the grid. Iterate over * each edge of the grid which is _not_ marked by the player as an * edge of the solution graph, unifying the faces on either side of * that edge. This groups the faces into connected components. Now, * there is more than one connected component iff a loop exists, and * moreover, an edge of the solution graph is part of a loop iff the * faces on either side of it are in different connected components! * * This is the first algorithm I came up with that I was confident * would successfully highlight exactly the correct set of edges in * all cases. It's also conceptually elegant, and very easy to * implement and to be confident you've got it right (since it just * consists of two very simple loops over the edge set, one building * the dsf and one reading it off). I was very pleased with it. * * Doing the same thing in Slant is slightly more difficult because * the set of edges the user can fill in do not form a planar graph * (the two potential edges in each square cross in the middle). But * you can still apply the same principle by considering the 'faces' * to be diamond-shaped regions of space around each horizontal or * vertical grid line. Equivalently, pretend each edge added by the * player is really divided into two edges, each from a square-centre * to one of the square's corners, and now the grid graph is planar * again. * * However, it fell down when - much later - I tried to implement the * same algorithm in Net. * * Net doesn't *absolutely need* loop detection, because of its system * of highlighting squares connected to the source square: an argument * involving counting vertex degrees shows that if any loop exists, * then it must be counterbalanced by some disconnected square, so * there will be _some_ error highlight in any invalid grid even * without loop detection. However, in large complicated cases, it's * still nice to highlight the loop itself, so that once the player is * clued in to its existence by a disconnected square elsewhere, they * don't have to spend forever trying to find it. * * The new wrinkle in Net, compared to other loop-disallowing puzzles, * is that it can be played with wrapping walls, or - topologically * speaking - on a torus. And a torus has a property that algebraic * topologists would know of as a 'non-trivial H_1 homology group', * which essentially means that there can exist a loop on a torus * which *doesn't* separate the surface into two regions disconnected * from each other. * * In other words, using this algorithm in Net will do fine at finding * _small_ localised loops, but a large-scale loop that goes (say) off * the top of the grid, back on at the bottom, and meets up in the * middle again will not be detected. * * Footpath dsf * ------------ * * To solve this homology problem in Net, I hastily thought up another * dsf-based algorithm. * * This time, let's consider each edge of the graph to be a road, with * a separate pedestrian footpath down each side. We'll form a dsf on * those imaginary segments of footpath. * * At each vertex of the graph, we go round the edges leaving that * vertex, in order around the vertex. For each pair of edges adjacent * in this order, we unify their facing pair of footpaths (e.g. if * edge E appears anticlockwise of F, then we unify the anticlockwise * footpath of F with the clockwise one of E) . In particular, if a * vertex has degree 1, then the two footpaths on either side of its * single edge are unified. * * Then, an edge is part of a loop iff its two footpaths are not * reachable from one another. * * This algorithm is almost as simple to implement as the face dsf, * and it works on a wider class of graphs embedded in plane-like * surfaces; in particular, it fixes the torus bug in the face-dsf * approach. However, it still depends on the graph having _some_ sort * of embedding in a 2-manifold, because it relies on there being a * meaningful notion of 'order of edges around a vertex' in the first * place, so you couldn't use it on a wildly nonplanar graph like the * diamond lattice. Also, more subtly, it depends on the graph being * embedded in an _orientable_ surface - and that's a thing that might * much more plausibly change in future puzzles, because it's not at * all unlikely that at some point I might feel moved to implement a * puzzle that can be played on the surface of a Mobius strip or a * Klein bottle. And then even this algorithm won't work. * * Tarjan's bridge-finding algorithm * --------------------------------- * * And so, finally, we come to the algorithm above. This one is pure * graph theory: it doesn't depend on any concept of 'faces', or 'edge * ordering around a vertex', or any other trapping of a planar or * quasi-planar graph embedding. It should work on any graph * whatsoever, and reliably identify precisely the set of edges that * form part of some loop. So *hopefully* this long string of failures * has finally come to an end... */ puzzles-20170606.272beef/filling.c0000644000175000017500000017627513115373615015503 0ustar simonsimon/* -*- tab-width: 8; indent-tabs-mode: t -*- * filling.c: An implementation of the Nikoli game fillomino. * Copyright (C) 2007 Jonas Kölker. See LICENSE for the license. */ /* TODO: * * - use a typedef instead of int for numbers on the board * + replace int with something else (signed short?) * - the type should be signed (for -board[i] and -SENTINEL) * - the type should be somewhat big: board[i] = i * - Using shorts gives us 181x181 puzzles as upper bound. * * - in board generation, after having merged regions such that no * more merges are necessary, try splitting (big) regions. * + it seems that smaller regions make for better puzzles; see * for instance the 7x7 puzzle in this file (grep for 7x7:). * * - symmetric hints (solo-style) * + right now that means including _many_ hints, and the puzzles * won't look any nicer. Not worth it (at the moment). * * - make the solver do recursion/backtracking. * + This is for user-submitted puzzles, not for puzzle * generation (on the other hand, never say never). * * - prove that only w=h=2 needs a special case * * - solo-like pencil marks? * * - a user says that the difficulty is unevenly distributed. * + partition into levels? Will they be non-crap? * * - Allow square contents > 9? * + I could use letters for digits (solo does this), but * letters don't have numeric significance (normal people hate * base36), which is relevant here (much more than in solo). * + [click, 1, 0, enter] => [10 in clicked square]? * + How much information is needed to solve? Does one need to * know the algorithm by which the largest number is set? * * - eliminate puzzle instances with done chunks (1's in particular)? * + that's what the qsort call is all about. * + the 1's don't bother me that much. * + but this takes a LONG time (not always possible)? * - this may be affected by solver (lack of) quality. * - weed them out by construction instead of post-cons check * + but that interleaves make_board and new_game_desc: you * have to alternate between changing the board and * changing the hint set (instead of just creating the * board once, then changing the hint set once -> done). * * - use binary search when discovering the minimal sovable point * + profile to show a need (but when the solver gets slower...) * + 7x9 @ .011s, 9x13 @ .075s, 17x13 @ .661s (all avg with n=100) * + but the hints are independent, not linear, so... what? */ #include #include #include #include #include #include #include #include "puzzles.h" static unsigned char verbose; static void printv(char *fmt, ...) { #ifndef PALM if (verbose) { va_list va; va_start(va, fmt); vprintf(fmt, va); va_end(va); } #endif } /***************************************************************************** * GAME CONFIGURATION AND PARAMETERS * *****************************************************************************/ struct game_params { int w, h; }; struct shared_state { struct game_params params; int *clues; int refcnt; }; struct game_state { int *board; struct shared_state *shared; int completed, cheated; }; static const struct game_params filling_defaults[3] = { {9, 7}, {13, 9}, {17, 13} }; static game_params *default_params(void) { game_params *ret = snew(game_params); *ret = filling_defaults[1]; /* struct copy */ return ret; } static int game_fetch_preset(int i, char **name, game_params **params) { char buf[64]; if (i < 0 || i >= lenof(filling_defaults)) return FALSE; *params = snew(game_params); **params = filling_defaults[i]; /* struct copy */ sprintf(buf, "%dx%d", filling_defaults[i].w, filling_defaults[i].h); *name = dupstr(buf); return TRUE; } static void free_params(game_params *params) { sfree(params); } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* struct copy */ return ret; } static void decode_params(game_params *ret, char const *string) { ret->w = ret->h = atoi(string); while (*string && isdigit((unsigned char) *string)) ++string; if (*string == 'x') ret->h = atoi(++string); } static char *encode_params(const game_params *params, int full) { char buf[64]; sprintf(buf, "%dx%d", params->w, params->h); return dupstr(buf); } static config_item *game_configure(const game_params *params) { config_item *ret; char buf[64]; ret = snewn(3, config_item); ret[0].name = "Width"; ret[0].type = C_STRING; sprintf(buf, "%d", params->w); ret[0].sval = dupstr(buf); ret[0].ival = 0; ret[1].name = "Height"; ret[1].type = C_STRING; sprintf(buf, "%d", params->h); ret[1].sval = dupstr(buf); ret[1].ival = 0; ret[2].name = NULL; ret[2].type = C_END; ret[2].sval = NULL; ret[2].ival = 0; return ret; } static game_params *custom_params(const config_item *cfg) { game_params *ret = snew(game_params); ret->w = atoi(cfg[0].sval); ret->h = atoi(cfg[1].sval); return ret; } static char *validate_params(const game_params *params, int full) { if (params->w < 1) return "Width must be at least one"; if (params->h < 1) return "Height must be at least one"; return NULL; } /***************************************************************************** * STRINGIFICATION OF GAME STATE * *****************************************************************************/ #define EMPTY 0 /* Example of plaintext rendering: * +---+---+---+---+---+---+---+ * | 6 | | | 2 | | | 2 | * +---+---+---+---+---+---+---+ * | | 3 | | 6 | | 3 | | * +---+---+---+---+---+---+---+ * | 3 | | | | | | 1 | * +---+---+---+---+---+---+---+ * | | 2 | 3 | | 4 | 2 | | * +---+---+---+---+---+---+---+ * | 2 | | | | | | 3 | * +---+---+---+---+---+---+---+ * | | 5 | | 1 | | 4 | | * +---+---+---+---+---+---+---+ * | 4 | | | 3 | | | 3 | * +---+---+---+---+---+---+---+ * * This puzzle instance is taken from the nikoli website * Encoded (unsolved and solved), the strings are these: * 7x7:6002002030603030000010230420200000305010404003003 * 7x7:6662232336663232331311235422255544325413434443313 */ static char *board_to_string(int *board, int w, int h) { const int sz = w * h; const int chw = (4*w + 2); /* +2 for trailing '+' and '\n' */ const int chh = (2*h + 1); /* +1: n fence segments, n+1 posts */ const int chlen = chw * chh; char *repr = snewn(chlen + 1, char); int i; assert(board); /* build the first line ("^(\+---){n}\+$") */ for (i = 0; i < w; ++i) { repr[4*i + 0] = '+'; repr[4*i + 1] = '-'; repr[4*i + 2] = '-'; repr[4*i + 3] = '-'; } repr[4*i + 0] = '+'; repr[4*i + 1] = '\n'; /* ... and copy it onto the odd-numbered lines */ for (i = 0; i < h; ++i) memcpy(repr + (2*i + 2) * chw, repr, chw); /* build the second line ("^(\|\t){n}\|$") */ for (i = 0; i < w; ++i) { repr[chw + 4*i + 0] = '|'; repr[chw + 4*i + 1] = ' '; repr[chw + 4*i + 2] = ' '; repr[chw + 4*i + 3] = ' '; } repr[chw + 4*i + 0] = '|'; repr[chw + 4*i + 1] = '\n'; /* ... and copy it onto the even-numbered lines */ for (i = 1; i < h; ++i) memcpy(repr + (2*i + 1) * chw, repr + chw, chw); /* fill in the numbers */ for (i = 0; i < sz; ++i) { const int x = i % w; const int y = i / w; if (board[i] == EMPTY) continue; repr[chw*(2*y + 1) + (4*x + 2)] = board[i] + '0'; } repr[chlen] = '\0'; return repr; } static int game_can_format_as_text_now(const game_params *params) { return TRUE; } static char *game_text_format(const game_state *state) { const int w = state->shared->params.w; const int h = state->shared->params.h; return board_to_string(state->board, w, h); } /***************************************************************************** * GAME GENERATION AND SOLVER * *****************************************************************************/ static const int dx[4] = {-1, 1, 0, 0}; static const int dy[4] = {0, 0, -1, 1}; struct solver_state { int *dsf; int *board; int *connected; int nempty; /* Used internally by learn_bitmap_deductions; kept here to avoid * mallocing/freeing them every time that function is called. */ int *bm, *bmdsf, *bmminsize; }; static void print_board(int *board, int w, int h) { if (verbose) { char *repr = board_to_string(board, w, h); printv("%s\n", repr); free(repr); } } static game_state *new_game(midend *, const game_params *, const char *); static void free_game(game_state *); #define SENTINEL sz static int mark_region(int *board, int w, int h, int i, int n, int m) { int j; board[i] = -1; for (j = 0; j < 4; ++j) { const int x = (i % w) + dx[j], y = (i / w) + dy[j], ii = w*y + x; if (x < 0 || x >= w || y < 0 || y >= h) continue; if (board[ii] == m) return FALSE; if (board[ii] != n) continue; if (!mark_region(board, w, h, ii, n, m)) return FALSE; } return TRUE; } static int region_size(int *board, int w, int h, int i) { const int sz = w * h; int j, size, copy; if (board[i] == 0) return 0; copy = board[i]; mark_region(board, w, h, i, board[i], SENTINEL); for (size = j = 0; j < sz; ++j) { if (board[j] != -1) continue; ++size; board[j] = copy; } return size; } static void merge_ones(int *board, int w, int h) { const int sz = w * h; const int maxsize = min(max(max(w, h), 3), 9); int i, j, k, change; do { change = FALSE; for (i = 0; i < sz; ++i) { if (board[i] != 1) continue; for (j = 0; j < 4; ++j, board[i] = 1) { const int x = (i % w) + dx[j], y = (i / w) + dy[j]; int oldsize, newsize, ok, ii = w*y + x; if (x < 0 || x >= w || y < 0 || y >= h) continue; if (board[ii] == maxsize) continue; oldsize = board[ii]; board[i] = oldsize; newsize = region_size(board, w, h, i); if (newsize > maxsize) continue; ok = mark_region(board, w, h, i, oldsize, newsize); for (k = 0; k < sz; ++k) if (board[k] == -1) board[k] = ok ? newsize : oldsize; if (ok) break; } if (j < 4) change = TRUE; } } while (change); } /* generate a random valid board; uses validate_board. */ static void make_board(int *board, int w, int h, random_state *rs) { const int sz = w * h; /* w=h=2 is a special case which requires a number > max(w, h) */ /* TODO prove that this is the case ONLY for w=h=2. */ const int maxsize = min(max(max(w, h), 3), 9); /* Note that if 1 in {w, h} then it's impossible to have a region * of size > w*h, so the special case only affects w=h=2. */ int i, change, *dsf; assert(w >= 1); assert(h >= 1); assert(board); /* I abuse the board variable: when generating the puzzle, it * contains a shuffled list of numbers {0, ..., sz-1}. */ for (i = 0; i < sz; ++i) board[i] = i; dsf = snewn(sz, int); retry: dsf_init(dsf, sz); shuffle(board, sz, sizeof (int), rs); do { change = FALSE; /* as long as the board potentially has errors */ for (i = 0; i < sz; ++i) { const int square = dsf_canonify(dsf, board[i]); const int size = dsf_size(dsf, square); int merge = SENTINEL, min = maxsize - size + 1, error = FALSE; int neighbour, neighbour_size, j; for (j = 0; j < 4; ++j) { const int x = (board[i] % w) + dx[j]; const int y = (board[i] / w) + dy[j]; if (x < 0 || x >= w || y < 0 || y >= h) continue; neighbour = dsf_canonify(dsf, w*y + x); if (square == neighbour) continue; neighbour_size = dsf_size(dsf, neighbour); if (size == neighbour_size) error = TRUE; /* find the smallest neighbour to merge with, which * wouldn't make the region too large. (This is * guaranteed by the initial value of `min'.) */ if (neighbour_size < min) { min = neighbour_size; merge = neighbour; } } /* if this square is not in error, leave it be */ if (!error) continue; /* if it is, but we can't fix it, retry the whole board. * Maybe we could fix it by merging the conflicting * neighbouring region(s) into some of their neighbours, * but just restarting works out fine. */ if (merge == SENTINEL) goto retry; /* merge with the smallest neighbouring workable region. */ dsf_merge(dsf, square, merge); change = TRUE; } } while (change); for (i = 0; i < sz; ++i) board[i] = dsf_size(dsf, i); merge_ones(board, w, h); sfree(dsf); } static void merge(int *dsf, int *connected, int a, int b) { int c; assert(dsf); assert(connected); a = dsf_canonify(dsf, a); b = dsf_canonify(dsf, b); if (a == b) return; dsf_merge(dsf, a, b); c = connected[a]; connected[a] = connected[b]; connected[b] = c; } static void *memdup(const void *ptr, size_t len, size_t esz) { void *dup = smalloc(len * esz); assert(ptr); memcpy(dup, ptr, len * esz); return dup; } static void expand(struct solver_state *s, int w, int h, int t, int f) { int j; assert(s); assert(s->board[t] == EMPTY); /* expand to empty square */ assert(s->board[f] != EMPTY); /* expand from non-empty square */ printv( "learn: expanding %d from (%d, %d) into (%d, %d)\n", s->board[f], f % w, f / w, t % w, t / w); s->board[t] = s->board[f]; for (j = 0; j < 4; ++j) { const int x = (t % w) + dx[j]; const int y = (t / w) + dy[j]; const int idx = w*y + x; if (x < 0 || x >= w || y < 0 || y >= h) continue; if (s->board[idx] != s->board[t]) continue; merge(s->dsf, s->connected, t, idx); } --s->nempty; } static void clear_count(int *board, int sz) { int i; for (i = 0; i < sz; ++i) { if (board[i] >= 0) continue; else if (board[i] == -SENTINEL) board[i] = EMPTY; else board[i] = -board[i]; } } static void flood_count(int *board, int w, int h, int i, int n, int *c) { const int sz = w * h; int k; if (board[i] == EMPTY) board[i] = -SENTINEL; else if (board[i] == n) board[i] = -board[i]; else return; if (--*c == 0) return; for (k = 0; k < 4; ++k) { const int x = (i % w) + dx[k]; const int y = (i / w) + dy[k]; const int idx = w*y + x; if (x < 0 || x >= w || y < 0 || y >= h) continue; flood_count(board, w, h, idx, n, c); if (*c == 0) return; } } static int check_capacity(int *board, int w, int h, int i) { int n = board[i]; flood_count(board, w, h, i, board[i], &n); clear_count(board, w * h); return n == 0; } static int expandsize(const int *board, int *dsf, int w, int h, int i, int n) { int j; int nhits = 0; int hits[4]; int size = 1; for (j = 0; j < 4; ++j) { const int x = (i % w) + dx[j]; const int y = (i / w) + dy[j]; const int idx = w*y + x; int root; int m; if (x < 0 || x >= w || y < 0 || y >= h) continue; if (board[idx] != n) continue; root = dsf_canonify(dsf, idx); for (m = 0; m < nhits && root != hits[m]; ++m); if (m < nhits) continue; printv("\t (%d, %d) contrib %d to size\n", x, y, dsf[root] >> 2); size += dsf_size(dsf, root); assert(dsf_size(dsf, root) >= 1); hits[nhits++] = root; } return size; } /* * +---+---+---+---+---+---+---+ * | 6 | | | 2 | | | 2 | * +---+---+---+---+---+---+---+ * | | 3 | | 6 | | 3 | | * +---+---+---+---+---+---+---+ * | 3 | | | | | | 1 | * +---+---+---+---+---+---+---+ * | | 2 | 3 | | 4 | 2 | | * +---+---+---+---+---+---+---+ * | 2 | | | | | | 3 | * +---+---+---+---+---+---+---+ * | | 5 | | 1 | | 4 | | * +---+---+---+---+---+---+---+ * | 4 | | | 3 | | | 3 | * +---+---+---+---+---+---+---+ */ /* Solving techniques: * * CONNECTED COMPONENT FORCED EXPANSION (too big): * When a CC can only be expanded in one direction, because all the * other ones would make the CC too big. * +---+---+---+---+---+ * | 2 | 2 | | 2 | _ | * +---+---+---+---+---+ * * CONNECTED COMPONENT FORCED EXPANSION (too small): * When a CC must include a particular square, because otherwise there * would not be enough room to complete it. This includes squares not * adjacent to the CC through learn_critical_square. * +---+---+ * | 2 | _ | * +---+---+ * * DROPPING IN A ONE: * When an empty square has no neighbouring empty squares and only a 1 * will go into the square (or other CCs would be too big). * +---+---+---+ * | 2 | 2 | _ | * +---+---+---+ * * TODO: generalise DROPPING IN A ONE: find the size of the CC of * empty squares and a list of all adjacent numbers. See if only one * number in {1, ..., size} u {all adjacent numbers} is possible. * Probably this is only effective for a CC size < n for some n (4?) * * TODO: backtracking. */ static void filled_square(struct solver_state *s, int w, int h, int i) { int j; for (j = 0; j < 4; ++j) { const int x = (i % w) + dx[j]; const int y = (i / w) + dy[j]; const int idx = w*y + x; if (x < 0 || x >= w || y < 0 || y >= h) continue; if (s->board[i] == s->board[idx]) merge(s->dsf, s->connected, i, idx); } } static void init_solver_state(struct solver_state *s, int w, int h) { const int sz = w * h; int i; assert(s); s->nempty = 0; for (i = 0; i < sz; ++i) s->connected[i] = i; for (i = 0; i < sz; ++i) if (s->board[i] == EMPTY) ++s->nempty; else filled_square(s, w, h, i); } static int learn_expand_or_one(struct solver_state *s, int w, int h) { const int sz = w * h; int i; int learn = FALSE; assert(s); for (i = 0; i < sz; ++i) { int j; int one = TRUE; if (s->board[i] != EMPTY) continue; for (j = 0; j < 4; ++j) { const int x = (i % w) + dx[j]; const int y = (i / w) + dy[j]; const int idx = w*y + x; if (x < 0 || x >= w || y < 0 || y >= h) continue; if (s->board[idx] == EMPTY) { one = FALSE; continue; } if (one && (s->board[idx] == 1 || (s->board[idx] >= expandsize(s->board, s->dsf, w, h, i, s->board[idx])))) one = FALSE; if (dsf_size(s->dsf, idx) == s->board[idx]) continue; assert(s->board[i] == EMPTY); s->board[i] = -SENTINEL; if (check_capacity(s->board, w, h, idx)) continue; assert(s->board[i] == EMPTY); printv("learn: expanding in one\n"); expand(s, w, h, i, idx); learn = TRUE; break; } if (j == 4 && one) { printv("learn: one at (%d, %d)\n", i % w, i / w); assert(s->board[i] == EMPTY); s->board[i] = 1; assert(s->nempty); --s->nempty; learn = TRUE; } } return learn; } static int learn_blocked_expansion(struct solver_state *s, int w, int h) { const int sz = w * h; int i; int learn = FALSE; assert(s); /* for every connected component */ for (i = 0; i < sz; ++i) { int exp = SENTINEL; int j; if (s->board[i] == EMPTY) continue; j = dsf_canonify(s->dsf, i); /* (but only for each connected component) */ if (i != j) continue; /* (and not if it's already complete) */ if (dsf_size(s->dsf, j) == s->board[j]) continue; /* for each square j _in_ the connected component */ do { int k; printv(" looking at (%d, %d)\n", j % w, j / w); /* for each neighbouring square (idx) */ for (k = 0; k < 4; ++k) { const int x = (j % w) + dx[k]; const int y = (j / w) + dy[k]; const int idx = w*y + x; int size; /* int l; int nhits = 0; int hits[4]; */ if (x < 0 || x >= w || y < 0 || y >= h) continue; if (s->board[idx] != EMPTY) continue; if (exp == idx) continue; printv("\ttrying to expand onto (%d, %d)\n", x, y); /* find out the would-be size of the new connected * component if we actually expanded into idx */ /* size = 1; for (l = 0; l < 4; ++l) { const int lx = x + dx[l]; const int ly = y + dy[l]; const int idxl = w*ly + lx; int root; int m; if (lx < 0 || lx >= w || ly < 0 || ly >= h) continue; if (board[idxl] != board[j]) continue; root = dsf_canonify(dsf, idxl); for (m = 0; m < nhits && root != hits[m]; ++m); if (m != nhits) continue; // printv("\t (%d, %d) contributed %d to size\n", lx, ly, dsf[root] >> 2); size += dsf_size(dsf, root); assert(dsf_size(dsf, root) >= 1); hits[nhits++] = root; } */ size = expandsize(s->board, s->dsf, w, h, idx, s->board[j]); /* ... and see if that size is too big, or if we * have other expansion candidates. Otherwise * remember the (so far) only candidate. */ printv("\tthat would give a size of %d\n", size); if (size > s->board[j]) continue; /* printv("\tnow knowing %d expansions\n", nexpand + 1); */ if (exp != SENTINEL) goto next_i; assert(exp != idx); exp = idx; } j = s->connected[j]; /* next square in the same CC */ assert(s->board[i] == s->board[j]); } while (j != i); /* end: for each square j _in_ the connected component */ if (exp == SENTINEL) continue; printv("learning to expand\n"); expand(s, w, h, exp, i); learn = TRUE; next_i: ; } /* end: for each connected component */ return learn; } static int learn_critical_square(struct solver_state *s, int w, int h) { const int sz = w * h; int i; int learn = FALSE; assert(s); /* for each connected component */ for (i = 0; i < sz; ++i) { int j, slack; if (s->board[i] == EMPTY) continue; if (i != dsf_canonify(s->dsf, i)) continue; slack = s->board[i] - dsf_size(s->dsf, i); if (slack == 0) continue; assert(s->board[i] != 1); /* for each empty square */ for (j = 0; j < sz; ++j) { if (s->board[j] == EMPTY) { /* if it's too far away from the CC, don't bother */ int k = i, jx = j % w, jy = j / w; do { int kx = k % w, ky = k / w; if (abs(kx - jx) + abs(ky - jy) <= slack) break; k = s->connected[k]; } while (i != k); if (i == k) continue; /* not within range */ } else continue; s->board[j] = -SENTINEL; if (check_capacity(s->board, w, h, i)) continue; /* if not expanding s->board[i] to s->board[j] implies * that s->board[i] can't reach its full size, ... */ assert(s->nempty); printv( "learn: ds %d at (%d, %d) blocking (%d, %d)\n", s->board[i], j % w, j / w, i % w, i / w); --s->nempty; s->board[j] = s->board[i]; filled_square(s, w, h, j); learn = TRUE; } } return learn; } #if 0 static void print_bitmap(int *bitmap, int w, int h) { if (verbose) { int x, y; for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { printv(" %03x", bm[y*w+x]); } printv("\n"); } } } #endif static int learn_bitmap_deductions(struct solver_state *s, int w, int h) { const int sz = w * h; int *bm = s->bm; int *dsf = s->bmdsf; int *minsize = s->bmminsize; int x, y, i, j, n; int learn = FALSE; /* * This function does deductions based on building up a bitmap * which indicates the possible numbers that can appear in each * grid square. If we can rule out all but one possibility for a * particular square, then we've found out the value of that * square. In particular, this is one of the few forms of * deduction capable of inferring the existence of a 'ghost * region', i.e. a region which has none of its squares filled in * at all. * * The reasoning goes like this. A currently unfilled square S can * turn out to contain digit n in exactly two ways: either S is * part of an n-region which also includes some currently known * connected component of squares with n in, or S is part of an * n-region separate from _all_ currently known connected * components. If we can rule out both possibilities, then square * S can't contain digit n at all. * * The former possibility: if there's a region of size n * containing both S and some existing component C, then that * means the distance from S to C must be small enough that C * could be extended to include S without becoming too big. So we * can do a breadth-first search out from all existing components * with n in them, to identify all the squares which could be * joined to any of them. * * The latter possibility: if there's a region of size n that * doesn't contain _any_ existing component, then it also can't * contain any square adjacent to an existing component either. So * we can identify all the EMPTY squares not adjacent to any * existing square with n in, and group them into connected * components; then any component of size less than n is ruled * out, because there wouldn't be room to create a completely new * n-region in it. * * In fact we process these possibilities in the other order. * First we find all the squares not adjacent to an existing * square with n in; then we winnow those by removing too-small * connected components, to get the set of squares which could * possibly be part of a brand new n-region; and finally we do the * breadth-first search to add in the set of squares which could * possibly be added to some existing n-region. */ /* * Start by initialising our bitmap to 'all numbers possible in * all squares'. */ for (y = 0; y < h; y++) for (x = 0; x < w; x++) bm[y*w+x] = (1 << 10) - (1 << 1); /* bits 1,2,...,9 now set */ #if 0 printv("initial bitmap:\n"); print_bitmap(bm, w, h); #endif /* * Now completely zero out the bitmap for squares that are already * filled in (we aren't interested in those anyway). Also, for any * filled square, eliminate its number from all its neighbours * (because, as discussed above, the neighbours couldn't be part * of a _new_ region with that number in it, and that's the case * we consider first). */ for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { i = y*w+x; n = s->board[i]; if (n != EMPTY) { bm[i] = 0; if (x > 0) bm[i-1] &= ~(1 << n); if (x+1 < w) bm[i+1] &= ~(1 << n); if (y > 0) bm[i-w] &= ~(1 << n); if (y+1 < h) bm[i+w] &= ~(1 << n); } } } #if 0 printv("bitmap after filled squares:\n"); print_bitmap(bm, w, h); #endif /* * Now, for each n, we separately find the connected components of * squares for which n is still a possibility. Then discard any * component of size < n, because that component is too small to * have a completely new n-region in it. */ for (n = 1; n <= 9; n++) { dsf_init(dsf, sz); /* Build the dsf */ for (y = 0; y < h; y++) for (x = 0; x+1 < w; x++) if (bm[y*w+x] & bm[y*w+(x+1)] & (1 << n)) dsf_merge(dsf, y*w+x, y*w+(x+1)); for (y = 0; y+1 < h; y++) for (x = 0; x < w; x++) if (bm[y*w+x] & bm[(y+1)*w+x] & (1 << n)) dsf_merge(dsf, y*w+x, (y+1)*w+x); /* Query the dsf */ for (i = 0; i < sz; i++) if ((bm[i] & (1 << n)) && dsf_size(dsf, i) < n) bm[i] &= ~(1 << n); } #if 0 printv("bitmap after winnowing small components:\n"); print_bitmap(bm, w, h); #endif /* * Now our bitmap includes every square which could be part of a * completely new region, of any size. Extend it to include * squares which could be part of an existing region. */ for (n = 1; n <= 9; n++) { /* * We're going to do a breadth-first search starting from * existing connected components with cell value n, to find * all cells they might possibly extend into. * * The quantity we compute, for each square, is 'minimum size * that any existing CC would have to have if extended to * include this square'. So squares already _in_ an existing * CC are initialised to the size of that CC; then we search * outwards using the rule that if a square's score is j, then * its neighbours can't score more than j+1. * * Scores are capped at n+1, because if a square scores more * than n then that's enough to know it can't possibly be * reached by extending an existing region - we don't need to * know exactly _how far_ out of reach it is. */ for (i = 0; i < sz; i++) { if (s->board[i] == n) { /* Square is part of an existing CC. */ minsize[i] = dsf_size(s->dsf, i); } else { /* Otherwise, initialise to the maximum score n+1; * we'll reduce this later if we find a neighbouring * square with a lower score. */ minsize[i] = n+1; } } for (j = 1; j < n; j++) { /* * Find neighbours of cells scoring j, and set their score * to at most j+1. * * Doing the BFS this way means we need n passes over the * grid, which isn't entirely optimal but it seems to be * fast enough for the moment. This could probably be * improved by keeping a linked-list queue of cells in * some way, but I think you'd have to be a bit careful to * insert things into the right place in the queue; this * way is easier not to get wrong. */ for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { i = y*w+x; if (minsize[i] == j) { if (x > 0 && minsize[i-1] > j+1) minsize[i-1] = j+1; if (x+1 < w && minsize[i+1] > j+1) minsize[i+1] = j+1; if (y > 0 && minsize[i-w] > j+1) minsize[i-w] = j+1; if (y+1 < h && minsize[i+w] > j+1) minsize[i+w] = j+1; } } } } /* * Now, every cell scoring at most n should have its 1<> 8) { val >>= 8; n += 8; } if (val >> 4) { val >>= 4; n += 4; } if (val >> 2) { val >>= 2; n += 2; } if (val >> 1) { val >>= 1; n += 1; } /* Double-check that we ended up with a sensible * answer. */ assert(1 <= n); assert(n <= 9); assert(bm[i] == (1 << n)); if (s->board[i] == EMPTY) { printv("learn: %d is only possibility at (%d, %d)\n", n, i % w, i / w); s->board[i] = n; filled_square(s, w, h, i); assert(s->nempty); --s->nempty; learn = TRUE; } } } return learn; } static int solver(const int *orig, int w, int h, char **solution) { const int sz = w * h; struct solver_state ss; ss.board = memdup(orig, sz, sizeof (int)); ss.dsf = snew_dsf(sz); /* eqv classes: connected components */ ss.connected = snewn(sz, int); /* connected[n] := n.next; */ /* cyclic disjoint singly linked lists, same partitioning as dsf. * The lists lets you iterate over a partition given any member */ ss.bm = snewn(sz, int); ss.bmdsf = snew_dsf(sz); ss.bmminsize = snewn(sz, int); printv("trying to solve this:\n"); print_board(ss.board, w, h); init_solver_state(&ss, w, h); do { if (learn_blocked_expansion(&ss, w, h)) continue; if (learn_expand_or_one(&ss, w, h)) continue; if (learn_critical_square(&ss, w, h)) continue; if (learn_bitmap_deductions(&ss, w, h)) continue; break; } while (ss.nempty); printv("best guess:\n"); print_board(ss.board, w, h); if (solution) { int i; *solution = snewn(sz + 2, char); **solution = 's'; for (i = 0; i < sz; ++i) (*solution)[i + 1] = ss.board[i] + '0'; (*solution)[sz + 1] = '\0'; /* We don't need the \0 for execute_move (the only user) * I'm just being printf-friendly in case I wanna print */ } sfree(ss.dsf); sfree(ss.board); sfree(ss.connected); sfree(ss.bm); sfree(ss.bmdsf); sfree(ss.bmminsize); return !ss.nempty; } static int *make_dsf(int *dsf, int *board, const int w, const int h) { const int sz = w * h; int i; if (!dsf) dsf = snew_dsf(w * h); else dsf_init(dsf, w * h); for (i = 0; i < sz; ++i) { int j; for (j = 0; j < 4; ++j) { const int x = (i % w) + dx[j]; const int y = (i / w) + dy[j]; const int k = w*y + x; if (x < 0 || x >= w || y < 0 || y >= h) continue; if (board[i] == board[k]) dsf_merge(dsf, i, k); } } return dsf; } static void minimize_clue_set(int *board, int w, int h, random_state *rs) { const int sz = w * h; int *shuf = snewn(sz, int), i; int *dsf, *next; for (i = 0; i < sz; ++i) shuf[i] = i; shuffle(shuf, sz, sizeof (int), rs); /* * First, try to eliminate an entire region at a time if possible, * because inferring the existence of a completely unclued region * is a particularly good aspect of this puzzle type and we want * to encourage it to happen. * * Begin by identifying the regions as linked lists of cells using * the 'next' array. */ dsf = make_dsf(NULL, board, w, h); next = snewn(sz, int); for (i = 0; i < sz; ++i) { int j = dsf_canonify(dsf, i); if (i == j) { /* First cell of a region; set next[i] = -1 to indicate * end-of-list. */ next[i] = -1; } else { /* Add this cell to a region which already has a * linked-list head, by pointing the canonical element j * at this one, and pointing this one in turn at wherever * j previously pointed. (This should end up with the * elements linked in the order 1,n,n-1,n-2,...,2, which * is a bit weird-looking, but any order is fine.) */ assert(j < i); next[i] = next[j]; next[j] = i; } } /* * Now loop over the grid cells in our shuffled order, and each * time we encounter a region for the first time, try to remove it * all. Then we set next[canonical index] to -2 rather than -1, to * mark it as already tried. * * Doing this in a loop over _cells_, rather than extracting and * shuffling a list of _regions_, is intended to skew the * probabilities towards trying to remove larger regions first * (but without anything as crudely predictable as enforcing that * we _always_ process regions in descending size order). Region * removals might well be mutually exclusive, and larger ghost * regions are more interesting, so we want to bias towards them * if we can. */ for (i = 0; i < sz; ++i) { int j = dsf_canonify(dsf, shuf[i]); if (next[j] != -2) { int tmp = board[j]; int k; /* Blank out the whole thing. */ for (k = j; k >= 0; k = next[k]) board[k] = EMPTY; if (!solver(board, w, h, NULL)) { /* Wasn't still solvable; reinstate it all */ for (k = j; k >= 0; k = next[k]) board[k] = tmp; } /* Either way, don't try this region again. */ next[j] = -2; } } sfree(next); sfree(dsf); /* * Now go through individual cells, in the same shuffled order, * and try to remove each one by itself. */ for (i = 0; i < sz; ++i) { int tmp = board[shuf[i]]; board[shuf[i]] = EMPTY; if (!solver(board, w, h, NULL)) board[shuf[i]] = tmp; } sfree(shuf); } static int encode_run(char *buffer, int run) { int i = 0; for (; run > 26; run -= 26) buffer[i++] = 'z'; if (run) buffer[i++] = 'a' - 1 + run; return i; } static char *new_game_desc(const game_params *params, random_state *rs, char **aux, int interactive) { const int w = params->w, h = params->h, sz = w * h; int *board = snewn(sz, int), i, j, run; char *description = snewn(sz + 1, char); make_board(board, w, h, rs); minimize_clue_set(board, w, h, rs); for (run = j = i = 0; i < sz; ++i) { assert(board[i] >= 0); assert(board[i] < 10); if (board[i] == 0) { ++run; } else { j += encode_run(description + j, run); run = 0; description[j++] = board[i] + '0'; } } j += encode_run(description + j, run); description[j++] = '\0'; sfree(board); return sresize(description, j, char); } static char *validate_desc(const game_params *params, const char *desc) { const int sz = params->w * params->h; const char m = '0' + max(max(params->w, params->h), 3); int area; for (area = 0; *desc; ++desc) { if (*desc >= 'a' && *desc <= 'z') area += *desc - 'a' + 1; else if (*desc >= '0' && *desc <= m) ++area; else { static char s[] = "Invalid character '%""' in game description"; int n = sprintf(s, "Invalid character '%1c' in game description", *desc); assert(n + 1 <= lenof(s)); /* +1 for the terminating NUL */ return s; } if (area > sz) return "Too much data to fit in grid"; } return (area < sz) ? "Not enough data to fill grid" : NULL; } static game_state *new_game(midend *me, const game_params *params, const char *desc) { game_state *state = snew(game_state); int sz = params->w * params->h; int i; state->cheated = state->completed = FALSE; state->shared = snew(struct shared_state); state->shared->refcnt = 1; state->shared->params = *params; /* struct copy */ state->shared->clues = snewn(sz, int); for (i = 0; *desc; ++desc) { if (*desc >= 'a' && *desc <= 'z') { int j = *desc - 'a' + 1; assert(i + j <= sz); for (; j; --j) state->shared->clues[i++] = 0; } else state->shared->clues[i++] = *desc - '0'; } state->board = memdup(state->shared->clues, sz, sizeof (int)); return state; } static game_state *dup_game(const game_state *state) { const int sz = state->shared->params.w * state->shared->params.h; game_state *ret = snew(game_state); ret->board = memdup(state->board, sz, sizeof (int)); ret->shared = state->shared; ret->cheated = state->cheated; ret->completed = state->completed; ++ret->shared->refcnt; return ret; } static void free_game(game_state *state) { assert(state); sfree(state->board); if (--state->shared->refcnt == 0) { sfree(state->shared->clues); sfree(state->shared); } sfree(state); } static char *solve_game(const game_state *state, const game_state *currstate, const char *aux, char **error) { if (aux == NULL) { const int w = state->shared->params.w; const int h = state->shared->params.h; char *new_aux; if (!solver(state->board, w, h, &new_aux)) *error = "Sorry, I couldn't find a solution"; return new_aux; } return dupstr(aux); } /***************************************************************************** * USER INTERFACE STATE AND ACTION * *****************************************************************************/ struct game_ui { int *sel; /* w*h highlighted squares, or NULL */ int cur_x, cur_y, cur_visible, keydragging; }; static game_ui *new_ui(const game_state *state) { game_ui *ui = snew(game_ui); ui->sel = NULL; ui->cur_x = ui->cur_y = ui->cur_visible = ui->keydragging = 0; return ui; } static void free_ui(game_ui *ui) { if (ui->sel) sfree(ui->sel); sfree(ui); } static char *encode_ui(const game_ui *ui) { return NULL; } static void decode_ui(game_ui *ui, const char *encoding) { } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { /* Clear any selection */ if (ui->sel) { sfree(ui->sel); ui->sel = NULL; } ui->keydragging = FALSE; } #define PREFERRED_TILE_SIZE 32 #define TILE_SIZE (ds->tilesize) #define BORDER (TILE_SIZE / 2) #define BORDER_WIDTH (max(TILE_SIZE / 32, 1)) struct game_drawstate { struct game_params params; int tilesize; int started; int *v, *flags; int *dsf_scratch, *border_scratch; }; static char *interpret_move(const game_state *state, game_ui *ui, const game_drawstate *ds, int x, int y, int button) { const int w = state->shared->params.w; const int h = state->shared->params.h; const int tx = (x + TILE_SIZE - BORDER) / TILE_SIZE - 1; const int ty = (y + TILE_SIZE - BORDER) / TILE_SIZE - 1; char *move = NULL; int i; assert(ui); assert(ds); button &= ~MOD_MASK; if (button == LEFT_BUTTON || button == LEFT_DRAG) { /* A left-click anywhere will clear the current selection. */ if (button == LEFT_BUTTON) { if (ui->sel) { sfree(ui->sel); ui->sel = NULL; } } if (tx >= 0 && tx < w && ty >= 0 && ty < h) { if (!ui->sel) { ui->sel = snewn(w*h, int); memset(ui->sel, 0, w*h*sizeof(int)); } if (!state->shared->clues[w*ty+tx]) ui->sel[w*ty+tx] = 1; } ui->cur_visible = 0; return ""; /* redraw */ } if (IS_CURSOR_MOVE(button)) { ui->cur_visible = 1; move_cursor(button, &ui->cur_x, &ui->cur_y, w, h, 0); if (ui->keydragging) goto select_square; return ""; } if (button == CURSOR_SELECT) { if (!ui->cur_visible) { ui->cur_visible = 1; return ""; } ui->keydragging = !ui->keydragging; if (!ui->keydragging) return ""; select_square: if (!ui->sel) { ui->sel = snewn(w*h, int); memset(ui->sel, 0, w*h*sizeof(int)); } if (!state->shared->clues[w*ui->cur_y + ui->cur_x]) ui->sel[w*ui->cur_y + ui->cur_x] = 1; return ""; } if (button == CURSOR_SELECT2) { if (!ui->cur_visible) { ui->cur_visible = 1; return ""; } if (!ui->sel) { ui->sel = snewn(w*h, int); memset(ui->sel, 0, w*h*sizeof(int)); } ui->keydragging = FALSE; if (!state->shared->clues[w*ui->cur_y + ui->cur_x]) ui->sel[w*ui->cur_y + ui->cur_x] ^= 1; for (i = 0; i < w*h && !ui->sel[i]; i++); if (i == w*h) { sfree(ui->sel); ui->sel = NULL; } return ""; } if (button == '\b' || button == 27) { sfree(ui->sel); ui->sel = NULL; ui->keydragging = FALSE; return ""; } if (button < '0' || button > '9') return NULL; button -= '0'; if (button > (w == 2 && h == 2 ? 3 : max(w, h))) return NULL; ui->keydragging = FALSE; for (i = 0; i < w*h; i++) { char buf[32]; if ((ui->sel && ui->sel[i]) || (!ui->sel && ui->cur_visible && (w*ui->cur_y+ui->cur_x) == i)) { if (state->shared->clues[i] != 0) continue; /* in case cursor is on clue */ if (state->board[i] != button) { sprintf(buf, "%s%d", move ? "," : "", i); if (move) { move = srealloc(move, strlen(move)+strlen(buf)+1); strcat(move, buf); } else { move = smalloc(strlen(buf)+1); strcpy(move, buf); } } } } if (move) { char buf[32]; sprintf(buf, "_%d", button); move = srealloc(move, strlen(move)+strlen(buf)+1); strcat(move, buf); } if (!ui->sel) return move ? move : NULL; sfree(ui->sel); ui->sel = NULL; /* Need to update UI at least, as we cleared the selection */ return move ? move : ""; } static game_state *execute_move(const game_state *state, const char *move) { game_state *new_state = NULL; const int sz = state->shared->params.w * state->shared->params.h; if (*move == 's') { int i = 0; new_state = dup_game(state); for (++move; i < sz; ++i) new_state->board[i] = move[i] - '0'; new_state->cheated = TRUE; } else { int value; char *endptr, *delim = strchr(move, '_'); if (!delim) goto err; value = strtol(delim+1, &endptr, 0); if (*endptr || endptr == delim+1) goto err; if (value < 0 || value > 9) goto err; new_state = dup_game(state); while (*move) { const int i = strtol(move, &endptr, 0); if (endptr == move) goto err; if (i < 0 || i >= sz) goto err; new_state->board[i] = value; if (*endptr == '_') break; if (*endptr != ',') goto err; move = endptr + 1; } } /* * Check for completion. */ if (!new_state->completed) { const int w = new_state->shared->params.w; const int h = new_state->shared->params.h; const int sz = w * h; int *dsf = make_dsf(NULL, new_state->board, w, h); int i; for (i = 0; i < sz && new_state->board[i] == dsf_size(dsf, i); ++i); sfree(dsf); if (i == sz) new_state->completed = TRUE; } return new_state; err: if (new_state) free_game(new_state); return NULL; } /* ---------------------------------------------------------------------- * Drawing routines. */ #define FLASH_TIME 0.4F #define COL_CLUE COL_GRID enum { COL_BACKGROUND, COL_GRID, COL_HIGHLIGHT, COL_CORRECT, COL_ERROR, COL_USER, COL_CURSOR, NCOLOURS }; static void game_compute_size(const game_params *params, int tilesize, int *x, int *y) { *x = (params->w + 1) * tilesize; *y = (params->h + 1) * tilesize; } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { ds->tilesize = tilesize; } static float *game_colours(frontend *fe, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float); frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]); ret[COL_GRID * 3 + 0] = 0.0F; ret[COL_GRID * 3 + 1] = 0.0F; ret[COL_GRID * 3 + 2] = 0.0F; ret[COL_HIGHLIGHT * 3 + 0] = 0.85F * ret[COL_BACKGROUND * 3 + 0]; ret[COL_HIGHLIGHT * 3 + 1] = 0.85F * ret[COL_BACKGROUND * 3 + 1]; ret[COL_HIGHLIGHT * 3 + 2] = 0.85F * ret[COL_BACKGROUND * 3 + 2]; ret[COL_CORRECT * 3 + 0] = 0.9F * ret[COL_BACKGROUND * 3 + 0]; ret[COL_CORRECT * 3 + 1] = 0.9F * ret[COL_BACKGROUND * 3 + 1]; ret[COL_CORRECT * 3 + 2] = 0.9F * ret[COL_BACKGROUND * 3 + 2]; ret[COL_CURSOR * 3 + 0] = 0.5F * ret[COL_BACKGROUND * 3 + 0]; ret[COL_CURSOR * 3 + 1] = 0.5F * ret[COL_BACKGROUND * 3 + 1]; ret[COL_CURSOR * 3 + 2] = 0.5F * ret[COL_BACKGROUND * 3 + 2]; ret[COL_ERROR * 3 + 0] = 1.0F; ret[COL_ERROR * 3 + 1] = 0.85F * ret[COL_BACKGROUND * 3 + 1]; ret[COL_ERROR * 3 + 2] = 0.85F * ret[COL_BACKGROUND * 3 + 2]; ret[COL_USER * 3 + 0] = 0.0F; ret[COL_USER * 3 + 1] = 0.6F * ret[COL_BACKGROUND * 3 + 1]; ret[COL_USER * 3 + 2] = 0.0F; *ncolours = NCOLOURS; return ret; } static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { struct game_drawstate *ds = snew(struct game_drawstate); int i; ds->tilesize = PREFERRED_TILE_SIZE; ds->started = 0; ds->params = state->shared->params; ds->v = snewn(ds->params.w * ds->params.h, int); ds->flags = snewn(ds->params.w * ds->params.h, int); for (i = 0; i < ds->params.w * ds->params.h; i++) ds->v[i] = ds->flags[i] = -1; ds->border_scratch = snewn(ds->params.w * ds->params.h, int); ds->dsf_scratch = NULL; return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { sfree(ds->v); sfree(ds->flags); sfree(ds->border_scratch); sfree(ds->dsf_scratch); sfree(ds); } #define BORDER_U 0x001 #define BORDER_D 0x002 #define BORDER_L 0x004 #define BORDER_R 0x008 #define BORDER_UR 0x010 #define BORDER_DR 0x020 #define BORDER_UL 0x040 #define BORDER_DL 0x080 #define HIGH_BG 0x100 #define CORRECT_BG 0x200 #define ERROR_BG 0x400 #define USER_COL 0x800 #define CURSOR_SQ 0x1000 static void draw_square(drawing *dr, game_drawstate *ds, int x, int y, int n, int flags) { assert(dr); assert(ds); /* * Clip to the grid square. */ clip(dr, BORDER + x*TILE_SIZE, BORDER + y*TILE_SIZE, TILE_SIZE, TILE_SIZE); /* * Clear the square. */ draw_rect(dr, BORDER + x*TILE_SIZE, BORDER + y*TILE_SIZE, TILE_SIZE, TILE_SIZE, (flags & HIGH_BG ? COL_HIGHLIGHT : flags & ERROR_BG ? COL_ERROR : flags & CORRECT_BG ? COL_CORRECT : COL_BACKGROUND)); /* * Draw the grid lines. */ draw_line(dr, BORDER + x*TILE_SIZE, BORDER + y*TILE_SIZE, BORDER + (x+1)*TILE_SIZE, BORDER + y*TILE_SIZE, COL_GRID); draw_line(dr, BORDER + x*TILE_SIZE, BORDER + y*TILE_SIZE, BORDER + x*TILE_SIZE, BORDER + (y+1)*TILE_SIZE, COL_GRID); /* * Draw the number. */ if (n) { char buf[2]; buf[0] = n + '0'; buf[1] = '\0'; draw_text(dr, (x + 1) * TILE_SIZE, (y + 1) * TILE_SIZE, FONT_VARIABLE, TILE_SIZE / 2, ALIGN_VCENTRE | ALIGN_HCENTRE, flags & USER_COL ? COL_USER : COL_CLUE, buf); } /* * Draw bold lines around the borders. */ if (flags & BORDER_L) draw_rect(dr, BORDER + x*TILE_SIZE + 1, BORDER + y*TILE_SIZE + 1, BORDER_WIDTH, TILE_SIZE - 1, COL_GRID); if (flags & BORDER_U) draw_rect(dr, BORDER + x*TILE_SIZE + 1, BORDER + y*TILE_SIZE + 1, TILE_SIZE - 1, BORDER_WIDTH, COL_GRID); if (flags & BORDER_R) draw_rect(dr, BORDER + (x+1)*TILE_SIZE - BORDER_WIDTH, BORDER + y*TILE_SIZE + 1, BORDER_WIDTH, TILE_SIZE - 1, COL_GRID); if (flags & BORDER_D) draw_rect(dr, BORDER + x*TILE_SIZE + 1, BORDER + (y+1)*TILE_SIZE - BORDER_WIDTH, TILE_SIZE - 1, BORDER_WIDTH, COL_GRID); if (flags & BORDER_UL) draw_rect(dr, BORDER + x*TILE_SIZE + 1, BORDER + y*TILE_SIZE + 1, BORDER_WIDTH, BORDER_WIDTH, COL_GRID); if (flags & BORDER_UR) draw_rect(dr, BORDER + (x+1)*TILE_SIZE - BORDER_WIDTH, BORDER + y*TILE_SIZE + 1, BORDER_WIDTH, BORDER_WIDTH, COL_GRID); if (flags & BORDER_DL) draw_rect(dr, BORDER + x*TILE_SIZE + 1, BORDER + (y+1)*TILE_SIZE - BORDER_WIDTH, BORDER_WIDTH, BORDER_WIDTH, COL_GRID); if (flags & BORDER_DR) draw_rect(dr, BORDER + (x+1)*TILE_SIZE - BORDER_WIDTH, BORDER + (y+1)*TILE_SIZE - BORDER_WIDTH, BORDER_WIDTH, BORDER_WIDTH, COL_GRID); if (flags & CURSOR_SQ) { int coff = TILE_SIZE/8; draw_rect_outline(dr, BORDER + x*TILE_SIZE + coff, BORDER + y*TILE_SIZE + coff, TILE_SIZE - coff*2, TILE_SIZE - coff*2, COL_CURSOR); } unclip(dr); draw_update(dr, BORDER + x*TILE_SIZE, BORDER + y*TILE_SIZE, TILE_SIZE, TILE_SIZE); } static void draw_grid(drawing *dr, game_drawstate *ds, const game_state *state, const game_ui *ui, int flashy, int borders, int shading) { const int w = state->shared->params.w; const int h = state->shared->params.h; int x; int y; /* * Build a dsf for the board in its current state, to use for * highlights and hints. */ ds->dsf_scratch = make_dsf(ds->dsf_scratch, state->board, w, h); /* * Work out where we're putting borders between the cells. */ for (y = 0; y < w*h; y++) ds->border_scratch[y] = 0; for (y = 0; y < h; y++) for (x = 0; x < w; x++) { int dx, dy; int v1, s1, v2, s2; for (dx = 0; dx <= 1; dx++) { int border = FALSE; dy = 1 - dx; if (x+dx >= w || y+dy >= h) continue; v1 = state->board[y*w+x]; v2 = state->board[(y+dy)*w+(x+dx)]; s1 = dsf_size(ds->dsf_scratch, y*w+x); s2 = dsf_size(ds->dsf_scratch, (y+dy)*w+(x+dx)); /* * We only ever draw a border between two cells if * they don't have the same contents. */ if (v1 != v2) { /* * But in that situation, we don't always draw * a border. We do if the two cells both * contain actual numbers... */ if (v1 && v2) border = TRUE; /* * ... or if at least one of them is a * completed or overfull omino. */ if (v1 && s1 >= v1) border = TRUE; if (v2 && s2 >= v2) border = TRUE; } if (border) ds->border_scratch[y*w+x] |= (dx ? 1 : 2); } } /* * Actually do the drawing. */ for (y = 0; y < h; ++y) for (x = 0; x < w; ++x) { /* * Determine what we need to draw in this square. */ int i = y*w+x, v = state->board[i]; int flags = 0; if (flashy || !shading) { /* clear all background flags */ } else if (ui && ui->sel && ui->sel[i]) { flags |= HIGH_BG; } else if (v) { int size = dsf_size(ds->dsf_scratch, i); if (size == v) flags |= CORRECT_BG; else if (size > v) flags |= ERROR_BG; else { int rt = dsf_canonify(ds->dsf_scratch, i), j; for (j = 0; j < w*h; ++j) { int k; if (dsf_canonify(ds->dsf_scratch, j) != rt) continue; for (k = 0; k < 4; ++k) { const int xx = j % w + dx[k], yy = j / w + dy[k]; if (xx >= 0 && xx < w && yy >= 0 && yy < h && state->board[yy*w + xx] == EMPTY) goto noflag; } } flags |= ERROR_BG; noflag: ; } } if (ui && ui->cur_visible && x == ui->cur_x && y == ui->cur_y) flags |= CURSOR_SQ; /* * Borders at the very edges of the grid are * independent of the `borders' flag. */ if (x == 0) flags |= BORDER_L; if (y == 0) flags |= BORDER_U; if (x == w-1) flags |= BORDER_R; if (y == h-1) flags |= BORDER_D; if (borders) { if (x == 0 || (ds->border_scratch[y*w+(x-1)] & 1)) flags |= BORDER_L; if (y == 0 || (ds->border_scratch[(y-1)*w+x] & 2)) flags |= BORDER_U; if (x == w-1 || (ds->border_scratch[y*w+x] & 1)) flags |= BORDER_R; if (y == h-1 || (ds->border_scratch[y*w+x] & 2)) flags |= BORDER_D; if (y > 0 && x > 0 && (ds->border_scratch[(y-1)*w+(x-1)])) flags |= BORDER_UL; if (y > 0 && x < w-1 && ((ds->border_scratch[(y-1)*w+x] & 1) || (ds->border_scratch[(y-1)*w+(x+1)] & 2))) flags |= BORDER_UR; if (y < h-1 && x > 0 && ((ds->border_scratch[y*w+(x-1)] & 2) || (ds->border_scratch[(y+1)*w+(x-1)] & 1))) flags |= BORDER_DL; if (y < h-1 && x < w-1 && ((ds->border_scratch[y*w+(x+1)] & 2) || (ds->border_scratch[(y+1)*w+x] & 1))) flags |= BORDER_DR; } if (!state->shared->clues[y*w+x]) flags |= USER_COL; if (ds->v[y*w+x] != v || ds->flags[y*w+x] != flags) { draw_square(dr, ds, x, y, v, flags); ds->v[y*w+x] = v; ds->flags[y*w+x] = flags; } } } static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float animtime, float flashtime) { const int w = state->shared->params.w; const int h = state->shared->params.h; const int flashy = flashtime > 0 && (flashtime <= FLASH_TIME/3 || flashtime >= FLASH_TIME*2/3); if (!ds->started) { /* * The initial contents of the window are not guaranteed and * can vary with front ends. To be on the safe side, all games * should start by drawing a big background-colour rectangle * covering the whole window. */ draw_rect(dr, 0, 0, w*TILE_SIZE + 2*BORDER, h*TILE_SIZE + 2*BORDER, COL_BACKGROUND); /* * Smaller black rectangle which is the main grid. */ draw_rect(dr, BORDER - BORDER_WIDTH, BORDER - BORDER_WIDTH, w*TILE_SIZE + 2*BORDER_WIDTH + 1, h*TILE_SIZE + 2*BORDER_WIDTH + 1, COL_GRID); draw_update(dr, 0, 0, w*TILE_SIZE + 2*BORDER, h*TILE_SIZE + 2*BORDER); ds->started = TRUE; } draw_grid(dr, ds, state, ui, flashy, TRUE, TRUE); } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return 0.0F; } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { assert(oldstate); assert(newstate); assert(newstate->shared); assert(oldstate->shared == newstate->shared); if (!oldstate->completed && newstate->completed && !oldstate->cheated && !newstate->cheated) return FLASH_TIME; return 0.0F; } static int game_status(const game_state *state) { return state->completed ? +1 : 0; } static int game_timing_state(const game_state *state, game_ui *ui) { return TRUE; } static void game_print_size(const game_params *params, float *x, float *y) { int pw, ph; /* * I'll use 6mm squares by default. */ game_compute_size(params, 600, &pw, &ph); *x = pw / 100.0F; *y = ph / 100.0F; } static void game_print(drawing *dr, const game_state *state, int tilesize) { const int w = state->shared->params.w; const int h = state->shared->params.h; int c, i, borders; /* Ick: fake up `ds->tilesize' for macro expansion purposes */ game_drawstate *ds = game_new_drawstate(dr, state); game_set_size(dr, ds, NULL, tilesize); c = print_mono_colour(dr, 1); assert(c == COL_BACKGROUND); c = print_mono_colour(dr, 0); assert(c == COL_GRID); c = print_mono_colour(dr, 1); assert(c == COL_HIGHLIGHT); c = print_mono_colour(dr, 1); assert(c == COL_CORRECT); c = print_mono_colour(dr, 1); assert(c == COL_ERROR); c = print_mono_colour(dr, 0); assert(c == COL_USER); /* * Border. */ draw_rect(dr, BORDER - BORDER_WIDTH, BORDER - BORDER_WIDTH, w*TILE_SIZE + 2*BORDER_WIDTH + 1, h*TILE_SIZE + 2*BORDER_WIDTH + 1, COL_GRID); /* * We'll draw borders between the ominoes iff the grid is not * pristine. So scan it to see if it is. */ borders = FALSE; for (i = 0; i < w*h; i++) if (state->board[i] && !state->shared->clues[i]) borders = TRUE; /* * Draw grid. */ print_line_width(dr, TILE_SIZE / 64); draw_grid(dr, ds, state, NULL, FALSE, borders, FALSE); /* * Clean up. */ game_free_drawstate(dr, ds); } #ifdef COMBINED #define thegame filling #endif const struct game thegame = { "Filling", "games.filling", "filling", default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, TRUE, solve_game, TRUE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, PREFERRED_TILE_SIZE, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, TRUE, FALSE, game_print_size, game_print, FALSE, /* wants_statusbar */ FALSE, game_timing_state, REQUIRE_NUMPAD, /* flags */ }; #ifdef STANDALONE_SOLVER /* solver? hah! */ int main(int argc, char **argv) { while (*++argv) { game_params *params; game_state *state; char *par; char *desc; for (par = desc = *argv; *desc != '\0' && *desc != ':'; ++desc); if (*desc == '\0') { fprintf(stderr, "bad puzzle id: %s", par); continue; } *desc++ = '\0'; params = snew(game_params); decode_params(params, par); state = new_game(NULL, params, desc); if (solver(state->board, params->w, params->h, NULL)) printf("%s:%s: solvable\n", par, desc); else printf("%s:%s: not solvable\n", par, desc); } return 0; } #endif /* vim: set shiftwidth=4 tabstop=8: */ puzzles-20170606.272beef/fifteen.c0000644000175000017500000007552713115373615015475 0ustar simonsimon/* * fifteen.c: standard 15-puzzle. */ #include #include #include #include #include #include #include "puzzles.h" #define PREFERRED_TILE_SIZE 48 #define TILE_SIZE (ds->tilesize) #define BORDER (TILE_SIZE / 2) #define HIGHLIGHT_WIDTH (TILE_SIZE / 20) #define COORD(x) ( (x) * TILE_SIZE + BORDER ) #define FROMCOORD(x) ( ((x) - BORDER + TILE_SIZE) / TILE_SIZE - 1 ) #define ANIM_TIME 0.13F #define FLASH_FRAME 0.13F #define X(state, i) ( (i) % (state)->w ) #define Y(state, i) ( (i) / (state)->w ) #define C(state, x, y) ( (y) * (state)->w + (x) ) #define PARITY_P(params, gap) (((X((params), (gap)) - ((params)->w - 1)) ^ \ (Y((params), (gap)) - ((params)->h - 1)) ^ \ (((params)->w * (params)->h) + 1)) & 1) #define PARITY_S(state) PARITY_P((state), ((state)->gap_pos)) enum { COL_BACKGROUND, COL_TEXT, COL_HIGHLIGHT, COL_LOWLIGHT, NCOLOURS }; struct game_params { int w, h; }; struct game_state { int w, h, n; int *tiles; int gap_pos; int completed; int used_solve; /* used to suppress completion flash */ int movecount; }; static game_params *default_params(void) { game_params *ret = snew(game_params); ret->w = ret->h = 4; return ret; } static int game_fetch_preset(int i, char **name, game_params **params) { if (i == 0) { *params = default_params(); *name = dupstr("4x4"); return TRUE; } return FALSE; } static void free_params(game_params *params) { sfree(params); } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } static void decode_params(game_params *ret, char const *string) { ret->w = ret->h = atoi(string); while (*string && isdigit((unsigned char)*string)) string++; if (*string == 'x') { string++; ret->h = atoi(string); } } static char *encode_params(const game_params *params, int full) { char data[256]; sprintf(data, "%dx%d", params->w, params->h); return dupstr(data); } static config_item *game_configure(const game_params *params) { config_item *ret; char buf[80]; ret = snewn(3, config_item); ret[0].name = "Width"; ret[0].type = C_STRING; sprintf(buf, "%d", params->w); ret[0].sval = dupstr(buf); ret[0].ival = 0; ret[1].name = "Height"; ret[1].type = C_STRING; sprintf(buf, "%d", params->h); ret[1].sval = dupstr(buf); ret[1].ival = 0; ret[2].name = NULL; ret[2].type = C_END; ret[2].sval = NULL; ret[2].ival = 0; return ret; } static game_params *custom_params(const config_item *cfg) { game_params *ret = snew(game_params); ret->w = atoi(cfg[0].sval); ret->h = atoi(cfg[1].sval); return ret; } static char *validate_params(const game_params *params, int full) { if (params->w < 2 || params->h < 2) return "Width and height must both be at least two"; return NULL; } static int perm_parity(int *perm, int n) { int i, j, ret; ret = 0; for (i = 0; i < n-1; i++) for (j = i+1; j < n; j++) if (perm[i] > perm[j]) ret = !ret; return ret; } static char *new_game_desc(const game_params *params, random_state *rs, char **aux, int interactive) { int gap, n, i, x; int x1, x2, p1, p2, parity; int *tiles, *used; char *ret; int retlen; n = params->w * params->h; tiles = snewn(n, int); used = snewn(n, int); for (i = 0; i < n; i++) { tiles[i] = -1; used[i] = FALSE; } gap = random_upto(rs, n); tiles[gap] = 0; used[0] = TRUE; /* * Place everything else except the last two tiles. */ for (x = 0, i = n-1; i > 2; i--) { int k = random_upto(rs, i); int j; for (j = 0; j < n; j++) if (!used[j] && (k-- == 0)) break; assert(j < n && !used[j]); used[j] = TRUE; while (tiles[x] >= 0) x++; assert(x < n); tiles[x] = j; } /* * Find the last two locations, and the last two pieces. */ while (tiles[x] >= 0) x++; assert(x < n); x1 = x; x++; while (tiles[x] >= 0) x++; assert(x < n); x2 = x; for (i = 0; i < n; i++) if (!used[i]) break; p1 = i; for (i = p1+1; i < n; i++) if (!used[i]) break; p2 = i; /* * Determine the required parity of the overall permutation. * This is the XOR of: * * - The chessboard parity ((x^y)&1) of the gap square. The * bottom right counts as even. * * - The parity of n. (The target permutation is 1,...,n-1,0 * rather than 0,...,n-1; this is a cyclic permutation of * the starting point and hence is odd iff n is even.) */ parity = PARITY_P(params, gap); /* * Try the last two tiles one way round. If that fails, swap * them. */ tiles[x1] = p1; tiles[x2] = p2; if (perm_parity(tiles, n) != parity) { tiles[x1] = p2; tiles[x2] = p1; assert(perm_parity(tiles, n) == parity); } /* * Now construct the game description, by describing the tile * array as a simple sequence of comma-separated integers. */ ret = NULL; retlen = 0; for (i = 0; i < n; i++) { char buf[80]; int k; k = sprintf(buf, "%d,", tiles[i]); ret = sresize(ret, retlen + k + 1, char); strcpy(ret + retlen, buf); retlen += k; } ret[retlen-1] = '\0'; /* delete last comma */ sfree(tiles); sfree(used); return ret; } static char *validate_desc(const game_params *params, const char *desc) { const char *p; char *err; int i, area; int *used; area = params->w * params->h; p = desc; err = NULL; used = snewn(area, int); for (i = 0; i < area; i++) used[i] = FALSE; for (i = 0; i < area; i++) { const char *q = p; int n; if (*p < '0' || *p > '9') { err = "Not enough numbers in string"; goto leave; } while (*p >= '0' && *p <= '9') p++; if (i < area-1 && *p != ',') { err = "Expected comma after number"; goto leave; } else if (i == area-1 && *p) { err = "Excess junk at end of string"; goto leave; } n = atoi(q); if (n < 0 || n >= area) { err = "Number out of range"; goto leave; } if (used[n]) { err = "Number used twice"; goto leave; } used[n] = TRUE; if (*p) p++; /* eat comma */ } leave: sfree(used); return err; } static game_state *new_game(midend *me, const game_params *params, const char *desc) { game_state *state = snew(game_state); int i; const char *p; state->w = params->w; state->h = params->h; state->n = params->w * params->h; state->tiles = snewn(state->n, int); state->gap_pos = 0; p = desc; i = 0; for (i = 0; i < state->n; i++) { assert(*p); state->tiles[i] = atoi(p); if (state->tiles[i] == 0) state->gap_pos = i; while (*p && *p != ',') p++; if (*p) p++; /* eat comma */ } assert(!*p); assert(state->tiles[state->gap_pos] == 0); state->completed = state->movecount = 0; state->used_solve = FALSE; return state; } static game_state *dup_game(const game_state *state) { game_state *ret = snew(game_state); ret->w = state->w; ret->h = state->h; ret->n = state->n; ret->tiles = snewn(state->w * state->h, int); memcpy(ret->tiles, state->tiles, state->w * state->h * sizeof(int)); ret->gap_pos = state->gap_pos; ret->completed = state->completed; ret->movecount = state->movecount; ret->used_solve = state->used_solve; return ret; } static void free_game(game_state *state) { sfree(state->tiles); sfree(state); } static char *solve_game(const game_state *state, const game_state *currstate, const char *aux, char **error) { return dupstr("S"); } static int game_can_format_as_text_now(const game_params *params) { return TRUE; } static char *game_text_format(const game_state *state) { char *ret, *p, buf[80]; int x, y, col, maxlen; /* * First work out how many characters we need to display each * number. */ col = sprintf(buf, "%d", state->n-1); /* * Now we know the exact total size of the grid we're going to * produce: it's got h rows, each containing w lots of col, w-1 * spaces and a trailing newline. */ maxlen = state->h * state->w * (col+1); ret = snewn(maxlen+1, char); p = ret; for (y = 0; y < state->h; y++) { for (x = 0; x < state->w; x++) { int v = state->tiles[state->w*y+x]; if (v == 0) sprintf(buf, "%*s", col, ""); else sprintf(buf, "%*d", col, v); memcpy(p, buf, col); p += col; if (x+1 == state->w) *p++ = '\n'; else *p++ = ' '; } } assert(p - ret == maxlen); *p = '\0'; return ret; } static game_ui *new_ui(const game_state *state) { return NULL; } static void free_ui(game_ui *ui) { } static char *encode_ui(const game_ui *ui) { return NULL; } static void decode_ui(game_ui *ui, const char *encoding) { } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { } struct game_drawstate { int started; int w, h, bgcolour; int *tiles; int tilesize; }; static int flip_cursor(int button) { switch (button) { case CURSOR_UP: return CURSOR_DOWN; case CURSOR_DOWN: return CURSOR_UP; case CURSOR_LEFT: return CURSOR_RIGHT; case CURSOR_RIGHT: return CURSOR_LEFT; } return 0; } static void next_move_3x2(int ax, int ay, int bx, int by, int gx, int gy, int *dx, int *dy) { /* When w = 3 and h = 2 and the tile going in the top left corner * is at (ax, ay) and the tile going in the bottom left corner is * at (bx, by) and the blank tile is at (gx, gy), how do you move? */ /* Hard-coded shortest solutions. Sorry. */ static const unsigned char move[120] = { 1,2,0,1,2,2, 2,0,0,2,0,0, 0,0,2,0,2,0, 0,0,0,2,0,2, 2,0,0,0,2,0, 0,3,0,1,1,1, 3,0,3,2,1,2, 2,1,1,0,1,0, 2,1,2,1,0,1, 1,2,0,2,1,2, 0,1,3,1,3,0, 1,3,1,3,0,3, 0,0,3,3,0,0, 0,0,0,1,2,1, 3,0,0,1,1,1, 3,1,1,1,3,0, 1,1,1,1,1,1, 1,3,1,1,3,0, 1,1,3,3,1,3, 1,3,0,0,0,0 }; static const struct { int dx, dy; } d[4] = {{+1,0},{-1,0},{0,+1},{0,-1}}; int ea = 3*ay + ax, eb = 3*by + bx, eg = 3*gy + gx, v; if (eb > ea) --eb; if (eg > ea) --eg; if (eg > eb) --eg; v = move[ea + eb*6 + eg*5*6]; *dx = d[v].dx; *dy = d[v].dy; } static void next_move(int nx, int ny, int ox, int oy, int gx, int gy, int tx, int ty, int w, int *dx, int *dy) { const int to_tile_x = (gx < nx ? +1 : -1); const int to_goal_x = (gx < tx ? +1 : -1); const int gap_x_on_goal_side = ((nx-tx) * (nx-gx) > 0); assert (nx != tx || ny != ty); /* not already in place */ assert (nx != gx || ny != gy); /* not placing the gap */ assert (ty <= ny); /* because we're greedy (and flipping) */ assert (ty <= gy); /* because we're greedy (and flipping) */ /* TODO: define a termination function. Idea: 0 if solved, or * the number of moves to solve the next piece plus the number of * further unsolved pieces times an upper bound on the number of * moves required to solve any piece. If such a function can be * found, we have (termination && (termination => correctness)). * The catch is our temporary disturbance of 2x3 corners. */ /* handles end-of-row, when 3 and 4 are in the top right 2x3 box */ if (tx == w - 2 && ny <= ty + 2 && (nx == tx || nx == tx + 1) && oy <= ty + 2 && (ox == tx || ox == tx + 1) && gy <= ty + 2 && (gx == tx || gx == tx + 1)) { next_move_3x2(oy - ty, tx + 1 - ox, ny - ty, tx + 1 - nx, gy - ty, tx + 1 - gx, dy, dx); *dx *= -1; return; } if (tx == w - 1) { if (ny <= ty + 2 && (nx == tx || nx == tx - 1) && gy <= ty + 2 && (gx == tx || gx == tx - 1)) { next_move_3x2(ny - ty, tx - nx, 0, 1, gy - ty, tx - gx, dy, dx); *dx *= -1; } else if (gy == ty) *dy = +1; else if (nx != tx || ny != ty + 1) { next_move((w - 1) - nx, ny, -1, -1, (w - 1) - gx, gy, 0, ty + 1, -1, dx, dy); *dx *= -1; } else if (gx == nx) *dy = -1; else *dx = +1; return; } /* note that *dy = -1 is unsafe when gy = ty + 1 and gx < tx */ if (gy < ny) if (nx == gx || (gy == ty && gx == tx)) *dy = +1; else if (!gap_x_on_goal_side) *dx = to_tile_x; else if (ny - ty > abs(nx - tx)) *dx = to_tile_x; else *dy = +1; else if (gy == ny) if (nx == tx) /* then we know ny > ty */ if (gx > nx || ny > ty + 1) *dy = -1; /* ... so this is safe */ else *dy = +1; else if (gap_x_on_goal_side) *dx = to_tile_x; else if (gy == ty || (gy == ty + 1 && gx < tx)) *dy = +1; else *dy = -1; else if (nx == tx) /* gy > ny */ if (gx > nx) *dy = -1; else *dx = +1; else if (gx == nx) *dx = to_goal_x; else if (gap_x_on_goal_side) if (gy == ty + 1 && gx < tx) *dx = to_tile_x; else *dy = -1; else if (ny - ty > abs(nx - tx)) *dy = -1; else *dx = to_tile_x; } static int compute_hint(const game_state *state, int *out_x, int *out_y) { /* The overall solving process is this: * 1. Find the next piece to be put in its place * 2. Move it diagonally towards its place * 3. Move it horizontally or vertically towards its place * (Modulo the last two tiles at the end of each row/column) */ int gx = X(state, state->gap_pos); int gy = Y(state, state->gap_pos); int tx, ty, nx, ny, ox, oy, /* {target,next,next2}_{x,y} */ i; int dx = 0, dy = 0; /* 1. Find the next piece * if (there are no more unfinished columns than rows) { * fill the top-most row, left to right * } else { fill the left-most column, top to bottom } */ const int w = state->w, h = state->h, n = w*h; int next_piece = 0, next_piece_2 = 0, solr = 0, solc = 0; int unsolved_rows = h, unsolved_cols = w; assert(out_x); assert(out_y); while (solr < h && solc < w) { int start, step, stop; if (unsolved_cols <= unsolved_rows) start = solr*w + solc, step = 1, stop = unsolved_cols; else start = solr*w + solc, step = w, stop = unsolved_rows; for (i = 0; i < stop; ++i) { const int j = start + i*step; if (state->tiles[j] != j + 1) { next_piece = j + 1; next_piece_2 = next_piece + step; break; } } if (i < stop) break; (unsolved_cols <= unsolved_rows) ? (++solr, --unsolved_rows) : (++solc, --unsolved_cols); } if (next_piece == n) return FALSE; /* 2, 3. Move the next piece towards its place */ /* gx, gy already set */ tx = X(state, next_piece - 1); /* where we're going */ ty = Y(state, next_piece - 1); for (i = 0; i < n && state->tiles[i] != next_piece; ++i); nx = X(state, i); /* where we're at */ ny = Y(state, i); for (i = 0; i < n && state->tiles[i] != next_piece_2; ++i); ox = X(state, i); oy = Y(state, i); if (unsolved_cols <= unsolved_rows) next_move(nx, ny, ox, oy, gx, gy, tx, ty, w, &dx, &dy); else next_move(ny, nx, oy, ox, gy, gx, ty, tx, h, &dy, &dx); assert (dx || dy); *out_x = gx + dx; *out_y = gy + dy; return TRUE; } static char *interpret_move(const game_state *state, game_ui *ui, const game_drawstate *ds, int x, int y, int button) { int cx = X(state, state->gap_pos), nx = cx; int cy = Y(state, state->gap_pos), ny = cy; char buf[80]; button &= ~MOD_MASK; if (button == LEFT_BUTTON) { nx = FROMCOORD(x); ny = FROMCOORD(y); if (nx < 0 || nx >= state->w || ny < 0 || ny >= state->h) return NULL; /* out of bounds */ } else if (IS_CURSOR_MOVE(button)) { static int invert_cursor = -1; if (invert_cursor == -1) { char *env = getenv("FIFTEEN_INVERT_CURSOR"); invert_cursor = (env && (env[0] == 'y' || env[0] == 'Y')); } button = flip_cursor(button); /* the default */ if (invert_cursor) button = flip_cursor(button); /* undoes the first flip */ move_cursor(button, &nx, &ny, state->w, state->h, FALSE); } else if ((button == 'h' || button == 'H') && !state->completed) { if (!compute_hint(state, &nx, &ny)) return NULL; /* shouldn't happen, since ^^we^^checked^^ */ } else return NULL; /* no move */ /* * Any click location should be equal to the gap location * in _precisely_ one coordinate. */ if ((cx == nx) ^ (cy == ny)) { sprintf(buf, "M%d,%d", nx, ny); return dupstr(buf); } return NULL; } static game_state *execute_move(const game_state *from, const char *move) { int gx, gy, dx, dy, ux, uy, up, p; game_state *ret; if (!strcmp(move, "S")) { int i; ret = dup_game(from); /* * Simply replace the grid with a solved one. For this game, * this isn't a useful operation for actually telling the user * what they should have done, but it is useful for * conveniently being able to get hold of a clean state from * which to practise manoeuvres. */ for (i = 0; i < ret->n; i++) ret->tiles[i] = (i+1) % ret->n; ret->gap_pos = ret->n-1; ret->used_solve = TRUE; ret->completed = ret->movecount = 1; return ret; } gx = X(from, from->gap_pos); gy = Y(from, from->gap_pos); if (move[0] != 'M' || sscanf(move+1, "%d,%d", &dx, &dy) != 2 || (dx == gx && dy == gy) || (dx != gx && dy != gy) || dx < 0 || dx >= from->w || dy < 0 || dy >= from->h) return NULL; /* * Find the unit displacement from the original gap * position towards this one. */ ux = (dx < gx ? -1 : dx > gx ? +1 : 0); uy = (dy < gy ? -1 : dy > gy ? +1 : 0); up = C(from, ux, uy); ret = dup_game(from); ret->gap_pos = C(from, dx, dy); assert(ret->gap_pos >= 0 && ret->gap_pos < ret->n); ret->tiles[ret->gap_pos] = 0; for (p = from->gap_pos; p != ret->gap_pos; p += up) { assert(p >= 0 && p < from->n); ret->tiles[p] = from->tiles[p + up]; ret->movecount++; } /* * See if the game has been completed. */ if (!ret->completed) { ret->completed = ret->movecount; for (p = 0; p < ret->n; p++) if (ret->tiles[p] != (p < ret->n-1 ? p+1 : 0)) ret->completed = 0; } return ret; } /* ---------------------------------------------------------------------- * Drawing routines. */ static void game_compute_size(const game_params *params, int tilesize, int *x, int *y) { /* Ick: fake up `ds->tilesize' for macro expansion purposes */ struct { int tilesize; } ads, *ds = &ads; ads.tilesize = tilesize; *x = TILE_SIZE * params->w + 2 * BORDER; *y = TILE_SIZE * params->h + 2 * BORDER; } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { ds->tilesize = tilesize; } static float *game_colours(frontend *fe, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float); int i; game_mkhighlight(fe, ret, COL_BACKGROUND, COL_HIGHLIGHT, COL_LOWLIGHT); for (i = 0; i < 3; i++) ret[COL_TEXT * 3 + i] = 0.0; *ncolours = NCOLOURS; return ret; } static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { struct game_drawstate *ds = snew(struct game_drawstate); int i; ds->started = FALSE; ds->w = state->w; ds->h = state->h; ds->bgcolour = COL_BACKGROUND; ds->tiles = snewn(ds->w*ds->h, int); ds->tilesize = 0; /* haven't decided yet */ for (i = 0; i < ds->w*ds->h; i++) ds->tiles[i] = -1; return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { sfree(ds->tiles); sfree(ds); } static void draw_tile(drawing *dr, game_drawstate *ds, const game_state *state, int x, int y, int tile, int flash_colour) { if (tile == 0) { draw_rect(dr, x, y, TILE_SIZE, TILE_SIZE, flash_colour); } else { int coords[6]; char str[40]; coords[0] = x + TILE_SIZE - 1; coords[1] = y + TILE_SIZE - 1; coords[2] = x + TILE_SIZE - 1; coords[3] = y; coords[4] = x; coords[5] = y + TILE_SIZE - 1; draw_polygon(dr, coords, 3, COL_LOWLIGHT, COL_LOWLIGHT); coords[0] = x; coords[1] = y; draw_polygon(dr, coords, 3, COL_HIGHLIGHT, COL_HIGHLIGHT); draw_rect(dr, x + HIGHLIGHT_WIDTH, y + HIGHLIGHT_WIDTH, TILE_SIZE - 2*HIGHLIGHT_WIDTH, TILE_SIZE - 2*HIGHLIGHT_WIDTH, flash_colour); sprintf(str, "%d", tile); draw_text(dr, x + TILE_SIZE/2, y + TILE_SIZE/2, FONT_VARIABLE, TILE_SIZE/3, ALIGN_VCENTRE | ALIGN_HCENTRE, COL_TEXT, str); } draw_update(dr, x, y, TILE_SIZE, TILE_SIZE); } static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float animtime, float flashtime) { int i, pass, bgcolour; if (flashtime > 0) { int frame = (int)(flashtime / FLASH_FRAME); bgcolour = (frame % 2 ? COL_LOWLIGHT : COL_HIGHLIGHT); } else bgcolour = COL_BACKGROUND; if (!ds->started) { int coords[10]; draw_rect(dr, 0, 0, TILE_SIZE * state->w + 2 * BORDER, TILE_SIZE * state->h + 2 * BORDER, COL_BACKGROUND); draw_update(dr, 0, 0, TILE_SIZE * state->w + 2 * BORDER, TILE_SIZE * state->h + 2 * BORDER); /* * Recessed area containing the whole puzzle. */ coords[0] = COORD(state->w) + HIGHLIGHT_WIDTH - 1; coords[1] = COORD(state->h) + HIGHLIGHT_WIDTH - 1; coords[2] = COORD(state->w) + HIGHLIGHT_WIDTH - 1; coords[3] = COORD(0) - HIGHLIGHT_WIDTH; coords[4] = coords[2] - TILE_SIZE; coords[5] = coords[3] + TILE_SIZE; coords[8] = COORD(0) - HIGHLIGHT_WIDTH; coords[9] = COORD(state->h) + HIGHLIGHT_WIDTH - 1; coords[6] = coords[8] + TILE_SIZE; coords[7] = coords[9] - TILE_SIZE; draw_polygon(dr, coords, 5, COL_HIGHLIGHT, COL_HIGHLIGHT); coords[1] = COORD(0) - HIGHLIGHT_WIDTH; coords[0] = COORD(0) - HIGHLIGHT_WIDTH; draw_polygon(dr, coords, 5, COL_LOWLIGHT, COL_LOWLIGHT); ds->started = TRUE; } /* * Now draw each tile. We do this in two passes to make * animation easy. */ for (pass = 0; pass < 2; pass++) { for (i = 0; i < state->n; i++) { int t, t0; /* * Figure out what should be displayed at this * location. It's either a simple tile, or it's a * transition between two tiles (in which case we say * -1 because it must always be drawn). */ if (oldstate && oldstate->tiles[i] != state->tiles[i]) t = -1; else t = state->tiles[i]; t0 = t; if (ds->bgcolour != bgcolour || /* always redraw when flashing */ ds->tiles[i] != t || ds->tiles[i] == -1 || t == -1) { int x, y; /* * Figure out what to _actually_ draw, and where to * draw it. */ if (t == -1) { int x0, y0, x1, y1; int j; /* * On the first pass, just blank the tile. */ if (pass == 0) { x = COORD(X(state, i)); y = COORD(Y(state, i)); t = 0; } else { float c; t = state->tiles[i]; /* * Don't bother moving the gap; just don't * draw it. */ if (t == 0) continue; /* * Find the coordinates of this tile in the old and * new states. */ x1 = COORD(X(state, i)); y1 = COORD(Y(state, i)); for (j = 0; j < oldstate->n; j++) if (oldstate->tiles[j] == state->tiles[i]) break; assert(j < oldstate->n); x0 = COORD(X(state, j)); y0 = COORD(Y(state, j)); c = (animtime / ANIM_TIME); if (c < 0.0F) c = 0.0F; if (c > 1.0F) c = 1.0F; x = x0 + (int)(c * (x1 - x0)); y = y0 + (int)(c * (y1 - y0)); } } else { if (pass == 0) continue; x = COORD(X(state, i)); y = COORD(Y(state, i)); } draw_tile(dr, ds, state, x, y, t, bgcolour); } ds->tiles[i] = t0; } } ds->bgcolour = bgcolour; /* * Update the status bar. */ { char statusbuf[256]; /* * Don't show the new status until we're also showing the * new _state_ - after the game animation is complete. */ if (oldstate) state = oldstate; if (state->used_solve) sprintf(statusbuf, "Moves since auto-solve: %d", state->movecount - state->completed); else sprintf(statusbuf, "%sMoves: %d", (state->completed ? "COMPLETED! " : ""), (state->completed ? state->completed : state->movecount)); status_bar(dr, statusbuf); } } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return ANIM_TIME; } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { if (!oldstate->completed && newstate->completed && !oldstate->used_solve && !newstate->used_solve) return 2 * FLASH_FRAME; else return 0.0F; } static int game_status(const game_state *state) { return state->completed ? +1 : 0; } static int game_timing_state(const game_state *state, game_ui *ui) { return TRUE; } static void game_print_size(const game_params *params, float *x, float *y) { } static void game_print(drawing *dr, const game_state *state, int tilesize) { } #ifdef COMBINED #define thegame fifteen #endif const struct game thegame = { "Fifteen", "games.fifteen", "fifteen", default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, TRUE, solve_game, TRUE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, PREFERRED_TILE_SIZE, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, FALSE, FALSE, game_print_size, game_print, TRUE, /* wants_statusbar */ FALSE, game_timing_state, 0, /* flags */ }; #ifdef STANDALONE_SOLVER int main(int argc, char **argv) { game_params *params; game_state *state; char *id = NULL, *desc, *err; int grade = FALSE; char *progname = argv[0]; char buf[80]; int limit, x, y, solvable; while (--argc > 0) { char *p = *++argv; if (!strcmp(p, "-v")) { /* solver_show_working = TRUE; */ } else if (!strcmp(p, "-g")) { grade = TRUE; } else if (*p == '-') { fprintf(stderr, "%s: unrecognised option `%s'\n", progname, p); return 1; } else { id = p; } } if (!id) { fprintf(stderr, "usage: %s [-g | -v] \n", argv[0]); return 1; } desc = strchr(id, ':'); if (!desc) { fprintf(stderr, "%s: game id expects a colon in it\n", argv[0]); return 1; } *desc++ = '\0'; params = default_params(); decode_params(params, id); err = validate_desc(params, desc); if (err) { free_params(params); fprintf(stderr, "%s: %s\n", argv[0], err); return 1; } state = new_game(NULL, params, desc); free_params(params); solvable = (PARITY_S(state) == perm_parity(state->tiles, state->n)); if (grade || !solvable) { free_game(state); fputs(solvable ? "Game is solvable" : "Game is unsolvable", grade ? stdout : stderr); return !grade; } for (limit = 5 * state->n * state->n * state->n; limit; --limit) { game_state *next_state; if (!compute_hint(state, &x, &y)) { fprintf(stderr, "couldn't compute next move while solving %s:%s", id, desc); return 1; } printf("Move the space to (%d, %d), moving %d into the space\n", x + 1, y + 1, state->tiles[C(state, x, y)]); sprintf(buf, "M%d,%d", x, y); next_state = execute_move(state, buf); free_game(state); if (!next_state) { fprintf(stderr, "invalid move when solving %s:%s\n", id, desc); return 1; } state = next_state; if (next_state->completed) { free_game(state); return 0; } } free_game(state); fprintf(stderr, "ran out of moves for %s:%s\n", id, desc); return 1; } #endif puzzles-20170606.272beef/emcc.c0000644000175000017500000006342413115373615014755 0ustar simonsimon/* * emcc.c: the C component of an Emscripten-based web/Javascript front * end for Puzzles. * * The Javascript parts of this system live in emcclib.js and * emccpre.js. It also depends on being run in the context of a web * page containing an appropriate collection of bits and pieces (a * canvas, some buttons and links etc), which is generated for each * puzzle by the script html/jspage.pl. */ /* * Further thoughts on possible enhancements: * * - I think it might be feasible to have these JS puzzles permit * loading and saving games in disk files. Saving would be done by * constructing a data: URI encapsulating the save file, and then * telling the browser to visit that URI with the effect that it * would naturally pop up a 'where would you like to save this' * dialog box. Loading, more or less similarly, might be feasible * by using the DOM File API to ask the user to select a file and * permit us to see its contents. * * - I should think about whether these webified puzzles can support * touchscreen-based tablet browsers (assuming there are any that * can cope with the reasonably modern JS and run it fast enough to * be worthwhile). * * - think about making use of localStorage. It might be useful to * let the user save games into there as an alternative to disk * files - disk files are all very well for getting the save right * out of your browser to (e.g.) email to me as a bug report, but * for just resuming a game you were in the middle of, you'd * probably rather have a nice simple 'quick save' and 'quick load' * button pair. Also, that might be a useful place to store * preferences, if I ever get round to writing a preferences UI. * * - some CSS to make the button bar and configuration dialogs a * little less ugly would probably not go amiss. * * - this is a downright silly idea, but it does occur to me that if * I were to write a PDF output driver for the Puzzles printing * API, then I might be able to implement a sort of 'printing' * feature in this front end, using data: URIs again. (Ask the user * exactly what they want printed, then construct an appropriate * PDF and embed it in a gigantic data: URI. Then they can print * that using whatever they normally use to print PDFs!) */ #include #include #include #include #include "puzzles.h" /* * Extern references to Javascript functions provided in emcclib.js. */ extern void js_debug(const char *); extern void js_error_box(const char *message); extern void js_remove_type_dropdown(void); extern void js_remove_solve_button(void); extern void js_add_preset(int menuid, const char *name, int value); extern int js_add_preset_submenu(int menuid, const char *name); extern int js_get_selected_preset(void); extern void js_select_preset(int n); extern void js_get_date_64(unsigned *p); extern void js_update_permalinks(const char *desc, const char *seed); extern void js_enable_undo_redo(int undo, int redo); extern void js_activate_timer(); extern void js_deactivate_timer(); extern void js_canvas_start_draw(void); extern void js_canvas_draw_update(int x, int y, int w, int h); extern void js_canvas_end_draw(void); extern void js_canvas_draw_rect(int x, int y, int w, int h, const char *colour); extern void js_canvas_clip_rect(int x, int y, int w, int h); extern void js_canvas_unclip(void); extern void js_canvas_draw_line(float x1, float y1, float x2, float y2, int width, const char *colour); extern void js_canvas_draw_poly(int *points, int npoints, const char *fillcolour, const char *outlinecolour); extern void js_canvas_draw_circle(int x, int y, int r, const char *fillcolour, const char *outlinecolour); extern int js_canvas_find_font_midpoint(int height, const char *fontptr); extern void js_canvas_draw_text(int x, int y, int halign, const char *colptr, const char *fontptr, const char *text); extern int js_canvas_new_blitter(int w, int h); extern void js_canvas_free_blitter(int id); extern void js_canvas_copy_to_blitter(int id, int x, int y, int w, int h); extern void js_canvas_copy_from_blitter(int id, int x, int y, int w, int h); extern void js_canvas_make_statusbar(void); extern void js_canvas_set_statusbar(const char *text); extern void js_canvas_set_size(int w, int h); extern void js_dialog_init(const char *title); extern void js_dialog_string(int i, const char *title, const char *initvalue); extern void js_dialog_choices(int i, const char *title, const char *choicelist, int initvalue); extern void js_dialog_boolean(int i, const char *title, int initvalue); extern void js_dialog_launch(void); extern void js_dialog_cleanup(void); extern void js_focus_canvas(void); /* * Call JS to get the date, and use that to initialise our random * number generator to invent the first game seed. */ void get_random_seed(void **randseed, int *randseedsize) { unsigned *ret = snewn(2, unsigned); js_get_date_64(ret); *randseed = ret; *randseedsize = 2*sizeof(unsigned); } /* * Fatal error, called in cases of complete despair such as when * malloc() has returned NULL. */ void fatal(char *fmt, ...) { char buf[512]; va_list ap; strcpy(buf, "puzzle fatal error: "); va_start(ap, fmt); vsnprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), fmt, ap); va_end(ap); js_error_box(buf); } void debug_printf(char *fmt, ...) { char buf[512]; va_list ap; va_start(ap, fmt); vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); js_debug(buf); } /* * Helper function that makes it easy to test strings that might be * NULL. */ int strnullcmp(const char *a, const char *b) { if (a == NULL || b == NULL) return a != NULL ? +1 : b != NULL ? -1 : 0; return strcmp(a, b); } /* * HTMLish names for the colours allocated by the puzzle. */ char **colour_strings; int ncolours; /* * The global midend object. */ midend *me; /* ---------------------------------------------------------------------- * Timing functions. */ int timer_active = FALSE; void deactivate_timer(frontend *fe) { js_deactivate_timer(); timer_active = FALSE; } void activate_timer(frontend *fe) { if (!timer_active) { js_activate_timer(); timer_active = TRUE; } } void timer_callback(double tplus) { if (timer_active) midend_timer(me, tplus); } /* ---------------------------------------------------------------------- * Helper functions to resize the canvas, and variables to remember * its size for other functions (e.g. trimming blitter rectangles). */ static int canvas_w, canvas_h; /* Called when we resize as a result of changing puzzle settings */ static void resize(void) { int w, h; w = h = INT_MAX; midend_size(me, &w, &h, FALSE); js_canvas_set_size(w, h); canvas_w = w; canvas_h = h; } /* Called from JS when the user uses the resize handle */ void resize_puzzle(int w, int h) { midend_size(me, &w, &h, TRUE); if (canvas_w != w || canvas_h != h) { js_canvas_set_size(w, h); canvas_w = w; canvas_h = h; midend_force_redraw(me); } } /* Called from JS when the user uses the restore button */ void restore_puzzle_size(int w, int h) { midend_reset_tilesize(me); resize(); midend_force_redraw(me); } /* * HTML doesn't give us a default frontend colour of its own, so we * just make up a lightish grey ourselves. */ void frontend_default_colour(frontend *fe, float *output) { output[0] = output[1] = output[2] = 0.9F; } /* * Helper function called from all over the place to ensure the undo * and redo buttons get properly enabled and disabled after every move * or undo or new-game event. */ static void update_undo_redo(void) { js_enable_undo_redo(midend_can_undo(me), midend_can_redo(me)); } /* * Mouse event handlers called from JS. */ void mousedown(int x, int y, int button) { button = (button == 0 ? LEFT_BUTTON : button == 1 ? MIDDLE_BUTTON : RIGHT_BUTTON); midend_process_key(me, x, y, button); update_undo_redo(); } void mouseup(int x, int y, int button) { button = (button == 0 ? LEFT_RELEASE : button == 1 ? MIDDLE_RELEASE : RIGHT_RELEASE); midend_process_key(me, x, y, button); update_undo_redo(); } void mousemove(int x, int y, int buttons) { int button = (buttons & 2 ? MIDDLE_DRAG : buttons & 4 ? RIGHT_DRAG : LEFT_DRAG); midend_process_key(me, x, y, button); update_undo_redo(); } /* * Keyboard handler called from JS. */ void key(int keycode, int charcode, const char *key, const char *chr, int shift, int ctrl) { int keyevent = -1; if (!strnullcmp(key, "Backspace") || !strnullcmp(key, "Del") || keycode == 8 || keycode == 46) { keyevent = 127; /* Backspace / Delete */ } else if (!strnullcmp(key, "Enter") || keycode == 13) { keyevent = 13; /* return */ } else if (!strnullcmp(key, "Left") || keycode == 37) { keyevent = CURSOR_LEFT; } else if (!strnullcmp(key, "Up") || keycode == 38) { keyevent = CURSOR_UP; } else if (!strnullcmp(key, "Right") || keycode == 39) { keyevent = CURSOR_RIGHT; } else if (!strnullcmp(key, "Down") || keycode == 40) { keyevent = CURSOR_DOWN; } else if (!strnullcmp(key, "End") || keycode == 35) { /* * We interpret Home, End, PgUp and PgDn as numeric keypad * controls regardless of whether they're the ones on the * numeric keypad (since we can't tell). The effect of * this should only be that the non-numeric-pad versions * of those keys generate directions in 8-way movement * puzzles like Cube and Inertia. */ keyevent = MOD_NUM_KEYPAD | '1'; } else if (!strnullcmp(key, "PageDown") || keycode==34) { keyevent = MOD_NUM_KEYPAD | '3'; } else if (!strnullcmp(key, "Home") || keycode==36) { keyevent = MOD_NUM_KEYPAD | '7'; } else if (!strnullcmp(key, "PageUp") || keycode==33) { keyevent = MOD_NUM_KEYPAD | '9'; } else if (chr && chr[0] && !chr[1]) { keyevent = chr[0] & 0xFF; } else if (keycode >= 96 && keycode < 106) { keyevent = MOD_NUM_KEYPAD | ('0' + keycode - 96); } else if (keycode >= 65 && keycode <= 90) { keyevent = keycode + (shift ? 0 : 32); } else if (keycode >= 48 && keycode <= 57) { keyevent = keycode; } else if (keycode == 32) { /* space / CURSOR_SELECT2 */ keyevent = keycode; } if (keyevent >= 0) { if (shift && keyevent >= 0x100) keyevent |= MOD_SHFT; if (ctrl) { if (keyevent >= 0x100) keyevent |= MOD_CTRL; else keyevent &= 0x1F; } midend_process_key(me, 0, 0, keyevent); update_undo_redo(); } } /* * Helper function called from several places to update the permalinks * whenever a new game is created. */ static void update_permalinks(void) { char *desc, *seed; desc = midend_get_game_id(me); seed = midend_get_random_seed(me); js_update_permalinks(desc, seed); sfree(desc); sfree(seed); } /* * Callback from the midend when the game ids change, so we can update * the permalinks. */ static void ids_changed(void *ignored) { update_permalinks(); } /* ---------------------------------------------------------------------- * Implementation of the drawing API by calling Javascript canvas * drawing functions. (Well, half of it; the other half is on the JS * side.) */ static void js_start_draw(void *handle) { js_canvas_start_draw(); } static void js_clip(void *handle, int x, int y, int w, int h) { js_canvas_clip_rect(x, y, w, h); } static void js_unclip(void *handle) { js_canvas_unclip(); } static void js_draw_text(void *handle, int x, int y, int fonttype, int fontsize, int align, int colour, char *text) { char fontstyle[80]; int halign; sprintf(fontstyle, "%dpx %s", fontsize, fonttype == FONT_FIXED ? "monospace" : "sans-serif"); if (align & ALIGN_VCENTRE) y += js_canvas_find_font_midpoint(fontsize, fontstyle); if (align & ALIGN_HCENTRE) halign = 1; else if (align & ALIGN_HRIGHT) halign = 2; else halign = 0; js_canvas_draw_text(x, y, halign, colour_strings[colour], fontstyle, text); } static void js_draw_rect(void *handle, int x, int y, int w, int h, int colour) { js_canvas_draw_rect(x, y, w, h, colour_strings[colour]); } static void js_draw_line(void *handle, int x1, int y1, int x2, int y2, int colour) { js_canvas_draw_line(x1, y1, x2, y2, 1, colour_strings[colour]); } static void js_draw_thick_line(void *handle, float thickness, float x1, float y1, float x2, float y2, int colour) { js_canvas_draw_line(x1, y1, x2, y2, thickness, colour_strings[colour]); } static void js_draw_poly(void *handle, int *coords, int npoints, int fillcolour, int outlinecolour) { js_canvas_draw_poly(coords, npoints, fillcolour >= 0 ? colour_strings[fillcolour] : NULL, colour_strings[outlinecolour]); } static void js_draw_circle(void *handle, int cx, int cy, int radius, int fillcolour, int outlinecolour) { js_canvas_draw_circle(cx, cy, radius, fillcolour >= 0 ? colour_strings[fillcolour] : NULL, colour_strings[outlinecolour]); } struct blitter { int id; /* allocated on the js side */ int w, h; /* easier to retain here */ }; static blitter *js_blitter_new(void *handle, int w, int h) { blitter *bl = snew(blitter); bl->w = w; bl->h = h; bl->id = js_canvas_new_blitter(w, h); return bl; } static void js_blitter_free(void *handle, blitter *bl) { js_canvas_free_blitter(bl->id); sfree(bl); } static void trim_rect(int *x, int *y, int *w, int *h) { int x0, x1, y0, y1; /* * Reduce the size of the copied rectangle to stop it going * outside the bounds of the canvas. */ /* Transform from x,y,w,h form into coordinates of all edges */ x0 = *x; y0 = *y; x1 = *x + *w; y1 = *y + *h; /* Clip each coordinate at both extremes of the canvas */ x0 = (x0 < 0 ? 0 : x0 > canvas_w ? canvas_w : x0); x1 = (x1 < 0 ? 0 : x1 > canvas_w ? canvas_w : x1); y0 = (y0 < 0 ? 0 : y0 > canvas_h ? canvas_h : y0); y1 = (y1 < 0 ? 0 : y1 > canvas_h ? canvas_h : y1); /* Transform back into x,y,w,h to return */ *x = x0; *y = y0; *w = x1 - x0; *h = y1 - y0; } static void js_blitter_save(void *handle, blitter *bl, int x, int y) { int w = bl->w, h = bl->h; trim_rect(&x, &y, &w, &h); if (w > 0 && h > 0) js_canvas_copy_to_blitter(bl->id, x, y, w, h); } static void js_blitter_load(void *handle, blitter *bl, int x, int y) { int w = bl->w, h = bl->h; trim_rect(&x, &y, &w, &h); if (w > 0 && h > 0) js_canvas_copy_from_blitter(bl->id, x, y, w, h); } static void js_draw_update(void *handle, int x, int y, int w, int h) { trim_rect(&x, &y, &w, &h); if (w > 0 && h > 0) js_canvas_draw_update(x, y, w, h); } static void js_end_draw(void *handle) { js_canvas_end_draw(); } static void js_status_bar(void *handle, char *text) { js_canvas_set_statusbar(text); } static char *js_text_fallback(void *handle, const char *const *strings, int nstrings) { return dupstr(strings[0]); /* Emscripten has no trouble with UTF-8 */ } const struct drawing_api js_drawing = { js_draw_text, js_draw_rect, js_draw_line, js_draw_poly, js_draw_circle, js_draw_update, js_clip, js_unclip, js_start_draw, js_end_draw, js_status_bar, js_blitter_new, js_blitter_free, js_blitter_save, js_blitter_load, NULL, NULL, NULL, NULL, NULL, NULL, /* {begin,end}_{doc,page,puzzle} */ NULL, NULL, /* line_width, line_dotted */ js_text_fallback, js_draw_thick_line, }; /* ---------------------------------------------------------------------- * Presets and game-configuration dialog support. */ static game_params **presets; static int npresets; int have_presets_dropdown; void populate_js_preset_menu(int menuid, struct preset_menu *menu) { int i; for (i = 0; i < menu->n_entries; i++) { struct preset_menu_entry *entry = &menu->entries[i]; if (entry->params) { presets[entry->id] = entry->params; js_add_preset(menuid, entry->title, entry->id); } else { int js_submenu = js_add_preset_submenu(menuid, entry->title); populate_js_preset_menu(js_submenu, entry->submenu); } } } void select_appropriate_preset(void) { if (have_presets_dropdown) { int preset = midend_which_preset(me); js_select_preset(preset < 0 ? -1 : preset); } } static config_item *cfg = NULL; static int cfg_which; /* * Set up a dialog box. This is pretty easy on the C side; most of the * work is done in JS. */ static void cfg_start(int which) { char *title; int i; cfg = midend_get_config(me, which, &title); cfg_which = which; js_dialog_init(title); sfree(title); for (i = 0; cfg[i].type != C_END; i++) { switch (cfg[i].type) { case C_STRING: js_dialog_string(i, cfg[i].name, cfg[i].sval); break; case C_BOOLEAN: js_dialog_boolean(i, cfg[i].name, cfg[i].ival); break; case C_CHOICES: js_dialog_choices(i, cfg[i].name, cfg[i].sval, cfg[i].ival); break; } } js_dialog_launch(); } /* * Callbacks from JS when the OK button is clicked, to return the * final state of each control. */ void dlg_return_sval(int index, const char *val) { sfree(cfg[index].sval); cfg[index].sval = dupstr(val); } void dlg_return_ival(int index, int val) { cfg[index].ival = val; } /* * Called when the user clicks OK or Cancel. use_results will be TRUE * or FALSE respectively, in those cases. We terminate the dialog box, * unless the user selected an invalid combination of parameters. */ static void cfg_end(int use_results) { if (use_results) { /* * User hit OK. */ char *err = midend_set_config(me, cfg_which, cfg); if (err) { /* * The settings were unacceptable, so leave the config box * open for the user to adjust them and try again. */ js_error_box(err); } else { /* * New settings are fine; start a new game and close the * dialog. */ select_appropriate_preset(); midend_new_game(me); resize(); midend_redraw(me); free_cfg(cfg); js_dialog_cleanup(); } } else { /* * User hit Cancel. Close the dialog, but also we must still * reselect the right element of the dropdown list. * * (Because: imagine you have a preset selected, and then you * select Custom from the list, but change your mind and hit * Esc. The Custom option will now still be selected in the * list, whereas obviously it should show the preset you still * _actually_ have selected. Worse still, it'll be the visible * rather than invisible Custom option - see the comment in * js_add_preset in emcclib.js - so you won't even be able to * select Custom without a faffy workaround.) */ select_appropriate_preset(); free_cfg(cfg); js_dialog_cleanup(); } } /* ---------------------------------------------------------------------- * Called from JS when a command is given to the puzzle by clicking a * button or control of some sort. */ void command(int n) { switch (n) { case 0: /* specific game ID */ cfg_start(CFG_DESC); break; case 1: /* random game seed */ cfg_start(CFG_SEED); break; case 2: /* game parameter dropdown changed */ { int i = js_get_selected_preset(); if (i < 0) { /* * The user selected 'Custom', so launch the config * box. */ if (thegame.can_configure) /* (double-check just in case) */ cfg_start(CFG_SETTINGS); } else { /* * The user selected a preset, so just switch straight * to that. */ assert(i < npresets); midend_set_params(me, presets[i]); midend_new_game(me); resize(); midend_redraw(me); update_undo_redo(); js_focus_canvas(); select_appropriate_preset(); } } break; case 3: /* OK clicked in a config box */ cfg_end(TRUE); update_undo_redo(); break; case 4: /* Cancel clicked in a config box */ cfg_end(FALSE); update_undo_redo(); break; case 5: /* New Game */ midend_process_key(me, 0, 0, 'n'); update_undo_redo(); js_focus_canvas(); break; case 6: /* Restart */ midend_restart_game(me); update_undo_redo(); js_focus_canvas(); break; case 7: /* Undo */ midend_process_key(me, 0, 0, 'u'); update_undo_redo(); js_focus_canvas(); break; case 8: /* Redo */ midend_process_key(me, 0, 0, 'r'); update_undo_redo(); js_focus_canvas(); break; case 9: /* Solve */ if (thegame.can_solve) { char *msg = midend_solve(me); if (msg) js_error_box(msg); } update_undo_redo(); js_focus_canvas(); break; } } /* ---------------------------------------------------------------------- * Setup function called at page load time. It's called main() because * that's the most convenient thing in Emscripten, but it's not main() * in the usual sense of bounding the program's entire execution. * Instead, this function returns once the initial puzzle is set up * and working, and everything thereafter happens by means of JS event * handlers sending us callbacks. */ int main(int argc, char **argv) { char *param_err; float *colours; int i; /* * Instantiate a midend. */ me = midend_new(NULL, &thegame, &js_drawing, NULL); /* * Chuck in the HTML fragment ID if we have one (trimming the * leading # off the front first). If that's invalid, we retain * the error message and will display it at the end, after setting * up a random puzzle as usual. */ if (argc > 1 && argv[1][0] == '#' && argv[1][1] != '\0') param_err = midend_game_id(me, argv[1] + 1); else param_err = NULL; /* * Create either a random game or the specified one, and set the * canvas size appropriately. */ midend_new_game(me); resize(); /* * Create a status bar, if needed. */ if (midend_wants_statusbar(me)) js_canvas_make_statusbar(); /* * Set up the game-type dropdown with presets and/or the Custom * option. */ { struct preset_menu *menu = midend_get_presets(me, &npresets); presets = snewn(npresets, game_params *); for (i = 0; i < npresets; i++) presets[i] = NULL; populate_js_preset_menu(0, menu); if (thegame.can_configure) js_add_preset(0, "Custom", -1); have_presets_dropdown = TRUE; /* * Now ensure the appropriate element of the presets menu * starts off selected, in case it isn't the first one in the * list (e.g. Slant). */ select_appropriate_preset(); } /* * Remove the Solve button if the game doesn't support it. */ if (!thegame.can_solve) js_remove_solve_button(); /* * Retrieve the game's colours, and convert them into #abcdef type * hex ID strings. */ colours = midend_colours(me, &ncolours); colour_strings = snewn(ncolours, char *); for (i = 0; i < ncolours; i++) { char col[40]; sprintf(col, "#%02x%02x%02x", (unsigned)(0.5 + 255 * colours[i*3+0]), (unsigned)(0.5 + 255 * colours[i*3+1]), (unsigned)(0.5 + 255 * colours[i*3+2])); colour_strings[i] = dupstr(col); } /* * Request notification when the game ids change (e.g. if the user * presses 'n', and also when Mines supersedes its game * description), so that we can proactively update the permalink. */ midend_request_id_changes(me, ids_changed, NULL); /* * Draw the puzzle's initial state, and set up the permalinks and * undo/redo greying out. */ midend_redraw(me); update_permalinks(); update_undo_redo(); /* * If we were given an erroneous game ID in argv[1], now's the * time to put up the error box about it, after we've fully set up * a random puzzle. Then when the user clicks 'ok', we have a * puzzle for them. */ if (param_err) js_error_box(param_err); /* * Done. Return to JS, and await callbacks! */ return 0; } puzzles-20170606.272beef/dsf.c0000644000175000017500000001216613115373615014617 0ustar simonsimon/* * dsf.c: some functions to handle a disjoint set forest, * which is a data structure useful in any solver which has to * worry about avoiding closed loops. */ #include #include #include "puzzles.h" /*void print_dsf(int *dsf, int size) { int *printed_elements = snewn(size, int); int *equal_elements = snewn(size, int); int *inverse_elements = snewn(size, int); int printed_count = 0, equal_count, inverse_count; int i, n, inverse; memset(printed_elements, -1, sizeof(int) * size); while (1) { equal_count = 0; inverse_count = 0; for (i = 0; i < size; ++i) { if (!memchr(printed_elements, i, sizeof(int) * size)) break; } if (i == size) goto done; i = dsf_canonify(dsf, i); for (n = 0; n < size; ++n) { if (edsf_canonify(dsf, n, &inverse) == i) { if (inverse) inverse_elements[inverse_count++] = n; else equal_elements[equal_count++] = n; } } for (n = 0; n < equal_count; ++n) { fprintf(stderr, "%d ", equal_elements[n]); printed_elements[printed_count++] = equal_elements[n]; } if (inverse_count) { fprintf(stderr, "!= "); for (n = 0; n < inverse_count; ++n) { fprintf(stderr, "%d ", inverse_elements[n]); printed_elements[printed_count++] = inverse_elements[n]; } } fprintf(stderr, "\n"); } done: sfree(printed_elements); sfree(equal_elements); sfree(inverse_elements); }*/ void dsf_init(int *dsf, int size) { int i; for (i = 0; i < size; i++) dsf[i] = 6; /* Bottom bit of each element of this array stores whether that * element is opposite to its parent, which starts off as * false. Second bit of each element stores whether that element * is the root of its tree or not. If it's not the root, the * remaining 30 bits are the parent, otherwise the remaining 30 * bits are the number of elements in the tree. */ } int *snew_dsf(int size) { int *ret; ret = snewn(size, int); dsf_init(ret, size); /*print_dsf(ret, size); */ return ret; } int dsf_canonify(int *dsf, int index) { return edsf_canonify(dsf, index, NULL); } void dsf_merge(int *dsf, int v1, int v2) { edsf_merge(dsf, v1, v2, FALSE); } int dsf_size(int *dsf, int index) { return dsf[dsf_canonify(dsf, index)] >> 2; } int edsf_canonify(int *dsf, int index, int *inverse_return) { int start_index = index, canonical_index; int inverse = 0; /* fprintf(stderr, "dsf = %p\n", dsf); */ /* fprintf(stderr, "Canonify %2d\n", index); */ assert(index >= 0); /* Find the index of the canonical element of the 'equivalence class' of * which start_index is a member, and figure out whether start_index is the * same as or inverse to that. */ while ((dsf[index] & 2) == 0) { inverse ^= (dsf[index] & 1); index = dsf[index] >> 2; /* fprintf(stderr, "index = %2d, ", index); */ /* fprintf(stderr, "inverse = %d\n", inverse); */ } canonical_index = index; if (inverse_return) *inverse_return = inverse; /* Update every member of this 'equivalence class' to point directly at the * canonical member. */ index = start_index; while (index != canonical_index) { int nextindex = dsf[index] >> 2; int nextinverse = inverse ^ (dsf[index] & 1); dsf[index] = (canonical_index << 2) | inverse; inverse = nextinverse; index = nextindex; } assert(inverse == 0); /* fprintf(stderr, "Return %2d\n", index); */ return index; } void edsf_merge(int *dsf, int v1, int v2, int inverse) { int i1, i2; /* fprintf(stderr, "dsf = %p\n", dsf); */ /* fprintf(stderr, "Merge [%2d,%2d], %d\n", v1, v2, inverse); */ v1 = edsf_canonify(dsf, v1, &i1); assert(dsf[v1] & 2); inverse ^= i1; v2 = edsf_canonify(dsf, v2, &i2); assert(dsf[v2] & 2); inverse ^= i2; /* fprintf(stderr, "Doing [%2d,%2d], %d\n", v1, v2, inverse); */ if (v1 == v2) assert(!inverse); else { assert(inverse == 0 || inverse == 1); /* * We always make the smaller of v1 and v2 the new canonical * element. This ensures that the canonical element of any * class in this structure is always the first element in * it. 'Keen' depends critically on this property. * * (Jonas Koelker previously had this code choosing which * way round to connect the trees by examining the sizes of * the classes being merged, so that the root of the * larger-sized class became the new root. This gives better * asymptotic performance, but I've changed it to do it this * way because I like having a deterministic canonical * element.) */ if (v1 > v2) { int v3 = v1; v1 = v2; v2 = v3; } dsf[v1] += (dsf[v2] >> 2) << 2; dsf[v2] = (v1 << 2) | !!inverse; } v2 = edsf_canonify(dsf, v2, &i2); assert(v2 == v1); assert(i2 == inverse); /* fprintf(stderr, "dsf[%2d] = %2d\n", v2, dsf[v2]); */ } puzzles-20170606.272beef/drawing.c0000644000175000017500000002166513115373615015502 0ustar simonsimon/* * drawing.c: Intermediary between the drawing interface as * presented to the back end, and that implemented by the front * end. * * Mostly just looks up calls in a vtable and passes them through * unchanged. However, on the printing side it tracks print colours * so the front end API doesn't have to. * * FIXME: * * - I'd _like_ to do automatic draw_updates, but it's a pain for * draw_text in particular. I'd have to invent a front end API * which retrieved the text bounds. * + that might allow me to do the alignment centrally as well? * * perhaps not, because PS can't return this information, * so there would have to be a special case for it. * + however, that at least doesn't stand in the way of using * the text bounds for draw_update, because PS doesn't need * draw_update since it's printing-only. Any _interactive_ * drawing API couldn't get away with refusing to tell you * what parts of the screen a text draw had covered, because * you would inevitably need to erase it later on. */ #include #include #include #include #include #include "puzzles.h" struct print_colour { int hatch; int hatch_when; /* 0=never 1=only-in-b&w 2=always */ float r, g, b; float grey; }; struct drawing { const drawing_api *api; void *handle; struct print_colour *colours; int ncolours, coloursize; float scale; /* `me' is only used in status_bar(), so print-oriented instances of * this may set it to NULL. */ midend *me; char *laststatus; }; drawing *drawing_new(const drawing_api *api, midend *me, void *handle) { drawing *dr = snew(drawing); dr->api = api; dr->handle = handle; dr->colours = NULL; dr->ncolours = dr->coloursize = 0; dr->scale = 1.0F; dr->me = me; dr->laststatus = NULL; return dr; } void drawing_free(drawing *dr) { sfree(dr->laststatus); sfree(dr->colours); sfree(dr); } void draw_text(drawing *dr, int x, int y, int fonttype, int fontsize, int align, int colour, char *text) { dr->api->draw_text(dr->handle, x, y, fonttype, fontsize, align, colour, text); } void draw_rect(drawing *dr, int x, int y, int w, int h, int colour) { dr->api->draw_rect(dr->handle, x, y, w, h, colour); } void draw_line(drawing *dr, int x1, int y1, int x2, int y2, int colour) { dr->api->draw_line(dr->handle, x1, y1, x2, y2, colour); } void draw_thick_line(drawing *dr, float thickness, float x1, float y1, float x2, float y2, int colour) { if (dr->api->draw_thick_line) { dr->api->draw_thick_line(dr->handle, thickness, x1, y1, x2, y2, colour); } else { /* We'll fake it up with a filled polygon. The tweak to the * thickness empirically compensates for rounding errors, because * polygon rendering uses integer coordinates. */ float len = sqrt((x2 - x1)*(x2 - x1) + (y2 - y1)*(y2 - y1)); float tvhatx = (x2 - x1)/len * (thickness/2 - 0.2); float tvhaty = (y2 - y1)/len * (thickness/2 - 0.2); int p[8]; p[0] = x1 - tvhaty; p[1] = y1 + tvhatx; p[2] = x2 - tvhaty; p[3] = y2 + tvhatx; p[4] = x2 + tvhaty; p[5] = y2 - tvhatx; p[6] = x1 + tvhaty; p[7] = y1 - tvhatx; dr->api->draw_polygon(dr->handle, p, 4, colour, colour); } } void draw_polygon(drawing *dr, int *coords, int npoints, int fillcolour, int outlinecolour) { dr->api->draw_polygon(dr->handle, coords, npoints, fillcolour, outlinecolour); } void draw_circle(drawing *dr, int cx, int cy, int radius, int fillcolour, int outlinecolour) { dr->api->draw_circle(dr->handle, cx, cy, radius, fillcolour, outlinecolour); } void draw_update(drawing *dr, int x, int y, int w, int h) { if (dr->api->draw_update) dr->api->draw_update(dr->handle, x, y, w, h); } void clip(drawing *dr, int x, int y, int w, int h) { dr->api->clip(dr->handle, x, y, w, h); } void unclip(drawing *dr) { dr->api->unclip(dr->handle); } void start_draw(drawing *dr) { dr->api->start_draw(dr->handle); } void end_draw(drawing *dr) { dr->api->end_draw(dr->handle); } char *text_fallback(drawing *dr, const char *const *strings, int nstrings) { int i; /* * If the drawing implementation provides one of these, use it. */ if (dr && dr->api->text_fallback) return dr->api->text_fallback(dr->handle, strings, nstrings); /* * Otherwise, do the simple thing and just pick the first string * that fits in plain ASCII. It will then need no translation * out of UTF-8. */ for (i = 0; i < nstrings; i++) { const char *p; for (p = strings[i]; *p; p++) if (*p & 0x80) break; if (!*p) return dupstr(strings[i]); } /* * The caller was responsible for making sure _some_ string in * the list was in plain ASCII. */ assert(!"Should never get here"); return NULL; /* placate optimiser */ } void status_bar(drawing *dr, char *text) { char *rewritten; if (!dr->api->status_bar) return; assert(dr->me); rewritten = midend_rewrite_statusbar(dr->me, text); if (!dr->laststatus || strcmp(rewritten, dr->laststatus)) { dr->api->status_bar(dr->handle, rewritten); sfree(dr->laststatus); dr->laststatus = rewritten; } else { sfree(rewritten); } } blitter *blitter_new(drawing *dr, int w, int h) { return dr->api->blitter_new(dr->handle, w, h); } void blitter_free(drawing *dr, blitter *bl) { dr->api->blitter_free(dr->handle, bl); } void blitter_save(drawing *dr, blitter *bl, int x, int y) { dr->api->blitter_save(dr->handle, bl, x, y); } void blitter_load(drawing *dr, blitter *bl, int x, int y) { dr->api->blitter_load(dr->handle, bl, x, y); } void print_begin_doc(drawing *dr, int pages) { dr->api->begin_doc(dr->handle, pages); } void print_begin_page(drawing *dr, int number) { dr->api->begin_page(dr->handle, number); } void print_begin_puzzle(drawing *dr, float xm, float xc, float ym, float yc, int pw, int ph, float wmm, float scale) { dr->scale = scale; dr->ncolours = 0; dr->api->begin_puzzle(dr->handle, xm, xc, ym, yc, pw, ph, wmm); } void print_end_puzzle(drawing *dr) { dr->api->end_puzzle(dr->handle); dr->scale = 1.0F; } void print_end_page(drawing *dr, int number) { dr->api->end_page(dr->handle, number); } void print_end_doc(drawing *dr) { dr->api->end_doc(dr->handle); } void print_get_colour(drawing *dr, int colour, int printing_in_colour, int *hatch, float *r, float *g, float *b) { assert(colour >= 0 && colour < dr->ncolours); if (dr->colours[colour].hatch_when == 2 || (dr->colours[colour].hatch_when == 1 && !printing_in_colour)) { *hatch = dr->colours[colour].hatch; } else { *hatch = -1; if (printing_in_colour) { *r = dr->colours[colour].r; *g = dr->colours[colour].g; *b = dr->colours[colour].b; } else { *r = *g = *b = dr->colours[colour].grey; } } } static int print_generic_colour(drawing *dr, float r, float g, float b, float grey, int hatch, int hatch_when) { if (dr->ncolours >= dr->coloursize) { dr->coloursize = dr->ncolours + 16; dr->colours = sresize(dr->colours, dr->coloursize, struct print_colour); } dr->colours[dr->ncolours].hatch = hatch; dr->colours[dr->ncolours].hatch_when = hatch_when; dr->colours[dr->ncolours].r = r; dr->colours[dr->ncolours].g = g; dr->colours[dr->ncolours].b = b; dr->colours[dr->ncolours].grey = grey; return dr->ncolours++; } int print_mono_colour(drawing *dr, int grey) { return print_generic_colour(dr, grey, grey, grey, grey, -1, 0); } int print_grey_colour(drawing *dr, float grey) { return print_generic_colour(dr, grey, grey, grey, grey, -1, 0); } int print_hatched_colour(drawing *dr, int hatch) { return print_generic_colour(dr, 0, 0, 0, 0, hatch, 2); } int print_rgb_mono_colour(drawing *dr, float r, float g, float b, int grey) { return print_generic_colour(dr, r, g, b, grey, -1, 0); } int print_rgb_grey_colour(drawing *dr, float r, float g, float b, float grey) { return print_generic_colour(dr, r, g, b, grey, -1, 0); } int print_rgb_hatched_colour(drawing *dr, float r, float g, float b, int hatch) { return print_generic_colour(dr, r, g, b, 0, hatch, 1); } void print_line_width(drawing *dr, int width) { /* * I don't think it's entirely sensible to have line widths be * entirely relative to the puzzle size; there is a point * beyond which lines are just _stupidly_ thick. On the other * hand, absolute line widths aren't particularly nice either * because they start to feel a bit feeble at really large * scales. * * My experimental answer is to scale line widths as the * _square root_ of the main puzzle scale. Double the puzzle * size, and the line width multiplies by 1.4. */ dr->api->line_width(dr->handle, (float)sqrt(dr->scale) * width); } void print_line_dotted(drawing *dr, int dotted) { dr->api->line_dotted(dr->handle, dotted); } puzzles-20170606.272beef/dominosa.c0000644000175000017500000014601113115373615015651 0ustar simonsimon/* * dominosa.c: Domino jigsaw puzzle. Aim to place one of every * possible domino within a rectangle in such a way that the number * on each square matches the provided clue. */ /* * TODO: * * - improve solver so as to use more interesting forms of * deduction * * * rule out a domino placement if it would divide an unfilled * region such that at least one resulting region had an odd * area * + use b.f.s. to determine the area of an unfilled region * + a square is unfilled iff it has at least two possible * placements, and two adjacent unfilled squares are part * of the same region iff the domino placement joining * them is possible * * * perhaps set analysis * + look at all unclaimed squares containing a given number * + for each one, find the set of possible numbers that it * can connect to (i.e. each neighbouring tile such that * the placement between it and that neighbour has not yet * been ruled out) * + now proceed similarly to Solo set analysis: try to find * a subset of the squares such that the union of their * possible numbers is the same size as the subset. If so, * rule out those possible numbers for all other squares. * * important wrinkle: the double dominoes complicate * matters. Connecting a number to itself uses up _two_ * of the unclaimed squares containing a number. Thus, * when finding the initial subset we must never * include two adjacent squares; and also, when ruling * things out after finding the subset, we must be * careful that we don't rule out precisely the domino * placement that was _included_ in our set! */ #include #include #include #include #include #include #include "puzzles.h" /* nth triangular number */ #define TRI(n) ( (n) * ((n) + 1) / 2 ) /* number of dominoes for value n */ #define DCOUNT(n) TRI((n)+1) /* map a pair of numbers to a unique domino index from 0 upwards. */ #define DINDEX(n1,n2) ( TRI(max(n1,n2)) + min(n1,n2) ) #define FLASH_TIME 0.13F enum { COL_BACKGROUND, COL_TEXT, COL_DOMINO, COL_DOMINOCLASH, COL_DOMINOTEXT, COL_EDGE, COL_HIGHLIGHT_1, COL_HIGHLIGHT_2, NCOLOURS }; struct game_params { int n; int unique; }; struct game_numbers { int refcount; int *numbers; /* h x w */ }; #define EDGE_L 0x100 #define EDGE_R 0x200 #define EDGE_T 0x400 #define EDGE_B 0x800 struct game_state { game_params params; int w, h; struct game_numbers *numbers; int *grid; unsigned short *edges; /* h x w */ int completed, cheated; }; static game_params *default_params(void) { game_params *ret = snew(game_params); ret->n = 6; ret->unique = TRUE; return ret; } static int game_fetch_preset(int i, char **name, game_params **params) { game_params *ret; int n; char buf[80]; switch (i) { case 0: n = 3; break; case 1: n = 4; break; case 2: n = 5; break; case 3: n = 6; break; case 4: n = 7; break; case 5: n = 8; break; case 6: n = 9; break; default: return FALSE; } sprintf(buf, "Up to double-%d", n); *name = dupstr(buf); *params = ret = snew(game_params); ret->n = n; ret->unique = TRUE; return TRUE; } static void free_params(game_params *params) { sfree(params); } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } static void decode_params(game_params *params, char const *string) { params->n = atoi(string); while (*string && isdigit((unsigned char)*string)) string++; if (*string == 'a') params->unique = FALSE; } static char *encode_params(const game_params *params, int full) { char buf[80]; sprintf(buf, "%d", params->n); if (full && !params->unique) strcat(buf, "a"); return dupstr(buf); } static config_item *game_configure(const game_params *params) { config_item *ret; char buf[80]; ret = snewn(3, config_item); ret[0].name = "Maximum number on dominoes"; ret[0].type = C_STRING; sprintf(buf, "%d", params->n); ret[0].sval = dupstr(buf); ret[0].ival = 0; ret[1].name = "Ensure unique solution"; ret[1].type = C_BOOLEAN; ret[1].sval = NULL; ret[1].ival = params->unique; ret[2].name = NULL; ret[2].type = C_END; ret[2].sval = NULL; ret[2].ival = 0; return ret; } static game_params *custom_params(const config_item *cfg) { game_params *ret = snew(game_params); ret->n = atoi(cfg[0].sval); ret->unique = cfg[1].ival; return ret; } static char *validate_params(const game_params *params, int full) { if (params->n < 1) return "Maximum face number must be at least one"; return NULL; } /* ---------------------------------------------------------------------- * Solver. */ static int find_overlaps(int w, int h, int placement, int *set) { int x, y, n; n = 0; /* number of returned placements */ x = placement / 2; y = x / w; x %= w; if (placement & 1) { /* * Horizontal domino, indexed by its left end. */ if (x > 0) set[n++] = placement-2; /* horizontal domino to the left */ if (y > 0) set[n++] = placement-2*w-1;/* vertical domino above left side */ if (y+1 < h) set[n++] = placement-1; /* vertical domino below left side */ if (x+2 < w) set[n++] = placement+2; /* horizontal domino to the right */ if (y > 0) set[n++] = placement-2*w+2-1;/* vertical domino above right side */ if (y+1 < h) set[n++] = placement+2-1; /* vertical domino below right side */ } else { /* * Vertical domino, indexed by its top end. */ if (y > 0) set[n++] = placement-2*w; /* vertical domino above */ if (x > 0) set[n++] = placement-2+1; /* horizontal domino left of top */ if (x+1 < w) set[n++] = placement+1; /* horizontal domino right of top */ if (y+2 < h) set[n++] = placement+2*w; /* vertical domino below */ if (x > 0) set[n++] = placement-2+2*w+1;/* horizontal domino left of bottom */ if (x+1 < w) set[n++] = placement+2*w+1;/* horizontal domino right of bottom */ } return n; } /* * Returns 0, 1 or 2 for number of solutions. 2 means `any number * more than one', or more accurately `we were unable to prove * there was only one'. * * Outputs in a `placements' array, indexed the same way as the one * within this function (see below); entries in there are <0 for a * placement ruled out, 0 for an uncertain placement, and 1 for a * definite one. */ static int solver(int w, int h, int n, int *grid, int *output) { int wh = w*h, dc = DCOUNT(n); int *placements, *heads; int i, j, x, y, ret; /* * This array has one entry for every possible domino * placement. Vertical placements are indexed by their top * half, at (y*w+x)*2; horizontal placements are indexed by * their left half at (y*w+x)*2+1. * * This array is used to link domino placements together into * linked lists, so that we can track all the possible * placements of each different domino. It's also used as a * quick means of looking up an individual placement to see * whether we still think it's possible. Actual values stored * in this array are -2 (placement not possible at all), -1 * (end of list), or the array index of the next item. * * Oh, and -3 for `not even valid', used for array indices * which don't even represent a plausible placement. */ placements = snewn(2*wh, int); for (i = 0; i < 2*wh; i++) placements[i] = -3; /* not even valid */ /* * This array has one entry for every domino, and it is an * index into `placements' denoting the head of the placement * list for that domino. */ heads = snewn(dc, int); for (i = 0; i < dc; i++) heads[i] = -1; /* * Set up the initial possibility lists by scanning the grid. */ for (y = 0; y < h-1; y++) for (x = 0; x < w; x++) { int di = DINDEX(grid[y*w+x], grid[(y+1)*w+x]); placements[(y*w+x)*2] = heads[di]; heads[di] = (y*w+x)*2; } for (y = 0; y < h; y++) for (x = 0; x < w-1; x++) { int di = DINDEX(grid[y*w+x], grid[y*w+(x+1)]); placements[(y*w+x)*2+1] = heads[di]; heads[di] = (y*w+x)*2+1; } #ifdef SOLVER_DIAGNOSTICS printf("before solver:\n"); for (i = 0; i <= n; i++) for (j = 0; j <= i; j++) { int k, m; m = 0; printf("%2d [%d %d]:", DINDEX(i, j), i, j); for (k = heads[DINDEX(i,j)]; k >= 0; k = placements[k]) printf(" %3d [%d,%d,%c]", k, k/2%w, k/2/w, k%2?'h':'v'); printf("\n"); } #endif while (1) { int done_something = FALSE; /* * For each domino, look at its possible placements, and * for each placement consider the placements (of any * domino) it overlaps. Any placement overlapped by all * placements of this domino can be ruled out. * * Each domino placement overlaps only six others, so we * need not do serious set theory to work this out. */ for (i = 0; i < dc; i++) { int permset[6], permlen = 0, p; if (heads[i] == -1) { /* no placement for this domino */ ret = 0; /* therefore puzzle is impossible */ goto done; } for (j = heads[i]; j >= 0; j = placements[j]) { assert(placements[j] != -2); if (j == heads[i]) { permlen = find_overlaps(w, h, j, permset); } else { int tempset[6], templen, m, n, k; templen = find_overlaps(w, h, j, tempset); /* * Pathetically primitive set intersection * algorithm, which I'm only getting away with * because I know my sets are bounded by a very * small size. */ for (m = n = 0; m < permlen; m++) { for (k = 0; k < templen; k++) if (tempset[k] == permset[m]) break; if (k < templen) permset[n++] = permset[m]; } permlen = n; } } for (p = 0; p < permlen; p++) { j = permset[p]; if (placements[j] != -2) { int p1, p2, di; done_something = TRUE; /* * Rule out this placement. First find what * domino it is... */ p1 = j / 2; p2 = (j & 1) ? p1 + 1 : p1 + w; di = DINDEX(grid[p1], grid[p2]); #ifdef SOLVER_DIAGNOSTICS printf("considering domino %d: ruling out placement %d" " for %d\n", i, j, di); #endif /* * ... then walk that domino's placement list, * removing this placement when we find it. */ if (heads[di] == j) heads[di] = placements[j]; else { int k = heads[di]; while (placements[k] != -1 && placements[k] != j) k = placements[k]; assert(placements[k] == j); placements[k] = placements[j]; } placements[j] = -2; } } } /* * For each square, look at the available placements * involving that square. If all of them are for the same * domino, then rule out any placements for that domino * _not_ involving this square. */ for (i = 0; i < wh; i++) { int list[4], k, n, adi; x = i % w; y = i / w; j = 0; if (x > 0) list[j++] = 2*(i-1)+1; if (x+1 < w) list[j++] = 2*i+1; if (y > 0) list[j++] = 2*(i-w); if (y+1 < h) list[j++] = 2*i; for (n = k = 0; k < j; k++) if (placements[list[k]] >= -1) list[n++] = list[k]; adi = -1; for (j = 0; j < n; j++) { int p1, p2, di; k = list[j]; p1 = k / 2; p2 = (k & 1) ? p1 + 1 : p1 + w; di = DINDEX(grid[p1], grid[p2]); if (adi == -1) adi = di; if (adi != di) break; } if (j == n) { int nn; assert(adi >= 0); /* * We've found something. All viable placements * involving this square are for domino `adi'. If * the current placement list for that domino is * longer than n, reduce it to precisely this * placement list and we've done something. */ nn = 0; for (k = heads[adi]; k >= 0; k = placements[k]) nn++; if (nn > n) { done_something = TRUE; #ifdef SOLVER_DIAGNOSTICS printf("considering square %d,%d: reducing placements " "of domino %d\n", x, y, adi); #endif /* * Set all other placements on the list to * impossible. */ k = heads[adi]; while (k >= 0) { int tmp = placements[k]; placements[k] = -2; k = tmp; } /* * Set up the new list. */ heads[adi] = list[0]; for (k = 0; k < n; k++) placements[list[k]] = (k+1 == n ? -1 : list[k+1]); } } } if (!done_something) break; } #ifdef SOLVER_DIAGNOSTICS printf("after solver:\n"); for (i = 0; i <= n; i++) for (j = 0; j <= i; j++) { int k, m; m = 0; printf("%2d [%d %d]:", DINDEX(i, j), i, j); for (k = heads[DINDEX(i,j)]; k >= 0; k = placements[k]) printf(" %3d [%d,%d,%c]", k, k/2%w, k/2/w, k%2?'h':'v'); printf("\n"); } #endif ret = 1; for (i = 0; i < wh*2; i++) { if (placements[i] == -2) { if (output) output[i] = -1; /* ruled out */ } else if (placements[i] != -3) { int p1, p2, di; p1 = i / 2; p2 = (i & 1) ? p1 + 1 : p1 + w; di = DINDEX(grid[p1], grid[p2]); if (i == heads[di] && placements[i] == -1) { if (output) output[i] = 1; /* certain */ } else { if (output) output[i] = 0; /* uncertain */ ret = 2; } } } done: /* * Free working data. */ sfree(placements); sfree(heads); return ret; } /* ---------------------------------------------------------------------- * End of solver code. */ static char *new_game_desc(const game_params *params, random_state *rs, char **aux, int interactive) { int n = params->n, w = n+2, h = n+1, wh = w*h; int *grid, *grid2, *list; int i, j, k, len; char *ret; /* * Allocate space in which to lay the grid out. */ grid = snewn(wh, int); grid2 = snewn(wh, int); list = snewn(2*wh, int); /* * I haven't been able to think of any particularly clever * techniques for generating instances of Dominosa with a * unique solution. Many of the deductions used in this puzzle * are based on information involving half the grid at a time * (`of all the 6s, exactly one is next to a 3'), so a strategy * of partially solving the grid and then perturbing the place * where the solver got stuck seems particularly likely to * accidentally destroy the information which the solver had * used in getting that far. (Contrast with, say, Mines, in * which most deductions are local so this is an excellent * strategy.) * * Therefore I resort to the basest of brute force methods: * generate a random grid, see if it's solvable, throw it away * and try again if not. My only concession to sophistication * and cleverness is to at least _try_ not to generate obvious * 2x2 ambiguous sections (see comment below in the domino- * flipping section). * * During tests performed on 2005-07-15, I found that the brute * force approach without that tweak had to throw away about 87 * grids on average (at the default n=6) before finding a * unique one, or a staggering 379 at n=9; good job the * generator and solver are fast! When I added the * ambiguous-section avoidance, those numbers came down to 19 * and 26 respectively, which is a lot more sensible. */ do { domino_layout_prealloc(w, h, rs, grid, grid2, list); /* * Now we have a complete layout covering the whole * rectangle with dominoes. So shuffle the actual domino * values and fill the rectangle with numbers. */ k = 0; for (i = 0; i <= params->n; i++) for (j = 0; j <= i; j++) { list[k++] = i; list[k++] = j; } shuffle(list, k/2, 2*sizeof(*list), rs); j = 0; for (i = 0; i < wh; i++) if (grid[i] > i) { /* Optionally flip the domino round. */ int flip = -1; if (params->unique) { int t1, t2; /* * If we're after a unique solution, we can do * something here to improve the chances. If * we're placing a domino so that it forms a * 2x2 rectangle with one we've already placed, * and if that domino and this one share a * number, we can try not to put them so that * the identical numbers are diagonally * separated, because that automatically causes * non-uniqueness: * * +---+ +-+-+ * |2 3| |2|3| * +---+ -> | | | * |4 2| |4|2| * +---+ +-+-+ */ t1 = i; t2 = grid[i]; if (t2 == t1 + w) { /* this domino is vertical */ if (t1 % w > 0 &&/* and not on the left hand edge */ grid[t1-1] == t2-1 &&/* alongside one to left */ (grid2[t1-1] == list[j] || /* and has a number */ grid2[t1-1] == list[j+1] || /* in common */ grid2[t2-1] == list[j] || grid2[t2-1] == list[j+1])) { if (grid2[t1-1] == list[j] || grid2[t2-1] == list[j+1]) flip = 0; else flip = 1; } } else { /* this domino is horizontal */ if (t1 / w > 0 &&/* and not on the top edge */ grid[t1-w] == t2-w &&/* alongside one above */ (grid2[t1-w] == list[j] || /* and has a number */ grid2[t1-w] == list[j+1] || /* in common */ grid2[t2-w] == list[j] || grid2[t2-w] == list[j+1])) { if (grid2[t1-w] == list[j] || grid2[t2-w] == list[j+1]) flip = 0; else flip = 1; } } } if (flip < 0) flip = random_upto(rs, 2); grid2[i] = list[j + flip]; grid2[grid[i]] = list[j + 1 - flip]; j += 2; } assert(j == k); } while (params->unique && solver(w, h, n, grid2, NULL) > 1); #ifdef GENERATION_DIAGNOSTICS for (j = 0; j < h; j++) { for (i = 0; i < w; i++) { putchar('0' + grid2[j*w+i]); } putchar('\n'); } putchar('\n'); #endif /* * Encode the resulting game state. * * Our encoding is a string of digits. Any number greater than * 9 is represented by a decimal integer within square * brackets. We know there are n+2 of every number (it's paired * with each number from 0 to n inclusive, and one of those is * itself so that adds another occurrence), so we can work out * the string length in advance. */ /* * To work out the total length of the decimal encodings of all * the numbers from 0 to n inclusive: * - every number has a units digit; total is n+1. * - all numbers above 9 have a tens digit; total is max(n+1-10,0). * - all numbers above 99 have a hundreds digit; total is max(n+1-100,0). * - and so on. */ len = n+1; for (i = 10; i <= n; i *= 10) len += max(n + 1 - i, 0); /* Now add two square brackets for each number above 9. */ len += 2 * max(n + 1 - 10, 0); /* And multiply by n+2 for the repeated occurrences of each number. */ len *= n+2; /* * Now actually encode the string. */ ret = snewn(len+1, char); j = 0; for (i = 0; i < wh; i++) { k = grid2[i]; if (k < 10) ret[j++] = '0' + k; else j += sprintf(ret+j, "[%d]", k); assert(j <= len); } assert(j == len); ret[j] = '\0'; /* * Encode the solved state as an aux_info. */ { char *auxinfo = snewn(wh+1, char); for (i = 0; i < wh; i++) { int v = grid[i]; auxinfo[i] = (v == i+1 ? 'L' : v == i-1 ? 'R' : v == i+w ? 'T' : v == i-w ? 'B' : '.'); } auxinfo[wh] = '\0'; *aux = auxinfo; } sfree(list); sfree(grid2); sfree(grid); return ret; } static char *validate_desc(const game_params *params, const char *desc) { int n = params->n, w = n+2, h = n+1, wh = w*h; int *occurrences; int i, j; char *ret; ret = NULL; occurrences = snewn(n+1, int); for (i = 0; i <= n; i++) occurrences[i] = 0; for (i = 0; i < wh; i++) { if (!*desc) { ret = ret ? ret : "Game description is too short"; } else { if (*desc >= '0' && *desc <= '9') j = *desc++ - '0'; else if (*desc == '[') { desc++; j = atoi(desc); while (*desc && isdigit((unsigned char)*desc)) desc++; if (*desc != ']') ret = ret ? ret : "Missing ']' in game description"; else desc++; } else { j = -1; ret = ret ? ret : "Invalid syntax in game description"; } if (j < 0 || j > n) ret = ret ? ret : "Number out of range in game description"; else occurrences[j]++; } } if (*desc) ret = ret ? ret : "Game description is too long"; if (!ret) { for (i = 0; i <= n; i++) if (occurrences[i] != n+2) ret = "Incorrect number balance in game description"; } sfree(occurrences); return ret; } static game_state *new_game(midend *me, const game_params *params, const char *desc) { int n = params->n, w = n+2, h = n+1, wh = w*h; game_state *state = snew(game_state); int i, j; state->params = *params; state->w = w; state->h = h; state->grid = snewn(wh, int); for (i = 0; i < wh; i++) state->grid[i] = i; state->edges = snewn(wh, unsigned short); for (i = 0; i < wh; i++) state->edges[i] = 0; state->numbers = snew(struct game_numbers); state->numbers->refcount = 1; state->numbers->numbers = snewn(wh, int); for (i = 0; i < wh; i++) { assert(*desc); if (*desc >= '0' && *desc <= '9') j = *desc++ - '0'; else { assert(*desc == '['); desc++; j = atoi(desc); while (*desc && isdigit((unsigned char)*desc)) desc++; assert(*desc == ']'); desc++; } assert(j >= 0 && j <= n); state->numbers->numbers[i] = j; } state->completed = state->cheated = FALSE; return state; } static game_state *dup_game(const game_state *state) { int n = state->params.n, w = n+2, h = n+1, wh = w*h; game_state *ret = snew(game_state); ret->params = state->params; ret->w = state->w; ret->h = state->h; ret->grid = snewn(wh, int); memcpy(ret->grid, state->grid, wh * sizeof(int)); ret->edges = snewn(wh, unsigned short); memcpy(ret->edges, state->edges, wh * sizeof(unsigned short)); ret->numbers = state->numbers; ret->numbers->refcount++; ret->completed = state->completed; ret->cheated = state->cheated; return ret; } static void free_game(game_state *state) { sfree(state->grid); sfree(state->edges); if (--state->numbers->refcount <= 0) { sfree(state->numbers->numbers); sfree(state->numbers); } sfree(state); } static char *solve_game(const game_state *state, const game_state *currstate, const char *aux, char **error) { int n = state->params.n, w = n+2, h = n+1, wh = w*h; int *placements; char *ret; int retlen, retsize; int i, v; char buf[80]; int extra; if (aux) { retsize = 256; ret = snewn(retsize, char); retlen = sprintf(ret, "S"); for (i = 0; i < wh; i++) { if (aux[i] == 'L') extra = sprintf(buf, ";D%d,%d", i, i+1); else if (aux[i] == 'T') extra = sprintf(buf, ";D%d,%d", i, i+w); else continue; if (retlen + extra + 1 >= retsize) { retsize = retlen + extra + 256; ret = sresize(ret, retsize, char); } strcpy(ret + retlen, buf); retlen += extra; } } else { placements = snewn(wh*2, int); for (i = 0; i < wh*2; i++) placements[i] = -3; solver(w, h, n, state->numbers->numbers, placements); /* * First make a pass putting in edges for -1, then make a pass * putting in dominoes for +1. */ retsize = 256; ret = snewn(retsize, char); retlen = sprintf(ret, "S"); for (v = -1; v <= +1; v += 2) for (i = 0; i < wh*2; i++) if (placements[i] == v) { int p1 = i / 2; int p2 = (i & 1) ? p1+1 : p1+w; extra = sprintf(buf, ";%c%d,%d", (int)(v==-1 ? 'E' : 'D'), p1, p2); if (retlen + extra + 1 >= retsize) { retsize = retlen + extra + 256; ret = sresize(ret, retsize, char); } strcpy(ret + retlen, buf); retlen += extra; } sfree(placements); } return ret; } static int game_can_format_as_text_now(const game_params *params) { return params->n < 1000; } static void draw_domino(char *board, int start, char corner, int dshort, int nshort, char cshort, int dlong, int nlong, char clong) { int go_short = nshort*dshort, go_long = nlong*dlong, i; board[start] = corner; board[start + go_short] = corner; board[start + go_long] = corner; board[start + go_short + go_long] = corner; for (i = 1; i < nshort; ++i) { int j = start + i*dshort, k = start + i*dshort + go_long; if (board[j] != corner) board[j] = cshort; if (board[k] != corner) board[k] = cshort; } for (i = 1; i < nlong; ++i) { int j = start + i*dlong, k = start + i*dlong + go_short; if (board[j] != corner) board[j] = clong; if (board[k] != corner) board[k] = clong; } } static char *game_text_format(const game_state *state) { int w = state->w, h = state->h, r, c; int cw = 4, ch = 2, gw = cw*w + 2, gh = ch * h + 1, len = gw * gh; char *board = snewn(len + 1, char); memset(board, ' ', len); for (r = 0; r < h; ++r) { for (c = 0; c < w; ++c) { int cell = r*ch*gw + cw*c, center = cell + gw*ch/2 + cw/2; int i = r*w + c, num = state->numbers->numbers[i]; if (num < 100) { board[center] = '0' + num % 10; if (num >= 10) board[center - 1] = '0' + num / 10; } else { board[center+1] = '0' + num % 10; board[center] = '0' + num / 10 % 10; board[center-1] = '0' + num / 100; } if (state->edges[i] & EDGE_L) board[center - cw/2] = '|'; if (state->edges[i] & EDGE_R) board[center + cw/2] = '|'; if (state->edges[i] & EDGE_T) board[center - gw] = '-'; if (state->edges[i] & EDGE_B) board[center + gw] = '-'; if (state->grid[i] == i) continue; /* no domino pairing */ if (state->grid[i] < i) continue; /* already done */ assert (state->grid[i] == i + 1 || state->grid[i] == i + w); if (state->grid[i] == i + 1) draw_domino(board, cell, '+', gw, ch, '|', +1, 2*cw, '-'); else if (state->grid[i] == i + w) draw_domino(board, cell, '+', +1, cw, '-', gw, 2*ch, '|'); } board[r*ch*gw + gw - 1] = '\n'; board[r*ch*gw + gw + gw - 1] = '\n'; } board[len - 1] = '\n'; board[len] = '\0'; return board; } struct game_ui { int cur_x, cur_y, cur_visible, highlight_1, highlight_2; }; static game_ui *new_ui(const game_state *state) { game_ui *ui = snew(game_ui); ui->cur_x = ui->cur_y = 0; ui->cur_visible = 0; ui->highlight_1 = ui->highlight_2 = -1; return ui; } static void free_ui(game_ui *ui) { sfree(ui); } static char *encode_ui(const game_ui *ui) { return NULL; } static void decode_ui(game_ui *ui, const char *encoding) { } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { if (!oldstate->completed && newstate->completed) ui->cur_visible = 0; } #define PREFERRED_TILESIZE 32 #define TILESIZE (ds->tilesize) #define BORDER (TILESIZE * 3 / 4) #define DOMINO_GUTTER (TILESIZE / 16) #define DOMINO_RADIUS (TILESIZE / 8) #define DOMINO_COFFSET (DOMINO_GUTTER + DOMINO_RADIUS) #define CURSOR_RADIUS (TILESIZE / 4) #define COORD(x) ( (x) * TILESIZE + BORDER ) #define FROMCOORD(x) ( ((x) - BORDER + TILESIZE) / TILESIZE - 1 ) struct game_drawstate { int started; int w, h, tilesize; unsigned long *visible; }; static char *interpret_move(const game_state *state, game_ui *ui, const game_drawstate *ds, int x, int y, int button) { int w = state->w, h = state->h; char buf[80]; /* * A left-click between two numbers toggles a domino covering * them. A right-click toggles an edge. */ if (button == LEFT_BUTTON || button == RIGHT_BUTTON) { int tx = FROMCOORD(x), ty = FROMCOORD(y), t = ty*w+tx; int dx, dy; int d1, d2; if (tx < 0 || tx >= w || ty < 0 || ty >= h) return NULL; /* * Now we know which square the click was in, decide which * edge of the square it was closest to. */ dx = 2 * (x - COORD(tx)) - TILESIZE; dy = 2 * (y - COORD(ty)) - TILESIZE; if (abs(dx) > abs(dy) && dx < 0 && tx > 0) d1 = t - 1, d2 = t; /* clicked in right side of domino */ else if (abs(dx) > abs(dy) && dx > 0 && tx+1 < w) d1 = t, d2 = t + 1; /* clicked in left side of domino */ else if (abs(dy) > abs(dx) && dy < 0 && ty > 0) d1 = t - w, d2 = t; /* clicked in bottom half of domino */ else if (abs(dy) > abs(dx) && dy > 0 && ty+1 < h) d1 = t, d2 = t + w; /* clicked in top half of domino */ else return NULL; /* * We can't mark an edge next to any domino. */ if (button == RIGHT_BUTTON && (state->grid[d1] != d1 || state->grid[d2] != d2)) return NULL; ui->cur_visible = 0; sprintf(buf, "%c%d,%d", (int)(button == RIGHT_BUTTON ? 'E' : 'D'), d1, d2); return dupstr(buf); } else if (IS_CURSOR_MOVE(button)) { ui->cur_visible = 1; move_cursor(button, &ui->cur_x, &ui->cur_y, 2*w-1, 2*h-1, 0); return ""; } else if (IS_CURSOR_SELECT(button)) { int d1, d2; if (!((ui->cur_x ^ ui->cur_y) & 1)) return NULL; /* must have exactly one dimension odd */ d1 = (ui->cur_y / 2) * w + (ui->cur_x / 2); d2 = ((ui->cur_y+1) / 2) * w + ((ui->cur_x+1) / 2); /* * We can't mark an edge next to any domino. */ if (button == CURSOR_SELECT2 && (state->grid[d1] != d1 || state->grid[d2] != d2)) return NULL; sprintf(buf, "%c%d,%d", (int)(button == CURSOR_SELECT2 ? 'E' : 'D'), d1, d2); return dupstr(buf); } else if (isdigit(button)) { int n = state->params.n, num = button - '0'; if (num > n) { return NULL; } else if (ui->highlight_1 == num) { ui->highlight_1 = -1; } else if (ui->highlight_2 == num) { ui->highlight_2 = -1; } else if (ui->highlight_1 == -1) { ui->highlight_1 = num; } else if (ui->highlight_2 == -1) { ui->highlight_2 = num; } else { return NULL; } return ""; } return NULL; } static game_state *execute_move(const game_state *state, const char *move) { int n = state->params.n, w = n+2, h = n+1, wh = w*h; int d1, d2, d3, p; game_state *ret = dup_game(state); while (*move) { if (move[0] == 'S') { int i; ret->cheated = TRUE; /* * Clear the existing edges and domino placements. We * expect the S to be followed by other commands. */ for (i = 0; i < wh; i++) { ret->grid[i] = i; ret->edges[i] = 0; } move++; } else if (move[0] == 'D' && sscanf(move+1, "%d,%d%n", &d1, &d2, &p) == 2 && d1 >= 0 && d1 < wh && d2 >= 0 && d2 < wh && d1 < d2) { /* * Toggle domino presence between d1 and d2. */ if (ret->grid[d1] == d2) { assert(ret->grid[d2] == d1); ret->grid[d1] = d1; ret->grid[d2] = d2; } else { /* * Erase any dominoes that might overlap the new one. */ d3 = ret->grid[d1]; if (d3 != d1) ret->grid[d3] = d3; d3 = ret->grid[d2]; if (d3 != d2) ret->grid[d3] = d3; /* * Place the new one. */ ret->grid[d1] = d2; ret->grid[d2] = d1; /* * Destroy any edges lurking around it. */ if (ret->edges[d1] & EDGE_L) { assert(d1 - 1 >= 0); ret->edges[d1 - 1] &= ~EDGE_R; } if (ret->edges[d1] & EDGE_R) { assert(d1 + 1 < wh); ret->edges[d1 + 1] &= ~EDGE_L; } if (ret->edges[d1] & EDGE_T) { assert(d1 - w >= 0); ret->edges[d1 - w] &= ~EDGE_B; } if (ret->edges[d1] & EDGE_B) { assert(d1 + 1 < wh); ret->edges[d1 + w] &= ~EDGE_T; } ret->edges[d1] = 0; if (ret->edges[d2] & EDGE_L) { assert(d2 - 1 >= 0); ret->edges[d2 - 1] &= ~EDGE_R; } if (ret->edges[d2] & EDGE_R) { assert(d2 + 1 < wh); ret->edges[d2 + 1] &= ~EDGE_L; } if (ret->edges[d2] & EDGE_T) { assert(d2 - w >= 0); ret->edges[d2 - w] &= ~EDGE_B; } if (ret->edges[d2] & EDGE_B) { assert(d2 + 1 < wh); ret->edges[d2 + w] &= ~EDGE_T; } ret->edges[d2] = 0; } move += p+1; } else if (move[0] == 'E' && sscanf(move+1, "%d,%d%n", &d1, &d2, &p) == 2 && d1 >= 0 && d1 < wh && d2 >= 0 && d2 < wh && d1 < d2 && ret->grid[d1] == d1 && ret->grid[d2] == d2) { /* * Toggle edge presence between d1 and d2. */ if (d2 == d1 + 1) { ret->edges[d1] ^= EDGE_R; ret->edges[d2] ^= EDGE_L; } else { ret->edges[d1] ^= EDGE_B; ret->edges[d2] ^= EDGE_T; } move += p+1; } else { free_game(ret); return NULL; } if (*move) { if (*move != ';') { free_game(ret); return NULL; } move++; } } /* * After modifying the grid, check completion. */ if (!ret->completed) { int i, ok = 0; unsigned char *used = snewn(TRI(n+1), unsigned char); memset(used, 0, TRI(n+1)); for (i = 0; i < wh; i++) if (ret->grid[i] > i) { int n1, n2, di; n1 = ret->numbers->numbers[i]; n2 = ret->numbers->numbers[ret->grid[i]]; di = DINDEX(n1, n2); assert(di >= 0 && di < TRI(n+1)); if (!used[di]) { used[di] = 1; ok++; } } sfree(used); if (ok == DCOUNT(n)) ret->completed = TRUE; } return ret; } /* ---------------------------------------------------------------------- * Drawing routines. */ static void game_compute_size(const game_params *params, int tilesize, int *x, int *y) { int n = params->n, w = n+2, h = n+1; /* Ick: fake up `ds->tilesize' for macro expansion purposes */ struct { int tilesize; } ads, *ds = &ads; ads.tilesize = tilesize; *x = w * TILESIZE + 2*BORDER; *y = h * TILESIZE + 2*BORDER; } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { ds->tilesize = tilesize; } static float *game_colours(frontend *fe, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float); frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]); ret[COL_TEXT * 3 + 0] = 0.0F; ret[COL_TEXT * 3 + 1] = 0.0F; ret[COL_TEXT * 3 + 2] = 0.0F; ret[COL_DOMINO * 3 + 0] = 0.0F; ret[COL_DOMINO * 3 + 1] = 0.0F; ret[COL_DOMINO * 3 + 2] = 0.0F; ret[COL_DOMINOCLASH * 3 + 0] = 0.5F; ret[COL_DOMINOCLASH * 3 + 1] = 0.0F; ret[COL_DOMINOCLASH * 3 + 2] = 0.0F; ret[COL_DOMINOTEXT * 3 + 0] = 1.0F; ret[COL_DOMINOTEXT * 3 + 1] = 1.0F; ret[COL_DOMINOTEXT * 3 + 2] = 1.0F; ret[COL_EDGE * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] * 2 / 3; ret[COL_EDGE * 3 + 1] = ret[COL_BACKGROUND * 3 + 1] * 2 / 3; ret[COL_EDGE * 3 + 2] = ret[COL_BACKGROUND * 3 + 2] * 2 / 3; ret[COL_HIGHLIGHT_1 * 3 + 0] = 0.85; ret[COL_HIGHLIGHT_1 * 3 + 1] = 0.20; ret[COL_HIGHLIGHT_1 * 3 + 2] = 0.20; ret[COL_HIGHLIGHT_2 * 3 + 0] = 0.30; ret[COL_HIGHLIGHT_2 * 3 + 1] = 0.85; ret[COL_HIGHLIGHT_2 * 3 + 2] = 0.20; *ncolours = NCOLOURS; return ret; } static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { struct game_drawstate *ds = snew(struct game_drawstate); int i; ds->started = FALSE; ds->w = state->w; ds->h = state->h; ds->visible = snewn(ds->w * ds->h, unsigned long); ds->tilesize = 0; /* not decided yet */ for (i = 0; i < ds->w * ds->h; i++) ds->visible[i] = 0xFFFF; return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { sfree(ds->visible); sfree(ds); } enum { TYPE_L, TYPE_R, TYPE_T, TYPE_B, TYPE_BLANK, TYPE_MASK = 0x0F }; /* These flags must be disjoint with: * the above enum (TYPE_*) [0x000 -- 0x00F] * EDGE_* [0x100 -- 0xF00] * and must fit into an unsigned long (32 bits). */ #define DF_HIGHLIGHT_1 0x10 #define DF_HIGHLIGHT_2 0x20 #define DF_FLASH 0x40 #define DF_CLASH 0x80 #define DF_CURSOR 0x01000 #define DF_CURSOR_USEFUL 0x02000 #define DF_CURSOR_XBASE 0x10000 #define DF_CURSOR_XMASK 0x30000 #define DF_CURSOR_YBASE 0x40000 #define DF_CURSOR_YMASK 0xC0000 #define CEDGE_OFF (TILESIZE / 8) #define IS_EMPTY(s,x,y) ((s)->grid[(y)*(s)->w+(x)] == ((y)*(s)->w+(x))) static void draw_tile(drawing *dr, game_drawstate *ds, const game_state *state, int x, int y, int type, int highlight_1, int highlight_2) { int w = state->w /*, h = state->h */; int cx = COORD(x), cy = COORD(y); int nc; char str[80]; int flags; clip(dr, cx, cy, TILESIZE, TILESIZE); draw_rect(dr, cx, cy, TILESIZE, TILESIZE, COL_BACKGROUND); flags = type &~ TYPE_MASK; type &= TYPE_MASK; if (type != TYPE_BLANK) { int i, bg; /* * Draw one end of a domino. This is composed of: * * - two filled circles (rounded corners) * - two rectangles * - a slight shift in the number */ if (flags & DF_CLASH) bg = COL_DOMINOCLASH; else bg = COL_DOMINO; nc = COL_DOMINOTEXT; if (flags & DF_FLASH) { int tmp = nc; nc = bg; bg = tmp; } if (type == TYPE_L || type == TYPE_T) draw_circle(dr, cx+DOMINO_COFFSET, cy+DOMINO_COFFSET, DOMINO_RADIUS, bg, bg); if (type == TYPE_R || type == TYPE_T) draw_circle(dr, cx+TILESIZE-1-DOMINO_COFFSET, cy+DOMINO_COFFSET, DOMINO_RADIUS, bg, bg); if (type == TYPE_L || type == TYPE_B) draw_circle(dr, cx+DOMINO_COFFSET, cy+TILESIZE-1-DOMINO_COFFSET, DOMINO_RADIUS, bg, bg); if (type == TYPE_R || type == TYPE_B) draw_circle(dr, cx+TILESIZE-1-DOMINO_COFFSET, cy+TILESIZE-1-DOMINO_COFFSET, DOMINO_RADIUS, bg, bg); for (i = 0; i < 2; i++) { int x1, y1, x2, y2; x1 = cx + (i ? DOMINO_GUTTER : DOMINO_COFFSET); y1 = cy + (i ? DOMINO_COFFSET : DOMINO_GUTTER); x2 = cx + TILESIZE-1 - (i ? DOMINO_GUTTER : DOMINO_COFFSET); y2 = cy + TILESIZE-1 - (i ? DOMINO_COFFSET : DOMINO_GUTTER); if (type == TYPE_L) x2 = cx + TILESIZE + TILESIZE/16; else if (type == TYPE_R) x1 = cx - TILESIZE/16; else if (type == TYPE_T) y2 = cy + TILESIZE + TILESIZE/16; else if (type == TYPE_B) y1 = cy - TILESIZE/16; draw_rect(dr, x1, y1, x2-x1+1, y2-y1+1, bg); } } else { if (flags & EDGE_T) draw_rect(dr, cx+DOMINO_GUTTER, cy, TILESIZE-2*DOMINO_GUTTER, 1, COL_EDGE); if (flags & EDGE_B) draw_rect(dr, cx+DOMINO_GUTTER, cy+TILESIZE-1, TILESIZE-2*DOMINO_GUTTER, 1, COL_EDGE); if (flags & EDGE_L) draw_rect(dr, cx, cy+DOMINO_GUTTER, 1, TILESIZE-2*DOMINO_GUTTER, COL_EDGE); if (flags & EDGE_R) draw_rect(dr, cx+TILESIZE-1, cy+DOMINO_GUTTER, 1, TILESIZE-2*DOMINO_GUTTER, COL_EDGE); nc = COL_TEXT; } if (flags & DF_CURSOR) { int curx = ((flags & DF_CURSOR_XMASK) / DF_CURSOR_XBASE) & 3; int cury = ((flags & DF_CURSOR_YMASK) / DF_CURSOR_YBASE) & 3; int ox = cx + curx*TILESIZE/2; int oy = cy + cury*TILESIZE/2; draw_rect_corners(dr, ox, oy, CURSOR_RADIUS, nc); if (flags & DF_CURSOR_USEFUL) draw_rect_corners(dr, ox, oy, CURSOR_RADIUS+1, nc); } if (flags & DF_HIGHLIGHT_1) { nc = COL_HIGHLIGHT_1; } else if (flags & DF_HIGHLIGHT_2) { nc = COL_HIGHLIGHT_2; } sprintf(str, "%d", state->numbers->numbers[y*w+x]); draw_text(dr, cx+TILESIZE/2, cy+TILESIZE/2, FONT_VARIABLE, TILESIZE/2, ALIGN_HCENTRE | ALIGN_VCENTRE, nc, str); draw_update(dr, cx, cy, TILESIZE, TILESIZE); unclip(dr); } static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float animtime, float flashtime) { int n = state->params.n, w = state->w, h = state->h, wh = w*h; int x, y, i; unsigned char *used; if (!ds->started) { int pw, ph; game_compute_size(&state->params, TILESIZE, &pw, &ph); draw_rect(dr, 0, 0, pw, ph, COL_BACKGROUND); draw_update(dr, 0, 0, pw, ph); ds->started = TRUE; } /* * See how many dominoes of each type there are, so we can * highlight clashes in red. */ used = snewn(TRI(n+1), unsigned char); memset(used, 0, TRI(n+1)); for (i = 0; i < wh; i++) if (state->grid[i] > i) { int n1, n2, di; n1 = state->numbers->numbers[i]; n2 = state->numbers->numbers[state->grid[i]]; di = DINDEX(n1, n2); assert(di >= 0 && di < TRI(n+1)); if (used[di] < 2) used[di]++; } for (y = 0; y < h; y++) for (x = 0; x < w; x++) { int n = y*w+x; int n1, n2, di; unsigned long c; if (state->grid[n] == n-1) c = TYPE_R; else if (state->grid[n] == n+1) c = TYPE_L; else if (state->grid[n] == n-w) c = TYPE_B; else if (state->grid[n] == n+w) c = TYPE_T; else c = TYPE_BLANK; n1 = state->numbers->numbers[n]; if (c != TYPE_BLANK) { n2 = state->numbers->numbers[state->grid[n]]; di = DINDEX(n1, n2); if (used[di] > 1) c |= DF_CLASH; /* highlight a clash */ } else { c |= state->edges[n]; } if (n1 == ui->highlight_1) c |= DF_HIGHLIGHT_1; if (n1 == ui->highlight_2) c |= DF_HIGHLIGHT_2; if (flashtime != 0) c |= DF_FLASH; /* we're flashing */ if (ui->cur_visible) { unsigned curx = (unsigned)(ui->cur_x - (2*x-1)); unsigned cury = (unsigned)(ui->cur_y - (2*y-1)); if (curx < 3 && cury < 3) { c |= (DF_CURSOR | (curx * DF_CURSOR_XBASE) | (cury * DF_CURSOR_YBASE)); if ((ui->cur_x ^ ui->cur_y) & 1) c |= DF_CURSOR_USEFUL; } } if (ds->visible[n] != c) { draw_tile(dr, ds, state, x, y, c, ui->highlight_1, ui->highlight_2); ds->visible[n] = c; } } sfree(used); } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return 0.0F; } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { if (!oldstate->completed && newstate->completed && !oldstate->cheated && !newstate->cheated) { ui->highlight_1 = ui->highlight_2 = -1; return FLASH_TIME; } return 0.0F; } static int game_status(const game_state *state) { return state->completed ? +1 : 0; } static int game_timing_state(const game_state *state, game_ui *ui) { return TRUE; } static void game_print_size(const game_params *params, float *x, float *y) { int pw, ph; /* * I'll use 6mm squares by default. */ game_compute_size(params, 600, &pw, &ph); *x = pw / 100.0F; *y = ph / 100.0F; } static void game_print(drawing *dr, const game_state *state, int tilesize) { int w = state->w, h = state->h; int c, x, y; /* Ick: fake up `ds->tilesize' for macro expansion purposes */ game_drawstate ads, *ds = &ads; game_set_size(dr, ds, NULL, tilesize); c = print_mono_colour(dr, 1); assert(c == COL_BACKGROUND); c = print_mono_colour(dr, 0); assert(c == COL_TEXT); c = print_mono_colour(dr, 0); assert(c == COL_DOMINO); c = print_mono_colour(dr, 0); assert(c == COL_DOMINOCLASH); c = print_mono_colour(dr, 1); assert(c == COL_DOMINOTEXT); c = print_mono_colour(dr, 0); assert(c == COL_EDGE); for (y = 0; y < h; y++) for (x = 0; x < w; x++) { int n = y*w+x; unsigned long c; if (state->grid[n] == n-1) c = TYPE_R; else if (state->grid[n] == n+1) c = TYPE_L; else if (state->grid[n] == n-w) c = TYPE_B; else if (state->grid[n] == n+w) c = TYPE_T; else c = TYPE_BLANK; draw_tile(dr, ds, state, x, y, c, -1, -1); } } #ifdef COMBINED #define thegame dominosa #endif const struct game thegame = { "Dominosa", "games.dominosa", "dominosa", default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, TRUE, solve_game, TRUE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, PREFERRED_TILESIZE, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, TRUE, FALSE, game_print_size, game_print, FALSE, /* wants_statusbar */ FALSE, game_timing_state, 0, /* flags */ }; /* vim: set shiftwidth=4 :set textwidth=80: */ puzzles-20170606.272beef/divvy.c0000644000175000017500000005453113115373615015206 0ustar simonsimon/* * Library code to divide up a rectangle into a number of equally * sized ominoes, in a random fashion. * * Could use this for generating solved grids of * http://www.nikoli.co.jp/ja/puzzles/block_puzzle/ * or for generating the playfield for Jigsaw Sudoku. */ /* * This code is restricted to simply connected solutions: that is, * no single polyomino may completely surround another (not even * with a corner visible to the outside world, in the sense that a * 7-omino can `surround' a single square). * * It's tempting to think that this is a natural consequence of * all the ominoes being the same size - after all, a division of * anything into 7-ominoes must necessarily have all of them * simply connected, because if one was not then the 1-square * space in the middle could not be part of any 7-omino - but in * fact, for sufficiently large k, it is perfectly possible for a * k-omino to completely surround another k-omino. A simple * example is this one with two 25-ominoes: * * +--+--+--+--+--+--+--+ * | | * + +--+--+--+--+--+ + * | | | | * + + + + * | | | | * + + + +--+ * | | | | * + + + +--+ * | | | | * + + + + * | | | | * + +--+--+--+--+--+ + * | | * +--+--+--+--+--+--+--+ * * I claim the smallest k which can manage this is 23. More * formally: * * If a k-omino P is completely surrounded by another k-omino Q, * such that every edge of P borders on Q, then k >= 23. * * Proof: * * It's relatively simple to find the largest _rectangle_ a * k-omino can enclose. So I'll construct my proof in two parts: * firstly, show that no 22-omino or smaller can enclose a * rectangle as large as itself, and secondly, show that no * polyomino can enclose a larger non-rectangle than a rectangle. * * The first of those claims: * * To surround an m x n rectangle, a polyomino must have 2m * squares along the two m-sides of the rectangle, 2n squares * along the two n-sides, and must fill in at least three of the * corners in order to be connected. Thus, 2(m+n)+3 <= k. We wish * to find the largest value of mn subject to that constraint, and * it's clear that this is achieved when m and n are as close to * equal as possible. (If they aren't, WLOG suppose m < n; then * (m+1)(n-1) = mn + n - m - 1 >= mn, with equality only when * m=n-1.) * * So the area of the largest rectangle which can be enclosed by a * k-omino is given by floor(k'/2) * ceil(k'/2), where k' = * (k-3)/2. This is a monotonic function in k, so there will be a * unique point at which it goes from being smaller than k to * being larger than k. That point is between 22 (maximum area 20) * and 23 (maximum area 25). * * The second claim: * * Suppose we have an inner polyomino P surrounded by an outer * polyomino Q. I seek to show that if P is non-rectangular, then * P is also non-maximal, in the sense that we can transform P and * Q into a new pair of polyominoes in which P is larger and Q is * at most the same size. * * Consider walking along the boundary of P in a clockwise * direction. (We may assume, of course, that there is only _one_ * boundary of P, i.e. P has no hole in the middle. If it does * have a hole in the middle, it's _trivially_ non-maximal because * we can just fill the hole in!) Our walk will take us along many * edges between squares; sometimes we might turn left, and * certainly sometimes we will turn right. Always there will be a * square of P on our right, and a square of Q on our left. * * The net angle through which we turn during the entire walk must * add up to 360 degrees rightwards. So if there are no left * turns, then we must turn right exactly four times, meaning we * have described a rectangle. Hence, if P is _not_ rectangular, * then there must have been a left turn at some point. A left * turn must mean we walk along two edges of the same square of Q. * * Thus, there is some square X in Q which is adjacent to two * diagonally separated squares in P. Let us call those two * squares N and E; let us refer to the other two neighbours of X * as S and W; let us refer to the other mutual neighbour of S and * W as D; and let us refer to the other mutual neighbour of S and * E as Y. In other words, we have named seven squares, arranged * thus: * * N * W X E * D S Y * * where N and E are in P, and X is in Q. * * Clearly at least one of W and S must be in Q (because otherwise * X would not be connected to any other square in Q, and would * hence have to be the whole of Q; and evidently if Q were a * 1-omino it could not enclose _anything_). So we divide into * cases: * * If both W and S are in Q, then we take X out of Q and put it in * P, which does not expose any edge of P. If this disconnects Q, * then we can reconnect it by adding D to Q. * * If only one of W and S is in Q, then wlog let it be W. If S is * in _P_, then we have a particularly easy case: we can simply * take X out of Q and add it to P, and this cannot disconnect X * since X was a leaf square of Q. * * Our remaining case is that W is in Q and S is in neither P nor * Q. Again we take X out of Q and put it in P; we also add S to * Q. This ensures we do not expose an edge of P, but we must now * prove that S is adjacent to some other existing square of Q so * that we haven't disconnected Q by adding it. * * To do this, we recall that we walked along the edge XE, and * then turned left to walk along XN. So just before doing all * that, we must have reached the corner XSE, and we must have * done it by walking along one of the three edges meeting at that * corner which are _not_ XE. It can't have been SY, since S would * then have been on our left and it isn't in Q; and it can't have * been XS, since S would then have been on our right and it isn't * in P. So it must have been YE, in which case Y was on our left, * and hence is in Q. * * So in all cases we have shown that we can take X out of Q and * add it to P, and add at most one square to Q to restore the * containment and connectedness properties. Hence, we can keep * doing this until we run out of left turns and P becomes * rectangular. [] * * ------------ * * Anyway, that entire proof was a bit of a sidetrack. The point * is, although constructions of this type are possible for * sufficiently large k, divvy_rectangle() will never generate * them. This could be considered a weakness for some purposes, in * the sense that we can't generate all possible divisions. * However, there are many divisions which we are highly unlikely * to generate anyway, so in practice it probably isn't _too_ bad. * * If I wanted to fix this issue, I would have to make the rules * more complicated for determining when a square can safely be * _removed_ from a polyomino. Adding one becomes easier (a square * may be added to a polyomino iff it is 4-adjacent to any square * currently part of the polyomino, and the current test for loop * formation may be dispensed with), but to determine which * squares may be removed we must now resort to analysis of the * overall structure of the polyomino rather than the simple local * properties we can currently get away with measuring. */ /* * Possible improvements which might cut the fail rate: * * - instead of picking one omino to extend in an iteration, try * them all in succession (in a randomised order) * * - (for real rigour) instead of bfsing over ominoes, bfs over * the space of possible _removed squares_. That way we aren't * limited to randomly choosing a single square to remove from * an omino and failing if that particular square doesn't * happen to work. * * However, I don't currently think it's necessary to do either of * these, because the failure rate is already low enough to be * easily tolerable, under all circumstances I've been able to * think of. */ #include #include #include #include #include "puzzles.h" /* * Subroutine which implements a function used in computing both * whether a square can safely be added to an omino, and whether * it can safely be removed. * * We enumerate the eight squares 8-adjacent to this one, in * cyclic order. We go round that loop and count the number of * times we find a square owned by the target omino next to one * not owned by it. We then return success iff that count is 2. * * When adding a square to an omino, this is precisely the * criterion which tells us that adding the square won't leave a * hole in the middle of the omino. (If it did, then things get * more complicated; see above.) * * When removing a square from an omino, the _same_ criterion * tells us that removing the square won't disconnect the omino. * (This only works _because_ we've ensured the omino is simply * connected.) */ static int addremcommon(int w, int h, int x, int y, int *own, int val) { int neighbours[8]; int dir, count; for (dir = 0; dir < 8; dir++) { int dx = ((dir & 3) == 2 ? 0 : dir > 2 && dir < 6 ? +1 : -1); int dy = ((dir & 3) == 0 ? 0 : dir < 4 ? -1 : +1); int sx = x+dx, sy = y+dy; if (sx < 0 || sx >= w || sy < 0 || sy >= h) neighbours[dir] = -1; /* outside the grid */ else neighbours[dir] = own[sy*w+sx]; } /* * To begin with, check 4-adjacency. */ if (neighbours[0] != val && neighbours[2] != val && neighbours[4] != val && neighbours[6] != val) return FALSE; count = 0; for (dir = 0; dir < 8; dir++) { int next = (dir + 1) & 7; int gotthis = (neighbours[dir] == val); int gotnext = (neighbours[next] == val); if (gotthis != gotnext) count++; } return (count == 2); } /* * w and h are the dimensions of the rectangle. * * k is the size of the required ominoes. (So k must divide w*h, * of course.) * * The returned result is a w*h-sized dsf. * * In both of the above suggested use cases, the user would * probably want w==h==k, but that isn't a requirement. */ static int *divvy_internal(int w, int h, int k, random_state *rs) { int *order, *queue, *tmp, *own, *sizes, *addable, *removable, *retdsf; int wh = w*h; int i, j, n, x, y, qhead, qtail; n = wh / k; assert(wh == k*n); order = snewn(wh, int); tmp = snewn(wh, int); own = snewn(wh, int); sizes = snewn(n, int); queue = snewn(n, int); addable = snewn(wh*4, int); removable = snewn(wh, int); /* * Permute the grid squares into a random order, which will be * used for iterating over the grid whenever we need to search * for something. This prevents directional bias and arranges * for the answer to be non-deterministic. */ for (i = 0; i < wh; i++) order[i] = i; shuffle(order, wh, sizeof(*order), rs); /* * Begin by choosing a starting square at random for each * omino. */ for (i = 0; i < wh; i++) { own[i] = -1; } for (i = 0; i < n; i++) { own[order[i]] = i; sizes[i] = 1; } /* * Now repeatedly pick a random omino which isn't already at * the target size, and find a way to expand it by one. This * may involve stealing a square from another omino, in which * case we then re-expand that omino, forming a chain of * square-stealing which terminates in an as yet unclaimed * square. Hence every successful iteration around this loop * causes the number of unclaimed squares to drop by one, and * so the process is bounded in duration. */ while (1) { #ifdef DIVVY_DIAGNOSTICS { int x, y; printf("Top of loop. Current grid:\n"); for (y = 0; y < h; y++) { for (x = 0; x < w; x++) printf("%3d", own[y*w+x]); printf("\n"); } } #endif /* * Go over the grid and figure out which squares can * safely be added to, or removed from, each omino. We * don't take account of other ominoes in this process, so * we will often end up knowing that a square can be * poached from one omino by another. * * For each square, there may be up to four ominoes to * which it can be added (those to which it is * 4-adjacent). */ for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { int yx = y*w+x; int curr = own[yx]; int dir; if (curr < 0) { removable[yx] = FALSE; /* can't remove if not owned! */ } else if (sizes[curr] == 1) { removable[yx] = TRUE; /* can always remove a singleton */ } else { /* * See if this square can be removed from its * omino without disconnecting it. */ removable[yx] = addremcommon(w, h, x, y, own, curr); } for (dir = 0; dir < 4; dir++) { int dx = (dir == 0 ? -1 : dir == 1 ? +1 : 0); int dy = (dir == 2 ? -1 : dir == 3 ? +1 : 0); int sx = x + dx, sy = y + dy; int syx = sy*w+sx; addable[yx*4+dir] = -1; if (sx < 0 || sx >= w || sy < 0 || sy >= h) continue; /* no omino here! */ if (own[syx] < 0) continue; /* also no omino here */ if (own[syx] == own[yx]) continue; /* we already got one */ if (!addremcommon(w, h, x, y, own, own[syx])) continue; /* would non-simply connect the omino */ addable[yx*4+dir] = own[syx]; } } } for (i = j = 0; i < n; i++) if (sizes[i] < k) tmp[j++] = i; if (j == 0) break; /* all ominoes are complete! */ j = tmp[random_upto(rs, j)]; #ifdef DIVVY_DIAGNOSTICS printf("Trying to extend %d\n", j); #endif /* * So we're trying to expand omino j. We breadth-first * search out from j across the space of ominoes. * * For bfs purposes, we use two elements of tmp per omino: * tmp[2*i+0] tells us which omino we got to i from, and * tmp[2*i+1] numbers the grid square that omino stole * from us. * * This requires that wh (the size of tmp) is at least 2n, * i.e. k is at least 2. There would have been nothing to * stop a user calling this function with k=1, but if they * did then we wouldn't have got to _here_ in the code - * we would have noticed above that all ominoes were * already at their target sizes, and terminated :-) */ assert(wh >= 2*n); for (i = 0; i < n; i++) tmp[2*i] = tmp[2*i+1] = -1; qhead = qtail = 0; queue[qtail++] = j; tmp[2*j] = tmp[2*j+1] = -2; /* special value: `starting point' */ while (qhead < qtail) { int tmpsq; j = queue[qhead]; /* * We wish to expand omino j. However, we might have * got here by omino j having a square stolen from it, * so first of all we must temporarily mark that * square as not belonging to j, so that our adjacency * calculations don't assume j _does_ belong to us. */ tmpsq = tmp[2*j+1]; if (tmpsq >= 0) { assert(own[tmpsq] == j); own[tmpsq] = -3; } /* * OK. Now begin by seeing if we can find any * unclaimed square into which we can expand omino j. * If we find one, the entire bfs terminates. */ for (i = 0; i < wh; i++) { int dir; if (own[order[i]] != -1) continue; /* this square is claimed */ /* * Special case: if our current omino was size 1 * and then had a square stolen from it, it's now * size zero, which means it's valid to `expand' * it into _any_ unclaimed square. */ if (sizes[j] == 1 && tmpsq >= 0) break; /* got one */ /* * Failing that, we must do the full test for * addability. */ for (dir = 0; dir < 4; dir++) if (addable[order[i]*4+dir] == j) { /* * We know this square is addable to this * omino with the grid in the state it had * at the top of the loop. However, we * must now check that it's _still_ * addable to this omino when the omino is * missing a square. To do this it's only * necessary to re-check addremcommon. */ if (!addremcommon(w, h, order[i]%w, order[i]/w, own, j)) continue; break; } if (dir == 4) continue; /* we can't add this square to j */ break; /* got one! */ } if (i < wh) { i = order[i]; /* * Restore the temporarily removed square _before_ * we start shifting ownerships about. */ if (tmpsq >= 0) own[tmpsq] = j; /* * We are done. We can add square i to omino j, * and then backtrack along the trail in tmp * moving squares between ominoes, ending up * expanding our starting omino by one. */ #ifdef DIVVY_DIAGNOSTICS printf("(%d,%d)", i%w, i/w); #endif while (1) { own[i] = j; #ifdef DIVVY_DIAGNOSTICS printf(" -> %d", j); #endif if (tmp[2*j] == -2) break; i = tmp[2*j+1]; j = tmp[2*j]; #ifdef DIVVY_DIAGNOSTICS printf("; (%d,%d)", i%w, i/w); #endif } #ifdef DIVVY_DIAGNOSTICS printf("\n"); #endif /* * Increment the size of the starting omino. */ sizes[j]++; /* * Terminate the bfs loop. */ break; } /* * If we get here, we haven't been able to expand * omino j into an unclaimed square. So now we begin * to investigate expanding it into squares which are * claimed by ominoes the bfs has not yet visited. */ for (i = 0; i < wh; i++) { int dir, nj; nj = own[order[i]]; if (nj < 0 || tmp[2*nj] != -1) continue; /* unclaimed, or owned by wrong omino */ if (!removable[order[i]]) continue; /* its omino won't let it go */ for (dir = 0; dir < 4; dir++) if (addable[order[i]*4+dir] == j) { /* * As above, re-check addremcommon. */ if (!addremcommon(w, h, order[i]%w, order[i]/w, own, j)) continue; /* * We have found a square we can use to * expand omino j, at the expense of the * as-yet unvisited omino nj. So add this * to the bfs queue. */ assert(qtail < n); queue[qtail++] = nj; tmp[2*nj] = j; tmp[2*nj+1] = order[i]; /* * Now terminate the loop over dir, to * ensure we don't accidentally add the * same omino twice to the queue. */ break; } } /* * Restore the temporarily removed square. */ if (tmpsq >= 0) own[tmpsq] = j; /* * Advance the queue head. */ qhead++; } if (qhead == qtail) { /* * We have finished the bfs and not found any way to * expand omino j. Panic, and return failure. * * FIXME: or should we loop over all ominoes before we * give up? */ #ifdef DIVVY_DIAGNOSTICS printf("FAIL!\n"); #endif retdsf = NULL; goto cleanup; } } #ifdef DIVVY_DIAGNOSTICS { int x, y; printf("SUCCESS! Final grid:\n"); for (y = 0; y < h; y++) { for (x = 0; x < w; x++) printf("%3d", own[y*w+x]); printf("\n"); } } #endif /* * Construct the output dsf. */ for (i = 0; i < wh; i++) { assert(own[i] >= 0 && own[i] < n); tmp[own[i]] = i; } retdsf = snew_dsf(wh); for (i = 0; i < wh; i++) { dsf_merge(retdsf, i, tmp[own[i]]); } /* * Construct the output dsf a different way, to verify that * the ominoes really are k-ominoes and we haven't * accidentally split one into two disconnected pieces. */ dsf_init(tmp, wh); for (y = 0; y < h; y++) for (x = 0; x+1 < w; x++) if (own[y*w+x] == own[y*w+(x+1)]) dsf_merge(tmp, y*w+x, y*w+(x+1)); for (x = 0; x < w; x++) for (y = 0; y+1 < h; y++) if (own[y*w+x] == own[(y+1)*w+x]) dsf_merge(tmp, y*w+x, (y+1)*w+x); for (i = 0; i < wh; i++) { j = dsf_canonify(retdsf, i); assert(dsf_canonify(tmp, j) == dsf_canonify(tmp, i)); } cleanup: /* * Free our temporary working space. */ sfree(order); sfree(tmp); sfree(own); sfree(sizes); sfree(queue); sfree(addable); sfree(removable); /* * And we're done. */ return retdsf; } #ifdef TESTMODE static int fail_counter = 0; #endif int *divvy_rectangle(int w, int h, int k, random_state *rs) { int *ret; do { ret = divvy_internal(w, h, k, rs); #ifdef TESTMODE if (!ret) fail_counter++; #endif } while (!ret); return ret; } #ifdef TESTMODE /* * gcc -g -O0 -DTESTMODE -I.. -o divvy divvy.c ../random.c ../malloc.c ../dsf.c ../misc.c ../nullfe.c * * or to debug * * gcc -g -O0 -DDIVVY_DIAGNOSTICS -DTESTMODE -I.. -o divvy divvy.c ../random.c ../malloc.c ../dsf.c ../misc.c ../nullfe.c */ int main(int argc, char **argv) { int *dsf; int i; int w = 9, h = 4, k = 6, tries = 100; random_state *rs; rs = random_new("123456", 6); if (argc > 1) w = atoi(argv[1]); if (argc > 2) h = atoi(argv[2]); if (argc > 3) k = atoi(argv[3]); if (argc > 4) tries = atoi(argv[4]); for (i = 0; i < tries; i++) { int x, y; dsf = divvy_rectangle(w, h, k, rs); assert(dsf); for (y = 0; y <= 2*h; y++) { for (x = 0; x <= 2*w; x++) { int miny = y/2 - 1, maxy = y/2; int minx = x/2 - 1, maxx = x/2; int classes[4], tx, ty; for (ty = 0; ty < 2; ty++) for (tx = 0; tx < 2; tx++) { int cx = minx+tx, cy = miny+ty; if (cx < 0 || cx >= w || cy < 0 || cy >= h) classes[ty*2+tx] = -1; else classes[ty*2+tx] = dsf_canonify(dsf, cy*w+cx); } switch (y%2 * 2 + x%2) { case 0: /* corner */ /* * Cases for the corner: * * - if all four surrounding squares belong * to the same omino, we print a space. * * - if the top two are the same and the * bottom two are the same, we print a * horizontal line. * * - if the left two are the same and the * right two are the same, we print a * vertical line. * * - otherwise, we print a cross. */ if (classes[0] == classes[1] && classes[1] == classes[2] && classes[2] == classes[3]) printf(" "); else if (classes[0] == classes[1] && classes[2] == classes[3]) printf("-"); else if (classes[0] == classes[2] && classes[1] == classes[3]) printf("|"); else printf("+"); break; case 1: /* horiz edge */ if (classes[1] == classes[3]) printf(" "); else printf("--"); break; case 2: /* vert edge */ if (classes[2] == classes[3]) printf(" "); else printf("|"); break; case 3: /* square centre */ printf(" "); break; } } printf("\n"); } printf("\n"); sfree(dsf); } printf("%d retries needed for %d successes\n", fail_counter, tries); return 0; } #endif puzzles-20170606.272beef/cube.c0000644000175000017500000014320313115373615014756 0ustar simonsimon/* * cube.c: Cube game. */ #include #include #include #include #include #include #include "puzzles.h" #define MAXVERTICES 20 #define MAXFACES 20 #define MAXORDER 4 struct solid { int nvertices; float vertices[MAXVERTICES * 3]; /* 3*npoints coordinates */ int order; int nfaces; int faces[MAXFACES * MAXORDER]; /* order*nfaces point indices */ float normals[MAXFACES * 3]; /* 3*npoints vector components */ float shear; /* isometric shear for nice drawing */ float border; /* border required around arena */ }; static const struct solid s_tetrahedron = { 4, { 0.0F, -0.57735026919F, -0.20412414523F, -0.5F, 0.28867513459F, -0.20412414523F, 0.0F, -0.0F, 0.6123724357F, 0.5F, 0.28867513459F, -0.20412414523F, }, 3, 4, { 0,2,1, 3,1,2, 2,0,3, 1,3,0 }, { -0.816496580928F, -0.471404520791F, 0.333333333334F, 0.0F, 0.942809041583F, 0.333333333333F, 0.816496580928F, -0.471404520791F, 0.333333333334F, 0.0F, 0.0F, -1.0F, }, 0.0F, 0.3F }; static const struct solid s_cube = { 8, { -0.5F,-0.5F,-0.5F, -0.5F,-0.5F,+0.5F, -0.5F,+0.5F,-0.5F, -0.5F,+0.5F,+0.5F, +0.5F,-0.5F,-0.5F, +0.5F,-0.5F,+0.5F, +0.5F,+0.5F,-0.5F, +0.5F,+0.5F,+0.5F, }, 4, 6, { 0,1,3,2, 1,5,7,3, 5,4,6,7, 4,0,2,6, 0,4,5,1, 3,7,6,2 }, { -1.0F,0.0F,0.0F, 0.0F,0.0F,+1.0F, +1.0F,0.0F,0.0F, 0.0F,0.0F,-1.0F, 0.0F,-1.0F,0.0F, 0.0F,+1.0F,0.0F }, 0.3F, 0.5F }; static const struct solid s_octahedron = { 6, { -0.5F, -0.28867513459472505F, 0.4082482904638664F, 0.5F, 0.28867513459472505F, -0.4082482904638664F, -0.5F, 0.28867513459472505F, -0.4082482904638664F, 0.5F, -0.28867513459472505F, 0.4082482904638664F, 0.0F, -0.57735026918945009F, -0.4082482904638664F, 0.0F, 0.57735026918945009F, 0.4082482904638664F, }, 3, 8, { 4,0,2, 0,5,2, 0,4,3, 5,0,3, 1,4,2, 5,1,2, 4,1,3, 1,5,3 }, { -0.816496580928F, -0.471404520791F, -0.333333333334F, -0.816496580928F, 0.471404520791F, 0.333333333334F, 0.0F, -0.942809041583F, 0.333333333333F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F, -1.0F, 0.0F, 0.942809041583F, -0.333333333333F, 0.816496580928F, -0.471404520791F, -0.333333333334F, 0.816496580928F, 0.471404520791F, 0.333333333334F, }, 0.0F, 0.5F }; static const struct solid s_icosahedron = { 12, { 0.0F, 0.57735026919F, 0.75576131408F, 0.0F, -0.93417235896F, 0.17841104489F, 0.0F, 0.93417235896F, -0.17841104489F, 0.0F, -0.57735026919F, -0.75576131408F, -0.5F, -0.28867513459F, 0.75576131408F, -0.5F, 0.28867513459F, -0.75576131408F, 0.5F, -0.28867513459F, 0.75576131408F, 0.5F, 0.28867513459F, -0.75576131408F, -0.80901699437F, 0.46708617948F, 0.17841104489F, 0.80901699437F, 0.46708617948F, 0.17841104489F, -0.80901699437F, -0.46708617948F, -0.17841104489F, 0.80901699437F, -0.46708617948F, -0.17841104489F, }, 3, 20, { 8,0,2, 0,9,2, 1,10,3, 11,1,3, 0,4,6, 4,1,6, 5,2,7, 3,5,7, 4,8,10, 8,5,10, 9,6,11, 7,9,11, 0,8,4, 9,0,6, 10,1,4, 1,11,6, 8,2,5, 2,9,7, 3,10,5, 11,3,7, }, { -0.356822089773F, 0.87267799625F, 0.333333333333F, 0.356822089773F, 0.87267799625F, 0.333333333333F, -0.356822089773F, -0.87267799625F, -0.333333333333F, 0.356822089773F, -0.87267799625F, -0.333333333333F, -0.0F, 0.0F, 1.0F, 0.0F, -0.666666666667F, 0.745355992501F, 0.0F, 0.666666666667F, -0.745355992501F, 0.0F, 0.0F, -1.0F, -0.934172358963F, -0.12732200375F, 0.333333333333F, -0.934172358963F, 0.12732200375F, -0.333333333333F, 0.934172358963F, -0.12732200375F, 0.333333333333F, 0.934172358963F, 0.12732200375F, -0.333333333333F, -0.57735026919F, 0.333333333334F, 0.745355992501F, 0.57735026919F, 0.333333333334F, 0.745355992501F, -0.57735026919F, -0.745355992501F, 0.333333333334F, 0.57735026919F, -0.745355992501F, 0.333333333334F, -0.57735026919F, 0.745355992501F, -0.333333333334F, 0.57735026919F, 0.745355992501F, -0.333333333334F, -0.57735026919F, -0.333333333334F, -0.745355992501F, 0.57735026919F, -0.333333333334F, -0.745355992501F, }, 0.0F, 0.8F }; enum { TETRAHEDRON, CUBE, OCTAHEDRON, ICOSAHEDRON }; static const struct solid *solids[] = { &s_tetrahedron, &s_cube, &s_octahedron, &s_icosahedron }; enum { COL_BACKGROUND, COL_BORDER, COL_BLUE, NCOLOURS }; enum { LEFT, RIGHT, UP, DOWN, UP_LEFT, UP_RIGHT, DOWN_LEFT, DOWN_RIGHT }; #define PREFERRED_GRID_SCALE 48 #define GRID_SCALE (ds->gridscale) #define ROLLTIME 0.13F #define SQ(x) ( (x) * (x) ) #define MATMUL(ra,m,a) do { \ float rx, ry, rz, xx = (a)[0], yy = (a)[1], zz = (a)[2], *mat = (m); \ rx = mat[0] * xx + mat[3] * yy + mat[6] * zz; \ ry = mat[1] * xx + mat[4] * yy + mat[7] * zz; \ rz = mat[2] * xx + mat[5] * yy + mat[8] * zz; \ (ra)[0] = rx; (ra)[1] = ry; (ra)[2] = rz; \ } while (0) #define APPROXEQ(x,y) ( SQ(x-y) < 0.1 ) struct grid_square { float x, y; int npoints; float points[8]; /* maximum */ int directions[8]; /* bit masks showing point pairs */ int flip; int tetra_class; }; struct game_params { int solid; /* * Grid dimensions. For a square grid these are width and * height respectively; otherwise the grid is a hexagon, with * the top side and the two lower diagonals having length d1 * and the remaining three sides having length d2 (so that * d1==d2 gives a regular hexagon, and d2==0 gives a triangle). */ int d1, d2; }; typedef struct game_grid game_grid; struct game_grid { int refcount; struct grid_square *squares; int nsquares; }; #define SET_SQUARE(state, i, val) \ ((state)->bluemask[(i)/32] &= ~(1 << ((i)%32)), \ (state)->bluemask[(i)/32] |= ((!!val) << ((i)%32))) #define GET_SQUARE(state, i) \ (((state)->bluemask[(i)/32] >> ((i)%32)) & 1) struct game_state { struct game_params params; const struct solid *solid; int *facecolours; game_grid *grid; unsigned long *bluemask; int current; /* index of current grid square */ int sgkey[2]; /* key-point indices into grid sq */ int dgkey[2]; /* key-point indices into grid sq */ int spkey[2]; /* key-point indices into polyhedron */ int dpkey[2]; /* key-point indices into polyhedron */ int previous; float angle; int completed; int movecount; }; static game_params *default_params(void) { game_params *ret = snew(game_params); ret->solid = CUBE; ret->d1 = 4; ret->d2 = 4; return ret; } static int game_fetch_preset(int i, char **name, game_params **params) { game_params *ret = snew(game_params); char *str; switch (i) { case 0: str = "Cube"; ret->solid = CUBE; ret->d1 = 4; ret->d2 = 4; break; case 1: str = "Tetrahedron"; ret->solid = TETRAHEDRON; ret->d1 = 1; ret->d2 = 2; break; case 2: str = "Octahedron"; ret->solid = OCTAHEDRON; ret->d1 = 2; ret->d2 = 2; break; case 3: str = "Icosahedron"; ret->solid = ICOSAHEDRON; ret->d1 = 3; ret->d2 = 3; break; default: sfree(ret); return FALSE; } *name = dupstr(str); *params = ret; return TRUE; } static void free_params(game_params *params) { sfree(params); } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } static void decode_params(game_params *ret, char const *string) { switch (*string) { case 't': ret->solid = TETRAHEDRON; string++; break; case 'c': ret->solid = CUBE; string++; break; case 'o': ret->solid = OCTAHEDRON; string++; break; case 'i': ret->solid = ICOSAHEDRON; string++; break; default: break; } ret->d1 = ret->d2 = atoi(string); while (*string && isdigit((unsigned char)*string)) string++; if (*string == 'x') { string++; ret->d2 = atoi(string); } } static char *encode_params(const game_params *params, int full) { char data[256]; assert(params->solid >= 0 && params->solid < 4); sprintf(data, "%c%dx%d", "tcoi"[params->solid], params->d1, params->d2); return dupstr(data); } typedef void (*egc_callback)(void *, struct grid_square *); static void enum_grid_squares(const game_params *params, egc_callback callback, void *ctx) { const struct solid *solid = solids[params->solid]; if (solid->order == 4) { int x, y; for (y = 0; y < params->d2; y++) for (x = 0; x < params->d1; x++) { struct grid_square sq; sq.x = (float)x; sq.y = (float)y; sq.points[0] = x - 0.5F; sq.points[1] = y - 0.5F; sq.points[2] = x - 0.5F; sq.points[3] = y + 0.5F; sq.points[4] = x + 0.5F; sq.points[5] = y + 0.5F; sq.points[6] = x + 0.5F; sq.points[7] = y - 0.5F; sq.npoints = 4; sq.directions[LEFT] = 0x03; /* 0,1 */ sq.directions[RIGHT] = 0x0C; /* 2,3 */ sq.directions[UP] = 0x09; /* 0,3 */ sq.directions[DOWN] = 0x06; /* 1,2 */ sq.directions[UP_LEFT] = 0; /* no diagonals in a square */ sq.directions[UP_RIGHT] = 0; /* no diagonals in a square */ sq.directions[DOWN_LEFT] = 0; /* no diagonals in a square */ sq.directions[DOWN_RIGHT] = 0; /* no diagonals in a square */ sq.flip = FALSE; /* * This is supremely irrelevant, but just to avoid * having any uninitialised structure members... */ sq.tetra_class = 0; callback(ctx, &sq); } } else { int row, rowlen, other, i, firstix = -1; float theight = (float)(sqrt(3) / 2.0); for (row = 0; row < params->d1 + params->d2; row++) { if (row < params->d2) { other = +1; rowlen = row + params->d1; } else { other = -1; rowlen = 2*params->d2 + params->d1 - row; } /* * There are `rowlen' down-pointing triangles. */ for (i = 0; i < rowlen; i++) { struct grid_square sq; int ix; float x, y; ix = (2 * i - (rowlen-1)); x = ix * 0.5F; y = theight * row; sq.x = x; sq.y = y + theight / 3; sq.points[0] = x - 0.5F; sq.points[1] = y; sq.points[2] = x; sq.points[3] = y + theight; sq.points[4] = x + 0.5F; sq.points[5] = y; sq.npoints = 3; sq.directions[LEFT] = 0x03; /* 0,1 */ sq.directions[RIGHT] = 0x06; /* 1,2 */ sq.directions[UP] = 0x05; /* 0,2 */ sq.directions[DOWN] = 0; /* invalid move */ /* * Down-pointing triangle: both the up diagonals go * up, and the down ones go left and right. */ sq.directions[UP_LEFT] = sq.directions[UP_RIGHT] = sq.directions[UP]; sq.directions[DOWN_LEFT] = sq.directions[LEFT]; sq.directions[DOWN_RIGHT] = sq.directions[RIGHT]; sq.flip = TRUE; if (firstix < 0) firstix = ix & 3; ix -= firstix; sq.tetra_class = ((row+(ix&1)) & 2) ^ (ix & 3); callback(ctx, &sq); } /* * There are `rowlen+other' up-pointing triangles. */ for (i = 0; i < rowlen+other; i++) { struct grid_square sq; int ix; float x, y; ix = (2 * i - (rowlen+other-1)); x = ix * 0.5F; y = theight * row; sq.x = x; sq.y = y + 2*theight / 3; sq.points[0] = x + 0.5F; sq.points[1] = y + theight; sq.points[2] = x; sq.points[3] = y; sq.points[4] = x - 0.5F; sq.points[5] = y + theight; sq.npoints = 3; sq.directions[LEFT] = 0x06; /* 1,2 */ sq.directions[RIGHT] = 0x03; /* 0,1 */ sq.directions[DOWN] = 0x05; /* 0,2 */ sq.directions[UP] = 0; /* invalid move */ /* * Up-pointing triangle: both the down diagonals go * down, and the up ones go left and right. */ sq.directions[DOWN_LEFT] = sq.directions[DOWN_RIGHT] = sq.directions[DOWN]; sq.directions[UP_LEFT] = sq.directions[LEFT]; sq.directions[UP_RIGHT] = sq.directions[RIGHT]; sq.flip = FALSE; if (firstix < 0) firstix = (ix - 1) & 3; ix -= firstix; sq.tetra_class = ((row+(ix&1)) & 2) ^ (ix & 3); callback(ctx, &sq); } } } } static int grid_area(int d1, int d2, int order) { /* * An NxM grid of squares has NM squares in it. * * A grid of triangles with dimensions A and B has a total of * A^2 + B^2 + 4AB triangles in it. (You can divide it up into * a side-A triangle containing A^2 subtriangles, a side-B * triangle containing B^2, and two congruent parallelograms, * each with side lengths A and B, each therefore containing AB * two-triangle rhombuses.) */ if (order == 4) return d1 * d2; else return d1*d1 + d2*d2 + 4*d1*d2; } static config_item *game_configure(const game_params *params) { config_item *ret = snewn(4, config_item); char buf[80]; ret[0].name = "Type of solid"; ret[0].type = C_CHOICES; ret[0].sval = ":Tetrahedron:Cube:Octahedron:Icosahedron"; ret[0].ival = params->solid; ret[1].name = "Width / top"; ret[1].type = C_STRING; sprintf(buf, "%d", params->d1); ret[1].sval = dupstr(buf); ret[1].ival = 0; ret[2].name = "Height / bottom"; ret[2].type = C_STRING; sprintf(buf, "%d", params->d2); ret[2].sval = dupstr(buf); ret[2].ival = 0; ret[3].name = NULL; ret[3].type = C_END; ret[3].sval = NULL; ret[3].ival = 0; return ret; } static game_params *custom_params(const config_item *cfg) { game_params *ret = snew(game_params); ret->solid = cfg[0].ival; ret->d1 = atoi(cfg[1].sval); ret->d2 = atoi(cfg[2].sval); return ret; } static void count_grid_square_callback(void *ctx, struct grid_square *sq) { int *classes = (int *)ctx; int thisclass; if (classes[4] == 4) thisclass = sq->tetra_class; else if (classes[4] == 2) thisclass = sq->flip; else thisclass = 0; classes[thisclass]++; } static char *validate_params(const game_params *params, int full) { int classes[5]; int i; if (params->solid < 0 || params->solid >= lenof(solids)) return "Unrecognised solid type"; if (solids[params->solid]->order == 4) { if (params->d1 <= 0 || params->d2 <= 0) return "Both grid dimensions must be greater than zero"; } else { if (params->d1 <= 0 && params->d2 <= 0) return "At least one grid dimension must be greater than zero"; } for (i = 0; i < 4; i++) classes[i] = 0; if (params->solid == TETRAHEDRON) classes[4] = 4; else if (params->solid == OCTAHEDRON) classes[4] = 2; else classes[4] = 1; enum_grid_squares(params, count_grid_square_callback, classes); for (i = 0; i < classes[4]; i++) if (classes[i] < solids[params->solid]->nfaces / classes[4]) return "Not enough grid space to place all blue faces"; if (grid_area(params->d1, params->d2, solids[params->solid]->order) < solids[params->solid]->nfaces + 1) return "Not enough space to place the solid on an empty square"; return NULL; } struct grid_data { int *gridptrs[4]; int nsquares[4]; int nclasses; int squareindex; }; static void classify_grid_square_callback(void *ctx, struct grid_square *sq) { struct grid_data *data = (struct grid_data *)ctx; int thisclass; if (data->nclasses == 4) thisclass = sq->tetra_class; else if (data->nclasses == 2) thisclass = sq->flip; else thisclass = 0; data->gridptrs[thisclass][data->nsquares[thisclass]++] = data->squareindex++; } static char *new_game_desc(const game_params *params, random_state *rs, char **aux, int interactive) { struct grid_data data; int i, j, k, m, area, facesperclass; int *flags; char *desc, *p; /* * Enumerate the grid squares, dividing them into equivalence * classes as appropriate. (For the tetrahedron, there is one * equivalence class for each face; for the octahedron there * are two classes; for the other two solids there's only one.) */ area = grid_area(params->d1, params->d2, solids[params->solid]->order); if (params->solid == TETRAHEDRON) data.nclasses = 4; else if (params->solid == OCTAHEDRON) data.nclasses = 2; else data.nclasses = 1; data.gridptrs[0] = snewn(data.nclasses * area, int); for (i = 0; i < data.nclasses; i++) { data.gridptrs[i] = data.gridptrs[0] + i * area; data.nsquares[i] = 0; } data.squareindex = 0; enum_grid_squares(params, classify_grid_square_callback, &data); facesperclass = solids[params->solid]->nfaces / data.nclasses; for (i = 0; i < data.nclasses; i++) assert(data.nsquares[i] >= facesperclass); assert(data.squareindex == area); /* * So now we know how many faces to allocate in each class. Get * on with it. */ flags = snewn(area, int); for (i = 0; i < area; i++) flags[i] = FALSE; for (i = 0; i < data.nclasses; i++) { for (j = 0; j < facesperclass; j++) { int n = random_upto(rs, data.nsquares[i]); assert(!flags[data.gridptrs[i][n]]); flags[data.gridptrs[i][n]] = TRUE; /* * Move everything else up the array. I ought to use a * better data structure for this, but for such small * numbers it hardly seems worth the effort. */ while (n < data.nsquares[i]-1) { data.gridptrs[i][n] = data.gridptrs[i][n+1]; n++; } data.nsquares[i]--; } } /* * Now we know precisely which squares are blue. Encode this * information in hex. While we're looping over this, collect * the non-blue squares into a list in the now-unused gridptrs * array. */ desc = snewn(area / 4 + 40, char); p = desc; j = 0; k = 8; m = 0; for (i = 0; i < area; i++) { if (flags[i]) { j |= k; } else { data.gridptrs[0][m++] = i; } k >>= 1; if (!k) { *p++ = "0123456789ABCDEF"[j]; k = 8; j = 0; } } if (k != 8) *p++ = "0123456789ABCDEF"[j]; /* * Choose a non-blue square for the polyhedron. */ sprintf(p, ",%d", data.gridptrs[0][random_upto(rs, m)]); sfree(data.gridptrs[0]); sfree(flags); return desc; } static void add_grid_square_callback(void *ctx, struct grid_square *sq) { game_grid *grid = (game_grid *)ctx; grid->squares[grid->nsquares++] = *sq; /* structure copy */ } static int lowest_face(const struct solid *solid) { int i, j, best; float zmin; best = 0; zmin = 0.0; for (i = 0; i < solid->nfaces; i++) { float z = 0; for (j = 0; j < solid->order; j++) { int f = solid->faces[i*solid->order + j]; z += solid->vertices[f*3+2]; } if (i == 0 || zmin > z) { zmin = z; best = i; } } return best; } static int align_poly(const struct solid *solid, struct grid_square *sq, int *pkey) { float zmin; int i, j; int flip = (sq->flip ? -1 : +1); /* * First, find the lowest z-coordinate present in the solid. */ zmin = 0.0; for (i = 0; i < solid->nvertices; i++) if (zmin > solid->vertices[i*3+2]) zmin = solid->vertices[i*3+2]; /* * Now go round the grid square. For each point in the grid * square, we're looking for a point of the polyhedron with the * same x- and y-coordinates (relative to the square's centre), * and z-coordinate equal to zmin (near enough). */ for (j = 0; j < sq->npoints; j++) { int matches, index; matches = 0; index = -1; for (i = 0; i < solid->nvertices; i++) { float dist = 0; dist += SQ(solid->vertices[i*3+0] * flip - sq->points[j*2+0] + sq->x); dist += SQ(solid->vertices[i*3+1] * flip - sq->points[j*2+1] + sq->y); dist += SQ(solid->vertices[i*3+2] - zmin); if (dist < 0.1) { matches++; index = i; } } if (matches != 1 || index < 0) return FALSE; pkey[j] = index; } return TRUE; } static void flip_poly(struct solid *solid, int flip) { int i; if (flip) { for (i = 0; i < solid->nvertices; i++) { solid->vertices[i*3+0] *= -1; solid->vertices[i*3+1] *= -1; } for (i = 0; i < solid->nfaces; i++) { solid->normals[i*3+0] *= -1; solid->normals[i*3+1] *= -1; } } } static struct solid *transform_poly(const struct solid *solid, int flip, int key0, int key1, float angle) { struct solid *ret = snew(struct solid); float vx, vy, ax, ay; float vmatrix[9], amatrix[9], vmatrix2[9]; int i; *ret = *solid; /* structure copy */ flip_poly(ret, flip); /* * Now rotate the polyhedron through the given angle. We must * rotate about the Z-axis to bring the two vertices key0 and * key1 into horizontal alignment, then rotate about the * X-axis, then rotate back again. */ vx = ret->vertices[key1*3+0] - ret->vertices[key0*3+0]; vy = ret->vertices[key1*3+1] - ret->vertices[key0*3+1]; assert(APPROXEQ(vx*vx + vy*vy, 1.0)); vmatrix[0] = vx; vmatrix[3] = vy; vmatrix[6] = 0; vmatrix[1] = -vy; vmatrix[4] = vx; vmatrix[7] = 0; vmatrix[2] = 0; vmatrix[5] = 0; vmatrix[8] = 1; ax = (float)cos(angle); ay = (float)sin(angle); amatrix[0] = 1; amatrix[3] = 0; amatrix[6] = 0; amatrix[1] = 0; amatrix[4] = ax; amatrix[7] = ay; amatrix[2] = 0; amatrix[5] = -ay; amatrix[8] = ax; memcpy(vmatrix2, vmatrix, sizeof(vmatrix)); vmatrix2[1] = vy; vmatrix2[3] = -vy; for (i = 0; i < ret->nvertices; i++) { MATMUL(ret->vertices + 3*i, vmatrix, ret->vertices + 3*i); MATMUL(ret->vertices + 3*i, amatrix, ret->vertices + 3*i); MATMUL(ret->vertices + 3*i, vmatrix2, ret->vertices + 3*i); } for (i = 0; i < ret->nfaces; i++) { MATMUL(ret->normals + 3*i, vmatrix, ret->normals + 3*i); MATMUL(ret->normals + 3*i, amatrix, ret->normals + 3*i); MATMUL(ret->normals + 3*i, vmatrix2, ret->normals + 3*i); } return ret; } static char *validate_desc(const game_params *params, const char *desc) { int area = grid_area(params->d1, params->d2, solids[params->solid]->order); int i, j; i = (area + 3) / 4; for (j = 0; j < i; j++) { int c = desc[j]; if (c >= '0' && c <= '9') continue; if (c >= 'A' && c <= 'F') continue; if (c >= 'a' && c <= 'f') continue; return "Not enough hex digits at start of string"; /* NB if desc[j]=='\0' that will also be caught here, so we're safe */ } if (desc[i] != ',') return "Expected ',' after hex digits"; i++; do { if (desc[i] < '0' || desc[i] > '9') return "Expected decimal integer after ','"; i++; } while (desc[i]); return NULL; } static game_state *new_game(midend *me, const game_params *params, const char *desc) { game_grid *grid = snew(game_grid); game_state *state = snew(game_state); int area; state->params = *params; /* structure copy */ state->solid = solids[params->solid]; area = grid_area(params->d1, params->d2, state->solid->order); grid->squares = snewn(area, struct grid_square); grid->nsquares = 0; enum_grid_squares(params, add_grid_square_callback, grid); assert(grid->nsquares == area); state->grid = grid; grid->refcount = 1; state->facecolours = snewn(state->solid->nfaces, int); memset(state->facecolours, 0, state->solid->nfaces * sizeof(int)); state->bluemask = snewn((state->grid->nsquares + 31) / 32, unsigned long); memset(state->bluemask, 0, (state->grid->nsquares + 31) / 32 * sizeof(unsigned long)); /* * Set up the blue squares and polyhedron position according to * the game description. */ { const char *p = desc; int i, j, v; j = 8; v = 0; for (i = 0; i < state->grid->nsquares; i++) { if (j == 8) { v = *p++; if (v >= '0' && v <= '9') v -= '0'; else if (v >= 'A' && v <= 'F') v -= 'A' - 10; else if (v >= 'a' && v <= 'f') v -= 'a' - 10; else break; } if (v & j) SET_SQUARE(state, i, TRUE); j >>= 1; if (j == 0) j = 8; } if (*p == ',') p++; state->current = atoi(p); if (state->current < 0 || state->current >= state->grid->nsquares) state->current = 0; /* got to do _something_ */ } /* * Align the polyhedron with its grid square and determine * initial key points. */ { int pkey[4]; int ret; ret = align_poly(state->solid, &state->grid->squares[state->current], pkey); assert(ret); state->dpkey[0] = state->spkey[0] = pkey[0]; state->dpkey[1] = state->spkey[0] = pkey[1]; state->dgkey[0] = state->sgkey[0] = 0; state->dgkey[1] = state->sgkey[0] = 1; } state->previous = state->current; state->angle = 0.0; state->completed = 0; state->movecount = 0; return state; } static game_state *dup_game(const game_state *state) { game_state *ret = snew(game_state); ret->params = state->params; /* structure copy */ ret->solid = state->solid; ret->facecolours = snewn(ret->solid->nfaces, int); memcpy(ret->facecolours, state->facecolours, ret->solid->nfaces * sizeof(int)); ret->current = state->current; ret->grid = state->grid; ret->grid->refcount++; ret->bluemask = snewn((ret->grid->nsquares + 31) / 32, unsigned long); memcpy(ret->bluemask, state->bluemask, (ret->grid->nsquares + 31) / 32 * sizeof(unsigned long)); ret->dpkey[0] = state->dpkey[0]; ret->dpkey[1] = state->dpkey[1]; ret->dgkey[0] = state->dgkey[0]; ret->dgkey[1] = state->dgkey[1]; ret->spkey[0] = state->spkey[0]; ret->spkey[1] = state->spkey[1]; ret->sgkey[0] = state->sgkey[0]; ret->sgkey[1] = state->sgkey[1]; ret->previous = state->previous; ret->angle = state->angle; ret->completed = state->completed; ret->movecount = state->movecount; return ret; } static void free_game(game_state *state) { if (--state->grid->refcount <= 0) { sfree(state->grid->squares); sfree(state->grid); } sfree(state->bluemask); sfree(state->facecolours); sfree(state); } static char *solve_game(const game_state *state, const game_state *currstate, const char *aux, char **error) { return NULL; } static int game_can_format_as_text_now(const game_params *params) { return TRUE; } static char *game_text_format(const game_state *state) { return NULL; } static game_ui *new_ui(const game_state *state) { return NULL; } static void free_ui(game_ui *ui) { } static char *encode_ui(const game_ui *ui) { return NULL; } static void decode_ui(game_ui *ui, const char *encoding) { } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { } struct game_drawstate { float gridscale; int ox, oy; /* pixel position of float origin */ }; /* * Code shared between interpret_move() and execute_move(). */ static int find_move_dest(const game_state *from, int direction, int *skey, int *dkey) { int mask, dest, i, j; float points[4]; /* * Find the two points in the current grid square which * correspond to this move. */ mask = from->grid->squares[from->current].directions[direction]; if (mask == 0) return -1; for (i = j = 0; i < from->grid->squares[from->current].npoints; i++) if (mask & (1 << i)) { points[j*2] = from->grid->squares[from->current].points[i*2]; points[j*2+1] = from->grid->squares[from->current].points[i*2+1]; skey[j] = i; j++; } assert(j == 2); /* * Now find the other grid square which shares those points. * This is our move destination. */ dest = -1; for (i = 0; i < from->grid->nsquares; i++) if (i != from->current) { int match = 0; float dist; for (j = 0; j < from->grid->squares[i].npoints; j++) { dist = (SQ(from->grid->squares[i].points[j*2] - points[0]) + SQ(from->grid->squares[i].points[j*2+1] - points[1])); if (dist < 0.1) dkey[match++] = j; dist = (SQ(from->grid->squares[i].points[j*2] - points[2]) + SQ(from->grid->squares[i].points[j*2+1] - points[3])); if (dist < 0.1) dkey[match++] = j; } if (match == 2) { dest = i; break; } } return dest; } static char *interpret_move(const game_state *state, game_ui *ui, const game_drawstate *ds, int x, int y, int button) { int direction, mask, i; int skey[2], dkey[2]; button = button & (~MOD_MASK | MOD_NUM_KEYPAD); /* * Moves can be made with the cursor keys or numeric keypad, or * alternatively you can left-click and the polyhedron will * move in the general direction of the mouse pointer. */ if (button == CURSOR_UP || button == (MOD_NUM_KEYPAD | '8')) direction = UP; else if (button == CURSOR_DOWN || button == (MOD_NUM_KEYPAD | '2')) direction = DOWN; else if (button == CURSOR_LEFT || button == (MOD_NUM_KEYPAD | '4')) direction = LEFT; else if (button == CURSOR_RIGHT || button == (MOD_NUM_KEYPAD | '6')) direction = RIGHT; else if (button == (MOD_NUM_KEYPAD | '7')) direction = UP_LEFT; else if (button == (MOD_NUM_KEYPAD | '1')) direction = DOWN_LEFT; else if (button == (MOD_NUM_KEYPAD | '9')) direction = UP_RIGHT; else if (button == (MOD_NUM_KEYPAD | '3')) direction = DOWN_RIGHT; else if (button == LEFT_BUTTON) { /* * Find the bearing of the click point from the current * square's centre. */ int cx, cy; double angle; cx = (int)(state->grid->squares[state->current].x * GRID_SCALE) + ds->ox; cy = (int)(state->grid->squares[state->current].y * GRID_SCALE) + ds->oy; if (x == cx && y == cy) return NULL; /* clicked in exact centre! */ angle = atan2(y - cy, x - cx); /* * There are three possibilities. * * - This square is a square, so we choose between UP, * DOWN, LEFT and RIGHT by dividing the available angle * at the 45-degree points. * * - This square is an up-pointing triangle, so we choose * between DOWN, LEFT and RIGHT by dividing into * 120-degree arcs. * * - This square is a down-pointing triangle, so we choose * between UP, LEFT and RIGHT in the inverse manner. * * Don't forget that since our y-coordinates increase * downwards, `angle' is measured _clockwise_ from the * x-axis, not anticlockwise as most mathematicians would * instinctively assume. */ if (state->grid->squares[state->current].npoints == 4) { /* Square. */ if (fabs(angle) > 3*PI/4) direction = LEFT; else if (fabs(angle) < PI/4) direction = RIGHT; else if (angle > 0) direction = DOWN; else direction = UP; } else if (state->grid->squares[state->current].directions[UP] == 0) { /* Up-pointing triangle. */ if (angle < -PI/2 || angle > 5*PI/6) direction = LEFT; else if (angle > PI/6) direction = DOWN; else direction = RIGHT; } else { /* Down-pointing triangle. */ assert(state->grid->squares[state->current].directions[DOWN] == 0); if (angle > PI/2 || angle < -5*PI/6) direction = LEFT; else if (angle < -PI/6) direction = UP; else direction = RIGHT; } } else return NULL; mask = state->grid->squares[state->current].directions[direction]; if (mask == 0) return NULL; /* * Translate diagonal directions into orthogonal ones. */ if (direction > DOWN) { for (i = LEFT; i <= DOWN; i++) if (state->grid->squares[state->current].directions[i] == mask) { direction = i; break; } assert(direction <= DOWN); } if (find_move_dest(state, direction, skey, dkey) < 0) return NULL; if (direction == LEFT) return dupstr("L"); if (direction == RIGHT) return dupstr("R"); if (direction == UP) return dupstr("U"); if (direction == DOWN) return dupstr("D"); return NULL; /* should never happen */ } static game_state *execute_move(const game_state *from, const char *move) { game_state *ret; float angle; struct solid *poly; int pkey[2]; int skey[2], dkey[2]; int i, j, dest; int direction; switch (*move) { case 'L': direction = LEFT; break; case 'R': direction = RIGHT; break; case 'U': direction = UP; break; case 'D': direction = DOWN; break; default: return NULL; } dest = find_move_dest(from, direction, skey, dkey); if (dest < 0) return NULL; ret = dup_game(from); ret->current = dest; /* * So we know what grid square we're aiming for, and we also * know the two key points (as indices in both the source and * destination grid squares) which are invariant between source * and destination. * * Next we must roll the polyhedron on to that square. So we * find the indices of the key points within the polyhedron's * vertex array, then use those in a call to transform_poly, * and align the result on the new grid square. */ { int all_pkey[4]; align_poly(from->solid, &from->grid->squares[from->current], all_pkey); pkey[0] = all_pkey[skey[0]]; pkey[1] = all_pkey[skey[1]]; /* * Now pkey[0] corresponds to skey[0] and dkey[0], and * likewise [1]. */ } /* * Now find the angle through which to rotate the polyhedron. * Do this by finding the two faces that share the two vertices * we've found, and taking the dot product of their normals. */ { int f[2], nf = 0; float dp; for (i = 0; i < from->solid->nfaces; i++) { int match = 0; for (j = 0; j < from->solid->order; j++) if (from->solid->faces[i*from->solid->order + j] == pkey[0] || from->solid->faces[i*from->solid->order + j] == pkey[1]) match++; if (match == 2) { assert(nf < 2); f[nf++] = i; } } assert(nf == 2); dp = 0; for (i = 0; i < 3; i++) dp += (from->solid->normals[f[0]*3+i] * from->solid->normals[f[1]*3+i]); angle = (float)acos(dp); } /* * Now transform the polyhedron. We aren't entirely sure * whether we need to rotate through angle or -angle, and the * simplest way round this is to try both and see which one * aligns successfully! * * Unfortunately, _both_ will align successfully if this is a * cube, which won't tell us anything much. So for that * particular case, I resort to gross hackery: I simply negate * the angle before trying the alignment, depending on the * direction. Which directions work which way is determined by * pure trial and error. I said it was gross :-/ */ { int all_pkey[4]; int success; if (from->solid->order == 4 && direction == UP) angle = -angle; /* HACK */ poly = transform_poly(from->solid, from->grid->squares[from->current].flip, pkey[0], pkey[1], angle); flip_poly(poly, from->grid->squares[ret->current].flip); success = align_poly(poly, &from->grid->squares[ret->current], all_pkey); if (!success) { sfree(poly); angle = -angle; poly = transform_poly(from->solid, from->grid->squares[from->current].flip, pkey[0], pkey[1], angle); flip_poly(poly, from->grid->squares[ret->current].flip); success = align_poly(poly, &from->grid->squares[ret->current], all_pkey); } assert(success); } /* * Now we have our rotated polyhedron, which we expect to be * exactly congruent to the one we started with - but with the * faces permuted. So we map that congruence and thereby figure * out how to permute the faces as a result of the polyhedron * having rolled. */ { int *newcolours = snewn(from->solid->nfaces, int); for (i = 0; i < from->solid->nfaces; i++) newcolours[i] = -1; for (i = 0; i < from->solid->nfaces; i++) { int nmatch = 0; /* * Now go through the transformed polyhedron's faces * and figure out which one's normal is approximately * equal to this one. */ for (j = 0; j < poly->nfaces; j++) { float dist; int k; dist = 0; for (k = 0; k < 3; k++) dist += SQ(poly->normals[j*3+k] - from->solid->normals[i*3+k]); if (APPROXEQ(dist, 0)) { nmatch++; newcolours[i] = ret->facecolours[j]; } } assert(nmatch == 1); } for (i = 0; i < from->solid->nfaces; i++) assert(newcolours[i] != -1); sfree(ret->facecolours); ret->facecolours = newcolours; } ret->movecount++; /* * And finally, swap the colour between the bottom face of the * polyhedron and the face we've just landed on. * * We don't do this if the game is already complete, since we * allow the user to roll the fully blue polyhedron around the * grid as a feeble reward. */ if (!ret->completed) { i = lowest_face(from->solid); j = ret->facecolours[i]; ret->facecolours[i] = GET_SQUARE(ret, ret->current); SET_SQUARE(ret, ret->current, j); /* * Detect game completion. */ j = 0; for (i = 0; i < ret->solid->nfaces; i++) if (ret->facecolours[i]) j++; if (j == ret->solid->nfaces) ret->completed = ret->movecount; } sfree(poly); /* * Align the normal polyhedron with its grid square, to get key * points for non-animated display. */ { int pkey[4]; int success; success = align_poly(ret->solid, &ret->grid->squares[ret->current], pkey); assert(success); ret->dpkey[0] = pkey[0]; ret->dpkey[1] = pkey[1]; ret->dgkey[0] = 0; ret->dgkey[1] = 1; } ret->spkey[0] = pkey[0]; ret->spkey[1] = pkey[1]; ret->sgkey[0] = skey[0]; ret->sgkey[1] = skey[1]; ret->previous = from->current; ret->angle = angle; return ret; } /* ---------------------------------------------------------------------- * Drawing routines. */ struct bbox { float l, r, u, d; }; static void find_bbox_callback(void *ctx, struct grid_square *sq) { struct bbox *bb = (struct bbox *)ctx; int i; for (i = 0; i < sq->npoints; i++) { if (bb->l > sq->points[i*2]) bb->l = sq->points[i*2]; if (bb->r < sq->points[i*2]) bb->r = sq->points[i*2]; if (bb->u > sq->points[i*2+1]) bb->u = sq->points[i*2+1]; if (bb->d < sq->points[i*2+1]) bb->d = sq->points[i*2+1]; } } static struct bbox find_bbox(const game_params *params) { struct bbox bb; /* * These should be hugely more than the real bounding box will * be. */ bb.l = 2.0F * (params->d1 + params->d2); bb.r = -2.0F * (params->d1 + params->d2); bb.u = 2.0F * (params->d1 + params->d2); bb.d = -2.0F * (params->d1 + params->d2); enum_grid_squares(params, find_bbox_callback, &bb); return bb; } #define XSIZE(gs, bb, solid) \ ((int)(((bb).r - (bb).l + 2*(solid)->border) * gs)) #define YSIZE(gs, bb, solid) \ ((int)(((bb).d - (bb).u + 2*(solid)->border) * gs)) static void game_compute_size(const game_params *params, int tilesize, int *x, int *y) { struct bbox bb = find_bbox(params); *x = XSIZE(tilesize, bb, solids[params->solid]); *y = YSIZE(tilesize, bb, solids[params->solid]); } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { struct bbox bb = find_bbox(params); ds->gridscale = (float)tilesize; ds->ox = (int)(-(bb.l - solids[params->solid]->border) * ds->gridscale); ds->oy = (int)(-(bb.u - solids[params->solid]->border) * ds->gridscale); } static float *game_colours(frontend *fe, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float); frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]); ret[COL_BORDER * 3 + 0] = 0.0; ret[COL_BORDER * 3 + 1] = 0.0; ret[COL_BORDER * 3 + 2] = 0.0; ret[COL_BLUE * 3 + 0] = 0.0; ret[COL_BLUE * 3 + 1] = 0.0; ret[COL_BLUE * 3 + 2] = 1.0; *ncolours = NCOLOURS; return ret; } static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { struct game_drawstate *ds = snew(struct game_drawstate); ds->ox = ds->oy = 0; ds->gridscale = 0.0F; /* not decided yet */ return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { sfree(ds); } static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float animtime, float flashtime) { int i, j; struct bbox bb = find_bbox(&state->params); struct solid *poly; const int *pkey, *gkey; float t[3]; float angle; int square; draw_rect(dr, 0, 0, XSIZE(GRID_SCALE, bb, state->solid), YSIZE(GRID_SCALE, bb, state->solid), COL_BACKGROUND); if (dir < 0) { const game_state *t; /* * This is an Undo. So reverse the order of the states, and * run the roll timer backwards. */ assert(oldstate); t = oldstate; oldstate = state; state = t; animtime = ROLLTIME - animtime; } if (!oldstate) { oldstate = state; angle = 0.0; square = state->current; pkey = state->dpkey; gkey = state->dgkey; } else { angle = state->angle * animtime / ROLLTIME; square = state->previous; pkey = state->spkey; gkey = state->sgkey; } state = oldstate; for (i = 0; i < state->grid->nsquares; i++) { int coords[8]; for (j = 0; j < state->grid->squares[i].npoints; j++) { coords[2*j] = ((int)(state->grid->squares[i].points[2*j] * GRID_SCALE) + ds->ox); coords[2*j+1] = ((int)(state->grid->squares[i].points[2*j+1]*GRID_SCALE) + ds->oy); } draw_polygon(dr, coords, state->grid->squares[i].npoints, GET_SQUARE(state, i) ? COL_BLUE : COL_BACKGROUND, COL_BORDER); } /* * Now compute and draw the polyhedron. */ poly = transform_poly(state->solid, state->grid->squares[square].flip, pkey[0], pkey[1], angle); /* * Compute the translation required to align the two key points * on the polyhedron with the same key points on the current * face. */ for (i = 0; i < 3; i++) { float tc = 0.0; for (j = 0; j < 2; j++) { float grid_coord; if (i < 2) { grid_coord = state->grid->squares[square].points[gkey[j]*2+i]; } else { grid_coord = 0.0; } tc += (grid_coord - poly->vertices[pkey[j]*3+i]); } t[i] = tc / 2; } for (i = 0; i < poly->nvertices; i++) for (j = 0; j < 3; j++) poly->vertices[i*3+j] += t[j]; /* * Now actually draw each face. */ for (i = 0; i < poly->nfaces; i++) { float points[8]; int coords[8]; for (j = 0; j < poly->order; j++) { int f = poly->faces[i*poly->order + j]; points[j*2] = (poly->vertices[f*3+0] - poly->vertices[f*3+2] * poly->shear); points[j*2+1] = (poly->vertices[f*3+1] - poly->vertices[f*3+2] * poly->shear); } for (j = 0; j < poly->order; j++) { coords[j*2] = (int)floor(points[j*2] * GRID_SCALE) + ds->ox; coords[j*2+1] = (int)floor(points[j*2+1] * GRID_SCALE) + ds->oy; } /* * Find out whether these points are in a clockwise or * anticlockwise arrangement. If the latter, discard the * face because it's facing away from the viewer. * * This would involve fiddly winding-number stuff for a * general polygon, but for the simple parallelograms we'll * be seeing here, all we have to do is check whether the * corners turn right or left. So we'll take the vector * from point 0 to point 1, turn it right 90 degrees, * and check the sign of the dot product with that and the * next vector (point 1 to point 2). */ { float v1x = points[2]-points[0]; float v1y = points[3]-points[1]; float v2x = points[4]-points[2]; float v2y = points[5]-points[3]; float dp = v1x * v2y - v1y * v2x; if (dp <= 0) continue; } draw_polygon(dr, coords, poly->order, state->facecolours[i] ? COL_BLUE : COL_BACKGROUND, COL_BORDER); } sfree(poly); draw_update(dr, 0, 0, XSIZE(GRID_SCALE, bb, state->solid), YSIZE(GRID_SCALE, bb, state->solid)); /* * Update the status bar. */ { char statusbuf[256]; sprintf(statusbuf, "%sMoves: %d", (state->completed ? "COMPLETED! " : ""), (state->completed ? state->completed : state->movecount)); status_bar(dr, statusbuf); } } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return ROLLTIME; } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return 0.0F; } static int game_status(const game_state *state) { return state->completed ? +1 : 0; } static int game_timing_state(const game_state *state, game_ui *ui) { return TRUE; } static void game_print_size(const game_params *params, float *x, float *y) { } static void game_print(drawing *dr, const game_state *state, int tilesize) { } #ifdef COMBINED #define thegame cube #endif const struct game thegame = { "Cube", "games.cube", "cube", default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, FALSE, solve_game, FALSE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, PREFERRED_GRID_SCALE, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, FALSE, FALSE, game_print_size, game_print, TRUE, /* wants_statusbar */ FALSE, game_timing_state, 0, /* flags */ }; puzzles-20170606.272beef/combi.c0000644000175000017500000000371413115373615015133 0ustar simonsimon#include #include #include "puzzles.h" /* horrific and doesn't check overflow. */ static long factx(long x, long y) { long acc = 1, i; for (i = y; i <= x; i++) acc *= i; return acc; } void reset_combi(combi_ctx *combi) { int i; combi->nleft = combi->total; for (i = 0; i < combi->r; i++) combi->a[i] = i; } combi_ctx *new_combi(int r, int n) { long nfr, nrf; combi_ctx *combi; assert(r <= n); assert(n >= 1); combi = snew(combi_ctx); memset(combi, 0, sizeof(combi_ctx)); combi->r = r; combi->n = n; combi->a = snewn(r, int); memset(combi->a, 0, r * sizeof(int)); nfr = factx(n, r+1); nrf = factx(n-r, 1); combi->total = (int)(nfr / nrf); reset_combi(combi); return combi; } /* returns NULL when we're done otherwise returns input. */ combi_ctx *next_combi(combi_ctx *combi) { int i = combi->r - 1, j; if (combi->nleft == combi->total) goto done; else if (combi->nleft <= 0) return NULL; while (combi->a[i] == combi->n - combi->r + i) i--; combi->a[i] += 1; for (j = i+1; j < combi->r; j++) combi->a[j] = combi->a[i] + j - i; done: combi->nleft--; return combi; } void free_combi(combi_ctx *combi) { sfree(combi->a); sfree(combi); } /* compile this with: * gcc -o combi.exe -DSTANDALONE_COMBI_TEST combi.c malloc.c */ #ifdef STANDALONE_COMBI_TEST #include void fatal(char *fmt, ...) { abort(); } int main(int argc, char *argv[]) { combi_ctx *c; int i, r, n; if (argc < 3) { fprintf(stderr, "Usage: combi R N\n"); exit(1); } r = atoi(argv[1]); n = atoi(argv[2]); c = new_combi(r, n); printf("combi %d of %d, %d elements.\n", c->r, c->n, c->total); while (next_combi(c)) { for (i = 0; i < c->r; i++) { printf("%d ", c->a[i]); } printf("\n"); } free_combi(c); } #endif puzzles-20170606.272beef/bridges.c0000644000175000017500000032046013115373615015461 0ustar simonsimon/* * bridges.c: Implementation of the Nikoli game 'Bridges'. * * Things still to do: * * - The solver's algorithmic design is not really ideal. It makes * use of the same data representation as gameplay uses, which * often looks like a tempting reuse of code but isn't always a * good idea. In this case, it's unpleasant that each edge of the * graph ends up represented as multiple squares on a grid, with * flags indicating when edges and non-edges cross; that's useful * when the result can be directly translated into positions of * graphics on the display, but in purely internal work it makes * even simple manipulations during solving more painful than they * should be, and complex ones have no choice but to modify the * data structures temporarily, test things, and put them back. I * envisage a complete solver rewrite along the following lines: * + We have a collection of vertices (islands) and edges * (potential bridge locations, i.e. pairs of horizontal or * vertical islands with no other island in between). * + Each edge has an associated list of edges that cross it, and * hence with which it is mutually exclusive. * + For each edge, we track the min and max number of bridges we * currently think possible. * + For each vertex, we track the number of _liberties_ it has, * i.e. its clue number minus the min bridge count for each edge * out of it. * + We also maintain a dsf that identifies sets of vertices which * are connected components of the puzzle so far, and for each * equivalence class we track the total number of liberties for * that component. (The dsf mechanism will also already track * the size of each component, i.e. number of islands.) * + So incrementing the min for an edge requires processing along * the lines of: * - set the max for all edges crossing that one to zero * - decrement the liberty count for the vertex at each end, * and also for each vertex's equivalence class (NB they may * be the same class) * - unify the two equivalence classes if they're not already, * and if so, set the liberty count for the new class to be * the sum of the previous two. * + Decrementing the max is much easier, however. * + With this data structure the really fiddly stuff in stage3() * becomes more or less trivial, because it's now a quick job to * find out whether an island would form an isolated subgraph if * connected to a given subset of its neighbours: * - identify the connected components containing the test * vertex and its putative new neighbours (but be careful not * to count a component more than once if two or more of the * vertices involved are already in the same one) * - find the sum of those components' liberty counts, and also * the total number of islands involved * - if the total liberty count of the connected components is * exactly equal to twice the number of edges we'd be adding * (of course each edge destroys two liberties, one at each * end) then these components would become a subgraph with * zero liberties if connected together. * - therefore, if that subgraph also contains fewer than the * total number of islands, it's disallowed. * - As mentioned in stage3(), once we've identified such a * disallowed pattern, we have two choices for what to do * with it: if the candidate set of neighbours has size 1 we * can reduce the max for the edge to that one neighbour, * whereas if its complement has size 1 we can increase the * min for the edge to the _omitted_ neighbour. * * - write a recursive solver? */ #include #include #include #include #include #include #include "puzzles.h" /* Turn this on for hints about which lines are considered possibilities. */ #undef DRAW_GRID /* --- structures for params, state, etc. --- */ #define MAX_BRIDGES 4 #define PREFERRED_TILE_SIZE 24 #define TILE_SIZE (ds->tilesize) #define BORDER (TILE_SIZE / 2) #define COORD(x) ( (x) * TILE_SIZE + BORDER ) #define FROMCOORD(x) ( ((x) - BORDER + TILE_SIZE) / TILE_SIZE - 1 ) #define FLASH_TIME 0.50F enum { COL_BACKGROUND, COL_FOREGROUND, COL_HIGHLIGHT, COL_LOWLIGHT, COL_SELECTED, COL_MARK, COL_HINT, COL_GRID, COL_WARNING, COL_CURSOR, NCOLOURS }; struct game_params { int w, h, maxb; int islands, expansion; /* %age of island squares, %age chance of expansion */ int allowloops, difficulty; }; /* general flags used by all structs */ #define G_ISLAND 0x0001 #define G_LINEV 0x0002 /* contains a vert. line */ #define G_LINEH 0x0004 /* contains a horiz. line (mutex with LINEV) */ #define G_LINE (G_LINEV|G_LINEH) #define G_MARKV 0x0008 #define G_MARKH 0x0010 #define G_MARK (G_MARKV|G_MARKH) #define G_NOLINEV 0x0020 #define G_NOLINEH 0x0040 #define G_NOLINE (G_NOLINEV|G_NOLINEH) /* flags used by the error checker */ #define G_WARN 0x0080 /* flags used by the solver etc. */ #define G_SWEEP 0x1000 #define G_FLAGSH (G_LINEH|G_MARKH|G_NOLINEH) #define G_FLAGSV (G_LINEV|G_MARKV|G_NOLINEV) typedef unsigned int grid_type; /* change me later if we invent > 16 bits of flags. */ struct solver_state { int *dsf, *comptspaces; int *tmpdsf, *tmpcompspaces; int refcount; }; /* state->gridi is an optimisation; it stores the pointer to the island * structs indexed by (x,y). It's not strictly necessary (we could use * find234 instead), but Purify showed that board generation (mostly the solver) * was spending 60% of its time in find234. */ struct surrounds { /* cloned from lightup.c */ struct { int x, y, dx, dy, off; } points[4]; int npoints, nislands; }; struct island { game_state *state; int x, y, count; struct surrounds adj; }; struct game_state { int w, h, completed, solved, allowloops, maxb; grid_type *grid; struct island *islands; int n_islands, n_islands_alloc; game_params params; /* used by the aux solver. */ #define N_WH_ARRAYS 5 char *wha, *possv, *possh, *lines, *maxv, *maxh; struct island **gridi; struct solver_state *solver; /* refcounted */ }; #define GRIDSZ(s) ((s)->w * (s)->h * sizeof(grid_type)) #define INGRID(s,x,y) ((x) >= 0 && (x) < (s)->w && (y) >= 0 && (y) < (s)->h) #define DINDEX(x,y) ((y)*state->w + (x)) #define INDEX(s,g,x,y) ((s)->g[(y)*((s)->w) + (x)]) #define IDX(s,g,i) ((s)->g[(i)]) #define GRID(s,x,y) INDEX(s,grid,x,y) #define POSSIBLES(s,dx,x,y) ((dx) ? (INDEX(s,possh,x,y)) : (INDEX(s,possv,x,y))) #define MAXIMUM(s,dx,x,y) ((dx) ? (INDEX(s,maxh,x,y)) : (INDEX(s,maxv,x,y))) #define GRIDCOUNT(s,x,y,f) ((GRID(s,x,y) & (f)) ? (INDEX(s,lines,x,y)) : 0) #define WITHIN2(x,min,max) (((x) < (min)) ? 0 : (((x) > (max)) ? 0 : 1)) #define WITHIN(x,min,max) ((min) > (max) ? \ WITHIN2(x,max,min) : WITHIN2(x,min,max)) /* --- island struct and tree support functions --- */ #define ISLAND_ORTH(is,j,f,df) \ (is->f + (is->adj.points[(j)].off*is->adj.points[(j)].df)) #define ISLAND_ORTHX(is,j) ISLAND_ORTH(is,j,x,dx) #define ISLAND_ORTHY(is,j) ISLAND_ORTH(is,j,y,dy) static void fixup_islands_for_realloc(game_state *state) { int i; for (i = 0; i < state->w*state->h; i++) state->gridi[i] = NULL; for (i = 0; i < state->n_islands; i++) { struct island *is = &state->islands[i]; is->state = state; INDEX(state, gridi, is->x, is->y) = is; } } static int game_can_format_as_text_now(const game_params *params) { return TRUE; } static char *game_text_format(const game_state *state) { int x, y, len, nl; char *ret, *p; struct island *is; grid_type grid; len = (state->h) * (state->w+1) + 1; ret = snewn(len, char); p = ret; for (y = 0; y < state->h; y++) { for (x = 0; x < state->w; x++) { grid = GRID(state,x,y); nl = INDEX(state,lines,x,y); is = INDEX(state, gridi, x, y); if (is) { *p++ = '0' + is->count; } else if (grid & G_LINEV) { *p++ = (nl > 1) ? '"' : (nl == 1) ? '|' : '!'; /* gaah, want a double-bar. */ } else if (grid & G_LINEH) { *p++ = (nl > 1) ? '=' : (nl == 1) ? '-' : '~'; } else { *p++ = '.'; } } *p++ = '\n'; } *p++ = '\0'; assert(p - ret == len); return ret; } static void debug_state(game_state *state) { char *textversion = game_text_format(state); debug(("%s", textversion)); sfree(textversion); } /*static void debug_possibles(game_state *state) { int x, y; debug(("possh followed by possv\n")); for (y = 0; y < state->h; y++) { for (x = 0; x < state->w; x++) { debug(("%d", POSSIBLES(state, 1, x, y))); } debug((" ")); for (x = 0; x < state->w; x++) { debug(("%d", POSSIBLES(state, 0, x, y))); } debug(("\n")); } debug(("\n")); for (y = 0; y < state->h; y++) { for (x = 0; x < state->w; x++) { debug(("%d", MAXIMUM(state, 1, x, y))); } debug((" ")); for (x = 0; x < state->w; x++) { debug(("%d", MAXIMUM(state, 0, x, y))); } debug(("\n")); } debug(("\n")); }*/ static void island_set_surrounds(struct island *is) { assert(INGRID(is->state,is->x,is->y)); is->adj.npoints = is->adj.nislands = 0; #define ADDPOINT(cond,ddx,ddy) do {\ if (cond) { \ is->adj.points[is->adj.npoints].x = is->x+(ddx); \ is->adj.points[is->adj.npoints].y = is->y+(ddy); \ is->adj.points[is->adj.npoints].dx = (ddx); \ is->adj.points[is->adj.npoints].dy = (ddy); \ is->adj.points[is->adj.npoints].off = 0; \ is->adj.npoints++; \ } } while(0) ADDPOINT(is->x > 0, -1, 0); ADDPOINT(is->x < (is->state->w-1), +1, 0); ADDPOINT(is->y > 0, 0, -1); ADDPOINT(is->y < (is->state->h-1), 0, +1); } static void island_find_orthogonal(struct island *is) { /* fills in the rest of the 'surrounds' structure, assuming * all other islands are now in place. */ int i, x, y, dx, dy, off; is->adj.nislands = 0; for (i = 0; i < is->adj.npoints; i++) { dx = is->adj.points[i].dx; dy = is->adj.points[i].dy; x = is->x + dx; y = is->y + dy; off = 1; is->adj.points[i].off = 0; while (INGRID(is->state, x, y)) { if (GRID(is->state, x, y) & G_ISLAND) { is->adj.points[i].off = off; is->adj.nislands++; /*debug(("island (%d,%d) has orth is. %d*(%d,%d) away at (%d,%d).\n", is->x, is->y, off, dx, dy, ISLAND_ORTHX(is,i), ISLAND_ORTHY(is,i)));*/ goto foundisland; } off++; x += dx; y += dy; } foundisland: ; } } static int island_hasbridge(struct island *is, int direction) { int x = is->adj.points[direction].x; int y = is->adj.points[direction].y; grid_type gline = is->adj.points[direction].dx ? G_LINEH : G_LINEV; if (GRID(is->state, x, y) & gline) return 1; return 0; } static struct island *island_find_connection(struct island *is, int adjpt) { struct island *is_r; assert(adjpt < is->adj.npoints); if (!is->adj.points[adjpt].off) return NULL; if (!island_hasbridge(is, adjpt)) return NULL; is_r = INDEX(is->state, gridi, ISLAND_ORTHX(is, adjpt), ISLAND_ORTHY(is, adjpt)); assert(is_r); return is_r; } static struct island *island_add(game_state *state, int x, int y, int count) { struct island *is; int realloced = 0; assert(!(GRID(state,x,y) & G_ISLAND)); GRID(state,x,y) |= G_ISLAND; state->n_islands++; if (state->n_islands > state->n_islands_alloc) { state->n_islands_alloc = state->n_islands * 2; state->islands = sresize(state->islands, state->n_islands_alloc, struct island); realloced = 1; } is = &state->islands[state->n_islands-1]; memset(is, 0, sizeof(struct island)); is->state = state; is->x = x; is->y = y; is->count = count; island_set_surrounds(is); if (realloced) fixup_islands_for_realloc(state); else INDEX(state, gridi, x, y) = is; return is; } /* n = -1 means 'flip NOLINE flags [and set line to 0].' */ static void island_join(struct island *i1, struct island *i2, int n, int is_max) { game_state *state = i1->state; int s, e, x, y; assert(i1->state == i2->state); assert(n >= -1 && n <= i1->state->maxb); if (i1->x == i2->x) { x = i1->x; if (i1->y < i2->y) { s = i1->y+1; e = i2->y-1; } else { s = i2->y+1; e = i1->y-1; } for (y = s; y <= e; y++) { if (is_max) { INDEX(state,maxv,x,y) = n; } else { if (n < 0) { GRID(state,x,y) ^= G_NOLINEV; } else if (n == 0) { GRID(state,x,y) &= ~G_LINEV; } else { GRID(state,x,y) |= G_LINEV; INDEX(state,lines,x,y) = n; } } } } else if (i1->y == i2->y) { y = i1->y; if (i1->x < i2->x) { s = i1->x+1; e = i2->x-1; } else { s = i2->x+1; e = i1->x-1; } for (x = s; x <= e; x++) { if (is_max) { INDEX(state,maxh,x,y) = n; } else { if (n < 0) { GRID(state,x,y) ^= G_NOLINEH; } else if (n == 0) { GRID(state,x,y) &= ~G_LINEH; } else { GRID(state,x,y) |= G_LINEH; INDEX(state,lines,x,y) = n; } } } } else { assert(!"island_join: islands not orthogonal."); } } /* Counts the number of bridges currently attached to the island. */ static int island_countbridges(struct island *is) { int i, c = 0; for (i = 0; i < is->adj.npoints; i++) { c += GRIDCOUNT(is->state, is->adj.points[i].x, is->adj.points[i].y, is->adj.points[i].dx ? G_LINEH : G_LINEV); } /*debug(("island count for (%d,%d) is %d.\n", is->x, is->y, c));*/ return c; } static int island_adjspace(struct island *is, int marks, int missing, int direction) { int x, y, poss, curr, dx; grid_type gline, mline; x = is->adj.points[direction].x; y = is->adj.points[direction].y; dx = is->adj.points[direction].dx; gline = dx ? G_LINEH : G_LINEV; if (marks) { mline = dx ? G_MARKH : G_MARKV; if (GRID(is->state,x,y) & mline) return 0; } poss = POSSIBLES(is->state, dx, x, y); poss = min(poss, missing); curr = GRIDCOUNT(is->state, x, y, gline); poss = min(poss, MAXIMUM(is->state, dx, x, y) - curr); return poss; } /* Counts the number of bridge spaces left around the island; * expects the possibles to be up-to-date. */ static int island_countspaces(struct island *is, int marks) { int i, c = 0, missing; missing = is->count - island_countbridges(is); if (missing < 0) return 0; for (i = 0; i < is->adj.npoints; i++) { c += island_adjspace(is, marks, missing, i); } return c; } static int island_isadj(struct island *is, int direction) { int x, y; grid_type gline, mline; x = is->adj.points[direction].x; y = is->adj.points[direction].y; mline = is->adj.points[direction].dx ? G_MARKH : G_MARKV; gline = is->adj.points[direction].dx ? G_LINEH : G_LINEV; if (GRID(is->state, x, y) & mline) { /* If we're marked (i.e. the thing to attach to is complete) * only count an adjacency if we're already attached. */ return GRIDCOUNT(is->state, x, y, gline); } else { /* If we're unmarked, count possible adjacency iff it's * flagged as POSSIBLE. */ return POSSIBLES(is->state, is->adj.points[direction].dx, x, y); } return 0; } /* Counts the no. of possible adjacent islands (including islands * we're already connected to). */ static int island_countadj(struct island *is) { int i, nadj = 0; for (i = 0; i < is->adj.npoints; i++) { if (island_isadj(is, i)) nadj++; } return nadj; } static void island_togglemark(struct island *is) { int i, j, x, y, o; struct island *is_loop; /* mark the island... */ GRID(is->state, is->x, is->y) ^= G_MARK; /* ...remove all marks on non-island squares... */ for (x = 0; x < is->state->w; x++) { for (y = 0; y < is->state->h; y++) { if (!(GRID(is->state, x, y) & G_ISLAND)) GRID(is->state, x, y) &= ~G_MARK; } } /* ...and add marks to squares around marked islands. */ for (i = 0; i < is->state->n_islands; i++) { is_loop = &is->state->islands[i]; if (!(GRID(is_loop->state, is_loop->x, is_loop->y) & G_MARK)) continue; for (j = 0; j < is_loop->adj.npoints; j++) { /* if this direction takes us to another island, mark all * squares between the two islands. */ if (!is_loop->adj.points[j].off) continue; assert(is_loop->adj.points[j].off > 1); for (o = 1; o < is_loop->adj.points[j].off; o++) { GRID(is_loop->state, is_loop->x + is_loop->adj.points[j].dx*o, is_loop->y + is_loop->adj.points[j].dy*o) |= is_loop->adj.points[j].dy ? G_MARKV : G_MARKH; } } } } static int island_impossible(struct island *is, int strict) { int curr = island_countbridges(is), nspc = is->count - curr, nsurrspc; int i, poss; struct island *is_orth; if (nspc < 0) { debug(("island at (%d,%d) impossible because full.\n", is->x, is->y)); return 1; /* too many bridges */ } else if ((curr + island_countspaces(is, 0)) < is->count) { debug(("island at (%d,%d) impossible because not enough spaces.\n", is->x, is->y)); return 1; /* impossible to create enough bridges */ } else if (strict && curr < is->count) { debug(("island at (%d,%d) impossible because locked.\n", is->x, is->y)); return 1; /* not enough bridges and island is locked */ } /* Count spaces in surrounding islands. */ nsurrspc = 0; for (i = 0; i < is->adj.npoints; i++) { int ifree, dx = is->adj.points[i].dx; if (!is->adj.points[i].off) continue; poss = POSSIBLES(is->state, dx, is->adj.points[i].x, is->adj.points[i].y); if (poss == 0) continue; is_orth = INDEX(is->state, gridi, ISLAND_ORTHX(is,i), ISLAND_ORTHY(is,i)); assert(is_orth); ifree = is_orth->count - island_countbridges(is_orth); if (ifree > 0) { /* * ifree is the number of bridges unfilled in the other * island, which is clearly an upper bound on the number * of extra bridges this island may run to it. * * Another upper bound is the number of bridges unfilled * on the specific line between here and there. We must * take the minimum of both. */ int bmax = MAXIMUM(is->state, dx, is->adj.points[i].x, is->adj.points[i].y); int bcurr = GRIDCOUNT(is->state, is->adj.points[i].x, is->adj.points[i].y, dx ? G_LINEH : G_LINEV); assert(bcurr <= bmax); nsurrspc += min(ifree, bmax - bcurr); } } if (nsurrspc < nspc) { debug(("island at (%d,%d) impossible: surr. islands %d spc, need %d.\n", is->x, is->y, nsurrspc, nspc)); return 1; /* not enough spaces around surrounding islands to fill this one. */ } return 0; } /* --- Game parameter functions --- */ #define DEFAULT_PRESET 0 const struct game_params bridges_presets[] = { { 7, 7, 2, 30, 10, 1, 0 }, { 7, 7, 2, 30, 10, 1, 1 }, { 7, 7, 2, 30, 10, 1, 2 }, { 10, 10, 2, 30, 10, 1, 0 }, { 10, 10, 2, 30, 10, 1, 1 }, { 10, 10, 2, 30, 10, 1, 2 }, { 15, 15, 2, 30, 10, 1, 0 }, { 15, 15, 2, 30, 10, 1, 1 }, { 15, 15, 2, 30, 10, 1, 2 }, }; static game_params *default_params(void) { game_params *ret = snew(game_params); *ret = bridges_presets[DEFAULT_PRESET]; return ret; } static int game_fetch_preset(int i, char **name, game_params **params) { game_params *ret; char buf[80]; if (i < 0 || i >= lenof(bridges_presets)) return FALSE; ret = default_params(); *ret = bridges_presets[i]; *params = ret; sprintf(buf, "%dx%d %s", ret->w, ret->h, ret->difficulty == 0 ? "easy" : ret->difficulty == 1 ? "medium" : "hard"); *name = dupstr(buf); return TRUE; } static void free_params(game_params *params) { sfree(params); } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } #define EATNUM(x) do { \ (x) = atoi(string); \ while (*string && isdigit((unsigned char)*string)) string++; \ } while(0) static void decode_params(game_params *params, char const *string) { EATNUM(params->w); params->h = params->w; if (*string == 'x') { string++; EATNUM(params->h); } if (*string == 'i') { string++; EATNUM(params->islands); } if (*string == 'e') { string++; EATNUM(params->expansion); } if (*string == 'm') { string++; EATNUM(params->maxb); } params->allowloops = 1; if (*string == 'L') { string++; params->allowloops = 0; } if (*string == 'd') { string++; EATNUM(params->difficulty); } } static char *encode_params(const game_params *params, int full) { char buf[80]; if (full) { sprintf(buf, "%dx%di%de%dm%d%sd%d", params->w, params->h, params->islands, params->expansion, params->maxb, params->allowloops ? "" : "L", params->difficulty); } else { sprintf(buf, "%dx%dm%d%s", params->w, params->h, params->maxb, params->allowloops ? "" : "L"); } return dupstr(buf); } static config_item *game_configure(const game_params *params) { config_item *ret; char buf[80]; ret = snewn(8, config_item); ret[0].name = "Width"; ret[0].type = C_STRING; sprintf(buf, "%d", params->w); ret[0].sval = dupstr(buf); ret[0].ival = 0; ret[1].name = "Height"; ret[1].type = C_STRING; sprintf(buf, "%d", params->h); ret[1].sval = dupstr(buf); ret[1].ival = 0; ret[2].name = "Difficulty"; ret[2].type = C_CHOICES; ret[2].sval = ":Easy:Medium:Hard"; ret[2].ival = params->difficulty; ret[3].name = "Allow loops"; ret[3].type = C_BOOLEAN; ret[3].sval = NULL; ret[3].ival = params->allowloops; ret[4].name = "Max. bridges per direction"; ret[4].type = C_CHOICES; ret[4].sval = ":1:2:3:4"; /* keep up-to-date with MAX_BRIDGES */ ret[4].ival = params->maxb - 1; ret[5].name = "%age of island squares"; ret[5].type = C_CHOICES; ret[5].sval = ":5%:10%:15%:20%:25%:30%"; ret[5].ival = (params->islands / 5)-1; ret[6].name = "Expansion factor (%age)"; ret[6].type = C_CHOICES; ret[6].sval = ":0%:10%:20%:30%:40%:50%:60%:70%:80%:90%:100%"; ret[6].ival = params->expansion / 10; ret[7].name = NULL; ret[7].type = C_END; ret[7].sval = NULL; ret[7].ival = 0; return ret; } static game_params *custom_params(const config_item *cfg) { game_params *ret = snew(game_params); ret->w = atoi(cfg[0].sval); ret->h = atoi(cfg[1].sval); ret->difficulty = cfg[2].ival; ret->allowloops = cfg[3].ival; ret->maxb = cfg[4].ival + 1; ret->islands = (cfg[5].ival + 1) * 5; ret->expansion = cfg[6].ival * 10; return ret; } static char *validate_params(const game_params *params, int full) { if (params->w < 3 || params->h < 3) return "Width and height must be at least 3"; if (params->maxb < 1 || params->maxb > MAX_BRIDGES) return "Too many bridges."; if (full) { if (params->islands <= 0 || params->islands > 30) return "%age of island squares must be between 1% and 30%"; if (params->expansion < 0 || params->expansion > 100) return "Expansion factor must be between 0 and 100"; } return NULL; } /* --- Game encoding and differences --- */ static char *encode_game(game_state *state) { char *ret, *p; int wh = state->w*state->h, run, x, y; struct island *is; ret = snewn(wh + 1, char); p = ret; run = 0; for (y = 0; y < state->h; y++) { for (x = 0; x < state->w; x++) { is = INDEX(state, gridi, x, y); if (is) { if (run) { *p++ = ('a'-1) + run; run = 0; } if (is->count < 10) *p++ = '0' + is->count; else *p++ = 'A' + (is->count - 10); } else { if (run == 26) { *p++ = ('a'-1) + run; run = 0; } run++; } } } if (run) { *p++ = ('a'-1) + run; run = 0; } *p = '\0'; assert(p - ret <= wh); return ret; } static char *game_state_diff(const game_state *src, const game_state *dest) { int movesize = 256, movelen = 0; char *move = snewn(movesize, char), buf[80]; int i, d, x, y, len; grid_type gline, nline; struct island *is_s, *is_d, *is_orth; #define APPEND do { \ if (movelen + len >= movesize) { \ movesize = movelen + len + 256; \ move = sresize(move, movesize, char); \ } \ strcpy(move + movelen, buf); \ movelen += len; \ } while(0) move[movelen++] = 'S'; move[movelen] = '\0'; assert(src->n_islands == dest->n_islands); for (i = 0; i < src->n_islands; i++) { is_s = &src->islands[i]; is_d = &dest->islands[i]; assert(is_s->x == is_d->x); assert(is_s->y == is_d->y); assert(is_s->adj.npoints == is_d->adj.npoints); /* more paranoia */ for (d = 0; d < is_s->adj.npoints; d++) { if (is_s->adj.points[d].dx == -1 || is_s->adj.points[d].dy == -1) continue; x = is_s->adj.points[d].x; y = is_s->adj.points[d].y; gline = is_s->adj.points[d].dx ? G_LINEH : G_LINEV; nline = is_s->adj.points[d].dx ? G_NOLINEH : G_NOLINEV; is_orth = INDEX(dest, gridi, ISLAND_ORTHX(is_d, d), ISLAND_ORTHY(is_d, d)); if (GRIDCOUNT(src, x, y, gline) != GRIDCOUNT(dest, x, y, gline)) { assert(is_orth); len = sprintf(buf, ";L%d,%d,%d,%d,%d", is_s->x, is_s->y, is_orth->x, is_orth->y, GRIDCOUNT(dest, x, y, gline)); APPEND; } if ((GRID(src,x,y) & nline) != (GRID(dest, x, y) & nline)) { assert(is_orth); len = sprintf(buf, ";N%d,%d,%d,%d", is_s->x, is_s->y, is_orth->x, is_orth->y); APPEND; } } if ((GRID(src, is_s->x, is_s->y) & G_MARK) != (GRID(dest, is_d->x, is_d->y) & G_MARK)) { len = sprintf(buf, ";M%d,%d", is_s->x, is_s->y); APPEND; } } return move; } /* --- Game setup and solving utilities --- */ /* This function is optimised; a Quantify showed that lots of grid-generation time * (>50%) was spent in here. Hence the IDX() stuff. */ static void map_update_possibles(game_state *state) { int x, y, s, e, bl, i, np, maxb, w = state->w, idx; struct island *is_s = NULL, *is_f = NULL; /* Run down vertical stripes [un]setting possv... */ for (x = 0; x < state->w; x++) { idx = x; s = e = -1; bl = 0; maxb = state->params.maxb; /* placate optimiser */ /* Unset possible flags until we find an island. */ for (y = 0; y < state->h; y++) { is_s = IDX(state, gridi, idx); if (is_s) { maxb = is_s->count; break; } IDX(state, possv, idx) = 0; idx += w; } for (; y < state->h; y++) { maxb = min(maxb, IDX(state, maxv, idx)); is_f = IDX(state, gridi, idx); if (is_f) { assert(is_s); np = min(maxb, is_f->count); if (s != -1) { for (i = s; i <= e; i++) { INDEX(state, possv, x, i) = bl ? 0 : np; } } s = y+1; bl = 0; is_s = is_f; maxb = is_s->count; } else { e = y; if (IDX(state,grid,idx) & (G_LINEH|G_NOLINEV)) bl = 1; } idx += w; } if (s != -1) { for (i = s; i <= e; i++) INDEX(state, possv, x, i) = 0; } } /* ...and now do horizontal stripes [un]setting possh. */ /* can we lose this clone'n'hack? */ for (y = 0; y < state->h; y++) { idx = y*w; s = e = -1; bl = 0; maxb = state->params.maxb; /* placate optimiser */ for (x = 0; x < state->w; x++) { is_s = IDX(state, gridi, idx); if (is_s) { maxb = is_s->count; break; } IDX(state, possh, idx) = 0; idx += 1; } for (; x < state->w; x++) { maxb = min(maxb, IDX(state, maxh, idx)); is_f = IDX(state, gridi, idx); if (is_f) { assert(is_s); np = min(maxb, is_f->count); if (s != -1) { for (i = s; i <= e; i++) { INDEX(state, possh, i, y) = bl ? 0 : np; } } s = x+1; bl = 0; is_s = is_f; maxb = is_s->count; } else { e = x; if (IDX(state,grid,idx) & (G_LINEV|G_NOLINEH)) bl = 1; } idx += 1; } if (s != -1) { for (i = s; i <= e; i++) INDEX(state, possh, i, y) = 0; } } } static void map_count(game_state *state) { int i, n, ax, ay; grid_type flag, grid; struct island *is; for (i = 0; i < state->n_islands; i++) { is = &state->islands[i]; is->count = 0; for (n = 0; n < is->adj.npoints; n++) { ax = is->adj.points[n].x; ay = is->adj.points[n].y; flag = (ax == is->x) ? G_LINEV : G_LINEH; grid = GRID(state,ax,ay); if (grid & flag) { is->count += INDEX(state,lines,ax,ay); } } } } static void map_find_orthogonal(game_state *state) { int i; for (i = 0; i < state->n_islands; i++) { island_find_orthogonal(&state->islands[i]); } } struct bridges_neighbour_ctx { game_state *state; int i, n, neighbours[4]; }; static int bridges_neighbour(int vertex, void *vctx) { struct bridges_neighbour_ctx *ctx = (struct bridges_neighbour_ctx *)vctx; if (vertex >= 0) { game_state *state = ctx->state; int w = state->w, x = vertex % w, y = vertex / w; grid_type grid = GRID(state, x, y), gline = grid & G_LINE; struct island *is; int x1, y1, x2, y2, i; ctx->i = ctx->n = 0; is = INDEX(state, gridi, x, y); if (is) { for (i = 0; i < is->adj.npoints; i++) { gline = is->adj.points[i].dx ? G_LINEH : G_LINEV; if (GRID(state, is->adj.points[i].x, is->adj.points[i].y) & gline) { ctx->neighbours[ctx->n++] = (is->adj.points[i].y * w + is->adj.points[i].x); } } } else if (gline) { if (gline & G_LINEV) { x1 = x2 = x; y1 = y-1; y2 = y+1; } else { x1 = x-1; x2 = x+1; y1 = y2 = y; } /* Non-island squares with edges in should never be * pointing off the edge of the grid. */ assert(INGRID(state, x1, y1)); assert(INGRID(state, x2, y2)); if (GRID(state, x1, y1) & (gline | G_ISLAND)) ctx->neighbours[ctx->n++] = y1 * w + x1; if (GRID(state, x2, y2) & (gline | G_ISLAND)) ctx->neighbours[ctx->n++] = y2 * w + x2; } } if (ctx->i < ctx->n) return ctx->neighbours[ctx->i++]; else return -1; } static int map_hasloops(game_state *state, int mark) { int x, y; struct findloopstate *fls; struct bridges_neighbour_ctx ctx; int ret; fls = findloop_new_state(state->w * state->h); ctx.state = state; ret = findloop_run(fls, state->w * state->h, bridges_neighbour, &ctx); if (mark) { for (y = 0; y < state->h; y++) { for (x = 0; x < state->w; x++) { int u, v; u = y * state->w + x; for (v = bridges_neighbour(u, &ctx); v >= 0; v = bridges_neighbour(-1, &ctx)) if (findloop_is_loop_edge(fls, u, v)) GRID(state,x,y) |= G_WARN; } } } findloop_free_state(fls); return ret; } static void map_group(game_state *state) { int i, wh = state->w*state->h, d1, d2; int x, y, x2, y2; int *dsf = state->solver->dsf; struct island *is, *is_join; /* Initialise dsf. */ dsf_init(dsf, wh); /* For each island, find connected islands right or down * and merge the dsf for the island squares as well as the * bridge squares. */ for (x = 0; x < state->w; x++) { for (y = 0; y < state->h; y++) { GRID(state,x,y) &= ~(G_SWEEP|G_WARN); /* for group_full. */ is = INDEX(state, gridi, x, y); if (!is) continue; d1 = DINDEX(x,y); for (i = 0; i < is->adj.npoints; i++) { /* only want right/down */ if (is->adj.points[i].dx == -1 || is->adj.points[i].dy == -1) continue; is_join = island_find_connection(is, i); if (!is_join) continue; d2 = DINDEX(is_join->x, is_join->y); if (dsf_canonify(dsf,d1) == dsf_canonify(dsf,d2)) { ; /* we have a loop. See comment in map_hasloops. */ /* However, we still want to merge all squares joining * this side-that-makes-a-loop. */ } /* merge all squares between island 1 and island 2. */ for (x2 = x; x2 <= is_join->x; x2++) { for (y2 = y; y2 <= is_join->y; y2++) { d2 = DINDEX(x2,y2); if (d1 != d2) dsf_merge(dsf,d1,d2); } } } } } } static int map_group_check(game_state *state, int canon, int warn, int *nislands_r) { int *dsf = state->solver->dsf, nislands = 0; int x, y, i, allfull = 1; struct island *is; for (i = 0; i < state->n_islands; i++) { is = &state->islands[i]; if (dsf_canonify(dsf, DINDEX(is->x,is->y)) != canon) continue; GRID(state, is->x, is->y) |= G_SWEEP; nislands++; if (island_countbridges(is) != is->count) allfull = 0; } if (warn && allfull && nislands != state->n_islands) { /* we're full and this island group isn't the whole set. * Mark all squares with this dsf canon as ERR. */ for (x = 0; x < state->w; x++) { for (y = 0; y < state->h; y++) { if (dsf_canonify(dsf, DINDEX(x,y)) == canon) { GRID(state,x,y) |= G_WARN; } } } } if (nislands_r) *nislands_r = nislands; return allfull; } static int map_group_full(game_state *state, int *ngroups_r) { int *dsf = state->solver->dsf, ngroups = 0; int i, anyfull = 0; struct island *is; /* NB this assumes map_group (or sth else) has cleared G_SWEEP. */ for (i = 0; i < state->n_islands; i++) { is = &state->islands[i]; if (GRID(state,is->x,is->y) & G_SWEEP) continue; ngroups++; if (map_group_check(state, dsf_canonify(dsf, DINDEX(is->x,is->y)), 1, NULL)) anyfull = 1; } *ngroups_r = ngroups; return anyfull; } static int map_check(game_state *state) { int ngroups; /* Check for loops, if necessary. */ if (!state->allowloops) { if (map_hasloops(state, 1)) return 0; } /* Place islands into island groups and check for early * satisfied-groups. */ map_group(state); /* clears WARN and SWEEP */ if (map_group_full(state, &ngroups)) { if (ngroups == 1) return 1; } return 0; } static void map_clear(game_state *state) { int x, y; for (x = 0; x < state->w; x++) { for (y = 0; y < state->h; y++) { /* clear most flags; might want to be slightly more careful here. */ GRID(state,x,y) &= G_ISLAND; } } } static void solve_join(struct island *is, int direction, int n, int is_max) { struct island *is_orth; int d1, d2, *dsf = is->state->solver->dsf; game_state *state = is->state; /* for DINDEX */ is_orth = INDEX(is->state, gridi, ISLAND_ORTHX(is, direction), ISLAND_ORTHY(is, direction)); assert(is_orth); /*debug(("...joining (%d,%d) to (%d,%d) with %d bridge(s).\n", is->x, is->y, is_orth->x, is_orth->y, n));*/ island_join(is, is_orth, n, is_max); if (n > 0 && !is_max) { d1 = DINDEX(is->x, is->y); d2 = DINDEX(is_orth->x, is_orth->y); if (dsf_canonify(dsf, d1) != dsf_canonify(dsf, d2)) dsf_merge(dsf, d1, d2); } } static int solve_fillone(struct island *is) { int i, nadded = 0; debug(("solve_fillone for island (%d,%d).\n", is->x, is->y)); for (i = 0; i < is->adj.npoints; i++) { if (island_isadj(is, i)) { if (island_hasbridge(is, i)) { /* already attached; do nothing. */; } else { solve_join(is, i, 1, 0); nadded++; } } } return nadded; } static int solve_fill(struct island *is) { /* for each unmarked adjacent, make sure we convert every possible bridge * to a real one, and then work out the possibles afresh. */ int i, nnew, ncurr, nadded = 0, missing; debug(("solve_fill for island (%d,%d).\n", is->x, is->y)); missing = is->count - island_countbridges(is); if (missing < 0) return 0; /* very like island_countspaces. */ for (i = 0; i < is->adj.npoints; i++) { nnew = island_adjspace(is, 1, missing, i); if (nnew) { ncurr = GRIDCOUNT(is->state, is->adj.points[i].x, is->adj.points[i].y, is->adj.points[i].dx ? G_LINEH : G_LINEV); solve_join(is, i, nnew + ncurr, 0); nadded += nnew; } } return nadded; } static int solve_island_stage1(struct island *is, int *didsth_r) { int bridges = island_countbridges(is); int nspaces = island_countspaces(is, 1); int nadj = island_countadj(is); int didsth = 0; assert(didsth_r); /*debug(("island at (%d,%d) filled %d/%d (%d spc) nadj %d\n", is->x, is->y, bridges, is->count, nspaces, nadj));*/ if (bridges > is->count) { /* We only ever add bridges when we're sure they fit, or that's * the only place they can go. If we've added bridges such that * another island has become wrong, the puzzle must not have had * a solution. */ debug(("...island at (%d,%d) is overpopulated!\n", is->x, is->y)); return 0; } else if (bridges == is->count) { /* This island is full. Make sure it's marked (and update * possibles if we did). */ if (!(GRID(is->state, is->x, is->y) & G_MARK)) { debug(("...marking island (%d,%d) as full.\n", is->x, is->y)); island_togglemark(is); didsth = 1; } } else if (GRID(is->state, is->x, is->y) & G_MARK) { debug(("...island (%d,%d) is marked but unfinished!\n", is->x, is->y)); return 0; /* island has been marked unfinished; no solution from here. */ } else { /* This is the interesting bit; we try and fill in more information * about this island. */ if (is->count == bridges + nspaces) { if (solve_fill(is) > 0) didsth = 1; } else if (is->count > ((nadj-1) * is->state->maxb)) { /* must have at least one bridge in each possible direction. */ if (solve_fillone(is) > 0) didsth = 1; } } if (didsth) { map_update_possibles(is->state); *didsth_r = 1; } return 1; } /* returns non-zero if a new line here would cause a loop. */ static int solve_island_checkloop(struct island *is, int direction) { struct island *is_orth; int *dsf = is->state->solver->dsf, d1, d2; game_state *state = is->state; if (is->state->allowloops) return 0; /* don't care anyway */ if (island_hasbridge(is, direction)) return 0; /* already has a bridge */ if (island_isadj(is, direction) == 0) return 0; /* no adj island */ is_orth = INDEX(is->state, gridi, ISLAND_ORTHX(is,direction), ISLAND_ORTHY(is,direction)); if (!is_orth) return 0; d1 = DINDEX(is->x, is->y); d2 = DINDEX(is_orth->x, is_orth->y); if (dsf_canonify(dsf, d1) == dsf_canonify(dsf, d2)) { /* two islands are connected already; don't join them. */ return 1; } return 0; } static int solve_island_stage2(struct island *is, int *didsth_r) { int added = 0, removed = 0, navail = 0, nadj, i; assert(didsth_r); for (i = 0; i < is->adj.npoints; i++) { if (solve_island_checkloop(is, i)) { debug(("removing possible loop at (%d,%d) direction %d.\n", is->x, is->y, i)); solve_join(is, i, -1, 0); map_update_possibles(is->state); removed = 1; } else { navail += island_isadj(is, i); /*debug(("stage2: navail for (%d,%d) direction (%d,%d) is %d.\n", is->x, is->y, is->adj.points[i].dx, is->adj.points[i].dy, island_isadj(is, i)));*/ } } /*debug(("island at (%d,%d) navail %d: checking...\n", is->x, is->y, navail));*/ for (i = 0; i < is->adj.npoints; i++) { if (!island_hasbridge(is, i)) { nadj = island_isadj(is, i); if (nadj > 0 && (navail - nadj) < is->count) { /* we couldn't now complete the island without at * least one bridge here; put it in. */ /*debug(("nadj %d, navail %d, is->count %d.\n", nadj, navail, is->count));*/ debug(("island at (%d,%d) direction (%d,%d) must have 1 bridge\n", is->x, is->y, is->adj.points[i].dx, is->adj.points[i].dy)); solve_join(is, i, 1, 0); added = 1; /*debug_state(is->state); debug_possibles(is->state);*/ } } } if (added) map_update_possibles(is->state); if (added || removed) *didsth_r = 1; return 1; } static int solve_island_subgroup(struct island *is, int direction) { struct island *is_join; int nislands, *dsf = is->state->solver->dsf; game_state *state = is->state; debug(("..checking subgroups.\n")); /* if is isn't full, return 0. */ if (island_countbridges(is) < is->count) { debug(("...orig island (%d,%d) not full.\n", is->x, is->y)); return 0; } if (direction >= 0) { is_join = INDEX(state, gridi, ISLAND_ORTHX(is, direction), ISLAND_ORTHY(is, direction)); assert(is_join); /* if is_join isn't full, return 0. */ if (island_countbridges(is_join) < is_join->count) { debug(("...dest island (%d,%d) not full.\n", is_join->x, is_join->y)); return 0; } } /* Check group membership for is->dsf; if it's full return 1. */ if (map_group_check(state, dsf_canonify(dsf, DINDEX(is->x,is->y)), 0, &nislands)) { if (nislands < state->n_islands) { /* we have a full subgroup that isn't the whole set. * This isn't allowed. */ debug(("island at (%d,%d) makes full subgroup, disallowing.\n", is->x, is->y)); return 1; } else { debug(("...has finished puzzle.\n")); } } return 0; } static int solve_island_impossible(game_state *state) { struct island *is; int i; /* If any islands are impossible, return 1. */ for (i = 0; i < state->n_islands; i++) { is = &state->islands[i]; if (island_impossible(is, 0)) { debug(("island at (%d,%d) has become impossible, disallowing.\n", is->x, is->y)); return 1; } } return 0; } /* Bear in mind that this function is really rather inefficient. */ static int solve_island_stage3(struct island *is, int *didsth_r) { int i, n, x, y, missing, spc, curr, maxb, didsth = 0; int wh = is->state->w * is->state->h; struct solver_state *ss = is->state->solver; assert(didsth_r); missing = is->count - island_countbridges(is); if (missing <= 0) return 1; for (i = 0; i < is->adj.npoints; i++) { x = is->adj.points[i].x; y = is->adj.points[i].y; spc = island_adjspace(is, 1, missing, i); if (spc == 0) continue; curr = GRIDCOUNT(is->state, x, y, is->adj.points[i].dx ? G_LINEH : G_LINEV); debug(("island at (%d,%d) s3, trying %d - %d bridges.\n", is->x, is->y, curr+1, curr+spc)); /* Now we know that this island could have more bridges, * to bring the total from curr+1 to curr+spc. */ maxb = -1; /* We have to squirrel the dsf away and restore it afterwards; * it is additive only, and can't be removed from. */ memcpy(ss->tmpdsf, ss->dsf, wh*sizeof(int)); for (n = curr+1; n <= curr+spc; n++) { solve_join(is, i, n, 0); map_update_possibles(is->state); if (solve_island_subgroup(is, i) || solve_island_impossible(is->state)) { maxb = n-1; debug(("island at (%d,%d) d(%d,%d) new max of %d bridges:\n", is->x, is->y, is->adj.points[i].dx, is->adj.points[i].dy, maxb)); break; } } solve_join(is, i, curr, 0); /* put back to before. */ memcpy(ss->dsf, ss->tmpdsf, wh*sizeof(int)); if (maxb != -1) { /*debug_state(is->state);*/ if (maxb == 0) { debug(("...adding NOLINE.\n")); solve_join(is, i, -1, 0); /* we can't have any bridges here. */ } else { debug(("...setting maximum\n")); solve_join(is, i, maxb, 1); } didsth = 1; } map_update_possibles(is->state); } for (i = 0; i < is->adj.npoints; i++) { /* * Now check to see if any currently empty direction must have * at least one bridge in order to avoid forming an isolated * subgraph. This differs from the check above in that it * considers multiple target islands. For example: * * 2 2 4 * 1 3 2 * 3 * 4 * * The example on the left can be handled by the above loop: * it will observe that connecting the central 2 twice to the * left would form an isolated subgraph, and hence it will * restrict that 2 to at most one bridge in that direction. * But the example on the right won't be handled by that loop, * because the deduction requires us to imagine connecting the * 3 to _both_ the 1 and 2 at once to form an isolated * subgraph. * * This pass is necessary _as well_ as the above one, because * neither can do the other's job. In the left one, * restricting the direction which _would_ cause trouble can * be done even if it's not yet clear which of the remaining * directions has to have a compensatory bridge; whereas the * pass below that can handle the right-hand example does need * to know what direction to point the necessary bridge in. * * Neither pass can handle the most general case, in which we * observe that an arbitrary subset of an island's neighbours * would form an isolated subgraph with it if it connected * maximally to them, and hence that at least one bridge must * point to some neighbour outside that subset but we don't * know which neighbour. To handle that, we'd have to have a * richer data format for the solver, which could cope with * recording the idea that at least one of two edges must have * a bridge. */ int got = 0; int before[4]; int j; spc = island_adjspace(is, 1, missing, i); if (spc == 0) continue; for (j = 0; j < is->adj.npoints; j++) before[j] = GRIDCOUNT(is->state, is->adj.points[j].x, is->adj.points[j].y, is->adj.points[j].dx ? G_LINEH : G_LINEV); if (before[i] != 0) continue; /* this idea is pointless otherwise */ memcpy(ss->tmpdsf, ss->dsf, wh*sizeof(int)); for (j = 0; j < is->adj.npoints; j++) { spc = island_adjspace(is, 1, missing, j); if (spc == 0) continue; if (j == i) continue; solve_join(is, j, before[j] + spc, 0); } map_update_possibles(is->state); if (solve_island_subgroup(is, -1)) got = 1; for (j = 0; j < is->adj.npoints; j++) solve_join(is, j, before[j], 0); memcpy(ss->dsf, ss->tmpdsf, wh*sizeof(int)); if (got) { debug(("island at (%d,%d) must connect in direction (%d,%d) to" " avoid full subgroup.\n", is->x, is->y, is->adj.points[i].dx, is->adj.points[i].dy)); solve_join(is, i, 1, 0); didsth = 1; } map_update_possibles(is->state); } if (didsth) *didsth_r = didsth; return 1; } #define CONTINUE_IF_FULL do { \ if (GRID(state, is->x, is->y) & G_MARK) { \ /* island full, don't try fixing it */ \ continue; \ } } while(0) static int solve_sub(game_state *state, int difficulty, int depth) { struct island *is; int i, didsth; while (1) { didsth = 0; /* First island iteration: things we can work out by looking at * properties of the island as a whole. */ for (i = 0; i < state->n_islands; i++) { is = &state->islands[i]; if (!solve_island_stage1(is, &didsth)) return 0; } if (didsth) continue; else if (difficulty < 1) break; /* Second island iteration: thing we can work out by looking at * properties of individual island connections. */ for (i = 0; i < state->n_islands; i++) { is = &state->islands[i]; CONTINUE_IF_FULL; if (!solve_island_stage2(is, &didsth)) return 0; } if (didsth) continue; else if (difficulty < 2) break; /* Third island iteration: things we can only work out by looking * at groups of islands. */ for (i = 0; i < state->n_islands; i++) { is = &state->islands[i]; if (!solve_island_stage3(is, &didsth)) return 0; } if (didsth) continue; else if (difficulty < 3) break; /* If we can be bothered, write a recursive solver to finish here. */ break; } if (map_check(state)) return 1; /* solved it */ return 0; } static void solve_for_hint(game_state *state) { map_group(state); solve_sub(state, 10, 0); } static int solve_from_scratch(game_state *state, int difficulty) { map_clear(state); map_group(state); map_update_possibles(state); return solve_sub(state, difficulty, 0); } /* --- New game functions --- */ static game_state *new_state(const game_params *params) { game_state *ret = snew(game_state); int wh = params->w * params->h, i; ret->w = params->w; ret->h = params->h; ret->allowloops = params->allowloops; ret->maxb = params->maxb; ret->params = *params; ret->grid = snewn(wh, grid_type); memset(ret->grid, 0, GRIDSZ(ret)); ret->wha = snewn(wh*N_WH_ARRAYS, char); memset(ret->wha, 0, wh*N_WH_ARRAYS*sizeof(char)); ret->possv = ret->wha; ret->possh = ret->wha + wh; ret->lines = ret->wha + wh*2; ret->maxv = ret->wha + wh*3; ret->maxh = ret->wha + wh*4; memset(ret->maxv, ret->maxb, wh*sizeof(char)); memset(ret->maxh, ret->maxb, wh*sizeof(char)); ret->islands = NULL; ret->n_islands = 0; ret->n_islands_alloc = 0; ret->gridi = snewn(wh, struct island *); for (i = 0; i < wh; i++) ret->gridi[i] = NULL; ret->solved = ret->completed = 0; ret->solver = snew(struct solver_state); ret->solver->dsf = snew_dsf(wh); ret->solver->tmpdsf = snewn(wh, int); ret->solver->refcount = 1; return ret; } static game_state *dup_game(const game_state *state) { game_state *ret = snew(game_state); int wh = state->w*state->h; ret->w = state->w; ret->h = state->h; ret->allowloops = state->allowloops; ret->maxb = state->maxb; ret->params = state->params; ret->grid = snewn(wh, grid_type); memcpy(ret->grid, state->grid, GRIDSZ(ret)); ret->wha = snewn(wh*N_WH_ARRAYS, char); memcpy(ret->wha, state->wha, wh*N_WH_ARRAYS*sizeof(char)); ret->possv = ret->wha; ret->possh = ret->wha + wh; ret->lines = ret->wha + wh*2; ret->maxv = ret->wha + wh*3; ret->maxh = ret->wha + wh*4; ret->islands = snewn(state->n_islands, struct island); memcpy(ret->islands, state->islands, state->n_islands * sizeof(struct island)); ret->n_islands = ret->n_islands_alloc = state->n_islands; ret->gridi = snewn(wh, struct island *); fixup_islands_for_realloc(ret); ret->solved = state->solved; ret->completed = state->completed; ret->solver = state->solver; ret->solver->refcount++; return ret; } static void free_game(game_state *state) { if (--state->solver->refcount <= 0) { sfree(state->solver->dsf); sfree(state->solver->tmpdsf); sfree(state->solver); } sfree(state->islands); sfree(state->gridi); sfree(state->wha); sfree(state->grid); sfree(state); } #define MAX_NEWISLAND_TRIES 50 #define MIN_SENSIBLE_ISLANDS 3 #define ORDER(a,b) do { if (a < b) { int tmp=a; int a=b; int b=tmp; } } while(0) static char *new_game_desc(const game_params *params, random_state *rs, char **aux, int interactive) { game_state *tobuild = NULL; int i, j, wh = params->w * params->h, x, y, dx, dy; int minx, miny, maxx, maxy, joinx, joiny, newx, newy, diffx, diffy; int ni_req = max((params->islands * wh) / 100, MIN_SENSIBLE_ISLANDS), ni_curr, ni_bad; struct island *is, *is2; char *ret; unsigned int echeck; /* pick a first island position randomly. */ generate: if (tobuild) free_game(tobuild); tobuild = new_state(params); x = random_upto(rs, params->w); y = random_upto(rs, params->h); island_add(tobuild, x, y, 0); ni_curr = 1; ni_bad = 0; debug(("Created initial island at (%d,%d).\n", x, y)); while (ni_curr < ni_req) { /* Pick a random island to try and extend from. */ i = random_upto(rs, tobuild->n_islands); is = &tobuild->islands[i]; /* Pick a random direction to extend in. */ j = random_upto(rs, is->adj.npoints); dx = is->adj.points[j].x - is->x; dy = is->adj.points[j].y - is->y; /* Find out limits of where we could put a new island. */ joinx = joiny = -1; minx = is->x + 2*dx; miny = is->y + 2*dy; /* closest is 2 units away. */ x = is->x+dx; y = is->y+dy; if (GRID(tobuild,x,y) & (G_LINEV|G_LINEH)) { /* already a line next to the island, continue. */ goto bad; } while (1) { if (x < 0 || x >= params->w || y < 0 || y >= params->h) { /* got past the edge; put a possible at the island * and exit. */ maxx = x-dx; maxy = y-dy; goto foundmax; } if (GRID(tobuild,x,y) & G_ISLAND) { /* could join up to an existing island... */ joinx = x; joiny = y; /* ... or make a new one 2 spaces away. */ maxx = x - 2*dx; maxy = y - 2*dy; goto foundmax; } else if (GRID(tobuild,x,y) & (G_LINEV|G_LINEH)) { /* could make a new one 1 space away from the line. */ maxx = x - dx; maxy = y - dy; goto foundmax; } x += dx; y += dy; } foundmax: debug(("Island at (%d,%d) with d(%d,%d) has new positions " "(%d,%d) -> (%d,%d), join (%d,%d).\n", is->x, is->y, dx, dy, minx, miny, maxx, maxy, joinx, joiny)); /* Now we know where we could either put a new island * (between min and max), or (if loops are allowed) could join on * to an existing island (at join). */ if (params->allowloops && joinx != -1 && joiny != -1) { if (random_upto(rs, 100) < (unsigned long)params->expansion) { is2 = INDEX(tobuild, gridi, joinx, joiny); debug(("Joining island at (%d,%d) to (%d,%d).\n", is->x, is->y, is2->x, is2->y)); goto join; } } diffx = (maxx - minx) * dx; diffy = (maxy - miny) * dy; if (diffx < 0 || diffy < 0) goto bad; if (random_upto(rs,100) < (unsigned long)params->expansion) { newx = maxx; newy = maxy; debug(("Creating new island at (%d,%d) (expanded).\n", newx, newy)); } else { newx = minx + random_upto(rs,diffx+1)*dx; newy = miny + random_upto(rs,diffy+1)*dy; debug(("Creating new island at (%d,%d).\n", newx, newy)); } /* check we're not next to island in the other orthogonal direction. */ if ((INGRID(tobuild,newx+dy,newy+dx) && (GRID(tobuild,newx+dy,newy+dx) & G_ISLAND)) || (INGRID(tobuild,newx-dy,newy-dx) && (GRID(tobuild,newx-dy,newy-dx) & G_ISLAND))) { debug(("New location is adjacent to island, skipping.\n")); goto bad; } is2 = island_add(tobuild, newx, newy, 0); /* Must get is again at this point; the array might have * been realloced by island_add... */ is = &tobuild->islands[i]; /* ...but order will not change. */ ni_curr++; ni_bad = 0; join: island_join(is, is2, random_upto(rs, tobuild->maxb)+1, 0); debug_state(tobuild); continue; bad: ni_bad++; if (ni_bad > MAX_NEWISLAND_TRIES) { debug(("Unable to create any new islands after %d tries; " "created %d [%d%%] (instead of %d [%d%%] requested).\n", MAX_NEWISLAND_TRIES, ni_curr, ni_curr * 100 / wh, ni_req, ni_req * 100 / wh)); goto generated; } } generated: if (ni_curr == 1) { debug(("Only generated one island (!), retrying.\n")); goto generate; } /* Check we have at least one island on each extremity of the grid. */ echeck = 0; for (x = 0; x < params->w; x++) { if (INDEX(tobuild, gridi, x, 0)) echeck |= 1; if (INDEX(tobuild, gridi, x, params->h-1)) echeck |= 2; } for (y = 0; y < params->h; y++) { if (INDEX(tobuild, gridi, 0, y)) echeck |= 4; if (INDEX(tobuild, gridi, params->w-1, y)) echeck |= 8; } if (echeck != 15) { debug(("Generated grid doesn't fill to sides, retrying.\n")); goto generate; } map_count(tobuild); map_find_orthogonal(tobuild); if (params->difficulty > 0) { if ((ni_curr > MIN_SENSIBLE_ISLANDS) && (solve_from_scratch(tobuild, params->difficulty-1) > 0)) { debug(("Grid is solvable at difficulty %d (too easy); retrying.\n", params->difficulty-1)); goto generate; } } if (solve_from_scratch(tobuild, params->difficulty) == 0) { debug(("Grid not solvable at difficulty %d, (too hard); retrying.\n", params->difficulty)); goto generate; } /* ... tobuild is now solved. We rely on this making the diff for aux. */ debug_state(tobuild); ret = encode_game(tobuild); { game_state *clean = dup_game(tobuild); map_clear(clean); map_update_possibles(clean); *aux = game_state_diff(clean, tobuild); free_game(clean); } free_game(tobuild); return ret; } static char *validate_desc(const game_params *params, const char *desc) { int i, wh = params->w * params->h; for (i = 0; i < wh; i++) { if (*desc >= '1' && *desc <= '9') /* OK */; else if (*desc >= 'a' && *desc <= 'z') i += *desc - 'a'; /* plus the i++ */ else if (*desc >= 'A' && *desc <= 'G') /* OK */; else if (*desc == 'V' || *desc == 'W' || *desc == 'X' || *desc == 'Y' || *desc == 'H' || *desc == 'I' || *desc == 'J' || *desc == 'K') /* OK */; else if (!*desc) return "Game description shorter than expected"; else return "Game description contains unexpected character"; desc++; } if (*desc || i > wh) return "Game description longer than expected"; return NULL; } static game_state *new_game_sub(const game_params *params, const char *desc) { game_state *state = new_state(params); int x, y, run = 0; debug(("new_game[_sub]: desc = '%s'.\n", desc)); for (y = 0; y < params->h; y++) { for (x = 0; x < params->w; x++) { char c = '\0'; if (run == 0) { c = *desc++; assert(c != 'S'); if (c >= 'a' && c <= 'z') run = c - 'a' + 1; } if (run > 0) { c = 'S'; run--; } switch (c) { case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': island_add(state, x, y, (c - '0')); break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': island_add(state, x, y, (c - 'A') + 10); break; case 'S': /* empty square */ break; default: assert(!"Malformed desc."); break; } } } if (*desc) assert(!"Over-long desc."); map_find_orthogonal(state); map_update_possibles(state); return state; } static game_state *new_game(midend *me, const game_params *params, const char *desc) { return new_game_sub(params, desc); } struct game_ui { int dragx_src, dragy_src; /* source; -1 means no drag */ int dragx_dst, dragy_dst; /* src's closest orth island. */ grid_type todraw; int dragging, drag_is_noline, nlines; int cur_x, cur_y, cur_visible; /* cursor position */ int show_hints; }; static char *ui_cancel_drag(game_ui *ui) { ui->dragx_src = ui->dragy_src = -1; ui->dragx_dst = ui->dragy_dst = -1; ui->dragging = 0; return ""; } static game_ui *new_ui(const game_state *state) { game_ui *ui = snew(game_ui); ui_cancel_drag(ui); ui->cur_x = state->islands[0].x; ui->cur_y = state->islands[0].y; ui->cur_visible = 0; ui->show_hints = 0; return ui; } static void free_ui(game_ui *ui) { sfree(ui); } static char *encode_ui(const game_ui *ui) { return NULL; } static void decode_ui(game_ui *ui, const char *encoding) { } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { } struct game_drawstate { int tilesize; int w, h; unsigned long *grid, *newgrid; int *lv, *lh; int started, dragging; }; /* * The contents of ds->grid are complicated, because of the circular * islands which overlap their own grid square into neighbouring * squares. An island square can contain pieces of the bridges in all * directions, and conversely a bridge square can be intruded on by * islands from any direction. * * So we define one group of flags describing what's important about * an island, and another describing a bridge. Island squares' entries * in ds->grid contain one of the former and four of the latter; bridge * squares, four of the former and _two_ of the latter - because a * horizontal and vertical 'bridge' can cross, when one of them is a * 'no bridge here' pencil mark. * * Bridge flags need to indicate 0-4 actual bridges (3 bits), a 'no * bridge' row of crosses, or a grey hint line; that's 7 * possibilities, so 3 bits suffice. But then we also need to vary the * colours: the bridges can turn COL_WARNING if they're part of a loop * in no-loops mode, COL_HIGHLIGHT during a victory flash, or * COL_SELECTED if they're the bridge the user is currently dragging, * so that's 2 more bits for foreground colour. Also bridges can be * backed by COL_MARK if they're locked by the user, so that's one * more bit, making 6 bits per bridge direction. * * Island flags omit the actual island clue (it never changes during * the game, so doesn't have to be stored in ds->grid to check against * the previous version), so they just need to include 2 bits for * foreground colour (an island can be normal, COL_HIGHLIGHT during * victory, COL_WARNING if its clue is unsatisfiable, or COL_SELECTED * if it's part of the user's drag) and 2 bits for background (normal, * COL_MARK for a locked island, COL_CURSOR for the keyboard cursor). * That's 4 bits per island direction. We must also indicate whether * no island is present at all (in the case where the island is * potentially intruding into the side of a line square), which we do * using the unused 4th value of the background field. * * So an island square needs 4 + 4*6 = 28 bits, while a bridge square * needs 4*4 + 2*6 = 28 bits too. Both only just fit in 32 bits, which * is handy, because otherwise we'd have to faff around forever with * little structs! */ /* Flags for line data */ #define DL_COUNTMASK 0x07 #define DL_COUNT_CROSS 0x06 #define DL_COUNT_HINT 0x07 #define DL_COLMASK 0x18 #define DL_COL_NORMAL 0x00 #define DL_COL_WARNING 0x08 #define DL_COL_FLASH 0x10 #define DL_COL_SELECTED 0x18 #define DL_LOCK 0x20 #define DL_MASK 0x3F /* Flags for island data */ #define DI_COLMASK 0x03 #define DI_COL_NORMAL 0x00 #define DI_COL_FLASH 0x01 #define DI_COL_WARNING 0x02 #define DI_COL_SELECTED 0x03 #define DI_BGMASK 0x0C #define DI_BG_NO_ISLAND 0x00 #define DI_BG_NORMAL 0x04 #define DI_BG_MARK 0x08 #define DI_BG_CURSOR 0x0C #define DI_MASK 0x0F /* Shift counts for the format of a 32-bit word in an island square */ #define D_I_ISLAND_SHIFT 0 #define D_I_LINE_SHIFT_L 4 #define D_I_LINE_SHIFT_R 10 #define D_I_LINE_SHIFT_U 16 #define D_I_LINE_SHIFT_D 24 /* Shift counts for the format of a 32-bit word in a line square */ #define D_L_ISLAND_SHIFT_L 0 #define D_L_ISLAND_SHIFT_R 4 #define D_L_ISLAND_SHIFT_U 8 #define D_L_ISLAND_SHIFT_D 12 #define D_L_LINE_SHIFT_H 16 #define D_L_LINE_SHIFT_V 22 static char *update_drag_dst(const game_state *state, game_ui *ui, const game_drawstate *ds, int nx, int ny) { int ox, oy, dx, dy, i, currl, maxb; struct island *is; grid_type gtype, ntype, mtype, curr; if (ui->dragx_src == -1 || ui->dragy_src == -1) return NULL; ui->dragx_dst = -1; ui->dragy_dst = -1; /* work out which of the four directions we're closest to... */ ox = COORD(ui->dragx_src) + TILE_SIZE/2; oy = COORD(ui->dragy_src) + TILE_SIZE/2; if (abs(nx-ox) < abs(ny-oy)) { dx = 0; dy = (ny-oy) < 0 ? -1 : 1; gtype = G_LINEV; ntype = G_NOLINEV; mtype = G_MARKV; maxb = INDEX(state, maxv, ui->dragx_src+dx, ui->dragy_src+dy); } else { dy = 0; dx = (nx-ox) < 0 ? -1 : 1; gtype = G_LINEH; ntype = G_NOLINEH; mtype = G_MARKH; maxb = INDEX(state, maxh, ui->dragx_src+dx, ui->dragy_src+dy); } if (ui->drag_is_noline) { ui->todraw = ntype; } else { curr = GRID(state, ui->dragx_src+dx, ui->dragy_src+dy); currl = INDEX(state, lines, ui->dragx_src+dx, ui->dragy_src+dy); if (curr & gtype) { if (currl == maxb) { ui->todraw = 0; ui->nlines = 0; } else { ui->todraw = gtype; ui->nlines = currl + 1; } } else { ui->todraw = gtype; ui->nlines = 1; } } /* ... and see if there's an island off in that direction. */ is = INDEX(state, gridi, ui->dragx_src, ui->dragy_src); for (i = 0; i < is->adj.npoints; i++) { if (is->adj.points[i].off == 0) continue; curr = GRID(state, is->x+dx, is->y+dy); if (curr & mtype) continue; /* don't allow changes to marked lines. */ if (ui->drag_is_noline) { if (curr & gtype) continue; /* no no-line where already a line */ } else { if (POSSIBLES(state, dx, is->x+dx, is->y+dy) == 0) continue; /* no line if !possible. */ if (curr & ntype) continue; /* can't have a bridge where there's a no-line. */ } if (is->adj.points[i].dx == dx && is->adj.points[i].dy == dy) { ui->dragx_dst = ISLAND_ORTHX(is,i); ui->dragy_dst = ISLAND_ORTHY(is,i); } } /*debug(("update_drag src (%d,%d) d(%d,%d) dst (%d,%d)\n", ui->dragx_src, ui->dragy_src, dx, dy, ui->dragx_dst, ui->dragy_dst));*/ return ""; } static char *finish_drag(const game_state *state, game_ui *ui) { char buf[80]; if (ui->dragx_src == -1 || ui->dragy_src == -1) return NULL; if (ui->dragx_dst == -1 || ui->dragy_dst == -1) return ui_cancel_drag(ui); if (ui->drag_is_noline) { sprintf(buf, "N%d,%d,%d,%d", ui->dragx_src, ui->dragy_src, ui->dragx_dst, ui->dragy_dst); } else { sprintf(buf, "L%d,%d,%d,%d,%d", ui->dragx_src, ui->dragy_src, ui->dragx_dst, ui->dragy_dst, ui->nlines); } ui_cancel_drag(ui); return dupstr(buf); } static char *interpret_move(const game_state *state, game_ui *ui, const game_drawstate *ds, int x, int y, int button) { int gx = FROMCOORD(x), gy = FROMCOORD(y); char buf[80], *ret; grid_type ggrid = INGRID(state,gx,gy) ? GRID(state,gx,gy) : 0; int shift = button & MOD_SHFT, control = button & MOD_CTRL; button &= ~MOD_MASK; if (button == LEFT_BUTTON || button == RIGHT_BUTTON) { if (!INGRID(state, gx, gy)) return NULL; ui->cur_visible = 0; if (ggrid & G_ISLAND) { ui->dragx_src = gx; ui->dragy_src = gy; return ""; } else return ui_cancel_drag(ui); } else if (button == LEFT_DRAG || button == RIGHT_DRAG) { if (INGRID(state, ui->dragx_src, ui->dragy_src) && (gx != ui->dragx_src || gy != ui->dragy_src) && !(GRID(state,ui->dragx_src,ui->dragy_src) & G_MARK)) { ui->dragging = 1; ui->drag_is_noline = (button == RIGHT_DRAG) ? 1 : 0; return update_drag_dst(state, ui, ds, x, y); } else { /* cancel a drag when we go back to the starting point */ ui->dragx_dst = -1; ui->dragy_dst = -1; return ""; } } else if (button == LEFT_RELEASE || button == RIGHT_RELEASE) { if (ui->dragging) { return finish_drag(state, ui); } else { if (!INGRID(state, ui->dragx_src, ui->dragy_src) || gx != ui->dragx_src || gy != ui->dragy_src) { return ui_cancel_drag(ui); } ui_cancel_drag(ui); if (!INGRID(state, gx, gy)) return NULL; if (!(GRID(state, gx, gy) & G_ISLAND)) return NULL; sprintf(buf, "M%d,%d", gx, gy); return dupstr(buf); } } else if (button == 'h' || button == 'H') { game_state *solved = dup_game(state); solve_for_hint(solved); ret = game_state_diff(state, solved); free_game(solved); return ret; } else if (IS_CURSOR_MOVE(button)) { ui->cur_visible = 1; if (control || shift) { ui->dragx_src = ui->cur_x; ui->dragy_src = ui->cur_y; ui->dragging = TRUE; ui->drag_is_noline = !control; } if (ui->dragging) { int nx = ui->cur_x, ny = ui->cur_y; move_cursor(button, &nx, &ny, state->w, state->h, 0); if (nx == ui->cur_x && ny == ui->cur_y) return NULL; update_drag_dst(state, ui, ds, COORD(nx)+TILE_SIZE/2, COORD(ny)+TILE_SIZE/2); return finish_drag(state, ui); } else { int dx = (button == CURSOR_RIGHT) ? +1 : (button == CURSOR_LEFT) ? -1 : 0; int dy = (button == CURSOR_DOWN) ? +1 : (button == CURSOR_UP) ? -1 : 0; int dorthx = 1 - abs(dx), dorthy = 1 - abs(dy); int dir, orth, nx = x, ny = y; /* 'orthorder' is a tweak to ensure that if you press RIGHT and * happen to move upwards, when you press LEFT you then tend * downwards (rather than upwards again). */ int orthorder = (button == CURSOR_LEFT || button == CURSOR_UP) ? 1 : -1; /* This attempts to find an island in the direction you're * asking for, broadly speaking. If you ask to go right, for * example, it'll look for islands to the right and slightly * above or below your current horiz. position, allowing * further above/below the further away it searches. */ assert(GRID(state, ui->cur_x, ui->cur_y) & G_ISLAND); /* currently this is depth-first (so orthogonally-adjacent * islands across the other side of the grid will be moved to * before closer islands slightly offset). Swap the order of * these two loops to change to breadth-first search. */ for (orth = 0; ; orth++) { int oingrid = 0; for (dir = 1; ; dir++) { int dingrid = 0; if (orth > dir) continue; /* only search in cone outwards. */ nx = ui->cur_x + dir*dx + orth*dorthx*orthorder; ny = ui->cur_y + dir*dy + orth*dorthy*orthorder; if (INGRID(state, nx, ny)) { dingrid = oingrid = 1; if (GRID(state, nx, ny) & G_ISLAND) goto found; } nx = ui->cur_x + dir*dx - orth*dorthx*orthorder; ny = ui->cur_y + dir*dy - orth*dorthy*orthorder; if (INGRID(state, nx, ny)) { dingrid = oingrid = 1; if (GRID(state, nx, ny) & G_ISLAND) goto found; } if (!dingrid) break; } if (!oingrid) return ""; } /* not reached */ found: ui->cur_x = nx; ui->cur_y = ny; return ""; } } else if (IS_CURSOR_SELECT(button)) { if (!ui->cur_visible) { ui->cur_visible = 1; return ""; } if (ui->dragging || button == CURSOR_SELECT2) { ui_cancel_drag(ui); if (ui->dragx_dst == -1 && ui->dragy_dst == -1) { sprintf(buf, "M%d,%d", ui->cur_x, ui->cur_y); return dupstr(buf); } else return ""; } else { grid_type v = GRID(state, ui->cur_x, ui->cur_y); if (v & G_ISLAND) { ui->dragging = 1; ui->dragx_src = ui->cur_x; ui->dragy_src = ui->cur_y; ui->dragx_dst = ui->dragy_dst = -1; ui->drag_is_noline = (button == CURSOR_SELECT2) ? 1 : 0; return ""; } } } else if ((button >= '0' && button <= '9') || (button >= 'a' && button <= 'f') || (button >= 'A' && button <= 'F')) { /* jump to island with .count == number closest to cur_{x,y} */ int best_x = -1, best_y = -1, best_sqdist = -1, number = -1, i; if (button >= '0' && button <= '9') number = (button == '0' ? 16 : button - '0'); else if (button >= 'a' && button <= 'f') number = 10 + button - 'a'; else if (button >= 'A' && button <= 'F') number = 10 + button - 'A'; if (!ui->cur_visible) { ui->cur_visible = 1; return ""; } for (i = 0; i < state->n_islands; ++i) { int x = state->islands[i].x, y = state->islands[i].y; int dx = x - ui->cur_x, dy = y - ui->cur_y; int sqdist = dx*dx + dy*dy; if (state->islands[i].count != number) continue; if (x == ui->cur_x && y == ui->cur_y) continue; /* new_game() reads the islands in row-major order, so by * breaking ties in favor of `first in state->islands' we * also break ties by `lexicographically smallest (y, x)'. * Thus, there's a stable pattern to how ties are broken * which the user can learn and use to navigate faster. */ if (best_sqdist == -1 || sqdist < best_sqdist) { best_x = x; best_y = y; best_sqdist = sqdist; } } if (best_x != -1 && best_y != -1) { ui->cur_x = best_x; ui->cur_y = best_y; return ""; } else return NULL; } else if (button == 'g' || button == 'G') { ui->show_hints = 1 - ui->show_hints; return ""; } return NULL; } static game_state *execute_move(const game_state *state, const char *move) { game_state *ret = dup_game(state); int x1, y1, x2, y2, nl, n; struct island *is1, *is2; char c; debug(("execute_move: %s\n", move)); if (!*move) goto badmove; while (*move) { c = *move++; if (c == 'S') { ret->solved = TRUE; n = 0; } else if (c == 'L') { if (sscanf(move, "%d,%d,%d,%d,%d%n", &x1, &y1, &x2, &y2, &nl, &n) != 5) goto badmove; if (!INGRID(ret, x1, y1) || !INGRID(ret, x2, y2)) goto badmove; is1 = INDEX(ret, gridi, x1, y1); is2 = INDEX(ret, gridi, x2, y2); if (!is1 || !is2) goto badmove; if (nl < 0 || nl > state->maxb) goto badmove; island_join(is1, is2, nl, 0); } else if (c == 'N') { if (sscanf(move, "%d,%d,%d,%d%n", &x1, &y1, &x2, &y2, &n) != 4) goto badmove; if (!INGRID(ret, x1, y1) || !INGRID(ret, x2, y2)) goto badmove; is1 = INDEX(ret, gridi, x1, y1); is2 = INDEX(ret, gridi, x2, y2); if (!is1 || !is2) goto badmove; island_join(is1, is2, -1, 0); } else if (c == 'M') { if (sscanf(move, "%d,%d%n", &x1, &y1, &n) != 2) goto badmove; if (!INGRID(ret, x1, y1)) goto badmove; is1 = INDEX(ret, gridi, x1, y1); if (!is1) goto badmove; island_togglemark(is1); } else goto badmove; move += n; if (*move == ';') move++; else if (*move) goto badmove; } map_update_possibles(ret); if (map_check(ret)) { debug(("Game completed.\n")); ret->completed = 1; } return ret; badmove: debug(("%s: unrecognised move.\n", move)); free_game(ret); return NULL; } static char *solve_game(const game_state *state, const game_state *currstate, const char *aux, char **error) { char *ret; game_state *solved; if (aux) { debug(("solve_game: aux = %s\n", aux)); solved = execute_move(state, aux); if (!solved) { *error = "Generated aux string is not a valid move (!)."; return NULL; } } else { solved = dup_game(state); /* solve with max strength... */ if (solve_from_scratch(solved, 10) == 0) { free_game(solved); *error = "Game does not have a (non-recursive) solution."; return NULL; } } ret = game_state_diff(currstate, solved); free_game(solved); debug(("solve_game: ret = %s\n", ret)); return ret; } /* ---------------------------------------------------------------------- * Drawing routines. */ static void game_compute_size(const game_params *params, int tilesize, int *x, int *y) { /* Ick: fake up `ds->tilesize' for macro expansion purposes */ struct { int tilesize; } ads, *ds = &ads; ads.tilesize = tilesize; *x = TILE_SIZE * params->w + 2 * BORDER; *y = TILE_SIZE * params->h + 2 * BORDER; } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { ds->tilesize = tilesize; } static float *game_colours(frontend *fe, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float); int i; game_mkhighlight(fe, ret, COL_BACKGROUND, COL_HIGHLIGHT, COL_LOWLIGHT); for (i = 0; i < 3; i++) { ret[COL_FOREGROUND * 3 + i] = 0.0F; ret[COL_HINT * 3 + i] = ret[COL_LOWLIGHT * 3 + i]; ret[COL_GRID * 3 + i] = (ret[COL_HINT * 3 + i] + ret[COL_BACKGROUND * 3 + i]) * 0.5F; ret[COL_MARK * 3 + i] = ret[COL_HIGHLIGHT * 3 + i]; } ret[COL_WARNING * 3 + 0] = 1.0F; ret[COL_WARNING * 3 + 1] = 0.25F; ret[COL_WARNING * 3 + 2] = 0.25F; ret[COL_SELECTED * 3 + 0] = 0.25F; ret[COL_SELECTED * 3 + 1] = 1.00F; ret[COL_SELECTED * 3 + 2] = 0.25F; ret[COL_CURSOR * 3 + 0] = min(ret[COL_BACKGROUND * 3 + 0] * 1.4F, 1.0F); ret[COL_CURSOR * 3 + 1] = ret[COL_BACKGROUND * 3 + 1] * 0.8F; ret[COL_CURSOR * 3 + 2] = ret[COL_BACKGROUND * 3 + 2] * 0.8F; *ncolours = NCOLOURS; return ret; } static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { struct game_drawstate *ds = snew(struct game_drawstate); int wh = state->w*state->h; int i; ds->tilesize = 0; ds->w = state->w; ds->h = state->h; ds->started = 0; ds->dragging = 0; ds->grid = snewn(wh, unsigned long); for (i = 0; i < wh; i++) ds->grid[i] = ~0UL; ds->newgrid = snewn(wh, unsigned long); ds->lv = snewn(wh, int); ds->lh = snewn(wh, int); memset(ds->lv, 0, wh*sizeof(int)); memset(ds->lh, 0, wh*sizeof(int)); return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { sfree(ds->lv); sfree(ds->lh); sfree(ds->newgrid); sfree(ds->grid); sfree(ds); } #define LINE_WIDTH (TILE_SIZE/8) #define TS8(x) (((x)*TILE_SIZE)/8) #define OFFSET(thing) ((TILE_SIZE/2) - ((thing)/2)) static int between_island(const game_state *state, int sx, int sy, int dx, int dy) { int x = sx - dx, y = sy - dy; while (INGRID(state, x, y)) { if (GRID(state, x, y) & G_ISLAND) goto found; x -= dx; y -= dy; } return 0; found: x = sx + dx, y = sy + dy; while (INGRID(state, x, y)) { if (GRID(state, x, y) & G_ISLAND) return 1; x += dx; y += dy; } return 0; } static void lines_lvlh(const game_state *state, const game_ui *ui, int x, int y, grid_type v, int *lv_r, int *lh_r) { int lh = 0, lv = 0; if (v & G_LINEV) lv = INDEX(state,lines,x,y); if (v & G_LINEH) lh = INDEX(state,lines,x,y); if (ui->show_hints) { if (between_island(state, x, y, 0, 1) && !lv) lv = 1; if (between_island(state, x, y, 1, 0) && !lh) lh = 1; } /*debug(("lvlh: (%d,%d) v 0x%x lv %d lh %d.\n", x, y, v, lv, lh));*/ *lv_r = lv; *lh_r = lh; } static void draw_cross(drawing *dr, game_drawstate *ds, int ox, int oy, int col) { int off = TS8(2); draw_line(dr, ox, oy, ox+off, oy+off, col); draw_line(dr, ox+off, oy, ox, oy+off, col); } static void draw_general_line(drawing *dr, game_drawstate *ds, int ox, int oy, int fx, int fy, int ax, int ay, int len, unsigned long ldata, int which) { /* * Draw one direction of lines in a square. To permit the same * code to handle horizontal and vertical lines, fx,fy are the * 'forward' direction (along the lines) and ax,ay are the * 'across' direction. * * We draw the white background for a locked bridge if (which & * 1), and draw the bridges themselves if (which & 2). This * permits us to get two overlapping locked bridges right without * one of them erasing part of the other. */ int fg; fg = ((ldata & DL_COUNTMASK) == DL_COUNT_HINT ? COL_HINT : (ldata & DL_COLMASK) == DL_COL_SELECTED ? COL_SELECTED : (ldata & DL_COLMASK) == DL_COL_FLASH ? COL_HIGHLIGHT : (ldata & DL_COLMASK) == DL_COL_WARNING ? COL_WARNING : COL_FOREGROUND); if ((ldata & DL_COUNTMASK) == DL_COUNT_CROSS) { draw_cross(dr, ds, ox + TS8(1)*fx + TS8(3)*ax, oy + TS8(1)*fy + TS8(3)*ay, fg); draw_cross(dr, ds, ox + TS8(5)*fx + TS8(3)*ax, oy + TS8(5)*fy + TS8(3)*ay, fg); } else if ((ldata & DL_COUNTMASK) != 0) { int lh, lw, gw, bw, i, loff; lh = (ldata & DL_COUNTMASK); if (lh == DL_COUNT_HINT) lh = 1; lw = gw = LINE_WIDTH; while ((bw = lw * lh + gw * (lh+1)) > TILE_SIZE) gw--; loff = OFFSET(bw); if (which & 1) { if ((ldata & DL_LOCK) && fg != COL_HINT) draw_rect(dr, ox + loff*ax, oy + loff*ay, len*fx+bw*ax, len*fy+bw*ay, COL_MARK); } if (which & 2) { for (i = 0; i < lh; i++, loff += lw + gw) draw_rect(dr, ox + (loff+gw)*ax, oy + (loff+gw)*ay, len*fx+lw*ax, len*fy+lw*ay, fg); } } } static void draw_hline(drawing *dr, game_drawstate *ds, int ox, int oy, int w, unsigned long vdata, int which) { draw_general_line(dr, ds, ox, oy, 1, 0, 0, 1, w, vdata, which); } static void draw_vline(drawing *dr, game_drawstate *ds, int ox, int oy, int h, unsigned long vdata, int which) { draw_general_line(dr, ds, ox, oy, 0, 1, 1, 0, h, vdata, which); } #define ISLAND_RADIUS ((TILE_SIZE*12)/20) #define ISLAND_NUMSIZE(clue) \ (((clue) < 10) ? (TILE_SIZE*7)/10 : (TILE_SIZE*5)/10) static void draw_island(drawing *dr, game_drawstate *ds, int ox, int oy, int clue, unsigned long idata) { int half, orad, irad, fg, bg; if ((idata & DI_BGMASK) == DI_BG_NO_ISLAND) return; half = TILE_SIZE/2; orad = ISLAND_RADIUS; irad = orad - LINE_WIDTH; fg = ((idata & DI_COLMASK) == DI_COL_SELECTED ? COL_SELECTED : (idata & DI_COLMASK) == DI_COL_WARNING ? COL_WARNING : (idata & DI_COLMASK) == DI_COL_FLASH ? COL_HIGHLIGHT : COL_FOREGROUND); bg = ((idata & DI_BGMASK) == DI_BG_CURSOR ? COL_CURSOR : (idata & DI_BGMASK) == DI_BG_MARK ? COL_MARK : COL_BACKGROUND); /* draw a thick circle */ draw_circle(dr, ox+half, oy+half, orad, fg, fg); draw_circle(dr, ox+half, oy+half, irad, bg, bg); if (clue > 0) { char str[32]; int textcolour = (fg == COL_SELECTED ? COL_FOREGROUND : fg); sprintf(str, "%d", clue); draw_text(dr, ox+half, oy+half, FONT_VARIABLE, ISLAND_NUMSIZE(clue), ALIGN_VCENTRE | ALIGN_HCENTRE, textcolour, str); } } static void draw_island_tile(drawing *dr, game_drawstate *ds, int x, int y, int clue, unsigned long data) { int ox = COORD(x), oy = COORD(y); int which; clip(dr, ox, oy, TILE_SIZE, TILE_SIZE); draw_rect(dr, ox, oy, TILE_SIZE, TILE_SIZE, COL_BACKGROUND); /* * Because of the possibility of incoming bridges just about * meeting at one corner, we must split the line-drawing into * background and foreground segments. */ for (which = 1; which <= 2; which <<= 1) { draw_hline(dr, ds, ox, oy, TILE_SIZE/2, (data >> D_I_LINE_SHIFT_L) & DL_MASK, which); draw_hline(dr, ds, ox + TILE_SIZE - TILE_SIZE/2, oy, TILE_SIZE/2, (data >> D_I_LINE_SHIFT_R) & DL_MASK, which); draw_vline(dr, ds, ox, oy, TILE_SIZE/2, (data >> D_I_LINE_SHIFT_U) & DL_MASK, which); draw_vline(dr, ds, ox, oy + TILE_SIZE - TILE_SIZE/2, TILE_SIZE/2, (data >> D_I_LINE_SHIFT_D) & DL_MASK, which); } draw_island(dr, ds, ox, oy, clue, (data >> D_I_ISLAND_SHIFT) & DI_MASK); unclip(dr); draw_update(dr, ox, oy, TILE_SIZE, TILE_SIZE); } static void draw_line_tile(drawing *dr, game_drawstate *ds, int x, int y, unsigned long data) { int ox = COORD(x), oy = COORD(y); unsigned long hdata, vdata; clip(dr, ox, oy, TILE_SIZE, TILE_SIZE); draw_rect(dr, ox, oy, TILE_SIZE, TILE_SIZE, COL_BACKGROUND); /* * We have to think about which of the horizontal and vertical * line to draw first, if both exist. * * The rule is that hint lines are drawn at the bottom, then * NOLINE crosses, then actual bridges. The enumeration in the * DL_COUNTMASK field is set up so that this drops out of a * straight comparison between the two. * * Since lines crossing in this type of square cannot both be * actual bridges, there's no need to pass a nontrivial 'which' * parameter to draw_[hv]line. */ hdata = (data >> D_L_LINE_SHIFT_H) & DL_MASK; vdata = (data >> D_L_LINE_SHIFT_V) & DL_MASK; if ((hdata & DL_COUNTMASK) > (vdata & DL_COUNTMASK)) { draw_hline(dr, ds, ox, oy, TILE_SIZE, hdata, 3); draw_vline(dr, ds, ox, oy, TILE_SIZE, vdata, 3); } else { draw_vline(dr, ds, ox, oy, TILE_SIZE, vdata, 3); draw_hline(dr, ds, ox, oy, TILE_SIZE, hdata, 3); } /* * The islands drawn at the edges of a line tile don't need clue * numbers. */ draw_island(dr, ds, ox - TILE_SIZE, oy, -1, (data >> D_L_ISLAND_SHIFT_L) & DI_MASK); draw_island(dr, ds, ox + TILE_SIZE, oy, -1, (data >> D_L_ISLAND_SHIFT_R) & DI_MASK); draw_island(dr, ds, ox, oy - TILE_SIZE, -1, (data >> D_L_ISLAND_SHIFT_U) & DI_MASK); draw_island(dr, ds, ox, oy + TILE_SIZE, -1, (data >> D_L_ISLAND_SHIFT_D) & DI_MASK); unclip(dr); draw_update(dr, ox, oy, TILE_SIZE, TILE_SIZE); } static void draw_edge_tile(drawing *dr, game_drawstate *ds, int x, int y, int dx, int dy, unsigned long data) { int ox = COORD(x), oy = COORD(y); int cx = ox, cy = oy, cw = TILE_SIZE, ch = TILE_SIZE; if (dy) { if (dy > 0) cy += TILE_SIZE/2; ch -= TILE_SIZE/2; } else { if (dx > 0) cx += TILE_SIZE/2; cw -= TILE_SIZE/2; } clip(dr, cx, cy, cw, ch); draw_rect(dr, cx, cy, cw, ch, COL_BACKGROUND); draw_island(dr, ds, ox + TILE_SIZE*dx, oy + TILE_SIZE*dy, -1, (data >> D_I_ISLAND_SHIFT) & DI_MASK); unclip(dr); draw_update(dr, cx, cy, cw, ch); } static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float animtime, float flashtime) { int x, y, lv, lh; grid_type v, flash = 0; struct island *is, *is_drag_src = NULL, *is_drag_dst = NULL; if (flashtime) { int f = (int)(flashtime * 5 / FLASH_TIME); if (f == 1 || f == 3) flash = TRUE; } /* Clear screen, if required. */ if (!ds->started) { draw_rect(dr, 0, 0, TILE_SIZE * ds->w + 2 * BORDER, TILE_SIZE * ds->h + 2 * BORDER, COL_BACKGROUND); #ifdef DRAW_GRID draw_rect_outline(dr, COORD(0)-1, COORD(0)-1, TILE_SIZE * ds->w + 2, TILE_SIZE * ds->h + 2, COL_GRID); #endif draw_update(dr, 0, 0, TILE_SIZE * ds->w + 2 * BORDER, TILE_SIZE * ds->h + 2 * BORDER); ds->started = 1; } if (ui->dragx_src != -1 && ui->dragy_src != -1) { ds->dragging = 1; is_drag_src = INDEX(state, gridi, ui->dragx_src, ui->dragy_src); assert(is_drag_src); if (ui->dragx_dst != -1 && ui->dragy_dst != -1) { is_drag_dst = INDEX(state, gridi, ui->dragx_dst, ui->dragy_dst); assert(is_drag_dst); } } else ds->dragging = 0; /* * Set up ds->newgrid with the current grid contents. */ for (x = 0; x < ds->w; x++) for (y = 0; y < ds->h; y++) INDEX(ds,newgrid,x,y) = 0; for (x = 0; x < ds->w; x++) { for (y = 0; y < ds->h; y++) { v = GRID(state, x, y); if (v & G_ISLAND) { /* * An island square. Compute the drawing data for the * island, and put it in this square and surrounding * squares. */ unsigned long idata = 0; is = INDEX(state, gridi, x, y); if (flash) idata |= DI_COL_FLASH; if (is_drag_src && (is == is_drag_src || (is_drag_dst && is == is_drag_dst))) idata |= DI_COL_SELECTED; else if (island_impossible(is, v & G_MARK) || (v & G_WARN)) idata |= DI_COL_WARNING; else idata |= DI_COL_NORMAL; if (ui->cur_visible && ui->cur_x == is->x && ui->cur_y == is->y) idata |= DI_BG_CURSOR; else if (v & G_MARK) idata |= DI_BG_MARK; else idata |= DI_BG_NORMAL; INDEX(ds,newgrid,x,y) |= idata << D_I_ISLAND_SHIFT; if (x > 0 && !(GRID(state,x-1,y) & G_ISLAND)) INDEX(ds,newgrid,x-1,y) |= idata << D_L_ISLAND_SHIFT_R; if (x+1 < state->w && !(GRID(state,x+1,y) & G_ISLAND)) INDEX(ds,newgrid,x+1,y) |= idata << D_L_ISLAND_SHIFT_L; if (y > 0 && !(GRID(state,x,y-1) & G_ISLAND)) INDEX(ds,newgrid,x,y-1) |= idata << D_L_ISLAND_SHIFT_D; if (y+1 < state->h && !(GRID(state,x,y+1) & G_ISLAND)) INDEX(ds,newgrid,x,y+1) |= idata << D_L_ISLAND_SHIFT_U; } else { unsigned long hdata, vdata; int selh = FALSE, selv = FALSE; /* * A line (non-island) square. Compute the drawing * data for any horizontal and vertical lines in the * square, and put them in this square's entry and * optionally those for neighbouring islands too. */ if (is_drag_dst && WITHIN(x,is_drag_src->x, is_drag_dst->x) && WITHIN(y,is_drag_src->y, is_drag_dst->y)) { if (is_drag_src->x != is_drag_dst->x) selh = TRUE; else selv = TRUE; } lines_lvlh(state, ui, x, y, v, &lv, &lh); hdata = (v & G_NOLINEH ? DL_COUNT_CROSS : v & G_LINEH ? lh : (ui->show_hints && between_island(state,x,y,1,0)) ? DL_COUNT_HINT : 0); vdata = (v & G_NOLINEV ? DL_COUNT_CROSS : v & G_LINEV ? lv : (ui->show_hints && between_island(state,x,y,0,1)) ? DL_COUNT_HINT : 0); hdata |= (flash ? DL_COL_FLASH : v & G_WARN ? DL_COL_WARNING : selh ? DL_COL_SELECTED : DL_COL_NORMAL); vdata |= (flash ? DL_COL_FLASH : v & G_WARN ? DL_COL_WARNING : selv ? DL_COL_SELECTED : DL_COL_NORMAL); if (v & G_MARKH) hdata |= DL_LOCK; if (v & G_MARKV) vdata |= DL_LOCK; INDEX(ds,newgrid,x,y) |= hdata << D_L_LINE_SHIFT_H; INDEX(ds,newgrid,x,y) |= vdata << D_L_LINE_SHIFT_V; if (x > 0 && (GRID(state,x-1,y) & G_ISLAND)) INDEX(ds,newgrid,x-1,y) |= hdata << D_I_LINE_SHIFT_R; if (x+1 < state->w && (GRID(state,x+1,y) & G_ISLAND)) INDEX(ds,newgrid,x+1,y) |= hdata << D_I_LINE_SHIFT_L; if (y > 0 && (GRID(state,x,y-1) & G_ISLAND)) INDEX(ds,newgrid,x,y-1) |= vdata << D_I_LINE_SHIFT_D; if (y+1 < state->h && (GRID(state,x,y+1) & G_ISLAND)) INDEX(ds,newgrid,x,y+1) |= vdata << D_I_LINE_SHIFT_U; } } } /* * Now go through and draw any changed grid square. */ for (x = 0; x < ds->w; x++) { for (y = 0; y < ds->h; y++) { unsigned long newval = INDEX(ds,newgrid,x,y); if (INDEX(ds,grid,x,y) != newval) { v = GRID(state, x, y); if (v & G_ISLAND) { is = INDEX(state, gridi, x, y); draw_island_tile(dr, ds, x, y, is->count, newval); /* * If this tile is right at the edge of the grid, * we must also draw the part of the island that * goes completely out of bounds. We don't bother * keeping separate entries in ds->newgrid for * these tiles; it's easier just to redraw them * iff we redraw their parent island tile. */ if (x == 0) draw_edge_tile(dr, ds, x-1, y, +1, 0, newval); if (y == 0) draw_edge_tile(dr, ds, x, y-1, 0, +1, newval); if (x == state->w-1) draw_edge_tile(dr, ds, x+1, y, -1, 0, newval); if (y == state->h-1) draw_edge_tile(dr, ds, x, y+1, 0, -1, newval); } else { draw_line_tile(dr, ds, x, y, newval); } INDEX(ds,grid,x,y) = newval; } } } } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return 0.0F; } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { if (!oldstate->completed && newstate->completed && !oldstate->solved && !newstate->solved) return FLASH_TIME; return 0.0F; } static int game_status(const game_state *state) { return state->completed ? +1 : 0; } static int game_timing_state(const game_state *state, game_ui *ui) { return TRUE; } static void game_print_size(const game_params *params, float *x, float *y) { int pw, ph; /* 10mm squares by default. */ game_compute_size(params, 1000, &pw, &ph); *x = pw / 100.0F; *y = ph / 100.0F; } static void game_print(drawing *dr, const game_state *state, int ts) { int ink = print_mono_colour(dr, 0); int paper = print_mono_colour(dr, 1); int x, y, cx, cy, i, nl; int loff; grid_type grid; /* Ick: fake up `ds->tilesize' for macro expansion purposes */ game_drawstate ads, *ds = &ads; ads.tilesize = ts; /* I don't think this wants a border. */ /* Bridges */ loff = ts / (8 * sqrt((state->params.maxb - 1))); print_line_width(dr, ts / 12); for (x = 0; x < state->w; x++) { for (y = 0; y < state->h; y++) { cx = COORD(x); cy = COORD(y); grid = GRID(state,x,y); nl = INDEX(state,lines,x,y); if (grid & G_ISLAND) continue; if (grid & G_LINEV) { for (i = 0; i < nl; i++) draw_line(dr, cx+ts/2+(2*i-nl+1)*loff, cy, cx+ts/2+(2*i-nl+1)*loff, cy+ts, ink); } if (grid & G_LINEH) { for (i = 0; i < nl; i++) draw_line(dr, cx, cy+ts/2+(2*i-nl+1)*loff, cx+ts, cy+ts/2+(2*i-nl+1)*loff, ink); } } } /* Islands */ for (i = 0; i < state->n_islands; i++) { char str[32]; struct island *is = &state->islands[i]; grid = GRID(state, is->x, is->y); cx = COORD(is->x) + ts/2; cy = COORD(is->y) + ts/2; draw_circle(dr, cx, cy, ISLAND_RADIUS, paper, ink); sprintf(str, "%d", is->count); draw_text(dr, cx, cy, FONT_VARIABLE, ISLAND_NUMSIZE(is->count), ALIGN_VCENTRE | ALIGN_HCENTRE, ink, str); } } #ifdef COMBINED #define thegame bridges #endif const struct game thegame = { "Bridges", "games.bridges", "bridges", default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, TRUE, solve_game, TRUE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, PREFERRED_TILE_SIZE, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, TRUE, FALSE, game_print_size, game_print, FALSE, /* wants_statusbar */ FALSE, game_timing_state, REQUIRE_RBUTTON, /* flags */ }; /* vim: set shiftwidth=4 tabstop=8: */ puzzles-20170606.272beef/blackbox.c0000644000175000017500000013146113115373615015630 0ustar simonsimon/* * blackbox.c: implementation of 'Black Box'. */ #include #include #include #include #include #include #include "puzzles.h" #define PREFERRED_TILE_SIZE 32 #define FLASH_FRAME 0.2F /* Terminology, for ease of reading various macros scattered about the place. * * The 'arena' is the inner area where the balls are placed. This is * indexed from (0,0) to (w-1,h-1) but its offset in the grid is (1,1). * * The 'range' (firing range) is the bit around the edge where * the lasers are fired from. This is indexed from 0 --> (2*(w+h) - 1), * starting at the top left ((1,0) on the grid) and moving clockwise. * * The 'grid' is just the big array containing arena and range; * locations (0,0), (0,w+1), (h+1,w+1) and (h+1,0) are unused. */ enum { COL_BACKGROUND, COL_COVER, COL_LOCK, COL_TEXT, COL_FLASHTEXT, COL_HIGHLIGHT, COL_LOWLIGHT, COL_GRID, COL_BALL, COL_WRONG, COL_BUTTON, COL_CURSOR, NCOLOURS }; struct game_params { int w, h; int minballs, maxballs; }; static game_params *default_params(void) { game_params *ret = snew(game_params); ret->w = ret->h = 8; ret->minballs = ret->maxballs = 5; return ret; } static const game_params blackbox_presets[] = { { 5, 5, 3, 3 }, { 8, 8, 5, 5 }, { 8, 8, 3, 6 }, { 10, 10, 5, 5 }, { 10, 10, 4, 10 } }; static int game_fetch_preset(int i, char **name, game_params **params) { char str[80]; game_params *ret; if (i < 0 || i >= lenof(blackbox_presets)) return FALSE; ret = snew(game_params); *ret = blackbox_presets[i]; if (ret->minballs == ret->maxballs) sprintf(str, "%dx%d, %d balls", ret->w, ret->h, ret->minballs); else sprintf(str, "%dx%d, %d-%d balls", ret->w, ret->h, ret->minballs, ret->maxballs); *name = dupstr(str); *params = ret; return TRUE; } static void free_params(game_params *params) { sfree(params); } static game_params *dup_params(const game_params *params) { game_params *ret = snew(game_params); *ret = *params; /* structure copy */ return ret; } static void decode_params(game_params *params, char const *string) { char const *p = string; game_params *defs = default_params(); *params = *defs; free_params(defs); while (*p) { switch (*p++) { case 'w': params->w = atoi(p); while (*p && isdigit((unsigned char)*p)) p++; break; case 'h': params->h = atoi(p); while (*p && isdigit((unsigned char)*p)) p++; break; case 'm': params->minballs = atoi(p); while (*p && isdigit((unsigned char)*p)) p++; break; case 'M': params->maxballs = atoi(p); while (*p && isdigit((unsigned char)*p)) p++; break; default: ; } } } static char *encode_params(const game_params *params, int full) { char str[256]; sprintf(str, "w%dh%dm%dM%d", params->w, params->h, params->minballs, params->maxballs); return dupstr(str); } static config_item *game_configure(const game_params *params) { config_item *ret; char buf[80]; ret = snewn(4, config_item); ret[0].name = "Width"; ret[0].type = C_STRING; sprintf(buf, "%d", params->w); ret[0].sval = dupstr(buf); ret[0].ival = 0; ret[1].name = "Height"; ret[1].type = C_STRING; sprintf(buf, "%d", params->h); ret[1].sval = dupstr(buf); ret[1].ival = 0; ret[2].name = "No. of balls"; ret[2].type = C_STRING; if (params->minballs == params->maxballs) sprintf(buf, "%d", params->minballs); else sprintf(buf, "%d-%d", params->minballs, params->maxballs); ret[2].sval = dupstr(buf); ret[2].ival = 0; ret[3].name = NULL; ret[3].type = C_END; ret[3].sval = NULL; ret[3].ival = 0; return ret; } static game_params *custom_params(const config_item *cfg) { game_params *ret = snew(game_params); ret->w = atoi(cfg[0].sval); ret->h = atoi(cfg[1].sval); /* Allow 'a-b' for a range, otherwise assume a single number. */ if (sscanf(cfg[2].sval, "%d-%d", &ret->minballs, &ret->maxballs) < 2) ret->minballs = ret->maxballs = atoi(cfg[2].sval); return ret; } static char *validate_params(const game_params *params, int full) { if (params->w < 2 || params->h < 2) return "Width and height must both be at least two"; /* next one is just for ease of coding stuff into 'char' * types, and could be worked around if required. */ if (params->w > 255 || params->h > 255) return "Widths and heights greater than 255 are not supported"; if (params->minballs > params->maxballs) return "Minimum number of balls may not be greater than maximum"; if (params->minballs >= params->w * params->h) return "Too many balls to fit in grid"; return NULL; } /* * We store: width | height | ball1x | ball1y | [ ball2x | ball2y | [...] ] * all stored as unsigned chars; validate_params has already * checked this won't overflow an 8-bit char. * Then we obfuscate it. */ static char *new_game_desc(const game_params *params, random_state *rs, char **aux, int interactive) { int nballs = params->minballs, i; char *grid, *ret; unsigned char *bmp; if (params->maxballs > params->minballs) nballs += random_upto(rs, params->maxballs - params->minballs + 1); grid = snewn(params->w*params->h, char); memset(grid, 0, params->w * params->h * sizeof(char)); bmp = snewn(nballs*2 + 2, unsigned char); memset(bmp, 0, (nballs*2 + 2) * sizeof(unsigned char)); bmp[0] = params->w; bmp[1] = params->h; for (i = 0; i < nballs; i++) { int x, y; do { x = random_upto(rs, params->w); y = random_upto(rs, params->h); } while (grid[y*params->w + x]); grid[y*params->w + x] = 1; bmp[(i+1)*2 + 0] = x; bmp[(i+1)*2 + 1] = y; } sfree(grid); obfuscate_bitmap(bmp, (nballs*2 + 2) * 8, FALSE); ret = bin2hex(bmp, nballs*2 + 2); sfree(bmp); return ret; } static char *validate_desc(const game_params *params, const char *desc) { int nballs, dlen = strlen(desc), i; unsigned char *bmp; char *ret; /* the bitmap is 2+(nballs*2) long; the hex version is double that. */ nballs = ((dlen/2)-2)/2; if (dlen < 4 || dlen % 4 || nballs < params->minballs || nballs > params->maxballs) return "Game description is wrong length"; bmp = hex2bin(desc, nballs*2 + 2); obfuscate_bitmap(bmp, (nballs*2 + 2) * 8, TRUE); ret = "Game description is corrupted"; /* check general grid size */ if (bmp[0] != params->w || bmp[1] != params->h) goto done; /* check each ball will fit on that grid */ for (i = 0; i < nballs; i++) { int x = bmp[(i+1)*2 + 0], y = bmp[(i+1)*2 + 1]; if (x < 0 || y < 0 || x >= params->w || y >= params->h) goto done; } ret = NULL; done: sfree(bmp); return ret; } #define BALL_CORRECT 0x01 #define BALL_GUESS 0x02 #define BALL_LOCK 0x04 #define LASER_FLAGMASK 0x1f800 #define LASER_OMITTED 0x0800 #define LASER_REFLECT 0x1000 #define LASER_HIT 0x2000 #define LASER_WRONG 0x4000 #define LASER_FLASHED 0x8000 #define LASER_EMPTY (~0) #define FLAG_CURSOR 0x10000 /* needs to be disjoint from both sets */ struct game_state { int w, h, minballs, maxballs, nballs, nlasers; unsigned int *grid; /* (w+2)x(h+2), to allow for laser firing range */ unsigned int *exits; /* one per laser */ int done; /* user has finished placing his own balls. */ int laserno; /* number of next laser to be fired. */ int nguesses, reveal, justwrong, nright, nwrong, nmissed; }; #define GRID(s,x,y) ((s)->grid[(y)*((s)->w+2) + (x)]) #define RANGECHECK(s,x) ((x) >= 0 && (x) <= (s)->nlasers) /* specify numbers because they must match array indexes. */ enum { DIR_UP = 0, DIR_RIGHT = 1, DIR_DOWN = 2, DIR_LEFT = 3 }; struct offset { int x, y; }; static const struct offset offsets[] = { { 0, -1 }, /* up */ { 1, 0 }, /* right */ { 0, 1 }, /* down */ { -1, 0 } /* left */ }; #ifdef DEBUGGING static const char *dirstrs[] = { "UP", "RIGHT", "DOWN", "LEFT" }; #endif static int range2grid(const game_state *state, int rangeno, int *x, int *y, int *direction) { if (rangeno < 0) return 0; if (rangeno < state->w) { /* top row; from (1,0) to (w,0) */ *x = rangeno + 1; *y = 0; *direction = DIR_DOWN; return 1; } rangeno -= state->w; if (rangeno < state->h) { /* RHS; from (w+1, 1) to (w+1, h) */ *x = state->w+1; *y = rangeno + 1; *direction = DIR_LEFT; return 1; } rangeno -= state->h; if (rangeno < state->w) { /* bottom row; from (1, h+1) to (w, h+1); counts backwards */ *x = (state->w - rangeno); *y = state->h+1; *direction = DIR_UP; return 1; } rangeno -= state->w; if (rangeno < state->h) { /* LHS; from (0, 1) to (0, h); counts backwards */ *x = 0; *y = (state->h - rangeno); *direction = DIR_RIGHT; return 1; } return 0; } static int grid2range(const game_state *state, int x, int y, int *rangeno) { int ret, x1 = state->w+1, y1 = state->h+1; if (x > 0 && x < x1 && y > 0 && y < y1) return 0; /* in arena */ if (x < 0 || x > x1 || y < 0 || y > y1) return 0; /* outside grid */ if ((x == 0 || x == x1) && (y == 0 || y == y1)) return 0; /* one of 4 corners */ if (y == 0) { /* top line */ ret = x - 1; } else if (x == x1) { /* RHS */ ret = y - 1 + state->w; } else if (y == y1) { /* Bottom [and counts backwards] */ ret = (state->w - x) + state->w + state->h; } else { /* LHS [and counts backwards ] */ ret = (state->h-y) + state->w + state->w + state->h; } *rangeno = ret; debug(("grid2range: (%d,%d) rangeno = %d\n", x, y, ret)); return 1; } static game_state *new_game(midend *me, const game_params *params, const char *desc) { game_state *state = snew(game_state); int dlen = strlen(desc), i; unsigned char *bmp; state->minballs = params->minballs; state->maxballs = params->maxballs; state->nballs = ((dlen/2)-2)/2; bmp = hex2bin(desc, state->nballs*2 + 2); obfuscate_bitmap(bmp, (state->nballs*2 + 2) * 8, TRUE); state->w = bmp[0]; state->h = bmp[1]; state->nlasers = 2 * (state->w + state->h); state->grid = snewn((state->w+2)*(state->h+2), unsigned int); memset(state->grid, 0, (state->w+2)*(state->h+2) * sizeof(unsigned int)); state->exits = snewn(state->nlasers, unsigned int); memset(state->exits, LASER_EMPTY, state->nlasers * sizeof(unsigned int)); for (i = 0; i < state->nballs; i++) { GRID(state, bmp[(i+1)*2 + 0]+1, bmp[(i+1)*2 + 1]+1) = BALL_CORRECT; } sfree(bmp); state->done = state->nguesses = state->reveal = state->justwrong = state->nright = state->nwrong = state->nmissed = 0; state->laserno = 1; return state; } #define XFER(x) ret->x = state->x static game_state *dup_game(const game_state *state) { game_state *ret = snew(game_state); XFER(w); XFER(h); XFER(minballs); XFER(maxballs); XFER(nballs); XFER(nlasers); ret->grid = snewn((ret->w+2)*(ret->h+2), unsigned int); memcpy(ret->grid, state->grid, (ret->w+2)*(ret->h+2) * sizeof(unsigned int)); ret->exits = snewn(ret->nlasers, unsigned int); memcpy(ret->exits, state->exits, ret->nlasers * sizeof(unsigned int)); XFER(done); XFER(laserno); XFER(nguesses); XFER(reveal); XFER(justwrong); XFER(nright); XFER(nwrong); XFER(nmissed); return ret; } #undef XFER static void free_game(game_state *state) { sfree(state->exits); sfree(state->grid); sfree(state); } static char *solve_game(const game_state *state, const game_state *currstate, const char *aux, char **error) { return dupstr("S"); } static int game_can_format_as_text_now(const game_params *params) { return TRUE; } static char *game_text_format(const game_state *state) { return NULL; } struct game_ui { int flash_laserno; int errors, newmove; int cur_x, cur_y, cur_visible; int flash_laser; /* 0 = never, 1 = always, 2 = if anim. */ }; static game_ui *new_ui(const game_state *state) { game_ui *ui = snew(game_ui); ui->flash_laserno = LASER_EMPTY; ui->errors = 0; ui->newmove = FALSE; ui->cur_x = ui->cur_y = 1; ui->cur_visible = 0; ui->flash_laser = 0; return ui; } static void free_ui(game_ui *ui) { sfree(ui); } static char *encode_ui(const game_ui *ui) { char buf[80]; /* * The error counter needs preserving across a serialisation. */ sprintf(buf, "E%d", ui->errors); return dupstr(buf); } static void decode_ui(game_ui *ui, const char *encoding) { sscanf(encoding, "E%d", &ui->errors); } static void game_changed_state(game_ui *ui, const game_state *oldstate, const game_state *newstate) { /* * If we've encountered a `justwrong' state as a result of * actually making a move, increment the ui error counter. */ if (newstate->justwrong && ui->newmove) ui->errors++; ui->newmove = FALSE; } #define OFFSET(gx,gy,o) do { \ int off = (4 + (o) % 4) % 4; \ (gx) += offsets[off].x; \ (gy) += offsets[off].y; \ } while(0) enum { LOOK_LEFT, LOOK_FORWARD, LOOK_RIGHT }; /* Given a position and a direction, check whether we can see a ball in front * of us, or to our front-left or front-right. */ static int isball(game_state *state, int gx, int gy, int direction, int lookwhere) { debug(("isball, (%d, %d), dir %s, lookwhere %s\n", gx, gy, dirstrs[direction], lookwhere == LOOK_LEFT ? "LEFT" : lookwhere == LOOK_FORWARD ? "FORWARD" : "RIGHT")); OFFSET(gx,gy,direction); if (lookwhere == LOOK_LEFT) OFFSET(gx,gy,direction-1); else if (lookwhere == LOOK_RIGHT) OFFSET(gx,gy,direction+1); else if (lookwhere != LOOK_FORWARD) assert(!"unknown lookwhere"); debug(("isball, new (%d, %d)\n", gx, gy)); /* if we're off the grid (into the firing range) there's never a ball. */ if (gx < 1 || gy < 1 || gx > state->w || gy > state->h) return 0; if (GRID(state, gx,gy) & BALL_CORRECT) return 1; return 0; } static int fire_laser_internal(game_state *state, int x, int y, int direction) { int unused, lno, tmp; tmp = grid2range(state, x, y, &lno); assert(tmp); /* deal with strange initial reflection rules (that stop * you turning down the laser range) */ /* I've just chosen to prioritise instant-hit over instant-reflection; * I can't find anywhere that gives me a definite algorithm for this. */ if (isball(state, x, y, direction, LOOK_FORWARD)) { debug(("Instant hit at (%d, %d)\n", x, y)); return LASER_HIT; /* hit */ } if (isball(state, x, y, direction, LOOK_LEFT) || isball(state, x, y, direction, LOOK_RIGHT)) { debug(("Instant reflection at (%d, %d)\n", x, y)); return LASER_REFLECT; /* reflection */ } /* move us onto the grid. */ OFFSET(x, y, direction); while (1) { debug(("fire_laser: looping at (%d, %d) pointing %s\n", x, y, dirstrs[direction])); if (grid2range(state, x, y, &unused)) { int exitno; tmp = grid2range(state, x, y, &exitno); assert(tmp); return (lno == exitno ? LASER_REFLECT : exitno); } /* paranoia. This obviously should never happen */ assert(!(GRID(state, x, y) & BALL_CORRECT)); if (isball(state, x, y, direction, LOOK_FORWARD)) { /* we're facing a ball; send back a reflection. */ debug(("Ball ahead of (%d, %d)", x, y)); return LASER_HIT; /* hit */ } if (isball(state, x, y, direction, LOOK_LEFT)) { /* ball to our left; rotate clockwise and look again. */ debug(("Ball to left; turning clockwise.\n")); direction += 1; direction %= 4; continue; } if (isball(state, x, y, direction, LOOK_RIGHT)) { /* ball to our right; rotate anti-clockwise and look again. */ debug(("Ball to rightl turning anti-clockwise.\n")); direction += 3; direction %= 4; continue; } /* ... otherwise, we have no balls ahead of us so just move one step. */ debug(("No balls; moving forwards.\n")); OFFSET(x, y, direction); } } static int laser_exit(game_state *state, int entryno) { int tmp, x, y, direction; tmp = range2grid(state, entryno, &x, &y, &direction); assert(tmp); return fire_laser_internal(state, x, y, direction); } static void fire_laser(game_state *state, int entryno) { int tmp, exitno, x, y, direction; tmp = range2grid(state, entryno, &x, &y, &direction); assert(tmp); exitno = fire_laser_internal(state, x, y, direction); if (exitno == LASER_HIT || exitno == LASER_REFLECT) { GRID(state, x, y) = state->exits[entryno] = exitno; } else { int newno = state->laserno++; int xend, yend, unused; tmp = range2grid(state, exitno, &xend, ¥d, &unused); assert(tmp); GRID(state, x, y) = GRID(state, xend, yend) = newno; state->exits[entryno] = exitno; state->exits[exitno] = entryno; } } /* Checks that the guessed balls in the state match up with the real balls * for all possible lasers (i.e. not just the ones that the player might * have already guessed). This is required because any layout with >4 balls * might have multiple valid solutions. Returns non-zero for a 'correct' * (i.e. consistent) layout. */ static int check_guesses(game_state *state, int cagey) { game_state *solution, *guesses; int i, x, y, n, unused, tmp; int ret = 0; if (cagey) { /* * First, check that each laser the player has already * fired is consistent with the layout. If not, show them * one error they've made and reveal no further * information. * * Failing that, check to see whether the player would have * been able to fire any laser which distinguished the real * solution from their guess. If so, show them one such * laser and reveal no further information. */ guesses = dup_game(state); /* clear out BALL_CORRECT on guess, make BALL_GUESS BALL_CORRECT. */ for (x = 1; x <= state->w; x++) { for (y = 1; y <= state->h; y++) { GRID(guesses, x, y) &= ~BALL_CORRECT; if (GRID(guesses, x, y) & BALL_GUESS) GRID(guesses, x, y) |= BALL_CORRECT; } } n = 0; for (i = 0; i < guesses->nlasers; i++) { if (guesses->exits[i] != LASER_EMPTY && guesses->exits[i] != laser_exit(guesses, i)) n++; } if (n) { /* * At least one of the player's existing lasers * contradicts their ball placement. Pick a random one, * highlight it, and return. * * A temporary random state is created from the current * grid, so that repeating the same marking will give * the same answer instead of a different one. */ random_state *rs = random_new((char *)guesses->grid, (state->w+2)*(state->h+2) * sizeof(unsigned int)); n = random_upto(rs, n); random_free(rs); for (i = 0; i < guesses->nlasers; i++) { if (guesses->exits[i] != LASER_EMPTY && guesses->exits[i] != laser_exit(guesses, i) && n-- == 0) { state->exits[i] |= LASER_WRONG; tmp = laser_exit(state, i); if (RANGECHECK(state, tmp)) state->exits[tmp] |= LASER_WRONG; state->justwrong = TRUE; free_game(guesses); return 0; } } } n = 0; for (i = 0; i < guesses->nlasers; i++) { if (guesses->exits[i] == LASER_EMPTY && laser_exit(state, i) != laser_exit(guesses, i)) n++; } if (n) { /* * At least one of the player's unfired lasers would * demonstrate their ball placement to be wrong. Pick a * random one, highlight it, and return. * * A temporary random state is created from the current * grid, so that repeating the same marking will give * the same answer instead of a different one. */ random_state *rs = random_new((char *)guesses->grid, (state->w+2)*(state->h+2) * sizeof(unsigned int)); n = random_upto(rs, n); random_free(rs); for (i = 0; i < guesses->nlasers; i++) { if (guesses->exits[i] == LASER_EMPTY && laser_exit(state, i) != laser_exit(guesses, i) && n-- == 0) { fire_laser(state, i); state->exits[i] |= LASER_OMITTED; tmp = laser_exit(state, i); if (RANGECHECK(state, tmp)) state->exits[tmp] |= LASER_OMITTED; state->justwrong = TRUE; free_game(guesses); return 0; } } } free_game(guesses); } /* duplicate the state (to solution) */ solution = dup_game(state); /* clear out the lasers of solution */ for (i = 0; i < solution->nlasers; i++) { tmp = range2grid(solution, i, &x, &y, &unused); assert(tmp); GRID(solution, x, y) = 0; solution->exits[i] = LASER_EMPTY; } /* duplicate solution to guess. */ guesses = dup_game(solution); /* clear out BALL_CORRECT on guess, make BALL_GUESS BALL_CORRECT. */ for (x = 1; x <= state->w; x++) { for (y = 1; y <= state->h; y++) { GRID(guesses, x, y) &= ~BALL_CORRECT; if (GRID(guesses, x, y) & BALL_GUESS) GRID(guesses, x, y) |= BALL_CORRECT; } } /* for each laser (on both game_states), fire it if it hasn't been fired. * If one has been fired (or received a hit) and another hasn't, we know * the ball layouts didn't match and can short-circuit return. */ for (i = 0; i < solution->nlasers; i++) { if (solution->exits[i] == LASER_EMPTY) fire_laser(solution, i); if (guesses->exits[i] == LASER_EMPTY) fire_laser(guesses, i); } /* check each game_state's laser against the other; if any differ, return 0 */ ret = 1; for (i = 0; i < solution->nlasers; i++) { tmp = range2grid(solution, i, &x, &y, &unused); assert(tmp); if (solution->exits[i] != guesses->exits[i]) { /* If the original state didn't have this shot fired, * and it would be wrong between the guess and the solution, * add it. */ if (state->exits[i] == LASER_EMPTY) { state->exits[i] = solution->exits[i]; if (state->exits[i] == LASER_REFLECT || state->exits[i] == LASER_HIT) GRID(state, x, y) = state->exits[i]; else { /* add a new shot, incrementing state's laser count. */ int ex, ey, newno = state->laserno++; tmp = range2grid(state, state->exits[i], &ex, &ey, &unused); assert(tmp); GRID(state, x, y) = newno; GRID(state, ex, ey) = newno; } state->exits[i] |= LASER_OMITTED; } else { state->exits[i] |= LASER_WRONG; } ret = 0; } } if (ret == 0 || state->nguesses < state->minballs || state->nguesses > state->maxballs) goto done; /* fix up original state so the 'correct' balls end up matching the guesses, * as we've just proved that they were equivalent. */ for (x = 1; x <= state->w; x++) { for (y = 1; y <= state->h; y++) { if (GRID(state, x, y) & BALL_GUESS) GRID(state, x, y) |= BALL_CORRECT; else GRID(state, x, y) &= ~BALL_CORRECT; } } done: /* fill in nright and nwrong. */ state->nright = state->nwrong = state->nmissed = 0; for (x = 1; x <= state->w; x++) { for (y = 1; y <= state->h; y++) { int bs = GRID(state, x, y) & (BALL_GUESS | BALL_CORRECT); if (bs == (BALL_GUESS | BALL_CORRECT)) state->nright++; else if (bs == BALL_GUESS) state->nwrong++; else if (bs == BALL_CORRECT) state->nmissed++; } } free_game(solution); free_game(guesses); state->reveal = 1; return ret; } #define TILE_SIZE (ds->tilesize) #define TODRAW(x) ((TILE_SIZE * (x)) + (TILE_SIZE / 2)) #define FROMDRAW(x) (((x) - (TILE_SIZE / 2)) / TILE_SIZE) #define CAN_REVEAL(state) ((state)->nguesses >= (state)->minballs && \ (state)->nguesses <= (state)->maxballs && \ !(state)->reveal && !(state)->justwrong) struct game_drawstate { int tilesize, crad, rrad, w, h; /* w and h to make macros work... */ unsigned int *grid; /* as the game_state grid */ int started, reveal; int flash_laserno, isflash; }; static char *interpret_move(const game_state *state, game_ui *ui, const game_drawstate *ds, int x, int y, int button) { int gx = -1, gy = -1, rangeno = -1, wouldflash = 0; enum { NONE, TOGGLE_BALL, TOGGLE_LOCK, FIRE, REVEAL, TOGGLE_COLUMN_LOCK, TOGGLE_ROW_LOCK} action = NONE; char buf[80], *nullret = NULL; if (IS_CURSOR_MOVE(button)) { int cx = ui->cur_x, cy = ui->cur_y; move_cursor(button, &cx, &cy, state->w+2, state->h+2, 0); if ((cx == 0 && cy == 0 && !CAN_REVEAL(state)) || (cx == 0 && cy == state->h+1) || (cx == state->w+1 && cy == 0) || (cx == state->w+1 && cy == state->h+1)) return NULL; /* disallow moving cursor to corners. */ ui->cur_x = cx; ui->cur_y = cy; ui->cur_visible = 1; return ""; } if (button == LEFT_BUTTON || button == RIGHT_BUTTON) { gx = FROMDRAW(x); gy = FROMDRAW(y); ui->cur_visible = 0; wouldflash = 1; } else if (button == LEFT_RELEASE) { ui->flash_laser = 0; return ""; } else if (IS_CURSOR_SELECT(button)) { if (ui->cur_visible) { gx = ui->cur_x; gy = ui->cur_y; ui->flash_laser = 0; wouldflash = 2; } else { ui->cur_visible = 1; return ""; } /* Fix up 'button' for the below logic. */ if (button == CURSOR_SELECT2) button = RIGHT_BUTTON; else button = LEFT_BUTTON; } if (gx != -1 && gy != -1) { if (gx == 0 && gy == 0 && button == LEFT_BUTTON) action = REVEAL; if (gx >= 1 && gx <= state->w && gy >= 1 && gy <= state->h) { if (button == LEFT_BUTTON) { if (!(GRID(state, gx,gy) & BALL_LOCK)) action = TOGGLE_BALL; } else action = TOGGLE_LOCK; } if (grid2range(state, gx, gy, &rangeno)) { if (button == LEFT_BUTTON) action = FIRE; else if (gy == 0 || gy > state->h) action = TOGGLE_COLUMN_LOCK; /* and use gx */ else action = TOGGLE_ROW_LOCK; /* and use gy */ } } switch (action) { case TOGGLE_BALL: sprintf(buf, "T%d,%d", gx, gy); break; case TOGGLE_LOCK: sprintf(buf, "LB%d,%d", gx, gy); break; case TOGGLE_COLUMN_LOCK: sprintf(buf, "LC%d", gx); break; case TOGGLE_ROW_LOCK: sprintf(buf, "LR%d", gy); break; case FIRE: if (state->reveal && state->exits[rangeno] == LASER_EMPTY) return nullret; ui->flash_laserno = rangeno; ui->flash_laser = wouldflash; nullret = ""; if (state->exits[rangeno] != LASER_EMPTY) return ""; sprintf(buf, "F%d", rangeno); break; case REVEAL: if (!CAN_REVEAL(state)) return nullret; if (ui->cur_visible == 1) ui->cur_x = ui->cur_y = 1; sprintf(buf, "R"); break; default: return nullret; } if (state->reveal) return nullret; ui->newmove = TRUE; return dupstr(buf); } static game_state *execute_move(const game_state *from, const char *move) { game_state *ret = dup_game(from); int gx = -1, gy = -1, rangeno = -1; if (ret->justwrong) { int i; ret->justwrong = FALSE; for (i = 0; i < ret->nlasers; i++) if (ret->exits[i] != LASER_EMPTY) ret->exits[i] &= ~(LASER_OMITTED | LASER_WRONG); } if (!strcmp(move, "S")) { check_guesses(ret, FALSE); return ret; } if (from->reveal) goto badmove; if (!*move) goto badmove; switch (move[0]) { case 'T': sscanf(move+1, "%d,%d", &gx, &gy); if (gx < 1 || gy < 1 || gx > ret->w || gy > ret->h) goto badmove; if (GRID(ret, gx, gy) & BALL_GUESS) { ret->nguesses--; GRID(ret, gx, gy) &= ~BALL_GUESS; } else { ret->nguesses++; GRID(ret, gx, gy) |= BALL_GUESS; } break; case 'F': sscanf(move+1, "%d", &rangeno); if (ret->exits[rangeno] != LASER_EMPTY) goto badmove; if (!RANGECHECK(ret, rangeno)) goto badmove; fire_laser(ret, rangeno); break; case 'R': if (ret->nguesses < ret->minballs || ret->nguesses > ret->maxballs) goto badmove; check_guesses(ret, TRUE); break; case 'L': { int lcount = 0; if (strlen(move) < 2) goto badmove; switch (move[1]) { case 'B': sscanf(move+2, "%d,%d", &gx, &gy); if (gx < 1 || gy < 1 || gx > ret->w || gy > ret->h) goto badmove; GRID(ret, gx, gy) ^= BALL_LOCK; break; #define COUNTLOCK do { if (GRID(ret, gx, gy) & BALL_LOCK) lcount++; } while (0) #define SETLOCKIF(c) do { \ if (lcount > (c)) GRID(ret, gx, gy) &= ~BALL_LOCK; \ else GRID(ret, gx, gy) |= BALL_LOCK; \ } while(0) case 'C': sscanf(move+2, "%d", &gx); if (gx < 1 || gx > ret->w) goto badmove; for (gy = 1; gy <= ret->h; gy++) { COUNTLOCK; } for (gy = 1; gy <= ret->h; gy++) { SETLOCKIF(ret->h/2); } break; case 'R': sscanf(move+2, "%d", &gy); if (gy < 1 || gy > ret->h) goto badmove; for (gx = 1; gx <= ret->w; gx++) { COUNTLOCK; } for (gx = 1; gx <= ret->w; gx++) { SETLOCKIF(ret->w/2); } break; #undef COUNTLOCK #undef SETLOCKIF default: goto badmove; } } break; default: goto badmove; } return ret; badmove: free_game(ret); return NULL; } /* ---------------------------------------------------------------------- * Drawing routines. */ static void game_compute_size(const game_params *params, int tilesize, int *x, int *y) { /* Border is ts/2, to make things easier. * Thus we have (width) + 2 (firing range*2) + 1 (border*2) tiles * across, and similarly height + 2 + 1 tiles down. */ *x = (params->w + 3) * tilesize; *y = (params->h + 3) * tilesize; } static void game_set_size(drawing *dr, game_drawstate *ds, const game_params *params, int tilesize) { ds->tilesize = tilesize; ds->crad = (tilesize-1)/2; ds->rrad = (3*tilesize)/8; } static float *game_colours(frontend *fe, int *ncolours) { float *ret = snewn(3 * NCOLOURS, float); int i; game_mkhighlight(fe, ret, COL_BACKGROUND, COL_HIGHLIGHT, COL_LOWLIGHT); ret[COL_BALL * 3 + 0] = 0.0F; ret[COL_BALL * 3 + 1] = 0.0F; ret[COL_BALL * 3 + 2] = 0.0F; ret[COL_WRONG * 3 + 0] = 1.0F; ret[COL_WRONG * 3 + 1] = 0.0F; ret[COL_WRONG * 3 + 2] = 0.0F; ret[COL_BUTTON * 3 + 0] = 0.0F; ret[COL_BUTTON * 3 + 1] = 1.0F; ret[COL_BUTTON * 3 + 2] = 0.0F; ret[COL_CURSOR * 3 + 0] = 1.0F; ret[COL_CURSOR * 3 + 1] = 0.0F; ret[COL_CURSOR * 3 + 2] = 0.0F; for (i = 0; i < 3; i++) { ret[COL_GRID * 3 + i] = ret[COL_BACKGROUND * 3 + i] * 0.9F; ret[COL_LOCK * 3 + i] = ret[COL_BACKGROUND * 3 + i] * 0.7F; ret[COL_COVER * 3 + i] = ret[COL_BACKGROUND * 3 + i] * 0.5F; ret[COL_TEXT * 3 + i] = 0.0F; } ret[COL_FLASHTEXT * 3 + 0] = 0.0F; ret[COL_FLASHTEXT * 3 + 1] = 1.0F; ret[COL_FLASHTEXT * 3 + 2] = 0.0F; *ncolours = NCOLOURS; return ret; } static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) { struct game_drawstate *ds = snew(struct game_drawstate); ds->tilesize = 0; ds->w = state->w; ds->h = state->h; ds->grid = snewn((state->w+2)*(state->h+2), unsigned int); memset(ds->grid, 0, (state->w+2)*(state->h+2)*sizeof(unsigned int)); ds->started = ds->reveal = 0; ds->flash_laserno = LASER_EMPTY; ds->isflash = 0; return ds; } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { sfree(ds->grid); sfree(ds); } static void draw_square_cursor(drawing *dr, game_drawstate *ds, int dx, int dy) { int coff = TILE_SIZE/8; draw_rect_outline(dr, dx + coff, dy + coff, TILE_SIZE - coff*2, TILE_SIZE - coff*2, COL_CURSOR); } static void draw_arena_tile(drawing *dr, const game_state *gs, game_drawstate *ds, const game_ui *ui, int ax, int ay, int force, int isflash) { int gx = ax+1, gy = ay+1; int gs_tile = GRID(gs, gx, gy), ds_tile = GRID(ds, gx, gy); int dx = TODRAW(gx), dy = TODRAW(gy); if (ui->cur_visible && ui->cur_x == gx && ui->cur_y == gy) gs_tile |= FLAG_CURSOR; if (gs_tile != ds_tile || gs->reveal != ds->reveal || force) { int bcol, ocol, bg; bg = (gs->reveal ? COL_BACKGROUND : (gs_tile & BALL_LOCK) ? COL_LOCK : COL_COVER); draw_rect(dr, dx, dy, TILE_SIZE, TILE_SIZE, bg); draw_rect_outline(dr, dx, dy, TILE_SIZE, TILE_SIZE, COL_GRID); if (gs->reveal) { /* Guessed balls are always black; if they're incorrect they'll * have a red cross added later. * Missing balls are red. */ if (gs_tile & BALL_GUESS) { bcol = isflash ? bg : COL_BALL; } else if (gs_tile & BALL_CORRECT) { bcol = isflash ? bg : COL_WRONG; } else { bcol = bg; } } else { /* guesses are black/black, all else background. */ if (gs_tile & BALL_GUESS) { bcol = COL_BALL; } else { bcol = bg; } } ocol = (gs_tile & FLAG_CURSOR && bcol != bg) ? COL_CURSOR : bcol; draw_circle(dr, dx + TILE_SIZE/2, dy + TILE_SIZE/2, ds->crad-1, ocol, ocol); draw_circle(dr, dx + TILE_SIZE/2, dy + TILE_SIZE/2, ds->crad-3, bcol, bcol); if (gs_tile & FLAG_CURSOR && bcol == bg) draw_square_cursor(dr, ds, dx, dy); if (gs->reveal && (gs_tile & BALL_GUESS) && !(gs_tile & BALL_CORRECT)) { int x1 = dx + 3, y1 = dy + 3; int x2 = dx + TILE_SIZE - 3, y2 = dy + TILE_SIZE-3; int coords[8]; /* Incorrect guess; draw a red cross over the ball. */ coords[0] = x1-1; coords[1] = y1+1; coords[2] = x1+1; coords[3] = y1-1; coords[4] = x2+1; coords[5] = y2-1; coords[6] = x2-1; coords[7] = y2+1; draw_polygon(dr, coords, 4, COL_WRONG, COL_WRONG); coords[0] = x2+1; coords[1] = y1+1; coords[2] = x2-1; coords[3] = y1-1; coords[4] = x1-1; coords[5] = y2-1; coords[6] = x1+1; coords[7] = y2+1; draw_polygon(dr, coords, 4, COL_WRONG, COL_WRONG); } draw_update(dr, dx, dy, TILE_SIZE, TILE_SIZE); } GRID(ds,gx,gy) = gs_tile; } static void draw_laser_tile(drawing *dr, const game_state *gs, game_drawstate *ds, const game_ui *ui, int lno, int force) { int gx, gy, dx, dy, unused; int wrong, omitted, reflect, hit, laserval, flash = 0, tmp; unsigned int gs_tile, ds_tile, exitno; tmp = range2grid(gs, lno, &gx, &gy, &unused); assert(tmp); gs_tile = GRID(gs, gx, gy); ds_tile = GRID(ds, gx, gy); dx = TODRAW(gx); dy = TODRAW(gy); wrong = gs->exits[lno] & LASER_WRONG; omitted = gs->exits[lno] & LASER_OMITTED; exitno = gs->exits[lno] & ~LASER_FLAGMASK; reflect = gs_tile & LASER_REFLECT; hit = gs_tile & LASER_HIT; laserval = gs_tile & ~LASER_FLAGMASK; if (lno == ds->flash_laserno) gs_tile |= LASER_FLASHED; else if (!(gs->exits[lno] & (LASER_HIT | LASER_REFLECT))) { if (exitno == ds->flash_laserno) gs_tile |= LASER_FLASHED; } if (gs_tile & LASER_FLASHED) flash = 1; gs_tile |= wrong | omitted; if (ui->cur_visible && ui->cur_x == gx && ui->cur_y == gy) gs_tile |= FLAG_CURSOR; if (gs_tile != ds_tile || force) { draw_rect(dr, dx, dy, TILE_SIZE, TILE_SIZE, COL_BACKGROUND); draw_rect_outline(dr, dx, dy, TILE_SIZE, TILE_SIZE, COL_GRID); if (gs_tile &~ (LASER_WRONG | LASER_OMITTED | FLAG_CURSOR)) { char str[32]; int tcol = flash ? COL_FLASHTEXT : omitted ? COL_WRONG : COL_TEXT; if (reflect || hit) sprintf(str, "%s", reflect ? "R" : "H"); else sprintf(str, "%d", laserval); if (wrong) { draw_circle(dr, dx + TILE_SIZE/2, dy + TILE_SIZE/2, ds->rrad, COL_WRONG, COL_WRONG); draw_circle(dr, dx + TILE_SIZE/2, dy + TILE_SIZE/2, ds->rrad - TILE_SIZE/16, COL_BACKGROUND, COL_WRONG); } draw_text(dr, dx + TILE_SIZE/2, dy + TILE_SIZE/2, FONT_VARIABLE, TILE_SIZE/2, ALIGN_VCENTRE | ALIGN_HCENTRE, tcol, str); } if (gs_tile & FLAG_CURSOR) draw_square_cursor(dr, ds, dx, dy); draw_update(dr, dx, dy, TILE_SIZE, TILE_SIZE); } GRID(ds, gx, gy) = gs_tile; } #define CUR_ANIM 0.2F static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldstate, const game_state *state, int dir, const game_ui *ui, float animtime, float flashtime) { int i, x, y, ts = TILE_SIZE, isflash = 0, force = 0; if (flashtime > 0) { int frame = (int)(flashtime / FLASH_FRAME); isflash = (frame % 2) == 0; debug(("game_redraw: flashtime = %f", flashtime)); } if (!ds->started) { int x0 = TODRAW(0)-1, y0 = TODRAW(0)-1; int x1 = TODRAW(state->w+2), y1 = TODRAW(state->h+2); draw_rect(dr, 0, 0, TILE_SIZE * (state->w+3), TILE_SIZE * (state->h+3), COL_BACKGROUND); /* clockwise around the outline starting at pt behind (1,1). */ draw_line(dr, x0+ts, y0+ts, x0+ts, y0, COL_HIGHLIGHT); draw_line(dr, x0+ts, y0, x1-ts, y0, COL_HIGHLIGHT); draw_line(dr, x1-ts, y0, x1-ts, y0+ts, COL_LOWLIGHT); draw_line(dr, x1-ts, y0+ts, x1, y0+ts, COL_HIGHLIGHT); draw_line(dr, x1, y0+ts, x1, y1-ts, COL_LOWLIGHT); draw_line(dr, x1, y1-ts, x1-ts, y1-ts, COL_LOWLIGHT); draw_line(dr, x1-ts, y1-ts, x1-ts, y1, COL_LOWLIGHT); draw_line(dr, x1-ts, y1, x0+ts, y1, COL_LOWLIGHT); draw_line(dr, x0+ts, y1, x0+ts, y1-ts, COL_HIGHLIGHT); draw_line(dr, x0+ts, y1-ts, x0, y1-ts, COL_LOWLIGHT); draw_line(dr, x0, y1-ts, x0, y0+ts, COL_HIGHLIGHT); draw_line(dr, x0, y0+ts, x0+ts, y0+ts, COL_HIGHLIGHT); /* phew... */ draw_update(dr, 0, 0, TILE_SIZE * (state->w+3), TILE_SIZE * (state->h+3)); force = 1; ds->started = 1; } if (isflash != ds->isflash) force = 1; /* draw the arena */ for (x = 0; x < state->w; x++) { for (y = 0; y < state->h; y++) { draw_arena_tile(dr, state, ds, ui, x, y, force, isflash); } } /* draw the lasers */ ds->flash_laserno = LASER_EMPTY; if (ui->flash_laser == 1) ds->flash_laserno = ui->flash_laserno; else if (ui->flash_laser == 2 && animtime > 0) ds->flash_laserno = ui->flash_laserno; for (i = 0; i < 2*(state->w+state->h); i++) { draw_laser_tile(dr, state, ds, ui, i, force); } /* draw the 'finish' button */ if (CAN_REVEAL(state)) { int outline = (ui->cur_visible && ui->cur_x == 0 && ui->cur_y == 0) ? COL_CURSOR : COL_BALL; clip(dr, TODRAW(0)-1, TODRAW(0)-1, TILE_SIZE+1, TILE_SIZE+1); draw_circle(dr, TODRAW(0) + ds->crad, TODRAW(0) + ds->crad, ds->crad, outline, outline); draw_circle(dr, TODRAW(0) + ds->crad, TODRAW(0) + ds->crad, ds->crad-2, COL_BUTTON, COL_BUTTON); unclip(dr); } else { draw_rect(dr, TODRAW(0)-1, TODRAW(0)-1, TILE_SIZE+1, TILE_SIZE+1, COL_BACKGROUND); } draw_update(dr, TODRAW(0), TODRAW(0), TILE_SIZE, TILE_SIZE); ds->reveal = state->reveal; ds->isflash = isflash; { char buf[256]; if (ds->reveal) { if (state->nwrong == 0 && state->nmissed == 0 && state->nright >= state->minballs) sprintf(buf, "CORRECT!"); else sprintf(buf, "%d wrong and %d missed balls.", state->nwrong, state->nmissed); } else if (state->justwrong) { sprintf(buf, "Wrong! Guess again."); } else { if (state->nguesses > state->maxballs) sprintf(buf, "%d too many balls marked.", state->nguesses - state->maxballs); else if (state->nguesses <= state->maxballs && state->nguesses >= state->minballs) sprintf(buf, "Click button to verify guesses."); else if (state->maxballs == state->minballs) sprintf(buf, "Balls marked: %d / %d", state->nguesses, state->minballs); else sprintf(buf, "Balls marked: %d / %d-%d.", state->nguesses, state->minballs, state->maxballs); } if (ui->errors) { sprintf(buf + strlen(buf), " (%d error%s)", ui->errors, ui->errors > 1 ? "s" : ""); } status_bar(dr, buf); } } static float game_anim_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { return (ui->flash_laser == 2) ? CUR_ANIM : 0.0F; } static float game_flash_length(const game_state *oldstate, const game_state *newstate, int dir, game_ui *ui) { if (!oldstate->reveal && newstate->reveal) return 4.0F * FLASH_FRAME; else return 0.0F; } static int game_status(const game_state *state) { if (state->reveal) { /* * We return nonzero whenever the solution has been revealed, * even (on spoiler grounds) if it wasn't guessed correctly. */ if (state->nwrong == 0 && state->nmissed == 0 && state->nright >= state->minballs) return +1; else return -1; } return 0; } static int game_timing_state(const game_state *state, game_ui *ui) { return TRUE; } static void game_print_size(const game_params *params, float *x, float *y) { } static void game_print(drawing *dr, const game_state *state, int tilesize) { } #ifdef COMBINED #define thegame blackbox #endif const struct game thegame = { "Black Box", "games.blackbox", "blackbox", default_params, game_fetch_preset, NULL, decode_params, encode_params, free_params, dup_params, TRUE, game_configure, custom_params, validate_params, new_game_desc, validate_desc, new_game, dup_game, free_game, TRUE, solve_game, FALSE, game_can_format_as_text_now, game_text_format, new_ui, free_ui, encode_ui, decode_ui, game_changed_state, interpret_move, execute_move, PREFERRED_TILE_SIZE, game_compute_size, game_set_size, game_colours, game_new_drawstate, game_free_drawstate, game_redraw, game_anim_length, game_flash_length, game_status, FALSE, FALSE, game_print_size, game_print, TRUE, /* wants_statusbar */ FALSE, game_timing_state, REQUIRE_RBUTTON, /* flags */ }; /* vim: set shiftwidth=4 tabstop=8: */ puzzles-20170606.272beef/icons/0000755000175000017500000000000013115375151015001 5ustar simonsimonpuzzles-20170606.272beef/icons/untangle-icon.c0000644000175000017500000004434313115373754017727 0ustar simonsimon/* XPM */ static const char *const xpm_icon_0[] = { /* columns rows colors chars-per-pixel */ "16 16 235 2 ", " c #D5D5D5", ". c #D5D5D5", "X c #D4D4D5", "o c #DBDBD4", "O c #E0E0D2", "+ c #D5D5D6", "@ c gray83", "# c #D5D5D5", "$ c #D5D5D5", "% c #D5D5D5", "& c gray84", "* c #D2D2D2", "= c #D5D5D5", "- c #D5D5D5", "; c #D3D3D5", ": c #E0E0D6", "> c #9D9DCD", ", c #6363C6", "< c #DFDFD3", "1 c #D6D6D8", "2 c #D5D5D5", "3 c #D3D3D4", "4 c #D6D6D8", "5 c #CDCDCC", "6 c #C3C3C3", "7 c #D7D7D7", "8 c #D5D5D5", "9 c #D4D4D5", "0 c #DCDCD6", "q c #B1B1CD", "w c #8484BF", "e c #C8C8C1", "r c #C6C6C8", "t c #D2D2D4", "y c #E0E0D9", "u c #D9D9D1", "i c #BDBDBF", "p c #D6D6D5", "a c #D5D5D5", "s c #D5D5D5", "d c #D5D5D5", "f c #D5D5D7", "g c #D5D5CF", "h c #D1D1C5", "j c #D6D6D8", "k c #C8C8C9", "l c #C9C9C3", "z c #A3A3C8", "x c #9999C1", "c c #D8D8D1", "v c #D5D5D6", "b c #D5D5D5", "n c #D5D5D5", "m c #D5D5D5", "M c #D5D5D5", "N c gray84", "B c #CECED0", "V c #C3C3C5", "C c #DBDBDA", "Z c #D4D4D6", "A c #D3D3C5", "S c #7070BE", "D c #6E6EC4", "F c #E3E3D5", "G c #D3D3D5", "H c #D5D5D5", "J c #D5D5D5", "K c #D5D5D5", "L c #D4D4D5", "P c gray83", "I c #D7D7D7", "U c gray83", "Y c gray76", "T c #C8C8C8", "R c #C0C0C0", "E c #C9C9CB", "W c #DFDFD6", "Q c #D4D4CA", "! c #BFBFC0", "~ c #D7D7D7", "^ c #D5D5D5", "/ c #D5D5D5", "( c #D5D5D5", ") c #D7D7D5", "_ c #DBDBD6", "` c #D7D7D7", "' c LightGray", "] c gray76", "[ c #B1B1B1", "{ c #CDCDCD", "} c gray84", "| c #D8D8D7", " . c #D3D3D5", ".. c #D7D7D9", "X. c #CBCBCA", "o. c #C1C1C1", "O. c gray84", "+. c #D5D5D5", "@. c #D7D7D5", "#. c #CECED3", "$. c #BDBDCF", "%. c #C9C9C7", "&. c gray77", "*. c gray79", "=. c gray77", "-. c gray85", ";. c gray83", ":. c #D5D5D5", ">. c #D5D5D5", ",. c gray83", "<. c #D8D8D8", "1. c #CACACA", "2. c #D0D0D0", "3. c gray84", "4. c #E0E0D6", "5. c #A7A7D0", "6. c #3333BD", "7. c #C3C3B9", "8. c #CFCFD1", "9. c gray83", "0. c #C5C5C5", "q. c #D8D8D8", "w. c #D5D5D5", "e. c gray83", "r. c #D5D5D5", "t. c #D5D5D5", "y. c #D5D5D5", "u. c #D7D7D7", "i. c gray84", "p. c #D5D5D5", "a. c #D5D5D4", "s. c #D7D7D7", "d. c #B1B1B4", "f. c gray75", "g. c gray79", "h. c gray75", "j. c #B4B4B4", "k. c #CECECE", "l. c gray83", "z. c #D8D8D8", "x. c #D7D7D7", "c. c #D5D5D5", "v. c gray83", "b. c gray83", "n. c #D5D5D5", "m. c #D5D5D5", "M. c gray83", "N. c #D8D8D8", "B. c #CDCDCC", "V. c #B5B5B8", "C. c #D3D3D4", "Z. c gray84", "A. c #BCBCBC", "S. c gray78", "D. c #C1C1C1", "F. c gray77", "G. c gray80", "H. c gray83", "J. c #D8D8D8", "K. c #D7D7D7", "L. c #D5D5D5", "P. c #D5D5D5", "I. c #D5D5D5", "U. c gray84", "Y. c #D0D0D2", "T. c #CFCFC0", "R. c #C7C7C1", "E. c #D2D2D3", "W. c #C3C3C4", "Q. c #D8D8D8", "!. c #D5D5D5", "~. c gray81", "^. c #C6C6C6", "/. c gray76", "(. c gray77", "). c gray80", "_. c #D5D5D5", "`. c #D5D5D5", "'. c #D5D5D5", "]. c #D4D4D5", "[. c #DDDDD3", "{. c #6666C6", "}. c #9F9FC4", "|. c #CECEC5", " X c #CACAC6", ".X c #D5D5D4", "XX c #D5D5D5", "oX c #D7D7D7", "OX c #D8D8D8", "+X c gray84", "@X c gray81", "#X c gray78", "$X c #D2D2D2", "%X c gray84", "&X c #D5D5D5", "*X c #D4D4D5", "=X c #DBDBD4", "-X c #8484CE", ";X c #A7A7C4", ":X c #BABAB4", ">X c #9D9DB7", ",X c #D4D4D6", " , < 1 2 3 4 5 6 7 8 ", " 9 0 q w e r t y u i p a s ", " d f g h j k l z x c v b n ", " m M N B V C Z A S D F G H n ", "J K L P I U Y T R E W Q ! ~ ^ / ", "( ) _ ` ' ] [ { } | ...X.o.O.+.", "@.#.$.%.&.*.=.-.;.:.>.,.<.1.2.3.", "4.5.6.7.8.9.0.q.w.e.r.t.y.u.i.p.", "a.s.d.f.g.h.j.k.l.z.x.c.v.b.n.m.", "M.N.B.V.C.Z.A.S.D.F.G.H.J.K.L.P.", "I.U.Y.T.R.E.W.Q.!.~.^./.(.)._.`.", "'.].[.{.}.|. X.XXXoXOX+X@X#X$X%X", "&X*X=X-X;X:X>X,X c #0101E4", ", c #0000E8", "< c #0000F2", "1 c #0000F5", "2 c #0000F9", "3 c #4545C1", "4 c #4141C7", "5 c #6666C0", "6 c #868695", "7 c #959595", "8 c #999990", "9 c #9B9B9B", "0 c gray62", "q c #8E8EA1", "w c #9292AA", "e c #8080BE", "r c #8888BD", "t c #9C9CB1", "y c #9292BF", "u c #9494BF", "i c #A9A9A9", "p c #AAAAAA", "a c #AAAAAB", "s c gray67", "d c #AEAEA9", "f c #A9A9AD", "g c #ABABAC", "h c #ACACAC", "j c gray68", "k c #AEAEAE", "l c #AFAFAF", "z c #B8B8A5", "x c #B1B1AC", "c c #B2B2AC", "v c #B5B5AD", "b c #A6A6B7", "n c #AFAFB0", "m c #AFAFB3", "M c gray69", "N c #B1B1B1", "B c #B2B2B1", "V c #B2B2B2", "C c #B2B2B3", "Z c gray70", "A c #B6B6B1", "S c #B1B1B4", "D c #B3B3B4", "F c #B4B4B4", "G c gray71", "H c #B6B6B6", "J c #B7B7B7", "K c #BDBDB7", "L c #B7B7B8", "P c #B7B7BC", "I c gray72", "U c #B9B9B9", "Y c gray73", "T c #BBBBBB", "R c #BABABF", "E c #BCBCBC", "W c gray74", "Q c #BEBEBF", "! c gray75", "~ c #C0C0B4", "^ c #C1C1B4", "/ c #C1C1B6", "( c #C7C7B7", ") c #C2C2BE", "_ c #C2C2BF", "` c #BFBFC0", "' c #BCBCC5", "] c #C0C0C0", "[ c #C0C0C1", "{ c #C1C1C1", "} c gray76", "| c #C3C3C3", " . c #C5C5C1", ".. c #C7C7C2", "X. c gray77", "o. c #C5C5C5", "O. c gray78", "+. c #C9C9C7", "@. c #C7C7C8", "#. c gray79", "$. c #CACAC9", "%. c #C9C9CA", "&. c #CACACA", "*. c #CBCBCB", "=. c gray80", "-. c #CDCDCD", ";. c #CECECD", ":. c #CCCCCE", ">. c #CECECE", ",. c #CECECF", "<. c gray81", "1. c #D0D0C2", "2. c #D7D7CF", "3. c #D8D8CA", "4. c #D9D9CC", "5. c #DEDECE", "6. c #D0D0D0", "7. c #D1D1D0", "8. c gray82", "9. c #D1D1D3", "0. c #D2D2D2", "q. c LightGray", "w. c #D4D4D0", "e. c #D7D7D1", "r. c #D1D1D4", "t. c #D2D2D4", "y. c #D3D3D4", "u. c #D2D2D5", "i. c #D3D3D5", "p. c #D3D3D6", "a. c gray83", "s. c #D4D4D5", "d. c #D5D5D5", "f. c #D6D6D5", "g. c #D5D5D6", "h. c #D4D4D7", "j. c gray84", "k. c #D6D6D7", "l. c #D7D7D7", "z. c #DADAD1", "x. c #DCDCD2", "c. c #DBDBD4", "v. c #D8D8D7", "b. c #DADAD7", "n. c #DCDCD4", "m. c #DFDFD5", "M. c #D5D5D8", "N. c #D7D7D8", "B. c #D6D6D9", "V. c #D7D7D9", "C. c #D8D8D8", "Z. c #D9D9D8", "A. c #D8D8D9", "S. c gray85", "D. c #DADAD8", "F. c #DBDBD9", "G. c #D9D9DA", "H. c #DADADA", "J. c #DADADB", "K. c gray86", "L. c #DDDDD8", "P. c #DFDFD8", "I. c #DCDCDA", "U. c #DFDFDA", "Y. c #DBDBDC", "T. c #DADADE", "R. c gainsboro", "E. c gray87", "W. c #E0E0CF", "Q. c #E2E2D4", "!. c #E3E3D5", "~. c #E0E0D6", "^. c #E0E0D7", "/. c #E4E4D6", "(. c #E6E6DB", "). c #E0E0DC", "_. c #E8E8DB", "`. c #EDEDDE", "'. c gray88", "]. c #E1E1E1", "[. c gray89", /* pixels */ "d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.C.d.d.d.d.", "d.d.d.d.d.d.d.d.d.d.d.C.x.M.d.d.d.d.d.d.d.d.d.d.d.d.d.-.d.d.d.d.", "d.d.d.d.d.d.d.d.d.w.C.' + q.d.d.d.d.d.d.d.d.d.d.d.C.N o.C.d.d.d.", "d.d.d.d.d.d.d.d.d.r.Q.3 < + (.d.q.d.d.d.d.d.d.d.R.T H C.d.d.d.d.", "d.d.d.d.d.d.d.d.d.d.m.e ; w Z %.C.C.d.d.d.d.d.C.o.h C.d.d.d.d.d.", "d.d.d.d.d.d.d.d.d.d.M.z.z ).%.Z h %.C.C.d.r.M.-.s C.d.d.d.d.d.d.", "d.d.d.d.d.d.d.d.d.d.d.r.N d.v.C.-.N h o.C.!.5.s -.C.d.d.d.d.d.d.", "d.d.d.d.d.d.d.d.d.d.d.w.N d.d.d.C.R.-.H v 5 o _ C.d.d.d.d.d.d.d.", "d.d.d.d.d.d.d.d.d.d.d.d.N d.d.d.d.d.C.[.d * > R U.r.d.d.d.d.d.d.", "d.d.d.d.d.d.d.d.d.d.d.d.h d.d.d.C.C.{ s K y + Z Y.d.d.d.d.d.d.d.", "d.d.d.d.d.d.d.d.d.d.d.d.h d.R.d.{ h H q.Y.U.(.L H C.d.d.d.d.d.d.", "d.d.d.d.d.d.d.d.d.d.q.C.H q.{ h H q.R.d.r.q.r.U.D T R.r.d.d.d.d.", "d.d.d.d.d.d.d.d.d.d.C.C.0 s T q.Y.d.d.d.d.d.d.d.Y.N W R.d.d.d.d.", "d.d.d.d.d.d.d.d.C.q.W N 9 -.R.d.d.d.d.d.d.d.d.d.r.U.h { C.d.d.d.", "d.d.d.d.U.C.C.q.W h T C.H q.d.d.d.d.d.d.d.d.d.d.d.d.C.h *.C.d.d.", "d.d.d.w.b %.W s W d.C.C.N -.d.d.d.d.d.d.d.d.d.d.d.d.d.d.q.d.d.d.", "d.r.!.% 1 . ( Y.).d.r.C.N -.C.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.", "d.r.!.u & X / D o.d.C.R.H %.v.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.", "d.d.r.)./ 8 :.*.H h N %.Z 2.R.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.", "d.d.d.d.M.s h C.R.M.o.R 7 i o.r.C.C.M.w.d.d.d.d.d.d.d.d.d.d.d.d.", "d.d.d.d.C.T H N C.d.C.[.I T K h N | q.C.C.C.d.r.d.d.d.d.d.d.d.d.", "d.d.d.d.C.{ W T { C.q.v.T %.E.M.%.T N N { q.C.Y.d.d.d.d.d.d.d.d.", "d.d.d.d.d.q.h C.s q.d.C.T { C.d.C.C.C.%.T N N { q.v.C.M.d.d.d.d.", "d.d.d.d.d.C.H w.-.h C.C.W { C.d.d.d.d.C.C.C.*.K h N W q.d.d.d.d.", "d.d.d.d.d.C.{ q C.K T [.T { C.d.d.d.d.d.d.d.C.C.C.-.W n -.d.d.d.", "d.d.d.d.r.!.# < @ `.f -.` W C.d.d.d.d.d.d.d.d.d.d.C.Y.C.d.d.d.d.", "d.d.d.d.r.m.r - O / :.D . .C.d.d.d.d.d.d.d.d.d.d.d.d.w.d.d.d.d.", "d.d.d.d.d.d.m.1.v.{ n c 6 t U.r.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.", "d.d.d.d.d.d.d.M.d.C.C.c = > P U.r.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.", "d.d.d.d.d.d.d.d.d.d.M.4.4 : +.M.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.", "d.d.d.d.d.d.d.d.d.d.d.M.4.3.v.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.", "d.d.d.d.d.d.d.d.d.d.d.d.r.M.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d.d." }; /* XPM */ static const char *const xpm_icon_2[] = { /* columns rows colors chars-per-pixel */ "48 48 253 2 ", " c #7B7B7B", ". c gray50", "X c #222297", "o c #0C0CBF", "O c #0E0EBF", "+ c #1919B7", "@ c #1111BF", "# c #1E1EB8", "$ c #2525A5", "% c #3939AD", "& c #2B2BBA", "* c #3030B0", "= c #3D3DB2", "- c #454597", "; c #414199", ": c #4D4D98", "> c #666687", ", c #727288", "< c #6C6C90", "1 c #4545A8", "2 c #4949A9", "3 c #5D5DA8", "4 c #6464A2", "5 c #6A6AA6", "6 c #6B6BAA", "7 c #0000C3", "8 c #0C0CC4", "9 c #0000CB", "0 c #0000CC", "q c #1111C0", "w c #1010C6", "e c #0000DD", "r c #0000E1", "t c #0000E9", "y c #0000EB", "u c #0000F1", "i c #0000F5", "p c #0000F6", "a c #0000FC", "s c #0000FD", "d c blue", "f c #82828F", "g c #909083", "h c #90908E", "j c #8A8A90", "k c #929292", "l c #959595", "z c gray59", "x c #979797", "c c #989898", "v c #9A9A9A", "b c #9B9B9B", "n c #9E9E9B", "m c gray61", "M c #9C9C9D", "N c #9D9D9D", "B c #9E9E9D", "V c gray62", "C c #9F9F9F", "Z c #8181AC", "A c #8383AF", "S c #8E8EAE", "D c #8F8FAE", "F c #9696A0", "G c #9696A5", "H c #9090AE", "J c #9494AF", "K c #9A9AB0", "L c #9E9EB1", "P c #9E9EB2", "I c #A0A0A0", "U c gray63", "Y c #A2A2A2", "T c gray64", "R c #A4A4A0", "E c #A4A4A3", "W c #A6A6A2", "Q c #A4A4A4", "! c #A4A4A5", "~ c #A5A5A5", "^ c gray65", "/ c #A7A7A7", "( c #A9A9A1", ") c #A9A9A3", "_ c #A9A9A6", "` c #ACACA4", "' c #AFAFA4", "] c #ACACA7", "[ c #A7A7A8", "{ c #A5A5AF", "} c gray66", "| c #A9A9A9", " . c #AAAAAA", ".. c #AAAAAB", "X. c gray67", "o. c #AEAEAA", "O. c #ACACAC", "+. c gray68", "@. c #AEAEAE", "#. c #AFAFAF", "$. c #B0B0A4", "%. c #B2B2A5", "&. c #B0B0A9", "*. c #B4B4AF", "=. c #A7A7B4", "-. c #A8A8B3", ";. c #B1B1B1", ":. c #B0B0B3", ">. c #B2B2B2", ",. c #B4B4B5", "<. c gray71", "1. c #B6B6B5", "2. c #B6B6B6", "3. c #B6B6B7", "4. c #B7B7B7", "5. c #B4B4BA", "6. c #B5B5BA", "7. c gray72", "8. c #B8B8B9", "9. c #B9B9B9", "0. c gray73", "q. c #BBBBBB", "w. c #BCBCBB", "e. c #BBBBBC", "r. c #BBBBBD", "t. c #BCBCBC", "y. c gray74", "u. c gray", "i. c #BFBFBE", "p. c #BEBEBF", "a. c gray75", "s. c #CACABE", "d. c #C0C0C0", "f. c #C0C0C1", "g. c #C1C1C1", "h. c #C0C0C2", "j. c #C1C1C2", "k. c gray76", "l. c #C3C3C3", "z. c #C3C3C4", "x. c gray77", "c. c #C5C5C5", "v. c #C5C5C6", "b. c #C6C6C6", "n. c gray78", "m. c #CFCFC3", "M. c #C8C8C8", "N. c gray79", "B. c #C9C9CB", "V. c #CACACA", "C. c #CBCBCB", "Z. c #CACACC", "A. c #CBCBCD", "S. c gray80", "D. c #CDCDCD", "F. c #CECECE", "G. c gray81", "H. c #D2D2C3", "J. c #D6D6C5", "K. c #D1D1C9", "L. c #D6D6CD", "P. c #DADAC8", "I. c #DBDBCA", "U. c #D8D8CF", "Y. c #DDDDCC", "T. c #DDDDCD", "R. c #D0D0D0", "E. c gray82", "W. c #D2D2D2", "Q. c #D2D2D3", "!. c LightGray", "~. c #D4D4D3", "^. c #D1D1D4", "/. c #D2D2D4", "(. c #D3D3D4", "). c #D2D2D5", "_. c #D3D3D5", "`. c #D2D2D6", "'. c #D3D3D6", "]. c #D3D3D7", "[. c gray83", "{. c #D5D5D4", "}. c #D4D4D5", "|. c #D5D5D5", " X c #D4D4D6", ".X c #D5D5D7", "XX c gray84", "oX c #D6D6D7", "OX c #D7D7D7", "+X c #D8D8D0", "@X c #D9D9D0", "#X c #DBDBD7", "$X c #DFDFD5", "%X c #DDDDD7", "&X c #D4D4D8", "*X c #D5D5D8", "=X c #D6D6D8", "-X c #D7D7D9", ";X c #D8D8D8", ":X c #D9D9D8", ">X c gray85", ",X c #DADAD9", ". .uX!.|.|.|.|.|.|.", "|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.(.fX2 d p 4 BX&X!.|.|.|.|.|.|.|.|.|.|.|.!.uXp.V ,X|.|.|.|.|.|.|.|.", "|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.(.0XH 9 w f _ b.uX,X!.(.|.|.|.|.|.|.|.(.,XS.x |.|.|.|.|.|.|.|.|.|.", "|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.(.NXn W FXa.U U l.tX,X(.|.|.|.|.(.|.|.,Xb M.,X|.|.|.|.|.|.|.|.|.", "|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.,X0.0.tX,XuXz.U U l.,X,X|.(.|.(.(.uXF w.uX~.|.|.|.|.|.|.|.|.|.", "|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.(.tX5.>.tX(.!.,XuXM.~ U p.,X,X&XMXFX .O.uX~.|.|.|.|.|.|.|.|.|.|.", "|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.,X0.>.,X|.|.|.|.|.uXM.~ V a.K.S v _ uX|.|.|.|.|.|.|.|.|.|.|.|.", "|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.tX0.>.uX|.|.|.|.|.~.&XuXZ.$.- y 7 -.uX|.|.|.|.|.|.|.|.|.|.|.|.", "|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.(.,Xp.O.,X!.|.|.|.|.|.(.|.JXJ.$ a e H xX!.|.|.|.|.|.|.|.|.|.|.|.", "|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.!.,Xp.O.uX|.|.|.|.~.,XuXM.U W G & % ' CX!.|.|.|.|.|.|.|.|.|.|.|.", "|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.!.,Xl. .uX!.|.!.,XuXM.~ U p.,XMXI.gX! >.uX!.|.|.|.|.|.|.|.|.|.|.", "|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.,Xl. .tX!.,XtXb.U U a.tX,X|.(.(.(.uXF 9.MX(.|.|.|.|.|.|.|.|.|.", "|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.!.,Xz.~ CX,Xl.U U b.uX,X|.!.|.|.|.|.|.tXn w.uX!.|.|.|.|.|.|.|.|.", "|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.(.,XS.X.n.V U b.,X,X(.(.|.|.|.|.|.|.|.|.|.x l.,X!.|.|.|.|.|.|.|.", "|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.,XuX<. .b.,X,X(.|.|.|.|.|.|.|.|.|.|.(.,X|.x b.,X!.|.|.|.|.|.|.", "|.|.|.|.|.|.|.|.|.|.|.|.|.|.,X|.p.V m V AX|.!.|.|.|.|.|.|.|.|.|.|.|.|.|.(.,X!.x Z.uX|.|.|.|.|.|.", "|.|.|.|.|.|.|.|.!.|.!.|.uX|.p.V .S.|.~ &X|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.(.,XS.x M.&X|.|.|.|.|.", "|.|.|.|.|.|.(.0X,X(.uX|.0.b .S.uX,XS.U ,X~.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.!.,Xb.O.0X(.|.|.|.|.", "|.|.|.|.|.&X@X{ p.#X,.V .!.uX|.(.|.!.U ,X|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.,X&X|.|.|.|.|.|.", "|.|.|.|.(.$X6 e q j <.!.0X|.!.|.|.|.!.U &X|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.", "|.|.|.|.&XI.* d y < @X&XtX,X|.|.(.|.!.U #X|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.", "|.|.|.|.(.0XJ @ X _ [ m X.z.|.uX,X|.!.U |.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.", "|.|.|.|.|.(.$XH.g ~ AXR.e.~ V O.l.|.,X~ |.(.(.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.", "|.|.|.|.|.|.(.CX-.n &.uX,X,X!.p.~ V .k !.uX,X|.(.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.", "|.|.|.|.|.|.(.,Xp.>.~ l.,X!.|.,XuX|.p.. b .a.|.uX,X|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.", "|.|.|.|.|.|.(.|.(.U !.x |.|.|.!.|.|.uX .S.l. .V [ p.|.,XuX|.!.(.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.", "|.|.|.|.|.|.|.(.tX~ n.a.U CX!.|.|.|.|.U !.,XuX~.l. .V ~ p.!.uX,X|.!.!.|.|.|.|.|.|.|.|.|.|.|.|.|.", "|.|.|.|.|.|.|.(.tXp. .LXU 0.,X(.|.!.,XU S.&X!.|.,XuX|.l.O.V ~ 0.!.tX,X|.!.|.|.|.|.|.|.|.|.|.|.|.", "|.|.|.|.|.|.|.|.|.!.V &X|.b !.|.|.(.,X~ S.,X|.|.(.!.|.,XuX|.z.O.V ~ 0.!.uXuX|.|.(.|.|.|.|.|.|.|.", "|.|.|.|.|.|.|.|.!.uX~ z.uXb.b tX|.|.tX~ M.,X|.|.|.|.|.|.!.|.,XuX|.b.O.V ~ 0.R.,XuX&X&X|.|.|.|.|.", "|.|.|.|.|.|.|.|.(.,Xp.&.FXuXO.O.uX!.tX~ M.,X|.|.|.|.|.|.|.|.|.(.|.,XuX,XM.&.F W <.K.#X|.|.|.|.|.", "|.|.|.|.|.|.|.|.|.|.L., K @XuXm b.|.,X~ b.,X|.|.|.|.|.|.|.|.|.|.|.|.(.(.,XuX,XM. .0.,X(.|.|.|.|.", "|.|.|.|.|.|.|.|.(.kXZ r e A MXZ.b |.uX .z.,X|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.&XuX&X|.|.|.|.|.|.", "|.|.|.|.|.|.|.|.(.gX3 a d : fXJX0.U LX_ l.&X(.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.", "|.|.|.|.|.|.|.|.(.,Xs.% = U V ,.AX[ a.5.z.,X|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.", "|.|.|.|.|.|.|.|.|.|.,XT.T.CX!. .V e.( h O.kX(.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.", "|.|.|.|.|.|.|.|.|.|.(.].(.(.|.uXS.&.> 0 8 -.,X(.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.", "|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.(.&XhX1 d p 5 xX(.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.", "|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.!.0XP q # 5.0X(.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.", "|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.(.0Xs.m.0X|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.", "|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.(.&X&X(.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.", "|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.", "|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|." }; const char *const *const xpm_icons[] = { xpm_icon_0, xpm_icon_1, xpm_icon_2, }; const int n_xpm_icons = 3; puzzles-20170606.272beef/icons/unruly-icon.c0000644000175000017500000004704713115373753017453 0ustar simonsimon/* XPM */ static const char *const xpm_icon_0[] = { /* columns rows colors chars-per-pixel */ "16 16 256 2 ", " c black", ". c #010101", "X c #020202", "o c gray1", "O c #040404", "+ c gray2", "@ c #060606", "# c #070707", "$ c gray3", "% c #090909", "& c gray4", "* c #0B0B0B", "= c #0C0C0C", "- c gray5", "; c #0E0E0E", ": c gray6", "> c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", ".~ ;.!.K.8.q.E f 7.rX}.wX", "wX-XAXq.- { VX0Xc a z q 9.BX;XwX", "wX}.eXl.) 1.E.S.D m _ } 0.!.F.rX", "wX&XrX3XvXE.w l b d E.SXj.5 H uX", "wX|.1X@X9XH.v S D m G.pXd.h Q uX", "uXQ v +.h.e.w.t.@X1Xb.u.r.q.r.tX", "uXP a X.l.r.w.y.6XdXM.w.t.i.p.tX", "uXT v L L #.XX/.n.m.u.r.q.e.t.tX", "uXS u l e | VXtXu.w.r.p.t.i.p.tX", "tX0.8.$./ @.l.d.r.t.q.t.q.e.y.tX", "wX:XNXE.d.;.9 g q.i.e.i.e.u.u.rX", "rX`.,XC.y.2.P Q r.p.t.p.y.u.a.yX", "kXrXqXrXtXtXuXuXtXtXtXtXtXrXyXkX" }; /* XPM */ static const char *const xpm_icon_1[] = { /* columns rows colors chars-per-pixel */ "32 32 256 2 ", " c black", ". c #010101", "X c #020202", "o c gray1", "O c #040404", "+ c gray2", "@ c #060606", "# c #070707", "$ c gray3", "% c #090909", "& c gray4", "* c #0B0B0B", "= c #0C0C0C", "- c gray5", "; c #0E0E0E", ": c gray6", "> c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", "X6XH.8XbX", "bX8XP.6X;X7X[.v b M d p.tXX8XL.8XbX", "bX8XY.rX8XsX@Xc b M s f.hX9XuX:XB x b n N c v b b XXaX0XsXR.7XbX", "bX8XU.eX8XaX+Xn M V g d.pX5XwX&XB c n n B n M M M }.rX5XtXU.8XbX", "bX8XU.pXeXgXXXa s h 8 f.mXiXjX5XC v m M v s f f s $XzXpXxX~.7XnX", "bX9XD.>X$X;X_.u.f.d.f.6.5.5.7.1.C M B c ] l.s.f.p.3.6.6.6.>.rXvX", "bX7XT.pX0XrX>XeXhXaXmX5.7 f a j n c n s 0.mXpXhXyXA u g u G aXxX", "bX8XY.uX8XeX-X,X0X5XiX6.g B M V n b M g 5.iX5X9X1XI v B v Y pXcX", "bX7XE.dXeXiXX%XI n V b T iXcX", "cXiXR M Z B H r.y.y.y.7.q.q.q.9. X:X*XXu.p.p.p.q.i.p.a.t.e.a.i.a.6.eXvX", "cXpXI l n v m m n N f p.yX2X8X%Xe.t.t.t.8.r.r.t.q.9.y.r.t.3.rXvX", "bX9XB.XX'..XE.2.6.5.9.] F L J I 7.r.w.e.6.w.w.e.9.8.r.w.e.2.rXvX", "bX7XE.iXqXdX>Xt.d.p.k.) s x k m w.s.p.p.w.p.p.a.y.r.a.p.a.6.eXvX", "bX8XP.0X6XyX%Xq.i.y.d._ l N m C q.p.u.i.0.u.i.i.r.w.p.u.p.5.rXvX", "nX7XE.jXsXxX>Xe.a.i.h./ f v z n w.s.p.a.q.p.p.a.t.e.a.p.s.5.eXvX", "vXwXx.!.R.!.A.2.6.5.8.{ K Y I T 1.6.5.5.1.5.5.6.3.2.6.5.5.1.yXcX", "lXlXwX6X7X7X9XrXeXeXeXyXpXpXpXiXrXeXeXeXrXeXeXeXrXrXeXrXeXyXkXlX", "lXlXvXnXbXnXbXvXvXvXvXcXcXcXcXcXvXvXvXvXvXvXvXvXvXvXvXvXvXcXlXlX" }; /* XPM */ static const char *const xpm_icon_2[] = { /* columns rows colors chars-per-pixel */ "48 48 256 2 ", " c black", ". c #010101", "X c #020202", "o c gray1", "O c #040404", "+ c gray2", "@ c #060606", "# c #070707", "$ c gray3", "% c #090909", "& c gray4", "* c #0B0B0B", "= c #0C0C0C", "- c gray5", "; c #0E0E0E", ": c gray6", "> c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", ".a b c v l F 9XrXwXwXwXkXx.tXcXlXlX", "lXkXbX5XF v n n n c S t.i.u.u.i.y.7.i.u.u.u.u.t.,XwX8X9X7XiX;.g M n n x H -X4X9X7X0XaXj.yXcXlXlX", "lXkXbX5XD c n b n c S y.p.i.i.i.u.8.p.i.i.i.i.y.X7XwX0XeXdXj.tXcXlXlX", "lXkXbX5XF v m n n v S t.i.u.u.i.y.7.p.i.i.i.i.y.,XwX9X9X7XpX-.f m b n x H ;X5X0X8XqXsXj.tXcXlXlX", "lXkXbX5XA k x z x k C p.d.s.s.s.a.8.p.i.i.i.i.y.7XsXiXiXyXlX>.d m v b z G 3XaXgXfXgXjXl.tXcXlXlX", "lXkXnX4XU K P L P K Y 2.5.4.4.4.2.3.i.y.y.y.u.w.~.}.].[.'.oX+.z V N B n J X=X%X%X%X*Xs.yXcXlXlX", "lXkXMX=Xn.wX>XX9X(.z b b b m d f.eX,X2XX>X>X2Xf.yXcXlXlX", "lXkXMX*XV.eX3X7X4XfX}.z n b b M s x.hXqXeXwXaX Xx c v v v m B x c c c x G 4XuXeXrXeXiXl.tXcXlXlX", "lXkXMX*XB.wX9XwX9XkX[.z n b b M d l.dX8X0X9XuX}.x v n b n m B c b n n v G 1XeX0XqX0XtXk.tXcXlXlX", "lXkXMX*XB.wX7X0X7XjX{.z n b b M s l.fX8XqX9XiX}.x c b b b m B x b b b v G 1XrX0XqX0XtXk.tXcXlXlX", "lXkXMX*XB.rXwXtXeXzX{.v M M M B g l.aX6X9X7XyX[.z v n b n m V n M M N m J ,XwX8X9X8XeXk.tXcXlXlX", "lXkXMX*Xm.pXeXtXrXdX_.p d d s g 9 x.bXuXaXiXkX+Xc m M m m M v a f f g p N 0XfXpXaXpXhXx.tXcXlXlX", "lXkXMX-Xf.&X|. X|.+XT.s.x.l.l.l.x.>.&.=.*.*.-.O.V B B B V v %.n.k.l.l.x.u.$.=.*.*.=.%.&.dXxXlXlX", "lXkXMX*XB.fXqXeXeXuX&X9XjXdXfXaXbX&.0 f s s s z m z c x n a c.mXaXfXsXxX%Xd f f f h u ( jXzXlXlX", "lXkXMX*XN.aX8X0X0XtX#X;XqX8X8X6XuX=.f N m m M V n c b b M f g.aX6X8X7XtX}.n m m m M x ' hXzXlXlX", "lXkXMX*XN.sX9XqX0XtX$X,XrXqXqX9XaX*.s m b b n N n c n b M f h.fX8XqX0XuX Xv b b b n k ` hXzXlXlX", "lXkXMX*XN.pX7X9X9XrX#X:XeX9X0X8XpX*.s m b b m B m c n b N g h.sX7X0X8XyX|.v n n b m l ` hXzXlXlX", "lXkXMX*XZ.lXyXiXuXdX;X4XaXyXuXrXjX=.a m b b b m c z v c m p k.zXrXuXtXfXOXx c c c v h _ hXzXlXlX", "lXkXMX-Xs.+X[.}.{..XR.`.+XXXoX.X&X$.n D A A Z F K J J J L V u.=X.XoXXX$XY.C A A A S N [ hXzXlXlX", "lXkXbX5XS l c c c l C 9.q.0.0.q.9.4.y.t.t.t.t.e.*X5X2X3X2X7Xk.6.q.0.0.w.4.0.y.t.t.y.r.,.sXxXlXlX", "lXkXbX5XD c n b n c S i.a.p.a.a.p.8.a.p.p.p.p.u.2XyXeXeXwXuXm.t.s.a.p.s.w.e.a.p.p.p.i.<.aXxXlXlX", "lXkXbX5XD c n b n c S y.i.i.i.i.u.7.p.i.i.i.i.y.X;X4X'.7.y.r.t.r.p.Q j v c c z C 0.e.e.e.e.w.3.e.e.e.w.r.6.8.r.e.e.e.q.>.sXxXlXlX", "lXkXMX*XC.rX4X7X4XdX+Xq.s.p.p.i.g.~ j v c v c A y.a.p.p.p.i.9.a.p.p.p.s.q.r.a.p.p.p.i.<.aXxXlXlX", "lXkXMX*XN.wX9XwX0XhXXX0.p.i.i.u.d.~ j n n n b A t.p.i.i.i.u.7.p.i.i.i.p.0.e.p.i.i.i.u.<.aXxXlXlX", "lXkXMX*XB.wX7X0X8XgXoX0.a.i.i.u.f.~ j n b b b A t.p.i.i.i.u.8.p.i.i.i.a.0.e.p.i.i.i.u.<.aXxXlXlX", "lXkXMX*XB.wX0XeXqXjXXX0.a.i.i.u.f.^ k M m m m S y.p.i.i.p.u.8.p.i.i.i.a.q.e.p.i.i.p.u.<.sXxXlXlX", "lXkXMX&XN.kXaXdXsXlXOX9.p.u.u.y.d.R d x z x k N r.i.u.u.u.y.6.i.u.u.u.p.9.q.i.u.u.u.y.:.aXxXlXlX", "lXkXnX3X6.x.j.j.j.l.i.:.<.<.<.<.1.X.) ` ` ` _ [ ,.<.<.<.<.<.;.<.<.<.<.<.:.>.<.<.<.<.:.4.fXzXlXlX", "lXlXlXlXpXtXyXtXtXtXuXsXaXaXaXsXaXgXjXhXhXhXjXhXsXaXaXaXaXsXsXaXaXaXaXaXsXsXaXaXaXsXaXfXlXlXlXlX", "lXlXlXlXxXcXcXcXcXcXcXxXxXxXxXxXxXzXzXzXzXzXzXzXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXzXlXlXlXlX", "lXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlX", "lXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlX" }; const char *const *const xpm_icons[] = { xpm_icon_0, xpm_icon_1, xpm_icon_2, }; const int n_xpm_icons = 3; puzzles-20170606.272beef/icons/unequal-icon.c0000644000175000017500000004243113115373753017557 0ustar simonsimon/* XPM */ static const char *const xpm_icon_0[] = { /* columns rows colors chars-per-pixel */ "16 16 253 2 ", " c LightGray", ". c #CACACA", "X c #CBCBCB", "o c #CBCBCB", "O c #CBCBCB", "+ c #CACACA", "@ c #D0D0D0", "# c #D5D5D5", "$ c #D5D5D5", "% c #CECECE", "& c #CACACA", "* c #D1CDD1", "= c #CFCCCF", "- c #CACACA", "; c #CCCBCC", ": c gray83", "> c #C6C6C6", ", c #CECECE", "< c gray80", "1 c #CDCDCD", "2 c #CBCBCB", "3 c gray76", "4 c gainsboro", "5 c #D7D7D7", "6 c #C1C1C1", "7 c #CFCECF", "8 c #B6C3B6", "9 c #BBC5BB", "0 c #D0CFD0", "q c #C3C3C3", "w c gray81", "e c #CBCBCB", "r c #CECECE", "t c gray85", "y c #D7D7D7", "u c #D7D7D7", "i c gray84", "p c #C6C6C6", "a c gray52", "s c #C8C8C8", "d c #CBCCCB", "f c #DFDADF", "g c #6AAB6A", "h c #499D49", "j c #E5DEE5", "k c #C9CAC9", "l c #CECECE", "z c #CBCBCB", "x c gray80", "c c gray83", "v c #D5D5D5", "b c #D2D2D2", "n c #CDCDCD", "m c #BBBBBB", "M c #626262", "N c #C6C7C6", "B c #DFD9DF", "V c #BCCABC", "C c #539F53", "Z c #E8DEE8", "A c #C6C8C6", "S c #CFCECF", "D c #CBCBCB", "F c #CDCDCD", "G c #D7D7D7", "H c #D5D5D5", "J c #D5D5D5", "K c LightGray", "L c gray80", "P c #909090", "I c #8D8D8D", "U c #CBCBCB", "Y c #DDD9DD", "T c #75AE75", "R c #208C20", "E c #BACCBA", "W c #CFCCCF", "Q c #CDCECD", "! c #CACACA", "~ c #CBCBCB", "^ c gray84", "/ c gray83", "( c gray83", ") c LightGray", "_ c #C1C1C1", "` c gray69", "' c #DADADA", "] c #C5C5C5", "[ c #D5D5D5", "{ c #B6C8B6", "} c #ADC4AD", "| c #C6CFC6", " . c #CBC9CB", ".. c #CDCECD", "X. c gray81", "o. c gray77", "O. c gray78", "+. c #C6C6C6", "@. c gray78", "#. c #C5C5C5", "$. c gray79", "%. c gray87", "&. c gray83", "*. c #C6C6C6", "=. c #C5C6C5", "-. c #CDC9CD", ";. c #CFCACF", ":. c #CAC8CA", ">. c gray77", ",. c #D2D2D2", "<. c gray84", "1. c #D7D7D7", "2. c gray84", "3. c gray84", "4. c gray84", "5. c gray84", "6. c gray84", "7. c LightGray", "8. c #D7D7D7", "9. c gray84", "0. c #D5D6D5", "q. c #D5D6D5", "w. c gray84", "e. c #D7D7D7", "r. c #D5D5D5", "t. c #D5D5D5", "y. c gray83", "u. c LightGray", "i. c #D1D2D1", "p. c LightGray", "a. c gray83", "s. c #D5D5D5", "d. c #D5D5D5", "f. c #D5D5D5", "g. c #D5D5D5", "h. c LightGray", "j. c LightGray", "k. c #D0D0D0", "l. c LightGray", "z. c gray83", "x. c #D5D5D5", "c. c #CECECE", "v. c gray76", "b. c #CAC8CA", "n. c #D4CCD4", "m. c #CAC8CA", "M. c gray77", "N. c #C6C6C6", "B. c #D7D7D7", "V. c #D5D5D5", "C. c gray77", "Z. c #C5C5C5", "A. c gray79", "S. c #D5D5D5", "D. c #C8C8C8", "F. c gray76", "G. c gray82", "H. c gray79", "J. c #D2CFD2", "K. c #C2CFC2", "L. c #55A255", "P. c #B4C8B4", "I. c #DCD8DC", "U. c #C4C5C4", "Y. c gray84", "T. c LightGray", "R. c gray77", "E. c gray87", "W. c gray77", "Q. c #585858", "!. c gray80", "~. c #CDCDCD", "^. c #CDCDCD", "/. c #CACBCA", "(. c #CBCCCB", "). c #DFDADF", "_. c #539E53", "`. c #9ABC9A", "'. c #E2DAE2", "]. c #C4C5C4", "[. c gray84", "{. c LightGray", "}. c #C6C6C6", "|. c #747474", " X c gray17", ".X c #C0C0C0", "XX c gray81", "oX c #CDCDCD", "OX c #CACACA", "+X c #CBCCCB", "@X c #DFDADF", "#X c #509C50", "$X c #7EB07E", "%X c #DED8DE", "&X c #C4C5C4", "*X c gray84", "=X c #D2D2D2", "-X c gray80", ";X c #BBBBBB", ":X c #444444", ">X c #1E1E1E", ",X c #909090", " , < 1 2 3 4 5 6 7 8 9 0 q w ", "e r t y u i p a s d f g h j k l ", "z x y c v b n m M N B V C Z A S ", "D F G H J K L P I U Y T R E W Q ", "! ~ ^ / ( ) _ ` ' ] [ { } | ...", "X.o.O.+.@.#.$.%.&.*.=.-.;.:.>.,.", "<.1.2.3.4.5.6.7.v 8.9.0.q.w.e.r.", "t.y.u.i.p.a.s.d.f.g.h.j.k.l.z.x.", "c.v.b.n.m.M.N.B.V.C.Z.A.S.D.F.G.", "H.J.K.L.P.I.U.Y.T.R.E.W.Q.!.~.^.", "/.(.)._.`.'.].[.{.}.1.|. X.XXXoX", "OX+X@X#X$X%X&X*X=X-X;X:X>X,X c #007E00", ", c #007F00", "< c #017F01", "1 c #047E04", "2 c #484848", "3 c gray32", "4 c #646464", "5 c #6F6F6F", "6 c #717171", "7 c #797979", "8 c gray48", "9 c #078107", "0 c #088208", "q c #0A830A", "w c #2D912D", "e c #469B46", "r c #61A661", "t c #67A867", "y c #69A969", "u c #6FAC6F", "i c #72AB72", "p c #71AD71", "a c #74AE74", "s c #79B079", "d c #7DB27D", "f c #838383", "g c gray52", "h c gray54", "j c gray57", "k c gray60", "l c #87B687", "z c #8CB78C", "x c #8CB88C", "c c #8EB98E", "v c #94BB94", "b c #9BBF9B", "n c #A0A0A0", "m c gray64", "M c gray66", "N c #AAAAAA", "B c #AEAEAE", "V c #AFAFAF", "C c #A0BFA0", "Z c gray69", "A c #B1B1B1", "S c #B2B2B2", "D c gray70", "F c #B4B4B4", "G c #B7B7B7", "H c gray72", "J c #B8B9B8", "K c #B9B9B9", "L c #B9BBB9", "P c gray73", "I c #BABBBA", "U c #BBBBBB", "Y c #BABCBA", "T c #BBBCBB", "R c #BCBCBC", "E c #BCBDBC", "W c gray74", "Q c gray", "! c gray75", "~ c #A1C0A1", "^ c #AAC3AA", "/ c #A9C4A9", "( c #AAC4AA", ") c #ABC6AB", "_ c #AFC5AF", "` c #B2C7B2", "' c #B5C8B5", "] c #B5CAB5", "[ c #B6C9B6", "{ c #BFC0BF", "} c #B8C9B8", "| c #BACABA", " . c #BDCBBD", ".. c #BECBBE", "X. c #BFCEBF", "o. c #C0C0C0", "O. c #C1C1C1", "+. c gray76", "@. c gray77", "#. c #C5C5C5", "$. c #C6C6C6", "%. c gray78", "&. c #C6CFC6", "*. c #C8C6C8", "=. c #C8C8C8", "-. c gray79", ";. c #CACACA", ":. c #CBCBCB", ">. c #C9CFC9", ",. c #CCC8CC", "<. c #CCCBCC", "1. c #CEC9CE", "2. c gray80", "3. c #CDCDCD", "4. c #CECECE", "5. c gray81", "6. c #C8D0C8", "7. c #C9D0C9", "8. c #CDD2CD", "9. c #CED2CE", "0. c #CED4CE", "q. c #D0CDD0", "w. c #D4CED4", "e. c #D0D0D0", "r. c gray82", "t. c #D0D2D0", "y. c #D0D3D0", "u. c #D1D2D1", "i. c #D1D3D1", "p. c #D2D2D2", "a. c #D2D3D2", "s. c LightGray", "d. c #D0D5D0", "f. c #D2D4D2", "g. c #D3D4D3", "h. c #D7D0D7", "j. c gray83", "k. c #D5D4D5", "l. c #D5D5D5", "z. c #D5D6D5", "x. c #D5D7D5", "c. c #D6D4D6", "v. c #D6D5D6", "b. c #D7D5D7", "n. c gray84", "m. c #D6D7D6", "M. c #D7D7D7", "N. c #D7D8D7", "B. c #D8D6D8", "V. c #D8D7D8", "C. c #D8D8D8", "Z. c #D8D9D8", "A. c #D9D8D9", "S. c gray85", "D. c #DBD9DB", "F. c #DADADA", "G. c gray86", "H. c #DCD8DC", "J. c #DCD9DC", "K. c #DDD8DD", "L. c #DCDADC", "P. c #DFD8DF", "I. c #DEDBDE", "U. c #DFDBDF", "Y. c gainsboro", "T. c #DDDDDD", "R. c gray87", "E. c #DFDFDF", "W. c #E1D9E1", "Q. c #E1DAE1", "!. c #E2DAE2", "~. c #E3DBE3", "^. c #E0DCE0", "/. c #E2DDE2", "(. c #E3DDE3", "). c #E4DBE4", "_. c #E5DBE5", "`. c #E5DCE5", "'. c #E5DEE5", "]. c #EBDEEB", "[. c gray88", "{. c #E2E2E2", "}. c gray89", "|. c #E4E4E4", " X c #E6E6E6", ".X c #E7E7E7", "XX c gray91", "oX c #E9E9E9", "OX c gray92", "+X c gray93", "@X c #F4F4F4", /* pixels */ "l.l.G.G.G.G.G.G.G.G.G.G.G.r.l.l.l.l.G.G.G.G.G.G.G.G.G.G.G.G.f.l.", "l.r.o.o.o.o.o.! o.o.! ! o.l.l.l.l.l.2.! o.o.! ! ! ! o.o.{ @.l.l.", "G.o.G -.#.#.#.#.#.#.#.-.D -.l.r.r.G.U U -.#.*.*.,.#.#.#.=.Z 2.G.", "G.o.-.Y.G.l.G.G.G.G.l.G.! -.XXG.r.G.! 2.Y.l.G.X.] 0.P.N.Y.! 2.l.", "G.o.#.l.r.r.l.l.l.l.r.G.! -.f U Y.G.! -.l.P.t 9 - z ~.r.G.G 2.G.", "G.o.#.G.l.l.l.l.l.l.l.G.U r.f + ! }.U 2.l.l.| v - x ~.f.N.U 2.l.", "G.o.#.G.l.l.l.l.l.l.l.l.! #.@Xh @ o.o.-.G.f.~.] - x ~.r.G.U 2.G.", "G.o.#.G.r.l.l.l.l.l.r.G.! -.r.@X4 & #.-.l.l.P.` - x _.f.l.U 2.l.", "G.o.#.G.r.l.l.l.l.l.l.G.U #.+Xk @ D o.-.N.r.B./ - x H.r.G.U 2.l.", "G.! o.G.l.l.l.l.l.l.r.G.! r.k O M XXY -.l.~.y , , , e H.l.U 2.N.", "G.o.#.G.r.l.l.r.r.r.r.G.U 2.6 M }.l.U -.N.l.| ~ ^ ~ _ k.l.U 9.B.", "G.! -.Y.G.l.G.G.G.G.G.Y.! -. XY.r.G.! 2.G.G.Y.`.`.`./.G.Y.! 2.B.", "G.o.D o.! U ! ! ! ! U ! B 2.l.l.k.G.U D o.! ! U Y Y U ! ! B r.l.", "l.r.-.-.-.-.-.-.-.-.-.-.2.l.l.l.l.l.r.-.-.-.-.-.-.-.-.-.-.2.l.l.", "l.l.G.l.G.l.G.l.l.G.l.G.l.l.l.l.l.l.l.G.G.l.l.G.G.G.G.l.l.G.l.l.", "l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.l.r.l.l.l.l.l.l.", "l.l.l.r.l.l.k.k.l.f.l.f.l.l.l.l.l.l.l.l.r.l.l.r.r.l.l.l.r.r.l.l.", "l.l.G.G.G.l.G.B.G.B.G.B.G.l.l.l.l.l.l.G.G.l.G.G.G.G.l.G.G.G.l.l.", "l.2.U R U U U U U U ! ! Y r.l.l.l.l.-.U ! ! U ! U U U ! U ! l.l.", "G.o.! 2.-.-.w.k.q.-.-.2.G -.l.l.l.G.U o.2.-.-.-.r.l.-.-.2.G 2.N.", "G.o.-.G.B.f./ b X.G.l.P.! -.l.l.l.G.! 2.G.l.l.Y.D k r.G.G.U 2.G.", "G.o.#.l.~.s q - i _.9.G.! -.G.l.l.l.! -.l.r.}.m . ! l.l.U 2.l.", "G.o.#.G.l.7.' , p `.f.N.U -.B.l.l.G.U -.G.l.2.% & . ! G.l.U 2.G.", "G.o.o.G.r.H.&., u _.9.G.! -.G.l.r.G.U -.l.}.3 5 j 2.G.G.U 2.l.", "G.o.#.G.r.G.>., a ].r.G.Y -.G.f.l.l.! -.Y.D . 8 2 8 l.G.U 2.l.", "G.o.@.G.l.9./ - r 9.r.G.! -.B.l.l.G.U -.Y.D $ # o & 2.G.H 2.l.", "G.o.#.N.~.d , 0 , w l.G.Y -.B.l.r.G.U -.G.l.l.XX8 #.G.l.U r.G.", "G.o.#.N.k.>.| .| X.r.l.! -.G.f.r.G.! -.l.k.l.l.-.U r.l.B.U 2.l.", "G.{ -.Y.l.G.P.P.P.Y.N.Y.! -.G.l.l.l.Y 2.G.l.G.l.Y.Y.G.G.Y.U 2.N.", "G.@.Z ! U U J J U U U U B 2.l.l.l.G.! D U U U G U G H U U Z r.l.", "r.l.2.2.2.2.2.9.2.2.2.2.r.l.l.l.l.l.l.q.2.r.2.2.2.2.2.2.9.r.l.l.", "l.l.G.l.G.l.G.l.G.l.G.N.l.l.l.l.l.l.l.N.l.l.G.G.l.G.N.B.B.l.l.l." }; /* XPM */ static const char *const xpm_icon_2[] = { /* columns rows colors chars-per-pixel */ "48 48 166 2 ", " c black", ". c #020202", "X c gray1", "o c gray4", "O c #101010", "+ c gray9", "@ c gray11", "# c #1D1D1D", "$ c #1E1E1E", "% c gray14", "& c #252525", "* c gray15", "= c #2D2D2D", "- c gray18", "; c #323232", ": c #007200", "> c #007300", ", c #007500", "< c #007700", "1 c #007800", "2 c #007900", "3 c #007E00", "4 c #494949", "5 c #4B4B4B", "6 c #4C4C4C", "7 c gray30", "8 c #5D5D5D", "9 c gray37", "0 c #5F5F5F", "q c #606060", "w c #626262", "e c gray39", "r c #656565", "t c #676767", "y c #6A6A6A", "u c gray42", "i c #6D6D6D", "p c gray43", "a c #717171", "s c #747474", "d c gray46", "f c gray50", "g c #098209", "h c #098309", "j c #0D840D", "k c #1C8B1C", "l c #248D24", "z c #278F27", "x c #288E28", "c c #298F29", "v c #4B9D4B", "b c #4B9E4B", "n c #52A052", "m c #59A259", "M c #5AA45A", "N c #5BA45B", "B c #60A660", "V c #61A661", "C c #66A866", "Z c #67A967", "A c #68A968", "S c #69A969", "D c #6BAA6B", "F c #6EAB6E", "G c #7FB27F", "H c #808080", "J c gray51", "K c #838383", "L c #868686", "P c gray53", "I c gray54", "U c #909090", "Y c gray59", "T c gray61", "R c #9F9F9F", "E c #86B586", "W c #8EB88E", "Q c #A0A0A0", "! c #A4A4A4", "~ c #A7A7A7", "^ c gray68", "/ c #AEAEAE", "( c #AEAFAE", ") c #AFAFAF", "_ c #B1B1B1", "` c gray74", "' c gray", "] c #C1C1C1", "[ c gray76", "{ c #C6C6C6", "} c gray78", "| c #C7CFC7", " . c #C8C8C8", ".. c gray79", "X. c #CACACA", "o. c #CBCBCB", "O. c gray80", "+. c #CDCDCD", "@. c #CECECE", "#. c gray81", "$. c #C9D0C9", "%. c #CAD0CA", "&. c #CBD1CB", "*. c #CCD2CC", "=. c #CED1CE", "-. c #CFD3CF", ";. c #D0D0D0", ":. c gray82", ">. c #D0D2D0", ",. c #D0D3D0", "<. c #D1D3D1", "1. c #D2D2D2", "2. c #D3D2D3", "3. c LightGray", "4. c #D1D4D1", "5. c #D2D4D2", "6. c #D3D4D3", "7. c gray83", "8. c #D4D5D4", "9. c #D5D4D5", "0. c #D5D5D5", "q. c #D6D4D6", "w. c #D6D5D6", "e. c #D7D5D7", "r. c gray84", "t. c #D7D6D7", "y. c #D7D7D7", "u. c #D9D7D9", "i. c #DBD6DB", "p. c #D8D8D8", "a. c gray85", "s. c #D9DAD9", "d. c #DBD8DB", "f. c #DADADA", "g. c #DADBDA", "h. c gray86", "j. c #DCD8DC", "k. c #DDD8DD", "l. c #DCDBDC", "z. c #DED9DE", "x. c #DFD9DF", "c. c gainsboro", "v. c #DDDDDD", "b. c #DEDCDE", "n. c gray87", "m. c #DFDFDF", "M. c #E0D9E0", "N. c #E1DAE1", "B. c #E2DAE2", "V. c #E4DBE4", "C. c #E5DBE5", "Z. c #E5DCE5", "A. c #EDDFED", "S. c gray88", "D. c #E1E1E1", "F. c #E2E2E2", "G. c gray89", "H. c #E4E4E4", "J. c gray90", "K. c gray91", "L. c #E9E9E9", "P. c #EAEAEA", "I. c gray92", "U. c #F1E1F1", "Y. c gray95", "T. c white", /* pixels */ "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.", "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.r.r.0.0.0.0.r.r.0.0.0.0.0.0.0.0.", "0.0.0.0.p.p.p.p.p.p.p.p.p.p.p.p.p.p.p.0.0.0.0.0.0.0.0.0.p.p.p.p.r.p.p.r.r.r.p.r.p.p.r.r.0.0.0.0.", "0.0.0.0.@.............................@.0.0.0.0.0.0.0.0.@.........X.X.X.X.X.X.X...X...=.0.0.0.0.", "0.0.p.;.R _ ) ) _ _ ) ) ) ) ) _ _ _ _ R @.0.0.0.0.0.p.;.Q _ _ ) ) ) ) ) ) _ ) _ ) ) _ R @.r.0.0.", "0.0.p..._ D.p.p.p.v.p.v.p.v.p.v.p.p.D._ ..p.0.0.0.0.p..._ D.p.p.v.p.p.N.v.v.p.p.v.p.D._ ..p.0.0.", "0.0.p..._ p.0.0.;.0.0.0.0.0.0.;.0.;.p.) ..v.p.;.0.0.p..._ p.0.0.5.u.0.X.| =.0.0.0.;.p.) ..p.0.0.", "0.0.0..._ p.0.0.0.0.0.0.0.0.0.0.0.0.v._ @.....v.;.0.0...) v.0.;.p.E k j 3 D N.5.0.5.v._ ..p.0.0.", "0.0.p...) p.0.0.0.0.0.0.0.0.0.0.0.0.p.) 0.Q J J.;.p..._ v.0.5.l.n z x , Z V.5.0.;.g.) ..p.0.0.", "0.0.p..._ v.0.0.0.0.0.0.0.0.0.0.0.;.v.) ..D.L L J.0...) p.0.0.0.-.V.V : D Z.5.0.0.v.) ..p.0.0.", "0.0.p...) p.0.0.0.0.0.0.0.0.0.0.0.0.v.) ..0.J.L J L..._ v.;.0.0.0.N.M : C V.5.0.0.v.) ..p.0.0.", "0.0.p..._ p.0.0.0.0.0.0.0.0.0.0.0.0.p._ ..p.;.J.L f @.) p.0.0.0.5.N.M : D V.;.0.0.p._ ..p.0.0.", "0.0.p...) p.0.0.0.0.0.0.0.0.0.0.0.;.v._ ..r.5.p.;.+ ; @.) p.0.0.0.;.N.M , D N.;.0.5.p._ ..p.0.0.", "0.0.p..._ v.0.0.0.0.0.0.0.0.0.0.0.0.p.) X.r.g.=.* * @.@.) p.0.0.0.u.U.N : F U.0.0.0.l.) ..p.0.0.", "0.0.p...) v.0.0.0.0.0.0.0.0.0.0.0.0.v.) } N.;.* * @.v...) v.0.5.p.E b z 2 x b W N.5.p._ ..p.0.0.", "0.0.p...) p.;.0.0.0.0.0.0.0.0.0.0.0.p.) @.] @ * @.p.0...) p.0.5.N.m , h j h 2 Z Z.;.p._ ..p.0.0.", "0.0.p..._ v.0.0.0.0.0.0.0.0.0.0.0.0.p.) ;.~ q ..v.;.p..._ p.0.0.0.;.=.=.&.&.=.;.0.0.v.) ..p.0.0.", "0.0.p...) p.;.0.0.;.0.0.;.0.0.0.0.;.p._ ..D.L.p.0.0.p..._ p.;.0.0.0.0.0.0.0.u.0.5.;.p.) ..p.0.0.", "0.0.p..._ D.p.p.v.p.p.v.v.p.p.v.v.p.D._ ..0.;.0.0.0.p..._ D.p.v.p.v.p.p.p.p.p.p.v.p.D._ ..p.0.0.", "0.0.0.@.R _ _ _ ) _ ) ) _ _ ) ) ) ) _ R @.p.0.0.0.0.0.@.R _ ) _ ) _ _ _ _ _ _ _ ) ) _ Q @.p.0.0.", "0.0.0.0.@.............................@.0.0.0.0.0.0.0.0.@.............................@.0.0.0.0.", "0.0.0.0.0.p.p.p.p.p.p.p.p.p.p.p.p.p.p.0.0.0.0.0.0.0.0.0.0.p.p.p.p.p.p.p.p.p.p.p.p.p.p.r.0.0.0.0.", "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.", "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.", "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.", "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.", "0.0.0.0.0.p.p.p.p.p.p.p.p.p.p.p.p.p.p.0.0.0.0.0.0.0.0.0.0.p.p.p.p.p.p.p.p.p.p.p.p.p.p.p.0.0.0.0.", "0.0.0.0.@...@.........................@.0.0.0.0.0.0.0.0.@...@.........................@.0.0.0.0.", "0.0.p.@.Q _ ) ) ) ) ) _ ) _ ) _ _ ) _ R ;.p.0.0.0.0.0.@.Q _ ) ) _ ) ) _ ) ) ) ) _ _ _ Q @.0.0.0.", "0.0.p..._ D.p.p.v.p.p.v.v.v.p.p.v.p.D._ ..p.0.0.0.0.p..._ D.p.p.v.p.p.p.v.v.v.p.p.p.D._ ..p.0.0.", "0.0.p..._ p.0.0.5.u.0.X.| =.0.0.0.;.p._ ..p.0.0.0.0.p..._ p.0.0.0.0.0.0...} @.0.0.;.p._ ..p.0.0.", "0.0.p...) p.0.0.p.E k j 3 D Z.5.0.0.p.) ..p.0.0.0.0.p..._ p.0.0.0.;.D.Y o y D.0.0.p.) ..p.0.0.", "0.0.p..._ p.0.5.l.n z x , C V.;.0.0.v.) ..p.0.0.0.0.p...) p.0.0.0.p.} $ q D.;.0.v._ ..p.0.0.", "0.0.p..._ p.0.0.0.;.Z.V : D Z.5.0.;.p._ ..p.0.0.0.0.p..._ v.0.0.;.D.4 $ 6 t D.;.0.p.) ..p.0.0.", "0.0.p...) l.0.0.0.0.N.M : Z Z.5.0.0.p.) ..p.0.0.0.0.p...) p.0.0.J.U R y q v.0.0.v.) ..p.0.0.", "0.0.p..._ p.5.0.0.5.N.M : D N.5.0.0.v.) ..p.0.0.0.0.p...) v.;.p.] o 8 T.t p Y.;.0.p._ ..p.0.0.", "0.0.p...) p.0.0.u.;.l.M : Z N.5.0.0.p.) ..p.0.0.0.0.p...) l.;.J.d 0 d - - I 0.0.p.) ..p.0.0.", "0.0.p..._ v.0.0.0.u.A.N : F U.0.0.0.v.) ..p.0.0.0.0.p..._ p.;.J.a X X - 0.0.p.) ..p.0.0.", "0.0.p...) v.0.5.j.E b z 2 c b W l.5.p.) ..p.0.0.0.0.p..._ v.;.p.' R ! _ 6 6 ' ;.0.v.) ..p.0.0.", "0.0.p...) p.0.;.N.m 2 h j h , Z Z.;.v._ ..p.0.0.0.0.p...) p.0.0.p.D.p.I.y p L.;.0.p.) ..p.0.0.", "0.0.p..._ v.0.0.0.;.=.&.&.=.&.;.0.0.p._ ..p.0.0.0.0.p..._ v.0.0.0.;.0.;.@...@.0.0.0.v.) ..p.0.0.", "0.0.p...) p.;.0.0.0.0.u.0.0.0.0.0.0.p._ ..p.0.0.0.0.p...) p.;.0.0.0.0.0.0.0.0.0.0.;.p.) ..p.0.0.", "0.0.p..._ D.p.p.p.p.l.p.p.p.p.v.p.p.D._ ..r.0.0.0.0.p..._ D.p.p.p.v.p.v.p.p.p.v.v.p.D._ ..p.0.0.", "0.0.0.@.R _ ) _ _ ) _ ) _ ) ) _ ) ) _ R @.u.0.0.0.0.0.@.R _ _ _ ) _ ) ) _ _ ) _ _ ) _ R @.0.0.0.", "0.0.0.0.@.........................@...@.0.0.0.0.0.0.0.0.@.............................@.0.0.0.0.", "0.0.0.0.p.p.p.p.p.p.p.p.p.p.p.p.p.p.r.p.0.0.0.0.0.0.0.0.p.p.p.p.p.p.p.p.p.p.p.p.p.p.p.p.0.0.0.0.", "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.", "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0." }; const char *const *const xpm_icons[] = { xpm_icon_0, xpm_icon_1, xpm_icon_2, }; const int n_xpm_icons = 3; puzzles-20170606.272beef/icons/undead-icon.c0000644000175000017500000003700513115373753017346 0ustar simonsimon/* XPM */ static const char *const xpm_icon_0[] = { /* columns rows colors chars-per-pixel */ "16 16 249 2 ", " c #E6E6E6", ". c #E6E6E6", "X c gray91", "o c #D5D5D5", "O c gainsboro", "+ c gray91", "@ c #E6E6E6", "# c #E7E7E7", "$ c #E4E4E4", "% c #DDDDDD", "& c gray91", "* c gray90", "= c #E6E6E6", "- c #E6E6E6", "; c gray90", ": c #EEEEEE", "> c gray69", ", c #989898", "< c #F1F1F1", "1 c #E1E1E1", "2 c gray95", "3 c #A2A2A2", "4 c #656565", "5 c gray91", "6 c #E6E6E6", "7 c #E6E6E6", "8 c #E6E6E6", "9 c #E6E6E6", "0 c gray89", "q c gray94", "w c #939393", "e c #A5A5A5", "r c gray94", "t c #E1E1E1", "y c gray94", "u c #ACACAC", "i c #767676", "p c gray91", "a c #E6E6E6", "s c #E6E6E6", "d c #E6E6E6", "f c #E6E6E6", "g c #E6E6E6", "h c #E6E6E6", "j c #EAEAEA", "k c gray91", "l c #DDDDDD", "z c #DFDFDF", "x c gray91", "c c #E9E9E9", "v c gray91", "b c #EAEAEA", "n c #E9E9E9", "m c gray91", "M c #E7E7E7", "N c #E6E6E6", "B c #E6E6E6", "V c #E6E6E6", "C c #E6E6E6", "Z c gray90", "A c gray", "S c #C1C1C1", "D c #D1D0D0", "F c #D0CFCF", "G c #C2C1C1", "H c gray73", "J c #C0C0C0", "K c #C0C0C0", "L c #C1C1C1", "P c #C5C5C5", "I c #CACACA", "U c #E7E7E7", "Y c #E6E6E6", "T c #E4E4E4", "R c gray91", "E c #DFDFDF", "W c gray76", "Q c #E5E6E6", "! c #9B9C9C", "~ c #9F9F9F", "^ c #E4E5E5", "/ c #D2D2D2", "( c #E1E1E1", ") c gray90", "_ c gray90", "` c #C5C5C5", "' c #E6E6E6", "] c #E6E6E6", "[ c #EEEEEE", "{ c #9B9B9B", "} c LightGray", "| c #E4E3E3", " . c #C7C8C8", ".. c #C5C0C0", "X. c #887A7A", "o. c #8A7C7C", "O. c #C6C1C1", "+. c #D8D9D9", "@. c gray90", "#. c #F1F1F1", "$. c gray60", "%. c gray72", "&. c gray93", "*. c gray90", "=. c gray95", "-. c gray53", ";. c gray71", ":. c #EAE9E9", ">. c #C1C2C2", ",. c #D1C6C6", "<. c #CBB6B6", "1. c #CCB6B6", "2. c #CFC4C4", "3. c #D4D5D5", "4. c gray90", "5. c #989898", "6. c gray71", "7. c gray95", "8. c #E4E4E4", "9. c #E6E6E6", "0. c #E7E7E7", "q. c #CACACA", "w. c #D7D7D7", "e. c #E1E1E1", "r. c #C6C6C6", "t. c #E2E1E1", "y. c #BFB3B3", "u. c #C0B4B4", "i. c #DFDEDE", "p. c #DEDFDF", "a. c #C6C6C6", "s. c #B9B9B9", "d. c gray96", "f. c #E6E6E6", "g. c gray91", "h. c #E6E6E6", "j. c #E6E6E6", "k. c gray92", "l. c gray92", "z. c gray88", "x. c #B9B9B9", "c. c #DBDCDC", "v. c #DAD9D9", "b. c #DBDADA", "n. c #D9DADA", "m. c #C5C5C5", "M. c #D6D7D6", "N. c #E1E0E1", "B. c #DAD8DA", "V. c gray84", "C. c #DADADA", "Z. c #E7E7E7", "A. c gray90", "S. c gray92", "D. c #E9E9E9", "F. c #E0DFDF", "G. c gray", "H. c #E6E3E3", "J. c #CCD6D6", "K. c #CED7D7", "L. c #E5E1E1", "P. c #CBCDCC", "I. c #E1DEE1", "U. c #D4D7D4", "Y. c #CAD4CA", "T. c #E2DEE2", "R. c #E1E1E1", "E. c #E6E6E6", "W. c gray92", "Q. c #A9A9A9", "!. c gray85", "~. c #E1E2E2", "^. c #C9C6C6", "/. c #C5D7D7", "(. c #70C6C6", "). c #72C6C6", "_. c #C4D3D3", "`. c #DFDADC", "'. c #D2DBD3", "]. c #76CE76", "[. c #65D165", "{. c #ADD2AD", "}. c #EDE8ED", "|. c #E4E6E4", " X c gray95", ".X c #8B8B8B", "XX c #BCBCBC", "oX c #E7E9E9", "OX c #C9C1C1", "+X c #97D1D1", "@X c #69CECE", "#X c #68CDCD", "$X c #94CCCA", "%X c #E6D7DE", "&X c #ACD2AE", "*X c #5CCE5C", "=X c #61CE61", "-X c #7BCF7B", ";X c #E9E2E9", ":X c #E5E7E5", ">X c #EAEAEA", ",X c gray70", " , < 1 2 3 4 5 6 7 ", " - 8 9 0 q w e r t y u i p a s ", "d f g h j k l z x c v b n m M N ", "B V C Z A S D F G H J K L P I U ", "Y T R E W Q ! ~ ^ / ( ) _ ` ' ] ", "[ { } | ...X.o.O.+.@.#.$.%.&.*.", "=.-.;.:.>.,.<.1.2.3.4.5.6.7.8.9.", "0.q.w.e.r.t.y.u.i.p.a.s.d.f.g.h.", "j.k.l.z.x.c.v.b.n.m.M.N.B.V.C.Z.", "A.S.D.F.G.H.J.K.L.P.I.U.Y.T.R.E.", "W.Q.!.~.^./.(.)._.`.'.].[.{.}.|.", " X.XXXoXOX+X@X#X$X%X&X*X=X-X;X:X", ">X,X c #6EAC6E", ", c #72AA72", "< c #59CE59", "1 c #5FD65F", "2 c #63C763", "3 c #6DC36D", "4 c #6BCF6B", "5 c #60D260", "6 c #69D369", "7 c #6BDC6B", "8 c #74C874", "9 c #7FC27F", "0 c #72DE72", "q c #6BE56B", "w c #6EE86E", "e c #7F8181", "r c #5FB5B5", "t c #6EBCBC", "y c #72B8B8", "u c #5CC3C3", "i c #5ECCCC", "p c #6BC6C6", "a c #64CCCC", "s c #73C3C3", "d c #6ED6D6", "f c #65DADA", "g c #69DBDB", "h c #7BDBDB", "j c #6EE6E6", "k c #71E3E3", "l c #74EAEA", "z c #808C8C", "x c gray54", "c c #929393", "v c #9E9E9E", "b c #A59494", "n c #A89797", "m c #8BBA8B", "M c #9CBC9C", "N c #87AAAA", "B c #8CAAAA", "V c #82BBBB", "C c #93BBBB", "Z c #A3A3A3", "A c #ABABAB", "S c #B3A1A1", "D c #B8A6A6", "F c #BBABAB", "G c #A0BEA0", "H c #B5B5B5", "J c #BBBBBB", "K c #C2B1B1", "L c #CAB6B6", "P c #C5BBBB", "I c #CBB9B9", "U c #D2BDBD", "Y c #93C193", "T c #A3C0A3", "R c #AFC2AF", "E c #B5C5B5", "W c #B8C6B8", "Q c #81CCCC", "! c #BBC7C7", "~ c #BAC8C8", "^ c #C5C5C5", "/ c #C8C6C6", "( c #C6CCC6", ") c #C2CDCD", "_ c #CACBCB", "` c #DBC5C5", "' c #CDD3D3", "] c #D4D4D4", "[ c #DAD7DA", "{ c #DCDCDC", "} c #E0C8C8", "| c #E2DDDD", " . c #DFE0DF", ".. c #E2DDE2", "X. c #E5E5E5", "o. c #E9E5E5", "O. c #EBE5EB", "+. c #E7E8E8", "@. c #ECECEC", "#. c #F0EDED", "$. c #F5EFF5", "%. c #EFF0F0", "&. c #F2F2F2", "*. c gray99", /* pixels */ "X.X.+.X.+.+.X.X.X.X.+.X.+.#.O.X.+.X.+.X.+.o.+.+.@.o.X.X.X.X.X.X.", "X.X.X.X.X.X.o.+.+.X.X.+.X.^ { @.X.X.X.X.+.O.+.o._ @.X.X.X.X.X.X.", "X.X.+.+.X.X.X.X.X.X.X.@.^ % + _ @.X.X.X.O...O., X c &.X.X.X.X.X.", "+.X.X.X.+.X.X.X.X.X.X.X.@.+.O ] @.X.X.X...O...+ - # $.X.+.X.X.+.", "X.X.X.+.X.X.+.X.X.X.X.+.{ O v $.X.X.X.X.X.X.@.@ * # %.X.X.+.X.X.", "+.+.X.X.+.X.+.X.X.+.X.&.A O % _ @.X.X.X.X.X.#.A + J @.X.X.X.+.X.", "o.X.+.X.X.X.X.X.X.X.X.X.+.&.+.+.X.X.X.+.X.+.X.@.&.@.o.X.X.+.X.X.", "X.X.X.X.X.X.o.+.+.@.@.%.@.@.@.@.@.@.@.@.#.@.@.@.@.@.%.@.#.+.X.X.", "X.+.X.X.X.X.+.+.{ ^ ^ / ^ / ( ^ / _ ( _ / / ( ^ / ( / / ^ ] +.X.", "X.X.X.+.+.X.o.@.c Z H A A A A A A A Z c A A A A A A A A A ^ +.X.", "X.X.o.X.X.X.X.@.v X.&.%.*.*.*.*.$.&.X._ *.%.@.&.&.%.*.&.%.@.X.+.", "X.X.@.&.+.X.X.@.v [ +.X.e X o x @.+.] ^ +.X.X.o...&.c J @.X.X.X.", "X.$.A % { +.X.@.v { &.; & & & $ x &.{ / @.X.X. .*.c + ..+.X.X.X.", "X.+.( o ( @.X.@.v X.( D L I L I S _ { / +.X.X.*.x @ @.@.X.X.X.X.", "X.X.*.# ] @.X.@.v ./ } F K F F ` _ .^ @.X.*.c @ @.+.X.X.+.+.X.", "X.@.Z - O.X.@.v { ] K L U U L H { { / X.*.x @ @.+.X.X.X.X.X.X.", "X.+.^ A J X.+.@.v [ @.P b D S n / @.[ ^ &.c @ @.@.X.X.X.+.X.X.X.", "+.+.@.&.@.X.X.@.v [ @.o./ P P / o.+.] ^ @.H .+.o.X.X.o.o.X.X.+.", "+.X.X.X.X.X.X.@.v .@.+.#.+.+.@.@.@.{ _ $.&.@.+.+.O.+.+.+.+.X.X.", "+.X.X.X.+.X.X.@.v H / W ^ ^ ^ ^ ^ ^ H A ( J ^ ^ W ^ ^ ^ ^ ] +.X.", "X.X.X.o.+.X.o.@.v ] .{ .o.o. .{ X.] ^ X.{ .X.+.+. ...{ ..X.X.", "X.X.@.@.X.X.X.@.v { @.@.| ! ! | @.+.{ ^ +.+.O./ W _ @.+.+.+.X.X.", "X.+.] J X.+.X.@.v { @.) p g f p _ @.[ ^ @...m 7 7 4 M O.X.X.+.X.", "o.&.Z . _ @.X.@.v { | t s d h t y o.{ ^ &.G 5 6 0 6 5 W @.X.X.X.", "X.X.*.# _ %.X.@.v .) a c r Q z u ' .^ O.9 7 : 6 : q Y O.X.X.X.", "X.X.] o A @.X.@.v X.) g k l k l d ' .^ O.9 w 0 7 0 q Y $.X.X.X.", "X.@.v @ - X.X.@.v | ) i l g j j i ' { ^ $.E < , > 5 2 ^ @.X.X.X.", "X.X.@.&.&.X.X.@.v .! B V C V C N ) ..^ +.O.G 3 4 8 E @.X.X.X.X.", "X.X.X.X.X.X.X.@.v { .o.| o.| o.X.X.{ ^ @.X.O.{ _ | @.X.+.X.X.+.", "X.X.X.X.X.X.X.@.Z { @.X.X.X.+.+.X.+.{ / @.X.X.+.@.X.X.X.X.+.X.X.", "X.X.X.X.X.X.X.+. .+.X.X.X.X.X.X.X.X.X.X.X.X.X.o.X.+.X.+.X.X.+.X.", "+.X.X.+.X.+.X.X.O.+.X.X.X.X.+.X.X.X.X.X.+.X.X.X.o.+.+.X.X.X.X.o." }; /* XPM */ static const char *const xpm_icon_2[] = { /* columns rows colors chars-per-pixel */ "48 48 140 2 ", " c #060505", ". c #0B0A0A", "X c #110F0F", "o c #151515", "O c #1D1D1D", "+ c #222222", "@ c gray17", "# c gray21", "$ c #3C3C3C", "% c #3E7D3E", "& c #414141", "* c #4D4D4D", "= c #534C4C", "- c #575353", "; c #5C5B5B", ": c #636262", "> c #6C6D6D", ", c #727272", "< c #7C7575", "1 c #7D7D7D", "2 c #8A7C7C", "3 c #539E53", "4 c #5E955E", "5 c #57AD57", "6 c #58AF58", "7 c #5CB45C", "8 c #63B263", "9 c #65BC65", "0 c #7DA37D", "q c #71B471", "w c #5DD35D", "e c #61C661", "r c #66CD66", "t c #65D165", "y c #67DD67", "u c #6BD36B", "i c #6FDA6F", "p c #72C772", "a c #71DE71", "s c #6BE66B", "d c #6EED6E", "f c #73E573", "g c #74EC74", "h c #77F377", "j c #78F078", "k c #6D9999", "l c #769797", "z c #799595", "x c #54A7A7", "c c #54AAAA", "v c #57B4B4", "b c #5CBEBE", "n c #61B5B5", "m c #6AB1B1", "M c #60BABA", "N c #71B5B5", "B c #58C5C5", "V c #56C9C9", "C c #5BCDCD", "Z c #62C2C2", "A c #6CC6C6", "S c #65CCCC", "D c #65DCDC", "F c #69D8D8", "G c #72DEDE", "H c #65E0E0", "J c #6CE3E3", "K c #6CEAEA", "L c #73E6E6", "P c #74EAEA", "I c #7AEEEE", "U c #77F6F6", "Y c #848484", "T c #8C8C8C", "R c #959494", "E c #A59696", "W c #AE9D9D", "Q c #84AB84", "! c #89A989", "~ c #8DB18D", "^ c #94AC94", "/ c #95B295", "( c #8CA3A3", ") c #84ADAD", "_ c #89ABAB", "` c #97AFAF", "' c #84B1B1", "] c #82BABA", "[ c #9AB4B4", "{ c #9ABABA", "} c #A4A4A4", "| c #AAA2A2", " . c #ADACAC", ".. c #B3A2A2", "X. c #B2AAAA", "o. c #BCA9A9", "O. c #A1B3A1", "+. c #ABB5B5", "@. c #AFBABA", "#. c #B4B4B4", "$. c #B9B6B6", "%. c #B5BBB5", "&. c #BABBBA", "*. c #C2AFAF", "=. c #C5B2B2", "-. c #CBB7B7", ";. c #CDB8B8", ":. c #D5BEBE", ">. c #BEC0BE", ",. c #BEC0C0", "<. c #C3C3C3", "1. c #CCC7C7", "2. c #CBCBCB", "3. c #D6C1C1", "4. c #DAC3C3", "5. c #D1CECE", "6. c #DFCACA", "7. c #D4CFD4", "8. c #D6D6D6", "9. c #DDD6D6", "0. c #D7D8D8", "q. c #DBDBDB", "w. c #E2CBCB", "e. c #EED5D5", "r. c #E1D9D9", "t. c #F3DBDB", "y. c #E1D9E1", "u. c #DFE1E1", "i. c #E6E6E6", "p. c #ECE5E5", "a. c #E7E9E7", "s. c #EDE7ED", "d. c #E6E8E8", "f. c #ECEBEB", "g. c #F1ECEC", "h. c #EEF0EE", "j. c #F1ECF1", "k. c #EFF0F0", "l. c #F3F3F3", "z. c gray99", /* pixels */ "i.i.i.d.i.i.i.i.i.i.d.i.i.i.d.d.i.i.i.i.d.d.i.i.i.i.i.d.i.d.i.i.i.i.d.i.i.i.i.i.i.i.i.i.i.i.i.d.", "i.i.i.a.d.d.d.i.d.i.p.i.i.i.i.i.d.i.i.d.i.d.d.p.i.i.i.i.d.i.d.i.i.i.i.i.i.i.i.i.i.i.i.d.i.i.i.i.", "i.i.a.i.i.d.i.i.i.d.i.i.i.i.i.i.i.i.i.i.f.a.i.i.i.i.i.i.i.i.p.i.i.i.i.d.f.i.i.i.i.i.a.i.i.i.i.i.", "i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.d.2.0.f.i.i.i.i.i.i.i.i.i.i.i.f.q.q.f.i.i.i.a.i.i.i.i.i.i.", "i.i.i.i.i.i.d.i.p.i.i.i.i.i.i.i.d.i.l.1 @ + R l.i.i.i.i.i.i.i.i.i.j.#.+ O .k.i.d.d.i.i.i.i.i.i.", "i.i.d.i.i.i.i.i.d.i.i.i.i.i.d.i.i.p.a.2.l.1 $ l.i.i.i.i.i.i.d.i.i.l.& < Y # l.i.d.i.i.i.i.i.p.d.", "i.d.i.i.p.i.i.i.i.i.i.i.i.d.i.i.i.i.u.l.q.+ R l.i.i.i.i.i.i.i.d.p.f.$ - : # d.i.d.i.i.i.i.d.i.i.", "i.i.i.d.i.i.i.d.i.p.d.i.i.i.i.d.i.i.d.r.$ R z.i.i.i.i.i.i.p.i.d.p.l.# R ( @ f.i.i.p.i.i.i.i.d.d.", "i.i.d.i.i.i.i.i.i.d.i.i.d.d.i.i.i.i.l.* . * , s.i.i.i.i.i.i.i.i.i.l.T O O 1 l.i.i.i.d.i.i.i.d.i.", "i.i.i.p.i.i.d.i.i.i.i.i.i.d.i.i.i.i.f. .R Y } d.i.i.i.i.i.i.i.i.i.i.a. .} f.i.i.i.i.i.i.i.i.i.i.", "i.i.i.i.d.i.i.i.i.i.i.i.i.i.i.i.i.i.i.h.l.z.l.i.i.i.i.i.i.i.i.i.i.i.i.k.l.i.i.i.d.i.i.i.i.d.d.i.", "i.i.i.d.i.p.i.d.i.i.d.p.i.i.i.i.i.i.i.i.u.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.i.", "d.i.i.i.i.i.i.i.d.i.i.i.d.p.f.k.f.f.h.f.f.h.f.h.l.f.f.l.f.f.f.k.k.h.f.k.k.f.h.f.g.g.g.a.i.i.i.i.", "i.i.d.p.d.i.i.i.i.i.i.i.a.8.<.<.<.<.<.<.<.<.<.<.<.<.<.<.1.<.<.<.<.1.<.<.<.<.<.<.<.<.<.q.a.i.i.i.", "i.d.i.i.i.i.i.i.i.i.i.i.s.> Y T T T T T T T T T T T T T > T T T T T T T T T T T T T Y 1.s.i.d.d.", "i.i.i.i.i.i.i.d.i.d.i.i.i.Y g.l.l.l.l.l.k.l.j.l.l.l.l.l.&.l.l.l.l.l.l.l.l.l.l.l.l.l.l.f.i.d.i.i.", "i.i.i.i.i.i.i.i.i.i.i.i.i.1 q.i.i.i.i.l.h.f.l.f.u.i.i.i. .i.i.u.i.i.y.i.i.u.i.k.i.i.u.d.i.i.i.i.", "i.i.i.i.i.f.f.i.i.i.i.i.i.1 i.i.i.f.q., $ $ : 5.l.i.i.a. .i.i.i.i.i.i.i.i.i.f.< 5.f.i.i.i.i.i.i.", "i.i.i.i.i.2.<.i.i.i.i.i.i.1 i.i.k.-.O . X X ( l.p.a.X.i.d.i.i.i.i.i.i.l.* # i.i.i.i.i.i.i.i.", "i.i.i.k.#.o + i.d.i.i.i.i.1 i.a.u.- ..t.3.;.t.=.= 5.s.i. .i.i.d.i.i.i.i.l.* $ h.a.i.i.i.i.i.i.i.", "d.i.i.a.i. .+ i.a.i.i.d.i.1 q.l.} o.t.< =.4.< 6.:.R l.i.#.i.i.i.i.i.i.z.* # k.a.i.i.i.i.i.d.d.p.", "i.i.i.i.l.$.O u.d.i.d.i.i.1 i.f. .6.4.: ..;.; =.e.| i.a. .i.i.i.i.i.l.* # l.a.i.i.i.i.i.i.i.i.d.", "i.i.i.i.l.<.+ f.a.i.p.i.i.1 i.f.#.3.w.e.e.e.t.w.w.X.d.d. .i.a.i.i.l.* # f.a.i.i.i.i.i.i.i.i.i.d.", "i.i.i.l. .+ . $ 7.a.i.i.i.1 i.s.<.=.*.E ;.;.| ..-.$.f.i.#.i.i.a.z.* # l.a.i.i.i.i.i.i.d.a.i.d.i.", "i.i.i.a.2.} .} r.a.d.i.i.1 i.i.f.| w.Y ..=.< 3.W u.d.d. .y.i.i.* # j.a.i.d.i.i.i.i.d.i.i.i.i.i.", "i.i.i.i.f.l.l.l.a.i.a.i.i.1 i.i.a.r.| ..3.4.o.| 0.a.i.a.#.i.l.} & f.a.i.i.i.i.i.i.i.i.i.a.i.i.i.", "i.i.i.i.i.i.i.i.i.i.i.i.i.1 i.a.i.a.f.2.$.%.<.d.f.i.i.d. .i.a.i.j.a.i.i.i.i.i.i.a.i.d.d.i.i.i.a.", "i.i.i.i.i.i.i.i.i.i.d.i.i.1 i.s.s.a.a.f.l.j.j.s.a.f.d.f.%.a.s.a.a.a.a.s.a.s.f.f.s.a.s.p.i.i.i.i.", "i.i.i.i.i.i.i.i.i.i.d.i.i.1 0.8.0.8.8.8.8.8.8.0.0.0.0.0.} 8.8.8.0.0.0.0.8.8.0.q.8.0.0.i.a.a.i.i.", "i.i.i.i.i.i.i.i.a.i.i.d.i., .&.%.%.$.$.%.%.#.$.#.#.%.&.T %.$.$.#.%.#.$.$.#.%.$.$.$.#.8.s.i.i.i.", "i.i.i.i.i.i.i.i.i.i.i.i.i.1 a.f.f.f.s.f.k.l.f.f.f.f.s.j.%.a.j.f.f.f.f.k.j.f.a.f.f.f.f.i.i.i.i.a.", "a.i.i.i.i.i.i.i.a.i.i.i.d.1 i.i.i.i.a.s.r.r.p.s.i.i.i.d. .i.i.i.i.f.f.y.y.s.d.i.i.i.i.i.i.i.i.i.", "i.i.d.d.i.f.l.i.i.i.i.i.i.< y.s.i.f.2._ N N ) ,.s.i.i.a. .i.d.i.f.<.Q q q Q 1.g.i.i.i.i.d.d.i.i.", "i.d.i.d.i.&.$.i.i.i.i.i.i.0 i.y.g.&.n K P P K b +.f.i.a. .i.i.j.$.7 s h g s 7 %.g.i.i.i.d.i.i.i.", "i.i.i.g.#.o + y.d.i.i.i.i.1 i.s.r.m F A L P A G b 2.f.d.#.i.a.8.8 g f f a f g 8 8.a.i.i.i.i.i.d.", "i.i.i.i.s.%.+ u.d.i.i.i.i.1 i.f.@.V { 2 v F .> V [ g.i. .i.j.O.y a % r r % a y O.g.i.i.i.i.i.i.", "i.i.p.i.g.%.+ i.i.i.i.i.i.1 u.g.[ D N z S J ) k D ' p.d.X.i.j.~ s i 7 u u 6 i s ~ s.i.i.d.i.i.i.", "i.d.d.i.l.$.+ s.a.i.i.i.i.1 i.g.[ H P L P L J L K ' p.d. .i.j./ y f h d j h f y / g.i.i.i.i.i.d.", "d.i.i.j.} o . @ 2.f.i.i.i.1 u.s.` H I L I P L I P ) p.d.+.i.f.>.e f 4 q 3 5 f e -.k.i.i.d.p.i.i.", "i.i.i.d.0.#.,.%.i.a.i.i.i.1 i.g.{ B A U Z S U Z C ] p.d.X.i.i.s.! w p z i h w ! f.d.i.i.i.i.i.i.", "i.i.i.i.a.l.g.j.i.i.d.d.i.1 u.j.( ( +.x +.+.c +.` l g.i. .i.i.i.y.^ e w t 8 ^ y.d.i.i.i.i.i.i.i.", "i.d.i.i.i.i.i.i.i.i.i.d.i.2 i.d.8.d.p.1.f.d.1.f.p.5.i.a.#.i.i.p.a.g.7.&.&.8.j.i.i.i.i.i.d.d.i.i.", "i.i.i.i.i.i.i.p.i.i.d.i.y.< i.i.a.a.i.a.i.i.f.i.i.f.i.a. .i.d.i.a.d.a.f.k.f.i.p.i.i.i.i.d.i.d.i.", "d.d.i.i.i.i.i.d.i.i.i.i.y.0 i.i.i.i.i.i.i.i.i.d.i.i.i.i.#.i.i.i.i.i.i.i.i.i.d.i.i.i.i.i.i.i.i.i.", "i.i.i.i.d.i.i.i.i.i.i.i.s.q.d.d.d.i.d.i.i.i.i.i.i.i.i.i.y.a.d.d.i.i.i.i.i.p.d.i.i.i.i.i.i.i.i.d.", "d.i.i.d.i.i.i.i.i.i.d.i.d.s.i.i.d.i.p.i.i.p.d.d.i.i.i.i.p.i.d.i.a.i.i.i.i.i.i.i.i.i.d.i.i.i.i.i.", "i.d.i.i.i.i.i.i.i.d.i.d.i.i.i.i.i.i.i.i.i.i.i.d.i.i.d.i.i.i.i.i.i.i.i.a.i.i.i.i.i.i.i.i.d.i.i.i.", "i.i.i.i.i.i.d.i.i.i.i.i.i.i.i.d.i.i.i.i.i.i.d.d.i.a.i.i.i.i.d.i.i.i.i.i.i.d.i.i.i.d.d.i.d.i.d.i." }; const char *const *const xpm_icons[] = { xpm_icon_0, xpm_icon_1, xpm_icon_2, }; const int n_xpm_icons = 3; puzzles-20170606.272beef/icons/twiddle-icon.c0000644000175000017500000004704713115373753017551 0ustar simonsimon/* XPM */ static const char *const xpm_icon_0[] = { /* columns rows colors chars-per-pixel */ "16 16 256 2 ", " c black", ". c #010101", "X c #020202", "o c gray1", "O c #040404", "+ c gray2", "@ c #060606", "# c #070707", "$ c gray3", "% c #090909", "& c gray4", "* c #0B0B0B", "= c #0C0C0C", "- c gray5", "; c #0E0E0E", ": c gray6", "> c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", "XdXyX", "9X5X9Xv.@XtXqX5XiX8X8XqXsXwXaXuX", "7X1XwXW A.gX3X0XeXwXeX0X7X9XwXyX", "8X1XrX&X8XqX5XyXqXaXwXrXrX4XqXiX", "8X,XwXyXeX5XeXrX5XH.4XwXwX1XpXuX", "8X>X7X8X9X9XyXyX+XA .XpX5X2XsXyX", "7X,XqX6X3XrX0X0X9X}.3XqX>X7XpXuX", "8XwXfXsXdXiXuXsXsXlXgXiXtXdXgXyX", "qXtXrXrXrXtXtXrXrXeXrXtXtXrXeXqX" }; /* XPM */ static const char *const xpm_icon_1[] = { /* columns rows colors chars-per-pixel */ "32 32 256 2 ", " c black", ". c #010101", "X c #020202", "o c gray1", "O c #040404", "+ c gray2", "@ c #060606", "# c #070707", "$ c gray3", "% c #090909", "& c gray4", "* c #0B0B0B", "= c #0C0C0C", "- c gray5", "; c #0E0E0E", ": c gray6", "> c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", "XeXrXrXqXbXfXwXrXrXeXwXwXrXrXrXuXgXhXyXwXeXrXrXrXrXqXvXiX9X", "qX0XOX0XqX9XuXcX8XqX0X0XyXpXpX9XqX0X0X9XeX9XzXtX0X9XqXqX8XxXiX9X", "qXqX@X0XwX9XvXiX9XqX0XuXk.~ S.pX9XqXqXeX2XdXhXaXgXyX0X0X8XcXiX9X", "qXqX@XqX9XpXbX9XwXqXqX8XrX9.( kX8XqXqX0X5XvX8X0XrXdXfXuX7XxXiX9X", "qXqX@XqX9XnXiX9XqXqX9XpXH.v [.yX0XqXeX1XdXsX9XwX0X0XrXdXaXnXiX9X", "qXqX@X8XdXmX8XqXqXqX9XaX6.Q v.yX0XqX0X3XvX9XqXqXqXqX0X0XqXmXiX9X", "qXqX@X9XxXeXqXwXqXqXqX0XdXgXyXqXqXrX,XsXdX9XqXqX9X8X0XwX8XxXiX9X", "qXqXOXuXnX4XXvX9XqXqX0XeXU.a L.fX6XcXiX9X", "qX9X:XiX9XwXqX9XeXiXrX2X1X9XwXtX-XaXdX9XqXqX0XwX(.k b.hX6XcXiX9X", "qX0XoX0XqXqXqX0X0X0XeXiXwX2X3X7X:XnX8XqXqX0XrX>X<.} '.iX7XcXiX9X", "qX9X=XqXqX0XwXuX0XqX0X0XrXyXwX&XiXiX0XwXqXqXqXeXwXiXiX0X8XcXiX9X", "0XrX8X9XqXrX9XOXuX0XqXqX0XqXqX=XcX3X1X8XeXqXqXqXqX9X0XwX8XcXiX9X", "qX0XoX0XqXqX| Y c.dX9XqX0XtX*X9XgXdXuX4X2X9XeXqXqXqXqXwX8XvXiX9X", "qXqX@X0XwX6X~ ) R jX8XqXwX8X&XjX8X0XyXdXuX5X3X9XwXqXqXwX7XsXpX9X", "qXqX@X0X0XuXA.h 0.gX8X0XtX*XrXpX9XqX0X0XtXsXyX5X4X0XwXrX-XyXsX9X", "qXqX@X0XqXrXE.F.wXwXqXwX7X=XlX9XqXqXqXqX0X0XtXsXyX6X5X0XOXxXpX9X", "qXqX@X0XqX0XaXfXqXqX0XrX&XuXiX9XqX0X0XrXqXqX0X0XtXaXuX>X;XbXiX9X", "qX0X@XqXqXqX9X8XqXqXwX6X:XzX8XwX0XeXyX;X9XwXqXqX0X0XwX;X9XcXiX9X", "qXqXOX8XeXqXqXqXqX0XrX&XsXiX9XqXwX0X#.+.-XtX0XqXqXrX:X1X0XxXiX9X", "qXqXOX,X2X9XwXqXqXwX5X,XcX8XwX9XsXE.y @._.iX0XqXwX9X&XwX8XcXiX9X", "qX0X@XqX6X c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", "XqXeXqXqXqXqXqXqX0X7X7X7X0XqXqX0XtX%XpXmX7XwXqXqXqX0X7X7X0XqXqXqX0XZXuX0XqXqX", "qXqX0XrX.X>XzXDXaX5X*XX;X6XwXyXoXuXnX7XwXqXqXqXqX9XaX,./ s ] aX9XqX9XZXuX0XqXqX", "qXqXqXrX].X1X+XFXeX0XqXqXqXqXqX0XrX+XB.W.tXwXqXqX9XZXuX0XqXqX", "qXqXqX0X$X7XwXqXqXqX9X7X8XqXqXqXqXqX0X0XyXaXwXoXpXzX8XeXqXqXqXqXqXqX0XuXhXsX0XqXqXqX9XZXuX0XqXqX", "qXqX0XyXfX6XwXqXqX0XaXzXfXqXqXqXqXqXqXqX0XwX9X.XmX3X*X5XwXwXqXqXqXqXqX0X9X9XqXqXqXqX9XZXuX0XqXqX", "qXqX0XrX{.X8XeXwXqXqX0XrXoXxXpX9XqXqX", "qXqX0XrX.X1XeX0XwX8X>.U Z -XtX0XqXqX0XtX|.yXkX8XqXqXqXqXqXqX9XqXaXkXuX1X,X8XeXqXeX4X XAXyX0XqXqX", "qXqX0XrX.X1XeXqXqXeX{.P.7XyX0XqXqXqXeX1XoXVX0XqXqXqXqXqXqXqXqXqX9XqXaXkXuX2XX2X;X3XqXwXqXqXqXqXrX:X*XSX9XqXqXqXqX7XlX0.# } r XXuX0XqXqXqXqXwXOX5XwXqX9XZXuX0XqXqX", "qXqX0XrX.X1XtX8XX#XrX0XqX9XZXuX0XqXqX", "qXqX0XrX.XX5XqXtX;X;XSX9XqXqXqXqXqXqXqXqXo.d +.0XqXqXqXqXqXwX.X5XwXqXqX9XZXuX0XqXqX", "qXqX0XrX.X1XeXqXqXwXeX8XXqX8X9X9X9X9X8X0X9XtX,X%X1X8X9X9X9X9X9X9X9X9X8X9X9X9X9X8XwX$XoXwX8X9X9X9X7XCXuX0XqXqX", "qXqXqX0X+XeXfXsXsXsXsXsXsXsXsXaXsXyX5X8XiXdXsXsXpXsXsXsXsXsXsXsXsXsXsX;XyXdXsXsXsXsXaXSXyX0XqXqX", "qXqX0XtXhXCXAXBXVXVXVXVXVXVXVXVXVXCXCXBXBXBXZXjXVXAXBXVXVXVXVXVXVXVXBXVXVXBXVXVXBXZXkXMXuX0XqXqX", "qXqXqXqX6XqX9X8X8X8X8X8X8X8X8X8X8X8X8X8X8X8X8X6XqX9X8X8X8X8X8X8X8X8X8X8X8X8X8X8X8X8X6XqXwXqXqXqX", "qXqXqXqXwXqXqXwXwXwXwXwXwXwXwXwXwXwXwXwXwXwXwXwXqXqXwXwXwXwXwXwXwXwXwXwXwXwXwXwXwXwXwXqXqXqXqXqX", "qXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqX", "qXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqX" }; const char *const *const xpm_icons[] = { xpm_icon_0, xpm_icon_1, xpm_icon_2, }; const int n_xpm_icons = 3; puzzles-20170606.272beef/icons/tracks-icon.c0000644000175000017500000003767213115373753017407 0ustar simonsimon/* XPM */ static const char *const xpm_icon_0[] = { /* columns rows colors chars-per-pixel */ "16 16 247 2 ", " c #D5D5D5", ". c #D5D5D5", "X c #D5D5D5", "o c LightGray", "O c #CBCBCB", "+ c #D5D5D5", "@ c gray84", "# c gray81", "$ c gray80", "% c gray84", "& c gray84", "* c gray80", "= c #D2D2D2", "- c gray84", "; c #D5D5D5", ": c #D5D5D5", "> c #D5D5D5", ", c #D5D5D5", "< c LightGray", "1 c gray43", "2 c #C5C5C5", "3 c #DFDFDF", "4 c gray71", "5 c #7E7E7E", "6 c #DADADA", "7 c gray87", "8 c #979797", "9 c gray66", "0 c gray87", "q c LightGray", "w c #D5D5D5", "e c #D5D5D5", "r c #D7D7D7", "t c LightGray", "y c gray62", "u c #D0D0D0", "i c gray87", "p c #BBBBBB", "a c #A2A2A2", "s c gainsboro", "d c gray86", "f c #AEAEAE", "g c gray69", "h c gainsboro", "j c gray83", "k c #D5D5D5", "l c gray84", "z c gray82", "x c #CBCBCB", "c c #D3D3D4", "v c #CECECE", "b c #CDCDCD", "n c #D0D0CF", "m c #D2D2D2", "M c #CACACB", "N c gray82", "B c #D8D8D8", "V c #D8D8D8", "C c #D2D2D2", "Z c gray83", "A c #D8D8D8", "S c #C6C6C6", "D c #A5A5A3", "F c #A8A7A6", "G c #9A978E", "H c #9B9993", "J c #9E9C95", "K c #A8A8A7", "L c #A9A9A8", "P c #CDCDCD", "I c gray82", "U c #D0D0D0", "Y c gray82", "T c gray83", "R c gray83", "E c #D8D8D7", "W c #C7C7C8", "Q c #A7A6A4", "! c #918D82", "~ c #918D81", "^ c #938E7F", "/ c #8F8B80", "( c #99958B", ") c #ADADAE", "_ c gray81", "` c gray77", "' c gray77", "] c gray83", "[ c gray83", "{ c gray83", "} c #D7D8D8", "| c #C8C8C6", " . c #97948C", ".. c #918D7F", "X. c #8D856D", "o. c #877D5F", "O. c #918A76", "+. c #8F8C82", "@. c #A6A49E", "#. c #D2D3D5", "$. c #D2D2D3", "%. c #D1D2D3", "&. c #D4D5D6", "*. c gray83", "=. c gray83", "-. c #D7D7D8", ";. c #C9C8C7", ":. c #969287", ">. c #928C7B", ",. c #938C77", "<. c #A7A18D", "1. c #8F8A79", "2. c #918B7A", "3. c #98917D", "4. c #BEBDB7", "5. c #C0BFBB", "6. c #BFBDB9", "7. c #C2C1BE", "8. c #D5D5D6", "9. c gray83", "0. c #D8D8D8", "q. c #C7C6C4", "w. c #928D7D", "e. c #908A79", "r. c #989488", "t. c #B0AFAD", "y. c #95928B", "u. c #918B7A", "i. c #8C846C", "p. c #908977", "a. c #908B7C", "s. c #8C8676", "d. c #9D998D", "f. c #D6D7D8", "g. c #D5D5D5", "h. c gray83", "j. c #D8D8D8", "k. c #C7C6C3", "l. c #928D7F", "z. c #908A79", "x. c #969182", "c. c gray69", "v. c #A4A29C", "b. c #908C82", "n. c #928D80", "m. c #928D7D", "M. c #918B7A", "N. c #8E8876", "B. c #9D998C", "V. c #D6D6D8", "C. c #D5D5D5", "Z. c gray83", "A. c #D7D7D7", "S. c #CACAC9", "D. c #969181", "F. c #908B7A", "G. c #999588", "H. c #ADADAB", "J. c #A9A9A8", "K. c #A7A6A4", "L. c #9C9991", "P. c #9C988E", "I. c #999588", "U. c #969285", "Y. c #A5A298", "T. c #D6D6D8", "R. c #D5D5D5", "E. c gray85", "W. c #DCDDE0", "Q. c #BAB5A8", "!. c #574F35", "~. c #6B6657", "^. c #777369", "/. c #C8C8C8", "(. c #CBCBCB", "). c gray80", "_. c gray80", "`. c #CBCBCB", "'. c #CECECE", "]. c #CDCDCD", "[. c #CDCDCD", "{. c #D5D5D5", "}. c gainsboro", "|. c #6C6C6C", " X c #BDBEC0", ".X c #A6A299", "XX c #5A533E", "oX c #4B483C", "OX c #908E89", "+X c #CBCBCB", "@X c gray82", "#X c #C8C8C8", "$X c LightGray", "%X c #D5D5D5", "&X c #CBCACA", "*X c #CCCCCB", "=X c gray83", "-X c gray83", ";X c gray82", ":X c gray48", ">X c #B6B7B8", ",X c #ADACA7", " , < 1 2 3 4 5 6 7 8 9 0 q ", " w e r t y u i p a s d f g h j ", " k l z x c v b n m M N B V C . ", " Z A S D F G H J K L P I U Y T ", " R E W Q ! ~ ^ / ( ) _ ` ' ] [ ", " { } | ...X.o.O.+.@.#.$.%.&.*.", " =.-.;.:.>.,.<.1.2.3.4.5.6.7.8.", " 9.0.q.w.e.r.t.y.u.i.p.a.s.d.f.", "g.h.j.k.l.z.x.c.v.b.n.m.M.N.B.V.", "C.Z.A.S.D.F.G.H.J.K.L.P.I.U.Y.T.", "R.E.W.Q.!.~.^./.(.)._.`.'.].[.{.", "}.|. X.XXXoXOX+X@X#X$X%X&X*X=X-X", ";X:X>X,X c #3E3F42", ", c #444444", "< c #4B4B4C", "1 c #525252", "2 c #545559", "3 c #5C5C5C", "4 c #796C47", "5 c gray39", "6 c #6C6C6C", "7 c #7B7460", "8 c #74726C", "9 c #7D796D", "0 c #717171", "q c #7E7C75", "w c #7D7C79", "e c #8B773C", "r c #877748", "t c #86784D", "y c #827551", "u c #8A7E5B", "i c #887F65", "p c #847E6E", "a c #817E74", "s c #8E825E", "d c #958557", "f c #95865B", "g c #8E8260", "h c #87816F", "j c #8C846C", "k c #928665", "l c #968A64", "z c #9B8D64", "x c #90866B", "c c #968B6C", "v c #998E6C", "b c #9E916C", "n c #858175", "m c #8B8574", "M c #85827A", "N c #89857B", "B c #8C897E", "V c #928A72", "C c #938D7A", "Z c #9D9273", "A c #9E957C", "S c #A0936A", "D c #A89768", "F c #A0977A", "G c #A49A7E", "H c #858481", "J c #898782", "K c #8A8984", "L c #858689", "P c #87888A", "I c #8C8C8A", "U c #949085", "Y c #9A9484", "T c #9F9885", "R c #96938B", "E c #98958D", "W c #9E998C", "Q c #8B8C90", "! c #8A8D98", "~ c #8E9096", "^ c #8E9199", "/ c #939393", "( c #999792", ") c #9D9A92", "_ c #95979E", "` c #9C9C9B", "' c #A29A84", "] c #A29C8A", "[ c #A29E92", "{ c #A5A194", "} c #AAA495", "| c #A6A39A", " . c #A9A69C", ".. c #9295A0", "X. c #9D9EA0", "o. c #A6A6A5", "O. c #A8A7A2", "+. c #ACAAA4", "@. c #A7A8AB", "#. c #ABABAB", "$. c #B9B6AF", "%. c #ADAEB1", "&. c #AFB0B3", "*. c #B4B4B4", "=. c #B8B7B5", "-. c #B8B8B7", ";. c #B3B4B9", ":. c #BBBBBB", ">. c #BBBCC0", ",. c #BFC0C3", "<. c #C2C3C3", "1. c #C3C5C8", "2. c #CDCDCD", "3. c #D5D5D5", "4. c #D8D7D7", "5. c #D8D8D7", "6. c #D7D7D8", "7. c #D7D8DB", "8. c #DADADA", "9. c #E0E0DF", "0. c #E3E3E3", "q. c gray91", /* pixels */ "3.3.6.3.3.3.3.5.3.3.8.6.3.3.3.3.3.6.8.4.3.3.3.3.3.6.6.3.3.3.3.6.", "3.3.3.3.3.3.3.3.3.3.>.2.6.3.3.3.6.1.<.8.3.3.3.3.3.<.2.3.3.3.3.3.", "3.3.3.3.3.3.3.3.6.3.6 < 6.3.3.3.6.o., ( 0.3.3.3.3., / 0.3.3.3.3.", "3.3.3.3.6.3.3.3.3.9.[ = 3.3.3.3.3.6.5 #.8.3.3.3.q.M I q.3.3.3.3.", "3.3.3.3.3.3.3.3.5.2.6 1 2.3.3.3.0.0 $ :.6.3.3.3.5.< 3 8.3.3.3.3.", "3.5.3.3.3.3.3.3.4.3.:.3.4.3.3.3.3.2.<.2.3.3.3.3.3.1.1.3.3.3.3.3.", "3.3.3.3.3.3.3.6.5.5.8.5.3.6.5.5.3.6.8.8.5.5.3.3.3.8.6.6.3.6.3.3.", "3.3.3.3.3.3.3.2.<.<.<.<.1.1.<.1.1.<.<.<.<.<.2.3.3.2.2.2.3.2.3.3.", "3.3.3.3.3.3.6.-.o.o.o.#.[ ] ;. .T #.o.o.o.o.2.6.3.3.3.5.3.2.3.3.", "3.5.3.3.3.3.6.:.o.#.#.%.Y h _ B m *.#.#.#.#.2.3.<.5.3.<.3.3.3.3.", "3.3.3.3.3.3.3.-.#. .l / L h ` m M ^ c ' %.o.2.3.1.<.:.2.3.2.3.3.", "3.3.6.3.3.3.6.-.@.#.J 7 O.f { f .n 9 o.%.#.2.3.8.$.:.5.3.3.3.3.", "3.3.3.3.3.3.3.:.| ` ! ' f L a H m b ../ .#.2.3.:.2.2.:.3.2.3.3.", "5.3.3.6.5.3.3.:.v p j A H y e r a Y k a v O.2.3.3.6.3.3.3.3.3.3.", "3.3.3.3.3.3.6.:.;.I ) C n d +.z i m { K | #.2.3.3.3.3.3.3.2.3.3.", "3.3.3.3.3.3.5.:.v M V C n A ;.*.( I b a t z #.O.+.O. .#.} :.3.3.", "3.3.3.3.3.3.6.-.[ J W R K { *.{ g a ] U 9 u c Y V Y k ) u #.6.4.", "3.3.3.3.3.3.6.-.c M l j n Z &.#.#.^ / d R a H M M J M K a ` 4.3.", "3.6.3.3.3.3.6.-.[ J ) E K | #.#.#.W 7 / A F ' A Z ] z } f -.6.3.", "3.3.3.3.3.3.6.-.l n f j n Z *.#.%.A ] ! a K B J N K n I a [ 4.3.", "3.3.3.5.3.3.5.-.| J ) ( K .&.#.#.%.%.#.f X.C C V U j E i +.6.3.", "3.3.3.3.3.3.5.-.l J k j n v *.o.o.o.o.o.[ %.} [ ] | ] O.Y =.5.3.", "3.3.3.3.3.3.6.=.z * Y w 2 :.*.1.<.<.<.<.1.<.<.1.1.1.<.<.1.<.4.3.", "3.3.3.0.3.3.7.D ; X S % @ { -.6.6.6.3.8.4.3.3.3.4.4.5.5.3.3.3.3.", "3.6.:.1 2.3.8.- 4 O.o 9 } -.3.2.2.8.1.1.3.2.3.<.3.3.<.3.3.3.3.", "3.0.P O o.9.7.j Z } . , ;.@.*.6.3.<.:.<.3.3.3.3.2.:.,.2.3.2.3.3.", "3.6.< = 3 9.7.U : # & l #.o.-.3.3.2.#.2.5.3.3.3.3.-.-.6.3.2.3.3.", "3.2.#.3.#.3.8.< + 8 -. .#.@.-.3.2.:.8.:.2.3.2.3.:.3.2.:.5.2.3.3.", "3.3.8.6.8.3.6.,.G +.#.+.#.o.$.8.3.3.3.3.3.3.2.3.3.3.3.2.4.2.3.3.", "3.5.3.3.3.3.6.:.#.%.&.&.&.#.-.2.2.3.2.3.3.2.2.3.2.3.3.3.3.2.3.3.", "3.3.3.3.3.3.3.3.3.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.3.3.3.3.3.3.3.3.3.3.3.3.3.3.3.3.3.3.3.3.3.3.3.3.4.3.3.3.3.3." }; /* XPM */ static const char *const xpm_icon_2[] = { /* columns rows colors chars-per-pixel */ "48 48 150 2 ", " c #020201", ". c #0C0A05", "X c #0A0A0C", "o c #110B00", "O c #1D1C17", "+ c #1D1C1B", "@ c #221E14", "# c #26231C", "$ c #373019", "% c #252525", "& c #2B2B2C", "* c #2D2E32", "= c #343434", "- c #3A3A3A", "; c #4F4423", ": c #5F532F", "> c #454135", ", c #715E26", "< c #695B33", "1 c #796938", "2 c #414141", "3 c gray29", "4 c #545453", "5 c #5B5B5B", "6 c #636364", "7 c #6D6D6D", "8 c #7D7766", "9 c #78746A", "0 c #7E796B", "q c #6F7177", "w c #757575", "e c #7D7C77", "r c #7E7E7D", "t c #866D24", "y c #866F29", "u c #87702C", "i c #89722D", "p c #91782F", "a c #8A7535", "s c #86733D", "d c #8B7639", "f c #8E793C", "g c #867645", "h c #887745", "j c #8D7A44", "k c #83764F", "l c #87784E", "z c #8A7A4C", "x c #947F42", "c c #917F49", "v c #857956", "b c #837A5F", "n c #8A7E59", "m c #8A7C53", "M c #837C66", "N c #847E6B", "B c #827E73", "V c #807F7C", "C c #99823D", "Z c #94814B", "A c #8F8051", "S c #8D815B", "D c #928253", "F c #9B8954", "G c #94865B", "H c #8D8363", "J c #8B836C", "K c #928660", "L c #978963", "P c #9A8C65", "I c #93896B", "U c #998E6D", "Y c #9C916E", "T c #858174", "R c #8D8774", "E c #84827C", "W c #888479", "Q c #918A75", "! c #948E79", "~ c #9D9377", "^ c #9C947B", "/ c #A39569", "( c #A0967A", ") c #7E7F81", "_ c #7F8082", "` c #828282", "' c #888783", "] c #8A8885", "[ c #84858A", "{ c #86888D", "} c #8C8C8C", "| c #908D85", " . c #9C9683", ".. c #9E9885", "X. c #9A968B", "o. c #9E998A", "O. c #868991", "+. c #8C8D91", "@. c #8F9093", "#. c #939494", "$. c #989796", "%. c #9E9B94", "&. c #9C9B9A", "*. c #A09984", "=. c #A49E8C", "-. c #A29E93", ";. c #A09E99", ":. c #AFA587", ">. c #A8A28F", ",. c #A6A194", "<. c #A9A390", "1. c #A5A39C", "2. c #A9A69C", "3. c #ACA89A", "4. c #9C9EA3", "5. c #A5A5A4", "6. c #A9A7A5", "7. c #AAA8A4", "8. c #A5A6AA", "9. c #A6A8AC", "0. c #AAAAAA", "q. c #B0AFAE", "w. c #B0B0AF", "e. c #A7AAB3", "r. c #ACAEB2", "t. c #AFB1B4", "y. c #B2B2B2", "u. c #B8B7B3", "i. c #B3B5BC", "p. c #B7B8BB", "a. c #BBBBBB", "s. c #C0BEB7", "d. c #B2B5C0", "f. c #B5B9C5", "g. c #B9BBC1", "h. c #B6BBC8", "j. c #BEC2CC", "k. c #C3C3C4", "l. c #C8C8C7", "z. c #C3C5C9", "x. c #C6C8CF", "c. c #CDCDCD", "v. c #D5D5D5", "b. c #D8D7D7", "n. c #D8D8D7", "m. c #D5D7DC", "M. c #DADADA", "N. c #DCDEE3", "B. c #E2E2E2", "V. c #EAEAEA", /* pixels */ "v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.", "v.v.v.v.v.v.b.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.", "v.v.v.v.v.v.v.v.v.v.v.n.v.v.v.M.N.v.v.v.v.v.v.v.v.v.M.M.v.v.v.v.v.v.v.v.v.M.M.v.v.v.v.v.v.v.v.v.", "v.v.v.v.v.v.v.v.v.v.v.v.v.v.n.l.0.c.n.v.v.v.v.v.v.v.k.y.M.M.v.v.v.v.v.v.v.a.k.v.v.n.v.v.v.v.v.v.", "v.v.v.b.v.v.v.v.v.v.v.v.v.v.M.} 3 & k.M.v.v.v.v.v.c.4 * 5 M.n.v.v.v.v.v.k.& - B.v.v.v.v.v.v.v.v.", "v.v.v.v.b.v.v.v.v.v.v.v.v.n.n.c.r % l.M.v.v.v.v.v.c.V.} & N.v.v.v.v.v.v.B.#.= B.v.v.v.v.v.v.v.v.", "v.v.v.v.v.v.v.v.v.v.v.v.v.v.n.v.V + u.M.v.v.v.v.v.M.0.- a.M.v.v.v.v.v.v.V.1.- V.v.v.v.v.v.v.v.v.", "v.v.v.v.v.v.b.v.v.v.v.v.v.v.N.w 5 % p.M.v.v.v.v.v.v.+ # w v.v.v.v.v.v.v.x.2 X } M.v.v.v.v.v.v.v.", "b.v.v.v.v.v.v.v.v.v.v.v.v.v.M.a.$.z.M.v.v.v.v.v.v.v.w.5.6.n.v.v.v.v.v.v.c.5.5.y.M.v.v.v.v.v.v.b.", "v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.M.B.n.v.v.v.v.v.v.v.v.M.N.N.v.v.v.v.v.v.v.v.B.B.M.v.v.v.v.v.v.v.v.", "v.v.v.v.v.v.v.v.v.v.v.n.v.v.v.v.v.v.v.n.n.v.n.n.v.v.v.v.n.n.n.v.v.v.v.v.v.v.v.v.v.v.b.v.v.v.v.v.", "v.v.v.b.v.v.v.m.v.v.v.v.c.c.v.c.c.c.v.c.c.c.c.c.c.c.v.c.c.c.c.c.v.c.c.c.c.v.c.c.v.c.c.v.v.v.v.v.", "v.v.v.v.v.v.v.v.v.v.n.k.7.0.0.0.0.0.0.t.0.0.y.0.t.0.0.0.0.0.0.0.y.v.v.v.v.c.v.c.c.v.c.c.v.n.v.v.", "v.v.v.v.b.v.v.v.v.v.n.j.6.0.0.6.0.0.0.P ,.y.u.1.L 0.0.0.0.0.0.0.0.v.v.v.n.v.b.v.M.b.v.c.v.v.v.v.", "b.v.v.v.v.v.v.v.v.v.v.k.6.0.0.t.0.0.t.S J 4.4.Q z t.0.0.t.0.0.7.t.v.n.l.c.n.v.b.k.v.b.c.v.v.v.v.", "v.v.v.v.v.v.v.v.v.v.n.k.8.0.0...1.0.#.` _ E ` _ ` } 6.7.^ 0.0.0.t.v.n.c.y.c.M.a.a.n.v.c.v.v.v.v.", "v.v.v.v.v.v.v.v.v.v.v.k.7.0.r.G z O._ | z 6.0.z | ` O.v D r.0.6.y.v.v.v.c.u.u.g.M.v.v.c.v.v.b.v.", "v.b.v.v.v.b.v.v.v.v.n.k.6.0.0.5.r 8 1.i.d *.3.a t.5.0 e 5.0.6.0.w.v.v.v.M.a.5.v.b.v.v.c.v.v.v.v.", "v.v.v.v.v.v.v.v.v.v.n.k.0.r.r.} { K d 5.T E E J 5.f D { ] 0.t.8.w.v.v.v.a.k.v.y.c.b.v.c.v.v.v.v.", "v.v.v.v.v.v.v.v.v.v.b.k.5.~ X.) 4.d.S 8 _ T T _ 0 S i.8._ X.~ 5.r.v.M.k.a.M.v.c.u.v.v.c.v.v.v.v.", "v.v.v.v.v.b.v.v.v.v.v.k.5.D b V D ~ } _ z i u j E { ^ A V M A 1.y.v.v.v.v.v.v.v.v.v.v.c.v.v.v.v.", "v.v.v.v.v.v.v.v.v.v.v.j.5.t.} ' U j r v t ..,.y v _ h P ' ] d.0.q.v.v.M.n.n.M.v.b.b.v.v.v.v.v.v.", "v.v.v.n.v.v.v.v.v.v.v.k.w.p.{ #.j.r._ =.<.i.p.>.*._ e.j.#.E L =.g.k.z.k.k.k.k.z.k.k.k.l.v.v.v.v.", "v.v.v.v.v.v.v.v.v.v.n.k.*.f T N d z _ z P t.w.t.0._ R j g _ g i ,.1.=.0.o.5.5...9.;.o.g.n.v.v.v.", "v.v.v.v.v.v.v.v.v.v.v.k.1.=.' ] =.X.) .,.r.y...a B T ~ ;.{ E s P Y D f.d =.2.i i.L D x.v.v.v.v.", "v.v.v.v.v.v.v.v.v.v.M.k.5.6.{ } 7.&.) ;.7.0.y.1.,.#._ e.,.s _ _ ' E T } T ' ] B } W e 4.M.v.v.v.", "v.v.v.v.v.v.v.n.v.v.v.z. .i B M i h ` s D r.0.0.t.6.[ ] d ~ 8.k @.R T @.M ' ] N @.W B 5.n.v.v.v.", "v.v.n.v.v.v.v.v.v.v.M.k.7.t.] +.i.5.) 8.y.0.y.0.6.t.X.9 E e.=.a g.P D f.d >.3.i i.P Z x.b.v.v.v.", "v.v.b.v.v.v.v.v.v.v.v.k.-.U E W P I _ I ^ r.w.7.0.5.d ! ] _ T J r.I H e.z o.%.h 9.I S g.n.v.v.v.", "v.v.v.v.v.v.v.v.v.v.v.k.o.Z E T D G ) S U t.y.0.0.0.,.0.8.#.E _ r _ _ _ _ _ _ _ _ ` r #.M.v.v.v.", "v.v.v.v.v.v.v.n.v.v.v.k.0.f.{ #.h.e.r e.t.0.t.7.0.0.r.0.0.7.a %.r.I S e.g X.%.s 9.I n g.v.v.v.v.", "v.v.v.v.v.v.v.v.v.v.b.z.o.d T N d l ` h G r.w.0.0.0.0.0.0.1.~ 0.p.( I i.G ,.7.D t.~ I j.v.v.v.v.", "v.v.v.v.v.v.v.v.v.v.n.k.1.*.E ' >. .e | >.0.w.7.0.0.0.0.0.0.r.0.0.r.0.0.0.0.0.0.0.0.0.a.M.v.v.v.", "n.v.v.v.v.v.v.v.v.v.v.x.~ c O > s.} 4.g.y.k.c.l.l.x.l.l.x.l.l.l.l.l.l.l.l.l.x.x.l.l.l.v.v.v.v.", "v.v.v.v.v.M.M.v.v.v.M.:.p < : C ; J 7.7.x.M.n.M.n.n.b.n.n.n.c.v.M.M.v.n.n.v.M.n.n.c.v.v.v.v.", "v.v.v.v.n.k.l.n.v.v.N.Y ; O 5.y.# + j ^ r.l.n.v.c.b.v.b.v.c.b.c.v.v.c.v.v.v.b.c.v.b.c.v.v.v.v.", "b.v.v.v.M.% * M.v.v.B.4 * s / ` 6 a.6.0.l.M.c.y.c.M.v.u.c.m.v.c.n.x.u.v.n.l.p.v.v.c.v.v.v.v.", "v.v.v.B.5.= = 0.M.v.M.$., 2.u.1 & 0.0.0.0.c.v.n.c.y.c.u.x.b.v.c.v.v.n.k.a.c.y.v.b.v.c.v.v.b.v.", "v.v.v.B.6 = * 7 B.v.b.m.F Q w X . v t.0.0.8.c.v.v.M.c.&.k.M.v.b.c.v.v.v.M.p.&.b.b.v.v.c.v.v.v.v.", "v.v.v.v.& 5 4 = v.v.M.` # . = X.Z ,.0.7.0.x.n.v.v.u.k.u.c.b.b.c.v.v.n.l.a.k.p.v.v.v.c.v.v.v.v.", "v.v.v.v.0.B.B.y.v.v.B.5 . $ V w.t.0.0.0.0.8.l.n.v.y.x.M.c.y.c.b.c.c.M.l.y.v.M.k.p.b.v.c.b.v.v.v.", "v.v.v.v.M.v.v.M.v.v.v.k.0.Z 3.0.6.0.0.0.0.0.c.n.c.c.M.v.M.c.c.b.v.v.M.x.v.v.v.n.l.v.v.c.v.v.v.v.", "v.v.v.b.v.v.v.v.v.v.v.k.5.1.5.0.7.0.0.8.7.6.c.M.n.n.b.v.n.n.n.b.c.v.n.n.b.v.v.n.n.n.n.c.v.v.v.v.", "v.v.v.v.v.v.v.v.v.v.v.k.0.y.y.y.t.w.w.t.t.w.l.c.c.c.c.c.v.c.c.v.c.l.c.v.c.c.c.c.c.c.c.c.v.v.v.v.", "v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.c.v.v.v.v.v.c.v.v.c.v.v.c.v.c.v.v.c.v.v.c.v.v.c.v.v.v.v.v.v.v.", "v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.b.b.n.v.v.v.v.b.v.v.v.v.v.v.v.b.v.v.v.v.v.b.n.v.v.v.", "v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.b.v.v.v.v.v.b.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.", "v.b.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.v.n.v.v.v.v.v." }; const char *const *const xpm_icons[] = { xpm_icon_0, xpm_icon_1, xpm_icon_2, }; const int n_xpm_icons = 3; puzzles-20170606.272beef/icons/towers-icon.c0000644000175000017500000004444713115373753017441 0ustar simonsimon/* XPM */ static const char *const xpm_icon_0[] = { /* columns rows colors chars-per-pixel */ "16 16 245 2 ", " c #E6E6E6", ". c #E6E6E6", "X c #E6E6E6", "o c gray91", "O c #EAEAEA", "+ c #E6E6E6", "@ c #E6E6E6", "# c #E6E6E6", "$ c #EAEAEA", "% c #E9E9E9", "& c #E6E6E6", "* c #E6E6E6", "= c #E6E6E6", "- c gray91", "; c gainsboro", ": c #D7D7D7", "> c #E7E7E7", ", c #E6E6E6", "< c #E6E6E6", "1 c #E6E6E6", "2 c gray91", "3 c #D7D7D7", "4 c #DADADA", "5 c gray91", "6 c #E6E6E6", "7 c #E6E6E6", "8 c #E4E4E4", "9 c #ECECEC", "0 c #C6C6C6", "q c #767676", "w c #EFEFEF", "e c gray89", "r c gray90", "t c gray94", "y c #AEAEAE", "u c #5D5D5D", "i c gray92", "p c gray90", "a c #E6E6E6", "s c #E6E6E6", "d c gray92", "f c #EFEFEF", "g c #CECECE", "h c gray38", "j c gray89", "k c #EAEAEA", "l c gray91", "z c gray91", "x c gray93", "c c #AEAEAE", "v c DimGray", "b c gray91", "n c #E7E7E7", "m c #E6E6E6", "M c #E6E6E6", "N c #E7E7E7", "B c gray76", "V c gray76", "C c #C0C0C0", "Z c #B1B2B1", "A c #C0C2C0", "S c gray78", "D c gray77", "F c #C6C6C6", "G c gray91", "H c gray84", "J c #DDDDDD", "K c #E6E6E6", "L c #E4E4E4", "P c #E6E6E6", "I c #E7E7E7", "U c gray91", "Y c #9F9F9F", "T c #DADADA", "R c #E6E7E6", "E c #E9E8E9", "W c #F0E8F0", "Q c #E2E2E2", "! c #E7E6E7", "~ c gray72", "^ c #C1C1C1", "/ c gray79", "( c #C4C6C4", ") c gray77", "_ c gray78", "` c gray", "' c gray86", "] c gray92", "[ c gray68", "{ c #DDDDDD", "} c #EDEAED", "| c #DFE3DF", " . c #A9CEA9", ".. c #E8E7E8", "X. c gray91", "o. c gray78", "O. c gray90", "+. c #ECE9EC", "@. c #F5EDF5", "#. c #ECE9EC", "$. c #EBECEB", "%. c gray82", "&. c gray83", "*. c #EAEAEA", "=. c #A9AAA9", "-. c #DBDCDB", ";. c #F0EBF0", ":. c #87C087", ">. c #3FA03F", ",. c gray90", "<. c gray91", "1. c #C4C5C4", "2. c #EAE6EA", "3. c #C5D9C5", "4. c #80BD80", "5. c #C9DAC9", "6. c #F0EDF0", "7. c #CFD0CF", "8. c gray83", "9. c #EAEAEA", "0. c #AAAAAA", "q. c #DEDDDE", "w. c #E5E7E5", "e. c #71B771", "r. c #349E34", "t. c #CDDCCD", "y. c #EDEAED", "u. c #C4C5C4", "i. c #E4E4E4", "p. c #E5E6E5", "a. c #69B469", "s. c #9DC89D", "d. c #F9F0F9", "f. c #CDCFCD", "g. c gray83", "h. c #EAEAEA", "j. c #A9A9A9", "k. c gainsboro", "l. c #E9E8E9", "z. c #EBE8EB", "x. c #C9DAC9", "c. c #E4E5E4", "v. c #E8E7E8", "b. c #C3C5C3", "n. c #EEE8EE", "m. c #B0D1B0", "M. c #38A038", "N. c #C6D8C6", "B. c #F0EDF0", "V. c #CECFCE", "C. c gray92", "Z. c #AEAEAE", "A. c gray87", "S. c #EAEAEA", "D. c #E6E7E6", "F. c #EEEAEE", "G. c #E7E7E7", "H. c #E9E9E9", "J. c #C8C8C8", "K. c #E8E7E8", "L. c #DAE2DA", "P. c #C5DAC5", "I. c #D8E1D8", "U. c #EFEDEF", "Y. c gray82", "T. c gray83", "R. c gray56", "E. c #A4A4A4", "W. c gray68", "Q. c #AAABAA", "!. c #A9AAA9", "~. c #ACACAC", "^. c #A7A7A7", "/. c #AAAAAA", "(. c #E4E4E4", "). c #E3E1E3", "_. c #E9E4E9", "`. c #E3E1E3", "'. c gray90", "]. c #CDCDCD", "[. c gray83", "{. c #D8D8D8", "}. c gray64", "|. c #E1E1E1", " X c gray86", ".X c #E0DEE0", "XX c #DEDDDE", "oX c #DDDEDD", "OX c #D7D7D7", "+X c #AAAAAA", "@X c #BBBBBB", "#X c #B9B9B9", "$X c #B8B9B8", "%X c #B9B9B9", "&X c #BBBBBB", "*X c #AAAAAA", "=X c gray86", "-X c #E4E4E4", ";X c gray79", ":X c #E9E9E9", ">X c #E9E8E9", ",X c #D8E2D8", " , < 1 2 3 4 5 6 ", "7 8 9 0 q w e r e t y u i p a ", "s d f g h j k l z x c v b n m M ", "N B V C Z A S D F G H J K L P I ", "U Y T R E W Q ! ~ ^ / ( ) _ ` ' ", "] [ { } | ...X.o.O.+.@.#.$.%.&.", "*.=.-.;.:.>.,.<.1.2.3.4.5.6.7.8.", "9.0.q.w.e.r.t.y.u.i.p.a.s.d.f.g.", "h.j.k.l.z.x.c.v.b.n.m.M.N.B.V.g.", "C.Z.A.S.D.F.G.H.J.K.L.P.I.U.Y.T.", "b R.E.W.Q.!.~.^./.(.)._.`.'.].[.", "{.}.|. X.XXXoXOX+X@X#X$X%X&X*X=X", "-X;X:X>X,X c #777777", ", c gray47", "< c gray49", "1 c #7E7E7E", "2 c gray50", "3 c #008400", "4 c #038903", "5 c #129112", "6 c #169316", "7 c #199419", "8 c #1B941B", "9 c #1E911E", "0 c #219721", "q c #2A9B2A", "w c #2E982E", "e c #2E9D2E", "r c #309730", "t c #379E37", "y c #389C38", "u c #41A241", "i c #43A543", "p c #4AA84A", "a c #4EA94E", "s c #51A751", "d c #5BAE5B", "f c #63B263", "g c #6BB56B", "h c #71B771", "j c #7FBD7F", "k c gray51", "l c #838383", "z c #848484", "x c #868686", "c c #8B8B8B", "v c #909090", "b c gray57", "n c #929292", "m c #939393", "M c gray58", "N c #959595", "B c gray59", "V c #979797", "C c #989898", "Z c gray60", "A c #9A9A9A", "S c #9B9B9B", "D c #9D9D9D", "F c #81BE81", "G c #84BF84", "H c #A0A0A0", "J c gray64", "K c #A4A4A4", "L c gray65", "P c gray66", "I c #A9A9A9", "U c #AAAAAA", "Y c gray67", "T c #AEAEAE", "R c #AFAFAF", "E c gray69", "W c #B1B1B1", "Q c #B2B2B2", "! c gray70", "~ c #B4B4B4", "^ c gray71", "/ c #B6B6B6", "( c #B7B7B7", ") c #B9B9B9", "_ c gray73", "` c #BBBBBB", "' c #BCBCBC", "] c gray74", "[ c gray", "{ c #8EC38E", "} c #97C697", "| c #97C797", " . c #A0CAA0", ".. c #AACEAA", "X. c #AFD0AF", "o. c #B2D1B2", "O. c #B5D2B5", "+. c #B8D3B8", "@. c #B9D4B9", "#. c #BAD5BA", "$. c #C1C1C1", "%. c gray76", "&. c gray77", "*. c #C5C5C5", "=. c #C6C6C6", "-. c gray78", ";. c #C8C8C8", ":. c gray79", ">. c #CACACA", ",. c #CBCBCB", "<. c #CDCDCD", "1. c #CECECE", "2. c gray81", "3. c #C5D9C5", "4. c #C7D9C7", "5. c #C7DAC7", "6. c #CADBCA", "7. c #CCDCCC", "8. c #CEDCCE", "9. c #CEDDCE", "0. c #D0D0D0", "q. c gray82", "w. c #D2D2D2", "e. c #D5D5D5", "r. c #D7D7D7", "t. c #D3DED3", "y. c #D5DFD5", "u. c gray85", "i. c gray86", "p. c #DDDDDD", "a. c gray87", "s. c #D6E0D6", "d. c #D7E0D7", "f. c #DEE3DE", "g. c gray88", "h. c #E1E1E1", "j. c #E1E3E1", "k. c #E2E2E2", "l. c #E2E3E2", "z. c gray89", "x. c #E0E4E0", "c. c #E1E4E1", "v. c #E3E4E3", "b. c #E3E5E3", "n. c #E4E4E4", "m. c #E4E5E4", "M. c gray90", "N. c #E5E6E5", "B. c #E6E6E6", "V. c #E6E7E6", "C. c #E7E6E7", "Z. c #E7E7E7", "A. c #E8E7E8", "S. c #E9E7E9", "D. c #EAE7EA", "F. c gray91", "G. c #E9E9E9", "H. c #EAE8EA", "J. c #EBE8EB", "K. c #EAEAEA", "L. c gray92", "P. c #ECE8EC", "I. c #EDE9ED", "U. c #EEE9EE", "Y. c #EFE9EF", "T. c #EEEAEE", "R. c #EFEAEF", "E. c #ECECEC", "W. c #ECEDEC", "Q. c gray93", "!. c #EEEEEE", "~. c #EFEFEF", "^. c #EFF0EF", "/. c #F0EAF0", "(. c #F0EBF0", "). c #F1EAF1", "_. c #F3EBF3", "`. c #F2ECF2", "'. c #F3ECF3", "]. c #F4EBF4", "[. c #F5ECF5", "{. c #F6EDF6", "}. c gray94", "|. c #F1F1F1", " X c gray95", ".X c #F3F3F3", "XX c #F4F4F4", "oX c gray96", "OX c #F6F6F6", "+X c gray97", "@X c #FEF0FE", "#X c #FFF1FF", "$X c #F8F8F8", "%X c #F9F9F9", /* pixels */ "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.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.B.z.B.B.B.B.B.B.B.B.B.B.", "B.B.B.B.B.B.B.G.G.B.B.B.B.B.B.B.B.B.B.B.B.~.G.z.B.B.B.B.B.B.B.B.", "B.B.B.B.B.B.G.i.2.z.B.B.B.B.B.B.B.B.B.B.B.:.2.~.B.B.B.B.B.B.B.B.", "B.B.B.B.B.z.~.M L Xz.B.B.B.B.B.B.B.G.q.= o 2 Xz.B.B.B.B.B.B.", "B.B.B.B.B.B.z.XX# M XXB.B.B.B.B.B.B.B.B.~.P . z XXz.B.B.B.B.B.B.", "B.B.B.B.B.B.z. X+ m XXz.B.B.B.z.B.B.B.B.a.q.& $ XXB.B.B.B.B.B.B.", "B.B.B.B.~.G.XXM X @ q. XG.G.~.G.G.G.z.~._ $ + c Xz.B.B.B.B.B.B.", "B.B. Xz.2.q.q.-.-.$.2.q.2.2.q.q.q.z.v.z.N.r.a.~.z.z.z.z.B.B.B.B.", "B.z.$.: T T T Q Q Q Q T Q T T Q C ] %X~.^. X`.~.~. X X~.~.~.B.B.", "B.G.C : XX X~.^.~.~.~.~.~.~.^.XXe.m ' ^ ^ ( ^ ^ ^ ^ ^ ^ ^ ^ z.B.", "B.~.-.l G.z.B.v.n.z.f.z.v.z.B.G.:.D 2.-.-.-.-.-.-.-.:.-.q.D :.~.", "z.~.] 2 ~.z.B.B.B.B.[.Y.B.B.B.L.:._ XX~.~.L.L.~.~.L.~.G.XX_ :.~.", "z.~.] 2 G.B.B.B.D.f.i F _.v.v.~.:.^ ~.z.B.v.G.B.z.B.B.z. XQ :.~.", "z.~.] 2 ~.B.B.v.[.f 3 s `.v.v.L.:.! ~.z.B.G.s.f.Y.B.B.z. X^ :.~.", "z.~.] 2 G.B.v._.} h g p #Xv.B.~.,.! ^.z.Y.d 0 7 | Y.B.z.~.^ :.G.", "h.].[ 1 L.B.v.Y.y u q 5 O.Y.z.~.:.! Xv.N.X.N.s r `.B.v.^.^ :.~.", "h.].[ 1 L.B.B.D. .F w 8 6.D.z.~.,.^ Xv.v.#Xs.7 { [.v.v. XQ :.~.", "D.).' 1 L.B.B.v._.#Xo...[.B.B.G.:.! ~.z.Y.O.6 j _.v.B.v.~.^ :.~.", "k.Y.) h L.B.B.B.v.z.Y._.v.B.B.~.,.! ~.z.Y.t 4 e a D.B.B. X^ :.G.", "k.Y.] 1 G.z.B.z.v.z.z.f.z.z.z.G.-.! ^.B.B.7.3.@.6.B.B.z.~.Q :.~.", "C.).' z X~.~.~.~.~.~.~.~.~.~. Xw.^ ~.v.B.P.Y._.Y.B.B.z.~.^ :.~.", "n._.*.; _ ^ ^ Q ^ Q ^ ^ Q ^ ^ ] A R XB.B.B.z.v.v.B.B.z. XQ :.~.", "n.P.< * D c m m m m m m m m m M : q.G.v.B.B.B.v.v.B.B.z.~.^ :.~.", "n.Y.- ] G.z.z.z.z.z.z.z.z.z.z.B.M L T P T P P P P P P P Q 2 q.L.", "G.i.x :.`.N.N.B.B.B.B.N.N.B.B.G.J :.q.0.2.q.q.q.q.q.q.q.:.J G.B.", "B.~._ $.~.z.N.N.Y.Y.G.B.N.B.B.~.M P Q T T R T T Q T T ( c _ ^.B.", "n.~.] $.~.B.B.G.7.O.7.D.G.B.B.B.Y L.^.^.^.`.~.~.~.~.~.XX2.] ~.z.", "B.B.z.z.B.B.B.B.y.5.s.B.B.B.B.B.f.z.v.B.B.z.z.B.z.z.z.B.z.z.B.B.", "B.B.B.B.B.B.B.B.G.Y.D.B.B.B.B.B.D.B.B.B.B.B.B.B.B.B.B.B.B.B.B.B.", "B.B.B.B.B.B.B.B.v.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.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.B.B.B." }; /* XPM */ static const char *const xpm_icon_2[] = { /* columns rows colors chars-per-pixel */ "48 48 239 2 ", " c black", ". c #010101", "X c #020202", "o c #040404", "O c #0C0C0C", "+ c #0E0E0E", "@ c #111111", "# c #131313", "$ c #151515", "% c gray13", "& c #2C2C2C", "* c #3F3F3F", "= c #007900", "- c #007C00", "; c #007D00", ": c #007F00", "> c gray26", ", c gray29", "< c #4C4C4C", "1 c gray31", "2 c #505050", "3 c gray32", "4 c #555555", "5 c #5D5D5D", "6 c gray37", "7 c #626262", "8 c gray39", "9 c #646464", "0 c gray40", "q c DimGray", "w c #6A6A6A", "e c gray44", "r c #717171", "t c #727272", "y c gray45", "u c gray46", "i c gray47", "p c #797979", "a c gray48", "s c #7B7B7B", "d c #7C7C7C", "f c #7E7E7E", "g c gray50", "h c #008200", "j c #008300", "k c #008500", "l c #018501", "z c #008600", "x c #008800", "c c #028B02", "v c #078C07", "b c #078D07", "n c #098C09", "m c #0E8D0E", "M c #148D14", "N c #109010", "B c #1D951D", "V c #1F951F", "C c #1E961E", "Z c #299A29", "A c #2A9B2A", "S c #2E9B2E", "D c #2F9D2F", "F c #37A037", "G c #39A139", "H c #3EA23E", "J c #3FA33F", "K c #43A143", "L c #42A442", "P c #46A646", "I c #49A649", "U c #4CA64C", "Y c #4BA84B", "T c #4EA84E", "R c #5AAE5A", "E c #63B163", "W c #66B366", "Q c #69B469", "! c #6AB46A", "~ c #6FB46F", "^ c #70B770", "/ c #72B772", "( c #77BA77", ") c #7FBD7F", "_ c #818181", "` c gray51", "' c #848484", "] c #868686", "[ c gray53", "{ c #888888", "} c #898989", "| c gray54", " . c #8B8B8B", ".. c gray55", "X. c gray56", "o. c #909090", "O. c gray57", "+. c #929292", "@. c gray58", "#. c #959595", "$. c gray59", "%. c #989898", "&. c gray60", "*. c #9B9B9B", "=. c #A0A0A0", "-. c #A2A2A2", ";. c gray64", ":. c #A4A4A4", ">. c gray65", ",. c gray66", "<. c #A9A9A9", "1. c gray67", "2. c #ACACAC", "3. c gray68", "4. c #AEAEAE", "5. c gray69", "6. c #B1B1B1", "7. c #B2B2B2", "8. c gray71", "9. c #B6B6B6", "0. c #B7B7B7", "q. c gray72", "w. c #B9B9B9", "e. c gray73", "r. c #BBBBBB", "t. c #BCBCBC", "y. c gray", "u. c gray75", "i. c #90C390", "p. c #91C291", "a. c #95C695", "s. c #97C697", "d. c #97C797", "f. c #9BC89B", "g. c #A0CAA0", "h. c #A4CBA4", "j. c #A5CCA5", "k. c #A6CDA6", "l. c #ADCFAD", "z. c #AFD0AF", "x. c #B2D2B2", "c. c #B7D3B7", "v. c #BAD4BA", "b. c #BDD5BD", "n. c #BDD6BD", "m. c #BFD7BF", "M. c #C3C3C3", "N. c gray77", "B. c #C5C5C5", "V. c #C6C6C6", "C. c gray78", "Z. c #C8C8C8", "A. c gray79", "S. c #CACACA", "D. c #CECECE", "F. c gray81", "G. c #C2D8C2", "H. c #C5D9C5", "J. c #C6D9C6", "K. c #C7D9C7", "L. c #CADBCA", "P. c #D0D0D0", "I. c gray82", "U. c #D2D2D2", "Y. c LightGray", "T. c gray83", "R. c #D4DFD4", "E. c gray85", "W. c #DADADA", "Q. c gray86", "!. c #DDDDDD", "~. c gray87", "^. c #DFDFDF", "/. c #D8E2D8", "(. c #DAE1DA", "). c #DBE2DB", "_. c #DCE2DC", "`. c #DEE3DE", "'. c gray88", "]. c #E1E1E1", "[. c #E2E2E2", "{. c gray89", "}. c #E0E4E0", "|. c #E1E4E1", " X c #E2E4E2", ".X c #E2E5E2", "XX c #E3E5E3", "oX c #E4E4E4", "OX c #E4E5E4", "+X c gray90", "@X c #E5E6E5", "#X c #E6E6E6", "$X c #E7E6E7", "%X c #E7E7E7", "&X c #E8E7E8", "*X c #E9E7E9", "=X c gray91", "-X c #E9E9E9", ";X c #EAE8EA", ":X c #EBE8EB", ">X c #EAEAEA", ",X c gray92", ".X t.fX#X#X#X#X#X#X#X#X#X#X#X#X#X{.fX4.< # +.fX#X#X#X#X#X#X#X#X#X#X#X#X", "#X#X#X#X#X#X#X#X#X#X{.fX<.X t.fX{.#X#X#X#X#X#X#X#X#X#X#X#X=XU.^.mX> % =X#X#X#X#X#X#X#X#X#X#X#X#X", "#X#X#X#X#X#X{.#X{.{.fX_ + X + @.4X{.{.#X{.{.#X#X{.#X#X#X{.hX+.# % o _ 4X{.#X#X#X#X#X#X#X#X#X#X#X", "#X#X#X#X#X#XfXfXfX4XhXT.q.M.q.Q.hXfXfXfXfXfXfXfXhX4X#X#X#X#X{.q.4.S.4X#X#X#X#X#X#X#X#X#X#X#X#X#X", "#X#X#X=X4X^.6.6.6.6.6.q.t.t.t.9.6.6.6.6.6.6.6.6.4.S.=X#X#X#X#XfXfX=X#X#X#X#X#X#X#X#X#X#X#X#X#X#X", "#X#X#XQ.^.8 ] 6.<.<.<.<.<.>.>.<.<.<.<.<.<.<.<.4.=.d 4X#X#X#X#X#X#X#X#X#X&X#X#X#X#X#X#X#X#X#X#X#X", "#X#X4XD.a > U.nXfXfXhXfXfXhXfXhXfXhXfXhXhXfXhXhX4X} #X{.#X{.#X{.{.{.#X{.#X#XoX{.#XXX#X=X#X#X#X#X", "#X#XXXhXU.7 V.,X{.oXoX{.oXoXXXXX#X{.XX{.#X{.{.#X{.0 ] } } } [ } } [ } } [ } } [ } [ } a ^.%X#X#X", "#X#X#X4XM.6 Z.6X{.#X#X#X#X#X#X#X#X#X#X#X#X#X#X%X^.} 4X#X%X=X=X%X=X%X%X=X=X%X=X%X%X#XhX+.D.4X#X#X", "#X#X#X4XV.6 Z.6XoX#X#X#X#X#X#X&X1X&X#X#X#X#X#X=X{.} =X#X#X#X#X#X#X#X#X#X%X#X#X#X#X{.fX+.U.,X#X#X", "#X#XXX4XV.6 S.0XoX#X#X#X#X#X=X`.L.(.&X#X#X#X#X=X^.[ 4X#X#X#X#X#X#X#X#X%X#X#X#X#X#X{.fX+.F.=X#X#X", "#X#X{.4XV.6 Z.4XoX#X#X#X#X%XXXS h ^ rXXX#X#X#X=X`.} =X#X#X#X#X#XXXXXXXXX#X#X#X#X#X{.fX+.D.,XXX#X", "#X#X#X4XV.6 Z.4XoX#X#X#XXXrXE m z ! rXXX#X#X#X=X^.} ,X#X#X#X#X1XrXzXrX1XoX#X#X#X#X{.fXo.F.,X#X#X", "#X#X#X4XV.6 S.4XoX#X#XXXrXk.M a.z Q wXXX#X#X#X=X^.} ,X#X#X#X=Xc.E Y E c.1X#X#X#X#X{.fX+.F.4X#X#X", "#X#X#X4XV.6 S.4XoX#X#X&X(.B g.(.: ( xXXX#X#X#X%X^.} =X#X#X#XwXK M G z n b.1X#X#X#X{.fXo.F.4X#X#X", "#X#XXX4XZ.6 S.4XoX#XXXrXi.h R L x B f.1X#X#X#X=X^.} 4X#X#X#X#XG.XXaX( : i.wXXX#X#X{.fX+.D.4X#X#X", "#X#X#X0XV.6 S.4XoX#XXXqXk.Z Z B x v ) qXXX#X#X=X^.} =X#X#X#X&X=X&XqXI z G.qXoX#X#X{.fX+.U.=X#X#X", "#X#X#X4XV.6 S.4XoX#X#X#X#X#XrXb.: ^ pXXX#X#X#X=X^.} =X#X#X#X#X=X&XU z a.qXoX#X#X#X{.fX+.D.4X#X#X", "#X#XXX4XV.6 S.4XoX#X#X#X#X#X=X(.h.K.&X#X#X#X#X=X^.} 1X#X#X#X&X(.J n x.xX&X#X#X#X#X{.fX+.D.4X#X#X", "#X#X#X6XV.6 S.4XoX#X#X#X#X#X#X#XwX&X#X#X#X#X#X&X`.} =X#X#XXXqXU = B I A a.qXXX#X#X{.fXX.U.=X#X#X", "#X#X#X4XV.6 S.4X{.#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X^.} ,X#X#X#X1X^ J L G S a.qXXX#X#X{.fX+.D.4X#X#X", "#X#XXX4XV.6 S.4X{.#X#X#X#X#X#X#X#X#X#X#X#X#X#X&X^.} 1X#X#X#X#XqXwXwXrXpX1X#X#X#X#X{.fX+.D.4X#X#X", "#X#X#X4XV.6 Z.4X{.#XoX#XoX#X#XoX#XoX#X#X#X#X#X#X^.} =XoX#X#X#X#XXXXX#X{.#X#X#X#X#X{.fXX.U.=X{.#X", "#X#XXX4XM.8 V.4X#X=X=X=X=X=X=X=X=X=X&X=X=X=X=X=X{.X.=X#X#X#X#X#X#X#X#X#X#X#X#X#X#X{.hX+.D.4X#X#X", "#X#XoXfXU.3 } &.@.@.@.@.@.@.&.@.@.@.@.@.&.@.@.&._ e 4X{.{.#X{.#X{.{.{.#X#X{.{.{.{.{.4X+.U.=X#X#X", "#X#X=XU.e & @.X.+.+.+.X.X.+.+.X.o.o.X.+.+.X.X.@.e M.mXfXfXfXfXfXfXfXfXfXfXfXfXfXfXfXmX@.U.4X#X#X", "#X#X&X4X, } Q.V.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.U.e =.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.<.9.a U.=X#X#X", "#X#X=XU.3 4.nX=X4X4X4X1X4X4X4X4X4X4X4X4X4X4X=XnX] =.6.4.4.4.4.4.4.4.4.4.4.4.4.4.4.4.>.q #X#X#X#X", "#X{.fX4.} 4.fX{.#X#X#X#X#X#X#X#X#X#X#X#X#X#XoX=XX.#XfX4XfX4XfX4X4X4XfX4X4X4XfX4X=XnX6.6.fX#X#X#X", "#X#X#X#X9.>.hX{.#X#X#X#X#XoXXXXX#X#X#X#X#X#X{.fXu a } } ] } ] ] } } ] ] } } ] ] } ] 0 #X#X#X#X#X", "#X#X#XfX9.=.hX#X#X#X#X#X&XqXqXqX&X#X#X#X#X#X#X4X} {.4X=X=X=X=X,X=X=X=X4X=X=X=X4X=X=X} #X#X#X#X#X", "#X#X#XfX9.>.fX{.#X#X#X&XR.l.f.x.`.#X#X#X#X#X#X4X} Q.#X{.#X#X{.#X#X{.#X#X{.#X#X#X#X=X} #X#X#X#X#X", "#X#X#X#X{.^.=X#X#X#X#X#X`.H.b.H.XX&X#X#X#X#X#X#XQ.#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#XQ.#X#X#X#X#X", "#X#X#X#X#X#X#X#X#X#X#X#X&X1XqX1X#X#X#X#X#X#X#X#X=X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X=X#X#X#X#X#X", "#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X", "#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X", "#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X", "#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X", "#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X" }; const char *const *const xpm_icons[] = { xpm_icon_0, xpm_icon_1, xpm_icon_2, }; const int n_xpm_icons = 3; puzzles-20170606.272beef/icons/tents-icon.c0000644000175000017500000004224413115373753017244 0ustar simonsimon/* XPM */ static const char *const xpm_icon_0[] = { /* columns rows colors chars-per-pixel */ "16 16 256 2 ", " c #E7E7E7", ". c #EBE6EE", "X c #EAE3ED", "o c #EAE5EE", "O c #EFE7F1", "+ c #F3E8F4", "@ c #ECE6F0", "# c #EAE4EE", "$ c #EAE4ED", "% c #EBE6EF", "& c #F2E7F4", "* c #F0E7F3", "= c #E8E7E9", "- c #E6E6E6", "; c gray90", ": c #E6E6E6", "> c #DFE1DD", ", c #B9D6A6", "< c #BCE2AB", "1 c #BAD8A5", "2 c #A9D198", "3 c #9CD18F", "4 c #B2D29E", "5 c #BBDDA8", "6 c #BCE0AA", "7 c #B5D3A1", "8 c #9ED191", "9 c #A3D192", "0 c #D7DCD1", "q c #E9E7EA", "w c gray92", "e c #E7E7E7", "r c #DAE0D7", "t c #A6EB75", "y c #BFDD31", "u c #B1EF71", "i c #37C527", "p c #00AF00", "a c #6EDA53", "s c #BDE956", "d c #BEE346", "f c #86E465", "g c #00B300", "h c #1BBE0E", "j c #CCDBBF", "k c #EBE7ED", "l c #A4A5A3", "z c gray88", "x c #D9E2DB", "c c #ABDB69", "v c #C9BE12", "b c #ADDB5D", "n c #98E46F", "m c #92CE4D", "M c #9CEB7B", "N c #BBCB36", "B c #C3C426", "V c #9EEA79", "C c #86CD4C", "Z c #8AD855", "A c #CBDDC3", "S c #EAE6EC", "D c #BDBEBC", "F c gray89", "G c #D9DED6", "H c #9DD973", "J c #A6F279", "K c #9FDD72", "L c #78CF56", "P c #5FCE43", "I c #8BD262", "U c #A4E877", "Y c #A4EC77", "T c #97D66C", "R c #AFED7B", "E c #A3E670", "W c #C7D6BD", "Q c #EBE8ED", "! c #EBEBEA", "~ c #E7E7E7", "^ c #DBE0D7", "/ c #ACEB7F", "( c #B9FF83", ") c #B5F382", "_ c #40C72E", "` c #00B100", "' c #78D956", "] c #BDFE87", "[ c #B5FF81", "{ c #A7E977", "} c #B7FF84", "| c #AFFA7A", " . c #CBDAC0", ".. c #E9E6EB", "X. c #A2A3A2", "o. c gray90", "O. c #DADFD6", "+. c #A1E077", "@. c #ADF87B", "#. c #A0E574", "$. c #9FDF6D", "%. c #A0D45D", "&. c #9EE273", "*. c #A7ED77", "=. c #ABF37A", "-. c #9BDD6F", ";. c #ACF47C", ":. c #A3ED71", ">. c #C8D7BE", ",. c #ECE8EE", "<. c #D3D4D2", "1. c #E4E4E4", "2. c #DADFD6", "3. c #A0DE76", "4. c #ABF679", "5. c #9DE171", "6. c #A1E473", "7. c #B1F072", "8. c #9ADD71", "9. c #A5EB75", "0. c #A8F079", "q. c #99DA6E", "w. c #AAF17A", "e. c #A1EA70", "r. c #C8D7BE", "t. c #EAE7ED", "y. c #DCDCDB", "u. c #E7E7E7", "i. c #DAE0D6", "p. c #ACEB7F", "a. c #BCFF84", "s. c #AAF382", "d. c #B6DF57", "f. c #D1C718", "g. c #A9EA76", "h. c #B4FB82", "j. c #B8FF83", "k. c #A7E978", "l. c #B9FF85", "z. c #B0FA7B", "x. c #CBDAC0", "c. c #E9E6EC", "v. c #A0A19F", "b. c #E4E4E4", "n. c #DADED7", "m. c #A2DC79", "M. c #ADF379", "N. c #9FE176", "B. c #A2D259", "V. c #B3D347", "C. c #9AD465", "Z. c #A2E976", "A. c #A6EC76", "S. c #97D76C", "D. c #A8EE79", "F. c #9EE66E", "G. c #C7D6BD", "H. c #ECE9EE", "J. c #E4E5E4", "K. c gray90", "L. c #EAE1E9", "P. c #6FC85B", "I. c #00B400", "U. c #57C63F", "Y. c #AFF282", "T. c #ACFF86", "R. c #9FE373", "E. c #AAF279", "W. c #AEF77C", "Q. c #9EE172", "!. c #B0F880", "~. c #A7F175", "^. c #C9D8BF", "/. c #EAE6EC", "(. c #C8C9C8", "). c #E7E7E7", "_. c #E6DFE7", "`. c #8BDD6C", "'. c #41C017", "]. c #79DC52", "[. c #B3F67F", "{. c #B8FF81", "}. c #A6EA77", "|. c #B2FA7F", " X c #B6FF82", ".X c #A4E973", "XX c #B4FF7C", "oX c #ABFA72", "OX c #CADABE", "+X c #EAE7ED", "@X c #A8A9A7", "#X c gray89", "$X c #DADDDA", "%X c #B4D39B", "&X c #C8DA9A", "*X c #B2D594", "=X c #9CDD71", "-X c #A8ED79", ";X c #97D66D", ":X c #A2E475", ">X c #A3EA74", ",X c #9FD07E", " , < 1 2 3 4 5 6 7 8 9 0 q w e ", "r t y u i p a s d f g h j k l z ", "x c v b n m M N B V C Z A S D F ", "G H J K L P I U Y T R E W Q ! ~ ", "^ / ( ) _ ` ' ] [ { } | ...X.o.", "O.+.@.#.$.%.&.*.=.-.;.:.>.,.<.1.", "2.3.4.5.6.7.8.9.0.q.w.e.r.t.y.u.", "i.p.a.s.d.f.g.h.j.k.l.z.x.c.v.b.", "n.m.M.N.B.V.C.Z.A.S.D.F.G.H.J.K.", "L.P.I.U.Y.T.R.E.W.Q.!.~.^./.(.).", "_.`.'.].[.{.}.|. X.XXXoXOX+X@X#X", "$X%X&X*X=X-X;X:X>X,X c #54C83B", ", c #53DA39", "< c #7AAE57", "1 c #7CB059", "2 c #5DC942", "3 c #5DD942", "4 c #63C749", "5 c #65C94B", "6 c #63CE47", "7 c #6ED145", "8 c #73D94A", "9 c #6FCF52", "0 c #72D352", "q c #7FD15B", "w c #6AE248", "e c #8E8F1C", "r c #8EA630", "t c #B1A43A", "y c #CEA700", "u c #CDAC00", "i c #CAB408", "p c #CAB810", "a c #C5CE2D", "s c #C7C926", "d c #C3D131", "f c #CAD530", "g c #C5DA3F", "h c #80B75B", "j c #82BA5D", "k c #80AF61", "l c #89BE65", "z c #9BC24B", "x c #8DD05F", "c c #83D95E", "v c #BDDF4D", "b c #A3C656", "n c #84E65F", "m c #BEEC5C", "M c #87C161", "N c #8AC463", "B c #8ECC65", "V c #8FC868", "C c #91CE67", "Z c #92CF6A", "A c #8FD261", "S c #8ADC62", "D c #93D266", "F c #96DD67", "G c #95D46B", "H c #99D56E", "J c #95D96B", "K c #9BDB6E", "L c #96C079", "P c #99CA7E", "I c #94D771", "U c #9DD670", "Y c #95DA72", "T c #9DDD71", "R c #A5D561", "E c #A3DC73", "W c #9CE56E", "Q c #9FE96D", "! c #87F162", "~ c #8CF567", "^ c #9CFB6E", "/ c #9EE171", "( c #9CE779", ") c #AAE76F", "_ c #A0EE6C", "` c #A4E26F", "' c #BBED64", "] c #B2E86F", "[ c #BAF065", "{ c #A2E475", "} c #A5EA76", "| c #A9ED77", " . c #A6E17A", ".. c #A5EE7A", "X. c #AAEE79", "o. c #A9E479", "O. c #B8E978", "+. c #A0F673", "@. c #ACFC77", "#. c #AAF27A", "$. c #AEFC7A", "%. c #A6F775", "&. c #B9F670", "*. c #B2FD7E", "=. c #B6F877", "-. c #C4DF44", ";. c #C5E146", ":. c #C0E24C", ">. c #C1E852", ",. c #868686", "<. c #8B8B8B", "1. c #959595", "2. c #9A9A9A", "3. c #98AC8C", "4. c #9FB78E", "5. c #A8BF96", "6. c #A2B695", "7. c gray68", "8. c #AFB5AB", "9. c gray70", "0. c #BDBDBC", "q. c #9FCE82", "w. c #A6CD87", "e. c #AACE8B", "r. c #ACD98E", "t. c #A5C192", "y. c #AAC796", "u. c #ABC897", "i. c #ADC898", "p. c #ADFF88", "a. c #B5FE82", "s. c #BAFF85", "d. c #B3FF89", "f. c #BAFF8B", "g. c #B5E197", "h. c #B7EB94", "j. c #B8CDA0", "k. c #B6C7A9", "l. c #BECBBB", "z. c #BCC6B5", "x. c #C1FF8D", "c. c #C5FF95", "v. c #C1F79D", "b. c #C3FA9F", "n. c #C3CBBC", "m. c #C4FBA0", "M. c #C3C3C4", "N. c #CFCFCE", "B. c #C9CEC5", "V. c #D1CFCF", "C. c #CDD2C9", "Z. c #D2D1D1", "A. c #DAD4D7", "S. c #D7DFD2", "D. c #D9DFD4", "F. c #D7D7D8", "G. c #D8D6DA", "H. c #D9DBD8", "J. c #D7E4CE", "K. c #DAE2D5", "L. c #E3DDE7", "P. c #E5DFE8", "I. c #E5E5E5", "U. c #E7E8E6", "Y. c #EAE6EC", "T. c #EBEAEB", "R. c #E7E4EC", "E. c #F4EFF9", "W. c #F2F2F3", /* pixels */ "I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.U.U.I.U.I.I.I.R.U.I.U.I.", "I.U.T.Y.T.T.T.T.T.U.Y.T.T.T.T.U.T.T.T.T.U.T.U.T.Y.I.I.U.I.I.I.I.", "U.I.N.N.N.N.V.N.N.A.A.A.Z.N.N.N.N.N.V.V.A.A.A.V.H.U.U.I.I.P.I.U.", "Y.K.l { { / } V G 9 4 4 J l ( { { { V G 0 5 5 c 5.Y.I.I.T.W.I.I.", "U.K.H f.' v f.E c o o X 3 E d.' -.f.o.S o X . , j.R.I.T.0.0.T.I.", "Y.K.G d.s i a. .> . o . = U d.a i a.o.2 . o . & i.I.I.W.2. W.I.", "Y.K.I ' u y ;.( W ! # 8 +.I [ u y g ( W ~ $ 7 ^ i.Y.I.Y.2.<.T.I.", "Y.K.I >.a d ;.T | x.t O.a.I m a d -.T } x.t O.s.y.Y.I.U.U.T.U.I.", "T.S.< K I I Y 1 N U J Y G < H I I Y j j G J G x 4.Y.I.I.U.I.I.I.", "Y.K.G *.*.$.a.T W ; & & n U $.*.*.s.W { a.$.a.@.y.Y.I.I.I.U.I.I.", "U.K.H a.a.a.a.o.6 . X . - U *.a.*.s.T } a.a.a.@.i.Y.I.W.2.7.W.I.", "Y.K.G a.*.*.a.{ 0 * X + 3 H a.*.*.a.W ( a.a.a.$.y.Y.I.W.1.,.W.P.", "U.K.H s.a.a.s.T O.f.e ] x.G s.a.a.s.E } s.a.a.*.i.Y.I.T.0.9.U.I.", "Y.K.N | } } ..B K ..b { } j } } } #.B H | } } Q 5.Y.I.I.T.W.I.U.", "T.D.j { K K { M Z / ( / K h { K K { N B ` K { F 4.T.I.I.T.U.I.I.", "Y.K.H s.a.s.s.E X.f.-.=.a.H s.a.s.f.{ } s.s.s.*.i.Y.U.T.0.V.Y.I.", "U.K.G a.a.a.a.K ..&.u v p.G a.$.*.a.T { a.*.a.@.u.Y.I.W.1.2.W.I.", "Y.K.G a.$.a.a.U ..a u p #.G a.a.*.a.W } s.*.*.$.u.Y.I.W.2.,.T.I.", "Y.K.H a.a.a.s./ | f a s ' H a.a.a.s.E } s.a.s.$.i.Y.I.I.I.I.I.I.", "U.H.k K U I / 1 N Y I I G < H G G K j M J G G D 4.T.I.I.I.I.U.I.", "U.L.e.w @ @ , U { *.*.=.X.B a.$.#.a.K / *.#.*.%.y.Y.U.I.I.U.I.I.", "U.P.w.% . . O A X.s.a.*.a.G a.a.*.s.{ } s.a.a.*.y.Y.I.T.2.9.W.I.", "I.R.P : O o = q X.a.*.a.$.G a.*.a.a./ { a.*.a.$.y.Y.I.W.2.<.W.I.", "U.L.w.x.z r c.E X.a.a.a.a.H a.a.a.s./ } s.s.a.*.i.Y.I.Y.9.7.U.I.", "U.L.L +.R b @.A K #.| | | N #.| | #.G F %.} } _ t.Y.I.I.T.W.I.U.", "Y.S.3.B.l.l.B.6.x E K K J 1 K K K K l 8.n.z.n.n.9.Y.I.I.T.U.I.I.", "U.J.k.E.T.U.E.B.| s.s.s.a.H s.s.s.s. .G.W.T.Y.T.M.I.I.U.M.F.U.U.", "Y.J.k.Y.I.I.Y.l._ *.$.*.$.D $.$.*.*.K V.T.I.I.I.0.I.I.W.1.2.W.I.", "T.K.n.Y.I.I.Y.C.h.m.v.v.v.r.m.v.v.m.g.G.Y.U.I.I.N.I.I.W.7.2.W.I.", "U.U.U.U.I.I.U.U.Y.R.R.Y.R.Y.Y.U.U.U.Y.U.I.I.I.U.I.I.I.I.I.U.I.I.", "U.I.I.I.U.I.U.R.U.I.I.U.U.I.I.I.I.I.I.U.I.U.I.U.I.I.I.I.U.I.I.I.", "I.I.R.I.I.U.I.I.I.I.I.I.I.I.I.I.I.R.I.U.I.I.I.I.R.I.I.U.I.I.R.U." }; /* XPM */ static const char *const xpm_icon_2[] = { /* columns rows colors chars-per-pixel */ "48 48 171 2 ", " c #3C3C3C", ". c #484848", "X c #5B5B5B", "o c #535353", "O c #6B6B6B", "+ c #626262", "@ c gray48", "# c #A45A02", "$ c #A66407", "% c #369801", "& c #00AD00", "* c #04B402", "= c #00B800", "- c #0CB609", "; c #0BB808", ": c #0AB807", "> c #1ABE13", ", c #418E00", "< c #5B8000", "1 c #26C21C", "2 c #2FCC21", "3 c #31CD23", "4 c #5FC835", "5 c #46D332", "6 c #4DD334", "7 c #51D636", "8 c #54D83B", "9 c #669249", "0 c #69944C", "q c #77B051", "w c #7BB454", "e c #7EB35A", "r c #778F67", "t c #789167", "y c #7D9070", "u c #5BDA41", "i c #62DC44", "p c #6ADC4C", "a c #69D947", "s c #74DD4E", "d c #79DA4D", "f c #76DC50", "g c #68E149", "h c #76E552", "j c #7CEB55", "k c #CEAD00", "l c #D0A800", "z c #CCB301", "x c #CBBB0D", "c c #C8BE15", "v c #C9C31A", "b c #C7C21C", "n c #C6C926", "m c #C7C720", "M c #C4D133", "N c #84BC5D", "B c #88BF5F", "V c #80B75C", "C c #86BF60", "Z c #89BF65", "A c #85C15C", "S c #88C05F", "D c #9CD95D", "F c #A4C64E", "G c #BFD943", "H c #BFDF4C", "J c #A6CC55", "K c #B4C257", "L c #81E659", "P c #91E05B", "I c #BDE04E", "U c #BDE454", "Y c #BBE658", "T c #87C162", "R c #8AC363", "E c #8DC964", "W c #89CB69", "Q c #90C667", "! c #92C569", "~ c #94C86B", "^ c #93DF60", "/ c #94CF71", "( c #B8DF6D", ") c #9BE868", "_ c #8BF065", "` c #9AF36C", "' c #95F06A", "] c #9FE372", "[ c #99F770", "{ c #9EF873", "} c #A2ED6D", "| c #ADE96D", " . c #BAED63", ".. c #A4F66D", "X. c #B6F36C", "o. c #B8F56E", "O. c #A4EE73", "+. c #A9EF75", "@. c #A7EF78", "#. c #A8EF78", "$. c #BAED78", "%. c #B8E370", "&. c #A5F373", "*. c #ACF275", "=. c #ACFD76", "-. c #ABF47A", ";. c #AFFA7C", ":. c #A5F977", ">. c #B6F673", ",. c #B2FD7E", "<. c #B8FD78", "1. c #B2F67B", "2. c #C0D740", "3. c #848484", "4. c #888888", "5. c #989898", "6. c #91A285", "7. c #94AB85", "8. c #97B783", "9. c #99B685", "0. c #97B881", "q. c #9CB986", "w. c #9DB58D", "e. c #9FB98C", "r. c #9DA896", "t. c #A5AE9F", "y. c #A2B792", "u. c #A4B993", "i. c #AABB96", "p. c #A4B599", "a. c #ABBB98", "s. c #A2A2A2", "d. c #AAABAA", "f. c #ACB7A4", "g. c #ACB8A5", "h. c #AEBAAA", "j. c #B3BBAB", "k. c #B5B5B5", "l. c #BABABA", "z. c #ADFC84", "x. c #B4FF81", "c. c #B9FF84", "v. c #B2FF89", "b. c #BAFF89", "n. c #BFC2BD", "m. c #C8DABD", "M. c #C0C0C0", "N. c #CFCFCF", "B. c #CED8C7", "V. c #CED7C8", "C. c #D2D7CE", "Z. c #D5D5D5", "A. c #DBDBDB", "S. c #D6EEC6", "D. c #DFE5DB", "F. c #E0EDD7", "G. c #E3ECDE", "H. c #E0E3DF", "J. c #E2DEE4", "K. c #E6E6E6", "L. c #E8E8E7", "P. c #E7E5E8", "I. c #EAE6ED", "U. c #EBEAEB", "Y. c #E4E8E2", "T. c #EFECF1", "R. c #F0EEF1", "E. c #F3EBF8", "W. c #F3F2F3", "Q. c #F9F9F9", "!. c #F8F2FD", /* pixels */ "K.K.K.K.L.L.P.K.K.K.K.K.L.K.K.K.K.K.K.L.K.K.K.K.K.K.K.K.K.K.K.K.L.K.K.K.K.L.L.K.K.K.L.K.K.K.K.K.", "K.K.L.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.L.K.K.K.K.K.L.K.K.K.K.K.K.K.K.K.K.L.K.L.K.K.K.", "K.L.K.K.K.K.K.K.K.K.K.L.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.L.K.K.K.L.K.K.K.P.L.K.K.K.K.K.P.K.", "K.K.K.L.P.Y.K.K.K.K.K.L.K.K.K.K.Y.K.K.K.Y.K.K.K.K.K.K.K.P.Y.K.K.K.K.Y.K.K.K.K.K.K.K.L.K.K.K.K.K.", "K.K.L.K.T.I.I.I.I.I.I.I.R.I.I.I.I.I.I.I.R.I.I.T.I.I.I.I.I.I.I.I.P.I.I.I.L.K.K.K.K.L.K.K.K.K.K.L.", "K.K.L.H.6.w.w.w.w.w.y.w.6.w.i.a.a.a.u.w.6.w.w.w.w.w.w.w.6.y.a.a.a.a.a.7.m.I.K.K.K.K.P.L.P.K.K.K.", "K.K.P.G.N :.=.=.;.=.=.=.N =.i 7 6 6 g =.A ,.=.=.=.=.=.&.A =.8 7 7 6 j } d.I.Y.K.L.L.T.L.K.K.K.K.", "K.K.L.Y.Z x.x.c.M <.x.,.Q [ & & * & - -.R c.x.>.M x.c.-.~ _ & * & & 1 #.f.T.K.K.L.A.M.A.L.K.P.K.", "K.K.P.G.Z ;.v.Y k I v.,.! u & * * * & a ! ,.v.G l .v.*.~ 5 & * * * * s j.R.J.K.U.N.o O W.K.K.K.", "L.K.P.G.Z ,.x.b k c ,.z.! 8 * * = * * i Q x.1.x z n v.+.Q 5 & * = * * s j.T.Y.K.K.U.@ X W.K.K.K.", "K.K.P.Y.Z z.Y k z l H v.N c.&.a % s :.;.S v.G k z z .z.R c.[ 4 % L :.&.g.T.K.Y.W.l.X @ U.K.K.P.", "K.L.L.G.T ;.b k z z c ,.T ,.b.( # $.b.,.T <.x z z z n z.S c.b.K $ b.b.} g.T.K.K.K.H.A.U.K.K.K.L.", "K.K.L.G.Z 1.X.X.o.o.o.,.S ,.;.*.F -.,.-.S ,.X.o.o.o.o.-.T c.;.| J ;.x.O.g.T.K.K.K.L.L.P.P.K.K.K.", "K.K.P.H.0 N W T T T T T 9 T ! ~ / ! ! C 9 T T T T T T e 9 E T T W T R q s.T.Y.K.K.K.K.K.K.K.K.K.", "K.K.L.G.Z ,.c.,.x.,.,.,.C c.u 5 5 5 g ,.T c.,.,.x.x.c.-.R c.x.,.x.,.c.&.g.W.H.P.P.L.W.K.K.K.K.K.", "K.L.K.G.Z ;.,.,.x.z.c.;.T [ & & & & - &.R c.,.,.z.x.c.-.T x.;.x.,.x.x.} g.T.K.K.L.A.k.H.L.K.K.K.", "K.K.L.G.T ;.x.x.x.,.x.;.! 8 & : & - & i ! x.x.,.c.,.x.-.T c.;.,.x.x.c.} g.T.Y.J.P.Z. k.W.P.K.K.", "K.P.L.G.Z ;.x.x.x.x.x.;.! u * * = * * p Q ,.z.,.x.,.x.-.E c.,.x.,.x.x.O.g.T.Y.K.Y.Q.O d.W.K.K.K.", "K.K.L.Y.Z ;.x.,.,.x.x.x.Z c.:.f , L ;.x.S c.z.,.,.x.x.-.T c.,.x.,.x.x.O.g.T.Y.P.L.N.. @ U.K.K.P.", "K.K.L.Y.Z ,.,.c.x.x.,.c.N ,.b.( # $.b.-.S c.,.x.x.x.c.-.T c.x.x.x.c.c.O.g.T.Y.K.P.P.P.K.K.K.K.K.", "K.K.L.G.C -.z.;.;.;.;.-.N ;.;.*.J -.;.-.N ,.;.;.;.;.;.@.S ,.;.;.;.;.x.) f.T.J.K.L.L.P.K.P.K.L.K.", "K.K.P.D.0 N Z T T T T T 9 T C T W R R N 9 R S T C T R N 9 E C T T N T w t.R.Y.Y.K.K.Y.P.K.K.K.K.", "K.K.P.Y.Z ,.x.c.c.c.c.c.T c.x.x.<.c.c.z.R c.x.c.c.c.c.-.T c.c.c.c.c.c.O.f.T.Y.P.K.L.W.L.K.K.K.K.", "K.K.L.G.Z ;.x.,.;.,.,.;.C c.x.>.m 1.x.;.N c.,.,.,.;.c.-.R c.;.;.,.,.c.O.f.T.P.K.L.A.d.A.L.K.K.K.", "K.K.P.Y.Z ;.x.x.,.x.x.x.T ,.v.G l U v.;.T x.x.x.x.x.x.-.T c.;.,.x.x.c.} g.T.Y.J.U.A. k.R.K.K.K.", "K.K.L.G.Z ;.x.,.x.x.;.x.C x.>.c k c ,.,.S c.,.,.,.x.x.-.E c.,.x.,.x.x.O.g.T.Y.K.H.Q.O d.R.K.P.L.", "K.K.L.G.T ;.x.x.,.,.,.,.N v.M z z k I z.N c.,.x.x.x.x.-.T c.,.x.,.x.c.O.g.T.Y.P.U.N.o @ U.Y.K.K.", "K.K.L.Y.Z ;.c.x.c.x.x.c.R ,.v x x x b ,.T c.,.c.x.x.c.-.R c.x.x.,.c.c.O.g.T.Y.K.K.K.U.U.K.L.K.K.", "K.K.K.G.C @.-.@.-.-.-.-.e +.+.*.*.*.*.+.N -.-.-.-.-.-.O.N ;.-.-.-.-.-.) f.T.K.K.K.K.K.K.K.K.K.K.", "K.K.K.K.r N ~ E E Q Q R 9 E R T R R R C 0 T R R T T R N 0 E T R T R E w t.R.H.K.K.K.H.K.K.K.K.P.", "K.K.K.I.y.,.8 2 3 3 5 c.T c.c.c.c.x.c.x.Z c.c.x.c.c.c.-.R c.c.c.c.c.b.@.f.T.K.P.K.L.W.U.K.K.K.K.", "K.K.K.I.y.` * & & & & ' R x.x.,.x.,.c.-.C x.x.,.,.c.c.-.R c.,.;.,.,.v.{ f.T.H.K.U.Z.5.A.U.K.K.K.", "L.K.K.I.a.7 & * : * & 6 ! ,.x.x.x.,.c.;.C c.,.,.c.x.x.-.T c.,.x.,.,.x.&.g.T.K.K.L.A.. k.W.K.K.K.", "K.K.K.I.u.h > ; = ; > h Z x.x.,.x.,.x.;.T x.z.x.,.,.x.-.T c.,.,.x.x.c.O.g.T.H.K.J.Q.+ s.W.H.K.K.", "K.K.K.I.w.1.c.) < P c.c.C x.x.,.,.x.x.-.S c.;.,.x.;.c.-.R c.;.x.x.,.c.` g.T.H.K.U.N.X 4.U.K.K.K.", "K.K.K.T.w.;.b.$.$ %.b.c.T x.x.c.c.x.c.x.T c.c.x.x.c.c.-.Z b.c.c.x.c.b.+.g.T.K.K.K.L.W.U.K.P.K.K.", "K.K.K.I.7.) &.} D } O.} w &.@.@.@.@.@.O.e -.@.@.@.@.+.} e &.O.} O.O.&.D f.T.Y.K.K.K.H.K.K.K.K.K.", "K.K.L.H.t f.f.f.h.g.f.h.r S E R E R R Z 0 E T E E E E N y j.f.f.f.f.j.r.d.R.K.K.K.K.J.K.K.K.K.K.", "K.K.P.F.e.T.R.R.T.T.T.E.e.,.b.c.c.c.c.x.R b.x.c.x.c.b.*.f.!.T.T.T.I.E.J.k.U.K.K.K.U.Q.L.K.K.K.L.", "K.K.P.F.8.K.K.J.Y.K.K.P.9.=.x.,.,.,.x.,.N c.,.,.,.x.x.&.p.I.Y.Y.Y.Y.L.Z.k.U.K.K.L.Z.4.Z.L.K.K.P.", "K.K.L.F.9.J.K.K.K.K.K.I.9.,.c.,.x.x.v.;.R c.c.,.x.x.x.=.p.T.K.K.K.K.U.Z.k.R.K.K.K.K.. k.W.K.K.K.", "K.P.L.D.8.P.K.P.K.K.K.I.9.=.,.=.=.;.,.=.A ,.=.,.,.=.,.` p.T.K.K.K.K.U.Z.k.U.K.K.K.W.X s.W.K.K.K.", "K.K.K.Y.V.L.K.K.K.K.K.P.V.S.S.S.S.S.S.S.m.S.S.S.S.S.S.S.C.L.K.K.K.K.K.K.Z.K.K.P.K.A.s.l.U.K.K.K.", "K.L.K.P.I.L.L.K.K.K.K.K.I.I.I.P.I.I.L.I.P.I.I.I.I.I.I.I.U.K.K.K.K.K.K.K.L.K.K.K.P.K.W.R.K.K.K.K.", "P.K.K.K.K.K.K.K.L.K.L.K.K.Y.K.K.K.K.K.K.K.K.K.K.K.K.K.K.P.K.K.K.K.K.K.L.P.K.K.K.K.K.K.K.K.K.K.K.", "K.K.K.K.P.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.K.L.K.K.K.L.K.K.L.K.K.K.K.K.K.K.K.K.L.K.", "L.K.L.K.L.K.K.K.K.L.K.L.K.L.K.K.K.P.K.L.K.K.K.L.K.K.K.K.K.K.K.K.P.K.L.K.K.K.L.K.K.K.K.K.L.K.K.K.", "P.K.K.K.K.K.K.K.K.P.K.L.K.K.K.K.K.L.K.K.K.K.K.L.K.K.K.K.K.K.K.K.K.K.L.K.L.K.K.K.K.K.K.K.K.K.K.K." }; const char *const *const xpm_icons[] = { xpm_icon_0, xpm_icon_1, xpm_icon_2, }; const int n_xpm_icons = 3; puzzles-20170606.272beef/icons/solo-icon.c0000644000175000017500000004352713115373753017070 0ustar simonsimon/* XPM */ static const char *const xpm_icon_0[] = { /* columns rows colors chars-per-pixel */ "16 16 246 2 ", " c #010101", ". c #101010", "X c gray7", "o c #0F110F", "O c gray7", "+ c #101010", "@ c gray7", "# c #111111", "$ c #101010", "% c #111111", "& c #101010", "* c gray7", "= c #0F110F", "- c #111211", "; c #101010", ": c #010101", "> c #101010", ", c #C2C3C2", "< c gray85", "1 c #DCD6DC", "2 c #D6D5D6", "3 c gray75", "4 c gray82", "5 c #D5D5D5", "6 c gainsboro", "7 c #D2D2D2", "8 c gray75", "9 c #D5D5D5", "0 c #DCD6DC", "q c #DCDADC", "w c gray76", "e c #101010", "r c gray7", "t c gray85", "y c #EBEEEB", "u c #94C794", "i c #E6EAE6", "p c #D5D4D5", "a c #EDEEED", "s c #CBCBCB", "d c #9D9D9D", "f c #EBECEB", "g c #D2D3D2", "h c #F4F0F4", "j c #A2CDA2", "k c #BBDBBB", "l c #E0DBE0", "z c #101110", "x c #101110", "c c #DAD5DA", "v c #C2DAC2", "b c #3F9E3F", "n c #D4DED4", "m c #D1CFD1", "M c #EBECEB", "N c gray68", "B c #6C6C6C", "V c #E9E9E9", "C c #CCCDCC", "Z c #F0EAF0", "A c #5BAC5B", "S c #7BBD7B", "D c #DED7DE", "F c #0F110F", "G c gray7", "H c #D5D5D5", "J c gray93", "K c #D2DED2", "L c #E5E8E5", "P c #D2D1D2", "I c #EAEAEA", "U c #CDCDCD", "Y c #C6C6C6", "T c gray91", "R c #D0D1D0", "E c #EDEBED", "W c #D6E0D6", "Q c #D8E5D8", "! c #D8D6D8", "~ c #111211", "^ c #101010", "/ c gray75", "( c gray83", ") c #D4D1D4", "_ c #D2D2D2", "` c #BBBCBB", "' c gray80", "] c gray84", "[ c #D8D8D8", "{ c #CDCDCD", "} c #BCBCBC", "| c gray82", " . c #D2D0D2", ".. c #D9D6D9", "X. c #BEBFBE", "o. c #101010", "O. c #111111", "+. c #D2D2D2", "@. c #E7E7E7", "#. c #DFDFDF", "$. c #E6E6E6", "%. c #CDCDCD", "&. c #E1E1E1", "*. c gray89", "=. c #E2E2E2", "-. c #E1E1E1", ";. c #CDCDCD", ":. c gray90", ">. c #E1E2E1", ",. c #E7E8E7", "<. c gray82", "1. c #111111", "2. c #101010", "3. c gray86", "4. c #CACACA", "5. c gray38", "6. c #E1E1E1", "7. c #D2D2D2", "8. c #E4E4E4", "9. c #E7E7E7", "0. c #E4E4E4", "q. c #D0D0D0", "w. c gray91", "e. c gray90", "r. c gray92", "t. c gray83", "y. c gray7", "u. c #111111", "i. c #D8D8D8", "p. c gray85", "a. c #686868", "s. c LightGray", "d. c gray84", "f. c gray89", "g. c #111111", "h. c #D2D2D2", "j. c gray89", "k. c #D8D8D8", "l. c gray91", "z. c #CDCDCD", "x. c #E1E1E1", "c. c #E4E4E4", "v. c #E3E4E3", "b. c #E1E1E1", "n. c #CDCDCD", "m. c gray90", "M. c #E1E1E1", "N. c gray91", "B. c gray82", "V. c #111111", "C. c #101010", "Z. c gray", "A. c #D8D8D8", "S. c #D2D2D2", "D. c #BBBBBB", "F. c #CDCDCD", "G. c #D3D1D3", "H. c #D4D2D4", "J. c #CDCDCD", "K. c #BCBCBC", "L. c gray82", "P. c LightGray", "I. c gray84", "U. c gray75", "Y. c #101010", "T. c #111111", "R. c #D7D7D7", "E. c gray89", "W. c #C6C6C6", "Q. c #E6E6E6", "!. c #D2D2D2", "~. c #E7E6E7", "^. c #DBE3DB", "/. c #D8E2D8", "(. c #E7E6E7", "). c #D0D1D0", "_. c #ECECEC", "`. c gray83", "'. c gray90", "]. c #D7D7D7", "[. c #111111", "{. c #111111", "}. c #D5D5D5", "|. c #DDDDDD", " X c #606060", ".X c #D7D7D7", "XX c #D1D2D1", "oX c #E9E5E9", "OX c #BBD4BB", "+X c #5FAF5F", "@X c #E7E4E7", "#X c #CBCCCB", "$X c #F3F3F3", "%X c #959595", "&X c #ACACAC", "*X c #DFDFDF", "=X c gray6", "-X c gray7", ";X c gray86", ":X c gray90", ">X c #AEAEAE", ",X c #F3F3F3", " , < 1 2 3 4 5 6 7 8 9 0 q w e ", "r t y u i p a s d f g h j k l z ", "x c v b n m M N B V C Z A S D F ", "G H J K L P I U Y T R E W Q ! ~ ", "^ / ( ) _ ` ' ] [ { } | ...X.o.", "O.+.@.#.$.%.&.*.=.-.;.:.>.,.<.1.", "2.3.4.5.6.7.8.9.9.0.q.w.e.r.t.y.", "u.i.p.a.s.d.f.9.9.0.q.w.e.r.t.y.", "g.h.j.k.l.z.x.c.v.b.n.m.M.N.B.V.", "C.Z.A.p.S.D.F.G.H.J.K.L.P.I.U.Y.", "T.R.E.W.Q.!.~.^./.(.)._.`.'.].[.", "{.}.|. X.XXXoXOX+X@X#X$X%X&X*X=X", "-X;X:X>X,X c #515151", ", c #555555", "< c gray35", "1 c gray37", "2 c #656565", "3 c DimGray", "4 c #777777", "5 c #797979", "6 c #7B7B7B", "7 c gray49", "8 c #7E7E7E", "9 c #158E15", "0 c #2B9B2B", "q c #2E9C2E", "w c #359D35", "e c #399F39", "r c #38A038", "t c #44A344", "y c #44A544", "u c #4AA74A", "i c #4BA74B", "p c #4EA94E", "a c #53AB53", "s c #5AAD5A", "d c #5CAF5C", "f c #77B677", "g c #74B874", "h c #7CBB7C", "j c gray53", "k c gray54", "l c gray55", "z c #989898", "x c gray60", "c c #9B9B9B", "v c #9D9D9D", "b c #82BD82", "n c #84BF84", "m c #86BF86", "M c gray65", "N c #A7A7A7", "B c gray67", "V c gray69", "C c #B1B1B1", "Z c gray70", "A c #B4B4B4", "S c #B7B7B7", "D c #BBBBBB", "F c gray74", "G c gray", "H c #8CC28C", "J c #8DC28D", "K c #8FC38F", "L c #99C799", "P c #A0C9A0", "I c #A2CAA2", "U c #A2CBA2", "Y c #A6CCA6", "T c #A8CCA8", "R c #AECFAE", "E c #B6D2B6", "W c #B6D3B6", "Q c #B7D2B7", "! c #B7D3B7", "~ c #C1C1C1", "^ c #C3C3C3", "/ c gray79", "( c gray80", ") c #CDCDCD", "_ c #CECECE", "` c #C0D7C0", "' c #C3D8C3", "] c #C5D8C5", "[ c #D2D2D2", "{ c LightGray", "} c gray83", "| c #D5D5D5", " . c gray84", ".. c #D6D7D6", "X. c #D7D7D7", "o. c #D2DDD2", "O. c #D6D8D6", "+. c #D7D8D7", "@. c #D7D9D7", "#. c #D8D8D8", "$. c #D8D9D8", "%. c #D9D8D9", "&. c gray85", "*. c #DADADA", "=. c gainsboro", "-. c #DDDDDD", ";. c gray87", ":. c #DFDFDF", ">. c #D7E0D7", ",. c #DDE2DD", "<. c #DEE2DE", "1. c #E1E1E1", "2. c #E2E2E2", "3. c gray89", "4. c #E1E4E1", "5. c #E2E4E2", "6. c #E3E4E3", "7. c #E4E4E4", "8. c #E5E4E5", "9. c gray90", "0. c #E5E6E5", "q. c #E6E5E6", "w. c #E7E5E7", "e. c #E6E6E6", "r. c #E7E6E7", "t. c #E7E7E7", "y. c #E6E8E6", "u. c #E7E8E7", "i. c #E7E9E7", "p. c #E8E6E8", "a. c #EBE7EB", "s. c gray91", "d. c #E8E9E8", "f. c #E9E8E9", "g. c #E9E9E9", "h. c #E9EBE9", "j. c #EAE9EA", "k. c #EAEAEA", "l. c #EAEBEA", "z. c #EBEAEB", "x. c gray92", "c. c #ECE8EC", "v. c #EDE8ED", "b. c #ECEAEC", "n. c #EEE9EE", "m. c #EEEBEE", "M. c #EFEAEF", "N. c #ECECEC", "B. c gray93", "V. c #EEEEEE", "C. c #EFEFEF", "Z. c #F1EAF1", "A. c #F1EBF1", "S. c #F3EBF3", "D. c #F0ECF0", "F. c #F1EDF1", "G. c #F2EDF2", "H. c #F3EDF3", "J. c #F4EBF4", "K. c #F5EBF5", "L. c #F4EEF4", "P. c #F6ECF6", "I. c #F6EEF6", "U. c #F7EFF7", "Y. c #F8EDF8", "T. c gray94", "R. c #F1F1F1", "E. c gray95", "W. c #F3F3F3", "Q. c #F4F4F4", "!. c gray96", "~. c #F6F6F6", "^. c gray97", "/. c #F9F0F9", "(. c #FBF1FB", "). c #F8F8F8", "_. c #FBFBFB", "`. c #FDFDFD", "'. c #FEFEFE", "]. c white", /* pixels */ " ", " O O O O O O O O O X O O O O O O O O X X O O O O O O O O ", " O _ -.$.$.$.@.$.:._ A :.#.$.#. .$.$.:.A _ -.$.$.$.$.$.-._ O ", " O -.B.d.d.m.L.d.B.$.~ T.d.d.!.).m.d.F.~ -.B.d.d.F./.d.B.-.O ", " O $.d.9.a.o.E 9.9.$.G m.9.d.C M 9.8.m.G .9.9.m.' T <.d.#.O ", " O $.d.9.S.p w S.u.$.G d.9.-.j * 3 ^.d.G @.a.m.E 0 f <.m.$.O ", " O $.a.S.n a y <.m.$.G B.9.d.`.3 x T.d.G #.9.Y.f e d Q L.$.O ", " O $.u.m.J i 9 ' F.$.G d.9.B.= $ G d.B.G #.d.L.L i t I L.$.O ", " O $.d.5.S.5.R m.d.$.G l.9.9.x l B m.d.G #.d.9.a.I Y a.u.$.O ", " O -.B.d.a.d.L.9.B.-.~ C.a.d.).).Q.u.F.G -.B.d.d.L.L.a.B.-.O ", " o _ -. .$.$. .#.-.( C -.$.#. . . .#.-.A ( -.#.$. . .@.$._ O ", " X A ~ G G G G G ~ A v ~ G G G G G G ^ v A ~ G G G G G ~ A X ", " O :.F.B.l.d.B.m.C.-.^ W.m.B.B.B.B.d.!.~ -.T.B.l.B.l.m.T.:.O ", " O $.d.9.d.T.d.9.u. .G l.2.9.9.9.9.9.d.G .d.9.9.9.9.5.d.$.O ", " O $.9.B.C - 7 5.m.@.G B.9.9.9.9.9.9.B.G $.d.a.9.9.9.9.m.$.O ", " O $.a.!.x + 2 9.d.#.G l.9.9.d.u.9.9.m.G $.d.9.9.d.a.9.d.$.O ", " O $.d.9.{ _ $ F W. .G l.9.9.9.9.9.9.B.G #.d.a.9.9.9.9.B.$.O ", " O $.9.T.M - 1 -.d.$.G B.9.a.9.9.u.9.B.G $.d.9.9.9.9.9.d.$.O ", " O $.a.9.9.$.B.d.a. .G d.9.9.9.9.9.2.B.G @.d.9.9.9.9.9.a.#.O ", " O 2.T.d.B.F.d.d.C.2.~ !.d.B.B.d.B.B.T.^ -.F.d.B.B.B.d.B.2.O ", " X A ~ G G G G ~ ~ C v ^ G G G G G G ~ v A ~ G G G G G ~ A X ", " O _ -.$.#. . .$.-._ C -.#.$. .$.$.$.-.C _ -.$.#. . .@.-._ O ", " O -.B.d.T.).T.m.B.-.~ B.d.m.W.L.d.d.F.~ -.B.u.d.!.B.a.B.-.O ", " O @.a.d./ B G -.d.#.G m.2.a.! Q 9.9.B.G $.d.a.-.S } d.d.$.O ", " O $.a.B.N < @ _ T.#.G m.9.9.H w h L.l.G $.9.d.} % 4 !.9.-.O ", " O $.m.2.`.B , !.9.$.G l.5.m.>.w n P.d.G $.d.2.`.k 6 `.9.$.O ", " O $.d.9.d.& C T.d. .G B.a.<.U i s P.d.G $.d.a.9.> : 2.m.$.O ", " O $.d.d. .x u.5.a.#.G d.9.2.J b o.9.m.G $.d.d._ 7 6 / B. .O ", " O -.B.d.m.^.d.d.B.-.~ F.d.d././.m.u.T.~ -.m.9.B.).).B.B.-.O ", " o _ -.$.$.#.$.$.-._ A 2.$.$.$.@.$.$.-.A _ -.$.$. .#.$.-._ O ", " O O O O O O O O O X O O O O O O O O X O O O + O O O O O ", " " }; /* XPM */ static const char *const xpm_icon_2[] = { /* columns rows colors chars-per-pixel */ "48 48 222 2 ", " c black", ". c #010101", "X c #060606", "o c #0E0E0E", "O c #101010", "+ c #111111", "@ c gray7", "# c #131313", "$ c gray8", "% c #151515", "& c #1B1B1B", "* c gray13", "= c gray14", "- c gray15", "; c gray16", ": c gray17", "> c #2C2C2C", ", c #2D2D2D", "< c gray18", "1 c gray19", "2 c #353535", "3 c #373737", "4 c gray22", "5 c #3A3A3A", "6 c #3C3C3C", "7 c gray25", "8 c gray27", "9 c gray28", "0 c gray29", "q c #4B4B4B", "w c #505050", "e c #515151", "r c #535353", "t c gray35", "y c #606060", "u c gray39", "i c DimGray", "p c gray43", "a c #727272", "s c #7C7C7C", "d c gray49", "f c #008300", "g c #008400", "h c #008800", "j c #048C04", "k c #088D08", "l c #109010", "z c #119011", "x c #129012", "c c #159215", "v c #169316", "b c #209720", "n c #229722", "m c #269726", "M c #229822", "N c #289A28", "B c #2C9C2C", "V c #309D30", "C c #319D31", "Z c #329C32", "A c #359F35", "S c #36A036", "D c #38A038", "F c #39A139", "G c #3DA03D", "H c #42A542", "J c #45A545", "K c #47A647", "L c #4AA84A", "P c #53A953", "I c #5BAE5B", "U c #5EAF5E", "Y c #68B468", "T c #69B469", "R c #868686", "E c #898989", "W c #8D8D8D", "Q c gray60", "! c gray62", "~ c #A0A0A0", "^ c #A2A2A2", "/ c #A4A4A4", "( c gray65", ") c #A7A7A7", "_ c #A9A9A9", "` c #AAAAAA", "' c #ACACAC", "] c gray68", "[ c #AEAEAE", "{ c #AFAFAF", "} c gray69", "| c #B2B2B2", " . c #B4B4B4", ".. c #B7B7B7", "X. c #B9B9B9", "o. c #BCBCBC", "O. c gray74", "+. c gray", "@. c gray75", "#. c #8CC28C", "$. c #91C391", "%. c #90C490", "&. c #94C594", "*. c #96C696", "=. c #99C799", "-. c #9BC89B", ";. c #A0CAA0", ":. c #A1CAA1", ">. c #A3CBA3", ",. c #A8CDA8", "<. c #ACCFAC", "1. c #B1D1B1", "2. c #B5D2B5", "3. c #B5D3B5", "4. c #B6D3B6", "5. c #B7D3B7", "6. c #B8D3B8", "7. c #BED6BE", "8. c #BFD6BF", "9. c gray77", "0. c #C8C8C8", "q. c gray79", "w. c #CBCBCB", "e. c gray80", "r. c #CDCDCD", "t. c #CECECE", "y. c gray81", "u. c #C1D6C1", "i. c #C4D9C4", "p. c #C8DAC8", "a. c #C9DAC9", "s. c #C9DBC9", "d. c #CADBCA", "f. c #CFDDCF", "g. c #D0D0D0", "h. c gray82", "j. c #D2D2D2", "k. c LightGray", "l. c gray83", "z. c gray84", "x. c #D7D7D7", "c. c #D5DFD5", "v. c #D8D8D8", "b. c gray85", "n. c #DADADA", "m. c gray86", "M. c gainsboro", "N. c #DDDDDD", "B. c gray87", "V. c #DFDFDF", "C. c #D8E0D8", "Z. c #D9E1D9", "A. c #DCE2DC", "S. c #DFE3DF", "D. c gray88", "F. c #E1E1E1", "G. c #E1E3E1", "H. c #E2E2E2", "J. c #E2E3E2", "K. c gray89", "L. c #E0E4E0", "P. c #E1E4E1", "I. c #E2E4E2", "U. c #E3E4E3", "Y. c #E3E5E3", "T. c #E4E4E4", "R. c #E4E5E4", "E. c #E5E4E5", "W. c gray90", "Q. c #E5E6E5", "!. c #E6E5E6", "~. c #E6E6E6", "^. c #E7E6E7", "/. c #E7E7E7", "(. c #E6E8E6", "). c #E7E8E7", "_. c #E8E6E8", "`. c #E8E7E8", "'. c #E9E7E9", "]. c #EBE7EB", "[. c gray91", "{. c #E8E9E8", "}. c #E9E9E9", "|. c #EAE8EA", " X c #EBE8EB", ".X c #EAEAEA", "XX c #EAEBEA", "oX c gray92", "OX c #EBECEB", "+X c #ECE8EC", "@X c #EDE8ED", "#X c #EDE9ED", "$X c #EEE9EE", "%X c #EFE9EF", "&X c #EFEAEF", "*X c #ECECEC", "=X c gray93", "-X c #EEEEEE", ";X c #EFEFEF", ":X c #F0EAF0", ">X c #F1EAF1", ",X c #F1EBF1", ".F x ,. c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", "X4XeXj.,XrX", "8XF.|.kXR.W.iX2X0X0X2XuX`.Y.wXqX", "6X7XI.`.9X/.Q.qXwXwXwX`.R.7X3XeX", "*XN.5XZ.n.8XE.~.qX0X[.K.qXi.c.wX", ">XP.7X].N. c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", "X1X9X6XwX", "rX,X:X6X4X4X5X3X*X5X4X7XXXXXr.$..X*X6X5X1X+X6X3X8X.XoXE v.'.:XrX", "eX3X6XrXwXeXeXqX,XrX8XlXW.<.P.~.=.=XdX0XwX1XrX8XzXU.1.U.C.'.tX0X", "eX2X4XwX0XqXqX9X,X8XhX!.$.4X#X-XoXo.;XaX6X,X8XhXT.*.6X#X-XtXqXqX", "eX2X4XeXqX0XeXtX*XhX!.#.9XgX4X6XlX+XX.:XiX&XkXT.%.eXdX1X9XtX0XqX", "eX2X5XeXqXeX5XK.U.A.=.0XpX[.V.R.@XjX@Xo.*XsXY.&.eXuX|.L.Y.=XtX0X", "eX2X3XqX9XwX~.!.| N.{.dX@XQ.j.,.^.:XdXOX#.c.<.8XiX#XL.&.8.W.5XwX", "eX1X*X,XX_.I.| ;.(.*XyX", "eX2X5XrX8XhXF.c.s.K. XfX;Xk.,.b.c.rXeX9XaX.X+.-XgX&XW.g.N.!.8XwX", "eX2X4X8XhX!.=.'./.|.rXuX<.M..X{.t.f.jX9X5X6X@X..-XfX+X(._.1XrX0X", "eX2X6XlX!.#.0XdX,XfXuX:.F.cX,X7XlXy.s.jXeX>XhX+XX.=XzX3XeXtX0XqX", "rX,X*XR.%.0XiX%X[.=X1.F.jX8XXhXOX+..XoX XqXwXqX", "yX$Xk.5.3XfXXXv.f.b.m.cX8XtX3X7XrXqXhXi.p.e.D.*XxX].0.i.D.).eX0X", "pX[.=.*X|.1XW.1XX.eX/.2XX>X-Xo.+XjX1XXXqXeX0X0XeX1X5XwXqX0XtX4X.XyXi.a.kXwX+X:XyXqXqX", "eX3X5XdX;XX.+XdX,XeX0XqXqXeX1X5XwXqXqXqXqX2XeXhXu.a.lX2X8XqXqXqX", "eX2X3X0XaX:XX.+X8X9XwXqXqXeX2X6XeXqXqXwX9X>XwX9XjXu.f.eX5XwXqXqX", "eX2XwX0X6XiX;X| ].sX6X0X9XqXX-X6XOX] `.9X-X>XX>X,X:X@X,X>X;X2X2XE 2XeXqXqX", "wX9Xp.t.hXqX9XpXXXO.#XfX8XrX2X6XrXwXwXeX0X,XrX0XyXeX=.I.eXqXqXqX", "eX1XpXl.q.gX0X5X5X:X..@XsX9X1X5XwXqXqXqX9X>X0XrXeX$.W.eX2XwXqXqX", "eX2X6XzXj.w.gXrX>XgX;XX.+XgX>X5XwXqXqXqX0X:XyXeX%.R.xXX@.`.eXeXeXeXeXeX-X-.W.xX c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", "X:X:X>X:X:X>X:X$XrX0XW.OXwX@X>X:X:X:X:X{.:X>X:X:X,X$X,XdXX5XwXqXqX", "qX0XtX&X%X5X2X2X2X2X2X4X;X#X5X2X2X2X4Xm.0XR.I ` wXN.0X1X2X2X4X`.,X3X2X1X9X~.(.1X0 &.sXD.=XtXqXqX", "qXqXeX,X5XtXeXeXeXeXeXtX6X>XyXwXeX0XhX(.c.N.q.@Xd.*XpXqXeXeXtX>X0XrXeXeXqXaXg.G.<.p.Y.G.yX0XqXqX", "qX0XrX:X2XeX0XqXqXqX0XwX3X;XeX0X9XrXrX~ <.~.~.Y.| $.hX0X0X0XeX*X8XqXqX6XlXS.H F.).W.D.6XeXqXqXqX", "qX0XrX:X2XeXqXqXqXqXqXeX3X;XrX8XrXyXY u.cX;X~.6XlX@.O.jX0X0XeX*X8XwX7XlXA.Z 2XaX`..XiXeX0XqXqXqX", "qX0XrX:X2XeXqXqXqXqXqXqX6XX4XtXwXeXqXpXL.Y.t.X.Y.e.uXqXpX].G.y.` K.A.%XuXqXzX$.+.iXN.D 4XaX0XeXB.[.+.,.).D.uX0XqXqX", "qX0XrX:X;X6X3X3X6X=XC.fXY.y ~.+XW.0X6XB.2XrX&...9XZ.wX1X2XiX#.C ! &X0XX;X;XX5XyXeXrXwXpXL.`.5.+. XA.,XtXaX^.'.@.L D.R.oXpXeXrXeXrX0X#.@.zXwXtX4XB.,X..:.:XN.wXqXqXqX", "qX0XrX:X2XwX0X8XeXtXE 8.]..XA.`.uX7XlX,.' }.|.R.U l.zX6X0X0XwX&XfX#.o.jX8XyX}.B.oX|.m.*XyX0XqXqX", "qX0XrX:X2XeX9XrXyXY p.iX!.K.,XuX7XzX>.[ yX}.F.&X7XK l.zX7XqXeX&X7XlX#.O.jX9XyX2XP.E.8XyX0XqXqXqX", "qX0XrX>X2X0XrXyXY i.zXqX0X4XtX7XzX>.] fXeXtX1XyXyXqXJ z.xX6XqX*X6X9XkX#.O.jX8XrX5X9XeX0XqXqXqXqX", "qX0XrX;X2XhXrXY i.xX6XaX3X*XsXlX>.] fXqX0X9X%XwX8XyXqXJ l.cXuX$XwXuX8XkX#.O.hXsX=X2XsX0XqXqXqXqX", "qX0XrX-XJ.(.~ u.xX7XyX].I.G.^.,.[ fXqX0XwX9X*XwXqX9XyX0XI a._.P.J.OXyX8XkX#.@._.I.D.(.yX0XqXqXqX", "qX0XuX|.m.n.,.cX6XiX^.D.r.c.].' yXeX0XwXwX0X*XeXqXwX9XaX=X .m.-.P.C.XXyX0XdXo.S.3.Y.T.T.iX9XqXqX", "qX0XtX*Xt =XR.>XeX4XN.dX0.D nX^.|.tX9X9X0X8X&XqX9X9X8XyXQ.#X#Xt.M 7XV.eXeXOXQ.hXE -.MXM.2XeXqXqX", "qX9XaX^.=.fXF.(.2X'.D.cX].Y cX`.H.1X%X*X*X&X}.=X*X*X%XX9XpXhX+.@.kX8XuXqX2XsX0XqXqXqXqXqX9X*XwXqXqXqXqXqXqXsX,XrXdX0XJ z.xX5XaX4X8XiX9XqXqXqXqX", "qX0XrX:X1XqX0XjX+.@.jXqX1X-XwX0XqXqXqXqXqX9X*XwXqXqXqXqXqX0XqX&X7X9XyXqXJ z.zX9X;XX;Xs #XuX0XqXqXqXqX", "qX0XyX%XB z.jX4X8X8X7X8XsX_ +.fX7X7X8X8X8X6X%X9X8X8X8X8X8X8X0X%X5X9X8X8X7X6XgX1.[ 8XwX0XqXqXqXqX", "qXqXwX3X1XL c.xX8XwXwXeX2XqX%.@.kXqXqXwXwX0X*XeXqXwXwXwXwXqXrX=X9XeXwXqX9XzX1.[ 7X3XwXqXqXqXqXqX", "qX0XrX-X7XwXG c.zX7XqXeX3X-XzXO.@.kX0X0XqX9X*XwXqXqXqXqXqX0XeX*X8XwX0X8XzX<._ hX>X1XeXqXqXqXqXqX", "qX0XrX:X,XiX0XH c.zX7XeX3X=XwXjX+.@.kX0XqX0X*XwXqXqXqXqXqXqXeX*X8XqX8XzX<.` dXrX-X1XeXqXqXqXqXqX", "qXqXeX,X9XqXtX0XH c.zXqX0X3XtX8XkX+.@.kX0X9X*XwXqXqXqXqXqXqXeX*X8X9XzX<.` fX0XrX5X8XrX0XqXqXqXqX", "qX0XtX&X).wXwXtX0XG c.fX].W.5XyX9XkX+.@.kX8X&XwXqXqXqXqXqXqXeX*X5XxX<.` fX0XtX6X~._.qXtX0XqXqXqX", "qX0XrX-XI.V.>XwXtX9XU 0.L.Y.m.|.yX8XjXO.@.hX&XqX0X0X0X0X0X0XwX&XhX1._ dX0XtXoXC.Y.U.V.:XtX0XqXqX", "qX0XiX|.~ }.Z.yX0XdXS.#X@._ dXv.3XyXwXzX$.@.3XrXeXrXrXrXrXeXrX5X,.{ hXrXrX6XC.'.T _ {.C.eXqXqXqX", "qXqX7XvX( M./.].5X.XA.cXQ.U bX_.U.6X-X:XeX` 6.0X-X>X>X>X>X-X0Xt.E 9X>X-X5XT.@X3.t.*.z.).#XyX0XqX", "qX0XwX8Xv W.R.oX8X%XC.lXh.j 8X_.W.9X1X1X2X9X%X3X2X2X2X2X2X2X3X%X8X3X1X1X8X^.|.z.E K U.W.*XtXqXqX", "qX0XuX|.m.OXZ.pXqXaXF.`.h.=.G.C.6XtXeXeXeXwXyXeXeXeXeXeXeXeXeXyXwXwXeXeXrXwXn.;Xs.n.+XC.yX0XqXqX", "qXqXeX4XR.Z.7XeX0XwX9XS.W.'.A.&XyX0XqXqXqX0X0XqXqXqXqXqXqXqXqX0X0XqXqXqX0XtX:XN.(.Q.C.6XeXqXqXqX", "qXqXwX4X&XyXeX0XqX0XwXuX*X+XqXyX0XqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqX0XtXeX#X&XyXeX0XqXqXqX", "qXqXqXwXtX0XqXqXqXqXqX0XtXyXqX0XqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqX0XqXyXtX0XqXqXqXqXqX", "qXqXqXqXqXqXqXqXqXqXqXqXqX0XqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqX0XqXqXqXqXqXqXqX", "qXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqX" }; const char *const *const xpm_icons[] = { xpm_icon_0, xpm_icon_1, xpm_icon_2, }; const int n_xpm_icons = 3; puzzles-20170606.272beef/icons/sixteen-icon.c0000644000175000017500000004704713115373753017574 0ustar simonsimon/* XPM */ static const char *const xpm_icon_0[] = { /* columns rows colors chars-per-pixel */ "16 16 256 2 ", " c black", ". c #010101", "X c #020202", "o c gray1", "O c #040404", "+ c gray2", "@ c #060606", "# c #070707", "$ c gray3", "% c #090909", "& c gray4", "* c #0B0B0B", "= c #0C0C0C", "- c gray5", "; c #0E0E0E", ": c gray6", "> c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", "X=X;X9XeX,XQ.*XrX", "rXhXI.&.z.yXsXR.q.V.uXeXG.Z.K.0X", "yXpX>X$X3X9XtX1XoX,X0XeX:XR.%XrX", "yXrX0XrX0X6XwX0XtXqX6XrXrXeXeXqX", "wXeXwXrXyXpXeXwXrXtXaXpXqXtXeXqX", "wX9XwX9X:X=X8XqX9X>X2XyX1X^.;XrX", "0X8XrX2Xi.5.;XyX6Xt.*.3XK.C.K.0X", "qX9XwX0XOX&X7XwXqXOX&XtX*XY.@XrX", "qX7X0X0XeXeX8X0X0XwXuXiXrXeXeXqX", "qXeXtXrXwXwXeXtXtXwXeXeX0XqXqXqX", "0XrX,XF.:XrXeX2XG.=XtX0XqXqXqXqX", "0XtXQ.Z.E.eXtX^.Z.Y.eXqXqXqXqXqX", "0XeX*XK.%XeXeX;XK.@XeXqXqXqXqXqX", "qXqXrX0XrXqXqXrX0XrXqXqXqXqXqXqX" }; /* XPM */ static const char *const xpm_icon_1[] = { /* columns rows colors chars-per-pixel */ "32 32 256 2 ", " c black", ". c #010101", "X c #020202", "o c gray1", "O c #040404", "+ c gray2", "@ c #060606", "# c #070707", "$ c gray3", "% c #090909", "& c gray4", "* c #0B0B0B", "= c #0C0C0C", "- c gray5", "; c #0E0E0E", ": c gray6", "> c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", "XiXqX0X9X0XiXqXqXqXqX", "9XpXgX9XeXgXeXiXdX0XeX2XaXqXwXfXtXpXfXqXeX2XpX0XtXsXrXT.tXqXqXqX", "9XpXgX9X9XC.1X}.P.yXqX2XaX0XwXD.%X/.H.0XeX1XiXtX%XR.Y.9.L.uXwXqX", "9XpXgX7XaX%.F.-.( `.aXXsXqXqXqXqX9XqXqXqXqX", "0XeXsXaXrXhXpXaXaXaXaXdXdXaXeXgXaXaXaXaXpXgXzX9XqXqXqX0XqXqXqXqX", "qXqX0X9X2XaX8X0X8X0X9X8X9XqX c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", "X,X[ 8.eX0XrX:XrXsX8XrX,X` h.yX>.] '.uX0X0X-XzX7XpXL.t.l.y.c.l.N.aXqXqXqXqX", "qXqX9XpXvX8XqXrXXXd %X%.&.L A.fXwX:XrXsX8XqXtX&.` tX#X{ { lX8X0X-XzX7XsXb.S.Q.R.~.'.g.A.rXqXqXqX", "qXqX9XpXvX8XwX0XhXS :X_ m.| j.hXwX:XrXsX9X8XxXM.' VX/.R #XyX0X0X-XzX7XaXN.Y.[.`.!.~.(.>..R.N T :XrXeX:XrXsX8XrXX;X:X:X:X:X:X:X:X-X@XzX9XwXqXqXqXqX0XqXqXqXqXqXqXqX", "qXqX0XuXlXeXyXqXwXtXrXrXrXrXrXrXtXeXxXiXrXrX9XtXrXrXrXrXrXrXtXwXgXvX8XwXqXqXqXqXqXqXqXqXqXqXqXqX", "qXqXqXqXiXaXfX3XlXfXaXsXsXsXsXsXaXsXiXaXdXrX0XbXiXsXsXsXsXsXsXpXlXvX8XwXqXqXqXqXqXqXqXqXqXqXqXqX", "qXqXqXqX9X8XwX$XfXqX8X9X9X9X9X9X9X9X9X9XqX1X2XhX5X9X9X9X9X9X9X7XiXvX8XwXqXqXqXqXqX0XqXqXqXqXqXqX", "qXqXqXqXqXqXrX*XhXeXqXqXqX9XqXqX9X9XqXqXeX3X4XjX8XwXqX0X0XqXqX8XpXvX8XwX0X9X0X8XwXtX9XqXqXqXqXqX", "qXqXqXqXqX0XrX*XhXeXqX0XrXsXeXqXaXfXeX0XeX3X4XjX8XwXqXpXiXqX0XiXkXcX8XqXtXaXsXtX<.=XpX9XqXqXqXqX", "qXqXqXqXqX0XrX*XhXeX0XeX>XQ.1X9X).I. c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", ".T.1X2XyX8X#XQ.", "].b + I U.k.^.A. X8Xn.-X3XE.", "].N # j ;X5.} -XH.tX( E.7XR.", "].b + A W.E.K.P.`.X4XE.", "_.] j N f 3.Q.c.A.V.=X1X8X1X#XW.", "Q.`.[.].[.(.(.L.G.).W.E.T.E.W.!." }; /* XPM */ static const char *const xpm_icon_1[] = { /* columns rows colors chars-per-pixel */ "32 32 256 2 ", " c black", ". c #010101", "X c #020202", "o c gray1", "O c #040404", "+ c gray2", "@ c #060606", "# c #070707", "$ c gray3", "% c #090909", "& c gray4", "* c #0B0B0B", "= c #0C0C0C", "- c gray5", "; c #0E0E0E", ": c gray6", "> c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", "XG.*...q.|.:X_.Q.!.", "~.R.%XqXO.7.^.T.1.o.iXd. X X u.nXe.O.I.~.s.) X:XT.~.", "~.R.*XO.D.wX^.2XMXV.=.j. + o o o o + v.c.>.sXXX*XxX$X/ !.^.!.", "Q.'.k.1.CXf.Q 3 T.VX8.! . X 7.+.iX+Xz c qXkXH.X.{.W.", "E.}.@.L.gX9Xo.9 XjXQ.c o . / u.aXfXK.l aXwX>X_ ^.Q.", "E.}.@.P.sXXX_.9 x.bXE.c o . / u.sXuXx.f 0XeX>X_ /.Q.", "Q.'.k.2.MX*.G J [.mX8.~ . X 7.+.pXXXB t ;.nXF.X.}.W.", "~.R.=X@.S.nXrXlXNXV.-.h. o o v.b.>.jXsXdXjX&X( ~.~.!.", "~.R.#X5X{ 4./.!.3.[ eXs. X X & * O X y.lX8.} C.I.i.! ].-XT.~.", "!.Q._.*X6X1.d s 1.7X*XR.A.W.f.] ( 7.T.G.E.@XX_.Q.!.", "~.R.@XuX<.;.C.D.;.1.qX%XzXh.#.M.V.<.:.tX=X8X0XpXcXzXfXeXeX+XE.~.", "~.T.:X<.p.hXhX9XgXs.&.0Xe.,.uX6XrXkXV.} %X9XqX0X@X;XuX9XrXOXE.~.", "Q._.M.*.lXdX` > :XnX&.u.+.zX!.0 ( iXvX9.t.aXpXA.G g l.sXwXOXE.~.", "W.}.%.F.bXA.) f 1XgXE.k N.aXdX7.J hXyX`.o.sX0X1XvXS ..lXqXOXE.~.", "E.}.O.U.sXz _ = n.zX/.p S.iXlX0.K zXrX|.X.aX9XrXO./ eXqXrXOXE.~.", "Q.].i.e.zXm.<.3 B.VXr.o.2.nXT.d 6 a.BXx.<.sXsXz. A t.pXwXOXE.~.", "!.E.@X' ^.SXzX8XBX^.^ ,X#.A.gX;X:XeX=X~ '.wXwX3X>XoX-XwXrXOXE.~.", "~.T.:X4X| j.XX#Xk. .>X>X5X{ e.$X:XC.Q '.:X8XwXrXyXiXtXqXtX+XE.~.", "!.~.P.L.A.( Z Z ( A.L.Q.%X3Xq.v h ..$X:X_.+X@X+XOXOX+X+X#X].Q.!.", "E.}.+. O % $ $ & . A.lXn.+.t.a.=.8.qX@X6X0X8X0X8X7X8XwXOXE.~.", "E.}.+. o . E.S. .7XsXtXyXi.-.:X8XqXyX0XtXaX0XtX+XE.~.", "E.}.+. o . c.} jXm.s Y ^.ZX-.h.iXpXH.D N J.pXwXOXE.~.", "E.}.+. o % .g.CX9.> I |.hX^.+.dXwX@XrXD ' lXqXOXE.~.", "E.}.+. o * ) V.hX#X7XD ] nX{.o.aX7XgXd.W 7XwXrXOXE.~.", "E.}.+. o @ <.6.mXi.` s k.BXV.-.sXsXv. D j.uXwXOXE.~.", "E.}.@. @ o o o o o P.+.~.aXR.+XvX8X/ E.eXeX&X_.U.{.eXeXOXE.~.", "E.}.+. o . P.5X( N.7X6XR._ I.X_.OX+XOXoXoXoXOX@X'.W.!.", "!.Q.).|.}.}.}.}.}.}.|.^.T.Q.}.(.^.{.(.Y.Q.E.E.E.E.E.E.E.E.W.!.!.", "!.!.Q.E.E.E.E.E.E.E.E.!.~.!.W.Q.!.W.Q.~.!.~.~.~.~.~.~.~.~.!.!.!." }; /* XPM */ static const char *const xpm_icon_2[] = { /* columns rows colors chars-per-pixel */ "48 48 256 2 ", " c black", ". c #010101", "X c #020202", "o c gray1", "O c #040404", "+ c gray2", "@ c #060606", "# c #070707", "$ c gray3", "% c #090909", "& c gray4", "* c #0B0B0B", "= c #0C0C0C", "- c gray5", "; c #0E0E0E", ": c gray6", "> c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", ". o . - _.uXjXj.x ( 0.r.O.x %.uXyX(.Q.!.!.!.", "!.!.~.R.#XyXJ ) 7XMXVXvXgXXXv >.kX:. @ o o o o o o o O > /.kX:.b XXvXNXmXjX5X) K wX).W.!.!.!.", "!.!.~.Y.4X%.) mX5XR.G.|.rXaXrXl S.0. o . * OXS.l tXsX|.P.(.8XeXbX_ @.@XR.!.!.!.", "!.!.!.^.W.n 2XjXl.w g X 8.uXsXY.D 5. o . - }.D U.lX#Xc X d wX9XeX6Xx A.(.Q.!.!.", "!.!.W.}.-.O.jX8X5X].A.O E gX7XqXU Q X . 4 k.H wXqX5X0XR w tXqX7XjXX.#.|.W.!.!.", "!.!.E.XXE y.kX6XfX>.* & T.aX6XfX} N . . 0 1.^ jX8X9XhXT 0 wX0X8XkXy.E XXE.!.!.", "!.!.E.XX! e.jX7XeXlXjXs h iX8XsX[ C . . 9 4.! fX8X0XVX( y vXtX7XjXw.! XXE.!.!.", "!.!.W.[.0.) gXtX$.U ) U pX0X5XG [ X . 1 C.A 5XrXX(.Q.!.!.!.", "!.!.!.Q.'. X[.9XXX .d l 7.1X1X].{._.$XOX2X#Xj.%.%.j.#X2X+XoX(..X{.$X-XY.g.s.D.$X=X}. X/.!.!.!.!.", "!.!.~.R.$XiXfXr.c ` 2.>.U M J.cX. ] 4X0XsX .h 2.jX7XwXnXb S BXqX7XlX+.;.lX8X9XaX{.r _ lXtX0XqX0X).Q.!.!.!.", "!.!.W.{.2.} jX9X| b u r #XyX8XG =.! iXwX-Xe.5 0 u.>XqXsXJ h.dX7XpX~.o 1 :.<.>XrXqX0X).Q.!.!.!.", "!.!.!.~._.b ;XuXeXlX%XD {.uXhXS.N &XM ).lX XF L J K OXjX`.l {.eX8XaXU.D R N G -XrX0X0X).Q.!.!.!.", "!.!.~.Y.4X8.H jXuX6X9XfXwXhX,Xd A.5Xv.x tXhXhXfXfXhXgXrXc h.*X0XqX0XyXkXhXlXkXeX0XqX0X).Q.!.!.!.", "!.!.~.R.+XdX` S oXaXhXsXyXP.a g.eX[.zX,.b `.uXdXdXuX`.v 2.pX].rXwXeXqX9X9X9X9XwXwXeXwX).Q.!.!.!.", "!.!.~.R.%XaXhXp.n ) ,.;.U C I.vX2X}.6XuXf.f T 1.1.T f f.pX>X[.6X5X5X5X5X5X5X5X5X5X5X4X(.Q.!.!.!.", "!.!.Q./.C.i.s.M.y.~ M C | k.b.u.k.).}._.3X$X*.g h *.%X3X`.[.(.}.{.{.{.{.{.{.{.{.{.{.{.^.!.!.!.!.", "!.!.E.|.] o o # # . X q #XwXhXY.G P . .P G U.lX4X}.rXwXeXeXwXwXwXeXeXwXeXwX).Q.!.!.!.", "!.!.E.|.[ + X . . o e oXjXa.s Z.0XhXhX0XC.a f.iX].wX0XqX0X0XeXqX9XqXqXqX0X).Q.!.!.!.", "!.!.E.|.] o X 9 .lX8X0XrXcXhXf x tXqXqX0X).Q.!.!.!.", "!.!.E.|.] o X x #.$.lX8XwXdXSX .. &XeXkX@.-.lX8X9XpX-Xx C rXuX9XqX0X).Q.!.!.!.", "!.!.E.|.] o X g p.W aXuXb.:.B.e w 6X0XdXY p.fX7XuX}., < a.c.1XeXqX0X).Q.!.!.!.", "!.!.E.|.] o X e .Xn XXjXK.N d S ).tXuX@Xj _.rX8XsXF.t n u h *XtX0X0X).Q.!.!.!.", "!.!.E.|.] o X 9 3Xy.S hXgXsXuXsXrXyXjXD 8.=X0XqX0XtXsXiXaXsXwXqXqX0X).Q.!.!.!.", "!.!.E.|.] o X q +XfX' J -XgXhXgXhX;XH { tX[.eXqXqXqX0X0X0X0XqXqXqXqX).Q.!.!.!.", "!.!.E.|.[ @ o o o o o o o O e +XeXiX5.h ] r.r.] h 5.sX4X{.wX0X0X0X0X0X0X0X0X0XqX0X).Q.!.!.!.", "!.!.!.~.L.C.A.Z.Z.Z.Z.Z.Z.Z.Z.Z.D.^.(.(.@XL.=.W W -.L.@X(.(./.).).).).).).).).).).).).!.!.!.!.!.", "!.!.!.!./.).).).).).).).).).).).(.!.Q.Q.R./.}.XXXX}./.R.Q.Q.!.Q.Q.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.E.E.W.Q.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.", "!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.", "!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!." }; const char *const *const xpm_icons[] = { xpm_icon_0, xpm_icon_1, xpm_icon_2, }; const int n_xpm_icons = 3; puzzles-20170606.272beef/icons/signpost-icon.c0000644000175000017500000003316113115373753017753 0ustar simonsimon/* XPM */ static const char *const xpm_icon_0[] = { /* columns rows colors chars-per-pixel */ "16 16 227 2 ", " c #A4A4A4", ". c gray63", "X c #A1A19F", "o c #9F9F9F", "O c #9F9F9F", "+ c #9F9F9F", "@ c #9F9F9F", "# c #A0A0A0", "$ c gray63", "% c #A2A2A2", "& c #9F9F9F", "* c #9F9F9F", "= c #9F9F9F", "- c #9F9F9F", "; c gray63", ": c #A4A4A4", "> c gray63", ", c #CECED0", "< c #DCDCE6", "1 c #E2E2E2", "2 c gray89", "3 c #E2E2E2", "4 c gray90", "5 c gray85", "6 c gray83", "7 c #DADADA", "8 c #E2E2E2", "9 c gray89", "0 c #E2E2E2", "q c #E7E7E7", "w c #D0D0D0", "e c #A1A1A0", "r c #9F9F9F", "t c #E3E3E4", "y c #DEDEFF", "u c #F9F9FE", "i c white", "p c #FEFEFE", "a c gray94", "s c #ECECEC", "d c #D2D2D2", "f c #F4F4F4", "g c #FDFDFD", "h c gray89", "j c #9F9F9F", "k c #9F9F9F", "l c #E1E1E2", "z c #D7D7FE", "x c #EFEFFB", "c c #FFFFFD", "v c #FDFDFD", "b c #EEEEEE", "n c gray90", "m c #D7D7D7", "M c gray95", "N c #FEFEFE", "B c #FBFBFB", "V c #E1E1E1", "C c #9F9F9F", "Z c #9F9F9F", "A c #E2E2E3", "S c #FBFBFC", "D c #EEEEEE", "F c gray93", "G c gray95", "H c #ECECEC", "J c #FEFEFE", "K c #F8F8F8", "L c #FDFDFD", "P c gray90", "I c #9F9F9F", "U c #9F9F9F", "Y c #E3E3E2", "T c gray99", "R c #D0D0D0", "E c #CACACA", "W c #EFEFEF", "Q c #EEEEEE", "! c white", "~ c #EAEAEA", "^ c #CACACA", "/ c #C3C3C4", "( c gray86", ") c gray63", "_ c #9F9F9F", "` c gray89", "' c #F9F9F9", "] c gray75", "[ c #BBBBBB", "{ c gray89", "} c #F1F1F1", "| c #E6E6E6", " . c #C5C5C5", ".. c #C1C1C0", "X. c #DADADA", "o. c gray63", "O. c #A0A0A0", "+. c gray85", "@. c gray97", "#. c #EEEEEE", "$. c gray95", "%. c gray88", "&. c gray87", "*. c #E6E6E6", "=. c #E1E1E1", "-. c #F3F3F2", ";. c #EDEEED", ":. c gray96", ">. c #ECECEC", ",. c #E9E9E8", "<. c #DDDDDC", "1. c #9F9F9F", "2. c gray63", "3. c #D5D5D5", "4. c gray88", "5. c #E9E9E9", "6. c #EFEFEF", "7. c gray94", "8. c #F4F4F4", "9. c #E1E1E1", "0. c #9880CA", "q. c #9275CF", "w. c #967AD2", "e. c #9377CF", "r. c #9378CE", "t. c #9678D6", "y. c #9985C2", "u. c #A5A7A2", "i. c #9F9F9F", "p. c gray89", "a. c gray86", "s. c gray93", "d. c #FEFDFE", "f. c #F2F1F2", "g. c #886DC0", "h. c #795ABC", "j. c #8565CA", "k. c #8766CD", "l. c #8061C2", "z. c #916BE1", "x. c #977ECB", "c. c #A5A7A1", "v. c gray63", "b. c #DADADA", "n. c #D8D8D8", "m. c #F4F4F4", "M. c #FEFEFE", "N. c gray94", "B. c #8D73C5", "V. c #8766CC", "C. c #8D6DD1", "Z. c #8C6CD1", "A. c #896ACB", "S. c #936FE0", "D. c #9780C9", "F. c #A5A7A1", "G. c #9F9F9F", "H. c gray89", "J. c #FDFDFD", "K. c #FDFDFD", "L. c #F1F1F1", "P. c gray96", "I. c #EDEDEC", "U. c #967AD3", "Y. c #936FDF", "T. c #9371DB", "R. c #9673E0", "E. c #8566C5", "W. c #8564CD", "Q. c #9B82CE", "!. c #A4A6A0", "~. c #E2E2E2", "^. c #FBFBFB", "/. c #CDCDCE", "(. c #AAAAAA", "). c #E2E2E2", "_. c #977CD2", "`. c #906EDA", "'. c #9271D9", "]. c #916FD7", "[. c #7057A5", "{. c #7457B2", "}. c #9880C9", "|. c #A5A7A1", " X c #9F9F9F", ".X c gray89", "XX c gray97", "oX c #C6C6C6", "OX c #D8D8D8", "+X c #E5E5E4", "@X c #9678D6", "#X c #8F6ADF", "$X c #926EDF", "%X c #8B68D4", "&X c #684EA0", "*X c #6B4DAB", "=X c #947BC8", "-X c #A6A8A2", ";X c gray63", ":X c #E7E7E7", ">X c gray89", ",X c gray88", " , < 1 2 3 4 5 6 7 8 9 0 q w e ", "r t y u i p i a s d f i g i h j ", "k l z x c v i b n m M N B i V C ", "Z A i S i D F G H i J i K L P I ", "U Y i T i R E W Q i ! ~ ^ / ( ) ", "_ ` i i ' ] [ { } i i | ...X.o.", "O.+.@.#.$.%.&.*.=.-.;.:.>.,.<.1.", "2.3.4.5.6.7.8.9.0.q.w.e.r.t.y.u.", "i.p.a.s.i d.i f.g.h.j.k.l.z.x.c.", "v.b.n.m.i M.i N.B.V.C.Z.A.S.D.F.", "G.H.i J.K.L.P.I.U.Y.T.R.E.W.Q.!.", "= ~.i ^.i /.(.)._.`.'.].[.{.}.|.", " X.Xi i XXoXOX+X@X#X$X%X&X*X=X-X", ";Xw :X>X,X c #755AB0", ", c #775CB1", "< c #785BB3", "1 c #785CB2", "2 c #7B5FB7", "3 c #7859BA", "4 c #7E61BD", "5 c #7F61BE", "6 c #7D5EC0", "7 c #8062BE", "8 c #8163C0", "9 c #8263C2", "0 c #8160C7", "q c #8365C5", "w c #8567C5", "e c #8566C6", "r c #8567C6", "t c #8566C7", "y c #8568C5", "u c #8667C9", "i c #8563CD", "p c #8A6ACD", "a c #8A6ACE", "s c #8B6ACF", "d c #8F78C1", "f c #9179C4", "g c #9179C5", "h c #927AC4", "j c #927AC5", "k c #927BC5", "l c #9178C7", "z c #937AC6", "x c #937BC6", "c c #937BC7", "v c #9177C8", "b c #9278C8", "n c #8A68D1", "m c #8C6BD1", "M c #8C6CD2", "N c #8D6CD3", "B c #8C6AD6", "V c #8E6ED4", "C c #8F6BD9", "Z c #8F6CD9", "A c #906ED6", "S c #906FD7", "D c #916FD8", "F c #916FD9", "G c #906DDB", "H c #906CDD", "J c #916DDD", "K c #926FDD", "L c #906CDE", "P c #916CDE", "I c #926EDE", "U c #936EDF", "Y c #9170D8", "T c #9170D9", "R c #9271D8", "E c #9270D9", "W c #9271D9", "Q c #9372D8", "! c #9270DA", "~ c #9271DA", "^ c #9270DB", "/ c MediumPurple", "( c #9371DB", ") c #9371DC", "_ c #9573DE", "` c #9573DF", "' c #9674DE", "] c #8E67E1", "[ c #916AE3", "{ c #936FE0", "} c #936EE1", "| c #936EE2", " . c #956EE7", ".. c #9570E2", "X. c #9774E1", "o. c #9D9D9D", "O. c #9D9D9E", "+. c gray62", "@. c #9F9F9F", "#. c #A09F9F", "$. c #A5A79F", "%. c #9583B9", "&. c #9C8EBA", "*. c #9C8EBB", "=. c #9C8CBD", "-. c #9C8DBD", ";. c #9D8EBC", ":. c #9E8FBD", ">. c #9E8FBE", ",. c #9D92B2", "<. c #9D92B3", "1. c #A19AAF", "2. c #A0A0A0", "3. c gray63", "4. c #A5A7A0", "5. c #A6A7A1", "6. c #A5A5A3", "7. c #A5A6A2", "8. c #A5A7A2", "9. c #A4A3A5", "0. c #A4A4A4", "q. c #A5A5A5", "w. c gray65", "e. c #A5A8A0", "r. c gray66", "t. c #A9A9A9", "y. c #AAAAAA", "u. c gray67", "i. c #ACACAC", "p. c gray68", "a. c #AEAEAE", "s. c #AFAFAF", "d. c gray69", "f. c #B1B1B1", "g. c gray70", "h. c #B4B4B4", "j. c #B5B5B4", "k. c gray71", "l. c #B9B9B9", "z. c #BCBCBC", "x. c gray", "c. c gray75", "v. c #C1C1BE", "b. c #BFBFF7", "n. c #BBBBF8", "m. c #C0C0C0", "M. c #C1C1C1", "N. c #C3C3C3", "B. c #C8C8C8", "V. c gray79", "C. c #CACACA", "Z. c #CACACB", "A. c #CBCBCB", "S. c #CCCCCA", "D. c #CCCCCB", "F. c #CDCDCB", "G. c #CFCFCA", "H. c #CECECB", "J. c #CBCBCC", "K. c gray80", "L. c #CDCDCD", "P. c #CDCECE", "I. c #CECECE", "U. c gray81", "Y. c #D0D1CD", "T. c #D0D0D0", "R. c #D2D2D2", "E. c LightGray", "W. c gray83", "Q. c #D6D5D6", "!. c #D7D7D7", "~. c #D8D8D8", "^. c #DADADA", "/. c gray86", "(. c gainsboro", "). c #DDDDDD", "_. c gray87", "`. c #DFDFDF", "'. c #E2E3DE", "]. c #C4C4F6", "[. c #C4C4F8", "{. c #C6C6F9", "}. c #CACAF8", "|. c #DBDBFB", " X c #DCDCF9", ".X c gray88", "XX c #E1E1E1", "oX c #E2E2E2", "OX c #E2E2E3", "+X c gray89", "@X c #E4E6E0", "#X c #E5E7E1", "$X c #E6E7E2", "%X c #E4E4E4", "&X c gray90", "*X c #E6E6E6", "=X c #E7E7E7", "-X c #E6E8E1", ";X c #E6E8E2", ":X c #E9EAE5", ">X c #E9EBE5", ",X c #EAEBE5", "X@X'.;X@X@X@X@X'.;X@X>Xv.#.0.", "0.@.z.&X&X&XoX).oX).).).'.).+XY.%.l l c l l h z z z l k l ,.5.9.", "0.@.L.mXQ.).fXmXmXmXmXmXmXmXmX;Xb .F B ..} ) F F I I ) [ ;.e.9.", "0.@.L.yX2Xm.L.mXfXmXhXmXmXfXmX'.l n ; 7 ) y ' s - B ( W I *.e.9.", "0.@.A.mXiXA.yXmXkXmXmXkXmXmXmX;Xf : 1 5 e = u ) > M ) W H *.e.9.", "r.@.L.yXi.A.0XmXmXmXmXkXmXkXmX;Xf 5 1 q A 5 W p = 9 W W H *.5.9.", "0.@.L.iX~./.&XmXkXmXmXkXmXhXmX'.l I Y I W W ( F F ) ) W H ;.e.9.", "0.@.A.mXmXmXmXmXmXmXmXmXmXmXmX@Xl I W W W ) F I F s M W I *.e.9.", "0.@.A.mXfXmXfXmXkXmX&X&X2X&XmX;Xk ) W W W F W ) s o & F H *.e.9.", "0.3.A.mXfXmXkXmXmXmX/.i.f.r.8X>Xl I W W F W W ..N o * ' } *.$.0.", "0.@.A.mXmXmXkXmXmXmXfXz.f.f.0X>Xl I W I ) W Y u 9 @ & y i *.e.9.", "0.@.A.mXfXmXmXmXmXiXN.r.z.i.0X>Xf F W W F W W < @ @ o 0 ;.5.9.", "r.@.A.mXfXkXfXfXmX+Xr.m.mXQ.5X>Xl I W W W W W ' 2 . @ y ..*.e.9.", "0.@.A.mXmXmXmXmXmXmX2XfXmXmXmX;Xl [ I I I H C [ .3 6 ..] ;.5.9.", "0.3.k.L.A.A.A.A.A.A.U.L.A.A.L.v.,.;.*.*.*.*.;.*.*.>.>.*.;.1.5.9.", "0.0.0.@.@.@.@.@.@.@.@.@.o.@.@.2.5.e.$.e.e.e.e.e.e.e.4.4.5.5.9.0.", "0.0.0.0.0.0.0.0.r.0.0.0.0.0.0.0.9.9.9.9.9.9.9.9.9.9.9.9.9.0.0.0." }; /* XPM */ static const char *const xpm_icon_2[] = { /* columns rows colors chars-per-pixel */ "48 48 55 1 ", " c #634C94", ". c #664E99", "X c #6E54A5", "o c #7055A7", "O c #7157AA", "+ c #7459AE", "@ c #775AB2", "# c #7B5FB7", "$ c #7C5FB9", "% c #7E61BC", "& c #8063BF", "* c #8F7ABC", "= c #8264C3", "- c #8667C8", "; c #8A6ACD", ": c #8F74C7", "> c #8F75C8", ", c #9176CA", "< c #8D6CD3", "1 c #8F6CD8", "2 c #906FD7", "3 c #926FDC", "4 c #9271DA", "5 c #936EE2", "6 c #9571E1", "7 c #9875E2", "8 c #9D9D9D", "9 c #A29EAA", "0 c #A4A4A4", "q c #AAA9A7", "w c #ADADAD", "e c #B2B2B2", "r c #BCBCBC", "t c #AEAEF7", "y c #B0B0F7", "u c #BEBEF7", "i c #BABAF8", "p c #C4C4C3", "a c #C7C8C4", "s c #C9CAC6", "d c #CDCDCD", "f c #CFCFD0", "g c #D0D0D0", "h c gainsboro", "j c #CFCFF8", "k c #D4D4F7", "l c #D5D5FA", "z c #DFDFFB", "x c #E4E4E4", "c c #ECECEC", "v c #E4E4FC", "b c #E8E8FB", "n c #F3F3F3", "m c #F3F3FC", "M c #FEFEFE", /* pixels */ "000000000000000000000000000000000000000000000000", "000000000000000000000000000000000000000000000000", "00000000q00000q00q00000000000q0000q00q00w0000000", "000008888888888888888880088888888888888888800000", "0000rgggggggggggggdggfgeagfdggggddggggggfffq0000", "0008fMMMMMMMMMMMMMMMMMMpxMMMMMMMMMMMMMMMMMMw0000", "0008fMkuimMMMMMMMMMMMMMpxMprpxMMMMMMMMMMMMMw0000", "0008gMbltmMMMMMMMMMMMMMpxMxcreMMMMMMMMMMMMMw8000", "0008gMMvymMMMMMMMMMMMMMpxMxpehMMMMMMMMMMMMMw0000", "0008gMMvymMMMMMMMMMMMMMpxMMcapMMMMMMMMMMMMMw0000", "00q8gMmktvMMMMMMMMMMMMMpxnxnawmMMMMMMMMMMMMw8000", "0008fMjiiizMMMMMMMMMMMMrccrrrxMMMMMMMMMMMMMw0000", "0008gMMMMMMMMMMMMMMMMMMpxMMMMMMMMMMMMMMMMMMw0000", "00q8gMMMMMMMMMMMMnnMMMMpxMMMMMMMMMMMMMMMMMMw0000", "0008gMMMMMMMMMMMneedMMMpxMMMMMMMMMMMMcgMMMMw8000", "0008gMMMMMMMMMMMcwqdMMMaxMMMMMMMMMMMMcqgMMMw9000", "0008gMMMMMMMMMMMnewdMMMpxMMMMMMMMmncnxewgMMw0000", "0008gMnMMMMMMMMMcewaMmMaxMMMMMMMMxqeeeeewgMw0000", "00q8gMMMMMMMMMdereeerecaxMMMMMMMMxqwqweeeene8000", "0008gMMMMMMMMMnrweeewhMpxMMMMMMMMcaadpewenMw0000", "0008gMMMMMMMMMMmpweehMMaxMMMMMMMMMMMMcwenMMw0000", "00q8gMMMMMMMMMMMmrqhMMMrxMMMMMMMMMMMMxenMMMw0000", "0008gMMMMMMMMMMMMmcMMMMpxMMMMMMMMMMMMnnMMMMw8000", "0000epppppppppappaapppaeraaaaappaaaaasspaaaq0000", "0000pcxxxxxxxxxxxxxxxxcr*,,>>>>>>>>,>>:>>>:90000", "0008fMMmmMMMMMMMMMMMMMMa,63453545446633334490000", "0008gMrrepMMMMMMMMMMMMMa,57-$44444<=;43444400000", "0008gMcMx0cMMMMMMMMMMMMa,1%++74#4464444444444442444290000", "0008gMMMMMMMMMMMMMMMMMMa,34444432441464444490000", "0008gMMMMMMMMMMMMMMMMMMa>44423444444;%=<44490000", "0008dMMMMMMMMMMnnnnnnmMa>34444434444# %73490000", "00q8dMMMMMMMMMMhqeeeqxMa>34444244444% =44200000", "00q8fMMMMMMMMMMMheeewxMa>32444244447% =74490000", "0008fMMMMMMMMMMMceeewxMp>344444441=;# %<-190000", "0008fMMMMMMMMMMceeeewxMa>544432444444444442o .. O1480000", "0008gMMMMMMMMMcewfMMgxMa>34423344242X O44490000", "00q8gMMMMMMMMMMxgMMMMMMa>323444344342XO243390000", "0008dMMMMMMMMMMMMMMMMMMa>44424444243421444290000", "0000wwwwwwwwwwwwwwwwwwwq999990909999909099000000", "000009808000000800800080000000080000000000080000", "000000000000000000000000000000000000000000000000", "000000000000000000000000000000000000000000000000", "000000000000000000000000000000000000000000000000" }; const char *const *const xpm_icons[] = { xpm_icon_0, xpm_icon_1, xpm_icon_2, }; const int n_xpm_icons = 3; puzzles-20170606.272beef/icons/samegame-icon.c0000644000175000017500000004226613115373753017672 0ustar simonsimon/* XPM */ static const char *const xpm_icon_0[] = { /* columns rows colors chars-per-pixel */ "16 16 248 2 ", " c #E6E6E6", ". c #E2E2E2", "X c #E2E2E2", "o c #E2E2E2", "O c #E2E2E2", "+ c #E2E2E2", "@ c #E2E2E2", "# c #E1E1E2", "$ c #DDDEE1", "% c #E2DDDE", "& c #E0DEDD", "* c #DEE1DE", "= c #E6E6E6", "- c #E2E2E2", "; c gray87", ": c #E2E2E2", "> c #E1E1E1", ", c #E2E2E2", "< c #E2E2E2", "1 c #E2E2E2", "2 c #E2E2E2", "3 c #DEE0DE", "4 c #E9E3EA", "5 c #BAD0B7", "6 c #169B0E", "7 c #E2362B", "8 c #A14E26", "9 c #2CA13B", "0 c #E6E3E2", "q c #E2E2E2", "w c #E2E2E2", "e c gray91", "r c #E7E7E7", "t c #E7E7E7", "y c #E7E7E7", "u c #E7E7E7", "i c #E7E7E7", "p c #ECE8EF", "a c #F9F5ED", "s c #C3CDD4", "d c #054A99", "f c #EB1329", "g c #9B3D04", "h c #0F9C25", "j c #E6E3E2", "k c #E2E2E2", "l c #E1E1E1", "z c #E7E7E7", "x c #E6E6E6", "c c #E6E6E6", "v c #E6E6E6", "b c #E6E6E6", "n c #E4E5E5", "m c #C2D5C3", "M c #CBD3DA", "N c #9C99F0", "B c #0005FF", "V c #BF1468", "C c #9B4426", "Z c #468D30", "A c #E6E3E3", "S c #E6E6E6", "D c #E5E6E5", "F c #E9E7E9", "G c #DCE0E0", "H c #1F9E06", "J c #12449C", "K c #0100FF", "L c #0B05F8", "P c #000DFF", "I c #771597", "U c #FF241E", "Y c #E3E2E7", "T c #E2E2E2", "R c #E1E1E2", "E c #E7E7E7", "W c #E6E6E6", "Q c #E6E6E6", "! c #E5E5E6", "~ c #E8E8E6", "^ c #DCDDE5", "/ c #2637D9", "( c #0304FB", ") c #1221DB", "_ c #157E45", "` c #C72142", "' c #9C3F27", "] c #3D902D", "[ c #E6E3E3", "{ c #E2E2E2", "} c #E4E4E1", "| c #E8E8E7", " . c #E6E6E6", ".. c #E6E6E6", "X. c #E5E5E6", "o. c #E9E8E8", "O. c #E0E0E6", "+. c #2649B4", "@. c #0A34AA", "#. c #19587C", "$. c #059200", "%. c #992B63", "&. c #923549", "*. c #6D7D2B", "=. c #E5E3E4", "-. c #E2E2E2", ";. c #D9D9E3", ":. c #E0E0E8", ">. c #E3E3E6", ",. c #E6E6E6", "<. c #E6E6E6", "1. c gray90", "2. c #D3DED2", "3. c #1B9215", "4. c #088900", "5. c #0F860A", "6. c #1F870A", "7. c #0131EA", "8. c #740C9B", "9. c #FF2311", "0. c #E3E2E7", "q. c #E1E1E2", "w. c #2020F7", "e. c #9A9AEF", "r. c #FFFFE3", "t. c #DFE1E3", "y. c #F3ECF3", "u. c #9EC69F", "i. c #08800E", "p. c #089300", "a. c #0C4AAA", "s. c #4B16D6", "d. c #FF110A", "f. c #FD0F06", "g. c #FF0100", "h. c #FD2124", "j. c #E8E3E2", "k. c #DFDFE2", "l. c #1717F8", "z. c #3030FB", "x. c #8A8AF0", "c. c #E5E7E2", "v. c #F5EBF5", "b. c #92C394", "n. c #007B00", "m. c #B85100", "M. c #4C20B0", "N. c #181DDD", "B. c #7D6B00", "V. c #76189A", "C. c #6D2D6B", "Z. c #747C25", "A. c #E4E3E5", "S. c #DDDDE3", "D. c #1F1FF5", "F. c blue", "G. c #3636F9", "H. c #E9EAE3", "J. c #F2EBF1", "K. c #96BCAB", "L. c #156845", "P. c #E31742", "I. c #6B249F", "U. c #0D47B9", "Y. c #11853A", "T. c #0C3CD6", "R. c #1D4F8E", "E. c #518F21", "W. c #E2E3E6", "Q. c #DDDDE3", "!. c #2520F7", "~. c #3B3BF8", "^. c #F2F1E5", "/. c #FBFBE4", "(. c #9E9BEE", "). c #0000FC", "_. c #0904FF", "`. c #126E63", "'. c #138234", "]. c #2800FF", "[. c #0F8A37", "{. c #7E5C02", "}. c #FF192C", "|. c #E4E5E2", " X c #DDDDE1", ".X c #2D912E", "XX c #113FA3", "oX c #0D05FF", "OX c #383AF6", "+X c #3A3BF8", "@X c #201EFE", "#X c #0A0CF5", "$X c #008451", "%X c #9E4D1D", "&X c #C83B18", "*X c #038B3D", "=X c #0C42CC", "-X c #7F1981", ";X c #FF2213", ":X c #E4E3E6", ">X c #DDDDE2", ",X c #25696E", " , < 1 2 3 4 5 6 7 8 9 0 ", "q w e r t y u i p a s d f g h j ", "k l z x c v b n m M N B V C Z A ", "O , t c S D F G H J K L P I U Y ", "T R E W Q ! ~ ^ / ( ) _ ` ' ] [ ", "{ } | ...X.o.O.+.@.#.$.%.&.*.=.", "-.;.:.>.,.<.1.2.3.4.5.6.7.8.9.0.", "q.w.e.r.t.y.u.i.p.a.s.d.f.g.h.j.", "k.l.z.x.c.v.b.n.m.M.N.B.V.C.Z.A.", "S.D.F.G.H.J.K.L.P.I.U.Y.T.R.E.W.", "Q.!.F.~.^./.(.)._.`.'.].[.{.}.|.", " X.XXXoXOX+X@X#X$X%X&X*X=X-X;X:X", ">X,X c #326F7A", ", c #517A71", "< c #FF0000", "1 c #FE090A", "2 c #FF1F0C", "3 c #FF0F17", "4 c #FF1013", "5 c #FF1B15", "6 c #F51D1D", "7 c #FB161B", "8 c #D32D14", "9 c #EB2C16", "0 c #E93918", "q c #EB1D2E", "w c #F51A22", "e c #D4392A", "r c #E32F24", "t c #FF2C25", "y c #FA292E", "u c #FF3327", "i c #E3223B", "p c #E72933", "a c #F32E31", "s c #FB3132", "d c #FC3A3F", "f c #BD441F", "g c #BB512D", "h c #BF4B37", "j c #B14F27", "k c #A56234", "l c #BF235E", "z c #A51F7B", "x c #B92A6D", "c c #A7207D", "v c #BC3576", "b c #D3234C", "n c #D82F41", "m c #D22857", "M c #E32B46", "N c #B65D42", "B c #86784C", "V c #93724C", "C c #8D7260", "Z c #C94E4F", "A c #DA5C4C", "S c #C9475E", "D c #D94C6D", "F c #018200", "G c #028C00", "H c #0B830C", "J c #008B0A", "K c #058A07", "L c #059307", "P c #139407", "I c #1D8C1E", "U c #168616", "Y c #099317", "T c #22930E", "R c #23931D", "E c #1B8921", "W c #1E8620", "Q c #1E8332", "! c #1C942C", "~ c #238B23", "^ c #3B8422", "/ c #3C8C2B", "( c #229620", ") c #32922F", "_ c #228639", "` c #249232", "' c #329531", "] c #319A30", "[ c #339F3B", "{ c #528939", "} c #198F44", "| c #298A47", " . c #3B885E", ".. c #499D49", "X. c #529254", "o. c #49A348", "O. c #59A859", "+. c #988151", "@. c #86894F", "#. c #723CAD", "$. c #6535BF", "%. c #6B27B6", "&. c #22539A", "*. c #2B6983", "=. c #256883", "-. c #376C8D", ";. c #224FA0", ":. c #2A5BA4", ">. c #2753A2", ",. c #274AB6", "<. c #294ABA", "1. c #2B58BE", "2. c #3057A5", "3. c #3460AB", "4. c #535D9D", "5. c #7F4B94", "6. c #4259B6", "7. c #446AAB", "8. c #4973A3", "9. c #293BD2", "0. c #233AD3", "q. c #0101FE", "w. c #0B02FF", "e. c #010DFF", "r. c #0E0AFE", "t. c #130EFF", "y. c #1609FF", "u. c #0A14FF", "i. c #0315FF", "p. c #1719FC", "a. c #2D1CED", "s. c #1D29FF", "d. c #1B28E4", "f. c #2327EB", "g. c #2323F1", "h. c #2823FE", "j. c #222CFC", "k. c #2E2EFC", "l. c #2020FB", "z. c #2E39FF", "x. c #3537FC", "c. c #3C34ED", "v. c #4C18DC", "b. c #5333D7", "n. c #403AFF", "m. c #3D47DA", "M. c #4A4AEF", "N. c #4A4AF6", "B. c #6363F4", "V. c #6B6BF3", "C. c #9D368E", "Z. c #A6368C", "A. c #8128A2", "S. c #8639A7", "D. c #984C96", "F. c #9348A0", "G. c #9851B1", "H. c #854FC3", "J. c #638DA0", "K. c #9CBF9C", "L. c #97C397", "P. c #A3C7A6", "I. c #B1CCB7", "U. c #9C9CEE", "Y. c #B8B9EB", "T. c #A9A7F0", "R. c #DCDCDC", "E. c #D5D5D5", "W. c #DDE2DD", "Q. c #E4E4DF", "!. c #D8D8E8", "~. c #C8C8E9", "^. c #DFE4E4", "/. c #E5E5E5", "(. c #E8E7E7", "). c #ECECE6", "_. c #E7E7E8", "`. c #E9E5E9", "'. c #E7ECEC", "]. c #E9E9E9", "[. c #E7E8E7", "{. c #F1EDED", "}. c #F4F4E4", "|. c #FFFFE3", " X c #F3ECF3", /* pixels */ "/./.(.(.(._._._._._.(.(.(.(.(.[.[.(.(.[.`.(.(.`.(.(.[./._./././.", "[./.Q.!.Q.Q.!.Q.Q./.Q.!./.Q.R././.R.Q./.R./././.!./.^./././.(./.", "[.R.E.Q.R.R.R.R.R.R.R.R.R.R.R.R.R.R.R.E.`.K.U ! h 6 s { U ..[._.", "[./.R.].(.(.(.(.[.[.[.[././.[.[.(.(._._. XL. J j < 4 ^ ' ]./.", "/.Q.R.[.[./.[./._./.[.[./././.[._./././. XP.o } h < 4 ^ . ' '.(.", "[./.R.[.[./.(././.(././._.[././././././.).U.q.u.x < 3 ^ ' ].(.", "[./.R.(./.[./.(.(./.[./.[././.[. X{.{.).|.U.q.e.x < 4 ^ F ' '.(.", "(.R.R.(./././.[./.[././.[./././.I.P.I.T.Y.V.q.q.A.x v B # @.].(.", "(.R.R.(.[././.[./.(./._._./.[.Q.W & r.q.q.q.q.q.q.u.i < s './.", "[./.R.[./.(.[./.(./.[./././.[./.( F | r.q.q.q.q.q.q.u.i < s './.", "(.!.R.(._./.[./.[./././._./././.7.&.,.w.q.9.> =.D.c C.V + +.]./.", "(./.R.[./.(./._././.(.[./././.^.p.q.q.q.q.:.G L j < 4 ^ F ' './.", "(.Q.R.(._._.(./.(././.(./._.[./.h.w.r.r.w.2.F J j < 5 / G [ ].(.", "/.Q.R._./././././._.[./././././. .% & & & _ . G 4.v.b.Z 8 A [.`.", "[.R.R.[././._._.(././.(._./.[./.I F F F . . . G ,.q.u.i < s '.(.", "[./.R././._./././.[.[././././.W.E H E I I W T 6.y.k.i < s [./.", "[.Q.c.r.N.)./././.[././. XO.U ~ H F | h.u.S.2 6 6 w w 1 < s [./.", "[./.g.q.x.}.).)././.[./. Xo. F F F & w.q.#.< < < < < 1 < s '.(.", "[.Q.f.q.k.~.Y.!.[./././. Xo. H $ @ , w.q.#.0 e n b b e 8 A [./.", "_.Q.g.q.q.w.q.B.}./././. X.. ~ y < b i.q.:.L L 1.q.p.} K [ './.", "_.Q.g.q.q.e.q.B.}./././. Xo.F R 6 < b e.q.>.G G ,.q.t._ F ] ]./.", "_.Q.g.q.q.w.q.B.}./././.).J.= -.C.z D.:.>.8.*.*.8.>.3.B + +.].(.", "[.Q.g.q.q.q.q.B.}.!.^.^.).M.q.w.q.q.0.P G *.q.q.: G Y r < s ]._.", "_.Q.g.q.q.q.q.V.|.}.}.}.|.M.q.w.w.q.9.P G *.q.w.: G Y r < s ]./.", "/./., - -.r.q.k.V.B.B.B.V.p.q.p.> - , g f C ; : 7.,.1.p < s [.(.", "/./.~ F Q u.q.q.q.q.q.q.q.q.q.p.~ F $ 1 < j K L ,.q.e.i < s './.", "(.Q.) F | t.q.q.r.q.q.q.q.u.e.j.` K { 5 1 k Y P <.q.u.M < d '.(.", "(./.m.d.f.q.q.q.q.q.q.q.e.v q i r 9 S c.a.F.9 0 $.q.t.X.T X.]./.", "_.W.g.q.w.q.q.q.q.q.q.q.e.b < < < < b e.q.A.< < %.q.t._ / ].(.", "_./.M.k.x.k.k.k.k.k.k.k.z.D t s s t D x.j.G.u u H.s.n.X.~ O.`.(.", "/./.[.).).).).).).).).[.).'.].'.'.'.'.).].).'.'.[.).].].].].(./.", "(././._._././._._./._._./././.(./././._./././.(./._./.(.(././.(." }; /* XPM */ static const char *const xpm_icon_2[] = { /* columns rows colors chars-per-pixel */ "48 48 164 2 ", " c #007600", ". c #007C00", "X c #FE0000", "o c #FF150D", "O c #FF1415", "+ c #FF1C15", "@ c #FF1519", "# c #FE1B1C", "$ c #EF251F", "% c #FD201D", "& c #F2221E", "* c #FC1E23", "= c #EC2424", "- c #EF2B27", "; c #EF242F", ": c #EF2F2A", "> c #F62326", ", c #FA2425", "< c #F42926", "1 c #F82827", "2 c #F2252F", "3 c #F02E29", "4 c #EF302A", "5 c #FF392E", "6 c #F22730", "7 c #FF3634", "8 c #FE3538", "9 c #F63F3F", "0 c #FD3C3C", "q c #FC3E36", "w c #F4453B", "e c #F9413C", "r c #ED3D40", "t c #F63D44", "y c #DF4C48", "u c #EF4943", "i c #EF434E", "p c #EA4C4C", "a c #F2434A", "s c #EA4A51", "d c #FE5353", "f c #F85857", "g c #F85759", "h c #F35E5A", "j c #F45960", "k c #038103", "l c #158F0F", "z c #0C8B13", "x c #178D15", "c c #1B8E14", "v c #158E1B", "b c #1C8D1B", "n c #16911D", "m c #1F901C", "M c #218C1D", "N c #21901E", "B c #1D8D22", "V c #1F8C2B", "C c #208620", "Z c #248D25", "A c #2C8B24", "S c #258C2B", "D c #2B8C2A", "F c #308B26", "G c #328C29", "H c #259025", "J c #299229", "K c #2F9F2F", "L c #359B2E", "P c #278B30", "I c #298E31", "U c #2B9E37", "Y c #359C34", "T c #3A9E34", "R c #3C963E", "E c #319E3A", "W c #3C9C3B", "Q c #38A02B", "! c #40973B", "~ c #439B39", "^ c #439C37", "/ c #4D9447", "( c #419C43", ") c #4C9A42", "_ c #449B4A", "` c #4D9A4B", "' c #529A47", "] c #52974E", "[ c #489450", "{ c #479A52", "} c #519750", "| c #4CA14D", " . c #51A94B", ".. c #4DA952", "X. c #57A157", "o. c #53A955", "O. c #5CA858", "+. c #68B368", "@. c #0101FF", "#. c #0A0AFE", "$. c #0E17FF", "%. c #1515FE", "&. c #1917FF", "*. c #1419FF", "=. c #1B1BFD", "-. c #201EFE", ";. c #1F22F6", ":. c #1E21FE", ">. c #252AEF", ",. c #292AEC", "<. c #3429EF", "1. c #2B30EF", "2. c #3E3BEB", "3. c #2224F5", "4. c #2C26F4", "5. c #262AF5", "6. c #292DF2", "7. c #2222FC", "8. c #2A2AFA", "9. c #3229F2", "0. c #2B30F0", "q. c #3C3EF6", "w. c #3535FD", "e. c #3833FF", "r. c #313AFD", "t. c #3C3BFD", "y. c #4B3EF0", "u. c #413CFB", "i. c #3C40F8", "p. c #474AE1", "a. c #4245EB", "s. c #4F44EC", "d. c #464AEF", "f. c #484FEA", "g. c #504CE6", "h. c #5247EC", "j. c #5849E8", "k. c #5757EB", "l. c #4244F4", "z. c #4943F1", "x. c #4349F0", "c. c #4140FB", "v. c #4948F8", "b. c #4E52FF", "n. c #5C5CF4", "m. c #5355FC", "M. c #CECECE", "N. c #D7D8D7", "B. c #DBDBDB", "V. c #D4D6D4", "C. c #E5E5DC", "Z. c #DEDEE7", "A. c #D7D7E8", "S. c #DCE5E5", "D. c #E6E6E6", "F. c #E8E7E7", "G. c #E7E8E7", "H. c #E9E9E6", "J. c #E6E6E8", "K. c #E8E7E8", "L. c #E9E9E9", "P. c #F1F1E8", "I. c #F1EDF1", "U. c #E8F1F1", /* pixels */ "D.D.D.D.G.D.D.G.D.D.D.D.D.D.F.J.D.D.D.J.F.D.J.D.D.D.D.D.D.D.D.D.D.D.F.D.D.D.D.D.D.D.D.D.D.D.D.D.", "D.D.D.D.D.D.D.D.G.F.G.D.D.D.F.L.D.D.D.D.L.L.D.D.D.D.D.D.G.D.D.D.D.D.D.D.D.D.D.D.D.D.G.D.D.D.G.D.", "D.D.D.D.L.J.L.L.L.L.L.L.F.F.L.L.L.J.L.L.L.L.L.L.L.J.F.G.L.J.L.L.D.D.D.L.L.D.D.G.D.F.G.D.D.D.G.D.", "D.D.D.G.Z.C.B.B.Z.B.B.B.B.C.B.B.B.C.B.B.B.B.B.B.B.C.Z.B.B.C.B.B.Z.D.D.Z.D.S.S.S.Z.F.Z.D.D.D.D.D.", "D.D.G.Z.M.B.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.N.R A C / r = = y ! A C X.L.D.D.D.", "D.D.G.B.N.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.L.G.L.L.L.D.b . . G # X X : v . R I.D.D.D.", "D.D.L.C.N.G.G.D.D.D.D.D.D.D.D.D.J.D.D.D.F.D.D.D.D.D.D.D.D.D.F.Z.b . G * X X 4 b k . W I.D.D.G.", "D.D.L.B.N.L.D.G.D.D.D.D.F.D.G.D.J.J.D.D.J.D.D.D.D.G.D.D.D.D.D.D.L c l ~ # X X : v . . W I.D.D.D.", "D.D.L.B.N.L.D.D.D.D.D.D.G.D.D.D.G.D.D.G.D.D.D.D.D.D.D.D.D.D.D.D.a.>.5.g.+ X X : n k . W I.D.D.D.", "G.D.L.B.N.L.D.F.J.D.D.D.D.D.D.D.D.D.D.D.D.D.G.D.D.G.D.D.G.D.G.Z.=.@.@.4.% X X 4 n . . W I.D.D.G.", "D.D.L.B.N.L.D.D.D.D.D.D.D.D.D.L.D.D.D.D.G.D.D.D.D.D.D.D.D.D.D.Z.:.@.@.9.+ X X 4 v . . R I.D.D.D.", "D.J.L.C.N.L.D.D.D.D.D.G.D.D.D.D.G.D.D.G.D.D.D.D.L.L.L.L.H.F.P.G.=.@.@.9.5 + O w U v x ..L.D.D.D.", "J.D.L.B.B.L.D.D.D.L.D.D.D.D.D.D.D.D.G.D.D.G.D.D.` J J | v.8.9.8.@.@.@.#.<.<.-.j.w < & h U.D.D.D.", "D.D.L.B.N.L.D.D.D.D.D.D.D.G.D.D.D.D.D.D.D.D.L.D.Z . . S -.@.@.@.@.@.@.@.@.@.@.9.+ X X 0 L.D.D.D.", "D.D.L.B.B.L.L.D.D.D.D.D.D.D.D.D.D.D.G.D.D.D.G.D.Z . . Z 7.@.@.@.@.@.@.@.@.@.@.<.+ X X 0 U.D.D.G.", "D.D.L.B.N.L.D.D.D.D.D.G.D.D.G.D.G.D.D.D.D.D.D.D.W c c ( 7.@.@.#.-.-.=.7.=.:.*.z.7 # O d U.D.D.D.", "D.D.P.B.N.L.D.D.D.D.D.D.G.D.D.G.D.D.D.D.D.D.D.D.z.3.5.5.#.@.@.5.( Z B ` t > * p W D M O.L.D.G.D.", "D.D.D.Z.N.L.D.D.D.G.D.G.D.D.D.D.D.D.D.G.D.D.G.D.7.@.@.@.@.@.@.5.N . . D # X X 3 v . W I.D.D.D.", "D.D.L.B.N.L.D.D.D.G.D.D.D.D.D.D.G.D.D.D.D.G.G.D.7.@.@.@.@.@.@.5.N . . G # X X 3 v . W I.D.D.D.", "G.D.L.B.N.L.D.D.D.D.D.D.G.D.D.G.D.D.D.D.D.D.D.D.q.=.7.-.7.7.&.l.m . k J 0 # # u E b x o.L.D.D.D.", "D.D.L.B.N.L.D.D.D.D.D.D.G.D.D.D.D.D.D.D.D.D.D.D.( B J H S H H Z k k . I u.-.-.h.0 > # f U.D.D.D.", "D.D.L.B.N.L.D.D.D.G.G.D.D.D.D.D.D.D.D.G.D.D.D.D.Z . . . . . . . k k k D =.@.@.<.+ X X 0 U.D.D.D.", "D.D.L.C.N.L.D.D.D.D.D.D.D.D.D.D.D.D.D.D.G.D.D.G.H . k k . . k . . . D -.@.@.9.+ X X 0 U.D.D.D.", "D.D.D.Z.N.G.D.D.D.G.D.D.D.D.G.D.G.D.D.D.D.D.D.D.H . k k H Z H H Z Z b _ q.-.=.h.+ X X 0 U.D.D.D.", "D.D.L.C.a.=.-.w.Z.H.D.D.D.D.D.D.D.D.D.D.( b H H k k . H c.=.:.z.q # , , , , , , X X X 0 U.D.D.D.", "D.D.F.C.,.@.@.&.Z.D.D.D.D.D.D.D.G.D.D.G.D . . . k k . D 7.@.@.4.% X X X X X X X X X X 9 U.D.D.D.", "D.D.F.C.,.@.@.%.Z.H.D.D.D.D.D.D.D.D.D.G.J . k k . . . Z 7.@.@.4.% X X X X X X X X X X q U.D.D.D.", "D.D.F.C.,.@.@.%.A.D.D.D.D.D.D.D.D.D.G.G.J . k k H H M _ -.@.@.4.e % < 1 , > > > 1 1 @ f U.D.D.D.", "D.D.D.C.,.@.@.@.=.7.=.w.Z.G.D.D.D.D.D.L.J . k H 9 # # a :.@.@.5.W b b _ t.=.=.d.T m v o.I.D.D.D.", "D.D.G.C.,.@.@.@.@.@.@.=.Z.G.D.D.D.G.D.L.J . . H , X X > 7.@.@.5.M . . P =.@.@.>.m . . W I.D.D.D.", "D.D.D.C.,.@.@.@.@.@.@.=.Z.H.D.D.G.D.D.L.D . . Z , X X > :.@.@.5.b . . D =.@.@.>.c . W I.D.D.D.", "G.D.D.C.,.@.@.@.@.@.@.=.Z.H.D.D.D.D.D.D._ C Z _ a > > a l.3.3.x.( V Z { i.3.7.f.~ A M O.L.D.D.D.", "D.D.G.C.,.@.@.@.@.@.@.=.Z.D.D.D.D.D.D.G.c.&.-.=.:.:.*.i.W c c ( e.=.&.l.L b c ~ 8 # @ d U.D.D.D.", "D.D.G.C.,.@.@.@.@.@.@.%.Z.D.D.D.D.D.D.D.7.@.@.@.@.@.@.7.M . . D -.@.@.6.b . . G # X X 0 U.D.D.D.", "D.D.G.C.,.@.@.@.@.@.@.=.Z.H.D.H.H.D.H.H.5.@.@.@.@.@.@.5.Z . . S =.@.@.6.b . . G * X X 0 L.D.D.D.", "D.D.G.C.p.3.6.6.#.@.@.=.A.D.Z.Z.Z.Z.Z.Z.8.@.@.#.6.6.3.d.~ A A ` l.3.3.f.( S V ] @ X X 0 U.D.D.D.", "D.D.D.Z.! c c L 1.@.@.@.=.=.%.=.=.%.=.=.#.@.@.7.W c x ~ 8 @ @ 9 T c c ( e.&.%.y.+ X X 0 U.D.D.D.", "D.D.D.D.F . c 1.@.@.@.@.@.@.@.@.@.@.@.@.@.@.7.Z . . Z , X X < B . . P =.@.@.<.+ X X 0 U.D.D.D.", "G.D.G.D.D . c 1.@.@.@.@.@.@.@.@.@.@.@.@.@.@.7.Z . . A # X X < b . . I -.@.@.<.+ X X 0 U.D.D.D.", "D.D.G.Z.[ P P ( >.@.@.@.@.@.@.@.@.@.@.#.<.<.4.s.) A F ' i ; 2 s ) A A } =.@.@.<.w - - h L.D.D.D.", "D.D.J.C.y.%.=.=.@.@.@.@.@.@.@.@.@.@.@.7.q o + + @ # O t r.$.$.q.7 @ @ t =.@.@.0.K v z ..L.D.D.D.", "D.D.J.C.,.@.@.@.@.@.@.@.@.#.@.@.@.@.@.7.1 X X X X X X > 7.@.@.4.% X X 6 :.@.@.1.c . W I.D.D.G.", "D.D.D.C.,.@.@.@.@.@.@.@.@.@.@.@.@.@.@.7.> X X X X X X > :.@.@.4.# X X 6 =.@.@.1.c R I.D.D.D.", "D.D.D.C.k.w.t.t.u.t.t.t.t.t.t.t.t.t.w.m.g 7 t 0 0 t 7 g m.w.w.n.d 0 7 j b.w.w.n. .W Y +.L.D.D.D.", "D.D.D.D.H.P.P.P.P.P.P.L.P.P.P.P.P.P.P.H.U.L.U.U.U.U.U.U.P.P.P.L.U.U.U.U.L.P.P.P.I.L.I.I.L.D.D.D.", "D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.C.D.D.D.D.D.D.D.D.D.D.D.G.", "D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.G.G.D.D.D.D.D.D.D.D.D.D.D.D.D.D.G.D.D.D.D.L.D.D.D.G.D.D.", "D.D.D.J.D.G.D.D.D.D.D.D.D.D.D.D.D.D.G.D.D.D.D.D.D.D.D.D.D.J.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D." }; const char *const *const xpm_icons[] = { xpm_icon_0, xpm_icon_1, xpm_icon_2, }; const int n_xpm_icons = 3; puzzles-20170606.272beef/icons/rect-icon.c0000644000175000017500000004704713115373753017052 0ustar simonsimon/* XPM */ static const char *const xpm_icon_0[] = { /* columns rows colors chars-per-pixel */ "16 16 256 2 ", " c black", ". c #010101", "X c #020202", "o c gray1", "O c #040404", "+ c gray2", "@ c #060606", "# c #070707", "$ c gray3", "% c #090909", "& c gray4", "* c #0B0B0B", "= c #0C0C0C", "- c gray5", "; c #0E0E0E", ": c gray6", "> c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", "X*X=X-X=X*X,X1X>X>X,X,X:X5XlX", "uXV.B.B.z.N.G.<...q.4.1.4.8.| 5X", "pXkXSXCXdXNXUX~.j.+X).`.x.l.i.;X", "pXyXzXjXqXgXBXI.h. X/.).N.G.e.:X", "pX4XrXwX:XwXvXZ.R 5.%.' :.,.W 4X", "pXtXlXgXeX3X&XR.w.k.c.@.U.R.,.,X", "pXpXbXzXsX*XK./.f.7.C.,.].|.8.>X", "pX0XdXpX5XtXnXH.u._.F.$.~.(.3.,X", "pX7XiXyX1XtXzXD.u.].D.#.!./.3.,X", "pXpXbXxXeXkXSXY.f..XP.*.`.[.6.>X", "pXyXxXkXyXkXAXU.a.|.J.&.).'.6.>X", "pX3XwXyX9.1.u.o.] -.[ ' /.).<.,X", "pXyXxXzX9.b.y.Q.R./.J.:.N.z.w.:X", "pXiXbXxXt.M.u.].^.}.T.2.N.k.y.;X", "aX8XiXaX2.g.b.h.j.v.s.} b.N.*.4X", "kXaXpXaXqX1X2X2X2X2X3X6X2X c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", "X:X1X.X.X1X,X>X=XeX) 1 M c x z b - p v z x c k 4 wXbX", "vXrX5XNXcXvXcXNXqXqXNXjXcXcXPX} 2.-X/.}.|.#Xb c.#X[.{.}.].j 7XnX", "vXtX1XvXjXkXjXcX7X5XVX).~ ,XIX] =.oX6.K H.|.z d.].Q.!.~.W.g 7XnX", "vXtX2XbXkXlXkXvX8X7XmX0XH _.UX] -.@Xz.P U. Xz g.{.~.^./.!.g 7XnX", "vXtX2XvXkXlXkXvX8X6XBXW.,.>XIX[ =.%X_ ! T.|.z f.{.!.~./.!.g 7XnX", "vXrX4XMXxXcXxXMXqXqXMXcXBXvXLX} :.oX`.`.~.|.x h.|.^./.).~.g 7XnX", "cXtX&XiXrXrXrXiX:X:XiXeXeX0XbX) &.].I.Y.Y.(.l i.(.Y.T.R.U.f 7XnX", "cXyXXX5X1X2X2X6X+X+X6X2X2X,XpX~ @.^.H.K.J.W.j r.E.J.K.L.H.d 8XnX", "vXrX6XBXvXbXvXNXwXwXNXvXbXzXIX| :.+X^.(./. Xc h.|./.(.).^.h 7XnX", "vXtX1XvXjXkXjXcX7X7XcXjXkXfXGX{ -..XQ.~.!.{.x f.[.!.~.^.Q.g 7XnX", "vXtX2XbXkXlXkXvX8X8XvXkXlXgXHX{ ;.XX!.^.!.}.x g.{.~.^./.!.g 7XnX", "vXtX1XvXjXkXjXvX6X4XzXfXgXaXSX] =.|.E.Q.E.'.z f.[.!.~.^.Q.g 7XnX", "vXrX5XBXcXvXvXMXyXjXUXHXJXDXUX@.6.1X.XoXXX;Xn g.|./.(.).^.g 7XnX", "cXyX@XwX7X8X6XyXR.:.w.8.8.7.p.l n ..` ' ` } 5 a.Q.L.P.U.L.d 8XnX", "cXyX@XwX7X8X4XhX4.e } ` [ / / ` ] ' ' ' ` } 5 a.Q.R.R.U.L.d 8XnX", "vXrX5XBXcXvXzXUXw.| 7XY.L.+X#X^.].@XoXoXXX;Xn g. XB.G.`.^.g 7XnX", "vXtX1XvXjXkXfXHX9.~ OXc.B j.].F.I.~.Q.Q.E.'.z d.XX=.M (.!.g 7XnX", "vXtX2XbXkXlXgXJX9.^ *Xp.A K.`.J.T.(.^.^.!.}.x f.|.w.v E.^.g 7XnX", "vXtX1XvXjXkXfXHX9.~ %X8.o.H.).H.U.^.!.!.W.].x f.`.5.e.^.W.g 7XnX", "vXrX5XBXvXbXzXUXq.' -XXX%X}.|.E.(.|.{.{.].#Xv x.#XOX+X}.].j 7XnX", "cXuXoX5X1X2X,XuX7.g O.` ` ] { ( ` [ ] [ ] .y U | ` ' { ` s wXbX", "lXlXuXrXtXtXtXrXtX6X c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", ".< xXzXlXlX", "lXkXmX*X5XbXkXkXkXkXkXjXnXoXtXcXkXkXkXkXjXvXwXo d.{.!.^.^.^.^.^.!.B.^.).G.L d 7.'.|.:.< xXzXlXlX", "lXkXmX*X6XbXkXlXlXlXlXkXnXOXyXcXlXlXlXlXkXbXwXo f.{.!.^.^.^.^.^.~.V./.^.!.OXS =.}.|.>.< xXzXlXlX", "lXkXmX*X6XbXkXlXlXlXlXkXnXOXyXcXlXlXlXlXkXbXwXo f.{.!.^.^.^.^.^.~.V./.^.(.S N T.!. X>.< xXzXlXlX", "lXkXmX*X6XbXkXlXlXlXlXkXnXOXyXcXlXlXlXlXkXbXwXo f.{.!.^.^.^.^.^.~.V.^.).H.M H 9._. X>.< xXzXlXlX", "lXkXmX*X5XbXkXkXkXkXkXjXnXoXtXxXkXkXkXkXjXvXqXO a.'.E.Q.Q.Q.Q.Q.W.M.!.W.~.}.'./.R.}.;.< xXzXlXlX", "lXkXmX*X0XBXvXbXbXbXbXcXVX#XaXMXvXbXbXbXcXNXyXo m.-X.XoXoXoXoXOX.XL.OXoXoX.X.XXX.X,X8., xXzXlXlX", "lXkXmX*X#XrX8X9X9X9X9X8XrX_.,XwX9X9X9X9X8XeX=X@ F { ) _ _ _ _ _ ` ^ ` _ _ _ _ _ ) | c 6 zXzXlXlX", "lXkXmX*X).=X$X$X$X$X$X#X=XY. X&X$X#X@X$X#X=X'.# 1 q 9 8 7 9 9 0 3 7 9 9 9 9 9 8 w * 0 lXzXlXlX", "lXkXmX*XwXCXnXmXmXmXmXbXAX$XdXBXnXSXHXNXbXCXpXo c.%X{.@X#X|.{.#XN.o E.oX}.|.|.|.[.-X5., xXzXlXlX", "lXkXmX*X5XvXjXkXkXkXkXhXbXoXrXzXzX*X(.iXkXcXqXo s.].Q.z.f.~.Q.'.j. G.).Q.!.!.!.W.|.:.< xXzXlXlX", "lXkXmX*X6XbXkXlXlXlXlXkXnXOXyXxXvXV.Z ` VXxXwXo d.}.T.[ h ^ }.'.l. H._.~.^.^.^.Q..X>.< xXzXlXlX", "lXkXmX*X6XbXkXlXlXlXlXkXnXOXyXxXbXfXQ +.VXxXwXo f.{.!.&X) +.}.'.l. H._.~.^.^.^.Q..X>.< xXzXlXlX", "lXkXmX*X6XbXkXlXlXlXlXkXnXOXtXvXhX/.-.B vXvXwXo d.[.).Z t M.^.].l. H._.~.^.^.^.Q..X>.< xXzXlXlX", "lXkXmX*X6XbXkXlXlXlXlXkXnXOXtXcXlXb.1..XvXcXwXo d.}.E.] / 3.(.].l. H._.~.^.^.^.Q..X>.< xXzXlXlX", "lXkXmX*X5XvXjXkXkXkXkXhXbXoXtXxXkXZXFXmXhXvXqXo d.[.!..X.X[.Q.[.k. H._.!.~.~.~.Q. X:.< xXzXlXlX", "lXkXmX*XqXCXnXnXnXnXnXbXZX$XsXBXnXvXxXbXbXVXiXO h. X/.^.^./.(.|.x. L.].(.).).)./.OX<.< xXzXlXlX", "lXkXmX*X|.4X,X,X,X,X,X>X4XQ.$X2X,X,X,X,X>X3XoXo w.R.G.J.J.J.G.T.y. n.I.H.J.J.J.F.!.@.1 xXzXlXlX", "lXkXmX*X|.4X,X,X,X,X,X>X4XQ.$X2X,X,X,X,X>X3XoXo w.R.G.J.J.J.G.T.y. n.I.H.J.J.J.F.!.@.1 xXzXlXlX", "lXkXmX*XqXCXnXnXnXnXnXbXZX$XsXBXnXnXnXnXbXVXiXO h. X/.).).).(.|.x. L.].(.).).)./.OX<.< xXzXlXlX", "lXkXmX*X5XvXjXkXkXkXkXhXbXoXtXxXkXkXkXkXjXcXqXo d.[.!.~.~.~.!.].k. H._.!.~.~.~.Q. X:.< xXzXlXlX", "lXkXmX*X6XbXkXlXlXlXlXkXnXOXyXcXlXlXlXlXkXbXwXo f.{.!.^.^.^.!.[.l. H._.~.^.^.^.Q..X>.< xXzXlXlX", "lXkXmX*X6XbXkXlXlXlXlXkXnXOXyXcXlXlXlXlXkXbXwXo f.{.!.^.^.^.!.[.l. H._.~.^.^.^.Q..X>.< xXzXlXlX", "lXkXmX*X6XbXkXlXlXlXlXkXnXOXyXcXlXlXlXlXkXbXwXo f.{.!.^.^.^.!.[.l. H._.~.^.^.^.Q..X>.< xXzXlXlX", "lXkXmX*X6XbXkXlXlXlXlXkXnXOXyXcXlXlXlXlXkXbXwXo f.{.!.^.^.^.!.[.l. H._.~.^.^.^.Q..X>.< xXzXlXlX", "lXkXmX*X5XvXjXkXkXkXkXhXbXXXeXzXhXjXjXjXhXxX0Xo s.].Q.!.!.!.Q.'.j. G.).!.~.~.~.Q. X:.< xXzXlXlX", "lXkXmX*XwXCXnXmXmXmXmXbXZX*XlXFXZXAXAXAXCXGXhX@ v.$X{.|.|.|.{.#XN. L.[.(.).).)./.+X<.< xXzXlXlX", "lXkXmX*X).=X$X$X$X$X$X$X*XJ p f f d d d d f a . 3 0 9 9 9 9 9 0 2 O z.H.A.S.S.S.Z.T.o.1 xXzXlXlX", "lXkXmX*X#XrX8X9X9X9X9X9XwX8 j [ ^ ~ ! ^ / ^ ) ^ ` _ _ _ _ _ ) [ J X B.E.I.L.L.I.L.).%.1 xXzXlXlX", "lXkXmX*X0XBXvXbXbXbXvXvXBX5 3.1X.X;X1X%XoXOX+XP..XOXoXoXoXoXXX=XC. K.'.(.XXoX`.~.OX,.< xXzXlXlX", "lXkXmX*X5XbXkXkXkXkXkXkXvX4 $.}.!.1.~ c./.W.!.M.E.Q.Q.Q.Q.Q.E.`.h. G.`.T.*.+.F.^. X:.< xXzXlXlX", "lXkXmX*X6XbXkXlXlXlXlXlXbX4 &.XXQ.u.) h [.!./.V.!.^.^.^.^.^.!.[.l. H.`.E.:.6 ;.{.|.>.< xXzXlXlX", "lXkXmX*X6XbXkXlXlXlXlXlXbX4 &..X!.}.) 7.[.!.(.V.!.^.^.^.^.^.!.[.l. H.(.'.A.g <.[.|.>.< xXzXlXlX", "lXkXmX*X6XbXkXlXlXlXlXlXbX4 &. X'.M : ,.~.^./.V.!.^.^.^.^.^.!.[.l. G.[.V. .j O.{.|.>.< xXzXlXlX", "lXkXmX*X6XbXkXlXlXlXlXlXbX4 &..X!.x.p.f.^.~./.V.!.^.^.^.^.^.!.[.k. G.`.R.y.j.(.Q. X:.< xXzXlXlX", "lXkXmX*X5XvXjXkXkXkXjXkXvX5 -.OX^.}. X|.).(._.Z./.).).).).)./.|.x.X L.].). X}.(.^.OX<.1 xXzXlXlX", "lXkXmX&X0XVXbXbXbXbXbXbXBX5 O.).L.P.L.P.I.I.Y.z.L.U.I.I.I.I.P.!.a. B.R.P.L.P.I.L.(.%.1 xXzXlXlX", "lXkXnX:X^.+X.XXXXXXXXXXXOXn i b x c c c c c c l x c c c c c x v k w z c c c c c x b i M lXzXlXlX", "lXlXlXlXaXiXpXpXpXpXpXpXiXjXhXdXfXfXfXfXfXfXfXfXfXfXfXfXfXfXfXdXgXkXfXdXfXfXfXfXfXdXgXlXlXlXlXlX", "lXlXlXlXxXxXxXxXxXxXxXxXxXzXzXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXxXzXzXxXxXxXxXxXxXxXxXzXlXlXlXlXlX", "lXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlX", "lXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlX" }; const char *const *const xpm_icons[] = { xpm_icon_0, xpm_icon_1, xpm_icon_2, }; const int n_xpm_icons = 3; puzzles-20170606.272beef/icons/range-icon.c0000644000175000017500000004704713115373753017211 0ustar simonsimon/* XPM */ static const char *const xpm_icon_0[] = { /* columns rows colors chars-per-pixel */ "16 16 256 2 ", " c black", ". c #010101", "X c #020202", "o c gray1", "O c #040404", "+ c gray2", "@ c #060606", "# c #070707", "$ c gray3", "% c #090909", "& c gray4", "* c #0B0B0B", "= c #0C0C0C", "- c gray5", "; c #0E0E0E", ": c gray6", "> c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", " 5 + i iX~.^.wX|.3XG Z..X ", ", 4 o p dXyXuXyX%XpXM.*XOX ", "; , X q ).)._.~.C.`.].OXv. ", " " }; /* XPM */ static const char *const xpm_icon_1[] = { /* columns rows colors chars-per-pixel */ "32 32 256 2 ", " c black", ". c #010101", "X c #020202", "o c gray1", "O c #040404", "+ c gray2", "@ c #060606", "# c #070707", "$ c gray3", "% c #090909", "& c gray4", "* c #0B0B0B", "= c #0C0C0C", "- c gray5", "; c #0E0E0E", ": c gray6", "> c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", "XtXwX0X9XwX9XhXS. o ", " % x.iX9X0XjXaX9X0XrXS.7XwXqXqXqXqX9XiXH.:XtX9XaXjX0X8XgXA. o ", " % x.iX8XsX-.M.fX8XrXS.7XwXqXqXqXqX9XiXH.:XwXfXM.-.sX7XgXA. o ", " % x.iX8XsX-.M.fX8XrXS.7XwXqXqXqXqX9XiXH.:XwXfXM.-.sX7XgXA. o ", " % x.iX0X0XjXaX9XqXrXS.7XwXqXqXqXqX9XiXH.:XtX9XaXjX0X8XgXA. o ", " % l.rX6X8X5X6X8X7XqXZ.5X0X9X9X9X9X8XuXG.;XeX9X8X6X0X6XdXZ. o ", " % B.nXhXkXkXkXkXjXcXP.rXaXiXiXiXiXuXjXI.4XdXiXiXiXiXyXcXJ. o ", " % [ r.q.w.w.w.w.w.w.+.H.H.H.H.H.H.G.I.6.N.L.H.H.H.H.F.R.2. X ", " 5 k X o V 8X-X:X:X:X:X;X4XN.XX1X:X:X,X>X-X9Xv. o ", " 7 v + O O O O @ G jXwXtXwXwXtXeXdXK.1XiXtXtX7X0XwXkXF. o ", " 7 x X o S dX8X9XfXfX9X9XiXH.;XuX>XN S c.iXsXA. o ", " 7 x X o S fX7XaXM.M.aX8XiXH.;XpX-X0 x A.uXdXA. o ", " 7 x X o S fX6XjX-.-.jX6XiXH.:XyX2X3Xr.s yXfXA. o ", " 7 x X o S fX9X0XsXsX0X0XiXH.;XsX|.| N O.iXdXA. o ", " 6 z X o S aX6X8X7X7X8X6XyXF.-XwX7X^.Q.eX6XaXC. o ", " 8 b X o H MXsXgXgXgXgXdXcXR.9XkXfXvXbXfXaXNXP. o ", " < y . X j P.C.A.A.A.A.Z.J.2.v.F.A.Z.Z.A.C.P.,. X ", " ", " . . o o o o o o o o X o o o o o o o o X " }; /* XPM */ static const char *const xpm_icon_2[] = { /* columns rows colors chars-per-pixel */ "48 48 256 2 ", " c black", ". c #010101", "X c #020202", "o c gray1", "O c #040404", "+ c gray2", "@ c #060606", "# c #070707", "$ c gray3", "% c #090909", "& c gray4", "* c #0B0B0B", "= c #0C0C0C", "- c gray5", "; c #0E0E0E", ": c gray6", "> c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", " V l x x x x x x x x x x x N x x x x x x x x x x x x N x x x x x x x x x x x c x X ", " X i 4.B.n.m.m.m.m.m.m.m.m.m.v.*.N.n.m.m.m.m.m.m.m.m.n.N.*.v.m.m.m.m.m.m.m.m.m.b.D.' X ", " o v C.hXyXiXiXiXiXiXiXiXiXpXeXa.dXuXiXiXyXyXyXyXiXiXuXdXa.eXpXiXiXiXiXiXiXiXiXrXMX:. O ", " o x n.yX6X9X9X9X9X9X9X9X9X0X4Xt.eX8X8XqXaXsXaXpXqX8X8XeXt.4X0X9X9X9X9X9X9X9X9X5XhX*. O ", " o x m.iX9XqXqXqXqXqXqXqXqXwX6Xy.tX9XeX1XI.P.Y.Q.2XeX0XtXy.6XwXqXqXqX9X0XqXqXqX7XlX=. O ", " o x m.iX9XqXqXqXqXqXqXqXqXwX6Xy.tX8XpX'.5 6 ; O ].iX8XtXy.6XwXqXqXqXpXiX0XqXqX7XlX=. O ", " o x m.iX9XqXqXqXqXqXqXqXqXwX6Xy.tX0XqX0X4XiXA c iX0X0XtXy.6XwXqXqXqX|.OXeXqXqX7XlX=. O ", " o x m.iX9XqXqXqXqXqXqXqXqXwX6Xy.tX0XqX0XsX{. B.gX8X0XtXy.6XwXqXwXeX> x gX9XqX7XlX=. O ", " o x m.iX9XqXqXqXqXqXqXqXqXwX6Xy.tX0XqX8XlX` q rXqXqX0XtXy.6XwXqXqXwX8.f.uX0XqX7XlX=. O ", " o x m.iX9XqXqXqXqXqXqXqXqXwX6Xy.tX0X9XiX|. i.hX8XqX0XtXy.6XwXqXqXqXkXgX0XqXqX7XlX=. O ", " o x m.iX9XqXqXqXqXqXqXqXqXwX6Xy.tX0X9XpXR.+.2XrX0XqX0XtXy.6XwXqXqXqX7X8XqXqXqX7XlX=. O ", " o x m.iX9XqXqXqXqXqXqXqXqXwX6Xy.tX0XqX0XiXzXwX0XqXqX0XtXy.6XwXqXqXqXqXqXqXqXqX7XlX=. O ", " o x M.pX0XwXwXwXwXwXwXwXwXrX7Xu.uXqXwXeXqX8XwXwXwXwXqXuXu.7XrXwXwXwXwXwXwXwXwX8XzX=. O ", " X z c.eX4X6X6X6X6X6X6X6X6X7X1Xe.0X5X6X6X6X6X6X6X6X6X5X0Xe.1X7X6X6X6X6X6X6X6X6X2XdX%. O ", " X 0 ' a.t.y.y.y.y.y.y.y.y.u.e.E i.t.y.y.y.y.y.y.y.y.t.i.E e.u.y.y.y.y.y.y.y.y.r.j.S X ", " o c B.dXeXtXtXtXtXtXtXtXtXuX0Xi.aXrXtXtXtXtXtXtXtXtXrXaXi.0XuXtXtXtXtXtXtXtXtXqXvX;. O ", " o x n.uX8X0X0X0X0X0X0X0X0XqX5Xt.rX9X0X0X0X0X0X0X0X0X9XrXt.5XqX0X0X0X0X0X0X0X0X6XkX*. O ", " o x m.iX9XqXqXqX0XqXqXqXqXwX6Xy.tX0XqXqXqXqXqXqXqXqX0XtXy.6XwXqXqXqX0X0XqXqXqX7XlX=. O ", " o x m.iX9XqXqXwXyXeXqXqXqXwX6Xy.tX0XqXqXqXqXqXqXqXqX0XtXy.6XwXqXqXqXtXrXqXqXqX7XlX=. O ", " o x m.iX9XqXqX9X:X5XwXqXqXwX6Xy.tX0XqXqXqXqXqXqXqXqX0XtXy.6XwXqXqXqX,X1XwXqXqX7XlX=. O ", " o x m.iX9X9XpX{. <.lX7XqXwX6Xy.tX0XqXqXqXqXqXqXqXqX0XtXy.6XwXqXwXeX> x gX9XqX7XlX=. O ", " o x m.iX9X0XyX%XJ B.dX9XqXwX6Xy.tX0XqXqXqXqXqXqXqXqX0XtXy.6XwXqXqXwX{ ,.pX9XqX7XlX=. O ", " o x m.iX9XqX0XrXzXpX0XqXqXwX6Xy.tX0XqXqXqXqXqXqXqXqX0XtXy.6XwXqXqXqXjXgX0XqXqX7XlX=. O ", " o x m.iX9XqXqX0X7X9XqXqXqXwX6Xy.tX0XqXqXqXqXqXqXqXqX0XtXy.6XwXqXqXqX8X8XqXqXqX7XlX=. O ", " o x m.iX9XqXqXqXqXqXqXqXqXwX6Xy.tX0XqXqXqXqXqXqXqXqX0XtXy.6XwXqXqXqXqXqXqXqXqX7XlX=. O ", " o x b.rX5X8X8X8X8X8X8X8X8X9X2Xt.rX9X0X0X0X0X0X0X0X0X9XrXt.5XqX0X0X0X0X0X0X0X0X6XkX*. O ", " o x S.nXgXjXjXjXjXjXjXjXjXkXdXs.pXrXtXtXtXtXtXtXtXtXrXaXi.0XuXtXtXtXtXtXtXtXtXqXvX;. O ", " X r S W E W W W W W W W W Q U F s.t.y.y.y.y.y.y.y.y.t.i.E e.u.y.y.y.y.y.y.y.y.r.j.S X ", " X F d . o R sX3X6X6X6X6X6X6X6X6X5X0Xe.1X7X6X6X6X5X5X5X6X6X2XdX%. O ", " o H h + o o o o o o o o # Q kX9XwXwXwXwXwXwXwXwXqXuXu.7XrXwXwXrXtXtXrXwXwX8XzX=. O ", " o H f X o W jX8XqXqXqXqXqXqXqXqX0XtXy.6XwXqXqX7X3X1X4XqXqX7XlX=. O ", " o H f X o W jX8XqXqXqXwXqXqXqXqX0XtXy.6XwX8XdXE 1 r j 4XeX7XlX=. O ", " o H f X o W jX8XqXqXqXeXwXqXqXqX0XtXy.6XwX8XhXm y <.J.tX0X7XlX=. O ", " o H f X o W jX8X0XtX,X& { jX8XqX0XtXy.6XwX9XsXW h 1 h :XrX6XlX=. O ", " o H f X o W jX8X0XrX1Xh ,.gX8XqX0XtXy.6XwXqXqXtXZX_. b.hX4XlX=. O ", " o H f X o W jX8XqXqXwXgXpX0XqXqX0XtXy.6XwXrX>X%.m.` W.aX5XlX=. O ", " o H f X o W jX8XqXqXqX9X9XqXqXqX0XtXy.6XwXwX9XO.g h j.uX0X7XlX=. O ", " o H f X o W jX8XqXqXqXqXqXqXqXqX0XtXy.6XwXqXwXgXsXdXsXqXqX7XlX=. O ", " o G d . o E dX4X7X7X7X7X7X7X7X7X6XqXr.2X8X7X7X5X6X5X5X7X7X3XgX&. O ", " o I j X O ( DXgXlXlXlXlXlXlXlXlXkXvXj.dXzXlXlXlXlXlXlXlXlXgXGX2. O ", " . e 2 . X p 1.&.=.=.=.=.=.=.=.=.*.;.S %.=.=.=.=.=.=.=.=.=.&.2.v X ", " ", " . . . O O O O O O O O O O O O X O O O O O O O O O O O O X ", " ", " " }; const char *const *const xpm_icons[] = { xpm_icon_0, xpm_icon_1, xpm_icon_2, }; const int n_xpm_icons = 3; puzzles-20170606.272beef/icons/pegs-icon.c0000644000175000017500000003613713115373753017051 0ustar simonsimon/* XPM */ static const char *const xpm_icon_0[] = { /* columns rows colors chars-per-pixel */ "16 16 225 2 ", " c gray84", ". c #DADADA", "X c gray86", "o c #DADADA", "O c #D9D9DA", "+ c #E3E3D8", "@ c #E5E5D8", "# c #D8D8D9", "$ c #D5D5D5", "% c #D5D5D5", "& c #D5D5D5", "* c #D5D5D5", "= c #D5D5D5", "- c gray86", "; c #DBDBDA", ": c #DADADC", "> c #E1E1DA", ", c #B5B5E2", "< c #B0B0E5", "1 c #DADAD2", "2 c #D0D0D1", "3 c gray84", "4 c #D5D5D5", "5 c #D7D7D7", "6 c #CBCBCB", "7 c #A6A6A8", "8 c #CBCBC4", "9 c #BEBEDB", "0 c #0808FC", "q c blue", "w c #A4A4D5", "e c #DADACF", "r c #D4D4D6", "t c #D5D5D5", "y c #D7D7D7", "u c gray81", "i c #B1B1B2", "p c #CECEC9", "a c #C9C9DA", "s c #1D1DF8", "d c #1111FD", "f c #B4B4D4", "g c #D7D7D0", "h c #D4D4D6", "j c #D5D5D5", "k c #D5D5D5", "l c #D7D7D7", "z c gray86", "x c #D6D6D8", "c c #DADAD3", "v c #CDCDD9", "b c #CBCBDC", "n c #D5D5CD", "m c #D0D0D1", "M c gray84", "N c #D5D5D5", "B c gray84", "V c #D2D2D2", "C c #C0C0C0", "Z c gray81", "A c #D6D6D8", "S c #C9C9C6", "D c #CACAC6", "F c #CECED0", "G c gray82", "H c gray84", "J c #D5D5D5", "K c #D5D5D5", "L c #D5D5D5", "P c #D5D5D5", "I c #D5D5D5", "U c #D5D5D5", "Y c #D8D8D7", "T c #CACACB", "R c #9E9EA2", "E c #C2C2C3", "W c #DBDBDA", "Q c #ACACB0", "! c #AAAAAE", "~ c #CFCFCE", "^ c #CFCFD0", "/ c #D2D2D5", "( c #D3D3D4", ") c gray83", "_ c #D1D1D4", "` c #D1D1D4", "' c gray83", "] c #D5D5D5", "[ c #D5D5D5", "{ c #D7D7D4", "} c #DBDBCA", "| c #D7D7D2", " . c #D4D4D7", ".. c #D9D9CE", "X. c #DBDBCE", "o. c #CFCFD1", "O. c #D9D9D6", "+. c #E9E9D9", "@. c #DEDEDA", "#. c #D9D9DB", "$. c #E5E5D8", "%. c #E5E5D9", "&. c #D7D7D9", "*. c #D5D5D4", "=. c #D7D7D4", "-. c #CECED6", ";. c #8F8FE5", ":. c #C3C3D9", ">. c #E0E0D3", ",. c #A7A7E0", "<. c #9F9FE1", "1. c #DEDED4", "2. c #CFCFDC", "3. c #9292E9", "4. c #CCCCDD", "5. c #E4E4D8", "6. c #A6A6E4", "7. c #A9A9E6", "8. c #D8D8D1", "9. c #D0D0D1", "0. c #E5E5D2", "q. c #6464EB", "w. c #4949F1", "e. c #C5C5D8", "r. c #0505FE", "t. c #B8B8DB", "y. c #6060EB", "u. c #5454ED", "i. c #BEBED8", "p. c blue", "a. c #0101FF", "s. c #ABABD3", "d. c #D9D9D0", "f. c #E2E2D2", "g. c #8383E5", "h. c #6868EA", "j. c #D3D3D5", "k. c #2323F8", "l. c #1515FB", "z. c #C8C8D8", "x. c #7F7FE6", "c. c #7575E8", "v. c #CECED7", "b. c #1C1CF9", "n. c #1F1FFB", "m. c #BCBCD2", "M. c #D6D6D0", "N. c #D4D4D5", "B. c #E2E2D2", "V. c #CACAD7", "C. c #DFDFD3", "Z. c #DEDED3", "A. c #D6D6D5", "S. c #D2D2D6", "D. c #E0E0D3", "F. c #D9D9D5", "G. c #CACADB", "H. c #D9D9D5", "J. c #DFDFD3", "K. c #D4D4D5", "L. c #D5D5D6", "P. c #D7D7CC", "I. c #CFCFD2", "U. c #DFDFD3", "Y. c #9898E1", "T. c #1B1BFA", "R. c #7F7FE6", "E. c #D8D8D4", "W. c #4242F2", "Q. c #3737F4", "!. c #C7C7D9", "~. c #D3D3D0", "^. c #BFBFBD", "/. c #D1D1CF", "(. c #CBCBD8", "). c #3D3DF2", "_. c #3E3EF4", "`. c #C4C4D0", "'. c #D4D4D1", "]. c #E5E5D2", "[. c #5F5FEC", "{. c #4545F1", "}. c #C0C0D9", "|. c #0202FF", " X c #A8A8E1", ".X c #D2D2C6", "XX c #9D9DA3", "oX c #CECEC4", "OX c #B2B2DF", "+X c #0000FE", "@X c #A8A8D5", "#X c #DADACF", "$X c #D9D9D4", "%X c #C2C2D9", "&X c #6B6BEA", "*X c #B2B2DC", "=X c #E0E0D3", "-X c #8A8AE4", ";X c #8282E5", ":X c #D8D8D5", ">X c #D5D5D5", ",X c #CECECF", " , < 1 2 3 4 * * * * * ", "5 6 7 8 9 0 q w e r t * * * * * ", "y u i p a s d f g h j * * * * * ", "k l z x c v b n m M N * * * * * ", "B V C Z A S D F G H J K L P I U ", "Y T R E W Q ! ~ ^ / ( ) _ ` ' ] ", "[ { } | ...X.o.O.+.@.#.$.%.&.*.", "=.-.;.:.>.,.<.1.2.3.4.5.6.7.8.9.", "0.q.q w.e.r.q t.y.q u.i.p.a.s.d.", "f.g.q h.j.k.l.z.x.q c.v.b.n.m.M.", "N.B.V.C.Z.A.S.D.F.G.H.J.K.L.P.I.", "U.Y.T.R.E.W.Q.!.~.^./.(.)._.`.'.", "].[.q {.}.|.q X.XXXoXOX+Xq @X#X", "$X%X&X*X=X-X;X:X>X,X c #7171E9", ", c #A6A6A6", "< c #ABABAB", "1 c #B3B3B3", "2 c #BBBBBB", "3 c #9F9FDF", "4 c #A4A4DE", "5 c #ABABDC", "6 c #BEBED7", "7 c #B4B4DC", "8 c #BCBCDA", "9 c #8383E5", "0 c #8B8BE3", "q c #8181E8", "w c #9393E2", "e c #9C9CE1", "r c #A1A1E1", "t c #C4C4C4", "y c #CDCDC3", "u c #CDCDCE", "i c #D4D4C2", "p c #D0D0CF", "a c #CDCDD3", "s c #C3C3D8", "d c #C8C8D8", "f c #D5D5D5", "g c #DCDCD3", "h c #D5D5D8", "j c #DADADA", "k c #F2F2CF", "l c #E2E2D2", "z c #EBEBD1", "x c #E7E7DE", "c c #EBEBDD", "v c #F1F1DF", "b c #DEDEE0", "n c #E2E2E2", "m c #E9E9E0", /* pixels */ "ffffffffffffffffffffffffffffffff", "ffjjjjjjjjjjjjjhffffffffffffffjg", "fjnxnnnnxncvmmnfpfffffffffffffff", "ffffffffff6&%5gtpjffffffffffffff", "fffu<k: . qiaf", "fj7. :z5 9z4 0ze eiaf", "ffg:. $faf:. %jfg>. -ffg- ;gtff", "fffgd8gfffgs8gfffgs6gfffgs6fftff", "fffflllffffllgffffjgffffglzfftff", "fff7*+0ffg5@+wgffjaufffl4++4gtff", "ffao elsX 4lft<gtff", "ffflasgjfflaslffffjjfffflaagjtff", "ffffffffffffffffffffffffffffffff", "ffffffffffffffffffffffffffffffff" }; /* XPM */ static const char *const xpm_icon_2[] = { /* columns rows colors chars-per-pixel */ "48 48 254 2 ", " c blue", ". c #0101FF", "X c #0303FE", "o c #0202FF", "O c #0404FE", "+ c #0505FE", "@ c #0606FE", "# c #0808FD", "$ c #0909FD", "% c #0A0AFC", "& c #0B0BFD", "* c #0A0AFE", "= c #0C0CFD", "- c #0F0FFC", "; c #1212FB", ": c #1414FA", "> c #1414FB", ", c #1717FA", "< c #1616FB", "1 c #1010FC", "2 c #1212FC", "3 c #1313FC", "4 c #1919FA", "5 c #1A1AFA", "6 c #1B1BFA", "7 c #1C1CF9", "8 c #1D1DF9", "9 c #1E1EF9", "0 c #1F1FF9", "q c #1E1EFA", "w c #1F1FFA", "e c #2323F7", "r c #2727F7", "t c #2828F7", "y c #2929F7", "u c #2A2AF6", "i c #2B2BF7", "p c #2C2CF6", "a c #2D2DF6", "s c #2F2FF6", "d c #2121F8", "f c #2020F9", "g c #2121F9", "h c #2222F8", "j c #2323F8", "k c #2525F8", "l c #2626F8", "z c #2929F8", "x c #3737F3", "c c #3131F5", "v c #3232F5", "b c #3333F5", "n c #3131F6", "m c #3535F4", "M c #3434F5", "N c #3636F4", "B c #3737F4", "V c #3B3BF3", "C c #3C3CF3", "Z c #3D3DF3", "A c #3F3FF2", "S c #3E3EF3", "D c #3F3FF3", "F c #3838F4", "G c #3939F4", "H c #3A3AF4", "J c #4242F2", "K c #4343F2", "L c #4646F1", "P c #4747F1", "I c #4A4AF0", "U c #7878E7", "Y c #7979E7", "T c #7D7DE6", "R c #7E7EE6", "E c #7171E9", "W c #7676E8", "Q c gray65", "! c #A7A7A7", "~ c #A9A9A9", "^ c #AAAAAA", "/ c gray67", "( c #ACACAC", ") c gray68", "_ c #AEAEAE", "` c #AFAFAF", "' c gray69", "] c #B1B1B1", "[ c #B2B2B2", "{ c gray70", "} c #B4B4B4", "| c gray71", " . c #B6B6B6", ".. c gray74", "X. c gray", "o. c #BEBEBF", "O. c gray75", "+. c #C2C2BF", "@. c #9C9CDF", "#. c #BCBCC0", "$. c #BDBDC0", "%. c #BEBEC2", "&. c #A1A1DF", "*. c #A2A2DF", "=. c #A4A4DF", "-. c #A6A6DE", ";. c #A7A7DE", ":. c #AAAADD", ">. c #ABABDD", ",. c #ACACDD", "<. c #ADADDD", "1. c #BEBED6", "2. c #B0B0DC", "3. c #B1B1DC", "4. c #BBBBDA", "5. c #BCBCDA", "6. c #8383E5", "7. c #8181E6", "8. c #8585E4", "9. c #8484E5", "0. c #8686E4", "q. c #8686E5", "w. c #8484E6", "e. c #8B8BE3", "r. c #8E8EE3", "t. c #8F8FE3", "y. c #8888E4", "u. c #8989E4", "i. c #8989E5", "p. c #8A8AE4", "a. c #8B8BE4", "s. c #8D8DE4", "d. c #9191E2", "f. c #9090E3", "g. c #9393E2", "h. c #9696E1", "j. c #9494E2", "k. c #9595E2", "l. c #9898E1", "z. c #9999E1", "x. c #9A9AE1", "c. c #9C9CE0", "v. c #9D9DE0", "b. c #9D9DE1", "n. c #9E9EE0", "m. c #9F9FE0", "M. c #C0C0C0", "N. c #C1C1C1", "B. c #C2C2C1", "V. c #C1C1C2", "C. c #C6C6C0", "Z. c gray77", "A. c #C8C8C8", "S. c #C9C9CB", "D. c #CACACA", "F. c #CACACB", "G. c #CBCBCB", "H. c gray80", "J. c #CCCCCD", "K. c #CDCDCD", "L. c #CECECE", "P. c gray81", "I. c #DDDDCF", "U. c #DEDECF", "Y. c #CFCFD2", "T. c #C8C8D4", "R. c #C9C9D7", "E. c #CACAD7", "W. c #CBCBD7", "Q. c #CCCCD7", "!. c #CDCDD7", "~. c #CFCFD6", "^. c #C1C1D9", "/. c #C2C2D9", "(. c #C6C6D8", "). c #C5C5DC", "_. c #CFCFDA", "`. c #D0D0D0", "'. c #D0D0D1", "]. c gray82", "[. c #D0D0D2", "{. c #D1D1D2", "}. c #D2D2D2", "|. c LightGray", " X c #D5D5D2", ".X c #D2D2D5", "XX c #D3D3D5", "oX c #D0D0D6", "OX c #D1D1D6", "+X c #D2D2D6", "@X c #D3D3D6", "#X c gray83", "$X c #D4D4D5", "%X c #D5D5D5", "&X c #D6D6D4", "*X c #D6D6D5", "=X c #D7D7D5", "-X c #D4D4D6", ";X c #D5D5D6", ":X c gray84", ">X c #D6D6D7", ",X c #D7D7D7", ".% p.wXXX7X;.@ t.cXXX7Xv.@ h.7XXX7Xx. v.cXo.L.%X%X%X", "%X%X%X%XXXwX,.A 5 n g.7X%X%XXX7X;.V 5 n x.7X%X%XXX7X*.H 5 m v.7XXX%XXX7Xm.H 5 H m.7XpXo.L.%X%X%X", "%X%X%X%X%XXX7X7XXX8XcX%X%X%X%XXX7XwXXX8X7XXX%X%X%XXX7X7XXXwXcXXX%X%X%XXXwXwXXX8X7XXXpX+.L.%X%X%X", "%X%X%X%X%X%XXX%XwX%X!.%X%X%X%X%XXXXXwX%XXX%X%X%X%X%XXXXX%XXXXX%X%X%X%X%XXX%X8X%XXXXX8Xo.L.pX%X%X", "%X%X%X%X%XXXwXXX4._.cX X%X%X%XXXcXXX4.!.wX%X%X%X%X%X%XXXpX%X%X%X%X%X%X%XcX!.5.XX7XXXdX%.L.dX%X%X", "%X%X%X%XXX7Xe.g @ , E 9X%X%XXXwXp.q @ , W 8X%X%X%X%XpXXXL.}.dX%X%X%X%XwXT 5 @ 5 6.wX%Xo.L.dX%X%X", "%X%X%XXXcXh. E cXXXcXg. U cXXX%X%XF.' ^ _ G.%X%XXXcX6. 0.mX%.G.%X%X%X", "%X%X%XXX7XA @ 5 _.%X8Xm @ @ q XX%X%X%X' Q ^ Q ' %X%X%X%Xz @ @ t 8X%.L.dX%X%X", "%X%X%X%X%Xg @ 4.8XXXq = (.8X%X}.( ^ ^ ^ ^ L.pX%XT.3 , _.+.L.%X%X%X", "%X%X%XXX7XI @ @ k XXXXwXJ @ @ t %X%X%X%X .Q ^ Q { %X%X%X8Xn @ @ m kX+.L.8X%X%X", "%X%X%XXX7X3.= e.cXXXwX>.% h.wXXX%X%X}. ./ .Y.%X%X%XcXv. @ *.cXo.L.%X%X%X", "%X%X%X%XXX7X,.L e H x.7XXX%X%X7X,.L g H v.7XXX%X%X%X8XdX}.%X%X%X%X%XXX7X;.A g A ;.7X%Xo.L.pX%X%X", "%X%X%X%X%XXX7X7X8X7X7XXX%X%X%XXX7XcX%XwXcX%X%X%X%X%X%X%X%X%X%X%X%X%X%XXX7X7X%X7X7XXXpX%.L.pX%X%X", "%X%X%X%X%X%XXXXX%XXXXX%X%X%X%X%XXXXX%XXXXX%X%X%X%X%X%X%X%X%X%X%X%X%X%X%XXXXX%XXXXX%X%X%X}.%X%X%X", "%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X", "%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X", "%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X%X" }; const char *const *const xpm_icons[] = { xpm_icon_0, xpm_icon_1, xpm_icon_2, }; const int n_xpm_icons = 3; puzzles-20170606.272beef/icons/pearl-icon.c0000644000175000017500000004704713115373753017220 0ustar simonsimon/* XPM */ static const char *const xpm_icon_0[] = { /* columns rows colors chars-per-pixel */ "16 16 256 2 ", " c black", ". c #010101", "X c #020202", "o c gray1", "O c #040404", "+ c gray2", "@ c #060606", "# c #070707", "$ c gray3", "% c #090909", "& c gray4", "* c #0B0B0B", "= c #0C0C0C", "- c gray5", "; c #0E0E0E", ": c gray6", "> c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", ".C % ^.3XeXL.:.;.#.>.9.1X2X-.", " .K 8 F.3XsX^ 3 Y A F @ [.6X=.", "=.xXB.i hX$XjXY 5.FX0XhXq `.7X=.", "*.*Xd.p 5X'.9XJ X.6X'.+X3 I.%X=.", "*.wXn.a dX%XaX .8.sX=X7X5 _.7X=.", "*.wXn.a dX>XoXmXdX$X1X6X5 _.7X=.", "*.rXm.s gX:XXZ ;.zX;X,Xe.XX4X-.", "*.7XJ.@ 5 1 6 o e.sX%X+XIX>X$X>.", ";.4XuX3X5X+X1X4XwXrX3X4X#.XX9X-.", "-.`.@X@X$X'.+X#X+X X_..X4 G..X=.", "&.#.@.+.+.@.@.+.@.#.#.@.&.#.#.&." }; /* XPM */ static const char *const xpm_icon_1[] = { /* columns rows colors chars-per-pixel */ "32 32 256 2 ", " c black", ". c #010101", "X c #020202", "o c gray1", "O c #040404", "+ c gray2", "@ c #060606", "# c #070707", "$ c gray3", "% c #090909", "& c gray4", "* c #0B0B0B", "= c #0C0C0C", "- c gray5", "; c #0E0E0E", ": c gray6", "> c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", "XiXwXtXsXtXeXyX8X XiXrXrXrXrXrXeXiX X8XyXrXrXrXrXrXiX,X&.&.", "&.&.;XeXuXqXoXwXyXqX5X{.rX0X0XqXqXqX0XrX{.4XwX0XqXqX0X0XrX-X&.&.", "&.&.-XsX Xj . z @XiX3X{.tX0XqXwXwXwXqXyX}.6XrXwXwXwXqX0XtX;X&.&.", ";.` q s 1 o ^ hX2X{.eXpX(.9 u u u i w y u u u 6 T.aXwX;X&.&.", ":.( . . o Z fX3X{.wXaXE. . X G.dXwX;X&.&.", "*.+.N.^.0.. N.fX2X{.wXaXW. 5 L.P.Y.k.G.I.U.e J.dXwX;X&.&.", "%.*.6XfXbX' | zX8X4X{.wXaXW. w pXdXhX@XtXfXhXd H.sXqX-X&.&.", "&.&.:XeXzX$. =.cXeX9X XuXhX^. q qXeXyX}.6XrXyXs P.kXuXXZ. 0 +X$X&XR.oX%X&Xu v.XrXzX+. $.lX0X6X}.eXsXQ. q wXrXuX|.7XtXiXf I.gXtX>X&.&.", "&.&.-X0XhXO. *.mXuXwXOXaXlX(. 0 8X0XrX{.3XrX7Xj O B.gXqX-X&.&.", "&.&.;XqXjXO. ` #X_./.Z.].XXc. q 9XqXrX{.5XrXS.wXDXP.+XaX-X&.&.", "&.&.;XqXjX . O . 9 9XqXrX[.wXXXoXUXUXvXJ.dX=X&.&.", "&.&.;XqXhX*.O 4 1 1 < > 1 1 2 - h 9XqXrX{.qX@X[.UXUXgXL.dX=X&.&.", "&.&.;XtXqX6X2X3X2X4X:X(.6X2X3X2X3XqX0XtX{.4XuXK.].6XB.>XiX-X&.&.", "&.&.=XeX8XqXwXwXwXeX6X}.tXqXwXwXqX9X8XeX[.3XqXrXi G.fX0X=X&.&.", "&.&.3XfXiXpXiXiXiXaXwXXXdXuXiXiXiXpXiXfXoXwXaXdXf Y.xXaX3X&.&.", "&.&.J.!.E.E.E.E.E.W.Y.V.!.E.E.E.E.E.E.!.V.U.W.Q.g . u.).W.J.&.&.", "&.&.o.X.X.X.X.X.X.X.X.O.X.X.X.X.X.X.X.X.O.X.X.X.$.&.O.X.X.o.&.&.", "&.&.=.=.=.=.=.=.=.=.=.*.=.=.=.=.=.=.=.=.*.=.=.=.*.&.=.=.=.=.&.&." }; /* XPM */ static const char *const xpm_icon_2[] = { /* columns rows colors chars-per-pixel */ "48 48 256 2 ", " c black", ". c #010101", "X c #020202", "o c gray1", "O c #040404", "+ c gray2", "@ c #060606", "# c #070707", "$ c gray3", "% c #090909", "& c gray4", "* c #0B0B0B", "= c #0C0C0C", "- c gray5", "; c #0E0E0E", ": c gray6", "> c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", ". >.lX5X8XuX'.OXtX7XuX X. 6 7XqX9X0X0X6.@.*.&.", "&.&.=.X.`.iX9XwX8X6 . .XiX9XqXwXT.0XqX0XdX` l l ` fX0X9XiX].+XuX9XiX.X. 6 8XwX0XqXqX7.@.*.&.", "&.&.=.X.`.iX9XwX8X6 . .XiX9XqXwXT.0X0XuXd.[.UXUX[.f.iX9XiX].+XuX9XiX.X. 6 8XwX0XqXqX7.@.*.&.", "&.&.=.X.`.iX9XwX8X6 . .XiX9XqXwXT.9XpX_.D.UXLXLXUXS._.iXuX].+XuX9XiX.X. 6 8XwX0XqXqX7.@.*.&.", "&.&.=.X.`.iX9XwX8X6 . .XiX9XqXwXT.8XgXS.&XUXLXLXUX&XS.fXyX].+XuX9XiX.X. 6 8XwX0XqXqX7.@.*.&.", "&.&.=.X.`.iX9XwX8X6 . .XiX9XqXwXT.9XaX~.P.UXJXJXUXL.~.pXuX].+XuX9XiX.X. 6 8XwX0XqXqX7.@.*.&.", "&.&.=.X.`.iX9XwX8X6 . .XiX9XqXwXT.0XqXrXt.XMXjXlXzX'.kXlXgXGX2. =.lX7X0XiX].+XyXeX4X9.Y.wXM.s.rXqXqXqX7.@.*.&.", "&.&.=.X.`.iX9XwX8X6 . ` %.+.@.@.W +.@.O.-.z =.lX7X0XiX].+XtXiXg. c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", "X:X,X=X;X=X=X c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", ".-.%.,.;.4.E O X $ - . # U VXhX", "lXlXlXlXjXCXG.i.BXgXBXM.9.j.f.p.r.g.a.x.| X @ = O Y CXhX", "lXlXlXlXkXMX|.g.bXhXBXn.2.p.y.w.8.u.r.f.] X @ = O U CXhX", "lXlXlXlXlXlXjXxXzXjXBXm.w.z.k.d.u.l.g.n.X. o # - + Y CXhX", "lXlXlXlXlXkXMXmXkXjXCXl.f m v n M v v n l - ; - < 5 = , . ~ VXhX", "lXlXlXlXkXmXOX}.nXgXZXg. X + = . - o + = O U CXhX", "lXlXlXlXjXCXJ.=.MXgXCXg. O . # : X + X > o @ - @ Y CXhX", "lXlXlXlXkXcX0X*XxXhXZXg. X + = . - o + = O U CXhX", "lXlXxXlXlXkXbXNXkXhXCXh.o - * ; a y u u i = * & : a y p 5 | NXjX", "lXkXsXlXlXzXsXfXzXhXCXg. $ $ #XUXAXUXP. & # *XUXFXUXwXdXxX", "kXvXg.qXcXNX|.D.ZXfXZXg. X X &XUXGXUXU. O . ;XUXKXUXtXdXxX", "kXnXd.-XnXmXOXl.MXgXCXg. O O %XUXFXUXI. O . *XUXGXUXwXdXxX", "lXkXkXkXlXlXjXjXlXhXZXg. X X &XUXGXUXU. @ o ;XUXKXUXtXdXxX", "lXlXlXlXlXkXcXNXkXjXVXc.T ] ` ^ d.H.C.P.;.@ > - : T _ _ E 8.nXkX", "lXlXlXlXkXvXwX}.bXhXBXm.w.z.k.f.7.e.0.p.` . + = O U CXhX", "lXlXlXlXjXCXV.} BXgXBXn.3.a.u.e.q.s.i.k.} O . # > o % R VXhX", "lXlXlXlXlXzXaX1XzXjXBXv.3.a.i.e.8.i.t.g.] X + * o I CXhX", "lXlXlXlXlXlXxXnXlXjXNXA.9.f.s.i.r.s.p.j.%.w i y a h t p 5 X.BXjX", "lXlXlXlXlXlXlXkXlXlXlXhXsXsXsXsXsXsXsXsXfXjXjXjXjXjXjXjXjXjXlXlX", "lXlXlXlXlXlXlXlXlXlXlXzXxXxXxXxXxXxXxXxXxXzXzXzXzXzXzXzXzXzXlXlX" }; /* XPM */ static const char *const xpm_icon_2[] = { /* columns rows colors chars-per-pixel */ "48 48 256 2 ", " c black", ". c #010101", "X c #020202", "o c gray1", "O c #040404", "+ c gray2", "@ c #060606", "# c #070707", "$ c gray3", "% c #090909", "& c gray4", "* c #0B0B0B", "= c #0C0C0C", "- c gray5", "; c #0E0E0E", ": c gray6", "> c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", ".pXxXhXBX[.E 2XbXkXkXMXe.e.MXkXjXnX_.=.6XbXkXlXlXlXlX", "lXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXVXBXxXlXlXlXlXlXgXzXlXlXkXjXkXkXlXlXzXgXxXvXkXlXlXlXlXlX", "lXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXjXjXlXlXlXlXlXlXzXlXlXlXlXzXzXlXlXlXlXzXlXkXlXlXlXlXlXlX", "lXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXlXlXlXlX", "lXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXxXmXnXnXnXnXnXnXnXnXnXnXnXnXbXbXbXbXbXbXbXbXbXbXvXbXvXlXlXlXlX", "lXlXlXlXlXlXlXlXlXlXlXkXlXlXlXlXxXpX._.BXjXjXBX(.2 X X 2 . . . < # . . # < . . O ) ZXhXlXlX", "lXlXlXlXlXlXlXlXlXzXhXkXmXkXlXjXBX(.1 . X 2 . , # # , . o ( ZXhXlXlX", "lXlXlXlXkXkXlXlXlXlXlXjXkXlXlXjXBX/.8 $ = * & - 6 . o o o 2 , % * * % , 2 o o @ _ ZXhXlXlX", "lXlXlXkXMXnXkXlXlXkXcXNXlXlXlXjXBX/.0 = : ; , . r.kX0XeXqXgXI.# > ; ; > # I.gXqXeXeXtX|.hXzXlXlX", "lXlXkXvX&XXdXzXlXlX", "lXlXjXCXP.| nXkXkXxXpXW #XmXkXjXBX(.1 . O z.UXKXUXLXUXoX X X oXUXLXUXIXUX,XdXzXlXlX", "lXlXkXcX*X'.gXzXkXcXrX^.6XvXkXjXBX(.2 o X @ z.UXHXPXJXUXXX X X .XUXGXKXJXUX:XfXzXlXlX", "lXlXlXkXmXVXzXlXlXkXcXCXbXkXlXjXBX(.1 . O z.UXKXUXLXUXoX o . . o oXUXLXUXIXUX,XdXzXlXlX", "lXlXlXlXkXjXlXlXlXlXkXgXkXlXlXjXVXQ.D R U U T H 2.U.F.H.F.U.r., 3 2 2 2 2 } ,.-.-.:.#.s.bXkXlXlX", "lXlXlXlXlXlXlXlXlXlXzXnXlXlXlXjXCXY.%.b.j.k.k.j.3.0.0.0.9.t.+. # , . o ( ZXhXlXlX", "lXlXlXlXlXlXlXlXlXlXxX:.*XMXkXjXCXT.o.d.t.y.y.t.5.s.p.a.p.h.=. # 2 . O O # _ ZXhXlXlX", "lXlXlXlXlXlXlXlXhXVXU.e K.ZXhXjXCXT.O.g.u.i.i.u.4.p.i.i.u.f.&. # , . o ( ZXhXlXlX", "lXlXlXlXlXlXlXlXlXzXsXC.oXMXkXjXCXT.+.g.u.i.i.u.5.p.i.i.u.f.*. X X X $ 1 X X + ) ZXhXlXlX", "lXlXlXlXlXlXlXlXlXlXcXZXnXkXlXhXCXY.o.h.u.i.p.u.4.p.i.i.u.g.&. # , . o ( ZXhXlXlX", "lXlXlXlXlXlXlXlXlXlXlXhXkXlXlXjXVX!.@.p.e.r.r.e.4.t.r.r.e.i.-.w e e e q u h 0 e e t < #.VXjXlXlX", "lXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXzXgXyXtXyXyXyXyXyXtXyXyXyXtXuXdXdXdXdXdXdXsXdXdXdXdXdXfXlXlXlXlX", "lXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXzXcXcXcXcXcXcXcXcXcXcXcXcXcXxXxXxXxXxXxXxXxXxXxXxXxXxXlXlXlXlX", "lXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXlXlXlXlXlX", "lXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlX" }; const char *const *const xpm_icons[] = { xpm_icon_0, xpm_icon_1, xpm_icon_2, }; const int n_xpm_icons = 3; puzzles-20170606.272beef/icons/palisade-icon.c0000644000175000017500000003415013115373753017666 0ustar simonsimon/* XPM */ static const char *const xpm_icon_0[] = { /* columns rows colors chars-per-pixel */ "16 16 253 2 ", " c gray83", ". c #C0C0C0", "X c #BBBBBB", "o c #BBBBBB", "O c #BCBCBC", "+ c #BCBCBC", "@ c #BCBCBC", "# c #BCBCBC", "$ c #BCBCBC", "% c #BCBCBC", "& c #BCBCBC", "* c gray74", "= c gray74", "- c gray", "; c LightGray", ": c #C0C0C0", "> c gray58", ", c #B1B1B1", "< c gray69", "1 c gray67", "2 c #AAAAAA", "3 c #AEAEAE", "4 c gray68", "5 c gray67", "6 c #AAAAAA", "7 c gray68", "8 c #B1B1B1", "9 c gray61", "0 c gray56", "q c #B6B6B6", "w c gray82", "e c gray73", "r c #B9B9B9", "t c #C0C0C0", "y c #959595", "u c #E2E2E2", "i c gray84", "p c #DDDDDD", "a c gainsboro", "s c gray85", "d c #D7D7D7", "f c gainsboro", "g c #E1E1E1", "h c gray77", "j c #B3B3B2", "k c #E4E4E3", "l c gray83", "z c gray73", "x c #B6B6B6", "c c #AAAAAA", "v c gray54", "b c gray86", "n c #D2D2D2", "m c #DADADA", "M c gray85", "N c #D7D7D6", "B c #D5D5D4", "V c gray85", "C c gray87", "Z c #C2C2C1", "A c #ACACB0", "S c #DBDBE0", "D c #D3D3D4", "F c #BCBCBC", "G c gray67", "H c #DADADA", "J c #D2D2D2", "K c #D0D0D0", "L c gray74", "P c gray", "I c gray74", "U c #BBBBBC", "Y c #BABABB", "T c #BEBEBD", "R c #C3C3C2", "E c #A8A8A9", "W c #A9A999", "Q c #DBDBC6", "! c #D3D3D2", "~ c #BCBCBC", "^ c #AAAAAA", "/ c #D7D7D7", "( c #D7D7D7", ") c gray74", "_ c #909090", "` c #B1B1B1", "' c #B1B1B4", "] c #AAAA9B", "[ c #A9A98E", "{ c #ADADB1", "} c #ADADB0", "| c #A8A89A", " . c #C1C18B", ".. c #D4D4B6", "X. c #D4D4D1", "o. c #BBBBBB", "O. c #B4B4B4", "+. c gray72", "@. c gray58", "#. c #C5C5C5", "$. c #B8B8B7", "%. c #BFBFBD", "&. c #8D8D91", "*. c #E3E3CC", "=. c #D6D6B0", "-. c #DDDDE3", ";. c #DDDDE0", ":. c #DBDBC4", ">. c #D4D4B2", ",. c #D6D6E3", "<. c #D5D5D4", "1. c gray73", "2. c #B6B6B6", "3. c gray67", "4. c gray57", "5. c #C6C6C6", "6. c #B1B1B5", "7. c #B4B4B8", "8. c #84848E", "9. c #DADAC9", "0. c #CFCFAE", "q. c #D5D5E0", "w. c #D4D4DD", "e. c #D2D2C1", "r. c #D2D2B0", "t. c #D6D6E0", "y. c #D5D5D4", "u. c #BCBCBC", "i. c gray67", "p. c gray85", "a. c #D7D7D7", "s. c #BBBBBC", "d. c #ABAB9B", "f. c #D9D9C3", "g. c #D6D6C5", "h. c #CECEA9", "j. c #CBCB9A", "k. c #D4D4C4", "l. c #D3D3C1", "z. c #CECEA9", "x. c #CBCB99", "c. c #D4D4C6", "v. c #D5D5D2", "b. c #AAAAAA", "n. c #D7D7D7", "m. c #DADAD9", "M. c #BABABB", "N. c #A9A98E", "B. c #D8D8B1", "V. c #D5D5B4", "C. c #CBCB99", "Z. c #C7C78C", "A. c #D3D3B2", "S. c #D2D2B0", "D. c #CBCB9A", "F. c #C6C68B", "G. c #D3D3B6", "H. c #D4D4D1", "J. c #BBBBBB", "K. c #B4B4B4", "L. c #B6B6B6", "P. c gray54", "I. c #C5C5C5", "U. c #B2B2B7", "Y. c #B7B7BD", "T. c #858591", "R. c #DCDCCC", "E. c #D1D1B1", "W. c #D6D6E4", "Q. c #D6D6E1", "!. c #D4D4C4", "~. c #D3D3B2", "^. c #D6D6E3", "/. c #D5D5D4", "(. c gray73", "). c gray72", "_. c gray73", "`. c #909090", "'. c gray79", "]. c #B7B7B6", "[. c #BBBBB8", "{. c #8B8B8F", "}. c #E0E0C9", "|. c #D0D0AA", " X c #D6D6DB", ".X c #D6D6D8", "XX c #D3D3BD", "oX c #D2D2B0", "OX c #D6D6E0", "+X c #D5D5D4", "@X c gray74", "#X c gray61", "$X c #C3C3C3", "%X c #C6C6C6", "&X c #A9A9A9", "*X c #9A9A9A", "=X c #C4C4C3", "-X c #C1C1C6", ";X c #BBBBA8", ":X c #CBCBA9", ">X c #D4D4DA", ",X c #D3D3D6", " , < 1 2 3 4 5 6 7 8 9 0 q w ", "e r t y u i p a s d f g h j k l ", "z x c v b n m M N B V C Z A S D ", "F G H J K L P I U Y T R E W Q ! ", "~ ^ / ( ) _ ` ' ] [ { } | ...X.", "o.O.+.@.#.$.%.&.*.=.-.;.:.>.,.<.", "1.2.3.4.5.6.7.8.9.0.q.w.e.r.t.y.", "u.i.p.a.s.d.f.g.h.j.k.l.z.x.c.v.", "+ b.n.m.M.N.B.V.C.Z.A.S.D.F.G.H.", "J.K.L.P.I.U.Y.T.R.E.W.Q.!.~.^./.", "(.)._.`.'.].[.{.}.|. X.XXXoXOX+X", "@X#X$X%X&X*X=X-X;X:X>X,X c #777769", ", c #77776A", "< c #73736E", "1 c gray45", "2 c #747474", "3 c gray46", "4 c #767676", "5 c #777777", "6 c #787877", "7 c #797977", "8 c gray47", "9 c #797978", "0 c #797979", "q c #7B7B78", "w c gray48", "e c #7A7A7B", "r c #7B7B7B", "t c #79797C", "y c #79797D", "u c #7B7B7D", "i c #79797F", "p c #7C7C7C", "a c gray49", "s c #7E7E7D", "d c #7E7E7E", "f c gray50", "g c #979744", "h c #A2A244", "j c #BEBE68", "k c #BEBE6A", "l c #A2A273", "z c #C2C275", "x c #C8C875", "c c #C9C977", "v c #CACA76", "b c #CACA77", "n c #C9C978", "m c #CBCB78", "M c #CBCB79", "N c #CECE7A", "B c #CFCF7D", "V c #CCCC7E", "C c #CFCF7E", "Z c #D1D179", "A c #D7D77E", "S c #808080", "D c #848484", "F c gray53", "G c #888888", "H c #898988", "J c #929292", "K c #949492", "L c gray58", "P c #9B9B9D", "I c #9D9D9D", "U c #9E9E9D", "Y c #9F9F9F", "T c #B4B49B", "R c gray63", "E c #A4A4A4", "W c #AAAAAA", "Q c #AEAEAE", "! c #AFAFB5", "~ c #B4B4B4", "^ c gray71", "/ c #B4B4B6", "( c #B6B6B6", ") c #B7B7B7", "_ c #B8B8B7", "` c gray72", "' c #B9B9B9", "] c gray73", "[ c #BBBBBB", "{ c #B8B8BE", "} c #BCBCBC", "| c gray74", " . c #BEBEBD", ".. c gray", "X. c #D1D180", "o. c #D3D380", "O. c #D7D780", "+. c #CBCB9D", "@. c #CBCBB6", "#. c #CFCFB4", "$. c #CFCFB5", "%. c #D1D1B4", "&. c #D0D0B5", "*. c #D1D1B5", "=. c #D1D1B6", "-. c #D2D2B6", ";. c #D2D2B7", ":. c #D3D3B8", ">. c #D2D2B9", ",. c #D3D3BD", "<. c #D4D4BD", "1. c #D9D9BE", "2. c #BEBEC2", "3. c #C0C0C0", "4. c #C1C1C1", "5. c gray76", "6. c #C6C6C5", "7. c gray78", "8. c #C8C8C5", "9. c #C8C8C7", "0. c #C9C9C7", "q. c #C8C8C8", "w. c gray79", "e. c #CACAC9", "r. c #CACACA", "t. c #CBCBCB", "y. c gray80", "u. c #CECECE", "i. c #CFCFCE", "p. c gray81", "a. c #D4D4C1", "s. c #D5D5C1", "d. c #D5D5C2", "f. c #DEDEC1", "g. c #DFDFC1", "h. c #DEDEC2", "j. c #D1D1CF", "k. c #D4D4CF", "l. c #D0D0D0", "z. c #D1D1D0", "x. c gray82", "c. c #D2D2D0", "v. c #D2D2D1", "b. c #D3D3D1", "n. c #D2D2D2", "m. c LightGray", "M. c #D4D4D0", "N. c #D5D5D1", "B. c #D4D4D2", "V. c #D5D5D2", "C. c #D5D5D3", "Z. c #D6D6D3", "A. c gray83", "S. c #D5D5D4", "D. c #D5D5D5", "F. c #D6D6D4", "G. c #D6D6D5", "H. c #D5D5D6", "J. c #D5D5D7", "K. c gray84", "L. c #D7D7D7", "P. c #D1D1D8", "I. c #D3D3D9", "U. c #D3D3DA", "Y. c #D4D4DA", "T. c #D6D6DA", "R. c #D6D6DB", "E. c #D3D3DE", "W. c #D6D6DC", "Q. c #D6D6DD", "!. c #D4D4DE", "~. c #D6D6DE", "^. c #D6D6DF", "/. c #D8D8D8", "(. c #D8D8D9", "). c gray85", "_. c #DADADA", "`. c gray86", "'. c #D8D8DC", "]. c #D8D8DE", "[. c #D9D9DE", "{. c gainsboro", "}. c #DDDDDD", "|. c gray87", " X c #DFDFDE", ".X c #DFDFDF", "XX c #E0E0DE", "oX c #E1E1DE", "OX c #D6D6E0", "+X c #D6D6E1", "@X c #D7D7E2", "#X c #D6D6E3", "$X c #D6D6E4", "%X c #D9D9E3", "&X c #DCDCE3", "*X c #DFDFE5", "=X c #D6D6E8", "-X c #D7D7E9", ";X c #D7D7EE", ":X c #DFDFEA", ">X c gray88", ",X c #E1E1E0", ".D.D.", "}.` 1 D.w.w.w.w.m.) + d 8 8 3 6 8 , $ i 6 8 8 8 8 < g o.c V k.D.", "}.` 8 2Xm.2X5X`.}.` S uX}.tXuX3X0Xh.A qXoX2X2XoX0Xg.Z ;XW.+XD.D.", "}.` 8 2XD.D 8 w.}.) 8 }.m.J 6 6.R.$.c W.k.B.m.m.U.&.m W.m.B.D.D.", "}.` 3 2Xm.3.X Y 5X) 8 }.`.E Q *X&.m +XB.D.D.B.R.>.M +XB.D.D.D.", "}.` 8 }.`.8 + p.}.) 3 2Xm.W . Y 0X$.m +XZ.D.D.D.W.&.M +XB.D.D.D.", "}.` 8 2XD.1 - ..2X) 8 2Xp.G d 8.W.>.m +XB.B.D.B.].&.M ].B.D.D.D.", "}.) 8 3Xm.3X3XR.].) t 0XR.4X0X].+X,.C -XR.W.W.R.$X<.X.-XW.W.D.D.", "}.` 8 }.p.p.p.m.`./ : h.$.&.%.&.,.+.j a.&.>.>.&.<.+.j d.$.>.D.D.", "}.` 2 D.w.w.8.w.k.! $ A c c c m C j h o.m m M M C j h o.c V k.D.", "}.) 8 2XD.}.2X`.}._ u qXE.:XwX%X-Xa.o.;XW.W.%X].-Xa.Z ;XW.+XD.D.", "}.` 8 2Xm.J u 6.}.) 6 oXB.K 6 8.W.&.m W.m.B.B.B.R.&.m W.B.D.D.D.", "}.` 8 }.`.R Q 5X) 8 }.`.R Q *X$.m +XB.D.L.B.W.>.m W.B.D.D.D.", "}.` 8 2Xm.W . Y 5X) 8 2Xm.W . Y 4X&.m +XB.D.D.D.W.&.M %XB.D.D.D.", "}.` 3 2Xm.D d w.}.) 8 2Xm.D d 8.].&.m +XB.D.D.D.W.>.c %XB.B.D.D.", "}.) u tX].5XtX}.2X..d 7X`.5XtX}.&X1.M +XB.D.D.D.W.:.C -XR.R.D.D.", "}.` * 5.) ) ~ ) ..Y & 2.) ) ~ ) { T z E.k.m.m.m.U.$.j a.&.>.D.D.", "].@.O u 8 8 8 8 8 3 - 8 3 8 8 3 d % < `.w.w.8.y.p.2.l Z m C k.D.", "}._ i uX}.}.2X2X2X}.`.2X2XoX2X2XtX3.8 2Xm.2X3XR.D.D.U.+X+X+XD.D.", "}.` 3 }.m.m.m.m.m.p.q.D.m.m.m.m.{.) 6 2XD.D 8 p.D.m.w.D.m.B.D.D.", "}.` d 2Xm.D.D.m.D.m.y.D.A.D.B.B.{.` d oXl._ o Y 2Xp.p.D.A.D.D.D.", "D.D.l.D.D.D.D.D.D.D.m.D.D.D.D.D.D.m.p.D.D.}.m.m.D.D.A.D.D.D.D.D.", "D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.D.R.D.D.m.D.D.D.D.D.D.D.D.D.D." }; /* XPM */ static const char *const xpm_icon_2[] = { /* columns rows colors chars-per-pixel */ "48 48 80 1 ", " c #050505", ". c gray6", "X c #161616", "o c #1D1D1D", "O c #303019", "+ c #252525", "@ c #2C2C2C", "# c #343426", "$ c #323232", "% c #3B3B3B", "& c #464646", "* c #484845", "= c #4B4B4B", "- c #555555", "; c #5E5E5E", ": c #6D6D42", "> c #646464", ", c #6A6A6A", "< c #7D7D67", "1 c #757575", "2 c #828223", "3 c #99992F", "4 c #939334", "5 c #BBBB3F", "6 c #A6A646", "7 c #BFBF46", "8 c #B1B156", "9 c #B2B25D", "0 c #B4B47B", "q c #C6C647", "w c #C6C649", "e c #C9C94A", "r c #D1D14D", "t c #C8C856", "y c #C8C859", "u c #C2C261", "i c #C9C967", "p c #CACA69", "a c #D0D06D", "s c #CBCB74", "d c #D3D371", "f c #828282", "g c #8E8E8E", "h c #939393", "j c #9C9C9C", "k c #A4A4A4", "l c gray67", "z c gray71", "x c #BABAB7", "c c #BBBBBB", "v c #C8C884", "b c #CECE8E", "n c #D0D08E", "m c #CFCF93", "M c #D4D493", "N c #D4D499", "B c #D1D1AD", "V c #D3D3BC", "C c #BDBDC1", "Z c #BCBCCA", "A c #C5C5C5", "S c #C7C7CC", "D c #CCCCCC", "F c #D3D3C6", "G c #D4D4CE", "H c #D5D5D4", "J c #D9D9D7", "K c #D5D5DA", "L c #DBDBDB", "P c #E2E2DF", "I c #D7D7E5", "U c #DADAE1", "Y c #D7D7E9", "T c #DDDDED", "R c #D7D7F6", "E c #D8D8FA", "W c #E3E3E3", "Q c #E9E9E9", "! c gray95", "~ c #F8F8F8", /* pixels */ "HHHHHHHHJHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH", "HHHJHHHHDHHHHHHHHHDHHHHHHHHHHHHHHHHHDHHHHHDHHHHH", "HHJJUWUWWWWWUWWWWWWWWUWWWUWWWWLWWWWUWWUWWLWWHHHH", "HHJDkjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjljjjjkHJHH", "HHPk+>;;;;;;;;;-;;;;;;;;;;;-;>;;;;;;;;o-;;;,DHHH", "HHWj>~WQWWWWQWQHWWQWWQWWWWLLWWWWWWQQQQ=HQWQWJHHJ", "HHUj;WDHLWLHHDHADHDHHDHHHHDAHHHHHHDHHH&AHHDHHHHH", "HHWj;WGLh&1HJHJAHHJHHHJHHJDDHHHHHHHHHH=ALHHHHJHH", "HHLj;WHLgjXgWHHAHJHHHHHHHJDDJHHHHHHJHJ&AKHJHKHHH", "HHWj;QHD!z$CLHHADJHJHHHHHJDDJHHHHHHHHH=AKHHHHHHH", "HHWj;WGLg fDHHHAHJHHHJHHHJDSKHHHHHHHHH&ALHHHJHHH", "HHWj;QDL,%&jWHHAHHHHHHHHHJDDJJHHHHHHJH&AKHHHHHJH", "HHUj;QHHWULLHHHDDHHHHJHHHHDDJHHHHHHHHH&ALHHHHHHH", "HDWj;WHHHHHHHHHAHHHHHHHHHHDAHHHHHHHHHH=ALHHHHJHH", "HHWj;QHHHJHHHHHDLLLULULPLLJHULKULWLLLU=AIIJKHHHH", "HHWj-JAAAAADDAD>&=========**==========O7wwqyHKHH", "HHWj;WDHHHDHHHL=kcccxcccxZ09Zccccccccc5BVVVVHHJH", "HHWj;WHHJULHHHL=CWLLWWLLLTNpTLLLKLLLLUeGKKKKHHHH", "HHWj;QDHAkALHHL=xLHHllHHHIviIGHHHHHHHHwFJHHHHHHK", "HHWj;WHU,%olLGL=cLLc;$=WGImiIHHHHHHHHHwFHHHJHHJH", "HDWj;QHHJWohUHL=cLHKk@;UHInpYHHHHHHHHHqFKHHHHHHH", "HHWj;WDJH&1WHHL=xLHLA-%LGIbpIHHHJHHJHJqFKHJHKHHH", "HDWj;QDW- =kLHL=cLLk-%&LHIbiIHJHHHHHHHqFKHHHHHJH", "HHWj;WHJxljcJHP=cLHDkkJJGInpIHHHHJHJHHqFHHHHHHHH", "HHWj;WHHLWWLHHL=xJHHPLHHGIbiIHHHHHGHHHqFHHHHHHHH", "HHWj;QHHHHHHHHL=ZTIIIKIIKRNdRKIIIIUIIUeHIIIIHHJH", "HHWj;LDDDDDDDDH&0MmbbbmbbN96NbbbmbbbbM3vmbmmHHHH", "HHUj-LADADDDDAH&8aipiiiiid64diiipiiiii2upiisHHHH", "HHLj;QHHHHHHJHW=ZTIIIIIIURNdEIIIIIYIIYrHTIIIHHHH", "HHWj;WHHLWWLHHL=xJGJPPLGGIbiUGHHHHHHHHqFHHHHJHJH", "HHWj>WDLh=>AHHU=xLLA;=jLHIniIHHHHJJHHHqFJHHHHHHH", "HHWj;WHLlf.jLHL=cLHAj%%UGInpIHHHHHHHHHqFJHHHHJHH", "HHUj;QHJU>+zLHL=cLDQk+,UHIbiIHHHJHHHHJwFJHHHHHHJ", "HHWj;WDHjkXfWGL=xLLzj,oLHIbiIHHHHHHHHJqFHHHJHHHH", "HHPj;QDLf&,DHHL=cLLz--kLHIbiYHHJHHHHHHqFKHHHKHHH", "HHWj;WHHWWWLHHL=cLHKWWLHHImpIHHHHHHJHHqFKHHHHHHH", "HHWj;WHHHHHHHHL=cLJHDHHHGUbiYHHHJHHHHJqFHHHHJHHH", "HHWj>WHHHHHHJHU=cLHJJHJHHInpIHHHHHHHHHqFKHJHHHHH", "HHLko=&&&&&=&&=+%==&&&=&*=# c gray91", ", c #C8C8C8", "< c gray66", "1 c gray82", "2 c gray91", "3 c gray91", "4 c #CECECE", "5 c gray66", "6 c #CBCBCB", "7 c #E9E9E9", "8 c gray90", "9 c #E6E6E6", "0 c #E6E6E6", "q c gray90", "w c #E7E6E6", "e c #B0AFAF", "r c #A2A1A1", "t c #B9B8B8", "y c #E9E8E8", "u c #E8E7E7", "i c #B6B5B5", "p c #A2A1A1", "a c #B2B2B2", "s c #E8E7E7", "d c gray90", "f c #E6E5E5", "g c #E7E9E9", "h c #F1F6F6", "j c #DBDEDE", "k c #B3B7B7", "l c #E4E8E8", "z c #EFF3F3", "x c #EFF3F3", "c c #E1E5E5", "v c #B2B6B6", "b c #DEE2E2", "n c #F0F4F4", "m c #E6E6E6", "M c #E6E6E6", "N c gray90", "B c #E7E9E9", "V c #DAD3D3", "C c #BFA8A8", "Z c #C3AEAE", "A c #C1ABAB", "S c #C3ADAD", "D c #C1ACAC", "F c #C1ACAC", "G c #C3ADAD", "H c #C2ADAD", "J c #C2ACAC", "K c #C4B0B0", "L c #E2E0E0", "P c gray91", "I c #E7E6E6", "U c #F1F5F5", "Y c #C0AAAA", "T c #C3ADAD", "R c #D1C8C8", "E c #908888", "W c #D8CDCD", "Q c #CBC0C0", "! c #CCC1C1", "~ c #D5CACA", "^ c #8F8888", "/ c #CFC4C4", "( c #D4CACA", ") c #E4E3E3", "_ c #EAEAEA", "` c #C8C8C8", "' c #B0AFAF", "] c #DADEDE", "[ c #C3AEAE", "{ c #D8D0D0", "} c #E8EEEE", "| c #A0A3A3", " . c #F0F3F3", ".. c #E1E3E3", "X. c #D6D9D9", "o. c #DEE1E1", "O. c #BDC0C0", "+. c #DDE0E0", "@. c #DFE2E2", "#. c gray90", "$. c gray88", "%. c gray66", "&. c #A2A1A1", "*. c #B2B6B6", "=. c #C5AFAF", "-. c #D3C7C7", ";. c #E3E5E5", ":. c #9D9C9C", ">. c #EAEAEA", ",. c #DDDCDC", "<. c #E7E7E7", "1. c #F2F1F1", "2. c #F1F0F0", "3. c gray90", "4. c #E6E6E6", "5. c #E6E6E6", "6. c #EAEAEA", "7. c gray82", "8. c #B9B8B8", "9. c #E4E8E8", "0. c #C2ADAD", "q. c #D6CBCB", "w. c #E6E8E8", "e. c gray62", "r. c #EEEEEE", "t. c gainsboro", "y. c #B7B7B7", "u. c #B9B9B9", "i. c #CACACA", "p. c #E9E9E9", "a. c gray90", "s. c #E6E6E6", "d. c #E6E6E6", "f. c #E9E8E8", "g. c #EFF3F3", "h. c #C1ACAC", "j. c #CDC2C2", "k. c #DCDEE1", "l. c #9C9B9F", "z. c #E3E3E5", "x. c LightGray", "c. c gray71", "v. c #B7B7B7", "b. c #8D8D8D", "n. c #E6E6E6", "m. c #E6E6E6", "M. c #E6E6E6", "N. c gray91", "B. c #E8E7E7", "V. c #EFF3F3", "C. c #C1ACAC", "Z. c #CDC2C2", "A. c #E9EBE0", "S. c #E3E2D2", "D. c #E4E4DD", "F. c #D8D8D9", "G. c gray91", "H. c #F4F4F4", "J. c gray63", "K. c gray89", "L. c #E7E7E7", "P. c #CECECE", "I. c #B6B5B5", "U. c #E1E5E5", "Y. c #C4AEAF", "T. c #D0C5C1", "R. c #5255DC", "E. c #2424E4", "W. c #7A7AD4", "Q. c #EBEBDF", "!. c #CFCFD2", "~. c #DADADA", "^. c #979797", "/. c #D7D7D7", "(. c gray86", "). c gray90", "_. c gray66", "`. c #A2A1A1", "'. c #B1B5B6", "]. c #C7B1B2", "[. c #CDC2BC", "{. c #2325EC", "}. c blue", "|. c #3A3ABF", " X c #A8A895", ".X c #DADADE", "XX c #E9E9E9", "oX c #9D9D9D", "OX c #E2E2E2", "+X c #E6E6E6", "@X c #E6E6E6", "#X c #EAEAEA", "$X c #CBCBCB", "%X c #B2B2B2", "&X c #DDE1E1", "*X c #C4AEAF", "=X c #CFC4C0", "-X c #5759D9", ";X c #2A29E0", ":X c #7B7BD0", ">X c #E6E6DA", ",X c #DCDCDF", " , < 1 2 3 4 5 6 7 8 ", " 9 0 q w e r t y u i p a s d ", ". ; 0 f g h j k l z x c v b n m ", "X M N B V C Z A S D F G H J K L ", "o P I U Y T R E W Q ! ~ ^ / ( ) ", "_ ` ' ] [ { } | ...X.o.O.+.@.#.", "$.%.&.*.=.-.;.:.>.,.<.1.2.3.4.5.", "6.7.8.9.0.q.w.e.r.t.y.u.i.p.a.s.", "d.3 f.g.h.j.k.l.z.x.c.v.b.n.m.M.", "m.N.B.V.C.Z.A.S.D.F.G.H.J.K.L.- ", "% P.I.U.Y.T.R.E.W.Q.!.~.^./.(.).", "+ _.`.'.].[.{.}.|. X.XXXoXOX+X@X", "#X$X%X&X*X=X-X;X:X>X,X c #6C6CBE", ", c #7474B1", "< c #7070BF", "1 c #2828C6", "2 c #2A2AC8", "3 c #0000EA", "4 c #0000F1", "5 c #0303FE", "6 c #5D5DC0", "7 c #838383", "8 c #8A8282", "9 c #8A8A83", "0 c #8B8B8B", "q c #949494", "w c #9B9B9B", "e c #9C9393", "r c #B99B9B", "t c #A3A39D", "y c #8383B5", "u c #A4A5A5", "i c #ADADAD", "p c #BAA3A3", "a c #B4B4B4", "s c #B9B7B7", "d c #BBBBBB", "f c #C1B5B5", "g c #CBBFBF", "h c #AFAFCB", "j c #BCBCC7", "k c #B1B1CC", "l c #C3C3C3", "z c #CEC2C3", "x c #C1C1CA", "c c #CBCACA", "v c #D2C6C6", "b c #D4CBCB", "n c #DACECE", "m c #D3D3D3", "M c #DCD5D5", "N c #D5D5D9", "B c #DBDBDB", "V c #DFDFE0", "C c #DEE1E1", "Z c #E5E5E5", "A c #E8E7E7", "S c #E7EAEA", "D c #EBEBEB", "F c #EFF2E1", "G c #EDF0EA", "H c #F7F7E7", "J c #F9F9E7", "K c #F5F5E9", "L c #F9F9E9", "P c #EDF3F3", "I c #F4F5F5", "U c #F5FBFB", "Y c #FBFBFB", /* pixels */ "ZZZZZZZAZAAZAZAAZZZZAZZZAAZAZZZZ", "ZZAZAZZZAZZAZDBZAZZAZZZSZVSZZAZA", "AZAAZSZAZAAZDN0uSSZZZZSAwqVDZZZZ", "ZAAZZZZZZZZAmwsiuZZSZAZwiawBSZZA", "SZZZAAZZZZZSw0da7dDZZDa7sd0uDZZZ", "ZAZAZZSZZAAZDidilGZZZZGsisiPZAZA", "ZZZZAZZZZZZZDwuqdDZZZZDawtuGZZZA", "AZSZZZZAZZZZAcaaBZZZZZAmsacZZZAZ", "ZZZAZZAZZPPPPIUUIPPPPPPIUUIPPPAZ", "ZSZZZZZZGr$&%%$%%%&%%%%&$$%%%&BS", "AZZZZZZZP%pbzMXengvsfvgn8oMzzzZZ", "ZZASAZZZP&bIDY+aYSPVCIPYu0YDPPAZ", "ZZGNwDDSP%zDCIOiIBSmcmmBq7VmmmVA", "ZDNw0uwcU%zPZIOiIZSNmBBBBBBBBBZA", "SC0dddusU%zDVIOiIZDmBSAASAASASZA", "ZZuusuwsU%zSZIOiGZDmmZZZZZAAAZAZ", "ZSDu7dfmP%vDZYOiIVDMDYIIIDZZZZZZ", "AZSZdIPZP%zDBIOiIVAm0qqqqMAZZZZZ", "ZZZZDZZVP%vIZYOaIZDm700q 0IZZAAZ", "ZAZZZZZZP%sBmZOuVmBcSYIYu7YZAAZA", "ZZZZZAAZP%fCNNNNNBBcNZBKq7UZZAZZ", "ZAZSDZZZP%vPKKKHLDDNBDZYw7YAAAZA", "AZSZaDGZP%vD,6;>=jDmmVBDq7SNBVZZ", "ZAAw7aamP%zH15553hYZlmmVq@CmmmZA", "ZZwisiwsU%zF25553*tqBGZYw7YZADZZ", "AVqadsusU%zF25554.97BDVIw7YVZZAZ", "ZSVw0iucP%vF15553kYZBAZIw7YZAZAZ", "ZZDBtPGAP&zGy>>>:xGmBACYw7UVZAAZ", "ZZZADZZVP%zDKKKKLAANNSZIw7UCAZAZ", "ZAAZAAZZP%zPZZZZZZSNBSCIw7YZAZZZ", "AZZAZAZZABZZZZZAZSZZZZAABBSZZZAZ", "ZZAZAZAZAAZZZZZZAZZZAZAAAAZAZAZZ" }; /* XPM */ static const char *const xpm_icon_2[] = { /* columns rows colors chars-per-pixel */ "48 48 87 1 ", " c #3C1616", ". c #2D2D2D", "X c #333333", "o c #353B3B", "O c #4F2626", "+ c #752121", "@ c #633838", "# c #494949", "$ c #5B5B47", "% c #545454", "& c #5A5A5A", "* c #7F5050", "= c #5D6363", "- c #666666", "; c #6A6A6A", ": c #747474", "> c #7D7D7D", ", c #855252", "< c #976363", "1 c #996666", "2 c #9A6A6A", "3 c #817F7F", "4 c #9E7373", "5 c #A16D6D", "6 c #A07575", "7 c #A37A7A", "8 c #AA7E7E", "9 c #848470", "0 c #111195", "q c #19199D", "w c #1212A9", "e c #1818B8", "r c #2B2BA6", "t c #2121B5", "y c #2B2BB0", "u c #2424B8", "i c #3333B5", "p c #474795", "a c #7A7AA5", "s c #7B7BA9", "d c #0000DF", "f c #0202EC", "g c #0000F2", "h c #0202FE", "j c #0808FF", "k c #828283", "l c #868E8E", "z c #8B8B8B", "x c #949494", "c c #9C9C9C", "v c #AE8282", "b c #8282A5", "n c #8A8AA6", "m c #8585A9", "M c #8A8AAB", "N c #9C9CAE", "B c #A3A3A3", "V c #ABABAB", "C c #B4B4B4", "Z c #BBBBBB", "A c #BBBBC2", "S c #C3C3C3", "D c #C0CACA", "F c #CBCBCB", "G c #CCD7D7", "H c #D6D5D5", "J c #DCDBDB", "K c #E1DEDE", "L c #E5E5D3", "P c #E8E8D6", "I c #E6E6DC", "U c #E6E5E5", "Y c #E9E7E7", "T c #EAE9E4", "R c #E7E7EA", "E c #E7E8E8", "W c #EAEAEA", "Q c #F5F4EC", "! c #FFFFED", "~ c #EDF7F7", "^ c #ECF7FA", "/ c #EFF9F9", "( c #F2F1F1", ") c #F8F6F6", "_ c #F8F8F0", "` c #F1FBFB", "' c #FBFBFB", /* pixels */ "UUUUUUUUUUUUUEUUUUUUUUEUUUUYUUUUURUUUYUUUUUUEUUU", "UUYUUEUEUEEUUUEUUEUEUUUUEUUUUEEUUUUEUUUUEUUEUUYU", "UUUUYUUUUUUEUUUUEUUURUERUUUEUUUUUUYUEUUUYUUUEUUE", "UEUEUUEUUYUUUEYUUUUYEEJWUUUUUEUUUUUEUUUUUUEUUUUU", "UUUUUUUUUUEUUUUUUUEUQB:FWUUEEYUUUUEUkzEYUUUUURUU", "UUEUUEEUUUUUEUEUUEUWBzZ3SQUUUUUUUEJkVBzYEUUUUUUE", "EUUYUUUUUEUUUUYUUEWVxSZZzFWEUUEUEUzVZSBxERUUUUEU", "UUUEUUEUUUYEUUUUUWC-cZCCk;JEUUUUW>:VZZV-xQUUUUUU", "UUYUUEUUUEUUUUUEUYKKzCZBBRKRUUUEUUZzSZzFUUUUYUUU", "EUUUUUUYUUEUUUUURURWxCSBC(UUUUUUU(FxSZxJEUEUUUEU", "UUEUUEEUUUUUUYUUUUUYzVCxV(UUEUUEUWFzCCkHEYUEUUUU", "UEUUUUUUYEUUUUUUUUYWBxczSWUUUUUUUWHzxxcUEUUUUEUU", "UEUUUUEUUUUUYUUUUUIKWWWWYKIUUUUKUUUWWWWUUIKUUUUY", "UUEUUEUUEUUEUUE`````/^~/``/``/````~^(^/````/UUUU", "UUEUUUUUUUEUUEH7466647v6666666664644v8466666KYUE", "YUUUUEUYUUUUU~8+4<<<1, 1<<<<<,<<<<<5O@5<<<<1KEUU", "UUUUUEUUUUUYU`45'^`/'Do'`````G~`/`~'-l'/`^``EUUU", "UUEUUUU(YUUUU`4<^KUK(CXWKUKUYSJUUUJ)&>)KUIKUUUUU", "EUUUUUWCJEUUU^6xFSSSSSUEUU", "EYUU(BxckxzBW)6<`KUUWZX(UUUUWSUUUUUJWEIUUUUUUUEU", "UUUEVzSZCCVxW/6<`UUU(CXWUUUUESUUYEUURUUUUREEUUUU", "UYEJ:ZZCZSZcW/6<`KYU(CX(UUUUESUUEUUUUUUUUURUUUUU", "UEEWF>ZCBBxzW/6<`UUU(ZXWUUYUESKUUUUUURUUUUUUUUUU", "UEUUQSzkcCBSY`6<^UUU(ZX(UUUUUSJUUUKUUUUUUUUUUUUU", "UUEUUWF;U((WU`6<`KUUWCX~UUUUEF)'''`''EUUUEUUUUEU", "UUUUUUWJUUUUK`6<`URU(ZXWUUUUWc#%%%%%&FWUEUUEEUUE", "UEYUURUWUUUUU`6<`KUUWZXWUUUUWV>zkzkx.k'UUUUYUUUU", "EUUEUURUUUUUU`41`YYY(ZX(EEEEWF)'))('-3)UUUUYUEUY", "UUUUUUUUUUUYK`6,GSSSFV-FSSSSSCKUUUK)%3'KEUUUUUUU", "UUUUUUUUYUUUU`6<~KUKUUWKUUUKUSUUUUU'&3'UUEEUUEEU", "UEEUUUUUUUUUU`6<`URRWRRWRREUEDKUUUU`&3)UUUUUUUUU", "UEUUYUEWUUUUU/4WHHJJHUUUU", "UEUUEJz:ZFSJU`6<^QsghhhhhyLKUZSFFFFJ&>JSFFFFUEEU", "UUUEUkVVzxkzW`6<^Qsfjhhhhi_''HUWEWE'&k'UWWWWUEUU", "UYEU3VZZZSZxW/6<^Qaghhhhh0$&%3WUUUU)&3'UUUUUUUUU", "UUEUzBSCZZCcW/6<~Qsghhhhhq3k>xEUUYJ'&3`KUUUUUUUU", "EUUEWzBVkx3xW/6<^Qsgjjhjhi!`'FKYUUU'&3'UUUEUEUUE", "UUUUEEx:FJHUY`6<^QadffffgrPUUSUUUUU'&3'KUEUUUUUU", "UUUEUEUxUWEYU`4 c #D7CBCB", ", c #967A7A", "< c #ADB2B2", "1 c #ABAAAA", "2 c #ADACAC", "3 c #B0AFAF", "4 c #DDDCDC", "5 c #DDDCDC", "6 c #DCDBDB", "7 c #E0DFDF", "8 c #B5B4B4", "9 c #ABAAAA", "0 c gray68", "q c #ADACAC", "w c #AEADAD", "e c gray87", "r c #D5C8C8", "t c #927474", "y c #B0B4B4", "u c #AAA9A9", "i c #9FA4A4", "p c #A4A9A9", "a c #D6DCDC", "s c #DEE1E1", "d c #DEE1E1", "f c #D8DDDD", "g c #B3B8B8", "h c #565858", "j c #0F0E0E", "k c #464848", "l c #A7ACAC", "z c gray86", "x c #D5C8C8", "c c #927474", "v c #B2B5B5", "b c #5E8686", "n c #618787", "m c #688B8B", "M c #8CACAC", "N c #73A1A1", "B c #6B9D9D", "V c #8DADAD", "C c #729999", "Z c #2C3C3C", "A c black", "S c #1D2929", "D c #739696", "F c #D9DBDB", "G c #D5C8C8", "H c #937575", "J c #AEB4B4", "K c #668888", "L c #B1ADAD", "P c #B4B1B1", "I c #F8F0F0", "U c #B9CBCB", "Y c #A6BEBE", "T c #FDF5F5", "R c #BDBABA", "E c #807F7F", "W c #5D5E5E", "Q c #7A7979", "! c #B2AFAF", "~ c #DDDDDD", "^ c #D5C9C9", "/ c #8E7070", "( c #A6ABAB", ") c #5F8383", "_ c #A1A2A2", "` c #A3A5A5", "' c #E0DBDB", "] c #B1BDBD", "[ c #9FB3B3", "{ c #E4DFDF", "} c #B0B2B2", "| c gray74", " . c gray65", ".. c #B9B9B9", "X. c #B2B3B3", "o. c #DDDDDD", "O. c #D5C8C8", "+. c #927373", "@. c #ADB2B2", "#. c #638686", "$. c gray66", "%. c #AFAFAF", "&. c #DFDEDE", "*. c #7FB3B3", "=. c #72ABAB", "-. c #E0DEDE", ";. c gray84", ":. c #EFEFEF", ">. c gray53", ",. c gray85", "<. c gray88", "1. c #DDDDDD", "2. c #D5C8C8", "3. c #937474", "4. c #AEB3B3", "5. c #648787", "6. c #A8A9A9", "7. c #B8B4B4", "8. c #BECECE", "9. c #00EEEE", "0. c #00EEEE", "q. c #BECECE", "w. c #DDD9D9", "e. c #EDEEEE", "r. c #898989", "t. c gray85", "y. c #DDDDDD", "u. c gainsboro", "i. c #D5C8C8", "p. c #937474", "a. c #AEB4B4", "s. c #648787", "d. c #A9AAAA", "f. c #B8B4B4", "g. c #C1CFCF", "h. c #11DBDB", "j. c #11DBDB", "k. c #C1CFCF", "l. c #DDD9D9", "z. c #EEEFEF", "x. c #898989", "c. c #DADADA", "v. c gray87", "b. c gainsboro", "n. c #D5C8C8", "m. c #917373", "M. c #ABB0B0", "N. c #628585", "B. c #A7A7A7", "V. c gray68", "C. c #DFDFDF", "Z. c #D5D3D3", "A. c #D5D3D3", "S. c #DFDFDF", "D. c LightGray", "F. c #ECEDED", "G. c #868989", "H. c #D6D8D8", "J. c #DDDDDD", "K. c #DDDDDD", "L. c #D5C9C9", "P. c #8F7070", "I. c #A6ABAB", "U. c #608383", "Y. c #A5A5A5", "T. c gray63", "R. c gray68", "E. c #B4B4B4", "W. c gray70", "Q. c #AFAEAE", "!. c #A6A7A7", "~. c #B6AFAF", "^. c #A79292", "/. c #B2A8A8", "(. c #AEAFAF", "). c #DDDDDD", "_. c #D5C8C8", "`. c #947575", "'. c #AFB4B4", "]. c #638787", "[. c #ACACAC", "{. c #A5A5A5", "}. c #A7A7A7", "|. c #A9AAAA", " X c #A9A9A9", ".X c #A7A9A9", "XX c #ABA1A1", "oX c #68A3A3", "OX c #28CACA", "+X c #58A8A8", "@X c #B0A6A6", "#X c #DCDEDE", "$X c #D5C9C9", "%X c #927373", "&X c #B2B3B3", "*X c #668888", "=X c #5F8585", "-X c #648787", ";X c #618888", ":X c #667A7A", ">X c #2DA6A6", ",X c cyan", " , < 1 2 3 4 5 6 7 8 9 0 q w e ", "r t y u i p a s d f g h j k l z ", "x c v b n m M N B V C Z A S D F ", "G H J K L P I U Y T R E W Q ! ~ ", "^ / ( ) _ ` ' ] [ { } | ...X.o.", "O.+.@.#.$.%.&.*.=.-.;.:.>.,.<.1.", "2.3.4.5.6.7.8.9.0.q.w.e.r.t.y.u.", "i.p.a.s.d.f.g.h.j.k.l.z.x.c.v.b.", "n.m.M.N.B.V.C.Z.A.S.D.F.G.H.J.K.", "L.P.I.U.Y.T.R.E.W.Q.!.~.^./.(.).", "_.`.'.].[.{.}.|. X.XXXoXOX+X@X#X", "$X%X&X*X=XU.N.-X5.;X:X>X,X c #4C5656", ", c gray34", "< c #496B6B", "1 c #407777", "2 c #4E7A7A", "3 c #686262", "4 c #737272", "5 c #747C7C", "6 c #268989", "7 c #02AEAE", "8 c #418383", "9 c #498585", "0 c #418C8C", "q c #568282", "w c #5B8585", "e c #558E8E", "r c #5E8888", "t c #409797", "y c #5D9292", "u c #628585", "i c #628C8C", "p c #7F8E8E", "a c #729B9B", "s c #7D9E9E", "d c #63A4A4", "f c #00CACA", "g c #11C9C9", "h c #02D4D4", "j c #00DEDE", "k c #00E2E2", "l c #00EAEA", "z c #01F5F5", "x c #03FFFF", "c c #918E8E", "v c #859696", "b c #8D9595", "n c #959595", "m c #9C9393", "M c #969A9A", "N c #9C9C9C", "B c #8EACAC", "V c #92A3A3", "C c #9DA1A1", "Z c #93B1B1", "A c #9BB6B6", "S c #A3A3A3", "D c #AAA1A1", "F c #A6AAAA", "G c #ABACAC", "H c #B4ADAD", "J c #B9AFAF", "K c #A4B3B3", "L c #ACB1B1", "P c #B3B3B3", "I c #BBB2B2", "U c #BBBBBB", "Y c #C3B7B7", "T c #C5BDBD", "R c #CCB8B8", "E c #AFC1C1", "W c #B2C3C3", "Q c #BEC3C3", "! c #B7C8C8", "~ c #C5C5C5", "^ c #C1CACA", "/ c #CCCCCC", "( c #D6CACA", ") c #D6D1D1", "_ c #DBDBDB", "` c #E4E4E4", "' c #EAEBEB", "] c #F3E7E7", "[ c #F3EAEA", "{ c #FAEFEF", "} c #F3F2F2", "| c #FAF3F3", " . c #FCF8F8", /* pixels */ "` ` ' ' ` ' ' ' ' ' ' ' ' ' ' ' ' ` ' ' ' ' ' ' ` ' ' ' ' ` ` ' ", "' ` _ _ _ _ _ _ _ _ _ _ ) _ _ _ ) _ ) _ _ _ _ _ _ _ _ _ _ _ ` ` ", "' ) $ C S S S S S S S S ( / / / / / / / G N S S S C C C S N _ ' ", "' ) @ G G H G G G G F H ' ' ' ' ' ' ' } ~ S P P I U U H H S _ ' ", "' ) @ F H G G G F G F G ` ` ` ` ` ` ` ' U F M O O O o 4 P C _ ' ", "' ) @ F G G H H H H H H } ] ] ] ] [ ] | T H m 3 T D _ ' ", "' ) @ F G H v = = - = - 6 9 8 0 6 8 8 8 - ; & % ; - _ ' ", "' ) @ F G Y w ; n v v v ! U ^ a 9 / W ! V v 5 > V p _ ' ", "' ) @ G G I q w R P H P [ ' .A y .' | ~ H N X o X . 4 T F _ ' ", "' ) @ F G I q q I F F G ` ` | Z e { ` ' T S G P L G L H G S _ ' ", "' ) @ F F J q q J F F F ` _ ] B e ] _ ` U N F S F H S S S N _ ' ", "' ) @ M N D 2 2 D N m N / ^ ( s 9 ( ^ / L I U ~ N , ~ U ~ H _ ' ", "' ) @ K G I q q Y G G H ' ' .K y .' ' / ` ' .P : .` [ / _ ' ", "' ) @ F G I q q I F F G [ Q d t 6 d Q } ~ _ ` } P : } ` ' / _ ' ", "' ) @ F G I q q I G F G } K k x x j K | ^ _ ` } P : } ` ' / _ ` ", "' ) @ F G I q q Y F D G } K k x x k K | ^ ` ` } P : } ` ' / ) ' ", "' ) @ F G I q q I G F G } K k x x k K | ^ _ ` } P : } ` ' / ) ' ", "' ) @ F G I q q I G D G } L 7 g g 7 L } / _ ` } P : } ` ' / _ ' ", "' ) @ F G I q q I G F G ' ` ( ( ( ( ` ' ~ _ ` } P : } ` ' / ) ' ", "' ) @ F F I q q I G F G ' ' ' } ' ' ' ' / ` ' } P : | ' ' / _ ' ", "' ) + N N D 2 2 D N N n H G G G G G G H N F H G N 4 L F L S _ ' ", "' ) @ F G I q q I G G N F F F D G F F G N F G J H Y J H F S _ ' ", "' ) @ F G I q q J F F N G G F G G G F G N F N u i i w b P S _ ` ", "' ) @ F F I q u R I I D I I I I I I I Y D Y m f x z l i J S _ ' ", "' ) @ F L I q * w q q 2 q q q q q q q q 2 q < h x x z i I S _ ' ", "' ) @ F G P C q q q q 2 q q q q q q q q 2 q < h x x z i J S _ ` ", "} ) + F H F P I I I I D I I I I I I I I D I m 7 j h f u I S _ ' ", "' ) @ F G H G F G G G M F G G G G G G G C G F b c c c N H S _ ' ", "' ) @ C G F F F F F F M F F F F G F F G M C F L L L P G F C _ ' ", "' _ # + @ @ @ @ @ @ @ @ @ @ + $ + @ @ @ @ @ @ @ @ + @ @ + $ _ ' ", "' ` _ ) ) ) ) ) _ ) ) ) ) ) ) ) ) ) ) ) _ ) ) ) ) ) ) ) ) ) ` ` ", "` ' ' ' ' } ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ' ` ` " }; /* XPM */ static const char *const xpm_icon_2[] = { /* columns rows colors chars-per-pixel */ "48 48 132 2 ", " c #010101", ". c #090909", "X c #2A2A2A", "o c #313131", "O c #660404", "+ c #680000", "@ c #670808", "# c #6B0A0A", "$ c #721212", "% c #7F2121", "& c #004343", "* c #074C4C", "= c #005252", "- c #006464", "; c #006969", ": c #0A6B6B", "> c #1E6F6F", ", c #007373", "< c #0B7070", "1 c #007A7A", "2 c #1E7171", "3 c #1E7878", "4 c #226D6D", "5 c #217272", "6 c #337878", "7 c #3F7D7D", "8 c gray30", "9 c #475E5E", "0 c #515151", "q c #5C5E5E", "w c #745C5C", "e c #467373", "r c #497676", "t c #447D7D", "y c #4E7C7C", "u c #517777", "i c #5F7777", "p c #507E7E", "a c #656464", "s c #696969", "d c #7B6D6D", "f c #6F7878", "g c #717272", "h c #7A7777", "j c #777A7A", "k c #7B7F7F", "l c #822F2F", "z c #846C6C", "x c #877E7E", "c c #887E7E", "v c #0B8B8B", "b c #258585", "n c #298484", "m c #268B8B", "M c #298888", "N c #249F9F", "B c #05AEAE", "V c #1FA1A1", "C c #468686", "Z c #4A8B8B", "A c #4D9191", "S c #6E8686", "D c #7E8181", "F c #758D8D", "G c #769292", "H c #789393", "J c #00C2C2", "K c #00DBDB", "L c #00E4E4", "P c #00E9E9", "I c #02FDFD", "U c #08FFFF", "Y c #878B8B", "T c #8B8C8C", "R c #938D8D", "E c #869494", "W c #8E9292", "Q c #8E9A9A", "! c #959494", "~ c #999696", "^ c #949B9B", "/ c #9C9C9C", "( c #A49595", ") c #A29D9D", "_ c #AC9B9B", "` c #B09B9B", "' c #BD9F9F", "] c #97A3A3", "[ c #9CA1A1", "{ c #9FAAAA", "} c #A5A5A5", "| c #AEA1A1", " . c #A1ADAD", ".. c #ABACAC", "X. c #B2A2A2", "o. c #BEA5A5", "O. c #B1ADAD", "+. c #B9A9A9", "@. c #A4B0B0", "#. c #ADB1B1", "$. c #A7B9B9", "%. c #B3B3B3", "&. c #BBB2B2", "*. c #B3BABA", "=. c #BABABA", "-. c #C1B7B7", ";. c #C6BDBD", ":. c #CDBBBB", ">. c #BEC1C1", ",. c #C4C4C4", "<. c #C7CACA", "1. c #CBCBCB", "2. c #D3CECE", "3. c #DBCDCD", "4. c #D5D5D5", "5. c gainsboro", "6. c #E0CECE", "7. c #E1D6D6", "8. c #F9D6D6", "9. c #DBE7E7", "0. c #DBE8E8", "q. c #E5E5E5", "w. c #EAE7E7", "e. c #E6E9E9", "r. c #EBEBEB", "t. c #F5E7E7", "y. c #F1EEEE", "u. c #FAECEC", "i. c #ECF1F1", "p. c #F2F5F5", "a. c #FFF4F4", "s. c #FCFBFB", /* pixels */ "q.q.q.q.q.q.q.q.q.e.q.q.q.w.e.q.w.q.q.q.q.w.q.q.q.q.q.q.w.q.q.q.q.w.q.q.q.e.w.q.q.q.e.q.e.w.q.q.", "q.q.q.w.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.q.e.q.q.q.q.q.q.q.q.q.q.q.q.q.q.", "e.w.q.e.p.r.r.r.r.y.r.r.r.r.r.r.r.r.r.r.y.r.r.r.r.r.p.r.r.r.r.r.r.r.r.y.r.r.r.r.r.r.r.r.e.q.w.q.", "q.q.e.4.o.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.=.=.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.<.q.q.q.q.", "q.q.p.` + ^ } / / ) [ / / / / / / / 4.1.4.2.4.<.,.4.4.2.4.4.~ ~ / / ~ / / / / ~ / ) / ~ 9.w.q.e.", "e.q.p.` @ .%.....O.O.#.%...%.%.....i.w.r.e.r.e.y.e.e.e.e.p.....%.%.%.%.%.%.%.%.%...O.} 7.q.q.q.", "q.q.i.` @ .....................} ..w.q.q.q.q.q.q.q.q.q.q.r...} ..} [ / [ ) / } ....../ q.q.q.w.", "q.9.p.` + .O...................} ..e.q.q.q.q.q.q.q.q.q.q.e.} } =.g . . . . Y %...~ 9.w.q.q.", "q.q.i.` @ { ..........%.%.%.%.%...%.p.r.y.y.y.p.r.p.p.y.r.p.%...>.g T =.O.} q.w.q.q.", "q.q.p.` + .O.....%.} T W W W W Y ! ,.>.>.>.>.=.;.>.=.,.>.,.T Y / q g ^ T Y 9.e.q.w.", "q.q.p._ @ { O.....+.t , - - ; ; ; ; - ; ; ; - 1 1 - - ; ; - ; - ; & = : - 3 q.q.q.e.", "q.q.p.` @ .O.....+.4 e _ ~ ~ ~ ! ! 2.1.1.<.6.7 7 6.<.1.<.4.~ R } a . . h [ ~ ! 7.q.q.q.", "q.q.p.` @ .O.....O.2 p -.#.%.%...%.p.r.e.r.a.Z Z a.e.r.r.p.O...;.g T =.%.} q.e.q.q.", "q.q.p.` @ .O.....+.2 y +.......} } w.q.q.q.u.C C u.q.q.q.e.} } %.Y 8 8 8 8 8 8 ~ #.../ 7.q.w.q.", "q.q.i.` + { ......+.2 y &.......} } e.q.q.q.u.C C u.q.q.q.w...} ..%.=.=.=.=.=.=......./ 9.q.e.q.", "q.q.i._ @ .%.O...+.2 y &.#...%.....p.r.r.e.a.Z Z a.e.r.e.p.....%...............%...%./ q.q.w.q.", "q.q.p.` O ^ ) [ ^ _ > r | / ) [ ~ ) 4.<.1.1.3.n y 6.<.1.1.2./ ~ ~ / / ~ ) / } ~ / / / ~ q.e.q.q.", "q.q.p.` O ] ) / / _ > r | / / / ~ / 1.,.,.,.3.7 7 3.,.<.<.<.} <.1.<.<.5.a o 4.,.<.<.1...7.e.e.q.", "q.q.p._ @ .%.O.#.+.2 y &.#.O.%.....p.r.r.i.s.Z Z s.r.r.r.y.=.e.r.r.e.s.s X s.e.r.e.p.=.5.e.q.e.", "q.9.p._ @ { ......+.> y &.....O.} ..e.q.q.6.8.t t 8.7.q.q.w.%.q.q.q.q.p.s X s.q.w.q.r.=.5.e.w.q.", "q.q.p._ O { #.....+.2 y &.......} ..e.p.E v N v v V 5 2.r.q.=.q.e.q.q.s.s X p.7.q.q.r.=.5.e.q.q.", "q.q.p.` O @.O...@.+.> y &.......} ..e.u.H P I I I I B :.i.e.%.q.e.q.q.s.s X p.q.q.q.e.=.5.r.e.q.", "q.q.p._ + { ......+.> y &.......} ..w.p.H L U I I I B :.i.w.%.q.q.q.q.s.s X p.q.q.q.r.=.7.e.q.q.", "q.q.p.` @ { %.....+.4 y &.......} ..e.u.H L U I I I B :.r.e.%.q.q.q.q.s.s X a.q.q.q.r...5.e.q.w.", "q.q.p._ @ .......+.> y &.........} e.y.H P U I I I B :.r.e.=.q.e.q.q.s.a X p.q.q.q.r.=.5.e.q.e.", "e.7.p.` @ .O.....O.> y +.......} ..e.a.G P I I I I B :.i.q.%.q.q.q.q.s.s X p.q.q.q.r.=.7.e.q.q.", "q.q.i.` @ .O.....+.4 p &.......} ..e.y.[ C A Z Z A y 4.e.w.%.q.q.q.q.s.s X p.q.q.q.r.=.9.w.q.q.", "q.q.p._ + .O.....o.> p &.......} ..e.q.r.t.t.t.t.t.u.e.q.e.%.q.q.q.q.s.a X p.q.q.q.e.=.5.w.w.q.", "e.q.p._ @ .O.....+.2 p &.....#.} ..r.e.q.e.e.e.e.e.q.e.e.r.=.w.r.r.q.s.s X s.e.e.r.y.=.5.e.w.q.", "q.q.p.` O ] } } } | 2 t X.} } } ) } 5.4.5.4.4.5.4.4.5.5.4.5...4.4.4.4.r.s X e.4.4.4.5.%.5.q.q.q.", "q.q.p.` + Q ~ ~ ^ ( > r ) ~ ~ / ~ Y / / / / / ~ / ~ ~ / / / T ~ / / ~ / ! Y [ ~ / ~ / ~ q.q.q.e.", "q.q.i._ @ @.%.%.#.+.> p -.#...%...~ %.%.O.#.#.%.#.#.%...#.%.~ ..#.#.#.#.%.%.#.#...%.O.[ q.e.q.q.", "q.9.p._ @ { ......+.4 y &.........! ........................~ ......+.` ` X.X.+......./ q.q.q.q.", "q.q.p.` @ .O.....+.2 y &.........! ........................! ..#.D 2 M n b n 4 R %.../ q.q.q.q.", "q.q.p._ + { O.....+.> y %.........^ #.#.......#.#.#.......#.! ..=.f K I I I I J x %...) q.w.e.q.", "q.q.p.` @ .O.....O.> u o.| | | | R | | | | X.| | | | | | | R _ +.g K U I I I J c %...[ 5.e.q.q.", "q.q.p._ @ .O.....+.6 , : : : : ; : : : : : : : : : : : : : : : : * L I I I I J Y %.../ q.q.q.q.", "e.7.p.` @ .%.....%.^ f F S S S S f S S S S S S S S S S S S i S F 9 K I I I I B c %...} q.q.q.q.", "e.q.i.` @ .O.........=.+.%.&.%.&.~ &.%.=.&.%.&.=.&.&.%.%.&.) O.;.j K I I I I J x %.../ q.e.q.q.", "q.q.i.` + { ....................} ! ......} ....} ..........! } %.D 3 m b b b > R %...[ 7.e.q.q.", "q.q.p.` O [ ......} ..} ..} ....| ! ..........} ............! ......X._ X.X._ X...} ../ q.w.q.q.", "q.q.p.` # $.=.*.*.*.*.*.*.*.*.%.*.[ *.*.*.%.*.*.%.*.#.*.%.*./ *.*.*.*.*.*.*.*.*.*.*.*.} 9.q.q.w.", "q.q.p.` + d z z z z z z z z z z z w z z z z z z z z z z z z w z z z z z z z z z z z z z q.q.q.q.", "q.q.e.;.l $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ # l q.w.q.q.", "q.q.q.e.9.9.9.0.0.0.0.0.0.9.9.0.0.0.0.0.0.0.0.0.0.0.0.0.9.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.q.q.q.w.", "q.q.q.q.w.r.w.w.w.w.w.e.r.w.w.w.w.e.w.w.w.w.w.e.e.e.w.w.w.r.w.w.q.e.w.w.w.w.w.w.w.w.w.e.q.q.q.q.", "q.q.q.w.q.q.q.q.w.q.q.q.q.q.q.w.q.q.q.w.w.q.w.q.q.q.q.q.q.q.w.e.w.q.w.q.q.e.q.q.w.w.q.q.q.q.q.e.", "q.e.q.q.e.q.q.w.q.q.w.q.e.q.q.q.e.q.q.q.q.q.q.q.e.q.q.w.q.q.q.q.q.q.q.q.q.q.w.q.q.q.q.e.q.w.q.q." }; const char *const *const xpm_icons[] = { xpm_icon_0, xpm_icon_1, xpm_icon_2, }; const int n_xpm_icons = 3; puzzles-20170606.272beef/icons/mines-icon.c0000644000175000017500000004254613115373753017227 0ustar simonsimon/* XPM */ static const char *const xpm_icon_0[] = { /* columns rows colors chars-per-pixel */ "16 16 256 2 ", " c #E7E6E6", ". c #EBEFEF", "X c #E8FCFC", "o c #EBEEEE", "O c #DFDEDE", "+ c #DFDDDF", "@ c #E6E0E6", "# c #DADBDA", "$ c #DDDCDD", "% c #E5E0E5", "& c #DFDDDF", "* c #DADADA", "= c #E4E4DB", "- c #DDDDDA", "; c gray89", ": c #E8E8E7", "> c #EBEEEE", ", c #EFE2E2", "< c #F79E9E", "1 c #E3D3D3", "2 c #C3C5C7", "3 c #93BA92", "4 c #8CB78C", "5 c #D7D0D7", "6 c #B2C5B2", "7 c #76AE76", "8 c #C4CBC3", "9 c #D1CFD0", "0 c #7D7DE5", "q c #BCBCD5", "w c #EEEEE8", "e c #EAEAEB", "r c #E9EFEF", "t c #F4DADA", "y c #E65656", "u c #CFBAB9", "i c #CBCCD1", "p c #8EBC8D", "a c #73B072", "s c #E1D8E1", "d c #BECEBE", "f c #56A557", "g c #C4CEC7", "h c #E3E1D5", "j c #7474EE", "k c #A7A7E1", "l c #F6F6EA", "z c #E8E8EB", "x c #EDECEC", "c c #D9E0E0", "v c #648282", "b c #868A8A", "n c #CBC7C9", "m c #79B57A", "M c #9BC39E", "N c #E1D8E1", "B c #9EBE9F", "V c #7AB776", "C c #D0D2CF", "Z c #D4D3D1", "A c #7E81ED", "S c #9FA1E3", "D c #F5F5EB", "F c #E8E9EB", "G c #DFE2E2", "H c #C0B3B3", "J c #C88D8D", "K c #BEB5B6", "L c #DFE2E2", "P c #F8ECF3", "I c #F3E6E9", "U c #CACDCC", "Y c #D6D2D3", "T c #B9B2CD", "R c #CDCDCE", "E c #E9EAEB", "W c #F6EEE3", "Q c #EDE6DF", "! c #E7E8E9", "~ c #EBEAEA", "^ c #DBDCDC", "/ c #D8D5D5", "( c #F85151", ") c #E8A7A7", "_ c #EAFEFE", "` c #F76866", "' c #F58585", "] c #C5D7D2", "[ c #A8A5C0", "{ c #373894", "} c #D0D2DA", "| c #F2EBE9", " . c #FC5255", ".. c #EBA2A4", "X. c #D8E6E6", "o. c #EDEAEA", "O. c #DBDFDF", "+. c #D8C7C7", "@. c #F25D5E", "#. c #E1A8A7", "$. c #F0FDFD", "%. c #B7A8A9", "&. c #827273", "*. c #C6C8C4", "=. c #9D9BBB", "-. c #444097", ";. c #BEBECF", ":. c #F7F8F4", ">. c #9D8A8A", ",. c #897F7F", "<. c #E1E3E3", "1. c gray92", "2. c #DBDDDD", "3. c #CAC3C1", "4. c #CFBEBC", "5. c #D6D5D8", "6. c #CDCDCD", "7. c #9FA29F", "8. c #8E9291", "9. c #B8B6B6", "0. c #EEF6F2", "q. c #E0F3F3", "w. c #E6E5E6", "e. c #DDDEDE", "r. c #A4BCBC", "t. c #A4ADAD", "y. c #DEDDDD", "u. c #ECEDED", "i. c #DEDCDE", "p. c #C6CFC8", "a. c #6BB070", "s. c #AAC2AB", "d. c #DFDAD9", "f. c #999AC1", "g. c #8684B8", "h. c #F2F9F1", "j. c #EDBFC1", "k. c #FC7F7F", "l. c #DBDADA", "z. c #E4E0E0", "x. c #FF8A8A", "c. c #F0C0C0", "v. c #DCE6E6", "b. c #ECEAEA", "n. c #DFDDDF", "m. c #C9CFC8", "M. c #55A354", "N. c #B5CAB4", "B. c #D6D1D7", "V. c #4C4D9E", "C. c #55549C", "Z. c #EDF2ED", "A. c #EFCBCC", "S. c #C06161", "D. c #C8C8C8", "F. c #EAE7E7", "G. c #D67979", "H. c #BA9696", "J. c #DEE5E5", "K. c #EBEAEA", "L. c #E2DEE2", "P. c #BFCDBF", "I. c #89BB89", "U. c #CDD5CD", "Y. c #D7D6D6", "T. c #C5C5D3", "R. c #ADADC8", "E. c #EEECEA", "W. c #C2CACA", "Q. c #647676", "!. c #A6A5A5", "~. c #E0E1E1", "^. c #819393", "/. c #787F7F", "(. c #DEDDDD", "). c #ECECEC", "_. c #E8E9E8", "`. c #F2F0F2", "'. c #FCF3FC", "]. c #E6E5E6", "[. c gray89", "{. c #F4F4F1", "}. c #F4F4EF", "|. c gray87", " X c #E4E3E3", ".X c #EEEBEB", "XX c gainsboro", "oX c #E0DFDF", "OX c #EBE8E8", "+X c #E6E4E4", "@X c #DFE0E0", "#X c #ECECEC", "$X c gray92", "%X c gray92", "&X c #E6E8E6", "*X c #D9DAD9", "=X c gray86", "-X c #EAEAEA", ";X c #E3E3E4", ":X c #D2D2D2", ">X c gray92", ",X c #EAEAEA", " , < 1 2 3 4 5 6 7 8 9 0 q w e ", "r t y u i p a s d f g h j k l z ", "x c v b n m M N B V C Z A S D F ", "G H J K L P I U Y T R E W Q ! ~ ", "^ / ( ) _ ` ' ] [ { } | ...X.o.", "O.+.@.#.$.%.&.*.=.-.;.:.>.,.<.1.", "2.3.4.5.6.7.8.9.0.q.w.e.r.t.y.u.", "i.p.a.s.d.f.g.h.j.k.l.z.x.c.v.b.", "n.m.M.N.B.V.C.Z.A.S.D.F.G.H.J.K.", "L.P.I.U.Y.T.R.E.W.Q.!.~.^./.(.).", "_.`.'.].[.{.}.|. X.XXXoXOX+X@X#X", "$X%X&X*X=X-X;X:X>X,X c #FA1D1D", ", c #F62222", "< c #EC3F3F", "1 c #F53333", "2 c #F63B3B", "3 c #A75C5C", "4 c #8D6D6D", "5 c #F44B4B", "6 c #F25757", "7 c #EA6666", "8 c #ED6D6D", "9 c #F26464", "0 c #E97A7A", "q c #F07575", "w c #128512", "e c #1C8B1C", "r c #168A16", "t c #2C8F2C", "y c #2C922C", "u c #349334", "i c #3E9A3E", "p c #489D47", "a c #469E46", "s c #4EA14E", "d c #57A357", "f c #68AB68", "g c #63AA63", "h c #7AB37A", "j c #151586", "k c #24248D", "l c #2E2E93", "z c #343495", "x c #383897", "c c #46469D", "v c #4A4AA0", "b c #5A5AA6", "n c #6161A7", "m c #6D6DAD", "M c #797BAF", "N c #7B7BB3", "B c #0606FF", "V c #2525F9", "C c #3F3FF5", "Z c #6969EF", "A c #858585", "S c #8E8E8E", "D c #939393", "F c #9D9D9D", "G c #A09F9F", "H c #82AF82", "J c #85B585", "K c #99BF99", "L c #9898BD", "P c #8888B8", "I c #A3A3A2", "U c #A7A7A8", "Y c #ACACAC", "T c #A5ACAC", "R c #B1ADAD", "E c #A8BFA8", "W c #B4B4B4", "Q c #BAB6B6", "! c #BABABA", "~ c #B5B9B9", "^ c #ED8282", "/ c #E59C9C", "( c #EC9494", ") c #CBBBBB", "_ c #E6B9B9", "` c #9FC29F", "' c #A4C4A4", "] c #A8C7A8", "[ c #B3C6B3", "{ c #B5CBB5", "} c #BDCDBD", "| c #BED0BE", " . c #C8C8BF", ".. c #C4C4BF", "X. c #9E9EC2", "o. c #8D8DDB", "O. c #B9B9CC", "+. c #A1A1D7", "@. c #ACACDD", "#. c #A7A7E2", "$. c #AFAFE4", "%. c #B3B3E1", "&. c #B3C7C7", "*. c #C3C4C3", "=. c #C9C4C5", "-. c #C0C0CF", ";. c #CAC6CA", ":. c #C6C8C8", ">. c #CBCBCB", ",. c #C3CFC3", "<. c #DBC6C6", "1. c #D1CFCF", "2. c #DACAC9", "3. c #CDD1CD", "4. c #C5D2C5", "5. c #DFDFCF", "6. c #D1D1CE", "7. c #C4C4D1", "8. c #CBCBD5", "9. c #C7C7DD", "0. c #D2CDD3", "q. c #D3CED8", "w. c #CED4D4", "e. c #CEDBDB", "r. c #D3D3D3", "t. c #D6D9D6", "y. c #DCDCD4", "u. c #D5D5D9", "i. c #D9D5D9", "p. c #D4DBDB", "a. c #DCDBDB", "s. c #D9D4D3", "d. c #EDC7C7", "f. c #E4CBCB", "g. c #E8C5C5", "h. c #EDD6D6", "j. c #E0D9D7", "k. c #ECDBDB", "l. c #DFE0D8", "z. c #E5E5D7", "x. c #E2E2DC", "c. c #DEDEE1", "v. c #E2DDE2", "b. c #D5E3E3", "n. c #DCE3E3", "m. c #D7E8E8", "M. c #E5E5E5", "N. c #EBE3E3", "B. c #E7E9E7", "V. c #EAEAE4", "C. c #E7E7EB", "Z. c #EBE2EB", "A. c #E4EBEB", "S. c #EBEBEB", "D. c #F0EFEF", "F. c #F6F2E7", "G. c #F6F7EC", "H. c #F7FBEF", "J. c #EFEEF0", "K. c #F4EEF2", "L. c #F1E5F1", "P. c #E3F7F7", "I. c #EDF3F3", "U. c #EBFCFC", "Y. c #E7FCFC", "T. c #F4F4F4", "R. c #F3FBFB", "E. c #FBFBFB", "W. c #F8F6FD", /* pixels */ "M.M.M.M.M.M.M.v.C.S.B.C.B.B.C.B.B.B.B.B.B.B.S.B.S.C.B.S.S.Z.M.M.", "M.B.I.S.S.D.S.G.l.>.i.v.i.r.r.r.r.i.v.i.r.r.r.0.5.y.r.r.t.S.M.M.", "M.T.T.I.U.I.T.B.Y r.[ H E r.1.! r.E H [ r.>.! r.+.o.7.r.u.E.B.V.", "M.S.T.g.^ 1 d.p.F v.h d r ' Z.*.a.g s e 4.a.:.M.Z B $.z.c.E.V.M.", "M.G.T.^ : ; d.p.I a.v.M.e ` v.*.u.Z.3.w &.j.*.a.l.V #.z.a.E.M.M.", "M.S.I.A.E.3 <.M.I a.r.i h Z.i.*.j.} y ' Z.t.:.a.z.V $.z.c.E.B.M.", "M.S.T.a.~ X = u.I M.s O a ` v.*.c.y w p { a.*.x.Z B C 9.M.E.B.M.", "M.J.I.U # $ $ G I t...[ ` ,.a.&.a.| { ' t.i.*.y.@.@.@.q.a.E.B.M.", "M.a.Y T &.&.~ I ! T.D.K.W.D.S.) *.;.s.j.:.*.a.I.F.G.H.D.S.E.M.Z.", "S.8.w.g.7 0 1.p.S.T.U.U.k.T.t.R i.z.L M t.i.T.I.Y.S.k.I.:.T.B.M.", "B.r.w._ ^ > 8 m.N.S.( 2 , N.*.U B.7.j k a.a.T.f.q > 9 P.W T.B.M.", "B.1.1.b.0 : / b.D.S.^ > : N.:.U M.n N x a.i.R.d.6 ; 9 P.Q W.B.M.", "S.r.w.f.<.2 6 m.S.D.U.E.% S.>.Y 7.k z + L M.J.A.E.) 4 E.W T.B.V.", "S.1.e.^ 2 1 ( b.S.T.*.= A *.Y a.7.P l 8.l.T.B.Y @ o Q ) T.C.M.", "S.r.1.a.<.r.n.u.S.u.D & = = F Y a.a.a.r.a.a.D.! = - - A Y E.C.M.", "S.0.! >.0.0.=.*.) Y W .. .! Y u.T.S.T.R.T.B.C.y.Z.A.A.M.u.R.V.M.", "B.8.i.] p d 4.v.*.i.V.L c u.a.T.T.Y.k._ I...M.R.Y.h.d.T.*.T.Z.M.", "S.r.r.] ] u d Z...i.r.z j -.a.I.h.9 ; 2 Y.Q B.g.5 ; 9 P.W T.B.M.", "S.r.>.L.a.u ' M.&.z.b N z O.x.T.N.( 2 < I.Q A.h.^ , 9 Y.Q T.B.Z.", "B.1.r.{ w f w.a.;.r.c z + m x.S.B.R.n.# E.! M.J.E.&.* E.~ T.V.M.", "S.1.i.J y i h Z...u.i.-.c -.x.T.T.I @ A ! C.B.D X . G ! T.B.M.", "S.r.1.M.Z.j.c.a.;.r.l.l.M.a.a.S.*.D S F D U a.Q D D D D W E.B.M.", "M.S.T.T.T.T.T.J.M.T.T.T.T.T.S.M.M.S.K.S.G.c.B.C.G.K.D.K.a.E.B.M.", "M.S.I.V.B.M.S.w.>.T.M.M.M.S.;.t.T.M.B.C.J.! M.J.B.M.M.B.! T.B.M.", "M.S.T.M.M.M.B.r.>.T.M.M.M.S.=.i.S.M.M.M.S.! M.M.M.M.M.B.! T.S.Z.", "M.T.S.M.M.M.S.>.:.T.x.M.M.S.*.t.T.M.M.M.J.! M.S.M.M.M.M.! T.C.M.", "M.S.T.M.M.M.S.r.:.T.M.V.M.S.:.t.S.M.M.M.S.! M.S.M.M.M.M.Q E.B.M.", "M.S.T.M.B.M.B.r.:.T.M.Z.M.S.:.u.T.M.B.M.J.! M.S.M.M.B.S.~ T.B.M.", "M.T.r.Q ! Q ! Y 1.>.W ! ! ! Y i.*.W ! ~ ! R a.! Q ! ! ! W E.M.M.", "M.S.T.T.T.W.T.R.E.W.T.T.T.T.E.E.T.T.T.T.T.E.E.T.T.T.T.T.E.E.Z.M.", "M.M.B.B.B.B.S.B.M.S.B.B.B.S.M.M.S.B.B.S.S.B.M.S.B.B.B.B.B.M.V.M.", "M.M.M.M.M.M.M.Z.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.M.A." }; /* XPM */ static const char *const xpm_icon_2[] = { /* columns rows colors chars-per-pixel */ "48 48 184 2 ", " c #030101", ". c #0C0C0C", "X c #131212", "o c #191A1A", "O c #2A2929", "+ c #262626", "@ c #323232", "# c #393E3E", "$ c #4E2B2B", "% c #007500", "& c #027D02", "* c #0A7E0A", "= c #00007C", "- c #4A4949", "; c #5B5B5B", ": c #545555", "> c #656464", ", c #6A6A6A", "< c #7B7B7B", "1 c #D20F0F", "2 c #D01E1E", "3 c #FF0101", "4 c #FD0B0B", "5 c #FD1212", "6 c #FB1D1D", "7 c #FB2323", "8 c #F83434", "9 c #A95252", "0 c #B85858", "q c #F84545", "w c #F44B4B", "e c #F64848", "r c #EF5757", "t c #F65858", "y c #EA6666", "u c #F46363", "i c #ED7B7B", "p c #F27676", "a c #9C2323", "s c #0C830C", "d c #028102", "f c #168916", "g c #1B8A1B", "h c #118711", "j c #318F31", "k c #359635", "l c #3B973B", "z c #3D993D", "x c #289128", "c c #439C43", "v c #489E48", "b c #4DA14D", "n c #53A253", "m c #5AA55A", "M c #65A965", "N c #6BAC6B", "B c #77B277", "V c #020281", "C c #0A0A83", "Z c #111184", "A c #131388", "S c #1E1E8B", "D c #22228D", "F c #2C2C8E", "G c #2C2C92", "H c #3B3B99", "J c #363695", "K c #42429B", "L c #48489D", "P c #5757A5", "I c #7373AF", "U c #7676B0", "Y c #7D7DB3", "T c #6565AA", "R c #0F0FFC", "E c #1212FC", "W c #2D2DF7", "Q c #3434F6", "! c #3D3DF5", "~ c #4B4BF3", "^ c #4242F9", "/ c #6767EE", "( c #6363F4", ") c #7777F0", "_ c #7D8686", "` c #949494", "' c #9C9C9C", "] c #9A9696", "[ c #8B8B8B", "{ c #8CBA8C", "} c #82B682", "| c #91BD91", " . c #98BE98", ".. c #8C8CBA", "X. c #9595BD", "o. c #9EA1A1", "O. c #A4A4A4", "+. c #ABABAB", "@. c #ABAAA7", "#. c #B5B5B5", "$. c #BBBBBB", "%. c #BEB2B2", "&. c #DD9F9F", "*. c #C79B9B", "=. c #E78C8C", "-. c #F08F8F", ";. c #E69494", ":. c #ED9494", ">. c #EA9D9D", ",. c #C2BFBF", "<. c #DFB2B2", "1. c #E4A4A4", "2. c #ECA6A6", "3. c #EBAAAA", "4. c #E1AEAE", "5. c #E9B4B4", "6. c #E9B9B9", "7. c #E0B6B6", "8. c #AAC6AA", "9. c #AECAAE", "0. c #B4CAB4", "q. c #BFC1BE", "w. c #BBCDBB", "e. c #D3D3BF", "r. c #9797C0", "t. c #A4A4C5", "y. c #A8A8C6", "u. c #B9B9C9", "i. c #B9B9DD", "p. c #C5BCC3", "a. c #C3C3C3", "s. c #C8C5C5", "d. c #CCC6CC", "f. c #CBCBCB", "g. c #C7CEC0", "h. c #DAC5C5", "j. c #C5D1C5", "k. c #CCD4CC", "l. c #C3C3D1", "z. c #CCCCD4", "x. c #C5C5DE", "c. c #C8C8DD", "v. c #D3C9D3", "b. c #CFDADA", "n. c #D5D5D5", "m. c #D6D9D6", "M. c #DADAD7", "N. c #D7D7D8", "B. c #DCDCDC", "V. c #D6D9D9", "C. c #E7C2C2", "Z. c #E9C6C6", "A. c #E7D5D5", "S. c #EBD5D5", "D. c #E3DBDB", "F. c #E9E9D4", "G. c #E3E3DD", "H. c #E4E4D7", "J. c #F4F4D6", "K. c #CECEE0", "L. c #DFDFE0", "P. c #E2DEE2", "I. c #E9DEE9", "U. c #D7E4E4", "Y. c #DBE3E3", "T. c #DAEAE9", "R. c #D6F4F4", "E. c #E5E5E5", "W. c #EAE6E5", "Q. c #EAEAE3", "!. c #EAE3EB", "~. c #E3ECEC", "^. c #EAEAEA", "/. c #F0ECEC", "(. c #F2E6F2", "). c #FFEAFF", "_. c #E3F3F3", "`. c #ECF5F5", "'. c #ECFAFA", "]. c #E6FAFA", "[. c #F4F4F4", "{. c #F4FDFD", "}. c #FDFDFD", "|. c #F8F7F7", /* pixels */ "E.E.E.E.~.E.E.E.E.W.E.E.~.E.E.E.E.E.E.E.E.W.E.E.E.E.E.E.E.E.E.E.E.E.W.E.E.E.E.E.E.E.E.E.E.E.E.E.", "E.E.E.W.W.E.E.W.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.W.E.E.W.", "E.E.E.E.E.E.E.E.E.E.E.E.E.W.^.^.^.E.^.^.W.^.^.^.^.W.^.W.^.E.^.^.^.W.^.^.^.E.^.E.^.W.^.E.~.E.E.E.", "W.E.E.E.^.^.^.^.^.^.^.W./.E.N.V.m.n.n.N.N.N.V.V.V.N.m.n.m.m.m.V.N.N.N.N.N.N.N.N.V.N.Y.^.E.W.E.E.", "E.E.E.^.}.}.|.|.|.}.}.}.}.#.#.a.d.v.v.f.a.e.a.+.$.e.v.v.v.d.q.a.$.+.s.g.e.h.g.a.a.$.V.}.W.E.W.E.", "E.E.E.^.}.E.~._._.Z.D.^.f.` V.E.| b b { L.V.D.u.L.n.B c b 9.E.Y.z.e.E.c./ ^ ) G.E.B.W.}.^.E.~.E.", "E.E.E.W.}.E.S.2.t 4 6.`.s.` N.M.c m c % { P.N.#.L.9.k M g s j.P.f.u.G.i.~ E Q G.N.N.E.}.^.E.E.E.", "E.E.~.W.}.S.q 3 3 3 6.`.s.` N.V.V.(.k.% B I.V.$.V.N.V.).{ % w.P.k.q.L.B.J.Q Q F.V.N.E.}.W.E.E.E.", "~.E.E.^.}.E.A.>.w 3 6.`.s.` N.V.D.V.l g k.B.B.$.B.N.P.w.s n P.B.v.q.Y.N.M.W Q H.B.V.W.}.^.E.E.E.", "W.E.E.^.|.E.E._.{.$ %.[.a.` n.L.n.z x N.!.m.B.#.V.P.0.f m (.P.N.k.q.B.B.J.Q ! J.B.V.E.}.^.E.E.E.", "E.E.E.^.}.E./.^.n.o ' }.s.` n.L.l % v n | L.V.$.P.w.* * n n 0.P.f.p.G.c./ E E / c.V.E.}.^.E.E.~.", "E.E.E.^.{./.#.- o . , s.` n.B.M b v k { P.B.$.L.w.b b c z 0.P.k.p.G.x.! ~ ~ ~ x.D.E.}.W.E.E.E.", "W.E.E.^.|.f.O.' O.O.O.' +.] k.B.P.!.I.I.P.V.N.$.B.E.(.!.(.(.E.P.n.$.V.V.F.F.F.F.M.N.E.}.^.E.E.E.", "E.~.E.E.$.` ' o.o.' ' o.] +.^.^.W.E.E.W.W.^./.#.$.a.$.$.$.q.$.a.,.V./.^.~.!.E.!.^.^.[.}.W.E.E.E.", "E.E.^.N.$.M.N.n.v.n.b.n.n.W.}.[.|.[.{.{.[.}.V.O.n.f.f.n.d.s.f.n.n.|.|.[.[.{.{.|.|.^.k.}.^.E.W.E.", "W.E.^.V.a.T.>.5 5 7 1.Y.M.^.[.E._.~.C.:.E.W.+.O.E.V.Q.r.V P E.V.P.|.E._._.D.:.C.`.a.#.}.^.E.E.E.", "E.E.W.N.a.Y.<.1.<.4 8 U.N.^.{.A.-.w 4 6 ~.^.+.O.L.B.l.D V K G.N.B.}.E.3.u 7 3 2.].s.#.}.W.E.E.~.", "E.E.^.m.a.B.T.;.w 4 =.U.n.^.{.6.8 3 3 7 E.^.+.@.P.G.L U K H E.N.B.}.E.u 4 3 3 3.'.s.#.}.W.E.E.E.", "E.E.^.V.a.B.U.=.e 5 p U.M.^.[.E._.Z.r 2 E.^.+.O.Q...S l.G G n.V.L.}.W._.D.>.1 4.'.s.#.}.~.E.E.W.", "E.E.E.n.p.E.h.B.R.8 6 M.N./.[.E.E.{.b.+ [.^.+.O.Q...= Z C = T Q.B.}.E.E.W.}.$ o.}.a.$.}.^.E.E.E.", "E.E.^.V.,.T.r 5 6 3 y U.N.^.|.E.E.$.> . ' E.+.O.P.z.u.p.D F z.M.B.}.E.E.f.] X ; B.f.#.}.W.E.E.E.", "E.E.W.m.a.Y.h.;.=.4.B.B.V.W.|.W.< @ O @ + [ #.O.L.B.Y.G.t.t.G.V.B.}.[.+.- + @ + : $.$.}.W.E.E.E.", "E.E.^.V.a.Y.B.T.T.U.V.B.N.^.N.@.+.#.#.#.#.+.] O.B.N.N.n.G.G.N.N.P.^.+.O.+.#.#.#.+.' #.}.^.E.E.W.", "E.E.^.V.+.$.$.p.p.p.#.$.$.#.+.O.O.O.@.@.O.O.O.M.|.[.[.[.[.[.|.|./.^.E.Y.D.B.B.L.E.B.E.}.~.E.E.E.", "E.E.^.V.a.P.n.8. .0.P.V.D.$.n.P.B.G.u.y.V.E.B.|.[.^./.[.'.[.^.^.#.|.|.[.[.{.'.[.|.B.s.}.^.E.W.W.", "E.E.W.N.q.E.N s f & } P.B.a.k.V.E.t.= Z l.M.N.[.^._.~.C.u =._.B.o.|.E._.E.3.w 5.`.a.#.}.~.E.E.E.", "W.E.^.N.u.E.0.j.B.g j D.B.a.z.G.n.J G A l.D.N.[.[.>.8 4 3 u '.D.@.{.E.p 6 3 3 2.'.s.$.}.E.E.E.E.", "E.E.^.V.e.B.B.!.j.& N I.B.q.f.Q.P I ..= m.L.N.|.`.5.t 6 3 u ].B.O.|.E.:.e 4 3 3.'.s.#.}.W.E.~.E.", "E.E.E.N.$.M.P.w.h n I.V.V.e.n.l.= U K = Y L.m.[.^.~._.W.0 9 '.B.O.|.W.].~.S.a *.'.s.#.}.W.E.E.E.", "E.E.^.N.u.E.8.s k 9.0.M.L.$.n.l.H G A = K M.N.[.[.E./.}._ : }.D.O.{.W.W.[.}.# O.}.s.#.}.W.E.E.E.", "E.E.^.N.e.^.M % g d k V.L.u.f.B.V.Q.Y C z.D.N.[.`.D.+.> X . < n.+.[.^.N.` - O ' s.#.}.~.E.E.W.", "E.E.W.z.$.L.n.j.j.k.k.V.M.$.n.B.M.B.z.z.N.M.N.[.`.s., ; > > ; O.+.[.^.@.; ; , ; , #.$.}.^.E.E.E.", "E.E.^.B.f.E.B.E.P.P.P.M.E.s.n.Y.B.L.D.B.B.L.Y.[.#.O.$.$.$.#.q.@.+.E.O.+.#.$.#.$.$.o.s.}.E.E.E.E.", "E.E.E.E.}.|.|.|.}.|.}.}.[.E.}.|.}.}.}.}.}.}.^.^.|.|.[.[.[.[.[.{.E.[.|.{.[.[.|.[.[.[.E.}.W.E.E.E.", "E.E.E.^.}.E.E.E.E.W.E.^.a.a.}.E.E.E.E.^.E./.#.B.[.E.E.W.^.W.E.E.+.|.^.E.^.~.^.E./.f.$.}.W.E.E.~.", "E.E.E.^.}.E.E.E.E.E.E.`.$.a.|.E.~.E.E.E.E.^.@.L.[.E.E.E.E.E.E.D.O.|.E.E.E.E.E.E.^.d.#.}.^.E.E.W.", "E.E.E.^.}.E.E.E.E.E.E.`.a.a.}.E.^.E.E.E.E.^.@.E.[.E.E.E.E.E.W.Y.@.|.^.E.E.E.E.E.^.s.$.}.E.E.E.E.", "W.E.E.^.}.E.E.E.E.E.E.^.a.$.|.E.E.E.E.E.E.^.@.D.[.Y.E.E.E.E.E.P.O.|.^.E.E.E.E.E.^.s.#.}.^.E.E.E.", "~.E.E.^.}.E.E.E.E.E.E.^.u.a.}.E.E.E.E.E.E.^.+.Y.[.E.E.E.E.E.W.Y.O.|.E.E.E.E.E.E.`.f.#.}.W.E.E.E.", "E.W.E.^.{.E.E.E.E.E.P.E.e.q.}.B.E.E.E.E.E.^.O.E.[.L.E.E.E.E.E.E.O.}.E.E.E.E.E.E.W.s.#.}.^.E.~.E.", "E.E.E.^.}.^./.^.^./.W.[.a.q.}.^.^.^.^.^.^.[.+.B.{.^.^.^.^.W.^.E.O.{.^.^.^.W.^.^.[.f.#.}.W.E.E.E.", "E.E.E.^.{.f.s.s.f.f.f.f.+.q.[.a.f.s.f.f.f.f.' E.D.s.f.s.f.f.f.a.' [.n.s.f.f.f.f.f.#.#.}.W.E.E.E.", "E.E.E.^.E.#.#.$.#.#.#.$.#.V.n.#.$.#.#.#.#.#.$.E.a.#.$.#.#.#.$.#.s.E.$.#.#.#.#.#.#.#.n.}.W.E.~.W.", "E.E.E.W.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.}.^.E.E.E.", "E.~.E.W.^.W.^.W.^.E.^.^.W.W.^.~.^.W.~.W.W.~.W.^.E.W.~.W.^.E.^.E.W.W.^.E.W.^.W.~.~.W.^.^.E.E.~.E.", "E.W.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.W.", "W.E.E.E.E.E.E.E.E.E.E.E.E.W.E.E.W.E.E.~.E.E.E.E.E.E.E.E.E.E.E.E.W.~.E.E.E.E.E.W.E.E.E.E.~.E.E.E.", "E.E.~.W.E.E.~.E.E.E.E.E.W.E.E.E.E.E.E.E.E.W.E.W.~.E.W.E.E.^.E.E.E.E.E.E.~.W.E.E.E.E.W.E.E.E.W.E." }; const char *const *const xpm_icons[] = { xpm_icon_0, xpm_icon_1, xpm_icon_2, }; const int n_xpm_icons = 3; puzzles-20170606.272beef/icons/map-icon.c0000644000175000017500000003767113115373752016673 0ustar simonsimon/* XPM */ static const char *const xpm_icon_0[] = { /* columns rows colors chars-per-pixel */ "16 16 256 2 ", " c gray90", ". c #DCDEDB", "X c #DADCD9", "o c #DBDDD9", "O c #DADFDA", "+ c #DADAD8", "@ c #DBD9D8", "# c #DEDDDC", "$ c #E1E1E1", "% c #DEDBDA", "& c #DEDCD8", "* c #DFDDD8", "= c #DFDDD8", "- c #DFDDD8", "; c #DFDEDA", ": c gray90", "> c #DADCD9", ", c #83996C", "< c #829B6A", "1 c #84956A", "2 c #838A65", "3 c #8C7B61", "4 c #886F56", "5 c #C7C1BB", "6 c #EAEEF2", "7 c #BCA294", "8 c #C1A663", "9 c #CDB770", "0 c #CAB36E", "q c #CAB26B", "w c #C8B476", "e c #E0DFDC", "r c #DFDFDF", "t c #B1BBA6", "y c #819969", "u c #817355", "i c #8B6E57", "p c #866D52", "a c #B4A89B", "s c #E9EAEB", "d c #E4E4E3", "f c #B68E7C", "g c #BC995B", "h c #CBB364", "j c #C9AF63", "k c #CEB561", "l c #CAB36E", "z c #E0DFDB", "x c #E1E1E1", "c c #E9E7EB", "v c #D1D3D0", "b c #D0CECA", "n c #D6D3D0", "m c #CECBC9", "M c #DEDEDF", "N c #EDF2F5", "B c #CABCB4", "V c #AB755A", "C c #B28168", "Z c #B18364", "A c #B08164", "S c #BD9D60", "D c #CEB970", "F c #E0DFDC", "G c #E2E2E2", "H c #D9D9D8", "J c #E4E4E5", "K c #EAEBEB", "L c #EAEBEC", "P c #E0E1E1", "I c #D8D8D8", "U c #B7ADA3", "Y c #8F7962", "T c #A97A60", "R c #B98269", "E c #B47F66", "W c #B37F67", "Q c #B17B61", "! c #A99067", "~ c #DEDEDB", "^ c #E2E2E2", "/ c gray86", "( c #E6E6E6", ") c #E6E6E6", "_ c #E3E2E2", "` c #DDDDDD", "' c #E1E3E5", "] c #B6ACA5", "[ c #886950", "{ c #A67A61", "} c #A78063", "| c #B18266", " . c #A88164", ".. c #8D825C", "X. c #947664", "o. c #DBDCDB", "O. c #E2E2E2", "+. c #D8D8D8", "@. c gray90", "#. c #E8E8E7", "$. c #E3E4E6", "%. c #DCDBD6", "&. c #CDB97D", "*. c #CCC5A0", "=. c #847A5E", "-. c #866F55", ";. c #788C5E", ":. c #8C7458", ">. c #8C8962", ",. c #799B64", "<. c #8A8164", "1. c #DFDBDB", "2. c gray88", "3. c #D8D8D8", "4. c gray87", "5. c #DADADA", "6. c #D5D4D5", "7. c #D1CCC0", "8. c #C1A95E", "9. c #BEA159", "0. c #8E805C", "q. c #789062", "w. c #809565", "e. c #7E885D", "r. c #7B9262", "t. c #7D8E5E", "y. c #8D7C63", "u. c #DEDCDB", "i. c #E1E1E1", "p. c #E2E2E1", "a. c #E4E3E3", "s. c #E6E7E8", "d. c #B9B0A6", "f. c #886F55", "g. c #8D765B", "h. c #8D7259", "j. c #A77A61", "k. c #949462", "l. c #819C65", "z. c #79875F", "x. c #896F57", "c. c #887055", "v. c #927A64", "b. c #DDDCDB", "n. c #E1E1E1", "m. c #E6E7E8", "M. c #ECEEEF", "N. c #EEEFF0", "B. c #D0CAC7", "V. c #8C735A", "C. c #8C7359", "Z. c #8D755A", "A. c #8B6D58", "S. c #B7955E", "D. c #BFB064", "F. c #A7975D", "G. c #88815A", "H. c #887056", "J. c #927C64", "K. c #DDDCDB", "L. c #DFDFDE", "P. c #C8C3BE", "I. c #D0CAC5", "U. c #B9B3A9", "Y. c #847A5C", "T. c #897257", "R. c #8B7059", "E. c #876F58", "W. c #866B57", "Q. c #AF975E", "!. c #D5BA68", "~. c #D0B766", "^. c #889360", "/. c #886E55", "(. c #937963", "). c #DDDCDB", "_. c #DBD9D7", "`. c #8A735C", "'. c #876B50", "]. c #837052", "[. c #789461", "{. c #7C9062", "}. c #90835A", "|. c #AA905B", " X c #A77C60", ".X c #B99163", "XX c #CAB365", "oX c #CDB366", "OX c #90945F", "+X c #7D7055", "@X c #8A8766", "#X c #DDDDDB", "$X c #DBD9D8", "%X c #937B62", "&X c #8C7458", "*X c #8A6D5A", "=X c #987C5F", "-X c #7E9967", ";X c #879D65", ":X c #CFBA66", ">X c #C1A065", ",X c #AD7965", " , < 1 2 3 4 5 6 7 8 9 0 q w e ", "r t y u i p a s d f g h j k l z ", "x c v b n m M N B V C Z A S D F ", "G H J K L P I U Y T R E W Q ! ~ ", "^ / ( ) _ ` ' ] [ { } | ...X.o.", "O.+.@.#.$.%.&.*.=.-.;.:.>.,.<.1.", "2.3.4.5.6.7.8.9.0.q.w.e.r.t.y.u.", "i.p.a.s.d.f.g.h.j.k.l.z.x.c.v.b.", "n.m.M.N.B.V.C.Z.A.S.D.F.G.H.J.K.", "L.P.I.U.Y.T.R.E.W.Q.!.~.^./.(.).", "_.`.'.].[.{.}.|. X.XXXoXOX+X@X#X", "$X%X&X*X=X-X;X:X>X,X c #8F7855", ", c #86755D", "< c #8C745A", "1 c #927956", "2 c #9D7B55", "3 c #90735B", "4 c #9B735B", "5 c #947E5E", "6 c #9B7C5F", "7 c #A4745C", "8 c #AC765B", "9 c #A47C5D", "0 c #AA7A5E", "q c #8D7760", "w c #9F7E60", "e c #927F6B", "r c #A37D61", "t c #AC7C63", "y c #A67A68", "u c #AA7E69", "i c #B17660", "p c #B37E66", "a c #B57F68", "s c #76865C", "d c #7A855C", "f c #748C5C", "g c #7B8B5E", "h c #7B915E", "j c #7C8E60", "k c #749762", "l c #7C9464", "z c #7E9A66", "x c #7E9369", "c c #7D9C68", "v c #7DA069", "b c #8B8256", "n c #84845D", "m c #88835C", "M c #828C5E", "N c #8C945F", "B c #8E995F", "V c #92965C", "C c #92985F", "Z c #AD825F", "A c #A08858", "S c #AB8B59", "D c #B08D5E", "F c #A69057", "G c #A39E5E", "H c #A89F5F", "J c #B4945E", "K c #B29C5D", "L c #BA9E5D", "P c #B4A35F", "I c #B9A15D", "U c #809765", "Y c #819A67", "T c #8D9960", "R c #829B6A", "E c #919B61", "W c #918976", "Q c #879A72", "! c #8C9C7B", "~ c #AD8260", "^ c #AE836C", "/ c #B48066", "( c #B88066", ") c #B28B61", "_ c #B48269", "` c #BC8169", "' c #A89362", "] c #B69E66", "[ c #B99B62", "{ c #AF8670", "} c #A68978", "| c #AFA267", " . c #B4A560", ".. c #BCA362", "X. c #BFAA60", "o. c #B5A56E", "O. c #BCA768", "+. c #BEAA6C", "@. c #BDAB71", "#. c #C1A75F", "$. c #C3AA5C", "%. c #C1A465", "&. c #C3AC65", "*. c #C8AE63", "=. c #C4AE6B", "-. c #C6B163", ";. c #CCB365", ":. c #C6B16B", ">. c #CCB46A", ",. c #CFB868", "<. c #D2B666", "1. c #D3BA66", "2. c #D0B669", "3. c #D2BA69", "4. c #9F9285", "5. c #A79A8C", "6. c #B99B8C", "7. c #ACA297", "8. c #ADA398", "9. c #B1A79C", "0. c #B3A99E", "q. c #B6ADA4", "w. c #B8B0A7", "e. c #BDB5AE", "r. c #BDBAB5", "t. c #C6B98F", "y. c #C4BEAE", "u. c #C5BCB7", "i. c #CBBFB9", "p. c #C1C5BC", "a. c #C8C3BF", "s. c #D1C5BF", "d. c #CAC6C1", "f. c #CDC9C6", "g. c #CDCDCC", "h. c #D3CEC0", "j. c #D6D1C1", "k. c #D3D1CF", "l. c #D5D5D4", "z. c #D9D6D5", "x. c #D7D8D6", "c. c #DBD9D6", "v. c #D6D6D9", "b. c #D8D7D9", "n. c #DCDCDC", "m. c #DEDEE1", "M. c #DFE1E2", "N. c #E5E5E5", "B. c #E8E8E7", "V. c #E5E6E9", "C. c #E5E8EA", "Z. c #E9E9E9", "A. c #EEEFF0", "S. c #EEF1F3", "D. c #F3F6FA", /* pixels */ "N.N.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.C.Z.B.Z.Z.Z.C.Z.Z.Z.Z.Z.Z.Z.Z.Z.B.N.", "N.N.x.x.c.x.x.c.x.x.x.z.z.c.c.n.n.n.c.z.c.c.c.c.c.c.c.n.c.c.N.N.", "Z.x.x U z z z x z x O < , $ 4.N.b.N.u.7 ] ;.&.&.=.&.&.&.&.+.n.Z.", "Z.c.l z U Y z + X o ; < 3 # q.S.N.A.d.8 %.<.;.;.;.;.<.;.<.:.n.Z.", "Z.c.! R l Y + * < < 3 < # 8.C.N.N.A.a.7 ..<.;.>.>.;.;.>.;.=.n.B.", "Z.n.m.c.Q f . % $ $ % # 7.A.N.N.Z.k._ / ~ #.;.-.*.;.;.;.<.=.n.Z.", "Z.n.n.Z.n.p.r.d.d.d.r.f.Z.Z.Z.N.Z.6.8 / p t ~ ~ ~ 0 I 3.;.=.n.Z.", "Z.n.n.B.n.z.N.A.Z.A.c.n.v.g.c.Z.C.} p / / / / / / _ t I <.:.n.Z.", "Z.n.n.n.c.N.N.N.N.N.N.M.l.x.k.z.5.# 4 / / / / / / / / t L O.n.B.", "Z.n.c.v.Z.N.Z.N.N.N.n.l.l.M.0.. : : 4 / ~ / / / / / p _ = , n.B.", "Z.n.n.v.Z.N.N.N.N.N.l.B.N.M.u.# < % / _ / ` / / / r n t 4 q n.Z.", "Z.n.n.b.N.N.Z.N.B.N.b.Z.n.k.D.w.$ < - 7 6 w 6 / ` 6 k 5 : < n.Z.", "C.n.n.b.Z.N.Z.N.N.N.x.C.t.+.n.x.$ < < $ s z f 0 r g z z + < n.Z.", "Z.n.c.b.C.N.N.C.B.z.N.s.$.;.:.o.f X = ; z d # % d c Y R + < n.Z.", "Z.n.g.k.l.n.Z.c.z.n.S.s.-.1.1.$.n o o l Y d , o g Y Y z o q n.Z.", "Z.n.n.Z.N.l.n.g.b.z.v.u.I $.I P i n c Y Y c z Y l g l + % q n.Z.", "B.n.n.B.B.N.n.M.g.$ < < : % : $ p 9 l l z U Y d $ $ ; : : q n.Z.", "B.n.n.B.N.N.B.B.N.e $ < < < < : 4 ` A G N z l $ 3 < 3 < : q n.Z.", "Z.n.n.B.N.N.N.N.Z.c.q : < : < < & 4 9 2.*.V M > ; X < < : q n.Z.", "B.n.n.N.N.N.N.N.V.q.: : < < : < < $ > *.;.<.;.;.B s * : : q n.Z.", "Z.n.V.S.S.Z.D.y., % : < : < < : < < 1 ;.;.;.>.;.E d : < : 3 n.Z.", "Z.b.8.0.9.9.q.W X O ; : < < < < : % 1 ;.;.;.;.;.E d : < 3 q n.Z.", "Z.z.$ @ $ # @ X v Y l o $ : > $ = a / ;.;.;.;.;.T s * < $ , n.Z.", "Z.z.< < < < < ; g Y Y z g H *.&.D p t J ;.,.;.;. .g O $ g U n.Z.", "Z.b.< < < < < < $ M Y Y z G 1.2.-.Z _ t Z J ;.;.3. .g l Y R n.B.", "Z.z.: = > % < % t t g Y U l H <.;.) a t t J ;.;.;.<. .l z R n.Z.", "Z.c.y D ;.A $ * _ / t g z x C -.;.) i J ;.;.;.;.;.;.<.P g x n.Z.", "Z.c.u [ 1.;.P J t / p t M c + : -.) t P ,.;.;.;.:.;.;.>.I o.n.B.", "Z.c.t 2 F ;.<.1.L t / ` 7 V b $ S Z / 0 %.;.;.;.;.;.;.;.1.>.n.C.", "Z.c.^ < < :.:.:.O.u _ ^ u %.' , y ^ _ u ..:.:.=.:.=.=.:.:.+.n.Z.", "Z.N.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.n.B.B.", "N.N.Z.Z.Z.C.Z.Z.B.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.C.Z.Z.Z.Z.B.Z.Z.Z.Z.Z.N.N." }; /* XPM */ static const char *const xpm_icon_2[] = { /* columns rows colors chars-per-pixel */ "48 48 106 2 ", " c #7B684F", ". c #7E6A52", "X c #767554", "o c #787755", "O c #767855", "+ c #82674C", "@ c #89664F", "# c #82694D", "$ c #846D54", "% c #8B6C55", "& c #836E58", "* c #877056", "= c #897157", "- c #86705A", "; c #8C735A", ": c #867C5A", "> c #897A59", ", c #90765C", "< c #9E735A", "1 c #A2755C", "2 c #A6785F", "3 c #AA7A5F", "4 c #AC765A", "5 c #A27761", "6 c #A47962", "7 c #AB7B63", "8 c #A67F6B", "9 c #AC7F68", "0 c #B27E65", "q c #74865A", "w c #758A5C", "e c #798E5F", "r c #77905D", "t c #79905F", "y c #798E61", "u c #769564", "i c #7B9363", "p c #7D9965", "a c #7E9468", "s c #9B8555", "d c #8F915A", "f c #92925A", "g c #A8875A", "h c #A9895A", "j c #AE9759", "k c #AE9A59", "l c #B29C5C", "z c #B7A15B", "x c #BDA65F", "c c #BEA85F", "v c #819A66", "b c #809669", "n c #839D69", "m c #AF8169", "M c #B48166", "N c #B88267", "B c #B78268", "V c #B98469", "C c #B39E62", "Z c #B5A062", "A c #BEA661", "S c #BFA962", "D c #B7A469", "F c #C0A75F", "G c #C1AA5F", "H c #C8AE5C", "J c #C0A760", "K c #C1AA65", "L c #C8AF60", "P c #C2AC68", "I c #CDB366", "U c #CEB668", "Y c #D1B666", "T c #D2B867", "R c #D0B768", "E c #D3B969", "W c #9F9387", "Q c #A1968A", "! c #A3988E", "~ c #A69C92", "^ c #A89E94", "/ c #B59F94", "( c #9EA993", ") c #BEB28E", "_ c #B5A095", "` c #BFB493", "' c #C6C5C3", "] c #C8C7C5", "[ c #C9C9C7", "{ c #CCCCCC", "} c #D2D0CF", "| c #D6D5D5", " . c #D8D7D7", ".. c #D7D8D7", "X. c #D9D8D7", "o. c #D6D7DA", "O. c #D7D8DC", "+. c #DADADA", "@. c #E0E0DF", "#. c #DFDFE0", "$. c #E6E6E6", "%. c #E8E8E7", "&. c #E5E6EA", "*. c #E7E9EA", "=. c #E9EAEA", "-. c gray94", /* pixels */ "$.$.$.%.$.$.$.$.%.$.$.$.$.%.%.$.$.$.$.$.$.%.$.$.$.$.$.$.%.$.$.$.%.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.", "$.$.$.%.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.%.$.$.$.%.%.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.&.$.$.", "$.%.$.$.%.%.%.=.=.=.=.%.%.%.=.%.=.=.%.=.%.=.%.=.%.*.%.=.=.%.&.*.*.*.=.=.*.*.=.=.%.=.%.=.$.$.$.$.", "$.$.$.$.+.o.X.X......... . ... .X.X.X.X.X.o.+.X.O.X.+.X.X.X.X.X.X.X.X.X.X.X.+. .+. .+.X.$.$.$.$.", "$.$.%.+.a a a a a a a a a a a y & - - ; ; - ] +...+.+.] 8 6 C P S P S S P S S S P P P C +.=.$.$.", "%.$.%...a v v p v v v p t i i q $ ; ; ; ; $ ..=.%.%.=. .7 7 J T I I U U U U U I R L I P +.=.$.$.", "$.$.=.+.a v v v v v p O $ . $ $ ; ; ; , $ Q %.$.$.$.%.| 7 3 J U I I I I I I I I I I I K +.=.$.$.", "$.$.%...y i i v v p O = , ; , ; ; ; ; # W *.%.$.$.$.=.o.7 7 J T I I I P I I I I I I I P .=.$.$.", "$.$.%.+.' X.( e n i $ ; ; ; ; ; ; ; $ W =.$.$.$.$.$.=./ 0 0 h I E U U U U U I I I I I P +.=.$.$.", "$.%.%.X.O.-.*.( e w . = = & & % & # W =.$.$.$.$.$.%./ 4 M M 7 h c c c G G c U I I I I K X.%.$.$.", "$.%.=.+.| %.$.$...[ ' | } } | ' [ .*.=.%.%.$.$.%.| 6 V M 0 B 7 3 3 3 3 3 2 h U I L I P X.%.$.$.", "$.%.%.+.X.%.$.$.#.| +.=.=.=.=.+.| #.X.X.X.+.$.$.=.X.7 0 M B 0 B B M M M M B 7 h U I I P X.=.$.$.", "$.$.%.+.X.=.$.{ ..| $.$.$.$.$.$.| ..+.{ { { +.-.=.! @ 0 M M M M 7 M M M M M V 7 h U T P +.%.$.$.", "%.$.%.+.X.%.{ #.=.%.%.$.$.$.$.$.%.%.#.} $.+.[ +.~ # = % 0 M M 7 M M M M M 0 0 N 7 g K C +.%.$.$.", "$.$.*.O.+.+.| =.$.$.$.$.$.$.$.%.$.[ X.{ +...- * $ , * % 0 M M M M M M M 0 M M M V 1 # * o.%.$.$.", "$.$.*.X.+.#.o.%.$.$.$.$.$.$.%.$.[ #.-.+.+...$ , ; = % M M m M M 0 m M M M 0 6 7 0 6 & ; +.%.$.$.", "$.%.%.+.+.+.X.%.$.%.$.$.$.$.=.X.o.%.%.X.o.%.! # , % % 0 V M N M M M M M M 2 w q 0 7 $ ; ..%.$.%.", "%.%.%.+.+.+.o.%.$.$.$.$.$.%.%.+.o.%.=.O.+.=.*.Q $ ; * % 3 2 2 7 2 2 M 0 B 2 i i < < $ ; ..=.$.$.", "$.$.%.+.+.+.o.%.$.$.$.$.$.%.%.+.X.=.&.` ) &.-.+.; ; ; ; $ q y i q 7 V 0 : p a y q $ ; ..=.$.$.", "$.$.%.+.+.#.X.=.$.$.$.$.$.$.%.o.X.*.` H H ` +.' . $ ; ; , $ i v i q < 2 : p p v n i $ - o.%.$.$.", "%.$.%.O.+.#.+.=.$.%.$.$.%.%.$.{ %...A T I L P l w w $ , % o a t . * $ . t v a v a i $ ; o.=.$.$.", "$.$.*.X.{ } { +.#.%.$.$...o.[ #.%.| K Y I I T A e w $ o p n e . * * . t v v p v e $ ; o.=.$.$.", "$.$.%.+.{ +.o.o.{ #.-.O.} #.%.=.-.+.P T U I T A 1 < q t a v v p e e e t v n v n p O % - o.=.%.$.", "$.%.=.O.+.=.%.%.$.{ X.{ { +.| | | ] l J A A J l 7 3 i v v v v v n v n v e e y r O = ; ; ..%.$.$.", "%.$.=.+.| %.$.$.%.$.....+.[ - ; = * % $ $ * = # 2 M : i n v v v v v p o $ . * $ ; ; ; - .=.$.$.", "$.$.=.O.X.%.$.%.$.%.%.%.=.+.$ ; ; ; ; ; ; ; ; $ 2 V 0 > t t a v v v o % ; ; ; ; ; ; , ; .%.$.$.", "$.$.%.X.X.%.$.$.$.$.$.$.$.%.~ # ; ; ; ; ; ; ; = % 0 V 3 l G f u n t $ , ; ; ; ; ; ; ; - .*.$.$.", "%.$.%.+.X.%.$.$.$.$.$.$.$.$.=.^ * ; ; ; ; ; ; ; * % 3 < G E I f t q . $ $ $ ; ; % ; , - X.=.$.$.", "$.%.%.+.| *.$.&.$.$.$.$.=.=.=.^ # ; ; ; ; = ; ; ; ; $ $ x U I I x A S k w q $ , ; ; ; ; .=.$.$.", "$.$.=.+.| *.$.$.$.$.$.$.} ..! + , ; ; ; ; ; ; ; ; ; ; $ x Y I I U I E S i y $ ; ; ; ; * +.*.$.$.", "$.$.%.O.+.-.%.=.*.%.-.+.; * * , ; ; ; ; = ; ; ; ; ; , % A T I I I I Y x t t $ , ; ; ; - .=.$.$.", "$.$.%.X.] .} } | } ..' . * * # = ; ; ; ; ; ; ; ; % $ A U L I I I Y x i y $ , ; ; ; - .%.$.$.", "%.$.%.X.- & * * * * ; . q i e y O % ; ; ; ; ; ; = % 3 1 x Y I I I I U A a e $ ; ; ; ; ; +.=.%.%.", "$.$.*.X.; ; ; ; ; ; ; $ y n v v p o $ * $ * $ $ % M N 3 c Y I I I L T Z i y $ ; ; = $ . o.%.$.$.", "$.$.*.X.; ; ; ; ; ; ; ; X p v p v v t w k G c c h 7 M 7 g I T U I I I I f i o = = o i y o.=.$.$.", "$.$.*.X.* ; ; ; ; ; ; ; % X p n v v n t K E U T U h 0 B 7 h x c L I I I I f u o X p v a +.%.$.$.", "&.$.=. .; , ; ; ; ; ; ; * % > i v v v i d I I I Y S 3 M M M 7 1 A U I P U Y f i v v v a ..%.%.%.", "$.$.=. .$ $ % % = ; ; % % 0 0 > p v a v u f L I U x 7 M M 7 3 1 A U I I L I I f i v v a ..%.$.$.", "$.$.=. .5 < j P s $ , $ 3 M M 0 > p v a v y S E U x 7 M 7 h K G I I I I I I I I f u v a X.*.$.$.", "$.$.=.| 9 0 J T U s $ . 2 V 0 N 0 > p v v i k x I x 3 0 h Y U U I I I I I I I I I f y y X.%.$.$.", "$.$.=. .9 7 J R I I A K h 7 0 0 M 0 > p n y . $ L P 7 0 g I R L I R I I I I I I I I F C .=.$.%.", "$.$.=. .9 7 j A L I U U U h 7 B M M 0 > i q $ = l l 6 V 0 g L Y L P I I I I I L L I R P +.=.$.$.", "$.$.*.X.9 3 $ # A T I I T G 7 N 0 M V 7 z z $ $ < 3 0 0 0 7 J T R Y I I R I Y I R I Y P +.%.$.$.", "$.$.%.X.8 6 - & C P S P P Z 5 9 9 7 9 5 A D $ & 5 0 9 9 9 5 C P P P P S P P P J P P K D .%.$.$.", "$.$.$.$.X.X.X.X.+.X.+.....+.....X.X.o.X.X.+.o.o.X.X.X.X.X.X.X.+.| +. .+.+.| +. .+.X.+.X.$.$.$.$.", "&.$.$.$.%.%.*.=.%.=.%.%.%.=.=.=.&.%.%.=.%.%.%.%.=.=.=.=.=.=.%.*.%.*.=.%.=.%.=.=.%.=.%.%.$.%.%.$.", "%.$.$.%.$.$.$.$.$.$.$.$.$.$.%.$.$.$.$.$.%.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.$.%.$.$.", "$.$.$.$.$.$.$.$.$.%.$.$.$.$.$.$.$.$.$.%.$.$.$.$.$.$.%.$.$.$.$.$.$.$.$.$.$.$.$.$.$.&.$.$.$.$.$.$." }; const char *const *const xpm_icons[] = { xpm_icon_0, xpm_icon_1, xpm_icon_2, }; const int n_xpm_icons = 3; puzzles-20170606.272beef/icons/magnets-icon.c0000644000175000017500000003756513115373752017556 0ustar simonsimon/* XPM */ static const char *const xpm_icon_0[] = { /* columns rows colors chars-per-pixel */ "16 16 251 2 ", " c #D5D7D7", ". c #D5D2D2", "X c #D5CACA", "o c #D4CACA", "O c #D5CDCD", "+ c #CFCBCB", "@ c #CCCDCD", "# c #CECECE", "$ c #CDCDCD", "% c gray83", "& c #D7D7D7", "* c LightGray", "= c LightGray", "- c LightGray", "; c LightGray", ": c #D5D5D5", "> c #D4C4C4", ", c #CD2323", "< c #CD1515", "1 c #CA1D1D", "2 c #D91111", "3 c #5E1A1A", "4 c #071313", "5 c #100D0D", "6 c gray1", "7 c gray27", "8 c #C8C8C8", "9 c #ACACAC", "0 c #AFAFAF", "q c #AEAEAE", "w c gray70", "e c #D4B6B6", "r c #CC0505", "t c #D06868", "y c #CE7D7D", "u c #DB0404", "i c #4B0000", "p c #061515", "a c #383535", "s c gray15", "d c #2C2C2C", "f c #BCBCBC", "g c gray65", "h c #A9A9A9", "j c gray66", "k c #AEAEAE", "l c LightGray", "z c #D3B1B1", "x c #CC1B1B", "c c #D1ABAA", "v c #CFBDBC", "b c #DC2726", "n c #450000", "m c #293A39", "M c #908E8C", "N c #767876", "B c #393939", "V c #BAB9B9", "C c #A9A7A7", "Z c #ABA9A9", "A c #A9A7A7", "S c #AFAFAF", "D c LightGray", "F c #D4BBBC", "G c #D20303", "H c #D52325", "J c #D23133", "K c #E20000", "L c #510202", "P c black", "I c #050202", "U c #2B2A2B", "Y c #C1C4C4", "T c #A6AEAE", "R c #A9B3B3", "E c #A8B1B1", "W c #AEB1B1", "Q c #D3D2D2", "! c #D6D5D6", "~ c #B7A592", "^ c #AC8F75", "/ c #AF9078", "( c #B1987F", ") c #91957E", "_ c #7A977D", "` c #839A82", "' c #7A9479", "] c #A2B2A4", "[ c #D7CCCE", "{ c #C7A3A2", "} c #C99D9D", "| c #C8A1A1", " . c #CBBEBE", ".. c #D5D7D7", "X. c #BDCEBD", "o. c #2AA732", "O. c #18A524", "+. c #19A524", "@. c #20A62B", "#. c #19A21D", "$. c #2DA72D", "%. c #22A322", "&. c #20A01D", "*. c #4BBC59", "=. c #D26D6E", "-. c #CD0000", ";. c #CF2D2D", ":. c #CD0000", ">. c #D15555", ",. c #D6E4E4", "<. c #B8CCB8", "1. c #20991E", "2. c #3CA239", "3. c #42A43F", "4. c #1F981C", "5. c #169615", "6. c #1E991E", "7. c #43A542", "8. c #319B2E", "9. c #36B246", "0. c #D05E5E", "q. c #CE2828", "w. c #D3C3C3", "e. c #CF5252", "r. c #CF4A4A", "t. c #D6E3E3", "y. c #B7CBB7", "u. c #199719", "i. c #359F35", "p. c #3BA13B", "a. c #189618", "s. c #139411", "d. c #1D971A", "f. c #41A33E", "g. c #309929", "h. c #34B042", "j. c #CE5F5E", "k. c #CB2828", "l. c #D1C3C3", "z. c #CD5252", "x. c #CD4B4B", "c. c #D6E3E3", "v. c #C2CFC2", "b. c #46B046", "n. c #34AC34", "m. c #34AB34", "M. c #3EAE3D", "N. c #26AA2F", "B. c #2FAE3E", "V. c #26AD35", "C. c #23A92F", "Z. c #52C56C", "A. c #D96465", "S. c #D70000", "D. c #D92E2E", "F. c #D80000", "G. c #D74B4B", "H. c #D5E4E4", "J. c #D5D3D5", "K. c #878E87", "L. c #737E73", "P. c #798278", "I. c #6E7F74", "U. c #A57E75", "Y. c #C68175", "T. c #C2796F", "R. c #BD7367", "E. c #D7AFAA", "W. c #886768", "Q. c #380000", "!. c #490909", "~. c #3A0000", "^. c #764D4D", "/. c #DFE3E3", "(. c #B7B7B7", "). c #070707", "_. c #040101", "`. c #800101", "'. c #DD0000", "]. c #CE3435", "[. c #CD1011", "{. c #DE2D2D", "}. c #636565", "|. c #070606", " X c #4C4C4C", ".X c gray89", "XX c #AFAFAF", "oX c gray15", "OX c #868685", "+X c #8F8D8C", "@X c #223232", "#X c #770000", "$X c #DD3434", "%X c #D1CAC9", "&X c #CE9897", "*X c #DF4343", "=X c #5E5959", "-X c #464545", ";X c #989595", ":X c #656262", ">X c #525050", ",X c #E2E2E2", " , < 1 2 3 4 5 6 7 8 9 0 q w ; ", "e r t y u i p a s d f g h j k l ", "z x c v b n m M N B V C Z A S D ", "F G H J K L P I P U Y T R E W Q ", "! ~ ^ / ( ) _ ` ' ] [ { } | ...", "X.o.O.+.@.#.$.%.&.*.=.-.;.:.>.,.", "<.1.2.3.4.5.6.7.8.9.0.q.w.e.r.t.", "y.u.i.p.a.s.d.f.g.h.j.k.l.z.x.c.", "v.b.n.m.M.N.B.V.C.Z.A.S.D.F.G.H.", "J.K.L.P.I.U.Y.T.R.E.W.Q.!.~.^./.", "(.).P _.P `.'.].[.{.}.P |.P X.X", "XXoXOX+X@X#X$X%X&X*X=X-X;X:X>X,X", " c #5D3537", ", c #444444", "< c #4C4C4C", "1 c #4C5353", "2 c #535353", "3 c #715353", "4 c #616161", "5 c gray46", "6 c #7D767E", "7 c #820202", "8 c #9B0202", "9 c #A21A1A", "0 c #C70302", "q c #CB0101", "w c #CC0D0D", "e c #D50101", "r c #DA0101", "t c #CD1414", "y c #CC1B1B", "u c #D61A1A", "i c #CE2626", "p c #CD2D2D", "a c #CE3535", "s c #CE3C3C", "d c #D23436", "f c #D93537", "g c #D33538", "h c #D43D3D", "j c #CF4545", "k c #CF4B4B", "l c #D44242", "z c #D34848", "x c #CF5252", "c c #D35555", "v c #D05B5B", "b c #D06262", "n c #CE7676", "m c #C6767E", "M c #D07070", "N c #DD747D", "B c #D17979", "V c #E2757E", "C c #048E02", "Z c #069105", "A c #0A9106", "S c #0C930B", "D c #10950F", "F c #139713", "G c #1B9617", "H c #169816", "J c #1B991B", "K c #219A1F", "L c #1F9A20", "P c #239B22", "I c #2B9F2B", "U c #2FA02F", "Y c #31A131", "T c #38A337", "R c #3BA43B", "E c #42A642", "W c #41AB47", "Q c #43AC48", "! c #4EAA4E", "~ c #4CAF51", "^ c #57AD57", "/ c #5AAE5A", "( c #65B266", ") c #6AB36A", "_ c #827A82", "` c #808080", "' c gray55", "] c #908E8E", "[ c #939393", "{ c #9D9B9B", "} c #BB9393", "| c #86BF8A", " . c #A7A4A4", ".. c #ABABAB", "X. c #B1B1B1", "o. c #BCBCBC", "O. c #D28484", "+. c #D38C8C", "@. c #D39393", "#. c #D29B9B", "$. c #D99CA1", "%. c #D4A5A4", "&. c #D3A9A9", "*. c #CCBEBE", "=. c #D3B2B2", "-. c #D4BBBB", ";. c #96D1A6", ":. c #99D1A7", ">. c #ADC8AD", ",. c #A6D1A6", "<. c #AAD2AA", "1. c #BDCEBD", "2. c #B4D5BE", "3. c #BFC6C6", "4. c #BFC9C9", "5. c #C3C3C4", "6. c #C2CECE", "7. c #D4C5C5", "8. c #DEC2C9", "9. c #D5CCCC", "0. c #CAD1CA", "q. c #C5D9CE", "w. c #CED9CE", "e. c #DFCFD6", "r. c #C2D0D0", "t. c #CBD0D1", "y. c #C8DAD2", "u. c #D4D4D4", "i. c #DAD6D9", "p. c #D5DBDB", "a. c #DDDBDD", "s. c #DFE0DF", "d. c #D6E2E2", "f. c #DCE2E2", "g. c #D6ECEC", "h. c #D6F6F6", "j. c #D7FAFA", "k. c #E3E3E3", "l. c #F3F3F3", "z. c #F8F8F8", /* pixels */ "u.u.u.u.u.i.u.p.u.p.u.u.u.u.u.i.u.u.u.u.u.u.u.p.u.u.u.u.u.u.p.u.", "u.p.p.u.u.u.u.u.9.u.u.u.u.u.t.u.u.u.u.a.u.u.u.u.u.u.u.u.u.u.u.u.", "u.9.z t u t t y y u 9 O + + + + + + + ' s.o.....X.X.X...X.X.u.u.", "d.&.q q q w t q q e 8 ; u.................X.u.p.", "p.&.q q q +.7.q 0 e 8 ; s.................X.u.u.", "d.&.q i s %.9.j p e 8 * , , , < . * p...................u.u.", "d.&.q v h.u.u.h.#.e 8 o.l.k.k.l.$ $ a.................X.u.u.", "d.&.q t y #.9.i y e 8 # $ # # $ ; a......... .......X.u.u.", "p.&.q w q O.=.q q e 8 . * i.................X.u.u.", "p.=.q q q q 0 q 0 e 8 < s... . . . . . . ...u.u.", "u.u.$.N N N N N N V m 6 6 6 6 6 6 6 _ 5.i.0.6.6.4.r.r.r.4.5.u.u.", "u.i.2.;.:.;.;.:.;.;.;.,.,.,.,.,.,.,.<.u.a.-.+.@.@.@.@.+.&.s.u.i.", "i.1.J A A S D S Z S Z Z S Z S S S Z C ( e.y q q q q q q q &.s.t.", "a.>.S R Y H J P E J J J L E J J H R P W 8.w q q s B w 0 q @.d.u.", "a.>.F P / I H / U H J J H R ^ S T ^ S ~ 8.0 q q M g.w q 0 @.d.u.", "a.>.F G G ^ ( P H J J J J D U ) ~ J S ~ 8.q p &.-.u.=.+.q @.s.u.", "a.>.F H G ^ ( I F J J J J F Y ) ! H S ~ 8.q a =.-.u.=.+.q @.d.u.", "a.>.F L / I H / U H J J H R / S R ^ D ~ 8.0 q q M g.w q q @.d.u.", "a.>.Z T I F H J R H J H H R H H D R J W 8.q q 0 a n w 0 q @.d.9.", "i.t.E H J P P J J J J K P J K K P J G | 8.e r r r r r r r @.d.u.", "u.i.s.w.w.w.w.w.y.w.w.q.q.q.q.q.q.q.y.f.7.7 7 7 7 7 7 7 : } d.u.", "u.u.4 % - * * * = * > f g g g d d d g %.4. [ s.u.", "f... @ e q q q q q q q l 4.. . . . . [ k.u.", "s... @ e 0 q w 9.v q q h 4.. [ k.9.", "s... o $ # # $ + @ e q y a d.B u q h 6. X $ # # $ + [ k.u.", "s... 4 z.k.k.z.{ @ e q 7.g.u.p.h.p d 6. ; z.k.k.l.o. [ f.u.", "s... + , , , , $ @ e q d c p.O.s 0 h 4. o , , , , * [ k.u.", "s... . . @ e 0 q w p.b q q h 4.. . [ f.u.", "a.X. @ e q q q t w q q z 6.X . { a.u.", "u.i.` < 2 2 2 2 2 1 3 c x x c z k x v =.f.] < 2 2 2 2 < 5 u.u.u.", "u.u.k.k.k.k.k.k.k.k.k.d.d.d.d.d.d.d.d.p.u.f.k.k.k.k.k.k.k.u.u.u.", "u.u.t.9.u.u.t.u.9.t.u.u.u.u.u.9.u.u.u.u.u.u.u.0.u.u.u.u.u.u.p.u." }; /* XPM */ static const char *const xpm_icon_2[] = { /* columns rows colors chars-per-pixel */ "48 48 122 2 ", " c #010101", ". c #0B0B0B", "X c #131313", "o c #181818", "O c #3A0101", "+ c #222222", "@ c gray21", "# c #343D3D", "$ c #3D3C3C", "% c #663D3D", "& c #424242", "* c #5B5B5B", "= c #636363", "- c #6D6D6D", "; c gray46", ": c #7B7B7B", "> c #920101", ", c #AB0101", "< c #A53D3D", "1 c #B73D3D", "2 c #CB0101", "3 c #CC0B0B", "4 c #D40101", "5 c #D80101", "6 c #CD1111", "7 c #CD1D1D", "8 c #CE2424", "9 c #CE2B2B", "0 c #CE3333", "q c #CE3D3C", "w c #D63D3D", "e c #CF4343", "r c #CC4846", "t c #CF5252", "y c #CD5959", "u c #D05555", "i c #D05959", "p c #D06464", "a c #D06B6B", "s c #CE7676", "d c #D17474", "f c #D17C7C", "g c #059305", "h c #0D950D", "j c #129712", "k c #169816", "l c #1A991A", "z c #21991E", "x c #239A21", "c c #2A9E2A", "v c #2EA02E", "b c #34A234", "n c #3CA43C", "m c #45A745", "M c #49A748", "N c #4BA94B", "B c #54AB54", "V c #5FAF5F", "C c #64B164", "Z c #69B066", "A c #6BB36B", "S c #72B26F", "D c #75B675", "F c #78B778", "G c #7CB87B", "H c #808080", "J c gray56", "K c #909090", "L c #999799", "P c #9A999A", "I c #AC999B", "U c #8BBD8B", "Y c #A09EA0", "T c #A7A7A7", "R c #AAAAAA", "E c #B4B4B4", "W c #BBBBBB", "Q c #D28282", "! c #D28B8B", "~ c #C5999B", "^ c #C99898", "/ c #D29090", "( c #D69799", ") c #D4999A", "_ c #D9999B", "` c #D59FA0", "' c #D2A2A2", "] c #D3ADAD", "[ c #D4B3B3", "{ c #D4BBBB", "} c #96C196", "| c #B7CBB7", " . c #BDCDBD", ".. c #C2CCBF", "X. c #C5C5C5", "o. c #C9C7C7", "O. c #C2CDC0", "+. c #CBCCCC", "@. c #D4C4C4", "#. c #D6CCCC", "$. c #CFD1CF", "%. c #CBDED7", "&. c #CEDED9", "*. c #D5D4D4", "=. c #D9D2D5", "-. c #D7DED7", ";. c #D8DED7", ":. c #DBD7DB", ">. c #D5DCDC", ",. c #DBDBDB", "<. c #D6E2E2", "1. c #DBE2E3", "2. c #D6ECEC", "3. c #D6F1F1", "4. c #D7FDFD", "5. c #E2E2E2", "6. c #E2EAEA", "7. c #E8E8E8", "8. c #E4E7F1", "9. c #E3F2F2", "0. c #F4F4F4", "q. c white", /* pixels */ "*.*.,.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.;.*.*.*.", "*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.=.*.*.*.*.*.*.*.*.", "*.*.*.*.=.*.*.*.=.*.*.=.*.*.=.*.*.*.*.*.*.$.$.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.=.*.*.*.*.*.*.", "*.*.*.*.>.<.<.<.>.<.<.<.<.<.<.>.<.5.5.5.5.5.5.5.5.5.1.5.1.*.*.:.,.*.,.,.,.*.*.>.,.>.;.>.*.*.*.*.", "*.*.*.>.' e q w q q e q w q q w < # $ $ $ $ $ $ $ $ $ $ - =.*.*.W E E E W E E E E E E E *.*.*.*.", "*.*.*.@.6 2 2 2 2 2 2 2 2 2 2 5 > ; 5.W T R R T T T R T T R R T +.:.*.*.", "*.*.>.[ 2 2 2 2 2 8 8 3 2 2 2 4 > . . * 7.E T R R R R R R R R R R R +.,.*.*.", "*.*.>.[ 2 2 2 2 6 #.>.9 2 2 2 5 > . . * 7.E R R R R R R R R R R R R $.=.*.*.", "*.=.>.[ 2 4 2 2 3 @.>.8 2 2 2 4 > * 7.E T R R R R R R R R R R R $.,.,.*.", ",.*.>.[ 2 2 e f f =.*.Q f u 2 4 > = : ; ; ; ; H @ * 7.E R R R R R R R R R R R R +.*.*.*.", "*.*.>.[ 2 2 ! 4.3.*.*.2.4.] 2 5 > +.q.0.0.0.0.q.- = 7.R T R R R R R R R R R R R $.*.*.*.", "*.*.>.[ 2 2 r f f $.>.Q f y 2 5 > = : ; : ; ; : @ * 7.E T R R R R R R R R T R R +.,.*.*.", "*.*.<.[ 2 2 2 2 3 #.>.8 2 2 2 4 > * 7.E T R R R R R R R R R R R $.=.*.*.", "*.*.>.[ 2 2 4 2 3 #.>.8 2 2 2 4 > . . * 7.E R R R R R R R R R R R T +.,.*.*.", "*.*.>.[ 2 2 2 2 2 8 8 3 2 2 2 5 > * 7.R T R R R R R R R R R R R $.*.*.*.", "*.*.*.*.e 2 2 2 2 2 2 2 2 2 2 4 > . T ,.X.R T R T T R T T R T T T $.*.*.*.", "*.*.*.*.*.' ) ) ) ) ) ) ) ) ) _ ~ P P P P P P P P P P P W ,.*.*.$.+.+.+.+.+.+.+.+.+.X.X.*.*.*.*.", "*.*.*.*.:.&.%.%.&.%.&.%.&.%.%.%.>.-.-.-.-.-.-.-.-.-.-.-.>.*.*.<.=.#.#.#.#.#.#.#.#.#.<.>.*.*.*.*.", "*.*.*.=.G x x x x x x x x x x x x x x x x x x x x x x z m ..,.] 8 3 6 3 3 6 3 3 3 3 i *.*.*.*.*.", "*.*.,...k k h h k l k k k j k k k k k k h k k k k k k k g D 8.r 2 2 2 2 2 2 2 2 2 2 2 ' <.*.*.*.", "*.*.:.| l k n v k l l l l m l l k l k l N k l l l k b n g A 8.q 2 2 2 2 0 a 0 2 2 2 2 ) <.$.*.*.", "*.-.:.| k k n D l k l k A N h l k l l k B C h l j x D b g A 8.0 2 2 2 2 Q 4.f 2 3 2 2 ) <.=.*.*.", "*.*.:.| k l j b D l j A N h l k l l l l h B C h c D c j h C 8.q 2 2 2 2 d 3.s 2 2 2 2 ( <.*.=.*.", "*.*.:.| k l l h b A A m h l l l l k l k l h N A C v j x g C 8.q 2 8 [ [ @.*.@.] [ 8 2 ) <.*.*.*.", "*.*.:.| l l l l h G U k k l l l l l l l k j x } C h l x h A 8.q 2 9 2.2.>.*.>.2.2.8 2 ) <.*.*.*.", "*.*.:.| k l k k A n v D l k k l k l k l j c F x N C j l g C 8.q 2 6 q 0 ! 2.! 0 e 3 2 ) <.*.*.*.", "*.*.>.| k l l A m j k b D x k l l l l k c F c k k B C k h Z 8.q 2 2 2 2 f 4.f 2 2 2 2 ^ <.*.*.*.", "*.*.:.| k j B N j l l h n V k l l l l l C c j l l h B N g Z 2.q 2 2 2 2 p #.p 2 3 2 2 ) <.=.*.*.", "*.*.:. .k k l j k k k k j k k k k k k k k j k k k k j l g S 8.0 2 2 2 2 2 2 2 2 2 2 2 ) <.*.*.*.", "*.*.*.*.G x l x x x x x x x x x x x x x x x x x x x x x M ..<.w 4 4 4 4 4 4 4 4 4 4 4 ) >.=.*.*.", "*.*.*.*.,.>.;.;.;.;.-.-.-.-.>.;.>.%.%.%.%.%.%.%.&.%.%.%.>.=.<.1 , , , , , , , , , , , ^ <.*.*.*.", "*.*.=.,.*.Y P P P P P P P P P P I _ ) ) _ ) ) ) _ ( _ ( { &.5.$ L 5.*.*.*.", "*.*.*.*.& O 5 2 2 2 2 2 2 2 2 2 2 3 ) 6.$ L 5.$.*.*.", "*.*.,.E O 5 2 2 2 2 2 2 2 2 2 2 2 y 9.$ L 5.*.*.*.", "*.=.1.E O 4 2 2 2 2 9 ' f 2 2 3 2 y 6.$ L 1.*.*.*.", "*.*.,.E O 4 2 2 2 2 e 4.{ 2 2 2 2 u 9.$ P 5.*.*.*.", "*.*.,.E X + + + + + + o O 5 2 2 7 7 t <.[ 7 8 6 2 y 9.$ + + + + + + + . L 5.$.*.*.", "*.*.:.E H 7.*.;.,.,.7.P O 5 2 2 { <.>.*.*.,.2.p 2 y 9.$ + ,.,.:.,.,.;.,.+ P 5.*.*.*.", "*.*.;.E ; ,.X.o.o.X.*.J O 5 2 2 ' $.#.*.*.@.*.i 2 y 9.$ + +.+.o.+.o.o.+.+ P 1.*.*.*.", "*.*.,.E . . . . . . . O 5 2 2 3 2 e <.] 3 3 3 2 y 9.$ . . . . . . . X L 5.=.*.*.", "*.*.,.E O 5 2 2 2 2 q 4.{ 2 2 2 2 i 9.$ P 5.$.*.*.", "*.*.;.E O 5 2 2 2 2 8 ! a 2 3 2 2 u 9.@ L 5.*.*.*.", "*.*.*.X.X O 4 2 2 2 2 2 2 2 2 2 2 2 s 9.* E ,.*.*.*.", "*.*.*.,.T & $ $ & $ $ $ $ $ & # % w q w e q w e e q q q a =.,.+.= $ & $ $ & $ $ & $ K ,.*.*.*.*.", "*.*.*.*.:.5.5.5.5.1.5.5.5.,.5.5.1.<.<.<.<.<.<.<.<.>.<.<.<.*.*.>.5.1.5.5.5.5.5.5.5.1.5.*.*.*.*.*.", "*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.=.*.*.=.=.*.$.=.*.*.*.*.*.*.=.$.*.*.*.$.*.*.*.*.*.*.*.*.", "*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.:.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.", "*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.*.,.*.*.*." }; const char *const *const xpm_icons[] = { xpm_icon_0, xpm_icon_1, xpm_icon_2, }; const int n_xpm_icons = 3; puzzles-20170606.272beef/icons/loopy-icon.c0000644000175000017500000004704713115373752017256 0ustar simonsimon/* XPM */ static const char *const xpm_icon_0[] = { /* columns rows colors chars-per-pixel */ "16 16 256 2 ", " c black", ". c #010101", "X c #020202", "o c gray1", "O c #040404", "+ c gray2", "@ c #060606", "# c #070707", "$ c gray3", "% c #090909", "& c gray4", "* c #0B0B0B", "= c #0C0C0C", "- c gray5", "; c #0E0E0E", ": c gray6", "> c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", "X#X:X", "kXjXcXlXDXK.XXMXhXjXhXbX5.3X#X:X", "kXuXiXrXcXV.XXBXjXkXiXuX3XgX(.>X", "eX#.l.b.b.:.#XvXhXuX#.j.z.l.t.0X", "0Xb.CX*XhXnXlXlXcXiXl.BXcXbXcXkX", "qXz.VX@.`.bXdXjXlXyXj.vXjXkXgXjX", "0XM.SX/.aXCXMXNXCXlXz.bXkXlXxXlX", "wX0.XX+XXXQ.(.}.|.~.t.cXgXxX3XyX", "kX5X:X;X>X:X:X>X>X:X0XkXjXlXyXfX" }; /* XPM */ static const char *const xpm_icon_1[] = { /* columns rows colors chars-per-pixel */ "32 32 256 2 ", " c black", ". c #010101", "X c #020202", "o c gray1", "O c #040404", "+ c gray2", "@ c #060606", "# c #070707", "$ c gray3", "% c #090909", "& c gray4", "* c #0B0B0B", "= c #0C0C0C", "- c gray5", "; c #0E0E0E", ": c gray6", "> c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", " c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", " K.UXCXSXSXSXSXSXSXSXSXFXvXjXzXlXlX", "lXlXlXlXyXgXzXlXlXkXAXKXvXkXlXlXlXyXgXzXlXkXmXJXHXvXkXlXzXxX; N.ZXdXhXhXhXhXhXhXhXhXjXuXjXzXlXlX", "lXlXlXzXpXjXlXlXlXbXZ.5.8XbXkXlXzXpXjXlXkXbX&X6.r.8XbXjXzXcX; V.FXhXlXlXlXlXlXlXlXlXzXpXjXzXlXlX", "lXlXlXzXpXjXlXhXSXa.y ! k lXzXkXzXpXjXlXjXVXc.:.N c cXlXlXcX; V.FXhXlXlXlXlXlXlXlXlXzXpXjXzXlXlX", "lXlXlXzXpXjXlXjXSXn 2.lX# +XNXjXzXpXjXlXlXkXxXUX1.h nXkXlXcX; V.FXhXlXlXlXlXlXlXlXlXzXpXjXzXlXlX", "lXlXlXzXpXjXlXjXSXm 1.kX# @XNXjXzXpXjXlXlXjXZXg.v uXMXjXzXcX; V.FXhXlXlXlXlXlXlXlXlXzXpXjXzXlXlX", "lXlXlXzXpXjXlXhXSXh.r U c zXlXkXzXpXjXlXhXAXh. ^ p.aXzXlXcX; V.FXhXlXlXlXlXlXlXlXlXzXpXjXzXlXlX", "lXlXlXzXpXjXlXlXlXnXJ.e.wXbXkXlXzXpXjXlXjXmX/.i.q.i.gXzXlXcX; V.FXhXlXlXlXlXlXlXlXlXzXpXjXzXlXlX", "lXlXlXzXyXhXzXlXlXkXAXJXcXkXlXlXzXyXhXlXlXjXBXGXHXGXlXkXlXxX; V.FXhXlXlXlXlXlXlXlXlXzXuXjXzXlXlX", "lXlXlXxXvXcXkXlXlXlXhXgXkXlXlXkXxXvXvXzXzXzXkXhXhXjXzXzXxXvX: C.DXgXlXlXlXlXlXlXlXkXxXxXjXlXlXlX", "lXlXzXjXU.5XbXlXzXzXzXzXzXzXzXxXlXP.2XbXlXzXzXzXzXzXzXlXxXlX: B.FXjXzXzXzXzXzXzXzXxXkX^.dXxXlXlX", "lXhXZXR. ) bXyXpXpXpXpXpXpXyXvXP. $ - = = = = = = = = - - R vXyXpXpXpXpXpXpXuXvXP., hXxXkXlX", "lXkXbX4XU F.MXgXjXjXjXjXjXjXhXvX3X+ #.Y.Z.S.S.S.S.S.S.S.D.S.R B.MXgXjXjXjXjXjXjXhXvX,Xh pXcXkXlX", "lXlXkXbXnXMXlXzXlXlXlXlXlXlXlXzXbX; Y.UXCXDXDXDXDXDXDXDXDXFXnXMXlXzXzXkXhXhXkXzXlXzXkXZ tXcXkXlX", "lXlXlXlXyXgXzXlXlXlXlXlXlXlXkXzXlX= Z.CXdXhXhXhXhXhXhXhXhXjXyXgXzXlXkXnXJXGXvXkXlXxXdXB yXcXkXlX", "lXlXlXzXpXjXlXlXlXlXlXlXlXlXlXzXzX= S.DXhXlXlXlXlXlXlXlXlXzXpXjXzXkXbX-Xq.u.9XbXjXxXfXB tXcXkXlX", "lXlXlXzXpXjXlXlXlXlXlXlXlXlXlXzXzX= S.DXhXlXlXlXlXlXlXlXlXzXpXjXzXjXVXv.&.M x xXlXzXfXB tXcXkXlX", "lXlXlXzXpXjXlXlXlXlXlXlXlXlXlXzXzX= S.DXhXlXlXlXlXlXlXlXlXzXpXjXzXlXkXzXUX8.s vXlXzXfXB tXcXkXlX", "lXlXlXzXpXjXlXlXlXlXlXlXlXlXlXzXzX= S.DXhXlXlXlXlXlXlXlXlXzXpXjXzXlXjXZXc.z wXNXjXxXfXB tXcXkXlX", "lXlXlXzXpXjXlXlXlXlXlXlXlXlXlXzXzX= S.DXhXlXlXlXlXlXlXlXlXzXpXjXzXhXZXx. ^ s.pXxXzXfXB tXcXkXlX", "lXlXlXzXpXjXlXlXlXlXlXlXlXlXlXzXzX= S.DXhXlXlXlXlXlXlXlXlXzXpXjXzXjXMX^.r.8.e.dXzXzXfXB tXcXkXlX", "lXlXlXzXyXhXlXlXlXlXlXlXlXlXkXzXlX= S.DXhXlXlXlXlXlXlXlXlXzXuXhXlXlXjXBXHXJXHXzXkXzXdXB tXcXkXlX", "lXlXlXxXcXcXlXzXzXzXzXzXzXzXlXxXxX- D.DXhXlXlXlXlXlXlXlXkXzXcXcXlXzXzXkXgXhXhXlXlXxXgXV tXcXkXlX", "lXlXlXkXU.6XmXxXcXcXcXcXcXcXxXvXlX- S.FXjXzXzXzXzXzXzXzXzXzXT.3XmXxXcXcXcXcXcXcXxXbXfXV yXcXkXlX", "lXhXZXY. & : ; ; ; ; ; ; ; ; : : ! bXyXpXpXpXpXpXpXuXcXT. % : ; ; ; ; ; ; ; ; > # 7 fXxXkXlX", "lXjXnX L.UXZXFXFXFXFXFXFXFXDXGXcXjXzXlXlX", "lXkXxXhX& F.CXdXgXcXFXSXzXgXhXgXjXyXgXzXlXlXlXlXlXlXlXkXzXxX; N.ZXsXhXhXhXhXhXhXhXgXjXuXjXzXlXlX", "lXkXxXjX& J.SXgXbX;X7.i.6XvXkXlXzXpXjXlXlXlXlXlXlXlXlXlXzXcX; V.FXhXlXlXlXlXlXlXlXlXzXpXjXzXlXlX", "lXkXxXjX& J.SXfXNXW.u.M x bXlXkXzXpXjXlXlXlXlXlXlXlXlXlXzXcX; V.FXhXlXlXlXlXlXlXlXlXzXpXjXzXlXlX", "lXkXxXjX& J.SXhXkXnX~.c &.CXjXlXzXpXjXlXlXlXlXlXlXlXlXlXzXcX; V.FXhXlXlXlXlXlXlXlXlXzXpXjXzXlXlX", "lXkXxXjX& J.SXhXjXBXW.H A zXlXkXzXpXjXlXlXlXlXlXlXlXlXlXzXcX; V.FXhXlXlXlXlXlXlXlXlXzXpXjXzXlXlX", "lXkXxXjX& J.SXfXBXz.f.R u kXzXkXzXpXjXlXlXlXlXlXlXlXlXlXzXcX; V.FXhXlXlXlXlXlXlXlXlXzXpXjXzXlXlX", "lXkXxXjX& J.SXfXmX`.-.w.7XbXkXlXzXpXjXlXlXlXlXlXlXlXlXlXzXcX; V.FXhXlXlXlXlXlXlXlXlXzXpXjXzXlXlX", "lXkXxXjX& H.SXhXjXBXKXGXvXkXlXkXzXuXhXlXlXlXlXlXlXlXlXkXlXxX; V.FXhXlXlXlXlXlXlXlXlXzXuXjXzXlXlX", "lXkXzXkX= L.FXjXxXlXhXjXlXxXxXzXcXvXvXzXxXxXxXxXxXxXxXzXxXbX> C.DXgXlXlXlXlXlXlXlXkXxXxXjXlXlXlX", "lXkXxXfX$ Z.BXaXfXfXfXfXfXfXfXfXdXP.,XkXdXfXfXfXfXfXfXdXgXfX= m.GXjXzXzXzXzXzXzXzXxXjX^.fXzXlXlX", "lXjXVX).> l Z B B B B B B B B V N , f Z B B B B B B B B V V : o.cXuXpXpXpXpXpXpXuXxX/.i fXxXkXlX", "lXlXzXgXdXpXtXyXtXtXtXtXtXtXyXtXyXhXpXtXyXtXtXtXtXtXtXtXtXyXfXsXjXjXjXjXjXjXjXjXjXjXfXfXzXlXlXlX", "lXlXlXzXxXcXcXcXcXcXcXcXcXcXcXcXcXxXcXcXcXcXcXcXcXcXcXcXcXcXxXxXzXzXzXzXzXzXzXzXzXlXzXxXlXlXlXlX", "lXlXlXlXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXlXlXlXlXlXlXlXlXlXlXlXlXkXlXlXlXlX", "lXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlX" }; const char *const *const xpm_icons[] = { xpm_icon_0, xpm_icon_1, xpm_icon_2, }; const int n_xpm_icons = 3; puzzles-20170606.272beef/icons/lightup-icon.c0000644000175000017500000003563013115373752017563 0ustar simonsimon/* XPM */ static const char *const xpm_icon_0[] = { /* columns rows colors chars-per-pixel */ "16 16 232 2 ", " c #E4E4E4", ". c #D8D8DC", "X c #D7D7DC", "o c #D8D8DC", "O c #D8D8DC", "+ c #D8D8DB", "@ c #D8D8DC", "# c #D8D8DC", "$ c #D8D8DC", "% c #D8D8DB", "& c #D8D8DB", "* c #D8D8DC", "= c #D8D8DC", "- c #D7D7DB", "; c #D9D9DC", ": c gray90", "> c #DEDED2", ", c #E6E62C", "< c #EEEE1C", "1 c #ECEC21", "2 c #EDED1F", "3 c #D5D543", "4 c #EBEB21", "5 c #ECEC20", "6 c #EEEE1D", "7 c #E4E42C", "8 c #D9D93D", "9 c #EFEF1B", "0 c #EBEB23", "q c #F0F016", "w c #D9D94E", "e c #DDDDE9", "r c #DFDFD0", "t c #F7F710", "y c yellow", "u c #FFFF01", "i c #E1E12C", "p c #FEFE01", "a c yellow", "s c #F4F410", "d c #E6E625", "f c #FDFD04", "g c #E5E539", "h c #DBDBEB", "j c #DFDFD0", "k c #F2F211", "l c #FCFC00", "z c #FAFA03", "x c #FBFB01", "c c #DFDF2D", "v c #FDFD04", "b c #FDFD03", "n c #F3F312", "m c #E6E627", "M c #FCFC06", "N c #E4E43B", "B c #DBDBEA", "V c #E0E0D1", "C c #F7F710", "Z c #FFFF01", "A c #E3E32E", "S c #FEFE01", "D c yellow", "F c #F4F410", "G c #E7E725", "H c #FDFD04", "J c #E5E539", "K c #DBDBEB", "L c #D4D4CC", "P c #9A9A20", "I c #9C9C12", "U c #999913", "Y c #999915", "T c #ACAC3A", "R c #E8E82C", "E c #E2E22A", "W c #E5E527", "Q c #DBDB35", "! c #D2D245", "~ c #EAEA20", "^ c #E2E219", "/ c #EAEA19", "( c #D3D356", ") c #DDDDE8", "_ c #C0C0C0", "` c #030305", "' c #010106", "] c #0F0F17", "[ c black", "{ c #68681A", "} c #FFFF0A", "| c #F6F608", " . c #FCFC04", ".. c #EFEF19", "X. c #E4E425", "o. c #E1E11C", "O. c #CFCF80", "+. c #DDDD28", "@. c #E1E137", "#. c #DCDCEC", "$. c #C3C3C3", "%. c #5A5A56", "&. c #A2A29A", "*. c #0D0D19", "=. c #65650F", "-. c #FFFF03", ";. c #FBFB00", ":. c #F8F810", ">. c #D6D622", ",. c #E2E2BD", "<. c white", "1. c #E9E9D5", "2. c #CCCC48", "3. c #E1E1E6", "4. c #C3C3C3", "5. c gray35", "6. c #A2A29E", "7. c #0D0D1D", "8. c #646411", "9. c #FFFF05", "0. c #FBFB02", "q. c #F9F911", "w. c #D0D025", "e. c #E2E2CC", "r. c #EBEBE2", "t. c #C7C74F", "y. c #E1E1E5", "u. c #C0C0C0", "i. c gray1", "p. c #010101", "a. c #0F0F0C", "s. c #696916", "d. c #FFFF02", "f. c #F7F700", "g. c #FEFE00", "h. c #F1F112", "j. c #E8E822", "k. c #EAEA2E", "l. c #E2E2A6", "z. c #E8E83E", "x. c #E4E435", "c. c #DCDCED", "v. c LightGray", "b. c #8E8E8E", "n. c #909090", "m. c #8E8E8D", "M. c #8B8B8E", "N. c #A2A291", "B. c #DBDBA5", "V. c #D5D5A3", "C. c #D7D7A3", "Z. c #D4D4A6", "A. c #5A5A34", "S. c #454505", "D. c #434303", "F. c #444400", "G. c #5D5D3A", "H. c #E1E1E4", "J. c gray88", "K. c #EFEFEF", "L. c gray96", "P. c gray95", "I. c #F7F7F6", "U. c #D7D7DB", "Y. c #E5E5F1", "T. c #E7E7F2", "R. c #E8E8F3", "E. c #E7E7F2", "W. c #252526", "Q. c #040405", "!. c #262625", "~. c #E4E4E4", "^. c #DADADA", "/. c gray93", "(. c #888888", "). c gray19", "_. c gray93", "`. c #CDCDCC", "'. c #E5E5E2", "]. c #E5E5E3", "[. c #E6E6E3", "{. c #E5E5E3", "}. c #292927", "|. c #080805", " X c #292927", ".X c #E4E4E4", "XX c #DDDDDD", "oX c #E6E6E6", "OX c #CECECE", "+X c #B2B2B2", "@X c gray92", "#X c #D0D0D0", "$X c #E7E7E7", "%X c #E7E7E7", "&X c gray91", "*X c #E7E7E7", "=X c #252525", "-X c #040404", ";X c #252525", ":X c #E4E4E4", ">X c gray87", ",X c #D8D8D8", " , < 1 2 3 4 5 6 7 8 9 0 q w e ", "r t y u y i p a y s d y f y g h ", "j k l z x c v b y n m y M y N B ", "V C y Z y A S D y F G y H y J K ", "L P I U Y T R E W Q ! ~ ^ / ( ) ", "_ ` ' ] [ { } | ...X.o.O.+.@.#.", "$.[ %.&.*.=.-.;.y :.>.,.<.1.2.3.", "4.[ 5.6.7.8.9.0.y q.w.e.<.r.t.y.", "u.i.p.a.[ s.d.f.g.h.j.k.l.z.x.c.", "v.b.n.m.M.N.B.V.C.Z.A.S.D.F.G.H.", "J.K.L.P.I.U.Y.T.R.E.W.[ Q.[ !.~.", "^./.(.)._.`.'.].[.{.}.[ |.[ X.X", "XXoXOX+X@X#X$X%X&X*X=X[ -X[ ;X:X", ">X,X c #4C4C4C", ", c #5B5B5B", "< c #676767", "1 c gray43", "2 c #7E7E7E", "3 c #BFBF1F", "4 c #878725", "5 c #88882F", "6 c #929223", "7 c #92922E", "8 c #8A8A31", "9 c #BDBD2A", "0 c #ACAC32", "q c #C6C60B", "w c #D3D300", "e c #DBDB00", "r c #DFDF08", "t c #C3C310", "y c #E1E100", "u c #EDED00", "i c #F1F100", "p c #FFFF01", "a c #F5F50D", "s c #FEFE0D", "d c #EDED1B", "f c #F4F410", "g c #FFFF11", "h c #F4F418", "j c #CDCD26", "k c #CCCC28", "l c #DEDE26", "z c #DBDB2E", "x c #CACA33", "c c #D2D235", "v c #DDDD30", "b c #D7D73C", "n c #D8D83C", "m c #E0E030", "M c #E2E23B", "N c #8A8A5E", "B c #8B8B66", "V c #ACAC61", "C c #ADAD6F", "Z c #B5B564", "A c #B4B475", "S c #C5C54D", "D c #CACA4C", "F c #D2D246", "G c #C6C654", "H c #C9C953", "J c #C4C459", "K c #CFCF5A", "L c #D2D253", "P c #C6C665", "I c #CECE66", "U c #C5C569", "Y c #CACA68", "T c #D0D064", "R c #C6C671", "E c #8B8B8B", "W c #979797", "Q c #B2B283", "! c #B0B089", "~ c #B2B291", "^ c gray64", "/ c #ABABAB", "( c #B1B1A5", ") c #B6B6AD", "_ c #B9B9B9", "` c gray76", "' c #C9C9C7", "] c #C3C3CF", "[ c #CCCCCC", "{ c #D7D7CC", "} c #D9D9CF", "| c #C7C7D4", " . c #CCCCD3", ".. c #CCCCDC", "X. c #D4D4D4", "o. c #D6D6DE", "O. c #DDDDDD", "+. c #DCDCED", "@. c #DADAF0", "#. c #E5E5E5", "$. c #E9E9E4", "%. c #E2E2E9", "&. c #EBEBEA", "*. c #F1F1ED", "=. c #E4E4F5", "-. c #ECECFF", ";. c #F2F2F3", ":. c #F7F7FF", ">. c #FEFEFD", /* pixels */ "#.#.&.&.&.&.$.*.&.&.&.&.&.&.&.&.&.&.&.$.&.&.&.&.&.*.&.&.&.&.#.#.", "#.#........... .......X...............X. ......... .......X.#.#.", "&.{ x z z z z z z l S G l z z z z z z c Z z v z z z z v l A +.$.", "&.{ a p p p p p p p m n p p p p p p p a G p p p p p p p p P +.$.", "&.{ a p p p p p p p v F p p p p p p p f H p p p p p p p p P +.$.", "&.{ a p p p p p p p v n p p p p p p p a H p p p p p p p p P +.$.", "&.{ i p p p p p p p v b p p p p p p p a H p p p p p p p p P +.$.", "&.{ a p p p p p p p v b p p p p p p p a G p p p p p p p p P +.$.", "&.{ a p p p p p p p v b p p p p p p p a G p p p p p p p p P +.&.", "=.{ u p p p p p p p z b p p p p p p p a H p p p p p p p p P +.$.", "&.} h s g g s s g p M F p f a a a f a d J a f f f f f f a U +.$.", ";._ # - % - - % % % * Z H G H G H H H J A D G H L L K G D A +.$.", ";./ . j p p p p p p p a G p p p e w u p p P +.$.", ";./ X + X o j p p p p p p p a G p e V .o.~ q p P +.$.", ";./ E [ ^ o j p p p p p p p a H p V :.>.>.>.) y I +.$.", ";./ + O.O X.: o j p p p p p p p a L w ' >.>.>.>.-.9 K +.$.", ";./ O #.O X.: o j p p p p p p p a L w .>.>.>.>.-.9 K @.&.", ";./ E [ ^ o j p p p p p p p a K i ! >.>.>.>.| w T +.$.", ";./ X X $ X o k p p p p p p p f G p q ( -.-.| 0 p P +.$.", ";./ o k p p p p p p p a H p p u j x y p p P +.$.", ";._ & = = = ; = = = ; A P U U U U U P U N 4 5 7 6 6 7 8 4 B %.$.", "&.X.#.;.&.&.&.*.&.;.X.] =.+.+.+.+.@.+.=.: X = &.#.", "&.X.o.&.#.#.#.#.#.&.[ ' &.$.$.&.&.$.#.*.: = &.#.", "&.X.O.&.#.&.#.&.#.&. .' &.$.#.#.#.&.#.&.: X = &.#.", "&.X.O.#.&., O 2 ;.&. .' &.%.#.#.#.#.%.*.: = &.#.", "&.X.O.#.;.= < ;.#.{ ' &.%.&.#.#.%.$.;.; X = &.#.", "&.X.O.#.&.W 1 / &.&.[ ' &.#.#.#.#.#.#.&.: = &.%.", "&.X.O.&.#.;.>.&.$.&. .' &.#.#.#.#.#.#.&.: = &.$.", "&.X.+.&.&.#.#.%.&.&.X.' &.#.&.&.&.&.#.;.- . X = &.#.", "&.X.' X.X.X.X.{ X.X.` ` o.X.X.X.X.X.X.O.> X O O O O O O X : &.#.", "&.$.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.&.#.", "$.#.&.#.&.&.#.&.&.&.&.&.&.&.#.&.#.&.#.&.&.#.$.&.&.&.&.&.&.&.#.#." }; /* XPM */ static const char *const xpm_icon_2[] = { /* columns rows colors chars-per-pixel */ "48 48 112 2 ", " c #010101", ". c #0C0C0C", "X c #050518", "o c #151515", "O c #1E1E1E", "+ c #20201F", "@ c #242424", "# c gray16", "$ c #33332A", "% c #3E3E34", "& c #3D3D3D", "* c gray20", "= c #404036", "- c #43433F", "; c #6D6D38", ": c #74743E", "> c #414142", ", c #767641", "< c #7C7C43", "1 c #75755E", "2 c #616161", "3 c #767676", "4 c #9E9E12", "5 c #A6A60E", "6 c #B5B506", "7 c #BBBB02", "8 c #B3B309", "9 c #A2A215", "0 c #9E9E27", "q c #9B9B28", "w c #9A9A30", "e c #C4C400", "r c #CDCD00", "t c #D7D700", "y c #E4E400", "u c #ECEC00", "i c #F5F502", "p c #FEFE01", "a c #FAFA0A", "s c #EBEB14", "d c #F2F214", "f c #FFFF13", "g c #FFFF18", "h c #D3D334", "j c #D9D939", "k c #E2E22C", "l c #EDED2A", "z c #8A8A4E", "x c #919144", "c c #969648", "v c #8A8A57", "b c #969652", "n c #999953", "m c #9B9B5F", "M c #BEBE4F", "N c #B7B755", "B c #8A8A65", "V c #AEAE6E", "C c #B6B663", "Z c #BBBB65", "A c #BABA69", "S c #AEAE71", "D c #A7A77B", "F c #ADAD7B", "G c #B2B272", "H c #B2B27B", "J c #C6C64C", "K c #C9C94F", "L c #D1D146", "P c #C2C250", "I c #CACA50", "U c #CFCF5F", "Y c #C0C06B", "T c #838383", "R c #8E8E87", "E c #8E8E8E", "W c #9E9E85", "Q c #9E9E9D", "! c #A6A685", "~ c #AEAE85", "^ c #A6A69B", "/ c #ADAD9A", "( c #B1B19D", ") c #A6A6A6", "_ c #A5A5A9", "` c gray66", "' c #ACACB5", "] c #B6B6B6", "[ c #BDBDBD", "{ c #BDBDC5", "} c #C6C6C5", "| c #C4C4CF", " . c #CACACA", ".. c #D0D0CF", "X. c #CECED4", "o. c #C9C9DD", "O. c #D3D3D3", "+. c #D3D3DD", "@. c #DBDBDB", "#. c #D3D3E7", "$. c #DBDBE7", "%. c #DDDDEA", "&. c #E5E5E5", "*. c #E9E9E6", "=. c #E5E5EA", "-. c #EBEBEA", ";. c #F0F0ED", ":. c #E2E2F3", ">. c #EAEAFB", ",. c #F3F3F3", "<. c #F4F4FF", "1. c #FEFEFE", /* pixels */ "&.&.&.&.&.&.&.*.&.&.*.&.&.&.&.&.&.&.&.&.&.&.*.&.&.&.&.&.&.&.&.&.&.&.*.&.&.&.&.&.&.&.&.&.&.&.&.&.", "&.&.&.&.&.&.&.&.&.&.&.&.&.&.&.&.&.&.&.&.&.&.&.&.&.&.&.*.&.&.&.&.&.&.&.&.&.&.&.*.&.&.&.&.=.*.&.&.", "&.*.=.*.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.*.-.-.-.-.-.-.-.-.*.-.*.-.&.&.&.&.", "*.*.&.$.X.o.o.o.o.o.o.o.o.o.X.o.X.X.o.o.o.o.o.o.o.o.o.o.o.X.O.o.o.o.o.o.o.o.o.o.X.o.o.O.&.&.&.=.", "*.&.-. .N J P P J P P P P J J J S V J P J M J P P P J P J C D J P P P P P P P P P P M ^ *.&.*.*.", "*.*.-.O.s p p p p p p p p p a p I L p p p p p p p p p p p k Z p p p p p p p p p p p p / =.&.&.&.", "=.&.-.X.s p a p p a p p p a p p I L p a a p p a p a p a p k Z p p p p p p a p p a p i / =.&.&.&.", "&.&.-.X.s p p p p p p p p p a p I L p p p p p p p p p p p k Z p a p p p p p p p p p a / =.&.&.&.", "&.&.-.X.s p p p p p p p p p p p I L p p p p p p p p p p p k Z p p p p p p p p p p p a / =.&.*.&.", "&.&.-.X.s p p p p p p p p p p p I L p p p p p p p p p p p k Z p a p p p p p p p p p p / =.&.=.&.", "&.&.-.X.s p p p p p p p p p p p I L p p p p p p p p p p p k Z p p p p p p p p p p p i / =.&.&.&.", "&.&.-.X.s p p p p p p p p p a p I L p p p p p p p p p p p k Z p p p p p p p p p p p i / *.&.&.&.", "&.&.-.X.s p p p p p p p p p p p I L p p p p p p p p p p p k Z p p p p p p p p p p p p / =.&.&.&.", "&.&.-.X.s p p p p p p p p p p p I L p p p p p p p p p p p k Z p p p p p p p p p p p i / *.&.*.=.", "&.&.-.O.s p p p p p p p p p p p K L p p p p p p p p p p p k Z p a p p p p p p p p p i / =.&.=.*.", "&.&.-.X.s p p p p p p p p p a p K K p p p p p p p p p p p k Z p p p p p p p p p p p a / =.&.&.&.", "&.&.-.O.l f g g g g g g g g g a U K a d d d d d d d d d a j A a s d d d d d d d d d s / =.=.&.&.", "&.&.,.] $ = % % % % % = % % % % - D G G G G G G G G G G G F ! G G G G G S G G G G G G ) *.&.&.&.", "&.&.,.` X h p p p p p p p p p p p k Z p a p p p p p p p p p p / =.&.&.&.", "&.&.,.` X h p p p p p p p p p p p k Z p p p i 6 0 0 8 u p p i / *.&.-.&.", "&.&.;._ X h p p p p p p p p p p p k Z p a t z | >.>.X.v r p p / =.&.&.&.", "&.&.,._ . . ) &.] O X h p p p p p p p p p p p k Z p u v <.1.1.1.1.<.B y a / =.&.&.&.", "&.&.,._ 3 1.> @.] X h p p p p p p p p p p p k Z p 5 o.1.1.1.1.1.1.#.9 p / =.&.&.&.", "&.&.,.) .} E ,. X h p p p p p p p p p p p k Z p c <.1.1.1.1.1.1.1.n i / =.&.&.&.", "&.&.,._ . . E -. X h p p p p p p p p p p p k A p b 1.1.1.1.1.1.1.1.m i ( *.&.&.&.", "&.&.,.) 3 1.> @.] X h p p p p p p p p p p p k Z p q :.1.1.1.1.1.1.>.q p / =.&.&.&.", "&.@.,.) . Q &.] + X h p p p p p p p p p p p k Z p r Q 1.1.1.1.1.1._ e a / =.=.&.&.", "&.&.,.) X h p p p p p p p p p p p k Z p p 5 _ <.1.1.1.' 4 p i / =.&.=.*.", "&.&.,._ . . X h p a p p p p p p p p p k Z p p p 7 w W W x 6 p p i / =.&.&.*.", "&.&.,._ X h p p p p p p p p p a p k Y p a a a p i i p a a p a ( =.&.&.&.", "&.&.,.] * & & & > & & > & & & & > ! H H H H H H H H H H G ~ 1 : , : : , < < , : : , ; R -.&.&.&.", "&.&.-.O.@.,.-.-.-.-.-.-.-.-.-.,.} { =.$.$.$.$.$.$.$.$.$.%.+.O 2 ,.&.&.&.", "&.&.*. .O.-.&.&.&.&.&.&.&.&.$.-.[ { -.*.*.*.-.*.*.*.*.*.-.@.+ . 2 ,.&.&.&.", "&.&.-.O.O.-.&.*.&.&.&.&.&.&.&.-.[ } -.&.&.&.&.*.&.&.&.&.*.@.+ 2 ,.&.&.&.", "*.&.-.O.O.-.*.&.*.<.,.,.*.&.&.-.[ } -.&.&.&.&.&.&.&.&.&.*.@.O 2 ,.&.&.&.", "*.*.-. .O.-.&.-.} T R E &.-.&.-.[ } -.&.*.&.&.&.&.&.&.&.-.@.O 2 ,.&.&.*.", "=.&.-.O.O.-.$.,.Q . O.-.&.-.[ } -.&.*.*.&.&.*.*.&.&.-.@.O 2 ,.&.&.&.", "&.&.-.O.O.-.&.,.Q . @.-.&.-.[ } -.&.=.&.&.&.=.*.&.&.*.@.O 2 ;.&.&.&.", "&.&.-. .O.-.&.,.` o O @ @.*.&.-.[ } -.&.&.&.&.&.&.&.&.&.=.@.+ 2 ;.&.&.&.", "&.&.-.X.@.-.&.&.&.&.=.*.&.&.=.;.{ } -.&.&.&.=.*.&.&.&.&.-.@.+ 2 ,.&.&.&.", "*.&.-. .O.-.&.&.*.*.*.=.&.&.&.-.[ } -.&.&.&.&.*.&.&.&.&.-.@.O 2 ,.&.&.&.", "*.*.-.O.O.*.&.&.&.&.=.*.&.&.&.-.[ } -.&.&.&.&.&.&.&.&.=.*.@.O 2 ,.&.&.&.", "=.&.-...@.-.-.-.*.*.*.-.*.-.*.,.[ } ,.&.&.-.-.-.*.=.-.*.-.@.O 2 ,.&.&.&.", "&.&.-.O.{ .} .| } } } } .} | ] ] .} } } } } } .} } .} & O @ @ @ @ @ @ @ @ # # o 3 ;.&.&.&.", "&.&.&.*.&.$.&.@.@.&.$.&.&.$.&.@.&.&.$.&.@.&.&.$.&.&.@.&.$.&.*.*.-.*.=.-.*.*.-.*.*.*.*.*.*.&.&.&.", "&.&.&.=.*.*.&.&.*.*.&.&.&.&.*.*.*.&.&.&.*.&.&.*.&.&.&.&.=.*.&.&.*.*.=.*.&.&.*.=.=.=.*.&.=.&.&.&.", "*.&.&.&.&.*.&.&.&.&.=.&.*.&.&.&.&.&.*.&.&.&.&.&.&.=.&.&.&.*.&.&.&.=.&.&.&.&.&.&.=.&.*.=.&.&.*.*.", "*.&.&.&.&.&.*.&.&.&.*.*.&.&.&.&.=.*.*.&.*.&.&.&.&.*.*.&.&.&.&.=.&.*.&.&.=.*.*.&.&.&.&.&.&.&.&.=." }; const char *const *const xpm_icons[] = { xpm_icon_0, xpm_icon_1, xpm_icon_2, }; const int n_xpm_icons = 3; puzzles-20170606.272beef/icons/keen-icon.c0000644000175000017500000003362513115373752017033 0ustar simonsimon/* XPM */ static const char *const xpm_icon_0[] = { /* columns rows colors chars-per-pixel */ "16 16 241 2 ", " c gray2", ". c #202020", "X c #272727", "o c #272727", "O c gray13", "+ c gray13", "@ c gray14", "# c #161616", "$ c gray10", "% c #272727", "& c gray16", "* c gray13", "= c gray13", "- c #232323", "; c #1E1E1E", ": c #010101", "> c #2A2A2A", ", c #979797", "< c #A9A9A9", "1 c #D0D0D0", "2 c gray88", "3 c gainsboro", "4 c gray92", "5 c #9A9A9A", "6 c #868686", "7 c #9D9D9D", "8 c #B5B4B5", "9 c #E6E2E6", "0 c gray87", "q c #E6E6E6", "w c #C6C6C6", "e c gray4", "r c gray16", "t c gray65", "y c gray75", "u c #D8D8D8", "i c #E9E9E9", "p c gray90", "a c #F4F4F4", "s c #9F9F9F", "d c gray56", "f c #BBBBBB", "g c #C6CAC6", "h c #CBDCCB", "j c #E8E7E8", "k c #EFEFEF", "l c #CECECE", "z c gray4", "x c gray13", "c c gray90", "v c #EEEEEE", "b c #E9E9E9", "n c gray90", "m c gray89", "M c #F3F3F3", "N c #959595", "B c #BFC0BF", "V c #FBF8FB", "C c #D7E2D7", "Z c #68B368", "A c #73B773", "S c #FAF2FA", "D c #C9CBC9", "F c gray4", "G c #222222", "H c gray87", "J c #E7E7E7", "K c gray90", "L c #E6E6E6", "P c gray89", "I c #F4F4F4", "U c gray59", "Y c #BABBBA", "T c #EEEEEE", "R c #E6E4E6", "E c #74B874", "W c #94C494", "Q c #F8F1F8", "! c #CACBCA", "~ c gray4", "^ c #222222", "/ c gray87", "( c #E7E7E7", ") c #E4E4E4", "_ c gray90", "` c #E2E2E2", "' c #F3F3F3", "] c #959595", "[ c #B8B9B8", "{ c #F5F0F5", "} c #BCD3BC", "| c #42A342", " . c #A4C9A4", ".. c #EFECEF", "X. c #C8C9C8", "o. c gray4", "O. c #222222", "+. c #E4E4E4", "@. c gray93", "#. c gray92", "$. c gray92", "%. c gray91", "&. c #F9F9F9", "*. c gray60", "=. c gray78", "-. c #FBFCFB", ";. c #F3F2F3", ":. c #FDF7FD", ">. c #F3F2F3", ",. c #FBFBFB", "<. c gray85", "1. c #0B0B0B", "2. c #1E1E1E", "3. c #C5C5C5", "4. c #CDCDCD", "5. c #CACACA", "6. c #CBCBCB", "7. c #C8C8C8", "8. c #D7D7D7", "9. c gray51", "0. c gray49", "q. c #A9A9A9", "w. c #9C9D9C", "e. c #9C9D9C", "r. c #959595", "t. c #9A9A9A", "y. c #848484", "u. c #060606", "i. c #202020", "p. c #D2D2D2", "a. c #DADADA", "s. c #D8D8D8", "d. c #D8D8D8", "f. c #D5D5D5", "g. c #E4E4E4", "h. c #939393", "j. c #6F6F6F", "k. c gray40", "l. c gray46", "z. c #949394", "x. c gray71", "c. c #C6C7C6", "v. c #929192", "b. c black", "n. c #222222", "m. c gray89", "M. c gray92", "N. c #E9E9E9", "B. c #E9E9E9", "V. c #E7E7E7", "C. c #F6F6F6", "Z. c #A0A0A0", "A. c gray57", "S. c #898A89", "D. c #9F9E9F", "F. c #AEADAE", "G. c #E0E3E0", "H. c #FEFEFE", "J. c gray73", "K. c #222222", "L. c #DFDFDF", "P. c gray91", "I. c gray90", "U. c #E6E6E6", "Y. c gray89", "T. c #F4F4F4", "R. c gray58", "E. c #C0C1C0", "W. c #FFFDFF", "Q. c #C4DBC4", "!. c #36A436", "~. c #A8CBA8", "^. c #FAF4FA", "/. c #AFB0AF", "(. c #222222", "). c #DFDFDF", "_. c gray91", "`. c gray90", "'. c #E6E6E6", "]. c gray89", "[. c gray59", "{. c #B9BAB9", "}. c #F3F0F3", "|. c #D0DCD0", " X c #69B369", ".X c #64B064", "XX c #FDF6FD", "oX c #B0B1B0", "OX c #DDDDDD", "+X c #E6E6E6", "@X c gray89", "#X c #E4E4E4", "$X c #E1E1E1", "%X c #F1F1F1", "&X c gray58", "*X c gray73", "=X c #F3F0F3", "-X c #CDDACD", ";X c #6FB56F", ":X c #81BB81", ">X c #FAF4FA", ",X c #AFB1AF", " , < 1 2 3 4 5 6 7 8 9 0 q w e ", "r t y u i p a s d f g h j k l z ", "x c v b n m M N B V C Z A S D F ", "G H J K L P I U Y T R E W Q ! ~ ", "^ / ( ) _ ` ' ] [ { } | ...X.o.", "O.+.@.#.$.%.&.*.=.-.;.:.>.,.<.1.", "2.3.4.5.6.7.8.9.0.q.w.e.r.t.y.u.", "i.p.a.s.d.f.g.h.j.k.l.z.x.c.v.b.", "n.m.M.N.B.V.C.Z.A.S.D.F.G.H.J.b.", "K.L.P.I.U.Y.T.R.E.W.Q.!.~.^./.b.", "(.)._.`.'.].I [.{.}.|. X.XXXoXb.", "+ OX+X@X#X$X%X&X*X=X-X;X:X>X,Xb.", " c gray19", ", c #313131", "< c #323232", "1 c gray20", "2 c #343434", "3 c gray21", "4 c #373737", "5 c gray22", "6 c #393939", "7 c #3A3A3A", "8 c #3C3C3C", "9 c gray24", "0 c #3E3E3E", "q c #007900", "w c gray25", "e c #414141", "r c gray27", "t c #505050", "y c gray32", "u c #535553", "i c #5A5A5A", "p c #5D5D5D", "a c gray37", "s c #5F5F5F", "d c gray38", "f c #6D6D6D", "g c #717371", "h c #727272", "j c #767676", "k c #7B7B7B", "l c #7C7C7C", "z c #008000", "x c #008500", "c c #008700", "v c #098609", "b c #149214", "n c #1B951B", "m c #1D941D", "M c #239823", "N c #299A29", "B c #2B9B2B", "V c #339E33", "C c #389F38", "Z c #36A036", "A c #3FA33F", "S c #40A440", "D c #47A647", "F c #4BA94B", "G c #4CAB4C", "H c #53AB53", "J c #50AD50", "K c #67B367", "L c #6EB56E", "P c #7DBC7D", "I c #7EBC7E", "U c #7FBC7F", "Y c #838383", "T c gray53", "R c #888988", "E c gray54", "W c #8B8B8B", "Q c gray55", "! c #8D8D8D", "~ c #8D8E8D", "^ c #8E8E8E", "/ c gray57", "( c #929292", ") c #939393", "_ c #959595", "` c gray60", "' c #9B9B9B", "] c gray62", "[ c #81BE81", "{ c #83BE83", "} c #84BD84", "| c #A0A0A0", " . c #A4A4A4", ".. c #A5A5A5", "X. c gray65", "o. c #A9A9A9", "O. c gray67", "+. c #ACACAC", "@. c #AEAEAE", "#. c #AFAFAF", "$. c gray69", "%. c #B1B1B1", "&. c #B2B2B2", "*. c gray70", "=. c #B4B4B4", "-. c gray71", ";. c #B7B7B7", ":. c #B9B9B9", ">. c gray73", ",. c #BBBBBB", "<. c gray", "1. c gray75", "2. c #88C188", "3. c #8AC18A", "4. c #8BC18B", "5. c #8EC38E", "6. c #94C594", "7. c #97C497", "8. c #9EC99E", "9. c #A2CBA2", "0. c #AACEAA", "q. c #AECDAE", "w. c #AFD0AF", "e. c #B4D2B4", "r. c #B7D3B7", "t. c #B9D4B9", "y. c #BAD7BA", "u. c #C0C0C0", "i. c gray76", "p. c #C3C3C3", "a. c gray77", "s. c #C4C5C4", "d. c #C6C6C6", "f. c gray78", "g. c #C8C8C8", "h. c gray79", "j. c #CACACA", "k. c gray81", "l. c #C7DAC7", "z. c #C8DAC8", "x. c gray82", "c. c LightGray", "v. c gray83", "b. c gray84", "n. c #D7D7D7", "m. c #D2DED2", "M. c #D3DED3", "N. c #D8D6D8", "B. c #DED4DE", "V. c #D8D8D8", "C. c #DFDFDF", "Z. c #DAE1DA", "A. c #DBE2DB", "S. c #DFE1DF", "D. c #DEE3DE", "F. c #DFE3DF", "G. c #E0D6E0", "H. c gray88", "J. c #E1E1E1", "K. c #E0E3E0", "L. c #E1E2E1", "P. c #E1E3E1", "I. c #E2E2E2", "U. c #E2E3E2", "Y. c gray89", "T. c #E1E4E1", "R. c #E2E4E2", "E. c #E2E5E2", "W. c #E3E4E3", "Q. c #E3E5E3", "!. c #E4E4E4", "~. c #E4E5E4", "^. c #E5E4E5", "/. c gray90", "(. c #E4E6E4", "). c #E5E6E5", "_. c #E6E6E6", "`. c #E7E7E7", "'. c #EBE2EB", "]. c #E8E7E8", "[. c #E9E7E9", "{. c #EAE7EA", "}. c gray91", "|. c #E8E9E8", " X c #E9E9E9", ".X c #EAE8EA", "XX c #EAE9EA", "oX c #EBE8EB", "OX c #EAEAEA", "+X c #EAEBEA", "@X c gray92", "#X c #EBECEB", "$X c #ECE8EC", "%X c #ECE9EC", "&X c #EDE9ED", "*X c #EDEBED", "=X c #EEE9EE", "-X c #EFE9EF", ";X c #EFEAEF", ":X c #ECECEC", ">X c gray93", ",X c #EEEEEE", " > > > > 2 > 1 @ * 8 8 > 5 > > > > > > > > ; ", " 6 V.j >.hXhXeX,X,X,X6XeX,XdX8 -.` ^ dXv. eXl Y s.' j. X!.~.!.!.J.6X5 -.u.i u.s | XJ.~.~.~.!.,Xj. ", " 6 p.= %.s.+.k.*X!.~.].].!.eX6 -.t h S.Q s.*X].~.~.~.!.,Xj. ", " 2 J.1.k.eXeX*X~.].].~.~.!.eX6 +.x.p.`. X6XZ.m.*X*X~.!.*Xj.O ", " > eX,X*X~.~.~.].~.].~.].!.eX5 -.dX,XQ.7X4.n b D S.].!.,Xj.O ", " > ,X!.~.~.].~.~.].~.].~.!.eX5 %.eXJ.~.*Xr.l.r.q q.4XQ.,Xj. ", " > eX~.~.].~.].~.].~.].~.!.eX5 *.rX~.].Q.4XpXL m A. X~.,Xj. ", " > 6X~.].~.].~.].~.].~.].~.eX5 %.eX~.~.~. XK N Q.6X~.~.,Xj.O ", " > eX!.~.].~.].~.].~.].~.~.eX5 *.eX!.J.7X[ q Z A w.4XJ.,Xj. ", " > ,X!.].~.].~.].~.].~.~.!.eX5 *.rX!.!.*Xt.5.4.I z. XQ.,Xj.O ", " > ,X~.~.].~.].~.].~.].~.~.eX5 %.eX~.].~.*XqX7XqX&X~.~.,Xj. ", " > ,XJ.!.!.~.~.!.~.~.~.!.!.eX6 %.eXJ.!.~.Q.J.J.J.!.~.J. Xj.O ", " 3 uX,X,X6X,X ", " > J.b.V.V.V.V.V.V.V.V.V.b.J.3 ^ +.R o.j #.>.>.#.&.%.#.t.f O ", " > eX]. X X X*X*X X X*X X XuX6 u.Q s ^ p | &.| XtXtX ,X!.~.~.].~.~.~.].~.~.~.6X8 ` y 9 p d ^ g u (.~.!.G.rXQ O ", " > eX~.~.].~.].~. X~.].~.~.eX6 -.!.+.j.R V.B.B.]. X~.!.uX^ O ", " 2 6X~.].~.].~.].~.].~.~.~.eX6 %.uX6X#XgXy.G H F m.*XJ.uX^ O ", " > 6X~.~.].~.].~.].~.].~.~.eX6 *.eXJ.J.4X7.v H P Q.].J.uX^ O ", " > ,X~.~.].~.].~.].~.].`.Q.eX5 *.eX!.].~.~.7XJ.x [ 7XS.uX^ O ", " > 6X~.~. X~.].].~.].~.].!. ,XJ.!.J.J.!.!.J.!.J.!.G.,X5 %.6XJ.~.~.J.Q.J.J.~.~.J.eX^ O ", " 3 hXuXuXuXuXuXuXuXuXuXuXuXhX8 >.dX*X,X,X X,X,X,X,X,X XhX/ O ", " # / ^ Q ^ Q ^ ^ ^ ^ W ^ W _ % | x.s.j.j.k.j.j.j.j.j.j.V.l O ", " O O O O O O O O ", " O O O O O O O O O O O O O " }; /* XPM */ static const char *const xpm_icon_2[] = { /* columns rows colors chars-per-pixel */ "48 48 73 1 ", " c #010101", ". c gray3", "X c #131313", "o c #1B1B1B", "O c #252525", "+ c #2B2B2B", "@ c #333333", "# c #3E3E3E", "$ c #007E00", "% c #434343", "& c gray30", "* c #545454", "= c #5D5D5D", "- c #626262", "; c #6C6C6C", ": c #707270", "> c #7B7B7B", ", c #008400", "< c #028A02", "1 c #0B8E0B", "2 c #138E13", "3 c #149114", "4 c #199219", "5 c #218F21", "6 c #209720", "7 c #259825", "8 c #2D9B2D", "9 c #3AA13A", "0 c #42A442", "q c #49A749", "w c #4DA84D", "e c #54AB54", "r c #5AAE5A", "t c #60B060", "y c #69B569", "u c #71B771", "i c #76B976", "p c #838383", "a c #8A8A8A", "s c #929292", "d c #9B9C9B", "f c #82BE82", "g c #A4A4A4", "h c #ACACAC", "j c #B5B5B5", "k c #BABABA", "l c #86C086", "z c #8AC18A", "x c #95C695", "c c #9AC79A", "v c #A7CDA7", "b c #ACCFAC", "n c #B7D3B7", "m c #B9D5B9", "M c #C7C7C7", "N c #CCCCCC", "B c #C0D7C0", "V c #C4D9C4", "C c #CFD1CF", "Z c #CCDCCC", "A c #D5D5D5", "S c #D1DED1", "D c #DCDCDC", "F c #DEE3DE", "G c #E5E6E5", "H c #E9E7E9", "J c #ECEBEC", "K c #F1E7F1", "L c #F3EBF3", "P c #FAEEFA", "I c #F4F4F4", "U c #FFF3FF", "Y c #FAFAFA", /* pixels */ " ", " . . ", " ", " .O@@+OOOOOOOOOOOOOOO X+@@OOOOOOOOOOOOOOOO. ", " OJjdDHGHHGJJJHHGJGJIXpJdjJHJHHHGGJHJHJGGJO ", " OH>&%IIIIGGGGHHGHGGJXpM;OdYajYGHHGHHGHHGJO ", " OHYp;DassGGGGGGGGHGJX>YJ%ks--hJGGGHGGGGGGO ", " OI-okSddgGGGGHGGGGGJXpFX=DD;sFGFGGGGGGGGJO ", " OJ;=>HIIIGGGGGGGGGGJXpN*-hINDJHKJGGGGGGHGO ", " OHYYIHGGGGGGJGGGGGGJX>YIIIGJHHSVZJHGGGGHJO . ", " OJFFGGGGGGGGGGGGGGGJo>YDGGGHH0<<YGGGGHGefv8$zLGGHGJO ", " OHGHGHGHGGGGGGGGGGGJX>YFGGGGGJKUi$lIGGGGJO ", " OJGGGGGGGGGGGGGGGHGJX>YGGGGGHGJZ44SJGGGGGO ", " . OHGHGGHGGGGGGGGGGGGJX>IGGGGGGLm34VKGGGGGJO ", " OJHGGGGGGGGGGGGHJHHJX>YFGHGGHv17SHFGGGGGJO ", " OGGGGHGGGGHHGGGGGGHJXuPGGGGHG4$241uKGGGGHO ", " OJGHGGGGHGGGGGGGGGGJX>PFHGGHFitrrecJGGGHJO ", " OJGGGGGGGGHGGGJGGHGJX>UFGGGGHKPULPJGGGGHJO ", " OJGGHGGGGGGGGGGGGHJJX>PFHGGGGGFGGGGGGGHGHO ", " OGHHGGHGGGGGGGGGGHGJX>YGGHGGGGGGGGHGGGGGGO ", " OHGFGGFFGGGFGGGGFGFJX>YFGGGHGGGGHGGGGGGHJO ", " OYJIIIIIIIIIIIIIIIJYX>YHJJJJJJIJJJIJKJJJJO ", " ossssssssssssssssssdX.XXXXXXXXXXXXXXXXXXo. ", " OMMMMVMMMMMMMMMMMMMNo%p>a>pap>p>>>>>>>>p* ", " OIJJJJJLJJIJJJJJJJJIXpYM*Hj*jYJYJYYYYYYYj ", " OHGHHGGGGHGGGGGGGHGJX>J-+j@a@k:apJFGFGDJg ", " OGGHGGGGGHGGGJGGGHGJXas@+;#A+Ap.NJGGGGGIg . ", " OJGGGGGGGGGGGGGGGGGJX>Ddod;+-C:d>HGGGGGIg ", " OJGGHGGGGGGJGGGGGHGJX>YINHGjGKLYKPHGGGGIg . ", " OJGGGGHGGGGGGGGGGGHJX>YDJGGJJxrrrrZHGGGIg ", " OJGGGGHJGGGGGGGJGGGJX>YGGGGGKe,642nJGGFIg ", " OJGGGGGGGGGGJGGGGGGJouPGHHGGLr1izZJGGGGIg ", " OGGGGGGGGGGGGGGGGGGJX:PDGGGFJe<1<4BJGHFIg ", " OJHGGGGJGGGGGGGGGGGJX>YGHGGGHnBGy$rKGGFLg . ", " OGGHGGGGGGGGGHGGGGGIX>UDHHGGGLPUn<0LGGGIg ", " OJGGGGJGGGGGGGGGGHHJX>YDGGGHFqzb9$iKGGGIg . ", " OJGGHGGGGJGGGGHGHHHJX>UGGGGGG0<,YFGGGGHHSVSJHGGGGIg . ", " OJHGGGGGGGGGGGGGGGGIX>IGGGGHGGHJJGGGGGDIg ", " OHGGGGGHGGHGGGGGGGGJX>YFGGGGHGGGGGHHGGGIg . ", " OGGGGGHFGGFFGGGGGDGJX>YGGHHGGGGGGGGGHGGIg ", " OYIIIIIIIIIIIIIIIIIYX>IFHGGGGGHHGGGGGGGIg . ", " oggggggggggggggggggh.iYHJJGJHJGJGHJJHHGIg ", " X+OOOOOOOOOOOOOOOOOo ", " . . . . . ", " ", " " }; const char *const *const xpm_icons[] = { xpm_icon_0, xpm_icon_1, xpm_icon_2, }; const int n_xpm_icons = 3; puzzles-20170606.272beef/icons/inertia-icon.c0000644000175000017500000003252413115373752017541 0ustar simonsimon/* XPM */ static const char *const xpm_icon_0[] = { /* columns rows colors chars-per-pixel */ "16 16 248 2 ", " c #D5D5D5", ". c #CECECE", "X c gray85", "o c gainsboro", "O c gray81", "+ c #D0D0D0", "@ c gray83", "# c gray82", "$ c #D2D2D2", "% c LightGray", "& c #D2D2D2", "* c gray84", "= c #D5D5D5", "- c #D5D5D5", "; c #D5D5D5", ": c #D5D5D5", "> c #D2D2D2", ", c #E4E4E4", "< c gray59", "1 c #717171", "2 c #E2E2E2", "3 c #CECECE", "4 c gray72", "5 c gray78", "6 c gray", "7 c gray75", "8 c #E6E6E6", "9 c gray91", "0 c #E6E6E6", "q c #E9E9E9", "w c gray84", "e c #D0D0D0", "r c gainsboro", "t c #9D9D9D", "y c #353535", "u c gray3", "i c #6F6F6F", "p c gray80", "a c gray73", "s c #D8D8D8", "d c gray82", "f c gray72", "g c gray90", "h c gray88", "j c #DDDDDD", "k c #E1E1E1", "l c #C8C8C8", "z c #CECECE", "x c #DDDDDD", "c c gray31", "v c #0C0C0C", "b c gray3", "n c #1D1D1D", "m c #B9B9B9", "M c #D7D7D7", "N c gray84", "B c gray85", "V c #CDCDCD", "C c #E2E2E2", "Z c #E1E1E1", "A c gray87", "S c #E2E2E2", "D c #CBCBCB", "F c gray81", "G c #D7D7D7", "H c #D7D7D7", "J c #3C3D3D", "K c #131313", "L c #B9B9B9", "P c LightGray", "I c gray68", "U c #D1D2D2", "Y c #C6C6C6", "T c #B2B2B2", "R c #E7E7E7", "E c #DFDFDF", "W c #DFDFDF", "Q c #E1E1E1", "! c #CACACA", "~ c #CECECE", "^ c #D3D2D2", "/ c #D4D5D5", "( c #C9C8C8", ") c #B8B5B5", "_ c #D9DBDB", "` c gray79", "' c #C7C8C8", "] c #CCC9C9", "[ c #C7C6C6", "{ c #CBCCCC", "} c #D0D0D0", "| c #CBCBCB", " . c gray77", ".. c gray80", "X. c gray", "o. c #D2D2D2", "O. c #D4D5D5", "+. c #DBD6D6", "@. c #B8C1C1", "#. c #A8BDBD", "$. c #D8D1D1", "%. c #CED0D0", "&. c #DDD5D5", "*. c #A5B9B9", "=. c #B9C2C2", "-. c #D8D3D3", ";. c #DADBDB", ":. c gray71", ">. c #222222", ",. c #A5A5A5", "<. c #E1E1E1", "1. c gray81", "2. c #DAD9D9", "3. c #B9BFBF", "4. c #8ADEDE", "5. c #8CF4F4", "6. c #A2BCBC", "7. c #D6CECE", "8. c #A2BCBC", "9. c #8DF4F4", "0. c #89DEDE", "q. c #BCC3C3", "w. c #AAA8A8", "e. c #2A2A2A", "r. c #2A2A2A", "t. c #040404", "y. c gray62", "u. c #DADADA", "i. c #DAD9D9", "p. c #B9BFBF", "a. c #8BDFDF", "s. c #8DF5F5", "d. c #A1BCBC", "f. c #D6CECE", "g. c #A2BCBC", "h. c #8DF4F4", "j. c #89DEDE", "k. c #BCC2C2", "l. c #AFADAD", "z. c #141515", "x. c black", "c. c #0B0B0B", "v. c #9D9D9D", "b. c #DADADA", "n. c #D3D4D4", "m. c #DDD8D8", "M. c #B7BFBF", "N. c #A2B7B7", "B. c #DBD3D3", "V. c #CDD0D0", "C. c #DDD5D5", "Z. c #A5B9B9", "A. c #B9C2C2", "S. c #D9D4D4", "D. c #DBDBDC", "F. c #B6B8B6", "G. c #232723", "H. c #A6A8A6", "J. c #DFDFDF", "K. c gray81", "L. c gray83", "P. c #CECFCF", "I. c #D3D1D1", "U. c #D5D1D1", "Y. c #CECFCF", "T. c #CCCBCB", "R. c #C6C8C8", "E. c #CCC9C9", "W. c #C8C6C6", "Q. c #CACACB", "!. c #CCCDCB", "~. c #D3C9D3", "^. c #CEBCCE", "/. c #D2C7D2", "(. c #CCCDCC", "). c #D2D2D2", "_. c #D5D5D5", "`. c gray84", "'. c #D5D5D5", "]. c #D4D5D5", "[. c #D7D7D7", "{. c #CBCBCB", "}. c gray69", "|. c #D1D2D2", " X c #C5C5C5", ".X c #B4B6B3", "XX c #CAC1CA", "oX c #659F65", "OX c #21D721", "+X c #59A359", "@X c #C3B9C3", "#X c #D4D7D4", "$X c #D5D5D5", "%X c #D5D5D5", "&X c #D5D5D5", "*X c #D5D5D5", "=X c gray84", "-X c gray79", ";X c gray83", ":X c #D7D7D7", ">X c gray85", ",X c #D1D2D1", " , < 1 2 3 4 5 6 7 8 9 0 q w e ", "r t y u i p a s d f g h j k l z ", "x c v b n m M N B V C Z A S D F ", "G H J K L P I U Y T R E W Q ! ~ ", "^ / ( ) _ ` ' ] [ { } | ...X.o.", "O.+.@.#.$.%.&.*.=.-.;.:.>.,.<.1.", "2.3.4.5.6.7.8.9.0.q.w.e.r.t.y.u.", "i.p.a.s.d.f.g.h.j.k.l.z.x.c.v.b.", "n.m.M.N.B.V.C.Z.A.S.D.F.G.H.J.K.", "L.P.I.U.Y.T.R.E.W.Q.!.~.^./.(.).", "_.`.'.].[.{.}.|. X.XXXoXOX+X@X#X", "$X%X&X*X=X-X;X:X>X,X c #3CA53C", ", c #0ECA0E", "< c #00D100", "1 c #0AD20A", "2 c #12C112", "3 c #00E200", "4 c #00F200", "5 c #02FE02", "6 c #4FA34F", "7 c #49A849", "8 c #628F62", "9 c #748574", "0 c #758875", "q c #7E837E", "w c #77A577", "e c #7AA07A", "r c #7A9595", "t c #7C9B9B", "y c #69B3B3", "u c #74C3C3", "i c #77C8C8", "p c #808080", "a c #8A838A", "s c #8D8D8D", "d c #928992", "f c #949494", "g c #9A939A", "h c #9C9C9C", "j c #A29BA2", "k c #9DA2A2", "l c #A3A3A3", "z c #A8A6A6", "x c #ABA2AB", "c c #ACACAC", "v c #B2A3B2", "b c #B2AFB2", "n c #BCADBC", "m c #B5B5B5", "M c #B7B8B7", "N c #BBBBBB", "B c #BFC2BF", "V c #8AEBEB", "C c #8DF0F0", "Z c #97FBFB", "A c #9EFFFF", "S c #A2FFFF", "D c #C4C4C4", "F c #C6C9C6", "G c #CCCCCC", "H c #D3CCCC", "J c #CDD0CD", "K c #D5C6D5", "L c #DBCBDB", "P c #D5D5D5", "I c #DED6DE", "U c #DBDCDB", "Y c #E2DFDF", "T c #E3D2E3", "R c #E5DBE5", "E c #E3E3E3", "W c #EEEEEE", "Q c #F2F2F2", /* pixels */ "PPPUPPPPIPPPPUPPPPIPPPPUPPPPIPPP", "PPGGGPUGGGGJGJJGPJGGJPJJJJGJJJPP", "PPPGPm*PJJFDPGmPDNUGPQWQQQQWQPPP", "PPPPU$ hEPGPGdMUGfcPUQYEEEEEEmPP", "PPUGo &EJGsGUPPEgcEQUYUUEUUmPP", "PPG# mX hPNMUPPPPJcEQUYEEUEUMPP", "PE@ .O. dYUPPPPPUPUQUYUEEUUmPP", "PUcO &DDFPPPPPPMEQUYEUUEUbPP", "PPEN. . +EPFsPUPPEllEQUUUEERUmPP", "PPPUBO *PPGPNsFPPlkPUQEEEEEEEmPP", "PPPGEz#PPJGGUNcPBcPKEUDDDFDFDcPP", "PJFGFJEFGGDDGGPHJJGFFDNNMMNNNNPP", "PPPPUGzUPPJGUPUcGUPPFPUW$oEUUGPP", "PPPUJfykRPJGPUlytHIPGPP# ODPGPP", "PPUHtVSuhRGFEkuSVrHPDW$.%. OEGJP", "PPHtCZZAikPPkuSZACtGG@ og oNPP", "PPJtVAZSikPPkuSZACrGG@ oNPP", "PPUJrVSuhRGGRhuSVrHPDW% OEGHU", "PPPUHfyhUPGGPUlytHUPFPP# ODUGPP", "PPPPUJcIPUJJUPUcGUPPGPPW#oEUPGJP", "PPGFFGJGFGDDGGJJJJGGBFGHDBJFGDPP", "PPPPPPJPPPGGUBcIDcPJDPHxLTmJPFPP", "PPPPPUPPPUGPNsFPPjhUGPgr670dGJJP", "PPPPPPPPPPJDsPUPPElzPj9155<8gGPP", "PPPPPPIPPIJBDIPPPPPNGn;55552xGPP", "PPPPPPPPPPGPUJPPPPPUGK=5555 c #6A7575", ", c #617C7C", "< c #6A7979", "1 c #757575", "2 c #7C7C7C", "3 c #1F9F1F", "4 c #02AC02", "5 c #0DA20D", "6 c #05B005", "7 c #00BC00", "8 c #249424", "9 c #3D8C3D", "0 c #359335", "q c #389238", "w c #00C100", "e c #00CE00", "r c #00D000", "t c #00D900", "y c #00E200", "u c #00EC00", "i c #01FE01", "p c #468C46", "a c #4F8F4F", "s c #6F896F", "d c #778C77", "f c #7D807D", "g c #788978", "h c #837F83", "j c #5A8484", "k c #5F8989", "l c #5D9696", "z c #5E9A9A", "x c #619C9C", "c c #77D4D4", "v c #7BD3D3", "b c #7EDCDC", "n c #858585", "m c #858885", "M c #8A8A8A", "N c #8B948B", "B c #938893", "V c #9C8E9C", "C c #939393", "Z c #9C939C", "A c #9C9B9B", "S c #9EA19E", "D c #A297A2", "F c #A39EA3", "G c #A4A4A4", "H c #A7AAA7", "J c #ACA4AC", "K c #ADADAD", "L c #B5ADAD", "P c #B5A8B5", "I c #B4B3B3", "U c #B7B8B7", "Y c #BCBCBC", "T c #BFC2BF", "R c #CDBCCD", "E c #88E7E7", "W c #8BECEC", "Q c #93F6F6", "! c #96FBFB", "~ c #9BFEFE", "^ c #A3FFFF", "/ c #C4C4C4", "( c #C8C2C2", ") c #CACACA", "_ c #CFD0CF", "` c #D5D5D5", "' c #D4D8D4", "] c #D7D9D9", "[ c #DBDCDC", "{ c #E0DEDE", "} c #E6D7E6", "| c #E6D8E6", " . c #E2E2E2", ".. c #EAE7EA", "X. c #ECECEC", "o. c #F1F1F1", "O. c #FCFCFC", /* pixels */ "` ` ` ` ` ` ` ` ` ` ` ` ` ] ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ] ` ` ` ` ` ` ` ", "` ` ` ` ` ` ` ] ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ] ` ' ` ` ` ` ` ` ' ` ] ` ` ` ` ` ", "` ` ` ` ] ` ] ] ] ] ` ] ] ` [ ` ` ` [ ` ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ] ` ] ] ] ] ] ` ` ` ` ` ", "` ` ` ` ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) ) / ) ) ) ) ) ( ) ) ( ) ) ) / ) / ) ) ) / ) ) / ) ` ` ] ` ", "` ` ` ` ) ) ) ) ) T Y / ) ) ) ) ( ( ) ) ` _ ) ) ) ) ` ) ) ( _ o.o.o.o.o.o.o.o.o.o.X.o._ ` ' ` ` ", "` ` ` ` ` ` ` [ ..# K ..` ] ] ) ) ' .I f ) ] ` m G .] _ [ O.o.o.o.o.o.o.o.o.o.o. .U ` ' ` ` ", "` ` ` ` ` ` ] ` M X % Y { ` ` ) ) .A 2 / ] ` ` ) m M { ) | O.] [ [ [ ] [ ] [ [ ./ K ` ` ` ` ", "` ` ` ` ` ` _ # . A [ ` / ` I 2 { ] ` ` ` ] .M S ] ] O.[ { .{ . . . .| ./ K ] ` ` ` ", "` ` ` ` ] o.* @ $ X / ..) ) 2 ) ] ` ' ` ` ` ` ` 2 / { O.[ .{ { .[ .[ { ./ K ] ` ` ] ", "` ` ` [ I 1 o H O.. % A ) ) / ` ` ` ` ` ` ` ` ] ) / [ O.[ [ [ .[ .[ .[ ../ L [ ` ` ` ", "` ` ` .n . . O ) ) [ ` ` ` ` ` ` ` ` ` [ ) [ O.[ .[ . .[ .[ { ./ K ` ` ` ` ", "` ` ` { A @ . O - ) ) ] ` ` ` ` ` ` ` ` ` ] ) { O.[ [ .[ [ .[ . . .) L ` ` ` ` ", "` ` ` ` [ ..$ I X./ ) M ` ` ` ` ` ` ` ` [ M / { O.{ { { . .[ .[ [ .) K ` ` ` ` ", "` ` ` ` ` ] I o : [ ` / ] A C ..` ` ` ` _ ..G M ` ] O.] . .[ [ .[ .[ ./ I ] ` ` ` ", "` ` ` ` ` ` { Y % . O M ] ` ` ) ) ] f A ] ] ` ` [ H 1 ` _ [ O.] { { { { { .[ [ ./ K ] ` ` ` ", "` ` ` ` ` ` ` ] ..+ G X.` ` ] ) _ ` [ B 2 ) [ ` n n ` [ ) [ O. . . . . . . . . . .) I ] ` ` ` ", "` ` ` ` _ ` ` _ _ G C / ` ` _ ` ( ) ` ` [ / ) ` _ T ] ` ` ) [ ..I I I I I I I I I U K I ` ` ` ` ", "` ` ` ` / / ( / / ) _ / R / ( ( Y Y / / T ) / T ( ) T / / T Y / Y Y Y Y ) ) Y Y Y Y Y Y ` ` ` ` ", "` ` ` ` ` ` ` ] ] [ [ ` _ ' ` [ ) _ ` ` ] ` ] { ] ' ] ] ` _ / ] ] ] [ _ % * ` ] ` ] ] / ` ` ` ` ", "` ` ` ` ` ` ` ` { A > ` ] ` ` ` ) ) ] ` ` { / ; I | _ ` ` _ ) ] ` ` .A . I [ ` ` ` / ` ] ` ` ", "` ` ] ` ` ` ` .A x v < _ [ _ [ ) ) ` ` [ R , b k L [ ` ` _ ) ` ` ` & : ] ` ` / ' ` ` ` ", "` ` ` ` ` ` { A x ~ ^ v > _ [ ` ) ) ` [ ( = E ^ Q j L .` ` ( ` .& : .` ( ` ] ` ` ", "` ` ` ` ` { A l ~ ~ Q ^ v > _ { / ) [ ( = E ^ ! ~ ! j L .) / ` A .I X I _ / ` ] ` ` ", "` ` ` ` { A l ~ ~ ~ ~ ~ ^ E > ` ) _ ) = W ~ ! ~ ! ~ ! j I ` ` $ : % * ` ) ` ` ` ", "` ` ` ` [ A z ^ ~ ~ ~ ! ^ b > ` / ` ) = W ^ ! ! ! ^ ! j I ` ` $ * ` _ ] ` ` ", "` ` ` ` ` .A l ~ ~ Q ^ v > ` { ) ) [ ( = W ^ ! ~ ! j L .) ( ` A X K _ / ` ` ` ` ", "` ` ` ] ` ` .A l ~ ^ v < ` ` ` / ) ` [ ( = E ^ Q j L [ ` _ / ] .& : ..] / ` ` ` ` ", "` ` ` ` ` ` ` .A x v < _ [ ` ` ) ) ` ` [ ( , b k L .` ` ` / ` ] ` & . : ] ` ' ( ` ` ` ` ", "` ` ` ` ` ` ` ` | A > ` ] ` ` ] ) ) ] ` ` ] / ; I [ _ ` ` ) / ] ` ` { S I .` ` ` / ` ` ` ` ", "` ` ` ` ` ` ` ` ` { { ] ` ] ` ] ) ) [ ] ` ` [ { [ ' ] ' ] ` ) ] ] ` ] ) % * ` ` ` ` ] / ` ` ` ` ", "' ` ` ` / ( / / / / / / / / / / Y T / ( / ) / / / ) R T / / Y ( / / / ) ` ` / / / / / Y ` ` ` ` ", "` ` ` ' _ _ ` ` _ ` _ _ _ ` ` ` / / ` ` [ / ) ` ) T ] ` ` ) / ' _ ] ) T ` ` / _ ] ) ` / ` ` ` ` ", "` ` ` ` ` ] ` ` ] ` ` ] ` ` ` [ ) ) ] ] C 2 ) [ ` m m _ ] ` / ` { K 2 P R R J 2 U | ` / ` ` ` ` ", "` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ] ) ) [ f A [ ` ` ` | H 1 ` _ / | G n C q 5 5 p Z 2 K [ T ` ` ` ` ", "` ` ] ` ` ` ` ` ` ` ` ] ` ` ` ] ( ` A C .` ` ` ` ` .H m ] ) T 2 C 4 i i i i 5 A 2 ) ) ` ` ` ` ", "` ` ` ` ] ` ` ` ` ` ` ` ` ` ` ` ) ) n ` ` ` ` ` ` ` ` [ M / _ A V 3 i i i i i i 0 Z H ) ` ] ` ` ", "` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ] / ) ` ` ` ` ` ` ` ` ` ` ] _ / .N e i i i i i i 7 S [ / ` ` ` ` ", "` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ] ) ) [ ` ` ` ` ` ` ` ` ` ] ` T ..d y i i i i i i r C ..T ` ` ` ` ", "` ] ` ` ` ` ` ` ` ` ` ` ` ` ` ] ) ) / ` ` ` ` ` ` ` ` ` ) ) ( ` C w i i i i i i 6 F _ / ` ` ` ` ", "` ` ` ` ` ] ` ` ` ` ` ` ` ` ` ] ) _ 2 ) ] ` ` ` ` ` ` ` 1 ) _ A V q i i i i i u a B H ) ` ` ` ` ", "` ` ` ] ` ` ` ` ` ` ` ` { ` ` ` / ` I 2 { ] ` ` ` ] ..M A [ / ` 2 Z 8 y i i t q D f ] T ` ` ` ` ", "` ` ` ` ` ` ] ` ` ` ` ` ` ` ` ` ) ) .A 2 ) ] ` ` ) n M [ _ / [ Y 2 Z d 9 9 g V 2 ) ] R _ ] ` ` ", "` ` ` ` ` ` ` ` ] ` ` ` ` ` ` ] ) ) ] { K 2 ) ] ` n G { ] _ R ` [ ) m I } } J N ` ] ` / ` ` ` ' ", "` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ) ) ` ` [ [ ` ` ` ` [ ` ` ` ( { ` ] [ _ ` ` ` { ` ` ` ) ` ` ` ` ", "` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ", "` { ` ` ` ` ` ` ` ` ` ` ` ` ` ] ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ", "` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ", "` ` ` ` ` ` ` ` ` ` ` { ` ` ` ` ] ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ] ` ` ] ` ` ` ` ` " }; const char *const *const xpm_icons[] = { xpm_icon_0, xpm_icon_1, xpm_icon_2, }; const int n_xpm_icons = 3; puzzles-20170606.272beef/icons/guess-icon.c0000644000175000017500000004410613115373752017233 0ustar simonsimon/* XPM */ static const char *const xpm_icon_0[] = { /* columns rows colors chars-per-pixel */ "16 16 252 2 ", " c #D6D5D5", ". c #D3DBDB", "X c #CAC4C4", "o c #D2DCDC", "O c #D1D8D8", "+ c #CAC5C4", "@ c #D5DDE2", "# c #CECDCF", "$ c #CCCCCA", "% c #D5D5E3", "& c #CBCBC8", "* c #CFCFD3", "= c #D5D5D9", "- c #D3D3D2", "; c gray83", ": c #D5D5D5", "> c #D3E1E1", ", c #D28181", "< c #F00000", "1 c #D17071", "2 c #D65F5D", "3 c #EF0201", "4 c #C98E8B", "5 c #E3EC34", "6 c #EAE61B", "7 c #C7C792", "8 c #EDEB13", "9 c #E0DF37", "0 c #C7C7CB", "q c #C5C5C5", "w c #CBCBCA", "e c #D5D5D5", "r c #D1E4E4", "t c #D65D5E", "y c red", "u c #D54646", "i c #DD3736", "p c #C86A5A", "a c #F0FF15", "s c #FBF801", "d c #C6C560", "f c yellow", "g c #F0F015", "h c #BCBBB7", "j c #B0B0B2", "k c #BEBEBD", "l c #D8D8D8", "z c #D8DAD9", "x c #CDC8C8", "c c #9C5B7C", "v c #CCC1C8", "b c #C1BAAE", "n c #967F50", "m c #D1D5E1", "M c #C7AE85", "N c #C6A16B", "B c #CDDCE9", "V c #C59C60", "C c #C9B593", "Z c #C8CED5", "A c #B5B4B2", "S c gray76", "D c #D8D8D8", "F c #E0DED1", "G c #7B87D6", "H c #1642FF", "J c #6A70E0", "K c #3CE72E", "L c green", "P c #72BD65", "I c #FE0919", "U c #F50604", "Y c #C66C6C", "T c #FB0000", "R c #F52122", "E c #989696", "W c #5C5D5D", "Q c #8D8C8C", "! c #DFDFDF", "~ c #DFDED2", "^ c #8893D7", "/ c #1F42FF", "( c #7A7DE2", ") c #4CE546", "_ c #00FD04", "` c #83C37E", "' c #F3242E", "] c #EC1E18", "[ c #C78484", "{ c #F11310", "} c #E63332", "| c #C4C5C5", " . c #B9BABA", ".. c #C0C0C0", "X. c #D8D8D8", "o. c #D6D9DB", "O. c #D2C9BC", "+. c #B78359", "@. c #D1C4B9", "#. c #CDBAA9", "$. c #B6914A", "%. c #D4D6DA", "&. c #C97F7F", "*. c #C96565", "=. c #CDE1E1", "-. c #C85A5A", ";. c #CE8F8F", ":. c #B9C5C5", ">. c #ABA8A8", ",. c #CECECE", "<. c gray84", "1. c #D1DBE4", "2. c #D59358", "3. c #FF7200", "4. c #D3853F", "5. c #DC8330", "6. c #FF7700", "7. c #C78252", "8. c #F10A12", "9. c #FC0200", "0. c #C45757", "q. c #FE0000", "w. c #F81919", "e. c #958F8F", "r. c #7E8080", "t. c gray", "y. c #D4D9E0", "u. c #D6B793", "i. c #EE830D", "p. c #D7B185", "a. c #D1A27D", "s. c #E07A23", "d. c #CBB8A9", "f. c #D95154", "g. c #DC3D3D", "h. c #CCB0AD", "j. c #E73328", "k. c #DE5A51", "l. c #CFD5D5", "z. c #CAC9C9", "x. c gray79", "c. c #D7D7D7", "v. c #DCDBD4", "b. c #ACB4D7", "n. c #4A60DE", "m. c #9BA6E1", "M. c #D7DB86", "N. c #D4D936", "B. c #CCD6BD", "V. c #D26167", "C. c #D64F4C", "Z. c #C6C5CD", "A. c #8643B1", "S. c #A276C3", "D. c #AFB4AF", "F. c #7A797A", "G. c #A2A2A2", "H. c gainsboro", "J. c #E2E0D1", "K. c #6975D4", "L. c #0F2EFF", "P. c #4B5BDB", "I. c #EAE820", "U. c #C7B450", "Y. c #EF0014", "T. c #FF0400", "R. c #A1557F", "E. c #7200B7", "W. c #7F13AC", "Q. c #A7A4A8", "!. c #858685", "~. c #9D9D9D", "^. c #DDDDDD", "/. c #DBDBD5", "(. c #B6B9D6", "). c #5B69CB", "_. c #A9ADDE", "`. c #DBD296", "'. c #CDCB42", "]. c #D4D6CD", "[. c #CC7174", "{. c #CE5B5A", "}. c #CDD4D3", "|. c #9051A8", " X c #A47CB4", ".X c #DBE0D9", "XX c #D2D1D3", "oX c #CDCDCD", "OX c gray84", "+X c #D3D3E1", "@X c #D7D685", "#X c #FAFA00", "$X c #E3D773", "%X c #53D46B", "&X c #03EC14", "*X c #93C894", "=X c #E93A45", "-X c #E62F28", ";X c #BB9BAF", ":X c #8323AF", ">X c #9C50B9", ",X c #A3A5A3", " , < 1 2 3 4 5 6 7 8 9 0 q w e ", "r t y u i y p a s d f g h j k l ", "z x c v b n m M N B V C Z A S D ", "F G H J K L P I U Y T R E W Q ! ", "~ ^ / ( ) _ ` ' ] [ { } | ...X.", "o.O.+.@.#.$.%.&.*.=.-.;.:.>.,.<.", "1.2.3.4.5.6.7.8.9.0.q.w.e.r.t.D ", "y.u.i.p.a.s.d.f.g.h.j.k.l.z.x.c.", "v.b.n.m.M.N.B.V.C.Z.A.S.D.F.G.H.", "J.K.L.P.I.f U.Y.T.R.E.W.Q.!.~.^.", "/.(.)._.`.'.].[.{.}.|. X.XXXoXOX", "+X@X#X$X%X&X*X=X-X;X:X>X,X c #E50D15", ", c #C92726", "< c #D72425", "1 c #C83130", "2 c #CB3D3D", "3 c #DA3C2F", "4 c #E02B3E", "5 c #E97706", "6 c #FF7600", "7 c #FE7D02", "8 c #F47400", "9 c #EE7408", "0 c #D87C25", "q c #D17C38", "w c #D67113", "e c #BF4C4C", "r c #BD5754", "t c #BB4B5D", "y c #BA5163", "u c #B86666", "i c #BA7A7A", "p c #B2727A", "a c #C94747", "s c #C45B5B", "d c #C75652", "f c #D34C41", "g c #C26558", "h c #CF5763", "j c #C37A7B", "k c #C36F69", "l c #01E600", "z c #02FE02", "x c #00F600", "c c #0CEB15", "v c #17E31D", "b c #2BD42C", "n c #12D410", "m c #41D733", "M c #55BF53", "N c #67BF67", "B c #2FCA40", "V c #49CC4B", "C c #59C464", "Z c #6EC175", "A c #FE8203", "S c #E58115", "D c #CA823B", "F c #D98C34", "G c #D9DA0A", "H c #D6D516", "J c #DFE41B", "K c #E5E403", "L c #E9E903", "P c #F3F300", "I c #FEFE02", "U c #E4E716", "Y c #C9C935", "T c #D7D630", "R c #CDE03F", "E c #BF8C59", "W c #81B07C", "Q c #BBBC62", "! c #B5B579", "~ c #B58D67", "^ c #C8884E", "/ c #C1BE57", "( c #C19B78", ") c #C49161", "_ c #C6B566", "` c #B8C161", "' c #C9CF48", "] c #C3D060", "[ c #C3C366", "{ c #710E99", "} c #792C99", "| c #7202A3", " . c #7507A5", ".. c #7C01B2", "X. c #7F15A9", "o. c #7E27A1", "O. c #7D46AF", "+. c #6A73BD", "@. c #263EEC", "#. c #233EFB", "$. c #2F43D4", "%. c #2A43FD", "&. c #2742F4", "*. c #364FFF", "=. c #3951FF", "-. c #4A59C6", ";. c #6C7AC9", ":. c #7B74C8", ">. c #8204B4", ",. c #8401B9", "<. c #8026A4", "1. c #864E9B", "2. c #937A9C", "3. c #BA7787", "4. c #8548A5", "5. c #8556AE", "6. c #926FAC", "7. c #7ACA8A", "8. c #7788CA", "9. c #6784CD", "0. c #888888", "q. c #959595", "w. c #9F9F9C", "e. c #A98685", "r. c #BC8888", "t. c #AB9B9C", "y. c #BA9999", "u. c #BB9D80", "i. c #BBBC86", "p. c #BBA996", "a. c #BDBD96", "s. c #A8A583", "d. c #989CB4", "f. c #918FB0", "g. c #B59DB1", "h. c #9DA1BD", "j. c #A4A4A4", "k. c #ACACAC", "l. c #A8A6A6", "z. c #BBAAA9", "x. c #BAB9AB", "c. c #ACA9B9", "v. c #B8ABB5", "b. c #ABBBB8", "n. c #B5B5B4", "m. c #BBBBBB", "M. c #BAB2BE", "N. c #A9BDA4", "B. c #C28782", "V. c #C19896", "C. c #C5AC93", "Z. c #C0AFAF", "A. c #C5B6AC", "S. c #C2BCBC", "D. c #C2B6B5", "F. c #8FC28C", "G. c #BCC393", "H. c #9ACAA6", "J. c #B8C1B7", "K. c #BDC4AD", "L. c #C0C384", "P. c #C2C190", "I. c #C2C1B8", "U. c #C1C1AC", "Y. c #8B82C9", "T. c #BEBDC1", "R. c #B5B5C7", "E. c #C9BCCB", "W. c #BBC6CB", "Q. c #C4C3C3", "!. c #CCCDCC", "~. c #C7C9C7", "^. c #D1CDCC", "/. c #CDD0CD", "(. c #D1D2CD", "). c #D6D8CF", "_. c #CCCCD5", "`. c #D2CED3", "'. c #D6CDD9", "]. c #CDD5D5", "[. c #CED9D9", "{. c #C9D7DA", "}. c #D5D5D5", "|. c #D9D7D7", " X c #D6DAD5", ".X c #DADAD6", "XX c #D4D4DC", "oX c #D4DCDD", "OX c #DADBDB", "+X c #DCD5DC", "@X c #E0DFD9", "#X c #DDE3DB", "$X c #DADAE1", "%X c #D8D9E6", "&X c #CFDCE7", "*X c #E0D9E8", "=X c #DBE2E4", "-X c #D5E6E6", ";X c #E3E4E3", ":X c #E6E9E4", /* pixels */ "}.}.}.}.|.OX}.}.}.}.OX}.}.}.}.|.|.}.}.}. XOX|.}.}.}.}.}.}.}.}.}.", "}.}.}.#XQ.S.-X}. X[.D._.oX}.%X~.I.%X}.}._.m.~.$X}.}.}.|.}.}.}.}.", "}.}.oXi # & e [.Q.1 * % p.%X! G K ' _.~.Y L H a.XXJ.Q.Q.T.!.|.}.", "}.OXv.& ; ; - r.s ; ; ; < n.L I I P i.[ I I I H E.!.(.n.oXQ. X}.", "}.=Xy.* ; ; ; u a ; ; ; > s.P I I I ` ' I P I K I.T.n.~.l.}.}.|.", "}.|.Q.% ; ; & v.i - ; ; a W.H I I K A.i.P I I Y XXw.q.k.0.!.|.}.", "}.}.oXD.f 3 V.#X[.j 4 h ~.%XD.' ' P.XXXXL.' ] ~.XX!.!.}.~.XX}.}.", "}.}. X/.8.9.W..XOXH.C 7.'.|.!.p y D.oXoXz.t 3. XOX!.!.}.Q.|.}.}.", "`.|.^.-.#.%.$.R.F.l z x M '.1 ; ; # D.y.& ; - e -Xo X + T.OX}.", "}..Xh.@.=.=.%.:.m z z z c e.* ; ; ; u a ; ; ; & ~.0.@ l.O !.}.}.", "}..Xc.@.=.=.#.Y.V z z z v t.* ; ; ; i s ; ; ; $ ~.m.k.S.j.}.}.}.", "}.}.).;.&.&.-.^.K.n z l F.=Xr * - , !.D.% ; & i =Xl.j.m.q.].|.}.", "}.}.}. Xd.f./.|.*X~.W b.*X}.-Xt.e.{.OX$XW.~ c.-X/.#X:XOXOX|.}.}.", "}.}.%Xu.S 5 ) ].Q.D 9 0 p.=Xr.: : d [.~.2 : < y.#X2.@ Q.k.}.}.}.", "}.OXx.5 A A 8 p.) 6 A 7 0 c.= ; ; - r.k ; ; ; % [.o . n.q.!.|.}.", "}.oXp.8 A A 7 ~ ^ A 7 A S e.- ; ; ; u a ; ; ; & S.Q.n.!.n.}.}.}.", "}. XQ.w 6 6 8 x.( 8 7 6 g W.% ; ; * z.j - ; ; 1 oXw.q.k.0.!.|.}.", "XX}.|.A.F F p.$X`.( q ) I.%XD.a 2 V. X].j 3 d I.OX!.!.}.Q.}.}.}.", "}.}.|.].8.;.T.OXXXK.` G.OX#X].~ u T.oXOXM.5.f. X|.].!.|.!. X}.}.", "}.}.(.-.#.%.$.R.P.K I P / {.1 ; ; # S.g.| >.| 1.:Xo X + m.|.}.", "}.@Xd.&.=.=.%.;.T I I I U e.- ; ; ; g 5.>.>.,. .~.@ + j.O !.|.}.", "].OXR.@.*.=.#.8.' I I I J t.* ; ; - k 5...>.,. .m.}.}.m.l.].}.}.", "}.|.(.+.&.%.-.!.x.G I L ! -Xd - ; , ~.M.{ ..| 2..Xm.Q.c.q.!.|.}.", "}.}.}.|.f.f._.|.%XE.! x.%X|.-Xt.e.{.|.#X~.2.k.#X}.OXOX;X:X|.}.}.", "}.}.XXi.U L Q %X~.V c b N.$Xr.% : s {.!.1.X.<.c.:X0.0.l.+ !.}.}.", "}.XXm.K I I P C.C z z z b v.= ; ; - B.6.| >.>.{ |.o X + m.|.}.", "}.$Xa.P I I I _ B z z z c e.- ; ; ; g O.,.>.>. .Q.j.q.m.@ }.|.}.", "}.|.Q.G I I L A.Z x z z b E.% ; ; & C.6.| >...} #Xo . + m.OX}.", "}.}.OXx.Y T i.{.`.N b V I.$Xz.2 4 r.oX).6.<.1.m.;Xk.j.T.q.}.}.}.", "}.}.}.XXR.M.XX|.}.'.v.E.OX}.|.W.b.[.}. X Xn.~.|.}.OX$X X;X|.}.}.", "}.}.}.}.(.!.(.}.}.]././.}.|.}.!.`.!.}.}.!.!.!.}.}.}.}.}.].}.}.}.", "}.|.}.}.|.|.}.}.}.}.}.|.}.}.}. X}.|.}.}.}.|.}.}.}.}.}.|.}.}.}.}." }; /* XPM */ static const char *const xpm_icon_2[] = { /* columns rows colors chars-per-pixel */ "48 48 203 2 ", " c black", ". c #0B0B0B", "X c #1E1E1E", "o c gray13", "O c #343434", "+ c #3B3B3B", "@ c #454545", "# c #585858", "$ c #616161", "% c gray43", "& c #7C7B7B", "* c #717171", "= c #BC211E", "- c #B82827", "; c #B23433", ": c #BB1A1A", "> c #C90B0A", ", c #D30202", "< c #DC0000", "1 c #D20A0A", "2 c #C31615", "3 c #E40000", "4 c #EC0000", "5 c #F30000", "6 c #FE0202", "7 c #C92828", "8 c #CB3036", "9 c #CE342F", "0 c #B17437", "q c #B76F27", "w c #BD6A18", "e c #D46E09", "r c #E66C00", "t c #F47301", "y c #FD7D01", "u c #FB7600", "i c #ED7000", "p c #CC7926", "a c #AD4545", "s c #BC4A4A", "d c #AB5757", "f c #B85857", "g c #BF544E", "h c #AF7B48", "j c #AB6969", "k c #B96663", "l c #AB7A7A", "z c #B37878", "x c #BB7169", "c c #C0524C", "v c #C04547", "b c #29B829", "n c #3CAE3B", "m c #40B23E", "M c #02DE02", "N c #07D406", "B c #0AC80A", "V c #00E800", "C c #01FE01", "Z c #01F401", "A c #35C83A", "S c #52B057", "D c #5CBB62", "F c #6DB16E", "G c #3FC242", "H c #43C44E", "J c #BDBD17", "K c #B9B924", "L c #B3B437", "P c #B0AF3E", "I c #FF8302", "U c #C3823C", "Y c #D8D805", "T c #C9C811", "R c #E3E300", "E c #EBEA00", "W c #F3F300", "Q c #FEFE02", "! c #F7FB03", "~ c #C5CA3B", "^ c #CDCB25", "/ c #AF8156", "( c #ADAD47", ") c #B1B353", "_ c #B1B155", "` c #B6997B", "' c #B28968", "] c #B3B365", "[ c #B6B877", "{ c #AEAD70", "} c #C2A069", "| c #C2C349", " . c #680A8E", ".. c #690393", "X. c #6A009A", "o. c #6B178C", "O. c #7400A4", "+. c #7701AC", "@. c #7C00B1", "#. c #3546BF", "$. c #4B57B3", "%. c #414FB7", "&. c #5B67B1", "*. c #6D75AC", "=. c #6A73B3", "-. c #2C3DD8", ";. c #1F39F2", ":. c #243CEC", ">. c #233EFC", ",. c #3346CC", "<. c #2943FC", "1. c #2944FF", "2. c #334CFE", "3. c #3952FF", "4. c #3750FF", "5. c #4555CC", "6. c #777EC1", "7. c #5B6DCA", "8. c #8203B4", "9. c #8501BC", "0. c #8804BC", "q. c #845996", "w. c #8B6799", "e. c #947D9D", "r. c #9073A6", "t. c #7B84B2", "y. c #7384C2", "u. c #858585", "i. c #8D8D8D", "p. c #9B9A9A", "a. c #959494", "s. c #908D8F", "d. c #AB8787", "f. c #B28B8B", "g. c #B38686", "h. c #AC9393", "j. c #AD9D9C", "k. c #B39897", "l. c #B28E94", "z. c #8DB190", "x. c #B3A986", "c. c #BEB299", "v. c #ADAE91", "b. c #9A87A5", "n. c #989AB7", "m. c #A598A8", "M. c #B295A7", "N. c #97A3B6", "B. c #A3A3A3", "V. c #ABABAB", "C. c #AAA6AA", "Z. c #B3A3A3", "A. c #B5AAA8", "S. c #B6B7AD", "D. c #B7B5A6", "F. c #ABACB5", "G. c #B8A9B4", "H. c #B4B3B3", "J. c #BBBBBC", "K. c #B7B7B7", "L. c #AAB8B0", "P. c #C2B8BC", "I. c #B2C1BB", "U. c #C2C2BD", "Y. c #BEBEC5", "T. c #ADBFC2", "R. c #C3BEC2", "E. c #BCC2C3", "W. c #BBC7C9", "Q. c #B7C9CE", "!. c #C3C4C4", "~. c #C3C4CD", "^. c #C4CDCD", "/. c #CCCCCB", "(. c #CAC6C5", "). c #D3CDCB", "_. c #D4D3CB", "`. c #DAD8CD", "'. c #CDCDDC", "]. c #C7C8D3", "[. c #CBD3D5", "{. c #CCD9D9", "}. c #C8D3D9", "|. c #D5D5D5", " X c #D9D6D6", ".X c #DADBD6", "XX c #D4D3DB", "oX c #D4DDDD", "OX c #DBDBDB", "+X c #D7D8D6", "@X c #D1CDD3", "#X c #DDE2DB", "$X c #E2E5DB", "%X c #D7C9E5", "&X c #CADAE3", "*X c #D4DAE3", "=X c #D9D9E3", "-X c #E4D9E4", ";X c #D5E2E2", ":X c #DBE2E2", ">X c #DCECEC", ",X c #E4E6E4", " l oX X^.d 1 3 2 d.oX X!.( Y Y T v.=XOXY.P Y R K D.XX+XJ.V.~.~.V.J.OX|.|.|.|.", "|.|.|.|.;Xj 5 6 6 6 3 l >Xd 6 6 6 6 < h.*X( Q Q Q Q Y S.'.K Q Q Q Q T J.|.S. 6 6 6 6 6 s K.Y ! ! Q Q Q _ D.R Q Q Q Q W { *XS./.K.H./.H.|.|.|.|.|.", "|.|.|.OXE.1 6 6 6 6 6 7 B.< 6 6 6 6 6 8 v.E Q Q Q Q Q ) v.W Q Q Q Q Q _ *X(.B.|.|.B./.OX|.|.|.|.", "|.|.|. X{.; 6 6 6 6 6 s Q.2 6 6 6 6 6 f W.T Q Q Q Q W [ K.Y W Q Q Q E x.=XB.u.H.H.u.B.+X|.|.|.|.", "|.|.|.|.#Xk., 6 6 6 > Z.>Xd.< 6 6 6 : J.=X{ R Q Q Q K R.*X] E Q Q W L ]..XV.u.J.K.u.C.+X|.|.|.|.", "|.|.|.|.|.oXV.s 9 f H.oX_.oXj.s 8 f J.OX|.XXv.| ~ ] R.=X X'.x.~ ~ { ~.OX+X|.!.+X+X~.|.+X|.|.|.|.", "|.|.|.|.|.|.$XJ.N.E.$X|.|. X=XI.z.Q.-X|.|.OX&XC.h.Q.:XXX|.OX&Xm.m.].:X|.|.OX,XOXOX,XOX|.|.|.|.|.", "|.|.|.|.+X/.&.-.:.-.*./.#X!.n M Z N F %XOXJ.- 3 4 1 l oX+XH.= 4 4 2 h.OX.XB.# J.J.# B.OX|.|.|.|.", "|.|.|.|.$X*.>.3.2.2.;.b.OXS C C C C V z.=X; 6 6 6 6 , Z.{.= 6 6 6 6 , V.,XO # $ O OX|.|.|.|.", "|.|.|.XXU.,.2.2.2.2.2.5.D.N C C C C C G G.3 6 6 6 6 6 f Z.3 6 6 6 6 6 j >Xl X B.B.X *.`.|.|.|.|.", "|.+X|.OXU.,.2.2.2.2.2.,.B.V C C C C C A M.3 6 6 6 6 6 s h.5 6 6 6 6 6 d ;XQ.K..X.XP.`.`.+X|.|.|.", "|.|.|.|.`.$.2.3.2.3.1.&.).b C C C C C F ].> 6 6 6 6 5 e.U., 6 6 6 6 4 h.:Xp.& V.V.F b.%X|.|.|.|.", "|.|.|.|.OXV.-.1.1.>.#.K.-Xz.N C C Z b R.:Xd.< 6 6 5 ; ^.$Xx 3 6 6 5 a {..XF.i.J.P.s.G. X|.|.|.|.", "|.|.|.|.|..XJ.=.7.t.U.OX|.OXH.D H F R.OX|.oXA.f g l [. X|.oXk.f c g.[. X|.|.@X|.+X_. X X|.|.|.|.", "|.|.|.|.|.OX&Xc.` P.*X X|.OXXXA.f.P.oX X|.OX{.j.h.E.;X|.|.OX[.j.h.W.;X|.|.#X,XOX|.+X X X|.|.|.|.", "|.|.+X|.XX^.0 r t r h ^.,XJ.q i u r / [.#XH.: 4 5 < j oXOXj.2 4 5 , l oXOXa.+ V./.B.I.OX|.|.|.|.", "|.|.|.|.&X/ u I I I t ' &X0 y I I I i f.&X- 6 6 6 6 < k.}.2 6 6 6 6 , A.,XO # H.& p.+X|.|.|. X", "|.|.|.OXW.e I y y I I p F.e I y I y y U C.3 6 6 6 6 6 f j.4 6 6 6 6 6 j >Xs.O C./.B.U.+X|.|.|.|.", "|.|.|.+XE.e I y I y I p V.e I y I I y U m.3 6 6 6 6 6 g h.5 6 6 6 6 6 f ;X/.K.|.@XF./.|.|.|.|.|.", "|.|.|.|.{.h y I y I u / &Xq y I I I t ' }.: 6 6 6 6 4 g.W.> 6 6 6 6 3 j.:Xp.& C.M.F p.XX|.|.|.|.", "|.|.|.|.OXJ.p t u t q R.:XA.e u y t 0 ~.:Xh., 6 6 4 a [.:Xd., 6 6 3 d oX XH.a.!.R.a.H.+X|.|.|.|.", "|.|.|.|.|.OXY.` } ` ^.oX|.OXE.` ' k.[.+X|.oXJ.z x k.{.OX|.oXH.x x Z.{.|.|.+X|.+XXXXXXX+X|.|.|.|.", "|.|.|.|.|.+X/.n.y.N._.+X|. X~.v.[ D.'.|.|.OX~.f.l A.=X|.|.OXY.b.r.H.#X|.|.OXOXOX X-XOX|.|.|.|.|.", "|.|.|.|.OXI.%.:.<.:.$.(.-XS.J W Q E ( ~.:XZ.> 5 6 3 d {.OXm...O.+...w.#XOXu.o B.B.o u.OX|.|.|.|.", "|.|.|.|.`.&.>.3.4.3.;.*.|.L Q Q Q Q W { }.= 6 6 6 6 3 f.^. .9.8.8.0.X.m.,XO $ $ O OX|.|.|.|.", "|.|.|.OXU.,.4.2.2.2.4.5.D.Y Q Q Q Q Q ~ m.4 6 6 6 6 6 g n.O.8.8.@.8.+.q.$XB.@ J.H.# B.OX|.|.|.|.", "|.|.|.OX(.,.2.2.2.2.2.,.D.Y Q Q Q ! Q ~ m.3 6 6 6 6 6 g m.O.8.@.8.8.@.q.#XY.J.(.@XH./. X|.|.|.|.", "|.|.|.|.`.&.>.3.3.3.<.*.|.L Q Q Q Q W { '.- 6 6 6 6 3 l.^.o.9.8.8.9.X.C.|.H. c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", "X$X@X=X%Xc.qX", "'.^.cXiXyXpXzXE.zXUXKXGXUXIX/.eX", "].Y.iX7X4X7XuXK.jXUXGXSXkXnX~.wX", "].I.yX4X2X5XeXQ.B.R.M.|.vXaX).5X", "].T.sX9X5X0X0X9X9XiX}.+XCXMXAXeX", "].R.sX9XrXpXpXtX0XpX|.#XUXIXCXeX", "].I.yX7XY.P.T.H.1XrX.Xm.+X[.).0X", "].Y.sX3XF.wXtXE.+XuX7X+XOX Xn.tX", "].E.uX2XI.nXFX/.$XqX0XiXjXdXT.tX", "{.H.sX:XZ.6X8XY.{.iX>X.X}.'.x.rX", "{.A.cX2Xe.R.E.I.*XbX(.C.;XOX X0X", "].E.0X c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", "X4X$XUXJ.L.xX7X", "fXE.%.pX1X4X4X5X,X1X5X4X4X3X0XW i.n.x.x.v.s.|.uXwXUXzXrXF.| sX0X", "fXE.*.dX4X7X7X8X1X3X8X7X7X6X0XQ.M.V.V.B.G.7.3.MX1XUXaX9XjX'.wXqX", "fXE.-.kX9XwXwXeX5X8XeXwXwXwXwX0XhXhXhXgXnX+X6.UX7X;X1XLXFXBXrX0X", "fXE.-.jX8XqXqXwX4X7XwXqXqXqXqX1X8X9X9X8XiX/.4.UXKXIXIXUXAXmXrX0X", "fXE.-.jX8XqXqXwX4X7XwXqXqXqXqX2X0XqXqX0XaX_.4.UXJXUXPXUXSXBXrX0X", "fXE.-.jX8XqXqXwX3X6XwX0XqXqXqX1X0XqXqX0XaX_.4.UXKXIXPXUXZXNXrX0X", "fXE.-.kX8XwXqXwX9XqXrXeXeXeXrX8XqXwXwX0XaX_.4.UXLXUXUXUXDXVXrX0X", "fXE.$.uX,X2X.3X-XUX1X c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", " g =XtX0XqX", "qX0XaX).x fXyXuXuXuXuXuXpX8X0XpXuXuXuXuXyXpXqXk xXUXIXUXUXUXUXUXSXnXUXIXUXUXUXUXLXUXP .XvX7XqXqX", "qX0XaX).z yX9X0X0X0X0X0XwX2X3XwX0X0X0X0X0XwX4Xj zXUXPXIXIXIXIXUXAXvXUXPXIXIXIXIXKXUXP .XvX7XqXqX", "qX0XaX).z uX0XqXqXqXqX0XeX2X4XwXqXqXqXqX0XeX5Xj xXUXIXUXUXUXIXUXAXbXUXIXUXUXUXUXLXUXP .XvX7XqXqX", "qX0XaX).z uX0XqXqXqXqXqXeX2X4XeXqXqXqXqXqXeX5Xj xXUXIXUXUXUXUXUXSXbXUXIXUXUXUXUXLXUXP .XvX7XqXqX", "qX0XaX).z uX0XqXqXqXqXqXeX2X4XeXqXqXqXqXqXeX5Xj xXUXIXUXUXUXUXUXSXbXUXIXPXIXIXIXLXUXP .XvX7XqXqX", "qX0XaX).z uX0XqXqXqXqXqXeX2X4XeXqXqXqXqXqXeX5Xj xXUXIXUXUXUXUXUXSXbXUXPXUXUXUXIXKXUXP .XvX7XqXqX", "qX0XaX).z uX0X0XqXqXqX0XwX2X4XwX0XqXqXqX0XeX5Xj jXUXJXKXKXKXJXPXBXxXUXUX8X'.'.tXUXUXP }.cX7XqXqX", "qX0XaX).z pXwXeXeXeXeXwXtX4X6XtXeXeXeXeXwXtX7Xz xXUXIXUXUXUXUXUXDXnXUX9X].KXFX/.iXUXI XXvX7XqXqX", "qX0XaX).k 8X2X2X2X2X2X2X4X-X:X4X2X2X2X2X2X4X,Xy #.5.2.2.2.2.2.4.=.P.LXW.SXUXUXnX!.UXJ Y 6XeX0XqX", "qX0XaX).k 0X3X4X4X4X4X4X6X:X>X5X4X4X4X4X4X4X4Xp.:.,.,.,.,.,.:.9.Z { UXQ.CXUXUXxX).UXT.p.2XrX0XqX", "qX0XaX).z pXwXwXeXeXeXwXtX4X5XrXwXeXeXeXeXwXeXqXxXcXcXcXcXcXlXKXM.{ UXeX/.VXmXQ.kXUXbXHXiX0XqXqX", "qX0XaX).z uX0XqXqXqXqX0XeX2X4XwX0XqXqXqXqXqXqX-X7X8X8X8X8X8X5XgXi.{ UXIXpX}. XhXUXUXlXAXiX0XqXqX", "qX0XaX).z uX0XqXqXqXqXqXeX2X4XeXqXqXqXqXqXqXqX>X0XqXqXqXqXqX8XlXs.{ UXJXUXUXUXIXPXUXxXGXiX9XqXqX", "qX0XaX).z uX0XqXqXqXqXqXeX2X4XeXqXqXqXqXqXqXqX>X0XqXqXqXqXqX8XlXs.{ UXKXIXPXPXIXIXUXxXGXiX9XqXqX", "qX0XaX).z uX0XqXqXqXqXqXeX2X4XeXqXqXqXqXqXqXqX>X0XqXqXqXqXqX8XlXs.{ UXKXUXUXUXUXIXUXxXGXiX9XqXqX", "qX0XaX).z uX0XqXqXqXqXqXeX2X4XwX0XqXqXqXqX0XqX>X0XqXqXqXqXqX8XlXs.{ UXJXIXIXIXIXIXUXxXFXiX0XqXqX", "qX0XaX).z uX0XqXqXqXqXqXeX3X6XtXeXeXeXeXeXeXeX,X0XqXqXqXqXqX8XlXs.} UXKXUXUXUXUXIXUXcXGXiX9XqXqX", "qX0XaX).z uXqXqXqXqXqXqXeX2X,X6X5X5X5X5X5X5X5X;XqXwXqXqXqXqX9XzXs.] UXSXHXHXHXHXGXLXkXCXuX0XqXqX", "qX0XaX_.j 4X:X>X>X>X>X-XwX2.6 x j h g h j k f s +X1X:X>X>X>X;X0Xc.: n l z z z z z c t l %XyX0XqX", "qX0XaX).z yX0X0X0X0X0X7XxX{ e.PXhXnXZXVXzXvXhXj $XyX0X0X0X0X0XwX2XXX%X#X$X$X$X#X+X2Xb !.kX8XqXqX", "qX0XaX).z uX0XqXqXqXqX7XcX{ l.UXPXCX8XsXIXUXHXx $XyX0XqXqXqXqXwX7X5XiXyXyXyXyXyXrXxXZ OXcX7XqXqX", "qX0XaX).z uX0XqXqXqXqX7XcX[ h.UXwXQ.wX$X_.UXGXz $XyX0XqXqXqXqXwX6XXUXSXl #XpX7XW.P.'.tXwX5X>X0X8X8X8X8X8X6XdXB .XcX7XqXqX", "qX0XaX).z sXX#Xs.s.s.s.s.s.s.p.z.y 9.eXqXqXqX", "qX0XaX_.h eXD.lXUXPXUXF.eX+.9 ~ P I I I I U L _ 2XR.4XUXHXUX!.:Xz.5 @.[ { { { { { } { { =XtX0XqX", "qX0XaX).l hXOXW.IXUX-XI.CX{ e.LXjXxXxXxXxXxXxXwXyX2XH.AXUXyXS.nXd.| UXKXUXUXUXUXIXUXnXHXiX0XqXqX", "qX0XaX).z tXyX[.K.Y.R.9XxX| <.jX4X8X8X8X8X7X8X-X9XyX$XH.R.K.3XxXa.[ UXFXKXKXKXKXJXIXkXAXiX0XqXqX", "qX0XaX).z uX9XuXqX7XiX8XcX| 2.xX8XqXqXqXqXqXqX>XqX0XyXrX5XuX0XkXs.{ UXKXUXUXUXUXIXUXxXGXiX9XqXqX", "qX0XaX).z uX0X0XqXwX0X7XcX| 2.xX8XqXqXqXqXqXqX>X0XqX0XqXwX0X8XlXs.{ UXKXUXUXUXUXIXUXxXGXiX9XqXqX", "qX0XaX).z uX0XqXqXqXqX7XcX| 2.xX8XqXqXqXqXqXqX>X0XqXqXqXqXqX8XlXs.{ UXKXUXUXUXUXIXUXxXGXiX9XqXqX", "qX0XaX).z uX0XqXqXqXqX7XcX| 2.xX8XqXqXqXqXqXqX>X0XqXqXqXqXqX8XlXs.{ UXKXUXUXUXUXIXUXxXGXiX9XqXqX", "qX0XaX).z yX0X0XqXqXqX7XxX| <.kX5X8X8X8X8X8X9X;X0XqXqXqXqXqX8XlXs.[ UXGXLXLXLXLXKXUXkXFXiX9XqXqX", "qX0XaX).x pXwXeXeXeXeX9XbX .0.FXsXhXhXhXhXhXhX0XeXeXeXeXeXeX0XxXd.} UXKXUXUXUXUXIXUXbXHXiX0XqXqX", "qX0XaX_.j 5X,X,X,X,X,X;XyX+.1 H V C C C C C N K %X2X,X,X,X,X:XeXj.> ! P I I I I I Y F -XsX9XqXqX", "qX0XaX_.x eX7X7X8X8X8X7XwX|.A.G.F.F.F.F.F.H.C.y #XwX7X8X8X8X7XqX&XZ.S.A.A.A.A.A.Z.U.a XXzX7XqXqX", "qXqXwX6X#XeXwXwXwXwXwXwXwXtXdXgXgXgXgXgXgXgXfX&X9XeXwXwXwXwXwXwXeXsXhXgXgXgXgXgXgXkX:X9XrX0XqXqX", "qXqXqXwXyXqXqXqXqXqXqXqXqX0X9X9X9X9X9X9X9X9X9XyXwXqXqXqXqXqXqXqX0X9X9X9X9X9X9X9X9X8XtXwX0XqXqXqX", "qXqXqXqX0XqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqX0XqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqX0XqXqXqXqXqX", "qXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqX" }; const char *const *const xpm_icons[] = { xpm_icon_0, xpm_icon_1, xpm_icon_2, }; const int n_xpm_icons = 3; puzzles-20170606.272beef/icons/flood-icon.c0000644000175000017500000004225013115373752017206 0ustar simonsimon/* XPM */ static const char *const xpm_icon_0[] = { /* columns rows colors chars-per-pixel */ "16 16 240 2 ", " c #D5D5D5", ". c #D0CFC9", "X c #CFCEC4", "o c #CFCEC5", "O c #CFCEC5", "+ c #CFCEC5", "@ c #CFCEC5", "# c #CFCEC5", "$ c #CFCEC5", "% c #D0CEC4", "& c #C9CCCF", "* c #C3CBD2", "= c #CCCAD2", "- c #D3C3D2", "; c #D2C9D2", ": c #D5D6D5", "> c #5663BC", ", c #4153DA", "< c #4657D4", "1 c #4557D6", "2 c #4657D4", "3 c #4958D1", "4 c #4857D2", "5 c #4758D4", "6 c #3B53DA", "7 c #9B694A", "8 c #E9781D", "9 c #739029", "0 c #0DDB1D", "q c #47C046", "w c #D8CFD8", "e c #CFCEC5", "r c #4254D5", "t c #2945FF", "y c #2F49FD", "u c #2F49FF", "i c #2C49FF", "p c #1E45FF", "a c #2145FF", "s c #314BFE", "d c #2043FF", "f c #AE6836", "g c #FF8000", "h c #74A005", "j c green", "k c #2DDC29", "l c #D9CBD9", "z c #4657D4", "x c #2F49FF", "c c #364DF7", "v c #334DFF", "b c #4349C8", "n c #8D585A", "m c #7D536A", "M c #3549EB", "N c #2F4BFF", "B c #5E4E92", "V c #885471", "C c #476277", "Z c #0C8870", "A c #3E877B", "S c #D7D2D3", "D c #4557D5", "F c #2F49FF", "G c #334DFA", "H c #2149FF", "J c #504EA9", "K c #FF8E00", "L c #E37F0B", "P c #3447E2", "I c #334DFF", "U c #2B4AFD", "Y c #2349FF", "T c #2D4AFE", "R c #283FFF", "E c #4A5ADE", "W c #D6D5CB", "Q c #4349C8", "! c #544EAE", "~ c #654474", "^ c #E05300", "/ c #C34D0D", "( c #3345E1", ") c #324DFF", "_ c #364BF7", "` c #354EFF", "' c #4041CB", "] c #522E9F", "[ c #65509F", "{ c #D4D6D0", "} c #4858D2", "| c #1F45FF", " . c #895964", ".. c #FF8E00", "X. c #D95505", "o. c #F80000", "O. c #E20407", "+. c #3445E2", "@. c #3350FF", "#. c #364CF9", "$. c #2454FF", "%. c #7B2677", "&. c red", "*. c #DB2A2D", "=. c #CBD9D9", "-. c #CFCEC5", ";. c #4858D2", ":. c #2146FF", ">. c #7D536A", ",. c #F37E00", "<. c #C34D0C", "1. c #E90000", "2. c #D30807", "3. c #323CCC", "4. c #3045ED", "5. c #3642DE", "6. c #2948F2", "7. c #71246C", "8. c #F10000", "9. c #C6302F", "0. c #CDD8D8", "q. c #4557D5", "w. c #2E49FF", "e. c #3549E9", "r. c #2D46EE", "t. c #524698", "y. c #F07300", "u. c #D1650B", "i. c #6F0695", "p. c #6902B1", "a. c #AA0828", "s. c #FB0000", "d. c #6B5C08", "f. c #00F500", "g. c #32C62C", "h. c #D8CDD8", "j. c #4557D5", "k. c #2E49FF", "l. c #364EFA", "z. c #2A4CFF", "x. c #564DA9", "c. c #FF8400", "v. c #E57408", "b. c #7E0497", "n. c #7800B4", "m. c #C00423", "M. c #756404", "N. c #2DDA29", "B. c #CFCEC5", "V. c #4559D3", "C. c #2D4CFF", "Z. c #344DF9", "A. c #324CFF", "S. c #3949DF", "D. c #5B4F9F", "F. c #544CA7", "G. c #3B35C8", "H. c #3A29D4", "J. c #31782E", "K. c #3BB400", "L. c #297544", "P. c #1861B0", "I. c #41759B", "U. c #D7D3D0", "Y. c #CFCFC5", "T. c #484ED5", "R. c #323BFF", "E. c #3649FD", "W. c #344DFF", "Q. c #2F4BFF", "!. c #1C3EFF", "~. c #2041FF", "^. c #3054FE", "/. c #3243FF", "(. c #0BB63A", "). c #198A67", "_. c #3824FF", "`. c #5155DA", "'. c #D6D6CB", "]. c #D1CBCC", "[. c #348078", "{. c #118B6D", "}. c #285FB3", "|. c #3347FF", " X c #3F54CD", ".X c #818A6A", "XX c #737D79", "oX c #354CEB", "OX c #3044FF", "+X c #4E7D37", "@X c #71AE00", "#X c #3A8132", "$X c #0B8579", "%X c #3C8B79", "&X c #D7D2D3", "*X c #D2C5D2", "=X c #22D325", "-X c #188673", ";X c #2733FF", ":X c #5166A5", ">X c yellow", ",X c #E3E40A", " , < 1 2 3 4 5 6 7 8 9 0 q w ", "e r t y u i p a s d f g h j k l ", "o z x c v b n m M N B V C Z A S ", "O D F G H J K L P I U Y T R E W ", "+ 2 i Q ! ~ ^ / ( ) _ ` ' ] [ { ", "@ } | ...X.o.O.+.@.#.$.%.&.*.=.", "-.;.:.>.,.<.1.2.3.4.5.6.7.8.9.0.", "O q.w.e.r.t.y.u.i.p.a.s.d.f.g.h.", "O j.k.l.z.x.c.v.b.n.m.&.M.j N.l ", "B.V.C.Z.A.S.D.F.G.H.J.K.L.P.I.U.", "Y.T.R.E.W.Q.!.~.^./.(.j )._.`.'.", "].[.{.}.|. X.XXXoXOX+X@X#X$X%X&X", "*X=Xj -X;X:X>X,X c #744C55", ", c #784D54", "< c #70474C", "1 c #5F6858", "2 c #737B55", "3 c #564165", "4 c #684964", "5 c #654563", "6 c #774E68", "7 c #4A7B68", "8 c #71636F", "9 c #777B68", "0 c #B60000", "q c #A70105", "w c #992300", "e c #B62B01", "r c #BE2A00", "t c #C80207", "y c #D30101", "u c #DB0000", "i c #E00000", "p c #FE0101", "a c #F60505", "s c #AF5900", "d c #B55902", "f c #966030", "g c #A56B31", "h c #B27431", "j c #CE6B03", "k c #C56707", "l c #D36B00", "z c #DC6D02", "x c #D16700", "c c #D27100", "v c #DF7300", "b c #E06C00", "n c #E06600", "m c #E97200", "M c #F67E07", "N c #FB7D03", "B c #860146", "V c #A34242", "C c #B54243", "Z c #B77E43", "A c #A87242", "S c #05A204", "D c #02A00C", "F c #328C32", "G c #2FA830", "H c #31A331", "J c #3BB63B", "K c #26A226", "L c #04C302", "P c #03CA01", "I c #09C804", "U c #05C709", "Y c #01D304", "T c #01DD01", "R c #00E401", "E c #06F706", "W c #01FE01", "Q c #118258", "! c #449E44", "~ c #42A342", "^ c #43B543", "/ c #42BB42", "( c #619661", ") c #72A772", "_ c #A7A804", "` c #BCBC3B", "' c #F78604", "] c #FE8302", "[ c #FF8A00", "{ c #D3D302", "} c #C5C60A", "| c #FEFE02", " . c #F6F708", ".. c #A2A242", "X. c #B7B743", "o. c #3A198E", "O. c #1E38BB", "+. c #2335B0", "@. c #441A9A", "#. c #6B0093", "$. c #6E009A", "%. c #64009E", "&. c #433D8C", "*. c #4115A4", "=. c #7F01AF", "-. c #7B01BD", ";. c #444B96", ":. c #5E6388", ">. c #414DA4", ",. c #4752A3", "<. c #4853A3", "1. c #4151AB", "2. c #575DA8", "3. c #555EA3", "4. c #575FBA", "5. c #5A66B5", "6. c #5766BA", "7. c #2E3FC8", "8. c #2C3CC6", "9. c #293FD4", "0. c #2F3EDE", "q. c #243ADB", "w. c #1C39F0", "e. c #2434E3", "r. c #263DE0", "t. c #2E3DE0", "y. c #2F3DEB", "u. c #283BFF", "i. c #7E00C6", "p. c #2844C6", "a. c #2D42DB", "s. c #2941D8", "d. c #1944FF", "f. c #2643E0", "g. c #2C45EB", "h. c #2446FF", "j. c #2D47FF", "k. c #2649FF", "l. c #2B4AFF", "z. c #3149F6", "x. c #3443FF", "c. c #3840FE", "v. c #344DFE", "b. c #384DF8", "n. c #2652FF", "m. c #2C51FE", "M. c #3651FE", "N. c #3850FC", "B. c #3450F6", "V. c #8600AB", "C. c #8600B7", "Z. c #8A00C1", "A. c #D6D4C7", "S. c #D6D5CC", "D. c #D7CFD7", "F. c #DAC7DA", "G. c #D9CAD9", "H. c #C7D0DB", "J. c #C9D1DA", "K. c #D3D4D3", "L. c #D9D6D4", "P. c #D4D9D4", "I. c #D5D5D9", "U. c #DDDDDE", "Y. c #E0DED2", "T. c #E3DBDE", "R. c #DCE2DE", "E. c #E1E0D4", "W. c #D2D2E4", "Q. c #D2DBE4", "!. c #E4D3E4", "~. c #E1D8E1", "^. c #D3E4E4", /* pixels */ "K.K.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.I.P.K.L.L.L.P.L.P.P.L.K.K.", "K.I.S.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.A.S.J.J.H.J.G.F.F.F.I.K.L.", "I.S.:.>.<.,.,.,.<.,.,.,.,.<.,.,.,.,.<.1.3 h g g f F G H K ( ~.K.", "I.A.,.h.j.j.x.j.j.j.j.j.j.j.j.j.j.j.j.h.4 ] N ] b P W W W ^ !.K.", "I.A.<.j.N.v.v.v.v.v.v.v.v.b.b.b.v.v.b.l.4 N M ] z I W E W ^ !.K.", "I.A.<.j.v.v.v.v.v.v.v.v.M.v.v.b.v.v.v.k.4 [ ' [ b P W E W ^ !.K.", "I.A.,.j.v.v.v.v.v.v.v.a.7.7.p.p.z.v.v.l.3 x k j d D Y U P ~ ~.K.", "I.A.,.j.v.j.v.v.v.v.k.: m z m d 9.v.v.v.g.q.f.r.r.0.t.0.e.2.L.K.", "I.A.,.j.v.v.j.v.v.v.k.> [ ] [ l 9.v.v.v.v.v.M.v.v.M.M.M.l.5.Y.K.", "I.A.<.j.v.v.v.v.v.b.l.> ] ' N x 9.v.v.v.v.v.v.v.v.v.b.b.h.5.L.D.", "I.A.,.j.v.v.v.h.h.l.d.: [ ' [ c 9.v.v.v.v.v.v.v.v.l.n.n.d.6.E.P.", "I.A.<.j.b.v.s.: , , : . r e r w 9.v.v.v.v.v.v.v.g.+ # # @ 6 R.K.", "I.A.<.j.b.v.7.v [ ] [ e p p p y 9.M.v.v.v.v.v.v.f.t p a p C ^.K.", "I.A.<.j.v.M.7.z ] N ' e p p p y 9.v.j.v.v.v.x.v.f.t p a p C ^.S.", "I.A.,.j.v.M.p.m [ ] [ e p p p y s.M.v.M.v.M.v.M.f.t p p p C ^.D.", "I.A.,.j.z.M.7.d z x c w y y y 0 +.a.9.9.9.9.s.a.O.q i y y V ^.K.", "I.A.<.j.v.l.z.9.9.s.q.$ z x z s % $.#.%.X u y u 0 S R Y Y ~ !.S.", "I.A.<.j.v.v.v.v.M.M.h.> [ ' [ l $.C.C.Z.B p p p i I W W W ^ ~.K.", "I.A.,.j.v.v.v.v.v.v.k.> ] M ] j %.=.=.i.B p a p u I W E W ^ !.K.", "I.A.,.j.v.v.v.v.v.v.h.> [ ] [ l #.C.V.-.B p p p i P W E W ^ W.K.", "I.A.,.j.v.v.v.v.v.v.l.&.< > , : o.@.@.*. O O O o & Q * * 7 T.S.", "I.A.,.j.v.v.j.v.v.v.v.j.h.k.k.l.m.M.B.x.= W W W T 8.c.x.u.4.Y.K.", "I.A.<.j.v.v.j.v.v.v.v.v.v.b.v.v.v.v.v.u.= W E W T p.M.B.l.5.Y.K.", "I.A.<.j.M.M.M.v.v.v.v.v.b.v.b.v.v.v.v.x.= W W W T p.M.N.l.5.L.D.", "I.S.;.e.f.t.t.v.v.v.v.g.q.r.r.r.v.v.v.x.- R T R S +.y.t.e.2.E.K.", "P.D.F P U Y D t.M.z.k.1 { } { _ 9.v.z.l.3 l k j s S Y U P ! !.K.", "P.F.H W W W U 0.M.v.u.2 | | | { 9.v.v.k.4 [ ] ] m Y W W W ^ !.K.", "P.G.H W E W U t.M.N.d.2 | .| { s.M.b.l.4 [ ' ] v P W E W ^ !.K.", "P.F.H W E W U q.j.j.u.2 | | | { q.j.z.u.4 N N ] n P W E W ^ !.K.", "K.D.( J ^ / ! 2.5.5.4.9 ` X.X...3.5.6.6.8 h Z Z A ! / ^ J ) U.K.", "K.K.T.!.!.W.!.R.L.Y.Y.U.W.W.W.W.Y.Y.P.L.T.Q.Q.Q.Q.!.!.!.!.~.K.K.", "I.K.K.S.K.K.S.K.K.K.I.K.S.K.K.K.K.P.K.P.K.S.K.K.S.P.K.K.K.K.K.K." }; /* XPM */ static const char *const xpm_icon_2[] = { /* columns rows colors chars-per-pixel */ "48 48 183 2 ", " c #1E331B", ". c #6C1502", "X c #77010F", "o c #5D072B", "O c #6D113B", "+ c #70153E", "@ c #593734", "# c #6A3930", "$ c #531A0D", "% c #214803", "& c #127412", "* c #316900", "= c #347100", "- c #0A7932", "; c #0B7731", ": c #2A792C", "> c #0D5632", ", c #7A4300", "< c #54433D", "1 c #6D423A", "2 c #65423B", "3 c #744532", "4 c #744639", "5 c #654B2C", "6 c #6D733C", "7 c #626738", "8 c #1E2374", "9 c #383868", "0 c #52007A", "q c #483969", "w c #0A415C", "e c #17536C", "r c #52556A", "t c #9A1D00", "y c #950400", "u c #A70900", "i c #A80401", "p c #B30202", "a c #BE0100", "s c #A21D00", "d c #830123", "f c #DC0000", "g c #D70101", "h c #E10000", "j c #ED0000", "k c #FE0101", "l c #934901", "z c #9D5000", "x c #A75C01", "c c #AA5C02", "v c #B25A03", "b c #B75B02", "n c #A86001", "m c #85582B", "M c #CA6900", "N c #D16701", "B c #D96D00", "V c #DB7400", "C c #E16101", "Z c #EC6E01", "A c #F26700", "S c #FC7E01", "D c #FE7400", "F c #877774", "G c #9A7070", "H c #08AA01", "J c #02AA08", "K c #01A602", "L c #01BA01", "P c #07B500", "I c #2D842D", "U c #01C200", "Y c #00CD00", "T c #00DC01", "R c #01E301", "E c #00EE00", "W c #03F601", "Q c #02FE01", "! c #07FF07", "~ c #708E70", "^ c #709570", "/ c #709A70", "( c #6B956C", ") c #9C9B03", "_ c #B2B205", "` c #A6A603", "' c #F48301", "] c #FE8401", "[ c #FF8B01", "{ c #F68B00", "} c #DEDC02", "| c #E0DF00", " . c #EDEC01", ".. c #FDFD02", "X. c #888875", "o. c #9A8570", "O. c #9A9A70", "+. c #9C916E", "@. c #2A1C8D", "#. c #162A98", "$. c #2E208D", "%. c #302A8D", "&. c #223AA7", "*. c #2933A8", "=. c #243BAA", "-. c #2838A8", ";. c #2535B2", ":. c #2437BA", ">. c #2838BB", ",. c #1A34A9", "<. c #5F008F", "1. c #6A008D", "2. c #60009C", "3. c #720191", "4. c #6A00A6", "5. c #7F00A4", "6. c #7F00B1", "7. c #7000B7", "8. c #3D4683", "9. c #374385", "0. c #747B86", "q. c #787C9A", "w. c #767A97", "e. c #1724C9", "r. c #1E39D5", "t. c #1E3BDD", "y. c #1E34DD", "u. c #2B34D5", "i. c #223CDC", "p. c #2B39D7", "a. c #283CC9", "s. c #1239EA", "d. c #133AFA", "f. c #122CF7", "g. c #233BED", "h. c #2B35E5", "j. c #233EFE", "k. c #343BFF", "l. c #3133E4", "z. c #7501C0", "x. c #1E42DC", "c. c #2243DD", "v. c #1C40FF", "b. c #2446FF", "n. c #244DFF", "m. c #2D49FF", "M. c #2943FC", "N. c #3149F5", "B. c #3544FF", "V. c #334CFE", "C. c #394DFE", "Z. c #3047F1", "A. c #3551FF", "S. c #3952FF", "D. c #254AF7", "F. c #8501A7", "G. c #8201B4", "H. c #8602BB", "J. c #8C03C2", "K. c #818F81", "L. c #ABB2AB", "P. c #D2D0C5", "I. c #D2D1CC", "U. c #C4CDD5", "Y. c #CACFD5", "T. c #D5C5D5", "R. c #D2CFD2", "E. c #D4D4D4", "W. c #D9D7D5", "Q. c #D5D9D5", "!. c #D6D6D9", "~. c #CED1D2", "^. c #E7E6DF", "/. c #DFDFEA", "(. c #E9DFE9", "). c #E1DFE1", "_. c #DFE4EA", "`. c #E7E6E1", "'. c #E8E7E2", "]. c #E1E3E9", "[. c #E9E0E9", "{. c #E1E9E9", "}. c #E5E9E7", /* pixels */ "E.E.E.E.!.E.W.E.E.Q.E.E.!.E.!.E.Q.E.E.E.E.E.E.E.E.E.W.E.E.E.!.E.E.E.!.E.E.E.Q.E.E.E.E.E.!.E.E.E.", "E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.E.W.E.!.E.E.E.!.E.E.E.!.E.E.W.E.E.E.E.E.E.!.E.E.E.!.E.W.E.E.Q.E.", "E.!.E.W.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.!.W.W.W.W.W.W.W.Q.Q.Q.E.Q.!.W.E.E.E.", "E.E.E.E.I.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.P.~.U.U.U.U.U.Y.T.T.T.T.T.T.E.E.E.E.E.", "E.E.!.I.r 9.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.8.9.< m m m m m 5 : I I I I & K.(.E.W.E.", "E.E.!.P.8.b.m.V.m.m.m.m.m.m.m.m.m.m.m.m.m.m.m.V.m.m.m.m.V.v.3 ] S S S ] c T Q Q Q ! W / (.E.E.E.", "E.W.!.P.8.m.C.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.S.b.3 ] S S S ] x T Q Q Q ! E / (.~.E.E.", "E.E.W.P.8.m.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.b.3 ] S ] S ] c T Q Q Q Q E / (.~.E.E.", "!.E.!.P.8.m.V.V.V.V.V.V.V.V.V.V.V.V.N.A.V.V.V.V.V.V.V.V.V.b.3 ] S S S ] x T Q Q Q ! R / (.~.!.E.", "E.E.!.P.8.m.V.V.V.V.V.V.V.V.V.V.V.A.S.A.V.S.V.C.V.V.V.V.V.b.3 [ ] ] ' [ n T Q Q Q Q W / (.E.E.W.", "!.E.!.P.8.m.V.V.V.V.V.V.V.m.V.V.V.a.:.:.:.:.:.:.N.V.V.V.V.b.@ M b b b M , K L L L L K ~ [.~.E.E.", "E.E.!.P.8.V.V.V.m.V.V.V.V.V.V.C.b.@ C N N N V l i.S.V.V.V.V.i.r.r.r.r.r.i.u.u.u.u.p.e.w.'.I.E.E.", "W.E.!.P.8.m.V.V.V.V.V.V.V.V.V.C.b.1 [ ] ] ] [ v i.V.V.V.V.V.V.S.V.C.S.V.V.S.S.V.S.S.D.w.^.~.E.E.", "E.E.!.P.8.m.V.V.V.V.V.V.V.V.V.C.b.1 ] ' S S ] v t.V.V.V.V.V.V.V.V.V.V.V.V.V.V.N.V.V.g.q.^.~.E.E.", "E.E.!.P.8.m.V.V.V.V.V.V.V.V.V.C.b.1 ] S S S ] c t.C.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.S.g.q.`.E.E.E.", "E.!.!.P.8.m.V.V.V.V.V.V.V.V.V.C.b.1 ] S ] S ] v t.S.V.V.V.V.V.V.V.V.V.V.V.V.C.C.C.C.g.w.`.E.E.E.", "E.E.!.P.8.m.V.V.V.V.S.b.b.b.b.M.v.2 ] ' ' ' ] n t.S.V.V.V.V.V.V.V.V.V.V.V.n.n.n.n.n.v.w.`.E.E.E.", "E.E.!.P.8.m.S.V.V.S.a.@ 1 1 1 1 2 $ t t t t s . i.S.V.V.V.V.V.V.V.V.V.S.>.o + O O + O r }.I.E.E.", "E.E.!.P.8.m.V.V.V.V.:.N [ ] ] ] { t k k k k k p x.V.V.V.V.V.V.V.V.V.V.A.-.h k k k k k G _.E.E.E.", "!.E.!.P.8.m.V.V.V.S.:.N ] S ] S ' t k k k k k p x.S.V.V.V.m.V.V.N.m.V.A.*.f k k k k j G {.E.W.E.", "E.E.!.P.8.m.V.V.m.S.:.N ] ] S S ' t k k k k k p x.C.V.V.V.V.V.V.V.V.V.A.*.h k k k k j G }.Q.!.E.", "E.E.!.P.8.m.V.V.N.S.:.N ] ] S S ' t k k k k k p x.C.V.m.V.V.N.V.V.V.N.V.*.f k k k k j G {.E.E.E.", "E.!.!.P.8.m.V.V.m.S.:.N [ ] ] ] { t k k k k k p x.S.V.S.A.S.V.S.S.S.V.S.*.h k k k k j G {.I.E.E.", "E.E.!.P.8.m.V.A.N.S.:.l b v v v c . a p p p a X #.;.;.;.;.;.;.;.;.;.-.>.8 y p p u p u F {.E.E.E.", "Q.E.!.P.8.m.V.V.V.V.N.t.t.t.t.i.s.@ V M M M V l 0 3.1.1.1.1.X h g g g h y U R T T R Y ^ [.~.E.E.", "E.E.!.P.8.m.V.V.V.V.V.S.S.S.C.S.n.1 ] ] [ ] [ v 4.J.H.H.H.z.d k k k k k u R Q Q Q ! E / [.E.!.E.", "!.E.!.P.8.m.V.V.m.V.V.V.V.V.m.C.b.1 ] S ] S ] v 2.H.6.6.G.7.d k k k k k u R Q Q Q Q E / [.I.E.W.", "E.W.!.P.8.m.V.V.V.V.V.V.V.V.V.V.b.1 ] S ] S ] v 2.G.6.6.G.7.d k k k k k u R Q Q Q ! E / [.~.E.E.", "W.E.!.P.8.m.V.V.V.V.V.V.V.V.V.V.b.1 ] ' ] S ] v 2.H.6.6.H.7.d k k k k k u R ! Q Q ! E / (.~.E.E.", "E.E.!.P.8.m.V.V.V.V.V.V.V.V.V.S.b.1 ] S S ] ] v <.G.5.5.F.4.d k k k k k u R Q Q Q Q W / (.~.E.E.", "E.E.!.P.8.m.V.V.V.m.V.V.V.V.V.V.A.%.q q q q q 9 $.$.$.$.$.@. = * * * = % w e e e e w 0.'.E.E.E.", "!.E.!.P.8.m.V.V.V.V.V.V.V.V.V.m.A.V.m.m.n.m.m.A.n.A.A.A.A.B.- Q Q Q Q Q J l.C.B.B.B.g.w.`.E.E.E.", "E.W.!.P.8.m.V.V.V.V.V.V.V.V.V.V.V.V.N.V.C.N.N.V.V.V.V.V.A.k.- Q Q Q W Q J p.A.N.A.A.g.q.^.E.E.E.", "E.E.!.P.8.m.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.V.k.- Q Q Q Q Q J l.A.A.V.S.g.q.^.E.E.E.", "E.E.!.P.8.m.V.N.V.m.N.V.V.V.V.m.V.V.V.N.V.N.V.V.V.V.V.V.A.k.- Q W Q W Q J l.S.N.m.S.s.q.^.E.E.E.", "!.E.!.P.8.V.S.V.V.S.S.V.V.V.V.V.V.V.A.S.S.A.A.A.V.V.m.V.A.k.- Q Q Q Q Q J h.A.V.S.S.g.q.^.E.E.W.", "E.E.!.I.9 ,.=.=.&.&.&.Z.V.V.V.V.V.>.-.-.-.-.-.-.N.V.V.V.A.B.> P H H H P & #.=.=.=.=.#.0.`.E.E.E.", "E.Q.Q.T.: R T R T R K u.A.V.m.S.j.7 .} .| .) y.S.m.V.V.b.# A B C C A l U R T T R Y ^ [.~.E.E.", "E.!.Q.T.I Q Q Q Q Q L u.V.V.V.S.j.6 .........._ y.S.V.V.V.b.3 [ S ] ] [ x T ! Q Q ! E / [.~.E.E.", "W.E.Q.T.I Q Q Q Q Q L u.A.V.V.S.j.7 .........._ y.S.V.V.C.b.3 ] S S S ] x T Q Q Q ! E / [.E.E.E.", "E.E.Q.T.I Q Q Q Q Q L u.S.N.V.S.j.6 .........._ y.S.V.V.S.b.3 ] S S ] ] x T Q Q Q Q E / [.~.E.E.", "E.E.Q.T.I Q ! ! Q Q L u.S.S.S.S.j.6 .........._ i.S.C.V.S.n.3 ] ] ] ] ] n T ! Q ! ! E / [.E.E.E.", "Q.E.Q.T.: Q E E R Q P e.M.g.g.g.f.7 .. . . ...` e.M.g.g.g.d.# D Z Z Z S z Y Q R E W T ^ ].E.E.E.", "E.E.E.R.K.( / / / / ~ w.w.q.q.q.w.X.O.O.O.O.O.X.w.w.q.q.q.w.F o.o.o.o.o.F ^ / / / / ( L.).E.E.E.", "W.E.E.E.].(.(.[.[.[.[.`.^.^.^.`.^.].)././.)./.].^.^.^.^.`.^.]._._._._._.].[.[.[.(.(.[.).E.E.W.E.", "E.!.E.E.E.I.I.~.~.~.E.E.~.E.~.~.E.E.E.E.E.E.I.E.~.E.~.~.E.E.E.I.E.R.I.E.I.E.E.~.~.~.E.E.E.E.E.E.", "E.E.E.E.Q.E.W.E.E.E.!.E.E.E.E.E.E.E.E.E.E.E.E.W.E.E.E.E.W.E.E.Q.!.E.E.E.E.E.E.E.E.E.E.W.E.E.E.E.", "E.W.E.!.E.E.E.E.E.E.E.E.W.E.E.E.E.E.!.E.E.E.!.E.E.E.E.E.E.E.!.E.E.E.E.E.E.E.W.E.E.E.E.!.E.E.E.W." }; const char *const *const xpm_icons[] = { xpm_icon_0, xpm_icon_1, xpm_icon_2, }; const int n_xpm_icons = 3; puzzles-20170606.272beef/icons/flip-icon.c0000644000175000017500000004704713115373752017046 0ustar simonsimon/* XPM */ static const char *const xpm_icon_0[] = { /* columns rows colors chars-per-pixel */ "16 16 256 2 ", " c black", ". c #010101", "X c #020202", "o c gray1", "O c #040404", "+ c gray2", "@ c #060606", "# c #070707", "$ c gray3", "% c #090909", "& c gray4", "* c #0B0B0B", "= c #0C0C0C", "- c gray5", "; c #0E0E0E", ": c gray6", "> c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", "XAXGXP.", "M.Y H Y V 0.%...U.zXVXUXJXUXGXI.", "Z.f.s.p.y.l._.jXSX3X0XCXFXFX7XF.", "L.cXBXAXPXhXNX,Xd.X.3XlX[.1.5.Y.", "L.pXpXrXBXdX:X&.~ d.SXY.o.L _.~.", "J.dXMX8XsXcXg.~ &.,XkX+.] 3.aXL.", "H.mXIXMXAX0X..g.;XNXQ.[ S.wXdXJ.", "C.p.u.s.i.V.0XcXgXiX,XvXJXZXzXL.", "M.T J Y M i.AXdXZXCXvXUXHXUXGXI.", "N.( O.e.Y s.MX8XyXzXbXLX>XAXHXP.", "N.~ / O.J u.LXmXdXhXNXUXxXKXHXP.", "N.] ~ ( T p.MXfXsXaXzXJXJXJXVXP.", "A.N.N.N.M.C.H.J.L.K.L.I.P.I.P.D." }; /* XPM */ static const char *const xpm_icon_1[] = { /* columns rows colors chars-per-pixel */ "32 32 256 2 ", " c black", ". c #010101", "X c #020202", "o c gray1", "O c #040404", "+ c gray2", "@ c #060606", "# c #070707", "$ c gray3", "% c #090909", "& c gray4", "* c #0B0B0B", "= c #0C0C0C", "- c gray5", "; c #0E0E0E", ": c gray6", "> c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", ".U Q.VXuXLXUXHXfX7XZXUXUXKXI.Z.", "F.M.~ W R ! | ^ R ! K *XD.J Y Q ] q.aXxXpXLXUXUXFXbXJXUXUXKXI.Z.", "F.M./ Q ! Q W Q ! ! T )...D ..n..z.[ G Q.mXJ.Z.", "Z.L.gXdXVXpX/.tXxXaXhXyXpX..} u.a.( m.VX0XmXn.Q <.x._ ` pXkXK.Z.", "Z.P.iXcXUXSXcXCXlXfXgXgX^.K / } ( ! c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", "X0.5XUXPXUXUXPXY.C.D.S.", "S.S.F.m.! W E ) +.3.7.3.+._ E Q I .XFX~.L o.*.8.8.;.` b.NXlXwXJXUXUXAXhX4X;XiXUXIXUXUXPXY.C.D.S.", "S.S.F.m.! E W W U O.{ +.U E W Q I oXBX2.P T _ +.O.Q L XkXMXfXdXgX8XxXcX7.X.O.M.M.X.%.W ;XNX7XsXBX{.] O.8.K.,.T L d.MXhXP.Z.S.S.", "S.S.Z.P.kXfXsXBXjX2Xm.>XzXjXtXxXdX7XNX;XQ %.X.M.M.O.X.7.xXxX8XsXMXw.) +.7.K.,.U E @XMXgXP.Z.S.S.", "S.S.Z.P.zXeXmXUXDXuXCXyXPXjXuXvXdX7XVXc.J / o.X.O.@.P ).MXzX7XlX5X^ W _ *.] %.H >.lXzXjXP.Z.S.S.", "S.S.Z.I.hXeXIXIXUXcXdXvXHX0XlXxXdXqXiX} T E / %.X.P -.sXzXxX6XvXA.K ~ T o.#._ U (.MXkXjXP.Z.S.S.", "S.S.Z.Y.tXkXUXIXUXPXbXuX0XgXzXzXaXiX!.P ^ T J W 6.(.aXxXkXxX0XtX#.R Q P L X.m.1XxXkXzXjXP.Z.S.S.", "S.S.Z.U.8XHXUXSXfX0XwXdXzXkXjXkXsX0X2.D L { x.-XxXNXzXkXkXlXuX^.K L E 3.^.iXNXbXkXkXlXjXP.Z.S.S.", "S.S.A.F.gXJXhXpXkXMXVXNXMXMXMXMXVXE.W 1.Q.uXVXNXxXzXxXxXxXMXeX=._ c.-XvXVXvXlXzXxXxXcXlXI.Z.S.S.", "S.S.S.A.Q.(.}.@X@XoXoXoXOXOXoXoX+XA.E.9XiXwX7X7X8X8X9XqX9X4X{.Z.:XaXpXwX0XqXwXwXwXwXeXqXL.Z.S.S.", "S.S.F.m.T Y Y I I I I I I I U Y G +XVXsXaXdXdXdXgXhXaX0X6XuX$XKXIXGXGXHXJXJXJXJXJXHXJXFXY.C.D.S.", "S.S.F.m.~ W Q Q Q Q ! Q Q Q Q ! Y oXMXkXzXzXvXxXdXrXyXvXUXCXXuXcXLXqXcXwXJXUXUXAXhX4X;XiXUXIXUXUXPXY.C.D.S.", "S.S.F.m.! W T .| 3.'.7.{ X.T ! I oXVXeXcXdXCXm.m.CXdXxXtXbXwXJXUXUXzXmX>X0.5XUXPXUXUXPXY.C.D.S.", "S.S.F.m.! W E ( O.2.3.3.O.) E Q I oXNX9XPXbXuX2X2XyXnXyXgXcXwXJXUXUXSXjX5X2XpXUXIXUXUXPXY.C.D.S.", "S.S.F.m.! E W W I O.| +.U E W Q I @XkXsXUXUXZXjXlXFXZXqXxXzXwXJXUXUXIXUXgXbXhXUXIXUXUXPXY.C.D.S.", "S.S.F.m.! E W W W ( .) W W W Q I @XpXZXUXIXUXVXlXhX9XhXlXxXwXJXUXUXIXUXDXcXFXUXUXUXUXPXY.C.D.S.", "S.S.F.m.! W W W W E T E W W W Q Y |.fXUXUXIXBXdXrXiXlXzXkXxXwXHXUXUXUXUXUXUXUXUXUXIXUXLXY.C.D.S.", "S.S.F.n.Q E W E E W W W E E W W Y (.HXLXzXrXeXfXxXcXzXlXlXcXeXHXUXUXUXUXUXUXUXUXUXUXUXPXY.C.D.S.", "S.S.F.m.^ Q ! ! ! ! ! ! ! ! ! ~ T W.jX8XtXhXzXkXjXjXjXjXjXlXqXFXIXLXPXPXPXPXPXPXPXLXPXJXY.C.D.S.", "S.S.S.A.m.n.m.m.m.m.m.m.m.m.m.m.m.A.F.U.Y.I.P.P.P.P.P.P.P.I.L.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.Y.D.S.S.S.", "S.S.S.S.F.F.F.F.F.F.F.F.F.F.F.F.F.S.A.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.Z.C.C.C.C.C.C.C.C.C.C.C.C.C.S.S.S.S.", "S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.D.D.D.D.D.D.D.D.D.D.D.D.D.S.S.S.S.", "S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S.S." }; const char *const *const xpm_icons[] = { xpm_icon_0, xpm_icon_1, xpm_icon_2, }; const int n_xpm_icons = 3; puzzles-20170606.272beef/icons/filling-icon.c0000644000175000017500000002532713115373752017535 0ustar simonsimon/* XPM */ static const char *const xpm_icon_0[] = { /* columns rows colors chars-per-pixel */ "16 16 256 2 ", " c #E2E2E2", ". c #DADADA", "X c #DDDDDD", "o c #DDDDDD", "O c gainsboro", "+ c #DDDDDD", "@ c #DFDFDF", "# c gray84", "$ c gray79", "% c #CBCBCB", "& c #CBCBCB", "* c #CECECE", "= c gray81", "- c #CDCDCD", "; c #D7D7D7", ": c #E7E7E7", "> c #C5C5C5", ", c #A5A5A5", "< c #E1E1E1", "1 c #D2D2D2", "2 c #BCBCBC", "3 c gray82", "4 c #D7D7D7", "5 c gray71", "6 c #9F9E9F", "7 c #B5B1B5", "8 c gray60", "9 c #767676", "0 c #A2A2A2", "q c #9A9A9A", "w c #868686", "e c gray90", "r c gray75", "t c gray", "y c gray64", "u c #BCBCBC", "i c #DADADA", "p c #E7E7E7", "a c #ECECEC", "s c #DAD8DA", "d c #DDE2DD", "f c #90CE90", "g c #CDD3CD", "h c #ABA9AB", "j c #ACACAC", "k c #B7B7B7", "l c gray63", "z c gray88", "x c #C1C1C1", "c c gray72", "v c gray73", "b c gray78", "n c #D5D5D5", "m c gray90", "M c #EAEAEA", "N c #D4D3D4", "B c #D7D9D7", "V c #A8D2A8", "C c #C5CAC5", "Z c #A3A1A3", "A c #B2B3B2", "S c #B2B2B2", "D c #9D9D9D", "F c gray88", "G c #C3C3C3", "H c gray62", "J c gray91", "K c gray83", "L c #B6B6B6", "P c #CECECE", "I c gray82", "U c #BCBCBC", "Y c #C7C6C7", "T c #E8DCE8", "R c #C3C1C3", "E c gray49", "W c gray62", "Q c gray59", "! c #888888", "~ c #E6E6E6", "^ c #C1C1C1", "/ c gray71", "( c gray77", ") c gray79", "_ c #D0D0D0", "` c gray89", "' c #E7E7E7", "] c gray82", "[ c #D6D8D6", "{ c #B0D1B0", "} c #D8DBD8", "| c #D0CFD0", " . c #E1E1E1", ".. c #DFDFDF", "X. c #CDCDCD", "o. c gray90", "O. c gray75", "+. c #C3C3C3", "@. c #9F9F9F", "#. c gray75", "$. c #DFDFDF", "%. c #E7E7E7", "&. c gray93", "*. c #D8D7D8", "=. c #D8DDD8", "-. c #7DC17D", ";. c #D5DCD5", ":. c #DEDCDE", ">. c #F3F4F3", ",. c gray95", "<. c #D5D5D5", "1. c #E4E4E4", "2. c gray77", "3. c #8E8E8E", "4. c gray77", "5. c gray70", "6. c gray68", "7. c #D7D7D7", "8. c #D8D8D8", "9. c #C3C3C3", "0. c #CECDCE", "q. c #E0DEE0", "w. c #CECECE", "e. c #A7A7A7", "r. c #B9B9B9", "t. c #B4B4B4", "y. c #AEAEAE", "u. c #E6E6E6", "i. c gray77", "p. c #888888", "a. c #A9A9A9", "s. c gray64", "d. c gray53", "f. c gainsboro", "g. c gray86", "h. c #C6C6C6", "j. c gray81", "k. c gray84", "l. c gray77", "z. c #838383", "x. c #A9A9A9", "c. c gray65", "v. c gray53", "b. c #E4E4E4", "n. c #C0C0C0", "m. c #B2B2B2", "M. c gray63", "N. c gray72", "B. c #A5A5A5", "V. c #ECECEC", "C. c #EFEFEF", "Z. c gray86", "A. c #D8D8D8", "S. c #797979", "D. c gray78", "F. c #AFAFAF", "G. c #A7A7A7", "H. c #B2B3B2", "J. c #A5A5A5", "K. c #DFDFDF", "L. c #C3C3C3", "P. c #9A9A9A", "I. c #B2B2B2", "U. c #AEAFAE", "Y. c #919091", "T. c #D9DAD9", "R. c gray86", "E. c gray78", "W. c #CECECE", "Q. c #C1C1C1", "!. c gray75", "~. c gray58", "^. c #B4B4B4", "/. c #AFAFAF", "(. c #939393", "). c #E1E1E1", "_. c #C6C6C6", "`. c #747474", "'. c #A49FA4", "]. c #969496", "[. c #7B7C7B", "{. c #9B989B", "}. c #A09BA0", "|. c #898989", " X c gray57", ".X c gray67", "XX c #898989", "oX c #6A6A6A", "OX c #A09EA0", "+X c #969396", "@X c #8B8B8B", "#X c #E6E5E6", "$X c #C1C2C1", "%X c #ADA8AD", "&X c #9EC89E", "*X c #AFC6AF", "=X c #CDC4CD", "-X c #B6CAB6", ";X c #95C195", ":X c #CAC5CA", ">X c #C8C9C8", ",X c #8E8E8E", " , < 1 2 3 4 5 6 7 8 9 0 q w e ", "r t y u i p a s d f g h j k l z ", "x c v b n m M N B V C Z A S D F ", "G H J K L P I U Y T R E W Q ! ~ ", "^ / ( ) _ ` ' ] [ { } | ...X.o.", "O.+.@.#.$.%.&.*.=.-.;.:.>.,.<.1.", "2.3.4.5.6.7.8.9.0.q.w.e.r.t.y.u.", "i.p.a.s.d.f.g.h.j.k.l.z.x.c.v.b.", "n.m.M.N.B.V.C.Z.A.S.D.F.G.H.J.K.", "L.P.I.U.Y.T.R.E.W.Q.!.~.^./.(.).", "_.`.'.].[.{.}.|. X.XXXoXOX+X@X#X", "$X%X&X*X=X-X;X:X>X,X c #55AC55", ", c #5AA75A", "< c #5BAB5B", "1 c #64AB64", "2 c #6AAD6A", "3 c #60B060", "4 c #74AF74", "5 c #75B975", "6 c #7AB27A", "7 c #7BBA7B", "8 c #848484", "9 c #8D8D8D", "0 c #949494", "q c #9B9B9B", "w c #81BD81", "e c #8FB78F", "r c #96BD96", "t c #9CBD9C", "y c #A4A4A4", "u c #ACACAC", "i c #AEB0AE", "p c #B5B5B5", "a c #B6B8B6", "s c #BCBCBC", "d c #96C596", "f c #99C099", "g c #A3C4A3", "h c #A7CCA7", "j c #A8C3A8", "k c #B1C8B1", "l c #BBC3BB", "z c #BBCABB", "x c #C3BEC3", "c c #C3C4C3", "v c #C5CDC5", "b c #CCCCCC", "n c #C7D0C7", "m c #CDD2CD", "M c #D2CCD2", "N c #D4D3D4", "B c #D5DCD5", "V c #DBD6DB", "C c #DBDBDB", "Z c #DCE3DC", "A c #E0D7E0", "S c #E1DBE1", "D c #E4E4E4", "F c #E6EAE6", "G c #EAE7EA", "H c #EBEBEB", "J c #F1EEF1", "K c #F3F3F3", "L c #FCFCFC", /* pixels */ "DGGDFDGFGFFDDGGHHHHHHHHGGHGGHGDD", "DDNDDDDDSCDDDDDbMNNNNNNCCBCCBZFG", "Ka#cpppaqyappps$@####@.@@@@#o*KD", "Kp%LDKHHbbKFGFHlDHJHHC#NNCNCq&KD", "Kp&KJ9aKcbGDDDHaCHhdGB#Nb&uDq&LD", "Kp%LaXqLcbHDDGHaCD:3ZC@mC%qD0&KS", "Kp%Lp+9KxbHDDDGaCG5>ZC@Mb@&D0&LD", "Kp%LKKGKbmKHHGKaDJGFJC#DCbbGy*KZ", "Ja$DmNNCpaCNNNNubNNNNbOqqqqy%&KD", "Ja#bssscyucsclcqacscca%&&&&*$qJD", "Ka&LHKGKbNKHHHKxDJKGHGcLLKKLDvHD", "Ka%KH$uLcbGDDDGaCH77GDpDDDDDMsHD", "Kp%Lu 9LcbHDFDHaCD:>BDpGGGSJNcHD", "Kp%Kc*qKsbHDDDGpCHd7ZDpDSSSSbsHD", "Kp*LLLLLNNKGHHKcDJKKHGcKLKJLDcHD", "Hso9***8%yvxcccqaccscx&*8848%qKD", "KsOq000q@9CmNbNybmNNNcO9000q$&KD", "Ka%HMcNH*yLGGGKxSKDbJC#DClNHy&KD", "Ka$ClOaD&qKDDDHaCG#&GC@bN@qD0&LD", "Ka$CN@yF&qKDDFHaZD++NC#mC$8G0&KD", "Ja$Ss&yD&qKDDDGaCHayGN@Mx40Cq&KD", "Ka%DNDCD*yLGJHKsDKKLKS#CVDCDq*KD", "Jc #@@@#oO$##$#+####$#.#@@@#o$KD", "Ka#caxxsyycacas0pascau+sxxxsuuHF", "Kp$DVgzCpaCNfmCubCbqCc@VMekAcpHD", "Kp$Sl;rAupCt-lCycB%oVl@NM2,AapJD", "Ka$Dr;4AppV6-tCybc#Xcc@Nb1 c #128F12", ", c #199219", "< c #269526", "1 c #2C992C", "2 c #349C34", "3 c #3B9D3B", "4 c #3BA13B", "5 c #44A344", "6 c #4AA44A", "7 c #4EA94E", "8 c #53A553", "9 c #51AA51", "0 c #59AE59", "q c #66AC66", "w c #6DAE6D", "e c #6DB56D", "r c #73AF73", "t c #74B074", "y c #76B876", "u c #7BB37B", "i c #848484", "p c #8A8A8A", "a c #949494", "s c #9B9B9B", "d c #85B685", "f c #84BE84", "g c #8CB98C", "h c #90BA90", "j c #9FBF9F", "k c #A4A4A4", "l c #A7A8A7", "z c #ABABAB", "x c #B4B4B4", "c c #B8B7B8", "v c #BCBCBC", "b c #95C695", "n c #9BC89B", "m c #A6C1A6", "M c #A3CBA3", "N c #ABC3AB", "B c #AFD0AF", "V c #B5C6B5", "C c #B9C7B9", "Z c #BCC8BC", "A c #B4D2B4", "S c #C3C3C3", "D c #CCCCCC", "F c #D1CFD1", "G c #D4D4D4", "H c #D7D8D7", "J c #DAD2DA", "K c #DADADA", "L c #DBE1DB", "P c #E7DDE7", "I c #E8DDE8", "U c #E5E5E5", "Y c #E7E9E7", "T c #E9E6E9", "R c #ECECEC", "E c #F2EBF2", "W c #F2F2F2", "Q c #FDF6FD", "! c #FBFBFB", /* pixels */ "UUTUUUUUUUUUUYUTUUUUUUUUUUUYUUUYUYUYUUYUUUYUYUUY", "UUUUUYUYUUYUTUYUUYUYYUYUUYUUTUTUUUUUUTUYTUUUUUTU", "YUUURUUUUUUUUUYUUUUUUUURUUUUUUUUURUUUUUUUUYUUTUY", "UTYUGRERERRRRYTRRRERERRGURRRRRRRYGRERWRRRWYTYUUU", "YURSollkkkkkzpizkklkkkzOX++OOOO+O +++@+++@o-WUUT", "UYRSOLHHKGHHUczUHKKKHGLazvccccxZaollkskksx$=WUUU", "UUES+RYTU!RTRSvWYYYYYTElUWRWQQE!DOKKHTUHKR==!UUU", "YURS+YUTUiFYRZcWUUUUTURlHYUHbMURSOGDD;iGDK*=!UUU", "UUWSOYUWa xWRScRUUUTUURkKYE03MRRvOGDG=+GDL*=!UUU", "UURS+UEc%#aWRvcEUUYUUURlHRR1e5LWSOGDKv$KDP*=!UUT", "UUES+TRS=X-RRScEUUUUTURlHYEe97UWvOGFG*.sGK*=!UYU", "UYRS+YUY!DUYRZcWUUUUUURkHYUUBLTRvOGDDkszDU*=!LUU", "YUWS+RYYURYTWScWUYYYYTWlKRYYERYWSOLKHPUUGR==!UUU", "UURSOKKKKKKKUxxUKKKKKKUsDKKKKKHUcolllkklkx$=WUUY", "UURSollklkkkliilkllklkl;slkkklklao++++++++X;WUTU", "UUWS+RRRYRRRWDv!YRERRRWzKWRRRRRRUzWRRRRRR!SvWUUU", "YURSOUUUYEUURvcRUUUUUUYkGYUTUUUUKkYUUUUUURvcWUUU", "UUES+YUED+vRRZvWUUUUUURlKYRA0bTTKkRUUUUUURvvRUUU", "UUWSOYUYioxWRScRUUUUUURlHYE55nTTKkYUUUUTURZvWUUY", "YURS+YWl@O;WRvcEUUUUUURkHYT2y2LYKkRUUTUUUEvvWUUU", "UURS+TYGx$aWRSxWUUUUUURlHYRM7fTUKkRUUUUUURvcWUUU", "UURS+YUURRYURcxWPUUUUURlGTURUYUYKkUUUULPPRvcRUYU", "UUWS+!!!!!!W!FS!RRRERR!zUWWREREWUz!!!!!!W!GSRUUU", "YYRSX=-====--&iScvZvvcSixvcvvvvZx%--==-==;%aWYYU", "UURD.*&**&*&=O&DcvvcvcSizSvvvvvSs.**&&*&&=o*WUTU", "UUWSOYKUYYUKW-=!RRWRWR!zUWRE!WR!S+RUUYTUK!-=!UUU", "TURSODDDzxDSK**!UUUUUURkGYUYvSURZOFDDlxDDK&=!UUY", "UURSOGDG%+GDU==!LUUUUUEkGYWi#sYRvOGFF%+GDU*=!UUU", "YURSOGDGc#KDP=*!UUUUUURkHYRO%;URSOGDKx#KDL*=!KUT", "UURSODDGioxGL=*!UUUUUURlKYW$=+KWvOGDGioxDU*=!UYU", "TURSODGD;&aGP*=!UTUUUURlGYRD-xYEvOGGD;&sGP*=!UUY", "UURSOGGDKLHDU**!LUUUUURkKYYRWRURvOGDFKLKSK*=!UUU", "UURSOHGGGGGFR==!TRRRERWlUWRRYYR!SOKGGFGGGT==!UUU", "YURD O+OOOOO+..@+++++++oO+++++++O +O+OOOO+ #EUUU", "UURSozllllllxppzllklllz;slllkklzpozllllllzpaRUUU", "UUWSOKHKHIKHPxzUHHKTKGUsDKKGUUKLx+KGHPIKHUxxWUUU", "YURSOGDFDrCFGzkGDFxtFDGaSGDGiaGGlOGDDurZDGzzWUUY", "UUWSOGDJd:jGGzlHFF5mGGaSGS;++DHzOGFCw2uJKzzEUUU", "YUWSOGDFPVDDGllHDJGVGDJaSGDKDvGGzOGFDmNGDHlzEUUU", "UUESOKKGGJKGUxzKGDFJGFHsDKKGKKGUxOHGGJJGGKzxWUUU", "UURSolkkkkkklpsDSSSSSZDisllkkkkliOSSSSSSSDsaWUYU", "YURD O++++OO+.$saaaaaasoo+O+OO++oXaaaaaaas$@WUUU", "UYUUGRRYRRRYEKKEYYRRRYRGURYRRRRRYGRYYRRYRRKKYUUT", "UUUURUUUUUUUUYYUUUUUUUURUUUUUUUUYRUUUUUUUUYYUUUU", "UUUYUUUUTUUYYUUYUTUYUUUUUUTUUUTUTUUUUUTUUTUUUYYU", "YTUUTUYUYUTUUUUUYUUUTUUYUTUUUYUUUUUYYUUUUUYUUUTU" }; const char *const *const xpm_icons[] = { xpm_icon_0, xpm_icon_1, xpm_icon_2, }; const int n_xpm_icons = 3; puzzles-20170606.272beef/icons/fifteen-icon.c0000644000175000017500000004704713115373752017534 0ustar simonsimon/* XPM */ static const char *const xpm_icon_0[] = { /* columns rows colors chars-per-pixel */ "16 16 256 2 ", " c black", ". c #010101", "X c #020202", "o c gray1", "O c #040404", "+ c gray2", "@ c #060606", "# c #070707", "$ c gray3", "% c #090909", "& c gray4", "* c #0B0B0B", "= c #0C0C0C", "- c gray5", "; c #0E0E0E", ": c gray6", "> c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", "XE.qX2X6X", "6XX9XyXyXrXrXeXuX8X7X", "6XqXgXx.v.$.{.rXeX0XtXyXuXqXX>X>X,X,XuXeXoX@X%XwX2X6X", "5X,X0X8X8X9X8XwXsX8XyXtXrXwX c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", "XeXeX#X5XeX", "wX5X@X0X8X8X8X8X8X8X8X8X8X8X8X7XbXeX9XpXU.) 9.7XP.r.eX0XeX#X5XeX", "eX4X=XlXhXhXhXhXhXhXhXhXhXhXhXhXNXwXqX0XuXkXdXeXaXgXqX0XrX#X5XeX", "eX2X7XMXfXjXhXhXhXhXhXhXhXhXlXrXhXtX0XqX0X7X9XqX9X8XqX0XeX#X5XeX", "eX2X7XsX5X8X8X8X8X8X8X8X8X7XqX&XiXuXqXwXwXwXwXwXwXwXwXwXtX$X5XeX", "eX2X7XgX9XwXqX0XqXwX0X0XwXqXtX;XpXqX5X6X6X6X6X6X6X6X6X5X8XXX5XeX", "eX2X7XfX8XqXeXsXrXqXdXuX0XqXrX;XeX7X1X2X2X2X2X2X2X2X2X2X2X>X9XwX", "eX2X7XfX8XeX4X~.>X9XR.oXrX0XrX-XsXcXhXjXjXjXjXjXjXjXjXjXzX9X6XwX", "eX2X7XfX7XtX;Xh t.7X:.j .XuXeX;XpXeX7X8X8X8X8X8X8X8X8X7X0XoX5XeX", "eX2X7XfX8X7XmXu.w.DXJ.g XXuXeX;XpXuX0XwXqX0XqXqX0X0XwXqXrX$X5XeX", "eX2X7XfX7XeX6XG Q |.0.a E.aXwX;XpXyX0X0XtXaXqXrXdXpXqXqXeX#X5XeX", "eX2X7XfX7XtX;Xb.B..Xn.Q.rX0XrX;XpXyX9XrX*X/.9X1XQ._.wX0XeX#X5XeX", "eX2X7XfX8XqXrXhXgXuXjXaXqXqXrX;XpXyX8XiXI.7 @Xk.w x.uX9XeX#X5XeX", "eX2X7XfX8XqX0X8X8X0X8X9XqX0XrX-XpXyX0X8XvX^ XX`.@.' 6XwXeX#X5XeX", "eX2X7XhXqXrXeXeXeXeXeXeXeXeXuX:XpXyX9XyX{.e y._.9.g 1XeXeX#X5XeX", "eX2X8XyX:X1X1X1X1X1X1X1X1XX>X>X>X>X>X>X>X>X>X c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", "X.X X% i.jX8X0XtX XxXpX9XqXqXqX0X8X0XqX0X9X8X9XqXqXqXwX9X[.0XqXqXqX", "qX0XtX$X9XvX7XwX9XsXZ.0 3 P /.n j G #XtX0X0XtX XxXpX9XqXqX0XuXgXuX0XrXfXjXdXqXqXqXwX9X[.0XqXqXqX", "qX0XtX$X9XvX7XwXqXwX6XXuXyX0XqX0XtX XxXpX9XqX0XeXXXF..XyX>XJ.b.P.wXqXqXwX9X[.0XqXqXqX", "qX0XtX$X9XvX7XwXqXqXwXrXeXrXqXeXrX0X0XqXqX0XtX XxXpX9XqX0XyX<.X [ mXV., Q &.wXqXqXwX9X[.0XqXqXqX", "qX0XtX$X9XvX7XwXqXqXqX0X0X0XqXqX0XqXqXqXqX0XtX XxXpX9XqXqX8XgXQ ! NXN.1 { I.uX0XqXwX9X[.0XqXqXqX", "qX0XtX$X9XvX7XwXqXqXqXqXqXqXqXqXqXqXqXqXqX0XtX XxXpX9XqXqX8XnX! ] BX@XL.<.@ OXuX9XwX9X[.0XqXqXqX", "qX0XtX$X9XvX6XqX0X0X0X0X0X0X0X0X0X0X0X0X0X0XrX|.xXpX9XqX0XwXOXv N ;XY.K.s.O oXiX9XwX9X[.0XqXqXqX", "qX0XtX%X9XnXqXyXtXtXtXtXtXtXtXtXtXtXtXtXtXrXpXXXxXpX9XqX9XpX<.V M w.(.H Z N.uX0XqXwX9X[.0XqXqXqX", "qX0XtX%X9XyX X@X+X+X+X+X+X+X+X+X+X+X+X+X+X+X#X/.cXpX9XqXqX0XsXhXjXpXuXjXjXsXqXqXqXwX9X[.0XqXqXqX", "qX0XtX=X$X3X&X=X*X*X*X*X*X*X*X*X*X*X*X*X*X*X*X=XCXuX0XqXqXqX9X8X8X9X0X8X8X9XqXqXqXwX9X[.0XqXqXqX", "qX0XrX-XoXuXrXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXtXeXSXyX0XqXqXqXqXqXqXqXqXqXqXqXqXqXqXwX9X[.0XqXqXqX", "qX0XtX=XOXtX0X0X0X0X0X0X0X0X0X0X0X0X0X0X0X0XqX9XAXyX0XqXqXqXqXqXqXqXqXqXqXqXqXqXqXwX9X[.0XqXqXqX", "qX0XrX=XOXtX0XqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqX0XAXyX9XqXqXqXqXqXqXqXqXqXqXqXqXqXqXqX9X[.0XqXqXqX", "qX0XrX-X+XrX0X0X0X0X0X0X0X0X0X0X0X0X0X0X0X0XqX9XAXiXqXeXwXwXwXwXwXwXwXwXwXwXwXwXwXeX0X[.0XqXqXqX", "qX0XtX=XoXuXwXeXeXeXeXeXeXeXeXeXeXeXeXeXeXeXeXeXmX#X}. X X X X X X X X X X X X X X X}.[.qXqXqXqX", "qXqXrX:XwXHXAXSXSXSXSXSXSXSXSXSXSXSXSXSXSXSXSXDXAXmXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXMXNXmXqXqXqXqX", "qXqXqXqXrXwXwXwXwXwXwXwXwXwXwXwXwXwXwXwXwXwXwXwXeXrXrXrXrXrXrXrXrXrXrXrXrXrXrXrXrXrXrXeXqXqXqXqX", "qXqXqXqX0XqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqX0X0X0X0X0X0X0X0X0X0X0X0X0X0X0X0X0X0X0XqXqXqXqX", "qXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqX", "qXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqX" }; const char *const *const xpm_icons[] = { xpm_icon_0, xpm_icon_1, xpm_icon_2, }; const int n_xpm_icons = 3; puzzles-20170606.272beef/icons/dominosa-icon.c0000644000175000017500000004704713115373752017725 0ustar simonsimon/* XPM */ static const char *const xpm_icon_0[] = { /* columns rows colors chars-per-pixel */ "16 16 256 2 ", " c black", ". c #010101", "X c #020202", "o c gray1", "O c #040404", "+ c gray2", "@ c #060606", "# c #070707", "$ c gray3", "% c #090909", "& c gray4", "* c #0B0B0B", "= c #0C0C0C", "- c gray5", "; c #0E0E0E", ": c gray6", "> c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", " s.t 8X", "lXlXzXzXlXxXvXkXlXgXNX-Xo 2 qX", "lXlXzXzXlXjXkXzXlXhXNX-XO 1 qX", "jXnXi.Q.CXuXi.sXCXR.W.5X- 9.r 8X", "lXSX$XqXBXpX/.jXmX@X,X2Xo f 0 0X", "gX{.'.'.eXrXjXtXtXaXdXeXI.n.T.lX", "wX: 5 $ A.CXoXjXvX1X c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", ". 2 eXvX", "gXFX&. j.V X X v ;XV. U Y. l @XZ.= . o Q q. < eXvX", "gXFX*. 4 F.| @ + . < O.4. U I. % ,.<.O O O + 3.c.o : eXvX", "gXDX,. O o R Q. X . 1 yXcX", "kXvX6Xa.u.a.p.i.i.i.i.p.s.s.e.#XkXx.y.s.a.i.u.a.b.v.n.M.k.{.bXkX", "lXkXvXFXDXGXDXFXFXFXFXFXDXFXGXmXzXDXFXJXFXDXHXmX6.} O. .[ h.cXlX", "lXlXkXfXxXpXlXhXgXgXgXgXlXdXgXjXlXhXgXwXjXdXmX(. X . : eXvX", "lXlXjXMX%X_ M.NXjXlXhXFXe.i.FXhXlXzXjX9.2.bXBX`. X j.5. , eXvX", "lXlXhXFXl.7.-.xXkXjXNX@XM &.BXjXlXjXNXA.Y cXVX'. 8 OXF.1 % rXvX", "lXlXkXnX1X .J.NXjXkXvX8Xu.7.nXkXkXcXyX9.t.zXVX`. . <.h.# * rXvX", "lXlXlXkXbXbXmXlXlXlXkXbXAXNXzXlXlXlXlXhXMXjXVX`. . X O ; eXvX", "lXlXlXlXkXkXkXlXlXlXlXkXhXjXlXlXlXlXlXzXjXhXCX`. X X o ; eXvX", "lXlXlXlXkXkXkXlXlXlXlXlXlXjXlXlXlXlXlXzXjXhXCX`. X . . ; eXvX", "lXlXlXkXbXbXmXlXlXlXlXlXjXmXlXlXlXlXlXhXmXjXVX`. X + ; eXvX", "lXlXkXnX1X..J.NXjXkXcXiX1.x.BXjXlXzXgXe.t.vXBX`. o K.%. : eXvX", "lXlXhXFXl.7.-.xXkXlXkXBXa.[ ZXjXlXjXBXA.Y vXVX`. + 9.J.@ = rXvX", "lXlXjXMX%X_ M.NXjXkXvX8X-.r.MXjXkXxXyX6.<.lXBX`. & O.F.% ; rXvX", "lXlXhXfXxXpXlXhXjXxXvXzXiXNXvXxXzXvXcXiXmXcXAX`. . o X : rXvX", "lXzXDXFXDXGXDXFXmXaXqXeXyXwXqXuXfXqXeXyXwXqXuXiX#.T E ! U r.cXkX", "xXsXg.y.i.a.a.t.,XdX h -X3. / ZXcX3XF <.ZXhXlXkXnX~.#.mXkXlXjXAXH.f.HXgXlXlX", "vXeX1 m W.l. / ZXvX=X| X.mXkXkXxXaXZ j.nXkXlXjXBXe.] cXlXlXlX", "vXeX; . . + Q SXfXmXmXfXxXlXlXzXgX7X5XkXlXlXlXlX7X4XhXzXlXlX", "cXuXG c N M m l D.BXjXkXkXzXlXlXlXlXzXnXbXlXlXlXlXlXbXnXzXlXlXlX", "lXzXMXMXMXNXMXNXNXkXlXlXlXkXlXlXlXlXlXkXkXlXlXlXlXlXkXkXlXlXlXlX", "lXlXjXjXjXjXjXjXjXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlX" }; /* XPM */ static const char *const xpm_icon_2[] = { /* columns rows colors chars-per-pixel */ "48 48 256 2 ", " c black", ". c #010101", "X c #020202", "o c gray1", "O c #040404", "+ c gray2", "@ c #060606", "# c #070707", "$ c gray3", "% c #090909", "& c gray4", "* c #0B0B0B", "= c #0C0C0C", "- c gray5", "; c #0E0E0E", ": c gray6", "> c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", "X . X s xXlXlXlX", "lXlXgXFX=. O & [ V o X X X X X X O ^ 9 . q.;X O : | C o X X X o z .., p zXlXlXlX", "lXlXgXFX=. . & /./. X o ( UXR q.;X X !.(.K . X I kXA i xXlXlXlX", "lXlXgXFX*. # W U. o . p n.~.] q.;X 6 hXn.c. X /.S i zXlXlXlX", "lXlXgXFX=. O s.1X5 . o I |.jXU. q.;X # &Xt.:XO . . u wX2. i xXlXlXlX", "lXlXgXFX=. . < r.l.H o . . . . . { l q.;X O z g.l X . . . o E l.0.= a zXlXlXlX", "lXlXgXFX*. O O q.;X X X i zXlXlXlX", "lXlXjXNX(.2 % * ; : = & & & & & & & & - = $ 3 {.jXV O * = ; = & & & & # # # % = * $ . 5.NXjXlXlX", "lXlXlXkXmXpX7X9X9X9X9X9X9X9X9X9X9X9X9X9X9X7XaXnXcXlX7X9X9X9X9X9X9X9X8XaXfXdXfXfXfXdXjXSXlXlXlXlX", "lXlXlXlXjXxXbXbXvXcXbXbXbXbXbXbXbXbXbXcXvXbXxXkXkXlXbXbXvXcXvXbXbXvXVXD.U W W Q Q E R !.mXjXlXlX", "lXlXlXlXlXkXkXhXbXMXhXkXkXkXkXkXkXkXjXmXxXjXkXlXlXlXkXjXMXBXlXjXjXcXwX, . X k vXkXlXlX", "lXlXlXlXlXlXkXMXXX7XmX,Xv.n.n.n.n.b.M.wXvXkXlXlX", "lXkXvXwXN.C.C.V.V.C.C.m.[.mXyX;X>X>X>X>X>X>X-XrXgX;X>X>X>X>X>X>X;X7XzXbXFXDXDXDXDXDXDXcXkXlXlXlX", "lXjXBX X . . `.ZXvXnXnXbXvXnXnXmXcXzXnXnXnXbXbXvXnXnXvXlXkXgXgXgXfXgXgXgXkXlXlXlXlX", "lXjXBX.X + o O X o # V.SXfXkXjXxXNXlXkXkXkXlXkXkXlXcXxXNXjXkXkXlXlXlXlXcXbXxXlXlXlXlXlXlXlX", "lXjXBX X . o D 3X0 C.SXhXjXmX5Xj `.BXjXlXlXkXxXdX;.K S.NXjXlXlXlXjXNXC.x %XMXjXlXlXlXlXlX", "lXjXBX X X $ l.rXg V.SXgXkXbXi.t E.SXhXlXlXlXzXpXjXu.H AXjXlXlXlXkXzXuXM ~.CXjXlXlXlXlXlX", "lXjXBX X + <.~.7X.. V.SXdXZXY.L M <.VXjXlXlXlXjXNXOXP ,XmXjXlXlXlXlXjXHXP '.AXjXlXlXlXlXlX", "lXjXBX X o l =.tX} C.SXfXbX,XM.z 5.BXjXlXlXkXzXjXf h h.cXkXlXlXlXjXNXD.6 ) dXxXkXlXlXlXlX", "lXjXBX.X + O . : O # V.SXhXkXbXJXgXcXxXlXlXlXlXlXjXrX3X4XzXlXlXlXlXlXxX0X6X4XhXzXlXlXlXlXlX", "lXjXBX X . X T.ZXhXlXkXgXzXlXlXlXlXlXlXlXlXvXnXbXlXlXlXlXlXlXkXvXnXnXzXlXlXlXlXlXlX", "lXkXnX3X$.=.=.*.*.=.-.@.v.zXlXlXlXlXlXkXlXlXlXlXlXlXlXlXkXkXkXlXlXlXlXlXlXlXkXkXkXlXlXlXlXlXlXlX", "lXlXkXcXGXFXFXFXFXFXFXGXAXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlX", "lXlXlXkXgXgXgXgXgXgXgXgXhXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlX", "lXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlX", "lXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlXlX" }; const char *const *const xpm_icons[] = { xpm_icon_0, xpm_icon_1, xpm_icon_2, }; const int n_xpm_icons = 3; puzzles-20170606.272beef/icons/cube-icon.c0000644000175000017500000004464613115373752017034 0ustar simonsimon/* XPM */ static const char *const xpm_icon_0[] = { /* columns rows colors chars-per-pixel */ "16 16 236 2 ", " c #E3E3E4", ". c #CECEDC", "X c #CCCCDC", "o c #CDCDDC", "O c #CDCDDB", "+ c #CDCDDC", "@ c #CCCCDC", "# c #CECEDB", "$ c #DADADA", "% c gray86", "& c gray86", "* c #DADADA", "= c gray86", "- c #DADADA", "; c gray86", ": c gray90", "> c #1818E9", ", c #0909F6", "< c #0D0DF2", "1 c #0C0CE2", "2 c #0D0DF3", "3 c #0909F6", "4 c #1A1AE6", "5 c #CECED5", "6 c #E0E0DE", "7 c #DBDBDC", "8 c #CDCDCD", "9 c #DDDDDD", "0 c gray87", "q c LightGray", "w c #DDDDDD", "e c #CDCDDC", "r c #0D0DF3", "t c blue", "y c #0101FE", "u c #0000EC", "i c #0101FF", "p c #1010F1", "a c #D9D9DF", "s c #EDEDEA", "d c #E7E7E7", "f c #D7D7D7", "g c gray91", "h c gray92", "j c #DDDDDD", "k c gainsboro", "l c #CDCDDC", "z c #0C0CF3", "x c #0101FE", "c c #0000EC", "v c #0202FE", "b c #1010F0", "n c #D6D6DD", "m c #E9E9E7", "M c #E4E4E4", "N c #D5D5D5", "B c gray90", "V c #E7E7E7", "C c #DADADA", "Z c gainsboro", "A c #D3D3DA", "S c #7272D7", "D c #6E6EE3", "F c #7979DF", "G c #3131D6", "H c #0000ED", "J c #0000EF", "K c #0F0FE0", "L c #C7C7CD", "P c #D9D9D7", "I c #D3D3D4", "U c #C5C5C5", "Y c #D5D5D5", "T c gray84", "R c gray80", "E c gainsboro", "W c #DCDCDB", "Q c #EBEBDB", "! c #F5F5E7", "~ c #FFFFE1", "^ c #6B6BE1", "/ c #1010F1", "( c #D5D5DD", ") c #E9E9E8", "_ c #E6E6E7", "` c #D8D8D8", "' c #E9E9E9", "] c #ECECEC", "[ c gainsboro", "{ c gray86", "} c #DBDBDF", "| c #E3E3EB", " . c #F5F5E6", ".. c #6464E3", "X. c #1010F1", "o. c #DCDCDF", "O. c #F1F1EB", "+. c #DCDCDB", "@. c #CACACB", "#. c #DADADA", "$. c gray85", "%. c #D7D7D7", "&. c gray87", "*. c #DADADA", "=. c #D2D2D2", "-. c #D9D9DD", ";. c #EAEAD9", ":. c #6060D7", ">. c #0000F4", ",. c #0000F5", "<. c #0E0EE6", "1. c #BEBED5", "2. c #CCCCDC", "3. c #C8C8CE", "4. c #E1E1E0", "5. c #E0E0E1", "6. c #D2D2D2", "7. c #C3C3C3", "8. c gray87", "9. c #DADADA", "0. c gray83", "q. c #DBDBDF", "w. c #ECECDA", "e. c #6060D8", "r. c #0000F6", "t. c #0303F7", "y. c #0000E9", "u. c #0909EA", "i. c #0000F5", "p. c #8B8BDC", "a. c #F4F4E9", "s. c #E3E3EA", "d. c #DADADF", "f. c #D2D2D3", "g. c #DDDDDD", "h. c gray86", "j. c gray87", "k. c #E7E7EB", "l. c #F8F8E6", "z. c #6767E3", "x. c #0808FF", "c. c #0404F3", "v. c #0606F5", "b. c #9595DC", "n. c #FFFFE2", "m. c #F5F5E3", "M. c #EDEDD7", "N. c #DEDED6", "B. c #DDDDDF", "V. c gray86", "C. c gray86", "Z. c #E3E3E8", "A. c #F5F5E2", "S. c #6464E1", "D. c #0404FF", "F. c #0000F3", "G. c #0101F4", "H. c #2323DB", "J. c #4040E0", "K. c #3B3BE8", "L. c #3737E0", "P. c #A3A3CD", "I. c #E5E5DE", "U. c #DADADA", "Y. c #CDCDCD", "T. c #D6D6D7", "R. c #DCDCD4", "E. c #9797CB", "W. c #6E6EE0", "Q. c #7878E2", "!. c #7070D5", "~. c #7070D6", "^. c #7777E3", "/. c #6C6CDD", "(. c #5E5ED1", "). c #6868E4", "_. c #6363E6", "`. c #8484C8", "'. c #E0E0D9", "]. c gray86", "[. c #E9E9E8", "{. c #E4E4E5", "}. c #DDDDD5", "|. c #F7F7E4", " X c #F9F9E7", ".X c #EBEBD9", "XX c #ECECDB", "oX c #F9F9E6", "OX c #F7F7E4", "+X c #E8E8D5", "@X c #FAFAE4", "#X c #FDFDE6", "$X c #E7E7DC", "%X c #DBDBDD", "&X c gray86", "*X c gray87", "=X c gray92", "-X c #E8E8E7", ";X c #D6D6D8", ":X c #E4E4E9", ">X c #E7E7EB", ",X c #DADADE", " , < 1 2 3 4 5 6 7 8 9 0 q w ", "e r t y u i t p a s d f g h j k ", "l z t x c v t b n m M N B V C Z ", "A S D F G H J K L P I U Y T R E ", "W Q ! ~ ^ t t / ( ) _ ` ' ] [ E ", "{ } | ...t t X.o.O.+.@.#.$.%.&.", "*.=.-.;.:.>.,.<.1.2.3.4.5.6.7.8.", "9.0.q.w.e.r.t.y.u.i.p.a.s.d.f.g.", "h.j.k.l.z.t x.c.v.t b.n.m.M.N.B.", "V.C.Z.A.S.t D.F.G.t H.J.K.L.P.I.", "U.Y.T.R.E.W.Q.!.~.^./.(.)._.`.'.", "].9 [.{.}.|. X.XXXoXOX+X@X#X$X%X", "&X*X=X-X;X:X>X,X c #0000DA", ", c #0000DB", "< c #0404DF", "1 c #1111D1", "2 c #1616DD", "3 c #3131CC", "4 c #2121D0", "5 c #3131D7", "6 c #3131D8", "7 c #3434DA", "8 c #0000E4", "9 c #0101E4", "0 c #0000E5", "q c #0101E5", "w c #0000E6", "e c #0D0DE3", "r c #0F0FE2", "t c #0F0FE3", "y c #0D0DE4", "u c #0000E9", "i c #0101E9", "p c #0202E9", "a c #0000EA", "s c #0101EA", "d c #0000EB", "f c #0101EB", "g c #0202EA", "h c #0000EC", "j c #0000EE", "k c #0101EE", "l c #0000EF", "z c #0101EF", "x c #0C0CE9", "c c #0D0DE9", "v c #1212E1", "b c #1010E3", "n c #1212E2", "m c #1414E3", "M c #1616E3", "N c #1010E4", "B c #1212E6", "V c #1313E6", "C c #1212E7", "Z c #1515E4", "A c #1616E4", "S c #1515E7", "D c #0000F0", "F c #0000F1", "G c #0000F5", "H c #0000F8", "J c #0000F9", "K c #0303FB", "L c #0000FD", "P c #0101FD", "I c #0303FC", "U c #0202FD", "Y c #0303FD", "T c #0000FE", "R c #0101FE", "E c blue", "W c #0101FF", "Q c #0202FF", "! c #5D5DCC", "~ c #8989B1", "^ c #9C9CBD", "/ c #ACACAC", "( c #AFAFBA", ") c #AEAEBB", "_ c #AFAFBB", "` c #B8B8B9", "' c #B9B9B9", "] c gray73", "[ c #BBBBBB", "{ c #BCBCBC", "} c gray74", "| c gray", " . c gray75", ".. c #C2C2BF", "X. c #9797CB", "o. c #9797CC", "O. c #9898CF", "+. c #9797D1", "@. c #B3B3C0", "#. c #B2B2C1", "$. c #B4B4C1", "%. c #BABAC1", "&. c #BEBECF", "*. c #C0C0C0", "=. c #C1C1C0", "-. c #C1C1C1", ";. c #C3C3C0", ":. c #C3C3C3", ">. c #C5C5C3", ",. c #C3C3C6", "<. c gray77", "1. c #C5C5C5", "2. c #C6C6C4", "3. c #C6C6C6", "4. c gray78", "5. c #C8C8C5", "6. c #CACAC5", "7. c #C9C9C6", "8. c #C8C8C8", "9. c gray79", "0. c #CBCBC9", "q. c #CBCBCB", "w. c gray80", "e. c #CCCCCD", "r. c #CDCDCD", "t. c #CDCDCE", "y. c #CECECE", "u. c #CECECF", "i. c gray81", "p. c #D3D3C8", "a. c #D2D2CA", "s. c #C1C1D0", "d. c #C2C2D0", "f. c #C2C2D1", "g. c #C1C1D3", "h. c #C6C6D0", "j. c #C7C7D0", "k. c #C6C6D1", "l. c #C6C6D2", "z. c #C2C2D4", "x. c #C6C6D4", "c. c #C6C6D5", "v. c #D0D0D0", "b. c gray82", "n. c #D2D2D0", "m. c #D2D2D2", "M. c #D2D2D3", "N. c LightGray", "B. c #D5D5D2", "V. c #D6D6D2", "C. c #D3D3D4", "Z. c gray83", "A. c #D5D5D4", "S. c #D4D4D5", "D. c #D5D5D5", "F. c #D6D6D4", "G. c #D7D7D5", "H. c gray84", "J. c #D7D7D6", "K. c #D7D7D7", "L. c #D8D8D3", "P. c #D8D8D4", "I. c #D8D8D5", "U. c #D9D9D5", "Y. c #D9D9D6", "T. c #D7D7D8", "R. c #D7D7D9", "E. c #D8D8D8", "W. c #D8D8D9", "Q. c gray85", "!. c #DADAD9", "~. c #DBDBD9", "^. c #D9D9DA", "/. c #DADADA", "(. c #DCDCD8", "). c #DDDDD9", "_. c #DFDFD9", "`. c #DEDEDA", "'. c gainsboro", "]. c #DDDDDD", "[. c #DEDEDC", "{. c #DFDFDC", "}. c gray87", "|. c #E1E1D7", " X c #E9E9DB", ".X c #EBEBDD", "XX c #ECECDC", "oX c #ECECDD", "OX c #E1E1E1", "+X c #E2E2E2", "@X c #E3E3E2", "#X c gray89", "$X c #E2E2E4", "%X c #E3E3E4", "&X c #E2E2E5", "*X c #E3E3E5", "=X c #E4E4E4", "-X c #E4E4E5", ";X c gray90", ":X c #E6E6E6", ">X c #E7E7E7", ",X c #E1E1E8", ".K.C.C.C.K.} K.3X", "tXl.g E E E E E q g E E E E E n E.uX7X9X3XtXM.E.tX3X3X3XtXM.E.3X", "rXl.g E P E P E q g E E E E E n K.3X%X:X%X3Xt.K.3X:X:X#X9Xe.R.3X", "rXl.g E E E P E q g E E E E E t Y.3X:X:X:X9Xt.K.3X%X:X:XtXt.E.3X", "tXl.p E P P P E 8 g E P E P E n K.3X:X:X:X9Xt.K.3X:X:X:X3Xt.E.3X", "rXl.q E E E E E q g E E E P E N (.tX3XtX3XxXM.E.xX3XtX3XxXM.E.9X", "tXl.= x y y y x X # g q q q g X :.C.i.t.t.B.] :.C.i.t.t.M.} K.3X", "tXi.:.E.C.C.M.(.$.: j g g g j = >.E.C.K.C.E.} <.K.K.K.M.Y.} E.3X", "9XM.K.tX3XrX3XjXl.g E E E E E N E.tX3X3X3XuXM.E.tX3X3X3XjXt.E.3X", "9Xi.C.9X%X:X%XrX&.g E E E E E t K.3X:X:X:X3Xq.K. c #0202C4", ", c #0000C6", "< c #0808C1", "1 c #0000CE", "2 c #1010CE", "3 c #0505D2", "4 c #0000D7", "5 c #0505DA", "6 c #0505DB", "7 c #0606DB", "8 c #0000DC", "9 c #0101DC", "0 c #0000DD", "q c #0101DD", "w c #0202DD", "e c #0303DD", "r c #0000DE", "t c #0000DF", "y c #0101DF", "u c #0202DE", "i c #0202DF", "p c #0505DC", "a c #0505DD", "s c #0808D9", "d c #0909D9", "f c #0808DA", "g c #1515D2", "h c #1515D3", "j c #1616D5", "k c #0000E0", "l c #0000E1", "z c #0000E3", "x c #0505E1", "c c #0606E0", "v c #0707E0", "b c #0404E3", "n c #0505E3", "m c #0000E5", "M c #0202E5", "N c #0000E6", "B c #0000E7", "V c #0808E0", "C c #0808E1", "Z c #0000E8", "A c #0000E9", "S c #0202EA", "D c #0000EE", "F c #0000F4", "G c #0101F4", "H c #0000F8", "J c #0101F8", "K c #0000FC", "L c #0101FC", "P c #0000FD", "I c #0101FD", "U c #0202FC", "Y c #0000FE", "T c #0101FE", "R c blue", "E c #0101FF", "W c #0202FF", "Q c #939393", "! c gray61", "~ c #8F8FA1", "^ c #A4A4AD", "/ c #A9A9AB", "( c #AAAAAA", ") c #A8A8AD", "_ c #ACACAC", "` c gray68", "' c #ACACAE", "] c #AEAEAE", "[ c #AFAFAF", "{ c #B0B0AF", "} c #A7A7B1", "| c #ABABB0", " . c #ACACB0", ".. c #AFAFB1", "X. c gray69", "o. c #B1B1B1", "O. c #B3B3B1", "+. c #B2B2B2", "@. c #B7B7B7", "#. c gray74", "$. c #BDBDBE", "%. c gray", "&. c gray75", "*. c #CACABE", "=. c #ABABC1", "-. c #ABABC2", ";. c #ACACC3", ":. c #AEAECB", ">. c #B0B0C9", ",. c #C1C1C1", "<. c gray76", "1. c #C3C3C3", "2. c #C1C1C7", "3. c gray77", "4. c #C4C4C5", "5. c #C5C5C5", "6. c #C6C6C6", "7. c #C7C7C6", "8. c gray78", "9. c #C9C9C5", "0. c #C2C2C8", "q. c #C5C5C8", "w. c #C6C6C8", "e. c #C7C7C9", "r. c #C7C7CD", "t. c #C8C8C8", "y. c gray79", "u. c #CACAC8", "i. c #CACAC9", "p. c #C9C9CA", "a. c #C8C8CB", "s. c #CACACA", "d. c #CBCBCA", "f. c #CBCBCB", "g. c #CCCCCB", "h. c #CDCDCB", "j. c #CFCFCB", "k. c #C8C8CD", "l. c gray80", "z. c #CDCDCD", "x. c #CFCFCC", "c. c #CECECD", "v. c #CCCCCE", "b. c #CCCCCF", "n. c #CDCDCF", "m. c #CECECE", "M. c #CFCFCE", "N. c gray81", "B. c #D0D0CE", "V. c #D5D5CD", "C. c #D8D8CE", "Z. c #D0D0D0", "A. c #D1D1D0", "S. c gray82", "D. c #D2D2D0", "F. c #D1D1D3", "G. c #D2D2D2", "H. c LightGray", "J. c #D2D2D4", "K. c #D5D5D5", "L. c #D7D7D7", "P. c #D9D9D0", "I. c #DCDCD1", "U. c #DCDCD3", "Y. c #D8D8D8", "T. c #DADADA", "R. c #DFDFDF", "E. c #E8E8D9", "W. c #E2E2E3", "Q. c gray89", "!. c #E2E2E4", "~. c #E3E3E4", "^. c #E3E3E5", "/. c #E4E4E4", "(. c #E4E4E5", "). c gray90", "_. c #E6E6E6", "`. c #E7E7E7", "'. c #E6E6EA", "]. c gray91", "[. c #E9E9EB", "{. c #EAEAEA", "}. c gray92", "|. c #ECECEB", " X c #EDEDEB", ".X c #EAEAEC", "XX c #EBEBEC", "oX c #ECECEC", "OX c #EDEDEC", "+X c gray93", "@X c #EEEEED", "#X c #EEEEEE", "$X c #F6F6E0", "%X c #F1F1EB", "&X c #F1F1EC", "*X c #F2F2EC", "=X c gray94", "-X c #F1F1F1", ";X c #F3F3F2", ":X c #F3F3F3", ">X c #F5F5F1", ",X c #F4F4F3", " > Z i i l i l i B - .x.f.f.f.f.f.f.D.{ o.N.f.f.f.f.f.f.D.' x.oX~._.", "_._.}.x.) r.2.0.2.q.0.2.k. .o l 8 i i 8 i 8 l - .x.5.f.5.f.5.5.k.' o.x.5.5.f.q.9.5.x.) k.oX_._.", "_._.}.f.j.1X|.oXoXoXoXoX.D.1X1.f.|._._.", "_./.XXj.k..~ V.1X2.f.}._._.", "_.~.XXx.5.}.Q.Q._._.~.Q.}.f.5 R U U R R R U R 8 8 R U R U R G X i G Z Z Z Z Z Z B % $Xf.f.}._._.", "_._.}.f.j.1X}.oXoXoXoXoX1XD.p R R R R R R R R i i R R R R R R U 1 F R R R R R R R G & *.x.oX_._.", "_._.XXx.' x.5.5.q.f.5.5.x.o.O l 5 5 5 p p 5 n ; ; c 5 p 5 p 5 c 3 . 5 p 5 5 p p 5 V 4 B.XX_._.", "_._.XXx.' B.f.f.j.f.f.f.D.o.o.D.f.f.f.j.j.f.B.o.o.D.f.f.f.f.f.f.J. .O.D.f.f.f.f.f.f.D.} j.oX_._.", "_._.oXk.f.-X}.}.XXXXoX}.1XN.x. c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", ".<.,.8.8.) CX7.=XS.'. XpX9X", "0X*X%X&X&X#X,XM.A.1XA.R.Z.D.gX0X", "wXjXkXkXkXkXkXkXU.M.R.j.C.B.b.pX", "&X7.f.s.s.s.s.d.v.m.<.(.$XT.P.|.", "-Xh.V.N.N.N.N.N.n.A.7.L.>XoXV.+X", "wXdXfXfXfXfXfXfXfXdXlXb.N.m.F.aX", "qX8X8X8X8X8X8X8X8X8X8XpX.X@XaX0X" }; /* XPM */ static const char *const xpm_icon_1[] = { /* columns rows colors chars-per-pixel */ "32 32 256 2 ", " c black", ". c #010101", "X c #020202", "o c gray1", "O c #040404", "+ c gray2", "@ c #060606", "# c #070707", "$ c gray3", "% c #090909", "& c gray4", "* c #0B0B0B", "= c #0C0C0C", "- c gray5", "; c #0E0E0E", ": c gray6", "> c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", "XXX9X3X|.9XyX0XqX", "qXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqX9XXXE E XsXG.g %XUXKXv.l >XtX0X", "qXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqX5XPXp.i.IX2Xk >XkX3.Y.UXy.( jX8X", "qXqXqXqXqXqXqXqXqXqXqXqXqXqXqXwX4XDXi.t.UXm.^ UXjX;Xl bXNXn .fX8X0XyX%Xv 6XsXK.G 0XkX^ d.UXt.i.FX4XwX4XPX@.I.NX6XqXqXqX", "uX#XJ.pX9XqX0XiXN P.cX#.N !.iXg `.IXp.s.FX2XwX4XPX@.I.NX6XqXqXqX", "qX0XqXwXqXqX9XgXA.r |.bXNXqXF X.bXNX-.;.CXpX0X4XPX@.I.NX6XqXqXqX", "qXqX7X6X6X6X6X4XiXf.r H Y u [ lXv.j Y P j v.gX1XPX@.I.NX6XqXqXqX", "qXeXmXBXNXNXNXNXmXLXlX/.T.8XUXN.a 8XIXUX0Xs b.uXJX@.I.NX6XqXqXqX", "wX8XI.J.K.K.K.K.K.G.I./.(.Y.U.z 5XZX9._ ZX5Xz 3XIX@.I.NX6XqXqXqX", "eX5Xe.5.7.7.7.7.7.7.6.5.3.e._ H UXUX}.z pXUXK I.UX+.I.NX6XqXqXqX", "eX5Xe.5.7.7.7.7.7.7.7.7.6.r._ G UXbXQ.g *XUXJ I.UXo.P.MX6XqXqXqX", "wX8XI.J.K.K.K.K.K.K.K.K.K.J.R.z 6XbXt.M.UX1Xz 1XUX$.Y.VX4XqXqXqX", "qXeXMXBXBXBXBXBXBXBXBXBXBXmXLXB.a wXUXUX0Xa n.nX8XG 5.aXsX9XqXqX", "qXqX2X,X,X,X,X,X,X,X,X,X,X,X:XyXj.i C C i k.zX{ z <.| p k.gX9XqX", "wX9XnXKXGXGXGXGXGXGXGXGXGXGXHXDXUXSX2X2XAXUX../ HXBXUXaXd C.fX8X", "tX-X5.p.y.u.u.u.u.u.u.u.u.u.u.u.r.u.k.k.a.5.n JXiX-.Y UX@XN iX0X", "uX@XT N.z.x.x.x.x.x.x.x.x.x.x.x.x.x.z.k.A.( @.UXUXG.A DXKXN $XuX", "yX%XN @.X.o.o.o.o.o.o.o.o.o.o.o.o.o.o.X.=.n ' UXwXc.g hXDXn ;XtX", "tX>X/.*X@X#X#X#X#X#X#X#X#X#X#X#X#X#X#X#X$X+Xk uXkXv.@XUXN.P hX8X", "qXwXhXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXkXgXVXl.p ,XUXKXC.r oXiX9X", "qXqX8X8X8X8X8X8X8X8X8X8X8X8X8X8X8X8X8X8X8X6XfXC.v b c J XXaX9XqX", "qXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqX9XfXpX$X;XhXiX9XqXqX", "qXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqX8X0XuXtX8X9XqXqXqX" }; /* XPM */ static const char *const xpm_icon_2[] = { /* columns rows colors chars-per-pixel */ "48 48 256 2 ", " c black", ". c #010101", "X c #020202", "o c gray1", "O c #040404", "+ c gray2", "@ c #060606", "# c #070707", "$ c gray3", "% c #090909", "& c gray4", "* c #0B0B0B", "= c #0C0C0C", "- c gray5", "; c #0E0E0E", ": c gray6", "> c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", " +XqXkXt.< 6X6XUX1.n UX9XqXqXqXqX7XUXH X.UX5XqXqXqXqXqXqXqX", "qX8XlXf.$.xX7XqXqXqX8XlXA R kX5XdX{.4 OXrXtXXXO /.rXUX1.n UX9XqXqXqXqX7XUXJ O.UX5XqXqXqXqXqXqXqX", "qX8XlXd. .cX7XqXqXqX8XlXb _ xX5XgX|.5 4XiXeX-Xo E.tXUX1.n UX9XqXqXqXqX7XUXJ O.UX5XqXqXqXqXqXqXqX", "qX8XkXk.0.kX8XqXqXqX8XkX` n sXqX-XX.% <.,XfXI.% OXqXUX1.n UX9XqXqXqXqX7XUXJ O.UX5XqXqXqXqXqXqXqX", "qX9XsXI.`.pX0XqXqXqX9XdXP.. `.zX`.] &.{ $XnXI c dX.qXUXlX, 6.jX4XUXJ O.UX5XqXqXqXqXqXqXqX", "qX9XdXP.r l h h h h h h h h h h g f f g g b , ^ UXUXXX`.A H UXUXw.t yX7XUXJ O.UX5XqXqXqXqXqXqXqX", "qX0XyXOXi.g.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.x.+ n.UXKXIXV.y c.UXUX&XO -XwXUXJ O.UX5XqXqXqXqXqXqXqX", "qXqXwX7X:X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X>X7X1 M.UXKXPX,X! A UXUX:XX =XwXUXJ O.UX5XqXqXqXqXqXqXqX", "qX8XgXV. # O O O O O O O O O O O O O O o $ $.UXUXp.r.M P UXUXc.7 0X8XUXJ o.UX5XqXqXqXqXqXqXqX", "qXwX9XfXUXLXLXLXLXLXLXLXLXLXLXLXLXLXLXLXHXUXT.# iXUX-Xl.Y.BXUXHXi O.jX1XUXJ O.UX2XqXqXqXqXqXqXqX", "qXqX0XrXdXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXsXhXN h cXUXIXIXUXKX) 4 :XyXdXUXH X.UXaXwX9XqXqXqXqXqX", "qXqXqX0X9X9X9X9X9X9X9X9X9X9X9X9X9X9X9X9X9X7XrX _.jX6X<.d o + k q.rXyX9XqXqXqXqX", "qXqXqX0X9X0X9X9X9X9X9X9X9X9X9X9X9X9X9X9X9X0X7XrXqX4.0 X . 2 | ;XhXoX0 < w.XX}.1.& g ,XtX0XqXqXqX", "qXqX0XtXaXuXiXiXiXiXiXiXiXiXiXiXiXiXiXiXiXiXiXyXiXnXfX2X1XuXnXgXqXy F CXUXIXIXUXzXh n tXqXqXqXqX", "qX0XiX`.fXUXIXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXLXUXd.4 NXUXB.Z _ 4XUXaX* h.hX8XqXqX", "qX8XgXV.o ; * * * * * * * * * * * * * * * * * * * * * & & * & < d.UXLX=X0Xg %.UXUX+.m dX9XqXqX", "qX8XlXg.! V M.aXeX9XqXqXqXqX", "qXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqX0XqXhXfXtXtXgXgX0X0XqXqXqXqXqX", "qXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqX8X9XqXqX9X8XqXqXqXqXqXqXqX", "qXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqX", "qXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqX" }; const char *const *const xpm_icons[] = { xpm_icon_0, xpm_icon_1, xpm_icon_2, }; const int n_xpm_icons = 3; puzzles-20170606.272beef/icons/blackbox-icon.c0000644000175000017500000004704713115373752017701 0ustar simonsimon/* XPM */ static const char *const xpm_icon_0[] = { /* columns rows colors chars-per-pixel */ "16 16 256 2 ", " c black", ". c #010101", "X c #020202", "o c gray1", "O c #040404", "+ c gray2", "@ c #060606", "# c #070707", "$ c gray3", "% c #090909", "& c gray4", "* c #0B0B0B", "= c #0C0C0C", "- c gray5", "; c #0E0E0E", ": c gray6", "> c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", " c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", ".:.>.*.r.g.&.>.:.>.*.t.d.&.>.:.>.*.r.qXqX", "0XtX0XgXc.i 2.dXqXk.$.:.;.:.&.e.f.%.:.;.:.&.t.d.%.:.;.:.&.e.qXqX", "0XtXqXsXH.y.p.9XrXl.%.>.:.>.*.r.g.&.>.:.>.*.y.d.&.>.:.>.*.r.qXqX", "0XrXrXqXtXsXyXqXyXg.X.%.#.$.O.9.a.o.&.%.&.O.q.i.O.&.%.&.+.9.qXqX", "0XtX9X3X4X3X3X4X6XS.i.z.z.x.d.v.C.i.d.d.d.p.m.V.i.d.d.d.p.n.0XqX", "0XtX0X5X7X6X6X6X8XC.w.] V L ,.v.m.q.y.t.t.q.z.m.q.y.t.t.w.l.0XqX", "0XtXrXwXqXrXwXqXtXl.w . $.h.o.*.&.&.+.q.p.O.*.&.*.@.0.qXqX", "0XtX0XfXb.j.1.$XfX1. O o O b z.%.>.:.:.&.t.d.&.>.:.>.*.e.qXqX", "0XtX0XhXf.F D %XjX . o . t d.%.:.;.:.&.t.d.%.:.;.:.&.e.qXqX", "0XtXqXsXD.U.j.&XfX<. O o + v z.%.>.:.>.*.y.d.&.>.:.>.*.r.qXqX", "0XrXrXqXuXtXiXeXtXk.9 . @.g.X.&.%.&.O.q.i.o.&.%.&.+.9.qXqX", "0XtX9X3X3X3X3X3X6XF.a. .D T 5.V.C.a.g.f.g.a.M.C.a.g.f.g.s.m.0XqX", "0XtX0X6X7X7X6X6X9XN.9.s.a.s.e.h.m.9.r.e.r.0.l.b.9.r.e.r.0.k.0XqX", "0XtXrXqXwXwXwXqXtXh.O.&.%.%.+.0.s.+.*.&.*.@.w.p.+.*.&.*.@.0.qXqX", "0XtXeX0XqXqXqX0XrXl.%.>.:.:.*.r.g.&.>.:.:.&.t.d.&.>.:.>.*.e.qXqX", "0XtXeX0XqXqXqX0XrXk.$.:.;.:.&.e.f.%.:.;.:.&.t.d.%.:.;.:.&.e.qXqX", "0XtXeX0XqXqX0X0XrXl.&.,.:.>.*.r.g.&.>.:.>.*.y.f.&.>.:.>.*.r.qXqX", "0XrXrXwXeXeXeXwXyXg.X.&.$.%.O.8.p.o.%.$.%.O.0.i.o.%.$.%.O.8.qXqX", "0XtX6X,X1X1X1XX,XX9XwX", "qXqXqXqXqXqXqXqXwX7X5X5X5X5X5X5X6X5X5X5X5X5X6X6X5X5X5X5X5X6XqXqX", "qXqXqXqXqXqXqXqXqXwXeXwXeXwXeXwXwXeXwXeXwXeXwXwXeXwXeXwXeXwXqXqX" }; /* XPM */ static const char *const xpm_icon_2[] = { /* columns rows colors chars-per-pixel */ "48 48 256 2 ", " c black", ". c #010101", "X c #020202", "o c gray1", "O c #040404", "+ c gray2", "@ c #060606", "# c #070707", "$ c gray3", "% c #090909", "& c gray4", "* c #0B0B0B", "= c #0C0C0C", "- c gray5", "; c #0E0E0E", ": c gray6", "> c #101010", ", c #111111", "< c gray7", "1 c #131313", "2 c gray8", "3 c #151515", "4 c #161616", "5 c gray9", "6 c #181818", "7 c #191919", "8 c gray10", "9 c #1B1B1B", "0 c gray11", "q c #1D1D1D", "w c #1E1E1E", "e c gray12", "r c #202020", "t c gray13", "y c #222222", "u c #232323", "i c gray14", "p c #252525", "a c gray15", "s c #272727", "d c #282828", "f c gray16", "g c #2A2A2A", "h c gray17", "j c #2C2C2C", "k c #2D2D2D", "l c gray18", "z c #2F2F2F", "x c gray19", "c c #313131", "v c #323232", "b c gray20", "n c #343434", "m c #353535", "M c gray21", "N c #373737", "B c gray22", "V c #393939", "C c #3A3A3A", "Z c gray23", "A c #3C3C3C", "S c gray24", "D c #3E3E3E", "F c #3F3F3F", "G c gray25", "H c #414141", "J c gray26", "K c #434343", "L c #444444", "P c gray27", "I c #464646", "U c gray28", "Y c #484848", "T c #494949", "R c gray29", "E c #4B4B4B", "W c #4C4C4C", "Q c gray30", "! c #4E4E4E", "~ c gray31", "^ c #505050", "/ c #515151", "( c gray32", ") c #535353", "_ c gray33", "` c #555555", "' c #565656", "] c gray34", "[ c #585858", "{ c gray35", "} c #5A5A5A", "| c #5B5B5B", " . c gray36", ".. c #5D5D5D", "X. c gray37", "o. c #5F5F5F", "O. c #606060", "+. c gray38", "@. c #626262", "#. c gray39", "$. c #646464", "%. c #656565", "&. c gray40", "*. c #676767", "=. c #686868", "-. c DimGray", ";. c #6A6A6A", ":. c gray42", ">. c #6C6C6C", ",. c #6D6D6D", "<. c gray43", "1. c #6F6F6F", "2. c gray44", "3. c #717171", "4. c #727272", "5. c gray45", "6. c #747474", "7. c gray46", "8. c #767676", "9. c #777777", "0. c gray47", "q. c #797979", "w. c gray48", "e. c #7B7B7B", "r. c #7C7C7C", "t. c gray49", "y. c #7E7E7E", "u. c gray50", "i. c #808080", "p. c #818181", "a. c gray51", "s. c #838383", "d. c #848484", "f. c gray52", "g. c #868686", "h. c gray53", "j. c #888888", "k. c #898989", "l. c gray54", "z. c #8B8B8B", "x. c gray55", "c. c #8D8D8D", "v. c #8E8E8E", "b. c gray56", "n. c #909090", "m. c gray57", "M. c #929292", "N. c #939393", "B. c gray58", "V. c #959595", "C. c gray59", "Z. c #979797", "A. c #989898", "S. c gray60", "D. c #9A9A9A", "F. c #9B9B9B", "G. c gray61", "H. c #9D9D9D", "J. c gray62", "K. c #9F9F9F", "L. c #A0A0A0", "P. c gray63", "I. c #A2A2A2", "U. c gray64", "Y. c #A4A4A4", "T. c #A5A5A5", "R. c gray65", "E. c #A7A7A7", "W. c gray66", "Q. c #A9A9A9", "!. c #AAAAAA", "~. c gray67", "^. c #ACACAC", "/. c gray68", "(. c #AEAEAE", "). c #AFAFAF", "_. c gray69", "`. c #B1B1B1", "'. c #B2B2B2", "]. c gray70", "[. c #B4B4B4", "{. c gray71", "}. c #B6B6B6", "|. c #B7B7B7", " X c gray72", ".X c #B9B9B9", "XX c gray73", "oX c #BBBBBB", "OX c #BCBCBC", "+X c gray74", "@X c gray", "#X c gray75", "$X c #C0C0C0", "%X c #C1C1C1", "&X c gray76", "*X c #C3C3C3", "=X c gray77", "-X c #C5C5C5", ";X c #C6C6C6", ":X c gray78", ">X c #C8C8C8", ",X c gray79", ".4.3.3.3.3.4.:.v.v.:.4.3.3.3.3.4.:.b.x.:.4.3.3.3.3.4.:.b.tX0XqXqX", "qXqX0XiXwXqXqXtXdXaXqXwXwXqXd.#.-.=.=.=.=.-.@.k.k.@.-.=.=.=.=.-.+.l.h.@.-.=.=.=.=.;.@.l.yX0XqXqX", "qXqX0XiXqX0XeX,XR.'.tX0XqX0Xg.%.>.;.;.;.;.>.$.l.l.$.>.;.;.;.;.>.$.x.j.$.>.;.;.;.;.>.$.z.yX0XqXqX", "qXqX0XiXqX7XjXe.j n f.gX8X0Xf.%.:.;.;.;.;.:.$.l.l.$.:.;.;.;.;.:.#.z.j.$.:.;.;.;.;.:.$.z.yX0XqXqX", "qXqX0XiXqX8XjXw.G U n.fX9X0Xf.%.:.;.;.;.;.:.$.l.l.$.:.;.;.;.;.:.#.z.j.$.:.;.;.;.;.:.$.z.yX0XqXqX", "qXqX0XiXqX7XjXq.l n s.fX9X0Xf.%.:.;.;.;.;.:.$.l.l.$.:.;.;.;.;.:.#.z.j.$.:.;.;.;.;.:.$.z.yX0XqXqX", "qXqX0XiXqX9XsXS.Z.oX>.uX0X0Xf.%.:.;.;.;.;.:.$.l.l.$.:.;.;.;.;.:.#.z.j.$.:.;.;.;.;.:.$.z.yX0XqXqX", "qXqX0XiXqX0X9XiXiXtXfX9XqX0Xg.&.>.:.:.:.:.>.%.l.l.%.>.:.:.:.:.>.%.x.k.%.>.:.:.:.:.,.%.x.yX0XqXqX", "qXqX0XiXwXwXeXqX0XqX0XwXwXwXa.o.&.#.#.#.#.&.X.h.h.X.&.%.%.%.%.&.X.j.f.X.&.%.%.%.%.&.X.j.uX0XqXqX", "qXqX9XpX4X>X,X,X,X,X,X,X,X>XT.C.S.K.L.L.L.F.V.R.R.C.S.S.S.S.S.S.C.E.T.C.S.S.S.S.S.D.C.W.eXqXqXqX", "qXqX0XpX9X7X8X7X6X8X6X7X8X7Xc.6.q._ M v U 2.8.n.M.3.0.9.9.9.9.0.3.N.n.4.0.9.9.9.9.0.3.N.tX0XqXqX", "qXqX0XiXwXwXqXyXuXwXpXwXwX0Xf...9 . $ Y c.h.O.=.*.*.*.*.=.O.l.g.O.=.*.*.*.*.=.O.k.yX0XqXqX", "qXqX0XiXqX0XrX*X+X7X[.0XqX9Xl.t o X X X + p.x.#.>.;.;.;.;.>.$.x.j.$.>.;.;.;.;.>.$.z.yX0XqXqX", "qXqX0XiXqX7XlX6.{ 5Xu 7XwXeX6. X o } m.@.:.;.;.;.;.:.#.z.j.$.:.;.;.;.;.:.$.z.yX0XqXqX", "qXqX0XiXqX8XhXp.0 U i 9X0XuX+. o o J n.@.:.;.;.;.;.:.#.z.j.$.:.;.;.;.;.:.$.z.yX0XqXqX", "qXqX0XiXqX7XkX7.Y (.e 6XqXyX%. X o U n.@.:.;.;.;.;.:.#.z.j.$.:.;.;.;.;.:.$.z.yX0XqXqX", "qXqX0XiXqX9XsXJ.n.qX2.9XqXwXr.o . o %.n.@.:.;.;.;.;.:.#.z.j.$.:.;.;.;.;.:.$.z.yX0XqXqX", "qXqX0XiXqX0X9XiXaXqXgXqXqX9Xx.m . X o X 3 l.z.$.>.:.:.:.:.>.$.x.k.%.>.:.:.:.:.>.%.x.yX0XqXqX", "qXqX0XiXwXwXwXqX0XwX9XwXwXqXa.#.m X . w [ k.g.o.*.%.%.%.%.*.X.k.f.o.*.%.%.%.%.*.o.j.yX0XqXqX", "qXqX9XpX4X:X,X,X,X,X,X,X,X>XT.Z.L.n.9.5.g.J.S.R.E.Z.D.D.D.D.D.D.Z.E.R.Z.D.D.D.D.D.D.Z.Q.eXqXqXqX", "qXqX0XpX9X7X8X8X8X8X8X8X8X7Xc.3.7.0.r.r.q.7.1.m.m.2.8.7.7.7.7.8.2.M.b.2.8.7.7.7.7.8.2.M.tX0XqXqX", "qXqX0XiXwXqXwXwXwXwXwXqXwXqXd.@.-.*.&.&.&.=.+.j.j.+.=.*.*.*.*.=.O.l.g.+.=.*.*.*.*.-.+.k.yX0XqXqX", "qXqX0XiXqX0XqXqXqXqXqXqXqX0Xg.%.>.;.;.;.;.>.$.l.l.$.>.;.;.;.;.>.$.x.j.$.:.;.;.;.;.>.$.z.yX0XqXqX", "qXqX0XiXqXqXqXqXqXqXqXqXqX0Xf.%.:.;.;.;.;.:.$.l.l.$.:.;.;.;.;.:.#.z.j.$.:.;.;.;.;.:.$.z.yX0XqXqX", "qXqX0XiXqXqXqXqXqXqXqXqXqX0Xf.%.:.;.;.;.;.:.$.l.l.$.:.;.;.;.;.:.#.z.j.$.:.;.;.;.;.:.$.z.yX0XqXqX", "qXqX0XiXqXqXqXqXqXqXqXqXqX0Xf.%.:.;.;.;.;.:.$.l.l.$.:.;.;.;.;.:.#.z.j.$.:.;.;.;.;.:.$.z.yX0XqXqX", "qXqX0XiXqXqXqXqXqXqXqXqXqX0Xf.%.:.;.;.;.;.:.$.l.l.$.:.;.;.;.;.:.#.z.j.$.:.;.;.;.;.:.$.z.yX0XqXqX", "qXqX0XiXqX0XqXqXqXqXqX0XqX0Xg.&.,.:.:.:.:.,.%.z.z.%.>.:.:.:.:.,.%.x.k.%.>.:.:.:.:.,.%.x.yX0XqXqX", "qXqX0XiXeXeXeXeXeXeXeXeXeXwXp.X.%.$.$.$.$.%...g.g...%.$.$.$.$.%...j.d...%.$.$.$.$.%...h.uX0XqXqX", "qXqX0XpX>X&X*X*X*X*X*X*X*X=X^.P.U.U.U.U.U.U.P././.P.U.U.U.U.U.U.P./.^.P.U.U.U.U.U.Y.P.).wXqXqXqX", "qXqXqXqX7X6X6X6X6X6X6X6X5XrXrXyXyXyXyXyXyXtXiX6X6XiXtXyXyXyXyXtXiX5X6XiXtXyXrXrXyXtXuX8X8XwXqXqX", "qXqXqXqXwXwXwXwXwXwXwXeXqXaX0X0X0X0X0X0X0X0XwX2X2XwX0X0X0X0X0X0XwX2X3XwX0XqXsXiX9X0XqX5X9XwXqXqX", "qXqXqXqXqXqXqXqXqXqXqXqX0XiXqXqXqXqXqXqXqXqXeX3X3XeXqXqXqXqXqXqXeX2X3XwXqX9XU.`.eX0XwX5X9XwXqXqX", "qXqXqXqXqXqXqXqXqXqXqXqX0XpXqXqXqXqXqXqXqXqXeX3X3XeXqXqXqXqXqXqXeX2X3XwXwX7XY D aX9XwX5X9XwXqXqX", "qXqXqXqXqXqXqXqXqXqXqXqX0XpXqXqXqXqXqXqXqXqXeX3X3XeXqXqXqXqXqXqXeX2X3XeX8XjX(.Y kX8XwX5X9XwXqXqX", "qXqXqXqXqXqXqXqXqXqXqXqX0XpXqXqXqXqXqXqXqXqXeX3X3XeXqXqXqXqXqXqXeX2X3XwX0XyX0.g &XeXqX5X9XwXqXqX", "qXqXqXqXqXqXqXqXqXqXqXqX0XpXqXqXqXqXqXqXqXqXeX3X3XeXqXqXqXqXqXqXeX2X3XwXeX2X1. .F.pX0X5X9XwXqXqX", "qXqXqXqXqXqXqXqXqXqXqXqX0XpXqX0XqXqXqXqXqX0XwX3X3XwX0XqXqXqXqX0XwX2X3XwX0XwXhXlXpX9XwX5X9XwXqXqX", "qXqXqXqXqXqXqXqXqXqXqXqX0XpXwXeXeXeXeXeXeXwXtX4X4XtXwXeXeXeXeXwXtX4X5XrXeXeX0X9XqXeXrX6X9XwXqXqX", "qXqXqXqXqXqXqXqXqXqXqXqX0XiX:X%X*X*X*X*X*X*X*X$X$X*X*X*X*X*X*X*X*X$X$X*X*X*X*X*X*X*X*X*X0XqXqXqX", "qXqXqXqXqXqXqXqXqXqXqXqXqXqX8X7X7X7X7X7X7X7X7X7X7X7X7X7X7X7X7X7X7X7X7X7X7X7X7X7X7X7X7X8XqXqXqXqX", "qXqXqXqXqXqXqXqXqXqXqXqXqXqXwXwXwXwXwXwXwXwXwXwXwXwXwXwXwXwXwXwXwXwXwXwXwXwXwXwXwXwXwXwXqXqXqXqX", "qXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqX", "qXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqXqX" }; const char *const *const xpm_icons[] = { xpm_icon_0, xpm_icon_1, xpm_icon_2, }; const int n_xpm_icons = 3; puzzles-20170606.272beef/icons/untangle.rc0000644000175000017500000000005713115373752017153 0ustar simonsimon#include "puzzles.rc2" 200 ICON "untangle.ico" puzzles-20170606.272beef/icons/unruly.rc0000644000175000017500000000005513115373752016672 0ustar simonsimon#include "puzzles.rc2" 200 ICON "unruly.ico" puzzles-20170606.272beef/icons/unequal.rc0000644000175000017500000000005613115373752017007 0ustar simonsimon#include "puzzles.rc2" 200 ICON "unequal.ico" puzzles-20170606.272beef/icons/undead.rc0000644000175000017500000000005513115373752016574 0ustar simonsimon#include "puzzles.rc2" 200 ICON "undead.ico" puzzles-20170606.272beef/icons/twiddle.rc0000644000175000017500000000005613115373752016771 0ustar simonsimon#include "puzzles.rc2" 200 ICON "twiddle.ico" puzzles-20170606.272beef/icons/tracks.rc0000644000175000017500000000005513115373752016623 0ustar simonsimon#include "puzzles.rc2" 200 ICON "tracks.ico" puzzles-20170606.272beef/icons/towers.rc0000644000175000017500000000005513115373752016657 0ustar simonsimon#include "puzzles.rc2" 200 ICON "towers.ico" puzzles-20170606.272beef/icons/tents.rc0000644000175000017500000000005413115373752016470 0ustar simonsimon#include "puzzles.rc2" 200 ICON "tents.ico" puzzles-20170606.272beef/icons/solo.rc0000644000175000017500000000005313115373752016306 0ustar simonsimon#include "puzzles.rc2" 200 ICON "solo.ico" puzzles-20170606.272beef/icons/slant.rc0000644000175000017500000000005413115373752016454 0ustar simonsimon#include "puzzles.rc2" 200 ICON "slant.ico" puzzles-20170606.272beef/icons/sixteen.rc0000644000175000017500000000005613115373752017014 0ustar simonsimon#include "puzzles.rc2" 200 ICON "sixteen.ico" puzzles-20170606.272beef/icons/singles.rc0000644000175000017500000000005613115373752017001 0ustar simonsimon#include "puzzles.rc2" 200 ICON "singles.ico" puzzles-20170606.272beef/icons/signpost.rc0000644000175000017500000000005713115373752017204 0ustar simonsimon#include "puzzles.rc2" 200 ICON "signpost.ico" puzzles-20170606.272beef/icons/samegame.rc0000644000175000017500000000005713115373752017115 0ustar simonsimon#include "puzzles.rc2" 200 ICON "samegame.ico" puzzles-20170606.272beef/icons/rect.rc0000644000175000017500000000005313115373752016267 0ustar simonsimon#include "puzzles.rc2" 200 ICON "rect.ico" puzzles-20170606.272beef/icons/range.rc0000644000175000017500000000005413115373752016427 0ustar simonsimon#include "puzzles.rc2" 200 ICON "range.ico" puzzles-20170606.272beef/icons/pegs.rc0000644000175000017500000000005313115373752016270 0ustar simonsimon#include "puzzles.rc2" 200 ICON "pegs.ico" puzzles-20170606.272beef/icons/pearl.rc0000644000175000017500000000005413115373752016436 0ustar simonsimon#include "puzzles.rc2" 200 ICON "pearl.ico" puzzles-20170606.272beef/icons/pattern.rc0000644000175000017500000000005613115373752017012 0ustar simonsimon#include "puzzles.rc2" 200 ICON "pattern.ico" puzzles-20170606.272beef/icons/palisade.rc0000644000175000017500000000005713115373752017120 0ustar simonsimon#include "puzzles.rc2" 200 ICON "palisade.ico" puzzles-20170606.272beef/icons/netslide.rc0000644000175000017500000000005713115373752017145 0ustar simonsimon#include "puzzles.rc2" 200 ICON "netslide.ico" puzzles-20170606.272beef/icons/net.rc0000644000175000017500000000005213115373752016117 0ustar simonsimon#include "puzzles.rc2" 200 ICON "net.ico" puzzles-20170606.272beef/icons/mines.rc0000644000175000017500000000005413115373752016446 0ustar simonsimon#include "puzzles.rc2" 200 ICON "mines.ico" puzzles-20170606.272beef/icons/map.rc0000644000175000017500000000005213115373752016106 0ustar simonsimon#include "puzzles.rc2" 200 ICON "map.ico" puzzles-20170606.272beef/icons/magnets.rc0000644000175000017500000000005613115373752016773 0ustar simonsimon#include "puzzles.rc2" 200 ICON "magnets.ico" puzzles-20170606.272beef/icons/loopy.rc0000644000175000017500000000005413115373752016475 0ustar simonsimon#include "puzzles.rc2" 200 ICON "loopy.ico" puzzles-20170606.272beef/icons/lightup.rc0000644000175000017500000000005613115373752017011 0ustar simonsimon#include "puzzles.rc2" 200 ICON "lightup.ico" puzzles-20170606.272beef/icons/keen.rc0000644000175000017500000000005313115373752016254 0ustar simonsimon#include "puzzles.rc2" 200 ICON "keen.ico" puzzles-20170606.272beef/icons/inertia.rc0000644000175000017500000000005613115373752016770 0ustar simonsimon#include "puzzles.rc2" 200 ICON "inertia.ico" puzzles-20170606.272beef/icons/guess.rc0000644000175000017500000000005413115373752016461 0ustar simonsimon#include "puzzles.rc2" 200 ICON "guess.ico" puzzles-20170606.272beef/icons/galaxies.rc0000644000175000017500000000005713115373752017133 0ustar simonsimon#include "puzzles.rc2" 200 ICON "galaxies.ico" puzzles-20170606.272beef/icons/flood.rc0000644000175000017500000000005413115373752016436 0ustar simonsimon#include "puzzles.rc2" 200 ICON "flood.ico" puzzles-20170606.272beef/icons/flip.rc0000644000175000017500000000005313115373752016264 0ustar simonsimon#include "puzzles.rc2" 200 ICON "flip.ico" puzzles-20170606.272beef/icons/filling.rc0000644000175000017500000000005613115373752016761 0ustar simonsimon#include "puzzles.rc2" 200 ICON "filling.ico" puzzles-20170606.272beef/icons/fifteen.rc0000644000175000017500000000005613115373752016755 0ustar simonsimon#include "puzzles.rc2" 200 ICON "fifteen.ico" puzzles-20170606.272beef/icons/dominosa.rc0000644000175000017500000000005713115373752017147 0ustar simonsimon#include "puzzles.rc2" 200 ICON "dominosa.ico" puzzles-20170606.272beef/icons/cube.rc0000644000175000017500000000005313115373752016250 0ustar simonsimon#include "puzzles.rc2" 200 ICON "cube.ico" puzzles-20170606.272beef/icons/bridges.rc0000644000175000017500000000005613115373752016754 0ustar simonsimon#include "puzzles.rc2" 200 ICON "bridges.ico" puzzles-20170606.272beef/icons/blackbox.rc0000644000175000017500000000005713115373752017123 0ustar simonsimon#include "puzzles.rc2" 200 ICON "blackbox.ico" puzzles-20170606.272beef/icons/untangle.ico0000644000175000017500000006117613115373752017332 0ustar simonsimon 00 ¨%–  ¨>& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÓÓÚØØÙ××ÔÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔØÝݾÊÊÃÏÏÙÜÜÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÓÓØÜܱžž¿¸ºµµÚÛÛÔÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓØÕÕ×èè¨EEÿõ¦jjØååÔÑÑÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔ×ÓÓ×ÓÓÓÒÒÖÖÖÝÝÝÍËË©°°‡ffÌÄ ´§§ÚÝÝÔÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÚÚÍÝÝÌÝÝßààÑÑÑ«««œœœ¼»»¡©©Žª®®ÜááÔÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÚÚ¾¿¿­99²==£¤¤žžµ´´âáá§§§ÂÀÀ···ÄÃÃÚØØÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÖää¨]]üý˜MMÒààäáá···¢¢¢ååå§§§ÂÁÁÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÒÒÙáá¬áݯƒƒÜääÌÊʘ˜˜ÖÖÖÜÜܨ¨¨ÄÄÄÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔØØØÝÝÝØØØÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×ÖÖÍÖÖˆrr°ššÏØØÝÛÛ›››ÆÆÆØØØÚÚÚ§§§ÆÆÆÙÙÙÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÔÔÔÙÙÙÝÝÝØØØÉÉÉ«««¸¸¸ÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÛÛÛ½»»¯´´áççÝÜÜ­­­®®®ÞÞÞÒÒÒÛÛÛ¦¦¦ÈÈÈØØØÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÓÓÓÕÕÕÙÙÙÝÝÝØØØÆÆÆ®®®ŸŸŸ£££¶¶¶ÏÏÏÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÜÜÜ¥¥¥ÂÀÀÝÛÛÄÄÄœœœÜÜÜÔÔÔÔÔÔÛÛÛ¤¤¤ÊÊÊØØØÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÓÓÓÕÕÕÙÙÙÝÝÝ×××ÅÅÅ­­­žžž¤¤¤¸¸¸ÏÏÏÛÛÛÜÜÜ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÒÒÒžžžÖÖÖÖÖÖ˜˜˜ÏÏÏ×××ÔÔÔÔÔÔÛÛÛ£££ÌÌÌ×××ÕÕÕÕÕÕÔÔÔÓÓÓÕÕÕÚÚÚÝÝÝÖÖÖÃÃ쬬žžž¥¥¥ºººÐÐÐÜÜÜÜÜÜÖÖÖÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÛÛÛ½½½©©©æææ¢¢¢¹¹¹ÜÜÜÓÓÓÕÕÕÔÔÔÚÚÚ£££ÍÍÍÖÖÖÓÓÓÕÕÕÚÚÚÝÝÝÖÖÖ«««žžž¥¥¥»»»ÑÑÑÜÜÜÛÛÛÖÖÖÓÓÓÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÜÜÜ¥¥¥ÉÉÉ¿¿¿¢¢¢ÞÞÞÓÓÓÕÕÕÕÕÕÔÔÔØØØ¡¡¡ÏÏÏÜÜÜÝÝÝÕÕÕÁÁÁªªªŸŸŸ¦¦¦½½½ÒÒÒÜÜÜÛÛÛÖÖÖÓÓÓÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓ   ÐÐЗ——ÖÖÖÕÕÕÕÕÕÔÔÔÓÓÓÕÕÕÝÝݨ¨¨ÏÏÏÁÁÁ¨¨¨ŸŸŸ§§§¾¾¾ÓÓÓÜÜÜÛÛÛÖÖÖÓÓÓÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÚÚÚ½½½±±±¤¤¤ÁÁÁÙÙÙÒÒÒÖÖÖÛÛÛÜÜÜÓÓÓ¿¿¿œœœªªª¿¿¿ÔÔÔÝÝÝÚÚÚÖÖÖÓÓÓÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÒÒàÝݳ°°ššš¯¯¯ÞÞÞÙÙÙÜÜÜÒÒÒ½½½¦¦¦žžžªªª’’’ÓÓÓÝÝÝÚÚÚÕÕÕÓÓÓÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔ×ÝÝÃÒÒƒ£¤¤áááÐÐл»»¦¦¦žžž«««ÂÂÂÖÖÖÜÜÜ¥¥¥ÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÓÓØÞÞ¯””¿—""§¬¬¨§§œœ¬¬¬ÃÃÃÖÖÖÝÝÝÚÚÚÕÕÕÒÒÒ¡¡¡ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕØÔÔÊÛÛ°00ÿëllÐØØØÖÖÛÛÛÙÙÙÕÕÕÓÓÓÔÔÔÖÖÖÒÒÒ¡¡¡×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÕßߪkkÝÀŠŠµ¶¶ÏÏÏÜÜÜÖÖÖÓÓÓÕÕÕÕÕÕÖÖÖÑÑÑ¡¡¡ØØØÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÕÕ×ÖÖÐÙÙ¯¥¥»¼¼×ÛÛµ´´›››«««ÏÏÏÝÝÝ×××ÓÓÓÖÖÖÐÐТ¢¢ÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØØØØÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÔÔÝßßÚÚÚÕÔÔÜÜÜ××׸¸¸œœœªªªÍÍÍÝÝÝÙÙÙÌÌÌ¢¢¢ÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÛÛÛÆÆÆ­­­ÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÓÓÔÔÔÕÕÕÔÔÔÔÔÔÜÜÜØØØ»»»§§§ÎÎÎÔÔÔ¦¦¦ØØØÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÎÎΕ••ËËË×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔÛÛÛÙÙÙ¼¼¼   œœœááá×××ÓÓÓÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÒÒÒ•••ËËËÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔÛÛÛÝÝݵµµ{{{¨¨¨ÆÆÆÜÜÜÙÙÙÓÓÓÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔ×××ÕÕÕ–––ÆÆÆÛÛÛÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔ×××ÌÌÌ«««ÈÈÈžžž¢¢¢ÅÅÅÜÜÜÚÚÚÓÓÓÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÖÖÖØØØ˜˜˜ÁÁÁÜÜÜÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÄÄħ§§àààÚÚÚÃÃ⢢¡¡¡ÃÃÃÜÜÜÚÚÚÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÛÛÛ›››¼¼¼ÝÝÝÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÃÃé©©ÛÛÛÒÒÒÙÙÙÜÜÜÅÅÅ£££   ÀÀÀÛÛÛÛÛÛÔÔÔÔÓÓØÔÔÖÓÓÜÜÜžžž¶¶¶ÞÞÞÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÚÚÚÁÁÁªªªÝÝÝÓÓÓÔÔÔÓÓÓÙÙÙÝÝÝÈÈÈ¥¥¥ŸŸŸ¾¾¾ÚÙÙÜààÈÚÚÕâ⥥¥±±±ÞÞÞÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÚÚÚ¿¿¿¬¬¬ÝÝÝÓÓÓÕÕÕÕÕÕÔÔÔÓÓÓØØØÝÝÝÊÊÊ¥¤¤ ¤¤¥––º++™AA¤¬¬àßßÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÚÚÚ¾¾¾­­­ÜÜÜÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÖÖÖãßßÅÖÖ¥%%ÿ鮎ŽÚââÔÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÛÛÛ»»»¯¯¯ÜÜÜÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓØØØÝÝÝËÉÉ¥²²—EEñó¨¨ÛÞÞÔÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÛÛÛººº±±±ÜÜÜÔÔÔÕÕÕÔÔÔÓÓÓØØØÝÝÝÉÉɦ¦¦¿¾¾ÉÑÑ® ––£©©ÜÛÛÓÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÛÛÛ·¶¶²²²ÜÜÜÓÓÓÓÓÓÙÙÙÜÜÜÇÇǤ¤¤ŸŸŸ¾¾¾ÚÚÚÚÚÚ×ÖÖÛááãå嫪ª¬¬¬ÞÞÞÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÜÚÚ»»»¹¸¸ÛÚÚØÙÙÜÜÜÄÄÄ¢¢¢¡¡¡ÁÁÁÛÛÛÛÛÛÔÔÔÔÔÔÕÕÕÔÒÒÓÒÒÝÝÝŸŸŸ»»»ÜÜÜÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÜã㛞ž¢¦¦àååÁÀÀ¡¡¡¢¢¢ÄÄÄÜÜÜÚÚÚÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××———ÊÊÊÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÓÓÙßß®ËÆ‚‚¦©©ÆÅÅÜÜÜÙÙÙÓÓÓÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÍÍÍ–––ÕÕÕÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÒÒÒââ©IIÿö¢ddÞëëØÕÕÓÓÓÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÜÜÜ¿¿¿œœœÜÜÜÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÓÓÙÞÞ²žž¿ ·º´´ÙÚÚÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÞÞÞ¯¯¯¨¨¨ÝÝÝÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÓÓÝã㤯¯¤°°ßââÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÝÝÝ£££¼¼¼ÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔ×ÕÕÕÓÓÕÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÍÍÍÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ( @ ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔ×ÔÔØÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔ×××ÌÙÙÊØØØÙÙÕÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÔÔÔ×ÖÖÏ××ÇAAÈ..ÇÉÉØØØÕÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÙ××ÕÔÔÙÙÙÚÙÙ¬²²Ñ ä¼··ÚÜÜÔÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÕÕÔÛÛÂÐÐÔÜÜÁÀÀ°¯¯¬±±•††±œœØÝÝÔÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÖà཈ˆÙ©kk¶ÁÁÎÌÌ´³³ÁÅÅÂÇÇÚÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÕãã»mmò»aaÞíí­©©ÍÎÎÀ¿¿¿¾¾ÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔ×××ÛÛÛØØØÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÚÚÚ¿ÂÂ¡ŽŽØÚÚººº¸¸¸ááẺºÂÂÂÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔ×××ÚÚÚØØØÍÍͼ¼¼¯¯¯ÍÍÍ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÚÚÚ³²²Ñ××ÏÏÏ«««ÙÙÙÙÙÙ»»»ÃÃÃÙÙÙÔÔÔÕÕÕÔÔÔÔÔÔØØØÛÛÛØØØÌÌÌ»»»¯¯¯±±±¿¿¿ÏÏÏÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÒÒÒ®®®Ø×ש©©ÐÑÑÖÖÖÚÚÚ¹¹¹ÄÄÄØØØÔÔÔØØØÛÛÛ×××ËË˺ºº¯¯¯±±±ÀÀÀÐÐÐÙÙÙÚÚÚÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÁÁÁ¿¿¿¹¹¹¿¿¿ÚÚÚÒÒÒÙÙÙ¸¸¸ÉÉÉÞÞÞÖÖÖÊÊʹ¹¹¯¯¯²²²ÁÁÁÑÑÑÚÚÚÚÚÚÖÖÖÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙØØ¸¸¸···³³³ÚÚÚÓÓÓ×××àà๹¹»»»¼¼¼®®®²²²ÂÂÂÒÒÒÚÚÚÚÚÚÖÖÖÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÙÖÖ«ªªªªªÙÙÙÛÛÛÖÖÖÇÇǼ¼¼•••©©©ÅÅÅÒÒÒÚÚÚÙÙÙÖÖÖÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔØßß´ÁÁ™™ÏÎÎÉÊʶ¶¶®®®³³³ÉÉɳ³³ÏÏÏÜÜÜÕÕÕÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓ×àà¿””Ò¨^^´ÀÀ´±±ÄÄÄÔÔÔÙÙÙÞÞÞµµµÊÊÊ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÖää¸xxõ­DD·ÇÇÞÚÚÞÞÞÕÕÕÒÒÒÙÙÙ³³³ÌÌÌ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÐÔÔ·¦¦ÉÊʼ¼¼ªªª½½½ÕÕÕÚÚÚÙÙÙ²²²ÎÎÎ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÕÕÕÑÑÑÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÚßßØØØÚÚÚÓÓÓººº¬¬¬»»»ØØØ···ÏÏÏÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÙÙÙ­­­ÊÊÊØØØÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÓÓÕÔÔÔÔÔÕÕÕÛÛÛÔÔÔ»»»¯¯¯›››ÎÎÎÜÜÜÖÖÖÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÚÚÚ®®®ÀÀÀÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÚÚÚ××מžž©©©ºººÒÒÒÛÛÛÖÖÖÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÛÛÛ±±±¼¼¼ÜÜÜÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓ×××µµµÓÓÓÀÀÀ­­­···ÑÑÑÛÛÛÖÖÖÔÔÔÔÒÒÔÑÑÜÜÜ´´´¹¹¹ÜÜÜÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖ¯¯¯ÓÓÓÛÛÛ×××ÁÁÁ­­­¶¶¶ÐÐÐÛÚÚ×ààÛææ¸··µµµÜÜÜÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖ°°°ÔÔÔÔÔÔÕÕÕÚÚÚØØØÂ¬««·½½¿’’­ww±¶¶ÜÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ°°°ÕÕÕÕÕÕÕÕÕÔÔÔÓÓÓÛÚÚããã©®®Õ迺ºÙÛÛÔÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔ°°°ÖÖÖÕÕÕÔÔÔ×××ÛÛÛÍÍÍ´³³­µµÀff°HH¾ÂÂÛÛÛÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÓÑѳ¯¯ÕÔÔרØÛÛÛÌÌ̳³³®®®ÄÄÄÙØØÔââÎÞÞªªªÏÏÏØØØÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×ÖÖÑÚÚ¥¸¸ÜààÊÉɱ²²¯¯¯ÇÇÇÙÙÙÙÙÙÔÔÔÕÒÒÙÖÖÎÎΩ©©×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÕßß¾€€Ä!!ª’’±¶¶ÈÇÇÚÚÚÙÙÙÔÔÔÔÔÔÕÕÕÕÕÕÔÔÔÚÚÚÄÄÄ®®®ÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÓÓÏààÁEEù³xxÛèèØÕÕÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÜÜܸ¸¸···ÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØÚÚż¼ŸssÐÑÑÖÖÖÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÛÛÛ°°°ÄÄÄØØØÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔ×ÚÚÒÜÜ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÕÕÕÎÎÎÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÖÓÓÕÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÕÕÕÕÕÕÕÕÕÕÕÕ(  ÕÕÕÕÕÕÕÕÕÕÒÒÕÓÓ×××ÑÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÕââØßßÉÁÁÇ88ÐÃÃÖÚÚÕÔÔÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÔÔÔÛÛ΄„ħ§´ºº·ÖÔÔÕÕÕÕÕÕÔÔÔÕÕÕÖÖÖØØØÕÕÕÕÕÕÕÕÕÕÔÔÓÝÝÆffÄŸŸÅÎÎÆÊÊÔÕÕÕÕÕ×××ØØØÖÖÖÏÏÏÇÇÇÒÒÒÖÖÖÕÕÕÖÖÖÒÐÐÀÏÏÁÇÇÓÒÒÄÃÃØØØÕÕÕÏÏÏÆÆÆÂÂÂÄÄÄÌÌÌÕÕÕÕÕÕÔÔÔØØØÌÍ͸µµÔÓÓÖÖÖ¼¼¼ÇÇÇÁÁÁÄÄÄÌÌÌÔÔÔØØØ×××ÕÕÕÕÕÕÔÕÕ×××´±±¿¿¿ÉÉÉ¿¿¿´´´ÎÎÎÔÔÔØØØ×××ÕÕÕÔÔÔÔÔÔÕÕÕÕÕÕÖààЧ§½33¹ÃÃÑÏÏÔÔÔÅÅÅØØØÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕ×××ÖÖÖÕÕÕÕ××ÓÎÎϽ½ÇÉÉÄÄÄÉÉÉÄÄÄÙÙÙÔÔÔÕÕÕÕÕÕÔÔÔØØØÊÊÊÐÐÐÖÖÖÕÕÕÕ××ÖÛÛ×××ÓÓÓ±±±ÍÍÍÖÖÖרØÕÓÓÙ××ÊËËÁÁÁÖÖÖÕÕÕÕÕÕÕÕÕÕÔÔÔÔÔ×××ÔÔÔÂÂÂÈÈÈÀÀÀËÉÉÖßßÊÔÔÀ¿¿×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÐÎÎÅÃÃÚÛÛÖÔÔÅÓÓ¾ppÄnnÕããÕÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×ÕÕÏÕÕÅÑÑØÖÖÉÈÈÃÉÉÈ££Á™™ÑØØÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÖÜÜͱ±¿„„ÁÈÈÈÆÆÔÒÒÙààÑÙÙ¿½½ÕÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÖààÍÆccÓßߨÖÖÕÕÕÔÓÓØÖÖÌÍÍÃÃÃ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÛÛÒààÖÕÕÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÒÒÒÕÕÕÕÕÕ(0` ÕÕÕÔÓÓØÔÔÙÞÞ¾ÊÊÃÏÏÓÓÓ²žžÀ¸º´´Öää¨EEÿö¦jjØåå×ÓÓÜÜÜÌÌÌ©°°‡ffÌÄ ³¨¨ÙÚÚÍÝÝàßߪªªžžž¼»»¡©©Ž¬¬¬Ùáá­99²==¡¡¡µ´´ààਧ§¿¿¿ÄÃÃÕââ¨]]ü˜MMÒââäáẺºæææ¦©©ÃÃìáݯƒƒßââÌÊÊ›››ÍÖÖˆrr°ššÐÙÙœœœÆÆÆ¥¥¥ÈÈÈ¿¾¾àååÜÛÛ ––¢¦¦µµµÉÑÑ×ÛÛÐÐÐÇÇÇÓÔÔ———²²²›žž’’’ÕßßÃÒÒƒ¯””¿—""«««ÊÛÛ°00ëllªkkŠŠ¯¥¥{{{»¼¼¹¹¹¥¤¤¥––º++¤¯¯ÅÖÖ¥%%®¤°°—EEÃ®ŽŽšššÜääËÆ‚‚©II¢ddÞëë¿ ·   !"#$%&'() *+,- ./01%234"56789:;*<=>?@ABAC1DE!!FBCCGHIJKB*A;FFBCA!B1L;B*!B1FD2%1%4!B1FFBM)%%N4BD%O4(DDPB4DQ;)RDBSTUVB'LB!4BWXY3(@Z*%[\ ]^?F%KT_7`I%?aDK&%1;%NA!DBOCD@'O:IbAOAZM%AO4*B4%%AFRc4FFA%%)FGd94CB%D9[+ePD!NC%Hfg#hD!0ij-7kF1PN:lm]n1PCB)Jop3F PFCB%D9E!N11F*%%4GcNqRHE)%%4F;Ckrst3AO/u vwDxy P9hl9%D( @ÕÕÕÔÑÑØÕÕÌÙÙÊØØ×ØØÇAAÈ..ÇÉÉØØØ¬²²Ñ ä¼··ÚßßÕßßÂÐÐÁÁÁ°¯¯•††±œœ½ˆˆÙ©kk¶ÁÁÎÌÌ´³³ÁÅÅÐÔÔÕãã»mmò»aaÞíí­©©ÍÍÍÀ¿¿½½½ÜÛÛ¡ŽŽ·½½»»»ããã¶¶¶¬¬¬ËË˱±±ÓÓÓ«««ÊÉÉÞÞÞ¸¸¸ÃÃÃÜÜÜÅÅÅ¿ºº•••©©©Üàà™™³³³Ï×׿””Ò¨^^¸xxõ­DD·ÇÇ·¦¦›››žžžÛææ¸··¿’’­ww©®®Õ­µµÀff°HH¿ÂÂÎÞÞÑÚÚ¥¸¸¾€€Ä!!ª’’ÔââÁEEż¼ÒÜÜ    !"#$% & ' ()*) #%# +#, % -(,.%//, 0/ ) 1)../  %) /)121)../ & )+. *3)(,.4/ 0, 567896 :;-+,.1<=5>?@6 5+1ABCD&: .# E1%0% .#/ /%,) +/ ,- /%.F#5, G0)/&&.%5/ +/,+/5/)5,5,+/&HI+ , 0(JK<&. *LM 7. 5#+NOPQ . #.,6 R0# ST:1<,1 #0 UVW<1 6, XYKH/5)+  ZK/ .6 [# ( ÕÕÕÕÒÒÕÓÓ×××ÑÒÒÕÔÔÕââØßßÉÁÁÇ88ÐÃÃÖÚÚÔÔÔÔÛÛ΄„ħ§´ºº·ÖÔÔÖÖÖØØØÓÝÝÆffÄŸŸÅÎÎÆÊÊÔÕÕÏÏÏÇÇÇÒÒÒÒÐÐÀÏÏÁÇÇÓÒÒÄÃÃÆÆÆÂÂÂÄÄÄÌÌÌÌÍ͸µµÔÓÓ¼¼¼ÁÁÁ´±±¿¿¿ÉÉÉ´´´ÎÎÎÖààЧ§½33¹ÃÃÑÏÏÅÅÅÕ××ÓÎÎϽ½ÇÉÉÙÙÙÊÊÊÐÐÐÖÛÛÓÓÓ±±±ÍÍÍרØÙ××ÊËËÈÈÈÀÀÀËÉÉÖßßÊÔÔÀ¿¿ÐÎÎÅÃÃÚÛÛÅÓÓ¾ppÄnnÕãã×ÕÕÏÕÕÅÑÑØÖÖÉÈÈÃÉÉÈ££Á™™ÑØØÖÕÕÖÜÜͱ±¿„„ÁÈÈÈÆÆÔÒÒÙààÑÙÙ¿½½ÕÖÖÍÆccÓßßÃÃÃÒàà     !"#$%& '()*+%& ,-.-/0  12345 6 789:%.%; <=7>?$@ABCD+  $EFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcde1fghU)U'i j[ (0`€€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwHwwwwwwwwwwwwwwwwwwwwwwxÌGwwwwwwwwwwwwwwwwwwwwwxÌGwwwwwwwwwwwwwwwwwwwwwˆ„wwwwwwwwwwwwwwwwwwwwx‡x‡wwwwwwwwwwwwwwwwwwtȈw‡wwwwwwwwwwwwwwwwwwwŒÄww‡xwwwwwwwwwwwwwwwwwwLÈwxwwwwwwwwwwwwwwwwwwwwxGw‡wxwwwwwwwwwwwwwwwwwwwwxwwwwwwwwwwwwwˆ‡wwwwww‡wxwwˆwwwwwwwwxxwwwwwwww‡w‡ww‡wwwwwwwˆˆwwwwwwwww‡wwww‡wwwwwxxwwwwwwwwwwwwxwww‡wwww‡ˆwwwwwwwwwwwxw‡wwwwwwwˆwwwwwwwwwwwwwxxwwww‡ww‡wwwwwwwwwwwwww‡ˆwwwwˆˆ‡wwwwwwwwwwwwwww‡wwwwˆ‡wwwwwwwwwwwwwwwwwˆwww‡w‡wwwwwwwwwwwwwwwwx‡wˆwww‡wwwwwwwwwwwwwwwwLˆˆwwww‡wwwwwwwwwwwwwwwxÌGwwwwwwwwwwwwwwwwwwwwwxÌHwwwww‡wwwwwwwwwwwwwwwwˆwˆ‡www‡wwwwwwwwwwwwwwwwwww‡‡ww‡wwwwwwwwwwwwwwwwwwwwwww‡wwwwwwwwwwwˆwwwwwwwwwˆ‡wwwwwwwwwwww‡wwwwwwwwwwx‡wwwwwwwwwwwwwwwwwwwwwwwˆwwwwwwwwww‡wwwwwwwwwwww‡ˆ‡wwwwwwwwwwwwwwwwwwwww‡wxwwwwwwwˆwwwwwwwwwwwwwwwwxwwwwwxwwwwwwwwwwwwww‡www‡‡wwwˆwwwwwwwwwwwwww‡wwwwx‡wxwwwwwwwwwwwwwww‡wwwwwxLÈwwwwwwwwwwwwwwx‡wwwwwwLÄwwwwwwwwwwwwwww‡wwwwwxŒÈwwwwwwwwwwwwwwwwwwwwˆ‡xxwwwwwwwwwwwwwwwwwwww‡www‡wwwwwwwwwwwwww‡ww‡wwwwwxwwwwwwwwwwwwwxwwx‡wwwwwxwwwwwwwwwwwwwx‡ˆ‡wwwwwww‡wwwwwwwwwwwwLÄwwwwwwwwwxwwwwwwwwwwwwŒÄwwwwwwwwww‡wwwwwwwwwwwtGwwwwwwwwwwxwwwwwwwwwwww‡wwwwwwwwwwxwwwwwwwwwwwwwwwwwwwwwwwwwww( @€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿwÿw÷w÷ÿww÷w÷w÷ww÷Äww÷ww÷÷ÿwwwÌww÷wwÿwwÿwww‡ÿwwÿ÷wwwwŒxw‡ww÷wÿwÿwwÌwwwÿww÷wwww÷‡wwwwÿÿw÷÷‡÷w÷ww÷w÷÷wwwwwwwwwwwwxww÷www÷wwww÷÷÷÷ww÷wwwww÷w÷ww÷www‡w÷w÷÷w÷xwww‡ww÷wwwww÷‡÷www÷ww÷ÿw÷|Çwÿww÷÷w÷wwtGwwww÷wwÿw÷wwwww÷wÿwwwwwwwwwwÿ÷w÷w÷w÷÷÷www÷÷÷wwww÷÷w÷÷ww‡w÷wÿ÷w÷÷wwÿwwwwwwwwwwwwww÷ww÷÷w÷ww÷wwwwww÷÷w÷÷wÿwww÷wxÈ÷w÷wÿww÷wwøÈ÷ww÷w÷÷w‡wwˆwwÿww÷wwwww÷w÷÷÷wÿww÷wwwwwww÷÷wwwüG÷ÿwwÿ÷ww÷wÿw÷|Çww÷www÷÷w÷÷÷w‡w÷wwww÷w÷w÷÷wwÿww( €€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ÷wwÿw÷w÷Ç÷wwwwwwww÷øww÷÷ÿwww÷wwwwwwwww÷w÷÷w÷øÇww÷wÿw÷w÷www÷wwww÷ww÷ww÷wwwˆ÷w÷÷wwwww÷÷wwwww‡÷ww÷www÷puzzles-20170606.272beef/icons/unruly.ico0000644000175000017500000006117613115373751017052 0ustar simonsimon 00 ¨%–  ¨>& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $ææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææèèèééééééééééééééééééèèèèèèèèèèèèèèèèèèçççççççççççççççççççççèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèçççææææææææææææææææææææææææÝÝÝÙÙÙÚÚÚÙÙÙÙÙÙÙÙÙÛÛÛßßßÞÞÞÞÞÞÞÞÞßßßÞÞÞâââäääãããããããããäääãããßßßÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßßßßÞÞÞÞÞÞÞÞÞßßßÞÞÞáááæææææææææææææææåååìììÍÍÍtttŒŒŒˆˆˆˆˆˆˆˆˆŠŠŠ€€€kkknnnnnnnnnnnnooo^^^SSSUUUUUUUUUTTTXXXmmmnnnnnnnnnnnnnnnjjjnnnnnnnnnnnnnnnkkklllnnnnnnnnnnnnkkkrrráááçççæææææææææåååîîî“““åååÞÞÞàààßßßæææ¼¼¼www~~~„„„JJJ(((000///000---777|||€€€~~~ttt€€€wwwyyy€€€~~~kkkÞÞÞèèèæææææææææåååîîîÃÃÔ””ÖÖÖÔÔÔ×××ÕÕÕää人ºxxx‚‚‚€€€€€€………PPP---666555555555===~~~€€€€€€vvv€€€€€€€€€‚‚‚yyy{{{€€€€€€nnnßßßèèèæææææææææåååîîîÃÃÔ””ÖÖÖÑÑÑÔÔÔÒÒÒâââ»»»xxx‚‚‚€€€€€€………OOO,,,444333333333<<<}}}€€€€€€€€€vvv€€€€€€€€€‚‚‚xxx{{{€€€€€€€€€nnnÞÞÞèèèæææææææææåååîîîÃÃÓ““ÖÖÖÓÓÓÖÖÖÔÔÔãã㺺ºxxx€€€€€€„„„OOO,,,444444444333<<<}}}€€€€€€€€€uuu€€€€€€€€€xxx{{{€€€€€€€€€nnnÞÞÞèèèæææææææææåååîîîÃÃÖ––ØØØÎÎÎÑÑÑÎÎÎààཽ½yyyƒƒƒ€€€†††OOO,,,222111222111<<<~~~‚‚‚€€€www‚‚‚ƒƒƒyyy|||‚‚‚€€€nnnÞÞÞèèèæææææææææåååîîîÄÄÄŽŽŽÓÓÓÅÅÅÈÈÈÆÆÆÎÎβ²²uuu~~~|||}}}|||MMM,,,222111111///:::xxx{{{{{{{{{{{{zzzqqq{{{{{{{{{zzz|||tttvvv|||{{{{{{{{{yyylllßßßèèèæææææææææåååìììÎÎÎEEE???AAAAAAAAA@@@AAA<<<;;;;;;;;;===222~~~ÁÁÁ¶¶¶¸¸¸···¼¼¼¤¤¤rrrzzzxxxxxxyyyxxxoooyyyxxxxxxxxxzzzrrrtttyyyxxxxxxyyywwwkkkßßßèèèæææææææææåååëëëÏÏÏ===...000000000///444333111333333666'''èèèÙÙÙÛÛÛÚÚÚáááÀÀÀzzzƒƒƒ‚‚‚‚‚‚www‚‚‚‚‚‚ƒƒƒzzz|||ƒƒƒ‚‚‚‚‚‚nnnÞÞÞèèèæææææææææåååëëëÏÏÏ???222444444444333888555111444333777***‰‰‰ßßßÑÑÑÔÔÔÒÒÒÙÙÙºººxxx€€€€€€€€€uuu€€€€€€€€€xxxzzz€€€€€€nnnÞÞÞèèèæææææææææåååëëëÏÏÏ>>>111444333333222777444111444333666)))ŠŠŠáááÒÒÒÕÕÕÔÔÔÛÛÛ»»»xxx‚‚‚€€€€€€€€€vvv€€€€€€€€€‚‚‚xxx{{{€€€€€€€€€nnnÞÞÞèèèæææææææææåååëëëÏÏÏ>>>111444333333222777555222444444777***ŠŠŠßßßÑÑÑÓÓÓÒÒÒÙÙÙºººyyyƒƒƒ€€€vvv€€€€€€€€€€€€xxx{{{€€€€€€€€€nnnÞÞÞèèèæææææææææåååëëëÏÏÏ>>>111333333333222666000+++,,,,,,///"""ŒŒŒéééÙÙÙÜÜÜÛÛÛâââÀÀÀttt}}}{{{||||||zzzuuu‚‚‚€€€€€€‚‚‚yyy{{{‚‚‚€€€nnnÞÞÞèèèæææææææææåååëëëÏÏÏAAA666999888888777===PPPPPPPPPPPPQQQJJJwww¥¥¥žžžŸŸŸŸŸŸ¢¢¢’’’‰‰‰‘‘‘uuuuuuvvvvvvuuuwwwoooqqqwwwuuuvvvvvvtttjjjßßßèèèæææææææææåååëëëÏÏÏ>>>222444333444111===‚‚‚………………………………………sssyyyyyyyyyyyyxxxxxxÎÎÎÜÜÜØØØÙÙÙØØØÝÝÝzzz€€€xxxzzz€€€~~~nnnßßßèèèæææææææææåååëëëÏÏÏ>>>111444333333111===}}}€€€~~~vvvƒƒƒ‚‚‚‚‚‚‚‚‚ÊÊÊ×××ÔÔÔÔÔÔÓÓÓØØØ|||€€€€€€‚‚‚yyy{{{€€€€€€nnnÞÞÞèèèæææææææææåååëëëÏÏÏ>>>111444333444111===~~~€€€€€€€€€vvv€€€€€€€€€€€€~~~ÊÊÊØØØÔÔÔÕÕÕÔÔÔÙÙÙ|||€€€€€€‚‚‚xxx{{{€€€€€€€€€nnnÞÞÞèèèæææææææææåååëëëÏÏÏ>>>111444333444111===~~~€€€€€€€€€€€€uuu€€€€€€€€€€€€~~~ÊÊÊ×××ÔÔÔÔÔÔÔÔÔØØØ{{{€€€€€€xxx{{{€€€€€€€€€nnnÞÞÞèèèæææææææææåååëëëÏÏÏ>>>111444333444111===€€€‚‚‚‚‚‚‚‚‚vvv‚‚‚ÌÌÌÚÚÚ××××××ÖÖÖÛÛÛ‘‘‘}}}ƒƒƒ‚‚‚ƒƒƒzzz{{{‚‚‚€€€nnnÞÞÞèèèæææææææææåååëëëÏÏÏ===...111111111...:::wwwyyyxxxxxxyyywwwrrr~~~}}}}}}}}}}}}{{{ÃÃÃÏÏÏÌÌÌÍÍÍÌÌÌÑÑщ‰‰tttyyyxxxxxxzzzrrrxxx~~~}}}}}}~~~|||mmmßßßèèèæææææææææåååîîîÅÅŃƒƒ½½½´´´¶¶¶µµµ¹¹¹¦¦¦±±±½½½ººº»»»¹¹¹ÂÂÂddd444>>><<<<<<;;;???CCCBBBBBBBBBDDD999ÄÄĹ¹¹»»»ºººÀÀÀ¤¤¤:::<<<<<<<<<===777XXXãããçççæææææææææåååîîîÃÃ×——æææÚÚÚÜÜÜÛÛÛàààÆÆÆÎÎÎÞÞÞÚÚÚÛÛÛØØØääähhh&&&555333333333555111///222111555%%%‰‰‰çççØØØÛÛÛÙÙÙááá¼¼¼000111111111222+++TTTãããçççæææææææææåååîîîÃÃÓ““ÝÝÝÑÑÑÓÓÓÓÓÓØØØ¿¿¿ÇÇÇ×××ÓÓÓÔÔÔÒÒÒÝÝÝggg'''555333333555888555111444333777***‡‡‡ßßßÑÑÑÔÔÔÒÒÒÚÚÚ···222444444333555...UUUãããçççæææææææææåååîîîÃÃÓ““ßßßÓÓÓÕÕÕÔÔÔÙÙÙÀÀÀÉÉÉØØØÕÕÕÕÕÕÓÓÓÞÞÞggg'''555333333444777444111444333666)))‡‡‡áááÒÒÒÕÕÕÔÔÔÛÛÛ¸¸¸222333333333444---UUUãããçççæææææææææåååîîîÃÃÓ““ÞÞÞÒÒÒÔÔÔÔÔÔÙÙÙ¿¿¿ÆÆÆÕÕÕÒÒÒÒÒÒÐÐÐÛÛÛhhh)))777555555666999444111333333666)))†††ÞÞÞÐÐÐÒÒÒÑÑÑÙÙÙ¶¶¶444555555555666000VVVãããçççæææææææææåååîîîÃÃÔ””áááÕÕÕ××××××ÛÛÛÂÂÂÓÓÓäääàààáááÞÞÞëëëfff)))'''''''''///555///111000444&&&íííÞÞÞáááßßßèèèÁÁÁ((()))))))))+++###RRRäääçççæææææææææåååîîîÅÅÅ………···¸¸¸···½½½¥¥¥ƒƒƒŒŒŒŠŠŠŠŠŠŠŠŠŒŒŒlllfffhhhggggggiii```999888888888999222eee‰‰‰ŠŠŠŠŠŠŒŒŒdddhhhgggggghhheeefffàààèèèæææææææææåååîîîÃÃÑ‘‘ÝÝÝ×××ÙÙÙØØØààà°°°%%%(((((('''***ŒŒŒëëëÛÛÛÞÞÞÜÜÜååå½½½111555666555555666222&&&))))))***%%%777ÔÔÔáááÝÝÝÞÞÞÝÝÝãã㌌ŒÙÙÙéééæææææææææåååîîîÃÃÔ””ØØØÖÖÖÙÙÙ×××çççµµµ222666666666888***ŠŠŠÞÞÞÐÐÐÓÓÓÑÑÑÚÚÚ´´´///222444333444555999444666666777555BBBÉÉÉÖÖÖÒÒÒÓÓÓÒÒÒ××׉‰‰ÙÙÙéééæææææææææåååîîîÃÃÔ””ÖÖÖÑÑÑÔÔÔÑÑÑäääµµµ///444333333666'''ŠŠŠáááÒÒÒÕÕÕÓÓÓÜÜܶ¶¶000111333333333555888000333333333222@@@ËËËØØØÔÔÔÕÕÕÔÔÔÙÙÙ‰‰‰ÙÙÙéééæææææææææåååîîîÃÃÔ””ÖÖÖÓÓÓÖÖÖÓÓÓååå´´´///444333333666(((ŠŠŠàààÒÒÒÔÔÔÓÓÓÛÛÛ¶¶¶000222444333444555888111333444444222@@@ËËË×××ÔÔÔÕÕÕÔÔÔÙÙÙ‰‰‰ÙÙÙéééæææææææææåååîîîÃÃÕ••×××ÍÍÍÑÑÑÎÎÎááá¶¶¶///444333333666'''ŒŒŒãããÕÕÕ×××ÖÖÖÞÞÞ¸¸¸000111222222222555888000111111111000@@@ÎÎÎÛÛÛ×××ØØØ×××ÜÜÜŠŠŠÙÙÙéééæææææææææåååîîîÄÄÄÖÖÖÈÈÈÊÊÊÈÈÈÓÓÓ®®®///333333333555(((………×××ÉÉÉÌÌÌÊÊÊÒÒÒ®®®.../////////...///888555444444555222AAA¿¿¿ÊÊÊÈÈÈÈÈÈÈÈÈÌÌÌ………ÚÚÚéééæææææææææåååìììÎÎÎGGGCCCEEEDDDEEECCCHHHpppsssrrrrrrrrrpppqqq€€€~~~~~~~~~zzz«««¶¶¶³³³´´´²²²»»»aaa///999777888444BBB¸¸¸ÄÄÄÁÁÁÁÁÁÁÁÁÃÃÃÚÚÚéééæææææææææåååëëëÏÏÏ<<<---000///000---:::„„„ƒƒƒƒƒƒƒƒƒ‚‚‚vvv€€€€€€€€€€€€~~~ÑÑÑßßßÜÜÜÜÜÜÚÚÚææælll(((555222333///@@@ÍÍÍÞÞÞâââáááâââää䊊ŠÙÙÙéééæææææææææåååëëëÏÏÏ???222555444444222===}}}€€€€€€~~~uuu€€€€€€€€€€€€~~~ÉÉÉÖÖÖÓÓÓÓÓÓÑÑÑÝÝÝiii)))555333444000AAAÆÆÆÏÏÏÔÔÔÒÒÒÕÕÕßß߈ˆˆÙÙÙéééæææææææææåååëëëÏÏÏ>>>111444333444111===~~~€€€€€€€€€vvv€€€€€€€€€€€€~~~ÊÊÊØØØÔÔÔÕÕÕÓÓÓßßßjjj)))555333444000AAAÈÈÈÑÑÑÖÖÖÔÔÔ×××àààˆˆˆÙÙÙéééæææææææææåååëëëÏÏÏ???222444444444111===}}}€€€€€€~~~uuu€€€}}}ÉÉÉÖÖÖÒÒÒÓÓÓÑÑÑÜÜÜjjj***666444444000AAAÅÅÅÎÎÎÓÓÓÑÑÑÔÔÔÞÞÞˆˆˆÚÚÚéééæææææææææåååëëëÏÏÏ===///222111222///<<<‚‚‚„„„„„„„„„„„„ƒƒƒyyy………„„„„„„„„„„„„ÔÔÔâââÞÞÞßßßÝÝÝééélll&&&333111222...???ÓÓÓØØØÖÖÖÖÖÖÖÖÖåå匌ŒÙÙÙéééæææææææææåååìììÎÎÎDDD===???>>>>>>===CCCfffggggggggggggfffaaagggggggggggggggfffŽŽŽ•••““““““’’’˜˜˜[[[999???>>>???===EEEŽŽŽ–––“““””””””“““tttÝÝÝèèèææææææææææææçççâââÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÎÎÎÊÊÊÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÄÄÄÃÃÃÃÃÃÃÃÃÃÃÃÂÂÂËËËÐÐÐÏÏÏÏÏÏÏÏÏÏÏÏÎÎÎÄÄÄÃÃÃÃÃÃÃÃÃÃÃÃÂÂÂÍÍÍæææææææææææææææææææææçççìììëëëëëëëëëëëëëëëëëëííííííííííííííííííìììííííííííííííííííííîîîîîîîîîîîîîîîîîîìììëëëëëëëëëëëëëëëìììîîîîîîîîîîîîîîîîîîìììææææææææææææææææææææææææååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææ( @ ææææææêêêìììëëëìììëëëêêêêêêêêêêêêéééééééééééééééêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêéééææææææææææææÖÖÖÐÐÐÑÑÑÑÑÑÓÓÓØØØ×××××××××ÚÚÚÝÝÝÝÝÝÝÝÝÜÜÜØØØ×××××××××ØØØ×××××××××ØØØØØØ×××ØØØ×××ÚÚÚåååæææêêêÖÖÖŒŒŒªªª¦¦¦ªªª˜˜˜ppptttsssvvvYYYCCCHHHFFFIIIoootttssssssooosssssstttqqqppptttssssssoooÚÚÚéééìììÑÑѧ§§äääßßßèèèÈÈÈ{{{‚‚‚€€€‡‡‡QQQ)))222///444zzzƒƒƒ‚‚‚yyy‚‚‚}}}{{{‚‚‚ƒƒƒsss×××êêêëëëÒÒÒ¡¡¡ÔÔÔÐÐÐÚÚÚÁÁÁyyy€€€~~~„„„TTT...777555:::yyy€€€xxx€€€€€€|||zzzsssØØØêêêëëëÑÑѧ§§ÜÜÜÕÕÕàààÈÈÈ}}}„„„‰‰‰SSS'''000---555zzzƒƒƒzzz‚‚‚~~~|||‚‚‚‚‚‚ttt×××êêêëëëÓÓÓ”””ººº²²²¹¹¹§§§ppptttssswwwWWW???DDDBBBFFFuuu|||zzz{{{tttzzzzzz{{{wwwvvv|||zzz{{{pppØØØêêêéééÝÝÝFFF...444222555555444777)))ÚÚÚÌÌÌÒÒÒÁÁÁ{{{}}}}}}}}}vvv||||||}}}yyywww~~~|||}}}qqqØØØêêêéééÝÝÝFFF///444222666333222666)))………ãããÓÓÓÚÚÚÈÈÈyyy€€€‚‚‚}}}{{{‚‚‚€€€‚‚‚ttt×××êêêéééÝÝÝFFF///444333666555444777***„„„ßßßÐÐÐ×××ÅÅÅ‚‚‚‚‚‚yyy€€€€€€|||zzz€€€sss×××êêêéééÝÝÝFFF///444333555...+++///!!!………ççç×××ÞÞÞËËËxxxyyyzzzyyyuuu€€€€€€€€€|||zzzsss×××êêêéééÝÝÝHHH333888555<<<[[[\\\\\\WWWwww———ššš’’’ššš£££   ¥¥¥†††uuuyyyyyyvvvtttzzzxxxyyyoooØØØêêêéééÝÝÝFFF///444111===ƒƒƒ†††………†††xxxzzz{{{{{{yyyÌÌÌßßßÙÙÙãã㥥¥yyy‚‚‚}}}{{{€€€‚‚‚sss×××êêêéééÝÝÝGGG///555111===}}}~~~yyy~~~ÅÅÅÖÖÖÐÐÐÙÙÙ   zzz}}}zzzsss×××êêêéééÝÝÝEEE---333///;;;~~~€€€€€€zzz‚‚‚‚‚‚‚‚‚ÊÊÊÜÜÜ×××ààࣣ£yyy‚‚‚}}}|||ƒƒƒƒƒƒttt×××êêêéééÜÜÜJJJ666;;;888AAA|||~~~~~~~~~uuuyyyyyyyyywww¸¸¸ÇÇÇÃÃÃÊÊÊ™™™xxx{{{uuuzzzyyyzzzoooØØØêêêëëëÓÓÓ›››ËËËÃÃÃÇÇǸ¸¸¿¿¿ÉÉÉÄÄÄÑÑÑppp...;;;888:::;;;:::===111rrrÐÐÐÄÄÄÈÈÈÁÁÁFFF444999333IIIÜÜÜéééëëëÑÑѧ§§ààà×××ÜÜÜÊÊÊÏÏÏÛÛÛÕÕÕääättt%%%555222666222111444'''tttäääÕÕÕÚÚÚÒÒÒCCC...444...FFFÝÝÝéééëëëÒÒÒ¤¤¤ÛÛÛÒÒÒ×××ÅÅÅÉÉÉÔÔÔÏÏÏÜÜÜttt***888666999444333666***sssÜÜÜÏÏÏÓÓÓËËËFFF222888222HHHÝÝÝéééëëëÑÑÑ¥¥¥ÝÝÝÔÔÔØØØÈÈÈ×××ãããÞÞÞííísss)))&&&,,,444111444'''xxxíííÝÝÝãããÚÚÚ<<<###***###@@@ÞÞÞèèèëëëÓÓÓšššÈÈÈÀÀÀÆÆÆ°°°………„„„………tttssssssuuuooo:::666888111WWWŠŠŠƒƒƒ………qqqtttttttttlllØØØêêêëëëÒÒÒ£££ÝÝÝ×××ââ⺺º&&&'''+++………íííÜÜÜäääÏÏÏ:::222555666222'''))))))'''ÀÀÀçççÝÝÝèèè«««ÑÑÑìììëëëÒÒÒ£££×××ÒÒÒÞÞÞ½½½444666999***„„„ÝÝÝÏÏÏÖÖÖÂÂÂ888111444444888444666666666¶¶¶ØØØÏÏÏÙÙÙ£££ÒÒÒëëëëëëÒÒÒ¤¤¤ØØØÒÒÒßßß¾¾¾111333666'''………ãããÓÓÓÛÛÛÇÇÇ888000333444777111222333333ºººÞÞÞÔÔÔßßߦ¦¦ÑÑÑëëëëëëÒÒÒ¡¡¡ÐÐÐÆÆÆÑÑÑ´´´222333666(((ÙÙÙÊÊÊÑÑѾ¾¾888...111111777444333333333±±±ÑÑÑÈÈÈÒÒÒ   ÒÒÒëëëéééÜÜÜPPPBBBFFFCCCIIIrrrttttttsssuuuƒƒƒ‚‚‚‚‚‚®®®»»»¶¶¶ÂÂÂxxx,,,888666444­­­ÐÐÐÈÈÈÐÐÐÒÒÒëëëéééÝÝÝDDD***000,,,999ƒƒƒƒƒƒƒƒƒyyy}}}ÌÌÌßßßØØØèè臇‡&&&555222222···ÞÞÞØØØæææ¨¨¨ÑÑÑìììéééÝÝÝHHH111777333>>>}}}€€€xxx€€€€€€€€€~~~ÄÄÄÕÕÕÏÏÏÞÞÞƒƒƒ)))777444444³³³ÖÖÖÐÐÐßßߦ¦¦ÑÑÑëëëéééÝÝÝCCC***000,,,999‚‚‚yyy‚‚‚‚‚‚ÍÍÍàààÙÙÙéé醆†"""222///...ºººÜÜÜÔÔÔää䪪ªÐÐÐìììéééÝÝÝUUUCCCGGGEEELLLrrrtttssssssooosssssssssrrr§§§£££¬¬¬vvv???HHHFFFFFF”””§§§¡¡¡§§§ŒŒŒÖÖÖêêêæææåååÝÝÝÝÝÝÝÝÝÝÝÝÜÜÜØØØ×××××××××ØØØ×××××××××ØØØÒÒÒÑÑÑÒÒÒÑÑÑ×××ÞÞÞÝÝÝÝÝÝÝÝÝÓÓÓÑÑÑÒÒÒÑÑÑÖÖÖææææææææææææéééééééééééééééêêêêêêêêêêêêêêêêêêêêêêêêêêêëëëëëëëëëìììêêêèèèéééééééééëëëëëëëëëìììêêêææææææ(  åå娨ØÕÕÕØØØÙÙÙÙÙÙÛÛÛÛÛÛÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙØØØÚÚÚåååØØØ±±±ÉÉÉ–––~~~pppEEEMMM|||}}}~~~‚‚‚ÚÚÚÖÖÖÇÇÇïïï§§§„„„jjj***yyy€€€{{{€€€{{{ØØØÙÙÙxxxvvvdddQQQbbbŠŠŠ„„„|||}}}yyy}}}yyy{{{~~~ÙÙÙÛÛÛ===###...[[[ñññÙÙÙzzz|||}}}€€€ÙÙÙÛÛÛIII222DDDDDDcccººº­­­‘‘‘|||yyy{{{}}}ÙÙÙÛÛÛEEE&&&^^^ŠŠŠ|||zzz~~~ÐÐÐààà’’’zzz}}}€€€ÙÙÙÛÛÛMMM222aaa‡‡‡{{{zzz}}}¾¾¾ËËË|||yyy|||ÙÙÙÖÖÖ···ËË˾¾¾ÓÓÓ222===>>>555œœœÝÝÝ„„„+++MMMÛÛÛÖÖÖÂÂÂØØØÍÍÍêêê§§§...333(((§§§õõõˆˆˆAAAÛÛÛÖÖÖ¶¶¶×××ŠŠŠSSSooo§§§™™™>>>555TTTZZZxxxªªª›››ØØØÖÖÖÅÅÅôôôyyy YYYñññÔÔÔ111&&&///wwwðððÆÆÆÖÖÖÙÙÙ………ŠŠŠlllOOOjjjªªªŸŸŸvvvyyyKKK)))uuuØØØ¶¶¶ÖÖÖÛÛÛ:::YYY}}}www|||×××ïïï```vvvéééÄÄÄÕÕÕÜÜÜXXX@@@fffƒƒƒ|||ƒƒƒ¶¶¶ÆÆÆfff666zzzÉÉɲ²²ØØØåååÜÜÜÛÛÛÚÚÚØØØÙÙÙÙÙÙÙÙÙÖÖÖÖÖÖÚÚÚÜÜÜÙÙÙÖÖÖØØØååå(0` æææèèèéééçççÝÝÝÙÙÙÚÚÚÛÛÛßßßÞÞÞâââäääãããáááåååìììÍÍÍtttŒŒŒˆˆˆŠŠŠ€€€kkknnnooo^^^SSSUUUTTTXXXmmmjjjlllrrrîîî“““àà༼¼www~~~„„„JJJ(((000///---777|||yyyÃÃÔ””ÖÖÖÔÔÔ×××ÕÕÕºººxxx‚‚‚………PPP666555===vvv{{{ÑÑÑÒÒÒ»»»OOO,,,444333<<<}}}ÓÓÓuuu–––ØØØÎÎν½½ƒƒƒ†††222111ÄÄÄŽŽŽÅÅÅÈÈÈÆÆÆ²²²MMM:::zzzqqqEEE???AAA@@@;;;ÁÁÁ¶¶¶¸¸¸···¤¤¤ëëëÏÏÏ...'''ÀÀÀ888***‰‰‰>>>)))+++"""ÜÜÜ999QQQ¥¥¥žžžŸŸŸ¢¢¢’’’‘‘‘sssÊÊÊÌÌÌ´´´µµµ¹¹¹¦¦¦±±±dddCCCBBBDDD———hhh&&&%%%¿¿¿ÇÇÇggg‡‡‡ÉÉÉÐÐÐVVVfffííí###RRRiii```eee°°°ËËË•••®®®GGGHHHppp«««³³³aaa˜˜˜[[[       ! "#$ %&'())*+,-./.012)))*)))('3)))* "456789 :;<)=>0?@@@A*(()B(<3C(()"456D7E F;<)=GHIJJJKL()B(<;C() "4$6M67 :;()+GHIIIJKL()N((;C() "4OPQDQ%R3S((TGHUVUVK*<((('<(((S32<((( "WXMYZ[Q\N*2L2(]HUVV/^;CCCC_`CCC_2B2CCC3 QabcccdcKeeeAU*fghi&j!_;;3;3;;;_!3;;3'klAm.../IJVJJ?no p_S(<<('<(<(S_2S(<<( klbUIIIJq@VIJ1rsD7E:;()N)(;_()) kltVIJJU1IVIJ?u E97F;<)B(<;C() kltVIJJU1@UII1rDME:3S(((B(;C() kltVJJJU?.vHH/wx pLC22_N<(<3C<((( klc?yqq1A>>>>z,'{|}}~s€‚‚‚NNBBN'`'NBBkltUIJIVA<=====ƒ3333;;QxPP‚_))(;_)))*kltVIJJVAL)))*BS(<<<)„877MP‚2(<3C(() kltVIJIVA*()B(*„P797‚2(<;C() kltVIJIVA*)N(*„8777PC((;C() kltVIJIVA<(<<(B<(((()…886€LS<(S_C<((( klAmVVVm^'3;;3'!*LLLLC4l……Ds3;;_!;*LL*2"YSR†g‡ˆ‰ŠR:Fˆ#‹ItKKebŒŽy)WˆF:pj^KKKA1 "4x%[Q P ‘@JJJ@V/UV@’sP &.VVVUv "4$DMMP“”8M7E•n@JJ@q@VIJ1r–D7EiUIIJ@m "4$M97p—P99M •n@JJI1IVIJ?u– E97hUJJJI0 "4$ E77“[9EE˜u1@@?yIVJJ?uT ˜EDgI@@@?.™ "45 988#M % kš›unnn/@/V.I‘oœ f-uuuvž "Y=#ihiR{S š••Ÿ yqqqyU¡‚s)‹••¡š%"4€8P%¢’--nr£k xRV@?@@?U‘uur’17   "45P68‡U???qr ˜MD†/UIJI@yI??1@—6EME8s"456D7D ‡/IJJ?n E9Mxg.VJJJ@q.JJJUd¤P797s"456M6M†/IJJ?-%E7Mg.UIJI@qVJIIUd¤8797s"4¥8DQ g/IJJ?n 986 h.VUUU@q.VVV.dQ8P8x"W‚6Z„ZM¦/JJJ@-=8—…„E¦m///m/q@II@Uc“„ZZZ…=Q§ŒaŽaŒ¨©ƒ!!!©`***)_ªg«†\F¬/y1qIhWfff4SklK0./.0^(+SSS>>³³³ÍÍÍ"""UUULLL¬¬¬   !"#$%&'()*+,-.$/..$0#$.- 123 4/%56789:;/.<%=<%%>,.<.  ?@"06.ABCDE:,-..,..$5>$.$ FGHIJKLMNO>,#,,#J>,#  8+)::+9(. P14#000>>0/J5>0  *+)QR)Q(ST "<.../%.$0#$%$  *+RQ:+9U6  V<$.$/%%.>,.%.  *+R:8W*XSY Z[=/,/O%%%>,.<.  R\:]^__KJ`abcbdefgO//,=/  *+hi-gSg=,##/P jTf/$.0#.%$  k*:hi0<<5/...5Vje,..0,.<.  lER*m5.%%,$$$-.-  oQm\p>555O///Jqrsnt=<<#O,/, u[srqvwx8m\;m;ihyx"4+zR @ n{|?}:)Q)h+C? 18+8 1~|1 Vw3{ U\Qz+RQU {[)\) f 3 " TZ€(‚+h+C= T ]ƒUƒ„Z!b"…†‡>>555œœœÝÝÝ+++ÂÂÂÍÍÍêêê333(((õõõˆˆˆAAA¶¶¶×××SSSooo™™™TTTZZZªªª›››ÅÅÅôôô YYYÔÔÔ111///wwwðððÆÆÆ………lllOOOŸŸŸKKK)))uuu:::```éééÄÄÄÜÜÜXXX@@@fffƒƒƒ666²²²   !"  #$%&'() *+,,-./01  23" ) 456) +78)9:;  <:9=>+#?@ABC DEFG%HIJKLMNO"PQR?@STUVWXYZ([\2]^_`ab"cdUefghNiLZj_ Oklmnopqrs sNart)uoo(0`€€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷wwwwwwwˆˆˆˆwwww‡wwwwww÷÷www€www‡wwwwwww÷÷÷ÿxww‡€wwww‡wwwwwww÷÷÷÷÷www€xwwwwxwxwxw÷ÿwwww€wwxwwwwwwwww÷÷÷www€wwwwwwwwwww÷÷÷w‡ww€wwwwwwwwwww÷ÿÿ÷wwwpwwwwwwwwwwwwø€÷wwwwwwwwwwwø÷÷ÿwwwwwwwwwwwø‡w‡w‡wxw‡wwø÷wwwxwwwwwwwø÷÷wwwwwwwxww‡ø‡÷÷wwwwwwwwww‡ø÷wwww‡wwwxwwø€ˆˆˆww÷wwwwwwwwwwxwøwwwwwww÷ÿ÷wwwwwwwøww‡wwww÷÷wwwwwwwwøwwww‡ww÷÷w‡w‡wwwwøwwwwwww÷ÿ÷÷wwwwwwwøwwwwwwww÷wwwxwwwøw‡wwxwxÿ÷wwwwwwwø‡wwwwwwwÿww‡www‡wx÷ww÷p€€÷wp€÷÷÷÷÷ÿÿ€÷ÿ÷ð÷÷÷ÿ€€ÿÿð÷÷÷÷w÷€÷w÷ð÷÷÷÷w€€÷÷p÷÷÷÷ÿ€÷wð÷ÿÿÿ÷ÿÿ€ÿÿÿð÷wwwxˆˆˆˆˆˆˆ€ˆˆˆˆˆ‡ˆˆ÷ÿÿpÿÿ÷€ÿÿ÷wÿwø÷w‡÷÷ðÿ÷÷÷÷÷÷÷÷pw÷ÿ÷ÿð÷ÿ÷÷÷÷ð÷÷w€÷ÿ÷÷ÿð€‡÷€w÷wøw÷wwww÷ÿÿø‡÷øwwwwwwwx÷ÿÿøwwwwxwx÷÷÷øwwøwwwwwwwwø÷÷øwwwwwww÷÷ÿø÷ÿøwwww‡ww÷øÿxwwwwwwwø÷÷÷ˆˆˆ‡ww‡wwwwwwwxˆˆˆ‡wwwÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ( @€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿwwÿw÷w÷wwÿxxˆˆˆˆˆˆˆˆˆˆˆ‡x÷÷ˆˆ€€ˆˆˆˆˆˆˆ‡w÷wˆˆˆˆˆˆˆˆˆˆxwÿˆˆ€€ˆˆˆˆˆˆˆ‡wwˆˆˆˆˆˆˆˆˆ‡xˆˆ€ˆˆxˆˆˆˆˆˆˆ‡x€‡ˆˆˆˆˆˆˆ‡ø€wˆˆˆˆˆˆˆp€€‡wˆˆˆˆˆˆˆ‡ð€÷wˆˆˆˆˆˆˆ‡xˆˆˆˆˆxxxˆˆˆˆ‡ð€ˆˆˆˆˆÿˆˆˆˆˆx€€ˆˆˆˆˆwwxˆˆˆˆ‡xˆˆˆˆˆˆw÷ˆˆˆˆˆ‡p€ˆˆˆˆˆwxˆˆˆˆ‡xwwwwxˆ€‡wø‡w÷w÷p€€€÷ø€‡w÷wwx€‡÷w‡w÷wpˆww‡wwwwwˆ€€‡wx€‡xww€€ˆww€€€ˆw÷€w÷ˆ÷wx÷ˆ‡÷w€wwwww€€‡ww€€÷÷xwwwwˆˆww‡xˆˆˆˆˆwp÷wwxˆˆˆˆˆˆwp€ÿx€ˆˆˆˆˆwpˆwwwp€ˆˆˆˆˆ÷pˆwwx€ˆˆˆˆ‡wˆww÷ÿwww÷wwwww÷wwww( €€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿw÷wwwxˆˆˆˆw÷ˆˆˆˆ‡xˆˆˆˆˆˆ‡ð€÷ˆˆˆxˆwˆˆˆ‡øˆˆxˆ‡p€ˆˆwˆˆ‡÷ww€€‡ww÷€€‡wøwˆ‡÷øw‡wxˆwˆ‡wpˆˆ€wxˆˆˆwˆ‡w÷w÷÷w÷ÿpuzzles-20170606.272beef/icons/unequal.ico0000644000175000017500000006117613115373751017166 0ustar simonsimon 00 ¨%–  ¨>& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÎÎÎÉÉÉÊÊÊÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÉÉÉÎÎÎÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÎÎÎÉÉÉÊÊÊÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÉÉÉÎÎÎÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÎÎΟŸŸ±±±¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯±±±ŸŸŸÎÎÎ×××ÕÕÕÕÕÕÕÕÕÕÕÕ×××ÎÎΟŸŸ±±±¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯±±±ŸŸŸÎÎÎ×××ÕÕÕÕÕÕÕÕÕÕÕÕØØØÉÉɱ±±áááÙÙÙÛÛÛÛÛÛÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÙÙÙááá±±±ÉÉÉØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÉÉɱ±±áááÙÙÙÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÚÚÚÚÚÚÚÚÚÛÛÛÛÛÛÙÙÙááá±±±ÉÉÉØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÊÊʯ¯¯ÙÙÙÒÒÒÔÔÔÔÔÔÖÔÖ×Õ××Õ××Õ××Õ××Õ×ÕÔÕÓÔÓÓÒÓÙÙÙ¯¯¯ÊÊÊØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÊÊʯ¯¯ÙÙÙÒÒÒÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÖÖÖ×××ÕÕÕÔÔÔÔÔÔÒÒÒÙÙÙ¯¯¯ÊÊÊØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÉÉɯ¯¯ÛÛÛÔÔÔÕÕÕÕÕÕÐÓÐÌÒÌËÑËÉÐÉËÑËÌÒÌÑÓÑÖÕÖÔÔÔÛÛÛ¯¯¯ÉÉÉØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÉÉɯ¯¯ÛÛÛÔÔÔÕÕÕÔÔÔÓÓÓÓÓÓÓÓÓÎÎÎÈÈÈÎÎÎÔÔÔÕÕÕÔÔÔÛÛÛ¯¯¯ÉÉÉØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÉÉɯ¯¯ÛÛÛÔÔÔÒÔÒáÚáY¢Yx ƒ „ ‚ wf¨fåÜåÐÒÐÛÛÛ¯¯¯ÉÉÉØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÉÉɯ¯¯ÛÛÛÔÔÔÔÔÔÙÙÙßßßÛÛÛëëëjjjnnnêêêÒÒÒÔÔÔÛÛÛ¯¯¯ÉÉÉØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÉÉɯ¯¯ÛÛÛÔÔÔÓÔÓܨ܆µ†KK$$y))KžKޏŽßÙßÑÓÑÛÛÛ¯¯¯ÉÉÉØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÉÉɯ¯¯ÛÛÛÓÓÓÙÙÙ¾¾¾ŸŸŸ¤¤¤±±±KKKLLL½½½ÓÓÓÔÔÔÛÛÛ¯¯¯ÉÉÉØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÉÉɯ¯¯ÛÛÛÔÔÔÕÕÕÔÕÔÙ×Ùíßí`¦`rn«nñáñ×Ö×ÔÕÔÔÔÔÛÛÛ¯¯¯ÉÉÉØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÉÉɯ¯¯ÛÛÛÐÐÐåååqqq---ÔÔÔÔÔÔÚÚÚ¯¯¯ÉÉÉØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÉÉɯ¯¯ÛÛÛÔÔÔÕÕÕÕÕÕÑÓÑÞÙÞZ¤Zsg©gâÚâÐÓÐÕÕÕÔÔÔÛÛÛ¯¯¯ÉÉÉØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÉÉɯ¯¯ÛÛÛÐÐÐåååttt^^^uuu...---ŠŠŠÔÔÔÔÔÔÚÚÚ¯¯¯ÉÉÉØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÉÉɯ¯¯ÛÛÛÔÔÔÕÕÕÕÕÕÒÔÒàÙà[¤[rh©häÛäÑÔÑÕÕÕÔÔÔÛÛÛ¯¯¯ÉÉÉØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÉÉɯ¯¯ÛÛÛÓÓÓÙÙÙÁÁÁ]]]ÿÿÿeeemmmòòòÒÒÒÔÔÔÛÛÛ¯¯¯ÉÉÉØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÉÉɯ¯¯ÛÛÛÔÔÔÕÕÕÕÕÕÔÕÔáÚáZ¤Zrh©håÛåÑÔÑÕÕÕÔÔÔÛÛÛ¯¯¯ÉÉÉØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÉÉɯ¯¯ÛÛÛÔÔÔÒÒÒãã㜜œkkkbbbàààÒÒÒÔÔÔÛÛÛ¯¯¯ÉÉÉØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÉÉɯ¯¯ÛÛÛÔÔÔÕÕÕÕÕÕÏÓÏåÜåa¦ari©iåÛåÑÔÑÕÕÕÔÔÔÛÛÛ¯¯¯ÉÉÉØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÉÉɯ¯¯ÛÛÛÔÔÔÕÕÕÓÓÓàààIIIMMMcccãããÒÒÒÔÔÔÛÛÛ¯¯¯ÉÉÉØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÉÉɯ¯¯ÛÛÛÓÔÓÓÔÓÝØÝR R''(Ž(uf¨fåÛåÑÔÑÕÕÕÔÔÔÛÛÛ¯¯¯ÉÉÉØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÉÉɯ¯¯ÛÛÛÔÔÔÕÕÕÔÔÔÙÙÙÆÆÆ```ãããÒÒÒÔÔÔÛÛÛ¯¯¯ÉÉÉØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÉÉɯ¯¯ÛÛÛÔÔÔÔÔÔÛØÛ²‹ „ ~kªkäÛäÒÔÒÕÕÕÔÔÔÛÛÛ¯¯¯ÉÉÉØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÉÉɯ¯¯ÛÛÛÔÔÔÕÕÕÕÕÕÒÒÒááá––– gggãããÒÒÒÔÔÔÛÛÛ¯¯¯ÉÉÉØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÊÊʯ¯¯ÙÙÙÒÒÒÔÔÔÓÔÓÛÖÛÖÕÖÊÐÊÇÏÇÎÑÎÕÔÕÔÔÔÔÔÔÒÒÒÙÙÙ¯¯¯ÊÊÊØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÊÊʯ¯¯ÙÙÙÒÒÒÔÔÔÔÔÔÔÔÔÓÓÓ×××ËËËÇÇÇÎÎÎÔÔÔÔÔÔÒÒÒÙÙÙ¯¯¯ÊÊÊØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÉÉɱ±±áááÙÙÙÛÛÛÛÛÛÙÚÙÛÛÛÞÜÞÞÜÞÜÛÜÚÛÚÛÛÛÛÛÛÙÙÙááá±±±ÉÉÉØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÉÉɱ±±áááÙÙÙÛÛÛÛÛÛÛÛÛÛÛÛÚÚÚÝÝÝÞÞÞÜÜÜÚÚÚÛÛÛÙÙÙááá±±±ÉÉÉØØØÕÕÕÕÕÕÕÕÕÕÕÕ×××ÎÎΟŸŸ±±±¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®¯®®¯®¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯±±±ŸŸŸÎÎÎ×××ÕÕÕÕÕÕÕÕÕÕÕÕ×××ÎÎΟŸŸ±±±¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®®®®¯¯¯¯¯¯¯¯¯¯¯¯±±±ŸŸŸÎÎÎ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÎÎÎÉÉÉÊÊÊÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÉÉÉÎÎÎÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÎÎÎÉÉÉÊÊÊÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÉÉÉÎÎÎÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÎÎÎÉÉÉÊÊÊÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÉÉÉÎÎÎÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÎÎÎÉÉÉÊÊÊÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÉÉÉÎÎÎÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÎÎΟŸŸ±±±¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯±±±ŸŸŸÎÎÎ×××ÕÕÕÕÕÕÕÕÕÕÕÕ×××ÎÎΟŸŸ±±±¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯±±±ŸŸŸÎÎÎ×××ÕÕÕÕÕÕÕÕÕÕÕÕØØØÉÉɱ±±áááÙÙÙÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÙÙÙááá±±±ÉÉÉÖÖÖÑÑÑÔÔÔÕÕÕÕÕÕØØØÉÉɱ±±áááÙÙÙÛÛÛÛÛÛÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÛÛÛÙÙÙááá±±±ÉÉÉØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÊÊʯ¯¯ÙÙÙÒÒÒÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÒÒÒÙÙÙ¯¯¯ÈÈÈàààééé×××ÓÓÓÕÕÕØØØÊÊʯ¯¯ÙÙÙÒÒÒÔÔÔÔÔÔÖÔÖ×Õ××Õ××Õ××Õ××Õ×ÕÔÕÓÔÓÓÒÓÙÙÙ¯¯¯ÊÊÊØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÉÉɯ¯¯ÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÛÛÛ­­­ÒÒÒ§§§___ÊÊÊÜÜÜÒÒÒØØØÉÉɯ¯¯ÛÛÛÔÔÔÕÕÕÕÕÕÐÓÐÌÒÌËÑËÉÐÉËÑËÌÒÌÑÓÑÖÕÖÔÔÔÛÛÛ¯¯¯ÉÉÉØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÉÉɯ¯¯ÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÛÛÛ®®®ÎÎÎÂÂÂ%%%ÎÎÎÚÚÚÕÕÕÊÊʯ¯¯ÛÛÛÔÔÔÒÔÒáÚáY¢Yx ƒ „ ‚ wf¨fåÜåÐÒÐÛÛÛ¯¯¯ÉÉÉØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÉÉɯ¯¯ÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÛÛÛ¯¯¯ÇÇÇàààÑÑÑ%%%$$$ÍÍÍÞÞÞÈÈȯ¯¯ÛÛÛÔÔÔÓÔÓܨ܆µ†KK$$y))KžKޏŽßÙßÑÓÑÛÛÛ¯¯¯ÉÉÉØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÉÉɯ¯¯ÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÛÛÛ¯¯¯ÊÊÊÕÕÕÚÚÚÏÏÏ$$$&&&ÏÏÏÍÍÍ®®®ÛÛÛÔÔÔÕÕÕÔÕÔÙ×Ùíßí`¦`rn«nñáñ×Ö×ÔÕÔÔÔÔÛÛÛ¯¯¯ÉÉÉØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÉÉɯ¯¯ÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÛÛÛ¯¯¯ÉÉÉØØØÒÒÒÚÚÚÓÓÓ222ÌÌ̯¯¯ÚÚÚÔÔÔÕÕÕÕÕÕÑÓÑÞÙÞZ¤Zsg©gâÚâÐÓÐÕÕÕÔÔÔÛÛÛ¯¯¯ÉÉÉØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÉÉɯ¯¯ÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÛÛÛ¯¯¯ÊÊÊØØØÒÒÒãã㇇‡ÏÏÏ®®®ÚÚÚÔÔÔÕÕÕÕÕÕÒÔÒàÙà[¤[rh©häÛäÑÔÑÕÕÕÔÔÔÛÛÛ¯¯¯ÉÉÉØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÉÉɯ¯¯ÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÛÛÛ¯¯¯ÉÉÉÖÖÖää䆆†€€€èèèÉÉɯ¯¯ÛÛÛÔÔÔÕÕÕÕÕÕÔÕÔáÚáZ¤Zrh©håÛåÑÔÑÕÕÕÔÔÔÛÛÛ¯¯¯ÉÉÉØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÉÉɯ¯¯ÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÛÛÛ¯¯¯ÈÈÈâââ‚‚‚ƒƒƒäääÕÕÕÉÉɯ¯¯ÛÛÛÔÔÔÕÕÕÕÕÕÏÓÏåÜåa¦ari©iåÛåÑÔÑÕÕÕÔÔÔÛÛÛ¯¯¯ÉÉÉØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÉÉɯ¯¯ÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÛÛÛ­­­ÔÔÔ   ‚‚‚äääÒÒÒØØØÊÊʯ¯¯ÛÛÛÓÔÓÓÔÓÝØÝR R''(Ž(uf¨fåÛåÑÔÑÕÕÕÔÔÔÛÛÛ¯¯¯ÉÉÉØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÉÉɯ¯¯ÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÛÛÛ¯¯¯ËËËÌÌÌÉÉÉÝÝÝÔÔÔÔÔÔØØØÉÉɯ¯¯ÛÛÛÔÔÔÔÔÔÛØÛ²‹ „ ~kªkäÛäÒÔÒÕÕÕÔÔÔÛÛÛ¯¯¯ÉÉÉØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÊÊʯ¯¯ÙÙÙÒÒÒÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÒÒÒÙÙÙ¯¯¯ÉÉÉÛÛÛØØØÓÓÓÕÕÕÕÕÕØØØÊÊʯ¯¯ÙÙÙÒÒÒÔÔÔÓÔÓÛÖÛÖÕÖÊÐÊÇÏÇÎÑÎÕÔÕÔÔÔÔÔÔÒÒÒÙÙÙ¯¯¯ÊÊÊØØØÕÕÕÕÕÕÕÕÕÕÕÕØØØÉÉɱ±±áááÙÙÙÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÙÙÙááá±±±ÉÉÉØØØÔÔÔÕÕÕÕÕÕÕÕÕØØØÉÉɱ±±áááÙÙÙÛÛÛÛÛÛÙÚÙÛÛÛÞÜÞÞÜÞÜÛÜÚÛÚÛÛÛÛÛÛÙÙÙááá±±±ÉÉÉØØØÕÕÕÕÕÕÕÕÕÕÕÕ×××ÎÎΟŸŸ±±±¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯±±±ŸŸŸÎÎÎ×××ÕÕÕÕÕÕÕÕÕÕÕÕ×××ÎÎΟŸŸ±±±¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®¯®®¯®¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯±±±ŸŸŸÎÎÎ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÎÎÎÉÉÉÊÊÊÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÉÉÉÎÎÎÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÎÎÎÉÉÉÊÊÊÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÉÉÉÎÎÎÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ( @ ÕÕÕÕÕÕ××××××××××××××××××××××××××××××ÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ××××××××××××××××××××××××××××××ÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÏÏÏÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÑÑÑÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÏÏÏÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÑÑÑÖÖÖÕÕÕÙÙÙÄÄݰ°»¼»¹¹¹¹¹¹¸¹¸¸¹¸¸¹¸¸¹¸¹¹¹»»»®®®ÍÍÍ×××ÕÕÕÔÔÔÙÙÙ¾¾¾²²²»»»¹¹¹¹¹¹¹¹¹¹¹¹¸¸¸¹¹¹¹¹¹ººº¯¯¯ÑÑÑÖÖÖÚÚÚÀÀÀÈÈÈÝÝÝØØØÜÚÜàÜàÞÛÞßÛßÞÛÞØØØÝÝݾ¾¾ÉÉÉØØØÕÕÕÔÔÔÙÙÙ»»»ÎÎÎÛÛÛØØØØØØØØØÛÛÛßßßÙÙÙØØØÝÝݺººÎÎÎ×××ÚÚÚÁÁÁÅÅÅר×ÕÔÕÉÏɸɸ½Ë½ºÊº¾Ë¾ÓÓÓØØØ¼¼¼ÊÊÊØØØÕÕÕÔÔÔÙÙÙ¼¼¼ÊÊÊ×××ÔÔÔÔÔÔÖÖÖÉÉÉ»»»ÒÒÒÔÔÔØØØ¹¹¹ÎÎÎ×××ÚÚÚÁÁÁÅÅÅÖ×ÖâÚâ}²}~‚-‘-ÕÔÕÙÙÙ¼½¼ÊÊÊØØØÕÕÕÔÔÔÙÙÙ¼¼¼ÊÊÊ×××ÕÕÕÔÔÔééézzzÆÆÆÚÚÚ×××¹¹¹ÎÎÎ×××ÚÚÚÁÁÁÅÅÅØØØÕÕÕÎÒΪĪ}a¦aÍÒÍÑÓÑÙÙÙ½½½ÊÊÊØØØÕÕÕÔÔÔÙÙÙ¼¼¼ÉÉÉßßß³³³***###222ÍÍÍÛÛÛ¹¹¹ÎÎÎ×××ÚÚÚÁÁÁÅÅÅÙÙÙÓÔÓÜØÜÉÐÉ}t®tëÞëÐÓÐÙÙÙ½½½ÊÊÊØØØÕÕÕÔÔÔÙÙÙ¼¼¼ÉÉÉààà±±±yyyHHHzzzÓÓÓÙÙÙ¹¹¹ÎÎÎ×××ÚÚÚÁÁÁÅÅÅÙÙÙÓÔÓÝØÝÆÏÆ}o¬oäÛäÑÓÑÙÙÙ½½½ÊÊÊØØØÕÕÕÔÔÔÙÙÙ¼¼¼ÊÊÊÕÕÕâââRRRooo‘‘‘ÏÏÏÛÛÛ×××¹¹¹ÎÎÎ×××ÚÚÚÁÁÁÅÅÅØØØÖÕÖÈÐȵȵq­qåÜåÑÓÑÙÙÙ½½½ÊÊÊØØØÕÕÕÔÔÔÙÙÙ¼¼¼ÊÊÊ×××ØØØÍÍÍ,,,222½½½ÙÙÙ×××¹¹¹ÎÎÎ×××ÚÚÚÁÁÁÅÅÅÕ×ÕáÙáy°y ƒ vr«räÛäÐÒÐÙÙÙ½½½ÊÊÊØØØÕÕÕÔÔÔÙÙÙ¼¼¼ÊÊÊ×××ÑÑÑààࣣ£¾¾¾ÙÙÙ×××¹¹¹ÎÎÎ×××ÚÚÚÁÁÁÈÈÈÛÛÛØ×ØÐÕЫƫ›¿›¿Î¿ÜÙÜÖÖÖÜÜÜ¿¿¿ÉÉÉØØØÕÕÕÔÔÔÙÙÙ½½½ÍÍÍÚÚÚ×××ÖÖÖÝÝÝ®®®   ÒÒÒØØØÛÛÛ»»»ÎÎÎ×××ÚÚÚ¿¿¿»»»ÎÎÎÊÊÊÌËÌÔÎÔ×Ð×ÐÍÐÊÊÊÊÊÊÎÎδ´´ÊÊÊØØØÕÕÕÔÔÔÚÚÚºººÀÀÀÍÍÍÊÊÊËËËÉÉÉÔÔÔÖÖÖÌÌÌÉÉÉÎÎβ²²ÏÏÏ××××××ÎÎκºº¼¼¼¼¼¼¼¼¼º»º¹»¹»¼»¼¼¼¼¼¼¼¼¼¼¼¼ÓÓÓÖÖÖÕÕÕÕÕÕ×××ËË˺ºº½½½¼¼¼¼¼¼¼¼¼ººº¹¹¹¼¼¼¼¼¼»»»¾¾¾ÕÕÕÕÕÕÕÕÕÖÖÖÚÚÚÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÚÚÚÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØ×××ÕÕÕÕÕÕÕÕÕÔÔÔÊÊÊÉÉÉÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÉÉÉÌÌÌÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÉÉÉÍÍÍÕÕÕÕÕÕÙÙÙ±±±¿¿¿¼¼¼½½½½½½½½½½½½½½½¼¼¼¿¿¿®®®ÌÌÌÔÔÔÓÓÓÔÔÔÙÙÙ¼¼¼´´´¿¿¿½½½¼¼¼º¼º»¼»º¼º»¼»¼¼¼¾¾¾®®®ÑÑÑÖÖÖÚÚÚÀÀÀÉÉÉÝÝÝÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙØØØÞÞÞ¿¿¿ÈÈÈæææÝÝÝÑÑÑÚÚÚ¼¼¼ÎÎÎÜÜÜØÙØàÜàåÞåãÝãåÞåâÝâØØØÞÞÞ»»»ÎÎÎ×××ÚÚÚÁÁÁÅÅÅØØØÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÓÓÓØØØ¼¼¼ÍÍÍqqq¨¨¨ãããÕÕÕ¼¼¼ÊÊÊÖÖÖ×Õ׸ɸ ¿ ªÃª¡À¡¯Å¯ÖÔÖ×××¹¹¹ÎÎÎ×××ÚÚÚÁÁÁÅÅÅÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙ»»»ÑÑÑ™™™ªªªèè躺ºÊÊÊÕÖÕáÚái©i~~F›FÝØÝר׹¹¹ÎÎÎ×××ÚÚÚÁÁÁÅÅÅÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙ½½½ÇÇÇëëë   ###¯¯¯ÂÂÂÉÉÉר×ÓÔÓØÖØ©Ä©z‡¶‡ÜØÜÒÓÒÙÙÙ¹¹¹ÎÎÎ×××ÚÚÚÁÁÁÅÅÅÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙ½½½ÊÊÊÐÐÐôôôddd444ÅÅÅÉÉÉ×××ÓÔÓÝØÝ²Ç²y޹ŽåÛåÑÓÑÙÙÙ¹¹¹ÎÎÎ×××ÚÚÚÁÁÁÅÅÅÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙ½½½ÇÇÇíí튊Š%%%ÂÂÂÀÀÀÉÉÉØØØÒÔÒäÛä¶É¶yŒ¸ŒâÚâÑÓÑÙÙÙ¹¹¹ÎÎÎ×××ÚÚÚÁÁÁÅÅÅÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙ»»»ÒÒÒ………½½½ää人ºËËË×××ÖÕֺʺ”»”zŒ¸ŒãÛãÑÓÑÙÙÙ¹¹¹ÎÎÎ×××ÚÚÚÁÁÁÅÅÅØØØÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÓÓÓÙÙÙ¼¼¼ËË˃ƒƒºººàààÖÖÖ¼¼¼ÊÊÊÕÖÕߨßg¨gyŒ·ŒâÚâÑÒÑØØØ¹¹¹ÎÎÎ×××ÚÚÚÁÁÁÉÉÉÜÜÜØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙØØØÝÝÝ¿¿¿ÉÉÉçççÚÚÚÒÒÒÚÚÚ¼¼¼ÎÎÎÛÛÛÙØÙ×Ø×¿Î¿µÊµÎÔÎÛÙÛר×ÝÝݼ¼¼ÎÎÎ×××ÚÚÚÀÀÀ···ÉÉÉÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÉÉɱ±±ÊÊÊÕÕÕÓÓÓÔÔÔÚÚÚººº»»»ÈÈÈÅÅÅÆÆÆÌÈÌÎÉÎÈÆÈÅÅÅÅÅÅÈÈȰ°°ÏÏÏ×××ÖÖÖÐÐÐÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÀÀÀÂÂÂÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÎÎο¿¿ÁÁÁÁÁÁÀÀÀ¿À¿¿À¿ÀÀÀÁÁÁÁÁÁÀÀÀÄÄÄÕÕÕÕÕÕÕÕÕÖÖÖÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÙÙÙÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÙÙÙÕÕÕÕÕÕ(  ÔÔÔÏÏÏÎÎÎËÍËÌÍÌÎÎÎÒÒÒÕÕÕÕÕÕÑÑÑÎÎÎÎÎÎÌÌÌÍÍÍÐÐÐÕÕÕÌËÌÃÃÃÍÌÍØÏØÖÏÖÈÈÈÄÄÄ×××ÔÔÔÂÂÂÊÊÊÌÌÌÕÕÕÎÎÎÂÂÂÐÐÐÉÊÉÓÐÓÂÐÂb¨bx±xÔÕÔÇÇÇÖÖÖÓÓÓÇÇÇØØØÐÐЂ‚‚ÄÄÄÏÏÏÍÍÍÊÊÊËÌËßÚßPœP~°~ÞØÞÄÅÄÖÖÖÒÒÒÌÌÌ»»»DDDÕÕÕÌÌÌÊËÊËÌËßÚßSžSš¼šâÚâÄÅÄÖÖÖÓÓÓÆÆÆ×××ttt+++ÀÀÀÏÏÏÍÍÍÉÉÉÒÏÒÂÏÂU¢U´È´ÜØÜÄÅÄÖÖÖÓÓÓÄÄÄÞÞÞÄÄÄXXXÌÌÌÍÍÍÍÍÍÎÎÎÂÂÂÊÈÊÔÌÔÊÈÊÄÄÄÆÆÆ×××ÕÕÕÄÄÄÅÅÅÉÉÉÕÕÕÈÈÈÂÂÂÑÑÑÕÕÕÔÔÔÓÓÓÑÒÑÓÓÓÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÓÓÓÐÐÐÓÓÓÔÔÔÕÕÕÖÖÖ×××ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÓÓÓÕÕÕ×××ÖÖÖÕÖÕÕÖÕÖÖÖ×××ÕÕÕÏÏÏÄÄÄÇÇÇÆÆÆÇÇÇÅÅÅÉÉÉÞÞÞÔÔÔÆÆÆÅÆÅÍÉÍÏÊÏÊÈÊÄÄÄÒÒÒÊÊÊËËËÖÖÖÔÔÔÔÔÔÓÓÓÁÁÁ°°°ÚÚÚÅÅÅÕÕնȶ­Ä­ÆÏÆËÉËÍÎÍËËËÍÍÍ×××ÕÕÕÕÕÕÓÓÓÌÌÌËËËÝÙÝu®u Œ ºÌºÏÌÏÍÎÍËËËÌÌÌ×××ÔÔÔÕÕÕÒÒÒÍÍÍ»»»bbbÆÇÆßÙ߼ʼSŸSèÞèÆÈÆÏÎÏËËËÎÎÎÙÙÙ××××××ÖÖÖÆÆÆ………ÈÈÈËÌËßÚßj«jIIåÞåÉÊÉÎÎÎÊÊÊÆÆÆÎÎÎÌÌÌÍÍÍËËËÂÂÂÜÜÜ×××ÁÁÁÏÎ϶ö»Å»ÐÏÐÃÃÃÏÏÏÓÓÓÊÊÊËËËËËËËËËÊÊÊÐÐÐÕÕÕÕÕÕÎÎÎÊÊÊÑÍÑÏÌÏÊÊÊÌËÌÔÔÔ(0` ÕÕÕØØØÖÖÖÎÎÎÉÉÉŸŸŸ±±±¯¯¯Ù×ÙáááÜÛÜÝÝÝÐÐÐÎÑÎËÑËáÚáY¢Yy ƒ „ ug©gåÜåëëëjjjnnnéééÒÔÒܨ܆µ†KžK''))ޏ޾¾¾¤¤¤LLLíßí[¤[rn«nñáñåååqqq...Z¤Zuuu___ŠŠŠkªkÁÁÁ ]]]ÿÿÿgggòòò```a¦aIIIR R(Ž(f¨fäÛäÇÇÇ‹~–––ÊÊÊÇÏÇ   §§§&&&ÚÛÚ222†††‚‚‚ÏÓÏ                      !"  #$%%#  &'()*  +,--. /( +010..2/(3  456789  /(+:;  <(3  =>%8  ? @AB C>; DE3 F5 GH C          I III                 J;    4KL  C LL   @" GM LL*'()*   NO /3  +PQ/(3B  +PR /(AB   PP+SB<(3 IR+   ? @B M   DE3    GH              IGGGGGGGG ( @ÕÕÕÛÛÛרר֨ÑÑÑÌÌÌÎÒÎÐÍÐÄÄݰ°¿¿¿»»»¸¹¸®®®³³³···¸¸¸¿À¿ÉÉÉÜÜÜßØßº¼ºÀÀÀÅÅÅÕÔÕÉÏɺʺ½Ë½¿Î¿ÒÔÒãÛã}²}‚-‘-èèèzzz©Ä©ya¦a***%%%222t®tëÞëHHHÜØÜÆÏÆo¬oåÛåãããRRRooo‘‘‘ÉÐɵȵq­qåÜå,,,y°y ƒ r«r£££›¿›™™™ÔÎÔ¼¼¼æææâÝâqqq¨¨¨¡À¡ªÃª¯Å¯i©iF›Fííí###Œ¸Œôôôddd²Ç²ŠŠŠµÊµƒƒƒ”»”g¨gŒ·ŒÎÔÎÈÆÈÌÈÌÈÈÈ            ! " #$% &'(  )*+%, -. /$0%$ 12 34  5678% 9: ;<  =,/  >?'@4  5A%/ &B  C  D  E        F <<>.<28.?@A:BCDE<FGHIJB )KBLMNOPJB &QRSTUVWXBY.Z ![\]. B^CX_`a BBB bP (0`€€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿwwwwwwwwwwwwwwwwwwwwwwwwx‡‡xxxˆ‡x‡wwwwˆx‡x‡xxxˆw‡wwwwwwwwwwwwwwwwwwwwww‡wwwwwwwww‡wwww‡wwwwwwwww‡wwwwwwwwwwwwwwwwwwwww‡‡wwxˆwwww‡wwww‡wwwwx‡wwwwwwr"""ww‡wwwwwwwww€‡ww‡‡wwxŠ"ˆww‡wwww‡ww‡ˆ‡ww‡wwwwx(www‡wwwwwwøwwww‡wwr(wwwwwwww‡wxww‡‡wwwr*www‡wwwwwwxw ‡ww‡‡wwwx(wwwwwwww‡ww€‡P‡wwwwwwwr(÷wwwwwww‡wwrP‡ww‡‡wwwx"www‡wwww‡www ‡www‡ww‚‚(wwwwwwww‡www€‡ww‡‡wwr"(www‡wwwwwwwwp‡ww‡‡wwww‡www‡wwwwwwwww‡www‡wwwwwwwww‡wwww‡wwwwwwwww‡wwwwwwwwwwwww‡wwwwwwwwwxxx‡ˆxx‡x‡wwwwxxˆxx‡‡ˆ‡‡wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww÷wwwwwwwwwwwxwwwwwwwwww‡wwwwwwwxˆx‡‡‡wxˆ‡wwwwˆw‡xxxˆ‡ˆw‡÷wwwwwww‡wwww‡wwwwwwww‡‡wwwwwwwwwwwwwwwwwwwwwww‡wwwwwwwwwwwww‡wwwwwww‡wwwwwwwww‡pwwwwwˆˆŠ‡www‡wwwwwwww‡www‡wwr""(ww‡‡wwwwwwwwwwxw‡wwx‚(ˆwwwwwwwwwwwwwww÷wwwwr'÷www‡wwwwwwww‡wwp‡wwwr(www‡‡wwwwwwwwwww€‡wwwr¨wwwwwwwwwwwww‡wxwwwwr(www‡‡wwwwwwwww€w‡wwwr¨www‡‡wwwwwwwwwwwwwwwwr(wwwwwwwwwwwww‡pww‡ww‚"(wwww‡wwwwwwww‡wwww‡ww‚"'www‡‡wwwwwwww‡wwwwwwwwwwwwwwwwwwwwwww‡wwww‡wwwwwww‡‡wwwwwwww‡wwww‡wwwwwwwwwx‡ˆx‡ˆ‡ˆxwwwwwxxˆxxˆx‡ˆw( @€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿw÷ww÷w÷wwww÷wwwwwwwwwwwwwwwwÿw÷w÷ww÷w÷wwwwwwwww÷w÷w÷wwr"(÷www÷ÿðwwww÷‚‡÷w÷… ww÷"wwwwP÷www‚ww÷w‚ðww÷‚ÿwwwwð‚wwwx"ww÷ww÷÷Wwwz"w÷ww÷€÷wwwÿww÷÷ww÷wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwÿwÿ÷÷÷w÷w÷w÷ww÷ww÷www÷÷ww÷w÷w÷wÿwwwwww÷ww÷w÷w÷w÷w÷÷÷w÷wwwwwwwwwwwwwwwwwww÷÷÷w÷wwwwwwwwwwwwÿw÷ww÷w÷w…÷wr‚(ww÷wr/w÷x"‡www÷÷÷÷÷ww€ww‚÷÷wwwwww…w‚wwwww÷wwxw÷÷¢www÷ÿwwÿ€ÿwx‚÷wwwww÷ww‡wwwr"wwww÷÷wÿwÿ÷wwwwwwwwwwwwwwwwwwwww÷÷wwwwwww( €€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿwww÷÷wwwwwwww÷xw÷w÷wxwwx(wwxwwxwzw÷‡÷ww÷w÷wwwwwww÷w÷ww÷wwwwww÷÷w÷wwwww÷x‡ø'÷÷w÷‡÷¯wwwx÷x‡w÷wwwwwwwwwwpuzzles-20170606.272beef/icons/undead.ico0000644000175000017500000006117613115373750016753 0ustar simonsimon 00 ¨%–  ¨>& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $æææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææåååæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææèèèææææææææææææææææææææææææææææææææææææææææææçççææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææÝÝÝææææææææææææææææææææææææææææææææææææææææææáááææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææ‚‚‚ãããçççåååææææææåååææææææåååææææææåååæææèèè³³³äääææææææææææææåååääääääåååæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææ}}}ãããæææêêêççæåååííìååäææåííìååäææåëëëåååèèè°°°äääçççææææåæäåäêëêðîððîðêëêäåäæåæææææææææææææææææææææææææææææææææææææåååäääääääääæææææææææææææææ~~~ââãêêéÒÒÔääçëëíÇÇÌííîèèëÆÆËììîèèëÎÎÑçççççè±±±äääçççåååçèçïêïÔÎÔ¹¾¹·¾·ÔÏÔïêïçèçåååææææææææææææææææææææææææææææææåååêêêñññïïïñññèèèææææææææææææ}}}ááàððô¢¢Œ¤¤Œµµ©§§Tµµ®³³žªªT´´­¯¯———vééïççæ°°°äääæææçéçæá攬”d¾d]Ò]eÑee¹e”¬”çáççéçåååææææææææææææææææææææææææåååéééÔÔÔ´´´¾¾¾¶¶¶ßßßèèèæææææææææ}}}ââàëëòººšÅÅXÈÈeõõvÁÁaÎÎeööwÃÃcÎÎ]¸¸„ääíèèæ°°°äääåçåíç퉨‰]Ö]rÇrªnØnvñv^Ò^‰©‰íçíåæåææææææææææææææææææææææææãããòòò§§§111ÍÍÍìììåååææææææ}}}ââàííò±±˜ââiïïzããtììvêêväätììyëën¯¯ƒååíèèæ°°°âãâïîï¾À¾aÆapäp^•^}£}SžSW­Wsäs`Æ`¾À¾îîîäåäææææææææææææææææææææææææäääóó󺺺 èèèèèèåååæææææææææ}}}ââàììò³³˜ÞÞgççpææmééuççtããkèèrèèm°°ƒååíèèæ°°°áãáñëñ•²•gÞgwéwwõwnínvívxðxvévgÞg•²•ñëñäåäææææææææææææææææææææææææäääòòò¶¶¶ âââèèèåååæææææææææ}}}ââàììò³³™ÜÜa»»€••yÏÏfáán¬¬†™™mààe²²…ååíèèæ°°°âãâðéð±kåkoÛoX¯XkÓkjÓjX°XoÚojåj±ðéðäåäææææææææææææææææææææææææåååìììµµµ"""âââèèèåååæææææææææ}}}áááîîñºº¯ÉÉV··xxŠ´´WØØi©©¯ookÌÌXµµ™êêðççå°°°âââòíò¡³¡fÛfqÝq>}>fÌffÍf>}>pÜpfÛf¡³¡ñíñäåäæææææææææææææææææææææäääððð´´´"""âââçççåååæææææææææ}}}âââëëéÖÖݱ±jÚÚgÇÇoæætççsÅÅiÞÞrºº`ÈÈËìììççç°°°ãããëìëÕÐÕc²cqìquåuqßqqßquåuqìqc²cÕÐÕêëêåååææææææææææææææææææææææææçççâââ···¸¸¸ææææææææææææææææææ}}}ãããåååííîÀÀ¾µµaééiììqììríím¾¾\´´©ììïäääèèè°°°ääääåäïíï´º´^¶^kækrírrírjæj^¶^´º´ïíïäåäææææææææææææææææææææææææææææææçççððððððææææææææææææææææææ}}}ãããçççååäííîÊÊÍ««‰´´rµµp¬¬‚ÁÁÀëëïææåååæèèè°°°äääçççäåäïìïÇÆÇ†¬†q´qq´q†¬†ÇÆÇïìïäåäææææææææææææææææææææææææææææææææææææääääääææææææææææææææææææ}}}áááåååääåããâêêêççîÚÚâØØàååììììääãääääääæææ¯¯¯âââååååäåâãâëëëíæíáÙááÙáíæíëëëâãâåäåääääääåååææææææææææææææææææææææææææææææææææææææææææææææææåååëëëîîîííííííìììííëððîððïííììììíííííííííïïï¶¶¶ëëëîîîííííííìììëíëîðîîðîëíëìììíííííííííîîîèèèææææææææææææææææææææææææææææææææææææææææææææææææèèèqqq±±±¸¸¸¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶···¶¶¶¶¶¶¶¶¶¸¸¸ŒŒŒµµµ···¶¶¶¶¶¶···¶¶¶¶¶¶¶¶¶¶¶¶···¶¶¶¶¶¶···³³³ÖÖÖéééåååæææææææææææææææææææææææææææææææææææææææææææææyyyÓÓÓØØØ×××××××××ÖÖÖÕÕÕÕÕÕÖÖÖ××××××××××××ÙÙÙ¥¥¥ÕÕÕ××××××××××××××××××××××××××××××××××××ÖÖÖáááçççæææææææææææææææææææææææææææææææææææææææææææææååå~~~çççëëëêêêééééééïïïòòñòòñðððêêêéééêêêéééììì³³³èèèêêêêêêééééééêêêêêêêêêêêêêêêêêêêêêêêêêêêçççææææææææææææææææææææææææåååãããããããããæææææææææææææææ}}}ãããçççåååèèèêêéÍÍ̶¶¹´´·ÈÈÈææåêêêäääåååççç°°°äääçççäääíííèèèäääææææææææææææææææææææææææææææææææææææææææææææææææåååëëëõõõòòòôôôèèèææææææææææææ}}}ãããæææèèèááদ¬££µÁÁ×ÅÅܨ¨º¡¡©ØØ×ëëëäääèèè°°°âââóó󤤤@@@íííéééäääææææææææææææææææææææææææææææææææææææææææææåååëëëÍÍÍ   ­­­£££ÝÝÝèèèåååææææææ}}}ãããææçéé裣©ÂÂÛ‰¡¡²¯¯ÂvvÂÂÙ  ªááßçççççç°°°ãããæææçççLLL777ïïïéééäääæææææææææææææææææææææææææææææææææææææææãããñññ¬¬¬""";;;ÏÏÏëëëåååææææææ}}}âââîîîÄÄݰ쬿––¥··Ë¸¸Í­¡¡²··Í¶¶¸îîíæææ°°°äääåååèèè÷÷÷MMM777ïïïéééäääæææææææææææææææææææææææææææææææææææææææãããöööÁÁÁ###ïïïêêêåååæææææææææ}}}ááâîîí±±µÁÁØÍÍ䨨ñÖÖïÖÖîÙÙòÍÍäÈÈપ²èèçççç°°°äääçççåååæææöööNNN777ïïïéééäääææææææææææææææææææææææææææææææææææææäääòòò···àààçççåååæææææææææ}}}ááâîîí©©®ÉÉáÅÅÛaac££²··Ê]]^´´ÆÔÔí¢¢«ççåèèè°°°äääææææææåååæææöööMMM777ïïïéééäääææææææææææææææææææææææææææææææææææææççç«««!!!âââèèèåååæææææææææ}}}áááòòò§§§¨¨¼ÛÛóvv|³³ÄÅÅÚrrxÊÊß¾¾Õ””—ðððæææ°°°äääçççææææææåååæææ÷÷÷MMM777ïïïéééäääæææææææææææææææææææææææææææäääððð´´´###âââçççåååæææææææææ}}}âââéééààßSSWœœ¯ÞÞöÀÀÕ¸¸ÍÝÝõ²²ÇLLSÌÌËìììæææ°°°äääçççæææææææææåååæææöööMMM777ïïïëëëåååæææææææææææææææææææææææææææææææææÉÉÉÆÆÆææææææææææææææææææ}}}ãããäääïïð¿¿¾ ¢¢¡óóóãããèèè°°°äääçççææææææææææææåååæææöööNNN555ãããçççåååææææææææææææææææææææææææææææææííííííææææææææææææææææææ}}}ãããçççãããððñÛÛÛsss>>=;;:eedÌÌËôôôãããæææèèè°°°äääçççæææææææææææææææåååçççíííxxxÐÐÐëëëåååææææææææææææææææææææææææææææææåååäääææææææææææææææææææ}}}àààäääãããáááçççõõõïïïîîîõõõêêêàààããããããååå®®®áááäääããããããããããããããããããââââââóóóæææâââãããåååææææææææææææææææææææææææææææææææææææææææææææææææåååñññôôôóóóôôôóóóðððññññññðððòòòôôôôôôóóóööö»»»ñññôôôôôôôôôôôôôôôôôôôôôôôôóóóñññóóóôôôôôôëëëåååææææææææææææææææææææææææææææææææææææææææææåååêêêkkk………ŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹nnn‹‹‹ŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒ†††ÇÇÇìììåååææææææææææææææææææææææææææææææææææææææææææèèèÕÕÕÁÁÁÄÄÄÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÇÇÇÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄÁÁÁÚÚÚèèèåååæææææææææææææææææææææææææææææææææææææææææææææêêêïïïîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîïïïéééåååææææææææææææææææææææææææææææææææææææææææææææææææååååååååååååååååååãããáááââââââååååååååååååååååååååååååååååååååååååââââââååååååååååååååååååæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææåååñññöööùùùóóóåååææææææææææææææææææææææææææææææåååóóóôôôåååæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææåååéé鯯¯–––†††¤¤¤éééåååææææææææææææææææææææææææåååííí¨¨¨£££ëëëæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææãããôôôNNN OOOpppìììåååæææææææææææææææææææææãããôôôŒŒŒõõõãããæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææåååéééÞÞÞ>>>”””ÿÿÿãããææææææææææææææææææææææææãããõõõ666‘‘‘¢¢¢+++ñññäääææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææãããóóóßßß"""–––óóóãããæææææææææææææææææææææäääïïï<<<YYYaaa444èèèæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææèèèÈÈÈôôô|||777õõõäääæææææææææææææææææææææããã÷÷÷BBBuuu………777ôôôäääæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææãããòòò{{{+++!!!“““ñññäääæææææææææææææææææææææäääððð³³³!!!©©©ñññäääæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææçççÌÌÌØØØðððåååæææææææææææææææææææææææææææåååîîîÛÛÛØØØïïïåååæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææíííêêêäääæææææææææææææææææææææææææææææææææäääéééêêêäääææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææååååååæææææææææææææææææææææææææææææææææææææææååååååæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææ( @ ææææææææææææææææææææææææèèèææææææææææææææææææææææææææææææçççæææææææææææææææææææææææææææææææææææææææææææææææææææææææææçççßßßåååææææææææææææææææææææææææåååãããæææææææææååååååæææææææææææææææææææææææææææææææææææææææäääííí¢¢¡ÚÚÚêêêææåèèçææåèèçççæææåëëêÙÙÙÈÈÈëëëåååäæäéééìëìèéèäåäæææææææææææææææææææææäääâââäääæææäääííížžŸÛÛÛââãææëÝÝâææëÞÞäââçããèäääÚÚÚÇÇÇëëëåæåîéîÚ×ÚÌÏÌߨßîêîåæåæææææææææææææææåååíííöööñññæææäääííížžááäÇÇ»ªªŒ»»¹¹–ºº‚½½ªª‡ÎÎÄÞÞáÆÆÅëìëéãé£À£mÃmkÏktÈt´Ã´íéíåæåæææææææææäääïïïNNNyyyçççäääííížžßßãÎÎÀÌÌ\ììrÜÜiæænæænËË_ÒÒÊÞÞßÄÅÃôðô¯Â¯YÎYrªrn¬n`Ô`cÇcÅËÅíëíåååææææææåååèèèÕÕÕ:::¬¬¬ìììãããííížžààâÌÌÀÚÚjããpêêwããqèès××lÏÏÉÞÞßÅÇÅïæïÀnènrÞrnÚnrÞrjåj•À•ïèïäæäæææææææææãããùùù\\\ÌÌÌîîîãããííížžßßâÏÏÃÌÌd——µµ_ÌÌŒŒ€ÃÃ\ÔÔÏÝÝ߯ÇÅíäí~Ä~jÞjT¥TjÕjU¥Ukäk‘Á‘ïæïäæäææææææäääïï£"""ÏÏÏìììãããííížžžÝÝÜÝÝá¼¼nÀÀuÕÕoÛÛ{¼¼m¸¸rââèÚÚÙÄÆÄõïõ ¾ _Ö_jÒjqÞqiÓi`Ð`¸Æ¸îëîäåäææææææåååéééÓÓÓ½½½äääçççäääííퟟŸÙÙØííðÊÊÂÆÆkÜÜiÚÚeÅÅpÎÎÊííï×××ÆÆÆíííâÝ⋺‹hÖhiÜiiÑiœ¼œêåêåæåææææææææææææåååêêêïïïææææææäääííퟟŸÜÜÜêêéììîØØÞÈȹÈÈ»ÚÚáììíêêêÚÚÚÈÈÈìììéééëåëÆÌƵǵÍÏÍîéîèéèèçèçççææææææææææææåååäääææææææäääíííÓÓÓââãÞÞÝããâååèååèââáÞÞÝãããÒÒÒÁÁÁåååÞÞÞßàßæåæéåéåäåÞßÞßßßßßßâââææææææææææææææææææææææææäääîî˜¶¶¶ÆÆÆÂÂÂÁÁÁÁÁÀÁÁÀÁÁÁÂÂÂÅÅÅ···¨¨¨ÇÇÇÀÀÀÂÂÂÁÂÁÀÁÀÁÁÁÂÂÂÃÃÃÀÀÀÒÒÒéééåååææææææåååääääääæææäääííí   ÞÞÞíííêêêððïêêèëëéððïêêêíííÜÜÜËËËïïïóóóìììéééêêêêêêêêêêêêêêêèèèæææææææææåååíííòòòðððæææäääííퟟŸÙÙÙéééååäÄÄȺºÅººÅÇÇÉææåééé×××ÅÅÅððð±±±ßßßëëëãããåååååååååååååååææææææåååêêêÅÅů¯¯¸¸¸æææåååííퟟŸÚÚÚëë齽Ĕ”¥¥¥¸  ³——¨ÁÁÆììëØØØÅÅÅ÷÷÷’’’NNNíííéééäääææææææææææææææææææäääîî¦vvvêêêäääííížžžßßÞÕÕÕ°°ÃµµÊ¾¾Ò¼¼Ñ¶¶Ê°°ÁÛÛÚÜÜÜÆÆÆéééùùùNNNíííéééäääææææææææææææææææææãããüüü^^^ÒÒÒîîîãããíííááàÆÆÈÈÈપº°°Á««»°°ÁÅÅÛËËÌßßÞÆÆÆìììáááûûûNNNíííéééäääææææææææææææåååêêêÈÈÈ888ÈÈÈíííãããííížžžáááÉÉɦ¦¸µµÅ¹¹Ê³³Ä¹¹Ë¡¡²ÑÑÐÞÞÞÆÆÆëëëåååâââûûûNNNíííìììäääæææææææææäääïïï«««bbbÜÜÜéééäääííퟟŸÙÙÙññð~~__l``lccp[[h‰‰Šóóó×××ÇÇÇëëëåååæææâââûûûNNNàààèèèåååæææææææææåååïïïöööçççæææäääííퟟŸ×××èèèççç220553‹‹ŠêêêçççÖÖÖÅÅÅéééãããääääääààà÷÷÷”””···íííãããææææææææææææäääâââææææææäääììì¡¡¡åååóóóñññþþþÿÿÿÿÿÿþþþðððôôôãããÐÐÐöööïïïñññññññññîîîûûûõõõðððìììåååæææææææææææææææææææææäääïïï———ŸŸŸ¯¯¯«««¨¨¨©©©©©©©©©«««®®®¢¢¢–––¯¯¯««««««««««««¬¬¬©©©«««§§§ÆÆÆêêêåååæææææææææææææææææææææèèèÚÚÚÅÅÅÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÉÉÉÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÅÅÅÕÕÕèèèåååææææææææææææææææææææææææéééîîîíííîîîíííëëëìììíííííííííííííííîîîíííîîîìììëëëìììîîîíííîîîêêêåååæææææææææææææææææææææææææææåååååååååäääéééðððéééæææååååååååååååååååååäääíííñññëëëäääåååååååååææææææææææææææææææææææææææææææææææææäääððð²²²@@@fffÎÎÎëëëåååæææææææææäääððð©©©LLL¼¼¼îîîäääææææææææææææææææææææææææææææææææææææææææææåååéééÜÜÜDDDœœœïïïäääææææææææææææåååéééQQQlll___óóóãããæææææææææææææææææææææææææææææææææææææææææææææäääîîîéééFFFÑÑÑëëëåååææææææææææææåååMMMwwwXXXñññäääææææææææææææææææææææææææææææææææææææææææææäääíííÃÃÃfffHHHÐÐÐëëëåååæææææææææãããñññ333•••óóóãããæææææææææææææææææææææææææææææææææææææææææææææçççäääÄÄÄÜÜÜìììåååæææææææææææææææççççççÌÌÌëëëææææææææææææææææææææææææææææææææææææææææææææææææææææææçççïïïéééåååææææææææææææææææææææææææíííåååææææææææææææææææææ(  æææäääåååæææãããèèçèèçèèççççåäååæåçççéèéåæåææææææåååïïïíííßß߯ÆÅääçÝÝãÝÝãââåÔÕÔèæèâââÚÞÚëæëææææææêêê³³³ÊÊÊääãÂÂÇÍÍ£ÒÒ{ÓÓ{Ë̤×ÖÝÖÝՀ€kÅk´Õ´ìçìåæåòòò‹‹‹¼¼¼ééçÁÁÉÑÑ—ÎÎiÍÍhÊÌ”Þ׿®Ò¬\Î\aÎa{Ï{éâéåçåëëë©©©ÙÙÙââáÆÆÉ××ÅÆÆpÆÆrÓÓÄÜÚßÓÛÒvÎveÑe­Ò­íèíäæäåååëëëéééßß྾¾ããæÖÖÌ××ÎááåÌÍËáÞáÔ×ÔÊÔÊâÞâáááææææææëëëëëëàà๹¹ÜÜÛÙÙÚÚÚÛÚÚÙÅÅÅÖ×ÖáàáÚØÚÖÖÖÚÚÚççççççÊÊÊ×××áááÆÆÆááâ³³¿´´ÀÞÞßßßÞÆÆÆ¹¹¹õõõæææèèèæææòòò‡‡‡µµµééêÂÂÁÆÆÑ¶¶Ë¶¶ÌÄÄÏÕÕÔåå嘘˜µµµòòòäääæææîîî›››ÓÓÓããäÈÈÇÀÀÅzzˆ||ŠÁÁÆÙÙØåååñññ™™™¸¸¸íííåååæææäääèèèßßßÂÂÂææåœœ›ŸŸŸååäÒÒÒáááååååååÅÅÅæææææææææææææææååå¾¾¾ÁÁÁÐÐÑÏÏÐÁÁºººÀÀÀÀÀÀÁÁÁÅÅÅÊÊÊçççææææææææææææêêêèèèÝÝÝßßßèèèéééèèèêêêéééèèèçççæææææææææææææææãããððð“““¥¥¥ðððáááðð𬬬vvvèèèææææææææææææææææææåååîîî°°°˜˜˜ñññáááòòò¢¢¢eeeèèèæææææææææææææææææææææèèèÕÕÕÜÜÜèèèæææçççäääÝÝÝèèèåååæææ(0` æææèèæçéçíçíååìÛÛÛáÙá}£}´´´uu|ëë쬬­ððï||ŠÖÖÖÇÇÌÎÎÑììñÔÏÔº»ºñìñóóó}}}ááߣ£Œµµ«§§TªªT¯¯———v”¬”aÆa]Ó]eÑec²cØØ×ÀÀ¾µ»µººšÅÅXÆÆlööwÂÂbÌÌeÍÍ[ºº‚ªª²‰©‰rÇr••yoÚowów¤¤¤ +++ËËËààeîîzææsêêt­­„¾À¾sås^•^q´qSžSW­W··Ë¶¶¹"""´´šããlêêl±±„•²•gÝgnínxðxÜÜeµµq™™m±kæk\´\kÓkX¯Xºº¯ÉÉV´´WØØimml¡³¡qÞq>}>fÍfÙÙá±±jÞÞr¾¾\tìtµµa««‰ÃÃÄ«„rrrŒŒŒ¢¢ª¢¢³ÁÁÖÃÃÚ©©¼AAAËËâ„„„²²Å®MMM666<<<¯¯Â––¥¸¸ÍüüüÕÕîÛÛóÊÊßbbc[[\¾¾Õ””•SSWLLSîðî         !"#$%&'()*+)*,-./ 0123 / 45678 9:;:<;:<= >?@ABC?D EFG9<;<;H;IJ KL?3MN3?LK%FGOP1+H=QOJ.RS2TUUV2SR%F WX& YZ [XG \L]^__^]L\5F`aZ(;<(bc8 "d??]?d"EeI<?+@>A %<.<%B'C DED F G//H    B  ''  IB I)JC B ' K !   FLL' I )C FLMNOPF 6Q 'RSTTSI2U23' VWRWWX  26J(J JNSYSYO 2U!)Z  [\\\]U 26^  F_`(U'  6C  42222!  24 42 46I)))))))6)))))))))   J  J J J '4K4K   )aZ K)^Ca !b34a'^3! Z^ #`6   K( æææäääåååãããèèççççåäååæåéèéïïïíííßß߯ÆÅääçÝÝãââåÔÕÔèæèâââÚÞÚëæëêêê³³³ÊÊÊääãÂÂÇÍÍ£ÒÒ{ÓÓ{Ë̤×ÖÝÖÝՀ€kÅk´Õ´ìçìòòò‹‹‹¼¼¼ééçÁÁÉÑÑ—ÎÎiÍÍhÊÌ”Þ׿®Ò¬\Î\aÎa{Ï{éâéåçåëëë©©©ÙÙÙââáÆÆÉ××ÅÆÆpÆÆrÓÓÄÜÚßÓÛÒvÎveÑe­Ò­íèíäæäéééßß྾¾ããæÖÖÌ××ÎááåÌÍËáÞáÔ×ÔÊÔÊâÞâáááàà๹¹ÜÜÛÙÙÚÚÚÛÚÚÙÅÅÅÖ×ÖáàáÚØÚÖÖÖÚÚÚ×××ÆÆÆááâ³³¿´´ÀÞÞßßßÞõõõèè臇‡µµµééêÂÂÁÆÆÑ¶¶Ë¶¶ÌÄÄÏÕÕÔ˜˜˜îîî›››ÓÓÓããäÈÈÇÀÀÅzzˆ||ŠÁÁÆÙÙØñññ™™™¸¸¸ÂÂÂææåœœ›ŸŸŸååäÒÒÒÁÁÁÐÐÑÏÏÐÁÁºººÀÀÀÝÝÝððð“““¥¥¥¬¬¬vvv°°°¢¢¢eeeÕÕÕÜÜÜ  !"#$%&'()*+,-./0123456789:;<=>?@ABC4DEFGHIJKLMNOP44QRSTUVWXYZ[\]P^_`abc^Rde$fghijklmnog$pqrstuvwxyz{| e }~€‚PWFƒ„…†‡ˆˆƒWe‰ eDeDeŠ‹ŒŠPŠŽepozP$‘ee’“e‰e(0`€€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøÿÿÿÿÿÿÿwÿÿÿÿÿÿÿÿÿÿÿÿÿÿøÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿø÷ÿw÷wÿÿÿ÷wwÿÿÿÿÿÿÿÿÿøøxwwwwÿwÿÿxx‡‡ÿÿÿ÷w‡ÿÿøÿw÷ÿwwÿwÿøwwwxÿÿÿ÷ÿÿø÷w÷÷wÿ÷ÿøxˆˆwÿÿÿðÿÿÿ÷ø÷ÿÿ÷ÿwÿwwxwwÿÿÿpÿÿø÷ww÷‡øÿ÷ÿ‡‡wwwÿÿÿðÿÿøÿ÷÷xwxwÿÿwxwˆ‡ÿÿ÷pÿÿÿø÷ww÷wwÿwÿww‡xwÿÿ÷€ÿÿøÿ÷ÿÿwÿøwwwxÿÿÿÿÿÿÿøÿww÷wÿ÷ÿÿ‡xwÿÿÿÿÿÿÿÿøÿÿwxwÿÿ÷ÿÿ÷wxÿÿÿÿÿÿÿÿÿøÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿøÿÿÿÿÿÿÿwÿÿÿÿÿÿÿÿÿÿÿÿÿÿø÷÷÷÷w÷÷÷÷wÿÿÿÿÿÿøwwwwwwwwx÷wwwwww÷ÿÿÿÿÿÿøÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿøÿÿÿÿÿÿÿwÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿÿwxÿÿ÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿøÿ÷÷‡ÿ÷ÿpÿÿÿÿÿÿÿÿwÿÿøÿwxwÿwÿøÿÿÿÿÿÿ÷ÿÿø÷w‡w‡wÿwÿÿ€ÿÿÿÿÿÿÿpÿÿø÷wÿÿ÷÷ÿ÷ÿÿøÿÿÿÿÿÿðÿÿø÷ÿwwwÿwÿÿÿ€ÿÿÿÿÿÿðÿÿÿøÿøwˆx‡wÿ÷ÿÿÿøÿÿÿÿÿpÿÿ÷÷w÷wˆÿwÿÿÿÿ€ÿÿÿÿ÷ÿÿø÷ˆÿwøÿ÷ÿÿÿÿøÿÿÿÿÿÿÿÿøÿpÿ÷ÿÿÿÿÿ€ÿÿÿÿÿÿÿøÿÿ€ÿÿwÿÿÿÿÿøÿÿÿÿÿÿÿøÿÿÿÿÿÿÿwÿÿÿÿÿÿÿÿÿÿÿÿÿÿøÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿøÿ÷÷÷ÿwÿ÷ÿ÷ÿ÷÷ÿÿÿÿÿÿ÷ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€ÿÿÿÿÿÿ€ÿÿÿÿÿÿÿÿÿÿÿÿÿpÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿøˆÿÿÿÿÿÿÿÿÿÿÿÿÿÿpÿÿÿÿÿÿ÷ˆÿÿÿÿÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿ÷ÿÿÿÿÿÿÿÿÿÿÿÿÿpÿÿÿÿÿÿÿ€ÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿ( @€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ÷÷ÿ÷w÷÷ÿ÷÷ÿÿ÷÷÷ÿ÷ÿ÷÷ÿ÷÷wÿÿwÿw÷ÿ÷ÿw÷‡wçw÷÷÷¨w÷ÿ÷xÿww~~w÷ˆw¨÷÷w÷wŽççw÷÷§ªwÿÿ‡÷wçwçç÷w¨‡zwÿ÷xŽx‡w÷zŠŠø‡wwçèwˆzˆw÷ÿ÷w÷~w÷÷ÿzˆwÿÿ÷÷ww÷÷ÿ÷ÿw÷÷÷ÿ÷÷www÷÷÷÷÷÷ÿ÷wwwwwxwwwwwÿ÷÷w÷÷ÿ÷ÿÿÿÿÿ÷w÷wÿwwÿwwÿ÷÷÷÷wÿwww‡w÷÷÷÷ÿø÷÷wwxww÷÷pÿÿˆÿwwwwww÷ÿ‡÷w‡‡w÷ÿÿpÿ÷ø÷wxwxwwÿwÿÿÿwø`÷w÷ÿÿx÷ÿ÷w÷wwÿ÷w÷÷ÿ÷÷ÿ÷w÷ÿÿwÿ÷wÿÿwˆˆˆxxˆ‡ˆˆxˆÿ÷÷ÿ÷÷ÿÿw÷wÿ÷ÿ÷ÿÿwwÿÿÿÿ÷ÿÿÿw÷÷ÿÿw÷÷÷w÷÷€‡ÿ÷wˆÿ÷ÿÿx÷ÿwa÷÷÷÷÷xˆ÷ÿÿÿ÷ÿˆ‡÷ÿ÷÷÷÷ÿÿww÷ÿw÷ÿ( €€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿÿ÷÷w÷wwwø‡ÿøwîwz‡wwwçx§ÿ÷ww÷ÿw÷÷÷www÷wÿwwwøøwwˆw÷‡÷ÿw‡wÿ÷÷w÷wwwÿ÷÷ÿ÷÷‡ÿw÷ÿxø÷ÿ÷puzzles-20170606.272beef/icons/twiddle.ico0000644000175000017500000006117613115373747017155 0ustar simonsimon 00 ¨%–  ¨>& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÐÐÐÕÕÕÓÓÓÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÐÐÐÕÕÕÓÓÓÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÐÐÐÕÕÕÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙãããòòòôôôðððñññññññññññññññññññññññññññòòòòòòðððððððððóóóäääñññôôôðððñññññññññññññññññññññðððññññññðððññññññðððóóóåååîîîÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔ½½½×××áááßßßßßßßßßßßßßßßßßßßßßßßßÞÞÞßßßÚÚÚÏÏÏÒÒÒÜÜÜàààßßßßßßÝÝÝßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßÆÆÆÚÚÚàààßßßßßßßßßßßßÞÞÞõõõÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØ´´´ÈÈÈÕÕÕÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÒÒÒÔÔÔÓÓÓÙÙÙÉÉÉÁÁÁËËËÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÒÒÒÖÖÖÀÀÀ»»»ÖÖÖÒÒÒÓÓÓÓÓÓÓÓÓÑÑÑòòòÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØºººËËËØØØÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖ×××ÓÓÓÆÆÆÕÕÕòòòÔÔÔ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÖÖÖÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖ¸¸¸ÐÐÐ×××ÕÕÕÕÕÕÖÖÖÔÔÔóóóÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØ¹¹¹ËËË×××ÕÕÕÕÕÕÖÖÖ×××ÒÒÒÊÊÊÉÉÉÒÒÒ¸¸¸ìììãããÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÞÞÞÒÒÒÞÞÞ×××ÕÕÕÕÕÕÕÕÕÔÔÔØØØÆÆÆ¾¾¾ØØØÔÔÔÕÕÕÕÕÕÓÓÓóóóÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØ¹¹¹ÊÊÊ×××ÕÕÕ×××ÒÒÒÊÊÊÈÈÈÏÏÏÕÕÕÙÙÙÆÆÆÆÆÆõõõÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ___(((aaaÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖ¹¹¹ÏÏÏÖÖÖÕÕÕÕÕÕÓÓÓóóóÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØ¹¹¹ËËËÙÙÙÒÒÒÊÊÊÇÇÇÎÎÎÖÖÖÖÖÖÕÕÕÕÕÕ×××¶¶¶çççäääÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÒÒÒâââÁÁÁžžžàààÓÓÓÕÕÕÕÕÕÕÕÕØØØÈÈÈ¿¿¿ØØØÔÔÔÕÕÕÓÓÓóóóÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØ¹¹¹ÈÈÈÌÌÌÆÆÆÍÍÍÕÕÕÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕØØØÇÇÇÃÃÃõõõÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÑÑÑæææxxxZZZ ºººÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖ¼¼¼ÏÏÏÖÖÖÕÕÕÓÓÓóóóÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØ¹¹¹½½½ÎÎÎÕÕÕÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕØØØ¶¶¶ääääääÒÒÒÕÕÕÕÕÕÕÕÕÓÓÓààà›››www¥¥¥ÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÊÊÊ¿¿¿ØØØÕÕÕÔÔÔóóóÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØ¸¸¸ÊÊÊÙÙÙÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕØØØÉÉÉÀÀÀóóóÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÚÚÚppp888XXXËËË×××ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××¾¾¾ÏÏÏ×××ÓÓÓóóóÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØ¹¹¹ËËË×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕØØØ¶¶¶áááåååÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕßßßÑÑÑÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÊÊÊ¿¿¿ØØØÓÓÓóóóÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØ¹¹¹ËËË×××ÕÕÕÕÕÕÕÕÕÔÔÔÓÓÓÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕ×××ÊÊʽ½½òòòÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÖÖÖÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÔÔÔÞÞÞàààÂÂÂÐÐÐÕÕÕóóóÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØ¹¹¹ËËË×××ÕÕÕÕÕÕÕÕÕÜÜÜàààÖÖÖÔÔÔÕÕÕÕÕÕÕÕÕÔÔÔØØØ···ÝÝÝåååÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÕÕÕÝÝÝäääÚÚÚÎÎÎÊÊʼ¼¼ÔÔÔóóóÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØ¹¹¹ËËË×××ÕÕÕÕÕÕ×××µµµ¡¡¡ÑÑÑÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕ×××ËËË»»»ñññÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÕÕÕÞÞÞåååÛÛÛÌÌÌÊÊÊÒÒÒØØØ¼¼¼ÇÇÇöööÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØ¹¹¹ËËË×××ÔÔÔÖÖÖÒÒÒlllGGG;;;ÅÅÅÙÙÙÔÔÔÕÕÕÕÕÕÔÔÔÙÙÙ···ÚÚÚåååÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÕÕÕÞÞÞåååÛÛÛËËËÉÉÉÒÒÒ×××ÕÕÕ×××ÎÎθ¸¸ôôôÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØ¹¹¹ËËË×××ÕÕÕÔÔÔÚÚÚžžžhhhvvvåååÒÒÒÕÕÕÕÕÕÕÕÕ×××ÍÍ͸¸¸îîîÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÕÕÕßßßæææÜÜÜËËËÈÈÈÒÒÒ×××ÖÖÖÕÕÕÕÕÕÔÔÔØØØ»»»èèèÝÝÝÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØ¹¹¹ËËË×××ÓÓÓÛÛÛ¼¼¼ ‚‚‚aaaæææÑÑÑÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙ¸¸¸ÖÖÖåååÒÒÒÕÕÕÓÓÓÕÕÕßßßçççÜÜÜÊÊÊÇÇÇÑÑÑ×××ÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÍÍÍëëëÜÜÜÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØ¹¹¹ËËË×××ÓÓÓÛÛÛ½½½‘‘‘!!!‹‹‹âââÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕ×××ÎÎζ¶¶ìììÔÔÔÕÕÕàààçççÝÝÝÊÊÊÆÆÆÐÐÐ×××ÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔóóóÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØµµµÊÊÊØØØÕÕÕÔÔÔÜÜÜœœœEEEÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙ¸¸¸ÐÐÐñññæææÝÝÝÉÉÉÅÅÅÐÐÐ×××ÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓóóóÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÚÚÚáááÐÐÐÖÖÖÕÕÕÕÕÕÔÔÔÞÞÞçççáááÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÖÖÖÓÓÓ¹¹¹íííÍÍÍÃÃÃÏÏÏÖÖÖÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÓÓÓÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓóóóÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÀÀÀÑÑÑÖÖÖÕÕÕÕÕÕÕÕÕÓÓÓÑÑÑÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔÚÚÚÞÞÞÖÖÖ»»»ÝÝÝçççÒÒÒ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÛÛÛãããßßßÔÔÔÕÕÕÕÕÕÕÕÕÓÓÓóóóÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕØØØ³³³ÊÊÊØØØÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔÚÚÚàààÖÖÖÇÇÇÈÈÈËË˽½½÷÷÷×××ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØ½½½”””¨¨¨ÙÙÙÖÖÖÕÕÕÕÕÕÓÓÓóóóÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØºººÌÌÌ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÓÓÓÚÚÚàààØØØÈÈÈÆÆÆÐÐÐÖÖÖÚÚÚ»»»ÛÛÛìììÑÑÑÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÞÞÞmmmQQQ'''WWWÞÞÞÓÓÓÕÕÕÓÓÓóóóÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØºººÜÜÜ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÓÓÓÙÙÙáááÚÚÚÉÉÉÅÅÅÏÏÏ×××ÖÖÖÔÔÔÖÖÖÐÐм¼¼ôôôØØØÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÒ´´´BBB555ÞÞÞÔÔÔÕÕÕÓÓÓóóóÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØ¸¸¸ëëëàààÓÓÓÖÖÖÕÕÕÔÔÔÓÓÓÙÙÙâââÜÜÜÊÊÊÄÄÄÎÎÎ×××ÖÖÖÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙ½½½ÜÜÜíííÑÑÑÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÝÝÝ{{{áááÓÓÓÕÕÕÓÓÓóóóÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙ¶¶¶ÝÝÝôôôÒÒÒÕÕÕÓÓÓÙÙÙâââÞÞÞÌÌÌÄÄÄÍÍÍÖÖÖÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÑÑѾ¾¾õõõØØØÔÔÔÕÕÕÕÕÕÕÕÕÔÔÔÛÛÛ¡¡¡•••...CCCáááÓÓÓÕÕÕÓÓÓóóóÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØ¸¸¸ËËËùùùßßß×××ãããàààÍÍÍÃÃÃÌÌÌÖÖÖ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙ¿¿¿ÜÜÜìììÑÑÑÖÖÖÕÕÕÕÕÕÔÔÔÛÛÛ¨¨¨RRRcccºººÙÙÙÔÔÔÕÕÕÓÓÓóóóÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØ¹¹¹ÈÈÈçççöööÞÞÞÏÏÏÃÃÃÊÊÊÕÕÕ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÒÒÒ¿¿¿ôôôØØØÔÔÔÕÕÕÕÕÕÕÕÕÔÔÔÝÝÝèèèæææÚÚÚÔÔÔÕÕÕÕÕÕÓÓÓóóóÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØ¹¹¹ÊÊÊÙÙÙìììÉÉÉÈÈÈÕÕÕ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÑÑÑÑÑÑÑÑÑÔÔÔÕÕÕÕÕÕÔÔÔÙÙÙÁÁÁÝÝÝíííÑÑÑÖÖÖÕÕÕÕÕÕÕÕÕÔÔÔÑÑÑÑÑÑÔÔÔÕÕÕÕÕÕÕÕÕÔÔÔóóóÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØ¹¹¹ËËËÔÔÔëëëíííÔÔÔÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÚÚÚçççæææèèèØØØÔÔÔÕÕÕÕÕÕÖÖÖÓÓÓÂÂÂôôôØØØÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÓÓÓóóóÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØ¹¹¹ËËË×××ØØØöööÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÛÛÛµµµgggkkk___ÃÃÃÙÙÙÔÔÔÕÕÕÔÔÔØØØÃÃÃÜÜÜëëëÑÑÑÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕôôôÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØ¹¹¹ËËËØØØÑÑÑêêêìììÒÒÒÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÜÜÜ´´´444ÃÃÃÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÓÓÓÃÃÃóóóØØØÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÖÖÖßßßäää÷÷÷ÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØ¹¹¹ËËËØØØÔÔÔ×××öööÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓààุ¸***›››âââÒÒÒÕÕÕÕÕÕÕÕÕÔÔÔØØØÅÅÅßßßíííÑÑÑÖÖÖÕÕÕÕÕÕÕÕÕÓÓÓÖÖÖßßßåååáááÖÖÖóóóÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØ¹¹¹ËËË×××ÕÕÕÒÒÒèèèìììÒÒÒÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÍÍÍïï﨨¨ ÃÃÃÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÆÆÆóóóØØØÕÕÕÕÕÕÓÓÓÖÖÖßßßæææááá×××ÔÔÔÓÓÓóóóÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØ¹¹¹ËËË×××ÕÕÕÕÕÕÖÖÖôôôÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÓÓÓÞÞÞ¥¥¥DDD555'''ËËËØØØÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕØØØÇÇÇÞÞÞëëëÐÐÐØØØàààæææááá×××ÓÓÓÔÔÔÖÖÖÔÔÔóóóÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØ¹¹¹ËËË×××ÕÕÕÖÖÖÒÒÒæææìììÒÒÒÖÖÖÕÕÕÕÕÕÕÕÕÖÖÖÏÏÏœœœ‘‘‘ÉÉÉÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÆÆÆôôôäääæææááá×××ÓÓÓÔÔÔÕÕÕÕÕÕÕÕÕÓÓÓóóóÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØ¹¹¹ËËË×××ÕÕÕÕÕÕÕÕÕÕÕÕòòòÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖáááää䨨ØÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÚÚÚÍÍÍÞÞÞèèèÖÖÖÓÓÓÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓóóóÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØ´´´ÉÉÉ×××ÔÔÔÕÕÕÕÕÕÒÒÒäääëëëÑÑÑÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÓÓÓÒÒÒÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÓÓÓÖÖÖàààäääÞÞÞÓÓÓÓÓÓÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓóóóÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÚÚÚßßßÑÑÑØØØÖÖÖ×××××××××ÖÖÖóóóÞÞÞÕÕÕ××××××××××××××××××××××××××××××ÖÖÖØØØáááçççááá×××ÕÕÕ××××××××××××××××××××××××××××××ÕÕÕóóóÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÅÅŸ¸¸¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶µµµ»»»ºººµµµ¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¸¸¸½½½¸¸¸´´´¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶···´´´ÆÆÆØØØÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÍÍÍÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÎÎÎÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÎÎÎÏÏÏÐÐÐÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÎÎÎÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×××××××××ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ( @ ÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖ×××ÕÕÕÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖ×××ÖÖÖÖÖÖÔÔÔ×××ÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÕÕÕÕÕÕÖÖÖÕÕÕÕÕÕÖÖÖÕÕÕÕÕÕÕÕÕÝÝÝïïïëëëììììììììììììëëëìììëëëæææéééíííæææëëëíííìììììììììììììììèèèèèèíííëëëìììéééëëëÛÛÛÓÓÓÖÖÖÒÒÒ»»»ÕÕÕÖÖÖÖÖÖÕÕÕÖÖÖÖÖÖØØØÔÔÔÇÇÇÍÍÍÔÔÔÖÖÖÖÖÖÕÕÕÖÖÖÓÓÓÓÓÓÕÕÕÕÕÕ×××ÑÑÑ¿¿¿×××ÕÕÕÖÖÖÓÓÓêêêÜÜÜÓÓÓÕÕÕÕÕÕ¾¾¾ÔÔÔÕÕÕÕÕÕÖÖÖÕÕÕÑÑÑÇÇÇää䨨ØÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔßßßãããÖÖÖÕÕÕÔÔÔØØØÃÃÃÊÊÊ×××ÕÕÕÒÒÒéééÜÜÜÓÓÓÕÕÕÕÕÕ¾¾¾ÔÔÔÖÖÖÖÖÖÐÐÐËËËÐÐÐÌÌÌÍÍÍêêêÑÑÑÖÖÖÕÕÕÕÕÕÔÔÔÛÛÛ………ÒÒÒÖÖÖÕÕÕÖÖÖÒÒÒÀÀÀÖÖÖÕÕÕÒÒÒéééÜÜÜÓÓÓÕÕÕÔÔÔ¾¾¾ÕÕÕÐÐÐÊÊÊÍÍÍÔÔÔÖÖÖÙÙÙÂÂÂâââÜÜÜÔÔÔÕÕÕÔÔÔÝÝݰ°°???DDDäääÒÒÒÔÔÔØØØÆÆÆËËËØØØÒÒÒéééÜÜÜÓÓÓÕÕÕÕÕÕ¼¼¼ÉÉÉÌÌÌÓÓÓÖÖÖÕÕÕÕÕÕÖÖÖÏÏÏÉÉÉéééÒÒÒÖÖÖÓÓÓßßß§§§"""bbb°°°ÜÜÜÔÔÔÕÕÕÖÖÖÓÓÓÂÂÂÖÖÖÒÒÒéééÜÜÜÓÓÓÕÕÕÕÕÕ¼¼¼ÒÒÒ×××ÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÂÂÂßßßÜÜÜÓÓÓÕÕÕÖÖÖÔÔÔcccaaaÅÅÅÙÙÙÔÔÔÕÕÕÕÕÕØØØÇÇÇËËËÔÔÔèèèÜÜÜÓÓÓÕÕÕÔÔÔ¾¾¾ÕÕÕÕÕÕÕÕÕÓÓÓÒÒÒÕÕÕÕÕÕÖÖÖÐÐÐÇÇÇçççÒÒÒÖÖÖÔÔÔ×××ÚÚÚÆÆÆÓÓÓÖÖÖÕÕÕÕÕÕÔÔÔÔÔÔÖÖÖÆÆÆÓÓÓéééÜÜÜÓÓÓÕÕÕÕÕÕ¾¾¾ÔÔÔÕÕÕÔÔÔÞÞÞáááÕÕÕÕÕÕÔÔÔØØØÂÂÂÛÛÛÜÜÜÓÓÓÕÕÕÔÔÔÔÔÔØØØÕÕÕÕÕÕÔÔÔÔÔÔÙÙÙÞÞÞÛÛÛÈÈÈÆÆÆëëëÜÜÜÓÓÓÕÕÕÕÕÕ¾¾¾ÔÔÔÕÕÕØØØ§§§›››ÖÖÖÖÖÖÕÕÕÖÖÖÑÑÑÄÄÄæææÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔÙÙÙßßßÚÚÚÐÐÐÏÏÏÔÔÔ¼¼¼èèèÝÝÝÓÓÓÕÕÕÕÕÕ¾¾¾ÔÔÔÔÔÔÛÛÛ˜˜˜+++xxxâââÒÒÒÔÔÔÙÙÙÃÃÃØØØÝÝÝÓÓÓÕÕÕÔÔÔÔÔÔÙÙÙßßßÚÚÚÏÏÏÎÎÎÔÔÔÖÖÖØØØÅÅÅÚÚÚßßßÓÓÓÕÕÕÕÕÕ¾¾¾ÔÔÔÖÖÖÐÐÐOOOSSSJJJäääÒÒÒÕÕÕÖÖÖÒÒÒÂÂÂäääÒÒÒÔÔÔÚÚÚàààÛÛÛÏÏÏÍÍÍÓÓÓÖÖÖÕÕÕÕÕÕÖÖÖÑÑÑßßßÝÝÝÓÓÓÕÕÕÔÔÔ»»»ÔÔÔÕÕÕÕÕÕ[[[HHHàààÓÓÓÕÕÕÔÔÔÙÙÙÃÃÃÓÓÓâââàààÛÛÛÎÎÎÌÌÌÓÓÓ×××ÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÒÒÒêêêÜÜÜÓÓÓÔÔÔØØØÒÒÒÓÓÓÕÕÕØØØÓÓÓ¼¼¼ÛÛÛÔÔÔÕÕÕÕÕÕÔÔÔÕÕÕÕÕÕÄÄÄéééÍÍÍËËËÒÒÒ×××ÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÔÔÔÖÖÖÒÒÒéééÜÜÜÓÓÓÕÕÕÓÓÓÄÄÄÕÕÕÕÕÕÔÔÔÖÖÖÛÛÛÔÔÔÕÕÕÔÔÔÔÔÔØØØÚÚÚÖÖÖÂÂÂÜÜÜÜÜÜÔÔÔÖÖÖÕÕÕÕÕÕÕÕÕ×××ÖÖÖÜÜÜÜÜÜÔÔÔÒÒÒéééÜÜÜÓÓÓÕÕÕÔÔÔ»»»ÔÔÔÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔÔÔÔ×××ÜÜÜÖÖÖÌÌÌÍÍÍÑÑÑÇÇÇìììÒÒÒÕÕÕÕÕÕÔÔÔØØØÈÈÈnnnZZZ²²²ÜÜÜÑÑÑéééÜÜÜÓÓÓÕÕÕÓÓÓÇÇÇÜÜÜÓÓÓÖÖÖÕÕÕÓÓÓ×××ÜÜÜØØØÌÌÌËËËÓÓÓÖÖÖÙÙÙÅÅÅÞÞÞàààÓÓÓÕÕÕÕÕÕÔÔÔÖÖÖ®®®---ãããÐÐÐéééÜÜÜÓÓÓÕÕÕÓÓÓÆÆÆîîîÓÓÓÔÔÔ×××ÝÝÝÙÙÙÍÍÍËËËÒÒÒ×××ÕÕÕÕÕÕÕÕÕÓÓÓÈÈÈêêêÓÓÓÕÕÕÕÕÕÔÔÔ×××£££&&&   áááÐÐÐéééÜÜÜÓÓÓÕÕÕÕÕÕ»»»ëëëãããÛÛÛÛÛÛÎÎÎÊÊÊÑÑÑ×××ÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕØØØÇÇÇÞÞÞàààÓÓÓÕÕÕÖÖÖÒÒÒiii¿¿¿ÚÚÚÑÑÑéééÜÜÜÓÓÓÕÕÕÕÕÕ¼¼¼ÛÛÛìììÎÎÎÊÊÊÑÑÑ×××ÖÖÖÕÕÕÕÕÕÓÓÓÒÒÒÔÔÔÕÕÕÕÕÕÓÓÓÊÊÊêêêÓÓÓÕÕÕÕÕÕÖÖÖÞÞÞãããÙÙÙÕÕÕÓÓÓéééÜÜÜÓÓÓÕÕÕÕÕÕ¾¾¾ÓÓÓèèè×××ÕÕÕÖÖÖÕÕÕÕÕÕÕÕÕÔÔÔàààâââÚÚÚÕÕÕÕÕÕØØØÉÉÉßßßàààÓÓÓÕÕÕÕÕÕÓÓÓÒÒÒÔÔÔÖÖÖÒÒÒèèèÜÜÜÓÓÓÕÕÕÕÕÕ¾¾¾ÒÒÒàààíííÒÒÒÕÕÕÕÕÕÕÕÕÓÓÓÞÞÞtttMMMŽŽŽÚÚÚÔÔÔÕÕÕÔÔÔÍÍÍêêêÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔÕÕÕíííÜÜÜÓÓÓÕÕÕÕÕÕ¾¾¾ÕÕÕÓÓÓìììÜÜÜÓÓÓÕÕÕÕÕÕÓÓÓÝÝÝ222´´´ÚÚÚÔÔÔÕÕÕ×××ËËËàààßßßÓÓÓÖÖÖÔÔÔÔÔÔØØØàààÞÞÞìììÜÜÜÓÓÓÕÕÕÕÕÕ¾¾¾ÕÕÕÓÓÓÝÝÝëëëÓÓÓÖÖÖÕÕÕÕÕÕÒÒÒØØØwwwRRRåååÒÒÒÕÕÕÕÕÕÔÔÔÏÏÏêêêÒÒÒÔÔÔØØØàààáááÛÛÛÑÑÑèèèÜÜÜÓÓÓÕÕÕÕÕÕ¾¾¾ÔÔÔÖÖÖÓÓÓêêêÜÜÜÓÓÓÕÕÕÔÔÔÛÛÛ‰‰‰OOO™™™ÝÝÝÓÓÓÕÕÕÕÕÕ×××ÌÌÌàààãããÞÞÞâââÚÚÚÔÔÔÔÔÔÒÒÒéééÜÜÜÓÓÓÕÕÕÔÔÔ¼¼¼ÔÔÔÕÕÕÓÓÓÛÛÛéééÒÒÒÕÕÕÔÔÔÔÔÔÚÚÚÝÝÝÝÝÝÓÓÓÕÕÕÔÔÔÔÔÔÓÓÓ×××ÓÓÓçççÙÙÙÔÔÔÓÓÓÕÕÕÕÕÕÒÒÒèèèÜÜÜÓÓÓÕÕÕÖÖÖÈÈÈ×××ØØØØØØÕÕÕëëëáááÖÖÖØØØØØØ×××ÖÖÖÖÖÖØØØØØØØØØÛÛÛâââãããÚÚÚÖÖÖ×××ØØØØØØØØØØØØÕÕÕêêêÜÜÜÓÓÓÕÕÕÖÖÖÌÌÌ¿¿¿ÁÁÁÁÁÁÀÀÀÅÅÅÉÉÉ¿¿¿ÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÀÀÀÂÂÂÉÉÉÆÆÆ¿¿¿ÀÀÀÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁÁ¾¾¾ÎÎÎÙÙÙÔÔÔÕÕÕÔÔÔÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÍÍÍÌÌÌÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÍÍÍÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÍÍÍÔÔÔÕÕÕÕÕÕÕÕÕ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××ÕÕÕÕÕÕ(  ÕÕÕÙÙÙØØØØØØØØØÙÙÙÙÙÙØØØØØØ×××ØØØÙÙÙÙÙÙØØØ×××ÕÕÕÒÒÒÖÖÖáááßßßàààÜÜÜÛÛÛßßßßßßæææâââÜÜÜÙÙÙàààâââÚÚÚÑÑÑÉÉÉÕÕÕÐÐÐÍÍÍØØØÔÔÔÔÔÔÓÓÓ¶¶¶ÍÍÍÕÕÕÈÈÈÑÑÑÝÝÝÛÛÛÒÒÒÈÈÈÑÑÑÒÒÒÓÓÓÓÓÓÚÚÚÚÚÚ½½½<<<¹¹¹ÝÝÝÏÏÏÌÌÌßßßÚÚÚÒÒÒÉÉÉÖÖÖÚÚÚ×××ÏÏÏ×××ØØØÏÏÏÎÎÎÖÖÖÖÖÖËËËÝÝÝÛÛÛÒÒÒËËËØØØÂÂÂÒÒÒÕÕÕÏÏÏÚÚÚÕÕÕÞÞÞÖÖÖØØØØØØÎÎÎÕÕÕÜÜÜÑÑÑËËËÖÖÖLLL˜˜˜âââÍÍÍÔÔÔ×××ÖÖÖ×××ÔÔÔÑÑÑÓÓÓÖÖÖÚÚÚÓÓÓÏÏÏÓÓÓŽŽŽ¾¾¾ÙÙÙÕÕÕÏÏÏÜÜÜÒÒÒÒÒÒÕÕÕßßßÖÖÖÞÞÞÛÛÛÒÒÒÌÌÌ×××ßßßÚÚÚÖÖÖÕÕÕÍÍÍØØØÖÖÖÖÖÖÒÒÒ£££ÈÈÈàààÚÚÚÑÑÑÔÔÔØØØÔÔÔÔÔÔÒÒÒÐÐÐÓÓÓÓÓÓÜÜÜÓÓÓÚÚÚ^^^¨¨¨çççÙÙÙÐÐÐÔÔÔàààÐÐÐÒÒÒÔÔÔàààÙÙÙÐÐÐÛÛÛ×××ÓÓÓ®®®ËËËßßßÚÚÚÑÑÑËËËâââÔÔÔÖÖÖÖÖÖ¡¡¡ÅÅÅ×××ÔÔÔÜÜÜÔÔÔÝÝÝÕÕÕßßßÛÛÛÒÒÒÉÉÉßßßÜÜÜÑÑÑÝÝÝooožžžàààÐÐÐÛÛÛÖÖÖ×××ÙÙÙáááÚÚÚÑÑÑËËËØØØããã×××ØØØ¯¯¯ÃÃÃÛÛÛÕÕÕÚÚÚáááÛÛÛÖÖÖÞÞÞÛÛÛÔÔÔËËËËËËÒÒÒÑÑÑËËËÓÓÓÐÐÐÌÌÌÒÒÒÏÏÏÌÌÌÌÌÌËËËÔÔÔÙÙÙÕÕÕÑÑÑÏÏÏÏÏÏÏÏÏÏÏÏÍÍÍÎÎÎÐÐÐÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÕÕÕ(0` ÕÕÕÖÖÖÐÐÐÓÓÓÒÒÒÔÔÔÙÙÙãããòòòôôôðððñññóóóäääåååîîîÛÛÛ½½½×××áááßßßÞÞÞÚÚÚÏÏÏÜÜÜàààÝÝÝÆÆÆõõõØØØ´´´ÈÈÈÉÉÉÁÁÁËËËÀÀÀ»»»ÑÑѺºº¸¸¸¹¹¹ÊÊÊììì¾¾¾___(((aaaÇÇÇÎÎζ¶¶çççâââžžž¿¿¿ÌÌÌÍÍÍÃÃÃæææxxxZZZ ¼¼¼›››www¥¥¥ppp888XXX···µµµ¡¡¡ööölllGGG;;;ÅÅÅhhhvvvèèè ‚‚‚ëëë‘‘‘!!!‹‹‹œœœEEEííí³³³÷÷÷”””¨¨¨mmmQQQ'''WWWBBB555ÄÄÄ{{{•••...CCCùùùRRRcccgggkkkêêê444***ïïï DDD   !"#$%&"' (") '*+ ()),-.( (")/012 345!678 (9:/;%<=>?@&A (01 BCDE)8 ') # FGH"+ ("1%)8 (")I ("J 0)A ("KL%"$ 9)A/M("NOPQJ" 0' ("7RST:'<"$U("AVWX.<%'2)/%:Y("SZ[\301*2) K)]^_' < Q 2(`:; #%%$2 a)/"bcd &9$*%efgh & QA ij 'Y3)k0`%lm_ 1 39k:%+Lnop '"q:;98*%drs& (2M;)8 U< ()* %%%!`%%% ("Y`2w_;;  b("M'xB3Q`% ("U*:ydz; < (" E{jg"/Y< ("<*]Z  < (" :U   Y%  % 2 Q'11111K$&K11111111111''11111111111J:0000( @ÕÕÕÔÔÔÖÖÖ×××ÝÝÝïïïëëëìììæææéééíííèèèÛÛÛÓÓÓÒÒÒ»»»ØØØÇÇÇÍÍÍÑÑÑ¿¿¿êêêÜÜܾ¾¾äääßßßãããÃÃÃÊÊÊÐÐÐËËËÌÌÌ………ÀÀÀÙÙÙÂÂÂâââ°°°???DDDÆÆÆ¼¼¼ÉÉÉÏÏϧ§§"""bbbcccaaaÅÅÅçççÚÚÚÞÞÞáááÈÈÈ›››ÄÄĘ˜˜+++xxxÎÎÎOOOSSSJJJààà[[[HHHnnnZZZ²²²®®®---îî£&&&   iiitttMMMŽŽŽ222´´´wwwRRRåå剉‰™™™ÁÁÁ           !"  #$%&'()*  +, -,  ./0& $  +$ 123#   45* *  67$  #6 8* .9: #5-+   ;<=%# #5->35 ?@A$5B -  CDEB # %B >    + :    : 5$  8FGH     #36B IJK  *L # 8 MNO7   >6B )P5  + >   6#   B%5,B   B  6QRS5      TU5B B6   VWX-B7      Y?Z B6%5  + 5   4#   87 %5 [["3,[[[[[["$,*"[[[[[[>#>>>>>>>>>>>>>>>>>>>>>>( ÕÕÕÙÙÙØØØ×××ÒÒÒÖÖÖáááßßßàààÜÜÜÛÛÛæææâââÚÚÚÑÑÑÉÉÉÐÐÐÍÍÍÔÔÔÓÓÓ¶¶¶ÈÈÈÝÝݽ½½<<<¹¹¹ÏÏÏÌÌÌÎÎÎËËËÂÂÂÞÞÞLLL˜˜˜ŽŽŽ¾¾¾£££^^^¨¨¨ççç®®®¡¡¡ÅÅÅooožžžãã㯯¯ÃÃà          !"  #$   %   &'( )  *+   ,-  ./0   (0`€€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ÷÷w÷w÷÷w÷÷w÷ÿÿ÷ÿ÷÷ÿÿ÷÷ÿ÷ÿÿ÷÷ÿÿ÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷÷ww÷÷w÷÷÷w÷w÷÷÷ÿ÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷ÿ÷÷w÷÷ÿ÷÷ÿÿ÷÷÷ÿÿ÷÷÷ÿ÷÷÷ÿ÷÷÷ÿ÷÷w€÷÷ÿ÷÷÷÷÷÷÷÷÷ð‡÷÷÷ÿ÷÷÷ÿ÷÷p‡ÿw÷÷÷ÿ÷÷÷÷ÿwÿx÷÷÷÷÷÷÷ÿÿ÷÷÷xw÷÷÷÷ÿÿ÷÷ÿ÷÷€÷ÿ÷ÿ÷÷÷÷÷÷÷÷÷÷÷ÿ÷÷÷÷÷ÿÿ÷÷÷÷÷÷÷÷ÿ÷÷w÷÷ÿ÷÷ÿ÷÷÷÷÷÷÷ÿ÷÷w÷ÿ÷÷÷ÿ÷€÷÷÷÷÷÷÷ÿÿ÷÷÷xÿ÷÷÷÷ÿ÷ÿÿ÷÷÷÷÷ÿ÷÷ÿˆ÷÷÷ÿ÷ÿw÷÷÷÷€÷÷÷ÿÿ÷÷÷ÿ÷øˆÿÿ÷wÿÿ÷÷ÿ÷÷÷÷÷€‡÷÷÷ÿÿ÷÷÷÷÷ÿ÷÷ÿw÷÷÷ÿ÷ÿ÷÷÷÷ÿ÷÷÷÷÷÷÷÷÷ÿ÷÷÷÷ÿÿ÷ÿÿ÷÷÷÷÷ÿw÷÷÷÷÷ÿ÷wÿÿ÷øˆÿw÷ÿ÷÷ÿ÷÷÷÷÷÷x€÷÷÷÷÷÷÷÷ÿ÷÷÷ÿ÷÷øÿwÿÿ÷÷ÿ÷÷÷÷÷÷‡÷÷ÿ÷ÿÿwÿ÷÷÷÷÷÷ÿ÷÷÷÷øÿ÷÷ÿ÷ÿÿÿx÷÷÷÷ÿÿ÷ÿÿ÷÷÷ÿ÷wÿwÿ÷w÷÷÷÷÷ÿ÷÷÷÷÷÷÷ÿ÷÷÷÷w÷÷÷ÿ÷÷÷÷÷ÿ÷÷÷ÿÿÿwÿÿ÷÷ÿÿÿÿ÷÷÷÷÷ˆˆ÷÷ÿ÷÷÷÷÷÷÷÷÷÷ÿ÷÷ˆ÷ÿÿÿÿ÷ÿ÷÷÷pw÷÷÷÷÷÷ÿÿ÷÷÷÷ÿwÿ÷ÿÿ÷ÿ÷÷ÿ÷÷ÿÿ÷wˆ÷÷÷÷ÿ÷÷ÿÿÿ÷÷÷÷÷÷€÷ÿ÷w÷÷÷w÷ÿ÷÷÷÷w÷÷ÿÿÿÿÿ÷÷÷÷÷÷ÿÿ÷÷÷÷÷÷÷÷ÿ÷÷÷÷÷ÿÿ÷÷wÿÿ÷÷ÿ÷ÿ÷÷ÿ÷w÷÷÷÷ÿ÷ÿ÷ÿ÷÷÷÷÷ÿÿÿ÷÷÷ÿ÷w÷w÷÷w÷÷÷÷÷÷( @€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿwwwwÿw÷w÷÷w÷÷ÿÿÿÿÿÿÿÿÿ÷÷ÿ÷wwwwwwwwwww÷w÷w÷w÷÷ÿw÷wÿ÷÷ÿww÷wøww÷wwww÷www€‡÷ww÷ww÷w÷÷wˆwww÷ww÷w÷w÷w÷wÿ÷÷ww÷÷ÿxwww÷wÿwwww÷÷ÿ÷w÷÷wwwwwwwww÷w÷ww÷‡÷÷w÷÷ÿ÷w÷÷w÷x€ww÷www÷w÷wø€÷ÿ÷wwwwwÿpˆwwww÷wwwÿwwÿw÷w÷÷ÿww÷ww÷÷÷÷w÷wwÿwwÿwww÷wwx‡÷÷w÷÷ww÷wÿwww÷w÷÷÷w÷w÷÷÷wxÿ÷w÷÷÷wwÿwxˆw÷wÿwwww÷w÷w÷÷ww÷÷÷wwwwwww÷ÿwÿ÷ww÷ww÷ÿ÷÷w÷÷w÷÷wÿww÷w÷wwÿ÷÷wxw÷ÿwww÷÷÷wÿÿw÷wpwwÿwÿ÷÷www÷wÿˆw÷ÿwwÿ÷w÷÷w÷ww÷÷w÷ww÷ww÷ÿw÷÷ÿ÷÷÷÷wÿ÷÷wwwwwwwwwwwwww÷ww÷wwwwwww÷ww( €€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿw÷w÷÷w÷÷÷÷÷÷wwwwwwwÿˆ÷÷w÷÷xwwwwwÿwwxw÷÷÷xwww÷wwww‡÷ÿwÿ÷‡ww÷ww÷w÷‡w÷÷÷÷w‡÷÷w÷ww÷÷÷wwwww÷www÷÷w÷÷puzzles-20170606.272beef/icons/tracks.ico0000644000175000017500000006117613115373750017002 0ustar simonsimon 00 ¨%–  ¨>& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÒÒÒÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔ×××ÃÃí­­´²±±°°°°°°°°°°°°°°°°°°°°¯¯¯ÈÈÈÑÑÑÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐËËËÍÍÍÐÐÐÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏËËËÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÕÕÕÕÕÕÓÓÓÕÕÕÔÔÔØØØÁÁÁ§¦¦š¡£¢¤¥ª©©©©©©©©©©©©©©©©©¨¨¨ËËËØØØ×××ØØØÕÕÕÖÖÖÖÖÖ×××××××××ÐÐÐÒÒÒ×××ØØØ×××ÖÖÖÖÖÖÖÖÖØØØÖÖÖÖÖÖÎÎÎÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÞÞÞÒÒÒÓÓÓÝÝÝÖÖÖÔÔÔ×××ÅÄÄ«¬­B”š¨¬¯¬«§¨¨ªªªªªªªªªªªª©©©ÊÊÊØØØÐÐÐÍÍÍØØØÓÓÓØØØÏÏÏÎÎÎ×××ÏÏÏÑÑÑ×××ËËËÓÓÓÖÖÖÔÔÔØØØËËËÓÓÓÕÕÕÍÍÍÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÐÐа°°ãããßßß°°°ÑÑÑÓÓÓãããZZZ 07}€±±±²°°­ª©ªªªªªªªªª©©©ÊÊÊØØØÒÒÒ³³³ÉÉÉÜÜÜÎÎβ²²ÐÐÐ×××ÏÏÏÑÑÑØØØÉÉɳ³³ÔÔÔÛÛÛÁÁÁ¸¸¸ÖÖÖÕÕÕÍÍÍÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÓÓÓ***[[[UUU111×××ÓÓÓÞÞÞƒ‚"& 655Ž•˜K”–Ÿ£®¬«©ªª©©©ÊÊÊ×××ÖÖÖÓÓÓµµµÅÅŵµµÏÏÏØØØÖÖÖÏÏÏÑÑÑÕÕÕÙÙÙÇÇǸ¸¸ÃÃø¸¸×××ÕÕÕÕÕÕÍÍÍÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÒæææbbb666111mmmæææÑÑÑÔÕÕÜ×ÕT‰›oŽ˜wqo  Ty…°¯¯¨©©ªªª©©©ÊÊÊ×××ÓÓÓÚÚÚÎÎΙ™™ÆÆÆÛÛÛÓÓÓÖÖÖÏÏÏÑÑÑÖÖÖÓÓÓÝÝݹ¹¹žžž××××××ÔÔÔÕÕÕÍÍÍÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓßßߥ¥¥444444­­­ÞÞÞÒÒÒÝÜÜ–—˜&^q ¨«³·¸8iy/*)®®®©©ªªªª©©©ÊÊÊ××××××ÎÎγ³³ÎÎεµµÉÉÉØØØÖÖÖÏÏÏÑÑÑÕÕÕÙÙÙÁÁÁ»»»ËË˳³³ÔÔÔÖÖÖÕÕÕÍÍÍÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÚÚÚ###...ÝÝÝÔÔÔÑÑÑäääPQQ2.-;r…i•£…‚edd»¸·¨¨¨©©©ÊÊÊØØØÑÑѳ³³ÏÏÏÚÚÚÓÓÓ³³³ÍÍÍØØØÏÏÏÑÑÑÙÙÙÆÆÆ···×××ÚÚÚÇÇǶ¶¶ÖÖÖÕÕÕÍÍÍÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÅÅÅÆÆÆ×××ÕÕÕÒÓÓãÞÜo›!CN"¨£¡°´µ$&C|{”œ±­«ÈÉÊ×××ÑÑÑÑÑÑ×××ÓÓÓÖÖÖÓÓÓÐÐÐ×××ÏÏÏÑÑÑÖÖÖÏÏÏÕÕÕÕÕÕÓÓÓ×××ÏÏÏÓÓÓÕÕÕÍÍÍÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÙÙÙÔÔÔÕÕÕÓÔÔÞÛÚ‡¥¯/x‘3[i/S_=‚™%DOjˆ¤©«¨§§ËËËÙÙÙ×××ØØØ×××××××××ØØØØØØØØØÑÑÑÓÓÓØØØØØØ××××××××××××ØØØ×××ØØØÎÎÎÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔÕÕÕÕÕÕÕÔÔÕ××ÏÈÆw’œH’5AE·¾À‹Š£›˜À¼º®®¯ÄÄÄËËËÉÉÉÉÉÉÊÊÊÊÊÊÊÊÊÉÉÉÈÉÉÊÊÊÇÇÇÇÈÈÉÊÊÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÈÉÉÉÉÉÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔ×רÄÃ㥀˜¡€„…‚†‡‰Ÿ¦‚“™||{~’˜Ÿ¥°¯¯°°°¨¨¨©©©©©©©©©©©©¨©©ªª©±­«§§§®®®¯­­«©©¨¨¨­«ªª©©©©©®«ª¨¨¨¬ªª©§§¼¼¼ØØØÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔ×××ÇÄȘž7v‹tƒk~…5v‹Myˆ„‚Ev‡[…“±®­°°°©©©ªªªªªª©ªªªªª¬«« ¥§y“œ©ªª»¶µz– mŽ™¼´±Y…”•¡¥Ÿ¦¨Tƒ“·±¯y•žkŒ—ÈÃÁÖ××ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÀÁÁ­ª©Ä¸´ŒŠ‰•‘È»¶²©¦~~~µ«¨»³°««¬±±±©©©ªªª«ªª®¬«¨©©­¬«£¨ª6sˆ”›ž³¬ªhˆ“\³ª§Ev‡ˆ–š“›ž@t…®¨¥iˆ’Y~ŠÀº¸Ö××ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔ××ׯÄÜ Q‚’x„r†Qƒ”_‚Ž‚€€Y€mŽ™°®­°°°©©©««ª¦¨©—¡¤°®­§§¨”““|€‚}~~€€‚€ƒ€€€€€€ƒ€‚}|{–––ÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔ×רÅÃÕž¢gŒ™|ƒ…y„ˆgŽ›oŠ“€€jˆ’|•ž¯­­°°°¨©©¬««¢¦§6uŠyŽ”‹‡…€t‚‡f‚‹¶­ªkŠ”`ƒŽ³ª§JyˆŠ–›”œžFw‡®¨¥l‰“]€Œ¿º¸Ö××ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÁÁÁ©¨¨¶±°Š‰‰‘¹´²¨¤£ª¦¥±®­«¬¬±±±©©©¨©©±®®Œ–šjtx„…²«©Œž¥0s‰Â»¹eŽœT„”ƺ¶5vŒŸ¥œ¦ª/sŠ¿·´dŒšQ‚’ÏÈÅÕÖ×ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÖ××ÈÅÃ…—,p‡r~‚g|ƒ+q‰Ev†ƒ€t†ƒ‚‚„€‚…†}„‡w„ŽŒ‹q~ƒƒ‡ˆ†ˆ‰p~‚‹‹|„†s}€¢¡ ÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔרØÃž£¤Š£‚†‡ƒ‰‹ŒŸ¥ˆ•š€€†•š’Ÿ¤¬¬¬¶³²…˜ž4sˆvq„v“œ¡£‹†„y€ƒ>t†c›m‘R‚’ĸ´5uŠŒž¤›¥¨/r‰½µ²d‹˜Q€‘ÍÆÃÕÖ×ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÖ××ÇÄÉšŸ;xtƒk~„9xN{Š‚€N|‹f‹˜°®­­¯°´¯­­ª©‚€t‡?{Gu„‚€Dvˆ-qˆ“¢§š£¦› ­ª©Š™žŸ£¥¢¥¦ˆ˜ž«©¨–Ÿ¢Žšž¿½½×ØØÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔ×××ÃÃݰ¯º·¶ŠŠŠ”’‘ËÁ½´­ª‚€Œ› £©º¶µ¿º¸¢¨…š €~¯§¥Í¾–•”‚‚a‰—‹¤Â»¹ÅÄÃÇÅÄÁÂÂÈÅÄÄÃÃÃÃÃÉÅÄÂÂÂÆÄÄÆÄÃÆÆÆÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÁÁÁ§§§µ±¯Œ‹‚†‡kŽšDxŠw|~Wy…$m†‡š ’¡¦)o†Ox†{}~FwˆfŒ™ƒˆŠŒ‰ˆÀµ²®«ª®¯°ÖÖÖ×ØØØØØÖ×××ØØØØØÖ××ØØØ×ררØÎÎÎÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔרØÃ£¥¦Rƒ“_zƒz~€Q€x”Œ‹‚JzŠ,qˆ,r‰FyŠ~ƒŠˆ~–žR‘v~€e{‚I~ž¤¥³²±ÓÓÓÕÕÕÒÒÒÖÖÖÔÔÔÔÔÔÖÖÖÔÔÔÓÓÓÕÕÕÍÍÍÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÃ£¥¦w“˜›€~}¤Ÿž¿¶³`…‘fw}‹ƒr€…p†‰ƒmy}X€Ž»´±ª¤¢€~}Ž—™v“ ¤¦³±±ÓÓÓØØØÃÃý½½ÙÙÙØØØÎÎζ¶¶ÕÕÕÕÕÕÍÍÍÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÁ¨¨¨µ¯­¯­¬‰Š‹‹†„`†’8wŒ¢£¤n‚‰w€ƒ}‚„h†¥¤£A{U‚‘ˆ††‡‡­¬«µ¯­ª©©°°°ÔÔÔÕÕÕØØØººº¿¿¿ÓÓÓ±±±ÏÏÏ×××ÕÕÕÍÍÍÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÂ§§§¨©ª«««§¦¦y}ix}œ ¢º´²7wŒˆœ£›§«0sг±°£¥¥kzv{|¤££­¬¬¨©©¨¨©±±±ÔÔÔÕÕÕÔÔÔÜÜܸ¸¸¢¢¢ÔÔÔ×××ÔÔÔÕÕÕÍÍÍÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÂ§§§©ªª²­¬]‡•Jz‰‘‰‡€ŠŽLx‡£¦§®®®Myˆ…‚ˆ…S|ŠR‚’°­«©ªª¨©©±±±ÔÔÔÕÕÕØØØÎÎη··¹¹¹¿¿¿ÙÙÙÕÕÕÕÕÕÍÍÍÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÂ§§§ªªª­¬«‚—ž¥§«ª©‘‘‘ƒ‚‚~€€€€€€~ƒŽ¨¨§¢§©€–ž««ªªªª©©©±±±ÔÔÔ×××ÍÍͱ±±ÏÏÏÛÛÛººº½½½×××ÕÕÕÍÍÍÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÂ¨§§«««ªªª±®¬¬«ª¨ªª¶±¯W‚k†¢ž£ŸžuŠ‘N}´°¯©ªª««ª²®¬ªªªªªª©©©±±±ÓÓÓ×××ÇÇÇÎÎÎØØØÔÔÔ×××ÄÄÄÓÓÓÖÖÖÍÍÍÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÂ§§§ªªªªªª¨©©©©©©©©®«ªfŠ—Ÿ£´²±·µµ˜¢¥b‰–«ªª©©©©©©¨©©ªªªªªª¨¨¨°°°ÕÕÕÖÖÖØØØ×××ÕÕÕÖÖÖÖÖÖÙÙÙÖÖÖÖÖÖÎÎÎÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÂ©©©¬¬¬«««««««««««««««²®­­¬«¬¬­°°°¬«ª³¯­«««««««««««««««¬¬¬ªªª±±±ÐÐÐÒÒÒÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑËËËÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÑÑÑÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÎÎÎÎÏÏÏÏÏÏÏÏÎÏÏÍÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÑÑÑÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÕÕÕÔÔÔÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÕÕÕÔÔÔÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÔÔÔÔÔÔÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÛÛÛâââÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÖÖÖÞÞÞàààßßßÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔ×××ààààààÝÝÝÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØººº˜˜˜ÅÅÅÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÑÑѯ¯¯¢¢¢¥¥¥ÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÌÌÌ£££¥¥¥²²²ØØØÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÜÜÜvvvYYY%%%···ÛÛÛÔÔÔÕÕÕÕÕÕÔÔÔ×××ÏÏÏ###sssÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÈÈÈAAA ŽŽŽÛÛÛÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÓÓÓ~~~µµµÜÜÜÔÔÔÕÕÕÕÕÕÕÕÕÓÓÓÝÝݰ°°888¼¼¼ÜÜÜÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÒÒÒæææ¡¡¡<<<ëëëÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÐÐÐ|||'''ÈÈÈØØØÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÎÎÎèè茌Œ)))àààÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓààà”””555ÞÞÞÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÝÝÝŒŒŒJJJ)))ÂÂÂÚÚÚÔÔÔÕÕÕÕÕÕÔÔÔØØØÊÊÊUUU...\\\ÞÞÞÓÓÓÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÃÃÃ---:::àààÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÈÈÈ«««ÌÌÌÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ××׿¿¿´´´ÙÙÙÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓ¹¹¹ÁÁÁ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕØØØÞÞÞ×××ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÚÚÚÝÝÝÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÜÜÜÚÚÚÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ( @ ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÒÒÒÒÒÒÒÒÒÓÓÓÒÒÒÒÒÒÓÓÓÓÓÓÒÒÒÒÒÒÓÓÓÓÓÓÒÒÒÒÒÒÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÕÕÕÓÓÓÕÕÕ××׺ºº²®­±¯¯°°°°°°°°°®®®¸¸¸ÒÒÒÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÏÏÏÍÍÍÒÒÒÑÑÑÑÑÑÑÑÑÒÒÒÑÑÑÎÎÎÕÕÕÕÕÕÕÕÕÖÖÖÝÝÝÖÖÖÞÞÞÕÕÕÖÖ×ÃÀ¿~𤠫®«©¨ª©¨ª©©¦¦¦´´´ØØØÒÒÒÖÖÖ×××ÖÖÖÓÓÓÔÔÔÑÑÑÕÕÕÓÓÓ××××××ÓÓÓÖÖÖÐÐÐÔÔÔÕÕÕ×××ÏÏÏ­­­ÐÐЫ««ÔÔÔÙÚÚNKJ!lrt·µµ¡§¨¨©©©©¨µµµØØØÊÊÊ¿¿¿ÙÙÙ¿¿¿ÌÌÌÕÕÕÐÐÐÖÖÖ½½½ÑÑÑÌÌÌ¿¿¿×××ÏÏÏÔÔÔÕÕÕÔÔÔØØØIII;;;YYYßààÚØ×…“*BJ",13`‰–ª««§§§µµµÖÖÖØØØÊÊÊ­­­ËËËÙÙÙÓÓÓÐÐÐÖÖÖÖÖÖµµµºººØØØÕÕÕÐÐÐÔÔÔÕÕÕÑÑÑãã㈈ˆ£££ßààÜØÖo„‹u’œ—§¬B?>º·¶«¨§´´´×××ÔÔÔ½½½ÃÃÃÕÕÕÓÓÓÐÐÐ×××ËË˾¾¾¾¾¾ÎÎÎ×××ÏÏÏÔÔÔÕÕÕÔÔÔÚÚÚ½½½PPPÎÎÎÖÖÖÛÛÛ4<@Gly£©«lx}˜¥©¶´´×רÉÉÉÇÇÇÛÛÛÆÆÆÊÊÊÔÔÔÐÐÐÔÔÔÁÁÁÖÖÖÒÒÒÂÂÂÕÕÕÏÏÏÔÔÔÕÕÕÕÕÕÔÔÔ×××âââÖÖÖÓÔÔÛØ×h—¨AOj“ #8>28¤«¸µ´ØÙÙØØØÚÚÚ×××ÚÚÚØØÙÖÖÖÒÒÓØØØÙÙÙרØ×ØØÙÙÙרØÑÑÑÔÔÔÕÕÕÕÕÕÕÕÕÔÔÔÒÒÒÕÕÕÔÔÕÙØ×²¶¸eŒ™/7:…“˜y|}YUTÀ¼»²³³ÃÃÃÁÁÁÁÁÁÁÂÂÁÁÁÆÃÃÀÀÀÅÂÂÄÃÂÅÃÂÄÂÂÆÃÂÃÂÁÆÃÂÆÅÅÕÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔ×××¹¸¸gŠ•~ˆ‹d†’k†r„Šj™³°¯¨¨¨§§§¦§§¦§§¥¦¦’ž¢°®®•£¨• ¤ž£š£¦‰›¡¡¦¨ƒ–µ¸¹ÙØØÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÕÕ×××··¸˜¡¤ƒ††• –˜†‰Š §©¯¯®¬¬¬ªªª±­¬°®­ª¬¬^ƒ žxŒ’}’t‰ƒ”k„•—b~ˆ£¨©ÚÙØÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔ×××·¸¸fŠ–w„c†‘j…Žq€…r‘œ³°¯ª««¯¬«x”œ •Žv}€…‰‰€ˆ‹€‡Š|†‰ƒ‰‹x„ˆˆŒrƒŸŸÙØØÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÕÕ××׸¸¸•Ÿ£„‡ˆ›ž•˜…‰‹›¤§¯¯®ª««¯­¬‹™ž`sy”“’–žs”Ÿ›¤}–Ÿp‘œˆœ£bŠ˜—£¨Wƒ“¯¶¹ÚÙØÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔ×××·¸¸i‹–x„f‡’l†Žr…t’œ³°¯ª««««¬—Ž‘‘W‡—‰’•x„…‡€„†~ƒ…‚…‡{‚……ˆˆu}€™š›ÙØØÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÕ×××···’ž¢ƒ†‡™Š“–„‰Š—¢¦³°¯“¡¥`‚Žv~€…™ ‡‘”mx|[~ŠjŠ”’˜r‹”…”™g†‘‘š]€Œ¨­¯ÚÙØÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÕÕ×××¹¹¹lŽšw…o—xŒ“s‚‡z— º´³³²²“—™‡Š‹l‘žw€ƒMx†d§­¯¤©«¡¨«¦«­ž§ªª­®™¤§¹»¼Ø××ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××¹¹¹¹²°Œ‹“œ yŽ•w…X‡—¥«­cŽgˆw…Š ¦‰ˆ‡š ¢¯®­ÎËËÕÔÔÕÔÓÓÒÒÕÓÒÔÓÓÖÔÓÎÎÎÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÕÕÖ××½º¹nŽ˜m}ƒi‰|•€‚Qu‚SZ?@6A BC7DEFGH     IJKLMNOL ;;"PQRSTRUVW; BXYZW [BY\]^_`aba ; cd;Yeafd2gYhHQJS[Wiej  _Jkbkkkkkkkkb_ljJmnYkY:;  RopkSA;YqarQdVgYeH psZ i tJaucHn[]RLvZnPMvwxvV2[;ypRB z{|S{xKpT{mw  ^F ,i}  _ka 2kkKJSFSKpwFmNG uKpuiM ;~cwSB}^J2n5[]Ru/vZ[I€STRrkrnk|9fkfv uQ ~g}QH^_\;kuZLIka\_JuHPP \ FKj9b+‚~ ƒ+kVnKp„… [†[BFkrv‡9J^:ˆxˆ  BiG„e‰kSSkŠeZ kB ;"!;;F^‹R SJJA €[^p " b‰ ZRIc ŠN "  ;WrŒkOrrOŒ+[;!!H ~ _kJkF :""eAGG(r  \n !  &44"-P  4)18)*F8!Ž" Žb1 F4_F$Ž "4( @ÕÕÕרØ×רØ××»»»«««±®­³°¯·¸¸ÍÍÍÚÚÚÃÀ¿~š¤¤ª¬¥¦¦¯¶¹LKK!lrtœ¦©«¨§:::\\\ßààÛØ×…”*BJ",13dŠ–ãã㊈‡l„Œs’•¤ªDDD¹´³´´´ÃÃÂRRR4<@Gly¢§¨my}ÈÅÃh—¨AOj“ #8>28”¡¥µ·¸d›/7:„”šy|}YUT‚‡‰e†’u…lŽ™’ž¢Šœ¢š£¦’š’—™„‰Š[†• žz“rŠ’•˜eˆ|•ž˜Št~~‰Œ{…‰ŠŒŒŒ™ž`t{“““z— „š¢l‹–z‚…™‘ŽW…•‹“–„…›œœ`‚Ž[~Šl‘žMx†t…‹n~„Qu‚?!@A'B#BCDC-;8D>EFGHIJJK!LM @H!@"'NCOPGQ>RG@SPBB>ELGDTUVNWXN"C9#HYZ!@"[V\]P^ZZ>ZGP_B>T]G7'7`PC/aY;K;?EaAZKJ@N&'FSbPc9- -#&SEJ@\ 9Md7GD Ae!N^fghP;?PA- D_OXHiP^dbjV   >U-H7H@/ Vik_dZ[YX 0( ;klQd' ((BC&m  ((((00(00(((((     ( 00 n) op Bq rZSrn%F%Vs 0( (   ( ÕÕÕÓÓÓÔÔÔÖÖÖÖÕÔÑÑÑßßßÝÝÝÀÀÀŸ¥¨»¹¸«««ÅÅÅzzz¸·¶§¬­7BFy„ª¬­ÅÄÄÎÎÎÂÂÂÒÒÒÆÆÆÇÇÇÜÜÜlllÀ¾½™¢¦>SZ?@ABCDE89FBƒ „…†~‡ˆ~ q**(0`€€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwx7wwwwwwxwwwwwwwwwwwwwwx‡wwwwwwwwwwww‡wwwwð‡÷x0‡‡wwww‡wwwwwwwwwwpwwƒ€8wwwww‡wwwwwxwwwø‡wwƒx@wwwww‡wwwwwwwwwx‡wx8w0wwwwwwwwwwwx‡www@wwx@3‡wwwwww‡wwwwwwwwwwwwøwƒwwwwwwwwwwwwwwwwwwx3ƒ€wwwwwwwwwwwwwwwwwwwˆ€ˆ€wwwwwwwwwwwwwwwwwwwxˆx‡wwwwwwwwwwwwwwwwwwws8ƒ8ƒwwwwwwwxwwwwwwwwwwwwˆsˆˆwwwwwswx‡ƒø78wwwwwwwxwxwwwwwws‡x‡7x‡‹wwwwwwxx¸ˆˆ‡wwwwˆˆˆ‹ˆ8ˆˆˆwwwwws8ˆ8ƒwwwˆ‡ˆˆˆ‡ˆx‡ˆwwwwwwxwxwwwxˆ‡7øƒxƒwwwwwwxˆˆˆˆ‡wwxƒwƒs‡ˆx7ˆwwwwwwsˆƒˆƒ‡wwˆs7ˆˆˆˆˆˆ‡‡wwwwwxxwwwˆwˆˆˆ‡‹x‡ƒwwwwwwxxˆˆ‡wx3ˆwˆƒs‡ˆx7ƒwwwwwws8ƒ73wwxƒ3ˆ8w‡‡wwxwwwwwwwx‡x‡wwx‡wƒ7wwwwwwwwwwwwwxwxƒ‡s8ˆw‡wwwwwwwwwwwwwwˆƒ8ƒ8ƒˆƒ8ˆwwwwwwwwwwwwwx8‡wˆƒ8ˆwxƒ‡wwwwwwwwwwwwwx‡sˆˆˆƒ‡ˆwwwwwwwwwwwwwwwwˆƒ‡8sw8ˆwwwwxwwwwwwwwwwwxˆø7swˆ‡wwwwwwwwwwwwwwww3ˆx‡xˆˆ8wwwwwxwwwwwwwwwwˆxˆˆˆˆ‡ˆwwwwww‡wwwwwwwwwwwsˆˆ‡wwwwwwwwwwwwwwwwwwwwƒww7wwwwwwwwwwwwwwwwwwwwwww‡wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww‡wwwwwwwwwwwwwwwwÿwwwwwwwwwwwwwwww4‡wwww€wwwwx‡wwwwwwwww‡÷www€ˆwwwwxwwwwwwwwwwswwwwwwwwwwwwwwwwwwwwx7wwwww€wwwwwwwwwwwwwww„wwwwˆwwwwx÷wwwwwwwwwˆ‡wwwwx‡wwwwxˆwwwwwwwwwwwwwwwwwwwwwww÷www( @€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ÷wwwwww÷÷wwwÿw÷wwww÷÷w÷w÷www‡w‡w÷w÷www÷wƒ7xwww÷ww÷÷wqƒ€ˆ‡wwwwww÷ø(÷wpww÷wwÿ‡÷ww€ˆww÷w÷w÷÷÷www€8€ˆww÷wwww÷÷÷ws7wwwwww÷w÷wwøˆu‡wwwwwwwwwwwxˆ8ˆwxw‡xxˆxwÿ÷wxxxx‡xˆˆsˆˆw÷x8ˆ8wsx8xˆxƒwwwxx‡‡wˆxsyxxwwÿxˆ8ˆwxˆˆxˆˆˆ÷÷wxˆxxx8x8ˆƒƒxwwxƒˆ‡wˆˆƒˆxxwwwwxxˆs‡x‡÷www÷÷xˆ8ƒƒˆ8‡ww÷÷w÷xˆxˆˆ7ˆ‡ww÷w÷ww‡ˆxxx‡‡wwww÷÷wx8ƒyˆ8‡wwwwwxˆxˆˆˆ‡xwwww÷w÷ÿwwwˆx‡ww÷wÿw÷x‡‡‡w‡wwwwww÷ww÷ww÷www÷÷÷÷wwwwÿw÷÷w÷÷w÷w÷ww÷ww÷ww÷÷w÷ø÷÷x÷÷øwwÿwƒww‡www‡÷w÷÷wh÷wÿøww÷w÷w‡wwww÷wÿw( €€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿwwwwww÷ww÷÷wxw8wwww÷øx‡÷w÷w‡w÷wwˆ‡w8xww÷ˆ‡xˆˆ‡÷wx‡ˆ‡8wwˆˆˆ‡wwÿw‡ƒ7w÷wwxxˆww÷÷x‡‡www÷www÷w÷÷÷ø÷wwwwwxwx‡÷wwwpuzzles-20170606.272beef/icons/towers.ico0000644000175000017500000006117613115373747017044 0ustar simonsimon 00 ¨%–  ¨>& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $æææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææåæåååååæåææææææææææææææææææææææææåååæææææææææææææææææææææææææææææææææææææææææææææææææææåååæææææææææææææææææææææææææææçççèèèææææææææææææææææææéçéîéîðêðîéîçæçæææææææææææææææææææææéééæææææææææææææææææææææææææææææææææææææææææææææææææææéééææææææææææææææææææææææææçççáááÞÞÞèèèææææææææææææçæçÜâÜÅÙŽֽÆÙÆáäáçæçæææææææææææææææçççÛÛÛåååææææææææææææææææææææææææææææææææææææææææææææææææÛÛÛæææææææææææææææææææææäääðð𸸸¤¤¤ôôôãããæææææææææèçèÔßÔ­Ï­ Ê ¯Ð¯ÞãÞèçèææææææææææææäääííí‹‹‹ÛÛÛçççååååååååååååååååååååååååååååååååååååååååååæææ‰‰‰åååææææææææææææææææææäääóó󸸸£££ôôôãããææææææææææææéçéñêñôëôñêñèçèæææææææææææææææäääííí‹‹‹áááíííêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêëë댌Œææææææææææææææææææææææææçççµµµ¤¤¤ôôôãããææææææææææææåæåäåäãåãäåäææææææææææææææææææãããñññxxxzzzŠŠŠ†††††††††††††††††††††††††††††††††††††††‡‡‡„„„fffåååæææææææææææææææãããòòò¬¬¬‡‡‡®®®ñññâââååååååååååååååååååååååååååååååååååååååååååãããììì‹‹‹äääðððîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîìììùùù±±±±±±ñññäääæææææææææåååëëëÓÓÓRRR®®®úúúêêêííííííííííííííííííííííííííííííííííííííííííëëë÷÷÷„„„¢¢¢±±±®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®®±±±¤¤¤iiiçççæææææææææææææææåååîîîJJJ‹‹‹ÚÚÚÇÇÇÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÈÈÈÒÒÒrrr£££°°°­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­«««µµµxxxÓÓÓëëëåååææææææåååêêêÒÒÒrrr,,,••••••rrr¿¿¿üüüñññóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóðððÿÿÿ˜˜˜ÏÏÏìììåååæææææææææãããóóóÐÐÐOOO‰‰‰™™™•••–––––––––––––––––––––––––––––––––––––––•••›››pppïïïáááäääääääääääääääääääääääääääääääääääääääáááïïïÏÏÏìììåååæææææææææäääíííÃÃÃbbbÉÉÉïïïæææççççççççççççççççççççççççççççççççççççççççççèèèãã㌌Œëëëåååæææææææææææææææææææææææææææææææææææææææãããòòò‘‘‘ÏÏÏìììåååæææææææææäääîîîÅÅÅ]]]ÇÇÇíííãããååååååååååååååååååååååååååååååååååååååååååçççÞÞÞ‰‰‰ëëëåååæææææææææäåäãåããåããåããåãåååææææææææææææãããòòò‘‘‘ÏÏÏìììåååæææææææææäääîîîÆÆÆ^^^ÈÈÈîîîäääææææææææææææææææææææææææææææææææææææææææææèèèßß߉‰‰ëëëåååææææææåæåñêñõìõõìõ÷í÷øíøîéîåæåæææææææææãããòòò‘‘‘ÏÏÏìììåååæææææææææäääîîîÆÆÆ^^^ÈÈÈîîîäääææææææææææææææææææåæåãåãåååæææææææææææææææèèèßß߉‰‰ëëëåååæææäåäíéír·r?£?B¤B9¡9//—Æ—ñêñäåäææææææãããòòò‘‘‘ÏÏÏìììåååæææææææææäääîîîÆÆÆ^^^ÈÈÈîîîäääæææææææææææææææåæåèçèôìôìéìåæåææææææææææææèèèßß߉‰‰ëëëåååæææãåãòëòL¦Ly•F¦F*›*—Æ—ñëñãåãææææææãããòòò‘‘‘ÏÏÏìììåååæææææææææäääîîîÆÆÆ^^^ÈÈÈîîîäääææææææææææææåæåèçèÚáڥ̥ÇÙÇêèêåæåæææææææææèèèßß߉‰‰ëëëåååæææåæåéçéÚáÚ>¢>Œ²Ò²ÿðÿéçéåæåæææææææææãããòòò‘‘‘ÏÏÏìììåååæææææææææäääîîîÆÆÆ^^^ÈÈÈîîîäääæææææææææçæççæçöíö½Õ½|o´oúîúâäâæææææææææèèèßß߉‰‰ëëëåååææææææäåäêèêèçèN¨Nƒ—Ç—ñêñäåäæææææææææãããòòò‘‘‘ÏÏÏìììåååæææææææææäääîîîÆÆÆ^^^ÈÈÈîîîäääæææãåãòëò¦Í¦)š))š)–‹½ñêñãåãææææææèèèßß߉‰‰ëëëåååæææææææææëèëéçéñëñI¦I†ÂØÂîéîäåäææææææãããòòò‘‘‘ÏÏÏìììåååæææææææææäääîîîÆÆÆ^^^ÈÈÈîîîäääæææâåâöíöÃZ®ZB¤Bˆ–›È›îéîäåäææææææèèèßß߉‰‰ëëëåååææææææçççÂØÂàäàÿðÿwºw}‘‘ôìôãåãææææææãããòòò‘‘‘ÏÏÏìììåååæææææææææäääîîîÆÆÆ^^^ÈÈÈîîîäääæææåæåéçéÛâÛ• Ê ØâØwºwÿñÿáäáæææææææææèèèßß߉‰‰ëëëåååæææãåãôëôC¡C7 7… Œ ¿×¿îéîäåäææææææãããòòò‘‘‘ÏÏÏìììåååæææææææææäääîîîÆÆÆ^^^ÈÈÈîîîäääææææææãåãõìõ¤Ë¤•Æ•…i´iôìôãåãæææææææææèèèßß߉‰‰ëëëåååæææåæåëèë·Ó·f³fK¨Kc±cºÔºîéîäåäæææææææææãããòòò‘‘‘ÏÏÏìììåååæææææææææäääîîîÆÆÆ^^^ÈÈÈîîîäääæææææææææâåâöíöc±c†j´jöíöâåâæææææææææèèèßß߉‰‰ëëëåååææææææåæåïêïøíøùîù÷í÷îéîåååææææææææææææãããòòò‘‘‘ÏÏÏìììåååæææææææææäääîîîÆÆÆ^^^ÈÈÈîîîäääæææææææææåæåèçèáäá.›.‚p·pöìöâåâæææææææææèèèßß߉‰‰ëëëåååæææææææææäåäâåââåââåâäåäæææææææææææææææãããòòò‘‘‘ÏÏÏìììåååæææææææææäääîîîÆÆÆ^^^ÈÈÈîîîäääææææææææææææåååéçéÞãÞÊÛÊÚáÚèçèææææææææææææèèèßß߉‰‰ëëëåååæææææææææææææææææææææææææææææææææææææææãããòòò‘‘‘ÏÏÏìììåååæææææææææäääîîîÆÆÆ^^^ÈÈÈîîîäääæææææææææææææææåæåéçéíéíéçéæææææææææææææææèèèààà‰‰‰ëëëäääæææææææææææææææææææææææææææææææææææææææãããñññ’’’ÐÐÐìììåååæææææææææäääíííÃÃÃ]]]ÈÈÈîîîäääææææææææææææææææææåæåäåäåæåæææææææææææææææèèèßßßŠŠŠíííçççèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèåååôôô’’’ÏÏÏìììåååæææææææææãããóóóÑÑÑcccÅÅÅëëëâââäääääääääääääääääääääääääääääääääääääääãããääääääfff‡‡‡ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ‰‰‰yyyÝÝÝèèèæææææææææåååëëëÎÎÎ{{{BBBÒÒÒûûûñññóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóóõõõííí‹‹‹èèèãããääääääääääääääääääääääääääääääääääääääääääãããêêêçççæææææææææææææææèèèÛÛÛÚÚÚddd†††±±±¨¨¨©©©©©©¨¨¨¦¦¦¦¦¦¦¦¦¨¨¨©©©©©©©©©©©©©©©©©©©©©«««   |||ïïïåååæææçççæææåååäääåååæææççççççççççççççççççæææçççåååæææææææææææææææææææææèèèïïïÞÞÞ°°°²²²±±±±±±°°°¸¸¸¿¿¿¼¼¼¿¿¿···°°°±±±±±±±±±±±±±±±±±±²²²®®®ÊÊÊêêêåååææææææçççðððóóóìììäääæææææææææææææææææææææææææææææææææææææææææææææææææææåååèèèòòòòòòòòòñññöööÔÔÔ···ÃÃö¶¶ÙÙÙöööñññòòòòòòòòòòòòòòòòòòóóóìììåååææææææçççààà»»»­­­ÊÊÊîîîææææææææææææææææææææææææææææææææææææææææææææææææææææææåååäääääääääáááñññ‚‚‚ •••ñññáááäääääääääääääääääääääåååææææææãããôôô”””!!!~~~ïïïäääæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææãããòòò«««¿¿¿ðððäääæææææææææææææææææææææææææææææææææåååéééÐÐÐÝÝÝÿÿÿ???!!!éééæææåååææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææãããñññ¨¨¨¾¾¾ðððäääææææææææææææææææææææææææææææææææææææäääòòò°°°LLLðððäääæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææâââúúú···¾¾¾ïïïäääææææææææææææææææææææææææææææææææææææäääîîîÄÄÄsssqqqòòòäääææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææãããñññ‹‹‹,,,¹¹¹ðððäääæææææææææææææææææææææææææææææææææåååíííÆÆÆUUUjjjPPPòòòäääææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææåååìì캺ºrrruuuÒÒÒêêêåååæææææææææææææææææææææææææææææææææåååèèèÚÚÚccc‡‡‡ÛÛÛéééåååæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææåååîîîúúúøøøéééåååææææææææææææææææææææææææææææææææææææææææææèèèøøøûûûöööéééåååæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææåååââââââåååææææææææææææææææææææææææææææææææææææææææææææææææãããââââââåååæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææ( @ ææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææåæååæååæåæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææççççççææææææææææææêèêíéíêçêæææææææææææææææçççæææææææææææææææææææææææææææææææææççççççæææææææææçççâââãããçççæææææææææÖàÖÇÚÇ×à×çççææææææææææææàààääääääääääääääääääääääääääääääåååáááâââçççæææäääïïï¾¾¾ÂÂÂîîîåååæææçæçÌÜ̵ҵÎÜÎèçèææææææåååééé«««ìììðððïïïïïïïïïïïïïïïïïïïïïîîîøøøÊÊʾ¾¾îîîäääåååííí¼¼¼ÁÁÁîîîäääææææææëèëðêðëèëåæåææææææäääììì•••¨¨¨±±±¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®¶¶¶¹¹¹ðððäääêêêÙÙÙ†††ÊÊÊîîîæææèèèèèèçççæçæçççèèèèèèèèèçççììì   ÊÊÊÑÑÑÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÒÒÒÇÇÇ£££éééååååååíííhhh»»»ëëëàààââââââââââââââââââââââââáááèèè•••¦¦¦«««ªªªªªªªªªªªªªªªªªªªªªªªª©©©°°°~~~ÑÑÑìììåååììì}}}\\\›››’’’’’’’’’’’’’’’’’’’’’’’’‘‘‘•••uuuÐÐÐêêêäääåååååååååååååååååååååãããîîî···ÊÊÊíííäääïïïÅÅÅkkk¹¹¹´´´µµµµµµµµµµµµµµµµµµµµµµµµ´´´¼¼¼ššš¯¯¯ñññäääæææåæåäåääåäåæåææææææäääððð´´´ÊÊÊíííäääîîî¼¼¼„„„ôôôíííîîîîîîîîîîîîîîîîîîîîîîîîíííôôôÒÒÒµµµïïïäääæææìèìîéîðêðíéíææææææäääððð´´´ÊÊÊíííäääîîî¾¾¾êêêãããääääääääääääâãâáãáääääääãããëëëÈÈȳ³³ðððäääæææÎÝÎÅÙźպÇÙÇçæçæææäääððð´´´ÊÊÊíííäääîîî¾¾¾ìììåååææææææäåäáäáïêïñêñãåãæææåååíííÊÊÊ´´´ïðïâãâîêî7ž7‰..N©Néçéæææäääððð´´´ÊÊÊíííäääîîî¾¾¾ìììåååæææåæåðêðÿñÿ²Ñ²ªÎªõìõãåãåååíííÊÊÊ´´´ðððâãâíéí¸Ó¸“¾ôëôäåäæææäääððð´´´ÊÊÊíííäääîîî¾¾¾ìììååååæåéçé Ê „¿„.˜.‘ÊÛÊëèëãäãíííÊÊÊ´´´ðððääääåäþðþÓÞÓ”ŽÃŽóëóãåãäääððð´´´ÊÊÊíííäääîîî¾¾¾ìììåååäåäðëð8œ8A¢A*›*‘¹Ô¹îéîãäãíííÊÊÊ´´´ðððäääæææ¯Ð¯çççQ§Q0—0òìòäåääääððð´´´ÊÊÊíííäääîîî¾¾¾ìììåååäåäóëó—Æ—q·qkµkJ¨JÿñÿáäáåååíííÊÊÊ´´´ïðïãããíéí[®[!—!”—Ç—ðêðäåääääððð´´´ÊÊÊíííäääîîî¾¾¾ìììåååæææãåãõìõc²c„Q§QóìóãåãåååíííÊÊÊ´´´ðððäääçæçêèêÕßÕàäàðêðåæåæææäääððð´´´ÊÊÊíííäääîîî¾¾¾ìììåååæææåæåêçêÞãÞC¥C½ñêñäåäåååíííÊÊʳ³³îîîãããåååäåäéçéçæçãäãååååååãããîîî³³³ÊÊÊíííäääîîî¼¼¼ìììåååææææææåæåèçèöíöïéïåæåæææåååíííÊÊʹ¹¹÷÷÷ëëëííííííìíìííííííííííííëëë÷÷÷ºººÊÊÊíííäääïïïÆÆÆ‚‚‚êêêãããäääääääääãäãáãáâãâääääääãããêêêÊÊÊÏÏÏÅÅÅÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÅÅÅÏÏÏËËËíííåååêêꘘ˜wwwøøøîîîïïïïïïïïïïïïïïïïïïïïïïïïîîîöööÕÕÕ’’’½½½µµµ¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶···âââççççççäääÂÂÂxxx¯¯¯¯¯¯®®®±±±±±±²²²°°°®®®¯¯¯¯¯¯®®®´´´™™™½½½ùùùíííïïïóóóñññíííððððððððððððððððððçççæææææææææðððáááÎÎÎÑÑÑÒÒÒÇÇÇÇÇÇÄÄÄÍÍÍÑÑÑÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑâââåååäääæææ×××ÝÝÝïïïãããäääääääääääääääææææææææææææäääçççìììéééõõõ———###AAAÒÒÒñññêêêëëëëëëëëëëëëçççäääïïﺺºQQQ<<<‹‹‹ñññäääææææææææææææææææææææææææææææææååååååãããòòò>>>“““õõõâââåååååååååååååååææææææçççÞÞÞÒÒÒYYYSSSõõõãããææææææææææææææææææææææææææææææææææææãããôôôCCC–––öööãããæææææææææææææææææææææäääïïï©©©ƒƒƒõõõãããæææææææææææææææææææææææææææææææææäääïïï”””¤¤¤óóóãããææææææææææææææææææåååêêêÑÑÑggg...}}}ôôôãããææææææææææææææææææææææææææææææææææææèèèÛÛÛÍÍÍáááçççææææææææææææææææææææææææææææææÉÉÉÎÎÎíííæææææææææææææææææææææææææææææææææææææææææææææéééìììçççæææææææææææææææææææææææææææææææææììììììåååææææææææææææææææææææææææææææææææææææææææææææææææåååææææææææææææææææææææææææææææææææææææååååååæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææ(  æææçççææææææéçéçççæææææææææåååååååååååååååæææææææææãããææææææÙàÙàãàçæçåååæææêêêêêêêêêêêêêêêåååæææäääÉÉÉééééèéØâØáåáëêëããã¾¾¾ÕÕÕÒÒÒÒÒÒÓÓÓÑÑÑ¿¿¿èèèØØØ£££áááÛÛÛàÞàÞÝÞÝÞÝ××תªª»»»¹¹¹¸¹¸¹¹¹»»»ªªªÛÛÛèè褤¤­­­ª«ª©ª©¬¬¬§§§ªªªäääãáãéäéãáãåååÍÍÍÔÔÔëëë®®®ÞÞÞêêêæçæîêîçççéééÈÈÈèçèÚâÚÅÚÅØáØïíïÑÑÑÔÔÔêêê©©©ÜÜÜéèéëèëÉÚÉäåäèçèÃÅÃîèî°Ñ°8 8ÆØÆðíðÎÏÎÔÔÔêêꪪªÞÝÞåçåq·q4ž4ÍÜÍíêíÄÅÄäääåæåi´iÈùðùÍÏÍÔÔÔêêꩪ©ÛÜÛðëð‡À‡? ?åååèèèÄÅÄêæêÅÙÅ€½€ÉÚÉðíðÏÐÏÔÔÔëëë­­­ÝÝÝíêíßãߩΩèçèèèèÇÇÇåååìéìõíõìéìëìëÑÑÑÔÔÔèè蟟ŸÚÚÚæçæéèéðèðâââçæç¸¸¸ÁÁÁÉÉÉÄÆÄÄÄÄÇÇǾ¾¾ÛÛÛçççÂÂÂÂÂÂÀÀÀ±²±ÀÂÀÇÇÇÄÄÄÆÆÆèèèÖÖÖÝÝÝæææäääæææçççæææëëëïïïÎÎÎaaaãããêêêèèèèèèííí®®®iiièèèçççæææææææææäääìììÆÆÆvvvïïïãããåååãããððð®®®]]]ëëëåååææææææææææææèèèÜÜÜ×××çççæææææææææèèè×××ÚÚÚèèèææææææææææææææææææèèèêêêæææææææææææææææêêêéééææææææææææææ(0` æææèçèíéíòëòèèèãããßßßÞãÞÅÙŽսãåãÛÛÛòòò¶¶¶¦¦¦ÔßÔ­Ï­›È›²Ò²ìì쉉‰   ôôôëëëäääuuuzzz†††fff®®®ûûû±±±ÒÒÒRRRiiiJJJÆÆÆÊÊÊppp©©©,,,”””’’’ÃÃÃüüü™™™cccÎÎÎ^^^ÈÈÈôëôõìõùîùp·p?£?B¤B9¡9.›.•Æ•îîîL¦Ly•I¦I*›*ÚáڤˤÇÙÇ Œ ÿñÿ†ñëñ¦Í¦)š)ˆŒ½ÂØÂÂZ®Zúîúwºw Ê çççC¡CÏÏÏi´i·Ó·c±cK¨Kj´jÿðÿÊÛʇ‡‡bbbBBB|||¸¸¸¼¼¼ÔÔÔ!!!LLLUUU                 !" #$ %&&&&&&&&&&&&&&&!'( !!')*+++++,,++*'-. .*! !"/******/*****/**/0'+! -1%+2%34  ! %3&5567 +2%3&89:;<=  +2>%3&5 ?@ABC=  ! %3&DEFD9GH +2%3&6 I87 ?J= +2K%3& LMMANOP BJQ +! 43& 6RST:NAQ UVIR5  +2%3&DAWDIVH X5YZ;JG  ,[%3& 6LZ=J\5 ]^_^] +[%34 6^`Ja6 6b6 ,[%34X X +!-34>XXXXXXXX+2 !e%  dddddX2f!        1 (((((((((((((g hiii &  jh-h  h& 0klk*+mno0 (li !.fnli  pm+  li%'m'  )lh %q#lp h'! 0 .( @æææãäãéééïéïêçêãããÕßÕÇÚÇÖàÖÞãÞäääïïï½½½ÁÁÁÌÜ̵ҵ«««ëëëïðïòìòôôôÏÏϺººåæå”””¨¨¨²²²®®®¯¯¯···‹‹‹ÛÛÛ†††ÉÉÉ£££ÑÑÑÐÐÐhhh¦¦¦ìèì}}}\\\“““uuuµµµóëóÅÅÅkkkšššòòòçæçñêñ¼¼¼„„„ÒÒÒâââ~~~ÇÇdz³³ÅÙŹԹÊÛʹ¹¹q·qËËË7ž7‰..N©Nÿñÿ²Ñ²ªÎªõìõ“½áááôëô¾¾¾ Ê ¾.˜.””ŽÃŽ8œ8A¢A*›*‘¯Ð¯Q§Q0—0—Æ—kµkJ¨J[®[!—!—Ç—c²c„C¥Cƒƒƒ˜˜˜ÕÕÕùùù×××ÞÞÞ###AAAQQQ>>>YYYCCCggg...        !"!#$#######!" % &'# ()*+,,,,,,,,,-# .! /01....... 233! 45673 38. (/ .! 9 : ;<=>? ! 9@A/ B< CDEF3.!56:/GHIJ!< KL/ .! MNO:PQRS? B.3GTUJ3! MNO:VWXY !<3Z[\.!  '/]A^_G B<`aTb .! ' Jcd[!<  3.!  ' eQ/ !. 3!  ' J!   ! ;f  !+;;;;;;;!;#+! g-3  h,6.......... -g i 3 33 3##;; ####jk  lm#3  no33o,k#pnq r7 s&3#tu'3!  ( æææçççéçéåååãããÙàÙàãàçæçêêêäääÉÉÉééééèéØâØáåáëêë¾¾¾ÕÕÕÒÒÒÓÓÓÑÑÑ¿¿¿èèèØØØ£££áááÛÛÛàÞàÞÝÞÝÞÝ××תªª»»»¹¹¹¸¹¸¤¤¤­­­ª«ª©ª©¬¬¬§§§ãáãéäéÍÍÍÔÔÔëëë®®®ÞÞÞæçæîêîÈÈÈèçèÚâÚÅÚÅØáØïíï©©©ÜÜÜëèëÉÚÉäåäÃÅÃîèî°Ñ°8 8ÆØÆðíðÎÏÎåçåq·q4ž4ÍÜÍíêíÄÅÄåæåi´iÈùðùÍÏÍÛÜÛðëð‡À‡? ?êæêÅÙÅ€½€ÏÐÏÝÝÝßãߩΩÇÇÇìéìõíõëì럟ŸÚÚÚðèðââ⸸¸ÁÁÁÄÆÄÄÄÄÂÂÂÀÀÀ±²±ÀÂÀÆÆÆÖÖÖïïïÎÎÎaaaíííiiiìììvvvððð]]]  !"! #$%&'() *+*,-./012 345678-9: ;<=4>?@ABCD-EFGHIJ KLMNO-'PQRSJTUV& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $ææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææåååæææææææææææææææææææææåååäæååæååæååæååæååæååæåäåååæååæååæååæååæååæåäæååååæææææææææææææææææææææåååæææææææææææææææãããäääæææææææææææææææææææææçææìéëæææææææææææææææææææææìéëíäéìäéìäéìäéìäéìäéìåéîèììäéìåéìäéìäéìäéìäéíåêëéêåæåæææææææææææææææçççéééææææææææææææèèèòòòîîîåååæææææææææææææææçåæâèäÇØÎçäææææææææææææææææèåçÈ×ÎÄîÕÇîÖÆîÖÆîÖÆîÖÆîÖÅìÕ½ÚÈÇïׯíÖÆîÖÆîÖÆîÖÇï×ÂëÓÎ×ÒéèéåæåæææææææææçççáááÖÖÖèèèååååååèèèÜÜÜ£££ºººéééææææææææææææåææêäç×íทéàåæçææææææææææäæåíäé„¶˜sÿ­|ÿ±zÿ°zÿ°zÿ°{ÿ±xú¬\Á…|ÿ³zþ¯zÿ°zÿ°zÿ°}ÿ³mö¤˜µ¤ñëïãåäæææææææææêêêÖÖÖ³³³îîîäääæææäääòòò^^^   òòòäääæææææææææåææéäçÙíá…¸šèàåæçææææææææææäæåíä釷š{ÿ°ƒþ´ÿ´ÿ´ÿ´‚ÿµú°bÁˆƒÿ¶þ³ÿ´ÿ´þ´„ÿ¶tö¨›¶¦ñëîäåäæææææææææêêê×××´´´îîîäääåååçççãããKKKµµµòòòäääæææææææææåææéäçØíჷ—æßããæäãääãääãääâåãêãç…µ˜xÿ®ý²ý²ý²ý²€þ³|ø®`¿†ÿ´ü±ý²ý²ý²‚ÿ´rô¦˜´£îéìáãâãääãääãäãçèèÔÕÔ³³³îîîäääåååêêêÓÓÓˆˆˆÕÕÕêêêåååæææææææææåææéäçØíᇺôèïñîðñíïðìïñíïðíïøë󌹟}ÿ¶†ÿº„ÿ¹„ÿ¹„ÿ¹…ÿº‚úµdÁŒ†ÿ¼„þ¸„ÿ¹„ÿ¹„ÿ¹ˆÿ¼wõ­¡¹«ýòøïìíñíïñíïñìïõñóâÝ൴µíííäääæææåååêêêöööéééåååææææææææææææåææéæèÚæßj‘z¥³ª¥¸­¦¸­ª½­¦¸­¤·¬ª¶¯cu`ÉŠeÇŒdÇŒdÇŒdÇŒeÈbÉL—jfËŽdÇ‹dÇŒdÇŒdÇŒfÉŽ[À„p}­»³¤¶«¥·­¥·­¥·¬©»°–¨ª¬«ðïðäääææææææåååãããåååææææææææææææææææææäæåïæë†©”fìœsð¤më¡]Ùœlê¡qï£oî¢W³|wí§wí¦wí¦wí¦wí¦wî§tè£Z³~yñ©vì¦wí¦wí¦wí¦xï¨rãŸW¶}sõ§oí¢pï£pï£pî£tò§`ß“¢µ©òíðãääæææææææææãããäääææææææææææææææææææäåäðèí‘·¡xû¯Šÿ¹xí¹f¨p㸉ÿ¸‚ýµcÀ‰‚ÿ¶‚ÿ¶‚ÿ¶‚ÿ¶‚ÿ¶ƒÿ·€ú³bÁŠ„ÿ¹‚þµ‚ÿ¶‚ÿ¶‚ÿ¶„ÿ¸}ô®dÃŒ‡ÿ¼ƒý¶„ÿ·„ÿ·„ÿ·ˆÿ»tï§¥·¬ñíïäääææææææçççòòòîîîåååæææææææææææææææäæåïè쎵yû±ˆÿºcç–€[[à‘†ÿ¸ƒý¸`¿†€ÿ³€þ³€þ³€þ³€þ³€ÿ´}ù¯`À‡‚ÿµþ²€þ³€þ³€þ²ÿµzô«bɃÿ·ý²€þ³€þ³€þ²ƒÿ¶p·¬ñíïãääåååëëëÏÏÏYYY†††ëëëåååææææææææææææäæåîçꕹ¦Pæw¿¸ ·¸ ½SätfÃþ±€ÿ³€ÿ³€ÿ³€ÿ³ÿ´}ú¯aÁ‡‚ÿ¶€þ²€ÿ³€ÿ³€ÿ³ÿµ{ô«bɃÿ¸ý²€ÿ³€ÿ³€ÿ³„ÿ·p·¬ñíïãääæææãããõõõbbb¤¤¤òòòäääææææææææææææäæåíæé˜»«7ÖS¬´³´¬7ÓMiÅ“~þ°€ÿ³€ÿ³€ÿ³€ÿ³ÿ´}ú¯aÁ‡‚ÿ¶€þ²€ÿ³€ÿ³€ÿ³ÿµ{ô«bɃÿ¸ý²€ÿ³€ÿ³€ÿ³„ÿ·p·¬ñíïãääåååèèèÞÞÞDDDµµµñññäääææææææææææææäæåîçë‘¶¢hò˜²­®­®jð•dÁŒ~ý±ý²ý²ý²ý²€ÿ³}ø®`¿†ÿµü±ý²ý²ý²ÿ´zóªaˆƒÿ·~ü±ý²ý²ý²ƒÿ¶p·«ñíïãääåååêêêÖÖÖ˜˜˜ÙÙÙéééåååææææææææææææãåäñèí”·£zý±:ÚP!Ì/$Í2"Ì03ÖGþ´dÀ‹ƒÿ¸ƒÿ¸ƒÿ¸ƒÿ¸ƒÿ¸„ÿ¹ú´cÁ‹†ÿ»ƒþ·„ÿ¸„ÿ¸ƒÿ¸…ÿº~ô°eÇÿ½ƒý·„ÿ¸„ÿ¸ƒÿ¸‡ÿ¼t﨤·¬ñíïäääæææåååéééõõõéééåååææææææææææææææææççåãägw\Á…iÈ’gÆfÆgÆhÇ‘cÄ‹I“gcĉdĉcĉdĉcĉdÆŠ`À†J”hdÆ‹bÉbÉbÉbÉcÆ‹^»ƒK•ieÉaˆbÉbÉbÉfÇR´zŸ®¥òïñãääææææææåååãããåååæææææææææææææææåææèåçÝëâ^¸‚wï§zôªyó©yóªyóªyó©zóª\·€xò«tï¬uñ¬uð¬uð¬tñ­vî¨]¸|÷®zòªzó«zó«zó«{ö­ué¤]ºƒ}ú¯yòªzó«zó«zó«~÷¯k䛣µªñíðãääæææææææææäääåååæææææææææææææææåææèåæßìäf¿‹~û±‚ÿ¶ÿµÿµÿµÿµþµcÁˆ{ü·ÃÊ »Ì¾Ë ºÍ ÉÉ}ù²bÁ‰ƒÿ¸þ´ÿµÿµÿµƒÿ·|ô­cÊ…ÿºý´ÿµÿµÿµ…ÿ¹r磻·¬ñíïãääææææææåååíííéééåååææææææææææææåææèåçÞìäe¿‰|û¯ÿ´€ÿ³€ÿ³€ÿ³€ÿ³€þ³^¾‡ˆÿ±@×À¬Î³Ì¬ÎLß¿†þ®_¿‡‚ÿ¶þ²€ÿ³€ÿ³€ÿ³ÿµzô«bɃÿ¸ý²€ÿ³€ÿ³€þ²„ÿ·p·¬ñíïãääåååëëëÏÏÏMMMìììåååæææææææææåææèåçßìäe¿‰}û¯ÿ´€ÿ³€ÿ³€ÿ³€ÿ³€ÿ³`¿‡ƒÿ³xù´ºÊ°Í¾Èþ´~ú¯`À‡‚ÿ¶€þ²€ÿ³€ÿ³€ÿ³ÿµ{ô«bɃÿ¸ý²€ÿ³€ÿ³€ÿ³„ÿ·p·¬ñíïãääæææãããøøøhhh©©©òòòäääæææææææææåææèåçßìäe¿‰}û¯ÿ´€ÿ³€ÿ³€ÿ³€ÿ³€ÿ³`À‡~þ´‰ÿ±DÚ¿¨ÐPὉÿ²{ù°aÁ‡‚ÿ¶€þ²€ÿ³€ÿ³€ÿ³ÿµ{ô«bɃÿ¸ý²€ÿ³€ÿ³€ÿ³„ÿ·p·¬ñíïãääåååéééÚÚÚ>>>µµµñññäääæææææææææåææèåçÞìäd¿‰|ú¯€ÿ³þ²þ²þ²þ²þ²`¿†þ³ƒÿ²söµ ÄÅzú³‚ÿ³}ù¯`À‡ÿµý²þ²þ²þ²ÿ´zó«aˆƒÿ·ü±þ²þ²ý²ƒÿ¶p·¬ñíïãääåååéééØØØ¨¨¨ÜÜÜèèèåååæææææææææåææèåæßìäf¿‹û²ƒÿ·‚ÿ¶‚ÿ¶‚ÿ¶‚ÿ¶‚ÿ¶bÀ‰‚ÿ¶‚ÿ¶‚ÿ¶zû·ƒÿ¶ƒÿ·€ú²bÁŠ„ÿ¹‚þµ‚ÿ¶‚ÿ¶‚ÿ¶„ÿ¸}ô®dˆÿ»ýµ‚ÿ¶‚ÿ¶‚ÿ¶†ÿºs捻·¬ñíïãääæææåååéééóóóèèèæææææææææææææææåæåéæèÛåßN“j^½„bˆaÁ‡aÁ‡aÁ‡aÁ‡aÁ‡I‘faÁˆ`À‡bˆjˉaˆaˆ_½…I’fbĉ`À‡aÁ‡aÁ‡aÁ‡bÉ]¹‚J“hcÆ‹`À‡aÁ‡aÁ‡aÀ‡dÅ‹Q±xŸ®¥òïñãääæææææææææãããåååæææææææææææææææåææèåçÞëãc»†zõ«~ú°}ù¯}ù¯}ù¯}ù¯}ù¯^»„}ù¯~û®uð«WÎ¥xô¬~û¯zô«^¼„ý²}ø®}ù¯}ù¯}ù¯~ü±xï§`¿†€ÿ´|ø®}ù¯}ù¯}ù¯ý³m꟤¶«ñíðãääææææææçççæææçççæææææææææææææææåææèåçßìäe¿Š}û°‚ÿµÿ´ÿ´ÿ´ÿ´ÿ´aÀ‡þ´‰ÿ¹m߸[¥xíº‡ÿ¹}ù°aÁˆƒÿ·€þ³ÿ´ÿ´ÿ´‚ÿ¶{ô¬bÊ„ÿ¹€ý³ÿ´ÿ´€ÿ´„ÿ¸q襤·¬ñíïãääæææçççäääæææäääåååææææææææææææåææèåçßìäe¿‰}û¯ÿ´€ÿ³€ÿ³€ÿ³€ÿ³€ÿ³`À‡þ¶{ý¨MÚyŽAVâ|þ«ù³`Á‡‚ÿ¶þ²€ÿ³€ÿ³€ÿ³ÿµ{ô«bɃÿ¸ý²€ÿ³€ÿ³€þ³„ÿ·p·¬ñíïãääåååëëëÑÑÑDDD}}}íííåååæææææææææåææèåçßìäe¿‰}û¯ÿ´€ÿ³€ÿ³€ÿ³€ÿ³~þ°hÄ‘EÜa³´¸³µMÝlhÅ‘€ÿ³€þ²€ÿ³€ÿ³€ÿ³ÿµ{ô«bɃÿ¸ý²€ÿ³€ÿ³€ÿ³„ÿ·p·¬ñíïãääæææâââúúúlll­­­óóóäääæææææææææåææèåçßìäe¿‰}û¯ÿ´€ÿ³€ÿ³€ÿ³€ÿ³~þ°iÅ’=×U®µ³µ°FÙbiÆ“€ÿ³€þ²€ÿ³€ÿ³€ÿ³ÿµ{ô«bɃÿ¸ý²€ÿ³€ÿ³€ÿ³„ÿ·p·¬ñíïãääåååééé×××999µµµñññäääæææææææææåææèåçÞìäe¿‰|û¯ÿ´€ÿ³€ÿ³€ÿ³€ÿ³þ±eÂoô›¯­®¬µ uó£c‹ÿµþ²€ÿ³€ÿ³€ÿ³ÿµzô«bɃÿ¸ý²€ÿ³€ÿ³€þ³„ÿ·p·¬ñíïãääæææèèèÛÛÛ···ßßßèèèææææææææææææåææèåçßìäe¿Š}û°€ÿµÿ´ÿ´ÿ´ÿ´€ÿ³aÀ‡ÿ²BÛ\3ÑG2ÐH2ÑFIàeû²aÀ‡‚ÿ¶þ³ÿ´ÿ´ÿ´ÿ¶{ô¬bÉ„ÿ¸€þ²€þ³þ³€ÿ³„ÿ·q襤·¬ñíïãääæææåååèèèñññèèèæææææææææææææææåæåéæèÛåßN’i^¼ƒfće†e†e†eÆaÀ†HeaÀˆhÄ‘kÇ“qÏ”jÆ“hÅ‘_¼„H‘fcĈeÂ…e†e†e†fŇ\¸J“gcÅŠ_¾†cćhʈ`¿†dÄŠQ°wŸ®¥òïñãääæææææææææäääææææææææææææææææææåææèåçÞìäe¿‰yø¯ló·mó¶ló¶mó¶kò¶{û³aÀ†þ²ÿ¯sò¬NƤwö¬ÿ°|ø¯bÁ‡|ÿ¶jñ¶mó¶ló¶ló¶nõ¸yò«bÈ‚ÿ·ÿ°mé­Sʧ~ý°ƒÿµp·¬ñíïãääææææææçççéééåååæææææææææææææææåææèåçÞìäe¿‰}û¯ÃȰ͵̱;É|ü´aÀ†ý³Šÿºm߸X£x캈ÿº|ø¯c‡xý¸ ¸É²ÍµÌ¯Í&ÊÇ~÷«aÉ‚ÿ¸Žÿ»W´ b¤†ÿ¼ˆÿ»p·¬ñíïãääæææçççâââØØØíííæææææææææææææææåææèåçßìäc¾Š…ÿ®W漯͵ˮÎMཉÿ±_¿ˆ€ý³søžF×m•4NÞttú¡~ù±_Àˆ‹ÿ´BØ¿®ÎµË°Íbî»øªbË€ÿ´p÷™5È_š8[é€yü§r捻·«ñíïãäääääîîî¹¹¹]]]{{{ïïïäääæææææææææåææèåçÞìäe¿‰|û¯ƒÿ´ÂǮξÈ~ý³þ°hÄ’@ÙY¯²¸²±HÚehÅ“‚ÿ³wø´ºÊ®Î&ÈŇÿ´xóªgÆ‘0ÔC­³·±·NÛs«»µðìíãääæææåååïïïvvvXXXóóóäääæææææææææåææèåçßìäe¿‰{ú°‰ÿ²X滩ÏOཉÿ±|ý±hÄ’BÚ\¯µ³µ±JÛhiÅ’~ÿ´‰ÿ°CÙ¿«Ïc칈ÿ´xóªhÇ‘1ÕE®µ³´¶PÜvª»´ðìíãääåååëëëÎÎÎSSSnnnóóóãããæææææææææåææèåçßìägÀ‹û±„ÿµ€üµ2ÐÄ{ù¶„ÿ´þ³gÃŽsõ ±®¯­ ¶ yô§fÃŒƒÿ·…ÿ³sõ·4ÑÄ„ÿ´ƒÿ·{ó«lÈ–eð‹ª¯¯«Â&wñª¥¸¬ñìïäåäæææèèèÜÜÜÀÀÀßßßçççææææææææææææåææèåçÞìã^¾…sù©wþ®wý¬wý¬wý¬vý­vý¬Y¾‚vý¬BÞc4ÕO5ÖP3ÕNHâkvù«Y¿‚xÿ¯vü¬wý¬wý¬wý¬xÿ®qò¥\Â…tÿª:ØX5ÖQ5ÖQ2ÔMUë|j¶ªòíðãääææææææèèèïïïèèèææææææææææææææææææèççßãà‡¤“Œ³œŽ¶žµžŽµžµžŽµžŽµž„¡Žµž•º¨—»«—»ª—»«•º¨´œ„¢Ž¶žŽµµžŽµžµžŽ¶žŒ²›„¢¸¡–º©—»ª—»ª—»«–»¨„¬”½Â¿íìíäåäæææææææææäääåååæææææææææææææææææææææçææñëîïèìïçìïçìïçìïçìïçìïçìñëïïçìíæêíæéíæéíæéíæêïèìñëïïçìïçìïçìïçìïçìïçìïèìñëïïçëíæéíæéíæéíæéîæêðéíëêëåååææææææææææææææææææææææææææææææææææææææææææäåääæåäæåäæåäæåäæåäæåäæåãåääæåäæåäæåäæåäæåäæåäæåãåääæåäæåäæåäæåäæåäæåäåäãåääæåäæåäæåäæåäæåäæåäåäåååæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææ( @ ææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææåæåæææææææææææææææåæååæååæååæååæååæååæååæååæååæååæåææææææææææææææææææææææææææææææææææææææææææçæçéèéææææææææææææèçèìæéëäèëåéëåéëåéìçêëåéëåéëåéëäèìæêçççææææææææææææèèèææææææåååæææèèèåååæææêçéÕäÛ¹ÏÂìèëååååååìêëÉÒ͔뷠ûÄ÷ÁžøÂœõÀŽÙ¬ŸúÃ÷Áž÷ÁŸüÄ—áµØ××éééåååæææåååÊÊÊçççäääððð®®®ðððäääìçêÍä֤Ųíèëâäãâäãìêì¼ÉÁmí |ÿ³yþ¯zÿ°wû¬eÓ‘{ÿ±yþ¯yþ®{ÿ³pßÐÐÐéêéãäääååãäã½¾¾çççãããôôô™™™õõõãããìçêÎä׭ɹùïôìéììéì÷ñõÅÎÉwí©ˆÿ¼„þ¸…ÿ¹ƒûµnÔ™†ÿº„þ¸„þ¸†ÿ¼{à¥ÚÖØôðòîêìïëíïëíÂÁÁæææåååéééÅÅÅÕÕÕéééåååìèêÐßÖŒ¬˜¿ÊĻ̾½Î¾¿ÌÅš°¢cËpßnÚ™nÜšlØ—[¶€oÞœnÚ™nÚ™páeÀ‰©¶®½ÍĹȿºÉÀµÆ¼­³¯êééååååååëëëèèèåååææææéçæÜâyÀ–sù¤aÕ¥VÉ£zû©cÎŽoÜ›zóªwî§xï¨vë¥cÆ‹yñ©wî§wí¦{ô«iÒ“hÙ–vô¨sî¤uï¦jï ‘Â¥ïæëäæååååîîîðððåååææææèççÞã‡Í¦ÿÂK›0¦Ž•ÿÅrÛ¡xì§…ÿ¹‚þµƒÿ·€û³lÓ—„ÿ¸‚þµþµ…ÿºsá w覆ÿºƒþ¶…ÿ·{ÿ²˜È¬îåêãåäììì´´´¬¬¬êêêåååæèæèßå~Ê™$Ð8 · ¶É+[Ñzî«ÿ´þ²€ÿ³~ú°jÓ”ÿµþ²ý²ƒÿ·qàt碂ÿ¶ý²‚þ´xÿ®–Ȫîåêâäãôôô˜˜˜‰‰‰ôôôãããæèæçÞä‚ΟÁ«®· ^Óƒ{ÿ¶€þ´ÿµû±kÓ•‚ÿ¶€þ´€þ³„ÿ¹qáŸu褃ÿ¸€þ³ƒÿµyÿ°—È«îåêâäãðððššš±±±ñññäääæèçæÜá‹ÎªHâj¿(À*=ØUqÚžsæ¡~ý²{ø¯|ù°{õ¬hÏ‘ü±}ù¯}ø®€ÿ³nÜšr⟀ÿ³}ø®ù°uúª•Æ©îåëäæååååèèèéééåååæææêééØÝÚa¯€oÛqמp×sÝ¡\¸cÄŠtÜ–rØ“sÚ”kÒ’X°|l×—jÔ•jÓ”mÙ™^»ƒaÁ‡mÙ˜jÓ”mÕ–aÒŽ·ŸïèìäæåæææçççæææææææææëçéÔâÚlÕ—ƒÿ·€þ³€þ³ƒÿ¹sÞoçª0ÕÊ+ÏÆ&ÍÉbë¹qÖ–‚ÿ¸‚þµþµ…ÿºsá v襅ÿº‚þµ„ÿ·zÿ²—È«îåêäæåæææáááâââææææææêçéÕâÚlÔ•ÿµý²ý±ƒÿ·mÛ›{ï¤-ÎǦϸÊuö±lÔ”€ÿµý²ý±ƒÿ·pàt碂ÿ¶ý²þ³xÿ®–Ȫîåêâäãñññ˜˜˜………ðððäääêçéÕâÚkÓ•ÿµý±ü±ƒÿ·mÛ›{î¤pö¹¬ÌMß½ˆÿ­gÑ”ÿ´ý²ü±ƒÿ·pàt梂ÿ¶ý±þ³wÿ®–Ǫîåêâäãôôô•••šššõõõãããêçéÕâÛnÕš…ÿ»ƒþ·ƒþ·‡ÿ¼rÝŸy쪊ÿºDÞÃyúº„ý´lÓ˜…ÿºƒþ·ƒþ·‡ÿ¼tá¢w视ÿ»ƒþ·…ÿ¸|ÿ´˜È¬îåêäåäêêê¾¾¾ÐÐÐêêêåååëèêÓߨ^ºƒqãŸpÞœoÝ›sä aÁ‡gΑqâŸyè›rámÛš]¹‚qážoÞœoÞœsä bÄŠfÊŽrã oÞœrßžgÝ–»¡ïçìäæååååìììéééåååæææëèéÔàÙcÊwî§ué¤ué£xð¨fËŽlØ—xï¦V¢oâ¤tè aˆwí¦ué¤ué£xð¨gΑkÕ•xï¨ué¤wê¥m韒À¥ïçëäæååååíííïïïåååæææêçéÕâÛnÕ™„ÿº‚þ¶‚þ¶†ÿ»pÝ~ì°ŒÿÁŽo貌ÿ¿kÓ—„ÿ¹‚þ¶‚þ¶†ÿ»sá¡w覅ÿº‚þ¶„ÿ·{ÿ²—Ȭîåêãåäëëë»»»´´´éééåååêçéÕâÚkÔ•ÿµý²ý±ÿµtà£PÕpÆ'´¾AÖZnÕ™€ÿ³ý²ý²ƒÿ·pàt碂ÿ¶ý²þ³xÿ®–Ȫîåêâäãôôô———†††ôôôãããêçéÕâÚlÕ–‚ÿ¶€þ³€þ²‚ÿ¶wâ§GÎc­²©,Ç>qØž€ÿ´€þ³€þ³„ÿ¸qážu裃ÿ·€þ³‚ÿ´xÿ¯—Ȫîåêâäãñññ–––­­­òòòäääêçéÕâÚkÓ”€ÿ´|ú±|ú±€ÿµpÜmä™$Ê3À%À"_æ„pÕœ~þ±|û±|ú±€ÿ¶pßœså¡ÿµ~û±€ü²wý­–ǪîåêäæåæææåååçççææææææëèêÓÞ×Y°|pÚ•sØ’s×’tÝ—[·€cÄŠoØ›oÙ–nטjÑ”W®zpØ•sØ’r×’tÝ–]ºƒ`À†jÖ•l×’lÔ“_ÐŽ·žïèìäæåæææçççäääææææææêçéÔáÛrØ–RèÁ.ÏÄ0ÐÃEâÆqÞœxë©‹ÿÀ8¢°w컄ÿ¶pÖ”Xê¿-ÏÄ1ÑÃ@߯qàŸvç¥ÿÂ;¦±s伂ÿ¶–ǪîåêäæåæææåååíííææææææêçéÔáÛrØ”^ͧÎGàÃwâ›oçžbñ‡›GJÙssö pוeðº­Í§Î?ÚÅyæmãœgõŒžIEÑnnûœ—ȬíåêãåäëëëšššŒŒŒíííäääêçéÕâÚjÓ–Šÿ³%ÅÄ ¶É‚ÿ´yâ§;ÈT¯¸®"Â/nÕœŠÿ±.˲Ê}ÿµ|æ©BÉ]°·®Â"™É®íåêâäãñññššš^^^òòòäääêçéÕâÛlÔ™Œÿ¸^ë½LâÀÿ¸uß§]ß‚ºµ²CÜ_sؤˆÿµeï¼GßÂÿ¸uâ¨bÞ‰½´°5ÛQ Í¸ìäçäæäêêê¹¹¹¿¿¿ëëëåååëèêÔßÙd¾ˆvå£vâ vâ wç¤gÅlÑ”RÏoIÇcJÉejÙ‘e¾Šuä¢vâ wâ wç¤hÈkΓTÑsIÇcKÈdaÚŠ–¿¨îçëäæååååîîîîîîåååæææçççãããÏÏÏÎÏÏÎÏÏÎÏÏÎÏÏÎÏÎÏÏÏÖÔÙ×ÔÚ×ÔÚÐÐÑÎÏÎÏÏÏÎÏÏÎÏÏÎÏÏÎÏÏÎÏÏÕÓØ×ÔÚ×ÕÛÏÏÑØÙØèèèææææææääääääæææææææææçççëëëëëëëëëëëëëëëëëëëëëêêéêêéêêéëëëìëëëëëëëëëëëëëëëëëëëëêêéêêééêéëëëéééæææææææææææææææææææææææææææåååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååæææææææææææææææææææææ(  çæçèçèåæåèççîåêíäéîæëíåêîäêêçéåææçææçççæææìììæææàäáÛâÞèèèÝâßÁëÒÃñÖ¿èÏÂíÔÀðÓÏã×èççâåãàààçççÆÆÆäääÒáØËÕÏøêîÒÖÓtó§zÿ²oê xú¬pÿª¦Û»öãîäÝáÖÔÕççç¶¶¶æææÚÝÚ›Ó´šÚȔղqÝœyí¨mÖ—uä¢tê£~П áº“Ú¯ÅÓËìéëëììæææçßælÝ‹ÀARÜyö³ÿ¸wê¦ú²‚ÿ¶sé¤|ÿ´rú«¾ÚÊíçê§©¨ãããéáê[Èo´?ÆW‚ò¯†ÿ¬sãŸyòª|÷®rកø°uñ§¿ØÉìæêÈÉÈççç×ÞÚyÜ¢yó­váŸYÒ¢GÓ³eÔšvé¢vì¦l×—yî¨næž½ÖÇîéìäåäåååÖàÚ묄ÿ¼‚óªWß¶ÇÑvê©‚û´ƒÿ¸xé§…ÿ¹{ú°ÀÚËìæéŸ¡ äääÖßÚvÞ yö«qásä¡rð±qÝšuë¥yð¨nÚ™zñªp꡾×ÈíçêÛÜÜçççÖßÚwà¡{ø­tå mߟ]Ô sâžwí§zó«oÝ›|ô¬qí£¾×ÈîèìÒÔÓäää×àÛ묃ÿ¹‚óµ.Ç@±VÙx‡þ½ÿµwé§„ÿ·zú¯ÀÚËëæé¢£¢åååÖÞÙsÙyò¦rÝŸVÏxCÎ_bÒ‹wè¤wì¤lÖ—{í¯p棽ÖÇíèëêëëçççÛâÙiÛ«¾É]Û­oä˜MÎ’{ëœ6Ë»&ÄÃyêžL͆UØŠÃÝËìæê¼¾½ããã×àÚuë¦1Ý¿qï±'Å7¯SÚnVé½Fã¾e䆳¾¿ÛÌíç룥¤àààÝáߦֹ«â¼¥Øº˜Ñ©ÑœžÒ²¨Ý»ªà¼¡Óµ‘Ñž’Ñ£ÑÜ×êçéëëëççççççîæëíãêîåêñçïôèóðæìîäêíäêïæëôçòóçðéçèæææåååæææ(0` èåçæææçèèâèäíæêëêëóòóñîðÈ×ÎÆîÖ½ÚÈÎ×ÒÕÕÕÛÛÛ¢¢¢ºººÛå߃·—…¶™vý¬~ý²|ú¯\Á…l󚙵¤ñìïµµµ[[[×íàäÞâ„ÿ¹ÿ´‰ÿ²cÊHHH]¼„s󥈈ˆŒ¹Ÿøëó‰ÿºuò¬¤·¬ýòøùùùßãàg‘xªº®¥¸¬gw_ÀˆdÉe¿‰L”ibÁ‡p}«»³–¨ª«ª…«”hè›mí¢]Ùœsî¤T´{xï§Z³~zô«u冀xíºd¦pã¸{ö²€[[à‘`¿†ÏÏÏ“¹¤Råv¾¸ ¸„ü­bbb˜»«6ÖQ­´¸ 4ÓMiÅ’’·¢jð•søž˜˜˜;ØT!Ì/#Í12ÓFkÈ”gÆI’fŸ®¥ÞìãÃÉ »ËÂÇ3Ñij̭ÎNà½SSSzzzsö¶¾ÈkkkCÙ¿¨ÐTä½<<< ÇÇxý¸iˉU̦m߸Z¤wù¥PÜvŽAYæAÚ[LÜj ¶ DÜbp÷™IáhqÏ”Q°wló¶nõ¸NƤmé­&ÉÆW´Xæ»Lß¿GÙi˜6NÝtcíº5È_eð‹Â&xï¨ÀÀÀUë|…¢‘–»ª     ! "#$  % &'&(!(()*+',-.***/0*/123!3!!45363333#78****89:;<$=>=?=@$AAAAA?BCAAAAD=B$?=??$>*-E(FGH(66C4((D0EI$Ê3Â%_æ„RèÁ1ÑÃFáÅ:¤±\ì¾§Îbñ‡›GJÙseðº?ÚÅgõŒžIEÑnnûœ‰ÿ³´Ê;ÈTBÉ]^^^^ÙƒbÜŠ Í¸hÈRÏoIÇcKÉe×ÔÚÑÑÒ  !" # $$%&'()*+,-./012345678988:;<==>1?@ABC*D!!!!"!!! E= !F0GHIJKLD!!:!!!EM!!NOP?QRRI7D !!:!! M= !!N01STUUVWMXDY!8!E8?@ABCDEFGHIJKLMNOPQRSTUVWX YZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„G… x†‡ˆ‰Š‹ŒŽ„‘’“j”•–—˜™š›œužŸh ¡¢£¤¥¦§¨©ª«e¬­ ®¯°±²³´µ¶·¸¹ºW»I¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ× Ø ÙÚÛÜÝÞßàá h (0`€€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿÿÿwøÿÿÿÿxwwxx‡xww‡ÿÿÿÿÿÿð÷ÿÿÿÿwwwww‡wwwwÿÿÿ÷ÿ÷øøÿÿÿÿ‡wwwxwwwwwÿÿÿÿÿÿ€øÿ÷ÿÿxwwwxwwww‡ÿÿÿ÷ÿÿÿÿøÿÿÿÿwwwwwwwwwwÿÿÿÿÿÿÿÿøwwwwˆˆˆˆxˆ‡xˆˆwwwxÿÿÿÿø‡wˆw‡wwwx‡wwwˆww‡xÿÿÿ÷wx7w‡wwwx‡wwwxwwwwÿÿÿÿøwx7w‡wwwxwwww‡wwwxÿÿwøwŠ(‡wwwwwwwwwxwwwwÿÿp÷Š""*‡wwwx‡wwwxwwwxÿÿóø‚""(‡wwwwwwwwxwwwxÿÿpør""'‡wwwxwwww‡wwwwÿÿ÷ÿ÷x("‡‡wwwxwwwwxwwwwÿÿÿÿøxx‡‡‡ˆxxˆˆx‡‡ˆ‡‡xˆÿÿÿÿø‡w‡‡‡wwxx‡wxw‡wwxxÿÿÿÿøwwww‡·‹{wwwwwxwwwwÿÿÿÿøwwww‡{»»xwwww‡wwwwÿÿwøwxww‡{»·xwwww‡wwwwÿÿpøwwww‡x»·w‡wwwxwwwwÿÿøøwwwwww»wxwwwwxwwwxÿÿpøwwww‡w{wx‡www‡wwxwÿÿxÿ÷wwww‡wwwwwwwwwwwwwÿÿÿÿx‡‡x‡‡w‡‡x‡‡x‡ˆx‡xxÿÿÿÿøˆwˆxˆˆw‡xˆw‡‡ˆxxxˆÿÿÿÿøwwww‡÷8÷xwwwwwwwwwÿÿÿøwwwwwwswwwwww‡w÷wwÿÿ÷ÿøwww‡w"‡x‡wwwwwwwwÿÿp‡÷wwwwˆ"""'wwwwˆwwwxÿÿøøwwwwx"""¨‡wwwˆ÷wwwÿÿpøwwww‡"""‡wwwwwwwwwÿÿwÿøwwww‡‚""xwwww‡wwwwÿÿÿÿø‡xwwˆwxwxw‡‡wˆxxwˆ÷ÿÿÿøˆ‡ˆˆˆˆwˆˆxˆ‡ˆˆ‡‡ˆ‡ÿÿÿÿøw{wwwwzwxwwwwwwwwwÿÿÿÿø{»»·‡ƒwww»»·xwƒwxÿÿÿÿøw»»w‡w‚wx‡»»·xw‚‡wÿÿpøw‹»ww¢""‡‡{»ww"""(ÿÿøøw{·wˆ"""'w{»w‡"""'ÿÿx÷ww·ww2""ˆ‡w·ww‚""'ÿÿˆøww·w‡‚""wwwww‡‚""‡ÿÿÿÿø‡‡xxˆxˆˆˆˆwˆwˆx¨wxÿÿÿÿ÷‡wwww‡wwwwwwww‡wwxÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ( @€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿ÷w÷w÷ÿw÷÷ÿÿ÷ÿÿÿÿÿÿÿÿ÷÷w÷ÿw·{‡·w·÷w÷÷ø÷wøw‡x‡zwÿwÿøwÿw{xz·¸w÷w÷x÷wwøxz·z‡‡w÷ÿÿs{‡¸¸§ˆwˆzºw§÷÷ÿ÷z·zx{x{··w{‡÷÷÷÷Šª‹w·¸wzx‡x‡÷øw¢#§zxx§w¸{‡·ø÷Š*{·{xw·¸{{wÿwózŠxzwºzwzw§‡÷ÿxw§zz{‡·§zw§§÷÷ÿø{{{{;zw{x{{wÿ÷zww¨{3z‹{·‡{w÷ø7ûˆ·xs··wwzsw§÷øøw·sw‹xww‡·w·÷÷w{‹xˆ«w¸º«sz§‡ÿÿúzz¸wzzw§zw§7ÿww·z{·ˆ·w¸·ww÷÷ú{‡·Š¨zx·z{{·÷øow‡x‡"£¨·wz‡w‡www{¸ª*{{·ww{‡÷wú{§xˆŠŠwz¸·¨‡÷ÿx‡·zz‡¸x‡‹·‡·÷÷ÿø{;¸{·z«»ˆz·w÷wxƒ³wŠ({{‹x‚ª‡ÿw{{·z¢ª§sº¸ª"§÷ø‡w{‹xƒ¢‹{ww‚ª·ÿ÷óxˆxz¨xˆ‹zz7‡w÷ww÷ww÷ÿÿ÷ÿÿ÷ÿÿÿw÷( €€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿ÷ÿ÷÷www÷÷÷{·www{zw{w÷ª{z{wwú(w·Š{ww‡‹w{ˆÿx·³zwxwww{¸‹§¸ÿúwx‡{xwwx‚§w·{ºzx§zøº{{7‹ww·¢¨ºª÷wwwwwww÷ÿwÿ÷ÿpuzzles-20170606.272beef/icons/solo.ico0000644000175000017500000006117613115373746016474 0ustar simonsimon 00 ¨%–  ¨>& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $ÐÐÐÞÞÞÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÚÚÚàààÄÄħ§§äääÙÙÙÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÙÙÙäää§§§ÄÄÄàààÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÚÚÚÞÞÞÐÐÐÞÞÞìììèèèééééééèèèæææéééééééééèèèïïïÑÑѲ²²óóóçççééééééèéèæèææèæèèèééééééçççóóó²²²ÑÑÑïïïèèèééééééèèèæææææææææéééèèèìììÞÞÞÚÚÚèèèäääåååäääìììóóóäääååååååäääëëëÎÎί¯¯ïïïãããåååäåäéçéöìö÷ì÷ëèëäåäåååãããïïﯯ¯ÎÎÎëëëäääåååäääíííøøøôôô÷÷÷çççäääèèèÚÚÚÛÛÛéééååååååìììÄÄÄ¢¢¢éééåååæææåååìììÏÏϰ°°ïïïäääåæåéçéÕßՔŔŒÂŒÉÛÉîéîåååäääïïï°°°ÏÏÏìììååååååììì¿¿¿‰‰‰™™™ÜÜÜèèèéééÛÛÛÛÛÛéééåååäääïïï¼¼¼½½½ïïïäääåååìììÏÏϰ°°ïïïäääãåãòëò›È›E¥EJ¨J¸Ó¸ïêïâãâïïï°°°ÏÏÏìììåååäääïïï­­­,,,SSS×××éééèèèÛÛÛÛÛÛéééåååæææããã÷÷÷EEEQQQøøøãããåååìììÏÏϰ°°ïïïäääæææåæåæææåæåµÓµŒ¡Ê¡óëóáãáïïï°°°ÏÏÏìììåååæææâââûûûªªªóóóêêêäääéééÛÛÛÛÛÛéééåååæææåååþþþ¾¾¾ÒÒÒìììäääìììÏÏϰ°°ïïïäääæææãåãõìõ™Ç™’6 6äåäçæçãäãïïï°°°ÏÏÏìììåååæææâââûûû¦¦¦ßßßèèèåååéééÛÛÛÛÛÛéééåååçççààપª¬¬¬iiiöööâââìììÏÏϰ°°ïïïäääåæåêèêÏÝϬϬ‘уµÒµñêñâãâïïï°°°ÏÏÏìììååååååêêêÉÉÉiiiáááèèèäääéééÛÛÛÛÛÛéééäääêêêÖÖÖ<<<000...cccîîîäääìììÏÏϰ°°ïïïäääåååìèìÉÚÉB¥B00i´iàäàçççãäãïïï°°°ÏÏÏìììåååäääððð§§§000JJJâââçççåååéééÛÛÛÛÛÛéééåååæææçççïïïïïïîîîíííæææåååìììÏÏϰ°°ïïïäääæææåæåêèêòëòïéïôëôèçèåæåäääïïï°°°ÏÏÏìììåååæææåååîîîòòòíííææææææåååéééÛÛÛÚÚÚèèèäääååååååääääääääääääåååäääëëëÎÎί¯¯ïïïãããåååååååååãäãäåäâäâååååååãããïïﯯ¯ÎÎÎëëëäääååååååäääãããäääååååååäääèèèÚÚÚàààïïïëëëìììììììììììììììììììììëëëòòòÔÔÔ´´´õõõêêêììììììììììììììììììììììììêêêõõõ´´´ÔÔÔòòòëëëìììììììììììììììììììììëëëïïïàààÄÄÄÑÑÑÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÎÎÎÔÔÔ¹¹¹žžž×××ÍÍÍÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÍÍÍ××מžž¹¹¹ÔÔÔÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÎÎÎÑÑÑÄÄħ§§²²²¯¯¯°°°°°°°°°°°°°°°°°°°°°¯¯¯´´´žžž†††···®®®°°°°°°°°°°°°°°°°°°°°°°°°®®®···†††žžž´´´¯¯¯°°°°°°°°°°°°°°°°°°°°°¯¯¯²²²§§§äääóóóïïïïïïïïïïïïïïïïïïïïïïïïïïïõõõ×××···ùùùíííïïïïïïïïïïïïïïïïïïïïïïïïíííùùù···×××õõõïïïïïïïïïïïïïïïïïïïïïïïïïïïóóóäääÙÙÙçççãããääääääáááááááááãããäääãããêêêÍÍÍ®®®íííâââääääääääääääääääääääääääâââííí®®®ÍÍÍêêêãããäääääääääääääääääääääãããçççÙÙÙÛÛÛéééåååæææçççöööööö÷÷÷êêêååååååìììÏÏϰ°°ïïïäääææææææææææææææææææææææææäääïïï°°°ÏÏÏìììåååæææææææææææææææææææææåååéééÛÛÛÛÛÛéééåååçççääännn888YYYÓÓÓêêêäääìììÏÏϰ°°ïïïäääææææææææææææææææææææææææäääïïï°°°ÏÏÏìììåååæææææææææææææææææææææåååéééÛÛÛÛÛÛéééåååéééÚÚÚ|||©©©&&&GGGôôôãããìììÏÏϰ°°ïïïäääææææææææææææææææææææææææäääïïï°°°ÏÏÏìììåååæææææææææææææææææææææåååéééÛÛÛÛÛÛéééåååææææææÝÝÝòòòKKK---óóóãããìììÏÏϰ°°ïïïäääææææææææææææææææææææææææäääïïï°°°ÏÏÏìììåååæææææææææææææææææææææåååéééÛÛÛÛÛÛéééååååååììì@@@&&&000¯¯¯îîîãããìììÏÏϰ°°ïïïäääææææææææææææææææææææææææäääïïï°°°ÏÏÏìììåååæææææææææææææææææææææåååéééÛÛÛÛÛÛéééååååååííí777$$$KKK®®®ïïïãããìììÏÏϰ°°ïïïäääææææææææææææææææææææææææäääïïï°°°ÏÏÏìììåååæææææææææææææææææææææåååéééÛÛÛÛÛÛéééååååååééé   }}}rrr´´´îîîãããìììÏÏϰ°°ïïïäääææææææææææææææææææææææææäääïïï°°°ÏÏÏìììåååæææææææææææææææææææææåååéééÛÛÛÛÛÛéééåååææææææòòòùùùûûûïïïåååæææìììÏÏϰ°°ïïïäääææææææææææææææææææææææææäääïïï°°°ÏÏÏìììåååæææææææææææææææææææææåååéééÛÛÛÙÙÙçççãããääääääáááààààààâââäääãããêêêÍÍÍ®®®íííâââääääääääääääääääääääääääâââííí®®®ÍÍÍêêêãããäääääääääääääääääääääãããçççÙÙÙäääóóóïïïïïïïïïïïïïïïïïïïïïïïïïïïõõõ×××···ùùùíííïïïïïïïïïïïïïïïïïïïïïïïïíííùùù···×××õõõïïïïïïïïïïïïïïïïïïïïïïïïïïïóóóäää§§§²²²¯¯¯°°°°°°°°°°°°°°°°°°°°°¯¯¯´´´žžž†††···®®®°°°°°°°°°°°°°°°°°°°°°°°°®®®···†††žžž´´´¯¯¯°°°°°°°°°°°°°°°°°°°°°¯¯¯²²²§§§ÄÄÄÑÑÑÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÎÎÎÔÔÔ¹¹¹žžž×××ÍÍÍÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÍÍÍ××מžž¹¹¹ÔÔÔÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÎÎÎÑÑÑÄÄÄàààïïïëëëììììììììììììêëêëìëìììëëëòòòÔÔÔ´´´õõõêêêììììììëëëêêêêêêêêêëëëìììêêêõõõ´´´ÔÔÔòòòëëëìììììììììëëëêëêììììììëëëïïïàààÚÚÚèèèäääååååååäåääåäëçëæææååååååëëëÎÎί¯¯ïïïãããååååååçççììììììíííèèèåååãããïïﯯ¯ÎÎÎëëëäääåååæåæãäãèæèíèíäåäååååäåèèèÚÚÚÛÛÛéééåååæææçæçíéíìèìÏÝÏäåäèçèåååìììÏÏϰ°°ïïïäääæææçççÞÞÞÏÏÏÈÈÈÄÄÄÜÜÜèèèäääïïï°°°ÏÏÏìììåååæææäåäïéïÜâÜÈÚÈíéíèçèåååéééÛÛÛÛÛÛéééåååçæçâäâÏÝϾ־–Æ–ðêðãåãìììÏÏϰ°°ïïïäääãããóó󤤤+++!!!§§§òòòáááïïï°°°ÏÏÏìììåååäåäïêï¶Ó¶(š("—"[®[éçéåååéééÛÛÛÛÛÛéééãäãðêð·Ó·,œ,ˆ11ßãßçæçëëëÏÏϰ°°ïïïäääåååçççäääPPP)))×××éééåååäääïïï°°°ÏÏÏìììåååãåãõíõ= =S©Sàäà„ÁÖÁîéîçèçÛÛÛÛÛÛéééäåäéçéØàØ5Ÿ5·Ó·“ Ê òëòãäãìììÏÏϰ°°ïïïäääæææäääíííþþþ```555äääçççãããïïï°°°ÏÏÏìììååååæåìèì2œ2"˜"G¦G — ÙáÙèæèèéèÛÛÛÛÛÛéééåååãåãöìö£Ë£9¡9¨Í¨óëóãäãìììÏÏϰ°°ïïïäääåååëëëËËËÎÎÎÌÌ̬¬¬òòòáááïïï°°°ÏÏÏìììåååãåãõíõS©S&—&ĿֿëèëäåäéééÛÛÛÛÛÛéééåååæææâäâöíöh´h„±Ñ±ñëñãäãìììÏÏϰ°°ïïïääääääñññ­­­$$$:::ÙÙÙéééãããïïï°°°ÏÏÏìììåååäåäìèìÊÛÊ8 89¡9^¯^åæååååéééÛÛÛÛÛÛéééåååææææææçæçèçèÏÝÏáäáçæçåååìììÏÏϰ°°ïïïäääæææåååêêêØØØËËËéééëëëåååäääïïï°°°ÏÏÏìììåååæææåååíéíçæçÄÙÄØàØèçèåååéééÛÛÛÚÚÚèèèäääååååååååååååëèëæææåååäääëëëÎÎί¯¯ïïïãããåååååååååéééìììåååäääåååãããïïﯯ¯ÎÎÎëëëäääååååååãäãåååíèíèæèåååäääèèèÚÚÚÞÞÞìììèèèééééééééééééèéèééééééèèèïïïÑÑѲ²²óóóçççéééééééééèèèèèèéééééééééçççóóó²²²ÑÑÑïïïèèèééééééééééééèéèèéèéééèèèìììÞÞÞÐÐÐÞÞÞÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÚÚÚàààÄÄħ§§äääÙÙÙÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÙÙÙäää§§§ÄÄÄàààÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÚÚÚÞÞÞÐÐÐ( @ ÎÎÎÝÝÝÙÙÙÙÙÙ×××ÙÙÙÙÙÙÝÝÝÍÍÍ´´´ßßßØØØÙÙÙר×ÖØÖØÙØØØØßßß´´´ÍÍÍÝÝÝÙÙÙÙÙÙÖÖÖÖÖÖØØØÝÝÝÎÎÎÝÝÝíííèèèììì÷÷÷ééééééíííÜÜÜÁÁÁðððèèèêêêùðùûñûîëîçèçðððÁÁÁÜÜÜíííèèèíííûûûûûûíííìììÝÝÝÙÙÙèèèçççØØØ˜˜˜çççäääèèèØØØ½½½ëëëåäåâä⽂ÒÝÒçåçêëê½½½ØØØçççéééÎÎÎ~~~{{{ÉÉÉîîî×××ÙÙÙéééåååêêê;;;±±±òòòçççØØØ¾¾¾ìììæåæÝâݢˢK§KZ­Zöìöéëé¾¾¾ØØØéééæææäääQQQKKKâââëëëÙÙÙÙÙÙêêêáááÿÿÿ«««UUUõõõçççØØØ¾¾¾ìììâäâîéî×à×8 8†¿†ôëôéëé¾¾¾ØØØêêêáááÿÿÿŠŠŠyyyþþþåååÚÚÚÙÙÙèèèîîî§§§YYYÎÎÎïïï×××¾¾¾ìììååååæåŒÂŒ.œ.|»|õëõéëé¾¾¾ØØØèèèêêêÓÓÓ,,,www÷÷÷æææÙÙÙÙÙÙèèèéééÉÉÉ«««½½½ÞÞÞëëëØØØ¾¾¾ìììäääèæèÀ×À·Ó·ååååäåììì¾¾¾ØØØéééçççÞÞÞ···ÔÔÔèèèéééÙÙÙÝÝÝíííèèèððð÷÷÷óóóëëëìììÜÜÜÁÁÁðððèèèéééòíòôîôêêêèèèðððÁÁÁÜÜÜíííéééëëëôôôíííèèèíííÝÝÝÍÍÍÜÜÜØØØ×××ÖÖÖÖÖÖØØØÜÜÜÌÌ̳³³ÞÞÞ×××ØØØ×Ø×ÖØÖØØØ×××ÞÞÞ³³³ÌÌÌÜÜÜØØØØØØÖÖÖ×××ØØØÜÜÜÍÍÍ´´´ÁÁÁ½½½¾¾¾¾¾¾¾¾¾¾¾¾ÁÁÁ³³³ÃÃý½½¾¾¾¾¾¾¾¾¾¾¾¾½½½ÃÃó³³ÁÁÁ¾¾¾¾¾¾¾¾¾¾¾¾½½½ÁÁÁ´´´ßßßðððëëëìììïïïëëëëëëðððÞÞÞÃÃÃóóóëëëììììììììììììëëëóóóÃÃÃÞÞÞðððììììììììììììëëëðððßßßØØØèèèäääæææÙÙÙëëëèèèççç×××½½½ëëëãããååååååååååååãããëëë½½½×××èèèäääåååååååååäääèèèØØØÙÙÙçççïïï§§§MMM^^^ßßßëëëØØØ¾¾¾ìììåååææææææææææææåååììì¾¾¾ØØØéééææææææææææææåååêêêÙÙÙÙÙÙéééçççÒÒÒÍÍÍ(((»»»óóó×××¾¾¾ìììåååææææææææææææåååììì¾¾¾ØØØéééææææææææææææåååêêêÙÙÙÙÙÙæææôôô™™™eeeåååêêêØØØ¾¾¾ìììåååææææææææææææåååììì¾¾¾ØØØéééææææææææææææåååêêêÙÙÙÙÙÙçççïïï°°°III}}}äääêêêØØØ¾¾¾ìììåååææææææææææææåååììì¾¾¾ØØØéééææææææææææææåååêêêÙÙÙØØØèèèãããêêêðððéééäääèèè×××½½½ëëëãããååååååååååååãããëëë½½½×××èèèäääåååååååååäääèèèØØØßßßðððìììëëëêêêëëëìììðððÞÞÞÃÃÃóóóëëëììììììììììììëëëóóóÃÃÃÞÞÞðððììììììììììììëëëðððßßß´´´ÁÁÁ½½½¾¾¾¾¾¾¾¾¾¾¾¾ÁÁÁ³³³ÃÃý½½¾¾¾¾¾¾¾¾¾¾¾¾½½½ÃÃó³³ÁÁÁ¾¾¾¾¾¾¾¾¾¾¾¾½½½ÁÁÁ´´´ÍÍÍÜÜÜר×ÙØÙØØØÖ×ÖØØØÜÜÜÌÌ̳³³ÞÞÞ×××ØØØÖÖÖÕÕÕÖÖÖ×××ÞÞÞ³³³ÌÌÌÜÜÜØØØØØØÖ×ÖÖ×Öר×ÜÜÜÍÍÍÝÝÝíííéééçèçêêêôîôèéèíííÜÜÜÁÁÁðððèèèêêêøøøûûûôôôçççðððÁÁÁÜÜÜíííéééèéè÷ï÷öîöèèèíííÝÝÝÙÙÙéééãäãóëóáäá®Ï®ëçëèéèØØØ¾¾¾ìììåååããã™™™ŒŒŒ«««êêêëëë¾¾¾ØØØéééåååìèì¢Ê¢¦Ì¦ëçëèéèÙÙÙÙÙÙçéçîéîÂK§KŽÃØÃðìðר׾¾¾ìììäääííí@@@***½½½èèèëëë¾¾¾ØØØçèçôëô™Ç™J§JD£D É ÷ï÷ר×ÙÙÙçèçóëó„¿„S«SD¥DÞâÞëêëØØØ¾¾¾ìììäääçççýýýiii›››ñññêêê¾¾¾ØØØæèæøíøw¶w9Ÿ9\¯\·Ò·óíóØÙØÙÙÙéééåååñëñN©N55ñêñèéèØØØ¾¾¾ìììæææÞÞÞ‡‡‡???iiiöööééé¾¾¾ØØØçéçïêï¶Ó¶+›+t¸tÝâÝìêìÙÙÙÙÙÙéééãäãëçëÒÝÒ¶Ò¶çæçèèè×××½½½ëëëãããççç³³³¦¦¦åååäääëëë½½½ØØØéèéãäãíèíÅØÅ¨Ì¨ÞâÞêéêØØØÝÝÝíííéééèéèîëîôîôéééíííÜÜÜÁÁÁðððèèèéééôôô÷÷÷êêêèèèðððÁÁÁÜÜÜíííéééèéèñíñ÷ï÷êéêíííÝÝÝÎÎÎÝÝÝÙÙÙÚÚÚØÙØ×Ù×ÙÙÙÝÝÝÍÍÍ´´´ßßßØØØÚÚÚØØØ×××ÙÙÙØØØßßß´´´ÍÍÍÝÝÝÙÙÙÚÚÚØÙØ×Ù×ØÙØÝÝÝÎÎÎ(  ÃÃÃ×××ÖÖÖÕÕÕ¿¿¿ÑÑÑÓÔÓÚ×ÚÒÒÒ¿¿¿ÕÕÕÓÓÓÚÚÚÂÂÂÛÛÛååå®®®óóóÑÒÑïëïÃÛÃÆëéëÒÒÒ÷ø÷¦¦¦¥¥¥ãããÕÕÕÝÝÝ```×××ÑÒÑéåé»Ô»_¯_çäçËÌËóóó•••¬¬¬ßßß×××ãããÆÆÆæææÒÒÒçæçÛãÛØâØçæçÐÑÐìììÔÔÔååå×××¾¾¾ØØØÙÙÙÒÒÒ»»»ÍÍÍÓÑÓÔÒÔÍÍͼ¼¼ÑÑÑÓÓÓÖÖÖ¿¿¿ÒÒÒãããØØØèèèÍÍÍáááäääãäãáááÍÍÍåååáááèèèÑÑÑØØØÙÙÙhhhÓÓÓÖÖÖãããççççççäääÐÐÐèèèåååëëëÔÔÔÛÛÛÊÊÊaaaáááÒÒÒäääççççççäääÐÐÐèèèåååëëëÔÔÔÒÒÒçççßßßæææÍÍÍáááãããâââáááÍÍÍåååáâáçèçÑÑÑ¿¿¿ÔÔÔÔÑÔÒÒÒ»¼»ÌÌÌÖÖÖØØØÍÍͼ¼¼ÑÑÑÒÐÒÙÖÙ¾¿¾ÕÕÕíííÒÞÒåèåÒÑÒêêêÍÍÍÆÆÆèèèÐÑÐíëíÖà֨娨֨ÚÕÚÂÚÂ?ž?ÔÞÔÑÏÑëìë­­­llléééÌÍÌðêð[¬[{½{Þ×ÞÙÙÙëîë”Ç”æêæÕÔÕíîíËËËëìëÒÓÒôðô¢Í¢»Û»àÛàÂÃÂÙÙÙÜÖÜÖÕÖ¿¿¿ÑÑÑÕÕÕÜÜÜÒÒÒ¿¿¿ÕÕÕÜÖÜÜÚÜÂÂÂ(0` ÑÑÑÝÝÝÛÛÛãããÄÄĦ¦¦åååÜÜÜéééììì°°°òòòæèæÏÏÏèçèöíö¯¯¯öööûûû¢¢¢ÕßÕ–Æ–ŒÂŒÊÛÊíéí½½½™™™òëò™Ç™E¥EJ¨J¸Ó¸+++PPPGGGðððãäã¶Ó¶Œ Ê ôëô©©©þþþÔÔԛț“6 6iii¨Í¨‘уðêðËËË<<<---cccB¥B00h´hKKKÓÓÓ´´´ëìë¹¹¹žžž†††nnn:::YYY|||&&&@@@000555!!!rrràààäääÜâÜÏÝϾ־(š("˜"[®[,œ,ˆ= =S©S„ÁÖÁØàØ·Ó·2œ2G¦G — Ùá٣ˣ9¡9óóó&—&ıѱíèí5Ÿ5ÄÙÄ                        !"#$%& '(  )( *+ ,-./* 0  12  +!345     06* 789,: ;6   2<==>  ?@A++* + =B   + ::: +*    + *  CD E DCEE   2FG2GF  DGHDDHGD02DD2             IJK    L0M)    B=   NMO   PQB   LR               D D 0DGHDDHGD  2FG22F2 EEEE2D   DE S     E+ T     ;   U   +VWX  'Q  ,YZ[  +:,X\]@+ E (' E +^_+`a  b5c4.!+ 1KP  dZefg  +hiX7!+ ; +j_klW  +A`m!+ QnJ  opi[   V+  ;   qg         * !    U ( @ÎÎÎÝÝÝØÙØØØØ´´´âââ×Ù×ÖÖÖíííèéèîëî÷÷÷ÁÁÁñíñùðùçèçðððåååøøø™™™âäâëçë¾¾¾Â‚½‚ÒÝÒ}}}{{{ÉÉÉ;;;±±±ÞâޢˢK§KZ­ZöìöQQQMMMýýý«««UUUõõõêëê×à×55„¿„ŠŠŠ§§§YYYŒÂŒ|»|ôîôÔÔÔ,,,www·Ó··Ò····óóóÃÃÃïï簾¦III^^^ÓÓÓ***½½½eeeßßßÌÌÌôôôóëó®Ï®ŒŒŒ¢Ê¢¦Ì¦ŽÃØÃ@@@™Ç™D£DS«SD¥Diiiøíøw¶w9Ÿ9\¯\N©N‡‡‡???¶Ò¶+›+åäå¨Ì¨           ! "#  $%&'()*  +,-./012( +3 + 4567189/:;<. !, => ?:   @9 .   # #  #ABA    C .  B      DEF  GHI@ /  .J/ #E    /  K / CB@ . / /K  ABA    L#  L  9 CM 99 NO/P,QR&ST UH 9V&WQ9N2XY$ +Z[\]^>9N_1N`aZ bc\$b#Dd Te$ 9 .   K K K ( ÃÃÃ×××ÖÖÖÕÕÕ¿¿¿ÑÑÑÓÔÓÚ×ÚÒÒÒÓÓÓÚÚÚÂÂÂÛÛÛååå®®®óóóÑÒÑïëïÃÛÃÆëéë÷ø÷¦¦¦¥¥¥ãããÝÝÝ```éåé»Ô»_¯_çäçËÌË•••¬¬¬ßßßÆÆÆæææçæçÛãÛØâØÐÑÐìììÔÔÔ¾¾¾ØØØÙÙÙ»»»ÍÍÍÓÑÓÔÒÔ¼¼¼èèèáááäääãäãhhhçççÐÐÐëëëÊÊÊaaaâââáâáçèçÔÑÔ»¼»ÌÌÌÒÐÒÙÖÙ¾¿¾íííÒÞÒåèåÒÑÒêêêíëíÖà֨娨֨ÚÕÚÂÚÂ?ž?ÔÞÔÑÏÑëìë­­­llléééÌÍÌðêð[¬[{½{Þ×Þëîë”Ç”æêæÕÔÕíîíËËËÒÓÒôðô¢Í¢»Û»àÛàÂÃÂÜÖÜÖÕÖÜÜÜÜÚÜ   !"#$%&'()* +,-+./0123 456758   295:;<:5:9 23=>>;?9@0AB: ;>>;?9@0 >'*5:C:5DE  0F GH258 IJKLMNOP5)9.QRSTUVWXYZ[\]^_`abcd3efghijk[lmnopq3rs t ruddU(0`€€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿÿ÷ÿÿ÷ÿ÷ÿÿ÷ÿwÿ÷ÿÿ÷ÿÿpÿÿÿÿÿÿ÷ÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿðÿÿÿÿÿÿ÷ÿÿÿÿÿÿ÷ÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿðÿÿøÿÿ÷ÿÿr¨÷÷ÿÿÿ€ÿðÿÿ÷ÿÿ÷ÿÿ‡rÿ÷ÿÿxÿðÿÿÿ€ÿÿ÷ÿÿÿrÿ÷ÿÿ÷ÿÿðÿÿÿðÿÿÿÿø"ÿÿ÷ÿÿÿ÷ÿÿðÿÿ÷ðÿ÷ÿÿò÷ÿÿwÿÿðÿÿpÿ÷ÿÿr"ÿ÷ÿÿ€ÿÿðÿÿ÷ÿÿ÷ÿÿÿÿÿ÷ÿÿÿ÷ÿÿðÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿðÿÿÿÿÿÿ÷ÿÿÿÿÿÿ÷ÿÿÿÿÿÿðÿÿÿÿÿÿ÷ÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿðw÷÷w÷÷w÷÷w÷wøww÷÷w÷p‡wwwwwx‡wwwwwwx‡wwwwwwpÿÿÿÿÿÿ÷ÿÿÿ÷ÿÿ÷ÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿ÷ÿÿÿÿðÿÿÿÿ÷ÿ÷ÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿpÿÿÿ÷ÿÿ÷ÿÿÿÿÿÿ÷ÿÿÿ÷ÿÿðÿÿpÿ÷ÿÿÿÿÿ÷ÿÿÿÿÿÿðÿÿ÷øÿÿÿÿ÷÷ÿÿ÷ÿÿ÷ÿÿÿðÿÿ÷øÿ÷wÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿðÿÿðÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿpÿÿðˆÿ÷ÿÿÿÿÿÿ÷ÿ÷ÿÿÿ÷ÿðÿÿðÿ÷ÿÿÿÿÿÿøÿÿÿÿÿÿðÿÿÿÿÿÿ÷ÿÿÿÿÿ÷ÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿðÿÿÿÿÿÿ÷ÿÿÿÿÿÿ÷ÿÿÿÿÿÿðÿÿÿÿÿÿ÷ÿÿÿÿÿÿ÷ÿÿÿÿÿÿpwwwwwww‡wwww‡wxwwwwwxwpwww÷wwøw÷wðÿÿÿÿÿÿ÷÷ÿÿÿÿÿøÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿpÿÿÿÿÿÿ÷ÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿðÿÿÿøÿ÷ÿxxÿ÷ÿÿ÷‡ÿÿðÿÿwrÿÿÿÿ€ÿ÷ÿÿ‚"ÿðÿÿ‚"/ÿ÷ÿÿøÿÿ÷ÿÿ(òÿðÿÿròÿ÷ÿÿÿ€ÿ÷ÿÿÿ"‚ÿðÿÿø¢ÿÿÿÿÿðÿøÿÿ‚wÿÿpÿÿ‚ÿ÷ÿÿ€ÿ÷ÿÿrŠÿðÿÿÿxÿ÷ÿø‡ÿÿ÷ÿÿ÷ˆÿÿðÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿðÿÿÿÿÿÿ÷ÿÿÿÿÿÿ÷ÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿðÿÿÿÿÿ÷ÿÿÿÿ÷ÿÿÿÿð( @€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ‡w÷w÷wwwww÷ww÷p÷÷ÿwÿÿ÷w÷÷ÿpÿ÷ÿwÿ÷wÿwÿ÷wÿp_p÷wx¨ÿwøÿð'÷÷_ÿw'÷wÿ'pÿw'w÷÷¨ÿww÷÷prXÿwÿx‡÷ÿø‡ÿp_÷ÿwÿ÷ÿw÷ÿpÿÿÿw÷ÿwwÿÿÿp'www‡wwwwwwwpwwww÷ww÷wwwwwp÷÷wÿÿÿ÷wÿ÷ÿp_ÿ÷ÿÿw÷÷wÿpwr‡w÷ÿ÷ÿw÷ÿÿÿðÿÿw÷÷wÿ÷wp/÷pˆw÷ÿ÷w÷ÿpWÿp‡ÿwÿ÷ÿwÿÿð÷÷÷wÿÿwÿp/ÿÿÿwÿÿÿw÷÷ÿ÷pW÷÷wwwwww÷÷wpxwww‡wwwwxwwwwp/ÿ÷÷ÿ÷wÿwÿ÷÷ð÷÷ÿÿw÷ÿÿ÷w÷÷ÿp÷‡÷wrXÿ÷÷‡ÿð_ÿŠ'÷õ'÷wÿòŠwpwx'ÿwÿˆÿw÷rˆp'ÿw§w÷xw÷ø§ÿp÷ÿwÿ÷w÷wÿwpÿwÿÿ÷ÿw÷ÿÿp÷ww÷ÿ÷ð€P%P%%€P ( €€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿw÷÷wwÿpw÷÷ÿwðøw‡‡pw÷wð÷www÷ð÷w÷px÷ÿ÷ÿpxw÷ÿr÷÷ÿ÷ÿp÷wwwwp÷÷wðx÷w‡ˆð'ø÷÷wwðÿwÿ÷rpuzzles-20170606.272beef/icons/slant.ico0000644000175000017500000006117613115373745016640 0ustar simonsimon 00 ¨%–  ¨>& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÚÚÚÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÚÚÚÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÎÎÎÂÂÂÚÚÚ×××ÔÔÔÕÕÕÔÔÔÖÖÖÛÛÛÃÃý½½ÕÕÕÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙ××׿¿¿ÂÂÂÚÚÚ×××ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÎÎΦ¦¦———ÑÑÑ×××ÔÔÔÖÖÖÓÓÓ™™™¨¨¨²²²˜˜˜ÂÂÂÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÇÇÇ“““®®®©©©–––ÐÐÐ×××ÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÛÛÛ···‘‘‘¼¼¼———ÝÝÝÕÕÕÞÞÞ›››±±±‡‡‡hhhœœœ–––ÐÐÐÙÙÙ×××××××××ÖÖÖÚÚÚ××××××××××××××××××××××××ÚÚÚÖÖÖÖÖÖ××××××ØØØÖÖÖÆÆÆƒƒƒ½½½–––ÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÔÔÔÖÖÖÒÒÒ222¨¨¨¦¦¦»»»ÒÒÒÁÁÁ–––æææ‡‡‡,,,ÒÒÒ°°°¨¨¨ÓÓÓËËËËËËÌÌÌÓÓÓÁÁÁÍÍÍÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÁÁÁÒÒÒÍÍÍËËËËËËÒÒÒ¬¬¬···‹‹‹KKKCCC£££¨¨¨ÃÃÃÙÙÙÕÕÕÕÕÕÕÕÕÕÕÕÑÑÑêêêRRR’’’­­­³³³ÏÏϹ¹¹˜˜˜ééé©©©GGGëëë°°°£££ÐÐÐÅÅÅÇÇÇ×××UUUtttÔÔÔÅÅÅÈÈÈÈÈÈÈÈÈÈÈÈÅÅÅÔÔÔ}}}KKKÓÓÓÈÈÈÅÅÅÏÏÏ¥¥¥¾¾¾qqq}}}ggg‹‹‹¯¯¯¿¿¿ÚÚÚÔÔÔÕÕÕÕÕÕÔÔÔÜÜÜ···OOO¶¶¶———ÚÚÚÔÔÔààà™™™¿¿¿bbbTTTàààŽŽŽÍÍÍÚÚÚÖÖÖçççdddbbbÍÍÍØØØ×××ØØØØØØØØØØØØ×××ØØØÏÏÏmmmYYYãããØØØØØØÐÐЖ––²²²IIITTTµµµ–––×××ÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÅÅÅ¢¢¢•••ÈÈÈÖÖÖÙÙÙÓÓÓGGGxxx   ¤¤¤‘‘‘···ÚÚÚÒÒÒäää```bbbãããÂÂÂÕÕÕÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÖÖÖÂÂÂãããoooTTTàààÔÔÔÙÙÙ»»»–––¤¤¤£££•••ÇÇÇÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙ¯¯¯ÖÖÖÖÖÖÙÙÙÔÔÔ@@@ááá³³³¨¨¨ÏÏÏÚÚÚÓÓÓåååaaabbbåååÒÒÒÂÂÂÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÃÃÃÏÏÏèèènnnUUUáááÔÔÔÙÙÙÐÐЫ««°°°ÕÕÕÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÉÉÉÓÓÓÕÕÕÙÙÙÔÔÔAAAçççÕÕÕÔÔÔÍÍÍÙÙÙÒÒÒåååaaabbbåååÔÔÔÓÓÓÃÃÃÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÃÃÃÒÒÒÓÓÓçççnnnUUUáááÔÔÔØØØÏÏÏÒÒÒØØØÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÇÇÇÉÉÉÜÜÜÔÔÔAAAçççÑÑÑ×××ÍÍÍÄÄÄÖÖÖäääaaabbbåååÔÔÔÕÕÕÔÔÔÃÃÃÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÃÃÃÒÒÒÕÕÕÒÒÒçççnnnUUUàààØØØÅÅÅËËË×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÅÅÅÑÑÑÖÖÖ@@@çççÑÑÑÕÕÕ×××ÍÍÍÅÅÅççç```bbbåååÔÔÔÔÔÔÕÕÕÓÓÓÃÃÃÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔ×××ÃÃÃÒÒÒÖÖÖÔÔÔÒÒÒçççnnnTTTãããÈÈÈËËË×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÍÍÍËËËDDDèèèÒÒÒÖÖÖÖÖÖ×××ÌÌÌÕÕÕeeebbbåååÕÕÕÕÕÕÖÖÖÖÖÖÔÔÔÃÃÃ×××ÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÕÕÕØØØÄÄÄÓÓÓ×××ÖÖÖÕÕÕÓÓÓçççoooXXXÑÑÑÍÍÍÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÚÚÚÁÁÁ888‹‹‹äääÎÎÎÒÒÒÒÒÒÑÑÑÒÒÒßßßTTTaaaáááÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÐÐÐÁÁÁÓÓÓÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÔÔÔÁÁÁÏÏÏÓÓÓÒÒÒÒÒÒÑÑÑÐÐÐâââoooXXXÒÒÒÖÖÖÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÝÝÝ­­­‡‡‡ÓÓÓÀÀÀÃÃÃÃÃÃÂÂÂÂÂÂÑÑÑYYY^^^ÒÒÒÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÄÄͶ¶ÄÄÄÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÅÅÅ···ÁÁÁÄÄÄÃÃÃÃÃÃÄÄÄÀÀÀÈÈÈÆÆÆ'''¿¿¿ÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÌÌÌØØØ×××××××××ÖÖÖÖÖÖæææeee[[[ØØØØØØÖÖÖ×××××××××××××××ÕÕÕÄÄÄØØØ×××××××××××××××ÖÖÖÙÙÙÅÅÅÔÔÔØØØ××××××ÔÔÔÜÜÜÖÖÖFFF………ÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÇÇÇÊÊÊ×××ÔÔÔÔÔÔÓÓÓäää```cccÝÝÝÄÄÄÖÖÖÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÂÂÂÖÖÖÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÖÖÖÃÃÃÒÒÒÕÕÕÕÕÕÒÒÒÙÙÙÔÔÔAAAÙÙÙÉÉÉ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÇÇÇÌÌÌ×××ÔÔÔÔÔÔäääaaaaaaæææÍÍÍÅÅÅØØØÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÃÃÃÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÃÃÃÒÒÒÖÖÖÓÓÓÚÚÚÕÕÕBBBŠŠŠêêêÄÄÄÌÌÌ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÇÇÇËËËÕÕÕÔÔÔäääaaabbbäääÕÕÕËËËÅÅÅÖÖÖÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÃÃÃÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÂÂÂÑÑÑÓÓÓÚÚÚÕÕÕBBB‹‹‹çççÓÓÓÆÆÆÊÊÊÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÈÈÈÓÓÓÝÝÝãããaaabbbåååÒÒÒÛÛÛÕÕÕÌÌÌßßßÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÃÃÃÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕßßßÉÉÉØØØàààÔÔÔBBB‹‹‹èèèÏÏÏÞÞÞÎÎÎÒÒÒÜÜÜÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÀÀÀÅÅÅeeeaaaåååÒÒÒÚÚÚÃÃà  ™™™¸¸¸ÙÙÙÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÃÃÃÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕ×××ÖÖÖ¯¯¯–––¨¨¨ÀÀÀGGGŠŠŠèèèÐÐÐÚÚÚ¹¹¹›››žžžÂÂÂÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÎÎά¬¬{{{\\\åååÒÒÒÚÚÚ¸¸¸®®®´´´’’’¢¢¢ÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÓÓÓÃÃÃÖÖÖÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖ–––   ···«««```êêêÏÏÏÛÛÛ¦¦¦•••²²²¯¯¯‹‹‹´´´ÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÓÓÓÞÞÞ«««[[[ËËË¢¢¢ÐÐÐ×××ÕÕÕ’’’×××hhh²²²¢¢¢¾¾¾ÛÛÛÕÕÕÖÖÖ×××ÕÕÕÄÄÄ×××ÖÖÖÖÖÖÕÕÕÞÞÞ¬¬¬¶¶¶€€€„„„ÉÉÉ£££ÙÙÙÙÙÙÄÄÄšššÕÕÕ@@@888ÅÅÅ———ÏÏÏÖÖÖÕÕÕÕÕÕÕÕÕÓÓÓÞÞÞ¬¬¬hhhááá›››®®®ÌÌ̲²²šššééé³³³HHHééé±±±ËËËÁÁÁÃÃÃÃÃö¶¶ÄÄÄÃÃÃÃÃÃÁÁÁÊÊÊ“““ÄÄÄßßßggg‡‡‡âââ½½½ËËË¢¢¢©©©òòò„„„iiiñññŸŸŸÀÀÀÚÚÚÔÔÔÕÕÕÕÕÕÔÔÔÙÙÙÃÃÃ!!!ÄÄĦ¦¦ÈÈÈ×××ÎÎΓ““àààxxx>>>ìì쬬¬···ÙÙÙÓÓÓÓÓÓÔÔÔÒÒÒÂÂÂÕÕÕÓÓÓÓÓÓÒÒÒÚÚÚ©©©¿¿¿¿¿¿}}}666ÑÑÑ•••××××××¼¼¼©©©ãããKKKiiiîîî’’’ÌÌÌ×××ÕÕÕÕÕÕÕÕÕÔÔÔÛÛÛ···‘‘‘mmméééÐÐÐÜÜܬ¬¬ššš|||³³³VVVÚÚÚ×××ÔÔÔÖÖÖÖÖÖÔÔÔÃÃÃ×××ÕÕÕÖÖÖÓÓÓÞÞÞÄÄÄ\\\‘‘‘iii¡¡¡–––ºººÚÚÚÔÔÔààà___™™™qqq¤¤¤¥¥¥¥¥¥ÜÜÜÓÓÓÕÕÕÕÕÕÕÕÕÔÔÔØØØÅÅÅžžž®®®OOOèèèÑÑÑÚÚÚ³³³¢¢¢œœœ¬¬¬mmmXXXáááÕÕÕÔÔÔÖÖÖÓÓÓÃÃÃÖÖÖÕÕÕÓÓÓÚÚÚÔÔÔFFF‚‚‚°°°¡¡¡žžž¼¼¼ÚÚÚÒÒÒåååcccbbb°°°¢¢¢ššš®®®ÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÆÆÆÌÌÌãããØØØHHH€€€èèèÐÐÐÞÞÞÍÍÍÃÃÃßßßææælllWWWáááÕÕÕÔÔÔÓÓÓÁÁÁÖÖÖÒÒÒÚÚÚÕÕÕBBBŠŠŠéééÛÛÛÀÀÀÖÖÖÛÛÛÒÒÒåååccc```ãããßßßÄÄÄÌÌÌßßßÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÈÈÈÌÌÌÔÔÔØØØÚÚÚHHH€€€çççÕÕÕÔÔÔÎÎÎÙÙÙÑÑÑçççlllWWWááá×××ÙÙÙËËËÚÚÚÚÚÚÕÕÕBBB‹‹‹èèèÐÐÐÕÕÕÃÃÃÐÐÐÓÓÓåååccc```äääÒÒÒØØØÏÏÏÓÓÓ×××ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÇÇÇÌÌÌ×××ÓÓÓØØØÚÚÚHHHÜÜܪªªŸŸŸÉÉÉÛÛÛÑÑÑçççlllXXXÚÚÚ¶¶¶›››ÂÂÂÑÑÑCCCŠŠŠçççÑÑÑÕÕÕ×××ÂÂÂÑÑÑæææccc```äääÓÓÓÚÚÚÌÌÌ¡¡¡§§§ÒÒÒÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÇÇÇÌÌÌÖÖÖÔÔÔÒÒÒ×××ÙÙÙKKKvvv³³³¹¹¹˜˜˜±±±ÛÛÛÑÑÑæææmmmVVV¶¶¶···¦¦¦GGGŠŠŠçççÐÐÐÔÔÔÔÔÔÖÖÖÂÂÂáááccc___äääÒÒÒÚÚÚ¶¶¶”””»»»···‘‘‘ÃÃÃÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÔÔÔØØØÈÈÈÏÏÏÚÚÚ×××ØØØÖÖÖÝÝÝ   ±±±sssaaa¸¸¸˜˜˜ÉÉÉÙÙÙÞÞÞ¬¬¬²²²bbbDDDššš¦¦¦»»»ÝÝÝ×××ØØØ×××ØØØÔÔÔcccbbbçççÖÖÖÙÙÙÎÎΔ””ÉÉÉ]]]kkkÇÇÇ“““ÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÇÇÇ¿¿¿ÈÈÈÆÆÆÆÆÆÊÊÊ···™™™ÝÝݤ¤¤(((‘‘‘ÀÀÀžžžÎÎÎÅÅÅÞÞÞ™™™999ÀÀÀÎÎÎ’’’ÍÍÍÅÅÅÅÅÅÄÄÄÚÚÚVVVQQQÚÚÚÃÃÃÄÄÄÎÎΣ££¾¾¾wwwhhhVVV’’’¯¯¯¿¿¿ÚÚÚÔÔÔÕÕÕÕÕÕÔÔÔØØØÇÇÇÆÆÆÐÐÐÍÍÍÍÍÍÐÐÐÄÄÄ–––ááᤤ¤"""«««½½½¨¨¨ÔÔÔÐÐД””ÌÌÌØØØfff]]]ÓÓÓ———ÖÖÖËËËÌÌÌÜÜÜccc:::NNNÂÂÂÔÔÔÊÊÊÔÔÔ®®®···|||eeeUUU•••©©©ÄÄÄÙÙÙÕÕÕÕÕÕÕÕÕÔÔÔØØØÈÈÈÎÎÎÙÙÙÖÖÖ×××ÕÕÕÝÝÝ   ¤¤¤}}}^^^¤¤¤{{{ÛÛÛÕÕÕÝÝݳ³³œœœ~~~UUUŸŸŸ˜˜˜ÁÁÁÛÛÛÕÕÕçççdddaaaÜÜÜ“““>>>ÎÎÎÞÞÞÔÔÔ×××”””´´´aaammm¯¯¯šššÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÔÔÔØØØÇÇÇÌÌÌ×××ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕŸŸŸššš£££¡¡¡KKKçççÐÐÐÚÚÚ¬¬¬ššš¥¥¥›››···ÚÚÚÒÒÒåååccc___æææÀÀÀããã™™™;;;ÌÌÌÛÛÛÕÕÕËËË™™™¤¤¤¢¢¢ÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÇÇÇÌÌÌ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÞÞÞÃÃõµµÝÝÝÚÚÚHHH€€€èèèÐÐÐÝÝÝÍÍͰ°°ÔÔÔÚÚÚÒÒÒåååccc```äääÖÖÖÃÃÃÎÎÎçç瘘˜;;;ÍÍÍÛÛÛÕÕÕÜÜܸ¸¸¾¾¾ÝÝÝÖÖÖÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÇÇÇÌÌÌ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÐÐÐÊÊÊÖÖÖ×××ÚÚÚHHH€€€èèèÐÐÐ×××ÌÌÌ×××ÒÒÒåååccc```äääÔÔÔÖÖÖÃÃÃÒÒÒÑÑÑæææ˜˜˜;;;ÍÍÍÛÛÛÔÔÔÏÏÏÒÒÒÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÇÇÇÌÌÌ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÍÍÍÆÆÆØØØÒÒÒØØØÚÚÚHHHéééÆÆÆ«««ÐÐÐæææbbb```äääÔÔÔÔÔÔ×××ÃÃÃÒÒÒÖÖÖÑÑÑæææ˜˜˜;;;ÌÌÌÞÞÞ±±±¹¹¹ÜÜÜ×××ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÇÇÇÌÌÌ×××ÔÔÔÕÕÕÕÕÕÕÕÕÔÔÔÖÖÖÍÍÍÆÆÆ×××ÔÔÔÓÓÓØØØØØØOOOnnn««««««¤¤¤[[[dddãããÔÔÔÔÔÔÔÔÔ×××ÃÃÃÒÒÒÕÕÕÕÕÕÐÐÐæææ™™™AAA›››¯¯¯¨¨¨šššÐÐÐ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÉÉÉÏÏÏÙÙÙ×××××××××××××××ÙÙÙÐÐÐÈÈÈÚÚÚÖÖÖ×××ÔÔÔããã®®®“““yyy¾¾¾„„„ÃÃÃÝÝÝÕÕÕ××××××ÙÙÙÈÈÈÔÔÔØØØ××××××ÕÕÕÞÞÞ†††œœœnnn¤¤¤œœœÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÂÂÂÁÁÁÏÏÏÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÎÎÎÆÆÆ¿¿¿ÏÏÏÌÌÌÌÌÌÌÌÌÎÎΑ‘‘ÔÔÔ¦¦¦FFFUUUÖÖÖ“““ÔÔÔËËËÌÌÌÌÌÌÎÎα±±ÉÉÉÍÍÍÌÌÌËËËÓÓÓ«««®®®ËËËfffßßßšššÄÄÄÙÙÙÕÕÕÕÕÕÕÕÕÕÕÕ×××ÊÊÊÂÂÂÉÉÉÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÇÇÇÇÇÇÈÈÈÇÇÇÇÇÇÈÈÈÇÇÇÀÀÀØØØÔÔÔ¨¨¨¼¼¼ÖÖÖ¾¾¾ÈÈÈÇÇÇÇÇÇÇÇÇÇÇǵµµÇÇÇÈÈÈÇÇÇÇÇÇÉÉÉÀÀÀÉÉÉàààÊÊʵµµÝÝÝÈÈÈÏÏÏÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÙÙÙ×××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÙÙÙÔÔÔÕÕÕßßßÛÛÛÔÔÔÚÚÚØØØØØØØØØØØØØØØÛÛÛØØØØØØØØØØØØ×××ÙÙÙ×××ÓÓÓØØØÜÜÜÓÓÓØØØÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÓÓÓÔÔÔÕÕÕÔÔÔÕÕÕÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÔÔÔÕÕÕÕÕÕÔÔÔÓÓÓÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ( @ ÕÕÕÖÖÖØØØÔÔÔÕÕÕÕÕÕÔÔÔÖÖÖÙÙÙÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÙÙÙØØØÔÔÔÕÕÕÕÕÕÖÖÖÒÒÒÉÉÉÙÙÙÕÕÕÔÔÔÙÙÙÑÑÑÇÇÇÕÕÕ×××ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÖÖÖÖÖÖÆÆÆËËËÙÙÙÕÕÕÕÕÕØØØÊÊʦ¦¦´´´ÙÙÙÙÙÙÄÄÄœœœ¡¡¡œœœÎÎÎØØØÖÖÖÕÕÕÖÖÖ×××ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×××ÕÕÕÖÖÖ×××ÕÕÕ¬¬¬¨¨¨¦¦¦···ÙÙÙÔÔÔÙÙÙÂÂÂsss«««ÁÁÁÒÒÒ§§§ºººMMM­­­®®®ÓÓÓÍÍÍÕÕÕÒÒÒÍÍÍÐÐÐÐÐÐÐÐÐÐÐÐÏÏÏÎÎÎ×××ÌÌÌÕÕÕ···©©©fff{{{¬¬¬ÉÉÉØØØÖÖÖÑÑÑ]]]¨¨¨ºººÉÉɱ±±ÏÏÏ^^^ÕÕÕ¤¤¤ËËËÓÓÓºººcccÅÅÅÌÌÌÊÊÊËËËÉÉÉÒÒÒqqqšššÙÙÙÌÌÌ´´´žžž]]]jjjªªªÅÅÅÙÙÙÛÛÛ¿¿¿†††¬¬¬ÓÓÓåå凇‡„„„¨¨¨½½½äääÈÈÈbbb±±±××××××××××××××××××ÅÅÅiii¨¨¨èèèÊÊʦ¦¦}}}ˆˆˆ¯¯¯ÖÖÖÕÕÕØØØÊÊʹ¹¹ÑÑÑæææˆˆˆ|||ÇÇDz²²ÂÂÂáááÆÆÆ]]]¿¿¿ÖÖÖÌÌÌÖÖÖÔÔÔÕÕÕÕÕÕÒÒÒÍÍÍØØØddd¦¦¦æææÊÊʶ¶¶¼¼¼ÕÕÕÖÖÖÕÕÕ×××ÌÌÌÐÐÐçç爈ˆzzzâââØØØÈÈÈâââÆÆÆ^^^½½½âââÈÈÈÏÏÏÖÖÖÕÕÕÕÕÕÕÕÕÔÔÔÇÇÇÚÚÚ×××eee¦¦¦èèèÊÊÊÔÔÔ×××ÔÔÔÕÕÕ×××ËËËÝÝÝŠŠŠyyyâââÔÔÔÏÏÏÏÏÏÇÇÇ]]]¾¾¾ßßßÓÓÓËËËÏÏÏÖÖÖÕÕÕÕÕÕÕÕÕÓÓÓÈÈÈÔÔÔØØØ×××ddd¨¨¨×××ÌÌÌÖÖÖÕÕÕÕÕÕÖÖÖÓÓÓ}}}ãããÕÕÕÓÓÓÝÝݺºº```¿¿¿áááÒÒÒØØØÌÌÌÐÐÐØØØÖÖÖÖÖÖ×××ÔÔÔÉÉÉØØØÔÔÔÚÚÚ×××hhh¢¢¢×××ÕÕÕÕÕÕÕÕÕÜÜÜ···uuuÔÔÔÈÈÈÅÅÅÐÐм¼¼WWW±±±ÓÓÓÅÅÅÈÈÈÊÊÊÁÁÁÄÄÄÊÊÊÈÈÈÈÈÈÉÉÉÇÇǾ¾¾ÉÉÉÈÈÈÆÆÆÌÌÌÌÌÌKKKÌÌÌ×××ÕÕÕÕÕÕ×××ÌÌÌÖÖÖÔÔÔÐÐÐÜÜÜÆÆÆ[[[³³³ßßßÐÐÐÔÔÔÓÓÓÕÕÕÊÊÊÎÎÎÕÕÕÓÓÓÓÓÓÔÔÔÒÒÒÇÇÇÕÕÕÓÓÓÒÒÒààà€€€ƒƒƒ×××ÕÕÕÕÕÕÕÕÕ×××ÌÌÌÍÍÍÔÔÔÞÞÞÇÇÇ^^^½½½ÒÒÒÓÓÓÖÖÖÕÕÕÕÕÕ×××ÌÌÌÐÐÐ×××ÕÕÕÕÕÕÖÖÖÓÓÓÈÈÈÖÖÖÓÓÓäää………×××ÏÏÏÖÖÖÕÕÕÕÕÕ×××ÍÍÍÏÏÏàààÆÆÆ^^^½½½àààÉÉÉ×××ÔÔÔÕÕÕÕÕÕ×××ËËËÏÏÏÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÌÌÌ×××ããã‚‚‚æææÌÌÌÒÒÒÕÕÕÕÕÕÕÕÕØØØÈÈÈÈÈÈÅÅÅ___½½½äääËË˺ººÕÕÕ×××ÔÔÔÔÔÔ×××ËËËÏÏÏÖÖÖÕÕÕÔÔÔÙÙÙÎÎι¹¹ÚÚÚ€€€‚‚‚åååÖÖÖ½½½ÇÇÇÚÚÚÕÕÕÕÕÕ×××ËËËžžžfff»»»æææ¿¿¿››››››ÍÍÍÙÙÙÕÕÕØØØÌÌÌÐÐÐØØØÕÕÕÚÚÚÀÀÀ———¤¤¤~~~ƒƒƒçççÓÓÓ¥¥¥˜˜˜³³³ÙÙÙÔÔÔÝÝݲ²²ŒŒŒ¸¸¸ÃÃÃÏÏÏ©©©½½½LLL¯¯¯«««ÒÒÒÎÎÎÑÑÑÆÆÆÊÊÊÐÐÐÏÏÏËËË®®®•••OOO½½½³³³ØØØ®®®ÂÂÂqqq|||µµµÇÇÇØØØÝÝÝ´´´hhhÃÃ÷··ËË˨¨¨ËËË^^^×××­­­ÌÌÌÊÊÊÍÍÍÃÃÃÆÆÆÌÌÌÌÌÌÅÅű±±ÓÓÓZZZ©©©«««ÑÑÑ­­­×××zzz¤¤¤½½½ÂÂÂÙÙÙÚÚÚÀÀÀ‰‰‰sssÍÍÍááẺºŽŽŽ………‘‘‘éééÒÒÒÙÙÙÍÍÍÑÑÑØØØÕÕÕãã €{{{šššÃÃÃèèè³³³xxx€€€ššš¯¯¯×××ÔÔÔØØØÉÉÉÃÃæ¦¦eeeÔÔÔÜÜÜÁÁÁ´´´ÄÄÄooo›››äääÒÒÒÊÊÊÎÎÎÔÔÔããã………ÊÊÊ´´´ÈÈÈããã¼¼¼aaa¹¹¹»»»¸¸¸ÕÕÕÖÖÖÕÕÕ×××ÌÌÌÐÐÐæææªªªcccÔÔÔàààÉÉÉáááÛÛÛkkk›››éééÉÉÉÑÑÑæææ~~~ƒƒƒäää×××ÈÈÈããã½½½^^^ÄÄÄçççÍÍÍ×××ÙÙÙÔÔÔÕÕÕ×××ÌÌÌÎÎÎÒÒÒãã㪪ªhhh²²²­­­···ØØØÛÛÛnnn’’’¹¹¹µµµ}}}………äääÓÓÓÏÏÏÐÐо¾¾]]]ÅÅÅááá½½½®®®°°°ËËËØØØÔÔÔ×××ÌÌÌÏÏÏØØØÒÒÒããã›››ƒƒƒŸŸŸ¸¸¸áááÆÆÆ‰‰‰mmmØØØ×××ÓÓÓÞÞÞ¹¹¹aaaÅÅÅââ⨨¨†††“““ªªªÒÒÒÖÖÖ×××ËËËÃÃÃÉÉÉÊÊÊÀÀÀ­­­ÕÕÕ???¤¤¤­­­ÌÌ̧§§ÓÓÓ}}}ÆÆÆ±±±ÊÊÊÑÑѸ¸¸444³³³ÔÔÔÈÈȰ°°¢¢¢[[[jjj®®®ÃÃÃÚÚÚ×××ÌÌÌÍÍÍÕÕÕÓÓÓÖÖÖ«««ªªª[[[“““µµµàà྾¾©©©ˆˆˆmmm¬¬¬ÇÇÇàà༼¼cccnnnÒÒÒÜÜÜ¿¿¿   fffvvv¨¨¨ÏÏÏÖÖÖ×××ÌÌÌÏÏÏ×××ÕÕÕ×××ÏÏÏŸŸŸ£££˜˜˜hhhÔÔÔÝÝÝ´´´•••¦¦¦¾¾¾äää¾¾¾___ÃÃÃßßߤ¤¤fff×××ÛÛÛ···   ¤¤¤ÄÄÄÙÙÙÔÔÔ×××ÌÌÌÎÎÎ×××ÕÕÕÔÔÔ×××ÙÙÙÃÃÃãã㪪ªcccÓÓÓâââÎÎÎÐÐÐæææ½½½^^^ÇÇÇÜÜÜÂÂÂåå奥¥eee×××àààËËËÓÓÓÙÙÙÔÔÔÕÕÕ×××ÌÌÌÎÎÎÖÖÖÔÔÔÕÕÕÕÕÕÓÓÓÉÉÉÒÒÒãã㪪ªdddÎÎο¿¿ÅÅÅ»»»___ÆÆÆÞÞÞÐÐÐÉÉÉÒÒÒãã㥥¥gggÐÐп¿¿ÅÅÅÙÙÙÕÕÕÕÕÕ×××ÍÍÍÐÐÐØØØÖÖÖ××××××ÕÕÕÉÉÉØØØÒÒÒæææ¨¨¨nnn¡¡¡«««hhhÄÄÄàààÔÔÔÖÖÖËËËØØØÒÒÒçç磣£ooo£££–––²²²ÙÙÙÔÔÔØØØÉÉÉÇÇÇÐÐÐÎÎÎÎÎÎÏÏÏÍÍÍÃÃÃÏÏÏÎÎÎÑÑѺººººº|||ddd¹¹¹ÃÃÃÐÐÐÏÏÏËË˽½½ÐÐÐÍÍÍÒÒÒ¹¹¹»»»KKKŽŽŽ²²²ÇÇÇØØØÖÖÖÐÐÐÉÉÉÍÍÍÌÌÌÌÌÌÌÌÌÌÌÌËËËÌÌÌÌÌÌÍÍÍÅÅÅÖÖÖÉÉɸ¸¸ÑÑÑÇÇÇÍÍÍÌÌÌÊÊÊÄÄÄÍÍÍÌÌÌÍÍÍÅÅÅØØØÈÈÈËËËÓÓÓÐÐÐÖÖÖÕÕÕÖÖÖØØØ×××××××××××××××××××××××××××ØØØÕÕÕ×××ÜÜÜÖÖÖØØØ××××××ØØØÙÙÙ×××××××××ØØØÔÔÔØØØ×××ÖÖÖÖÖÖÕÕÕ(  ÔÔÔÕÕÕØØØÒÒÒÑÑÑ×××ÕÕÕ×××ÖÖÖÖÖÖ×××ÕÕÕ×××ÔÔÔÕÕÕÖÖÖÈÈÈ¡¡¡ÑÑѳ³³“““ÊÊÊ×××ÍÍÍÒÒÒÒÒÒÍÍÍÖÖÖÏÏÏ•••ŸŸŸÕÕÕÃÃÓ““ÏÏÏ———ÒÒÒ§§§«««ÕÕÕÔÔÔ´´´ŸŸŸÕÕÕ€€€ÖÖÖÐÐÐÑÑÑ¢¢¢±±±ÓÓÓ­­­©©©ÕÕÕÖÖÖÖÖÖÖÖÖ±±±¦¦¦ÑÑÑÍÍÍ×××ÒÒÒ›››···åå妦¦¨¨¨ÜÜÜÌÌÌÔÔÔÔÔÔÌÌÌÛÛÛ±±±¤¤¤ÖÖÖÕÕÕÇÇǶ¶¶ààࢢ¢   ØØØÍÍÍÉÉÉÏÏÏÏÏÏÈÈÈÎÎÎ××׈ˆˆÉÉÉØØØÒÒÒÞÞÞ¬¬¬ªªªÝÝÝÖÖÖÕÕÕÏÏÏÖÖÖ×××ÕÕÕ××׿¿¿ÛÛÛÕÕÕÑÑѤ¤¤«««ÉÉÉ®®®ÒÒÒÕÕÕÎÎÎÖÖÖÏÏϲ²²œœœ¼¼¼½½½¸¸¸×××¾¾¾‘‘‘ÔÔÔ£££„„„ÉÉÉÐÐÐÆÆÆÑÑÑÄÄÄ{{{¢¢¢ÕÕÕŽŽŽ———ÓÓÓÍÍÍššš²²²ÅÅÅ¢¢¢¥¥¥ÚÚÚÓÓÓ××ןŸŸÇÇÇ­­­œœœ½½½ÖÖÖÑÑÑÙÙÙ§§§­­­ÐÐд´´¡¡¡ÄÄÄžžž¼¼¼ããã«««­­­ÎÎÎËËË×××ÐÐÐÍÍÍÒÒÒššš€€€ÑÑѪªªyyy­­­ããã”””¢¢¢ØØØ~~~ÕÕÕÐÐÐÏÏÏÕÕÕµµµ………°°°ÊÊÊ‘‘‘ÌÌÌ«««———ŸŸŸÎÎΙ™™ŸŸŸ×××ÑÑÑÓÓÓØØØÓÓÓÔÔÔ¨¨¨®®®ÓÓÓªªª¬¬¬ßßßÃÃÜœœÊÊÊÒÒÒ×××ÐÐÐÎÎÎÓÓÓÏÏÏÍÍÍ××פ¤¤ŒŒŒ¦¦¦ÚÚÚÇÇÇ×××ÁÁÁ‡‡‡¦¦¦ÕÕÕÓÓÓÐÐÐÑÑÑÐÐÐÐÐÐÏÏÏÕÕÕÆÆÆÒÒÒÐÐÐÎÎÎÏÏÏÓÓÓÍÍÍÌÌÌÔÔÔ(0` ÕÕÕÔÔÔÖÖÖÙÙÙÚÚÚÎÎÎÂÂÂ×××ÛÛÛÃÃý½½¿¿¿¦¦¦———ÑÑÑÓÓÓ™™™¨¨¨²²²˜˜˜ÇÇÇ“““®®®©©©–––ÐÐз··‘‘‘¼¼¼ÝÝÝÞÞÞ›››±±±‡‡‡hhhœœœØØØÆÆÆƒƒƒÒÒÒ222»»»ÁÁÁæææ,,,°°°ËËËÌÌÌÍÍͬ¬¬‹‹‹KKKCCC£££êêêRRR’’’­­­³³³ÏÏϹ¹¹éééGGGëëëÅÅÅUUUtttÈÈÈ}}}¥¥¥¾¾¾qqqggg¯¯¯ÜÜÜOOO¶¶¶àààbbbTTTŽŽŽçççdddmmmYYYãããIIIµµµ¢¢¢•••xxx   ¤¤¤äää```ooo@@@áááåååaaaèèènnn«««ÉÉÉAAAÄÄÄDDDeeeXXX888ßßßâââÀÀÀ^^^'''[[[FFF………ÊÊÊcccBBBŠŠŠ¸¸¸žžž{{{\\\´´´€€€„„„šššHHHòòòiiiñññŸŸŸ!!!>>>ììì666îîî|||VVV¡¡¡ººº___‚‚‚lllWWWªªª§§§vvv”””sss]]]kkk(((999QQQwww"""fff:::NNN~~~;;;yyy†††     !"#$%&'% () *(+,!-(.//0+10000001+(1//(23456 789:;<=>?@.6ABCADDDDAE4DA;‰> |/+ Mk +xkpI!q /YЇ‹Œr Žk DN[2(( E‘ZV4‹’90%T>K2ˆ“b;” k€‹•–N—H]FFK$A~Lƒf;Y#2Tnc v˜.•~(dyO.Yˆ$&0V$‰…f1 p,™šc+(z{>r(dy_Vpk0p$D0$‰…RR™šc/z3f dy_^($<$0$‰›KœiR™nM5{R,y_^0•($0(4ž;= ,T”M ?{Rcy—^(MŸ* $D<$\  e}i2Olˆ *$$yORŸi¡¢$ D&&x]£r~A¤r91AAk”¥ k6G¦"”9J $&11kc]§h Ÿ0$¨¡ /0Ky©ªx“mBZk$D\]Es];#«B+RSeKŸ‚eTJˆ$0ˆ6•4›R2ˆF(dy—,rV¬0/]Y|$0 X‰…f1.(dy_^ R¬1K}G$0x‰…f0(dy_^ (,¬1<($01&$($‰ƒ>&h,O_^ (,¬0 =K$01&$$Lghh]uSV (,jJˆi<DVb­G‡ D$®#g›]#+<00000& <000 vB/00 i10/h/¯¨pˆkxiDDDr$GDXDiriNxXD<$$$$$$$$$$$$$p$$$$$$$$$$K$( @ÕÕÕÖÖÖØØØÔÔÔÙÙÙÒÒÒÉÉÉÑÑÑÇÇÇ×××ÆÆÆËËËÊÊʦ¦¦´´´ÄÄÄœœœ¡¡¡ÎÎά¬¬¨¨¨···ÂÂÂsss«««ÁÁÁ§§§ºººMMM­­­®®®ÓÓÓÍÍÍÐÐÐÏÏÏÌÌÌ©©©fff{{{]]]±±±^^^¤¤¤cccÅÅÅqqqšššžžžjjjªªªÛÛÛ¿¿¿†††åå凇‡„„„½½½äääÈÈÈbbbiiièèè}}}ˆˆˆ¯¯¯¹¹¹æææ|||²²²áááddd¶¶¶¼¼¼çççzzzâââÚÚÚeeeÝÝÝŠŠŠyyy¾¾¾ßßßããã```hhh¢¢¢ÜÜÜuuuWWWKKK[[[³³³ààà€€€ƒƒƒÞÞÞ………‚‚‚___»»»›››ÀÀÀ———~~~¥¥¥˜˜˜ŒŒŒ¸¸¸ÃÃÃLLL•••OOOµµµZZZ‰‰‰ŽŽŽ‘‘‘éééxxxoooaaakkknnn’’’°°°ŸŸŸmmm“““???444   vvv£££ggg–––         !!!!" #$%&'(")* +,# -.#/'01,23456789:;<( ,=> ?@A BC@DEF '3# G C HI #!J@KL;L )9L;"M N >   OPQL""'RS "; G #T?UOV3F#! M WX YZ;,!I[(,;  ;;R; ##\# #!Y ]^S! _`a # b)9 #! ;:8c " "_ )9_  "# U8dC#;;,e9:   "BM`d59M /%fC3ghg #!Mij*kaJlhm^OEnop"$9qA !" rs9^-DtOWp  ) # p ##,(u$ K*9Miv Fwcxyz U`T&.p>^{`.A p NY|g: U8c ;UI}Bfo #!C1+_F2~gzCka: ;U9)J  #U1WE2€Bt?c:"!R',F9  #"Ug‚aƒoF v„x‚ bB},L4…1 p i†*#?8 ( o‡^;X]0pM # 1]…t_R$@„_I+‚Y3ˆ%‰" #" "ƒŠmWOr R:RepS*% 2ˆ* #  pU1+L!C9)Y5lN _  #U1G3,fe b!Ul‹!3, ! CW_ JŠ|ŠŒE!" p"DGBp!" 9! Bf\wE! #### ## ,o #  # ,; !  Y   ( ÔÔÔÕÕÕØØØÒÒÒÑÑÑ×××ÖÖÖÈÈÈ¡¡¡³³³“““ÊÊÊÍÍÍÏÏÏ•••ŸŸŸÃÃ×——§§§«««´´´€€€ÐÐТ¢¢±±±ÓÓÓ­­­©©©¦¦¦›››···åå娨¨ÜÜÜÌÌÌÛÛÛ¤¤¤ÇÇǶ¶¶ààà   ÉÉÉÎÎΈˆˆÞÞÞ¬¬¬ªªªÝÝÝ¿¿¿®®®²²²œœœ¼¼¼½½½¸¸¸¾¾¾‘‘‘£££„„„ÆÆÆÄÄÄ{{{ŽŽŽšššÅÅÅ¥¥¥ÚÚÚÙÙÙžžžãããËËËyyy”””~~~µµµ………°°°™™™ßßߌŒŒÁÁÁ‡‡‡       !"#$$%&'()* + ,-+./01 23%&+4, 56789:;<=+>?@A B5CDE2'68F?G7H,I B0JHKL MNO ;$,P"40/Q6 , &RE'ST >,  $(0`€€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿw÷w÷÷÷÷wwÿ÷‡÷÷÷wxÿ÷÷÷÷÷ÿ÷www÷wøwx‡÷ÿÿÿ÷÷w‡ø÷x‡ÿ‡ð‡w÷÷÷w÷ÿww÷‡wøw÷÷øwwwˆ÷÷w‡‡wø÷xw÷p÷÷ÿø‡÷÷wwxxxˆw‡÷÷÷÷wˆÿxxwww÷wˆÿ€ÿ÷÷÷x÷÷xx÷÷ø÷÷ÿ÷÷÷÷ÿˆ÷÷w÷÷ÿ÷p÷÷ÿwð÷÷ÿðw÷‡w÷÷÷ˆw÷÷÷÷ÿ€w÷÷÷wÿ÷÷÷÷x÷÷÷wðw÷ø‡ÿw÷ÿwˆ÷÷ˆ÷ÿÿ€÷ÿw÷÷÷÷ð‡÷ð÷wø÷ww÷÷w÷wwˆww÷÷wÿ€÷÷÷ÿww÷wÿ÷ÿˆ÷÷÷÷ÿwÿ÷÷÷÷÷ø÷÷÷÷p÷÷÷÷÷€÷÷wÿ÷ø‡÷÷÷÷÷w÷x‡÷÷ˆw÷÷÷÷÷÷÷÷÷ˆw÷÷÷÷÷÷÷÷÷÷ÿ÷x‡÷÷÷÷p÷w÷÷÷wÿ€ÿw÷wx÷÷wwÿÿ÷ÿw÷÷ÿwwxwøwwÿwxÿxw‡ww‡wˆwÿww‡xw÷p‡ÿ÷ÿÿ÷øw÷€‡wxw‡÷øw÷wwwwxˆ÷wøwøwøw÷÷÷÷÷wð‡÷xwxxwÿ‡pw‡ˆxw‡ˆwwp÷÷‡xÿww÷ø‡w‡÷ÿˆwx÷wÿ€÷÷ð÷ÿ€÷wÿp‡w÷÷øw÷÷ÿ÷÷÷ø‡÷÷÷ÿ÷÷÷÷ˆÿ÷p€ÿwÿp÷÷÷÷÷÷øxw÷ÿ÷‡ø÷÷÷ÿÿwwÿwÿˆwxÿxw€wðøwxw÷÷÷÷wx‡øˆˆw÷÷÷÷÷÷‡xw÷xw÷wøwÿp÷÷ww÷wxwwÿˆøwwÿ€÷w÷w‡w÷÷÷wxw÷wxˆ÷ÿðˆÿwwˆww÷xˆ‡wøxˆ‡÷ÿÿˆ÷xxwÿ÷ÿwwˆÿw‡wpwø÷÷x‡÷÷÷÷÷xÿÿÿÿwÿˆÿww÷÷ˆ÷wp÷÷wø÷ÿ÷÷÷wÿx÷÷‡ÿÿ€÷ÿ÷÷÷÷÷÷ÿw‡pw÷w÷÷ˆxw÷wÿ÷w÷÷x‡wˆ÷÷÷ˆwxÿw÷÷÷ÿ÷wxˆ÷ÿ÷÷÷ÿ‡w÷÷÷÷ww÷€øwwww÷wˆww÷w÷ÿw÷÷÷÷ÿw÷÷w÷( @€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ÷÷÷÷wÿwwww÷xwwxwwwww‡wxwwx‡ww÷w÷÷‡wxxxø‡ww‡www‡wxˆwxw÷ˆ‡wxww÷ˆwxˆwwwx‡wˆww÷÷xw‡w÷ˆ÷xÿwwÿˆwwxwwwˆ÷ww÷wwøwwˆ÷÷x÷÷ww÷‡wxwwˆ÷wwÿw÷wxwwwwxwwwwwwwwwx‡÷w÷÷ˆ÷÷÷w÷xw÷wwxww÷wwww÷ww÷ˆwwwww÷ˆwwxwwwÿ÷÷ww‡÷w÷wˆ÷w‡÷www÷‡xwxxwxw÷x‡wwwxpww‡ˆwxxxx‡www÷wø‡w‡wx‡÷xxwwøˆ‡ˆˆwwˆwxxw÷wxxwø‡ww÷w‡÷wˆwø‡÷xwwxwø‡wxwww‡wwx‡ˆˆˆ‡wwˆxˆwwwwx‡wwˆww‡wwˆwwwwx‡wwˆxw€‡wˆˆw÷wxˆxˆw÷ˆ÷wˆwwwwx‡÷wˆwø‡÷‡w÷ÿwwxww‡÷ˆwÿwwwwwø‡xˆ÷wwø‡w÷ÿw÷wx‡‡÷÷÷ˆˆwwww÷wwˆwww÷÷wwww÷w÷wwwwwwwwww( €€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿwww÷wx÷w÷÷wwxx‡wwxx‡ww÷‡ww÷øxw‡wwxwwøww÷w÷‡www÷÷xwwxw‡wwˆøwwwwøwxwxww‡øwwxxw‡x‡ww‡xw‡÷‡÷ww‡w‡wwxwxwwwww÷puzzles-20170606.272beef/icons/sixteen.ico0000644000175000017500000006117613115373745017176 0ustar simonsimon 00 ¨%–  ¨>& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕØØØÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔ×××ÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕØØØÊÊÊÛÛÛÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÛÛÛÌÌÌÕÕÕ×××ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔßßߘ˜˜kkk»»»ÞÞÞÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÜÜÜÆÆÆqqqŒŒŒÛÛÛÖÖÖÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÞÞÞ”””†††®®®vvv¶¶¶ßßßÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÜÜÜÃÃÃvvv¨¨¨ˆˆˆÚÚÚÖÖÖÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÛÛÛšššŠŠŠ²²²«««¬¬¬~~~¹¹¹ÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÄÄÄ~~~¦¦¦­­­±±±’’’×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÝÝÝ©©©ZZZ«««ªªª¥¥¥xxxdddÍÍÍ×××ÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖoooppp¢¢¢«««¬¬¬”””]]]˜˜˜ÞÞÞÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÑÑÑÒÒÒ‚‚‚¦¦¦°°°’’’›››ÙÙÙÑÑÑÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÒØØØ¨¨¨‰‰‰°°°«««ÊÊÊÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÚÚÚŠŠŠ©©©´´´•••¤¤¤áááÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔßßß±±±ŽŽŽ³³³®®®†††ÓÓÓ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙ‚‚‚˜˜˜¤¤¤†††   ßßßÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÝÝÝ®®®€€€¤¤¤|||ÑÑÑÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÚÚÚ   ‹‹‹“““‰‰‰»»»ÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÄÄÄŠŠŠ’’’˜˜˜×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÕÕÕÝÝÝßßßÞÞÞàààÚÚÚÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÕÕÕØØØàààÞÞÞßßßÞÞÞÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÓÓÓÓÓÓÒÒÒÓÓÓÑÑÑÑÑÑÑÑÑÐÐÐÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÒÒÒÒÒÒÐÐÐÑÑÑÑÑÑÑÑÑÓÓÓÓÓÓÓÓÓÓÓÓÒÒÒÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ××׿ææçççæææèèèèèèæææççççççççççççççççççççççççççççççççççççéééççççççççççççççççççççççççæææéééàààÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÅÅÅÅÅÅÅÅÅÁÁÁàààÆÆÆÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÆÆÆÀÀÀÓÓÓ×××ÁÁÁÆÆÆÅÅÅÅÅÅÅÅÅÅÅÅÅÅÅÃÃÃÐÐÐêêêÒÒÒÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔ×××ÁÁÁâââ×××ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÖÖÖÌÌÌÌÌÌäääÑÑÑÕÕÕÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÒÒÒÝÝÝêêêÒÒÒÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÃÃÃããã×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÍÍÍÎÎÎäääÒÒÒÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÞÞÞêêêÒÒÒÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÞÞÞÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÃÃÃããã×××ÕÕÕÕÕÕÔÔÔÑÑÑÒÒÒÔÔÔÒÒÒÒÒÒÕÕÕÕÕÕ×××ÍÍÍÎÎÎäääÒÒÒÕÕÕÕÕÕÒÒÒÑÑÑÓÓÓÔÔÔÏÏÏÜÜÜêêêÒÒÒÖÖÖÕÕÕÖÖÖ×××ÒÒÒ˜˜˜×××ÖÖÖÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÃÃÃããã×××ÕÕÕÔÔÔÛÛÛæææäääÛÛÛåååãããÖÖÖÕÕÕ×××ÍÍÍÎÎÎäääÒÒÒÕÕÕÕÕÕâââçççÞÞÞØØØäääæææéééÒÒÒÖÖÖ×××ÑÑÑÒÒÒËËËeeeŽŽŽÚÚÚÖÖÖÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔÕÕÕØØØÃÃÃããã×××ÓÓÓÜÜܰ°°hhhuuu¶¶¶sssÒÒÒÖÖÖÖÖÖÍÍÍÎÎÎäääÑÑÑÖÖÖÕÕÕdddÉÉÉkkk°°°ïïïÏÏÏÞÞÞ˜˜˜www†††{{{”””’’’ˆˆˆÛÛÛ×××ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕ×××ÍÍÍÊÊÊ××××××ÃÃÃããã×××ÔÔÔ×××ÍÍÍ777hhhÀÀÀ£££444|||åååÔÔÔÍÍÍÎÎÎäääÒÒÒÔÔÔÛÛÛ‹‹‹ ÁÁÁMMM[[[>>>ãããÒÒÒÞÞÞžžž®®®¬¬¬¬¬¬±±±ŒŒŒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÃÃÃããã×××ÕÕÕÐÐÐîîîbbb’’’ÐÐÐ^^^NNN¨¨¨ÝÝÝÕÕÕÍÍÍÎÎÎäääÒÒÒÔÔÔÞÞÞÂÂÂAAAäää---KKKtttêêêÐÐÐÞÞÞ’’’¤¤¤³³³±±±«««¬¬¬¨¨¨qqqÌÌÌ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÃÃÃããã×××ÓÓÓÛÛÛ°°°”””ÀÀÀ___ÆÆÆØØØÖÖÖÍÍÍÎÎÎäääÑÑÑÕÕÕØØØ\\\...ãããyyy666˜˜˜íííÏÏÏàààŠŠŠ}}}ŽŽŽ‡‡‡¢¢¢§§§vvvÅÅÅÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÃÃÃããã×××ÔÔÔ×××ÈÈÈ©©©ËËËÓÓÓ¯¯¯¢¢¢ÊÊÊ×××ÖÖÖÍÍÍÎÎÎäääÒÒÒÕÕÕÖÖÖ²²²¶¶¶×××ÛÛÛ¬¬¬»»»ìììÑÑÑØØØÄÄÄ«««±±±¦¦¦rrr}}}ÂÂÂÜÜÜÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÃÃÃããã×××ÕÕÕÔÔÔØØØßßß×××ÕÕÕÞÞÞááá×××ÔÔÔ×××ÍÍÍÎÎÎäääÒÒÒÖÖÖÕÕÕÝÝÝÜÜÜÕÕÕÔÔÔÜÜÜåååéééÒÒÒÕÕÕÙÙÙÞÞÞßßßÙÙÙnnnÄÄÄÝÝÝÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕØØØÃÃÃããã×××ÕÕÕÕÕÕÕÕÕÓÓÓÕÕÕÕÕÕÓÓÓÓÓÓÕÕÕÕÕÕ×××ÍÍÍÎÎÎäääÒÒÒÖÖÖÕÕÕÔÔÔÔÔÔÕÕÕÕÕÕÒÒÒÝÝÝêêêÒÒÒÖÖÖÔÔÔÓÓÓÔÔÔÒÒÒÖÖÖÙÙÙÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÒÒÒÖÖÖÀÀÀáááÕÕÕÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÕÕÕËËËÌÌÌãããÏÏÏÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÑÑÑÜÜÜêêêÒÒÒÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÜÜÜÞÞÞáááÍÍÍæææáááÞÞÞßßßßßßßßßßßßßßßÞÞÞßßßÜÜÜÞÞÞàààØØØÔÔÔëëëÜÜÜßßßßßßßßßßßßßßßßßßÝÝÝæææêêêÒÒÒÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÛÛÛæææ×××ÚÚÚÕÕÕÖÖÖÙÙÙØØØØØØØØØØØØØØØØØØÙÙÙ×××èèèÜÜÜØØØØØØÓÓÓÙÙÙØØØØØØØØØØØØØØØØØØÙÙÙÖÖÖâââêêêÒÒÒÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÞÞÞãããÃÃÃÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÆÆÆÉÉɺººÕÕÕÒÒÒÄÄÄÇÇÇÈÈÈÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÅÅž¾¾çççÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÝÝÝìììÕÕÕÙÙÙØØØØØØØØØØØØØØØØØØØØØØØØØØØÛÛÛÊÊÊÙÙÙáááÖÖÖØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÇÇÇçççÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕ×××ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÝÝÝêêêÒÒÒÕÕÕÕÕÕÔÔÔÔÔÔÔÔÔÕÕÕÔÔÔÔÔÔÕÕÕÔÔÔØØØÆÆÆØØØÞÞÞÒÒÒÕÕÕÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÔÔÔÅÅÅçççÓÓÓÖÖÖÔÔÔÓÓÓÓÓÓÑÑÑÍÍÍÛÛÛÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÝÝÝêêêÒÒÒÖÖÖÕÕÕÙÙÙÚÚÚÚÚÚÓÓÓØØØÖÖÖÔÔÔÕÕÕØØØÇÇÇØØØßßßÓÓÓÕÕÕÖÖÖÚÚÚÚÚÚØØØØØØÚÚÚÙÙÙÕÕÕÕÕÕÔÔÔÅÅÅçççÓÓÓÕÕÕÚÚÚàààáááÚÚÚddd¹¹¹ÞÞÞÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÝÝÝêêêÒÒÒÕÕÕ×××ÆÆÆÄÄÄÁÁÁÜÜÜÉÉÉÑÑÑÚÚÚÔÔÔØØØÇÇÇØØØßßßÓÓÓÖÖÖÑÑÑÂÂÂÃÃÃÉÉÉÍÍÍÀÀÀÄÄÄ×××ÕÕÕÔÔÔÅÅÅçççÒÒÒÚÚÚ»»»œœœ¤¤¤˜˜˜xxx}}}¶¶¶ßßßÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÝÝÝêêêÒÒÒÔÔÔÝÝÝlll¦¦¦777IIIÇÇÇØØØ×××ÇÇÇØØØßßßÒÒÒØØØÊÊÊBBB&&&«««///...“““ÛÛÛÓÓÓÔÔÔÅÅÅçççÐÐÐßßߌŒŒ„„„•••¥¥¥¬¬¬vvvºººÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÝÝÝêêêÒÒÒÖÖÖÔÔÔããã===ÇÇÇTTT‘‘‘[[[ˆˆˆãããÖÖÖÇÇÇØØØßßßÓÓÓÒÒÒèèè’’’VVVñññ­­­JJJ¿¿¿ÚÚÚÔÔÔÔÔÔÅÅÅçççÑÑÑÞÞÞ“““¤¤¤´´´±±±ªªª«««®®®lllÊÊÊØØØÔÔÔÕÕÕÕÕÕÕÕÕÓÓÓÝÝÝêêêÒÒÒÕÕÕØØØººº(((ÁÁÁeeefffDDD˜˜˜áááÖÖÖÇÇÇØØØßßßÒÒÒÕÕÕÙÙÙfffUUUÙÙÙ¿¿¿YYYYYYæææÒÒÒÔÔÔÅÅÅçççÑÑÑßßß™™™©©©¦¦¦«««²²²†††˜˜˜ØØØÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÝÝÝêêêÒÒÒÔÔÔÝÝÝ’’’MMMÈÈÈÉÉÉXXXvvv×××ÔÔÔØØØÇÇÇØØØßßßÒÒÒØØØÉÉÉUUU‡‡‡ÚÚÚlllWWW²²²ÛÛÛÔÔÔÔÔÔÅÅÅçççÑÑÑÝÝÝ   }}}ŠŠŠ~~~ŠŠŠ“““ÞÞÞÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÝÝÝêêêÒÒÒÖÖÖÔÔÔÝÝÝãããÖÖÖØØØãããáááÕÕÕÔÔÔØØØÇÇÇØØØßßßÓÓÓÕÕÕ×××ãããÝÝÝÕÕÕàààãããÜÜÜÔÔÔÕÕÕÔÔÔÅÅÅçççÓÓÓÕÕÕÚÚÚÙÙÙÚÚÚÔÔÔbbb˜˜˜ÞÞÞÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÝÝÝêêêÒÒÒÖÖÖÕÕÕÓÓÓÒÒÒÕÕÕÔÔÔÒÒÒÒÒÒÕÕÕÕÕÕØØØÇÇÇØØØßßßÓÓÓÕÕÕÕÕÕÒÒÒÓÓÓÕÕÕÓÓÓÒÒÒÔÔÔÕÕÕÕÕÕÔÔÔÅÅÅçççÓÓÓÖÖÖÔÔÔÔÔÔÕÕÕÑÑÑ©©©ÚÚÚÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÝÝÝëëëÓÓÓÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÕÕÕÙÙÙÇÇÇÙÙÙßßßÓÓÓÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÕÕÕÆÆÆçççÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÖÖÖÝÝÝÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÝÝÝéééÏÏÏÓÓÓÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÕÕÕÃÃÃÖÖÖÜÜÜÐÐÐÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÑÑÑÂÂÂçççÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÛÛÛôôôéééëëëêêêêêêêêêêêêêêêêêêêêêêêêêêêìììãããçççïïïéééêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêáááçççÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÛÛÛÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ( @ ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕØØØ×××ÖÖÖÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕØØØ××××××ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÛÛÛ›››“““ØØØ×××ÔÔÔÕÕÕÕÕÕÕÕÕÔÔÔÜÜÜ£££ÓÓÓØØØÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÙÙÙ   ˜˜˜œœœ™™™ÖÖÖÕÕÕÕÕÕÕÕÕÔÔÔÚÚÚ¨¨¨”””   ”””ÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÜÜÜ¥¥¥www­­­°°°|||šššÜÜÜÓÓÓÔÔÔÜÜܰ°°sssªªª±±±‚‚‚ÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔ×××¥¥¥¡¡¡¦¦¦ŸŸŸÖÖÖÔÔÔÕÕÕÕÕÕÔÔÔØØØ­­­œœœ¬¬¬™™™ÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓßßߨ¨¨’’’———ŸŸŸÞÞÞÓÓÓÕÕÕÕÕÕÓÓÓÞÞÞ±±±ŽŽŽ›››———ÝÝÝÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÁÁÁ¡¡¡¡¡¡»»»ÙÙÙÔÔÔÕÕÕÕÕÕÔÔÔØØØÆÆÆ¢¢¢¢¢¢¶¶¶ÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÞÞÞÝÝÝÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔ×××ÞÞÞÝÝÝÛÛÛÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÝÝÝÜÜÜàààßßßÚÚÚÛÛÛÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÜÜÜààààààÚÚÚÛÛÛÜÜÜÝÝÝÜÜÜßßßßßßÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔËËËÊÊÊËËËØØØÉÉÉÌÌÌËËËËËËËËËËËËËËËËËËÉÉÉÙÙÙÉÉÉÌÌÌËËËËËËÊÊÊÏÏÏäääÔÔÔÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÖÖÖÍÍÍßßßÕÕÕ×××ÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖ×××ÌÌÌßßßÖÖÖ×××ÔÔÔÕÕÕÕÕÕØØØåååÓÓÓÕÕÕÔÔÔÔÔÔÛÛÛÖÖÖÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÍÍÍÞÞÞÓÓÓÖÖÖâââÝÝÝÝÝÝÞÞÞÔÔÔÕÕÕÌÌÌÞÞÞÓÓÓÕÕÕáááÞÞÞØØØãããæææÒÒÒÙÙÙÝÝÝÔÔÔÓÓÓØØØÔÔÔÕÕÕÕÕÕÔÔÔÔÔÔÔÔÔÍÍÍÞÞÞÕÕÕÐÐШ¨¨©©©¨¨¨×××ÕÕÕÌÌÌÞÞÞÔÔÔÔÔÔ•••£££¿¿¿¤¤¤äääÙÙÙ¶¶¶•••———‚‚‚”””ÓÓÓ×××ÔÔÔÖÖÖÐÐÐÐÐÐÕÕÕÍÍÍÞÞÞÑÑÑßßß___ŒŒŒ   ???ÆÆÆÙÙÙËËËÞÞÞÑÑÑâââmmmaaaAAAÅÅÅââ⤤¤œœœ«««±±±   ×××ÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÍÍÍÞÞÞÓÓÓÚÚÚWWW±±±WWWeeeØØØÕÕÕÌÌÌÞÞÞÒÒÒßßßaaa¢¢¢ddd[[[ÞÞÞÝÝÝ¢¢¢›››ªªª”””£££ØØØÔÔÔÕÕÕÕÕÕÕÕÕÔÔÔÍÍÍÞÞÞÔÔÔÑÑѦ¦¦ÎÎα±±¯¯¯ÖÖÖÕÕÕÌÌÌÞÞÞÔÔÔÔÔÔ§§§ÊÊÊÍÍͱ±±ããã×××ÆÆÆ°°°¬¬¬ttt§§§ÜÜÜÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÎÎÎßßßÓÓÓ×××ßßß×××ÝÝÝÝÝÝÕÕÕÖÖÖÌÌÌÞÞÞÔÔÔÖÖÖßßßØØØÖÖÖáááæææÓÓÓØØØÞÞÞØØØ°°°ÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÓÓÓÌÌÌÞÞÞÒÒÒÔÔÔÒÒÒÔÔÔÓÓÓÒÒÒÓÓÓÕÕÕÊÊÊÝÝÝÓÓÓÕÕÕÒÒÒÔÔÔÓÓÓÕÕÕåååÓÓÓÕÕÕÓÓÓÔÔÔÜÜÜÔÔÔÕÕÕÕÕÕÕÕÕÔÔÔ×××ßßßÞÞÞØØØãããÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞààààààÞÞÞ×××âââÞÞÞÞÞÞÞÞÞÞÞÞÝÝÝâââçççÓÓÓÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÝÝÝÛÛÛÉÉÉÌÌÌËËËÌÌÌËËËÌÌÌËËËËËËÊÊÊÚÚÚÊÊÊÌÌÌËËËÌÌÌËËËÌÌÌËËËÌÌÌÈÈÈßßßÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÝÝÝãããÔÔÔÖÖÖÔÔÔÔÔÔÕÕÕÔÔÔÖÖÖ×××ËËËÞÞÞÕÕÕÖÖÖÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕØØØËËËÜÜÜÕÕÕÔÔÔÓÓÓÔÔÔÜÜÜÕÕÕÔÔÔÕÕÕÕÕÕÓÓÓÝÝÝâââÒÒÒÖÖÖàààÜÜÜÙÙÙÝÝÝÓÓÓÖÖÖËËËÞÞÞÔÔÔÕÕÕßßßÞÞÞÝÝÝàààÖÖÖÖÖÖËËËÝÝÝÔÔÔÙÙÙßßßÖÖÖšššÖÖÖ×××ÔÔÔÕÕÕÓÓÓÝÝÝâââÓÓÓÒÒÒ¡¡¡³³³ÀÀÀ¯¯¯ÛÛÛÕÕÕÌÌÌÞÞÞÔÔÔÕÕÕ¦¦¦¬¬¬¬¬¬¡¡¡ÎÎÎØØØËËËÜÜÜÚÚÚ»»»|||™™™ØØØÖÖÖÕÕÕÓÓÓÝÝÝâââÑÑÑßßß```yyymmmRRR¶¶¶ÝÝÝÊÊÊÞÞÞÒÒÒááámmmxxxŒŒŒNNNÒÒÒØØØËËËÛÛÛÝÝݤ¤¤———¦¦¦°°°œœœ“““×××ÕÕÕÓÓÓÝÝÝâââÑÑÑÞÞÞeee›››iiiRRR±±±ÞÞÞÊÊÊÞÞÞÒÒÒáááppp’’’ÉÉÉHHH½½½ÜÜÜÊÊÊÛÛÛÝÝÝ£££’’’¡¡¡­­­˜˜˜›››ØØØÕÕÕÓÓÓÝÝÝâââÓÓÓÓÓÓ–––ËË˶¶¶¡¡¡ÚÚÚÕÕÕÌÌÌÞÞÞÔÔÔÖÖÖšššÁÁÁ­­­ÔÔÔ×××ËËËÜÜÜÙÙÙÁÁÁ¦¦¦¤¤¤www   ÛÛÛÖÖÖÕÕÕÓÓÓÝÝÝâââÓÓÓ×××âââ×××ÜÜÜàààÔÔÔ×××ÌÌÌÞÞÞÕÕÕÖÖÖáááÙÙÙÝÝÝáááÕÕÕ×××ÌÌÌÝÝÝÔÔÔÙÙÙßßßØØØ¥¥¥ÙÙÙÕÕÕÕÕÕÕÕÕÓÓÓÝÝÝàààÐÐÐÓÓÓÐÐÐÒÒÒÑÑÑÐÐÐÒÒÒÓÓÓÉÉÉÜÜÜÒÒÒÓÓÓÐÐÐÒÒÒÑÑÑÐÐÐÒÒÒÔÔÔÈÈÈÜÜÜÕÕÕÔÔÔÓÓÓÔÔÔÜÜÜÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÜÜÜëëëàààââââââââââââââââââãããÚÚÚçççâââââââââââââââââââââãããÛÛÛàààÔÔÔÕÕÕÕÕÕÕÕÕÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞØØØÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ(  ÕÕÕÕÕÕØØØÔÔÔØØØÕÕÕÕÕÕØØØÔÔÔØØØÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔ×××ÃÃߟŸÁÁÁ××××××ÆÆÆŸŸŸ¾¾¾×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙ©©©———§§§×××ÙÙÙ¬¬¬———¤¤¤×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÉÉÉ›››ÇÇÇØØØ×××ÌÌÌœœœÄÄÄÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÙÙÙØØØÖÖÖÖÖÖ×××ÙÙÙÙÙÙÖÖÖ××××××ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÑÑÑÔÔÔÔÔÔ××××××ÒÒÒÔÔÔÔÔÔÖÖÖÛÛÛÜÜÜØØØ××××××ÕÕÕÕÕÕÓÓÓÖÖÖÔÔÔ¼¼¼ÂÂÂÑÑÑÖÖÖÕÕÕ¼¼¼ÂÂÂÙÙÙÃÃ䤤¾¾¾ØØØÔÔÔÒÒÒØØØÌÌÌ€€€sssÆÆÆÚÚÚÐÐÐ}}}gggÍÍÍŸŸŸ–––ŸŸŸÔÔÔÖÖÖÓÓÓÖÖÖÓÓÓÇÇÇÄÄÄÒÒÒÕÕÕÓÓÓÈÈÈÌÌÌÚÚÚËËˬ¬¬ÆÆÆØØØÖÖÖ×××ÖÖÖØØØÚÚÚÝÝÝ×××ÖÖÖØØØÙÙÙÞÞÞÝÝÝÕÕÕÙÙÙ×××ÕÕÕÚÚÚØØØÔÔÔØØØÔÔÔÐÐÐÖÖÖÔÔÔÙÙÙÕÕÕÐÐÐØØØØØØ××××××ÕÕÕÚÚÚÝÝÝÈÈÈÀÀÀÍÍÍÓÓÓÙÙÙËËË»»»ÉÉÉÔÔÔ×××ÇÇǦ¦¦ÁÁÁØØØØØØãã㢢¢fff‹‹‹ÚÚÚßßߦ¦¦yyy•••ÛÛÛ××לœœ———ŸŸŸÔÔÔÚÚÚÜÜÜÇÇÇÂÂÂÆÆÆÓÓÓØØØÈÈÈÄÄÄÆÆÆÓÓÓ×××ÉÉÉ©©©ÃÃÃØØØÚÚÚßßßÝÝÝßßßÞÞÞØØØÜÜÜÝÝÝßßßÞÞÞØØØØØØØØØÙÙÙ×××ÕÕÕÕÕÕÚÚÚÚÚÚÙÙÙÙÙÙÚÚÚÚÚÚÚÚÚÙÙÙÙÙÙÚÚÚÖÖÖÔÔÔÔÔÔÔÔÔÕÕÕ(0` ÕÕÕÔÔÔØØØ×××ÊÊÊÛÛÛÓÓÓÌÌÌßßߘ˜˜kkk»»»ÞÞÞÒÒÒÜÜÜÆÆÆqqqŒŒŒÖÖÖ”””†††®®®vvv¶¶¶ÃÃ訨ˆˆˆÚÚÚšššŠŠŠ²²²«««¬¬¬~~~¹¹¹ÙÙÙÄÄĦ¦¦­­­±±±’’’ÝÝÝ©©©ZZZªªª¥¥¥xxxdddÍÍÍoooppp¢¢¢]]]ÑÑÑ‚‚‚°°°›››‰‰‰´´´•••¤¤¤áááŽŽŽ³³³   €€€|||‹‹‹“““àààÐÐÐæææçççèèèéééÅÅÅÁÁÁÀÀÀêêêâââäääãããÎÎÎÏÏÏåååËËËeeehhhuuusssÉÉÉïïïwww{{{777£££444 MMM[[[>>>žžžîîîbbb^^^NNNÂÂÂAAA---KKKttt___\\\...yyy666ííí}}}‡‡‡§§§ÈÈȯ¯¯ìììrrrnnnëëëÇÇǺºº¾¾¾œœœlllIIIBBB&&&///„„„===TTT‘‘‘VVVñññJJJ¿¿¿(((fffDDDUUUYYY™™™XXXWWWôôô   !"#$%"&'()*+,- ./012345 !6 7 8&9):$7 ;9 < +=>?@(AB$8 ?C*D?EF7CGH; $%)- * II   777J  J777 KLKMMKLLLLLLLLLLLLNLLLLLLLLKNIOOOPIOOOOOOOOOOQPOOOOOJR PST7 *R U2VT  R  U7  2VT 7WR  UKTXU2VT SL TKN 7 YZAU9[\]^ 2VT7^1E_ 9`W ab)2U2c[QdeFX2VT GfPghiU jk!!(UJlm)Jno*2VT  pqTrstRJ )?B( !U9uQvw2VT7xyUz{ |WI}A~5OU€+Y52VT ! ‚7% (&ƒ}pU @2VT *XN $ $„%*U2VT  *R  $ Q@ YUW7R  @2K@   I…*KR K$$M$$SR  U†††††††††_‡ %†€†††††††OˆL*‚$$@†L*R  OL72*R $†$OLI@1# *R %P_7†7p_2Q%OL  ‰? 0}*R *Š‹&cŒ†† Ž yHOLJ>j/!‡*R U‘†’“hU† M)”•'–—OL7 H?=(. ‹*R ‡˜PZ™š @† $™›$—œœK OL7+&  *R *)g€_ž† _›~‹ŸOL7*C}"-H *R *UU@†U*IUOL$m *R   †  OL7+*…$†$L**NW J 7pL N…RRRRRRRRR‚UL`NRRRRRRRRRRR@L************ ************ ( @ÕÕÕÔÔÔØØØ×××ÖÖÖÛÛÛ›››“““ÜÜÜ£££ÓÓÓÙÙÙ   ˜˜˜œœœ™™™ÚÚÚ¨¨¨”””¥¥¥www­­­°°°|||šššsssªªª±±±‚‚‚¡¡¡¦¦¦ŸŸŸ¬¬¬ßßß’’’———ÞÞÞŽŽŽÝÝÝÁÁÁ»»»ÆÆÆ¢¢¢¶¶¶àààËËËÊÊÊÉÉÉÌÌÌÏÏÏäääÍÍÍåååâââáááãããæææÒÒÒÐÐЩ©©•••¿¿¿¤¤¤ÑÑÑ___ŒŒŒ???mmmaaaAAAÅÅÅ«««WWWeeeddd[[[ÎÎί¯¯§§§tttçççÈÈȳ³³ÀÀÀ```yyyRRRxxxNNNiiipppHHH½½½–––ëëë       !" #$%!& &'%( )* +,,- &(&((.#((((..(##/0/12//////1 12//0345#2#6 5& 7((&2& 8&9:; ( 5&<=>2&? @A4 -?% <<5&B#CD E+ /&B7FGHIJ7AK 5& LLM2&;#H,NO&(,  5&B PQ2&R059+"SRP# #((2&#8: & 2&;; ; 0( ; 6 #&9(&&&&..&7&&&&(7T  (12/2/2//002/2/2/2U# (9/&/  (7;. ( /&#&(./( # (7 ;VWQ2& ""P/*XX (7B#YZF[-(0&;8F\D];/(A%  (7B&M^[&0&;8_$1`a0( $ (7 b/-2&)X/ ) A  (7 7.2&8 (82( # (.< <;B<; 1; <;B<;U  c.7777779T77777779. (((((((((((((((((& ( ÕÕÕØØØÔÔÔ×××ÃÃߟŸÁÁÁÆÆÆ¾¾¾ÙÙÙ©©©———§§§¬¬¬¤¤¤ÉÉÉ›››ÇÇÇÌÌÌœœœÄÄÄÖÖÖÑÑÑÒÒÒÛÛÛÜÜÜÓÓÓ¼¼¼Â€€€sssÚÚÚÐÐÐ}}}gggÍÍÍ–––ÈÈÈËËËÝÝÝÞÞÞÀÀÀ»»»¦¦¦ãã㢢¢fff‹‹‹ßßßyyy•••       !"#$%& ' ('   '%)# &*+,-./0+12 % 0'0('0(   (0`€€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ÷÷÷ÿ÷÷ÿ÷ÿ÷÷÷÷÷÷ˆ÷ÿ÷÷÷xw÷÷÷÷÷ÿ÷ww‡ÿ÷÷ÿ‡w÷÷÷÷wÿ÷÷÷wÿøw÷÷xøw÷÷ÿ÷÷÷øw÷‡÷÷‡ÿ÷w÷ÿ÷÷÷÷ø‡ÿx‡÷÷ˆ÷wˆ÷÷÷÷xx÷÷÷÷÷w÷÷ÿ÷÷÷÷÷w÷øÿ÷ww÷÷÷÷÷÷÷÷wÿøw÷ÿøw÷w÷÷÷÷÷÷ÿxˆˆÿ÷÷÷øˆˆ÷÷÷÷÷÷÷ÿ÷÷÷÷÷÷÷÷÷w÷ÿ÷÷÷÷ÿ÷÷ÿÿww÷÷÷÷ÿw÷÷÷÷÷ÿw÷÷÷÷ÿÿÿÿÿÿ÷ÿÿÿÿÿÿ÷ÿÿ÷÷÷÷ÿ÷÷÷ÿ÷÷ÿÿ÷÷÷w÷÷÷÷÷÷ÿ÷ÿ÷÷÷÷ÿ÷wÿ÷÷÷ÿ÷÷÷÷÷÷÷ÿÿ÷÷÷÷÷÷ÿw÷÷÷÷÷ÿÿ÷÷÷÷÷÷ÿ÷÷÷÷ÿÿˆÿ÷w÷÷÷÷ÿ÷w÷ÿÿwx‡÷÷ÿ÷p€‡÷÷÷÷øwˆ÷÷‡‡‡÷÷÷÷ÿwÿ‡p€ÿ÷÷w÷÷÷÷ˆ‡÷÷ÿˆpˆ÷÷‡÷÷÷ÿx‡ˆ÷÷ÿ÷÷øÿwwx÷÷÷÷÷øx‡ÿ÷‡÷ˆ÷÷xx‡ÿwÿ÷÷÷÷÷ÿÿÿÿˆ÷÷÷÷÷÷÷ÿ÷÷÷÷÷wÿ÷ÿ÷÷÷÷÷÷÷ÿ÷÷ÿ÷÷ÿw÷÷w÷÷÷÷÷ÿ÷÷wÿ÷ÿÿ÷ÿÿ÷÷÷÷÷÷÷ÿ÷ÿÿ÷ÿÿÿÿÿÿÿÿÿÿÿÿ÷÷÷÷ÿw÷÷÷w÷w÷ÿ÷÷÷÷ÿ÷÷÷÷÷÷÷÷÷ÿÿ÷÷ÿw÷÷ÿÿ÷÷÷÷÷÷ÿ÷÷÷÷÷ÿw÷÷÷÷w÷÷÷ÿ÷÷ÿ÷÷÷ÿÿÿÿˆ÷ÿ÷ww÷÷÷ÿwwx‡ÿ÷÷÷ˆ‡‡w€ˆ÷p€‡÷ÿw÷x÷÷ÿxøˆÿ÷wx÷÷÷wÿ÷ÿpðˆ÷÷ø÷÷ÿÿ÷÷w÷w€wÿp‡€ÿ‡xw‡ÿ÷÷w÷ÿ÷ÿwww÷÷÷÷wwww÷ÿÿÿ÷ÿÿÿˆÿÿ÷÷÷÷÷÷÷÷÷÷÷÷÷÷w÷÷÷ÿ÷ÿÿ÷÷÷÷ÿ÷w÷÷÷ÿ÷÷÷÷÷wÿw÷÷÷ÿÿÿÿÿ÷÷ÿÿÿÿÿ÷ÿ÷÷÷÷÷÷ÿ÷ÿÿÿ÷ÿ÷÷÷ÿÿw÷( @€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿwwwww÷wwÿww‡÷wxw÷wwwxxw÷÷w‡‡w÷ÿww÷÷ˆx‡wwx‡ˆwwÿw÷xww÷w‡ww÷÷www÷xxww÷‡‡÷wwÿw÷øˆww‡‡wÿw÷÷www÷wÿw÷÷÷ww÷w÷ÿ÷ÿw÷÷÷÷÷w÷wwwww÷w÷wwÿ÷w÷w÷w÷ww÷÷ww÷www÷w÷÷÷w÷÷÷÷wwwww‡÷÷wwxˆwˆxw÷‡ˆww÷‡ˆ÷wˆpxww‡w÷ø‡ˆpwøˆˆwww÷wwww÷www÷w‡ÿwÿ÷÷÷÷wÿwwwwww÷wwwww÷w÷ÿw÷÷÷÷÷ÿÿÿ÷÷÷ÿww÷wwww÷www÷w÷w÷÷÷ww÷wwwww÷÷÷w÷÷w÷wÿ÷wwwwÿwwÿ÷ww÷w‡÷÷wˆpw÷xˆˆwxˆˆw÷ˆˆw÷ø‡ˆ÷÷www‡ÿˆx‡wx‡ˆ÷÷xˆxwwww÷wwww÷w‡w÷w÷÷ÿwwÿ÷ww÷ww÷w÷wwÿww÷÷÷ÿww÷÷÷÷÷w÷÷ÿw÷w÷( €€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿÿw÷www‡w÷x÷w÷wwwwww÷xw‡ÿw÷ww÷wwwwÿ÷÷÷ÿw÷÷wwwwwˆwx‡ˆw÷wwwwwÿww÷w÷÷÷ww÷w÷wwwwwx‡÷ˆw‡‡wwwÿw÷÷÷www÷÷wÿwpuzzles-20170606.272beef/icons/singles.ico0000644000175000017500000006117613115373744017162 0ustar simonsimon 00 ¨%–  ¨>& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©ªªªªªªªªªªªª©©©¨¨¨§§§§§§¨¨¨©©©ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª­­­¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯®®®ªªª©©©©©©¦¦¦­­­¶¶¶ºººººº¶¶¶­­­¦¦¦©©©©©©ªªª©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©©ªªªªªªªªªªªªªªªªªªªªªªªª«««   –––˜˜˜———————————————————————————ššš¬¬¬®®®®®®¾¾¾   hhhLLLLLLiii   ¾¾¾®®®®®®­­­¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯ªªªªªªªªªªªªªªªªªªªªª§§§···XXX½½½×××ÜÜÜsss+++WWW||||||WWW+++sssßßßÎÎεµµÖÖÖÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÔÔÔ¯¯¯©©©ªªªªªªªªªªªªªªª§§§···WWW½½½áááVVVBBBÅÅÅâââãããâââãããÆÆÆAAAYYYÙÙÙ´´´×××ÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕ¯¯¯©©©ªªªªªªªªªªªªªªª§§§···WWWÍÍÍ~~~===ãããâââßßßÛÛÛßßßØØØÚÚÚäää>>>vvvÄÄÄÔÔÔÕÕÕÔÔÔÙÙÙßßßÜÜÜÞÞÞßßßÖÖÖÕÕÕÕÕÕÔÔÔ¯¯¯©©©ªªªªªªªªªªªªªªª§§§···WWW¹¹¹444ºººää䟟Ÿ777(((===¯¯¯ÙÙÙÛÛÛ¾¾¾,,,°°°ØØØÒÒÒßßß›››!!!444###+++ÃÃÃÙÙÙÔÔÔÔÔÔ¯¯¯©©©ªªªªªªªªªªªªªªª§§§···WWW***LLLÞÞÞÛÛÛkkk”””ÐÐÐÔÔÔàààHHHáááÑÑÑÛÛÛ¶¶¶‚‚‚ËËË×××ÕÕÕÔÔÔ¯¯¯©©©ªªªªªªªªªªªªªªª§§§···WWW000cccdddæææÒÒÒÖÖÖàààõõõ\\\ÂÂÂ×××åååbbbiiiæææÒÒÒÓÓÓÝÝÝÅÅÅ000:::ØØØÛÛÛÓÓÓÕÕÕÔÔÔ¯¯¯©©©ªªªªªªªªªªªªªªª§§§···WWW///gggaaaãããÜÜÜ¥¥¥444\\\ÛÛÛÑÑÑååå___lllæææÒÒÒÔÔÔØØØéééããã)))000ÙÙÙÕÕÕÕÕÕÔÔÔ¯¯¯©©©ªªªªªªªªªªªªªªª§§§···WWW'''CCCÚÚÚÞÞÞ¢¢¢WWWsssºººÙÙÙÒÒÒÞÞÞ===ßßßÒÒÒÜÜÜ«««¸¸¸444ÍÍÍØØØÔÔÔÔÔÔ¯¯¯©©©ªªªªªªªªªªªªªªª§§§···WWWÃÃÃ:::   ííí¤¤¤&&&]]]ÙÙÙââ⤤¤111ºººÖÖÖÓÓÓÝÝݪªª&&&‡‡‡ÛÛÛÓÓÓÕÕÕÔÔÔ¯¯¯©©©ªªªªªªªªªªªªªªª§§§···WWWÊÊÊŸŸŸ'''ËËËäääÎÎÎÉÉÉÉÉÉÑÑÑæææÊÊÊ***———ÁÁÁÔÔÔÕÕÕÔÔÔÚÚÚÚÚÚÎÎÎÖÖÖÞÞÞÕÕÕÕÕÕÕÕÕÔÔÔ¯¯¯©©©ªªªªªªªªªªªªªªª§§§···XXX»»»äää‚‚‚'''———ÔÔÔããããããÔÔÔ–––&&&………ÜÜܳ³³ÖÖÖÔÔÔÕÕÕÔÔÔÔÔÔ×××ÕÕÕÓÓÓÕÕÕÕÕÕÕÕÕÔÔÔ¯¯¯©©©ªªªªªªªªªªªªªªª§§§···WWW¿¿¿ÖÖÖãã㤤¤@@@EEE\\\\\\EEE@@@£££æææÎÎζ¶¶ØØØÖÖÖ××××××ÖÖÖÖÖÖÖÖÖ××××××ÖÖÖ×××ÖÖÖ¯¯¯©©©ªªªªªªªªªªªªªªª©©©­­­–––€€€ƒƒƒ’’’~~~OOO666:::[[[‰‰‰‰‰‰¯¯¯¶¶¶°°°ÍÍÍÀÀÀggg***+++gggÁÁÁÍÍͱ±±´´´®®®¶¶¶µµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµµ¬¬¬ªªªªªªªªªªªªªªªªªª«««¦¦¦ÁÁÁÞÞÞããã444SSSmmmjjjGGG:::¢¢¢êêêÌÌ̶¶¶ÐÐÐÛÛÛ………)))IIIooooooIII)))………ÝÝÝÈÈÈ´´´ÐÐÐÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÎÎή®®©©©ªªªªªªªªªªªªªªª«««¦¦¦½½½àààUUU===»»»ÞÞÞãããßßßÚÚÚ¡¡¡&&&†††×××´´´çççmmm333±±±ÛÛÛààààààÛÛÛ±±±222pppÝÝݳ³³ØØØÖÖÖ×××ÕÕÕÓÓÓÓÓÓÓÓÓÓÓÓÖÖÖÖÖÖ×××ÖÖÖ¯¯¯©©©ªªªªªªªªªªªªªªª«««¤¤¤ÎÎÎvvvAAAäääÛÛÛÐÐÐÓÓÓáááÖÖÖãããÉÉÉ(((˜˜˜ÏÏÏŽŽŽ000ÙÙÙããããããááááááãããâââØØØ111‡‡‡ÃÃÃÔÔÔÕÕÕÔÔÔÚÚÚåååãããæææååå×××ÔÔÔÕÕÕÔÔÔ¯¯¯©©©ªªªªªªªªªªªªªªªªªª«««°°°333ÆÆÆÛÛÛ××׿ææÁÁÁ>>>µµµÛÛÛããã™™™777ÂÂÂ666¯¯¯æææ¸¸¸???DDDBBBCCC¼¼¼äää±±±...µµµ×××ÒÒÒÞÞÞ£££>>>JJJ777@@@ÅÅÅØØØÔÔÔÔÔÔ¯¯¯©©©ªªªªªªªªªªªªªªª¨¨¨µµµpppZZZäääÓÓÓ[[[333### ¿¿¿ÚÚÚÒÒÒ@@@hhhNNNÜÜÜÖÖÖÅÅÅ{{{ÈÈÈÕÕÕßßßBBB‡‡‡àààÑÑÑÝÝÝ«««kkknnnÈÈÈØØØÕÕÕÔÔÔ¯¯¯©©©ªªªªªªªªªªªªªªª§§§ºººLLL|||äääÙÙÙ(((HHHlllWWWÎÎÎÔÔÔßßß\\\+++pppäääÑÑÑÖÖÖììì333===ðððÕÕÕÑÑÑæææaaajjjæææÒÒÒÓÓÓÞÞÞµµµ TTTæææÙÙÙÔÔÔÕÕÕÔÔÔ¯¯¯©©©ªªªªªªªªªªªªªªª§§§ºººLLL}}}âââÝÝÝ™™™999±±±¥¥¥æææÏÏÏààà]]]+++pppäääÑÑÑÖÖÖâââ...666ÞÞÞÓÓÓÒÒÒæææaaajjjæææÒÒÒÔÔÔØØØéééÑÑÑCCCÜÜÜÔÔÔÕÕÕÔÔÔ¯¯¯©©©ªªªªªªªªªªªªªªª¨¨¨µµµpppZZZäääÏÏÏäääaaa!!!”””áááÒÒÒÓÓÓ@@@hhhOOOÝÝÝÔÔÔÊÊʼ¼¼***777àààÓÓÓÒÒÒßßßBBB†††àààÒÒÒÛÛÛ´´´›››ÒÒÒBBBÍÍÍØØØÔÔÔÔÔÔ¯¯¯©©©ªªªªªªªªªªªªªªªªªª«««¯¯¯333ÆÆÆÚÚÚÓÓÓÕÕÕ,,,›››ÜÜÜâââššš666ÂÂÂ666¯¯¯ççç°°°'''CCCÞÞÞÏÏÏààà³³³...µµµ×××ÒÒÒÞÞÞ¢¢¢qqqÛÛÛÔÔÔÕÕÕÔÔÔ¯¯¯©©©ªªªªªªªªªªªªªªª«««¤¤¤ÎÎÎvvvBBBåååÛÛÛÕÕÕËËË···ÍÍÍæææÉÉÉ***———ÐÐÐŽŽŽ111ÙÙÙáááÇÇÇ···ÂÂÂÓÓÓàààÙÙÙ333‡‡‡ÃÃÃÔÔÔÕÕÕÔÔÔØØØÌÌ̺ººÇÇÇÝÝÝÖÖÖÕÕÕÕÕÕÔÔÔ¯¯¯©©©ªªªªªªªªªªªªªªª«««¦¦¦¾¾¾áááUUU>>>¼¼¼ÝÝÝæææêêêÝÝÝ¡¡¡'''………××׳³³äääkkk111°°°áááìììéééÞÞÞ¯¯¯000mmmÛÛÛ³³³ÖÖÖÔÔÔÔÔÔÔÔÔÖÖÖÙÙÙÖÖÖÑÑÑÔÔÔÔÔÔÕÕÕÔÔÔ¯¯¯©©©ªªªªªªªªªªªªªªª«««¦¦¦ÀÀÀÜÜÜááá|||111UUUppplllGGG666žžžéééÊÊʹ¹¹ÙÙÙãã㎎Ž333FFFaaabbbGGG222ŽŽŽåååÏÏ϶¶¶ÚÚÚØØØ×××ÖÖÖÜÜÜâââãããßßß×××ÖÖÖÙÙÙØØØ¯¯¯©©©ªªªªªªªªªªªªªªªªªª©©©²²²¸¸¸´´´ÓÓÓººº\\\(((...uuuËËËËË˳³³µµµ°°°ÀÀÀ¼¼¼ÌÌÌ¿¿¿ˆˆˆeeeeeeˆˆˆ¿¿¿ÌÌ̽½½»»»®®®¹¹¹µµµÀÀÀÅÅŤ¤¤†††ƒƒƒšššÀÀÀÄÄͶ¶¸¸¸­­­ªªªªªªªªªªªªªªªªªª«««¨¨¨¹¹¹ËËËÖÖÖˆˆˆ///EEE]]][[[::::::¦¦¦ÖÖÖËËËvvv )))//////)))(((­­­ÊÊÊÕÕÕ©©©;;;000IIIKKK888---ŠŠŠ×××ÈÈÈ®®®©©©ªªªªªªªªªªªªªªª«««¦¦¦¾¾¾çççooo111¤¤¤ÒÒÒÝÝÝÜÜÜÐÐЉ‰‰&&&œœœçççiii­­­èèè›››&&&ŠŠŠÏÏÏÞÞÞáááÔÔÔ¥¥¥111qqqããã­­­©©©ªªªªªªªªªªªªªªª«««¤¤¤ÍÍ͈ˆˆ222ØØØëëëçççåååààà×××èèèµµµ"""¸¸¸ttt ······"""¶¶¶êêêèèèåååãããèèèæææ×××222………½½½¦¦¦ªªªªªªªªªªªªªªªªªª©©©···222¹¹¹äää›››\\\VVVÏÏÏÒÒÒèè臇‡KKKyyy ¼¼¼LLL‡‡‡ëëëÅÅÅ```[[[aaaTTT³³³ååå¹¹¹...¦¦¦«««ªªªªªªªªªªªªªªª¨¨¨´´´xxxSSSâââÙÙÙdddGGGSSSGGGÝÝÝÔÔÔÏÏÏ@@@XXX–––<<<ÏÏÏØØØÊÊÊiii XXX¹¹¹×××ãããPPPoooµµµ¨¨¨ªªªªªªªªªªªª§§§ºººNNN{{{äääÑÑÑ××׿ææäää'''+++ÜÜÜÒÒÒßßßXXX:::rrrNNNáááÒÒÒÔÔÔñññRRR"""êêêÙÙÙÑÑÑäääzzzNNNººº§§§ªªªªªªªªªªªª§§§ºººKKK~~~åååÐÐÐááálll ¥¥¥ÞÞÞÐÐÐáááZZZ777oooPPPäääÒÒÒÓÓÓãããIIIÖÖÖÔÔÔÒÒÒååå~~~KKKººº§§§ªªªªªªªªªªªª¨¨¨¶¶¶iii```äääÒÒÒÏÏϳ³³˜˜˜KKKâââÑÑÑÕÕÕGGGMMM‰‰‰AAAÖÖÖÕÕÕÏÏÏÔÔÔJJJÙÙÙÕÕÕÑÑÑäää^^^ccc···¨¨¨ªªªªªªªªªªªªªªª¬¬¬¨¨¨444ÌÌÌää䊊Š***vvvÛÛÛßßߤ¤¤>>>sss ¶¶¶>>>£££æææ¿¿¿111(((ÖÖÖÓÓÓ×××ÐÐÐ000˜˜˜®®®©©©ªªªªªªªªªªªª«««¤¤¤ÎÎÎeeeSSSíííÏÏϦ¦¦œœœ···ØØØÞÞÞØØØ...™™™xxx ¼¼¼™™™...ÙÙÙßßß···¡¡¡®®®ÒÒÒ×××ëëëTTTbbb¾¾¾¦¦¦ªªªªªªªªªªªªªªª«««¦¦¦¿¿¿ÚÚÚBBBSSSÑÑÑîîîñññêêêââ⺺º222lllåååkkk­­­åååkkk333ºººêêêïïïíííäääÏÏÏSSSCCCÖÖÖ¯¯¯¨¨¨ªªªªªªªªªªªªªªª«««¦¦¦¿¿¿ßßßÚÚÚeee111___|||yyyRRR///ˆˆˆäääÚÚÚlll °°°ÛÛÛää䈈ˆ000RRRxxx|||```000eeeÛÛÛÚÚÚ®®®©©©ªªªªªªªªªªªªªªªªªª©©©µµµ¿¿¿¿¿¿ÎÎΨ¨¨iiiKKKNNNwww···ÍÍͼ¼¼ÁÁÁŠŠŠQQQYYYWWWWWWWWWWWWWWWWWWWWWXXXVVV]]]¬¬¬ÁÁÁ¼¼¼ÍÍÍ···wwwNNNKKKiii¨¨¨ÎÎÎÀÀÀ½½½­­­©©©ªªªªªªªªªªªªªªªªªªªªª©©©¦¦¦¦¦¦¤¤¤¬¬¬¶¶¶ºººººº´´´©©©¤¤¤§§§¦¦¦¯¯¯¸¸¸···························¸¸¸¶¶¶©©©¦¦¦§§§¤¤¤©©©´´´ºººººº¶¶¶¬¬¬¤¤¤¦¦¦§§§ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª«««««««««ªªª¨¨¨§§§§§§¨¨¨ªªª«««««««««©©©§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ªªª«««««««««ªªª¨¨¨§§§§§§¨¨¨ªªª«««««««««ªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªªª( @ ªªªªªª©©©§§§§§§§§§§§§§§§§§§§§§§§§ªªª«««ªªª¨¨¨©©©ªªª¨¨¨©©©«««ªªª««««««««««««««««««««««««ªªªªªªªªªªªª©©©¯¯¯···¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶···¬¬¬¥¥¥©©©¶¶¶®®®¬¬¬µµµ®®®¤¤¤©©©§§§§§§§§§§§§§§§§§§§§§§§§¨¨¨ªªªªªª©©©¯¯¯ŠŠŠ\\\bbbaaaaaaaaaaaaaaa___¡¡¡ÇÇÇ´´´eeeQQQSSSYYYŸŸŸÈÈȰ°°¼¼¼½½½¼¼¼»»»»»»»»»¼¼¼¾¾¾²²²¨¨¨ªªª§§§¶¶¶aaa¡¡¡ÏÏÏRRR“““ÑÑÑÐÐЦ¦¦TTT¢¢¢ÊÊÊÔÔÔØØØÜÜÜáááãããßßß×××ÜÜܾ¾¾§§§«««§§§¶¶¶bbb¡¡¡aaa«««ÞÞÞ¦¦¦½½½êêêÒÒÒQQQ§§§××××××°°°£££µµµ××××××¼¼¼§§§«««§§§¶¶¶aaannntttíí퀀€UUU'''‰‰‰ððð•••iiißßßßßßŽŽŽ>>>ˆˆˆÛÛÛÖÖÖ¼¼¼§§§«««§§§¶¶¶aaa SSS•••ããã¿¿¿ÑÑÑ>>>WWWìììµµµ___ÞÞÞÑÑÑâââ„„„LLLÑÑÑÖÖÖØØØ¼¼¼§§§«««§§§¶¶¶aaa \\\†††òòòwwwFFF···ãã㬬¬aaaàààÖÖÖ¾¾¾ØØØ>>>VVVæææÕÕÕ¼¼¼§§§«««§§§¶¶¶aaaZZZäää‘‘‘'''HHH¬¬¬óóóiii‡‡‡ÜÜÜÝÝÝ>>>777žžžÝÝÝÖÖÖ¼¼¼§§§«««§§§¶¶¶aaa§§§™™™\\\ÑÑÑßßßÙÙÙÚÚÚ€€€iiiÇÇÇÒÒÒÕÕÕÚÚÚÔÔÔÙÙÙÞÞÞÔÔÔÙÙÙ½½½§§§«««§§§¶¶¶aaa  ˜˜˜æææaaa}}}‚‚‚hhhvvvÕÕÕ¾¾¾ÐÐÐÔÔÔÒÒÒÔÔÔÒÒÒÑÑÑÒÒÒÖÖÖ¼¼¼§§§«««ªªª«««¡¡¡   ˜˜˜RRR;;;;;;RRR˜˜˜   ©©©ÁÁÁÍÍÍyyy222+++]]]ÀÀÀÇÇǰ°°½½½¾¾¾½½½¼¼¼¼¼¼½½½½½½¿¿¿³³³©©©ªªª«««¥¥¥ÇÇÇÎÎÎ[[[ˆˆˆººº¿¿¿‰‰‰\\\ÈÈÈÈÈÈÏÏÏYYY{{{ÀÀÀÇÇÇ–––MMM²²²ÇÇÇÒÒÒÖÖÖØØØÚÚÚÜÜÜÙÙÙÕÕÕÙÙÙ½½½§§§«««ªªª§§§¾¾¾VVV¬¬¬õõõçççÒÒÒðð𬬬PPPÉÉÉccc˜˜˜âââÆÆÆÇÇÇ×××ÄÄÄOOO²²²ÖÖÖÖÖÖÍÍÍÈÈÈ»»»ÅÅÅÖÖÖØØØ¼¼¼§§§«««©©©³³³€€€{{{ççç‘‘‘nnn”””ñññ|||___pppìì쥥¥(((‚‚‚ðððŒŒŒnnnßßßßßß‹‹‹<<<}}}ÝÝÝÖÖÖ¼¼¼§§§«««§§§¶¶¶```£££ßßß///TTT ççç­­­%%%™™™ÜÜÜæææxxxCCCçççØØØ···^^^ÞÞÞÓÓÓØØØ```QQQ×××ÕÕÕØØØ¼¼¼§§§«««¨¨¨¶¶¶eee›››ëë똘˜SSS)))ËËËâââ§§§---“““ÞÞÞàààuuuBBBãããÚÚÚ±±±___ßßßÔÔÔËËËêêê===]]]æææÕÕÕ¼¼¼§§§«««©©©°°°’’’gggæææàààUUUÇÇÇìììfffaaaçç窪ªRRRÜÜÜêêêwww}}}ÞÞÞÝÝݘ˜˜@@@***ŠŠŠßßßÖÖÖ¼¼¼§§§««««««¥¥¥ÇÇÇnnnããããããÓÓÓââ⃃ƒfffÔÔÔ{{{mmmÛÛÛÐÐÐØØØååå•••ZZZÁÁÁÓÓÓÕÕÕÔÔÔ¾¾¾ÆÆÆÛÛÛÓÓÓØØØ¼¼¼§§§««««««¦¦¦¾¾¾ÛÛÛnnnjjj–––šššjjjoooÕÕÕÁÁÁçç燇‡ccc’’’•••nnnkkkÙÙÙÄÄÄÒÒÒÔÔÔÝÝÝéééçççááá××××××½½½§§§«««ªªª©©©°°°ÃÃÃÐÐÐooo((('''oooÑÑÑÃÃæ¦¦˜˜˜¨¨¨………WWWRRRuuu¥¥¥œœœ§§§¾¾¾ÊÊÊqqqkkk~~~¸¸¸ÈÈȰ°°©©©ªªª«««¦¦¦¿¿¿ÏÏÏYYYrrr­­­ªªªqqqXXX××׃ƒƒ ~~~ææævvvZZZ–––¢¢¢€€€NNN³³³ÅÅÅ¥¥¥««««««¦¦¦ÄÄÄbbb™™™ìììØØØæææïïï•••iii‡‡‡ŽŽŽllläääßßßàààäääÂÂÂRRR««««««ªªª©©©²²²‰‰‰pppîîîggg@@@BBB´´´ííívvvOOOuuuaaaÝÝݺºº888!!!jjjììì›››^^^¶¶¶¨¨¨§§§¶¶¶bbb¡¡¡ßßߺºº°°°ŒŒŒëëë§§§111QQQßßßÛÛÛŒŒŒ)))ÔÔÔ×××ÈÈÈTTT­­­©©©§§§¶¶¶bbb   âââÓÓÓ___¸¸¸äää©©©111QQQÞÞÞáá៟Ÿ...ÞÞÞÖÖÖÈÈÈTTT¬¬¬©©©©©©²²²‰‰‰oooòòò………MMM¥¥¥ñññvvvNNNuuuaaaÜÜܽ½½///111ÕÕÕååå^^^µµµ¨¨¨«««¦¦¦ÃÃÃ```šššÖÖÖ¬¬¬ÌÌÌîîî•••hhhˆˆˆŽŽŽlllßßߺººÃÃÃèèèÀÀÀQQQªªª¬¬¬ªªª«««¦¦¦ÁÁÁÕÕÕ```uuu¬¬¬¥¥¥ooo___ÜÜÜ„„„ììì{{{```¢¢¢«««ƒƒƒSSS¸¸¸ÇÇÇ¥¥¥«««ªªª©©©±±±ÁÁÁÃÃȈˆ```aaa‰‰‰ÃÃÃÄÄÄ–––\\\bbbaaaaaaaaaaaabbb\\\———ÀÀÀÈÈÈœœœggg]]]yyy···ÇÇǰ°°©©©ªªªªªªªªª©©©¦¦¦¦¦¦²²²¶¶¶¶¶¶²²²¦¦¦¥¥¥­­­···¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶···­­­¦¦¦¥¥¥®®®¶¶¶¶¶¶´´´©©©¥¥¥©©©ªªªªªªªªªªªªªªª««««««©©©§§§§§§©©©««««««©©©§§§§§§§§§§§§§§§§§§§§§§§§©©©««««««©©©¨¨¨§§§¨¨¨ªªª«««ªªªªªªªªª(  ©©©±±±´´´³³³´´´®®®®®®   œœœ¯¯¯¨¨¨§§§¥¥¥§§§¨¨¨ªªª°°°WWW,,,777)))qqq©©©˜˜˜•••ÄÄÄËËËÒÒÒËËË¿¿¿¨¨¨³³³333<<<¨¨¨§§§ŸŸŸ¡¡¡±±±ÊÊÊmmmÈÈÈÎÎΧ§§³³³777,,,ÆÆÆsssZZZÅÅÅÙÙÙRRR§§§ÑÑѦ¦¦³³³333FFF£££‰‰‰¬¬¬˜˜˜¸¸¸ÒÒÒÅÅÅÍÍͧ§§®®®qqq000&&&...‰‰‰ºººssslll¥¥¥ËËËÌÌÌÚÚÚÒÒÒ¿¿¿©©©¯¯¯ªªª«««ÊÊʤ¤¤©©©™™™ŸŸŸ¦¦¦ÁÁÁÎÎζ¶¶ÎÎÎÇÇǧ§§¥¥¥ŽŽŽ¨¨¨;;;»»»ooo±±±•••|||¾¾¾¢¢¢ÍÍÍMMMºººÏÏϦ¦¦¨¨¨ŒŒŒÁÁÁPPPÇÇÇpppªªª’’’žžž···   ØØØeee©©©ÒÒÒ¦¦¦®®®ªªª›››¢¢¢“““²²²ªªªŸŸŸ¯¯¯ÊÊÊÕÕÕ···ÙÙÙÊÊʧ§§©©©ÁÁÁ………ttt‰‰‰®®®QQQ666000NNN¯¯¯›››ŸŸŸ’’’´´´¬¬¬®®®‘‘‘§§§¤¤¤»»»mmmwww¯¯¯ŽŽŽªªª©©©¢¢¢ÔÔÔ888ÁÁÁyyyjjjâââYYYÎÎΜœœššš­­­“““©©©„„„···oooxxx­­­ÄÄÄŠŠŠªªªªªªººº“““–––¢¢¢222444444111§§§ššš‘‘‘ŒŒŒ³³³¬¬¬©©©ªªª®®®¡¡¡­­­¬¬¬³³³³³³³³³³³³«««¯¯¯¢¢¢­­­¬¬¬©©©(0` ªªª©©©¨¨¨§§§­­­¯¯¯®®®¦¦¦¶¶¶ººº«««   –––˜˜˜———ššš¬¬¬¾¾¾hhhLLLiii···XXX½½½×××ÜÜÜsss+++WWW|||ßßßÎÎεµµÖÖÖÔÔÔÕÕÕáááVVVBBBÅÅÅâââãããÆÆÆAAAYYYÙÙÙ´´´ÍÍÍ~~~===ÛÛÛØØØÚÚÚäää>>>vvvÄÄÄÞÞÞ¹¹¹444ŸŸŸ777(((,,,°°°ÒÒÒ›››!!!###ÃÃÃ***kkk”””ÐÐÐàààHHHÑÑÑ‚‚‚ËËË000cccdddæææõõõ\\\ÂÂÂåååbbbÓÓÓÝÝÝ:::///gggaaa¥¥¥___lllééé)))'''CCC¢¢¢¸¸¸ííí¤¤¤&&&]]]111‡‡‡ÊÊÊÉÉÉÁÁÁ»»»………³³³¿¿¿@@@EEE£££€€€ƒƒƒ’’’OOO666[[[‰‰‰ÀÀÀ±±±SSSmmmjjjGGGêêêÌÌÌIIIoooÈÈÈÏÏÏUUU¡¡¡†††ççç333222pppŽŽŽ™™™???DDD¼¼¼...JJJZZZ NNN{{{nnnìììðððTTT}}}999qqqÇÇÇžžžFFF²²²uuuˆˆˆeee;;;KKK888---ŠŠŠœœœèèèëëë"""ttt yyy ```xxx<<< PPPrrrñññRRRzzz MMM^^^îîîïïïwwwQQQ     !""! #$%&'''''''''('!)*+,-./0/012345(((''''((((!)67890/#:#;<=>?@'('4#A#&(('!)BC =DEF94:GH;I#JKCL M4''!)NOA:PQRST'UVO+W:XYZ[\('!)]^_`I&Uabcdef`Igh.]i;:g('!)jkl0mC)b:Weno`I';p0q]4(('!)rPs%:0§Ed`u¨©-sª=”«%IAŠ>¬Eˆ.;''%¥­=g£L®‡ªh`™h r…†=Q|H+µpA]–:†&'''&4&W''(' “+"|Ÿ¥o˜½p€B40¦£¾lf˜¤¦ež<;&/0#&4;¿u5g bF«À\\†%H“ªš‡ÁÂÂÁ‡š„B%“.x¡Œ“@u B\&Áj‰{ii&\?³®6SqjjqS²6F€(Ã]›ÄÅÆÇ ¢œ|xIhT‘yÈ¢cÉÊJyÇžA+'m|»0 x7Á¤;Ë¢eUÊ%ÌuÍ)))))))ÎÌ™Êe0Ê`¤…¤B=Jb,OžIÊÄÏcЪË.Ñl·†eB« 5Ò•/4_˜•˜h'žˆ)c³ Óž;€}ÔB0Õœ% ¯°=W`=r I#icc6Ö¯+I'×ØÌ™4W=Ù¯  Ä8eT+oÐÚmAT+­Ecc²œÕ=Ig0›²&'Ie8Ä Ñ=Iž† Ä/W(˜Û)cÜ‘2&(ž'¬S4(W=Ý^Cš=ÇSN)?:#x>cÎ>Š`‡|)F&gT]  x$•wžÈ;A;«§ÒcЪ§«4# IË·f ‡<-•WÞ×™/ ¤oeQßeQ£ ™àw=ž•s& ‡#<Â|n"ÏØjÁ=>>ˆˆˆÛÛÛÖÖÖ ¿¿¿WWWìììâââ„„„LLL †††òòòwwwFFFàààVVVæææÕÕÕZZZäää‘‘‘HHHóó󇇇ÝÝÝ777žžž™™™ÙÙÙÚÚÚ ˜˜˜}}}‚‚‚hhhvvv   ;;;ÁÁÁÍÍÍyyy222+++]]]ÀÀÀ³³³ÎÎÎ[[[ººº{{{–––MMMõõõçççPPPÉÉÉcccÆÆÆÄÄÄOOOÅÅÅ”””ñññ|||ppp(((ŒŒŒ‹‹‹<<<```/// ­­­%%%xxxCCC^^^ÓÓÓ›››ëëë)))ËËË---uuuBBB±±±===’’’gggfff@@@***ƒƒƒmmmåååjjjšššoookkkéééÃÃÃ………œœœqqq~~~¸¸¸rrrXXXNNNïïïlllîîî888!!!111...ÌÌÌèèè———     !"!!!!#!$%&'()*+,-./0123/!4"""""!5)673389 33!"!!!!!4:;<=>?@ABC22D!EFGH!"!!!!!IB1J'EKL 5'MNO'H.!"!!!!!PQRSTU1VH.EWXY!"!!!#!!Z[\]?^_C`/abEcdaH!"!!!!#!e'2fg=C7Yg-f5-f!hPiij#!kXlmnopY(-7-7'7Hqk%rr%kqstuvwxyJz {|F}J@$~y€ 7H.g/fYfW‚7Aƒ„…kM†3‡ˆ HHt‰H.z=~‚]:Š‹ŒŽL nA‘:22’!“maH”92•*–l‚—˜e/X™š‚.›5œ.”3Y.žkŸ M¡&5V¢£1g¤2- 6¥xXY¦§XV>TL¨©‚ª%/6Sm5ak«¬ 2H :­11œM®¨-~¯G(.°B[sœY-†Gœ.)G:±²±³Ys‚`…¦B:´f‡7-aµ‚033¶(³?³'¶)k·K%¢ ¸,b¹´º»)J$¼—¹½3®!¾¾jIh¾!ºXp[+=¿z‰ )‡eL.XÀBC`!"!!!!"!DÁÂ\2V\8% @ŽÃ§«£?"@"A BCDEFGH3I7J,K?LAM NOPQR, SHTU (VP) ?WX/YZ4[SN0\ `a?bcddefg"hiTjPEk^li2m 72TnHoppq h\K0 i0;Hi0(0`€€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷÷ÿw÷÷w÷÷÷÷ÿxˆˆˆˆˆˆˆ÷÷x€‡ÿ÷÷÷÷pÿø‡ø€w÷÷÷÷÷÷p÷€ÿ÷ÿÿw÷÷ð÷÷ÿ÷ðwÿÿ÷÷pð÷‡÷÷÷ÿx€÷pð÷ðwÿp÷ðˆwÿÿpˆÿww÷÷ÿpˆÿx€÷€‡pˆ÷ø÷ˆ÷ÿÿ÷÷÷÷ppÿø÷ÿ÷÷xwÿ÷ðpwx÷ø‡ÿp÷p÷÷wwðwÿ÷wÿ÷÷ð÷€÷ÿ÷÷÷÷ÿw÷ðÿøwø€÷÷÷÷p€÷ˆ€‡÷÷÷÷÷ÿ÷wxw÷ˆÿ÷ÿ÷÷÷÷÷÷pˆ÷÷÷€ˆ÷÷wøÿøp‡ÿp÷÷wÿÿ€ÿ÷ð÷ÿÿ€ÿ÷ÿw÷÷÷÷÷ÿw÷ø‡wðw÷wwÿwø÷‡€wˆpwðÿ÷ÿ€÷ÿ÷ðwðÿpˆÿpw÷ÿ÷xx÷ð÷ø‡w÷ðÿxÿˆ÷€÷÷p÷€wÿpˆ÷ðw÷ˆ÷÷÷xwðwpx€ÿwðÿˆÿ÷ÿ÷÷ø÷xwˆpwøw÷÷ÿp÷ÿ÷÷÷ˆw÷øwˆ÷øwwˆ÷÷ˆÿ÷ÿð‡÷ÿÿÿpÿÿ÷÷÷÷÷xwøwpÿp÷÷÷wwwpˆw÷€€w÷ÿÿ÷÷÷÷÷ÿˆˆÿ÷ÿÿ÷ˆ‡ÿÿ÷÷÷ÿwwÿw€ÿˆˆˆˆˆˆˆÿ€÷÷÷÷wxÿ€÷pÿøð÷÷÷€€÷ÿ÷÷wÿÿÿ÷ø€ð÷ÿÿ€÷øw€‡÷€pÿx€ððwðÿˆ€÷x÷ø‡pÿÿð÷p€÷pÿxwxx€ÿp÷pðp€ÿ€÷wx÷px€ˆ÷w€÷ø‡wwˆ€p÷pwøwÿx÷ø€ðÿwwÿ€wpÿÿÿp€÷ÿÿ÷ÿ÷ÿ‡wpÿ€ÿpwx÷÷ø€€÷÷ˆ÷÷w÷ÿw÷÷÷w÷÷÷÷÷÷÷( @€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿww‡xw‡xx‡ˆxxw‡xxˆˆˆˆ€‡w€ˆ‡wwwwwwxˆwˆwwxˆ‡ˆ÷÷øwwwwx€ø‡÷÷xxw€w‡wpwpwˆÿw÷wxˆ€‡w‡÷ˆxx‡x‡x‡ˆwÿxxˆ‡xˆw÷ÿwwx€‡w€ˆwwwwwwx‡w€ˆww€€‡wwwwwwwˆwxˆwˆ÷ˆwÿÿw÷x‡ˆwx‡‡wˆø‡wxwwx‡ˆ÷ˆ€w÷ˆwwˆ€€w€wø‡wxxx‡ˆ÷€‡øw‡÷w÷wˆøwˆ€‡wwˆxwˆwð‡ˆwwx‡wwwwwxˆwˆ÷x‡xˆw÷ÿx‡wˆwx÷xˆwwwˆ‡wwwx€€‡ø€‡øˆˆ‡xwˆÿˆðˆÿwˆw‡‡x‡ø€ˆ‡ˆ‡ð‡ˆ‡ˆ€÷ˆˆø‡xwø€w€ˆwðwxøÿ€wðw‡ˆˆwˆˆ€‡x‡wˆwxp‡w÷pw‡øˆˆˆðxˆx‡wwxˆˆ‡xˆˆ€ˆ‡wˆˆwxx‡wxxw‡‡wwxxww‡‡( €€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ‡ww‡‡xw‡x€xxwwwpxˆw‡wpx‡wˆxpxˆwwwx€x‡wwwww‡ˆxwxˆˆxx‡‡‡wˆxxˆw‡‡ww‡‡wxwxwˆˆ€xˆwx‡x‡‡‡ˆxx‡‡ˆxxx‡w‡wˆx€xˆwxx‡w‡xwxpuzzles-20170606.272beef/icons/signpost.ico0000644000175000017500000006117613115373744017364 0ustar simonsimon 00 ¨%–  ¨>& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¢££¡¡¡¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡¡¡¡¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡££££¥¥¢¥¤£¥¤£¥¤£¥¤£¥¤£¥¤£¥¤£¥¤£¥¤£¥¤¢¥¤£¥¥¢¥¤¢¥¤£¥¥¢¥¤¢¥¤£¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤££¤¨ª«¯¯®®®®®®®®®®®®®®®®®®®®®®®®®®®®­­­­­­®®®®®®®®®®®®®®®¯¯¯¨¨ª©ž¢ªž¢ªž¢ªž¢ªž¢ªž¢ªž¢ªž¢ªž¢ªž¢ªž¢ªž¢©ž¢«Ÿ£«Ÿ£©ž¢ªž¢ªž¢ªž¢¦¢¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¦¦¦ÐÏÏÿÿÿûûûýýýýýýýýýýýýýýýýýýýýýüüüþþþÿÿÿýýýüüüýýýüüüüüüÿÿÿÄÈÇÈuÝp“Ùq’Ùq’Ùq’Ùq’Ùq’Ùq’Ùq’Ùq’Ùq’Øp’Ûr”ÔnÖoÛr”Øq’Úq’Ør“ªž¢¢¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¦¦¦ÐÐÐÿÿÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿÿÿæææÒÒÒÿÿÿþþþþþþþþþüûûÿÿÿÄÈÇÈtÞo“Úp’Úp’Úp’Úp’Úp’Úp’Úp’Úp’Ùo‘Üq“×n£Sm¨VpÚo’Ûq“Úo‘Úq’ªž¢£¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¦¦¦ÐÐÐÿÿÿüüüþþþþþþþþþþþþþþþýýýÿÿÿççç²²²«««ÏÏÏþþþÿÿÿÔÔÔâââÿÿÿÃÇÆÈuÞo“Ùq’Úp’Úp’Úp’Úp’Úp’Úp’Ùp‘Üq“×n¥To–Ld•LdªWqÙp‘Ûq“Øq’ªž¢¢¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¦¦¦ÐÐÐÿÿÿüüüþþþþþþþþþþþþþþþýýýÿÿÿççç²²²²²²­­­ÒÒÒÜÜܨ¨¨ãããÿÿÿÃÇÆÈuÞo“Ùq’Úp’Úp’Úp’Úp’Úp’Ùp’Üq”×o¦Uo–LdšOgšOg•Lc«WrÚp’Ûr“©ž¢£¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¦¦¦ÐÐÐÿÿÿüüüþþþþþþþþþþþþþþþþþþýýýÿÿÿééé³³³±±±°°°°°°­­­äääÿÿÿÃÇÆÈuÞo“Ùq’Úp’Úp’Úp’Úp’Úp’Ûq“ÔmŽ¢Sl‘Ja™Nf™Nf™Nf˜Ne‘Ja§UoÖo«Ÿ¢¢¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¦¦¦ÐÐÐÿÿÿüüüþþþþþþþþþþþþþþþþþþþþþýýýÿÿÿêêê³³³²²²´´´­­­ãããÿÿÿÃÇÆÈuÞo“Ùq’Úp’Úp’Úp’Úp’Úp’Ûq“ÔmŽÅe„Îjв[w–Ld–Md·^zÍjŠÆe„Õn«Ÿ£¢¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¦¦¦ÐÐÐÿÿÿüüüþþþþþþþþþþþþþþþþþþþþþþþþÿÿÿÜÜܱ±±²²²³³³­­­ãããÿÿÿÃÇÆÈuÞo“Ùq’Úp’Úp’Úp’Úp’Úp’Úp’Ûq“Ýr”ãu˜¼`~•Lc•LcÃdƒâu˜Ýq”Úq“ªž¢£¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¦¦¦ÐÐÐÿÿÿüüüþþþþþþþþþþþþþþþþþþýýýÿÿÿÛÛÛ¬¬¬±±±²²²²²²¬¬¬ãããÿÿÿÃÇÆÈuÞo“Ùq’Úp’Úp’Úp’Úp’Úp’Úp’Úp’Øo‘Þr•º_}–Ld–MdÁcÞr•Øo‘Ùq’ªž¢¢¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¦¦¦ÐÐÐÿÿÿüüüþþþþþþþþþþþþþþþþþþþþþþþþòòòòòòóóóóóóóóóòòòùùùÿÿÿÄÈÇÈuÞo“Ùq’Úp’Úp’Úp’Úp’Úp’Úp’Úp’Ùo‘ßs–¸^{I`J`Àb€ßs•Ùo‘Ùq’ªž¢£¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¦¦¦ÐÐÐÿÿÿûûûýýýýýýýýýþþþþþþþþþþþþþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿÿÿÄÈÇÈuÞo“Ùq’Úp’Úp’Úp’Úp’Úp’Úp’Úp’Úp’Üq“Ïj‹ÁcÂc‚ÑlŒÛq“Úp’Ùq’ªž¢£¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¦¦¦ÐÐÐÿÿÿýýýÿÿÿÿÿÿÿÿÿÿÿÿþþþþþþþþþþþþþþþýýýýýýýýýýýýýýýüüüÿÿÿÄÈÇÈuÞo’Ùp’Ùp’Úp’Úp’Úp’Úp’Úp’Úp’Úp’Ùp‘Üq“ßr•ßr•Üq“Úp’Úp’Ùq’ªž¢£¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¦¦¦ÑÑÑÿÿÿÑÑÑÑÑÑÎÎÎÉÉÉîîîÿÿÿýýýþþþþþþþþþþþþþþþþþþþþþþþþýüüÿÿÿÄÈÇÈtàp”Ür”Ýq”Üq“Úp’Ùp‘Üq“Ùp’Úp’Ûp’Üq”Üq”Úp’Ùo‘Úp’Úp’Úp’Ùq’ªž¢£¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¦¦¦ÑÑÑÿÿÿ¹¹¹©©©ÐÐÐÐÐÐîîîÿÿÿýýýþþþþþþþþþþþþþþþþþþþþþþþþýüüÿÿÿÄÈÇÊv‘Ðh‰­Yt°Zv¹_{ßr•Þr•½aÛq“ßr•Íi‰ªWr§Up½a~Üq”Ùp’Úp’Úp’Ùq’ªž¢£¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¦¦¦ÏÏÏÿÿÿøøøÆÆÆÅÅÅûûûÿÿÿþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþýüüÿÿÿÄÈÇÌw’­Vr¿c€¼`}ªWqÖnº_}¥Tn¸^{Ðk‹Þr”º_|¥TnØo‘Úp’Úp’Úp’Úp’Ùq’ªž¢£¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¦¦¦ÐÐÐÿÿÿýýýÿÿÿÉÉÉ»»»úúúÿÿÿþþþþþþþþþþþþþþþþþþþþþþþþþþþýüüÿÿÿÄÈÇÌw’´Yw¯Zv²[w®YtØo‘Ãd‚©WqÁcÒlât˜Çf…«Wrßr•Ùp’Úp’Úp’Úp’Ùq’ªž¢£¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¦¦¦ÑÑÑÿÿÿêêêÿÿÿãã㦦¦êêêÿÿÿýýýþþþþþþþþþþþþþþþþþþþþþþþþýüüÿÿÿÄÈÇÉuØl¼a~®Yt¬Xràs–Þr”¸_|Ûp“Þr•ÒlŒ©Vp©VpÝq”Ùp’Úp’Úp’Úp’Ùq’ªž¢£¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¦¦¦ÑÑÑÿÿÿ¾¾¾»»»²²²ÅÅÅùùùþþþýýýýýýýýýýýýýýýýýýýýýýýýýýýüüüÿÿÿÄÈÇÇuÞp“âv™Èg†·_{Ýr”Øp‘Ùp’Øp‘Úq“ÔnŽÁd‚ËiˆÚq“Ùp’Ùq’Ùq’Úp’Ùq’ªž¢£¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¦¦¦ÐÐÐÿÿÿüüüöööøøøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿÿÿÄÉÇËtân“Üo’ßo“áp”Þo’Þo“Þo“Þo“Þo’ßp“ãr–áq•Þo’Þo“Þo“Þo“Þo’Ýp“ªž¢¢¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¥¥¥ŸŸŸÄÄÄéééäääèèèçççäääääääääääääääääääääääääääãããääääääãããéé鼿¾¼zËsÈuÈtÈtÈuÈuÈuÈuÈuÈtÇtÇtÈtÇtÈuÈuÈtÈu¨Ÿ¢£¥¥¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¢¢¢µµµÅÅÅÂÂÂÂÂÂÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÂÂÂÄÄÄÇÇÇÂÂÂÃÃÃÃÃÃÅÅű°±¼¿¾ÆÊÉÄÈÇÄÈÇÄÈÇÄÈÇÄÈÇÄÈÇÄÈÇÄÈÇÄÈÇÄÈÇÄÈÇÆÊÉÇËÊÃÇÆÄÈÇÄÉÇÄÈǧ©ª£££¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¦¦¦ÐÐÐÿÿÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøøøëëëÿÿÿÿÿÿýýýÿÿÿÃÃÃåååÿÿÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿõôõòòòÿÿÿþþþÿÿÿþþþ®®®¢¡¡¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¦¦¦ÏÏÏÿÿÿûûûýýýýýýýýýýýýýýýýýýýýýüüüþþþøøø¿¿¿ªªªÝÝÝÿÿÿúúúÿÿÿÃÃÃãããÿÿÿüüüýüüýüüýüüýüüüüüýýýüüüûûûúúúÿÿÿååå±±±ïïïÿÿÿüüüûûû®®®¢¢¢¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¦¦¦ÐÐÐÿÿÿüüüþþþþþþþþþþþþþþþþþþýýýÿÿÿùùùÁÁÁ®®®³³³¯¯¯ßßßÿÿÿÿÿÿÃÃÃäääÿÿÿýýýþþþþþþþþþþþþþþþþþþþþþÿÿÿþþþÿÿÿììì«««¸¸¸ðððÿÿÿüüü®®®¡¡¡¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¦¦¦ÐÐÐÿÿÿüüüþþþþþþþþþþþþþþþþþþÿÿÿ÷÷÷¿¿¿¬¬¬³³³³³³±±±­­­ÛÛÛÿÿÿÂÂÂäääÿÿÿýýýþþþþþþþþþþþþýýýÿÿÿìììÆÆÆÊÊÊËËËÃÃò²²°°°···ñññÿÿÿ­­­¢¢¢¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¦¦¦ÐÐÐÿÿÿüüüþþþþþþþþþþþþþþþþþþþþþÊÊÊ´´´¹¹¹²²²²²²µµµ¹¹¹´´´ïïïÇÇÇäääÿÿÿýýýþþþþþþþþþþþþýýýÿÿÿááᨨ¨¯¯¯­­­¯¯¯²²²³³³¯¯¯¶¶¶õõõ°°°¡¡¡¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¦¦¦ÐÐÐÿÿÿüüüþþþþþþþþþþþþþþþþþþýýýùùùÿÿÿîîî±±±®®®ÉÉÉÿÿÿùùùÿÿÿÃÃÃäääÿÿÿýýýþþþþþþþþþþþþýýýÿÿÿããã«««²²²±±±±±±²²²³³³­­­ÒÒÒüüü®®®¡¡¡¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¦¦¦ÐÐÐÿÿÿüüüþþþþþþþþþþþþþþþþþþþþþþþþÿÿÿððð±±±®®®ÊÊÊÿÿÿüüüÿÿÿÃÃÃäääÿÿÿýýýþþþþþþþþþþþþþþþÿÿÿùùùïïïïïïóóóààà°°°­­­ÒÒÒÿÿÿýýý®®®¢¢¢¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¦¦¦ÐÐÐÿÿÿüüüþþþþþþþþþþþþþþþþþþþþþýýýÿÿÿïïï°°°­­­ÉÉÉÿÿÿûûûÿÿÿÃÃÃäääÿÿÿýýýþþþþþþþþþþþþþþþþþþþþþÿÿÿþþþÿÿÿëëë©©©ÓÓÓÿÿÿþþþüüü®®®¡¡¡¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¦¦¦ÐÐÐÿÿÿüüüþþþþþþþþþþþþþþþþþþþþþýýýÿÿÿððð³³³°°°ËËËÿÿÿûûûÿÿÿÃÃÃäääÿÿÿýýýþþþþþþþþþþþþþþþþþþþþþýýýüüüÿÿÿèèèÏÏÏÿÿÿýýýþþþýýý®®®¢¢¢¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¦¦¦ÐÐÐÿÿÿüýýþþþþþþþþþþþþþþþþþþþþþþþþþþþýýý÷÷÷÷÷÷ùùùþþþüüüÿÿÿÃÃÃäääÿÿÿýýýþþþþþþýýýþþþþþþþþþþþþþþþþþþþþþüüüþþþþþþýýýÿÿÿýýý®®®¢¢¢¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¦¦¦ÐÐÐÿÿÿüüüþþþþþþþýýþþþþþþþþþþþþþþþþþþþþþÿÿÿÿÿÿÿÿÿþþþýýýÿÿÿÃÃÃäääÿÿÿþþþþþþÿÿÿÿÿÿþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþÿÿÿýýý®®®¢¢¢¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¦¦¦ÐÏÏÿÿÿøÏÏø¹¹ø½½ø¹¹ûßßþÿÿþýýþþþþþþþþþþþþþþþþþþþþþþþþýýýÿÿÿÂÂÂèèèììì¼¼¼¼¼¼¿¿¿äääÿÿÿþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþÿÿÿýýý®®®¢¢¢¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¦¦¦ÐÐÐÿÿÿüõõú××÷®®üããþøøþÿÿþþþþþþþþþþþþþþþþþþþþþþþþþþþýýýÿÿÿÂÂÂçççòòòäääõõõÅÅÅ®®®øøøÿÿÿþþþþþþþþþþþþþþþþþþþþþþþþþþþÿÿÿýýý®®®¢¢¢¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¦¦¦ÐÐÐÿÿÿýÿÿûåå÷°°ýõõþÿÿþýýþþþþþþþþþþþþþþþþþþþþþþþþþþþýýýÿÿÿÃÃÃäääÿÿÿøøøíííÇÇÇÅÅÅýýýþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþÿÿÿýýý®®®¢¢¢¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¦¦¦ÐÐÐÿÿÿýÿÿüåå÷°°ýòòþÿÿþýýþþþþþþþþþþþþþþþþþþþþþþþþþþþýýýÿÿÿÃÃÃäääÿÿÿéééÀÀÀ³³³ÚÚÚÿÿÿýýýþþþþþþþþþþþþþþþþþþþþþþþþþþþÿÿÿýýý®®®¢¢¢¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¦¦¦ÐÐÐÿÿÿûèèúÒÒ÷®®ýòòþÿÿþýýþþþþþþþþþþþþþþþþþþþþþþþþþþþýýýÿÿÿÃÃÃæææýýýãããîîî»»»´´´þþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþþÿÿÿýýý®®®¢¢¢¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¦¦¦ÏÏÏÿÿÿ÷ÔÔ÷½½÷¾¾ûóóýþþüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüûûûÿÿÿÂÂÂåååùùùÁÁÁ½½½ÀÀÀãããþþþüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüýýýûûû®®®¢¢¢¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¦¦¦ÐÐÐÿÿÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿÿÿÃÃÃåååÿÿÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþ®®®¢¡¡¥¥¥¤¤¤¤¤¤¤¤¤¤¤¤¥¥¥¡¡¡ºººÓÓÓÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÏÏÏÓÓÓµµµÄÄÄÒÒÒÏÏÏÐÐÐÏÏÏÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÏϨª«¢££¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¥¥¥¡¡¡œœœœœœ¢¢¢ŸŸŸœœœ££¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¥¥¥¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¤¤¤¥¥¥¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤( @ ¤¤¤¤¤¤¥¥¥¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥£¤¥£¤¥£¤¥£¤¥£¤¥£¤¥£¤¥£¤¥£¤¥£¤¥£¤¥£¤¥£¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¡¡¡žžžžžžžžžžžžžžžžžžžžžžžžŸŸŸ¢§¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥ ¨¥Ÿ§¥ §¥ ¨¥ ¨¥£¥¥¤¤¤¤¤¤¥¥¥¡¡¡´µµÎÎÍÊÊÊËËËËËËËËËËËËÊÊÊÏÏÏÌÌÌÊÊÊÊÊÊÍÍ;ÁÁ³’½œ»Žœ»Žœ»Žœ»Žœ»Žœ»Žœ»Žœ¾ž½žºŽœ½Œœ¯š¡¢¦¥¤¤¤¦¦¦ËËËÿÿÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿìììùùùÿÿÿþþþÿÿÿâèæÈw‘ãj‘Ým‘Þl‘Þl‘Þl‘ÞlÞl‘ân“ºYxÇ`âp•ág޽Œœ ¨¥¥£¤¦¦¦žžžÊÊÊÿÿÿûûûüüüüüüüüüÿÿÿãã㦦¦ÁÁÁüüüØØØìêëåêéÄz’Ýo’Ør“Ùq’Ùq’Ùq’Ùq’Þs•·_{’Lc˜NfÅh…âp•ºŽœ ¨¥¥£¤¦¦¦žžžËËËÿÿÿüüüþþþþþþþþþÿÿÿ÷÷÷ÃÃë««¾¾¾­­­ìëìæìêÄy‘Þn’Ùq’Úp’Úp’Úp’Ûp“³[x‘Ja›Og˜Me“LcÇ`¾ž §¥¥£¤¦¦¦žžžËËËÿÿÿüüüþþþþþþþþþþþþÿÿÿûûû¾¾¾°°°®®®ïíîåëéÅy‘Þn’Ùq’Úp’Úp’Ûp’×oÇf…Àc—Me¡RlÅg…Íc…¼Ž ¨¥¥£¤¦¦¦žžžËËËÿÿÿüüüþþþþþþþþþþþþÿÿÿÛÛÛ®®®¯¯¯©©©íììæìêÄy‘Þn’Ùq’Úp’Úp’Úp’Úp’át—Ól–Ld¤TnÞt–án“»Žœ ¨¥¥£¤¦¦¦ËËËÿÿÿûûûýýýýýýþþþþþþýýýçççæææéééæææþýýâèæÅz’Þn’Ùq’Úp’Úp’Úp’Ùp’Üq“Ïj‹•Ld£SmÙq’Ýl»Žœ ¨¥¥£¤¦¦¦žžžËËËÿÿÿþþþÿÿÿÿÿÿþþþþþþþþþÿÿÿÿÿÿÿÿÿþþþÿÿÿáçåÅz’Þn’Úq’Úp’Úp’Úp’Úp’Ûp’Ùo‘Ïj‹ÑkŒÙq’Þl‘»Žœ ¨¥¥£¤¦¦¦ÍÍÍõõõÚÚÚÚÚÚæææÿÿÿýýýþþþýýýýýýýýýüüüÿÿÿáçåÆz“ßn“Øp‘Ûp’Ûq“Ûq“Ûq“Øo‘Ùp‘Ûq“Üq“Ùq’Þl‘»Žœ ¨¥¥£¤¦¦¦ÎÎÎòòò­­­ÌÌÌïïïÿÿÿþþþþþþþþþþþþþþþýýýÿÿÿáçåÅz’À^}±\wÅeƒÖn½a~Ùp‘ÎjЧUpÂc‚Üq“Ùq’Þl‘»Žœ ¨¥¥£¤¦¦¦žžžÊÊÊÿÿÿôôôËËËñññÿÿÿýýýþþþþþþþþþþþþýýýÿÿÿâçæÁx²Wt²\x¾aÆf…§UpÉg†ßs•°ZuÒlŒÜq“Ùq’Þl‘»Žœ ¨¥¥£¤¦¦¦ÍÍÍóóóéééÀÀÀÌÌÌÿÿÿûûûýýýýýýýýýýýýüüüÿÿÿàæäÆ{“ÑhŠ®[u¾b€Þs•Æg…Þs•ÍjŠ©WrÔnŽÛq“Øq’Ým‘»Žœ ¨¥¥£¤¦¦¦ÍÍÍüüü×××ÜÜÜûûûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿÿÿáèæÈx’çn•ÙlÖjŒào“ßn“Þn’ÛmÙkÞn’Þn’Ýo’ãj‘½œ ¨¥¥£¤¥¥¥   ¾¾¾æææäääåååáááßßßßßßßßßßßßßßßàààÞÞÞãââÍÑйƒ•Çx‘Æ{“Ç{“Åz’Åz’Åz’Æz“Ç{“Æ{“Åz’Å{’Èw‘²’¡§¦¥£¤¥¥¥   ¾¾¾ãããÝÝÝÞÞÞßßßßßßßßßßßßààààààÞÞÞàààâââÌËËÍÑÐåëêàæäáçåáçåáçåáçåàæäáçåÞãââèæàæäåëé¾ÁÁŸŸ ¥¥¥¦¦¦ËËËÿÿÿýýýÿÿÿÿÿÿÿÿÿÿÿÿþþþÿÿÿØØØÈÈÈüüüÿÿÿßßßàààÿÿÿþþþÿÿÿÿÿÿÿÿÿÿÿÿþþþÿÿÿèèèÖÕÖÿÿÿÿÿÿËË˦¦¦¦¦¦žžžÊÊÊÿÿÿûûûýýýýýýýýýýýýÿÿÿÒÒÒ¬¬¬¬¬¬¿¿¿ÿÿÿàààÞÞÞÿÿÿüüüýýýýýýýýýûûûðððõõõßßߨ¨¨ÓÓÓÿÿÿÊÊʦ¦¦¦¦¦žžžËËËÿÿÿüüüþþþþþþýýýÿÿÿÚÚÚ±±±´´´³³³°°°ÏÏÏÞÞÞßßßÿÿÿýýýþþþýýýÿÿÿñññ®®®®®®°°°´´´ªªªÛÛÛÎÎΦ¦¦¦¦¦žžžËËËÿÿÿüüüþþþþþþþþþþþþ÷÷÷úúú¿¿¿¯¯¯îîîÿÿÿÝÝÝàààÿÿÿýýýþþþýýýÿÿÿôôô¾¾¾¿¿¿¼¼¼±±±°°°êêêÍÍͦ¦¦¦¦¦žžžËËËÿÿÿüüüþþþþþþþþþþþþÿÿÿÿÿÿ¼¼¼«««ñññÿÿÿßßßßßßÿÿÿýýýþþþþþþþþþþþþþþþÿÿÿçç第¬åååÿÿÿÊÊʦ¦¦¦¦¦žžžËËËÿÿÿüüüþýýþþþþþþþþþþþþþþþÉÉɼ¼¼óóóÿÿÿßßßßßßÿÿÿüüüýýýþþþþþþþþþýýýÿÿÿêêêâââÿÿÿÿÿÿËËËžžž¦¦¦¦¦¦žžžËËËÿÿÿýþþþÿÿþÿÿþþþþþþþþþþþþÿÿÿÿÿÿýýýÿÿÿßßßßßßÿÿÿþþþÿÿÿþþþþþþþþþþþþþþþþþþÿÿÿüüüÿÿÿËËËžžž¦¦¦¦¦¦ËÍÍÿûûøÊÊùÆÆûÛÛþÿÿþþþþþþþþþþþþþþþýýýÿÿÿßßßáááãããÉÉÉÓÓÓùùùÿÿÿþþþþþþþþþþþþýýýüüüÿÿÿËËËžžž¦¦¦¦¦¦ËÊÊÿÿÿùÜÜø»»þùùþþþþþþþþþþþþþþþþþþýýýÿÿÿßßßßßßõõõîîî¹¹¹ãããÿÿÿýýýþþþþþþþþþþþþüüüÿÿÿËËËžžž¦¦¦¦¦¦žžžËÊÊÿÿÿûèèøÄÄþÿÿþþþþþþþþþþþþþþþþþþýýýÿÿÿßßßàààÿÿÿÔÔÔ¾¾¾õõõÿÿÿþþþþþþþþþþþþþþþüüüÿÿÿËËËžžž¦¦¦¦¦¦žÊÌÌÿüüöÄÄ÷¿¿ýÿÿüüüüüüüüüüüüüüüüüüûûûÿÿÿÝÝÝáááëëëÎÎδ´´ìììÿÿÿüüüüüüüüüüüüüüüûûûÿÿÿÊÊÊžžž¦¦¦¦¦¦ËÌÌÿÿÿýììÿóóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿÿÿßßßáááýýýéééõõõÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿÿÿËË˦¦¦¥¥¥¡¡¡µµµÎÎÎÊÏÏËÎÎËËËËËËËËËËËËËËËËËËËËËÊÊÊÍÍ;¾¾¾¾¾ÐÐÐÐÐÐÎÎÎËËËËËËËËËËËËËËËËËËËËËÊÊÊÎÎÍ´µµ¡¡¡¥¥¥¤¤¤¥¥¥¡¡¡žžžžžžžžžžžžžžžžžžžžžžžžž      žžžžžžžžžžžžžžžžžžžžž¡¡¡¤¤¤¤¤¤¤¤¤¤¤¤¥¥¥¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¥¥¥¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¥¥¥¤¤¤¤¤¤(  ¤¤¤ ¡¡ŸŸŸŸŸŸ   ¡¡¡žžž   ¢¦¥¡§¥¡§¥ ¦¤£¨¦¢¨¦¡¦¤¤¤¤¡¡¡ÐÐÐçççãããàààÙÙÙêêêרØÃ†™Ë~—É€—Í‚šÀ|’Æz’ÁŒ¡¦¤ŸŸŸãããÿÿÿÿÿÿ÷÷÷ÆÆÆØØØäååÖx–ßjßn’Ôh‹ Nh«MkÈ{”¢¨¦ŸŸŸâââÿÿÿûûûÿÿÿÎÍͪªªâââÒ|—ÚnÙq’×o‘¥Wp²WtÉ€˜¡§¥ŸŸŸãããÿÿÿýýýýýýñññõõõìííÓz–ßo“Ûq“às–Åf…Íd…΂› ¦¤¡¡¡ÚÚÚØØØôôôÿÿÿþþþÿÿÿðððÅsÌf‡ÑmÑlŒËj‰ào“É€—¡§¥ŸŸŸãããÛÛÛíííÿÿÿþýþÿÿÿòñòÀmˆ¼ZyÊe…Íf‡Âa€ák‘Ë~—¡§¥¡¡¡ÕÕÕàààéééïïïðððôôôáááÊ€˜Ïu’Òz–Ïw“Îx“Öx–Â…™¢§¥   ÙÙÙ÷÷÷îîîòòòàààÞÞÞæææáááòóóíîíõõõìììèééÜÝÝŸŸŸŸŸŸãããÿÿÿÿÿÿùùù¿¿¿»»»ãããñññÿÿÿÿÿÿæææÅÅÅÀÁÁÚÚÚ¡¡¡ŸŸŸâããÿÿÿüüüÿÿÿÐÐÐÊÊÊïïïîîîÿÿÿÿÿÿêêêÊÊÊÄÃÃÛÛÛ¡¡¡ŸŸŸãââÿÿÿüûûÿÿÿîîîíííòòòìììÿÿÿþþþÿÿÿøøøýýýåå域ŸŸŸŸâááþ××ûïïýÿÿýýýÿÿÿîîîååå×××òòòþþþûûûÿÿÿáá៟ŸŸŸŸäããÿÞÞþùùÿÿÿþþþÿÿÿðððìììÒÒÒôôôÿÿÿýýýÿÿÿãã㟟Ÿ¡¡¡ÐÎÎæÜÜâââãããâââåååÙÙÙÔÔÔÚÚÚâââãããâââçççÐÐР¡¡¤¤¤¡¡¡Ÿ¡¡ŸŸŸŸŸŸŸŸŸŸŸŸ   ¡¡¡¢¢¢ŸŸŸŸŸŸŸŸŸŸŸŸ¡¡¡¤¤¤(0` ¤¤¤ªž¢­­­§©ªÍÍÍþþþÄÈÇÈuÚq’×oÜo’ØlÐÐÐäää¥TnªWqììì²²²ÐÏÏ”LcÜÜܧUp™Nfân“ÓlÃÄÄÃd‚ÍjŠ·_{¼a~Èg†âu˜óóóüóóÊv‘áq•²Zw¿c€®Yt¼¼¼¹_|¼zÇtÆÊÉøÏÏøººûßß÷ÔÔ÷®®üää÷°°ûèèúÕÕ÷¾¾                    !!!!!!"      # $   !$  #%% & '  #&    (!#%'%' $'  # ''    ((# )  ""#$    $$ (*###++(,, "!! "((! "! !(! ((! !"  !"!!    !  !! -.../(((( "012!!" 23" 23" 451"(06."((      ( @¤¤¤¨¨¨¥£¤ŸŸŸ   ¡§¦ ¨¥Ÿ§¥ §¥¡¡¡µµµÍÍÍËËËÏÏϾÁÁ²’¼Ž»Žœ¾ž¯š¡ÿÿÿéééúúúâèæÇx‘ãj‘Þn’ÝlÙkçn•ºYxÀ^}âp•ágŽüüüãããÀÀÀÖÕÖìêëåëéÙq’Þt–·_{’Lc˜MeÅh…ôôôÃÃü¼¼¬¬¬îîîÄy‘Ùo‘³[x‘Ja•LdÇ`±±±Üq“Øp‘Ég†Âc‚£SmÍc…ÛÛÛíììÓl¤Tnán“åååÅ{’Ïj‹àæäÒlŒØØØþùùÞãâÛq“òòò¾a²\xÅeƒÖnÍjЧUp²WtÆf…°ZuÑhŠ®[u¾b€©WrÖjŒÝÝÝÈx’âââÍÑйƒ•Ç{“Äz’Æz“ßßßàààÌËËÊÏÏŸŸ ÒÒÒ¿¿¿´´´÷÷÷ûûûÈÈÈóóóøÊÊöÄÄùÜÜø»»¹¹¹ûèè÷¿¿ëëëýììÿóóËÎÎ     !" #$%&'()))))*+,-.! /0123(45))5))67--89 #1::3();)<=>-?.@ #A2:B())5))!C8D*E #FFFG;)))5);H8?5 I)));55HJ) /KAF##LM<))N55;;) O2 3##4PQRSP)TU>)) / O##4VQPWU=;XJ;) O% LMYZ[;.*H\]N) &^_5]!E;55;1FFF`^`^^^M^$abcdeeeG 1$^^^M^Mfg^f`hi(IMIIIIMI(j #K #^`&  ####k22l`^O/`k  L#K:m:: ^^O2:2 ^  #no123^`/111::  L12O`^2F  #p1q^``  ##^^#  Lrst``` k#  tuL^^/3v`#  wsg`&1/  sx####^`y 3  z{^`/  || p|11 k    ( ¤¤¤ ¡¡ŸŸŸ   ¡¡¡žžž¢¦¥¡§¥ ¦¤£¨¦¢¨¦¡¦¤ÐÐÐçççãããàààÙÙÙêêêרØÃ†™Ë~—É€—Í‚šÀ|’Æz’ÁŒÿÿÿ÷÷÷ÆÆÆØØØäååÖx–ßjßn’Ôh‹ Nh«MkÈ{”âââûûûÎÍͪªªÒ|—ÚnÙq’×o‘¥Wp²WtÉ€˜ýýýñññõõõìííÓz–ßo“Ûq“às–Åf…Íd…΂›ÚÚÚôôôþþþðððÅsÌf‡ÑmÑlŒËj‰ào“ÛÛÛíííþýþòñòÀmˆ¼ZyÊe…Íf‡Âa€ák‘ÕÕÕéééïïïáááÊ€˜Ïu’Òz–Ïw“Îx“Â…™¢§¥îîîòòòÞÞÞæææòóóíîíìììèééÜÝÝùùù¿¿¿»»»ÅÅÅÀÁÁâããüüüÊÊÊÄÃÃãââüûûøøøåååâááþ××ûïïýÿÿ×××äããÿÞÞþùùÒÒÒÐÎÎæÜÜÔÔÔŸ¡¡¢¢¢    !"#$% &'()&*+,-./01123456789:;<=>?@ABCDEFGHIJKLMNOPQR?=STUVWXYZ[\]^S_`3abcdef2^gh<ij kR[klFmn[G\a>o1pqrst1[pu\>'Svwx>?ay=1z{&&p|<&& }~(0`€€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿw÷÷÷÷ww÷÷÷÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿwwwwwwwwwwwÿÿÿÿÿÿÿÿÿÿÿÿwwwwwwww‡wwwÿÿÿÿÿÿwÿÿÿÿwwww‡wwwwwwwÿÿÿÿÿÿÿÿÿÿwwwwwxwx‡wwwÿÿÿÿÿÿ÷ÿ÷÷wwwwwwwwwwwÿÿÿÿÿÿÿ÷÷÷ÿÿwxwxwwwwwwwwÿ÷ÿÿÿÿ÷ÿwwwwwwwwwwwwÿÿÿÿÿÿÿÿwwwwwwwwwwwÿÿÿÿÿÿÿÿ÷÷ÿÿwwwwwwwwwwwwÿÿÿÿÿwÿ÷wwwwwwwwwwxÿÿÿÿÿÿÿÿÿÿÿÿwwwxwxw‡wxwwÿÿÿÿÿÿÿÿÿÿÿwwww‡wwwwwwÿÿÿÿ÷ÿÿÿÿÿwwwwwwwwwwwwÿÿÿÿÿÿÿÿÿÿÿwwwwwwwxwwwÿ÷ÿÿÿÿÿÿÿ÷wwwxwwwww‡ww÷÷ÿÿÿÿÿÿÿÿÿwwxwxwwwwwwÿÿ÷ÿÿÿÿÿ÷ÿÿwwwwwwwwwwwwÿÿÿÿÿÿÿÿÿÿÿÿwwwwwwwxwwwwÿÿwÿÿÿÿÿÿÿwwwwwwwww‡wÿ÷ÿÿÿÿÿÿÿÿÿwwww‡wwwwwwwÿ÷ÿÿÿÿÿÿÿÿÿ÷wwwwwwwwwwwÿÿÿÿÿÿÿÿÿÿ÷wwwwwwwwwwwÿÿ÷÷ÿ÷ÿ÷ÿwwwwwwwwww÷wwÿ÷ÿ÷ÿ÷ÿ÷ÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷÷ÿÿÿÿÿ÷ÿÿÿ÷ÿ÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷÷÷ÿÿÿÿÿÿ÷÷÷÷ÿ÷ÿÿÿ÷ÿ÷÷÷ÿÿÿÿÿÿÿ÷ÿÿ÷ÿÿÿÿÿÿÿÿÿÿÿÿÿw÷÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿ÷ÿÿÿÿÿÿÿ÷ÿ÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿÿ÷ÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷÷ÿ÷ÿÿÿÿÿÿÿ÷÷ÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿ÷ÿÿÿÿÿ÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿ÷ÿÿÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿÿÿ÷ÿ÷ÿÿÿÿÿÿÿÿÿÿ÷ÿÿ÷ÿÿÿÿÿÿÿ÷÷ÿÿÿÿÿÿÿÿÿ÷÷ÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿÿÿÿÿÿ÷÷÷÷wÿw÷÷ÿ÷÷÷wÿw÷( @€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ‡‡ˆxˆw‡‡‡‡xxxxxw‡÷w÷wwwxx|‡}ˆ‡xwÿÿÿÿÿÿÿÇ×wW‡|‡‡ÿÿÿ÷‡÷÷x|Ç||V×xwÿÿÿ÷ww÷؈×Èȇ‡‡ÿÿ÷ÿw‡ÿwˆw|ˆ…ŒÇwÿÿÿÿww÷ÈØÇw׈ØxwÿÿÿÿwwÿˆˆÇŒÈxw‡ÿÿÿÿÿÿ÷wˆŒØˆ…wÇwÿÿÿ÷ÿÿÿ͈wxx}LJwwwÿÿÿÿ÷wÈ׈؈ׇ‡÷ÿÿÿ÷ÿŒu|ÇŒˆxxwÿ÷ÿÿÿÿÿxÈxÇ||̇wwwÿÿÿÿ÷×Ljh×wx‡ÿÿÿÿÿ÷xˆØx×Ç}‡w÷÷w÷}ˆ‡ÇÇwXx‡÷ww÷÷ww÷xwÿÿÿÿ÷÷ÿÿÿÿ÷ÿw‡ÿÿÿÿwwÿÿÿÿÿÿwwÿÿÿ÷xwwÿÿ÷wwx‡ÿÿÿÿwwÿÿÿ÷wwwwwÿÿÿÿ÷÷ÿÿÿÿxwwÿÿ÷ÿwÿÿÿÿÿÿwÿx‡ÿÿÿÿ÷÷÷ÿÿÿÿwwÿÿÿÿÿÿ÷ÿÿÿÿÿxw÷wÿÿÿÿwÿÿÿÿw‡ÿÿÿ÷ÿ÷÷ÿÿÿÿw‡ÿÿÿÿÿÿwÿÿÿÿÿx‡÷ÿÿÿÿ÷ÿwÿÿÿÿwÿÿÿÿÿÿÿÿÿÿÿÿÿx‡wwww÷xwwwwwwwxxw‡xˆxw‡‡xw‡‡ˆx( €€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ‡ˆ‡ˆwxxwwÿw÷ˆ|xÿÿÿwÇX‡÷÷‡xŒwÿÿ×|‡ÇwÿÿŒwLJwÿ|ˆ‡wÿ‡ˆxw÷÷ÿwÿ÷wÿÿwwÿ÷ÿ÷ww‡ÿÿ÷ÿÿøÿ÷ÿÿø÷ÿ÷ÿw‡÷ÿ÷w÷ÿww‡‡‡‡‡ˆxpuzzles-20170606.272beef/icons/samegame.ico0000644000175000017500000006117613115373743017274 0ustar simonsimon 00 ¨%–  ¨>& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $æææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææääåããæääåääåääåääåääåääåääåääåääåääåääåääåääåääääåääæääåääåääåääåääæääååääåääæääåääääåääåääæääåæääåääæääåäääåääåääåääåäæææææææææææææææææææææåååçîîèòòèññèññèññèññèññèññèññèññèññèññèññèññèññèððððèòòèññèññèññèññèòòèððèèððèññèñòèððððèññèòñèððèèððèññèòñéðððìðñíñòíòïëïææææææææææææææææææèççÝääëWWÿ55ý==þ;;þ;;þ;;þ;;þ;;þ;;þ;;þ;;þ;;þ;;ý<=þ66üUSYWø56ÿ==ý;;þ;;þ==ý56ÿYWøüUSþ77ÿ65öX\QTþ87ý56ÿ`YôÿRNý88ÿ56ò_[K©Q:›83™3h³hïëïäåäææææææææææååèççÜååë((ÿþÿÿÿÿÿÿÿÿÿÿþÿý!'$øÿþÿÿþÿ'$øý!ÿÿõ&+ÿþÿ/'òÿþÿï.)‹xt;™;ñíñäåäææææææææææææèææÜååê))ÿýþÿÿÿÿÿÿÿÿÿþÿý#"'$÷ÿýþþýÿ'$÷ü! þÿõ&+ ÿýÿ0'òÿ!þÿï0+Ž{x;›;ñíñäåäææææææææææææèççÜääë;>ÿþÿÿÿÿÿÿÿÿÿÿþÿý" 8=ù ÿþÿÿþÿ?9øý:1ÿÿö><55ÿþÿF;óÿþÿñ/*/Ÿ/Ž‹ Q©KðìðäåäææææææææææææçççãàäP”H/‹#1Š%D›@ò-)ÿþÿÿÿÿÿÿÿÿþñ*3ï*5ñ#.ìDOD˜O$Š/$Š.GšRNCï/$ï/#ñQJêCšJ%Š0!‹/P—Qÿþÿñ+3:Fõ'+ï%ï[_òððéääåæææææææææææææçæåáå)‰)|{ï/)ÿþÿÿÿÿÿÿÿÿÿÿþÿû##$Ž#{|$'! ýÿÿ&)õ Ž{|0Œ'ÿýÿï*5ÿþÿ;;þññèääåæææææææææææææçæåáå)ˆ){zð.(ÿþÿÿÿÿÿÿÿÿÿþýÿú$%#Œ#zz$Œ'! üþÿ&)ô z{0‹'ÿýÿï)4ÿýþ==ýññèääåææææææææææææçèçäàä;—@+ 8ð0+ÿþÿüüüüüüüüÿþÿû$$8ž=ŽŽ9œ@;8ýÿÿ??ö4ž6ŽC›@ÿ38þÿð>Kÿþÿ;;þññèääåææææææææææææèççÝääáJGö% ò-(ó-)þ ÿÿüè××çááçÞÞçßßçßßçÞÞçßßçààû&&ÿÿþô,(ò-(ô%!îJFA›J#‹+!‹*KšMôDAò'#ô%"êNHC›@,Š$+ŒN—Rÿþÿ;;þññèääåææææææææææææèææÜååë))ÿþÿÿÿÿüçááæêêæççæèèæèèæèèæèèæêêú((ÿþÿÿþÿø&$Ž!{|+Œ&ÿ þÿó+'Ž{|)‹4ÿþþ<=ýññèääåææææææææææææèææÜååê**ÿýþÿÿÿüçÞÞæççæååæååæååæååæååæççû''ÿÿÿþþÿø&$!zz+‹&ÿ þÿò+'z{)Š4ÿþÿ;;þññèääåææææææææææææèææÜååë))ÿþÿÿÿÿüçßßæèèæååæææææææææææææççû@Aÿÿ!ÿÿþ!ÿø@<7<ŽBœ@ÿ8;þÿóDB1ž:@šL83ÿþÿTRþððèääåææææææææææææèææÜååë))ÿþÿÿÿÿüçßßæèèæååææææææææææææçççKF%‹ 'Œ!HšCHBò'!ö%!öKDñõD@õ$!÷"!ïJEBœ@(‹!$Œ RšGø??ô%!ø" êOH7œC$Œ(‰"X¨\ðìðäåäææææææææææææèææÜååë))ÿþÿÿÿÿüçßßæèèæååææææææææææææèçè''z{####ûÿÿ'$øý!ÿÿõ)&Ž {|/‹'ÿþÿï.)Ž{x;›;ñíñäåäææææææææææææèææÜååë))ÿþÿÿÿÿüçßßæèèæååææææææææææææèçè)’(}~%$##ûÿÿ'$øü#!þÿõ*' z{0‹'ÿþÿð.)Ž{w;›;ñíñäåäææææææææææææèææÜååë))ÿþÿüû!!üù55çààæèèæååææææææææææææèçè'‘'}~#$??ùþþC?÷ý!ÿÿö)'9ž;ŽJ›Aÿ99üÿðIC3ž8Ž‹U©SðìðäåäææææææææææææèææÜååë))ÿÿýçÚÚææææââæääæææææææææææææææææææææèçè'‘'|€ƒ%'&(Œ!E›Eý !ÿÿö'+ûû$$ú##û##û##û$#û"!ûÿÿÿ;;þññèääåææææææææææææèèèÝÝÝØØØéèèåååææææææææææææææææææææææææææææææææææææææææææåæåæææåæå##}€ƒ$#########%%KšEý:=ù þìDOÿþÿ;;þññèääåææææææææææææèèèÝÝÝØØØéééåæææææææææææææææææææææææææææææææææææææææææææææææçæçæææ%%}€}}}}}}z0‹'ÿþÿð)4ÿýþ==ýññèääåææææææææææææèèèÝÝÝØØØéèèåååææææææææææææææææææææææææææææææææææææææææææåæåæææåæå##y~}~}}}€~1Ž)ÿþÿï)4ÿþÿ;;þññèääåææææææææææææèèèÝÝÝØØØéééåååæææææææææææææææææææææææææææææææææææææææææææææææææææDœB!Œ)&'$'$'$($&$‚€}/)ûü"#÷øWXøððèääåææææææææææææèèèÝÝÝØØØéééåååæææææææææææææææææææææææææææææææææææææææææææææææææææú??þý"#ý !ý !ü""ÿôCA}~(Ž/:9ÿüÿCIï:ž1Ž‹U©SðìðäåäææææææææææææèèèÝÝÝØØØéééåååææææææææææææææææææææææææææææææææææææææææææææææççæææû##ÿÿÿÿþÿõ)&!}~)1ÿþÿ).ðŽ{w;›;ñíñäåäææææææææææææèèèÝÝÝØØØéééåååææææææææææææææææææææææææææææææææææææææææææææææççæææû##ÿÿÿÿþÿõ*'Ž z{'‹0ÿþÿ).ðŽ{x;›;ñíñäåäææææææææææææèèèÝÝÝØØØéééåååæææææææææææææææææææææææææææææææææææææææææææææææææææóFCö"õ*'ö(&þþÿö(&Bœ@'‹"&ŒK™MD<÷'"ô&øLLê=œ<#Œ)‰"X¨\ðìðäåäææææææææææææèèèÝÝÝØØØéééåååæææææææææææææææææææææææææææææææææææææææææææææææææææ;>Ž>œ?ý!!ÿÿþÿ ÿ ÿ þÿþ!ÿñCI16ÿþÿTRþððèääåææææææææææææèèèÝÝÝØØØéééåååæææææææææææææææææææææææææææææææææææææææææææææçæçæææ#Ž#z{'$ý"#ÿþÿÿÿÿÿþýÿï)4ÿýþ;;ýññèääåææææææææææææèèèÝÝÝØØØéééåååæææææææææææææææææææææææææææææææææææææææææææææçæçæææ#Œ#xz'‹$ý !ÿþÿÿþþÿÿþÿð)4ÿþÿ;;þññèääåææææææææææææèèèÝÝÝØØØéééåååæææææææææææææææææææææææææææææææææææææææææææææææææææK¡K*’))“*N LøHIû))ù00ú..þÿÿþ ó)0ò(1õ 'èIX9C÷%(ò"òY]ôððèääåææææææææææææèèèÝÝÝØØØéééåååæææææææææææææææææææææææææææææææææææææææææææææææææææêèêëèëëèëêèêåêêåëëåííæææüÿÿó)0.9ÿþÿ=Fñ7ž+Ž‹R©NðìðäåäææææææææææææèèèÝÝÝØØØéééåååæææææææææææææææææææææææææææææææææææææææææææææææææææåæååæååæååæåæååæääæçççààûþÿò)1ÿýÿ).ïzw;š;ñíñäåäææææææææææææèèèÝÝÝØØØéééåååæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææååæçççááüÿÿó'/ÿýÿ*/ï‘~{<=ñíñäåäææææææææææææèèèÝÝÝØØØéééåååææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææåæççæââîE@ï*%ò*!æLPÿþÿ).ð~z;;ñíñäåäææææææææææææèèèÝÝÝØØØéééåååææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææåæåçççâäâ.›5Ž8šFÿþÿ).ð~z;;ñíñäåäææææææææææææèèèÝÝÝØØØèèèååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååçæçáãáŠz{'‹/ ÿýÿ*0ï‘~{==ñíñäåäææææææææææææèèèÝÝÝÚÚÚìììèèèééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééèèèêéêäæä‹{|(Œ0ÿþÿ)/ð{x;›;ñíñäåäææææææææææææèèèÞÞÞÎÎÎÚÚÚØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØ×Ø×ÙØÙÔÖÔ>”>%ˆ%$‰"G”M@=í%%ê#"îHLß>—9&‰' † W¡WîêîäåäææææææææææææææææææÞÞÞÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝäàäæáææáæäàäääÜææÜææÜääÝäàåæáåæáæäàäåååæææææææææææææææææææææèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèçççæçææçæçççççèææèææèççèçèçæçææçæçççææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææåææææææææææåææææææææææåæåæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææ( @ æææææææåååååæååæååæååæååæååæååæååæååæåååååååæååæååæååæåååæååæåååååååæååæåååæååæåååååååååååææææææææææææçêêèììèììèììèììèììèììèììèììèììçììëëèììçììèììèììçëëèèììçììéëêììçììçéëêçììèììëêëíêìëéëææææææèççàããïJJþ+*ü21ý//ý//ý//ý//ý//ý//û,/ÿ9.mKØ&+ÿ41ú32ú$,ÿlLÙÿ:4ÿ,#±Q˜%1ÿ)5ÿÃO…ÿ)ÿ:@^˜L“$W¨Wëéëåååèççßããð""ÿþÿÿÿÿÿÿüÿ K#ÔÿýýÿK"Óÿ ÿ¢(ÿÿ¶'kÿÿ9!v1“0ìêìåååèççàããÚG=ä(è,#ÿÿÿÿÿÿýÿ s7½.ë;$ä'/ä)é^GÉë,<í- H“.ì5ð¿5eÿÿS…M~.L˜^ëêëåååçççãáã/’2ŠC‹/ÿ þÿÿÿÿÿÿþ ÿ ù+ 2’$ ‹4†Sÿ ÿ4b¥’ •ºN*ÿÿ F+ãÿ?:üììèååæçççäáä%Œ#9†"ÿþÿÿÿÿÿÿýÿö‹ƒ$}L ÿÿ(V¢ŠŒ ¶J'ÿÿ :!âÿ10ûììèååæçççââã{{BamŒm6ÿ ÿú,,ókkôbbôddôccôiiû ÿú|s6gmt{[/Q¿D½`rrqht.ªmG¸A!¿X.3)çÿ11üììèååæèççßäãñ"'ÿþÿÿókkâÿÿåòòäööäôôãÿÿôMLüûý ÿÔ8) ” †j*ÿÿ kt,”!/áÿ02ùììèååæèççßääí""þûÿÿôbbåòòçßßæââçààåïï÷FGÿÿýÿÓ:#’i+ÿÿks(‹’ #.ãÿ21üììèååæèççßääñ""ÿþÿÿôddäööæââæææåääìíð cx\Žk8Ž6{¥–L˜§_,¢P%¢tI€g)‚i-¤rH O"«`4Ov‡\|Q—ëêêåååèççßääñ""ÿþÿÿôddäööæââæææãåãóëóH¥I€’"öÿL$Òÿÿ¢V(޶J'ÿÿ9†!1š0ìêìåååèççßääñ""ÿþÿÿôddäööæââæææãåãòìóKžIv!‰","öÿW(Òÿÿ¦Z(“ ”½W'ÿÿEŽ#‡<Ÿ2ìêìåååèççßããð%%ÿù//éÈÈê¾¾èÑÑæééæååæææãåãóìóH Hz …)I|JcxVÿ ÿ­(xk-…i!”K} §Œ6¦Lr“]yQ˜ëêêåååèèèàààÜÜÜèèèæææææææææææææææææææææææææææåæåçççáäâ –"‹L†*ÿüÿÿÿÿþÿ :!ãÿ20üììèååæèèèàààÜÜÜèèèæææææææææææææææææææææææææææåæåçççáäá †xLv#ÿ ýýûûþþÿ >"ãÿ60üììèååæèèèàààÜÜÜèèèæææææææææææææææææææææææææææææææææååå±Î°£Ê¥½Ê²ð§©ë³²ónnþÿ¨3ƒ^#¿x2ºIy„h`O‰†ëêêåååèèèàààÜÜÜèèèææææææææææææææææææææææææææææææææææææñëñôìóîìñäïîãÿÿížžûÿ k)¸ÿÿ!‡:0›1ìêìåååèèèàààÜÜÜèèèææææææææææææææææææææææææææææææææææææäåäãåãäåäçààåññýÿ n+¹ÿÿ"‚<z1•5ìêìåååèèèàààÜÜÜèèèåååææææææææææææææææææææææææææææææææææææææææææãäãñìò©Ã¡,yD7K¿ÿÿ#ƒ;|1—3ìêìåååèèèßßßÞÞÞêêêèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèåæå÷ï÷—×u ‹'I·ÿÿ!:y0”1ìêìåååèèèàààÕÕÕÞÞÞÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÚÛÚèâ蜿œ‚,”B]¶û1.ó=ŒQ†JKêéêåååææææææàààßßßààààààààààààààààààààààààààààààààààààààààààààààààßßßáàáäáäãáäãâàääßããßãáãäáäãáãææææææææææææèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèçèçççççççççèççèççèçççççççççææææææ(  æææãäâæãâèââèââèââçâãæâäâäãããæããæâåãçããæãäâãçæææãÞÞø1;ÿü$$ù%(ÿ#¨6ƒ#ÿÿ»0há/;'ÿé&S¦^0¯2æããâÝÝni%Á( ÿûÿÚ 1…‡ZxW-“nšd€ç "Bb«çâãáÝÝ.‘-£?ÿ ö:8ø;:þ õ Q„Mž;È=‹ÌB "ÿæãäãÝÝ÷ %ÿø;;åñòäûûüÿ cn4‚ÿ(7Š\~,ÿâåäãÝÝõÿù66ãêéñëò«¼–EhBãŸ$k¹G :…Ö< ŽO!Qæãââßßøû00ðŠŠâçåõëõ”Ã’{Q¸° LÝk}švk-m%|tåãäâáá÷ ïššãÿÿãáßóìóŸÆž€“ªJ ÖK ÿýÿ$!ýâãèâââãÙÙèààæããææææææåååÒÞÓ’‰ † ‡ê1› t#ÿçâãâââáääçèèæææææææååèèéæàà´I&ª4 |X’c+™I5’+}mäãåââââááçççæææææææååæèèåÝÜÙ7&ûÛ!E~B!Ç'?œ-=ããæââââââçççææææææåæåéçéààÜžœDÿø ÿ —w$ÿçâãâââáááçççææææææææææææååäÃÕÂÚÓËð™œÿh¿&D›0FããæââââââèèèçççççççççççççççïèìíõùÔÍÙJ)ë=›%œâãæâââÞÞÞâââáááââââââââââââÞàÞêãé·Ðº›+6â&N¡;¡,âãææææââââââââââââââââââââââââââââáááÞÝÞÝâÝÞàÞáÞæææ(0` æææèææçèçéééÜååæééèññññèñíñëWWý55ý;<û–<þ '(ø ý|ð>Kþ6>ü ÿÿÿÿý:1ÿö><ð0+/Ÿ/Ž‹ R©MçÞÞP”H0‹'CœAï*%ï)4ìDOBšL$‹,&‹0GšRNCï/$ï/%òQJêP—Q;Eô'+ïZ^ó*Œ+%$&)ô1Ž)þ %$ú";—@.›59›C85þ??ö4ž:ÿ38ÿáJGõ$"ò-)è××ú**ïJFKšMôDBêOH+Œ%+ŒN—Rõ*&)Œ2#üŒ!û@Aÿø@<J›D † JCòðICRšGX¨\)’)%%U©Sççè?(@@ ABCDEFGHIBCCJ#@KLLMN+&%$O++C!PQ++RS@0D&+%$O++OTPU++=#@0;V%%W$##-##-##(%XYZ11[\%%>]^-,0_`aa(#b;;;;;;c(aa`dYCCef``g>hij1#;kkO++h#aQ++lm-;n++NSaQ++l!#;o^S#pq%%>]#^fWQ%YZ!1#;rsOrttf``u>iOvq`gYCnw#;N++OTkQ++N#?%+&#;x++yTkn++=#?z++## ;x+{y[!!tkQQr ##d\z8|}-bx+{{yynrS ~*P)T))1}-;x+{{+++O *.}^;N+++{{+N *[€#S ;>Qyy{{+yo#.!TTTTTT;‚y+{{yOyyOOQr5S#ƒ0‚y+{{++{+++&NS„0…‚O+++++++{{{N#@0…‚>UxyhyyO{{+R SSƒ!…‚5#S^fz+{x!!†‡QX|…‚kˆ++l!‰8+&;‚kˆ++N!‰8+&…‚`kk(k>OUemŠNnw…‚%%>(SS##p!2……O++O@0…‚O++hS„0……exx‹Œc„c(@@SKPŽM‚}#„02K8X:…‚;„0‘8++'…‚};# *‘’++…‚€?k“0”’{+…‚}W%•Y!”8++‚}};Q&+lm‘Q{+…‚Q++l!”8&+';–…‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚‚'Cs—˜™™šVCs›;……;……………………………………;…………;;œœœ;};}}}}}}}}}( @ççèåååèçççèçæììììçéééïJJü..ü75ÿ9.mLÙ%,ÿ21ûü,"±Q˜'3ÿÃO…ÿ)ÿ:@T’R#‹#Y¨YéåéÝâÝñ##þÿ ÿ L#Óÿ¢(¶'kÿ9†"v+Œ<ÚG=ä(ë'#v5¼.ë;"ã$/ã,ë^GÉí4<í- H“9é¿5e“"ßää/’2‚GŠ)þ ÿ 2’$Š9‰Rÿ þ4b¥“ ”ºJ)F+ã?:ü2ƒü'~K'O±“¶J'qzQdml7ókkôcczo2-Q»D½`rrqjt+«jD¾X+3)çãÿÿäôôÒ;)Œƒi+èØØääßÓ:# cx\Ž6{¥–L˜¤[*¢S'£sI«`4Lx†]{Q˜óìóH£I“#õ0š1II.)úÿD;Ÿ3éÈÈ빸 ƒ |J­?@AB9CD6E9F6G>H;IJ* KLM8NOOONFFPLKQRSTUVJWX 4NYZZZY[A\]U\@+ 4OZ^__`A\]U\@+ 4OZabMcdefgh]]hgijkl4OZmn6opg\\J!"6q4OZmr#stfIIWFu;v4'wx^mn#yGzK{1|}|~ Zmn#666€{> 4.8m‚y67ƒ9„…pp††> ‡ˆ#yˆ‰‰Š3‹Œ* ‡‡‰666\J9* 4‡Ž€€€"\‘’“~4‡ƒ88”6•H=$\v‡_Ff\IH–—6˜^‡V™J[Pše›cœkl‡6789* ‡‡4Š#€89* ‡‡žŸž xN¡(j¢£‡m¤¤Y¥¡–—6˜‡¥9¡¦—#˜4‡mŸ§u¨–—˜‡m©#•H–—#˜‡ª4‡‡‡‡‡‡‡‡‡‡‡‡‡‡‡ª«‚¬¨p <‚r4^44^444^4‡‡4‡^_( æææãäâæãâèââçâãæâäâäãããæâåãçããæãäâãçãÞÞø1;ÿü$$ù%(ÿ#¨6ƒ#ÿÿ»0há/;'ÿé&S¦^0¯2æããâÝÝni%Á( ÿûÚ 1…‡ZxW-“nšd€ç "Bb«áÝÝ.‘-£?ÿ ö:8ø;:þ õ Q„Mž;È=‹ÌB "ÿãÝÝ÷ %ø;;åñòäûûüÿ cn4‚ÿ(7Š\~,ÿâåäõù66ãêéñëò«¼–EhBãŸ$k¹G :…Ö< ŽO!Qâßßøû00ðŠŠâçåõëõ”Ã’{Q¸° LÝk}švk-m%|tåãäâáá÷ ïššãÿÿãáßóìóŸÆž€“ªJ ÖK ÿýÿ$!ýâãèâââãÙÙèààåååÒÞÓ’‰ † ‡ê1› t#ÿáääçèèæååèèéæàà´I&ª4 |X’c+™I5’+}mäãåçççæèèåÝÜÙ7&ûÛ!E~B!Ç'?œ-=åæåéçéààÜžœDÿø ÿ —w$ÿáááååäÃÕÂÚÓËð™œÿh¿&D›0FèèèïèìíõùÔÍÙJ)ë=›%œâãæÞÞÞÞàÞêãé·Ðº›+6â&N¡;¡,áÞÝÞÝâÝÞàÞáÞ  !"#$%&'()*+,-./012345678 9:;<=>?@ABCDEFG9HIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€u‚ƒ„…†‡ˆ‰Š‹ŒueŽƒ‘’“”•–—uuŽ˜™š›œžŸ ¡u¢Ž£¤¥¦§¨©ªuu«ŽŽŽŽŽ¬­®¯°±²³u´u¢uuuuµ¶·¸¹º»³uuuuuuuuue¼½¾¿(0`€€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüŒÌ|xÌŒxŒÈ—‰˜sŒÈˆ‰˜ŒŽ‚‚üÌÌÌÌÌÌÌÌÇ™™™™|ÌÈ™‰ÌÌ‚"oøÌÌÌÌÌÌÌÌÈ™™™™ŒÌÉ™™ÌÌ‚"üÌÌÌÌÌÌÌÌÉ™™™™ŒÌX™™ÌÌ2"oöˆŒÌÌÌÌÌÌȉx‰‰ˆ‡‰ˆÌÌvƒø&(ÌÌÌÌÌÌÌÌÅb&‰™8*(Ì̉¹Ÿò"£ÌÌÌÌÌÌÌÌÌ2"‰™˜"¨ÌÌ™™ò"(ÌÌÌÌÌÌÌÌÌ‚"‰™ƒ"(ÌÌy™Ÿò(fÌÌÌÌÌÌÌÌÈ¢"‰™˜*(ÌÌ™™üƈÌÌÿwÿ|ÌÌÈÈx¨ŒÈÇŠˆ‰™ŸøÌÌÌÌÿÿÿÿÌÌÌÌ‚"'ÌÈ"#‰™øÌÌÌÌÿÿÿøÌÌÌÌÂ",ÌÆ2"™™üÌÌÌÈÿÿ÷ÿÿÌÌÌÌ‚"'ÌÈ"¢‰™ŸüÌÌÌÌÿÿÿwÌLjÈxЇÈ|Š8˜‰üÌÌÌÌÿÿÿÿ÷"(‰™ŒÌÈ"(ÌÌŠ‚üÌÌÌÌÿÿ÷"(‰™œÌÈ"(ÌÌ‚"øÌÌÌÌÿÿÿø""™™|ÌÃ"(ÌÌ‚"üÌÌÌÌÿÿÿ÷ø"#™™ŒÌÆ"(ÌÌ‚"øÌÌÿ÷ÿÿÿ÷"&¨ˆ|̈‰ˆ¸x‰ˆŸöÌÌÿÿÿÿ÷ÿ÷""""ŒÌÇ™™™™™™?üÌÈÿÿÿÿÿÿ÷""""ŒÌÉ™™˜™™™ŸøÌÇÿ÷ÿÿÿÿö"""*ŒÌÇ™™™™™™ŸüÈÇÿÿÿÿÿÿ÷2c""ŒÌɘ™™˜™™wÿÿÿÿÿÿÿÿÿÿÿ‚¢"‚"ŠhÎÌ™‰Ÿÿÿÿÿÿÿÿÿÿÿÿÿ""""""(Ì̹™ÿÿÿÿÿÿ÷ÿÿÿÿ"""&""(ÌÌy™xÿÿÿÿÿÿÿÿÿ‚"""""#ÌÌ™™Ÿÿÿÿÿÿÿÿ÷ÿÿxˆˆhˆ"(ˆ‡˜˜÷ÿÿÿÿÿÿÿÿÿÿÌÌÌÆÊ"&™™b"÷ÿÿÿÿÿÿÿÿÿÿÿÌÌÌÌÈ"¨™™‚"ÿÿÿÿÿÿÿÿÿÿÿÿÌÌÌÌÃ"(™™Š"÷ÿÿÿÿÿÿÿÿÿÿÿŒÌÌÌÈ#(‰™‚2ÿÿÿÿÿÿ÷ÿÿÿÿ‚ƒŒÌÌ|ŒÇ^‰‰?ÿÿÿÿÿÿÿÿÿ2*lÌÌÌÌÌÌy™Ÿøÿÿÿÿÿÿÿÿÿÿÿb"ŒÌÌÌÌÌÌ™™øÿÿÿÿÿÿÿÿÿÿ""lÌÌÌÌÌÌy™ÿÿÿÿÿÿÿÿÿÿÿÿˆhwŒ|ÌÈ|h‰‰Ÿøÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿ÷ÌÌ™™‚"ÿÿÿ÷ÿÿ÷ÿÿÿÿÿÿÿÿÿüÌÈ™™Š"ÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿÿÿ÷ÌÆ™™j"÷ÿÿ÷ÿÿÿÿÿÿÿÿÿÿüÌÈ™™‚"wÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿÿ÷h‡™™‚"/ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿó"&™™‚"÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿø"(™™‚"ÿÿÿÿÿÿÿÿÿÿÿÿÿÿø"(™™b"/÷øø÷÷ø÷ÿ÷÷øò("™‰‚¢ÿÿÿÿÿÿ÷ÿÿ÷ÿøÿÿÿÿÿÿÿÿÿÿ( @€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿ÷üÈŒŒÈŒx˜‰…ȘȂ|ÌÌÌÌÌÉ™™œÌ™œÌ&§øÌÌÌÌÌÉ™™¼Ì™ˆÌ2r(ŒÌÌÌÌŒ‚‰˜ŠŒÈ‰Ÿö"ÌÌÌÌÌÌ"i™",Ì™Ÿó#ÌÌŒÌÌÈ:‰™b<Ì™|ÌÌoÿ|ÌÌʨŒ†¨™ŸüÌÌÇÿüÌÌÃ(ÌÊ&™?øÌÌÏüÌ̆"ÌÃ(™Ÿ|ÌÌÏ÷ó(‰¼ÈŠŒÈ2o|ÌÌ÷ÿr*™œÌ"¬Ì¢øÌÌÇ÷x"™œÌbŒÌbo|Ìÿÿr"jŒÈ™‰›™ŸüÌÿÿwò""¬Ì™™™™ŸüÈ÷÷ÿò‚"ŒÈ‰™™™÷÷"&*2ŒÌ™Ÿ÷ÿÿ÷÷÷2""",È™w÷ÿ÷ÿÿ÷ÿ‚:(2¬È™Ÿ÷÷÷ŒÌÌ"‰˜‚o÷÷ÿwÿ÷ÌÌÈ"©˜"oÿÿwÿ÷ÿÌÌÌb‰™2?÷÷÷÷w*ŒÈÌÈ̉÷ÿ÷ÿ"<ÌÌÌÈ™Ÿÿw÷b<ÌÌÌÌ™?÷÷ÿÿÿÿ÷ÌÉ—‚?wÿ÷÷÷÷ÿ÷ÌÉ™"g÷÷÷ÿ÷÷ÿŒé™2÷ÿÿÿ÷w÷‚9˜"/÷÷÷wÿÿÿ÷")™b/÷w÷÷÷÷"i‰2÷÷ÿw÷÷÷ÿÿw( €€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿ÷ÿöÌ̉•ÉÆ/tÌÌÈ9SÈWølÈ̈2ÈŸöÌ÷|Æ,#—|Èv•hÆ?üÇÿb…Ã…7ü÷s&É™Ÿ÷÷6"ÅŸ÷ÿÿfc…?÷÷÷ÌF˜/÷÷÷6ÌÅŸ÷÷÷ÿ|7ÿ÷÷ö“o÷r˜'÷÷÷÷÷wÿpuzzles-20170606.272beef/icons/rect.ico0000644000175000017500000006117613115373742016451 0ustar simonsimon 00 ¨%–  ¨>& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $ææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææèèèèèèèèèèèèèèèèèèèèèèèèèèèççççççèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèççççççèèèèèèèèèèèèèèèèèèèèèèèèçççæææææææææææææææææææææææææææÞÞÞÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÜÜÜäääãããàààáááááááááááááááááááááááááááááááááááááááááááááàààâââåååáááàààáááááááááááááááàààâââææææææææææææææææææåååìììÇÇǬ¬¬½½½¹¹¹ººººººººººººººº¼¼¼444$$$333000111111111111111111...000111111111111111000222---///111111111111111000333$$$666æææçççæææææææææåååíííÂÂÂÔÔÔñññëëëëëëëëëëëëëëëëëëððð```¯¯¯   ¡¡¡   ¡¡¡¢¢¢¢¢¢¤¤¤‹‹‹   £££¢¢¢¢¢¢¢¢¢¢¢¢¡¡¡ªªª‚‚‚”””¦¦¦¡¡¡   ¡¡¡¢¢¢   ®®®eeeèèèçççæææææææææåååíííÃÃÃÏÏÏêêêäääåååååååååäääåååêêêiii¼¼¼¬¬¬¶¶¶¸¸¸···¯¯¯®®®°°°———­­­¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯­­­···ŒŒŒ   ³³³¯¯¯¸¸¸¶¶¶®®®¬¬¬¼¼¼nnnèèèçççæææææææææåååíííÃÃÃÐÐÐëëëåååæææææææææææææææëëëfff¹¹¹ªªªŒŒŒ………¬¬¬«««­­­•••ªªª¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬ªªª´´´‰‰‰œœœ±±±¦¦¦~~~ˆˆˆ®®®©©©¸¸¸kkkèèèçççæææææææææåååíííÃÃÃÐÐÐëëëåååæææææææææææææææëëëfff¸¸¸²²²666mmm«««¬¬¬­­­•••ªªª¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬ªªª´´´ŠŠŠœœœ´´´•••\\\,,,```µµµ···lllèèèçççæææææææææåååíííÃÃÃÐÐÐëëëåååæææææææææææææææëëëfff¹¹¹ªªª¶¶¶SSSuuu´´´ªªª®®®•••ªªª¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬ªªª´´´ŠŠŠ®®®²²²˜˜˜***nnn´´´···lllèèèçççæææææææææåååíííÃÃÃÐÐÐëëëåååæææææææææææææææëëëfffººº©©©SSS+++´´´ªªª­­­•••ªªª¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬ªªª´´´ŠŠŠ±±±§§§kkkjjjµµµ···lllèèèçççæææææææææåååíííÃÃÃÏÏÏëëëååååååååååååååååååêêêddd¶¶¶ªªªoooOOO­­­¨¨¨ªªª’’’§§§©©©©©©©©©©©©©©©§§§±±±‡‡‡œœœ±±±¥¥¥gggaaa›››¬¬¬¸¸¸kkkèèèçççæææææææææåååíííÃÃÃÔÔÔðððêêêëëëëëëëëëêêêêêêðððqqqËË˹¹¹ÆÆÆËËËÁÁÁ»»»¼¼¼½½½¡¡¡¹¹¹¼¼¼»»»»»»»»»»»»ºººÄÄÄ–––ŸŸŸ²²²®®®ººº»»»±±±«««¼¼¼mmmèèèçççæææææææææåååíííÃÃÿ¿¿ØØØÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÖÖÖ,,,XXXPPPOOONNNPPPQQQPPPSSSPPPUUUTTTTTTTTTTTTTTTSSSXXXBBB”””§§§¢¢¢      ¢¢¢   ¯¯¯eeeèèèçççæææææææææåååíííÃÃﯯÄÄÄÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÃÃÃBBB%%%))))))(((((((((((()))&&&‹‹‹˜˜˜™™™™™™™™™———¥¥¥___èèèçççæææææææææåååíííÃÃÃÖÖÖòòòìììííííííííííííëëëóóóÃÃÃæææ÷÷÷óóóôôôôôôôôôòòòøøøãã㎎ŽÀÀÀµµµ·········µµµ¿¿¿“““   ´´´®®®¯¯¯¯¯¯¯¯¯­­­½½½nnnèèèçççæææææææææåååíííÃÃÃÏÏÏêêêäääååååååååååååãããëë뺺º×××çççãããäääääääääãããèèèÔÔÔƒƒƒ³³³©©©ªªªªªªªªª©©©²²²ˆˆˆœœœ¯¯¯ªªª«««««««««©©©¸¸¸kkkèèèçççæææææææææåååíííÃÃÃÐÐÐëëëåååææææææææææææåååììì¼¼¼ÚÚÚéééææææææææææææåååëëëÖÖÖ………µµµªªª¬¬¬¬¬¬¬¬¬ªªª´´´ŠŠŠ°°°«««¬¬¬¬¬¬¬¬¬©©©¹¹¹lllèèèçççæææææææææåååíííÃÃÃÐÐÐëëëåååææææææææææææåååììì¼¼¼ÚÚÚéééææææææææææææåååëëëÖÖÖ………µµµªªª¬¬¬¬¬¬¬¬¬ªªª´´´ŠŠŠ°°°«««¬¬¬¬¬¬¬¬¬©©©¹¹¹lllèèèçççæææææææææåååíííÃÃÃÐÐÐëëëåååææææææææææææåååììì¼¼¼ÚÚÚéééææææææææææææåååëëëÖÖÖ………µµµªªª¬¬¬¬¬¬¬¬¬ªªª´´´ŠŠŠ°°°«««¬¬¬¬¬¬¬¬¬©©©¹¹¹lllèèèçççæææææææææåååíííÃÃÃÐÐÐëëëåååææææææææææææåååììì¼¼¼ÚÚÚéééææææææææææææåååëëëÖÖÖ………µµµªªª¬¬¬¬¬¬¬¬¬ªªª´´´ŠŠŠ°°°«««¬¬¬¬¬¬¬¬¬©©©¹¹¹lllèèèçççæææææææææåååíííÃÃÃÏÏÏêêêäääååååååååååååãããëëë»»»ÙÙÙèèèååååååååååååäääéééÕÕÕ„„„´´´ªªª«««««««««ªªª³³³‰‰‰°°°ªªª«««««««««©©©¸¸¸kkkèèèçççæææææææææåååíííÃÃÃÕÕÕòòòìììììììììììììììëëëóóóÀÀÀßßßðððììììììììììììëëëñññÜÜ܇‡‡¸¸¸­­­¯¯¯¯¯¯¯¯¯®®®···ŒŒŒ   ³³³®®®¯¯¯¯¯¯¯¯¯­­­¼¼¼nnnèèèçççæææææææææåååíííÃÃ÷··ÎÎÎÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÈÈÈÎÎΩ©©ÀÀÀÌÌÌÉÉÉÉÉÉÉÉÉÉÉÉÈÈÈÍÍÍ»»»zzz¦¦¦œœœžžžžžžžžžœœœ¥¥¥~~~¢¢¢žžžžžžžžž›››ªªªbbbèèèçççæææææææææåååíííÃÃ÷··ÎÎÎÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÈÈÈÎÎΩ©©ÀÀÀÌÌÌÉÉÉÉÉÉÉÉÉÉÉÉÈÈÈÍÍÍ»»»zzz¦¦¦œœœžžžžžžžžžœœœ¥¥¥~~~¢¢¢žžžžžžžžž›››ªªªbbbèèèçççæææææææææåååíííÃÃÃÕÕÕòòòìììììììììììììììëëëóóóÀÀÀßßßðððìììêêêèèèëëëëëëñññÜÜ܇‡‡¸¸¸­­­¬¬¬¬¬¬­­­®®®···ŒŒŒ   ³³³®®®¯¯¯¯¯¯¯¯¯­­­¼¼¼nnnèèèçççæææææææææåååíííÃÃÃÏÏÏêêêäääååååååååååååãããëëë»»»ÙÙÙèèèåååóóó÷÷÷íííãããêêêÕÕÕ„„„´´´ªªª¹¹¹¹¹¹´´´©©©´´´‰‰‰°°°ªªª«««««««««©©©¸¸¸kkkèèèçççæææææææææåååíííÃÃÃÐÐÐëëëåååææææææææææææåååììì¼¼¼ÙÙÙéééæææooo¹¹¹êêêéééÖÖÖ„„„¶¶¶§§§WWWQQQqqq®®®³³³ŠŠŠ°°°«««¬¬¬¬¬¬¬¬¬©©©¹¹¹lllèèèçççæææææææææåååíííÃÃÃÐÐÐëëëåååææææææææææææåååììì¼¼¼ÙÙÙêêêããã­­­iii888êêêêêêÖÖÖ„„„´´´¯¯¯;;;!!!’’’¬¬¬³³³ŠŠŠ°°°«««¬¬¬¬¬¬¬¬¬©©©¹¹¹lllèèèçççæææææææææåååíííÃÃÃÐÐÐëëëåååææææææææææææåååììì¼¼¼ÚÚÚèèèëëëáááMMMaaañññèèèÖÖÖ………µµµªªªÂÂÂSSSaaa¶¶¶²²²ŠŠŠ°°°«««¬¬¬¬¬¬¬¬¬©©©¹¹¹lllèèèçççæææææææææåååíííÃÃÃÐÐÐëëëåååææææææææææææåååììì¼¼¼ÚÚÚèèèêêê•••;;;UUUñññèèèÖÖÖ„„„¶¶¶¥¥¥XXX+++PPP¶¶¶²²²ŠŠŠ°°°«««¬¬¬¬¬¬¬¬¬©©©¹¹¹lllèèèçççæææææææææåååíííÃÃÃÏÏÏêêêäääååååååååååååãããëëë»»»ØØØççççççÃÃî®®ÜÜÜåååéééÕÕÕƒƒƒ³³³©©©‹‹‹………«««©©©²²²ˆˆˆœœœ¯¯¯©©©ªªªªªªªªª¨¨¨···kkkèèèçççæææææææææåååíííÃÃÃÖÖÖòòòìììííííííííííííëëëôôôÀÀÀàààðððìììõõõùùùïïïëëëòòòÝÝÝÁÁÁµµµ¾¾¾¿¿¿···µµµ¿¿¿“““§§§»»»¶¶¶·········´´´ÅÅÅsssèèèçççæææææææææåååíííÃÃﯯÄÄÄÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ¿¿¿ÄÄĤ¤¤¸¸¸ÂÂÂÀÀÀ¿¿¿¾¾¾ÀÀÀ¿¿¿ÄÄIJ²² æææçççæææææææææåååíííÃÃÿ¿¿ØØØÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÒÒÒØØØ°°°ÉÉÉÖÖÖÓÓÓÓÓÓÓÓÓÓÓÓÒÒÒ×××ÄÄÄ???YYYSSSTTTTTTTTTTTTTTTUUUPPPUUUTTTTTTTTTTTTTTTSSS[[[111ççççççæææææææææåååíííÃÃÃÔÔÔðððêêêëëëëëëëëëëëëéééñññ¿¿¿ÞÞÞîîîêêêëëëëëëëëëéééïïïÚÚÚ‘‘‘ÅÅŹ¹¹»»»»»»»»»»»»¼¼¼¹¹¹   ¼¼¼»»»»»»¹¹¹¹¹¹ººº¹¹¹ÉÉÉvvvèèèçççæææææææææåååíííÃÃÃÏÏÏëëëåååååååååååååååäääììì»»»ÙÙÙèèèååååååååååååäääêêêÕÕÕ‚‚‚²²²§§§©©©©©©©©©©©©©©©¨¨¨’’’ªªª¨¨¨«««¶¶¶²²²­­­¦¦¦¶¶¶jjjèèèçççæææææææææåååíííÃÃÃÐÐÐëëëåååææææææææææææåååììì¼¼¼ÚÚÚéééææææææææææææåååëëëÖÖÖ………µµµªªª¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«««•••¬¬¬¯¯¯666AAAwww°°°¸¸¸lllèèèçççæææææææææåååíííÃÃÃÐÐÐëëëåååææææææææææææåååììì¼¼¼ÚÚÚéééææææææææææææåååëëëÖÖÖ………µµµªªª¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«««•••­­­¬¬¬®®®===777¥¥¥ªªª¸¸¸lllèèèçççæææææææææåååíííÃÃÃÐÐÐëëëåååææææææææææææåååììì¼¼¼ÚÚÚéééææææææææææææåååëëëÖÖÖ………µµµªªª¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«««•••­­­¬¬¬ªªª¼¼¼===hhh¶¶¶···lllèèèçççæææææææææåååíííÃÃÃÏÏÏëëëåååååååååååååååäääììì»»»ÙÙÙéééååååååååååååäääêêêÖÖÖ„„„µµµªªª¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬ªªª”””¬¬¬¯¯¯œœœDDD(((uuu²²²···kkkèèèçççæææææææææåååíííÃÃÃÑÑÑíííæææççççççççççççæææîîî½½½ÛÛÛêêêççççççççççççæææììì×××………¶¶¶«««­­­­­­­­­­­­­­­¬¬¬–––®®®­­­­­­›››   ²²²ªªªºººlllèèèçççæææææææææåååíííÄÄÄÐÐÐëëëåååææææææææææææäääììì¼¼¼ÚÚÚéééåååæææææææææåååêêêÖÖÖ†††¶¶¶«««­­­­­­­­­­­­­­­«««–––®®®¬¬¬­­­±±±°°°¬¬¬ªªª¹¹¹mmmèèèçççæææææææææãããõõõ     åååçççæææææææææåååëëëÏÏÏ•••ššš™™™™™™™™™™™™™™™™™™™™™ššš™™™™™™™™™™™™™™™™™™™™™™™™šššŸŸŸœœœššš››››››››››››››››››››››››››››››››››››››››››››››››ššš©©©ææææææææææææææææææåååëëë÷÷÷ööööööööööööööööööööööööööööööööööööööööööööööööööööööõõõõõõööööööööööööööööööööööööõõõöööööööööööööööööööööööööööóóóæææææææææææææææææææææåååããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææ( @ ææææææéééêêêêêêêêêêêêêêêêêêìììííííííííííííííííííííííííííííííííííííëëëííííííííííííííííííêêêææææææææææææÛÛÛØØØÙÙÙÙÙÙÙÙÙØØØÙÙÙÐÐÐÊÊÊËËËËËËËËËËËËÌÌÌÌÌÌËËËËËËËËËËËËËËËÔÔÔÎÎÎËËËËËËËËËËËËËËËÖÖÖææææææéééÛÛÛ»»»ÏÏÏËËËÌÌÌÉÉÉÛÛÛuuu***```UUUUUUWWWYYYRRRUUUXXXWWWXXXWWW\\\"""GGG[[[UUUVVVYYYUUU'''ÖÖÖëëëêêêØØØÏÏÏðððêêêëëëçççÿÿÿyyyVVVÅÅźººÁÁÁ¶¶¶···§§§®®®···µµµµµµ³³³¿¿¿222ŒŒŒ¿¿¿¼¼¼½½½¶¶¶³³³,,,ÑÑÑìììêêêÙÙÙËËËêêêäääåååáááùùùwwwOOOÁÁÁvvv___¯¯¯£££¬¬¬ªªªªªª¨¨¨³³³000………±±±sss{{{¬¬¬¨¨¨***ÑÑÑìììêêêÙÙÙÌÌÌëëëåååæææâââúúúwwwPPPÃÃÃ<<<ŸŸŸ±±±žžž¥¥¥®®®¬¬¬¬¬¬ªªª¶¶¶000………···zzz222§§§¬¬¬***ÑÑÑìììêêêÙÙÙËËËêêêäääåååáááùùùwwwOOO¼¼¼888ˆˆˆ³³³›››¢¢¢«««©©©©©©§§§²²²///„„„ºººhhh666®®®ªªª***ÑÑÑìììêêêØØØÏÏÏðððéééêêêçççÿÿÿzzz[[[ÑÑѤ¤¤   ½½½¿¿¿¬¬¬³³³¾¾¾»»»»»»ºººÆÆÆ444†††¸¸¸”””œœœ±±±¬¬¬***ÑÑÑìììéééÚÚÚ¾¾¾ÖÖÖÑÑÑÒÒÒÎÎÎãããrrrZZZUUUXXXQQQQQQUUUWWWVVVVVVVVVUUUZZZ‚‚‚©©©¦¦¦¦¦¦£££   (((ÒÒÒìììéééÚÚÚ¾¾¾ÖÖÖÑÑÑÒÒÒÐÐÐÚÚÚ¦¦¦kkkzzzvvvvvvuuu...444]]]UUUVVVUUUZZZ‚‚‚©©©   ¡¡¡£££   (((ÒÒÒìììêêêØØØÏÏÏðððéééêêêêêêîîîÚÚÚäääÿÿÿùùùúúúöööÿÿÿbbbtttËË˹¹¹»»»ºººÆÆÆ444†††···­­­®®®¯¯¯¬¬¬***ÑÑÑìììêêêÙÙÙËËËêêêäääåååäääêêêÐÐÐÎÎÎçççáááâââÞÞÞõõõWWWhhh···§§§©©©§§§²²²///………´´´ªªª«««¬¬¬©©©***ÑÑÑìììêêêÙÙÙÌÌÌëëëåååæææåååêêêÒÒÒÒÒÒêêêåååæææâââùùùYYYjjjºººªªª¬¬¬ªªª¶¶¶000†††µµµ«««¬¬¬­­­ªªª***ÑÑÑìììêêêÙÙÙËËËêêêäääåååäääéééÑÑÑÑÑÑéééäääåååáááøøøYYYiii¹¹¹©©©«««ªªªµµµ000………´´´ªªª«««¬¬¬©©©***ÑÑÑìììêêêØØØÐÐÐðððêêêëëëêêêïïïÖÖÖÖÖÖïïïêêêëëëçççþþþ[[[kkk½½½¬¬¬®®®­­­¸¸¸111‡‡‡···­­­®®®¯¯¯¬¬¬+++ÑÑÑìììéééÚÚÚºººÏÏÏËËËÌÌÌÌÌÌÐÐн½½½½½ÐÐÐÌÌÌÌÌÌÉÉÉÝÝÝOOObbb¬¬¬ŸŸŸžžž¨¨¨,,,|||§§§žžžŸŸŸ   (((ÒÒÒìììéééÙÙÙÂÂÂÜÜÜØØØØØØØØØÜÜÜÇÇÇÇÇÇÜÜÜ××××××ÔÔÔëëëSSSfff³³³¢¢¢¤¤¤¤¤¤®®®...€€€®®®¤¤¤¥¥¥¦¦¦£££)))ÑÑÑìììêêêØØØÎÎÎîîîèèèéééèèèîîîÕÕÕÕÕÕîîîéééðððêêêüüüZZZkkk»»»±±±±±±«««···000‡‡‡···¬¬¬­­­¯¯¯«««***ÑÑÑìììêêêÙÙÙÌÌÌêêêåååæææåååêêêÒÒÒÐÐÐðð𨨨mmmÈÈÈþþþXXXhhhÁÁÁTTTNNN¥¥¥···///………µµµªªª«««­­­ªªª***ÑÑÑìììêêêÙÙÙÌÌÌëëëåååæææåååêêêÒÒÒÑÑÑíííÔÔÔAAA°°°ÿÿÿWWWiii¾¾¾‹‹‹EEE£££¸¸¸///†††µµµ«««¬¬¬­­­ªªª***ÑÑÑìììêêêÙÙÙËËËêêêäääåååäääéééÑÑÑÏÏÏñññ¯¯¯OOOÉÉÉþþþWWWhhh»»»tttCCC···///„„„³³³©©©ªªª«««¨¨¨***ÑÑÑìììêêêØØØÏÏÏïïïéééêêêéééïïïÕÕÕÕÕÕïïïäääééééééýýýZZZpppÅÅÅ­­­¶¶¶···¿¿¿333¿¿¿´´´µµµ¶¶¶³³³,,,ÑÑÑìììéééÚÚÚ¶¶¶ËËËÇÇÇÈÈÈÇÇÇËË˹¹¹¹¹¹ËËËÉÉÉÈÈÈÄÄÄ×××SSS666111000///333 %%%222///000111---ÖÖÖëëëéééÙÙÙÇÇÇãããÞÞÞßßßÞÞÞãããÌÌÌÌÌÌãããÞÞÞÞÞÞÛÛÛñññXXXOOO‘‘‘„„„………………‡‡‡€€€………††††††‡‡‡‡‡‡ƒƒƒ$$$ÓÓÓëëëêêêÙÙÙÍÍÍíííçççèèèçççìììÔÔÔÔÔÔìììçççèèèäääûûûYYYpppÃÃò²²µµµ´´´···¤¤¤±±±µµµ³³³¯¯¯´´´³³³,,,ÑÑÑìììêêêÙÙÙÌÌÌëëëåååæææåååêêêÒÒÒÒÒÒêêêåååæææâââùùùYYYhhh¸¸¸¨¨¨«««ªªª­­­›››¦¦¦¯¯¯???UUU­­­¨¨¨***ÑÑÑìììêêêÙÙÙÌÌÌêêêåååæææåååêêêÒÒÒÒÒÒêêêåååæææâââùùùYYYiiiººº©©©¬¬¬«««®®®§§§±±±†††GGG­­­ªªª***ÑÑÑìììêêêÙÙÙÍÍÍìììæææçççæææëëëÓÓÓÓÓÓëëëæææçççãããúúúZZZjjj»»»«««­­­¬¬¬¯¯¯žžž©©©®®®kkkZZZ­­­«««+++ÑÑÑìììêêêØØØÊÊÊéééãããääääääéééÐÐÐÐÐÐéééääääääááá÷÷÷XXXhhh¸¸¸¨¨¨ªªª©©©¬¬¬›››¦¦¦««««««±±±¬¬¬§§§***ÑÑÑìììêêêÙÙÙ:::222444444444444000000444444444333777,,,************(((*********)))+++'''×××êêêæææåååÑÑÑÎÎÎÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÏÏÏÏÏÏÏÏÏÏÏÏÎÎÎÔÔÔÔÔÔÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ×××åååæææææææææìììììììììììììììììììììììììììììììììììììììëëëëëëììììììììììììììììììììììììììììììììììììêêêææææææ(  åååÞÞÞÝÝÝÞÞÞÕÕÕËËËÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÐÐÐÌÌÌÊÊÊÒÒÒæææÞÞÞÒÒÒÜÜÜÞÞÞppp†††‡‡‡ˆˆˆŽŽŽƒƒƒZZZ“““gggÎÎÎÝÝÝÜÜÜëëëèèè}}}’’’³³³¬¬¬¶¶¶¥¥¥ppp“““‰‰‰~~~ÆÆÆÝÝÝÚÚÚèèèçççwww~~~©©©¦¦¦­­­žžžkkk“““‹‹‹zzzÇÇÇÝÝÝÍÍÍÖÖÖÚÚÚwwwooo___WWWiiiXXXVVV­­­¯¯¯nnnÉÉÉÝÝÝÚÚÚèèèåååÚÚÚåååôôô£££‚‚‚···žžžfff¯¯¯²²²tttÈÈÈÝÝÝÝÝÝëëëèèè×××åååõõõ¤¤¤………¹¹¹¡¡¡ggg±±±´´´tttÈÈÈÝÝÝÑÑÑÜÜÜÚÚÚËËËÙÙÙçççššš³³³šššcccªªª­­­qqqÉÉÉÝÝÝÔÔÔàààÝÝÝÏÏÏÙÙÙììì°°°›››ddd«««®®®qqqÉÉÉÝÝÝÝÝÝëëëçççßßßÃÃߟŸ­­­………uuu–––mmm³³³···vvvÈÈÈÝÝÝÙÙÙæææâââ×××ÍÍͦ¦¦zzz‰‰‰bbb£££¦¦¦mmmÉÉÉÝÝÝÎÎÎØØØÖÖÖÇÇÇÖÖÖêêê———JJJssseeeVVVkkkmmmLLLÎÎÎÝÝÝÚÚÚçççäääÕÕÕâââðð𢢢‡‡‡¸¸¸­­­¯¯¯“““œœœ{{{ÇÇÇÝÝÝåååõõõòòòàààïïïÿÿÿ«««ˆˆˆ½½½¯¯¯±±±ŒŒŒŠŠŠ€€€ÆÆÆÛÛÛ•••””””””‹‹‹“““œœœnnn]]]yyyrrrooorrrvvv[[[ÏÏÏäääÈÈÈÃÃÃÄÄÄÅÅÅÄÄÄÃÃÃÉÉÉËËËÈÈÈÈÈÈÉÉÉÉÉÉÇÇÇÏÏÏæææ(0` æææèèèçççÞÞÞÜÜÜÝÝÝäääãããàààáááâââåååìììÇÇǬ¬¬½½½¹¹¹ººº¼¼¼444$$$333000111...222---///666íííÂÂÂÔÔÔñññëëëððð```¯¯¯   ¡¡¡¢¢¢¤¤¤‹‹‹£££ªªª‚‚‚”””¦¦¦®®®eeeÃÃÃÏÏÏêêêiii¶¶¶¸¸¸···°°°———­­­ŒŒŒ³³³nnnÐÐÐfff………«««•••´´´‰‰‰œœœ±±±~~~ˆˆˆ©©©kkk²²²mmmŠŠŠ\\\,,,µµµlllSSSuuu˜˜˜***+++§§§jjjdddoooOOO¨¨¨’’’‡‡‡¥¥¥gggaaa›››qqqËËËÆÆÆÁÁÁ»»»ÄÄÄ–––ŸŸŸ¿¿¿ØØØÒÒÒÓÓÓÖÖÖXXXPPPNNNQQQUUUTTTBBBÀÀÀ%%%)))(((&&&™™™___òòòóóó÷÷÷ôôôøøøŽŽŽ“““××׃ƒƒÚÚÚéééÙÙÙÕÕÕ„„„ßßßÎÎÎÉÉÉÈÈÈÌÌÌÍÍÍzzzžžžbbbWWW888;;;!!!MMMõõõùùùïïï¾¾¾ÅÅÅsss ???YYY[[[îîî‘‘‘vvvAAAwww===777hhhDDDÑÑÑÛÛÛ††† šššööö      !""""""#$%&'('())*+',))))(-./01('()'234 567  7$89:;&2<=>&&&&&>;?@'A&:92B4 5C" "DE-?FGH>I--JK/LM1NO2P:QR 5C" "DE:STUH>I--JV/LJIWX%Y;ZR 5C" "DE-9[\J-2I--JV/]2S^_BJ;ZR 5C" "DEP`[aJ->I--JV/]MbQcdY;ZR 56" 7De9-fgh>i-jbPPPPPbMk/LMlmno:QR 5 #7"""77#$pqrqst(ttttuv/wS2tMHUR 5xyz{{{{{|}X~g€[‚ƒƒƒƒƒ[~„@0b)'')'&34 5&u………………5„†‡‡ˆˆˆˆ‡‰Š‹ŒŒŽ+]^=l‘4 5|’ "“5”“•••’–—˜…Y;;;Yx™/'J2&&&>BR 567 "š ›œAP---PSO/L&-HHHP:QR 5C" ž "|›GY--JV/]&&&2;?/'A2&&&>BR 5;£¤¤¤¤¤¥£P…¦¤¤¤¤¥§t›¨1L©©©LlN/ª)]©©©o-«4 5;£¤¤¤¤¤¥£P…¦¤¤¤¤¥§t›¨1L©©©LlN/ª)]©©©o-«4 5 ’ "“…¢# 7""!k:>>2;?/'A2&&&>BR 567 "tŸ “”7 ›¡J-JPJK/]<-HHHP:QR 5C" Ÿž¬f7ž|›¡9b­p2AV/]8®77|›¡J&¯°jAV/]19dR 5C" ž "|›GY-HI&]ÃÄ<:ZR 5C" ž "|›GY-HI>2ÅÆl-:ZR 5C" ž "|›GY-HI>-ÅÇ9;ZR 56"  tŸž 7|›¡Y--0&LȈ\S;QR 5ÉÀÊ7 š›G9H>>>>>v2>>o'S-ZR uC"  ž 7|¹Ë9H>>>>>Hv2>M<-U‹²'/̼¼¼¼¼¼¼¹Í¼¼¼¼¼¼¼Í/›Î›—/º  "6IÏÏÏwLÏooooooooooooooooÏP "”ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐв²ÐÐÐÐÐÐÐвÐÐÐÐÐÐÐÐГ ( @æææéééêêêìììíííëëëÛÛÛØØØÙÙÙÐÐÐÊÊÊËËËÌÌÌÔÔÔÎÎÎÖÖÖ»»»ÏÏÏÉÉÉuuu***```UUUWWWYYYRRRXXX\\\"""GGG[[[VVV'''ðððçççÿÿÿyyyÅÅźººÁÁÁ¶¶¶···§§§®®®µµµ³³³¿¿¿222ŒŒŒ¼¼¼½½½,,,ÑÑÑäääåååáááùùùwwwOOOvvv___¯¯¯£££¬¬¬ªªª¨¨¨000………±±±sss{{{âââúúúPPPÃÃÃ<<<ŸŸŸžžž¥¥¥zzz888ˆˆˆ›››¢¢¢«««©©©²²²///„„„hhh666¤¤¤   ¾¾¾ÆÆÆ444†††¸¸¸”””œœœÚÚÚÒÒÒãããrrrZZZQQQ‚‚‚¦¦¦(((kkk...]]]¡¡¡îîîöööbbbttt¹¹¹­­­ÞÞÞõõõ´´´jjjøøøiiiïïïþþþ111‡‡‡+++ÝÝÝ|||ÂÂÂÜÜÜÇÇÇ×××SSSfff€€€)))èèèÕÕÕüüümmmÈÈÈTTTNNNAAA°°°‹‹‹EEEñññCCCýýýppp333ÄÄÄ %%%---ßßß‘‘‘ƒƒƒ$$$ÓÓÓÍÍÍûûû???÷÷÷:::777    !"#$%&'()*+),,-./0.12(-34 56789:';<=>=?@AAB-CDEFG@B4 6HI9JKLMNEOP+@@A(CD)Q/*@4 56789:1RST-UVWXX*YZ[&\]+A4!"#Q4^_2.@-`&abcdefE@4g`4hijklmmlnoXpp?_qhg`4h gprQ;;LsbtlnoX_u?_qh!vg5#8Iw#xy z&abc){+>@4 565 "7H|}\)*X*YZD~AW@X4 66hh6H8&A@A(Cc,W@{A4 56544567€zXWA,CD~AW@X4 !‚‚"ƒr2@+{d„…){+>@†4g& 22 ‡:x@=NOB3ˆ*ON_=qh‰ŠŠ‹‹ŠŒŒ Ž-V^^+s+^Pp?4v‘‘v’’v!“lrEEW)C…)@{>W4 66h !B”•ƒ\'–—P)ZD,AW{A4 66h4 ˜™#`š›?dZc,W@{A4 5654œ>:ƒ\y=)Z[-XAWB4‚‚’’‚5žlŸ%{(). R.~,(-34g( ‹•‹ zz •¡Œ¢]„CZ £¤/ZC„¥¦‹i|§|i i||œ:¨[DD…Dcc……©ª«¬"‘" "‘5­ŸKY,~)^E,->~-34 66hh6H8\dBWA{Up>®{B4 66hh6H8&X@W+=*Ec{A4¬"««"iIlW{@>OX+rl{W†4 i55 557¯\dBAX@UpWWE@*4°/bbbbCCbbb ±²k3q† kŒ64  44444h444444Œ6( åååÞÞÞÝÝÝÕÕÕËËËÌÌÌÍÍÍÐÐÐÊÊÊÒÒÒæææÜÜÜppp†††‡‡‡ˆˆˆŽŽŽƒƒƒZZZ“““gggÎÎÎëëëèèè}}}’’’³³³¬¬¬¶¶¶¥¥¥‰‰‰~~~ÆÆÆÚÚÚçççwww©©©¦¦¦­­­žžžkkk‹‹‹zzzÇÇÇÖÖÖooo___WWWiiiXXXVVV¯¯¯nnnÉÉÉôôô£££‚‚‚···fff²²²tttÈÈÈ×××õõõ¤¤¤………¹¹¹¡¡¡±±±´´´ÑÑÑÙÙÙšššcccªªªqqqÔÔÔàààÏÏÏììì°°°›››ddd«««®®®ßßßÃÃߟŸuuu–––mmmvvvâââÂÂÂbbbØØØêêê———JJJssseeeLLLäääðð𢢢¸¸¸œœœ{{{òòòïïïÿÿÿ½½½ŒŒŒŠŠŠ€€€ÛÛÛ•••”””]]]yyyrrr[[[ÄÄÄÅÅÅ      !"#$%!&'()*+,-.#%/01234(567##89:;)<5=>?@ABCDEFG>?H #I$JJKL(M7NOPIQRSTUVWM7$XYZ(C[\];^?I _@`', ab9']7c.-.defgh4*]i#$j_klm(5no-ApOqrVs5Ftuv"wxyy+n6z{|/|^}Pj?Y~~Y7??77-P (0`€€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿÿ÷ÿÿwwÿ÷wwwÿÿ÷ÿ÷÷÷€€€€ÿÿÿÿÿ÷÷÷÷w÷÷ÿ€ÿ÷÷ÿwwÿÿÿÿ÷÷÷÷÷÷ÿ€÷ÿøÿÿÿÿÿ÷÷ÿÿw÷÷ÿ€÷÷ÿ÷÷ÿÿÿÿ÷ÿ€wÿwpwø÷ÿÿÿÿ÷ð÷÷÷÷ÿÿwpøÿÿÿÿÿ÷÷÷w÷ÿ€÷ÿ÷÷ÿÿÿÿÿ÷ˆ÷÷÷ÿÿÿ÷xwwÿÿÿÿ÷ˆw÷÷wwwwˆ÷ø‡ÿøÿÿÿÿÿ÷ÿÿÿÿ÷ÿÿÿÿ€÷ÿÿwø÷ÿÿÿÿ÷‡ˆxx‡‡‡xwwÿw÷÷÷÷w÷w÷w÷wÿÿÿÿÿÿw÷wp‡www÷wøÿÿÿÿÿÿÿÿÿÿÿð÷ÿ€÷÷øwÿÿÿÿÿÿÿÿÿð÷ÿ€÷ÿ÷÷ÿÿÿÿÿÿÿÿÿÿÿð‡wÿ€÷÷ø÷ÿÿÿÿÿÿÿÿÿðÿ÷÷÷÷÷ø÷ÿÿÿÿÿÿÿÿÿÿðwÿ÷÷wÿÿÿÿÿÿÿÿÿÿð÷÷ÿ€÷÷÷ø÷ÿÿÿÿÿÿÿÿÿÿð÷÷÷÷ø÷ÿÿÿÿÿÿÿÿÿð‡÷÷÷ÿ€ÿøÿÿÿÿÿÿÿÿÿÿÿð÷ÿ÷ÿ÷ø÷÷÷÷w÷÷ðw÷€÷wwwwwÿÿÿÿÿÿ÷ÿðw÷øÿÿÿÿÿÿÿÿÿÿð÷÷ˆ÷÷÷÷w÷ÿÿÿÿÿÿÿÿÿÿðÿÿÿ÷ÿÿÿÿÿÿÿwÿð÷xwÿ€÷÷÷÷ø÷ÿÿÿÿÿÿˆÿð÷‡ÿøÿÿÿÿÿÿÿ÷ÿðˆwÿ€÷÷÷÷øwÿÿÿÿÿÿÿøÿð÷ø÷wÿÿÿÿÿÿÿˆÿðw€ÿ÷÷ø÷ÿÿÿÿÿÿÿÿÿÿðwwøÿÿÿÿÿÿÿÿÿÿðÿÿÿÿˆwÿÿÿø÷ÿÿ÷ÿ÷÷ÿð€€ˆ€€÷÷ÿp€€ÿÿÿÿÿÿÿÿÿÿÿðÿÿÿ÷ÿ÷÷÷÷ÿÿÿÿÿÿÿÿÿðw÷w÷ÿwÿø÷ÿÿÿÿÿÿÿÿÿð÷w÷÷÷xÿÿÿÿÿÿÿÿÿÿÿð‡÷÷ÿÿð÷÷ÿÿÿÿÿÿÿÿÿðw÷w÷wÿÿÿÿÿÿÿÿÿð÷÷÷ÿ÷ÿpÿø÷ÿÿÿÿÿÿÿÿÿÿð÷wx÷øÿÿÿÿÿÿÿÿÿÿð÷w÷wÿx‡÷øÿÿÿÿÿÿÿÿÿÿÿð‡ÿÿÿÿÿ÷øøxxx‡xˆxx‡x€ˆxx‡‡ˆˆwx‡xpÿ÷ÿÿ÷ÿÿÿ÷÷ÿ÷ÿ÷ÿÿ( @€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ÷÷w÷w‡wwwxw÷xw‡www÷wˆ€€ˆˆˆˆˆ‡÷ÿ÷÷wwwwwx€wxww÷÷x‡xxx‡€xˆxwÿ÷€‡ˆ‡w‡ˆx€w÷÷ww‡‡w€w€w÷ÿ÷xˆxwww€wˆ‡w÷÷‡‡‡xˆˆˆxww÷wwwxx‡w÷ÿwÿø‡wwˆwxw÷ÿÿø‡w‡€wwww÷ÿw÷ð‡w€x‡‡wø‡xwˆx‡wwÿ÷ÿ÷ð‡ww€wwx‡w÷ÿÿ÷ÿø‡‡€wxw÷wwwwwwð‡‡‡€wxˆ÷wwwwp‡ˆw€wxwwÿÿ÷ÿÿø‡ww€x‡wwÿÿwøøˆ‡€xww‡÷øø‡p‡€wxˆw÷ÿwwø‡p‡ˆ‡ˆxxw÷ÿ÷wø‡ˆw€www‡wÿww÷øˆˆˆ€ˆˆˆww÷wwwwp€€÷÷ÿÿwÿø‡wx‡wwww÷÷wð‡ˆwxxˆw÷ÿÿÿ÷ÿø‡wwxˆˆ‡ww÷ð‡xxw€xwÿwÿÿø‡wxwx€x‡÷÷÷÷ð‡w‡xwwwð€€€€€÷ww÷wwww÷wwwww÷( €€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿÿwwwwwˆˆ‡ˆx‡÷ˆ‡‡xˆ‡wÿˆ‡xˆˆ‡÷ˆˆˆˆw‡÷wwˆˆ‡‡ÿÿ÷ˆˆw‡w÷wx‡ˆˆ‡wø‡ˆ‡‡÷÷÷wˆˆw‡wÿwwˆˆw‡wwˆˆ÷÷øˆwˆ‡ÿ÷w‡xˆ‡x‡‡ˆˆˆˆ‡÷wwwwwpuzzles-20170606.272beef/icons/range.ico0000644000175000017500000006117613115373741016607 0ustar simonsimon 00 ¨%–  ¨>& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $%%%ooofffhhhhhhhhhhhhhhhhhhhhhhhhgggjjj===eeehhhhhhhhhhhhhhhhhhhhhhhhhhhfffppp222FFF,,,RRRöööâââææææææææææææææææææææææææåååêêꈈˆàààçççææææææææææææææææææææææææâââøøøppp@@@(((KKKàààÎÎÎÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÐÐÐÕÕÕ|||ÌÌÌÒÒÒÑÑÑÑÑÑÏÏÏÐÐÐÏÏÏÏÏÏÑÑÑÑÑÑÍÍÍâââfffAAA)))LLLäääÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙ~~~ÐÐÐÖÖÖÕÕÕÖÖÖâââßßßàààßßßÕÕÕÕÕÕÑÑÑæææhhhAAA)))LLLäääÒÒÒÕÕÕÕÕÕÕÕÕÓÓÓÓÓÓÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙ~~~ÐÐÐÖÖÖÖÖÖÓÓÓ```***+++ˆˆˆÛÛÛÔÔÔÑÑÑæææhhhAAA)))LLLäääÒÒÒÕÕÕÕÕÕÖÖÖâââÝÝÝÔÔÔÕÕÕÕÕÕÔÔÔÙÙÙ~~~ÐÐÐÖÖÖØØØÈÈÈeee‘‘‘UUU¨¨¨ÞÞÞÏÏÏæææhhhAAA)))LLLäääÒÒÒÔÔÔØØØËËË+++mmmâââÒÒÒÕÕÕÔÔÔÙÙÙ~~~ÐÐÐÖÖÖÕÕÕÕÕÕÙÙÙóóó°°°ãããÎÎÎæææhhhAAA)))LLLäääÒÒÒÔÔÔÙÙÙÉÉÉ YYYäääÒÒÒÕÕÕÔÔÔÙÙÙ~~~ÐÐÐÖÖÖÓÓÓßßßLLL++++++ÇÇÇØØØÐÐÐæææhhhAAA)))LLLäääÒÒÒÕÕÕÕÕÕÕÕÕ×××ÖÖÖÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙ~~~ÐÐÐÖÖÖÒÒÒããã555"""nnnžžžÙÙÙÔÔÔÑÑÑæææhhhAAA)))LLLäääÒÒÒÕÕÕÕÕÕÕÕÕÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙ~~~ÐÐÐÖÖÖÒÒÒàààKKK ,,,ÎÎÎ×××ÑÑÑæææhhhAAA)))LLLäääÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙ~~~ÐÐÐÖÖÖÕÕÕÕÕÕÑÑÑÍÍÍËËËÎÎÎÕÕÕÕÕÕÑÑÑæææhhhAAA+++MMMåååÓÓÓÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÕÕÕÛÛÛÑÑÑØØØÖÖÖÖÖÖØØØÙÙÙÙÙÙØØØÖÖÖÖÖÖÒÒÒçççhhh???(((JJJßßßÍÍÍÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÏÏÏÔÔÔ{{{ËËËÑÑÑÐÐÐÐÐÐÐÐÐÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÌÌÌàààeee ===LLLKKKLLLLLLLLLLLLLLLLLLLLLLLLMMMGGG???ƒƒƒ}}}~~~~~~~~~~~~~~~~~~~~~~~~}}}€€€KKK{{{~~~~~~~~~~~~~~~~~~~~~~~~|||ˆˆˆ===000™™™ìììâââääääääääääääääääääääääääåååàààƒƒƒÝÝÝØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙØØØÞÞÞ€€€ÔÔÔÛÛÛÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÕÕÕêêêjjj000ØØØÏÏÏÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÌÌÌ}}}ØØØÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÓÓÓØØØ}}}ÏÏÏÕÕÕÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÐÐÐåååggg000‘‘‘ÜÜÜÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÐÐÐ~~~ÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙ~~~ÐÐÐÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÑÑÑæææhhh000‘‘‘ÜÜÜÓÓÓÕÕÕÕÕÕÔÔÔÑÑÑÓÓÓÕÕÕÕÕÕÕÕÕÖÖÖÐÐÐ~~~ÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙ~~~ÐÐÐÖÖÖÕÕÕÕÕÕÕÕÕÒÒÒÒÒÒÕÕÕÕÕÕÕÕÕÑÑÑæææhhh000‘‘‘ÜÜÜÓÓÓÕÕÕÔÔÔØØØçççÝÝÝÔÔÔÕÕÕÕÕÕÖÖÖÐÐÐ~~~ÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙ~~~ÐÐÐÖÖÖÕÕÕÕÕÕÕÕÕäääâââÔÔÔÕÕÕÕÕÕÑÑÑæææhhh000‘‘‘ÜÜÜÓÓÓÔÔÔÚÚÚÁÁÁBBB”””àààÓÓÓÕÕÕÖÖÖÐÐÐ~~~ÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙ~~~ÐÐÐÖÖÖÕÕÕÕÕÕÖÖÖYYYmmmÝÝÝÓÓÓÕÕÕÑÑÑæææhhh000‘‘‘ÜÜÜÓÓÓÓÓÓÝÝݵµµnnnæææÑÑÑÕÕÕÖÖÖÐÐÐ~~~ÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙ~~~ÐÐÐÖÖÖÕÕÕÖÖÖ×××000âââÓÓÓÕÕÕÑÑÑæææhhh000‘‘‘ÜÜÜÓÓÓÕÕÕÕÕÕÓÓÓÇÇÇÏÏÏÖÖÖÕÕÕÕÕÕÖÖÖÐÐÐ~~~ÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙ~~~ÐÐÐÖÖÖÕÕÕÕÕÕÕÕÕÉÉÉËËËÖÖÖÕÕÕÕÕÕÑÑÑæææhhh000‘‘‘ÜÜÜÓÓÓÕÕÕÕÕÕÖÖÖÚÚÚ×××ÕÕÕÕÕÕÕÕÕÖÖÖÐÐÐ~~~ÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙ~~~ÐÐÐÖÖÖÕÕÕÕÕÕÕÕÕÙÙÙØØØÕÕÕÕÕÕÕÕÕÑÑÑæææhhh000‘‘‘ÜÜÜÓÓÓÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÐÐÐ~~~ÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙ~~~ÐÐÐÖÖÖÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÑÑÑæææhhh000ÛÛÛÒÒÒÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÏÏÏ}}}ØØØÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÓÓÓØØØ}}}ÏÏÏÕÕÕÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÐÐÐåååggg111”””ààà×××ÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÛÛÛÔÔÔ€€€ÞÞÞØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙØØØÞÞÞ€€€ÔÔÔÛÛÛÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÕÕÕêêêjjjVVV‚‚‚}}}~~~~~~~~~~~~~~~~~~~~~~~~{{{KKK€€€}}}~~~~~~~~~~~~~~~~~~~~~~~~}}}€€€KKK{{{~~~~~~~~~~~~~~~~~~~~~~~~|||ˆˆˆ===///×××ÎÎÎÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑËËË{{{ÔÔÔÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÏÏÏÔÔÔ{{{ËËËÑÑÑÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÌÌÌàààeee000’’’ÝÝÝÔÔÔÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖØØØÑÑÑÛÛÛÕÕÕÖÖÖ×××ÕÕÕÒÒÒÖÖÖÖÖÖÖÖÖÖÖÖÕÕÕÛÛÛÑÑÑØØØÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÒÒÒçççhhh000‘‘‘ÜÜÜÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÐÐÐ~~~ÙÙÙÔÔÔÕÕÕÔÔÔÜÜÜçççÖÖÖÔÔÔÕÕÕÕÕÕÔÔÔÙÙÙ~~~ÐÐÐÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÑÑÑæææhhh000‘‘‘ÜÜÜÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÐÐÐ~~~ÙÙÙÔÔÔÓÓÓÝÝݦ¦¦aaaÌÌÌØØØÔÔÔÕÕÕÔÔÔÙÙÙ~~~ÐÐÐÖÖÖÕÕÕÕÕÕÕÕÕÑÑÑÒÒÒÕÕÕÕÕÕÕÕÕÑÑÑæææhhh000‘‘‘ÜÜÜÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÐÐÐ~~~ÙÙÙÔÔÔÓÓÓÜÜÜ···€€€ãããÒÒÒÕÕÕÔÔÔÙÙÙ~~~ÐÐÐÖÖÖÕÕÕÕÕÕÕÕÕåååâââÔÔÔÕÕÕÕÕÕÑÑÑæææhhh000‘‘‘ÜÜÜÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÐÐÐ~~~ÙÙÙÔÔÔÕÕÕÒÒÒæææUUUØØØÕÕÕÕÕÕÔÔÔÙÙÙ~~~ÐÐÐÖÖÖÕÕÕÕÕÕÖÖÖvvv………ÛÛÛÔÔÔÕÕÕÑÑÑæææhhh000‘‘‘ÜÜÜÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÐÐÐ~~~ÙÙÙÔÔÔÕÕÕÔÔÔßßßµµµ”””âââÒÒÒÔÔÔÙÙÙ~~~ÐÐÐÖÖÖÕÕÕÖÖÖ×××000âââÓÓÓÕÕÕÑÑÑæææhhh000‘‘‘ÜÜÜÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÐÐÐ~~~ÙÙÙÔÔÔÕÕÕÔÔÔÎÎÎÜÜÜ<<<111ÜÜÜÔÔÔÔÔÔÙÙÙ~~~ÐÐÐÖÖÖÕÕÕÕÕÕÕÕÕ···¼¼¼×××ÕÕÕÕÕÕÑÑÑæææhhh000‘‘‘ÜÜÜÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÐÐÐ~~~ÙÙÙÒÒÒÝÝݲ²²³³³ÜÜÜÒÒÒÙÙÙ~~~ÐÐÐÖÖÖÕÕÕÕÕÕÕÕÕÝÝÝÜÜÜÔÔÔÕÕÕÕÕÕÑÑÑæææhhh000‘‘‘ÜÜÜÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÐÐÐ~~~ÙÙÙÓÓÓ×××ËËË¢¢¢¡¡¡¤¤¤©©©ÌÌÌ×××ÔÔÔÙÙÙ~~~ÐÐÐÖÖÖÕÕÕÕÕÕÕÕÕÓÓÓÔÔÔÕÕÕÕÕÕÕÕÕÑÑÑæææhhh000ÚÚÚÐÐÐÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÎÎÎ}}}×××ÒÒÒÒÒÒÕÕÕÞÞÞßßßÞÞÞÝÝÝÕÕÕÒÒÒÒÒÒ×××}}}ÎÎÎÔÔÔÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÏÏÏãããggg222–––ãããÚÚÚÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝ××ׂ‚‚àààÛÛÛÜÜÜÜÜÜÚÚÚÚÚÚÚÚÚÚÚÚÜÜÜÜÜÜÛÛÛààà‚‚‚×××ÝÝÝÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜØØØîîîkkk$$$rrr”””‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘ŽŽŽggg“““‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘“““gggŽŽŽ‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘šššVVV999...000000000000000000000000000000000777000000000000000000000000000000000000777000000000000000000000000000000000111000( @ """,,,¡¡¡–––˜˜˜˜˜˜˜˜˜˜˜˜———žžžpppŽŽŽ›››˜˜˜——————˜˜˜–––¡¡¡mmm333AAAîîîßßßââââââââââââàààéé馦¦ÓÓÓåååáááêêêëëëáááÞÞÞïïï¡¡¡///===ÞÞÞÐÐÐÒÒÒÑÑÑÑÑÑÒÒÒÐÐÐÚÚÚ›››ÅÅÅÖÖÖÑÑѬ¬¬©©©×××ÐÐÐÞÞÞ–––000===áááÓÓÓÔÔÔßßßßßßÔÔÔÔÔÔÜÜÜÆÆÆßßß···[[[777```ÜÜÜààà˜˜˜000===áááÐÐÐäääiiiiiiäääÐÐÐÜÜÜÇÇÇÚÚÚÌÌÌÍÍÍ|||'''ÚÚÚááᘘ˜000===áááÑÑÑÞÞÞ’’’’’’ÞÞÞÒÒÒÜÜÜÆÆÆÝÝÝÅÅÅ000˜˜˜ÛÛÛààà˜˜˜000===àààÒÒÒÓÓÓááááááÓÓÓÓÓÓÜÜÜÆÆÆÛÛÛÈÈÈ777===ÜÜÜßßߘ˜˜222@@@äääÖÖÖÙÙÙÖÖÖÖÖÖÙÙÙ×××àààŸŸŸËËËÜÜÜÙÙÙÙÙÙÑÑÑÔÔÔÖÖÖååå›››---999ÒÒÒÅÅÅÇÇÇÇÇÇÇÇÇÇÇÇÆÆÆÎÎΓ““ºººËËËÇÇÇÇÇÇÉÉÉÈÈÈÅÅÅÓÓÓŽŽŽ XXX|||yyyzzzzzzzzzzzzzzzzzzaaaœœœ¢¢¢ttt“““   ›››¦¦¦ppp ”””ìììãããååååååååååååäääééé¡¡¡ØØØÞÞÞÜÜÜÜÜÜÜÜÜÜÜÜÛÛÛää䢢¢ÎÎÎàààÜÜÜÜÜÜÜÜÜÜÜÜÚÚÚéééžžž ŠŠŠØØØÐÐÐÒÒÒÏÏÏÐÐÐÒÒÒÑÑÑÕÕÕ———ÏÏÏÔÔÔÓÓÓÓÓÓÓÓÓÓÓÓÒÒÒÛÛÛœœœÆÆÆ×××ÓÓÓÒÒÒÐÐÐÔÔÔÐÐÐààà——— ŒŒŒÜÜÜÔÔÔÔÔÔäääÞÞÞÓÓÓÕÕÕØØØ™™™ÑÑÑÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÜÜÜÇÇÇÙÙÙÓÓÓÞÞÞäääÔÔÔÒÒÒââ☘˜ ŒŒŒÜÜÜÒÒÒßßßiii’’’áááÒÒÒØØØ™™™ÑÑÑÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÜÜÜÇÇÇÖÖÖááá’’’iiißßßÑÑÑââ☘˜ ŒŒŒÜÜÜÒÒÒßßßiii’’’áááÒÒÒØØØ™™™ÑÑÑÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÜÜÜÇÇÇÖÖÖááá’’’iiißßßÑÑÑââ☘˜ ŒŒŒÜÜÜÓÓÓÔÔÔäääÞÞÞÓÓÓÔÔÔØØØ™™™ÑÑÑÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÜÜÜÇÇÇÙÙÙÓÓÓÞÞÞäääÔÔÔÒÒÒââ☘˜ ŒŒŒÝÝÝÔÔÔÖÖÖÓÓÓÔÔÔÖÖÖÕÕÕÙÙÙ™™™ÒÒÒ×××ÖÖÖÖÖÖÖÖÖÖÖÖÔÔÔÞÞÞžžžÈÈÈÙÙÙÖÖÖÔÔÔÓÓÓÖÖÖÓÓÓããã™™™ ‰‰‰ØØØÏÏÏÑÑÑÑÑÑÑÑÑÑÑÑÐÐÐÔÔÔ–––ÍÍÍÒÒÒÑÑÑÑÑÑÑÑÑÑÑÑÏÏÏØØØšššÄÄÄÔÔÔÑÑÑÑÑÑÑÑÑÑÑÑÎÎÎÝÝÝ•••ddd———™™™™™™™™™™™™˜˜˜›››mmm–––™™™™™™˜˜˜˜˜˜™™™———žžžppp›››˜˜˜™™™™™™™™™———¢¢¢mmm ŽŽŽßßß×××ØØØØØØØØØØØØ×××ÜÜÜ›››ÔÔÔÙÙÙØØØÙÙÙ×××ØØØÖÖÖàààŸŸŸÊÊÊÜÜÜØØØØØØØØØØØØÕÕÕååå››› ‹‹‹ÛÛÛÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÓÓÓ××ט˜˜ÐÐÐÕÕÕÓÓÓÔÔÔØØØÓÓÓÓÓÓÜÜÜœœœÇÇÇØØØÔÔÔÒÒÒÑÑÑÔÔÔÑÑÑááᘘ˜ ŒŒŒÜÜÜÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØ™™™ÑÑÑÕÕÕÞÞÞOOO˜˜˜âââÑÑÑÝÝÝÇÇÇÙÙÙÓÓÓÞÞÞãããÔÔÔÒÒÒââ☘˜ ŒŒŒÜÜÜÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØ™™™ÑÑÑÓÓÓããã‚‚‚999âââÑÑÑÜÜÜÇÇÇ×××ÞÞÞ£££„„„ÜÜÜÑÑÑââ☘˜ ŒŒŒÜÜÜÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØ™™™ÑÑÑÕÕÕÚÚÚæææ333¤¤¤ÞÞÞÛÛÛÇÇÇÖÖÖããã„„„QQQáááÐÐÐââ☘˜ ŒŒŒÜÜÜÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØ™™™ÏÏÏßßߣ££OOOXXXâââÙÙÙÇÇÇÙÙÙÓÓÓÜÜÜáááÔÔÔÒÒÒââ☘˜ ‹‹‹ÚÚÚÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÖÖÖ˜˜˜ÏÏÏ××ןŸŸ©©©¼¼¼ÓÓÓÚÚÚœœœÆÆÆ×××ÓÓÓÒÒÒÑÑÑÓÓÓÑÑÑààà——— ãããÚÚÚÜÜÜÜÜÜÜÜÜÜÜÜÛÛÛßßßØØØÜÜÜàààèèèæææáááÚÚÚää䢢¢ÎÎÎßßßÛÛÛÜÜÜÜÜÜÜÜÜÙÙÙéééiii‹‹‹ŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹rrrŠŠŠŒŒŒ‹‹‹ŠŠŠŠŠŠŠŠŠ‹‹‹ttt†††‹‹‹ŒŒŒŒŒŒŒŒŒŠŠŠ’’’ooo  (  ¯¯¯¯¯¯°°°«««–––±±±³³³¼¼¼ŽŽŽ%%%àààÚÚÚÛÛÛÚÚÚÁÁÁÝÝÝ’’’ÃÃü¼¼$$$ÜÜÜ«««¬¬¬ÖÖÖ···ÍÍÍ@@@———¹¹¹$$$ÙÙÙÙÙÙÚÚÚÓÓÓ¼¼¼ÓÓÓ„„„ÒÒÒ´´´ ===>>>===:::KKK¶¶¶¸¸¸¸¸¸´´´žžž¼¼¼ÂÂÂÁÁÁ–––±±±êêêååååååÂÂÂÆÆÆÓÓÓÑÑÑÍÍÍ´´´ÓÓÓÓÓÓÚÚÚ«««©©©××ר¨¨×××¹¹¹ÌÌÌØØØ×××ÑÑѸ¸¸ÚÚÚ¬¬¬ÛÛÛ°°°¬¬¬ÝÝÝ­­­ÝÝݽ½½ÎÎÎÚÚÚØØØÓÓÓ¹¹¹ÛÛÛ­­­ÝÝݱ±±¢¢¢ÕÕÕÑÑÑÏÏϲ²²ÂÂÂÌÌÌËËËÇÇǯ¯¯ÎÎÎÑÑÑÕÕÕ¦¦¦•••ÃÃ÷··¿¿¿¤¤¤±±±Â¿¿¿¶¶¶¡¡¡½½½···ÃÃÙ™™­­­âââÖÖÖÞÞÞ½½½ÕÕÕ»»»ÉÉÉÚÚÚºººÜÜÜØØØããã²²²§§§ÛÛÛÏÏÏÖÖÖ···ÒÒÒ£££oooÙÙÙ³³³ÖÖÖ‘‘‘ÕÕÕ®®®±±±çççÛÛÛâââÂÂÂÙÙÙ«««†††ÜÜÜ¿¿¿áááÕÕÕççç¶¶¶ŠŠŠ°°°§§§­­­———¢¢¢¯¯¯´´´¦¦¦•••¬¬¬©©©±±±(0` %%%ooofffhhhgggjjj===eeeppp222FFF,,,RRRöööâââæææåååêêꈈˆàààçççøøø@@@(((KKKÎÎÎÑÑÑÐÐÐÕÕÕ|||ÌÌÌÒÒÒÏÏÏÍÍÍAAA)))LLLäääÔÔÔÙÙÙ~~~ÖÖÖßßßÓÓÓ```***+++ÛÛÛÝÝÝØØØÈÈÈ‘‘‘UUU¨¨¨ÞÞÞËËËmmmóóó°°°ãããÉÉÉ YYYÇÇÇ×××555"""nnnžžž MMM???JJJ{{{GGGƒƒƒ}}}€€€000™™™ìììÜÜÜÚÚÚÁÁÁBBB”””µµµ111VVV‚‚‚///’’’¦¦¦aaa···vvv………<<<¼¼¼²²²³³³¢¢¢¡¡¡¤¤¤©©©–––îîîkkk$$$rrrŽŽŽ“““ššš999...777  !!!!!!!!"#$%&!!'"''!!()*+,&########-./"0#011##! )*+,&###22###-./"0023456-! )*+,&##07-##-./"089 :;<=' )*+,&-8>5?&#-./"0##.@ABC  )*+,&-.DEF,&#-./"021+5G5H8" )*+,&###I0###-./"0&CJKLM.-! )*+,&###0####-./"0&GN I! )*+,&########-./"0##!(> ##! )5OPQ200000000#6R!8008..800& ST1(""""""""'-U>!"""'''""% N +++++++++QVSWX////////XYUR////////$ Z[\,,,,,,,,W78........8=Y-6........# ZB8'&&&&&&&&2%X82--------28X'#--------" Z:]2########0"/.-########-./"0########! Z:]2##-!2###0"/.-########-./"0###&&###! Z:]2#-87-##0"/.-########-./"0###,-##! Z:]2-^_`a2#0"/.-########-./"0##0F?72#! Z:]227bL!#0"/.-########-./"0#0IcZ2#! Z:]2##2H'0##0"/.-########-./"0###D>0##! Z:]2##0^I###0"/.-########-./"0###.8###! Z:]2###-####0"/.-########-./"0###--###! Zd6&--------#'X82--------28X'#--------" eaI........6-Y=8........8=Y-6........# fghX////////RUYX////////XYUR////////$ ijI """"""""!>U-'""""""""'-U>!""""""""% Zk7-000000008!R6#0I#&0000#6R!800000000& Z:]2########0"/.-#-]0-##-./"0########! Z:]2########0"/.-27lm%8-#-./"0###!&###! Z:]2########0"/.-2]nYC&#-./"0###-##! Z:]2########0"/.-#&;o8##-./"0##0pq6-#! Z:]2########0"/.-#-1ba&-./"0#0IcZ2#! Z:]2########0"/.-#- ]re]--./"0###nsI##! Z:]2########0"/.&7tuvwx]&./"0###7]-##! Z:]2########0"/.2I>yz{|%I-./"0###2-###! Zd^"22222222- XI&&#=1=7#&&IX -22222222'C }C^]]]]]]]]7Ih6]]^^^^]]6hI7]]]]]]]]8~€ad:::::::::‚ ƒd::::::::dƒ ‚:::::::::B„gc…†ZZZZZZZZZZZ‡ZZZZZZZZZZZZ‡ZZZZZZZZZZZeZ( @""",,,¡¡¡–––˜˜˜———žžžpppŽŽŽ›››mmm333AAAîîîßßßâââàààéé馦¦ÓÓÓåååáááêêêëëëÞÞÞïïï///===ÐÐÐÒÒÒÑÑÑÚÚÚÅÅÅÖÖÖ¬¬¬©©©×××000ÔÔÔÜÜÜÆÆÆ···[[[777```äääiiiÇÇÇÌÌÌÍÍÍ|||'''’’’ÝÝÝÛÛÛÈÈÈ222@@@ÙÙÙŸŸŸËËË---999ÎÎΓ““ºººÉÉÉ XXXyyyzzzaaaœœœ¢¢¢ttt   ”””ìììãããØØØŠŠŠÏÏÏÕÕÕŒŒŒ™™™‰‰‰šššÄÄÄ•••ddd ÊÊÊ‹‹‹OOO‚‚‚£££„„„æææ¤¤¤QQQ¼¼¼èèèrrr†††ooo     !"#$%%$#&'(%)*+#,-".../012345/ ,-"#6776#/08&9:;<& ,-"%==$/01>'?- @ ,-"$/01@A4"B/ ,CDEEEEFG6(H((H+IJ/HH%.(KLM$'88881NOPJ88QA' RS;TUUUUUUV000000WXYOZ0000 R[\]6^////@6XN////& R_^#$`#$%a `.$@W1+$#.# Rb/..6a^c%(aaaa/08H6.$ Rb/$7=$^c%(aaaa/08(=7% Rb/$7=$^c%(aaaa/08(=7% Rb/.6.^c%(aaaa/08H6.$ Rb>.(.(aHc$+((((. AH(.(]cRd^`%%%%#.:$%%%%`^ef.%%%%N>ghi0 cccc cc c j ccc Xk +^^^^+/.H^H+^(Il/^^^^aRm@....+ #a.^/W8^.$%.% Rb/aaaa.^c%an %>08H].$ Rb/aaaa.^c%]oM%/08+pq/% Rb/aaaa.^c%a&rs@08(]qt# Rb/aaaa.^c`pn,SH08H/.$ Rm&$( `+uI*v&W1+$%% kw]&////@0^/xr&6XN@///H0h7jmbbbbmBy_bm___mjYzBmbbb_={|RRRRRRRR}kRRRRRkR|kRRRRRkR~( ¯¯¯°°°«««–––±±±³³³¼¼¼ŽŽŽ%%%àààÚÚÚÛÛÛÁÁÁÝÝÝ’’’ÃÃÃ$$$ÜÜܬ¬¬ÖÖÖ···ÍÍÍ@@@———¹¹¹ÙÙÙÓÓÓ„„„ÒÒÒ´´´ ===>>>:::KKK¶¶¶¸¸¸žžžÂÂÂêêêåå寯ÆÑÑÑ©©©××ר¨¨ÌÌÌØØØ­­­½½½ÎÎ΢¢¢ÕÕÕÏÏϲ²²ËËËÇÇǦ¦¦•••¿¿¿¤¤¤¡¡¡™™™âââÞÞÞ»»»ÉÉɺººããã§§§£££ooo‘‘‘®®®çç熆†ááኊŠ    !"#$$% %&'()*+*,-.//(0 12 34415%6(%%7898":;86/<=>;%"< ?@6AB1:CD>6@E2FGH 1G.I=J& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÕÓÓÕÕÕÕÓÓÕÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÕÓÓÕÕÕÕÓÓÕÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÕÓÓÕÕÕÕÓÓÕÓÓÕÕÕÕÕÕÓÓÓÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÝÝÓààÕÖÖÓÞÞÓààÕÓÓÕÕÕÕÕÕÕÕÕÕÓÓÓÝÝÓààÕÖÖÓÞÞÓßßÕÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÞÞÓßßÕÕÕÓßßÓÞÞÕÒÒØØØÀÀÀÍÍÍ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÞÞܱ±ñFFø!!ô88áššÓÞÞÕÓÓÕÕÕÕÓÓÓÞÞÝ­­òCCø!!ó;;àžžÓßßÕÓÓÕÕÕÕÕÕÕÕÕÖÖÖ×××ÓÓÓÖÖÖÖÖÖÕÕÕÕÕÕÕÕÕÕÓÓÓßßߤ¤ó>>ø!!ò??Þ§§ÒÞÞØÖÖ¿¿¿ÍÍÍ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÝÝܰ°ý ÿÿÿÿ㎎ÓááÖÐÐÓÞÞݪªýÿÿÿÿâ””ÓààÖÒÒÕÕÕÖÖÖÐÐж¶¶­­­µµµÏÏÏÖÖÖÕÕÕÕÓÓÓßßàžžÿÿÿÿþß¡¡ÖââÀ½½ÍÍÍ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓßßðJJÿþÿþÿø%%ÖÒÒÕÔÔÓÝÝòBBÿþÿþÿ÷++ÕÕÕÕÕÕÕÔÔÖÖÖµµµ¦¦¦ªªª¦¦¦³³³ÕÕÕÕÕÕÕÔÔÔÙÙõ44ÿþÿþÿó77×ÞÞ¿¾¾ÍÍÍ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖø##ÿÿÿÿÿþÚ¼¼ÔÜÜÖÑÑùÿÿÿÿÿý ÙÂÂÔÚÚÖÕÕÑÑÑ«««ªªªªªª«««ªªªÏÏÏ×ÖÖÔØØ×ÊÊüÿÿÿÿÿúÚÏÏ¿ÂÂÍÌÌ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÝÝó;;ÿþÿþÿú×ËËÕÖÖÔÚÚõ44ÿþÿþÿùÖÐÐÕÖÖÕÔÔÕÕÕ±±±§§§«««§§§¯¯¯ÔÔÔÕÕÕÕÕÕÕÕÕ÷''ÿþÿþÿö**ØÙÙ¿¿¿ÍÌÌ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÓààᘘÿÿÿÿÿéqqÓââÖÐÐÓááâ‘‘ÿÿÿÿÿçxxÓââÖÒÒÕÕÕ×××ËË˯¯¯©©©®®®ÊÊÊ×××ÕÕÕÖÒÒÓáá僃ÿÿÿÿÿ䆆ÖääÀ¼¼ÍÍÍ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÞÞ㎎ùþûéqqÔÚÚÕÕÕÕÕÕÕÓÓÓÞÞ䉉ùþûèvvÔÛÛÕÕÕÕÕÕÕÕÕÕÕÕ×××ÓÓÓÍÍÍÓÓÓ×××ÕÕÕÕÕÕÕÕÕÕÔÔÔÝÝæ~~úþúæÓÜÜØ×׿¿¿ÍÍÍ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓààÖÒÒÚ»»×ÌÌÓááÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÓááÖÑÑÚ»»×ÍÍÓááÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×ÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÓááÖÏÏÚ»»ÖÏÏÓááÕÓÓØØØ¿¿¿ÍÍÍ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÐÐÕÔÔÔÜÜÕÖÖÖÐÐÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÐÐÕÔÔÔÜÜÕÖÖÖÐÐÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÕÓÓÔÖÖÕÓÓÕÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÐÐÕÕÕÔÜÜÕÕÕÖÐÐÔÔÔØØØ¿¿¿ÍÍÍ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÞÞÓÞÞÖÐÐÔÛÛÓààÕÓÓÕÕÕÕÕÕÕÕÕÕÓÓÓÞÞÓÝÝÖÐÐÔÛÛÓààÕÓÓÕÕÕÕÕÕÕÕÕÕÓÓÓßßÓÝÝÖÒÒÔÝÝÓßßÕÓÓÕÕÕÕÕÕÕÕÕÕÓÓÓßßÔÜÜÖÐÐÔÜÜÓßßÕÒÒØØØ¿¿¿ÍÍÍ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÞÞÝ««ó??úõ11â““ÓÞÞÕÔÔÕÕÕÕÓÓÓßßÞ§§ó<<úõ33ᘘÓÞÞÕÓÓÕÕÕÕÓÓÓßßߢ¢ô99úô66àœœÓßßÕÓÓÕÕÕÕÓÓÓßßàžžô77úô88ß¡¡ÒÞÞØÖÖ¿¿¿ÍÍÍ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÝÝݬ¬ýÿÿÿÿ䈈ÓááÖÐÐÓÞÞÞ¦¦þÿÿÿÿãÓááÖÐÐÓßßàŸŸÿÿÿÿÿá––ÓààÖÐÐÓààá™™ÿÿÿÿÿßœœÖââÀ½½ÍÍÍ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓßßñGGÿþÿþÿø""ÖÑÑÕÕÕÓÝÝò??ÿþÿþÿ÷((ÕÔÔÕÔÔÔÛÛô88ÿþÿþÿö//Õ××ÕÔÔÔØØõ22ÿþÿþÿô55×ÝÝ¿¾¾ÍÍÍ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖø##ÿÿÿÿÿþÚ¼¼ÔÜÜÖÑÑùÿÿÿÿÿý ÙÁÁÔÜÜ×ÍÍúÿÿÿÿÿüØÆÆÔÜÜ×ÉÉûÿÿÿÿÿúÚÏÏ¿ÂÂÍÌÌ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÝÝó==ÿþÿþÿú×ÌÌÕÖÖÔÚÚô66ÿþÿþÿù ÖÐÐÕÖÖÔØØö//ÿþÿþÿø&&ÕÔÔÕÖÖÕÕÕ÷))ÿþÿþÿö,,ØÚÚ¿¿¿ÍÍÍ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓßßàœœÿÿÿÿÿèvvÓââÖÐÐÓààá––ÿÿÿÿÿæ}}ÓââÖÐÐÓááãÿÿÿÿÿå„„ÓááÖÏÏÓáá䈈ÿÿÿÿÿã‹‹ÖääÀ¼¼ÍÍÍ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓßßâ••ø%%ý úçyyÔÛÛÕÕÕÕÕÕÕÓÓÓÞÞãø##ý ùæ~~ÔÜÜÕÔÔÕÕÕÖÔÔÔßßä‹‹ù!!þ úæ„„ÔÞÞÖÕÕÖÕÕÖÔÔÔÞÞ円úþ ù 剉ÓÞÞÙ××ÀÀÀÍÍÍ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓààÕÖÖÙÁÁÖÐÐÓââÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓààÕÕÕÙÁÁÖÑÑÓááÕÔÔÕÕÕÕÕÕÒÒÒÒÐÐÏÝÝÒÐÐÖ¾¾ÒÏÏÏÞÞÒÑÑÒÒÒÒÒÒÒÒÒÒÑÑÏÞÞÒÏÏÖ¾¾ÒÐÐÏÞÞÑÐÐÕÕÕ½½½ÍÍÍ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÒÒÕÕÕÔÚÚÕÖÖÖÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÒÒÕÕÕÔÚÚÕÖÖÖÒÒÕÕÕÔÔÔØØØèèèééééææèééèîîèêêéææéèèééééééééééèèéææèééèîîèéééææèèèíííÌÌÌÌÌÌ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÖÕÕÕÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÖÕÕÕÔÔÕÕÕÕÕÕØØØÄÄÄÖÖÖâââßßßßßßàÞÞßßßßßßßßßßßßßßßßßßßßßßßßßßßàÞÞßßßßßßßßßàààÚÚÚÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÑÑÑÕÕÕ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÑÑÑÕÕÕ×××ÔÔÔØØØÀÀÀÈÈÈÕÕÕÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÒÒÒÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÐÐеµµ«««±±±ÌÌÌ×××ÕÕÕÕÕÕÕÕÕÖÖÖÏÏÏ´´´«««²²²ÍÍÍÖÖÖØØØÁÁÁËËËØØØÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××¶¶¶¦¦¦ªªª§§§¯¯¯ÓÓÓÕÕÕÕÕÕÕÕÕÖÖÖµµµ¦¦¦ªªª§§§°°°ÓÓÓÙÙÙÁÁÁÊÊÊ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÓÓÓ­­­ªªªªªª«««©©©ÍÍÍ×××ÔÔÔÖÖÖÒÒÒ¬¬¬ªªªªªª«««ªªªÍÍÍÚÚÚÁÁÁÊÊÊ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖµµµ¦¦¦«««§§§®®®ÓÓÓÖÖÖÕÕÕÕÕÕÖÖÖ´´´¦¦¦«««§§§¯¯¯ÓÓÓÙÙÙÁÁÁÊÊÊ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÏÏϳ³³ªªª¯¯¯ÊÊÊ×××ÕÕÕÕÕÕÕÕÕÖÖÖÎÎβ²²ªªª°°°ËËËÖÖÖØØØÁÁÁÊÊÊ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÕÕÕÏÏÏÔÔÔ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÕÕÕÏÏÏÔÔÔ×××ÔÔÔØØØÁÁÁÊÊÊ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×ÖÖÕÕÕÕÕÕÔÔÔØØØÁÁÁÊÊÊ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÓÓÕÔÔÔØØÕÕÕÖÒÒÔÔÔØØØÁÁÁÊÊÊ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓßßÔÙÙ×ÉÉÕÖÖÓááÕÓÓØØØÁÁÁÊÊÊ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÐÐÐÔÔÔ×××ÕÕÕÕÕÕÕÕÕÕÓÓÓßßáššö--üø&&䊊ÓÝÝÙ××ÁÁÁÊÊÊ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÏÏÏ´´´«««°°°ÊÊÊ×××ÕÕÕÕÓÓÓßßàÿÿÿÿÿä……Öää¾¾ÊÊÊ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖµµµ¦¦¦«««§§§®®®ÓÓÓÖÕÕÕÓÓÔÜÜô::ÿþÿþÿ÷##ÙÖÖÁÂÂËÊÊ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÓÓÓ­­­ªªªªªª«««©©©ÍÍÍ×ÖÖÔÖÖÖÒÒùÿÿÿÿÿü ÜÅÅÀÆÆËÉÉ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖ¶¶¶¦¦¦«««§§§®®®ÓÓÓÖÕÕÕÓÓÔÜÜó;;ÿþÿþÿ÷##ÙÖÖÁÂÂËÊÊ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÐÐд´´«««°°°ËËË×××ÕÕÕÕÓÓÓßßàŸŸÿÿÿÿÿ䆆Öää¾¾ÊÊÊ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÕÕÕ×××ÖÖÖÑÑÑÕÕÕ×××ÕÕÕÖÖÖÖÖÖÖÔÔÔßßáö11üø))äÓÞÞÙØØÂÁÁÊÊÊ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÐÐÐÜÜÑØØÔÈÈÒÕÕÐÞÞÒÐÐÕÕÕ¾¾¾ÊÊÊ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔ×××êêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêëèèëééêííêêêëèèéééïïïÑÑÑÊÊÊ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÜÜÝÝÝÝÝÝÝÝÝÝÝÝÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ( @ ÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÕÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÕÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÕÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÕ××ÔÙÙÕÓÓÕÔÔÕÕÕÕÕÕÕÓÓÔØØÔÙÙÕÓÓÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÔØØÔØØÕÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÓàà×ÍÍØÃÃÓßßÕ××ÕÕÕÕÔÔÓàà×ËËØÅÅÓßßÕÖÖÕÕÕÕÕÕÕÕÕØØØØØØÕÕÕÕÕÕÕÕÕÕÕÕÓààØÈÈØÈÈÒàà×××ÆÆÆÒÒÒÖÖÖÕÕÕÕÓÓÓßß䊊ûýíYYÕÖÖÕÓÓÓÞÞåüý ìaaÔÙÙÕÕÕÕÕÕÖÖÖÇÇÇÆÆÆÕÕÕÕÕÕÕÔÔÔÜÜéqqý ý èqqÕÞÞÄÂÂÑÑÑÖÖÖÕÓÓÔÛÛÚººý ÿþÿ怀Ñêêܯ¯þÿþÿ㌌ÒááØÕÕÁÁÁ¦¦¦¦¦¦½½½ØÕÕÓßßß  ÿÿÿÿᢢÂÏÏÒÏÏÖÖÖÖÒÒÓàààÿþþÿíZZÏññãÿþþÿëhhÑääØÔÔ´´´¨¨¨©©©°°°×ÓÓÒääæ~~ÿþþÿ耀ÁÓÓÒÎÎÖÖÖÕÔÔÔØØ×ÉÉúÿÿÿá™™ÒääÙÀÀûÿÿÿߣ£ÓÞÞ×ÕÕÈÈÈ«««ªªªÅÅÅ×ÕÕÓÛÛÛ´´ý ÿÿýݶ¶ÃËËÒÐÐÖÖÖÕÕÕÕÓÓÓÝÝܲ²òAAö00㌌ÓÝÝÖÒÒÓÞÞݬ¬ó==õ22â““ÓÞÞÕÓÓÕÕÕ×××ÑÏÏÐÎÎ×××ÕÕÕÕÓÓÓÞÞà  ô77ô77ߟŸÕààÅÂÂÑÒÒÖÖÖÕÕÕÕÕÕÕÓÓÔÚÚÒääÒääÓßßÕÓÓÕÖÖÕÓÓÔÛÛÒääÒääÓÞÞÕÓÓÕÕÕÕÕÕÕÒÒÕÛÛÕÜÜÕÓÓÕÕÕÕÕÕÕÓÓÔÜÜÒääÒääÓÜÜ×ÕÕÄÅÅÑÑÑÖÖÖÕÕÕÕÕÕÕÔÔÓÞÞØÄÄÚººÔÚÚÕ××ÕÔÔÕÕÕÓÞÞÙÂÂÚ»»ÔÛÛÕ××ÕÔÔÕÕÕÓßߨÂÂÙ¾¾ÓßßÕÖÖÕÔÔÕÖÖÓÝÝÙ¾¾Ù¾¾ÓÜÜ×××ÄÄÄÑÒÒÖÖÖÕÕÕÕÓÓÓßßæ€€ý ÿïOOÕÔÔÕÔÔÓÝÝçxxýþîWWÕ××ÕÔÔÔÝÝéooþþì__ÔÙÙÕÓÓÔÛÛëggþþêggÖÝÝÄÃÃÒÑÑÖÖÖÕÓÓÔÜÜÛ··þÿþÿç||ÑëëÝ««ÿÿþÿ円Ñììߣ£ÿÿÿÿãÐììá™™ÿÿÿÿâžžÂÏÏÒÏÏÖÖÖÖÒÒÓàààžžÿþþÿí[[Ïññâ‘‘ÿþþÿëeeÏóó円ÿþþÿéppÏóóç{{ÿþþÿèÁÓÓÒÎÎÖÖÖÕÔÔÕ×××ÌÌù!!ÿÿÿàžžÒââØÄÄúÿÿþÞ§§ÒããÚ¾¾üÿÿþݰ°ÓããÛ··ý ÿÿü Ý»»ÃËËÒÐÐÖÖÖÕÕÕÕÓÓÔÜÜÛ¹¹ðMMó<<á––ÓÞÞÖÒÒÓÝÝÜ´´ñIIó>>àœœÓÞÞÕÑÑÑÛÛÚ¬¬ïDDð>>Ý  ÑÜÜÓÏÏÑÜÜܦ¦ð@@ïAAÛ¦¦ÓÝÝÃÁÁÒÒÒÖÖÖÕÕÕÕÕÕÕÓÓÔÛÛÒââÒààÓßßÕÔÔÕÕÕÕÓÓÔÜÜÒááÒààÓßßÕÓÓØØØàÞÞÞççÝííÝììÞééàÞÞààààÞÞÞèèÝììÝììÝèèãááÊËËÑÑÑÖÖÖÕÕÕÕÕÕÕÕÕÕÓÓØÕÕÙÖÖÖÓÓÕÕÕÕÕÕÕÕÕÕÓÓØÕÕÙÖÖÖÓÓÖÖÖÊÊÊÛÛÛáßßàÝÝàÝÝàÝÝààààààààààÞÞàÝÝàÝÝàÝÝáááÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÅÅÅÀÀÀÒÒÒÖÖÖÕÕÕÕÕÕÕÕÕÄÄÄÀÀÀÓÓÓØØØÄÄÄÍÌÌÔÔÔÓÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÒÒÒÔÔÔÕÕÕÕÕÕÕÕÕÔÔÔØØØÃÃæ¦¦¦¦¦¶¶¶ÖÖÖÔÔÔØØØÁÁÁ¦¦¦¦¦¦¸¸¸ÙÙÙÆÆÆÐÐÐ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØººº¦¦¦©©©­­­ÔÔÔÕÕÕØØØ···§§§©©©¯¯¯ØØØÆÆÆÏÏÏÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÎÎΰ°°«««ÄÄÄ×××ÔÔÔ×××ÌÌ̯¯¯¬¬¬ÅÅÅÙÙÙÅÅÅÏÏÏÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÔÔÔÒÒÒ×××ÕÕÕÕÕÕÕÕÕ×××ÔÒÒÓÐÐÖÖÖ×××ÆÆÆÏÏÏÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÓÓÔÝÝÔßßÔÓÓØÖÖÆÆÆÏÏÏÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕØØØØØØÖÖÖÕÕÕÕÕÕÕÖÖÓÞÞÛ´´Ý««ÔÙÙ×ÛÛÆÅÅÏÏÏÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÃÃý½½ÑÑÑÖÖÖÕÓÓÔÝÝëeeÿÿñBBØÕÕÆÇÇÏÎÎÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÂ¦¦¦¦¦¦µµµÖÔÔÓÞÞÞ¨¨ÿÿþÿ胃ÃÓÓÐÌÌÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØººº¦¦¦©©©®®®ÕÒÒÓââá––ÿþþÿìmmÃÕÕÐÌÌÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÏÏϲ²²­­­ÆÆÆØ××Õ×××ÍÍø$$ÿÿý ßµµÅÍÍÏÍÍÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÒÔÔÔÒÒÒÑÑÑÔÔÔÒÓÓÓÑÑÑÙÙ×¾¾ê]]ìQQÚªªÓÞÞÄÂÂÏÏÏÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××âââââââââãããââââââââââáááççßññßññàééåããÏÐÐÏÏÏ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÜÜÞÚÚÞÚÚÝÛÛÞÞÞÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ(  ÕÔÔÔÙÙÑççÔÜÜÕÔÔÒããÒääÕÕÕÕÕÕ×××ÕÕÕÕÕÕÒããÒããÕÕÕÕÕÕÔÙÙÙÂÂêkkܲ²ÓààäŠŠå‚‚ÕØØÕÕÕÏÎÎÕÔÔÔÙÙ䆆懇ÎÓÓÒÑÑÒååì__ÿñEEÙÀÀÿÿᨨÆÒÒ£ÄÎÎß²²þÿÕ¨¨ÏÚÚÓßßᘘúæÔØØòBBô77ÙÇÇÐÓÓ½¿¿ÏÑÑØËËò==ô>>ÐÄÄÑÔÔÕÔÔÒââ×ÊÊÓßßÓÞÞÕÖÖÖÒÒÓààÕÙÙÛÊÊÕÙÙÓßßÕÔÔÖÕÕÌ××ÒÏÏÒââ僃ÿêhhÕÓÓø##ûØÈÈæÿèuu×ÎÎùûÒ¼¼ÐÖÖÒååëddÿñIIØÅÅþÿÛ¸¸ë``ÿíTTؾ¾ÿÿÓ««ÐÙÙÔ××ÖÎÎåÙÃÃÓàà১៟ÔÞÞÜÏÏé’’ÝÌÌØäää¦¦æ©©ÑØØÑÐÐÕÕÕÔ××ÊÛÛÒ×××ÔÔÎÙÙÎÛÛÑÏÏÖÙÙÙééÚÞÞÛÙÙØååÙååÙ××ÔÕÕרØËÊÊ¢žžÃÂÂÚÛÛ°¬¬®ªªÎÏÏÐÏÏÕÒÒÔÓÓÔÔÔÔÑÑÔÑÑÔÔÔÕÕÕÖÖÖÒÒÒÀÀÀÏÏÏØÖÖÆÉÉÆÊÊÐÎÎÑÑÑÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÛÛÛØÖÖÓÚÚÙÍÍÜËËÍÕÕÑÐÐÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÏÏϲ±±ÉÎÎÚÉÉøýÔ´´Ð××ÖÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ËË˨¦¦ÄËËÛ¾¾üÿÕ¤¤ÏÚÚÖÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÛÛÛÚÛÛÜÚÚÚáá⵵尰ÒÚÚÑÐÐÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÚÚÚÛÛÛÚÚÚÚÙÙØããØååÙØØÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ(0` ÕÕÕÕÓÓÒÒÒÓßßÔØØÓààÔÜÜØ××¾¾ÎÎÎݬ¬ñFF÷##ô::áššù!!àØØØÞ§§ò??¿¾¾Ü±±ý ÿã‹‹Ý««ü á––¶¶¶«««ÒÏÏþߢ¢ðJJø%%òBB÷((¦¦¦ªªª³³³ö11ô55ÚÚÚ¿ÂÂÚ»»úØÆÆ¬¬¬ÔÈÈüúÚÏÏú°°°ø))éqqâ““çxxËÊÊ®®®ËËË僃䆆ÖääÔÙÙ䊊èvvæ}}ÒÕÕ×ÍÍÚ¼¼ó;;àŸŸãö--ÙÁÁÖÒÒÂÁÁâ••çyyãä……ÏÝÝÖ¾¾ééééææêííèêêâââíííÄÄÄààààÞÞÝÝÝÖââÝÜܯ¯¯ÜÅÅÀÆÆêêê       !"#$%&%'()*+ ,-./&&&& 0123+ 43)-5%&%56$ 789:5&;<=>?<27@A-2B C44= ,3D,EEF E +  4(8G4( 4)H 4 H AI  $ J@()* F-KE21.012L+ 4E@)J"6$M B?CI=A N"4OP-CI-=Q-AM KEKRSRS TTUTVWUTTTTUUTVWTXY< ZX[\][[][[][]\\]][^_MZDD&5 5;5 M<L%&&;%&%5M<D;&&/& &&&& *M<%/%;%;%`DM<5&;< 5&;<M< M<M<M<0M< J1"AM< &5<>?<%;%;  M<;&&;& L-ab<%&%;  M<;; >?<(16M<DD0D<TTTTTTYTTTcTccVTcTY<]]]]]]]]]]]]]]_]]]]D( @ÕÕÕÒââÓÍÍØÃÃÓÜÜÚÚÚÄÄÄã‹‹üÿì\\僃ý ëeeëlléqqÚ¼¼ç{{ÑëëÜ´´¦¦¦»»»á¡¡Þ¤¤ÃÍÍߟŸÏòò³³³«««ØÕÕèÂÔÔú᜜ñAAõ44Ü««ò==â““ÎÍÍØÈÈ×¾¾ïOOíTTñKKïCCàÞÞÞççÝëëâââàééÏÐÐù##ßññ          !  "#$%#&'##()) * +   $  ! !      $  *%&,%$--$"-./000120001'''.1.1.../3'33'''''3$' "'$ ' '4 ') +$31/1111/1052213( ÕÔÔÔÙÙÑççÔÜÜÒããÒääÕÕÕ×××ÙÂÂêkkܲ²ÓààäŠŠå‚‚ÕØØÏÎÎ䆆懇ÎÓÓÒÑÑÒååì__ÿñEEÙÀÀÿᨨÆÒÒ£ÄÎÎß²²þÕ¨¨ÏÚÚÓßßᘘúæÔØØòBBô77ÙÇÇÐÓÓ½¿¿ÏÑÑØËËò==ô>>ÐÄÄÑÔÔÒââ×ÊÊÓÞÞÕÖÖÖÒÒÕÙÙÛÊÊÖÕÕÌ××ÒÏÏ僃êhhÕÓÓø##ûØÈÈèuu×ÎÎùûÒ¼¼ÐÖÖëddñIIØÅÅþÛ¸¸ë``íTTؾ¾ÿÓ««ÐÙÙÔ××ÖÎÎåÙÃÃ১៟ÔÞÞÜÏÏé’’ÝÌÌØäää¦¦æ©©ÑØØÑÐÐÊÛÛÒ×××ÔÔÎÙÙÎÛÛÑÏÏÖÙÙÙééÚÞÞÛÙÙØååÙååÙ××ÔÕÕרØËÊÊ¢žžÃÂÂÚÛÛ°¬¬®ªªÎÏÏÐÏÏÕÒÒÔÓÓÔÔÔÔÑÑÖÖÖÒÒÒÀÀÀÏÏÏØÖÖÆÉÉÆÊÊÐÎÎÑÑÑÛÛÛÓÚÚÙÍÍÜËËÍÕÕ²±±ÉÎÎÚÉÉøýÔ´´Ð××ÖÔÔËË˨¦¦ÄËËÛ¾¾üÕ¤¤ÜÚÚÚáá⵵尰ÒÚÚÚÚÚÚÙÙØããÙØØ  !"#$%&'()*+,-./0123"456 787"9:;2<=>?@A%BCDEFGHIJKLMNOPQRSTUV WXYZ[\]^_`aSbcdefghijklmnopqrstuvwxyz{||{}~€‚ƒ„…}†‡ˆ‰Ša}€‹ŒŽ‘’“”•–—˜!’†t™š›œa}}ž†žŸ l¡(0`€€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿwwwwwwwwwwwwwwwwwwwwwwwwwwxwwwwww‡wwwwwwwwwwwwwwwwÌ̇wwwÌÌwwwwwwwwwŒÌÇwww|ÌÌÇwwÌÌÌÇwwwwwwwxÌÌÌwwwŒÌÌÈwwÌÌÌÈwwwwwww|ÌÌ̇wwÌÌÌÌwxÌÌÌÌwwwwwww|ÌÌÌÇwwÌÌÌÌwxÌÌÌÈwwwwwww|ÌÌÌÏww|ÌÌÌwwÌÌÌÇwwwwwww|ÌÌ̇ww|ÌÌÇww|Ì̇wwwwwwwwÌÌÌwwww|ˆwwwwŒÇ÷wwwwwwww|Èwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww÷wwwwwwwwwwwwwwwwwwwwwww÷wwwww|Èwwww|ÇwwwwŒÇwwwxÈwwwwüÌÌÇww|Ì̇wwŒÌÌwwwÌÌÌwwwŒÌÌÈwwÌÌÌÇwwÌÌ̇wxÌÌÌwwwÌÌÌÌwxÌÌÌÌ÷xÌÌÌÇw|ÌÌ̇wwÌÌÌÌwwÌÌÌÌw|ÌÌÌÇw|ÌÌÌÇwwŒÌÌÌwwÌÌÌÇwxÌÌÌÇw|ÌÌ̇ww|ÌÌÈwwŒÌÌÇwwÌÌÌÇwxÌÌÌwwwxÌ̇ww|ÌÌwww|ÌÌwwwŒÌÇwwwwwwwwwxwwwww‡wwwww‡wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww÷÷ÿÿ÷÷ÿwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwx‡wwwwwwwwwwwwwwwwwwwww|ÌÌwwwwwwwwwwwwwwwwwwwwwÌÌÌÈwwwwwwwwwwwwwwwwwwwwÌÌÌÌwwwwwwwwwwwwwwwwwwwwÌÌÌÌwwwwwwwwwwwwwwwwwwwwÌÌÌÈwwwwwwwwwwwwwwwwwwwwÌÌÌÈwwwwwwwwwwwwwwwwwwwxÌÌwwwwwwwwwwwwwwwwwwwwwwx‡wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww÷÷÷÷ÿ÷ÿwwwwwwwwwwwwwww÷wwwwwwwwwwwwwwwwwww( @€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ÷÷ww÷÷wÿwwÿw÷w÷÷ww÷w÷w÷ww÷÷|Ì÷ÌÌwww÷|ÌÏwwÌ̇wÌÌÿxww|ÌÇw÷ÌÌÇüÌ̇w‡w÷ÌÌÈ÷wÌÌÏøÌÌw÷wwŒÌÇw÷|ÌŒÈwxw÷üÌw÷ww÷÷÷÷w÷÷www÷w÷ww÷ww÷øÇ÷wÏwŒwwÈÌÌwÌÌüÌÇ|ÌÇwwÌÌÇüÌ̇|ÌÌŒÌÇw÷ÌÌÇüÌÌ|ÌÌwÌÌÇw÷ŒÌwwÌÌwüÌÇ÷|ÌÇwwwÇwww‡ÿwwww‡w÷÷÷÷÷wÿ÷wÿ÷ÿww÷w÷w÷wÿw÷÷ÿwwwÿwwwww÷w÷÷wwwwwxw÷÷÷wwwwwxw‡ww÷wÿ÷w÷ww‡ÿww‡÷÷wwÿw÷wwwwwww÷ÿwwww÷wwwÿÿw÷www÷÷÷÷wwwwÿw÷ww÷wx‡ww÷wÿw÷÷w÷÷ÌÌwÿw÷w÷wwwxwüÌÌÏwww÷ÿwwxww|Ì̇÷÷wwwÿww÷ÌÌ÷wwwÿwwwwwww÷wwÿwÿÿ÷÷÷÷÷÷ww÷÷÷w÷ww÷wÿw÷w÷( €€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿw÷w÷ww÷÷w÷ww÷‡wüÌ|Ï÷wÌ÷Ç|ÇwwÈ÷w÷wwÈ|Ç|‡ÌwüÌ|ÇÌÇÌ÷wwÿww÷÷w÷÷w÷‡ww÷wwwwwww÷www|Çwÿw÷wüÇÿww÷ww÷ww÷wwÿwpuzzles-20170606.272beef/icons/pearl.ico0000644000175000017500000006117613115373740016615 0ustar simonsimon 00 ¨%–  ¨>& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeeeeeeeeefffffffffffffffffffffffffffffffffffffffggghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhggghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgggggghhhhhhhhhhhhiiiiiiiiihhhhhhhhhhhhhhhfffffffffffffffffffffgggaaa^^^___^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^bbb___^^^^^^^^^^^^^^^^^^^^^^^^^^^___^^^aaa```^^^^^^___^^^YYYXXXYYY^^^___^^^^^^^^^eeefffffffffffffffgggaaa™™™¶¶¶°°°±±±±±±±±±±±±±±±±±±±±±±±±±±±²²²‘‘‘±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±°°°¶¶¶ššš¡¡¡µµµ¯¯¯···ššš¯¯¯²²²±±±±±±±±±pppdddgggfffffffffhhh^^^¶¶¶äääÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝ©©©ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÛÛÛää丸¸ÃÃÃâââÚÚÚããã¿¿¿ÚÚÚÝÝÝÜÜÜÜÜÜÜÜÜvvvbbbgggfffffffffhhh___°°°ÛÛÛÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔ¤¤¤ÓÓÓÔÔÔÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÒÒÒÚÚÚ²²²¼¼¼ÙÙÙÑÑÑÚÚÚ···ÐÐÐÔÔÔÓÓÓÔÔÔÓÓÓtttbbbgggfffffffffhhh^^^±±±ÜÜÜÓÓÓÕÕÕÕÕÕÒÒÒÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒ¢¢¢ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÓÓÓÕÕÕÕÕÕÔÔÔÜÜܳ³³½½½ÛÛÛÒÒÒÞÞÞ¾¾¾ÙÙÙ×××ÔÔÔÕÕÕÕÕÕuuubbbgggfffffffffhhh^^^±±±ÜÜÜÓÓÓÕÕÕÕÕÕäääæææææææææææææææææææææ²²²åååæææææææææææææææçççÞÞÞÔÔÔÕÕÕÔÔÔÜÜܳ³³½½½ÚÚÚÖÖÖÑÑÑxxx–––ÊÊÊ………‡‡‡ÚÚÚÕÕÕÕÕÕÕÕÕuuubbbgggfffffffffhhh^^^±±±ÜÜÜÓÓÓÕÕÕÔÔÔyyykkknnnmmmmmmmmmmmmnnnUUUmmmnnnmmmmmmmmmoooeee   ÝÝÝÓÓÓÔÔÔÜÜܳ³³½½½ÙÙÙÝÝ݉‰‰ÃÃÃÿÿÿûûûÿÿÿ¦¦¦›››ßßßÓÓÓÕÕÕuuubbbgggfffffffffhhh^^^±±±ÜÜÜÓÓÓÖÖÖÒÒÒhhhæææÑÑÑÔÔÔÜÜܳ³³½½½ÝÝÝÊÊʈˆˆÿÿÿûûûûûûÿÿÿïïï„„„ÙÙÙÔÔÔÕÕÕuuubbbgggfffffffffhhh^^^±±±ÜÜÜÓÓÓÖÖÖÒÒÒjjjæææÑÑÑÔÔÔÜÜܳ³³½½½ÝÝÝÊÊÊŠŠŠÿÿÿûûûüüüÿÿÿòòò„„„ÙÙÙÔÔÔÕÕÕuuubbbgggfffffffffhhh^^^±±±ÜÜÜÓÓÓÖÖÖÒÒÒUUUeeeaaabbbbbbLLLaaabbb```iii///hhhæææÑÑÑÔÔÔÜÜܳ³³½½½ÙÙÙÜÜ܆††ÊÊÊÿÿÿûûûÿÿÿ­­­˜˜˜ßßßÓÓÓÕÕÕuuubbbgggfffffffffhhh^^^±±±ÜÜÜÓÓÓÖÖÖÒÒÒÈÈÈîîîäääæææççç²²²åååæææâââøøøppphhhæææÑÑÑÔÔÔÜÜܳ³³½½½ÚÚÚ×××ÎÎÎwww¤¤¤ÖÖÖ’’’ƒƒƒØØØÕÕÕÕÕÕÕÕÕuuubbbgggfffffffffhhh^^^±±±ÜÜÜÓÓÓÖÖÖÒÒÒµµµØØØÐÐÐÑÑÑÒÒÒ¢¢¢ÑÑÑÑÑÑÍÍÍâââfffhhhæææÑÑÑÔÔÔÜÜܳ³³½½½ÛÛÛÒÒÒßßß¼¼¼××××××ÔÔÔÕÕÕÕÕÕuuubbbgggfffffffffhhh^^^±±±ÜÜÜÓÓÓÖÖÖÒÒÒ¹¹¹ÜÜÜÓÓÓÕÕÕÕÕÕ¥¥¥ÔÔÔÕÕÕÑÑÑæææggggggæææÑÑÑÓÓÓÜÜܳ³³½½½ÚÚÚÓÓÓÛÛÛ¹¹¹ÒÒÒÕÕÕÔÔÔÕÕÕÕÕÕuuubbbgggfffffffffhhh^^^²²²ÝÝÝÓÓÓ×××ÓÓÓ¹¹¹ÝÝÝÔÔÔÕÕÕÖÖÖ¥¥¥ÕÕÕÖÖÖÒÒÒçççhhhhhhçççÒÒÒÔÔÔÝÝݳ³³½½½ÛÛÛÓÓÓÝÝݹ¹¹ÓÓÓ×××ÕÕÕÖÖÖÖÖÖuuubbbgggfffffffffgggbbb‘‘‘©©©¤¤¤¦¦¦£££ªªª¤¤¤¥¥¥¥¥¥ŠŠŠ¥¥¥¥¥¥¢¢¢²²²PPPPPP²²²¢¢¢¤¤¤©©©‘‘‘———¨¨¨£££ªªª£££¦¦¦¤¤¤¥¥¥¥¥¥nnndddffffffffffffhhh___±±±ÜÜÜÒÒÒÕÕÕÒÒÒ¸¸¸ÛÛÛÓÓÓÔÔÔÕÕÕ¥¥¥ÔÔÔÕÕÕÑÑÑåååggggggåååÑÑÑÓÓÓÛÛÛ²²²½½½ÚÚÚÒÒÒÛÛÛ¸¸¸ÒÒÒÕÕÕÔÔÔÕÕÕÕÕÕuuubbbgggfffffffffhhh^^^±±±ÜÜÜÓÓÓÖÖÖÓÓÓ¹¹¹ÜÜÜÔÔÔÕÕÕÖÖÖ¥¥¥ÕÕÕÕÕÕÑÑÑåååggggggåååÑÑÑÔÔÔÜÜܳ³³½½½ÛÛÛÓÓÓÜÜܹ¹¹ÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕuuubbbgggfffffffffhhh^^^±±±ÜÜÜÓÓÓÖÖÖÒÒÒ¹¹¹ÜÜÜÓÓÓÕÕÕÖÖÖ¥¥¥ÔÔÔÕÕÕÐÐÐééénnnnnnéééÐÐÐÔÔÔÜÜܳ³³½½½ÛÛÛÓÓÓÜÜܹ¹¹ÒÒÒÖÖÖÔÔÔÕÕÕÕÕÕuuubbbgggfffffffffhhh^^^±±±ÜÜÜÓÓÓÖÖÖÒÒÒ¹¹¹ÜÜÜÓÓÓÕÕÕÖÖÖ¥¥¥ÔÔÔÔÔÔÖÖÖØØØVVVNNNNNNVVVØØØÖÖÖÓÓÓÜÜܳ³³½½½ÛÛÛÓÓÓÜÜܹ¹¹ÒÒÒÖÖÖÔÔÔÕÕÕÕÕÕuuubbbgggfffffffffhhh^^^±±±ÜÜÜÓÓÓÖÖÖÒÒÒ¹¹¹ÜÜÜÓÓÓÕÕÕÖÖÖ¥¥¥ÔÔÔÕÕÕØØØ}}}ÊÊÊÿÿÿÿÿÿÉÉÉ}}}ØØØÓÓÓÜÜܳ³³½½½ÛÛÛÓÓÓÜÜܹ¹¹ÒÒÒÖÖÖÔÔÔÕÕÕÕÕÕuuubbbgggfffffffffhhh^^^±±±ÜÜÜÓÓÓÖÖÖÒÒÒ¹¹¹ÜÜÜÓÓÓÕÕÕÖÖÖ¥¥¥ÓÓÓÞÞÞ«««¡¡¡ÿÿÿúúúúúúÿÿÿ   «««ÝÝÝÛÛÛ³³³½½½ÛÛÛÓÓÓÜÜܹ¹¹ÒÒÒÖÖÖÔÔÔÕÕÕÕÕÕuuubbbgggfffffffffhhh^^^±±±ÜÜÜÓÓÓÖÖÖÒÒÒ¹¹¹ÜÜÜÓÓÓÕÕÕÖÖÖ¥¥¥ÒÒÒâââ™™™ÂÂÂÿÿÿüüüüüüÿÿÿ™™™áááÚÚÚ³³³½½½ÛÛÛÓÓÓÜÜܹ¹¹ÒÒÒÖÖÖÔÔÔÕÕÕÕÕÕuuubbbgggfffffffffhhh^^^±±±ÜÜÜÓÓÓÖÖÖÒÒÒ¹¹¹ÜÜÜÓÓÓÕÕÕÖÖÖ¥¥¥ÓÓÓÝÝݰ°°šššÿÿÿüüüüüüÿÿÿ™™™°°°ÜÜÜÛÛÛ³³³½½½ÛÛÛÓÓÓÜÜܹ¹¹ÒÒÒÖÖÖÔÔÔÕÕÕÕÕÕuuubbbgggfffffffffhhh^^^±±±ÜÜÜÓÓÓÖÖÖÒÒÒ¹¹¹ÜÜÜÓÓÓÕÕÕÖÖÖ¥¥¥ÔÔÔÔÔÔÛÛÛ„„„´´´ÿÿÿÿÿÿ´´´………ÜÜÜÓÓÓÜÜܳ³³½½½ÛÛÛÓÓÓÜÜܹ¹¹ÒÒÒÖÖÖÔÔÔÕÕÕÕÕÕuuubbbgggfffffffffhhh^^^±±±ÜÜÜÓÓÓÖÖÖÒÒÒ¹¹¹ÜÜÜÓÓÓÕÕÕÖÖÖ¥¥¥ÔÔÔÕÕÕÔÔÔàààUUU......UUUáááÔÔÔÓÓÓÜÜܳ³³½½½ÛÛÛÓÓÓÜÜܹ¹¹ÒÒÒÖÖÖÔÔÔÕÕÕÕÕÕuuubbbgggfffffffffhhh___°°°ÛÛÛÒÒÒÕÕÕÑÑѸ¸¸ÛÛÛÒÒÒÓÓÓÔÔÔ¤¤¤ÓÓÓÔÔÔÏÏÏææællllllæææÏÏÏÒÒÒÛÛÛ²²²¼¼¼ÙÙÙÑÑÑÛÛÛ¸¸¸ÑÑÑÕÕÕÓÓÓÔÔÔÔÔÔtttbbbgggfffffffffhhh^^^¶¶¶äääÚÚÚÝÝÝÙÙÙ¿¿¿ãããÚÚÚÜÜÜÝÝÝ©©©ÛÛÛÜÜÜØØØíííkkkkkkíííØØØÛÛÛãã㸸¸ÃÃÃâââÙÙÙããã¿¿¿ÙÙÙÝÝÝÛÛÛÜÜÜÜÜÜvvvbbbgggfffffffffgggaaaššš¸¸¸±±±´´´±±±›››¹¹¹±±±³³³³³³‘‘‘²²²³³³¯¯¯ÁÁÁWWWWWWÁÁÁ¯¯¯²²²¸¸¸›››¢¢¢···±±±¹¹¹›››±±±´´´²²²³³³³³³pppcccgggfffffffffggg```¡¡¡ÃÃû»»¾¾¾»»»¤¤¤ÃÃü¼¼½½½½½½———½½½½½½ºººÌÌÌ\\\\\\ÌÌ̺ºº¼¼¼ÃÃ⢢ªªªÁÁÁ»»»ÃÃ䤤»»»¾¾¾¼¼¼½½½½½½qqqcccgggfffffffffhhh^^^µµµâââØØØÜÜÜØØØ½½½âââÙÙÙÛÛÛÛÛÛ¨¨¨ÚÚÚÛÛÛ×××ìììjjjjjjììì×××ÙÙÙâââ···ÁÁÁáááØØØâââ¾¾¾ØØØÜÜÜÚÚÚÛÛÛÛÛÛuuubbbgggfffffffffhhh___±±±ÛÛÛÒÒÒÔÔÔÐÐз··ÚÚÚÓÓÓÔÔÔÕÕÕ¤¤¤ÔÔÔÔÔÔÐÐÐåååggggggåååÐÐÐÓÓÓÛÛÛ²²²¼¼¼ÚÚÚÒÒÒÛÛÛ¸¸¸ÒÒÒÕÕÕÓÓÓÔÔÔÔÔÔuuubbbgggfffffffffhhh^^^¯¯¯ÙÙÙÏÏÏÖÖÖØØØ½½½ßßßÒÒÒÕÕÕÖÖÖ¥¥¥ÔÔÔÕÕÕÑÑÑæææhhhfffãããÎÎÎÐÐÐÙÙÙ°°°ººº×××ÏÏÏÙÙÙ¶¶¶ÒÒÒÖÖÖÔÔÔÕÕÕÕÕÕuuubbbgggfffffffffhhh___½½½ëëëâââáááWWW:::ÎÎÎØØØÔÔÔÖÖÖ¥¥¥ÔÔÔÕÕÕÑÑÑæææhhhoooööößßßâââëëë¿¿¿ÊÊÊéééáááëëëÅÅÅÒÒÒÖÖÖÔÔÔÕÕÕÕÕÕuuubbbgggfffffffffiiiZZZ999FFFGGG777gggáááÒÒÒÕÕÕ¥¥¥ÔÔÔÕÕÕÑÑÑæææhhh!!!JJJCCCDDDGGG:::===FFFDDDGGG<<<ÒÒÒÖÖÖÔÔÔÕÕÕÕÕÕuuubbbgggffffffeeeiiiYYY(((ÚÚÚÔÔÔÕÕÕ¥¥¥ÔÔÔÕÕÕÑÑÑæææiiiÒÒÒÖÖÖÔÔÔÕÕÕÕÕÕuuubbbgggffffffeeeiiiYYY555ÜÜÜÔÔÔÕÕÕ¥¥¥ÔÔÔÕÕÕÑÑÑæææhhhÒÒÒÖÖÖÔÔÔÕÕÕÕÕÕuuubbbgggfffffffffhhh\\\sssŽŽŽŽŽŽyyyŠŠŠàààÒÒÒÖÖÖ¥¥¥ÔÔÔÕÕÕÔÔÔÛÛÛ¯¯¯………ŒŒŒ‹‹‹‹‹‹‹‹‹ŠŠŠttt{{{ŽŽŽŠŠŠ‹‹‹‹‹‹‹‹‹‰‰‰“““ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕuuubbbgggfffffffffhhh___½½½ëëëáááèèè“““!!!zzzÛÛÛÔÔÔÕÕÕÖÖÖ¥¥¥ÔÔÔÕÕÕÕÕÕÔÔÔÝÝÝåååãããäääääääääâââëëë¿¿¿ÊÊÊêêêãããääääääääääääâââÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕuuubbbgggfffffffffhhh^^^®®®ÙÙÙÐÐÐÑÑÑßßßÑÑÑ»»»ËËËàààÔÔÔÕÕÕÕÕÕÕÕÕ¥¥¥ÔÔÔÕÕÕÕÕÕÕÕÕÓÓÓÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÐÐÐØØØ°°°ººº×××ÑÑÑÒÒÒÒÒÒÒÒÒÑÑÑÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕuuubbbgggfffffffffhhh^^^±±±ÜÜÜÔÔÔÕÕÕÓÓÓ×××ÜÜÜØØØÓÓÓÕÕÕÕÕÕÕÕÕÖÖÖ¥¥¥ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÜÜܳ³³½½½ÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕuuubbbgggfffffffffhhh^^^±±±ÜÜÜÓÓÓÕÕÕÕÕÕÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖ¥¥¥ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÜÜܳ³³½½½ÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕuuubbbgggffffffffffffeeepppvvvtttuuuuuuuuuuuuuuuuuuuuuuuuuuuuuunnnuuuuuuuuuuuuuuuuuuuuuuuuuuuuuutttvvvppprrruuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuhhhfffffffffffffffffffffdddbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbdddbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbccccccbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbffffffffffffffffffffffffgggggggggggggggggggggggggggggggggggggggfffggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggggffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff( @ ffffffhhhhhhhhhhhhhhhhhhhhhhhhhhhggghhhhhhhhhhhhhhhhhhhhhhhhggghhhhhhhhhgggfffhhhhhhhhhhhhffffffffffff___^^^^^^^^^^^^^^^^^^^^^^^^```^^^^^^^^^^^^^^^^^^^^^^^^```^^^^^^^^^dddfff```^^^^^^___ffffffffffffžžžªªª§§§§§§§§§§§§§§§¨¨¨¤¤¤•••ªªª§§§§§§§§§§§§§§§§§§ªªª•••£££¨¨¨©©©***¯¯¯¨¨¨žžžffffffffffffÍÍÍáááÜÜÜÝÝÝÜÜÜÜÜÜÜÜÜÞÞÞÖÖÖºººàààÛÛÛÜÜÜÜÜÜÜÜÜÝÝÝÜÜÜááá»»»ÖÖÖÞÞÞààà)))¤¤¤èèèÞÞÞÍÍÍffffffffffffÄÄÄ×××ÒÒÒÕÕÕÖÖÖÖÖÖÖÖÖ×××ÐÐж¶¶ÙÙÙÕÕÕÖÖÖÖÖÖÕÕÕÓÓÓÒÒÒ×××´´´ÍÍÍÕÕÕØØØ$$$œœœáááÔÔÔÄÄÄffffffffffffÆÆÆÙÙÙÕÕÕÐÐÐÌÌÌÍÍÍÌÌÌÎÎÎÇÇÇ®®®ÐÐÐÌÌÌÍÍÍÌÌÌÍÍÍÕÕÕÔÔÔÙÙÙµµµÎÎÎÛÛÛŸŸŸ³³³ÐÐД””ÈÈÈÜÜÜÅÅÅffffffffffffÆÆÆÕÕÕãããggg +++ÓÓÓÕÕÕØØØµµµÕÕÕ¾¾¾´´´ÿÿÿÿÿÿâââ   àààÄÄÄffffffffffffÆÆÆÕÕÕäää\\\ÓÓÓÕÕÕØØØ´´´ÖÖÖººº»»»ÿÿÿÿÿÿêêêžžžàààÄÄÄffffffffffffÆÆÆÕÕÕäää```UUU¿¿¿°°°­­­———³³³ºººÓÓÓÕÕÕØØØµµµÏÏÏØØØ™™™ÖÖÖööö¡¡¡½½½ÞÞÞÅÅÅffffffffffffÅÅÅÔÔÔããã```gggíííÛÛÛÖÖÖ¼¼¼ÞÞÞæææ®®®ÒÒÒÔÔÔØØØµµµÍÍÍØØØÑÑÑ,,,”””âââÕÕÕÅÅÅffffffffffffÈÈÈØØØçççaaadddæææÔÔÔÐÐж¶¶×××ßßß©©©ÖÖÖØØØÛÛÛ···ÑÑÑÙÙÙÜÜÜ)))¢¢¢âââÙÙÙÈÈÈffffffffffffªªª´´´ÁÁÁQQQUUU²²²°°°žžžµµµ¼¼¼ŽŽŽ²²²µµµ···žžž°°°µµµ¶¶¶!!!………¾¾¾µµµªªªffffffffffffÂÂÂÑÑÑààà^^^bbbáááÏÏÏËË˲²²ÒÒÒÚÚÚ¤¤¤ÎÎÎÑÑÑÔÔÔ²²²ËËËÒÒÒÔÔÔ&&&›››ÜÜÜÒÒÒÂÂÂffffffffffffÇÇÇÖÖÖååå```dddæææÔÔÔÐÐж¶¶×××àà௯¯ÙÙÙÕÕÕÙÙÙ¶¶¶ÐÐÐ×××ÙÙÙ'''žžžááá×××ÇÇÇffffffffffffÆÆÆÕÕÕäää```dddåååÓÓÓÏÏϵµµØØØÚÚÚoookkk¯¯¯ÛÛÛ×××µµµÏÏÏÖÖÖØØØ'''žžžàààÖÖÖÆÆÆffffffffffffÆÆÆÕÕÕäää```dddåååÓÓÓÏÏÏ´´´ààବ¬ÁÁÁÿÿÿÿÿÿ¥¥¥ÃÃÃÝÝݵµµÏÏÏÖÖÖØØØ'''žžžàààÖÖÖÆÆÆffffffffffffÆÆÆÕÕÕäää```dddåååÓÓÓÏÏÏ´´´àààéééûûûÿÿÿÅÅů¯¯ááá´´´ÏÏÏÖÖÖØØØ'''žžžàààÖÖÖÆÆÆffffffffffffÆÆÆÕÕÕäää```dddåååÓÓÓÏÏÏ´´´àà௯¯»»»ÿÿÿýýý¡¡¡ÇÇÇÜÜܵµµÏÏÏÖÖÖØØØ'''žžžàààÖÖÖÆÆÆffffffffffffÅÅÅÔÔÔããã___cccäääÒÒÒÎÎεµµÖÖÖÜÜÜVVVYYY´´´ÚÚÚÖÖÖµµµÎÎÎÕÕÕ×××&&&ßßßÕÕÕÅÅÅffffffffffffÊÊÊÚÚÚééébbbfffêêêØØØÓÓÓ¹¹¹ÛÛÛããã²²²ÜÜÜÙÙÙÝÝݹ¹¹ÓÓÓÛÛÛÝÝÝ'''¡¡¡åååÛÛÛÊÊÊffffffffffff³³³¿¿¿ÍÍÍVVVZZZÎÎξ¾¾»»»¦¦¦ÁÁÁÈÈÈ———½½½ÀÀÀ¦¦¦»»»ÁÁÁÂÂÂ###ŽŽŽÊÊÊÀÀÀ³³³ffffffffffffµµµÁÁÁÏÏÏVVVZZZÐÐп¿¿¼¼¼§§§ÂÂÂÊÊÊ™™™¿¿¿ÂÂÂÄÄħ§§¼¼¼ÂÂÂÄÄÄ###ÌÌ̵µµffffffffffffÇÇÇ×××çççdddhhhééé×××ÓÓÓ¸¸¸ÛÛÛãã㬬¬ÕÕÕ×××ÚÚÚ¶¶¶ÐÐÐØØØÚÚÚ'''¡¡¡åååÛÛÛÊÊÊffffffeeegggÐÐÐáááëëëVVV[[[çççÒÒÒÎÎεµµÖÖÖÞÞÞ¨¨¨ÝÝÝàààããã¾¾¾ÙÙÙáááããã(((ßßßÕÕÕÅÅÅffffffgggaaa“““¬¬¬xxx“““áááÌÌ̵µµÖÖÖÞÞÞ¨¨¨   ¡¡¡¤¤¤‰‰‰œœœ¢¢¢£££žžžàààÖÖÖÆÆÆffffffkkkRRR;;;áááÍÍ͵µµÖÖÖÞÞÞ§§§œœœàààÖÖÖÆÆÆffffffjjjUUU'''PPPãããÌÌ̵µµ×××ÝÝÝ®®®#########$$$"""#########¥¥¥ÞÞÞÖÖÖÆÆÆffffffffffffÅÅÅßß߸¸¸,,,///¾¾¾ÜÜÜÍÍ͵µµÙÙÙÔÔÔÕÕÕÖÖÖÖÖÖÖÖÖÕÕÕÚÚÚ¶¶¶ÐÐÐØØØÖÖÖÖÖÖÖÖÖÕÕÕÔÔÔÙÙÙÆÆÆffffffffffffÆÆÆ×××ÛÛÛÕÕÕ»»»ÖÖÖÚÚÚÕÕÕÏÏϵµµØØØÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÔÔÔØØØµµµÎÎÎÖÖÖÔÔÔÕÕÕÕÕÕÔÔÔÔÔÔØØØÅÅÅffffffffffffÈÈÈÜÜÜÖÖÖÙÙÙßßßÙÙÙ×××ÚÚÚÒÒÒ¸¸¸ÜÜÜØØØØØØØØØØØØØØØ×××ÜÜܸ¸¸ÒÒÒÚÚÚØØØØØØØØØØØØØØØÜÜÜÉÉÉffffffffffffyyy}}}||||||{{{|||||||||{{{vvv}}}||||||||||||||||||}}}vvv{{{||||||||||||||||||}}}yyyffffffffffffaaa```aaaaaaaaaaaaaaaaaaaaabbb```aaaaaaaaaaaaaaaaaa```bbbaaaaaaaaaaaaaaaaaaaaa```aaaffffff(  fffcccbbbaaaaaabbbbbbaaabbbccccccbbbfffccccccfffiii±±±¾¾¾¾¾¾ÀÀÀ²²²½½½¿¿¿½½½¸¸¸°°°¹¹¹œœœ¹¹¹hhhjjjÎÎÎÛÛÛÍÍÍÏÏϽ½½ËËËÎÎÎÖÖÖØØØÍÍÍÎÎÎcccºººÓÓÓiiigggÑÑÑžžž{{{ßßßÁÁÁ½½½þþþÈÈÈÀÀÀlllgggØØØ“““ ÅÅŨ¨¨ÈÈÈ;;;jjjçççÆÆÆÉÉÉ{{{ºººÎÎÎiiigggÉÉɆ††'''ÙÙÙ»»»ÜÜÜFFFaaaÕÕÕ¸¸¸ÅÅŦ¦¦ÄÄÄhhhgggÑÑÑŒŒŒ%%%ÙÙÙºººÞÞÞBBBcccßßß¾¾¾ËËˬ¬¬ËËËhhhgggØØØ‘‘‘'''âââÇÇÇÊÊʶ¶¶···ÎÎÎÉÉÉÒÒÒ²²²ÒÒÒhhhgggÖÖÖ&&&àààÈÈÈ»»»íííàààÀÀÀËËËÐÐа°°ÑÑÑhhhgggÖÖÖ&&&àààÁÁÁÞÞÞ\\\vvvßßßÄÄÄÑÑѰ°°ÑÑÑhhhgggÃÃÄ„„%%%ÏÏϲ²²ÓÓÓBBB^^^ÐÐв²²½½½¢¢¢ÁÁÁhhhhhhèèè”””$$$ãããÀÀÀäääHHHsss÷÷÷ÔÔÔããã±±±ÑÑÑhhh\\\CCC›››ÍÍÍßßßPPPHHH<<<???´´´ÐÐÐhhh```lll::: ¬¬¬ÍÍÍ×××   kkkjjjccclllwwwËËËÌÌÌiiikkkØØØÙÙÙÆÆÆÙÙÙÁÁÁÎÎÎÛÛÛäääáááÓÓÓåååààà×××ÄÄÄjjjfffpppvvvyyytttsssuuusssrrrrrrppprrrrrruuutttggg(0` fffeeeggghhhiiiaaa^^^___bbb```YYYXXX™™™¶¶¶°°°±±±²²²‘‘‘ššš¡¡¡µµµ¯¯¯···pppdddäääÛÛÛÜÜÜÝÝÝ©©©¸¸¸ÃÃÃâââÚÚÚããã¿¿¿vvvÒÒÒÓÓÓÔÔÔ¤¤¤¼¼¼ÙÙÙÑÑÑÐÐÐtttÕÕÕ¢¢¢³³³½½½ÞÞÞ¾¾¾×××uuuæææåååçççÖÖÖxxx–––ÊÊÊ………‡‡‡yyykkknnnmmmUUUooo   ‰‰‰ÿÿÿûûû¦¦¦›››ßß߈ˆˆïïï„„„jjjŠŠŠüüüòòòLLL///†††­­­˜˜˜ÈÈÈîîîøøøÎÎÎwww’’’ƒƒƒØØØÍÍ͹¹¹¥¥¥£££ªªªPPP———¨¨¨éééVVVNNN}}}ÉÉÉ«««úúúÂÂÂááá´´´ààà...ÏÏÏlllíííÁÁÁWWWccc»»»ºººÌÌÌ\\\qqqìììëëë:::öööÅÅÅZZZ999FFFGGG777!!!JJJCCCDDD===<<<(((555sssŽŽŽŒŒŒ‹‹‹{{{“““èèèzzzêêê®®®ËËËrrr      !"#$%&'$()*********+,*+********)$-./$012+*+*3*44)//////)5///////*44+67)89:.;+44<*44=======>=====?8+4+67$@/ABCDE$444<*4+FGHIIIIHJIHIIIKL*+67.M"NONPQR*4<*@):0=/+67CSNOONTU.+4<*@)1VWXY=/+67CZNO[N\U.+4<*@):J] ^=/+67._CNON`aR*4<*@):bc=?>=#d=/+67$;ef,@ghi444<*@):i2/)5//j#=/+67)R-k;;+44<*@):l*44m+4/==/*67$*ln1)4+44<*;*:l+4@m4@)??)+67*l:*;4@@< ,Popqr,mmZmm5ss5, tuorqpoP,mmH)4):!*+4m+4/>>/*7$)!:)4+44<*@*:l+4@m44/>>/+67*l:*@444<*@):l*4@m+42vHHv2+67*l:)@+44<*@):l*4@m++@iwxxwi@*67*l:)@+44<*@):l*4@m+4iyCNNzyi*67*l:)@+44<*@):l*4@m*8{N||NL{67*l:)@+44<*@):l*4@m)# }N[[N} ~$67*l:)@+44<*@):l*4@m*N[[N 67*l:)@+44<*@):l*4@m++UNND*67*l:)@+44<*@):l*4@m+4+€JJ~+*67*l:)@+44<)4/:!)*+,*+‚=ƒƒ=‚)-./!:/4*++3 $.'&%$ i„GG„i%!"#.%&'.(!Ql666…††…!Q5lQ66‡ "ˆ9ˆ‰,"-77t77Š‹ŒŒ‹Š-"5r…ˆ",‰ˆ9-77‡#ii'7#.u$;ŽYYŽ;.#…~i#9'i$<)+2'W$*+4,++2>>2*-$)!:)4*++<.‚@i7R)4@m+4/=%e2.Š;‚. :)@+44<7#~†n‘ei+@m+4/=K’R#&Cv~“:)@+44<”•–—˜n~)4m+4/=™š›œ—‘–œ—ž:)@+44< WWŸ$+4m+4/=XWV1)@+44< WW0 +4m+4/=0:)@+44<Œ¡¢¢FXZ€)@m+4+D£¤¤¤Zq3¥¢Z¤¤¤M¦+4444<7~§¦™n¨+4@m+44+>%#&C©%#44444<ª.2/R/ˆ«€+444m+444*/))))2iŠ;/)))/)44444<+4*;i*444@m4444444444+67+4444444444<*44+++4444@m4444444444+67+4444444444<(3<<<<<<<<<?@'#)2#A(BBCD -#EF9G'#)(BBH -#EIJKLM4NO'#)2P)QRST77,8UVW1X",)2)YZ95C#76)[\W,$%!]O)^Y&_C&6(`aIbcK2Vdec2^K2%fgA2bYhPic"j k/Y,ci",lm"b0nW,$%!o&#&%$!&p!0-#En'P2)jqrs!2P)p--#En'P(t`BBuv2P)p--#En'P(wxyB7(P)p--#En'P(BzS02P)p-7,8{E"/2|}~(j2/#!lw]#7jxhH)'€8ck&€'pSn4J}/A‚`6MXTƒb‚`b„dƒ42`P}$JV bQ…Jb Vb „q.b20![x!'†8tO#!j%$)jpSn‡$ˆ}‰["/2 o8A&8Šw]#7\‹tŒ‹.2 DS Ž+_ k-s‘2 ’+-“IOp;”8.2!1G„„„*o•„„„eu-7]†Z–A2&,##j%$)#,&--!#j#P2),,###,)2/,##,,)76&]&!j"†)))))!†"j)))))—˜™šš›ššš›œ™šššššš™œ›šššššš™˜\\\\\\\\h\\\\\\h\\\\\\\\( fffcccbbbaaaiii±±±¾¾¾ÀÀÀ²²²½½½¿¿¿¸¸¸°°°¹¹¹œœœhhhjjjÎÎÎÛÛÛÍÍÍÏÏÏËËËÖÖÖØØØºººÓÓÓgggÑÑÑžžž{{{ßßßÁÁÁþþþÈÈÈlll“““ ÅÅŨ¨¨;;;çççÆÆÆÉÉɆ††'''ÙÙÙ»»»ÜÜÜFFFÕÕÕ¦¦¦ÄÄÄŒŒŒ%%%ÞÞÞBBB¬¬¬‘‘‘âââÇÇÇÊÊʶ¶¶···ÒÒÒ&&&àààíííÐÐÐ\\\vvvÃÃÄ„„^^^¢¢¢èèè”””$$$ãããäääHHHsss÷÷÷ÔÔÔCCC›››PPP<<<???´´´```::: ×××   kkkwwwÌÌÌáááåååpppyyytttuuurrr    !"#$% &'()*+,'-./0#01234567 +89:;3<=$>?@2ABCDE0F!FGHI'4JIK GHI%^_$`QXabcKd(ef?ghi(jki3/3%WlmIg9nMopYqYrrnrrqp(0`€€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwxwwww÷ÿw÷÷÷ÿ÷ÿÿÿ÷÷÷øÿ÷÷wÿ÷÷ÿw÷÷÷w÷øww÷÷ÿ÷÷ÿ÷÷÷÷ø÷÷wÿ÷w÷www÷w÷÷÷ø÷ww÷÷ÿÿÿÿÿÿÿÿwwÿˆÿx÷÷w÷xˆ€ˆ€ˆ€ˆˆ÷ÿÿw÷ÿ÷ww÷p÷÷÷÷ÿ÷ww÷wÿÿp÷wxÿÿ‡ÿww÷pÿ÷ÿ÷÷ÿw÷÷w÷÷pÿ÷ÿÿ÷w‡ÿøww÷pÿ€÷wÿø÷÷÷w÷ð÷÷÷w÷ÿw÷ø÷ww÷p÷wÿw÷ø÷÷wÿ÷p÷ÿ€÷÷÷ÿ÷øÿwwwwp‡÷ww÷w€÷w÷wwø÷wwwÿðw÷÷ÿ÷wÿ÷x÷÷÷w÷ÿpÿ÷€ÿ÷÷wøwwwpw÷÷÷÷÷÷÷÷wÿp‡÷÷÷øÿ÷w÷p÷ÿÿø‡x÷÷ø÷wpww÷xÿÿ‡÷wøwww÷ÿpwÿÿw÷÷÷ÿøÿ÷÷wÿp÷÷‡÷ÿøø÷ww÷p÷÷ÿÿ÷÷÷÷÷øÿ÷÷w÷p÷÷wÿwÿÿw÷w÷x÷÷w÷÷pw÷‡ˆ÷wð÷w÷€÷ÿw÷x÷w÷÷p÷÷øwwÿp÷÷ÿÿÿ÷÷ø÷ww÷wpw÷w÷€ww÷w÷øw÷wwp÷÷ww÷€w÷wø÷wwÿÿpÿ÷÷÷ø÷÷p÷÷ÿ÷÷wøÿww÷÷pw÷ÿ÷÷÷ÿø÷÷÷wp÷÷÷÷€÷÷÷øÿ÷wÿ÷÷ÿÿ÷÷ø÷wp÷w÷÷wpÿ€÷÷€÷÷ÿ÷÷÷xˆˆˆˆˆˆˆˆˆˆˆ‡÷w÷÷÷÷÷ÿÿ÷ÿÿ÷ÿÿÿÿ÷wwwøˆ÷÷w÷ww÷ww÷w÷÷ÿ÷wÿÿw÷÷ÿw÷÷ÿÿww÷÷ÿÿw÷÷ÿÿ÷÷÷÷÷ww÷÷w÷w÷ww÷÷w÷÷÷wwwwwwwwwwwwwwwwwwwwwwwww( @€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿˆ€ˆˆ€ˆ€ˆˆˆwwwwxwwwwxwpwx÷÷w÷÷÷wpx‡÷w÷wwww÷wp÷x÷www÷ÿww÷‡xwx‡wð€wø÷x‡pww÷÷ÿwx÷p‡ˆˆ€wwwx‡wpÿwpwˆˆwx‡ÿp÷w÷pwwwp÷xw€wxwpwwwpwxˆwpwwwp÷‡w€wx‡p÷wpwp÷x‡÷€÷wp÷wpx÷pwww‡xwwpx‡p÷w÷÷÷w÷pwxpwø÷wwwwp÷x‡€÷ww÷wpwx‡wpw÷ˆˆ÷wpwx‡ÿpwwpw÷p÷øwpwwwpwwwpwx‡w€www€wxwpwx‡p÷wÿpÿwÿp÷xwpwwwpwwwpwx‡÷€ww÷pww÷px€w÷pˆ÷x€‡wwp÷xˆˆw÷xˆˆˆˆˆ‡wxxw÷ÿwÿ÷÷x‡÷ww÷xwww÷wwwxˆ÷wwwwxwwwwww÷wˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ( €€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿˆˆˆˆˆˆˆˆw‡xw‡x‡wx÷ww‡x‡€w÷x‡pwx‡w‡pˆ€wx‡wx‡€wð‡wxˆ÷wwø‡€÷w÷x‡ˆ÷x‡wx‡€wp‡wx€÷øx‡ðxˆwwˆˆ‡x‡wwwwxˆˆˆˆˆˆˆˆpuzzles-20170606.272beef/icons/pattern.ico0000644000175000017500000006117613115373740017167 0ustar simonsimon 00 ¨%–  ¨>& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $ææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææåååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææçççéééééééééééééééééééééééééééééééééééééééèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææçççâââÚÚÚÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÙÙÙÚÚÚÚÚÚÚÚÚÙÙÙÛÛÛààààààààààààààààààßßßàààààààààààààààáááæææææææææææææææææææææææææææææææææææææææææææææãããåååææææææäääñññªªªbbb{{{||||||{{{rrr}}}||||||{{{€€€iii###+++!!!cccñññäääææææææææææææææææææææææææææææææææææææéééóóóìììåååæææãããòòò¤¤¤___‡‡‡€€€rrr€€€€€€†††fffRRRóóóãããæææææææææææææææææææææææææææææææææçççßßß–––»»»îîîåååäääòòò¥¥¥aaa†††€€€€€€sss€€€€€€………gggSSSóóóãããææææææææææææææææææææææææææææææãããñññ£££ŸŸŸóóóãããäääòòò¥¥¥```†††€€€€€€rrr€€€€€€………fffRRRóóóãããææææææææææææææææææææææææææææææææææææèèèkkkÃÃÃîîîåååäääòòò¥¥¥___„„„}}}~~~~~~}}}sssƒƒƒ‚‚‚‡‡‡hhhTTTóóóãããææææææææææææææææææææææææææææææææææææçççìììæææææææææäääòòò¤¤¤eeeˆˆˆ‰‰‰‰‰‰ˆˆˆqqqxxxxxxxxxwww}}}aaaRRRóóóãããææææææææææææææææææåååäääææææææææææææåååâââåååææææææäääñññ©©©>>>JJJGGGGGGIIIAAAppp£££››››››£££|||ZZZmmmiiiiiikkkcccƒƒƒëëëåååæææææææææææææææåååíííñññçççææææææåååéééòòòëëëåååæææäääððð®®®‹‹‹ÿÿÿûûûÿÿÿüüüÿÿÿ»»»»»»ÿÿÿüüüÿÿÿþþþÿÿÿÉÉÉàààçççææææææææææææåååéééÃÃò²²âââçççåååéééØØØ¬¬¬ÐÐÐêêêåååäääððð®®®‹‹‹ÿÿÿùùùýýýúúúÿÿÿººº¹¹¹ÿÿÿøøøûûûúúúÿÿÿÇÇÇáááçççææææææææææææäääòòò¡¡¡[[[ìììååååååèèèÝÝÝLLL¿¿¿íííåååäääððð®®®‹‹‹ÿÿÿûûûÿÿÿüüüÿÿÿ»»»»»»ÿÿÿüüüÿÿÿþþþÿÿÿÉÉÉàààçççææææææææææææäääòòò›››~~~÷÷÷ãããåååéé騨Ø]]]ÞÞÞéééæææäääððð®®®ŠŠŠÿÿÿùùùýýýúúúÿÿÿººººººÿÿÿúúúýýýüüüÿÿÿÈÈÈàààçççææææææææææææåååêêêÂÂÂÊÊÊêêêååååååééé××׺ººåååææææææäääððð®®®‹‹‹ÿÿÿûûûÿÿÿüüüÿÿÿ»»»»»»ÿÿÿüüüÿÿÿþþþÿÿÿÉÉÉàààçççæææææææææææææææåååîîîìììåååææææææåååéééïïïæææææææææäääððð­­­ |||åååÔÔÔ×××ÕÕÕââ⢢¢¢¢¢âââÕÕÕ××××××ÙÙÙ···ãããçççææææææææææææææææææååååååæææææææææææææææäääåååææææææäääððð­­­  TTTóóóãããæææææææææææææææææææææææææææææææææçççãããåååíííåååæææäääððð®®®RRRóóóãããææææææææææææææææææææææææææææææåååëëëÎÎÎlll°°°ðððääääääððð®®®SSSóóóãããææææææææææææææææææææææææææææææäääïïï¹¹¹CCC­­­ñññääääääððð®®®RRRóóóãããææææææææææææææææææææææææææææææäääïïﺺºnnnØØØéééåååäääððð®®®RRRóóóãããæææææææææææææææææææææææææææææææææåååìììòòòæææææææææäääððð®®®  TTTóóóãããææææææææææææææææææææææææææææææææææææäääàààåååææææææäääñññ¨¨¨HHH[[[WWWXXXXXXWWWUUUXXXXXXXXXWWWZZZNNN [[[òòòãããæææææææææææææææææææææææææææææææææåååêêêóóóêêêåååæææäääòòò¤¤¤eeeŽŽŽ†††‡‡‡ˆˆˆ†††xxx‰‰‰‡‡‡‡‡‡†††kkkRRRóóóãããææææææææææææææææææææææææææææææåååêêêÑÑÑ›››ÔÔÔêêêåååäääòòò¥¥¥___„„„~~~~~~}}}qqq~~~~~~}}}„„„eeeSSSóóóãããææææææææææææææææææææææææææææææäääìììÉÉÉOOOšššôôôãããäääòòò¥¥¥```†††€€€€€€rrr€€€€€€………fffRRRóóóãããææææææææææææææææææææææææææææææãããòòò©©©BBBÐÐÐëëëåååäääòòò¥¥¥```†††€€€€€€~~~rrr€€€~~~………fffSSSóóóãããæææææææææææææææææææææææææææææææææçççâââÑÑÑàààçççæææäääòòò¥¥¥bbbŠŠŠ‚‚‚ƒƒƒ„„„‚‚‚uuu„„„ƒƒƒƒƒƒ‚‚‚‰‰‰iiiRRRóóóãããææææææææææææææææææææææææææææææææææææçççëëëçççææææææäääñññ§§§KKK```\\\]]]]]]\\\XXX]]]\\\]]]\\\^^^TTT111222222222111444888111222222444'''iiiðððäääæææææææææææææææææææææææææææææææææææææææåååææææææææææææèèèÝÝÝÊÊÊËËËÊÊÊÊÊÊÊÊÊÊÊÊËËËÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÌÌÌÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÒÒÒÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÒÒÒ×××çççææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææèèèíííììììììììììììììììììììììììììììììììììììëëëëëëëëëëëëëëëëëëëëëëëëëëëëëëêêêëëëêêêæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææåååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææääääääææææææææææææææææææçççææææææææææææççççççææææææææææææçççæææåååææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææñññðððèèèæææææææææææææææâââçççææææææåååäääååååååææææææçççâââèèèêêêåååæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææ¬¬¬lllÝÝÝèèèãããððð´´´KKKÌÌÌëëëååååååîîî{{{{{{îîîåååäääììì°°°hhhÐÐÐëëëåååææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææåååêêêddd999áááèèèåååçççáááddd¯¯¯ñññäääãããõõõ‹‹‹———öööãããåååêêêÐÐÐ>>>ÃÃÃîîîåååææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææåååîîîÍÍÍŠŠŠìììååååååëëëÊÊÊzzzÆÆÆíííäääåååêêêŠŠŠ¹¹¹ïïïääääääííí¹¹¹{{{ÝÝÝéééåååæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææåååêêêñññåååæææææææææéééñññìììåååææææææåååðððëëëåååæææææææææêêêòòòèèèåååæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææãããáááææææææææææææäääàààäääææææææææææææããããããææææææææææææãããàààåååææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææðððñññæææææææææåååííí÷÷÷éééåååæææææææææêêêïïïåååææææææåååðððõõõçççæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææèèè««««««çççæææäääíííÁÁÁƒƒƒÑÑÑêêêåååæææéééÓÓÓ´´´êêêåååäääîî¬ŒŒŒÝÝÝèèèåååææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææåååëëë®®®EEEÝÝÝéééäääëëëÐÐÐQQQÀÀÀîîîãããêêê×××GGGQQQìììåååäääîîîµµµTTTÙÙÙéééåååææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææäääïïœUUUçççæææåååêêêÓÓÓbbb­­­òòòääääääððð€€€tttõõõãããåååêêêÁÁÁYYYËËËíííåååæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææçççÕÕÕÜÜÜçççææææææèèèÜÜÜÏÏÏéééæææææææææèèèåååÛÛÛçççææææææéééÕÕÕÕÕÕêêêåååæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææêêêéééææææææææææææèèèëëëææææææææææææææææææéééæææææææææåååêêêêêêåååææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææååååååæææææææææææææææåååææææææææææææææææææåååæææææææææææææææåååæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææ( @ æææææææææææææææææææææææææææææææææçççèèèèèèèèèèèèèèèèèèèèèèèèèèèçççççççççççççççççççççççççççæææææææææææææææææææææææææææåååæææææææææãããßßßßßßßßßßßßßßßßßßßßßßßßáááäääääääääääääääääääääääääääææææææææææææææææææææææææèèèìììæææäääïï˜www………ƒƒƒ€€€|||ƒƒƒˆˆˆeee$$$"""&&&+++!!!%%%^^^ðððäääæææææææææææææææçççÞÞÞËËËçççäääðððŽŽŽqqq‚‚‚€€€{{{vvv€€€}}}†††WWW FFFòòòãããææææææææææææäääòòò•••ZZZðððâââðððqqq‚‚‚{{{yyyƒƒƒ€€€‰‰‰ZZZ JJJñññãããææææææææææææåååêêêÖÖÖ¶¶¶ëëëãããððð‘‘‘zzz‹‹‹‰‰‰………uuu{{{xxxUUU GGGòòòãããæææææææææææææææåååéééïïïåååäääñññIIIWWWUUUPPP„„„–––¡¡¡jjj IIITTTTTTKKKvvvìììåååæææåååååååååææææææääääääæææãããóó󆆆ÂÂÂÿÿÿøøøÿÿÿ£££ÆÆÆÿÿÿûûûÿÿÿÙÙÙàààèèèåååììì„„„ÅÅÅìììííí¼¼¼ŠŠŠîîîâââòòò†††ÁÁÁÿÿÿ÷÷÷ÿÿÿ¢¢¢ÃÃÃÿÿÿøøøÿÿÿÖÖÖàààèèèåååêêꆆ†ÕÕÕéééïïï···šššóóóáááóó󆆆ÂÂÂÿÿÿøøøÿÿÿ£££ÆÆÆÿÿÿûûûÿÿÿÙÙÙàààèèèæææåååßßßææææææçççßßßáááçççãããòòò†††¿¿¿ÿÿÿôôôÿÿÿ¡¡¡ ÃÃÃÿÿÿ÷÷÷ÿÿÿÖÖÖàààèèèææææææèèèææææææåååëëëïïïåååãããòòò‡‡‡ &&&"""######$$$ &&&"""%%%[[[ïïïäääææææææææææææåååéééÔÔÔÃÃÃèèèãããóó󆆆   GGGòòòãããææææææææææææäääòòòžžžhhhîîîâââòòò††† HHHòòòãããææææææææææææåååííí¼¼¼¶¶¶ìììâââóó󆆆   GGGòòòãããæææææææææææææææåååîîîíííåååäääòòòŠŠŠ)))555222444666222222444...   OOOñññãããææææææææææææææææææäääèèèçççäääððð‘‘‘zzz‹‹‹‰‰‰„„„ŠŠŠ†††^^^ HHHòòòãããææææææææææææåååîîî···†††ëëëãããðððppp~~~zzzvvv|||………WWW GGGòòòãããææææææææææææäääòòòœœœ€€€ðððâââððð’’’wwwˆˆˆ………|||†††‚‚‚ŒŒŒ[[[ HHHòòòãããæææææææææææææææçççââââââçççãããñññ‰‰‰^^^ooollliiieeemmmjjjrrrKKK GGGñññãããææææææææææææææææææççççççæææåååêêꤤ¤©©©¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨¨©©©ªªªªªªªªªªªªªªªªªª«««§§§¹¹¹èèèåååææææææææææææææææææææææææææææææåååìììòòòððððððñññññññññðððñññññññññððððððññññññððððððñññîîîæææææææææææææææææææææææææææææææææææææææåååãããäääåååããããããæææêêêääääääãããèèèçççããããããæææèèèãããäääææææææææææææææææææææææææææææææææææææææææææççççççáááçççèèèÜÜÜÎÎÎææææææèèèÓÓÓ×××èèèçççÝÝÝ×××çççææææææææææææææææææææææææææææææææææææææææææåååïïïppp‰‰‰óóóéééËËËgggâââåååóó󌌌¥¥¥ñññèèèÒÒÒbbbÜÜÜéééæææææææææææææææææææææææææææææææææææææææäääïï﨨¨±±±ïïïçççØØØ”””áááæææííí¨¨¨ËËËìììéééÖÖÖŒŒŒãããçççææææææææææææææææææææææææææææææææææææææææææåååíííêêêåååæææåååêêêçççæææåååèèèçççææææææåååìììçççææææææææææææææææææææææææææææææææææææææææææææææææêêêìììåååæææéééíííåååææææææïïïíííåååæææéééíííåååææææææææææææææææææææææææææææææææææææææææææåååëëë«««¸¸¸íííêêêÌÌÌ‘‘‘ææææææêêê®®®µµµíííêêêÊÊÊ’’’çççææææææææææææææææææææææææææææææææææææææææææäääóóóŠŠŠŠŠŠôôôçççÒÒÒjjjÞÞÞçççðððkkkŽŽŽôôôèèèÐÐÐjjjàààèèèææææææææææææææææææææææææææææææææææææææææææèèèÐÐÐÛÛÛèèèçççÞÞÞÍÍÍææææææéééàààÜÜÜèèèçççÝÝÝÍÍÍææææææææææææææææææææææææææææææææææææææææææææææææåååìììéééææææææèèèíííææææææåååèèèéééåååæææèèèíííææææææææææææ(  æææææææææêêêçççãããÝÝÝÞÞÞÞÞÞÞÞÞÞÞÞÝÝÝÞÞÞÝÝÝßßßæææææææææçççÔÔÔëëëÁÁÁ|||†††„„„BBB'''EEEèèèæææçççèè謬¬ççç½½½zzz†††rrr|||))) ,,,èèèåååâââæææäääïïï¶¶¶%%%---®®®ØØØHHHKKK®®®§§§âââÜÜÜ···ììì°°°ììì´´´×××ÿÿÿUUUhhhÿÿÿêêêßßßåååâââæææäääñññ´´´ yyy———666@@@ŽŽŽ’’’ãããæææççççç篯¯ëëë´´´ ,,,èèèæææææææææÒÒÒïïïµµµ!!!!!!444èèèææææææçççÅÅÅêêê¾¾¾zzz………€€€ŽŽŽ/// ---èèèææææææçç縸¸ëëë»»»jjjuuuppp|||,,,///èèèæææææææææìììéééÜÜÜÆÆÆÈÈÈÇÇÇÉÉÉÄÄÄÆÆÆÄÄÄÄÄÄÊÊÊææææææææææææååååååéééæææèèèéééãããîîîâââîîîäääêêêçççææææææææææææåååííí»»»ÅÅÅØØØµµµççç±±±ëë믯¯ÖÖÖêêêææææææææææææææææææèèèèèèåååææææææéééææææææææææææææææææææææææåååíííÁÁÁÊÊÊÙÙÙ¸¸¸èè訨¨ëëë³³³ÚÚÚéééæææææææææææææææèèèÝÝÝßßßãããÛÛÛçççÙÙÙçççÚÚÚãããççç(0` æææåååçççéééèèèâââÚÚÚÙÙÙÛÛÛàààßßßáááãããäääñññªªªbbb{{{|||rrr}}}€€€iii###+++!!!cccóóóìììòòò¤¤¤___‡‡‡†††fffRRR–––»»»îî¥aaasss………gggSSS£££ŸŸŸ```kkkÃÃÄ„„~~~ƒƒƒ‚‚‚hhhTTTeeeˆˆˆ‰‰‰qqqxxxwww©©©>>>JJJGGGIIIAAAppp›››ZZZmmmëëëíííððð®®®‹‹‹ÿÿÿûûûüüüþþþÉÉɲ²²ØØØ¬¬¬ÐÐÐêêêùùùýýýúúúººº¹¹¹øøøÇÇÇ¡¡¡[[[ÝÝÝLLL¿¿¿÷÷÷]]]ÞÞÞŠŠŠÈÈÈÂÂÂÊÊÊ×××ïïï­­­ ÔÔÔÕÕÕ¢¢¢···  ÎÎÎlll°°°CCCnnn¨¨¨HHHWWWXXXUUUNNN ŽŽŽÑÑÑOOOšššôôôBBBuuu§§§KKK\\\^^^111222444888'''ËËËÌÌÌÓÓÓÒÒÒ´´´ddd999¯¯¯õõõ———öööÍÍÍzzzÆÆÆ«««ÁÁÁŒŒŒEEEQQQÀÀÀµµµœœœtttYYYÜÜÜÏÏÏ    !" #$%&'''()*****+,*-*.*/!  012 #34(''5'67*888*9:*88;*! #3?('''6)*****+,*-*.*/! @A2 #3%BCC5DE&F*****+G-HH+*I! " #$JKLMMLNOOOP4*****+,*-*.*/!   QRSTTUVW=XYX=,ZGGGG[\@ D]^#] _`:*-*H*abcbdb1*.--.*1bdbebf Aghijk _`G*.8l*abmnobp*8**8*qbrcobs  #tu"vwx^ _`:*-*H*abcbdb1*8**8*1bdbebf  #XCy hz{ _`G*8-H*|bmnobp*8--8*pbondb} k~k€p _`:*-*H*abcbdb1*8**8*1bdbebf 2" _‚ƒ„…,-†€‡ˆ+‰……‰+ˆ‡€€Š   _‚‹9ƒŒŽ-...*G,ŒŒ,G*..l*I!  ^ _`:*-**8G***-*,+****+,*-*.*/! ]‘’“_ _`G*8**8G*---*+*--*+*--H*?@AB4 C"DE'6')F'5'G-H ;IJ&EKLMNOPQ8RSJTTU#V%'(('WXYXZ'Q+'[X\X]^L_`abc0-%'55'dXeXf'56'gXYX=^<%hH ijVV%'(('WXYXZ'56'[X\X]^-%'kk'lXmXO'n7'gXeX=^? -o+R*pqqF*nSr HsgV%'(')F'6'R+'')F'5'G--tuc0-%'567S()(8+''QR'Q'v-`a>0V%'(')F'6'R+'')F'5'G-c`-bwxyz{yyz|RpR}F~6;@AB4L2b%1'+'7R')'v-ci%?1€A#2 &'('QF'5'G--‚0ƒ  %!„r'('QF'5'v-00;4…†‡ˆP‰U'5(kR67'G;?@ABCC& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖ×××ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÑÑÑÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÒÒÒÖÖÖÕÕÕÕÕÕÖÖÖÏÏÏÏÏÏØØØÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓááᢢ¢jjjäääÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÈÈÈÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓããã•••tttåååÒÒÒÓÓÓÙÙÙÜÜÜ,,,§§§ßßßÓÓÓÕÕÕÈÈÈÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓââ✜œ^^^æææÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÆÆÆÒÒÒÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÒää䎎ŽiiiçççÐÐÐÛÛÛgggDDD±±±ÝÝÝÓÓÓÕÕÕÆÆÆÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓââ✜œ^^^åååÑÑÑÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÆÆÆÒÒÒÕÕÕÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÒÒÒãã㎎ŽiiiçççÑÑÑØØØ½½½–––¿¿¿ÜÜÜÔÔÔÕÕÕÕÕÕÆÆÆÓÓÓÕÕÕÔÕÕÔÕÕÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓâââ›››___êêêÕÕÕÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÉÉÉÖÖÖÚÚÚÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÖÖÖèèè‘‘‘ijjçççÒÒÒÕÕÕÛÛÛãããÛÛÛÔÔÔÖÖÖÕÕÕÕÕÕÈÉÉ×ÔÔÙÖÖÙÕÕÙÕÕØÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓâââWWWÕÕÕÃÃÃÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆ¿¿¿ÄÄÄÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÃÃÃÔÔÔƒƒƒiiiåååÐÐÐÔÔÔÒÒÒÑÑÑÒÒÒÔÔÔÓÓÓÓÓÓÔÔÔÁ½½ÄÑÑÆÔÔÆÓÓÅÓÓÇÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓààদ¦MMMFFFGGGGGGGGGGGGGGGGGGGGGIII'''AAAIIIGGGGGGGGGGGGGGGGGGFGGOLL&44g}}ÖÒÒÃÄÄÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆÆËÇÇBmm>½½JÉÉHÆÆDÆÆVÈÈÑÕÕÖÕÕÕÕÕÕÕÕÕÕÕÓÓÓââ✜œ^^^çççÓÓÓÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÕÕÕÞÞÞKKK¼¼¼ÜÜÜÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÓÖÖå×׎ÐÐiÍÍçÖÖÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÕÕGÇÇÇÔÔÚÕÕÕÕÕÖÕÕÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓââ✜œ^^^æææÒÒÒÕÕÕÓÓÓÒÒÒÒÒÒÔÔÔÕÕÕÓÓÓÝÝÝLLL»»»ÛÛÛÔÔÔÔÔÔÒÒÒÒÒÒÓÓÓÕÕÕÒÕÕä×׎ÍÍiÉÉç××ÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÕÕHÆÆÆÓÓÙÕÕÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓââ✜œ^^^æææÒÒÒÔÔÔáááåååããã×××ÔÔÔÓÓÓÜÜÜKKK»»»ÛÛÛÓÓÓÚÚÚååååååÝÝÝÔÔÔÒÕÕäÖÖŽÍÍiÊÊç××ÑÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÕÕGÆÆÆÓÓÙÕÕÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓââ✜œ^^^æææÐÐÐÛÛÛEEEnnnÎÎÎ×××ÓÓÓÝÝÝKKK»»»ÚÚÚÚÚÚ···QQQPPP¦¦¦ÛÛÛÑÓÓä×׎ÎÎiÊÊç××ÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÕÕGÆÆÆÓÓÙÕÕÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓââ✜œ^^^æææÑÑÑÖÖÖœœœ¥¥¥€€€äääÐÐÐÝÝÝKKK»»»ÚÚÚÙÙÙ···¡¡¡ddd!!!ÚÚÚÒÔÔäÖÖŽÎÎiÊÊç××ÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÕÕGÆÆÆÓÓÙÕÕÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓââ✜œ^^^æææÑÑÑÖÖÖÞÞÞddd###¶¶¶ÛÛÛÒÒÒÝÝÝKKK»»»ÜÜÜÐÐÐåå娨¨%%%hhhàààÐÓÓäÖÖŽÎÎiÊÊç××ÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÕÕGÆÆÆÓÓÙÕÕÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓââ✜œ^^^æææÑÑÑÙÙÙ®®®ƒƒƒàààÑÑÑÝÝÝKKK»»»ÛÛÛÖÖÖÉÉÉššš@@@;;;áááÐÓÓäÖÖŽÎÎiÊÊç××ÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÕÕGÆÆÆÓÓÙÕÕÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓââ✜œ^^^æææÐÐÐÝÝÝ“““HHHaaaÆÆÆØØØÓÓÓÝÝÝKKK»»»ÛÛÛØØØÅÅÅ\\\JJJ˜˜˜ÜÜÜÑÓÓä×׎ÎÎiÊÊç××ÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÕÕGÆÆÆÓÓÙÕÕÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓââ✜œ^^^åååÑÑÑÔÔÔÝÝÝáááãããØØØÔÔÔÓÓÓÜÜÜKKK·ººØÛÛÐÓÓÔ××ÞááßââÛÞÞÑÔÔÏÕÕàÖÖ‹ÌÌgÈÈã××ÎÔÔÒÕÕÒÕÕÒÕÕÒÕÕÒÕÕÑÕÕÒÕÕÓÕÕFÄÄÃÓÓÕÕÕÑÕÕÑÕÕÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓâââ›››___èèèÓÓÓ×××ÕÕÕÔÔÔÔÔÔÖÖÖ×××ÕÕÕÞßßMLL˼¼îÝÝæÖÖæÖÖäÔÔäÔÔåÕÕç××ä××÷×ךÔÔrÓÓúØØã××ç××ç××ç××ç××ç××ç××ç××è××MÒÒÖÖÖë×׿××ç××å××ÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓââ✜œYYYÚÚÚÇÇÇÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÈÈÈÓÑÑAGGV±±mÐÐhÉÉiÊÊiÊÊiÊÊiÊÊiÊÊhÉÉpÒÒF¦¦4““rÓÓgÈÈiÊÊiÊÊiÊÊiÊÊiÊÊiÊÊiÊÊiÊÊ#‚‚aÂÂkÌÌiÊÊfÊÊtËËÒÕÕÖÕÕÕÕÕÕÕÕÕÕÕÓÓÓââ✜œZZZÞÞÞÊÊÊÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÌÌÌÖÕÕDHHy´´“ÔÔÍÍŽÎÎŽÎÎŽÎÎŽÎÎŽÎÎŒÍ͘ÓÓ^³³F¦¦šÔÔ‹ÌÌŽÎÎŽÎÎŽÎÎŽÎÎŽÎÎŽÎÎŽÎÎŽÎÎ/™™„ÈÈÏÏŽÍÍŒÍÍ•ÎÎÓÕÕÖÕÕÕÕÕÕÕÕÕÕÕÓÓÓââ✜œ^^^çççÓÓÓ×××ÕÕÕÕÕÕÕÕÕÖÖÖ×××ÕÕÕÞÞÞLLLɼ¼ëÝÝãÖÖäÖÖãÕÕâÕÕäÖÖä××áÖÖô×טÓÓpÒÒ÷××àÖÖä××ä××ä××ä××ä××ä××ä××å××LÐÐÔÖÖè××ã××å××ãÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓââ✜œ^^^åååÑÑÑÔÔÔÛÛÛßßßáááÙÙÙÔÔÔÓÓÓÜÜÜKKK¸ººÙÛÛÑÔÔÔÖÖÝßßÜßßÒÔÔÒÔÔÐÕÕáÖÖŒÍÍhÉÉä××ÏÔÔÒÕÕÒÕÕÒÕÕÒÕÕÒÕÕÒÕÕÒÕÕÓÕÕFÅÅÃÓÓÖÕÕÒÕÕÒÕÕÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓââ✜œ^^^æææÑÑÑ×××¹¹¹«««œœœÁÁÁØØØÓÓÓÝÝÝKKK»»»ÛÛÛÕÕÕÐÐÐ¥¥¥§§§ØØØ×××ÒÔÔä×׎ÎÎiÊÊç××ÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÕÕGÆÆÆÓÓÙÕÕÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓââ✜œ^^^æææÏÏÏãããTTTJJJ   ÞÞÞÑÑÑÝÝÝKKK»»»ÚÚÚÝÝݦ¦¦TTT:::FFFÜÜÜÑÔÔäÖÖŽÎÎiÊÊç××ÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÕÕGÆÆÆÓÓÙÕÕÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓââ✜œ^^^æææÑÑÑ×××ÓÓÓFFFvvväääÒÒÒÔÔÔÝÝÝKKK»»»ÛÛÛÓÓÓ×××ÀÀÀUUU:::ÜÜÜÑÔÔäÖÖŽÎÎiÊÊç××ÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÕÕGÆÆÆÓÓÙÕÕÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓââ✜œ^^^æææÒÒÒÓÓÓÕÕÕããã”””âââÑÑÑÝÝÝKKK»»»ÛÛÛÒÒÒÛÛÛ§§§***\\\ãããÐÒÒä×׎ÎÎiÊÊç××ÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÕÕGÆÆÆÓÓÙÕÕÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓââ✜œ^^^æææÐÐÐÞÞÞmmm;;;ªªªÝÝÝÒÒÒÝÝÝKKK»»»ÚÚÚÙÙÙ¾¾¾^^^///MMMàààÐÓÓäÖÖŽÎÎiÊÊç××ÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÕÕGÆÆÆÓÓÙÕÕÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓââ✜œ^^^æææÑÑÑ×××ÉÉÉ¥¥¥ÄÄÄÜÜÜÔÔÔÔÔÔÝÝÝKKKºººÚÚÚÔÔÔÓÓÓ­­­ªªªÖÖÖÕÕÕÑÓÓãÖÖÍÍhÉÉæÖÖÑÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÔÔGÆÆÅÓÓØÕÕÓÕÕÔÕÕÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓââ✜œ^^^æææÒÒÒÕÕÕÙÙÙàààÚÚÚÔÔÔÖÖÖÔÔÔÝÝÝMMMÁÁÁâââÚÚÚÜÜÜäääåååÛÛÛÛÛÛÙÛÛëÝÝ“ÔÔmÐÐîÝÝØÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÜÜÜIÊÊÌÔÔßÖÖÛÖÖÜÖÖÛÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓââ✜œ\\\ãããÏÏÏÒÒÒÒÒÒÑÑÑÑÑÑÒÒÒÒÒÒÑÑÑÚÚÚIII¢¢¢ÁÁÁººº»»»¹¹¹¹¹¹ººº»»»¸ººÈ¼¼|´´\±±Ê¼¼¸ºº»»»»»»»»»»»»»»»»»»»»»¼ºº?¸¸­ÑѾÓÓºÒÒºÒÒ½ÓÓÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓâââWWWÖÖÖÄÄÄÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÅÅÅÎÎÎaaaAAAMMMKKKKKKKKKKKKKKKKKKKKKLLLDHHAGGMLLKKKKKKKKKKKKKKKKKKKKKKLLKHH00F¿¿LÉÉLÆÆHÆÆYÈÈÑÕÕÖÕÕÕÕÕÕÕÕÕÕÕÓÓÓââ✜œ^^^çççÒÒÒÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÎÎÎÛÛÛÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÜÜÜÞÞÞÖÕÕÓÑÑÞßßÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÜÜÜÝÝÝÞÞÞJIIÍÆÆáÚÚÜÕÕÝÖÖÜÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓââ✜œ^^^æææÑÑÑÕÕÕÓÓÓÒÒÒÓÓÓÔÔÔÕÕÕÕÕÕÖÖÖÅÅÅÑÑÑÔÔÔÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÕÕÕÌÌÌÈÈÈÕÕÕÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÕÔÔGHHÄÆÆ×ÙÙÓÔÔÓÕÕÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓââ✜œ^^^æææÒÒÒÔÔÔßßßáááßßßÙÙÙÔÔÔÕÕÕÖÖÖÇÇÇÒÒÒÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÎÎÎÊÊÊ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖGGGÆÆÆÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓââ✜œ^^^æææÏÏÏßßßiii<<<CCCœœœßßßÓÓÓÖÖÖÇÇÇÒÒÒÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÎÎÎÊÊÊ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖGGGÆÆÆÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓââ✜œ^^^æææÏÏÏßßß„„„ÏÏÏÖÖÖÔÔÔÖÖÖÇÇÇÒÒÒÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÎÎÎÊÊÊ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖGGGÆÆÆÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓââ✜œ^^^æææÒÒÒÑÑÑòòò´´´222ÁÁÁÚÚÚÔÔÔÖÖÖÇÇÇÒÒÒÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÎÎÎÊÊÊ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖGGGÆÆÆÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓââ✜œ^^^æææÐÐÐÚÚÚ™™™ŽŽŽãããÒÒÒÖÖÖÇÇÇÒÒÒÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÎÎÎÊÊÊ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖGGGÆÆÆÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓââ✜œ^^^æææÐÐÐÜÜÜ‘‘‘HHHtttÒÒÒÖÖÖÔÔÔÖÖÖÇÇÇÒÒÒÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÎÎÎÊÊÊ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖGGGÆÆÆÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓââ✜œ\\\âââÏÏÏÑÑÑÝÝÝãããàààÓÓÓÑÑÑÒÒÒÒÒÒÄÄÄÏÏÏÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÑÑÑÓÓÓÊÊÊÇÇÇÓÓÓÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÑÑÑÒÒÒÓÓÓFFFÃÃÃÕÕÕÑÑÑÒÒÒÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓâââ›››ffføøøâââæææäääâââãããåååææææææçççÖÖÖãããæææææææææææææææææææææåååçççÞÞÞÚÚÚèèèåååæææææææææææææææææææææçççMMMÕÕÕêêêåååæææäääÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓààत¤'''eee\\\^^^^^^^^^^^^^^^^^^^^^^^^WWW\\\^^^^^^^^^^^^^^^^^^^^^^^^^^^ZZZYYY___^^^^^^^^^^^^^^^^^^^^^^^^^^^WWW___^^^[[[jjjÑÑÑÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕ×××ÎÎΣ££›››œœœœœœœœœœœœœœœœœœœœœœœœœœœœœœœœœœœœœœœœœœœœœœœœœœœœœœœœœœœœœœœ›››œœœœœœœœœœœœœœœœœœœœœœœœœœœ¦¦¦›››œœœššš¢¢¢ÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××àààâââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââàààââââââââââââáááÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ( @ ÕÕÕÖÖÖ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖ×××ÕÕÕÕÕÕÓÓÓ×××ÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÓÓÓÏÏÏÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÏÏÏÖÖÖÕÕÕßßßÑÑÑÓÓÓÖÖÖÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÜÜܹ¹¹~~~àààÓÓÓÕÕÕÕÕÕÕÕÕÖÖÖÒÒÒÌÌÌÖÖÖÕÕÕÕÕÕÕÕÕÔÔÔÜÜܹ¹¹~~~áááÏÏ϶¶¶EEEŸŸŸáááÐÐÐÌÌÌÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÝÝݸ¸¸wwwÞÞÞÐÐÐÒÒÒÒÒÒÒÒÒÓÓÓÏÏÏÈÈÈÔÔÔÒÒÒÒÒÒÒÒÒÑÑÑÚÚÚµµµxxxáááÔÔÔˆˆˆvvvÌÌÌØØØÑÑÑÉÊÊÔÖÖÒÔÔÓÕÕÕÕÕÕÕÕÝÝÝ···îîîÞÞÞáááááááááâââÞÞÞØØØâââáááááááááàààéééÂÂÂ{zzâââÔÔÔâââåååÙØØÖÖÖÔÕÕØÑÑâ××áÖÖàÖÖÖÕÕÕÕÕÛÛÛ¾¾¾JJJ~~~xxxyyyyyyyyyzzzuuunnnzzzxxxyyyyyyxxx~~~bccnssØØØÉÉÉÉÉÉÈÈÈËËËÎÏϾ¾s¢¢yÑÑwÊÊ~ÌÌÏÔÔ×ÕÕÜÜܺººiiiÁÁÁµµµµµµ´´´¶¶¶½½½hhhÁÁÁµµµµµµ´´´¶¶¶¾¸¸›´´uÂÂÞÔÔÏÑÑÒÒÒÒÒÒÑÒÒÙÓÓ¶ËËj¾¾ÁÕÕ´ÑѹÒÒÓÕÕÖÕÕÝÝÝ···|||éééÚÚÚçççêêêÞÞÞããã¾¾¾~~~èèèÚÚÚçççêêêÞßßãÜܾÙÙzÎÎâ××ÓÖÖÖÖÖÖÖÖÕÖÖÝÖÖ¸ÓÓ~ÏÏé××ÚÖÖÜÖÖÕÕÕÕÕÕÝÝݸ¸¸xxxáááÐÐЈˆˆ}}}ÇÇÇÞÞÞ¶¶¶xxxáááÐÐЈˆˆ}}}ÇÈÈÞØØµÐÐyËËáÖÖÒÕÕÕÕÕÕÕÕÔÕÕÜÖÖ·ÒÒxËËàÖÖÑÕÕÔÕÕÕÕÕÕÕÕÝÝݸ¸¸xxxáááÒÒÒªªª222èèèµµµyyyáááÒÒÒªªª222žžèááµÐÐyËËáÖÖÒÕÕÕÕÕÕÕÕÔÕÕÜÖÖ·ÒÒyËËáÖÖÒÕÕÕÕÕÕÕÕÕÕÕÝÝݸ¸¸xxxàààØØØ¤¤¤%%%®®®åååµµµyyyàààØØØ¤¤¤%%%®®®åßßµÐÐyËËáÖÖÒÕÕÕÕÕÕÕÕÔÕÕÜÖÖ·ÒÒyËËáÖÖÒÕÕÕÕÕÕÕÕÕÕÕÝÝݸ¸¸xxxàààÕÕÕ”””{{{ÇÇÇßßß¶¶¶wxxÞààÒÕÕ’””x{{ÅÈÈÜØØ´ÑÑwÊÊÞÖÖÐÔÔÒÕÕÒÕÕÑÕÕÚÖÖµÑÑwÊÊÞÖÖÐÔÔÓÕÕÕÕÕÕÕÕÝÝÝ···yyyâââÓÓÓßßßää䨨ØÝÝÝ·¸¸yyîââÞÓÓêßßïääãÙÙèÖÖÂÕÕ€ÑÑî××ÞÖÖáÖÖáÖÖàÖÖé××ÁÕÕ€ÑÑî××ßÖÖàÖÖÖÕÕÕÕÕÝÝݸ¸¸ttt×××ÉÉÉÉÉÉÈÈÈÊÊÊÑÓÓµ¯¯Jss~××xÉÉwÉÉuÈÈxËË}ÏÏh¾¾D¢¢€ÑÑwÊÊyËËyËËxËË}ÏÏh¾¾D¢¢€ÑÑvÊÊ~ÌÌÏÔÔ×ÕÕÝÝݸ¸¸wwwÞÞÞÏÏÏÏÏÏÏÏÏÐÐÐÙÙÙ¶´´jwwÁÞÞµÏϵÏÏ´Ï϶ÑѽÔÔËËh¾¾ÁÔÔµÑÑ·ÒÒ·ÒÒ¶ÒÒ½ÓÓËËh¾¾ÂÕÕ´ÑѹÒÒÓÕÕÖÕÕÝÝÝ···yyyâââÓÓÓäääää䨨ØÜÜÜ·¸¸|yyéââÚÔÔçááêããÞÙÙãÖÖ½ÔÔ}ÏÏé××ÚÖÖÜÖÖÜÖÖÛÖÖäÖÖ½ÓÓ}ÏÏé××ÚÖÖÜÖÖÕÕÕÕÕÕÝÝݸ¸¸xxxáááÔÔÔtttmmm»»»ááá¶¶¶xxxáááÐÑш‰‰}~~ÇÉÉÞØØ¶ÑÑxËËàÖÖÑÕÕÔÕÕÔÕÕÓÕÕÛÖÖ¶ÒÒxËËàÖÖÑÕÕÔÕÕÕÕÕÕÕÕÝÝݸ¸¸xxxßßßÜÜÜyyyLLLÎÎÎÞÞÞ¶¶¶yyyáááÒÒÒªªª222žžèááµÐÐyËËáÖÖÒÕÕÕÕÕÕÕÕÔÕÕÜÖÖ·ÒÒyËËáÖÖÒÕÕÕÕÕÕÕÕÕÕÕÝÝݸ¸¸xxxáááÏÏÏÁÁÁBBB¡¡¡çççµµµyyyàààØØØ¤¤¤%%%®®®åßßµÐÐyËËáÖÖÒÕÕÕÕÕÕÕÕÔÕÕÜÖÖ·ÒÒyËËáÖÖÒÕÕÕÕÕÕÕÕÕÕÕÝÝݸ¸¸xxxáááÔÔÔ‡‡‡yyyËËËÞÞÞ···xxxÞÞÞÒÒÒ’’’xxxÅÆÆÜÖÖ´ÏÏxÉÉÞÔÔÐÒÒÒÒÒÒÒÒÑÒÒÚÓÓµÏÏwÊÊÞÖÖÐÔÔÓÕÕÕÕÕÕÕÕÝÝÝ···yyyâââÔÔÔâââåå娨ØÝÝÝ···îîîÞÞÞêêêïïïãääèááÂÞÞ€××îââÞááááááááàááéââÁß߀ÓÓî××ßÖÖàÖÖÖÕÕÕÕÕÝÝݸ¸¸sss×××ÉÉÉÉÉÉÈÈÈÊÊÊÑÑÑ···OOO}}}xxxwwwuuuxxx}yyiwwJssyywyyyyyyyyxyy}{{hooD——€ÓÓvÊÊ~ÌÌÏÔÔ×ÕÕÝÝݸ¸¸wwwÞÞÞÏÏÏÏÏÏÏÏÏÑÑÑÓÓÓÏÏÏ···················¸¸¶´´µ¯¯·¸¸·········¶¶¶½¾¾››huuÂÞÞ´ÏϹÒÒÓÕÕÖÕÕÝÝÝ···yyyâââÓÓÓääääääÙÙÙÖÖÖÓÓÓÑÑÑÞÞÞÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÙÙÙÑÒÒÞÞÞÜÜÜÜÜÜÜÜÜÛÛÛäää½¾¾}{{éââÚÓÓÜÖÖÕÕÕÕÕÕÝÝݸ¸¸xxxáááÔÔÔtttmmm¼¼¼ÛÛÛÑÑÑËËËÕÕÕÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÑÑÑËËËÕÕÕÔÔÔÔÔÔÔÔÔÓÓÓÛÛÛ¶¶¶xyyàááÑÒÒÔÕÕÕÕÕÕÕÕÝÝݸ¸¸xxxßßßÜÜÜyyyLLLÏÏÏ×××ÑÑÑËËËÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÒÒÒËËËÖÖÖÕÕÕÕÕÕÕÕÕÔÔÔÜÜÜ···yyyáááÒÒÒÕÕÕÕÕÕÕÕÕÝÝݸ¸¸xxxáááÏÏÏÁÁÁBBB¡¡¡áááÐÐÐËËËÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÒÒÒËËËÖÖÖÕÕÕÕÕÕÕÕÕÔÔÔÜÜÜ···yyyáááÒÒÒÕÕÕÕÕÕÕÕÕÝÝݸ¸¸wwwÞÞÞÒÒÒ„„„wwwÉÉÉÕÕÕÏÏÏÉÉÉÔÔÔÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÏÏÏÉÉÉÔÔÔÒÒÒÒÒÒÒÒÒÑÑÑÚÚÚµµµxxxÞÞÞÐÐÐÓÓÓÕÕÕÕÕÕÝÝÝ···~~~îîîÞÞÞíííïïïãããáááÞÞÞ×××âââááááááááááááâââÞÞÞ×××âââáááááááááàààéééÁÁÁ€€€îîîßßßàààÖÖÖÕÕÕÛÛÛÀÀÀPPP}}}wwwvvvuuuxxxyyywwwtttyyyxxxxxxxxxxxxyyywwwtttyyyxxxxxxxxxxxx|||iiiJJJuuu~~~ÏÏÏ×××ÕÕÕÕÕÕÀÀÀ¶¶¶¸¸¸¸¸¸¸¸¸¸¸¸···¸¸¸¸¸¸···¸¸¸¸¸¸¸¸¸¸¸¸···¸¸¸¸¸¸···¸¸¸¸¸¸¸¸¸¸¸¸···ººº¾¾¾······¹¹¹ÓÓÓÖÖÖÕÕÕÕÕÕÛÛÛÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÜÜÜÛÛÛÝÝÝÝÝÝÜÜÜÖÖÖÕÕÕ(  ÓÓÓÑÑÑÔÔÔÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÒÒÒÒÒÒÕÕÕËËËÕÕÕÓÔÔÔÕÕÕÕÕ¾¾¾¶¶¶äääÛÛÛÛÛÛÙÙÙÜÜÜâââÆÅÅ·¶¶½½½–––ÛÛÛØÒÒÝÖÖÕÕÕ¾¾¾²²²«««©©©¦¦¦­­­°°°˜™™§¨¨×××ÒÒÒËËË¨ÆÆ°ÓÓÒÔÔ½½½œœœÃÃÃÆÆÆ©©©šššÃÄÄÆÁÁ¨»»©ËËÚÔÔÖÓÓ¼ÎΚËËÆÔÔÒÕÕººº¸¸¸ºººÉÉɶ··¸»»‹‹ÉààªÐÐÛÖÖØÖÖ½ÓÓ°ÒÒàÖÖÔÕÕ»»»´´´¶¶¶ŠŠŠÅÅÅ·²²½··‘……ÌÜܱÑÑäÖÖáÖÖÄÔÔ²ÓÓãÖÖÔÕÕ¼¼¼ªªª×××ÙÚÚ»ººŽ©©±ØØ´ÕÕ™ËËŒÇDzÓÓ°ÒÒšËË‹ÆÆ¶ÓÓÑÔÔ¼¼¼«««ÙÙÙ×××¼»»›««ÃÙÙÅÖÖ©ÎΚËËÄÔÔÁÓÓ©ÎΙËËÆÔÔÒÕÕººº¶¶¶«««‘‘‘ÆÆÆµ±±¸´´Ž„„ÉÚÚ®ÏÏàÕÕÝÔÔÁÒÒ°ÒÒàÖÖÔÕÕ»»»´´´¸¸¸”””ÅÅÅ·¸¸½¿¿‘Ìãã°ÖÖãÝÝàÝÝÄÛÛ²ÔÔãÖÖÔÕÕ¼¼¼ªªª××××××½½½±±±´±±›ªªŽ©©±­­°­­š¨¨‹ÁÁ¶ÔÔÑÔÔ¼¼¼«««ÚÚÚÒÒÒÐÐн½½¾¾¾½½½¼»»»ºº½¾¾ÂÃ騨™©©ÆÛÛÒÓÓººº¶¶¶ªªªŠŠŠÛÛÛÒÒÒÚÚÚÙÙÙÖ××ÔÕÕÙÙÙÞÞÞÁ°¬¬àÛÛÔÓÓººº¹¹¹ÀÀÀ•••âââÖÖÖÝÝÝÜÜÜÙÙÙ×××ÜÜÜáááÄÄIJ³³ãääÔÔÔÀÀÀ”””±±±°°°«««ªªª®®®­­­«««ªªª­­­±±±œœœ¶¶¶ÑÑÑÔÔÔÀÀÀ»»»»»»¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼½½½½½½¾¾¾ÓÓÓ(0` ÔÕÕ×ÙÙÚÕÕÛÛÛÌÌÌáÚÚ¤¤¤jjjãããÅÅÅ“““uuu,,,ÌÇÇœœœ^^^éé鎎ŽFFFµµµ»»»Á½½UUU‚‚‚ÆÓÓKKK%%%;;;EHH&44g}}Bmm?»»IÆÆGÆÆVÈÈdddå×׎ÐÐiÊÊÎÔÔŽÎÎgÉÉé×דÏÏßââ·ºº«««ʼ¼íÝÝö××™ÔÔqÓÓúØØMÑÑV±±mÐÐF¦¦4““#‚‚aÂÂtËË{´´“ÔÔ]²²/™™„ÈÈJÉÉ222­ÑѼÓÓ00F¿¿YÈÈòòòøøø             !"##$%&'()'$*+,-$'.)'$/'+,-$*0'+,'$&'+,'#12 *'()'$& & 0 '(,'$0*//**'+,*$34''''''5678'''''-''-94'''   :;,),,,,,7<=7,,,),,,,,>?),,@AB.+++.++6C<6+++.++++BDE.+..34'''''5675''''''F''''0/*'+,'*$01/*'()'$G'+,'$ 0 *'+)'$  '()-$1*H*'.,'#  011'E,'*#46)4F*003AC3"IJJJJ  &KL##$M/ ''      *G   NH    *       &O/&&1( @ÕÕÕÛÖÖÓÓÓÐÐÐÏÏÏÝÝÝÔÔÔ¸¸¸~~~ãããÌÌÌÒÔÔÜÜÜÞáá·¸¸EEEŸŸŸuuuÈÈÈ···wxx„„„xxxÉÉÉyyîîîÛÛÛêêêÀÀÀãääÚÓÓáÖÖÞØØ¶ËËJJJ}{{mmmbccnssÅÈȾ¾s¢¢yÑÑxËË~ÏÏÏÔÔiii´´´¾¾¾hhh¾¸¸›´´uÂÂÞÓÓµÏÏh¾¾ÁÔÔµÐйÒÒäääçççãÜܾÙÙyËËÜÖÖ¸ÓÓé××wÉÉãÙÙªªª222çáá¡¡¡%%%®®®åßß×××’’’ÅÆÆ’””îââêßßïää€ÓÓî××tttµ¯¯Jss~××D¢¢~Ì̶´´huuÂÞÞ´ÑѽÓÓË˽ÔÔÂÕÕ|yyêããäÖÖ€ÑÑsssˆˆˆLLLÓÖÖBBB¤¤¤€€€ÁßßjwwD——››PPP             !"#$%&' ()*+,-./012(03456-789:;# < 1=<>?@ AB,C  ' :+ A;DE  FG< FGH:+ A:@E IJK<IJKL7+ M A;+A  N#O P'A:+A :+A   #Q6RSEC9TUAAE C9*UAV'-WXYDDD+,8ZT++@@,8ZTD[-\]^7:_:`a89:;;:ba8c7; deHe `,CAAfbgCAA h$1  i'A;+ :@ j FGe7+kA:@  l<mJKL:+ ;@  NO7DA- :+A   <ne^YQ eo*UAhjpX&qTD[-W1r]^7; <<  1#eA h$1  j lI     n s."11( ÓÓÓÑÑÑÔÔÔÒÒÒÕÕÕËËËÓÔÔÔÕÕ¾¾¾¶¶¶äääÛÛÛÙÙÙÜÜÜâââÆÅÅ·¶¶½½½–––ØÒÒÝÖÖ²²²«««©©©¦¦¦­­­°°°˜™™§¨¨×××¨ÆÆ°ÓÓÒÔÔœœœÃÃÃÆÆÆšššÃÄÄÆÁÁ¨»»©ËËÚÔÔÖÓÓ¼ÎΚËËÆÔÔÒÕÕººº¸¸¸ÉÉɶ··¸»»‹‹ÉààªÐÐÛÖÖØÖÖ½ÓÓ°ÒÒàÖÖ»»»´´´ŠŠŠÅÅÅ·²²½··‘……ÌÜܱÑÑäÖÖáÖÖÄÔÔ²ÓÓãÖÖ¼¼¼ªªªÙÚÚ»ººŽ©©±ØØ´ÕÕ™ËËŒÇÇ‹ÆÆ¶ÓÓÑÔÔ¼»»›««ÃÙÙÅÖÖ©ÎÎÁÓÓ‘‘‘µ±±¸´´Ž„„ÉÚÚ®ÏÏàÕÕÝÔÔÁÒÒ”””·¸¸½¿¿‘Ìãã°ÖÖãÝÝàÝÝÄÛÛ²ÔÔ±±±´±±›ªª±­­°­­š¨¨‹ÁÁ¶ÔÔÚÚÚÐÐн¾¾ÂÃ騨™©©ÆÛÛÒÓÓÖ××ÞÞÞÁ°¬¬àÛÛÔÓÓ¹¹¹ÀÀÀ•••ÖÖÖÝÝÝáááÄÄIJ³³ãää®®®   !"#$%&'()*+,-./01023456789:;<=>? @ABCDEFGHIJKLMNOPQRSTJ<-UVWL XYZ[\-I]\S./0 ^$_`abcdef<=>?1gAhijklmnopKLM2qrsPtuvwxWLyzXO{|}~€0 M@ y  ‚ƒ„…†0‡ˆ‰Š‹  ŒŽˆgqMMq" ˆ>>LLLLLLLL(0`€€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿwwwwwwwwwwwwwwwwwwwwwwwwˆwwwwwwwwwwwwswwwƒwwwwwwpwwwwwwwwwwwwtwwˆCwwwwwwˆwwwwww÷wwwwwswwtˆwwwwww„wwwwwwwwwwwwpwwwwwwwwwwˆwwwwwwwwwwwwswwwwwwwwwwƒwˆx‡xˆˆxˆˆwˆ€‡wwwwww‡ww€€44CCCC„4wwwwww383·ˆwwwwwwwwwwwxwwwwww7www€wwwwww‡wwwwwswwwwww‡wwwp÷wwwwwwwwwwówwwwww7wwwˆwwwwwwww‡wwswwwwww‡wwwƒ÷w€8wwwx‡wxwwwwww·www„wwwww‡wwt7wswwwwwwˆwwwˆwwpwwww€‡wswwwwww7www€wwˆwwGwx€‡wxwwwwww7wwwˆww€Gwwwx0‡wswwwww7wwwpwwwwww7wwwwwswwwwww8wwwƒwwwwww7wwwwwxwwwwww‡wwx„÷wwwwxGwwwww{wwwwww8wwwˆwwwwww³ƒƒ83ƒ83ƒ3;ƒ33ƒ‡€wwwwwwwwwwwswwwwww‡÷wwˆwwwwww‡wwwwwxwwwwww7www„wwwwwwwwwwswwwwww7wwwˆwwwwww7wwwwwswwwwww‡wwwƒwwwwGwt‡wswwwwww7wwwˆww€www7wwsGwxwwwwwwˆwww€wwxwxww‡wó‡wwww·wwwpwwwwwGwwp‡wswwwwww7wwwˆww0ww7wxwwxwwwwww7wwwˆwwwwwwwwwwswwwwww‡www„wwwwwwGwwwwws÷wwwwwˆwwwˆwwwwwx7wwwwwówww÷ww‡www€wwwwww4€3ƒ87ˆwwwwwwwxwxwwww‡wxwwww„wwwwwwwwwwwwwwwwwwˆwwwˆwwwwwwwwwwwwwwwwwww8wwwƒwwwwwwwwwwwwwwwwwwwHwwwˆwwwwwwwwwwwwwwwww7www€ww€wwwwwwwwwwwwwwwwKwwwpwwxwwwwwwwwwwwwwwwwwwˆwwwwwwwwwwwwwwwwwwˆwwwƒww€wwwwwwwwwwwwwwHwww„wwwwwwwwwwwwwwwwwww8wwwˆwwwwwwwwwwwwwwwwwwwwwwpwwwwwwwwwwwwwwwwwwwˆwww€€H084H€4€€H0ˆ€‡xxˆxˆwˆˆˆˆ‡ˆ‡‡ˆ‡ˆwˆˆˆˆx‡( @€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿwÿwwÿww÷÷w÷w÷ˆ÷w÷w÷w‡wƒ÷w÷÷xww÷w÷w‡wH÷ÿwxÿ÷ÿw÷÷ÿww÷÷twˆx‡xxx‡7÷wwwwwsˆˆˆˆˆˆˆˆ‡÷÷ÿˆ{wˆ÷÷ÿxÿ¿wwww÷xwwxwwwww÷·w÷ˆ÷ƒxˆ‡÷wwwww÷x÷x‡øwøw·÷ÿ÷{÷÷ˆ€øx÷¿www·÷wˆ÷xwx‡øwww÷wwx÷xw÷ÿw·w÷w÷ˆwwø··‡w‡w··;{wx÷wÿxwww÷·www·wˆ÷÷wxw÷wwwwˆ÷ˆwøx÷¿÷w·wx€wx‡xw‡w÷w÷ˆ÷÷xx÷wwwxw€øx‡w·w·ÿwx÷w÷xw÷÷wˆ÷÷wxˆww‡7xww‹wwxw÷xˆˆˆˆˆˆˆˆˆ{wˆw÷w÷ÿw÷÷÷w÷ˆ÷÷x÷÷÷w÷ww÷wwˆ÷x€wwwÿww÷ÿ‡wˆ÷xwwwÿwˆ÷÷ˆ÷pw÷ww÷ww‡w÷ˆˆw÷ww÷w÷ˆ÷÷x÷wÿ÷÷ÿ‡÷ˆˆˆˆˆˆˆˆˆˆˆˆˆˆ‡wwˆw‡x‡xxxw‡ˆwxw( €€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿw÷wwwÿwwwÿ÷wxw÷xwxw‡÷wwwxxw÷{xxwxwwwxwxû÷w÷wwwwwwwwwx{w{÷wxwxw÷wwxxwxw÷xxw‡‡xww÷wwww‡wxww÷wx÷÷w÷wwwxwwwwˆwwxwxwwwpuzzles-20170606.272beef/icons/netslide.ico0000644000175000017500000006117613115373737017327 0ustar simonsimon 00 ¨%–  ¨>& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $ææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææååæååæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææååååååæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææååæééèééèååæææææææææææææææææææææææææææææææææææææçççæææææææææææææææåååéééèèèæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææèèçÛÛßÙÙÞèèçææææææææææææææææææææææææææææææææææææãããæææææææææææææææèèèØØØÜÜÜèèèæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææââäúúðxx¢hh™ûûðââäæææææææææææææææææææææææææææåååéééÅÅÅâââçççææææææâââúúú]]]„„„ùùùãããæææææææææææææææææææææææææææææææææææææææææææææäääææææææææææææââäûûñuu cc—ûûðââäåäääââäââäââäââäââäââäããæææåååéééÄÄÄâââçççææææææâââûûûYYYúúúâââæææææææææææææææææææææææææææææææææææææææåååçççðððæææåååææææææââäûûñuu dd—üüñááãìîîðøøîööî÷÷î÷÷îööï÷÷ïóóæææåååéééÄÄÄâââçççææææææâââûûûYYYúúúâââææææææææææææææææææææææææææææææææææææåååèèèççç”””áááìììéééçççââäûûñuu cc—úúïçéë»»¥‚‚¬‹‹«‰‰«‰‰«ŠŠ©……®œœæèèåååéééÄÄÄâââçççææææææâââûûûYYYúúúâââæææææææææææææææææææææææææææææææææåååèèèèèè•••nnnÍÍÍÛÛÛ×××ãããããåûûñuu cc—ú÷ìêóõ¥zzßïììêô¦++ÖèèåááåååÂÂÂâââçççææææææâââûûûYYYúúúâââææææææææææææææææææææææææææææææåååéééêêꢢ¢¨¨¨………‚‚‚–––ëëíùùïuu cc—ú÷íéóõª||óÿÿÿýÿµ33ìÿÿüøøþþþÍÍÍàààçççææææææâââûûûYYYúúúâââææææææææææææææææææææææææææææææçççååå¡¡¡¿¿¿ººº½½½¾¾¾³³³———êêëùùïuu cc—ú÷ìéóõ©zzòÿþþûÿp„„…|||”””êêêåååææææææâââûûûYYYúúúâââææææææææææææææææææææææææææææææçççááá®®®½½½¹¹¹¿¿¿ÁÁÁ¶¶¶˜˜˜êêëùùïuu cc—ú÷ìéóõ©zzòÿÿÿûÿ•G[[_ZZQQQ‚‚‚ëëëäääååååååáááúúúYYY€€€øøøáááååååååååååååææææææææææææææææææåååëëëààà‚‚‚­­­¯¯¯ŒŒŒ”””†††ììíùùïuu cc—ú÷ìéóõ©{{ðÿüýûÿ´22îÿÿýùùÿÿÿÏÏÏæææìììëëëëëëçççÿÿÿ[[[ƒƒƒÿÿÿçççëëëëëëëëëëëëæææææææææææææææææææææäääëëëÝÝÝ‹‹‹vvvºººÉÉÉÃÃÃØØØääæúúðuu cc—ú÷ìéóõ©zzòÿÿÿýÿ°++Ôççåààæææ»»»ÄÄÄÊÊÊÉÉÉÉÉÉÆÆÆÚÚÚYYYyyyÙÙÙÆÆÆÉÉÉÉÉÉÉÉÉÊÊÊãããçççææææææææææææææææææäääëëëÞÞÞ}}}äääðððîîîêêêââãûûñuu cc—ùøíëñ󦊊©¸$$µ!!µ!!µ""¸•GGàëëçääéééÁÁÁÕÕÕÚÚÚÙÙÙÙÙÙÖÖÖìììYYY}}}ëëëÖÖÖÙÙÙÙÙÙÙÙÙÚÚÚåååææææææææææææææææææææææææåååéééëëëäääåååååååååââäûûñuu cc—ûûðãâäãææÒååÓååÓååÓååÓååÑååÜææçææåååéééÅÅÅåååêêêééééééåååþþþZZZ‚‚‚ýýýæææééééééééééééææææææææææææææææææææææææææææææååååååææææææææææææââäûûñuu dd—ýüòããåèççìèèìèèëççéååìèèìèèêçççççæææêêêÄÄÄáááçççææææææâââûûûYYY€€€ùùùâââææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææââäûûñuu aa•÷÷ìÞÞàââââââáááåååîîîáááâââââââââáááåååÂÂÂâââçççææææææâââûûûYYYúúúâââææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææââäúúðww¢RR…××ÌÀÀÃÄÄÄÃÃÃÉÉÉ­­­fffÉÉÉÃÃÃÄÄÄÄÄÄÄÄÄÄÄij³³áááãããããããããßßß÷÷÷WWWúúúâââæææææææææææææææææææææææææææææææææææææææææææææåååææææææææææææââäûûñtt ee˜þþôååçéééçççôôôººº333ñññèèèééééééèèèëëëËËËöööúúúùùùùùùõõõÿÿÿddd€€€úúúãããææææææææææææææææææææææææææææææææææææææææææåååéééçççæææææææææââäûûñuu cc–ûûðááãåååäääðð𸸸555íííäääååååååãããííí¨¨¨~~~ˆˆˆ†††‡‡‡„„„”””---ˆˆˆøøøâââæææææææææææææææææææææææææææææææææææææææäääìììÜÜÜáááäääãããåååââäûûñuu cc—ûûðââäæææäääñññ¸¸¸333îîîåååææææææãããñññšššIIIVVVTTTTTTTTTSSSYYYÉÉÉìììåååææææææææææææææææææææææææææææææææææææãããðððËËËgggæææôôôñññíííááãûûñuu cc—ûûðââäæææäääñññ¸¸¸333îîîåååæææææææææèèèÊÊÊøøøûûûûûûûûûûûûûûûúúúëëëåååææææææææææææææææææææææææææææææææææææäääðððÇÇLjˆˆ„„„ŸŸŸ°°°¦¦¦ÄÄÄççéúúðuu cc—ûûðââäæææäääñññ¸¸¸333îîîåååææææææåååéééÃÃÃÞÞÞãããâââââââââââââââåååææææææææææææææææææææææææææææææææææææåååìììÌÌ̹¹¹µµµ¡¡¡•••ëëíùùïuu cc—ûûðââäæææäääñññ¸¸¸333îîîåååææææææåååéééÄÄÄâââçççææææææææææææææææææææææææææææææææææææææææææææææææææææææèèèÝÝÝtttºººººº¸¸¸¿¿¿ÁÁÁ¶¶¶šššééëùùïuu cc—ûûðââäæææäääñññ¸¸¸333îîîåååææææææåååéééÄÄÄâââçççææææææææææææææææææææææææææææææææææææææææææææææææææææææåååêêꨨ¨ŽŽŽÀÀÀºººµµµ¶¶¶«««•••êêìùùïuu cc—ûûðââäæææäääñññ¸¸¸333îîîåååææææææåååéééÄÄÄãããèèèççççççççççççååååååççççççççççççççççççææææææææææææææææææææææææñññ¢¢¢“““œœœ†††”””ˆˆˆ¦¦¦êêìùùïuu cc—ûûðââäæææäääñññ¸¸¸333îîîåååææææææåååéééÃÃÃßßßäääãããããããããáááíííêêêâââãããããããããããããããææææææææææææææææææææææææäääððð©©©fffàààìììêêêëëëââãûûñuu cc—ûûðââäæææäääñññ¸¸¸333îîîåååææææææåååëëë¼¼¼¾¾¾ÅÅÅÃÃÃÄÄÄÁÁÁÎÎÎ}}}’’’ÍÍÍÂÂÂÄÄÄÄÄÄÃÃÃÅÅÅãããçççæææææææææææææææææææææåååíííµµµßßßçççååååååââäûûñuu cc—ûûðââäæææäääñññ¸¸¸333îîîåååææææææåååéééÄÄÄäääéééèèèèèèäääþþþZZZ‚‚‚üüüåååèèèèèèèèèèèèææææææææææææææææææææææææææææææåååïïïçççæææææææææââäûûñuu aa–÷÷îÞÞâââäààâííïµµ·224êêìááãââäââäááãååçÀÀÂÝÝßââäááãááãÞÞàööøYY[ôô÷ÞÞàááãááãááãââäæææææææææææææææææææææææææææææææææäääææææææææææææââäûûñttŸppœÿÿü÷÷îûûðùùïÿÿüÊÊÀ;;5ÿÿùúúïûûðûûðûûðþþô××Ì÷÷ìüüòûûðûûð÷÷ìÿÿÿcc]ŽŽ†ÿÿÿøøíûûðûûðüüñûûðèèçååæææææææææææææææææææææææææææææææææææææææææææââäøøð¥!!uoo›bb–cc—cc–hhœPP<gg›cc–cc–cc—cc–ee˜RR…aa•dd—cc—cc—bb•mm¡&&O88cll¡bb•cc—dd—bb–hh™ÙÙÞééèååææææææææææææææææææææææææææææææææææææææææåååêêéÑÑÖ{{¥ttŸuu uu uu ttŸxx£‚‚®ttŸuu uu uu uu tt ww¢uu uu uu uu uu ssž«||¨ssžuu uu uu ssŸxx¢ÛÛßééèååæææææææææææææææææææææææææææææææææææææææææææåååêêéùùðûûñûûñûûñûûñùùïøøîööìùùïúúðûûñûûñûûñûûñúúðûûñûûñûûñûûñúúðùùï÷÷í÷÷íùùïûûñûûñûûñûûñúúðèèçååæææææææææææææææææææææææææææææææææææææææææææææææææåååââäââäââäââäââãêêìêêìééëììíççéááãââäââäââäââäââäââäââäââãääæììíêêëêêìëëíããåââäââäââäââäææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææåååëë릦¦šššŒŒŒÄÄÄíííåååæææææææææææææææåååêêêØØØ———•••–––ãããçççæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææåååéé骪ª¶¶¶–––«««ñññäääæææææææææææææææåååíííÆÆÆŠŠŠµµµ²²²†††ØØØéééæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææçççííí”””¶¶¶ÁÁÁ¢¢¢°°°ôôôäääæææææææææææææææåååðððÊÊÊ”””ÁÁÁ¾¾¾ÜÜÜìììåååæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææçççßßßÝÝÝ‹‹‹µµµ¾¾¾ŸŸŸ¢¢¢æææáááçççææææææææææææääääää»»»¿¿¿½½½‰‰‰ÌÌÌáááæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææäääïïïµµµ___œœœººº¸¸¸µµµ………hhhÜÜÜéééåååææææææåååëëë~~~rrr¯¯¯¹¹¹ººº¨¨¨hhh”””ðððäääææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææåååíííªªª“““ÀÀÀººº¹¹¹ˆˆˆËËËìììåååæææææææææåååéééÞÞÞŒŒŒ­­­½½½¿¿¿£££–––ççççççææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææåååððð¢¢¢ŽŽŽ»»»€€€ÆÆÆðððäääæææææææææææææææåååëëëÝÝ݃ƒƒ®®®¡¡¡ŒŒŒèèèèèèåååæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææäääñññ§§§tttËËËðððãããæææææææææææææææææææææäääëëëààà€€€éééèèèåååææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææéééÜÜÜìììäääæææææææææææææææææææææææææææäääëëëàààäääéééåååæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææåååéééåååæææææææææææææææææææææææææææææææææåååèèèçççåååæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææåååæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææ( @ æææææææææææææææææææææææææææêêèçççææææææææææææææææææææææææçççææææææææææææèèèéééåååæææææææææææææææææææææææææææææææææææææææççç××ÝââãçççæææææææææææææææææææææääääääææææææèèèÝÝÝÚÚÚèèèææææææææææææææææææææææææååååååææææææããåóóìgg˜ÄÄÏîîëäââæââæââæââåââåääêêêÖÖÖÙÙÙéééãããöööœœœ„„„øøøãããææææææææææææææææææåååèèèíííääääääââäóóìdd—ÃÃÏïîëéóóçøøè÷÷ç÷÷éøøèêêéééÕÕÕÙÙÙéééãããöööšššƒƒƒøøøãããæææææææææææææææäääëëëÛÛÛ¢¢¢ïïïîîîççèòòìee—ÄÃÏëðíµƒƒ¾ii½oo¿ppµiiÊÁÁêííÒÑÑÙÙÙéééãããöööšššƒƒƒøøøãããææææææææææææåååêêêßßßšššŠŠŠ«««¥¥¥ÍÍÎ÷÷ñcc•ÇÃÎáòïÆ((ÿúÿé̱±ÿÿÿãááÙÙÙéééãããöööšššƒƒƒøøøãããææææææææææææèèèààà•••³³³¼¼¼¶¶¶¡¡¡¸¸¹ûûõbb•ÆÃÎáòïÉ+,ÿýÿñz__ƒŠŠ„‚‚ÚÚÚèèèâââõõõšššƒƒƒ÷÷÷âââååååååææææææçççããã­­­¹¹¹®®®ššš··¹ûûõbb•ÆÃÎáòïÈ++ÿüÿð‹oo££—••ÝÝÝíííæææúúú………üüüæææêêêêêêææææææåååéééæææŸŸŸƒƒƒ¶¶¶±±±ÓÓÔööðcc–ÇÃÎàòïÈ((ÿýÿë˯¯ÿÿÿàßßÇÇÇÕÕÕÐÐÐààà’’’}}}âââÐÐÐÒÒÒÓÓÓäääçççæææåååéééááá°°°ðððïïïææèòòìdd—ÄÂÎéðí±tt¿VV½\\À]]´UUǼ¼ëîîÑÑÑÐÐÐßßßÙÙÙëëë–––€€€íííÙÙÙÜÜÜÜÜÜåååæææææææææåååçççîîîääääääããäóóìdd—ÆÆÒòñîêõõçúúèùùçùùéúúëííìììØØØÛÛÛìììåååùùùœœœ„„„ûûûåååèèèèèèææææææææææææææææææäääææææææããåóóìdd–··ÃááÞ×ÕÕÙÕÕØÕÕÙÕÕÙÕÕØ××ÜÜÜÊÊÊÖÖÖåååßßßòòò˜˜˜ƒƒƒøøøâââææææææææææææææææææææææææäääææææææããåóóìdd–´´ÀÝÝÚÑÑÒääättt¦¦¦àààÓÓÓØØØÉÉÉéééûûûôôôÿÿÿ¨¨¨ƒƒƒøøøãããææææææææææææææææææåååæææíííääääääããäóóìee—ÆÆÒòòïåååûûûttt±±±÷÷÷æææïïïÓÓÓ„„„‹‹‹ˆˆˆ•••VVVˆˆˆ÷÷÷ãããæææææææææææææææåååèèèååå¼¼¼ïïïîîîææçòòìdd—ÂÂÎîîëáááööösss®®®òòòâââêêêÐÐД””““““““”””ÔÔÔêêêåååææææææææææææåååèèèêêꥥ¥€€€ÀÀÀ¼¼¼××Ùõõïdd–ÃÃÏîîëááâ÷÷÷rrr®®®óóóãããéééÖÖÖèèèúúúööö÷÷÷÷÷÷êêêåååææææææææææææææææææåå奥¥§§§µµµ§§§”””··¸üüõbb•ÃÃÏîîëááâ÷÷÷rrr®®®óóóãããêêêÕÕÕÖÖÖæææâââãããâââåååææææææææææææææææææèèèÞÞÞ···½½½¼¼¼¦¦¦¸¸ºûûõcc•ÃÃÏîîëááâ÷÷÷rrr®®®óóóãããéééÕÕÕÛÛÛìììèèèéééééééééééééééééééééææææææåååëëëÙÙÙ———¤¤¤ÈÈÊøøòcc–ÃÃÏîîëááâ÷÷÷rrr®®®óóóãããêêêÕÕÕÎÎÎÝÝÝÚÚÚÚÚÚÛÛÛÛÛÛÚÚÚÚÚÚÚÚÚÚÚÚåååææææææäääíííÕÕÕ˜˜˜íííìììççèòòìdd—ÂÂÎííëààáööörrr­­­òòòâââéééÔÔÔÈÈÈÖÖÖÐÐÑààà–––ƒƒƒâââÐÐÐÓÓÓÓÓÔäääçççææææææåååéééêêêäääåååããäóóìgg˜ËËÔ÷÷ñêêçÿÿýxxuµµ²ûûøììéòòïÞÞÛääáõõòïïìÿÿÿ¢¢ ŠŠˆÿÿÿîîëòòïòòïçççææææææææææææååååååææææææããåóóícc–££ºËËÔ¿¿ËÒÒÞaag““œÎÎÚÁÁÌÆÆÒ´´À¶¶ÂÅÅÑÀÀËÐÐÝ‚‚ŠoouÒÒÞÀÀËÂÂÎÃÃÏââãçççæææææææææææææææææææææääåððë››¹ZZ’gg˜dd—dd–]]``’dd—dd—ee—dd–dd–dd—dd—dd—__‘^^dd—ee—cc–gg˜××Ýêêèææææææææææææææææææææææææååæððëôôíóóìòòìøøñýý÷üüöõõïòòìóóìóóìóóìóóìòòìööïýýöýýö÷÷ñòòìóóìóóìçççææææææææææææææææææææææææææææææääåããåããäææèÈÈʵµ·¶¶·××ÙææçããäããåããåããäææèÓÓÔµµ·µµ·ÍÍÎççèââäããåæææææææææææææææææææææææææææææææææææææææåååìììžžž¤¤¤•••½½½îîîäääææææææäääïïï³³³™™™ŸŸŸ¦¦¦îîîäääææææææææææææææææææææææææææææææææææææææææææäääííí§§§¼¼¼©©©ÂÂÂïïïäääææææææäääðð𸸸¯¯¯¶¶¶®®®ïïïäääæææææææææææææææææææææææææææææææææææææææåååêêꘘ˜½½½µµµ€€€¼¼¼íííääääääîîî±±±ƒƒƒ¹¹¹¼¼¼ŠŠŠ¢¢¢íííåååææææææææææææææææææææææææææææææææææææåååéééÕÕÕ———···¨¨¨¥¥¥åååæææææææææçççáá៟Ÿ­­­³³³šššÛÛÛèèèåååæææææææææææææææææææææææææææææææææææææææåååíííÙÙÙ¤¤¤êêêèèèåååææææææåååéééæææ•••ßßßëëëåååæææææææææææææææææææææææææææææææææææææææææææææäääëëëÞÞÞåååèèèåååææææææææææææåååéééãããàààêêêäääæææææææææææææææææææææææææææææææææææææææææææææææææææåååèèèæææåååææææææææææææææææææåååçççèèèåååæææææææææææææææ(  æææååååååæææààãããäèååèääçååååååååæææßßßææææææææææææéééççèôôð¯¯ÄÊÊÔèõòÝîïåîîàßßßßßééé¡¡¡ãããçççæææêêêËË˲²²ááݯ®ÄÀÄÏÙYWà)*Ð{{ÚææßÜÜéééãããçççæææààਨ¨¡¡¢¶µ±²±Ç¼ÂÍì%#ÿ¿::•¨¨ÞÚÚéééâââææææææêêêÎÎεµ¶ååᯮÄÁÅÐÜURä$$ÔzzßëëÒÏÏÚÚÚ———×××ÛÛÛåååæææèèèççèóóשּׁÁÂÂÍàëéÒâãÝääÙØØèèèôôô¡¡¡ãããçççææææææèèèèèéóóשּׁÁÂÂÍáÞÜŸ›œåããÓÓÓµµµ···æææææææææêêêÑÑѸ¸¹èèä­­ÂËËÖèèæžžžîîîÜÜÜ···¹¹¹ÊÊÊéééåååæææààਨ¨¡¡¢¶¶²¯¯ÅÇÇÓåå㜜êêêÜÜÝçççññòððñåååææææææêêêÈÈȯ¯°ÞÞÚ®®ÃÐÐØîî裣 óóðããáÙÙÖááÞÀÀ½ààÝââßåååæææèèèææçõõñªªÀ­­ÃÈÈшˆÍÍØÀÀËÁÁÌÊÊÕˆˆÄÄÏÊÊÔããäææææææåååééçÓÓÚ¨¨¿®®Ã««Á­­Ã¬¬Á¬¬Á­­Ã­­Â¬¬Â°°ÄààâæææææææææååæééçööñÞÞÛ··³èèäóóïóóïååá¶¶²ââÞôôðæææææææææææææææåååææç¯¯°¡¡¢¸¸¹èèéççèµµ¶¡¡¢²²²ççèåååæææææææææææææææèèèÈÈȨ¨¨ÑÑÑèèèèèèÎÎΨ¨¨ËËËéééåååææææææææææææææææææêêêàààêêêææææææêêêàààêêêææææææ(0` ååæèèçççéêççÛÛÜÞÞáÕÕÖûûñzz£ff™ùùïêêêÃÃÃööøcc]ƒ‚‚uu cc—ÜææZZZññòðøøìôõûûû”””ssžÂ»»©……«ŠŠ®œœtttËËËú÷ì¥zzßìò¦++Öèè‹‹‹£££«««©{{ÿþµ33íÿÿ´´´»»»œœœ÷÷í}}}•G[[TTT°++Óåå¦ŠŠ©µ!!¸•GGäéêÊÊÀRR…××Ìfff333---IIIjjjmm¡;;5ŽŽ†~~ª!!u<&&O88c‚‚®              !"#$$$$%&'  ()* !+%,,-,-./ () 01102 3+%-----45*111 1 !"%-----678 **(( !+$,----.   (1 !+%-----9:1 5  !3;<====>?@  5   ::::::'     A 3  BC *D 0 8 1E  D   1E *5((F 1E 2G88888  H  0E3  (20) !1E  510))( 1E  1101 12 0E *( 100* 0E  )2()  1E  )D 1E 11 5  0! 0E !0E   5 I! AJC3 3DK !3LM BN BIOPI QQL !3   3!!     )2( (2(*0* (00 0 )0  1(01))1( 1(  0D2100H 5*11*D * 11( (*1 ) )(1 *)() ( ( @åååççèÛÛÛêêçóóídd–ÃÂÎÙÕÕááÞõõô›››ƒƒƒûûûëëëàßßéõõéùùûûõ££êðígg˜µƒƒ¾llµiiÊÁÁÓÓÓ‹‹‹­­­¥¥¤ÊÊËÆÆÒáòïÆ((þê̱±”””´´´»»»··¹È**ñz__ƒŠŠ‹ooç÷÷˯¯ÃÃÃ}}}±ttÀ]]½\\´UUǼ¼µµÁsssVVVÕÕÜËËÔxxu££ºaag““œÎÎÚ¿¿Ë‚‚Šoou››¹]]‘        !!!"#  $%&''(!!!)*+    ' '(!!!",$   %%- !!!". /$0%  12345  $  -  6$ '7    7%  $8 &   7 $$$$9  &6 7  9 ' ' 7 &&&'  7     7    7 $ : ;%    <:9=>?@'6@?AB9CDDDD    %%'% $& %  &/'' &% & % '&  ' %   $  ( æææåååààãããäèååèääçååßßßéééççèôôð¯¯ÄÊÊÔèõòÝîïåîîàßß¡¡¡ãããçççêêêËË˲²²ááݯ®ÄÀÄÏÙYWà)*Ð{{ÚææßÜÜààਨ¨¡¡¢¶µ±²±Ç¼ÂÍì%#ÿ¿::•¨¨ÞÚÚâââÎÎεµ¶ååáÁÅÐÜURä$$ÔzzßëëÒÏÏÚÚÚ———×××ÛÛÛèèèóóשּׁÁÂÂÍàëéÒâãÝääÙØØôôôèèéáÞÜŸ›œåããÓÓÓµµµ···ÑÑѸ¸¹èèä­­ÂËËÖèèæžžžîîîÜÜܹ¹¹ÊÊʶ¶²¯¯ÅÇÇÓåå㜜ÜÜÝññòððñÈÈȯ¯°ÞÞÚ®®ÃÐÐØîî裣 óóðããáÙÙÖááÞÀÀ½ààÝââßææçõõñªªÀ­­ÃÈÈшˆÍÍØÀÀËÁÁÌÊÊÕˆˆÄÄÏééçÓÓÚ¨¨¿««Á¬¬Â°°ÄààâååæööñÞÞÛ··³ââÞ  !"#$%&'()*+,-./0123456789 :;<=>?@9A9B:;& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $æææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææåååææéççêççêççêççêççêççêççêççêççêççêççêççêççêççêççêççêççêççêççêççêççêççêççêççêççêççêççêççêççêççêççêççêççêççêççêççêççêççêççéææææææææææææææææææåååëëëééÛççÚèèÛèèÛèèÛèèÛèèÛèèÛèèÛèèÛèèÛèèÛèèÛèèÛèèÛèèÛèèÛèèÛèèÛèèÛèèÛèèÛèèÛèèÛèèÛèèÛèèÛèèÛèèÛèèÛèèÛèèÛèèÛèèÛèèÛèèÛèèÛèèÛèèÛççÜæææææææææææææææääåííìÄÄÆ!!srrrrrrrrrrrtrrrrrrrrrrrrtrrrrrrrrrrs n//‚æææææææææææææææãããõõð°hmm{ll‡kk„ll„ll„ll„ll„ll„ll„ll„ll„kkƒ\\tll…ll„ll„ll„ll„ll„ll„ll„ll„ll„ll„ll…\\tkkƒll„ll„ll„ll„ll„ll„ll„ll„ll„ll„jj‚mm‚ãããçççæææææææææãããõõ𜜰g¹¹§ºº·¹¹³¹¹³¹¹³¹¹³¹¹³¹¹³¹¹³¹¹³¹¹³¸¸²  šºº´¹¹³¹¹³¹¹³¹¹³¹¹³¹¹³¹¹³¹¹³¹¹³¹¹³ºº´  š¸¸±¹¹³¹¹²»»²¼¼²¼¼²¼¼²¼¼²»»²¹¹³¹¹³ºº´§§¢áááçççæææææææææãããööð››°fªªŸªª®©©ª©©ª©©ª©©ª©©ª©©ª©©ª©©ªªªª¨¨©“““«««©©ª©©ª©©ª©©ª©©ª©©ª©©ª©©ª©©ª©©ª«««“““¨¨©©©ª««¬  ±°žž±žž±°¢¢±¬¬«©©ªªª«œœœáááçççæææææææææãããööð››°f­­¡­­°¬¬¬¬¬¬¬¬¬«««ªª©ªª©ªª©ªª©ªªª©©¨“““«««ªª©ªª©ªª©ªª©ªª©ªª©ªª©ªª©ªª©ªª©«««“““§§¦²²³{ttŠŠ'……%……%‹‹%mm ³³²¬¬«žžžáááçççæææææææææãããööð››°f­­¡­­°¬¬¬¬¬¬«««°°°³³¹²²¹³³¹³³¹³³¹±±·šš ´´º²²¸³³¹³³¹³³¹³³¹³³¹³³¹³³¹³³¹²²¸´´ºšš ¯¯´½½ÆzzwÛÛÿÿþþüüÿÿÂÂ~~‡¶¶´«««žžžáááçççæææææææææãããööð››°f­­¡­­°¬¬¬«««¯¯°šš˜‚‚l‡‡n††n††n††n……mww_††n……m††n††n††n††n††n††n††n††n……m††nww_ƒƒku^^GÜÜÿÿûûúúÿÿÁÁ~~ˆ¶¶´«««žžžáááçççæææææææææãããööð››°f­­¡­­°¬¬¬­­ª¨¨µxx3sshh kk kk kk jj ii kk kk kk kk kk kk kk kk kk kk kk kk ii jj pp LLààÿÿþþüüÿÿÂÂ~~‡¶¶´«««žžžáááçççæææææææææãããööð››°f­­¡­­°¬¬¬­­ª©©¸pp wwQ¥¥¾  «¡¡®¡¡®  ­ŠŠ—¢¢¯¡¡®¡¡®¡¡®¡¡®¡¡®¡¡®¡¡®¡¡®¡¡®¡¡®¢¢¯ŠŠ—žžªªªºppqÚÚÿÿûûúúÿÿÁÁ~~ˆ¶¶´«««žžžáááçççæææææææææãããööð››°f­­¡­­°¬¬¬­­ª©©¸ooO´´¼®®©¯¯¬°°­®®«˜˜•±±®¯¯¬¯¯¬¯¯¬¯¯¬¯¯¬¯¯¬¯¯¬¯¯¬¯¯¬¯¯¬±±®˜˜•¬¬¨ºº¹xxoÛÛÿÿþþüüÿÿÂÂ~~‡¶¶´«««žžžáááçççæææææææææãããööð››°f­­¡­­°¬¬¬­­ª©©¸oo||O°°»ªª©¬¬¬¬¬¬ªªª”””­­­«««¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬«««­­­”””©©¨´´µ~rr ‡‡*ƒƒ(ƒƒ(ˆˆ)ll$ŽŽ‘³³²¬¬¬žžžáááçççæææææææææãããööð››°f¬¬ ¬¬¯«««­­©¨¨·oo||N°°»ªª¨«««¬¬¬ªªª”””­­­««««««««««««««««««««««««««««««­­­”””ªªª«««®®®¤¤´¡¡³¡¡³¡¡²¡¡³¦¦´®®­«««¬¬¬áááçççæææææææææãããöö𛛯g°°¤°°³¯¯¯±±­¬¬¼pp~~P´´¿®®¬¯¯¯°°°®®®———°°°¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯°°°–––­­­¯¯¯®®®±±­±±­´´°µµ±±±­°°­®®¯¯¯¯°°°ŸŸŸáááçççæææææææææãããööð››°dššŽšš™™™››˜••¤llttFœœ§˜˜—™™™ššš˜˜˜ŠŠŠœœœ››››››››››››››››››››››››››››››œœœ‹‹‹ššš›››››››››‘‘‘ŠŠŠžžžššš›››››››››•••ãããçççæææææææææãããööð››°e££—¤¤¦¢¢¢¤¤¡ŸŸ®nnxxJ¦¦±¡¡ £££¤¤¤žžž¢¢¢ÜÜÜÖÖÖ×××××××××××××××××××××××××××ÙÙÙ®®®ÕÕÕØØØ×××ÔÔÔëëëeee***æææÕÕÕ×××ÖÖÖÜÜܳ³³ÞÞÞèèèæææææææææãããöö𛛯g¯¯£¯¯²®®®¯¯¬««»pp}}P³³¾­­«®®®°°°©©©«««ïïïéééèèèééæééæééæééæééæèèæééééééììì¹¹¹çççêêêêêêåååÿÿÿkkk+++úúúçççêêêèèèïïï¼¼¼ÜÜÜèèèæææææææææãããööð››°f¬¬ ­­¯«««­­ª¨¨¸oo||O°°»ªª©¬¬¬­­­¦¦¦©©©ëëëãããëëíèèöææõççõççõææõëëõèèçäääèèè···ãããæææåååáááúúúiii)))öööãããåååäääëë뺺ºÝÝÝèèèæææææææææãããööð››°f­­¡­­°¬¬¬­­ª©©¸oo||O±±¼««©¬¬¬­­­§§§©©©éééïïñ¥¥@‘‘OŽŽLŽŽM‘‘K}}PÒÒÖêêêççç···ãããçççæææâââûûûiii)))öööãããæææåååëë뺺ºÝÝÝèèèæææææææææãããööð››°f­­¡­­°¬¬¬­­ª©©¸oo||O±±¼««©¬¬¬­­­§§§©©©ééçðð÷’’vççÿÿýýúúÿÿ­­»»Íððìççç···ãããçççæææâââûûûiii)))öööãããæææåååëë뺺ºÝÝÝèèèæææææææææãããööð››°f­­¡­­°¬¬¬­­ª©©¸oo||O±±¼««©¬¬¬­­­§§§©©©ééçðð÷““xééÿÿþþüüÿÿ¯¯¼¼Íððìççç···ãããçççæææâââûûûiii)))öööãããæææåååìì츸¸ÜÜÜèèèæææææææææãããööð››°f­­¡­­°¬¬¬­­ª©©¸oo||O±±¼««©¬¬¬­­­§§§©©©ééçðð÷’’vééÿÿþþüüÿÿ®®»»Íððìççç···ãããçççæææâââûûûiii)))öööãããæææäääîî¨ÙÙÙéééæææææææææãããööð››°f­­¡­­°¬¬¬­­ª©©¸oo||O±±¼««©¬¬¬­­­§§§©©©ééçðð÷’’wææÿÿûûøøÿÿ­­¼¼Íððìççç···ãããçççæææâââûûûiii)))öööãããæææåååëëë»»»ÝÝÝèèèæææææææææãããööð››°f­­¡­­°¬¬¬­­ª©©¸oo||O±±¼««©¬¬¬­­­§§§©©©ééçðð÷’’vééÿÿþþüüÿÿ®®»»Íððìççç···ãããçççæææâââûûûiii)))öööãããæææåååëë뺺ºÝÝÝèèèæææææææææãããööð››°f­­¡­­°¬¬¬­­ª©©¸oo||O±±¼««©¬¬¬­­­§§§©©©ééèññô””†ˆˆŸŸ$ ŒŒ ¡¡uu"ÉÉÑííëççç···ãããçççæææâââûûûiii)))öööãããæææåååëë뺺ºÝÝÝèèèæææææææææãããööð››°f¬¬ ¬¬¯«««­­©¨¨·oo||N°°»ªª¨«««­­­¦¦¦©©©êêêäääããåÏÏàÖÖù{{G{{GÕÕùÖÖáææåäääççç¶¶¶âââååååååáááùùùiii***õõõâââåååãããêêê¹¹¹ÝÝÝèèèæææææææææãããöö𛛯g°°¤°°³¯¯¯°°­¬¬¼pp~~P´´¿®®¬¯¯¯±±±ªªª­­­òòòëëëíííððéùùÿJJúúÿïïéììíìììïïï»»»éééíííìììèèèÿÿÿlll+++ýýýêêêìììëëëòòò½½½ÜÜÜèèèæææææææææãããööð››°ežž’žž¡žž›™™¨mmuuH  «œœšžžž™™™›››ÌÌÌÇÇÇÇÇÇÆÆÄËËÙ}}>}}>ËËÙÆÆÄÈÈÈÇÇÇÉÉÉ¥¥¥ÇÇÇÊÊÊÉÉÉÆÆÆÚÚÚeee111×××ÇÇÇÉÉÉÉÉÉÍÍͬ¬¬ßßßèèèæææææææææãããööð››°eŸŸ“ŸŸ¢žžž  ššªmmvvI¢¢­œŸŸŸ   šššÏÏÏÊÊÊËËËÊÊÇÏÏÝ??ÏÏÝÊÊÇËËËÊÊÊÏÏÏœœœ˜˜˜œœœœœœœœœœœœœœœœœœœœœ›››–––âââçççæææææææææãããöö𛛯g°°¤°°³¯¯¯°°­¬¬»pp~~P´´¿®®¬¯¯¯°°°©©©¬¬¬òòòëëëìììëëèóóÿ‰‰I‰‰Ióóÿëëèìììëëëòòò¬¬¬ªªª±±±¯¯¯¬¬¬¬¬¬¬¬¬­­­¬¬¬¬¬¬¯¯¯¯¯¯±±±ŸŸŸáááçççæææææææææãããööð››°f¬¬ ¬¬¯«««­­ª¨¨¸oo||N°°»ªª¨«««­­­¦¦¦©©©êêêäääåååääáììú‡‡G‡‡Gììúääáåååäääêêê©©©¦¦¦¬¬¬°°°ººº¹¹¹¹¹¹¹¹¹¹¹¹¹¹¹®®®«««¬¬¬áááçççæææææææææãããööð››°f­­¡­­°¬¬¬­­ª©©¸oo||N°°º©©¨«««¬¬¬¦¦¦¨¨¨êêêãããåååããáëëù‡‡G‡‡Gëëùããáåååãããêêꨨ¨¤¤¤²²²‹‹‹IIIQQQOOOOOOPPPMMM˜˜˜¯¯¯«««áááçççæææææææææãããööð››°f­­¡­­°¬¬¬­­ª©©¸ooQ··Á°°®²²±³³²¬¬«¯¯®óóòììëíííììéõõÿ‰‰J‰‰Jõõÿììéíííììëóóò¯¯®©©©¿¿¾rrrŒŒ‹ºº¹±±°¢¢¡áááçççæææææææææãããööð››°f­­¡­­°¬¬¬­­ª¨¨¸qq qqF™™¨••—––š˜˜›’’•””—ÏÏÒÉÉÌÊÊÍÉÉÊÎÎà@@ÎÎàÉÉÊÊÊÍÉÉÌÏÏÒ””—’¢¢¥bbdwwz¡••˜âââçççæææææææææãããööð››°f­­¡­­°¬¬¬¬¬ªªª¶{{?rreehhhhhhhhhhhhhhhhhhcczzzzcchhhhhhhhhhffooCCRRnnccxxææåææçæææææææææãããööð››°f­­¡­­°¬¬¬««¬¯¯®¢¢¦Œ““Ž‘‘Ž‘‘Ž’’‰ŒÆÆÂÀÀ½ÁÁ¾ÁÁ¾Â¾¾¾¿¾¾¿Â¾ÁÁ¾ÁÁ¾ÀÀ½ÆÆÂŒ‹‹‡™^^\ssp˜˜•ŒŠŠ‡âââçççæææææææææãããööð››°f­­¡­­°¬¬¬¬¬¬««¬®®­³³´²²³²²³²²³´´µ­­®°°±ôôõîîîïïðïïðïïðïïïïïïïïðïïðïïðîîîôôõ°°±ªª«ÀÀÁsss»»¼²²³¢¢£áááçççæææææææææãããööð››°f­­¡­­°¬¬¬¬¬¬¬¬¬¬¬¬ªªª««««««««ª¬¬¬¥¥¥¨¨¨éééãããääääääääääääääääääääääääãããéé騨¨£££···qqq  ‰‰‰²²²ªªªœœœáááçççæææææææææãããööð››°f¬¬ ­­¯«««¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬­­­¦¦¦©©©êêêäääååååååååååååååååååååååååäääêêê©©©¦¦¦®®®§§§žžžŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸ©©©¬¬¬¬¬¬áááçççæææææææææãããõõ𜜰h°°¤°°³¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯±±±ªªª­­­ñññêêêëëëëëëëëëííííííëëëëëëëëëêêêñññ­­­ªªª±±±±±±³³³³³³³³³³³³³³³³³³°°°¯¯¯±±±   áááçççæææææææææãããööð››°ežž’žž¡žžž™™™›››ÔÔÔÏÏÏÐÐÐÐÐÐÑÑÑÊÊÊÊÊÊÑÑÑÐÐÐÐÐÐÏÏÏÔÔÔ›››™™™žžžœœœœœœœœœœœœœœœœœœ”””âââçççæææææææææåååëëéÏÏÖŸŸ½ÃÃÀÃÃÄÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÅÅźºººººÅÅÅÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÂÂÂÇÇÇææææææææææææææææææåååëëéõõîííîíííííííííííííííííííííííííííííííííííííííííííííííííííïïïïïïííííííííííííííííííííííííííííííííííííííííííííííííííííííìììæææææææææææææææææææææåååããäååäåååååååååååååååååååååååååååååååååååååååååååååååååååääääääåååååååååååååååååååååååååååååååååååååååååååååååååååäääåååææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææ( @ æææååæéééììëììêììêììêììêììêììêììêììêììêììêììêììêììêììêììêììêììêììêììêììêììêììêììêììêììëëëêææææææååæèèèÝÝÜÐÐÕÑÑÖÑÑÖÑÑÖÑÑÖÑÑÖÑÑÖÑÑÖÒÒÖÑÑÖÑÑÖÑÑÖÑÑÖÑÑÖÑÑÖÑÑÖÑÑÖÒÒÖÑÑÖÑÑÖÑÑÖÑÑÖÑÑÖÑÑÖÑÑÖÑÑÕÓÓ×åååæææéééÝÝÜ++~%%p++t**s**s**s**s**s**s''p**s**s**s**s**s**s**s**s((p**r**s))q))q))q))q**s''q33xÙÙÞêêèììêÑÑÖ**r¨¨ ««¨ªª¦ªª¦ªª¦ªª¦ªª¦««§™™–©©¥ªª¦ªª¦ªª¦ªª¦ªª¦©©¥¬¬¨››—¦¦¢¬¬¨°°¬±±¬°°¬±±­¬¬¨««§  ÜÜÛéééììêÑÑÖ++t««¨®®°­­®¬¬­¬¬«¬¬«¬¬«­­¬œœ›««ª¬¬«¬¬«¬¬«¬¬«¬¬««««®®­œ©©¨©©¨‘ŽŽ’’ŒŒ¡¡¢°°±££¤ÜÜÜéééììêÑÑÖ**sªª¦­­®«««®®¯±±»±±»±±»²²¼  ª°°º²²¼±±»±±»±±»±±»±±»´´½  ©´´¾““¯¯ÛÛÔÔÈÈ……b²²º¡¡ŸÜÜÜéééììêÑÑÖ**sªª¦¬¬­®®¯  ™……Y‚‚U‚‚VƒƒVzzN‚‚U‚‚V‚‚V‚‚V‚‚V‚‚V‚‚UƒƒWzzM……WkkHÔÔÿÿÿÿõõŒŒb°°º¢¢ ÜÜÜéééììêÑÑÖ**sªª¦¬¬«±±º……\qq$„„_‚‚TƒƒVzzN‚‚U‚‚V‚‚V‚‚V‚‚V‚‚V‚‚UƒƒWzzN……WkkIÔÔÿÿÿÿõõd°°º¢¢ ÜÜÜéééììêÑÑÖ**sªª¦¬¬«±±»‚‚U……`¸¸Ì°°¸³³¼  ª°°º²²¼²²»²²¼²²¼²²¼±±»´´¾  ªµµ¿““žËËþþööêꊊb±±º¢¢ ÜÜÜéééììêÑÑÖ**sªª¦¬¬«±±»‚‚V‚‚T°°¸©©¦¬¬ª››™ªª©¬¬ª««ª««ª««ª««ª««©­­¬œœšªª©¡¡Ÿ††cŽŽbŒŒbˆˆ^••²²³¢¢¢ÜÜÜéééììêÑÑÖ**s««§­­¬²²¼ƒƒVƒƒV³³¼¬¬ª®®®›››¨¨¨ªªª©©©©©©©©©©©©©©©«««›››¥¥¥­­¬­­µ¯¯¹¶¶À¬¬¶­­¯ªªª¡¡¡ÜÜÜéééììêÒÒÖ''p™™–œœ›  ªzzNzzN  ª››™›››•••­­­¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¬¯¯¯©©©¬¬¬¯¯®››™ssq°°®ªªª®®®£££ÜÜÜéééììêÑÑÖ**s©©¥««ª°°º‚‚U‚‚U°°ºªª©¨¨¨­­­êêêéééïïìïïìïïìïïìèèèìììÉÉÉáááèèèôôô´´´AAAõõõåååíííÎÎÎØØØêêêììêÑÑÖ**sªª¦¬¬«²²¼‚‚V‚‚V²²¼¬¬ªªªª¬¬¬ééèààáÉÉÖÉÉ×ÉÉ×ÉÉÖààáëëêÇÇÇÞÞÞæææñññ³³³BBBòòòâââêêêÌÌÌÙÙÙêêêììêÑÑÖ**sªª¦¬¬«±±»‚‚V‚‚V²²¼««ª©©©««ªòòõ´´¨­­ÉÉÉÉ­­³³§ôô÷ÆÆÅßßßæææòòò³³³@@@óóóãããëëëÍÍÍÙÙÙéééììêÑÑÖ**sªª¦¬¬«±±»‚‚V‚‚V²²¼««ª©©©««ªññö³³£ââÿÿÿÿââ³³£óóøÆÆÅßßßæææòòò³³³@@@óóóâââëëëÉÉÉ×××êêêììêÑÑÖ**sªª¦¬¬«±±»‚‚V‚‚V²²¼««ª©©©««ªññõ´´¥ááÿÿÿÿáá´´¤óó÷ÆÆÅßßßæææòòò³³³@@@óóóâââìììÆÆÆÖÖÖêêêììêÑÑÖ**sªª¦¬¬«±±»‚‚V‚‚V²²¼««ª©©©««ªññö³³£ßßÿÿÿÿßß³³£óóøÆÆÅßßßæææòòò³³³@@@óóóãããëëëÍÍÍÙÙÙéééììêÑÑÖ**s©©¥«««±±»‚‚U‚‚U±±»««©©©©««ªîîïÃþ¤¤b——@‰‰&££cÃýïïñÆÆÅÝÝÝäääððð²²²AAAñññáááéééËËËÙÙÙêêêììêÑÑÖ**s¬¬¨®®­´´½ƒƒWƒƒW´´¾­­¬«««¯¯¯ëëëëëëøøÿ´´ ‘‘]øøÿëëêíííËËËåååìììøøø···BBBùùùéééñññÑÑÑØØØêêêììêÒÒÖ((p››—œ¡¡«{{N{{N¡¡«››››ÉÉÊÅÅÄÎÎÒžž}……IÍÍÕÅÅÃËË˰°°¹¹¹¾¾¾ÅÅÅŸŸŸWWWÆÆÆ¼¼¼ÁÁÁ°°°ÛÛÛéééììêÑÑÖ**r¦¦¢¨¨§­­·€€T€€T®®¸¨¨¦¦¦¦©©©áááÜÜÛèèï¬¬ŽŒŒSççòÜÜÚååå¹¹¹¦¦¦£££§§§®®®£££¤¤¤¥¥¥ÜÜÜéééììêÑÑÖ**s««§­­¬²²¼ƒƒV‚‚U±±»««©©©©¬¬¬èèèääâðð÷±±“Vïïúããáííì¾¾¾¥¥¤¯¯¯°°°¯¯¯­­­°°°®®®®®®£££ÜÜÜéééììêÑÑÖ**sªª¦¬¬«±±»‚‚V……\··Å°°²®®²±±µððôëëîøøÿ¶¶›’’\÷÷ÿêêìôôøÂÂÇ®®²››žqqt½½Â¤¤¨ÜÜÜéééììêÑÑÖ**sªª¦¬¬«±±»„„Yww@šš’––„””„––†ÅÅ´ÁÁ°ÊÊÀ››rƒƒCÉÉÂÁÁ¯ÈÈ·££“––„qVVL¢¢ŽŽÜÜÛéééììêÑÑÖ**sªª¦¬¬¬¯¯³——…vv+ss1ss0rr/ss0„„Aƒƒ@‚‚@‰‰AŽŽA@ƒƒ@……Bww5uu/aa)DDzz1tt6ÝÝÙééêììêÑÑÖ**sªª¦­­®¬¬«®®±¬¬¶­­µ­­¶ªª³­­¶ììõééòêêóééóççóêêóèèñððù¾¾Ç««´’’šbbh»»Å  ¨ÛÛÜéééììêÑÑÖ++sªª¦­­®¬¬¬«««¬¬ª¬¬ª­­ªªª§­­ªççåääâååãååâååâååãããáëëé½½»©©§šš˜000111444(()xxw¶¶´¡¡ŸÜÜÜéééììêÑÑÖ**s««§®®¯­­­­­­­­­­­­®®®«««®®®íííêêêëëëëëëìììëëëéééñññÁÁÁ¥¥¥±±±·········¸¸¸±±±®®®£££ÛÛÛéééëëêÓÓ×33x  ££¤¢¢¢££££££££££££¡¡¡£££ÎÎÎÌÌÌÍÍÍÉÉÉÆÆÆÍÍÍËËËÑÑѰ°°¤¤¤   ¡¡¡¡¡¡   ¢¢¢£££ÝÝÝèèèæææåååÙÙÞÜÜÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜØØØÙÙÙÙÙÙ×××ÖÖÖÙÙÙÙÙÙØØØÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÛÛÛÝÝÝææææææææææææêêèéééééééééééééééééééééééééééêêêêêêéééêêêêêêéééêêêêêêéééééééééééééééééééééééééééèèèææææææ(  ççæÑÑÚÇÇÔÉÉÕÈÈÔÉÉÕÈÈÕÈÈÕÈÈÕÈÈÕÉÉÕÈÈÓÊÊÑÈÈÒËË×ääåÑÑÚ]]Œvv“ss’uu”ppss‘tt“tt“ss’ppŽttšmm ppš{{–ÛÛÞÈÈÔxx”½½²³³²´´¯««¦°°«´´®³³®²²«ªª¬ªªzÀÀB¬¬l°°²ÞÞÜÉÉÕss’³³²ˆˆf……_ƒƒ`……b‡‡d‡‡dˆˆazzf¦¦-ÿÿÁÁ3¡¡´ààÛÈÈÕuu”´´¯‡‡c¬¬¬¥¥¥§§§ªª©©©©©©§¡¡«££hÊÊ(¨¨X¦¦°ÞÞÜÉÉÕpp««¦ƒƒ`¥¥¥¡¡¡­­­´´´³³³®®¯§§¦¯¯¶’’§¨¨²¯¯®ÝÝÝÈÈÕss‘°°«……b§§§­­­ßßßÓÓÕÓÓÕßßßÓÓÓíí쉉†ØØÖÝÝÝÝÝÝÈÈÕtt“´´®‡‡dªª©´´¸ÏÏÁÛÛÛÛÏÏÁÙÙÝïï‰ÚÚÚÞÞÞÜÜÜÈÈÕtt“³³®‡‡d©©¨´´¸ÎξîîîîÎξÙÙÝîî퉉‰ÙÙÙÝÝÝÜÜÜÈÈÕss’²²­††c¨¨¨¯¯¯ÞÞß³³««rÞÞàÖÖÖïï‡ÙÙÙàààÝÝÝÉÉÕppŽ««¦ƒƒ_¢¢¡¥¥£ÛÛཽ±³³Ÿßßä²²°½½½¦¦¦¹¹¹³³²ÝÝÝÈÈÕuu“´´®ˆˆf­­±±±´ððøË˹¾¾¦õõýºº½€^^]yyz¯¯²ÝÝÝÈÈÕtt’µµ²††^‡‡a‹‹h¬¬Œ¡¡sk­­™™r<<,))––sÛÛÙÈÈÕtt’´´°©©ª¤¤Ÿ©©¤ÜÜÖááÞááÞÝÝØ¸¸³XXVHHF¬¬§ÛÛÛËË×zz–²²­ªª«¬¬­¯¯°ÜÜÝÜÜÝÛÛÜßßà´´µªª«­­­¬¬­­­®ÞÞÞääåÛÛÝÞÞÝÝÝÝÝÝÝÝÝÝÝÝÝÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞååå(0` åååééæççêëëëççÛèèÛ½½Æ//‚r kõõò››°hmm{ll„\\t¹¹§ººººº³³³³¡¡œ±±­œœœ¥¥¥f¬¬«¡¡®””•¢¢²››¬ññ쪪Ÿ~xx‹‹&……%oo“ÖÖág­­¡­­±©©¹²²»––™¢zzwÛÛýýÂÂ~~‡››”xxou††nww_^^G®®~~ˆxx3sskk iiLLää‹‹‡wwQ¥¥¾rrqÿÿÜÜÜ||Nqqˆˆ)„„)mm"°°¤~~P··ÁššŽ••¤vvIŒŒ‹££—}}DÕÕÕiii***ûûüîîñççõììúdde††F‘‘M‹‹Jôôÿ’’vé黻͓“x””†‹‹ ŸŸ$¡¡rr!ÎÎÓÎÎàÖÖùËËËÄÄÄÍÍÛ}}?ÊÊÇ111MMMssF wwzddzzCCRR’’ŽÁÁ¾^^\      !"###$%& '()*++,++++++-)./000012& '(345666646666666666667658/00009: '()*;<====>================?@00001A '())$BC%%*D/E0001:F  )*$G34/000012- '()*HG+ HIJ#JK% '*KG+,* *'L*$MN,),) O,,3P$Q-,,,A,,,R,,A,,, SHT-FUFUUFUUFFUFUUUUVWUUUFF '()*HM+XVWXYF  ()C$M+ZZZZZ[X\W F '()*KM+Y]^__^GUXVW & '())$G*`ab00009cXVW & '(*$G+YdbE0009cX\W F '*KG+[d@E0009cXVW`F  *$G+ d@E0009cXVW & L)L*$G+[db00009cXVW F *HG+ efgffhijXVW &F '*$G+)klTTl& VWXF '()*HG+) X__XYXVWX F S-$Q,mnnnopponqqqqmqqF\rUnqqm& 3-3$Q-,-UqmmoJGkqmmj,,,-,,'()*HG+ `__`  *HG+[]][ '()*HG*[]][Assssss,& '())HMN `__` )DttttttR '()*Ku,,,jmmqkppkqmqU,%\tvttvtw,& ')*T>>>x>>>xyyxx>>x>x>ztttttt{=x! ()R||||An}}}}}n}nRA~ttttttD3RA ' YYY  Y }DttttttR) ()DtvvvvtA, '(- '())Y )& 3-UmUjUqnUUjUU,,,,-,UCnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnq YY Y( @äääëëêòòóÛÛÛÑÑÖ++~''p**s33x¡¡¬¬«ªª¦šš–±±¬³³³­­´••ŽŽ‘œœœ£££²²»¡¡ª““œ®®ÞÞÔÔÊÊ……b‚‚VzzNkkIÿÿõõŒŒb¯¯¹qq$……[¸¸Ì··Ãêê•••rrsÌÌÌAAAóóúÊÊÖÅÅÅÉɳ³¤ââÊÊÁêêóÃþ¤¤c——@‰‰&øøü’’]žž}……I»»»WWWççó¬¬ŽŽŽU±±“ïïú½½Å¶¶›(()zz1––…ÈÈ·››rÃò££’||tVVLŽŽtt.tt2ƒƒAŒŒAaa)DDbbh222         !" #$ ! %&& '!" "   !!$     "&" (   )   *+,*  ----.+*    // *+*  0110,2+* &  0110,2+*  010,2+*  3456754.+*0 & 8098*8+83* *2-:;-2* <.=.<. "" >?@><    ,A@BC    $%38D98,.EFEG)C  &$H(IIIJ<2K;*LJMINOOOOPMQ IRRSRS7;TU7TTTSHVOOOOWHS >>>>3>,COOOOXC  < YYYF)   .<< -*******  ( ççæÑÑÚÇÇÔÉÉÕÈÈÔÈÈÕÈÈÓÊÊÑÈÈÒËË×ääå]]Œvv“ss’uu”ppss‘tt“ppŽttšmm ppš{{–ÛÛÞxx”½½²³³²´´¯««¦°°«´´®³³®²²«ªª¬ªªzÀÀB¬¬l°°²ÞÞ܈ˆf……_ƒƒ`……b‡‡dˆˆazzf¦¦-ÿÿÁÁ3¡¡´ààÛ‡‡c¬¬¬¥¥¥§§§ªª©©©©©©§¡¡«££hÊÊ(¨¨X¦¦°¡¡¡­­­´´´³³³®®¯§§¦¯¯¶’’§¨¨²¯¯®ÝÝÝßßßÓÓÕÓÓÓíí쉉†ØØÖ´´¸ÏÏÁÛÛÙÙÝïï‰ÚÚÚÞÞÞÜÜÜ©©¨ÎξîîîîíÙÙÙ²²­††c¨¨¨¯¯¯ÞÞß³³««rÞÞàÖÖÖïï‡àààƒƒ_¢¢¡¥¥£ÛÛཽ±³³Ÿßßä²²°½½½¦¦¦¹¹¹uu“­­±±±´ððøË˹¾¾¦õõýºº½€^^]yyz¯¯²tt’µµ²††^‡‡a‹‹h¬¬Œ¡¡sk­­™™r<<,))––sÛÛÙ´´°©©ª¤¤Ÿ©©¤ÜÜÖááÞÝÝØ¸¸³XXVHHF¬¬§ÛÛÛzz–ªª«¬¬­¯¯°ÜÜÝÛÛÜßßà´´µ­­®ÛÛÝÞÞÝååå    !"#$%& '()*++,-./0123456789:;<=>&)5?@ABCDEFGHI*6@JKKJLMNOII+7PQRRQSTUVWX+YPZ[[ZS\U]IX ^_`abcdefgh]iIjklmnopqrstIu'vwxyz{|}~€I‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”••–—˜™š›œ ^žŸ ¡¡¢£¤ž@Ÿ¥W ¦§IIIIXXIIIIIW¨(0`€€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷÷ÿÿ÷ÿ÷ÿ÷÷ÿñq‡ˆxˆxˆˆˆˆˆˆˆˆˆxˆ‡ˆˆˆˆˆñ‡wwwwwwwwwwwwwwwwwwñ‡wwwwwwwwwwwwwxwwwwwww‡ð‡wwwwww‡wwwwwwwwx‡ˆx‡wq‡wwwwww‡wwwwwwxwvnnngwñ‡wwwwwwwwwwwwwwwxîîægwð‡wwˆˆ†ˆhˆˆˆˆ†ˆˆ†€îîîgwq‡wwff†fff†f€fffînîˆwñwww†www‡wwwwxwxwvîîîgwwq‡ww†www‡wwwwwwwwxîîîgwñwww†www‡wwwwwwxwxhffgwwð‡ww†wwwwwwwwwwxwxx‡wwwq‡ww†xwwwwwwwwwøwww÷wwwwñ‡ww†www‡wwwwwwwwwwwwwwq‡‡‡†‡‡xˆxˆxwxwxx‡‡ˆxwwñ‡ww†wwwÿÿÿÿÿÿ÷ÿÿÿ€ÿÿq‡ww†wwwÿÿÿÿÿÿ÷ÿÿ€ÿÿÿ÷ñ‡wwf‡wwÿÿÿ÷ÿ÷÷ÿÿÿpÿÿñ‡wwˆwwwÿwxwwÿ÷ÿ€÷ÿÿwq‡ww†wwwÿ†nfèÿ÷ÿÿ€ÿÿÿñww€wwwÿnîîè÷÷ÿÿÿpÿ÷q‡wwfwwwÿŽîîèÿ÷ÿÿpÿÿÿñ‡ww†wwwÿŽîîèÿ÷ÿ÷ÿ€ÿÿñ‡w‡†wwwÿŽîîèÿ÷ÿÿpÿÿwñ‡ww†wwwÿnîîæ÷÷ÿÿÿpÿÿÿð‡ww€www÷†næhÿ÷ÿÿ€ÿÿÿq‡ww†wwwÿwxhwÿ÷ÿÿ€ÿÿñ‡wwfwwwÿÿøoÿÿ÷ÿÿÿ€ÿÿÿwq‡wwˆwwwÿÿøoÿÿ÷ÿÿÿpÿÿÿñ‡‡w†‡‡‡‡wwxgwww‡w€wwwwq‡ww†‡wx÷øoÿ÷÷xwwwwwwñ‡ww†wwwÿÿøgÿÿ÷wwwwwwwð‡ww†www÷ÿxo÷ÿ÷wwwwwwwñ‡wwfwwwÿÿøoÿ÷ww‡ˆw‡wq‡ww†wwwÿ÷÷oÿÿ÷‡pwñ‡ww€wwwÿÿøoÿÿ÷wxwñ‡ww†ˆ‡ˆˆxxxhˆ‡ˆˆ€†‡q‡wwvfffffffffhff`foñ‡www‡wxÿ÷‡pwð‡wwwwwwÿÿÿÿÿÿ÷wøwñ‡wwwwwwÿÿÿÿ÷wvwwqwwwwwww÷ÿ÷ÿÿÿ÷wxˆ‡ˆwwq‡wwwwwwÿÿÿÿÿÿ÷wwwwwwwñ‡wwwwwwÿÿÿÿ÷ÿ÷wwwwwwwq‡xx‡‡w‡‡wwww÷ww‡‡xwwxwÿÿÿ÷ÿ÷÷ÿÿ÷ÿÿ÷ÿÿ÷ÿÿ( @€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ÷wwwwww÷wwww÷qpw‡‡‡xxx‡‡x‡wxwñww‡w‡w‡w‡xxˆ‡w‡xxwwxxx‡wwwxnf‡wqwxˆˆxˆxˆˆˆ†îîˆwq‡xffh†††hf†îî‡wqwˆgwx‡x‡x‡vîñwxgw‡‡wwxxxæf‡‡p‡xh‡xw‡xww‡ˆwwqwxˆwxxx‡‡ˆxw‡xwqxxhˆ‡ww‡wwwx‡wwxwxgxwÿÿ÷÷wøÿq‡xˆw‡÷wwÿwÿøwqwxg‡‡ønæ÷÷vÿwqxxgwwøîîwÿøowqwxgx‡wîîwx‡ÿwqwxgwwøîîÿx‡xxxh‡‡÷fhw÷øÿð‡xgww÷÷oÿ÷÷v÷wqxˆg‡‡wø‡ww÷øwq‡xˆx‡wøowxˆˆ‡‡qxx‡‡wÿø‡ÿxwwwwwx‡xhw‡÷øo÷wxˆˆˆwq‡x‡xÿ÷ÿ÷v‡wxwxfˆh††hh†€h‡qxxˆ†ˆˆgˆˆ†€`h‡qwwxwwÿÿÿøx‡q‡ˆwwˆ÷wÿxx€‡wxwwxxwÿÿ÷ÿ÷‡wwxwqxwx‡‡÷wwwxx‡xx÷wwwwww÷÷( €€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿww÷wwwwxˆˆˆˆˆˆ‡xwx‡wxgxxˆˆˆˆæxˆw‡xˆæxx‡www‡wøx‡wxˆw~ç÷‡÷øx‡~ç‡÷xˆwx‡w÷xx‡÷ww‡xˆw÷xˆ‡xxˆˆg€‡xxw÷xwøw‡÷÷wwww÷w÷puzzles-20170606.272beef/icons/mines.ico0000644000175000017500000006117613115373736016632 0ustar simonsimon 00 ¨%–  ¨>& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $ææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååæææææææææææææææææææææçççéééèèèèèèèèèèèèèèèèèèèèèèèèééééééèèèèèèèèèèèèèèèèèèèèèèèèéééèèèèèèèèèèèèèèèèèèèèèèèèèèèéééèèèèèèèèèèèèèèèèèèèèèèèèèèèêêêææææææææææææææææææåååéééÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿéééåååææææææææææææäääìììáááµµµ¶¶¶¶¶¶µµµµµµ¶¶¶¶¶¶²²²ÙÙÙÔÔÔ²²²¶¶¶µµµµµµµµµ¶¶¶µµµ···äääÃÃó³³¶¶¶µµµµµµµµµ¶¶¶´´´ÃÃÃäää···µµµ¶¶¶µµµµµµ¶¶¶¶¶¶²²²ÒÒÒÿÿÿèèèåååææææææææææææåååëëëöööÊÊÊÈÈÈÈÈÈÈÈÈÈÈÈÇÇÇÎÎΪªª¿¿¿òòòÃÃÃÉÉÉÈÈÈÈÈÈÈÈÈÇÇÇÍÍÍ›››ààààààÄÄÄÉÉÉÈÈÈÈÈÈÈÈÈÉÉÉÃÃÞžžõõõÎÎÎÇÇÇÈÈÈÈÈÈÈÈÈÇÇÇÍÍͰ°°²²²ÿÿÿèèèåååææææææææææææåååêêêüüüëëëíííìììììììììëëëôôôÄÄÄÀÀÀÿÿÿéééíííìììììììììëëëóóó­­­ààà÷÷÷êêêíííìììììììììîîîæææ§§§øøøíííììììììììììììëëëóóóÍÍͶ¶¶ÿÿÿèèèåååææææææææææææåååëëëûûûäääååååååååååååäääììì¿¿¿ÀÀÀýýýáááååååååååååååäääëëë©©©àààòòòâââååååååååååååçççßßߥ¥¥øøøçççäääåååååååååäääëëëÇÇǶ¶¶ÿÿÿèèèåååææææææææææææåååêêêûûûåååææææææææææææåååîîîÀÀÀÀÀÀýýýâââææææææææææææåååìì쪪ªàààóóóãããææææææææææææèèèàà॥¥øøøèèèææææææææææææåååìììÈÈȵµµÿÿÿèèèåååææææææææææææåååêêêûûûåååææææææææææææåååîîîÀÀÀÀÀÀýýýâââææææææææææææåååìì쪪ªàààóóóãããææææææææææææèèèàà॥¥øøøèèèææææææææææææåååìììÈÈȵµµÿÿÿèèèåååææææææææææææåååêêêûûûåååææææææææææææåååîîîÀÀÀÀÀÀýýýâââçççæææææææææåååíííªªªàààóóóãããææææææææææææèèèààদ¦øøøèèèææææææææææææåååìììÈÈȶ¶¶ÿÿÿèèèåååææææææææææææåååêêêûûûåååææææææææææææäääííí¿¿¿ÀÀÀýýýâââææææææææææææåååììì©©©àààóóóãããæææææææææåååçççßßߥ¥¥øøøçççåååæææææææææäääìììÇÇǵµµÿÿÿèèèåååææææææææææææåååêêêûûûæææççççççççççççæææîîîÅÅÅÀÀÀýýýãããççççççççççççæææîî¯ÞÞÞõõõåååèèèèèèèèèèèèéééããã©©©÷÷÷êêêçççèèèèèèèèèçççîîîÎÎη··ÿÿÿèèèåååææææææææææææåååéééýýýûûûûûûúûúúûúúûúúûúýýýöööåååÿÿÿûûûûûûûûûûûûûúúûûûþþþííííííúúúöööôôôóóóóóóóóóóóóøøøäääôôôøøøöööôôôóóóóóóóóóõõõôôôäääÿÿÿéééåååæææææææææåååéé騨ØÇÇÇáâáßÝßâßââßâãßãáßáÜÜÜâââÇÇÇÒÒÒàààÝÝÝÝÜÜÞßßßââÝÝÝÝÝÝÞÞÞððð···¦¦¦¸¸¸¼¼¼¹¹¹¹¹¹¼¼¼©©©®®®åå娨¨­­­ººº»»»¸¸¸ºººººº¡¡¡ÃÃÃÿÿÿèèèåååæææææææææåååêêêÖÖÖÀÁÀßÞßÑÕÑÉÓÉÇÑÇÇÒÇÌÔÌØØØÞÞÞ¾¾¾ÎÎÎÜÜÜÙÙÙÚÚÚÖÑÑÓÉÉÙØØÚÚÚÖÖÖõõõñññÄÄÄiiiZZZdddeeeXXX¨¨¨ªªªôôôëë릦¦^^^[[[hhh^^^jjj±±±¸¸¸ÿÿÿèèèåååæææææææææåååêêêÖÖÖ¿Á¿ìäìd¨d}‹5–5ר×ßßßÀÀÀÏÏÏÝÝÝÙØØâîî²xx… ÔÌÌÝßß×××öööðððáá᪪ªddezzzÐÐЩ©©öööëëëÖÖÖ”””LLN***   ÆÆÆ¶¶¶ÿÿÿèèèåååæææææææææåååêêêÖÖÖÀÁÀæâæ¨Å¨4”4¯É¯¶Ë¶ØØØßßß¿¿¿ÑÔÔÒ—77((ˆ}™==ÛÝÝ×××öööîîîããåììðÿÿÿ††}TTRÿÿÿààߥ¥¥øøøçççææéññôÿÿÿ==6¢¢¡ÿÿÿÆÆÆµµµÿÿÿèèèåååæææææææææåååêêêÖÖÖÂÂÂÝÞÝäÝä¶Ë¶‡T£TåßåÚÙÚÞÞÞ¿¿¿ÑÕÕÑÀÀ€ °vvEE´ÜÞÞ×××öööííîîîãóóàææîXX¸RR©úúîÛÛݦ¦¥÷÷øééèôôãîîàÔÔî##œ››ÇúúðÅÅǵµµÿÿÿèèèåååæææææææææåååêêêÖÖÖÂÂÂÞÞÞÜÚÜëáëÂÐÂh«hæÞæÜÝÜÀÀÀÎÍÍâêê¥[[¯ssºŒŒØÖÖÜßß×ÖÖõõöòòî±±ê[[öüÿccôúúæÛÛ॥¥øøøååè••îFFøýÿ¨¨ìúúëÅÅȵµµÿÿÿèèèåååæææææææææåååêêêÖÖÖÁÂÁâàâ±È±ÀÏÀÜÛÜŠ11áÝáÝÞÝÀÀÀÎÎÎÞààÖÑÑ“44’..ˆÐÃÃÜßß×ÖÖõõöôôì00û ÿÿaaóúúæÜÜদ¦ùùøääévvòüÿÿ§§ëúúëÆÆÉ¶¶¶ÿÿÿèèèåååæææææææææåååêêêÖÖÖ¿Á¿ëäën­n†ˆ~‚¶‚ãÝãÜÞÜÀÀÀÎÎÎÛÙÙÞääÄ¥¥yÐÃÃÜÞÞÖÖÖööõììíîîáððãÃÃèddòïôôäÚÚÝ¢¢¢÷÷÷ææåòòáååã­­éMMó°°èõõéÂÂij³³ÿÿÿèèèåååæææææææææåååêêêÖÖÖÁÁÁßßßÒÖÒ«Æ«˜¾˜·Ë·àÜàØØØÞÞÞ½½½ÑÑÑâââÞÝÝàãã˱±Ç¥¥ÜÙÙßààÛÛÛ÷÷÷õõôëëíííï÷÷íüüíôôíîîïíí츸¸÷÷÷õõõððóôôóþþòÿÿòõõò÷÷÷àààÃÃÃÿÿÿèèèåååæææææææææåååéééÙÙÙ®®®½½½»º¼Â¼ÅƽÉÀ»Â¹º¹ººº»»»···©©©£££¥¥¥£¢¢§­­¨¯¯£¤¤¥¥¥£££ØØØúúúõõõöööôô÷òñôôóôöööøøøðððíííßßßáááßßàÜÜßÜÜßÞÞÞààààààäääÿÿÿéééåååæææææææææåååêêêÖÖÖÂÂÂßÞßÞÞØçéÖèêÕâã×ÙÙÚÛÛÛ×××íííÙÙÙ¨¨¨©©©³³³µ´´´²²´´´­­­™™™£££ÛÛÛÖÖÖ×ÖÖ×ÕÕÜããÜââ×ÖÖÖÖÖÞÞÞííí¯¯¯¥¥¥«««´´´²²²³³³®®®™™™¸¸¸ÿÿÿèèèåååæææææææææåååêêêÖÖÖÁÁÂááÞÂÂÝ’’把箮áÞÞÙÛÛÚÖÖ×êêêúúúççç{{{555)))001&&&‹‹‹¶¶¶£££ßßßÛÜÜÝââßååã£Æ¨¨ÞââÙÙÙÝÝÝúúúõõõ­­­FFF***000(()UUU»»»ºººÿÿÿèèèåååæææææææææåååêêêÖÖÖ¿¿ÂììÜWWïüúÿllíããÙÕÕ×ëëìõõõãããááá¼¼¾ddg œœœæææ­­­£££ßààÔÍÍ˵µÏ¾¾‹!!Ž,,ÖÎÎÚÛÛÝÝÝûûûåååæææÌÌÍ––šZZZÛÛÛÈÈȵµµÿÿÿèèèåååæææææææææåååêêêÖÖÖÂÂÂààÞÃÃÝßßÙôôÖ00÷úØØÛØØÖëëì÷÷÷ââãååæÿÿøÚÚÏ%%%óóóîî¬£¡¡äëë´€‡ƒ|ªeeàèèÜÚÚûûûçççããåììèÿÿÿ??<¢¢£ÿÿÿÄÄͶ¶ÿÿÿèèèåååæææææææææåååêêêÖÖÖÂÂÂÝÝßää×çFFó ývvëããÙÕÕ×ìììõõ÷ééãïïåÄÄê``æÐååäìì묬­£¢¢äë뽕•‹ÒÆÆ‘))“//×ÒÒÙÚÚÝÝÝûûûèèçòòäÙÙæ——ïÒŸŸÝúúìÅÅȵµµÿÿÿèèèåååæææææææææåååêêêÖÖÖÂÂÂÜÜßææ×––åIIó ý‹‹çååÙÔÔ×êêìþþö¸¸è44úÿÿ##ûççåìì쬬­¤¤¤ÞÝÝÞææHH°uuš@@˜99àççØ××ÝÜÝýýûááçddô þÿÿ¨¨ìúúëÅÅȵµµÿÿÿèèèåååæææææææææåååêêêÖÖÖÁÁÂääݲ²ß¦¦â¶¶à ý::õææØÔÔ×êêëúú÷ÓÓæðJJøþ ûèèåììì­­­¤¤¤ÝÝÝÛÞÞÒÆÆŽ""€™@@ÜààØØØÝÜÝüüûææç¬¬ìddõ##üÿ§§ìûûëÆÆÉ¶¶¶ÿÿÿèèèåååæææææææææåååêêê×××ÂÂÄêêßœœåýþ%%û¡¡æääÛ××ÙìììôôõääàôôâîîâÀÀç‘‘ìâââêê騨¨£££âââÛÙÙâêêÀ——¤SSàããÜÛÛàßßúúúååäïïâóóâÜÜä‘‘ìÃÃæññéÃÃIJ²²ÿÿÿèèèåååæææææææææåååêêêÕÕÕ¹¹¹ÙÙÚÖÖÓÑÑÔËËÕÔÔÓÛÛÒÔÔÕÑÑÑçççÿÿÿõõõôô÷õõ÷ýýöþþõöööûûûÙÙÙ©©©ÑÑÑÎÎÎÎÎÎÐÓÓÌÈÈÌÉÉÏÏÏÎÎÎÒÒÒüüü÷÷÷ôô÷óó÷úúöÿÿõùùöùùùëëëÑÑÑÿÿÿéééåååææææææææææææææææææ¹¹¹’’’œœœ¡¡Ÿ  œœœ››žŸŸŸ•••­­­êêêìììèêèçêèæèèäçèêëêëëëïïï···¾½¾ÀÀÀ¼¾¼¼½»½Á¾½À¾¿¿¿ÁÁÁ½½½ÙÙÙïïïëêêìèèëçèéäèëçèìëëëëëðððÿÿÿéééåååææææææææææææåååëëëøøøÍÍͧ§¨˜˜˜££¤¨¨¨£££ŸŸŸ¯¯¯•••ÐÐÐÙÙÙåÜåèÞèéÞéëßëáÛáÖÖÖ×××»»»ÞÞÞâàâðæðïåïñæñòæòãàãáááÓÓÓºººÜÛÛÕØØÓëëÔèèÔèèÓêê×ÚÚÔÓÓäääÿÿÿéééåååææææææææææææåååêêêùùùñññ°°°JJJkkkÅÅÅ–––ÖÖÖÚÛÚfªfL LHžH7—7‹º‹ãÞãÙÚÙ¹º¹ßÛ߼ͼN NN N@š@=™=³É³âÞâÎÏÎÀ¿¿ÞääÝÄÄõ??óMMóJJóHHßÅÅ×ÝÝçååÿÿÿéééåååææææææææææææåååëëëûûûãããííîììðÒÒÔ›››ÿÿÿÇÇÇ“”“ÕÕÕßÝß:–:rHžHQ¡Q»âÝâÙÚÙ¹º¹àÜà½Ï½  } W¥WQ¡Q¶Ë¶ãßãÎÏο¾¾ÞââÜÈÈîbbüüíkkÞÈÈ×ÛÛæååÿÿÿéééåååææææææææææææåååêêêûûûååæééäïïáÿÿô++N²²¾÷÷ôÅÅÅ”””ÔÕÔßÝßÒ×Ò<™<(‘(ÕØÕéàé×Ù×ÛÛÛºººØÙØâÝâ²Ê²‰\¦\îâîßÜßÛÜÛÐÐп¿¿ßÞÞÙÚÚÖóóö44õ::Õ÷÷ÛÛÛØ×׿ææÿÿÿéééåååææææææææææææåååêêêûûûææåÕÕèžžîLLõø··éööëÅÅÈ”””ÕÕÕÚÛÚßÜßÚÚÚ;—;ŠÊÔÊÞÛÞÙÚÙºººÚÚÚÙÚÙåßåºÍº„R¡RàÝàÜÜÜÐÐп¿¿ÞÞÞÙ××ÙÝÝ÷--ö33ØääÛØØ×ØØæææÿÿÿéééåååææææææææææææåååééëþþû××çCCøÿÿÿ¹¹éööëÅÅÈ”””ÖÕÖÚÛÚר×ôåôÏÖÏx{±{èàè×Ù׺ººÚÚÚÖÙÖÛÚÛÿêÿ‰¹‰w¹Ì¹äàäÎÏο¿¿ßÞÞÙÚÚÖññö55ö55ØççÛØØ××׿ææÿÿÿéééåååææææææææææææåååêêêûûûææåÙÙ祥íTTö ý··ê÷÷ëÅÅÇ”””ÖÕÖ×Ù×FœFX¤X@™@vŽºŽåÞåר׏¹¸áÜá±É±4•4eªe‰ ÂÐÂáÞáÎÏο½½Üääݹ¹ñMMüõ33×ääÚØØÖÖÖæææÿÿÿéééåååææææææææææææåååëëêûûûääåééåòòäññäÊÊèÛÛåííëÉÉÉ“““ÙÙÙãá㑾‘K¡KDŸDŒ¼Œàßàßßßßßß¼¼¼áßáÓÚÓs²sDŸDO£O­Ê­äáäàáàÔÔÔÂÁÁãççàÎÎôccùBBðwwÝææßÞÞÜÜÜéééÿÿÿéééåååææææææææææææåååêêêÿÿÿûûûúúûøøûùùûÿÿúüüûûûûûûû¸¸¸¹¹¹ÄÄÄÍÆÍÔÉÔÔÉÔÍÇÍ®®®ÁÁÁÄÃÄÑÈÑÔÉÔÓÉÓÊÅÊÁÁÁÄÄÄ»»»±±±ÅÄÄÁÄÄ¿ÒÒ¿ÓÓÀÍÍÂÁÁÃÃþ¾¾ÖÖÖÿÿÿèèèåååææææææææææææææææææêêêëëëêêêëëêêêêééëêêëêêêíííæææÕÕÕ×××ÔÕÔÓÕÓÓÕÓÔÕÔÖÖÖÖÖÖÖÖÖÙÙÙÖÖÖÖÖÖÓÕÓÓÕÓÓÕÓÔÖÔÖÖÖÖÖÖ×××ØØØÖÖÖÖÖÖ×ÓÓ×ÓÓ×ÔÔÖÖÖ×××ÕÕÕÝÝÝëëëææææææææææææææææææææææææååååååååååååååååååååååååäääæææêêêêêêêêêêêêêêêêêêêêêêêêêêêéééêêêêêêêêêêêêêêêêêêêêêêêêêêêéééêêêêêêêêêêêêêêêêêêêêêêêêèèèåååææææææææææææææææææææææææææææææææææææææææææææææææææææææååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææ( @ ææææææååååååååååååååååååæææååååååååååååååååååæææååååååååååååååååååæææååååååååååååååååååæææææææææææææææéééééééééééééééèèèèèèéééééééééééééééèèèèèèéééééééééééééééèèèèèèéééééééééééééééèèèçççææææææåååìììøøøöööööööööööö÷÷÷úúúöööööööööööööööøøøúúúõõõööööööööööööùùùùùùõõõööööööööööööúúúûûûçççæææäääïïïÐÐд´´¹¹¹¸¸¸ººº®®®ÎÎÎËËË´´´¹¹¹¸¸¸ººº­­­ÖÖÖ¶¶¶¸¸¸¸¸¸¹¹¹°°°ÛÛÛººº¸¸¸¸¸¸¸¸¸···´´´úúúèèèåååäääïïïòòòåååçççæææìììÐÐÐÈÈÈôôôäääçççæææîîîÄÄÄÖÖÖñññåååçççæææííí»»»äääìììæææççççççèèè···öööéééåååäääïïïñññäääæææåååëëëÐÐÐÊÊÊóóóãããæææåååìììÄÄÄØØØïïïäääæææåååëëë¼¼¼åååêêêåååææææææçç縸¸öööéééåååäääïïïñññäääæææåååëëëÐÐÐÊÊÊóóóãããæææåååíííÄÄÄØØØïïïäääæææåååììì¼¼¼åååêêêåååææææææçç縸¸öööéééåååäääïïïñññäääæææåååëëëÐÐÐÊÊÊóóóãããæææåååìììÄÄÄØØØïïïãããåååäääëëë»»»åååéééåååååååååæææ¸¸¸öööéééåååäääïïïñññäåäçççæææìììÑÑÑÉÉÉôôôäääçççåååíííÅÅÅ×××óóóçççéééçççïïï¿¿¿åååîîîèèèéééèèèêê꺺ºõõõéééååååååêêêöööóôóòôòóôóõõõðððããã÷÷÷ôóóôôôóòòöööìììèèèèèèíííïïïíííñññÝÝÝéééèèèïïïîîîîîîïïïÛÛÛùùùèèèæææêêêÒÒÒÏÐÏãàãåßåàÝàÞÜÞÞÞÞÈÈÈÖÖÖÝÝÝÜÞÞßääÜÝÝÜÛÛíííÁÁÁ“““™™™’’’©©©ÞÞÞ¸¸¸ŽŽŽ““”––—”””±±±ùùùèèèåååêêêÏÑÏÜÕ܆¹†*‘*?š?|³|æàæÂÄÂÖÕÕÚÚÚÏÀÀžIIÐÁÁÙÜÜñððïï𢢥JJL‡‡‡»»»çççèèé‘‘•889žžž¼¼¼õõõéééåååêêêÐÑÐÖÒÖ·Í·†h«hÒÖÒÜÜÜÅÆÆÕÓÓœCC•22{­mmÞååðîïëëèÿÿóååÛSS^üüü¼¼¼ããäîîèÿÿü¾¾¹ggrÿÿÿ´´´öööéééåååêêêÒÒÒÌÎÌñåñ×Ù×2•2£Ã£æàæÂÃÁÚßߦZZ´~~“//̹¹ÚÞÞóòðááë’’ì66õ??ìôôé¹¹¼èèåÖÖì„„î""õeeê÷÷äµµ¹öööéééåååêêêÐÑÐÖÒ֦Ʀ§Å§5‘5]£]îäîÂÃÁ×ÛÛÔÍÍ”33ƒÐÄÄØÛÜóóïØØëaaòþ99÷÷÷é··»ééãÆÆìKKôþeeó÷÷ã²²¶öööéééåååêêêÐÑÐØÓØ¨Ç¨GHW¤XÄÑÄáßáÂÃÂÙ××äììžž JJØÑÑÞààòòóððíüüçßßë¼¼ìòòïÂÂÂååçùùóÿÿêÕÕîÇÇïôôîÁÁÂõõõéééåååëëëÑÑѺ»ºÎÊÎØÎÓÔËÓÆÄÉÄÄÄ¿¿¿­­­²±±¿ÄÄ¿ÈÈ»¼¼«ª«Ö×ÖõõöìëïõôñûûòòñòìììèèèØØÚããçîîèïïçããåÖÖÖúúúèèèæææêêêÒÒÒÐÐÐÚÛÛÆÈÙÒÔ×âãØÖÖ×ììëØØØ’’’onozxzyyyŸŸŸ«««ÝÝÝÚßßÙÜÝÔÒÔÙÛÛÛÛÛîîî¼¼¼{{{rruttx„„ƒ¯¯¯øøøèèèåååêêêÏÏÒÛÛÎ……ë::õ00÷™™æààÖééìõõõÄÄÈ|||„„„ÄÄĬ¬¬ÞÛÛÐÃøˆˆ“--ÓÈÈÜÞÞöõõèèé­­±OON%%%···½½½õõõéééåååêêêÑÑÒÑÑÏÉÉàÇÇÝ==õTTñççÔêêîîîìùùéÿÿúUU|ééíÌËÊ«¯¯ÔÄÄ!!–66~¾––àçæòðñëëäÿÿû»»Ëmmÿÿÿ³³´öööéééåååêêêÒÒÒÎÎÐèèÚzzêûŸŸäââÕëëíëëîùúääêÈÈÆ©©ªàáá§aa±xx—88ÛÜÜÙÙÛùùôÈÈêYYóýddò÷÷ãµµ¹öööéééåååêêêÑÑÓ××ϱ±ä‚‚èúmmíèèÔééíêêì••ë<<÷!!÷ääëÅÅè§§äèèÒÆÆ‰Œ''ÛÚÚÛÛÝ÷öòÍÍçuuðúggñööã±±¶öööéééåååëëëÎÎÏÓÓ;¾âffêzzçËËÚÚÚ×ììíõõôûûêúûëÙÚíððòÖÖÕ­­­Ù×רàß»š™¯{yÖ×××××ôôõôôîÿÿêïììÝÛíòòïÆÆÇöööéééåååçççàà߬¬­¬¬¥ÈȲÅų¹¹µ££¤¼¼¼ððððìóôî÷ýöøòïñííí¿¿¿ÄÄÄÌÆËÓÔÙ×ÙàÈÆÈÂÂÂÜÜÜïîïçòöì÷öïû÷ìïïìëëûûûçççæææäääïïïïï¦[[`ZZa__`   ¤¥¥Ø×ؽ̽°Ç° À¢ÃÏÃÚØÚÄÄÄÛÜ۽н²É±§Ã¥ÓÙÓÚØÚÁÁÁÙÛÛÝ®®Ý­®Þ¨©×ÍÍÜÞÞüüüçççæææäääîîîôôôÙÙܶ¶³44/}}~ÕÕÕ¡£¡èáèS¡SFžFŸÂŸãÞãÁÃÁÜÛÜ,,…M M·Ì·ÜØÜÅÅÄÝááîffþõ??ÝÇÇÞããüûûçççæææäääïïïðððîîâýýÿ\\§ÅÅÙääߟŸ ÞÜÞÑÖÑ=™=|³|êáê×Ù×ÂÃÂàÝà¼Î¼.“.ŸÂŸéáéÓÔÓÆÅÅÜÝÝØààù$$á³³×ææßÜÜüüüçççæææäääîîïõõñ‚‚ïüþÆÆìÞÞÕ¡¡£ØÚØãÞãéà鉙¿™æßæÂÃÂÖØÖíâíÊÓÊ…¿Ð¿ÜØÜÄÄÃÜÝÝØààø&&â§§×ããÞÜÜüüüçççæææäääïïïññïÁÁåï33ôÇÇëÚÚÑžŸåáåv²vT¤TТŢçáçÄÅÄÙÛÙcªcN¡NŒÅÓÅÝÚÝÆÇÆßààïllÿä¯¯ÚææáÞÞüüüçççæææäääîîîøøøøøïÿÿïõõðññóêêê­®­ÑÏÑ´Å´ƒ°ƒ¨¿¨ÖÒÖÎÏλ»»ÒÑÒ¨¿¨‚¯‚µÅµ×Ó×ÊËʽ¼¼ÒÔÔס¡ÛÒÅÅÎÑÑÕÔÔüüüçççææææææèèèïïïîîïììïîîïïïîòòòßßßÏÏÏØÕØâØâÚÕÚÑÑÑÒÒÒÑÑÑÑÒÑÚÕÚâØâ×Ô×ÑÑÑÒÒÒÑÑÑÒÑÑÐÜÜÏßßÒÔÔÑÐÐÕÕÕìììææææææææææææäääääääääääääääãããçççëëëéêéçéçèéèêêêêêêêëêêêêéêéçéçéêéêêêêêêêêêêêêëèèëççêêêêëëêêêåååææææææ(  æææëëëííííííììììììíííììììììííííííììììììíííëëëæææêêêàààØØØÙÙÙáááÚÚÚØØØÞÞÞÝÝÝØØØÚÚÚàààÙÙÙ×××çççëëëëëëæææàààÓÓÓ×××ãããÝÝÝÎÎÎâââáááÏÏÏÜÜÜâââ×××ÖÖÖíííëëëëëëæèæÙÚÙÛÛÛêêêäããÒÒÒëëëêêêÖÖÖãããìììàààÙÙÙìììèéèòðòüóüæåæãããñôôïôôÞÞÞããäëëîÜÜÜßßàèèëääæààßìììâÞâ¿Í¿‰»‰ÍÕÍÖÖ×ÓÅÅÈ­­êìîÊÊÂvvd¥¥¦ááà““xÝÝÞìììßÝßÈÏÉT£U´Êµ×ÑÖžMLœTUíòíÌËïaaÀÈÈÈççêyyÖ––ºååÞêêëÞÜÞÈÏÆp°k«ÂªÙÚßÁ𙏄†ñùòÁ¿íüÚÚÛàà䊊ÿÀÀðææÜêêìÝÝÛÁÃʼ¾ÏØÕÖÍÍÍŸ¢Ÿ‘’޶¶¸òöîóóàæåæÞÞݼ¼¤­­¤ÝÝÞííìßßÛÇÇØ^]ò§¨áýý𩨷sr‚ÄÈÆ»›—@DϾ¾ôø÷ŠŠ‰ããáëëëÜÜÛÕÕØQQø§§èþþêfh÷……õÒ×ÅÀ¥¨”87ÚÒÐéëòURü¤¢ëææØêêíââß³³Àȶµ¾ââßóìøéæóÌÍÊÓÒÖͲ¹ÎÍÍëêéãîößæíéèçêêëììíààÙ‚‚dŠŠ†ÉÇËzµyžÃ›áØáŸ¾žv·zÏÒÐÑÓÔí~㡟ëõõëéèïïéÚÚôVV湺ÏÑÌ˼Žr°sáØá¾Î¾W¥VÇÎÄÕáãîttá§§êööëèèîîëââïžž÷ÓÓãÇÅÃ’º“Œ·Œ×ÐײŲv®vÃËÄÐÏÑå}}Õ¼¼èîîëêêææçïïëüüèîîëÞÞßßÝßæàæÚÛÚÝÜÝåàåßÝßÚÚÚÛääÚÝÝãããçèè(0` åååììãåæêêêêýýýµµµ»»»ÙÙÖÕÕÕÃÃÃÅÅÈýýôËËË«««¾Á¿ôôôœœœÛÛãììðÜÜܤ¤¤âÞâ¿ÓÓàßßɹ¹ããÛ÷÷øõõ짪«ÌÆÌ×ÚÚ¡¡žÔÌÌÅÑÅÌÔÌØ××jjj[[[ddee©euŠ5–5ãêê³}}ƒ  {{{”””IIJ))*ªÆª ƒ ®Ê®´Ê´ÑÃÙ;;’,,ˆ|›BB††}UUT>>9»Í»‡S¢SéÞé°vvÖÙÖóóãXX¸RR©úúìúúæÕÕë##œ››Çëãê}k¬k¥WW¯ssºŒŒ´´éXXöûÿccô””íHHö ýªªë11Ýãã•66ê44øvvò¦¦ì‰‚¶‚Ť¤„ÂÂ猌çKKô˜¾˜Æ¨¨Ã¼ÅéêÚää×––šÅÅÚ””æ®®á222&&&‹‹‹¿¿ÂWWïýffê""Ž,,ôôÖÚÚϪee++NÆÆéЋÒ¹¹é##ûHH²²ß¤¤äÕÕçðÀ——ÓÉÓòæòÔééM¡MHžHŒºŒCœC=™=ÞÅÅõ==óKK;—;‘½‘ ~ ÝÈÈîggü²²¾(‘(Z¥ZÖôôö44÷--×ääEEøw²wÿêÿݹ¹ùBBðwwÀÎÇ                                !!"" ## $%&&% %%$%$#'()*+ ,-. # &/01 #2345 #67+89:;<=>?#@A B #CDEF:>G?>-HIJKLMNOPL Q!RSF ,TUV>H#WXYZ[M\]^Z_L #9!)` ab<=:#cd^Z[L eYZZfL #S7gRh "i>j:#Ik[lII_mW  6n9aoL L  ppp  qqr##  s##aa##   H tulv1w5wxyaiia 3xwxAzq{|YZ}r#&0  p~  s/% pt€dY# x ,V>j.>‚,ƒ  rl]|erI„{… ,V†:<<Ic‡vL H qum^lr ˆdZZ‰ aŠG?;#[^ZZ_L # ‹Œ‹^dr# Žm^Y :~?a#_[‰ZfM  qc||‰ŒIk\ ,TII\k ##‘    "2s   zQQ  s"QFF#’Q’’““““# 3”40$ 2'•–+—C••˜™9"paš›œœœš” 2(–EžCŸŸEE9 pa ¡¢¢¡ I ƒ£ 2™¤#QH9g¥’#"¦§›¦cmZˆ 2#)"#C7E‘#¨§©NªZZZˆ 2#’"(«F#¬—(C"¦§§“#NfX^ˆ 2#˜¥˜(—#8+')7! a­œ¢§a##II„ 2ž••—«˜•8  ¡®¯a ‘‘  ‘‘‘  °t° #H####HHHH#########( @åååëâëëëäçéçëëëäêêôôôýöøûûóûûûÓÓÓ¶¶ºººº¬¬¬ÏÏÑËËË´´´ÙÕÙÃÄù¹µ­­±ÛÛÜÈÈÆÙÕÕðîïÖÙÖÜââëççÅÄÉóóíÔÔÎÊÆÊòîôì÷öáÞÞïïð×ÙàØàß“““ŽŽŽ¨§§…µ…,’,>š>z³z¿ÄÄÏÀÀFF¢££MMM………44/ŸŸ µËµ…h«h•44}­mmããÜSS^Çdzggrñåñ4“4¤Ä¤×åå¦ZZ³{{̹¹ããë””ì;;ö??ìÖÖí‚‚í""öddòüüç¨Ç¨W£W†þÅÅèKKô÷÷ãÕËËGHÅÒÅâÝ⽘˜ÛÛì¹¹æÇÇíÓÍÒ»»Ë¿ÈÈÔÜÜÆÆÛono{{{sswÛÛÎ33õããÕÑÄĸˆˆ“..///ËËäWWòèè×üüëUU|$$mmzzéûœœåú§aa—88mmíuuðffêÛÛÔ¯{y¬¬¥ÓÔÙçòöïû÷\\`³Æ³ŸÂŸÃÏþоݬ¬ØÎÓN¡NFžFïiiÿõ??ÝÇÇ\\§½Í½ù%%䯯‹ÍÑÍâ§§Šcªc‚¯‚¨¿¨×¡¡ÛÏßß                       !"! #   $" %%&'(&) &&&& *+,-./0/1234 &567  89: 0;<=>?  @A  BCD@EFG;HIJKL MNOPQ  RRCS. ;T/MPUKQ VWUPXYRZS[\]0Q^_.QM`a aab .c d e >&fgg(  # ghh4 iNKjJkg34 lmnY% 2o b peKqr#s t lu;<] bv kwxyk#NzxI){G|`qUPX  _Nz}rIJKOI)lTup~zPXYVw€ss^E]Q^ ‚@@1 # #bƒ$„!…# )?††71.‡ˆ‰@Š8Dd‹‹‹Œ 5g1Žˆ\"+9Z8‘’“  ”e1 ,-$•+DE–—E" !NxU`€1\˜ˆ\™9@$%–šE VNj`€(\-S›Dœ˜[‘—E" s ‡ž  ž‡  Ÿ l  #!%\ \ a¡d \( æææëëëíííìììêêêàààØØØÙÙÙáááÚÚÚÞÞÞÝÝÝ×××çççÓÓÓãããÎÎÎâââÏÏÏÜÜÜÖÖÖæèæÙÚÙÛÛÛäããÒÒÒèéèòðòüóüæåæñôôïôôããäëëîßßàèèëääæààßâÞâ¿Í¿‰»‰ÍÕÍÖÖ×ÓÅÅÈ­­êìîÊÊÂvvd¥¥¦ááà““xÝÝÞßÝßÈÏÉT£U´Êµ×ÑÖžMLœTUíòíÌËïaaÀÈÈÈççêyyÖ––ºååÞêêëÞÜÞÈÏÆp°k«ÂªÙÚßÁ𙏄†ñùòÁ¿íüÚÚÛàà䊊ÿÀÀðææÜêêìÝÝÛÁÃʼ¾ÏØÕÖÍÍÍŸ¢Ÿ‘’޶¶¸òöîóóàÞÞݼ¼¤­­¤ííìßßÛÇÇØ^]ò§¨áýý𩨷sr‚ÄÈÆ»›—@DϾ¾ôø÷ŠŠ‰ããáÜÜÛÕÕØQQø§§èþþêfh÷……õÒ×ÅÀ¥¨”87ÚÒÐéëòURü¤¢ëææØêêíââß³³Àȶµ¾óìøéæóÌÍÊÓÒÖͲ¹ÎÍÍëêéãîößæíéèçììíààÙ‚‚dŠŠ†ÉÇËzµyžÃ›áØáŸ¾žv·zÏÒÐÑÓÔí~㡟ëõõëéèïïéÚÚôVV湺ÏÑÌ˼Žr°s¾Î¾W¥VÇÎÄÕáãîttá§§êööëèèîîëââïžž÷ÓÓãÇÅÃ’º“Œ·Œ×ÐײŲv®vÃËÄÐÏÑå}}Õ¼¼èîîëêêææçïïëüüèÞÞßæàæÚÛÚÝÜÝåàåÛääÚÝÝçèè        !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`a4bcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…‚†‡ˆ‰Š‹ŒŽD‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦—§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁ¯Â5ÃÄÅÆ5 ÇÈÉ(0`€€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷‡ˆˆ‡ˆ÷ˆˆˆˆ‡ø‡ˆˆˆxˆˆˆˆÿwwwxw÷wwˆ÷www‡÷wwÿÿÿÿøÿÿÿÿÿwÿÿÿÿ‡ÿÿÿÿ÷ÿÿÿÿÿøÿÿÿÿˆÿÿÿÿÿ‡ÿÿÿÿ÷ÿÿ÷ÿÿøÿÿÿÿÿxÿÿÿÿwÿÿ÷ÿ÷ÿÿÿÿÿøÿÿÿÿÿwÿÿÿÿÿ‡ÿÿÿ÷ÿÿÿÿÿøÿÿÿÿxÿÿÿÿÿwÿÿÿÿ÷ÿÿÿ÷øÿÿÿÿwÿÿÿÿÿ‡ÿÿÿÿ÷ÿÿÿÿÿøÿÿÿÿÿxÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿøÿÿÿÿÿxÿÿÿÿ‡ÿÿÿÿ÷ÿÿÿÿÿ÷ÿÿÿ÷ÿ÷ÿÿÿÿÿwÿÿÿÿÿ÷ÿÿ÷ÿÿÿw÷wwwwwxwwwww‡wwwww÷ˆ‡x‡‡w‡ˆˆxwwwwwwwwwwwwÿxˆˆ‡wÿˆˆˆWwx ‚7w‡wwEwwÿw€G‡ÿxwxx66ww‡xˆD‡wÿÿ÷'ÿwÿÿø/÷wwz7wwwtDDWwÿÿÿÿ‡ÿÿø/÷wwwcww‡t‡EwwÿÿyŸÿ‡ÿ÷yŸ÷wwwvgwwwGFwwÿy™Ÿÿ‡÷‰™Ÿ÷ww‡ƒ7www„Fwwÿy™—ÿ‡÷‰™Ÿ÷wx6b‡w‡wtEwwÿÿø—ÿwÿÿyŸ÷wwˆ8ww‡wwGwÿÿÿÿÿ‡ÿÿÿÿ÷xwwwxw‡wwwwwÿÿÿÿÿÿÿÿÿÿÿxwxxw‡xˆˆˆˆwwwwxˆˆˆˆwww÷ww÷wwwwxwwwwww÷wwwwwwx‡wwÿøBuwww‡wÿ€ 0‡xx™™wwÿÿx xwwôG÷wÿÿˆ÷wxwy—wÿÿ€ÿx‡tDD‡ÿÿø÷ww™—wÿÿÿxÿxw„„H‡ÿÿ÷÷ww™™wwÿ÷˜™ÿxwtxGwÿw™Ÿ÷wwwy—wÿy™˜÷xwxHHw÷™™Ÿ÷ww‡‰Ÿwÿ÷‰™ÿxwwdHwwÿw™Ÿ÷ww™™‡wÿÿÿwÿxwwtGwÿÿ÷÷wwwwwwÿÿÿÿÿxwwwwwÿÿÿÿÿxˆxˆˆˆÿÿÿ÷÷‡‡ˆxˆ‡ÿÿÿÿÿÿ÷ˆ‡‡xˆ‡xwwwwwwwwwwwwwwwÿ÷ˆˆˆx‡wwwww‡wwwwxwwwwwÿ÷€ øwx26wwwv68wwwt„„wÿÿÿrø‡scwxwƒcjwxwxDGwÿÿÿòø‡w¢‡wwwx¢wwwwwtwwÿÿ÷‰ÿø‡wx8wx‡wˆgwxwwDwwÿø™™øwww†wwwww6wwww„‡wÿù™™ÿø‡ww(‡wwww#wxww„wwÿÿ÷‰ø‡sc`wwwz‚cwxw„Dwwÿÿÿ÷ÿø‡÷6‡wwwv(‡wwx„wwÿÿÿÿÿ÷‡wxw‡x‡www‡xwww‡‡ÿÿÿ÷ÿÿwwwwwwwwwwwwwwwwwÿ( @€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ÷÷ÿÿÿÿ÷ÿÿÿ÷ÿÿÿ÷÷ÿÿ÷÷ÿ÷ÿ÷ÿ÷wwwwwxwwwwwwwÿ÷wÿw÷÷w÷ÿÿw÷ÿw÷÷÷wÿw÷ÿwÿÿÿÿ÷÷ÿø÷ÿ÷÷ww÷÷÷÷ÿw÷ÿwÿ÷w÷wÿÿ÷÷÷ÿÿÿÿÿÿÿ÷ÿ÷ÿÿ÷÷÷ÿÿwww÷www‡w÷wøˆˆˆ‡ÿwr(ÿwxGÿwgw€÷÷wø/÷weHÿøww‡wÿŠwwGOÿw™÷y—÷ÿwx‚÷wt‡÷x™÷x—÷wx'øÏÿ÷÷w÷wwwwwwwÿ÷ÿÿ÷÷w÷÷÷wˆˆ‡÷w÷ˆˆ‡ÿ÷y™ÿ…hx÷ô÷rSw÷w÷y÷÷?wtHÏÿÿˆwÿ÷w˜ÿ÷wŸwôtwy‡øÿww‰ww™ŸxwEÿ‰—÷wx˜÷wÿ†wÿ÷wwÿwwwÿ÷ÿwwww÷ÿÿ÷÷‡‡ˆÿwwwwÿÿÿÿx‡w¨‡øˆ|Èw÷ÿw÷w(‡÷x*ww|‡÷ÿÿ‡ør‡wˆw÷Ï÷÷y—ø'÷wx÷Ç÷ÿ÷—÷w‚'÷ø¢ww|‡÷ÿ÷ÿ÷wx÷w÷wwwww÷ÿÿwÿwwww÷w÷( €€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿÿÿ÷÷w÷÷wwÿÿ÷ww÷÷ÿ÷÷÷ÿ÷ÿ÷÷w÷w‡wøxÿ÷‡ü‡w÷—w‡wywwwø‡ÿ÷w÷‡÷‡Œˆ÷w—ùwuw‡÷ww÷ÿwˆwŠ÷‡ÿ‡xww‡ww‡x‡ÿÿ÷wÿwÿpuzzles-20170606.272beef/icons/map.ico0000644000175000017500000006117613115373735016273 0ustar simonsimon 00 ¨%–  ¨>& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $ææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååææææææææææææææææææææææææéééêêéêêéêêéêééêééêééêééêééêééêêéêêéêêéêêéêêéêêéêééêééêêéêêéêêéêêéêêéêêéêêéêêéêééêééêééêééêééêééêééêééêééêééêééêééêéééééæææææææææææææææææææææåå娨Ù×ר×ר×ררÙרÙרÙרÙרÙרÙ×ררØ×ר×ררØ×ררØ×ØØ×ר×ר×ר×ר×ררØ×ØØ×ררÙרÙרÙרÙרÙרÙרÙרÙרÙרÙרÙרÙ×ØÙØÙÙåååææææææææææææåååéé騨Ùk¦aw¢Zo…Zp…a±i­Ãgª¿gªÀh­Âb µby¢h¬g~ªg~ªh¬by¡d¤ºd¤¹Xo„Ynƒbx¡j¯g~ªg~ªh¬by¢b µh­ÃgªÀgªÀgªÀgªÀgªÀgªÀgªÀgªÀgªÀhªÀf¬Âi¤·ØÙÙéééåååææææææåååêêé×רh€®_y«PiPj^¥½g¸Òe³Íe³Íg¸Ò_«Ã^z©g·e€´e€´g‚¸_x¬[ ·[¡·To‡Tm†YrŸa|®d³e€´g‚¸_x©_§Àg¸Òe´ÎeµÎeµÎeµÎeµÎeµÎeµÎeµÎeµÎf´Îd¶Ðg«ÂרÙêééåååææææææåååêêé×רi¬`z«Y—®`¦¾e°Èg³ÌhµÎh¶ÐeµÌZŠªe}¯g´f€²g³e}µZz‰`’zZ‡vVo…Vpˆ[›²\œµ`y¨iƒ·ez®Z†¨e³Êg³Ìf³Ëf³Ìf³Ìf³Ìf³Ìf³Ìf³Ìf³Ìf²Ëg³Ëg·Ñi¬ÃרÙêééåååææææææåååêêé×רh¬_z«a§Ài¹Òg³Íf´Í`§¿`©ÀZ‰ªdy­gµe²g´e}¶Yz‰d—yjž„`yQj~Qk‚b¬Ãc¬Å`{©f}±Zˆ©e´Ëf³Íf²Ëf³Ìf³Ìf³Ìf³Ìf³Ìf³Ìf³Ìf²Ëg´Íe²Í_©Àb¡µ×ØÙêééåååææææææåååêêé×רj¯a|®`¦¿i¹Òf¶ÎU…›Tn…Oj€^t£hƒ·e±g´e}µZz‰d˜zgš‚gš_{Y™­_¥¾f³Ì`¦¾`{ªe}±YŠ©e¶Íh¶ÏgµÏf³Ìf³Ìf³Ìf³Ìf³Ìf³Ìf²Ëg´Íd²ÎZ’“^yb{ר×êéêåååææææææåååêêé×רcx£Zs Z™±b­ÄT„šVk„\vUm…_x§h‚¶f³e}¶Yz‰d˜zgš‚e˜hœ‚`xa©¿i¹Óg¶Ï`¦¾`z©hƒ·dy­Z‰©`©À`¨Àe²Ëf³Ìf³Ìf³Ìf³Ìf²Ëg´Íe³ÏY‘‘e”xg‚h•~רØêéêåååææææææåååêêê×רXm‚Rk…To†Sn†Wo‡ZtŽYsŒWq‰TkŒf€´f~¶Yz‰d˜zgš‚e˜€gš‚e•xZ’d±Ëf²Ëg¶Î`¦¾`z©gµg´e}°a|¬[w£`§Àg¶Ïf²Ëf³Ìf²Ëg´Íd²ÎZ’’e•ygš‚e™€g“~רØêéêåååææææææåååêêé×ר]tŠYtŽZtZtYtYsŒYsŒZtWq‡ShYz‰d˜zgš‚f˜€f™e–|Z‘d±Íg´Íe±Êh·Ð`¨¿_z¨gµf´e~±c{­\v¢`§¿g¶Ïf³Ìf²Ëg´Íd²ÏZ’“d”vf›g™e™€g“~ר×êéêåååææææææåååêêé×ר\rˆXrŒYsŒYsŒYsŒYsŒYsŒZtXpRstd—zg›‚e˜f™€iƒa’{aªÁjºÔgµÍh·ÑeµËZˆ©e}°g‚µdz®Z‡©_¦¾_¥½e±Êf³Ìf³Ëg´Íd²ÎZ““d–vTvxTvvf›~gƒh–רØêéêåååææææææåååêêé×ר\sˆXsŒZsŒYsŒYsŒYsŒZtŒXq‹Stve˜}gš‚e—gšf™ayZˆuZœ¯a©Á`¦¾_¨¾Zˆªez®g‚´d|¯Z‡¨d´Êh·Ðg¶Ïf³Ìf³Ìf³Ìe²ÌZ’“d”vUwxWo‹WnŠUxv_‘xb‹xר×êéêåååææææææåååêêé×ר\s‰XsŽYtYtYtYsZuTm„`yjŸ„gšhœƒfš}UwvSlƒTn‚Tn…To†To‡RmƒTi‹f€µi„¹`{ª`¨¿h·Ðe±Êf²Ëf³Ìf²Ëh¶Ð_¥ºb’y`zSkƒ[uŽZtXpŠRm‚Xn€×רêêêåååææææææåååêêé×ר[p„Wo‡Xp‡Xp‡Xp‡Xp†YqˆSjY„ra‘z_Žy`xTwvVnŠ[uZtŽZtZtZt[uVp‡TkayªZtŸ`¦¿g¶Ïf²Ëf³Ìf³Ìf²Ëg¶Ð_¦»b”}`zTn„ZtŽYs‹ZtŒYt]sŠ×רêêéåååææææææåååéééÙÙÙÄÅÆÓÕÖÐÑÓÑÒÓÑÒÓÐÑÒÔÕ×ÁÃÅUlSn…Vo„Sm‚WpŠZtYs‹YsŒYsŒYsŒYsŒYsŒZtWq‰Tl…Pi€_¦½h¶Ïf²Ëf³Ìf³Ìf²Ëg¶Ð_¦»b”|`yTm„ZtŽYsŒYsŒXsŒ\rˆ×רêêéåååæææææææææéééÙÙÙÛÛÛîîîêêêëëêëëêêêêïïîÚÚÛ\q†XpˆTo‰\vYtŒYsŒYsŒYsŒYsŒYsŒYsŒYsŒYsŒYs[uUp‡_¦¾g¶Ïf²Ëf³Ìf²Ëe²ÊgµÏ_¥ºa“|`ŽyTm„ZtŽYsŒYsŒXs\sˆ×רêêéåååæææææææææéééÙÙÙÖÖÖèèèäääåååååååååååæãããÑÒÓÖÖÖ˜£Kg‚[uŽYsŒYsŒYsŒYsŒYsŒYsŒYsŒYsŒYsŒ[uUp‡_¦¾h¶Ïf²Ëf³Ìg¶ÐgµÏi¹Óa¨¾c–~a‘{Tm„ZtŽYsŒYsŒXs\sˆ×רêêéåååæææææææææéééÙÙÙ×××éééåååæææææææææææææææêêêëëëîìê“§Rm†[tYsŒYsŒYsŒYsŒYsŒYsŒZtXq‰Um…Pi€_¥½gµÎg´Íe²Í`§½`§¼a©ÁYš®\ŠuZ†sTm„ZtŽYsŒYsŒXs\sˆ×רêêéåååæææææææææéééÙÙÙ×××éééåååæææææææææææææææåååååæîí딞¨Rl†[uYsŒYsŒYsŒYsŒYsŒZtWp‡TkŒay©Zsa©ÂiºÔd±ÎZ’’a’zY‡uPjUo‡Tm‚TmƒXr‹YsŒYsŒYsŒXs\sˆ×רêêéåååæææææææææéééÙÙÙ×××éééåååæææææææææåååååååååéè皥Lg‚[uŽYsŒYsŒYsŒYsŒYsŒYsWq‰TkŒe~²j…º`z¬Z›°aªÂZ‘‘d”xjŸ„_ŽxTl…\vZtZtŽYsŒYsŒYsŒYsŒXs\sˆ×רêêéåååæææææææææéééÙÙÙ×××éééåååææææææçççéééèèèîííרØTm„YuYsYsZtZtZtZt[uUm…_x§i„¸d{²Z{‡_‘y_{e–|gš‚f™€e˜~TuvVn‹[uŽZtZtŽZtŽYtŒYsŒXs\sˆ×רêêéåååæææææææææéééÙÙÙÖÖÖéééååååååèèèäää××××××ÛÛÚÈÉÉ\p„XpˆZq‡Xp†Tn†To†Tn†Tn†Up‡Pi€_x¦fµY{†d˜zhœ‚g›fšf™€f˜€gše˜|TuvSlƒTnƒTnƒTmƒXq‹ZtXrŒ\sˆ×רêêéåååæææææææææéééÙÙÙÙÙÙíííèèèêêêãããËËËÚÚÚÌÌÌÍÍÍÞÞÞÓÔÕÑÒÔÖ×ØÃÆÇ_ž³_§¿_¥½_¥½`¨ÀZš±b}®b{ªa‘yjŸ„e˜€f˜€f™€f™€hœ‚g›hƒg›€_Žx_Žy_Žy_xTuwWo‹Yt\rˆ×רêêéåååææææææåååéééÙÙÙËËËÚÚÚ×××ØØØÊÊÊáááîîîÛÛÛÎÎÎÝÝÝçççìììîííÙÛÛg­Äg¸Òh¶ÏgµÏi¹Òa¨À[u [sœZ…t`ye˜~gšf™€e˜_Žx_Žx_x_Žygšhœ‚g›hœƒe™|TuwWpŒ\s‰×רêêéåååææææææåååéééÙÙÙÍÍÍÏÏÏÊÊÊÚÚÚâââèèèåååää䨨Ø×××ÊÊÊßààëëêÓÖ×gªÀe´Îf²Ëg³Ëg·Ò_§¾]Œy\‰uOh{Tm…Tvve™}hƒ_xQj}Vp‡Vp†Qj|`yg›f˜€e˜hƒ_ŽwSl„]tŠ×××êêéåååæææææææææéééÙÙÙÜÜÜßßßÙÙÙíííææææææææææææéééêêêãããÊÊÊçççÕ××`¨¿g¶Ðh´Í`¯Èf¬Ã_ž²\‹v\ˆtUn…\v‘VnŠTvvg›€_yQi}Uo†VnˆPh}_whœƒe˜f˜€g›_ŒySm…]tŠ×××êêéåååæææææææææéééÙÙÙÙÙÙÜÜÜÖÖÖéééåååæææææææææåååäääêêêØØØÖ××ìéè”´¿\­È\®È’³¾ÜÜÛÀÄÆTkTm„XrŠYsŒ\wTm„a‘yhœ‚b“z[†tZrœ`xªZ|†e™zgšf™€ižƒ`ySm„]tŠ×××êêéåååæææææææææéééÙÙÙÚÚÚÜÜÜÖÖÖéééåååæææææææææææææææéééÙÙÙ×××êëëíçå²¾±½ìåãðððÛÚÚYqˆZtZtŽWq‰Tm†Ph}Z…ta|b’}\‡wa{ªj„ºd{³Z|†e™}e—a‘{YƒsSm„]tŠ×××êêéåååæææææææææéééÙÙÙÚÚÚÜÜÜÖÖÖéééåååææææææææææææåååéééÙÙÙØØØèèèéêêÜØ×Ú×Öëììêé犖¢Sm‡[uŽVp†Tk`x©_x§`y§`y§`y¦`y§e±e²h‚·_w¦c”{b’|\uŸ[rSl…]tŠ×××êêéåååæææææææææéééÙÙÙÚÚÚÜÜÜÖÖÖéééåååææææææææææææåååéé騨Ø×××êêêçççרØ×ØØëêé‹—¢Mhƒ[uWpˆTkŽf€´h‚¶g‚¶g‚¶g¶g¶g¶f€³f€²g¶_y¥\ˆv[†wc|®azªSl…]tŠ×רêêéåååæææææææææéééÙÙÙÚÚÚÝÝÝ×××éééåååæææææææææææææææçççäääËËËàààîîîÚÚÚÜÜÜÕÖ×RkƒZu[uŽWqˆTkf€´f³f²f€²f€²f€²f€²f€³f€³f€³e±`y§`y§g´_x¥Tm‡^u‹×רêêéåååæææææææææéééÙÙÙÚÚÚÜÜÜÕÕÕëëëäääåååæææææææææææææææèèèâââÊÊÊÙÙÙÊÊÊÛÛÛÖר\p„Yq‡Sm‡[vWq‡SjŠe²f€³f€³f€³f€³f€³f€³f€³f€³f€³g‚¶gµiƒ¸^t£Nh€Yp…×××êêéåååæææææææææéééÙÙÙ×××èèèÊÊÊàààëëëéééçççæææææææææææææææëëëçççÞÞÞÏÏÏÞÞÞÞÞÞÇÈÉÜÜÜŽ™¤Mi„Xr‰TkŒe²f€³f€³f€³f€³f€³f€³f€³f€³f€³e²g‚µdy­Z‰©_ªÁbŸ´×ØÙêééåååæææææææææéééÙÙÙÖÖÖëëëãããËËËÕÕÕÖÖÖâââåææåååååååååãããÖÖÖÖÖÖÝÝÝÍÍÍÍÍÍÎÎÎÛÛÛîîîîìꎘ¢Of‰gµg´f€³f€³f€³f€³f€³f€³f€³f€³e€²g‚µdz®Z‰©eµÌg¸Óh­ÃרÙêééåååæææææææææéééÙÙÙ×××éééæææäääàßßÒÑÒÜÛÛïîîëêêëêêîîîÝÝÝÑÑÐááàØØØ×××ØØØÙÙÙääääääëëë×רe|«g¶f€²f€³f€³f´hµgµgµgµgµh‚·dy­Z‰©e¶Íg³Íe´ÍgªÀרÙêééåååæææææææææéééÙÙÙÖÖÖçèèæææèæçÖØ×ÇÊÈÂÄÅÒÔÕÏÐÒÏÐÒÒÓÕÃÅÆÅÇÈÔÖ×êéèëëëèèèéééæææåååêêéÑÓÕ`x¨g‚¶f€³f€³gµe|°_z¨_{©_{©_{©`{©_x§ZŠªeµÌg³Íf²ËeµÏgªÀרÙêééåååæææææææææéééÙÙÙÛÚÛïïïìèê“©ž_x^‰uSj}XpˆWo†Wo†Wo†Wo†Xo†Qj‚‡“Ÿëéçææçäääæææææææææéèæ• µZv¬gµgµdy­Z‰ª`ªÁ`§À`¨À`¨À`¨À`§¿e´Ìg´Íf²Ëf³ÌeµÎgªÀרÙêééåååææææææåååéééÙÙÙÂÅÄרג¨Zviž„`ySlƒ[vYsŒYtYsYtYt[uMiƒ‡“Ÿìêéçççåååæææååæçççíë生µ`|°f}°Z‰©eµÌh¶ÐgµÏg¶Ïg¶Ïg¶Ïg¶Ïf³Ìf³Ìf³Ìf³ÌeµÎgªÀרÙêééåååææææææåååêéêר×eŽza’z`”{h›‚f™€f™UxvVm‰[uZtŽZtŽZtŽYsŒYsŒ\vMi„‡“Ÿëêèèèèåååæææääåëëë×××e|«_zª`©Àh¶Ðe²Ëf³Ìf²Ëf²Ëf²Ëf²Ëf³Ìf³Ìf³Ìf³ÌeµÎgªÀרÙêééåååææææææåååêéêרØh•fœhšf™€f™€gšfš~UxvSl‚Tn‚Tn‚Tm‚XrŠZsŒYsŒ\vMiƒˆ” èçæååååååäååêééÐÒÔf}¬`{«a¦¾gµÎf²Ëf³Ìf³Ìf³Ìf³Ìf³Ìf³Ìf³Ìf³Ìg²Ëf´ÎhªÀרÙêééåååææææææåååêéêרØg”~e›€fš€eš€eš€eš€f›eš_y_ya“{Z‡sSmƒYtXsŒXsŒYuRk„ÔÕÖîîîèèèèèèîîíÕÖØe}®_{¬`¨Ág¸Ñe´ÎeµÎeµÎeµÎeµÎeµÎeµÎeµÎeµÎf´Îe¶Ñg¬ÂרÙêééåååææææææåååéééØÙØi}f”~h”~g”~g”~g”~g“~g”~i–€h•j˜cyXn€]tŠ\rˆ\sˆ\s‰]q…ÆÆÇÛÛÚÖÖÖÖÖÖÛÛÚÅÆÈg{¤bz£b µh­ÃgªÀgªÀgªÀgªÀgªÀgªÀgªÀgªÀgªÀhªÀf¬Âi¤·ØÙÙéééåååææææææææææææåååØÙØ×Ø×רØ×ØØ×ØØ×Ø×רØ×Ø×ר×ר×ר×××××ר×ר×ר×ר×ר×רÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙ×ר×ררÙרÙרÙרÙרÙרÙרÙרÙרÙרÙרÙרÙ×ØÙØÙÙåååæææææææææææææææææææææéééêéêêéêêéêêéêêéêêéêêéêêéêêéêêéêêéêêêêêêéêêéêêéêêéêêéééééééééééééééééééêêéêêéêééêééêééêééêééêééêééêééêééêééêééêééêéééééææææææææææææææææææææææææåååååååååååååååååååååååååååååååååååååååååååååååååååååååååææææææææææææåååååååååååååååååååååååååååååååååååååååååååååååååååææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææ( @ ææææææééèéééééééèèéèèéèèéèèééèééèééèééèéèèééèéééééèééèééèééèééèéèèéèèéèèéèèéèèéèèéèèéèèéèèæææææææææåååÜÜÝÜÜÝÜÝÝÜÝÝÜÝÝÜÝÝÜÜÝÜÜÝÜÜÝÜÜÝÜÜÜÜÝÜÜÜÜÛÜÜÜÝÝÜÜÝÜÜÝÜÜÝÜÝÝÜÝÝÜÝÝÜÝÝÜÝÝÜÝÝÜÝÝÜÝÝÜÝÝÜÝÞåååæææêêéרÚl‚¬^o\w‰j­Ãk®Ãl°Åh§¼g©l‚°lƒ¯i}ªg£Àb“¨\n„hz¦m‚°lƒ¯i~ªfž¶l²Çk®Äk®Äk®Äk®Äk®Äl®Äi®Åq«½ÜÝÞéèèêêéÕ×Úe|®U{W¦d³Íf·Ñf»Ô]žºa{®e€´f€¸_x§Z”’V‚‹Sj†Y‹«_®f¶^zª_§Áe¶Ðd³Íd´Îd´Îd´Îd´Îe³Ìd·Òk²ÊÜÝÝéèèêêéÖØÚgzª`˜¹j¾Õf³Ì_¢¹]˜²a}¬g€³h¶b{ª_Š€izZzSsŽb²Åa³bxª_ ºh¸Ðf²Ëf³Ìf³Ìf³Ìf³Ìf²ÊhµÐ`ª¿g¢¯ÜÝÝéèèêêéÖØÚex©]“µe·ÎXˆ TkWmh¶g¶azª_Šgœg™~^—’c°Ìe³Ê`‰°dz®^”³c³Ée³Ëf³Ìf³Ìf³Ìf²Êg¶Ò_£´^‘{i”}ÜÜÜéééëêêÕÖØXn‰TtŽVyWoˆZuŽVoŠb{­b{¬_Šgœ~g™‚c“x_Ÿ¨gµÑeµË_‰°g~³e~°`}ª]°f¶Îf²Ìf²Êg¶Ò`¤´c”}ešl™ƒÜÜÜéééêêêÕÖ×[s‰Yr‹Zq‹YtYsŒYsŒSj†_Šgœ~f™ƒf˜|^¢g·Ôh¶Îd´Ê^„¬h´d~¯_‚­^“³f¶Îf²Ëg¶Òa¦µ^xazfl™ƒÜÝÜéééêêêÕÖØ]t‹[uŽ\vŽ[u\vWq‡]ˆygœ€gš‚f™_v]Ÿ°c­Ça«Á^ޱf~±d}¯^•´d¶ÌfµÍf²ËgµÏ`¤´^ŽxWv~Un„\‹xh“~ÛÜÜéééëêêÔÖ×QjƒMj…Oj…Ok…Mg†Ruxi ~g›€c–{Vv}Uo…UqˆVs‹Tp‡Xn“h¶`ƒ®d´Êg´Îf²Ìf³Ëe²Ï`™]†vVnŒ[uTn†]u…ÛÜÜééééééØÙÙ˜¢¬¨²œ§±›¦°¢«µv‰‘Nsw[}VtXpZtŽZsZsŒZtWr‰VlVy—e²Êf³Ìf³Ìf³Ëe²Ïa›‘]†xWo‹ZtŒXrawŽÜÜÜéééèèèÝÝÝæäãóñïðîíîíëû÷ô®µ½^r‹UmŠWqZtŒYsŒYsŒYsŒYsŒYtZrŠVze³Ëf³Ìf³Ëg´Ìe²Ïa›‘^†xVo‹ZtWr‹`wŒÜÜÜéééèèèÜÜÜÚÛÛææçãäääääääåãããçæä¦¯¶Wq‰YsYsŒYsŒYsŒYsŒYtWo†UxŽd²ÉgµÎe³Îd±Ëc²Î_™Ž\…uWo‹ZtWr‹`wŒÜÜÜéééèèèÜÜÜÜÜÜèèèæææææææææäååíììÚÚÚawŒWrŒZsŒYsŒYsŒYtŒVoˆ[q™Z}£f¶Òc®È_˜’\ƒTxUu„Vr€YrŒZtŒWrŒ`wŒÜÜÜéééèèèÜÜÜÜÜÜèèèåååæææèèèêêêááák’Rn‰ZtZsZsZtŽWpˆ\užj‚½^¡]ž¤_”Œg™{b‘yTl[sZtZtŽZtWr‹`wÜÜÜéééèèèÜÜÜÝÝÝèèèçççæææÜÜÜáááÊÌÍXo…ZsŠXqˆVpˆVpˆVq‰Sl…c}¯`}¡`zf—yf˜~f™g›\†{TnƒVp†Vo…Xq‹Wr`wŒÜÜÜéééèèèÜÜÜÛÛÛèèèäääÔÔÔÚÚÚÍÍÍÙÙÙÓÕ×Ùר®¾ÄZ¡¹b§¿b©À]´`v±_‡‡h |gšƒf™g›€f›~gb“{`Ž{a‘{Y~zUn‰awÛÜÜééééééÜÜÜÍÍÍÐÐÐÔÔÔßßßëëëÚÚÚÕÕÕÜÝÝõñïÁÑÖ`°Êj·Ðg¹Ô^ªÂ\ƒˆVw|Wy|a‘{hž[…zXxWx}_‹{h‚g›gœ~Ux{_uŽÜÜÜéééèèèÝÝÝÛÛÛÙÙÙèèèçççåååçççèèèÖÖ×áÞÝÀÎÓZªÄb³Ík°Æn¥µ[‰sVu~Xo‘Ur€e˜}Z{Tm„ShŠX~yhže—€hX}_sÜÝÜéééèèèÝÝÝÚÚÚØØØçççåååæææææææææåååÕÖÖéæå¹Æm«ÀÙÛÜÙÖÖVm†XrŒZt‹Tk…\‡vf›{]‹uaz©a|¥`~gšfš|V|y_tÜÝÜéééèèèÝÝÝÛÛÛØØØçççæææææææææçççäää×××ìëëÞÝÝÏÐÑøôò§°¸ToˆYsŠXo’]u¡^zœ`ž`}Ÿe€°h€º_}™b—t^~”Uo_vŠÜÜÝéééèèèÝÝÝÛÛÛÙÙÙçççææææææææææææåååÓÓÓçèèáââãâá·½ÃNiƒ[uUl‹f€µhƒ·g·g€·g€·f€³g€µa}£[d~®Yr›_v‰ÜÜÝéééèèèÝÝÝÛÛÛ×××èèèææææææææææææçççÞÞÞÕÕÕÕÖÖâáߟ©³NhVqŠWqŠ[s›f€´f€²f€²f€²f€³f€³f€´e~µi‚·Um’\t†ÜÜÝéééèèèÜÜÜÞÞÞÚÚÚÙÙÙååååååääåäååääåçççàààÓÓÓØØØÐÑÒÕÖÖŒš§Ni[sšgµf€²f€³f€³f€³f€³f³g´a|«\¹g¦ºÜÜÝéèèèèèÜÜÜÜÜÜèèèÛÛÛÙרâááðïîíìëîíìÚÙØßÞÝÖÖÖÐÐÐØØØìììêèåx‰¦b}´g³f€³g€´g´g´g€´h´a{«`¡¼f¹Òl°ÇÜÝÝéèèèèèÜÜÜÛÜÜîíîÝßÞ¼ÅÁ¶»¾ÂÆËÀÅÉ¿Ãȳ¸¼ÆÉÍêéèèèèçççããäîì錛¹Zw¯h‚´g~³a~¬`‚­`­`‚­_€«`¡¼h¸Ïd²Ìk®ÄÜÝÝéèèèèèÛÛÛàÝÞר×rš‡ZŽsPl}SmˆRm…Rm…Tn‡Nh‚—¢¬ïíëåææåååééèÏÑÕp†¯d~³`¬`¨Àd²Éc°Çc°Çd±ÉgµÎf²Ëd´Îk®ÄÜÝÝéèèêéêÖØ×{œŒk˜‚b—}iœY||Xo[sZr[u[vŽNi„˜£­íëêåååããäòð칿Ë[s§a¡»h¹Ñg³Ìg´Íg´Íg³Íf²Ëg³Ìe´Íl®ÄÜÝÝéèèêêêÕØ×a”{cšgšfše™~X~zWxWy}UqƒYs[uŽJg‚¤­¶ñðîäåæïîì¿ÅÑ[t©b¥Áf·Ðe³Íe´Íe´Íe´Íe´Îf´ÍdµÏk¯ÆÜÝÝéèèêéêÖØ×i“~g–g–f•~g–h˜~g—}g˜{Yw|Zq‹]uŠSl……’ŸåãâÙÙÚäãà¶»Æ\s£cž¸h±Çf­Äg­Äg­Äg­Äg­Äg­Äe®Ælª¾ÜÝÝéèèæææäääÖØ×ÕØ×ÖØ×ÖØ×ÕØ×ÕØ×ÖØ×ÖØ×Õ××ÕÖØÕÖØÕÖרÙÚÝÝÜÜÜÜÝÝÜÚÚÛÕÖÙÕÙÚÖÚÛÖÚÛÖÚÛÖÚÛÖÚÛÖÚÛÖÚÛÕÙÛ×ÚÛåååæææææææææêéêêêêêêêêêêêêêêêêêêêêéêêêêêêêêêêëêêêêéèèèèèèèèèéééêêéêééêééêééêééêééêééêééêééêééêééææææææ(  ååæÜÛÝÚÛÜÜßàÛÞàÛÜÞÜßâÛÞàÜÛÞÜÜßÛÞßÜßàÜßàÛßßÜßßåååÛÜáo…¥gŸµq¾Òl•µpµk’«aƒ’j„¬nˆ³n­ÄpµËp³Ém´Ëx¶ÍÜßàØ×ÜgŽ´\¦¾Y†¡b}¶`£avY’˜_˜½_†°b±Êc²Ìe´Ð_¯Çi¡ ÛÞÝØÙÛb{“XtŒZmŠ_|˜g™~e‡fºÏe Áey­`³fµÍf°È^”ˆqœÜÞÝ×ÙÛ\sŠPk‡Rpƒa”xb|Zƒ[ª`|§c‘¹e³Êf³Í_”Up}f‡ŠÛÝÝÞßß¾ÃÈÅÊЩ³¹\z„Wr‰Yp‹Xo‡Wk†^—¯hºÕf·Ð`“ˆUnˆcy“ÛÜÝáááèçæïîìðïîÇÊÐZsŒYsŒZuXm‹^•·d°¿]—§ZˆVpˆd|’ÛÜÝááááââããäèçæ¦°¹Uoˆ[vYraz§b””eœ_‡yWo‰Upˆdz’ÛÜÝàààØØØÞÞÞÚÚÚÕÔÕÀÌÑ^©ÁY¡¾\€Žbxe•€]ˆ~b’{^Ž}c|ÛÜÞâââØØØåååçèèæäãÖÛÜ}¹Í ÅÌ^z„Uo†^ŒxXtŒb‰Œd›ydŠÛÛßâââÛÛÛææææææââãÝÝÝåãᥬ¶Piˆaz¦c€§f‚±d¨\‚dv”ÛÜÛâââØÙÙåääëëêìëêááàØØØ£­·by`z©i‚¹f´g³a{±g©ÛÞÞáááëçéÐÓÑÊÎÐÐÓÖÉËÎßÞÞõòí´¼ÊZu«h²dƒ±d°`½p¹ÎÜßàßßߦ»±i™UsWn‹Rm†›¨´ëêéãää|޶[™¼d³Ëc¯ÉaµÎn³ÊÛßàÙÜÚl™ƒj›‚j•„eŠƒa{ŒVoˆ»ÁÇòîꔢ¼c¦Áp·Ín³Êk²Êv´ÈÜßàåååÛÞÜÙÜÚÙÝÛÚßÚØÚÚØÙÛÜÝÞáááÚÛÞØÜÞØÝߨÝߨÝßÚÞßååå(0` æææçèèêæåêéçêêéרÙÚÚÚר×Ú×ÖÕÕÖ×רk¦by¤Zp†Xnƒbž³h¬Âb©¿b µaw¢h¬c{«a¦¾i¤·Tm„e~²`§ÀeªÁ_zªMi‚g¸Òf³Í_ªÁg‚¸f´i„¹[¡·Zsžh·Ðf¶ÑY—®`¯Èh¶ÎZ‰©h‚·Yz‰c“{Z†tWq‰\œ²Z‡¨e™}iƒaŽyRj~_§ÀU…›_x¦fšYš®_¦½Z’’\vh”~i¹Ód•vUl‹ZsŒ\u¢Vp‡Z‘Tuv_y_¨¾Uwx\Šu_ŽyUxvÅÇÈÏÐÒÃÅÆOh{ÜØ×ðððŽ˜£Lg‚”ž¨’œ¦ÇÉÉZ|†ÌÌÌ]wàßß“´¿\®È޲¾Š–¡i¯Of‰“©ž‡“Ÿ”ŸµZv¬       !"#$$%&'&'&' ()***+,""-./011 #2)')))& &+"-3456)2&)&7  *869#!-3::.;<<+'**=55 %(8>""-3:?:5@*<"+ =A:? BB0CCBB-3:?:A=)*<""D*)=.::? C>CCCCCCEB-.:::.F'"""D**'=.:::?ECCCCCCCBG34::4H@**+,+CCC RSSCEE>CCCC0CCCCC>B'CCC  OTU>CCCCCCCCCC<'*@.5CCCCE VCCCC0CCCC<*<;K/>CCCC VECCCCCCCEB% @=H/6CCBC> WCCCCCCC0B#1 =A4H>CCCCCCC RCCCCCCCC9#-HH?:::JBCCCCCC>C  X C0EBE09"Y.4:::::3J6ECCC RZZZ N11.:::::4:4:LL5[M0CCZZ\SRO\S*D%/H?::3LLLH:4:43MB ZOZ\X\ 'LKQJ34L6EE6H::3:LCR\Z)1KK>BJ?H6E6H:?:?.C\]^^]P6CC>.:./%9Y33:4. ]_SCCCCQ/5./#Y3?5/CR`CEB9999",9..%%CT>BB#"!""""""9K/C\X\S>C0B""a""a"""  CR XZ E>EB""""""""""#DEZ\\OXW0B"""""""!2Z ZZZSTb"""""""""#+*\  \",,,"""",+* XP OO PX  #",9+*)RScLK600Bdef""+III I*PcL4.CCCCCCCde+@*****5..::3M0>C>CCCCd ?:::::3M6CCC>` *?::3:::3H../CCCC *****&)???????????5 CC NN   R  ( @åååéééêèåçèèÜÜÜÖÙÛlƒ®ZtŒk±Æh§¼i~ªi‚´e¤Áb“¨]u†hz¦b£¼k®Älª¾c|¬U{W¦e³Ìf¶ÒfºÓ]žºf€´i¼\t¤\–’V‚‹Tm…Y‹«_‚­^zªj´Ìb›¹_£´^”´f~³^Œ‚hœ}Y}|Vr‹c±Æa‹²h¸Ï]¡¹n¥µ^°Xˆ ZoŒ^‹{fš~i“~_˜’`v±ÕÖÙUm’UxUnŠgše—€d”|_Ÿ¨hµ`¥´j›‚Ùר^ž£i¶ÐiºÒUr„c®Èe¬ÃYw|Lg„NiƒVv}i }Wy|`™\†v˜£­ž©³œ§±¤­¶v‰‘Vy’a›‘\…z[s`wéæåóñîúöó®¾Ä_™ŽZo…[s›]|¤k’_”ŒâáßÌÍÍÔÕÕÙÖÖ·¼Å\ªÃ]„„ÏÑÓ¿ÅÑ\Œt֨׹Æa}£§°¸Xo’_|›`~Ÿb—t^~”Pl}`‚­Œš§ðïîx‰¦¼ÅÁµº½ÁÆÊÆÉÍŒ›¹[v¬áÞÞrš‡—¢¬_§Á{œŒ¿ÃÈ…’Ÿfž¶    !" # $%&'()*+,-%.#/0123 4567,-8&%469+:;<<4=>?@-A&B?5CD(==5EF,! !&GB4?=C9H4==54@IJ1'&.B4K4>9LMLNO=?P+;:AQR3DSTUUVWNKH++=ZH++\ihD9jk/l/%8m)==)5=?4?*<\hni9^o,lmPP?=ZP4==5P\D9ol0pN:H5ZM=5*NPH[MV^}„ q6>555656K‹DkŒJJJJJJqqqqqqq999( ååæÜÛÝÚÛÜÜßàÛÞàÛÜÞÜßâÜÛÞÜÜßÛÞßÛßßÜßßåååÛÜáo…¥gŸµq¾Òl•µpµk’«aƒ’j„¬nˆ³n­ÄpµËp³Ém´Ëx¶ÍØ×ÜgŽ´\¦¾Y†¡b}¶`£avY’˜_˜½_†°b±Êc²Ìe´Ð_¯Çi¡ ÛÞÝØÙÛb{“XtŒZmŠ_|˜g™~e‡fºÏe Áey­`³fµÍf°È^”ˆqœÜÞÝ×ÙÛ\sŠPk‡Rpƒa”xb|Zƒ[ª`|§c‘¹e³Êf³Í_”Up}f‡ŠÛÝÝÞßß¾ÃÈÅÊЩ³¹\z„Wr‰Yp‹Xo‡Wk†^—¯hºÕf·Ð`“ˆUnˆcy“ÛÜÝáááèçæïîìðïîÇÊÐZsŒYsŒZuXm‹^•·d°¿]—§ZˆVpˆd|’áââãã䦰¹Uoˆ[vYraz§b””eœ_‡yWo‰Upˆdz’àààØØØÞÞÞÚÚÚÕÔÕÀÌÑ^©ÁY¡¾\€Žbxe•€]ˆ~b’{^Ž}c|âââçèèæäãÖÛÜ}¹Í ÅÌ^z„Uo†^Œxb‰Œd›ydŠÛÛßÛÛÛæææââãÝÝÝåãᥬ¶Piˆaz¦c€§f‚±d¨\‚dv”ÛÜÛØÙÙåääëëêìëêáá࣭·by`z©i‚¹f´g³a{±g©ÛÞÞëçéÐÓÑÊÎÐÐÓÖÉËÎßÞÞõòí´¼ÊZu«h²dƒ±d°`½p¹Îßßߦ»±i™UsWn‹Rm†›¨´ëêéãää|޶[™¼d³Ëc¯ÉaµÎn³ÊÛßàÙÜÚl™ƒj›‚j•„eŠƒa{ŒVoˆ»ÁÇòîꔢ¼c¦Áp·Ík²Êv´ÈÛÞÜÙÝÛÚßÚØÚÚÜÝÞÚÛÞØÜÞØÝßÚÞß   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghij[\kl]mnopqrstuvw[xyz{|}~€‚ƒ„…†‡y ˆ‰Š‹ŒŽ.‘’“‡”••–—˜™š›œžŸ ¡‡¢£¤¥¦y§¨©ª«¬­®¯\°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÌÚÛ ÜÎÝÞß,à\áâãããä (0`€€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿ÷ÿ÷ÿÿÿÿ÷ÿw‡wwwwxxwwwxwwwwwwww÷÷wxw÷wwww÷wwww‡ÿÿ÷÷÷÷xwwÿÿwww‡xww‡ww÷w÷÷wÿ÷wÿw‡ww‡‡www÷÷÷ÿ÷÷ÿwww÷w‡wwwww‡w‡w÷w÷w÷wwwww‡www÷wwÿw÷÷÷‡wx÷wwww‡www÷÷wwwwÿwww‡xwwwww‡wwÿwwwww÷÷www÷www‡xxxwwwÿww‡‡ÿ÷wwwwwwwwwwwwwwwÿ÷‡ww÷÷÷w‡w÷wwwwwwwwwÿwww÷wÿwwxwwxwwwwwwwxxww‡ww÷÷wwwxw÷wwww‡wwwww‡www÷÷wxwww÷wxww‡w‡wxwwxx÷w÷wwxwwÿÿ÷w‡‡wwwwwwwÿww‡wwwÿÿÿÿwwwwwwwwww÷w÷w‡ww÷ÿÿÿÿ÷wwwwwwwwÿwwwwwÿÿÿÿÿÿ÷wwwwwwww÷÷÷w‡wwÿÿÿÿÿÿxw‡xwxxwwwˆwwwÿÿÿÿÿÿ÷wwwwwxw÷‡xwwwxwwÿÿÿÿÿwwwwwwww‡wwwwwwwwÿÿÿÿÿÿwwwwwwwww‡wwwxwwww÷ÿÿÿw‡w‡‡x‡‡wwwwxwxwwÿÿÿ÷ÿÿwwwww‡wwwwxx‡‡wÿÿÿÿÿÿ÷÷wwwwwwwwwww÷÷ÿÿ÷ÿ÷ÿ÷÷ˆw‡wx‡xwwww÷ÿÿÿÿ÷ÿ÷wÿ÷w‡xwwwwwww‡ÿ÷ÿÿÿÿÿw÷ww‡‡wwwˆˆwwwwÿÿÿÿÿÿÿÿÿwwwwwwwwww‡ÿ÷ÿÿÿÿÿÿ÷ÿÿ‡w‡‡xwwxwx‡w÷ÿÿÿÿÿÿÿÿ÷ÿ÷wwwxw‡www‡w÷ÿÿÿÿÿÿÿÿÿxw‡wwwwwwˆwwÿÿÿÿÿÿÿwÿ÷÷wwwwwwwwwww‡ÿ÷ÿÿÿÿÿÿÿ÷wwxwwwx‡wwww÷÷ÿÿÿÿÿÿ÷÷÷www‡wwwwwwxxwÿ÷ÿÿÿÿÿÿÿÿÿÿwxwwwwwwwwÿÿÿÿ÷wwÿ÷wwwwwwwwwÿÿÿ÷ÿÿÿÿÿÿÿÿÿww‡wwwwwwÿÿÿÿÿÿwÿÿÿÿÿwwwxwxxÿÿøwxwxw‡ÿÿÿÿwwwwwww÷÷ÿwwwwwwwÿÿÿ÷wwÿÿ÷÷÷÷xwx‡wwwwwÿÿÿÿww÷÷÷÷wwwwwwwwwwÿÿÿwwwÿ÷÷ÿwwwwxx‡‡wwwÿÿÿww÷÷ÿ÷wwwwwwwwwwÿÿÿww÷w÷÷ÿøwwxwww‡wx‡ÿÿxw÷ww÷wwwÿwÿ÷÷÷ÿwÿÿwÿÿ÷ÿÿÿÿÿ( @€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ÷÷÷wwÿw÷w÷÷w÷wxƒ7ˆˆ…‹ƒˆˆ‡·—‡·wøˆ‡·¸ˆˆˆƒ¸‹yx»x·{—»ˆ‰y88w˜‹‡¸x»ø‹x‰ˆ‡ƒ‹¸˜·{{·x‡sˆ8ˆ¸8ˆ‡yˆ8‹ˆ‰8?x…˜8ˆˆ‡‹ƒ‡u··xƒ‡x8ˆ88ˆ;{·y7s¸8ˆxX8ˆˆƒˆˆˆx‡‹sˆ3‡óƒˆ88ˆ˜88›‹‡ˆ˜ˆ‡w÷wó88ƒˆˆ7·yˆˆˆ‡ÿÿxqˆˆ3‰ˆ¸·¸ƒ˜?÷÷ÿw˜8Xˆw¸88ˆ?÷÷ÿwˆ888[¸ƒˆˆƒ‡wÿÿƒˆ‰ˆ‹‹ˆˆƒ‰ƒ‡÷÷wxƒˆƒ…ˆ8ƒˆƒˆ‡÷÷ww‹¸ˆˆˆˆˆˆ8?w÷wÿ÷ˆxƒƒ¶ƒƒƒˆ‡÷÷÷ww{yˆƒˆƒƒˆƒ?wÿ÷ÿ¸÷ƒˆ8ˆ7ˆˆ‡÷÷÷ÿw÷˜8‰ˆ‰7ˆ‡÷÷÷÷÷÷ó8xˆ¸‡ƒ‰‡w÷ÿƒˆsx¸ƒˆs‡ÿÿw÷÷wƒ˜˜ˆ‡ˆ˜¿÷w÷÷x——¸—ˆ›w÷ÿ÷wøˆˆ‰s‹xww÷xx‡‡ÿwsˆ‡9‡··x¸88ƒ÷ÿy‹{w¸ˆ‡xˆˆ8ƒXWÿ󸈷·‡·ø8ˆ8ƒƒƒ‡÷xW·‰x·‡x¸hˆˆƒ8ÿø‹‹‡{{w÷wÿw÷www÷÷ww( €€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿÿw÷÷÷w󗋈ˆ¸w¿wsˆ7¸‡x‡sˆˆ‹y‹³x8ƒˆ‹¸ˆ‡÷w…˜ˆwƒwÿxˆ˜yƒ7ÿs8ˆƒˆw¸8ˆˆ‡÷÷÷w888w÷w‰ˆ˜?ÿ÷‡‹‡‡ÿw÷sˆ‡·wƒƒø‹¸‡xˆˆ7w‡¸w÷÷wÿpuzzles-20170606.272beef/icons/magnets.ico0000644000175000017500000006117613115373734017153 0ustar simonsimon 00 ¨%–  ¨>& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÒÒÕÒÒÕÒÒÕÒÒÕÒÒÕÒÒÕÒÒÕÒÒÕÒÒÕÒÒÕÒÒÕÒÒÕÔÔÕÕÕÕÔÔÔÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÝÝÝãããâââââââââââââââââââââââââââââãââÞââÕââÖââÖââÖââÖââÖââÖââÖââÖââÖââÖááÖ××ÕÔÔÔØØØââââââââââââââââââââââââââââââßßßÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÜÜÜ¡¡¡BBB<<<=======================?==4==f==×==Í==Ï==Ï<<Ï>>ÏAAÏ@@Ï==Ï==Ï99ÎooÑÒÒÔØØØÊÊÊ```999>>>=====================ÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÃÃÃ:ØÉËËÌËËËËËÌËvvÎððâYY\®®®ÝÝÝÓÓÓÕÕÕÕÕÕÕÕÕÓÓÓÝÝݳ³³<ØÉÌÌÌ%%Ή‰ÒhhÐÌÌÌËXXÍòòâ99=˜˜˜âââÒÒÒÕÕÕÕÕÕÕÕÕÓÓÓÝÝݳ³³:ØÉÌÌË??Ïüü×¾¾ÔÌÌÌËYYÍòòâ::>™™™âââÒÒÒÕÕÕÕÕÕÕÕÕÓÓÓÝÝݳ³³ :ØÉÌ ÍÌCCÏååÖ¯¯Ó Ì Í ÌËXXÍóóã99= ˜˜˜âââÒÒÒÕÕÕÕÕÕÕÕÕÓÓÓÝÝݳ³³sssØØØÅÅÅÈÈÈÈÈÈÆÆÆÔÔÔ:ØĘ́¨ÓÏÏÕÊÊÕÖÖÕÓÓÕÄÄÔØØÕYYÐË[[Íóóã;;>###ËËËÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈËËË###šššâââÒÒÒÕÕÕÕÕÕÕÕÕÓÓÓÝÝݳ³³~~~ìììØØØÜÜÜÜÜÜÙÙÙééé:ØÉ̹¹ÔååÖØØÕÔÔÕÖÖÕØØÕííÖaaÐË\\Íóóã;;>&&&ßßßÛÛÛÜÜÜÜÜÜÜÜÜÛÛÛßßß&&&šššâââÒÒÒÕÕÕÕÕÕÕÕÕÓÓÓÝÝݳ³³$$$!!!!!!!!!!!!###:ØÉÌÍÍRRÏääÖ´´ÔÍ$$ÎÍËYYÍóóã99="""!!!!!!!!!!!!!!!"""™™™âââÒÒÒÕÕÕÕÕÕÕÕÕÓÓÓÝÝݳ³³:ØÉÌÌË>>Îøø×»»ÔÌÌÌËXXÍóóã99=˜˜˜âââÒÒÒÕÕÕÕÕÕÕÕÕÓÓÓÝÝݳ³³:ØÉÌÌÌ++Χ§Ó~~ÑÌÌÌËXXÍòòã99=˜˜˜âââÒÒÒÕÕÕÕÕÕÕÕÕÓÓÓÝÝݳ³³<ØÉÌÌÌÌÌÌÌÌÌËYYÍóóã99=˜˜˜âââÒÒÒÕÕÕÕÕÕÕÕÕÔÔÔÖÖÖÓÓÓAAA:×ÈËËËËËËËËË Ì  Ðêêâ;;=˜˜˜âââÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÏÑÏ ž š˜šœšœ›™››™››™››™››™››™››™œ›™˜›™¬›™Ù›™Õ›™Õ›™Õ›™Õ›™Õ›™Õ›™Õ›™ÕœšÕ™—ÖººÔÙÙÑááâ===˜˜˜âââÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÕÝØÝÙÞÙ×Þ××Þ××Þ××Þ××Þ××Þ××Þ××Þ××Þ××ÞØ×ÞÓ×ÞÊ×ÞË×ÞË×ÞË×ÞË×ÞË×ÞË×ÞË×ÞË×ÞË×ßÊÝÛØÕÒÙáâ×==·©¬«««««««¬©˜˜Éââ×ÒÒÔÕÕÕÕÕÕÕÕÕÕÕÕÔÕÔÙÖÙ}¹}#š# ™ "š"!š!!š!!š!!š!"š"!š!!š!!š!!š"!š$!š$!š#!š#"š%!š$!š$!š$!š$#š%™!H§I¿ÌÂåãÙ<<ÓÔÔÔÔÔÔÔÔÔÔÔ˜˜ÕââÕÒÒÕÕÕÕÕÕÕÕÕÕÔÕÔÛ×۽ͽ˜—™–™˜˜™–˜˜˜˜˜˜™˜—™˜˜˜–š’o²rðæä9<ÊÊÊÊÊÊÊÊÊÊÊʘ˜ÒââÖÒÒÕÕÕÕÕÕÕÕÕÕÓÔÓÜ×ܶ˶™—S«SI¨I • šš–:¤:_¯_˜š™™™™e±e-Ÿ-—šš•V¬VJ©J’g°iñçä9<ËËÌÌÌeeÐÎÎÕeeÐÌÌÌ˘˜ÒââÖÒÒÕÕÕÕÕÕÕÕÕÕÓÕÓÜ×Ü·Ì·˜™™l³lF§F––5¢5s¶s"œ"˜™™™™˜,Ÿ,v¶v*ž*—–S«Sb°b™ • g°jñçä9<ËËÌÌË{{Ñÿÿ×{{ÑËÌÌ˘˜ÒââÖÒÒÕÕÕÕÕÕÕÕÕÕÓÕÓÜ×Ü·Ë·˜™˜˜o´o>¥>-Ÿ-v¶vš—™™™™™š–(ž(x·x!›!MªMd±d–š • f°iñçä:<ËË Í??Ï//ÎÒêêÖÒ//Î??Ï ÍË™™ÒââÖÒÒÕÕÕÕÕÕÕÕÕÕÓÕÓÜ×Ü·Ë·˜™™™–y¸y‹½‹˜˜š™™™™™™š— › –Á–h²h ” šš ” f°iñçä;>ËË((ÎííÖëëÖÞÞÕÒÒÕÞÞÕëëÖííÖ((ÎËššÓââÖÒÒÕÕÕÕÕÕÕÕÕÕÓÕÓÜ×Ü·Ë·˜™š–5¢5i³ii²iC¦C–š™™™™™™š–MªMg²gi²i+ž+—› ” f°iñçä;=ËËÍ´´Ô­­ÓÄÄÔÛÛÕÄÄÔ­­Ó´´ÔÍËššÒââÖÒÒÕÕÕÕÕÕÕÕÕÕÓÕÓÜ×Ü·Ë·˜š–5¢5u¶uš—n´nF§F • š™™™™™ • S«Sd±d ” )ž)w·w)ž)— • f°iñçä9<ËËÌÌËttÑññÖttÑËÌÌ˘˜ÒââÖÒÒÕÕÕÕÕÕÕÕÕÕÓÕÓÜ×Ü·Ì·™—9£9s¶sš˜™˜l³lH¨H—™™™™—T¬Tb°b–š—(ž(v¶v1¡1“h°jñçä:<ËËÌÌË€€Ñÿÿ×€€ÑËÌÌË™™ÒââÖÒÒÕÕÕÕÕÕÕÕÕÕÓÔÓÜ×ܶ˶˜˜A¦A%%—šš˜šE§E™™™™™šF§F˜™™š—. .?¥?“f°iðæä:=ËÌÌÌÌ33ÎiiÐ33ÎÌÌÌ̘˜ÒââÖÒÒÕÕÕÕÕÕÕÕÕÕÔÕÔÛ×۽ͽ˜—–—˜˜˜˜˜–˜˜˜˜˜˜–˜˜˜˜™——“n²qðæäFHÌËÌÌÌËËËÌÌÌË¡¡ÓààÕÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÔÕÔÙÖÙ|¸}#š%"š%"š%!š$!š$!š$!š$!š$"š%!š$!š$!š#!š!!š!!š!"š"!š!!š!!š!!š!!š!#š# ™ G§GÀÍÂßÜÙ®¯Ò''Í Ì Ì ÌÌÌÌ Ì Ì Ì[[ÏÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÖÝØÜÙÞÎ×ÞÊ×ÞË×ÞË×ÞË×ÞË×ÞË×ÞË×ÞË×ÞË×ÞÊ×ÞÎ×ÞØ×Þ××Þ××Þ××Þ××Þ××Þ××Þ××Þ××Þ××ß×ÝÛÝØÕØÓÔÔÜÜÕÖÖÖÊÊ×ÌÌ×ËË×ËË×ËË×ËË×ËË×ËË×ÍÍ×ßߨÚÚØÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÕØÙÕÐÑÓ ŸÕš˜ÕœšÕ›™Õ›Õ›ÕœšÕ›™Õ›™Õ›™Õ›™Ù›™Å›™˜›™œ›™››™››™››™››™››™››™›œšœ™—™ºººÛÜÛÔÔÔÕÕÖÎÎÎÌÌÈÌÌÉÌÌÉÌÌÉÌÌÉÌÌÉÌÌÉÌÌÉÌÌÉÇÇÉÈÈÉÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÔÔÕÖÖÕÓÓÕBBÏËËËËÊÊËËËÈב £££ßßßÄÄÄ©©ª¦¦§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ÎÎÎ×××ÕÕÕÕÕÕÕÕÕÓÓÕÝÝÕ³³ÔÌÌÌÌÌ##Í&&ÎÌÌÌÉØ“[[[èèè²²²§§§««««««««««««««««««««««««««««««ªªªÎÎÎ×××ÕÕÕÕÕÕÕÕÕÓÓÕÝÝÕ³³ÔÌÌÌÌÍÌÌÕßßÕ%%ÎÌÌÉØ’[[[èèè³³³¨¨¨«««ªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©ÎÎÎ×××ÕÕÕÕÕÕÕÕÕÓÓÕÝÝÕ³³ÔÌÌÌË ÌÈÈÔÛÛÕ!!ÍËÌÉØ’ZZZèèè²²²§§§«««ªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©ÎÎÎ×××ÕÕÕÕÕÕÕÕÕÓÓÕÝÝÕ³³ÔÌÌEEÏ~~ÑzzÑÏÏÕØØÕ„„ÒzzÑUUÐÉØ’ddd{{{uuuvvvvvvttt€€€666\\\èèè²²²§§§«««ªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©ÎÎÎ×××ÕÕÕÕÕÕÕÕÕÓÓÕÝÝÕ³³ÔÌËÒÿÿ×ïïÖ××ÕÔÔÕííÖÿÿׯ¯ÓÉØ’ÎÎÎÿÿÿóóóõõõõõõñññÿÿÿlll___èèè²²²§§§«««ªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©ÎÎÎ×××ÕÕÕÕÕÕÕÕÕÓÓÕÝÝÕ³³ÔÌÌEEÏ~~ÑzzÑÏÏÕØØÕ„„ÒzzÑUUÐÉØ’ddd{{{uuuvvvvvvttt€€€666\\\èèè²²²§§§«««ªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©ÎÎÎ×××ÕÕÕÕÕÕÕÕÕÓÓÕÝÝÕ³³ÔÌÌÌË ÌÈÈÔÛÛÕ!!ÍËÌÉØ’ZZZèèè²²²§§§«««ªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©ÎÎÎ×××ÕÕÕÕÕÕÕÕÕÓÓÕÝÝÕ³³ÔÌÌÌÌÍÌÌÕßßÕ%%ÎÌÌÉØ’[[[èèè³³³§§§«««ªªªªªªªªªªªªªªªªªªªªªªªªªªª©©©ÎÎÎ×××ÕÕÕÕÕÕÕÕÕÓÓÕÝÝÕ³³ÓÌÌÌÌÌ##Í&&ÎÌÌÌÉØ“ZZZèèè²²²¨¨¨««««««««««««««««««««««««««««««ªªªÎÎÎ×××ÕÕÕÕÕÕÕÕÕÔÔÕÙÙÕÃÃÔÌËÌËËËËËËËÉØ‘xxxååå¹¹¹¥¥¥¨¨¨§§§§§§§§§§§§§§§§§§§§§§§§¨¨¨§§§ÎÎÎ×××ÕÕÕÕÕÕÕÕÕÕÕÕÓÓÕÜÜÕ¡¡ÓBBÏ<<Ï==Ï==Ï>>Ï??Ï==Ï==Ï==Ï==Í==×==¥==4==?=====================>>>999nnnÒÒÒÖÖÖÒÒÒ½½½¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶¶ÐÐÐÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÕÝÝÕããÖââÖââÖââÖââÖââÖââÖââÖââÖââÖââÕââÙââãââââââââââââââââââââââââââââââáááÖÖÖÔÔÔÖÖÖØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÕÒÒÕÒÒÕÒÒÕÒÒÕÒÒÕÒÒÕÒÒÕÒÒÕÒÒÕÒÒÕÒÒÕÒÒÔÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÔÔÔÕÕÕÕÕÕÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ( @ ÕÕÕÕÕÕÒÒÒÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÑÑÕÑÑÕÑÑÕÑÑÕÑÑÕÑÑÕÑÑÕÑÑÕÓÓÕÕÕÕÒÒÒÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕáááåååäääääääääääääääääåääáääÕääÖääÖääÖææÖååÖääÖååÖÛÛÕÔÔÕààßåååäääääääääääääääâââÖÖÖÕÕÕÕÕÕÕÕÕ×××€€€NNNTTTSSSSSSSSSSSTSSLSSqSSÕSSÎSSÏRRÏKKÏPPÏSSÏVVв²ÒààÛŽŽNNNTTTSSSSSSTTTNNNuuuÓÓÓÕÕÕÕÕÕÞÞÞ¯¯¯1ÔÊËÌÍÌÌÊHHÓÏÏÄ ›››àààÒÒÒààਨ¨4ÕÊËÌààÕccÐËÊ??ÔÈÈ¿“““âââÒÒÒààà©©©HHHBBBBBBGGG--/2ÕÊ44ÎQQÏÛÛÕ††Ò==ÏË;;ÔËËÀGGGBBBBBBFFF888”””âââÒÒÒààà«««```øøøãããäääööö››ž4ÕÊ¿¿ÔïïÖÑÑÕÜÜÕööÖ,,Í22ÓÏÏÂ>>>ôôôååååååòòò¼¼¼”””âââÒÒÒààà©©©)))%%%&&&)))2ÕÊÍ55ÎààÕxxÑÍË==ÔÊÊ¿ )))&&&&&&(((!!!“““âââÒÒÒààਨ¨3ÕÊËÌÎÎÕ[[ÐËÊ@@ÔÉÉ¿“““âââÒÒÒßßß«««1ÓÉËËËËËÉCCÔÉÉ¿““”âââÒÒÒÖÖÖÒÓÒaaa2/296975775775775975/75]75Ù75Ñ85Ò74Ò52Ò74Ò85Ó64Ф¥×ÆÆ¿“““âââÒÒÒÔÔÔÚØÚßàßÍØÍÏÙÏÍÙÍÎÙÎÎÙÎÏÙÎÍÙÎÎÙÌÎÙÅÎÙÅÏÙÆÎÙÅÎÚÅÎÙÅÍØÅÒÚÈçäݾ¾Ì„‚‚‚‚ƒ}““»ââÚÒÒÔØÖØÊÑÊ@¤@—™ š š ™˜ ššš!š!˜š š!!š"˜–Š¿†ÈÁߨÚÚÚÙÚÚÚ““×ââÕÒÒÕßØß¬È¬“5¢5,Ÿ,–˜š=¤=—˜˜™?¥?˜˜–7£8™G«AÉÂÞÇÉÉ::ËvvÎ ÉÉÈ““ÑââÖÒÒÕÞØÞ®È®—"œ"]®]+Ÿ+˜]¯]0 0˜™™˜;¤;W­W•9£9X­X•Q¯LÈÁÝÊÌËppÐëëÖ ÌËÌ““ÒââÖÒÒÕßØß­È­—˜™X­Xf±f&&—™™™™—1 1j³jNªN˜ ” Q¯LÊÃÝÊ..ΰ°Ó»»ÔÑÑÕ´´ÔŠŠÒË””ÒââÖÒÒÕßØß­È­—˜™X­Xf±f&&—™™™™—0 0j³jNªN˜ ” Q¯LÊÃÝÊ..ΰ°Ó»»ÔÑÑÕ´´ÔŠŠÒË””ÒââÖÒÒÕÞØÞ®É®–!›!\®\*ž*˜]®]/ /˜™™˜:¤:W­W • 8£8X­X•Q¯LÈÂÞÊÌËppÐëëÖ ÌËÌ””ÒââÖÒÒÕßØß«È« • :£:1¡1˜™"œ"B¦B™šššD§Dšš—<¤<#›$H¬CÈÁÞÊÌÌ==ÏyyÑ ÌÌË““ÒââÖÒÒÕÛ×۽ν˜‘ ’ ’ ‘  ’ ‘ ‘ ’  ‘ ’ ’ g³dÖÏßÊÊËÊÊËË˨¨ÒÞÞÕÓÓÕÔÕÔÙÖÚ¾Õ´¤Ñ”§Ñ˜¦Ñ–¦Ò–¦Ñ—§Ñ˜¦Ñ–¦Ñš¦Ñ¦¦Ñ¦§Ñ§¦Ñ¦¦Ñ¦¦Ñ¦¦Ñ¦ªÒªÐÕÑÛÚÖ»»ÕŽŽÕ‘‘Õ’’Õ””Õ’’ÕÕ¬¬ÖÜÜØÔÔÕÕÕÕÔÔÕØÙÔ¡œÙzqÞwÝ|tÝ{sÝ~vÝ~vÜ~uâ~vÆ~vz~v~v~~v~~v~~v~}u}‚z‚ÄÃÃØÙÙÑÐËÏÏÁÏÏÂÏÏÂÏÏÂÏÏÂÐÐÂÉÉÁÃÃÃÕÕÕÕÕÕÝÝÕ´´ÔÊÈÉÉÉÉÆÓ˜KKKßÞÞ©©ª¢¢¦¤¤§¤¤§¤¤§¤¤§¤¤§££¥¬¬¬ÔÔÔÕÕÕààÕ§§ÓÌÌË‚‚Ѹ¸ÔÌÊל:::ÛÛÛ©©©ªªª«««««««««««««««©©©°°°ÕÕÕÕÕÕààÕ©©ÓÌÍÍššÓËËÕ&&ÎËÖ›(((&&&&&&***999ÜÜÜ©©©ªªªªªªªªªªªªªªªªªª©©©¯¯¯ÔÔÔÕÕÕààÕ««ÓË``Ðúú×ÖÖÕÒÒÕööÖœœÐÖ›¾¾¾ñññååååååôôô------ÞÞÞ©©©ªªªªªªªªªªªªªªªªªª©©©¯¯¯ÔÔÔÕÕÕààÕ©©ÓËÍ==Ï¢¢ÓÉÉÕEEÏ--ÌÖ›777FFFBBBBBBIII666ÜÜÜ©©©ªªªªªªªªªªªªªªªªªª©©©¯¯¯ÔÔÔÕÕÕààÕ¨¨ÓÌÌËŒŒÒÅÅÔËÉ×›;;;ÛÛÛ©©©ªªªªªªªªªªªªªªª«««©©©°°°ÔÔÔÕÕÕààÕ¨¨ÓËÌÌÍÍÌÉÖ›:::ÛÛÛ§§§¨¨¨©©©©©©©©©©©©©©©§§§®®®ÔÔÔÕÕÕ××ÕÎÎÕEEÏÍÍÍÍÍËÖ¢ŒŒŒÞÞÞººº®®®°°°¯¯¯¯¯¯¯¯¯°°°®®®´´´ÕÕÕÕÕÕÔÔÕØØÕÜÜÕÒÒÕÓÓÕÔÔÕÔÔÕÒÒÕÒÒÕÒÒÕÒÒÔÒÒÒÒÒÓÒÒÒÒÒÒÒÒÒÓÓÓÒÒÒÕÕÕÝÝÝÕÕÕ×××ÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÕÔÔÕÖÖÕÖÖÕÖÖÕÖÖÕÖÖÕÖÖÕÖÖÕÖÖÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÕÕÕÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ(  ØØØÞÞÞÝÝÝÝÝÝÜÜÜÛÛ×ÝÝÕÙÙÕÛÛÕÝÝÕÜÜÛÝÝÝÝÝÝÝÝÝÜÜÜÕÕÕÈÈÈ>>> $$',,!22’((Ø88Ì$$ËaaÚ””'''|||ààà´´´***..1{ÛƒƒÎMMÌ..Ýaaa 556MMMãã㯯¯&&&…††Œ22"w44ÝÉÊÑ—˜ÎCCßYY^EEF••˜bbePPRâââ···€Ý54ÎÍ--ÞeecLLLãããÕÓՇއs~sx‚ytnu~¥uÆoyÂgs½ª¯×hgˆ8 I:MMvããßÂÏÂF°F4¬44«4=®>/ª&>®/5­&/©#lÅRedÙ×..ÙØKK×ääÕ·Ë·—5Ÿ5;¡;–”—>£A)™0B°4^_Î((ËÃÃÑRRÍKKÍãã̸ָ™ 9¢<?¤B˜–™B¥C.›1F²6^^Ð((ÎÃÃÓRRÏJJÏããֽν2§*$¥$¥+¦ ¢-§-"£"  Y¼KnmÒÍ--ÏÍUUÑääÖÖÕÖ’¥·u¬x¯˜±~•‘}—z‚šƒy”z¤²¢ÎÌ×¢£ÇÉ¡¡È¾¾Ë××Õ¼»ÔÒ%#Õ31ÒâQ+*+ÄÄÁ®®¦³³©±±¨±±®ÒÒÓ±±Ó̪«Ñ¼½Ï&'ÜE9:)ŒŽvxv999¹¹º§§©©©«§§©¯¯¯ÓÓÓ¶¶ÔÌhhÐ}}ÎÛK558&&&,,,¼¼¼¦¦¦©©©¨¨¨®®®ÓÓÓÄÄÔ##ÍÍÊÙ^ EEEÈÈȬ¬¬¯¯¯®®®³³³ÓÓÓ××ÕÒÒÕÊÊÕÊÊÔÍÍÕËËÏÍÍÌÎÎÎÍÍÍÔÔÔ×××ÓÓÓÓÓÓÓÓÓÓÓÓÕÕÕ(0` ÔÔÕÛÛÛÛ×ÛÕÒÙÏÑÏâââãâÛââÖÜÜÕ§§§BBB<<===4==f==Ö<=ÎCCÏkkÐÌÌËcccÅÅÅ:ÔËvvÎòòã[[[´´´×ÞØØ$$΋‹Ò ÌUUÐ666™—™ýý×»»ÔYYК™š ­­ÓYYÍuuuÇÇÉ¢¢ÒÌÌÖÄÄÔ"""€€€èèèììÖddÐÍRRϳ³ÔÍ++Î||Ñêê⚙Ԡž ›™¬›™Ù™—ÖÙÞÎ×Þ××ÞË==·«˜˜É{¸|!š#™H§I¿Ì½ͽ˜—“o²rñçä33η˷T«TK©K • <¤<_¯_d±d*ž*f°ik³kE§E4¢4u¶ux·x. .‹½‹–Á–ttÑññÖ‚‚ÒFHÌ™!›™Å»»»’ªªª{{{ÿÿÿôôômmm==¥   !"#$%& '() *+++++++ #,###- +++++++&.//0 123)- 4///4*566* (78- 44*4444449 ::;<:!=- 4444444+&'($ *>1?#-@ & - &  #A@ &B**********CDAADAAADEDE(F &GGGGHHHHHHHFHHHIJJJJJJJJJJJKLMNMMMMMMMMMMMMMMMMMMMMMOPAQRRNSRRRRSRRRRRRRRSRRRRSNTUVWAXRSYZSNN[\]RNNNNN^_SNN[YZT`7828#AXRNNabSRcdMRNNNNR_e_RRY^R[`V?'?KXRNRRa\fdNRRNRNRNS_eMZ^SNT^V=W"7"W#AXNNNN[LgRRNNNNNNNRSMh^[NM[aV>7777!AXRNN[caab[NNNNRNRN[Za^fSMT^V!<<33, p++6qqqqqqqqqqqq<!!#p++6 qqqqqqqqqqq3= p.o qq q qq 1v uoo( @ÔÔÔÑÐËÌÌÕÊÑÊÛÛÕãããââÖââÜÙÖÚ€€€LLLSSSSSLSSqUUÓRRÏHHÓKKÏ[[в²ÓŽŽuuuÝÛݱ±±2ÕËÍ ÌÎΠ››ßàß«««ÇbbÐ==ÔÉÉ¿“““DDD***64Ò„„Ò<<Î767aaaøøøÅÅÔììÖööÖ--Í:::óóó¼¼¼%%%Ì55ÎyyÑÖBBÔ2/296975975]75Ù85Ó¤¥ÔÎÙÎÒÚÈÎÙÅ‚}““»B¦B˜™"›#š!–Š¿†ÉÂÞÚ““Ó­È­‘7£8+Ÿ+—;¤;•G«AvvÎ šZ®Z/ / “ W­WQ¯LppÐf²e1¡1j³jNªN»»ÔŒŒÓ©©Ó½Î½‘ ŽÖÏß¾Õ´¦Ñ–§Ñ™¦Ñ¦ªÒª¡œÙ}tÝ~uâ~vÆ~v}‚z‚ÄÃÃÐЛ¤¤§››Ò&&ÎEEÏ¢ŒŒŒ   !"#  $%&'  ("#)****+,-.$&'/****0("#122!3456,7289("#/+::+);<=>&+::+)("#$&' (#?'   (1@A000B0CDEEE,,,EF'(""GGGGGHGGIIIIIIIH3JJJJJJJKLMNOPPOOOOQPOQQPORSTUUUUUUUVWXYZ[NO\NONN\NN]\O^T$<_$VW[`aZNabNOON\ac\d]eT$f4VW[NRdgZ[OOOO[hijNceT<klVW[RRdgPNOOOO]bieOceT6mklV"W[PaZNabNOON\dcYdceT$f4$VWc\hNOPMOOO`MOON\P^T.=$VnOooc]cXcXXcXcccXpgq;m"rstsstsssuuuuuuuvklVVVVlm"wxxxxxxyz{{{{{{{|}'~~~'}$$ "#€€€€€€€#m- 0########m;‚;:+::+7####€###m55988++########m‚.Fƒ60*** 0#########ml3$7"########m7########>;;>„…)))))))†"9###( ØØØÞÞÞÝÝÝÜÜÜÛÛ×ÝÝÕÙÙÕÛÛÕÜÜÛÕÕÕÈÈÈ>>> $$',,!22’((Ø88Ì$$ËaaÚ””'''|||ààà´´´***..1{ÛƒƒÎMMÌ..Ýaaa 556MMMãã㯯¯&&&…††Œ22"w44ÝÉÊÑ—˜ÎCCßYY^EEF••˜bbePPRâââ···€Ý54ÎÍ--ÞeecLLLÕÓՇއs~sx‚ytnu~¥uÆoyÂgs½ª¯×hgˆ8 I:MMvããßÂÏÂF°F4¬44«4=®>/ª&>®/5­&/©#lÅRedÙ×..ÙØKK×ääÕ·Ë·—5Ÿ5;¡;–”—>£A)™0B°4^_Î((ËÃÃÑRRÍKKÍãã̸ָ™ 9¢<?¤B˜–™B¥C.›1F²6^^Ð((ÎÃÃÓRRÏJJϽν2§*$¥$¥+¦ ¢-§-"£"  Y¼KnmÒÍ--ÏUUÑääÖÖÕÖ’¥·u¬x¯˜±~•‘}—z‚šƒy”z¤²¢ÎÌ×¢£ÇÉ¡¡È¾¾Ë××Õ¼»ÔÒ%#Õ31ÒâQ+*+ÄÄÁ®®¦³³©±±¨±±®ÒÒÓ±±Ó̪«Ñ¼½Ï&'ÜE9:)ŒŽvxv999¹¹º§§©©©«ÓÓÓ¶¶ÔÌhhÐ}}ÎÛK558,,,¼¼¼¦¦¦©©©¨¨¨®®®ÄÄÔ##ÍÍÊÙ^ EEE¬¬¬³³³ÒÒÕÊÊÕÊÊÔÍÍÕËËÏÍÍÌÎÎÎÍÍÍÔÔÔ×××  !"#$%&'()*+,-./0123456789:;<=<>?@ABC& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $ææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææåååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååææææææææææææææææææææææææææææææææææææåååæææææææææææææææææææææçççèèèééééééééééééééééééééééééééééééééééééèèèééééééééééééééééééééééééééééééééééééèèèèèèçççççççççççççççççççççççççççæææçççèèèææææææææææææææææææçççâââàààÝÝÝÙÙÙÚÚÚÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÙÙÙÚÚÚãããÝÝÝÙÙÙÚÚÚÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚáááßßßääääääääääääääääääääääääääääääááááááçççææææææææææææäääñññ¯¯¯...;;;888888888888888888888888999777)));;;888888888888888888888888999999___éééÛÛÛÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÛÛÛèèè­­­$$$áááèèèåååææææææåååèèèááá———ðððÞÞÞááááááááááááááááááááááááààà¡¡¡ÉÉÉåååàààááááááááááááááááááàààâââááá ‘‘‘øøøäääçççççççççççççççççççççèèèää䬬¬áááçççæææææææææåååçççååå    ÷÷÷äääèèèæææãããäääæææèèèèèèçççéééêêêêêêçççèèèèèèèèèèèèèèèèèèèèèçççèèèëëë–––öööâââæææææææææææææææææææææåååèèèèèèäääææææææææææææåååèèèäää õõõãããäääðððûûûøøøêêêåååæææåååçççÛÛÛãããææææææææææææææææææææææææåååæææèèè•••÷÷÷ãããææææææææææææææææææææææææçççÛÛÛäääçççæææææææææåååèèèäää žžžõõõáááííí±±±iiizzzÑÑÑëëëåååæææçççÝÝÝäääæææææææææææææææææææææææææææçççééé•••÷÷÷ãããææææææææææææææææææææææææçççÝÝÝäääçççæææææææææåååèèèäää žžžõõõáááððð‹‹‹………JJJ###åååçççåååçççÝÝÝäääæææææææææææææææææææææææææææçççééé•••÷÷÷ãããææææææææææææææææææææææææçççÝÝÝäääçççæææææææææåååèèèäää žžžõõõãããäääðð𨨨AAA<<<çççæææåååçççÝÝÝäääæææææææææææææææææææææææææææçççééé•••÷÷÷ãããææææææææææææææææææææææææçççÝÝÝäääçççæææææææææåååèèèäää žžžõõõãããåååììì«««111fffòòòäääæææçççÝÝÝäääæææææææææææææææææææææææææææçççééé•••÷÷÷ãããææææææææææææææææææææææææçççÝÝÝäääçççæææææææææåååèèèäää žžžõõõáááïï﨨¨666000ëëëæææåååçççÝÝÝäääæææææææææææææææææææææææææææçççééé•••÷÷÷ãããææææææææææææææææææææææææçççÝÝÝäääçççæææææææææåååèèèäää žžžõõõâââëëëÆÆÆuuu€€€ÐÐÐêêêåååæææçççÝÝÝäääæææææææææææææææææææææææææææçççééé•••÷÷÷ãããææææææææææææææææææææææææçççÝÝÝäääçççæææææææææåååèèèããã ›››òòòàààâââééé÷÷÷õõõçççâââãããâââäääÚÚÚâââçççæææææææææææææææææææææåååçççèèè“““óóóßßßãããããããããããããããããããããâââäääÛÛÛäääçççææææææææææææçççééé ©©©ÿÿÿóóó÷÷÷õõõóóóóóóõõõ÷÷÷öööööö÷÷÷ëëëîîîæææçççççççççççççççççççççææææææííí   ÿÿÿóóó÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷öööøøøéééäääçççæææææææææäääìììÊÊÊcccŸŸŸ“““•••••••••••••••••••••–––”””EEE”””îîîâââääääääääääääääääääãããéééÎÎÎ^^^   “““•••••••••••••••••••••–––___ßßßèèèæææææææææãããóó󤤤 NNNëëëÚÚÚÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÛÛÛéé饥¥ áááèèèåååææææææææææææåå壣£ÐÐÐíííèèèééééééééééééééééééèèèêêêæææ ™™™÷÷÷äääçççççççççççççççççççççççççç祥¥ÍÍÍíííèèèééééééééééééééééééèèèëëëááá999ÚÚÚéééåååææææææææææææèèèééééééæææçççççççççççççççççççççæææèèèèèè šššöööãããæææææææææææææææææææææåååçççééééééæææççççççåååâââããããããææææææèèèâââ999ÙÙÙéééåååææææææææææææçççÚÚÚãããææææææææææææææææææææææææåååçççæææ ™™™öööãããææææææææææææææææææææææææçççÛÛÛãããææææææäääðððùùùúúúùùùçççåååçççààà888ÙÙÙéééåååææææææææææææçççÝÝÝäääæææææææææææææææææææææææææææçççççç ™™™öööãããææææææææææææææææææææææææçççÝÝÝäääçççäääîî¬|||vvv{{{àààççççççááá888ÙÙÙéééåååææææææææææææçççÝÝÝäääæææææææææææææææææææææææææææçççççç ™™™öööãããææææææææææææææææææææææææçççÝÝÝäääçççãããóó󌌌PPPƒƒƒÝÝÝèèèçççááá888ÙÙÙéééåååææææææææææææçççÝÝÝäääæææææææææææææææææææææææææææçççççç ™™™öööãããææææææææææææææææææææææææçççÝÝÝäääçççæææäääóóó///ÖÖÖïïïäääèèèááá888ÙÙÙéééåååææææææææææææçççÝÝÝäääæææææææææææææææææææææææææææçççççç ™™™öööãããææææææææææææææææææææææææçççÝÝÝäääçççæææåååçççÿÿÿvvv'''êêêæææçççááá888ÙÙÙéééåååææææææææææææçççÝÝÝäääæææææææææææææææææææææææææææçççççç ™™™öööãããææææææææææææææææææææææææçççÝÝÝäääçççäääñññŽŽŽfff666000èèèæææçççááá888ÙÙÙéééåååææææææææææææçççÝÝÝäääæææææææææææææææææææææææææææçççççç ™™™öööãããææææææææææææææææææææææææçççÝÝÝäääçççåååëëëÅÅÅyyyÓÓÓëëëäääèèèááá888ÙÙÙéééåååæææææææææææææææÚÚÚâââçççæææææææææææææææææææææåååçççæææ ———òòòàààããããããããããããããããããããããããäääÚÚÚâââçççæææåååìììúúúøøøêêêåååæææèèèààà888ÚÚÚéééåååæææææææææåååëëëìììîîîæææçççæææææææææææææææææææææçççëë뤤¤ÿÿÿòòòöööööööööööööööööööööööö÷÷÷ìììîîîæææççççççåååããããããåååçççæææçççååå;;;ÙÙÙéééåååææææææåååëëëÎÎÎGGG›››îîîâââääääääääääääääääääãããêêêÍÍÍccc¤¤¤———™™™™™™™™™™™™™™™™™™™™™ššš™™™JJJ”””îîîâââääääääääääääääääääãããêêêÉÉÉ+++ÝÝÝéééåååææææææãããóó󦦦SSSëëëÚÚÚÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÚÚÚêêê¡¡¡ JJJêêêÚÚÚÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÛÛÛêêê¡¡¡ãããèèèåååæææææææææçççää䣣£ÏÏÏëëëæææçççççççççççççççççççççèèèæææ¡¡¡ÌÌÌëëëæææççççççççççççççççççæææèèèæææ”””÷÷÷äääçççççççççççççççççççççèèèåå嬬¬àààèèèæææææææææææææææèèèêêêéééåååæææææææææãããâââåååææææææåååèèèêêêêêêçççççççççåååããããããäääççççççèèèêêê–––öööâââæææææææææææææææææææææåååèèèèèèäääææææææææææææææææææçççÚÚÚãããçççææææææåååôôôúúúéééåååææææææçççÚÚÚãããææææææäääðððøøøùùùøøøæææåååæææèèè•••÷÷÷ãããææææææææææææææææææææææææçççÛÛÛäääçççæææææææææææææææçççÝÝÝäääæææææææææìììžžž{{{ÖÖÖëëëåååæææçççÝÝÝäääæææäääííí­­­€€€yyy€€€âââçççæææééé•••÷÷÷ãããææææææææææææææææææææææææçççÝÝÝäääçççæææææææææææææææçççÝÝÝäääæææãããõõõ‡‡‡ GGG111çççæææåååçççÝÝÝäääæææãããôôô‡‡‡PPPÞÞÞçççæææééé•••÷÷÷ãããææææææææææææææææææææææææçççÝÝÝäääçççæææææææææææææææçççÝÝÝäääæææäääõõõ555oooååå¾¾¾ïïïäääçççÝÝÝäääææææææäääóó󆆆222ÛÛÛîîîäääçççééé•••÷÷÷ãããææææææææææææææææææææææææçççÝÝÝäääçççæææææææææææææææçççÝÝÝäääæææäääõõõ444pppæææ½½½ïïïäääçççÝÝÝäääææææææåååèèèÿÿÿooo+++ìììåååæææééé•••÷÷÷ãããææææææææææææææææææææææææçççÝÝÝäääçççæææææææææææææææçççÝÝÝäääæææãããõõõ‚‚‚"""NNN---æææçççåååçççÝÝÝäääæææäääñññkkk777111éééææææææééé•••÷÷÷ãããææææææææææææææææææææææææçççÝÝÝäääçççæææææææææææææææçççÝÝÝäääæææææææææëëë———sssÒÒÒëëëåååæææçççÝÝÝäääæææåååëëëÂÂÂttt|||ÒÒÒëëëäääçççééé•••÷÷÷ãããææææææææææææææææææææææææçççÝÝÝäääçççææææææææææææææææææÚÚÚâââçççææææææåååôôôûûûêêêåååæææææææææÚÚÚâââçççæææåååíííúúúùùùêêêåååæææçççèèè“““óóóàààããããããããããããããããããããããããäääÛÛÛäääçççææææææææææææåååëëëíííîîîæææçççææææææãããâââåååççççççåååëëëíííîîîæææççççççåååããããããåååçççææææææííퟟŸÿÿÿòòòõõõõõõõõõõõõõõõõõõõõõõõõ÷÷÷êêêäääçççæææææææææåååëëëÏÏÏLLLîîîâââääääääääääääääääääãããéééÐÐÐMMM›››îîîâââääääääääääääääääääãããéééÐÐÐccc©©©›››žžžžžžžžžžžžžžžžžžŸŸŸ˜˜˜hhhßßßèèèæææææææææãããôôô¦¦¦SSSëëëÚÚÚÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÚÚÚêê꣣£OOOëëëÚÚÚÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÚÚÚéé餤¤ áááèèèåååæææææææææçççãã㥥¥ÏÏÏëëëæææçççççççççççççççççççççèèèää䦦¦ÍÍÍëëëæææçççççççççççççççççççççèèèåå夤¤ÊÊÊéééãããäääääääääääääääääääääåååááá±±±âââçççæææææææææææææææçççôôôëëëåååæææææææææææææææææææææææææææçççôôôëëëåååææææææææææææææææææææææææææææææóóóíííçççèèèèèèèèèèèèèèèèèèèèèèèèçççèèèñññçççæææææææææææææææææææææãããåååæææææææææææææææææææææææææææææææææãããåååæææææææææææææææææææææææææææææææææãããäääæææååååååååååååååååååååååååååååååãããææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææ( @ æææçççëëëîîîïïïïïïïïïïïïïïïïïïïïïîîîîîîïïïïïïïïïïïïïïïïïïïïïíííéééæææççççççççççççççççççìììçççæææçççãããÓÓÓÇÇÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÉÉÉÆÆÆÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÃÃÃÍÍÍÙÙÙäääããããããããããããããããããÐÐÐãããççççççããã---[[[yyyrrrsssssssssssswwwJJJcccwwwssssssssssssrrr}}}%%%‰‰‰ðððÞÞÞáááááááááàààåååsssÐÐÐìììäääòòò@@@ÃÃÃÿÿÿòòò÷÷÷õõõòòòôôôõõõæææïïïõõõôôôôôôôôôôôôðððÿÿÿUUU   ÷÷÷äääççççççççççççèèèåååãããçççäääððð>>>¶¶¶íííâââÕÕÕÝÝÝìììáááäääßßßâââãããããããããããããããßßßõõõOOOõõõãããææææææææææææçççàààãããçççäääñññ>>>···ôôôÖÖÖvvvMMM¨¨¨ñññåååàààäääæææææææææææææææâââøøøOOOöööãããææææææææææææçççáááãããçççäääñññ>>>¸¸¸ïïïéééÉÉÉ444•••õõõäääàààäääæææææææææææææææâââøøøOOOöööãããææææææææææææçççáááãããçççäääñññ>>>¸¸¸ñññäää«««***ŸŸŸôôôäääàààäääæææææææææææææææâââøøøOOOöööãããææææææææææææçççáááãããçççäääððð===¶¶¶îîîààà‘‘‘}}}ÏÏÏçççãããÝÝÝãããçççææææææææææææâââøøøOOO›››óóóáááããããããããããããäääÞÞÞãããçççãããòòòBBBÆÆÆÿÿÿôôôþþþÿÿÿùùùõõõ÷÷÷ñññëëëæææççççççççççççãããúúúTTT©©©ÿÿÿóóóöööööööööõõõ÷÷÷ðððäääææææææèèè...{{{¥¥¥œœœ›››šššœœœ¡¡¡xxxºººëëëâââäääääääääáááððð@@@ggg©©©›››ŸŸŸ‰‰‰ÙÙÙêêêèèèßßß:::BBBRRROOOOOOOOOOOOOOOVVV ðððÝÝÝááááááààààààäääJJJ;;;TTTOOOOOOOOOOOOOOORRR---ÐÐÐìììåååèèèãããôôôúúúøøøøøøøøøøøøõõõÿÿÿOOO¯¯¯ôôôåååçççççççççæææéééäääñññúúúøøøøøøúúúúúúõõõÿÿÿ}}}ÃÃÃïïïææææææßßßâââãããââââââââââââßßßòòòEEEªªªóóóäääæææææææææææææææàààáááãããáááæææÞÞÞÜÜÜàààðððrrrÄÄÄïïïæææçççàààåååæææææææææææææææãããõõõFFF«««óóóäääææææææææææææçççàààãããæææêêêIII<<<¦¦¦êêêòòòsssÄÄÄïïïæææçççàààåååæææææææææææææææãããõõõFFF«««óóóäääææææææææææææçççáááäääåååîîî¹¹¹OOOÏÏÏèèèóóósssÄÄÄïïïæææçççàààåååæææææææææææææææãããõõõFFF«««óóóäääææææææææææææçççáááäääçççßßßÏÏÏ[[[nnnõõõñññsssÄÄÄïïïæææçççÝÝÝäääæææææææææææææææãããõõõFFF©©©ñññâââääääääääääääåååÝÝÝâââçççççç‹‹‹nnnÊÊÊèèèóóósssÄÄÄïïïæææçççðððëëëæææçççæææææææææããã÷÷÷JJJ¶¶¶ÿÿÿñññóóóóóóóóóóóóôôôñññëëëæææçççóóó÷÷÷ìììâââõõõwwwÄÄÄïïïçççåå円†ÃÃÃëëëãããäääääääääãããîîî999|||µµµ©©©«««««««««ªªª¯¯¯‰‰‰ºººëëëãããâââáááãããâââïïïdddÆÆÆîîîèèèááᘘ˜îîîÝÝÝàààààààààáááßßß999555JJJFFFFFFFFFFFFEEENNN }}}ðððÝÝÝààààààààààààäääXXXÌÌÌíííåååèèèáááçççççççççåååæææåååçççéééßßßîîî÷÷÷õõõôôôõõõöööòòòÿÿÿWWW¡¡¡öööäääçççççççççæææéééáááâââçççææææææáááåååæææçççïïïíííìììäääçççáááããããããâââëëëäääáááàààõõõOOOöööãããææææææææææææçççáááäääçççæææçççßßßäääæææêêê|||KKKÂÂÂíííåååàààäääçççäääHHHHHH¬¬¬ëëëöööOOOöööãããææææææææææææçççáááãããçççæææçççàààãããïïï¼¼¼KKK‘‘‘ZZZ÷÷÷äääàààäääåååïïï¡¡¡NNNØØØæææøøøOOOöööãããææææææææææææçççáááãããçççæææçççàààãããîîîÃÃÃFFFyyyddd÷÷÷äääàààäääèèèÞÞÞÙÙÙTTT|||ôôôõõõOOOöööãããææææææææææææçççáááãããçççæææçççÝÝÝäääåååííí”””bbbÒÒÒëëëæææÝÝÝãããçççääägggÉÉÉèèè÷÷÷OOOœœœôôôâââääääääääääääåååÞÞÞãããçççæææçççîîîêêêææææææòòòöööëëëåååçççîîîëëëåååçççòòòõõõìììâââúúúRRR¦¦¦ÿÿÿîîîñññññññññðððòòòîîîåååæææææææææ•••ÉÉÉêêêäääâââáááäääåååçç瘘˜ÃÃÃëëëãããâââáááãããâââóóóFFF{{{ÅÅŶ¶¶¸¸¸¸¸¸¸¸¸¸¸¸ººº   ÚÚÚééééééààà•••îîîÝÝÝààààààßßßáááââↆ†ðððÝÝÝàààààààààßßßäää:::(((BBB===>>>>>>>>>>>>???'''ÑÑÑìììæææçççàààæææçççççççççççççççæææèèèáááåååçççççççççççççççæææèèèÞÞÞéééòòòðððñññññññññðððòòòåååãããçççææææææéééæææææææææææææææææææææåååèèèçççææææææææææææææææææåååèèèæææãããäääääääääääääääãããççççççæææ(  åååÏÏÏÇÇÇÆÆÆÈÈÈÇÇÇÇÇÇÈÈÈÈÈÈÇÇÇÔÔÔåååäääæææÚÚÚáááÖÖÖxxxººº½½½ººº©©©®®®¶¶¶···«««}}}éééâââèèèÍÍÍÚÚÚÔÔÔ’’’õõõ­­­ÞÞÞòòòîîîïïïòòòæææ‹‹‹ëëëåååæææèèèæææÕÕÕ‹‹‹ñññbbb±±±ëëëàààäääæææÚÚÚˆˆˆêêêäääåååâââäääÔÔÔòòòÃÃÃãããìììææææææéééÜÜÜŠŠŠðððéééëëëéééååå×××cccŠŠŠkkk¿¿¿êêêãããÛÛÛcccˆˆˆ‹‹‹ŠŠŠ}}}ÔÔÔåååÛÛÛÜÜÜØØØééé•••ºººðððäääåååÜÜÜÛÛÛÍÍÍâââ®®®ÈÈÈåååäääéééæææöööŸŸŸºººîîîãããäääãããëëësssÍÍÍ¿¿¿ÇÇÇçççêêêæææäääóóóŸŸŸÄÄÄúúúîîîðððêêêêêêÈÈÈ¿¿¿ÇÇÇÞÞÞ¿¿¿çççßßßòòò••••••¸¸¸¸¸¸¿¿¿æææàààñññ®®®ÇÇÇÙÙÙ§§§èèèëëëîîî¶¶¶¦¦¦§§§‘‘‘nnnêêêáááèèèÃÃÃÖÖÖçççíííää䯯¯×××íííúúúËËËÂÂÂïïŒëëëåååæææéééæææäääæææÑÑÑLLL°°°êêêèè误¯rrrâââ………éééãããåååáááäääæææèèèååå¹¹¹ÜÜÜéééêêêÐÐÐÂÂÂßßß‹‹‹ôôôíííïïïëëëåååÖÖÖ›››èèèéééïïï§§§¿¿¿ïïïìììÛÛÛdddŒŒŒŒŒŒŒŒŒ‡‡‡ØØØãããÖÖÖæææãããçççÙÙÙÞÞÞæææãããååå×××ÔÔÔÕÕÕÕÕÕÓÓÓããã(0` æææåååçççèèèéééâââàààÝÝÝÙÙÙÚÚÚãããáááßßßäääñññ¯¯¯...;;;888999777)))___ÛÛÛ­­­$$$———ðððÞÞÞ¡¡¡ÉÉÉ ‘‘‘øøø¬¬¬   ÷÷÷êêêëëë–––ööö õõõûûû•••žžžííí±±±iiizzzÑÑÑ‹‹‹………JJJ###¨¨¨AAA<<<ììì«««111fffòòòïïï666000ÆÆÆuuu€€€ÐÐЛ››“““óóó©©©ÿÿÿîîîÊÊÊcccŸŸŸ”””EEEÎÎÎ^^^¤¤¤NNN¥¥¥ £££ ™™™ÍÍÍšššùùùúúú|||vvv{{{ŒŒŒPPPƒƒƒ///ÖÖÖ'''ŽŽŽÅÅÅyyyÓÓÓGGG+++¦¦¦SSSÏÏÏÌÌÌôôô‡‡‡ 555ooo¾¾¾†††222444ppp½½½‚‚‚"""---kkksssÒÒÒÂÂÂtttLLLMMM˜˜˜hhhOOO          !"  #$%  & #'(  ))*+,  -./ 0%) 12(   -3/ 45678* 12(   -3/ 9:;< 12(   -3/ =>? 12(   -3/ @ABCD  12(   -3/ E=FGH* 12(   -3/*IJKL) 12(   -MD(/  1NO   #PQO(/OO/(,,(*R4'QO(((((((,%  @STUVN2222222+WXWR YZ['N2222222+\  O]^-11111111^_* `^a11111111bc dL4)ef( `g4*  eh,   #f,  iji #f,   R&klm  #f,   On^op  #f,   OqrsE   #f,  Qlt)  #f,   uCGH  #f,  *vwFx*   #D @j%) *@R*1]QD,,,,,,,,(@R *YyMR )gzU]fffffffhf;WR )"{ O|^}*  )!^e########ee^;) )!  d~*!*W( &) )) )+,  €j %i%12(   @3ms* 4KwK12(   /‚yB €^oƒ 12(   /„…b†E  O‡ˆR 12(   /‰Šb‹E  Q…{@12(   /Œ_Ž qB12(   *‘* *’“k‘* 12(   €0) 4ji)1NO  *4R *4R 4VQD////////() *~”.R L•MR LUPM333333.V–—  €|^}*  )d^˜*  ]^Z™--------#š›  `~* |g*]S  5€*€*O4    ( @æææçççëëëîîîïïïíííéééìììãããÓÓÓÇÇÇÄÄÄÉÉÉÆÆÆÃÃÃÍÍÍÙÙÙäääÐÐÐ---[[[yyyrrrssswwwJJJccc}}}%%%‰‰‰ðððÞÞÞáááàààåååòòò@@@ÿÿÿ÷÷÷õõõôôôUUU   èèè>>>¶¶¶âââÕÕÕÝÝÝßßßOOOñññ···ÖÖÖvvvMMM¨¨¨øøøööö¸¸¸444•••«««***ŸŸŸ===‘‘‘ÏÏÏ›››óóóBBBþþþùùùúúúTTT©©©...{{{¥¥¥œœœššš¡¡¡xxxºººgggêêê:::RRRVVV ;;;¯¯¯EEEªªªÜÜÜFFFIII<<<¦¦¦¹¹¹nnn‹‹‹ÊÊʆ††999|||µµµddd˜˜˜555NNN XXXÌÌÌWWWKKKÂÂÂHHH¬¬¬¼¼¼ZZZØØØ”””bbbÒÒÒÅÅÅÚÚÚ(((???'''ÑÑÑ  !"#$%#&'#(''((((%)*&+",-./0 1.1'23'!4,5(67894"!.:23; 4,< =>'!.:23; 4,<4?@A(!.:23; B-!CD0.:2EF #G %(H%I'&4JKL%F;;;'&+MNOPEQP3RST. $ULE3333AV+1WGX22222YZ[0 !!\K22222X"+(J::::'%2]("4J::JJ'%1.....1#^_F!  `! !"'a?F!VbcdV# !"'a?F "e2D+F !"'a?F 1Df'4 0'aL4."0.gfh+F &-%4FFFF(4F&.' "ijklL???_]T. .m + no0!!! 1jpaaaa^qr0!!!!st"+ ""1&'(';#%uR; . " . !'23; 1Vkvw"!xxy;23; !zvC{&!"Rq|:23; !am&!+Kk('23; 0"}~0€U +&2P(."V#;""#'.JXd%444#"> V. "o. .FaN-<<<0!!1 .„i0!!!1W…GB,,,,†‡ˆ!+ "+#444#""+"+( åååÏÏÏÇÇÇÆÆÆÈÈÈÔÔÔäääæææÚÚÚáááÖÖÖxxxººº½½½©©©®®®¶¶¶···«««}}}éééâââèèèÍÍÍ’’’õõõ­­­ÞÞÞòòòîîîïïï‹‹‹ëëëÕÕÕñññbbb±±±àààˆˆˆêêêÃÃÃãããìììÜÜÜŠŠŠððð×××ccckkk¿¿¿ÛÛÛØØØ•••öööŸŸŸsssçççóóóÄÄÄúúúßß߸¸¸ÙÙÙ§§§¦¦¦‘‘‘nnnííí¯¯¯ËËËŒŒŒÑÑÑLLL°°°rrr………¹¹¹ÐÐÐôôô›››ddd‡‡‡ÓÓÓ  !"#$ %&'()*+,-. /0-((12'*30&-3,45 .,367 ** 829':7;<.''(229=55>??2%"@A (BACD' ) 9EF/EH IJK'FLM* N,'O>=PE QA2+3RHHHS4* *9@*/!!T*(0`€€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ÷÷wÿÿwww÷wwÿÿÿÿÿÿÿÿð€ÿÿÿ÷øøÿÿÿÿÿÿwÿÿÿÿÿÿðÿÿÿÿÿÿwðÿÿÿÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿøÿÿÿÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿðÿøÿÿ÷ÿÿÿÿÿÿøÿÿÿÿÿøÿ÷ÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿøÿÿpÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿøÿÿøÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿøÿÿ‡ÿÿ÷ÿÿÿÿÿÿøÿÿÿÿÿÿðÿÿ€ÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿøÿÿÿÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿøÿÿÿÿÿ÷ÿÿÿÿÿÿøÿÿÿÿÿÿøÿÿÿÿÿ÷ÿÿÿÿÿÿðÿÿÿÿÿÿð€ˆ€ˆÿÿÿÿ÷ÿp€ˆ€ˆð€€÷ÿÿ÷ÿp÷ÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿ‡ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€ÿÿÿÿÿÿÿÿÿÿÿÿÿ‡ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøÿÿÿÿÿÿÿÿÿÿ€ÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿÿÿðÿÿÿÿÿÿÿÿ€ÿÿÿÿÿÿÿÿÿÿ÷ÿÿ‡ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ˆÿÿÿÿÿÿÿÿÿÿ€ÿÿÿÿÿÿÿÿÿ÷ˆÿÿ‡ÿÿÿÿÿÿÿÿ€ÿÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿÿÿÿÿ€ÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿðÿÿÿÿ÷€€ÿÿÿ÷ÿøðÿ÷ÿÿÿ÷€ˆ€ÿÿÿÿÿ÷÷ÿÿÿÿÿÿwÿÿÿÿÿÿøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿðÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿÿ÷ÿÿÿ÷ÿÿwwÿ÷ðÿÿÿÿÿÿÿÿÿÿ÷€ÿÿÿÿÿ€ÿøÿÿÿÿÿÿÿÿøˆÿÿ÷ÿÿðÿÿðÿÿÿÿÿÿÿÿÿÿø€ÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿø€ÿÿÿÿÿÿpÿð‡ÿÿÿÿÿÿÿÿÿÿ÷ÿÿ÷ÿÿx€ÿøÿÿÿÿÿÿÿ÷ÿÿÿxÿÿÿÿÿø‡ÿÿðÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿwÿÿÿÿÿÿðÿÿÿÿÿÿÿð÷ÿÿ÷ÿÿÿ÷ÿpðÿÿÿÿÿ÷ÿ÷ÿÿÿð€ˆˆˆˆÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿ( @€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ÷‡w‡w‡‡w‡xwÿwwðˆˆˆˆˆˆˆˆˆ÷÷÷ÿ‡xÿÿ÷ÿÿ÷ÿÿˆÿwÿ÷ðw÷÷w÷ÿ€÷ÿ÷ÿøwxˆÿ÷ÿpÿ÷÷ÿð÷€÷ÿw÷ÿˆ÷÷÷p€ÿ÷÷ÿxÿÿÿøøˆÿ€÷÷÷÷pw÷÷ÿÿ€÷÷÷÷øÿÿÿ÷÷w÷ˆÿÿÿð€€w÷€€€ˆ‡x‡ˆx‡€ÿÿxx‡‡ˆÿÿÿÿÿðÿÿÿÿÿÿˆ÷÷÷p÷ÿ÷w÷wÿ‡wwÿÿp÷÷ÿÿp‡ÿ‡÷ÿÿx÷÷ÿwø‡ˆ÷ÿ÷÷ðÿ÷ÿw÷ˆÿ‡w÷ÿpwÿ÷÷ÿx‡ˆ÷ÿ÷÷ÿx÷÷÷÷ÿ‡÷÷÷pÿ÷÷÷÷ÿˆpwp€€€÷w‡÷÷ÿ÷ÿw÷wwwxÿ÷wÿ÷÷÷ÿÿÿÿ€÷ÿ÷÷w÷wÿwx÷ˆÿ÷÷ÿÿÿð€w÷ðˆ÷÷ÿ÷ðxÿ÷‡ÿˆ÷÷wø€÷ÿwÿp÷ÿ÷÷÷ÿw‡ÿ÷øˆÿ÷ÿ÷ÿÿÿÿÿˆ÷÷ÿ÷ø÷÷xwÿˆwwwwpwpw÷ÿ€÷ÿ÷÷÷÷ÿ÷ÿÿÿ÷ÿ( €€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ÷wwwwwÿxxwww÷wx÷÷ÿøøwÿ÷÷x÷÷÷ÿxˆˆ÷ˆˆ‡ÿø÷wøw÷‡wÿ÷ø‡wwøwwÿwww‡x÷w÷÷‡ÿ÷ÿðw‡÷÷÷÷÷ÿxø÷ˆ‡‡ÿ÷÷wwpuzzles-20170606.272beef/icons/lightup.ico0000644000175000017500000006117613115373733017170 0ustar simonsimon 00 ¨%–  ¨>& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $ææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççççææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææâââááááááááááááááááááááááááááááááàààääääääáááááááááááááááááááááááááááááááááâââéééééééééééééééééééééééééééééééééééééééèèèæææææææææææææææåååêêêÔÔÔ¿¿¿ÉÉÉÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇËË˶¶¶¸¸¸ÊÊÊÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÈÈÈÅÅÅ???%%%$$$$$$$$$$$$$$$$$$$$$$$$'''vvvñññäääæææææææææåååëëëÏÏÏØØØíííééééééééééééééééééééééééèèèñññ¾¾¾ÃÃÃñññèèèéééééééééééééééééééééèèèìììÝÝÝ```óóóãããæææææææææåååëëëÐÐÐÕÕÕéééååååååååååååååååååååååååäääììì¾¾¾ÃÃÃìììäääåååååååååååååååååååååäääèèèÛÛÛbbbóóóãããæææææææææåååëëëÐÐÐÖÖÖêêêåååææææææçççççççççææææææåååííí¾¾¾ÃÃÃíííåååæææææææææææææææææææææåååéééÛÛÛaaaóóóãããæææææææææåååëëëÐÐÐÖÖÖêêêåååææææææåååææææææææææææåååííí¾¾¾ÃÃÃíííåååæææææææææææææææææææææåååéééÛÛÛaaaóóóãããæææææææææåååëëëÐÐÐÖÖÖêêêãããóó󨨨)))ÚÚÚéééäääííí¾¾¾ÃÃÃíííåååæææææææææææææææææææææåååéééÛÛÛaaaóóóãããæææææææææåååëëëÐÐÐÖÖÖêêêâââõõõŸŸŸ ÙÙÙêêêäääííí¾¾¾ÃÃÃíííåååæææææææææææææææææææææåååéééÛÛÛaaaóóóãããæææææææææåååëëëÐÐÐÖÖÖêêêâââõõõŸŸŸ ÙÙÙêêêäääííí¾¾¾ÃÃÃíííåååæææææææææææææææææææææåååéééÛÛÛaaaóóóãããæææææææææåååëëëÐÐÐÖÖÖêêêäääìììÉÉÉ‚‚‚‡‡‡àààèèèäääííí¾¾¾ÃÃÃíííåååæææææææææææææææææææææåååéééÛÛÛaaaóóóãããæææææææææåååëëëÐÐÐÖÖÖêêêæææåååëëëøøø÷÷÷öööçççæææåååííí¾¾¾ÃÃÃíííåååæææææææææææææææææææææåååéééÛÛÛaaaóóóãããæææææææææåååëëëÐÐÐÕÕÕéééåååæææäääáááââââââåååæææäääííí¾¾¾ÃÃÃìììäääæææææææææææææææææææææåååèèèÛÛÛaaaóóóãããæææææææææåååëëëÏÏÏÔÔÔéééäääåååååååååååååååååååååäääììì¼¼¼ÃÄÄíððåççæééæééæééæééæééæééæééåèèéëëÛÝÝ bbbóóóãããæææææææææåååêêêÓÓÓÜÜÜïïïëëëëëëëëëëëëëëëëëëëëëëëëêêêòòòÅÆÆÅ½½îááæÚÚçÛÛçÛÛçÛÛçÛÛçÛÛçÛÛçÛÛæÚÚêÝÝÝÓÓaaaóóóãããæææææææææäääððð···333???===========================:;;EBB‚¦¦z´´{±±{²²{²²{²²{²²{²²{²²{²²{±±y³³…®®^uu9tt@uu?uu?ssAvvC||C||Avv?ss?uu@ww8mm‡ŽŽìëëåååæææææææææãããôôô¦¦¦4ÓÓÿÿýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþÿÿ,ââkÀÀÿÿýýÿÿÿÿÿÿõõõõÿÿÿÿÿÿÿÿ úú±±êääåççæææææææææãããóóó§§§5ÓÓÿÿüüþþþþþþþþþþþþþþýýÿÿ-ââd¹¹ÿÿùùÿÿ»»A‘‘„žž†žžG‘‘µµýýýýõõ˜¬¬êåååæææææææææææãããôôô¦¦¦4ÓÓÿÿýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþÿÿ,ââe»»ÿÿÿÿ ¥¥ª¥¥ÿûûþÿÿþÿÿÿýýµ¬¬žžÿÿøø™­­êåååæææææææææææãããôôô¦¦¦ æææ···4ÓÓÿÿýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþÿÿ,ââeººÿÿÊÊ™žžÿÿÿûýýûýýûýýûýýÿÿÿ¨¥¥ÄÄÿÿ™««êåååæææææææææææãããôôô¦¦¦üüü@@@ÛÛÛ³³³4ÓÓÿÿýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþÿÿ,ââgººÿÿ(››óââÿÿÿþþþÿÿÿÿÿÿþþþþÿÿûêê0ššýý›¬¬êåååæææææææææææãããôôô¦¦¦ÈÈÈÆÆÆííí4ÓÓÿÿýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþÿÿ,ââi¼¼ÿÿR––ÿýýüÿÿÿÿÿÿÿÿÿÿÿÿÿÿûþþÿÿÿ_››ññ¯¯êåååæææææææææææãããôôô¦¦¦ÈÈÈÆÆÆŽŽŽîîî4ÓÓÿÿýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþÿÿ,ââh»»ÿÿH––ÿööýÿÿÿÿÿÿÿÿÿÿÿÿÿÿüÿÿÿûûS™™ôôœ®®êåååæææææææææææãããôôô¦¦¦üüü@@@ÚÚÚ´´´4ÓÓÿÿýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþÿÿ,ââf¹¹ÿÿ§§ÜÊÊÿÿÿúûûþþþÿþþûûûÿÿÿçÓÓ¢¢ÿÿš««êåååæææææææææææãããôôô¦¦¦ æææ···4ÓÓÿÿýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþÿÿ,ââe»»ÿÿèèW‰‰ÿòòÿÿÿþþþÿþþþÿÿÿøøeŠŠääþþ™¬¬êåååæææææææææææãããôôô¦¦¦4ÓÓÿÿýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþÿÿ,ââe»»ÿÿÿÿ××NŠŠÏÄÄúééûêêÔÈÈWŠŠÏÏÿÿ÷÷™­­êåååæææææææææææãããóóó§§§4ÓÓÿÿüüÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýÿÿ,ââe»»ÿÿüüÿÿïïµµ&žž' ³³ììÿÿÿÿøø™­­êåååæææææææææææãããôôô¦¦¦4ÓÓÿÿýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþÿÿ,ââe»»ÿÿýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøø™­­êåååæææææææææææäääðððµ··*336@@4>>4>>4>>4>>4>>4>>4>>4>>4>>1<<?CC{§§qµµs²²r³³r³³r³³r³³r³³r³³r³³s²²p´´{­­‡¥¥p´´s²²r³³r²²s°°t°°t°°s°°r²²s³³s³³p¯¯Ÿ©©èææææææææææææææåååêêêÕÓÓ*ííÿÿþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿýý ÿÿ_ÏÏQÊÊúúððòòòòòòòòòòòòòòññ øø9ÙÙk¸¸ ùùððòòòòòòòòòòòòòòòòóóì욬¬êåååæææææææææææåååêëëÒÏÏêêÿÿþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýÿÿOÉÉFÐÐÿÿýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþÿÿ,ââe»»ÿÿýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøø™­­êåååæææææææææææåååêëëÓÏÏêêÿÿþþþþþþþþþþþþþþþþýýÿÿPÊÊFÐÐÿÿýýþþþþþþþþþþþþþþýýÿÿ,ââe»»ÿÿýýþþþþþþþþþþþþþþþþÿÿøø™­­êåååæææææææææææåååêëëÓÏÏëëÿÿþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýÿÿPÊÊFÑÑÿÿýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþÿÿ,ââe¼¼ÿÿýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøø™­­êåååæææææææææææåååêëëÓÏÏëëÿÿþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýÿÿPÊÊFÑÑÿÿýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþÿÿ,ââe¼¼ÿÿýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøø™­­êåååæææææææææææåååêëëÓÏÏëëÿÿþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýÿÿPÊÊFÑÑÿÿýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþÿÿ,ââe¼¼ÿÿýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøø™­­êåååæææææææææææåååêëëÓÏÏëëÿÿþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýÿÿPÊÊFÑÑÿÿýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþÿÿ,ââe¼¼ÿÿýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøø™­­êåååæææææææææææåååêëëÓÏÏëëÿÿþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýÿÿPÊÊFÑÑÿÿýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþÿÿ,ââe¼¼ÿÿýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøø™­­êåååæææææææææææåååêëëÓÏÏëëÿÿþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýÿÿPÊÊFÑÑÿÿýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþÿÿ,ââe¼¼ÿÿýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøø™­­êåååæææææææææææåååêëëÓÏÏëëÿÿþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýÿÿPÊÊFÑÑÿÿýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþÿÿ,ââe¼¼ÿÿýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøø™­­êåååæææææææææææåååêëëÓÏÏééÿÿüüýýýýýýýýýýýýýýûûÿÿQÉÉGÐÐÿÿüüýýýýýýýýýýýýýýüüÿÿ.ááf»»ÿÿüüýýýýýýýýýýýýýýýýÿÿöö™­­êåååæææææææææææåååêëëÓÐÐëëÿÿþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýÿÿPÊÊFÑÑÿÿýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþÿÿ,ââf¼¼ÿÿýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøøš®®êåååæææææææææææåååëëëÏÐÐU··OÅÅQÂÂPÂÂPÂÂPÂÂPÂÂPÂÂPÂÂPÂÂQÁÁJÆÆr¬¬n®®JÆÆQÁÁPÂÂPÂÂPÂÂPÂÂPÂÂPÂÂPÂÂQÂÂLÅÅc¶¶{¦¦KÆÆQÁÁPÂÂPÂÂPÂÂPÂÂPÂÂPÂÂPÂÂPÂÂPÃÃO¾¾›¦¦éææåææææææææææææææçççàààÙÉÉÝÉÉÜÉÉÝÉÉÝÉÉÝÉÉÝÉÉÝÉÉÝÉÉÝÉÉÜÉÉÞÈÈÖÍÍ×ÍÍÞÈÈÜÉÉÝÉÉÝÉÉÝÉÉÝÉÉÝÉÉÝÉÉÝÉÉÜÉÉÝÈÈÙËËÔÎÎÞÈÈÜÉÉÝÉÉÝÉÉÝÉÉÝÉÉÝÉÉÝÉÉÝÉÉÝÉÉÝÉÉÛÈÈÕÔÔæææææææææææææææææææææçççéììèììèììèììèììèììèììèììèììèììèììèííéëëéëëèííèììèììèììèììèììèììèììèììèììèììéììêëëèììèììèììèììèììèììèììèììèììèììèììèììêêêææææææææææææææææææææææææååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææ( @ ææææææèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèèééééééééééééééééééééééééèèèæææææææææåååÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞààààààÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßÞÞÞÜÜÜÝÝÝÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝÜÜÜßßßææææææéééÖÖÖÌÌÌÕÕÕÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓ×××ÄÄÄÀÀÀ×××ÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÒÒÒÜÜÜLLLFFFìììåååêêêÕÕÕÞÞÞìììéééæææåååçççéééïïïÐÐÐÉÉÉïïïèèèééééééééééééèèèòòò@@@888ìììåååêêêÖÖÖÛÛÛèèèäääòòòùùùïïïãããëëëÎÎÎÈÈÈëëëäääååååååååååååäääîîîAAA999ìììåååêêêÖÖÖÜÜÜèèèêêê———nnn«««íííéééÎÎÎÈÈÈìììåååææææææææææææäääïïï@@@888ìììåååêêêÖÖÖÜÜÜæææïïï<<<gggöööçççÎÎÎÈÈÈìììåååææææææææææææäääïïï@@@888ìììåååêêêÖÖÖÜÜÜçççîîî[[[~~~óóóèèèÎÎÎÈÈÈìììåååææææææææææææäääïïï@@@888ìììåååêêêÖÖÖÛÛÛèèèåååèèèéééçççåååëëëÎÎÎÈÈÈìììåååææææææææææææäääîîî@@@888ìììåååêêêÕÕÕÚÚÚçççäääääääääääääääêêêÍÌÌÇÉÉêîîãççäèèäèèäèèäèèãççíññABB9::ìììåååéé騨ØäääðððíííííííííííííííóóóÖ××ÏÃÃôááíÜÜîÝÝîÝÝîÝÝîÜÜìÛÛöææA??888ìììåååððð¹¹¹333>>><<<===>>>======;<<A;;o­­hËËiÄÄiÆÆiÆÆiÆÆiÆÆgÆÆqÆÆ^ŠŠ'‡‡/ˆˆ/$’’!‘‘,““1ŠŠ#††f‹‹êääåççóóó«««&ÍÍÿÿýýÿÿÿÿÿÿÿÿÿÿööVÊÊÿÿÿÿìì&ÌÌ3ÊÊßßþþÿÿhÉÉíÜÜäééóó󬬬 (ÌÌÿÿüüþþþþþþþþÿÿõõTÄÄÿÿ ÆÆ¥±±þêêÿïïÔÇÇ2¬¬ÿÿfÄÄíÜÜäééóóó«««‹‹‹ÏÏÏ£££&ÍÍÿÿýýÿÿÿÿÿÿÿÿÿÿõõVÌÌññ‰°°ÿÿÿûþþüýýÿÿÿÒÈÈÒÒdÐÐîÚÚäééóóó«««ßßßÐÐÐBBB&ÍÍÿÿýýÿÿÿÿÿÿÿÿÿÿôôRÒÒÔÔÖÏÏÿÿÿüýýþþþüÿÿÿîî*½½YÎÎðÚÚäééóóó«««ßßßÏÏÏBBB&ÍÍÿÿýýÿÿÿÿÿÿÿÿÿÿôôTÑÑÙÙÉÉÉÿÿÿúûûüýýýÿÿÿéé¿¿[ÏÏïÚÚäééóóó«««‹‹‹ÎÎΣ££&ÍÍÿÿýýÿÿÿÿÿÿÿÿÿÿööVÉÉýýaªªÿ÷÷ýÿÿüýýÿÿÿ­¶¶ááfÎÎîÚÚäééóó󬬬 'ÌÌÿÿüüþþþþþþþþÿÿõõTÆÆÿÿßßbªªÒÎÎÞÖÖ‘²²ÃÃÿÿfÅÅíÜÜäééóóó«««&ÍÍÿÿýýÿÿÿÿÿÿÿÿÿÿööSÇÇÿÿÿÿøøÙÙÓÓîîÿÿÿÿeÆÆíÜÜäééñð𸹹55'AA&??&??'@@&??&??#??0==`¯¯PÎÎSÇÇRÈÈRÈÈRÈÈSÈÈQÉÉXÄÄv°°PÊÊSÆÆVÊÊSÒÒQÓÓVÍÍUÆÆLÊʃ²²èààæèèìééÏÙÙôô ÿÿÿÿÿÿÿÿÿÿþþÿÿ;ââFÒÒûûôôõõõõõõõõ ÷÷ííZÃà øøôôôôóóóóôôôôúújÃÃìÝÝåééíééÌÖÖññÿÿýýþþþþþþýýÿÿ/ÞÞ;××ÿÿþþÿÿÿÿÿÿÿÿÿÿööSÈÈÿÿþþÿÿÿÿÿÿÿÿþþÿÿeÆÆíÜÜäééìééÌ×× òòÿÿþþÿÿÿÿÿÿþþÿÿ0ßß<××ÿÿýýÿÿÿÿÿÿþþÿÿööSÇÇÿÿþþÿÿÿÿÿÿÿÿýýÿÿeÆÆíÜÜäééìééÌ×× óóÿÿþþÿÿÿÿÿÿþþÿÿ/ßß;××ÿÿþþÿÿÿÿÿÿÿÿÿÿööSÈÈÿÿþþÿÿÿÿÿÿÿÿþþÿÿeÆÆíÜÜäééìééÌ×× óóÿÿþþÿÿÿÿÿÿþþÿÿ/ßß;××ÿÿþþÿÿÿÿÿÿÿÿÿÿööSÈÈÿÿþþÿÿÿÿÿÿÿÿþþÿÿeÆÆíÜÜäééìééÌ×× óóÿÿþþÿÿÿÿÿÿþþÿÿ/ßß;××ÿÿþþÿÿÿÿÿÿÿÿÿÿööSÈÈÿÿþþÿÿÿÿÿÿÿÿþþÿÿeÆÆíÜÜäééìééÌ×× ññÿÿýýþþþþþþüüÿÿ1ÞÞ=××ÿÿüüþþþþþþýýÿÿõõTÇÇÿÿýýþþþþþþþþüüÿÿfÆÆíÜÜäééìééÌ×× óóÿÿþþÿÿÿÿÿÿþþÿÿ0àà<ØØÿÿþþÿÿÿÿÿÿÿÿÿÿööTÈÈÿÿþþÿÿÿÿÿÿÿÿþþÿÿeÇÇíÜÜäééìêêÍÔÔ2ÐÐ,ÜÜ.ÚÚ.ÚÚ.ÚÚ.ÚÚ/ÙÙ'ÞÞMÅÅUÀÀ&ßß/ÙÙ.ÚÚ.ÚÚ.ÚÚ.ÚÚ+ÛÛ7ÔÔdµµ*ÜÜ/ÙÙ.ÚÚ.ÚÚ.ÚÚ.ÚÚ0ÙÙ%ÝÝt··êÞÞåèèçççáááÚÌÌÜÌÌÜÌÌÜÌÌÜÌÌÜÌÌÜÌÌÝÌÌÙÎÎØÏÏÝËËÜÌÌÜÌÌÜÌÌÜÌÌÜÌÌÜÌÌÛÍÍÖÐÐÜÌÌÜÌÌÜÌÌÜÌÌÜÌÌÜÌÌÜÌÌÜËË×ÒÒåææææææææçççéììèììèììèììèììèììèììèììéììéëëèììèììèììèììèììèììèììèììêëëèììèììèììèììèììèììèììèììéëëææææææ(  åååáááßßßÞÞÞàààáááààààààààààààÚÚÚØØØØØØØØØÚÚÚæææÞÞÞØØØåååéééÞÞÞÌÌÌÝÝÝÞÞÞÞÞÞÞÞÞ777888äääÝÝÝæææÎÎβ²²ëëëÐÐÐççççççèèèççç%%%%%%äääÚÚÚíí툈ˆ000íííÌÍÍâååãååãææãåå'))'))äääàààïïïõõõòòòö÷÷Û××ñååòççóèèòçç&%%%&&äääÓÓÓŽŽŽŽŽŽ‹‹‘¢¢¥ÛÛ£ÕÕ£×צÔÔ4ZZEECCDD:]]äááÀÀÀ iiÿÿ÷÷þþññ"èè.êê¦ââ>èè5ääíÜÜÃÃÃYYYž¢¢ ddÿÿûûÿÿùù%ÐÐÌââÿÿÿâëëOÇÇåááÃÃÃVZZ𢢠eeÿÿûûÿÿøø"ÖÖ½ââÿÿÿÕééHÌÌæááÀÀÀhh ÿÿööüüïï%ääáá€ÏÏ(ÝÝ7ááìÜÜÌÔÔ ššœœ™™™™:¬¬,èè*ââ'åå5ÛÛEÒÒ êêââêêVÓÓèÝÝÑàà÷÷ÿÿÿÿÿÿ.ããþþÿÿÿÿôô%ççÿÿýýÿÿ9ååëÛÛÐßßòòüüúúûû-ßßýýýýÿÿóó'ææÿÿüüÿÿ;ääêÛÛÐßß÷÷ÿÿÿÿÿÿ,ááþþÿÿÿÿôô%ææÿÿýýÿÿ9ååëÛÛÒÞÞ,ææîî!ììííCÕÕ!ëë ììîî,ää=ÙÙïï#ëëððNÙÙéÝÝäääÜØØÜ××ÜØØÜØØÛØØÜØØÜØØÜØØÛØØÛØØÜØØÜØØÛ××ÜÙÙååå(0` æééåååêååçÛÛÛÛÛêëëÓÓÓŽ½ÊÊÊÅÆÆÏÄͶ¶===$$$)))vvvíððÏÐÐóóó½½½aaaÔÎÎ ¨¨¨žž ƒƒƒ‡ŽŽŽŽŽÿôôêÝÝÝÓÓ333BAA…¦¦{²²r²²…®®^uu>ttAvvC||8mm©¥¥4ÓÓþþ úú,ââkÀÀõõ±±e»»»»0šš…žžD‘‘µµš­­¦¦¦¦¦þþþµ¬¬žžÍÍÄÄ(››óââûêêiººR––_››H––S™™ÝÉÉçÓÓ¢¢ììWŠŠeŠŠää××NŠŠ'žž ³³*336@@4>>?CC{§§{­­q®®*ííÿÿÿÿ_ÏÏOÉÉòò9ÙÙëëFÑÑPÊÊU··LÆÆPÂÂn®®O¾¾c¶¶›¦¦                           !"  # $ $ $%&&&&&&&&&&'()*+**+,,+**+-./011111111121341222155122126./0121111111113711189::;<115=>/0111111111113711?. @@@AB15=> /011111111111371C@@@@@@.D2=>@$ /011111111111371EF@@@@@@GE1=./0111111111113H1I@@@@@@@@J56> /011111111111371K @@@@@@@L5=.@$ /011111111111371?M@@@@@@NO1=.> /011111111111371PQ @@@@ RS2=./0111111111113712TU GGQC11=/011111111111371115_`aaaaaaaaa2bc2ddddddddd2eH2fdddddddddf=f11111111121cc1111111111137111111111112=f11111111111cg1111111111137121111111115=f11111111111hg1111111111137111111111115=f11111111111hg1111111111137111111111111=f11111111121hg1111111111137111111111115=f11111111111hg1111111111137111111111115=f11111111111hg1111111111137121111111111=f11111111111hg1111111111137111111111112=f11111111121hg1111111111137121111111112=f12112111211hg1221121212137111111211215=f11111111121hg1111111111137111111111111=ijkkjkkkkjjj^ljkjmjkkkjkjn\jkkkkkkkkkkmoMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM( @äééåååêëëÝÝÝÞÖÖÔÔÔÇÉÉÌ××ÂÂÂLLLAAAíÜÜéââóòò'AA:;;ýþþÓÌÌ———nnn«««ÌÌÌgggA==[[[~~~íññÏÃÃõääðÚÚ¹¹¹333u´´eÆÆiÅÅ^ŠŠ%‡‡/ˆˆ.’’#’’1ŠŠf‹‹(ÌÌÿÿ õõSÉÉíí&ÍÍ3ÊÊáá ôôTÆÆ ÆÆ¥±±ÿììÔÇÇ2¬¬‹‹‹£££ZÏÏññ‰°°ÓÓdÐÐSÒÒ*½½a¬¬ÿ÷÷­¶¶fÎÎÛÛ‘²²55%??0==dµµYÄÄLÊÊÏÙÙôô þþÿÿ;ââFÒÒíí.ÛÛ<××0ÝÝ<ØØ0àà&ÞÞMÅÅ5ÒÒÜÌÌ            !  "#$%&&&&&%&'()*++*,(-./00000001200345600%   7 ./0000000890:;<<=>0% ?@.400000001ABC=DE    .400000001FDèè5ääíÜÜÃÃÃYYYž¢¢ ddÿÿûûÿÿùù%ÐÐÌââÿÿÿâëëOÇÇåááVZZ𢢠eeÿÿûûøø"ÖÖ½ââÕééHÌÌæááhh ÿÿööüüïï%ääáá€ÏÏ(ÝÝ7ááìÜÜÌÔÔ ššœœ™™™™:¬¬,èè*ââ'åå5ÛÛEÒÒ êêââêêVÓÓèÝÝÑàà÷÷ÿÿ.ããþþôô%ççýý9ååëÛÛÐßßòòüüúúûû-ßßýýóó'ææüü;ääêÛÛ,áá%ææÒÞÞ,ææîî!ììííCÕÕ!ëë ììîî,ää=ÙÙïï#ëëððNÙÙéÝÝÜØØÜ××ÛØØÜÙÙ    ! "#$%&'()(*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZL[\]^_`SabcWdef=ghijklmnopqrstuvwxyz{|}~€‚ƒ„…†S‡Sˆ‰SSŠ‹SŒSŽ‘’“”Œ•S–—S˜S™š†S‡S›‰SSŠœSŒSŽžŸ ¡¢£¤¥¦§¨©ª«¬­®­­¯­­­¯¯­­&°(0`€€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿ÷ÿ÷w÷www÷w‡wwwwwðwÿÿÿÿÿÿ÷ÿÿÿÿÿÿð÷ÿÿÿÿÿÿwÿÿÿÿÿð@0ÿÿ÷ÿÿÿ÷wÿÿÿÿø÷ÿ÷ÿÿÿÿ÷ÿÿÿÿÿÿðwÿøwÿ÷ÿÿÿÿÿt@÷ÿÿpÿ÷ÿÿ÷ÿÿÿó?wÿÿpÿ÷ÿÿÿÿÿð÷ÿ€ÿ÷ÿÿÿÿÿô÷ÿÿwˆÿ÷ÿ÷ÿÿÿ÷ó÷ÿÿÿÿÿÿ÷ÿÿÿÿÿð?wÿÿÿÿÿÿ÷ÿÿÿÿÿÿô÷ÿÿÿ÷ÿ÷ÿÿÿÿÿó@Owÿÿÿÿÿÿ÷ÿÿÿÿÿô0÷÷w÷w÷÷wwwwwst‡8¸ƒˆ¸ƒˆ8888883ð;»»»»»»¸»»»»»»»p‹»»»»»»¸»»3ˆ3»»ð‹»»»»»»¸»³ÿ÷‹»p‡@;»»»»»»¸»7ÿ÷ó»ðws‹»»»»»»¸»ÿÿÿø;ðó;»»»»»»ˆ³ÿÿÿÿ‹‡p÷ø‹»»»»»»¸³ÿÿÿÿÿ;ðwø‹»»»»»»¸³ÿÿÿ÷‹ð‡ð;»»»»»»¸»ÿ÷ÿ÷;ðÿp‹»»»»»»¸»7ÿÿÿó;p@;»»»»»»¸»³ÿw‹»ð;»»»»»»¸»»8ˆˆ»»‡ð‹»»»»»»¸»»»»»»»p;»‹¸»»»¸»»»»»»»ø8ƒˆ8888x‡ˆ¸ˆˆˆˆˆˆˆˆˆˆˆ‡û»»»¸»»¸;»»»»»»¸»»»»»»»x»»»»»»»‹»»»»»»¸»»»»»»»û»»»»»»»{»»»»»»¸»»»»»»»w»»»»»»¸;»»»»»»¸³»»»»»»ó»»»»»»»‹»»»»»»¸»»»»»»»{»»»»»»¸‹»»»»»»¸»»»»»»»‡û»»»»»»»‹»»»»»»ˆ»»»»»»»÷»»»»»»¸ƒ»»»»»»¸»»»»»»»{»»»»»»»;»»»»»»¸»»»»»»»ø»»»»»»¸‹»»»»»»¸»»»»»»»x»»»»»»»‹»»»»»»¸»»»·»»»û»»»»»»»»»»»»»»¸»»»»»»»û»»»»»»»‹»»»»»»¸»»»»»»»wx»»»»»»¸‹»»»»»»¸»»»»»»»øˆˆxˆˆxˆ8ˆˆˆxˆˆˆˆˆˆˆˆxˆÿÿ÷ÿ÷ÿÿÿ÷ÿÿÿÿÿÿÿÿÿ( @€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ÷÷÷÷÷ÿww÷÷÷w÷wwwwwwp÷ÿ÷ÿÿwÿ÷€wÿ÷÷wÿ÷ÿp‡÷ÿwÿ÷ÿÿ€@w÷€ÿw÷÷ÿpÿp÷w÷ÿp÷÷wwÿÿ÷÷pOwÿw÷w÷ÿ€Gÿÿÿwÿp?wwwxwww‡wwp@@p »»»»‹»»»»wð »»»»{»·s»wp€ {»»»‹¸‹wp‡x»»»¸»?ÿÿ{·ðx‡ »»»»{÷óð‡K»»»»{7ÿ÷ûp‡x »»»»»·÷÷‹wp »»»»{³ww»·tK»»»»‹»¸»»s@CK·‡¸»‡·‡¸‹w{»»»»s»»{»‹»»»»wû»»»»¸»»»»{»»»»x»»»»{»»»»¸»»»»w{»»»»{»»»»»»»»»{»³»»‹»»»»‹»»»»w÷»»»»»»»»»{»»»»·{»»»»{‹»»»‹»»»»wû»»»»¸»»»»·»»»»w{»»»»‹»»»»‹»»»»·wx···‡·¸x{‡··¸xw÷ww÷÷w÷÷w÷( €€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿ÷w÷÷w@0÷÷÷÷w€O€ÿ7ÿ÷øˆˆwwƒCOp»»{{¿p‡C»»··ðˆ»»¿€»»‹»·ó38‹‹»‹w{»»»»{»¿û{»»»»»¿{»·»»{»·{»»·»‹»w÷÷ww÷puzzles-20170606.272beef/icons/keen.ico0000644000175000017500000006117613115373733016436 0ustar simonsimon 00 ¨%–  ¨>& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $((($$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%$$$'''§§§¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤«««€€€ýýýæææêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêçççøøø§§§'''øøøóóóôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôóóóüüüzzzùùùâââææææææææææææææææææææææææææææææææææææææææææâââóó󤤤$$$çççâââãããããããããããããããããããããããããããããããããããããããããããããâââëëë{{{ùùùâââææææææææææææææææææææææææææææææææææææææææææãããôôô¤¤¤%%%êêêæææææææææææææææææææææææææææææææææææææææææææææææææææîîî{{{ùùùâââææææææææææææææææææåååäåäåååæææææææææææææææãããôôô¤¤¤%%%êêêæææææææææææææææææææææææææææææææææææææææææææææææææææîîî{{{ùùùâââæææææææææææææææåæåìèìïêïìèìäåäåæåæææææææææãããôôô¤¤¤%%%êêêæææææææææææææææææææææææææææææææææææææææææææææææææææîîî{{{ùùùâââææææææææææææçççëèëÐÝÐÃØÃÏÝÏîéîéçéåæåææææææãããôôô¤¤¤%%%êêêæææææææææææææææææææææææææææææææææææææææææææææææææææîîî{{{ùùùâââææææææææææææåæåA¤Aˆ†ŠU¬Ußãßèçèåæåæææãããôôô¤¤¤%%%êêêæææææææææææææææææææææææææææææææææææææææææææææææææææîîî{{{ùùùâââææææææåæåéçéÜâÜI§IˆÀˆ¬Ï¬:¡:}w¹wôìôãåãæææãããôôô¤¤¤%%%êêêæææææææææææææææææææææææææææææææææææææææææææææææææææîîî{{{ùùùâââææææææææææææäåäôìôùîùÿòÿ·Ó·ƒD¤Dôìôãåãæææãããôôô¤¤¤%%%êêêæææææææææææææææææææææææææææææææææææææææææææææææææææîîî{{{ùùùâââææææææææææææéçé¸Ô¸À×Àßãßiµi~^®^ôìôãåãæææãããôôô¤¤¤%%%êêêæææææææææææææææææææææææææææææææææææææææææææææææææææîîî{{{ùùùâââæææææææææäåäñëñUªU‰ ‚“À×Àíéíäåäæææãããôôô¤¤¤%%%êêêæææææææææææææææææææææææææææææææææææææææææææææææææææîîî{{{ùùùâââæææææææææäåäòëòX­X€½€‹Â‹ËÛËíéíåååææææææãããôôô¤¤¤%%%êêêæææææææææææææææææææææææææææææææææææææææææææææææææææîîî{{{ùùùâââåååæææåååâãâðêðT¨T#˜# — ‘¶Ó¶ðêðäåäæææãããôôô¤¤¤%%%êêêæææææææææææææææææææææææææææææææææææææææææææææææææææîîî{{{øøøßßßìììæææçççðñðíêí•Æ•Y®YW«WY¯YX­XÈÚÈìéìåååæææãããôôô¤¤¤%%%êêêæææææææææææææææææææææææææææææææææææææææææææææææææææîîîzzzÿÿÿñññÏÏÏéééããã···áâáðêðõìõÿùÿñçñúîúêèêåæåææææææãããôôô¤¤¤%%%êêêæææææææææææææææææææææææææææææææææææææææææææææææææææîîîÙÙÙ•••ggg...```ÏÑÏpsp››}}éìéäääæææææææææãããôôô¤¤¤%%%êêêæææææææææææææææææææææææææææææææææææææææææææææææææææîîŠ555+++kkk<<<ÖÖÖ...××ׂ‚‚ÌÌÌíííäääæææææææææãããôôô¤¤¤%%%éééåååååååååååååååååååååååååååååååååååååååååååååååååååííí{{{ëëë___(((´´´333‰‰‰555»»»pppŒŒŒ}}}êêêàààâââââââââßßßðð𢢢&&&òòòíííîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîíííööö„„„ÿÿÿÃÃÃSSSééé···TTT±±±ýýýïïïÿÿÿìììúúúùùùùùùùùùùùùöööÿÿÿ³³³ ÊÊÊÆÆÆÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÇÆÆÆÆÆÆÌÌÌ???„„„ŠŠŠ|||„„„‰‰‰„„„|||}}}yyy~~~{{{{{{{{{{{{{{{zzzƒƒƒXXX“““‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘”””'''øøøóóóôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôôóóóüüüÿÿÿêêêîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîíííîîîððð%%%$$$çççâââãããããããããããããããããããããããããããããããããããããããããããããâââëëë{{{ùùùâââææææææææææææææææææææææææææææææææææææææææææååååååééé%%%%%%êêêæææææææææææææææææææææææææææææææææææææææææææææææææææîîî{{{ùùùâââæææææææææææææææææææææææææææææææææææææææææææææåååééé%%%%%%êêêæææææææææææææææææææææææææææææææææææææææææææææææææææîîî{{{ùùùâââæææææææææææææææâåââäââäââäââäâäåäæææææææææææææææêêê%%%%%%êêêæææææææææææææææææææææææææææææææææææææææææææææææææææîîî{{{ùùùâââæææææææææææææææöìöùíùùîùúîúûîûñêñåæåææææææææææææêêê%%%%%%êêêæææææææææææææææææææææææææææææææææææææææææææææææææææîîî{{{ùùùâââæææææææææçæçäåäu¹u`°`]¯][®[S«SšÇšîéîäåäæææææææææêêê%%%%%%êêêæææææææææææææææææææææææææææææææææææææææææææææææææææîîî{{{ùùùâââæææææææææçæçãæã!!}•Šq·qóëóãåãæææææææææêêê%%%%%%êêêæææææææææææææææææææææææææææææææææææææææææææææææææææîîî{{{ùùùâââæææææææææäåäíéí§Í§Œ&˜&ÌÜÌëèëàäàçæçææææææææææææêêê%%%%%%êêêæææææææææææææææææææææææææææææææææææææææææææææææææææîîî{{{ùùùâââææææææææææææäåäõìõºÕºŽ‘ÆÚÆñêñãåãææææææææææææêêê%%%%%%êêêæææææææææææææææææææææææææææææææææææææææææææææææææææîîî{{{ùùùâââææææææææææææçæçáäáïêïÊÛÊ‘ÒßÒëèëåååæææææææææêêê%%%%%%êêêæææææææææææææææææææææææææææææææææææææææææææææææææææîîî{{{ùùùâââææææææææææææåååíéíðêðÿóÿ‚¿‚}…¾…ôìôãåãæææææææææêêê%%%%%%êêêæææææææææææææææææææææææææææææææææææææææææææææææææææîîî{{{ùùùâââæææææææææçççâäâM¨M†À†¦Ì¦-›-~ŠÁŠôëôãåãæææææææææêêê%%%%%%êêêââââââãããææææææææææææææææææææææææææææææææææææææææææîîî{{{øøøÞÞÞâââäääæææäåäèæèB¥B‰†‰Q«Qßãßèçèåæåæææææææææêêê%%%%%%êêê÷÷÷øøøôôôæææãããããããããææææææææææææææææææææææææææææææîîîzzzÿÿÿööö÷÷÷îîîãããìììêéêéæéÑÞÑÃØÃÍÜÍíéíêçêåæåææææææææææææêêê%%%%%%êêêmmm```}}}èèèöööõõõôôôçççæææææææææææææææææææææææææææîîî„„„ÌÌÌTTTeee¬¬¬øøøÏÏÏÜÝÜíííëçëïêïíéíååååæåæææææææææææææææêêê%%%###óóó```ºººÓÓÓœœœ¤¤¤ãããçççææææææææææææææææææææææææîîîßßß___ØØØÛÛÛmmmàààåæåäåääåäæææææææææææææææææææææêêê%%%%%%çççÿÿÿ„„„kkkÚÚÚŠŠŠŒŒŒ•••âââçççåååææææææææææææææææææåååîîîxxxÿÿÿêêêEEEººº———aaaccc¬¬¬îîîäääæææææææææææææææææææææåååééé%%%%%%æææ|||MMM@@@óóóóóóõõõóóóæææåååææææææææææææææææææååååååííí„„„ÉÉÉjjj&&&•••ÿÿÿŠŠŠµµµöööãããæææææææææææææææææææææååååååééé%%%%%%ððð´´´›››ÝÝÝìììæææççççççêêêêêêêêêêêêêêêêêêêêêêêêééééééòòò€€€ðð𘘘µµµíííèèèéééèèèéééêêêêêêêêêêêêêêêêêêêêêêêêééééééííí%%%%%%000555((($$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%&&&+++444000$$$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%( @ ’’’ŒŒŒŒŒŒ‹‹‹“““"""   ÓÓÓÈÈÈÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÊÇÇÇØØØ{{{444ÿÿÿõõõöööööööööööööööööööööööööööôôôÿÿÿ<<<···ùùùëëëííííííííííííííííííííííííéééþþþ‘‘‘000ëëëáááâââââââââââââââââââââââââââàààííí777±±±ðððâââäääåååãäãáãáâãâáãáääääääáááõõõŒŒŒ111ïïïäääæææææææææææææææææææææææææææäääñññ888²²²òòòäääæææåååðêð÷í÷õìõóëóææææææâââööö111ïïïäääæææææææææææææææææææææææææææäääñññ888²²²òòòääääåäïêïªÎª?£?6 6ˆÁˆëèëåæåâââööö111ïïïäääæææææææææææææææææææææææææææäääñññ888²²²òòòääääåäñêñ”Å”ƒ¾ƒ¾…¢Ë¢óëóßáßööö111ïïïäääæææææææææææææææææææææææææææäääñññ888²²²òòòäääææææææåæåøíøßã߇„½„÷í÷ßáßööö111ïïïäääæææææææææææææææææææææææææææäääñññ888²²²òòòäääãåãóëóžÉž#˜#+›+3ž3ÒÞÒêèêáâáööö111ïïïäääæææææææææææææææææææææææææææäääñññ888³³³ñññââââãâñéñ—Ä— † S«S}¼}áäáçççâââööö111ïïïäääæææææææææææææææææææææææææææäääñññ888²²²õõõîîîêëêþùþº×ºL«LP­PK©KÒÞÒëèëáâáööö111ïïïäääæææææææææææææææææææææææææææäääñññ888µµµååå«««ÊÊʈ‰ˆØÖØàÖàÞÔÞëâëêéêåååâââööö111îîîäääåååææææææææææææææææææææææææäääððð>>>™™™RRR<<<]]]aaaŽqsqSUSäæäãäãäääàààôôô‹‹‹222òòòèèèéééêêêêêêêêêêêêêêêêêêêêêêêêèèèõõõ888ÂÂÂŠŠŠ___ŽŽŽ^^^žžž²²²žžžéééôôôñññîîîÿÿÿ•••...àààÖÖÖ×××ØØØØØØØØØØØØØØØØØØØØØØØØÖÖÖâââ444ŽŽŽ®®®‡‡‡©©©vvv°°°ºººººº±±±³³³²²²°°°¿¿¿mmm###¬¬¬¥¥¥¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¤¤¤®®®***%%%@@@AAA:::EEE999777777999888888888:::222333÷÷÷íííîîîîîîîîîîîîîîîîîîîîîîîîîîîìììúúú:::»»»ýýýíííñññïïïññññññññññññññññññïïïùùùÔÔÔ000íííãããäääääääääääääääääääääääääääâââïïï888±±±ðððâââääääääâãâàãàáãáàãàãäãäääâââëëëÈÈÈ111ïïïäääæææææææææææææææææææææææææææäääñññ888²²²òòòäääæææåååïéï÷í÷÷í÷úîúìèìååååäåíííÊÊÊ111ïïïäääæææææææææææææææææææææææææææäääñññ888²²²òòòäääåååìéì¹Ô¹ŽÃŽŠÁŠ~¼~ÈÚÈìèìãäãíííÊÊÊ111ïïïäääæææææææææææææææææææææææææææäääñññ888²²²òòòäääâåâöíö¼y8Ÿ8@¤@¯Ð¯ðêðâäâíííÊÊÊ111ïïïäääæææææææææææææææææææææææææææäääñññ888²²²òòòäääææææææëèëg³g)š)ÞãÞòëòãåãåååíííÊÊÊ111ïïïäääæææææææææææææææææææææææææææäääñññ888²²²òòòäääæææäåäîéîÿñÿnµn”ÛâÛéçéãäãíííÊÊÊ111îîîãããåååææææææææææææææææææææææææäääñññ888²²²ðððãããåååìéì·Ó·ÇÚÇ´Ò´€®Í®òëòâãâíííÊÊÊ000òòòîîîëëëääääääåååæææææææææææææææäääñññ888³³³úúúìììãåãóëó‹Á‹•’G¦GÞãÞèçèäääíííÊÊÊ444ááá¾¾¾ÏÏÏñññòòòëëëåååææææææææææææäääñññ999¯¯¯ÑÑÑÃÃÃçççëìëðíðÚáÚÓÞÓíéíêèêåæååäåíííÊÊÊ:::ÃÃÃ***°°°ÆÆÆ«««ÏÏÏêêêåååæææææææææäääñññ999´´´PPPrrrßßߌŒŒÄÅÄíëíêçêååååååæææäääíííÊÊÊ000ñññ|||ƒƒƒÄÄÄ›››ÉÉÉéééãããäääääääääãããïïï777µµµÀÀÀZZZÀÀÀ___   èéèãããäääåååäääãããëëëÈÈÈ999ØØØvvv¹¹¹ÿÿÿûûûôôôîîîïïïïïïïïïïïïíííúúú<<<µµµ™™™ŽŽŽøøøÔÔÔððððððïïïïïïïïïïïïíííöööÑÑÑ 666<<<999...///000111111111111111000333 '''======000666111111111111111111111222+++(   ­­­´´´²²²²²²°°°½½½uuu©©©ÔÕÔËËËÎÍÎÉÉÉÖ×Öžžž###ëëëôôôñññòòòïïïÿÿÿÁÁÁ÷÷÷êêêáèáòíòùùù···!!!ÝÝÝæææãããäääáááñññ”””ºººóðóÍÚÍoµo»úôú¯±¯"""ßßßèèèåååæææãããôôô–––¹º¹óðóÐÜÐi³id°dýöý°±°"""ßßßèèèåååæææãããôôô”””ÀÁÀÿýÿÄÛÄ6¤6¨Ë¨úôú¯°¯"""ãããëëëééééééçççööö   ‘‘‘‰Š‰ŸžŸ®­®àãàþþþººº ÒÒÒÚÚÚØØØØØØÕÕÕäää“““ooofffuuu”“”µµµÆÇÆ’‘’ÅÅÅÍÍÍÊÊÊËËËÈÈÈ××ׂ‚‚}}}©©©œœœœ•••ššš„„„"""äääíííëëëëëëèèèùùù™™™ÇÇÇûüûóòóý÷ýóòóûûûÙÙÙ """ÞÞÞçççäääåååâââóóó•••¸¹¸õðõ¼Ó¼B£B¤É¤ïìïÈÉÈ """ÞÞÞçççåååæææãããôôô–––º»ºîîîæäæt¸t”Ä”øñøÊËÊ !!!åååîîîéééåååãããóóó•••¿À¿ûøû×â×h³hs·súòúÉËÉ )))¦¦¦¿¿¿ØØØéééåååôôôŸŸŸ»»»ÆÊÆËÜËèçèïïïÎÎÎ ***———©©©ÐÐÐàààÜÜÜëëëššš†††µ´µæâæÞÞÞæææÆÆÆ  ''''''!!!!!!$$$''')))!!!!!!###(0` +++%%%¤¤¤¬¬¬v¹vúúúéçéìëìåæåôôô{{{ÞãÞÜÜÜÑÞÑÄÙÄÿóÿB¤BŠ„T«TI§IŠÁŠ¬Ï¬:¡:~ñçñóëóúîú·Ó·À×ÀiµiZ®Zprp Ž ’q·qÌÜÌ — Ž•Æ•ÌÌ̵µµ›œ›lllbbbÏÑÏŠŠŠ’’’333>>>ÕÕÕƒƒƒºººÇÇÇTTTCCC`°`šÇš§Í§%˜%¹Õ¹‘†À†‚¾‚-›-]]]MMM                                ! "#  $  %&!   ' #%(   )&*     +####(   , -    ../01$.  234/5667,   0-4248$27      7 9: -:- -99999999999999999,;7272777:333333333333333333.                     <##=  ' &*&%'    >%?    @A&   (&&    B   C>D        (  /E 7,:0 ,   08.. 7E/3   7/233  ;8300  F; 79/. 2-  -. 7 .- 4444( @‘‘‘ŽŽŽŒŒŒ‹‹‹•••###   ÑÑÑÄÅÄÊÊÊÏÏÏØØØ|||666ýýýööö<<<ºººúúúíëíîîîééé000áááäääàÖà888±±±ðíðäåäãåãñññèçèçççòòòòëòõìõïïï³³³ªÎª@¤@6 6„½„—Ä—¾…¢Ë¢ßáß#˜#+›+3ž3ÒÞÒ999 † S«S}¼}444ëìëþùþº×ºL«LK©Kµµµ¬¬¬ˆ‰ˆÞÔÞ™™™RRR===]]]aaaqsqSUSäæäÀÀÀ___²²²ôôôÖÖÖ©©©vvv¯¯¯¹Ô¹mmm%%%¥¥¥¦¦¦***@@@AAAEEE»»»úîúíéíŽÃŽ‹Á‹~¼~ÈÚÈy?£?¯Ð¯g³g)š)ÿñÿnµn”ÛâÛ·Ó·ÇÚǮͮ•’G¦G¿¿¿ÃÃÃÚáÚPPPrrrƒƒƒ›››ZZZÔÔÔ ...333 '''  ! " ## # $"% &''' #  ## # #()% *+,- ( # # # ")% &.//01' # # # #$!")"# '0/'2( # # # # "%!&13456# # # # # "7)"&.89:!#; # # # # "7<=>?9@6" # #  # "7AB CDD#  # # EFGHIJKL %"#7MNH O PP(=QQBCRSTTOTUVWBXXXXYXXXYXXBZW[\7]777777((7^"""""""Q  "7" !   # # # # "" # _'_`  # # # # ")%Uabcd! " # # # # ")"'/e,fg&  # # # # # "" hi!  " # # # # ")% #!&jklm   # # # "" nonep&! " # # #"A!'bqrs2# ;t "" ## "7B u$v6  7uZ B  ##"7Awx2 #  "y z  AM{MN   7S""AE|(""" }7~~;€~(  ­­­´´´²²²°°°½½½uuu©©©ÔÕÔËËËÎÍÎÉÉÉÖ×Öžžž###ëëëôôôñññòòòïïïÿÿÿÁÁÁ÷÷÷êêêáèáòíòùùù···!!!ÝÝÝæææãããäääááá”””ºººóðóÍÚÍoµo»úôú¯±¯"""ßßßèèèååå–––¹º¹ÐÜÐi³id°dýöý°±°ÀÁÀÿýÿÄÛÄ6¤6¨Ë¨¯°¯éééçççööö   ‘‘‘‰Š‰ŸžŸ®­®àãàþþþ ÒÒÒÚÚÚØØØÕÕÕ“““ooofff”“”µµµÆÇÆ’‘’ÅÅÅÍÍÍÊÊÊÈÈÈ××ׂ‚‚}}}œœ•••ššš„„„ííí™™™ÇÇÇûüûóòóý÷ýûûûÙÙÙ ÞÞÞâââóó󸹸õðõ¼Ó¼B£B¤É¤ïìïÈÉȺ»ºîîîæäæt¸t”Ä”øñøÊËÊ¿À¿ûøû×â×h³hs·súòúÉËÉ)))¦¦¦¿¿¿ŸŸŸ»»»ÆÊÆËÜËèçèÎÎÎ***———ÐÐÐàààÜÜ܆††µ´µæâæÆÆÆ'''$$$  !"#$%&'()*+,-./0123$%45*6789:0123$%(;<=>?.@0%AABCDEFGHIJ)KLMNNO&PQR STUVWXYZ[\]^ __`abc0&d2 efghihjkl0mB&3no`pqrstuv0mB3$%4wxyz{|}"3xA3%o`~€‚ƒ„…†‡NA3ˆ‰Š‹ŒŽ ‘’“a”•–m$—˜K™™""š›™…""Wœ(0`€€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿPˆ‡ˆˆˆˆˆ‡ˆˆ€ÿÿÿÿ÷÷ÿÿ€ÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿ€ÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿ€ÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿ€÷ÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿ€ÿÿÿÿÿ÷ÿÿ÷ÿðÿÿÿÿÿÿÿÿ÷ÿ€ÿÿÿÿÿÿÿÿÿÿð÷ÿÿÿ÷ÿÿÿÿ€_ÿÿÿÿÿÿÿÿÿÿð‡ÿÿÿò""ÿÿÿ€ÿÿÿÿÿÿÿÿÿÿðÿÿÿò‡"'ÿÿÿ€ÿÿÿÿ÷ÿÿÿÿÿðÿÿÿ÷ÿø(ÿÿÿ€/ÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿø(ÿÿÿ€ÿÿÿÿÿÿÿÿÿÿðÿ÷ÿø‡‚(ÿÿÿ€ÿÿÿÿÿÿÿÿÿðÿÿÿ÷""ÿÿÿ€ÿ÷ÿÿÿÿ÷ÿÿÿðÿÿÿø(wÿÿÿÿ€ÿÿÿÿÿÿÿÿÿÿðÿÿÿø""'ÿÿÿ€ÿÿÿÿÿÿÿÿÿðÿÿÿ÷*ˆ‡ÿÿÿ€ÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿ€ÿÿÿÿÿÿÿÿÿÿðø…ˆÿ÷ÿÿ€ÿÿÿÿÿÿÿÿÿð‡xÿÿÿÿ€ÿÿÿÿÿÿÿÿÿÿð('pÿÿÿÿ€ÿÿÿÿÿÿÿÿÿÿðp_ˆÿÿÿÿ€ÿÿÿ÷ÿÿÿÿÿÿð÷xÿÿÿÿÿÿ€w÷÷w÷ww÷wðˆˆˆˆˆˆˆˆˆˆ€ˆˆˆ‡ˆxˆˆˆˆ€ÿÿÿÿ÷ÿÿÿÿðÿÿÿÿÿÿÿÿÿÿpÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿÿÿpÿÿÿÿÿÿÿÿÿðÿÿ÷ø(Šˆÿÿÿðÿÿÿÿÿÿÿÿÿÿðÿÿÿò""(ÿÿÿòÿÿÿÿÿÿÿÿÿðÿÿÿ÷"ÿÿÿðÿÿÿÿÿÿÿÿ÷ÿðÿÿÿr'ÿÿ÷ÿðÿÿÿÿÿÿÿÿÿÿðÿÿÿÿ÷"ÿÿÿðÿÿÿÿÿÿÿÿÿÿðÿÿÿÿÿr/ÿÿÿðÿÿÿÿÿÿÿÿðÿÿ÷÷ÿò'ÿÿÿð/ÿÿÿÿÿÿÿÿÿÿðÿÿÿò'‚'ÿÿÿðÿÿÿÿÿÿÿÿÿÿðÿÿÿø""ÿÿÿðÿÿÿÿ÷ÿÿÿÿ÷ðÿÿÿÿ÷ÿÿÿ÷ðx‡ÿÿÿÿÿÿÿÿð‡ÿÿÿÿÿÿÿÿð€ˆ÷ÿÿÿÿÿÿÿðxÿÿÿÿÿÿðøx€ÿÿÿÿÿððÿÿÿÿÿÿðÿˆ÷ÿÿÿÿÿÿð÷x‡ÿÿÿÿÿÿð€ÿÿÿÿÿÿÿÿðøÿÿÿÿÿÿÿðÿÿÿÿÿÿÿÿ÷ðÿÿÿ÷ÿÿÿÿÿð( @€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ‡wx‡wxx÷÷ÿ÷ÿ€ÿÿ÷ÿÿrÿÿ÷pwÿÿõ÷ÿ÷ÿpÿw÷xw÷ÿ÷€ÿ÷ÿÿðÿ÷x§ÿÿp÷÷wÿÿx÷ÿ(‚ÿ€÷÷ÿÿw÷ò‡÷rwp÷÷ÿ÷÷õÿÿˆ*÷ÿpÿÿ÷÷÷xww*‡÷÷p÷w÷øwÿÿ‚(€ÿÿÿÿp÷÷wÿ€ÿÿ÷÷÷x‡‡ˆøÿÿp÷w÷òˆˆpw€ÿ÷ÿÿÿ÷õw‡ˆÿpww÷ww÷òWˆ(ˆˆxˆ€‡wxw‡wpR€…%(€ÿwÿwÿ÷øÿ÷ÿ÷ð÷ÿÿ÷wuÿÿwwð÷÷ÿ÷ÿò÷ÿwÿÿpww÷õ÷ÿwwð÷ÿÿÿÿÿò÷"¢ÿÿp/÷÷ÿ÷÷ðr÷ðÿ÷wÿ÷øw÷÷÷¨÷ÿpÿ÷ÿ÷uÿ÷rð_w÷ÿ÷ÿòw÷ˆ"ÿpÿ÷÷wõÿz‡ÿ÷ðˆÿ÷÷ÿò‡‡ÿ÷÷ÿpˆx‡ÿðˆ‡ˆw÷ðp÷ÿÿÿxˆxÿÿÿp‡ÿwÿÿu‡‡wÿÿwÿð€( €€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿwwxw÷p/ÿw÷÷pÿøxp÷øwøpW÷÷øzwp/ÿ÷÷ˆ‡÷pw÷øˆˆwpWwww‡‡‡€/ÿx÷ÿðÿÿørwp‡wø÷pÿøxðw÷÷‡wpw÷øwÿðPpuzzles-20170606.272beef/icons/inertia.ico0000644000175000017500000006117613115373732017146 0ustar simonsimon 00 ¨%–  ¨>& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÔÔÔÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÊÊÊÎÎÎ×××ÓÓÓÝÝÝÛÛÛÔÔÔÖÖÖÔÔÔÙÙÙßßßÓÓÓÖÖÖÑÑÑÈÈÈ×××ÓÓÓØØØÞÞÞÑÓÑÓÖÓÒÕÒÒÓÒßßß×××ÓÓÓÖÖÖÇÇÇÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÇÇÇÌÌÌÖÖÖßßß²²²}}}ÈÈÈÙÙÙÒÒÒƒƒƒ¤¤¤ÞÞÞÖÖÖÐÐÐÄÄÄÖÖÖÛÛÛËËË…ˆ…·²·æ×ææØæ«§«ŠŠÒÒÒÚÚÚÕÕÕÃÃÃÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÈÈÈËËËááá›››zzzÅÅÅÖÖÖÔÔÔÖÖÖËËË………‹‹‹ÞÞÞÏÏÏÄÄÄÞÞÞ¾¾¾xyxž‘žo‰o<‹<?Š?x‰xœœy{yÉÉÉÚÚÚÃÃÃÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÆÆÆÕÕÕ²²²{{{áááÚÚÚÔÔÔÕÕÕÕÕÕ×××æææŠŠŠÛÛÛÄÄÄÔÔÔz{z¡—¡$”$âþýÙ66¢–¢}€}ÚÚÚÃÃÃÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÇÇÇÐÐÐ{{{ÈÈÈÙÙÙÓÓÓÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕ×××xxxÇÇÇÑÑÑšš™‹™8’8øÿþþÿìOO“ˆ“¦©¦ÍÍÍÑÑÑÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÈÈÈÊÊÊÆÆÆÖÖÖÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔ×××ÈÈÈÊÊÊÅÆÅÓÒÓ“”“Áÿûÿÿûÿ°¦ž¦ÑÒÑÄÄÄÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÈÈÈÍÍÍÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÚÚÚÒÒÒÀÂÀìçìwŒwáÿþÿÿþÿÐ’–’èçèÀÀÀÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÈÈÈËËË×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÏÏÏÂÃÂäá䈓ˆÎÿýÿÿüÿ¼ ž àààÁÂÁÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔ×××ÈÈÈÌÌ̇‡‡ÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÒÜÜ܉‰‰ÂÂÂÑÑÑž¡žŸÿýüüþÿ3–3§ª§ÌÌÌÑÑÑÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÆÆÆ××ט˜˜’’’çççÓÓÓÔÔÔÕÕÕÕÕÕÒÒÒæææ¦¦¦†††ÙÙÙÈÈÈÀÁÀ~|~ޔެÿÿÿû ¡ ™–™{{{ÌÌÌÆÆÆÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÈÈÈÌÌÌÝÝݘ˜˜ÝÝÝ×××ÔÔÔÕÕÕÞÞÞ¨¨¨tttÔÔÔÒÒÒÂÂÂâá⢣¢ƒƒ–”–;Ž; £ ¡FŒFœ•œ|z|°°°ßßßÂÂÂÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÕÕÕÙÙÙÈÈÈÌÌÌÙÙÙÙÙÙ|||ÍÍÍÙÙÙÕÕÕ†††„„„ÒÒÒÛÛÛÐÐÐÆÆÆÖÖÖßßß­®­}}}µ¨µÌ»Ìͼͭ¡­|}|·¸·ßßßÕÕÕÄÄÄÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÑÑÑÔÔÔÆÆÆÊÊÊÓÓÓÑÑÑÝÝÝÃÃÃËËËÔÔÔÏÏÏÀÀÀÛÛÛÔÔÔÒÒÒÎÎÎÃÃÃÔÔÔÏÏÏÛÛÛËËËÂÅÂÔØÔÔ×Կ¿ÏÐÏÚÚÚÏÏÏÓÓÓÂÂÂÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÑÑÑÃÃÃÄÄÄÄÄÄÄÄÄÄÄÄÃÃÃÃÃÂÃÃÄÄÄÄÄÄÄÄÄÄÆÆÆ¼¼¼¿¿¿ÅÅÅÄÄÄÂÂÂÈÈÈÅÅÅÂÂÂÄÄÄÈÈÈÂÂÂÃÃÃÅÅÅÁÁÁºººÅÅÅÄÄÄÂÂÂÅÅÅÈÈÈÒÒÒÑÑÑÇÇÇÄÄÄÂÂÂÄÄÄÄÄĽ½½ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ××××××××××××ÖÖÕÝÝÝÞÞàÙÙØÖÖÖ×××ÖÖÖÚÚÚÉÉÉÎÎÎÙÙÙ××××××ÕÕÕÛÛÚÞÞàÜÜÛÕÕÕ××××××ØØØÒÒÒÆÆÆÙÙÙ×××ÕÕÕÙÙÙËËËMMMYYYÕÕÕÖÖÖÖÖÖ×××ÙÙÙÄÄÄÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÑááâœssjÒÒÖÙÙØÓÓÓÔÔÔ×××ÈÈÈÌÌÌ×××ÕÕÕÒÒÒÝÝÜÃÃÆkka²²´àààÒÒÑÕÕÕÖÖÖÐÐÐÅÅÅ×××ÓÓÓÕÕÕãã㟟Ÿ ²²²âââÔÔÔÔÔÔÖÖÖÃÃÃÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÒãã☘žœœaÔÔwyykÐÐÖÚÚØÓÓÓØØØÈÈÈÌÌÌ×××ÒÒÒÞÞÜÀÀÇ||aÞÞ|ˆˆ^­­´ááàÒÒÒÖÖÖÐÐÐÅÅÅÖÖÖÖÖÖÓÓÓVVViiiÚÚÚÔÔÔÕÕÕÄÄÄÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÒâââššŸ––]ÿÿœÿÿ¥ÒÒzxxjÑÑÖÙÙ×ÖÖÖÈÈÈÍÍÍÕÕÕÝÝÜÁÁÈzz^ççˆÿÿ¦öö“„„Z®®µááàÓÓÓÑÑÑÄÄÄÙÙÙáááSSSkkkäää×××ÃÃÃÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓâââ™™Ÿ––\ÿÿýýšûû–ÿÿ¢ÔÔ{wwjÐÐÖÜÜÛÇÇÇËËËßßÞÀÀÈyy^éé‰ÿÿ üü–ÿÿøø•ƒƒY­­µââáÎÎÎÄÄÄÒÒÒžžž¯¯¯ÐÐÐÄÄÄÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÞÞÞœœžšš^ÿÿŸýýšþþ˜ÿÿ™üü—ÿÿ¡ÙÙyyhÔÔ×ÈÈÈÐÐÐÅÅÈ||]îîŒÿÿŸýý—ÿÿ™þþ˜ÿÿœüü—††Z²²¶ÕÕÔÑÑÑGGG___ÔÔÔÏÏÏÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÞÞÞœœžšš^ÿÿŸýý™þþ˜ÿÿ™üü—ÿÿ¡ÙÙzzhÔÔ×ÈÈÈÐÐÐÄÄÈ||]îîŒÿÿŸýý—ÿÿ™þþ˜ÿÿœüü˜††Z²²¶ÕÕÔÑÑÑGGGcccNNN___ÔÔÔÏÏÏÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓâââ™™Ÿ––\ÿÿýýšûû–ÿÿ¢ÔÔ{wwjÐÐÖÜÜÛÇÇÇËËËßßÞÀÀÈyy]éé‰ÿÿ üü–ÿÿøø•ƒƒZ­­µââáÎÎÎÄÄÄÒÒÒžžžååå³³³¯¯¯ÐÐÐÄÄÄÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÒâââššŸ––]ÿÿœÿÿ¥ÓÓ{yyjÑÑÖÙÙ×ÖÖÖÈÈÈÍÍÍÕÕÕÞÞÜÁÁÈzz^ççˆÿÿ¥öö“„„Z®®µááàÓÓÓÑÑÑÄÄÄÙÙÙàààSSSkkkäää×××ÃÃÃÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÒãã☘žœœaÔÔwyylÐÐÖÚÚØÓÓÓØØØÈÈÈÌÌÌ×××ÒÒÒÞÞÜÀÀÇ||aÞÞ|‰‰_­­´ááàÒÒÒÖÖÖÐÐÐÅÅÅÖÖÖÖÖÖÓÓÓUUUhhhÚÚÚÔÔÔÕÕÕÄÄÄÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÒááâœssjÒÒÖÙÙØÓÓÓÔÔÔ×××ÈÈÈÌÌÌ×××ÕÕÕÒÒÒÝÝÜÃÃÆkka²²´àààÒÒÑÕÕÕÖÖÖÐÐÐÅÅÅ×××ÓÓÓÕÕÕãããžžž ±±±áááÔÔÔÓÓÓÖÖÖÃÃÃÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ××××××××××××ÖÖÕÛÛÛÛÛÝØØ×ÖÖÖ×××ÖÖÖÚÚÚÉÉÉÎÎÎÙÙÙ××××××ÕÕÕÛÛÚÞÞàÜÜÛÕÕÕ××××××ØØØÒÒÒÅÅÅÚÚÚÙÙÙ×××ÜÜÜÎÎÎOOO[[[ØØØÙÙÙØØØÙÙÙÛÛÛÅÅÅÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÑÑÑÃÃÃÄÄÄÄÄÄÄÄÄÃÃÃÍÍÍÑÑÐÆÆÆÃÃÃÄÄÄÄÄÄÆÆÆ¼¼¼¿¿¿ÅÅÅÄÄÄÂÂÂÈÈÈÅÅÅÂÂÂÄÄÄÈÈÈÂÂÂÃÃÃÅÅÅÁÁÁ¾¾¾Âººº»»»ººº¼¼¼ËËËÉÉɺºº»»»»»»»»»¼¼¼ºººÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÒÒÒÒÒÒÒÒÒÐÐÐÒÒÒ£££‘‘‘ÂÂÂÓÓÓÑÑÑÑÑÑÔÔÔÆÆÆÊÊÊÓÓÓÑÑÑÝÝÝÃÃÃËËËÔÔÔÏÏÏÀÀÀÛÛÛÔÔÔÒÒÒÊÊÊÝÝÝççç²²²¶¶¶¶¶¶µµµ²²²²²²µµµµµµµµµ···­­­¯¯¯×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÔÔÔÛÛÛæææ+++¡¡¡îîîÒÒÒÕÕÕÙÙÙÈÈÈÌÌÌÙÙÙÚÚÚ|||ÌÌÌÙÙÙÕÕÕ†††„„„ÓÓÓÛÛÛÌÌÌÝÝÝýýýàààãããããããããããããããããããããâââçççÉÉÉ®®®×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÞÞÞºººMMM &&&‰‰‰ÜÜÜÔÔÔ×××ÈÈÈÌÌÌÝÝÝ———ÝÝÝ×××ÔÔÔÕÕÕÞÞÞ¨¨¨uuuÔÔÔÎÎÎÜÜÜûûûÛÛÛßßßÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÝÝÝãããÆÆÆ®®®×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÒÙÙÙ¶¶¶lllÝÝÝÓÓÓÆÆÆ×××™™™’’’çççÓÓÓÔÔÔÕÕÕÕÕÕÒÒÒæææ¦¦¦‡‡‡ÖÖÖÛÛÛüüüÜÜÜßßßßßßßßßßßßßßßßßßßßßÞÞÞãããÇÇÇ®®®×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÚÚÚèèèBBB±±±ìììÆÆÆÌÌ̈ˆˆÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÜÜÜŠŠŠÀÀÀàààûûûÜÜÜßßßßßßßßßßßßßßßßßßßßßÞÞÞãããÇÇÇ®®®×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓßßßœœœ666 """cccÉÉÉËËË×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ËËËÝÝÝüüüÜÜÜßßßßßßßßßßßßßßßßßßßßßÞÞÞãããÇÇÇ®®®×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÑÑÑååå~~~ $$$ËËËÍÍÍÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÚÚÚÎÎÎÝÝÝüüüÜÜÜßßßßßßßßßßßßßßßßßßßßßÞÞÞãããÇÇÇ®®®×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÛÛÛµµµwww«««ÿÿÿNNNšššÈÈÈÉÉÉÆÆÆÖÖÖÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔ×××ÉÉÉÆÆÆÞÞÞüüüÜÜÜßßßßßßßßßßßßßßßßßßßßßÞÞÞãããÇÇÇ®®®×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙððð___000BBBÇÇÇëëëÆÆÆÐÐÐ{{{ÈÈÈÙÙÙÓÓÓÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕ×××xxxÅÅÅßßßûûûÜÜÜßßßßßßßßßßßßßßßßßßßßßÞÞÞãããÇÇÇ®®®×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÔÔÔÏÏÏ=== šššÝÝÝÒÒÒÆÆÆÕÕÕ²²²{{{áááÚÚÚÔÔÔÕÕÕÕÕÕ×××æææŠŠŠØØØÛÛÛüüüÜÜÜàààààààààààààààààààààßßßäääÇÇÇ®®®×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓØØØÕÕÕŠŠŠOOO¼¼¼ÞÞÞÒÒÒ×××ÈÈÈÊÊÊàààšššzzzÅÅÅÖÖÖÔÔÔÕÕÕËËË………ŠŠŠÞÞÞËËËÝÝÝúúúÙÙÙÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÛÛÛààବ¬×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖ×××ØØØÖÖÖ×××êêê;;;­­­êêêÒÒÒ×××ÚÚÚÊÊÊÎÎÎØØØááá´´´ËËËÛÛÛÔÔÔ………¥¥¥àààÙÙÙÏÏÏÜÜÜÿÿÿïïïñññññññññññññññññññññðððóóóäää¹¹¹ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÓÓÓÊÊÊËËËËËËÊÊÊÈÈÈÁÁÁ¿¿¿ÆÆÆÊÊÊËËËÊÊÊÍÍÍÀÀÀÄÄÄÍÍÍÉÉÉÓÓÓÑÑÑÉÉÉËËËÊÊÊÏÏÏÕÕÕÉÉÉÌÌÌÅÅÅÏÏÏòòòïïïððððððððððððððððððððððððïïïóóóÌÌÌÑÑÑÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÒÒÒÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÌÌÌÍÍÍÊÊÊÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÉÉÉÉÉÉÉÉÉÈÈÈÈÈÈÊÊÊÉÉÉÊÊÊÉÉÉÇÇÇÉÉÉÉÉÉÉÉÉÉÉÉÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÇÇÇÌÌÌÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖØØØØØØØØØØØØØØØ×××××××××ØØØØØØØØØØØØ××××××ØØØØØØØØØ××××××ØØØØØØ×××ØØØØØØØØØ×××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ( @ ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÖÖÖÚÚÚÔÔÔØØØÚÚÚÓÓÓÕÕÕÕÕÕÕÕÕÔÔÔÙÚÙÓÕÓÑÔÑÙÚÙÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÎÎÎÍÍÍÜÜÜÐÐм¼¼ÚÚÚÈÈÈÁÁÁÝÝÝÓÓÓÊÊÊÖÖÖÙÚÙÀÂÀÞÖÞåÛåÁÂÁÔÖÔÙÙÙËËËÑÑÑÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÌÌÌÒÒÒÊÊÊ‹‹‹µµµÛÛÛÌÌÌ’’’ªªªÜÜÜÇÇÇÙÚÙ¤¡¤‹‹z zw¥w‰…‰š”šÔÕÔÌÌÌÐÐÐÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÎÎÎËËËÉÉÉÞÞÞÓÓÓ×××ààà–––±±±ÕÖÕª©ª€€€»ðóÊs†s › ÍÎÍÐÐÐÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÑÑѼ¼¼¸¸¸ÝÝÝÒÒÒÕÕÕÔÔÔ×××ÎÎή®®ÍÐͲ£²<¥<ÿÿýÿ ¹ ¥™¥ÆÉÆÒÒÒÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÌÌÌÑÑÑÞÞÞÒÒÒÕÕÕÕÕÕÕÕÕÔÔÔ×××ÜÜÜÊÍÊÕÆÕ¼ÿüýÿÑ·¸·ÕÕÕÎÏÎÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÐÐÐÀÀÀÅÅÅÙÙÙÓÓÓÕÕÕÕÕÕÕÕÕÓÓÓ»»»ËÎ˼­¼-­-ÿýüÿÁ«¢«ÉËÉÑÑÑÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÐÐÐÄÄÄŽŽŽ×××ÛÛÛÔÔÔÕÕÕää䣣£¦¦¦Õ×Õ¢ž¢t„t Ò ÿÿâbb›’›ÊÌÊÑÑÑÖÖÖÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÕÕÕ×××ÍÍÍÕÕÕ¼¼¼ŽŽŽÅÅÅØØØÒÒÒ¡¡¡›››ÚÚÚÊÊÊÔÕÔš“š~ƒ~O£OI¨Iuˆu’‰’ÊÍÊÏÏÏÐÐÐÖÖÖÕÕÕÔÔÔÒÒÒÒÒÒÓÓÓÒÒÒÑÑÑÒÒÒÒÒÒÔÔÔÌÌÌÊÊÊÛÛÛ¿¿¿­­­ØØØÁÁÁ«««ØØØÒÒÒÆÆÆÖÕÖÑÒѰ®°ÛËÛãÒ㳯³ÈËÈÙÙÙÇÇÇÑÑÑÖÖÖÖÖÖÒÒÒÉÉÉÊÊÊÈÈÈËËËÒÒÒÈÈÈÉÉÉÊÊÊÄÄÄÄÄÄÉÉÉÍÍÍÏÏÎÑÑÐÎÎÎÐÐÐÉÉÉÈÈÈÀÀÀÉÉÉÉÈÉÎÏÎÂÅ¿¿ÍÏÍÊÊÊÉÉÉÃÃÃÒÒÒÖÖÖÕÕÕÕÕÕ×××ÕÕÕÜÜÛÍÍÏ©©¬ÝÝßÖÖÕØØØÏÏÏÎÎÎØØØÕÕÔÜÜÞªª­ËËÎÛÛÚÕÕÕÖÖÖÊÊÊ×××ÕÕÕíííQQQ(((âââÚÚÚ×××ËËËÑÑÑÖÖÖÕÕÕÕÕÕÓÓÓÚÚØÌÌÔ³³h¡¡žÜÜßÖÖÔÍÍÍÍÍÍÕÕÔÝÝߣ£ ³³i~ÊÊÒÚÚØÒÒÒÈÈÈÕÕÕÒÒÒXXX???ÂÂÂÚÚÚÈÈÈÑÑÑÖÖÖÕÕÕÔÔÔÚÚØÍÍÕ••{èèˆÿÿ¥ÂÂt›ßßâÍÍÌÌÌÌßß⟟žÀÀsÿÿ¤êꉕ•yÌÌÔÙÙØÅÅÅìììbbb:::åååÌÌÌÐÐÐÖÖÖÕÕÕ××ÖÎÎÒ˜˜zîî‹ÿÿžûû—ÿÿ ÈÈw¢¢›ÒÒÓÒÒÓ¤¤žÆÆvÿÿ ûû—ÿÿžðð˜˜xËËÏÌÌËIII///ºººÕÕÕÕÕÕÕÕÕ××ÖÎÎÒ˜˜zîî‹ÿÿžûû—ÿÿ ÈÈw¢¢›ÒÒÓÒÒÓ££žÅÅvÿÿ ûû—ÿÿžðð˜˜xËËÏÌÌËKKK***———///ºººÕÕÕÕÕÕÕÕÕÔÔÔÚÚØÍÍÕ••zèèˆÿÿ¥ÃÃt›ßßâÍÍÌÌÌÌßß⟟žÀÀsÿÿ¤êꊕ•yÌÌÔÙÙØÅÅÅííí]]] ```:::åååÌÌÌÐÐÐÖÖÖÕÕÕÕÕÕÓÓÓÚÚØÌÌÓ´´i¡¡žÜÜßÖÖÔÍÍÍÍÍÍÕÕÔÝÝߢ¢ ³³ižž~ÊÊÒÚÚØÒÒÒÈÈÈÕÕÕÒÒÒQQQ===ÂÂÂÙÙÙÈÈÈÑÑÑÖÖÖÕÕÕÕÕÕ×××ÕÕÕÜÜÛËËΦ¦¨ÝÝÞÖÖÕØØØÏÏÏÎÎÎØØØÕÕÔÜÜÞªª­ËËÍÛÛÚÕÕÕÖÖÖÉÉÉØØØØØØòòòWWW***æææÝÝÝÙÙÙÍÍÍÑÑÑÖÖÖÖÖÖÒÒÒÉÉÉÊÊÊÅÅÅÐÐÐããâÇÇÆÈÈÈËËËÄÄÄÄÄÄÉÉÉÍÍÍÏÏÎÑÑÐÎÎÎÐÐÐÉÉÉÈÈÈÄÄÄÄÄļ¼¼½½½¸¸¸¶¶¶½½½¼¼¼¿¿¿½½½ÒÒÒÖÖÖÕÕÕÔÔÔÓÓÓÎÎÎãã㦦¦RRRÖÖÖÖÖÖÒÒÒÌÌÌÉÉÉÛÛÛ¿¿¿­­­ØØØÁÁÁ«««ÙÙÙÎÎÎÝÝÝßßßÁÁÁÅÅÅÆÆÆÇÇÇÄÄÄÆÆÆÃÃﯯÓÓÓÖÖÖÕÕÕÖÖÖÒÒÒÜÜÜÀÀÀ<<<uuu××××××ËËËÕÕÕ¼¼¼ŽŽŽÄÄÄØØØÒÒÒ¡¡¡œœœ×××ÝÝÝóóóáááäääããããããääääääáááµµµÒÒÒÖÖÖÕÕÕÒÒÒæææºººFFFåååÔÔÔÃÃÃŽŽŽ×××ÛÛÛÔÔÔÕÕÕää䤤¤¤¤¤æææïïïÛÛÛßßßÞÞÞÞÞÞÞÞÞßßßÜÜÜ´´´ÒÒÒÖÖÖÔÔÔØØØ¯¯¯:::nnnÂÂÂÃÃÃÄÄÄÙÙÙÓÓÓÕÕÕÕÕÕÕÕÕÔÔÔ¸¸¸áááðððÜÜÜàààßßßßßßßßßàààÝÝÝ´´´ÒÒÒÖÖÖÒÒÒãããJJJ ;;; ‘‘‘ÞÞÞÜÜÜÒÒÒÕÕÕÕÕÕÕÕÕÔÔÔØØØÙÙÙÝÝÝñññÜÜÜàààßßßßßßßßßàààÝÝÝ´´´ÒÒÒÖÖÖÕÕÕÔÔÔÎÎÎVVV···&&&˜˜˜ÐÐм¼¼¸¸¸ÝÝÝÒÒÒÕÕÕÔÔÔ×××ÏÏÏ«««ãããðððÜÜÜàààßßßßßßßßßàààÝÝÝ´´´ÒÒÒÖÖÖÕÕÕÓÓÓÞÞÞËËË***iiiåååÏÏÏÊÊÊÉÉÉÞÞÞÓÓÓ×××ààà———®®®äääïïïÛÛÛßßßÞÞÞÞÞÞÞÞÞßßßÜÜܳ³³ÒÒÒÖÖÖÕÕÕÖÖÖÔÔÔÙÙÙÛÛÛWWW›››âââÖÖÖÍÍÍÓÓÓÌÌÌ···ÜÜÜÍÍÍ“““¬¬¬ÚÚÚÝÝÝóóóßßßãããâââââââââãããááá¶¶¶ÒÒÒÖÖÖÕÕÕÓÓÓÏÏÏÌÌÌ×××µµµ€€€ÒÒÒÏÏÏÐÐÐÈÈÈÆÆÆÕÕÕÊÊʶ¶¶ÓÓÓºººØØØÊÊÊÕÕÕ÷÷÷ðððòòòññññññññññññõõõÕÕÕÏÏÏ×××ÖÖÖÓÓÓÌÌÌÌÌÌÊÊÊÑÑÑÛÛÛËËËËËËÌÌÌÌÌÌÌÌÌËËËÍÍÍÑÑÑËËËÏÏÏÑÑÑÊÊÊÌÌÌÌÌÌÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÏÏÏÔÔÔÕÕÕÕÕÕÕÕÕ×××××××××ÕÕÕÓÓÓ×××××××××××××××××××××ÖÖÖ×××ÖÖÖÖÖÖ×××××××××ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÕÕÕÕÕÕ(  ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÙÙÙÕÕÕ×××ØØØÔÕÔÚÛÚàÙàÛÛÛÕÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÑÑѼ¼¼ÊÊÊÁÁÁÄÄÄÔÒÔ¶°¶ž¹ž²¯²ÐÎÐÒÓÒÕÕÕÕÕÕÕÕÕÕÕÕ×××ÇÇǺºº×××ÏÏϺ¼ºÂ·Â4µ4ù&½&¹²¹ÖØÖÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÉÉÉÔÔÔ×××ÙÙÙÑÒѾ·¾Úÿ â ³·³Ø×ØÕÕÕÖÖÖÕÕÕÕÕÔ×××ËË˰°°ÒÒÑÅÅų¶´ÊÁÊeŸe!×!Y£YùÃÔ×ÔÔÔÔÏÏÎÑÑÓÑÑÕÏÏÎËËÌÈÈÆÉÉÌÆÆÈËÊÊËÍÌÓÉÓμÎÒÇÒÌÍÌÒÒÒÔÔÓØØÝ¿¿···¢ÓÓÛÐÐÍÕÕݹ¹¥Â¹ÔÔÙÜÛÛ¶¸¶#'#¦¨¦ßßßÏÏÏÙÙÚ¿¿¹ßß‹õõ¼¼¡ÎÎÖ¼¼¢ôôÞމ¼­­¯ ÚÚÚÙÙÚ¿¿¹ÞÞŠôôŒ¼¼¢ÎÎÖ¼¼¢ôôÞÞ‰Ãü¨¨ª******žžžÚÚÚÕÕÔÖÖÛÁÁ¸½½¨ÑÑØÐÐÎÕÕݹ¹¥Â¹ÓÓØÛÛÚµµµ"""¥¥¥áááÏÏÏÒÒÓÕÕÔÈÈɵµ¸ÛÛÙÉÉÉÈÈÇÉÉÌÆÆÇÌÌËÐÐÐËËËÄÄÄÌÌ̾¾¾ÒÒÒ××××××==<¹¹¹ÓÓÓ­­­ÒÒÑÆÆÆ²²²çççßßßßßßáááÊÊÊÎÎÎÝÝÝOOO ¹¹¹×××ÖÖÖÙÙÙÍÍÍâââáááÞÞÞâââËËËÏÏÏÜÜÜ555oooÌÌ̺ººØØØÑÑѸ¸¸åååàààÝÝÝáááÈÈÈÎÎÎÒÒÒäää–––qqqâââÎÎθ¸¸ÇÇǾ¾¾¿¿¿æææèèèæææéééÖÖÖÐÐÐÕÕÕÎÎÎÙÙÙÜÜÜÏÏÏÐÐÐÔÔÔÑÑÑÒÒÒÓÓÓÒÒÒÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕ(0` ÕÕÕÞÞàÙÙ×ÊÊÊÜÜÛÂÂÈÏÐÏ­­­|||………¤¤¤Í¼Í…ˆ…³³´æ×欤¬‹”‹ÄÄÄÔØÔâââ››œŠŠŠ¼¼¼œ“œwŒw=Œ=x‰xœŽœêçê$”$âþÙ8’8¢—¢}€}¿Â¿uuuìOO“ˆ“§ª§“““Á°£ž£Ðμž¡žŸ5“5¬ ¢ æØæFŒFµ¨µ·¸·NNN]]]uujkkaœœaÓÓ{yyj||aÜÜ~‰‰_­­µTTT jjj––]þþ›ÿÿ£zz^ççˆöö“„„Zìì‹ûû–šš^EEE+++ìììüüü$$$333cccñññ<<<       !"#$%!&'()*+,-$.*$/01 23)*) $*45#6)%6 *!557$* 8 96$$$ $:;6<= 1>> ?@ABCDEF>>>GHIJK@ALMKNOEF>>>>>>HIJJNK@<LPKQJQOE>>>>>>>RSKJJJQKC<LPKQQQKQO T>>>>>>>>>>;IJJJJJKM<LPJQJQJQO T>>>H:>>>>>;IJJNK@<LMKQJQOE>> >>>R ?JK@<LMKNOEF>>>>>>H?@A BCDEF>>>>H<= 6>G :; $$$$ *$ 9 U> V( W :G>X#)%W Y>>>>>H* W T>>>>>>> VWZG>>>>>>>X[WE >>>GG>>>>>XW %Y>)WG>>>:WE\;>ZT>>>RW]>>>>G 1W6R>: 6W]> # W\\\\\\\\\\9$\\\\\\\\\\V\( @ÕÕÕÛÜÛÍÐÍ»»»ÆÉÆÄÄÄÌÌ̿¿ÞÖÞåÛåµµµ”””¦¦¨£££ŠƒŠz zw¥wš“šßß⬬¬uuu»òÊt…t¢›¢«¢«I¨Iþ ¹ ÕÆÕ¼Ñ·¸·¼­¼-­-Áããã Ò bbœœœ••zO£Ouˆu’‰’ÌÌÓÛËÛãÒãîîîTTT+++³³i››|<<<ëëŠÿÿ¢ÃÃtaaaÿÿžûû—ÈÈw¢¢ððJJJ[[[ òòòFFFlll²¯²&&&      !"#$% & '!( )*+,-./0 .123&. 4)45.2667*89:)  ):98*.1;66667&.58<=9>??:9=<@*A6666663.5@==<>??:9=<@5A636663.589:) &?:98*.1BC;C67& 4? 45.2667 1B3&&.""& 2&76 ?D&&&&&&& &C6C6E& &&D&&  766666F"&D&&G&A6C7C666-D&& 26 H66)"&D&&&"3666F& &&D& B6)&-" D&&&&&&   D1DDDD1D( ÕÕÕÙÙÙ×××ØØØÔÕÔÚÛÚàÙàÛÛÛÕÖÕÑÑѼ¼¼ÊÊÊÁÁÁÄÄÄÔÒÔ¶°¶ž¹ž²¯²ÐÎÐÒÓÒÇÇǺººÏÏϺ¼ºÂ·Â4µ4ù&½&¹²¹ÖØÖÖÖÖÉÉÉÔÔÔÑÒѾ·¾Úÿ â ³·³Ø×ØÕÕÔËË˰°°ÒÒÑÅÅų¶´ÊÁÊeŸe!×!Y£YùÃÔ×ÔÏÏÎÑÑÓÑÑÕËËÌÈÈÆÉÉÌÆÆÈËÊÊËÍÌÓÉÓμÎÒÇÒÌÍÌÒÒÒÔÔÓØØÝ¿¿···¢ÓÓÛÐÐÍÕÕݹ¹¥Â¹ÔÔÙÜÛÛ¶¸¶#'#¦¨¦ßßßÙÙÚ¿¿¹ßß‹õõ¼¼¡ÎÎÖ¼¼¢ôôÞމ¼­­¯ ÚÚÚÞÞŠôôŒÃü¨¨ª***žžžÖÖÛÁÁ¸½½¨ÑÑØÐÐÎÓÓØÛÛÚµµµ"""¥¥¥áááÒÒÓÈÈɵµ¸ÛÛÙÈÈÇÆÆÇÌÌËÐÐÐÌÌ̾¾¾==<¹¹¹ÓÓÓ­­­ÆÆÆ²²²çççÎÎÎÝÝÝOOO ÍÍÍâââÞÞÞÜÜÜ555ooo¸¸¸åååàààÈÈÈäää–––qqq¿¿¿æææèèèééé  !"#$%&'()*+,-./0123 4564789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`QRabWVWXYcdeefg`(hijklHIJmnopqrs(tuvw9xyz) {|A}~€+‚ƒ„PPr …†‡ˆ‰Š‹ŒrŒ)Ž_‰{ ‘’“†r”…A•–—Œ…‘|˜™š™›z…Žz A€A(0`€€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwxwx‡wwwwxwx‡wwwwwwwwwwwx‡wwˆwwwxx‚ˆxwwwwwwwwwwwXwwww‡wwX‚ª"ˆ‡wwwwwwwwwx‡wwwwˆwxˆªªª(ˆwwwwwwwwwxwwwwwrwx‚ªªª¢ˆwwwwwwwwwwwwwwwwww**ªªª‡wwwwwwwwwwwwwwwwwwŠªªªª‡wwwwwwwwwwwwwwwwww*ªªªª‡wwwwwwwwwxwwwwwxwˆŠªªª¢xwwwwwwwwwx‡wwwwˆwxrªªª(ˆwwwwwwwwww‡wwwwˆwx‡ ª¢ˆ‡wwwwwwwwwwˆwwwxwwwˆ…((x‡wwwwwwwwwwxˆwxˆwwwwˆwx‡wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwˆwwwwwwwwwwwwwwwwwwwwwww Wwwwwwwˆ‡wwwwwwˆ‡wwwwwxˆwwwwwx‡ˆwwwwwxwˆwwwwwP‡wwwwˆwx‡wwwwˆwx‡wwwrwwwx‡ww‚wwwx‡wwˆwww€wwwxwwww‡ww‡wwwx‡wp ww‡wwwXww‡wwwwˆw€wwxwwwx‡ww‡wwwx‡wˆðwww‡ww‚wwwx‡wwxwww€ðwwwwxwx‡wwwwxwxWwwwpwwwww‡ˆwwwwwx‡ˆwwwww€‡wwwww…‡wwwwwwˆ‡wwwwwxWwwwwwwwwwwwwwwwwwwwwwwP'wwwwwwwwwwwwwwwwwwwwwwxwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwˆ‡÷wwwwwxwww÷wwwwwwwwww€wwwwwˆwxˆww÷wwwwwwwwwwwwww‚wwwx‡w÷wwwwwwwwwwww‡wwww‡w÷wwwwwwwwx‡wˆwwwwwx÷wwwwwwwwp‡wxwwwwwxw÷wwwwwwwpwwwwwwwww÷wwwwwwwp‡wwwwwwww÷wwwwwwwxøPwwwwwwwww÷wwwwwwwwpxwxwwwwwx÷wwwwwwwwxwwx‡wwwwˆw÷wwwwwwwww€'wwwˆwwwx‡w÷wwwwwwwwwwwwwwx‡wwˆww÷wwwwwwwwww€wwwwwxwx‡wwÿ÷÷÷÷wwwwwwwwwwwwwwwwwÿÿÿÿÿÿÿ÷wwwwwwwwwwwwwwwwwwwwwwww( @€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿw÷w÷÷w÷www÷÷÷÷w÷wwww÷÷ww÷w÷wxwwwxˆˆww÷÷w÷w‡ÿÿˆ÷ˆªªw÷w÷wwwwwŠª¢‡wwwwww÷w÷÷Šªª§÷÷÷÷wwwŠ*ª§ww÷ww‡wøwˆªªˆw÷wÿww‡‡xЍ‡÷w÷wøwxww‡xww÷w÷÷ww÷wwwwwwwwwwww÷wøwww÷v÷÷wxwwpgwww÷çˆ÷wwˆwøwÿxwx~wçwwp÷woþþ‡w‡þwçøw‡w÷w÷xïw‡x€‡w÷çîww÷‡~÷p€‡wwx‡ww~‡÷w÷wwøwww÷wp‡w÷÷÷÷wwwwwwwwwwwwx‡www÷÷wwww‡÷÷p÷wx‡÷÷÷wwøw‡ww÷wwpwwwwø÷wwøw÷÷÷÷w÷xww÷w÷÷wð‡ww÷ø÷÷÷ww÷÷÷‡÷w‡w÷÷wwwp‡wxwøwÿ÷ÿw÷wwwww÷ÿÿÿÿwww÷w÷wwwwwwwww( €€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿÿww÷÷ww÷wwwwwwwwwsªwÿw÷÷z¦wwwwv¨wwwwÿwwwwwwww'÷÷~wwpwwwwwp`w÷wwww÷wwwwww`wwwÿwxw÷w÷‡w÷ˆww÷ww÷w÷w÷÷puzzles-20170606.272beef/icons/guess.ico0000644000175000017500000006117613115373732016641 0ustar simonsimon 00 ¨%–  ¨>& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖ×××××××××ÖÖÖÕÕÕÕÕÕÕÕÕÖÖÖ×××××××××ÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖ×××××××××ÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖ×××××××××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÒËÌÌËÎÎÌÍÍÓÓÓÕÕÕÕÕÕÖÖÖÑÑÑËÌËËÎËÌÍÌÓÓÓÕÕÕÕÕÕÕÕÕÐÐÐËËÍËËÍÍÍÍÔÔÔÕÕÕÕÕÕÕÕÕÏÏÏÌËÌÍËÌÎÍÍÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÎÑѽ¹¹¶¬¬¾¼¼ÏÒÒÕÕÕÕÕÕÕÕÕÌÏÌ»¶»·­·À¿ÀÐÓÐÕÕÕÕÕÕÔÔÕÊÊͺº´··­ÂÂÂÒÒÔÕÕÕÕÕÕÕÔÕÊÈÉ´¹µ±·³ÅÄÄÔÓÔÕÕÕÕÕÕÓÓÓÒÒÒÔÔÔÔÔÔÒÒÒÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÜÍͦµµ†³³¬··ÞÐÐ×ÙÙÒÓÒÛÚÛØÊØŸ´Ÿ‡³‡³¸³àÓàÖØÖÓÒÔÜÜÚÔÔÆ™™´‰‰³ºººááÖÔÕ×ÔÓÓÛÞÜÆÎɪ”¤§ŒŸ¾Á¿ÚàÜÕÔÕÔÔÔÞÞÞäääÛÛÛÛÛÛäääÞÞÞÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØÙÙÍÄÄ<¯¯ääóóààL¬¬ÓÈÇÛÝݽÂ-´-èóÛ^ª^ÙÌÙÜßÚµµ· ºëòÔppªÝÜÑÚÝݯ¦¬k£q¥s’i ƒ˜×ÞÙÜÚÜ™™™@@@³³³³³³@@@™™™ÝÝÝÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÖÖáÒÒV®®ùùÿÿþþÿÿóói®«êÎÝ>²@ÿÿþÿé­„âÙÔ*,µÿþþÿß›š³ÏÕË‹jº·„¶ƒ½†”h°©®âäã323______444ÜÜÜÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØÚÚÉ¿¿ÌÌÿÿüüÿÿüüÿÿ(ÉÊ·©©Ú ÿüÿüÿ?Å<­œ»ßÿýÿýÿSX¾³œ¢s·„²³€´‚¯y˜a‡áëä;;;¬¬¬¬¬¬;;;‘‘‘ÜÜÜÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÛÛü¼ ÐÐÿÿýýÿÿüüÿÿ"ÍÏ­¤Ÿßÿýÿüÿ8É3£’·äÿþÿýÿJPÀ°“•¤u¶ƒ³€³€³°z—W„Þêâ¶´µnnnÉÉÉÉÉÉnnn···ÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔ××ÜÍÍ>´´ÿÿþþþþÿÿýýQ³°àÃÑ'¼*ÿþþÿõk°m×ÊÍÁÿýþÿì……³ÇȾi½†³‚³¼ˆžl¦“ äèå534bbbbbb666ÜÜÜÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÔÔÜÛÛ´¸¸¿¿ùùÿÿ÷ö ¹¹¿¼»äß䢱£ È ýÿô/²/ÊÁÌãäÜ­ÐþÿîAA®ÕÓÈÚáß}”•g®w¯yk‘T€ÑÚÓßÝÞqqq –––––– qqqÞÞÞÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÔÔÜØØÈ¿¿tººPÂÄ|¸¹ÎÂÂÛÙÙÒÔÒÝØÞ¾¾Àuµl_¸QŠ´…ÑÈÔÙÙÙÒÓÔÝÝ×µµ»pp¶aa¸’’´ÖÖÌ×רÕÓÔ×ÝÙµ­³ k‘žcŽ­›¨ÒÙÔ×Ö×ÕÕÕÛÛÛÕÕÕÛÛÛÛÛÛÒÒÒÛÛÛÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØÚÚÊÔÕ¾™–Á~w¾ŸÌØÙØØØÓÓÓÛÚØÓÇÈ•±¿|¯Áªµ¿ÜÑÏÖØ×ÓÒÔÜÜÙÍÍİ~~¯±±·ÞÞÔÕÕ×ÔÓÓÚÝÛÂÇĤ‰œ¡˜º¹¹ÙÞÚÕÔÕÕÖÖÕÕÕÌÌÌÖÖÖÖÖÖÙÙÙ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÚÚھ´RDì<#øB(é;#°[OÂÉÊàÞݵ··»ºóðû÷æäG¬¬ÓÇÉßáݦ¦²ÂöûàZZªÚÙÍÚßÞ¦”¡g¨sªu•h˜n×ßÙÖÔÕµµµ´´´¼¼¼ÆÆÆ›››»»»ØØØÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÔÓÐÛݰf\þ?$ÿR9þO6ÿR9ø‚¬£©äÿýÿýÿWW»œœ¬íÿþþþü__°ììÝ‘777¨¨¨ÎÎΣ££ÀÀÀ×××ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÔÖàÙÒS¯vû†ÿ‚þ‡ÿrôf‰¯éÜÍ:u³zÿ…ÿƒþ‡ÿmë~•°áÜÊ'(¹ÿþþÿá——´ÔÔÅÁÿþþÿ×§§²ååâ223WWW³³³xxxšššØØØÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØÙÙËÇÂ6s°måsôkáEy¬ÑÌÆÜÝÞ¿½¼'o´qévókÛWª×ÑÌÝÞݱ±¶»ïöØjj©ÛÛÑÝÝÛ¡¡±ÂòõÑ}}ªÞÞÔÛÛÝ”””:::«««ÍÍÍ   ¿¿¿ØØØÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙØØßØÑ²½wž¹¤¶¾áÚÓ×××ÓÓÔÙÛØÜÔÏ¥¢¿‹‘½º²ÃáÜÔÕÖ×ÓÓÓÛÛÛÙÙÉŸŸ­ªÁÁ¹ááØÔÔÖÓÓÔÝÝÛÔÔÅ™™¬«ÈȽààÚÓÓÕÔÔÔÞÞÞäääÛÛÛÖÖÖÛÛÛØØØÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÓØÜܸº¼»~tÊm[¹ƒy»ÁÃÙÛÜÓÔÒÞ×Þ¯·²b»\NÄCvµtÈÁÌÛÙÚÒÓÔÝÝÕ¥¥¶\\ºOO¾~~³ÏÏÇÙÙÙÔÔÖÜÜÒ››´XX»QQ¾ˆˆ³ÕÕË×רÕÕÕÔÔÔÎÎÎÕÕÕ×××ÐÐÐÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÓÓÛÝÝ´®­Ç@-þ?%ÿD+ý>#¿F5·¸·åàæ—®–Ðÿÿú$¸$ĽÆåæÜƒƒªÙÿÿö44±ÏÏÆââÙoo©âÿÿðGG­ØØËØØÛ¯¯¯½½½½½½°°°ØØØÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×ÕÕËÖØ·YLÿF*þQ8þM5ÿQ9ÿB&³j\ÌËÚ$½!ÿýýÿùd²eÓÅËÅÿýýÿñ~~´ÃûÒÿýýÿè®ääÝššœ}}}­­­­­­}}}ØØØÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÛÚÚ¼ÀÀÑF2ÿM4ýL3ÿL3ýL3ÿK0ÐSC¬§Þÿþÿýÿ7Ê1 ¶åÿþÿýÿNN¼‘‘©ñÿÿÿþþVV²ææÕÐÐÔºººØØØØØØºººÓÓÓ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÚØØÀÇÈÉI7ÿM3üL4þL3üM4ÿJ/ÇXH¬µ¸ Õ ÿüþüÿBÂ?± ½Ýÿüþýÿ[[¹¡¡­éÿýþÿúdd®ììÞ{{      ÝÝÝÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÔÞß­unö:ÿP7þO6ÿP6î8ª…|áÚêI­Gýÿþÿ劭åÝÖ24²ÿÿþÿÚ¡¡µÙÙÉ »ÿþþÿа°µããâ334``````555ÜÜÜÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙ××ÈÏЫh`Ú=+ì?*Õ=,©rkËÔÕÛÚÙÊÁÉ;®<ÞëÐl©mÛÐÜÚÝÙ¿¾¼,.´æï ͪÝÝÔÛÛÛ±±¶"¹éí Æ‘‘­ÞÞÖÚÚܤ¤¤RRR»»»»»»RRR¤¤¤ÜÜÜÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔ×Ö×Ùãâ¿­·£ŽÄijÚããÖÔÖÓÔÓרÚç×â·À¥›·‰ËÇ»æÛæÓÕÔÓÒÓÚÜÛåÞΰž«‹¦ÒüäåÜÒÓÕÓÒÓÜßÜáØÊª˜©¡Ž¦ØËÁâäÝÒÒÔÔÔÔÝÝÝèèèÚÚÚÚÚÚèèèÝÝÝÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÕÞÞש§²KL¼/4ÎRS¹³±µÞÞØÒÒÖÞÞÔšž®GEÀ60ÏZ[µ»¾¸ÝÜÙÓÕÖÜÑÑŽ­°BÄÀ7ÎÈc²³Ä½¿ÛÙÙÔ×רÌÍ‚­°>ÇÃ9ÌÆm¯±ÍÂÄÙÚÙÕÕÕÓÓÓÇÇÇÕÕÕÕÕÕÇÇÇÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÔààÚœœ°Ñÿþÿ É©©´êê߆†«ÛÿþÿÀº¼»çÜÜq©©ääÿÿÿÿþþ$¸¸ÇÂÂâ××\©©ííÿÿÿÿùù5²²ÓÇÇÙÜÜ©©©‡‡‡¸¸¸¸¸¸‡‡‡ªªªØØØÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕØØØÈ..ºÿýýþÿBB¹ÖÖ»Åÿüýÿü\\µÌȹ ÊÍÿÿüüýýÿÿôôv´´½··××ÿÿüüüüÿÿìì„®®åÜÜ ¢¢†††±±±±±±†††£££ØØØÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÚÚÛÁÁ» Ñÿýÿýÿ Ϩ¨¢áÿþÿýÿ60Æžµ¤æêÿÿþþÿÿýýÿÿM½½¨¨òòÿÿÿÿÿÿþþþþT²²çÖÖÈÌ̧§§ÔÔÔÔÔÔ§§§ÌÌÌØØØÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔ××ÚÎÎÂÅÿûþûÿ//ÃÁÁ® ÓÿûþüÿGE½·¿®ØÜÿÿüüþþþþýý`··§¯¯ææÿÿüüýýÿÿ÷÷m°°âÕÕ±´´ÍÍͶ¶¶¶¶¶ÍÍÍ´´´ÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÕââÖmm«ïÿýÿç~~­ííÖTT¬÷ÿýÿÜ•˜±çØÓ?®°ýýÿÿýýÿÿÒÒª··ÝÍÍ+¶¶ÿÿÿÿþþÿÿÈȽ¼¼ÑÑÑ´´´ÿÿÿ««««««ÿÿÿµµµËËË×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÕÕØÙÙÍdd« Ñâ ÍssªÛÛÐÖÖÚÒÒÇTT¬ÕâÈ„„¬ÝÞÓרÚÊÂÂE¯¯ÙÙáá•®®ÞÖÖÙÚÚ¿¼¼8³³ÜÜàà"½½¤²²ÞØØÖ××¾¾¾§§§ÈÈÈÈÈȧ§§¾¾¾ØØØÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÖÖØááÕÃü««¶ÇǾáá×ÕÕ×ÔÔÓ××ÙààÒ¾¾º¬¬¶ÌÌÀááØÔÔÖÔÔÓÙÚÚßÏϺ¹¹­¶¶ÑÃÃàÚÚÓÕÕÓÔÔÛÚÚÜÌ̶¸¸¯¶¶ÕÆÆÞÚÚÓÕÕÕÕÕÙÙÙÙÙÙØØØØØØÙÙÙÙÙÙÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÒÒÕÙÙÛÞÞÜØØÚÒÒÕÕÕÕÕÕÕÔÔÔÓÓÖÚÚÛÞÞÜ××ÚÒÒÔÕÕÕÕÕÕÔÔÔÓ××ÛÛÛÞÜÜÖÙÙÒÔÔÕÕÕÕÕÕÓÔÔÔ××ÜÛÛÞÜÜÕÙÙÓÔÔÕÕÕÕÕÕÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÓÓÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÓÓÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÓÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÔÔÓÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ( @ ÕÕÕÕÕÕÕÕÕÕÕÕ××××××ÖÖÖÕÕÕÕÕÕÖÖÖ×××Ö×ÖÕÕÕÕÕÕÕÕÕ××××××ÖÖÖÕÕÕÕÕÕÖÖÖ××××××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÓÓÌÐÐÌÐÐÐÒÒÕÕÕÕÕÕÎÑÎÌÐÌÍÐÍÓÔÓÖÖÕÒÒÓÌÌÐÌÌÐÏÏÒÕÕÕÕÕÕÐÎÐÏÌÎÏÍÎÔÓÔÕÖÕÓÓÓÓÓÓÔÔÔÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÕÕÝ×ׯµµ¾®®ÜÒÒÔÖÖ×Ø×ØÊØ¹©¹Ï¾ÏÛÙÛÒÓÔÝÝØÇǶ½½­ÜÜÑÕÕÖØ××ÏØÒ®º²ÂÎÅÚÜÚÓÒÓÞÞÞßßßÚÚÚâââÖÖÖÕÕÕÕÕÕÕÕÕÓÕÕÞ××¥¾¾7ÎÎ+ÕÕ…¼¼ÞÕÓÓÍÖg¿g&Ù&IÇI¾Á¿äáݨ©½99Í**Ö¼ÞÝÓÏÕÓ¦l•¤&€¡F‡À»¾ßáß©©©£££ÀÀÀ“““ÔÔÔÖÖÖÕÕÕÔÔÔÚÙÙÀÃÃØØÿÿÿÿê禼ÊuÁnøÿÿ8Í8Ç»ÇÕÿÿ떠IJ}š¤p·²y™,yÙáÛ534!!!fff¹¹¹ÜÜÜÓÓÓÒÔÔâÙÙ“¼¼òòÿÿûûÿþfµÆ@Ê/ÿùÿì …¤õÿûÿTaÀ¯F}´°€·…£tÅÀ䦥“““¾¾¾~~~ÖÖÖÕÕÕÕÕÕÓÔÔÜÙÙ³ÀÀââÿÿÿÿóð“ºÉdÄYþþÿ*×'µ«½ àÿÿóƒÃ°kªt·‚¶}™sÕÚ×;:;&&&lll¼¼¼ÛÛÛÓÓÓÕÕÕÓÖÖÞÔÔ‡¼»âã ëìa¿¾ÜÐÐÆÈÊBÈAè )Ô%¤½©çá݇‰»Üå[ZÁØØÏÈÊÊ F‡©¡'~´ ®áæâ‰‡ˆ¨¨¨dddÎÎÎ×××ÔÔÔÕÕÕÕÔÔÖØØÙ×Ù¶™–®ŽŠÔËÌÖÛÛáØÚʼËy«ª¯³¿çÖÛÓÖ׿æÐ››®‚‚«ÙÚÄÛÚØÚßÝÂÍÅœz“°¬¯ÚçÞÖÔÕÜÜÜÚÚÚáááèèèØØØÔÔÔÕÕÕÕÕÕ×ÕÕÎר½rgòB)ûD*ÅYIÎËˬÁÁ ×Ôþÿéæxº»çÜÏQT¿òü! ËÉÌʾ²º™r°{¢r§s˜ÔÝ×¾¼½ÅÅÅ®®®”””ÏÏÏ×××ÕÕÕÔÓÓÙÝÞ¾ª§ì>&ÿO6ÿQ8ù?$É€x@ÓÕÿÿýýÿÿäßš—®îÿÿüiuîV…±|µƒ¹ƒ u¾½¾ÓÔÓ××׸¸¸©©©ÑÑÑÖÖÖÕÕÕÔÓÒÙßཡžñ@&ÿQ9þQ9ýD)Éul4רÿÿûüÿÿë䊌«óÿýÿ[hïK€³€²‚¹… rÉÆÈ{||fff¤¤¤UUUÍÍÍ×××ÔÔÔÕÔÔØ×ÖÉÏÐÇYJý=$ÿB)ÓD1Ì»ºÁÂåçÿÿõ÷W¾ÁÞÐÆ03ÈþÿÙµ»Æ¸›¬™m±~¥s›N†àêã979'''mmm½½½ÛÛÛÓÓÓÕÕÕÕÔÔÖÙÚÏÏÍÉŠyÉ~lÌÀºÔÜÝÞÔԭĽaÁ¸‘Á¹ÛÐÐØÙÙÔÔÊ~~¸ii¸¿¿ÂÝÛ×ÖÝÛð°«b…·Ž›ÔÚÔØØÙÑÑÑÏÏÏ×××ÌÌÌØØØÔÔÔÕÕÕÕÕÕÓÔÕÝÙÖ®·Â;Õ-ŠÜ©ÁÞØÔÓÒÏw™À8|Ñ[‹ÅÂÄÆáàÙ¯°ÂLLÉ==ÏŽŽ¿ÛÜÔ×ÕÎw{Ã,9ÚPXËÂÀÅÜÜÙÉÉÊÈÈÈÏÏÏÆÆÆÔÔÔÕÕÕÕÕÕÔÔÔÙÙÙÂÃÃqÖzÿ~ÿkè©´½yœÁnö‚ÿvÿ;ËÊļÖÿÿ꣣½€€Àôÿÿ11ÈÚÚÏ ———®®®………ÌÌÌ×××ÔÔÔÒÓÔâÝÙ“¦¼wò„ÿû}ÿgµ@…Ê€ÿù‚ÿ傃§ôÿûÿbb¸FFÇÿùÿâ¼¼ÄÂÂÀ³³´ÏÏÏ···ÕÕÕÕÕÕÕÕÕÓÔÔÝÛÙ±¹Àpãÿ‚ÿpõ¥ºa‘Äuÿ„þ|ÿ(}Ö±­³ äÿÿöŠŠ»hhÃþþÿÒØØÒ<<>³³³ŽŽŽÍÍÍ×××ÔÔÔÕÕÕÓÔÖÞÙÓ€»}å ~îYŒ¿ÛÕÏÃÆÆ:‚Éyõ"{ÙŸ¯¼èäÖ€½ßèSSÂ××ÎÇÇÈ>>Èë Øšš¼ççß‚‚„rrrÇÇǬ¬¬ÒÒÒÖÖÖÕÕÕÕÕÕÕÔÔÖרÚÞÙ²Ÿšª‘ŽÔÔÎ×ÚÚáÚßÌÿ{§€²¸¨èÙàÓÕ×èçÑžž®„„ªÜÜÅÚÚÚààÙÏϾ||ª®®²èèÖÒÒÕääãæææÛÛÛÞÞÞ×××ÕÕÕÕÕÕÕÕÕ×ÕÔÏØÙ¼tlñC+ùE+Ä[MÎÍѰÁ±Ôýå}¹‚èÝÛWZ»ðù&&ÊÎÎɶ¶ÃÓüèxx»ä䨦¦¨¢¢¢ººº———ÏÏÏÖÖÖÕÕÕÔÓÓÙÝÞ¾«¨ë>&ÿO5ÿP8ø? É‚‹CÒOÿýÿ㙲ìÿÿýxxºXXÅÿýÿÜÇÇÆ¸¸¸®®¯ÀÀÀ¥¥¥ÑÑÑÖÖÖÕÕÕÔÓÒØßཡœò@&ÿQ9ýQ9þD%Èt{3×Aÿûÿì ‰Š¨õÿýÿffºJJÈÿûÿáÃÃÉŠŠˆvvw¦¦¦]]]ÎÎÎ×××ÔÔÔÕÔÔØ××ÈÎÎÉVGþ;$ÿ@)ÕA,̹ÁŒÂæÿöS¿UÜÎÓ,/Æÿÿܸ¸Á——ÀçÿúII¾ééÛ558%%%kkk¼¼¼ÛÛÛÓÓÓÕÕÕÕÔÔÖØÚÍÎÊÌuÍ„gËÀ·ÔÛÜÞÒަʚ\ÎJŠÊzØÎØÚÛÙÐÌÉxgºcQº¹°ÁÛÝ×ÜÝÕªž¾]K»‡wº×ÖÎÙÙÙÍÍÎËËËÕÕÕÆÆÆØØØÔÔÔÕÕÕÕÕÕÓÓÕÝÜÖ³³ÃALÓ2?Ù•˜ÂÞÝÔÕØÍwÇ>+àcWÏÆÉÆàÚÙµÂÃSÕÆCÞ˕ĿÜÓÕ×ÎЃÆÀ?àÍ`ÐÃÅÆÇÛØØÌÌÌÌÌÌÑÑÑÉÉÉÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÄÄÄÔÿÿ嬬¾||Àóÿÿ??ÉÍʽÐÔÿÿÿÿç覾¾„ÀÀñòÿÿÿÿ5ÇÇÜÐМŸŸ–––¯¯¯‡‡‡ÌÌÌ×××ÔÔÔÒÒÔââÙ““¼òÿüÿgg¶AAÊÿùÿ 僥¨öôÿÿûûÿÿb¸¸GÇÇÿÿúúÿÿââ¼ÄÄÀ¾¾³´´ÉÉÉ©©©ÕÕÕÕÕÕÕÕÕÓÓÔÝÝÙ¯¯Àäÿÿö¹^^Åÿþÿ&#×®º²äåÿÿÿÿøø‡»»fÃÃÿÿþþÿÿ××Ä¿¿ËÌÌÍÎζ¶¶ØØØÂÂÂÙÙÙÔÔÔÕÕÕÓÓÖÞÞÓxx¼ßæOO¿ÚÚÏÂÂÆ00ÈêÕ›ž½èÝÖ{¹» ÝÝççJÀÀ×ÎÎÆÈÈ4ÆÆêêÖÖ™½½ÞÖÖÀÂÂÃÃÃÁÁÁÂÂÂÌÌÌ×××ÕÕÕÕÕÕÕÕÕÕÕÖààÔÅÅü¼ÁÞÞÐÖÖ×ÚÚרØÌ··ÀÎÎÆÞÞ×ÓÕÖàÕÕÆÄÄ»ÁÁÝÐÐÖ××Ù××ÙÌ̸ÀÀÍÆÆß××ÔÖÖÕÕÕÔÔÔ×××ÒÒÒ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÕÙÙÙÛÛÚÓÓÖÕÕÕÔÔÔÔÔ×ÝÝÚ××ÙÓÓÕÕÕÕÒÕÕÙÙÙÜÚÚÓ××ÔÔÔÔÔÔÔ××ÝÚÚ×ÙÙÒÕÕÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕ(  ÔÕÕØÕÕßÎÎØÕÔÙÔÚßÏßÖÕØÜÜÑÝÝÐÖÖ×ÔÞ×ÔÛÖÙØÙÞÞÞÚÚÚÔÔÔÙÖÖÉÏÏvÄÃÅÎԸʹxÃ{ØÙМ›Ê‹‹ÆÚÝÔ±ƒ¥Á¥¹ÉÎ˳²²ÁÁÁØØØäÑÑ\ÕÕÿÿDÔÞ4Ü&ÿX¸iÿþ‡^¦´o³†ŒMONƒƒƒááááÓÓ…Ö×úús×ãkÔSì”È“E:é(/毛»¯#ƒ¹Pœ£¥£jjj———ÞÞÞÕÛÛÖ¹¶Ëi[Þ­©–ÒÛBËÍÍÖÔtqÌZ[ÎÓÔͨQ´|¤ÙàÛÓÑÒÍÍÍÖÖÖÑàâÔuiÿ.Û[K èêÿÿP´ÇïÿU¡·r¬¨¤§…†…ÝÝÝÔÛÜ×´¬Þ`Jᦛ†Û×6ÙÔ½ÖÌgaÒLOÖÍÅÆ±C†Ãv¢¯´¯zyz¢¢¢ÜÜÜàÙÔ“·Ö ƒî…±×}¢Ñ#z੸ËTQÙ==Ü­°Ì(3çQZÞÕÕÏÉÉÊÉÉÉ×××äÛÑX“Õrÿ?…Ó0ƒÜwÿR‚Ç ñüWWÄþø•€€~¾¾¾ØØØÛÙÖ¼ÉÒYƒ·¹ÄÑ©ºÍJ‘¶ÚÖÔÉeeÉááÍZZÈÎÅŹ¨¨«ÎÎÎÖÖÖÒÞßדˆÿBâ}zFåLý~Ã.$óì„„Çñ23æÅÅĺº¹ÀÀÀØØØÑÞàÖ‡{ÿBàpj.ç<ÿe½r þõllÆû"!õ––˜]]\ŒŒßßßÙÚØÈÈÍ|[œÈÁÌ®ºÁP–áÕÑ…®Çk¡ÆéÜÍ`œÅ“µÉÕÎȲ´µÂÂÂØØØääÑ^]ÖÿFFÕ67ÝÿZjÈÿðøû`ÅÆÿÿðð·»¼²°°½¾¾ØØØááÓÒðqpÑ]_ÖÉ4ìãæê’ÇÇëí7ßàËÇÇÅÅÅÊËËÕÕÕÕÕÖÛÛÓÄÄÊÜÜÒØØÑÄÅÊâÝÕÏÍÎÊÌÌãÕÕÈËËÓÏÏÙÕÕÒÓÓÔÔÔÕÕÕ(0` ÕÕÕÖØ×ÛÓÔÖÖÙËÌÌËÍÓÕÓËÍÍÄÓÍѼ»»µ¬«Ã¼ž¾´©¸Â¾ÃËÓÔ···°¸ªÄÄÃÍÄó³´ÅÆÊÜÍͦµ·†©³­·¶ÛÛÛåÉב®­±ãÙÙ—˜³‹‹²ââÕ¨˜¥¥‡š½ÂÂäæä>¯°ããóóG­­ÓÈÇÛâÝ)¸)èôÞW°RÝÝÔ'(¸äóÓii«Œk¤t“išš›EEE;;;ãÚÔU±±û÷þþp­®>²@þãÚÊ34²þܱ|´‚¼…«««ââÛ444XXXaaaÈÉ%ËÍÔBÂ?§•²WX¸·š˜šj¼ˆ¬w™g‹¨ªµª¦ª:È5LRÀ–Y„Ûåâqqqnnn7´³S³±n±mƆ³Ž h$¹¹äÙ䣣£ È ““¬EE­ÖÛÚ}”¬um ””•w¸¶IÙ²¾iq»cf¹”޲³sjÍØÚ¼¸Âzz«·OAì<$üC)³WK½½££³WW«ÙÙ̱g[ü>#ÿR9ÿÿÿ{{|ÌF3þL3ØØ;ÊÅNT¿ÿP7ÌUEìò9ÙÓÈ!¼»Á²êë É………!!!„s¶£—¦s{™¶i Âh‰²xx³&yÌsôvû'o· nÔ}ý7t±‡‡«H{¯ƒÿV¯»ÉÇ»œ­<‚ÃììÜpílæÊm[²„{b»\NÄCØ=,ÿD)¿F5JJ¼ÎÉ·;®< Ò/4Î60Ëe³³((É   !"#$%%&'(')*+,-./01234561 7889#:;<:=>?@@@(ABCCCC-ADEFFFFG7HIIJ9KLMNOPNM Q@@@@?R SCCCCCTU3FFFFFVWXYIIIZ[%\<]K<\ Q@@@@@R^-CCCCC_U3FFFFF`W8IIIIHabcde@@@@@f,CCCC.ghFFFF4ijIIIY8#bMNPPN<+Q(@(k lmnCC.,!o5FF4pqr9ZZXsct:utcvwx g0lyz{[["W| }q*xv~{!## +$€‚ƒ+„(?')*…h4FG†‡"j8Z9[ : }ˆ‰ŠŠŠ‚se@@@@(A2FFFF3{7JIIJX^‹ mŒ:ŽŽŽŽŽ@@@?@"3FFFFF‘"8IHIIHa+ $’ŽŽŽ’“@@@@@"”FFFFF‘W8IIHIZabm; Om}ˆ‰Š’Š•se@@@@(A–—FFFF3 jJIIYX"%MNPPNM˜€‚ƒl„(@™)L…š4F3†‡"98Z9[+›œmmœ›Wžv ] #Ÿ+l  ¡ 1  ¢1 £y‡1yy…‡ ¤¥¦¥§L]¨¦©¥ªLo5FF”pL«5FF3†1uu‡¬©­©­¦®D§©­­­¥¢–¯FFFF”i°šFFFF3±L:Œ^Ug: ¨­©­©­¤K¨­©­­©²"3FFFFF‘o4FFFFFV! °¨­©©­­¤ ¨­©­©©²^3FFFFFV±”FFFFF6³\M^m$D®¦­­­¥¢Dª©­­­´ D2FFFFG–hFFFF5]%MNOŒ:ªµ¥µ¬% §´¦µ®+¯”4G61±h”451u=mmhFFFFFÄ šFFFFF¾??@@@>'@@@@(A=!64FFF3³†FFFFGo=)@@@@k@@@@Q ‹KK‹‡6ÂGš1†Â3h«1)Q &'k KK ! ]11 ]= Lqq( @ÕÕÕ××ÙÕÚÖÍÒÑÌÍÌÕÕÍÍÐÍÓÎÒÜÔÔǵµ¾²ºÙÍÖµ«¸Ë¼ÉÛÛÚËÆ»¸»«ÙÙδµµÇÉÇáÚÚãä㫹º5ÉÉ0Ö׆¼»Ú×Ég¿g,Ô+KÌI¸Á©ª»==Ë>+àˆˆ¼ÝÜÔÏØÖ¬o’¤&€›N†»»»¬¬¬¤¤¤Á½¾•••ÃÃÄ ÚÙþþé鬶ÅuÁnöþÖþ䓬ţr´‚²|™,yÛãÝ879iii–½½óófµÆ@Ê/ë …†©ôXe¯F}¹„¥uzzzäådÄY ₇™q%%%çäb¼»æÙؤ½©è[[Ä©¹©¬äéæˆˆˆ¦¦¨°‘ÕÌÌyµµææÕœ›«œz“½sjôB'ýC*ÆYJRVÇ&'ÉÖÚÚì>&ÿO6ÿQ9û>#ʈwHÏÉäßëioîV…Ùßà´œ˜ÉzlYYYÔC/ÁÂW¾Á01Èܼ¼Â±µ­Ä½aÁ¸“ügµff¸4ŒÙ–©»x›Á8|Ña‘ĵ¶ÂGGÉ–˜Á{zÃ/<ÚqÖvÿtô}þœŸŸ‚þNˆÈåwé%|Ø€»;‚ÊtîäâÛ%$×™™ºèÙà|°ÌÍÑÔæŒÂTW½zzºÉ‚‹ãܽ¡Èt{3×AS¿ULL¿Í„g¦ÊšŠÊzzr²cQº]K»‡wºALÓcWÏ„ÃÀ`ÐÃÕÖ 僥¨fÃ÷Á¸   !"#$%&'()*+,-.//012344 56678%9:;<=>?@A(BC///DE444FGH666IJK::L-*,(M(N//C8O444 P66HQ%9::R>S@A(T0UVFW"5XY'Z&[\]]^@__`V aVbcG=d)=\efgh./0abiH6j R;9dk(-[, lmnopq///rcs66Htu;:KL((^vwfnngx///TGH666Iu::KLM@*yhogz {N/C|}66~€9:9'\>S@A(px+‚ƒ=„…+# u_1††‡ˆ‰ŠV‹Œ Ži--‘‘’ˆ’“‘I566sŽH66}#”,)]#‡’••“„–•“•—GH666…Œ6667-˜••’‡Š‘•“™[P66H"t6665>?,Vš—˜Š-›œ™‡"XXi XžŸ=dM-)w_ ¡ bcG„[b=\$xffh¢£4¤¥¦sHj‹567§^*(,k[lnno¨444©cs666§Y666ª()*k«lnng¬­444FGs666…Œ6667]M^y¢hogz ¥¤43® }66~‹Ÿ76H¯b>S@A+p°k±O² ³´‹##µ¶-#‹·=Ž!¸V‹qq{¹qº-5667 §H66Œ»//N1C//”,)]Ÿs666…Œ666¼½C///‚q/C/N+^ 766H"Y666ž0//C¾///» #-#§~7¯-}s5‡Va.Nq`0»B¿--+=-b‹`#VV`(( ÔÕÕØÕÕßÎÎØÕÔÙÔÚßÏßÖÕØÜÜÑÝÝÐÖÖ×ÔÞ×ÔÛÖÙØÙÞÞÞÚÚÚÔÔÔÙÖÖÉÏÏvÄÃÅÎԸʹxÃ{ØÙМ›Ê‹‹ÆÚÝÔ±ƒ¥Á¥¹ÉÎ˳²²ÁÁÁØØØäÑÑ\ÕÕÿÿDÔÞ4Ü&ÿX¸iÿþ‡^¦´o³†ŒMONƒƒƒááááÓÓ…Ö×úús×ãkÔSì”È“E:é(/毛»¯#ƒ¹Pœ£¥£jjj———ÕÛÛÖ¹¶Ëi[Þ­©–ÒÛBËÍÍÖÔtqÌZ[ÎÓÔͨQ´|¤ÙàÛÓÑÒÍÍÍÖÖÖÑàâÔuiÿ.Û[K èêP´ÇïÿU¡·r¬¨¤§…†…ÝÝÝÔÛÜ×´¬Þ`Jᦛ†Û×6ÙÔ½ÖÌgaÒLOÖÍÅÆ±C†Ãv¢¯´¯zyz¢¢¢ÜÜÜàÙÔ“·Ö ƒî…±×}¢Ñ#z੸ËTQÙ==Ü­°Ì(3çQZÞÕÕÏÉÉÊÉÉÉ×××äÛÑX“Õrÿ?…Ó0ƒÜwÿR‚Ç ñüWWÄþø•€€~¾¾¾ÛÙÖ¼ÉÒYƒ·¹ÄÑ©ºÍJ‘¶ÚÖÔÉeeÉááÍZZÈÎÅŹ¨¨«ÎÎÎÒÞßדˆÿBâ}zFåLý~Ã.$óì„„Çñ23æÅÅĺº¹ÀÀÀÑÞàÖ‡{ÿBàpj.ç<e½r þõllÆû"!õ––˜]]\ŒŒßßßÙÚØÈÈÍ|[œÈÁÌ®ºÁP–áÕÑ…®Çk¡ÆéÜÍ`œÅ“µÉÕÎȲ´µÂÂÂääÑ^]ÖÿFFÕ67ÝZjÈÿðøû`ÅÆðð·»¼²°°½¾¾ááÓÒðqpÑ]_ÖÉ4ìãæê’ÇÇëí7ßàËÇÇÅÅÅÊËËÕÕÕÕÕÖÛÛÓÄÄÊÜÜÒØØÑÄÅÊâÝÕÏÍÎÊÌÌãÕÕÈËËÓÏÏÙÕÕÒÓÓ  !"#$%&'()*+,-./0123456789:;<=> ?@ABCDEFGHIJKLMNOPQRS"TUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›NœžŸ ¡¢£¤¥¦§¨©ª«¬­®¯%°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍËÎÏÐÑ"ÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóå(0`€€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿwwwwwwwwwwwwxwwwwwwwwwwwwwxxwwx‡‡wwxxwwwˆ‡wwxwwwwwxwwwwxwwwwwwww‡wwwww‡wwx;¸‡w†ª8wx‘wwu…Xwwwx‡ww‹»»¸wŠªªwq™™•weUUWx%†ww‹»»¸vªªª§™™™™xUXX8tSQww»³»»sªªª¨‰™™™……XUXx7xgww;»»»rªªª§Y™™‘xUUUWw€rWww{»»³rªªªg‰™™‘wUUUWuSTwwx»³7wŠªªws™™—wXXU‡v€ˆ'www‹¸wv£ˆwwˆ8‡wxX'ww‡xwwwwwwwwwwwwwwwwwwxwwwwwwwwxŒÅ‡wx»7wwY‡wuUXwwˆwwwwvÌÌÇw;³»‡s™™˜w5U…‡x÷ˆˆww\ÌÌÈx»»»7‰™™‘xXUUWw÷‡xwwlÌÄÌs»»»·Y™™™…UXUSwxw‡wwÌÄÌÄx»»»·‰™™‘…UUUXsGrWwwŒÌÌÈw»;»‡9™™™wUX…Wu5…awwxÌÌÈw;»»wu™™w…UX‡rƒˆwwxŒŒwwx;8ww9˜‡wxXTwwˆxgwwww‡www‡wwwwwwwwwwwwwwwwww“8‡wƒµ7ww‡wxww‡÷wwwƒŠˆwXc8‡x™™˜w‰™‘wxˆx(ww83ƒ3x3;ƒ‰™™™x™™™—xW‡‡wwƒ3ƒ3u3†8‡‰™™™x™™™˜wwwwwƒƒ88sS3ƒ™™™™ˆ™™™w‡x‡ww8ƒ8x8ƒ3§‰™™‘w™™™—vxˆwwv88wƒ38Ws™™˜w™™7uxgwwxƒ3wws8Wwx‰‘wwxww‡wwwww÷‡wwwxwwww‡wwwwwwwwwwwwwHŒwwsj7ww5˜‡wqˆwwwwwwwuÌÌÈwjªª‡x™™—w‰™™wxˆxˆww\LÌÈrªªªgy™™™w™™xˆx‡wwŒÌÌÌxªªª¨‰™™‘q™™™—wxw‡wwŒÌÌÌzªªª§‰™™™ˆ™™™wtWwwÌÌlÅvªªª7™™™x™™™˜pe8%wwŒÌÌÈwŠ¢ª‡y™™˜w™™™‡sC‚wwx\Èwwƒª&ww‰Y‡wx˜wwxx‡wwww‡wwwwwwwx‡wwwxwwwwwwwww‰ƒwwx5‡wws¸‡ww8wwwwwwwwx™™‡w‰™™‡s»»·w‹»¸‡xGw‡ww‰™™“q™™™‡{»»¸x»»»·wxˆˆww‰™™™x™™™;»»»ˆ»»»·w‡x‡ww™™™‰™™™˜‹»³»s»;»¸xˆw‡ww‰™™•x™™™—‹‹»»x»;»¸x÷‡÷ww‰™™˜x™™‘‡{»»³w;»»‡w÷wøwwx‘‡ws˜wx‹»‡wx»¸ww‡x‡wwww‡wwwxwwww‡www‡wwwwwww( @€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿwwwwww÷÷w÷wwwww÷wwwww÷ÿ{‡v§÷x—÷uÈwwww‹»‡ªª‡™™‡X؇4C‡x»»¸¢ª§™™XÍ…_ˆx÷÷{»¸ªªˆ™™7X؇a÷‹»wŠªw™™X\wG0www7ø‡÷øwwõ‡wÿwÿwÇw{8ws—÷X…wwxÈ\‡»»w™™‡\Øwwx÷ŒÈh»»·™™8ÕWwwwwŌ߻»ˆ™™‡UȇwÈÅ‹»w9™wÈØw€†w÷w÷‡÷‡÷øWww÷x¸w»8wy˜y÷ww÷w¹8w‰y‡™™x™™w‡xwø³˜—˜‹¸™™…™™—ww÷w‰¸·‹›7™™7™™?x÷x‰wy•w‰™‰™waww÷{wwøw÷ww÷÷‡÷w|…z¨wy˜wx˜www÷Èȇªª‡™™7™™w‡‡w÷\ŒÈªªƒ™™•™™?wwwwÈ͇ªª‡9™‡™™?4w|ŒŠªw9™w9™wX†÷÷‡÷÷‡ÿ÷ww÷÷wwy•q™w{¸ws¸÷www‘™7™™—;»w»»‡‡xww™™˜™—»»¸»»·‡w÷™™7™™ˆ»»x»»wwwwq™y“‹»‹¸÷wwwww÷‡÷wwwww÷÷÷w( €€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿwwwwwxwwwwx»ª‰—Èx‡÷·Šy•…ˆ‡wÇ{wu÷÷wŒ»¹˜]ˆww‡{x‡ˆx÷—yx—Y÷ww‰¸™™™x÷Ÿxw‡xwxÇz‰—™wwŒª©˜™xW÷y÷wwx™‰‹³»xw÷˜‰{·»wwww÷wwwpuzzles-20170606.272beef/icons/galaxies.ico0000644000175000017500000006117613115373731017307 0ustar simonsimon 00 ¨%–  ¨>& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÚÚÚÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÚÚÚÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÒÒÒÙÙÙÖÖÖÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÐÐп¿¿×××ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÙÙÙàààâââââââââââââââââââââáááÂÂÂÓÓÓ×××ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×××ßßßãããââââââââââââââââââåååÇÇÇÓÓÓØØØÔÔÔÕÕÕÕÕÕÕÕÕÔÔÔÞÞÞ°°°000×××ÑÑÑÑÑÑÒÒÒÒÒÒÒÒÒÑÑÑÖÖÖ···˜˜˜œœœ›››››››››››››››–––"""¿¿¿ÖÖÖÑÑÑÒÒÒÒÒÒÒÒÒÑÑÑÕÕÕ———™™™˜˜˜˜˜˜˜˜˜˜˜˜˜˜˜———£££&&&ºººçççÑÑÑÕÕÕÕÕÕÕÕÕÔÔÔÞÞÞ°°°,,,ÏÏÏÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÆÆÆÚÚÚaaaAAA999:::::::::::::::777CCCÁÁÁÌÌÌÉÉÉÉÉÉÉÉÉÉÉÉÇÇÇ××׈ˆˆNNNEEEFFFFFFFFFFFFFFFHHH???ÅÅÅßßßÓÓÓÕÕÕÕÕÕÕÕÕÔÔÔÞÞÞ¯¯¯000ÝÝÝÖÖÖ××××××××××××ÓÓÓëëë\\\xxx÷÷÷ßßßããããããããããããããããããÔÔÔ××××××××××××××××××ÔÔÔèèè„„„ZZZÿÿÿûûûÿÿÿÿÿÿÿÿÿÿÿÿþþþÿÿÿëëëùùùÜÜÜÔÔÔÕÕÕÕÕÕÕÕÕÔÔÔÞÞÞ¯¯¯///ÚÚÚÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÑÑÑèèè[[[nnnåååÏÏÏÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÆÆÆÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÒæææƒƒƒXXXÿÿÿøøøüüüüüüüüüüüüûûûÿÿÿååå÷÷÷ÜÜÜÓÓÓÕÕÕÕÕÕÕÕÕÔÔÔÞÞÞ¯¯¯///ÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÑÑÑééé[[[pppèèèÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÈÈÈÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÒæææƒƒƒYYYÿÿÿûûûÿÿÿÿÿÿÿÿÿÿÿÿþþþÿÿÿèèèøøøÜÜÜÓÓÓÕÕÕÕÕÕÕÕÕÔÔÔÞÞÞ¯¯¯///ÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÑÑÑééé[[[pppèèèÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÈÈÈÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÒæææƒƒƒYYYÿÿÿûûûÿÿÿÿÿÿÿÿÿÿÿÿþþþÿÿÿèèèøøøÜÜÜÓÓÓÕÕÕÕÕÕÕÕÕÔÔÔÞÞÞ¯¯¯///ÛÛÛÔÔÔÔÔÔÕÕÕÖÖÖÔÔÔÑÑÑééé[[[pppèèèÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÈÈÈÔÔÔÕÕÕÔÔÔÕÕÕÖÖÖÔÔÔÒÒÒæææƒƒƒYYYÿÿÿûûûÿÿÿÿÿÿÿÿÿÿÿÿþþþÿÿÿèèèøøøÜÜÜÓÓÓÕÕÕÕÕÕÕÕÕÔÔÔÞÞÞ¯¯¯///ÛÛÛÓÓÓÛÛÛÕÕÕÑÑÑÜÜÜÒÒÒééé[[[pppèèèÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÈÈÈÕÕÕÔÔÔÚÚÚØØØÏÏÏÛÛÛÔÔÔåå僃ƒYYYÿÿÿûûûÿÿÿÿÿÿÿÿÿÿÿÿþþþÿÿÿèèèøøøÜÜÜÓÓÓÕÕÕÕÕÕÕÕÕÔÔÔÞÞÞ¯¯¯///ÙÙÙÚÚÚ´´´ŸŸŸ¤¤¤¦¦¦ÓÓÓèèè[[[nnnäääÎÎÎÒÒÒÒÒÒÒÒÒÒÒÒÑÑÑÒÒÒÅÅÅÓÓÓÚÚÚÀÀÀ¦¦¦ŸŸŸÍÍÍèèè‚‚‚XXXÿÿÿ÷÷÷ûûûûûûûûûûûûúúúþþþåååôôôÜÜÜÔÔÔÕÕÕÕÕÕÕÕÕÔÔÔÞÞÞ¯¯¯...ããã¼¼¼¨¨¨þþþÿÿÿÅÅÅ¢¢¢òòòYYY{{{üüüäääèèèèèèèèèèèèèèèèèèÖÖÖÚÚÚÌÌÌôôôÿÿÿÚÚÚ™™™ììì„„„[[[ÿÿÿûûûÿÿÿÿÿÿÿÿÿÿÿÿþþþÿÿÿìììùùùÜÜÜÔÔÔÕÕÕÕÕÕÕÕÕÔÔÔÞÞÞ°°°+++×××šššæææÿÿÿýýýÿÿÿ›››×××aaaOOOEEEFFFFFFFFFFFFGGGDDDTTTÌÌ̦¦¦ÎÎÎÿÿÿùùùÿÿÿªªªÇÇÇ‹‹‹bbbXXXYYYYYYYYYYYYYYYZZZYYYYYYÄÄÄÙÙÙÔÔÔÕÕÕÕÕÕÔÔÔÞÞÞ¯¯¯,,,ÝÝÝ¡¡¡ÛÛÛÿÿÿÿÿÿøøøšššâââ\\\RRR²²²ŸŸŸ¢¢¢¨¨¨¥¥¥¡¡¡¥¥¥žžž!!!ÅÅŲ²²ÃÃÃÿÿÿüüüÿÿÿ¦¦¦ÈÈÈ¿¿¿ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒ‹‹‹"""www×××ÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÞÞÞ¯¯¯///ßßßÊÊÊšššàààííí¨¨¨±±±ñññWWW‰‰‰ÿÿÿûûûÿÿÿÿÿÿÿÿÿþþþÿÿÿùùù111ÂÂÂÛÛÛ™™™ÒÒÒñññ¸¸¸¦¦¦ÞÞÞÓÓÓÙÙÙèèèæææææææææææææææãããõõõ@@@¼¼¼éééÑÑÑÕÕÕÕÕÕÕÕÕÔÔÔÞÞÞ¯¯¯///ÚÚÚØØØÉÉɤ¤¤¡¡¡¼¼¼×××èèèXXX†††ÿÿÿëëë«««···«««ÈÈÈÿÿÿõõõ...¿¿¿ÝÝÝÑÑѨ¨¨¡¡¡²²²ÙÙÙÖÖÖÏÏÏÈÈÈÔÔÔÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÐÐÐààà888¹¹¹éééÑÑÑÕÕÕÕÕÕÕÕÕÔÔÔÞÞÞ¯¯¯///ÛÛÛÓÓÓØØØÝÝÝÝÝÝÛÛÛÐÐÐêêêXXXˆˆˆÿÿÿ­­­áááÿÿÿÿÿÿ±±±ãããÿÿÿ...ÀÀÀÚÚÚÕÕÕÝÝÝÝÝÝÜÜÜÔÔÔÖÖÖÐÐÐËËË×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÒããã888¼¼¼éééÑÑÑÕÕÕÕÕÕÕÕÕÔÔÔÞÞÞ¯¯¯///ÛÛÛÔÔÔÔÔÔÓÓÓÓÓÓÔÔÔÑÑÑéééXXXŒŒŒÿÿÿ¬¬¬ÿÿÿøøøÿÿÿÚÚÚÃÃÃÿÿÿ---¿¿¿ÚÚÚÔÔÔÔÔÔÓÓÓÔÔÔÕÕÕÖÖÖÐÐÐËËË×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÒããã888¼¼¼éééÑÑÑÕÕÕÕÕÕÕÕÕÔÔÔÞÞÞ¯¯¯///ÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÑÑÑéééXXX‰‰‰ÿÿÿ©©©õõõÿÿÿÿÿÿÂÂÂÔÔÔÿÿÿ---ÀÀÀÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÐÐÐËËË×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÒããã888¼¼¼éééÑÑÑÕÕÕÕÕÕÕÕÕÔÔÔÞÞÞ¯¯¯///ÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÑÑÑéééXXX‡‡‡ÿÿÿÖÖÖ©©©ÖÖÖÀÀÀ°°°ÿÿÿøøø///ÀÀÀÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÐÐÐÊÊÊÖÖÖÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÒÒÒâââ888»»»éééÑÑÑÕÕÕÕÕÕÕÕÕÔÔÔÞÞÞ¯¯¯///ÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÑÑÑéééYYYŠŠŠÿÿÿýýýòòòÒÒÒßßßþþþÿÿÿùùù000ÀÀÀÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÑÑÑÏÏÏÜÜÜÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚØØØèèè;;;¼¼¼éééÑÑÑÕÕÕÕÕÕÕÕÕÔÔÔÞÞÞ¯¯¯///ÚÚÚÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÑÑÑèèèYYY{{{ýýýãããìììóóóñññçççêêêããã,,,ÀÀÀÚÚÚÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÖÖÖÌÌ̺ººÁÁÁ¿¿¿ÀÀÀÀÀÀÀÀÀ¿¿¿½½½ÌÌÌ333ªªªåååÒÒÒÕÕÕÕÕÕÕÕÕÔÔÔÞÞÞ°°°,,,ÎÎÎÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÅÅÅÖÖÖppp000,,,+++***+++,,,---)))'''½½½ËËËÇÇÇÈÈÈÈÈÈÈÈÈÆÆÆÔÔÔ444...///////////////111!!!...ÁÁÁÚÚÚÔÔÔÕÕÕÕÕÕÔÔÔÞÞÞ¯¯¯///ÛÛÛÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÌÌÌÉÉÉÐÐÐÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÆÆÆÕÕÕÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓçç烃ƒWWWÿÿÿõõõùùùùùùùùùùùùøøøüüüåååòòòÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÔÔÔÞÞÞ¯¯¯///ÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÍÍÍÐÐÐÙÙÙ×××××××××××××××××××××ÉÉÉÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÒæææƒƒƒZZZÿÿÿûûûÿÿÿÿÿÿÿÿÿÿÿÿþþþÿÿÿéééøøøÜÜÜÓÓÓÕÕÕÕÕÕÕÕÕÔÔÔÞÞÞ¯¯¯///ÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÌÌÌÎÎÎÖÖÖÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÈÈÈÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÒæææƒƒƒYYYÿÿÿúúúþþþþþþþþþþþþþþþÿÿÿèèè÷÷÷ÜÜÜÔÔÔÕÕÕÕÕÕÕÕÕÔÔÔÞÞÞ¯¯¯///ÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÌÌÌÎÎÎ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÈÈÈÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÒæææƒƒƒYYYÿÿÿûûûÿÿÿÿÿÿÿÿÿÿÿÿþþþÿÿÿèèèøøøÜÜÜÓÓÓÕÕÕÕÕÕÕÕÕÔÔÔÞÞÞ¯¯¯///ÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÌÌÌÎÎÎ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÈÈÈÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÒæææƒƒƒYYYÿÿÿûûûþþþýýýýýýþþþþþþÿÿÿèèèøøøÜÜÜÓÓÓÕÕÕÕÕÕÕÕÕÔÔÔÞÞÞ¯¯¯///ÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÌÌÌÎÎÎ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÈÈÈÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÒæææƒƒƒYYYÿÿÿúúúÿÿÿÿÿÿÿÿÿþþþýýýÿÿÿèèèøøøÜÜÜÓÓÓÕÕÕÕÕÕÕÕÕÔÔÔÞÞÞ¯¯¯///ÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔ×××ÌÌÌÎÎÎÖÖÖÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÅÅÅÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÏÏÏââ €YYYÿÿÿþþþÝÝݶ¶¶¸¸¸ãããÿÿÿÿÿÿæææôôôÜÜÜÔÔÔÕÕÕÕÕÕÕÕÕÔÔÔÞÞÞ¯¯¯///ÝÝÝÖÖÖÖÖÖ×××××××××ÖÖÖÙÙÙÎÎÎÏÏÏØØØÖÖÖ××××××××××××ÖÖÖ×××ÕÕÕèèèéééééééééééééééæææûûû’’’YYYÿÿÿ×××­­­ñññííí©©©åååÿÿÿëëëùùùÜÜÜÔÔÔÕÕÕÕÕÕÕÕÕÔÔÔÞÞÞ¯¯¯---ÔÔÔÍÍÍÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÐÐÐÇÇÇÈÈÈÏÏÏÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎÎkkkmmmmmmmmmmmmmmmkkkwww;;;YYYÿÿÿ©©©òòòÿÿÿÿÿÿèè误¯ÿÿÿ¥¥¥ÌÌÌØØØÔÔÔÕÕÕÕÕÕÔÔÔÞÞÞ¯¯¯---ÒÒÒÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÎÎÎÅÅÅÇÇÇÎÎÎÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÎÎÎÉÉÉ"""cccsssppppppppppppppprrrhhh¡¡¡üüü¨¨¨õõõÿÿÿÿÿÿìì쪪ªÿÿÿBBBHHHÐÐÐ×××ÔÔÔÕÕÕÕÕÕÔÔÔÞÞÞ¯¯¯///ÝÝÝÖÖÖ××××××××××××ÖÖÖÙÙÙÎÎÎÐÐÐÙÙÙ××××××××××××ÖÖÖÙÙÙÑÑÑ///èèèÿÿÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿöööìììÿÿÿÓÓÓ³³³ûûû÷÷÷­­­ÜÜÜÿÿÿFFFºººêêêÑÑÑÕÕÕÕÕÕÕÕÕÔÔÔÞÞÞ¯¯¯///ÛÛÛÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÔÔÔÖÖÖÌÌÌÎÎÎÖÖÖÔÔÔÕÕÕÕÕÕÕÕÕÔÔÔ×××ÏÏÏ,,,äääÿÿÿúúúûûûûûûûûûúúúýýýðððèèèÿÿÿÿÿÿÒÒÒ²²²²²²ÙÙÙÿÿÿÿÿÿEEE¶¶¶éééÑÑÑÕÕÕÕÕÕÕÕÕÔÔÔÞÞÞ¯¯¯///ÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÌÌÌÎÎÎ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÏÏÏ,,,èèèÿÿÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿõõõëëëÿÿÿýýýÿÿÿÿÿÿÿÿÿþþþûûûÿÿÿEEE¹¹¹êêêÑÑÑÕÕÕÕÕÕÕÕÕÔÔÔÞÞÞ¯¯¯///ÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÌÌÌÎÎÎ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÏÏÏ,,,èèèÿÿÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿõõõëëëÿÿÿþþþýýýþþþþþþþþþüüüÿÿÿEEE¹¹¹êêêÑÑÑÕÕÕÕÕÕÕÕÕÔÔÔÞÞÞ¯¯¯///ÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÌÌÌÎÎÎ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÏÏÏ,,,èèèÿÿÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿõõõëëëÿÿÿþþþÿÿÿÿÿÿÿÿÿÿÿÿüüüÿÿÿEEE¹¹¹êêêÑÑÑÕÕÕÕÕÕÕÕÕÔÔÔÞÞÞ¯¯¯///ÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔ×××ÌÌÌÎÎÎÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔ×××ÏÏÏ,,,èèèÿÿÿþþþÿÿÿÿÿÿÿÿÿþþþÿÿÿôôôëëëÿÿÿþþþÿÿÿÿÿÿÿÿÿÿÿÿüüüÿÿÿEEE¹¹¹êêêÑÑÑÕÕÕÕÕÕÕÕÕÔÔÔÞÞÞ¯¯¯///ÚÚÚÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÖÖÖÌÌÌÍÍÍÖÖÖÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÖÖÖÎÎÎ,,,çççÿÿÿýýýþþþþþþþþþþþþÿÿÿôôôêêêÿÿÿýýýþþþþþþþþþþþþûûûÿÿÿEEE¹¹¹êêêÑÑÑÕÕÕÕÕÕÕÕÕÔÔÔÞÞÞ¯¯¯000áááÚÚÚÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÝÝÝÒÒÒÔÔÔÝÝÝÛÛÛÛÛÛÛÛÛÛÛÛÚÚÚÝÝÝÕÕÕ---èèèÿÿÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿõõõìììÿÿÿþþþÿÿÿÿÿÿÿÿÿÿÿÿüüüÿÿÿEEE¹¹¹êêêÑÑÑÕÕÕÕÕÕÕÕÕÔÔÔÜÜÜ··· ////////////////////////------/////////////////////... 333999888888888888888888666333999888888888888888777<<<***ÄÄÄÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÒÒÒ···¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯···®®®­­­­­­­­­­­­­­­­­­­­­®®®®®®­­­­­­­­­­­­­­­­­­­­­¬¬¬¶¶¶±±±ÏÏÏÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÜÜÜÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÜÜÜÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞßßßÜÜÜÞÞÞÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ( @ ÕÕÕÕÕÕÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔÖÖÖÖÖÖÖÖÖÖÖÖÕÕÕÚÚÚäääääääääääääääåååÙÙÙÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖ×××âââåååååååååäääæææßßßÖÖÖÕÕÕÕÕÕßßß­­­sssÝÝÝÍÍÍÐÐÐÏÏÏÕÕÕµµµ‡‡‡‹‹‹ŠŠŠŠŠŠŠŠŠŠŠŠJJJÇÇÇÒÒÒÏÏÏÐÐÐÑÑÑËˈ††ˆˆˆˆˆˆ†††’’’RRR£££äääÒÒÒááá§§§fffÞÞÞÌÌÌÏÏÏÌÌÌßßßsssUUU‰‰‰€€€~~~ˆˆˆÎÎÎÏÏÏÏÏÏÎÎÎÖÖÖ±±±III¤¤¤ššš››››››žžž’’’ÒÒÒÜÜÜÓÓÓááá§§§jjjæææÓÓÓÖÖÖÓÓÓçççvvv¥¥¥óóóãããååååååæææÙÙÙÖÖÖÖÖÖÖÖÖÕÕÕßßß±±±sssÿÿÿüüüÿÿÿÿÿÿÿÿÿöööñññØØØÔÔÔááá§§§iiiäääÑÑÑÔÔÔÑÑÑåååttt•••ßßßÐÐÐÒÒÒÒÒÒÒÒÒÊÊÊÔÔÔÕÕÕÔÔÔÓÓÓÞÞÞ°°°qqqÿÿÿøøøûûûûûûþþþñññïïïØØØÔÔÔááá§§§iiiäääÓÓÓÛÛÛÔÔÔåååttt˜˜˜ãããÓÓÓÕÕÕÕÕÕÖÖÖÌÌÌÔÔÔÕÕÕÚÚÚØØØÝÝݰ°°rrrÿÿÿüüüÿÿÿÿÿÿÿÿÿõõõðððØØØÔÔÔááá§§§hhhçççÌÌÌ»»»ÊÊÊééésss–––àààÐÐÐÒÒÒÒÒÒÓÓÓÉÉÉÔÔÔ×××ÀÀÀÂÂÂááᯯ¯qqqÿÿÿøøøüüüûûûþþþñññíííØØØÔÔÔááᦦ¦kkkÝÝݯ¯¯ÚÚÚ±±±ÛÛÛwww¡¡¡ïïïßßßááááááâââ×××ØØØ´´´ÎÎÎÅÅÅÁÁÁµµµqqqÿÿÿüüüÿÿÿÿÿÿÿÿÿöööñññØØØÔÔÔááᦦ¦jjj½½½ÞÞÞÿÿÿæææ¼¼¼xxx>>>jjjaaacccbbb___jjj¾¾¾¿¿¿ÿÿÿÿÿÿ»»»®®®>>>wwwqqqrrrrrrtttgggxxxÕÕÕÕÕÕááᦦ¦lllÍÍÍÅÅÅÿÿÿËËËÊÊÊxxx™™™éééÙÙÙÖÖÖÞÞÞÜÜÜYYYÁÁÁ···öööííí²²²ÑÑѳ³³¯¯¯°°°¯¯¯­­­½½½hhhäääÒÒÒááá§§§hhhççç···²²²µµµèèèsss»»»ÿÿÿÎÎÎÏÏÏßßßÿÿÿcccÉÉÉÌÌ̱±±²²²ÎÎÎÖÖÖÒÒÒßßßÞÞÞÞÞÞÛÛÛïï†¤¤¤çççÑÑÑááá§§§iiiäääÖÖÖ×××ÖÖÖææærrr½½½ØØØèèèÿÿÿÇÇÇòòògggÃÃÃÜÜÜØØØÙÙÙØØØÒÒÒÌÌÌÕÕÕÔÔÔÔÔÔÑÑÑäää~~~¢¢¢çççÑÑÑááá§§§iiiäääÑÑÑÕÕÕÑÑÑææærrr½½½×××ðððÿÿÿÌÌÌïïïhhhÄÄÄØØØÔÔÔÔÔÔÕÕÕÓÓÓÌÌÌÖÖÖÔÔÔÕÕÕÑÑÑåå壣£çççÑÑÑááá§§§iiiåååÒÒÒÕÕÕÒÒÒæææsss½½½üüüÅÅÅÎÎÎÒÒÒÿÿÿdddÅÅÅÙÙÙÕÕÕÕÕÕÖÖÖÓÓÓÏÏÏÚÚÚÙÙÙÙÙÙÖÖÖêêꃃƒ¤¤¤çççÑÑÑááá§§§hhhäääÑÑÑÔÔÔÑÑÑåååsss­­­ÿÿÿëëëåååõõõööö___ÅÅÅØØØÔÔÔÔÔÔÕÕÕÓÓÓÅÅÅÅÅÅÅÅÅÅÅÅÂÂÂÔÔÔuuušššæææÒÒÒááá§§§dddÛÛÛÉÉÉÌÌÌÊÊÊ××׋‹‹JJJ```^^^```]]]ZZZUUUÉÉÉÍÍÍÌÌÌËËËÑÑÑ···@@@fffbbbcccbbbgggPPPgggÖÖÖÕÕÕááá§§§iiiåååÒÒÒÖÖÖÕÕÕÖÖÖÓÓÓÕÕÕØØØ×××××××××ØØØÒÒÒÕÕÕÖÖÖÖÖÖÔÔÔÞÞÞ°°°rrrÿÿÿüüüÿÿÿÿÿÿÿÿÿöööñññØØØÔÔÔááá§§§iiiäääÒÒÒÕÕÕÕÕÕÖÖÖÍÍÍÐÐÐÖÖÖÔÔÔÕÕÕÕÕÕÕÕÕËËËÔÔÔÕÕÕÕÕÕÔÔÔÞÞÞ°°°rrrÿÿÿûûûþþþýýýÿÿÿóóóïïïØØØÔÔÔááá§§§iiiäääÒÒÒÕÕÕÕÕÕÖÖÖÎÎÎÑÑÑÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÌÌÌÔÔÔÕÕÕÕÕÕÔÔÔÞÞÞ°°°rrrÿÿÿúúúÿÿÿýýýÿÿÿõõõðððØØØÔÔÔááá§§§iiiäääÒÒÒÕÕÕÕÕÕÖÖÖÎÎÎÑÑÑÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕËËËÒÒÒÓÓÓÓÓÓÒÒÒÜÜÜ­­­rrrÿÿÿûûûþþþþþþÿÿÿôôôíííØØØÔÔÔááá§§§iiiåååÓÓÓÖÖÖÖÖÖ×××ÏÏÏÒÒÒ×××ÖÖÖÖÖÖÖÖÖÖÖÖÔÔÔãããããããããâââììì½½½tttÿÿÿÑÑÑÆÆÆËËËüüü÷÷÷ðððØØØÔÔÔááá§§§gggàààÎÎÎÑÑÑÑÑÑÒÒÒËËËÍÍÍÒÒÒÑÑÑÑÑÑÐÐÐÔÔÔ©©©’’’••••••”””œœœuuuqqqîîîËËËÿÿÿÞÞÞÓÓÓäää²²²ÖÖÖÕÕÕááá§§§eeeÝÝÝËËËÎÎÎÎÎÎÏÏÏÉÉÉËËËÏÏÏÎÎÎÎÎÎÍÍÍÔÔÔLLL€€€ŒŒŒŒŒŒŽŽŽƒƒƒ···ÛÛÛÖÖÖÿÿÿçççØØØ›››[[[ßßßÔÔÔááá§§§iiiæææÓÓÓÖÖÖÖÖÖØØØÏÏÏÒÒÒ×××ÖÖÖÖÖÖÖÖÖØØØ^^^ñññÿÿÿþþþÿÿÿÿÿÿûûûòòòÿÿÿÈÈÈÎÎÎÀÀÀÿÿÿžžž   èèèÑÑÑááá§§§iiiäääÒÒÒÕÕÕÔÔÔÖÖÖÎÎÎÑÑÑÖÖÖÕÕÕÕÕÕÔÔÔ×××]]]íííÿÿÿúúúûûûüüü÷÷÷ìììÿÿÿüüüðððöööÿÿÿšššžžžçççÑÑÑááá§§§iiiäääÒÒÒÕÕÕÕÕÕÖÖÖÎÎÎÑÑÑÖÖÖÕÕÕÕÕÕÕÕÕ×××]]]ñññÿÿÿþþþÿÿÿÿÿÿûûûïïïÿÿÿþþþÿÿÿûûûÿÿÿ›››   èèèÑÑÑááá§§§gggáááÏÏÏÒÒÒÒÒÒÓÓÓËËËÎÎÎÓÓÓÒÒÒÒÒÒÑÑÑÔÔÔ\\\íííÿÿÿûûûûûûüüü÷÷÷ëëëýýýûûûûûû÷÷÷ÿÿÿ˜˜˜žžžçççÑÑÑááᦦ¦pppõõõáááääääääæææÝÝÝàààåååäääääääääçççaaaðððÿÿÿþþþÿÿÿÿÿÿûûûñññÿÿÿÿÿÿÿÿÿûûûÿÿÿ›››   èèèÑÑÑßß߯¯¯333pppgggiiiiiiiiieeegggiiiiiiiiihhhjjj...vvv}}}}}}~~~{{{uuu~~~}}}}}}|||ˆˆˆIII\\\ÝÝÝÔÔÔÖÖÖÒÒÒ¯¯¯¥¥¥§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§¯¯¯¥¥¥£££¤¤¤¤¤¤¤¤¤¤¤¤¥¥¥£££¤¤¤¤¤¤¤¤¤£££ªªª°°°ÓÓÓÖÖÖÕÕÕÖÖÖßßßááááááááááááááááááááááááááááááááááááßßßáááâââáááááááááááááááááááááááááááâââàààÞÞÞÖÖÖÕÕÕ(  ÓÓÓÓÓÓÕÕÕÕÕÕÙÙÙÕÕÕÖÖÖÏÏÏÓÓÓÕÕÕ×××ÖÖÖÒÒÒÒÒÒÍÍÍÕÕÕ···§§§ØØØÑÑÑ‘‘‘–––ŠŠŠÇÇÇÖÖÖÁÁÁ¦¦¦œœœ¨¨¨ÜÜܳ³³¥¥¥âââÐÐÐ’’’ÔÔÔÒÒÒÐÐÐÓÓÓßßß···¾¾¾ÿÿÿüüüñññ××׳³³§§§ÔÔÔÊÊÊ™™™àààÝÝÝÚÚÚÒÒÒÐÐж¶¶¿¿¿ÿÿÿþþþòòò×××µµµ˜˜˜éééÌÌÌ{{{¦¦¦§§§¢¢¢ÃÃÃëëë®®®–––ÆÆÆ¼¼¼¸¸¸ÔÔÔµµµßßßÇÇÇ———ÐÐÐÒÒÒ¤¤¤µµµÜÜÜÈÈȹ¹¹¶¶¶²²²ŒŒŒØØØ³³³§§§ÛÛÛÌÌÌ¢¢¢ììì÷÷÷­­­ÀÀÀÕÕÕÔÔÔÜÜÜäääàà॥¥ÙÙÙ³³³¤¤¤ßßßÍÍÍ›››ÖÖÖÙÙÙ§§§½½½ÛÛÛÑÑѽ½½¼¼¼¸¸¸ÙÙÙ³³³¢¢¢ÚÚÚÑÑѤ¤¤¡¡¡¥¥¥ËËËØØØ¹¹¹‘‘‘½½½´´´¯¯¯ÔÔÔ³³³¦¦¦ßßßÓÓÓØØØÝÝÝÝÝÝÙÙÙÔÔÔÝÝÝ···¿¿¿ÿÿÿþþþòòò××׳³³¥¥¥ßßßÓÓÓÏÏÏÔÔÔÔÔÔÓÓÓÓÓÓÜÜܶ¶¶½½½òòòîîîôôô××׳³³¢¢¢ÚÚÚÎÎÎÌÌÌÏÏÏ××ש©©”””¦¦¦’’’···êêêÞÞÞ¯¯¯ÏÏϳ³³¤¤¤ÜÜÜÑÑÑÎÎÎÑÑÑÛÛÛŸŸŸäääÿÿÿøøøõõõåååììì«««ÖÖÖ²²²¬¬¬éééÜÜÜÚÚÚÝÝÝççç§§§çççÿÿÿûûûøøøÿÿÿþþþ­­­×××···………«««¤¤¤¢¢¢¤¤¤«««²²²ÈÈÈÀÀÀ¾¾¾ÄÄÄÁÁÁÕÕÕÓÓÓ···²²²³³³³³³³³³³³³µµµ²²²±±±±±±±±±±±±°°°¹¹¹ÓÓÓ(0` ÕÕÕÔÔÔÖÖÖÚÚÚÓÓÓÒÒÒÙÙÙÐÐп¿¿×××àààâââáááÂÂÂßßßãããåååÇÇÇØØØÞÞÞ°°°000ÑÑÑ···˜˜˜œœœ›››–––"""———™™™£££&&&ºººççç,,,ÏÏÏÉÉÉÆÆÆaaaAAA999:::777CCCÁÁÁÌÌ̈ˆˆNNNEEEFFFHHH???ÅÅů¯¯ÝÝÝëëë\\\xxx÷÷÷èèè„„„ZZZÿÿÿûûûþþþùùùÜÜÜ///[[[nnnæææƒƒƒXXXøøøüüüÛÛÛééépppÈÈÈYYY´´´ŸŸŸ¤¤¤¦¦¦äääÎÎÎÀÀÀÍÍÍ‚‚‚úúúôôô...¼¼¼¨¨¨¢¢¢òòò{{{ììì+++šššýýýOOOGGGDDDTTTªªª‹‹‹bbbÄÄÄ¡¡¡RRR²²²¥¥¥žžž!!!ÃÃÃwwwÊÊÊííí±±±ñññWWW‰‰‰111¸¸¸õõõ@@@†††«««888¹¹¹êêê­­­ËËËŒŒŒ¬¬¬---©©©‡‡‡»»»ŠŠŠ;;;óóó½½½333***)))'''444€€€¶¶¶’’’kkkmmmcccsssrrrhhhBBBööö³³³ððð 666<<<®®®        !"#$%&&&&&'()*+,,,,,-./0&&&& 1234555556789: ;<=> ?@ABCBBBBDB;EF9G?HI%'JKLBMNNNNCB>F9GOPHQ?RJKSBCBBBBDB?MF9GOPHQ?RJKSBCBBBBDB?MF9GOPHQ?RJKSBCBBBBDB?MF9GOOFPHQ?R%OKSBCBBBBDB?MF9GTUVW?HIXY8ZWU[?\LB>CCCC]D^F9_`aDB8bcSdNX??????0^Be@HBCBBBBDBeEFf gJBhB (ij45555klm0WYBEBnopqLSSSSSASSr9$:sOBBMg F9GO 0Y RJKSBCBBBBDB?MF9GO 0Y RJKSBCDhhDDB?MF9GO 0Y RJKSB]BBBDhB?MF9GO 0Y8% ŸSBD: ƒBBJ^F9G: Y%  ?PPPPPJC¡SB ‹}B;EF9[YYYYYR%YYYYYYYz¢£££££¢{”SBcBB?9Bvz09000000Y8Y00000Y&¤¥QQQQQ¦§sNa„BBenB¨6 9G: Y G?BDBBBBB©eBªC>‹FB5"Š9GO0Y %$XB]CCC]h«?BBuuBB4 P9GO 0Y %$?BDBBBBB„;BhBBBDCB4‰Š9GO 0Y %$?BDBBBBB„;BDhDDDNB4‰Š9GO 0Y %$?BDBBBBB„;BDBBBBNB4‰Š9GO 0Y %$?BDBBBDB^;BDBBBBNB4‰Š9G0[Y$#BhDDDDB^ŠBhDDDDCB4‰Š9 OOOOO::OOOO:?BDBBBBB„eBDBBBBNB4‰ŠF¬GGGGGGGGGGGGGGG_­—+ˆˆˆˆˆˆ®—+ˆˆˆˆˆ-¯2™r999999999999999999°‹‹‹‹‹‹‹°°‹‹‹‹‹‹‹Ž ~%FFF( @ÕÕÕÖÖÖÔÔÔÒÒÒÚÚÚäääåååÙÙÙ×××âââæææßßß­­­sssÝÝÝÍÍÍÐÐÐÏÏϵµµ‡‡‡‹‹‹ŠŠŠJJJÇÇÇÑÑÑËˈ††ˆˆˆ’’’RRR£££ááá§§§fffÞÞÞÌÌÌUUU‰‰‰€€€~~~ÎÎα±±III¤¤¤ššš›››žžžÜÜÜÓÓÓjjjçççvvv¥¥¥óóóãããÿÿÿüüüöööñññØØØiiittt•••ÊÊʰ°°qqqøøøûûûþþþïïïÛÛÛ˜˜˜rrrõõõðððhhh»»»ééé–––àààÉÉÉÀÀÀ¯¯¯ííí¦¦¦kkkwww¡¡¡´´´ÅÅÅÁÁÁ½½½¼¼¼xxx>>>aaacccbbb___¾¾¾¿¿¿®®®ggglll™™™YYY···²²²³³³èèèòòòÃÃ⢢ÄÄÄdddêêꃃƒëëëuuu```^^^]]]ZZZ@@@PPPýýýúúúôôôìììÆÆÆ÷÷÷©©©”””œœœîîîeeeLLLŒŒŒŽŽŽ[[[ÈÈÈ   \\\ppp333...}}}{{{|||ªªª    !"#$$ %&'()*++,-./00123 !4 3356789  , :;:::<=> !?@A B3#CD:EFFG=H> !?3I@J93$>CK:;:::LM> !N5$OBP QR3STU VD:E;FG=W> XYV,IZ[H >\+]^D:;:::<=> X4_#: `ab4cdef4gh::OibZDKK@ja Xk]:BalP#2m^nr:sjt2>>$*u5 !? K_M:$HNv>3$'5 !? _;]+:w]3xy.5 !N :zL3]]]]U{/  !wIS$B|}|~%S$n€"edejj !?3>>#CK:;:::<=> !?#CK:FG‚:8H> !?+$#CK:ƒ:‚:LM> !?+332 K:FGG:„W> !?3999 …_@:†;‡M> !jR+ˆAA‰Š{D‹:#3o !Œ++S++(ŽynI:5>0‘  !? 3>>}=:G::Fs:’+T:1“r !?+~W:ƒF;‡…:;M<:/15 !?+~=:G::FH:G:F:0“r !j 3+3”W:FF;‡z‚FF‡:J15 X•L  R5cM:G::F=:::F:0“r V–•j???Œj???N4—6'˜˜*™{*˜˜š-”V7!!!!!!!!!!!V7....7...›C3 R#( ÓÓÓÕÕÕÙÙÙÖÖÖÏÏÏ×××ÒÒÒÍÍÍ···§§§ØØØÑÑÑ‘‘‘–––ŠŠŠÇÇÇÁÁÁ¦¦¦œœœ¨¨¨ÜÜܳ³³¥¥¥âââÐÐÐ’’’ÔÔÔßßß¾¾¾ÿÿÿüüüñññÊÊÊ™™™àààÝÝÝÚÚÚ¶¶¶¿¿¿þþþòòòµµµ˜˜˜éééÌÌÌ{{{¢¢¢ÃÃÃëëë®®®ÆÆÆ¼¼¼¸¸¸———¤¤¤ÈÈȹ¹¹²²²ŒŒŒÛÛÛììì÷÷÷­­­ÀÀÀäää›››½½½¡¡¡ËËË´´´¯¯¯îîîôôôÎÎΩ©©”””êêêÞÞÞŸŸŸøøøõõõååå«««¬¬¬çççûûû………ÄÄı±±°°°    !"#$%&'()*+,-. /012345*678*9:&;<  =-/>?@AB#8C D= D45E/% 8F6G : DHI $$$'()&D)JK/%L-MNOPI8 L =QBRST>U;V,%$W WXR(@YU8/8UZ;9A[\;*;]]]]^:(0`€€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿw÷÷÷ÿ÷÷÷÷÷÷÷÷÷ÿ÷÷ÿˆ÷÷÷wÿÿpÿ÷÷÷ÿ÷wÿp÷ˆÿ÷÷÷w÷€÷÷÷øwww÷÷÷÷÷ÿÿ€÷÷÷øÿ÷ÿÿ÷÷÷ÿwÿÿÿÿÿ÷ˆ÷÷÷÷wÿ÷÷ÿÿÿÿÿÿ€ÿÿ÷ø÷÷÷÷÷÷÷ÿÿÿÿ÷p÷÷ø÷÷÷÷÷ÿÿÿÿÿ÷ˆ÷ÿ÷ø÷÷÷÷÷÷ÿÿÿÿÿÿ€ÿwÿø÷÷÷ÿwÿÿÿÿÿ÷€÷÷‡w÷÷÷w÷w÷w÷÷ÿÿÿÿÿÿˆ÷w÷øÿÿÿx÷wwÿÿÿÿÿ÷€÷ÿ÷øÿÿ÷ÿÿwÿ÷÷ÿÿÿÿÿ÷p÷ÿø÷÷ÿø÷€øÿøøwwwˆ÷ÿ÷÷wwwxw€ˆÿwÿ‡øÿÿÿÿp÷w÷wÿ÷ÿÿpÿˆÿw‡÷÷ÿxÿpw‡÷÷÷p÷€÷ø÷ÿøˆ÷ÿ÷÷÷÷pÿ€÷÷÷÷øwÿÿp÷÷÷÷÷÷÷ÿ÷pÿpÿøwÿÿpp÷ˆ÷÷÷w÷÷ÿ÷ˆ÷÷÷ÿ÷ÿðÿ€ÿÿ÷ø÷wwÿp÷÷÷÷wp÷€÷øÿ÷ÿp÷ÿ÷÷ÿwpÿˆ÷÷÷÷øÿÿÿÿx÷÷÷÷ÿ÷ÿp÷€ÿÿw€ÿ÷w€€p÷÷÷÷‡‡www‡÷÷÷÷÷w‡ww€÷÷÷ÿÿÿÿÿÿ÷÷÷wÿÿÿÿÿ÷ˆ÷w÷ww÷÷÷÷ÿÿÿÿÿÿˆÿ÷÷÷÷ÿ÷÷÷÷÷ÿÿÿÿÿ÷€÷÷÷÷÷÷÷ÿÿÿÿ÷ÿ€ww÷÷÷ÿÿ÷÷÷ÿÿÿÿÿ÷ˆÿÿ÷÷÷÷÷÷÷wÿÿÿÿÿÿ€÷÷ÿÿ÷÷÷÷÷ÿ÷ÿÿ÷ˆ÷ww÷÷ÿ÷÷ÿ÷÷÷÷÷wwÿÿÿˆÿ÷÷÷÷÷÷ÿÿÿÿ÷÷ÿ÷ÿ÷€÷÷÷÷pwÿÿp‡€÷÷÷÷÷÷p‡wwx‡wÿÿðˆ÷÷÷÷pÿÿÿÿÿÿ÷÷p÷ˆÿ÷÷÷÷ÿ÷ÿ÷xÿÿÿÿÿÿÿwwÿðÿ€÷÷ÿwpÿÿÿÿÿÿÿÿÿÿð€÷÷÷÷ÿ÷÷€ÿÿÿÿÿÿÿÿÿpÿˆ÷ÿ÷÷ÿpÿÿÿÿÿÿÿÿÿÿð÷€ÿ÷÷÷÷xÿÿÿÿÿÿÿÿÿÿðÿp÷÷÷÷÷ÿ€ÿÿÿÿÿÿÿÿÿÿp÷€÷w÷wÿ÷w÷ˆÿÿÿÿÿÿÿÿÿÿðÿˆÿÿÿÿÿÿÿ÷ÿpÿÿÿÿÿÿÿÿÿÿp÷p€€€€€€€€€‡xxˆˆxw‡ˆˆˆˆ‡ˆˆˆˆxˆˆˆˆˆˆ‡( @€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿw÷wwÿÿw÷wˆ÷wˆˆˆ€wwˆˆˆˆxw÷ˆˆˆˆw÷wˆ‡x‡wˆ÷wwÿÿ÷÷÷ˆÿÿÿ÷xwÿ‡÷wwww‡ÿÿÿÿˆwww‡w‡ÿÿÿ÷ˆ÷w‡w÷wwwwˆÿÿ÷÷ˆ÷‡wÿ÷÷÷w‡ÿÿÿ÷xwÿ‡x‡‡wÿwˆwwˆwˆwÿwˆˆx€‡ÿwxˆˆˆ‡x÷wwÿÿøwwwww÷ø€÷w÷wwðww÷wøˆ÷÷w÷ø‡÷÷÷wxxw÷÷ø÷wwwÿøˆww÷÷øw÷øˆÿ÷w‡÷÷ðww‡xxxwwwˆ€ˆ€ww€ˆˆ‡pÿwÿw÷ww÷‡ÿÿ÷÷p÷÷www÷÷ww‡ÿÿ÷ÿxw÷÷w÷ww÷÷ˆÿÿÿ÷x÷÷ww÷w÷‡ÿÿÿÿp÷w÷÷÷wwˆ÷ÿwˆ÷wwww‡÷÷ÿ÷p÷wÿwxˆ÷w‡p÷ÿwwxÿw÷øx÷wwwxÿÿÿÿ÷w÷x÷ww÷ðÿÿÿÿÿ÷p÷wwÿwxÿÿÿÿÿÿøxwwwwxÿÿ÷ÿÿ÷‡xÿ÷ÿøÿÿÿÿÿ÷pˆ€ˆ€€ˆˆˆˆˆˆˆ‡w‡‡wˆww‡ˆxˆ‡ˆ‡ˆ‡( €€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿwwwww÷‡‡xxww‡wwwÿ÷xwwÿwÿ÷x÷ˆxxwwxwwwww‡wwøw÷wxÿ‡www‡÷wxwxwwxwwwÿw÷wwwÿÿ‡÷ww‡‡wwx÷÷wÿ÷ww÷wÿÿxx‡ˆwww‡wwwwww‡wpuzzles-20170606.272beef/icons/flood.ico0000644000175000017500000006117613115373731016615 0ustar simonsimon 00 ¨%–  ¨>& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÑÒÑÐÒÐÐÒÐÐÒÐÐÒÐÐÓÐÐÒÐÒÑÑÓÑÑÒÑÑÒÑÑÒÑÑÒÑÑÑÑÑÐÓÓÐÒÒÐÒÒÐÒÒÐÓÓÐÒÒÒÑÑÒÑÑÒÑÑÒÑÑÒÑÑÒÑÑÑÑÑÐÑÓÐÑÒÐÑÒÐÑÒÐÑÓÐÑÒÐÒÐÐÒÐÐÒÐÐÒÐÐÒÐÐÒÐÒÓÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÕÔäáäêàêéàééàééàééßééâéáçèßæçàççàççàæçßçèçååêßßéààéààéààéßßéããáçèßæçàççàççàæçàçèèçåêäßéåàéåàéåàéäßéæãéáêéßééàééàééßéëáëáßáÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÒÏÒl™lqšqpšpp™ppœppŽp“xw›}y™|xš|x™}y›zvyƒ‚nœœp™™pššp™™pœœp”xu›}y™|xš|xš}y›{ux{ƒn†œp…™p…šp…™p†œp‹p”mp›qp™ppšprœrg‘g«²«áßáÒÓÒÕÕÕÕÕÕÕÕÕÕÕÕÕÙÕÕÅÕ+}+õíïìü®È&ø?#í:!ï;"í>%÷,6hbüýìëïïììýý¦¦Ï%ö@&í:!î;"î<%ô4.:jtþnëoïnëtþPÎ÷íîóÞp—péàéÐÒÐÕÕÕÕÕÕÕÕÕÕÕÕÕÙÕÕÅÕ/…/ÿþÿüÿºÖ8/ÿU9ýO7ÿP7ýS;ÿA(=uoÿÿüüÿÿüüÿÿ³³Ý8"ÿV<ýP7ÿP7þR;ÿH&5HwŠÿƒû„ÿƒûŠÿ`©Üÿýÿÿïr›réàéÐÒÐÕÕÕÕÕÕÕÕÕÕÕÕÕÙÕÕÅÕ,ƒ,ÿýÿüÿ¹Õ3+ÿQ5üK2þL3ýO7ÿ=#:rlÿÿûûÿÿûûÿÿ±±Ü3ÿQ8ýK3þL3þN7ÿD"1Dt†ÿ~û€ÿû†ÿ\§ÛÿýþÿîpšpéàéÐÒÐÕÕÕÕÕÕÕÕÕÕÕÕÕÙÕÕÅÕ,ƒ,ÿüýúÿ¸Õ3+ÿQ5ýK3ÿL3ýO7ÿ=#:qlÿÿúúýýúúÿÿ±°Ý3ÿR8ýL3ÿL3þN7ÿD"2Dt…ÿ~úý~ú…ÿ[§Úÿüýÿíp™péàéÐÒÐÕÕÕÕÕÕÕÕÕÕÕÕÕÙÕÕÅÕ-ƒ,ÿþÿüÿºÖ4+ÿQ5ýK3ÿL3ýO7ÿ=#=rmÿÿüüÿÿüüÿÿ²²Ý4ÿR8ýL3ÿL3þN7ÿD"2Gtÿ…û‡ÿ†ûÿ`¨ÛÿýÿÿïqšpéàéÐÒÐÕÕÕÕÕÕÕÕÕÕÕÕÕØÕÕÇÕ,x,äÞßÜë¢Õ5+ÿQ5ýK3ÿL3ýO6ÿ?%:faêíÜÞßàÜÝìÝ5ÿQ7ýK3ÿL3þM7ÿG$28ifòaàbäaàgòG–ÁæÝÞãÎp”péáéÐÒÐÕÕÕÕÕÕÕÕÕÕÕÕØÖÖÊÑÓe?7©4§;#¨:"¨:"¨:"§7!ñG0ÿM4þL3ÿL3þL3ÿL3»;(£9)©:)¨:)¨:)§:*©8'óH0ÿM4þL3ÿL3þO3ÿA42V ´©«©¶r–)¬>#§9!§:!¬>&—(‹yuãçèÒÑÑÕÕÕÕÕÕÕÕÕÕÕÕÙÖÖÅÐÒƒG>ÿJ1þP8ÿO6ÿO6ÿO6ÿO6ÿM4ÿL3ÿL3ÿL3ÿL3ÿL3ÿO5ÿO4ÿO4ÿO4ÿO4ÿO4ÿO5ÿM4ÿL3ÿL3ÿL3þP3ÿ;42y ÿüÿüÿªä60ÿT8ýN6ÿO6ÿS:ï=%š}yàæçÒÑÑÕÕÕÕÕÕÕÕÕÕÕÕÙÖÖÅÐÒ‚F=ÿG,úM4ûL2ûL2ûL2ûK2þL3ÿL3ÿL3ÿL3ÿL3ÿL3üK3ûL3ûL3ûL3ûL3ûL3ûK3þL3ÿL3ÿL3ÿL3þP3ÿ<42x ÿøüøÿ¨à4-ÿQ4úK2ûL2ÿP6ë:!™|xàççÒÑÑÕÕÕÕÕÕÕÕÕÕÕÕÙÖÖÅÐÒƒF=ÿH-þM4ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3þP3ÿ;42y ÿüÿüÿªä4.ÿR4ýL3ÿL3ÿP7ï;"š|xàççÒÑÑÕÕÕÕÕÕÕÕÕÕÕÕÙÖÖÅÐÒƒF=ÿH-þM4ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3üL3ûL5ûL5ûL5ûL5ûL5ûL4üK3ýK3ýK3üK3üO3ÿ:41w ÿøû÷ÿ§à5-ÿS4ùM2úM2ÿQ6ëp([ys‚çéåÑÐÑÕÕÕÕÕÕÕÕÕÕÕÕÙÖÖÅÐÒƒF=ÿH-þM4ÿL3ÿL3ÿL3ÿM4ÿG&ÿE#ÿF#ÿF#ýG'ÿ?:BeŠÿƒó„öƒóŒÿ]«Ý:ÿP8ýK3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿM3ÿO%ÿO#ÿO#ÿN#ÿS'ï=š}vàæèÒÑÑÕÕÕÕÕÕÕÕÕÕÕÕÙÖÖÅÐÒƒF=ÿH-þM4ÿL3ÿL3ÿL3ÿL3ýM6ýN7ýM7ýM7üO:ÿG'9Bm„ÿ~üÿ~ü‡ÿY±Ý;ÿP8ýK3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3þL3ýK6ýL7ýK7ýK7ÿP;í:%™|yàççÒÑÑÕÕÕÕÕÕÕÕÕÕÕÕÙÖÖÅÐÒƒF=ÿH-þM4ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ýM7ÿF#:Bl…ÿû€ÿ~û‡ÿZ±Ý;ÿP8ýK3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3þL3ÿP7ï;"š|xàççÒÑÑÕÕÕÕÕÕÕÕÕÕÕÕÙÖÖÅÐÒƒF=ÿH-þM4ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ýM7ÿF#:Al„ÿ~úý}ú†ÿY°Ý;ÿP8ýK3ÿL3ÿL3ÿL3ýL3ýK3ýK3ýK3ýK3ýK3ýK3ýK3ýK3ýK3üK2ÿO7í:!™|xàççÒÑÑÕÕÕÕÕÕÕÕÕÕÕÕÙÖÖÅÐÒƒF=ÿH-þM4ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ýN7ÿE#/ÿQ7ùP8ÿA'V|tÿÿ÷öÿÿÒÒÔ@+ÿP7øN8ÿK)eIhƒÿ÷…ÿjÝÈ ÿøÿEµDäÒäÑÖÑÔÙÔÚÇÚ0£0ÿûÿÉà<-ÿP4úO6ÿ?$T|tÿÿúúÿÿÔÔÕ>)ÿO5ùL6ÿI&cIh‡ÿƒû‰ÿmàËÿûÿB¶BäÒäÑÖÑÔØÔÙËÙ3‹0Î ÆÒ  á=-ÿO4úN5ÿC(Xh_ÒÓ ÆÅÑШ§Ö?*ÿO5ùL5ÿK*cAVkÐiÄnÍX° Ò ÇÊEžCäÖäÒÕÑØÕÕÉÕÖ–KDç6&ß=.à;-á=-ûK2ÿL3þL3ÿM4êC,Þ:%á<&à;%à='úK2ÿL3ûN2ÿC6cfåÚãÁ°4#ë=/Ý>/ã2#¨]WÔàáÕÒÒÙÖÕÇÔÖ£THÿK.ýQ6ÿP4ÿO4ÿL3ÿL3ÿL3ÿL3ÿN5ÿP6ÿO6ÿP6ÿO6ÿL3ÿL3ûN2ÿA6crÿûÿÞÈD)ÿQ7ûQ6ÿH+¶fZÒÞàÖÓÒÙÕÕÇÔÖ£RGÿG,ûM4ýL3ýL3ÿL3ÿL3ÿL3ÿL3üL4úM6úM6úM6úL5þK4ÿK4úM4ÿ@8cpÿöÿÚÄC'ÿQ4öP4ÿG(´fYÒÞàÖÓÒÙÕÕÇÔÖ£RGÿG-ýM4ÿL3ÿL3ÿL3ÿL3ÿL3ÿL4ÿL.ÿG#ÿH%ÿG$ÿI'ÿQ/ÿQ-ûS-ÿF0csÿûÿßÈ7*ÿ@9ûA8ÿ6,¶_[ÒßàÖÓÒÙÕÕÇÔÖ£RGÿG-ýM4ÿL3ÿL3ÿL3ÿL3ýL4ÿL.Œ=CIKyWJrTMxTCcŽ:œE—C¤A<%;WeSbWfFWBcX‚U|Mxh{JÞÛãÓÔÒÙÕÕÇÔÖ£RGÿG-ýM4ÿL3ÿL3ÿL3ÿL3üM6ÿG$TLtˆÿ‚ú‰ÿnÔ’n¶‹«†»DˆÿüÿàÈÿûÿB¶BäÒäÑÖÑÙÕÕÇÔÖ£RGÿG-ýM4ÿL3ÿL3ýL3ýL3úM6ÿG%VJr‚ÿ|õƒÿiЖh¹‚¯¿wFƒÿöÿÛÄÿöÿD´CäÒäÑÖÑÙÕÕÇÔÖ£RGÿG-ýM4ÿL3ÿM3ÿO5ÿO5üP8ÿJ&TNu‰ÿƒúŠÿoÔ›mÁе†Æ~HˆÿüÿàÈÿûÿB¶BäÒäÑÖÑÙÕÕÇÔÖ£RGÿG-ýM4ÿM3öI1Ó>)Õ?)Ò?,á;F>`nßiÏoÛY¯{X™nkžd:oÚÒÚ»¦ßÒÖB£BäÕäÑÕÑÙÕÕÇÔÖ£RGÿG-úM4ÿO4È>-[¹nÛhÓqÒ#˜ÔÑÛ°°5"ÜB+Ò?*Ó?*Ô?*Õ?)Ó?)ÛA+»8§ÞÒÖBB£ääÕÑÑÕÙÕÕÇÔÖ£RGÿG-úM5ÿO4È?.s߉ÿ‚þý,·ÿýÿÔÕB+ÿR7ýN5ÿO5ÿO5ÿO5ýN5ÿQ8àE'ÉÿûÿBB¶ääÒÑÑÖÙÕÕÇÔÖ£RGÿG-úM5ÿO4È?.mÚ‚ÿ|ù†÷*µþûÿÓÓ?)ÿN5ûK3ýK3ýK3ýK3ûK3ÿM6ßB& ÅÿöþDC³ääÒÑÑÖÙÕÕÇÔÖ£RGÿG-úM5ÿO4È>.r߈ÿþŒý+·ÿýÿÔÕ?)ÿO5ýK3ÿL3ÿL3ÿL3ýK3ÿN6àC&ÉÿûÿBB¶ääÒÑÑÖÙÕÕÇÔÖ£RGÿG-ûM4ÿN4ÚB.OCgUMwSJuYLn)n(½*µ,¾#™Õ?)ÿO5ýK3ÿL3ÿL3ÿL3þL3ÿM5êF,X_SyVtM ohNwÞâÜÓÒÓÙÕÕÇÔÖ£RGÿG-ýM4ÿL3ÿM3ÿI'ÿG$üI(ÿCTLnŒÿ†÷ÿqÒÕ?)ÿO5ýL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿM4ÿP(ÿQ$þR'ÿI¶gSÒÞáÖÓÒÙÕÕÇÔÖ£RGÿG-ýM4ÿL3þL3üM6üM6øN9ÿI(SJuÿ|ù‚ÿhÓÕ?)ÿO5ýL3ÿL3þL3ýL3ýL3ýL3ýK3úK5úK6ùL8ÿC,´d[ÒßàÖÓÒÙÕÕÇÔÖ£RGÿG-ýM4ÿL3ÿL3ÿL3ÿL3üM6ÿG$UMtˆÿ‚ú‰ÿnÔÕ?)ÿO5ýL3ÿL3ÿN4ÿO6ÿO6ÿO6ÿO6ÿO4ÿP4þQ7ÿH+¶fZÒÞàÖÓÒÙÕÕÇÔÖ£RGÿG-ýM4ÿL3ÿL3ÿL3ÿL3üM6ÿI'TDhqëmÚsç\ºÕ?)ÿO5üK3ÿM4ìE-Þ>%á?&à?%à@&à=-à;-à>/ã2#¨]WÔàáÕÒÒÙÕÕÇÔÖ£RGÿG-ýM4ÿL3ÿL3ÿL3ÿL3þL3ÿM3ÚB.Ä>-È?.È?.Ç>-öI1ÿM3ûL5ÿK*g@VgÑ eÆjÎT± Ò ÇÊEžCäÖäÒÕÑÙÕÕÇÔÖ£RGÿG-ýM4ÿL3ÿL3ÿL3ÿL3ÿL3ÿL3ÿN4ÿO4ÿO4ÿO4ÿO4ÿM3ÿL3ûM6ÿI&cJhˆÿ„û‹ÿnàËÿûÿB¶BäÒäÑÖÑÙÕÕÇÔÖ£SHÿH.ûN6ýM4ýM4ýM4ýM4ýM4ýM4ûM4úM5úM5úM5úM4ýM4ýM4ùN7ÿJ(dIhÿ~ö„ÿiÝÈÿ÷ÿD´DäÒäÑÖÑÙÕÕÇÔÖ£PDÿC&ýI.ÿG-ÿG-ÿG-ÿG-ÿG-ÿG-ÿG-ÿG-ÿG-ÿG-ÿG-ÿG-ÿG-ûH0ÿD cFe‚ÿ~û„ÿiàËÿûÿB¶BäÒäÑÖÑ×ÕÕÏÕÖˆc^¤MA£SH£RG£RG£RG£RG£RG£RG£RG£RG£RG£RG£RG£RG£RG¢SH«QA]P_(k©2i¢0l§0`–0Œ30¨/2£2&¢&a–aà×àÒÔÒÕÕÕÖÕÕÏÕÖÆÔÖÇÔÖÇÔÖÇÔÖÇÔÖÇÔÖÇÔÖÇÔÖÇÔÖÇÔÖÇÔÖÇÔÖÇÔÖÇÔÖÇÔÖÈÔÖÆÔ×ÒÔÒÛÐÆÙÐÈÚÐÇÚÒÉÚËÙÚÆÚÙÈÙÚÆÚ×Ï×ÔÕÔÕÕÕÕÕÕÕÕÕ×ÕÕÙÕÕÙÕÕÙÕÕÙÕÕÙÕÕÙÕÕÙÕÕÙÕÕÙÕÕÙÕÕÙÕÕÙÕÕÙÕÕÙÕÕÙÕÕÙÕÕÙÕÕÖÕÖÔÖÙÔÖÙÔÖÙÔÖØÔØÔÔÙÔÔÙÔÔÙÔÕ×ÕÕÕÕÕÕÕ(  ÕÖÕØÏØÚÊÙÓÒ×ÊÖÖÐÓÔÙËËØÍÍÍÕÖËÕ×ÖÓÐÙÒÊØÐÓÙÊÚØÏØÕÖÕÒÉÒI¿Eè!}‰=öRJ se!áá4ÈÇÉ_Pç[CNs£!„ð.™z&ãNÇNØÏØÒÅÒ%Ó"ÿs†ÿ3'¥fQÿÿ äãáG2ÿB4^®oÿ™tÿ)Ü-ÙËÙÌËÑx€4m‹³_(ÿG3ÍT?jŠy}sëL5ÿD07}N®q2:y… y‹<ÓÒ×ÅÏÏÕNHÿ;2ýI6ÿM4ÿK/ÿ>ÿA þT0ÿC2:¶ ÿgŠÿ$8ÚUQËÖÖÅÎÏÓYEÿL-ùM4ÿL2ßI9ŸO[§LTÈ5;Ô):.x1´;Du)°a›uAÐÓ×ÅÎÏÕWEÿI.úN6ÿL*©MV„ÿtå—~´x#Àÿduÿ)Ú-ÙËÙÅÎÏÕWEÿI.éI5îF-˜FRsð eÑ•o±i(ªû\kõ,Æ2ØÍØÅÎÏÒXHÿF!jS}~ó MÃéÓÌ<2íE0ÞB6òH)l$qñ/0ÆØØÍÅÎÏÒXHÿEdY‰ŽÿUÙøââE4ÿP3ùL6ÿT$w&{ÿ-*ÛÙÙËÅÎÏÔWFÿI,ÈIC®NTtDeSà MÃáE3ÿM2÷K6ÿN5ËA@Ÿ.RŸPeÐÖÔÅÎÏÕWEÿI/úM3ÿI!©NPŽÿ ãâG4ÿM3ýJ+ÿI#þJ-ÿ?(ÞZJËÕÖÅÎÏÔWFÿI/÷M6ÿM3ÈICZXjS}ëI5ÿK/’N^qTˆwbGpˆ {‡>ÓÒ×ÅÎÏÕTBÿE)ýI/ÿI/ÿI,ÿEÿE!þK1ÿC 6h®€ÿ tÿ)Ü-ÙËÙÉÏмcVÚSAÔWFÖWEÔWFÑXIÒWHÔXGÚS;Ji›xé)sÛ FÀGØÏØÕÕÕÉÏÐÄÎÏÅÎÏÅÎÏÅÎÏÅÎÏÅÎÏÅÎÏÄÎÐÏÌÉÒËÃÒÊÌÒÃÓÒÉÒÕÖÕ(0` ÔÔÔÕ×ÙÙÖÖÕÙÕÌÑÒÒÑÎÒÏÒéãáéßééàéáæçßæçáßáêßßêäßl•kpšppŽp—zvš|xuˆˆpšštw‡p…šp•p«²«ÕÅÕ,y*þîãµÉ$üC)í;#÷,8gbýýìí¦¦ú:09jtþnì~üPÍöÜ-„-ÿºÕ4+ÿR9þ>#p;mjURÿ@÷J%Õ9Cz…C7=CT+X…,KeÕÍÄÕÏÊ       !"###$%&'''&(!"###)*+,,,-./0123345666678&&&&&9:6;<6=>?????@1333 2456A<678&&&&&9B6<<6C>?--??D1 245E<<67%&&&&&9B6<<;C>?---?D13 245<<<678&&&&&9B6<<F-??FD133 11G5EF??|F@10^_H<<<<<<<<<<<?---?D13^_H<<<<<<<<<<<<<<<<<<<<<<?-?-?1^_H;<<<<<<<<<<<<<<<<<<<<<6C>?---?D13^_CH?---?130§¬_______________________¬­®®®®®¯2222[^^^^^^^^^^^^^^^^^^^^^^^^^°°°°°±( @ÙÕÕÓÔÓÌÕÖÔÙÔÞÛãäÓääÒÒÞâÜÔÖÙÒÞàÞÝÝäÛÒáØá×Ï×a–a;¶;CµCB»BDžD¨]WµfZº_Wh{w;¼¼C··B¢¢£^UºfWocq1t²C~·Br¨r§rÚÇÚ1£1þ÷ ÇÛ:$ÿG-ÿ;(U{sþþÓÓöI1dIh}ûƒþfàÊÙÊÙà=.þQ6üP8ÿD÷öØA)øM8ÿJ+Šÿ†÷sßÞ>/þM4Ô?)ÿI&réÓ2Œ2  Xh_ ÆÅ¨§eAVkÓgÅkÎY¯¢–KDã4$àC&ëE,à=&ÿC4cfäݰ5#ë=/ÔàáÇÔÖ£SHcrÆD(öP4£RGÿF$þQ,Æ<,þ@8Œ=CLGpULtTMxUHjŽ:šD¤A<%;VdFWBcX‚Qz h{J“k·†«†½{F†þà~öžd¯Æ~öÛÈ šnÁŠF>`mÜgÑ{X:oÓ¶B£BÈ?.YµqÒ#™ÛB-»8§BB£ääÓ+¶ÈCBµ)n*¾X_UwM ohNwÿR&làˆc^¤MA«QA1k¥0`–0¨/&¢&ÚÑÉÛÐÇ      !"#$#%&''()***+&',(-../01#$#2"#$#%3456)*7*+849:-;4?()***+@??A-;//BC### D1%CE34,AF+G+H@?,:IJKLMNC%1OPQ33????R&SSS???TUVWVNXY3PZ[\'444?????9?9????T]###W^45: [\'??'??????9?????(]#$#W^4_: [`'??'????'aAA:b4_T]###WcdT( [`'??????:efghijkklmnnnopqrrs[`'??????ag;/;Jtuvwxyyyz1#$#[`'??????Ag/{/L|}}~xyy€#$#[\'????44ag;<;J‚uuƒxyyyz### [\'?:,@@8&„…†…M‡‚t|ˆ€‰€ŠNVCC‹[`',4Œ…†Ž‰‰‰ŠX@@@@8‘’z‰‰“”[`'?4^B;/;•yyy‰84?4?4?4Q–yyy—” [\'?4Œ…/.<•yyy‰@?'???T?Q–yy—”[\'9?Œ=;/;•yyy‰@4??????Q–yy—”[\'9?8ihhi˜™•™@???????Rš››œ[`'???aa:6i;<;Ž@????????:žž6Z[\'?????9:g/<.†@?????????99a [`'??'???Ag;/;J@?????4??444: [`'?'????AiB…B@???R&QSS>3>P[`'???????ŒŒ^^,??:I†KLEC%1‹ [\'????????4??9???A-;<;Ÿ1#$#[\'5????????999??9:-.{/…#$#[`a''T''''''''''''a-/./Ÿ1### ¡\```\````\````\¢I££¤D¥"¦ [[[[[[[[[[[[[[[[[§§¨§2!!!( ÕÖÕØÏØÚÊÙÓÒ×ÊÖÖÐÓÔÙËËØÍÍÍÕÖËÕ×ÖÓÐÙÒÊØÐÓÙÊÚÒÉÒI¿Eè!}‰=öRJ se!áá4ÈÇÉ_Pç[CNs£!„ð.™z&ãNÇNÒÅÒ%Ó"ÿs†ÿ3'¥fQÿÿ äãáG2ÿB4^®oÿ™t)Ü-ÙËÙÌËÑx€4m‹³_(ÿG3ÍT?jŠy}sëL5ÿD07}N®q2:y… y‹<ÅÏÏÕNHÿ;2ýI6ÿM4ÿK/ÿ>ÿA þT0ÿC2:¶ gŠÿ$8ÚUQËÖÖÅÎÏÓYEÿL-ùM4ÿL2ßI9ŸO[§LTÈ5;Ô):.x1´;Du)°a›uAÐÓ×ÕWEÿI.úN6ÿL*©MV„ÿtå—~´x#Àÿdu)Ú-éI5îF-˜FRsð eÑ•o±i(ªû\kõ,Æ2ØÍØÒXHÿF!jS}~ó MÃéÓÌ<2íE0ÞB6òH)l$qñ/0ÆØØÍÿEdY‰ŽÿUÙøââE4ÿP3ùL6ÿT$w&{-*ÛÙÙËÔWFÿI,ÈIC®NTtDeSà MÃáE3ÿM2÷K6ÿN5ËA@Ÿ.RŸPeÐÖÔÿI/úM3ÿI!©NP ãâG4ÿM3ýJ+ÿI#þJ-ÿ?(ÞZJËÕÖ÷M6ZXëI5’N^qTˆwbGpˆ {‡>ÕTBÿE)ýI/ÿEÿE!þK1ÿC 6h®€ÿ tÉÏмcVÚSAÖWEÑXIÒWHÔXGÚS;Ji›xé)sÛ FÀGÕÕÕÄÎÏÄÎÐÏÌÉÒËÃÒÊÌÒÃÓ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYJZ[\]^_`abcdef+JZ[ghijklmnopqrsJtuvwxyz{|}~€‚Jtƒ„…†‡ˆ‰Š‹ŒdŽJ‘’“”•–—˜™š›œžJZŸ ¡¢…£¤¥¦§¨©ª«JŸ¬¥’­v®@¯°±²³J´µ¶Ÿ‘·¸¹º»¼½*+¾¿ÀÁÂÃÄÅÆÇÈÉÊ˾ÌJJJJJJÍÎÏÐÑ(0`€€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿw÷wwwwwwwwwwwww÷w÷÷wwwS7ˆX‡Xˆg‡S8‡ˆ…ˆ‡ƒ‡uƒvˆwsªªª¬ÌLÌ»»¸ÌÌÌû³»:ªªª/vªªª¬ÌÌÌk»»»LÌÌÈ»»»:ªªªWrªªª,ÌÌÌK»»¸ÌÌÌ»»»2ªªªwqªªª,ÌÌÌ;»»³ÌÌÌû»»:ªªªWxªªª¤ÌÌÌ »»³LÌÌÈ»»»:ªª¢‡vªªªŒÌÌÌ;»»³ÌÌÌû»»Šªªªsªª¢¤ÌÌÌK»;³LÌÌû»³:ªªª‡xDDLŒÌÌÌDLHÄÌÌÌÈ&"ªTDLL7tÌÌÌÌÌÌÌÌÌÌÌÌÌ̪ªª¬ÌÌ̇tÌÌÌÌÌÌÌÌÌÌÌÌÌÌêª*<ÌÌÌwtÌÌÌÌÌÌÌÌÌÌÌÌÌÌĪªª,ÌÌ̇xÌÌÌÌÌÌÌÌÌÌÌÌÌÌꪪ¬ÌÌÌWtÌÌÌÌÌÌÌÌÌÌÌÌÌÌʪªª,ÌÌÄqÌÌÌÌÌÌÌÌÌÌÌÌÌÌŪªª,ÌÌ̇ôÌÌÌÌÌÌÌCDT„TLdEcb65D\D‡sÌÌÌÌÌÌÌ[»»³%•Q1™™™ªªª‡tÌÌÌÌÌÌÌ‹»»³EUUX™™™ªªª‡tÌÌÌÌÌÌÌ;»»³U…UQ™™™Rªªª‡tÌÌÌÌÌÌÌ »»³UUUS™™™ŠªªªwxÌÌÌÌÌÌÌ[»»¸EUUÁ™™ªªª/tÌÌÌÌÌÌÌ+»»³UUUQ™™™ªªª7sÌÌÌÄÌLă³»³…QS™™ª**‡tÌÌÌH3¸3dÄLHÄ\DIQ‡ôÌÌÌK»»»™™‘ÌÌÌÌÌÌÌÉ™™™‡tÌÌÌK»»»™™˜ÌÌÌÌÌÌÌA™™™‡xÌÌÌË»»»‰™™‘LÌÌÌÌÌÌi™™™‡tÌÌÌK»»»9™™‘LÌÌÌÌÌÌI™™™‡sÌÌÌË»»»™™‘ÌÌÌÌÌÌÌa™™™‡tÌÌÌK»»»9™™‘ÌÌÌÌÌÌÌI™™™WtÌÌÌ@e04ÄÌÌÌÌÌÌÈAR‡sÌÌÌÌÌÌÌ;»»³LÌÌÌÌÌÌÌÌÌÌtÌÌÌÌÌÌÌK»»³ÌÌÌÌÌÌÌÌÌÌ̇tÌÌÌÌÌÌÌ‹»»¸ÌÌÌÌÌÌÌÌÌÌÌwtÌÌÌÌÌÌÌ;»»³LÌÌÌÌÌÌÌÌÌ̇tÌÌÌÌÌÌÌ »»³ÌÌÌÌÌÌÌÌÌÌ̇xÌÌÌÌÌÌÌ[»»³ÌÌÌÌÌÌÌÌÌÌÌWtÌÌÌÌÌÌÌ3»»³LÌÌÌÄÌÌÄÌÄ̇xÌÌÌÌÌÌÌÄÄÄÄÌÌÌó3»3*ª*?tÌÌÌÌÌÌÌÌÌÌÌÌÌÌû»»:ªªª‡sÌÌÌÌÌÌÌÌÌÌÌÌÌÌÅ»»»:ªªª_uÌÌÌÄÌÌÌÌÌÌÌÌÌÌû»»:ªªªwtÌÌÌÌÌÌÌÌÌÌÌÌÌÌû»»Šªª*/tÌÌÌÌÌÌÌÌÌÌÌÌÌÌÆ»»»Šªªª7tÌÌÌÌÌÌÌÌÌÌÌÌÌÌû»»:ªªª‡xD4„ˆDAVFA†EA†AF3X2C2((‡wwwwwwwwwwwwwwwww‡wwwww( @€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ÷÷÷w÷÷ww÷÷v&s†W‡¸{gˆq7µzcwøªªÇÌË·¸ìÈË“9ªª‡sªªÌì‹;;ÇÌS»¸ªªöªªŒÈÇ‹³Èl‰¹3ªª/sªªÈÇK»‹ŒÇƒ“™ªªguHˆŒÌÈheÈ̈£X…‡öÈÌìì|ÈŒŒìŠª¦ÎÌxÈÌŒŒŒÌìÇìZª£ìÌwxì|ÎÈÎ|ÇÌÇŠª¦Ç|‡xÌ|Ç|Œ|ÇeÌʪ%lŒ‡|ÇÌìÌu51ŒX8¨j‡xŒì|ìÁ¹˜LÕY™˜ªª7vÈÈÌ|Û¹…Õi™‘ªªxÌŒçÈË»“ÍÅY™‘ªªgx|ÈÌlÉ9³XU‰“ª*‡öÈÌ3˜‘“ŒÈÆÌe™™ẍ‰¹¹™™È|Œ|v‘7xÈÈ[›9™™ŒÌÈ|Æ™™w|ìŒ9¹˜™ÈÎŒÎÅ™™?xÈÈ;9ƒ““ŒÈÌÌå™™wxŒŒÌÆÉ3•ÎìÇ|̌̇xÎ|Ç|Ë›¹ˆÈÎÌŒìÈoxÌÌì̃¹8ÌŒ|ÇÈÇÌ|ÇÌŒÇÈ›¹ÈÎÎÌŒÈÌwxÎÈÎÎS3lŒÅˆŒlÈøÌŒŒ|ÈÌŒÇÈy³9ªª/xÇÈÈÌŒ|ÈÌŒƒ›¸ªªwvÇìÇÈÎÌì~Çi¹9ªª‡uÌÈÌŒŒÇÌÌÌË›¶ªª/xÈhhȆˆˆVV1(6w÷w÷www÷÷ÿwww( €€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿwwÿww÷ó¨…;\;Їz¦Œ»ì‰ª§vŒÇgÈ8ˆgøÈÈÌŒ:lÏ|ì̈̊ˆ‡|xx³X™j/øÌÌ9\™Š§xÈ“™|ÌY‡|ˆ{™|Œ‰‡üÆŒ“Ìçe‡öŒˆ;ÈÌÌxLj…Ȉ†‡üÌÌÌÌ‰Š¯xŒÇŒ†ƒ:7w÷÷w÷÷puzzles-20170606.272beef/icons/flip.ico0000644000175000017500000006117613115373730016443 0ustar simonsimon 00 ¨%–  ¨>& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™ššššššššššššššššššššššššššššššššššššššš™™™™™™™™™™™™™™™™™™™™™™™™›››››››››››››››››››››››››››››››››››››››™™™˜˜˜————————————————————————————————————–––––––––––––––––––––––––––––––––––––––™™™™™™™™™™™™™™™™™™™™™˜˜˜‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘˜˜˜›››£££¤¤¤¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¢¢¢   ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ššš™™™™™™™™™™™™™™™›››‘‘‘PPPMMMNNNNNNNNNNNNNNNNNNNNNNNNNNNOOOIII¨¨¨äääÒÒÒÙÙÙãããçççåååäääääääääääääääæææÕÕÕ÷÷÷þþþüüüýýýýýýýýýýýýýýýýýýýýýüüüýýýúúú¤¤¤–––ššš™™™™™™™™™›››MMMKKKLLLKKKKKKLLLLLLLLLKKKKKKLLLLLLHHH®®®ùùùüüüçççØØØ×××áááèèèéééçççææææææééé×××ùùùÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýý¤¤¤–––ššš™™™™™™™™™›››‘‘‘NNNLLLLLLLLLLLLKKKIIIKKKLLLLLLLLLMMMHHH···áááÿÿÿÿÿÿþþþðððàààØØØÜÜÜæææçççåååèèèÖÖÖùùùÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿÿÿüüü¤¤¤–––ššš™™™™™™™™™›››‘‘‘NNNKKKLLLLLLLLLRRR\\\SSSLLLLLLLLLMMMFFF¾¾¾ÝÝÝóóóÿÿÿþþþÿÿÿñññæææãããÓÓÓãããæææèèèÖÖÖúúúÿÿÿÿÿÿþþþÿÿÿöööééé÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿýýý¤¤¤–––ššš™™™™™™™™™›››‘‘‘NNNKKKLLLLLLFFF```[[[aaaGGGKKKLLLMMMFFF¾¾¾åååßßßÿÿÿÿÿÿóóóäääæææ÷÷÷óóóÕÕÕèèèçççÖÖÖúúúÿÿÿÿÿÿþþþÿÿÿâââëëëãããÿÿÿþþþÿÿÿÿÿÿýýý¤¤¤–––ššš™™™™™™™™™›››‘‘‘NNNLLLKKKRRR```pppqqqqqq```SSSKKKMMMFFF»»»ïïïÓÓÓýýýëëëÛÛÛÌÌÌÌÌÌÚÚÚìììÚÚÚâââéééÖÖÖúúúÿÿÿÿÿÿõõõäääÏÏÏÌÌÌÝÝÝÿÿÿþþþÿÿÿÿÿÿýýý¤¤¤–––ššš™™™™™™™™™›››‘‘‘NNNLLLIII\\\[[[qqq²²²uuuYYY^^^IIINNNFFF»»»ñññ×××éééàààòòò‘‘‘‘‘‘òòòàààèèèÙÙÙëëëÖÖÖúúúÿÿÿÿÿÿçççíííÈÈÈxxxÏÏÏÿÿÿýýýÿÿÿÿÿÿýýý¤¤¤–––ššš™™™™™™™™™›››‘‘‘NNNLLLKKKSSSaaaqqquuuqqqaaaTTTKKKMMMFFF»»»ïïïáááÚÚÚêêêÚÚÚÇÇÇÈÈÈÛÛÛéééüüüÕÕÕéééÖÖÖúúúÿÿÿÿÿÿôôôãããÎÎÎÆÆÆÜÜÜÿÿÿþþþÿÿÿÿÿÿýýý¤¤¤–––ššš™™™™™™™™™›››‘‘‘NNNKKKLLLLLLGGG```YYYaaaGGGKKKLLLMMMFFF¼¼¼îîîçççÕÕÕôôôöööçççåååóóóÿÿÿÿÿÿàààßßßØØØùùùÿÿÿÿÿÿþþþÿÿÿâââíííãããÿÿÿþþþÿÿÿÿÿÿýýý¤¤¤–––ššš™™™™™™™™™›››‘‘‘NNNKKKLLLLLLKKKSSS^^^TTTKKKMMMLLLMMMFFF¼¼¼îîîåååâââÔÔÔååååååïïïþþþþþþÿÿÿóóó×××ÙÙÙùùùÿÿÿÿÿÿþþþÿÿÿôôôçççöööÿÿÿÿÿÿÿÿÿÿÿÿýýý¤¤¤–––ššš™™™™™™™™™›››‘‘‘NNNLLLLLLLLLLLLKKKIIIKKKLLLLLLLLLMMMGGG»»»îîîäääçççæææÛÛÛÙÙÙâââòòòÿÿÿÿÿÿÿÿÿÛÛÛÒÒÒúúúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüü¤¤¤–––ššš™™™™™™™™™›››‘‘‘OOOLLLMMMMMMMMMMMMNNNMMMMMMMMMMMMNNNHHH»»»îîîåååççççççêêêèèèàààØØØÚÚÚêêêÿÿÿòòòÊÊÊûûûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýý¤¤¤–––ššš™™™™™™™™™›››‘‘‘IIIHHHHHHFFFFFFFFFFFFFFFFFFFFFGGGHHH@@@½½½ñññßßßÞÞÞàààààààààâââãããÞÞÞÔÔÔÐÐÐÛÛÛÀÀÀûûûþþþøøøøøøùùùúúúúúúúúúúúúúúúùùùúúú÷÷÷¤¤¤–––ššš™™™™™™™™™™™™˜˜˜©©©®®®¶¶¶¾¾¾¾¾¾»»»»»»»»»¼¼¼¼¼¼»»»»»»½½½˜˜˜§§§ÓÓÓÜÜÜÖÖÖÑÑÑÑÑÑÒÒÒÒÒÒÓÓÓÕÕÕÓÓÓÎÎεµµ———ÇÇÇÞÞÞÝÝÝÖÖÖÔÔÔÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖ×××ÕÕÕ   ———™™™™™™™™™™™™˜˜˜›››âââúúúãããÝÝÝåååîîîñññïïïîîîîîîîîîîîîñññ§§§LLLooo©©©ÛÛÛñññïïïèèèçççèèèèèèèèèîîî×××hhhTTTÅÅÅêêêñññêêêæææçççèèèèèèéééæææ¢¢¢———™™™™™™™™™™™™———£££ÒÒÒùùùÿÿÿõõõáááÔÔÔÖÖÖàààçççåååäääåååßßßÔÔÔppp>>>DDDYYYŒŒŒÅÅÅèèèïïïçççååååååæææÛÛÛ¬¬¬CCCDDDKKKqqq¬¬¬ÜÜÜïïïëëëååååååæææäää¡¡¡———™™™™™™™™™™™™———¤¤¤ÙÙÙåååÿÿÿþþþÿÿÿýýýëëëÛÛÛÔÔÔâââççççççÞÞÞÜÜܪªªEEEPPPIIIBBBLLLttt®®®ÞÞÞèèèåååèèèÔÔÔÙÙÙcccJJJMMMEEEDDD^^^‘‘‘ËËËèèèåååçççäää¡¡¡———™™™™™™™™™™™™———¢¢¢ããã×××þþþþþþÿÿÿéééàààêêêùùùÔÔÔæææèèèàààÕÕÕÜÜÜZZZIIIKKKQQQeee^^^EEEiiißßßçççèèèÐÐÐêêꘘ˜CCCOOOIII___cccTTTGGG®®®îîîåååäää¡¡¡———™™™™™™™™™™™™———¡¡¡ççç×××íííÿÿÿöööÛÛÛòòòÚÚÚýýýäääÛÛÛêêêàààÑÑÑñññBBBQQQ___^^^```bbbEEE¯¯¯îîîçççÑÑÑæææÏÏÏPPPLLLTTTgggWWWeeeAAAlllæææçççäää¡¡¡———™™™™™™™™™™™™———¡¡¡åååáááßßßðððäääÌÌÌ‘‘‘ÈÈÈçççäääÙÙÙèèèàààÑÑÑïïïÆÆÆMMMeee^^^’’’’’’```^^^uuuèèèèèèÒÒÒßßßîîîzzzSSSaaauuuŸŸŸmmmGGGKKK¾¾¾îîîâââ¡¡¡———™™™™™™™™™™™™———¡¡¡äääèèèØØØäääæææÌÌÌ‘‘‘ÈÈÈåååîîîáááàààâââÒÒÒèèèéééuuu^^^```’’’’’’^^^eeeLLLÆÆÆïïïÑÑÑßßßðððµµµWWW```vvvŸŸŸmmmIIIDDD„„„îîîããã¡¡¡———™™™™™™™™™™™™———¡¡¡äääéééÜÜÜâââþþþÚÚÚòòòÛÛÛõõõÿÿÿððð×××ãããÒÒÒçççîî¯EEEaaa```^^^___QQQBBBñññÑÑÑàààèèèãããfffLLLjjjWWWbbbJJJKKKUUUÔÔÔèèè   ———™™™™™™™™™™™™———¡¡¡äääçççæææÔÔÔ÷÷÷ëëëàààèèèÿÿÿþþþÿÿÿÙÙÙÞÞÞÓÓÓèèèçççßßßjjjEEE^^^eeeQQQLLLIIIZZZÜÜÜÕÕÕàààåååîîî§§§DDDUUUccc^^^KKKOOOCCCŸŸŸîîŸ———™™™™™™™™™™™™———¡¡¡äääæææçççãããÕÕÕÚÚÚéééýýýÿÿÿþþþÿÿÿèèèÔÔÔÕÕÕèèèåååèèèßßß°°°vvvMMMBBBIIIPPPEEEªªªÜÜÜÞÞÞçççæææçççÊÊÊ]]]CCCEEEMMMIIIgggààࢢ¢–––™™™™™™™™™™™™———¡¡¡âââåååäääåååçççááá×××ÓÓÓàààóóóÿÿÿüüüÏÏÏÒÒÒèèèååååååçççîîîéééÇÇÇŽŽŽZZZEEE>>>pppÔÔÔàààçççååååååëëëïïïÛÛÛ«««pppKKKCCCEEE···ªªª•••™™™™™™™™™ššš———¢¢¢ìììïïïîîîîîîîîîïïïñññïïïæææÞÞÞâââúúúßßßÏÏÏîîîæææèèèèèèçççèèèïïïñññÝÝÝ«««qqqMMM¦¦¦êêêèèèèèèèèèçççæææêêêñññêêêÄÄÄŒŒŒRRRsss¥¥¥–––™™™™™™™™™™™™˜˜˜»»»¼¼¼»»»¼¼¼¼¼¼»»»»»»»»»¾¾¾¾¾¾···¯¯¯¥¥¥±±±×××ÛÛÛÔÔÔÐÐÐÑÑÑÒÒÒÑÑÑÑÑÑÕÕÕÜÜÜÔÔÔ§§§œœœØØØÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÕÕÕÔÔÔÖÖÖÝÝÝÞÞÞÅÅÅ™™™™™™™™™™™™™™™™™™˜˜˜›››HHHFFFGGGFFFFFFFFFFFFFFFFFFFFFHHHHHHLLL|||nnn©©©ØØØéééæææßßßßßßààààààÞÞÞàààêêêØØØôôôûûûùùùúúúúúúúúúúúúúúúùùùøøøøøøþþþýýý¤¤¤–––ššš™™™™™™™™™›››‘‘‘OOOMMMMMMMMMMMMMMMNNNMMMMMMMMMMMMMMMKKK­­­[[[BBBbbb–––ÎÎÎíííðððèèèæææççççççèèèÖÖÖúúúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüü¤¤¤–––ššš™™™™™™™™™›››‘‘‘NNNLLLLLLLLLLLLKKKIIIKKKLLLLLLLLLMMMEEEÄÄÄ”””BBBJJJCCCPPPyyy´´´âââîîîæææåååèèèÖÖÖùùùÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüü¤¤¤–––ššš™™™™™™™™™›››‘‘‘NNNKKKLLLLLLKKKSSS^^^TTTKKKMMMLLLMMMEEEÂÂÂÍÍÍJJJMMMOOOLLLSSSWWWeee¦¦¦çççåååèèèÖÖÖúúúÿÿÿÿÿÿþþþÿÿÿôôôçççöööÿÿÿÿÿÿÿÿÿÿÿÿýýý¤¤¤–––ššš™™™™™™™™™›››‘‘‘NNNKKKLLLLLLGGG```YYYaaaGGGKKKLLLMMMFFF»»»ðððpppEEEIIITTTaaa```MMMDDDÊÊÊëëëçççÖÖÖúúúÿÿÿÿÿÿþþþÿÿÿâââíííãããÿÿÿþþþÿÿÿÿÿÿýýý¤¤¤–––ššš™™™™™™™™™›››‘‘‘NNNLLLKKKSSSaaaqqquuuqqqaaaTTTKKKMMMFFF¹¹¹÷÷÷«««DDD___gggvvvvvvjjjUUUïïïæææÖÖÖúúúÿÿÿÿÿÿôôôãããÎÎÎÆÆÆÜÜÜÿÿÿþþþÿÿÿÿÿÿýýý¤¤¤–––ššš™™™™™™™™™›››‘‘‘NNNLLLIII\\\[[[qqq²²²uuuYYY^^^IIINNNFFF»»»ðððÛÛÛ___cccVVVŸŸŸŸŸŸVVVccc\\\ÚÚÚëëëÕÕÕúúúÿÿÿÿÿÿçççíííÈÈÈxxxÏÏÏÿÿÿýýýÿÿÿÿÿÿýýý¤¤¤–––ššš™™™™™™™™™›››‘‘‘NNNLLLKKKRRR```pppqqqqqq```SSSKKKMMMFFF¼¼¼ìììííí’’’SSSkkksssrrrggg]]]CCC©©©ñññÔÔÔúúúÿÿÿÿÿÿõõõäääÏÏÏÌÌÌÝÝÝÿÿÿþþþÿÿÿÿÿÿýýý¤¤¤–––ššš™™™™™™™™™›››‘‘‘NNNKKKLLLLLLFFF```[[[aaaGGGKKKLLLMMMFFF¼¼¼íííéééÌÌÌEEEJJJaaabbbSSSIIIFFFoooéééÖÖÖùùùÿÿÿÿÿÿþþþÿÿÿâââëëëãããÿÿÿþþþÿÿÿÿÿÿýýý¤¤¤–––ššš™™™™™™™™™›››‘‘‘NNNKKKLLLLLLLLLRRR\\\SSSLLLLLLLLLMMMFFF¼¼¼îîîäääèèè®®®mmmWWWPPPKKKOOONNNJJJÃÃÃÝÝÝøøøÿÿÿÿÿÿþþþÿÿÿöööééé÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿýýý¤¤¤–––ššš™™™™™™™™™›››‘‘‘NNNLLLLLLLLLLLLKKKIIIKKKLLLLLLLLLMMMGGG»»»îîîäääåååîîîæææ½½½ƒƒƒUUUCCCHHHCCC‹‹‹ÞÞÞøøøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþþþÿÿÿüüü¤¤¤–––ššš™™™™™™™™™›››MMMKKKLLLKKKKKKLLLLLLLLLKKKKKKLLLMMMFFF¼¼¼ïïïåååçççåååçççîîîïïïÕÕÕ   hhhEEEQQQÄÄÄýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýý¤¤¤–––ššš™™™™™™™™™›››‘‘‘PPPMMMNNNNNNNNNNNNNNNNNNNNNNNNNNNOOOHHH»»»ìììâââäääääääääââââââèèèíííááḸ¸ttt™™™ÿÿÿüüüüüüýýýýýýýýýýýýýýýýýýýýýüüüýýýúúú¤¤¤–––ššš™™™™™™™™™™™™˜˜˜‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘¢¢¢¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡   ŸŸŸ¢¢¢ªªª¥¥¥™™™¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ššš™™™™™™™™™™™™™™™™™™™™™›››››››››››››››››››››››››››››››››››››››˜˜˜———————————————————————————–––•••–––™™™–––––––––––––––––––––––––––––––––––––––™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™˜˜˜™™™ššš™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™ššššššššššššššššššššššššššššššššššššššš™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™™( @ ™™™™™™›››››››››››››››››››››››››››™™™˜˜˜———————————————————————————————————————————————————™™™™™™™™™˜˜˜’’’’’’’’’’’’’’’’’’’’’’’’’’’˜˜˜œœœ¡¡¡¡¡¡   ŸŸŸ         ŸŸŸ¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢ššš™™™›››’’’RRRNNNOOOOOOPPPOOOOOOPPPHHH«««ééé×××ÜÜÜâââääääääâââäääÚÚÚøøøüüüûûûûûûúúúûûûûûûüüü÷÷÷¢¢¢———›››’’’NNNJJJLLLKKKIIIKKKLLLLLLEEE°°°ýýýûûûêêêáááßßßäääèèèçççÞÞÞüüüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûûû¢¢¢———›››’’’OOOLLLKKKMMMYYYOOOJJJNNNFFF´´´êêêÿÿÿÿÿÿñññæææâââàààèèèÝÝÝüüüÿÿÿÿÿÿùùùîîîûûûÿÿÿÿÿÿûûû¢¢¢———›››’’’OOOKKKMMM\\\hhh___NNNMMMEEEºººäääöööõõõÝÝÝáááôôôÜÜÜçççÝÝÝüüüÿÿÿüüüåååÚÚÚóóóÿÿÿÿÿÿûûû¢¢¢———›››’’’PPPIIIYYYhhhšššooo[[[LLLEEEºººéééáááééé®®®­­­éééàààâââÞÞÞûûûÿÿÿëëëÑÑÑ–––òòòÿÿÿÿÿÿûûû¢¢¢———›››’’’OOOKKKOOO___ooocccPPPMMMEEE¸¸¸ïïïÚÚÚòòòÙÙÙÕÕÕòòòõõõÜÜÜßßßüüüÿÿÿùùùáááÑÑÑóóóÿÿÿÿÿÿûûû¢¢¢———›››’’’OOOLLLJJJNNN[[[PPPJJJNNNEEE¸¸¸ðððÝÝÝæææéééðððÿÿÿÿÿÿáááÚÚÚýýýÿÿÿÿÿÿ÷÷÷ëëëúúúÿÿÿÿÿÿûûû¢¢¢———›››’’’PPPLLLNNNMMMLLLMMMNNNOOOFFF¸¸¸îîîæææâââÞÞÞãããðððÿÿÿòòòÕÕÕýýýÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûûû¢¢¢———›››’’’HHHEEEFFFEEEEEEEEEEEEFFF===»»»ôôôàààâââãããàààÚÚÚÚÚÚåååÏÏÏýýýÿÿÿúúúûûûûûûüüüüüüýýýøøø¢¢¢———™™™˜˜˜«««°°°´´´ºººººº¸¸¸¸¸¸¸¸¸»»»›››¯¯¯ÜÜÜâââÚÚÚÖÖÖÙÙÙ×××ÖÖÖºººŸŸŸÔÔÔçççãããÜÜÜÛÛÛÝÝÝÞÞÞÚÚÚŸŸŸ———˜˜˜æææÿÿÿìììåååéééïïïðððîîîôôô¯¯¯HHHppp«««ÝÝÝñññíííæææìììÛÛÛcccTTT‘‘‘ÊÊÊëëëðððççççççäää   ——————¡¡¡×××ùùùÿÿÿøøøâââÚÚÚÝÝÝæææàààÜÜÜppp>>>CCC\\\ÊÊÊèèèäääââ⪪ª@@@CCCLLLzzz²²²âââèèèâââ   ——————¡¡¡ÜÜÜéééÿÿÿõõõéééòòòæææáááâââââ⬬¬CCCQQQZZZRRRNNNÊÊÊíííÙÙÙÚÚÚ]]]HHHWWWXXXCCCðððááá   ——————   âââàààñññÝÝÝ­­­ÙÙÙèèèÞÞÞãããÚÚÚÝÝÝ]]]ZZZ‚‚‚RRR‘‘‘ñññÔÔÔíííMMMnnnŒŒŒTTTUUUÝÝÝåå域Ÿ——————ŸŸŸäääàààäääááá­­­ÕÕÕñññãããàààÖÖÖñññ‘‘‘RRR‚‚‚ZZZ]]]ÝÝÝÙÙÙèèèËËËWWWlll‹‹‹XXX@@@©©©ííížžž——————   ääääääâââôôôéééòòòÿÿÿïïïÙÙÙÙÙÙíííËËËNNNRRRZZZQQQCCC¬¬¬âââßßßíííyyyGGGYYYUUUFFFoooåå域Ÿ——————   áááæææßßßÚÚÚßßßõõõÿÿÿþþþØØØ××׿ææèèèËËË’’’]]]CCC===pppÜÜÜáááèèèÞÞÞªªªsssIIIBBBGGGÀÀÀ¨¨¨•••———¡¡¡ëëëððððððïïïêêêåååéééýýýêêêØØØëëëäääíííñññÞÞÞ­­­qqqIII­­­ëëëåååèèèñññéééÃÃɉ‰MMMxxx§§§–––˜˜˜œœœ···¹¹¹¸¸¸¸¸¸ºººººº¶¶¶°°°ªªª²²²ÜÜÜâââÙÙÙÔÔÔÙÙÙâââÝÝÝ®®®£££àààÝÝÝÝÝÝÛÛÛÝÝÝäääçççÍÍÍŸŸŸ™™™™™™›››’’’HHHDDDEEEEEEEEEEEEEEEFFFHHHyyykkk§§§ÙÙÙíííèèèßßßáááëëëàààùùùýýýüüüüüüûûûúúúúúúÿÿÿûûû¢¢¢———›››’’’QQQMMMNNNMMMLLLMMMNNNNNNIII¯¯¯]]]>>>]]]ÊÊÊíííèèèåååÝÝÝüüüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿúúú¢¢¢———›››’’’OOOLLLJJJNNN[[[PPPJJJNNNCCCÃÃÚššBBBHHHMMMWWWyyyÞÞÞèèèÝÝÝüüüÿÿÿÿÿÿ÷÷÷ëëëúúúÿÿÿÿÿÿûûû¢¢¢———›››’’’OOOKKKOOO___ooocccPPPMMMDDD¾¾¾ÒÒÒKKKWWWnnnlllGGG©©©ñññÛÛÛüüüÿÿÿùùùáááÑÑÑóóóÿÿÿÿÿÿûûû¢¢¢———›››’’’PPPIIIYYYhhhšššooo[[[LLLEEE···óóóyyyYYY‹‹‹‹‹‹YYYrrrèèèÝÝÝûûûÿÿÿëëëÑÑÑ–––òòòÿÿÿÿÿÿûûû¢¢¢———›››’’’OOOKKKMMM\\\hhh___NNNMMMEEE¶¶¶øøø±±±DDDccchhhVVVIIIÃÃÃäääúúúÿÿÿüüüåååÚÚÚóóóÿÿÿÿÿÿûûû¢¢¢———›››’’’OOOLLLKKKMMMYYYOOOJJJNNNEEE¸¸¸ïïïàààaaaLLLEEECCC‰‰‰çççúúúÿÿÿÿÿÿùùùîîîûûûÿÿÿÿÿÿûûû¢¢¢———›››’’’NNNJJJLLLKKKIIIKKKLLLMMMDDD¹¹¹ðððæææñññÛÛÛ¨¨¨oooGGGMMMÌÌÌÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûûû¢¢¢———›››’’’RRRNNNOOOOOOPPPOOOOOOQQQHHH···ëëëááááááæææíííåååÀÀÀxxxžžžÿÿÿúúúûûûûûûúúúûûûûûûüüü÷÷÷¢¢¢———™™™˜˜˜’’’’’’’’’’’’’’’’’’’’’’’’’’’œœœ¡¡¡      ŸŸŸžžžŸŸŸ¨¨¨§§§ššš¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢¢ššš™™™™™™™™™›››››››››››››››››››››››››››˜˜˜——————————————————•••–––™™™———————————————————————————™™™™™™(  ˜˜˜“““““““““’’’–––žžž   ŸŸŸ   ¢¢¢¡¡¡¢¢¢¡¡¡ššš“““WWWOOORRRIIIîîîáááßßßÞÞÞçççúúúúúúúúúñññ¡¡¡“““OOOQQQ```BBBüüüíííàààãããïïïÿÿÿèèèûûûùùù¡¡¡“““RRR```{{{HHHƒƒƒîîîÒÒÒÚÚÚçççëëëüüüÈÈÈôôôùùù¡¡¡’’’IIIBBBHHH666€€€ôôôàààóóóòòòêêêÿÿÿùùùÿÿÿøøø¢¢¢–––ƒƒƒ€€€•••ÔÔÔéééâââÜÜÜÉÉÉêêêúúúóóóççç   íííþþþîîîôôôÔÔÔ]]]†††ÆÆÆïïï©©©XXX™™™ÖÖÖàààžžžžžžàààîîîÒÒÒßßßéé醆†OOOfffÉÉÉåååaaaWWWqqqÞÞÞ      ÝÝÝÝÝÝØØØðððàààÇÇÇfffOOO„„„õõõ¤¤¤___DDD°°°«««   éééðððôôôýýýãããïïïÉÉÉ„„„^^^ÍÍÍæææ´´´ooosss¤¤¤———………ƒƒƒ~~~ŠŠŠ°°°äääõõõÍÍÍÔÔÔòòò÷÷÷÷÷÷ÑÑÑ›››’’’HHHAAAHHH999xxxeee]]]£££çççñññÿÿÿúúúÿÿÿøøø¢¢¢“““RRR```{{{EEE¦¦¦UUU```´´´÷÷÷úúúÈÈÈôôôøøø¡¡¡“““OOOQQQ```@@@†††âââuuuKKKnnnöööÿÿÿçççûûûùùù¡¡¡“““WWWOOORRRHHH„„„ìììÜÜܱ±±sssÑÑÑÿÿÿùùùúúúñññ¡¡¡˜˜˜“““““““““’’’———      «««¤¤¤›››£££¡¡¡¢¢¢¡¡¡ššš(0` ™™™ššš›››˜˜˜———–––‘‘‘£££¤¤¤¢¢¢¡¡¡   PPPMMMNNNOOOIII¨¨¨äääÒÒÒÙÙÙãããçççåååæææÕÕÕ÷÷÷þþþüüüýýýúúúKKKLLLHHH®®®ùùùØØØ×××áááèèèéééÿÿÿ···ðððàààÜÜÜÖÖÖRRR\\\SSSFFF¾¾¾ÝÝÝóóóñññÓÓÓööö```[[[aaaGGGßßßâââëëëpppqqq»»»ïïïÛÛÛÌÌÌÚÚÚìììõõõÏÏϲ²²uuuYYY^^^òòòíííÈÈÈxxxTTTêêêÇÇÇôôôÎÎÎÆÆÆ¼¼¼îîîÔÔÔÊÊÊûûû@@@½½½ÞÞÞÐÐÐÀÀÀøøø©©©¶¶¶§§§ÑÑѵµµooohhhÅÅÅ>>>DDDŒŒŒ¬¬¬CCCªªªEEEBBBtttcccJJJËËËZZZQQQeeeiii___bbb¯¯¯gggWWWAAAlll’’’zzzŸŸŸmmmvvv„„„fffjjjUUU°°°]]]ŽŽŽ«««•••¦¦¦ÄÄÄsss¥¥¥±±±œœœ|||nnn­­­”””yyy´´´ÂÂÂÍÍ͹¹¹VVVkkkrrrÃÃË‹‹¸¸¸    ! !!! !!"#$%&'())&$*********** !!!!  !!!"+'**,-%.(/$**********  !!!012!!!3456**78(/***9)****  !!3:;<= !34>**66(/***?@*** ! 0:ABB:2 3CD8@EFFGHG?)/**IJF5*** !1;BKLMN3C7&)-OO-(@/**PQRJ*** ! 2%$***?P***  !! 2NS !3YZ?[D*6&$***V9**** !!!!  !!!=CZE?O***E*********** !"CZT(-%GT*O\]*********** ""3333333="^_7>`---?`[aEb]cc$$ d#e44CCCYYCC_f8./gg88WhU`5/[////& ?5Z7DZZZZ7f!idE7D((((Z&jSklT7T(() $*I'[/->[AmnMol(DEpqn Bp.D@  **@E[?`.rs t!u#`(([vwsnNx(  &*)-T$[(-.y z{Ns|>(aTq}vS=#Z  &P*9EOGET-g7ktz}N:~sZgJ !S€{‚ƒ  '>,FQ(-gDX{N„„:NL((>Z…2,h:ˆ†‡n‰Z  ).?GOEI*,&Zs<:N}ztk7g-(Š!‹~w Œ[(  [@-(**`8(>‹sN{z!y.-ZfnŒvN q†Z† G)**([((>ˆt sr.`\Žqs€-  ?'&8-6*J(Z)UysmA[-@DEA qs+r‘ HDZZZD7D`?>JZ(((D75B’T(((T7T“o0”•–CYCYYCCC44+•—&E[aggg.[f˜%/////[/5`l"3=3333333""!™šd%)>>--`-T%V]$$cc  ›;t~WP,((/*********** !!!!  !!!s“œtwq ž?Z(/$***********  !! 2NS !sŸ w!2{’(/***V9****  !!=:M<= !3C,AsS<:n\@/***?P*** ! 2>>CCCªªª@@@zzz²²²¬¬¬QQQZZZ]]]WWWXXX‚‚‚nnnŒŒŒUUUËËËlll‹‹‹©©©žžžyyyGGGþþþØØØsssBBBÀÀÀ¨¨¨•••qqqÃÃɉ‰xxx§§§···¹¹¹¶¶¶£££ÍÍÍDDDkkk¾¾¾ÒÒÒrrr±±±VVVaaaÌÌÌ      !"#$%&'()))))))  *+  ,-#))./0&1))23))  *456 * 7891$:'1);<)) +5 => 7$?@0()ABCD))   6=E* FGDHID9%)2$B<))   > FJ1/J))$"))A))  ** ,F3/(KJ)DI")))))))  , ,LM:0K0;N")" !-77FFFMOPHP7Q'KR1(S/)T;GJ3:OU1.V/TREWXYAJ''2)1/0UZ[4\Y&]^[_`&)9D/$a[bc YVHdef[\J$0.1@H&(K1dcgh X.QV\*ijWk1;0$@I.K0P.X hgcd1H&lemnf^oVp:D)GHHVl cb[a%Vqr+k,=;$/%%9)st/&ld[LU$&(]uvrwxyAJJG#;"#tAV.(@z@A;&.{|*}~C€FF77!]`HQH1?‚011R1'ƒ„ ,q…~HV&%$A02") b* ** OdZd\YV&;1)))))))   > [{ v*eq(&1))A))   6=E*„†‡eimro.R)2$B<)) +5 => ?'4: @7AB CDDEFG@ HIJKLMN4F+O7HPQRSTUJVW&XYMZIQ3/[[\]%^%_`a9b  1 $cdefS[*+1  g:5hijk "#  %Hl6mU\ # VNJ]b  (0`€€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿww‡wwwwwwwwwwwwwwwwwwwwwwwwwwwwwÿÿÿÿÿ÷ÿÿÿÿÿÿÿwwwwwwxwwÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿ÷wxwwwwwxÿÿÿÿÿÿÿÿÿÿÿÿÿ÷wwwwwwwwÿÿÿ÷ÿÿÿÿÿÿÿÿÿ÷wwwww‡wwÿÿ÷ÿÿÿ÷ÿÿÿÿÿ÷wxwxwwwxÿÿÿÿ÷ÿÿÿÿÿÿÿÿÿ÷wwwwwwwwÿÿwwÿÿÿÿÿwÿÿÿ÷wwwwwwwxÿ÷÷ÿÿ÷ÿÿwÿÿ÷wwwwwwwwÿÿÿ÷ÿÿÿÿwÿÿÿ÷wwwwwwwwÿÿÿ÷ÿÿÿÿÿÿÿ÷wxw‡‡wwwÿÿÿ÷ÿÿÿ÷ÿÿÿ÷ÿÿ÷wwwwwwwwÿÿÿÿÿÿÿÿÿÿÿÿÿ÷‡wwwxwxwÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿ÷wwwwwwwwÿÿÿÿ÷ÿ÷ÿÿÿ÷ÿÿÿ÷wwxwwwxwÿÿÿÿÿ÷÷ÿÿÿÿÿÿÿww÷÷÷wÿÿ÷ÿ÷w÷ÿ÷ÿwÿÿÿÿÿÿÿwwÿÿÿÿÿ÷wÿÿÿÿÿ÷wÿ÷ÿÿÿÿwwwÿÿÿÿwwwÿÿÿÿ÷ÿÿÿ÷ÿÿÿ÷wwwÿÿÿ÷wwwÿÿ÷ÿÿ÷ÿÿÿÿwwwwÿ÷÷wwwwÿÿ÷ÿÿÿ÷ÿÿÿÿwwww‡ÿÿ÷w‡ww÷÷ÿÿ÷ÿÿÿwwwwwÿ÷ÿwwwwwÿ÷÷ÿ÷w÷ÿÿÿ÷‡wwwÿÿ÷wwwwÿ÷ÿ÷÷w÷÷ÿÿ÷wwww÷ÿ÷wwxwÿ÷ÿÿÿ÷ÿÿÿÿÿwwwwÿÿ÷wwww÷ÿ÷ÿÿÿÿÿww‡ww÷ÿ÷wwwww÷ÿÿÿÿÿÿÿ÷‡wwwÿÿÿwxwww÷ÿÿÿÿÿÿÿÿÿÿ÷wwwwÿÿÿwwww÷ÿÿÿÿÿ÷ÿÿÿ÷wwÿÿÿÿ÷wwwÿÿÿÿÿÿÿÿÿÿÿÿÿwwÿÿÿÿÿÿwww÷÷÷wwÿ÷ÿÿ÷÷÷ÿ÷ÿ÷÷wwww‡xwwwww÷ÿÿÿÿ÷ÿÿÿÿÿÿ÷wwwwww‡w÷wÿÿÿÿÿÿÿÿÿÿÿÿ÷wxwwwwwwwwwwÿÿÿÿÿÿÿ÷ÿÿÿ÷‡wwwwwwxÿwwwwÿÿ÷ÿÿÿÿÿÿÿ÷wwwwwwwwÿw‡wxwÿ÷ÿÿÿÿÿ÷wwwwwxwwwwwwwÿÿÿÿÿÿÿÿÿ÷wwxwwww‡÷wwwwÿÿÿ÷wÿÿÿ÷wwwwwwwwÿ÷wwww÷ÿÿÿw÷ÿ÷xxwwwwwwÿ÷wwwwÿÿÿ÷÷ÿÿ÷wwww‡wwwÿwwwww÷ÿÿÿÿÿÿ÷wwwwwwwwÿÿwwwwwÿÿÿÿ÷ÿÿÿ÷ww‡wwwwxÿÿwxww÷ÿÿÿÿÿÿ÷wwwwwwwwÿÿÿÿwwwÿÿÿÿÿÿÿ÷wwwwxwxwÿÿÿÿ÷wwÿÿÿÿÿÿÿ÷wwwwwwwwÿÿÿÿÿÿwÿÿÿÿÿÿwwxwwwwwwwwwwwwwwwwwwwwww( @€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿˆ‡ˆˆˆˆ‡‡ˆxˆxx‡ˆwˆˆˆˆw÷÷ÿÿÿÿxx€€€‡ÿÿÿÿÿÿÿ÷€ˆ‡ÿÿw÷ÿÿ÷ÿÿøˆ€€‡ÿ÷ÿÿÿø€ˆˆˆ÷ÿ÷wÿøp€ˆ€wwÿÿ÷ÿwˆ€€ˆ€‡ÿÿ÷ÿ÷ÿÿø€ˆ€ˆ‡÷wÿÿÿÿÿÿøˆ€€€‡÷ÿ÷ÿÿÿÿÿøˆˆ€wwwÿÿÿÿ÷‡w÷wxw÷÷wwwx÷÷÷÷wÿxˆ‡ÿw÷‡ÿÿwÿ÷€‡w€ˆ‡ÿxwÿÿÿˆˆ€ˆ€øø÷÷pˆÿ€ˆ€w÷øw÷÷xˆˆ‡xˆ‡wÿÿÿwø€ˆ÷÷ˆ€ø÷ÿ÷÷ˆ÷ˆ€øw÷÷ÿ÷xwwˆˆww÷÷wÿx‡÷ÿxˆˆˆˆˆˆˆ÷w÷wÿxˆˆ€ˆ‡wÿÿÿÿÿÿÿ÷€€€‡€ˆ‡÷ÿÿÿÿøp€€ˆ€ÿÿÿøˆˆ€ˆxˆˆ‡ÿÿ÷ÿøˆˆˆ€‡xˆˆÿxÿ÷p€ˆ‡ø€÷ÿÿÿÿøˆ€€ˆ€÷ˆˆwÿÿÿÿø€ˆ€€‡÷ˆ€ÿÿÿÿ÷ˆ€€ÿ÷ÿxÿÿÿÿøˆˆ‡ˆxˆxx‡‡‡wx‡xx( €€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿˆˆˆw‡‡‡ˆˆˆ÷wÿÿ÷ˆˆÿÿøˆ€ˆ÷ÿøˆÿ÷ÿÿøˆxˆ÷ÿøÿ÷ˆˆwø‡÷ÿ€‡øwww÷xøˆ‡ÿ÷ˆˆ‡ˆˆˆw÷wÿxˆˆ€ÿÿw€ˆˆx‡ÿøˆˆxÿ÷xˆ÷xÿøˆˆˆwx‡xxpuzzles-20170606.272beef/icons/filling.ico0000644000175000017500000006117613115373727017143 0ustar simonsimon 00 ¨%–  ¨>& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $ææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææåååææææææææææææææææææææææææååååååææææææææææææææææææææææææååååååææææææææææææææææææææææææåååææææææææææææææææææææææææååååååæææææææææææææææææææææçççëëëååååååååååååååååååååååååééééééäääåååååååååååååååååååååëëëçççåååååååååååååååååååååçççëëëåååååååååååååååååååååäääééééééåååæææææææææææææææçççâââÒÒÒììììììììììììììììììëëëîîîÜÜÜÙÙÙíííêêêêêêêêêêêêêêêêêêìììÓÓÓåååíííëëëìììììììììëëëíííæææÒÒÒëëëêêêêêêêêêêêêêêêêêêíííÛÛÛÙÙÙéééåååæææææææææåååíííËËË///000000000000000///555JJJ   ’’’””””””””””””“““›››(((!!!333///000000000///333$$$"""˜˜˜”””””””””””””””’’’¢¢¢III;;;óóóäääæææææææææåååîîîÅÅÅ###¦¦¦¤¤¤¤¤¤¤¤¤£¤£¤¤¤£££«««‰‰‰———ÌÌÌÂÂÂÃÃÃÃÃÃÂÃÂÃÃÃÂÂÂËËË‚‚‚ššš§§§¤¤¤¤¤¤£££££££££«««†††)))ÈÈÈÃÃÃÃÃÃÂÃÂÂÃÂÃÃÃÂÂÂÍÍÍ™™™•••ðððäääæææææææææåååîîîÃÃÃ...ÜÜÜÙÙÙØØØÕØÕÝÚÝÚÙÚ×××ááá´´´ªªªÛÛÛÑÐÑÐÑÐÐÑÐ×Ô×ÑÒÑÐÐÐÙÙÙ™™™ÌÌÌÜÜÜÙÙÙÕÕÕÚÚÚÝÝÝÖÖÖâââ´´´---×××ÑÑÑÓÒÓÝÕÝÚÕÚÑÒÑÑÑÑÚÚÚ®®®²²²ðððäääæææææææææåååîîîÃÃÃ+++ÐÐÐÌÍÌÑÎÑßÓߺǺÊÌÊÎÍÎÕÕÕ«««¥¥¥ØØØÌÍÌÚÒÚØÒØ¸Ç¸ÓÐÓÌÍÌÖÖÖ”””ÁÁÁÐÐÐÍÍÍßßßÇÇǾ¾¾ÑÑÑÕÕÕªªª,,,ÓÓÓÏÏÏËÍËŸ¿Ÿ¬Ã¬ÔÑÔÍÍÍ××ש©©¬¬¬ðððäääæææææææææåååîîîÃÃÃ+++ÐÑÐÕÑծĮf¬f’i­iÙÑÙÕÖÕ¬¬¬¦¦¦Ö×ÖÔÐÔŽ¹ŽS¥S§Â§ÕÐÕÕÖÕ•••ÂÂÂÔÔÔÈÈÈuuu555111ÍÍÍØØØ«««,,,ÓÓÓÔÐÔ·Ç·n¯n4›4{³{ÛÒÛÕ×Õ©©©­­­ðððäääæææææææææåååîîîÃÃÃ+++ÐÑÐ×ÒצÁ¦G¢G;;„¶„ÙÑÙÕÖÕ¬¬¬¦¦¦Õ×ÕÛÒÛr°rM¤M5œ5ºÈºÑÏÑÕÖÕ•••ÂÂÂÒÒÒÍÍÍOOOIIIPPPÖÖÖÖÖÖ«««,,,ÔÔÔÌÎÌØÒØ²Å²+˜+‰¸‰ÚÒÚÕ×Õ©©©­­­ðððäääæææææææææåååîîîÃÃÃ+++ÒÒÒÌÎÌÛÓÛ…¶… Š ¤À¤ØÑØÕÖÕ¬¬¬¦¦¦×Ø×ÎÎÎÓÐÓI¡I'”'ÒÐÒÎÍÎÖÖÖ•••ÂÂÂÐÐÐ×××µµµeeeßßßÔÔÔ«««,,,ÓÔÓÐÏÐÈÌȺ%–%…¶…ÛÒÛÕ×Õ©©©­­­ðððäääæææææææææåååîîîÃÃÃ+++ÐÐÐÍÍÍÏÎÏÉÌÉo®o·Æ·ÑÎÑÔÕÔ«««¥¥¥ÖÖÖÊËÊÖÐÖ¨Á¨v°vÏÎÏÌÌÌÕÕÕ”””ÁÁÁÑÑÑËËË××׃ƒƒ•••ÔÔÔÔÔÔªªª,,,ÒÒÒÎÍÎÈËÈ{²{s¯s½È½ÏÍÏÕÖÕ¨¨¨¬¬¬ðððäääæææææææææåååîîîÃÃÃ---ÛÛÛØØØ×Ø×ÙØÙèÝèÜÙÜÖÖÖááá³³³¬¬¬âââ×××ר×ßÛßçÝçØØØ×××ààà›››ËËËÜÜÜØØØ×××åååáááÖÖÖááá³³³...ÝÝÝ×××ÙØÙæÝæçÝçÜÙÜÖÖÖááá±±±±±±ðððäääæææææææææåååîîîÅÅÅ$$$ªªª¨¨¨¨¨¨§¨§¤§¤§¨§§§§®®®ŠŠŠ­­­¥¦¥§§§¥¦¥¤¦¤§§§¥¥¥­­­xxxœœœ©©©§§§§§§¤¤¤¥¥¥¦¦¦®®®ŠŠŠ$$$¬¬¬§§§¨¨¨¥§¥¥§¥§¨§§§§¯¯¯ŠŠŠ™™™ïïïäääæææææææææåååíííÊÊÊ ---...............---222777222333333333333222444$$$///333333333333333222555*** ///---............---444 BBBòòòäääæææææææææåååîîîÃÃÃ,,,ØØØÕÕÕÕÕÕÓÓÓÒÒÒÔÔÔÒÒÒééékkkiiiÿÿÿéééííííííííííííëëëöööªªªßßßñññíííìììêêêëëëììì÷÷÷ÆÆÆ...ÚÚÚÕÕÕÕÕÕÓÓÓÒÒÒÔÔÔÒÒÒéééggglllûûûâââæææææææææåååîîîÃÃÃ+++ÑÑÑÎÎÎÎÎÎÛÛÛßßß×××ÊÊÊááágggfffúúúáááååååååååååååãããííí¤¤¤×××éééäääêêê÷÷÷îîîâââîîî¿¿¿,,,ÓÓÓÍÍÍÎÎÎÛÛÛßßß×××ÉÉÉááácccjjjûûûâââæææææææææåååîîîÃÃÃ+++ÑÑÑÏÏÏÎÎÎyyy^^^•••ÓÓÓàààhhhfffûûûâââææææææææææææäääîî¥ØØØèèèëëëÍÍÍsss´´´ëëëîîî¿¿¿,,,ÓÓÓÏÏÏÍÍÍxxx^^^———ÓÓÓàààdddjjjûûûâââæææææææææåååîîîÃÃÃ+++ÒÒÒÎÎÎÕÕÕ†††$$$µµµÏÏÏáááhhhfffûûûâââææææææææææææäääîî¥ØØØèèèðððJJJiii555ÙÙÙòòò¿¿¿,,,ÔÔÔÍÍÍÕÕÕƒƒƒ%%%···ÏÏÏááádddjjjûûûâââæææææææææåååîîîÃÃÃ+++ÒÒÒÍÍÍØØØ¸¸¸AAAÙÙÙËËËâââhhhfffûûûâââææææææææææææäääîî¥×××éééêêê000TTTvvväääïïï¿¿¿,,,ÔÔÔÍÍÍÙÙÙµµµBBBÚÚÚÊÊÊâââdddjjjûûûâââæææææææææåååîîîÃÃÃ+++ÑÑÑÏÏÏÑÑÑVVV222ÓÓÓËËËâââhhhfffûûûâââææææææææææææäääîî¥ØØØçççòòò‚‚‚???éééîîî¿¿¿,,,ÓÓÓÏÏÏÐÐÐRRR555ÔÔÔËËËâââdddjjjûûûâââæææææææææåååîîîÃÃÃ+++ÎÎÎËËËÌÌ̬¬¬±±±ÍÍÍÈÈÈÞÞÞfffeeeùùùàààääääääääääääâââìì줤¤ÖÖÖèèèäääêêê¼¼¼ÂÂÂåååííí¾¾¾,,,ÐÐÐËËËÌÌÌ«««±±±ÍÍÍÈÈÈÞÞÞbbbjjjûûûâââæææææææææåååïïïÂÂÂ///æææââââââêêêéééâââßßß÷÷÷tttkkkÿÿÿëëëïïïïïïïïïïïïíííøøø¬¬¬áááóóóïïïîîîùùù÷÷÷íííùùùÇÇÇ222èèèââââââêêêéééâââßßß÷÷÷pppmmmûûûâââæææææææææåååíííÈÈÈ`````````______```^^^jjj***YYYÌÌ̸¸¸¼¼¼¼¼¼¼¼¼¼¼¼ºººÂ‡‡‡°°°¿¿¿»»»¼¼¼ººº»»»ºººÂ   bbb``````______```^^^kkk&&&ffføøøâââæææææææææåååíííÇÇÇoooooonnnnnnnnnnnnnnnsss[[[†††ÅÅźºº¼¼¼¼¼¼¼¼¼¼¼¼ºººÂ‡‡‡°°°¿¿¿»»»¼¼¼»¼»¼¼¼»»»¿¿¿¯¯¯WWWqqqnnnnnnnnnnnnnnnnnntttXXX’’’ñññäääæææææææææåååïïïÁÁÁ333þþþûûûúúúøøøùùùúúúùùùÿÿÿÐÐÐÂÂÂùùùîîîïïïïïïïïïïïïíííøøø¬¬¬áááóóóïïïíïíðððîïîïïïòòòæææ°°°ÿÿÿùùùûûûûûûûûûûûûùùùÿÿÿÏÏÏÁÁÁïïïäääæææææææææåååïïïÂÂÂ///åååáááåååðððëëëêêêàààëëë¼¼¼¶¶¶îîîâââääääääääääääâââìì줤¤ÖÖÖèèèãäãíèíãäãíèíåååçççÛÛÛ   èèèáááââââââââââââáááëë뺺º¸¸¸ðððäääæææææææææåååïïïÂÂÂ000ééééééÖÖÖ¯¯¯KKK———ïïïííí¿¿¿¸¸¸ðððäääææææææææææææäääîî¥ØØØçéçïêï¡Ë¡N©N€½€éçéèèèÜÜÜ£££ìììäääææææææææææææäääïïï½½½ºººðððäääæææææææææåååïïïÂÂÂ000çççòòò¬¬¬???,,,xxxñññííí¿¿¿¸¸¸ðððäääææææææææææææäääîî¥×Ø×éééìèì55v¸v3›3ÙáÙëêëÜÜÜ£££ìììäääææææææææææææäääïïï½½½ºººðððäääæææææææææåååïïïÂÂÂ000éééåååèèè'''¶¶¶ñññììì¿¿¿¸¸¸ðððäääææææææææææææäääîî¥ØØØèéèîéî=¡=A£A›È›êèêçèçÜÜÜ£££ìììäääææææææææææææäääïïï½½½ºººðððäääæææææææææåååïïïÂÂÂ000éééäääîîîÌÌÌ222¾¾¾íííííí¿¿¿¸¸¸ðððäääææææææææææææäääîî¥ØØØèéèîéî´Ò´Y®Y•Æ•êçêèèèÜÜÜ£££ìììäääææææææææææææäääïïï½½½ºººðððäääæææææææææåååïïïÂÂÂ///çççäääãããèèèïïïåååãããííí¾¾¾···îîîâââääääääääääääâââìì줤¤ÖÖÖèèèãäãíèíæåæâãâåäåçççÛÛÛ¢¢¢ëëëãããååååååååååååãããîîî¼¼¼¹¹¹ðððäääæææææææææåååïïïÂÂÂ111ðððííííííìììëëëíííìììöööÅÅž¾¾÷÷÷ëëëííííííííííííëëëöööªªªÞÞÞñññíííëìëìíìííííííðððãã㨨¨ôôôìììííííííííííííììì÷÷÷ÄÄľ¾¾ðððäääæææææææææåååîîîÅÅÅ###¥¥¥¤¤¤£££¤¤¤£££¤¤¤£££ªªªˆˆˆƒƒƒ«««¢¢¢¤¤¤¤¤¤¤¤¤¤¤¤¢¢¢©©©vvv™™™¦¦¦£££¤¤¤£¤££¤££££¨¨¨“““%%%444333333333333333222777tttóóóãããæææææææææåååîîîÃÃÃ---ÞÞÞÛÛÛÛÛÛÛÛÛÙÙÙÚÚÚÚÚÚããã¶¶¶¯¯¯äääÙÙÙÛÛÛÛÛÛÛÛÛÛÛÛÙÙÙãããÍÍÍÞÞÞÛÛÛÚÛÚÙÚÙÚÛÚÙÙÙãã㸸¸$$$ªªª¦¦¦§§§¥¥¥¥¥¥¦¦¦¤¤¤···MMMjjjúúúâââæææææææææåååïïïÂÂÂ000ìììéééèèèäääîîîêêêçççòòòºººóóóçççééééééééééééçççñññ§§§ÚÚÚíííèèèéééõîõìêìæçæòòòÂÂÂ000ÝÝÝØØØÙÙÙâââãããßßßÔÔÔìììjjjkkkûûûâââæææææææææåååïïïÂÂÂ///éééåååêêêùùùÎÎÎáááçççîîî¿¿¿¸¸¸ðððäääææææææææææææäääîî¥ØØØéééçæçæææ¯Ð¯ÚáÚéæéîîî¿¿¿,,,ÒÒÒÍÍÍÌÌÌ£££°°°ÎÎÎàààcccjjjûûûâââæææææææææåååïïïÂÂÂ000èèèíííÀÀÀnnnsssñññííí¿¿¿¸¸¸ðððäääææææææææææææäääîî¥ØØØçéçñêño¶oQªQM©Màãàððð¿¿¿,,,ÓÓÓÎÎÎÒÒÒccc›››ÓÓÓááádddjjjûûûâââæææææææææåååïïïÂÂÂ000èèèïïﺺºPPPBBB”””ñññííí¿¿¿¸¸¸ðððäääææææææææææææäääîî¥×Ø×éééêèê-š-j´jI§IÝáÝñðñ¿¿¿,,,ÔÔÔÌÌÌÚÚÚ»»»DDDÝÝÝÊÊÊâââdddjjjûûûâââæææææææææåååïïïÂÂÂ000éééãããôôô••• ¶¶¶ðððììì¿¿¿¸¸¸ðððäääææææææææææææäääîî¥ØØØçéçñêñX­X8 8§Í§êçêîïî¿¿¿,,,ÓÓÓÎÎÎÒÒÒnnn444ÓÓÓËËËâââdddjjjûûûâââæææææææææåååïïïÂÂÂ///éééåååçççâââÎÎÎéééîîî¿¿¿¸¸¸ðððäääææææææææææææäääîî¤ÖÖÖçççèåèØß؇¿‡¢Ê¢æäæííí¾¾¾,,,ÒÒÒÍÍÍÍÍÍ}}}………ÑÑÑÉÉÉàààcccjjjûûûâââæææææææææåååïïïÂÂÂ111íííéééèèèêêêúúúíííçççòòò»»»óóóçççééééééééééééçççñññªªªâââõõõðððóòóÿ÷ÿûõûïïïúúúÉÉÉ///ÞÞÞØØØÙÙÙçççåååÙÙÙÖÖÖíííjjjkkkûûûâââæææææææææåååîîîÃÃÃ---ÜÜÜÙÙÙÙÙÙÙÙÙÖÖÖØØØØØØâââµµµ®®®ãããØØØÙÙÙÙÙÙÙÙÙÙÙÙ×××ááá‘‘‘¬¬¬ººº¸·¸···´¶´µ·µ¶¶¶¿¿¿™™™###§§§££££££      £££   ³³³KKKjjjúúúâââæææææææææåååîîîÆÆÆ'''¦¦¦¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤£££«««‰‰‰………«««£££¤¤¤¤¤¤¤¤¤¤¤¤£££¬¬¬,,, 333///000000000///111(((666555555555555555444999!!!vvvóóóãããææææææææææææçççâââÓÓÓîîîîîîîîîîîîîîîîîîíííïïïèèèçççïïïíííîîîîîîîîîîîîíííïïïÔÔÔäääíííëëëìììììììììëëëíííæææÓÓÓðððïïïïïïïïïïïïïïïïïïðððéééæææçççææææææææææææææææææçççëëëääääääääääääääääääääääääææææææääääääääääääääääääääääääëëëçççåååååååååååååååååååååçççëëëääääääääääääääääääåååäääææææææææææææææææææææææææææææææåååææææææææææææææææææææææææææææææææææææææææææææææææææææææååååååææææææææææææææææææææææææåååææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææ( @ æææææææææäääåååååååååäääææææææåååååååååååååååçççåååäääååååååäääåååæææåååååååååååååååæææçççæææææææææåååèèèííííííííííííîîîèèèæææêêêéééêêêêêêêêêåååëëëííííííííííííìììçççêêêêêêêêêêêêêêêèèèåååææææææîîîÇÇÇ;;;]]]YXYXYXXXX]]]CCCƒƒƒ¯¯¯¦¦¦¦§¦¦¦¦¯¯¯]]]NNN\\\YYYXXX[[[QQQLLL¬¬¬¦§¦¦§¦¦¦¦¯¯¯†††nnnòòòãããñññ¹¹¹ZZZÇÇǶ·¶½»½¼º¼¿¿¿¡ ¡±±±ÎÎÎÇÇÇÍÊÍÉÈÉÎÎβ²²¼¼¼ººº¿¿¿½½½­­­PPPÌÌÌÉÉÉÒÌÒËÉËÍÍ͵µµªªªîîîäääòòò¸¸¸gggâãâ×Ó×ÇÐÇÆÎÆÝÛݵ¶µ¹¹¹ÕÖÕÖÒּʼÊÎÊ×Öר©¨ÌÌÌØØØÖÖÖ½½½ØØØÇÇÇVVVÕÔÕÉÎɨèÄÌÄ×Ö×¾¾¾¶¶¶íííäääòòò¸¸¸abaæàæ—º—0š0t¯tâÙâ®°®¶·¶ÙÖÙz²z+˜+Ÿ¾ŸÝ×Ý£¥£ÈÈÈÈÈÈZZZ666ÆÆÆÄÄÄSSSÔÓÔÉÍÉd«d]©]Þ×Þº¼º³³³îîîäääòòò¸¸¸bcbáÞá¸Å¸2™2·áÙá®°®µ¶µÛÖÛ™¼™,–,¸Æ¸ÙÕÙ¤¥¤ÅÅÅ×××ooo@@@×××ÀÀÀSTSÑÑÑÔÐÔj­jZ§Zà×๻¹³³³îîîäääòòò···fffáâáÛÔۣģ¹Ê¹àÜà´µ´»¼»ÚÚÚÖÔÖ™À™ËÑËÛÚÛªªªËËËÛÛÛÇÇÇ›››ÛÛÛÆÆÆVVVÙØÙÎÒΔ¿”±È±ÝÚÝÀÀÀµµµîîîäääñññ¹¹¹ZZZÈÈȶ¸¶Ä¾Ä¿»¿¿¿¿¤¤¤§§§½¾½¸¹¸Å½Åº¹º½¾½•••²²²ººº¼¼¼ÄÄļ¼¼­­­LLL½¾½»»»Æ¾ÆÁ½Á¾¾¾«««¬¬¬îîîäääðððÁÁÁ***\\\UUUQSQSTS]]]888CCCccc]]][][]]]```KKKZZZ___[[[YYY___XXX$$$XXXVVVQSQRSR]]];;;aaaôôôãããòòò···gggåååÕÕÕåååÚÚÚæææ|||   ÿÿÿìììîîîíííôôô¿¿¿åååðððöööúúúòòòàààZZZØØØÖÖÖãããÞÞÞââ⟟Ÿwww÷÷÷âââòòò¸¸¸bbbßßß¼¼¼ttt¢¢¢ääävvv™™™ôôôáááäääãããêêê···ÚÚÚììì···   èèè×××VVVÑÑÑËËËÞÞÞ———vvv÷÷÷âââòòò¸¸¸cccÝÝÝÐÐÐRRR¤¤¤çççwwwšššöööãããæææåååëë븸¸ÞÞÞâââMMMKKKÒÒÒÞÞÞVVVÏÏÏÛÛÛiii„„„ççç———vvv÷÷÷âââòòò¸¸¸bbbÞÞÞ¿¿¿HHH¹¹¹âââvvvšššõõõâââåååäääëëë···ÜÜÜëëëZZZsssêêêØØØVVVÎÎÎÑÑÑTTT›››äää•••vvv÷÷÷âââòòò···jjjîîîÑÑÑ¿¿¿ØØØîîîžžžüüüéééëëëêêêñññ½½½áááñññåååÎÎÎïïïÝÝÝ]]]àààÚÚÚ¾¾¾ÔÔÔëë륥¥xxx÷÷÷âââñññ¼¼¼FFFššš———œœœQQQŽŽŽÝÝÝÍÍÍÏÏÏÎÎÎÔÔÔ¦¦¦ÇÇÇÑÑÑÑÑÑÖÖÖÒÒÒÆÆÆCCC‘‘‘———‘‘‘šššfffrrr÷÷÷âââððð¾¾¾===‡‡‡|||zzz|||ƒƒƒkkk£££ÉÉÉÁÁÁÂÂÂÁÁÁÇÇÇœœœºººÄÄÄ¿À¿¾À¾ÂÃÂÀÀÀppp~~~}}}~~~ƒƒƒnnnšššñññãããòòòµµµwwwÿÿÿøøøÿÿÿûûûÿÿÿÕÕÕÔÔÔóóóìììíííìììóóó¾¾¾äääðððôðôöñöñïñéééÂÂÂûûû÷÷÷øøø÷÷÷ýýýäääÅÅÅìììåååòòò¶¶¶lllöööÉÉÉzzzœœœôôôÀÀÀÊÊÊëëëäääåååãããêêê···ÛÛÛìéì–Å–x¹xÞâÞãâã³³³åååâââââââââçççÏÏϽ½½íííäääòòò¶¶¶lllÿÿÿ§§§)))ûûûÂÂÂÌÌÌìììåååæææåååëë븸¸ßÞßáåáF¡FU¬UÓßÓçäçµ¶µéééåååæææåååëëëÓÓÓ¿¿¿íííäääòòò¶¶¶nnnóóóìììfff¬¬¬÷÷÷ÂÂÂËËËêêêãããäääãããêêê···ÚÛÚîêî~»~½êçêááá³³³åååâââââââââçççÏÏϽ½½íííäääòòò¶¶¶rrrþþþêêêòòòëëëôôôËËËÒÒÒóóóìììíííìììóóó¾¾¾ãäãðððôðôçëçíîíêéêÂÂÂûûû÷÷÷÷÷÷÷÷÷üüüää䯯Æìììåååñññ¹¹¹\\\ÌÌ̼¼¼¾¾¾¾¾¾ÅÅŤ¤¤©©©ÄÄľ¾¾¿¿¿¾¾¾ÄÄÄ™™™¸¸¸ÁÁÁ½¾½À¿ÀÀÀÀ½½½iiiuuuvvvvvvuuuzzzeee–––ñññãããòòò¸¸¸eeeâââÎÎÎÒÒÒÒÒÒÙÙÙµµµ»»»ØØØÒÒÒÓÓÓÒÒÒØØØ©©©ËËËÔÕÔÓÓÓÔÓÔÕÕÕÉÉÉFFF™™™™™™›››£££mmmsss÷÷÷âââòòò¶¶¶qqqúúúððððððéééòòòÉÉÉÐÐÐñññêêêëëëéééððð¼¼¼áááðîðéêéäèäóðóÜÜÜ]]]ßßßÙÙÙÌÌÌÌÌÌèè褤¤xxx÷÷÷âââòòò¶¶¶lllýýý¶¶¶PPP‰‰‰ùùùÂÂÂËËËëëëäääåååäääëë븸¸ÜÜÜéèéu¹uY­YÙâÙÜÚÜVVVÏÏÏÑÑÑUUUrrrããã–––vvv÷÷÷âââòòò¶¶¶lllþþþººº///™™™ûûûÂÂÂÌÌÌìììåååæææåååëë븸¸ÞÝÞãæãA A`°`ÝåÝÛÚÛVWVÏÏÏÛÛÛnnn™™™ççç———vvv÷÷÷âââòòò¶¶¶nnnóóóïïïŽŽŽºººõõõÃÃÃËËËëëëäääåååäääëë븸¸ÛÛÛïëï§Ì§–Å–ìêìר×WWWÒÒÒÌÌÌppp¯¯¯ááᘘ˜vvv÷÷÷âââòòò¶¶¶pppùùùäääõõõíííïïïÈÈÈÎÎÎïïïèèèéééèèèîîî½½½âáâìììóîóðìðíííÜÜÜYYYÔÔÔÑÑÑÜÜÜÓÓÓÝÝÝ›››vvv÷÷÷âââñññºººXXX³³³³³³´´´»»»œœœ¡¡¡»»»µµµ¶¶¶´´´¿¿¿```NNN]]]XYXXYX[[[TTT$$$XXXVVVTTTUUU]]]<<<wwwõõõâââèèèàààÔÔÔäääâââãããâââãããßßßßßßãããâââãããâââäääÍÍÍÑÑÑÕÕÕÔÔÔÔÔÔÕÕÕÓÓÓÎÎÎÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙØØØàààçççææææææèèèëëëæææççççççççççççèèèèèèççççççççççççæææììììììêêêëëëëëëëëëëëëìììêêêêêêêêêêêêêêêêêêèèèææææææ(  åååÚÙÚÕÖÕÖ×ÖÚÙÚàáàßáßÝÜÝÖÖÖÕÕÕ×××ßßßàáààààÝÜÝåååÊÊÊ}~}¤ž¤–“–’”’ÄÁÄÊÅÊ£££ŽŽŽ¦¦¦ˆˆˆÊÇÊÁ¾Á¥¦¥ãããÁÂÁª¦ª É ±Ç±ÈÀȰŰ•½•ÇÂÇÇÇÇ”””³³³¢¢«É«§Á§ÇÂÇãäãÁÂÁ­¨­žÈž¯Æ¯ÍÄͶʶ•Á•ÊÅÊÈÉÈŽŽŽ²³²§¢§¬Í¬§Å§ÍÇÍãäãÆÆÆttt¤Ÿ¤–”–{|{›˜› › ‰‰‰‘‘‘«««‰‰‰jjj ž –“–‹‹‹æåæÃÃÃššš²²²®¯®‘‘ÙÚÙÛÛÛÇÇÇÎÎÎÁÁÁ¿¿¿”””´´´¯¯¯“““áááÀÀÀ²²²¡¡¡¸¸¸¥¥¥ìììïïïÛÛÛØØØyyyÇÇǯ¯¯§§§²³²¥¥¥ßßßÄÄĈˆˆ©©©£££‡‡‡ÜÜÜÛÛÛÆÆÆÏÏÏÖÖÖÄÄăƒƒ©©©¦¦¦‡‡‡äääÄÄÄŽŽŽÄÄij³³­­­×××ØØØÃÃÃÎÍÎàÞàÎÎΧ§§¹¹¹´´´®®®æææ¿¿¿ÃÃߟŸ¿¿¿ßßßçççíííØ×ØØÝØ}Á}ÕÜÕÞÜÞóôóòòòÕÕÕäääÁÁÁµµµÄÄÄÉÉÉÐÐÐãããçççÑÑÑÖØÖ°Ñ°ØÛØÐÏÐáááßßßÍÍÍåååÃÃÞžžèèèÔÔÔ¶¶¶ÎÎÎÑÑѼ¼¼ÇÆÇèÜèÃÁÃ}}}žžž–––ˆˆˆæææÁÁÁ¸¸¸ºººÇÇÇÕÕÕåååêêêÔÓÔ×ÙרҨÅÊÅ£¡£²³²²²²ààà¿¿¿¾¾¾£££¼¼¼ÚÚÚçççìììÚØÚÝâÝÎÍÓÍ«©«¬¬¬···¡¡¡àààÅÅÅ¥¥¥áááÒÒÒ¼¼¼ÑÑÑ×××µµµŸžŸµ±µ™™™vvv¢¢¢ššš†††åååâââÚÚÚÝÝÝÝÝÝÜÜÜÝÝÝßßßÖÖÖÉÉÉËËËËËËÎÎÎÏÏÏÍÍÍ×××ççç(0` çéçéæéåååìììÔÔÔòëòÚÚÚÌÌÌ ---222KKK›››”””$$$===òòòÃÃ稧¤¤¤ŠŠŠ¼È¼„„„ÚÒÚ´´´«««ÑÏÑר×çÝçµÆµ¼¼¼¦Á¦«Ã«f¬f’ºS¥Syyy¹Ç¹m®m4œ4{³{D£D;;…¶…s¯sN©NSSS,™, Š Ÿ¿Ÿ&•&dddŒ¹Œt°tèÝèÛáÛBBBkkkûûû]]]ttt¸·¸£Ë£„¾„v¸v›È›´Ò´Y®Y•Æ•¯Ð¯mµmQªQýöý              !""#$#%&'!(  )*+, !-./01+ 2 3/ /45-67 86/ 0)9 ,0 : ; :(     < ==>> ==> ;77>; ;7=> (?7=>@ (? 7=> ;=7> =  7=> A<=7> 2( <;7=> 2 ==>;<  2 7=> 77>  ?=> @=>>>> >@=> 7?77?7?= ?A A A  77??7??=7=@====@@?A  A A 2@@==@==(2 >>>>>>>>>>>>>>>> A; A  B1C A  ( A+D+;  A--E    FGH   A A  >> (  (  A = A ;==> >AI;  7=>; =@AJK1 7 7=> A2< A3J-;  7=> AG.B = ;7=> AHB (7=> > LL> ==> ;A; AAAA   =    @( @äääêçêæêæëëëóóóñîñÅÍÅ;;;ddd[[[TTTDDD„„„®°®¤¤¤LLL¬¬¬ttt¶¸¶ÃÄõµµ¼¼¼Ã¾ÃÌÌÌÔÓÔ›››ÒÌÒÛÖÛÛÛۻʻ»Ã»–½–1š1t¯tà×àz²z+˜+œ½œ666d«d[«[áÛáÕÜÕlllj­jZ§Z£Ä£™À™ÍÒÍ·±È±”””+++$$$|||üüüÜãÜ–Å–{º{D¡DU¬Uu¹u`°`§Ì§          !"#$% & '() "%$*+ ,-"./0 12" 34      5 +677) 6) !3 8 0 3    37+67)  333 900 93339666 +6 ! +67777777+6:;8))))+7497<=*)+7;;7777 +60 ++70 68+79>=8  37+7&7?@>ABCDEFGHIJK$LMN%OPQRSGTUVWXKYZ$P[2V \]^_K7`\a]^b\\&c YEdeL[fOghNEiN jklmnopqrbMs\tujvwxyzR {E|}~Lv€‚ƒ„|…hMU†$‡ˆ‰Š‹Œ2G NŽ€jW‘’“”•–T —VR˜€v s™š›œFžŸ  _  t¡¡L`{ j(0`€€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿp%€%€ˆˆxˆ€%%R‡ˆ‡ˆp€ˆˆ‚€ˆˆwwˆxˆ‚…ˆ…(xxˆˆxuwwww‡wwwwxw÷wwww÷÷xrwww‡w‡wwwwxwwwwwwwwwxpwxww‡w‡wx÷wx‡w(wx‡wx‚wx"ww‡w‚(wxwx ‡wˆ‚wx…wrˆww‡wˆ¨wxwu€‡www'wx‚ww¢ww‡wx'wxww€wwww¨wxuwwˆww‡wx'wxww€‡wwxˆwx…wwwww‡wwwwxwwwwwwwwx‚÷wwwwwww÷xwwww÷wwx€…€ˆ€ˆ(€ˆ€ˆ…"ˆˆ"€€p‚%€ˆˆ(ˆˆˆ€ˆXXˆ€‚ww÷wøÿ÷ÿÿøÿÿ÷ÿÿÿwwðuwwwwxÿÿÿÿøÿÿÿÿÿwwwwpp÷wˆwxÿÿÿÿ÷ÿÿxÿÿwx‡wppwxwwÿÿÿÿøÿø%ÿwxwp…wwwxÿÿÿÿøÿøX/ÿwxWwðpwwˆwwÿÿ÷ÿøÿøÿwx'wp€wwwx_ÿÿÿÿ÷ÿÿ(ÿˆwpwðˆwwwwxÿÿÿÿøÿÿÿÿÿwwwpˆwww÷wÿÿÿÿ÷ÿÿÿÿÿ'w÷wwðpˆˆˆˆ‚w÷w÷ø÷w÷wˆˆˆˆ€€€€‚€'w‡xxx‡‡w‡w( €pÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿÿÿøÿpÿÿÿÿ÷ÿÿÿÿøÿÿÿÿÿÿÿÿÿ÷ˆÿ÷ÿÿÿÿÿÿøÿÿwÿÿÿÿÿÿ÷ÿˆÿ÷€ÿÿÿÿÿ÷ÿ÷ˆÿÿÿÿÿ÷ÿpÿð€ÿÿÿÿÿøÿø¨/ÿÿÿÿÿøpÿ÷÷ÿ÷ÿÿ÷ÿø(ÿÿÿÿÿÿ÷ÿpÿÿ€ÿÿwÿÿÿÿøÿ÷Šÿÿÿÿ÷€ÿÿÿÿÿÿÿÿÿ÷ÿÿ÷ÿÿÿÿÿÿøÿxÿÿÿÿÿÿÿÿÿøÿÿÿÿÿÿÿÿÿ÷pÿ÷÷÷÷ÿxwÿ÷ÿ‡÷øwwxp‡xxwx‡wwxwxwx‡xwpÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿwww÷ðpÿÿÿÿ÷ÿÿÿÿøÿÿÿÿÿwwwppÿÿ÷ÿÿÿÿÿÿ÷ÿÿ÷ÿÿwx‡wpˆÿ÷€ÿÿ÷ÿÿøÿ÷(ÿwxwðˆÿð€ÿÿÿÿÿ÷÷øˆ/ÿwxwppÿ÷ÿÿÿÿÿøÿø(ÿÿXwx‡wppÿÿ€ÿÿÿ÷ÿ÷ÿ÷‚ÿwxwðpÿÿ÷ÿÿÿÿÿÿøÿÿÿÿwxwwp€ÿÿÿÿ÷ÿÿÿøÿÿÿÿÿwwwðxÿÿÿÿÿÿÿÿÿ÷÷÷w÷÷wxxxppxwˆxx‡xx‡‡€wÿÿÿÿÿÿÿÿÿ÷÷ÿ÷÷ÿÿÿÿ÷ÿ( @€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ÷w÷÷÷÷÷w÷÷÷p(XR'‡‡uX(x‡xWxw÷‡wxwwˆ÷w÷uwwww÷www÷wˆwwwx÷ªw‡ø‡ww€ˆw¨x…wˆ÷wx§xw‚wˆ÷ˆ÷wxwˆww‡wxwˆ§wr÷ÿw÷÷÷ˆwÿwp‚X(U(%‚‚XXX%‚_uwwx'wwx‡wwˆ‡wxx÷wwW÷ÿwÿ÷ÿˆ÷÷÷uw(‡ÿ÷rˆ÷w/ˆ÷ˆw/÷÷Rˆ‡øxwˆW÷ø÷xˆ÷(w‡xw÷‡ÿ÷÷÷ÿˆø‡pˆˆˆw÷ø‡÷w…ˆˆˆ_pˆ‡ˆ‡wwwwwwxˆˆˆ‡xÿÿÿwÿÿ÷ÿÿÿrÿˆÿ÷÷xwwÿ÷xw…w÷wÿŠÿ÷wx÷ˆ÷w÷÷÷wˆwÿ÷ÿwˆÿwÿÿ÷÷÷w÷ÿ÷ˆw÷÷ww÷wwwwwwuww‡‡wwxwww€€€€ˆ÷ÿÿ÷ÿÿÿˆ÷÷øx÷ww÷wwwx÷ˆw/x÷ÿÿx‚ˆwˆwˆÿˆwwÿ÷Šˆw‡÷‡xwÿw÷÷øˆwwxx÷÷w÷ÿ÷ÿ÷ˆ÷wwWˆwww‡wwˆ(R%€w÷÷÷÷÷÷wÿÿ( €€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ÷w÷wÿxˆ‡w‡‡wwwwwwxxwww‡wwxwwwxxˆˆ‡ˆˆxw÷wxwwˆ÷øw‡wxw‡wwxw‡xww÷wwwwwøww÷ww÷x÷wwxˆwwwwwwwwwwÿÿ÷xxø÷w÷‡ˆxww÷wwpuzzles-20170606.272beef/icons/fifteen.ico0000644000175000017500000006117613115373727017137 0ustar simonsimon 00 ¨%–  ¨>& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕØØØÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕØØØÇÇÇÖÖÖùùùôôôõõõõõõõõõõõõõõõõõõõõõõõõõõõõõõõõõõõõõõõõõõõõõõõõöööôôôíííîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîîïïïíííÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÄÄÄ»»»ÛÛÛÖÖÖ×××××××××××××××××××××××××××××××××××××××××××××××××××ííí¿¿¿¶¶¶¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¶¶¶´´´ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÅÅŽ½½ØØØÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÓÓÓôôôÜÜÜÕÕÕ×××ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×××ÔÔÔ´´´ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÄÄļ¼¼ÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔôôôÚÚÚÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓ´´´ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÄÄļ¼¼ÙÙÙÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÓÓÓôôôÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÓÓÓ´´´ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÅÅÅ»»»ÛÛÛØØØÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙ×××õõõÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÓÓÓ´´´ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÄÄÄÀÀÀÍÍÍÂÂÂÄÄÄÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄÄòòòÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÓÓÓÒÒÒÒÒÒÓÓÓÔÔÔÒÒÒÒÒÒÓÓÓÕÕÕÕÕÕÕÕÕÖÖÖÓÓÓ´´´ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÁÁÁÓÓÓÚÚÚ¸¸¸¾¾¾½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½½¿¿¿­­­éééÝÝÝÓÓÓÕÕÕÕÕÕÔÔÔßßßãããäääÝÝÝÛÛÛääääääßßßÕÕÕÕÕÕÕÕÕÖÖÖÓÓÓ´´´ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÁÁÁÓÓÓìììÕÕÕÚÚÚÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙØØØÝÝݺººèèèÝÝÝÓÓÓÕÕÕÓÓÓÝÝÝnnn999666zzz®®®AAA;;;“““ÛÛÛÔÔÔÕÕÕÖÖÖÓÓÓ´´´ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÀÀÀÓÓÓêêêÐÐÐÕÕÕÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔØØØ···èèèÝÝÝÓÓÓÕÕÕÔÔÔÖÖÖ¼¼¼222777ÆÆÆ¤¤¤ŸŸŸƒƒƒ»»»ÜÜÜÓÓÓÖÖÖÓÓÓ´´´ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÀÀÀÓÓÓêêêÑÑÑÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙ¸¸¸èèèÝÝÝÓÓÓÕÕÕÕÕÕÒÒÒìììNNNWWWððð¾¾¾   nnn¼¼¼ÛÛÛÓÓÓÖÖÖÓÓÓ´´´ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÀÀÀÓÓÓêêêÑÑÑÖÖÖÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙ¸¸¸èèèÝÝÝÓÓÓÕÕÕÕÕÕÒÒÒâââMMMNNNïïï“““YYY¢¢¢ÛÛÛÔÔÔÕÕÕÖÖÖÓÓÓ´´´ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÀÀÀÓÓÓêêêÑÑÑÖÖÖÕÕÕÕÕÕÖÖÖØØØ×××ØØØÕÕÕ×××ØØØÔÔÔÔÔÔÕÕÕÕÕÕÔÔÔÙÙÙ¸¸¸èèèÝÝÝÓÓÓÕÕÕÔÔÔÚÚÚnnnXXXííí•••MMMfffÖÖÖÕÕÕÕÕÕÖÖÖÓÓÓ´´´ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÀÀÀÓÓÓêêêÑÑÑÖÖÖÕÕÕÖÖÖÐÐÐÊÊÊÎÎÎÉÉÉÖÖÖÐÐÐÈÈÈÛÛÛÚÚÚÔÔÔÕÕÕÔÔÔÙÙÙ¸¸¸èèèÝÝÝÓÓÓÕÕÕÔÔÔ××׺ºº›››¹¹¹ÚÚÚÈÈÈžžž¡¡¡ÖÖÖÕÕÕÕÕÕÖÖÖÓÓÓ´´´ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÀÀÀÓÓÓêêêÑÑÑÖÖÖÓÓÓßßß———EEE­­­444,,,@@@¿¿¿ÙÙÙÔÔÔÔÔÔÙÙÙ¸¸¸èèèÝÝÝÓÓÓÕÕÕÕÕÕÔÔÔÛÛÛâââÛÛÛÔÔÔØØØáááäääàààÕÕÕÕÕÕÕÕÕÖÖÖÓÓÓ´´´ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÀÀÀÓÓÓêêêÑÑÑÖÖÖÕÕÕÓÓÓÞÞÞ„„„ÎÎÎÈÈȹ¹¹¸¸¸ €€€äääÒÒÒÔÔÔÙÙÙ¸¸¸èèèÝÝÝÓÓÓÕÕÕÕÕÕÕÕÕÔÔÔÒÒÒÔÔÔÕÕÕÔÔÔÓÓÓÒÒÒÓÓÓÕÕÕÕÕÕÕÕÕÖÖÖÓÓÓ´´´ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÀÀÀÓÓÓêêêÑÑÑÖÖÖÕÕÕÒÒÒççç’’’ÑÑÑååå§§§(((ÃÃÃÙÙÙÔÔÔÔÔÔÙÙÙ¸¸¸èèèÝÝÝÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÓÓÓ´´´ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÀÀÀÓÓÓêêêÑÑÑÖÖÖÔÔÔÕÕÕÑÑÑxxxÒÒÒÐÐÐÁÁÁ¥¥¥¢¢¢ßßßÓÓÓÔÔÔÙÙÙ¸¸¸èèèÝÝÝÔÔÔÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÓÓÓµµµÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÀÀÀÓÓÓêêêÑÑÑÖÖÖÓÓÓÞÞÞššš222ÔÔÔÉÉÉGGG)))222¼¼¼ÚÚÚÔÔÔÔÔÔÙÙÙ¸¸¸èèèÚÚÚÐÐÐÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÑÑÑÒÒÒÏÏϱ±±ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÀÀÀÓÓÓêêêÑÑÑÖÖÖÕÕÕÕÕÕÕÕÕÌÌÌÍÍÍÕÕÕÖÖÖÍÍÍÅÅÅØØØÚÚÚÔÔÔÕÕÕÔÔÔÙÙÙ¸¸¸éééëëëãããååååååååååååååååååååååååååååååååååååååååååååååååÅÅÅÒÒÒÖÖÖÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÀÀÀÓÓÓêêêÑÑÑÖÖÖÕÕÕÕÕÕÕÕÕØØØ×××ÕÕÕÕÕÕ×××ÙÙÙÕÕÕÔÔÔÕÕÕÕÕÕÔÔÔØØØ¹¹¹àààâââÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÜÜÜÞÞÞÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÀÀÀÓÓÓêêêÑÑÑÖÖÖÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔÕÕÕÕÕÕÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙ¸¸¸äääÇÇǹ¹¹¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼ººº®®®ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÀÀÀÓÓÓêêêÑÑÑÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙ¸¸¸èèèáááØØØÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚØØØ¶¶¶ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÀÀÀÓÓÓëëëÑÑÑÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÕÕÕÙÙÙ¹¹¹èèèÜÜÜÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÒÒÒ´´´ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÀÀÀÓÓÓçççÍÍÍÒÒÒÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÐÐÐÕÕÕ³³³çççÝÝÝÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÓÓÓ´´´ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÁÁÁÒÒÒùùùéééìììëëëëëëëëëëëëëëëëëëëëëëëëëëëëëëëëëëëëëëëëëëîîîÙÙÙíííÜÜÜÓÓÓÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÓÓÓ´´´ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÃÃÃÃÃÃëëëæææçççççççççççççççççççççççççççççççççççççççççççççèèèæææ÷÷÷ÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÙÙÙÙÙÙÙÙÙÙÙÙÓÓÓÒÒÒÖÖÖ×××ÔÔÔÕÕÕÕÕÕÖÖÖÓÓÓ´´´ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÅÅÅ»»»ÕÕÕÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÐÐÐôôôÚÚÚÔÔÔÕÕÕÕÕÕÖÖÖÆÆÆÅÅÅÄÄÄÆÆÆÜÜÜãããÓÓÓÐÐÐÛÛÛÔÔÔÕÕÕÖÖÖÓÓÓ´´´ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÄÄĽ½½ÚÚÚÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÕÕÕôôôÚÚÚÔÔÔÕÕÕÓÓÓÝÝÝgggnnnÄÄĪªªIII666ÎÎÎÖÖÖÔÔÔÖÖÖÓÓÓ´´´ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÄÄļ¼¼ÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔôôôÚÚÚÔÔÔÕÕÕÕÕÕÓÓÓáááFFFNNNîîîFFF%%%¥¥¥ÝÝÝÓÓÓÖÖÖÓÓÓ´´´ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÄÄļ¼¼ÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔôôôÚÚÚÔÔÔÕÕÕÕÕÕÒÒÒëëëMMMPPPñññ„„„jjjkkkAAAèèèÒÒÒÕÕÕÖÖÖÓÓÓ´´´ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÄÄļ¼¼ÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔôôôÚÚÚÔÔÔÕÕÕÕÕÕÔÔÔÄÄÄ;;;RRRâââÜÜÜXXXIIIáááÓÓÓÕÕÕÖÖÖÓÓÓ´´´ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÄÄļ¼¼ÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔôôôÚÚÚÔÔÔÕÕÕÔÔÔÛÛÛmmm kkkßßßØØØÃÃÃZZZàààÓÓÓÕÕÕÖÖÖÓÓÓ´´´ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÄÄļ¼¼ÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔôôôÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕ×××ÑÑÑÓÓÓÕÕÕÔÔÔØØØÖÖÖÒÒÒÕÕÕÕÕÕÕÕÕÖÖÖÓÓÓ´´´ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÄÄļ¼¼ÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔôôôÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕ×××ÖÖÖÕÕÕÕÕÕÔÔÔÕÕÕÖÖÖÕÕÕÕÕÕÕÕÕÖÖÖÓÓÓ´´´ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÄÄļ¼¼ÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔôôôÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÓÓÓ´´´ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÄÄļ¼¼ÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔôôôÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÓÓÓ´´´ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÄÄļ¼¼ÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔôôôÛÛÛÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÔÔÔµµµÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÅÅŽ½½ÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔôôôÖÖÖÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÏÏϰ°°ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÃÃû»»ÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔõõõñññìììíííííííííííííííííííííííííííííííííííííííííííííïïïÓÓÓÒÒÒÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÐÐÐÍÍÍÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔßßßæææååååååååååååååååååååååååååååååååååååååååååååååååæææâââÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÑÑÑÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ( @ ÕÕÕÕÕÕÔÔÔÓÓÓÔÔÔÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÔÔÔÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÕÕÕÕÕÕÕÕÕÔÔÔØØØÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÚÚÚÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÞÝÝÝÖÖÖÕÕÕ×××ÏÏÏÍÍÍîîîêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêëëëíííØØØ×××ØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØÕÕÕÕÕÕ×××ÏÏϽ½½ÕÕÕÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÒÒÒéééËËËÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÊÊÊ···ÏÏÏ××××××ÏÏÏÀÀÀØØØÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔìììÚÚÚ×××ØØØØØØØØØØØØØØØØØØØØØØØØ×××ÛÛÛÁÁÁÏÏÏ××××××ÏÏϾ¾¾ÚÚÚØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØØííí×××ÔÔÔÕÕÕÓÓÓÒÒÒÓÓÓÔÔÔÒÒÒÓÓÓÕÕÕÔÔÔ××׿¿¿ÏÏÏ××××××ÏÏÏÄÄÄÊÊÊÁÁÁÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÂÃÃÃÁÁÁçççØØØÔÔÔÔÔÔÜÜÜäääàààÛÛÛåååÛÛÛÔÔÔÕÕÕ××׿¿¿ÏÏÏ××××××ÌÌÌÒÒÒÚÚÚÇÇÇËËËËËËËËËËËËËËËËËËËËËËËËÊÊÊÎÎν½½ÝÝÝÚÚÚÓÓÓÚÚÚ³³³‹‹‹ŸŸŸººº†††½½½ÚÚÚÓÓÓØØØ¿¿¿ÏÏÏ××××××ÌÌÌÑÑÑãããÕÕÕØØØ××××××××××××××××××××××××ÛÛÛÇÇÇÝÝÝÚÚÚÓÓÓÚÚÚµµµ~~~°°°www***ËËË×××××׿¿¿ÏÏÏ××××××ÌÌÌÑÑÑáááÒÒÒÕÕÕÔÔÔÒÒÒÒÒÒÔÔÔÒÒÒÓÓÓÕÕÕÔÔÔØØØÅÅÅÝÝÝÚÚÚÔÔÔÒÒÒêêêPPPººº±±±bbbVVVÐÐÐÖÖÖ××׿¿¿ÏÏÏ××××××ÌÌÌÑÑÑáááÒÒÒÕÕÕØØØãããâââÛÛÛäääÞÞÞÕÕÕÕÕÕØØØÆÆÆÝÝÝÚÚÚÒÒÒÜÜÜ¢¢¢¾¾¾‰‰‰ŒŒŒÛÛÛÓÓÓ××׿¿¿ÏÏÏ××××××ÌÌÌÑÑÑáááÑÑÑÙÙÙÆÆÆ”””¹¹¹©©©ØØØÔÔÔØØØÆÆÆÝÝÝÚÚÚÓÓÓØØØÃÃí­­ÓÓÓËËË©©©°°°ÖÖÖÔÔÔ××׿¿¿ÏÏÏ××××××ÌÌÌÑÑÑáááÑÑÑ×××ÐÐÐ@@@MMM···xxx&&&§§§ÞÞÞÖÖÖÆÆÆÝÝÝÚÚÚÔÔÔÔÔÔÙÙÙÞÞÞÕÕÕØØØàààÝÝÝÕÕÕÕÕÕ××׿¿¿ÏÏÏ××××××ÌÌÌÑÑÑáááÒÒÒÑÑÑííízzzöööžžž***ºººÛÛÛ×××ÆÆÆÝÝÝÛÛÛÔÔÔÖÖÖÕÕÕÔÔÔÕÕÕÕÕÕÔÔÔÔÔÔÖÖÖÕÕÕØØØÀÀÀÏÏÏ××××××ÌÌÌÑÑÑáááÑÑÑÙÙÙÆÆÆ+++}}}ÑÑÑkkk,,,¹¹¹ÛÛÛ×××ÆÆÆÝÝÝ×××ÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÑÑÑÔÔÔ»»»ÏÏÏ××××××ÌÌÌÑÑÑáááÒÒÒ×××ÎÎΫ««ÈÈÈÓÓÓ¦¦¦»»»ØØØÔÔÔØØØÅÅÅßßßéééãããäääääääääääääääääääääääääääçççÓÓÓÐÐÐÖÖÖ×××ÌÌÌÑÑÑáááÒÒÒÕÕÕ×××ßßßØØØÕÕÕàààÛÛÛÔÔÔÕÕÕØØØÆÆÆ×××ÑÑÑËËËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÈÈÈÓÓÓÖÖÖ×××ÌÌÌÑÑÑâââÓÓÓÖÖÖÕÕÕÔÔÔÕÕÕÖÖÖÔÔÔÔÔÔÖÖÖÕÕÕÙÙÙÆÆÆÝÝÝÕÕÕÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÏÏÏÒÒÒºººÏÏÏ××××××ÌÌÌÑÑÑßßßÏÏÏÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÑÑÑÕÕÕÂÂÂÜÜÜÛÛÛÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÙÙÙÀÀÀÏÏÏ××××××ÌÌÌÑÑÑîîîáááäääããããããããããããããããããããããããæææØØØãããÙÙÙÔÔÔÕÕÕÔÔÔÑÑÑÓÓÓÕÕÕÓÓÓÒÒÒÕÕÕÔÔÔ××׿¿¿ÏÏÏ××××××ÎÎÎÄÄÄæææããããããããããããããããããããããããããããããããããããïïïÖÖÖÕÕÕÔÔÔÛÛÛåååààà×××ÞÞÞâââÕÕÕÔÔÔØØØ¿¿¿ÏÏÏ×××ÖÖÖÏÏϾ¾¾ÔÔÔÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÑÑÑëëë×××ÓÓÓÝÝÝ£££SSSwwwÑÑÑ¡¡¡|||×××ÔÔÔ××׿¿¿ÏÏÏ××××××ÏÏÏ¿¿¿ØØØÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÕÕÕììì×××ÔÔÔÖÖÖÎÎÎ222žžžiii444%%%ÈÈÈ×××××׿¿¿ÏÏÏ××××××ÏÏÏ¿¿¿×××ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔììì×××ÔÔÔÔÔÔÛÛÛCCC···²²²AAAWWWâââÑÑÑØØØ¿¿¿ÏÏÏ××××××ÏÏÏ¿¿¿×××ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔììì×××ÓÓÓÞÞÞœœœ///¶¶¶ëëë[[[YYYáááÒÒÒ××׿¿¿ÏÏÏ××××××ÏÏÏ¿¿¿×××ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔììì×××ÔÔÔÕÕÕÔÔÔÔÔÔÖÖÖÔÔÔÜÜÜÖÖÖÕÕÕÔÔÔ××׿¿¿ÏÏÏ××××××ÏÏÏ¿¿¿×××ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔììì×××ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÕÕÕÔÔÔ××׿¿¿ÏÏÏ××××××ÏÏÏ¿¿¿×××ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔìììØØØÕÕÕÖÖÖÕÕÕÕÕÕÕÕÕÖÖÖÕÕÕÕÕÕÖÖÖÕÕÕØØØÀÀÀÏÏÏ××××××ÏÏÏ¿¿¿ØØØÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔìììÕÕÕÒÒÒÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÒÒÒÕÕÕ¼¼¼ÏÏÏ×××ÖÖÖÐÐÐÀÀÀ×××ÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔîîîíííêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêíííÝÝÝÒÒÒÖÖÖÕÕÕÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÓÓÓÔÔÔÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÓÓÓÓÓÓÕÕÕÕÕÕ(  ÕÕÕÙÙÙÛÛÛÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÙÚÚÚÖÖÖÐÐÐÔÔÔáááÞÞÞÞÞÞÞÞÞÞÞÞáááÞÞÞÑÑÑÒÒÒÑÑÑÑÑÑÓÓÓÏÏÏÓÓÓÏÏÏÉÉÉÔÔÔÒÒÒÒÒÒÓÓÓÒÒÒÖÖÖßßßÒÒÒÚÚÚÙÙÙØØØÖÖÖÊÊÊÏÏÏÑÑÑÎÎÎÊÊÊÈÈÈÈÈÈÈÈÈÉÉÉÉÉÉÛÛÛ×××»»»¾¾¾ÁÁÁÖÖÖÌÌÌÐÐÐÐÐÐØØØÖÖÖÚÚÚÜÜÜÛÛÛ×××ÐÐÐÖÖÖààà€€€ˆˆˆ]]]ÊÊÊÏÏÏÏÏÏÐÐÐÖÖÖÙÙÙ¿¿¿¸¸¸¾¾¾ÔÔÔÑÑÑØØØÙÙÙ¢¢¢§§§‹‹‹ÙÙÙÌÌÌÏÏÏÐÐÐÕÕÕââ⌌ŒŽŽŽdddµµµØØØ×××ÔÔÔÙÙÙÚÚÚÛÛÛÕÕÕÊÊÊÏÏÏÐÐÐÖÖÖÝÝݤ¤¤µµµ’’’ÈÈÈÓÓÓÚÚÚÚÚÚØØØØØØ×××ÛÛÛÒÒÒÑÑÑÑÑÑ×××ÔÔÔØØØÖÖÖÚÚÚ×××ÎÎÎÕÕÕÑÑÑÏÏÏÐÐÐÏÏÏÒÒÒÌÌÌÑÑÑÐÐÐÚÚÚÞÞÞÛÛÛÛÛÛÚÚÚÝÝÝÙÙÙÚÚÚÔÔÔÝÝÝÜÜÜÜÜÜØØØËËËÏÏÏÏÏÏÑÑÑßßßÜÜÜÜÜÜÜÜÜÜÜÜßßßààà×××®®®µµµ¶¶¶ÑÑÑÍÍÍÏÏÏÐÐÐÊÊÊÕÕÕÓÓÓÓÓÓÓÓÓÓÓÓÖÖÖÞÞÞÝÝ݃ƒƒIIIÍÍÍÎÎÎÏÏÏÐÐÐÌÌÌ×××ÕÕÕÕÕÕÕÕÕÕÕÕØØØßßß××ר¨¨ÈÈȧ§§ÕÕÕÌÌÌÐÐÐÏÏÏËËË×××ÕÕÕÕÕÕÕÕÕÔÔÔØØØßßßÑÑÑÛÛÛÖÖÖÛÛÛÕÕÕÉÉÉÏÏÏÐÐÐÌÌÌ×××ÕÕÕÕÕÕÕÕÕÕÕÕ×××äääÞÞÞÝÝÝÞÞÞÜÜÜàààÖÖÖÑÑÑÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÙÙÙÛÛÛÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÕÕÕ(0` ÕÕÕÔÔÔØØØÖÖÖ×××ÇÇÇùùùôôôõõõöööíííîîîïïïÙÙÙÄÄÄ»»»ÛÛÛ¿¿¿¶¶¶¸¸¸´´´ÅÅŽ½½ÓÓÓÜÜܼ¼¼ÚÚÚÀÀÀÍÍÍÂÂÂÃÃÃòòòÒÒÒÁÁÁ¾¾¾­­­éééÝÝÝßßßãããäääìì캺ºèèènnn999666zzz®®®AAA;;;“““êêêÐÐз··222777ÆÆÆ¤¤¤ŸŸŸƒƒƒÑÑÑNNNWWWððð   âââMMMYYY¢¢¢XXX•••fffÊÊÊÎÎÎÉÉÉÈÈÈ›››¹¹¹žžž¡¡¡———EEE444,,,@@@áááàààÞÞÞ„„„ €€€ççç’’’ååå§§§(((xxx¥¥¥µµµšššGGG)))ÏÏϱ±±ÌÌÌëëë³³³æææ÷÷÷gggªªªIIIFFF%%%PPPñññjjjkkkRRRmmm ZZZ°°°            !"#$%&'(%((& !) %*+%%,-./0123 456+%789:;<= 4> +% )?@A"B,C 4> +% DE? 3FGH 4> +%,IJ KLEM 4>5NOP5Q +%*RSQTUV 4>&WXYZ#[\]  +%D^(_ 4>`abOQScd(  +%   4> efg>hijk  +% 4>>lg 5!mnH& +%o 4>`pq7Prs7 +5 > tu 4>v $w'hhhhhhhhhhhhhhhh  4> S_D%%%%%%%%%%%%%%`  4> (S*0 4> +^ w> S+  e >>>>>>>>>>>>>5xe% ! $)wwwwwwwwwwwwww  wyeeeeeeeeeeeeeee+yz  >>>>>>>>>>>>>>>>>599'5 %{LL,|}.O ^~? ~gnm%  wE€a‚ƒ1+  2„DJ…}^ †‡ƒ&Yˆ_ >     o 5>>>>>>>>>>>>>> t‰  )  5&yhhhhhhhhhhhhhhhhyD > ( @ÕÕÕÔÔÔÓÓÓØØØÛÛÛÚÚÚÞÞÞÝÝÝÖÖÖ×××ÏÏÏÍÍÍîîîêêêëëëííí½½½ÒÒÒéééËËËÈÈÈÊÊÊ···ÀÀÀìììÁÁÁ¾¾¾¿¿¿ÄÄÄÂÂÂÃÃÃçççÜÜÜäääàààåååÌÌÌÇÇÇÎÎγ³³‹‹‹ŸŸŸººº†††ÑÑÑãããµµµ~~~°°°www***áááÅÅÅPPP±±±bbbVVVÐÐÐâââÆÆÆ¢¢¢‰‰‰ŒŒŒÙÙÙ”””¹¹¹©©©­­­@@@MMMxxx&&&§§§zzzöööžžž+++}}}kkk,,,»»»«««¦¦¦ßßßæææïï£SSS¡¡¡|||222iii444%%%CCC²²²AAAWWWœœœ///¶¶¶[[[YYY¼¼¼           !"#  $%&'()*+ $,- %./0123  $,45 6*789:  $,4-;!< =>?@A  $,4,B& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $æææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææåååââââââââââââââââââââââââãããæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææåååéééøøø÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷øøøôôôææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææåååìììÍÍÍdddhhhhhhgggggghhhiiibbbŽŽŽçççæææææææææææææææåååææææææææææææææææææææææææåååååååååæææææææææææææææææææææåååååååååææææææææææææææææææææææææäääðð𸸸¥¥¥óóóãããæææåååâââçççææææææææææææææææææææææææêêêìììëëëææææææææææææææææææåååêêêììììììçççæææææææææææææææææææææäääððð¹¹¹•••õõõãããåååëëëúúúâââéééèèèæææææææææææææææää䨨ØÍÍÍÎÎÎçççæææææææææææææææèèèÔÔÔÐÐÐÎÎÎãããçççææææææææææææææææææäääðð𸸸...hhhÙÙÙZZZ–––õõõáááëëëÉÉÉ’’’///sssðððäääææææææåååçççäää)))+++‡‡‡éééåååæææææææææäääïïïšššSSSàààèèèåååæææææææææææææææäääðð𸸸nnn«««ÑÑÑ]]]•••õõõàààóó󤤤DDD666nnnñññäääæææææææææäääïïï¼¼¼EEEÉÉÉíííäääææææææææææææäääùùùEEE²²²ôôôäääææææææææææææææææææäääðð𸸸ŠŠŠØØØ***•••õõõâââåååëë뀀€!!!§§§õõõãããæææææææææçççÝÝÝäääAAAôôôäääæææææææææåååçççÛÛÛ666«««òòòäääææææææææææææææææææäääðð𸸸>>>ÍÍÍ–––õõõãããäääíííÏÏÏ,,,±±±ðððäääææææææåååèèèàààjjjCCC™™™ïïïäääæææææææææäääïïï–––000ÁÁÁîîîäääææææææææææææææææææäääððð¹¹¹•••õõõáááåååäääèèèïïïæææåååååååååæææååååååæææéééèèèïïïäääååååååææææææææææææéééëëëèèèææææææææææææææææææææææææäääðð𸸸±±±óóóêêêììììììëëëêêêììììììíííéééçççìììììììììëëëëëëêêêììììììêêêæææåååâââââââââáááâââââââââåååæææææææææææææææåååêêêÖÖÖ“““––––––••••••––––––‘‘‘´´´íííÚÚÚÆÆÆÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÅÅÅØØØâââÆÆÆÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÆÆÆÑÑÑçççëëë÷÷÷ööööööööööööööööööéééåååæææææææææææææææåååéééöööõõõõõõõõõõõõõõõõõõöööïïïçççÛÛÛÇÇÇÊÊÊÉÉÉÉÉÉÉÉÉÉÉÉÊÊÊÇÇÇØØØâââÈÈÈÊÊÊÊÊÊÉÉÉÉÉÉÉÉÉÊÊÊÈÈÈÑÑÑíííÉÉÉŽŽŽ’’’ÖÖÖêêêåååæææææææææææææææåååâââããããããááááááâââáááãããäääæææèèèììììììëëëíííëëëêêêììììììéééçççìììììììììììììììêêêìììëëëìììààà%%%CCCîîîåååææææææææææææææææææææææææåååêêêìììëëëìììåååæææææææææååååååçççáááæææïïïäääååååååæææååååååçççããããããðððåååäääêêêÓÓÓ $$$çççææææææææææææææææææææææææåååêêê×××UUUGGGÅÅÅíííäääææææææåååìììÉÉÉaaaOOO¢¢¢ðððäääææææææåååéééÛÛÛkkkPPPŠŠŠîîîãããëëëÓÓÓ ooo¯¯¯yyy%%%èèèææææææææææææææææææææææææãããøøø|||___XXXøøøãããææææææææææææâââ»»»===fff÷÷÷ãããææææææææææææåååÅÅÅVVVEEEñññãããëëëÓÓÓ  BBBâââ%%%çççææææææææææææææææææææææææãããùùùsssmmm”””QQQøøøãããæææææææææäääìììÀÀÀ...ŽŽŽõõõãããæææææææææåååëëëÑÑÑAAAjjjõõõâââëëëÓÓÓ ‘‘‘¼¼¼___$$$çççææææææææææææææææææææææææåååìììËËËEEE;;;´´´ðððäääææææææåååéééÖÖÖttt888‘‘‘óóóãããæææææææææçççããã‚‚‚@@@sssòòòãããëëëÓÓÓ •••ÀÀÀccc$$$çççæææææææææææææææææææææææææææåååìììàààÛÛÛîîîåååæææææææææææææææçççÐÐÐÖÖÖîîîåååæææææææææææææææèèèÕÕÕÐÐÐíííæææåååëëëÓÓÓ $$$çççææææææææææææææææææææææææææææææäääèèèéééäääæææææææææææææææææææææëëëêêêåååæææææææææææææææææææææêêêëëëåååæææåååëëëÓÓÓ $$$çççæææææææææææææææææææææææææææææææææååååååææææææææææææææææææææææææååååååææææææææææææææææææææææææååååååææææææåååëëëÓÓÓ $$$çççæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææåååëëëÓÓÓ $$$çççææææææææææææææææææææææææææææææåååããããããåååæææææææææææææææææææææåååãããäääæææææææææææææææææææææäääãããäääæææåååëëëÓÓÓ $$$çççææææææææææææææææææææææææææææææèèèôôôõõõêêêåååæææææææææææææææèèèìììóóóïïïåååæææææææææææææææèèèñññóóóðððååååååëëëÓÓÓ $$$çççæææææææææææææææææææææææææææçççãããppp___ÖÖÖêêêåååæææææææææçççàààÔÔÔqqq¤¤¤ïïïäääææææææåååèèèÞÞÞrrr^^^©©©íííãããëëëÓÓÓ 000ŸŸŸ```$$$çççææææææææææææææææææææææææããã÷÷÷ˆˆˆOOOhhheeeøøøãããææææææãããóóó   666VVVïïïäääæææææææææçççáááµµµ[[[>>>ðððãããëëëÓÓÓ ÀÀÀtttÍÍÍ&&&%%%çççææææææææææææææææææææææææãããúúúpppzzz¤¤¤NNNøøøãããææææææåååêêêÔÔÔpppBBB   õõõãããæææææææææäääííí×××>>>qqqôôôâââëëëÓÓÓ ÏÏÏ©©©$$$çççææææææææææææææææææææææææäääïïﺺº:::888žžžóóóãããæææææææææãããôôô¯¯¯¥¥¥óóóãããæææææææææçççâââ???___óóóâââëëëÓÓÓ oooººº___%%%èèèæææææææææææææææææææææææææææåååîîîÊÊÊÀÀÀîîîåååæææææææææææææææåååëëëÃÃÃÚÚÚèèèæææææææææææææææèèè¿¿¿²²²äääçççäääëëëÓÓÓ 333222%%%çççææææææææææææææææææææææææååååååãããëëëîîîãããåååååååååååååååååååååäääíííèèèäääåååæææææææææåååäääîîîðððæææääääääéééÖÖÖ---êêêåååææææææææææææææææææäääèèèëëëëëëêêêéééëëëëëëëëëëëëëëëëëëëëëëëëëëëéééêêêëëëèèèååååååæææëëëëëëêêêéééêêêëëëëëëêêêñññšššGGGLLLLLLMMMMMMKKKJJJªªªíííäääæææææææææææææææåååíííÝÝÝÑÑÑÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÑÑÑÞÞÞìììéééæææÑÑÑÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÒÒÒÞÞÞáááàààáááááááááàààäääõõõææææææææææææææææææäääïïï®®®  µµµäää999   sssïïïäääææææææææææææâââ÷÷÷gggyyyÆÆÆ$$$çççæææææææææææææææâââ÷÷÷hhh|||ŠŠŠAAAYYY...yyyÆÆÆ///†††...KKKŠŠŠxxx &&&çççæææææææææææææææâââ÷÷÷hhhƒƒƒËËËFFF···ää䣣£yyyÆÆÆÂÂÂ}}}ÇÇÇ###ÖÖÖppp$$$èèèæææææææææææææææâââ÷÷÷gggLLL£££%%%«««WWWyyyÆÆÆããã­­­===$$$çççæææææææææææææææâââ÷÷÷hhh ­­­­­­RRRÿÿÿJJJyyyÆÆÆªªª®®®CCCFFFååå<<<$$$èèèæææææææææææææææâââ÷÷÷hhh XXX999PPPyyyÆÆÆ[[[:::///]]]%%%çççæææææææææææææææâââ÷÷÷jjj{{{ÈÈÈ'''èèèæææææææææææææææäääíííÀÀÀ333"""%%%'''&&&$$$$$$$$$$$$$$$$$$$$$$$$$$$'''&&&!!!444ÄÄÄéééYYY%%%%%%'''&&&$$$$$$$$$$$$$$$$$$$$$%%%(((%%%$$$!!!ïïïäääæææææææææææææææåååííííííçççèèèççççççççççççççççççççççççççççççççççççèèèçççíííìììçççðððçççèèèççççççççççççççççççççççççççççççççççççèèèçççéééïïïææææææææææææææææææææææææäääåååææææææææææææææææææææææææææææææææææææææææææææææææååååååæææäääæææææææææææææææææææææææææææææææææææææææææææææææææææäääææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææ( @ ææææææäääääääääääääääääääääææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææçççîîîîîîîîîïïïîîîïïïïïïåååæææææææææåååæææææææææææææææååååååæææææææææææææææååååååææææææææææææéééÛÛÛ@@@111777666555...šššðððäääååååååçççææææææææææææçççìììëëëæææææææææææææææëëëìììçççæææææææææêêê×××MMMõõõáááííííííáááèèèææææææçççâââÑÑÑÏÏÏåååææææææææææææÑÑÑÎÎÎãããçççææææææêêê×××555¨¨¨ŠŠŠQQQóóóêêêÄÄÄ[[[^^^íííååååååèèèÞÞÞ;;;ˆˆˆìììåååæææäääððð{{{WWWéééæææææææææêêê×××+++ÅÅÅqqqQQQóóóéééÍÍÍ???nnnóóóãããæææåååììì«««cccíííåååæææäääôôô………ùùùâââææææææêêê×××pppQQQPPPôôôßßßööö–––’’’òòòãããåååèèèÛÛÛ~~~‰‰‰êêêäääæææåååííí~~~ŸŸŸñññäääææææææêêê×××TTT÷÷÷èèèéééôôôòòòêêêêêêçççëëëìììðððöööëëëêêêåååãããâââëëëéééâââãããææææææèèèßß߆††~~~€€€‚‚‚‚‚‚}}}ÉÉÉàààÊÊÊÍÍÍÊÊÊËËËËËËÔÔÔÞÞÞËËËÍÍÍËËËÊÊÊÌÌÌÐÐÐèèèõõõôôôóóóóóóõõõóóóæææææææææçççööö÷÷÷öööøøøööö÷÷÷íííÞÞÞÕÕÕ×××ÚÚÚÖÖÖÕÕÕÛÛÛáááÕÕÕ×××ÚÚÚÖÖÖÕÕÕÛÛÛÜÜÜcccIIIKKKNNNGGG|||éééåååææææææãããáááèèèÝÝÝæææãããäääèèèêêêçççÜÜÜïïïêêêèèèçççêêêéééÜÜÜíííéééôôô±±±ØØØêêêææææææäääîîîÁÁÁTTT’’’ïïïäääåååêêêÒÒÒiii|||îîîäääåååèèèÚÚÚtttnnnæææððð±±± ```››› ØØØêêêææææææããã÷÷÷ŠŠŠuuuiiièèèåååæææåååððð‚‚‚XXXóóóäääæææäääðð𘘘HHHêêêñññ±±±wwwžžž ØØØêêêææææææåååìììËËË]]]žžžïïïäääåååéééÜÜÜoooŒŒŒðððäääæææçççâââ{{{}}}êêêððð±±±ŸŸŸeee×××êêêæææææææææåååëëëëëëíííæææææææææææææææäääíííæææææææææææææææãããíííäääñññ±±±×××êêêææææææææææææåååååååååææææææææææææææææææäääæææææææææææææææçççäääãããòòò±±±×××êêêææææææææææææåååååååååææææææææææææåååãããäääæææææææææææææææçççäääãããòòò±±±×××êêêæææææææææåååëëëëëëíííæææææææææåååëëëôôôïïïçççææææææææææææãããîîîäääñññ±±±×××êêêææææææåååìììËËË\\\žžžïïïäääåååêêêÒÒÒuuuìììååååååéééÚÚÚwww}}}çççñññ±±±nnn‡‡‡ ØØØêêêææææææããã÷÷÷ŠŠŠuuuiiièèèåååäääïïï¾¾¾666fffðððäääæææäääïï˜HHHéééñññ²²²¼¼¼››› ØØØêêêææææææäääîîîÁÁÁTTT’’’ïïïäääæææããã÷÷÷{{{€€€÷÷÷ãããæææçççäääwwwpppëëëððð±±±ˆˆˆsss×××êêêææææææåååáááèèèÝÝÝæææãããââââââââââââæææàààâââäääæææãããâââÖÖÖäääàààííí®®®×××êêêæææåååêêê÷÷÷öööøøøööö÷÷÷÷÷÷÷÷÷÷÷÷÷÷÷ööö÷÷÷øøøíííçççööö÷÷÷úúú÷÷÷öööùùùííítttZZZ```\\\XXX‡‡‡éééæææåååêêêÐÐЂ‚‚‚‚‚€€€€€€€€€€€€ƒƒƒƒƒƒ{{{¿¿¿åå匌Œ~~~ƒƒƒ‚‚‚€€€‚‚‚ŽŽŽ’’’‰‰‰µµµëëëåååâââööömmmJJJ©©©ÚÚÚéééâââ÷÷÷ggg›››[[[```rrrGGG¢¢¢ mmmnnnqqq×××êêêâââ÷÷÷fffˆˆˆ999222ÆÆÆ•••GGG¤¤¤...¾¾¾——— MMMyyy×××êêêâââöööhhh­­­(((ˆˆˆ€€€JJJ£££¥¥¥ddd………lll×××êêêâââ÷÷÷fff DDD¡¡¡ ×××êêêäääïïï«««111444///444555555555444555444444+++ŽŽŽÔÔÔ===444444///555555555555555000444...eeeèèèææææææåååíííðððîîîïïïîîîîîîîîîîîîîîîîîîïïïïïïïïïïïïêêêñññîîîïïïïïïîîîîîîîîîîîîîîîïïïïïïîîîñññçççæææææææææääääääääääääääääääääääääääääääääääääääääääåååãããäääääääääääääääääääääääääääääääääãããææææææ(  æææäääâââäääéééæææèèèæææåååêêêèèèææææææêêêçççæææØØØ444&&&!!!­­­ñññÞÞÞåååèèèÚÚÚßßßçççåå娨ØäääçççØØØhhh444ãããfffáááóóóŸŸŸ¥¥¥òòòßß߃ƒƒÝÝÝèèèÖÖÖ˜˜˜òòò»»»äääêêêËËËÊÊÊìììðððÖÖÖóóóæææâââµµµ²²²²²²×××ØØØäääÙÙÙÙÙÙÞÞÞààà×××¢¢¢¥¥¥ææææææõõõÀÀÀÕÕÕðððÝÝÝ­­­äääííí¾¾¾ÉÉÉÌÌÌ)))ÔÔÔäääìì쀀€©©©òòòÛÛÛ€€€ßßßòòò¦¦¦¨¨¨ÏÏÏ www ÒÒÒææææææççççççæææäääåååçççæææãããïïïÅÅÅÕÕÕææææææççççççæææèèèêêêåååæææâââïïïÅÅÅÕÕÕåååìì쀀€¨¨¨òòòÎÎÎmmmßßßñññ¢¢¢¥¥¥ËË˃ƒƒ!!!ÒÒÒäääñññÁÁÁÕÕÕøøøíííÀÀÀìììòòòÏÏÏ×××ÕÕÕ 999ÕÕÕéééÆÆÆ®®®±±±±±±°°°«««ÃÃÃÍÍͪªª²²²¬¬¬jjjHHH{{{æææððð777 555KKK 888$$$ÖÖÖñññ---@@@+++uuu444<<<XXXOOOWWWÔÔÔïïï]]]"""(((%%%$$$VVVppp***###(((''';;;ÝÝÝçççèèèáááãããäääåååâââèèèêêêâââãããääääääáááçççèèè(0` æææåååâââãããéééøøø÷÷÷ôôôìììÍÍÍdddhhhgggiiibbbŽŽŽçççäääðð𸸸¥¥¥óóóêêêëëë¹¹¹•••õõõúúúèèèØØØÎÎÎÔÔÔÐÐÐ...ÙÙÙZZZ–––áááÉÉÉ’’’///sss)))+++‡‡‡ïïïšššSSSààànnn«««ÑÑÑ]]]¤¤¤DDD666ñññ¼¼¼EEEíííùùù²²²ŠŠŠ***€€€!!!§§§ÝÝÝAAAÛÛÛòòò>>>ÏÏÏ,,,±±±jjjCCC™™™000ÁÁÁîîîÖÖÖ“““‘‘‘´´´ÚÚÚÆÆÆÈÈÈÅÅÅöööÇÇÇÊÊÊ%%%ÓÓÓ $$$×××UUUGGGaaaOOO¢¢¢kkkPPP ooo¯¯¯yyy|||___XXX»»»===fffVVV BBBmmm”””QQQÀÀÀËËË;;;ttt888‚‚‚@@@cccÕÕÕpppqqqÞÞÞrrr^^^©©©ŸŸŸ```ˆˆˆeee   µµµ[[[&&&zzzNNNººº:::žžž???ÃÃÿ¿¿ 333222---LLLMMMKKKJJJªªªÒÒÒ®®®  999YYY†††xxxƒƒƒFFF···£££ÂÂÂ}}}###WWW­­­RRRÿÿÿ<<<{{{'''"""444ÄÄÄ(((  !"#$ %#&'%() *+,!-./0123456789#:;<= !9>?@:A5BC.DECFGH$I !JKL!MNOP@;Q(R S,!DTUV#9WXY55,Z[\(( !-#5#5#VD-]^,, ,,_`Dabccccccd$bccccccb<eeeeeee!!!!!!e5Pfg....gf$cgg...gc5#•–—˜DklZ™šm›r œ@ž5-Ÿ Rklˆ‹ ¡j"“¢>£&“ƒ!DnR”klT˜NGm5¤¥Œ¦x§¨{klw¤{j#\gˆ\©a##ªFk«¬­j\D#\]®¯##A6p°°±±²³´DDM%?8@ABCD!EFEGHIJK8DA!!@LEMNNOPQR3RSST*S3SRUV8&&&AKAWAK*XYZXXYZX[7\]^_`!a![[8bI=cdeJCfg`Yh5bijkld!K$mgNn&opHbqrstdSur[vw-ObIGxc!Hb=!Db=!!Db==I8!Hb=ySzrf{mYqOHb5|}~d!K$mg €opH‚ƒk"ldeJC!K-MK!q>b=,„…a!Q!ZQ†=cKAWAKKKKKAKWAK‡KA;hˆjzn|VN{N‰MMMM‰ŠŠ-‹wEŠNM{NŒŽCFAyI‘’="YK“”k(s?@ABCDEF/BC4EG/%8<HI ,#J A K/L0.%=)/MNO/PQRRSTUVW(XYZ[&\GOE]^_`abEMcd efgEhi jklEmno7Bpqrsdtuvwxyrz{(0`€€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿxˆˆˆˆÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿpÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿpÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿpÿÿÿxÿÿÿÿˆˆÿÿÿÿxÿÿp€ÿÿpÿÿÿÿðÿÿÿÿøÿÿp‡€ÿÿx€ÿÿÿÿ÷‡ÿÿÿÿøÿÿpÿÿ÷ÿÿÿÿwˆÿÿÿÿøÿÿpÿÿ÷ˆÿÿÿÿxÿÿÿÿpÿÿpÿÿÿ÷ÿÿÿÿ÷ÿÿÿÿÿÿÿÿÿpÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿp€€€€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿ÷ÿÿ÷ÿ÷÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿø€€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿpÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€ÿÿ÷ÿÿÿøˆÿÿÿÿp‡ÿÿp‡ðÿÿðxÿÿÿ÷pÿÿÿÿ÷€ÿÿpxÿÿðxÿÿÿ÷ÿÿÿÿ÷ÿÿpˆðÿÿø€ÿÿÿ÷€ÿÿÿÿøˆÿÿpw€ÿÿ÷ˆÿÿÿÿø‡ÿÿÿÿx‡ÿ€ˆˆÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€‡ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿpÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿpÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿpÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿpÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿpÿÿÿÿÿÿÿÿ÷ÿÿÿÿ÷ÿÿp€ÿÿø€ÿÿÿ÷€ÿÿÿÿxÿÿ€‡xÿÿðx‡ÿÿÿp€ÿÿÿ÷ˆÿÿ€xˆÿÿðxÿÿÿø€ÿÿÿÿ÷ÿÿpwˆÿÿø€ÿÿÿÿÿÿÿÿø÷ÿpˆÿÿÿÿÿÿÿÿwÿÿÿÿøÿÿp€ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿpÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿÿðÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿw÷ÿÿw‡xwwˆwwxw÷wwwˆwwwwwwÿ÷ð‡øðøxð€ˆøw€‡€ð‡‡ðøw‡ð‡ðøwwðˆp÷øøðxpøðøðÿ€€€€€‡øÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿ( @€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ÷÷÷ÿ÷ÿ÷ÿ÷÷÷ÿ÷x€ÿ÷÷ÿÿ÷pwwÿÿw÷ð‡÷ˆ÷ÿð‡ÿ÷xpwøÿ÷‡÷÷øpˆˆ÷x‡÷ÿx÷ðw÷÷÷wÿ÷÷pÿÿÿ÷÷ÿÿ÷ÿwwww÷www÷ww÷÷ÿ÷ÿ÷÷ÿÿ€÷÷w÷wwÿ÷ˆwÿwˆw÷øÿ€pxˆÿÿw÷ÿ€€÷÷ˆ÷÷‡÷ÿø‡€÷ÿÿÿÿÿ÷ÿÿ€÷÷÷÷ÿ÷÷€ÿ÷ÿ÷÷÷÷€wÿÿÿw÷ÿÿÿÿ€÷÷ˆ÷÷÷‡÷ø‡ÿ€ÿ÷€ÿø÷ÿwÿ€‡€ww÷ÿ÷€÷ÿwÿ÷ÿ÷÷÷wÿ€€ÿ÷ÿÿÿÿ€÷ÿ÷÷÷÷wÿwøp€ø€p÷ˆxpppøˆxppøxxpp€øp÷€€€p€€€‡÷ÿÿÿwÿÿÿÿÿÿÿÿ( €€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿ÷ÿÿð÷÷pˆ‡‡÷øðww÷ÿww÷ˆwww÷wÿ‡÷ww÷ÿ÷÷÷ÿ÷÷ÿ‡÷‡÷www÷xwwwwˆ‡øðpˆ€ø€÷ÿÿÿÿpuzzles-20170606.272beef/icons/cube.ico0000644000175000017500000006117613115373726016434 0ustar simonsimon 00 ¨%–  ¨>& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $ææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååæææææææææææææææææææææçççììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììçççæææææææææææææææçççäääÎÎÎÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÎÎÎäääçççæææææææææåååìììÎÎά¬¬ËËËÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÅÅÅËË˯¯¯¬¬¬ËËËÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÅÅÅËËË®®®®®®ËËËÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÅÅÅËËˬ¬¬¯¯¯ËËËÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÅÅÅËËˬ¬¬ÎÎÎìììåååææææææåååìììÌÌÌËËËôôôëëëííííííííííííìììóóóÑÑÑÍÍÍôôôìììííííííííííííìììôôôÏÏÏÏÏÏôôôìììííííííííííííìììôôôÍÍÍÑÑÑóóóìììííííííííííííëëëôôôËËËÌÌÌìììåååææææææåååìììÌÌÌÅÅÅëëëãããååååååååååååäääëëëÉÉÉÆÆÆëëëãããååååååååååååäääëëëÈÈÈÈÈÈëëëäääååååååååååååãããëëëÆÆÆÉÉÉëëëäääååååååååååååãããëëëÅÅÅÌÌÌìììåååææææææåååìììÌÌÌÆÆÆíííåååææææææææææææåååìììËËËÇÇÇíííåååææææææææææææåååìììÉÉÉÉÉÉìììåååææææææææææææåååíííÇÇÇËËËìììåååææææææææææææåååíííÆÆÆÌÌÌìììåååææææææåååìììÌÌÌÆÆÆíííåååææææææææææææåååìììËËËÇÇÇíííåååææææææææææææåååìììÉÉÉÉÉÉìììåååææææææææææææåååíííÇÇÇËËËìììåååææææææææææææåååíííÆÆÆÌÌÌìììåååææææææåååìììÌÌÌÆÆÆíííåååææææææææææææåååìììËËËÇÇÇíííåååææææææææææææåååìììÉÉÉÉÉÉìììåååææææææææææææåååíííÇÇÇËËËìììåååææææææææææææåååíííÆÆÆÌÌÌìììåååææææææåååìììÌÌÌÆÆÆíííåååææææææææææææåååìììËËËÇÇÇíííåååææææææææææææåååìììÉÉÉÉÉÉìììåååææææææææææææåååíííÇÇÇËËËìììåååææææææææææææåååíííÆÆÆÌÌÌìììåååææææææåååìììÌÌÌÅÅÅìììäääååååååååååååäääëëëÊÊÊÆÆÆìëëäããåääåääåääåäääããëëëÈÈÈÈÈÈëëëäããåääåääåääåäääããìëëÆÆÆÊÉÉëëëäããåääåääåääåäääããìëëÅÄÄÌÌÌìììåååææææææåååìììÌÌÌËËËóóóëëëììììììììììììëëëóóóÐÐÐÍÍÍóóóëëëìííìííìííìííëëëóóóÎÏÏÎÏÏóóóëëëìííìííìííìííëëëòóóÍÍÍÐÐÐóóóëëëìííìííìííìííëëëóôôËÍÍÌÌÌìììåååææææææåååìììÍÍͯ¯¯ÐÐÐÉÉÉËËËËËËËËËËËËÊÊÊÐÐв²²¯°°ÐÑÑÉÊÊÊËËÊËËÊËËÊËËÉÊÊÐÑѱ±±±±±ÐÑÑÉÊÊÊËËÊËËÊËËËËËÈÊÊÓÑѰ°°±³³ÐÐÐÉÊÊÊËËÊËËÊËËËËËÈÊÊÓÓÓ±§§ËÌÌìììåååææææææåååìììÍÍͬ¬¬ÍÍÍÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÆÆÆÍÍͯ°°¾ ãÛÜÜÜÜÛãÀÀãÛÜÜÝÛáÒ£ÚÜÛÜÜÜÚá×z@@ÍÕÕìêêåååææææææåååìììÌÌÌËËËôôôëëëííííííííííííìëëóóóÐÑÑÜÿþÿÿÿÿþÿßßÿþÿÿÿÿøÎøÿÿÿÿÿþÿô»XX¾ÊÊÏÍÍëëëåååææææææåååìììÌÌÌÅÅÅìììãããååååååååååååäããëëëÉÊÊÛÿüþþþþüÿÝÝÿüþýÿô«ßîçéééèêæ«QQàööËÈÈËËËìììåååææææææåååìììÌÌÌÆÆÆíííåååææææææææææææåääìííÊËËÜÿþÿÿÿÿþÿßßÿþÿýÿέ¤¤Ë®®Á««Ã¬¬Ã¬¬Ã¬¬Ã¬¬Â««É°°¡ÎØØõóóÃÃÃÌÌÌìììåååææææææåååìììÌÌÌÆÆÆíííåååææææææææææææåääìííÊËËÜÿþÿÿÿÿþÿßßÿþÿýÿÕÙèèñõõìññìòòìòòìòòìòòëññóúúÅÉÉÔÒÒðððÅÅÅÌÌÌìììåååææææææåååìììÌÌÌÆÆÆíííåååææææææææææææåääìííÊËËÜÿþÿÿÿÿþÿßßÿþÿýÿÓÐÙÙêææäââåããåããåããåãããââìêê¾½½ÒÒÒñññÅÅÅÌÌÌìììåååææææææåååìììÌÌÌÆÆÆíííåååææææææææææææåääìííÊËËÜÿþÿÿÿÿþÿßßÿþÿýÿÓÑÜÜëééåååææææææææææææåååííí¿¿¿ÓÓÓñññÅÅÅÌÌÌìììåååææææææåååìììÌÌÌÅÅÅìììäääååååååååååååäããëëëÉÊÊÛÿüþþþþüÿÞÞÿüþüÿÒÑÜÜëééåååææææææææææææåååííí¿¿¿ÓÓÓñññÅÅÅÌÌÌìììåååææææææåååìììÌÌÌËËËôôôëëëììììììììììììëëëóóóÐÑÑÜÿþÿÿÿÿþÿßßÿþÿýÿÓÑÜÜëééåååææææææææææææåååííí¿¿¿ÓÓÓñññÆÆÆÍÍÍìììåååææææææåååìììÍÍÍ®®®ÏÏÏÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÈÈÈÎÏϱ±±ÀåÝßßßßÞåÃÂåÝÞÝå»ÓÜÜëééåååææææææææææææåååííí¿¿¿ÑÑÑõõõÃÃÃÊÊÊìììåååææææææåååìììÍÍÍ®®®ÏÏÏÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÈÈÈÎÏϱ±±ÀåÝßßßßÞå°¬¬ÏÍÍÈÅÅÉÇÇÈÆÆÏÌÌ«©©ÓÓÓêêêåååååååååååååååäääììì½½½ØØØååå“““ÍÍÍìììåååææææææåååìììÌÌÌËËËôôôëëëììììììììììììëëëóóóÐÑÑÜÿþÿÿÿÿþÿßÏÍÍóõõëìììííëììôõõÆÇÇ×××ðððêêêëëëëëëëëëëëëêêêñññÇÇÇÇÇÇ···¾¾¾ÏÏÏëëëåååææææææåååìììÌÌÌÅÅÅìììäääååååååååååååäããëëëÉÊÊÛÿüþþþþüÿÝÈÅÅëììäããåääãããììì¾½½¾¾¾ÕÕÕÑÑÑÑÑÑÐÐÐÑÑÑÐÐÐÏÏÏØØØªªªœœœëëëÉÉÉËËËìììåååææææææåååìììÌÌÌÆÆÆíííåååææææææææææææåääìííÊËËÜÿþÿÿÿÿþÿÞÉÇÇìííåääæææåååèèèÚÚÚ¾¾¾ÈÈȪªª­­­ÇÇÇÁÁÁÂÂÂÂÂÂÃÃþ¾¾ßßßñññÄÄÄÌÌÌìììåååææææææåååìììÌÌÌÆÆÆíííåååææææææææææææåääìííÊËËÜÿþÿÿÿÿþÿÞÉÇÇìííåääæææææææææèèèìììôôôÍÍÍÑÑÑóóóìììíííííííííîîîæææìììÆÆÆÌÌÌìììåååææææææåååìììÌÌÌÆÆÆíííåååææææææææææææåääìííÊËËÜÿþÿÿÿÿþÿÞÉÇÇìííåääæææææææææåååãããëëëÆÆÆÉÉÉëëëãããåååååååååääääääíííÆÆÆÌÌÌìììåååææææææåååìììÌÌÌÆÆÆíííåååææææææææææææåääìííÊËËÜÿþÿÿÿÿþÿÞÉÇÇìííåääææææææææææææåååíííÇÇÇËËËìììåååææææææææææææåååíííÆÆÆÌÌÌìììåååææææææåååìììÌÌÌÅÄÄìëëäããåääåääåääåäääããëëëÉÉÉÛÿüþþþþüÿÝÈÆÆëììäããååååååååååååäääëëëÆÆÆÉÉÉëëëäääååååååååååååãããìììÅÅÅÌÌÌìììåååææææææåååìììÌÌÌËÌÌôõõëíííîîíîîíîîíîîëííóõõÐÒÒÜÿþÿÿÿÿþÿßÏÌÌóôôìëëííííííííííííëëëôôôÍÍÍÐÐÐóóóìììííííííííííííëëëôôôËËËÌÌÌìììåååææææææåååìììÍÍÍ­¨¨ÍÇÇÇÁÁÈÂÂÈÂÂÈÂÂÈÂÂÇÁÁÍÈȰ««¿ãÜÝÝÝÝÜãÁ®¬¬ÍÎÎÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÆÆÆÍÍÍ­­­¯¯¯ÍÍÍÆÆÆÇÇÇÇÇÇÇÇÇÇÇÇÆÆÆÍÍͬ¬¬ÍÍÍìììåååææææææåååìììÌÏÏÁçßááááàçÆÃçßááááßçı¯¯ÐÑÑÊÉÉËËËËËËËËËËËËÉÉÉÐÐЯ¯¯²²²ÐÐÐÊÊÊËËËËËËËËËËËËÉÉÉÐÐЯ¯¯ÍÍÍìììåååææææææåååìììÌÏÏÚÿýÿÿÿÿþÿáÝÿþÿÿÿÿþÿßÎÌÌóôôëëëììììììììììììëëëóóóÍÍÍÐÐÐóóóëëëììììììììììììëëëóóóËËËÌÌÌìììåååææææææåååìììÌÏÏÙ ÿüþþþþýÿßÜÿüþþþþüÿÝÈÆÆëììäããååååååååååååäääìììÆÆÆÊÊÊëëëäääååååååååååååäääìììÅÅÅÌÌÌìììåååææææææåååìììÌÏÏÚÿýÿÿÿÿþÿáÝÿþÿÿÿÿþÿÞÉÇÇìííåääææææææææææææåååíííÇÇÇËËËìììåååææææææææææææåååíííÆÆÆÌÌÌìììåååææææææåååìììÌÏÏÚÿýÿÿÿÿþÿáÝÿþÿÿÿÿþÿÞÉÇÇìííåääææææææææææææåååíííÇÇÇËËËìììåååææææææææææææåååíííÆÆÆÌÌÌìììåååææææææåååìììÌÏÏÚÿýÿÿÿÿþÿáÝÿþÿÿÿÿþÿÞÉÇÇìííåääææææææææææææåååíííÇÇÇËËËìììåååææææææææææææåååíííÆÆÆÌÌÌìììåååææææææåååìììÌÏÏÚÿýÿÿÿÿþÿáÝÿþÿÿÿÿþÿÞÉÇÇìííåääææææææææææææåååíííÇÇÇËËËìììåååææææææææææææåååíííÆÆÆÌÌÌìììåååææææææåååìììÌÏÏÙ ÿüýýýýüÿßÜÿüýýýýüÿÝÈÆÆëììäããååååååååååååãããëëëÆÆÆÉÉÉëëëäääååååååååååååãããëëëÅÅÅÌÌÌìììåååææææææåååìììÌÏÏÚÿýÿÿÿÿþÿáÝÿþÿÿÿÿþÿßÏÍÍóôôìëëííííííííííííìììôôôÍÍÍÑÑÑóóóìììííííííííííííëëëôôôËËËÌÌÌìììåååææææææåååìëëÎÐнàÙ ÚÚÚÚÙàÁ¾àÙÚÚÚÚÙ à¿ ®¬¬ËÌÌÅÄÄÆÆÆÆÆÆÆÆÆÆÆÆÅÅÅËËˬ¬¬¯¯¯ËËËÅÅÅÆÆÆÆÆÆÆÆÆÆÆÆÅÅÅËËˬ¬¬ÎÎÎìììåååæææææææææçççäääÎÐÐËÏÏÌÏÏÌÏÏÌÏÏÌÏÏÌÏÏÌÏÏÌÏÏÌÏÏÌÏÏÌÏÏÌÏÏÌÏÏÌÏÏÌÏÏÌÏÏÌÏÏÌÏÏÌÏÏÍÍÍÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÎÎÎäääçççæææææææææææææææçççìëëìììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììììçççæææææææææææææææææææææååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååååææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææ( @ ææææææêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêêéééæææææææææäää××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××ÖÖÖÙÙÙææææææëëëÑÑѾ¾¾ÐÐÐÌÌÌÍÍÍÌÌÌÑÑÑ»»»¾¾¾ÐÐÐÌÌÌÍÍÍÌÌÌÑÑѺºº¿¿¿ÐÐÐÌÌÌÍÍÍÌÌÌÑÑѹ¹¹ÀÀÀÐÐÐÌÌÌÍÍÍÌÌÌÐÐл»»ÙÙÙéééëëëÑÑÑØØØïïïêêêëëëêêêðððÔÔÔÙÙÙïïïêêêëëëêêêðððÓÓÓÙÙÙïïïêêêëëëêêêðððÒÒÒÚÚÚïïïêêêëëëêêêðððÑÑÑ×××êêêëëëÐÐÐÒÒÒéééäääåååäääêêêÎÎÎÓÓÓéééäääåååäääêêêÎÎÎÔÔÔéééäääåååäääêêêÍÍÍÕÕÕéééäääåååäääêêêÌÌÌ×××êêêëëëÐÐÐÓÓÓêêêåååæææåååëëëÏÏÏÔÔÔêêêåååæææåååëëëÎÎÎÕÕÕêêêåååæææåååëëëÎÎÎÖÖÖêêêåååæææåååëëëÍÍÍ×××êêêëëëÐÐÐÓÓÓêêêååååååäääêêêÏÏÏÔÓÓêééåääåååäääêêêÎÎÎÔÔÔéééåääåååäääêêêÍÍÍÕÕÕéééåääåååäääêêêÌÌÌ×××êêêëëëÑÑÑ×××îîîéééêêêéééïïïÓÓÓØ××îîîéééêéééèèïîîÒÒÒÙØØîííéééêéééèèîîîÑÑÑÚÙÙîííéééêéééèèîïïÐÒÒ×××êêêëëëÐÐÐÄÄÄÚÚÚÕÕÕÖÖÖÕÕÕÚÚÚÁÁÁÅÈÈÙÝÝÕØØÕÙÙÔØØÚÞÞÀÃÃÆÉÉÙÝÝÕØØÖÙÙÔØØÜÞÞ¿ÂÂÅÊÊÙÝÝÕÙÙÕÙÙÓØØÜßßÁººÖ××êêêëëëÏÏϽ½½ÑÑÑÍÍÍÎÎÎÍÌÌÒÕÕ»¯¯ÑæáâáçËÑæâáæÝ¼ãääãçß™YY×ááêèèëëëÑÑÑØØØïïïêêêëëëêééðóóÕÆÆëÿþÿþÿåìÿþÿùÑõÿýýÿøÌ]]ÈÓÓÙ××éééëëëÐÐÐÒÒÒéééäääåååäããéííÐÂÂêÿýþýÿäëÿûÿÐ!!½œœÑ——Ë——Ì——Ë——Ϙ˜±‰‰ÝëëÑÑÑÖÖÖêêêëëëÐÐÐÓÓÓêêêåååæææåääêîîÑÂÂëÿþÿþÿåìÿýÿÚ44áüüëôôéõõéõõèôôíúúÊÒÒåããÎÎÎ×××êêêëëëÐÐÐÓÓÓêêêåååååååããêîîÐÂÂêÿýþýÿäëÿüÿ×11ÛééèááåââåããäââéççÆÃÃãããÏÏÏ×××êêêëëëÑÑÑ×××îîîéééêêêéèèïòòÔÆÆëÿþÿþÿåìÿýÿØ11ÜììèååææææææåååêêêÆÆÆãããÏÏÏ×××êêêëëëÐÐÐÄÄÄÙÙÙÔÔÔÕÕÕÔÓÓÙÝÝÁ´´ÚðëìëñÔÛðêñÌ11ÝììèååææææææåååêêêÅÅÅæææÎÎÎÖÖÖêêêëëëÏÏϾ¾¾ÒÒÒÎÎÎÎÎÎÎÍÍÒÖÖ»®®ÓéäåäêÌ Á²²ÔÂÂϾ¾ÓÁÁº¯¯âããêééèèèèèèçççìììÌÌÌÜÜܬ¬¬ØØØêêêëëëÑÑÑØØØïïïêêêëëëêééïóóÕÆÆëÿþÿþÿäÙßßïóóéííïôôÉËËÔÔÔáááÞÞÞÝÝÝÜÜÜââ⺺º¼¼¼ÉÉÉØØØêêêëëëÐÐÐÒÒÒéééäääåååäããéííÐÁÁêÿýþýÿâÔÕÕéèèäââèççÕÔÔÈÈȹ¸¸½½½ËËËÇÇÇÉÉÉÀÀÀæææÐÐÐÖÖÖêêêëëëÐÐÐÓÓÓêêêåååæææåääêîîÑÂÂëÿþÿþÿãÕ××êêêåååæææèèèðððÒÒÒÚÚÚîîîêêêêêêëëëìììÌÌÌ×××êêêëëëÐÐÐÓÒÒêééåääååååããêííÐÁÁêÿýþýÿãÔÖÖéééåääåååäääéééÌÌÌÔÔÔèèèääääääãããêêêÌÌÌ×××êêêëëëÑÑÑ×××îïïéêêêëëéééïóóÔÆÆëÿþÿþÿäÙÚÚîîîêééêêêéééïïïÑÑÑÚÚÚîîîêêêêêêéééïïïÐÐÐ×××êêêëëëÐÐÐÃÃÃØØØÓÓÓÔÔÔÓÒÒØÜÜÀ³³ÙïêëêðÒÄÆÆØØØÔÓÓÔÔÔÓÓÓÙÙÙ¾¾¾ÅÅÅØØØÔÔÔÔÔÔÓÓÓØØØ¾¾¾×××êêêëîîÐÇÇÒ é ä ä ã é Î ÔêåæåëÍÀÁÁÓÓÓÏÎÎÏÏÏÎÎÎÔÔÔ¹¹¹ÁÁÁÓÓÓÏÏÏÏÏÏÎÎÎÓÓÓ»»»×××êêêëîîÒÆÆêÿþÿþÿæëÿþÿþÿäÙÛÛïïïêêêëëëêêêðððÒÒÒÚÚÚïïïêêêëëëêêêðððÑÑÑ×××êêêëîîÑÆÆéÿýþýÿåêÿýþýÿâÔÖÖéééäääåååäääêêêÍÍÍÕÕÕéééäääåååäääêêêÌÌÌ×××êêêëîîÒÆÆêÿþÿþÿæëÿþÿþÿãÕ××êêêåååæææåååëëëÎÎÎÖÖÖêêêåååæææåååëëëÍÍÍ×××êêêëîîÒÆÆéÿýþýÿåêÿýþýÿãÔÖÖéééåääåååäääêêêÍÍÍÕÕÕéééååååååäääêêêÌÌÌ×××êêêëîîÒÆÆêÿþÿþÿæëÿþÿþÿäÙÛÛîîîêééêêêéééïïïÒÒÒÚÚÚîîîêêêêêêéééïïïÐÐÐ×××êêêëîîÑÆÆ×îéêéïÓØîéêéïÑÃÅÅ×××ÓÒÒÓÓÓÒÒÒØØØ½½½ÄÄÄ×××ÓÓÓÓÓÓÒÒÒ×××¾¾¾×××êêêçççâââÑÆÆÒÆÆÒÆÆÒÆÆÑÆÆÒÆÆÐÆÆÑÆÆÒÆÆÑÆÆÒÆÆÑÆÆÒÆÆÐÇÇÐÐÐÑÑÑÐÐÐÐÐÐÐÐÐÑÑÑÏÏÏÐÐÐÑÑÑÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑäääææææææçççëîîëîîëîîëîîëîîëîîëîîëîîëîîëîîëîîëîîëîîëîîëëëëëëëëëëëëëëëëëëëëëëëëëëëëëëëëëëëëëëëëëëææææææ(  åååÝÝÝÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝåååÛÛÛÓÓÓÝÝÝÚÚÚÌÌÌÛÛÛÝÝÝÑÑÑÓÓÓÝÝÝÚÚÚÍÍÍÛÛÛÜÜÜÒÒÒÝÝÝÛÛÛÞÞÞëëëçèèØÖÖéääëççÞÚÚßÛÛëçççää×ÔÔéååëççÝÚÚÜÝÝÛÛÛÝÝÝèééåääÕÝÝä÷÷çùùÙëëÛììæùùä÷÷ÕèèäúúæýýÜççÝÛÛÚÚÚÍÍÍ×ÖÖÔÜÜË——ànnâxxÕppÖppãwwÝllÑ^^ähhæccÈ„„ÙààÛÛÛÛÛÛèããâõõáddÿÿóôÿÛ##à@@è;;à77Í££ÞååÛÛÛÞÞÞëççæøøãggÿÿóõÿÜ••âÿÿãõõ×ííÖÞÞßÝÝÚÚÚÔÔÔßÛÛÚììØ``ö÷éê õÜ‹‹éôôêããßÚÚÓÒÒÝÝÝÚÚÚÒÒÒÝÙÙÙêê×``ôõæÕ¾¾ÜÌÌÎÈÈàáááààÒÒÒÃÃÃÞÞÞÛÛÛßÛÛëããæõõãddÿÿñßÜÜëññÛÜÜËÊÊÚÚÚÙÙÙ×××ÞÞÞÛÜÜÛëëçõõáÿÿákkÿÿñÝÕÕèééçææØØØéééìììÜÜÜÜÜÜÚÓÓ×rrãnnßyyÖ11íïàÍÇÇ×ÙÙÔÓÓÅÅÅÕÕÕÖÖÖÌÌÌÜÜÜÜÍÍó ÿþìþÿðÝÖÖçééäääÕÕÕåååçççÚÚÚÜÜÜÜÍÍó ÿþìÿÿñßÙÙêííççç×××èèèëëëÝÝÝÜÜÜÜÎÎéö ò â ó ö æÕÎÎÞààÜÛÛÍÍÍÝÝÝÞÞÞÓÓÓÝÝÝäããÜÎÎÜÌÌÜÍÍÛÍÍÜÍÍÜÌÌÛÎÎÚÚÚÛÛÛÛÛÛÚÚÚÛÛÛÚÚÚÛÛÛååå(0` æææãããääääããëëëìëëìììëììêææÌÏÏÍÈÈËÏÏËËË­¨¨ÅÅů°°­­­ÈÅÅ®¬¬ÅÉÉÇÁÁóõõñññÐÒÒõóóÎÐÐÏÏϱ±±ÔÒÒ°¬¬±³³±§§¾áÚÜãÀàÒ£à×z@@ÿßüÎôô»XX¾ÊÊÜ«èç«QQàööέ¤¤Ë®®Á««Ã¬¬É°°¡ÍÕÕÕÙèèëññìòòóúúÒÑÜܾ½½ÎØØÓÜÜÓÓÓ»ÃÃÿªªªØØØ“““ððð···××לœœèèèÍÇÇÈÂÂÁÄÚÙ ½                                                            !"""##"$%%&"#"#"&'("#""##")*+ #,,,,,,,,--,,,,,,./0,,,,,,,123   ",..,,,.,44,.,.,15-1666666789   ",,,,,,,,--,,,,,:;<=>>>>>?@A   #,.,,,,,,--,,,.,BCDDEEEDF   ",,,,,,.,--,.,.,GHI   ",,,,,,,,--,,,,,BJI   ",..,,,.,--,.,.,GK3  #,,,,,,,,--,,,,,GK3L     %74-----!MM74-"!NK?O     P74----4!M QLIRS  ",,,,,,,,- RT UI   ",.,.,,.,-IIV V;W   ",.,,,,,,-RIQOOOOIC   #,,,,,,.,-  X   #,,,,,,,,-    #,.,,,,,,-     ",.,,...,4   #,,,,,,,,!    YZZ P!4--4-4!M        [7-!!-!!7\\6--!-!-7M    ],,,,,,,,!-,,,,,,,,-    ^,.,,.,.,-4,.,.,,.,-   ],,,,,,,,--,.,,,,.,-   ],.,,,,,,!4,,,,,,,,-    ],.,,,,,,!-,,,,,,,,4  ],,,,,,,,!-,,,,,,,,-    ^,...,,.,-4,..,...,4   ],,,,,,,,!-,,,,,,,,#   _&]]]]]^)[ ]]]]]]^#[       ( @æææëîîèèèêîîäããÙ×××××ÖÙÙØØØéééÓÒÒ½½½ÎÍÍ»»»ÍÌÌËË˺ººÁºº¿Â¼¼¼ðððïòòîííêêêÏÏÏãããÊÒÒÔÓÓèååÄÄÄÒÕÕÃÃÃÆÉÉØÜÜ×áắ¯ÑäâãËäݼä™YYðóóÔÆÆêÿäîõÑýÌ]]ÑÂÂÐ!!½œœÏ˜˜Ë——±‰‰ÝëëäääåýÚ44áüüëôôéõõèôôíúúû×11ÛééèááÆÃÃÜÜÜÁ²²ÙðÓÛÌ11»®®Î ÔÂÂϾ¾¬¬¬ÉËËÝÝÝÐÁÁÇÇÇãÒÆÆÁ´´Ò ÃÅÅé ä éêèè×ÐÆÆ                            !! !! !" #$%&'&%($%'&)*+''''),-" ./01111123111454166167  8011161201619:;<<<;=>  ?8011111@31A1BCDEEFG  8016161201H1IJKL  /016111@3111B>K  M!NO3030PQRP0PS>  TQ0@22@UNVW8TMX/011111&".YZZZ  ?[011161& \  8311161] W011111]  ^011111%   !_O30003`a   ^`bcccbUQ0@@@0U  ^@11111@011161%!  ^d166612016161&  ^011161@011111]  ^016161@011111& ^011111@011111&e  ^f30003ff3@003` a ^^^^^^g^^^^^^^     ( åååÝÝÝÜÜÜÛÛÛÓÓÓÚÚÚÌÌÌÑÑÑÍÍÍÒÒÒÞÞÞëëëçèèØÖÖéääëççÞÚÚßÛÛçää×ÔÔéååÝÚÚÜÝÝèééåääÕÝÝä÷÷çùùÙëëÛììæùùÕèèäúúæýýÜççÝÛÛ×ÖÖÔÜÜË——ànnâxxÕppÖppãwwÝllÑ^^ähhæccÈ„„ÙààèããâõõáddÿÿóôÛ##à@@è;;à77Í££ÞååæøøãggÿóõÜ••âÿÿãõõ×ííÖÞÞßÝÝÔÔÔÚììØ``ö÷éê õÜ‹‹éôôêããßÚÚÓÒÒÝÙÙÙêê×``ôæÕ¾¾ÜÌÌÎÈÈàáááààÃÃÃëããæõõãddñßÜÜëññÛÜÜËÊÊÙÙÙ×××ÛëëçõõáÿÿákkÝÕÕçææØØØéééìììÚÓÓ×rrãnnßyyÖ11íïàÍÇÇ×ÙÙÔÓÓÅÅÅÕÕÕÖÖÖÜÍÍó þìþðÝÖÖçééäääçççó ÿßÙÙêííèèèÜÎÎéö ò â æÕÎÎÞààÜÛÛäããÛÍÍÛÎÎ   !"#$%&'()*+,-./01234567859:;<=> ?@5ABC5DEFGHIJKLMNOPQRSTUV WXYZQ[\]^_` a bcd55efghijk hlmno55epqrstuvwxyz{|}~€‚ƒ„5…†‡5ˆ‰Š‹Œƒ5…†Ž5eŒk‘ ’“”•–”—˜™š ›’]ƒœƒ](0`€€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿ÷÷ÿ÷ÿ÷÷wÿ÷÷÷wwwwwwwwwwwwww÷wwww÷ÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿ÷ÿÿÿÿÿwwÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿ÷ÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿ÷ÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿøÿÿÿÿ÷wÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿ÷ÿÿÿÿÿw÷ÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿ÷ÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿ÷ÿÿÿÿÿ÷wÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿ÷ÿÿÿÿÿ÷ÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿ÷ÿÿÿÿÿwÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿÿÿÿÿw÷wwwwwŒˆÈˆˆˆŒˆÈˆˆˆŒˆˆˆˆwÿÿÿÿÿ|ÌÌÌÌÌÌÌÌÌÌLÌÌÌÌÌ÷ÿÿÿÿÿŒÌÌÌÌÌLÌÌÌÄÌÌÌÌÌOÿÿÿÿÿŒÌÌÌÌÌÌÌÌÌLÌÌÄÌÌw÷ÿÿÿÿÿŒÌÌÌÌÄÌÌÌÌwwwwwwÿ÷wÿÿÿÿÿŒÌÌÌÌÌÌÌÌÈÿÿÿÿwÿ÷ÿÿÿÿÿŒÌÌÌÌÄLÌÌÌÿÿÿÿÿ÷ÿ÷÷ÿÿÿÿŒÌÌÌÌÌÌÌÌÄÿÿÿÿ÷ÿw÷ÿÿÿÿÿÌÌÌÌÌÌÌÌÌÌÿÿÿÿ÷ÿÿÿÿÿÿŒÌÌÌÌÄLÌÌÄÿÿÿÿÿ÷ÿwÿÿÿÿÿŒÌÌÌÌÌÌÌÌÌÿÿÿÿÿ÷ÿw÷w÷÷wŒÄÄÄÌŒLÄÌLÿÿÿÿ÷ÿ÷÷w÷w„ÌŒÄÄÌwwÿÿÿÿ÷÷wÿÿÿÿÿ|ÌÌÌÌÄÿÿÿ÷ÿÿÿÿ÷÷w÷ÿÿÿÿÿŒÌÌÌÌÌÿÿÿÿÿÿÿ÷wÿÿÿÿÿŒÌÌÌÌÄÿ÷÷wwwwwxÿ÷ÿÿÿÿÿ|ÌÌÌÌÌÿÿÿÿøÿÿÿÿÿÿÿÿÿÿÌÌÌÌÌÌÿÿÿÿÿ÷ÿÿÿÿÿwwÿÿÿÿÿŒÌÌÌÌÄÿÿÿÿ÷ÿÿÿÿÿ÷ÿÿÿÿÿŒÌÌÌÌÌÿÿÿÿÿ÷ÿÿÿÿÿwÿÿÿÿÿŒÌÌÌÌÌÿÿÿÿ÷ÿÿÿÿÿwÿÿÿÿÿÿŒÌÌÌÌÄÿÿÿÿÿ÷ÿÿÿÿÿwÿÿÿÿÿŒÌÌÌÌÄÿÿÿÿ÷ÿÿÿÿÿ÷øÈŒŒˆŒLLÄÄÄćwwwwxw‡wwwtÌÌÌÌÌLÌÌÌÌÌÿÿÿÿÿ÷ÿÿÿÿÿøÌÌÌÌÌÌÌÌÌÌÌÿÿÿÿ÷ÿÿÿÿÿwtÌÌÌÌÌLÌÌÌÌÌÿÿÿÿ÷ÿÿÿÿÿüÌÌÌÌÌÌÌÌÌÌÄÿÿÿÿÿ÷ÿÿÿÿÿ÷üÌÌÌÌÌLÌÌÌÌÄÿÿÿÿ÷ÿÿÿÿÿtÌÌÌÌÌÌÌÌÌÌÌÿÿÿÿ÷ÿÿÿÿÿwôÌÌÌÌÌÌÌÌÌÌÌÿÿÿÿ÷ÿÿÿÿ÷üÌÌÌÌÌLÌÌÌÌÄÿÿÿÿ÷ÿÿÿÿÿüÌÌÌÌÌÌÌÌÌÌÌÿÿÿÿÿ÷ÿÿÿÿÿwtÌÌÌÌÌÌÌÌÌÌÌÿÿÿÿ÷ÿÿÿÿÿôLÌÄÄLDÄLÄÄDwwwwww÷wwwwÿÿÿ÷ÿÿÿÿ÷÷ÿ÷÷÷ÿ÷ÿ( @€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ÷ww÷w÷wwww÷wwwwwwwww÷wwÿÿÿÿ÷÷ÿÿw÷ÿw÷wÿ÷÷÷ww÷w÷wÿ÷÷w÷ÿw÷ÿ÷wÿÿÿÿw÷÷÷ÿ÷ww÷÷w÷÷ÿ÷÷÷÷w÷ÿÿ÷÷÷ÿ÷ÿwwwȈȈˆŒŒˆˆ|ˆ‡w÷ÿŒÌÌÌÌÌÌÌÌÌÌ÷ÿÿ÷ÌÌÌÌÌÌÈÌDÌÇ÷w÷ŒÌÌÌÌÌÇ÷ÿw÷÷|ÌÌÌLÌÇÿ÷w÷w÷ÿ÷ÌÌÌÌÌÌÇÿ÷÷÷ÿŒÌÌÄÌÌÇ÷www÷wŒLŒÌÄÌGÿÿwww|ÌLÄw÷wÿwwÿÿÌÌÌÌ÷w÷÷ww÷÷ŒÌÌÌ÷wwww÷wÿ÷ŒÌÌÌ÷÷÷ÿÿw÷ÿŒÌÌÌ÷÷÷ww÷ŒÌLÌ÷w÷ÿÿ÷ÿÿÿŒÌÌÌwÿÿw÷÷wøŒˆÈÌLÄÈwwwwwwww|ÌÌÌÌÌLÌ÷ÿwÿÿw|ÌÌÌLÌÌÌw÷÷÷|ŒÌÌÌÌÌÌ÷÷wÿÿ|ÌÌÄÌÄÌÌ÷ÿ÷ÿww|ÌÌÌŒÌÌÌw÷ÿw|ÌÌÌÌÌÌÄ÷ÿ÷÷ÿ÷|LÌLÌÌLÌ÷w÷÷÷w÷÷w÷ww÷÷wwwwwww( €€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ÷ÿw÷÷ww÷wwÿwÿÿÿ÷÷ÿ÷w÷wwwxˆ||wÿÌÌÌÈŒw÷ŒÌÌ÷÷÷ŒÌ̇ÿ|Ìww÷÷÷ÌÌ÷ÿŒÌÿwÿwx‡ÌÌw÷wüÌÌÈÿÿ|ÌÌÌw÷w|ÌÌÌ÷÷÷÷w÷w÷puzzles-20170606.272beef/icons/bridges.ico0000644000175000017500000006117613115373725017134 0ustar simonsimon 00 ¨%–  ¨>& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÒÓÓÓÕÕÕÕÕÕÓÓÓÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕãããáááÙÙÙÙÙÙââââââÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÓÓÓÙÙÙÚÚÚ‡‡‡222999’’’ÞÞÞ×××ÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÒÒÒÙÙÙÉÉÉ000___œœœ™™™VVV@@@ÒÒÒØØØÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÙÙÙÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×××ÚÚÚ000***âââÿÿÿþþþýýýÿÿÿÕÕÕDDDÝÝÝÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÛÛÛ¸¸¸çççÿÿÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûûûÿÿÿ‘‘‘ åååÿÿÿÕÕÕ°°°ÑÑÑþþþÿÿÿÒÒÒ’’’âââÒÒÒÕÕÕÕÕÕÕÕÕÒÒÒâââ•••"""'''yyyÿÿÿùùùaaa[[[ ƒƒƒÿÿÿÿÿÿWWW;;;âââÓÓÓÕÕÕÕÕÕÕÕÕÒÒÒåå剉‰<<<¥¥¥”””——————————————————————————————————————————————————————————————————–––™™™¹¹¹ÿÿÿüüüôôôààà@@@JJJÿÿÿÿÿÿ›››ÙÙÙÕÕÕÕÕÕÕÕÕÕÕÕÒÒÒæææ†††NNNÊÊʵµµ¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸¸»»»°°°»»»ÿÿÿÿÿÿñññaaa···ÿÿÿÿÿÿžžžÙÙÙÕÕÕÕÕÕÕÕÕÕÕÕÒÒÒâââ••• „„„ÿÿÿüüüÄÄÄÔÔÔ***eeeÿÿÿÿÿÿaaa555àààÓÓÓÕÕÕÕÕÕÕÕÕÔÔÔÜÜܱ±±áááÿÿÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿÿÿ„„„ïïïÿÿÿ”””;;;TTTÎÎÎÿÿÿÞÞÞ ‡‡‡ãããÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÞÞÞÛÛÛÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÚÚÚÜÜÜìììáááÌÌÌËËËÛÛÛìììâââÕÕÕ"""???òòòÿÿÿþþþþþþÿÿÿççç+++444ÙÙÙÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÓÓÓÔÔÔÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÑÑÑØØØÕÕÕrrr[[[ÆÆÆããã»»»zzzººº¶¶¶ooo ***ÉÉÉÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÓÑÑÑØØØÊÊÊ))) yyy¾¾¾ÅÅÅŽŽŽ°°°äääÐÐÐnnn(((---yyyØØØÚÚÚÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØàààßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßããã777+++éééÿÿÿþþþþþþÿÿÿûûûSSSÇÇÇÚÚÚàààÿÿÿAAA^^^ÿÿÿÞÞÞÖÖÖÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÓÓÓáááÿÿÿüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüüùùùÿÿÿ¥¥¥ÜÜÜÿÿÿÅÅÅŠŠŠ¤¤¤ðððÿÿÿùùù$$$```äääËËËÿÿÿBBB```ÿÿÿÌÌÌÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÒâââ•••dddÿÿÿÿÿÿ|||666EEEÿÿÿÿÿÿÔÔÔÒÒÒÿÿÿBBB___ÿÿÿÏÏÏÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÑÑÑÇÇÇÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÈÑÑÑ’’’ÿÿÿûûûýýýÉÉÉNNN<<<ÿÿÿÿÿÿÇÇÇÄÄÄÖÖÖÿÿÿBBB```ÿÿÿÏÏÏÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÚÚÚ¼¼¼€€€†††………………………………………………………………………………………………………………………ŒŒŒÿÿÿûûûþþþ•••"""ÿÿÿÿÿÿÂÂÂÅÅÅÖÖÖÿÿÿBBB```ÿÿÿÏÏÏÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓààà¡¡¡ ...++++++++++++++++++++++++++++++***))))))******333PPPÿÿÿÿÿÿººº±±±<<<AAAÿÿÿÿÿÿzzz!!!ÚÚÚÑÑÑÿÿÿBBB```ÿÿÿÏÏÏÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÒÒÒâââÿÿÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿÿÿ¼¼¼ÁÁÁÿÿÿ¾¾¾YYYlllÕÕÕÿÿÿææætttäääÎÎÎÿÿÿBBB```ÿÿÿÏÏÏÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÒÒÒÕÕÕãããÏÏÏ«««¥¥¥ºººßßßÜÜÜßßßUUU ÅÅÅÿÿÿýýýþþþÿÿÿààà***---ÖÖÖÖÖÖÑÑÑÿÿÿBBB```ÿÿÿÏÏÏÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÓÓÓÙÙÙÓÓÓccc---¢¢¢áááÖÖÖRRRAAAŒŒŒ”””UUU111ÊÊÊÚÚÚÓÓÓÑÑÑÿÿÿBBB```ÿÿÿÏÏÏÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÊÊÊ((( zzz¶¶¶ÁÁÁŸŸŸDDD~~~âââÞÞÞŸŸŸUUUHHHŽŽŽÛÛÛÙÙÙÓÓÓÕÕÕÑÑÑÿÿÿBBB```ÿÿÿÏÏÏÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÝÝÝ???!!!ÊÊÊëëëîîîêêêòòòëë뢢¢ÝÝÝØØØÿÿÿppp777ÿÿÿàààÔÔÔÔÔÔÕÕÕÕÕÕÑÑÑÿÿÿBBB```ÿÿÿÏÏÏÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓßßߢ¢¢±±±ÝÝÝÔÔÔÕÕÕÕÕÕÕÕÕÓÓÓààà¡¡¡±±±ççç±±±WWWfffYYYÀÀÀìììFFF111àààÊÊÊÿÿÿooo444ÿÿÿÐÐÐÔÔÔÕÕÕÕÕÕÕÕÕÑÑÑÿÿÿBBB```ÿÿÿÏÏÏÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÒåå剉‰xxxåååÒÒÒÕÕÕÕÕÕÕÕÕÒÒÒåååUUU444ßßßÕÕÕÅÅÅ^^^ nnnÉÉÉááᢢ¢ ¼¼¼ÕÕÕÿÿÿooo444ÿÿÿÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÑÑÑÿÿÿBBB```ÿÿÿÏÏÏÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÒæææ„„„\\\éééÑÑÑÕÕÕÕÕÕÕÕÕÒÒÒæææ333TTTèèèÏÏÏâââ···ÎÎÎÜÜÜ×××ÅÅŧ§§ÙÙÙÿÿÿooo444ÿÿÿÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÑÑÑÿÿÿBBB```ÿÿÿÏÏÏÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÒæææ………dddèèèÑÑÑÕÕÕÕÕÕÕÕÕÒÒÒæææ<<<JJJåååÏÏÏàà൵µ¼¼¼ØØØÙÙÙººº­­­ØØØÿÿÿooo444ÿÿÿÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÑÑÑÿÿÿBBB```ÿÿÿÏÏÏÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÒããã”””âââÓÓÓÕÕÕÕÕÕÕÕÕÒÒÒäääxxxÓÓÓÜÜܲ²²:::½½½ÕÕÕååå}}}ÐÐÐÐÐÐÿÿÿooo444ÿÿÿÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÑÑÑÿÿÿAAA^^^ÿÿÿÏÏÏÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÚÚÚ¾¾¾ÉÉÉØØØÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÆÆÆ mmmíííÆÆÆzzzÊÊÊãããËËËfffäääËËËÿÿÿooo444ÿÿÿÓÓÓÕÕÕÕÕÕÕÕÕÒÒÒÑÑÑÿÿÿCCCaaaÿÿÿÎÎÎÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÒááጌŒkkkØØØõõõöööâââ²²²)))ÒÒÒ×××ÍÍÍÿÿÿooo444ÿÿÿÓÓÓÕÕÕÕÕÕÓÓÓßßßÚÚÚÔÔÔ)))>>>ÙÙÙÛÛÛÞÞÞÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓàààŒŒŒGGGQQQ333;;;ÊÊÊÚÚÚÔÔÔÎÎÎÿÿÿooo444ÿÿÿÓÓÓÕÕÕÓÓÓááá¡¡¡ )))®®®àààÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓáááÇÇÇxxx===333SSS   ÞÞÞÙÙÙÓÓÓÖÖÖÎÎÎÿÿÿooo444ÿÿÿÓÓÓÒÒÒáá቉‰___ÔÔÔúúúøøøÍÍÍOOOœœœàààÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÒÙÙÙäääææææææåååàààÔÔÔÔÔÔÕÕÕÕÕÕÎÎÎÿÿÿooo444ÿÿÿÑÑÑÜÜܵµµÿÿÿýýýÿÿÿÿÿÿýýýÿÿÿsss ÄÄÄÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÎÎÎÿÿÿooo444ÿÿÿÐÐÐäääMMM777ÿÿÿÿÿÿnnnRRRJJJ~~~ÿÿÿüüü"""eeeåååÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÎÎÎÿÿÿooo444ÿÿÿÕÕÕÒÒÒ™™™ÿÿÿÿÿÿyyyÒÒÒüüüÿÿÿ}}}"""ÝÝÝÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÎÎÎÿÿÿooo444ÿÿÿÖÖÖËË˾¾¾ÿÿÿûûûÿÿÿ777ëëëÿÿÿÿÿÿ£££ ØØØÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÎÎÎÿÿÿooo444ÿÿÿÕÕÕÐÐÐ ¦¦¦ÿÿÿúúúôôôÿÿÿEEEZZZÿÿÿÿÿÿŠŠŠÛÛÛÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÎÎÎÿÿÿmmm333ÿÿÿÐÐÐâââ===KKKÿÿÿüüüfffNNN‹‹‹ÿÿÿÿÿÿ333TTTåååÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÿÿÿppp666ÿÿÿ×××ßßߢ¢¢¯¯¯ÿÿÿááá­­­ÍÍÍþþþÿÿÿ———µµµÝÝÝÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÀÀÀªªª666   ºººÓÓÓáááiii‡‡‡ïïïÿÿÿþþþãããvvv~~~âââÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔØØØ¶¶¶‰‰‰†††«««ÖÖÖÕÕÕÚÚÚ›››………³³³ÜÜÜÚÚÚ­­­ƒƒƒ¢¢¢ÝÝÝÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÛÛÛåååäääãããåååÝÝÝÕÕÕÕÕÕÔÔÔâââæææÛÛÛÓÓÓÓÓÓÝÝÝæææàààÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÕÕÕÕÕÕÕÕÕÒÒÒÒÒÒÔÔÔÕÕÕÕÕÕÔÔÔÒÒÒÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ( @ ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÒÔÔÔÛÛÛÙÙÙÒÒÒÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓáááÝÝÝÀÀÀÆÆÆãããÜÜÜÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÐÐÐááá–––222333111BBBºººÞÞÞÓÓÓÕÕÕÕÕÕÖÖÖãããåååååååååååååååååååååååååååååååååååååååååååååååååååâââñññŠŠŠ%%%ÉÉÉÿÿÿûûû––– »»»ÜÜÜÓÓÓÙÙÙÈÈÈ­­­ÃÃþ¾¾¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿¿ÀÀÀ½½½---ÛÛÛåååŽŽŽ¾¾¾ÿÿÿ“““EEEãããÒÒÒÚÚÚÁÁÁ777bbb^^^__________________________________________^^^hhh444VVVÿÿÿÖÖÖ***ãããööö444ÆÆÆÙÙÙÛÛÛ¾¾¾III“““‹‹‹ŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒŒ‹‹‹‰‰‰˜˜˜RRRbbbÿÿÿÿÿÿœœœ<<<öööûûû777ÀÀÀÛÛÛÙÙÙÅÅÅsss~~~|||‰‰‰‰‰‰‚‚‚sss444úúúÜÜÜiiiHHHÿÿÿ¾¾¾777ÜÜÜÔÔÔÖÖÖÓÓÓìììûûûøøøøøøøøøøøøøøøøøøøøøøøøøøøøøøùùùöööÿÿÿõõõÌÌÌÌÌÌôôôÿÿÿ]]]QQQùùùðððÿÿÿÞÞÞ(((–––áááÒÒÒÕÕÕÕÕÕÌÌÌÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÇÇÇÚÚÚˆˆˆ$$$::::::$$$‰‰‰çççYYY///nnn[[[%%%‰‰‰âââÓÓÓÕÕÕÕÕÕ×××îîîððððððððððððððððððððððððððððððíííüüü”””&&&ÖÖÖÿÿÿÿÿÿÔÔÔ&&&ìììÒÒÒ@@@sssÞÞÞßßßÓÓÓÕÕÕÕÕÕÖÖÖÒÒÒ¢¢¢žžžŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸžžž¦¦¦///ÐÐÐëëë}}}’’’ÿÿÿËËË///ËËËÿÿÿddd¤¤¤ñññÎÎÎÕÕÕÕÕÕÕÕÕ×××ÏÏÏ{{{sssuuuuuuuuuuuuuuuuuuuuuuuuttt|||TTT@@@ÿÿÿëëë©©©***ÃÃÃÿÿÿBBB¢¢¢ÿÿÿ___¡¡¡îîîÐÐÐÕÕÕÕÕÕÕÕÕ×××ÏÏÏ{{{sssuuuuuuuuuuuuuuuuuutttsssqqq{{{TTTAAAÿÿÿÿÿÿ¶¶¶///ÝÝÝÿÿÿCCC¢¢¢ÿÿÿaaa¢¢¢ïïïÐÐÐÕÕÕÕÕÕÕÕÕÖÖÖÒÒÒ¢¢¢žžžŸŸŸŸŸŸŸŸŸŸŸŸŸŸŸœœœ¢¢¢­­­®®®¤¤¤£££///ÏÏÏóóówwwTTTóóóÏÏÏ///ÍÍÍþþþbbb¢¢¢ïïïÐÐÐÕÕÕÕÕÕÕÕÕÕÕÕ×××íííðððïïïïïïïïïïïïíííüüüæææ­­­¥¥¥ÒÒÒÿÿÿ“““&&&ÒÒÒþþþÿÿÿÔÔÔ'''ÛÛÛúúúbbb¢¢¢ïïïÐÐÐÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÑÑÑÐÐÐÐÐÐÐÐÐÐÐÐÎÎÎÜÜÜ……… AAAHHH###XXXæææŽŽŽ,,,HHHEEE,,,ŽŽŽâââËËËýýýbbb¢¢¢ïïïÐÐÐÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÖÖÖÕÕÕÕÕÕÓÓÓââ☘˜ ···ëëëïïïÕÕÕ???^^^ëëëïïïiiijjjòòòÝÝÝÔÔÔÎÎÎýýýbbb¢¢¢ïïïÐÐÐÕÕÕÕÕÕÕÕÕÛÛÛ¿¿¿žžžÝÝÝÓÓÓÕÕÕÔÔÔÜÜÜ777¡¡¡éééccc777ªªªÜÜÜ***±±±þþþƒƒƒ÷÷÷ÌÌÌÖÖÖÎÎÎýýýbbb¢¢¢ïïïÐÐÐÕÕÕÕÕÕÕÕÕÝÝݹ¹¹llláááÒÒÒÔÔÔÚÚÚÁÁÁ222ÐÐÐßßߟŸŸ@@@ÔÔÔåååPPP„„„ÿÿÿ}}}€€€÷÷÷ÎÎÎÖÖÖÎÎÎýýýbbb¢¢¢ïïïÐÐÐÕÕÕÕÕÕÕÕÕÜÜܹ¹¹vvváááÓÓÓÔÔÔÙÙÙÇÇÇ222ËËËÞÞÞ‘‘‘HHHÛÛÛãããIIIÿÿÿ~~~øøøÎÎÎÖÖÖÎÎÎúúúaaa   íííÐÐÐÕÕÕÕÕÕÕÕÕÙÙÙÅÅų³³ÛÛÛÔÔÔÕÕÕÓÓÓãããFFF}}}óóóccckkkñññ···(((ÅÅÅûûû€€€øøøÏÏÏÕÕÕÍÍÍÿÿÿddd¥¥¥ôôôÎÎÎÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖØØØÕÕÕÕÕÕÕÕÕÓÓÓÜÜܺºº{{{ÕÕÕÙÙÙŸŸŸ‹‹‹ÜÜÜõõõøøøÍÍÍÙÙÙÛÛÛ¶¶¶333]]]ÅÅÅáááÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÞÞÞ»»»DDD...000555———âââÌÌÌøøø÷÷÷ÑÑÑÒÒÒCCC;;;ŠŠŠ{{{(((mmmàààÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÜÜÜãããÇÇÇÁÁÁÝÝÝáááÓÓÓÎÎÎøøøöööÜÜÜIIImmmÿÿÿýýýÿÿÿôôô666‚‚‚äääÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÓÓÓÙÙÙÚÚÚÔÔÔÒÒÒÖÖÖÎÎÎøøøÿÿÿ¨¨¨777ÿÿÿ¸¸¸rrrøøøÎÎÎ444ØØØÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔÕÕÕÕÕÕÖÖÖÎÎÎøøø~~~ÿÿÿ~~~cccÿÿÿÿÿÿzzzÿÿÿùùù888¾¾¾ÛÛÛÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÎÎÎööö€€€}}}ÿÿÿ‘‘‘PPPÿÿÿää䯯Æ...ëëëïïï444ÊÊÊØØØÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÏÏÏýýý€€€þþþÌÌÌ---ÈÈÈåååqqq¤¤¤ÿÿÿ~~~RRRäääÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓºººKKKKKK¸¸¸ßßßœœœ***ÁÁÁÿÿÿûûûŽŽŽ...ÈÈÈÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖ¿¿¿¾¾¾¾¾¾ÀÀÀÔÔÔÝÝÝÈÈȺººÓÓÓÍÍÍ···ÓÓÓÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÛÛÛÛÛÛÛÛÛÛÛÛÕÕÕÓÓÓÙÙÙÜÜÜÕÕÕÖÖÖÝÝÝÖÖÖÓÓÓÕÕÕÕÕÕ(  ÕÕÕÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÝÝݹ¹¹¾¾¾ÞÞÞÔÔÔÖÖÖàààáááááááááááááááááááááàààæææ“““‘‘‘›››ÞÞÞÅÅ҇‡•••“““““““““““““““˜˜˜uuu   ÈÈÈ»»»•••½½½ÂÂÂuuu………ƒƒƒƒƒƒƒƒƒƒƒƒ„„„ŽŽŽ‘‘‘nnn®®®ÀÀÀ¥¥¥¡¡¡···ÖÖÖäääååååååååååååååååå壣£’’’¦¦¦ˆˆˆ–––”””ÝÝÝÔÔÔÃÃÃÁÁÁ¿¿¿ÉÉÉ’’’˜˜˜Ëˢ˜˜¦¦¦———šššâââÔÔÔÍÍÍvvvlllnnnmmmvvvvvvSSSòòòuuuÄÄÄ™™™²²²¸¸¸ÝÝÝÓÓÓÔÔÔÅÅÅÃÃÃÃÃÃÊÊÊ¡¡¡¥¥¥———žžž¿¿¿”””§§§³³³µµµÞÞÞÔÔÔÕÕÕÜÜÜÚÚÚäää“““‚‚‚ŠŠŠ………ŸŸŸooo›››ää䪪ª···ÞÞÞÓÓÓ¿¿¿¯¯¯àà຺º†††²²²““““““ºººžžžàààÞÞÞ«««···ÜÜÜÔÔÔ···ßßßÁÁÁªªª¨¨¨ŠŠŠ´´´œœœÓÓÓèè謬¬¼¼¼äääÒÒÒÖÖÖ×××ÓÓÓÞÞÞšššsss|||‹‹‹ááá‘‘‘âââ«««}}}¸¸¸ÜÜÜÕÕÕÕÕÕÕÕÕÔÔÔÞÞÞÄÄÄ¿¿¿ÜÜÜÙÙÙ™™™ÃÃȈˆ¼¼¼ÄÄÄ………ËËËÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÙÙÙÛÛÛÒÒÒÚÚÚ   «««···°°°§§§©©©²²²ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔÖÖÖÎÎÎ~~~ÆÆÆ„„„ÌÌ̾¾¾†††ÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÍÍͽ½½ÒÒÒÊÊÊÓÓÓÏÏÏÍÍÍÙÙÙ(0` ÕÕÕÒÒÒÓÓÓÔÔÔãããáááÙÙÙâââÖÖÖÚÚÚ‡‡‡222999’’’ÞÞÞ×××ÉÉÉ000___œœœ™™™VVV@@@ØØØ***ÿÿÿþþþýýýDDDÝÝÝÛÛÛ¸¸¸çççûûû‘‘‘ ååå°°°ÑÑÑ•••"""'''yyyùùùaaa[[[ ƒƒƒWWW;;;‰‰‰<<<¥¥¥”””———–––¹¹¹üüüôôôàààJJJ›››æææ†††NNNÊÊʵµµ»»»ñññ···žžž „„„ÄÄÄeee555ÜÜܱ±±ïïïTTTÎÎÎìììÌÌÌËËË???òòò+++444rrrÆÆÆzzzººº¶¶¶ooo)))¾¾¾ÅÅÅŽŽŽäääÐÐÐnnn(((---ßßß777éééSSSÇÇÇAAA^^^ŠŠŠ¤¤¤ððð$$$```BBBddd|||666EEEÏÏÏÈÈȼ¼¼€€€………ŒŒŒÂ¡¡¡...333PPP!!!ÁÁÁYYYlllttt«««UUU ccc¢¢¢RRR111ŸŸŸ~~~HHHëëëîîîêêêpppfffÀÀÀFFFxxx \\\èèè§§§­­­²²²:::½½½}}}mmmíííCCCkkkõõõöööÍÍÍ>>>GGGQQQ®®®===   úúúøøøOOOsssMMM£££¦¦¦ZZZKKK‹‹‹¯¯¯ªªªiiivvv³³³   !"#$%&'()*+,-./000000000000000000000000123456789:);<=>??????????????????????@ABCDEFGHIJKLM$$$$$$$$$$$$$$$$$$$$$$$N*ONP5QRS -TUVVVVVVVVVVVVVVVVVVVVVWWVWXYCZ[5\E]^CY_`>:abV #]]]]]]]]]]]]]]]]] ]cde#c/fg%hi+jklO.6mNkXnopqW+Lr(3stu0 *vwxyT,z3 E{{{{{{{{{{{{{{{{{|h}&~_ E€CCCCCCCCCCCCCCC4=‚]tƒ„…4†‡veˆ‡d-‚T‰Š‹ŒŽ ˆ+‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘+’&K<lZˆ‡ “”J•••••••••••••••–,A&-/—tˆ‡E˜7™hhhhhhhhhhrršH›o^<€nœ +ˆ‡C“sžŸIH vbˆ‡¡=o{]{¢£tEz+ˆ‡¤Hl‚z¥¦€–>¢l§L +ˆ‡Ly£np¨!©¨¢Hª«u#+ˆ‡"fœL¬­®g¬¯¥"°|E+ˆ‡{¥^"E˜O^%^9±ž²c³§ELqiw+ˆ‡);´))¢i{tµx¥µ“qi+ˆ‡IY¶}+Iša·R¸b]tT¹qi+ˆ‡I•Š·+Iv´.]¼½ ¾)¿Xwwqi+€ sm(ÀÁmn¯LeH±veqi+Â5b–ÃÄż0rÆqi{ rÇ#E–‚’ÈÉš:L bqi˜0,71TrÊE´Ëš~Ìbqi;ÍÎÆÏEvII)Ebqi+]MOÐWZ bqiwvÑ|x¦F©C/[)bqi’3AC¿/"bqiels&A|¬Ò(bqiw£ÓÍDŽÔƒÕ#bÀšwËÖC±K’ךa)°{¥ØºÆ?M"²Ù¸ÌoÚ `Û©p;AJ¡ G•Ü] º8¥"#)v)"I#"IE( @ÕÕÕÒÒÒÔÔÔÛÛÛÙÙÙÓÓÓáááÝÝÝÀÀÀÆÆÆãããÜÜÜÐÐЖ––222333111BBBºººÞÞÞÖÖÖåååâââñññŠŠŠ%%%ÉÉÉÿÿÿûûû »»»ÈÈÈ­­­ÃÃþ¾¾¿¿¿½½½---ŽŽŽ“““EEEÚÚÚÁÁÁ777bbb^^^___hhh444VVV***öööIII‹‹‹ŒŒŒ‰‰‰˜˜˜RRRœœœ<<<ÅÅÅsss~~~|||‚‚‚úúúiiiHHHìììøøøùùùõõõÌÌÌôôô]]]QQQððð(((ÇÇLjˆˆ$$$:::çççYYY///nnn[[[×××îîîíííüüü”””&&&@@@ßßߢ¢¢žžžŸŸŸ¦¦¦ëëë}}}’’’ËËËddd¤¤¤ÎÎÎÏÏÏ{{{uuutttTTT©©©¡¡¡qqqAAA¶¶¶CCCaaaïïï®®®£££óóówwwÍÍÍþþþæææ¥¥¥'''ÑÑÑ………###XXX,,,ýýý···???jjjòòòééécccªªª±±±ƒƒƒ÷÷÷¹¹¹lllPPP„„„€€€vvv‘‘‘   ³³³FFFkkkØØØDDD...000555———;;;mmmààà666ää䨨¨¸¸¸rrrzzz888ÊÊÊKKK       !"###############$%&"'( )*+,-..............-/0123 40 "5'67777777777777689:,;<4+=>?@AAAAAAAAAAABA88C>0D EF"+ GHHHHHHHHHHI4JKKLMNIOP KQ)RSTTS8UVWXY8Z[OOOOOOOOOO\]^__`Ga>bcdeeeeeeeeedfW ghijWjklmZno>ppppppppqBrags3!c.t[ Zno>ppppppq>uorvwWxcycz cdeeeee;c {l|Wn}~r}nW€,cz Z\Ozzzz\] ‚'_€ƒ„D,cz … m †vF‡ˆ&‰F(‰&jŠ,cz 9‹gzŒ-gzEŽmŠ,cz #d +t+‘ 3’€?“”KmŠ,cz •–)* bea—˜h™”mmŠ,cz •šQj›F 52@?HmmDyœ\ = žh}Ÿ‹P=™?Hnk‚Lm  ¡oe¢6 J??HwM=£¤¥¦§KH??”…x¨oP©ª Q*mH??4 5©ŠL«C¬)mH?A­+®¯°Hm0 mH?@@±`I²"m4™h›—¬ ¤gz0³ nŠ?™€K%ul@:¬´´®b;3*&¤#""‹) ( ÕÕÕÒÒÒÝÝݹ¹¹¾¾¾ÞÞÞÔÔÔÖÖÖàààáááæææ“““‘‘‘›››ÅÅ҇‡•••˜˜˜uuu   ÈÈÈ»»»½½½ÂÂÂ………ƒƒƒ„„„ŽŽŽnnn®®®ÀÀÀ¥¥¥¡¡¡···äääåå壣£’’’¦¦¦ˆˆˆ–––”””ÃÃÃÁÁÁ¿¿¿ÉÉÉËËË———šššâââÍÍÍvvvlllmmmSSSòòòÄÄÄ™™™²²²¸¸¸ÓÓÓÊÊÊžžž§§§³³³µµµÜÜÜÚÚÚ‚‚‚ŠŠŠŸŸŸoooªªª¯¯¯ººº†††«««ßßߨ¨¨´´´œœœèè謬¬¼¼¼×××sss|||‹‹‹}}}ÙÙÙÛÛÛ°°°©©©ÎÎÎ~~~ÆÆÆÌÌÌÏÏÏ     !"#$%%%%%%&'()*+ ,-./'0(12345675589:;<=>,,?"!1@.+ABCDE$ FGHI$J#>.KLM< L@N#D#O-PJQGRS>TUV$W>2XYZ 3N[\=D:.D];,)V:0>]^EN#_A`<abcdM4?>e4](0`€€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ÷÷÷ÿ÷÷÷ÿwÿw÷÷ÿ÷÷÷÷÷÷÷÷øˆÿ÷÷÷÷wÿÿÿ÷÷ÿÿ÷ˆx÷w÷÷w÷÷www÷wwp‡ÿÿøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ€ÿÿÿÿ€wx‡wwxwxw‡wxwxwxwxÿ€ÿðpÿwpøpÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿøÿø€ÿ÷pˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆ€ÿøÿ÷p€ÿ€ÿðwÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿpÿð÷÷÷ÿ÷ÿÿÿÿÿÿÿ€ÿÿÿÿ÷÷w÷wÿˆˆwxÿÿ€÷÷÷÷÷ÿÿ÷ÿpˆ‡ÿ€€÷÷w÷wwøÿøwÿpw÷÷ÿÿÿ÷ÿÿÿÿÿÿðÿÿÿðøÿÿÿ÷ÿÿ÷ÿÿÿ€øˆÿ÷÷ø÷pÿxp÷÷ø÷÷wwxwwxwww‡wÿÿøÿ÷øÿ÷wÿw÷wwwÿ÷ÿˆ÷ø÷÷ÿpÿ÷ðÿ÷ø÷÷÷www÷w÷€ø÷÷ø÷ÿÿÿÿÿÿÿÿÿÿðÿwÿð÷øÿ÷÷÷w÷wÿ÷ˆˆ÷ÿÿ÷ÿ÷ø÷ÿÿpˆÿø÷÷÷÷÷÷÷pwø‡÷ˆˆÿ÷÷ø÷÷÷÷÷€ÿÿx÷ÿÿwøÿ÷w÷ÿ÷øÿ‡xÿ÷÷÷÷÷ø÷x÷÷pw€pÿˆ÷÷ÿ÷øÿp÷÷p÷ð÷pÿ÷ø÷÷÷p÷÷ppð÷w÷÷ø÷÷x÷÷p÷øpÿ÷ÿø÷÷ÿx÷÷wð€pÿÿ÷ø÷÷÷wÿ÷ÿø÷xwÿ÷ÿ÷÷÷÷ø÷÷ÿ€ÿ÷ð÷ÿÿøÿ÷÷pxxw€ÿ÷ÿx÷÷÷÷÷÷ˆÿwÿ÷ø‡w‡÷÷÷ww÷ÿÿ÷pÿÿ÷÷÷÷÷÷÷÷ÿ÷÷÷ÿˆÿÿÿÿp÷ÿÿ÷÷÷ÿð÷w÷÷÷÷ÿ÷ˆÿøÿpÿøÿ÷÷÷÷ÿw÷ÿ÷øÿ÷ÿ÷÷÷÷÷÷÷÷÷ÿ÷ðÿÿpÿ÷÷÷÷÷ÿ÷÷wÿw€ÿð÷÷÷÷ˆ÷÷ÿpÿp÷÷ÿ÷÷÷÷÷ÿpÿÿÿ÷÷÷÷÷÷ˆ‡xÿ€÷÷÷ÿ÷÷÷ÿxw÷ÿxwwÿ( @€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ÷÷wwÿw÷w÷wÿwwwww÷ww÷÷‡÷÷ÿw÷ww÷xÿ€ww÷÷ÿ÷÷ÿ€÷ø‡p€ˆ€÷€ÿxwxxw÷xwwwwÿˆÿ‡p€€€÷€ÿÿÿÿÿÿÿÿÿÿÿp÷‡øÿwww÷ww€ˆøw€÷wwwwww÷w€ˆ÷ÿÿÿÿÿðÿ÷ÿ÷wx€ˆˆ€ˆ÷€ˆ‡wwwˆxwww€ÿxp‡ÿwxˆ€€€ÿpˆÿ÷÷wwwwwwwpˆˆ‡w÷÷ÿx÷ÿø÷wwwwpˆw‡wwÿ÷ÿˆ÷÷ˆ÷÷wwwøð‡pp÷wwx÷ðxøˆ÷ÿÿwˆÿwøøðˆ÷wÿwxw÷xp‡ðx÷÷÷÷÷÷www€ÿpÿw÷w÷wÿpˆ€wˆ÷ˆ‡wwÿww€ˆwx÷x÷€w÷wÿ÷pÿ€÷wø‡ÿwww÷ÿwˆ÷‡ø÷wÿw÷wwxwÿ‡ÿ÷wwwÿ÷÷p÷÷€ÿwÿw÷wwxÿˆwø‡w÷÷÷www€wx‡ÿ€w÷w÷w÷÷÷wwwwwww÷( €€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ÷ww÷www÷÷øxxxxˆˆ‡w‡xˆˆˆˆ‡ww÷÷ÿxxˆwwwx‡x‡÷xˆˆˆxx‡wwwxxwwwwˆˆˆ‡w÷‡‡x÷wwww‡xww÷ˆˆøwˆww÷wwøxw‡÷÷÷÷wwxww÷wxxwwwÿwwwpuzzles-20170606.272beef/icons/blackbox.ico0000644000175000017500000006117613115373725017302 0ustar simonsimon 00 ¨%–  ¨>& hæ600¨N; ¨öIhžR00hX èn^(Va(0` $ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÒÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÜÜÜÇÇÇÁÁÁÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÀÀÀÀÀÀÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÀÀÀÀÀÀÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÝÝÝÖÖÖ××××××××××××××××××ÖÖÖÙÙÙÎÎÎÎÎÎÙÙÙÖÖÖ××××××××××××ÖÖÖÙÙÙÎÎÎÏÏÏØØØ××××××ÔÔÔÓÓÓÕÕÕ×××ØØØÐÐÐÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÝÝÝÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÖÖÖÍÍÍÍÍÍÖÖÖÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÖÖÖÌÌÌÍÍÍÖÖÖÔÔÔÖÖÖãããæææÝÝÝÓÓÓÖÖÖÏÏÏÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÝÝÝÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÍÍÍÍÍÍ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÌÌÌÍÍÍÖÖÖ×××ÌÌÌooo\\\›››ÝÝÝÔÔÔÏÏÏÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÝÝÝÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÍÍÍÍÍÍ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÌÌÌÍÍÍÖÖÖÔÔÔÚÚÚxxx***ÂÂÂ×××ÕÕÕÏÏÏÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÝÝÝÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÍÍÍÍÍÍ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÌÌÌÍÍÍ×××ÒÒÒäää®®®HHHåååÒÒÒÖÖÖÏÏÏÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÝÝÝÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÍÍÍÍÍÍ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÌÌÌÍÍÍÖÖÖÖÖÖÑÑÑHHH>>>ÞÞÞÓÓÓÖÖÖÏÏÏÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÜÜÜÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÍÍÍÍÍÍ×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÌÌÌÍÍÍÖÖÖÕÕÕÓÓÓ£££±±±×××ÔÔÔÖÖÖÏÏÏÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ×××ÕÕÕÞÞÞÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÖÖÖÌÌÌÌÌÌÖÖÖÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÖÖÖÌÌÌÍÍÍÖÖÖÔÔÔÕÕÕßßßÜÜÜÓÓÓÔÔÔÕÕÕÏÏÏÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÑÑÑÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÏÏÏØØØØØØÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÙÙÙÜÜÜÐÐÐÐÐÐÜÜÜÙÙÙÚÚÚÚÚÚÚÚÚÚÚÚÙÙÙÜÜÜÏÏÏÐÐÐÜÜÜÙÙÙÚÚÚØØØØØØÚÚÚÙÙÙÛÛÛÒÒÒÒÒÒÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÝÝÝÈÈÈÂÂÂÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÃÄÄĬ¬¬¡¡¡££££££££££££££££££¡¡¡­­­­­­¡¡¡££££££££££££££££££¡¡¡­­­¬¬¬¡¡¡£££££££££££££££¤¤¤¡¡¡¯¯¯ÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÜÜÜ×××××××××××××××××××××××××××ÖÖÖ^^^eeeddddddddddddeee]]]††††††]]]eeeddddddddddddeee]]]ˆˆˆ„„„]]]eeeddddddddddddeee]]]‡‡‡ÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÜÜÜÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÔÔÔ†††fffmmmkkkkkkkkkkkkmmmeee‹‹‹‹‹‹eeelllkkkkkkkkkkkkmmmeeeŒŒŒ‰‰‰eeelllkkkkkkkkkkkkmmmeeeŒŒŒÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÜÜÜÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔ………eeekkkjjjjjjjjjjjjkkkdddŠŠŠŠŠŠdddkkkjjjjjjjjjjjjkkkccc‹‹‹ˆˆˆdddkkkjjjjjjjjjjjjkkkddd‹‹‹ÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÜÜÜÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔ………eeekkkjjjjjjjjjjjjkkkdddŠŠŠŠŠŠdddkkkjjjjjjjjjjjjkkkccc‹‹‹ˆˆˆdddkkkjjjjjjjjjjjjkkkddd‹‹‹ÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÜÜÜÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔ………eeekkkjjjjjjjjjjjjkkkdddŠŠŠŠŠŠdddkkkjjjjjjjjjjjjkkkccc‹‹‹ˆˆˆdddkkkjjjjjjjjjjjjkkkddd‹‹‹ÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÜÜÜÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔ………eeekkkjjjjjjjjjjjjkkkdddŠŠŠŠŠŠdddkkkjjjjjjjjjjjjkkkccc‹‹‹ˆˆˆdddkkkjjjjjjjjjjjjkkkddd‹‹‹ÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÜÜÜÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔ†††eeellljjjjjjjjjjjjllldddŠŠŠŠŠŠdddllljjjjjjjjjjjjllldddŒŒŒˆˆˆdddkkkjjjjjjjjjjjjlllddd‹‹‹ÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÜÜÜÖÖÖÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÕÕÕÖÖÖÕÕÕ„„„bbbiiigggfffffffffhhhaaaˆˆˆˆˆˆaaahhhgggggggggggghhh```ŠŠŠ†††aaahhhggggggggggggiiiaaa‰‰‰ÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÝÝÝÓÓÓÑÑÑÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÒÑÑÑqqquuuxxx||||||yyyuuuooo‘‘‘‘‘‘pppvvvuuuuuuuuuuuuvvvppp’’’pppvvvuuuuuuuuuuuuvvvppp’’’ÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÝÝÝÎÎÎÇÇÇÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÈÈÈ¥¥¥———   wwwsss†††žžž™™™¦¦¦§§§———šššššššššššššššššš———§§§¦¦¦———šššššššššššššššššš———©©©×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÜÜÜÖÖÖÖÖÖÖÖÖÕÕÕÔÔÔÖÖÖÓÓÓÖÖÖÖÖÖÕÕÕ‚‚‚ccc555XXX‰‰‰†††___gggeeeeeeeeeeeeggg^^^‰‰‰………___gggeeeeeeeeeeeeggg___ˆˆˆÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÜÜÜÕÕÕÔÔÔÓÓÓÜÜÜÞÞÞÕÕÕâââÕÕÕÕÕÕÓÓÓŒŒŒ555ŠŠŠ‹‹‹dddlllkkkkkkkkkkkkllldddŒŒŒ‰‰‰eeelllkkkkkkkkkkkkllleeeŒŒŒÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÜÜÜÕÕÕÓÓÓßßßžžžÕÕÕpppÓÓÓÕÕÕÖÖÖ|||eeebbbkkkjjjjjjjjjjjjkkkccc‹‹‹ˆˆˆdddkkkjjjjjjjjjjjjkkkddd‹‹‹ÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÜÜÜÕÕÕÑÑÑåååuuuHHH®®®ÐÐÐÕÕÕÚÚÚeeeGGGbbbkkkjjjjjjjjjjjjkkkccc‹‹‹ˆˆˆdddkkkjjjjjjjjjjjjkkkddd‹‹‹ÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÜÜÜÕÕÕÒÒÒãããGGG$$$ÓÓÓÔÔÔÛÛÛaaaBBBbbbkkkjjjjjjjjjjjjkkkccc‹‹‹ˆˆˆdddkkkjjjjjjjjjjjjkkkddd‹‹‹ÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÜÜÜÕÕÕÑÑÑææætttYYYÏÏÏ###ÑÑÑÖÖÖ×××tttZZZ‘‘‘bbbkkkjjjjjjjjjjjjkkkccc‹‹‹ˆˆˆdddkkkjjjjjjjjjjjjkkkddd‹‹‹ÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÜÜÜÕÕÕÔÔÔØØØÃÃý½½ÑÑÑ´´´ÔÔÔÕÕÕÓÓÓŠŠŠ!!!ŒŒŒcccllljjjjjjjjjjjjllldddŒŒŒˆˆˆdddllljjjjjjjjjjjjlllddd‹‹‹ÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÜÜÜÖÖÖÖÖÖÕÕÕÚÚÚÛÛÛÖÖÖÝÝÝÖÖÖÖÖÖÔÔÔ………]]]HHH‡‡‡```hhhgggggggggggghhh```ŠŠŠ†††```hhhgggggggggggghhh```‰‰‰ÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÝÝÝÓÓÓÑÑÑÒÒÒÑÑÑÐÐÐÒÒÒÐÐÐÑÑÑÒÒÒÑÑÑtttyyyTTT666222GGGpppvvv’’’qqqxxxwwwwwwwwwwwwxxxqqq“““rrrxxxwwwwwwwwwwwwxxxqqq“““ÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÝÝÝÎÎÎÈÈÈÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÉÈÈÈ¥¥¥–––™™™ŸŸŸ         ›››•••¦¦¦¦¦¦–––™™™™™™™™™™™™™™™™™™–––§§§¥¥¥–––™™™™™™™™™™™™™™™ššš–––¨¨¨×××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÜÜÜÖÖÖÖÖÖ×××ÕÕÕÔÔÔÕÕÕÔÔÔÖÖÖÖÖÖÖÖÖ‚‚‚___fffccccccccccccfff^^^‡‡‡‡‡‡^^^fffeeeeeeeeeeeefff^^^ˆˆˆ………^^^fffeeeeeeeeeeeefff^^^ˆˆˆÛÛÛÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÜÜÜÕÕÕÔÔÔÓÓÓÜÜÜÜÜÜÙÙÙáááÓÓÓÕÕÕÔÔÔ†††ffflllkkkkkkkkkkkkllleeeŠŠŠŠŠŠeeelllkkkkkkkkkkkkllleeeŒŒŒ‰‰‰eeelllkkkkkkkkkkkkmmmeeeŒŒŒÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÜÜÜÕÕÕÓÓÓßßß™™™———»»»lllÛÛÛÔÔÔÔÔÔ………eeekkkjjjjjjjjjjjjkkkdddŠŠŠŠŠŠdddkkkjjjjjjjjjjjjkkkccc‹‹‹ˆˆˆdddkkkjjjjjjjjjjjjkkkddd‹‹‹ÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÜÜÜÕÕÕÑÑÑäääyyy...444ƒƒƒáááÓÓÓÔÔÔ………eeekkkjjjjjjjjjjjjkkkdddŠŠŠŠŠŠdddkkkjjjjjjjjjjjjkkkccc‹‹‹ˆˆˆdddkkkjjjjjjjjjjjjkkkddd‹‹‹ÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÜÜÜÕÕÕÒÒÒäääzzz@@@GGGáááÓÓÓÔÔÔ………eeekkkjjjjjjjjjjjjkkkdddŠŠŠŠŠŠdddkkkjjjjjjjjjjjjkkkccc‹‹‹ˆˆˆdddkkkjjjjjjjjjjjjkkkddd‹‹‹ÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÜÜÜÕÕÕÑÑÑäää{{{,,,444………âââÒÒÒÔÔÔ………eeekkkjjjjjjjjjjjjkkkdddŠŠŠŠŠŠdddkkkjjjjjjjjjjjjkkkccc‹‹‹ˆˆˆdddkkkjjjjjjjjjjjjkkkddd‹‹‹ÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÜÜÜÕÕÕÔÔÔ×××ÉÉɦ¦¦²²²ÙÙÙÔÔÔÕÕÕÔÔÔ†††eeellljjjjjjjjjjjjllldddŠŠŠŠŠŠdddllljjjjjjjjjjjjllldddŒŒŒˆˆˆdddllljjjjjjjjjjjjlllddd‹‹‹ÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÜÜÜÖÖÖÕÕÕÕÕÕÙÙÙàààÞÞÞÕÕÕÖÖÖÖÖÖÕÕÕ„„„ccciiihhhhhhhhhhhhiiibbb‰‰‰‰‰‰bbbiiihhhhhhhhhhhhiiiaaaŠŠŠ‡‡‡bbbiiihhhhhhhhhhhhjjjbbbŠŠŠÚÚÚÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÝÝÝÓÓÓÑÑÑÒÒÒÑÑÑÐÐÐÐÐÐÒÒÒÒÒÒÒÒÒÑÑÑŠŠŠlllrrrqqqqqqqqqqqqrrrkkkŽŽŽŽŽŽkkkrrrqqqqqqqqqqqqrrrkkkŒŒŒkkkrrrqqqqqqqqqqqqrrrkkkÙÙÙÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ×××ÒÒÒÏÏÏÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÍÍÍÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÍÍÍÍÍÍÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÎÎÎÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ( @ ÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖ×××ÖÖÖ×××ÖÖÖ×××ÖÖÖÖÖÖ×××ÖÖÖ×××ÖÖÖ×××ÖÖÖÖÖÖ×××ÖÖÖ×××ÖÖÖ×××ÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÑÑÑÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÐÐÐÏÏÏÏÏÏÏÏÏÏÏÏÏÏÏÐÐÐÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÏÏÏÉÉÉÊÊÊÊÊÊÊÊÊËËËÇÇÇÆÆÆËËËÊÊÊÊÊÊÊÊÊËËËÇÇÇÆÆÆËËËÊÊÊÈÈÈÉÉÉÊÊÊÈÈÈÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙØØØÖÖÖ×××××××××ØØØÒÒÒÏÏÏØØØ×××××××××ØØØÒÒÒÐÐÐØØØ×××àààÛÛÛ×××ÓÓÓÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙÖÖÖÔÔÔÕÕÕÕÕÕÔÔÔÖÖÖÐÐÐÎÎÎÖÖÖÔÔÔÕÕÕÔÔÔÖÖÖÐÐÐÍÍÍÙÙÙÊÊÊ[[[ÝÝÝÐÐÐÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙ×××ÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÑÑÑÎÎÎÖÖÖÕÕÕÕÕÕÕÕÕÖÖÖÐÐÐÎÎÎÔÔÔáááddd¦¦¦àààÐÐÐÓÓÓÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÙÙÙ×××ÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÐÐÐÎÎÎÖÖÖÕÕÕÕÕÕÕÕÕÖÖÖÐÐÐÍÍÍØØØËËËKKK···ÝÝÝÐÐÐÓÓÓÖÖÖÕÕÕÕÕÕÖÖÖ××××××××××××ÖÖÖÚÚÚÖÖÖÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÐÐÐÎÎÎÖÖÖÔÔÔÔÔÔÔÔÔÕÕÕÐÐÐÎÎÎÖÖÖÑÑÑÆÆÆÓÓÓÕÕÕÑÑÑÓÓÓÖÖÖÕÕÕÖÖÖÑÑÑÎÎÎÏÏÏÎÎÎÏÏÏÎÎÎÒÒÒ×××ØØØØØØØØØØØØÙÙÙÓÓÓÐÐÐÚÚÚØØØØØØØØØÙÙÙÓÓÓÐÐÐÙÙÙÙÙÙÜÜÜØØØÙÙÙÔÔÔÒÒÒÖÖÖÔÔÔÙÙÙÐÐÐÉÉÉËËËËËËËËËÊÊÊÍÍ͆††ŠŠŠ‰‰‰ŠŠŠ‡‡‡”””ššš†††ŠŠŠ‰‰‰ŠŠŠ‡‡‡•••™™™†††ŠŠŠ‰‰‰ŠŠŠ‡‡‡”””ÔÔÔÕÕÕÔÔÔØØØØØØÖÖÖ×××××××××ÖÖÖÚÚÚ†††^^^fffdddeee```vvv___eeedddeee```xxx€€€___eeedddeee```vvvÕÕÕÕÕÕÔÔÔÙÙÙ×××ÔÔÔÕÕÕÕÕÕÔÔÔÔÔÔØØØŠŠŠfffmmmkkklllggg|||†††ffflllkkklllggg~~~………ffflllkkklllggg|||ÕÕÕÕÕÕÔÔÔÙÙÙ×××ÔÔÔÕÕÕÕÕÕÕÕÕÔÔÔØØØ‰‰‰dddkkkjjjkkkfff{{{………eeekkkjjjkkkfff}}}„„„eeekkkjjjkkkfff{{{ÕÕÕÕÕÕÔÔÔÙÙÙ×××ÔÔÔÕÕÕÕÕÕÕÕÕÔÔÔØØØŠŠŠeeelllkkkkkkggg|||†††ffflllkkkkkkfff}}}„„„ffflllkkklllggg{{{ÕÕÕÕÕÕÔÔÔÙÙÙØØØÕÕÕÖÖÖÖÖÖÖÖÖÕÕÕÙÙÙ‡‡‡```fffeeeeeeaaaxxxƒƒƒaaagggfffgggbbbzzzaaagggfffgggbbbxxxÕÕÕÕÕÕÔÔÔÙÙÙÔÔÔÐÐÐÑÑÑÑÑÑÐÐÐÐÐÐÓÓÓ“““wwwƒƒƒ‚‚‚ƒƒƒ{{{‡‡‡‘‘‘www|||{{{|||xxxŠŠŠwww|||{{{|||xxx‰‰‰ÔÔÔÕÕÕÔÔÔÙÙÙÓÓÓÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÐÐЛ››‚‚‚\\\>>>IIIsss•••–––‚‚‚†††………†††‚‚‚’’’–––‚‚‚†††………†††ƒƒƒ‘‘‘ÔÔÔÕÕÕÔÔÔØØØØØØÕÕÕÛÛÛÙÙÙÜÜÜ×××ÙÙÙ‰‰‰bbb†††^^^fffeeefff```yyy€€€___fffeeefffaaawwwÕÕÕÕÕÕÔÔÔÙÙÙÕÕÕßßßššš£££ˆˆˆÂÂÂááánnn222‹‹‹eeelllkkklllggg~~~„„„ffflllkkklllggg|||ÕÕÕÕÕÕÔÔÔÙÙÙÔÔÔããã………???>>>ÁÁÁäää\\\!!!„„„eeekkkjjjkkkfff}}}„„„eeekkkjjjkkkfff{{{ÕÕÕÕÕÕÔÔÔÙÙÙÔÔÔááለˆoooÀÀÀáááooo333‹‹‹eeelllkkkkkkfff}}}„„„ffflllkkklllggg{{{ÕÕÕÕÕÕÔÔÔÙÙÙØØØÖÖÖÕÕÕØØØÖÖÖÕÕÕÙÙÙŠŠŠddd‡‡‡___gggffffffaaayyy```gggfffgggbbbxxxÕÕÕÕÕÕÔÔÔÙÙÙÔÔÔÏÏÏÑÑÑÐÐÐÐÐÐÐÐÐÒÒÒ–––zzzWWW999DDDmmmŽŽŽ‘‘‘yyy~~~}}}}}}yyy‹‹‹‘‘‘yyy~~~}}}}}}zzzŠŠŠÔÔÔÕÕÕÔÔÔÙÙÙÓÓÓÍÍÍÎÎÎÍÍÍÍÍÍÎÎÎÐÐЙ™™€€€‹‹‹‹‹‹ŒŒŒ„„„ŽŽŽ–––€€€„„„„„„„„„‘‘‘•••€€€„„„„„„„„„ÔÔÔÕÕÕÔÔÔØØØØØØÕÕÕÙÙÙßßßÚÚÚÕÕÕÚÚÚ†††^^^eeecccddd```www‚‚‚___fffeeefff```yyy€€€```fffeeefffaaawwwÕÕÕÕÕÕÔÔÔÙÙÙÕÕÕßßß~~~ÓÓÓØØØŠŠŠeeelllkkklllggg|||†††ffflllkkklllggg~~~„„„ffflllkkklllggg|||ÕÕÕÕÕÕÔÔÔÙÙÙÔÔÔâââ$$$pppàààÕÕÕ‰‰‰dddkkkjjjkkkfff{{{………eeekkkjjjkkkfff}}}„„„eeekkkjjjkkkfff{{{ÕÕÕÕÕÕÔÔÔÙÙÙÔÔÔßßßšššAAA„„„ÝÝÝÖÖÖŠŠŠeeelllkkklllggg|||†††ffflllkkklllggg}}}„„„ffflllkkklllggg|||ÕÕÕÕÕÕÔÔÔÙÙÙ×××ÕÕÕÖÖÖÏÏÏÚÚÚÕÕÕÙÙÙ‡‡‡```gggfffgggbbbxxxƒƒƒaaagggfffgggbbbzzzaaagggfffgggbbbxxxÕÕÕÕÕÕÔÔÔÙÙÙÕÕÕÑÑÑÒÒÒÓÓÓÑÑÑÑÑÑÔÔÔ”””vvv|||{{{{{{xxx‰‰‰‘‘‘www|||{{{|||xxxŠŠŠwww|||{{{|||xxx‰‰‰ÔÔÔÕÕÕÕÕÕÕÕÕÔÔÔÒÒÒÒÒÒÒÒÒÒÒÒÓÓÓÒÒÒÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕ(  ÕÕÕÕÕÕÕÕÕÕÕÕÔÔÔÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÒÒÒÑÑÑÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÐÐÐÑÑÑÎÎÎÎÎÎÑÑÑÐÐÐÍÍÍÏÏÏÎÎÎÏÏÏÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕ×××ÔÔÔÕÕÕÒÒÒÑÑÑÕÕÕÔÔÔÓÓÓÇÇdž††×××ÓÓÓÕÕÕÕÕÕÕÕÕÕÕÕÚÚÚÜÜÜÜÜÜØØØ×××ÝÝÝÛÛÛØØØÑÑÑ´´´ÞÞÞÓÓÓÖÖÖÐÐÐÍÍÍÐÐÐÃÃ쬬®®®°°°°°°­­­®®®±±±¯¯¯²²²±±±ÓÓÓ×××ÖÖÖÓÓÓÜÜÜ«««]]]cccnnnqqqaaadddxxxeee___rrrÑÑÑ××××××ÔÔÔÝÝÝ®®®bbbhhhrrrvvvgggiii|||kkkfffwwwÑÑÑ×××ÔÔÔÐÐÐØØØ°°°tttwwwrrrttt„„„uuuqqq€€€ÒÒÒ×××ÓÓÓÔÔÔÚÚÚ²²²<<<]]]†††ssswww†††xxxsss‚‚‚ÒÒÒÖÖÖÜÜÜxxxœœœ£££ssseeegggzzziiiddduuuÑÑÑÖÖÖÙÙÙ¢¢¢¹¹¹ªªª---yyygggjjj|||kkkfffxxxÑÑÑ×××ÑÑÑßßßààà³³³mmm[[[ˆˆˆzzz|||‹‹‹}}}zzz‡‡‡ÒÒÒÖÖÖÙÙÙ¨¨¨Â²²²gggqqqvvvwwwiiikkk}}}mmmhhhyyyÑÑÑÕÕÕßßßbbb¥¥¥¸¸¸]]]dddppptttdddfffzzzhhhcccuuuÑÑÑ×××ÕÕÕÎÎÎÙÙÙ²²²rrrwww€€€‚‚‚uuuxxx‡‡‡yyyuuuƒƒƒÒÒÒÕÕÕÔÔÔÕÕÕÔÔÔÓÓÓÑÑÑÑÑÑÒÒÒÒÒÒÑÑÑÑÑÑÒÒÒÑÑÑÑÑÑÒÒÒÕÕÕ(0` ÕÕÕÖÖÖÒÒÒÑÑÑÔÔÔÜÜÜÇÇÇÁÁÁÃÃÃÀÀÀÝÝÝ×××ÙÙÙÎÎÎÏÏÏØØØÓÓÓÐÐÐÍÍÍÌÌÌãããæææooo\\\›››ÚÚÚxxx***ÂÂÂäää®®®HHHååå>>>ÞÞÞ£££±±±ßßßÛÛÛÈÈÈÄÄĬ¬¬¡¡¡­­­¤¤¤¯¯¯^^^eeeddd]]]†††ˆˆˆ„„„‡‡‡fffmmmkkk‹‹‹lllŒŒŒ‰‰‰………jjjŠŠŠcccbbbiiiggghhhaaa```qqquuu|||yyy‘‘‘pppvvv’’’ÉÉÉ¥¥¥———   wwwsssžžž™™™¦¦¦§§§ššš©©©‚‚‚555XXX___âââGGG$$$BBBtttYYY###ZZZ½½½´´´!!!TTT666222“““rrr–––ŸŸŸ•••¨¨¨ááá»»»...444ƒƒƒzzz@@@{{{,,,²²²àààŽŽŽ                        !"  #$  "%     & '()*######*++*######*+)*#####,*- ./0111102332011110245201111026&378999980::0;999980<=0;999980<>09????91@@19????9A:419????91:>09????91@@19????9A:419????91:>09????91@@19????9A:419????91:>09????91@@19????9A:419????91:30;????;1@@1;????;1<419????;1:5BCD777EF44FEDDDDEG@3FEDDDDCF= HIJKKLJMMNOJJJJONPQNOJJJJONP  RRRRRRR'STUVWX3YZ[\T]]]]]]T\[T]]]]]]T^ _A`abcbde=3fD0000D/=>fD0000Df4"g<`bcahabi@:1;9999;1<=0;9999;0<%YVNKhbcbbbhb0VB9????9A:419????91: Jj0babbbbhbkVB9????9A:419????91:.lkm&FbhbbbbhbnVB9????9A:419????91:opq obabbbbhbrMB9????9A:419????91:st@ubhaaabv.2wbcbbxH6GEDDDDEG@3GEDDDDEG= HoLyz{kNOVPIWWWWI|V}WWWWI|  'RRRRRRR'S~ZUUU€[[~ZZZZZZ~\S~ZZZZZ]~  _f7AAAA7/66/700007/4>/700007/4& ‚37;9999;0@@0;9999;0<=0;999980<%ZTƒ;&>09????91@@19????9A:419????91:L„…†‚>09????91@@19????9A:419????91:‡ˆkV‚>09????91@@19????9A:419????91:‰Š…>g>09????91@@19????9A:419????91: R[‹ 30;????;1@@1;????;1<41;????;1: Œ"5ACEEEECB==BCEEEECF@6BCEEEE?B@ @;}IIII}99}IIII}9Q<9}IIII}9Q    ( @ÕÕÕÖÖÖ×××ÑÑÑÏÏÏÐÐÐÔÔÔÙÙÙÉÉÉÊÊÊËËËÇÇÇÆÆÆÈÈÈÓÓÓØØØÒÒÒàààÛÛÛÎÎÎÍÍÍ[[[ÝÝÝáááddd¦¦¦KKK···ÚÚÚÜÜ܆††ŠŠŠ‰‰‰‡‡‡”””ššš•••™™™^^^fffeee```vvv___xxx€€€mmmkkklllggg|||~~~………jjj{{{}}}„„„aaaƒƒƒbbbzzz“““www‚‚‚‘‘‘›››\\\>>>IIIsss–––’’’yyyßßߣ££ˆˆˆÂÂÂnnn222‹‹‹ããã???ÁÁÁäää!!!oooÀÀÀ333WWW999DDDŽŽŽŒŒŒcccâââ$$$pppAAA       !"!#$% !"!#&' !"!#$ ()*+,-.**+/0.**+,!)12345 )323467)32345"282)97*282):;*282)9!*32245 )322):;)32349#+)**?-<4)4>/@A=B=9#CA595/!A595/"DBEFGH&IB 7 BJIB 7 =C"KLMLL> ()*)+N0.)*)/I?bcd1eCN6::NXCN6::?!'0XXf;eI0;;;-C&0;;;-gO (*h+AB.)*)+N0+)*)/=<4)4>?-<4)4>/$,599/"CA595/!gA595/"( ÕÕÕÔÔÔÑÑÑÒÒÒÐÐÐÎÎÎÍÍÍÏÏÏ×××ÓÓÓÇÇdž††ÚÚÚÜÜÜØØØÝÝÝÛÛÛ´´´ÞÞÞÖÖÖÃÃ쬬®®®°°°­­­±±±¯¯¯²²²«««]]]cccnnnqqqaaadddxxxeee___rrrbbbhhhvvvgggiii|||kkkfffwwwttt„„„uuu€€€<<<sss‚‚‚œœœ£££zzzÙÙÙ¢¢¢¹¹¹ªªª---yyyjjjßßßààà³³³mmm[[[ˆˆˆ‹‹‹}}}‡‡‡¨¨¨ÂÂÂ¥¥¥¸¸¸pppƒƒƒ      !"#$%&'(&)*+,-./0/12&034 5  67 8/ #89 #:;<<=8$*>+"4?@ABC,MN>O?PQ* )/+-NJ(EG'RS"T0".>(4?&/594#OE4U (0`€€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ÷÷÷w÷÷÷÷÷÷÷÷÷÷÷÷ÿ÷÷÷÷÷÷÷÷÷÷÷ÿ÷ÿ÷÷ÿ÷÷wÿ÷÷÷÷÷÷÷÷÷÷÷ÿ÷ÿ÷÷w÷÷÷÷÷÷÷÷÷ÿww÷÷÷÷ÿ÷÷w÷÷÷€‡÷÷÷÷÷÷÷÷÷ÿÿ÷÷xÿÿ÷÷÷ÿÿwÿ÷÷÷÷ðw÷÷÷÷÷w÷÷÷÷÷÷p÷÷ÿw÷ÿÿ÷÷÷÷÷÷÷xÿ÷÷ÿ÷÷÷w÷÷÷ÿ÷÷÷÷÷÷ÿ÷ÿ÷÷÷ÿ÷ww÷÷÷÷ÿ÷÷ÿ÷ÿ÷ÿw÷ÿÿ÷÷wwwwwwwwwwwwwwwww÷÷÷ÿ÷wwwwwwwwwwwwwwwwwwÿ÷÷÷wwwwwwwwwwwwwwwww÷÷ÿwwwwwwwxwwwwwwwwwÿ÷÷÷÷wwwwwwwwwwwwwwwwwwÿ÷÷÷÷÷xwwwwwwwwwwwxwxww÷÷wwwxwwwwwwwwwwwwwÿ÷÷w÷wwwwwww‡wwwwwwwwww÷÷ÿwwwwwwwwwwwwwwww÷ÿwwwwwwwwwwwwwwwwwÿ÷÷÷÷÷÷wwwwwwwwwwwwwwwwww÷ÿ÷w÷w÷÷÷www÷wwwwÿ÷÷wxwwwwwwwwwwwww÷÷÷ÿ÷€ww‡wwwwwxwwÿww÷wwwwwwwwwww÷ðx÷wwwwwwwwww÷øˆ÷ðwwwwwwwwwwwwÿpˆðwwxwwwwwwww÷÷xw÷øwwwwwwww‡www÷www÷÷wwwwwwwwxww÷ÿÿÿw€wwwwwwwwww÷ÿ÷÷wx€ˆwwwwwwwwwwww÷÷÷÷wwwwwwwwwwwwwÿ÷÷ÿ÷wwwwww÷wwwwwwwwwwÿww÷wwwwwwwwxwwwwwww÷÷÷÷wwwwwwwwwwwwwwwwÿøwwwxwwwwwwwwwwwwww÷÷ð€wwwwwwwwwwwwwwwwwwø÷÷wwwwwwwwwwwwwwwwÿ÷px÷wwwxwwxww‡wwwxwxww÷÷wwwwwwwwwwwwwwwww÷÷÷ÿ÷÷wwwwwwwwwwwwwwww÷÷wwwwwwwwwwwwwwww÷ÿ÷÷÷wwwwwwwwwwwwwwww÷÷÷÷÷÷÷w÷÷÷÷wÿw÷÷w÷( @€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿ÷ww÷w÷÷w÷w÷÷÷wwwwwwwwwwwww÷ww÷wÿ÷www÷÷w÷÷w÷w÷ww÷÷xww÷÷÷ÿ÷ww÷pwÿwwwwww÷÷x÷w÷w÷÷ww÷x÷wwÿww÷w÷ww÷wwwwwwxw‡xx‡‡ww‡w÷÷ˆˆˆˆˆˆˆˆˆˆˆ‡ww÷xˆˆˆˆˆˆˆˆˆ‡ÿw÷wxˆˆ€ˆˆˆ€‡w÷ˆˆˆxˆˆˆˆˆ‡w÷÷xˆ€ˆˆˆˆ‡ÿwwxˆˆˆˆˆˆˆˆ€wwˆˆˆˆˆˆˆˆˆˆˆ‡÷÷wwxˆ‡ˆˆxˆˆˆˆ‡ww÷ÿxˆˆˆˆˆˆ‡÷÷ˆðˆ€ˆˆˆˆ‡÷xˆ€ˆˆˆˆˆ€‡wø‡pˆˆ€ˆ€ˆ‡÷÷xˆˆˆˆˆˆˆ‡÷÷x€ˆ€ˆˆˆˆˆwwwwxˆˆˆˆˆˆˆˆˆˆ‡÷wxˆ‡ˆˆˆˆˆˆ‡÷wwxˆˆ€ˆˆˆˆˆ‡wwˆwˆ€ˆˆˆ‡ˆˆ‡÷xˆˆˆˆˆˆˆ€ˆ‡w÷ˆwpˆˆˆˆ€ˆˆˆˆÿwxˆˆˆˆˆˆ€ˆ‡wxˆˆˆˆˆˆˆˆˆˆw÷wwww÷w÷w÷www( €€€€€€€€€€ÀÀÀ€€€ÿÿÿÿÿÿÿÿÿÿÿÿw÷www÷wwwwwwxÿw÷÷÷wwww‡wˆ‡‡w÷ˆˆˆˆˆ‡wÿpˆˆˆ‡÷wxˆˆˆˆ‡÷wpˆˆˆ‡‡€ˆˆˆ‡wpˆˆ‡wwxˆˆˆˆ‡÷wpˆˆ‡w‡xˆˆˆˆ÷wˆˆˆˆˆ‡www÷ww÷puzzles-20170606.272beef/icons/untangle-web.png0000644000175000017500000002650013115373724020106 0ustar simonsimon‰PNG  IHDR––³cæµgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEák Ö,DIDATxÚí}yxUÕ¹÷ÚÓ™çÌóxNÈDNf‚R>¬J‹¥©ujoo½~÷Þ>ßí­­J,”âE1Qð¢EB s˜ $ñäLûìq}¬Ë)—!fÞ õ÷OÎÞk­ß~ßõNë]XCCø“¸Ôø#)õ&DB(b†ã“æãþžÂ¿C¡B¡T(‚ ¸\. äÔwã{ ÿFyîÜÙsçÎëtÚôôlŠÒ²,a]¿§  õÁÛ §3€®éÓ·üÇü800še=\±ï-RQÕjMqñ¾çŸçØ@†<ß:~ÁÆ«YÇ0(õÂD×c !Ï‹ÅïÛw €Å$  ‡a–ââ˜Ë—e2…(ŠRs üãR!¢(½^/“Q6›Bà8¹R)W«Õ‰Ìâ?Ü^ˆø IR¥Rá8ÞÞÞ^]]sá­¶€oEñ'$)B({@ÀÁ={¦OÇ’’H’t¹\¢(N@gãˆBApW(r¹¼··÷Ì™3555N§3,,lÁ‚ÁÁ> ÅÖ;í΄ÐòÑÆ‹ärÃÁƒßÌÌÌÌÌÌÔh4n·›ã8‚ ¤žÍßñà›3HÊd2¥Réñx.\¸PYYÙÑÑa4SSSãããõz=M»wäÈ‘ÆÆ›µµå¿úÕêÄÄ,Žc ‚hii)))éééIMM6mš¯¯/MÓ Ãà8>ŒÕ–B¤0)ŠR*•€¶¶¶êêêsçÎaµZ“’’xž÷x<<ÏÚÿp¥Ràóî»›"#c³²Ò].†aJ¥’¢¨¶¶¶cÇŽ]¼xÑl6Ϙ1#44”aÇV»>h"æ‚P(Euww×ÕÕÕÕÕ¹Ý˜ÔÔÔÈÈHÇ=˲w‹Ï J¥²¢¢âüùs+V¬°Ùlˆ]Qår¹R©ìîî.//¯©© ˜9s¦ÅbºÝn¡TD>8"…)—Ë …Ûínmm=}útggg@@€ÕjW©Tƒ‘’$»ºº>ûì³5kÖð<ïåØ+Ö*•ÊétVUUUTTÈåò¼¼¼äädŠ¢¤²w&=…ˆ9daò<õêÕêêê .(•Ê”””¤¤$___Žã<(І}çî!¤(jóæÍ<òHxx8Ã0wüñ¤V«yž¯««+++s¹\™™™ÙÙÙZ­Öårq7žÛäd¥Bˆt—R©$¢»»»¦¦¦®®Žçy‹Å’––ŠaMÓC]PAŒFãöíÛCBBfÏžít:ï)Xèƒ@žÉ¹sçŽ?ÞÞÞž˜˜8cÆ ???ÇãñxƇÈIF!b€L ·ÛÝÐÐP[[ÛÝÝbµZãââär9Ã0 Ã#vw¿B©TVWWŸ9sæùçŸïïïÀ…@ãAŽÊµk×ÊÊÊZ[[ÃÂÂòóóÃÃÃ9Ž£iŒ±½3i(D[ò 8Ž»xñbmmíÅ‹ Crrrrr²^¯çyž¦iá0˜»Aô÷÷ôÑG/¾øâàdžìÞÞÞòòò³gÏj4šüüüøøx€Ëå;{gBPˆ €{,»7˜¢T*qïè設­mllÄÅÅ¥§§`æv»A!s·¿T.—oÙ²eîܹ±±±Ï ’H" ‚@€ÊÊÊÓ§OCsrrÒÓÓår¹ËåBÌ=§?ì‘KL!Ò‹2™ÃpŽcD‘÷~ªh³Q(2™¬¿¿¿¡¡¡¦¦Æn·‡……effFFFÊår+£­©ÐvXTT¤×ëçÍ›çp8†ô|¯½#B}}ý‰'‡ÕjÍÉÉÑëõn·Ûëψ¢ˆãE) „,KcØpˆ”’B!APr9ÞÙyãhŸ¹Üèr90 “Éd …‚eÙóçÏWWW·µµ™L&LÑéth«;Õ„¶·úúú“'O®Zµj¨" SY¥R‘$yáÂ…£Gvtt˜Íæ™3g1 ãv»Õj Ï;»º.‘¤Ìß?†ç1Žc‡Ê¢dBI’òxú >ݽÛàv«SR®¼újFnîŽc¯_¿Ž‚)8Ž'&&Z­Ö€€AP0e,=ÇišÞºuëªU«H’¼¥ê‡3M¤– Å7Ž;vþüù   ¼¼¼)SjkË~ÿû’S§"e2fÁ‚Η^Z¤× •EÉ(E R‘¿ýí¦¢¢ãø,„®  7þå_‚/_î¶ÛmÑÑÑééé$IÒ4}Ï`ÊØÙ¥ï¿ÿþôéÓ“’’Ün÷H^íµÅT*Uyyyuõ½ß¹S¸téß1Ì„a@«çÏßúÎ;k8nhIfibB¢(*•ªsçÎ~ùe³à!äHRÝÑñ³¢¢£³gç®^ýâ“O>êv»ív» AŒgL­x``à•+WnEP‡ ÂEìæÎ}èõ×ÿéÆ Ï¥K?¦(ާ}óMòÙ³§U*õÒ“’Åg ‚t:ûh:Ç(B(¡AAqùù3ÕjÃá@¾$±Gdž±X,W®\aôfM@ûûû´Zb ’¢ˆá8€0ÌfëªÞ–(2‹a,ˆµˆ" ǵÝÝgÿíßþóÈ‘Ãn·[£Ñèt:ÇEQç¼9†a,ˆ……¹Ýn$:£õd!†ŠREGë8Àq pžzý™ððÈ»CzƒX³fÍx.w8Žóó –É©„Њa2Q<>}úηÞZ§VÏŸ?wôèÑúúz»Ýn4 ƒ\.çy^Eä¹Ã EQÔh4MMM …âžÁÒa@’$õzý±cÇ««O’dÓÕ«z¢ dضvmÏüùóÝnzHŠGZ§ÈåTiiñ_þrÊfƒ?ñÔSiµ‘$ép8š››ÛÛÛýüü,Kbb¢ÉdÐ4Íó<VülHËm0¾úê+dzhÑ"»Ý>•ŽLS­VÛ××÷é§Ÿ9ö%KžÑëåEE{ [L&å³Ï&Íû0ÇA†¶ïJYxa€¦™ A(@È-\ø³7º†Æ0 ù|iii™™™ˆËæææ“'Oêtº„„„Û¹DQl0‚èÆý€ÒŠ‹eÿþýÇäù‚  Ð`iié¡C‡rrræÍ›Ç0 Ãp¯½¶N­~Çb±ÌœùpGGA` íE×Î`p¹½½¬^¯³Ù‚ð?e)h½\.ZJÄ¥Ífkjjjll,++3™L ñññ¾¾¾¢(z<žQOñ mÂ0Loo¯V«Æ~Œ„O¯×wvv~ðÁ‚ ¬Zµ*88¸¿¿Ã0…þ~Mc.—èp80 •? 9…Ç9ΣTúÝ^ò*.Ä%EQÙÙÙ9996›­¹¹¹¾¾¾¬¬Ì`0$%%M™2Å××W†aF‘K´úùù]¸p!''g¨aAär¹\.?|øpIIɬY³æÌ™ãñx¼ö:ƒãÇA SKKO!²ýärùv Z8¡ÓéP•••5mÚ´¾¾¾––”wõõõMNNŽõññáy~´¸$"44ôÊ•+¹¹¹ƒÿ>ƒÁÐÞÞ^TTDQÔºuëüüüìv;òGq%¦9@ Ã(ŠÁ8Cwp)“É233srrzzzÎ;wæÌ™ââb__ß©S§šÍæ‘s‰a˜Ç㉭¯¯¼E*ªÜÙ·o_yyùܹsgÍšåv»N=ÒK!€a$…ƒÿ‰—K”ŠS(ÙÙÙÝÝÝÍÍÍÕÕÕGŽ1™L)))‹Åd2y‹Õ†Ä%ÒAAA<Ïwww£ç ðs4£ÑxùòåÏ>ûL£Ñüò—¿4 6› Çñ1ª>r7°"ˆKQQ™J¥ÊÍÍ1cFgggKK âÒÇÇqi49Žcfð\¢ u``à¹sçfÏž4á=ÿR”ÔüòË/«ªª~øÃNŸ>Ýét:Ž1-–˜BÇQÂo$Ùä#Š¢èt:!„æv.«ªªŽ?n2™’““Íf³Á`@r‰‚g)†…‡‡_¾|ù~€R›F£ñüùó»ví2™L/¿ü²F£éëëÃq|¬„’;JAä¨-:©‹LÊÜÜܼ¼¼®®®¦¦¦òòòƒ ýÒ[®†»—m‡ÑÑÑ•••n·ûî?A¥RAwíÚUWW÷È#dee9§Ó9>uû…‘gîùp‚ xžG‘9F“——7cÆŒ›7o666ž43!¤pL)¼ý]ˆNžç@§ÓÍ™3'??¿«« qùí·ß†„„$$$X,•J…¸A&“›Í!{÷~©Ó !AA±†544ìÞ½;::úµ×^#Irœ…Ï é)DNÛX(Ò^êåÒn·´Zíœ9sfÏžÝÝÝ}æÌ™ÒÒÒýû÷‡‡‡'&&šÍf?¿€††ÊßÿþxeåÿÙ¶M¶ÿ7¿‰p»¹¦¦æE‹%&&Úív–e¥:±&½Eê•Bôñ|»—KA¼\>üðÃsæÌ¹yóæÙ³gKKK÷îÝ?eJDQÑ•ÊÊ7"B±­í‰µk_|ùeâ7¿ù­(rR ŸE I’•„ܰ‡^-Š"âÒh4Ο?Μ9‡«¨èýÊÊ ’ äyŒ¢pŽ{¢¾‘˱®.EI¼†ÒS8n{á áõIúûûEQô÷HMMÀÕë@@ÐݸÑ3¼²ÏѰ´¯GRHÄ„:úŒ€vh§ÓrZEQ$ p 77†aDÿǦYí ÃÈd² "‚wÃ0Çm6[—,¡X'Š—¡Â÷Ÿ{î¬Y³].×Dèž }Œ”eÙA¦)Æ¢(j4êææ‡Ãý駙ǎmu:Ù3¢fÏ~Že†ÁadhGÒS8Œ4ÅøBH’¤ÛMÿ×}øä“O¦¤¤åå18Ž1 t¹\„? 9…B–e•J%ŠK½wB¡Püñœ1cÆÔ©S»»;q‡â8ju9QF+½931¥P½^ÿÉ'Ÿøùùýð‡?ìëë£(’ p’”Ò¼'$ ’‰¶¢òÃC‡]¿~}Ù²ec”m-HÿA}gáÌ8å4š››‹‹‹W­Z…LdHO!R¤¤OjwÑßß¿}ûöŸÿüçf„¤ã€ ±N(EŠ:–Ì›7Ïl6OÏo`H¿ޤpftL˜íÛ·GFFæççîi˜±ƒ¤ÍÃ0l¬ó½ƒ:_¿wï^›ÍöÔSOMþ€ä2 ƒ¤ÒR(‚V«=sæLYYÙÊ•+iš–\% ’Qˆ¾xó½.*Cíéé)**zî¹çÐ)¸ï)ŽsÊþx÷à÷Þ{ïÑGŒŒ¼g™ÚD†´™ À0<ŽS†KåTˆ¢¨Õj·mÛ?}úô îÅßÒP!ÓëuáT(ÜF£Ž (Ç›EdÂüíoãyþ‰'ž@%’,ÈH I˜â8ãÂGm/,¼ÞÕå´Û·,_¾@­öã¸ñ«½A§Ó:uªººú׿þ5j,ÅjŒP(Š@­&ß|sÛ{ïMŰW1Œ((8~öìöM›^À0ã!‹¢(*•ÊŽŽŽÝ»w¯]»Ã0Ô|}üWcäïA£Ž3MM5}ä ÀÏpÀD^IÉÜýûk4*As Qi¯ [¶lY´hQPPê:ÎK1ZïqCe2ùõëm.WºšE ¤_¾l£(l›¼ 0µZ½eË–´´´ŒŒ »Ý>·@/ƽ‘4†ñ}êÔ©÷ë{?!Ù4Ð) Pðvp"‚a›Í´bÅŠ¥K—öõõmÚ´é‹/¾ðx<^"‡SE&Laa!:)ñ˜0·Câ/e ïàɲ¬Ífóõõ]¾|ùŠ+Ün÷æÍ›wîÜét: I’ƒ$Õ2_½zuâ×2 ä{oDºÛ¬@Dr×××§Óé–,Y²råJÀ–-[ m6›Á` (j`"EQT«Õ---ß~ûíªU«Ð)ß ÒÔ¾[ o‡÷¼¼ÍfS*•?ýéOûúúJJJ¶nÝ9kÖ¬ˆˆˆ;®fEB ¡(—ËœNçöíÛ—/_®Õj']"i0žÂÁ´‹õ6Fîïï§(jáÂ…sæÌ9vìØöíÛCCCgÍšͲ,ºRK¡P+B9Ïco¿ýÖC=7‰j)†©7’¤÷ººïÜØ¼Í úûûq_°`ÁìÙ³ËËË‹ŠŠ|||æÌ™ƒãD]]ù'ŸT¶µqÓ¦ùªTý11–ITË4œ5”ðÝ·ï…CZ_¤ Q×¹sçæåå:uê³Ï> ñ÷×¼þzW_ßZ:~¼ÁÇçw{öÌ£iæÁÓŸ_ ßíU¤#iÝe·Û9ŽËËËûÕ¯þÉlyã#}}od†•ÚÓó·n=$—cRÈ!$“Bo?—µ‘‡ƒ$Vk, B„<ÉÕÕ<„NdCm˜Àü‰ H‘S1¼p3º-M§ÓA÷îÝóñÇ_NŸ~ €¯DÇ0‚çY¾<Âq*›3ÖBA(ŠÒjµ6›í믿®®®ŽˆˆX¼ø)ŸØØm;vT÷öúM™Ò™’ÒÐÖFäkËÉ) :s¿Ÿ ;‘µZmOOÏêêꢢ¢ž{¦YVøå/W-^ÜêtöšLIÁÁ+ß~ûíO>ÙñÌ3K{{{H¿BâÏó;£3^@Ñ=F£ÑétîÚµë½÷Þóx<+W®\ºt©Éd²ÙlÇA(:nŸØèè\µ:°§§wõêÕííŸþ¹Éd‡ªŽñ‡ô‡ÓpÿÎnÉHm »Ý^XX¸eËáÊ•+Ÿ~úiN‡ÈC÷ra†ãÇyhÚ)†dz~ýú¦¦¦½{÷ÆEéÛ%$‰®~¹Û¨ñÞ‘«R©ÚÚÚ>|õêÕÄÄĵk×¢œíýz^ß~‰Œ(Š<Ïÿâ¿xóÍ7U*Õ¬Y³°HôMKPûžä) …BqåÊ•C‡utt¤¤¤<öØc(‰?ø†å†ñH)'é)ôJ!"O©TÊåò .wuu¥¦¦þô§?ÕjµN§H‡cYV¥R­[·îwÞQ*•¨åƒÁ¢ôz¥Ù5èÂúÖÖÖââb‡Ã‘––¶dÉ•Jå%oxÑNt“ÉdZ½zõ¦M›^xá…ˆˆˆqkŸ=¦žB’$9ŽC‡ü(Šjjj*..v»ÝÙÙÙÓ¦MS(N§E´GªÆqÜår?ûì³[¶lY¿~½¿¿¿Ûížì,JoÎ`FQ”F£©ªª:räÃ0¹¹¹™™™E9NÔ|}´ò A8N³Ù¼dÉ’?ÿùÏ/½ô’^¯ŸÔÕø@B Q¦W¥Réõúººº'NØíöüüüÔÔT‚ \.×í‰øQAv»=%%…¦é‚‚‚W_}U&“¡Eª¥!$9Ù$b¦Ñhxž¯¨¨8pà€Á`xæ™g¦L™‚ã8jM?¦—ga³Ùrrr<ÏÛo¿ýꫯ¢bªIZ<®"ò´Z-Çq'Ož,--õññ‰ÏÉÉÉÈȸyó&ҙ㰔Aôõõåçç»Ýî7¾üòËCŠóM(Œ…¨¨^§Óy<žcÇŽëëë£izîÆ¹ˆÅGy„¦éM›6mذÝà5éXó%CYt1ö¡C‡ÞyçÆÆÆ… ®_¿Þl6£;ëGëÔÄPADooï¢E‹|}}7oÞ¬Õj%o3 ŒáÂ!½¤Óé0 ;pàÀ;ï¼sñâÅ'žxâÅ_ŒŒŒìïïG Ú‡¤š?Ú—.]Jć~h0&H7¸ÁcL(DäéõzAöîÝ»qãÆöövTËj³ÙPÇ ¤²Pt¹ö’,†av»}åÊ•‡ã“O>™t¡ðaRoáŽÿD'Öõz=Çq_|ñEAAAooï²eËž}öÙÀÀ@›Í†nU¹}¿¹gŒt<^ít:׬YÓÖÖößÿýß“+-5sFE’”“¤LxŽ£½;Èd2•JÕÝݽoß¾æææ˜˜˜+V„„„¸Ýî¢ÒwÄH%Ò%4Ôjõ¼yó&Ëé™!S!Ôh´}}W{{;4c``¬ÓI“$¡ÕjoÞ¼ù·¿ý­µµuÊ”)/¼ðB`` ËåB×0°’K!º¾RoZ*//oR¤¥†F!Šd~ñÅ®‚‚ÎË—#}}–-;òâ‹?ïêêÛ½{÷… ’’’Ö¬Yãëë;òP†Ö»J½ÿÓ™Q&“­_¿¥¥ÒÒÒ&~ZjŠ¢¨VkÙ÷Ê+¢(þÃÄînüOÚ}þü?……ÆÅMY¿~½ÑhD™ØA^ƒÊg$W¤^ ´”F£Y·nÝÆ•Je\\Ü?’?$sÇ0÷ŽçEqIøqiiÀ²e?yôÑ…È@juýÈ«GyEpÜãñøúú®ZµjûöíW®\Ñh4Ùº…„Lw7€(òPò– …ÐC¤B¡ Ir0'•¼•‚îÑ_w¹\aaaË—/ß¼yóÍ›7U*Õ„áÿíPþXÄqmj*@A!ภW@@ÝŽ_lÛ¶µ¾¾uQ«ÕàV.bà'" Á-WRêÕø;‚p8S¦Lyúé§ß}÷]»Ý>qzÀß!Pˆa€eÁŠ?ˆ‰ù3Ç…P„›õëÿüÏË–½X^^¾iÓ¦?ü°ººZEN§Ñh¥7Àä' zÖßßoµZ{챂‚Žã(Šš€ã‚9ƒaÃÐÁÁ–íÛnß^ØÒ"¸Ý,ÑãÉ ðËÏÏŸ;wngggCCCeeå¡C‡‚ƒƒÍfsBB‚Á`€¢KqÁm÷=‚aU'P(<77×ívOØ´ÔМ Ç=·Ÿ_ô?ÿsŒN'ûôÓ/X;~¼4$$888Øétêtºüü|t)nsss}}}II‰¿¿BBB||¼Á`Ð4í5A'æ^ø¿ˆ$ûúúæÎ‹ÒR°ç±fÍš!ýÃ0AàišeY\`ssÓ¼yóvîÜ9cÆ ¤0†AwøÄÄĤ§§'%%‰¢ØØØXZZzîÜ9Ô¯Â`0Èår$”‡ãüùóV«Uꥸ/P"Újµ^¿~ýðáÃyyy¨íÂÈY„ªTªêêj“É1¼«p‡#Å0Œ$ Žó˜Í±½½½AAAf³y×®]z½¥Pk‡Ãáp8äry^^ÞóÏ?¿jÕª„„„ÖÖÖ>ø`Ë–-¥¥¥.—K§Ó¡TÏóƒ¬Ì—È_Z¼x±Ñh|ÿý÷ÑY*©uklC•B/ „æúõë7oÞ\¼xñ®]»t:]xx8ú”¼ ¹¤(*222===99™$ÉæææŠŠŠšš›ÍÖÕÕ5kÖ,táâŒÆ7>ºÀ0Œ¦éiÓ¦UUUÕÕÕåääŒü.„Q‘ÂáSnˆ¨¬¬œ6mZHHHQQQFF2ÛnÊí\2 C’dDDDFFFBB‚V«mnn.++ëèè iZ¥RùúúÞÎåD#’a˜œœœ£G^½z533s„]P$¦5C6™LAAAS¦Lq¹\%%%3fÌ@U÷ü "˲ˆË°°°ÄÄÄÎÎΜœœ‹/VVVž:uÊn·k4¹\@Í&—h ÇMŸ>}ïÞ½½½½©©©#aQz)DÊ/]ºäñxÂÂÂÌfóÉ“'NgBBÂýXô®Êïð<ïr¹êëëçÍ›—“““`2™.^¼XVVV]]m·Û•J¥ÉdBÁT¢q»O2þ@ÃE1''çóÏ?çy>11qØ,JO!ZM‚ *++³³³ÝnwRRRaaá”)St:ÝwúO^2jkkãââ=éééV«Õh4¶µµ•––VUUuuui4£Ñ¨V«QbYB.½½Ø³³³ år¹Ùlø“½F…ÂU°¡ë^¢¢¢X–moo7™LƒáñÇÿøã_yå•A>ÄÛ4¥,<*’‹‹KJJòx</^¬¯¯/**R(QQQIII¡¡¡J¥’¦i–e‘ <Î\¢«Šärù† Þzë-¥RiµZ¥JK´õ‰ liiùÁ~`³Ù²³³ëëëwïÞ½xñâïL|ßAL Ÿx<dò™ÍæÄÄDš¦/]ºÔÒÒ²{÷nÇ£¢¢RRRBCC ²’Ð~9n\â8Î0ŒN§[»vmAAB¡°X,’¤¥F¤HÁ-eˆãøéÓ§³²²X–å8Îjµ~ùå—&“)$$„eÙOð’$YYY™˜˜xG6Àë– ÑEÑßß?111++Ëßß¿«««¬¬¬ªªêÚµkEùøø xìxú$†±,k0,ËÖ­[-‹º…jO̵¿{QQQ4Mwtt p>ŽãK–,ÙµkMÓƒ‘ÂãàèÁ0ÌãñØívš¦###.\¸aÆG}T&“íÛ·¯  `çÎçÏŸ§(J§Ó)•J$Ùc퀣ãáááË–-Û¼ysOOºà}L_zçF(…à–.mmmåy>&&†ã8–eCCCGiii^^Þ[=ªä(//G>âÀ“¿].†A.MBBBFFFXXXOOOUUUyyùÕ«W1 óóóÓh4hE#¹D)âÐÐP£Ñøá‡fff*•ÊA–’Ho‘zW1TSS“••…jDišNNN.--å8...î~,¢½'Nœ@Fì ¿ß;¸äyÞh4&%%¥¥¥EEEõ÷÷WUU•––^»v àãã£ÕjQ…Îq‰ã8MÓ111r¹|ÇŽ999ƒLhHo‘z”a˜˜˜˜ƒvvvêt:ô z<žeË–mܸÑb± †®¦F½F‘Ë5¤9Ü+À0Ì××wÁ‚ÇݼyÝ ºÿþààत$‹Å‚\ÇÃóüèÚ±¨¶æÌ™(¡ñÊ+¯Œ[Zj¤ÜêÝÒÒ"ŠbLL ÚÒ‘p(Š={öÌœ9óžv R¤•••QQQ¨wxsöÊ¥—!µZ˜˜˜––†œ¶ÚÚÚÒÒÒK—.‰¢¨×ëF#únÐGe¡QB#99¹··wïÞ½yyyßWš(ŠUÍœ9s&##±…6‰¸¸¸ÆÆÆ«W¯¦¥¥ÝÅ@VUU………ùùù¼ÑË%*íåy^¥RÅÅÅedd˜Íf–eÏž=[VVÖÜÜ !4 ˆKÔØŒXÇ"ÓÒÒÚÚÚJJJòòò¾Ó Ÿ(¢Ïß`0”••ÅÇÇ#»±È0LJJÊîÝ»ýýý°¦¦&((( `t Joç’eYµZm6›333- „°¦¦æÄ‰ÍÍÍÇét:ôŽK´/fff666ž>}:77×ãñÜïiˆBRPMMMb±±q€ˆ g EpppQQQNNÎÝ?”Ëåµµµ~~~AAAcTìå”Jetttvv¶Åb!¯¯¯çy^§Ó™L&™L†tìðÂëÈÈÎÎ>yòdssó´iÓîDX"'$e S§†cT(tÇ"A ïë뫨¨˜>}úíóÊåòºº:£Ñ:€É3*¸KÇ£R©"""²²²âãã)Šª«««¨¨hhh@¥F£• KŽãrss‹‹‹ÛÛÛ322îÉâÄ¢@’d}}å›oÖüõ¯¶’’Š€{ttºöœ¦é©S§>|ëm2!”Éd Z­6,,làc”<„ã8š¦år¹—K™LÖÒÒRZZZ__¸ÔëõJ¥rH\¢E„ÜÜܯ¾úÊf³Y­Ö{š©·Õê¯^ÝÇó;1 ¿qƒ®©ù>(ÎË{Èår¢ ÎÒ¥Kß}÷]³ÙŒŽÛ{‡+áÉ”iEÑív‹¢(“ÉÒÓÓ³²²úûû[ZZN:e0"##SRRüüüËëMG0f´‰p÷‹_üâøƒJ¥š3gÎXœ–-)$p½þúá«WEJyŠ’³lrOÏîý(QH Çùúú’$¹ÿþ3f /)Ò––™L†îš*è Pp‡ÒÑáááiiiV«U¡P\¾|ùèÑ£uuu6›M¯×ëõzÑ8$‹¬<’$³²² •JeLLÌíQŽ $…8Np\ÿ•+Jô¢ÈAHñ<€o[›Nœ1 ¢ÊÚüüüÆÆÆ={ö,\¸°¯¯ïŽƒ¾’w÷º£oËÛ>%%%%--Íårµ´´´´´ìرƒ¢(‹Å’œœŒî cüïÙ[+ƒ³,+—Ëׯ_ÿöÛo«Tª¤¤¤Ñmÿ6:µEQÉôQQ46’¤0Œ' €™¬B¥N§ñ^Fáp8žyæ™êêê––ojyÙãJÔ à•K—Ëe·Û!„)))O=õÔš5kæÎk³Ù ß}÷Ý}ûöutt¨T*N‡¼©;ÂëÈ Óëõ«W¯.,,<þüèž³E ¡ Pè}|lû÷â¸l “‹¢C¯ÿóì)/?Ã0ttt4Jì¡{°vîÜ™››‹¶ŸK—.q?>>ÑÑÑ[·n7™LHp'ŠEŠaDZ±±qVkWgçNA(MI9øÆQ?ûÙó¡¡Á§N:|ø°L&‹ŒŒ¤(Ên·GFFvvvÖÔÔdggó<åÊ·Û˜˜81)¼}š·§0V«5%%%((èÚµk§Nêîî&Â××W¥R¡?F 8†aƒƒƒÿú׿Z­V­V‹ÕÕÕF£qØb £5C¡J¥E;ËÚe2=ŽkœNj ÛÜÜüÍ7ßp÷ÐCM:™-üãóóóóó°oß7ÝݽO>¹¨··›¢(©™Ú”Ñ!“É …Ëåº~ýz]]Ý¥K—Pê-)))22R¡P fYÖd2UVV~ùå—脆^oØ¶í£ØØ˜œœ,‡c8{ähú…†±,#$ž,Ë MަiÿœœµZ}ðàÁÓ§Oûøø„……ÅÄÄ|ôÑŽ¬¬ôë×ëÚÛ›³³§ ãù±õîGÞý’çyš¦F£1999===44´³³Éåµkׂ@µEn·;** ÇñO>ù$/o¦^O=º_§£’’’YVÆñ Ñ”€Ší‘b9uêÔ‘#GôzýÓO/©¯¯Þ¸ñãöö¹7nˆÓ¦u¾òÊ´©S§¹Ý“ø¢d$—8Ž#¹dæúõë---<χ……Y­Öððð={¾>räëÎÎðÔ*•øØcýë×/Òhüx~hžÕ8Qè*ãçyþèÑÒÚÚSÍÍ}‡­`:†í¯=<…ã<“Hï7Y/—(P×ÖÖÖÐÐÐÚÚ*Š¢¿`JJìÚµû¯\ùˆa@+y䣷ÞZò`HSMEú@¶Ã0Ç¥¦¦k4àw¿q|)†ñ ¥²Û}µÚCùù™4Íàøä¦Ð[ò#š²Á`ˆÏÊÊ @øË_>ª­]G’‰¢Èb˜ˆaáçÎ]™9³;<Ü̲C°k$ÐWhb.—Ûåê‡0 Š B@ô®AÜF9™€¸D>¾Ýnw¹\>>¾?þ£ÄÄ BP¢ˆá8Åð¾¾’¤†4Éîµçy. ,  II’\ÝÓ‰‰>÷ "& -H'ß6°ŽÔópäŽv„‘ iÌö\Ñ~_Ç'øíàW«_Çq`c¤A‘ú$¿¡®¨s>,ò±v޵û8QBƒ#òµ<$êœ0–^9—ÇM»ß #ý¼TM&ìœ)¬eÞUàÎqLGk0qç¸æ¼3qçDÈ3$Õ™ ç$È&c/I‘ÓZaòœ“J¨0™ÎI­¢™LçdE1¹ÎÉÇž`rS|¢`²SŠX3Û9„]“/’ª5v1ß9äèÇL¾sèÏ>…Ãù³³ó*„ÿÿ÷'‘&¥¤Ä#ÝGijj :qâÄ’%K+ƒ’¿ÙµµµN<¥FW9œy<ÒÝ„ ¡P©@i€±Y¬Ë"UžÒF"5?ÿ2ÒÝ„‰Dogg·iÓ&Å%Q"6wO"!+üEVÖÖÞCº›°Àd2›››‡,‰’ݸPØ Àd…EÌ::Z‘î¦úùþûïKJJ.]º¤§§7da”ÌlšykhhŠt7ÕÌo¿ý–””tæÌ™É“'+S%b‰K0˜r…EØÖÖ6HwS´µµEFFîÝ»wþüùJ>‚±)”.Á ß °Ø”/DFFþúë¯HwV ˆÅâØØXwwwåŸB‰ØD"‘DrÆãýåé-Àãý׬qÿî»ïÜÝÝ÷îÝ|÷î]¤»¬t:½»»;&&fXOéFEE!Ýsõà꺜Ïç½zEíë3`2xš0˜b<>L¶MLŒÅb±vvvAAAX,öôéÓl6ÛÔÔtÆŒHw|Ø”••Ÿ;wn¸–ôœ Aðx<èl¼­­…@˜¸dÉ’ÐÐ{{û~ÅÄbñ;w †X,÷ññÁ`0H÷])ÂÂÂX,–µµõpŸE›ØRÖ¯_Ÿ’’2wî\e$Iuuuvv¶H$Ú±cǪU«Fùùùû÷ï7oÞ¼oß>‰4‚ÇQò7{ zzzÝÝÝŠË`077·K—.%$$\¿~L& ùRôööîÝ»wõêÕ#S|äbK!‰,‹F£ÕÔÔøùù‰D"¤GÐF "##G\šÅîééÖ#D"‘Édž={¶®®ÎÇLJÁ`‚aÕ¥¥¥?ýôFÓѹdh{d ² Ng±X|>ßÏÏÁ`´µµ!;–úúú“'Ofdd©RVlùÌž=›F£}ýõ×mmmd2™F£µ´´ 2–––˜˜˜”””Y³f©X•VlEXXXP©Ô+W®Ö­[G£Ñš››U¬sXtuuíÚµ+00ÐÕÕUõÚ´bÍÔ©S©Têõë×ׯ_O¥R_½z¥™Q;vÌÜÜ|çÎj©M+¶²˜ššFEEݸqÃÂÂ"00pÿþý/^¼€u………>¤Ñhê:ðÑŠ=}:ÒCggçÄÄĈˆˆ—/_ެíßìÿÂçó‹ŠŠÊÊÊüüü®]»6qâD¤GÐ//¯öööˆˆˆÂÂB%ó•Ê¢ž?Îb±~øá‡Í›7³Ùlccc¤û>(Ÿ}öYKKKxxøùóçÇ?¬g?v±!ßüqÓ¦Meee0ÙÕKXX˜@ ˆˆˆÈÏÏÖ)šÿf+öLª¯¯ŒŒ ³²²ª¨¨ˆŠŠJCìÛ·ÏÆÆ&::º««Kù§Ð,ö`3›ÇãEFF~ñÅNNN•••¡¡¡[ÁƒÁ$$$˜šš8p@ùðÁKl·sçN*•êîî^^^‡€fÐÑÑIKKëíí‹ÅJ=‚tŸaD*¶D"ár¹GŽY»v-›ÍÞ¸qã(OSª ãÆ;uêTSSFSª<Ò†ÈêÅår™Lfooï¶mÛV¯^­^wÄÁáp cçÎÙÙÙŠ £Vl±XÜÔÔÄf³---###]]]ÇJ’éábddC ¶nݪ $ ņŒÍ999]]]ÎÎÎéééH÷vLMM!c(@Pp‘ªÄ–56§¦¦Þ½{w…À„¹¹9d 522òöö–[%bCÆæ‚‚›ŒŒŒyóæx<^{{;Ò]ÓŸ~úivvvXX˜¡¡¡³³óÀc^쎎ŽK—.?~þüù™™™¶¶¶Ò¯FCœ€†™3gNFFÆž={˜Læ@÷Š1¼5…ŒÍ$éùóç………L&SViðQŠ X´hQrrrddä¿ÿýï~_É™ÝÚÚZ\\\\\ìââòÕW_YZZÊ-6:C´5€››ÛÁƒÃÃÃ/\¸ ›#qŒ‰ýæÍ›óçÏ—––’H¤’’ʼn…FgÔ®fXµj•@  +,,œ4iôᘻ©©©°°26߸qC:|œË¸”-[¶üý÷ß1ô“O>cBìׯ_³X¬ÊÊÊ 6”••AýV†\l@DDD{{û?ÿùϼ¼<ƒQ½Akll¤R©AAA“&Mª¨¨Ø¿¿òJ­ØbbbfÏž½{÷îîîîQ*vCCÃþýû)Š••UeeåÈŒÍZ±Ác¨±±ñFرy×®]ööö*›µbCèêꦧ§wuu¢¿Ù<Éd¾~ý:88øôéÓª'kÕŠ-‹Åž9sfTˆ åðíèèØ¹s§/Äü˜_½‚ÃáŠlf2™===*°ËE;³ûŒØb±øÖ­[™™™úúúaaa0Ýh¬»j[n¶ôÙu¡ösçΙ˜˜ÄÄĨ7€½Z±û¡±Ë–þóÏñ$’sr2Zœ!Ÿ‚¬¬¬‰'&$$8::Â=6­ØýPƒØÒlé2™•-$’ðÎÎ-Ž?´C‡b¾ýö[ÈØ|üøñ hflZ±û¡ªØµµµNMgç¯r³¥wv^½ys.—ËY°`ÆØ¥@+J__ IÕ‚ªb³X—E"ª‚lé==ñÖÖß0™gôö¥BÕ4ïžDBVX„üäÉc¤†§]ÉeQUld³¥‰VlYT[™léx¼ RÃÓŠ-‹ªb‰K0˜r…EØ"‘(88¸¨¨è?þÐðð´bË¢ªØJ—*/{6„O;wî…ByüøñÚµkƒƒƒY,Öëׯ53<­Ø²¨º'‰$’3‡ãßÙyu@v|çO&»@ç'nnnÝÝݵµµ\.700ÐÄÄÄ××wÕªUŸ~ú)|ÃÓÚBdQCîÒ'h?ÈfK lܸ£ffååÿøæÓ××wÿþýŠŠ ‡óÉ'Ÿøúú’Éä™3gª}xÁÁÁ111ðåæ[èFEE©X…ŽŽŽ‡ÇŠÅ‹m[[ÿÕÚz¤·÷0ð•XÌa0ŽÕÖþd```cc3ð‘)S¦¸¸¸lݺuîܹ?¦ÓéW¯^mmm0a‚©©Ú®¿¹y󦽽½z¯»À••844tË–-3gÎܾ}ûÅ‹‡\«Åbq}}=—Ë­¬¬”H$nnn¾¾¾ªßRäââÓÏ7¶PÃÌ–Kggç?ü°iÓ&,Ë`0Ö­[§80ƒÁL™2ÅÉÉ)88ØÉɉÏççää\¸pÏçš››ÌZYY9{ölDÒŽBàòAóöö®®®îêê ž0aBNNŽòÏZYYEEE±Ùl&“illœàííM£Ñx<Þpoœ×îÆeKì &Ì™3çîÝ» &%%¥¤¤¤¾¾~¸•@ªß¼y3;;ÛØØ8))ÉÓÓ“F£ÕÔÔ(™5F+¶,0z—z{{WVVLMM“““cccG@ ©~ýúõÂÂB ƒáêêJ¥R¹\noo¯‚GÃ-Ú£xÅ®ªª‚^s]\\–/_žšªê]t!!!/^¼|ù²­­m^^žTu¹ïÓÚ™- Œb›™™Íœ9ó矆þûøñc6›­Z­ÿÇ´iÓ Õ¿ýöÛ~ªËª«[¸vã ¶¶ÖÝÝ0nܸ… ÆÆÆ’H$5æ422Z¸p¡¿¿ÿªU«º»»ËÊÊŽ;VWW×ÛÛkiiùàÁ ³x1\W™Ž-à½ý§©©ióæÍÕÕÕÒC4‹U]]]PPŸCÁ_ýuçÎŠŠŠÚÚÚ‰'B—yÂ7̱¼á?Ó¦M›:uê½{ÿ½ê}ÇŽX,6??¾FMLLÖ®]Ëd2+++mllž?îááYZZúQ¥X¼Ë8àï¿ÿ~ðàÁŠ+ b0˜eË–ÅÇÇ;88(¥W÷ǘššž={VWW·¢¢"--­®®N(N™2ÇÃÚú(öÀ>‰tëÖ-Ù×b33³„„„/¾ø¢££îÖ¡ š±±14׫««7mÚÄãñÈd2db÷îÜ}=À.¶……Å„ ú¨xyy-^¼øÄ‰p·Þo7ŽÃáÜÜÜh4—Ë…Lì~~~ê---pwq4²ëããsëÖ­~:tè—_~©¨¨€µéÁ^½¤ªWWWCª¯Y³R½¹¹yøíŒ 4!¶¯¯/dË’ýÇ?~<%%åíÛ·ð5=ä{¶¾¾¾Tõ¨¨(>Ÿ¿aÆ5kÖ0ŒW¯^iàÇÑ$š{æÌ™áÁƒý>·³³ :|øðpÍÊ£ü¡Šžžž““t,“””ÔÖÖ©þÛo¿iàWÒʼ w%„‡‡÷ôôÁÔîÜ’tuu‰D"•J­ªª‚Tß±c¤ú‹/4ósÁ„æÄ¸’ƒéðY,ÖÓ§OáhW•ãR©êßÿ=¤:…BY³f NçñxšùÝÔ‹†Ä¶¶¶ÖÓÓ{üXNhˆ¹¹ù<(‰ÔÞ®ZÎÆutt¤ªÓét}}ýøøx__ß‘™ØDs t¼¼¼ä®ä€Õ«WÛØØÐétµ7ªvCˆÔ±‚Á`@Ž>>>cEu͉-5oËåðáÃ\.·ººZ½Âgõ’:VdeeAŽ^^^Ãr¬Ð<šÛÎή¯¯¯±±Qî·FFFiii‰‰‰þù§Õ€‰SêX‘““3yòdƒáææ¦Œc…æ×êÕ“'Oâp¸èèèÁ dddÈ’»wïæóùCþWÌ(ŸÙèN£.Ç Þôuuu=<d󔨨Ø<~üøôéÓ%%%oÞ¼Ñ×ן2eŠü§ê®ò+9ÀÔÔôèÑ£T*µ­­m¸ •ÝøÈ:Vܾ}›F£éëë:th0Ç ÄÄvrrjllT> ÞòåËÝÝÝ“’’†Ûžž^WWRÃÔ:::vvvQQQåååƒ9V ³ŒtuuŸ={&‰ »®•ÁÑÑ1//@ ËFRQQamm GÞ­Q‹©©éÒ¥Kù|~^^‹Åúý÷ß‘<1öööV~%èëëŸ8qâøñãMMMÊ?…¦ Úp+nܸ9V iQ'÷î58:º …)¸V¤_ïCCCccc/\¸ dÐïÇ,¶++++++dfv___||Jtô‘ÞÞ´öö{bq‡@pïÎ5ááñññ)Š}¸¶nÝJ rss•l룽E{ Ȉ-s­ÈçLûáZ‘_9œ–ÄDš‚g1Ì‘#GŠ‹‹•´R£{7>,ûõ"W»V„ÃùQ±þäÉ“bcc• úÕ.ãR{ÈkED"j~þeÅ•xzz:::¦¥¥ ÙœVl)ˆ=äµ"ÉÊÚÚ{CÖWWWW^®8µ½Vìÿ‚€ØêºV úMMMU|Æ®[ b+s­ˆ¡¡R~9¶¶¶!!!qqq 6ðZ±¥ ¶2׊ØÛ+›|šB¡èèè\¸pa°ÚݸÄòZ]Ý#ýüÍ7ß(4ýž?þáÇr hg¶Df6‘DrÆãýåé-Àãý?ûÌóÌ™37nÜð÷÷W&銙™ÙáÇ©TªÜ _­ØR9TIN¦’H“ðøyLÿ €ÿ`0Ùxü<2Ù,11vÑ¢E………qqq999AAA²ióäâíí=oÞ<¹é—´bKѴ߸,<ïÕÛï ':88„†ô»¼ºVN§OŸ>ýàÁƒsæÌ¬6¡P¸aƃB©R¥TUU•””dff"5ÌÑ’†"‘8ä- :::¾¾¾×®]ûüóωDâ¾}û¦OŸ>°¤ÁñãÇ£££çÍ›7iÒ$éçÚ™-etÅ ‹Ý¸qcyy¹Ý–-[’’’ä†qÏ›7oãÆ_~ù¥¬‡†Vl)cCl<zóæM(Š‚N§ ý·xB¡ð«¯¾’~¢½L@ÊXbüøñû÷ï/))ikk#“É,KÖëHWW7===''GšâA;³¥ ¹AS/^dffÞ¿?""Âßß_êÎpíÚµ‚‚‚¸¸¸¢¢Ý»÷sGG«‘ÑDeœ#ÐÍØâÁƒ§NjiiÙµk—ƒéëë#“ýß¾öõ%~¸1²ƒaãp©$’sr2¾Ôö£4ˆ QSSC§Óuuu÷íÛwãÆ­òò?E¢&sïO"MJI‰Gº¿€±‰¤²²òøñã--˜¾¾ÆALæ<~þ¹s)áz>ö6h À`0¾¾¾³gÛ÷õ%ªèJP%6D}=?”tŽ@([]Îè…b«Ñ9e Pì!#0˜r‡ñZ7Š=¤sG @º›€B±‡tŽ “]úR?P(6PÂ9é"ªUú¡ŒsÄGšÅÖÒt.ãZäò¿Ô[Ñ×ç•O%tEXtdate:create2017-06-06T01:31:16+01:00m…%tEXtdate:modify2017-06-06T01:31:16+01:00À=¿IEND®B`‚puzzles-20170606.272beef/icons/untangle-base.png0000644000175000017500000003364013115373724020246 0ustar simonsimon‰PNG  IHDR@@Bò2ýbKGDÿÿÿ ½§“ IDATxœíÝi@×Úð k¦à*¨µîh«Q h• `0XE ˆà†ŠŠ7Z"  TPŠÈj‚Ø*¶•¸¯µ.UªˆZ%@Â’äý0÷æõ²„&™dæü¾U&3f;ç9„{÷îAh'´ @y À Å@€@‹€- Z ´0h1`Ðbzh¨UUU‡s’Ï¿ÞÐðÁØØ‚LžL§/&“Éh×(‰†Râ„X,f2Y\îU‘h›T:‚¬ ¨†@(%w»ºNeèêê¢]#Ðm ÀxÇå¾ OCÉÿþD@"y¹ºö‹‹‹D§2 À=0.TUUq¹•¥‚ S¡ð4—{•Ïç£PÐ3 À¸Àᜉ¥f*1Ž?©Öš$€ãŸ]*¥ÉÙ@*SUu]mõHÆ…ÆÆÔ_î&– ÔT €`\022‡ ¹›¼16¶PS5r@€1®®®.77—@Ѓ R¹–d-‹ÕT€`ljnn.//߸q£‹‹Kee%¾˜DbA “Í»tuEsæÌáp8Ag›ŒÄš'Ožž9sfðàÁžžž;wî466† èÙ³×\®—Px‚Lÿ÷É‹F£ìرíþýû™™™T*ÕÝÝ}ÅŠVVV¨üÅñöí[—ŸŸ_WWG£Ñ.\hmmýùÿ‰u峑Xo„R"‘E£Mg2#d#±ª««Ož<™ŸŸ?eÊ”•+WŽ7¿ `íÖÔÔT^^^PPpëÖ­3fxxxØÛÛ„ζçóùÿ ý^_߬OŸ>{öDOœ8±ý–õõõùùùiii¤Ó鎎Žrv  X[Ý»w/77—ËåŽ7ÎÝÝJ¥‰ÄníáÁƒáááÅÅÅr¶iii)--MKK#>>>†††=+@°–yóæMIIInn®§§§§§gß¾}•Û•D"qttüùçŸ---»Ü˜Ï秦¦Þ»woáÂ…¾¾¾½zõRî ²@€µC}}ý… ŠŠŠpàÀž×ô°F“H$7oÞ,,,,++›0a‚§§ç¬Y³ôô{w““sçÎ]»vuëSïÞ½;yòdvvöW_}µjÕª¯¿þ©z€îÖPOŸ>={öì™3gH$’§§çwß}gaüH©çÏŸ\¸pA‰Ï644œ>}:##ÃÒÒÒÏÏÏÙÙÌ(V?`ÍRWWÇãñ þùç//¯Q£F©ôˆ...©©©C† Qîã‰äòåËÇŽû÷ß}||¼½½»û, è ` ‹ÿý÷ÜÜÜ+W®L›6ÍÃÃcúôéê9¡mÛ¶í믿^´hQ÷Ãçó³²²ªªª.\èããcnnŽHy€| À(ƒNåçç0ÀÛÛ›F£Á§Ô¦°°°¼¼{ölJJŠ‘‘ÑÒ¥KçÎ žr!XMîÝ»WXXXZZ:dÈOOϹsç’H$´‹ú¸¸8kkkUì~Ê•ššZ[[ëëë»`ÁÍù‹c°jÕÔÔçååéê꺺ºÎ›7oРAhÕÖùóçóòòŽ9¢Ò£Ü»w/++«¢¢ÂÝÝ}åÊ•Š ÿº¬"‘¨¢¢"77÷þýû³gÏFjà”Š—_ýÁ!"yõêUfffaa!…BY¹råˆ#T}DlF’là<ÇÀÛÛ{æÌ™úúúh×Õ5ooïmÛ¶u8-IÁ™3gÀT§žFƳgÏJKK U7pJu8`dd´zõjužêtüøq==½eË–¹¹¹©ác@€{D Àoƒª««gÏž=oÞ¼1cÆ ]”2®\¹’’’’žž®þCK¥Òk×®effÞ¿ßÛÛÛÏÏÏÌÌLýeh)`eÀ§à!ê8¥""‘hÆŒ(>"~øðá?þX^^îáááïï?`À´*Ñ" ÀÝ#ë8eeeåîîîîîÞ»wo´‹BÆòåËW­Z5uêTt˨­­=uêTNNΔ)SV¬X1~üxtëÑp À ùôéSYYÙ©S§Þ¿?wîÜùóç+=ú_c±Ùl‘H´qãF´  ÿNuJOO0`xÊ%°<ÍÍÍW¯^-,,„çx{{kÂÀ)áóùñññ§NB»ÿ×ÚÚzáÂ…´´´ººº%K–€©Níá"ÀJ¬jÝfà”›››‘‘‘Ú F…X,ž6mÇÓÀv9pCŸ»wï.Z´héÒ¥Þ¶àsírŒ¸»«ZçNŸ>M æÌ™ãééÙ¦9+¶/X°ÀÙÙíB:öüùóììì’’ggçå˗˦:áyírŒXÁU­áSð¸ãÔĉ±z©,GZZZuuud¤F¯ôýþýûœœ¸¡OPPЄ ð¼v9–\UUµjU´Px§“uq$ÒøÍ›—=|ø°'ÍY±D‘F³¢±±±¤¤$==@ TW·67ß—ó-;‡Õki,¯ÔåªÖBáÖŽÚØØ”””¤¦¦zzzâ9½5êÓ§O55ò×1ÔFFFÞÞÞEEEÆÆ–ÍÍÛq»v9–ÜåªÖDÓÓÓ èÓ§šjÒl:::“'Oþí·ßÐ.DQ:::/^<ƒ 79Û`{ír,¬j­;;;- 0„ûoËVdUk##mšr ööö×®]C»ŠnÀùÚåX0™<…@8+w“ÒÆFaHHHAAACCƒšÊÒlC‡ÕÑÑyñâÚ…(ªËo™@8;iÒdµÕ£fX0¾˜HÜ-gUk)þÈ‘}T*•ÇãÍœ9Nrcc£Z«Ôwîœd'''8ÉB¡…¢5€½½½VÜ·¶¶r8œýû÷ýõò¿eµ5*P?ÝÐÐP´kP!GÇi¯^ñ_¼`ˆÅFÔ‚HTM d“H>4ÚX&3BÖKÕÐÐpôèÑnnn .ÔÓÓãñx,ëÆ­­­C‡ÅÕDsssó¬X±B“‡²uêÔççäÊÊJ‰D¢ê£#hÒ¤I÷ïßGe4 Çsww744ÌÏÏŸ2eŠú Ð"Z·¦8¥ŸB+gàÀð}ruuõÅ‹“’’¶oßîââB¥Rµ¢Ý‘H3fÌ7ÔÙhöÝ»w;wî|ñâERRÒ¸qãÔv\í…£3°J/¡å4h|NÎÈȰ¶¶NHHpvvf±X|>_*•ª¿ÅÙÙÙ©ó6˜Çãyyy 2äÔ©S ½ ÂÑX=—ÐrX[[Ãçä¿þú‹ËåÆÄÄ4448;;kì9ÙÞÞ>>>^ ª®®Ž‰‰yÿþ}rròرcÕpDÌÀÑXO¡•óå—_†††=zÔÌÌ,::ÚÅÅEÏÉ_ýõßÿýéÓ'ÕB*•æææ.^¼ØÞÞ~þ§ºca8£iøðáÇ }òä Ç‹ŽŽnjjš9s&•JÕ„&lººº&Løã?T4vâåË—ÑÑÑÍÍͲ±@·à%ÀR©´±±QcßF´IrTTTKK‹““êI†oƒ°D"ÉËË;tè¿¿ÿŠ+0<[HÕðদ&}}}ÍoðÝ&É‘‘‘b±˜B¡xxxØÚÚª¿{{ûððpd÷ùçŸFEEfeeao‰)5ÃK€Ñz­´6IÞ¼y³¾¾>•J3gΰaÃÔV†¬Ñ¬¥¥eÏ÷&‹ÓÓÓÓÓÓ×­[·`Á |n§uð` ¼VP›$¯^½ÚÐÐJ¥Òh45Ü7ÊÍzxxôpW=ŠŒŒìÛ·onn®••"å8 °†<‚Vš,ÉðÂk&&&jH2Üh¶'njjJMMÍÉÉY·n··7‚µ8 °–žÛ³µµµµµˆˆ¸yó&Ç[¹r¥©©)•Juss:t(⇳··OIIQúã7oÞŒŠŠ1bDAA…fÛ»¢GÖØGÐÊÑÑÑ!“Éd2Y–d333*•êîî>xð`¤$k4ÛÝNp¢¢mÛ¶¹¸¸ Uð9XÛ/¡;Ó>É~~~½zõ¢R©666=?Üh¶[®ªªŠŠŠ=zt~~~‡ËùˆÀK€µî)´dIÞ²eË­[·x<¼6•JíáBÇöööååå‹-Rdc@˜˜xîܹÈÈÈ™3g*}P@xyŽ¥{à.éêê’ÉdƒqéÒ¥˜˜˜ºº:__ßÌÌÌ·oß*±Cxn°"Ó!ùå—ï¾û®©©©¨¨¤W ðrÆU€eà$~N^°`ÁàÁƒ©Tª««k¿~ýÜOÿþýÍÍÍ?~,§Ñ¬¬÷Í®]»ìììú]ÀK€ €v¨i“äÂÂB/¿üÒ·o_ù¯ªªjjÒ÷ñ li[É“éôÅŸñ,//ß±cÇŒ3òóó1ö°PÃá%Àø<·'Kò¶mÛ®^½ÊãñØl6œdÖ~d±XÌd²¸Ü«"Ñ6©tY 5—/—þþ{¤«ëÔØXÆÇãââž>}úÃ?|õÕW¨ü¥ð /ÆÃC¬n100 P( ¥©©©²²’Çã%%% >~Ÿ,{aËd²¸ÜwBá]’=÷–Jƒ„Â%\®Wuõš§Oï{zzîÙ³'kVh¼œ;chhØY’­­­¹ÜJ¡ðÎgé•1 O_¿>2&fÝüùóQ¨€ WÆê{`¤´OòþýÉ­­ñ¥f*•Æ\ºT Œ"ð h N2‹Å"‘ !ÈMΖR霪ªëj+ hGOG»«±ñõ—»‰eCÃ5UtG—ÐÝeddA5r7ycl æ'  G—ÐÝE&O!ÎÊÙ€@8;iÒdµÕ´‡‹777C„í}UN_L$î† A'?‰¬€€Åj­ ø_¸0¸~V™Lvuª¯ïÙQ†$’6õå q/×ÏÊñò¢éèTÚG!èoj† ¿ „difÉdF ] Þáâ=0x­œwïÞ…‡‡ÿ}¼©©)‡s’ÏihxolÜwÒ¤I»Á¹Wà%ÀົZ[[7nܸhÑ"GGG‚4¡Ñ<Ð..¡Á@h%ìܹÓÜÜ<00íByðrî–Ÿ~úéöíÛ'Nœ­›5^ .¡Ççó;–••E"‘Юè..¡ÁC,ÅýóÏ?aaa»víB¤ jx 0¸„V„H$Ú°aNÿöÛoÑ®P0ðR©4**êË/¿ôóóC»@Qx¹«àu‰Ãá<þ<33íB€nÀK€ÁC,ù®^½zâĉììl"‘ˆv-@7à%ÀàZŽçÏŸGDDüðȬ! ¨^îÁSèÎ444¬_¿~ýúõ“&MB» Ûð`p Ý!‰D²eË–)S¦,X°íZeàâ ¥ìLRRÒ§OŸ~øá´ ”„‹ƒ{à]¸p¡°°ðäÉ“ ÕöÂE€A€ÛxúôiLLLrr2Xt[«aÿX,·´´€·#ŸûôéShh(ƒÁ°µµE» G°`𺠱X¼eˆv-@Oá"Ààôçöïß/‘HÖ¯_v!° A®¨¨èâÅ‹'OžÔÕÕE»Ø0x-óàÁƒ½{÷?~¼wïÞh× û—Ðà4ìýû÷kÖ¬‰ŠŠ1bÚµˆÁ~€Á%4ôßu ,˜={6ÚµHÂ~€Á%4Aqqq½zõZµjÚ…÷ÀØ—““SUU•­£ƒýß×xƒý×××ãù5ÒÍ›79’™™‰çÿ †ý_Éx~ˆõæÍ› 6ÄÅÅ <íZ•À~€q;«©©iýúõ+V¬˜>}:Úµª‚‹ãó ¼sçΡC‡._¾íBÂì=pUU‡s’Ï¿^_ÿîüù«\î¯túbü,ð“––öðáì¬,´ T ƒ‹ÅL&‹Ë½*m“J@•PXsùréï¿GººNe`~aeeeFFèP‡¼„f2Y\î;¡ð®TA6¤AÖRiPx‡Ë­e2Yh¨ZÕÕÕ cïÞ½VVVhרÖ\UUÅåV …§!¨ý[S¡ð4—{•Ïç£P™Z466††††„„L™2íZuÀZ€9œ“"££ôÂLE"Æñã'ÕZ“ºH¥ÒÈÈH[[Û… ¢]  &X 0Ÿ]*•7O]*SUu]mõ¨›Í®©©a2™h¨Öb56~€ þr7±lhø ¦jÔèâÅ‹yyy999hרÖÎÀFFæT#w“7ÆÆXkãöìÙ³˜˜˜ƒöï/ÿ—€5X 0™<…@8+w“Ò‘#G«©µ¨«« Ù°aÃøñãÑ®P7¬˜N_L$î† A'?èëÇ=}z;$$äÎ;j­L5$IDD„“““——Úµ(ÀZ€Éd²«ëTÉ«£ H$/§ .899mذÁ××÷Úµk(T‰œ„„„æææM›6¡]€¬‚ ØX†«k?ip‚þ† fú›@H&‘ÆÑh–Lf„··7ÇóööŽ‹‹óõõ-//G»je”””œ;wnÿþý˜[t†pïÞ=´kP >Ÿ…®««51é;eÊ”€€Å'Nl³™D"¹|ùrRR’D" š={6@@¥àîzøða`` ‡Ã9r$Úµh[[[¬þ«n³–™?~\\ܘ1cäl#•J+**’““E"ÑŠ+æÎ«áç´?.Z´(,,ÌÕÕíZ4®ŒÁKè6 š››åoC (JNNNtttaa!FËÌÌìòShimmݰaƒ»»;H/ü?Èd2‡Ãa±X•••nnn™™™"‘H¥å)Åb™˜˜„„„ ]€>\¸¥¥¥[!“Él6ûðáÃ7nܘ={vRR’@ÐÙ{)u+((øí·ßX,èP@8 °rãGNHHàp8¯^½rssKJJª««C¼¼n¹yóæþýû:djjŠn%€†îˆ#X,Ö‰'êêêh4‹Åª­­E°<ÅÕÖÖnÚ´)..nذa¨h `…X[[3ŒS§NAôÝwß±X¬šù#®ÖÔÔ´víZGGGuÐp ÀÝ0pà@ƒQXXhff6þ|ƒñâÅ DöÜ¥]»vYYY­\¹R=‡´p·YXX„††Y[[ûøølܸñéÓ§ŒŒŒ»wï²X,md¨ °’ÌÍÍCCCËÊÊ&Nœ¢¢Á×®]KMM=tè‰DRÅþ­†ýëëëw÷5’âŒýüüJKKÖ®]K§Óoݺ…àþ«««·nݺÿ~kkkw `ö¬¢3ðçH$’ŸŸÇswwg0HÍŽhll\³fͪU«¾ù曞ï À$`Äèëë{zzz{{ïß¿éÒ¥åååR©T¹½I¥Ò¨¨¨1cÆ,Y²Ù:,F˜žžãÀÀ@6›íååUPP ‹»»Ÿ£G¾~ý:&&F5ص¦ví©9À0 …B¡P*++>|äÈ‘€€//¯ö“œdKÀ44|06¶ “'Óé‹…Bá©S§²³³A‡:@>`Õrpppppàóù©©©)))~~~ .444„:ZF ¨¹|¹ô·ß¶K¥uN¢¥¥%ZeÚû—Ðúúú¨O „gGìÙ³§²²röìÙG$u¶ŒHtW"™˜—W‚nÍ€Vg`õ™8q"›Í~üøqZZÚÌ™3MZZv¸LKK—;ÞË‹Ÿåå`ÿ ¬9†9’Åb1±¥% ŸKÀFÇ£G ÈMÎ^@ölhh¨Æí0²°`Í<ãs qذJÇB+mìØñT*gáì¤I“ÕV ¥ÀShuûóÏ??þðáu}ý‡-->Ôas‘È Ø­îâmƒý3°æøÑ£G ƒN§[[[—••Í;£³%`·Y³¦´oCm€3°:ܸq#%%åñãÇË—/g2™D"‚ ØX±¸Üq"Ñ6©tYAС”Hd lþçŸoh^ÈÎÀªÅçóCBB"""JJJüüüàôB¤««yìØ.GÇb33;]]33{ ¥$%e÷éÓ'ìììÖ®]ÛÔÔ„Vå€VÀþÒ*ÀÅÅEý«VVV&&&¾ÿ¾³i òI¥ÒÈÈÈ?:tHÃ×yÑ4`iLQóSh©TZ^^¾hÑ¢½{÷.\¸°¤¤ÄÛÛ[‰„ØØX©TºmÛ6‰D¢ŠR À~€Õv -‘HÊËË.\xøðá•+Wž>}ÚÓÓ³''O==½„„„šššÝ»Áãh cØ°ŽŽ@PbJ½âZ[[ <<|ØÖÖ©=Ëaii™’’âïïobbB¥RÕpD@+€wC}}ýÉ“'ÓÒÒ¾ù懣æEÆœœœL§ÓMLL¦M›¦ÎC û± ¥–nãßÿMJJš3gΓ'O²²²PY"päÈ‘‡Úºuë7Ôt@á%ÀJŸ?|ø@£Ñ^½zuâÄ ‹5tèPD«ëž &ìÙ³gݺu>D± @C€wêŸþa±XMMMgΜa±X666ª(¯»¦NÊd2ƒƒƒŸ?Žv-ÊÀ=p^½z•™™YRRâæævæÌ™¾}ûª®6å8;;×××gddôï/¿³€e ÀÿãÉ“'çÊ•+‹-*--533SumJ›7o^mmmPPPzzzïÞ½Ñ.@ðÀÝ^¯^½ `ÖŠy| 88øøñ㪦h>\ÜËŸÏpóæÍÀÀÀáÇóx¼ÐÐP­H/,,,lôèÑkÖ¬ñ îì OÖݲe‹ƒƒCYYY@@€l²®¶ ÑÑÑ›7oVéxo@3á4À|>åÊ• ÃÉÉéìÙ³~~~ðzEÚHGG'>>¾µµ522L<Ä|ž¬»xñâ;vxzz–––*7YWÓèéé}ÿý÷ÕÕÕ, íZµÂËC¬¦¦¦òòr6›ÝÚÚº|ùrwwwLýò"‰III+W®LNNF»@M°`‰DR]]]ZZ:xðàGGGDfêj SSSxâ¡‘‘ѲeËÐ.P,ž¬{ôèѦ¦¦©S§îÙ³íŠTΞxhbbâåå…v9€Êa3ÀŸOÖݽ{÷µk×4pq±²²‚'šššº¸¸ ] ZX 0¿¾¾íÒÔgÈ!ÉÉÉÆÆÆS§NE»@…°à†††œœœôôôñãÇ'&&Ž;Vö#Mèí®f£F:tèÐúõëÙl¶zZ¨À“Xx²®««ë“'O222Ølöçé…p`‚&L˜ò×_¡]  *Ú}þðáCvvvvX×"IIDATvöôéÓúé§Áƒw¸™f.¬ %<<<((èÇ´¶¶F»yÚàׯ_§§§¸ººæååYZZÊÙX3WU¹sç ‚ÀÀÀŒŒŒ~ýú¡]€0í puuuFF}h4ÚåJB>ÀUUUÎI>ÿzCÃcc 2y2¾˜L&·Ù¬µµµ¤¤äرcæææ›6m¢P(ˆW"Ü¡°Ù쀀cccGGG´Ë”d€Åb1“Éâr¯ŠDÛ¤Ò#d%Ô\¾\úûï‘®®Sccð…1<ÏþÈ‘#}ûöŽŽ¶³³C°†wføð቉‰!!!ßÿýäÉ“Ñ.è6$ŸB3™,.÷PxW* ‚ Ò‡ k©4H(¼ÃåÖ2™,¡P˜™™I¥Ry<ÞÞ½{³²²Ô^X®ñãÇ8p ,,ìÞ½{h×tbgપ*.·R(¼A&í~h*ž..S^ÎýꫯԶ(¶ |æ‹Åh@© ß|óÍŽ;BCC?ŽÊ²©€Ò 0‡sR$bt”^˜iKKäÈ‘¹löa¤ŽØ-ð›$àÎ899Õ××Ó– „v9€¢»„æó¯K¥òfÒ<¸ÔẠ\EwÉÝÝ= 00ðýû÷h×( ±76~€ ùë\Z64|@êpݬF§ÓëêêЮPb622‡ ¹›¼!‘Ì‘:\w+hÍš5«W¯ …h×t ±“ÉS„³r7)‰D¾¾¾™™™oß¾Eê¸ V\xxø°aÃÀÄC­€X€éôÅDântòs‰ìØ÷t:ýþýûžžž¾¾¾çåË—H °âBLLŒ‰‰Ixx8˜x¨á<“]]§’H^eX@$zÑhÓíìì( ‹Åª¨¨ }ûö­‡‡GRRÒ‹/ª¤C`>C·èêêîÝ»·±±q×®]h×ȃä@ŽØX†«k?ip‚þ† fú‚ŽèéêÓç“!ÛÒÀÀÀÁÁÁ`”——ÇÄÄÔÕÕ-[¶ Nò³gÏ,éó#‚3p·èëë:tèÑ£GD» SHXWW7..òر]ŽŽÅffvºº&¦¦vzzŒ¤¤½âââ?B&“ ÆÅ‹á$¯\¹N2²ÝŒA€•@"‘’’’.\¸ÀápЮèò“ÈdòçSD"Ѿ}ûüýý'L˜0dÈ?'™L&GDDܼy³¼¼<44T*•R(*•Ú~.Dw+§wïÞ©©©~~~½zõZ°`Úåm©¼#‡‹‹Ë¹sç¾üòË   -[¶´¶¶vQŽ™LÞ¸q#—ËMJJ233‹ŒŒœ={6‹ÅâóùJ7‚VZÿþýSSSÙlöÙ³òß2(PG€+**ššš|}}ûôésôèQÅ?;|øðÐÐÐÒÒR6›mffíââ¢\’A€{ÂÆÆ&99™ÅbýòË/h×ü•¸OŸ>£Fºví@ˆ‹‹ËËË»yófww'¹¸¸899ÙÌÌ,&&fÖ¬Y,«²²RÁ÷ À=4räÈÄÄÄmÛ¶UUU¡] ðÿÔÑÔÎÅÅ¥¬¬ ‚ ‹ØØØˆˆ¥û„“\XX˜‘‘amm””äèè?Í–q®¯¯ÜC_}õÕ¾}û6lØðàÁ´kþCM¾téüvúôéÓ¦MÛ½{w÷immíçç—••uòäɱcǦ¦¦Ê’Üáû^pF„½½}LLÌêÕ«Uô¶è.uØÒÒò‹/¾øý÷ßáÿŒˆˆ¸ÿ~ii)";4hœäŸþ¹M’?O,0RfÍšøúõk´kÔÕZv A¡¡!‹Åb±Xÿüó‚‡0`œäüü|2™|êÔ©éÓ§‡„„466âv…QUðôôô÷÷§Óé`â!êêi¤R]]½hÑ¢ŠŠ Ù”z‡SQQ‘––¦ºIöÿþûïåË—y<^UUUß¾}‡ oll¬¢ÃáÍÁƒ/_¾œžž®Äb7*ekk‹Ÿö@j:4hàÀׯ_—ýÉŠ+ôõõ?®ºƒš››{zz²Ùì²²²Ñ£G?yòdæÌ™ð9Yé§h€Ìúõë¿ù曵k×655¡] ~©oi•Ù³gŸ;wîÿ¬£³{÷îÌÌÌÛ·o«úнzõš0a‚££ã¹sçà–z³fÍ ÉÍÍýðµ°eË–AƒmܸLZB‹úìêêzîܹϿiKKËèèè-[¶444¨úèðC,333øœ\QQ±páB>ŸO£Ñà)ÊàvN !66V*•nÛ¶M"‘ ]©/ÀÖÖÖ}úôi3ŠÃÙÙyòäÉûöíSõÑÛ<…&‰ðÄÆòòrxв››œäÚÚZUƒ%zzz 555=5(A­«¶¹Š†mß¾ý?þàñx*=tg¯‘dI®¨¨€“ìáá'¹¦F~‡ à?ˆDbbbâíÛ·Ñ®wÔ`*•ZVVÖf3‰DÚ»wo\\Ü›7oTwè.ß~ÞlàÕ«W ,PO³ 0119zô(ÇKKKC»|Qk€¿øâ “öO­lmm—.]ªÒU§ÈѾـŸŸŸJ› `ƒ¹¹yjjjNNN^^Úµàˆºøîð*‚    –––ÌÌLW‰–:²f—.]‚“¼bÅ 8ÉOŸ>UQZÍÒÒ2%%%))IÕ7D€ n AŽŽN||<‡Ãyôè‘*ŽÛ“¡”íÛ†Ðét„„>ŸlÚnðàÁÉÉÉ»víºrå Úµà‚º™AÖlnÝó¶!˜1a„={ö¬[·îáÇhׂq(øó‰ íEEE•——WTT {PÕÍF’58räÜlÀÙÙ¹[Í0iêÔ©L&388øùóçhׂe(ØÖÖV,?~ü¸ÃŸšššÆÇÇ3™ÌwïÞ!xP5L'”58zôhÿþý“’’(Š"ͰÊÙÙyÆ ÁÁÁê_ˆ?P0ÔÕI˜L&{yymß¾ÁkQuvä>|x@@@VVVvv6~üˆv-Ø„Z€¹\®œ BCCANNRGDeB¿¬mÈ©S§i‚I3fÌnllD» B'À_}õ•H$’ó6UWWwÏž=l6»³+íîBwBÿÀá$çåå;6++‹B¡lܸ±  ‹†……=zÍš5`â!âÐ 0@pvv–s A͆ ¶lÙ‚È·®!-u¬¬¬üüüRSS‹‹‹y<…B§(«aJZBtt´……ÅæÍ›ñü`OÐ 0ÔÕm0lþüù_~ù%"Cäõôô$‰æLy“5àñxðel7€ê´¶¶FFFj瀨xâĉ>|èrt1“Éär¹×®]ëù5sÂÞ½{ÃIÆ|³==½ï¿ÿ¾ººšÅb¡] v `ggç .ÈßÌÌÌl÷îÝÛ·oïùcL ¹ŠîŒ¬ÙÀùóç===1Ùl€H$&%%ݼy399íZ0µCŠ]EC4eÊ”9sæ0™ÌN3ÏÀ홚šÂÃ31ÙlÀÔÔôèÑ£ÅÅÅhׂhxòäɯ_¿~õêU—[®[·îÕ«W§OŸîÉá4ü Ü^û¶!Øh6`aa‘ššš••ÕÃ/€T±¼¨âtuugΜyþüyù[ìÛ·oùòåd2yèСÊNë,'™B¡455UVV–——{{{[YY9::º»»<í»ÍÊÊ*%%ÅßßßÔÔÔÅÅír´šg`¨óéÁí 6,$$D‘J;£½–Û†ÄÄÄ\ºtiëÖ­uuu¾¾¾ðe­r_ÓÆ3.Y²ÄÓÓ3((èÓ§Oh×¢MÐ0A...Š_ECdhh¸oß¾½{÷VWW+þ)XNrQQÜl !!A6±QsfO›6mõêÕ`â¡â4"À&&&ׯ?´³s?~‚½ýÌ-]>€'ÍGDD(þïÏ–ißl@–dMh6°iÓ¦#F¬[·|S B9Àb±822nÍš­­ñõõ×%’àúåËAA‘‘‘qòùlÙ2“””Öøþœf6€'𙙉‡ B9ÀL&‹Ë}'Þ… UdAúd-• …w¸ÜZ&SÞ´°cÇŽììì[·n)r,l?…VZ›f²$óxo6píÚ5gggxb£JÛ†XXX¤¤¤dff–––ªî(Z Í™Cüy­oŒ-ÙÕØ±cýüü¶nÝ*çÑ%pÏÉš ÈÖC—µ A¶¿Ì€Ølöž={_¬Ð 0™<…@Ý[:q"YÁ½Ñétü±³ ÀShµo60wî\8Ɉ¯Ã0|øðÄÄÄÈÈÈë×»¾ŸÂ4L§/&wCPgwS]Ý÷îýž››«È+A¸ïazzúÝ»w;ÜœUA–dÙ9ÙÓÓÓ××—Ãá¼|ù©£Œ?þÀaaa`âaèžÉ®®SI$¯Ž2, ‘¼æÍ›uðàÁ¢¢"///EÖŒ¶´´ŒŠŠb0.P ¬Rp³‹õ믿nܸñíÛ·>>>6øæ›ovìØªEžÕ€€î¯4±XÌd²¸Ü+"Ñ6©tYAС”HdÑhÓ™Ì]]]‚*++÷íÛG"‘ÂÂÂ&Ož,Ÿ ÃÈÈ(**ªÍŸóx<§ŠµK‰Åâ[·nñx<.—Û«W/*•J£Ñ¾øâ‹žì³¨¨è‡~ÈÈÈ4hPgÛØÚÚâçDr€a|>ŸÃ9Éç_ohxolÜwÒ¤I‹'Nœøù6‰äܹs 666ááá£Fêlo ,wrrúüÏ/]º”——‡H›x [$ÉÍ›7y<^YYüŒB¡ØÚÚ*··'NdeeefföéÓ§Ã @€5WKKË™3g’’’ÈdrXX˜M‡›Ý½{wÍš5¹¹¹ýúõ“ýá•+W~üñÇcÇŽ©«X -‰DòàÁƒòòò¢¢"©TJ¡P¨Têĉ B·ö“˜˜xáÂ…üÑÌ̬ýOA€5P(À°§OŸ&&&Þºu+88ØËËKöuž9s&--mëÖ­™™ùׯÿÞÐðÁÔ´/™<™N_L&+:DP³W¯^]ºt‰Çã=þ|úôéT*õÛo¿ÕÓë`‚–––›èè說*øQ¨@PkjÚ'ß2F »}ûö÷ß_[[»víÚÙ³g±XL£y½yÓ(3ÿûšª†@(%w»ºNeÈù ®ººúâÅ‹<ïÙ³g3fÌ R©Ó¦MÓ××ÿ|¡P Aÿýñ³—‘xù–1`Xee%|MVTtîìÙw"Qû)ÇÉËÕµ_\\$:UÝñúõëóçÏóx¼§OŸ:::R(GGG"‘ÿtË–èÒÒZ©´‡ß2 AT*-++Û»wom-A,~ÜÉ”c‰4þر8Ì_eaIMMÍåË—/]ºTUU5iÒ$*•Ú·oßõëw …wðù-c3À°ààÍ¿üâ A«:Û€@8J¡'&îQgU">~üXQQÁãñ~ýõ¦X¼·ß2–lo?S ¸AÖoò·™™]e¥B »šÉÎnf}=~¿e­|¬ ¤šL(Äõ·Œå#Ø0ÐX8ÿ–±à.g'Mêbn ápþ-c9À]6 Y‹ÕZ€4œËXp— h´ém&-Zçß²nhh(Ú5¨£ã´W¯ø/^0Äb#êA$ª&²I$m,“¡£ƒå_a8ço˯‘dih;|~˸0`f/-@€@‹€- Z ´0h1`Ðb À Å@€@‹€- Z ´0h1`Ðb À Å@€@‹€- Z ´0h1`Ðb À Å@€@‹€- Z ´0h1`Ðb À Å@€@‹€- Z ´0h1`Ðb À Åþø1j£• IEND®B`‚puzzles-20170606.272beef/icons/untangle-48d8.png0000644000175000017500000000246513115373751020024 0ustar simonsimon‰PNG  IHDR00`Ü µgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<qPLTEÕÕÕÚÚÙÔÔØÓÓÔÌÌÌââ߯¯¤°°¤ÓÓÓÜÜÜ¡¡¡¾¾¿ÞÞÙžž² ¿·´´º²²²ªªªââÒII©ÿödd¢ëëÞžžž®ËÆ‚‚©©¦ÆÆÆ———ääÜžž›¦¦¢ååà¿¿¿ÃÃÃÛÛÜ›››ÈÈȺººÃÃÄ–– ¼¼»ÔÔÓ¥¥¥¬¬¬ÑÑÉŽŽ®šššÊÊÌEE—ë訳ááäÖÖÅ%%¥üÝå娖–¥++º99­ßßàÛÛÊââÕ¤¤¥¹¹¹«««ÇÇǵµµ{{{œœœàààÙÙÐ¥¥¯ÛÛ×´´µßßÕkkªÀŠŠ00°ll””¯¿""—§§¨ÒÒÃÐÐл»¼°°©’’’æææÖÖÍrrˆšš°áá٬Ⴣ¯]]¨MM˜Êʾ==²ÝÝÍ©©¡ŽÓÓ×ff‡Ì ÄääÖEE¨jj¦¸ÏÏÃÿÿÿ¹@NbKGDz8Õ…jtIMEá%=¹"ÁIDATHÇÍ•Ù[Ó@ÅçΤpg´  jS&m MPDP)( (®(TQqCÜ·ÿÞ™T>è’¤/~ŸóЇäüæÞ9çNCȳ úeížjQr–êêNaÓCäBÖ^oôœ8™lÒgLŽzOeûNŸ¡Ø ×­È#0£ÿì¹ó9›¶À@ËǸÁ. „pÜzÓòŠ¥xž ¼,)gŒðJL7q/ùÒ ©!3ˆÓ« ™z± £/å8‰]®—©+*”u_¿20Ѓ¿102yõÚÔtÿ Æ(pËŠ<†œ½>×UM•êá©Só 72<–€‹àÚB\髲õfŠÅU(ûUp„a“úÎîÀHL 9‹K–°ØÑ¶y" àË·L%?¾ÉÛÝZ±VIã[˜kNCC¸”›ñi›>ó¥†§ÌÆ‰W45š€–ÙA°ãX—tí¶¾¾a™Èe¼(Ú 3/ÀîÜÞ¼·ŒFØ; J¿Ÿ°FePa…õ$€=Îm­,–‰JK$éUOOžú«Û;¾8|ÂX"Q¨qÔ}Ë|†\]ÎxôŒ¯ò™Åó¢YP½Å„ ̇ùnjŽimé ÆÈBÌõ— ¢~U„¼ Éøºê 1ÐÍ]áÉ™C {sË÷ÐÒA‹’"ªãøšÊ#dÊ!Ã9i5¹_ævÑ•÷Å?ü£ [1ÛÀiSþÒ§ÚŽG@èp(Õ†—G[òñòÕ_±epvƒ¥Œ)Æôš>lïõ›é·©±¢´µÜšåÍÉÞMeß÷Nzb7çÐÄÑPgØŸû ¬Õ­Bº Éz¹àà Š¦µóñS°×AYã³R®Õ¾|ý6!E¿ÿÈöýœé hôlþJòúíÿ6:—‡]uâê¿[^HõßÚË%tEXtdate:create2017-06-06T01:31:37+01:00‰Ï‰Ê%tEXtdate:modify2017-06-06T01:31:37+01:00ø’1vIEND®B`‚puzzles-20170606.272beef/icons/untangle-48d4.png0000644000175000017500000000066613115373751020021 0ustar simonsimon‰PNG  IHDR00¥,ä´gAMA† 1è–_PLTEÀÀÀ€€€€ÿÿÿÿ³ÑY‹bKGDhÙQtIMEá%=¹"ÐIDAT8ËSÑ„ k =Àçèþ» "ÐðîüðiCÒ¦-"?¼ŸÚÆ—0Öƒ’EöƒDa`„|LAåª `Pe‡“·ø¹-»g쑉Gs ¿ÌפƒOd ¼½½>|/¼'òSesý^Ê.è¹yÝ ¼ÙÍ(#;0 ÜaÀ;|ÚW]‹AúMþ{¾Q‘ ËVŠùl%tEXtdate:create2017-06-06T01:31:37+01:00‰Ï‰Ê%tEXtdate:modify2017-06-06T01:31:37+01:00ø’1vIEND®B`‚puzzles-20170606.272beef/icons/untangle-48d24.png0000644000175000017500000000452513115373751020101 0ustar simonsimon‰PNG  IHDR00Ø`nÐgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEá%=¹"YIDATXÃ͘ËO×ÇÏ9óôxüã±Á¾øA•]žA-…„En¥ªë.ҪꦪTeÕ? ëÔMûTb‘J•*]!q (¥ª áZJ <Œ ØÁ6/{ìys'±Ø`ªÛ³[óøÌ÷÷øþÎÀçÏŸƒ¿ÓBÿo€¿ BõÝ !„1=heAUU…^ÆÄå×Ö–67Ÿ9ÆøŠ—cQ—––X–%çÞéj@»›ž~þÙg¯¾òÄãë‚À7Ï„1¶Ûíñxœã¸H$¢ëúy‘®DbYmjªR*MîíÝûå—l[‡‡1&—Åcl³ÙR©T¡P­T*×2±e |À°èv/wwffþ8<,Úl6Ž»‹ÂqÜÑÑÑÊÊJ,««ÍëG\µa Ünazú?¢(Ü»ww}=•J%!„ÑhÔï÷cŒu]Ô‰B³³³###.—Ë0Œk"„ð¼˜JmYŽF£„X Ãf³ÙD"A ‡Ã]]]MÓ(–eˆÝ.ÍÍ̓ÁH$R©TÕ<€½Í›ÀÃ0MÓ@V*†×ëõûýûûû›››‰D" ƒA€iZ.˲â“'8Žžžžr¹|M‹@–e ãuh „†aèºÞÖÖ‹ÅòùüæææÖÖV$õx¤GvxþØãacªz Më@ÂÓÕN±,Ë2 ÃårçóÅ\níÛo§§? þóχ Ci”9ïDa†yBÈ0 Œ±¢ø=™LààÆîî“z]ðZ:ƒB¡µ-Šb¡PxúôÆ×_s?ü0­([ÝÝvËâ!Ô¸D¢BµQžçY–¥y­ëz( ‚‚€îßÏ‹âùùåxü¿ýýýIRBB„Ú yžg&—Ë% ˲Âáp hš¦ëB·¦áñññ¹¹¹ÕÕÕÞÞÞ‹™Þ)©9Ž#„är¹­­-BH4íììÄך„ ¢iÚÄÄÄìì,Ïó‘HDUÕFL­QÇfY6›Í¾xñ‚eÙžžŸÏ‡1¦u¦–h†A™8Ž Úã€h‘‚€J$ËËË–eõöö*ŠbYEiôÞTQáÄÄÄãÇ9Žóz½ÕjõüùMYG cœN§3™ŒišÂû÷﫪J/ï0BX–Õu}~~~llÌívkšvæÂú aL |-5@EÓ4“Éäöö¶$I<ÏÇãñJ¥bšæ¥Í÷´N¦i ‚‹ÅÆÆÆdY>3NÕ"ʲh–®¢(†±±±‘ÉdœNçÐÐÛí6Móää¤yaÎ0éºîp8†‡‡···ûûû-Ë:}“3@B†eµßéóÉ¡PpuõåÞÞ®Ûíq:º®«ªÊ0 ˶Xž„¦iííííííç£·ÔÆÚløûï×>ýtàã¹GþAUUŒ1 fS^Ð8vg´©!cšå'Ox¢ÿÜÞÑh@lÔ¼hw¦ôFM¹ec¦ºÿ¿¥Y–é;Ÿïd hÔÅ_*d9ag.—‹ÇãCCC´ôNÕg.¤dt³†êèèðûý†aP²ååe–e=Ogg§ gü]df àž™yùë¯ÏLóx``¨P(d³Yžçi°N+T÷4š¦iÒ±Éãñ Æb±7n”Ëå\.G‹·) Ë"v;ššÚúî»_~Ù?5•´ÙÈààp<§[Û+6c±ô|Ó4éår¹nß¾‡é Óa¬ €á?ÿÌ™¦êóùC¡Ðââ"m6–ue/«íq)Ùùêtê7WŒÙ÷ÞÃkkË‘ÈæçŸãt¹\îëëÛÝÝÑu“eA%IÆØj¡/7ªÿ‹fjBÏs S€0Œçèèxmmíèè( ‹;{{…îîàÈÈíãã*B×f®— ù„B!T¡X<ÜÙÙøí·Ä?þK–«?ýt86vCUõëbºd>‡"„ ƒ!ªªJ’ýý÷¶¶"Œ”JÃóóÇ¢xsÑÕ¾1"„06K%øàÍéœíîžÿ裎ƻÐVÖ•?é6S(ìrçp(ÕªñhM½ªj:ABH¥b\cF·@š¦N®‘¦u p­sôéõ?wÙÉK¹Y}%tEXtdate:create2017-06-06T01:31:37+01:00‰Ï‰Ê%tEXtdate:modify2017-06-06T01:31:37+01:00ø’1vIEND®B`‚puzzles-20170606.272beef/icons/untangle-32d8.png0000644000175000017500000000165213115373751020012 0ustar simonsimon‰PNG  IHDR D¤ŠÆgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<PLTEÕÕÕØØØÜÜÒÕÕØÍÍÍÔÔм¼Åww­ÓÓÓ±±±ÅÅÅÑÑÔââÔEEÁòææÛÜÜÜ»»»¶¶¶ßßÕ€€¾!!Ä’’ª³³³ÉÉʬ¬¬ÚÚѸ¸¥ààÜ«««ØØ×ããÕÞÞεµ­ffÀHH°Â¿ããã®®©Õ人¿ßßÚÁÁÁ½½·’’¿ÛÛÜ··¸³³´žžž½½½›››ËË˦¦·xx¸õDD­ÇÇ·””¿Ò^^¨ÁÁ¶™™ÌÌÎ××Ï•••©©©¸¸¸ÃÃÃÞÞÞŽŽ¡¯¯°mm»aa»ííÞ©©­¿¿Àˆˆ½Ùkk©ÅÅÁÐв²¬††•œœ± Ñ··¼ÙÙÌAAÇ..ÈÉÉÇØØÊÿÿÿ›è´bKGD\êØ—tIMEá%=¹"IDAT8Ë}’g[à …¹†XŽ@ÕmR÷Hj¬X·µî½÷øÿÿCòDkÒ ÷œ—{à\ú» °ÑcåÖ8/ÛÐ["Yœ:ù¬¯ 4ˆ~—‹n‹òÐðHŃtY¸‚5:Võ*2A˜…ý‚®M( Sé@mÜÇÀ¦Io‹‰É©iƒŽMígfçæBfd"Cä×K•ER8\E‚$²‹aaƒ»Ý&Ë>'?­cªÜ¼L]Á¿{,”QÇ%-K®-rGdó›°W=å+mA»æ—ò¬¶¶¾±WÓ€)VÛÚÞi5¡ðÓëYµµÛn I½Êž‹Œeù\ËYØ?p€eà‚‚žÁ!¯KzD xˆ€Ü;¶ž2d¾0K•f§™¦öR$ëqu>Ã;áj«ÓNn¬v6p~q‰¯T&(ˆ¬|}sÛj7îîrIfŸ[¾¢Ó‡Ç'ãGK³Ò¶Ïó/šy}{ÿ°úø пŠ翤Z#’so(%tEXtdate:create2017-06-06T01:31:37+01:00‰Ï‰Ê%tEXtdate:modify2017-06-06T01:31:37+01:00ø’1vIEND®B`‚puzzles-20170606.272beef/icons/untangle-32d4.png0000644000175000017500000000070213115373752020002 0ustar simonsimon‰PNG  IHDR TgÇgAMA† 1è–_PLTEÀÀÀÿÿÿ€€€ÿ€Wÿ‰bKGDÿ-ÞtIMEá&¤°C˜ÜIDAT(ÏER KÑ´úÔxÎìÿ¯2Iá¼mP(iÒ0 õd P?™‰œ½Šáå Dr‘:Ïíû™Åc-¦ŽêãF­Ã*ærž\Oh!Œn“+_O´& pgC@“0Ò¬‹ d‘‚.`Ø£%`ײl&¤¸‡-ZÑõD»K$[/»²,AN¡¨¬)׳{ŽMSzÔJ @£6ã¿‹\¸6ft'Ø®a+Œé Š»ÓÚŽ¾æÓûÒ!éáv4ÌXe9ŽVZÝ6ɾË»U¶Æÿés[ o/V’%tEXtdate:create2017-06-06T01:31:38+01:00‡ù#%tEXtdate:modify2017-06-06T01:31:38+01:00ÚAŸIEND®B`‚puzzles-20170606.272beef/icons/untangle-32d24.png0000644000175000017500000000301613115373751020064 0ustar simonsimon‰PNG  IHDR üí£gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEá%=¹"IDATHÇVKOg½÷›‡gü‡àp<`7 °¨ÒJ‘ZeU—ÉOáD*«,²Ì&RYe“d‘}TUM›c c†`À<¯ïÑÅ(Ƙ‡IïÎÖçsî½çÜ{‹‹‹paB ¢@„Ë!„s~üq ºª]§’4à% "¸®‹=¹ Ñ…ªJëë»ÿ>" !.x¬(J¥Rét:„îË‹ ˆªºÒùùÏžýkY ¢,„8MÃ9×4­Z­Æb±«W¯RJ»E\\¸B½s‡ÿ9:ê¾{Wj·÷UUU¥—F‹Å¶¶¶:N>Ÿ÷}¿·Ex±ÈˆD–ƒ••…Bá'ÇÙuœcüÚµk–e@†œ£,ËžwT©T¦§§{åB¤w]âºÆá¡ŸN§,+ÓjµF£ÑÈf³W® Çã!¥G Ë“““‘HxÒm„IBDF2Æ)õ‰D¡Ph·Û››VËyñbh}}nîJ2™ô<þž_Ö|QÇ‘1æy^*eÌÎÎø>}òdøõëŸ=8À“2°Eýªªrη¶޳mYÆüüv½^¦Tø1ü?ºBÓ4Ji£ÑØÙÙÑuݶóñxbb‚ªjîýûêÒÒç©©)Ïóú4Ð"Îy”5ÔëõR©yѶmUUƒÀo·Ù—/¾mç…ÕjUÓ´>#Kõ$‹€ã8¥R)Û¶óù¼¢(¾ïG†‘$”eô3c…BRÚ}I€10 xútëÁƒ_ææ6‰pvöÇññqð<ï+ýè^å¢´Ž RÌåbˆÕÑÑÐ÷Ù§O¥ÍÍÍh‹)Šr™ÜOÓ·ˆ8<ä÷îܺµ\.oƯñx°³ÓÜÞÞV%›ÍrÎEéš¾Nße¢«±áaÛqÜååÊÌÌL&c…aØjµÖ××;N.—K¥Rš¦ !cQM™z'Y†‘B,--MMM1ÆLÓaŒB\×uG–eÓ4MÓÔ4 ºzžÇtbU ‚®ëœó êõúØØX´ …†a {žwxx¸··×l6%IJ§Ó¦iêº~“ÜƒŽŒ±L&³¼¼\,þðáÃ{ËÊ(ŠŠˆ‘ǃ àœ†‘Éd(¥ÓÊÊ !¤Ë„ˆ”Ò~‘»VYVüÉÉÉ¥¥Êôôt4ÝcŒQJ •J™¦É‹˜jµ!Ä0 Ó4£-plÓ¾0Íä«Wÿ$z:®Õj‘ª½IE51Æ|ß§”&‰ëׯGÏ[]]u]·{yú*@]Ÿ?§ýöñã¿ÿžóæïfsGQTJÙi£o8çŒ1ˆÇã†aD%vç¦ÿ0†ccDÓñøîÂB811^¯oZVŠrþ¢c&ß÷ût>ý¯U•í&“ÖÆFsooº¸èd³¹»w§:JÈeGì<‚èÐËŒQE‘ðóç÷ïÛÎÐË—eÛþÞuƒoâ8ãd"cadMB$Ûž¸}»Ólº–• ”_~Iœ[ÁÉj„$I„ Á0d߈?èèGvd,ˆBÐoMþ×Í p:Œy%tEXtdate:create2017-06-06T01:31:37+01:00‰Ï‰Ê%tEXtdate:modify2017-06-06T01:31:37+01:00ø’1vIEND®B`‚puzzles-20170606.272beef/icons/untangle-16d8.png0000644000175000017500000000144513115373752020015 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<DPLTEÕÕÕÔÔÕÛÛÔààÒÕÕÖÔÔÔÖÖÖÒÒÒÓÓÕààÖÍccÆßßÓÖÖØÓÓÔÍÍÌÃÃÃ×××ÜÜÖ±±Í„„¿ÈÈÁÆÆÈÒÒÔààÙÙÙѽ½¿ÖÖÕÕÕ×ÕÕÏÑÑÅÈÈÉÉÉã£È™™ÁØØÑÎÎÐÃÃÅÛÛÚÔÔÖÓÓÅpp¾nnÄããÕÂÂÂÈÈÈÀÀÀÉÉËßßÖÔÔÊ¿¿À××ÕÛÛÖÓÓÓ±±±ÍÍÍØØ×××ÙËËÊÁÁÁÎÎÓ½½ÏÉÉÇÄÄÄÉÉÉÙÙÙØØØÊÊÊÐÐЧ§Ð33½ÃùÏÏÑÅÅÅÕÕÔ±±´¿¿¿´´´ÎÎεµ¸¼¼¼ÇÇÇÌÌÌÐÐÒÏÏÀÇÇÁÒÒÓÃÃÄÏÏÏÆÆÆÝÝÓffÆŸŸÄÎÎÅÊÊÆ„„Χ§Äºº´·ââÕßߨÁÁÉ88ÇÃÃÐÚÚÖÒÒÕÒÒÑÿÿÿ :GXbKGDkRe¥˜tIMEá&¤°C˜ÞIDATÓc`F&fV ÍÆÎœ\Ü<¼ |¼ü‚`F!aQ1q I)iˆ Y9^yE%e¨›Šªšº†¦–6D« «Ž®ž¾¡ØcAS3s6 K+k6 ߯ÖÎÞÁÞh-«“³ §«›»«§È!‚@^‚Þ>>¾~¬N‚ ¬ AV'~>¶€@kû ÈÎàаp'†ˆHû °­QÑ1±q^ ‚Nlìl ŸÅ'$&©53°9A–œ’š–žÁ2âòLÁ,˜±ò¾ú?¾%tEXtdate:create2017-06-06T01:31:38+01:00‡ù#%tEXtdate:modify2017-06-06T01:31:38+01:00ÚAŸIEND®B`‚puzzles-20170606.272beef/icons/untangle-16d4.png0000644000175000017500000000045013115373752020004 0ustar simonsimon‰PNG  IHDRbògAMA† 1è–_ PLTEÀÀÀÿÿÿ€€€ÿ.dp6bKGDÿ-ÞtIMEá&¤°C˜EIDAT×Ê1 €@ Dш Vð@X¬,ö {ÿÚµyÕ#*N*ÒÀÍÕD%ˆ­M³ðD;£øxsw‚z[øÈøáœ$*-(û%tEXtdate:create2017-06-06T01:31:38+01:00‡ù#%tEXtdate:modify2017-06-06T01:31:38+01:00ÚAŸIEND®B`‚puzzles-20170606.272beef/icons/untangle-16d24.png0000644000175000017500000000233513115373752020072 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<ÁPLTEÕÕÕÕÕÕÔÔÕÛÛÔààÒÕÕÖÔÔÔÕÕÕÕÕÕÕÕÕÖÖÖÒÒÒÕÕÕÕÕÕÓÓÕààÖÍccÆßßÓÖÖØÕÕÕÓÓÔÖÖØÍÍÌÃÃÃ×××ÕÕÕÔÔÕÜÜÖ±±Í„„¿ÈÈÁÆÆÈÒÒÔààÙÙÙѽ½¿ÖÖÕÕÕÕÕÕÕÕÕÕÕÕ×ÕÕÏÑÑÅÖÖØÈÈÉÉÉã£È™™ÁØØÑÕÕÖÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÎÎÐÃÃÅÛÛÚÔÔÖÓÓÅpp¾nnÄããÕÓÓÕÕÕÕÕÕÕÕÕÕÔÔÕÔÔÔ×××ÔÔÔÂÂÂÈÈÈÀÀÀÉÉËßßÖÔÔÊ¿¿À×××ÕÕÕÕÕÕÕÕÕ××ÕÛÛÖ×××ÓÓÓ±±±ÍÍÍÖÖÖØØ×ÓÓÕ××ÙËËÊÁÁÁÖÖÖÕÕÕ××ÕÎÎÓ½½ÏÉÉÇÄÄÄÉÉÉÄÄÄÙÙÙÔÔÔÕÕÕÕÕÕÔÔÔØØØÊÊÊÐÐÐÖÖÖààÖ§§Ð33½ÃùÏÏÑÔÔÔÅÅÅØØØÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕ×××ÖÖÖÕÕÕÕÕÔ×××±±´¿¿¿ÉÉÉ¿¿¿´´´ÎÎÎÔÔÔØØØ×××ÕÕÕÔÔÔÔÔÔÕÕÕÕÕÕÔÔÔØØØÍÍ̵µ¸ÓÓÔÖÖÖ¼¼¼ÇÇÇÁÁÁÄÄÄÌÌÌÔÔÔØØØ×××ÕÕÕÕÕÕÕÕÕÖÖÖÐÐÒÏÏÀÇÇÁÒÒÓÃÃÄØØØÕÕÕÏÏÏÆÆÆÂÂÂÄÄÄÌÌÌÕÕÕÕÕÕÕÕÕÔÔÕÝÝÓffÆŸŸÄÎÎÅÊÊÆÕÕÔÕÕÕ×××ØØØÖÖÖÏÏÏÇÇÇÒÒÒÖÖÖÕÕÕÔÔÕÛÛÔ„„Χ§Äºº´·ÔÔÖÕÕÕÕÕÕÔÔÔÕÕÕÖÖÖØØØÕÕÕÕÕÕÕÕÕÔÔÕââÕßߨÁÁÉ88ÇÃÃÐÚÚÖÔÔÕÕÕÕÕÕÕÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÒÒÕÓÓÕ×××ÒÒÑÕÕÕÕÕÕÕÕÕÿÿÿpµ³bKGDêÈÚ.tIMEá&¤°C˜IDATÓc````dbfaecçàäâæáòøø…„EDÅÄ%$¥@Ò2²rò ŠJÊ*ªjê  M-m]=}C#c ßÔÌÜÂÒÊÚÆÖÎÞÁÑ„ÁÉÙÅÕÍÝÃÓËÛÇ×Ï? !(8$4,<"2*:&6.>!‘!)9%5-=#3+;'7/¿ ¡¨¸¤´¬¼¢²ªº¦¶®¾¡‘¡©¹¥µ­½£³«»§·¯ÂD†I“§L6}ÆÌY³çÌ7ÁB†E‹—,]¶|ÅÊU«×¬]·~ÃF†M›·lݶ}ÇÎ]»÷ìÝ·ÿÀA†C‡=vüÄÉS§Ïœ=wþ‚:ÃÅK—¯\½výÆÍ[¦·ïܽwŸáÁÃGŸ<}öüÅK0!kA:¦ê%tEXtdate:create2017-06-06T01:31:38+01:00‡ù#%tEXtdate:modify2017-06-06T01:31:38+01:00ÚAŸIEND®B`‚puzzles-20170606.272beef/icons/unruly-web.png0000644000175000017500000000451713115373724017633 0ustar simonsimon‰PNG  IHDR––j.>gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEák ÖWIDATxÚíœkOg€ûc¶Ò®ñmn¾%)·°% “¤m¨ípI¶i¥(”4 …|7öëªê‡m¢6ÝìVZí~K‰²Û‚ ¤ÐÆ—ßØÐÆFjzû¶gÞsŒ°ƒÉd5Ï7ކÃÃxì9¯Ïœ÷…‚*yáY <‡Z›*B¦µ¦"ÊZ›k'zœ½Îý ·–Ô='Ö6ËZ=ǺqºjáX'FW•ÌøÑ=2-g·³¬lïäÄ;êñƒè¸ðƒèÜÉ\ìªÉ†¤¦\Kóààùûw:2­ÞnŽ¢ŒÉ I¡±Áˆ†¯ùäQ*C’,ð:I­÷äÒ™LZŽôãê}BËB3Öì úü$¾à•0ž¾™ $±õ@‡¤6¸³ !©°J Bz~oZ<üûþ*ZI+!’Ä7ªi=’ßÌÎU˜]…̳×JdîÌÌ}9[➸˪Bënt¥|fÅ QuhÍ,%Ë¡-ªFk9U>0ÛÔ´4-MKÓÒ´êÓúük1QBxPP‹Ö=1¿Z®á³?Tq«Dññ/?Wøu5®­˜Aõ–•a%U§àåi_€Ä¾‘‹Áê4¿›VRRRzÀ¨ëò€ðøé w’ĸUÌ<$IoòºêZ¤–³ëu7ºšëûÓ«o½qŽä·Ü'O#)N?ÚÐÞwùÈ¥‘.…VçR. þÓìºGG™ôïƒÄ4Irã³&£9ã­6zïgK¹ÄpvΧBB $²n#‡\rMu¸Ä‰¯Ý6sðhŽn¯E‹x;2BR¹Â“Žzè6°0¥¤µ)¹Û&é`¥”ô3õD „÷¬•üæÎÝ™2Ÿß«G‹¥õ $¡--–RD 5h¥Ó³3Ñ¥å_‹cbíZ”Ž6SìÛg‹5êéJÐÌØé´ææV’©bþ纴ôœüs”´L²0c©MëËLåÈÄjZŠ_(keaš«MkV®µ¦iiZš–¦õhe+å¢Ð8-¦&­Ìì=1Z®«dëÓjbä_(—µ ²0ÅÖ •I- ‹•ÎËOõi™íÖ ¶C;ZÒݹ´Ú5h âÆf¡X¢P\ê©·8«K©Þ²(ÂÜž ›ù´´J‰Ê‰‹RuZEk=†V§[ÑØÑ"¢;ßËÒdѼ”¸B’Ý8m²p«^ªåa»â»Ø® Mmæ°˜<9Øò »ÎÎýwæ.É̯½¨oèçMÌ/’,Ä>bí6ˆ¥Ãü$Ç‹ýß~r|µÒLÃ2XÒŠsäŠ=²|£8¥Ö±¿}váÏ7>þ°M¹vÞY*·2˜M$fCó‡Ã7n½ÂØ`‹C¡ÕÛ͘”Æî³Ã3ž×/½ ¹ìÿûSð}úŸ‘SX’¡“£HŽÑó]{isö½?!™~ß;x ¶ƒ×Ïüý‡p¬üÈ_º“D"n!9{‘ð×†Þ ƒÉ® tó0 y÷ðNd˜--²‰U­)œ¿9<¼ˆá+ÈÄþNôöò±­E嘫¶Ð%­H­ýýÜz¢Åêõ¦Š•±Ð*Ñ¢eýHÆnU‹–¼yI[Õ£ÅjZ𖦥i=ÇZ6ÕhÉz ¥š³%ÝeMµÜÆ.ÇÁ©£°Ïõ¤º c;° ¤•GªÓÜjZ|ýZذ–ÁpÔlÆÆøÍ4œÊ*Þzê³EÍÎ.—´òà[oô÷¸À±.Ï+'Ý.ˆ»ïv9± «/ÃZkoú‘~QÈ׬C¦²ôÌ(¿Ï/b•a­Ô9¯Y‘{Ûhd*‹±½Íïó%_eX+}n2€\ÞVŠãWÒ}©!ZȰVu-†1(æ¯Ìlƒ´ž k-+‡µv;[:Åó¢6®aZpXk7­&ùËÈ8¨†µv×’±õŒMôÀ,†¦¥iiZš–ÚµÈa-5h!ÃZ»ÞÉgTA¤ErXk7-“üû{ëá†i âF±P¡¸*ìªÅ*kP½… k ©s“ðW}ÛZ`*k­z¿—wvÞ_Mgˆ¾D&½òæì4ø©VìÙ@Ê2†Ôù#ƒcȾuÁ€+ˆ¥öZwî#ûå-ž» 7è»:ÖÎZáž{œãü$²oŸÏ3êEvù›èÇ‚ÞË ­žj› âìÇÞ‡Õogx¢§û9Ö„lóG•n•©ÚEU‡¦U ¿û×Xx„æÕ%tEXtdate:create2017-06-06T01:31:16+01:00m…%tEXtdate:modify2017-06-06T01:31:16+01:00À=¿IEND®B`‚puzzles-20170606.272beef/icons/unruly-ibase4.png0000644000175000017500000000102413115373751020213 0ustar simonsimon‰PNG  IHDRàà?F5=gAMA† 1è–_bKGDÿ‡Ì¿tIMEá%=¹"HIDATxÚíÑÑ ƒ0DAJOiéÌi€p1{ÌûE–=ì6š·­~ `ïÓL0½‡_L¯nÇM_ÿ>®¼¿:x 8ÇN­€ßÏÞ˜_¼úWç/_p p.ŽZÏ?ð˜ßä‚«ªÎþ˜_¬ÿÐ\ÕB€€€€€€€€€€€€€€€€€€€€€€€€€€7æ7¹`õýú…ÿ̯Î.P- øPà\ ;µ~ p˜`zGÀ†¦˜`z€é¦˜^{àTÊöêeÕ3›%tEXtdate:create2017-06-06T01:31:37+01:00‰Ï‰Ê%tEXtdate:modify2017-06-06T01:31:37+01:00ø’1vIEND®B`‚puzzles-20170606.272beef/icons/unruly-ibase.png0000644000175000017500000000210113115373751020124 0ustar simonsimon‰PNG  IHDRàà•Oý¶bKGDÿÿÿ ½§“öIDATxœíÝÁm"I€Qfµ§îœB÷•˜œ‚cp މ+„`G€Ïsi éíñÞÙ].¡O”ªŸ_ŸŸŸ;¨úgë ÀOJš@I(i%M ¤ ”4’&PÒJš@I(iÿ^øw¯¯¯«îƒ§òññqá_z%M ¤]zÄÿçëëk}üñòò²ßï×[ÿp8¬½þûûûz뿽½­ýú¯½ÿkñJš@I(i%íêI<•ãñxó³óaùêOñæ_þàØÿ£¿>×>âˆ'M ¤ ”4’¶ô«ÎÍçGÆÏ盟Çqóõ7w‡ïâ·ÙwsÃ0|o¾þ¶ñ¤ ”4’&PÒJš@I(i%M ¤ ”4’&PÒJš@I(i%M ¤ ”´¥W>6Ÿ7Žã0 »þæîp'éî-±ö½Ÿþ½¢%ñ¤ ”4’&PÒÌe<ÔüΟ×ô×çÚGñ¤ ”4’&PÒžý§ÍïŒ{ö@wæw¶9âI(i%M ¤ ”4’&PÒJš@I(i%M ¤ ”4’&PÒJš@I(iÏ~åÃüθgtg~g›#ž4’&PÒJšù l`Åù kÏÜï÷ë­8Ö^íùþú\ûˆ#ž4’&PÒJš@I(i%M ¤ ”4’&PÒJš@I(i%M ¤ ”4’&PÒJš@I(i%M ¤ ”4’&PÒJš@I(i惲žºöúæwn»þµ8âI(i%M ¤Õ ñ|>ßüì8ŽwÜ ›¨º[ÐÙ0 ~'óÑ9âI(i%M ¤ ”4’&PÒJš@I(i%M ¤ ”4’&PÒJš@I(iõ+ã8ðõ.ØL=ÐÝnç^Ñ3sÄ“&PÒJš@I3” ¬8ôÑçk®=ôÑçwš W(i%M ¤-ýªóx<Þüì<Ï ÿûræÆÝá»ø›;›¦ét:-ßÀBæ–9âI(i%M ¤ ”4’&PÒJš@I(i%M ¤ ”4’&PÒJš@I(iK¯|ÌóaùêOñæ_þàØÿ£¿>×>âˆ'M ¤ ”4’¶ô«ÎÍçGÆÏ盟Çqóõ7w‡ïâ·ÙwsÃ0|o¾þ¶ñ¤ ”4’&PÒJš@I(i%M ¤ ”4’&PÒJš@I(i%M ¤ ”´¥W>6Ÿ7Žã0 »þæîp'éî-±ö½Ÿþ½¢%ñ¤ ”4’&PÒÌe<ÔüΟ×ô×çÚGñ¤ ”4’&PÒžý§ÍïŒ{ö@wæw¶9âI(i%M ¤ ”4’&PÒJš@I(i%M ¤ ”4’&PÒJš@I(iÏ~åÃüθgtg~g›#ž4’&PÒJšù l`Åù kÏÜï÷ë­8Ö^íùþú\ûˆ#ž4’&PÒJš@I(i%M ¤ ”4’&PÒJš@I(i%M ¤ ”4’&PÒJš@I(i%M ¤ ”4’&PÒJš@I(i惲žºöúæwn»þµ8âI(i%M ¤Õ ñ|>ßüì8ŽwÜ ›¨º[ÐÙ0 ~'óÑ9âI(i%M ¤ ”4’&PÒJš@I(i%M ¤ ”4’&PÒJš@I(iõ+ã8ðõ.ØL=ÐÝnç^Ñ3sÄ“&PÒJš@I3” ¬8ôÑçk®=ôÑçwš W(i%M ¤-ýªóx<Þüì<Ï ÿûræÆÝá»ø›;›¦ét:-ßÀBæ–9âI(i%M ¤ ”4’&PÒJš@I(i%M ¤ ”4’&PÒJš@I(iK¯|ÌóÈÅ[´€%6Ä ‰¾#3P$‰çgÈË!Žcc×rÀâ:Æc Š %åL×ëõ¨3°ñh4¼Ý¦¡p©^“7“›iŸ ìù¿ª«?[_÷õÍÛ7o¹].íøsäŸáW—‘2½¬›Ÿ™™™óª{ØŸ -­,q/‚ (M¯°¼ºxYŠ H)bk¥ðš·+KKK«½y`Æú“#IºÂTPÉc(†ã8e@1 C«ýA¢ù%íÏ=q!nkX4¾D€ç"#(œ£ ì¨~'ðA^ê?°<›~›Á— ¹èŠÁP Ä$d^ã:ÎPä“786<Œ(3”‘:žª…§‡1AÖh ‹>ØÈÑ­)ŒÒQ”/Ðj‹NëùdLŽ¥ò©±¿Ð;;:6:õÂ;àóùÚ››š®ý\f0Êð«ƒý`ˆ¾†š¯6&²ù%%ƒ‚™åÒ‰¤¼Ûø¹¶°°¡ % î½—“ñìŒF«Õžùò»tF†äÏKoƒÀF¤Y«k)#Á¦uÚ;òF€•FH ¡?¤€8L˜^ƒANn*¤‚Ô“ !uÚ»À2>2†¯È’†C Ærœøö_ã1  ôEwã,‚ô'¨ÒCà—íp4’XôËመn. à ` ¨¨Óý1"%'áyãg.æïÔðÈë7ü=5>ñfö Yi4VTÕÕÖÖž-£çßLŒO?/7&ý%%Z ÞPZnµÛlvk‡«¨kn}um•í7ƒ1G‡ Œ¹œ×ãÙ+Îía<Æâa€èÕ° „"»½Æëè‚cîvùà‚•C«·"ðè=ÆÖ¥ïÇÀñšæ¥A'èyNˆÜ­A»,^°0 gàÄ`Wæ9 àÊ ž^¨Ûv ›Í%16è/alåUí›®ÑTÓ›.}{Îúâ·gÏ~ÔÿðÁàà`g§ÅÒi½qË ZsË—`™èÐ3ÅÅÈ;R4²9mîîr:7—t‚K®§@è‹|q– Hãv/üp²KÈå›OÉ· ›çÀ²]RîVBÍ·~˜oÒ¸MùM' `Ó ý`*EQ\° ïe¥H89í€î2Vpøà¤J'ìùë«jjjªkŒ&Ü5326:ù¼ÃËv rɬdY«êÒþü}naiÑÿªÓåìv2ß㆔ۺ€·`pš-NÐÚÛòÀÜSÑÏúSÐ÷óÀ1£KqÒ £×îüÀVPqàæãSÊ>éžóÅÐc7s‰ÇmÍÝ|MÅIºàUàD[!À Áôx¸Pn0JI]FòÉ—ßÃìЖœˆoOZa=ç4ðßEïTòÍ #cµ+Ö¼­kæ¾¾>Ÿ»µèÆOß744\¼tvÚ[”ØÚ¦ÄŽdFýtˆIaI’"qY–ãòf:•J¥S°#Ç•˜kâròà[#»£(«(“Söce€Oþšùý„îu,̺>%tEXtdate:create2017-06-06T01:31:37+01:00‰Ï‰Ê%tEXtdate:modify2017-06-06T01:31:37+01:00ø’1vIEND®B`‚puzzles-20170606.272beef/icons/unruly-48d4.png0000644000175000017500000000116013115373751017530 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA† 1è–_bKGDÿ‡Ì¿tIMEá%=¹"¤IDATHÇV à óè97cV@~êÛÛÚjH‚è6øô¸L /ä3âè „!Q§ò÷bý®çƒ àÀÌ7†Œ/aßk„‚Ž%Ã! ÈÓñ‚œŸ&¨‚àAMïG800)pb`"óÙ=@Æ@í°–Ã††æshº%I'Ø H½MK6- ºö +0rˆcX—ˆ’b•ÜC–$å( –vdEL4«¹©JbÁ%IGÓ6‹½…PbM÷k‚UIwIì¶Lè½J¹=wÃÈê'€N¥´`†€&;0(K“”—Åzi³pc{ÁÚ·3H5›mÆÕ"P¨$ñ@GêþÑöò‘7Â55Ïër¤³çP³ÿ0 œ2¦ï @¦è t=ù¬Ÿ’Ö;Ó=漣Ê!PËcÖFkâXÎJqœÍ¢|‹9xó0»–ÂÀf’Šëƒ}á9ßNïØ——^ô•Þ­/*wuï zÜ[YÞ &É ëÅ )léðɱÂûÔ`+x•„Î@|÷Ð4qÛõßàT®åþ\*W!'EñB%tEXtdate:create2017-06-06T01:31:37+01:00‰Ï‰Ê%tEXtdate:modify2017-06-06T01:31:37+01:00ø’1vIEND®B`‚puzzles-20170606.272beef/icons/unruly-48d24.png0000644000175000017500000000320713115373751017616 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá%=¹"IDATHÇ•–[OG†ó?Ú«V›{¶ ؃ZEª’¶¡ŠT©j¤’ãÆëµ!‹$$$i¯©JzS)jS„ƒÂ¹@À°Þµwׇµ 6‚ð:³^!\4ïÅ7šY?;3ï|ßxOm¢NÁ°õ?•2{»ŠÞ+ÚË5ûŠrOöÔŽ d6ýëPþ•e(5ÎÏ;ÛPžä:k9`kÏÖTUYiªklj¼Ü¤4÷Ÿ =úõDzªÊ*Sýý§C™cYØ]7!8†#FO×Þ †ß”ã±¶ÃK«81 m H;*P…“$‰™ºÝ4ívu‚HÓÝË¡ÇF[Št$‰Ö,ø9–—ûÂy # ¸·ÛM[`t»VD>ÈÅ[´€%6Ä ‰¾#3P$‰çgÈË!Žcc×rÀâ:Æc Š %åL×ëõ¨3°ñh4¼Ý¦¡p©^“7“›iŸ ìù¿ª«?[_÷õÍÛ7o¹].íøsäŸáW—‘2½¬›Ÿ™™™óª{ØŸ -­,q/‚ (M¯°¼ºxYŠ H)bk¥ðš·+KKK«½y`Æú“#IºÂTPÉc(†ã8e@1 C«ýA¢ù%íÏ=q!nkX4¾D€ç"#(œ£ ì¨~'ðA^ê?°<›~›Á— ¹èŠÁP Ä$d^ã:ÎPä“786<Œ(3”‘:žª…§‡1AÖh ‹>ØÈÑ­)ŒÒQ”/Ðj‹NëùdLŽ¥ò©±¿Ð;;:6:õÂ;àóùÚ››š®ý\f0Êð«ƒý`ˆ¾†š¯6&²ù%%ƒ‚™åÒ‰¤¼Ûø¹¶°°¡ % î½—“ñìŒF«Õžùò»tF†äÏKoƒÀF¤Y«k)#Á¦uÚ;òF€•FH ¡?¤€8L˜^ƒANn*¤‚Ô“ !uÚ»À2>2†¯È’†C Ærœøö_ã1  ôEwã,‚ô'¨ÒCà—íp4’XôËመn. à ` ¨¨Óý1"%'áyãg.æïÔðÈë7ü=5>ñfö Yi4VTÕÕÖÖž-£çßLŒO?/7&ý%%Z ÞPZnµÛlvk‡«¨kn}um•í7ƒ1G‡ Œ¹œ×ãÙ+Îía<Æâa€èÕ° „"»½Æëè‚cîvùà‚•C«·"ðè=ÆÖ¥ïÇÀñšæ¥A'èyNˆÜ­A»,^°0 gàÄ`Wæ9 àÊ ž^¨Ûv ›Í%16è/alåUí›®ÑTÓ›.}{Îúâ·gÏ~ÔÿðÁàà`g§ÅÒi½qË ZsË—`™èÐ3ÅÅÈ;R4²9mîîr:7—t‚K®§@è‹|q– Hãv/üp²KÈå›OÉ· ›çÀ²]RîVBÍ·~˜oÒ¸MùM' `Ó ý`*EQ\° ïe¥H89í€î2Vpøà¤J'ìùë«jjjªkŒ&Ü5326:ù¼ÃËv rɬdY«êÒþü}naiÑÿªÓåìv2ß㆔ۺ€·`pš-NÐÚÛòÀÜSÑÏúSÐ÷óÀ1£KqÒ £×îüÀVPqàæãSÊ>éžóÅÐc7s‰ÇmÍÝ|MÅIºàUàD[!À Áôx¸Pn0JI]FòÉ—ßÃìЖœˆoOZa=ç4ðßEïTòÍ #cµ+Ö¼­kæ¾¾>Ÿ»µèÆOß744\¼tvÚ[”ØÚ¦ÄŽdFýtˆIaI’"qY–ãòf:•J¥S°#Ç•˜kâròà[#»£(«(“Söce€Oþšùý„îu,̺>%tEXtdate:create2017-06-06T01:31:37+01:00‰Ï‰Ê%tEXtdate:modify2017-06-06T01:31:37+01:00ø’1vIEND®B`‚puzzles-20170606.272beef/icons/unruly-32d8.png0000644000175000017500000000216113115373751017527 0ustar simonsimon‰PNG  IHDR V%(gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá%=¹"yIDAT8ËUTkoÛTÎ߀oc¢!Y—Ôö±ã¦+ƒeóRÄ  ±Ÿ€Ô‹‹ørì¤hŸÐ$ ¨R§Ð•‹¸iŒ"ƺµkÖÅvÒ8I¤Z3/‰ÓÿÀqª õ•ŽÎ«Wžó¼·ãsœ¾gƒ—æºîpÐC‘‘ã8>çy ™]·,ktLÃ4¬6 USC€~ë£Øõkï.r,;DzìâJ±ðCòrœanïoÕ NŒOÊ*„¼ UùߣFé5<Ú°«Ýu}ˆq,B¼)*²œVEÚ:(·µ@€ßjzç®á"ÀUjšÆË²,îwê½›c$ŽÿÑ®;߈Á~ï ›Yä86¡©ªüÓ_÷¥Çi ü¨—ôÓõ¹æý‰ñ;NPoÀÆ®ñ€aXñ‹Q2WG€oëfçFPþüqåp‡ž @à b£]ipÍ‚e¶ÿÔd0×*×Ñ4 (ê^½Ü(Œ -ëÙÆ˜ÿ«ù»[Žâ$…ûÿíÞ÷H¤[Y.=|ò³œÏåQ­sQŠÆf?×òpã¸OëŸk¬µªõ’uÜ>a_ Œ øÓ'­ãæ¥óÁóoµ{žÈCÓÚ~Z-Û\¦&AY»\Ùcp·úˆ¡xdÙ»åÃ.÷:‰S8bàºM3!ÆT¾Ù{¼sÿŸ§[Æ|hŠŽNE§±E}«´É€IbÆî£J¾CMÑog%IJð<Ÿº¿óx÷ë´,g/ÌÕ½n^»H„§$¨(‚ŠJ½k[GÔW1«A³<Àõ0‰M‹²,ñBi»¦7VEʘ0À¦µ¥üRZÈdøýNãxÍcÈ@E=Ä š¼ôɳ©•/—¿X.¬®-!5INHó§A†.„Ïå_Xí½4/ð 49Ù3O "Á\G·¶Ñ쩼¢@PþàSÔîfIFJyªbFUÔÓ,˜ÀIÄ€Í}s3#Šb2›ù””¼fUnoüúgqžcS³—¯^aY!à B&•DÎü¨›Eûà¨$æàgø'.’‚!*ƒ*e‘ï 4“U½¹É+RîÃP„ŒòPVÒòË,ÃÐ(v;½’tóýˆAE%õDBÍËbP»µ~wý+¤!ùq,ÎÌÌî ·0ï9;ÏqjºaT¼ÅmžÙâ:ºšÏÑv;ƒ¡;t½Í?ûŒ"Žóv&O&V³9%tEXtdate:create2017-06-06T01:31:37+01:00‰Ï‰Ê%tEXtdate:modify2017-06-06T01:31:37+01:00ø’1vIEND®B`‚puzzles-20170606.272beef/icons/unruly-32d4.png0000644000175000017500000000072313115373751017525 0ustar simonsimon‰PNG  IHDR V%(gAMA† 1è–_bKGDÿ‡Ì¿tIMEá%=¹"IDAT8ËmTà ËÓy?Ë$QQ;Ú]…ÆÀL2eóñ¬‘˜·mËC-2ˆÐo#XÛ+&BÁqÄ.Æ3ÅaÚ78€d¥(‚C…¸ô(Y XæŽdIÖo0PUHw8©¹|Û-†(h}ªÙ”¢WR=Ъb›µ¹B!•g¦˜Å¹€¹ÔL€çãíêòlF4 !V‰¬ôî÷Ù͈9ÆJñLS„‡ ‰?%æÜ ù0ð=0¥ïp‘7A¤®ƒìÑ·4¸ó>„üàšð°œæ›·ÀîCÿ1^¹MŒ£eh†šÔçýÉÐÅÝÙ"¹ºÿô´S>:ûPZ,™k9ýþÎàgÔê%tEXtdate:create2017-06-06T01:31:37+01:00‰Ï‰Ê%tEXtdate:modify2017-06-06T01:31:37+01:00ø’1vIEND®B`‚puzzles-20170606.272beef/icons/unruly-32d24.png0000644000175000017500000000216113115373751017605 0ustar simonsimon‰PNG  IHDR V%(gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá%=¹"yIDAT8ËUTkoÛTÎ߀oc¢!Y—Ôö±ã¦+ƒeóRÄ  ±Ÿ€Ô‹‹ørì¤hŸÐ$ ¨R§Ð•‹¸iŒ"ƺµkÖÅvÒ8I¤Z3/‰ÓÿÀqª õ•ŽÎ«Wžó¼·ãsœ¾gƒ—æºîpÐC‘‘ã8>çy ™]·,ktLÃ4¬6 USC€~ë£Øõkï.r,;DzìâJ±ðCòrœanïoÕ NŒOÊ*„¼ UùߣFé5<Ú°«Ýu}ˆq,B¼)*²œVEÚ:(·µ@€ßjzç®á"ÀUjšÆË²,îwê½›c$ŽÿÑ®;߈Á~ï ›Yä86¡©ªüÓ_÷¥Çi ü¨—ôÓõ¹æý‰ñ;NPoÀÆ®ñ€aXñ‹Q2WG€oëfçFPþüqåp‡ž @à b£]ipÍ‚e¶ÿÔd0×*×Ñ4 (ê^½Ü(Œ -ëÙÆ˜ÿ«ù»[Žâ$…ûÿíÞ÷H¤[Y.=|ò³œÏåQ­sQŠÆf?×òpã¸OëŸk¬µªõ’uÜ>a_ Œ øÓ'­ãæ¥óÁóoµ{žÈCÓÚ~Z-Û\¦&AY»\Ùcp·úˆ¡xdÙ»åÃ.÷:‰S8bàºM3!ÆT¾Ù{¼sÿŸ§[Æ|hŠŽNE§±E}«´É€IbÆî£J¾CMÑog%IJð<Ÿº¿óx÷ë´,g/ÌÕ½n^»H„§$¨(‚ŠJ½k[GÔW1«A³<Àõ0‰M‹²,ñBi»¦7VEʘ0À¦µ¥üRZÈdøýNãxÍcÈ@E=Ä š¼ôɳ©•/—¿X.¬®-!5INHó§A†.„Ïå_Xí½4/ð 49Ù3O "Á\G·¶Ñ쩼¢@PþàSÔîfIFJyªbFUÔÓ,˜ÀIÄ€Í}s3#Šb2›ù””¼fUnoüúgqžcS³—¯^aY!à B&•DÎü¨›Eûà¨$æàgø'.’‚!*ƒ*e‘ï 4“U½¹É+RîÃP„ŒòPVÒòË,ÃÐ(v;½’tóýˆAE%õDBÍËbP»µ~wý+¤!ùq,ÎÌÌî ·0ï9;ÏqjºaT¼ÅmžÙâ:ºšÏÑv;ƒ¡;t½Í?ûŒ"Žóv&O&V³9%tEXtdate:create2017-06-06T01:31:37+01:00‰Ï‰Ê%tEXtdate:modify2017-06-06T01:31:37+01:00ø’1vIEND®B`‚puzzles-20170606.272beef/icons/unruly-16d8.png0000644000175000017500000000102113115373751017523 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá%=¹"IDATÓcxzçö­7oÞ¼víÖ›×nØÑÑÁ0LßÄ`ŒÓÒÒNœ8¡§7cŒEQ\¸p¡‘©‚Âó¼Ûí®¬¬L(Bˆ1ž1c†ËåŠh¡o€9rcÿ!T±ùùùóæÍóù|}ž54MKOO?zôhŒbcçBEQ:::â¼Èh˜` AÄÀ.dÓÙH–e«Õª§fc¿ßoœB:'|!B ý~¿q õL½´¤,Ë>ŸÏï÷÷™B*«{ÇèaVg!t#I„t>ÝÆÚ0Á¢ò+~º<!Ô+Õ „ RH+LéI¨ÍHùÞÖ³û£zU8"´Ï{{·0#„p WÖTöÍÿgãl%0!s¬ìY²fèu¾ ÀB’¸²7zA!&ØÂXêuëþ¼®¾¥žçx9(ÿËä™7bž¤I èãÜÙß }În·³, …‹½èÔB•¨{+÷Öûêù4žY`,ÏÆŒ¢¦ƘaY–×®];iÒ¤—^zÉn·ëœÀnè¥P#šµýwí©9’fMc+iÀ@#†Öåý Œ1˲²,oÚ´é“O>±ÛíK—. ‡Ã&ó{ ]b‚­Œõ‚÷žÊ=ƒÇò›>t:V°‰»ßµ®¢(›7oþì³ÏÆŽ{àÀiÓ¦\…š‰)$€@5¢í®Ü}µýêíÃn_9q%¦‹"ýoóæÍŸ~úéèÑ£÷ìÙ3~üø@ 0Èøz(ÄÛYû]ü¯£µGY+»þÎõN«SÖdÓvAz¼'ËòK/½tøðá¼¼¼ýû÷?> ÜE˜ ($„XYëé¶Óoüý  ‚§Æ=5cøŒv¹ýš" À+šbž‘Â0Œ¦i6l ãçÞ½{'L˜ …ú|Þdr$ØT ˆÂZø¿¿q¥íʽcîÝôƒM"+BFDVtÙ]ÁÆ 4ÃÒ”îÜ×­[wôèѼ¼¼½{÷Fúß@W­¿˜Â€(¹RxÐ*µ>WúœŠUÑiÏiÀ€ÀÉÆ“K¿\Z0¬à‰±O˜¤/BÓÒÒápØï÷tuú‰·öô,PÙXY©U@€€Û뮿R\–¿ ˜`ÓL`¶nÝ*¡C‡~ö³ŸíÙ³§   ÒßÖ^…‡[ ‹XDçNZ¥Ö°ˆQ´‹9¶3ð:ž5M{ñÅB\½zõk¯½VPP@—£ƒo9“€BhöÞ½W%êµî™Mÿ»©¢©0kø¬çï|ž…¬J¯o(‹¡_þò—¡÷ߟöÅ»îºË IÄœÐÕ oÏ¸ŽŸ”B±6Ö40Èà3î̺³-܆6Ãr&Rgzж~ýzŒñÁƒ×­[÷ꫯNŸ>}ðQ¨k&i’¤J’ÖùO•¬œÕbµ0V†gø T°bþ((‹„_üâO=õTCCÃÓO?]\\l±X‹º,vaš²oÖ>Ê!DÒ$%Ç›(¹ Þ@ ì_¿žçùcÇŽýùÏ^¼xñ?"…ÝA!&YÀÄEƼqãÆ¢¢¢P(ä÷ûÙߌ½§?ÐÞÞNgG‡Ã1ø{!ÆØˆEþ¼WjêmùB"u¾Ñs†a&"wâ¦9^DW²o¸ÑÏ»PH 4ôhÈ—NZZš :ËS“ºA AEQ§N!„¢(¦¥¥´Rw…AHŠb»»æ^§ð»Ýî'N1ªQ…ÖÔÔÜqÇ ‰AÒÒR#ª¤5÷x<:}´ !åååµµµ}s !ÔÕ/~3éÉ{MM ÀÈKñµ=zt´D‰l¢ˆ—/_Žqs££M|ÁôX+úýb&''G„„žÎW®\ñûýI94q:š¦ÝèiT›ííí---ÆÅBìv{vvvÂ6†ÃáÆÆFƒžÇ s˜ÌÍÍî‹0:8 BÈó|tû©Ï9õŠ£„Åb‰ö«'„Ȳ¬3¦"YKDEQv,Úe9ŽKŠDMÓô8hwWlŸÑ]±±s¡$IÑÿe¦¢¢bܸqt-н´L(ºtéÒ„ ¢{°Î˲œmê !TUUO,K²$‚nŠM®D'Dcœžž>wîÜ{ï½wÆ áp8¦/Rþ „ëׯ¯««ûâ‹/®^½š¬ ¡t"ÞêˆFOŠ÷îÝKë"]˜%B¶mÛöÙgŸñÊÍÍݼyó!Cô¸Ä§\$ PÓ´qãÆ7®´´ô믿ÆÏœ9“ò!¤ü1b÷îÝwÝuWÂ8´úñ(!9”ů¿þº¤¤c<{ölÐÙÿrrrvïÞ=}úôÁíŸbf@=/4M³ÛíÇ_½zµßïöÙgƒÁà‡~8lذ×_}Ú´i@`ßBÐE!èŒå<~üøóÏ? …0ÆN§sß¾})þz‡>„P0¼ï¾ûöìÙcµZN'íÁ`0ÅßÀBo/¤ „Øl¶ââb«Õ:sæÌAéß~Ë!ö€ tßô¼c?˜[¿ÇŸþpç„ÏѨ :7KIÙÅêŒOÖ£XýAWÅvÉxÑÚÚZRR"Šb|aô¸6ÎøIí S@‹‹‹ãLëoX(r¹\¡P(NÆ «ÕZVVæv»­V«AÒÍñüùóã°1/”••Ùl6ƒét6gΜ!C†DÎ2Ù˜¯³²².\h0ªßn·—––êqq >Ÿ<ð€ñt ÕÕÕ %2 ãóù FŒa<]—_~™ÐnÌ0Œßïw¹\³gÏ6®Ø¯¾ú* :4òylÆ :2gèoõ;ÝÖ"?×3¬EŒb …v±ÉÝ -úÛi¦AÅvÎêÇl7ú3^$~ #Dž¦`S„Tv¯|ʪÐ0Á,bÝ·‚JùPëP ætÚKQ hé\ú‰ÆËO,É!Ä ¬àß>ôÛ‚a’&™Íã¤(Œ&X@ÂÕÐÕßî ©!V`©Ã¬™·¿©ƒéX0ˆyûìÛ§¯žf9VÅjg ‰y‘¢ð:0Á"+ž¼|òƒê žû‹Xó¯ïR^‹Øf©yWå.,á¥ß[úèmªØ,wq¢ðhz²·N¿uöÊÙ‘™# ' Œ00ßò%)  «P>ý‹ú/~þ÷€ÿ1ñ?Ƥé;"üiXS±®<Õ7) ¯­Bk}µ¯U¾–Ã?ÿ“å– Œà´8#e‚Ãiqrˆ3áÚ&µ©˜à4>í㋟k>'Šb®˜ûÑùõz ð•û«:_ÝĬ‰9Ö…˜+6Eá5@²&o?µýÚ2pßÿîãXn×Ü]ß»í{a9“y`‘¢ð!@´ÀH'»v.J°,Œƒ¼SQ@ L:}óÌÍ<ÃÓf±n¿ûÓo@ &ÏLz&ß‘ŸŸžÆá˜°õGŠÂkIÊòÒóÆeŒ£ŸBx†¯ôT¾uæ-2 VîwÝ_0´À§øT¬šj") ) €ÑTU¥ìB0À!%„%L  ©! K˜Š î'¤(¼Žè˜, ky޼ß>ô[ &x\Æ8½ë¥Ÿ¢°g@l¬mVö,0¨Mbò펅7&¸Cî ›m (LŠ‹G¯~ž—@ú=¾3ÑÅÄX¨§X¯ÔbP±Ý?¥ažçyž7âh%‚þ@Q„ñØDZgýÎH´¼‰ —/X–A–e#Šåy¾»‹^¬¢½^¯Ûí6¦D£/<ÍfÓ£…P(ÔÐÐ`D•Ô ñÊ•+züQiÄÝ•+WƳå‡B!Oðx<õõõÆÛýÚ>6Ò0UU‡Ýn§÷éB–eNgÂTB—ËU]]mðÚ&J̨Q£â_×F³zŒ5ª®®Îãñ”ˆ1v¹\ u¥(ŠÓélll¬ªª2(‘æØp8ÑY!bò- -j$= ý#ëé‚ Ð ãdÔQ΃=¦lô$ìX´ËF’~i&}oÂápÂ’ ÃDr)”H3/ÄËxú& ;tz‡B¡„õ¦Iï†Q%Î@¤G" zM¨wýH80R¦“¨Ø‰lü¯oâH¤ü‰¢øöÛoþùçû÷ïÏÉÉ‘$É`8ÜÍOïܯͻݡc…Õj}ÿý÷wíÚUUUµzõêË—/gd0)…þ>øàƒ¢¢"Q¿ÿýïWTT<ÿüó ‹%Åbf¤òg±X<¸}ûv–e7nÜøæ›oÞsÏ=ååå§40#…‹ÅrèС-[¶pWTT´téR§Ó¹k×®yóæ•——¯^½Úív§ú"…é(Ä[,–>úèå—_¶X,/¿üòã?.I’$I;vì¸÷Þ{¿ýöÛ5kÖ444tOÎùsQH>ü«_ýŠã¸­[·>þøãt9Ž’eÙápüú׿ž3gNEEźuëÂáp*Yƒ¹($„X,–³gÏvìØ±téRÑOWätK—‘‘±sçΙ3gþõ¯¿MüAì¾0‰³‹ÎÍP´Dšlsذa7n\¼x1½4+¦J¡P(##ã7¿ùÍ®]»EÑ4-R@§Ää^­­çêW‰¦;`£‡¹š ¶ÇÊÐxe›Íh¨;-ó~ÀFÓT|óÍ7¥ôMè<ÏœN s𛥮®nèСÙÙÙÆMeeewÞygü2ǵ´´¨ª:uêTãŠ=uê”×ëu8‘fÆÎ…‡ÃårÌ­‘––V[[«§0!ÄjµŽ1¸É Ç~D‡µììlš´ÄˆP¡ÕjÕ9édee9’Ž7}G“–8Ž˜Ïc)Ô4M–eƒÆåp8¬?ù5Æ8a"vº,zôdÑ™Ít.š(úÖFŠ^å­RU5÷¨XHL,q ¤Šê~&Õƒ{ìDŸÖÛŸ'X€" ÁÂX¨3&8 v1ÜD/Lô›@Wþ53æ·Ñ¹oâ«%6k bYÈ"ˆ(m=60ú Ý?7» žþÂýÅöòíVÖ*©’Ëîzûž·Yh¢šÓ« X–U¥·³ÝÙ¶³eÍegÚΜk;'cYÖäQi£Þû®F4nã&RDª„G|C a{ùö†ö„V1Ö0&@@;å@×ñÚí8•••N§3??_’¤„,@@2–÷Tí9ùÝI1Ñ ‰J î]£L}´AAíüvgƒ·±²p1È ÌE@Só;vìÇ?þñ²eËNž<©3]„P#š¬ÊH@Sr§Œ:– 8™ÁB¡ŠUï8\{øÈÅ#–Œiçiª€érˆ0 ãõz ׬YÓÞÞ¾~ýú?ýéO Y„B8ÄN.¿š&¥A¤õÍÓo^j¹”?4¿pR¡Éó‡BE),,,,,lkkûùÏa1Þ¯ñ)>ŸìSp⋟n¨«n{Ï YñÈ¥#ŸÖ|ÊX™µw®jª`Åœ]‚ž~)вjÕªU«Vutt¬]»¶¸¸8áÕŒ dÈ Ø÷ ÞtÒáå¼÷üîÊ݃§oú~×ý VXÄFFº—2Õ¢t²(ËòÊ•+W­Zåõz_xá…?þñôH½ÿLÓ¦£lçìÿyö?¯´]¹}èíå=Öjj•ZƒjR† ö„=^ÅkÂh1z^£ªê³Ï>»`ÁdzeË–¶¶¶dݵ×#L·/¤‰–p `Áw¾ï<ú †5&ðp5tõžÃ÷Œ2þÀœ9bެ%óî<㕇rwðàÁcÇŽ‰¢¸jÕªŒŒŒºººþ 0&8z9C z‚âLG!ÖÂ@ ¹–‹W@0×Ú +2ØTci´ãkQQ‘ÕjݲeË’%K¨¹íF'y dXÈòˆN„Â!ÐHb/=ÓQˆ ’4i^μL>S`zÌAî\û¹ª–*€€È‰óFÏe%2¢F46ŠþÞ{ï½W^y…eÙ¢¢¢%K–øýþ8^Àf©Ù§øDFl“Úè ©bõ;ßwcA®5—Elüý†) ªÁec—=1ö ú &XäÄwξSÕT…4D²eÚñzh†Í>„P„÷Þ{oûöí‚ lÛ¶íÑGs ­3‹Ø·N¿õií§™|¦_ñ³< !ô„=O?IOà>¹ÿ§Å¿/šŽBŠè9BÈ@FÓ4˜Ç £Ðs} ̲œ¡Ç܇Ú¶m›(Š[¶lyôÑG‡€nó·…šCŠUQ‰™š|M´á×rlÄ}EMJa¤cQCš‚•;œw,ûÁ22„ ‘Iθš¦effî߿ǎ¢(nݺuÉ’%´ÿÅñ´€Hóo›ïLsЬÝÕèÐ!´²Ö„ o“RÝ‚•Ù9³õ DÚ'ìèzEÕBY–'Mš´sçN—ËE¯"Óco¢¦Áóo?ù§ŸÜˆéÖpë-Oa¤µ%à•½´çq¨·Y½BH’¤¹sçò … sª›3gÎùóçÿò—¿TVVR9Ž«®®^³fÍùóç~øá­[·Z­Ö…‚.›Š¡iÏó~¿ݺuÇŸ=eee4õ‘†±,ëñx,XÏoŒAªªªTUÍÊÊ28‹BΜ9³hÑ¢øeA¨­­­¬¬3fLœlzÄñ<_UUeµZsss#ué…ªªº\®yóæLÌ––uÓHa›Í6{öl#SUS}}}UU•žò©S§Ž9ÒˆBés¨ý(þCè ɘ1cæÎk\±¡P(æÍëb© c©Ïç3˜´‡-‹Îò~¿ß …²,ƒAývƒ`0èóùº6ôÂ-ê  €ÄqŒè•™,'T¬ªª;Ã01K*«û4׃ï êDŸušÐ¾Ø½¼A #Ö™ñ"ÒÆ˜ò dF…,å/ :äŽcz›Õ#¾b©]žB3 ãóùºÏ=þö–qº9¸ºZÓQsÁ{¡)Ô!ô+þ™Ãg>4ê¡ ì×k›èZäã?þÛßþf·Û;::æÏŸ?wî\=C}ŠB:ƒëõëþgÝÙö³áp¨€E¬TÁ°$o‰_ñ÷…Ô¤´´tÓ¦MÁ`çyš³sÁ‚¡P(áŽ+E!C±_ñ×zjÃj8Ö!k2&X…*Ã1ý²Aû_ss󫯾JùcYV–e–euÔ) èŒ^pð޽ý_sl9“2'mûÛ¶Š«€è 3ºœÞ·o_EEEvv¶Ïç£w¯è_(¥( ó"Ø\1wÓ6iD ©¡›ã0N÷T%%%ï¼óà§?ýéçŸþí·ßöê!)óÂu¨Dm‘Z¼²7ŒÃ7!Þ c̲lkk+Mo¼páÂþð‡ñ¯?ê) ¯È"– ¨¿£¦è&J„TUU >|íÚµ¡>8*¦(Bl6[qqñ‡~X¹re^^Í%O д zMÍ…zÚÙÔÔôúë¯+Šò£ýè™gžQU5ú’PQ‡ F“»Æ_š¦(ì‚kç[Ýò Ñÿ$¥Òóz¨[VVöÐCÑɦü»ßýîøñã‹-zòÉ'ã› Rv„»’¤ÿ’.Žz²WWWwÿª±±ñòåË'N¤§) õ‚†Ôbr=zˆ¢M"(‰4t,ÍÏÏÎ󨫫£·&deeeffº\®„–…Яùdß+¯´J­,dk:j¥¥ÿþõ¿·Ëí“2'½øý“rXJ-B™™™ˆ˜&¨MjÅŠÔÔúðÃ?óÌ3@ÇÑ) ¯(aé›Úoš|M…„!tµîns_n½Œe,™0ÉJBÍÔ[w䪔Èr&--môèÑííí m8) ¯ƒ‡|Þ°<Ñ.òˆ×ˆFÙ‚rˆó)¾‘CF&×oŠš9#Ó^èr¹$I ƒ‡C’$zƒqüç¤( 3ù„ƒwü~þïiF”îT¢Ô€Á¸øÄØÿBï¾û.µb†Ãa=f ¢04ÁküÑE¿š )" úÍæ) »à&” ½w–èÂèëäúŒqüœÔ=þÄ ãª?ãîD²®Ñ_É>‹Ã÷èÆ¨Íq\zz: Ïî¹ÔÑŠçy¬ „f?N¨žçEQÔóMiEÑn·¼v‹ºÃè¯!uìë³S’¦iéééÝï¾½N!対¾þèÑ£z<”ã€ã8·Û=uêÔ„ÄÐ_}õ•A(zÓ€žWèO:åp8ŒøæÒ®Lsu%¸pŠŽãªªªB¡qÅÖ××ßvÛmѯ;äÓE­Çã1¬K7=™™™ ¯K†¶··ÓÛ&H¤p8´/Æ— ½^¯qq´7gdd$”¨(J[[›ñø!ú6deeE_¾S¡ße#¡°ˆWd|°,›¬À6Ö„Ë&gGMB ‹õ«bcçBƒ÷ÁÅÔ[O1ƒcK$R ÎÍÚ¯Šøl›8˜š™²ÚßòøVÞir¦£v%tEXtdate:create2017-06-06T01:31:16+01:00m…%tEXtdate:modify2017-06-06T01:31:16+01:00À=¿IEND®B`‚puzzles-20170606.272beef/icons/unequal-ibase4.png0000644000175000017500000000077413115373750020341 0ustar simonsimon‰PNG  IHDRhhï2¨’gAMA† 1è–_PLTEÀÀÀ€€€€ÿÿÿ¶ù0RbKGDhÙQ oFFshh“©ÚVtIMEá$J¾"´ vpAgÐІÔd9ìIDATXÃíÖíƒ `Ph™@.ûïV ô Š˜Ðžö#ïO!8_“q‘½ñý<‡ÜÿO$'k/Tä )è@\Fã„D t°ïKQQ,EE±…RdJÑ‘ƒ*u½SÏê•û4Ù+å1X›Ž,áìáQqÊѨüž–[ÑZ=FXÔõ«áp8ï ÷{/£J_÷@óª´h ©dhÝ×Ý‘„mTùõëôt†ŽŒSd$a¦#ßБq‚ŒüÓÑQh):PŒ;­úº¸þn0àtUº­4Yc!ŽC9y±üâ~Ã9/7R„2ŠÜ´Ž%tEXtdate:create2017-06-06T01:31:36+01:00/¸‚~%tEXtdate:modify2017-06-06T01:31:36+01:00^å:ÂIEND®B`‚puzzles-20170606.272beef/icons/unequal-ibase.png0000644000175000017500000000145213115373750020247 0ustar simonsimon‰PNG  IHDRhh*ÂE“gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<´PLTEÕÕÕ………€€€ÊÐÊ”»”g©g:—: „ ÈÐÈ–¼–   £££ žžž—¼—ŒLžLy°y³ªÄªsss¢¢¢ËÑË À ²ÒÓÒ­Å­¾¾¾ËËËVVV›››ÉÉÉRRRPPP´´´———ÈÈÈÇÇÇMMMXXX’’’ÌÌ̆††~~~kkkqqqÿÿÿiP6ebKGD;9ôl oFFshh“©ÚVtIMEá$J¾"´ vpAgÐІÔd9IIDAThÞíØÙRÂ@…á!n‘‚¸#DÄ}}ÿ3± L  'a¦]rþ+jèª.H+ųVÅ[XeÙù4oñçð–'T heum}ÃÛt UýqÖ µPªo¡±=?¿³»·`÷ÖéRvþÐòw¤In!Mr M%×P*9‡&’{H5k8’€Z ™+;Ρ‰ãJm¾EÑqUã'v ©£ÍŸúZm+æ8…tÇ) æ™/~ë–™'Dh>±ÇÆcì7Ä}¡Ÿ„Ìöo3aqg¹ ³µXö༨Ùþ-s0:ù¡¤ïçõƒ‹!Д€.«kèÞ @wº%ÝJzžž% ^êJz…^¿ÔÙþ-=x}õž0£VÈl[5{PàÇðÿ ³·ÿÒB¥‡¸¯cŒ1V†>ä)'"œÄ%tEXtdate:create2017-06-06T01:31:16+01:00m…%tEXtdate:modify2017-06-06T01:31:16+01:00À=¿IEND®B`‚puzzles-20170606.272beef/icons/unequal-base.png0000644000175000017500000000471113115373724020100 0ustar simonsimon‰PNG  IHDRÐÐùÆx#bKGDÿÿÿ ½§“ ~IDATxœíÝÁkgÇñ×NFöˆªx»˜8“š¦Ð"ÒMÔªŒ”[¡&n!ö¥&‡8²š€1.$˜±rDrðà€ z³]¼‹i:‘Ób|,¦%Ë«îGÕØž¬³‡iíF¤wžÑ¼ïïsrHó¾ÕkyFó4­®®2*Í^/ä‚à€‚RH!8 …à€‚RH!8 …à€‚RH!8 …à€‚R«}ÀÇ Ãpc)Œ1EQz{{±×Sup†aœ;w®ÚG9ôàÁƒj‚õØk´õ`KRH!8 …à€TÕoª¢åµ ß^xùò¥õùžùCê!W ÌÅW¸â‹â íFim.7ñãÄÓÂS÷ž¿hšvâĉp8ǽ^‹?¸ÜÒúÒôOÓŒ±À€K‡ð\.—K$»»»ªªÞ¾}Ûëåøƒ+ÁŒÂÍÇ7ͯ¯„¯¸qÏår¹]×UUM§Ó'OžôzEþàJpc?Œ­×c½oõÆßp¯Am5ãÜâ¿gÖfcÁŽ‘ã#ÜŸßs¨­œƒÛÚÝ}<Êkjjºõá­P Ä÷ù=‡ÚêÄ9¸Ô“Ô†¾Áë»ÿTÇ)¾Oî9ÔV?žÁÍýsnöçYÆXçkCïq|æF€Ú¸àÜøãŒ±æ¦æÔG)õ Êñ™Áµk×t]WeppµÕŒç©­Â‹clïåÞùùóûý3³gc}o÷~0ÊñÐîÞ½;00P,3™L8FsµÁÉ{§"‘Ƚ{÷‚Á ®ëÉdòÑ£G^¯È—\Ð\ýxn©ÃÞþÏöÿ}ss{3½š¶þóúû×CJèèëG9—’Ùœ¹·&“I¼{¨ÏàξuöÕo®=_+ ®çHß/OBsõÀ–Z ì­5Cp5Bsµq÷Š_ÆXW¨kµOÌQ‘H$“É\ºtI×õ‘‘‘……¯Wä®'¶h4úäɯWá'ØR‚RH!8 …à€TÕïRE©áž9Ο¼†‡`=öi¨õ4a^*P– ¤â\,Ó4Íá_Ö4-‹ñ:4ø·àòùüåË—4§iZ"‘Èçó¼ >Â-8EQ¶··‰„}sfmº®·´´ð:4ø·à¦¦¦Ìku‰Ä~×ê˜w1?i—Ífy|„[p¯Ãç:ñ}—jÓjç_‹”mµÅ•3 Ö;ƒÖÖÖd2™Éd¬ŸÛ¢Ñ(÷øujËjNQÃ0P˜Ü:ÓF³Ù¬ªª¨ J¹xjËl®­­ µW‹)œ¼R˜—Šõ®óRí`=ö0/‚RH!8 …›ÙxIÂy²x…óŒœódœgd˜'û*ç æÉ–…à< Ã<Ùý 8?OÖ‚£&ü}Úù\WàN¢àÌY%Ïž=s8×Ü Kp¥“qœÌu—HœU›ªªW¯^UUU×u¼ÎyBüàJ§§Óé‹/Þ¿? š¯sûÍ—\ÙÉ™g ƒ{DÎfN+šóаÁUœ Œæï/ïq_䫤NÔù¤~¼†TüàÄžOê»æN†ù¤þjNðà$™Oê£æDNªù¤~iNäàd›O‰D‰„¢(º® 5èÿ`"Ÿim>i.—Ëd2†a¨ªzçί—SžÈ¯pR©ø9ÜàDà—Ú˜Ø[ª$óIë©­ø¢¸úï?>¶·¶µVúGË¿.ͯ#h>Àeµ"'Ã|Ò:_Û~)üòÅÂeÿhðïƒÖ×ÚgZ°9XÏ:-ØR}ÌG;©Áù•kcbo©e 3ŸthhH×õ@ àðŽe½Ûö.ñ¿†tÁ caaÁë%Ô[*Bp@ Á)¤Â¼Ô O^ÃC°¸&– ¤â\,s~ÏMÓb±¯Cƒp .ŸÏ;œÏgÎâÈçó¼ >Â-8‡sHK'¿ð:4ø·à¦¦¦ÌϨÙÜ[¥t’d6›åuhðnÁUü\¤O¯ß¾x¾Kµiµ‰ó¯EÊ6‡ÚÀâÊ™ëAkkk2™Ìd2ÖÏm5_› bpëÔ–Õœ¢(ægÁQ0÷Î4XsHQ”rñÔ–Ù\[[j ®R8y¤0/ë!]æ¥ÚÁzìa^*4:¤Bp@ 7³!E?Ÿ´*š¦]¸ð¿ódççâyÃFGŠ~>©sÅbñÆ ×çÉbK…?LLL<}êúiµººº\½^ဂRH!8 …à€‚R˜—ZáÉkxÖcwÀRØR‚RH!8 …à€‚RH!8 …à€‚RH!8 …à€‚RHý²Y¿Y@{HGIEND®B`‚puzzles-20170606.272beef/icons/unequal-48d8.png0000644000175000017500000000227313115373750017655 0ustar simonsimon‰PNG  IHDR00`Ü µgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<üPLTEÕÕÕÖÖÖØØØÎÎÎÉÉÉÊÊÊÎÑÎÐÐПŸŸ±±±¯¯¯   áááÝÝÝáÚáÒÔÒÙ×ÙÇÏdžµ†‹ „ ~kªk‚‚‚åååÜÛÜR R''(Ž(ug©gäÛäÚÛÚ†††ÏÓÏa¦aråÜåéééZ¤Zf¨f222&&&ñáñ[¤[n«nÇÇÇKžKyޏŽÁÁÁY¢Y ƒ §§§```ËÑË––– jjjIIILLLggg]]]ÿÿÿnnnòòòuuu___...ŠŠŠíßíqqqÜØÜ))¾¾¾¤¤¤ëëë†ð*abKGDE޳¨WtIMEá$J¾"´¼IDATHÇÕUm{Ò0M“ÂmCÓàœdÔ ÊØÔMÙ‹›àØ‹:'¾Nÿÿñ¦IÛ¤²=û ¼´´œôæÜ›žùÛÕwÔðs)Xèóð†‰°6‹y Š9ñäúdzxË‚<æú‰ˆÆ r û¡IÒ G B_ \à : @y((¸l“Æ]ŒÆm{ù@"ÆÚf„\àc+WuRI¤¨¸—@9i©µ. ƒ 2{¼¾Ñë$M^•$œçAð0ªa—˜‰ž žŽ:[™ù- 8@ºCµ6Ɖtgéöhgà'ø=P¬0ãË'’˜Ð€Á—16H Ï_˜H·{ˆt¼°éF°ÙÜÝe&¡½÷rôjo2§á÷0IŸ—teý`cÿ0•^Ià1°£×»Œæ«$ÓãÞÉêÉA î( ÞLñÍÙÅ€fs6kBmY!×FΣgJÆÔ¬^ÁÜ&²’F)2aNYžšã¹)õÄGX„šæ¥ÄQÆ´Àµ°M ÞbÅòß¹–àõ=zîïëÿ>î×t5ÀBv˲.Å)kÅ¥ûè7}q7GnX-›áHÃóŸ7u_rü§J(|hÂÜnQã?Ú UòNÞžªyRáfÀøÏÎÀѽÝëtr¦Ô4"ü’lÿqKšàüìB]b‚ÃÀ3}E;éû%i†î;ÍÕTÔ|IZÿI¥WîÓ£Ó÷.ÕÕG¨ûR2dH}† º×êÓõB->ûMkh±þ#œU‚îWõMá±ð´ÿ|×þócÿ0“βbI7ÑÏøB]Ü@ÍŒ!=>@ÿé¡ÿˆØmš&ô×\]á’@ÛÏÌ1Ý'ÀrÝÕ}I›ùí08ŽX÷%J3c?Zdƒ «?ß—rY[)£/µ ¼ô«\öËý‡Ý×jöC—ãÔûŸúwñÇN9Xø¿¥(%tEXtdate:create2017-06-06T01:31:36+01:00/¸‚~%tEXtdate:modify2017-06-06T01:31:36+01:00^å:ÂIEND®B`‚puzzles-20170606.272beef/icons/unequal-48d4.png0000644000175000017500000000100713115373750017643 0ustar simonsimon‰PNG  IHDR00¥,ä´gAMA† 1è–_PLTEÀÀÀ€€€ÿÿÿ€ÿ€€ºd#çbKGDf |dtIMEá$J¾"´IDAT8ËÕRKŽÃ µ!°'tÏÜ }"¡ÙÏzÿ3 ¿ðqh÷µ`ìgž?€Äa… ¢ r\ÄE¨nBNƒ*ÚˆŽ=bu÷Ñ–¯bØdŸ- ÊìIÓ"à¡*‚2f¯ˆ‘Õ’ Û…¼·)ÔÝ V˜>ÇucÊ'M»˜ÈàžNæÛ¤žQS¢ˆ—jÛi?Bº¡_ôÆ@ZH|´á">RB¢ap‘²ïa–iR])$ U§á‰r3‡¹X<ún½³©@×Ç<¬7Ûz6DÊг‚õOûx$DBwô¿þ8ݰ£û탔PxsÜXgº¦Õõ™›“¶éÎ%®Wõ¢¤oª;C„~¥iÍ9¶2êðRþ¥òÏ''Â%tEXtdate:create2017-06-06T01:31:36+01:00/¸‚~%tEXtdate:modify2017-06-06T01:31:36+01:00^å:ÂIEND®B`‚puzzles-20170606.272beef/icons/unequal-48d24.png0000644000175000017500000000307213115373750017731 0ustar simonsimon‰PNG  IHDR00Ø`nÐgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEá$J¾"´>IDATXÃíXÍkIUÕŸ™$ KñcdO} dÀƒdÀ\<¹èEÈIEÅðà¿ ’!‡$°‡lVDP/<™ˆdw‘aÇ´éLOOOÕÛC­í|ôô|Eôwúõ¯~ェzï7äõë×ð3ýÑjM©bG)!¤Å/Qe8U„<Ï ‚€‚ˆ1ÒAUU]×#ºÁQ˜<Ï{õêU2™lwMòùüÉ“'MÓ¬ôÁA@ @âq”lÉdrll¬X,R··„†alllAÐÓÓƒˆa"q J(#L> ’V NmÉ!Bˆb±èû~SBá/c ‚ ?©ÁA@ƒŸƒÏ¹Nué2[!Nå†ûFHÖ›RÚtKJùà8çüÈ‘#žçÕ〡K.e·²Žïì•öfFf®Ÿºž÷óŒ°Ð§r«u~ì…¦innnÚ¶½¼¼<00 #ƒA@¤@sù\BI¤zRàA Df(:ÚŽ QJ]ט˜˜›››]XXH&“œó0\„ZäÅ[¿Þz’ybÿb¹“bLi¾rc#„¸®{áÂEQnܸÁ9¿té’ëº5n*UË¢ì ¾žµïHHžÛééiBÈÍ›7ñìÙ³ˆX¹- D |<§®ZG¸ªçy“““G][[ãœ×œ D   ä÷]B8ç†aìïïOMMY–•Ífåý[¹µ Ű4K£ èT·t+<ùõÖUÉ8ç‰DÂqœsçÎÀƒ,ËúôéSÈF 0såíÊóç[»[ Ãã¿Ý{›JO O})}9HBˆ¨ëú‡Ο?ošæÊÊJoo¯çy•—*ªTÍý›[ÿkÝL˜}‰¾÷{ïßì¼Iõ¤4¦E®+BŠ¢loo§Óé™™™þþþB¡ iUË0ÂÜÀ½vêÚ•±+ˆ({!D%ªã; X½ªu€BÑ´uHŸB¡`ÛöÄÄD>Ÿ÷Dýö}º¡ñØ3dÝÕÏê0CáBpªKGSÎÍ’»EVö÷—‰É1¨¥\… ±`ø¤išð;q×,%uHn×r­—õäDŠ- Ã…ŠyÙ¶íck;"h±±LÂûš´éTÃðȵ3/hVðà$72ŸÑ.F¾%tEXtdate:create2017-06-06T01:31:36+01:00/¸‚~%tEXtdate:modify2017-06-06T01:31:36+01:00^å:ÂIEND®B`‚puzzles-20170606.272beef/icons/unequal-32d4.png0000644000175000017500000000072313115373750017640 0ustar simonsimon‰PNG  IHDR TgÇgAMA† 1è–_PLTEÀÀÀÿÿÿ€€€€ÿ€€bqbKGDÿ-ÞtIMEá$J¾"´çIDAT(ÏmQ[nÃ0 ìŸr€ ò¿zh‹Ü èÇî†éáÞP°•˜")F¤)¿ ÑB¢ð"«s«7¿ßU0˜}qLWç}tÂØq`]¡¹ûGc°pÖùS8µµdƒä `¶ 0š‚†Gxgô9ònÑŸ1¸£…y…’%Ë/ [ΙŸ}0Ѱú_)ªjw˜™v<>Zj:že@Së6x>‘³˜éb·¢3T¶Ü$ËV)àü¾ça_x|ÝSen—A—mpy —ÉÕpÄ`wH,#ËF/~Ä&*=3*%tEXtdate:create2017-06-06T01:31:36+01:00/¸‚~%tEXtdate:modify2017-06-06T01:31:36+01:00^å:ÂIEND®B`‚puzzles-20170606.272beef/icons/unequal-32d24.png0000644000175000017500000000304413115373750017721 0ustar simonsimon‰PNG  IHDR üí£gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEá$J¾"´(IDATHÇVÏkTI®ªî~ófÆ÷¼`A¢¼ä"Y"² (ô cŽ‚‡ü"‚¢‚G¯&¢‘È.k a=¹²]–@4! !“8™o¦_ÿØCϾg’8uæ5ýuuU}U_ãââ""rÎaw³Ö*¥ºWˆˆ16„#¢”r}}wÛJDQ¥1ŽãjµJDnƒ èöXk9ç…B8ç|}}=Žã(Šz®éŒs^.—}ßÏçóÆDBlll bZkDôÈ#$©¥¶cår9ŸÏû¾ÏÝ¢(VJõÄa­B4›MkmEµZ­Õj¹EQÑÆ€)7ËMÕ<D ¬ò„W¯×­µ@î õŸ%}¦”ÒZÑ“'O–——Ã0t*¥d"=ðþùðÜësç_·ò.ƒ)e’$ZëNµÒ˺»cŸ¹82™ ]»vmii) C—+BŠu|iôÒýŸîvŠÐùM3 5R©$„(•JOŸ>õ<ÏùHlr¼p\Y¶“Ò^ì \ÝVVV¦¦¦NŸ>}óæM!„;Ûº­ŒBbØËÝ"­õÁƒ_¼x1??ïÞ=­5ç 1I¬c@hëv¬c„ïh2PƘ\.÷òåËééé;wZ-D4Æ„^øè¯GW~½Â9Ÿþczê÷©¼ÈkvˆÀZÛŸA·ˆˆJ©ÏŸ??xð`||¼R©¸CÀfÒœ8|xóæM.—›››€ÙÙÙV«Õ탺„´-·¿Ô¿@¥UùZÿÚ£ý>ˆèÈ‘#333ïß¿€·oßJ)wv`¬ DðjùÕå_.ûÂö÷³«óW9rVÿéˆØjµFGGgffnܸ?‚ »+y7 &k]8U<%Hh«9òN%v¯…«S¥R™˜˜8sæÌ¾}û¤”ÝÑŽà0Æ<á% {ÃÅ hlg¾K-…DÔSp79ç)Í¢(‘Rº·ZºÎÝÖr¹\«×Œ6= IÕchh¨Ûcluu5›ÍvñTQ±Ñh‹ÅŽà€ó¼[cýÏïBÜíÀœúì‘èþ³„ü c:c8?µ~%tEXtdate:create2017-06-06T01:31:36+01:00/¸‚~%tEXtdate:modify2017-06-06T01:31:36+01:00^å:ÂIEND®B`‚puzzles-20170606.272beef/icons/unequal-16d8.png0000644000175000017500000000144513115373750017650 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<,PLTEÓÓÓÊÊÊËËËÐÐÐÕÕÕÎÎÎÑÍÑÏÌÏÌËÌÔÔÔÆÆÆÌÌÌÍÍÍÂÂÂÜÜÜ×××ÁÁÁÏÎ϶ö»Å»ÐÏÐÃÃÃÏÏÏÙÙÙÖÖÖ………ÈÈÈËÌËßÚßj«jIIåÞåÉÊÉÒÒÒ»»»bbbÆÇÆßÙ߼ʼSŸSèÞèÆÈÆÝÙÝu®u Œ ºÌºÍÎͰ°°ÚÚÚÅÅŶȶ­Ä­ÆÏÆËÉËÄÄÄÇÇÇÉÉÉÞÞÞÅÆÅÍÉÍÏÊÏÊÈÊÕÖÕÑÒÑÔÌÔÑÑÑÒÏÒÂÏÂU¢U´È´ÜØÜÄÅÄXXXÊËÊSžSš¼šâÚâttt+++ÀÀÀPœP~°~ÞØÞDDDÓÐÓÂÐÂb¨bx±xÔÕÔØØØ‚‚‚ÍÌÍØÏØÖÏÖËÍËÌÍÌÿÿÿø+þ·bKGDc\¾-ªtIMEá$J¾"´öIDATÓ×RÃ0D¯ä+£ˆ¶!qè¡L‘ÀÐBï½ÿÿG ÎÓÎÎÎî,¡”‘‘)s ‚IEýA]© Ô lTk#ÆÂ(Ÿ¨7P©9&ª995=3;7_ª4"ÈÖ]\Z^)µ]§á*«k)®olnµ!°™ÈÒ¼ÃÅöÎna0Úü¨M·k4rØŽÏ `~±_X¡Ñ¦9†~òƒÃ£ã“¾Û±§R)8‹âó‹Kg}u}( Q|{wß7‰l><¶PBãéùåõ-3½{Ö%ʵϯïÐjî‰ÌwCûùe b¹Ûþ-sÓ^_JZ%tEXtdate:create2017-06-06T01:31:36+01:00/¸‚~%tEXtdate:modify2017-06-06T01:31:36+01:00^å:ÂIEND®B`‚puzzles-20170606.272beef/icons/unequal-16d4.png0000644000175000017500000000047413115373751017646 0ustar simonsimon‰PNG  IHDRíÝâRgAMA† 1è–_PLTEÀÀÀÿÿÿ€€€ÿ€?R&bKGDÿ-ÞtIMEá%=¹"SIDAT×-ŒÀ Iº× t„nÐs÷Ÿ¦@õN#…r™×§š= $8øØ‘¾_Ŷ¢SIK3N7<ÏK@¹áO¡—qS3¨Ãùáøïjc5†ÚÐ%tEXtdate:create2017-06-06T01:31:36+01:00/¸‚~%tEXtdate:modify2017-06-06T01:31:36+01:00^å:ÂIEND®B`‚puzzles-20170606.272beef/icons/unequal-16d24.png0000644000175000017500000000242513115373750017725 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<÷PLTEÓÓÓÊÊÊËËËËËËËËËÊÊÊÐÐÐÕÕÕÕÕÕÎÎÎÊÊÊÑÍÑÏÌÏÊÊÊÌËÌÔÔÔÆÆÆÎÎÎÌÌÌÍÍÍËËËÂÂÂÜÜÜ×××ÁÁÁÏÎ϶ö»Å»ÐÏÐÃÃÃÏÏÏËËËÎÎÎÙÙÙ××××××ÖÖÖÆÆÆ………ÈÈÈËÌËßÚßj«jIIåÞåÉÊÉÎÎÎËËËÌÌÌÔÔÔÕÕÕÒÒÒÍÍÍ»»»bbbÆÇÆßÙ߼ʼSŸSèÞèÆÈÆÏÎÏËËËÍÍÍ×××ÕÕÕÕÕÕÓÓÓÌÌÌËËËÝÙÝu®u Œ ºÌºÏÌÏÍÎÍÊÊÊËËËÖÖÖÔÔÔÔÔÔÓÓÓÁÁÁ°°°ÚÚÚÅÅÅÕÕնȶ­Ä­ÆÏÆËÉËÍÎÍÏÏÏÄÄÄÇÇÇÆÆÆÇÇÇÅÅÅÉÉÉÞÞÞÔÔÔÆÆÆÅÆÅÍÉÍÏÊÏÊÈÊÄÄÄÒÒÒÖÖÖ×××ÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖÓÓÓ×××ÖÖÖÕÖÕÕÖÕÖÖÖ×××ÕÕÕÕÕÕÔÔÔÓÓÓÑÒÑÓÓÓÔÔÔÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓÓÓÓÐÐÐÓÓÓÔÔÔÕÕÕÎÎÎÂÂÂÊÈÊÔÌÔÊÈÊÄÄÄÆÆÆ×××ÕÕÕÄÄÄÅÅÅÉÉÉÕÕÕÈÈÈÂÂÂÑÑÑÉÉÉÒÏÒÂÏÂU¢U´È´ÜØÜÄÅÄÖÖÖÓÓÓÄÄÄÞÞÞÄÄÄXXXÌÌÌÍÍÍÍÍÍÊËÊËÌËßÚßSžSš¼šâÚâÄÅÄÖÖÖÓÓÓÆÆÆttt+++ÀÀÀÏÏÏÍÍÍÊÊÊËÌËßÚßPœP~°~ÞØÞÄÅÄÖÖÖÒÒÒÌÌÌ»»»DDDÕÕÕÌÌÌÉÊÉÓÐÓÂÐÂb¨bx±xÔÕÔÇÇÇÖÖÖÓÓÓÇÇÇØØØÐÐЂ‚‚ÄÄÄÏÏÏÍÍÍÌËÌÃÃÃÍÌÍØÏØÖÏÖÈÈÈÄÄÄ×××ÔÔÔÂÂÂÊÊÊÌÌÌÕÕÕÎÎÎÂÂÂÐÐÐÔÔÔÏÏÏÎÎÎËÍËÌÍÌÎÎÎÒÒÒÕÕÕÕÕÕÑÑÑÎÎÎÎÎÎÌÌÌÍÍÍÐÐÐÕÕÕÿÿÿÁDF°bKGDü<£tIMEá$J¾"´IDATÓïþ  !"#$%&'()*+,-./0"123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstu2vwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶o·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûÂ%|OEëk%tEXtdate:create2017-06-06T01:31:36+01:00/¸‚~%tEXtdate:modify2017-06-06T01:31:36+01:00^å:ÂIEND®B`‚puzzles-20170606.272beef/icons/undead-web.png0000644000175000017500000002731313115373724017534 0ustar simonsimon‰PNG  IHDR––³cæµgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEák Ö-ÏIDATxÚí]{\TÕößûœ3sæ=0¼EÔ05Ë¢”¢i&?³ü••=4S+­k·n·‡Yii–ÙÓº*>ÊÔõbšÏÔTM ‘7Ì{Î{ÿþØ9?~ 0s` î¯õÇýxiÎ>{ïïÙ{¯½Öw­ËËËÁ_Ò™…èèü%­ªý_‰Bá„_¾!tC‚€úuB?½ÂKio%IRÐ4­PŠ’ÄpœÈóm$BH’$š¦iš†rÇ0 hÓoE’$HB•JE‘€ã9–e!è0 ÛB„A’µº²´ôjY™›e Zmèhch¨Ãél“ñK’¤P(t:]IIIQQ‘(Š]ºtéÙ³§ .—‹$Iü3QñêÄxû´R%IÒh5‚C¸tùRµ†$È®¡]cºÅp€ãX( ›•$ !äyµ?¶:ƒ" Ä0ssO"$FE!š†N']R2&$dìèÑ.ŽÃ³ˆ÷%² (AX»[»OOnŠ01nB¨T*µZ-Ã0¢(RE’¤Ýn÷ßm'!AŽ{wãÆªaúöë‡ÜnŒ¤R]ٳ箊Š“'[NS`à§Ÿ~ºtéR¡ 6›mÚ´iË–-³ÛíÍï„x󬩩?a•¢"‚ $I¯@Ñ4½yË–áÆÙívQ—/_¾gϳْ••õÔSOáß7?Ë’$étºýû÷UõU—ñ]t¥êÒji§´0}ap—`€Àµk×–,Yrúôi—Ë;sæÌ‰'º\.?üí¡‘J’¤¥éM»w—ßu—V£)ûåŽe—Ëåp”þüshRÒ¡ƒ‡é´ZammmeeerròøñãÓÒÒbcc½Y…B…B1wîÜø¨¨¼M›~Ú¼ùñÌJOßöÕWG¶obÚ´ùóæUTVjµÚºººo¾ù&(((55µ¤¤ä7Þøè£ôz=†üV‚¢UtIaɺÒu=ÿ«§Qk”8‰u²œ‹<ˆî­œ¨\³o b‘J£:wîÜöíÛ“““ûöí{ôèÑG}ôàÁƒ:®ùWÈ¿Ÿ…!MW–”œ¢išaœ;âˆÕššjݲ%K©,¼|Ù’’²ÿìÙ»V«ñ‘™™™––æt:[\‚ƒaÏÞ½½¢¢>üç?KJKAxÿïEÑÅ0«õƒ%K>Z½zãÆÏ/X ÓéöíÛm4—/_þÜsÏ]¼x±ÅÉ•D“t^~žv¸YÐÕ3Wi’»ø²³eItÒµ(¶è\Á¹Aw8h`AAADD„V«8qâÖ­[‹ŠŠFíåví«ø}"„h…âjY×µ+uåʤ´´ÔþýׯÛ&´¶öþ¬¬°ºº.$¤ª¢B©TrÈÉÉùûßÿ>qâÄ'Ÿ|’¦é—€ðzqñôI“,Vëêßÿæ›ÊêjA¾üî»w×®ýíüù)&–­·Xôz}XX˜Óé´ÛíGŽŒ1¢ÅƒŠ ÆÁ\®êCõ  ›/TŸ­&i’¤ÉËÛ.—/#B£ºX}ˆ 88X£Ñ0 SXXxæÌŠ¢ Ä0ŒŸŽÃöØH!„nŽ#I’JN~oÇŽµGJII4]Õ³ç›_~¹£¢"àöÛyQ$ÉårMš4éСC.\ÈÍÍ5 ëÖ­»pá‚F£iE|pt:F!œ”4°wo•J%JÒm={Þ™”€ æx^E’$ ‚˜1cƦM›žzê©iÓ¦Ùl¶æ•F¡È‹àH)râç†Ä á¼à’ŸHŽŸÏÙ9RMº7–aõz}qqqFFFqqñ'Ÿ|Ò·o_·Ûí§³°½. ,Ô³§Y«ò6[èw^éÙ“V©‚ƒkyž Že#""ÂÃÃBwÞygxx¸Íf³Ûí-*å„ šf9®Îb韘fw:BéC‡:ÝîŠêj£N‡ TP”R¡¨¬¬|ä‘GŽ?þñÇÏš5Ëf³±,Û|ûHBJZ©ZÆÅhuZ]„N„"ÏòZ£V¡“ qHtˆFÚ( AoÐïß¿ÿá‡Öh4‡ºë®»Ìf³ÿ4Òö€ðû.­â8‚¢D·;Èd’$ñ<À§¦Ryßĉ*•*55õÀ—/_NHHèÕ«—Ûínf „H’ºDGÞ1`Àçë×wïÖ-&2Po³ýšŸ?a̛ͦ 0èõ“&MºtéÒí·ß^\\üðÃ'&&>úè£øŽq«WH’¤Ô+{©{ý\ú³>NŸ¿._tZ¶Ê^EҤʠŠç¾ìîÓ¥R­Ü—·ï¾ûîáÎ;ïܶmÛªU«233ÓÓÓý¤”¶ÇFŠ)T*»Ó)AH'IN†Q¨ÕB»Ã!@H)•H’H’1bÄùóç_}õÕ#Gޤ§§öÙg‚ 4¡ËíNJJ*³ÙœGöĉÿÚ¶íʵk‹åËÍ›ûöî}[|üÁÓ§ï¸óNžçN§Ãá0™LEEEï¾ûîÚµkwíÚÕâÌp±®1ƒÇGH‡àˆHŽP—¨gŒê uäí‘‘"¯\ëké›Ð;çy³ÙL’dhhh^^Þ{ï½·nݺ3gÎÐ4í'uÆï÷BI’ô:ÝÏGŽ|P^_Yi×îÎÉ¡].13’$ÈÉݺUIÒk Q={*)Šã8‡Ã! EÑ›S!DQ”Ãéü>'')&Æb³eÝ}·R«Íݳ‡„ð·k×§¥Å÷ì‰×ÛíÆÜ,AJ¥Ò›h4šÂß —]®ÍÒªÕ"#„0n¦<¿<òDä¼ûæ‘R%I’Ün7n™ Ü7Šò׆×ôúïßÿÓÑ£ï¼ðÂwyy[NzyâÄèððw¶l±³ìß§L1Ûío®^ýÂcuíÚÕåra‹BHàµy!¤P(XŽû)/Or8b;·€!Æu‰ŒôìcNVlór,¦¦¬fËÁ-WTWX+1’ΦKѦd¦e%x[—õ›Ùü4Ãíaò§¢i‰ „X‡Ce0ˆŽÒh‚àÝnŠ¢ðP=NŸ^„" B¥ÑÔ˜ÍuuuH’ôCxX˜$Š,Ëz¦µélúd#UÒJ©ª©¬±Z­I„‡èMz‡Û$äi§Ñ+üjo/„B!!A’’ 6‹âÿ¾ÙäÊI’(ŠR(Q8žo[BHB’B© H Äó¼(ˆ$áGCv sûŸêµ—·Ž}m߯¯ðR:ÀåÛ>âï™ípä<òñ¢ÓË_vzù ÂN/AØéå/;½t˜FÚ&Jy+o­ïßájÑ1«3<•J¥B¡m|Â|5Ü‚ì>Ð4òZP(˜íè'R…7Òb>„°²²Òb±èt:]Í{êtºúúz«ÕªÓédôA¥RAËÊÊÌf³ŒQ@5Åb©¨¨€jµZÿYA›—ö†óÀöíÛ—˜˜˜œœÜ»wïY³f¹Ýnl×ö²lû_¼xqBBBbbâ’%K|r刢¨Óérssûõë÷ÄOøú áe7uêÔ>}úôë×oÈ!ûöíkžZà?é€U!dYvêÔ©?üðÃÓO?½aÆõë×·È!óˆ(Šz½þßÿþ÷Š+fÏžýðÿõÖ[GÕjµ^¶€Ï-A&Ožm±X|òÄ"„ „ ÃDGG¯ZµêÛo¿u:Ï?ÿ¼ÓéôéCl+iou† »Ý~Ï=÷Lœ8Q¥RuéÒåƒ>p¹\Þ«øÊËË,Z´Èf³}þùçû÷ïOKK³ÙlÞ€A„Ãá;vìC=tÇwØl6Ÿ”¼Õjõ²eËA0ß~ûí±cǰy½çtˆFŠW¡Ûí6Ï?ÿ¼N§›2eJ‹LÆJKK£££gÏž­P(‚ƒƒËËË[äò6íƒÅbá8N¶2YSS²eË–;w.^¼Ød2Õ××û•{Sé˜È&’$FãÌ™3óòò~øá‡¨¨(ï!ü£ßåp8¦OŸÎóüÖ­[•J¥ ç"¸A÷A’$Ÿf_ÅÐÐП~úiòäÉÓ§OŸ;w.&ü·ÿ|vÌ¥B¥RÍž={÷îÝÇ7nœO €êÙ³g]]ÝÀÝnw·nÝ0Þ· ÕjðÅ&44Ô'¶5VÊ>|ÿý÷ÏŸ?íÚµjµÚOÃ¥½ß*Š¢Ñh\±bÅW_}¿bÅŠôôôÍ›7û¤Œ°,›‘‘˜0aBvv6EQ>ñÃ0ßÿý„ ._¾|íÚµñãǯ[·ÎKBJ¥²¢¢";;!TUU…)Ëÿ_ÔpC£‹w:û÷ï·ÛíC† ñ~ðA8Îäää/¿üòý÷ß§(êÛo¿MHHð~+Æw’ÊÊÊÇÇÆÆŽ;Ö¯_?ïû€5Ò¸¸8–e>Ìó|XXfú´¿t€×ÅEyhBDZ,ëë^ªÓéðã¢(:}ŒPÄæš¦Aøƒ7Ų>õB¨R©ð¹Ž÷p—ËÕ!·ûŽ!^4ŒÕrcEQô<%ãj}¶ÐáÚcæn“·Rýk}:<ÊË_ΦN/~\…!/c¬ÿ³Åwî'ñ„Xg1 þ뺗Ýhå^×ÊpàœÕjõŸ¦ã1~ÅÅÅ;vìh7››‰i¾ìMl¢(Qå€ñ š4i’ ‡š·=ôG£øî|ìØ±Ó§Oß{ï½V«ÕWûó %IŠ—"‹[ÈÏÏ ãyÞ×Qàñĉ‰‰‰jµZÆw€¿¡ 6Œ5*""¢5öØfÄoá6r—––ößÿýßN§ÓW>v=zT’¤»îºKFˆ¬(ŠæÇìÑ£G¯^½d|¸&“iôèÑF£QƹŽ[8v옟ÀÃâßK…Õju»Ý555 Äd‹†i¼š†a§¼$Iõõõ-&-ÁâIÚEÑ`0X,–ºººšš !^IÞÛáÔjµÅb1›ÍÇɃ' ñëÝÿAÞü ¦Óé0ïÿ…ã8l^ñ kqžX2Ï¿›Ÿ/¥R©R©œNgÃ<}h4ì,ôFE„RÕðq_÷ÁßwG™ÊËS‡páÂ…¼¼¼ .‚н{÷Q©©)b—<{?æR”––Œ5ª©â9†>|x]]]‡¸g› ÞZ“îOæ0H’¤iš¢(·ÛÝ|”ºG°† ˜?þš5k<û„ðŸÿüçØqã>X¾<88Ûû}êŒ(ŠjµÚn·O:Õáp8p@¥R5Ú÷pz¨uëÖ}öÙg?þøãÈ‘#kkk;EÌ›¢(ŠaÙ祜1@yž¿páB]]]BBBHHH‹z?þÐB“î¿ÿÐÁƒI‰‰*•êRa!ò½{õ" bïîÝ#SSwçæFDDàÜ…^ ÆÏétfee•””lÛ¶M¯×7M¯€÷ÏW^yåêÕ«ãÇß¶mÛ¨Q£:EœaîìÙ³ÕÕÕ=zôèÒ¥‹—‹¡‘È„pÒ¤IǬZµê¡‡j‘p IR``à³sç"—ëÔž=Ý££I’<{á‚ËíNNJRPTEMÍ?Þ{ï™gžùþûï½wÞ6ፍèÇ0`îL£;ž/µZ½nݺìì쬬¬~ø¡QÄšÎÔ©SwïÞ øÇ?þ1þüºº:‡®Ï^‚3fÌxýõ×wÚv‘ÿzê”­ºzçºu=cc‹¯_¿TTÔ;>~ð€åUU~ÿÝd4~³re¿¸¸¶m3Þ\ÂâWXX¸sçÎþýû73 Aàü2ëׯ9rdVVÖ¾}û‚‚‚:Äχ;sß}÷-]º´Ž .ÇGxòÉ'GŒáå»ÿ¸#?>còd…BQtíÚG6,ÿæ›ÂââºúúOrrÞ_»6ÿ·ßlvûcÓ¦]ºÄÝHlÙŒxð»÷Þ{ wíÚuûí·×××7¿¤‚Àwü?Š‚ <òÈ#ãÆÃÿW6ŠrÔ?!¾«ï¢ã!Ï+!ŒéÒÅÍ0Ø9.!„o˜ŽwP@@°Ñèp:‰f÷“†øýþûï^â÷Ç€ 8bĈŽEÑb±X­VüoÙæ7™Ç€ççUƱNO‘¤(Š]ÂÃgM™"IRTD„pÖ”)v§3¾[7Q’‚ШTÍ¥5øaÁ(bÓ×Ô©S³²²¶mÛ–ššÚþçbÃilä‚ö^dú õz=ŽdÐh4z½¾Eu”$Z£±;,Ë–UVöíÕ+¾{w TDÄÀ~ý¬v{½Õʰ,¢(Õ­S6ÄïòåË2ðûcØ7Ö↠FŒ‘™™ùÓO?µÿZÔétz½ V«µZ­<ö”ÏÖg‚ 8Ž>|ø<X°`ARRREE…R©¼Õë±e«klìï×®©h:ïàÁõ?üPVQáf†e«kk·ïÝ»yÇŠ$¯^¿¢ºE€D#ürssåá÷ÇÈ;E’$³²²ÆŒxûí·{õêuñâE2ß­[7“Éd4±5«üNfév÷éÓ'ÿäɳù‰éÓ.]zììÙ‰‰A\ºv­Ìl~cî\½Vû}^ÞäéÓojÔÆf9›Ívï½÷^ºti÷îÝ­ÁÏ3ÏŽúÀdffnÛ¶---­¶¶¶}H¡111AŒ5Êív3 #ÏâÛøñz¢iúóÏ?Ç7-¬Á{Ål—¤ôŒŒïׯŸž‘1~äÈÒÊÊ)ãÇ‹¢xìÔ©òª*“ÑøÉúõCF6 .—«Ñ£X§½~ýúôéÓ Û?,srr0ŠëׯOKKóɼ OBË—/§(Jl˵X, ÃøúõÈ™„PMMMÃe×¢1BÈr\hHHÖÔ©›·o tÛmuuuÂØÈHI>ݲåÎôôÞ‰‰˜ÚècÄá={öüþûïmˆŠ›6m?~üêÕ«ÓÓÓ}â†Ë–ÚÚZŸ¦ñ¦"ßF*c¦Ünwhppöß>}úXa¡àv#(¥2(<|Òƒtº[Ñyq€x ###,,Ìb±´­êˆQ¤i:''‡ã8þáv›Æ¦Ò®:4V… „Cî¸C4ˆå8€B¡P*n—«yF=¶’5,Ò¶}cYV¥R©Õjl«ì¨¨]_Å¿âkC#ö BÈf³„ Ï»oê2 Ä-`£O'#!‚{‘J¥Òét,Ëúº 1øž„Ã_d¬!N§V«5 €¦i•J¥Õju:<U*•§þTÛÏ2À¯© ±±±ÉÉÉ2lx#å8N’¤AƒyIj(8±¢¢¢GòhŒx#½zõjÿþýF£ :+¾ áôðþ™cü !Žåd¦)—B’$ˆYkJ¢ˆ$©B˜Cív»%Ir8‡£)Å  €€$IHBM@’$Ã0.—Ëét6_&ᦂ5Oÿå­B æ¿yö¯FŠ#¦—$‰ (ƒZ-0 ãt„ÔjµR¯w±¬Àq oqC<ÿ‰RRZÃ99ÎÅ´-¥¦n‡$üŸO6y[±§ó˜5âëð}-Ž(Oä3Ø<Å}ÊM®R«y‡c×Áƒgëêj!”@¨—V›šœál²Ú‰(‰:­ÎReÙyrçEçE+´BMÈ”˜4bеAívù«®Ž?Ä3M™´Þ‹LišV«Õ$I:/5|´”~òóÏõ·Ý˜’¢Òj„·{_IÉO¹¹'&¼ãÇ­Q%Q¯ÓÿzüׯÏ-ÑFµZ ¨sÖm-ÜúÓæŸžúDl¯X—Ó_•Û\”J¥F£!IÒétÊf ËôT?~Ül6=:>>¾EB´JU^\üö¦ìì„w]ÈóE÷ïï¼í¶•ß~;ÂäÁƒGÓþ¨àyâÔŠßWÄNUC5Ïò€=­hI°,ÉYò2õrd·H–i¡S‡ ÞÀÊËËùå—ŠŠŠaÆ%%%ÉP›l3÷Œ3 &“))) 'Qkî Aørÿ~ã”)JŠNž íуÀ>E]=wÎh2õx衵kÖôˆUM¬””‚²ÕØÖ¬y0F)(R „È‹BI¬  ï¿üáË—»¼ @ÒŸÚ<†}/Ï<óÌÁƒ¯¾úêàÁƒ[žÆ›‰LÛ²e˾þúk€7™ ñ=ýܹså±±j¥}ÿý]gÏVnÞ,AH(•æƒï8{–Ü´ÉU\ † 9pò¤F¥jê©Ð¨4‡Nbû±­¡æ÷šŠ_+J•ð.ÞQå(=VZz¼´®¤.4"´<º<ÿl¾F£ù“[8 ‚`æ•W^Ù²e  U^O_ÀgojjjTTðŽ´ƒ ((+Ó÷éS™ŸbbŸîÝü1ày7Ï›JJžÌξ¼sg馄„‹6›àvƒF‡"#þfûÍkdm¬)ÎtaÓ…ê Õj“Z©¿²÷ÊõC×1FÞÎkºkÎWž'‰ÀŸB€$IÆ ‹‹‹­ D• ¾Ífó8E½úÞ%©Žã E…ÄÇoÌÍ`ðìÙ@¡PSTulìÊý+!3Ó>x0DÈ !ϲÄÿý*!y–· ‹B­€¬¿Tßç>‚[p×¹Y;wwBÈVj è Ð+jÙZÐIâÃív;.ÐÕú“Lq:^A^n !­Ñh7îxuuxL ”$‰ãB†ýµ¤Dc00‚ Äu=!$)!IäÄÀîø2#°¥¦ŒQFÄK’ !„:°öŽŒiij‡ã§ä-D9Ê7BˆaÌŒÁív{Ÿ4Iây MGÆÅAø£ÂÇEÄÄè aÀ-¼tHBJµ2”el A@¤@NÁÉÓ¼B£D H@P[ËFª#;KÏ4âíABô0Øúõë7aÂáÓO?UVVÖbÑdpcÇ—$‰g„«‹" äXV„æ,  ˆ`ýÍJiK©åì»g5{5h :µòÔ¥—.l¹ÀÔ3„š`cûwïωŸ¦y!I255uèСA¼öÚkAAAçÏŸ÷;ƒ û ÅìÙ³N§J¥ÂîÀÀÀ–ƒ›$‰R(x‚ IRdЦYQT(•€ãP©äy^¡Tr’Ôt%ÂérJ”·.¯ìjYdïHg³·»wSWŸ\Ö?Lpúp}Ñ™¢d&¹G¯v—Ïfñ‘Ç{Ìl6k4AAˆˆˆÜäóŽƒ!œ;w.&)á÷Y­Öæ!D’¤ÔhêÍfÛöí099&=½öúuÛ† ::<#C¡T^ß¾(,¤²³:ºégˆ€HŠOÜýÄ›ÛÞ,[û_±?üL*Éè˜h$ …^Qt¦(üXøôû§»8 uXÊzïg§÷„­V«Œ(C™W{³Ùì=õ !D)u••Êââw¦MÛväÈw6tµXþ™•õ{IÉ›6¹Uª5šaÙÙolß^U_OÍ7ABȱ\`xàâ¬Å_ïýúbþE]_¡&*K*¹zN¼,fOÉ&T.åù§¿S@]]]ç`°ºEqDBBÏîÝ•!!“324»vÝ>r¤±K—!ÑѪS§ÌµµcFfDñʼnþò Oðf ‘ ÆÍhMÚ粟»|ñò¹ßÎÕ¸j‚ˆÔE&%%Åöˆu²Î?ðë$ÒilA° 3tØ0Žç]„03+ËÍ0n—Ë @ߤ$’$mN'€R«ÓÇŽu9Í4%ðø¸Þq } ˆ@¬ÀÚœ6úݳó'¿3ØDQÄY'ív;ÞñBõõõGšÓéDxÞʲ8F×#˜@Ö¨e§ÃÙÐþ‚Á“äù›‡væþBƒÍ3 y-øu’ýÎ`à 0yÄ L:2 MkT·(øALœÑëõ­d° ÙÄ‹NÌ`S*•GŽÙºu«ŒÔÿ8mÏÅ‹1ù_Fö' À‰'®\¹RPP CÓÃC8~ü¸Ûí–W ·PYY©P(:%ƒM„èèè4ÍþÔ¢àïoDýû÷÷µ¸QT¦¶¶6&&¦[·n2\q’$©Tª²²²¾}ûb©¼`ƒAƳދ7RI’L&Stt4ÎPãë³:îúõë¢(FGGËc° †àààððð®]»z|âÞû0AAA]ºtñ0Ø|r)à§ðöß<û—Á&˲2˜á¬^<ÏK’$/+”$IÇ ‚Àó¼'}{Ã$mÞô$IAðãx>eqÃq þ®Åå÷Kþfå•rñ´ # v£ßã´Z-„ÐápxÓ%Ï‚kȄõ,¼ÜØÑ”~a™†DQ±Y¯³¤nÆ{ÚªU«-Z|Ï0u“E‹­^½'¼j}¯Údef2™Løxã8g/ùó ÞEW­ZE’äÛo¿]__|ß\.×Â… 5Íc=&CMk(Ø=€cÜ[3>÷çŠýä“ONœ89räĉe{œÛMp¶ùóçÓ4½`Á„Ð’%K|E‘eÙ•+WÒ4=g΄Ðã?.ELAúúë¯<ˆ3fLff¦¼•íÛëñfRZZúÎ;ï`=;''§¨¨è•W^騺aÞ A555O?ý4BèùçŸø„"Ö†¬Vë»ï¾‹zöÙgòPÄwÖ+W®,Z´(!!Áápäää¼ôÒK .”1>û q}¢Ã‡ÇÄÄÔÔÔ$$$œ;wÎËYèp!IÒl6?óÌ3Ù(Úl¶÷Þ{ðì³ÏBeì¨Øm~äÈ‘îÝ» ‚зoßÜÜÜ Èpsú¼ à:ÖJ¥rÈ!'OžŒýõ×eDïu”4BBèÓ¹ØÅ9sæd ˆÕ+FÃ0ÌÕ«WKJJ222”J¥Œt¬rÎBI’AHOO7™L‡>xð`||¼'¾M¥éZìyžW«Õõõõ“'O¾í¶Û^xáF( Ïk¯T*^{í5Š¢Æ·dÉ’|°S…">­Vë¸qãŒFcnn®F£ñ²q#‘sŸ9sæÌ™3wÜq‡Ãá(((0™LAt– ¢GÚE«Õ*Elµ±X,“'O¶ÙlüñÕ«W!„1112{Ÿ5R…BQUU5oÞ<5©Õjß|óM\ÿ¯s-Dp3ßzë-\œÇWBÍfs‹9’õzýNŸ>MĘ1c°5?77WÆJð BœÂgäÈ‘'Ož,))&$$„‡‡ËÛÄÿ ÒT»Á(zù¸ÅeË–æÌ™ƒuT³ÙÜÌ„à,JIII›6mò3½Ì…ÜTdÒŸºuë†UÇÜIñÃB’dMME–eßzë­¦yàn% Q„Ξ=›eÙ™3g:nbçyD“ÉtÏ=÷xþ(Š¢÷/m(2íCn·¿¯5á©¡(Êl6Ï™3ÇårÕ××{"^>ÞPGõÒ´Q´X, ÿ"o&eBø[#ÁkqΜ9¸Ü³¯ ¼<(¾ûî»8ÅCÓd€Mé4 ¶Î"< ÷Å+[«Ûó÷;ƒM^غ™øÔ‚§²—O{<û AÚñFEÂ|j¡þe°Q¥T*q tŸžÅ5´pIÜ‚ â~/6Ê#!âpä1ØdôÜWñ/ƒíèÑ£6l°X,òJP^¾|!T^^.¯¥Z­>uêTaaa~~¾ì”¿üò‹Ýn—]‚²s3ØxžOJJš0aBuuµ ¢N§ Eñ®»î’AÂ×gœF¼G²?œK³Ð|lËÞµk—¼bL^ŠÏBŠ¢T*MÓ2Òè©T*¥R)Š"MÓ\ƒÄP^ ¦* œ σ‹G õ¥0÷ަiš¦1‘°á¼MÓu#õŒ“áeàÉÇÚP¼§6Ê'ëÍŒã­ÛJðÿâ—6üGC½i°È éRáÑJ¼Y”2¶Mœ7Àƒz£¦<ÙÊp"ïÖä¨h[‘Ï`Ãq'íC™ÁÛÆSSS-‹F£i[Ç…Á`˜;wî¬Y³è[Ô:Q(<òÈ‹/¾|çÀÝt\ ÷yÈ„000000°²{„eÙ„„„òòòÌÌÌÚÚZyizo*üž{î¹ýë_)))7Pü—”””/¾øâÅ_4 Õ(j4ƒÁ`4nõÝ´(rR‘$¹råÊôôô¡C‡8p³cÛd6oÙK‚p»ÝƒÞ»woMMÍøñãÛ E~óçÏÿôÓO?üðÃùóçß4 çkz饗–.]úá‡Êæ£6œÆ'Ÿ|rÀ€ÉÉÉ=zôøì³Ïäé½rx ‚ðã?ÖÔÔÔÔÔÈ+å«$YWWŸ››ÛV(6Åï±Ç«ªªºÕA !¬®®~æ™g–.]ºbÅŠ… ¶f-’$yâÄ ‚ FŒ‘”” Ãþä©3’$íØ±#??øðáíY-Ž¢(«Õ¿{÷î»ï¾{üøñ;vì ’A·À¯EŸ{#ÏðÑKÜP°r›’’2iÒ¤¸¸¸¨¨(yµ¢dÚs=‘ íÌnˆbkÖ¢<ü<}À(âµ({GõÔ;vlbbâÆå•R™ý kÕ ½b‘Í`C322|E±5øyúÐÅ… ødÑÆTÒ%K–œ;wîØ±co½õÃ0í‘Ì܈©ÀÇ€N§“QI¤•ÒÅÚÚZŸPijl4çÍ›'?O0cÃb`` ÷(J’„ùqqqƒ JKK»víæùºäðHEQܸqã™3g$I2%%Åh4ú5–µé bsssï¹çžqãÆíܹ³ÅsуßsÏ=·fÍÙøaiÄ»ñ>NÞŠ‹‹ßyç”””ÒÒÒ¯¾ú*--M§Ó5_¸êæSáÓ¯± C„Ù³gWWWÓ4½fÍš¯¾újÿþý!!!2jº´F|Ekøþ·fÍš+VÌœ9³•ÑI!„ ,,Y²Ä{&ㆠ0‡qÈ!ï¼óN{П°åP¥Rååå ‚€ŸA˜L¦!!6DqìØ±;vì0™L·* ©ÕjçÍ›‡×_ëñÂQ|úé§ ,€¾ñÆÍGšá ]»v=qâÖB#""BòæPf`UDDDÿx´›öŠ»víºû²²vïÞ­P(z‰¢ð·¿ýíÓO?]¹rå£>Ú&øai„¢F£ùÛßþf±XšYˆø<""22'õ>‚¼ñ Èë4΢ٰCm2ò£˜˜˜¸yóæŸþù¦þUœp*?yW.‚ ÌfóöíÛe#sÈÉ«`é¥Àòòr?5 p¹\²É[žCK¶ÑÇ“|IžÇÓ6ËnA­VËvçz#þÝHõz}kNï‰F~m¡•‡™¼jÜÞ‹!ôkÔÎ"^iæ¿þg,²§²uLŒÖѱÆ(Û݈ T²Ãü1Ù·ò6:O žš‘€3µµZ-˲8@YûÆ`0`ª™Á`9E’¤^¯çyž$I­V+£…B¡Õj9ŽÃ5U; Åö†çÌ8räHrrrß¾}ûöíûÒK/áõäý$bÛ²eËúôéóé§Ÿú4ƒØ ,Šâ¼yóâââ¸{÷nŸR7cüjkk³³³»uë–––VPP /ùs륽!ÄjzUUURRÒÊ•+Ç·råÊœœ½^ïåøqÄÌ^}õÕŒŒŒáÇ?ÿüó¿þú+Níe z½~íÚµŸþù¬Y³‚ƒƒŸxâ‰ÊÊJœ”ÐË4Í›o¾™››ûâ‹/–——?û쳂 tHðs{¿_Ø'L˜ðÍ7ßLŸ>}Ñ¢E€ššï3ˆíÝ»°råJœ‚iß¾}ª&µGo%Øë¹cÇŽˆˆˆ>ø`ñâÅV«õÔ©S^.#¼-Ë®]»FýÆoÌš5ëÌ™3W¯^õ¾m(`æÆLÔÚÚZÀ믿NQÔ}÷Ýç½ÇûeŠ‹‹£¢¢æÎKQTPPPII‰÷÷w8WVV;iÒ¤àà`@ii©÷Š%NY__o0ƨªªJHHhÿùì°¬!!!/¼ðBNNÎÚµkããã}-c@˲cÆŒ>|8&~ÉÐìEQœˆ@IDATxÚí›W¶ä( @Yº–¦Õ<'‚ Ë}FúxÇt®{‹hÀá÷G°pk°pk°pk°pk°pk€ BذÿÀÞ`ÀADŸJò¿#Ðg Ê¿X ß øLŽº‹½g>&ÿ:ø•;èó_ÜtþºÑNˆ?“þ™Äþ‰&VñÏ_J¤ùÔî—¼8ÿ‚…­«â„¬%Çkx~|ŒÉÊÜÅššq¼fWÖ´ükÖFá„ͯ³weÔü‹V§› ç_¶?PÈXTó/Ü¡ydÔò/Ü#ƒb k¾ voÄJþn—òM—\ÀÀ¬\ÀÀ¬\ÀÀ¬ÃKÀÀ¬\ÀÀ¬\ÀÀ¬Ö Œ®Ì½´²G®^«òµÑ[þ3:ò ô®Nçù˘òþX*[ xîø»‚<ÿ @ÿÍ•¿Æß(„…{d2ƒjþV ½ hóW jùAa@Yë{ Í/Ù'þQü ÈŸ"žP 0gžØz`ØþAbw¸ÌY ¤ùŸ•h¶@Fà^ ù¹àO»d…Ùñþ@·ÊQRšc©T탾'óîÿ@·€ÙëBãÙªÄ9ºñ+V%lŠésQ³.Ô+P}q OÐWæúö§ˆœ-4Æ3°\ Çòg|e,»ÎÜ\Æpu:œË·ñ æ÷»–S²?3ÛYï–¢!`‘Ì&­vhÒ·`È*,” ÑtØf,û•ŠåŸ[B`¼K)¾u~s°pk°pk0ø…(9àÑUŸ,%tEXtdate:create2017-06-06T01:31:36+01:00/¸‚~%tEXtdate:modify2017-06-06T01:31:36+01:00^å:ÂIEND®B`‚puzzles-20170606.272beef/icons/undead-ibase.png0000644000175000017500000001535413115373750020043 0ustar simonsimon‰PNG  IHDRÀÀݾûPgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“ oFFsPcGétIMEá$J¾"´ vpAg àõ>ˆÆIDATxÚíi\×Þ€‡È„„-ʨDŒˆ¢òBX\î5Ê"Ô*b½Tá[áÒm­ m­mQ©¢e±àŠ«"qg3¤`Eá*(;Ö*I™HÞ©i fBÀœçSΙæüOx8s23™£ñôéS)8U'ߨP @€ @ *€@T¨P @€ @ *€@T¨P¡©êÆMMM7oÞd±X>looïêêÒÕÕ%‘HT*uéÒ¥+V¬ÐÕÕUuŽC#‰rrrrrrjjj::: ¬­­½½½ÿõ¯‰DlÛÒ7ÕK‰=}úô “'ONLL\´h‘ª3Œ/^„……UTT(Ì?%%eþüù6aóüùóÁþøãõëש:Óaxýúõ í‘äôøñc [)ÆÒÒrÉ’%ÞÞÞT*U¶¾··÷ÓO?íîîVu‚ŠIII¹wïžl —-r8œmÛ¶aØ"è-,--ãââ˜L&“ÉßÕÕ…I»@ Á€a888¸¾¾^Rœ0aÂÁƒÇæHnN£©©©¥¥%-jiiÉ!쾤§§'$$¤¼¼\RÄápû÷ï_ºt©ªóRŒŽŽŽl±¯¯ÏÁÁ!66–L&ûûû …BÙ¹iÄ€‹©Š …¡¡¡·nÝ’q8ܾ}ûV¯^­ê¼Çãp8éQŒÏçC#©‘rôôô0iŒ@  …7n¼zõª¤8a„¬Y³FÕy ‘‘‘ôõË—/å¶ÊÕcÒ(HžÞÞÞˆˆˆÂÂBIQSS399y,=R¦N*}ÝÔÔ$·U¶‡ÃÙØØ`Ò(è-z{{### $E--­ÔÔT???Uç…{{{éëÆÆÆÎÎNÙ­wïÞ•¾¶¶¶–›3 ÐßôõõEEEåååIŠ:::™™™Ë—/Wu^H‘½Q©¯¯ïüùóÒb}}}uuµ´ˆá‰P0‰þ‹¾¾¾-[¶äææJŠZZZIIIŽŽŽ O¸éèè`5 ÅOOO"‘(½žºwï^ …B£ÑZ[[£¢¢Äb±4Ò×׫FÁ‰Q]]|°ùàƒU²8ðý÷ßËÖèêêJ¾‘Iquu=wîV-‚CØ_ÈþƒŽ_"""ekäì!‰{öìÁ°E Ð;?v옳³³Â­æææÇ·³³Ã°E0zט4iÒùóçsrr.\¸PSSóòåK"‘H&“½¼¼‚‚‚À¯2c p @€ @ *€@T¨P @€ @ *€@T¨P @€Šñ}SýØ|TZF *Æ÷$a\ÿ°dÊ”)ã:0P @€ @ *€@T¨P @Å»p- CØlvIIÉíÛ·ïÝ»×ÚÚ Ã°@ ÐÑÑÁãñ–––ŽŽŽ .tww—[ ðAò”ãa=Xô·nÝJNNf±XÚÚÚ<Oö¡­@ tvvÖÔÔ\¼xQ(:;;oÞ¼ÙÓÓSÕYcInnnTT”ä5r‡€@‹ÅŠ}úô©d ¶A‹Å<‚ ââ⪪* ‹ÄÄÄyóæ©ºÀ`0¢¢¢z{{!Ú¼y³P(\µj’7ªõ†á­[·®]»öñãÇÃ]Á¯«««¾¾~Íš5ÑÑÑcsgä0ŒÍ›7Kì‘ ¡¡ð½ê+P[[ÛâÅ‹sssù|þÈž2.‹ù|þÅ‹—,YÒÞÞ®êÜÜ\Y{$«É.>8j*P]]ÝòåËÛÛÛÑ0 ·¶¶ÒétéʘãÙ#ôfe´aM¢ÕQ ¶¶¶•+W²Ùlé7QW—H èâñp8]<žH LÔÕ•{× 1}}}¯_¿^¹råø‡äŽ\&LHJJB>öHÀ~ÝÔÔÄd2™LfEEECCƒ´>$$ä›o¾Qé'AÃp@@‡Ã‹ÅÚZZŽ3g¬X1ÛÞ~’©©±Á«ÎÎç/^Ü«­=›—W][‹ÓЉŃLjÅâ¡°³³3 àÆX-Å¥T0±Â\ ˆˆéŠIc“¸¸¸?ÿüS$áñx¿¥K·òÉ$Ù3ÉŒDr°·ZµêÏŽŽï““?Š<æÛŸ~b ‚?ÿüsÛ¶mûöíSu/‡+{ ÌaÝÝݪþpƒÅb1Œ¾Þ^#£¼cÇìÚ%g†f$RâÎCÆ$íÚ•›‘alhØ+^¼x±²²RÕ íÔmÛÛÛkkm}ýìÙ™˜.Z3kÆŒ¿þjceÕÛ۫ꎶö@ÊÈØØØËË+!!áÊ•+$IUŸTnß¾ÝÚÚJÔ×?›šJÂhÍbYHÆÆgSS‰úúÍÍÍÅÅŪî®0·Â|”˜˜H"‘¤§¡Ÿ’’’ :säˆ2ì‘`jbr:9Ù?$$))ÉÃÃCÕ=~ eØa>™ššŽ)i¤°ÙìßïÞõ£Ó©ŠÂ€ ÿX»v*öµk/¼Yµy1öö¾ÿüçݪ*¹E“U‹’ìÔgTTT$‹·mÙ¢pëÅÂÂ}éé{öî}ðàÁž½{÷¥§_|³nü°b$|ñÉ'"±øúõëªîô_(ÏH}úõ×_çP©fÌÉŽœ8±oÿþ‚‚GGÇ‚‚‚}û÷9qb1ÌLMfÌÈÎÎVu§!HÉö@ê#ÐãúúUÞÞmmhjš9sfFFÇËÈȘ9sfCSÓb¤¬öñ©{ôHÕVº=úóùs¨Ô¶Ú’ɵµµ¡¡¡!44´¶¶Ö–LAŒG*~{¹äÑgìÔG ¡p’©é@[7}øaLt4Nÿý÷ßétzLtô¦?AŒsSSAO û;:ö@êsC†MŒŒÚê¿l™H$ÚöùçM--d+«˜ÐPÿeËF#…dbÂWÝMB£f¤>ijjÂ0¬7qâ@+½¼Vzy ¾$1ø|¾–¦j>ÛÑ´RŸCÉĤ“õæ^s8¦1•Ç(Û©@6drCK˨5×ÐÜlcc3Ê}}{ õˆbo_[W7jÍÕÔÕQfÌͪÄH}rqq)«ªµæJY,6jÍ©Ê[Äbñ«·‘½Y†aÙM\.wº'ÅÃÃãNe%Oæ§íÏžý300rÛ6î0! ·«kS\ýƒž>{&­äðx¿UW»¹¹N×Th„­@\.wÖÛtttH·feeÉnúè£F§‡ i®®yEEÒ sóü' ‰Ä…ï¿þÒ%‘H4¬ŠD¢sùù ßßØÈˆqìØss馼¢"w77"‘8 ýR­=ú   I9uJVmío·mKûñǃ¿üâêç—•“ƒd4âðxY99®~~É™™é?þøÍçŸëhkK·ŠD¢ÔS§‚CBF¡G*·RŸó@yzzꌢ"¹€ó®eg;.]š{ãFÂþýógÏv[°`…bkmM$zzËã547?xô¨¤¢¢òþýyNN]ÝÝe¹¹pòÿ9—/ ÜÝݕݱ`¤VA”°kׯ°°%îî==Ùz·Öß_CO/%55:::ÿêÕ¥¥ --<Ããõõõõõm­¬ºù|sKËŠŠŠƒRmmûÛÃáñ¾þé§ô£G•Ý‘1bAãú1é’µ2†Õ…mqqœŽŽä~?0jhn^ά¨puqÉJNž®è,Î1qq&“'óí·ÃêÂpÿcÇH­æ@vÆÇ?llL;uJ®ÞÖÚzŠ™ÙîÝ»'Oš4}€s€ƒÇ¤œ8ÑÐÖöÕÎJÍLÙ©¡@x<þøñã)§NÍ˓۴fÅŠ£Gøúòöb²Œô3g2Sê¯ Çš= A……EÖ™3{N}{ò§Ó'›™ùÓ郼ןN·²°‹I9q⇟>•¥Ôå§P>AI¨ÝHJ{{û†õëíÈä½_|!7§F·«ë³¯¿~ÒÚšyìØÈìA8ƒcu$XXXä_ºd8iÒÂU«.ŒàDâùK—®Zelhläñx.—H èëëÛÚÚRfÌ Ñhn˜^çï+Tß…q¿úN¢˜ @€ @ *€@T¨P @Å»p-  BÞ…ŸõŒ÷ÿq?8„P @€ @ *€@T¨P @Å»p- CØlvIIIé;5uuMó»»»¹Ü‰‚îĉäiÓ¨vvî®®îî†ªÎtðüKkêjš7ñ»ùÝÜ‰ºuÉÓÈT;ª»«;¶ù¿ Wã1é­[·Ò23™ååV..ænn${{£©Suôõµ „.WÀ㱟<éøßÿž•”´0™.4ZXp°§§'&]À.ÿ4f9ÓÊÅÊÜÍœdO2šj¤£¯£MÐîáöxövÇÿ:ž•ßaãF;__m}ýÁã{x¼º¼¼ê”=½= óæÍCÙ,òßÎæ³6:ØùÚiëkßÃë©Ë««N©6Ñ3Ù“°eþj- Ã_ÆÇ¹íÜIY±ÎzÓb‘¨ŽÁ(ݵ˛Nß½s'qÐåÿeAQÛN7Ê 4œå²Å"q£®tW©7Ý{÷ÎÝ#Î_}'ÑmmmtŸû<^Э[?¿aÙAGñ÷ºy³šÃYæëÛÞÞ®Šüé÷y÷ƒnQü†gA8 Š?%èfP5§z™ï²篦ÕÕÕù¾÷žõºuôC‡†š£„üçêØéìHØ1¬wa,Pww7æÃ‹uùêÕEß}§¤ý/Þ»7ÿòåÊÊJeæyÑw‹”–ÿâüËùÃÊ_½&ÑÛããi_}…fÖ<8ÚmÇŽíññJË;í+šYóPùkÓvжÇoGþì266öòòJHH¸rå ‰DRRWGÀíÛ·_ñù”+d+…|þ~ÈZ¼øÐÔ©Y‹3üQÈ粓!ã)þþ\nqq±ròEYAQU·“‚(þ”nòü1(11ñþýûG ›5k–Æ0O®(•´ÌÌÙáá²ç{àׯÿ»lÙ¤öö‡×>xpòÈÓ¶¶ÿ._¿~­pHâ5p8‡ðð´ÌL%äŸ6;|vÿó=Â.aæ¢ÌÖ²ViMkYkæ¢La—pX1oò×pwHËLC˜Æ™ššŽ)i¤°Ùì;eev>>²•¬ýû—yx$8`oo¯««;cƌ䖹»³öïW¸„ñ_ßòÒÒÎÎN¬ó¿cçcד–ž–÷!(¼–’‚Ú˜myyËö-ÓÒÓVŒLþ”òÒr„ù«Ë¨¸¸ØÚÅEnöóäÒ¥ˆ°0i1!!ÁÎή‡Ïré’ Œ×&,,(--Å:ëf?Î~é~ù‘ùUiUŒ0†Ïa+w«ļÉ_Ûr%ÂüÕE 2&Ó¬ß:ÜÏŸËž7ËÈÈàñxçÏŸï|þ\áNÇ›»¹•”—cš™Íl g ××› 7D.È $1oò7/)/A’˜ºôàÑ#S*U®ÒÀÌLöPhh(@00Sü§BO¢Rk=Â4ÿ¦TÓAÚ˜måûÊÅ/bfIŽS#‹y“?©æQ ’ÄÔE –ÆFÃ~k NóñINI‘¿üòËGAššS½½îy¼‘Msc#¦ù·Ú´µÙ&9*9…:IŽSýý@#“¿Qsc3’ÄÔE ‡ƒ70«œ¿uëµ;w"?þ¸¶¶¶»»»¶¶vÓ–-×îÜY­p'Èãñ††<ÓüyxÅw\»„[ |ö••,œ-|ö-Œ)”û6dÌÛùãy’ÄÔåb*ÜÕ¥Õo'¼A`AAÕáÃÁ[¶¼hn6µ¶&{{þðƒæ7Ç ×Ö×ïær1Ì¿îÑÄ+þciéiß Öšø÷÷)Kš¥\ ’˜·ö©«wÃHSì?ï㣤x¬ÐÆk÷½ ¿uCÔ߃‘ÕHò…ø‰ˆn1S—CØxGŸ¨w"0~ ë]ð¬m¬Ù ìQkŽÝÀ&Û‘DÆT µ£¶cÔš{Qób&e&’H ÐøÀÍÅíYÙ³QkîYé3š’H,'Ñb±˜ÍfËÕH_Ã0üêÕ+iQKK‹@ ŒÚ'2Þñððˆù4¦‡×£¼{9¤8‚¶ßÚÜ»! ÆR .—;kÖ¬¶feeeeeI‹îîîÙÙÙÊþ,Þ ]h.uyu³ÖÎB¿·Á©Ï«wuwE¸.¬ºG„‡E®¡jàäïwHœ’8²}þçéäjÄ"qujuÒ×I÷7xzzšè™Ô1ê(þò÷”I<ÈtÎdd3Èd²ì¦ÆÆF¿@¿àŠ`„­<ÊydJ0E¾¢9˜D'ö$ì)ÝUÚÃíQ¸ušÏ´ä”d¹Ê釧zOE¸GPöuÙ· ß"O ˈH$ŽëJ}æÍ›çM÷¾w“žLï¿uþÖùçÞ;ùqdTD™Lnjj:xä ósUÎ*„û¿ñÙ _/_'''ä)hœ±{çnø!|7ínÿMx|`AàKòËà-ÁÔÙÔà-Á/É/ º +GUJUoCﮯv +5¨µ¬,mîÜÖ²²!bæÌyRX8ô®„a?}üôƒ”µgkûoÕÄk:Ç8^ Œzx-ðÿþó]‚•£6»¶&½æTæ©áþ*Rj-+»þqXXaxø@Ibâ¶n-ݾýnjêà»2 [,,,Îf­Ü[y7õ.ú½AT•RUùCåÙÓgG°ú‘Ú ÔÆdFD¤9yìèшˆ–’’b‚ƒƒ¯\ºôôܹ뱱"¡pdaÊ`úôéùó[³[ # šS#¡‡ÛS¸©ðé¹§—.^š>}úö ^µ1™—ÃÂÒ–|Muvv>–ž~%2RÖ!¹333Æùó/^0>üP sÂ0åaaaq%ÿÊÃ9'ž|xá¡X$ÖÛÅ"ñÃóO.<édìt™qyÄ+¯©‘@rr r)ŒÑÓÓ;ñË/nÓ¦{ï=N[ò0e£££óý·ßO;ÞòKËé%§ïgÝG2 8‚ûY÷³–dµf´žH?ñÝ7ß¡y„º<¡lÊ”)D“_RRhý~›APYYÙGá᎛6ý~äÈ@1¥¤¦þ”’â´e +1qÈ0ö L “?AqqqZfZyi¹¥³¥9ÍœD%Ùá‰xm‚¶€#pìvGMdzÒg­¬VWw×Á‘Ÿ-uÈiþüC?ý4П‚ ²²²ˆÍ›NN$‚ Ë……ŸÅÅ! ÛþÅU¿ý†¤ þ 8NIIIqYqm]mSCS¯«›Ó=‘8QO_lK¦R¨4777„×¹ .YÀ’—µ@€ @ *€@T¨P @€Šÿd%œnè\u´%tEXtdate:create2017-06-06T01:31:16+01:00m…%tEXtdate:modify2017-06-06T01:31:16+01:00À=¿IEND®B`‚puzzles-20170606.272beef/icons/undead-base.png0000644000175000017500000004270613115373724017674 0ustar simonsimon‰PNG  IHDR àl .bbKGDÿÿÿ ½§“ IDATxœíÝi@×Þð![@,‚hEKqÁD«ö‚ˆîZôº[¡j«ÕV«ÖÚ[e±¸T´UoíÕ*¸á† ¢@Å¥JUd‘E[°%÷CÞ››†$™ÌÉóû”9s2ùçy˜51xöì@"Ýh ˆ…€b!à€X8 ˆ…€b!à€X8 ˆ…€b!à€X8 ˆ…€b!à€X8 ˆ…€b!à€X8 ˆ…€b!à€X8 ˆ…€b!à€X8 ˆ…€bÑ]ÈÅ✜œÔ+Wnæääçó**j«ªÌ,-¹:ôèÙs˜‡ÇèQ£<<<è.“6’ñ¹|ùòµk×ŠŠŠª««‰‰‰……E÷îÝGŽ9fÌŒOê•Ô›97 ò x¼ÚªZ3K3nnž=†y =j´>Ú<{öŒî˜¡®®îÐáà ûö5š˜8ýãöC‡ÚôìifkklaQ_]]ûêUy^ÞóÌ̧/²êëCCBfs8º«ÖžºººŸ~ú)..®¶¶V 4444íÃf³MLLÌÌÌÂÃÃgÏž­oãsèð¡„} &Nÿp²joÓÓÆÌÖÌØÂ¸¾º¾öUmy^ùóÌçO/>eÕ³BCBgÏÒ«ñÑœJΜ9³æ‹/ì è¿ti—”w~ž“s'>þÕÝ»ßlÜèçç§ éuæÌ™•+W ‚ÚÚZUú›™™q8œï¾ûNÆgÍkìØõ_Ú¿Ë€.Ê;?Ïy~'þΫ»¯¾ÙøžŒæ àZ V®^öÛo£¿û®ë!ª?±433522ÈÏï‹5k 5W!½ADDÄùóçUŒ6Yfff3gÎܰaÙã³rõÊ´ßÒF7ºë®ª?±4³4525È/è‹5_<>š†€S¦ªªjÖ¼yuvvïGE±ÍÍ[ût~eeÊ¢Eölö¾ï¿·°°PÞù“O>9r䈊KÞµkWPPPkëQ»ªªªéÓ§?zôˆÏç·m fff}ûö=xð`‹ãCQT^^^VVÖíÛ·óóóŸ>}Êãñ¹¹y‡z÷îíéé9iÒ$;;»¶U¢ UUU³æÍª³«{?ê}¶9»µOçWòS¥Ø³í÷}¿ÈñÑ\³Á´à`q¯^ïmÞlÀjãéæF¡ðòªUV/_JLTþ˜q'&NœøðáC@О嘘˜xxx=zTÉø\»vmåÊ•%%%ÊÅf³CCCW¬XÁf·:MÔN L ž&î%~oó{,ƒ¶-¤QØxyÕe«—V‡6>ÚËDšµjÍš:;»ö¤EQ,#£1ß~û¬¾~ã–-j¬MDFF>zôH’nF††\KKSÇÅ2åp¸––FMÖÆæú‚»wï®_¿^Ékµ¸öRÕÐÐ3þ|…§8´lÕšUuvuíI7Š¢XF¬1ߎyVÿlã–Jº1q|´—‰(væÌ™kÙÙ3ÎkOºI°ŒŒÆ&$õ÷áéùþûï«¥<Ú9s&%%…Ïç›™šrLLfúÝí­·l¬­Ëß¼).-=—šúï¤$@P[W×rŸÚÚ#GŽŒ5J-ãsùòåØØØˆˆˆö/ªÍΜ9s-ûÚŒs3Ú“n,#ÖØ„±GýŽðAÌøh vQ¨««ó9rL\\«Î*(WxéÒíM›®]¼ØÜކÜ.ê¢E‹:wîÜÜÒ|}}{ôè¡®ÚZ«®®nðàÁååå¦Î'‹‡7íV__¿çСí{öD.Z¤¼Ï¶Ý»ëøü·ÞzëÆ ÇçàÁƒŸ}öEQ–––~~~#FŒpqqáp8………‡ºråŠ\ÿ:ܽ{×Ȉžÿßuuuž#=ÇÄiÕYå /ÞÞtûÚÅkŒ6‘ÿÛàÐáÃvHÓ­¡®îVllá™3¯‹‹;vëæ2~¼GXÛÔ´é•ôìþþûw¾ÿþç£Gƒ?ø@•¦M›æææ¦Æ7¥F?ýôSmm-×Ââp|¼‡»{sÝŒÃæÏ÷4¨Å>à ^ºôåË—ÿþ÷¿gÍš¥°§½½ýG}4mÚ4333iã;ï¼3~üø˜˜˜-?PQQ‘››Û·oßÖ¿958tøÝ;5¦EQÝßï~çû;?ý9øƒ`…4>Ú„cpòÄbq¾}ý—,‘Lòß¼ùyìØNee?ÆÇçÞ¿ÿÓ®]v¥¥?ûùñß¼‘{b‹=‡~ú鎸8Õ+‰D¯_¿~ùò¥N1‹Å;wî4 (åé&¥JŸîî‡ããY[·nUØa̘1sçΕ]{¥Âšníþõ×_-¾®&ˆÅâ„} ý—ô—ko¨mPøXõ>C?º#n‡Â'2h|´ '/''§ÑÄDz5oööícGŒˆ‹ŽîÓ§©©iï޽㢣Çz{goß.÷Ä{: ÔÀbݹsG•2/^ìâââîîÞ¯_?''§Áƒ/Y²äòåËb±Xo¶ rrrê‚O/V%¹T7ÐÝ}ùÂ…>_áø¼õÖ[&&&Í=—Åb5ÝaïØ±£ËS]NNN£I£ÜÕ¼ 5 ‰£K2J(Š*É(I•ØP#Ÿ_-öqäÐÀj`úøhN^ê•+N>>ÒÉü3gB.”ëºpaþ™3rªôtòñImr@D¡‚‚Ù ·²²²“'OΞ=;  ¨¨H•%hÈÏ?ÿÌ62 –ßQ**)™øá‡.žž?ü°¨™3zÊû,š=ÛÈÐðçŸnCU¥¥¥²“l6»gÏžmXNû¥^Iuòq’kd›³ýcýO…žÊÙ“s*ôÔØmc›^§J'§Ô+©m¨JwÆGËpònæäØËœ[¨|ñ¢k×ÿLqpp (ªk×®•/^È=Q•žöÆݸu«=åݾ}ÛßßÿÉ“'íYH{¤¦¦Îœ8±éƒÈ¯¾š0iRnnî„I“"¿úJás•÷116žtùòåÖ–tùòåââbÙ–É“'s¹ÜÖ.G-næÜ´bß´½ë®ž‘žW6\¼tp7ïn ŸÛbûaö7nÝhmI:5>Z†€“WŸo#óÏͪsç²²2é¤ä¤sii©U“ƒªô´éÙ³ ?¿¾yófÁ‚B¡°Ëi›Úšš±ï½×´ýþÌœ9ÓÅÅeæÌ™÷ÿøCás[ì3ö½÷ª«ªZUOiié'Ÿ|"ÛÂår###[µ5*È/°éiÓ´½4³ôƶ£ÖÊŽÏ.N/nÚA•>6=m ò ZU®–!àä½yýÚ¼S'édÏñããäúÄïÞÝÃß_®Q•žævvo^¿n­­§M›¶cÇŽË—/?zôèéÓ§·nÝÚ±cG÷îÝåz>yò䨱cª¿)5âóùNŽŽMÛÝûô9tèГ'O:äÞ§Âç¶ØÇÙѱU÷E<~üxÒ¤I²ÇËÙlöîÝ»U¨o^¿1ï$W_CMÃÙeg¾ðñø> %2Eá1¸û˜Û™¿y-vK -Ãupò>‘~e屉‡¹»‡‡†:;;ÅìÚ•yÿþ”'8VV²OT±g”ƒƒÂ1/((pttTxMuuõäÉ“ïß¿/ÛèããsàÀö¾ÛÖëÚµkño¿6¹þ¹¨´tÅW_ݹ¿Ÿ›[Ô—_:¿õVÓç¶ØGÔØØmÐ Ù a%RSSCCC«d¶øŒ÷ìÙã#sUûÞr|kyÑrCùë{jØfì¦[ÕG,G;G—–”6yªº9>Z†€“'pE ùüœøøÂÓ§_>}jçääìï?0,ÌHÑwu©Ò³¹€SîúõëÓ¦M“m±³³»{÷nk—Ó~NNN¹W®˜+º¡ýªkjÞ=ºèéÓ{îÝ»wÆ "‘HÚÂårøá///M¦:—·]ÝYÔ†[ëUQ_]¿oà¾'Z>«³ã£e¸Ð·eFÎÈÈ!*¶P½gk ÌcXss1>Z†€Ó ñññS§NMOOWx£Â‹/š~›]SFuáÚ5館±qSt´W`ॿ¯W-ºží¸yçÎÆÆFiãùk×F¥°zzúøñã ¥-Ÿ~úéÎ;uêÛÍFýôBËÇÛ¦è|ÑèQ£ÎbÊøhŽÁ銌ŒŒŒŒ gggÿ!C†8::ZXX¼|ù2==}Ïž=¯›\\2}útZê0`@½P˜óûï’[µ Y¬µË—{´):zûž=_FD î/¦œ[÷î}·kWAqñ¦U«|d.©»uïe`Ð_ÑÓ/^¼ØôÒ?OOO33³={ö(|•Aƒ hé×34aÀ€¬zÖóœçö .÷mg·žSÆL-CÀé–¢¢¢øøøøøxå݇®’ä„„„Ä<¸÷_ÿ’6¾ïí=ÊË+lõê+¬¬¬|GŒ2`ÀÛÝ»w´±áZXðª«_——çfÞ¾}þÚµJohÿþ×~ýÕäï·CÄìßÒä^7‰‡6½°Yò/¡¹:W­ZEË l``z$þˆýÞ¿\”CTkõɳ¿] {;ævhH¨Âž -CÀ1··wtt4Ïšµk׮̜œ¡2¿àiÈbE.^ÿæ¶‘Qù›7¼êj®……µuƒP8dذ˜¸¸Å‹­ “K·ëÙÙóóTû.)7+xVÌ®˜ÒÌÒ·†þïB?iZýâ÷KÌÆéiñìììeë–M;7MÁ‚d”\/©|Xœ ø»’ 98§† Ö§™«ÿe™››öÙg‡¦÷39ÎÆM›"¿úª’Ç“mïåâÂ20077þüùú+2’“¦¥=»}ûaZZFrò—Ÿ|òüùs33³F‘èí¿ß›ñ¦²rå¦M7mRò• Âáp¾ÙøMjd*¿RÁoñô]ÒwY䲬¬¬ººº¬¬¬e‘Ëú.iá{Ùøoø©+S¿Ùø ã£MØ‚Ó ï¿ÿþûï¿ÿäÉ“´´´[·nåçç—••UUU‰D" [[[www//¯   U~]I üüü²23}ú顨XÙŸ_íåSR\<¶É¹¿Ñ£×GEÅÆÆ¾ïí-Û.jl _»v|@IWØûùùÝȺ‘²(e¡ ,£¿mF¸¹ŠÅa«Ã^½²u¶íÙß5ÈUÉ¢Ä"ñ…ð SÆO!i|´w2È“½“¡$#ã\X˜_\œ£¢S–%ç–.ýõ×=›Ü—ª¤CÛîdÐA"‘hîœ9¬¬¾]»Všqç¯^·|ùš> Ÿ?¿éSb~øaKLÌèh鹡H´jÓ¦WUU‰°Úýó:E$Ï æuâùvŒ\Æ©®Qؘº*Õê•Õ¡ÄC„v`ÈšU’‘qnñâ.LY¼¸¤ÉÁZÉÜÕ7¿ü2{ǪÉå-v`:CCÃï^òx³ÂÃßTVJ‡ÜÕÞ>xÒ$…O™5yò[öö^ÿ=üô¦²28,ì¿kyk¯¡¡á¾ï÷Y½´Jž•ÌÓ–ßå¿á''q_q÷Äï!o|´£¦XiffJhèÞ]»–.]z`ß¾”ÐÐb™ë¼¤sçÎ{)%¥úÊ•sK–e~ü¸Åd°°°Hšƒ€“çààÀíØñ‡„¹[222>\¼¸ß’%wvíj:W,ïØ¹sïO?y„‡g}÷’åeeD޹H$:zôh\l,ËÀ@ùupbŠú0$$88X¯Î ŠD¢Ÿþ¼#nG«ÁÙ×¹Ë.6oÛ˜u43ášx‚Ú×µåyåÏ3Ÿ/2/þpñ¬àYz5>‚€“ç1hPìÎ o„ÊÈÈ û>.®¹Û¤NŸ9³úóÏ•wX»nÝíö}k¹Ž»sçΕ+Wnegççç—WT𪪸––6:ôìÙsààÁï½÷žÂkñõÇ;wR¯¤Þ¸u£ ¿àMù›Z^­×ÌÚÆºGÏž=G½7JÏÇG½p@,œdb!à€X8 ˆ…€b!à€X8 ˆ…€b!à€X8 ˆ…€b!à€X8 ˆ…€b!à€X8 ˆ…€b!à€X8 ˆ…€b!à€X8 ˆ…€b!à€X8 ˆ…€b!à€XFtÀlEEEW®\ÉÎÎ~øðaYYYMM©©©­­­›››Ï„ LMMé®±e'Nœ8qâă^½zeeeåäääïï?kÖ,.—Kwu-(**ÊÌÌÌÌÌÌÊÊ*((¶ÏŸ?óæÍ4¦ 2>?ºÌàÙ³gt×ÀT+V¬8|ø°’öööQQQ£FÒVEmñòåË… fee5eooŸ0hÐ íW¥¢ÐÐФ¤$…³t?àÈøüè8좶݋/”wxþüùœ9s.\¸ zÚ€ÏçÏ™3GaºQõüùóÙ³g?yòDËU©®¶¶–îÚŽ€ÏîCÀ©‡££ã˜1cüýýÝÜÜdÛ…BáÊ•+uv=LHH¸{÷®l ‡Ã‘äñx«W¯ÖnQúˆ¡Ÿ݇cpíâèè8kÖ¬I“&9::JsrræÎûúõkÉä‹/.]º4ašjlV]]Ý®]»¤“\.wïÞ½ÞÞÞÅÅÅ!!!÷ïß—´_¿~=++kÈ!4•Ù›¡C‡6ÌÓÓ388øÕ«WtWÔ Œþü0®í"""ÜÝÝŒäÇÐÃÃcݺuË—/—¶<|øP? iii<O:¹jÕ*oooŠ¢ºuë3zôhé¬äädÝ ¸¨¨([[[ɤô#0ýóÃØEm»4ýtJȘçóùZ©¨uRSS¥Y,ÖäÉ“¥“®®®}ûö•N^¾|Y«•©ÌÎÎŽY¡&‹éŸF@ÀiDUU•줃ƒ]•(ñðáCéãîÝ»[[[ËÎõðð>~úô©@ Ð^ezŸF@ÀiDrr²ì¤ìîžîÈÏÏ—>vvv–›ëää$}ÜØØXXX¨ª€bÈç‡pê—ŸŸ¿wï^éä¸qã\\\h¬§9åååÒǶ¶¶E­[·®W¯^Ó§Oçñx’…A£˜òùaœšUUU-X° ¾¾^2Éår7nÜHoI ñùüÆÆFé$‡ÃÉÉÉÙ·o_uuuzzúþýû宩©©Ñzúˆ)Ÿ¦@À©ŸÏŸ7o^^^ždÒÐÐ0&&F7 ÈS322b³ÙÒI6›-;Iá8·V0èóÃ8µ©¯¯Ÿ?þ7$“,kûöí>>>ôVÕÙI‘Häîî¾bÅ ggç   yóæ544ÈvÛ µcÖç‡)pœz444„„„\½zU2Éb±¶mÛ6uêTz«R‚Ãá°X,é^j]]EQ‘‘‘‘‘‘’¹M6sss-W¨W÷ùa lÁ©ACCâE‹.^¼(™444ŒŽŽž>}:½Uµ¨C‡ÒÇÒëæ›k±±±ÑFMz‰¡ŸF@Àµ—P( MII‘LÅÅÅ1âo=¤‹ŠŠäæÊ¶°X¬îÝ»k¥(½ÃÜÏ# àÚE(.]ºôìÙ³’I6›½{÷îÀÀ@z«RQŸ>}¤ +++eçÞ¾}[úØÉÉI£??Œ€€k;‘H~êÔ)ɤ‰‰Ibb¢ŸŸ½U©Nö‹ÆD"ÑñãÇ¥“yyy÷îÝ“NâBSM`úç‡p’¡D"Ѳeˤ߶Èf³wìØÑ¯_?…Äš˜˜èàAú‘#Gr¹\éýö[·nuuuõòò*)) ‹ÅÒž4Õ¨ŒX,®¨¨k‘>æóù² 6›mii©½âZBÀç‡ð¾mtïÞ=ÕÿÙ~ðÁQQQ­§m¢££¿ýö[ÙSSSÉU)OOÏcÇŽi·.•ðx¼Þ½{«ØÙÛÛûèÑ£­§UÈøüè>좶‘ìÆs…††öë×O¶E.ݸ\î–-[´[”^ ãó£ûpzÃá8p ¹ïzëÒ¥ËÁƒ{õê¥åªÔÇàô]§NŽ?~âĉ_ýõÁƒ¯_¿ær¹ÎÎÎãÆ›={¶îÿª€8ÄÂ.* ÄBÀ±p@, ÄBÀ±p@, ÄBÀ±p@, ÄBÀ±p@, ÄBÀ±ôëGgè.€~úóK,Ø‚béל£ÿ}988 ~P?Ý%h¶à€X8 ˆ…€b!à€X8 ˆ…€b!à€X8 ˆ¥÷¢ªQEEEzzúµk×îÞ½[RRÂçó‰‰ ‡Ãqttìׯß{ï½çíímmmMw¥‘””DQT`` C—ÄCÀµÑÕ«Wãââ²³³«««Åb±t–@ •••<8yòdCCÃ!CÂÂÂFŽIcÁj—””.y¬‰ ÒôòA àZ-;;{ÅŠÏž=«©©¡(J 4×S,WWWS•–––““Óµkר¨¨j¯VINN …E………544L™2…AË=cp­Àçó—/_>sæÌ'OžHÒMu555yyyÓ§OˆˆàóùªP;’““ÃÂÂ$é#a`` Þ—] H$Z¾|ù±cÇÔû pª*--=ztRRR]]ì©êÄbq]]ÝÉ“'ÇŒSVV¦ö µ#))I6ÝŒŒŒâââ&Ož¬ÞW ˆ52úÿ= ‘H!9$ :œJ?~ìççWVVÖþ/>Ÿ_RRâëë›——§–Ú´IvÏ‘¢(CCÃèèh  Œ—fœP( Ãv´ ®e¥¥¥“&Mª¨¨®Øf¦¦\KKSÇÅ2åp¸––f¦¦rÏRÒG$½yófÒ¤IÌÚŽ“Û3544ܱc‡Ú·ÝdÈföU¡µè?ÉPTT”™™™™™™••UPP mŸ?þæÍ›i,L‚ÏçO›6Çã‰Åbc6ÛÀÀ ß;ïL›0¡oŸ>ììl¬¬Ê++_¼|y77÷—S§îåæ² Åbå}Äbq}CCeeå´iÓRSSMLLè~—-Ó~ºIPµtéRÉKK2Ž¢(œsÐ:¾þÒp¡¡¡:~`å³Ï>û믿9N Ïš?îÔ±£l‡Î¶¶mmÝûô™=eÊ_¯^}÷ix¸ò>_ïÜ™|á‚@ øë¯¿V¯^½mÛ6í¾§V£+Ý$q:K÷×_šwQkkké-@¹ìììääd‘PرC‡SDõ•\rÉélkõå—-öÙñÕWIû÷ÛX[ Nžuuul#zþLO7 d(„]TÅl;v¬äñ´örox<»æ÷ˆ5‡Œt“À¾*4…€S¬»³sAq±Ö^®àéÓîÝ»kíå$HJ7 dÈAÀ)æÚ§OîãÇZ{¹»öî­µ—£HL7 dÈBÀ)6lذŒœ­½Üõìl///­½©é&Œ):O2ˆÅ⊊ ¹éc>Ÿ_^^.d³Ù–––Z«mĈ+W®¬®©±07—´”ýùçÜ?îåâ²uíZËÿ6¶VUMͪóŸ>MܾݡKI#¯ºú·{÷â‡WOé-!;Ý$pÎA tyý•2xöì™ö_U‚ÇãõVy¿ÌÛÛ»ý73988P¥â[^0¾ï°a3'N”¶êë7DE»reíÇOôóc±Z±ýÛØØøëÙ³›wî7fÌ&ÆÆÒY‡ýõrvöÞ}ûT| íù“Ñžní¬¿UN:%Í8ê¿?‘ÓÎŒÓfýšÐªU@9í¯¿m€]ÔfÍ›??áÐ¡ÆÆFi‹‰±ñ׫Wïù~ð râ„g``\bâÞï¾Ûüé§²éÖØØ¸ûСyóçkä=üíé¦eØW\׬‘#Gš[Z&_¸ wî@w÷KGöóñIJMݰ}û ¾}‡ü®««‹“×ÒÒÒÜœW]]U]]ðôéýGÒ³²nýþû@šÚÚŒ¤$Ã&}'γ´²òööÖôÛÑ·t“À¾ªžCÀ)³á«¯-\8ÆÛ[î ‹Åšd`nž°{wDDÄé‹S¯_/(.®®®æUWs-,,,,\ºu«­«ëâ蘕•ãæâÒ4ÝxÕÕ›vîTqç´=ô3Ý$qúŒÎ€ãr¹:~8càÀ¾¾¾Ÿ}ýu\“@û (hêâÅ+W®¼{çΑ¸¸·]ÅVðôéÔÅ‹MMM=~üH\\Ó«6m7nœ‡‡‡Fªÿ/}N7 dœ&èþúKá\‹¾\¿þaaážC‡äÚ]œœ:wÞ¸q£}§N Ó­Å> ?þXPZúÅ—_j¤îÿBºIàxœ~BÀµ€Ãá,(,¬®®æUUq---,,\\\\{÷öòò>|8—ËU×+p/$ê§‘ÚW‡-¸vár¹þþþþÍÿÀ Ð'€X8 ˆ…€b!à€X8 ˆ…€b!à€X8 ˆ¥7Ûè9ýYëõñf{Fÿu ø6 ÔO#}û]T ˆ…€b!à€X8 ˆ…€b!à€X8 ˆ…€bé㽨jTQQ‘žž~ýæÍ=yRW[[[UefiijfæÜ³§[¯^ÞžžÞÞÞÖÖÖtWªØë¿þàñƒ¢'EuµuµUµf–f¦f¦Î=Ýz¹y{zërýÊéã·‰¨å-_½zuObbæ݆ ë2|¸mŸ>zô0±°0¶´¬¯ªTWWäç¿úã?ÓÓ‹33‡yy-œ7oäÈ‘í]uÝì}õêÕ=‰{2odvÖ­Ëð.¶}l;ôè`babli\_U/¨TäW¼úãÕŸégó¶pÞBªŸ.ÔO1üû&Z×jÙÙÙkÖ¯¯¨«s_´¨W@€±……òþõÕÕOº—ÐÑÜ|ˆ lÏ«·ËÎÎ^³~ME]…û"÷^½Œ-Œ•÷¯¯®|êñ½„{Í;nÙ°…öúéE@ýŽTíüëòùüµëן½paø—_ºN˜@¨þ\qcããääë_}åïë»ñË/9NÛjhÏ Æçó×®_{öÂÙá_wàJµ¢|JÜ(~œüøúW×ý}ý7~¹‘–úuõSúp8É ªÒÒRßñ㯮ž}õªk``«Ò¢(Ë5(hö•+÷x¼±eeeª³9¥¥¥¾ã}¯þ}öÕÙ®­K7Š¢ X®A®³¯Ì¾Ç»76`¬öëhœJ?~0q¢Sp°oll‹û¤J[ZúÆÅ9Θ1>((//O*÷øñ〉NÁN¾±¾-î“*aliìçë8Ãq|ÐxmÖÐ68‹Ú²ÒÒÒéÁÁƒ>û¬ÏÔ©jYà€… M¬­§Ÿ>q¢k×®jY¦¥¥¥Óƒ§úlPŸ©}Ô²À ˜X›L žvúÄi-ÔÐfô\QQQffffffVVVAA´}þüù›7o¦±0 >Ÿ¦ý?ì¯ö%X4àÅë6¬ûöëoÕ¾p`Ý_i>W[[KoÊeggŸ»xqÔ7ßhhù£·n=}îÜ­[·4´üìììsÏúf”†–?zëèÓçNk®~Ðq:¾þR´œŽ[³~½×_´ç¬‚rÆ––^ëÖ­Y¿^CË_³~×^í9« œ±¥±×:¯5ë×hhùíDÀÙØØŒ7nÆ çÏŸ·µµ¥»œÿ¹víZy]ë„ ² uu7ÿõ¯#£GÇöèqdôèÌï¾k¨«S²û»½ªªJKKÓLýå®\TUÛ –Š¢\ƒ\_U½ÒDýÀ:»þJÐpQQQ¿ÿþû¾}û.\øî»ï´òâ2Ú“˜ØwñbÙëÝøoÞüãÒŒ¡Ÿ mî}9¹Gsì}p(ñ~õt®e%ç/þhá”ŋ›Ë8IŸÏ–/¿¾fÍíÝ»•/ªÅnêÕµk×_Žürkë­Û»lǵANBέÝúåð/jY €† àZPš™™ºw×®¥K—Ø·/%4´8]þ»¹¥}æÍ›wþÌ™gÇŽ]^±¢±Aþ«ÓTì¦ o¿ýöé“§KŽ–¤,Mi*ê«êS–¤<;öìÌÉ3o¿ý¶+М2¥™™ç.Ü/¹ bÈ!öî=¿t©lÆÉõéܹsòñãV/_&ÿóŸ™ï°T±›ætíÚõüéóý­ûÿôÞO}(n·üâFñÃãzï'sÉç°íŒ€€k–\$IÈeœÂ>æææ?þðÃðž=MœÈ+-U½›¦™˜˜|ûõ·÷,þ¡øð˜Ã¿ù]•­9Oðû‘ߌ9R²¿äǽ?~³ùw¦0Ðý½j$ÙîPå-;88p;vü!!Á«ÉokQ•‘‘ñáâÅý–,¹³kWs}(ŠJؽ{gB‚DzeÙQQ-v«xþ\ÅÂÔò'KKKÛ“¸çÆõŽC»xu±u³íàÒÃå[ xA• ¢ âÕƒW^ÿ³$»ÄÓÛsѼEj¹šW]õÓ…€ú)ÕV2 àó4(vçÎæ"‰¢¨ŒŒŒÐ°°ïãâ”ô¡(ê\JʪÏ>S¥ÛšÏ?Ïùí· Sï ÆãñÒÓÓÓ2ÒrçÕT×Ôòj͸fææÎ.În®n#¼F >\÷™L¯ŸBÀ‘Š€¿.+ê§«@«à ÄBÀ±p@, ÄBÀ±p@, ÄBÀ±ôñ^T=§?k½>þ.*£ÿºÜìúi¤oÿ㱋 ÄBÀ±p@, ÄBÀ±p@, ÄBÀ±p@,认¤¤¤¤$º«h;¦×O}¼Ù!)))<<\ò800ÞbÚ€éõ“[p ‹’““ÃÃÃ…B¡P( ;vìݵÓë't‘ô±H$Z¾|9³2‚éõº( 66ÖÈèÿ¡ˆD¢ˆˆÏbzýÄ@ÀŽ Œ—fãöõ˜^?p »d3‚qûzL¯ŸtžE‰DüñGvvvVVÖãÇËÊÊjkkŒŒ¬¬¬zöì9tèÐÉ“'»¸¸ÐX!Ð. €¢¨¥K— …Bê¿AQÔ”)Sh®L5L¯_¹¢¢¢+W®dgg?|ø°¬¬¬¦¦ÆÔÔÔÖÖÖÍÍÍÇÇg„ ¦¦¦ôVHçΜ**jÔ¨Qí­6Óé]T‘H´ÿ~éÅD ·˜¾¯Çôúzñâ…òÏŸ?Ÿ3gÎ… ´SB:pl6›Ëå²Xò%%''_¿~–’@w0=#˜^¿rŽŽŽcÆŒñ÷÷wss“m …+W®¬­­¥«0:Á™™™3fðàÁƒîÕ«—­­-EQB¡ð÷ßÿöÛo¯^½*홚š:|øpú*ÀôãYL¯¿)GGÇY³fMš4ÉÑÑQÚ˜““3wîÜׯ_K&_¼xqéÒ¥ &ÐR!çããããã#×hdd4`À€ƒº»»óx‹ÅÚ¶mÛÔ©Sé­ŠÒ€“Ó±cÇE‹I'³²²h¼ÛéÁÜú-ZtñâEɤ䫦OŸNoU:pEÉÞÔ&‰^D ‹¹!ÁÄú…BahhhJJŠdÒÈÈ(..N¶Ý$tå\S•••²“²_rЦÏbVýB¡péÒ¥gÏž•L²Ùì„„???z«’EÛ\CCí[·š›ÛØØøã?J' ììì´R0·ƒd1¥~‘H~êÔ)ɤ‰‰Ibb¢N¥Eã\}}ý„ Þyç±cÇ6ìí·ß¶³³344¬ªªúý÷ß·oß.ûI}ûöµ°° «T`fm5¥ûõ‹D¢eË–IF‡ÍfïØ±£_¿~ /\511177×nÿæ]ÔÜÜÜÜÜ\餱±±ôAYóçÏ×bQ@ÝÏåt¼þœ8qB:ÙÐÐÚ\ç>ø **J+uÉÓ­“ ÓmܸqÓ¦MÓ~1ÀtLÙ×kŽ.×/‹é.A%´‹Å211QÞÇÐÐpñâÅßÿ=Î0@ÛèrF¨‚éõÓŽ¶]TSSÓû÷ï§¥¥eeeÝ¿¿¸¸øõë×|>ßØØØÊÊÊÕÕuèСS§NÅöÐN:¾¯×"¦×O/:Á™››ûùùéÚi Ó3Bëïׯ#~ÝM·ŽÁhÓ÷õ˜^?]p /˜žL¯Ÿ8Ð#±±±²!½˜K÷1½~íCÀ~ ”Ý …aaa ÚbzýZ†€½#·¯G1íNg¦×¯Mº{³=€æ466†‡‡SHwE­ÃôúµzJ M¦×¯8Ð_L¦×¯8ÄBÀ±p@, ÄBÀ±p@, ÄBÀ±p@,Ë€¿¡.t—@?ýYëõñÛDý×upp@ý4" ~ºKÐ*좱p@, ÄBÀ±p@, ÄBÀ±p@, G²¤¤¤¤¤$º«Ð]šŒ?íôñf{=‘””.yHo1:HÓãƒñר‚#Srrrxx¸P( …aaaÇŽ£»"Ý¢éñÁøë™ ¤E"Ñòå˱ŽI%''‡…… …Bi‹ìp©Æ_G àÈkdôÿ‡ D"QDDŽQ•””$›nFFFqqq“'OVï«`üuŽXñññÒu ûJ”Ìž£dÒÐÐ0::ZCÈ0þºG²€€ÙuLÏ÷•äöL wìØ¡öm7YÚѵ¨¨(333333++«  @Ú>þüÍ›7ÓX(ŠZºt©dÅ–¬cEM™2…æÊ´Kûé&Aöø;::ŠD"å}ÆŽ»ÿ~íÔÓÍŠšFö:¦ ºÒMãO#šwQkkké-@Oèó¾½é&¡ÏãO/ƒÓú¹ŽéBºIèçøÓŽþcp666C‡6l˜§§gppð«W¯è®ˆXú¶¯¤;é&Aðø8pß¾} gq8-#‹æ€‹ŠŠ²µµ•^©öë-AÁë˜]K7 RÇßØØ¸S§NtW¡ÍgggGozˆÔuL–n¦›„>Œ¿î ´ìuL—ÓM‚¼ñ/++ûøãóòòjkk;tèðî»ïúùù >œîºpúмuLB÷ÓM‚°ñ/.....–NfffîÛ·ÏÓÓ366ÖÞÞžÆÂpU‘w^)é&AÞøË¹qãÆ¸qãdƒOûpz¤uŒYé&AÒø+ôâÅ‹ ´x·ƒæ àôëÓM‚Ñãonn>cƌݻwß¼y³°°°  àÂ… ~ø¡¡¡¡´OnnîñãÇéªÇà€ñǃ˜›nÌÿììlKKKÙ77·7>|Á‚ÒÆãÇO›6MëÕQ¶à@‚¹ÛLO7 †Ž¿\ºIùùùùøøH'³³³µU‘<ü?&®cd¤›Ç_ ///éãÚÚÚššZÊ@ÀÁÿ0k#)Ý$˜5þÊIß…„X,¦¥ ü SÖ1òÒM‚)ãߢ{÷îIs8 ZÊ@À<Ý_ÇHM7 Ý @Ðܬœ8qB:9pà@­T¤gQÅbqEE…\‹ô1ŸÏ///—N²ÙìæŽh‚Úéòy=²ÓMB—Ç_êŸÿügçÎÇ7pàÀÎ;Kÿú믤¤¤¨¨¨††iO–΀«ªªz÷Ýw››{äÈ‘#GŽH'½½½=ª•º€¢tuÓ‡t“ÐÍñ—%Ž;&Ù´455µ´´äóù<O®[Ïž=gΜIG…ëà@ ][Çô'Ý$tmü•¨«««««kÚÞ±cǰÙlí—$cp ŒîÒ·t“Ðño//¯”””îÝ»ÓX¶à º°¡Ÿé&¡ ã¯Ð?ü–––ýàÁƒââ⊊ ¡Phiiéàà0dÈ   ¡C‡Ò[!EoÀq¹ÜgÏžÑX¨ˆÞuLŸÓMB73®cÇŽ'Nœ8q"5´»¨ ºö•nŒÞW¥T¥ýu é& ×8h…€€€ØØXÙu,""BC?Ý””$›nFFFqqqz›nÚ2 à ue·#„BaXX˜Ú·#’““ÃÃÃe·Ý¢££i¼^Twhgü‰€ƒV“ÛW¢4ð{² Ôó=Ó¦´0þÄÀe"ÐáááEÅÆÆª}ÛJÓËg:ŒŠpÐFÒ•JCk—¦—ÏtU à í4½jaÕUãÓ"ƒb!à€X8 ˆ…€b!à€X8 ˆ…€b!à€X8 ˆe W?ûâàà@w ôÓŸµ[p@,ýÚ‚½‚-8 ˆ…€b!à€X8 ˆ…€b!à€X8 ˆ…€b!à€X8 ˆ…€b!à€X8 –Ý0[QQÑ•+W²³³>|XVVVSScjjjkkëæææãã3aÂSSSºklYccã‰'Nœ8ñàÁƒW¯^YYY999ùûûÏš5‹ËåÒ]]ËPû.9cIDAT?4_YÞv+V¬8|ø°’öööQQQ£FÒVEmñòåË… fee5eooŸ0hÐ íW¥:ÔJ`µí^¼x¡¼ÃóçÏçÌ™sáÂíÔÓ|>Μ9 ×.Š¢ž?>{öì'Ožh¹*Õ¡~P§ŽŽŽcÆŒñ÷÷wss“m …+W®¬­­¥«0åîÞ½+ÛÂápd'y<ÞêÕ«µ[T+ ~P×.ŽŽŽŸ}öYfffffæO?ý´wïÞ .œ:uªcÇŽÒ>/^¼¸téE6§®®n×®]ÒI.—{ôèÑ‚‚‚›7o¾ûî»Òöëׯ7·‰A/Ô-BÀµ]DDÄõë×?úè#GGGÙvuëÖɶ<|øP»¥©$--ÇãI'W­ZåííMQT·nÝbbbd{&''k»8 ~h®í `d¤ø4´Üa>Ÿ¯•ŠZ'55Uú˜ÅbMžnll,,,ÔNUªCýÐ"œúåççïÝ»W:9nÜ8ëiNyy¹ô±­­-EQëÖ­ëÕ«×ôéÓy<ž¤Eagú¡E85«ªªZ°`A}}½d’Ëånܸ‘Þ’âóùÒI‡“““³oß¾êêêôôôýû÷Ë]¯PSS£õ•Aý  œ:ñùüyóæåååI& cbbtóœÜ1###6›-d³Ù²“”î'Aý  œÚÔ××ÏŸ?ÿÆ’I‹µ}ûvz«jމ‰‰ì¤H$rww_±b…³³sPPмyód;ÈmPÐõƒ*p³½z444„„„\½zU2Éb±¶mÛ6uêTz«R‚Ãá°X,é^R]]EQ‘‘‘‘‘‘’¹Msss-W¨êU` N -ZtñâEɤ¡¡attôôéÓé­ªE:t>~ýúµÜ\¹mÔÔ¨Z„€k/¡Pš’’"™422Š‹‹Óåm7©=zHÉÍ•ma±XÝ»w×JQ­€ú¡E¸v …K—.={ö¬d’ÍfïÞ½;00ÞªTÔ§OéãÂÂÂÊÊJÙ¹·oß–>vrr’;f¤ P?´×v"‘(<<üÔ©S’I“ÄÄD???z«RìÕ‰D¢ãÇK'óòòîÝ»'ÔÍ •Q?´×F"‘hÙ²eIII’I6›½cÇŽ~ýú•+¢›19Rö c·nÝš‘‘AQTIIIxx¸X,–Î  ¡¾– ~h¾Ñ·îÝ»§úÆÚ|¥ÑzÚ&::úÛo¿•m155•œÑ“òôô}>fÍfeÜÜy••eÌÌlããm™™„±±±oÚokÓkX¯Xeàà•²•nínxðx—¯¯zîî¾À¾aÆa^•^SžSW­WXÅÅwööbÂÂ[ÍÍ‚ºº‰©‰]Ó]rÇrT§§Tªªv——”¬”eÑeÿÿÿ^.[—bKGD‰a&ÌtIMEá$J¾"´3IDATHÇ}‰BGtfv’L»ìÆ®!Ù$$  ›¶Ý‚b‰á¨¤„ªE<[±Újé¡VzØÏî›Ùk6iû²™}3óÞ¼{Þ"„FÄ KÜa£p;$Bc±§ù+0ÁšÂ!ôÞáá%>æòQŸî?ÇâT™ÒD‚Ðû Œ%‡RÃ,ØÒÔˆiùv…ª£Fb,™fÁ;—Éæ˜·¯a—&›g‰PÖhúüh.ê0×dÍ_Â…ôð˜o3ÖXnx|ˆúö㛫'›˜œ˜âÆlzd$ÉêJ-" Qs8[TœLÌ¢ê´X"TbcL[þùa hR¡Àö<úÀÊ\bQZO‰Q µ¬üaÁ¶m?tX ’¤\‰@5$$H¿|&;­ÂLd–­r%Þnd²6`1]¾k,´ß;%Òó%P_nJûëb´`PóÙstR&çT:=:ËDB‚Ìl$±JÀ`ÍL^¸pñâ8Óȼ¯›ÈEc\J¹[IDòç ‹K Íf¹PÉK–t)(,JÃL¹u—L°âå…Ls9såCHXÃ%›ÈYžG½à²ÖH^º) ‰tey´±ôQseÕ·ôaêùb©’‚2Ö$ƒ±¸¶²²²°¶6±)ä}X㞊fj2}•Hx¥ùñ'KK«¹*‘±ð|L<$V4‹"UBtu-Ûhf?̓ÁDN'÷…0!Haµ±¸|y5 bÅsŠ>ƒ ¸k9qItâËÌ' Vë/L$?ÒR&nÀ¼¸ ›y1±oµ‰Ûý ‡(+ Ùü¨ò¼q"à ª–˜iäév>¢ðæsÒ¶‹OlÃÇ0EŠÇ–Eˆ‘ÙÒÚÌCóPo¯›SxHeg=å<ßʰ ~•˜i–#7^9'L˜«´ïC„ì#Š~Š˜ f ¢‚+#(Û‰{ÐRy^åýiýèÂëá%tEXtdate:create2017-06-06T01:31:36+01:00/¸‚~%tEXtdate:modify2017-06-06T01:31:36+01:00^å:ÂIEND®B`‚puzzles-20170606.272beef/icons/undead-48d24.png0000644000175000017500000000541713115373750017524 0ustar simonsimon‰PNG  IHDR00Ø`nÐgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEá$J¾"´ IDATXÃ͘]lÕÇïÇÌÎÌîì‡?²rì¬c'Ø8v> nŒT7F$E(¢(&Áæ%|HEy€—(H­¨xˆ*Q I¡•"ñ"¢DÈEIC„„!iœ`¡rì8¶wݽޯ™¹3÷Þ>Üxm¯×›ÅðÐûä33¿sÎÿžsî…‘Hü?-ôSæœsÎ^㟤ªª,ËŒ±{Z2Æ$I*Çxå@ÂÑÑÑééi]×K»Î9w»Ý©TjzzÚãñ”6^ ¥T×õ¾¾¾p8ÜÓÓsüøq]×—s1æñxvíÚµsçÎ3gΔ0À•‰!tóæÍ7¾ùæ›gÏžýì³Ïfff*⥴ººú±Çkoo§OŸ>wî\2™,j¼ÂlÛnkk‹Çã~øa8fŒ-—¡iš„‰‰‰ááaJi&“YŽf…@œs—ËÇÃáðÁƒ_xá…d2‰1.aLéìììîî6 CÓ´)“V$dqàÀK—.UTT :tȲ,árL½½½GŽAíß¿_’¤º^‰†8ç’$}ùå—Ñh4™LÖ××ïܹÓqœ@ªªž={Ö¶íÝ»wÛ¶]âå+5ç\×uY–1Æ„T*µMÞÞçóAgggK[– ´4ÈŒ1ƘxûrZ¸(¥E- øÊÕ,˲,—ß(Ê\BBÈÂt—„ŠÇã‰Dc\“$IŽã”CC)]½zµÏ磔 ¦{qÎBï¾ûnmm­ªª÷족±±P(TZ+Ȳ¬îîîÊÊJ‘в€ „¶mƒÁ—_~YDBÈ9Ïû$ D­ãœcŒ:::JT&ÆBHY¢kŠ\ûýþ}ûöE£Ñ—^z©¨ðï1Æt]ÿâ‹/öïßï÷ûÏŸ?/†©…ø¢+ÍÌÎþ­¯ï¯¯¿þ›G½uË4Í–¦¦«ß}wä½÷Z[[!ËѧŸ~:‹9sÆqBÈRáßõ!”ËåÚÛÛ=*:ßRSι¦i¾úêÀÞ½þú×>vl&öz½zçššš?<8xá‚$IËÑTTTšO?ý”²\h™bz*:N@lÇQjjlœŠÅ¢ñøt2™L¥"ñx4« «}¾¬aäS&ÞMooožÆ¶íå2;ïh™n·[’$¿ßoÛvÑ!AQUÃ4u]ÿËk¯1Æ8}‡¥2™t&£¨*‚0ï „P$=ìÛ·¯šy J©ÏçëïïõÕW#‘Èž={úúúÖ¬Y³(ÍBüUUñD"Gb±æÆFáÍÉIY’ê‚A—®»\.Ë4ó!Çûýþ2c³!Dill<|ø°×ëÍår¢œ/J„–iÞ×ÔôùèèÖµkÿsíš×ã ø|Wøá™={¾ÙÖÝMæ”!Šç|ïÞ½ñx¼Lšy Ñäêëë[ZZ(¥¡L&S°ËÈùC]]ƒï»o]}½,IoÝ:4:º¹³Sw»-˺æœ{½ÞS§Ne2™þþþ2iiH0™s/ZøE;TåW>:>>~ëömÆXECC[}½,Ibã —vìØÑÓÓcÛ¶ã8åЀ‚Â!,Ê!vŠ$I¢upÎçë×­kjjpÆDq¹\¢—aŒ%IõZô—˵¥táŽ.küý5‘H,‰òGcá¢f„P*•ºsçN9!áœ{<áÉB™¦922¢(JÑZìv„P4 BÔÿ]ø«èÙëׯWU5?£•$ŠÂöíÛó œsÎ!ÄC1›ržBˆ1¶mÛ¶ÅÆ\ˆR ù|D…pó“L €¥ãc,—ËI’8§œ«Š"QšI§cº× %gpȲ,Ã00ƀʩ¦jˆ t: н:“YÎÈaˆ9(’ñBQëºÈårE‡¢Œéš6zãÆ¿ÇÆnkƒ°Ò0ºV­ÚÒÚš³mȹ˜(挩Wõ^ÿïõó‘óq5Xe®ê®íninÉZY‹ˆlѶ·m{hhB¸y󿢹cŒ¹UuèÚµãÙ¬ÚÕ¥bŒˆCø÷o¾yüâÅ]YÓÌ„2êQ=—N8'¼Û½Š¢&¬‰£CG{¯ô>ÜþpÖ,„ò_Ò4íêÕ«ápøÅ_+诜sÉåš¹}û£ÙYWS“kdmÛ¹~=ØÐð/—kxx8?t‹I229iž¬ê¨rs7Oqžâî©ê¨:ižŒŒGn®B „P6›íììüàƒò+0圫_˜HÔÔtܸQwêÔø•+¹ÙÙ]Ö[o™••WîÜ‘æ6!ç\Êàø Þ€Á,¸xìböN6;½xì"Or¼Ž*H2*ææ/¡ß¢ùâBÆb–婪—¤™PÈ_W'kÚ÷£ÖVouu‚RjÛw=€9,Á²[fŒÕn­•YrIµíµœqÉ-%X‚;E0…¢¨Daå¸JnÜHÛÚüsÆ&zH‘åü3ãAªŽåè>}í®µ†i¨@õ…|ÌbfÖT¡ Ñòš¨4Ÿ|òI8ŽF£===“““Š¢æBÀ’$·ª*”BŒÆ„Š$AŒÁÂê Ãlƒo™"–mEÿõ÷ûoœº1zn”ÚÔš²6ø6PL—͆alÚ´éý÷ßw»Ý¦iVVV¹Ð` iÚÌø¸ƒqŦMñÁAÉë­li‰]¾L<ž ¦å™D9+·åþ-—>¿ômàÛU[WIãRݶ:uµ:56Õ6Þ¶¥k‹aKwÙüøá8N0 …BâgF¡˜8G²œššúB¡ŠŠž>ýŒÏ—L¥ú‡‡ïvljѩ)ôàƒ`î)È!Áä¹_>÷ñ¥‡*‡â-qÕR FGºã©Î§"À`IÒ ëPþ̰´Xc³„ì~àªÊJ—¢¬^×ÜLm{ÓÈÈúæfê8‘HÄd ÍíP!sRг]Ïî˜Ø1™˜d€…‚¡ºëLf2‡ò E]âÒ @H'XSãPjÒÐÜœ3Maãý÷‹jC!BÈÂ+„Sž¥Ù`(¸¦a €P’%YÐrú×1ù( nË4„€üù\ôÑ»X €lbNÄŠvŒù ”ya%.+ˤ·m[8°‚Uî-¬Çã)ÿ¥%ÊØÏTp)½~ÊE[¹@÷¼}ú¹Öÿ´ÊÇÉLX³¿%tEXtdate:create2017-06-06T01:31:36+01:00/¸‚~%tEXtdate:modify2017-06-06T01:31:36+01:00^å:ÂIEND®B`‚puzzles-20170606.272beef/icons/undead-32d8.png0000644000175000017500000000220313115373750017425 0ustar simonsimon‰PNG  IHDR D¤ŠÆgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<,PLTEåååçèèðííëåëéååìììÅÅÅÜÜÜÊËËeeeMMMâÝârªr233’““òòòCCCÔÔÔwww\\\õïõžžžQQQlllïðð«««»»»ÈÆÆÆÌÆ£££µµµüüüÚ×Ú999ŠŠŠ}}}l``j]]ßà߸¦¦Ê¶¶Ë¹¹³¡¡àÈÈ»««Â±±ÛÅÅÒ½½Å»»¥””¨——¸Æ¸âÝÝ»ÇÇÂÍÍkÆÆiÛÛeÚÚ‹º‹kÜkkÏkœ¼œ"""n¼¼sÃÃnÖÖ{ÛÛr¸¸ ¾ `Ò`iÓirÞrdÌÌ_µµÌÌ€ŒŒ\ÃÃÍÓÓÂU¥Ukåk“Á“qããtêênèn^ÌÌnææµÅµYÎYn¬ncÇcŒªª‚»»“»»‡ªªmÃmtÈtÿÿÿ?DÎbKGDc\¾-ªtIMEá$J¾"´TIDAT8ËMS‹_Ó0έ¹¤¬ÐPèf»t1 e t ¢<|!/ þÿ„É5+ܶË/»ïrù¾»0Æ€0Fk-pž@Îw`B"Aà!VÁ2ßЉ:ýDÁäT¬|ØÿÓ‰DATŸ™MøPµÊéFê¡ÍG³™Ï¦09•OOøÒµ¼ÞÂ2—WìVAY*G²@ÌÐ[|†µñ \!)„º:,BíÖBk‘À˜'ǸÝÉKkÇùØH2l0•u­¥Š…Ý •Ý© é|TàsÀOõæ—Ç#·JFi>!í­R=YXXx:¯¤¶Óë‘¿AÑ+Е(ûKý¥åPjèÎ7qÜîlâF?[Y]Yy¬7|›°ýb&p%’ÕþÚZ¿#¥¦üJ$y‹½$®¿\\~¥qN¨¸<ßKdU%Èõúºæ–v Xòœû6•:„še˜*;4ãY :zCuò¢%m¼ÔÜIÝHŒ4œÉÁ¤±¥M$£òt¤q°¹9@Û6{¾Þü0'-FJâpkûõVhY`ôf4ÚÙ ÊQí·¡JöÞí¿ßûÀ¥P‡GÇG‡8V2Ì‹áÇøÓç/_OŒ¾NNÏ΃ôrêÅpûâòârŸßGÇgç©W 9ãü`xu¹}}}u"Ezócòçá/áKØá ¡6ßÞÝÞýF‚ƒ¿;ÿnîßVIÓðý0&mf ÃV†mz––9ÐÀVí{jàáô\€U_ë‚û7@ž—2òÿÊŸ7Qy?e%tEXtdate:create2017-06-06T01:31:36+01:00/¸‚~%tEXtdate:modify2017-06-06T01:31:36+01:00^å:ÂIEND®B`‚puzzles-20170606.272beef/icons/undead-32d4.png0000644000175000017500000000101113115373750017415 0ustar simonsimon‰PNG  IHDR TgÇgAMA† 1è–_PLTEÿÿÿÀÀÀ€€€€€€ÿÿÿ+Î…îbKGDˆHtIMEá$J¾"´IDAT(Ï-Q[nÃ0 sÑš_ÛÚߦWv„À»Áú³ëTjø‘$EID™z’:‘ȘCßxúSG=mv¡Ëh¦ð«ë†˜‰!(gZÃB„µ!<Ã(Ç’ /±%•XQÎ9[›C÷´†“‹D‹˜OÉ'ß±,¯ÌíóF4í ±uÁâbQú\DŒ˜¢Ð ñHÚžÙôK•B¨2”L±Úòl»¢8?ª½öæÕêÎ ÉhZU¶“¸`äÙJ„«´O7d"pýÈúTDý8½ÝšŒì÷»ð1TÜâZàkì PÓám-‰üþÑ k¶~•jN¾p6¶×ÙF!”\¹ªùg“QÃ)ÓQCI´êÊz½—zººq%tEXtdate:create2017-06-06T01:31:36+01:00/¸‚~%tEXtdate:modify2017-06-06T01:31:36+01:00^å:ÂIEND®B`‚puzzles-20170606.272beef/icons/undead-32d24.png0000644000175000017500000000355213115373750017513 0ustar simonsimon‰PNG  IHDR üí£gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEá$J¾"´nIDATHÇ•VKoSI®ª[÷Û1!™PÆ8Mƒ25"š‘Z(»nµXE04KÄ&b”íô‚ ^e„X Ñü‚²€^ hˆ"ºI‚ vºA!ÄN_ßgÝzÌ¢Œ};¡»Vö­Sß©óø¾Spss|nA à „PJ!„‡Ú躆áÁ]ô{Ðc¯^½jµZº® !@«Õª¦iÆç\Ó´jµúàÁƒ©©©÷ïßkš–ôÁ³,ëþýûwîÜ™››K¥RŒ±?à!Á¹s禧§9ç3 (ŠëºKKKÏž=;hóBUUwwwoÞ¼9999<<EQB1Æ{ž§ë:Bh_?ï@×õ••JéââbµZÝWipýúõ[·nÅq¼/xTuPdº®GQÄ;Xd!„išcBH2>ùuwŒ±ªªB¡"ŽcEQ0þ½Ü‚rÎ !B˲äJ©Œæp¡f³Y«Õ:<‡²5c‡Ò‚sžÉdz{{cøÐmÓ4ŸœsÇq<Ïó}ÿÓÓ¹xñÒW_ýó‡!­V«Õjyž×jµ\ו†išårùéÓ§Œ± $âœ[–õøñã©©)ÏóEIVÂ0Íû33;•Ê_/\øÛ… •ååÍÎ;v Bˆ‹s>88X.—çççGGGã8î„…!„q ­¬¬Ôëõl6K‘a†ñzmíJ©”º|YŘ¢kÚ‡­­õJ%Juú•R:00pïÞ½………ÙÙY!D†BEÑ¥K—ŠÅ¢eY, !‚±Ò™3žçA„¡£##”¡Ìä>tJi½"Û¶çæææçç>|ØdY†TOÏ»­­ŒmgÓé¾lÖÔ´ÍZ-ÉpÆdUûûû“èÉätSD)- 333¦i&Ð8Î÷õ5¶¶Þ¬®öf³q{A0üÅÙlv§^B¤Óér¹üл5(•JçÏŸçœû¾Ÿ Àù©R ë:ó}@_*u²PàŸ#Š¢B¡p÷î]Éä}Jו a†AÈÎél«ªŠ1†žýòˈ¡¦ª1!Š¢¨ª*ÃÕ«W¥F麾­œó®Iê'‡a¸¶¶&™,>] !TÅqœf³)Ù„@!`2Ær¹Ü‰'(¥¸Û3Bt®/thh(ÓÓC(UUUC1F)ÕTµÑhX–Õꪮ… Å (ŠÜSUUf©Ã2Ó45ðÚ«×W÷öÅ\.“Ë1Î ÃÐu]×uŒ1¢è͇7¸ÑoôŸþÓià@´û`9’>~ü¸½½}öìÙ$“)cº¢¼\_D)ï룜۵Úß]÷Ï…cLNÇÈ­?Z?¹5ù3¢È@@àÇüK¿,™ªÉïd¹®;999>>.Ŷ]4„~u?“\]ÝÛØÐšÍÞååmÛþà8š¢@ˆB/¬hÛ°·ÚŽ‚¨þ²nçí×ñëD˼}û¶R©lllœ:u*9VcZ:½ñí·ýº¾Eèûï3 C`Y„¤[xøÊ0¥tèÊPC,0@pÐM‘®ëÏŸ?Ïçó/^¼HNm(@ÈqdšŽã0E‰9o¹.TçBµÔ14VÛ¬ÿðìú»Ñ¯Ñ˜=ÆE#„|ß¿víÚ7â8ö<¯Bq½{ç5#œ×!L+J°³CFF¢€ã§ÇÝuwq`‘ãy7ÿ5ýºt¦ÆÝ7d›ÉAxž'Ž!¥ÁÁ±B!Ó4£0T0†Å"…Ð÷}!€*ô›Ño.ï^vB§7ÓÛ“ë hЭ@‡ÉIèöŒ…ºaJUÛ&œ+–%„àBhªêy^ûŽøÌïÉõäPŽrêÇ>‚¿Á9ü]$¥BÓ´£ÞÒBÎy‡4²³5FG7Mó(t‰•|#퓲äú¿%ò¹m„ÀÇ%tEXtdate:create2017-06-06T01:31:36+01:00/¸‚~%tEXtdate:modify2017-06-06T01:31:36+01:00^å:ÂIEND®B`‚puzzles-20170606.272beef/icons/undead-16d8.png0000644000175000017500000000167713115373750017445 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<¿PLTEæææèèèÕÕÕÜÜÜçççäääÝÝÝåååîîî°°°˜˜˜ñññáááòòò¢¢¢eeeãããððð“““¥¥¥¬¬¬vvvêêêßßßééé¾¾¾ÁÁÁÑÐÐÐÏÏÂÁÁºººÀÀÀÅÅÅÊÊÊÂÂÂåææ›œœŸŸŸäååÒÒÒ›››ÓÓÓäããÇÈÈÅÀÀˆzzŠ||ÆÁÁØÙÙ™™™¸¸¸íí퇇‡µµµêééÁÂÂÑÆÆË¶¶Ì¶¶ÏÄÄÔÕÕ×××ÆÆÆâáῳ³À´´ßÞÞÞßß¹¹¹õõõëëëàààÛÜÜÚÙÙÛÚÚÙÚÚÖ×ÖáàáÚØÚÖÖÖÚÚÚàßßæããÌÖÖÎ××åááËÍÌáÞáÔ×ÔÊÔÊâÞâ©©©ÙÙÙáââÉÆÆÅ××pÆÆrÆÆÄÓÓßÚÜÒÛÓvÎveÑe­Ò­íèíäæä‹‹‹¼¼¼çééÉÁÁ—ÑÑiÎÎhÍÍ”ÌÊæ×Þ¬Ò®\Î\aÎa{Ï{éâéåçå³³³ãääÇ£ÍÍ{ÒÒ{ÓÓ¤ÌËÝÖ×ÕÝր€kÅk´Õ´ìçìåæåïïïÅÆÆçääãÝÝåââÔÕÔèæèâââÚÞÚëæëçèèåäåéèéÿÿÿÂ-lbKGD”gJtIMEá$J¾"´ýIDATÓc`F&fFV6Fv0—ƒ“‹›‡—ŸÂgä… ˆ1²‰3J0ŠI0²@tHJIËÈÊÉËK)(EXÅ•”UTÕÔyØÙ€ÒšZÚ:ºzúì܆FÆì ¼&¦fæ–VÖ6ì\¦¼¬ ,ж’ð_õX’ÿ߯ ¾Ï1²l»ù %tEXtdate:create2017-06-06T01:31:36+01:00/¸‚~%tEXtdate:modify2017-06-06T01:31:36+01:00^å:ÂIEND®B`‚puzzles-20170606.272beef/icons/undead-16d24.png0000644000175000017500000000241113115373750017506 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<ëPLTEææææææèèèÕÕÕÜÜÜèèèæææçççäääÝÝÝèèèåååææææææåååîîî°°°˜˜˜ñññáááòòò¢¢¢eeeèèèææææææææææææãããððð“““¥¥¥ðððáááðð𬬬vvvèèèææææææææææææææææææêêêèèèÝÝÝßßßèèèéééèèèêêêéééèèèçççææææææææææææååå¾¾¾ÁÁÁÑÐÐÐÏÏÂÁÁºººÀÀÀÀÀÀÁÁÁÅÅÅÊÊÊçççæææäääèèèßßßÂÂÂåææ›œœŸŸŸäååÒÒÒáááååååååÅÅÅææææææîîî›››ÓÓÓäããÇÈÈÅÀÀˆzzŠ||ÆÁÁØÙÙåååñññ™™™¸¸¸íííåååòòò‡‡‡µµµêééÁÂÂÑÆÆË¶¶Ì¶¶ÏÄÄÔÕÕåå嘘˜µµµòòòäääæææçççÊÊÊ×××áááÆÆÆâáῳ³À´´ßÞÞÞßßÆÆÆ¹¹¹õõõæææèèèææææææëëëëëëàà๹¹ÛÜÜÚÙÙÛÚÚÙÚÚÅÅÅÖ×ÖáàáÚØÚÖÖÖÚÚÚçççåååëëëéééàßß¾¾¾æããÌÖÖÎ××åááËÍÌáÞáÔ×ÔÊÔÊâÞâáááæææëëë©©©ÙÙÙáââÉÆÆÅ××pÆÆrÆÆÄÓÓßÚÜÒÛÓvÎveÑe­Ò­íèíäæäòòò‹‹‹¼¼¼çééÉÁÁ—ÑÑiÎÎhÍÍ”ÌÊæ×Þ¬Ò®\Î\aÎa{Ï{éâéåçåêêê³³³ÊÊÊãääÇ£ÍÍ{ÒÒ{ÓÓ¤ÌËÝÖ×ÕÝր€kÅk´Õ´ìçìåæååååïïïíííßßßÅÆÆçääãÝÝãÝÝåââÔÕÔèæèâââÚÞÚëæëæææææææææäääåååæææãããçèèçèèçèèçççåäååæåçççéèéåæåææææææÿÿÿN÷˜IbKGDø;cgftIMEá$J¾"´IDATÓïþ   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷ Òw²¼@%tEXtdate:create2017-06-06T01:31:36+01:00/¸‚~%tEXtdate:modify2017-06-06T01:31:36+01:00^å:ÂIEND®B`‚puzzles-20170606.272beef/icons/twiddle-web.png0000644000175000017500000001103713115373724017724 0ustar simonsimon‰PNG  IHDR––j.>gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEák Ö'IDATxÚíœ{pÇ}Ç—Ô3’«²ìØ®#Fq“(nfìqÝ&õ¸‰k9µšØ“ñ8•ªŽÓZÍÔ±l§mÆé8Ó&Nþpí?¢ÆqêØ-‹â[¤(Q$%‘ñ8$$»ÛÛ»ÃûÁ^âK¢DQ$·‰{àÒ*3úÍhF~·÷¹ïíîý~¿ÝànJÿß¿XH¸‰ ­`!Ö=0XŒ (Lí3…¾‹ääbÐ2–ன;ZInG«Vy¬º°U;VUUS£ãU]s¬¾†5Pw¶¿Ü\Æ.™{íÝ]Ì`0Û¬”©³Ó`è*ìב‰0+Xƒ•< mODßZó£ó8ãÏÿLfþhr|: ½|~>ƒCk°úðt"EdÉdº³±p­¡™YeÅÈXf8€ úqžIÌÃJ¸/‰y ±v_;˜“ÄÃHwÌCè¦2ÃAÄjû zB¦VŠá‰qþŽš¡<,N¼|ÅÏrúÆrh:B†Ó¸ ä”cyõ/8wÑbg>VN,ÂYrþX:=è’cùdjÁÀì¬rq,òGE»{’W=¢tXˆIáaHvìRÈu2¾˜ˆ‰*`%ÃBlhî²B,–¡i†Õ5wã…KI5°Ò©Å¦ð(+;ùÃÑX4¨Þò´àiÿH:ˆ 2°Ra!6<)ß8lo<ù@Ńm‚ªX&ž‹²¼o$’ƒ•N­4“‰EÇýIP@ù]*\È{z OgA¾át*ËÕ¥ÁBLÏdôÈ/úi穇8¨2 !+Öòâp*¬d71ƒŒü@~Ð#Âà·ƒ= ¯8Þs*‰/¬è‹81žL§®•+'–_Å qLôí­àÊlÞiÀW#k?†%°(ÏAB¬ìóU9È×bA~'•ËP´î;ŒÊ¾5ØœÆe÷Vˆ'$0A",!Ń Ø5XlV,U*ß¹ÝàŽ*å-äÎJsVXqˆ“À"ÒEèc¡Cs]U‡|NZƒù)é ¯Ò«‘¿þ³ ¢^…Ø}"+–Ê…ð±1 ̧Œ äX›·—¯ßvÉæâµX’X>U±Þ»b MaœQ9Ä~ý©¿ÜÖ½/”â&VNÆT#š,X9MƾA¸‚wV;ð|L)òDZÃëÁ£¶XUÁ€Æ\ ¥G9G·É± †˜Ž“a|žWN‹þ¶s´ýfx¤$X5­8 I_ÇRÃ\o·Ù9¸Ò÷Õ=øªŠ¾žôþ]ýÃ= ì'¥‰5¡À÷PŒ§ã\r¡œXí-<Ž”­{Gþµ,[Ù©8t홪ÄJz8Hb¬ ¨4˃œ¤X RÝVgöRÕ6<WéŒP°W½óÖÛ¿:á+0“°ð:ÄŠ á®ÂXÙr¾x2ʘ»íNšmmâ ÕŠ·tÃG“‰ÑðêcW‰•0uv‘X§¡µA+KD¼F“Ý~ÂŒ¯¨\2´dkÊ/2¬£®éö*Ò²š£‚Ö2XtÐl2Ƥt‡0‘«åÀé‰É B‰ÊðùbÃCçÂ$ï" ù•XE¬‰4a^lmö\tX(Y.¢ì[i(’-ÚŠL³›à&.qÙêÛ.\MzÍ”mêk\º åV°4ú{²y/Î$S‹Å6¨Ë¥2Þ™ü’.úÿmçúmOwøT­ÇÛ/_ÆéTRì¡Ìvo R ,(¸Ÿ›vlwªÙ$±NÀň$h4™J¦„Ê$…üK#¥ÁbFÞàŸR•wƒ¿Rö7dil»²T¿å#‰T:Í÷RƦX©Ô ¾nûï0ü°RÈÙ“MâÂr±¢ÈX2âú(““ѕȣ[;% ýlxsܱå]D¦¦3s3+Ÿ"ˆÂ£ÉL:,&§Ö­z“²µê뻉Ãÿ³|å£ýëËA“|Ù2§Ž‡eÅîÈHò| :Íf·ê­„¾3‘R`A~èÕÍR¢wÛFÐ._'ã»OtÎÍÈæÂÃÉñ1Öe²¸Ur4ÔP,)×ßÿîó=¶Èûô¶Ô,*V Å“cÐe¢¹ˆ”f׌”‹÷Ø" 3§w}CòLÞÐdœ›Q»S\0žšáœFÛ`~ßçÝ-gÆKr}¶ö¾òÂÝàžS²ùµÖ'°ÆÊ ÆRÜCJ’ÖÜIˆÌö ¥™N{Áz°ù«Çdºms‘V*‚‚ÑÔxõ{VÂiÈ»› ‚y‹ñz<^y%[}e;Þ?ü‹ìAyIp µ!¥!ÖÒqÈMÇø^){[ñ2w±ºó„Á±tj,Àj®ùä,8’H ûdÑ' õι ë·PËH`=¦¾l."‰u¢‹Ó­ËC}÷¹'¿±ÿC>¿„§XÙÏí-Ÿ³¿µ1­W¿•H|‘L&ÎÛÍ)N€æ&‡¨÷ðˆ~µ¼¼¬¬ìo°ù 7¾ýC0Ö ÎOë•$³g‘ò] ÌF9XOs‡þ3‘ 7W€/WÕî”j¥¹!çéæ´²$©&DÓéd¥¨3½‚î2'­»ücxb¸Í,ËXå]˜Òk,5ÆSv‚Ea)’z|¥ÛüEð„ÓW$ï<ÕJ(ÖR“œbÎ’µj(:Ÿ7€¯[}»¼šX¦*Vwe@æ8ÞG‚yïAP~ûí`ÇoògJ],È;NœËÈë·ÙÓH9¹ÆâbºÚ³S¯.3üá:p O‚Í]Åö-S5Äãò`‰^gŸÃͨšûx"¬±Ãü<•xe¨É‹¤ô° ïlìWÔo¡Ðúì&îyK¥t“-åÄ"ÀŠÙoi}€v…Z“}ÆXÅn&Xûð»îßþ=µð¹O8x",i$\'ͦe›æ‡,Våe4Ÿv¼³Þ8…eõ[ˆŸ¯>Ÿ66ªíqcÏ,‰E2}ôáçö<ùÃH”Ä:“Ù>Äju^C=§èYtüW;À놪ZWDí × çÒÉ 2C‰tz,¤|T×:û­&‡G5áûkÍ3‹òú­7ù#Ú¶ì=§V£n[‹lëf`ã‘FULÙOÝÑÄãqyýÖ›>6‚ÇžùøS•佯ɵ²qêÆ–¢x„$0³ÓÃÉ=䪱ÌÍÇYÖ+<á} €V…\ìé±n8}•&däuQ—W&ÖÙfO(&zì§ëÁk¾ï—ƒX¶&×µãKUçÀ(½ö<®Zj᪲~Ë„îß„“O”n9ÛÒ¾zY¥ÙíÆy”ÕŬ® ´µñ¤2„là Øò­}[À3Š/-«b•no f±]«A:ë(õb7ës¼òI¶=ߣزF¬Rnæh ¬?7G3§OÇñ”j} Э5µ§¼ò:25ö¯ú—p«uŒ²Kù t4X%±Ô–ÇãyÒ=-gÖ|TJ¬k`ÜÙ–$žÖ*_e7@Êw@JÒñ5b•+æ ¬v<+"ú“ÒÉ–³ìï+·Õ´ÇrÏpEìR‚|WÃZ±nèíÍx òWRž^ÂvrÖßrŽÕÁ¢IßÅèÔE™{¼ú<+bÕ牥†åaˆŒFµCša bVÊÜKsˆ@3)C’mkåiùâ ßX][CdõÕnŽÕ4èíµ˜ºmƒ4ÃêÞ©vä·‡òK#®‰®N©uð¡@ ŠCî~í_þ3ªû…h£MÌÿ.è»p½KQ_,ÂÏOáŒ/^–aÍLL‘ÙäEÃy<]вnËÿ½5ã+Sš~²¿/Ûä%ÝÄ@n)T×¼,U=Ž¡‡Ì™öœêÄÄM÷VGåµSâ—µ:+'±È9#­6à)â¦-Gâ×[Ò»ŽM`Òbj»ðñâõñucùº*‹Áª1ƒuýjݺ…u ëÖM¥Üé¡…¥ºÓXKÕ™ €üÕ&u,è[Ž˜|² Ž:Öò.nAÞ-”‘W Õ°ø>ÊjµR”Å‘Ÿ j`õ›³î÷õ`A6´”ïè ÉŠ”*XÞ±?Êîò“þýE"/ÁPÅâ™—Àúì ?¸üj1 {÷Seë+ºƒúXtü[÷îÚõÙ»ÊËö `±?Û*v~nÛÏÄâÕbý½l¹Üg ÀÊÝD›õ¯ÁöªüO ¬O‰žžþ븉lð‡à‡vaåÎfÙþ,œÿžÖ¿€G½{´W¾ìN€ÅDë¶~Éþ4¨è"ÂÊþüÂ!°å—²åa¾õr¶o­ûêIym]‹õìÿ•ü:¨ U ¹ïŸçd…i ¬ñ;Ï?¼|Íê/²ËÃà‚ç½þ=äXü›`ÝëAY%P 1ç:£‰îG8šW9ÔÇ‚<ýxìÀs÷‚Oíy//!לåÑÀ§Ýòú¤*’sâE~;Âä5­‹% ÈÞÊÁßæmaÖê[è£uàïC$XÐgÿ÷“|¤éË`]u¬8µ8›ßzç—ï= þð'çHÔbb_+ßbVþdV¸}sÅã{?Wží‹žNÉÑáñ½`‡#Aз pt3xÊO†%:Þ•}Ùáªè‘(Eš¡Ù¶Ê¦€ºZˆª­±r Óx&vlll§}òU.ÒÀ&4ååǪwy_<®òš¼VŠÆbaEÙ™<ÞbåXs$²j¿–¡ÕÊοÿÑé-¬[X·°naÝÂ*+é%}£3‹Å9CŽÎb7mQ”t“ÐOò®–O$,Q röù‘„5É’6mSªe·P$f±©ÄÌYroèÆS}¤MwVçc¹g»*||„À>>RýÛL°‰Äuɽ}Žª"núƒp–i2“Zx6&vŽ$f#E4½ö'P\m¼XÌBÖïÎW±CGÃÁ",TŒsqÞ¡¥˜ué‡EÙ‚ðÿ‰åfÄ›ùgXo>»I±þŽVx’b·­z%tEXtdate:create2017-06-06T01:31:16+01:00m…%tEXtdate:modify2017-06-06T01:31:16+01:00À=¿IEND®B`‚puzzles-20170606.272beef/icons/twiddle-ibase4.png0000644000175000017500000000156113115373747020324 0ustar simonsimon‰PNG  IHDRff´»¾gAMA† 1è–_bKGDÿ‡Ì¿ oFFsE² ËtIMEá#ÔÚ· vpAgÀÀÏÀtó{IDAThÞíÙa’ƒ `Žž£q3v·Õ©…¼ð^D·³³þêXà3h1¤¥Þr”?Ä´ZZkÎyïäØfÞhkùÃø_PÝÙvþ¤ ×É´Ä §`è`H2‚B@>£C\bR îæ2Ù`”“S6ŠdÜ–fåû° ƒ ŸqF)Û1Qä0~ØÅ¬Zϱ×¹ œƒL7nL[ÁôÐÀ„3¼7þm?Þ/)|0Ô3|{íÏõ4¨cbÅðPÛÄ1%ø}¯›7&h0òÛ3½4KÌeÊo0×)“PÌeÊ‘á3âÓŒ É9ôž2ÜÁ$ÒZ²ÝƼ¥ ç˜2æ@£í:Æ“æ,~;3¦ yÆêð¢}1Ì|s2äÒüöÓM øz|/…ÌŠ7šÄÄ„—Ð%(SO©ËÄÊõ@ ¶Í›Ê¸ÐäÎø?OŠ3:¸Ø¨ºÄ ¨Ì²—`еÌ©¯¿†êiA—ŠW˜ÑúT= ’'m땘´sþžÔ3êcû%Acx¿ôê´‡”g‚ñ„e ¶ÍÝb &·,—MÆ¢íy\6¡+á30)›Ð̳ 0sþ<3+›ÑÔ°Ö„‡Š² toLTBÈ‹&P¦o¡rŽB4!+·á¹V*“¼1³¡—þa[–K DHaô7s{}TI麲L®@•`ÒŠÀœ Fb¼³³uT&*h,eœ“OÂÖ1(êCÍ¿Åþo›;ùtÝwå…˜:Ži±µŒ{z{ÐV1h°µÑÌþÔ±%L\\õ@ŸZ3?Y¡| ³Da˜J²üðÏÜÅ´;ŽG=Mí£·ÿ#&Amÿ™rªÀZ¬†ÿ%tEXtdate:create2017-06-06T01:31:35+01:00P˜ã%tEXtdate:modify2017-06-06T01:31:35+01:00o _IEND®B`‚puzzles-20170606.272beef/icons/twiddle-ibase.png0000644000175000017500000000427713115373747020247 0ustar simonsimon‰PNG  IHDRff´»¾gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿ oFFsE² ËtIMEá#ÔÚ· vpAgÀÀÏÀtóIDAThÞ½™KlGÇ%¨M T!Ô ÑªªTÑJHôÐÒF¥'Šzè…C{áPTõ!qi%mOp©DÕCÅ£j…J»ëÄÄ„œàGœ—;ûHœ¸yà7;×: óÚCvIá¬þ,“1AŒ!Âu;·î?¡Èדåái£›1ÓAL!À\®@h;BïÆh2½ÙYÍJ )T2›€˜×PEƒz ¡A™€àš_.h›X K¤˜{½­ª·z”‘¤¬½m2 ÝŽ ™Ä´ ô–ªzÚœ5Ù/4üG´MfLýÔ)=$fpÚ|©çs\ÊÛA% ´M =)`m~ÊmfQy|›à^„Û&S}ä(Ý"tAÿöÎŽý_îAUäœAQŠgim“i ‚CÐM‘v{z7Ù"CîøVáæ3‡¶‰" ƒÒ%µ˜ë¿w\{mºFüg1QJdÛ&Æ©#B[Œ˜_¬•9Ȉ·VœÛ&™tƒl…oé[¡Û³þÈ®Š-,3‘-Õ6Á ^ Ú¸º•F1ÊS:廢wµÄ£yH›ÌX õÔ‰ex0QAš*ý†aÐ$Y!ÈXŒ|Gô15[4mŸºÉž@‡ K†ÅÒ/Âò¤‰TtÛaÇ zE?GçH36å8ß5dØ1ý‚Èú",wêÆRéÌxø^Œ#·Hí¼m0-!ß¹iý“Ós÷ë9&´rað0ÌßÓ“Cæú³c"8g”ñî¨1'ÈÁ2½ Ìc»*jÿA™ÈËä1%C/Î̹-f•ýŠ‚iÈËä1%ƒç @¦ù´ïr$|ñ"üãÚÖeò¿sbÀ9ÚhœDè*ýÇÅ\ë2yL—SÛDñàœ­L-ª<}°æÐyx–oCfý»Îன2—M¾…¦E¥ ™‚+ÍQƒDyyŒSð‡]7¶£­a`–WŒA %œ3à-àn„ðê×!¼Öé/”)ºo ™$ÚûÖ£]QÕc]'eš V†¼= PQbÀ9ƒ²Ÿý¡Oe_5ª ¾ŠØd€*`‚ δj†ÏWåf´é)ã±É€ÅÆm$œ3¨›óØ™[_zA=vJM3@ùÄ M•Qš›ì2ÔÒ‰Afb¸s÷ë32aò 1UÆ»#w‘Œãƒ@Æ%Èç/C¦£X¦ÄóF·eÖVyßÉÅ2¥kKÔŽ>>Jˆ)1.:£zs`\„ ËCš$H¶FH–HÖ~;Hidòý4o,òoöÓøf•s¼ÙOÃqŒ²ŽÿÞÇÀlÕB%tEXtdate:create2017-06-06T01:31:16+01:00m…%tEXtdate:modify2017-06-06T01:31:16+01:00À=¿IEND®B`‚puzzles-20170606.272beef/icons/twiddle-base.png0000644000175000017500000001452113115373724020062 0ustar simonsimon‰PNG  IHDRÀÀݾûPbKGDÿÿÿ ½§“IDATxœíklçÕÇÏÌÞo^Ûk{m|Åà —ˆD¡´BI©n¤@*'”’¢R) ­Ú"T ”WŠú¡-MTHi.‚¶I«6¡$‚©•#J.µŠM@`š﮽÷ÛìÎìÌôÃy3Ýw{ŸÙÁûü>­×øñþïžËyÎa._¾ J±°Z@¹³¡¢AD!‚ ˆB…* T@"¨€(DPQˆ ¢AD!‚ ˆB…* T@"¨€(DPQˆ ¢AD!‚ ˆB…#ùããã’$‘C)3V«uÉ’%„ƒ¨à@T=w"ƒ¡¯¯|Ù²e Ã0jFÇqEü Ç㩯¯ŸššŠF£¥û`0 c0œN§Éd’eÒét:.ѯûDêêê‚Á á8ªÍô£Q/\¸PIJ,[__/IRIÕ²,çr¹X,Fs¹Ã0v»ÝãñØl¶ÒýÒTG5BÆÆÆÔ°"‘ˆßï÷x<óýAüòå‘eY„h4j2™œN§Ñht86›-•Je³ÙòÄ@Î\…MNNñSƒÁãñ”Á~f"B$‰Åb’$ —ËU[[k2™ÊCѨì@w.uuuPFû™ ÊÝÈ`0¸ÝnQ‰D.—Ó*¤¹°¨ŒFcMM&ö£ ˲,Ë<χÃáx<.I’Ñh¬®®v»Ý,«ß?u €†††a4´Ÿ²Ùl6›5›Í™LÆçóI’´yófŸÏ—L&õ¶i¢_i— “ÉTUU%Šb$ÑÕŸ'›ÍJ’‹ÅV¬X5Çãt:ueH: E+¼^/Ú~v"Y–c±˜Õj]´hX­V°Ùlµµµ.—K'2ÒEb±XœN§(ŠÎ~f! Ý}÷Ý Ãär¹7n$“IQ†±Z­:‘Q¥Ïû)îÇÏž={êÔ©ÑÑÑ`0Èó|SSÓ† üq\Ó‘ IR(2‹-Â%Iâ8.“ÉX,‡ÃÁ²¬ÕjµX,Ùl6•Ji¥þŠÍf³Ûí$öó›ßüfxxXùrbbbbbâÔ©SøÃÈ5‡×®]‹öFñÐC–eeŠíp8 ƒ¶2ªèGXcc#˲$‹/ƒÁ000ðÒK/ =zÏ‚Áàoû[’ÀdYžšš2™LŠý|e‡c±†hõP«\²Ûí‹?ÜEp‡††ªªªðu]]ÝŽ;ž}öY¸uëIlhŠŸùÌgû¹]„¸ýh6›ív»Éd*¿U®€Ð~¦¦¦HQÔƒp‡/ÚÚÚŠíÇl6¢ýÌüÇÀó¼ x b4Ë)£ Ëå2›Í„öSÀäää±cÇpð­[·=Ô÷õõ}ªýäƒ'üÑhTI)Œ*täõz g?\¿~ýÑGD"‹å§?ýiÑÉ’$ùý~‹Å2û™‰’(‰D²ÙlæF•( ·Ûm4U´Ÿ‹/úý~—ËuäÈ‘uëÖ=” ÉdRÙû).B”Q"‘‡Ã¥–‘.aápøÈ‘#£££W®\áy†††zè¡ý:´ÂÙ™3göîÝ›Íf½^ï‘#GºººŠJ’$ŸÏW´ý Ë2žç§R)‡Ãa±Xòj$#ç£ MMM?~¼<¿«¦¦†eYµìç÷¿ÿý3Ï<#IRUUÕ¾}ûÒéô?ÿùOp:Eä«ó<ÏqÜ|g?³£È(™L:N‹Å‚J"VAr¹\=öØ]wÝ5::ŠóÐÁ0LCCƒŠösúôiüÇãñ={ö(ï¯]»öå—_ž×P’$MNNªe?àÖÊÈn·/4577ïÝ»ŠM&œ;µµµ*~¸Õ…ã¸l6«ØO$Á%ºŠ ŒR©T:ÖiN´žÁœyí~õ«_©2ÎÌÅÃ0ª A©5Z­Â0g^‡ö#Ër2™äyžpñ¥ •" Ì™WwïGE@‰f?¥¦RTWWÇ0 &ø•èÑP˜5–ËåîDûÊ™9ÎD"á÷û£Ñ(žé$ÿP–å;×~@'Bc€¼ÃÈt:‰D ¦¦†||£Ñ(Ëò7ð·È²œN§qoM[I’„‰Øw¨ý€Näóùî»ï¾üw††††††`ddÄb±ŽßÐЀ•(âñ¸ÏçK¥R¢(Æãq£ÑˆçŽ ÝÕìééé;×~@'*)xé¬Vk&“iooÏf³“““Çá'^¹Y\f aÒª,Ëw®ý€NÔÜÜ\ºæÑ˜õŒIé‹Åf³Y,–Å‹sçóù2™Œ’“…gå”Q0¼£íü* /]0 355…Iéáp¯çÙl¶ÎÎÎöövœ ñ< …ð‚z–i˜5w´ý€N¨t ý‚¿zÏd2Ê݇ñtéÒd2éóùAày]Áår1 S:7E1㯢íçÒ¥KGýàƒÂáp.—óx<«V­züñÇW¬X¡zÀ·c!;^º`&俟Ÿ”žH$$Ir:]]]ÍÍÍ8Êf³¡Pªn„öÃ0 ¡ýŒýõ¯œœÌd2¹\.üùÏüàƒTùv,daÖs6›M&“3u0SFn·»»»»±±Ñ`0Çq¡PóAÕ•ž•’Ï~ÚÛÛðƒ¼þúëï¼óÎñãÇ/^ <Ï¿õÖ[*F;; ö†—.Àï÷ÏòçÇoáM+|¨ÕÖÖVWWG"‘ééiI’Òét&“ÁÒO²,“?ÔðÜ”eYòÙÏúõëׯ_¯=ÏÀÀÀÏ~ö3(gm¡+ ¦¦&–e9Žã8îSýc¦Œ<OMMM(šžžÆLÌë#ßÂ!Ûl6_¢(Þ¸qãôéÓàr¹¾ô¥/‘9G¬€ðSè÷ûçþáž)£úúúššš`0‡QF„[ؘ´ªŠý(¬_¿>âëÆÆÆçž{ŽäRÑ|Y°s –e“ÉdÅ æF,Ë666öôôÔÔÔàql<D"<Ï‘XÃó|*•RwïÇét*†~¿×®]×®]#vŽ,X@ (úÃ] #†aššš–.]ZUU¥¤TcÕ¹k“VÕµxûí·/^¼8<<<00ápø¹çž#sî,XÅãqA)‘ÑhliiéììÄÍI¥8¦(Šs‘NÈJ´õ\WW788ˆ¯ÿýï«8òì,Ø9‰ý?7²Z­v»½½½ã8¿ßÏqna›Í檪ªYöU\|)ìÝ»wÆ ½½½Ççóýüç?Ç÷[[[I† V@¢(ª; Ê({ñâÅétÚçóñøo|ƒ¼|Ž,ËápXEƒÁ°lÙ2Q¯]»ær¹ ˲ƒaÑ¢E^¯×ï÷ÇãqLPÔäZ9- sçÎíÞ½;ºÙl¶?üððáÃçÏŸ饗ŒF¢ÿY–qîÜÖÖær¹pI ¥Q¶1hllD ‚ …Êϯ. ð6w†††r¹œÑhüãÿxáÂ…;wÀÈÈyùP(„]Qz{{ñ9% žíÇãqœÆæææîîn<‹Å3µx<®nŸ™ª5Tå (ܼy–/_ÞÓÓ?ü0~ëĉ$#+öÓÙÙi·ÛC¡PÁwg6*@uuu¡ý ŒR©T‰d¤â˜•ûS’•s{åÅÕ«WÑ™ŠV’$ì¬c4»»»go£YШÀd2µ´´ˆ¢èóù‰æ)—“Ôz¨É²¬± §rHYÿíoK¥R¯¼ò ~ K/=r(bY¶»»ÛjµÎ±Q–Wܨ¥¥¥»»ÛårÞ¦Íd2 žs¨x`P¹d0öìÙóôÓOK’´k×®‚ïw3o J’d6›—,Y2÷.¾3 ŒAðûýx ¦Êµ,²‰rT…Ê|ùË_®­­}ùå—oܸáv»7mÚôöÛo—Ëåt:‹P’$´†aÜnwSSS‰ì§¥mJ*•­j›Í†2 ét:›Íâ›øïñÌ_uûèÌ™3J¯$‡Ã‘H$.\¸páÂ…D"AÒ|´<(ÛÖwÝu”3g7¦Óé4Çq87²Ùlííí(£|—ÂDlÕítr”ñúë¯ã‹ýû÷Ÿ?þ—¿ü%~ùÚk¯iÔœE÷åêêêêëëËc?3A7 ‡Ãxþj³Ù::::::¬Vk*•šžž6¥°ЉaI9øìg? ýýýƒAÅ"г”™\.džÁº–Ú^ÙÁSRŽãðʬÍf[¼xq*•ÂÅW‰r|uá@[·nE 8q"“ÉœõÔSZ‡6‚ $ X±b…Þn ¢Œ0 Òáp”îéB@/^üÞ÷¾—L&Àív³,+ÂßÿþwLøÒ'J±:L Á•¼Þ.,Çb1†aJ1wVÐ…€<˜H$ ÃñãÇÏ;wòäI—Ë566öä“Oêö®«cfÙ²ez³…P(T¢¹³‚.týúuhjjºçž{ ££cÙ²epóæM}þa”jQ˜3Ob?ÿú׿öìÙ³qãÆU«VÝ{ï½_ûÚ×ÞyçU" …B¹\®¤ö:vöù|###0111>>xÚ\ܘ%ÍHÏd2h?xã½h•ÿéOúêW¿zæÌüc‡Ãá÷ßÿÒ¥KªÄ‡Km? “eüÎ;<(Šâ£>êr¹”Âò[·nUöRç A n|bR„’3_´ýܼyóÀ¢(¶´´8p`õêÕ<ÏŽŽªáÔÔ”(Š¥¶Љ€¶mÛæñx^}õÕñññT*e·Û;;;yä‘¢ÇÄýÙe¤s‡9ó$ïÇçy~ô£­Y³¬Vë† ȃDM—Á~@'€û i!!6› k¨Û¨>.V‡9ó$Õ¢Þ}÷]°Z­çÎûá …ÚÚÚyä‘/~ñ‹$á)yÙe°ЀTÇår9ô!u3Ò9ŽÃœy¼¬Ä•Éd>Œï„ÃáK—.}ôÑGßüæ7‹³ªËc? “It‰`YÖétz<´Ÿd2‰÷cŠž_+³Ì™',V‡Wª`Ó¦Mï¾ûîk¯½†¾Ã‡}©—‡²,×××7Â|YÈBòe$IR"‘(®QÚO6›5™L,Ën1TWWã‹mÛ¶¹\®•+Wö÷÷€ E7ü!™LÖÔÔ”èàb& _@H¾ŒDQŒÅbó-ª¢ØæÌ“×ÊTú *gÉÊ‹âUãæx‰Ò6nG¥É—*`Ž ð (æÌ“Û`k 8qâ¶Ñxï½÷ ªªª···ˆyžç8®l³¤²„äËH,rð©m ý~¿’3¯J©ÞxàóŸÿ<œù2*ÈH‡sæõÙ¨ hb?@4EFxi&™LFÌ™×§ýà~„&ö•<‰ž–e].—Çã±Z­¸÷ƒUyõÖ¨ t7çu Ù`Y¶êc¢Ñ¨Ïç‹D"xýJëÐ>¾_Š Ës‡ hN\»v ç× ”\уŒ´µ °9’¿iÄ0 Öʃ*V«œ/˜´*˲†ö´_ؼ(Xí£Œ4t£`0¨­ýíVzf€¶ö ¸_˜&( ™L†¼ÿFÊa~¨X¥Uµ9~z;`¿0­£ø¢(¾ÿþûZGñ?ÔgÁö Ã×4ž™äÇCÎ\…é¤_˜ÂÂŽg ˆRN¨€(DPQˆ ¢AD!‚ ˆB…* T@"¨€(DPQˆ ¢AD!‚ ˆB„¾nep700€ùëÖ­S¥`¬_¿>Î|¿µµõôéÓågxxø[ßúÖÌ÷ßxã®®®òÇ“¾èСCzËžÉGÛìc}¢#º|ùò¯ýk›Í¦á]ä…^P Ào¼ñ»ßýî¿ÿ~í‚øÅ/~áv»•/[[[5 Ñ‹€DQĪÛO>ùä³Ï>«m0ùùê’$}ÿûß³Ù¼mÛ6í‚X¾|96ÿÖOº^a¯¼òÊøøø¦M›4ÿ”ð—¿üåÖ­[ðàƒ–¨gÛÜù¾°fÍšÕ«Wýë_¿xñ¢¶Á ºÐG}ôüóÏ;Žýû÷kK!ÇŽÃ=ö˜¶‘@:žçß{ï½;v`MEmÑ…€žyæ™L&óÔSOy½^­cùŒá ¡¾¾¾žž­Âðz½ûöí{óÍ7GFFN:…AEQÿM­Ð^@ºåÕW_µ]õ<ñÄK–,Ù¼yskk«ÏçûñŒïcmÑ^@6lÈ·â@ €Õ“5܉€l6‹]뫪ªzè!­Â@âñø‹/¾øâ‹/æ¿ér¹¾ûÝïj’‚öÒ''OžŒD"@ÖôN-žx≷Þzkdddzz:“Éx½Þþþþ]»v577kèP@^¯WsÃ-[¶lÙ²Eë(þ¾¾¾¾¾>­£ødt±Œ§Ü¹PQˆ ¢AD!‚ ˆB…* T@"¨€(DPQˆ ¢AD!‚ ˆB…*  ¹_§ ,Ì~a ÃÐxfAÅoud0‰„~ú…!4ž2 ‚€,K}}=ùP”r"Iù Œ)w.tF!‚ ˆB…* T@"¨€(DPQˆ ¢AD!‚ ˆB…* T@"¨€(DPQˆ ¢AD!‚ ˆB…* T@"þ ³iŠ!‚IEND®B`‚puzzles-20170606.272beef/icons/twiddle-48d8.png0000644000175000017500000000240713115373747017644 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá#ÔÚ·IDATHÇ–;ŒU†ÓE‰ˆ è  ¢ "QC¢‰" ‰ ¨––E‚*Q¤‘¶ÇözýØGíÛ3sß3Ïc×/aoðÚÞè˜û{ÆÚ&9ZíÎ}|÷?çÜsö~N»öB%Òhò¡F™a<‘¨c ³º]3m]ÓÊŽQÔ‹nùr)_ØX±ZÌ¥†{9! 7°™p`écº6¢qDSxÙS˵hü S›{‰ @ò/ >„H… —nì"ž…+ÖH4`jt;þ„(n8@ÀhßoÞ¿Ûr´Õ`Ql˜¬Ä.è?úøÖMCj°†?µX(‚²˜HL:ÿî¾\“H[²ø ÄÊ(0D/•0,¾sïðí¬œÙü”F$Øÿ(è宿·Ss„{µå:| ž¥³Ä.¹„zùo¾»ÍÄjÞTȼJhz†ÔrÇ£ ?˜ÀÇ«D€Ç–ŽAwf­&¦Š°m;^AÎq_F€Ä§³Ô_úfMOy"8”¨?qgR Eã¿€ž†Z›¬äz3.€z»Ÿ]ŠcÚN¡¿:'~ûI‡¨Pˆ}p!zÿz÷£f¦!$q±9'žþ¤K…ßNÕ“Ä.ýúúN(yÒ“‰ÜVݤ«²NÈ}xËG ¸Ž ²¦f·Ü›IèÿðÙÍ/ü”fël„Ü4šFõU7ɪî:$•%ŒŽdÁØ A|RîAr/½Ó [Þndñôùã(Q!pÿ¬S3UÆ„[(»„¼ûŸì$õä­óQ¿U·èº”¶ìUoÜ}ëwQÖ˜v 3„Ãq_×RÚ*/ýöÆ‘-È0¾IŒ=½a+„v¦L½8ä>øöÆOC –ŠO¥8yFp±ò¤ŸßúAÝeºçòûÞъF»ÅU¶ÍÐüC[¼Rj”Ï7Ï@ m°Jãr«/y!ÅÆöú‰€Bú·«W¶ºO·8—êÕ…jIåBä‡-¼ (c…H 6LrJôC–.oÝÙìo-eOr|ÿKC=0iúâª]LÖƒíéÞ+??R³4Ⱦé¶Ö‘kÔ.D娣_®õf©'ûsÅ$ÙÒp€Þèòia,08ùãµãW„œfÍC–y@ûz|1@ošØÑ4)ÀíöÛwddß$Wtïiâì4¹ê_¤›i,ÛfJ†xq„B /ЦÓ!FHÑ⦂Î51€±¸ ´Ž ñ-Æâ9*þe/ÖO´J£@™¸&ð èkÓÜP,]$µäœ.VóóÄ‹ù|¾œ¯§æòg9|š(` C°eWNñ›á‘mÙ•SøEÿ9yû å]pWÑ%tEXtdate:create2017-06-06T01:31:35+01:00P˜ã%tEXtdate:modify2017-06-06T01:31:35+01:00o _IEND®B`‚puzzles-20170606.272beef/icons/twiddle-48d4.png0000644000175000017500000000124213115373747017634 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA† 1è–_bKGDÿ‡Ì¿tIMEá#ÔÚ·ÖIDATHÇ•VÙC!ctFc3ªÈ‘èûiOëALZq3~å“{ºÛ$~à+Ÿ«íÑãõ;ºÔ´„·B©nIð3 +²íðDE„ül„ 3Û<*ZSm„‹Kq0Þˆ›Šè Š‘J¼ÌUÉy|#ØšJ¨?Rä{«Ä9ب;) #¶Ô-ꢠ„$òJ‹§z8|¬8¤S…¡à(&·4&ÌH¡)F2"ð­S_(~yÅ”Z fŽóíüìlÐÖ,Û*•ip'H6rSõ@î﨓ƒœ§Y8‡;|¶ÕhºH‡¶Ó™96˜øZ;ªz@¿Pæ<·àþ(¥R»ˆO!Ü+,k/éjÂÝ)s.åê%›êXýÓ©ˆ°ËLåe€Û•ŽrV™áÀð´w&I¿ØKÃ¥Vtöü‹ KŒ0QqÆgZ¦DI»;ûÝW‡À•Ô»41Âë‘ÁGzx ‹¦í—Dz>+ä‰7—ÔÊ>ß?pS‘Öx”>aæ#z–…‰±¬OEì× •lþ)Ž"rî¨ópùÆænFA¡€Ü>‚«Êïköɶõߎrë_é‹.X ŠfŒoyàÿÜàiüÁaÓÀ„Ò{\%tEXtdate:create2017-06-06T01:31:35+01:00P˜ã%tEXtdate:modify2017-06-06T01:31:35+01:00o _IEND®B`‚puzzles-20170606.272beef/icons/twiddle-48d24.png0000644000175000017500000000240713115373747017722 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá#ÔÚ·IDATHÇ–;ŒU†ÓE‰ˆ è  ¢ "QC¢‰" ‰ ¨––E‚*Q¤‘¶ÇözýØGíÛ3sß3Ïc×/aoðÚÞè˜û{ÆÚ&9ZíÎ}|÷?çÜsö~N»öB%Òhò¡F™a<‘¨c ³º]3m]ÓÊŽQÔ‹nùr)_ØX±ZÌ¥†{9! 7°™p`écº6¢qDSxÙS˵hü S›{‰ @ò/ >„H… —nì"ž…+ÖH4`jt;þ„(n8@ÀhßoÞ¿Ûr´Õ`Ql˜¬Ä.è?úøÖMCj°†?µX(‚²˜HL:ÿî¾\“H[²ø ÄÊ(0D/•0,¾sïðí¬œÙü”F$Øÿ(è宿·Ss„{µå:| ž¥³Ä.¹„zùo¾»ÍÄjÞTȼJhz†ÔrÇ£ ?˜ÀÇ«D€Ç–ŽAwf­&¦Š°m;^AÎq_F€Ä§³Ô_úfMOy"8”¨?qgR Eã¿€ž†Z›¬äz3.€z»Ÿ]ŠcÚN¡¿:'~ûI‡¨Pˆ}p!zÿz÷£f¦!$q±9'žþ¤K…ßNÕ“Ä.ýúúN(yÒ“‰ÜVݤ«²NÈ}xËG ¸Ž ²¦f·Ü›IèÿðÙÍ/ü”fël„Ü4šFõU7ɪî:$•%ŒŽdÁØ A|RîAr/½Ó [Þndñôùã(Q!pÿ¬S3UÆ„[(»„¼ûŸì$õä­óQ¿U·èº”¶ìUoÜ}ëwQÖ˜v 3„Ãq_×RÚ*/ýöÆ‘-È0¾IŒ=½a+„v¦L½8ä>øöÆOC –ŠO¥8yFp±ò¤ŸßúAÝeºçòûÞъF»ÅU¶ÍÐüC[¼Rj”Ï7Ï@ m°Jãr«/y!ÅÆöú‰€Bú·«W¶ºO·8—êÕ…jIåBä‡-¼ (c…H 6LrJôC–.oÝÙìo-eOr|ÿKC=0iúâª]LÖƒíéÞ+??R³4Ⱦé¶Ö‘kÔ.D娣_®õf©'ûsÅ$ÙÒp€Þèòia,08ùãµãW„œfÍC–y@ûz|1@ošØÑ4)ÀíöÛwddß$Wtïiâì4¹ê_¤›i,ÛfJ†xq„B /ЦÓ!FHÑ⦂Î51€±¸ ´Ž ñ-Æâ9*þe/ÖO´J£@™¸&ð èkÓÜP,]$µäœ.VóóÄ‹ù|¾œ¯§æòg9|š(` C°eWNñ›á‘mÙ•SøEÿ9yû å]pWÑ%tEXtdate:create2017-06-06T01:31:35+01:00P˜ã%tEXtdate:modify2017-06-06T01:31:35+01:00o _IEND®B`‚puzzles-20170606.272beef/icons/twiddle-32d8.png0000644000175000017500000000157613115373747017643 0ustar simonsimon‰PNG  IHDR V%(gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá#ÔÚ·†IDAT8Ë}’;Ó@Çï³PÐ ¾ BB'APÑP!A{ЂÐIHס¢K”är—·Ø»3³k¯_IŽ»$và+0k;œhYöxôÛÿ¼vQýÇ÷Ü)›ëLwæºW.0@Nûä¤ÓñÛZ§;ê·;•ßšÀÀPiùœ´VÄ/mË8ÆÑM$9EPšµ@€0Ž%¤’—HD±²¶€$£æíþ'&P9Ù2Y„b](ã\Яüˆ0ÛÐÙÜø«P°c‡·~„€j’¥’€‘¤¨‘mùÊäåý÷ €»aœ…· W ÉF²Eˆ¨GifõP]dÓÓ±¯¨ òkl(Y(«"ùÒ˜aAÂ$ž·C¿dÿ—îD([ÉÐ €úzýËÜ«€AÄ=Jig")èYúvóò eÉ "r\PØIèá‹Gߣ:Å™=`¸=Ð!u£l-ŠØ)' ZHÔ²Éòs¶®kAÉm^¥x|÷§†àT.23ud‰Øì–åí?¼w.8Ò=ffæÚÝŸÆæã× ÁºÜw†³)î…i >úLÄ'Î.ê-0âÍ ¹ª’¹í­kìµ]"‰öó²È–-™›'op)TØ·P¿ÞE³j‹R xö¤€]ÊêmŽœ²æÙh-H¦GמG€$»»9´Ð»@AwÁqˆoß9àfu¢wwˆ¼‰ç¸ßæ6‡ow$:„ÖGp®±¬%]t:V@¢v¤aÀ‰Ø“öæûm¾†²uü;/Øò"¿Xo/ò­ý)V«m^¬scª®¬uˆÇPû¶/ûìa¹å+ûç‡íHDP7ñ_%tEXtdate:create2017-06-06T01:31:35+01:00P˜ã%tEXtdate:modify2017-06-06T01:31:35+01:00o _IEND®B`‚puzzles-20170606.272beef/icons/twiddle-32d4.png0000644000175000017500000000071213115373747017626 0ustar simonsimon‰PNG  IHDR V%(gAMA† 1è–_bKGDÿ‡Ì¿tIMEá#ÔÚ·þIDAT8ËmS Ã0âèÍ›±ÆˆÒmy}IóQ äÓ8]~O ÛøÓ˜¸Yý3òŽgµþQ;Zê(ÿÇÂ’5d§ª *;ѵr!rОâ#¨ËaHAš”’•¡áF9…`$+/®„"¹Bô)þB(–¶ÎŒˆÜÚ±ãâZè+{Ñk9ü-M!ŒŠ›ƒÆT™°¿#A Êä×5Õ¿$ãPÞ:Ú¡+3Ï71âð”q RHs”_v¾¦xyÌTH86¤ŠN_÷{b°W3¶_OIÁ]4WËn0wã9=ÆÌî=˜‡(œ®ÖTó¥?=Á`·´¾ßhep¯ù“èþº¨AªG.L+%tEXtdate:create2017-06-06T01:31:35+01:00P˜ã%tEXtdate:modify2017-06-06T01:31:35+01:00o _IEND®B`‚puzzles-20170606.272beef/icons/twiddle-32d24.png0000644000175000017500000000157613115373747017721 0ustar simonsimon‰PNG  IHDR V%(gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá#ÔÚ·†IDAT8Ë}’;Ó@Çï³PÐ ¾ BB'APÑP!A{ЂÐIHס¢K”är—·Ø»3³k¯_IŽ»$và+0k;œhYöxôÛÿ¼vQýÇ÷Ü)›ëLwæºW.0@Nûä¤ÓñÛZ§;ê·;•ßšÀÀPiùœ´VÄ/mË8ÆÑM$9EPšµ@€0Ž%¤’—HD±²¶€$£æíþ'&P9Ù2Y„b](ã\Яüˆ0ÛÐÙÜø«P°c‡·~„€j’¥’€‘¤¨‘mùÊäåý÷ €»aœ…· W ÉF²Eˆ¨GifõP]dÓÓ±¯¨ òkl(Y(«"ùÒ˜aAÂ$ž·C¿dÿ—îD([ÉÐ €úzýËÜ«€AÄ=Jig")èYúvóò eÉ "r\PØIèá‹Gߣ:Å™=`¸=Ð!u£l-ŠØ)' ZHÔ²Éòs¶®kAÉm^¥x|÷§†àT.23ud‰Øì–åí?¼w.8Ò=ffæÚÝŸÆæã× ÁºÜw†³)î…i >úLÄ'Î.ê-0âÍ ¹ª’¹í­kìµ]"‰öó²È–-™›'op)TØ·P¿ÞE³j‹R xö¤€]ÊêmŽœ²æÙh-H¦GמG€$»»9´Ð»@AwÁqˆoß9àfu¢wwˆ¼‰ç¸ßæ6‡ow$:„ÖGp®±¬%]t:V@¢v¤aÀ‰Ø“öæûm¾†²uü;/Øò"¿Xo/ò­ý)V«m^¬scª®¬uˆÇPû¶/ûìa¹å+ûç‡íHDP7ñ_%tEXtdate:create2017-06-06T01:31:35+01:00P˜ã%tEXtdate:modify2017-06-06T01:31:35+01:00o _IEND®B`‚puzzles-20170606.272beef/icons/twiddle-16d8.png0000644000175000017500000000072713115373747017642 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá#ÔÚ·ßIDATÓŽ=NÄ0F}0ŽÀö Ü„š†• tH[@BÊÊIlgÆãŸ¬ Á5pøŠW=é}Šœé›fkþG µ§½ÁŒ£Æ¨œ–ï /Ÿ™Òšù’œkqËͱÙÌ!®©2?|,¸PÍÊb³€-Úü³®Ý@Aë}ñéðôŒ¡&¦I˜áqhIyãoß#™@u¯8Í×wÛ„:ÏI– “èÂ"3•þƒS0AÌý̬—~lpà}JoW§ÅŒ{öLvêeÿ:Ñàvƒ×ÚJ®õg+±mIQ‘Øvú­éѹӜ–%tEXtdate:create2017-06-06T01:31:35+01:00P˜ã%tEXtdate:modify2017-06-06T01:31:35+01:00o _IEND®B`‚puzzles-20170606.272beef/icons/twiddle-16d4.png0000644000175000017500000000044213115373747017630 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA† 1è–_bKGDÿ‡Ì¿tIMEá#ÔÚ·VIDATÓMO  âé<ÍŸQ‰¸J]‹CEõѽ®Põ» ð‹—0™+‚1.Ñ’ŠÓ3µXà ÕӖùˆÿÆÈXšQ±#Ñ‚“ݬ%ú¶¹iD1ÝŬ”ÐóÎt›Y%tEXtdate:create2017-06-06T01:31:35+01:00P˜ã%tEXtdate:modify2017-06-06T01:31:35+01:00o _IEND®B`‚puzzles-20170606.272beef/icons/twiddle-16d24.png0000644000175000017500000000072713115373747017720 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá#ÔÚ·ßIDATÓŽ=NÄ0F}0ŽÀö Ü„š†• tH[@BÊÊIlgÆãŸ¬ Á5pøŠW=é}Šœé›fkþG µ§½ÁŒ£Æ¨œ–ï /Ÿ™Òšù’œkqËͱÙÌ!®©2?|,¸PÍÊb³€-Úü³®Ý@Aë}ñéðôŒ¡&¦I˜áqhIyãoß#™@u¯8Í×wÛ„:ÏI– “èÂ"3•þƒS0AÌý̬—~lpà}JoW§ÅŒ{öLvêeÿ:Ñàvƒ×ÚJ®õg+±mIQ‘Øvú­éѹӜ–%tEXtdate:create2017-06-06T01:31:35+01:00P˜ã%tEXtdate:modify2017-06-06T01:31:35+01:00o _IEND®B`‚puzzles-20170606.272beef/icons/tracks-web.png0000644000175000017500000003577013115373724017571 0ustar simonsimon‰PNG  IHDR––³cæµgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEák Ö:üIDATxÚí}wœ\ŕ{oç0y4I“”ÓÌH›ŒàŒÆ^ãõŠ5óìõ³w°×ÞØrص±ŸŸI ëKÆc“ŒI$,‚@ŒP˜(irìœî½}ûVÕû£4MÓ“º{ÙZ|þàGú뺷N…Sç|u:zô(üMNgÁéø›,T¤Eü-J)çB„€cŒóUŒ1Æçœ’Pˆiš@Aå’ïÓÖâ¼²h*DY,ι®ëñxDsk !DUÕÝ»w···cŒÏ9çœ /¼Ršc»/¾øâþýûãñøUW]uÎ9ç$‰\¦…hW×õ»ï¾;\ýõµµµsk‘s.IR8¾ÿþûÇÆÆÀ0Œ+®¸â¢‹.Ò4mÞFÓoz÷Ýw‡ÃámÛ¶UWWç8næ•E˜…œsY–‡‡‡xàMÓb±Ø®]»úúún¾ùæX,6Çë1Æ\.׫¯¾úï|§¾¾~tttçÎßøÆ7n¸á†¹¢G¢Ñè}÷Ý×ÕÕ‹Åššš.¾øâ¹QYíÞÿýwÜq|ä#ihh0 cnbŒãñøƒ>¨ªjMMM8Þ´iSŽû…hñÞ{ï½ë®»BûØÇêêêR©ÔÂ;ÅœÁ›¦YRRrï½÷vww?øàƒðÖ[oÍ; 1ÆÉd²¾¾þþûïî¹çvìØ»wïÆÏ D‰qsûí·ÿûß»Ý>7$SV«õرc÷Þ{ïºuëÄ~Æ9Ÿ{Bˆ•e!tÝu×=úè£Ï<ó̵×^›Ë¼çœÛl¶îîîûî»O´˜—¡0ÿ/ʯPJN§$I·ÜrËO~òÇsÓM7%“ÉyûÅ0Œªªª––J©•9jB–åššI’€1–㣠þð‡?lii¹ôÒKsŠñaš&!ä¿øÅªU«®¹æšƒZ­Öysn±X¶oß¾yóæ‹.ºHØn9¸\dÑ¡ÉÉÉ;î¸ãé§ŸN&“ccc¹,ô¡d2‰1îêêÚ¶m[]]ݾð…\vÑ5š¦ sž‹2cN§óÙgŸmooÿÁ~ Ë28I’r™÷‹åºë®»çž{¾ò•¯tuuýøÇ?VÉX±„>ùä“Gݾ}»x/1ÜK‹‹¦BJéÚµkûúúöìÙƒºçž{„&æ~PƘÃáèììüÜç>WRRòÐC-[¶lîm)SÜn·Ãá›Íær¹rA #(oß¾ý¡‡€þð‡sÏ'„Ø,nºé¦O|â7ÞxcccãÈÈH(ËÀ@J©hñÖ[o}ä‘G`ûöí===¹Ìà\dÌ1Ð^zé¥?þñ^xaWW—¦i^¯W–å¹.ƘÕj=~üøç?ÿùÉÉÉO~ò“/¾ø¢Íf»øâ‹s¡/¾øâ«¯¾ o½õÖÓO?ÝØØ8÷¦(:´¾¾¾ººúðáÃÁ`†††TU{¢”z<ž§Ÿ~úá‡þÈG>ÒÞÞ~âĉóÎ;¯¤¤dÞG)mll¬ªª:tèP(€ÁÁÁWš\dbuzå•W¾ð…/D£Q„ÐæÍ›¿þõ¯¯]»vîíPôËîÝ»·nÝjµZMÓ4Msݺu»ví»ÅlXa†ñ©O}ª³³Ón·«ªZUUµsçÎêêj±2ÏñÀ‹EQ·Û½}ûöÿøÇO=õÔªU«¢ÑèÜÆ³Íf;zôèÍ7ßÜÕÕÅ9?çœsn¾ù榦¦\Ö «Õ*˲Ëåºå–[n»í¶Ý»w755åh?Ÿ žü!„(¥Édìv»¢(º®ÏûnbÒ4Mh!V«5ÇFu]§”2Æ„a)Žùó¢„CGS©TJôï¼(q4䜫ª*F­$Ióšl i1מ_D77ÆX¼Oº[sz‚wzã8ç9íឪ¼€éƧÝ{óŠgâ½òzÇ‚[ÌEÙG*þ!”û»qγ¹…y,ó aŒQJsG ãS4š×;Üb.²˜*,øÉN=p!¿°ÀFWð·`Óÿ)p.–Aœ—°ˆ!º óÚä­B„P*•ŠÇã¹YÒÏ—~½´G#ÇÃ8š’|Ÿ6÷Vþâ@áåe9_-2 9ç¹ûPÒh·Û@UUŒ… ÊrR¡,Ëõõõ‹…1–W|NUU°ÛíB6›íÔ !‰DÂ4MEQN… …1&þ;Ÿk‘k#ôöd³a…33—…w_!òêq\‘$)w;0XX‹â˜”/°à½iAé\úãE‹ Oôü¾¸îwùJœsàf45Úñ›§®¬áRf&a¾WåS’nt6ßMæß§Còf~Ì·Å€³½û¼¬”wË*ºâÌŒŒHøK²…"˲$K’¤0#z1¥‡œÖÌ^Àϸgˆ%7ó=³¦BîÀìn:åÀ4ÜëõVVVVTT8Ž5½ˆçÂô¯£“}¦Ã[ï,[‰Æä±AFÍÉI!cE aK¹wÉ&Œ{ÇåÀæ#@ƒÁH$’åŸäœ+Šrüøq·Û]RR’uêÀ@ Fgz<žâââÙ€±X¬±±1_ ßïÇã3;VTTTTT”LG0~÷»ß:tH–åóÎ;ïüóÏŸ9X¬YÈ–V"S$ŽÇãããcÌ}¡aÛ8:2<>>>66622:22JXHÅ5öû&ãé=a K–¹[þÉ@ ÐÓÓ#ØV0V=vì˜Ïçs¹\3qDDÅï÷÷ööf{{{ý~¿Óéœèóù¦{zzæNNN;v, ØÝÝ g”úÚk¯}ï{ßëèèxüñÇ·mÛ¶k×®éEQ!GXÖcÃíw$²b£Ôôûýýýýãcª1±I’eÉn·Ûl6I’ˆ¤PdÃCCƒCCCš¦B0‘Ç»öx fY]Ó”‹¶¶¶p8ÜÝÝ-ºF¨!lܸQ,\YC5 ܸqc(ÊöôôƒÁ\€Á`0=n„ÂáðÜ@EQ6nÜÒêW¥««+‰´µµ ¿ùŒ;¥`”­^½úؽ{÷=÷Ü{ö왾,/† 9 @f2Û?Øþÿ“ÇûúÇÆFc—Ó†bû¬»yÙª5kV­ß°±¢³À³%a±Ú@<;~üØÄ¤¬ë¡±î‡ôøgóx«…3Vh±««Ëf³õôô¶¶60™ …P̆7B†w6 Ðbww·Ífëêê ‡ÃmmmóBmmm~¿¿§§G…þæаFmmíš5kR©”¦iÐÔÔ4}Ö.† bÌp•­kÜüe#ŇNèI;ö††úúú;OÞ@À Lˆ™è‡Ø›UÅMMËÊÊËœÃä¤ob¬¿¬ñ²šµ×Î{0B‰7immÕ4mß¾}ñx¼µµUü}S> lkkÀD"!z3G`kkk"‘Ø·oŸ¦i­­­9…ãñø¾}ût]ÏS¬Y–ßxã›nºiÕªU[·nÇãYFÐbí…ˆ3Cr-'U×bK9p³¸ÈÙØ¸Ìá°Ùa/YŸÔ‚zlP¶8%ãþnÙQ£¸ê%«ªjêêj „€”^ªT|!ÄùüG~1Û,‹Ûíöù|N§Sðr‰P  ØÞ\.WŽ¡ «Õš Ì帙:NŸÏçv»sŠíðõ×_ߺuëÊ•+wíÚUSS3C¼˜ô§ñ±#©!DPü mð>Cós97]%͈'#¾žp$ô«áwI³¬XcŒ#mây:ö[Ä“À¹ob\ÓÔ\8z‚ˆÖÝÝí÷û·lÙ‡;;;Ó&üÀ®®®@ °e˱¢æ´X,¡PhË–-@ »»[Ðs†Ãá-[¶ø|¾\€‚'päȑ믿^UÕ .¸à±Ç{ä‘G/äœqÎ0F@@UÈëqÕ5µiѱ¾7~nj“I] D)¿*¤:»:;ÞŠ/U¥Õ¿c<Þóû‘ŽßW,«­­C1ÎÇÇǧHi fyÉ´ý [[[eYnmmD"ÂH™û…ý …°¥¥%mÍ ìîîŽD"---¢Å´u3/Pì¢Å¶¶¶`0˜iÜÎöŽŠ¢ F"BÈÏ~ö³oûÛ;vì˜~”Ì;j/ÜÜ}}}ɤމ‚±Ì9K¥ôc½=†aX­–ÆÆFÅꎌ¿9pàgVO3/½JMĉì@ˆ0ª!,#$ÓTœHŠEŽßW¼ôÒê5Ÿ!’4:<8éó@MMMYy%c€3šacc£ðŠóÖñãǃÁ °_ÒÑó7ß|Óãñ,[¶L˜ Y>R „ °_2^¯·¹¹9 —%2ÇŽKÛ/iàŠ‹‹›ššæööö¦í䜿ùæ›%%%³aŠ•’L&3Y)Š¢di¤ÀYÈ9GXÖ"ýÇÿ;î?ú)eáÒ²*ÅbMéQOEKÕú›4¼"™4«KÆ:‹¼ZU*9y/hÝ›ET«kéÕÕ«¯àÔ4Ê*ª­6¨‰„˜èýƒ¿ïi„Iæ#}н™6ÒFJ4õûýÓ‰äâ¤ì÷û3Õi¤D"‘@ 0#PœÐ£Ñèt °ŠƒÁàl@ŸÏ‹Å²€Âº ƒ3³~Áår¹Ýn§Ó)öû&Ua³ðĉã&Eá‘—‡Ý˹IʯÛjÄÕêr‹«¸QR܆¡õ÷÷'“3uÙ¬\²dô诽•ëânWù&®TO† Ù^ UU•¥¥¦i‰á±±É˜n!È`š‰¢ê÷×¶|˲”ž…¢/Ä~™e†¤™;bÌNŸ…¹³æD˜åMóh˜ùå¬çÌ’laF“çm‡Ç xrtðÀ$K±³¨ž¸VkZ1BØëu«}û&â’l-‡YÕÈ€Ù]Zÿ •Øt5œìKù_ˆLv$£}ܾ—^ÎqUÿ¯Š%5’µ|F®ôÛÞœw¾RÚ<Ûc/˜5šß=àÜj[ž|>b±:X)ñź“F²¬¼ÉZö™X '8B£qRv5‚(Ñë*]õu–6]ZVÛFøñ7ÿÛêi²5žèÅJ½ëÑüÏØ½ eMRœ ž¢ÜYºÖQ\a¦tÑÃéwž7\œaÎŒTä L£ ÜbaR  ÅÎgfRWMÓNí®%Å¥-žêsM#:08¨§R6¢£û u|ɪk¼µça‰*ö²Ê•Ÿìý§cÁÇ,å"¥Ž+UÕ¿í-®@ÄÆùbGc†¡‘ÌÔ)5„5MrÌu„MEgò½U» ˆ,LFím6›ÕjD‘¤X`!ìr9]‹i•1)'Ô@eõò†÷ý$ðÆÿÓ"'°­Ê>†°4ôÖƒÞØÜ„²I¶†ÐÈ+¡#ÏS†êZ¯÷TžÁESj‚¡I² ŒÂDöòw¾ªE‡MÝGÜëqi E®ÊU[ÐÀà^JiUóŽ¢f-Ü <å,YÅ9à±Éƒ’ÕkuÕ @¦‹‡ŽÙ<õ²µ$ããÉÄ„ÍÛ„±“s–u*s+(¾Ÿ/0w¢Íb©8Ƥ¨úlWéJ ŽP qμK6*h ÀÃ)a&íî:wñå”r«£’s@cbh¾ÐpG,Øo²zl­N$TK2ì®hq•,§RùÈxK8A _—·r}d|¿Œ“Î÷ýËDïã)mrå?æœcíwy«Î¬^{- ¬ÇFú^ÿy]ÛŠkÞ‡Ç^Ÿ<öxÓÙÿ ž²é9o¿XA–E–´¸-Îͽ(L…–Ê/Ã’¬&â¡î#ÀiIÝnO‘išcµç¨ ;Ê–W/½Ì4MF“Ô4RDpQ ö½õ+«³ÂZV“ä[+«W|Õé)Ž(MªÆp8N¦²äS6¯;ê­l‘˜aD%Ib”s L‚¹$IaB0‚!H’$„ Á€À$„H’̬¤Å½ÉÝSi0DPЙÄm˜…ÿ¸Ûíä¿x<.r WáIáœr†8§Sg&çôä8Dœ1frffx;g)WùºÆ3¿æ(jÒ ÞßwÜ4Y4¦9ºiR"Y¤Ä~š@Þ÷§¸uÌoàŠTÚ×›’WPGÍèè0pÆ9ãžsT^=6:*ÅņrrdާБ÷\PM$û9§Â»ïñxrqgÔÜçó ×®¸1ºX-ŠañÐCíÝ»c|å•Wž{î¹Yw W!ç,æ;ÌL5E%€ãNãŒB@ a9©N„GÆLJÞ¢xs„1çL²xÜeœ&­ª(Jµ`Ðïv»œ.ÏhçïÆ»,o¾œ¹½Á`€Èv v_ ÎýQIYŽ,xltä䣻ÏÖX*>6 K¤ø‚HB ņ8&EØû@(ÎÑô˜µZ­9¤òíeJ©ßï=›þ}Á&]H‹"Xqë­·Þwß}ëׯ×uÝãñ\rÉ%Âå´0r.&ÓÈÑZ¨;êÉ’k–Æ{â‰^ 6à)²äZboŽNþ9Òñ'Êqæ/zªÎæÀÅ«pFM;²ªªjp`ÀH%'&ýÑ‘çÆ»v•6}¨jõßq@v ïy;WYœÍ±dÂǹét.à\K’Ãæ,Fõ¤:`±•Ù€ÌdÄÔ'lŽ "9ajsŽ®E¿•’ÖV&wT¨m!- ã¶½½ý¾ûî»úê«·oß.\ÞÑh4+W [ZõÚ¿çT3L<Îè’Ÿ°Y8c€Œ‡–LxÊ[K—µš&µ{—ršB²%ã70pÎN‡ÇëõBªªÇb´¬ùÊš5×PJ‰l—!D#oTÔm¬^ÑTëÜ÷¤¡Ž7·üˆÑç´óù_¸–œYÝü„pÜßqüÕ_—·ÞX\³ ï~xrèñš³þµ¸b£†ªž\yån{–‡gmm­˜ŽY‡Š‚[dŒ‰(#>|xݺu^¯÷{ßûÞù矟ub)<^ˆv–¬ô.Ùä,Y)ÞÅ^Ôä©Üä®hñT¶ÙÎYÊb/õTnôT¶É/çl&v!g•••)å,I\k ûYªª‚‚˜¿+EŽâeÀ ‹Ÿç'þmPŒ ˜ŠlàÂìÃ…èò³".—ë§?ý©iš·Þzk0ÌŠú.0äË8gÀÓ‹¿p΀ââÅæz%Ä©é?ñ¸1t¯ÄÃŒÑX4Øßß76>¡Æj¨ËæZbsU!ĉ$7OB0&˜``&˜úð$F€ Á˜ Ä#B$a.ă•‹à)ÖïÂ[§LqØ?ï¼ón¸á†M›6 ¬„'í€3Ó?ø¼©(rÔÂÁÁ=qc@ð]Š%—ê¾D)/ª>ËâªÍ&Üq†%[xôµñ®‡ËšþWùò3|¾`$6Msrb" PëY‡56‰‘".³D<Θ œ‚¥Êg"G€uƒ#km2…ñB8Å,`©Öu32– dY^Ü´Ko¿皦‰#„ø¯hQQ”‚oJˆðSkk«×ë}æ™gš››÷ïß¿bÅŠªªª¬ IÅ £¯@S#ý¯ß¦EŽc[-”}¾G@ïlÞ°5@ô5½À8ªk¹Þ]y†EA“ wGˆÐ”õòT´ÉЀʼn‘‘ÃHr$#D8K1j ”>Ò¢wÒÆ3ç÷Ü¡®®ÎívçÈ;ʸ„5ÄØ××7==ÄÒ¥K].W.- [CCCæ")ãÅ_¼å–[Ö¯_ÿÝï~wÆ Y‡Š…/’À)BH×õ}œó¥uµ.—ƒR†1êëŒÅãee¥ÕU•¦ib"3Æívût%Ba™Ñ$6BŒR=™ëMM"ÉZÂ]ð^S!L‘µt]7 CäɘžccAG{„eŒ1ÂæÔG …EÃɳFXÁ €™i¯œ3nj€Äw€1† ±Ù€žsÚkªšÎ1Sº,ËD’ûî0“¥­7‰…´ÿÀÿu–®)k¼ V#}#G~]¹â*WÙ„p`ð…ÐðŸ«×þƒ»¸–13½.ú¡¦B˜555b Ô´ôBºÀB‚ên·Û)¥º®/–ƒí¤`"a,!|2_Æ" æc|òà& ã8M…Bù™}‚ˆ%î;¢E‡‹j>àpz ;n@™>ÐGN'£)ÎM¦öVãp8ÂLš8¦Óét&Q”`jŸÕ*¹ÜF“¾x÷¬Sq.„ŒHÅ"¶(~G¸{f\ 6g£ÆàÁ;“ÑAd©÷Å“¡C÷bc„c85Ý¥:4úr¬÷猡ªÕ×8Ë6pΚǠ@qš²:+kÖ}ÎQ¼ÜLiŒišcÉZ ”šœQΘÅYK,^J)BŒ#ÙêZŠˆRÃ’ËâªåSj2Jßã`–¤™2»è-Î1•0 "’]²¸¹ì`Œq@Šd—°—#q–LM“ E¶x)D@ðv fÖá‰0çTR³¸øƒb?§f’+v>5Nçk‚™¦Ø·‘Øc8瀄ÉÛ Š$;¼ñ aÉÁßþ(!"SjŠÙoŒBdm‡<}+iOËõß-xâ¢Bá~Udr¼ý~‡Óë‹{ïýõ£)øþ†ÿýþsΊEC’$Ý~ûí½½½çŸþ 7ÞD Á‚™{¦´Ì×ç9«Õв™Y3ˆœC0ïc" p^@ñŽ6›­°¤¨£rŒ1ËäÐk‘ñö=ÿz¬·'a‘ 2¼glÀŠ- ðÑ£G}6‹&âQ"Éâõò¿ˆC.8޼^²` `–ô÷÷ç›]°èëëëóM\! ó5ßE5?rÎ1‘ =8ÒñûñcÏ Õkþ¡ïÉûË• Âív—––ΘFbn Ç㙞ñâ´>•ñâÞ{ï=zô¨¢(gžyæ‡?üáéƒgÁ¬VëK/½´k×®?üáO<ñÄt—$I~ $ž4 ÷x‹¯ß¶Íctíû÷”æã =ð›|êºÁØæit5O¿>O)u¹\â²|zóç‰Ün÷i$fŠ÷³e¼8½D¬(ccc?þxÿË/¿üÍo~óž{îN×¹TˆúÓŸþTTTTRR²wï^ŸÏ—m\q.IR‘×õ¡÷ÛoüÜÅß»õ–Ö3¯,[½ÍÔƒþ®»»óžööƒpÕUWqÆšªrf03™õ|b(BÄ ôÎÎNÑJŽù'0‹¥µ¨(ÊÜù'N;;EmmíÎ;;::þó?ÿzzz¦WGx[…â´×××÷òË/¿ï}ïûô§?}üøñžžžÌ‰(²½mhi½ýö;Îj©XSjë–Æ£âªkÎý—ç^ØõÐcP\\|ùåÄsA°˜¥7…ñ&tttäžB…;;;0—ü§—PJÝnw"‘øÒ—¾ôïÿþïÛ¶m‹ÇãYQÏ·U(Æòt]ß²eËÕW_ O>ùdöZ €ØìX69Ú¡ÅE%ez"¼ó÷¯üi_ [eøÜµ¯¨¬IΗ^]°˜9ç---¦i¾ôÒKªªæžB¨ß0Œ—^z)Çü§£LNNîܹóÀ±XìĉsÍB1sŸyæرcÇ·¾õ-xõÕWƒÁ`&ŒsNv»‹Ëj6H …';ŸøãS7ëæÇ{”Ò”b±~æò’Ëk¡É^"Íš(K²,;Î`0(Rëçž" t8 ìüµ‰¸¨}ÆgŒŒŒ<ñĪªîܹSØá3/„2::úÒK/y½^Ji,«­­ííí}ýõ×·lÙ".í‹=vr"°û¹gG{_û³6öÛŸEã)Æ(!¤¾~égÿ~kcêÞ÷&z¨aÓ—ç}Jž‘FiË–-‡îèèXµjÕ¼ÉN³€‡êìì\µjUŽUþú…RêõzüñçŸþ¼óÎkoo€’’Y– Ø ,6Â×^{MUÕ¯ýë_úÒ—BO>ùä§?ýé\|ñÅiz¤Ífëêîþþ÷ow·Z­W\qÅ5×\ƒ1JQÜô¾¯`É Í›ä0¢­­M>looʘ»6\Z­­­™À•+W.VQ¹¿¸âóÏ?ÿÈ#(ŠrÙe—}õ«_žwæmâ…Èeš¦ˆ;‹Kâ©TJŒwñ14ž~úéÏþó^¯7©Åê*¥‹>ø™uëϨªªL&“Œ1Œ `ÌÈÌ$fp¦T¤‘…B™ù'Bííí‡cùòåâl ®ÌsÎÓ®ÎóO „Þ|óM—˵lÙ²L dܵÏQDWœ8q¢0iCCC>ÒïÚ WŸ”V«U” œ•x!TeµZElHLU‘b!ý£cMÓV®\ù½ïÝêr'‚É¡Ë7ÕÛK«5-–&)qjˆÛ]s¼ª8¡OO#1nmm=xð ßï///ÏšR<#'ålÀ@ PVVö?c.Š·‰JÄtš‡x‘®K“ù—Ì/ˆ ¶¨¨hóæ34-iVºï;ñr½wý;nÔå–EËív·´´@†Ÿ7½Q‹Š†3,‰JO­­­éûìi B¨µµuFàé+iùlw³}¤¹˜‚"C~*•ªÖ\kq”q^H—ÍXÉÔÍlÀÆyÿ#¥À‹Ú„Ó41–KêÎF <Ç"ËñŸ{Ggé8_`VÆ‹Y÷uóâO,üó•¹3éÀornå&ÄÝŸ¼"p™·¥ó¢ É7ÿ„h(ÍÎΕŠF xÔÜŸ0S $^ˆ|Rù¸€l"ì öó|Œ1Q\/¯Gåœ;Î|Kdñ©Šù¶(¶'Q5_)¤Z c¬¤¤¤„ªª”Ò|M|asÎ 8âyaUQD»ù&®P¥¼¼<ߢ/éƒSî´ž:¨0D¾ )däã)(LS”CU”´ˆçLs/òjQì/â~S¾Ã´à…tA—Ó ¦ALÿ¼Ÿn×Ì œíÿç–L;¨°YDÚ¸ U âÅlcbêTˆ4ï*b±€§BD"hqÿ-ë–ýÉÞXHb÷ŽD"½½½Y©NùTŽÙ’|BB¡PÁÀcÇŽe9±ÒÄ‹¹“|ž.’îÛ»îºkëÖ­7ÞxãO<1ãýÈ…&vü‰X,ÖÑÑ‘ÞÃsáOïL4íììÌ þÄÀÙˆÝÝÝ¡Ph6àé%â†Íþýûo»í¶ñññ={ö|ñ‹_üÍo~ãp8æ"^ä+bÎIMÓ:::Ò4ˆyùi`"‘H/æåOÌÆØÈ±~Çi$Â^·n݃>ø§?ýI/öíÛ'òڼ㛠oLì=B‹G…?rçOd/ráOLæX¿ã4-©ªªjnnN&“Á`–/_>}ƒXŠ“"¥´¥¥…1¶wïÞ¼øŒ1A¼Ø»wo^õ;ÒŒ½{÷æ^¿ã4q/Àb±¼òÊ+7ÝtÓúõëßÅR#â,%I’Ãá‡ÃV«5wþ„0#Ðf³åK¼°Ûíáp8wÆÆi$b;Ü·oß?þã?nÚ´é·¿ýmeeå»Uj$mMøý~‘aêÈ‘#¹„=ÓÀ@ pÉ%—ÄãqA{ÍØÕÕ ….¹äaOPEõ¯V„‡è­·ÞÚ¶m[2™Ü¼yóŽ;zè¡w§ìÖ;ëwB6lØ ëºèÓyYü UU…‘2/0]¿CÓfÑ_´çMÒT`‘(áöÛoß¾}ûƒ>8ý\‘wÆ‹ÙhYü Œq{{»Íf[±bE¾ü‰ööv»Ý>7pzýŽéŒ adùHÓáÓ¬þÊ tçžñ"ëw—x!®( ‡ßl^ÆE8ÚÏÈŸFŠ®ë~¿:õ1 œ^†C˜šš¦Í ñx|F ªªÓó#eJºÔrf÷å:e‚1lEQfK}´³PtëtÇ 5éxÍ©fÍBñOÂG%*a ¸ˆŸX,–4/ë¯gæ„ÍëÛ3JzLŸÏ§(lôÁÁÁÁÁA¡Tñ ããã}}}áp8÷hÆ_•,t!-ì›§(½³®Gf¬œŸL°xrþ…ye:¹$÷G]ÈÐ)¸àOáÜ‚€ i1ÝA™ š©x'E‚òƒÆÄ*a3uJ“Š4ñ¢°ª(§”x!ø…Ñ  PþDa@‘ãÕf³ Ïç‚òV«Õãq3†Ë¼ÑT<6öçÉ¡×ëV_YT¶‰. ã…/ Ó4=OÓ±Àj1V«õ”ñ'H¼ðù|‚Œ$“†$I)Ãд¤ª¥Ôè¨ê5ã1"/ ùC¾G0&ã'öb[Ífe¦®Í”ólvP0, F‰Õj-***@…/¤…ñ' ·raÓ/ç”RB,Û°ÁKÊäð›Göé±Qj„$o.^ÊHQåšÏëþ—ýƒ{M3U½ì»wËÓc.NSâQó¢zÀìĆye¢ö0;grÞ OîÀ ¥YLN@À1&z|$î; ˜h9¶V«ªneFQÍ9®’å)T<<&’Œ)ÿ±âª¡±ýêK×qåQrô΢m9öÞÿšN$…¦òµgÉ¢/¦§'˜—Q0c#/ çaY õŽt<`sWÛK–éœ[Uõª¯8\%ÀRC5†Ã¡’Rõ‹ ÓÑ·Š*[ I’1!‹U1¤ÉÊx1#Ëm¥F¸$I¡PÈï÷/_¾û¬ßï?xðàw¾ó»ï¾[”M…™ü‰d2yôèQѧ9ò'fdlÌÍŸ˜ƒ±ÑÕÕF7nÜ(Æé;ˆsJS*c cRUU%I’i¦Æ'ü#»|Ç­\þ±Ê•Ÿ¬ª®©©ô@à1Ùr¹‹¼^Ëår¹\‚ëpЍ‚¢WWW·sç΃Þyç0Ï]û‚Ep…SûÈ‘#V«5wþDcCŽ/Œx!\ísœÇEbRιÓéðz½[4M÷G¥ŠWW¯þ$£& ¡>}«¼Ôµví†+VÔ××766Úl¶¿Ÿ*MôÚ¶mÛ÷¿ÿýÊÊÊn¸a®Œ o¯¥¥…sž/"ÍØØ³g®ëy16Z[[MÓܳgO2™7sÜsÆqYY‰Ìœ%‰sµniKÄ£!AÔßE,¥6o3£É| ËwIÀ£>ÚÑч»»»ß•Yx²c8—$Én·G"‘|‰™À“ gm6[ÎÙÓ3õÉž‡SÃ÷ÉcÌŒEƒýýý#cñȤîµ¹«í®JŒ¹D¤¿lJ¸&6oÞ<44ôØcéºþÀLÏx±ÈÄ‹@ °eË–|‰]]]Á`pË–-‰D"/`ggg(Ú²eK,ˉ±Á&–èäÁÉã,k¼¬iåæÒ’"E±˜”ú&'ú†’ö€û¬`Ð …#Ñh"‘ˆÅb‘;Ãbݽ{÷¿øÅŸÿüçÿõ_ÿé 7™Ï³ñBHÛ/mmmâ×ßzë-‹Å²fÍš´Ý?0m¿àÁƒm6ÛêÕ«sF£ÑÖÖV!ûÌT3FíÂÔTãþ.WùzLdŒx"¡ŽŒŒÉ$G ©Ai*íKBåUàb!µ|3ëT‹ýùçŸÿÆ7¾ …,Ë\ðå/¹¦¦&ë@¼hÄ‹,þÆøàÁƒ‹eåÊ•yñ'ral`Œ{{{EÄ_ì326fT!ÌXÜ„±d25zâÏj’ÈöJAwH[¶µµµ Qa.T>S©±S€8‹ˆôô‹v‹C¼˜ÎŸFŠa>ŸoâÅtþDŽŒ QÏ(m¿¤mT]×ç&^猙šÐæÔÐ!™þg]èxSóŠ¥K—®^µjåÊ• ½^ðZZ0ÕCDZDfb‘®dÆ‹’ «“‘¸"3'þK)]¿~ý‰+fЮ߰aÃÜ/òN{ô¬â&JÂß©Ç'Jë/µÙ]Q§ËͧnCl—Š0Y<‡wR=âñxÕcn™q§å]$^@ΤìéOü.gû5NS6wuí†Ï;Kט)sÃÿí”…öŒaiª‡øûØØØ"R=ê#Íý–奄sÿ›ÃCvÒW²ô|NSœ™bŽfÍïyeÚnǀυȷ‰å½B¼˜×½Â9jŠÂœŸäÉåŽàï'Æacê_côd±ê)屌’‡kñ½B¼ÈëÓ¦ ,K¡¼Š›HÀÑcî´9K%çjˆ3îp–¹S†Æ9ã'£ÐÄëõ¦Ø‚çâB‰¹/kYü‰S&±Èþ8o¥Y$|=ibŒ3 a¢pN93AœLˆÌiJLY„%Œ‰™Òív‘c}¯Ä=áÑ×ÀÄžs¸1>~ì‰dùJ««Žú€h$lRŠ1I 3zOñB|¿âÅÂ9eâ0aÔûÒ&Ltò0pÓU¾8㜆ÇÞPì¥6÷R@(¥…â.GñrÙVŒ©ádbÔY¶^Kh¡¡GÇŽ?'ÉJÍú+)fô÷>âëU[‘RÜʤ5b[@’A’Qã$+« Y4[^?5À¹mñL –,Z¤¿ÿõŸÅ½€”t½®ÉãOŽuîBXÎÌ¡·î ¿‚Aˆè±‘7©Fú0–±dŒ¿>xðnNX oððOÅZÎRc£Ã ÙiJu•­m>û_+–Äb/ÒTs@ýÇ:tolòŸƒ®ZH©‘|eÄ‹Eæ]µ „A‰`gQÅ O󹆎ìN—®éÇ\"†ÈD"aB0FL"˜HÆÁˆ @@½åË잆\ŽÆB¡02u»ÝYVQcµÚíÅ+iê’þþ¾X\µ)„èšïÄ«†p•®æœÎ˜ÁîÔ/|>ߊ+f$^¸ÝîÙÒŠƒÁ@ 0#c£§§ÇëõÎA¼ƒ+V¬È…x1³Ö¦ç²YeKùrdo~æÙÈF,ñz<]|±.¯É )]`Õ#ÃC€¡2\zi0FâC¡„YENL†ˆ¬³â‡SEU$ÙX¼E»qÍVÎ,œéªª%pæöV.Yõᄉ¨¸š™~2(©·ß~ûáÇE9ûì³?úÑNw<-t ‡úÀÀ@GGGÚ©Ž?D"‘ººº9ˆ³£ÑèÒ¥Kç ^ vtt¬^½:ÍŠŽïX,60Ý9ËÀ97Í”ÕjeŒýùÏn?xðèáÁ‘QÆ#ŒÑ+V¬Y»6%7a"MŒŠþ•ÜïS©Ÿ?B¼'<6°TŒ=K¡8cL<’E¡¦f³ØŠkëGýñÄÿ·aÓ?)¶Ò‰‰qÎ!ÄétpÎlžœ±T–þ`jEá…E™˜˜xæ™gü~ÿ×¾öµp8œé±[âEKKKñ"wþÄt ˆ¿ÏÄŸ˜‡±!\µ3Óƒ±¢†÷½ñ3-6êtyƒÁÀŽ;~ô£=óôÓ#£>°Ù,N§³²²ÒãñêÃÆˆÛíu»Ý.—´>ÅÜn·Ûíµ[W{mîv{ÝÞ" I€Öç°[ܯÃÂØäJláúúúÒšÍK7~ÙHL µÿbtøD"¡ðŠŠ ‡ÃÁeTŸ2w³E˜Óuuu;vì8pàÀwÜýýý‹? !ƒxqðàÁ#Gެ_¿¾³³3“?1Û‚–¶·· `GGGfüa6 ›*(ÔÞÞ~ôèÑuëÖ=zTxÌçõ±qfêÑÉ#|ëÌ_Ýÿ»P(’$·µm(·œXµ¦¥õ¼=.ãø M†šÚ~ĨÁ™ÑñÜOݵçU5‰ŽN:Ñ»³bó—½U+"£ø}OU/ûnqÅòdÂxð.w+–‹Sɘ§²­~ã¿©…ãKV‹R|’µ=ÏQÚhhhèºë®;tèÐ’%KÞuâņ `Ïž=š¦åŸH…Ï:wþÄtƆa9/âÌp•­_qοtôŒÜy×]¡PZZ6üàÛ¿þõo\vÁÚ2‡#š2MÆÂaŒ1Îã€$hÊq €dÎÓUc ™qΘ)Y\öⵉРӈÊ«¡Gc©rä9a‰“¥EŠdÉãfA0|ê©§DŽŽŽwxa³Ùb±Xîü‰, ÅbÉ—xaµZój‘1.vb”Ý÷dLKb~õǯøî¿ÝºlY‹)×GC#TŸp¹‹ARˆD"!„``:*>a À4Œ@"D’$„0`LV,WÉrSƃ'üp߉~ÿ¤™R Á8ü¬¯ón-2„1É¥K*•Ú´iÓÀÀÀc=–L&wíÚõî/Òü MÓ„•#0ÍŸÈ—±ÑÑщD¶lÙÇsò©,•;~}_ÊHÙúás‹ÎnJ„G’I&K¨ré§]:øús¯¼º?‘HP\ÊäªX4‹ÅbñØêSàŠÆ¢±hTKrdoÖ F¢‘°Á`­W5# MNŽêh *ÿèðdrdh@Ó“"^}}ÃÒu×h±±‰ÞGa¾âðÂÜ{î¹çnºé¦Ÿüä'wß}7TTT¼‹Ä‹LþBèàÁƒŠ¢¬]»6_þDŽŒ Y–»ººâñxKKËlŒ¬¨½pNÚ¬¶ß<ðÀ®]»àŠ+?òé«Î<º÷?$kÑÊsþåÄ`è¿ÿ­:Ñq,²lÅÊ­[ÿ!‘P1!éÊ}KÀ™ð¨‰ÂìœS8é@À€0gTÜC˜É€€Á¥¥e¥¥¥œs„•˜ï°dq[]5<Ãxñ /|ó›ß ƒV«õ‚ .ø§ú§êêêÅ'^`Œ;–ÉŸ8„W­Z•"ÆƸ§§'Ó~™‘±‘©BLd„‘ÈøèÈW¿úTUmhh¸õÖ[ìÎâàè_Ç]‘¤ç®‡'BÁ€¨‚³jÕª­[·ÆbQŒ1Bi ;©-ÑëÀpúÎ)Î9„$ɦEÆHUÃYNO©,¥3ÌrŒœ¿ó 1ñB8ëŨ}·ˆ¡P(‹?SFЏÞ7BUÕ,þDš±17ñBXL™À4c#‹x!®Å$‚ÝýoÞ©úÚ~]dLøàåW—jñ`YÍ&Ãó¡û~ß $ÙVW]~ö:ù³ŸúPSór«¾_Ž>Û¼leccSC}ø~çÁ}MÍËššW,)%llge‘Ù¼lå²åkŠ”að=\³Ä»fíú•+–74.«,FæÄc2eÙJß® Š5øLÁé"”—vnœRâ…y‰§¸¸¸ÆÆŒ@ñq&âGª/6ñFtüÕÝ»U(òØÖ6[#¡ ‡«tp°ÿçw< œ»ÑýÙÏþýС_U—¨6» ™~f„l6;££„iC˜/·Ùì€p*ƨÚ/j³;’W™6¤ÈÄétQSÒ“Ì]\?Š¥ÈøAWYKV¯0U`vgïâøHg3‘s9¼Û@„0£†»bSqUkOÇþ±_À’bîë¸{ŒÛÊ«WvôC0€^vÑ…kƆ;~O‘S‹G㊽’).JMÎ(ãÜæi”¬ÅŒR@ a«Í» ;¥&BœX¼6O# B©É(§Ô Š«fýuVçÆòK¼Wˆ˜HŠÕí,Ye±¹µdøÌs¯¨o[î>¨FzÇúÇ$›bn^‰­žf}²§ví§ÊjZh*QµúŒ1p0–Îø*B„CìÞ¥Íg cXŠCª¸öÅÕgq$§c€‰R\ó~Æh †ÙMå¿ ñ åO ,ŒxUQ87}“£ápÊ«–•Ô¯µh‰Ð¾_ À¬«)ÅFßè±ÑšµŸuUlâÀ8cI€ðÛ>^¬p<ã#ãN~Ä[5E["ZÂMeFùg—¼Ùoš¯EŠJ&“‰Dbn®æŒ@Ñù&Î^1¦iZšyF{zzÆÍMM·‹2Î9ttt$“zyyYmUi<2lsUaÉI0‘H ÞÞ½8çùïB$>áÀ„÷+ß%BJKK H昷 Ó/Sê/"b⢩RÜ‚Q¡iš!›Í&.ó% “H £ÆÛÁ<—¸ô÷ ž:î œòû’ žQw"•J%“IÈH¿Á9Åb'Y¿¥¨eN»ÚZ°YœŒ§‹ŸƒØ«Òôø“_Èaßúk“÷– aÊåQTTD‰iTUSó4•÷– E’¥¾¾¾_þò—‘HD×õŠŠŠ+¯¼òýï¾¥¹þzdÑ‚M§‹àOôEÃ|>ß‹/¾¨ªêðððñãÇOß ïEB4M»üòËûûûúÓŸF"‘çž{î4µeà=¸Â”÷«««ë¶Ûn{úé§ ¨¨è4]Eá=¨BAŸ©©©øçþg—Ëõ©O}êcû˜®ë§éD,ÐGzºKš«!hÄâÞÉiªÂ÷Ü,"ßoÜ]º°Y첬ÑpW›ÝöiVŠ£‹ºbÅÃê,ooVë;!¬jÁ:#“]߈ÕRÊö‰›Cì×¾öµÿdàùË» öü…¯™¸•‰ LÁ» 'C]¤øúÅüaê×\Ϫۢ ;yÓ\ÎÐDz—TàßÃb‚#`C«˜­ ,'_,X75´b9=ô!V< ¦È¥‘•…Nk#ìñ4³GIwãB©ex-TZ X³½U|HU¹¶dKg(Y)yr%cM$gµXäT{F`©?ÛýŠŸ o6•Ҥȧ!9f©ÆÁ'8ÜÒD< ˆ„ÚˆkS³x72³‰{SBDªúá[2„,RÀÄ’!v]ëw™‘ž&©³ÈÕ»•ØœÚü4Ò0Nôƒþ¸ÍÒ%ðÀË×ⱜXNó8ëΊšc^³Íç;é.,pfø’*ûN™£õ>T•:¶é*/šFh:ȳÂùB%Ú+ºè »Ô¡áÙvH²‹ž º<˜¬œ‚,¶ÓYN}ƒl3å^°'÷>Sý°Vj‰cÛ¥m8n³¤Ž²Ÿ¥ü‚íµj¶ìIŽÔÖe(¿jË4Ò'û¶Œ²u‹8Åò¦t¢ov™f7Øk‰óì»c޵u¼2Y¼þÒF§7«<¹É"ŒÌ°y“cÞ$lã,äÉ4³ˆì#áŸó§N°n±èðòõ9úF¸rD Š²±­q‡ë=B±£ut¾ôLt õn®Ú¸vûØ÷1)±´ÙŽÌ®¹ö.!îø±ÓœÚžn©ºÞ·¯ûÁ>ùåbr"Žv·ý¨#ïðUvÕ‹‰rãÏqòÉÓ’:¯Ó/DÒ?ǹ!¯XQ«1áBt K¨êÒî?dž˜ÈQóœ—Ù"l\ŽxY6ÛKB–K‰^¾¤›:W„fvWMr‹•_Q{=µ^ô«–}êÿœÔV¹"жW㨵¹œÊ¾æÙ¹ÅäköÚ‰$ªŽúð%tEXtdate:create2017-06-06T01:31:35+01:00P˜ã%tEXtdate:modify2017-06-06T01:31:35+01:00o _IEND®B`‚puzzles-20170606.272beef/icons/tracks-ibase.png0000644000175000017500000001362113115373747020073 0ustar simonsimon‰PNG  IHDRvv’ÅðFgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“ oFFsZ)òUtIMEá#ÔÚ· vpAgöö”ÿ6kIDATxÚí]yl×™ÿfxÎ Iñ)Y‡%[’-ÅÒ6í8Ç6‘½N¬¸Û pÑÕ\ØE6X´@Q›dQ,Š Øm¶õfÛE#»@Ü]$­E»ñÛ±#ñ!Ù²E)­“÷"9ÃkŽýc¨Ñˆ–(ÊäH²«ß_3ï½ùæÍß|ï}ßûéééeÈ t±;ðàc™bÙ±L±ìX¦Xv(þ–gΜ9tèÐW_}‡ Euuu[[ÛÞ½{ E’?þé§Ÿöôôø|>­V[SS³gϞ͛7Þçááá\»vmppçy£Ñxþüù<¯]Н\¹ÒÙÙ)§Ói§Óét:=Ïo¼Q äƒvww Çñx< ]½zuß¾}íííJîïïÿè£îíÚEPo¿ýöŸÿüçÓ§O¿õÖ[‚ÀÇ\¸dF³k×®?üðÔ©S¯¿þºPøþûï.Ùn·¿úê«¿úÕ¯Ö­[7ßk‘E·‹·lÙâv»-ËÙ³g Fõz½xºmÛ¶ááa¸råŠV«-Jo÷ìÙsùò奮(D$‰S§Ny½^øÎw¾S¸@)¿J¥Àjµ‹ß{ÃâP<66¶uëVñ´½½ýµ×^+î->ìñxà?øÁ¢<£ˆÅ1ÚPÕëõJeæ>tèÐþýû‹(ÿÈ‘#o¿ý6´¶¶¾ôÒK‹òŒS»(w-++»páÂõë×>lµZ ££# EøáÇß|óMŽãZ[[ß}÷]]dÛ1o HKK˦M›€eÙÑÑÑÂevttüìg?ãy¾­­í¿ø…J¥Zݺø‡?üáöíÛëêê0 ëêê:}ú4 R^^^ ä_ÿú×ï½÷477ïܹóæÍ›BùÚµkÕju!’Y–D"N§€çùP(8Žk4šÜ×.‚ÑÖÔÔtwá÷¾÷½Â§/¼ð‚Óé¼»üèÑ£UUU…H¾zõêŒó—·ÞzkN[hFñîÝ»/]º466FQ”N§«¯¯þùç¿õ­o-|O‹?õxà±¼Ò&;–)–ËËŽeŠeÇ2Ųc™bÙ±L±ìX¦Xv,S,;Š?öù|‹ýPK ²¬Qøý~9ÄÚl6ù$—––Ê!Ùçó-+ Ù±L±ìXLôlHR*èTj†Ò–Í"¾.&&, ±Ø]Î…¥HñH×û):@˜rS=O‘N5n]ýØ›‹Ýå\XŠŠ‚0¯:<ÈsÌlmxŽ¡Ãƒb㥌¥Iq=ð\Z xžÏ: Ãƒ<—¹A¾ž°,[xË¥¨(S=(Д»½a$4€ãx4e …Á` ( ˜0àu'Ìu2uƒa˜¿üå/6l°Ùl¹[úýþK—.=óÌ3bdˆKŽâp8Ìóü€¢èñzEÑ4=[m":îéû#Ï1_¦¯Pã¥$I Åb±ì¦\’c˜*V½êkv»½´´´±±ð’’’døF:T ˆRÊ;MÓÁ`EQÇcž‘îƒ<Ç$)ÞúRcÈÑg‚ ‚˜­Çq‹ÅÒÙÙi2™ÄfyòKQÔBb­~Eeó‹ªä9f¸û k GˆŸ IÇkjjtÌ% 1d§F£ãÒPÕh4iòÇtéË5558ž­R¼^¯ë«žáîƒ<Ç ¨²²ùE­~EÝÎËyò›éóS :kSeËË€*AUOLû QWW·råJ ÃÓ-'St@Ú&EûÓñ è, †­\¹²¾¾>k ÆSª2@ëöê¬Ms÷i>,÷÷÷çÏ/,–E¡³¬Åª_Ž'9€©¿¹Ãá0›ÍSt›2/rªq«XN‘™*á7¥RY]]M’¤ä€e¦½­8ü °Z­MMM×®]knnÎenq¦$IÆ“ü¿Ës,/(ÅápXªW¬˜2W§XæQ·TSÏÛÍóˆ”_¢²fæÞÔÅœöo>,Ë«(’”çΗÿ™¤|<Ǩ4%tûì³ùl~·Ùl9ZÊ«(”Z#an@P€ºœƒÉ]œ\Âïü 8üY26.hLžçÇÇǧ]ý2æ:@…¾Â U@‘½!ï Ъè°+6Ø‘ Òæccc‚Áó|26þÌïü¸ÌB(`‡ *ÂÜ XÜs"ÿä9ZÊ;Š ¥-†ÒžgãCnO0ÉMZ²)OŒ¼ Üò(Ô:ÂT‡›Æ(^¨ÃxÊÓÅsìèßJ[â®DÌ-T©1SæýF÷è#tF&Ë2Q7M:cÁ[éD8#È\ Ú•™ _wÔ?M˜tAç´ q3QàÆZò0¹¸ŽcÊ4f–ØT,â½ñuƒc J@XQQ׿(,•Å·,U­zkCIIÉèÀÅðx§¸¾C˜êbý_ ö1Ç2c7IçJM‰JÍÇÅnhJuÖU IîÂQ,Ã0ÑQVû ÍÚ­):@‘½Ù#û8…Eà8ª·ïl‡ÖPe(mŽnU¶¼‚›V€ÑfK+Êô¶u#]ïë¬~×ñ‘®|É“€7 P;P6¨3׿z¼F[“ÉäÀÀ@æwÅóZæ¿_)æy>Š§Â¦N5nUãO˜*ž`Ò©¡¡Ádjr¶–åy6>áŠO¸,Õ­¿"pÓ*cù¦àð©ÉÆ#Š4ŽíÕ+k•*MÖD£Q‡Ã1㺾¬X »A©EœeÜ ¨bŠ_€Šú-–ª§µúr@½e³ÞÚ¢Õ—[ªž®¨ß"–'Ó|–ž•Þˆa˜…çdÅ3ºlµZm"‘în044$Ö®jÜð\’m¶ê†'ű³gʼnœÃ1Ííâ £OÈ{ƒšmyê'FG³X#_@éÂEfŠ£˜eÙ»ä®0cd&Ïó(ŠŠ—{½Þi#7Ò¨Qñ/rëÊŸ žQÍ£ƒ—ÒŠ²’‹›Í&£.N'BïUñ”cJÀ1‰àÐɬƳÕì«´¦wAÄ`0Lzþ!Nk4šì©å¹LkM’¸£5T©1sx¬So}(KÑË)NÅÞþÿ›:·z`zZyÎZ­¡*7Å ]ØsžM“‚9˜ëžÉ˜ƒÄšº–mñ‰AÁéú±|“Þºl6¡Ãé8 ŠÁ  ÂÌjlÊù’ã%ª2/“H“™:ž†I~3“sƒ/ªâ88ÆGc®ŒçTgm 9-hö ÷—þÁ£Ð¸å—Ò» ]ýo°Õn³Õ>+æßXFŠ SôöýýýÂËG¥5×MïÖœµw#âë žÏD¶áu`lÍT¨ËtÖFÂ\¯37¨‰2A8Ž Ò—yïEã-u½bÝÞÀ Õ•Íy»B°Ãó“S¤Sˆ„”¸I]jl »,UOkt傉†¢¨tÕ@ÿˆ®æ%´:ùc;ïWEAXÔ¸•0¯!Ìõ:s}8ý>Ÿ¯ººZÚÇq‡ñxÜâ2^4Žôõ‚ñiHŽiõó½û¼Pü|>ŸoFhJ¨Tuuuóªô ‡ÃÒ…ººº:é¼.ãyâ°´IKEhµZŽãØ4Í24H_kŠ@¡Äª©)xžQtaלäƒÑhôù|B@Ïó£££555ÓøåUØívOh†Ë…Y€˜Ì¡7…XØiåù6–‘b*Ô?t彩óI³, oøçìÖ³ÔVýŸS^Ä‹Ep¼"ǃÁ ÅbÉòœêmM˜1>::ʲ DZ ó*z@F1n*ѽíõzÆçíÉöœb¶jÕª ÷—îÞÿµCSöÍdŠ»_…Jk²TOå1Ç JÌTSx¶Ú9çR”””H#<4 ±,Ï)Š¢tØ <£à‚ÕÕµªp8~¿ß?xÌ?vVO·oø/0O·‹ól,ïZYíu/žFúû¹tJLZžOmžP*•‡c*ÔQ‚m‡Ý¢ÈŠlãyž"û7Õ+UåoË÷«]<Ìf3¦A@tP#J™Ù–Œ¹™äè,2nÅñ Q ÞŽuyTïñxîܹ#.lR¡ÉØNÓBPüà¼î@ˆŒŽ´SC\bMÑ4Ýßßã¸ÝnŸZ©Á­÷|¯üqß/fŠHDÇF$‘ñ:kÓôˆcš¦].(7€¹J‰)’ɤJ¥’;5¬Œ³»Ùìb`£à=œ}Ù,µR»x®…s~üÖ&<_ ü E ÃD"‘h!éî+ïW£mÁ”7~×\ù·ÒJ¥Òl6ó<X–Íw'ëìîY£È¦IÏØ7ôµ0xFñ0l:îöÿ Ñ”«M@e&"‰°,»¬(Š*Ô,tÙš­„y5‘ÂÿC¦Ù݃fç†`®!¨ 7Ö %  1þÚ(îÜX»‘ƒÎbf>¨lyEH‰#ßSß¿.]¬!9"·Kʈտ*Ì|o¨Å̡ƬY怬H‰ù6~ 3—&þº^w‹YfwÂAØÓÝuú¢¤Âd_§ÀWîýÇ©T_GŽÉJ5³yófa§Š¢'OžœÇý–>>ã‡{dÍl)Ÿd¹t1w–8NÅC‰ÈðÀèÔZÉã´§ëßc’íÒÝëׯ_ F*"ŠOqØÓí¸ïd™DÄ×-lzqz%s?RåPsL<âëŠøº@©)évMq:ã|îkŸâ®ÓïÏ—8¾ñuñ3Ò}°s ’¦3ŠB­Ñ–5îd©;âÖ-&9ÑucÊ·f-ácž…ߺ%ŠÿDIIÅÉÊ–—Gº:Î] ¿82UKèô¶f¬j#Ïó)Ê#Ù7ìùLl°ÊN _ÿ°Œ`ªxŠì£ÈÞ§UwƒeÙ<ºr›Îâwç³&eä˜4ø|¾ÞÞ^ñT§Ó¡JÌPÚR¶æÛ«{3ŸÄÄ Ã;v,oˆßï?vìXîl{rHÎEñ‰'ÄËNŸ>=éàºìÚµ[£QÝfÿþýâ~.ƒÁÐÚÚ:_ÉBfËÎÎÎÜ»º„Ì–ëׯŸ-³¥|’sQ|ìØ1ñ˜¦éÏ?ÿ|~¯@·Ùl?ýéOzx³4oŠÀò'Ÿ|Ò××'4Fäù矟/¿Š’ÙR>ɳR‡/\¸[·n>¯yôèÑ<{V[SÙÞfþÉnû;ÿúÊÏþóµk×"’•ææÕã|ðxÉÎ;Ÿ{î¹<åÏ‹‹{æ·X’g¥øÄ‰Â~Á¶¶¶7À™3gòÑGŽÙ·ï_êkL*%’Ž J¿$.²%ßþqÒŒ È“O>Y gF. ä·(’g¥XÐjµúñÇê©§ ‘H_»Í £Ñh4™WEŒtòü´”:ËZÎÔö? ¤™©òÝ»w›LEX.$³¥|’g¦˜$ÉK—.À† p(†ùè ÁÞbSÑå––òÉ'ÿöÎû"¿(·4´µµÎoóÍl)Ÿä™_‚Ç´DCCC?TUU Ÿ;wަé|;“)Þ)²O£+€`0¸ÿþÛ·o‹mP¾ÿ¬yu5õß”†XÎÅ=d¶”OòÌ‹¶Ä8 – º"ŸA§Æm*Ì’ŽcAg Qþûßÿ¾··7Ki´4¯Y]MÇŒÞø­4­@ˆ™-oß¾m4‹Èò½Ižâ`0xåÊ•Ù.8zôèœÇãñ@ pÃ¥¾zñ~Of/±#ÒÞÞ¾}ûv1‘óH÷Ášõ?*<ѰTKšL¦"êŠ{–<ÅŸ~ú© %öíÛ'ý„·ð­ðóçÏS•#…¡è¿˜‚ìØ±cË–-ÂûMgmªl~q¤û`‰ã­¾ÐÆÏ˜Ù²(,"y†× % ŶmÛ¤åÂàM&“§NÊ!1¿ƒ¡½½}ÇŽRûAgmªYÿ£òÆïJs΂€yå•Irñ}wMMÙ*µD¯~î›;t:Ý–-[îId9K¹­¨9m¬Ž¥Â%¥ EQN·~ýz§Ói3*jJ'jWhÙö ªÄŠ~¯<Ÿóž5FQ$Ÿâ“'OºÝnaM„"û„ü Ù¯/m.TôL`æâÅ‹›6mÊý «ÕºiӦߑO²¼!Ü<ÇôžÞÇsiSÅek¾] äÙE᫺³)Š¢H–y' ª¿„H™P”Ì–òI–Ýiªx\om"dáÒ„ì?þͱÓ&;–)–ËË#3—!àÿÌÒ¤VÞÖiÆ%tEXtdate:create2017-06-06T01:31:16+01:00m…%tEXtdate:modify2017-06-06T01:31:16+01:00À=¿IEND®B`‚puzzles-20170606.272beef/icons/tracks-base.png0000644000175000017500000003055113115373724017716 0ustar simonsimon‰PNG  IHDRööjpíŸbKGDÿÿÿ ½§“ IDATxœíytTU¾ïçÔ<%5’Ê@B‚™1é' "8m…HÛ®n×EÅ öòéÕ¾¾+­×qݶ{u/í‹zénbô™î¬Û­-ú‚L‚­™ I%$!sUjH¥Rs:çýqÂÉI%©T¨¹ÜŸ¿Ní³Ï¯vÈ—}~{ïïÆZ[[H]ðx7ˆ.HâˆI‘â ‰#R$qDŠƒ$ŽHqÄ)’8"ÅAG¤8H∇ï?~¼¾¾þòåËV«•ÃáäååUWWoÞ¼™Ãá„ùСClmm …ùùù>úèwÜ~›ûúúÞÿýóçÏwwwS%—Ë¿ýöÛðò9}úô£>J_ÿãÿ()) 3àßþö·_ÿú×…ÿò/ÿòÚk¯…™!âmŸ„øÙ³g›ššèkŸÏ§Óét:^¯ùå—ÃŒ\WW×ÒÒB_»\®ÑÑÑsçνð 555aFîììüä“O ¿ß¿}ûöèÅ‰Ùæ„xYYÙŽ;®¿þz©TzôèÑ×_¢¨}ûö…/q@°iÓ¦Ÿüä'*•jÏž=ï¼óìÞ½;|‰gddüâ¿øÑ~´k×®‹/†m: B¡ÐívG6rVVÖïÿ{æ£J¥ŠTäèµ9Bâk×®e®7lذ{÷îááa~äwÞyG&“Ñ×O<ñÄçŸÞ××g6›Ýn·P( 'ò’%K–,Y|ðAøí Àb±¼÷Þ{r¹üÞ{ïýè£"\ ,Y²„ @Á°Qms8$Öë¦ÛíÞ¿¿Á`€ 6„Ñ7×ëµZ¦¾£Í[o½5>>þË_þ2===âÁûúú–.]zà 7Ü~ûí;wîôù| Õ6‡C¢H|pp°¼¼|éÒ¥Û¶m#I²¦¦æ©§žŠìW444èõzxøá‡#9²´´´|öÙgååå÷ß4âûý~ZÖF£ñOúÓüÇ„3Úm‡D‘8Žã2™ŒË8Õ××ïܹ3‚ñ÷ìÙ³cǨªªÚ²eK#G’$ó›ßÀK/½„ãþí¼ñÆGŽ9{öìŸÿügúO\cccwww8a£ÚæðI”effžvì`–••fä]»v½ûî»PQQ±qãÆï¿ÿž./--åóùáDöûý6› èq-EQ£££ ‹#›©ˆ [¶lYµjÕš5kärùéÓ§ÿö·¿Žã•••ñnZÁa{ryyùôÂ|0ü¼øÏ~ö3N7½¼±±1777œÈçΛ1¹þꫯF$DóÇ?þ‘ÎåGd¦pýúõ===…›7o~î¹çÂŒÌ&²mŸ„èÅyä‘S§N :©TZTTtß}÷ýô§?w»Rçž{nïÞ½/^48Žmذ!åÿ¢G ¢Gâæˆˆ€$ŽHqÄ)’8"ÅAG¤8HâˆI‘â ‰#R$qDŠ‹ ü‘‘‘| "IY°`ATãÇhŠÑhŒFXF½ÈQú§A‘Ù‘£– ¨ R$qDŠ“‹içÄãÐ;Ì:®Pž¶ Øâ}ÛH3á¶JTʼn6fmC$8É!ñþæÝ^§I¢,.ñÑo_¬¾îæWbÖ6D‚“‰²œÖnŠ$f«C‘„ÓÚÍTF h’EâE@‘>ZÄ@QTÀ…ÓÚM‘>*‹£×¿ßñš(rTI‰+Š€#qá°ÁÚÕÕ5<<ÜÙÙyéÒ¥ãÇwtt _¾|yxÄ âBàH$ÊÂ(5ƒ ˆ„’¦4`¶¸£ÈóŠÌæÐ¡CÛ¶m«®®^¶lÙêÕ«kjjŽ92¯œˆ›NMÇápÐ>׆Õjõx '©¥DE~àûý~·ÛM’$}—¢(·Ûí÷ûý„ù˜¸ˆÃ“x½Þ0-Ý$‰D" (Äq\©T655)ŠéwL&SSSÓŠ+ìæhŠ<2›—_~ù›o¾#Âív766¦¥¥…î ½8åœ^j6›;::††††‡‡ILR \h0†††t:ÝŒNCîñAꚪV«o¾ùæ“'OÎ6ga2™Nœ8qÓM7Íw®EžÚ[øã?>zôèÓO?MîÞ½;ô‰Ð‹SC—þGßñ‘,‡/žø‡ Âjµ ¦·ž ÃfGQ†Qåp8@ 0V8vSkïùÿö¹,2Í€že˜±§‹Å*•jÆÞ+”ßh~ EžÎwÜQUU¥Ñh¤Ré²eËöîÝ;66ær¹¶lÙÂØ'þ½¸{|hL†"‰þ–:»©,KGGm±9Òî^6°xñâ’’’²²²[o½µ¤¤dñâÅblܽ@ºaªîFcGGÝÛM­ý-uIŒéϸLJÂióŒ½Wø=Š<ð½…ã/q¡,{aÅcÎ¥H¢¯¥®§«•-n:a"‹óóó¥Ä)° ,MìŽÇq@೜Ë©ït~~¾X8¤1 =—[ûZê(’ÀpîŠD޲ì0›ð{ÔoEµy 'Â@øâ¢´Ü±‘ ÀË$x׫–H$‹-R©T<ðŽ;Ìí$áJ×.çðÄô]§ÓéuM=_€ráê4u¡\.W(n·›íœMøÄß蜚QäÙ³g}|HUUÕ‹/¾8ãuFevSª*åmuyHöY«Õ*•Jæ£D1‘ðvŒêøb5Sî°LXºÑésàr¹yyy‹…õÕ:‘dšÌ宵Z]^^~þüùŠŠŠÈöX(2›†††7ÞxƒÖ÷|½…ã?P¡±X,.5©oŠÈPPl}€@šÉ¤€Ý<ŦÐaé_Æ—d²Ë•J¥V…Ťc1—³X,l¶Édjmm­¬¬looìºP™¡¶¶vûöíEUWWÿá˜ï 9 !q‚ ¦¼\R?i{Üø=»†aô´Žs´ƒðyéÓŸ×1Ú ReqÀ/»¹ÍÐZ ÆOX*½^©™6fÄYXXT÷@æf½MÖÕÕår¹€­oœ“sýcªÌr­vry­Á`óü‰3ù½¢È'δ###AV2èt:fä ‹-ZD_³ešQ¶UòZ«Â ­“úfò'===N§“Ìp¹Ü¢¢¢ A‚ll ž›3_d“Š âÜ‹[­VöÈ8;{2]-U]íË)|8ä¿J ¦(,@ß““à ÖéÙÓkh𜿳kî½Pä(k‰{úË'^nÿØ6ÒL.ZßÌüNÀ˲TUšQ¶TÕr˜a®.°~­ÁJ Ò`ô08Û¦$‘øZPU/( Ìóx}z^«öPä(능︾ãÓ‰\)¦ù…‰èOùùù"‘ˆý Óé¼rå »D&¢².n?þ"P~U^•H(ÐíÇ0Nñío ö÷Œ;§¬¯Z´hQÀL§ËåbNÁ(eÜÄ8ýQ[üsåÂ[™š³ TN„ Âl5gûÓŒ"G‰X÷â\¡\¢,Æp?‹„«+ H·Q÷‘¹ï+}ˆîÔ)Ššº’düŒ½ç}ÇèeQZ.8,í£†‹ LËuZ{ìݵ`;É®>88HçX(Šò؇Ì}_ué¡ïR˜øZÀpžDYLgÜç$ôßæ{4Š%b=»™¶ 2mA%Eù]c½Ãz³‡¼šÉöêí–KvÓ%‡/•( ÅŠb‚3JE”CßL‘þ‹¤-¨tõ¸íÃô-¾H1ñbêl•iWØœ1ý~bÜØâ´èìæK>÷Õ‘·r!M<(_ª-Z#Qcx¢Ìò""N|~µÆË ÀLg¢O‹¸>‘Êç2€ßk·ÎÛFZ@û(`\À1ÈÎ)pÉ£— ÚM—T¹U2uqzzú@×wÖ¡&f}•DQhï¼LçÇI?1ø}={Þ‡+Hçñ)Ó Á©zqLrD̉gï%‰N¦Ls}ón©ºÌØs¨¿ù}*ý`àkq¿Yª,’(‹$ʾXíñxºººè°Ó×$"R¸Iœ¢¨ññqæ#Ká‹Õ|ñjEÎjÂçííífæwÀ3@Q~×Xk¬G•WEë›A¬X,ÏZiî;zµrÿ„ÄÚõy‹ ¸šWeDÌHµ)zR |€‰å(N—®ê{bRIY<2Î#I H †ºí=;—¥ê2sßWæþcôÈ~løŒ±»Êîü/ö·ôž{4ë4k™ÂyUFÄŒ˜J\¢(dÿú;;;é—?žPY8UsÞŽm¤ytàÛ gCq!È«&nð3¥ê2‰²Hª,æK21 #IÒìì"ɉ÷Îq’JÌq!çúͦ+‡@(Íœí[IGü·DD ÂmuXt´s'x‡¼:VÁšâMªÜ5i"Äqœ½j@¶Lš¿E¢¸Îeëäm›Z¤Î@E¢*æ‹Õe‰DY$UYm.fïÓÈÈH^^»²X,Ö*1½~®.ÓwaÝ _žA¡<Øn DrÏ]?“C¯°0ÐN6ø]š É,«ÕÊ^¨XXXȞלØRDa ªþ GJ…B’$ý>§Ÿp@À›¢×eWL۹ЄXÇqöS™L–‘‘1ã0_"•Ú3 ì‰gˆr›CYL»ÿþ†††ŽŽ¿ßŸ‘‘qÛm·=ÿüó!~EêôâÈåò‘‘z>EQùùùô­)[æ22ô£3{ö,dgg¿þúëgÏž¥(êæ›oþå/à”„˜Jœ/RgÞË|´uv’>p¸"vy(wC„ËåjµÚI[Œ šû3TœgCŠ¢–N+Џ<þô8ˆ¸àóùhƒ¾ÖÖV&/òÉ'Ÿœ={ö“O> Ñ9õ‡žJ¥R$ÀàêÂCÀ¸zK ³¡Ç>LxÆ@:ÓJ]D¼`oÚá…N:USS===_|ñEˆAR_âvs›«·,ìóOôzý•+W˜…µŽÑ«Þ¶ $ñB$ ÀqüÁ”H$=ô}«­­-Ä ).q»©µ¿¹H|â©§ÓÙÙÙyåÊ—Ë5¹RJŒVJ%ÅÅÅ€a=3ͼé¼!Ó2¸ÇûY'CHÕåSÇœNgOOpoe.WÄñx<<o^öÕˆ¨²nݺ––¿ßÿå—_VWW3ã“¥K—†!¦³›³åÅÁ?††ÀÇf¹Ë΋Ïõ¦O ]úŸ1ýZßtA6›:}öÕô'Ñì&»$޳›^¯÷¡‡¢‡%"‘ˆ¶e]¾|y]]]ˆ=Q*ç۬²” oeŸìÃår•J%EQ&“Éï÷϶wÍn¯³Æðùüººº;w>|xtt4;;{íÚµO>ùdèiSvJ(X­VŠ¢ôƒ]$&Š×>e¹\ž••‘P‘ê҆†‚{šF¶ÍÑ6|Kí^|är¹ßç6~Š ²øŠ§”H$6›Íï÷£ÙMvIâ·9?h‰€c´üpvf–Ü%Q^´³ Ý#¢ÙMšÄos~è©:]ˆá<±¼€.AÎ*)’x;ˆåȹ3UIåÅ´¡°°òq‡YÇÊ箊HN~è]—@¢HfØõC“ž¹ŒÀ°É»á)à‰”×\3R|1m˜ðEêÍOœR®¡2"f¤øbZâ‡þº‰Hyb4»I_Xõ-ÍÇ~+IÏQd\Ï/Úü¿_aêìÙ³G.ŸòÎwÇwÐÓ 8Ž9¸H ‘2¤Èì&=q`èú(ÊaíwXû¿ïbÎ#‚E9Æ=ÛÙét2ÓiR©thh(à¼BšèMÿFï$±¨FŽžlôÚ°lb7wŽvY‡šÒµ7x]£n[_×ÀäBŸUeN}óïì¬ãJØx/_¾|F}#¡ ‰[õ-†®SÖ¡&?ᶴЇNéêŸhËÕòéS^m#ÍÀ¤·ôLjZ§ÓÅ ‘ˆT%o>ö[ ¨tíRÛH3Eý-uM] Ή _ Ì,Ûèw\aŽ$‡EGï“G B'½8G’ßÚíîô´ÕÿÂét3åy™‚M55ôþS6ùË_˜ëêõ÷/_÷c»¥ÃaépXÚCœ) ÿlöØGFD‰ùIÜf³ÝrË-´»Euuõï~÷»PžÚüÄËÓ ó2×*¸¶vSÛ˜jdd¤½½ù(•Jq®ˆ>V<ÄFñå—_Þxãs•d4O:u÷Ýws¹!ý;D/2b6Ž?^__ùòe«ÕÊápòòòª««7oÞz÷1¿ÊáÇ÷–cÇŽ]Ýàx-lÚôˆ@À£HÿÀźqã÷LùÎ;™óÓÒÒªªªf 0+\.wÅŠMMMÁs®&“©©©iùòå¡«0z‘³qöìÙ¦¦&£ÑèóùÜn·N§{ûí·wìØz„ùIüÀ̵Óéüç?ÿ9¯Ç¹L"k4šÿüÏÿ\rà +·b8—­òýû÷wttЕ1 »ï¾ûæŸA­Vß|óÍ'OžœM‹&“éĉ7ÝtÓ|g4¢1#eee;vìØ»wï±cÇ^}õUzÃʾ}ûB0nÆjµžúˆydãÆ÷ÜsÏì!ç€ÖâŒj S…Ñ‹Œ˜ÎÚµ“[7lذ{÷îáááyMΣ?|ø0í.P]]½bÅ 8~üx(c•={ö¼ðÂKEù óÙ»Ùn‹´Ê1œkõìø}-3iaØ-·Üæ³{܈¨0z‘³áv»÷ïßOû oذ!ôç!qz”ÂçóW­Zuûí·ÓßzìØ±9”Ëår…’Þªc·è˜¡6TUJ*ªÿø“˜,ä‘GЬ ÐbU½ÈˆËËË—.]ºmÛ6’$kjjžzê©ÐUâ‹åÔ©Spã7ŠÅbZâÐØØb:ßç÷Ž{Ãìòýû÷¿þÛÝŒ¾q n¨,®®®1ìœ0Zìì쌬 £ÁÇq™LƼ»×××ïܹs‡XïСCô(¥¸¸¸³³Óf³åææÀ7ß|Ã>ª8åDþ›Þôf³ùµ×^ûðÙñ ŽÁCk•÷®t°s,á£V«ËËË›››KJJ"«ÂèEF0dffžbFçW¸\.“Ét±‡î‚¥ßð•˸Åðšššõë×ÛM­ÇÑ·Ôå/ÿ?l;Âkƒ=JV(QD/2‚áÙgŸ]¿~}aa¡H$jnn¦ûS ÃBwœ Iâ¤G)/¼ðmÓOó³ŸýL§Ó}ûí·‡C"‘Ìö8³gF0 »ÿþûï¼óNúýRª._XñXK]ºv™P®q^À[`|_âDF°9xðàÁƒ xà9'˜B¨Ð£‡³nÝ:v9Ýy{<ž£Gy<ˆ¾ÓÒÒjjjî¿ÿ~vþDª.Ï_þ²Ê+i8c–cι›øFFðÈ#”––¦¥¥q8œôôôåË—oß¾ý¥—^ =B,ön–——”¤Ëø÷üä~©Tzçw†9Ȇ«àY¼9s|A¶ŸE/r˜$鯶TØ»‰ã¸T*]¾|¹N§ÓÈ9ù Æ ²…ËÖÝsEQúÆ9uvÍãŠèEFD‰XHüÈ‘#ÃÃÃt^Óaéè=÷8,²Ñø:‚ ¾û+W®©Õê•+WÎw¥a”"#¢GŒ~ÌoZ,/ÀpEúì]”$Îår×®]ÊbKFbÍhGFDX[a8—6þ£-a£DèÚš¯ £%âðgT‘³J¦.— C\1!Gû‹±y"R$qDŠƒ$ŽHqbêL‹@L'f7!j?òe½£“Ú™ T)’8"ÅAG¤8HâˆI‘âÄSâôf¹ÈÖLÞȈ(7‰qàÀP’\F£ñÀŒ]hJFFÌÆ¡C‡¶mÛV]]½lÙ²Õ«W×ÔÔÌ÷ø¾¸I<ýc‘3mì©««Û¿oo¯Ëå=wîÜ3ÏŸ~פ¯Á=`3¶Ž.:Æ*o^®<,ô3…çKòÎd!gÚ8Džž½¦( ÇqÆzÅ`0°—D>¯€{¼‡P_:û)¸ºèëîS>N&}Õ¼xô TÑIDAT"G#,”4L0 KKK¥?ú|>@àuš–v‡¥Ãné 9*PÝ3Q[ƒ¹¯Órù"¥u°I¦^"V,Ž[Ó$ñDÁét2×ÃÝ_û,M>—yò¶(0.à’’ÂÊu®±îþ–:Š$ú›ÿ,ÏZ)S—@ô{ÄdI<þP”ß5Ö > €„.qº|pUß¾T¢(+‹GÆy$IIÁÐ@·½§Ž" çJÕe澯ÌýÇòŠo‰ÛÏÀ ‰ÇÛHóèÀ·Nk7Eú@\òª‰üL©ºL¢,’*‹ù’L ÃH’4;»Hrâ¥sÜ…¤s\ȹ~³éÊaJ3ãõS$8(iO·ÕaÑQ´p½Ã@^«àMñ&Uî4 Ã0Àq<;;{ÊòeÒü-Åu.[H”%±m{ÒÏ^<üU{ÉY¢*æ‹Õe‰DY$UYm.Ú'FFFòòòØ•Åb±V‰éõÃÀ×Ò%ã.¬£³äkÀ3(”…þSü ˆ›Ä ‚øòË/o¼ñÆ9ÓFF£ñÔ©Swß}wˆ.˜IY Ñ^wó+ÌG÷0ׇÃçó±w›ÛÍm†Kµ@a ªfTNR¢Å Z·Û­ÓéÞ~ûmÚ3(D3m¢D¦Q©Tô†a.—Ël6[ß8'çúÇ”™åùùù<Ç12h¼¤§¬¬lÇŽ{÷î=vìØ«¯¾J¿™ìÛ·/ôÈ™6"€J¥b. ƒÅ0Eß2͉D‹/ÎÃð`Þ'àã  ù,æ»'#1Y»ví½÷Þ›ŸŸ¯Ñh6lØ Õj`^nAñOθk=‚þ±ÉÒÓÓ óQoò.ÁÀÎè›Çq§UÁ!ÍyyÎÑjµQšfOÜn÷Ñ£Gé™ 6„þ`B$ “Ñ?6z‘¹\.ÝWM€qAsFÙ¶¾€¢(‡¥ÄŠ"./Eúì,//_ºté¶mÛH’¬©©yê©§Bñ\iH»¼TÑ.¯ó]˜t‘ç…c´üpvf–Ü%Q^Z­ðèõµI r¦M>gÚáöG¾Áp^Éíobøä¡$ÝœiçW3y#‡ŽÃÒby[ßq!)Üt"iˆ˜ +w˜u\¡<Þ I7]$ñäC Ñ $Ú¹ë! ¡&ðˆh€$ŽHqÄ)r¦CäèyUF;²UßÒ|ì·’ôEÆõišr¶_®\.ØovéÒ%ú‚ ˆØsÎr¦CädÌ^Ó‘ ]ßE9¬ýk?ôé@q']AÀÃLF—'`a/Ãq|dddÆåÈ™‘@8G»¬CMéÚ¼®Q·­,dnyô{/š¥Ê"‰²H¢,á‹ÕL2™,ôUSI<ÕðºL>—$Ê)þX“[(DêùV¶ê[ ]§¬CM~ÂmiYXñ˜DQ¨ëì¢mDòƒWOR„m¤Ù6Ò \A:W±ð|:šËåŠâ<Hâɇǡ§§~ÒTN¿;6|ÆØÝewþ»¼÷Ü{ )X§)X;ßÊÍÇ~ •®]ji¦H¢¿¥NZðINtÌ8‡›¹¤ÆiÑÙÍ—|n+ž1‹ƒp"å±›Üeq\¦c‘Ä“þæÝ^§I¢,žQâÑ@’žã°ö{]–…•[û›k)qù¸sràÁápešâôŒQåu Û-:‡¥ÃΘœ¢(Êk=Û7؉á<±¼@‘³*fͦAIÃäƒ6¡uZ»)’ˆÍ7*2®·­O,Ï—l…´›Øw³³³ému† ¤YªÜ5šâM€O¼zrÀ^=P¤ÏaÑÑ®±$žÝto¾ö|É9tèq3EúœÖnº„ ¢«u™¦D‹©ôUÝ6ç¤)xõrR,Ô§ }(Š6¯dõK9)rVóÅê€A @δ y^HEvÕ=èþüÄn£Õ_\\|úôi»ÝþÆo$é÷eAƃpùòå)e<xŒUbe¯×KçI–¼)¯3ï±|Þ›.ŸÏGï‚£³(çŠÒT^Ûø$|gÚ¸Iœvys?/íòzÓM7Í×?6¹"‡ÎW_}åóù>Ûk5º¬ÀØ-¸Ýnº™ÀIZ—l8ià§À?¥<ÔÊÓ÷Œfj3 Š"ýëØftƒƒƒ“a8¹<¬‘´3-}íóùt:N§Óëõ/¿ürˆ3m¢DfA¹Ç‹(jïÞ½[·nݵkWmm­iÔ}­Á¯‘ }S~Çx<Þ¢E‹”ÚÒ…•[1œK«|Üø=X,öFfÚÙ'3mJEjèÒÿôœ~ËnšÜ566ÖØØX__o³Ùf{ Çqzï&#Ào¿?ºƒSöw†V<Ìû@ÿ¡6;xñbzü-UMQ¹Eßʶ|ÉÈÈ`¼¤¯äL›j‘ÝãCcú3tî™¶RillüðÃ)Š ¨)à 3xÿëGå7Þ¶Q­V‹D"zšÝØ}À8Ø×MMu_:ü(§æÅC¬,—ËMÆ‘®!‹Ÿ"–vyÖr¦&­òþæZ —èÍ~úØDš0‡(\³3mü%ÓqÿØ$Š,”e/¬xŒ6Äêk©û¼Ir¾¹]ð’’’7 _ÙM—x"ÏÂ… g‹)x<—Ç—( m#Ív‹.`\.U•f”oÕ›|l}kµÚHmí¼ë®»˜óu¦M‰K1¥¥¥mmm÷M¢ÈRuùÂÊ­}͵—{Í-ýì[EEEÏ<ó ý-æ¾A»é’Ïeñ:M±±5”(‹l#Í~ï¸×1,N:´X,½™bé›ñA©TFê{igZ—ËEçFëëëÅbñ3Ï<êã‘jGø$lô"KU¥Ÿ7IþzÀÂ$épôÑGó›ß0ßÂÒ2µÑF¢¼ú–ú‚ ˆÞÞÞ©–‹˜]}ïÓoŸ9Ó¦`äýû÷Ÿong†ß<.öò¶-ÕÕÕì:i&WvsŒ$Îkx"ý.—ëÊ•+v»]G$ð 鏸û9|®Ù™6Q$ÎŒe #ë&•t‘GGG?úè#æ#‹=ñs5g¬1 _Ä0L¢,çh‡uÔ$ÙH’ôx<<åM \kç-ïééaÏïÐhµÚüÅå¹a8—~cžžýœ/Ï>ûì‘#GúúúŒFãáǯÁ™6Ξ†4ÓßÕB|{KÒÈA6.PõÅ_üå/¡?â8þÊóã£û޳·Û=6|F¯û{ŸÞûm›¤»§ÿÍ7ß$IÒïsú '°Í€×eWÌáMη‡X9pbhF¡P0S]vSkK]ºvYVÙÁVŠÏiT^^>½ðÁ }ê9ÓÆ!r—×}ûö1ú€M›6­ºõnQZ®mäEúÇÍBi6_¬ÑétÛ·oßw°éë³c:\£V¬^½Úï÷S€.\àŸ ]HÎ. ±òl­.—«ÑhÔj5Ûàœ/^ S/Qä¬ ®oˆ‰3mœ3*Az¾0»“12|öÙgL ¼¨¨èž{îvî™$.Öéë^ÿíîkA0ʽ@›‡ã¸B¡˜±‚P–‘/úÕ¯~fäL›(‘àèÑ£ÌÃ0v^Œ™GôxöHMôf71 ãr¹ …B ðq;XR#Ÿ(Òųé;¡@δñŒìqèû›wK”%e‘TY4>>ÎÜ*-- ø_$Q–øåÕý¿ö{˜B¡€¿8/ÈÜ^½õ†+¢4»©Ñh˜ýÅ‹¿w –NÙ‚Š ?]‚Ï•†k×® eL£Ñ„X3é";Ì:¯Óäu~3:ð͸‹Ú¿w”¹õðÃTÖét¿~óOì’;×ܸõñm?þ"P~>©‡hÂŒ}Åò çQ¤ÏnÑ%…Äã9PIFÿØÈFæ åe1†ó gÀ=:6Ñ=‹„8ß~ÄÜ÷•Ç>DÍ=Ï{ï½Ç~vÍ2Ù-ÅCŽÑË¢´\¸jW0œ+–ÄòÃ$Q&ð˜Ð(ÊïëýìÛÿ¦×@nÏnºd7]2pøR‰¢'-°Û'‡1w®YqKñE?H[PéëqÛ‡cÖlEÎ*™º\’$GÚ"‰Ç ãˆåFëdnî†-á‰<>—ü^»Ípž:çõLX5ˆD‚-[ŸtuÓ«µì¦KªÜ*™zBpé™Ëè^6€¼žžhÊÒ‘yUfˆñþâ0AOŠ‹‹™ý2ËoÛ˜““ãuš–v‡¥Ãnéè°úˆ‰dbi§ãë—„i¹i *ì¦K +gïÆ©æqhfÜ49¯ÊI ’xBàóùΜ9Ã|¤wðÅj¾xµ"gµuÔòaãúnA6Ÿ¢ü®±×X*¯Š­oÄtÄǬg¢OÙdßÅ9Üîž>æã-w?Ž{£:·}X–$â8£5*Ñþ Dò’ ÇYÅñœ"QÓ"QI‘â ‰#R$qDŠƒ$ŽHqÄ)šúI8^|ñÅÏ?ÿœù(‰-Z´nݺG}4Ræ;?(Ä—ËÕÖÖÖÖÖ6>>þoÿöoñnNò*‰ËG}têÔ©wß}—ÞŽÐØØï%%H≋P(”H$kÖ¬IK›Éh ’¸¸Ýn‡ÃqæÌzÏòm·Ýï%%Hâ‰Ë¦M›˜ëüüüÿ÷cc’4PIzzz¶mÛïV$%Hâ‰Ëßÿþ÷ÖÖÖ#GŽTTTÀ?ÿùϬ|N=Ä­V{ûí·Ó×½½½qmKR‚Æâ‰‹Ûív:ƒáàÁƒtIø§CýAO\د›PTT´téÒx5&yAOt¸\nFFÆ­·Þúä“O¢ ük {7ˆ8‚^7)’8"ÅAG¤8HâˆI‘â ‰#R$qDŠƒ$ŽHqÄ)’8"ÅAG¤8Hâˆçÿ7ÙŸzkZIEND®B`‚puzzles-20170606.272beef/icons/tracks-48d8.png0000644000175000017500000000344513115373747017502 0ustar simonsimon‰PNG  IHDR00`Ü µgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<¶PLTEÕÕÕØ×רØ×ÚÚÚÜÞãÈÈǪªªÍÍÍÃÃIJ²²»»»ŒŒŒJJJ++,TTS-.2[[[:::âââ~~}%%%êêê“””444€|¸·³¥£œuuu·¸»&#ÆÈÏAAA ˜—–ÃÅɰ°¯¥¥¤©§¥Õ×ܪ¨¤¯±´¾ÂÌšŒe¦¡”—‰c[‹ƒlœž£‘ŠuŠzL¥¦ªž˜…‚‚‚€‚„‚|œ”{¬®²”†[†‰‘……yV’‚S¹»Á}wf³µ¼‹v9 ™„¬¨šŠu5~yk}|w†ˆ’†`…tŽy<Šˆ…“wš–‹~²µÀƒz_‰r-‡p,zD€Qƒ|fˆ‡ƒ™Žm†m$†o)ˆwE°¯®¤žŒ©£¨¢§ª³„~k‡t†vEž™Š¦¨¬ ž™œ–ƒ‚~s†s=œ‘nµ¹Å©¦œœ›šˆ„y„…ŠƒvO“Œ‘xtj”K¢ž““‰k”Žyƒcž›”¶»ÈŠ~Y‡xN –z‘IEA5À¾·¯¥‡‘x/i[3_S/™‚=OD#£•iccdq^&yi8mmm›‰T 70ÿÿÿHÞl2bKGD‘ ¾štIMEá#ÔÚ·lIDATHÇU‹[âFOvÍnõDzgAô@ã)¨'å¯Ô[KåÎ÷ÝikkiíëZúº^öOînˆÀ»¯ßÍ7I&Ù™ùÍÎL8îíˆ++@/ØÓz…ð&±ÓF@ز(µô\bs»îx û^±©†ûú`SKì”oFö ¶Á°»×ŽOöúÚ œ0FFýMˆ]vHÃÁá×d©gl`(h«ŽÙ_CïÞrÃNUƒëöÄÕ’BÂ6PLˆ_“(·²{Z)–åóz¥ cKpäÒ±9“&-ט²uáÖ“³oŒ;ˆ*²HCHb7‹$k'Û´9Sa„(£HTò¦mdÅÊsçp'l1lí®ÅffgïÄ5ëEÕh¹ÐjáEŽÇ]!%š oR7’zÒVçY|À†.àº@P æBü®¾£øbòîRÊDa†ûýiÈXñ\]Ô ‰xî2Ùå•UÜ_#’b'a*Ý!!ÓtçÞË’¼aÌ©\i f@«[Â|—/’bi}öaìžžÏë÷c™„^*“ƒ"-BìoóÐL•HR金n=^þ`ÃÈÍ?Ù|®µº@OÍ]ÙÚð,}8ýhIߎT ÑÇãùoõ¤Ìy§L½úI&¸³¬×¦¼Æt5-Nˆ”ØMè½ü ÿ8×ãMÑþdcWß-GU´GÈÜþÁ^tXˆj¥P-­FMinõ(_<ÈÇ‘§©gÙêórf:êl‘„snõdý@ER êÕkÑc]¯yw¾R8rŸ®Í:›‚y›8,m–·“Çô„‘þ´-&>;{’?Û¬ŸÐŽŠªVøÕupe£²s¸¶¸ƒ»½M‹mjBPñ‡?þän̦% BÈb›BLtœ³…?ÿòkã·ß_6fT5-9ž&Ìé|‚L¼F Žzž¾l¼ ÒøèÆ¼IßiÇОaÏé“¿žp¨ŸºûýÇ$¯\a$@ÖùœOr„ütrý ŸAÞþó¹ÿ¯F/Ç­YáY} D–8þjPƒW¾þ¿eŽŸüçÎØ­Ë%:t âú/²â€Á¾môôùèçäøeÃW:"…(&¿èÇ<3‚K ¶µ(’eÚºòÀå¿#Š5S´b8xŒ¡ Ñ ² ´²j1-ók¸R €*Ò¨˜d‡‡+C‘ %Ô0f§Àþ4$&1tJ$I’¦(š¦¸õ[Z?Œ.çôÁ6ãkñÄóÀlóɃ7´÷â kÿƒšûÿ 5Ý'Ó!%tEXtdate:create2017-06-06T01:31:35+01:00P˜ã%tEXtdate:modify2017-06-06T01:31:35+01:00o _IEND®B`‚puzzles-20170606.272beef/icons/tracks-48d4.png0000644000175000017500000000110713115373747017467 0ustar simonsimon‰PNG  IHDR00¥,ä´gAMA† 1è–_PLTEÀÀÀÿÿÿ€€€€€€ÿÿÐ…ƒbKGDÿ-ÞtIMEá#ÔÚ·[IDAT8Ë¥Tmnƒ0 uŸ–ÿÚŒ÷=@±ÿQV.°ûbNB!ÐhR5#ÈóóÇK€¨c¯Í³pö¨^à#¸x„†‚Xn¾øÐ0\h–Z€ ÝKMÕߥ¬_jðœêíþ4¦ÿÛé©ÜJ»€é1bÆòs°a©*Ú0 CtÔI&ÊÉQ’[måÄÆ±x(3%» v äXgËÇêÖ+—C¢ûé]Ò8 ³M¼5d=0‹s,ˆz—#ÆÜe]Îà;àÄ:² â¢c¾ "E[(ÕT²¦"œJÇaTŒkª$)?›îY{¬Ò?Ë6p–d~›|áÚ¤|^µrKŒ³ñuˆi›<éJÞí߈ÞI ñâ?;ë˜'õ×0L‚W/ƸÌ<Õ·­&Ó;Ñ­ý¼J#[rÅe<èeÊ€©Ê(ïö½â6Õ x8 _»•æeù/ìåxÖ~Ð.?©˜6(%tEXtdate:create2017-06-06T01:31:35+01:00P˜ã%tEXtdate:modify2017-06-06T01:31:35+01:00o _IEND®B`‚puzzles-20170606.272beef/icons/tracks-48d24.png0000644000175000017500000000657113115373747017563 0ustar simonsimon‰PNG  IHDR00Ø`nÐgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEá#ÔÚ· }IDATXÃÍYkl\Çuž×½sïîÞ].¹KR|S¤ž&)S²Iê 6кhÒÖ@Sµ€ŠØµôG ¤EÑ?ê.j×@ÒªUì ­‹ FQ)äÚ²ìÈ‘õ‚DQ$ÅÇ.—\’»Ë}ï}Μþ¸òjER$å @ç×,îÌœo¾ó˜sÎâ±±1ôÿi°GZ þc¼É‚‡}ÝÎòhð ”Ò:²5CUU]×ö!¤išªª›ˆx@„B¡påÊ•jµª(Êz©„………ññqEQ6ä@J9==N§ y¨ÜíªLJ©iÚÅ‹ßÿýÙÙÙ·Þz«½½Ýq_00ÆJ¥Òo¼111122òꫯV«Õº`Peeeå•W^1 ãwÞ)—ËÂÚ.C„Û¶?~ðàA)¥ªªRÊúWŒ±”’1vúôé“'O^¹re0Œ±ã8ÝÝÝ/¼ð‚ëº{¿¸ÊB”RBˆiš¹\ޱØBD"‘K—.½ûî»§OŸöyµZmývJ©®ë¾~MÓÜзö²ú6ß0}bÖ;ˆ¿Ì4MÀopuŒ R©øó5 }@®ë !Ö ŒBøó_€ñ£¹ˆ?!þ± ßnr¹\:^ åRºeÌq=ʸô¬5”H)9ç½½½kœ q8ŽÓh[w’RJ)@JqoŽèÊÝÿ´ÊóLÕ…»fvyò'÷VJ) ¾KQÆç\UUƘ¢(Š¢hšæO(¥²¶©±oTÑ¥pxŠªÙVÑJO9ÐŒ1.g¦½JVQuש"L½Ç–oL~ÌÌçóœó@ ày¥4“ÉD"‘ ˆß Lhiù†pŠ€hrnª„†òvë|r&™˜ÎUCvxnvRHÏ,-]EF„ªªóóó¦irÎçççmÛfŒ­×ãöÓÀX1 S™ùK2ò´UË7EÖÊ…¾‘ßáZpòò?j±cÅR¥f/)•4Œ¶ÇAØA]éÁ`°»»{ii‰¢ªjGGÇúh¾}†iG{Ÿ­Ñµüþ®Ý+ñj ÂÎg¾opdp°ß)M•` Úÿ› †û{ž‡1ÆËËËñxÜ7¯/0ÆT50a ©¤¢7ÇÃæÊøJù%<:—ÊOL%½Ð±r¹´rûšµ•€Ñ–J%!¦ßw.ÆØÌÌ ç|tttzzÚ²¬5æ¼}@D ·ºÏÌ”*fÇŽýÿ¾Þ;q뢅» r ”]Ö?9v ”¶¾ƒßîêê®™Îj&QH}(ÜÆÔÑ™L†RÚÑÑ¡(Jwww:Þð-ÛÒ†îݯV˜*˜K”uÿÕ=?ÀeÝüi&1FŒwØÚ1GÈ%?*gnQ4¸œZÓ”ÝëN?`Œ¹®‹Ò4­§§GJ¹>âo HLX×È)kjÒsÊA­#—ú¬Âq1çU&;†O©<8wõM zÍZÉ]ŽÆûž!qëΡߵj« \J)!˜R £þ™Œ1€ð½'¥þl(!š®sUéBÍžÉe—Çn^íì=¬k_ µì§L!‡¾mYµ™·ûñ?ÚÑÙsûæ§«¹å…[ÿdÄöGzŽæVó)B9H!ÀD•Â&„B” MÓî›Ú–*Ì +«3ïÙüKNż~îmAãX}"“¸`DÚY°b¡»°f“ôØÒÜÇ+·¾_u4üJ17_\úŒ*ZsǪé‘îj~šâ˜P«¼ˆ8µŒçZ½£ÍÍØó¤OÒF1é)z¼u×sŒ‡y°½}Ï7š:¾ #;Ž…bC =ÂôâòÙOÿ ËŠi‰pûÑÞ¡ßRTÝ –4ZÉ\7Wo–Ò‚á¶ìÝ7G™üq Ô\Ë^-/~¤êah°núòË/oæ`„V«Õr¥¢ò`¡XeLm‰ïð$-˱XDa„)QSÛU›ŠUÙ¹óvsÅÄO¤¶×UmˆÔlÕ’MùBÑ–MU[)–L·KfÕfU×D|÷ÚÒ†$¦ªYL¬LüØ ŸpeuzáŒP:pð« ·ÎMí]Ã'Az kV­|¡<{wŒ¬þG{ßWyt`æÆ¿híO:æ*Ac*‡Œ ÁÒfŠ"lAǘ‚è–*#Ò³ƒÑÁ}¿ú:¶‡Zöï{ê{Ý#§@z}O|§sè÷¤°1&Rx–ªêñ&VÌ%½È‰`ÛW½¨ŠÄcÃGbz&L{öÔí_t´ê=1n~²kÏp³–iR’ý{¥Ûv{B˜SËSï{N\±#h;ÕÎ^þ~(ÒÚ±ï·mébL€"Ö÷T(4#Ül[J  ‘X0hP%ŽÄºnM #º®=@Áæ*c”f²¹äÜ„WOe!¤w/Wìä²ÓÝJ #hêÇY–õ`~Þè95Î9ö<@ª€&Š!L·tuuÕk4¶º_ú`@’*A3?YËÝøû^Û»«çÏÿâÕ_\¹óׯ÷oÿî‡ñîîji5oåœûOw–oé!ƈòÂU [ƒFQ„Ðçu ¤,¸<ý^uñ§wæÙ|jùëGÛ'.¾öñ…%Çq ‹?/†±'ç<û‘m}G˶mBˆlcFVSkµÚÆ«_ôd³YŒq4õ3:B•lféüåÒO/¤vöľþ‹jãÿüÇ=ÝíÜ(f¢‘G@ )¥ã8!UUýÞóøÀÏQlÛ|òk'ö?6’[¼vîgÿæÌ퀊¾õÜ.ŒÉo{Ã.Æk›y>óœsŒ±ÂY—Qïù}E¿¯%¥4 cM,Ý 0Ö‹’Æv.!„s•…:ü¨¿†aBøt®7_•>‚‡µcDC2„¶ÓÒó¯õË,Ø|B«³mµô6ùkmúÇÅ6Ç£µôé¸_~|‘®àÿéø_&ÜC¨»î%tEXtdate:create2017-06-06T01:31:35+01:00P˜ã%tEXtdate:modify2017-06-06T01:31:35+01:00o _IEND®B`‚puzzles-20170606.272beef/icons/tracks-32d8.png0000644000175000017500000000230613115373747017466 0ustar simonsimon‰PNG  IHDR D¤ŠÆgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<_PLTEÕÕÕ××ØØØ×ÚÚÚØ××»¼ÀÍÍÍÃÅÈÂÃÃlllKKL¦¦¥DDD™—’ããã“““ààߢž’:::ccc«««èèè…‚zŒŒŠRRRqqq...»»»\\\¸¸·¢œŠ³´¹©¦œŸ˜…­®±š”„‡o•—žŒ‰~‹…t´´´–Šd…†‰œœ›Ž‘™–‹l¢š„§¨«‰‡‚{t`¨§¢•†[¥¡”…u}ym¹¶¯¦£šŠ˜~t…„ž‘l’• ™Žl„~nŒ„lž•|‚uQ‹w<‡wH’†eš’“z•…W¬ª¤›dˆeЉ„’Šr†xMª¤•ž™Œ–“‹Ž‚`”…Š~[’s¯°³˜• —z‰…{ž ¸·µ:7/}|yTUY×ØÛ¨—hOA “j>8#82@<4ylG‡ˆŠ¿ÀÃJB*"31,!trl¤š~ÿÿÿŠ®êÝbKGDtßm¨mtIMEá#ÔÚ·dIDAT8ËuS SÚ@Þ#ÝD¢ öÚ®4X žD1Z mA,ZÛÚÖÞ·=ÿÿLw7 Áßdv³û^¾w|_B #Qõ‚0ÕÂ]ûÐn0yºAÕÑ`hÌ0šˆ©sr*./&ñˆSØtr&<Ü 1k¥fÇ›¸%Aã·ïpù‰ÍÑ¡'Ü4Ä‘ªŽ “ëúx „P"WÑ%ò#*ÚˆôÀ aº.i„1†.Á¶išLgœ» ÞLÕ1 T ˜›nvþÞBÎa Ñlpò‰Åù¥œµ¼²êš é¥Pã±× °^,•KŽ¿aºnrEà•¥­ÕÒb°Û¹ŸpDgŒ+"[ÕµúöÃGƒìnP-²qšd‘™T£éïµÚû¹r§Ãþ.Û$¼j4ýzÆ›JíOÚPlèòÈ’…ãNÙ+? Ò½ã•ìAv·q X»X±ò5¿?XNìÛ–U°:Á’6âZ"4NDr€ÃõDýÙj½ŸnwK6¾L‘÷KÁ·žÞ : …ç?$µáÄ®SG¤p](½h6zµ“ýÖ±ó…Ýš_õ$SfÒí&Ó•t1{z1L|Ú~™}õš{Šm]2/#L!Äyöæí»÷>–m,d¢t¯i„Œ†(´H?}þRüºÑµ…N¨“\éŽûnNŸÕúÝ“™5#ƒ+ãçCºqlfnú¬÷ó×ï<˜¶ðSض‚ `€ÑØŸ¿¶k"§J)‚kNB²(¦ŸÿkA ÌM¡‘iQM‚; À¥<ô•ßó#×9Â!ý{YIš1y¾%tEXtdate:create2017-06-06T01:31:35+01:00P˜ã%tEXtdate:modify2017-06-06T01:31:35+01:00o _IEND®B`‚puzzles-20170606.272beef/icons/tracks-32d4.png0000644000175000017500000000100513115373747017455 0ustar simonsimon‰PNG  IHDR TgÇgAMA† 1è–_PLTEÀÀÀÿÿÿ€€€€€€€€ÿ€€€ž8C±bKGDÿ-ÞtIMEá#ÔÚ·IDAT(Ï5‘ÝmÄ@„”øòˆ]‡â- %\+ʳµ%¥â à³%ËüÌ7, _à Ìðe‚Ç*Û7C¬,8[œ*d{˜éa¶lLJêù‹"^:³Âe(]ÊK‚¨»#™å £7B½544"\»#Y:Ç-¦'®Uª¡-`%9Ã+H‰Æ£%´Í´j,®žã¤Jt„#b”LK[Õ©3ÆÈŒ¬d³5ͽœË3t¹µFØ<±P:„'$ç¢`I !Í€Ó½ Øâã:<Úvùý<_Û¨Ùö¹Goµ>OÙãÀ½ª¹ÂíÏðþì­¯ÎïÛý'¼UŽ1N½Ök5¸ w^¥Œ­/^²*–Ê£omÅ?ýÄØvÀŽ%tEXtdate:create2017-06-06T01:31:35+01:00P˜ã%tEXtdate:modify2017-06-06T01:31:35+01:00o _IEND®B`‚puzzles-20170606.272beef/icons/tracks-32d24.png0000644000175000017500000000376113115373747017552 0ustar simonsimon‰PNG  IHDR üí£gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEá#ÔÚ·õIDATHÇV[oT×^kï}nssñŒg| 6Ø`9"”І*Š¢ViQ«ÀÆÆÆÔÔ””²Z­V*•!ƒƒ@ÈD»þu½A¶PÊ-¶õ1h}ᳺJ‚–õv…ößý#VÜyã=D ¢b±è8Žë:¶mÓ>S„¤Ææ.º¹ÙÊäü Ö¢ÑçøÙ_–+“ÞnµZ¥ñyÇ/åw,Ç#bÆ–”J*â\hÂañÊ`ûñŸ’žáÀÇPyùã¶7::÷‘ÚXkwºƒÖc5ðŸ?ü¼R©0ú@) ¤·´;ˆ£ÆhefrjZk%õoŒqó'Ù eeJ4׉핊û­µ^ý=UÍ ¬¶9³Û#yO¸·,¯8h¯¥ùFuÙõrÈŽ>À€öj º»´ÌõÂgŠl)í~³ée§ìLåè©‹ë;­Al÷¿Ÿ8ÓhøZz”QÀmt) »=¶³Û‚C[Å mðHi¡]k¥±$Ѻ;ðGÊD €‰¼×}´º2>ó½€×3Ei9ž”ZËŽãõµüø·ëk_únêëƒ= ¨SÿJ%…Ný‰&'‘Now× ÞD@r÷ÍS§Ã.®oG^0º’ˆl µ,÷¶Z}5YÝ §¿†A¶r¦¹QÏUŽb©:ý#å "…ÈŒ‘¹ñóˆä“g/³£ó½ð! eÔ@8N,;oT¶›Ï~-d­­û«´·îpÀ8Íêóòì•ЉHë^Z½ÅɳA>ï[o( d$·2Ò·¿dã±|~ä‘1†sŽ€ L,˜ùÃïn\úùO7¶ºþ½våÊ•AÔ.MN¦ˆ€±cZ'¬4 HD€ŒHã'8cÔ^7M»U6›ív»† k>½uëæ‡É…»wþ’$ªYûŽWx«\%Ƙ֚sNÆhc´R–m#"QŠÍˆL'Æ"2"²m»Z­^½zu00ƇÏ~»|óóæ•ÏøåóžÄßÿÁ º@† µZ­ÝÝ]!ÄÎÎN«Ý6Æhc”RµZÍJ¹µµ¥µV2ÓZ{ž·´´´¼¼¼²²’ÉxRãÅßýì7Ÿ¾óîGŸ~ò‹So<ÿÞO /ð}_J¹¾¾®µö}?mjœóL&S«Õvvv‚ Ø?ôç¼×ëݽ{wzzúÖ­[€`Ü üû?ÞüäW¿?ºð³íu›@{ãEáºn³Ùt]Wˆ—ú¾E‘R*“É|£]sΣ(º|ùòììì£GºÝžm[¾ýåƒÕç—>¾ôþ;ímc 2Œ±v»ÝëõªÕ*"zž—.›››i»ÞÜܶk\YYADÇqâ8v]7Š"†XÛÞÝX½)OŒ@ µÊf³sssI’!R6éÖZ !Œ1)¡t÷^Û{Eý~Ÿ1¶·3!Ê$òJgÉŽ@ŒBˆt”K)_T%¾Xjˆ’$‹Þ0K{Id/2¶Ò‰‰ JGÕþ3üíåÚ#öBLׯá·eY¯š{¡ô>t÷ÿœ¡ÿ¾xB¶üK‘G%tEXtdate:create2017-06-06T01:31:35+01:00P˜ã%tEXtdate:modify2017-06-06T01:31:35+01:00o _IEND®B`‚puzzles-20170606.272beef/icons/tracks-16d8.png0000644000175000017500000000163413115373747017473 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<žPLTEÕÕÕÓÓÓËËËÖÖÖÏÏÏÌÌÌÒÒÒnnnÅÅÅßßßµµµ~~~ÚÚÚÞÞÞ———¨¨¨××מžžÐÐл»»¢¢¢ÜÜÜÛÛÛ®®®°°°ÔÔÔÑÑÑÓÓÔÎÎÎÍÍÍÐÐÏÊÊËØØØÆÆÆ¥¥£¨§¦š—Ž›™“žœ•¨¨§©©¨ØØ×ÇÇȧ¦¤‘‚‘“Ž‹€™•‹­­®ÄÄÄרØÈÈÆ—”Œ‘…m‡}_‘ŠvŒ‚¦¤žÒÓÕÒÒÓÑÒÓÔÕÖ×רÉÈÇ–’‡’Œ{“Œw§¡Šy‘‹z˜‘}¾½·À¿»¿½¹ÂÁ¾ÕÕÖÇÆÄ’}Šy˜”ˆ°¯­•’‹Œ„l‰w‹|Œ†v™Ö×ØÇÆÃ’–‘‚¤¢œŒ‚’€Žˆv™ŒÖÖØÊÊÉ–‘‹z™•ˆ­­«œ™‘œ˜Ž–’…¥¢˜ÙÙÙÜÝີ¨WO5kfWwsiÈÈÈlll½¾À¦¢™ZS>KH<މËÊÊÌÌËzzz¶·¸­¬§FB7„y­¬ªÄÄÅÂÂÂÇÇÇÝÝÝÀÀÀ¨¥Ÿ¸¹»«««ÿÿÿD/“HbKGD‰a&ÌtIMEá#ÔÚ·ûIDATÓc`F&fVffV6f0`dçàäâæáåãçeñ…x…EDÅÄ%D%|f)&iY96y)6 _RAQIYEUM]CVJH ¨BRSK[GWOßÀÅÈH$`lbjfnaiemckgpptrvqus÷ðôòöñ™áçì ˆŠˆ‘ˆ‹÷wOHL $§¤¦¥khgd¦eerróò ‹˜XY™ddeD‹KJËÊ+˜¤Š*«€ÖJU×ÔÖÕ74Ê4±I*63­ålimkïàd”’bd¹”Q’ÙÈ”d”±,Ù¦®Ùˆ%tEXtdate:create2017-06-06T01:31:35+01:00P˜ã%tEXtdate:modify2017-06-06T01:31:35+01:00o _IEND®B`‚puzzles-20170606.272beef/icons/tracks-16d4.png0000644000175000017500000000050013115373747017456 0ustar simonsimon‰PNG  IHDRíÝâRgAMA† 1è–_PLTEÀÀÀÿÿÿ€€€€€€€žÏíTbKGDÿ-ÞtIMEá#ÔÚ·WIDAT×%M‰ À@&°7± 47B“î¿RÕÓø’8)ˆD¬ÀDL5"ŤìyÁ÷ƒ¨™éáÉéÝ[Zƒ±ÚVÿ½®;±ô¹~ŠŠ}ô[€Ñ><Ž?}è¯ÍÞv]%tEXtdate:create2017-06-06T01:31:35+01:00P˜ã%tEXtdate:modify2017-06-06T01:31:35+01:00o _IEND®B`‚puzzles-20170606.272beef/icons/tracks-16d24.png0000644000175000017500000000240313115373747017544 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<åPLTEÕÕÕÕÕÕÕÕÕÓÓÓËËËÕÕÕÖÖÖÏÏÏÌÌÌÖÖÖÖÖÖÌÌÌÒÒÒÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÓÓÓnnnÅÅÅßßßµµµ~~~ÚÚÚÞÞÞ———¨¨¨ÞÞÞÓÓÓÕÕÕÕÕÕ×××ÓÓÓžžžÐÐÐÞÞÞ»»»¢¢¢ÜÜÜÛÛÛ®®®°°°ÜÜÜÔÔÔÕÕÕÖÖÖÑÑÑËËËÓÓÔÎÎÎÍÍÍÐÐÏÒÒÒÊÊËÑÑÑØØØØØØÒÒÒÔÔÔØØØÆÆÆ¥¥£¨§¦š—Ž›™“žœ•¨¨§©©¨ÍÍÍÑÑÑÐÐÐÑÑÑÔÔÔÔÔÔØØ×ÇÇȧ¦¤‘‚‘“Ž‹€™•‹­­®ÏÏÏÄÄÄÄÄÄÔÔÔÔÔÔÔÔÔרØÈÈÆ—”Œ‘…m‡}_‘ŠvŒ‚¦¤žÒÓÕÒÒÓÑÒÓÔÕÖÔÔÔÔÔÔ×רÉÈÇ–’‡’Œ{“Œw§¡Šy‘‹z˜‘}¾½·À¿»¿½¹ÂÁ¾ÕÕÖÔÔÔØØØÇÆÄ’}Šy˜”ˆ°¯­•’‹‘‹zŒ„l‰w‹|Œ†v™ÖרÕÕÕÔÔÔØØØÇÆÃ’Šy–‘‚°°°¤¢œŒ‚’€’}‘‹zŽˆv™ŒÖÖØÕÕÕÔÔÔ×××ÊÊÉ–‘‹z™•ˆ­­«©©¨§¦¤œ™‘œ˜Ž™•ˆ–’…¥¢˜ÖÖØÕÕÕÙÙÙÜÝີ¨WO5kfWwsiÈÈÈËËËÌÌÌÌÌÌËËËÎÎÎÍÍÍÍÍÍÕÕÕÜÜÜlll½¾À¦¢™ZS>KH<މËËËÑÑÑÈÈÈÓÓÓÕÕÕËÊÊÌÌËÔÔÔÔÔÔÑÑÑzzz¶·¸­¬§FB7„y­¬ªÄÄÅÎÎÎÂÂÂÒÒÒÔÔÔÆÆÆÇÇÇÓÓÓÔÔÔÕÕÕßßßÝÝÝÀÀÀ¨¥Ÿ¸¹»«««ÅÅÅÔÔÔÓÓÓÑÑÑÑÑÑÓÓÓÓÓÓÑÑÑÔÔÔÕÕÕÓÓÓÔÔÔÖÖÖÔÕÖÑÑÑÓÓÓÓÓÓÔÔÔÓÓÓÔÔÔÔÔÔÔÔÔÔÔÔÔÔÔÕÕÕÿÿÿ%Š bKGDöÜÛJatIMEá#ÔÚ·IDATÓïþ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõdÖu¹BñÕ‚%tEXtdate:create2017-06-06T01:31:35+01:00P˜ã%tEXtdate:modify2017-06-06T01:31:35+01:00o _IEND®B`‚puzzles-20170606.272beef/icons/towers-web.png0000644000175000017500000002700313115373723017612 0ustar simonsimon‰PNG  IHDR––³cæµgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEáæÛô-IDATxÚí}yXUÕúÿZ{ïsö>óaÔEP4‡4¼j‰åS”fÚí>Tßl¸¥–––fiƒ…¥eZé͹®7§JKTRDEC1Ed8ó9{Z¿?V! ìuŽP¿Þ{Ÿ8¼g­õ®á]ïûy? –••¿åÏ,Tk7ào!æ6|BÿBèEm^WØ6›×¤øÜ„!š¦)Š‚@Ø1„„a¡$I¢(bÍ$BÓ4MÓQë@™PEÓ´›×¤øÜ„Ç9N§Ó ð÷÷‡z<eVD©T*€ÕjEQ£Ñ˜L&¬Y™`…<ÏWWW#„ ƒJ¥"±"EQ’$Y­V„Çq&“Éårùz„}8G𥦦öêÕ+...>>~Ú´i—.]R«Õ †I–e–e GŒѳgÏnݺ%&&®]»–eYeƒ.I’ÑhܺukÏž={÷îÝ«W¯ÜÜ\­V+I’âΖ”” <¸G111ƒ Z¹r%áœhŽøÐ„BQÏ;7tèÐwß}7!!a÷îÝ©©© Ã(ë#†a^}õÕgžyæòå˳gÏ>sæ ˲²,+Pˆ7ù‰'ÆÆÆ ‚€wiÂ^>üÓO?]°`AUUÕ›o¾yáÂÅ“¬™âÛT–å%K–˜Íf£Ñsÿý÷×ÖÖŠ¢¨`¤(Šr:LJJÒjµjµúĉ™™™V«Ÿd-š¦­Vë„ RRRzè¡cÇŽ)ÓƒBÈó|§N.\xäÈžçU*•ÑhÔétʦWóÅ·&¤(Ša§Óév»W®\ ?~<˲n·[ÁxáÆår±,ûÍ7ßdff8°W¯^.—K™×@Q”ÃáeûY!’å‚ÿöرc&Làyž¢¨·ß~;""¢¦¦†dr4Ý ß©H’¤ÑhœNç”)SvìØñÞ{ï%''+^7x˜üüü6nÜ8iÒ¤¾}û®Y³F¥R‘Lsì@z¥³B„P||üáÇüñÇ… ž9s†ã8Ÿn¤¾ugÔjuQQÑøñã8°aÆçž{Îáp(ö³ñѵdÉ’§Ÿ~zܸq;vìh×®žï$ 5 vtY–å8N±*†aJJJ<OtttbbbÇŽ+** 8Žóé^ê[w!4wîÜüü|ŽãÞ}÷݈ˆˆ§Ÿ~Z–eü«i“eY¯×§¥¥-\¸ŸŸ?tèи¸¸ÌÌL­V«`Œ$I2 »wï0`@ZZ`úôé'NTv™ÃÚ6oÞÜ­[·¤¤¤®]»feeEFF&$$(Þç›)>wgâããEQdÆívëtºàà`ü+$IþþþIIIE¹\.„,ËÍߦ˜ÿ9„¦é;3a|ŸÃŸlrN@ëw¦i§Ó9räȪªª_ý5&&桇šsæÌàÁƒm6áÉ„¯€………«V­j0Ÿš9A½+·#SÑ"Á®ÝêÕ«ËÊÊ”…ânTÈqÜÿþ÷¿Å‹Oš4Éét2 Q¯BE½øâ‹$Îp}m„Q¡¶eBY–FãÞ½{×­[—ššj·Û ÇH’$“É”––Ö·o_·ÛmµZ«««½²PxžoŽ×Ó¤@Y–%92Û– ñᔞžîï˜X[[KnB??¿’’’_ý•¦i†a†!4!Þ™ËÊÊ^{í5Âk;MÓÕÕÕ111³fÍRÄ!5¡Wf"„V«=yò$„°GW®\‘$‰Ð„¢(ªÕj§Ó©,ÿШPåñxBCCßxã ÂÜ'˲ÅÅÅ«W¯&i‘ eYÖétøfMîzI’¤ÕjÓÓÓœ••…]GBµun¡/ôôº¡ëð0)ج¸€ ¶ GË"€†Ñq¼ò¸Ct´hYËHäy™· ¶všv§kNp*®OPe÷F£Õj†‘$Éétº\®mñb³­]»6//‡xà.]º(†ÐûB(Hé}ï Þ}‚úpgR›^øé…Ì+™§kN÷ êãZv·Š²¸là2—ä¢eT—žZº>o}lhìg‰ŸµÓ´sI®YQ HÁšà=¥{ææÌx©ßK½z)Øä)Š:qâDzzúåË—Fã}÷Ý׿ÿa¿›‡¸®]»öÖ[oáÄtEEÅÚµk¿ûî»ÐÐж°±ëñ«í×Ý%»ûõ ÖÛÛî’Ý€,ÅjŒaºŠ2EQ‘èÏúi‚:Fëkì2’[¶z ðWûo8·á…C/¸=îW¼òBÜ -µŽ™x<ž3fÜqÇ¥¥¥Ë—/_¿~ýèÑ£äà~7!6›ÉdÚ¿HHȵk×xà‚‚‚ÒÒÒˆˆˆ¶°B4¤-¼eqöb7tSjJdJ  &GOîfî¦ø^è‘<ø ªpU<óä¤ÈIÍÙx[s"¥h!@Í}ÿÁüœùzV¿zÈêÇ£·ñ6–fy™o¾*<Ô²,Ï™3'666$$äƒ>X¼xqZZÚ¨Q£|ø){Z­ÖaÆ•””TTT<üðý{÷ö5Œ®™BAÊ#{:;¿ów]9Tî*§!®:|DÇÉ£8R?ÊêÇúi‚d$·Ô?’dV›?=ýéüÃó‚Êìe³sf ²0¬Ã°Aí¹ÄìÉœwÿý÷»Ýn“É„‘®‘‘‘[Uÿ“ ÝìŽ<ø—_~IKKãy^\wÒê«àœ"£}¼ëã)1)xÐe$ËHvˆoݺD$ ¢ $tŽEQE׊€0ZæÐ…C‡~9DCZ$x72Ì)¶¬ŽGFã²eËÞxã¡C‡N›6Íét6XN Ý@—.]–,YBÓôÔ©S7lØpÏ=÷<öØcµµµ·ØÓxÇlåÿc„RòÖ­…‘B R.Á56zl˜Gs Ü*AúõiÑ×C†a.\øþûïÿë_ÿZ¾|9BèF$Ãï&”eÙ`0|ÿý÷LLL¬©©9xð À×% „†mb25¡Gö l7ðž{êœ ¼78E§Krµt’QõÊ+¯|þùçqqq øâ‹/BBBî¾û?x¤øR±zõêU«V!„ŒFãôéÓï¿ÿ~»ÝÞF–` ]°7Ø$@Ëóøv`³Ù222ÿ÷ÿ'ËrRRÒ?þñ‰þßMHÓ´Ýn>|x~~~UUÀd2…††z<žæ€ȳö8QöõbÊ]I’¼¥öf;“W²KøvÀqÜÚµkqÃP ÃÕ™ Ý„P```ûöí¢(â¿oÒ~É£Ó锕‚ë)_ŒÞ7™LjµÚl6ã™ä•±fF£Ñ AÈq¤ø”òJUð-BXßÅ{$Ï7Ä4Òžç=¸Žjò›ðUäĉkÖ¬ñ÷÷W<Íiš¶X,¥¥¥3fÌ8qâÄÂ… gÏž­xN`E×›¹\®­[·ž8q‚¼H…¢(«ÕZZZÊqœ¯K^°-4ºœ1a‹’·x‚°,»hÑ¢»îºë™gž©¬¬T|pÒ4­R©œNçK/½ôÊ+¯œ:uJ£ÑlÑ’$Y,–òòò~øaãÆ,Ë"ÆdY6™L{÷î £(J’rWŠ¢njÎòŽT¯×gggó<ÕQÔW¨Óét:ÇãY¿~½Á` 1!Þ!6mÚ4xðàœœœ/U-\wöìÙÍ›7ëõzŽãH&„Z­&›šãb:4fÌÇ#Š"¦Ž Ñ)˲ÛíX´hI‰,&©®®^½zõ‹/¾8tèPr„?EQn·;%%eãÆ‚ j£iºªª ÇŸ‘ 1uËÁƒýýý#""òóó½‡Ã.Yee%ÞHÌtìúùù}ùå—ÑÑÑ‹¥¶¶Öb±xeüýýA Ü“ÍfsNNN\\ @¥™ßC²²²Ö®]›››ë­ƒë¡(Êh4’¬B•JUZZzáÂ…1cƸÝnµZÍ0 ùºq8aaa<òa½„ÐétfffŽ7Ž„‚€Ô„‹%***,,,##£9À˜€„ðfAì¬{<žŸþYY=¸îwlÚ´©ÿþ¸"¤§õÛ†Sr999n·[ñ¸ã#?==½C‡!!!$Ä&^ØH‡ šç;!€(@ù±~89wc£þ0Ùl¶­[· ÅŒZÇeddLŸ>}çÎ~~~$=­¯V¥R]½zõ›o¾!$©Q«ÕÙÙÙ+V¬ t²¼º1ýÑx£¢ ÅKüºs뜢3€ :¼ÑORÅó|PPÐâÅ‹GhEQÔëõsæÌir­ €p®¸.×A›Xã³°[·nï½÷žÃáP¼tpó^zé%ìË´r‰h3ƒn»èÔ¢·³ÞDFÝzo£‘_¬°¾;£ U8kÖd¥ˆŒV¥ÅY\Má’\·ÈÐâmùÚµk$¦ºôJdÀ;hî& ®X8tõЇ'?4VÞªâT·#ü_\Ñ©ØiÒyÁö«rW­º¸*¯*¯†¯ÑКs̤ÈI <ÒM umSlÂ:VU²±à6±Ä@Æ!:fdÎ3„ ë8ìÓÜO•á\¼+2’µ*ížk{^Ïxª!ðà{øýÆs¿»ÿ»p}8 à¶ÉíhŸŒd£Ú¸4o陲3ïÜõN˜> È¿AÇ@+½ÙyHy$OS—Oïý4}lznrîw¿Áh˜«–«™e™,ͶnóšÛ _Œd=£ß_¶ÿý“ïOï;}\×qÉ )ÚŸóWQªV& Göt1v™=5! !Ê®%@Ð^߾ŨµV’F6R|°Õñ5‘EQ©ù© ÃÄÄ}wî»3µg¬¼uû¯Û{ô â‚D$¶â`ÉH>o9?5}j±½ØÉ;)H½>àõá!ÃBËpÀ¾NF£æhÄ„˜D”¢¨:¢Nò1ºæº&:Äg~|F–dÀ %Ö’Gw>ºfÔšäÎɵ|mëb)Š1ªFµQI’NV¬tWšÕæÖ[ ž-B˜&åFª@> ¼¼Üét²,DØ¡$KE>”˜ a4,Í­<š]–¤ßc|”)Ê#y¨Ö{. ä¿ñ-(»<{ʾ)Û ¶w3u{¥÷+ÞÒºsK–åÊÊJ—ËÅ0Lpp°F£¹š»N¦M›öÓO? ‚ЧOŸï¿ÿžQËÉžéñ )I–ü8¿7޼‘}:;ÈôNÿwx‰÷È­ 2F•»ËýÔ~,Ū)uWsWƒÚ`Q[ŠlE­»þ0íå—_^µjæ0`Àûï¿ß¥K—ÁŠFj*úõëÿᇒóiÔ †PÊ@FnÔ=°ûÃýŽ2Eáú‡V)„†Ñ¼‘ûÆÑŠ£I¡IÂW”Ö–wܺ×ÌÙ½{÷÷ß?**jÕªU»víÚ´iÓ›o¾év»ëò&Ä.Ì›o¾YPP°lÙ2à½÷N°_@Ê#y’B“&všÈK|-_ÛŠcô[—Š2FíøuÇçùŸCtôëøxôãÉ’¢£wQèOII9räHQQþaÇŽoüd#éµk×jkkë¡·¤B‡à°òV![¹@Bè‘<ÏÇ=?©Ë¤jwµ *JÕAסƒ¶ƒM°µnÛ°Øl¶åË—oݺ˜˜˜œœ|cqKc%‡õXÊ|qJQRQªV·_ „:h;$&ô€‹{[»Q@Q”J¥zï½÷Ξ=;wîÜC‡-_¾üÆ·Knz©À8;š¦ë“®þUÅ#ypqFã·´8~€¡¨¨(222 22pìØ±Ñ MHÓtJJJff¦Ûí>uêTÏž=Ÿxâ‰Y³fy‹²mJ«_ᆪÚíö±cÇr§Óé.\¸=z´Z­nÀƒÚÈ*lß¾}\\\bb"B¨²²²ùÐP¼^ɹë`Ýòui-%­%øjàïï¿páÂÌÌL»Ý>dÈŒÆo¢² €zï½÷T*Þ<1T¤ÉÇAp¾I§Ói4³ÙL—V«ÕЭ8_(Š"fi4›ÍƒÁ`0435ÝFC¦Nš’’‚³§n·»Ñôg#c]UUU×Õú¯ÞB0\3//oÏž=äïÛ`\IYYÙîÝ»IR¾&“ WI?~Üd2õë××ެ(в,‹¢Hò¾qgeeÍ›7„Beee¹\.­V;mÚ´àà`eÀTRâ¦|ýõ×£FÂ$$ss;gffž?~àÀçÎS B¬I’***úõë7nÜ8×Z’¤ÀÀÀO>ùÄãñLž<™¤zwv̘1:î³Ï>»páBxx¸²9ábç¼¼¼òòò^xÁf³±,K¢/Á­[·Ž;6''ßMIãìb®ðððøøøªª*´²²2**ªG„ª<ÏwìØ‘¤ê‘t2 ³aÆ'Ÿ|’¼Âû´¹¹¹µµµIII˜Û™°yuš!„.—Ën·+~zO–e??¿;vøùù^»v ŒEEüp‰"ªÕêË—/3 óðÃ;Žº'µ” ^Ó_ýõèÑ£¿íÚ¨`ê[£Ñ¨×ë±³®@ ïß¿üøñ?ýôf§ó +aïH7RŽãl6Ûüùó­V+á”T©Tååå'))©ùÚšÃU‚¹÷?ÿüó‹/Úí éÕjõ¥K—ŒF#N£¶ˆ#© Y–ý÷¿ÿÓ(Ã[óß%Μ9sòäINgµZ›©MM©EYðVI\Aw÷Ýw?òÈ#ʰºM¾¸¸¸ÉJŒ'ư.tõiNÔ é‚ÐÐИ˜ÂÒ=lBQsss›CA±ûlæ³û.ï‘øÑÀÆEŒ»TB–å:tíÚµ²²RÁFŠsè555/^l²y4¤Õ´³¿KHr‰.rö÷[ˆLèñx\.!¶{ òÑ·‰þjÿ/Î~ñUÁW*µJð.¡ bAÜn·â— †iŽßtKî‹¶‹Þ"È‚–Ñv5u%d¿µ´!zõ拌d£+´¾žózÜq•žÊ«ÂUH5ýí$ílÎ_aÜúË9/ÿ÷ì)‘’‘Ìh™þ=–ô_BÂþ~ki[I–f Í9‡çȲüî€wÈ´Ô5P/ñÆMï3}|·ñjJWš·øÄb ù*çÚVRçÍ Iþ¬ÿŠÓ+öžßûá=v÷ëníØi øy„Ðǃ>öcý´*-Bhüžñ;NïpxÉCCZÞGˆÿÉL(#YÃh~®ùùÕ#¯Žé6æÙØg/X/àUÈÑGs`iÝ"€XšÍ¸šqâÚ‰«®«Ê@-LŽJÖ«ô ˆ›#2zu–ÖæWå !¿*¿Ç–ÉSã©x>ëùW¼ÓÿÖ}¥!„Ùß?Éú„Ñ0¢J1ìÁζˆR¶N”ЫS¥×ëëèÕG[ t®/’tŒŽÕ³Už*Á%°Ënq[*\­^È!t Î)1Sî½»Ä^òqÁÇû‹öO‡Ó¿ú%„-~ªB«Õj4Œ`r¹\M§|1Ã7ß|“““c³Ù:wî:†´ŠRUº+'íTc­Yœ¸xr—É­^HJ¯Ò'&ô ì¥Ñhx™Ÿ—9/«<«ÈZ„©§›?’ÂŒŒŒ={ö\¾|Ùd25jèС7Úâ|¤z½þðáÃÏ>ûlxx¸ Û¶mÛ¶mÛ·ß~DȱâE‘‘¬Sé¢Ùh„ŠRéT:­J[CׄèBÚkÛ_s_k­†á÷¤ÎÔœÙyiç vƒ‚5Á•îÊo/} ÐÓzü’MóUÑ4ív»çÎ[TTöË/¿|ùå—«W¯~ðÁ¤<ÿ@¯.Bhhè®]»AHNN>|øp^^Þ¨Q£ÚÔv*#Ù-º¼ÄkíÞQ{ñM±ÆSÓŠøA éZOmê‘Ô%p d ”!Pƒ”)†ˆæ»3x¨Bo¾ùf÷îÝÛ·o¿téÒùóçüò<UØl6†a"##Ûά“º± À@E$¶.º‰‚”[r÷ðï±üžå99•îJ2áúð¤ŽIÛ lé½§ìv»9Žs:€˜˜˜&èÕ1ª“䧤¤¤¦¦FGG“P;ÜÁTö­îÈ€ëìïF=úÏèþöP’y‰wJNeî¨ËåÒëõï¼óλï¾;jÔ¨G}ôF[4|ä£Nüñ‹/nÛ¶mܸq•••mm 6¶`¼:‘‘lá-à:* §)xXø8Ìž={åÊ•ÿþ÷¿—,Yâñxn¤‘£êÿ ˲çÏŸONN>uêÔÈ‘#/_¾¼`Á‚³gϪÕê?³Õ…†4 i†bŠ¡!­ÌCƱÜY³f­\¹2666""âí·ßÞ¾};‘Ô—?Ы«Õê‹/^¼x‘¢¨-[¶lÙ²!äçç׫W/eþ¿E™Ôò?8sæÌÌ™3eY1bÄ}÷Ý×®ø» )Šr:ýû÷ÏÍÍÅ@B\âm6›[…!ß[Xú:d¾w\z@¨¤®w¸…u?ÇHŽã¾úê+œÅöÀ)Õ[jc깈ˆˆú?E±9ø*¶ŽÄ\ϪT*FCHì ®£.4 vê¼"B“É„™™Iô`êp†at:ݧ„°C‡õ Ö(EÃfä­?²ÍL°á8bCb©V«ÅLû555EEEsçÎ%7!ÆLäääüë_ÿò¤JÅ9sæTWW¾Ã‚¯âââýû÷kµÚØØØU/§nÿ¸™-§Woôß7kþÌéÓ§IÊñpþüùÒÒÒ¢¢¢M›6õéÓçùçŸ'çñÅ5%µµµýúõ#'vÆGôóóÛ¹s§W†„„¬Y³æÜ¹s}ûöu8 _7¤7[/òFã'Ÿ|’••…[@ˆ  ^µjUFFÆš5khšÖëõääÉ[¶l‰‰‰éܹ3a•$ŽAæææêõúnݺ1 CØ<€$I˜‘O1=7iÃ0‹eÓ¦M .œ0aaÑ žt<Ï¿úê«[L²SA«««³²²ž{î9¯(T*ÕÆ'L˜àr¹0 9—<¸îÎ(› ^äïß¿¿k×®N§Ójµ’ãP-~eyI˜^ý¿ÿýoDDDxx8®šS¦W¿r—ŸŸo±Xž}öÙ>ø Ü²ˆL¨R©***Š‹‹ï½÷^žçU*U}ªe‚ýi†aðã<$‡+MÓ.—ëÔ©S/¼ð&kW¬ —Gµk×nóæÍË–-k×®]Û‰™¯˜~ýúUUUy«K4M[­Öììl;¢‡r:W®\),,$<¤9Ž»páB=FÕü=YB¿A 0¬Ô+ãÓ@HéÕ Ã}÷Ý———çņajjjöíÛGrKÁ›üž={~øáÂâ^Çq………#GŽl×®]EEE3¹¬j#Gs+oU†½hR¼à‘6yq¬ã/¯“[D~1 ¸S§No½õI’×Ú»Ýî)S¦ÄÄÄ#•9Ž;vìØŽ;š;2HÖ0šK~,¨)  5²ãÈC„/¬èzõ[ý 2•¦þ«š¼Ì»%÷Í:ƒòËËËIÎQív{UU&$4¡^¯¿víZ3w ðɯÎOÙ›buY"GGv5wuKn¯'¥½ƒæ¾iÏb Sí©^ÿóúÜÊÜ*O•†ÖD™¢¦DMéÐË-Þte`öqÂÀ&fòd® ¡ ›ï©áô=/ósÏq#·Ád°¹l¾s_}›È•‘Ì1ÜéÚÓ‹,N+MË«ÊË(ÎX“¿fìcóªò4Œ¦-¬{]$$™Ô¦ >>\zxNŸ9ZDï³ÙÕ‰oMˆßélè¼.i]Ö¸¬Ÿ“þxØÇÆî°g]Éb(¦-௽+’Œ*ã‘Ê#oå¼õPÌCF>hì I’Ú¢;skÁÇ^ˆ.¤‹±‹[r *æ/3†ýõÒÈøà° Ö™™3#Ì+¯¬ákð¯Ì¬Ù¨2ڻ׿´qzõút5äß!#¹ÄQ’œ–|ºö4”!‚赯 cìm°Î‹"#ÙÌš¿*úêxÙñ©qS(ùá¼õ¼Œd@ƒ]Å»8š‹õ‹miYE9nf‹F¼0;Ni¹B*¨êbê(s–Õ¸k\90>b|G}G^jCØFrAQªñÔ l>µy}îz@ ”Šúôð§«/n¼o£[p7ß‚BµZ]!ÇÓh¬£aÊ—a·Û]\\ìñxŒFcÇŽqÊJq¯ € ŘXÓº!ëÕÓ&<ðsÓçïÜõŽGò´)ð¡Pr‰®^½žîû´–Ñ2©åkן[ïœãâÇMì4"Í„Е+Wª««aaafOÿ€ææ8îôéÓ=öØÅ‹:î©§žš={6 + °ÄQbTÍj3C1Áš`-£*Pì,þë…¤\’+> ¾_p?É,Íž·œßðóàÓºL1ªÂUÑ̳C’$ÿ%K–,X°§kvíÚu×]wݘ¡üÃ*ÄOJÆÅÅÍ›7¯¶¶vÑ¢E©©©Ã† 4h²LŒd½JÿaÞ‡ß{oè½ Å.?|±ú"@?›ö×óH!€‚,àqœ¢“¦èçúš ÇŸ###/^¼}ûö#GŽÜŒ"àð'—Ë•°víZš¦ Þ={~üñG—å%$ÅÆí,Ù¹åÜ §êØeZÔ´G"i]þrß ¿ó û³þ ú, !]Ë×¶(ºFQ”Ýn3fŒÁ`8pàÀ->ÙHqšÍfóóó[³fÍ?þ8dÈ~ýú)ŽNáw­‹~lløØZ¾VÒA\P°&¸ð—ûZ$$U¸*@ Å´ôÔǶp¹\8F_ÿ¦P_º3E™Íæ+VÌž={ذaÿùÏÔj5¡_*È‚Ymä1¶€—ùVáç¶ öæÿ9MÓ,ËâÁ¿1lÚ „Ђ RSSÇ¿téR€Ãá DsC$ð"_÷-ÿŸØ\ðÓîØr7ƒÔþnUœ`ËÌÌÄ–ûé§ŸzöìÙ¹sçÝ»wët:§\Ï.áÿÿ•n¾üÔõ† bbbÒÓÓÉÉÉcÆŒ¹1µ×°¾°C‡)))²,c:^Q;vìHèÑü%¯r=’$5 Ç…ò¡¡¡C† 1™LØ»ÁD…7-NÕiÑÑÑü1¨‡`´Z­„,•=Á¬ˆäªDQÔjµƒ¡ñ;£Fš4i&° iZE|ͯ/ ÏBœk­ßÖ&éÕ±§„™Âë³e(Š¢ÈA> Á®®®Þ¼yóo·´TdY6™LÇŽëß¿ÿ€|»Ýn±X꣹o¼6ò~aKYæpцÁ`ÀlŸ^!¶Ù p ëèÑ£¢(ò}Úápv o •••jµºíýê:‹ÿñõ×_§¤¤$%%1Ûxüøñòòòž={* ‘šÇä>ø`›âØÀ‚ïÍÛ¶m›8q"Îê.A£ÑxìØ1ôÐCu·x(!EqÆ ÙÙÙµµµ‰‰‰3f̸ €®B< ©©©GމÍÊÊúöÛo+++gΜ© „ó2{öìyýõ×ãããm6Û¾}ûöíÛ·sçN???d žØ·oßÑ£G;uê”™™ùÝwßUWWÏž=[Aü¥ŽåaÍš5<Ï_ºtI¥RÝžÔ‡çß_yå•“'OþôÓOŸ|ò ;;Ûår)è~ƒ°[·n‡JOO?tèPBBÂ/¿üröìY–e,kLø9oÞ¼cÇŽíÚµkúô進²2e7w¼õz}vvöÊ•+„qðæ‹W!÷éÓ#‰+**ñññFÁ*Ä"""±Ó鬨¨ˆŒŒT|â•ýÒK/}ñÅ€¨¨¨§žzŠ$ØDQ˲˜oÒ»Aœ[ˆoÝ„Ëå2}ôÑìÙ³‡:}úô|Íü¤²Á`(..ž:ujYYÙÚµkCBB“«á•=|øðààà´´´ÂÂÂsçÎEGG“ô—çyl<P½  n¤xªÕêùóç¿üòËO=õÔ÷ßß¾}{ÅyœÎÍÍ=ztUUÕÁƒ§NJâ‘ʲ¬R©&L˜°hÑ¢¥K—Úl¶+VT`Ô`0ÔjµŸŸßm 5§gΜé;í,˾þúëË—/ 4hPZZÚÙ³gccc;'Nœxøá‡¯^½:räH—˵}ûövíÚµoß¾¥î öe¬Vë³Ï>{âĉüüü+VßyçãÇW–=À[ýöíÛ÷îÝ{ìØ1µZít:U*UHHˆOq\¾õHA(,,TVV.Z´H–å>}ú$''3 ÓR¨ôââ⪪*­Vû¿ÿýï믿ÄÆÆÆÇÇ+p‘ð[Òn·{Ù²e<Ïëõú±cÇΛ7OYgñG„ùóç—””pwîܹY³f-Z´hÀ€>}èÇ÷B,N§³Ž €y¨¶BAìv;Åâ$¥V«U¼Ya%6›M•Jåçç‡"yc !d·Ûñˆ•h4Bòç¦{ák6ƒæoD*“3Õ×1ò ‚@ΘހfÊ+DúM|£Oµn4!j×ëxE–:Îy¯¼(Ý€Áþ6\ }nB¯÷¡+¼ýØ×¿“MzùTµâ¼iÀ%tEXtdate:create2017-06-06T01:31:15+01:00\uŸž%tEXtdate:modify2017-06-06T01:31:15+01:00-('"IEND®B`‚puzzles-20170606.272beef/icons/towers-ibase4.png0000644000175000017500000000117413115373746020212 0ustar simonsimon‰PNG  IHDRffËñùQgAMA† 1è–_PLTEÿÿÿ€€€ÀÀÀ€+¹¬bKGDˆH oFFs—Œ7³tIMEá"£Ý‡ vpAg,,û8rilIDATXÃí×Qnƒ0 `B.@(æp„ï¦%졬ø0šÔ­Â©¾:¶Au«êŽ;îxOO$DÔS“l¦tÞ#ÓãQ­<¯óðrÐXò@ãq=%ÓhÍèôyr»Õ=H£Sš¶Ðk“Fç„Ϩw° ùÙ¡‡`JÏ0)KËù”È/•ãÁy‰%µ!º§ž.˜ú7ÜÍÇ…<·y£™™ƒÒXÖsÁÌzcyQíÚÌ;æË«=šÜKæà 4 03ѬùvA6é’i·¹!óͱoöyª1ê<én 1Æ1"Í {ýr‰ý3õ,ç¬évã9iö>ùnÛnWÍI3ÿHsʤë.ι 4û©ý)ó·ùF¹¿m-®`ù3;@C0œ®‰õj™ŒÁ`àþV+×Q“ÊôÊ‘N©Ì^iòÔÙ¦ÖèL.§ ʵ7î Îëê£uéW#ž0_JîS¥%ÓMk%tEXtdate:create2017-06-06T01:31:34+01:00¸'“W%tEXtdate:modify2017-06-06T01:31:34+01:00Éz+ëIEND®B`‚puzzles-20170606.272beef/icons/towers-ibase.png0000644000175000017500000000271713115373746020132 0ustar simonsimon‰PNG  IHDRffPgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ< PLTEæææ”””YYY)))555ÙÙÙlll;;;<<<ŠŠŠâââ ÆÆÆDDDååå!!!###SSS+++EEE___jjjPPP °°°ÞÞÞVVVäää   áááTTTººº“““aaatttÇÇÇ………bbbFFF½½½RRRÔÔÔ«««hhh''':::ccc–––WWW¤¤¤ZZZ((( """§§§ÐÐÐfffgggÏÏϬϬŠŠÍÜÍÛáÛ–]¯]¨Í¨ŒÙáÙ”|»|X­XW­WÂØÂ£Ë£ØàØÐÝÐŽÃŽ//‘Œ–K¨KœÈœåæå×àדÜâÜ:¡:ØáØS«S_°_A¤AžÉž — <¢<ƒ¿ƒªÎª Ê [®[‹¸Ô¸—°Ð°F¦FÁ×Áwºw„¿„ÊÛÊŸÊŸo¶o’àäàÈÀˆs¸sz»z¯Ð¯¡Ê¡—Ç—’Ä’Œv¹vyºyâäâZ®ZÃB¤B ¤Ì¤ÏÝÏ-œ-“•`±`}¼}§Í§Y­Y¼¼¼111ÚÚÚ888©©©yyyßßßsssÓÓÓ¼Õ¼{»{H§H%™%’ Ž •ÿÿÿ F/bKGD®¹k“§ oFFs—Œ7³tIMEá"£Ý‡ vpAg,,û8ri•IDAThÞíØù[ Qð‰ÞˆT’¥P¶PÊ%a$ЏQîÛUT–èÚ¯}-K‰Ê¾†²gßù3s‡žGê¼Ó}‡‡óýáÎóÜç;ó¹gæÌ¹Ïs CGGGGGçŸNÌ¡±qªõaÃãGŒL•˜”LcFƒŒ2“‘ŒI%1cÇŸ@aÒÒ'Nšœ!œL3Å0¦˜iÖ ¦ &†v×hŒÌŒ”,ÁÌäefÙÏf6UqÃdçÐf™“›7×0/™—‘™ŸÄÏ 8™…‹äçbñx²HFži.(4Í¥zbÂÒ"3],O°ŒÄÄ9«Çr5ƩӦ‘)Y±2-¶tUÁj¢óWÅŸ ´ø\1e@<Ú·³†Ÿ·`m¹'£ oòi^1n¦%óhàÇQ3šù˜u©df‚ëÑ ¦ ½`ª7ð3kkù™:ÄM›Ù™-ˆ5[™úmuÛB;vîÚ½‡Èì݇jC ÐÉþ4æ â!C‘ âÏ&1G†Õ™À±ã'Nžj”í& sϪLøì9ëØ,Û-¦{§ªÆI¥ìÖ²3çe·•¹ ªÛ(L{‡•K¹ÜqE‰¹åk¿~?ðÿ e¸~Ct›ß—£ÂÜ”Õ[}]$ŠÌí;¢ºÛçE¢÷'ìʽûý—Í<èJwÓåÁ2á‡òÞ>zlå Sßû{ª%F±¬ÍhÆóÌGÜOËwÅ\ÜpuPB0ƒ€”Ì „`%3(!˜A À JfPB0ƒ€”Ì „`%3(!˜A À JfPB0ƒ€”Ì „`%3îDDeeå•+WÚÛÛ ƒÑh‰D2™,;;;..ò „ÊËË5MSSS{{»ÙlFEFF~ýõ×X >|X«ÕÞ½{·¿¿ßl6{{{-[¶,==ÇsÚ÷*lj¯;úÙgŸíÞ½û©Oåååååå¹x„Ptttgg§ýÆvvvFGG?õ©„„„S§Nq8š#ÑÃi?]l¼½½cccÅbñ­[·jkkÉÁ¢¢"¹\àây8N@@€L&kkkkii¡yíO‰D‰ÄÝÝ]¯×«T*£ÑˆªªªjhhX°`î€áÌ%‹Å………)))|>Ÿ)..Þ·oBÈb±h4šßôL˃ª®®vssCmÚ´ { ¥RéÍ›7í§;•J•M.ß»wÏYKèÌ;färyzzºíZºt©mÙjµºx„Ù@†àr¹¶šL¦ÎÎÎŠŠ Û³AAA˜r9œ3Ï„Oêèè°-GEEaLBbZ&(++Û¸qã„ÁœœœÐÐP,yhàB%Ôëõ;vì ——/_>gÎÈÃ|\.W¡PlÞ¼wr•¶´´deeõöö"„bcc÷ïßy˜iþüùEEEF£Q§Ó?~ppðÀÍÍÍÇwÖ_)œó¿j‚ªªªõë׌Œ „’““:dÿÅ ò0Š¿¿¿¿¿?¹¼råÊ„„«ÕªR©Î;—™™‰7›ƒ8óŽRIIINNùŽß°aƒR©ÄûŽgZ& ‰Där}}=Þ0ŽãÌ3¡Ùl.((())Añx¼={öddd@ƺxñbTT”­u!FÓ××G.s¹N;a¸Ê3~~~!!!öÏ&&&fee¹r„Piiiww7BH­Vß¾}!4kÖ,¹\ŽòððP(t†Y±bÅwß}Âçóu:]MM y0BH©T’Áœ3Ï„äÁ$ƒÁ`0ìŸ tñ<¡ .444Øôöö9r!äëëKs B&“©®®®®®nÂxZZZrr2ÍahãÌ%ì’››+•JoܸAÄÀÀ€@ ‹Å2™,55×îôpæÍQXÁi¿ìÀPB0ƒ€ì˜q6A„‡‡[,ÜA~! ÛÚÚp§`.(¡³Q*•‹…QûÛ$ £N… ˆ¯¾ú w ð|`&|q}}}aaaŒÚð999GÅ<(á‹;yò$7ürss¡„웣/hllììÙ³¸S<…ŸŸîàùÀLø‚ÊËËCCC'ÿ &Ä}3ŒÝI %|AÇ/((¨®®Æ„˜°Ñ΄‚§‚ÍÑQ[[k±XbbbpÎJø"Ž;¶nÝ:g½ 4 ”ð¹étº––g=ÁÐJøÜŽ9²zõêiӦᜠvÌÌ™3gppwŠ_¹yó&îÀy° „ƒƒƒLØ·f#‘H|||p§Î6GÀŒ3!À¢ÎP—z)ÕŠ~¹MMã{âbŒ‘œÌ„à)FL#Šk ûÇ‚§ØucW×pî®6G1hý©U­W7>hÔ êúîàsù¢i¢`¯àøWâÓþ˜æÎwÇïò?/Ÿé8ƒpc–1ŒI\”e«²ün¹ýȸe¼g¼§g¤§F_sè‡N½u*Ì' K¶!ÓâÚãkþ~öáÇÚ±Äp)°9Ê8Ä#bÍå5&‹ ËÚ ¾/Ðõ¡´€´%³—`Éàj`&Ä€ÏåGûElj㤞R_7ßQó¨ööó[Ÿš“Ð3Òs¸¾xÖbšƒU÷TŸÓCIfHvFì$F š „ˆGD¾æ:qýÖÃ[]Ã]C¦!‡ç;Ý÷MÑ›ÿöÚ¿%J9ÈÙÙ…bppáA.çWÛ ñ’ø¹¢¹Ù϶ôýÜGsª±ê?@q§pQ¡P ¤¿„Æqã¼²yöÊŽ£ñîáîîáîoº¾‰ö‹.y«DÈÒÌ¡`sƒ $y ¼ìÎvŸMWœÇ¶7l7<2 „V­ŠÇÒ¼v’Õjúw‘:CÝú+ëiËC˜ ±1[Íã–q‹Õòpì¡ööí'¶§Â|Âd/Ëè óm÷·ewËB¯y¾–žO窟ÄAœÅ³¿3û`¯`ã¸ñÒ½Kÿ§û?‹õñµÔzusó›¢7ñ†¤”›/t_›,ò[¤ŒQÒüÍgç!.‡[¼¨xo«¶Çáp–¼ºä¿æý×^oØ—¼ºäUW÷6íµ|ÿ{(!p”˜Y1»çïö›N÷ÅšÇB«E®šô<Ɉò„PÖY{£öNöšßioÆÉ·N>9¾â+ìK8:>ê XÀwBf¹Ú{5ᛄ·OàÂ,f«Ùþa€W®$Ž%Ä�CŸ©ïÊèÒ¦hKß*µý:o¶šóòµ´xã1Êÿtümùe·—ÿUò¯ÃP6G1ãqy~ÓýÞyõÅ~‹#ÿ906@ŽŸí8;ïåy´Å(/5OÜÆ»?zÿ`óAÛÃmó¶ ùÂà?Ó–ŠtéÞ¥ÿnýoÛÃÝ‘»\ÍŠÊ >|X«ÕÞ½{·¿¿ßl6{{{-[¶,==ǃÂOŃïèØx¿‘|Ø9ÜIçÚW¬xrðÎàû¦¼žBÿ©Lç<ŸWŸ7n'þ‡ì?’ýiºy=A•••W®\ioo7 F£Q$Éd²ììljoßMe1úúú>ýôSû‚ ‚¸zõªJ¥:uê\ž !ôãÐî<÷'w½t wµþÔj{èö’½¹˜¨øfñ¾öÙn•mݺ‘¶µ—••íÞ½Û~Ä`0TVVVVVæåååååQµ"Šg'‘H!‘HÜÝÝõz½J¥2¡ªªª††† P»:6ª7Ôo½¾5fVLœ8.È+È“ïùpìasóéöÓÆÙ^¶pæBŒ!±·Œÿçõÿüß;ÿK>äqy{£öþ%à/ô'ñööދŷnݪ­­%‹ŠŠäry@5û‡¨,¡T*½yó¦ýt§R©²³³Éå{÷îA I&‹I­W«õêÉ^ ž!^¼šÎHO( Ôgb¸ºÏˆidÝ•u5úò¡;ßýèÿ;/‰§9†X,.,,LIIáóùäHqqñ¾}ûB‹E£ÑPUB*÷Žr¹\[M&SgggEE…íÙ   ×åĿп–ý©ÌÉ|v†G†÷.½gk ïtß²?•Ñß@„\.OOO·5!´téRÛ²ÕJÙe¨ßYRVV¶qãÄ ÷œœœÐÐPÊ×ÅFïú¿ë%ðÒ4MšîÞïí3[Íî<÷Ù³C½C¥‰o¿ò¶ó(ðŒŒãÆw¿}÷ÞÈ=ÛH’4IÓ«Ñôjì_ö/Þÿ'¦r×È3êèè°-GEEQõg¾Ç’Ëå*ŠÍ›7;zEláÉ÷L’&%I“pa¢aÓ°}B'oŸ|òe ø ý%Ôëõ;vì ——/_>gΪþ2õ%œ?~QQ‘ÑhÔétçÏŸé}]çAÄŠ™P 0ùc »;wþõ¯6mî Åði±b&´X,ëׯÇâ7àÝh»×aß;Êáp˜ùã J8>>>sæLÜ)~Æ}€‰ÄÇÇ×Úö½£‰„áïlŽàÜX0:H¡.õRªýr[Æ÷é¿ &.:Ž˜F×ö -á®»º†»p§!×ܽüÏËg:Î „\Á˜e wüZjUëÕuƒºþŸûÆø\¾hš(Ø+8þ•ø´?¦¹óÝqgtf.WÂ!Óâš‚\þ0ìõãÍÃÊVeùÝrû‘qËxÏxOÏHO¾æÐ?zëT˜O®xNÏå6G ¾/Ðõ¡´€´%³—àŽÃÄ#bÍå5&‹ w§åZ3auOõ9Ý9„d†dgÄNb”Àˆø\~´_tœ8Nê)õuó5jh?¿õù i|AÏHÏuâúâY‹ñætV.T±ê?@q§pQ¡P „’.<Èåüj›(^?W47ûïÙ¶‘¾ŸûèŽå2\hst{ÃvÃ#BhUЪXq,î8 2¡$/—ýÃÙî³éŠãr\e&ü¶ûÛ²»e¡×<_ËÏLJ‰ÌVó¸eÜbµ<{¨} ýDû‰í©0Ÿ0ÙË2ŒÙœ›«”pç!.‡[¼¨xoî8Lô…î rs}‚E~‹”1J‚“ÅUJ886ˆ²X-rÕ¤çÝE”G „²ÞÈÚµ—¾dÌ3+f÷üÝ~Ó™{p¡ï„à\í½šðM‰Û'pqfPBðXF`†>SߕѥMÑ–¾UjûuÞl5ç7äk0ú”³ÕìÎsŸí1;Ô;4Qšøö+o»òá2eee7nœ0˜““JÕ* „®Î“ï™$MJ’&áÂ\.W¡PlÞ¼™Â¿ %`*óçÏ/**2:îüù󃃃hnn>~ü8U¿R@ ˜Š¿¿¿¿¿?¹¼råÊ„„«ÕªR©Î;—™™IÉ*à°5žUHHˆH$"—)¼+”€§»xñb¿ýˆF£éë{|….—²îP¼9ZZZÚÝÝúá‡È‘îîî]»v!„<<< µ«ÀqJKKsss###CBBø|¾N§«©©±=OÕŠ(.á… ìGz{{9‚òõõ…v1™LuuuuuuÆÓÒÒ’““©Z ì˜àérss¥Ré7‚b±X&“¥¦¦ÆÅÅQ¸"ŠKÈ„& D||<…ÛœS€3`%3(!˜±oÇLkk«P(Ä~'ô ðæ±_»D" …mmmó€ç¾nÙ²%55u÷îݸƒ<–””¤Õj±ß™ÝÓ>¡ÀÔXVÂÖÖÖ¶¶¶’’ÜA#óàNØÃ¨ð§’H$¶IIIááጚÃÃÃOœ8Á¨F˜ 'ÃÌ u6̜̈́KJJNœ`ܵq™ð¡ššªÑh˜Ä†™OlÚ;ºeË–ŒŒ ??¦\’iyexxX«…ë?Ö”œv6lØ€;ÈcLËÃ4ùùù2ÜÈé™°¦„L›v˜–‡i.]ºôþûïãNÁìøNÈØoƒ¸ƒ0ÔáÇ===cbbpavÌ„L›v˜–‡iNŸ>½iÓ&ª.PíôØ12jÚipjjµzhhH.Ÿô>`Ì„€QÓŽB¡`T¦Ù¹sçÚµk§M›†;k°ãÇzÜ&jjjš9s¦í¡ýáL€ý_ìæÍ›>>>ˆ‘ÿ2ŒÊCbÇæ(£þá$‰}™ 㿘D"!ž 6Gpnì˜ ]A¡.õRªYm#ï5ÂMK]Ì„Œ0bQ\SØ7¸(!#캱«k¸ w €lŽâwùŸ—ÏtœA ¸‚1Ëî8øµþÔªÖ«4êuý?÷Œ ð¹|Ñ4Q°Wpü+ñiLsç»ãÎH%(!fC¦!ŵÇ×Dþ0ìõãÍÃÊVeùÝrû‘qËxÏxOÏHO¾æÐ?zëT˜O®x”ƒÍQÌ ¾/Ðõ¡´€´%³—àŽÃÄ#bÍå5&‹ wÊÀLˆSuOõ9Ý9„d†dgÄNb”Àˆø\~´_tœ8Nê)õuó5jh?¿õù i|AÏHÏuâúâY‹ñæ¤ ”›±ê?@q§pQ¡P „’.<Èåüj-^?W47ûïÙ¶‘¾ŸûèŽå0°9ŠÍö†í†G„Ъ U±âXÜqdBI^/û‡³ÝgÓÇá`&ÄãÛîoËî–!„^ó|-?<w&2[Íã–q‹Õòpì¡ööí'¶§Â|Âd/;ÏiûPB{ØÜß|ºýô£ñG¶—-œ¹ž<4¼Ÿ©,¡X,.,,LIIáóùäHqqñ¾}ûB‹E£Ñ@ §( Ôg2èj:¸˜,&µ^­Ö«'{x†xuðjGÇ íýLåÞQ¹\žžžnKŒZºt©mÙj…ÓÆæŠæ–ý©LÈ:zE´½Ÿ»w´££Ã¶åÐuçð®ÿ»^/AÓô éþèý¾Ñ>³ÕìÎsŸí1;Ô;4Qšøö+oã:\ÆAïg–P¯×ïØ±ƒ\^¾|ùœ9s·.à4<ùžIÒ¤$iî 9îýì¨ë[ZZ–.]ÚÓÓƒŠÝ¿¿ƒV ú~vH «ªªäryoo/B(99ùÌ™3pQtÀ^Ž~?S_Â’’’œœœ‘‘„І ”J¥ýW[Ø…†÷3•ß ÍfsAAy»"·gÏžŒŒ ÿ>t¢íýLe ;f»a˜OEEEEE…íÙÄÄĬ¬, W€CÑö~¦²„F£Ñ¶l0 ƒý³® G£íý §2€;îOȨOæa~B\k‡™g3!˜A À Jfpy‹ß«µµU(b¿M¼=‡A—$"<<Üb±àò˜D" …mmm¸ƒüJø{mÙ²%55uÂ)Ø}ôÑGŒ*¡R©´X,ŒÚ¨OL%üZ[[ÛÚÚl?ébGÄ—_~©VOz:,ý¾úê+ܘŽM%ìëë c†í£ô¥—^ÊÎÎöócʵh•JeZZCòܹsÇÃÃ#99ùäÉ“¸³0›JxòäInØlذwŠÇ˜6 æååY­Ö÷ßJ85Öì;{ö,îOÁi1lniiY¹r%Cò0kfÂòòòÐÐÐ Çï¦Mƒ[¶lA­_¿w`ÍLxüøñµk×âNÁ\ŒšBjµ¦ÁgÄŽ™°¶¶Öb±ÄÄÄàÂPL›÷ìÙc2™þýßÿwv`ÇLxìØ±uëÖ1êç/FaÚ4xæÌ™ÌÌLæäa8vÌ„---Ìù-Ži˜6 "„FGGa|v,˜ ÝÜÜV¯^ —ŠšLqq1£¦A@ߟ fÂñññU«VáN1)†uôèQÜ~ÁœßNY%ôññÁbRØ`Ú‰ª‰dæÌ™¸S° 6Gpn,˜ @ÕêR/¥ZÑ/·ai|¯Ñ9n¢ 3!`ÓˆâšÂ¾ÎJX`×]]Ã]¸S8ŠKl޶þÔªÖ«4êuý?÷Œ ð¹|Ñ4Q°Wpü+ñiLsç»ãÎ&uùŸ—ÏtœA ¸‚1Ëî8Ôs‰*[•åwËíGÆ-ã=ã==#=5úšCÿ8tê­Sa>a¸â) ™†×äò‡a~¬ýoG€ÍQD<"Ö\^c²˜pOQð}Þ¨G¥¤-™½w‡p‰™ÏåGûElj㤞R_7ßQó¨ööó[ŸšÉôŒô\'®/žµoN0AuOõ9Ý9„d†dgÄNb”ÀÈ!\¢„är~5çÇKâçŠæfÿ=Û6Ò÷sݱÀ”Æ>¨ÿ!ÄAœÂE…BÐYK蛣HòxÙ?œí>›®8à™loØnxd@­ Z+ŽÅÇ\b&$™­æq˸Åjy8öPû@û‰öÛSa>a²—e³ ¾íþ¶ìnBè5Ï×òÃóqÇq,*áº/ÈÍ› ù-RÆ(9NVd7v"„¸nñ¢â¼¸ã8– •ð©bfÅìž¿Ûo:œwÃ,ƒcƒ!‹Õ"WÉ'{MDyB(묽Q{éKæ.ñp W{¯&|“pâö ÜA€ër¡ffè3õ]]Úmé[¥¶_çÍVs~C¾öo<à²\ns”ÇåùM÷{çÕwû-Žü[äÀØ9~¶ãì¼—çáÍl  FÍ£ïÞ?Ø|ÐöpÛ¼mB¾0øÁôF£•%$¢²²òÊ•+íííƒÁh4ŠD"™L–GáŠ(áÁ÷ô l¼ßH>ìîÄüÊŠ€OÞ¼c_”×S}*Syy¹F£ijjjoo7›Í¡ÈÈȯ¿þšÚµPY²²² 7'2 ••••••yyyyyy®ëÙý8ô£;ÏýÉ]/]Ã]­?µÚº½äFo.ÀèììtôZ¨ßõööދŷnݪ­­%‹ŠŠäry@@å«ûMõ†ú­×·ÆÌЉÇyyò=Ž=lîo>Ý~úÑø#ÛËÎ\H6Àp' @&“µµµµ´´8h-T–P,¦¤¤ðù|r¤¸¸xß¾}!‹Å¢Ñh°”!d²˜ÔzµZ?éEÅ3Ä«ƒWÓ ¼€@a >“Ö«éTWW»¹¹!„6mÚä¸R¹wT.—§§§ÛˆZºt©mÙjeèiÑsEsËþT&ä qŒC6ÐÑ»w´££Ã¶åÐuMæ]ÿw½^ƒ¦éAÓýÑû}£}f«Ùç>Ûcv¨wh¢4ñíWÞ†ÃeF,¡^¯ß±c¹¼|ùò9sæ8n]Sðä{&I“’¤IXÖÀoœƒØ~GIDATrÔõ---K—.íééAÅÆÆîß¿ßA+€íRªª*¹\ÞÛÛ‹JNN>sæ \Ä€ÉP_Â’’’œœœ‘‘„І ”J¥ý®ÀT~'4›Íäí“x<Þž={222(üû8%*KxìØ1Û Ì|||******lÏ&&&feeQ¸:­´´´»»!ôÃ?#ÝÝÝ»víByxx( JÖBe F£mÙ`0L¸¿|`` …ë€.\hhh°éíí=räBÈ××—ªºÐ©L0•3!Æ£´pÊO˜x*˜ À JfPB0s¹Ë[šµ¶¶ …B‰D‚;È/8f¯%޵eË–ÔÔÔ —\Àè£>‚ÒÚÚÚÖÖf;„;‚ ¾üòKµzÒÓ»±`S ïܹ6ì²eË–ŒŒ ??¦\[Y©T¦¥¥1'‰M%ܺuëŸÿüçÂÂBÜA;xð A8ç}‚(Óà3bÍÞÑááa­V»~ýzÜA;{öìš5kpa.˜ŸkfÂüü|™LöÆoàòXyyyhh(sò0 LƒÏŽ53á¥K—Þÿ}Ü)~qüøñµk×âNÁ\0 >;vÌ„‡öôôŒ‰‰Áä±ÚÚZ‹Åœ}úµk×fΜ‰;ȤXPBœ 6GpnPB0ƒ€”Ì „`%3(!˜A À JfPB0ƒ€”Ì „`%3(!˜A ÀŒטy1ATVV^¹r¥½½Ý`0F‘H$“ɲ³³ãââ ÏÐÐÐáǵZíÝ»wûûûÍf³··wPPвeËÒÓÓy< ïòòrFÓÔÔÔÞÞN^¾ 22’žÛåbäÌgÖöÙg“Ý ˽™–§³³3::ú©O%$$œ:uŠþËÉEGGwvvÚ¸B y&$y{{ÇÆÆŠÅâ[·nÕÖÖ’ƒEEEr¹< ÀÅóˆD¢ˆˆ‰Dâîî®×ëU*•ÑhDUUU544,X°€æ<' @&“µµµµ´´Ð¼v\œ¹„b±¸°°0%%…Ïç“#ÅÅÅûöíCY,FCó›žiy¤RéÍ›7í§;•J•M.ß»wþVWW»¹¹!„6mÚä:%tæ3r¹<==ÝöŽG-]ºÔ¶Lÿʘ–‡ËåÚh2™:;;+**lÏÑœ!D6ÐÕ8óLø¤ŽŽÛrTTÆ$$&ä)++Û¸qã„ÁœœœÐÐP,y\ •P¯×ïØ±ƒ\^¾|ùœ9s Ï“¸\®B¡Ø¼y3î .ÄUJØÒÒ’••ÕÛÛ‹ŠÝ¿?ä!ÍŸ?¿¨¨Èh4êtºóçÏ8p ¹¹ùøñãX~¥pA.ñ¯\UUµ~ýú‘‘„Prrò¡C‡ì¿˜¹xryåÊ• V«U¥R;w.33W*—âÌ;fH%%%999ä;~Æ J¥o™–Ç^HHˆH$"—ëëëñ†qÎ<šÍæ‚‚òö@<oÏž=ÇæâÅ‹QQQ¶Ö!„4M__¹Ìå:ÿ4C¸Ê3~~~!!!öÏ&&&fee¹rž+V|÷Ýw‘‘‘!!!|>_§ÓÕÔÔØîu£T*é¿]iiiww7BH­Vß¾}!4kÖ,2†‡‡‡B¡ 9=œy&$þ  ƒÁ`ÿl`` ‹çA™L¦ºººººº ãiiiÉÉÉôç¹páBCCƒýHooï‘#GB¾¾¾PBàlrss¥Ré7‚b±X&“¥¦¦b9 Üe9óæ(¬_¾À JfPB0ƒ€”Ì „`%3(!˜A À JfPB0ƒ€”Ì „`%3(!˜A À JfPB0ƒ€”Ì „`öÿU^E§@YNKIEND®B`‚puzzles-20170606.272beef/icons/towers-48d8.png0000644000175000017500000000257013115373746017533 0ustar simonsimon‰PNG  IHDR00`Ü µgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<YPLTEæææãããèèèìììûûûôôôüüü¸¸¸pppuuuÒÒÒÛÛÛfff†††òòò‰‰‰,,,ÆÆÆUUUiiiLLL¶¶¶¼¼¼¦¦¦®®®’’’©©©ßßßBBB!!!”””ÔÔÔÃÃÃÊÊʱ±±ccc   |||èçèÎÎÎzzzäääãåãbbbëë뇇‡ççç^^^ÈÈÈîîîíéíñëñÞãÞÊÛÊÚáÚÏÏÏ.›.‚p·põìõc±c†j´jÿðÿ¦Í¦•Æ•i´iôëô·Ó·K¨K• Ê wºwÿñÿC¡C9¡9 Œ ½Õ½ÃZ®ZB¤Bˆ›È›ÂØÂúîúòëò)š)Œ½I¦IùîùL¦L¤Ë¤ÇÙÇ?£?²Ò²y*›*RRR™™™JJJÔßÔ­Ï­ÅÙÅÿÿÿUÑ»gbKGDr6 XtIMEá"£Ý‡IDATHÇÝUy_Ažƒ\!¹T VvBÒÕðÀ(0RóÈ£µÔÒB+¿ÿ?Íű«|Ÿ™¿yæyÞyg_xb€ ¯ààõØçó®Gš_CׂCº{…ÂÑÐ4ÈH4`¸àسÑè˜1ÀôÅ£ ìžÄ±àxpàd4axTScãicÀzhdÁµÒ³þ‰ÉÇb€ìüŒðTt*‡!ÿÍß°®¥Ç'Ÿ‡ñ#– ÃÀÚ‹@>Ò ‹©~°ál‘#H$âE…TÉ1ÊNGŠŽd2£*½ìílzg¦<¡û˜ ÞÄÃ&<0q5X´{m¨¦¿ŠU e±F)€TD ‡#„Ù^›%ålUIä_ÏÍ{N¢š%Tª¢ª–žÁt2‚¥ìÚÒ0‚¤mU¦)­W¤%F(,HZ|S ”Å®õœ°$÷€\ B•.¯¬Ö©`*ÊÐ!ÌTh×’ ÐúÚÛÆ;IÈ¡o×ß×mKÖ—*Ý œ@ë›[Í>Ú^û¸¶mw,a7Á¬µ>Õvv÷¨<%n©ùys¿qph+¬‚žZ?Zùr|Ò:µ¥‚˜=£_wwޏ(A),HêlœŸ·N¾}w¨ p™ÎEã̱ä±"·%†úáÎꥊAÌ"óª±Å×÷)Ð>ªýø©ò@¸3³v}p³gÌ÷,L™iSä:W¿Z¿·CÛeÉûUÉcµW¯÷—ÁmÉC0¥%à4›õKÛcId‹=r È’W@u5˜%(òÓ1 P¦aÛómÂîõ¶ ý–Üåî:ã]8(ꇬÆwò€ôàH®N§Ûlh¯¯ó± æý†þœ.Lü‡„b7ô`)åF&^î*ܦ|clã./R*zÉQŒ‘")o½µP˜?Xuä+»E6žÔ$ÁR_Ûe¨LH„DXéP=2ÜÝΈ—4ã8ªha1?Ý ëXvÒGH Kæß§7‹BÈ’¬ 3è#˜•á/ÞÞS%^<|Ê’cw~?¬ÁÿŸ>þæ†tÔÑ® %tEXtdate:create2017-06-06T01:31:34+01:00¸'“W%tEXtdate:modify2017-06-06T01:31:34+01:00Éz+ëIEND®B`‚puzzles-20170606.272beef/icons/towers-48d4.png0000644000175000017500000000105113115373746017520 0ustar simonsimon‰PNG  IHDR00¥,ä´gAMA† 1è–_PLTEÿÿÿÀÀÀ€€€€€€„Ž%bKGDˆHtIMEá"£Ý‡@IDAT8˵TAŽƒ0 ´#q½â‡åN³)Hüÿ+ë@Bœ¶ZNkU(dÌêmºò#;³#ÈÜ™ÖHÌ$‘D÷ ²ôþÕZÙ`¸äkôùj>Néíímjj²,«¦]Æ!$—ËŒŒ¬¬¬Äb±ãLJÃa/LÕjÈqQgff&&&†††?~,IOAME1™LÞ»wO–å³gÏž9sFQ/ºÕ€!Ùlv```hhˆ¯á‘4MÛ¹sçÀÀ€¢(ÑhtÇŽ^QÍ]ÆMg³Y÷«G»!A’ÉäÜÜÆxûöíŽãü@‚R cLÅÅÅÅÝ»w߸qc×®]/^4 c\3ƸܖóL,Ë ‡Ã.\8yò$Æ8…B!˲œJâ.æ8N ˜œœÜ¿[[Û;wz{{%Ir§¦W°ù.ã»Ãï÷—8º¼¼ UUmoooii©¸ÑÀ0 Ã0ø_üëüü|.—kii‰Åbº®{‰îs Œ±,ËétzvvÖ-cÌçóɲL)%„èºî.YBcÛvssskk«‹ Š¢B ÃÐucO·ÂÆXUUÆØ¹sçÚÚÚººº4Mãvy]èŠ1Ç …………Ó§O‹EöLà™”—”äQp3¥ªêµk×ûûû;;;‹Å¢GŸ8®ë£££†a” Ǫ¨ÈÏ^÷†Ù]×;::zzzÖÖÖTUÍd2š¦yâŽ"„æçç/]ºT×Ñ™L¦¯¯/ð<î¦iær9Ó4 !„Œq9CÏR€^Xc¬iZ,;uê”iš™(¥‘Hdtt4—ËE"^Ïï2~ÞT±Å@ˆ`;6e´ÜW^m”R¡å£O8¯UÂ@(Ø…D.‘5³*`.Y])+©0oU‚ÁD§ú±ñc¯_}}øÞpX ÛÌ®æØÌæ‡yº:j7h!ÊèyË{“ï-å–€Lj"Q`ˆÄ€Bp˜£Ùšfk¿ªýpiåÆë‹×?_øü㿌bˆ9̪P 1 Kw×ïöÿ¯ÿ­‰·Þ|wêé”"(5ãTˆÛ]-®~øÿÏÿãü¡æCÈDa)ÕM;ÌQˆrþÛóŸ%>KêÉÑïGããñ™Ÿfü‚¿ºb ÊhH }ùã—Ë?-O¬L¼sû¤ « W?ýáÓªbšQmuðoƒÓǧï»ûÁ¾´¬6ûtV"CÕ.ü5lÇÞæßÖùRçwÉï v¼®­¯Vê¦cÑN‡99+7›œE Ú»m¯IÍê¹®D€ä­ü¿8ð¯9òõÚׇ®z{ÿÛíýh­¸&àjêsb ±Þÿô~•øjäŸ#{ö¨–Z~dÔ´á+b ±œ™k ¶Œk µeÌ Á¤ºŠˆÅŒ‘éûoß7O¾ù"þÅ›}ó‰öä7Øenî(£a)owD;,Ǫy‡9Š ¼çýÛ?ÜnRš>ùþ“®w]p=(ËOùº#´™)m¤1µ?–c½²å•7^}ƒQ-UÄ"ݯª¡òe/ObÀ:Õ_äu†‚¢]ÌÛù:jˆ•‰GЊÕR7ïD/¡6å“!o<êšä@E>œ”Ä©® <bŒI’ …R©Ô­[·¦§§½ñ\wuu5N ‚P,ËÉ* o?JB»ÑÂʲüàÁƒ+W®$‰#GŽð¾Ø£OÜb6›Çã¡P¨bgWQxƒæóùJÀ²¬æææû÷ïŸ8qâðáéTÊ£—ÜQ¿ßŸH$VVVnÞ¼É{.ïŠKKKÝÝÝ/ôÔ<æ=òù|ííí­­­Ñh´. `0ØÐÐà%IJ§ÓÙlvëÖ­îð$p‹²,ÏÍÍíÛ·!¤iš®ëu€,Ëäo’Ÿ÷ûýõ¾- @àS›ß~ðÒ)w‘±ˆ;Ì1¨Q±/#„xOV­ wY¹eÔ¦6bÁ/ÞÕu½ ­¢åõ¶‡]C}óa­?Ü›ü?jÉÏæJ-Âð 0%tEXtdate:create2017-06-06T01:31:34+01:00¸'“W%tEXtdate:modify2017-06-06T01:31:34+01:00Éz+ëIEND®B`‚puzzles-20170606.272beef/icons/towers-32d8.png0000644000175000017500000000223313115373746017520 0ustar simonsimon‰PNG  IHDR D¤ŠÆgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<ePLTEæææãããéééïïïÛÛÛÏÏÏÉÉÉ”””¦¦¦òòòÑÑÑggg...ôôôCCC¨¨¨„„„>>>“““ÞÞÞYYYQQQ###AAAººº‹‹‹ÇÇÇÁÁÁãäãåæå×××uuu®®®²²²˜˜˜½½½ùùùïðïòìòÕÕÕ¼¼¼µµµ···ƒƒƒäääÞãÞõìõïéïëëëêçêC¥C¾óëóc²c„Q§Q³³³ÖàÖ—Æ—q·qkµkJ¨JÿñÿËËË[®[!—!”—Ç—áááôëô¾¾¾~~~8œ8A¢A*›*‘µÒµ¯Ð¯0—0 Ê .˜.”ÊÛÊŽÃŽñêñ²Ñ²ªÎª“½âââ¹¹¹7ž7‰..N©NÌÜÌÅÙŹԹçæçÒÒÒìèìÅÅÅkkkššš¯¯¯}}}\\\hhh†††£££ÐÐЫ««ÕßÕÇÚÇÿÿÿAL‘˜bKGDv1cÉAtIMEá"£Ý‡3IDAT8ËSù{Ò@ÝÝ1Án”ˆ-µÊ1‘Ð$•c‹¬R­G=ðªõ¨UëQÿßÙåñó—>H“÷½¹Þ2¶/ðCBLþ1M¬ÉmÁ”$¤ÎÈE8‡§åßÜ=’rÿdÈu§r.kB&<ï[p'_ƒpSÇO8RBpÈ-Ìå'RHn9N¡P´‹~8¹wr8a¨^,ù¾_&øez.§ ”)L/b±äJÁ tOg«Q´ ¡E p†Æ‚5^'q&ì†UÀ.8 hAL¶¦¢[lç\€8¦‹JÏ zÌIýìr ìˆè(t¿\–G ŒaóÜù• bl·‰ :u¥ ÑX[V/^ê"ƒµvÈÕå+ëW½ŠlÁ®]¿±3T7oݾÓSì¶Dï®·r¯Â0Ô Kî/?x¸™pX‹$b·³þ¨‰hjH¶ªš€­îã'MšŠ®Aõž>k!CÐ Ûêù*rE1]^¼|õ:¡%è¶U°Aƒ¢!Ѥ8…vÈXÿÍÛMíâÝVuVÂò}ÈvTK·iRÔZ>梨Lý >íJ½AÄÑ j;Ÿ¿4òÙR%G . Ç êk ø,5ãgüÌå´“Ÿ¿ÙÏÓÛÒw±g;ßµo4ì=½%È{žR‚R²Í®¯Í³”ÏQG5Š´,ÑïõÍÿ‡aX1¹V`Œ0ðÞÏ_ã@² qsMž-•˜gò¿óŠû;æŒý#HèÊlœ%tEXtdate:create2017-06-06T01:31:34+01:00¸'“W%tEXtdate:modify2017-06-06T01:31:34+01:00Éz+ëIEND®B`‚puzzles-20170606.272beef/icons/towers-32d4.png0000644000175000017500000000076713115373746017526 0ustar simonsimon‰PNG  IHDR TgÇgAMA† 1è–_PLTEÿÿÿÀÀÀ€€€€€€ÿ¥Q‹äbKGDˆHtIMEá"£Ý‡ IDAT(ÏMQÁiA ³Ã /ï{¤€ Öa ¸…Üý鿆H¾ dð.3F’-;H}ÝuôPèÎ0A Æ! /ïô³>ÿØÛU?´òfâg$Xo.BQ!2‡²5F½ŠÔ×*FlMº¡D‚»àªê^Ý‘ížÝàô¦:=Ýb»t¤,¤š0‚ùzHcE{à¸ÙaÞS¸Gý|™’üŠ%Êz0¶€¤ì¥%¯ÒÒ¸ÀýåîI¥)•9´w%ÖøÉ(x~C1!-ªŒkõZµN¸è[5.>Of18ߢÐc³¥aãžèÿDNÊK³°'C<3œmê:!¡sýÀÄì=ð &žWóØ%tEXtdate:create2017-06-06T01:31:34+01:00¸'“W%tEXtdate:modify2017-06-06T01:31:34+01:00Éz+ëIEND®B`‚puzzles-20170606.272beef/icons/towers-32d24.png0000644000175000017500000000300613115373746017575 0ustar simonsimon‰PNG  IHDR üí£gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEá"£Ý‡ IDATHǵVÏkI®W]Õ=Ó=™™ÌŽ¢âHÈ\A³O‚¢ ç˜“9yô”!7APO‘=I DÅÃ’C4“LÌŒý»»êí¡âd2é$^öúÐõª¾÷½ï½Wkkkäÿ4ºß"þÊ~D<Ø3@Ó4Ã0àPÃ0 Ã8#€RZ¯×—––Â0<caaayy9•Jý*€”Ò0Œ—/_ ½~ý:“É!3ëT*=Ïf³‰ž­”RÛ¶GFFΜ9S¯×5MKŒ Â0,•JCCCÕjU×õý¸²–¸<¢(BàOk9]éôýû÷žžžÁÁÁÙÙÙCR$¥Ã0c…BáéÓ§«««ÏŸ?_XXÈårœs½É@J™J¥>þ<66¶²²200Çq" P}`šf­V«V«š¦€ã8„!D:fŒ53€öövMÓ‘RZ«Õt]/ ¶m·PJ !°¾¾.„(—Ë/^¼8{ö¬J”J½ŠT‘Sÿu]_]]íìì<þ¼mÛ”RƘ”2Žã½jyž‡ˆLJ©ëúÜÜ"^¾|ÙuÝýäBÄT*µ¸¸8==Mñ}ÿ€"€ÞÞ^Î9CDÎy__ß·oßêõzmHP¢¨ˆãØq˲ …‚ëº* { Ý4Í™™™b±ØÑÑÁÔN×u…”RJévB2`Y=Ä+\ ÐHÝÉ“'»»»UŠ”'hÈd2•JE)G›ÙÉAÜÝ«“WÇÿϰŒDÙX ÃÐó<ß÷}ß÷|O„" B×sýŸæy^ }°JK·î}¸7½8¥YJis˜ ˆR Õ*^ÅâV^Ï;±«»ú åô¼ž2ÿ$˳£Ždø.Š""êš~÷íÝ+“WÎý}îÙÂ3‹Y-nd¿i*ˆx<÷x¶2ûjíÕ»¯ï¦V¦Úx[ófi ‚›7ß^;ðÛÀƒÙ‰š'ü€ îôݹôû%&X†dÚv ƒL¢¼vêÚ†·ñ¾ú~øa@@Ò:·41Æ×O]Ϲ¾BŸ/üÞöÞÍ`Së.¸5µ25üÏðhïèíîÛ[á–ZK–’Evd×ÂÚ…ã(¡›Á¦ZóÀP‘À؇±ª[XœøXùøpðá^¢»š!D#ÚàTq!¢r@DÕ}~ìßÿë¾{Nì´±¶½ ïH)9ç¦iªa—H  Ã0M“RÚ`S²J(*P"H€t:½¾¾þæÍ›(ŠžEårùÈ‘#‚ d À ¹Ÿw@199Y«Õ–——ÇI¬6òóšüòåK¿jÔí£Õ¹¸-ŒÊdc¸n3¨T*·nÝ:}úôÁ†aLLLÌÍÍ}úôi¿—„r›™™¹qã"2ÎùÆÆF©TÊårš¦éº¾=ÂÕxØ®ˆŒ1˲:;;xªPJÇéêê:vìX,Š¢b±ØßßïyžR[ùqÊ9呌Bª$¨Bp§\.§Óé†ç^æçç{zz È¢ˆ©›¯1ž¶¿–쥯î×ãæñÖ UJ­£G^¼x±åm0M³X,Ú¶­"€µµ5PÅÓ¼m+ܪ…µ¼žÏùæ³Â0d,¹=•€zpÎqûÒoܺ;åE™š"Ƹeÿ¡ÏÖæÓXƒZ‹S$£ˆD;UØ”r˜í tß(Èá/ß_±ÿA‘ö“)„†%tEXtdate:create2017-06-06T01:31:34+01:00¸'“W%tEXtdate:modify2017-06-06T01:31:34+01:00Éz+ëIEND®B`‚puzzles-20170606.272beef/icons/towers-16d8.png0000644000175000017500000000154213115373747017525 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<ePLTEæææèèèêêêéééÜÜÜ×××çççÚÚÚäääìììÆÆÆvvvïïïãããåååððð®®®]]]ëëëÎÎÎaaaíííiiiÂÂÂÀÀÀ±²±ÀÂÀÇÇÇÄÄÄÖÖÖÝÝÝŸŸŸæçæéèéðèðâââçæç¸¸¸ÁÁÁÉÉÉįľ¾¾ÛÛÛ­­­íêíßãߩΩèçèìéìõíõëìëÑÑÑÔÔÔ©ª©ÛÜÛðëð‡À‡? ?ÄÅÄêæêÅÙÅ€½€ÉÚÉðíðÏÐϪªªÞÝÞåçåq·q4ž4ÍÜÍåæåi´iÈùðùÍÏÍ©©©ëèëäåäÃÅÃîèî°Ñ°8 8ÆØÆÎÏÎÞÞÞîêîÈÈÈÚâÚÅÚÅØáØïí襤¤ª«ª¬¬¬§§§ãáãéäéÍÍÍØØØ£££áááàÞàÝÞÝ»»»¹¹¹¸¹¸ØâØáåáëêëÕÕÕÒÒÒÓÓÓ¿¿¿ÙàÙàãàéçéÿÿÿyNžbKGDv1cÉAtIMEá#ÔÚ·úIDATÓc````db&f`daeQ¬ìŒ`>'7//¿€ H@ˆGX„—‰‘QT@Œ¤’M\\BRJZ†‹QVŽƒQž]AQIYEUM]CFZS‹AH[NGWOŸQšÏÀÐÀÈØ„ÉÔÌÜÂ’ÑÊÚÆÖÎÞ(àèäìâê¦cÅáîáéå ðaQôµóÓ÷ ¶1aeRcc׈ŒŠšÁ«gŸàÈ‘˜”È—lÂ’š¦•î”Áꘙ••é¨ÅÀ¡Î¬˜“›Ç«™_PPh\ô/Cq‰ €<t)È| ÀÀŽ·$H‰Vø%tEXtdate:create2017-06-06T01:31:35+01:00P˜ã%tEXtdate:modify2017-06-06T01:31:35+01:00o _IEND®B`‚puzzles-20170606.272beef/icons/towers-16d4.png0000644000175000017500000000046313115373747017522 0ustar simonsimon‰PNG  IHDRbògAMA† 1è–_ PLTEÿÿÿÀÀÀ€€€€|SƒbKGDˆHtIMEá#ÔÚ·PIDAT×ʱ €0@Ñ/¶HìÝ$—ԉ䆰tÝÅÕW?f 3ú¡Ü‹"×*$·Àf>ÍñÜ•þT#Jub*‰Ã»1þÔµ8!9·9nÏés}$%tEXtdate:create2017-06-06T01:31:35+01:00P˜ã%tEXtdate:modify2017-06-06T01:31:35+01:00o _IEND®B`‚puzzles-20170606.272beef/icons/towers-16d24.png0000644000175000017500000000237513115373747017610 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<ßPLTEæææææææææèèèêêêæææææææææêêêéééæææææææææèèèÜÜÜ×××çççæææææææææèèè×××ÚÚÚèèèææææææäääìììÆÆÆvvvïïïãããåååððð®®®]]]ëëëåååææææææëëëïïïÎÎÎaaaãããêêêèèèèèèííí®®®iiièèèçççææææææçççÂÂÂÂÂÂÀÀÀ±²±ÀÂÀÇÇÇÄÄÄÆÆÆèèèÖÖÖÝÝÝæææäääæææçççèè蟟ŸÚÚÚæçæéèéðèðâââçæç¸¸¸ÁÁÁÉÉÉÄÆÄÄÄÄÇÇǾ¾¾ÛÛÛëëë­­­ÝÝÝíêíßãߩΩèçèèèèÇÇÇåååìéìõíõìéìëìëÑÑÑÔÔÔêêꩪ©ÛÜÛðëð‡À‡? ?åååèèèÄÅÄêæêÅÙÅ€½€ÉÚÉðíðÏÐÏÔÔÔêêꪪªÞÝÞåçåq·q4ž4ÍÜÍíêíÄÅÄäääåæåi´iÈùðùÍÏÍÔÔÔêêê©©©ÜÜÜéèéëèëÉÚÉäåäèçèÃÅÃîèî°Ñ°8 8ÆØÆðíðÎÏÎëëë®®®ÞÞÞêêêæçæîêîçççéééÈÈÈèçèÚâÚÅÚÅØáØïíïÑÑÑÔÔÔ¤¤¤­­­ª«ª©ª©¬¬¬§§§ªªªäääãáãéäéãáãåååÍÍÍÔÔÔØØØ£££áááÛÛÛàÞàÞÝÞÝÞÝ××תªª»»»¹¹¹¸¹¸¹¹¹»»»ªªªÛÛÛäääÉÉÉééééèéØâØáåáëêëããã¾¾¾ÕÕÕÒÒÒÒÒÒÓÓÓÑÑÑ¿¿¿èèèæææãããææææææÙàÙàãàçæçåååæææêêêêêêêêêêêêêêêåååæææçççææææææéçéçççæææææææææåååååååååååååååææææææÿÿÿ›ËÆbKGDô2Õ+MtIMEá#ÔÚ·IDATÓïþ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•†–—˜™š›œžŸ ¡¢£¤¥3¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóFRt¯ª™d™%tEXtdate:create2017-06-06T01:31:34+01:00¸'“W%tEXtdate:modify2017-06-06T01:31:34+01:00Éz+ëIEND®B`‚puzzles-20170606.272beef/icons/tents-web.png0000644000175000017500000003771313115373723017435 0ustar simonsimon‰PNG  IHDR––³cæµgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEáæÛô>ÏIDATxÚí½yœÝU•/ºÖÞû7ž¡¦Œ„ @˜#ˆ@DÔ‡Únmîs¾Ýmkûž¶ýÑ–g7}¯mß¾^µAïEi[ú!³´ HL @™‡J*•TR©ÔxÎù{¯õþøªT*UçW$Í"ŸP•ÚgÕÞkíq­õ] »ººà-z#“x½;ð-½¥Â7<©1ßÑëÝ¥ÿŒ$Ä‘¯¥CTˆˆ¥r Oâ£lNê÷ 3£ÀÉ2'@¬p2Äô :Ãp|ŒÉPP ';ÎÃHb…Iš¬ùÝÚ46(¸!G&p|•ƆˆsÇB ²eê|Á!0í*cȤ„“¢íª8L'Ó–”-!)330 3fÿ"³Î;ž•D:G&Ã#•RHK$¡ÎÄH#ÌýBfúóŠÎçœ&Qòi±®B"*–ŠëŸÙøßùòâëN †bqpÒ,„ƒ+‚ˆÝ‚½â§O»hVÓÔ‚Ñ&Wd]ÕÍ+÷\|Óéa5 g4ö›œçÚ6eVyΙSã0ÍÑ"¢Ié¹{·\tÓéFVù8=g·ho~fw™³/?)ŠQ¢'m&&%3k2–†)6)2ZžZþ“ o{×|·`󘃆Fõ,WuoèÜÐóŽ÷/ †bè( 3ž’QB2p¬S&ðÊjõ};¿Ùüƒù çDaŒ“š°ã©P`ë·_tÊ、_פÙyøÖC#ý5†ÊÒØ\õsgÌlIYÃÄ¿›™mT]»{­Äúƒ÷]2¨ƒQÌÇ!£M‹*š^˜{æô·Ÿ¿ FqãM ÒÔT:¢>t‘f3J ™€€é9*Kÿ)omXK®»aqÅDBâ6èrÀ*€Ûƒ6¨(öÀ` üÙ05¤ØNßæÚµ7]P.{f”˜Aâ(æÌ졽yãž5…ípÃ%ƒºæ(«öP {`¦B¹ª Ä<˜ë´¬ü¨’Xòƪ€10q?TMM€¨Ï^" Y–6r}+!Ã$Mh’!¸`¥Æ4þ5–RC:)é‡jÅ¢áM˜ ‚ÀÄUöC-0RC ÔÚD” BMksPˆHuLv™²ž31IªR™djiõ{k|jçË®mÙ–5T „M®ßT-)ÿˢ믙u^IDñ®ÑW!ˆ$0NaD,À[Iʼnû¡Pòý þÛæ§•EתÐâ+Q¨É|ø´Ko]p¥RÜX{Ìœ]3ñð‹Ï¡ß3‰„B*!•Qº--w¬DY²— !0k/‡ÛÿGŠŒ'ŠI4VBH!A Ì˜cn{)„Pˆ P8üK¥ç÷lžòâ¿ )Å(æYÏA@Ü ƒOízY¸c:”è"Kê«ÂÆ”Ì/¶-‹ µ@¡@¡„„‘¡PŽSë™úÜÿQ”¥¤B©„ÈÄ"¸`wÇý÷·¯FÒ@\E ÑÂþ¸j$‚û·¯èN\°sôgYVkkk[[›çy|Øy¬r>–]ÝãíYgüæÚ¼ YÙpÈNr „¤Ð±ÚÝ×áöl¦žŽœ²Ì,@( ~" ¬ß7Ø `œë×jg·¿{meÞ%‚ƒÑG @ $ fuæ Ñb) “™•Rû÷ï_½zu’$guÖ)§œLJ™Ÿ# ÛŸAbUí÷;_$p&s+{ý‰‰Áq»7ÛÚYBqÛr=Z …‚àÏ@v%¹203ƒ€}Aÿ#»VÙ ™ûÌŒ¶UÝãí^Cv<+õ ­h àûw®HŒÎ® ‡0FÀD§÷ï\A o¡Ììºîã?~ÇwÜqÇ—\rÉ“O>Y(F?ßE£OgÝóK„ÂŽ•RÊ#~Á;BÛW +áôlwöofpêïAbò¤³‘;ŸíÜ$ä8ë"iþ÷mËcHÅ!w …ögE”’ÖP¯ßù"=2¹™Ájô?ؾ²ÎkÜ_ð`ûÊn°¥â †"‚n¸aõêÕwß}·Özß¾}RÊÑí¬Â¬£Ïˆ8,Ñêõ;×¼"ƒãìßìôì`…ÅíÏ /Äú3ƒmT €ˆ™3=eÊcf_:xè»ax ®e ‰ÅÈäV#OP =aŒb\i+Ùæ=ÑhŒ1Ó¦Mûä'?y饗žrÊ)W]uU†£/5ã«áŽf“wT_åq½³%¸}ŒÜA-µ9“c¨“Ó`öO»Ä’Ò·É‚ #PÊž²-)ÛJåyµ ŠÎÚá%'€˜Y¢5ÔW_ˆ@™6ÒS¡écg^í;Ž£l i@ Í6*GÙ¾ã|ìÌ«§BSJºÁƒµÖû·ûÈ#ìØ±ãûßÿ~±X½‘NpaY‚l `Êúª†zýÎ5•y—W_oEM0`fF×Ý¿®¾GDOPܾ"žv*’üÔw]?ÿKȵ}ÿ¶îÉŽê à¼OûÃÓ®,Û¾#¬&Yˆn¤£f¶‚‘m9›ÜÁìsI9Ù¿Àôõs–\4ë î¬øÙú'6è€Ó¦Ì¾ùÌ«gÛ°M”hô"$¢B¡ðõ¯= C"ÒZϘ1cŒ{\2)ÛY‚£-Y_眫…õz+k|bD]Üþ ŒÞØB§§ÝéÙL=‡× GLs›™è]3.|ÛŽdÇOï·Û¬Ó¿þ«Ô¤9!„Ð$pFØ3ÈÂŽgE’°%€)Û4Y 5Ôçw¾84ï2„t¤3'-v‰g¶N?}–µù§?@€S¿|]©õ”„j,0LI‰è¼óÎ{ôÑGñ‡?üá{ßûÞ¡¡!)åH5ÑG‹Û–Ë(%[ÀˆÎX 5Ø[èx~`þe“3âSB`FÇï~Ùéng‰pÈlE4PÜúû°m wä_b ˜j æ) ÈT&jHLÖ`D} ¶]éôw½†™sý/„ÂögƒÏa»y´4N!6lÚæqf0ÊµÈ bEïÿûo¹å‚ Z»ÿ¦BfKUºìž­Æ·¹þDþ! íîyYÌ>Ÿ­âñv5e@ãu®aKr>a,°wÛ½<õìÑ72@H)ÇC ]FÙ¸q”除·û%àÔ¸Ò!ïcB”Ñ€»o“™s)Že‚ Ä0 ëã$ˆˆ•Jepp0ûzôú_…ÄLj«Ø}ɧ'4{21`cù˜A*""&6@Æ0`#¯$&ÅLL† Ø }!ˆH†™˜€Yë¾³o€³'jÏÄ‚˜(ë¾af†DÍÑô'K…ï‚¥  d2L6310DCó/šÉÄ„&3™‘aD©h)7Ýz`KÉ@ ÄÀL†¢aÛß„$„hàP­Bd`WØ%p2B©±vøC¤¬‹àÚÂ*§n*™¹ÙË®-T <–,dC)S\GXžtŠà¢Ä|3·4¶PEpµ4  õɘ"¸ž°A@<#i¸3\8éä¶“Îd`†@ 0’Ž-¬‚t‹àÇ™@& €ÌäåKÇÖæ8eFËûþ"ÊÎFZÏÖÑìfUÈDŽgýþ§ëƒ¨šŽrtêE“(˜Àñ­ŸÚ>0P-¶z£¿ã’Tb¨7ع¶›ÇAÚX%LìíõOwl|aךÛÓ¨áü@£éåe;ñÎ'I3`c{8¾µsmw›½]}Q5Ù›™3_JÉ£ˆ–£^|z{”&ŽoåD50(GõîÚ»½/¦4ª&GÊ\?>…Ûµéw]=ߢ¼µ˜¯BDLcsÖ¥s¯ýÔâžšk[žr˜˜% 6Liœj]lñ*}áE7ž>uvSš˜2fË‘Ý;lG]ó©óªýá¡«pÄ¥W'c¨iJ‰g6匥sÂJŽ ¦± †â«?~®Nr\ÄD\lqW>°9 ÒËo>{¨7pmÛ•63Œ©dæ@GÚW´‡zj—ßrN¡Å¥†“•œ‚µã¥}—w^ó©ó†zÙx¿1\lsMð|k1ɨ€*&.–Ý6«äOwöè÷vüÎ‘Ö ¯eë`—-ÕüÒôíCûж÷9µBÉ•v¡è´¶•ÚšË)7zÜdþ¤MûEgŠÛdOµF;#"¤‘ššU¡Xv›Z SüràNÊ_蜶–ò¡þÂq¥F%é—›}K%mv¹8ÝÝï{x×ʲ巺¥m]¾åÎ)NÝ:Ø5Õkzÿì ]°,¡ü¢Û:µX,ûUÈ.Úý­ÕBÑj7YSUžg”š”ïÝÜãpr*̘21@w2ðÕg~ÒÕ߇¹îœ@ŒdxÓþί/¾Åi€4˜ìNl"b`hÀp Fƒ©_ó˜m{`'¦Q<õ4ä8Ûa2¶†9㜂ilÎG͆€5˜|f̲>wû¿²âîþJuÜ‘¶÷îýò¹Ò` “fÒ`ˆ ú¬Ñ0tÈH'R!P š8çÊü…Ì,¥<|tcUÈÀ6¨žÚ`W¥Oy’˜qøfœÙ×ycß® ‰›<D‚˜#b¬·ùßÁ_'Š[—©ZßþËO{à 3Äþ2ê÷ç·>èaw@í©ôõת–§ Óè‘ d̺ގÄè‚r¾&Áûæ˜ÙqœÌ¨ÁOn#e¬¦!HÐdˆ‰˜ “a"fbKªjJGõ*df´Ágÿk°ÛÛ»a´'áXÔôø#5DÀ „¨ôu²ì‘ëºk×®½ñƯ¾úêßüæ7¾ï¹R¢B¶…êÁï½ü Ð8Óƒ…À¡0øÞËj <‚Yw¨ í+Dj¡Ø¾!ãÒ{íˆauÀþÿ¹î‘qÁÀBâþÊà?¯{Dí0–â8nmm}æ™g:::”ë™:T…Ì–ûa ghP*!p¬¨î(‘°¥oO ¢ì‚zD"dFÛÜåu­c,Ñ>ÐéîÝxÌ"3ÛRu™¾J5TRŽ;R$lêíŒ!Çjn!!D†]tÑßüÍß !Äágá!=CÄ„ÌthžÞÔlB¢„Ù0Á€¤™S†Nk›U7;?Ž”°Ð¾SYyÅöåÈÇh!"bbô,ÙÖTôudÆiÊ”0Äpæ”9X¹7Ž×¶«IÒ××—¦é¸ûù¡ÑÜ€šL3¿¶øæûw­(vuoéÛ.3ǰxæ)eÛ/ZÞç.ÅÉZ%ftF–`Ý©Ð>ÐéîÛÎ\„\{Í嘞­_¿àÖw=ëHkKÿîƒÝà"3C ï˜uš+í)^ù¦¹KÍë.„ˆJ)¦1?{#ˆ è¹¥_]ôØáãÏÿzõŠåJÂ¥×ÜpÙ‚ |°8ÐQÚð!‘Û«l »lêTl_Í8ŽÉB€1¤§5Ï:·íf¸j-díó«]G\ùž/žý6&20¹ˆò×€ˆ¨T*ýêW¿ºýöÛ1_þò—7oÞ|çw ŒØ»Çq6!@iÊš‰Y~¯ZpÑò墈S>xŠ *`þíºQ¯¤ãîv÷n`KàÈÎI–°û:ÝîÍÕg‹ cNÖlLQµ|€ç^¾lµœjM¹åÔLHчç¾j=DŒ¢hÑ¢E÷Þ{o¡Pð\.A0Úê=¾¿% @  $Ð;3A!±ˆÁ”7=©ªš-lFÿ5”7>´Í«éØDèÔ¯- ˜*¦C6(‹}ޏÃ#}=jYÔEKKËÌ™31RJ­u2·{Úg'füÃuS¯ 둺]`ø$¬‡ïqC£2g±} 0‰ÒRÛÐi‹'2^c°Õ#±œ £©Çf½iÜvTàuý;æ,B ¢¬‡ ãÁ†ÃCÍÐ3ÌÜhâáh€á®äÌC®ÿ—«ÅJ¥2ò혽Aa¨P:`Ù¨$ `ÔÙ ?øK¶€ ,0H6X „Ê…ÐhËa” J¢t@ÆÒϸib‡'*]sJ •–F#0Çú#% ,"ÇÌlƒR -öÁ‘*Ý´äm¥óNDi„i/QØhÙ`5Þ~2Û–…J8(Æ‰É 9`ɼ³Ü[Ìx*dRôõT:ú÷WzƒGB›¾™“¡B³;ÐWëêìM8Õ‰ix8²å¨ý»új»z÷Wû#!z¬,"lóûz*^—½«gXIò< 3Ø_ëììÑiž”¨ØìõtƵtWÿþJßH@ƒ(0°éé;k°?ØÓq Ðì’ΉÜu|kßžþþÞjGÿþJo˜ã54ÐæöÕ7kL£ü…ÌÊ–ÛVwù%7¬ ãÇêKeØ4¼rˆÙñ­]ë÷Û®Êü…Mʃ=Á®uû—ß·! R@P(1s` a“=Ÿ5 ðJvû‹ûú÷UûöV“0͹V æÝ›<û變۪Ùñíö5{ub„À°–Ô—m64æº%nµ–£:7ô<ÿÈV§`±i¨BË–:»¶õ-ÿņ\3Û¾êXߣÞ-ØYqP…Bˆ8L/ºæŒ›þè’]*gú”¤OzçÍçÎ8!§5™jOgïS¿XûÇ·]5¨ƒ‚r† HÁÀ­ADÀ%ðBˆ ŠŽ›UñÖ²¹gN?÷ü5ŠòœM˜¦šC¾å³Wj6ïÊd¸,ý§þcmTM®ûƒóLud`ýô?D”Lì 'Ôïÿ¿.*ÕÁiFꢽeãî5¿m¿õSWæ‹QS“*üT?‡édQÄ T˜9"BBmhø1–QZ5áØ“§UMQ:µ„õ“»×|Ý#)™ÙÅ)»ª=šÌÜÒôžh0ÒÉ­§]yÜwTC×L4µ@çù j­cJ‡ ¦5åþ‰Yr@qfÒáÁÀDdâC?Ïĉ­#J‡tÀÀ9ñ ±•VMÖ™ç‰Q3(ˆ)ɇI33óäžöÃ@²Æ¾JD N#ÉWá08 lPhèG~5ÕPâ¦þÝÙ· ìAÌðã O¼mÊ‚s›æÃòM‰ÜUHJd¡8ÏåË2ë¹@B*¬¯BfF·yí}ñ”Á odV¢z{©„‘ “ „¬3Ïq UCDîúCDÛ¶…iššÃV‹‚cK¨HFœ‚Ê.}YÄ£BfRÒhPÀ$3¼JÄÌhYÕ½…«Uµ7<álx½õ£ÉÓÕÕ†áôéÓK¥R#gÓk/(P —ï_ê8“ ?Ìèà« –u¯;æfÉ )±ìÞn÷f÷˜:/' "ò}Ù²e×]wÝÒ¥Kyä‘B¡0f!;2°b‚ÿ½áIch‚íàç›· ziѱq´f`¥Êo÷K¬ Ší+ôñ°3ÛÛÞö¶þð‡¾ïk­óÏÂ×¶C€”†úCÄáÀa3±s åÇPGJ¤l –ìô´;Ý›£ég"‡¯»"ƒÂh­i˜Æ´9v«pØ“U¸ñ”‹ i®¦ƒ `Ã×Î_<¦Å&ï9øªÐè%(²è¦Ñ ñ8À ¢ïûRÊr¹\*•Æx í*DL@dÁe‹gœ’½/èÿÙæßvE}Ðê?xÊ¥ ›gÐÂÂ,€¼˜ªW“.Á: O¡ÓÓîìßM;!8–"CY®„ŽŽŽx MÓ'Ÿ|rÁ‚‹-JÓƒóûXßH æô´òlÁ(ZìÅbú‹ÿíŸMg}òú“æ^ )5›ë ³´íáSð MŠÛWDÓò뺑fákÛ¶m»÷Þ{/¹ä’õë×?üðÃK–,‰ã¸‘¿ðµ†œ¢ñPžÑ/8¤2« DÌp=ßÍ1ÊÂŽ•ÃKpØ Á-Dwÿ–`Zøº¢V«]zé¥/¼ðBælJ’¤R©L_øZÖA{A$ÄÕ8ß°‚Ñ£ó‡ l{`»¿k  9ħň¨¡¸my8õdÆ×AJÅ…˜$ÉF¾ƒr:´sdÈQÌ… IDœµ7&Çì$,"CT§Qf9GKƒmùKÏà$ÅrACʆˆ4EYL§6šr¬3ˆ¤3pM¹Ö#)‹%HUè¾ècÅ\1 %©qMæÐìOã´g6Vù¤Ä˜4ÏÀ=.¬pf&_º-P9`¤2øž°ËÒo†b"uc|¡ ª&#OØÍP‡™3L™9åöÛ0ƒl¡e€j†¢'í¢t›¡`))r1Ê8Âj‚¢V&×_X¿ ]!°|ôPOh` bJ|p<¢@·ho}¾+ôPD•¤±ÊÀrÔºç:ÄOÐ)ØWLæ™Úß1°gs¯j‘}vµ'vŠÖË+;nYlqÀøhpÍ3浜ºäÄj_ž¯’È/;ÛVï{ÎôÖJ:ÉÅØ¶µwO·j?éÃ'}f Ò/…lÀÜÓÒÜ‚m?Ÿ7}Þ¹sÞ^ j¹þBND÷ÔoÎ?'}åXB&d "%¹õk:N´.6¹µÁ(Ò…̪„3òf“uës{æŸ;Ó/;d]•3—¯W´“P/\2+_Œ† -ÎîuýFÓƒFƒÓÐhsâܶsæÏ˜3)áê¶-8í M ,AÌ)O l€4 DÁ€ H³N Z0ÍoÖæÈÓ™cÊ\†ýýýI’c¿O½ÉV¡ùÔ™×{j½¸­· @s“]˜Õ4%L“÷Í}Çé0ç7fÍëŽÝ$eΊ)S¦(¥2áÀÀÀèo""h0SݦÿûíÈÀ¥¿Ú¹êÉgþ#HÌ©sæÞxá{Oõgh a0}ì|‘GGY2˧žzêÏÿüÏã8þêW¿ÚÞÞþÕ¯~ut2Ä7 !3–²IA€òÆY¾cõ²¤³:õgýù5Ó‡R ¦7Ψ³]ô„N¸ýöÛ§L™Òßß?{öì4MóÁio\Âá*W9Ž-ÔB+HD=ãáéøÏÜÕ»§Õ’H±rÔúßïÒ©qü¼”“ Ê–º*[ÔS•¾ óý…^°ceh],^pZÕnºæÖÛoûÔ}²¡?ÈÝÚÜú×ðW'²6kÆ †*m$`¤@"@ ƳV¨víéÜñãòÿó¥¯õö÷ä17S¦LùçþŸñ;ž]¼øÌ*…y^{êjáoZ¾ý…ÿê b£%NdZZšþå¯V©»¯ûÀ;LMÊO…'0O¼÷ÓKJe//"xènؼ¥úà)ñÅ¿8Л/Æ)m­ÿwÖªhèC” !Ë¡ÃZ\ âŠT9{Û©IRÖ)˜š ²é‰UÝ›On:!ÐñîÚÙÅ©®´¶î}ÇŒÓ>ºðå%¬µÖaFQ,¥nÌ<Š¢4M h΢!aH×’ÁP×gj"Cv,¢´¦¥‰A§¤Mž³I a˜RÒ è\g“”iÊ”˜¨×jqE5£6µØNt<™4§å¨ )¤R4œËŒ,„DD.€ûÓO>¸ùYaá¾J?ÂþÊ¿ÜôL³SüÄÉ×d;mælj¼‘2SÝÇ$¸žù¼áY˜µ@R ÌI¶%0+m–Ý–^+g R‘#ÆzµI¤oDBŒ{W?ÚGÛ C @(QO1 ™ˆdLo0dƒzCxŽO’Rf;“eYyõ _!1€%T î û@BØGÌꌘ4è {{`È:Ò½þ?3‘çyË—/_ºtéÙgŸýðÿÊà4b*Xî/;žYÓÕ.ä8I;™Y(±z϶‡v?[°\s öÞX„ˆišÎš5ë _øB–}æð÷ØÑ­BØögÙWâÍÊN>%0t¯W>È74e¶… ¾ûÝïζÐÃ×ÉQ‰U Æ:½bÖ9Žg%¡æ”Ø02Hd`ÜRj׳/›uv¬“7Šàx#­u¶yº®ë8Ϋ鵈‘IÎ-žü÷K?±¾o—§ìw<»½²—,ä”O)ŸxýÜ BŸÕ:÷,î–þ½×[o<’R®]»Ö³}ûöíÛ·755~`í#HN)xvy3]6ëܧ~òÃ};O8ó¤Ë®ûD™-DqÁ1Á{¾é(KfùÔSO}æ3Ÿ™5kÖüã¡¡¡üÇìïï5ý…0‚$âˆlYº¨ß6{¢o=HÝã¿öèqIYìÌe—]öòË/üãäŠß½⺟³ä—25‚"¿žùRŒJö!խ͘%£lx‘1Æäes2†È˜ìHÀdYÓš“}5µ™À°É2‘0©úƒÑ1†²Ò€ ˜c˜(«œF†sr‚"“!f2ÆåT÷ÈHY!·zå´œö$²2nd€r1¤ˆ 33C†LÎHM¦«ÂzŽÑÜÜÜÌ\( …‚!kŸ-•Šžç‘Ëà'R!BV ¾të‡ñVÁ@¬d•ŒÀ.¢ë¹n©\d4¹Ì …‚_ô-á5AAÊœüH„%صݖ¶–(µ±±”L©X.•K¾vš Èr+H>8Ž°Ë²PßHÓX…>¸Eáß+ †óÅX,=Ï=š:‡dB´m{õʧ·<:44(¤ÌB¡G ¦ ‘È å/oéÿM°mêŽvñŒ ÖÖaU¶êÙ×ÓóréÁû­Ô…Äœ¡8eY™–r¹éÅç_ŠâMÕ òÊn¡HL¸ecøË_<”˜QŒÇ2è.‹…çž}a“·Ýš*ƒÁ(×­fûÖö-{žúõ ^ɦƙ×êlß›¾X{èÿ{tphPN(F(²ù´þå^xÑ«Nc`ÉöîâÊ—Új2RøÊa`Md ÅÀ)iK(buÌ^É>ànž©c&(Ay°Î;ƒÚîq7½ÔvO`%(ÀSŽ@LÉXB"@BF €¡Ž³d§{ü-ïØÿÁS÷-ˆÂ¼Ùœˆ5ø?^lûßJr”e¡JHg‡Ôè,s¨C¦Pò¶6mŸ½ïÒÓ÷.­T*ùà4×]W¡Sö_]¨‰mŒ™ ýî½OzÿgM[È%úÊ@M&31¦d”è˜ xMÖ>¯]±ÃGŠèí/Ä4ÑgŸ»àºË.Ò!*XGD‹(î5} å4ÑÜmú}ᜎ³c“¥·ï…¡¥WŸ1œÌ2§rZWgoÚ¯¯½âŠlem¤]!'ÓeK·é7@ dk?Uø,1—4••_Ý‘^¹àŠ /9¿ZË‘2 P,žßûè»®9ƒY:¨¶óÞø¾Je(Ï­F¥bqã¶uïýƒ÷´´´­{íý‚·î…-]Ï.ËÄh)¹Ž:hŠ(ï3ý0C¶ôÐq¦8)Õ¦¬¼õi’ù£kl2Ë€¢A¨ ˜Úw_úåïv¾¬¤´l† ø®Å ÿáé—ßròLHI…BœÔ䵕ªPQÒ•ôÿÚøèÏ7>-]Ç¢<ÏN£¹rޢϞy) (êè«Vr ¢8-L㨺àý²cù?­yÈhò='JÒìzN}ÖÌ“þêÜÌð[kU‡ª•j¥¯¯¿q%qa_?7¾è1s‡ƒƒ!ÅP (þÁÚÇÞºJ a;VÆ™ã85Lן²äS ¯!Ð娭WN;lv#øàì¨îû]çËÂE£(4‰p L 6‚„‡v®Ò PJ!&þ#¥ „ À«?­>´sX6& C“"áào:_êöûà Öã ²¿“R” Ò;ž5LÒ‰YðDDi*Œòåº}kú¶Áe“a{ÿ+l .XûâþÇv=°Í¡‰…‹ÂÁÀÄl3XðXÇóÝñ€ vnå4¥T[[Û´iÓ·®ÁxÅï-T  žfë(¡zD ‚’R¡<2ƒ'Z(• ënèƒÌ³_(Á%à×Èœ”H%%`yö¦AÌR„1(°PÉcJŠ€()¥14v¤ € ¤°òĘ鯯¯ï¨T*_|ñüùóG§~‚Ã+§IÄ÷n}*;\yTÕΕQõß¶=-Ž øþ|ÛÓCq0¬³ÑÌ!³ülëoCÈߎ;Zì;VnÜ ²žs4sf÷m_¶ú-!_S4 Ÿm{*IÓì>rÆe‹ä¼@Çøš¹  %ÝåÛι®­Xnv ¾rŽ4e_9ÍnaJ±|û9×µAIS£t DdÛöôéÓ-Ëjmm-—Ë96R˜‚¾á¤%WÌ9G¢ØVÙ÷¯kÿcs÷.‰pÞIg~øÌwNqJ„vé+…è ÄÒ §¾hÚ|þuý/îÚhNŸqÒGÎy×üâtTb/…W áÌj¾Z>ñ¿]ü©ˆÒÐ$÷myzù–çC¢“š§~ðmï:·m^J¦ ýlóxM]_ˆƒ~çÌ·½ã„…°;è»÷å_¯Û³ Ξuòžuõ‰~+Ø‹ºáF¢¢¿óïDQôÿð•JåÿøGWÞß‚râ+—Éœ×|Æ)MQÇ]÷È,øú5ÊŸ–rÄ¡N¬#òrdime!󂬿œsͶ»7RsÿìòbÓiUP`˜&.ØGÆ<âD ,§¬ Ÿ[øžkïYí®ø'çMz~`ú]eG&uÀ>&™2!äØU6ŸQZðÕÜ~×6@˜ÿWW»¥ù Õ@`˜Æ&Ãí„NøÒ—¾ÔÝÝ}8V{ÂÊi€ˆS0>²Œ QPv@ÅØ€Ù`ª!ñX0S :„˜êÕfX d`b2¨‰c¤ä¬þ[Ì@t,Õ`=«#EÇú C Lr¤Bˆ,7÷å—_ž¦©eYQõ÷÷O _˜ñ€ !aGžkGs™)Ž€@˜‡ˆW+À-Ó“@Ô“' Mv©9¶žËz rh @3R%~r£(Ú³gdBŒ1'ö´'àìo`$H­9Ó[?{-*%ŠÊêh³–Õ% `"nl`cYDÅXQ.¶~ê½lŒš5 eF z€€xü„⇋‰i¸Ržaβ(›o}ÕB{á<‚³_͸ÎÜådNÌRpg›<37b‚CÄZNmmý/ï9¥…A3Ãè‘æj±A¾¬±?,K€¬'çÕjj›ÿÎ+€  Ì)h$XÁAËK‘c#e£%,u9AÑ÷.¿b @°„×õ|ß7šòÌÜL(¥ $Ü)„p.z€`ˆÒŒ91X€Ùµý¢WJ\“‹)ºEG¹§\t›tCû®[pJRà¡b4ª¹ä]yD4f¤GC‡€Ól_>wg²×k£’Y2g…ŒFe "v=ûåßvõ÷V‹Í~nîT©äP_­ë¥Ê¿¥k£àL™L (‚/‰Ø+8kŸÙÓ_þÑ“Ë~•ÄIcæYJÙŸßBßLùP ãáÌ™Ùñœí뻞 ÿå¥Ý¿ƒ(·¸™e[Ï,nÜázN~2KÛêéêmßÝ ÕÂ!b`C€£<Ì™3rýŠ}öêÕ§…qí}ýÑÇÿäz¨†ö{M¦µÜöíÊ×ç}¢z⬒$iX[“mÇîìØÝùã–¿üã¯õ ôæ07fJÛ”òÿZpê¼ /¼°Z­æ¹|1Imô½å/Ò4§Ø¡!jnnzü‘'VîºôÃMCÕÌ_9!‘a¯hïç‚ÛJÅ—L8Íw6½Ô·à÷þOþë¾<1ÓÖÚöOÑwƒøU§1ƒå ·Y¹©jŒªÒÜfe9Òólϲ•†mÏs,GzÍÊe™“ÌRƒÛ¬,Oú¾_*•2%5h/„H’Är”Û$eªrThŒ×¬¬‚ðìB´°gɜ̫ìíX^Ék*Ù¹øBöÀ-ºer…Û¬\-ór>‚׬”+ŽæŽux-_ MLœa`˜4×ï2çò„ˆ€˜™4gAM¤f¸Þ‡áX¬<0c²>“É1ËemØ00&'ü‰Ù€a cÀä¨8ã9Ò™ÆÕœëɻΌ`Ò²iþ»p²Ï²I¿¯ð~n´1÷U Æáš¡“¾ÔÁˆ'ûÉŒŽ™³8|"BÄ ÆTnz ªr\SN{ì±Ç.ºè¢%K–|ñ‹_RŽ6“¾¥Âãš27»ã8_úÒ—>ñ‰OüèG?ºÿþû‹Åâè·ò[*<® Ã0¼êª«Z[[7nÜ8{öì‹/¾xLbà·Tø Û¶—-[¶jÕª0 ÷îÝ;ÆÀö– w²,kÙ²eŸþô§ï¹çž¾¾¾Ç{ÌuÝÑé›-Þ›Œ²d–?ÿùÏo¹åD\´hÑÇ>ö±Z­öf΄ø&#!DßøÆ7>ûÙÏ2óÌ™3lj¢è-¾‘(ú̙3g$%bN&Ä,p˜(Ç9@ÌÃéIVž¸ÀX÷LeùLDÃöYꇿÈç5n9Š730pÃ`Êzw9‹C­[ü'nœ¹Õ2OeŸÌH÷ytÔSN©fvÛ÷ýBÑÏqÁh](ù¶m¹h|pâ†Õ@ØÛE˶íBÑ҂ʃlù¾ï8Žë9…’oX7žOˆ¨iÛv±PLòÌÜDT,=׳QyàÄ"•Ál‚+»ÅÌu‡Q–4²Ì†ˆõä,zo×¾çV?§S«ÂR¹´eë–=Nß†ŽŽJØØSÁÄŽoõìܺ~ßäRãd– ®gïØÚuxkV®ïèËMÛÙÜÔ¼w×~u¡Ê]‹ù*$ [º+»J¶lÊ-~ÇÄNÁÞг)}î„Þ¶Èh }¾ÊR}ú{;ÝU«VÖ‚ÇŠ!S*”vîܹ]-Û\;¢ì…Þxpj8ØýPm…R ¼L”Ö~½ßç?ÿ…(­åª°P(<öЯWéÁ÷~à¢SÍw6 §¶7zÿÇ.,•ý\g“‹Î–»_üíö›o½´_WeNå4nR>=G:'-êdT˜á%“ @mP‡cDɰ‘QR1vÚ›Ï`[I…ÂZ †+}ý½¹•Ó°R­$&ª@p üïkùlצV¿$QôÔ ŽÛlöT{g[¾tîM§·ž4hjaèéLµqòAcŒ6éÐà`àEPÔ5Á9Åïb;(Ôç‚u­´bÂ’¨ é qbgÒÌŠ#Jrµ—ÝzÆ­s¨(„D B(l<}IŠ,õ%’· „D!„’J)Ùø„`¥”$”À¿¿{ù³»7 WôÅ j&ª‘°pß`ÿ½Û~÷í%R ¢RR‚jœ), %ÊMJR‰¼b›,AR ¢ñ+Œ™‡GŠ„P¢±H‚È]ˆX(¤”YšÖ7Rå4V ê puYX‘bÃdƒƦ½ ){nÚ´©V«Í›7¯­­ÍóF1s³-Ô^è[¶oÝجî¼~‚€íC{ŸØâ*ûˆ±êÇ3eþÂ+V|ä#¹þúëüñB¡Ðœv\1ûÊý}ÿúµ];¤‡‡G0°b°VûÅÖe å›2¹”" Ã%K–Ü{ï½™›0ï,<îˆêºã::ê Dâƒ?}SöJ®V«Zëq£ßU(_Üræy³O6†”¬‡“ PÊJC4¥\þð©—j6¯vÍqDRʦ¦&¥Tsss©Tz• DÃTïk‹oîz\iývÏÚG¶?;d"‹ñ‚Y§}èÔËâ»<ÅiÐý¹5WÞˆ”E]lÙ²åž{î‰ãøßÿýßÛÚÚ.½ôÒ8ŽsÀiÇ !` žVžÅ†>yêû/Ûu>ülùäÖEï½U2°Á›6Ym–.¡««kåÊ•ï{ßûöîÝûÜsÏ]uÕUQ´9®U˜… rl°›µ´ÁŠT:³H!‚„7mâöÌ_¸téÒeË–i­•Rq¾ÊÉ,_kÊ./ŒB¦1Õªà_ƒÓã“2pZ­Vù¶!8 ˆ 0é Ð?!Ã$³l€¡†¶_0g)µÑÚ˜ÆÏp­Öš‰È€6š…`&™X g—?PU3¦!¾Ú0"ibfmŒ1šs lZS†92š¡¡}™ˆÉf& MÈ蜑’Ed˜³L™yb$ÍFQ®}{²à4dfOXMà‘29öY¤xްŠÒ-ƒ›JÓØÀæ€Ý'ÏõÊM%<™…bA « <©xØÅ¥ÅKpñ%† i/@X¤]Ûikk‹R'×Ì],ËMeO[Mà±2¹6lG¨¢rËà•‹©°‹Òq„U5£jÏêh^FEi ygõ¿ïŒ"Žr]0̶gmXÙFTlq'NèxÞùû¿»3ˆòÊ*1üªU«Ìö®mÏ&Ñpå4&†Ãrˆ˜š¤ýùÚßýýÿ›N"Ÿ™ë¹[6nëR;zt丈™Árä¦çöÁ÷Ÿ³=+œ lÙ·§²¯½ÿµ,ª%yÈ7°=¹éÙ½Þ›Žœ†]]]£zÀû÷ô&a:Ç3»¾Äš»Ð†û*¥.‡am2ÙB2ä*×…;2Ûµ¨:ÉúU¶m)v“h’#·`%¡nuqp¤J(KÄÁ䘻E{ê̶#¶QŒ­œ6{þL˜o4f6ÉÆ#výÉ´‰YdÏ3h1Œ›©w¢Î4®}d”£BDlkk“RQ†aæv·¥¥%ËÜW©TrÃ#[[[•R“ažY [ZZ Š¢ r{R.—³4ºqX7&bnYV©TBŒÔónÜÇq2^n㌚šš2±T«Õ£)ip8M87³ÉÁç>÷¹¥K—~ä#YµjUn¬•ï|ç;K—.ýæ7¿™ÅŒÛÝl²'Iòo|㪫®ºé¦›–-[6°3¦½RêÀ·ÝvÛ•W^y×]wžYuL{)å÷¿ÿýw¿ûÝ×_ý}÷ÝgY†Ûfï»wïΘßvÛm;wî´m{¢öDäºî /¼pã7^{íµ+V¬ÈíŒRê»ßýî;ßùÎÏ~ö³"âUÔb£í%sÏœ9ó¶Ûn[³f;ð…(ŠÆ „GÈÓÔÔôOÿôOwÜqǵ×^ûÝï~÷Î;ï,—ËM)544ÔÙÙyýõ×wuu}ô£ݳgϸ¹§Gw¦X,®_¿þÅ_l'„HÓtóæÍW\q…ëºú§úüóÏû¾?ng²%¸{÷î4Mo¸á†xàóŸÿüDµ3Êì–Åbñé§Ÿîììl0?`¸Œ¤¢Z­>ñÄc"_Žž&ÎÁ†˜¦éôéÓ?þñ¯^½º\.Ÿþù¾ïO´Ý!¢Öú¡‡:ÿüó¿ño¬Zµê±Çû«¿ú«Låc>’1okkûÞ÷¾×ÖÖÁwÜÑ —Ù’={öwÞùôÓOg;DƒöÙoüö·¿=uêÔ_üâ?üð¸! #ú‚`ñâÅW\qE±X|ôÑG‡††Hy$Sï©§žúàƒNòTþÊW¾Á~ô£‰ÖÀSŽ9ÑuÝ-[¶üõ_ÿu{{{¦¤RNÓ4IÏóÀó¼8ŽsOÏóî¾ûîoûÛwÜqÇܹsã¸QacL___Ç“,räyÞO<ñÉO~ò3ŸùÌÅ_\­V'w6'ˆèsŸûÜ /¼ðw÷wÙ =¡Ô„ˆã¸¿¿_k=I}T«ÕJ¥2Ì+¥Fg¡ã8»víš6mÚË/¿ü¡}è®»îêéé™èÈ’Ÿ.X°`óæÍ½½½6l˜;wn¹\“ac ÿþð‡·ÝvÛ7¿ùÍ~ô£ƒƒƒ¹ðÛ¶Å05h™M¾ÇüøÀÍ7ßüµ¯}­qUD$¢/~ñ‹?ùÉOþõ_ÿuÑ¢E ô Ãg­eYÙõu2 Q)¥”Ên¤¯îFš£Âööö÷¼ç=óçÏ¿ï¾û>ýéOO:u¢…•û¿ô¥/Ù¶}ê©§†aø•¯|åð¸Õæ–euwwë[ß"¢üàguÖ¶mÛ&ºdÙ½{÷…^ØÞÞþóŸÿüúë¯opfgá·¾õ­ìøY¸páo~ó›R©4n¡cL±X\±bÅ]wÝ¥”ºí¶Û®½öÚ,_ÑD§~¹\~øá‡¯ºê*øüç?ÿ•¯|¥¥¥e¢*$Ù~ðGôGYéÈ%K–¬[·n¢ƒùè3÷áDDýýýS¦LY°`A’$ ö,ÉM__ßöíÛçÍ›7uêÔï„lãݵkW’$Ù-éä“O>wÆÿ½3æ]ÿ)4Wûä²í¿“qÿ)4ÓößÓØ>d*“»CÔ\†)~V-í?ÕD9'ÿ&œMÎÙ„³ÉgšLÿÙ”ng“b3 `2ýgSºMÊ÷3žÚD³É›x69[ó~6)2Ùþs¤ÉöŠÄlòY&w‡P³É9šÔlrަӳšÁÍýgà=eºÌ;…¦Ó¼Sh:Í?„¦ÓÌOMÒ4ýgä:÷bÌÔšnó9î=¯é6Gäö3^œém?éíÜéï{¦Ó¼“1MÿÙÞÉòy'cš^ÑÜóâ¹×Ä&¼CÔ\†)6ÔdÍ óϵã{ÿý{5Õ|a³›z4Óf7ÿô¹Ÿ±š¯hvóOfÛ+þ£èaû˜Ê&Ï%tEXtdate:create2017-06-06T01:31:34+01:00¸'“W%tEXtdate:modify2017-06-06T01:31:34+01:00Éz+ëIEND®B`‚puzzles-20170606.272beef/icons/tents-ibase.png0000644000175000017500000000334413115373746017741 0ustar simonsimon‰PNG  IHDR¥¥ õÍègAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<qPLTEæææ³ÿ€¬ü{TÖ<¼µPÕ9bÜF%à ¸´%ÃcÜFPÔ9T×<¦úw¼¶³³´µøtÊ» IÒ4µÂÓ5Ì´ ¹ ˵̳¶÷s˵̵¹ #Á#²²²FFF LLL¸¸¸µ………¼¼¼¦¦¦½½½ÑÑѱ±±###kkkxxxpppâââ¾¾¾***ÆÆÆºººKÓ5µJÓ5§úw½ÐÐÐTTTJJJ­ü{W×>¼+Å,ÆV×=···(((wåU¶xæVRRR“““ÒÒÒBBBGGG«ûzgßJ!¢ ¯² ®hßJ«üz ¹¹¹™fttt444$$$```ɹ ÓÓÓccc222»»»ÉÉÉeee———dddzzzäääÔÔÔqqqßßßÿÿÿïË 8bKGDz8Õ…j oFFsŽþÃftIMEá"£Ý‡ vpAg@@MF™ãFIDATxÚíÚ÷WAðìE,Á‰ Ä*Å^P,( "ö®Ø;6lÑÿÞ»„ÛÛÝ0»7Ë.¼™xê½a?λ58ï›ËQQQQQQQQQQ!s_e° yYNJ?•ùU-«[Ö¬]Wh-¬ß°1üõ¦¼–Rݨlk/–ÂÚ})uD_ŠímÊ&ý&ÊÎ-²SººKéêî’)õûM”å­eÙ)•’X™R¿ß@ÙÙSíÙ&9¥UrJ«DiÐo ,o¯î(KN镜Ò+Qôë+ÃQTSè?Ïïì騕”&ýR×î={ûöí?Ð/U†£¨¦†=okÌb ~K3÷K•ƒñ§çÐA‰²>ŠÔ0¢ç’Ú¸¥™û¥ÊCƒ‡=ÆØq‰²>ŠÔ0¢ç•’¼*B¿úu<ÁØIQ97 ~LqCçoiæ~•ñÔðivfDT΂SÜÐù[š¹_<¾–ç΋·§1 nÑó £ÒCF/ý 奾96,(£à†=Ÿ(ÊîèÄx€Ð¯|-/_aìjZ™Erõç“צVO]_8ªx#üýÍÉ @èWßž[ŒÝN+£H#ñÞÝ)ÄçÜ-Üãß»LýRàýÃû1ö8¥äF‘Fò_š'O§Ÿ=1ýòU *û•w'¬×oRJn‰aðŸÓo£âþ$s¿Tùîý؇¾ŸFRw<5Š…a•æý¹Å«ñ]R£XPiÞ¯¡FÑL™¡_C)Œ¢1 ˜2C¿†r¦*ÖŒ†2C¿Î{©,è7î· ´ðœ”¤Êõò’ö—¤Ì¤Ìº¿\eÖýåÒ(ÁûK§JðþÒ©º¿t«„î/*¡ûK4åç/_‡û¦¥ï/Ñ”ßëžzJèþO9ûãç/]%t‰§ ë·®¸¿t¬î/+aûK×JØþÒµ´¿t¯Œ«ùþUù§VûËØ`­¦¯lº¿ÄUÎÎÿ¯èŸ¾2ûnce)ù"%)I¹TJ ÏIIJ¡\//iIJRz¦Tä+=S*ò•~)UùJ¿”ª|¥WJU¾]i²¿LŽR–¯ÄWšì/¹QJò•øJ“ý%7JI¾_™3ßÀ(ó•^)•ùJŸ”ê|¥OJu¾Ò#e³|¥?ÊÅó•ˆJÓý%$_‰§4Ý Âò•Ž•À|%–’/ð)À|¥[%4_éV ÍWºUBó•n•Ÿ“’”ËTézy Û_†Îe0KRZPÚËW"*-æ+•ó•ˆJ‹ùJD¥Å|%¢Òb¾Oi3_i¤ä÷—±Òj¾ÒHÉï/c¥Õ|¥‘’ß_ÆJ«ùJ#eŽÛÀÄJ«ùJ4¥Õ|%šÒj¾Mi5_‰¦´š¯ÄSÆe'_i¤ä÷—üOÁVò•FJ~3˜þYÝBöj+ÓEJR’GiAAJRj+]//aûËÅÿ.¶gEJR’’”¤\ùJ!é¥RÈ_z©ò—^*sé)IIÊ¥ò—^*¹ÍàÉÛ{âƒÒê%tEXtdate:create2017-06-06T01:31:15+01:00\uŸž%tEXtdate:modify2017-06-06T01:31:15+01:00-('"IEND®B`‚puzzles-20170606.272beef/icons/tents-base.png0000644000175000017500000001237413115373723017566 0ustar simonsimon‰PNG  IHDR@@Bò2ýbKGDÿÿÿ ½§“±IDATxœíÝmlTeÞÇñ«Ãtb;`†e ¶Ý¢¨#dc*,Y”–·/n_@1 ¦@–Ðu’†¤˜%;° Ý(ƒ1‹ÊSÁ&64€’  b±ÒTåA¥ ¶¥ÐBéÌtz¿8M­•–Îy˜9ÿ3ßÏ«ÉÐþçÊ5ü朞Îô— ™R½ú`@0 F€Á0 #À€`Œ‚`@0 F€Á0 #À€`é±~ƒßï·b€¶ú}ÌVJ¨6{¿z9¥šùÌ·ó|ë†ëÀ)4 Ós dÓ×þï÷§O¿éê»;Éýȼ)lwÖç׿ Þíì„<éüä¼0%Ðq¿ûLÛEíkJ§Îzõñùî4W¢×®”üõã!ºÃ½ÿøìßwB÷úúÃJ©öÞ;G®œMQ)j@û‚»áû?tµ^º¼§½÷α«_žnmü× Ëry¶t¥”üõÍÚSèÔ¾žÉ'þ/µ¯ÇÒGÁhLÙÿýÍõ]}=Úÿþ!Cÿû½gà7÷ôõ‡»úzö7×yhéëkœõÃéÔ¾ž¬N[ú()ûæzS8Ú¯ãÃÑþ3×›Œ<´ôõÇ…NíëñüÜ âÏ8 ´t·¯;µ«;Üë÷J_ÿëêêZZZz{{Ãáp[[ÛñãÇ-ZÔÔ¤ççmKü›—O á82kÿ¯ßFõ‚ú¢z®åJ_ÿØŠŠŠ¶lÙR__áÂ…£G+¥B¡ÐáÇuL³$À#^>5„ãÆ¬ý×}ýv8×r¥¯l¥¥¥¯¿þúSO=•——÷ÜsÏ-]ºT»ßåÒó¦óü€—O á¸0qÿͺÓéë¿H$ÒÜÜ\SS£”òz½ååå:†˜à¾|j8ljûoÖ5ؘæH_ÿ8Ç{lÁ‚MMM~¿ÿã?.,,Ô1Çäúò©á l1s÷ÿyÀ•jôͶ®ÔôyþÀ8¿XúúÇÏëõz<ƒoÒ ƒË—/onnÖ1Çäñò©á l)s÷ŌٙFÞÐïNuegd®œ±`œ_/}ýãwöìÙË—/744,Y²D)ÕÞÞ¾}ûvsÌ ðC^>5„-cúþgº<»ç¯¥h®Ï3)=5Íç™È.;î4×39C_¿øÞ=}æø> }ý:ø|¾ŠŠ íö•+WtL0óÓH}ùÔh/¢·Ÿù_ÊšýŸæZñä‚Oþz:¼¸«ñX$Ú?âi®´Ô´¿ÏZô—)OǺrôõSeeeYYY ÈÍÍ ƒÛ¶mÓî/((Ð1Í´ëåSx~nè™þBF–Yޏíÿ< Ä÷ø‰–†ºÏkÛ²T_šrGÔzÔKÏ¿ø×ü?e¤MÐ1SÉ_ÿø5ш;h÷?YbÒ÷_úúË„‹X7ÿçMãC ›ôý—¾þÄâÏÊB'ÿª½C¤¯_C3 #À€`)±–ÒŒ$G?ðXÐË|gÏ·n¸œB‚`@0s~ìàþU(ž_3!ÀÎî_ϯ™p íàþUú•£Ÿ_0!Àî_¥ßX9úùuìÔþUú5N}~Á„;µ•~cSŸ_g0`ö¯š‚~cSŸßêèèØ´iÓÂ… ý~¿ßï?pà€îi†lÏþUSÐo¬ýü&P[[ÛÞ½{ÏŸ? …ŒO3`{ö¯G¿±Æ©Ïoby½Þ5kÖìÙ³gõêÕÆ§ °=ûW£ßXãÔç7±òóó7oÞ¼xñbŸÏg|š¡Û¼Uú‡8òùuC¶sÿªnôqäóë0†lçþU}è7Îyϯó °ûWõ¡ßx8ç=¿ÎcðÚîý«1¡ßx‡=¿ŽdôɆý«ºÑoü{Nz~m"vuu)¥z{=~ïÞ½ÎÎN¥Tvvv¬ÓÌÿ»Ð ï_Õ‡~ãqúüÚGkkëœ9s†ßSUUUUU¥”ºzõªÛíŽiš%Ø=±ý«úÐo<~Ÿ_§¢™A©$ë§Ebåçç›øw-ù›XJÑO ±0ý´ŒÓO Á0ý´Œ‹XôÓB0 ìŒþUŒ†ç×8…#À€`Œ~` 6ôÅý±Ìwö|ë†ëÀ)4 ãJÑ ±0ý·ŒShúoõ£?9á0ý·úÑŸœp˜þ[èO¶Lÿ­Nô'ÛA²˜þ[}èOÖÍFýÀÒÑ«ýɺ٨X:úoõ¡?ÙõKGÿ­>ô'a£~`éè¿Õþd[IêÓ«ýɶ’Ô¦ÿ6Vô'ÛMR˜þÛXÑŸl7I`úocB² %û§‘è¿?ú“Ma÷~`éè¿} ú“Í" X:úoþd{"Àx8ú“MD?0âþdÛ"Àxú“íŒã!èO¶3Œ‡ ?Ùθˆ…‡ ?ÙÎð¨è¿…ýq F€Á0 ýÀ@lèKú]-}ü~¿Õó¥ï¿ôùÖ ×Sh@0 Æï€~ã¤E€Å£ß8™q -ýÆÉŒ‹G¿q2#ÀâÑoœÌ°xô'3,ýÆâÐŒAôKD?0Ño,ýÀD¿±DôcýÆ À‚Ño ,ýÆ À‚Ño ,ýÆàÓH²Ño,ýÀ ýÆ6G?0‚~ãäA€¸¢À  F€Á0 ã*´cÑoœ 8‚`@0 F?0ñýÀÒûoYÿÐ?lõþX7\N¡Á0 ˜ŒßÓ <€Ó ŒFÀ)4ý·Àh˜þ[`4Lÿ-0¦ÿÝLÿ-&‰úé¿…ó$Q?0ý·pž$ê¦ÿΓDýÀôßc³u€é¿ÆfëÓ ŒÍÖ¦ÿ›­Lÿ-06»‰þ[8L²÷Ó Ñè¦ÿ$2À€\ôD€Á0 #À€`‚¯BÓ p#À€`Œ~` 6âû¥÷ÇJï§•¾~éûcÝp8…#À€`æüXz/ëw6ï –ÞßËú¶ô¸pöþ˜p -½¿—õ;›³÷Ç„KïïeýÎæìý1!ÀÒû{Y¿³9{L°ôþ^ÖïlÎÞ£–ÞßËúÝŸlÃý±Q?°ôþ^Öïìþd{îú¥÷÷²~g÷'ÛslÔ,½¿—õ+!×Zõ±çþبXz/ë7wŽÝ$Ãþ °ôþ^Öoî»I†ý1`éý½¬_9º?9öÇP€¥÷÷²~g÷''Ãþ<…–ÝßËúÝŸœ ûcôCz/ëw6îÝû¥÷÷²~gKøþè–ÞßËúÍIû#¸™ˆ~`ƒ0 #À€`Ì«ÐÒû{Y¿³9c8‚`@0 F?0ñýÀÒû]¥÷ßJßéϯuÃuàŒ‚`@0 F€Á0 #À€`üM, ®Î;·k×®¦¦¦ŽŽŽH$’““SRRRYY9kÖ,Ó8qÕØØXWW×ÒÒÒÛÛ‡ÛÚÚŽ?¾hÑ¢¦&=ˆˆ«¢¢¢-[¶Ô××_¸páèÑ£ÅÅÅJ©P(tøðaÓ8…⪴´´´´T»——·téÒ­[·*¥\.=NHŒH$réÒ¥šš¥”×ë-//×1„ nݺ¥Ýöûýûöí+,,Ô1‡Ÿðz½Ï`éa0\¾|yss³Ž9H€³gÏ^¾|¹¡¡aÉ’%J©öööíÛ·ë˜C€„ñù|Úí+W®è˜ÀÏÀ@\UVV–••ÜÜÜ`0¸mÛ6íþ‚‚Ó0W'Ož}ýáÿ~úTð›®¾»“ÜÌ›Èvg}~ýÛàÝÎÞHÈ“>ÁÿHÎ S÷»Ï´]Ô¾¦tê¬WŸïNÓó§F‘<°åºÃ½ÿøìßwB÷úúÃJ©öÞ;G®œMQ)j@û‚»áû?tµ^º¼§½÷α«_žnmü× Ëry¶tاЖÛß\ßÕ×£¥wÈPz½gà7÷ôõ‡»úzö7×[¾>HF€-wæzS8Ú¯ãÃÑþ3×õôå y`ËÝ ßOÈ÷"`Ëeº2ò½HØZ}ýἌ‰))):¾7%%%Ï3qÄÏ®££cÓ¦M .,,,ôûý~¿ÿÀº§` u‡{×ÚÕÒÓ>âÕ8 ´t·¯;µ«;ÜkúÚ(mmm{÷î=þ|(2>[hðúsTÿ!´/ʵh§ñz½kÖ¬Ù³gÏêÕ«O#ÀÒ}ýy8®E;L~~þæÍ›/^ìóùŒO#À2ë2×¢1l!³®!s-£!ÀzÞp¥}³ª+5}ž?`Êzà<ØB+f,ÈÎÈ4òwª+;#såŒ&® NB€-”éòìž¿þ•¢¹>ϤôÔ4ŸgR »`ì<»Ó\Ïä }ýâ?þy÷üõ™|ž£àÓHÖšæZñä‚Oþz=¼¸«ñX$Ú?âi®´Ô´¿ÏZô—)OÇ}™ˆŸh4ÚÕÕ¥”êíüõþ½{÷:;;•RÙÙÙ±N#Àñ6Ï(ñ=~¢¥¡îóÚ¶,Õ—¦Üõ‡õÒó/þ5ÿOi½@X«µµuΜ9Ã頻ªªªªRJ]½zÕívÇ4'@Fú„……³Ÿýgíð;ý+g'j=‹q•ŸŸoâŸ%ä" #À€`Œ‚q:aüÿ©Nô G`@0 F€Áèbc«~à˜ À>8…#À€`Œ‚`@0 F€Á0 #À€`Œ‚`@0 fÉßÄ:wîÜ®]»ššš:::"‘HNNNIIIeeå¬Y³ÌzˆÛ·oïØ±£¶¶öÆ>úhYYÙ›o¾iÖg•OžSæwttìܹó믿þöÛoC¡RjÇŽË–-3e¸²~ýÒ÷ÇêùñdÉçß}÷]­¬i¸ &ÔÖÖ>ý´ Õ{===/¿üòwß}7üÎÉ“';vlÚ´iÆç¿öÚk'Nœq§Ïç«««3åÿèÅ‹_|ñÅá÷˜ûÈêõKß«çÇ“%§ÐEEE[¶l©¯¯¿páÂÑ£G‹‹‹•R¡PèðáæÌß¹s§–Þ•+W~ñÅ7nTJݸqcóæÍ¦ÌOKK[²dÉG}ÔÐÐpàÀÉ“'+¥nÞ¼ùÞ{ï™2ßëõ®Y³fÏž=«W¯6eàV¯_úþX=?ž,9….-----Õnçåå-]ºtëÖ­J)—KWýp~ø¡6­ººÚãñ¼ñÆû÷ïommýôÓOoß¾=qâDƒówîÜ94Äçó­[·®ººZ)õÓO?œ¬ÉÏÏ×^k®]»fÊÀ¬^¿ôý±z~_EE…vûÊ•+ÆN:577W)ÕÒÒ2ôÓ—vlOOOŸ9s¦ñ‡PJ}òÉ'¯¾úêíÛ·§L™räÈ‘¹sçš26n¬^¿ôýq K~®¬¬,++ ¹¹¹Á`pÛ¶mÚý¦Ì///ß½{w8®®®^¿~ýÁƒ¯_¿®”z饗Œ_‚VJ½ÿþû7nŒF£'N|ë­·îÞ½ûÕW_)¥²²²žxâ ãó£ÑhWW—vùçÞ½{J©ììlãó­^¿ôý±z~¬´UÛZk‹V´ý[;³w’jçDZ7»ûeßÌî) !ª"G¥uhQin[ÿÏÎÖEòÊù>ª¿x¢jÛ-x䲦´h-.é†/‘í1œ2TxH»‹$ÚCéŒuÄÞèêêÚóõX¬£³ eç.CÚ R£¨ÝfO-ŹطŸ³Á–•¶ÚŽà‡öqa½ªõö;veßÍ?hµ;Es‡‡äXþ¨•N§­cy–;~âdndhõô©Ó‘1ÅïLÁŒO ŸeÅ|:=™NïäSÓ¥s¹™AL"@‡L¹³s…0y©âááÒ‰÷s¦H;ª‡–sLJK¥“EGøàü…žÄE]Ñ —æf]I!Ý€ g™Ç*~t¹Â¼ýÓ¥Ré\±,*_©T’P”hÖ ÓÚšºzu~~ž•ùÄfv™¡:o{‚~zòª@Á…i.˜‹Ê’—ú,Ÿ¯-IÍ[^ª{Þ¢ç|¾¢‡lûi… ㌱š8:::º‡y‚1È4¦æEâb!ªª¤Ð¬ H+l( ê–u0á S@pÉ®FÃò‡ 9‡šï·®[­ÝyÐÀ&Æ€– ©«Ÿ7p G%_ ²"¸Âí:zÊ1hMÑnž(4K,ÃO‰ž/¿º@yYQ M€JÆo< €1^˜>vY b8iA “Š1Ôì"±MJG®Ù02TéZYŽ|=£É¾Wý¦Po/˜©€‡š·è8æ’S†7ë5Ï3½;_G4 B M@-10 ‚.ìjHêà’”jbPHlA´}ðͧ&ðÀ(Ga°?;%M iàÜÃ>ø6G=™åvÜìÕH« ×ø¡³Ð¬Œx;Qà!âŸ6>Ó°…™¹}¥Òð‘¢)Óò ÓªBÇͺZ“8ˆl;ì»ééé ,>°ãó-ç†GSwmÍ^³A–gfF@fL[JÕ¤r\ÇC MîšCõúà ³Tw<Çqj ðßêLÔ‡(¶\ó¬4:Yÿ÷÷î ™wp.%$àJe , nhÀèÜHc#üàpÙ0v s HOîÇŒUÜÆO²©1£«×J_O[}yL@ ¬F?KŒ'üºµöœ±ãþƒ‡“ÜOI ˆ+âF;hUÈRT»ùóJ!bSbý—_…®À/—‘a¿4ÐâÜñ¹GazŒV._ù­"<¬~‚Ç7;UAµ2ã3tP¯ÆÎõDòq²š¼“XC©.Û8Ì$—Õdµšxœ‘ÄE› ý=“É<¹˜yr·\wꎓ‚ü×AÌ?NÃBæôŸ²êÆB€ºùTDt]ö”U$N…£+#™¿`Öx6¶ŠÎ»7›÷Ýæs€ƒQu+Ž5È™éWkâ…¡HãQƒ‡Àæ–oÍØÂÓˆç(0ŒŒÄ_Èr~#„<¨äösU"­8ÜU”á•Åào£ @— s+!qÚËà~ù·/»‚ñŸ œèJvå’œ­ªAüÿ–%òªE ‰’‘*…HËÝ|´êÍ5¢*Êk^• ‘m_$üè_T¥íÓ¥U%m¿®¶}¬¼æ+Æ—0 g½€Õ#%tEXtdate:create2017-06-06T01:31:34+01:00¸'“W%tEXtdate:modify2017-06-06T01:31:34+01:00Éz+ëIEND®B`‚puzzles-20170606.272beef/icons/tents-48d4.png0000644000175000017500000000125213115373746017335 0ustar simonsimon‰PNG  IHDR00¥,ä´gAMA† 1è–_PLTEÿÿÿÀÀÀ€€€ÿÿÿ€€€´ý®>bKGDˆHtIMEá"£Ý‡»IDAT8Ë…TËNÃ0Œ{€«g ôʺî•ø€HùŠü qçÿOÌî:n \5²3ÞÇÌØ†ÿFº^æ!)8üÑ&·U‘"…üÉ âï‡ 0AµF'@2µµ %3bœP*×gh @ ìgà™”œ l> Ì܈Dçy¶Œ¹Ö|deŽ`šèj´vî ´v‹ráLµ´v7Ê­…ûª$((95‚ÁKº49¼}]×@„ÀÉ’Øf“¹Ml—4I™ºªè*ÕV#ð°Ø‘HKñôžVÃ(s‡UøWòí $3 úÙZYŽï©¤wegÁ–®æPWmn2OžOZ*'È]®D4}M¯,©¦½ûØS¹Qä`Ͱ+ñ®–“È7Θޚ¯T C’sÕÞÐ:Õ=­èÀRÜÔ¥Ýç.ÉŠ`ÚÕúêºn¬ÝÝ% ×p‚ò†«SôÁrŠ šín†$vzytÍbô;h‹{q• éÅM‹UD¯»D<åø" ËÉô3ä²K¤²ˆÛüˇÄË__›ã âÐU®«K|%tEXtdate:create2017-06-06T01:31:34+01:00¸'“W%tEXtdate:modify2017-06-06T01:31:34+01:00Éz+ëIEND®B`‚puzzles-20170606.272beef/icons/tents-48d24.png0000644000175000017500000000615313115373746017424 0ustar simonsimon‰PNG  IHDR00Ø`nÐgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEá"£Ý‡ oIDATXÃÍY[ŒÇu½÷VÕLÏc_\+r ñýpäБÄX+Bâ ´ÄNb'Hò ?1`øSBþõ!@€>"I'r`K¡E* %ŠÍ]’KqIîƒÜÝÙǼzº«êÞ|ôÌlÏ챑¨ÐhLߺ}ëô}œz .--Á©Ñÿ7€/< ~`aÄJ"‚½:zÊE ·{Úy ÌgúØ3H·’2ä³p»ˆH)òŽ»µ ”"ç˜e» •&FÛøÑ˜š€)rá?þôlnÀ"@€äåµzÿ—òy“UH‰È WãFu=ìÿR^ZúˆÞqm³14Z (“ŒdmkýÈèÓÇŸ £°™*ÌŒØá¶ƒÊIyÏÌè³#Æè¶+DÞ¿·÷¹Ç|çÒZXFD~¼odzìøÒù{“Ó“Þ3´,aX‰V>YÝó›ãÿtý|ÄûcSOê‘Õ ‹ ¤˜(S.—‹¢ˆ™»=”x5C¹€Š °¸úÏåCßàLNÄMµáÏ~öž÷ŒˆÂÒ—ËŸÞõ•¼î  àéúzßÜû›Ç_T ÕPfðÎÖÖßzž ;¹¾¾ò×'þ˜H‰H‚žˆªÕêìììääd"Ò xgR‹8&³2[¸þqvùªÃb5â,^öÌÙ¬13®ØúûËW2¤ÅÏ/„{O0€ìÍŽí âSç~2ö‡‡Á Ö¢ªÖ\ÊÏ_ ŹŸoÛË h0ñX¼¼ùáÕñ¿8"@÷á~¦Í DQ:t襗^ Èvï6N¾(íš–&ÓA j~8ƒß?S΋†°Ò¥§ÿH%Á""°V `TýåïV¹aÈtÑ›ˆc†††FwÙ !ÚÈÏö ö‘IÕ=ø¥ÛŸ,@NgI)ÌMÉ'–­JÞýÅTè™lS]a\Y_º¹N„.r˜Ñ˜áÿ¼«.­•Žó "Lc²Ö¶}³ ¼Y½ïØØ“§ÇV’úœ¤L?7ñsçVë[(˜;óØ)¥éø³“^|û ¨^‹ƒBæø3ûbqØ2 A—6û²n}jRh…B! ÃÞ<”ÌB’8<Å’!ý ¶ù·W&, rÁׇj"Iæ®Vù$š?E€Z4.1SJU*•Ë—/ýð_ÿeúÛ¿xï“UWî( ¾‡:ÜÕ/"¹\nfffvvvhhhzzº'16¯Ö‘‡¨ÿ9óÄÑhäÏö B¨#`ûjYÀ¶‘m9J—Ù$^ÃÃÃo¾ù&3§+_§Q;Ç6ö (±ðÖ[Ë1ÕüP?üN9 Ê…Îzg½eçìö²ŽZëc ÎZ×F4Zë²² *©²ö½#d ¹Ø/Ì®2Ymt »×VuF‰anX>~ÞòÝk«&Ðì:–QÝ.Ý(™¬r±oÊ´Q¥µÒ1ÿkØÉCÞ{"ê&Fà„‡ŽŽ8½ÛhÝU¢$xìëO4½í¢w#€µÞhuâÙý.µð% z-Êå³'ŸÞ³m¯A¯md:yHkÝ××W«ÕÒ­ Þ‹oᦛò´o´Öï¼óNµZ%¢žë¡f.&KñΖ,3ù…+……ùüò5,'ÊêIÆ""À¶!JÔº+…ˆ^{íµëׯçr¹Þ ´GÔ­ QñFaþ¢ pë’º ‚ÿÅq<11qøðájµšÎ¡îìÜs€0ƒ)~þ¡.—E©ÌújáÎG¢ƒ ÙñBçóN“"AÌÌÌ,..ÎÎÎÆqÜ]öÉ|D€Ds 2_ɯÍò@A”–lœ_¹ZÙó"•¼Òþ@" lÚ¡6;%jiYkGGGÏž=뜋¢¨°p5êÕH'"ØŠ€zT­ûÚÑ?Â&v[‹¡­7¢. kqÆ5Û°mÒÚ×k‘aI'"†aØs„@L 6“û<·Ø—ícfI’2övy®”ë˦vj‚„.vËs¥|–}ªh6jvéæz~ °Q.•ÖŽÄ®‹‡vî}›òìs¦ÿèÁcý§—~të½Ûåe…Š…ÇòCuð›àðØ³“A´ÖT'ŸÞïÄ·ŒJÂCù {òÔþ˜Û˽¶Ù¯›<„Ъüb±X­Vs;B†ÈâEürmýdz—"#¢ˆÂ7÷| "¶“¡eoÙÇ`§BF‹³âbp±XäfÄâTÊ5Ƙµµµ·ß~ûùçŸlcÚN4É™ìO.Gq¬³J4Y ÿv6‚€„Û ´~¤å€Û<Ô©ßÉDÌÁ[o½577×{£ˆˆ–ý—wïÉjc5­Ç‡† íuìñÑ Œ_±%U666611±±±±3©1tÑ3#‡~k÷oÌÝ¿ùÁësêÏ¿}`ò°ÿøæ-Bìà€æw H² j¦´¹¨Ù ÒÉ$ ݸq# ûwïö(ûäðF“bšÊŒìZ2ƒj@yp •JûA!i HO® ”2 ¥c?ª5èö*9ñÐøøøë¯¿îœKŠ¿+©Y*åšÝZ¯ië9¶?ü£(ëhó¾W*Õ­õZ‡ƒ\ì«åÆf¹æ­ï8ý¨Æ[•Êj}Í6ZU& µ^Û\m†~{ÂßÚÚBÄKXQ`ª°ºtáä…産á¶a%™èÖ¿ß}@lÚ¶ÑY¿¶P^¼QòŽ·™š¨ÖàÆî¢y¦aÃdã,Zë|©D:âí-Ф¼Ø2ÊñÔ¡Ç_8þ-Ìx‘$Š šƒMuwìÔ–†œ·Cf­WLÇ¿úDz=¤@oÕ78:üÂ×^¬ÅåæÁ”@²QüÅÌgž}1¦X,V*•<”´Ø»jXFö­qAP4Ç‘‹`5khB´ìbv °¾ƒ‡8ëmX ·êq%$Æéj£ÌÂÉÀ š¼ñÆgΜ±Övó*$B"TD­«ùHжQ"ï‘¢”RªuOGÇ{?88xîܹùùù4µ=„ìÁõÜаx DL‡Ì÷{ˆp{VW D ÛEŸ*õö¨ˆè½^]]M«aó$_•]Ù\/>Ôa…–ËóÙ1‡ ÒcKe½10’ÞÞL ¢sVÖŠcC9v]'TµZm×®]Éa™RªZ­^¸pallìĉí4Lýµ€Fëã2*ûW^ÍcáÎDÍÖÇ]äž”w{à¤$óù|¥=ê€P ×zè >ÌN—Ü{ß“‡R׫as;Ú££§úÃæ½ö•R]’/Ü_8@ÿüÚ¹ißXß×%tEXtdate:create2017-06-06T01:31:34+01:00¸'“W%tEXtdate:modify2017-06-06T01:31:34+01:00Éz+ëIEND®B`‚puzzles-20170606.272beef/icons/tents-32d8.png0000644000175000017500000000274413115373746017341 0ustar simonsimon‰PNG  IHDR D¤ŠÆgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<ïPLTEåååçèæçäìëêëêæìÏÏÎÑÏÏÚÔ×ÒÑÑÙÛØåßèÚâÕ‰¾e¢äužáq¥êvÈh•ÔkoÏRcÇI•ÙkœçyrÓReÉKƒÙ^¨¿–òòó™Õnºÿ‹»íd½ßM£Üsº³]ÙB³ÿ‰ÄßD©äyŠÜb­SÚ9¸Í ½½¼ÇÉ&Ê´µþ‚¦ázTÈ;/Â"ÖpÅÎ-]ÉB%­Șššš^^^”×qͬΧÅáFœån‡ñbG›sÙJ ösºðeÅÚ?ŒõgIžnÑEœûn‹‹‹ÁèRÃÑ1Ýq©íwÁÿ±¤:¸éx¾ì\ºÿ…ªÇ–×ßÒz®W›Ûn•Úr|°YŠÄc‚º]Ð_Ÿ·Ž²ý~®üz3Ê$„æ_¬üwcÎG>Ç,­­­(ľ•••†††Ž²èo³³³¥îzŽÌe£ÆVªòzŸémÙßÔ‡Áa’Ïj€·[¤âo–Ýgªîy¶øw¹öp­ÿˆ«È—ʸÊÕ0€¯a“ÒfãÝçªÎ‹jâH(¿¦÷u¦Í‡Á · Òa™Ê~8Ð$Ñ[›ÂKަ0Åÿ•–Ày¥Õa îl¥Á’˜¬ŒÉΞ˻¢¶•¯µ«Ã˼¼Æµ×äζǩôïùØÖÚÃÃÄ×רÍÒÉ·ë”Äû Á÷¬Ù޵á—ÿÿÿü¡QGbKGD¤Y¾z¹tIMEá"£Ý‡òIDAT8Ëm“ûWAÇwvÌDzn‚`€0tLHiQ*{š`¶ê*èlQV e%ö´RÓÞYZä«ÒúG»³@þÒ=ggîì|ÏwîýœŽûO Ä!˜øü„,°@Æ„òüäŒ]6š Ì&SIIÉ>“‘›!5—‚ WÛ¸¼B-R¥¼¿ªÊZaE±R®®©©=‚9”;œu®Z·ÛSïj¨kt6r{¼Í‡yNðù䆖VÒvÄëö¶û­¤é(¤g³3Rêê¶…Ÿ8Ù£œ u¶…Ïœ=w¾s8Øk8(}Ý‘hÿÅ¢\ ô5F$HÕA Ý P¨04¬)ÊÈhÌo‘‡Æã²U/ö 5Pª“HørGÇ¿N©‰NàW@¢éª×ã½æ§„ª Ö ¨Áœ0Š” ¥D¬¾î¹Qï`iØì7'íeÌA%D 8oÝî—Yê’`¤à ø’ˆ9Ä¢’”Jk©)QŠK’”I;àÇIÄ w㢦‰Ó÷,6‹vŸ¥±ôMœ¬Kp€#TÕ•u6Ζ:EIUU8 >3늄ÐRCÉD§$"JY‘ÁB:!þT ô$ZèBR ' ÔŒƒj‰> ´Ô)ëBÕ;qñz•>ÓüŠe46¢(€Z–µø´U–çX‘JôüÅËùùf¿Hél6Mô Ñ,4C1* .[|åõ.-gU8žÕ Š( )“ìJñ¯ß,¹Ûßfa_ê„XXê`¯±ØÿîýW–5›¯8¨qr¨ácϧ©Ä²–‰F£12òÌ‚$­|.¢ÆC_V×ÖV¿Ž¹4Í:ªAT|Ë}Ïå’¸€­ol hs5 |5DÛ–ÞÒ6lmÿ€Ç×7@‹×V¨Nõ9®”ff|\µPžc‚Ÿ¿vvwwðóg‹!0`‚ bo !Ìó˜ÇVq{ï²ø!ÞPèsùg]Pqü¿¬°D{yô(¨U¨¨ƒ¡%tEXtdate:create2017-06-06T01:31:34+01:00¸'“W%tEXtdate:modify2017-06-06T01:31:34+01:00Éz+ëIEND®B`‚puzzles-20170606.272beef/icons/tents-32d4.png0000644000175000017500000000107613115373746017332 0ustar simonsimon‰PNG  IHDR TgÇgAMA† 1è–_PLTEÿÿÿÀÀÀ€€€€€ÿÿÿ€€€x»`tbKGDˆHtIMEá"£Ý‡OIDAT(Ï%QArÜ0 £¢ä.˜ä¶3¹/c;wÇÞ½³Ú| ÍäÜÿŸ 9[#RÐR¤5i?k)hh¥ý¬MDžtVÛu^Í.òUßî«ïGJiâžv?¶éÑï­Ô}ûå¯÷~„à*Õ_;A·ÏÙ’º4‹®±fd)"Ͼé¼,°ž{ÐŽÞ/Jsƒ‚Ðøþغ#%rÙMÓˆ*õ)Üæœè${6ë0ÃÆ÷2òÑÑ|CÜ&Ûb„«È «‘ ÈËœ:%ù6Yš°û/[=ÃQê…Yø¼\Ý1â+õ^Æ-ÛÈòd‹6Î,eùòtEöA¡uÜÿl¦º¡“×ꕈcå1L™²Œ†¥)¯ BÕÉ£÷mÆlœ· *QÁa°l§®³ÓÇ„‹6©uLÍÆ‰P”8¤ŸQÉ)W~Pϯ° Ûq41êÿþoN å¶fFkf¯Ùk4ë[¿½¨Óéü߃ˆž¨Ë‰(ŠžŸ ƒ¨L ÿÅA˜8„à½ÿ’Däœ[YYyö}T‹È\á%Ðs1ª:ab"¤&OjÕæH3„ ¼23­Hïºßoýüðé±ò tD«÷·“F´h;½Ÿ;8õèõ·†¿ç‘B¨V«ȲŒˆ´ˆ°¢Ñƒ•íƒÑúM•m懾¡ò°ˆ•Ÿ.þ†-y~0þÖ7Û¯ŽO¶ïÅÛÒ#ßÒ6,»Ÿ-]1™'>?ü¦óAq]¿~=Žã¹¹9c —?ÄK°ÉÂ_«·þèЇÒ7WïK_H)8ü½³”{ëÀñÝO*Ÿ]õØ&ÜZû¢èZ¥4>}¼”ºBII’,//¿ÿþûI’ˆˆ@"!ªÔ¶nU;‹ä0²ü—Çüêw޾vnæôG—=÷õ¯¾|d¦¿ì«;‹õŸ‘‘æâŸVçßl¿ôÊÜôÕ_þjúܹùÙ™p#”z1ƘŸŸ·Öî©Úô²“óB¬83õjõ+Ó3ÉL}üe[º/ë‘éf'æ„µŠˆM'ÕSµÓ•™úø¼Ñ#=€ˆÈZ{éÒ¥J¥R3k"r^:·Ë씯‡ ²´ºð¸6TÙÝÈìoðZæu;÷6hö_= xãÞªŠÕöVÏŸ9CÛ…Y¿7ºÝàã„€R?Y–í©HD”æC/ŽnzëèHÇrÀUü/:¿ÛMSðÃSß>¡_8pj>@E:fŪÕvα¥ºÏ*Á ¥L•ReñòÞ/bb0kMZ¸'מ,ÜøçÝ¥ÝÕû«+,ß`EŠ˜•f­š™X1ƒY1+f&•K×ëõ+W®|üñÇF#„°@D²7 .ø¡¤zú…IÅÜ>0>9rÀz/À¾ÃsökP)EDwîÜaæŠM*‚*aAï.LÌ¿3ûµï½wòûßš8rûÖR í)ÐPš”&¥¡@ b  REY–Áðí«Ê`èΟu¶Q©“gž¹£}Ë{¯”Z[[³Ö‘.w&08À«8Î{*QÙÌK*ØJƒyDAD)E¬¡„ÀÄö ²†ûýþÅ‹‰(MSfÖ`Õ« ý8^'Çѱz¸¸Zm$ë‡Þö*Sxœ?¹ÿ˜ÈDÅêɃ«îNæŒgV…ï5·Z|lqïïÁ:ˆKdxöèìGÉÕ?<ü½tèèů©NÔ¼õDä\E¼oOïH)ŠbÝ:2l ÏĆ*ÒKÄ "ÂÌÌìœ#"-€bê#ûíÒµë›PXΞÌOŸiѬ9f""Z«H©À$@ E*ŠU…L ЖY€ÂPcøòåË.\èv»¼qçÚ#cõF-®ÄÇÆ&\ð ƒc ;@‚ È`ª4¨ÐZ‡nß¾]òNàE†Tõ'¯üøÎî‡Ý‡Þ¸ø£»wï¹"hÏ XA*“Ìš”†k¨€½oÍó|rr²Õj ’L ÛÝÝ`Ökã+Iý¡{´ÑÝ¢†J¸Ìw¡×ÍvvûƒèîNªá†8ã™Ø ™ƒDD ¢(Ο?_ʉˆ´’xK=äõñcŸž3ìqò)׊œ Äð.ô·óîFêÐ §›n:}û`¯e­#"çmw'ÊÂQY OQEáø‘ã¯NŸÏM@µR×'Gï:qDä\`ÇSÇ'ÊrÕÄéϦgÚí¶1¦dð-û™÷®ÌÁÂÂB³ÙlµZÎ9 @ …˲¢—»´¬ÊÜfÒ ‘ƒ'ƒÏ%ËÐDà\ú¹I3Ó·ÆQñÞ‘÷¾^¯_¿~½Z­¾ûî»›››Z"Tšµ€0©MêÐD8=äÞy" > Þ³£Á€TDÌy’T b"bH£1T&Ù9755µµµU¢‚:˜Ù‡§%“h ²ßΓÐÌäÉ>Û23sÙ1Š1³÷¾dâ‚{Š+ Hƒ ûi»ºO6ü[/]®ŽAB( ýŸ0|ºÈ—ôâÿÃøÎ5z >ÎÊ%tEXtdate:create2017-06-06T01:31:34+01:00¸'“W%tEXtdate:modify2017-06-06T01:31:34+01:00Éz+ëIEND®B`‚puzzles-20170606.272beef/icons/tents-16d8.png0000644000175000017500000000230713115373746017336 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<©PLTEçççëæîêãíêåîïçñóèôìæðêäîêäíëæïòçôðçóèçéæææåååßáݹ֦¼â«ºØ¥©Ñ˜œÑ²Òž»Ý¨¼àªµÓ¡žÑ‘£Ñ’×ÜÑéçêëëëÚàצëu¿Ý1±ïq7Å'¯nÚS½éV¾ãF†äe³¾ÌÛ¿ëçí¤¥£àààÙâÛ«Ûiɾ­Û]˜äo’ÎMœë{»Ë6ÃÄ&žêy†ÍLŠØUËÝÃêæì½¾¼ãããÙÞÖÙs¦òyŸÝrxÏV_ÎC‹Òb¤èw¤ìw—Öl¯í{£æpÇÖ½ëèíëëêÛà׬ë¹ÿƒµó‚@Ç.±xÙV½þ‡µÿ§éw·ÿ„¯úzËÚÀéæë¢£¢ÚßÖ¡àw­ø{ åtŸßm Ô]žâs§íw«óz›Ýo¬ô|£íqÈ×¾ìèîÓÔÒäää Þv«öyáq¡äs±ðršÝq¥ëu¨ðy™Únªñz¡êpêçíÜÜÛÚàÖ¼ÿ„ªó‚¶ßWÑÇ©êv´û‚¸ÿƒ§éx¹ÿ…°ú{éæì ¡ŸÚÞ×¢Üy­óyŸáv¢ÒY³ÓGšÔe¢év¦ìv—×l¨îyžænìéîäåäêáéoÈ[´WÆ?¯ò‚¬ÿ†Ÿãsªòy®÷|žár°ø€§ñuÉØ¿ÈÉÈæßç‹ÝlAÀyÜR³ö¸ÿ¦êw²ú¶ÿ‚¤és´ÿ|«úrÊÚ¾¨©§ÚÝÚ´Ó›ÈÚš²Õ”œÝq¨íy—Öm¢äu£êtŸÐ~ºá ¯Ú“ËÓÅëéìììëØáÒÏÕËîêøÓÖÒ§ót²ÿz êo¬úxªÿp»Û¦îãöáÝäÕÔÖ¶¶¶áäàÞâÛèèèßâÝÒëÁÖñÃÏè¿ÔíÂÓðÀ×ãÏççèãåâÆÆÆçæçèçèåæåéäíêåíææåææçìììÿÿÿwL›5bKGDâÆžtIMEá"£Ý‡IDATÓïþ   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijk\lmnopqrstuvhwxyNz{|}~€‚ƒY„…k†‡ˆ‰Š‹ŒŽ‘J’“”•–—˜™š›œžŸ ;¡¢£¤¥¦§¨©ª«¬­®w¯=°±²³´µ¶·¸¹º»¼½¾ ¿ÀÁÂÃÄÅÆÇÈÉÊËÌ ÍÎÏÐÑÒÓÔÕÖר-ÙkÚÛÜ×ÝÞßà á hTP½%tEXtdate:create2017-06-06T01:31:34+01:00¸'“W%tEXtdate:modify2017-06-06T01:31:34+01:00Éz+ëIEND®B`‚puzzles-20170606.272beef/icons/tents-16d4.png0000644000175000017500000000053413115373746017332 0ustar simonsimon‰PNG  IHDRíÝâRgAMA† 1è–_PLTEÿÿÿÀÀÀÿÿÿ€€€€€€NKI“bKGDˆHtIMEá"£Ý‡pIDAT׎Á Ã0 )ý‹4€a¤#íý'n;@÷_¢‚õŽ¢HÀp¸¦6¶Ç³Fܺô›%«GŽpó3ØüÄÆ¼”,¢}ŽŽl÷`’à5©¯Û‹í­²Û¡×qP¬?fjN˜¯L¯«•ø µ«k(%tEXtdate:create2017-06-06T01:31:34+01:00¸'“W%tEXtdate:modify2017-06-06T01:31:34+01:00Éz+ëIEND®B`‚puzzles-20170606.272beef/icons/tents-16d24.png0000644000175000017500000000164613115373746017421 0ustar simonsimon‰PNG  IHDR‘h6gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEá"£Ý‡ªIDAT(ÏÁKoUà{ν3sgîŒgì$NL‚uQZõ÷±ƒ*T* H]²€®ºãð`Ç`ņ}7%- T©•ÚEuÓ‚¥ÓšZuÓÄñxœyÜ{ßãñXqÀŽ‚‡R¬È‘ ˆx$¸ bÇÌ Êz1(þ”±Gy}Tå¹8éBš$VùÉšz®šŽé¡ÖZÕpýne¯7û½XýøÇçwŸLþþöÜÍ/b õôY{󻽟ÖMëNtgYlÜ»÷£¯)FåMçÑ«éàÖæ§_…§£öþ¦«éÚé+ß¿÷™2!£bæ^¯'¥TÂ63Šö¯Þ®ÞV÷£±Xœõû×…Õ$?»µ=¯ ;­ÁÀÅ ­uˆi'^J¢n7{\þõó«?Þó^7k/EÙ’Ñ0^Ž”’Dôëî.)f.Š•Ϫ¯×v¾I¶)ìNŽ¦Ê—óyéï¤:qŽ$ÊK—úÌŒB&&"gz~{cÅ6DDÎ19&GäXAÌ¡¥”(@ÄIØMÒi¯4£­¿¤‰—fI–F­4J[&ÍŒ”ÈÌ=tÎ)A°8®A×Å¡+stñöñä¨b¡¤8>\€‹²XµNJ¼q〙ì<=xyóÁ»ÿ=I¶ÎVçw¼´¥C©D¾Ž‚ЈHŽF£"¢%ÚXi_WOu—”r±h‚@iíkíûT`UèY ‡ÿXka°?,,õö›ÜTH"=”„"-„"@MD,£¨Œ Š3¢cA‘±€¢ØQ,àˆÃCç¡@”*M@)R%DJIH/·ßS÷ïEŽ—›{÷9ÎàøÞû¹ÿàrWö]g­½÷Y{}W¡.]º„~ÿ›ý[3ðûøwñUUk–~:ƒ¦¯ØxlÄg6›¢¨ßšI„RU5‚׫80ÆÆcŒúEô¿ž eY…Bá¿ùY…4MãÇGPÃ0ªªÂꊢhšVÅàä‹EEQŒˆƒ¦iŠ¢ŒOβ¬,ËF(1Æ&“ !$‚AÅŸdˆ16~ø%$$tîÜ9\æ—U¨ªªÕj=qâD^^^FF†®à0Æ4M{<³ÙÌ󼪪z E1 ÅÅÅœü§Ÿ~JOO·Ûídz …B²,;#“Såv»N§®J0ÆÇ•••aŒÛ¶m+I’‘?ñx——çñx†!?›Éd8pàÛo¿““ãõz ÌÀâ+,,¬®®¾ñÆLÎ²ì† FÍó<ù‘e9))é‘Gáý÷߯««cY‡¢(›6mš8q¢îbRUÕápìܹÓåreff’e®ªªÝnÿá‡fΜñQ$CŠ¢øýþ@  «B†aAƒ@@W…Š¢ƒAA`r‚”A¦Š¢¨ª …™8‚‚Á FlD…‚ Y–uU(I’$IðC ÐU¡ªª0¹Âù ue{4 ¶d8’!xcÁ«å a!DS4…(ÔüvçÒ~øeøä03BˆBMÑEiGPËÉ[ŽNZrÞrA¬g6ÂÙŽ`Fwò¨lkbѾWã¶%½ŠUŒ.«Š¡˜¨r‹©Â¨cÇÇÑí“| V@‹± )) ~†m¡û>prNžá)Dä@P &¿Z#*K¢M‰!Qý²¿%Fl™pšz—Ë–‹×ë•e9âÓpýa„­¬ÕĘ(Da„=¢GSgÔ¡oµ+XqðŽ…GÞ¸ñÆ2_™‰1Å:|À&œ7oÞõ×_?qâĽ{÷Â[:ÖÌ*V­œ5¿4ô¦Ñ×}ýÎK;­¬UÅ¿ÁÅ”B”Œå§==òë‘ /03fƒf¶ÁÁ0Ì[o½5tèÐ9sæx½^–ecͯbÕÊX—.»qã¹›r'm›ä•¼ Å´¨£B+ ¦„õÖ¿ýãÛÊ4„bM§ÙW.\?~|uuõ]wÝU[[Ëq\Tvael¯Ø>c׌ᭇßÖé6Žæ~ýa„)ŠÁevÕûë÷–íei–¼ðEQœNçš5kž}öÙÙ³gïÛ·oîܹV«5– 1Âî:|±ébwW÷á­‡[X‹ŠUÂáDR!FØÄ˜.ú..+XöÊàWc嬱æ¢(J–e§Ó¹bÅŠyóæåææ ‚@~ù³ûŹ/LŒéxýño+¿mïhÿ[mA«fƼ`À‚¾©}F¸º‡9MÓuuu¡Ž;¦¤¤ìÞ½»¡¡¼9Ž(aóÅÍÇë«X%³CR¡ŠU;gŸÿÃüö ¦Y”‹šŠ$Uçnd6›ß|óÍwÞygåÊ•ÉÉɱŒU Q Vü²? &¶Ÿx¢úÄœ½sx†¿Š²ûE#Bð2fiC&‚‘·ç{î¹çæ›ož5kV}}=Çq-ß…Ú`(& ô[ppòÁ—¼¼¶`íÖ²­NΩ}Q¾‚ðõ¢DET‘º£rÇcûCzýÇ×›Ä&–о‚0Æf³yÑ¢EsçÎ}íµ×† Ë-–È8šëèèhFæÛ:Þvmüµ B賈Ã/ùeU–UÙ-¸¯ÖAª©ê¥—^Úµk—ÃáèÒ¥KRRR,/…(AŠšŠŠáhQˆ¦èÝœ¡):(— Zrâæï弇(ôÆà7M‰Q7"82jkkßyç³Ù¼xñâþýûWUUź>Ó핼÷÷¸?3%³ÃšM ú/À_-Ùa Qã ['l¯Ø~Þs~ØWÚ„&Žæþ}fTUåyþÒ¥KãÇÏÊʪ¯¯_²d Áý/¯å§–÷ÿ²ÿŒÝ3ÆwŸ{M®WôÂÕ"êÐ910ÂÖÂPÌ€ä¦H·¥ ª@StË—˜£v»}ç΢(ʲÌ0LëÖ­ ©¤JÉæä £7œqŸimmhNôK~†b®®5¨;ÀvghæÁo¨X¥)ZVåxS¼¬ÊÿþK.ï:uúâ‹/¼^o§Nxžƒ4MlõÕׯ.õ•²4ÛÁÑAVe“<®ú‡¾ŠUUU9šë×YTD‚|Á(mß¾=j>@A ÐÃAMQTOWOQý’_»Sÿç…¨ÎqApš]ÅócœžžÎ0 øbÈž/°?;ÇuF…ä¢./²XôlË/SEQ”ˆ¯‘±,)EQ°0ÕCÛj~¿_û+˜<ñ€i¨ª'¨Xõ*^ QEÁæ2í¯È^üˆÉu]þð€ð/ܵµüJç­=&Æè̯ñá` …Bàu¢( &8\æaI‘\ù1…ÖˆõUÈ0ŒÃá`ƈ‹Öb±Øl6‡ÃAbÀmm³Ù,‹Ãá@-@˨ô ÃX­V‡ÃXØðù|v»LŒšßÙf³Ùápĺ³jC–ežçŠáyÞn·“¯Ið6±X,v»Ýˆ²‡Õj’enn›Í¦£B†aóóóu±1UU-Ë¡C‡ª«« V2 ³tÊÊÊTUÕ=I€ÞãñìÛ·¯±±‘ìÿÅó<_VVÖÔÔŒLÎ0Ì‘#GಔEIHH8wîœ$I7nlhhÐýUU9Hªž}ºsçÎݺu»Š!“E:uêüùóiiiYYY’$]]CAcA™¯,Ý–žŸ!a)–Ó•òòòÂÂBŽãúõëG8I…`ýøã·Þzkß¾}çÍ›×µk×P(dÿ¼ºCUU§ÓùÆo,]º´G‡ãÝwß5›ÍÆcÅ3Ûl¶Ã‡ß~ûíñññgΜ™;wîsÏ=çóùþ}¶1Â<ÍW*çîŸ{øÒá¼yŸå~Ö 4Är˜Á|óÍ7>>êþ—I™¢dYŽïܹó÷ß¿oß¾GyÄl6§Õaa–b-ŒER%«Ø5¿¼†™óÌ3Çýûœc„ŠñI¾¹ßÍ=]{𣹧¾jVÆ,–ŠÛ[ÐãñÌž=;55µ°°!är¹ÈQê$Bˆ~nnnmmmMMÍ;ï¼sË-·ø|>ð]ÝüY`LÓôš5k–/_îv»óóó¸ Œ ¸‡ñ먎”ÒÒRƒHEmmmEE…¢(º–= 555¥¥¥º`ÐÆ+--õûýäõa±X*++ëêêŒL*¬««+++Óus+Š"Š¢ÇãE±¬¬¬ººšl¦Âˬ®®îâÅ‹FÜÜv»½¦¦& ÅÇÇ“eÞ|}77zœ>}šà \YY@Œº.ŽãjjjÊÊÊN:¥»>€> ]¸pÁf³éÒó<ñâŦ¦&ƒ“3 SQQQ\\LæÔ¤\[[ÛÐÐ IRAAA}}½® UU­¨¨(**2?`±XJKKív;BˆìóâóçÏ·üè *ŠŸ——G^ø¨(QUµwïÞmÚ´ÑõšBrÚ©S§òòò ‚MÏ?ÿ|vvö°aÃŒ€MÕÕÕ¹¹¹dâËÏ̲¢(Ž;àx%\ѶlÙ …ÆŽ[__olRUuܸqºùªà2´Ùlœ¦ 6ÙíöÔÔÔO>ù„¤B„¢(ÇHrB²ª¼^¯.ä+Š¢Ïç ƒ^¯—ì1‚m!Š¢¢(@Àëõ’ÏF*ËMwrÔ|÷ …B^¯×H~¡ÃáHÁÈ»ÓÈ»!xž÷z½ºÉiªª†Ç%ÅT!cáqáö^8†B_9« â nµ( h„ +°´9ÃÑí—±6"ž<¦ '»br„5Û=|rx:  W! AÀL¢±­Ñ‡s ‚áb¡šÓÞ"”q,lF 57©6g„Ì5õ‡G‡„?I…-׬ÿLëž™q|œ‚/sà—üäÉM&“Ùl†eNÀÑôg±X ;U—ž¥XŽá@²‚"6(ŠŠ×R_u£‡hš-MÓ€KÇ¢‡¥ìäœ2–ŠQ±5ù-|¸\.8EQº€‰~6ö²e˺uë–““3xðà'Ÿ|’ì–¤)úÑýöû²ßðüáÿøé<ó¤eœ8qb̘1×]wÝ×_ít:ÉïpFoÞ¼¹k×®«V­"Ð+X±sö//|9xÃàÜM¹× ,l,´0‚iš~õÕW 0yòä³gÏ’´5þüÁƒ5ª°°0=F˜F´¨ˆÏüðÌ õƒnØxÖ²-fÆ‹0˜çÏŸ?hРÁƒ/_¾\÷´×qs‹¢8hРÇ{lÆŒÅÅÅpƒ‰™_ˆ(Q{'ô^6tYŠ)å/ßþ¥Ahˆ•襹µn¸á†’’’ªª*²}žÌóçÏÿõ¯…ˆC³åžòЦоI}ÿÐùíìí5úÆ‚•ºqãÆ_|ñ•W^á8òÙcí*È7[²dÉŠ+ž~úé‡zB£Ò«Xµóö}Uû–î_úBÿ’¸¤'ö<¡`%V¦ _’$=üðÃ}úôyâ‰'Nœ8aµZIÛ† ¸&öïßÿ±ÇKIIaæÁ$ؾ*R-ŒelÛ±ùò š &u›”lI–Ôè5EQ¡P¨gÏžsæÌ1™LÚ¹Aà‡çùgžy桇êÕ«Bˆ¼Q0ÆËÙ-öíåÛWYU¬‰•̓š½w¡ºº:ŒqAAAyyy¬ÅÊ0Œßïߺu«Ýn÷Ýw7lØ@@hŠH~Éýz´í±²he‘§èö·Ã.$÷/¼ð¬Y³Œr:äxFý0$Aêëë.\8~üø.]º 'Œ1„÷$[’[ÛZŸóœkšé–°â|>Ÿ¢(àè‰%b¸í¬]»öÈ‘#mÚ´)///..>þ|L)SŒGôÜÓõžSOl»±¤©dåé•vÞõøbÆãñLš4iÞ¼y+W®ôù|N`ɲ,ËK/½´mÛ¶%K–ÄÒ"Ƙ¥ÙÊ@¥Wò^ë¼6Å’rÖsÒbÉÂ*?øàƒÇüã?îÞ½;ù¾¡—å«(qqq;vì(..~øá‡É/mžá+•‡ëÏé1gdë‘K^ò_âi>– B*))ÁWWW_ºt)"B>r}Ð4ÏóO?ý´ÏçûöÛo>+Ò\vTìø±áÇsžs²,;MNÍË•¯×;nܸµk×2 Ó­[·6mÚDµh´LØÎ;ó<ß½{w(,D‹™5¼tðbíÅ'û<9²ÕÈ E¼’7*Ø„šÝ^o¾ùæ<ðè£öîÝ»¢¢‚ {éïB„Ð'Ÿ|2lذ®høršË‹G_ìñß=V¯||Èãã:• í[Àœ9~üø”)SâââÞ{ï½§Ÿ~:ÖZ†ðÑ£Gïß¿ÿÀíÚµ›={ö¤I“ÜnwÔ7"dížl8yÛŽÛþ°ë£Úº¿ûýÑ5b7z衇úôéS__ÿî»ïÀx¼ð ‹%+++##2è£J†¦h¿äwí¸a×øåÀ•gV>;äÙ8>.Öûì5kÖX,–Ï>û,''§  €\²@çR°Î’%Kìv;ùîIQ”¨Šé¶ôm7mkš¬œÕer¤@¬¬Ø‚}úôÙ»w/Ë²Š¢°,ë÷ûÉ!$IÒ¦M›8ŽkllŒeÊú\ßçæôœ#ªbª9UÂH­%3Z|Ɇ |>_jj*EQ„ü1¸EtêÔióæÍµµµ©©©à» äà¥ZR×宫 TYXK¢)Ñ/û£&øÁPeÆ ’$Á=Õf³ý2¼PÃ5ƒ3“’’Ào¤E‰(Ë4¢“,I*V «^ûB¶áë BW7 c å±tÝ~Ùocmvd‡{X„³"B÷Š¢@ô&$ÔµY8=蘢¨”””pú€éò}Q¢""„’-É*V=R±„»8Bv»=üšO¾TDÙ…-ŸP[b-‘¹–x¡ŠTEQ(DшÆ1ÐÄð߇—Šøö¨ØBHËr&ã…=ù‚QŸ+bfÄWKT5_1yse8}„ñç¢"†‹%*¬?„—¥jé&ÓQá¿€¶G þ—ñBHŽ1‚þ¢É/þ â…ðƒ.^nnàÄØÎ9Y漂Â΀]ˆKøÙ‚ÂJË8Qý~0ôx<-/—0[xlà…~¿ßãñ„«\ËÚ '–eðÂbÔŒò °Ž B€ôÂUaâÂüp8k xP>M£%…m @##T¨qk樆šL¦™klk2‡7жÄÿ¼ÃÊZý’? ÿœ /trNžæ)DIXòˆ†ÿ…c{áú‹‹‹ã8Îívk¦Z,¼Ðf³A*Œ×ëÕDkr«&Æäà!葱 õeÂ'×¾Ñd29NÜ\sÁëõ†Ãœx¡vN „|>_D:&VÅS“j<ÏÒ¬¨Š>égð(FÕdˆfãà,ÅúeH …ÕWaÄÀÛXÛ‘Ú#jd§fg%e$Ò~§(jKÙ–Ro©  ©–ÔñmÇ“K€?i÷îÝ/^7ndºÄ"¦iúðáÃÉÉÉ£FÒ {Áª•µ^ \ZõÓ*–bs¯ÉM4%F-à¯Þ .lß¾eYŽãœNç¨Q£ 2/*=˲.\Ø¿¿ªªÃ‡¿æško2@+·—o/÷—wtvÌi•‚%p†b$UúüÜç5Áša­‡u‹ï’IÙÄ€|¬ÄñqŸýì‘ï”:hññÅï}wBû ÑÕ9„æ(îåÃ/W‡ªÛƵmoo?¾íxÒüŠâp8Ž?>yòd–e‡ ât: ·{EQ–/_¾iÓ¦ôôôn¸„LaÕÂZ  §~35ÕASt¢9qBû ^ÑÛ’s8ZËËË?øàƒøøøââb—Ë5räÈX>6زÏ=÷ÜùóçžþùÍ›7wìØ1 µ4v 8eqSñÛoÛ9ûî²Ý3{Ì|sð›MbStblfÍwíºëhíÑ̤Ìg=³qìÆA©ƒ¼‚7ÖÃêE Ñìú³ë¯±\³kÒ®4KÚ{ïш֭‰Ä2¬Ë亹ÃÍ&ÆDÀ6!†åÙgŸ0a‚.° *\½zõÿøGðÃ(Á¹üöoS*5¾Ýøº?Û&7Vi"š¦ý~ÿàÁƒ?¾cÇ—Ë5a„V­ZÅ2³!OáÅ_!‡äJ%ÏÄ(£GÓ@`÷îÝ_~ùåìÙ³BsæÌ!g*A,¥Óéä8.%%…€òÃqÄÓ|[{ÛÍ·lÔzÐÎÒE–?äú,_¾|„ Ñ`QÈ_Ÿ2eŠ$I{÷î‹‹#ÜŒŠq‹î;;ßé»×70uàsž“°µ2/T‡læœ÷TÖSuw׬:øéOŸÆ›âÿÅb–*Ví¬}[ù¶¹æ.:¶ètÓé?gþYV£Gýb„Yšõˆžá_ óŘ»¶ßÕ­u· =rôå ö÷Â… _xá…ÜÜ\„Д)SÈZáyþñÇÿì³Ï&L˜@ÖÁ(¿§Û=e¾²I_L:Z{t|ÇñÇ,³±ëÖ­+((x衇tc*-ËìÙ³÷ìÙÃq\^^Þ¦M›[23Vœ#¿4äW#§l›ò]åw}SûBT”ò߈+º‹«ËªâUwî¼aÔÞÑ>2Cç¢*(B†+£ObŸz" =}’/z%DDIª”dNúkÿ¿¨>0¼ÕðÉ&;9§ Ä,²«ªêˆ#GŸ>}Zµj5eÊ23€ ÜvÛmv»½©©‰ÈËPŒWôNl71!7a[ù¶O®ÿ$·M.@QUþ?“ÉôꫯfeeéÂj‚ Lš4©ÿþж!%%%V<;’:¤.T× 4¼?üýqmÇ ŠÓVB˜¡˜5£Ö¬=¿¶:XSþVC¼’—pUˆ( K©ÖÔçú=G!Ê+yu‹b„Ç^3vJû)2–=¢"Ž/-ˆ$NOOŸ7o^CC˜£±èeYž3gŽ.Bœ<Á”÷Ëþa­‡m;6(ÉF€—cÆŒáy¾±±Q×%+IÒwÞɲ,ÜÝnw(Šªuaº-ý‰Ì'ŠTÁ+z¡Ë@,{BTÅx>~nï¹p/¤ì—UB„»­Æ(‹URBˆ¦hšŠJZ"&MBS#nD1†Oþî<ˆ¢'-Ášˆù!< ~Ž oIL!Ê+zÝ‚›¢(í݃›Ë,¶ä\*á‡y8™öWðQCCƒö³æ%ˆ ×S…€€ç?F‘Äá2—T©&PsY>!CÒ4 –¡®Ôb±dµZÉUüps-žçáònl2™LV«•œµo&³Ù _A&FÍ·@ 6â#…ä1€,‹)ÏóäP‰pB0´®ÌXßG çIaa¡Áä´²²2³Ùìv»u“Ó8Ž«¬¬¼xñbAA‘²'<Ï ‚PRR’ ›œf6›Ï;W___XXh$óa˜²²²Ó§Oëf6)ŠR_____/ŠbQQQMM‘ä´òòòS§Nìl6Û… À{n$9íìÙ³-?Šts˲\]]­ 6aŒ}>_SS”ï7’œVWW×ÔÔT]]­‹=dK½î¯¯¯oll¬ªª2˜œæv»kjjŒ¨¼í’$UUUé‚Mps…É &§566B&¥‘ä´úúú–E‚MN§óÆo46A@Tff¦ñÎi§NÊÍÍ56™L&»ÝÞ¿]üž­°°°ªªÊàäÇy½Þ‘#GÉlJHHX¿~½ #FŒ06Q£FìœÆ0ŒËåÊÊÊ2Ò9->>þÃ?$©ÅHNÓCÂgăAŸÏ‘œ.-ÂEKN<(b-kà”6ƒ–œÖ?j©Y–Ã3ߌ@¾ÀyÔw¡kƒˆ` sU‡Ûº„ä´1j€Ïóº2â¨)2†’Ó ‰xÚX`S8ßáàQÔä4¸_r4§¨ Fn,˜˜œÖR%® áéÂÁ¦+> ó›’Ó®XsèŠP¥¨<€§%¿Á/ Éið_h4ÎLË'Ò/Ý –˜n(œ6´záú/„-¬ÅÆÚ$U²°+kýÏ7©ˆàÇÌšU¤a#¬`E¹ —&F§Ó 1Ný­K Û ^‘ÑÁ¦ªf³ùÌ™3¹¹¹=zôX±b´qõÅ<Ï———ggg÷íÛwèС,..Že^«X5Ñ¦Ó§ó¶æ Ù0d̦1Gꎲ¶~í!«²ËäZV°ìšÕ×l¸°Ðc|fïz¯ß—ýÆl3â«åþòX®`Ôl½¯_¿>''gÈ!k}CŒÌÚµkA€Ð·…¼t2› ¸¡áö‹QØõIII/¿üòŠ+:wîÚ¶mËÒ¬­U§W¯<þõد/6]üðä‡Vî·i~§`%Þ¿»b÷ŠÓ+TY­ Ô’-†fª|Uª¤ŽH1·÷Üt[z¬L¸Ï>}úþûï;vì|——˛۠¶¶vÖ¬Y7ß|ó[o½õÌ3Ï:tˆ\o_G…PåñÖ[o…µ ”«ªÅb™0aÂàÁƒ=:sæLBddmMï:Ýn³ßÿíý*«ÞqwHýç»@¥B¯è]x|á[Ùoµr´2sfòy ªªÓìL´'n,Ýøòñ—Ë}å<ÍG¥‡këþýûAØ·oßÿøÇ“'O¼»ðj·ÙlGÝ¿?BèĉdËÙ@ Êæ²2àG C1Ý>ú¨©©é®»î"×diöûêïMŒiF—ñ|üîÊݱò}~Õ¡b5ÞÿÑé*Üåòº`ÝžÊ=ç<çLŒ)*3 Åx$Ï™OÜR°uÜֲƲu%ëbe¾i2D=ùä“3f̘;wnuuuT­Àžq¹\ëÖ­³ÛíÕÕÕFø×Q! zû÷ïE±´´ôøñãäbÇù|¾wÞygúôé‹@Ê@§™åQ×~¯òß•GÑ¿A™L„¤J)¶”xküŠ¢ª¢®9\î/'d™Ó½¢hÅ—%_n,݈d”fKSÔè·@ÐJff&BÂìl6aWAf“×ë]°`AÛ¶miš6l¹ù†Nagpê<ðÀñññûöí{öÙgW­Z«Ö*8víÚ%IÒƒ>Hv”Pˆ É¡Çû?þäÁ'¯œjI]0` _åöFC1^É;¥ý”;:Ý!( CþÜóÏCR‡Ôk¢žêùV¬^~z¹¢*ö{ðækoŽ•DÓ´Ïçëß¿ÿ¢E‹æÏŸo6›—/_Nð‚í³mÛ¶þóŸ‡RD}>A’:Å,C¡PÇŽ¿ÿþûËr§(x·€ø¾}û;vŒaòÚ ’^ ½¶Ü´Å'ùl¬ !T‚òŸ“a]»ÆïBA•€¨ø6pþÒu/=Óç©6ÖäB ¡Pèᇾçž{†áy1±2ß‚Áà_ÿú×§žzÊl6³, ^ß=¿FøáI–/œ¥!#H(Då Bˆ£¹ Ô®ö¿Éв״ê0äá=¹E·gLÍ -,t]Ä€>†B!UUuSô‹Y¢hjk‰Ï…cl-Ÿ!ÒC)êå†òá0!І¶áŸêG<’]Áj,É·P“áŸÿ*Ïš'(<ó-‚™pz-TœÌ-Šê`cYðhÂ6ü R¶ÀÓ¨›Y^0¹n/ØÊ09Çqdÿ/pÂ0Œö-djœèâ… ð±½n/pÅÄH>‡@†ábÑ}̨ßæ´Å˜eÙ¦¦¦ 6©„h6›9RYY™  6±,[WWWQQ!Š¢‘6P¢zïÞ½µµµº@šÉd*++s»Ý^¯× ØôÃ?ˆ¢h¤¢Ëå:{ö¬,Ëk×®mll$Ÿ6;v 5o#² -KAAÍf;þ¼nj‘Åb)..Ž"«ð¯—e9..nôèÑFÊèAgÁ=z¤¥¥éœVVVV\\I}F·b'VÁ03æ 6|_ý}÷øîS:L‰yŽš´ÒÒÒM›6555 :4''‡ðJ‡3ê£>*++ ƒ]ºt¹ãŽ;bUÖ„€ZŒñßú{qSñ”S22¡Ú A%?þøc~~¾ÝnŸ:u*´sEÌóü™3g¶nÝ*IÒ-·ÜB=«jÈ/Í73fžæS,)Ó®FZÓ­¨Êâã‹S,)7_{³¤’¢ËôbXÓ©¦SßV~{ÑwqÆÖË —9y íÅ£/ÎùnÆø`ÍÁËÔÑT¨(ŠÝn_½zõ矾wïÞÉ“'ççç;ލx$ËŠ¢¼õÖ[›7o...®¨¨Ð‰÷b­Ozzþó+üã6;RwÄÊFG²4XtäÈ‘gÏž]·nÝĉŠzpAñ‰ƒ~þùç .,++#›E,Åօ꾯þþDÉ׼þIÁ'ÃAÉÝèbT•x>~Yá²;|zêSBõ?}BZÌÈ´‘K‡,ÒaŠÍfsðŽXÓa„MŒ©Â_ñQáGÙ©ÙÉ–ä»»ÜÝÊÒJTŨç˲n·û8xðà¦M›B?ýô“®•5{DQ0`»ÏMÑ‚*ì(ÝqcÚ+G¬ô þÿ>÷ßÖBÈ”ãyÞápŒ5ªÿþ•„bvBÜ}÷Ý÷÷¿ÿéÜ‚ sÛäš|hŰ,ÏÞÕã.;kU QÁŠËäÚ|qóžK{Æöë§ü ­céxzT¬ZËgç>›½o6Gs}ûÄR Ƙ¥Øê`µOñ•ÊŽÔóÕ˜£õGm¬P© ºqßÿýiiiøÃ ‚GTÍÁF|öÙg_y嚦ïºë®ªªªXi1*V9Š{8ëá/K¿¸n ÅPÑ£âè%(HOO8pàóÏ?ÿÏþóÆo$çþÐØØˆÂÒÿc#* DE|ãÇ7xŠŸzíTä‰z¤CjQ“Ø´àÈ‚ùýæ§XRrûÊ諥ؚ`ÍÓYO×Þ]kclKŽ,á™è• )ŠR°’lIF º½ÓíŸýL•ÔsçàЈªrp…ßqÇ………ûöík×®ù](Šâ¨Q£¦M›6uêT†‹E@St@ÜÛõÞ3ÓÏ|4ü#mkko«Š+Üq·nÝúÍ7ßœzýõ×/\¸@¨ž —Ë…r:äØm8ŸšÄ¦UÅ«ftŸ‘bI!lm*ñ–7ÏÞ7ûË’/Ï4žyñè‹„——Ž ¡<òEd~‘™½>»Â_1²ÝÈX[ŠB” mlmföœ¹øøâ¡_ m›Ô6;-;Vz#”É\²dÉ×_Íqܘ1c/^ Õ±[ƒ{©ºº:;;{àÀ<òÈØ±c;tèËoåå§—ß¾ãöûvß×ÚÞúžn÷xEoT<ˆjnMåp8&NœøÔSOõêÕËårÅ Q‡hÛÕ«WOŸ>a˜»îº 2¼cíZ«Îñá©›‚M÷u»Ï+yýl„ó¿­½íÚܵËs–gÅg¥™Óîè|ÁC:`EäÀmo»ÆvMP¾2ð•¾I}}’Òã¢Òû%ÿË^™6²2PySÛ›R-©A9uÅ1 nºé¦N:A¥”>}úČҠiA®½öÚ?üðäÉ“<òÈõ×_¯) *'A%xÓ57™³µ½f¬ƒs\N k±èÞ½û®]»víÚe³Ùrss-K,#“¦iI’:tè0sæÌäääÚÚÚÎ;.!Ÿ–‘±fôšÖ–Ö±êKÃ2§uŽ•±*ý·èîèìè}ÿj~!¢d,§ÛÒïív/è  Èò¹ŒUqB» ͹E7ÄÂD=Žz0`À°aÃP3N@áø2dÈõ×_/I’×ë%d²A²c[{Û9=æ@ñAÐ_Ì'¥¨P(Ô®]»9sæÀ½à2Îûö훓“#Ë2˲@€à£%¨Â˜kÆ „¼¢×H 0¿ä÷JÞÁ©ƒ¡¼1C6A3wí›(à|(¬Œ Bú¼CéÀz„PT‡®¬ÖÃ0 D–±ö´n·òùÂ4@îú¦¦&­t$?Dkœ‡ãy`'+*!¡° /á}í¡ ƒFìõzÁ·Î9Ü|€“ˆ·cƒÔ 5Æy„vݲþDEªF¬£B¸n'%%éÖ‹—]BBBjjj«V­Œ ¢(ÖÖÖ&&&:]ÌÜŒIII à¾!¬YŽãêëë¡ç)™X›ÜårµnÝÚHóÙl·ÛY–5›Í­[·6â#u¹\iiiFþð<Ÿ˜˜˜ +sxÌ”””(NÉ+<òˆ® á"uîܹ¤¤$r”# (›ØÐаeË2¬¡ÑWTT,Y²ÄHÎ ¨Ðï÷¯_¿ÞÈä4MŸ={vûöíºÊ0aÇŽŠ¢<þøãF2ß0Æ%%%»wïÆzá#€c2™Œ”"â–E®)UU¡0¤î×ÃÙ"Š¢ º*„»Ô³4RR˜\W…ТN’$]b«é I¿pÖ…B!#‚1NŒ¨7W„AW…@Üò£+ðBè‡úþûïÃtdÔžçù7fee¥§§“€èÊÊÊ å1Tx!#„X–=xðà¼yó D¦‡ûFQQQUUÕˆ#ÈÄ3k×®?~¼.^(I’Ùl~üñÇC¡Ð²eËB¡nfEQòóóo¾ùf#¨=Ïó{÷îu¹\={ö„ÞAäÇ<~üøôéÓcª5;êêêZæj6£Ýnohh€(ý–k?<ß ŽèêêjȘ8Ž~ŽF sí›L&ड¡!²¸á•œä[SSøÊ´7Ô|ð666VVVFà…-9È×çó ‚ …" ßNPó»°¡¡áÒ¥K*l™Éù…uuu²,G'„s¿ÔúU¶Ô.)v&|½@ò»vÀ £}D”OˆCE—A2-\¥eÖXÃ> §‡ÃlÍò$LæxýÃÓ€ˆ#„Çf¸Y Ä4MkÀ²&øF8Ü´JˆÛ+‰F4D5B·Ÿpr~†/‹FÜR…†‚þâââ|>_}}½î›Øåi¾IlòK:ýÁÀ-R___SSSSS£û2`¶¾ v»|ÒRBu¡:réË‚ iEQjkkargÄØn·C‚5¹•&„Pm°#lãld´cÜØØ'¹0ËeÎuy…†ž#FŒÈÍÍýàƒ þu,zY•]¼k]ɺ.ÿèòÊñW|̲g6}óÍ7ýû÷Ÿ6mÚˆ#¾ÿþ{¨Ä•n`>úè°aÃrrrÖ®]k³Ùb™QàÜ|qsö†ì̵™{ªöØ9{,N`_ÖÖÖæåå1bÀ€+V¬ÐÍûüóχ:zôè›nº‰PFOŪµª94pýÀ_°nÀŽŠVÆ+‡\ES§N½îºëFÕ£G;w’e®ãät:¿úê«×_ý/ùËÇ<~üxBŒ¶ŠU;g/l,\úãR›ÙVªGÄ`½¢(×]wÝ“O>9xðàX>Ð÷ž={>þøãüüü3f<ôÐCuuu±‚_hŠÉ¡^ ½]·H’$rÂ,“É´hÑ¢={ö$&&~üñÇäh Žã>øàƒk®¹fË–-‡Þ½{7¡¹ ¾O÷yzëM[i•~ãÈ1ý8`äÒ¥KwîÜ9iÒ$„Pff&ÙÖO‹9pàBhåʕӦMÛ¿?©ùEQˆšxþ¼þó¶ˆ(dãl„a¼Ø«W¯¢¢¢¿üå/ß|óM¬µfBBBBè7ÞøöÛoA¸xñb,“lã:^—|¢~®“kˆ¢˜ššª(ʤI“Š‹‹gÍšÅq!LUÕ?ÿùÏ'OžÌËËëÚµë¤I“ ‚J0Õñ@·’ÍÉ~Éß;µw,\“yfff=¶mÛvË-·ddd#+ õlB}ñÅ&Lxþùç¡pjKÁ)XqrÎoÊ¿ùîâw……§O­;º³|§µ)(Ê!m˜&L˜pèÐ!hôzõêX…x¡dhÿþý7nܘœœÜ¶m[„î•cÌÒ,¢ƒsØX–Ïž=/^|Ýu×}úé§„’§4M˲¼fÍš~ýú-]ºü„S<×?6ü8ü«ác;Œ}sÈ›àöŒÅ „¯[·îìÙ³³fÍÒ­>¢ß9mÈ!¡ï¾ûîüùóiii±œR—ËèY’rÚåüPóC ¨ó×Õ„jXšºàÀJ^¹rå‚ Þzë­ÒÒÒž={\P¹¦¢¢bÚ´i§OŸÎÌÌìÚµk¬¨b°e.ú.®¿°ÉhWÅ®µbå »íàÁƒ«V­2›Í@àâÅ‹$:E)ŠR\\ a·õõõ%%%±â à-j*ºn¨*©Ù­²×•¬CWÞs¢.‘×_}ĈýúõÓ­´Dú ¼b7ÝtÓ‹/¾¸páBžçß{ï½X½"áÄèéêù٨϶޴utûÑö|ð–ko!¬8ŒqRRR~~þòåËï»ï¾¹sçÆ:Žàì2™L[·n½ûî»[µjµjÕ*Ø:„ £~\V¸l@ú€Íå›×—¬'ÄÀÙ¸qãœ9s ¶ Tˆˆ•?Æ0ÌÒ¥KUU9sæm·Ý6kÖ¬X=ÜB,ÍVø+Rì)­œ­[ôùùϣ–ړšL¦3g΂ðè£ê:Z‘n"ØýþóŸçÌ™£õ)Ž•+UÿQp‹î÷†¾§"µ*PÅÒÑ—'œS§N½õÖ[²ñûý±Ö>ü’ã¸?þœ@€¡)ƒ7¦ß8~êx¸‡Éªì–ÜQ‹YΕ™™¹cÇI’àŠ†!lÈ![¶l"m@ fhŠöI¾œV9G§U°PkH‰Y.žžž¾oß>¨§£ïµ×U2B¨©©‰¾²[xLš{Sª€ÂºÇbzÀ~ŠUÄ_cÇCQ<˜NÉID)Xù¹¥7E:»À¹Dz¡Ç¤(hAà‡uNS°â“ša["'ÚüÁ`éÅVÁÐN.±,n®¸ÓòSªyD•c8½F^;GsІ?y¬ÉA²-+E<¼ŽS„à"(QXÎXøäÏþ_ó¨U [Êäçé-TþuQ•á˜*Ç¿‘~C@?]ºð&zC%…0Ö¼Jº•ÔøM[èÉ6­öíÚ·èn ƒ2Ñ(5b23%I…à¤p»Ý›6m"'J¡æú$GŽ©­­u¹\ºH…fOB‰2ƒ•îöïßßØØ¨["J¹Ýî@ `dr†aŽ;Q=6– ].WII‰$Iùùù F’] ¨„.Ø2,,,„² ºÉif³ù§Ÿ~"©¼Øñññ'N4X ‘a˜^½zIN3™L/^,**7nœÁJˆ¯¾úêСC‡j$9íÔ©S555£F2X !”››k¤¤lZZÚîÝ»A¸ùæ›/]ºdµg&//Ï`Û­¸¸8—ËÕ»wo#m·>¬Ÿœ~bñÂðZkäƒW;œµCƒ,bÔœ_©5dADœHdÁiÌ€¬Éœk‡­&òbj¯]¼0â}AÆ c½&¢€M¯b- + ÇVÕŠEÙ·‹P + ËÜІŒe„K_qÞ hnΔ RòäQE×’yŒ0Ô@Í%Î#&Œ˜¼ešAnzÉiÍ-ÅÀì†~bFtök Œ±ÍfÓú•ÉÉÆ'™’…Ü‚[âa&!!ã¸P(äv» ®N}¶f(&Á’à¥_òû$ùЂì_EQÜn·în&&§aÌóüùóçW¯^]SS3hРiÓ¦QĦ¿Þ€ÅtèСիWÓ4}çwfee‘k`„M´iÑñE^Ñ;·÷\r)¨[õöÛo9rúôéºÇ ±0Gqµ¡Ú…Gº%·GôŒ½fì­o o×ò1÷ìÙ“ŸŸÏqÜÃ? ‘Q„¯Ð)f Õœ:$IÒŸþô§wß}7Vþد:`1UVVŽ7. Ö××çååÕÔÔì(N¹æìš—¾iÍé5Ðñ$ÖF„uyûí·oÚ´©W¯^UUUFêæ䜡™&±é£“Uø*0±’R~¦g˜¢¢¢cÇŽ½ÿþûn·[×lÖ÷‘NŸ>}ÇŽ«W¯Ž‹‹+//×µª¥áµ×^›šššššÚ¹sgBð# —'êOüãÌ?ê÷Ȉ<ÃÇš*ìß¿ÿÀÕÕÕ£G6ÒÛøÀ3S(¯ T¶¶´&—Šòz½sçÎ}ñÅÁï£{æéGáY­VAn¿ýv‡ÃñØcñÚ]õ—q«ÕÚ½{÷ 6lÙ²¥k×®à‰ŽN(š¢Ÿ:ðÔÔk§^ë¼Ö-º¡Ÿi,ùÒ4 ¥þ%I*--7n\UU•‘~|F8—U9Õšúé¨Oßúž_ð?´ç!˱ҬP³÷¸¡¡éÕÚ‚¡ó.`ýÁ,**ÚºukZZ9íáWp+úî»ï6lØpøðaA²³³gÍšÕ§OŸ–ǡƢ[t—úKŸX,©VðŸøÇÈDí" 76mÚ „æÌ™£(Ê–-[šššZ·n}Uò 3\]\]º'tß^¶]Q‚›7ÓF™L&ÝcO'ð"..nÕªU›7o¦(jÔ¨Q=ö˜ÃḊ'ŒQ)P” ;vìÖ­Û”)S¦M›Ö»wï¶mÛFõh@ÿ1Žæ>õÙ¶qÛftžÁ æÙ>ÏÆŠU߯_¿I“&M›6múôé&Lèܹ³®£Çȸ {Õÿ8pÝÀ®kº®=·vnÖ\kƒ¶M±dþÚk¯Ý{ï½³÷Å_êi#ò.dÆçó3¦k×®²,ƒAMjÿá]ž£ÄÄÄM›6a`?UWWgee‘Û* æezþüùž={9H“’’’““AèÙ³gmm­‘ä´²²²Þ½{›œNgCCƒËå™ë¤:ù…)Ôâ×U!´ƒÁ@ Ñ9 ä^Ùî$¡P* èª,žül!˜87¢BA€,˺*”ÂF0Ô=oEÉ£vN †B!0[vNóGKNÓb¢tTH5·Ó‰ nî'Ö_„T«ˆ”ÔpzòäTs¡' ¼$sb„síOŒP†3 }™^SRIJ;Ëd2‰¢yFå\Å*MÓfƬ`jè¾ÊÞNp£œ={¶¤¤ä7Dÿ§ П$I§OŸÖ·…¨‚†‚r¹~ZÝÕe”çùùóçgggçååOáwE¢f{rÖ¬YÙÙÙ{÷î%$›þN7¾þëëïÛsß;ï<ë9+•†¡P`ƒƒ¢¨@ ðÔSO%''¿ûî»ä6Ûÿÿ Y–SSS—,YRRRqèdz–fŸÜÿ$ø×¿æäííEE$å`\uŽ»ténYã]+ÿ9tèÐW_}õé§Ÿªª ©†lžš@Í9ϹJ¡rÎwsîØqG™¯,V)BWY…p胕Ÿœœ¬å÷~À5ñã?¾téÒ›o¾)ËòòåËÏž=«Ì"ÀúA98´ÕП¦ÿTí¯þâì䄞«ü.4™LëÖ­Ûºu«,Ëo¼ñ†nÅÜÿórh†ž““Ð&)ÍQ’*%š¯O¿þXͱ¿üM”ÅN ¢¶ŽÒÆÕ|‚9³k×®ÆÆÆQ£Fmذ!;;ªŒþÖ’üÍ`æãÇ¿ãŽ;êêê<Ï3Ï<Ó®];¨<…ž¢ý’ÿµÁ¯½rü•ÕgW/Î^<µÃT¯ä%ä³]M» .„Ò,Ëz½^]§åÿùWr¸Käççû|¾¦¦&ˆBŽBŒ(ËαtÈRÚÐíJ 6Eá@ nð‘V¬…!ádF@ãÑÜd°‰@ßlŠÊF8Ûºó*•XÇPø%< Ÿ\“¹ˆÄZ¹ö² ›ûTÄâ6R…,ËÚívJ/ÁâÉå±ÙlÐÜ… 5“ÉdµZâQõº…ƒMP_FlÒ&'£0°‰ÜÍd€ÇqP‡ªªP<Ñ`Ã`^Wæjsw –4W0-/øá#H…Õj=sæ Æ¸²²ÒRQUUURRrèÐ!]÷ÐûýþÓ§O›L&r¾ çÏŸohhˆ‹‹Ó|¤gÏžMNN6‚T$''WUU‰¢xìØ±ÚÚZ#HŹsç>l©(**r8Z‚*m@÷ZNK]ºtISIAAÁ=÷ÜóûMàæã¶k×®«V­ wî\Váåÿ蟿ÿ #Â9 ùþçƒíÿæø}Ïý¯¿«ðýø]…ÿëÇÿ§ò>ÿÇ%à%tEXtdate:create2017-06-06T01:31:15+01:00\uŸž%tEXtdate:modify2017-06-06T01:31:15+01:00-('"IEND®B`‚puzzles-20170606.272beef/icons/solo-ibase4.png0000644000175000017500000000146713115373745017647 0ustar simonsimon‰PNG  IHDR‘‘1öGgAMA† 1è–_PLTEÿÿÿÀÀÀ€€€€ ÿ¹ÛbKGDÿ-Þ oFFs·´®atIMEá!:ÔÖ; vpAgáá(Ö'IDAThÞíÙa²‚ `m:@’è‰Páþgz =v©0æ½j–Ÿè~±(Œ´UõŽ­Á[× ‰$’¾GbJu0âìP:ÚœÒà‡e7ú€XФpH‘ÄmPŽÄ¿V^“Nþhâ÷)‘BhÕ ðÛvÑc8¬bÇuÒõbƒH®@:¦Wp¦4¿š¿÷¿$9ªç )hu^?I$‘ôéÊH"‰¤·—†h“ù>É~˜š2ñtv¦˜„žœ·IÈywƒdÜÉy, ‰ùÛ». -~©äþa(3O¬*õìXUj/ÒT@šÿ±šE|ì>NI$ý™Dç;’H"éÝ¥vÙdjqv%4%÷¸Ë’´Bkh®¾°ERs§;´º6 íKYd\ºŽ F4×Ú ì?¥¥V…Ü$ èùŽ ‰ÍÓ] «‰-5Ö.O J‡·Ï“‚Òá‹c ®DLæÎ¸?“Ág7æH ­øÍm­‰='µa¡n`|S–¼—QíÐÕõì„Ý v‚cR² ÔénVðº†c)œ¦[)±«àÃë™ìl!ìÜwgLQ«óúI"‰¤ÿ‘Þ¯ýÕ[žÙ5ܯ%tEXtdate:create2017-06-06T01:31:33+01:00}€­Ù%tEXtdate:modify2017-06-06T01:31:33+01:00 ÝeIEND®B`‚puzzles-20170606.272beef/icons/solo-ibase.png0000644000175000017500000000621513115373745017557 0ustar simonsimon‰PNG  IHDR‘‘LºÍtgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“ oFFs·´®atIMEá!:ÔÖ; vpAgáá(Ö gIDATxÚímP׀φ$ P¸ š‹$¥^  TPVj±PFæF«ulgÚ¥µjÇÚq.?hi§µ8–Z­R¥ÓJ™Šiɵ-(Tæ^>±ÈG,)_ ›û#Þ%b[M²lrÒ÷ùÃ9';oÞsžÙ³gw³ BL5„íN§sw&w‘J¥ž“Œ§å#•JBw§8 8Ãp†à ?À~€3ügøÎðœá8Ãp†à ?À~pŒUß[Ÿ§Ê³"+ÝrqÕÅ0akÑëõµµµ---ÃÃÃ\.7$$$>>>'''++‹ Ö’±gÄ4Rq½â»žïÚÛúÇûý¸~Á‚`Y ,Y’œ™#拊Ƙ3ÒDn>·Ù^Ë ¹\nµÞ“€Ùlîêêêêꪮ®NJJúôÓOE"ˉ©ºU[Îoéë£[ŒÆëC׫;«£ÄQ‹B9±¹ñíKowŽt²<öX­ÖIÂ&Q__¿iÓ&–³ªºYµîì:{a®ÃÌ~öí>oû!Äçð”‘åq±‡ ˆäääÌÌL™Lf0T*Õ_|AQ”íSµZ­ÕjãããÙI¦›ì.:_d±ZlÕØ ØWb_I˜žðˆÏ#:RwuðjMW —pXΆMÛÏm¶•ߘ÷Æ;šwØ‘I‘‘‘±cÇŽÙ³gÓáááÅÅÅtË… XsöaӇæa[ynÐÜê¬j>‡o«† ÃC ¢ œËÀܸëÂ.A‡ÊÊϘ‘ÁÎpÜP(üì³Ïì…Ùxá…ì«cccìäc¤Œ'oœ¤«ÿúÇ¿lÂèÝÎi\ÝϾïùþXû1„T(ݸ[?¦ggD‹åž1ŠŠŠbç{µw´³ÁVàŒ˜FÖ¨×4è†MÃ"¾H>]¾vÎÚå3–;Ù%gƒÆÁ¢óE!ï*ÞñEèìèÑ£t988xÉ’%ì|oë@+]µŒÔNLƒCÆ¡³·Îž½u6ï±¼÷ïqÇf;—æÆ·~~«w´!´fΚÅa‹Ù ‡P©T}ô]ݳgŸÏg竌tÙL™w›7N”þ§ÔÑÈÎ;;Ýuºò—J„PD@ÄÎ'v²3qòäÉõë×›ÍwÇkëÖ­+W®díÛÇ-ãöU_®oÙ¢²kù×Ô+Ôò`9ݾ¯yi"Šì¼³Ý—v#„8§TQ*ä Y‹‡¤´´ôÕW_5™L¶ê¶mÛ^{í56àØW ¢ žõ¬?Ï_(+^0±Ž5˜ ú.8ÙùãÙq!DY©çÎ<÷GÛ$~™ˆRÎVÚg9Õ˜Íæ7ß|³¢¢ân¹ÜâââÕ«W³–€Pa¨}5~úÄ FL`ŒáC/ 5üêPd&¯7z$Inܸ±¶¶ÖVõóóÛ¿ZZû™ÄO»ç,@„}™ ú2Ÿ/×סÈ^u]¿··wÕªU´°ÊÊJ·CEDÌÏ¡«M¿5Ñ嫃WíW%2±Ì¡ÈÎïg»žØ5f™|~z{ìv‰¶„®n—oñD²@ÇrrƒÁÝÝÝM·<óÌ3uuuuuuö›Í;755•…|B/þýÅ­ [må£×. [´8tqïhïŽÆô61A1ŽŽÃÏX\º¾øÔĢ߉{1N?Ó ×ë¸ÙêÕ«KJJÎå|B”•z^õ|ƒ¾n±?Œ!„¸îñôã ‰âá“A^67z‚sè©CI’$ºÅ^˜?Ï¿,¥ìá…ÑxÛÄÓñE'–¨ºYUùK¥ö޶¼ß—ëá±Dº¤PV(ñ•8ž?Ã)˜qœá8Ãp†à ?À~€3ügøÎðœá8Ãp†à ¦¸ƒS>p/WÀ~€3ügøÎðœá8Ãp†à ?À~€3ügøÎðœá‡KÏ2}üñÇ{öìù“ æÏŸÿõ×_»»ÞìgøÎðƒ±ç<7mÚ4©Ñv_`Æœ)•ʈˆwwç/cÎ6lØÐÝÝm0‚‚‚bccW¬X‘››ËãñÜÝA/„±ãYSSÓàà ÉdÒëõjµzË–-YYY]]]îî 2…kææf¥RÉÚ{Iÿ:¸:7ŠÅâÌÌÌ… Μ9“$IFsàÀ’¼ûr»k×®>|ø¥—^rw7½ —~ߨÝÝ,웚šž~úiú%|‰‰‰UUUÓ£~Oèiù0ðûÆðððIÂB±±±Ë—O¼f·µµÕ± Àƒ˜’ãÙ¬Y³è2I’ôëíF˜gÿÐ" €Ã«-Lâühvtt¼üòË7oÞœÔÞÒÒòí·ßÒÕ¸¸8w÷ÑÛpiÝøÕW_:u*==}éÒ¥ÑÑÑããã—.]*++£ ¡ÜÜ\w÷ÑÛpu­OQ”J¥R©T¿û©B¡ÈËËsw½ ççF>ŸÿçïªÏÌÌ™›››’’âîÞy'ðÌ NùÀ3ƒ¸Îðœá8Ãp†à ?À~€3ügøÎðœá8ÃpSÜ‹Á)¸ƒ+à ?À~€3ügøÎðœá8Ãp†à ?À~€3ügøÎðÃùg™***ŠŠŠ¸Y||üéÓ§ÙéLóoÍjúbßÅö¡öþñþAã ÛöÈ4™X–öhZþcù~Í^Í^ú£yÓç%'°Ÿ³0ìlÿþýt9;;;44”ý.o?^tþwNBž”}Äÿj†/LÎW®\ill¤«7ntwï&H MÙ;¯ÄWâîD€Igö;™B¡ð¨7]ýôëOK«—–_-w=”ÛaÌÙ­[·¾ùæºêƬ º@÷O]gA§æyÍÁ§Ò'Ñ«eçÏ;5}w%ÆŒ9+//7›Í¶rddä²eËÜÛ1.‡+ñ•d†gžXzÂ~éx¤íˆ{sfœ †#G&ÆbÆ á)‡zž´8š®vŒt¸;#WaÆÙ±cÇè  lžGÓܾÑ;Ú{{çHgóoÍtUà#p ¨GÂÀZŸ¢¨O>ù„®*•J___ö{r¾÷ü¶Æm)¡)©a©sÄsxÆm¿öðµÃ£æQz³…[ÈZJ$IÒ—?ÚÛÛí?jhhðó»{“aÁ‚½}ggΜqûy´ eRëÔjú6†­•­e-ŸŽŽŽ?zåèÚµi´µµÑþæFû%þÊ•+%=Š›W¹¬RÄsò®•çàê~¦Õj誗øÙ³²Å|q]oÝå¾Ë·Çnß»c±Zü¸~3üg<ôxÖ̬ôGÓ½à"‚gñÊžÄp†à ?À~€3ügøÎðœá8Ãp†à ?ÀÀýü«pÝ{a!*%tEXtdate:create2017-06-06T01:31:15+01:00\uŸž%tEXtdate:modify2017-06-06T01:31:15+01:00-('"IEND®B`‚puzzles-20170606.272beef/icons/solo-base.png0000644000175000017500000006301313115373723017401 0ustar simonsimon‰PNG  IHDRááÖ(‘YbKGDÿÿÿ ½§“ IDATxœìÝyTS×Þ?þ0‚RA&EHA0ZPÐo/µT‘I”Z¼­ú<­K©c»¼ Þê]ËJ[kuõ*`ô"|)\ª%[A¨åW&D”A†„!Óïø=JŸ÷Ù}úyýµ÷>§ä½ødgŸ}ެ¶¶6€Hl¦x!¨Ñ@.¨Ñ@.¨Ñ@.¨Ñ@.¨Ñ@.¨Ñ@.¨Ñ@.¨Ñ@.¨Ñ@.¨Ñ@.¨Ñ@.¨Ñ@.¨Ñ@.¨Ñ@.¨Ñ@.¨Ñ@.¨Ñ@.¨Ñ@.¨Ñ@.¨Ñ@.¨Ñ@.θü{{ûqù9ð¿F[[Ûïÿ!0rArÏZe\æöãÂÞÞžœ0ˆ°<ÔÚQ‘È ƒËïטˆÊ3¾k¿0rArArArArArArArArArArArArósïÆEI{I¸(\‹´ÔÈ­wnÙ™Úa ÐÑÑQTTT^^^]]ÝÜÜÜßßÏáp¬­­===ÃÂÂV¬XÁb±°…¡“)eõWZ¯ÔõÕuuó8<+c+Á¿Ø”0 C FR=2¥¬¤½DÒ%‘<‘Üéº#UJ©C55|.ŸÁlä¸zõjVV–D"éèè000°µµ Œ‹‹˜“|SõMâíÄ—œ0ÏzÞ÷!ßcË£‡¸-WÊ·•n£hÌ …···Vû\•JÕÒÒÒÒÒRPPàççwúôi>÷_šè¡hûí]ƒ]ÔHïpoïpo½´¾ ¹ÀÕÂ5Ð6s$0ªÒöÒ¸ÿÄ1‚\2™ìƒ>(**¢666666¦§§ïÚµkóæÍLe#qknh–53@«Õêh=%%%›6m–G'ÿAþ†â ô ÀÔÆéšÍfS_LU*URRRZZCÑHDÖ<úÚ£kßÕ}‡2dk†LÂb±üýýCBBB¡‰D™™™FwT,WTTxzzâ óPþ0áF‚Z«ÖuÝ'ºoqßâõš—‘Q›¼­¶¯¶°¥Ã"ë­ü3c³ØŞx[y{[y|ãc¦äÊ•+ÅÅÅT÷³Ï>‹ŒŒÔh4§OŸ>xð n011qùòå666øãmšµi¢ÑD½A{S&ÿ½V‚þ°û•ýÛJ·éÚ;fïH’$1ƒÅbïÝ»wúôéÔ`pp°ƒƒÃáÇ©‘›7ob«ÑÇ*õ+ûuíYg¬(0dêºv¦vBkaô´he:Î(.\¸¯R=­;wî\¹r%¶WRÑ»&“'îEÜÿEìmåM¯:.Wʱ¥à·±´´LIIõöç¹¥W###<‘BC%«$ɾɑ®‘~6~Ë–혽#78—Ë~¶Ò’ÿ O˜‘˜¯ÑûoïG±YìdßdSŽ)Óqô%''øá‡JåÓë»wïþè£p0çšÓ»Ñ®Ño9¿eÆ5LžÿlŸ‰B¥¸Ùug0~±XO]$´´´Œˆˆøê«¯è§M˜0Ožƒ±±Þ ûDwúežš¾Äæ¯J‡¥!Vóöå·_tŽ0GˆŠK¯J¯šJ¥ÚµkWFF†®Ëáp>…-€Ž­©-½ëùÚ³ nÜ XÔÇŠÇX“ð[ÙÙÙ8pàÀ*•J©Tš˜˜ „RSS©y<Þ ÿ{,œÍœ©¶\)×h5l“Zæk4™ärùûï¿OÝ ÅãñNž<¹dÉüI<-ŸÛ…ÍB,z›ÅbQ·Í›pLpà÷ãp8ÔGnn.5îããÃP¢gè7<›sÍ)Ј„µµ··¿óÎ;T¶¶¶ÎÎÎf¤@#„\Ì]fXÌ ºÔÞ „Pm_-ý*¢À÷Ãhø z{{Gž?¾¼¼œêÆÄÄà ÓÔß´ù§ÍúèW÷V_l¹Hu=,=ðä‰ùyô¾9ûFîkéì¤FÞ|óÍëׯ_¿~~Ú¬Y³.\ˆ!Bè½™ïí,Û©k§×§Ú.°]Ð>о·|/uŽÛD7<ÿÀ˜äJùÝî§·6Hè‡ÊÚ˨ ó'Í7`àG€C‡ÕÕÕ…‡‡ …B>ŸÿèÑ£ìì씔ꄠ  7Þx[žÜ¦Ü¼yAöAK–NãORÝîº}¢úýî•ÕSWcË£‡ù½ÆuÍÈÁzi=½F¯š² Û³Ie2½@£ç—É(QQQØjtÌ´˜œû9ee!™R¶¶h-}!Äas’æ2së<©IÖ´Z4úŸôúÿ¬§Úuuô ^Z­¶´´´´´tÔ£NNNGÅI£ÕˆZE¢VѨG}m|ç†cŽDµŽ?6‹¶(ÍÏÆ¡h3®Ù‰€¾6¾LD`<ÍŸ??//ÏÊÊ Û+RO¿UˆCHÊ¿ñ0?¿ߟµ,+ÿA~öýìŠ'ÝCÝ&3—Åö‹ãq6& »o\~Ú¸°··'' ",¼_c"*¼_c"*Ïø¾_°Öä‚ ä‚ ä‚ ä‚ ä‚ ä‚ ä‚ ä‚ ä‚ ä‚ ä‚ ä‚ äççÞЗê:ÎÏ&êñ€ä„A„åg]މ¨<ð~‰¨<ã;g…µ Ôh Ôh Ôh Ôh Ôh Ôh Ôh Ôh Ôh Ôh Ôh Ôh Ôh ×8?›ô·ùæ›o_r¼yó¾ÿþ{lyÀ¯$“É222®\¹RWW×ÝÝÍãñ¬¬¬¿¿XX˜……Ó™ÑÑÑQTTT^^^]]ÝÜÜÜßßÏáp¬­­===ÃÂÂV¬XÁb±˜ÎÈ$™RVÒ^"é’HžHîtÝ‘*¥Ô¡šˆ>—9OUU•X,¾uëVCCCwww__—˵´´K–,‰ˆˆàñx˜#ÑQ£Á‘H$Ú¾}{WW5ÒÛÛÛÛÛ[___PPàêêÈ`<¦( ooo­VKT©T------~~~§OŸæóqW"r”¶—Æý'ŽéÏ?~<''‡>¢R©Z[[[[[‹ŠŠ¾üòË´´´Ù³g3Ö:Ào‘ŸŸ¿aÃz:Z­V¯@ë)))Ù´i¶<àwêèèˆW*•L n½iÓ¦‰'ê ¿ÅE”‡&$$¨Õj]×ÝÝ}Ë–-^^^FFFmmmµµµ………q¿Z8±X,ÿ@ P(D"Qff¦F£Ñ‹ÅžžžÌ†d ›Åžb>ÅÛÊÛÛÊÛØÀøã3›‡Ëåúùù-\¸ÐÉÉÉÚÚzppP"‘|ûí·RéÓE˜ÖÖÖòòrFâ÷‡ëââÂt ð2ÇŽëïï×µgÍšUPP`hh¨ëÚÙÙ …ÂèèhæÒ1ŒÅbïÝ»wúôéÔ`pp°ƒƒÃáÇ©‘›7oþiktÐä  ÉAºöÝ'w™ ƒ:rä›ýÜŠÂ’%K<<<ââ⨑'OžàŽõÿ·Ö±qãF777ggg//¯˜˜˜ÌÌL¿e€‘†‡‡/\¸@u:¤+ÐÔ´úOÎÔÔ455•^ uÖ¬YCïb ^F¯@ëè]ñvttÄGq5º²²²¯¯O©TvttˆÅâíÛ·¯X±¢¥¥…é\à©ŠŠ …B¡k›››Ëd²uëÖ GGÇ™3gFEE]ºt‰Ù„dÒû suue* •Z­xôèÑ?ü°}ûvêÐìÙ³½¼¼˜ FÜZÇHUUU±±±—.]266f: @555T{``€¾¬!•J‹‹‹‹‹‹ÃÃÃ=:êôäO+==j[YY-^¼˜Á0`¤óçÏ'$$Œ÷õõ=~ü8ƒÛ%I©Ñ!!!>>>NNNr¹\·f/—ËuGïÝ»wæÌ™¿þõ¯Ì†¡ÞÞ^ª­R©F='++ËÙÙyÛ¶m¸B‘N$}ýõ×T711‘ZÁ$ HLL´±±a03ÐÐP‰D’œœéçç·lÙ²;väæær¹\êœüü|ÊÐнkbbrâĉ{÷î‰ÅbooojüøñãÔGìŸÜ… âãã©Ï³;w®\¹’ÙHàWúé§Ÿ–.]zêÔ)3Q£F®c¸»»/_¾œêÒ¿b™››Ó»ÑÑÑo½õ–™™™@  ï[P(7oÞÄžŽ8ÉÉÉ~ø!uÝ{÷îÝ}ô³‘À¨¢££ÛÚÚš››%IJJ uÓŠZ­þôÓO% SÁˆ¨Ñ/âììLµår9µ½0ÈÖÖ–Þ¥o sss300 º?Æ‹<*•*!!áÿø‡®ËápŽ9òßÿýß̦/ÇáplllBBB²²²è[;Ξ=ËT$¢ktss3Õ677‡kP$ÐÛÕK¿–Âb±è]|±#—Ëãââ222t]—ššÅl*ðë™™™M›6ê6551•„ùª×ÔÔ´yóæèWWW_¼x‘êzxxàÍFçââ2cÆ ª[YYIµkkkéWÖdÄhooçwŠŠŠt]kkëììì%K–0› Œª±±±½½}äxsssUUÕepSû:rssóòò‚‚‚–.]:mÚ´¡¡¡Û·oŸ8q‚~÷ÊêÕ«LèÞ{ï½;wêÚééé ,hooß»w/uŽ››ÛŸ³F+ŠÐÐЇR#o¾ùæõëׯ_¿N?mÖ¬Y .ÄžŽr¥ün÷ÓÛ ¤ ôCeíe<îÓ‡ÌÍŸ4߀e ÿ·7nìÞ½; `áÂ…3fÌ077ïíí­¨¨8sæÌÀÀušÏ«Nò"DÔh„F£‰D"‘hÔ£¾¾¾ááá˜#‰‰‰ÉÉÉ)++CÉd²µk×ÐïÑàp8IIIÌd’L&£h„PjjêÈÓ¢¢¢þ´5ºIÖ´Z4ú”kýÖSíºˆ:ª^¿RJ¥R,‹Åâ`gg·~ýú}Õ˜_ë044|ù^Ñ””úÅ(À,6›––æççGÐ ´™™Ù‰'|}}™ˆÀ8óððÈÎÎfðY²ÌÏ£ííí+** üñÇÊÊÊÖÖV¹\nlllcc3wîÜÕ«W0èãóùYYYùùùÙÙÙÝÝÝ&&&...‹/Ž‹‹cvÏ?¿^hh¨……Åõë×ïܹÓÙÙùäɵZÍãñ_ýõ+V1ûo2°ÚÚÚ~ÿO¡ž:.?m\ØÛÛ“–Þ¯1•Þ¯1•g|ß/æ×:¼Ôh Ôh Ôh Ôh Ôh Ôh Ôh Ôh Ôh Ôh Ôh Ôh ×8?÷€Î¸T×q~~4Q$' ",<ërLDå÷kLDåß9+¬u¹ F¹ F¹ F¹ F¹ F¹ F¹ F¹ F¹ F¹ F¹ F¹ F¹ F¹ÆùÙ¤¿AFFFBB˜§yzz^ºt C„PUO•¸M|«ëVƒ´¡{¨»o¸ËæZY ,K&/‰˜Áãòð$Ñ‘Éd%%%‰D"‘ܹsG*•R‡jjjø|>Î0#•””„‡‡kµZjäÖ­[vvvØ|SõMâíÄ—œ0ÏzÞ÷!ßcË£sõêÕ¬¬,‰DÒÑÑa```kk'0'¡Èd²ŒŒŒ+W®ÔÕÕuwwóx<+++@àïïfaa-‰Z«Î{WÐ\PÙSÙ9Ð9¤âqy“M' ­…S#„ÖBlIBEEEåååÕÕÕÍÍÍýýýÇÚÚÚÓÓ3,,lÅŠ, g=Ì×h¯:žs?‡>¢Ò¨ZU­­òÖ¢¶¢/ù2mQÚì×fcËSZZ‡íåþGärù¶mÛèÈd²>ø ¨¨ˆ>ØØØØØØ˜žž¾k׮͛7ãO%‰¶oßÞÕÕEôöööööÖ×׸ººâIÒ=Ô+Ž•tIèƒÒa©tXZÝ[}¶î컂wÎ;ˆ'ŒB¡ðööÖûV©T------~~~§OŸfp&ô‡Yë044d:ÂSñ×â•%ÓAˆpàÀææf¦SeãÆôÍf³©‰˜J¥JJJJKKÃ)??Æ ôÍ =å{ô 4‡ýÜd1¥6%û~6ž0Z­öå3Œ’’’M›6á 3*æçÑÞÞÞ{öì9.—Ë¿øâ ª†-—Íõ³ñ[h·ÐÉÜÉÚØzP=(é’|[ý­Tùt‘¡UÞZÞQîoë'›Íž2eŠ······±±ñÇŒçuÇtíÚµï¾û!dhh8<<Ìt„Ú4kÓD£‰zƒö¦øþ-·+W®SÝÏ>û,22R£Ñœ>}úàÁ§sÃÄÄÄåË—ÛØØà‰ôðáÄ„µZ­ëº»»oÙ²ÅËËËÈȨ­­­¶¶¶°°ÃÁT Õƒ[.RÝv ’ý’mLlnwÝŽûOÜ“Á'ºñœû9«¦¬Â !Äb±üýýCBBB¡‰D™™™FwT,WTTxzzbËCÇ|vsssss9~êÔ)ªmaa-ÒŸ#lÖsß0–Ø/ñ°ôˆûO5òdè ¶0¬¬¬/^ÌTçÑwïÞ-//§ºï¿ÿ>ƒaôØü}ÞßmL0]í!Ó'Ÿ|ÒÞÞŽZ·nÝ‚ ˜ŽƒB†k\×|îûù…eÒ¥mõØJßÃ~¯ïÞ™{gð$‰ŽŽ¦o4Þ¿¿››Û믿~äȽ3e2†<½½½T[¥RzNVVVrr2†0:&“¯ü¿ú/÷ÿyˆÏåðM„+¾‹O£‰D_ý5ÕMLLdp_‰5š>‰öõõõðð`0ŒžŸÿ´´`é©ÚScŸú¿Ô¥K—²³³B...Ÿ~ú)ÓqB(Ô9T²J’ì›éégã·ÌaÙŽÙ;rƒséëžùòñ„±´´LIIu;­ÞÞ ### y†††è]“'NÜ»wO,{{{SãÇ—Ëåò „¤ ‹ò«ÏvîܹråJ¦Â kô£GþýïS]'ÑÑÓ¢ÛÖ¶5G7KVIR¥P7­¨µêOþToƒçŸ‡nõ™Íf'''ã¼û<‡‘ëîÝ—;.§º5}5±XO]$´´´Œˆˆøê«¯è§M˜0Csssz7::ú­·Þ233ô} …âæÍ›ò(5ʵâµ÷ûŸ®ÔGºFþþKStSÑ_ŠÜ'ºëhþ!Qò²G_äää?üºT°{÷î>úˆ‘$âjô©S§¨O°)S¦,[¶ŒÙ<6ÇÆÄ&Ä!$ki}kÇÙº³ ¦bîNtFóöÛoÛÿ?z+B¡ÐÞÞ~çÎ e|ÊÙÌ™jË•rVƒí¥íìì8pãÆæææ†††_~ùåèÑ£===Ô ŽŽŽ<Ž' è]Ë¡o sss300 º?Ƨ°¥ðAÿ]ÛÚÄúðüÖF–,Äš9a&ýÞ³ug‡ÔC/ø¯„J¥JHHøÇ?þ¡ër8œ#GŽü÷ÿ7Î £"«F+гgŸÕ¾72{§<×lšÅ4ªÛ$kb. øUšeÏn€4皺¥òUãp8&&&ºvnn.5îããƒ'€Þ®^ú‹Å¢w©œ¯T½´žj;›9Ó×£¦ò§Rm•FÕÔß„!Ž\.‹‹ËÈÈÐuy<^jjjTT¶/AV>wîõÀ  &à¼o…񯧯>Ð>r¼YÖ\ÕSEuñlcjêoÚüÓfjjF©î­¦ßÏæa‰ïªý2åüùóô+á111x¸¸¸Ì˜1ƒêVVVRíÚÚZúUD<{¢ßöý@ö€¾{^¾B\.¢½½ýwÞ¡nß·¶¶ÎÎÎ^²d žWA{ï4Í?ÿùOª‹çƒ]Ïö»ËwØ,´[8Ãb†9×¼w¸·¢»â̽3ôë>“0̓Br¹œº½°¡¡~¨¬¬ŒúÊ<þ|úW×Wdß¾}#÷ówvvÒ÷-ìÙ³‡Ïçc{À[nSnÞƒ¼ û ¥K§ñ§ ©‡nwÝ>Q}‚þ÷¿zêjÿÑ£GÙÙÙ)))Ô AAAo¼ñ¶<ï½÷µî”žž¸`Á‚ööö½{÷R縹¹áy¿<-ŸÍë;:w–íÜíµÛÊĪº§zoù³<†N<·±(ŠÐÐЇR#o¾ùæõëׯ_¿N?mÖ¬Y .Äg$‚jôåË—¿oEG©QŠÛÄâ6ñ‹N°3µ[/X-OSSÓêÕ£—êVc„P]]†%N½û¯têëëé5zÕªU8ŸMŠÒh5¢V‘¨U4êQ_ßð©áØÂhµÚÒÒÒÒÒÒQ:99=z[„PLLLNNNYYBH&“­]»ÖÀÀ€~‡ÃÁv+¿¿­¿ûD÷Êž§Óùs çÎ5œ3`Ðo2DÅÏŒ×{ÐÒ+"“Éè!”šš:ò´¨¨(¦j4Akô-w+W®ÄöÄ™ÿ)KìeÙ|.ÃOm:†††ì—í] qIY˜bÀzåß0~ùóççååYYYá|Q6›––æççGÐ ´™™Ù‰'|}}ñ„1`¤,J™a1ƒ>¨W £\£¶z`z˜ ùH™GWTTè>çuÜrêjahq½ýú®;ƒOŸ¨µj‡çhæøúÄ×W8­šôg¾É4ö .* IDAT¦öá…-…?>þ±²»²UÞ*WÉ9Æ6Æ6s'Í]=e5þ;Öbccù|~YYY[[[ww7‹Åš4i’P(\¹r%Sû”ø|~VVV~~~vvvEEEww·‰‰‰‹‹ËâÅ‹ãââ0χx¢7E¹M¹[.VõTuv«‡M9¦fs^›á1×z.Î<„cé‹ó;ÙÛ?}öã¸ü´qaooONDXx¿ÆDTx¿ÆDTžñ}¿Zë j4 j4 j4 j4 j4 j4 j4 j4 j4 j4 j4kœŸ©@ž©ÿËAró3þ‰z„+9aayàyÄc"*¼_c"*Ïø®ýÂ<È5È5È5È5È5È5È5È5È5È5È5È5È5ÎϽû=®¶^ÍjÌ’<‘t t° lMlíãfÄ &0'ù¦ê›ÄÛ‰/9ažõ¼ïC¾Ç–GOIIIxx¸V«¥Fnݺegg‡-€L&+))‘H$‰äÎ;R©”:TSSÃçó±%Ѧ”eÔg\i½R×W×=ÔÍã𬌭þ6þaSÂ, -0dÈÈÈHHHó4OOÏK—.aȃêèè(***//¯®®nnnîïïçp8ÖÖÖžžžaaa+V¬`±Xx’èTõT‰ÛÄ·ºn5Hº‡ºû†û¸l®¥‘¥ÀB°dò’ˆ©<.g„Z«Î{WÐ\PÙSÙ9Ð9¤âqy“M' ­…S#„ÖBÌy舨Ñ2¥ìƒ?(j+¢6ö76ö7¦×§ïòÚµyÖf¦²‘F.—oÛ¶^ ñ+--‹‹c0À¨DEÛolïì¢Fz‡{{‡{ë¥õÍ®®¶ ÆcŠB¡ðööÖû…Q©T------~~~§OŸÆùÉz¼êxÎýœçòhT­ªÖVykQ[Ñ—¿|™¶(mök³±åéêŽÇJº$ôAé°T:,­î­>[wö]Á»çÄ–Gk¯m¤h6‹ÍBO?ØUUÒí¤´{i E#Κ››™NAœüùŠ7Ð 4á ñ¼V«}ù'zIIɦM›ð„ù5::â¯Å+5Jl¯¸§|^æ°Ÿ›¼¦Ô¦dßÏÆ–Góóè+­WŠSÝÏÞø,Ò5R£Õœ®=}Pòô³+ñvârÇå6&6øãmšµi¢ÑD½A{SfþýÆk×®}÷Ýw!CCÃááaF2 „Ølö”)S¼½½½½½?þøc¦’è<”?L¸‘ Öªu]÷‰î[Ü·x½æed`Ô&o«í«-l)ä°0ýª{{{ïÙ³gä¸\.ÿâ‹/¨nXXž<:,Ëßß?$$D ( ‘H”™™©ÑhtGÅbqEE…§§'ž0\6×ÏÆo¡ÝB's'kcëAõ ¤Kòmõ·RåÓE³VykyG¹¿­?†0ƒêÁ‹-©î»É~É6&6·»nÇý'îÉàÝxÎýœUSVaÈ3ó5º°¥jûLòY?c½®½Å}KNSNuO5BH¡RdÖgnõØŠ?^ìôXsü¯;Rÿ¶mÛtí;v$%%1•$(((((H×¾{÷.S1(Ç*õ+ûuíYg¬(0d?¥Ú™Ú ­…ÑÓ¢±…qsssss9~êÔ)ªmaa'‹Å Þ»wïôéÓ©Áàà`‡Ã‡S#7oÞÄV£øa³žû¿Ä~‰‡¥GÜ⨑'COð„éê¡ÏÙwyí²5±E ­„1Ób¾üåKÝxÇ@ž<#1¿ÖѪh¥ÚNæNôCN¼gÝË/ãËD³ñÚF·¹9g8{e{ÅÅd6dâüF·oß>Ý¿ÌH k†/4^ º‡Þ8¤+ÐÔ´š†^£cccMMMñ¼´©©ijj*½@ë¬Y³†ÞÄ“!¤W uô®è:òñ„±6¶æ²¹TW­yökCÿr2{®4áÄ|660¦Ú÷¥÷釚dMT»ª§Š‘âXÙSÙ7ܧÔ(;:Ämâí¥ÛW\\Ñ"kÁãêÕ«çÎCÙÛÛïß¿󫓬âI…B¥ÐµÍ¹æ2¥lxà¼À1Ýqæ¿fF]ºÔ‚iûÄK655éÚ\.wÆ ŒÆA!µú¹Ï0WWWÜ´ê!õЀjà‘âÑÍ?l/ÝNšýÚl/+/<18lN¤k$Õýû¿7ö7ªzüSz]:5þ®à]5ü¨ïÑQ§oxœÅTž§1Ø›‡ÿyÿwµæy¶î,ýkЫSØRø ÿ®mmb}xþaÝ$zæ„™ç|ûòÛTž}sö`ú*OGÄ<šŽÃæè 4B(÷A.5î3ɇ¡DÏ4ËžÝàgÎ5gð xZ>·«—~­‰…Xô'QP¿WØ(гgÏRÝ7b~2E.—ÇÅÅQšÇ㥦¦2^ é̸fÓ,¦Q]úž®Wª^ZOµÍœéë™SùS©¶J£jêÇIU†~Ù‡r¾á|ydz+-1Óbð„iêoÚüÓf꣕RÝ[M¿ÉÃ’áUE ãbî2Ãbխ쩤ڵ}µô«ˆ Üç:wîõÀ© &`»oEO{{û;ï¼STôôq ÖÖÖÙÙÙK–,a$Lccû@ûÈñfYsUOÕŶiŠ~Ñëì}ƒ/½|#„¸\Ä"Ö:Ý9T×W>5\h%äò)e7f§ÜK¡NšôƤ7°åÉmÊÍ{d´Ôaé4þ´!õÐí®Û'ªOÐß¿ÕSWã ³oß¾‘÷tvv9r„êîÙ³‡Ïç ˜j\.§n/lhh *++ãñž.IÍŸ?ßÀÀCž÷f¾·³l§®^Ÿh¸ÀvAû@ûÞò½Ô9nÝ0?@Q£ÑüóŸÿ¤º±±±&&¸'ò!…BúðáCjäÍ7ß¼~ýúõë×é§Íš5káÂ…òÜh¿±»|w€mÀB»…3,f˜sÍ{‡{+º+ÎÜ;C¿.‡í{3ý{Xç@çβ»½v[™XU÷TÓ, -è·ÔáDDÖjµ¥í¥¥í¥£u2s:ê{s$V#j‰ZE£õµñ ŸŽ'‰Þý`:õõõô½jÕ*œÏ&mjjZ½zô¨õë×Síºº:ª^¿R1Óbrîç”u”!„dJÙÚ¢µôeh„‡ÍIš‹ûÖùË—/“pߊL&£h„PjjêÈÓ¢¢¢ðÔh„R£·‰Åmâ`gj·^°þEGÇ—¿­¿ûDwêë×¹†sçÎéýþ „âgÆëm3ƈµŽ—˜?i~^Hž•±¶W440¤žö0ª‡”…),3Dðk°Yì´Ei~6~ÔýÌŒkv"à„¯/æTô-w+W®´±aà‰`D–Ù˲GÝŒû*° R¥Ð—ËЈ D¹F1ò° "æÑ±3bù†ü²Ž²6y[÷P7‹Åšd2Ih%\é¼r™îëàö¦öá…-…?>þ±²»²UÞ*WÉ9Æ6Æ6s'Í]=e5ƒwáò³–eå?ÈϾŸ]ñ¤¢{¨Û„câbæ²Ø~qœ ÿ+**ÊÊʨ.ã[îÈêjahq½ýú®;ƒOŸ¨µj‡çhæøúÄ×W8­š„ó&C„ÏAô¦(·)÷bËŪžªÎÁÎaõ°)ÇÔÁÌaÎks"\#æZÏÅ™GK÷˜žßÉÞþé³:Çå§ {{{r ÂòÀû5&¢òÀû5&¢òŒïûEúZü™ArArArArArArArArArArArArósïèŒKuççGõx@r ÂòÀ³.ÇDTx¿ÆDTžñ³ÂZ j4 j4 j4 j4 j4 j4 j4 j4 j4 j4 j4 j4 j4kœŸMúÛÈd²’’‰D"‘Hîܹ#•J©C555|>g˜ŒŒŒ„„„1Oóôô¼té†<:j­:ïA^AsAeOeç@çzˆÇåM6,´FLZ ±%ÿS%í%á¢p-ÒR#·Þ¹egj‡-À7Uß$ÞN|É ó¬ç}ò=¶<™L–‘‘qåÊ•ºººîîngee%üýýÃÂÂ,,,p†¹zõjVV–D"éèè000°µµ Œ‹‹8cŒDD.--‹‹c:¹º‡ºcű’. }P:,•K«{«ÏÖ}WðîÁy™Š^B®”o+ÝF/Ð@G$mß¾½««‹éííííí­¯¯/((puu Ä“D&“}ðÁEEEôÁÆÆÆÆÆÆôôô]»vmÞ¼O’QÁZÇodhhˆíµö”ïÑ+Ðös®)µ)Ù÷³±å¿ÞÛšeÍL§ N~~þ† èšA7n¤h6›Íb±tm•J•”””––ÆP4„™G³Ùì)S¦x{{{{{üñÇ †ñööÞ³gÏÈq¹\þÅ_Pݰ°0¥FÙ1Ð!no/ݾââŠY ¶ …B×677—ÉdëÖ­ŽŽŽ3gÎŒŠŠÂ¹] !dllLµïß¿O?DýÉ#„ªªª”J¬f¨Ñ¿ÊÉ“'©vhh¨­­-ÎWÿ›ðoo9¿¥k—¶—|05sêš+kz‡{B<.ï¨ïÑÛœ‘ÀKô ÷%ÜH@±ësßÏù†X7þOUõTÅŠcÕƒx^®¦¦†j DGG_¹rE·ô!•J‹‹‹7lØðÑGi4þ±²»²UÞ*WÉ9Æ6Æ6s'Í]=e5#w¨òùü¬¬¬üüüìì슊Šîîn—Å‹ÇÅÅažÅÆÆòùü²²²¶¶¶îîn‹5iÒ$¡P¸råJüû¸FbµµµýþŸboÿôÙ†ãòÓÆ…½½=9aayàýQyàýQyÆ÷ý‚µ Ôh Ôh Ôh Ôh Ôh Ôh Ôh Ôh Ôh Ôh Ôh Ôh ×8?÷€Î¸T×q~~4Q$' ",<ërLDå÷kLDåß9+¬u¹ F¹ F¹ F¹ F¹ F¹ F¹ F¹ F¹ F¹ F¹ F¹ F¹ F¹ÆùÙ¤¿MUO•¸M|«ëVƒ´¡{¨»o¸ËæZY ,K&/‰˜Áãò &SÊ2ê3®´^©ë«ëêæqxVÆV‚ ÿ°)a†xbttt•——WWW777÷÷÷s8kkkOOϰ°°+V°X,Ÿ3LF}F„1Oó´ô¼ô.aÈ3RI{I¸(\‹´ÔÈ­wnÙ™Ú1R£WϹŸCQiT­ªÖVykQ[Ñ—¿|™¶(mök³1§=m¿±½k°‹éîíî­—Ö4¸Z¸Úbˆ¡P(¼½½µZ-}P¥Rµ´´´´´øùù>}ó_QdJÙ?~PÔVDlìolìoL¯Oßåµkó¬Í8ótwwÇÆÆJ$ú T*•J¥ÕÕÕgÏž}÷Ýw<ˆ-Oiii\\¶—ûC“+åÛJ·Ñ 4ãþkñ×â•%ÎÍ¿¡x½@3E«Õêh=%%%›6m–‡@¯m¤h6‹ÍBO¿X¨4ª¤ÛIi÷ÒpæÙ³g^æpž› ¥¤¤dggãŒô‡ch`ÈÈë¸} YÖÌÈK¿óh.›ëgã·Ðn¡“¹“µ±õ zPÒ%ù¶ú[©òé—²VykyG¹¿­?ž<ån$¨µj]×}¢û÷-^¯yµÉÛjûj [ 9,¬ÿëX,–¿¿HHˆ@ P("‘(33S£Ñ莊Å⊊ OOOœ‘t6mÚ4qâD½AœÿvÚ•Ö+ÅŠ©îgo|é©ÑjNמ>(y:WM¼¸Üq¹‰ †<ƒƒƒ/^¤º ,HNN¶±±¹}ûv\\Ü“'Otã999«V­Â!Äf³§L™âííííímllüñÇãyÝQy[yïñÞ3r\®”ñËT7Ì% c¨§®=ºö]Ýw!C¶á°f€QQ£øa³ž›Ñ/±_âaé÷Ÿ8jäÉÐlyŽUëWöëÚ³&Î*XQ`È~ú©ngj'´FO‹Æ†ÅbïÝ»wúôéÔ`pp°ƒƒÃáÇ©‘›7o2R£ccc]\\ð¿.¥°¥jûLòY?c½®½Å}KNSNuO5BH¡RdÖgnõØŠ!OOORùì;ß®]»lmmBB¡0&&æË/¿Ôwtt`£¤kß½{ÛëŽÊm‚›Û·‘ã§jOQm C‹×Œ¡B¨_Ù¿­t›®½cöŽ$Iæ/BÄZ‡^ÖÑ»"çÈsÄfX3|¡ñÕ=ôÆ!]¦¦Õ˜™šš¦¦¦Ò ´Îš5kèÝÁÁAŒ¡žÙ¸q£›››³³³——WLLLff&½BaЪh¥ÚNæNôCN¼gÝË/ãÉcmmÍår©®Z­µíäô\Ô?9VsªæYŽkÊ1ÅœaßÍ}mŠ6„P„kD°c0æW "j´ŽZ«R ¨)ýÐüÃöÒíÔ¡Ù¯Íö²ò£âI…B¥ÐµÍ¹æ2¥lxà¼À1Ýqæ¿fF]ºÔÂÌåf=ô?x„««+#1*++ûúú”JeGG‡X,Þ¾}ûŠ+ZZZ°060¦Ú÷¥÷釚dMT»ª§ Ï% ‡Iuÿþ÷¿766þôÓOéééÔø»ï¾‹!ÌEáæþ&]›Ëæn˜¹s€«­WÏ5œCÙ›DÁ` IDATÚïîÇüê/GÄZ‡Îù†ó£nÊñµñ=pœº ôªÕôÖPíõ@tѳe é°´øQqñ£âð©áG}Ž:ýdžþoeeµxñbÃÐUUUÅÆÆ^ºtÉØØxì³·9Vs¨OÍŸ;>Y}2Ò5R­U§Ô¦ÔöÖR§ k†{†z&™LÂéoû[___^^B¨´´4 €~”Çã%%%é þɬ>IµCCmMlq¾zßpŸ®ò°ësßÏù†üŽA|+Qc"¨F*À6 qn"ž«=:½Ã½T[¥QzNVc–³™ó6Ïm¸Bé‰D_ý5ÕMLL44ÄzÜÂÂ"$$ÄÇÇÇÉÉI.—K$’o¿ýV.—ëŽÞ»wïÌ™3ýë_1$‰žýuå×}Ã}ºîþ[û÷ß}$SÉ&!5ÚÄÄ䫯¾rrr:vì˜Þ!>Ÿìر¥K—bˆñGq÷ÉÝòŽrªû¾Ûû˜|òó'íí¡u3Ö-°[€ùÕÇDÐZǨ~züÓÒ‚¥ôë ¯ÚzˆÞ5ᘜÅùÒ¿A5:zZtÛÚ¶æèfÉ*IʢꦵVýéÏŸJº$/ÿÏÇ‹9×ü¹T®Ño9¿eÆ5Lžÿl…B¥¸ÙuO$ºäää?üº.·{÷î>ús‡‘ëîîîË—/§º555ŸI>âPqüÌx'³§â,,#\#¾òÿŠ~Úà Â(•ʵk×Þ¿ÿte<22ò—_~ijj***rww× þðÃ/¿QóÏã‘âÑ¿›ÿMuñO¢÷ßÞb³ØÉ¾Éø/TþÄ­upØ›‡ÿyÿwõölÝYú4öÕ±5}n-ÌóµgÚÜ&¸° ¨ 1䡨Tª]»veddèºçðáÃQQQ83¼œ³³3Õ–Ëå†ÍÆ4 °3µ;0÷À¹T•R£4ᘠ„RkS©Íñ·Ë˜~­’…Xô'cè r¹<..Ž*Ð</55•¨jn~vƒ–¹¹9¶MÇas¨÷%÷A.5î3ÉO€úúzªíììL_ÿ™:u*ÕV©TMMMx"K¡Rœ­;Ku7Î܈mkÀó5º±¿Q·`¯§YÖ\ÕSEué[¬^)s—3¨neO%Õ®í«¥_EX`zXO{{û;ï¼STôôvgkkëììì%K–àyu=MMM›7o¦¦Š”êêjúýuøVé—y)çÎÓ¯DÅL‹Á†~Û÷ƒè»ÅéåÑ©ÿ´Î5œ£î%ž`8ÿ}+̯uÜh¿±»|w€mÀB»…3,f˜sÍ{‡{+º+ÎÜ;3 zv]Û<!ôÞÌ÷v–íÔµÓëÓíØ.hhß[¾—:Çm¢žª)ŠÐÐЇR#o¾ùæõëׯ_¿N?mÖ¬Y .Ä!”›››——´téÒiÓ¦ ݾ}ûĉôz´zõj>^ïAK¯NSSÓ‹>2ׯögUWWGÕk .?¼üÜ}+Ü÷­è¬q]3r°^ZO¯Ñ«¦¬bð٤̯uŒÉÃÒ#{Yö¨›«^6‹¶(ÍÏÆ¡h3®Ù‰€¾6¾ØòÅÐÐðå{±CBBRRRpÎÈ^bþ¤ùy!yVÆVØ^ÑÀÀ %%eÆŒôA½µu+އ‡Œ¾ån¥ËJœ÷@ü±0?uµ0´¸Þ~ýN×ÎÁÎ'ƒOÔZ5Ãs4s|}âë+œVMÂ%oÈÏZ–•ÿ ?û~vÅ“Šî¡nމ‹™ËbûÅq‚¸?ó½}EEEaaá?þXYYÙÚÚ*—ËmllæÎ»zõjüwÐÅΈåòË:ÊÚämÝCÝ,k’É$¡•p¥óJüûB"‘(77÷âÅ‹UUUÃÃæ¦¦sæÌ‰ˆˆ˜;w.þTD©è®Ð}OÕÁ¿åî„ÕÖÖöû õ,ÊqùiãÂÞÞžœ0ˆ°<ð~‰¨<ð~‰¨<ãû~ýÖ:àO j4 j4 j4 j4 j4 j4 j4 j4 j4 j4 j4kœŸ©@ž©ÿËAró3þ‰z„+9aayàyÄc"*¼_c"*Ïø®ýÂ<È5È5È5È5È5È5È5È5È5È5È5È5È5ÎϽûd2YFFÆ•+Wêê꺻»y<ž•••@ ð÷÷ ³°°`$UI{I¸(\‹´ÔÈ­wnÙ™Úa ðÍ7ß$&&¾ä„yóæ}ÿý÷Øòè\½z5++K"‘tttØÚÚÆÅÅ ÌIdJYI{‰¤K"y"¹ÓuGª”R‡j"jø\>æ*•*)))--¡hñññJ¥Û+îÙ³G¯@s8ÏMÎRRR²³³ñ„Ñjµ/Ÿñ”´—lúqž0¿ž¡¡!S/MÄ<úáÇ jµZ×uwwß²e‹———‘‘Q[[[mmmaa¡Þo×]û®î;„!ÛpX3Œ?ÀH›6mš8q¢Þ ÎOòÊ•+ÅÅÅT÷³Ï>‹ŒŒÔh4§OŸ¦æb‰‰‰Ë—/·±±Á‰ÍbO1Ÿâmåímåml`üññ¼î‹p¹\??¿… :99Y[[J$’o¿ýV*}ºÓÚÚZ^^îïï!ÌàààÅ‹©î‚ ’““mllnß¾÷äÉÝxNNΪU«0äÑa!–¿­ˆcˆÀB P)DE™ ™­FwTÜ&®è®ð´ôÄÄÛÛ{Ïž=#Çårù_|AuÃÂÂ0„5úرcýýýºö¬Y³ ¨O-;;;¡P?U¿²[é6]{ÇìI’$üFŠuqqa0@aa!ÕöññY¿~½®½eË–œœœêêj„B¡ÈÌÌܺu+žHA“ƒ‚&éÚwÿÿöî4(ª+Ñøé¦Aš¥1ˆ0 (jÛØfP\PŒ/—² bÄ7•d*I©—XEK>¨T4†ÔL4.䃂À¨cD{Â& ,Š¡én–†æ}è¼ã ¢NÍÀ½ÇäÿûtÎíû_,nŸ»äáM~Þô:$ÿâê’%KfΜC·Ðrm=â³ïرc„ „¥RùñÇ›¶·¶¶ò“G$ºîöÚ=Õn*Ýèèbã’t#‰n¹ÖvŸŽV( …âÉíŸþ9ÛÙÙ…††òfX¯uôõõeffÒéÁƒMM«…-¾YßL õ t 6 µyóf…Báææ6{öìÈÈȳgÏòù©™rïÞ=:ž8q"÷%îôâÅ‹üebÌ‚6rÆÛÕÕ•Ÿ0ææætÊýµâއ|+G•Ä*mQ· MÖM^Çöô÷ð“gXF£‘ÛÑQQQVVVB…¾£Õjµ^¯7mmmµZmtt´\.wuu>}zxx¸ §S¿¾÷uz]:!ÄÙÊ9A™À€§)//ïìì4 ­­­EEE[·n]±bESSo,--éøÎ;Ü—êëë鸢¢‚ç?¬èíííîî¾ÿþùóç·nÝJ_zå•WfÏžÍO ‰DF§¸}ûvOOÏ¥K—NŸ>M·oܸ‘Ÿúè£ÎÎΜœBHIIÉüùó¹¯Z[['&&ÙÈ¿Ó5ÿ`Ø[Ú/v^,`˜Ï>ûŒŽƒ‚‚L«CBþ8º££ƒŽûûû‡Ý'###99™¯DäÃï?lén!„DO‹öwòçí}ŸÁÎÎnݺu‡ÎÌÌýôS[MTwUŸT|B§û^Ýg!ì:Š›7o^½z•NÿøÇ? •ÄDøŽîííåN¥RiJJÊ­[·ŠŠŠ¼¼¼èöãÇët:òä7ågÝÉ"„¸Ûºï™³‡‡w|®   ²²²äää°°0__ßeË–mß¾=;;›»Î˜››ËO˜qãÆ¥¦¦ÊdÃ\¾:äÚ›1cÆðéréÒ¥¥K—r×:yPWW·hÑ¢cÇŽÑ-ô'G£ÑDGGÇÆÆvwwó‰+óvfì7±ýÆŸÏâfÇ­r[%Tò˃hŸ™3g †°ÐѶ¶¶ÜiDDÄÊ•+mlläryRÒãó¼z½þÚµk<äI¸ž@‹ÄÉ>ÉVÁNp¹¸¸<¹ŽáééùÚk¯Ñ)wÉh´Í›7¯¨¨(66–žh7n\hhèÑ£G¹»;–·H Šˆˆhnnnll,++KMM¥7­ ìÙ³gÈË£Ç`0¬_¿žž9 ûñÇëëë ===MÏŸ?ÿìYGOò?“ß½ò®Áøó©‹³w¾÷ò{‚$1¹ÿþßÿþw:ü š°°=d­gÖ¬ÇÜ( 333zöùÁƒ<äÑôi!ÆAãê‹«Ÿ¶òœ’55*É;éiûðÀÍÍŽu:ÑhämÉÞÉÉiïÞ½{÷îíïï7 R©”’––FwpuuåÿŽgI$GGÇåË—ûùù½úꫦí§Nâ~L= ¦±ƒƒCRR’é zúôéû÷ï_½z5ÍÏçGŸ~cÿŽ«;ÎÔž1M%bI’wR¸G8o†õùçŸÓ×I“&-[¶LØ<„…ãhn)B¸çRD"wj* ßikkË[AsI$ú}ÉÎΦÛçÍ›Ç–ÙØØL™2…N¹×ÀŒªÚÚZ:vssã®Mž<™Žûûûy‹DÑt1ÿˆ¡mmn¶(Mð‚Öëõ§N¢ÓÍ›7óyj÷i„ïhww÷iÓ¦Ñiyy9WWWsÏ"òÿ°Ô×׿ýöÛôPˆª¬¬äÞ?Æçª÷4/õå—_rÏ´DFFò–‡)·oßniiyr{cccEEòsùåI‚††î‘Üú&œEêÑÖÒÝò†êÂæŸ'à uÈZ–µÄy ?ïþ éééô^бcÇ ~*ÕDøµBȦM›âââLãÓ§O/X°Àßß¿¥¥e÷îÝt…BÁOGÇωïzý|[OÛ!õãëvyí’™Ëäcyú›‘““°téÒ)S¦ôöö^¿~=%%…ûûÌOBÈÁƒkjjBBB”J¥L&»ÿ~VVVjj*Ý! àøoytÝÍöŸo/¬ÓÔq_*m)µ6ÿyÉÅ{¼·™Èl´Ã|÷Ýw;wîœ?þÂ… §M›fkkÛÑÑ¡V«Ož<É=/ÇÛç îçÔ¶¶¶¸¸¸;wÚÛÛWVVr¿ìììø¹E߯ʺ«»K·¼>ñõË._~p™»ÛŒ—f,tZÈCÊh4þå/¡Ó¨¨(F>¸3ÑÑ‘‘‘çÎ+--%„hµÚõë×s—¡ !‰$1‘§[±×y¬{rc­¦–ÛÑk'­åóÙ¤„£Ñ¨R©T*Õ°¯úøø„„„ðfpp°¤¤¤¤¤dØW'NœxäÈÞÂBêµõÁªáÿDmøÇ:® ­¡}=ª CQQQQQÑÓvprr¢÷Ð6???OOOúñ4=====}Èï!$66–ŸGâh ZnABÒªÓžÜ-Ü#œç޾xñ";÷­p ¿ÖA‹Å'Nœðõõ¥[¸?@666)))>>>BDž……ųŸ¹µ|ùòÔÔT3³Q?BüWx{{çääØÛÛ „]3gÎÌÊÊöâÅÑ`ff–ššÊ]N$Oø€Ïw.áPD"Q``àîÝ»§NJ7º¸¸$%%Ñ-×®]CG³àÑ£GƒNwìØ1aÂBˆR©ŒŒŒüøãMÛ[[[yÖeèÚR²Å4ÞþÊöIJDžPÇŽëêê2g̘‘——gaaaš:99)•ʈˆ¡²±&jj”»­»°Lã›7o æI¯uXYY¥¥¥q ÚdݺuÜiOO¡à©ÌÍÍé”-Oœ8‘×X„Ä_‹oÖ7BB=B]y~wª¯¯/33“Nº¢‚“J¥G8qâ±cdž¼$“ÉŽ;¶téR>ó|øý‡-Ý-„èiÑþNþ|¾õ“:::踿¿Ø}222ÜÜܶlÙÂW(æØYØ-w]>oü¼‰6u]Ùò?WýYgЙ^½Õyëä­“ÿ£øaC2‚ſ䙙™±±±ôç;..nÕªUÂF®ºººE‹q š®Pk4šèèèØØØîîn~Âä7ågÝÉ"„¸Ûºï™³‡Ÿ7}†ÞÞ^îT*•¦¤¤Üºu«¨¨ÈËË‹n?~ü¸N§ã=‚Ü‚ÊÖ–%û$‡y„ù:ú.sY¶ý•íÙÙæâÇç9rrLÈæ::99ùÝwߥWìܹó½÷Þ6p †õë×ß¹sÇ4 ûñÇëëë ===MÏŸ?¿oß³n$A ×!b‘8Ù'ÙJbÅÏ›>ƒ­­-w±råJ¹\νNI¯×_»v÷tLp±vyrÃó%Ï×\_£ÓªÎ*„¦Ö:úûûwìØqæÌÓT"‘$%%…‡‡ › †(((hhh0’’’LÑÓ§Oß¿ÿêÕ«M/:u*>>~̘1£GÓ§!„«/®~Ú>ÊsJBHÔÔ¨$蠟í3RLW"RÜ F …™™=þàÁƒÑóbq³q£cAg4ŠEÌDò•/N§‹‰‰¡mmm––†‚fPmm-»¹¹q¯Ã›jF$q§R©”¿X/î ¢¶æ¶(h&¾ ---o¼ñFaa¡iêàà••µdÉaSÁ°¸7È544pïgáÖ7á,Rÿ¦¸»»O›6NËËË鸺ºš{Q.—óšŒ õ]õo_z»¡«aÈöÊŽÊ Mï_9n&¿¹Ø%üZ‡^¯ º{÷.Ýòúë¯_¾|ùòåËÜÝf̘±páBÞÓÁPÜãͶ¶¸¸¸;wÚÛÛWVVîÞ½›¾dggÇÏm,ñsâ{†ÞßÔÖÓvH}ˆNwyí’™ËäcyêÄM›6ÅÅřƧOŸ^°`¿¿KK ÷ë£P(~›MÉ®ÏÎiÈ pXê²tŠlJï@ïõŸ®§T¦pï^ žÌ[NGo/¬««ã¾TZZjmmm{{{›™™ñ–о£µZ-·  !iiiOfŸŸŸ§§'=‰$1Q°[ÕY`4ªî©T÷Tþêãè29„·0õõõÁÁÃÿIذa×ÔÔоækð133KMMå~œ'OÜþþûïó›‹!b±øÄ‰¾¾¾t ÷ëccc“’’âãã#D4áY˜YXˆŸu¯Ãr—å© SÍD±²IøãhxḸ¸¨Tªììì .TTT´µµõõõYYY¹¸¸Ì™3'44tîܹBg˜L&ËÈÈÈÍÍÍÊÊR«ÕíííR©ÔÝÝ}ñâÅ111ŽŽŽBŒ³•³:D]ÐTðíƒoËÛËïéîéúu–KGKǹãçO ž?¿;T_¢æææÿü_qvþùY‚#ò¯gggvÂ/ÒœIDATÆòàûõ\LåÁ÷빘Ê3²ß/¬u°  À.t4»ÐÑìBG°  À.t4»ÐÑìBG°  À.t4»ÐÑìBG°k„Ÿ{&#Ò®#üüh¦ÈNÂX<ëò¹˜Êƒï×s1•gdY±ÖÀ.t4»ÐÑìBG°  À.t4»ÐÑìBG°  À.t4»ÐÑìBG°  À.t4»FøÙ¤¿Z­öÊ•+eeeeee7nÜÐh4ô¥ªª*™L&`6€_™+W®„„„ Ò-?üðƒ““ÿI´í™Ú3_Ýûª¦³¦½·ÝZbmoi/+÷sô[3i…ÿ‘:zX%%%111B§øõÓét[¶lá´PTwU[¿ÛúSÏOtKG_GG_G­¦6¯1ÏÃÎcÁ„‚CG€`öîÝÛØØ(t ’Ûûö¥·„2 tô0Äbñ¤I“¼¼¼¼¼¼,--?øà¡ü }óÍ7_|ñ!Ä¢¯¯O¨wuw·}·´çKžïx¾3ûw³Ç˜iÖ5WwV4HD‚U%:z¦ñÍ›7… ð«ÔÕÕµeËÓxûö퉉‰B%9V~¬ËÐeÏxiFÞŠ< ±…iêdå¤tPFL‰*Áu ˆøøxÓÿ044400P¨}ƾÌÛ™tzðMÍκŽ£€o_ýuzz:!ÄÙÙ9!!¡µµU¨$ê‡j}¿Þ4¶5·Õ´ÑEÑ¥­¥]†.™…Ìëw^¦mxÍõ5¡ât4𬳳sÛ¶m„‘Htøða™L&`GWuTÑq÷@wDáãe MŸ¦ø~qñýâÉ!G|ŽˆE¬:`­xõᇶ´´B¢££ýýý… ÓÑ×AÇýÆþa÷ɸ‘üÏd¾ …ŽþäççgeeBÜÝÝ÷ìÙ#tÒ;ÐËJ%Ò”)·Boýw‘—½Ý~¼â¸Î ã=!èhàSBB!D,'''[YY ‡ØšÛr§+ÝVÚ˜ÛÈÇÊ“¼“èv}¿þÚO×xOGÖ£€O¦'+ÆÕ«W?m¥RI‰ŠŠJJJzÚ>#e‚ÕîtÖïfѱb¬ÂLdF/ðx 0Úa†…ãhøíš5nw*""îX$z<•J¤üÅâ@GÀo—»­û4»itZþ¨œŽ«;«¹gåvr^“ý?¬u C§ÓÑÛ ëêê¸/•––Z[[›ÆÞÞÞfff|‡x‘ÅÇÇ÷ôô ÙØÖÖvèÐ!:ݵk—L&“ËyêÄMÓ7ŕƙƧkO/pZà?Á¿¥»e÷ÕÝtÅK ùXt43êë냃ƒ‡}iÆ t\SSCûþëÖ­{rcmm-·£×®]Ëç³I#§Dž»s®´µ”¢5h×®ç.CB$bIâ\ÁnUÇZü¦‰Eâ‹Nø:úÒ-Ü‚¶1·I™Ÿâãè#D4Bp ³e,ËÈmÈͺ“¥~¨nïm—J¤î6î‹ÇÈc¥ŽfCGÃÓÓÓô´àÁ”)SÿÑJ·•+ÝV ãIXë`:€]èhv¡£Ø…Ž`:€]èhv¡£Ø…Ž`:€]èhv¡£Ø%‘G™8;;ÿçÿÀ¯Éˆ´+Ž£Ø…Ž`×ȬuÀhÀq4»ÐÑìBG°  À.t4»ÐÑìBG°  À.t4»ÐÑìBG°  À.t4»ÐÑìBG°  À.t4»ÐÑìBG°  À.t4»ÐÑìú?U?ÈÂîfÅIEND®B`‚puzzles-20170606.272beef/icons/solo-48d8.png0000644000175000017500000000277613115373745017173 0ustar simonsimon‰PNG  IHDR00`Ü µgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<YPLTEÏÏÏÝÝÝÛÛÛãããÄÄĦ¦¦åååÜâÜÜÜÜÑÑÑìììéééððð°°°òòòòëòèç误¯íéíÏÝÏãäãËËËÄÙÄÙáÙöíöh´h„±Ñ±!!!:::íèíÊÛÊ5Ÿ59¡9[®[£Ë£¨Í¨óóóS©S&—&ľ־ØàØ6 6·Ó·“ Ê þþþYYY5552œ2"˜"G¦G — ðêð¶Ó¶,œ,ˆ00ëìëPPP+++= =ÁÖÁ–Æ–ööö¢¢¢(š(ÕßÕäääÔÔÔ´´´àà๹¹žžž©©©†††ûûû|||rrrKKK@@@&&&000---GGGnnnÓÓÓ<<àn,i¿¿€g×€>»Õm¤‹/}>—r7D 2^º¼ìãa€€/V®\½F‡´kÒÅ/¯®^WÔ \·K H¿Z»qó–h˜}}û›õ;üî½ûÌú|ûà»ï/DS€t¸±úÃS¡I€Í-_û0Bå?­¥—%0­!¿µºW€l§µµÔ3&A²ñóƒkhR*J¹] •€,t=aÌ®`\£þT”€"«ò ¥4)vGëÇQBŸ«°zœd4ñ‘Ì‹Lೋ¯¬d‚_Zâ¿”aí®•|o?7C\Ìwör;vƒ®ÕЇqˆ‚¯¸ØR¨‰Z(žìå$ìu¬Ü>™_L8—-\L ?ãj>A•i¤cÌc†|8SQ`"vu 1U¨Aófت&M¿¿t€Öh¶ ƒ1õ uÔ È#Àó¿† ÁV“Ñ ÁÓGl‡Òh0F[Œ†©zþÓñ‹£ ”a6•>@Ã2 ^.ß „0ãfÍ1¥¶dYF®[ËØWaÕ™¡„ Eo“9ƫġT&UöUþs¤†4tà“"¯¨!Kjtza[ºUä‹ãùÆ%ùJz5zÓš¿¿ØqÞ¦€”ÈWº€°jT½’XVjApÖ,Q0W¥ai²qš%Æ=ÓaÅ­b8FtXyÆÏf:}xø†ëLC²òöáÅôXRÙ;<`Í›¼qì¼ËˆK%YgŽ ÓôcÁ4êfôîI]÷,{e%O…º&Ë}¤µ2¯ð–9ë¼{Üfζ#ö7Zq*DR•sÍ àêár¤Ë§yï+¾ÔÃÝÔƒ¯-ʇ] 4Ìn]*syc¡<öUöpN°û»W@e€œÁ,I‡ößЉsW¾,~mëXóQý %tEXtdate:create2017-06-06T01:31:33+01:00}€­Ù%tEXtdate:modify2017-06-06T01:31:33+01:00 ÝeIEND®B`‚puzzles-20170606.272beef/icons/solo-48d24.png0000644000175000017500000000445313115373745017243 0ustar simonsimon‰PNG  IHDR00Ø`nÐgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEá!:ÔÖ;/IDATXÃíY]hY¾UÝ]ÝéNz3«ÐIo Ý5þ&1d߆€̃>øa@œAdt@A†¼,#Œˆ+ˆãAXqÖÌàÊ<8½ ù1¡5TwUWWÕýÙ‡;©TwUw–]}Øó”¤Î=÷»çœ{¾snxÇVýákç!ÄÛöC}Yr „°¹¹¹±“ „Œ1ι¢(!t]!„1n¬)„XXXðtˆ\,„hnn¾ÿ~2™¤”†ÂB¨ª:55599Ù××gš&B(tÎy<ioookks§žABH±XìïŸ—0ˆÿLÉd2H”ë#‘ˆ®ëñx<•JaŒ=@ò|Þ*Îy"‘ˆÇãMMM©Tʶ탠ªs—ø!ÓEñk¨Xu¹+„B`ŒcŒ1©æ"„`ŒmÛB@9ç”R¿¦4ÈGEqÔå.TƒRêÇPåsX-"Œð”9årAäÿä)E™ŸŸ#„D"ïÄ5Öš¢!ˆ~ÑYp0ÂþOဪ¼Åi*’úüŸoú릟æ~Ò Ì•D"122²oß¾‘åZc¥1 é‰;G-ØIÐl !"82VûUÿuèñPÞÌõ쫹ÊAµ±inYÖ¡C‡?~<<<¬( çð·ÞÿhmËZ‹ZÖÏ!„‚”l"Ûo¿¿ÿþ{Ñ÷*¬L#Œ±a½½½£££¶mSJW®\Y.—1ÆÁCš®ÙóÇžÛ¹ýºòzujµËÝЭ«‰E‘˜,jÚ´6W¸Œ³Z…E‰ÅbÉd,Òc¬FAþŠ2\#A-É‹Z@ €÷5„PUÕH$‚1ö‡† ®@EÖH$¢ªª¢(RS&¯‚sîùŒÂ9÷«_-B0À¢$ ©CUÕðJÍ›ššÒu1ր˦§§óùüÄÄD¹\nÀeš¦åóyEQ ¸ c\*•ü9GüV&''ãñx@Š¢äóùÙÙÙññq˲ŠÅb³³³×u]×mÈ4MÏÁU€EéëëK¥R5äâUU'&&ÆÇÇ Ãh(‘H:::²Ù¬ã8õ Bt]—ެ$„0Mcìq¡—ž!„Ì¡r¹lY–aÛ€eYårÙ4Ͷ÷ïH1MÓŸ×U· -Š\ŸL&eæ†!3&(õŽ^£VPÐH:$!䯹\Î4ÍÞÞ^Ó4Á›R÷!W®\™››[³fÍŽ;~·þ¿®ÏeÅCMOOËæòm’}ŵk×~üñÇL&súôiÿEx£2Œ±®ëÃÃÃëׯñâŪU«ÞrÈd©-‹/^ܲeË… Êåòî-ß?!,•Jõªí›ÄEîýêÕ«ß܈Ìk^-õŒò€Ô«CA;UlljDcêÐ4-‹IfhL±XLÓ´x<ÞàBBj¨s ëº###ÿ!¹–%×ÑÑÑ™™™\.·,¹ºîR³¶!ÔÞÞ.Ð퇗Ëe2™l6Û˜\u]÷·¼Ulï8Žlåzuöеã8®ëJMBÈÇK@Š¢xj Ù°zÓª‚1æ8N]¶¯~£Ñ¨gŶm¿‚÷³¢8Ê8SbPƒ :J !4M#„¸®+­ß<¾”9õ<9??¿ÿþþþþ]»vÿÿ_ð.i¢ã8ÃÎd²Ù|³wß·ûÍÌœ³uÌ5I“•ÿ=Æ9÷yËk·Î[í²Ä9ób–¢ x¤ãŽÄ$r¥¤‹ÀJGÒó DÜHÂt‘.H#ˆäÒÅe j@ïÒJ/ã‰]¾²º†Æ×ráêú²ä@÷6®]·_û«…& ë7om†S@&·¶o/%®ÜÙ1&Àðîö½Ý€ÃÞð¾Dnr¢Áƒ‘´ìµvêŒ×,4†,ÚÓØé<ÊãX„¡®X<ö˜å.¶Ÿ2+ƒ°Y{Ÿ\Ÿ—:̵#ã"jT‰4¥9wD+Aî±ñD‚ Œ#¦ ‡\ªV­*¤L˜¼ hº÷§,Òã¡ô­e€á¨]ÒŽŸŽ&f¶n6ÓTw@zêí<›¨:U¨P‹‡Ï:©m=+¨.Sa'iŦ*`ü*ÓÕ4 … îQŒ–$€³_(þ*ŠÒƒq%TôP^©°Ý¯Ô ì6-­JþŸ•S%í°å$Ärå2Œa:¬Y_ãÉÈ0«ƒ,ô‹Í©Pìå)6,àÕë7ž²¢·+ïÂÜpÂÓ÷bš.­,ú£±]Ú|(?­l|FÛ¡è9ëS£$~M zùÛö÷ éÇÏ¢ž¢dCX¡Š­_óå,Ð;:;Q³kh]Y¹º]™©ˆI‚Nš•ã

k¥9+­'‚©õþg^û7æ='~D=F9ìFÒv%tEXtdate:create2017-06-06T01:31:33+01:00}€­Ù%tEXtdate:modify2017-06-06T01:31:33+01:00 ÝeIEND®B`‚puzzles-20170606.272beef/icons/solo-32d4.png0000644000175000017500000000101613115373745017142 0ustar simonsimon‰PNG  IHDR TgÇgAMA† 1è–_PLTE€€€€€€ÿÿÿÀÀÀÿ¿ ì¼bKGDhÙQtIMEá!:ÔÖ;"IDAT(Ï]‘½nÃ0 „åÂÞ Ê\ ÑÞÉ·Ç]6xÐ!ïÿ ½“;Õ¿”L?žK™ÊëËÇE×ÅÁ{™32™:ˆ|”·L$3€^fEÈÐJ/f/ |*{›ôXŸÎàÖœsc?)ã†s“ìwSÉ×™Ý]ªöOµˆŠ‡D¥­ŽjGW„*´ÍâQ–dÕMÒ¸G8 I#é’”o zY4‹Ï4?%zG¯CÏh¸kôSz.·M£#'êá†èÌ½Ž„A'ÒéM‹ÎG¶Ñõ)]"( îà“A^tÊXÄh Ždc;L¶†½!¶ªåZ›çúQM,®EÜTA{šÍ&g÷_Ù”‘ëdOÃÃÂø#ã_Ú •T!Æ€¸½ü?~ýO…õz;šZ%tEXtdate:create2017-06-06T01:31:33+01:00}€­Ù%tEXtdate:modify2017-06-06T01:31:33+01:00 ÝeIEND®B`‚puzzles-20170606.272beef/icons/solo-32d24.png0000644000175000017500000000325613115373745017234 0ustar simonsimon‰PNG  IHDR üí£gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEá!:ÔÖ;²IDATHǵVÏkT×?÷ç›g’™7Ó „`­A±5Z$‹W‚Ònº)´j\¹è^»©tã T(®WEéÒ’ Š$-T2‚¯ ¿ 3“IfÞyy?î}÷vqâ›iLáK¿xV÷ÝóÎ=÷üøœÏxÏB€R«Õ!節µÆÆØ¾ÆEQPJÿÉ0k-€Z­öèÑ£Z­¦µ&„k,X ”sîû~«ÕšÍ²ŒRjŒ±ÖRJ­µŽã4›Í©©)ÏóF ÁEçÎó}Ÿ—ତR2«˜sn­ õz=MSBÈØØc,Š"cL¥R™˜˜5t¹+©Œòˆq†Çň´ÖZë\å̰õpý·õßLa”RJ)­5.Œ1?~ðàA¹‰VZé\åŠÕîê¯ÿùu ](¥ðd:š8J¨äò‡•~\þñ?È[aŒ%I²ººzçΛ7o6 c ÞÑ3.ÇŸwŸ_}ruekÅ‚¥dX˜¡cMUVZýIPQ«Ô¶ÓmF†µ5Ƹ®{ýúõ'NÌÍÍ)¥Ê#¬µ.s—þ»TåÕvÒ^ó׿X°ïD@@å27ÕéŸ?7v6å ¥<þüÒÒÒÌÌL’$¥D=SŸ©WêíA»“t8åÖîòa~€Æ*¾úÉÕof¾ù½ûûǵÓ"%ðöBvvv¢(êõz”oF òàë#_»Ìå”>ýy”п9àœsÎ`P \é~qø‹.8çŒ1ιÖZ±¸¸È˲,Š"×uQ…†ô·Ç¾µÖ†yˆ†CÖZß÷­µJ+ Ԃݲ[”ìâ Ã^¯—e!dkkËZ‹eO’$ ñ±1lBèÙÆŠ8À,q,`«Õ ˆ—2vÆX†›››žçåy>ª²ÖJ)777 Žã¢(FUœsÄÊ®ÆØììl½^×Z[kË;rÎ{½žçy§OŸF žR©T`zzºÑh`¥JÑï÷qÀìf*˲4M•RŽãH)³,SJqγ,Ëó{öìÜÜ\£Ñ(Š¢l*¤=E¶#R>xËQ{G…ã8•JGØÁƒµÖŒ1!D’$RJìÈwÛTJ‰†ï¶©ã8CEQ4›Í‰‰‰ì ´µµ5ß÷«Õê¾@ÃM”Ò©©)¤L 79ç8 ¦§§qTX°È¦H™¾ï—”‰y+¦t—2=Ïóú*È&ž‚O¿v»}êÔ©¢(Z­Ö±cÇpÜÂ(e !”R“““‹‹‹ab›¢!Š¢T|wê;Jh”GY‘I!Q+¥TJ>|øÆ†¡1FJ9t€ïHxË|Ýnw·…9‚ Š¢~¿8Ø¶Ûøì ©“FQ! ;–Dˆ!e¾÷Ç/¼où ÂîãÍ@dUé%tEXtdate:create2017-06-06T01:31:33+01:00}€­Ù%tEXtdate:modify2017-06-06T01:31:33+01:00 ÝeIEND®B`‚puzzles-20170606.272beef/icons/solo-16d8.png0000644000175000017500000000154713115373745017161 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<ePLTEÂÃÂÙÙÙÜÖÜÖÕÖ¿¿¿ÑÑÑÕÕÕÜÜÜÒÒÒÜÚÜÂÂÂëîë”Ç”æêæÕÔÕíîíËËËëìëÒÓÒôðô¢Í¢»Û»àÛàÚÕÚÂÚÂ?ž?ÔÞÔÑÏÑ­­­llléééÌÍÌðêð[¬[{½{Þ×ÞíííÒÞÒåèåÒÑÒêêêÍÍÍÆÆÆèèèÐÑÐíëíÖà֨娨֨ÔÔÔÔÑÔ»¼»ÌÌÌÖÖÖØØØ¼¼¼ÒÐÒÙÖÙ¾¿¾çççßßßæææáááãããâââåååáâáçèçÛÛÛÊÊÊaaaäääÐÐÐëëëhhhÓÓÓãäã¾¾¾»»»ÓÑÓÔÒÔ×××çæçÛãÛØâØìììÝÝÝ```ÑÒÑéåé»Ô»_¯_çäçËÌËóóó•••¬¬¬®®®ïëïÃÛÃÆëéë÷ø÷¦¦¦¥¥¥ÃÃÃÓÔÓÚ×ÚÚÚÚÿÿÿ‰n:bKGDv1cÉAtIMEá!:ÔÖ;ÿIDATÓMWSÂ@Fï]ƒI\°c‹Ø{Y‚%j‚ØE£Ælذwýÿ.o¾}óÍœ3sÄŠTŽ8`’¨W5½©z"™B JcSsKk[{º£³«»Ç£7Ó×?ŸˆÑ'§¦gfyÖÌÍÍ/,ÆUk‰-¯ØÏk«k딹…"Þ†àþæ–FKÛ;‚®ìšþžE€:Ê~h{ÿæ9&ÁD„YC…ñã) mUJ#/[dåÓ³rîÜò# T¿¸Œ*W×7·wÕû‡Â#’ÿT­<¿¼¾±÷O¿"[Wµïþ¦j¹2)1d>%‡,és×%tEXtdate:create2017-06-06T01:31:33+01:00}€­Ù%tEXtdate:modify2017-06-06T01:31:33+01:00 ÝeIEND®B`‚puzzles-20170606.272beef/icons/solo-16d4.png0000644000175000017500000000050413115373745017145 0ustar simonsimon‰PNG  IHDRíÝâRgAMA† 1è–_PLTEÀÀÀÿÿÿ€€€€½fí¨bKGDf |dtIMEá!:ÔÖ;^IDAT×5ŒÀ qû€­>À?°'˜ìÿoZ1Y®¿ÊÄ$ÕâY¥ ›ïˆ‹v˜Ž`±zÐg«CÆšwÙ)ü?pŒŒç~ðEiœ“#M¥n×äq #?X!/%tEXtdate:create2017-06-06T01:31:33+01:00}€­Ù%tEXtdate:modify2017-06-06T01:31:33+01:00 ÝeIEND®B`‚puzzles-20170606.272beef/icons/solo-16d24.png0000644000175000017500000000240013115373745017224 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<âPLTEÂÃÂÙÙÙÜÖÜÖÕÖ¿¿¿ÑÑÑÕÕÕÜÜÜÒÒÒ¿¿¿ÕÕÕÜÖÜÜÚÜÂÂÂÙÙÙëîë”Ç”æêæÕÔÕíîíËËËëìëÒÓÒôðô¢Í¢»Û»àÛàÚÕÚÂÚÂ?ž?ÔÞÔÑÏÑëìë­­­llléééÌÍÌðêð[¬[{½{Þ×ÞÕÕÕíííÒÞÒåèåÒÑÒêêêÍÍÍÆÆÆèèèÐÑÐíëíÖà֨娨֨¿¿¿ÔÔÔÔÑÔÒÒÒ»¼»ÌÌÌÖÖÖØØØÍÍͼ¼¼ÑÑÑÒÐÒÙÖÙ¾¿¾ÒÒÒçççßßßæææÍÍÍáááãããâââáááÍÍÍåååáâáçèçÑÑÑÛÛÛÊÊÊaaaáááÒÒÒäääçççäääÐÐÐèèèåååëëëÔÔÔØØØÙÙÙhhhÓÓÓÖÖÖãããÒÒÒãããØØØèèèÍÍÍáááäääãäãáááÍÍÍåååáááèèèÑÑѾ¾¾ØØØÒÒÒ»»»ÍÍÍÓÑÓÔÒÔÍÍͼ¼¼ÑÑÑÓÓÓÖÖÖ¿¿¿×××ãããÆÆÆæææÒÒÒçæçÛãÛØâØçæçÐÑÐìììÔÔÔååå×××ÕÕÕÝÝÝ```×××ÑÒÑéåé»Ô»_¯_çäçËÌËóóó•••¬¬¬ßßßÛÛÛååå®®®óóóÑÒÑïëïÃÛÃÆëéëÒÒÒ÷ø÷¦¦¦¥¥¥ãããÃÃÃ×××ÖÖÖÕÕÕ¿¿¿ÑÑÑÓÔÓÚ×ÚÒÒÒ¿¿¿ÕÕÕÓÓÓÚÚÚÂÂÂÿÿÿK«½ÆbKGDõEÒÛtIMEá!:ÔÖ;IDATÓïþ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwwxyz{|}~€‚ƒ„…wwxyz{|}~†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóô¥§ze+A%tEXtdate:create2017-06-06T01:31:33+01:00}€­Ù%tEXtdate:modify2017-06-06T01:31:33+01:00 ÝeIEND®B`‚puzzles-20170606.272beef/icons/slant-web.png0000644000175000017500000002367413115373723017422 0ustar simonsimon‰PNG  IHDR––j.>gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEáæÛô&ÄIDATxÚíœgx×™ï¡fÙ’%Û’,¹É%®rIâ;qlÉI¼ÞllÇikG¶Õ(“b§$Š¢z¡ U(«÷n5I$A€ @€D!03g*¦ ©.û&¹ÏÝg¿Üé3`³¬}îf?Üó g€yùã™3ïùŸ÷}g,èÿÈfùgü@,†sˆ}ðÏÆB0.™ 6‘ŒSÈ­šýƒ…0ðáËötp*BRçÖ.Ùêâÿ»Æ«_,„­IÛæhÜ‘vDáBb¾¬¥Õ-Ç26ÒÿD,@Û¿ôÙ×lűŒ£ ³ª._ÒÔ½l-÷ßs ,µ!dfcâcÆÔñPZæWø.cøów¿–]M#Ú¯ôß÷ßÿÁ ûÁt‚ äFÄmKø³æ.'.”ê&H&’‡EF|qs´kgVwi¿b’$ej$Õ£þ+ “}±]³Íߨ$5GûÆmñ¨°d„ƒ`ÊMž º–ù—òRÌ÷•Gþ‘Óá­ÚÔܤ7gcKãúzW“¹9Mƒö›Ì}§ÃS³ëƒ'¶[¡^ŸßçóÂ;·Ä#77ÞÙÉÓg–¯/|~aÜoÉúÇ~‘hÉélóù|~O¤îÞ· ¯Om~oGÇ+ã=í>S Xís¿£ébJßï­è0uB®‡_¤AŸÑ"üÅÃ×÷`Ià¬k>ö¾=|Æ…K+O%p‚BsBüû÷§YV߉Úc†zþÇÕý\Dª-µ¬IÀ»ðÄõ/0åd4Wš‹°PVr-8óÕ5–ÖJ€B´÷‘ŸzUæ* ãø;Ý-¸y“ÍnÒÜÇ;$bê£Pö{¦BÏM‰8¢X_¬&oÏ:ËÚ,\pÖñ«ÿî;ß Ç4°d~iìæ?®úÓKf¼“¨mÈ‚xw’3^ÆÍ^†jñfïKt8(sƒE,uÅÂÏ=bjáþ°|Xb½Â…PÁÂÜõ æ—Ýû)‡Šã‡ãë2×–.M?kP‘H0Q¹¬>t›X"Õ”çÃZ×/–Ÿ€’ÁµîÞâ .½ë¯2*´[W Xƒ ÆT,…Š…¨ÛÅR¨b0Ñ?–pR»Ž uH4^®p‰H¹ãÀ4V¨Š¥RÁ€¼M, ÅÀ"Äßè\„·‘§¥ qaaÙŠN¥biTèíbéT` Ñ"€ÁHŸS²¢saa«hÅ  V¾ÚÄT™ª/áj%̸¿žè‹¥S¡«¢ai\–ÆÇÄ‹ˆFï£ ‚ó-éT½±"„"¼! >y˜±LToeHd ,‹P±.^ð\Uõ¸U*À‡N­8HâïªT½°XÌ^ºµQÿ;çšw•Ôâ bÆ"LT|´|åÑv`©\X›Š%r5}CîΫ2·?óºBÅìÊ,;´)£ì7U*¸rVØS˜×F#Ê—‘¢…{ö/K¯1„‘ˆ…Rá)S”+Èž[rhkÆFKáêñhX(”8uÏŽHDÿ"& i„[W°U˜¢ Mœ*GÌX Öø¥Õ}¡‰½ð¥W2ðhÚ‘p­ƒm›YÉ":V R©îë¯éàK)ëb*–Ú Ä:ËzD_+`nçŽËïL¼ëÉV!OœÆ¢ó¨È¾¾ö¾{G⠃h"MÄÒ é®Èó,ï'.äHú æ—޽øÀð×ðì°¾âD#ÏM Qâí…Ðu鉦Çï½õ»¥û$+@¤Ò¬gã°…JéÈ#'À7–Å7lèÂI\X\Ç9™ŽaÓ{êçsêIãˆÆ”Ïx¼rE²ÝûÝ'£[» mzÕG¦ê§#²Xv×&ØãZ+ LÏô±ÍBõBØ£ü¾-ôÂWÀ£œ;/À¾ôâÍ‚¡!¯LŪiqê­¡}ÏhKn°QúÜä=¹‡ù¢;v¡¾to“ÓåHG‘Ä™Åc?gñLk³zJKE½ú±1¸äÃ6½{¿³{÷š@c“gI¡gÜS-u¹ê žßõ9›”sç†øWžùœá-B¾'«)Èè*뮸szñ° —pñIGóàXºeÎÉÚÄÙµ¢h&ù…ný7çF½—l.ÐN"ÙÆ(­Êß®S%W*KZ?±Ô\Zv!A|ë|l)<áèÚ³£WO ÷ŒûˆIœH,½x5kÈþg~Ì„òdWožòúŒ §‡Ïì n´¬‰CÒ”çWèy}â#—Ü̬§0ÌYÿ¿æÞ?qšízÙ^VÝY „=„i³9:±þhâ“k-éÒ1˜É¯Æž|øÑ»ötÍñˆ6å[êÇü–Baéû³ z"ÿ>îÚ{OyÝA@ñ3#>O¶9.—¨ë#™}¶Gà’ìÒu’ßAHdÊÆËIáÒ¥Ocý8„=7;z…O^óͬ•( Ü_Ö÷ð\ž³—79ˆ¸mì¿Ñ˜d‘]ºV¸"ô\>’0´,‰ê žð:ñ„¶nSí9‹OTî™·Yò*â:øÎä‚üU <ý*¬:òTwÊ™SzîLIÚEÅM!Œ3}婊¯çîOq§€³Q¸PjmæÞª# æw’ ,‘jø<ÒôBƪÖåîjáªw'8»le9›k“þɯ $ÒÏâÃv]T|Ò$†ŸYY°ßϧ.>¯r”oÚž³±š!X|*DZ 8ÚÓ-¯ÑâXMU_,ѧ!Úÿ¨ÊÕk©F°®p4‰±TÀýÝxŸ¥Zäú­r©.7ÇÐÿR-R ©ª( ECVL¥ß,é+¤¿§µñê+lœ-¸IÈÌgÇû6¼ýn…  5ýK‹”±Dª¡2•<.`Ï-¹vvmãkãüôéTº94vÕ3,G€r;¢‘µÈN‘ÝÜïRÌâj¬Sù ÒäB:#z넼öÔ>¨¥Âú yñ®©ú ±’+ªœüøÅo]箳I­ÎµôfO­]îØì6«·dZ•Ë*÷ëkÒp˜mzàW 2ªlÖ–¹­ýìq?.,Ýݬ°5Tˆ_™ZýųFß^Wßøže¦øÇ´¿PÛrì/)a7$¾m_<ô«1§Bܲš¸¢i‰Xçû£+ºPRÓÑD¬ÃÔÏô|7[yßÛÞ¼#_ÔÉXךs‚û¥G¬A(¶ÐêR›u·1š —O 5±z§„ÇϽ£°×a¼J™[”+ýÊ^Ë=ãïoƒ3T GùÚg ;#@šÃBµ¸¾å(Ûñ·-øàæ¡ ,î*óÿ¶Ô2aÌÓT}­o9šÝ„9ž…·ñ-¥7¦*¸Ë2?ë¿AkRïD„ß°2æk¬oÃ?ÚÝ wb×ç#ÎÆµi¨,>Êw8:­ompÀuïtÊë!»èë˜×ÑÌjЃ9c>ce.tï²,Hh;ヒ Wç_ N<û¤—Ñv£¾&’ûÂà2°2îúl‹3Ú²íË»§Ëq& +,¶Eü‡fÛÀA°dªZ¡³$L\ý­‰ÜÅUs³Ö»±W'·1°æN Àq‡Æ¥cOz”ÙW4«p7UqÇg sfÙœ¼-¬¡dÄR¨xXô[‰«?,„îòt& ¼®rÉ^A . K¢v4x¾‘åPq§Â˜¤ M¹«±$ª±µ<$»SØàê7„m˜8OÁëÊ\Êâ.ÈÀR© QBÔˆ7Q¸P·P³WK£Òô–Î5X|KäzCæR×D‰k¤Ì¥`ÉTGdN%ì&q)qÌ[ »éTºÞJì"s vÓ¸Üç"¥QÓ¸d,‰j¸LÌ`pÝ–Hõ‘B%ú›¸ÅÒ¸hÁÓÀsÀ/ Ñ©BÀ/¢‚äT.äV°` ¡¸šâ%á(Îû! E®A±.ïùÂô¹óÅ0K@"vÑ©˜@Iîìœ5~Ñâ…€ø~,Õ©ØÖ•Ù³óK#1 ÆÅ’v§¿˜´Ô%ÄýË`˜rï<›Úp!C£ªŸq’èÂϬѹXÒþ}邆­SYKwÍnѹâØàX(Ôµ-7žþÔO7]ÙºLNsJãU«íÒæ˜á?ö³çg3ÚH5îûY¢>88V{£ Îvkš{ãù£7­s iÞK\ º¬Ð`XÍÃ;xÏrþrN}Lö üçw dª÷ "¬ß=;w¾å‹›ÇVʲOä9£5Œ¥`5·˜#Ë4ÿaŒL%ªÛ¢ªKûþdYG'·}­ýÄ"w¿9?‰bRü™EÏð“`ü`YÁ¤+)|~ï´Q‡Å†ÔðüN\%Få!¸tŽWŒú-Ž)ä†Rˆ¦>:®F  d0_¼ÝÃ7òXëZ> Nî:»ŸÄ嬰[ë¤VÛ²êkj|zä[¾2§µF>fuMŸTÖ"®³]L#Ä-Ø[µáTºzVuóŽ)šÅJóú7ªjŒ¾ã„eµÿ‚ôÑÚp2›ƒ¨ê!ë9šm“O²Ö¸—¿A ý_DU·œZvüŸí–×lQ¥ ‚’­œ¦rмÒÿÚó!Dò¢ª‚8·H’­Ä¬÷¾Fë|óÁzRrxùâøº‡ï¸‚ºçSˆfÀ pÕÉH笓_¼çigÏ|«6°jrE¾U…5Gn~bùÑ£ºrf™¾¥ l©w"á¯{êUبèÀƒMï«iÀ^¸R:qøØ/nîÜ"è‘%ë÷܉ɲʼn3ëwEnìX„4«&½E„> ÕïØ´ö<üi›¦¡úzyg øØk°ž˜ Úì{÷7J\€¶Ï&]kvn¨ò~†`ê­^~‹À3~U[O·ìÙgT“‚'vŒüýú*oýôŽu x ¬–Þ÷¸ÁEtÔÓä¯&È\w|Vmâ2}þƒQ‡4A÷}^ž Þ½¿éL~ÆWù{CªžHÁ‚_[ŠÛ—e§eû6hñœ~—jŒöã%yyŒzOãj\œ•–½*”3ä`º,)ç5ÑÅ1œËʰ1ä5KÇ’¨Šâ$TDy2¡Ç™ú]ª!‘K‹Êk"®sÅøpÊ“ñ¬¡*×à B+ #D{3 ‹ë£Æ¥aÉTâŠàvQsñ¯~±¤8“Æ¥(‰Kž÷â½Y/ݧ:× zK¥Ò6û—Š¥QI7Ž)΄¤· .Uo‰\ãe.Eo$ž¥\DZ *=4"r½*s)X•–6ò¢ý+‘ëQ‰ `þz\NDª\ª T¹`Ak# ?,)~õî-k©Fl$.IßËX&* ËÈ‹ ld.„Ä’ÀÛ3qi¡‰Ër03 #hÞÂìN1\ŽÖê;JÓ_¯Nö1HÄF@&*Kå‚”×OÑжœ9%VU¸Æ‰\ZÄFæ:øfÙ̃h é…åôÆ *s|KâzÄdž쨙ÊÀR¸âø€2¦}OMÉ9AÎg—È}œš&rujˆÄ5ê³æÞ0·E L™ŠY:h=Z›v“¹üxuÏ6• KæZsÉ6 :…ºŽ¾ïÿËŒŠžåëyå:N»Ï«Ñ–€2S÷·å|º%iŸ”‘æ–ö©ã\Œ¶#„ס‡`ye²3°Ã²È2°(QbÙÐ0/ÕæBäycÓ?{ÁRqižCZšaŒœz_½S_ÖÙCëþ‘ñóµÌúöàª^9çëºã¥P˜`˜ÃÕ…3ÄOä]Òƒ!ÊNè?&±K¥–¼ijëñ±êG¾±ˆ†q¾p¬µûЖn\2H³ïßsŠ×2žBQ},$\šüÉëÄMXp÷ZËÙVk½Ö쮣_8mZ×Öd{Ý’å±ÙëvÚܱµåß{±ÑtÄî¨<ïP¿so-‰ãî‡-ïÀ´-Ó['s8_ê¯Ó~;'Šâñ<ˉ]à¡ÌXü‘¡x0R[®ö‹H$Vºá©ŠB¦¾ ›ºØEOÄü}Ôጪ¶°oV 0‘ÜmÙpµb )[ #H…öû ”ãÇ©Ì{+¯Ad/%ÍIø·ÍJbz4“ì<óÀÔ…j}"ê SBŸ„-¥‹‘ÒܧØ)œG5ÿ|ú+ÃŽ__}4®™„ëµß£‰µ‡oäZ^ü(såS)Sžr€ã–yq=ÚDzüîûÞ%õÄÖiK©EQãÎë\!›õ;æË¶'–|òŹˮ=ºŒAº®DÛ<öàÓ[ÜwŠë•æôt¹€—w$œãÞ%µ ŒIoõqÊ ú-€$ŠFmãþñ¶æ'¯M™ËÊØ–I®ÿï¿ó7p½üV“ѹ$¿…1®ñ:×íc‰T‹,[v¤/*Ê-®|ò§jþÑ\VƺÆý¦2'¿haƶo>‘„:—ìN!Öàºm,™êë$•ï÷Ó ß£/«\FYëšð..Í»ê0mgZV&r Q¸//Ÿ¡pÝ.–Lµ=Ãäfaˆñ?¦réeeâߘJ0Â8Il€Š$K]|äsd®ÛÄÒ¨Dí ªþR¸´ø–B…ˆÛîþ6û„ëDT.-Íɺ~0–œ}5¨PÌ'—•I\r¾VjTâÂXÛ'ûŠ ] …k¨Ä¥§9Y§Ìõ±4Ž&D¦RÀãí]˜œOó?.q)¹jé¿–©"éæh$Eo!lää¢U•„Õ‘¸½¬LáÂÑ„…0ð©âeçÀ¥B… ¡¨ók s&.)³¯SÞ³7k=‡›îD„;=§´ºry†KW%›'àzâNæ"ȰýÖ±îüWÛjªVåϹM¦¢=Y««ª·¤Ó¹`*b:JoJß[w"o1Lèu÷MLî;oø²U.S¹2º¼Fš“uNœJAu·Œ…0çgyÏ—Å/,¾ É·õŒê–‡–qØ/ì¢ ÚU® ·zi¢ýëšž½Y¸>Zxh ??nô¯º/æÊ)›hüÐÐl¨QOÑ@lÓýÓàzÜœÂIÑ[½kl´`ÇO§ ù ÕV ר° *ñ禌zÔGΑ0í{üÕ°G+qiÏe*s¯VŒ}dxáß6lÕôÂïßüÝZ‹ç åtÏ‚&^*ÂzNÜùe˜6*”î‡~ébˆ”²}{j?눪'É3%‰ô·?ÜÓ–X\'HÎ3Ÿ Ù¯ìµì¼±}—\‘„ ¡'ߨÿЯ—+’–¿öëû.ÿi4ÊEÔŠ$8¹êìÕô!U– 7JË‚®±5·[JBέ5uœó×HS‹¹•7›{ÍžJG«rÄ^vœaOM²d³ìÑŠ+°{­¸³aÞ{¨«ÍW¬:ýž¶Ls·Ê­ÙýUˆyñ¥«Cëãy^RÃZ}úú qѲçÚÆ­±µD6X6GZÓt#LÙ貤\>ë™q.ê àåÌÑݧ©jŽŸ»{I¤ÍG‡Ò÷«uiü¹#è"KÔº4ÓfÝ)RÁÆþÛ™RfÚì#Luúåìûî~°òrö9‘ÓžÄÞñ÷*ý®l§ܦ2«…·-w\®\ÊèIЇfa¿Yyí÷Ýùl ›Ö“ª0]¹ÉªI–/„ä¢#|ÊfŸð­º¤Óž‰Ãéöæ”ä(¨žVû˜°äbü ½aäï.Ù 9œÀ’;v\9sºó¹'Ñh&DáaI"XÿljaÀ4pêY±P“n0–×JíqŸ¶dÜ8¹:Xbõ7qwùŸò„;0,ì·,Dýz 9máv£Ûð^ ©ý€? B©+,Ëx$ÛìðƒEtG&~c‹Ë¡v¾î0]ž9!„ò;Ë0Õh¨¥V3väQ}me¯Ðž-lg0 ðßyˆ*H)ㇻJ,'½¶F‡Öšª+Sk´ŸmÒ>Ú¾ÂþܘYBÍ«v:ê½é-í}ê- –îw7Ô·à¡îYÎï[é¯W ÖVh›Ï尰뎥 ™+YmJ‹ öÐôK“vdË´ûº0Cw´pfUCX­bŸ[èöYÞ«¶“¾‚˜¨€»×ŸLZ'>qÆ áùí,It/Gý»Н®L*R›dÂNÕ CóÂì˧Vk-Ž¢h.¶ÑÕ÷ÿ¶ tæESÊøIWø£QV.ªïÄ)Ÿ¢·Ä)¯—•íYõ÷O, ÿíw¥Ûx 1ë¼oWZ&ßý,S·˜†%m–‘?¹küˆr8M·a*+ƒù’Ý×ßñèд¬>ÁÀâäDѷߌ7êÙî½%½Bºíü¿ªãõ²²Áü™½_ `”?ž!¥×E‡±v…¸Ì¶ù¥ )}ƒpÇ2PQhQá´ ½tÊ\à‰Gg—Çq6¾IK+ – ¢%¶|NOuÎ6Š6¸Å´`ÑYGÅ’<µê¥×ek¨^—û“Çåº4„;”¶Ç^·3í”Q¶oÆT{æŠ*Ç©¢¹÷|ªÖ¥œvT­Ìj§z—ñûqŒÑ¹¾ÇËãLUIúšrZøó [æÁ±—ö)\¾]y{¦‡ÖSÊa’:½2}Ã…îòaŸÉçW³!}åi’ì\—jÄàúž5&Ñ"°Àø;T·—Œ¼¢rÝ¡H—¹$<µJ ך¤!¡b¸Ì%¶µršrí¸Ã˜ß‰\ð÷+µŒßh^ó0*ÀSËøûÔ4ƒH-*Õ¥é\%î`pÝ®:•òC2×­–Zë\ý¦9áXk€Ÿ^d~7Zâº]ѬqÝz¿P1Bæê‹0«°S÷ʯï³Å¡ç¡ú˜‘-D»‹-Ëy#¡ºŽÞù»G¦Å(T=\à™'ýœa€ 6Ñæ $l”ÑÝë‡.Š™G IJèýQwÍàBéÒ«'¤·F<ûb£ÿ“»k95é--2¥dZµ×TÅÉê¨4•Àõƒxkë[“ÛhÝÀ ¯©PžM^ÛšZ²ˆp«Ö_fÏ×u±ÙJÜ<ž2 :…ÇZùþÊøå½sRM…²£ï®C›'N#´ÕP.?aÔY ~'ÂÉõ–Õݵ½s>dñB+œMß¡Q=b=M±ØG—©Œ_ŠmOÀºƒ¨æñ„½Cp\RYƒ¼ap öö ‘jM¢Ïk*Æž^’–±ÒÎkTa ó9 ”6¸Œ2~‰ê뤻Sy¬„¨÷_—´&ŠóçÇ4®AÞž!SõW< Ø„+ˆéT1XZaѯޣréeü ¬{y)ª–!(O¡C—¼TäÁ5ðÛ3ªþÑäÃMTŠ‚@.s¿F¥a©Tja:¬s)eeˆÁ5àÛ3ªAËÊŒwY( ÂàRËøu*­Œ_¢Rò¢òâ£s©ÂFZ‡®›T©++3½Ÿos*úKåRÊøu*€+‚Jn{B4»å22«, …±º¨.ÂSËÊ *:ÑÑ’`EOH\ÊÓœ‚ó´°¸6V('8 „û”¸Þ#:éö%hW¿XÆXaâ@ã’Êøa-ևĠmù_æoG‡*Tu¸pfæÚVQóxUñœ¯VTs@ã¢Ñ~° J\ÛwÍŸ‘³1Àô-+cMoH¿ã›,“â —´aqªeö.XèØ5}d¦”I8”»Â'NÍ>©p5=òüòF–8Ÿµ‰Õ¹x_,½¨ò<¹ÿ«ÒŽrpf Û«<ÊjTüᜤ磷O^_³–W¯ãXYÓ³H‹â‘™MÞßÚy½éƒ $¦ öÝØ÷æŸÃÄlùqƒè¥%݋ߚNÄîæµëØÕ÷ªíV©P [quýks¨ŽîÔÂãzñ9ù]‹~Á¿úKù¥yMÒÃ>Ò“h÷V‹-ÛÊ«6í¼qìwÃæÑñk¤sfÑ·û,_>ó,ß”×=²5› §?õP; Òƒ¸´ÈÈkO4´¦¼Ú zJ%*Ùàîõ_nɸêµÓÅ)a7„®yøÇF¯Xuå„å4cɼ±g{*ÚHŸÜ±½H3œ*ðc4:.KÁ<ñ 4±²üú︾ÅR“XÐÌâhrÿv>z=cb'Êo<™l¢1ì͉5f„ñÄ-|Æ’nT2ˆq…Mݯ=þŸ#üx^ˆ0»Óäægk²\ªm]½õÆ.Ë7ðÝŸ])ÏuËǬ¶ÆÇ®nUä”­: GpϘ Š¥WÔ×ÕºÒš»>˜Àm³»V¼Ëi­u/ø†‡˜é@Ø¿T1PÛ`ÿiާÖ,¸/ªÆE-6;J¿øÒ•‚¡ö®<·9¾%^_F—QæØºËU–=QË¢ë‡7rŠÂŒÂL,¦‰O(W\þÈq…ßÁP^"Ìâêk³,ÂrKc¢¨Ž„"ܶ}<ô]ƃÅmÛϪÌâT´BÒQåHÏoí™6áÛOïê$óÛ‰,é…CªênÏ$ˆ_}ì×¥…ÕŒvTŽ«(k«N\9ùˆñIV,7R@8Xr­vü“£ÿÀû³¤ŸÒ ùBôÏ÷Ž|±²+ÓMé°^Í0ß´çúÑ»ž»#ëRÝ|¤bé 6®½‚•·Ý82Ÿ}¿TëLàÎ]UX†ÏqHŠR¼‘¬×]‹¶ÑÉ9PŒpE{/•®*èܱŠGÐïm€è˜Õv¥vþx,ý"cžò©\´Ìwåftkz'Ñ–üôõòÍKî9ÇåHˆµÌ<ˆ~ÛÓœ·Av;‡3Kc7¯Ñòq ½…†0Õ3NSß%ìé{SËÊRé1z_nnNN) AÿfئÂìœì»¿Bèàª\q_~ŠS•"oÍÊÉÉÚAáýèkÐ],˜‘Kõò½¸€€µy`½ò¹¯™pw°´žó!„NÒ£l¯Ð[£’V>än§™^kbŸŸ¡$… 2-BP„é¨R>i~‚‘$z ó*Å è!ûÖþ?Öiÿù0¢¯cÚ’%tEXtdate:create2017-06-06T01:31:15+01:00\uŸž%tEXtdate:modify2017-06-06T01:31:15+01:00-('"IEND®B`‚puzzles-20170606.272beef/icons/slant-ibase4.png0000644000175000017500000000336213115373745020010 0ustar simonsimon‰PNG  IHDR  ®¤8ñgAMA† 1è–_bKGDÿ‡Ì¿ oFFs  m1ÉtIMEá!:ÔÖ; vpAgAAŸ{üIDATxÚí›Ûº£ …óèy4m¦U `ÎÁé\ÈÅþZc–¿¨Vݘipœ ¾íúÌîjþW¯O×ZTl|œˆa#„Lþà{ ð(ö“ÛˆØÿ¶kŒÏ'ý'å'ÏÓ ÷ äóAÉOâÕ­È}ïΧ€R~ðvÂðP~–¯XË÷K½¿Ïk•|#;Ì|äÇíÓ€–Êß ØhèS"ºówNû5“¿p¾}„í‰ü]€3Š‘xþÀ…•X8àÊ€j4š_¼lŽW«=dç׫÷˜'¿X}J}ùyÀê8çÍÏVg ¾Кk¥¹”lDf›™ï´ª¥{ãm‹'ßHk4®Þ›ã÷ƒ·£K|z¾ ¸¬}]§WT"ŸC\ºÒ¢íóIÏÂMàŒ Ïwír¾HVmײ—9cã ¾.ç€ß$ª÷8üÝùx'Dþù½ »»$Ë|l7âƒùñ¥u`ÿtÈé ÷Š£r}Øø’HË—À8=ƒæ3‡ €h¦ü¿!6d} Úƒ‡àÿõϤƒ„˜=XºÄC†D ³×=¨ hù~O{Чa&èÂu†ÒT2ÅAîu-gÖ÷å+ºÅ xŠ‹þ¡[ ÿoˆÎ»ul.êïïõÏC ÷òØQÕ‡£YOõÉxÄúT ñ~¡ä†¹¶õ`Y_ð÷6"”õoÏSŒ¤ÿÒOqIçµü?± AÎwë÷䑞›€¸fõáöÁùÝÜæ/¶íiÿNܾä§ýÁko«”òå’½ö{ó誨ÀvEÝk’8`þ 8¢þU[.žÓ¬‹‹€9ý³PLéǼ™"`F?ènúQ°×;¬EÀ°~Ü£.Fõgç!À >7vζÉvÀ˜>;ÏL…ð~À>?…'#úÂL= èK¥Ä0uô뛾ÜC€n}¥”=žôê+Õâ©ð S_+g¿ ÏúôÕzû£ð  KßX †" Gߨ´WСÿíeÍè3âÕæ¬]åÇ{ 3^ô݃ú^v<è}ŠUG< è5O<™IW<›‹e_<­fDg< ¯%o<˜©¨w<˜[“XþÝ>ÿ0»ª³ü»]þa~]lùw{üʳ`ùw;üÚ7cùwuÿ°ênYþ]Õ?|Þ¬ù‡u‡Õ¾G*þaÝ£¾«Äã2@Ýågtq  þ; §”‰óÉ_šØ´^ f«;Rï÷ÅýC$ôþà=Ù|ÿ#€Ìø¢ê/€ìx8•}€Ÿ®ë X§Šù‡Üõ=Úýq˜ìû}~ÿãúÆÿ ÿß{ ú~Ÿ×?äÔ ê#ú{3Ý™ÖøýËd<ŸÈŽ/­þø+ ®§Ð?@éÿ‡-@~ méüiOÌ:ý=ö°=Ý€™÷Mûß!X¸ÄéFÍKÜ.Óý1Ì$žâ|;ŦaFzŠ?Q}œªv!èH&ý@i¤Ï¶£Ê3=æ¬ïeB§~Û~_ÌÌæ€mÑ÷‘Q@öó>B—>rEëªx -øþ –暡Ԝk’ÿº½€/à¯Û øþº½€/à¯Û øþº½€/à¯Ûûîk÷‘%tEXtdate:create2017-06-06T01:31:33+01:00}€­Ù%tEXtdate:modify2017-06-06T01:31:33+01:00 ÝeIEND®B`‚puzzles-20170606.272beef/icons/slant-ibase.png0000644000175000017500000000445313115373745017726 0ustar simonsimon‰PNG  IHDR  ®¤8ñgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿ oFFs  m1ÉtIMEá!:ÔÖ; vpAgAAŸ{ IDATxÚíœÍk\eÆ6iÃÈ é¤“¤AЊâB‰Ù.,b›”RºÛM¬ EmZ\tãFºéfªz'X ]ôSMcÁ4*÷ÿqî½ó}ÏyÏÇûÙÌ»˜¹É3çäa:÷ë7Ï)@Õ²†¶ãt=3åµds{{!€³>¾5 {¾M·¶wÇØ‚jì^¸^yØÜÚ80›lü1a¨JPü>Û$ê§k­Í/¦kF_eL¬5~EÔ .œJ~±öèÆA€CÉógÔõŸ=¥++++·õFƒ«û·ê£®§®ooMÞT׿žÕÃkŽz£ÁxöBýᣙò®‘ïÝM~±xD_ßiª·¼3ºÒõóõÑ{~õcD½Õ`T(^ïì_,,yÕW®ßh0* £‹[Ÿ¶÷ ¥%ú1ÊŸÑ`½iéîÜä|´¾½þÃüä‘{µáPXOþ}“Á¨áææÂÌøÐøÌB²ÿQ¥õ! F^Z:áP\Î`Wÿw(¯e°»§Ž:TÔ‡1ØÓ¿KÇjêCìíß­#Uõþsý{ô£sõ¾#öª9ß!¾ÞÏ`$øŒÕŸ1I½ÁH´—ÖȽTVo7 s5â8'­·ŒÄgŠz¦×Ë ®žž® U¦O¯ý;uÊa³¿¦^hðöá©SËÿy¸|jÿ줗N:¬’þõ"ƒWËŸ46Ÿ\@®÷ºô±¯(‡UÊŸ³^`ðjåÇŽŸVrWÌ=z…rX¥ü¹ëYƒ·ËõúëoM M¹‘tØ{7¯_;þ|iäÀ‰DëÖ[«¸¿´>~|rjxßñß±zÎàá‹õ‡KÙM×î_ëÛ‹syýÍLß·‘×[«øþ‘ÖÿõBZ_y€Õ» ®N%Ÿ¯/ÝüsùÀ|Ü{ߚ野}·ñÍ8ÀBŒÝ×f«øþ›Öϼ{ï,À\¬¾/þðtkólf þ`!§?N>8šÓÛ«èñ/«/ÃÐßq¼v=Fë]§—ÿ®½Åô ½Šéqü À™œÞrX<ŸÓúßž«?XÂëÓUœÁÉ_ÒÍõqDã{¡¸žÓÛ=¤õ?¼Rzà2QŸ4ñ?Œï|ÎQýë_®?½ÔñAŽÿ)øú¦õõâgëOodÿÄ:>Èñ?9ß[Ä?ƒi}¶“Ld;‰ŽrüOÎ÷ªè½^VŸf>Î3J>Èñ?9ß«¢÷zY}ã@½ïA¬çƒÿó½*~7šÖ'§º¡ìT§æƒ¿SñAÄá²'äøŽ"¿¬8ûs9~§åƒ˜Ã²äøž"ºäø…bº•rüÎÆåü3Èñ;+”òCÎ Çïì|PÆ9ƒ¿óáƒ~Èäøäù!gãw¾|Ó9ƒ¿ó僼î6Èñ;_>(Ñ]9~çËe:mãw¾|PªS9~çËåz·A)ÿ‹˜s-æ€ã‡">(äsµ‚8àø¡&<ÿÓ~\K®ÝüЩ÷ð?í7êµBÑͽm°É÷0þ÷èýéݟLjμ=êæ‡©ÞÙŸäƒßKùÝjzÏ–6 ùaã‡âþ€ó½ŒßÝ?yùD³2ÃðCyÀù^‹žo6 ønã‡òþ€ó½ÿk7 ønã‡òþ€ó½ÿk7 ønã‡òþ€ó½ÿk7Àù“/¤ø!ÖŸàƒ8ßkñÁvƒ ù@y‚ïµø`Çg$d>PÞp¾—ñ»ÿ67.mnætÎ Çåý ¾—ñ»û ¼[¡óòþßKù]gƒÀù@qÿÆÅBŽï‰ùa0Woíß0˜ç{R~Gì­7÷O ¢|OÈï(ƒÝõöþ@ó=¿# Æ?òAß“ð»ªCãø¡ŽùX÷çƒ6~'×ýù ‰ß)t>háwÝŸøJ÷çƒz~§Ó}ù ß)u?>ˆulЋ¢Bôàƒx‡àÍ|èÞ ’b/Àò ªúãßvæóA júß÷æÿTô§¾qïÎÿ7(ïO;ó}0(îOGDÛù¿¾”öw„l›ù¿>öwÅ”³ü_ß Êú;sÔIþ¯EýÝIô$ÿ×Gƒ’þD¾Ëÿ…Zç€7H}CÓ|£{½ƒ‘à\,¹pºÁHô¬¹°ºÝ`$Ü‹ÝxÝj0ºÍ`¤8“¸Ht‹ÁHu.v8ézƒ‘òj†v Óµ#õõ !ÿça02\Q[òVƒ‘鞤Où?D·Î÷'ÿ—×íóÅ}ÉÿåtŸùâ~äÿzu¿ùâ>äÿztßùâðù¿nݾ8xþ¯K1_:ÿש‡™/œÿëÐC͇ÍÿµõpóÅAó-Ý:_lÉ÷Yø¡y¾Ø”ïÓóCû|qò Ï÷iù¡Ç|qö¤Î÷éø¡Ï|11ßËæû4üÐk¾˜˜ïåó}r~è7_ŒÏ÷Jò}R~è9_ŒÏ÷Šò}2~è;_ŒÏ÷Êò}¾ç=_ŒÏ÷ ó}¾ç;_Üžï5åûÿ ñ(æ‹ñù^y¾Ï¶óÅø|¯<ßg[Šùb|¾Wžï³-Å|1>ß+Ï÷Ù–b¾˜˜ïçûŒK>_ÜxÎÍKó}Æ¥Îæò{Ò|Ÿu)óƒH~O˜ï³;ÔåI–ï³/a~pØ‘ßKò}ÃL¾ÏgIús§Ò_ƒƒ;½wz  îôÜé5080¸ÓëØÐYt*D%tEXtdate:create2017-06-06T01:31:15+01:00\uŸž%tEXtdate:modify2017-06-06T01:31:15+01:00-('"IEND®B`‚puzzles-20170606.272beef/icons/slant-base.png0000644000175000017500000002732113115373723017550 0ustar simonsimon‰PNG  IHDRAAflŠfbKGDÿÿÿ ½§“ IDATxœíPTåþÇŸîn‹ƒ¢ë½€(™æµ6EðZY¤æ¤A-›æZ ZDêmøy£{G˦Â9 ˆn“øÔœF*H±;Ö½3âEÌËZAʯ%”•…eùþqæžÙïþ8{öœç9Ïóì>¯¿p9|øø9Ï›³?Î9¯û®]» µüw C,à ݰ 3tÃ2Ì`Ð Ë0ƒA7,à ݰ 3tÃ2Ì`Ð Ë0ƒA7,à ݰ 3tÃ2Ì`Ð Ë0ƒA7,à ݰ 3tÃ2Ì`Ð Ë0ƒA7,à ݰ 3tÃ2Ì`Ð Ë0ƒA7jÜ HÁh4ž9sæÂ… ýýý“'O_´hÑòåËçÌ™C~}"÷ÑuoÚÖÖV½^ßÜܼbÅŠ%K–DFF›L¦öööúúúššN—››;}út2ë3С)Ãõõõ[¶lIKKKNNÖh4Î WVVîß¿¿  àé§Ÿ&­>ƒj2\__¿uëÖ’’’yóæ oyåÊ•ììì÷ßß«˜¡®Ï` ‚Ž ·¶¶¦¤¤”••qëëë3 MMMF£qxxPPP°zõj~û+W®dffVVVN›6MB}ÀÀÀ@yyù?ÿùÏîîîI“&ÅÅÅeff†……I«Ï` ƒŽ÷¥õz}ZZ°®®®#GŽ455qv&::ú•W^ÑëõÒê®[·îСC###===ÕÕÕ/¿ürGG‡´ú :(ȰÑhlnnNNNæ Z¿~ý®]»Ö­[çî§RRR®^½úã?J¨o0®_¿X³fM]]]vv6 »»ûÃ?”PŸÁ@ ®««[µj•ý›LS§NÍÏÏOLLÔjµî~* `åÊ•uuuêŸùäùóçí±Ùl&“Éd2Ý»w{Äl6sØoV__ÿä“OJ¨ÿ /¬VëÎ;ÛÛÛ÷îÝ{ûömÀ²eË&Nœèm}ø¬V«wïÞííc¯ÏFùù+ñžVll¬œÇÇÇ×ÔÔX,þ‘ÎÎθ¸¸¸¸¸½{÷rpð›Y,–ÚÚÚøøx õ7mÚĽýé§Ÿ&$$ìÙ³ ÕjóòòømÄ×·Ç~K~q±>C,óWè}i91ž3gŽN§«ªªòê79rdÞ¼y³gÏ–Püøñ‡^¿~}DD„Z­Öjµ«W¯>~üxDD„„ú<,À¾ ®ù+wý0ãôôt.Æ^ý'sss×®] ˜:uªð{}Ç—V0qâÄüüüüü|wõ<èÕŸ`ßãüý|XòÑxúôéÙÙÙ7nllüë_ÿ:<<|óæMDõsrr¶mÛ)²> °oƒwþJŸã!9Æ‹/~ï½÷233÷íÛgÿÚՋŲoß¾ŒŒŒÑÑQ¢úYYY|ðA\\œÈÊ,À¾ öùc8OKNŒ«ªª®^½š˜˜XXXØÐÐÐÕÕ522ÒÕÕuéÒ¥ÂÂÂÄÄÄï¿ÿþرcƒ]ýªª*` óÇs?-ɯ§M›V\\üã?ÖÕÕvttp'ZDDD<ñÄåååÜ›L‘‘‘Hë‹„Ø·!dþØî‰'ç-®Ù³gÏž=;33¸?Ïu}°û6äÌç52?7Æ^_`߆¨ùc¾nÉ'cÌìÛ6ü×úXŒY€}ç?ÃÀ‡bÌìÛ9"2 |"Æ,À¾ ±ó'%Àò³û6$ÏŸ  jcÌìÛ>²2 (Œ1 °oCþü‰Ë0 *Æ,À¾ ó'1À’³û6´ÌŸ\ÿ°œ“%eÖ·÷›L¦àà`gÿ°œŒº>jÄôOr}1 Þ¿AîL“yßÀË—/s1s7J¸õÃÂÂÄø‡»»»¥í`‘~cÉõ{ßFßó?»œäcñW“žaà)Æë4͆ „ýÃüÆÞî`‘~cÉõ]1Ã>évžäãòW«ÒÓÓaÕrÉ/¿üòÀÈ©{úôi«ÕzæÌ™¹sçÚß@Výšš•Je0T*•Ë-U*ULLÌ‚ jkkÇÆÆJJJ¼ÚÁ[·n---ETßòçÃ!¾ÿØØØ¼¼¼™3gFEE‘Sßó‘`,ý*ŽÃîŽÆPê·¶¶&''———súÒï¾ûîÔ©SMMM===ÃÃÃáááqqq¯¿þ:¯h»råJzzúÑ£G¥ù?ùä“~ø¡¯¯Ïjµ†††FGG¿þúëœCB}`ÍÇÛþåøŸÅÌ–ÿÙ~>ržBcôWSpæpw4†RÿwÞY¹reBB÷Ï;vÔÕÕ™L&‹ÅbµZûûû›ššjjjV­Z «®®~öÙgEÖ_±b_ÿìÙ³‡ºsçŽÕjµÙlƒƒƒ7nÜøüóÏŸyæn™z[_Xóñ¶›Í&y>bæïU}øùÈyË¡ÿÁÁÁ”””sçÎݹsÇf³™Íf£ÑxêÔ©åË—sâ.ˆýb?[r ¢œœýÃ*•ê¹çžÛ¿}}ý'Ÿ|òûßÿÐÓÓsôèQ~9~㨨¨Í›7Ÿ}úܹsCCCÃÃÃïÞ½Ëý=züñÇùjâë #þ¨ûG=a~ùå—ÞÞ^9Ÿ8÷Ÿ——wïÞ=µZ}àÀ œ  úË_þbÿ-i~cž§žzª¿¿Ÿû:,,¬´´Ôaâ7FÝ?êù STT(çc<ìþj%2,ÙÐ+Ìk¯½Æù]u:"¿ñ76nÜh2™Š‹‹¹f<2ýÆ&LâÔŠ·nÝÚ¸qcEE…ýÿB¦ß˜GfÔý£ž¿GÌfsNNν{÷¤•’ã¯æÿÊA‰ £ö»"òsïs íÙ³gáÂ…HóóÔÕÕzzzôzý_|Ñ××WZZjoÊ“ã7æ‘ÿÙêþQÏß#p×Wþêàà`‰MÛAßëaðÿý®ˆüÆ_ýõ† þð‡?>|Øy©~c´ZmJJ ÷ukk«„ú¨AÝ?êù }ý(à¯v€¾ ;ø]QøOœ8ñæ›oZ,–‰'þãÿ0›ÍW®\¹råÊ7ì7“ì7ÎÏÏÿòË/[ZZúúú®]»Æ¹Q/ ¥ù¡ƒºÔóÅúAê¯v†šó´8œ?Çãê{¼4B£Ñ˜‘‘Q[[˽éHKK»xñ¢ó– .ûì3>^ÕG êþQÏ_ p×"µ;¨9» °}}ÉMÛÚÚÖ®][ZZÊû‡…illÌÊʪªª©/mkkKJJúè£Ä×OOO?~ü¸x=ª; Ì_ù ­/ëG:ŽÃ"O…SÌoì­¸»»{xxxÓ¦MˆüɨA=ÔõEBìú†‚s-…ìP_øBE¢¢¢|ðÁ·ÞzkllL§Ó©Õ.>u³X,ܱcGAA·úR›Í666Æ}#\Û¶m###¯úw¬s]ÑÍG™úî ýx„ô {<;×—³âãã«««‹ŠŠz{{5Z­Öh4½½½ÍÍÍÇŽ{÷Ýwï»ï>½^ÿè£J迤¤$55ÕcýÂÂÂeË–Ièß%ÏWG1%뻄ðõ#¢_‹y í®¾œw9ÿðÅ‹üà PüÃbêËé߸Ÿ pÀš®úö¼~DBn†E¾¨%~Û?«OÅü±ïiA¹«#íþaŒý3=ó'1ÃoËJ»˜–eä«P1â2 ý¾Ê´û‡©XF> ùó'+ÈnŒN»˜üeäÛ>‚2ŒÔl@»˜ðeäó<R2¬€š„jÿ0 {ùÄΟˆ +æ¢Ô?ÌCì2òÈœ?þ +,£Î?ì™ËÈ pþ˜3ŒÅîG‘Ø%.#¿‚´ùãÌ0F='þaH[FþQóGrO<*üº2ýÆØý´2ýÉ ™ öc‹òq¸µµ5+++33Óf³ååå8q¢¡¡áĉyyy6›-###;;»­­ {€9$ÿ5•#×3Éýíφ£1Ìk(õëzë7&ÍOë­?µ¿.ä×GíÇö´ã0ç_-++{õÕW]. €F£IMM-++ã­Àöxõ×T¦ŸVÌ|öìÙóöÛoûí·^õP©TåååÐë3„Á~4†“áÖÖÖ-[¶”””ðþØÍ›7¯ZµjÑ¢E ,X¹råŽ;zzz¸£££ C@@€ý-Âð"r7Èy íÕ|vïÞ½yóf»:;ªÑh>þøcDõÂà1œ ëõú´´4^ \UUU]]ýÓO? ýüóχ~ñÅí—Qjjª^¯‡òÛ¡àq7Èy /a>¯¼òŠøùèõú 6 «ÏðÆCÈ0 þX(ì¸~ZÔ~cJçO;¸b á~ZØý±¨ýÆÐý´¨ýÆôΟöú(üØpÆë…ŽƒßºŸ ÷S=ÚîÇö„ ãõÇ¢€ß £££EEE2?ÇÆå7†UŸá-öëõ}c”ó´~ûí7ŒþXnFrüÃîØ¾};WÜl6—••A÷ÓÄ~cXõ=‚È/º~KK 篈×j dxòäÉTûc¸ví:/j¿±2ó'ÿ —@ôW À­¸5ð\šv,j°ø›?ÀõWcB†i÷Ç¢Fy¿±’ó§èþjì@Èp|||MM w 4ÇéÓ§m6``` '''ù¼ÿþûü6‹¥¶¶–ÿ¨CØOvõ|°ÏŸ"\~ÎOøúñ„ ÓîEò~c¸õ}DþjìÀ¹~877wíÚµ±±±œuß¾}ÂÛ766VTT?~Êoç çzNgrss“’’ÐÍGÂü<èmì©Æã™v$¯aàœ/í­‘_—Ø¿¦¨ýÄø{‰µ¿/ÐÜ¥âý«Hýº’Å“"ëK@ÿ0!þ^èÐâ¯vêù¸÷ñX¼xqUUÕÕ«W ºººFFFººº.]ºTXX˜˜˜øý÷ß;vÌ`0 ûkGÔ_SûTZZzìØ1tó9ÿªª*ˆk‘p± QëG HÜ¥$øuIð÷âò“àï%¡>.µ˜úÁéFíweþaáúP ¶¾ŸÌà½7-ê'-Ì?ì·øÕü1ß#Þ'cÌüÃxñ·ùãwµøXŒ™/~8ü>cæÆ‹Οˆ Ÿˆ1óãÅoçOJ†å1fþa¼øóü Ê0 6ÆÌ?Œ?Ÿ?YƘù‡ñÂæO\†U1fþa¼°ù23 (‰1óã…ÍŸç¹–qw²,¿®˜“éÜõÝ?,³XàªÏæÏCèq˜µ_×÷üÃ"vØüí!:Ãàÿ)###99966¶¶¶6'''&&fÊ”)jµzÊ”)111999_}õÕüùóSRR¼zµäèKSRR°÷O;lþ@»€;ä_Í]–]SS£R© CBB§/vF¥RÅÄÄÄÆÆæååÍœ93**J|}w—};ô/Ó?\ZZŠ·è(\ŸÍßÒÃ~ÝÆÆÆŒŒŒøøø DGG/[¶ìoûÿÂ^‚_—vÿ0 G€5ÿ¾¾¾íÛ·'%%ÅÄÄèt:NW]]ÍoLÝüéȰƒ_÷¿ÿýï¹sç:::†††¬VëíÛ·Ïœ9“’’òÃ?pHðëRíÓ?í@œWWב#Gššš†‡‡]nO×ü)Ȱ³_7**jóæÍ'Ož<þü‘#Gf̘®­­å·‘à×¥Ô?,¦Ú;ÿ   õë×ïÚµkݺuî~Š¢ùSðzØÙ¯;}úô¹s熆††‡‡ß½{—›×ã?Îï]µ$¿.þaýÓþzúü'Nœ÷ÐCÆ‹/þüç?;|ªDËüÇag¿.ÏèèhKKËéÓ§AAAÏ?ÿ¼ýw¥ùu©ó ÷ï퓊ù‹„–ùSaw~ݧžzjÞ¼y«W¯þá‡ÂÂÂöïßïÉ~]ºüÃÎ(ì¿E êù @Ëüáx„‘©otç×0aÂÐÐÐÐÐàÖ­[7n¬¨¨°·ÈÊôëÒâvß?R}&:ÿ3ÙlÎÉÉA1a`Í5Jd‘¿—»ßzOO^¯ÿâ‹/úúúJKKwïÞÍo ߯K…X(ý{¿J}wó÷¬ùKþq‘Pð\Ú¥_—G«Õ¦¤¤p_·¶¶Ú‹¿®oûQû{å×^?P1@E†ýºùùù_~ùeKKK__ßµk×öìÙÃ=î𲇿®oûQû{å×wž¿Íf3™L&“‰7Ñl6sØoFÅüvöë~÷ÝwÿûßW¯^ýôÓO¯Y³†;»uüøño¼ñ¿ 9~]Ÿ÷~¡¨óü;;;ãâââââöîÝË= ¨âââøÍ(š?vö릤¤ÌŸ??$$D¥R7nÆŒIIIŸ}öÙ#<ÂoCŽ_×üÀ$ÇØçç¯Ä{Zòqð÷¾ñÆö‡\gPøå€Ú?L¨ý½rê;ø™§N*|Ù<]ó§à8 Ðû{QC{ÿ"!öhLˆd˜û À}b¾oß>û×6öX,–}ûöeddŒŽŽ9g˜öþ½‚Ø/^¼ø½÷ÞËÌÌô½ù“ža%ý½¬(cüØÐ!ú~Z¸ü½¬ùõIöKûÒüɦÝK{ÿòëÓî—¦bþ€ØçÒ´ûciï Ä>©&¤>,HÌ0íþXÚû‡í1£bþÄe˜v,íýC‡ö˜‘?²2L»?–öþA{ÌŸ?A¦ÝK{ÿH¡=f$ÏŸ” Ó =fÄΟˆ ÓÅ =fdΆi÷ÇÒÞ¿ÂÐ3ç9ôûciï ´ÇŒ´ùãÌ0íþXÚûÇí1#jþØ2Œ12wíýcG £ÑXRR’””´téÒììì¥K—&%%•””F(õ©è_ö« ÁÞÂüÒ2Qèc†;˜_Z&Êù‡IöÓ2ðâ‡~éƒz{w(zÍ;3\B»ŸÙÛþsrr¶mÛ å·+}í!‹1ÃÚýÌÞöŸ••õÁÄÅÅÁjÃ=XŒ<´û™%ô_UU1À£»”d?­˜ú°ðçú´û™åôœþaæõçú´û™å÷ œ÷¦eOªýÚýÌD]OŽùñ,Æ~í~f¢ °g°û´û™I 0 !Ã€ÅØo ÝÏL`€!,Æ~í~f2 ÈÉ0`1öih÷3`@T†‹±B»Ÿ™äÒ2 XŒ}ÚýÌ„˜aÀbìCÐîg&?À€Ì cŸ€v?3ˆ®6gΜ¹páBgg§Éd _´hÑòåËçÌ™#²»Þ˜XÄì_9 aý`ï_<Ï—nmmÕëõÍÍÍ+V¬X²dIdddpp°Édjoo¯¯¯¯©©Ñét¹¹¹7 Àã9±2ÏGE]ß#tÕ¹»»»¥€õ#9ÀÐûÌ ×××oÙ²%---99Ù¥¾qxx¸²²rÿþýîníïŒðn¿FQ׆¢ú"÷/­· dýH0¢þ=Í·T__¿uëÖÒÒÒ„„•Jåú—©T111±±±yyy3gÎŒŠŠSÙÙ‘cù¾Ôõ…¡¥¾øý»`Á‚ÚÚÚ±±±’’¯@Âú‘`Dý{Î{Z­­­[¶l)))áõ;w?þ’%K6oÞ|ëÖ-î[úcÙ[\Â8ì_~`ƒÁ!­>t/j¿4êõ/ œãð;ï¼³bÅŠ„„ƒƒ)))çλsçŽÍf3›ÍF£ñÔ©SË—/ „……Ùl¶êêêgŸ}Vä¯p÷×Öqu}wPQßaÿž={öСCwîܱZ­6›mppðÆŸþù3Ï<£Õjaaacccâ÷¯Cý;vÔÕÕ™L&‹ÅbµZûûû›ššjjjV­ZЬ9ob)°þ€pvö¯ †ëׯÖ¬YSWWÇÙ庻»?üðC~rü±ŠÕ§Ô~`Åü½ˆüÒŠ­w@Èp]]ݪU«ì_ÄŸ""B­VkµÚÕ«W?~Üþä; þU`, öc÷÷y1Vlý»ÎuKmmmk×®---åü«illÌÊʪªª¯ot`òßòúmmmIII}ô¢ý+¡~zzúñãÇåë?íç#Yþ¢ÀúÎ5Ó§O/((ÈÎÎFä_eG`¼ öëâ–|4F½þ…víaTTÔƒ>øÖ[oét:µÚŧV‹åàÁƒ;vì(((¯o0× P]Ÿ›¿Ífã>OB±Å×ß¶mÛÈÈÀùBB 8ÌGøBEЭ@Ë0 ***>>¾ººº¨¨¨··W£Ñ¨ÕjFÓÛÛÛÜÜ|ìØ±wß}÷¾ûîÓëõ>ú¨ÈšÀäg€êúöó/))IMME·EÖ/,,\¶l™„˜¹Äy>rb }ý‹‰»–UÌShÚTbjzIDAT*^ORZµ_—dÿ°œú~䆿«ßÖG=òýÃTø«±÷¦eobáõü©ðÓr!*‰fÆ æ`1f˜/˜ƒÅ˜¬ ³ã…ºsøyŒ Ê0 0^( 0‡?ǘ” ³ã…êsømŒ‰È0 0^| ÀþcüfƋϘÃcŒ9Ã,Àxñ±sø[Œqf˜/>`¿Š1ÿ°ü9À¨ý´$ø±ï_ÿ0j¿1Ýþagàú]EÖ‡¯d?-!~`Éõë— Cê7†^_ 2 ÷/4EFí§%Ä,¹¾K ú¥fÆ ˆüƈê{æõÃ.åwY:Êû{¥ùiÉñK«ïX~éšš•Je0ùÑÕ÷ˆ¢¯‡±¿FÂç§-++ãýº§Njjjêéé‹‹{ýõ×9ñ'ç§ÍÌ̬¬¬˜È©o0ÒÓÓ½õóõûúú CSS“Ñh¬^½šÛXB}Ô„††j4šòòrDów¨ïq>ÞÖF¹÷¥ý6À½^Ÿ––Æ ¦«ªªª««úé§¡¡¡ŸþùðáÃ/¾ø¢½&û•W^Ñëõèꧦ¦J®ßÕÕuäÈ‘¦¦&n:ãm}Ôèõú 6 ¿}}1óñª¾0 eØŸŒÚ¯«|ý   õë×ïÚµkݺuî~ ¢_W&>?%žKûs€¿.¿­V›ššºsçNàÆ¯ëñî-Êן:uj~~> ££ÃÝO‰¯ŸŸòã°|¿+í öë*__$°üº2ñùù ϰ|¿+í öëâ­/,¿®L|~>J<—–éwõ¥þ^ɯ‹±¾02ýÀ<ôÎ_‚üÑéw†üs¬j(êÆŒŒŒÚÚÚ€€î‘´´´‹/:o¹páÂp_[,–ÄÄÄòòrŸ=(_ÿæÍ›Ë—/w¹ñåË—¹ÍÄ׆Æù+9 Ø9D]o©0¨ýº´×GÏÏGÑë–PÉ?ô~Z õ½ò÷bôëâš?-ó ßÇÃoƨý´ÞÖ÷Öߋׯ+ßžÒ×JCЬXõQûiÅ×—æïÅå×U~þtÍ(Ÿa;Æ´d ÷ÓŠ¬/Ùߋů«üüéšÀè.Eí…Šú¨ý´¨ý½JúuqÍŸ–ù¼þa*ü®>\ŸÍ_¸>óxïMë·oq›¿0´Ìó=âi“¯Âæ/ óÁïj¡bL> ›¿0äφ còmØü…!|>Dd?&Ÿ‡Í_’çCJ†ÙcòØü…!v>e<&?Í_2çCV†©còØü…!p>Äe9&¿‚Í_ÒæCb†ycò7Øü…!j>H2l4KJJ’’’–.]š½téÒ¤¤¤’’£Ñ(¾QcòCØü…!g>3ÜÚÚš•••™™i³ÙòòòNœ8ÑÐÐpâĉ¼¼<›Í–‘‘‘ÝÖÖ&²9còOØü…!d>03\__Ÿ’’[[[›““3eʵZ=eÊ”˜˜˜œœœ¯¾újþüù)))ß~û­Èš„ŒÉoaó†„ù@Ë0ç§-++{õÕW] ”&55uÏž=o¿ý6‹1-°ù ƒ}>p2ÌùiKJJx}ãÀÀÀÎ;ãããçÏŸ¿dÉ’Í›7ߺu‹ûç_ݼy³ø»òb“ŸÃæ/ ÞùÀɰƒŸvpppݺu‡êèèééé©®®~ùå—y œÿ*[Fxaóã| dØÙ¿j0®_¿X³fM]]]vv6 »»ûÃ?ä·‘à_eË/lþÂàš„ ;ûWOž< P«Õùùù‘‘‘7näœgÏžà¶áý«^ý.¶ŒðÂæ/ –ù@Ȱƒµ³³³¯¯9nÜ8îÁY³fFGG›››ù-¥ùWíÇÄáJÂæ/Œòóaÿjoo/÷Å„ øƒ‚‚¾ døWù1ŽŽ¢¾/'Ã6ažwéo¿ýæÒ¿:66æòk™~Ú×^{­¸¸ Óérrrzè!iu<‚ÈoÜÒÒÂõ_VV†´>Å|¶oßÎ-PJçº>¿>Q!Ó'O¶÷¯†††r_ܽ{—ßæÎ;ßòü´ f³™F¿±}ÿ¨ë£›Ïµk×t:óG]ß~þЋ;á¹´ƒ5<<<$$póæÍ¡¡!îÁ––€J¥zøá‡ù-%ûW9û³ÕjU©T4úíûGqVr>4Î5¨÷¯2ìì_}á…V«uçÎííí{÷î½}û6`Ù²e'Nä7“æ_å¤V«wïÞMߨ¡ÔõQχºù£õþuB†ãããkjj, ÿȦM›¸7¢?ýôÓ„„„={ö´Zm^^¿Åb©­­÷êwÙˆòFÑ.ûG]õ|(š?jPï_—@Ȱ³uüøñ‡^¿~}DD„Z­Öjµ«W¯>~üxDD¿ÿªÀ€¨XFXÌÁb¬X `k™››[QQqåÊþ‘‰'æççýõ×W®\©¯¯/(( ã¿ÛØØxðàÁÜÜ\ñ¿Âã€_FÌÁbŒ\°2ŒÚ¿*r@Ä.#ìæ`1Fƈ×.^¼ø½÷ÞËÌÌÜ·oŸýkc{,˾}û²²²>øàñþU¯Dà2"$À,ÆÐÁ`÷‹/®ªªºzõjbbbaaaCCCWW×ÈÈHWW×¥K— ¿ÿþûªª*Dæ j`cˆ`0€~/žiÓ¦———ßÿý………/½ôÒŸþô§—^z©¨¨èþûï////**‚þÚB–æ`1† ˆî‰7{öìÌÌÌÊÊÊsçÎíÞ½ûܹs•••™™™°Þ…öeDl€9XŒeBH€±÷¦…2 ŒËˆðs°K†œ23 q@X–æ`1–Qfú€^F˜ƒÅØ+H 0 -ȤØ2¢.À,Æ"!0À€¨ #ˈÒs°{„Ìr2¬À€.#ªÌÁb,±„dX±!ZF>`c—`@B†ôeä3æ`1v€ðìÆ2 ˆËÈÇÌÁbÌC~€Þ c”e䓿`1”pßµk×þw÷“3 £ÑxæÌ™ .tvvšL¦àààðððE‹-_¾|Μ9âë\¾|9==]¸\ý“<æ ’×§HðdXò€Z[[õz}ssóŠ+–,YÉÝà¶½½½¾¾¾¦¦F§ÓåææNŸ>]dAËKÿÝÝÝdÎ',,Œ„ùC„ðõ) –< úúú-[¶¤¥¥%''»Ô£WVVîß¿¿  À^=!Œð2R¾þlÒæÐh46lÀ;¸¿>=¢B}ú_~ùåàÿ)g@[·n---MHHP©T.·Q©T111±±±yyy3gÎŒŠŠS9<<<66öôéÓV«õÌ™3sçε¿:Rùþ,XP[[;66VRRBÎ|jjjT*•Á`À;è¿>=¢è{Zrž¢à7†Õ__ßöíÛ“’’bbbt:N§«®®æ7ŽŽŽ6 ö·ôª>€=ŸÐÐPFóñÇ‹ìŸR¿4±ëSå2,çMüÆûïêê:räHSSÓðð°Ëí£££SSSÅ÷z>z½~Æ ^õO_šðõ)€B–ù.v¿1Üþƒ‚‚Ö¯_¿k×®uëÖ¹û)ñý£žêþy(½Þ[±õé%2,ós6ì~cèýO:5???11Q«Õºû)ñý£žêþí¡ñzo%×§Kgøúõë2?(Çë7†Þ¿xDöz>¨ûw@a/uëÓä.**’y¦ ^¿1ôþÅ#²ÔóAÝ¿3Jú{i\Ÿ@p—zÄl6—••Ý»wOšèµ¿¿‹ß˜÷ë"êß#"ûG=Ôý»ƒŸ?jÿ0ÆõÙßß/á7:€<ÃòÏ!áþ« û9 œãпxDöz>¨ûõ HP~…œùËüíûuKbPÞo ‡þÅ#²ÔóAÝ?í`_ŸdXa¿1tœû·Ùl&“Éd2Ý»w{Äl6sØo&²ÔóAÝ?í`_ŸÈÏ—–ÑhÌÈȨ­­ àLNNæ>‚ãÑjµGåÏm²X,‰‰‰ååå^ݘÎýß¼ysùòå.7¾|ù2·™øþQÏuÿ´ƒ}}RpVÌoŒçþÅ ¾ÔóAÝ?í`_Ÿ‡mmmk×®---ŽŽ³}cccVVVUU•x·RP÷O{}ÚÁ;ä×-AaÒ¤I³fÍÊÏÏŸ?¾½‹Ü%œß¸  àÑGU¦= îŸöú´ƒw>tdõàƒ¾õÖ[ccc:N­vñ©˜Åb9xðàŽ; ÄëQ•uÿ´×§Œó¡ã¹4ϯ¿þª×ë¯^½ÊÝ'aÚ´i܉mmmçÏŸ¯­­7o^nn.±OáP÷O{}ÚÁ2Ê2Ìñã?ÖÕÕ]¼x±££ƒ»_QDDÄO<‘@Å›(¨û§½>í(<*3Ì`0x(øl‰Á`À2Ì`Ð Ë0ƒA7,à ݰ 3tÃ2Ì`Ð Ë0ƒA7,à ݰ 3tÃ2Ì`Ð Ë0ƒA7,à ݰ 3tÃ2Ì`Ð Ë0ƒA7,à ݰ 3tÃ2Ì`Ð Ë0ƒA7,à ݰ 3tó1DN*¥” IEND®B`‚puzzles-20170606.272beef/icons/slant-48d8.png0000644000175000017500000000337113115373745017330 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá!:ÔÖ;IDATHÇ•VëOSgç_Ø÷%Ëöeû°Oû°¸™F\Hf¶€Óxƒ"^²¡1[6uêæfa H¡¡°2*W¡:Ús)-çœöœ÷z.m -¸eÉöì}O[¬fûà“æœ'oŸßyÏûû=—S…_Ѫøaô‚a Qå"ó1‚üZP‹š•f!¼ä Ûõ~aÐLC“tQH,p‹—~“¹8_›áK‰Hbyq&O@–M©Ü’±yî$ÛÑðî:Ò‰æO&4U£cÊëÇ—ü’UÜ!‘²(7KÛ„¢ÜX[çwsWÅ fKqdRг?÷¾賑»ƒ¹ R~D´EÐ4÷ž <–cÇ¥"ÀXÏûvôŽý:Å›—1ªÅL`Ú{.mÄFõ¼§~Õ#ß³UÍN>L»­`}‘P{Ïåuª¬52×”eZŸ²âLÆÏhÈvDLxÏ„p_)eS“dú'¿jxГ°²¡)Ï.ÿð£ 5©‰=b%o&±ÐI6M VÍ7Ó{&#ß¼o6<\ÝRÐ"ÂJãÑU`ÏÞ|n+”†L¯+éßî$£ðå~{¶W0v¶ L#ÏØ…¶z÷W`—i«ˆÅ_.`”´Xüç+ÔRlÔº®cQ‡\`¦ Ý.¦æL®WV—ò,žK”†hÙp"Äá æ–$ui ßÛ{iݰ§úBÍûY<"ÁÐF»˜¸{û1WÐ31à+¿’n¿Ñ¼¡§Cþ mÓûlŠA"Åf¥Cí§îz·ÑòQßÙÀÐP H|SŽÓdçò¹m†Â„B`ÌÏ_|ßè¢ôñH®æÔ_<çª0̆N®ôŽ©Sþé=“·”¨( ³’(F;¥¥מ^¢ ŒüsõÔßw"®p0;zP`ÅÑAO¾150ç`–X%gC³—_»š´,É·o‘»‹5I2tþа\»ß1àžŒšßˆ·?+rKnj`±ß÷Àr+ƒ³ÄKŒ{ƒ‘ê–uÝ~Ø{[p6…ƒ™\ƒg 8¸Äu€ñRÂ\FLÁT6 8G¥ÔP0Zmð¬bE&/ È5/ÀØ"Á%Š¢!¯ÉæK;ð&À-ϤR»€E€«õ©¼ƒPtxÀXhG›•(0UY¯b4曚&q[–L÷N,™72”&»"åî 3÷®ÁK0‚ Š¢ä ÇMG™'Eâ±·çròÙÑ-­«I °TÛ°b= k(šbž¡?=³r»'š²«mBUÜäYc Åäc†M R–¸…3û í9K²A¶·ñòÒäB½g MZ9KN׿âJK‰4£¡`PM"L56q*hÅ,¾nÙ”•ç,% æÄ±Õ,°Æ•:@¿‚Ì0ˇ¶„qB,´½me:˜²!GaZçñ–>:ÁžZ>Ã@WœX°ú\ µÔÕzON(MD"äÎÔ.#ë‘70ص`³5Þ;ÛÍÊÐ7ï©]þE³Iá˜G3Ý9IÍTóœiêÞ©kg¼Å‚gŸuÜ›N=ìÙ©þcbP—hÝ×HŽ3“ÑÅ—SCsg/žh-·JÞ ?QoþÚ»`"E…QÍ“ªš¢€P¸µfç`P´Ê]ãqwg{'¯ìóê|@›–Ìfz²Æ{#öã'Þb«Ä49Üm°æ}Á©Á-Q„Ê_ ®‡¬…αoi(²šX3b¯æˆO°½ZiÈ¢ónPñÓX¨´lãÿŒç¥g—‚ª^Zÿ_+ÿU…_Ñþ‘ ÕIQ’-í%tEXtdate:create2017-06-06T01:31:33+01:00}€­Ù%tEXtdate:modify2017-06-06T01:31:33+01:00 ÝeIEND®B`‚puzzles-20170606.272beef/icons/slant-48d4.png0000644000175000017500000000150213115373745017316 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA† 1è–_bKGDÿ‡Ì¿tIMEá!:ÔÖ;vIDATHÇ]V r1ãé<Ÿ© ’ÀiÚÉì¬mIȉÂ÷·ÿàwõøõoCÔ.Ïn½Ï@–?zŸÙká˜Ø ß'3•^KÄw"'ÃnTòÌ9ƒÚŠ0ñ¿—]ÒEQ¬È^©È·ôŽ’ý¬ï9ó…f?éÜ?ŒG¨mêÔjcŠêýÐÉ …Ñö†‡+ý %Ë=ùeáá‹òR2KL$ÆïÅyu]}/b6ð™‚xšî ËäWyà‰Ž¯—Î>JŠýºjV…Ù5abR„©é΀yú…¥ †Ÿ'Ãw KL°ÅAâ‘©‡¨Û†Ôy‡) ÀR z®g|c%Ý"Èr¯ª›¨‹aFcŬ ¹½3ë$Ï[¶n訂‡¡CÜø$²!R›¹ê!è”aƒX63ÈŸÑèÍ)IÌSÊ-1ý˜Àˆ'WÉ ñÝIOe7üB·†—.‚v#È4<ýÓw2kê14â>íÛÌ̈́Ò(3D*qv&~YƒÔKÆbMï1!–s‘~zx¶­UÚ©–i#zæú´°Çi“ÐLÿèæÇÓ öÖ§Sé•tŽE]©$¿ŽÇ’k½gûÑ|DՃŠÛüù« àbÙ(mž õÚ%уl¹‡åoˆÜŠUiæ/®‡­%Ǧ tOªÿD•ÏLËH¤ÊCáá…Ä•/E_æãU¨hƒ¯"uïX^?2ÑdÝ D¦ MßÛ¯ï‡3Ýr³)-¥ME<ð’Ú!¿>Ày’,Û‚vÏ«àLœ®³tÌ1ƃ±„Ø}–„»–ßMÎ9G-í/ Þ9£%ÃíûágîÊËëóÛäþ7uøË3º¸û%tEXtdate:create2017-06-06T01:31:33+01:00}€­Ù%tEXtdate:modify2017-06-06T01:31:33+01:00 ÝeIEND®B`‚puzzles-20170606.272beef/icons/slant-48d24.png0000644000175000017500000000337113115373745017406 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá!:ÔÖ;IDATHÇ•VëOSgç_Ø÷%Ëöeû°Oû°¸™F\Hf¶€Óxƒ"^²¡1[6uêæfa H¡¡°2*W¡:Ús)-çœöœ÷z.m -¸eÉöì}O[¬fûà“æœ'oŸßyÏûû=—S…_Ѫøaô‚a Qå"ó1‚üZP‹š•f!¼ä Ûõ~aÐLC“tQH,p‹—~“¹8_›áK‰Hbyq&O@–M©Ü’±yî$ÛÑðî:Ò‰æO&4U£cÊëÇ—ü’UÜ!‘²(7KÛ„¢ÜX[çwsWÅ fKqdRг?÷¾賑»ƒ¹ R~D´EÐ4÷ž <–cÇ¥"ÀXÏûvôŽý:Å›—1ªÅL`Ú{.mÄFõ¼§~Õ#ß³UÍN>L»­`}‘P{Ïåuª¬52×”eZŸ²âLÆÏhÈvDLxÏ„p_)eS“dú'¿jxГ°²¡)Ï.ÿð£ 5©‰=b%o&±ÐI6M VÍ7Ó{&#ß¼o6<\ÝRÐ"ÂJãÑU`ÏÞ|n+”†L¯+éßî$£ðå~{¶W0v¶ L#ÏØ…¶z÷W`—i«ˆÅ_.`”´Xüç+ÔRlÔº®cQ‡\`¦ Ý.¦æL®WV—ò,žK”†hÙp"Äá æ–$ui ßÛ{iݰ§úBÍûY<"ÁÐF»˜¸{û1WÐ31à+¿’n¿Ñ¼¡§Cþ mÓûlŠA"Åf¥Cí§îz·ÑòQßÙÀÐP H|SŽÓdçò¹m†Â„B`ÌÏ_|ßè¢ôñH®æÔ_<çª0̆N®ôŽ©Sþé=“·”¨( ³’(F;¥¥מ^¢ ŒüsõÔßw"®p0;zP`ÅÑAO¾150ç`–X%gC³—_»š´,É·o‘»‹5I2tþа\»ß1àžŒšßˆ·?+rKnj`±ß÷Àr+ƒ³ÄKŒ{ƒ‘ê–uÝ~Ø{[p6…ƒ™\ƒg 8¸Äu€ñRÂ\FLÁT6 8G¥ÔP0Zmð¬bE&/ È5/ÀØ"Á%Š¢!¯ÉæK;ð&À-ϤR»€E€«õ©¼ƒPtxÀXhG›•(0UY¯b4曚&q[–L÷N,™72”&»"åî 3÷®ÁK0‚ Š¢ä ÇMG™'Eâ±·çròÙÑ-­«I °TÛ°b= k(šbž¡?=³r»'š²«mBUÜäYc Åäc†M R–¸…3û í9K²A¶·ñòÒäB½g MZ9KN׿âJK‰4£¡`PM"L56q*hÅ,¾nÙ”•ç,% æÄ±Õ,°Æ•:@¿‚Ì0ˇ¶„qB,´½me:˜²!GaZçñ–>:ÁžZ>Ã@WœX°ú\ µÔÕzON(MD"äÎÔ.#ë‘70ص`³5Þ;ÛÍÊÐ7ï©]þE³Iá˜G3Ý9IÍTóœiêÞ©kg¼Å‚gŸuÜ›N=ìÙ©þcbP—hÝ×HŽ3“ÑÅ—SCsg/žh-·JÞ ?QoþÚ»`"E…QÍ“ªš¢€P¸µfç`P´Ê]ãqwg{'¯ìóê|@›–Ìfz²Æ{#öã'Þb«Ä49Üm°æ}Á©Á-Q„Ê_ ®‡¬…αoi(²šX3b¯æˆO°½ZiÈ¢ónPñÓX¨´lãÿŒç¥g—‚ª^Zÿ_+ÿU…_Ñþ‘ ÕIQ’-í%tEXtdate:create2017-06-06T01:31:33+01:00}€­Ù%tEXtdate:modify2017-06-06T01:31:33+01:00 ÝeIEND®B`‚puzzles-20170606.272beef/icons/slant-32d8.png0000644000175000017500000000213313115373745017314 0ustar simonsimon‰PNG  IHDR V%(gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá!:ÔÖ;cIDAT8Ë]SiO[G}?ªßûÒª#Ù4e©›*DQÔ¨M &¡¤¤*‰Ú(m„³ccc/Ô <üüüöuÖglð†!ÿ¢3Ž¢J=ŸæhŽî=wÎ\aJ>"Òᔜ@J0Fv5Ëd0LÓ’±VöËÔ›#T5€‹ª)®m;–äØ^µº8[‘\Ç]˯ì_z”W¨@,—bBFýqráM:ÒìAlPÿ|óúæ_ù Ä´1Dhþ05k×åýéÖ‰ËÈÖwn]â‚ ¤aj lw,†•NãlkŽô @.p"ΫÍgØ->MÔFµié4>OŽK¯ãÍI œNM=ÙëÕ¶×®í(½ƒ™õ¿S=+é`’¦fÐçñŒù,E[9Ý+V€êû·SW³R›· þ0¶¾òªÜo=¼öxpR¹"ÉOR>æ&™ÿH>S¢Ç Vö–VGÀqk!¹/fß”{pÇ©ØÓúÇ?Ä>hÞøîʈ¨C1Ü<·Ÿ‚jRbvŽŠÍ뱑¯Ûp]Õ‹êðàJe¿ŒXíÇ7­~õÑêã?>øåQ4\¾wgCº(ü´¼±K Ð-F¤’‘4Â$cê–Ô2M9¾ÞN{r;.6¡›ÿ½,9Ûâ»ißöZ:‹*ûô+±@³‹{<,ãåüþ¸{³DM—¢öáßñ»+ç`ëų{Iªªò´82ªˆ@H #Ø•öòý3,*m–åôZa±§–éDÀ`’aôþØôÑ$M ž(aÑìŠ= AƒQt•p5`èvZS…S¤Ûè+ø½åÂ+tJ?BUv.瀬êGM]U5¥¦©lÞK&SÜ["Э~Sïû| Œ Ô(l“ÈÛIbtûyG ÕNÁG“@e_~6ɺO<¸çk·T°YêD•6™K\èð°ôŠ7^[Tò~+TÇ&ÿÁ¾EgcýŸÖqýÁ8ûõ—hR©ßæ>®˜ü}òBO,­íòÍòBɪ–sÂ(n€êŒlê†æßØÌâËÐÕ”AãfúÈWý2“+î2861Qi{þÎŽF™‡D1šÏß<·)F˜í+a´“L”XXØ×–§ Æ€· ¾Ylý!§L…þ‡€ßü \xÛx/Ž%tEXtdate:create2017-06-06T01:31:33+01:00}€­Ù%tEXtdate:modify2017-06-06T01:31:33+01:00 ÝeIEND®B`‚puzzles-20170606.272beef/icons/slant-32d4.png0000644000175000017500000000074513115373745017317 0ustar simonsimon‰PNG  IHDR V%(gAMA† 1è–_bKGDÿ‡Ì¿tIMEá!:ÔÖ;IDAT8ËmT Â0ãè97‹Ú§Îç\ù&Yõý¹ÊûÔ7Àçc9ΨÇ>uHùÑÎcNxÜb<ç2N3N1F—Tf£) rË?®>¡+PÝÛÒΧыAðe"09†îž¢9D 1\@[¡Ñ–qJ*+\~X~œ$JêN<=VÏÄ U“„§&WjÌWse—Sá£%u‚0\ iR0–¸Œª»g¿ Ìž¦õÛÁ/Û·k˜¥×+¼r£5gü¤ÉæÀßaýYÙî»G^5n³6‰f+a†éÜùáÁ˜TžhÒ?œ ä7M¼›®†©¥5½Ë•o¶È7ài"ž#Þ¼›ù¦êµÔ½Ákõ¿ÀÄümÄõ¶þ¹#å%tEXtdate:create2017-06-06T01:31:33+01:00}€­Ù%tEXtdate:modify2017-06-06T01:31:33+01:00 ÝeIEND®B`‚puzzles-20170606.272beef/icons/slant-32d24.png0000644000175000017500000000213313115373745017372 0ustar simonsimon‰PNG  IHDR V%(gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá!:ÔÖ;cIDAT8Ë]SiO[G}?ªßûÒª#Ù4e©›*DQÔ¨M &¡¤¤*‰Ú(m„³ccc/Ô <üüüöuÖglð†!ÿ¢3Ž¢J=ŸæhŽî=wÎ\aJ>"Òᔜ@J0Fv5Ëd0LÓ’±VöËÔ›#T5€‹ª)®m;–äØ^µº8[‘\Ç]˯ì_z”W¨@,—bBFýqráM:ÒìAlPÿ|óúæ_ù Ä´1Dhþ05k×åýéÖ‰ËÈÖwn]â‚ ¤aj lw,†•NãlkŽô @.p"ΫÍgØ->MÔFµié4>OŽK¯ãÍI œNM=ÙëÕ¶×®í(½ƒ™õ¿S=+é`’¦fÐçñŒù,E[9Ý+V€êû·SW³R›· þ0¶¾òªÜo=¼öxpR¹"ÉOR>æ&™ÿH>S¢Ç Vö–VGÀqk!¹/fß”{pÇ©ØÓúÇ?Ä>hÞøîʈ¨C1Ü<·Ÿ‚jRbvŽŠÍ뱑¯Ûp]Õ‹êðàJe¿ŒXíÇ7­~õÑêã?>øåQ4\¾wgCº(ü´¼±K Ð-F¤’‘4Â$cê–Ô2M9¾ÞN{r;.6¡›ÿ½,9Ûâ»ißöZ:‹*ûô+±@³‹{<,ãåüþ¸{³DM—¢öáßñ»+ç`ëų{Iªªò´82ªˆ@H #Ø•öòý3,*m–åôZa±§–éDÀ`’aôþØôÑ$M ž(aÑìŠ= AƒQt•p5`èvZS…S¤Ûè+ø½åÂ+tJ?BUv.瀬êGM]U5¥¦©lÞK&SÜ["Э~Sïû| Œ Ô(l“ÈÛIbtûyG ÕNÁG“@e_~6ɺO<¸çk·T°YêD•6™K\èð°ôŠ7^[Tò~+TÇ&ÿÁ¾EgcýŸÖqýÁ8ûõ—hR©ßæ>®˜ü}òBO,­íòÍòBɪ–sÂ(n€êŒlê†æßØÌâËÐÕ”AãfúÈWý2“+î2861Qi{þÎŽF™‡D1šÏß<·)F˜í+a´“L”XXØ×–§ Æ€· ¾Ylý!§L…þ‡€ßü \xÛx/Ž%tEXtdate:create2017-06-06T01:31:33+01:00}€­Ù%tEXtdate:modify2017-06-06T01:31:33+01:00 ÝeIEND®B`‚puzzles-20170606.272beef/icons/slant-16d8.png0000644000175000017500000000076613115373745017330 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá!:ÔÖ;þIDATÓËNÂ@@ïoÃB£ 10X¬ÔZ°¥Ä"> 1 ¥µÓyÞ™ ¾âX·'çä€dœ1Š Á *I®€’ãú«Ä¼ìû\–Rõ‡2|ÏìL¨ô»½›¬‘‡–Sœ: ¢]ãÁV´i¹åN½JÞ{wçç“MoH{ôê^­¤q:IdO5<5ÔånÊ|¾íâ‘%{a:Xh:²'ÓGâk|j¤Ú é<¯’û÷¢$)¥Ë¤%ˆ³‡_¿ÿ‘+•¯cO#0îÆ2ºF­uìsb`ֱ֤腨ÆÖê–]~ÛÌ ‚hzâ (,¯ú£Pÿ“À>ñ­›Ç%tEXtdate:create2017-06-06T01:31:33+01:00}€­Ù%tEXtdate:modify2017-06-06T01:31:33+01:00 ÝeIEND®B`‚puzzles-20170606.272beef/icons/slant-16d4.png0000644000175000017500000000045213115373745017314 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA† 1è–_bKGDÿ‡Ì¿tIMEá!:ÔÖ;^IDATÓ=!y:Oóg\ÞLV¢¸MÍ8¼kДÝj ¡ ÓD[H¶‚×÷ŒÅˆA›ã|«Z”u̽Kú±KQçb9ÊÜZx>SJnOÐQŠœø~ À1h“%tEXtdate:create2017-06-06T01:31:33+01:00}€­Ù%tEXtdate:modify2017-06-06T01:31:33+01:00 ÝeIEND®B`‚puzzles-20170606.272beef/icons/slant-16d24.png0000644000175000017500000000076613115373745017406 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá!:ÔÖ;þIDATÓËNÂ@@ïoÃB£ 10X¬ÔZ°¥Ä"> 1 ¥µÓyÞ™ ¾âX·'çä€dœ1Š Á *I®€’ãú«Ä¼ìû\–Rõ‡2|ÏìL¨ô»½›¬‘‡–Sœ: ¢]ãÁV´i¹åN½JÞ{wçç“MoH{ôê^­¤q:IdO5<5ÔånÊ|¾íâ‘%{a:Xh:²'ÓGâk|j¤Ú é<¯’û÷¢$)¥Ë¤%ˆ³‡_¿ÿ‘+•¯cO#0îÆ2ºF­uìsb`ֱ֤腨ÆÖê–]~ÛÌ ‚hzâ (,¯ú£Pÿ“À>ñ­›Ç%tEXtdate:create2017-06-06T01:31:33+01:00}€­Ù%tEXtdate:modify2017-06-06T01:31:33+01:00 ÝeIEND®B`‚puzzles-20170606.272beef/icons/sixteen-web.png0000644000175000017500000001262313115373723017750 0ustar simonsimon‰PNG  IHDR––j.>gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEáæÛô›IDATxÚÍœyxÇ•À;16v¸Lâ#±'¶w7x'Þ„Ï‹áC`Œ9 8A’ ’À˜`D^Ö›5¯í|ß~ØË¡Ø$¬i¤ÑNè>¦»úž³çÒaàf»{4=}TkÀ‘Þ:úuuýººúU½ª×ÁǤ £ pX$ª¸ž"‰ba, ¿ œ˜N'¡S„duŠ$Š…ºk;¡×”£Ê ­sW9(Ætֺћ…úŽ%¥;hmõ€¤_}¦€ƒT‚r³^¥ImŒFÓ’ŽúâsÅÅB}¥‹ »W£Œº@2™Û-Ëû5• þ¼¥æœ FÃ…ÑXò®ÂÅÖø\ñ°xªÅ‡må»’Õ\.bYŸêì Û–oµ+>˜û±sDû5"æÚºlC’Á\l,{;ió¼CLRØæmz.§œ¿wóµ¿_KÅÊÐk·v¡™o“òœç6Í·º¤"žÃó6'½]f,6’6,ßâ±¹F~ˆÀëÜpÐZl¬Ì>pÆ'ˆ47P’UUÄבðødw|ž@:'EUY%œü!2¾3²+ÅÖƒ=Þ‘}œ.õx2ry,û¶=\üJ ×·¾²¨¸ÄJ9ýsP©†’â¢Êõyî^E‘nÏ6¾?Zs3<=qL}\Á‰X•Ù{Ê—ó­Åc±ª¬ˆU•UàSVŽöŠ­•›ÁÝ °ö›‹ Ë·B°2+ ‹Lù0¬|SQaE&kkya‘yÿMÀòej*ÊšßØ£ÁÊß|²Ì^Y𯍱˜´ÒJ{ÙÉÍù¬=o4—UÔ²nÔœòÆqÝ¢ôÔ”uOçªîó˜g®MNM[±R=Zcî•+ÒR“×Î4{TX\îÓëRRÓ­óß(NtVUWWWÕb„ZêEM›FA´‰ŠzÍËF`µ¢¦“ÀãHüé„…\‰5”VAEŠ@î1R„Œ[i|,0,×®¸ž"׈ERÿ!ÃÂ:ÚZu¤M_“°¢µ‹H‹ì0Ú+áRe×ÓTV$Z¤ÊîH‹j³_½|"—¯‡k®\ ëùä3¸æ›¯ú?E‰D°Z+¯@€>êwÀÔ©ÆKpkDÚ† v Ð m{oeéƒcÑM —áX„ù<‹©¹YX8m ÷Ã: OèbYÎùaÏ 0ǯ ĆŠâu`™¯ “™³ƺ¤ã£\2YÂBýE[¼Ñ㣀…y·|ë‚Q,ÔW6÷EwÊ‹  ÂÜs8P ÅâGoD‰¢çk±€4—a µö¸_”ùÛH”ªtÙû=çó2,@‡ú¼8p÷÷ûI-–¯¿ÏÃL_PšÆ+°ö«±¿ã<ƒ¯|°\ò‘(Õâ#–¤Ì ^Öu’ Š躗ì¦èÎÏé|QöÎóK÷ÓZ,À”¯š›Qʱ}ú…õÃÿ c²sPof’%oqÔßF¢T‡KM†¹¹û VwJX˜+ÿ7ßYÀ2¯/_„¼$LêdX€>ùëg Dæzr,̽a òKþ  õýy°;âlG±œÇWìÏÍ=`0ÅümD¼Ì±E¼G_l¶Y­æšôê–°õÈF„ªïؤ ´û|5’™µ*ûá#~6‹Òb¡þu¯ «:½ÆlµÚxw´ôÈâ£âd\‚ºy6£è#ó^}ª‹è~`‹Ò¿E¦Øœ*,þºÔ¬‰ Ð`¡þ dÜŸ£Sæ »³¦ÝíQc¥VEj7Ú “j—EÀ";_zKp¼–¥È±0–{xñYÜí(Ÿòo.UßTïìé§‚(¤Ë»Á©ßLl£Õ­…úÞùnöOoÛMâJ¬”²B¡nÁß&öaDÔ£ÂRJqY¥½²¼y]•SÖåvLyìÝŽ—ßÈ·À­ê[„ãIdÍöœÚ¾åy}ã»÷Mï"ÕX˜ëïO=u7’ªÂªZ×\ÎW]V,. ‰­/vyq‰§Âôö–mÙ[wÌ®gc]Þýñô_Íx¼eÓc¿tŠR¶Òì'güðu¯¦oaî÷~þèóÇ o"`ýŸfÏ÷ЇÈÖÏÞ±5{Û–·M;“ÑÈrUÄ@`4š²Ëöì¾={÷þ%#d}‹ú¸á 8q¹FÑ·ŸÏ±T1ð³0»Å[gg´ÏEíåþeïÞ=ûžµ½%-î ›S¾½Ò³7ŸåG(­¼`÷1þÌÊG«ßDA! pªÁ“ÉœŠÕžÝ¼m ]Ú‹>¿°È§|Tò팉âàã]ô¥¡cÛIí> C5`µÅ¦±‰  <£;±ñÈVòÇü4P.<ÖeÞ÷Z¡,áþ^¨‚ÇrÀ€Çâ úš&ÍJ¬+Ek…rÚŸà0…ëT† c=‚i(w}ÂXUCG-V­Xly.Tah„•à¥`ðd1¬Hi~{‚Xmö ¡¾0DúŸ „á:«Wdz<Ü:ó™#A¬«ýP9ÓÝ÷Ex¢ôö|Ó7-Ò>ô)Tó K|™ßå0é¦p¸…(ðººKÝÐ2¨ñœ¦é%ì-__‡ûJhEp_P˜‚in¼Œ0!y÷ƒ©½–¾56í FÛ}% VP=šc"muĶb¢X€t®YÈõb˜8ïPbi.¢ÆŠiTîëðu´X¼h°„³{¹ç×8¥ýG$Jż’¹iÀíóù<,Æã„ca¤ÇMB°ëõ¸Ý à.iDŽayøjÝ›Öoök‘(UÖvëS^AAžà@‰Õh©0,àì)9ÚMh°uÜd¶“&±²I3E”•´ÏŸ$,`ê5-±Æö·‘›•m/ÎÉXŸ•¹if+ÇLÍCÈÏ£Û•r,Ìi}ðîiïiÝWÔ¿ ™xë„FFíbð^É¢Û'M·EæUÒ\¾aæ¦Ì¬õ9Åöm™Lä9ŠžÅdfóžOyUeUÅɵ2ÏG²õØÓ-ÀÉžÑÔÜ¢m-œho>ñƒY.‹9k$²1äc9«Öž¬à«.ç=Ÿí45ìùÝ´]ÜD.***,K®Vb"4ça[?î¡é—h2^‚û‘C^Tûkœý@5£r_“Ë ùª‚ŠœWÅ#`9«Ÿ1[¢^µ=U…Åëgÿ‡`9ë§ê~𤠂…±O>*mºÈ"ÕòøŒ%ÓŽ¸0%Vª=êU[,ÏT9At ¢pY‘°o.)1U¦i±æ<‚A°ÈÞ{çö=ü —ÖÙÇÌ P,˸ •9%¼Ò!¾ÈõìT]Þ- sPšS·—VyÕ8áfX– d}´R @‘ÖN9üdƒŸøkalœgÕà³³ ,L¶ïz ƒ_­Ã“)ˆò¥‘Lii$ÞBReê¬äÊá=5… ÿë©%¥Nõ›èþðÉ¥sž½xz©0DÏ¢9KŸ0Nz~æ¼&Ä]H—ÝÖë-»&Ôb ~¢o Ìjv_k0Ø×‡~®²[á¾à Óõ÷Q‡-»e*–ÝD®™›¡‹”Bôt5P'ô{Ã1CJ+/l3Q­0§º‹”—KwIW&ßΘ¨»¤;VÀÇêvÁ·¼¹»Öum ßL,îZ°ä¢?—‡îvŒ5<ˆ’в†+@o‡,€Á൉o Ú̳Ùb5+Śϵ-•¢°)\"þ¡.bþ¸¿É½VAG­õÕÐùsç.ô‡ùŸ 91òÛ?¤Rœûòs±H_¿ºÈ…‹Â¹ç‡êC_'ÓÜ^êç… Ÿì?ïõ+Å'ü’W|j'jNœ;£ÒpÂÿ\E/{” ï¹ÄöªÉv[$æÇÔ‚ûÐu —º¡>4j:ïúФ½ýË.ŵ°îPbÎ>ųÂp?| ¸©é2TA– | øxÇE‡òz-k2»Åc‰§S–þ>¸9° ÄÍtÌAºƒ–Φ°,ôg4°à¡?Š@©QÀ‚Ja4¾<V¦Åâq Î%,€Ef=ªÆR;«Öp€õ„#Xºae¥mái±œœ \~/¡Â¢¼¢3 <©ÂNçzUX´ÏÏO+1&à±tƒð„ŲE Quðï¼oWºÏ Ú¿Ùžÿ• èoݤ«l^/uúàûÿk XäéÃûê)ÌÕð×}¬Ì" Y\­Y¾wVxª±ôßÇÝYîi| y¨=q=Œ…yß½ Éòöz ‘ñöˆ³ÁTË ä¾Ü!dúÔ…bsF±0OöíÈŸÜ΃“ùQÞÕU€§#à 4ùMÞU‹…ÃjZ«·uëmÕÎÎÓËîïV`áDë±I™^àxêñ;«YNt·$OmáßvÀŽ“@ñ[ ¿ó'×gÕ7ù¿p(Ãaw­–ÂaÙ™® Ž˜Sþã-Õ \zO— sµÜ‘áæÖ®x9!o-þœPʤӾC¦E¢rcX˜·y£¯ ùÑý“Ê®ôèCB­É®ÂÁŠHXh ç–:—ÿì”Rb1§'dÚ¿whr8bw¢XX urÛ}Ê›†T¸09–ÛŽü÷™rd!>)õj—n¨5^Ùbe`:Ùiì ­…¾r‹E»|¿U¾‰è±;VÓ†;&Þ†üD¼ í}abw¤c1Rí”cáX>²tÝ7½ë¥40¿‚÷èE?Ù^J)ßÄ_"·#;ð{nä]e õ½ƒŒ÷Hïiì5d8ˆy¸Ë“ä~0yâ„ÿ`ä} å^CÆ#¿ æÞ7ñ§Í—Ôaü¶X¿øyÁùGZ»ÕXÛXÓ†×Õ5Ôt‘ ÑQÓPWÓlW=A( ¨çOî`ÚjÛ\„Ò@´Ö4Ö6á®Îã=gù‰þG×Ñå²OD´X Ë:)œå’*sêäâÑ7%»%ž h'­¶ò|'ƒc” LlbŸˆØ”ŸˆD>¨Yåað·à¢_bÊŸácÒ'šVDývS>øD5Ñ1Q÷ƒÕçG£0TÃ??R~¬5*èÇZcu(Kè$ßnlÒݾàƒi0º¦ã+åµðÞp‚wí¥,Ã0´ËÖ?H0Z¡Ý'O\†)x±^’°"žºÎ¯qVqŒLÐÅè(©;ÎK}~˜¶××J½¥þóšã0©-rTŠ4Û†”ŠZ;™X”.Ù^ÒÒÞÆKû¼UüC%í-îp LÑÖÖu¶W§Ç)‹´Ÿò&¶)Lvb__å³/‡ÿPËŸ_ԑϾÒ-¢V|ÖIW¡ó¹7A8zEq ÿÖˆ®"‘"*ýoö‰ˆà‰bI¢ÿõ¼T ],Q¬±™xal¦©£I=Æj ”1š0fL¦×›Éˆ®3uSÚ·›ºI•èê°<ÑÕ|½DWë~·.–èʦ—èjë $º¬Q–l¹"-XšnZ°yÃiÁŠUiÁÚ_§cGl®xIÔÊ—ë%QÛ¨“D-`ÐM¢–¾ë¦$QýÇ%ð”s³^L9gÔ¤œã¶GN97^|sÊsÙÊwBô±ëOЗzsô‰\‹ »“aé Ù¬‘ÒfBÓ¦¼U¸8>Õ%dt“?¾íä‘T™ ¬‡ŽjªÌ±šX£iXGAÆ(Öÿ'@«çˆ4ú%tEXtdate:create2017-06-06T01:31:14+01:00ú”*%tEXtdate:modify2017-06-06T01:31:14+01:00‹_,–IEND®B`‚puzzles-20170606.272beef/icons/sixteen-ibase4.png0000644000175000017500000000162713115373744020347 0ustar simonsimon‰PNG  IHDRÂ-½dgAMA† 1è–_bKGDÿ‡Ì¿ oFFs¶ *—tIMEá MÓæ­ vpAg  Oý¡IDATxÚí›Qšƒ „9:Gãf»[ë!2 ÛɃßÖÉoD@²u?Ã-@æPï¸ÂŒÖˆ@"Vrˈæyhâ-Ó‰fö!•hj§Öˆr ïþÌÇ¿}#@ÔûcS]ïŽt¢ÈE¯‡†e ¨wm½ /‰D†ê÷k÷[êzéG%§u I$ûWü:–¢þÿCE¯ ¢þ@X†‘(PBû$ê $y @)Q×[¦ðŒÈÈk<ûí±OôrX¼þ”†7ûÀ¸©’!Ø Ô‡Ò½=u\jÔM»¢?3— JÛlÿN ÕÖC«­—[S»Ây¾—5Œ@"$€0}€õƒËSo®—¨†uº–à¶ž@"tW LçßT šTz·ŸTÚý˜TØš¤ï U›ªa¦=Ù¤dö¬\Á{ŒÕ:TÛö)¯ìÂÖ¯8­žI+ê÷"‰o)ûÔÕÉ>½ÂcÐÃ;ùöÊ+ë Ú’×:0 Üe ÈÒ‡$‘(ø= ´áz™(ìaì@Þ”eÈ'_NÊûh;·Ì[°§LŸ‚QŒ‡’YÁ 68Q/kÜ‚†a“ëõ¹¬3PŸíÇ­¶ZmŸܚÚÎO ¦ó_üæJ ˆ@wÂZôV/[¼GÃ@"fÛ€ÄE˨Çê__Öˆ@">HÎGõ ÕãR ½…ýÛ3zH‹Põêa ¡áÕÃ@y„¦T¥ þQ= ’Ÿ­Z\€z(F0úGõ0Pxý?‰Õ ¨‡žÿ¨ Û/J7 *Ö×B'= O“xnñæJ ˆ@ZÊ~9Æ™Šf¦™O%tEXtdate:create2017-06-06T01:31:32+01:00Û÷¦m%tEXtdate:modify2017-06-06T01:31:32+01:00ªªÑIEND®B`‚puzzles-20170606.272beef/icons/sixteen-ibase.png0000644000175000017500000000252513115373744020261 0ustar simonsimon‰PNG  IHDRÂ-½dgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿ oFFs¶ *—tIMEá MÓæ­ vpAg  Oý3IDATxÚíÙÝKQð7ÝÕ-ÝEmk³‚Rêª»Š C𢨊 P/ê" ,ê&"° ¼J–tƒ,‘"ÒB7Œ@¡lþûšG™sæ<»ng«ó^¸«ûxÞ³3;;óÒÏ_P-bñL^‡Š°õ—¦ñ< BâÓZaó0H yR R ÿ*2Uy‹äT%Š ¤y‹$‚¼E2Až"h¦í@ÑCóùlÇö`´õ=·-o­„êÚSœ|˜ÖªÂiwÝ{¶4j†ÍŸö˜Ï·Lò@¶|Ór£hŠÏl•ìro#h¢£·Ýjp™èÂÛëD-<-ß|öYj`+Q'r‹ÜûÐ «A æt½–Jg9 [ÞŒÝ": \"&èÑnãá8Q‚Ù dÖ5¢«È)b‚Fˆö§ˆzÅA“ÕžA´Ïx8‰€Æ·Qù`Ö‹" ­-&ø–í2ŽoÙp„ÂŽÃXt¿Zh Y;uLx§ÖûÊ)6æxQ”íq‚ÒéN¢;é´uØwùö¶ü½Šô%“Éq äð¸>‡V>HçW>£ÜF[þ°õ¬9=PæÔð;uä ryþìÉ5‡sYaAY=·\—G&ÈÓ#äíQW«Ut×e¬R R ’ú>¥!çQÐ7lýh>¿ñTÓ0ÿÊ”Ë4lÝAö_ 1 Ë TˆcHHHAÌë2Y æ•«4k^& Äš—É1æeAÞó2^Û4ì‰ukpL0¯ë#-›5ýð=F^Û4LdËë=¥æ/Wày¯mf€ú“FÍ æ_—ÑΧs³ñ8×ÏËŒÞ~5ÿ¦‰¨A0 :ñqd#áyÙ±fÍAQ¢¸®7ùƒó²n±_2?¦ˆB‚ ccèz‹È9/ãlÓ°¦KÉ­‘è¨.–Ltfa2Bx^Æk`>\~~)˜Ï¼[¡ÚÐÏË$ÎÕUvœŸÐEAŸoÖ+ úöó2Ÿ}‚[èÉ5ïsÙzƒ²kŒy™D÷¼Lˆ1/“bÍˤŠíª£è®ËX¥@ ¤@ $”ý… ž†-ùåóÓ0mÑ7Ÿß¼¬ Ul  ‹¾HHd×߲ߣ ,æaý €ÈDó ¤@ ¤@ ôj×î±[Uaþ¥–ñÏh=¯îö¸ödÜ¿Í!ƒ<;ðÖGó0È£}4ƒ\üÖGó0ÈÑÁ}4ƒ²:ˆ¬æa­ƒØúh­v]Íà «ƒøúh™õÑ< Ò‡ªÚó¬õÉà }(Š­æa´R R ’] äW¿úCpÐB;HD%tEXtdate:create2017-06-06T01:31:14+01:00ú”*%tEXtdate:modify2017-06-06T01:31:14+01:00‹_,–IEND®B`‚puzzles-20170606.272beef/icons/sixteen-base.png0000644000175000017500000002020013115373722020072 0ustar simonsimon‰PNG  IHDR  ›á9×bKGDÿÿÿ ½§“ IDATxœíÝ}Pwþð—PаЩœHAG=5œj˜Œøpœ£Öá8Ä®À ¢ÞØ!—©"׎\;FÇ«@ u„¬µP[éyj‘AÏwÜXEcP2„`)£w‡ ,ixˆ þþX'Í¡æióÝÝàçõ×fÝì¾ÍæÍn6›Ý½^!2~Äu„¦3,BaÁ" †AX0„‚!D !‚°`„Cˆ ,BaÁ"hzL£Ñ¬^½Z£Ñpä1ÌãßòøÐ4,˜F£‘Ëå6lËå|Xg˜Ç¿òø–à­·Þâ:ƒ/iµÚÂÂB™L¶råÊ ”””ÄÅÅEGGcÌÉiU0­V+“Éd2Y\\„‡‡/X°àøWë óøW¦OÁ¦¬-‡ë óøWB¦IÁžº¶hœ¬3Ìã_yÈ™s²¶h,¯3Ìã_yˆòû‚¹\[4ÖÖæñ¯<¤ùwÁÜ\[4Öæñ¯<,ðã‚y´¶hD׿ñ¯<ìðׂy±¶h„Öæñ¯<¬ñË‚y½¶h>_g˜Ç¿ò°)À¯‹øóŸÿüþýûŽcD"ÑñãÇ?+//Ïl6;Ž™3gÎßþö7Ìó¼åa“ëÞxòUŽuù,³ÙLè¯ æñ¯™B|’’¢Ñh˜ÏÇÓh4r¹¼¿¿Ÿù¬â‰þþ~¹\μcL ¦Õjår¹L&c8„øF¡PÈåòk×®1™ £‚iµZ™L&“Éâââ˜Ì!‹Å …B¡P0é˜÷Ãv¡iyǼ,¶ ='v̛߃ÑG5 cccí#E"‘ãç¢(ª¥¥Å‹%>•Ñh¬ªªÒét‹”Jezzº}‚[·nUWWß¾}Ûh4Z­ÖY³f½öÚkÛ¶ms™ÓW._¾ÜØØ¨Ó醆†,Kdddrrò¶mÛÂÃÃÙ 0ç/ȳŒ¥¥¥õöö@bbâ±cLj..11Ñd29ŸF$Ù‡Åbqaa¡B¡P©TR©Ô£ey\0ûQ)kåøñã.ŸëòŽ5¨­­u2AGGÇßÿþwûÃþþþ¿þõ¯ÿøÇ?>ÿüóE‹ù0ɳœÈÉÉyêÿ÷ÿ÷Î;ïœ9sæŸÿügmmmLL X,–††v ‚´´´ãÇ777WWWÓ¿fúì³ÏØ 0ç/ÈSéõúO?ýtÆŒfp‡wûŠŒW퀨¨¨¢¢¢7>kk°bÅŠ_ÿú× .œ5kÖ²eËÒÒÒèñì$T*•X¾|yxxxRRR^^=¾§§‡Spþ‚<Éf³•””Øl6¿ø¦Ç‹Ž¹[0¾µË#6›­««ëÂ… @QÔ/ùKv–êøpllŒ˜7o;ž…«äI'Nœ0 kÖ¬Y¿~=W<âiÇÜú æ×íZ±bŃèá9sæ|øá‡œ¼¿{{{kjj€¢¨ÌÌLöØñä€{÷î9rD$íÝ»—“Þ±wÌÏcnmÁvíÚ•ššêí€àà`zøþýû;vìèêêb9CwwwNNÎððpPPJ¥âöÒb|xAhï¿ÿþøøxaaaDD'¼&‹SSS‹‹‹]NéVÁ:ÔÐÐÐÞÞÎ8.^¼¨Õj›››éF£ñÃ?d3€V«ÍÎξÿ>EQUUU‰‰‰l.ýIœ¿ ´›7o^¾|9::zÙ²eÝÝÝôøÑÑÑÎÎNû6–Ÿ CCCÃ\NéVÁ$‰Z­®¨¨ðÓŽ@xxxvv6=ü¯ý‹µå^ºtiûöí###555ž~‹BW/ˆÙl€žžžÌÌÌŒŒŒíÛ·Óãu:]FFÆÅ‹Ùä&ƒÁ R©JKKÝ9^ïîAvlrrrxxxxxØ~ð`tt”C?,**ª¯¯ïêê2z½¾¢¢‚?wî\v~ñÅ …bbb"44´¸¸xtt´­­­­­Íþךeœ¿ Ó€Gí¾h¦;&“É øðy¬¯¯oݺuŽc”J¥R©€ÖÖÖ   Ë—/Ÿ?~ʳD"ÑÎ;ÙIxáÂúŽ###r¹Ü>^*•~üñÇìdpÄù â(99Y¯×Ûö÷÷Ó?)dáL¯yÚ.ðô‹fnÇœÈÎÎ^ºtéK/½$‚ƒƒcbb²²²NŸ>½xñb®£q_&¼hxqª”D")//ò\ļ¼>(˜F£‘ËåýýýÌg…Oô÷÷ËåræcZ0­V+—Ëe2Ãù Ä7 …B.—3<˜QÁ´Z­L&“Éd|¸£,B¾%‹ …B¡`Ò1ï †íBÓóŽyY0lzN0ì˜7¿£jL¹G³H$r|øTE¹s÷N¯ƪª*N×ÙÙi±X@©T¦§§“[¢;ÚÛÛ«««[[[¿ûî»ÐÐÐùóçoݺuÕªUì'Y±bŃž?wîÜ .°Ÿš››kjj ƒÉdš9sæ¢E‹²²²6lØ@t¡‰‰‰&“Éù4"‘È>,‹  ÷h¶Õ˜R'Ç;F?‹Ë;O3400P[[KtžúòË/ß}÷]›ÍF?4F£Q"‘pR°g äd¹—.]²ßYN$™L¦7nܸqÃd2eff’[®Édª««óè)±±±ô1²²2îÇçYÁx¾gHQTnnî’%Kt:]MM ×qàîÝ»%%%6›-::º¤¤D"‘X,NÇUž?ýéOV«ÕþðìÙ³ôûlýúõœä9sæ =°wïÞ_ýêWW®\Ù¾};œ:uŠhÁ¼cßWô¨cŒç퀨¨¨¢¢"èííå: @mm-½§ºÿþøøxNNNæ*ãNÇäääîÝ»à…^ÈÊÊâ$@  V¯^ IIIÀf³MLLp’Ç%/:æîAþ·‹‡èœÁÁÁW®\IOO_¹råo¼Q__Ïu.€¦¦¦žžظqã¬Y³8É™™Iwìܹsãããõõõô¾ôÏ~ö3Nò¸ÃÓcn Ûå¾¾>¯¬¬ìêê2·nÝÚ³gOee%×ÑÀ¾ ››ËU†U«V9r$$$D­VÇÇÇæççrÉuÌ­‚íÚµ+55Ûå)ûž5kÖ´´´œ:ujÆŒPYY922Âa°ŽŽŽ7n@BB¢E‹¸Š¡ÕjwíÚõý÷ß@XXØ~ô£‡^½zõîÝ»\Er“X,NMM-..v9¥[;tèPCCC{{;ã`Ï—_|‘ÈÊÊ¢(*...)) >|xûömƒÙ7_¿ùÍo8Œ±oß>“É$jkk¯\¹R__OQTGG‡L&{ôè‡Á\2 p9¥[“H$jµº¢¢;æûAû§yû@PP7™à'?ù ·ßtww@ddä²eËè<¯¾ú*ܽ{whhˆÃ`Î •JUZZêÎqwrøEÇ&''‡‡‡‡‡‡ÇÆÆè1£££ôNò¤¥¥ÑçΛœœìíí¥÷ÚCCCÅb1'‘àóÏ?øð!dggs{]ÞÙ³g@___kk+ܹsÇ`0€P( á0˜µ <:UŠÿëëëKNNNNN¶EP*•ôNŽünذþ™\}}½T*]¿~ýÈÈH@@@qqñ /¼À~˜˜˜8uꄆ†r~ŽK~~>Øl¶œœœÄÄÄ_üâô ™™™ô‡U¾ñ´]à鹈üïß”——+ŠW^yÅf³Íœ93))©ººÚ¾ec_}}=½=çÛ8++«¼¼û1†óAˆoÊË˽8ª1….Û&•JU*UDDóY!ÄÌÛ¾º…¬T*mjjòɬâ_½ŸñÒÙ„Cˆ ,BaÁ" †AX0„‚!D !‚|óE³oY­ÖÁÁA®ƒ<†yœ³Ùl¼ÊÃ+¼+ØøøxKK ÖæqB(NLL\½z•?y¸Ž0U~%I'Ù´i^¦±±±ÀÀ@^å æöJ5ŽÆÇǃƒƒ¹Nñ{žŽŽ®³<Æ»Ï`üy7[­Öëׯó-ÚeµZÞ^Õ·ø–‡Æ—wÏ|ø 488800@cž'ñ9ðn Æ|[[˜Ç9¾å¡aÁ" †AX0„‚!D !‚°`„Cˆ ,Bù¦`†¾BÓCJJŠF£a>L£ÑÈåòþþ~æ³Bˆ'úûûår9óŽ1-˜V«•Ëå2™Œá|â…B!—Ëž@̨`Z­V&“Éd2û]š6Äb±B¡P(L:æ}Á°]hÚcÞ1/ †íBÏ †óæ÷`ôQ)÷h‰DŽŸŠ¢(wîÞ鵿ææ7ß|óÉñgÏž]°`¹å:¡×ë+++[[[Ífsdd䯷oßÎί€FcUU•N§ëìì´X, T*ÓÓÓ§9zôèW_}588–œœ\PP0gÎNò\¾|¹±±Q§Ó Y,–ÈÈÈääämÛ¶…‡‡û6Ibb¢Édr>H$²‹ÅâÂÂB…BÁÆ=šíG5¦ÔÉñŽÑÏâòÎÓÓÌ•+WvîÜiµZ`ÆŒÿþ÷¿+++¯_¿~üøq~(=00P[[ëd³Ùœ““óí·ßÒ‡††Îž=ûõ×_Ÿ£ÑÑÑÑöÏ„?ýéOÀf³ ö#M©ôØØ=0oÞ<öÃ<‹§Û1· æ_í€ÑÑQ°X,×®]ËËËãäbCQQQaaa`0¾þúk³Ù|âÄ úŸl6ÛÈÈû‘ý÷¿ÿ¥BBBì#)Ššò¯\éíí­©©Š¢233¹ 3…Gs«`»víJMMå»"""Š‹‹ÏŸ?ßÚÚÚØØ¸zõj°Ùljµšý0€¾7üäääŽ;–/_þç?ÿÙþ¯ìGzªG=u˜CÝÝÝ999ÃÃÃAAA*•Šþ0Æ+b±855µ¸¸Øå”nìСC íí팃‘%‹³³³cbb‚‚‚æÍ›·oß>z>ÞÒÒŸµÅ«>‚ƒƒ“““ÉE¢yÑ1wrøo»üÔ‰' Ú5kÖ¯_Ïu–¼þúëñññ‰dëÖ­Z­–«ô'ùààà+W®¤§§¯\¹ò7Þ¨¯¯gaÑžóp«`Ø.–Ý»wïÈ‘#"‘hïÞ½\gù£££`±X®]»–——ÇÕµ¢úúú`||¼²²²««Ëh4ÞºukÏž=•••,,Ý£Ž¹U°]»v¥¦¦²Ó®‘‘–Âsï¿ÿþøøxaa!Oî|Q\\|þüùÖÖÖÆÆÆÕ«W€ÍfS«Õœä±Z­ôÀš5kZZZN:5cÆ `§` ‹SSS‹‹‹]NéVÁ:ÔÐÐÐÞÞÎ8˜k·oßfa)|vóæÍË—/GGG/[¶¬³³³»»›?::ÚÙÙùàÁö#‰Åâìì옘˜   yóæíÛ·ÏÕUk_|ñEz ++‹¢¨¸¸¸¤¤$xøð!; CCCÃ\NéVÁ$‰Z­®¨¨`¡cAAA¤Ásf³zzz233322¶oßN×ét/^d?’ýh8;ì‡ûWDöl&1 *•ª´´Ôãîä`­cb±Øç󜜜¶ï¥Ç¸9ËyXæ2OAAAiii[[›ÑhÔëõ»wï¦ÇÓGðØÏ“––Fœ;wnrr²··—þ8J"#Úž^›¾µµU&“x÷ylË–-NGÿ“ËÓAà¯bïΕbïÝ»·nݺ§þSkkkPPË XÎã8¦¿¿Ÿþ­ûgrø|˜s@*•VTTLÙW4›Íü¹BN¸sƹãÆÃ`0¨Õê²²2OÛ^ÿ\÷Ñs»=C;ïp‰CÓÃvÃK`ÇÐ4Ƽ]Àü|öc çƒß”——{qTc \¶M*•ªT*žœ5‡ODDD0oøê²R©”þÖ¡éÁWïg¼t6BaÁ" †AX0„‚!D !‚°`„Cˆ ß|ÑìCýæÅf³ ’ËãÌãœÕj%ÇkÓ³‰wsßÄÄÄÕ«WùóîÁ<η´´ð';<»&Qz½^ ¬\¹òÇ?þ1×YsçÊìàÑ,((()) Û…šœœä:Âx´ChúÁ£ˆ„Cˆ ,BaÁ" †AX0„‚!D !‚°`Ä£S¥˜HLL4™LΧ¡(Ê«þcžç09Ó¤`&“Éå-Õ\ޱƇ0s|ËCî""D !‚°`„Cˆ ,BaÁ" †AX0„‚!D !‚üòT©µk×öõõ9މD.Ÿ%‰bccÇDFF~õÕW˜çyËÃ&¿¼l[kk«L&+((ˆ‹‹ónƒA¥R•––&$$`žç-›o½õ×<¹téÒ÷Þ{/&&föìÙž>Ýçk óøW6ùeÁ€Á:#´¶0åa¿ ¼ZgD׿ñ¯<ìðょ댅µ…yü+ ü»`àö:cmmaÿÊCšß ÜXg,¯-Ìã_yˆš§ëŒ“µ…yü+9Ó¤`ðŒuÆáÚÂ<þ•‡éS0xbq¾¶0å!aZ "##—,YòÞ{ï=zôè“O>Q©TË—/Ç<˜‡+~yª”Kæí·ß>tèT*å: æq…oy|hz !žÀŸ« D !‚ƒëÝ)IDAT°`„Cˆ ,BaÁ" †AX0„‚!D !‚þyDª¸? ^%IEND®B`‚puzzles-20170606.272beef/icons/sixteen-48d8.png0000644000175000017500000000246113115373744017664 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá MÓæ­9IDATHÇ–KoUÇû%X°@b…Ø´l]DÅPYQ ´€T¥U¥F@y„"š@+”¦nÅI¥áQ×ĵâ´ŠÔD¢qüŠ˜xî{^wìLâÄI Bâ0sgÆ»þòbŽçüæž×ûþ:ð¿!ÔÐŒ€¸®·˜ôÒþªïíúÚ·¶Öw›ªnCÒ@£¾/œ&z¹ayÙ`؃ÄVòŠÙ4 ι1PØC€‘ý|ÌòÌ´Ÿ ý탲6€–cj+€ ‹0«Š‘ PËÀKGÀª¢¢SGá£+…·ú¨+»¢ö¾9§!ÉþÐÀHhœÌžN>ó’T%€•3Ç”Ç×€˜c߯¢ñ¹A‰C²žÏ¿þ͉!Ë Ø ¿ñçW¨â>¹—¼Ÿé-2Ô iì±Þèá—󌊊GžŠ?sh\ƒ6P6‡¿¾qýV¢oACÍh.“Ò ²ê&Mäåt¡´”¡NÒ@]ü!"]èŸwª×,«¢ªä••¨*cª‚½*UªjÏ}‚IcdÛù°³ï W~ ”Klöa+Ì—VTª„5•÷Fƒ:Í­tÞW®°€A&¿’óì쯀‚ÓZ£*&Þ! Ýу¾E6œÛßWKµ*7qSç†öta™F­YªÚóæ ¯®Yëû öŒ¦-ê½íŽié·MÛÍ©c Hˆ™ó*E`èé[u{²¸©¼Ÿ1`€èJlþ2U¤Ä0™›§Zbq_f™x2úQÿ²[¨Í>>±ôÄ{9æ2f'YŸ?'ý¾^ õ^™ú¹/ëÍR#¤ò§Âåw_›6°sâË/n|õ“Ý2Gî&ã‰éókT´T¤T„T:|vé§g/n!hמL=ñ‚øõg‰äذŸƒ] ’>{öÓù/"B"øRÏ͹هë\úlð‹‰ðFÛB²[¾©mYÄ-+ÆÛœmÖê€P¬žU j++F2›Ã€ Ѻh¡@¢µ÷¡!¯b¸×iîµÚ]ƈ¦6(jˆ¬­Ùe—¢Óm›Ãl6›ªä² å– M¹vºÜaøhm»¶³SÛ¨î_ÔêˆÛ{à €²,— @Ù¶ÅU«¿ ˆ­k˜¼¢b³ 7¹{£àä­N^¿º¨º¥@J&‘Ú~KZ岜4Ý 1óUäæE™t°ŠÝ»©º2“£wg!í \ŽÎ†¿Wda6}u6þet {{$~ûÖ…ž’Ø?䃧≉w$»œ€´ïBsñÄÀ}çqrˆÞI†Çº‡dÏÊÄàLß¼Ÿ´žî›rç³ €LéÜ"÷ƒ†zîü°ÖÁ?ø×µfÄP[k¬ÓnfADq'ÿ £Ã£€¥¿G„8½“@K˜%tEXtdate:create2017-06-06T01:31:32+01:00Û÷¦m%tEXtdate:modify2017-06-06T01:31:32+01:00ªªÑIEND®B`‚puzzles-20170606.272beef/icons/sixteen-48d4.png0000644000175000017500000000132613115373744017657 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA† 1è–_bKGDÿ‡Ì¿tIMEá MÓæ­ IDATHÇuU¶Ã ãè97ó[ Üû«ë&E‘P;~îˆÛé[sê1ê²t*GïYXÂ{,¿—í©k¯SÛ2ÌÏ ¨9íÞzíXOgdîh:ÀÙqfÞùN&Í„»¾#7Ï-ÃÜa9¼®EøÇHXc¡Ö‰F|sŠÓX™p]€Q©û8ä–Iá¿Á4ïFöÙFîbÌÓw¡¾ ønô’Êsü!ÙR÷XÏÂíê’9gAsØé§:w½»þÖl»/²4õÈÖzPJ£³biæŸÏ"#Qúáf8™MP“ Ã<ÏgÏÎ?é*¿úµ ۪„$Ñ%Ÿg"H¢Ò•´öGÆ;é4$;¿'˜…Kg¤©¢»‰áPr'ÙÚ ¥(¼ó¿“â<­PHB¬•Ƚ]7Cx,Å©óH4u᜾Èc.¶ul¡(éÑðF6?=5a=ŒÐò‹V¾)ƒïK¾YtëµþÃm6X›Öƒ³Ø:ôHeþÌ’r³Éÿ­Ò:!·íñô‰GQÝ…õ’¤¯9ÍìÞˆ^Ün1߈¬ÔÓ ® Jð­²{F ¨¡ Áîü[yR)áÅî>»ÒéÙ˜%ü‘:ûý&$%š'>IPÿךŠ\‚¯9 T¯^8£‹dݯ´Dz_t/J<°¾½r,|`ý,ìß{Jé%tEXtdate:create2017-06-06T01:31:32+01:00Û÷¦m%tEXtdate:modify2017-06-06T01:31:32+01:00ªªÑIEND®B`‚puzzles-20170606.272beef/icons/sixteen-48d24.png0000644000175000017500000000246113115373744017742 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá MÓæ­9IDATHÇ–KoUÇû%X°@b…Ø´l]DÅPYQ ´€T¥U¥F@y„"š@+”¦nÅI¥áQ×ĵâ´ŠÔD¢qüŠ˜xî{^wìLâÄI Bâ0sgÆ»þòbŽçüæž×ûþ:ð¿!ÔÐŒ€¸®·˜ôÒþªïíúÚ·¶Öw›ªnCÒ@£¾/œ&z¹ayÙ`؃ÄVòŠÙ4 ι1PØC€‘ý|ÌòÌ´Ÿ ý탲6€–cj+€ ‹0«Š‘ PËÀKGÀª¢¢SGá£+…·ú¨+»¢ö¾9§!ÉþÐÀHhœÌžN>ó’T%€•3Ç”Ç×€˜c߯¢ñ¹A‰C²žÏ¿þ͉!Ë Ø ¿ñçW¨â>¹—¼Ÿé-2Ô iì±Þèá—󌊊GžŠ?sh\ƒ6P6‡¿¾qýV¢oACÍh.“Ò ²ê&Mäåt¡´”¡NÒ@]ü!"]èŸwª×,«¢ªä••¨*cª‚½*UªjÏ}‚IcdÛù°³ï W~ ”Klöa+Ì—VTª„5•÷Fƒ:Í­tÞW®°€A&¿’óì쯀‚ÓZ£*&Þ! Ýу¾E6œÛßWKµ*7qSç†öta™F­YªÚóæ ¯®Yëû öŒ¦-ê½íŽié·MÛÍ©c Hˆ™ó*E`èé[u{²¸©¼Ÿ1`€èJlþ2U¤Ä0™›§Zbq_f™x2úQÿ²[¨Í>>±ôÄ{9æ2f'YŸ?'ý¾^ õ^™ú¹/ëÍR#¤ò§Âåw_›6°sâË/n|õ“Ý2Gî&ã‰éókT´T¤T„T:|vé§g/n!hמL=ñ‚øõg‰äذŸƒ] ’>{öÓù/"B"øRÏ͹هë\úlð‹‰ðFÛB²[¾©mYÄ-+ÆÛœmÖê€P¬žU j++F2›Ã€ Ѻh¡@¢µ÷¡!¯b¸×iîµÚ]ƈ¦6(jˆ¬­Ùe—¢Óm›Ãl6›ªä² å– M¹vºÜaøhm»¶³SÛ¨î_ÔêˆÛ{à €²,— @Ù¶ÅU«¿ ˆ­k˜¼¢b³ 7¹{£àä­N^¿º¨º¥@J&‘Ú~KZ岜4Ý 1óUäæE™t°ŠÝ»©º2“£wg!í \ŽÎ†¿Wda6}u6þet {{$~ûÖ…ž’Ø?䃧≉w$»œ€´ïBsñÄÀ}çqrˆÞI†Çº‡dÏÊÄàLß¼Ÿ´žî›rç³ €LéÜ"÷ƒ†zîü°ÖÁ?ø×µfÄP[k¬ÓnfADq'ÿ £Ã£€¥¿G„8½“@K˜%tEXtdate:create2017-06-06T01:31:32+01:00Û÷¦m%tEXtdate:modify2017-06-06T01:31:32+01:00ªªÑIEND®B`‚puzzles-20170606.272beef/icons/sixteen-32d8.png0000644000175000017500000000156213115373744017656 0ustar simonsimon‰PNG  IHDR V%(gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá MÓæ­zIDAT8Ëm’ÏOAÇùÏŒ7O¸pð $rð@b¢ š˜p1P,Ðú‹R± mLz!9Hèn‹íÎ{3³»óc»E8øO8³K[iüîå›}Ÿ}o¾og‘üG€cÍ!r¬‰S| ñ'Š‚»øÞ…‘mAR@F}Ò÷}t„—:¸Ä=3ë*¤C_‘u%øšùc€|vÛÅ» èþEã˜+ü‹je¥Ò¨¥Ü«ù–r”7|½Õyò]8¡,o»9žúÅûåù¶´Àò»õ§wCYÉV›ùm–ŽðŠß~œ†vVëõâ5wEpvp°ºÇÓ„/ u  •Œ(uí!é>e`PÊ\“ŒÐtHcB’"ìt]û¸Nम{¥q²(`Zñ‘TFQ¤XlŒïlÒašu• # ‡¿ šˆ×š0ͤDjw¥9Þ®x3€€ž‚AõºuJmR8vz­»lÖß‹ @‚…ÖÂ7€§K/Ÿ)YÚÈdÊæh¿=5ÐÏ× .}W â勯•ü×VaÃlMðžÂþ§Ú—KFì”Ï+7~{'»–! Æ#hlî€àÐľõ| ›„ƒ=£=ÌF¢¬«íz‘›˜!MR€ë¸Ü,3QÇ·ÎùuÓEQ)"„É…QdЦ·Ú¢\É yLÉpüñÿ¢X<óÁ’—¥RÛŸ–S€èÚVöМ‰j}Ìeå,ì¨X=¤I‡F¾¾3G+æê¾0ÿ¯ù椵¶ÂÃèvó{Ôö j™B†Ð™ˆan›'«QÞ°û›3 cÇþ­©Ôñ/m2©öæç%tEXtdate:create2017-06-06T01:31:32+01:00Û÷¦m%tEXtdate:modify2017-06-06T01:31:32+01:00ªªÑIEND®B`‚puzzles-20170606.272beef/icons/sixteen-32d4.png0000644000175000017500000000072513115373744017652 0ustar simonsimon‰PNG  IHDR V%(gAMA† 1è–_bKGDÿ‡Ì¿tIMEá MÓæ­ IDAT8Ë]S ¢1sôÍͼ!¢y»ŸÖ(Ñ„‰¬Êþf¥³÷?ÞO¯Ð ±Î]fÝ-t.ÜÚ˜¯`’ ûƒÃ |Q@ôŽ9õÐæ ´íMÅÖÁbîÐiÁÆ.ÖXq”D@&ßuxôöhꡎžW¨ÿ4]® Ò¥e5cJt¦e–zñ¿G*]—ó‹P~O†OIŒVi3{{Bõg2à3aR·¹O;FëñÄÞц&ÏÂÍ2’§oe‰iÒ/‚)}ó¨¤`çÊšjCM¼üU¿¦²Y-ɦ G£î]öyïEé½À+ ¢ïPšõUtL£;ÝP–ªé¦A?ŽVâ ±hÚ8»däûe_-‰Sq»ˆ%tEXtdate:create2017-06-06T01:31:32+01:00Û÷¦m%tEXtdate:modify2017-06-06T01:31:32+01:00ªªÑIEND®B`‚puzzles-20170606.272beef/icons/sixteen-32d24.png0000644000175000017500000000156213115373744017734 0ustar simonsimon‰PNG  IHDR V%(gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá MÓæ­zIDAT8Ëm’ÏOAÇùÏŒ7O¸pð $rð@b¢ š˜p1P,Ðú‹R± mLz!9Hèn‹íÎ{3³»óc»E8øO8³K[iüîå›}Ÿ}o¾og‘üG€cÍ!r¬‰S| ñ'Š‚»øÞ…‘mAR@F}Ò÷}t„—:¸Ä=3ë*¤C_‘u%øšùc€|vÛÅ» èþEã˜+ü‹je¥Ò¨¥Ü«ù–r”7|½Õyò]8¡,o»9žúÅûåù¶´Àò»õ§wCYÉV›ùm–ŽðŠß~œ†vVëõâ5wEpvp°ºÇÓ„/ u  •Œ(uí!é>e`PÊ\“ŒÐtHcB’"ìt]û¸Nम{¥q²(`Zñ‘TFQ¤XlŒïlÒašu• # ‡¿ šˆ×š0ͤDjw¥9Þ®x3€€ž‚AõºuJmR8vz­»lÖß‹ @‚…ÖÂ7€§K/Ÿ)YÚÈdÊæh¿=5ÐÏ× .}W â勯•ü×VaÃlMðžÂþ§Ú—KFì”Ï+7~{'»–! Æ#hlî€àÐľõ| ›„ƒ=£=ÌF¢¬«íz‘›˜!MR€ë¸Ü,3QÇ·ÎùuÓEQ)"„É…QdЦ·Ú¢\É yLÉpüñÿ¢X<óÁ’—¥RÛŸ–S€èÚVöМ‰j}Ìeå,ì¨X=¤I‡F¾¾3G+æê¾0ÿ¯ù椵¶ÂÃèvó{Ôö j™B†Ð™ˆan›'«QÞ°û›3 cÇþ­©Ôñ/m2©öæç%tEXtdate:create2017-06-06T01:31:32+01:00Û÷¦m%tEXtdate:modify2017-06-06T01:31:32+01:00ªªÑIEND®B`‚puzzles-20170606.272beef/icons/sixteen-16d8.png0000644000175000017500000000071413115373744017656 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá MÓæ­ÔIDATÓ-ŽMjÂPFßjë:ê àÜq›A…€ˆEp©IxI0BÌ»ÿ&fÐôE½ƒß®C3U»ƒÃx“~‚ˆr}™ù Uá×Û\œü­^6nÞ>®¼LRp6T¿ç §Ÿ¸ÜÅ™€@K ØŠpl“Ø¡·§( eÑa¨;í¼8褙¿zkßgçô3F1ì³ á>Ó|}‡æ€®ý=ЬBÄªÄ ˆè@ê¯R¸Y:í(t›|³î’5ãCpž™}zx ÄøêÓý̯ 2Œ&%tEXtdate:create2017-06-06T01:31:32+01:00Û÷¦m%tEXtdate:modify2017-06-06T01:31:32+01:00ªªÑIEND®B`‚puzzles-20170606.272beef/icons/sixteen-16d4.png0000644000175000017500000000045113115373745017651 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA† 1è–_bKGDÿ‡Ì¿tIMEá!:ÔÖ;]IDATÓ=O‰ ! btGc3ŽÒš@by*(ú($´¬ ;âÍç|Ï/>_Tp‹.tñê/ÒZNÞÐ Cÿ«$X‹† ®fjg/C$m©™ErŸÛ6çñL̽Œît%tEXtdate:create2017-06-06T01:31:32+01:00Û÷¦m%tEXtdate:modify2017-06-06T01:31:32+01:00ªªÑIEND®B`‚puzzles-20170606.272beef/icons/sixteen-16d24.png0000644000175000017500000000071413115373744017734 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá MÓæ­ÔIDATÓ-ŽMjÂPFßjë:ê àÜq›A…€ˆEp©IxI0BÌ»ÿ&fÐôE½ƒß®C3U»ƒÃx“~‚ˆr}™ù Uá×Û\œü­^6nÞ>®¼LRp6T¿ç §Ÿ¸ÜÅ™€@K ØŠpl“Ø¡·§( eÑa¨;í¼8褙¿zkßgçô3F1ì³ á>Ó|}‡æ€®ý=ЬBÄªÄ ˆè@ê¯R¸Y:í(t›|³î’5ãCpž™}zx ÄøêÓý̯ 2Œ&%tEXtdate:create2017-06-06T01:31:32+01:00Û÷¦m%tEXtdate:modify2017-06-06T01:31:32+01:00ªªÑIEND®B`‚puzzles-20170606.272beef/icons/singles-web.png0000644000175000017500000002671113115373722017737 0ustar simonsimon‰PNG  IHDR––j.>gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá‘ëb,ÑIDATxÚÍ|wtTG—çU„ ’1`ƒeÀ&™h‘s²ÁØÆØ€ &~dl2&JÉD”¥VΩ[9«Õýrê×QØ3³3çÌîþ3{ÎnÕk’ºeãùfÎ~÷½«zõ~ªpëþêÞ*`þ!þøXô?’¼Å ¯„çð¯9gòæÏ<ßåñ¿DøW°h®*¿ KNnIYyyyInŽòXPT^Q^ÑMÊ+4…Jé‚ÜœB * .ÈÎ+PJÛ+é.……E]Pú–Ÿ™‘‘‘žVZòôZdäµè"uz:R¤=½äD.þ’€ÿ˜‘šW–r+2âêÝÌòìT¬HJõ8H’Ê™:3%Ù¹ZõVA¦çY£åá·#É;~5™XÎPûÔÄ>ÌoyNh/Ù?³¸€ï¢m'2 õŽw1U#;ª99/ÇàL]–¾i­ ž¦ŒÙ3\ÝWE<޾ú¹LN3R|Õ“^.®ÝÅÆå5²¤Hl÷ƒqÇ}~ûoCaÀi‘¥‰„ZÞÉfU¥卿s²•Ô]aQÒƒÞ>'HQ6™e‘>àqSD°œ·V^#TMƒ¥’d4E)e |¡ãXŽSC°Õ´“íTÝk¼ï1UÓFzŽ ™ÖªO]¯[+z‚Õ(ÕójH½®•6¸.çÈøX4¡å‹&_«»À¢št+ݘí=U+k[{«L1„øÔ=£1Ú9¬Ü&nû³V‚‘[_¼4Ó E[ÏÁ!΋–^¾À"ÓÝ`Ñ´©­Ýf苦dôQ#ëVšu¦¿F&˜¼_/_¸–!±WÍ€É ÑNaes7à¼`µQ?ŸxÎѨfóFHK­Æ°h©øÔÏHΤÛÛî5,Z®\¸™Ó ÍÉ™W/\W¬¬œÒG.Ç[ NŒfôÙÊ­ÜN¤º:ƒVX=úc„ÜzÞÜa•€ 3%U O«Á@ˆ¶+H‹êÙ!wE‰eó<:´Yÿ ͵|Ý©=³ŒTwX¹ÅÝI–áZ¿9´k¸$˜I†fý?U¹9…Uú¢,$i½üɶáð…„k'Ú¶ÂãzüAÒv <¼S´ÐÍ·L‘§ý²‰ïÒZâ:è¿ÿQäÚ|™î‹/y:r•ˆXËïÿòûçÏ,–᫨ÞÎ`}Pöùà"‰BïµëÇÂZizìó½žÅ°ZoAè韮·X©Îc‹’¯Ï¥óGcZí°-¥¹Á¡«‡ïdª{'re× «)qgÿwzÁZªŸ6܆3¾NaUÅ2øSLÕ˜X4W:‹a”Nüp#xfèÒZâjðÄÕ}F³`Qæàê‡:qjнµ¸òHˆ6cXò¶>~04‰2&Á ?§°ª|æ·â Mó5¯`¡Ï†~ÌaX¤åñ¬c‘_yÀ»øŸ{3¶øŸ­¸"So`‘–oßû›;ìaEØa±T}YÞ2ðIAo¾,Š­z>çI»YýHŰ´Ál4­¾±J¿¼‚%Ì·è*÷†•h„t‚õÀ©6á]ç` ¸òkpUéDK«ñ?v‡C2îÄ;pº‡NõÛ¬ yN¿i[lÆ…PÇч| À×§ÀÞ¯‡¼ ñ‡ÙúÀ.‡Nr‹6xÒ iÝ.îè»SêÑ48+¥ñn#a¹ìêŠ TH–"Ú·ÃCl h–Zîè=¯kJc½1§âvpõu‡¥]†í¾€¡âþëý-Žo¸ç £Ñ`à#ž«zÒÛÕ½»x„¼FZ(ë+’l”%SV8¬hâõ 5åÔ;åÕöN©»ÀÊ”yÞš9Ù=à«ÛIIw¾ rŸbëÙ—Ïk‘8±ÉÇsú…çiÑÇ?p úÉ`ØøzÙ 9“Tj££š—s³”æeÉo`¤V•—kêêŽNï¿8í`u½¦¼²ðÙê+‘,_¶rõš5«W-_†W-Þš^ZQQVÙòxùHÜßÕÕoæÙ b+BE’^¯×éM%W!OÍeÔÁxŽoÑ‘u -Êt¦DY¢ÿœ%ÿ(†€ÌZý6_˜°yÿþï'‚÷w52…`¡uW  …‘ßî?üC¸‡ë²<Å7Åé¸WÕà™ØñyK`œÂ Å°µ´¨éNÈrGÁº­¡µUn)ú†¥K‚E u³aVj£hm3å½|îJ\cükXä¿¥µXCfÐÀX«ÄQzÁJ–”a¾‰VM-Ö†õŽ08D½HV2—M…Hký«Ö¢;5VgXXM9¢¡»Ã¢ßh¬¼T5bx‘•D¦C2›EŠ´”½7°²:‘¡Â½Ÿµ¢af4›• ebžg"ûªµD£É$uTÙ – ›LºûâÙq d¸´‘§œÁJm_í™lÑc'§8)Q#Є9Ë{iSLëO‰ø Y™•œP‰°RýÈ÷êÑW€0•¹iie2×ËÕæ¥§‰B×¥škIINIQ%w‡UWžšÕ`t+·Håõ}‡\Iˆ lüMÏèÛ÷y])Ô že¢(ã± 78‚ý$½í®Ë¡Ìf{úý]ÀeÀª+,îìä׬«ç:ûò”1“=WXÒ×4•ö}݉‘£Ù ˜†2ÂBè ;^ „lKŸðª«j (˺й>ð£âSò‡Ã2›±?Ê×õX´Âà8v7;uâ˜ýy(À—]x"%çzxÌ[±lÚa¶3,Z¨8cu¸7ºóD¾8n§˜‘–30m0lǰhyÉà˜#?HoÈñ‡·Ž´íõ°s¦{Õ‚ 9óp;¿†ÅR %CQ*vƒåÚ+êQL³ÉÁ±iÿ—ß—$™»ÃâÊn¸žGô‰2äõŸbo-Úð \ þÆ^·”ñ -ª<¶ÛÉ+ózS¡7¬o%º´–,’<5&ºvb6öd]ÆÄHÝÜ@éÌ¢Å0»‰sFÈ"÷åfAR~?ØfÓã/κî³)§,¡¾‘íÉ" Ę«@‹"yÃvð|Ø–œ7tÉóÝa`u²Úb)xÀ{Nè+"dOÍÈÅ< 'ÿC ûÿƒÀÿž ÎÀA¥ƒ(!ÝŽìܰ6¼‚e,ûÅw´ÝX’n ô¹*u›‰º&Y4#úõKgŠ_qòÝat¹èØZWá†LQ¦i0eÞÇž0x‘.ù>üÜw»ÒD¬ ­ãVNéÄ×M;,cÜ0˜ZÑÆw‰´±h"ŒHi»Ù-Ö$±­×N»ÀâMfùÞ¸(; ùÒ!ß‹4%ÏÄ4ÝÅ<›xÔç{|nŸC"Çžm¬îûšjí{ ½ul#Dö‰ée9e]`ÑbÜ ö¸2·¸ËÃ_<]R? VêÔ‰´ôðWuEé2€ °„¼¼5ŸxëÞÓS>°0IÇ¢ïù¸ð”K4e<ûÛqAÁ“Ït%d¨m—ð þhW¥3B–ÁA!^…9ËÒ$CqìË¥•î™d8žgYŽçð¶ßgnÉ-ë Rbé¶&vQ¿[‚$/³Ýì/âhˆáÕŽa·MÊ{ð•̯–}’5m;Mq†¼>SHIÿZMY/Â~*ö?åØÐ~v™‰]ÔÝ ÙaØÄ¢Søaâ€]–²$Òtæ6Ø(Ò®6˜/Âb¡“øW`u‘·%d4·¦$ØÌ"Ï‹¦Ö”°Ê’hJŠèýÎmÙ& ¼(·K¤úøÖ ñú¯PÝ`I,oŽ ê3õdv]}ÎÙéÞþ&^ªLBãÉš4ÊýýªêÆÂë =ö¡ÒGˆqN ãë%'ÁA¥vE1äf;Uw!déõuµz͆}óáÒ;ä‹¢®¶©$¥±©±žh<4ÔoÍxõŸŸA5Õ7W&Ô47:HS}b™Vù­¡¡KCƒ]¯*Ô68×fejµ Ú"ÕX…q8Z•–¥Î¿ºwûö½¹êì´tÄŠ‹‹ÉÊ¿up×νçTE‰1H‘–ï qñi‰X›’–™“™–ƒõ©ÉNJÇÇ©TNÕIÌk+_µ¸ÜÀaF¡6v0š`å­Ð+Fa¬¶xZ¨õAŽÀ"ûØÂäh^@½6uÕüpÏØµµÄeð$ÝXÿ ¬#¸ƒ¸œZR¼Õã¯òͯ )‘ë¡O¤²Ú’Iƒ”Q††:‚¥WâDû¢> ,qÜý¿·\AõïúN°(ãyØÿòüáôÿÑ¿u'Ànü!Îb`Dݘ܈\$¡Äå;;!£eSaà3Ë«É_<#´£ç܉ Zš¤´×ìã¿õÀ<XtEêDÈ(y|}è³^0õ8¶okUñ •8$[xµ–nzÃR}Çð ×þŽ˜xÜp“É7éì°Zòׇ䉸“4¹>ÒÑ ±¨7-š«Ç1V¼e3ÞÖ)pG‹ã”O»€/õ¶°VTmõª 9Ñ»÷ì©^àù‘#âÅšÀG„BÈǃÛðÆ _«DˆY}j´ç‰eÈ[á ’ i‰…}ÊLdõÇ=³Â>»#væ‰ü•}GO}Û>½B¾½Ýz &‚¯ýn¨;ôþä¡„·£ëB'ç*vK@<½å“”ŽìVcè Ž&Ì1žx\o j oqyPaß³XÿzÝbÿÑeÈ›l¦Îôƒcÿë­ÇÖŠRý¬À⹆JM9aRÒ#vB´J«,>TEI©Z­.­zµø´ü·­«/Ó¨KK5š–4æÀ¶¬’…È^ciIs7B†H ¥U×;²×Ä")ÖÈ,Aó¢$±È:Ö§ðùŠùˆEÄXñõÔø@µ‰`%»ž#$}Xÿ²ìâ7®‡´N<ôÿ`•¶˜~‚Í‚L8Fé9[|Ÿ°ík¢s6ö Ly#ÕVZ‡xEéI³6Y’Þʱq»–ž~€9yV+J^èNxŽ)2"BÆ9zpŠ¿%ÇßâÚEäímrÜÏË2ýŸæ‰=·Á²ÆKÞëoVq²Vu`<,n”¸¦8=âþÝ…ÃN3e*³OæêMté¥ežƒž›i^U*1¥17[t¦îâ4_é ˆŸ_ükûÅZ’ Ä’/]½ú‡‡øÁ{hVG×Ç7S°’ú­VÛ¢W~§t‰•zmÝp¶ø£Ò®ž»+Ø&­NUÂÚKˆ®h[tÊÁäd1vug!ØÒNôµ0F n%&ªòJÔê’1-1>!!!..!½ ¸¤(?ñ³¤NÎ..**(©P?ܼtÞâ 7ÐoùEEEˆÖ¡Òˆ°¥ä•f&Æ+ÅU*¬î.ñ¢¯õ5µ55ZmáÁyS&ÏÙ—§ÕÖÔÔÔ§Ô"©nÔVF¬_¼`åÞôææÚêÚú²ÄÊ:¬n©½±jÚÄë£[ê«kë*³7Mš5sæŒé3ç,Y¾bù’¹3§OŸ9sæôûŨòê:msÊ–Ù“¦.>WÞÒ\][[Ÿ•‰ÔÝ¥¦¡@Õ™ì[7å.t÷4(4À=<Ã$²re"/ðœ¹b£—wHHð€·°'¢ÌJZDöyÖÜtį÷ÀÐA¡Áž¡‘´‰õEÊf¢ƒÜ©2p¬,>ùÀ=(•÷ñÚXaá8‘}ÇNîLöó3xÄwÀÍÑ ¢ÔølëpøŽâØò$4qåó½ý¿¸UÅ£!¿̯BFšž ð\zIM›ˆÜ3!,O¦´E³ÀÓÍA\îTò„X7ÆíOÕÊ|ÕÍuþ½.Èç|k„ï¶cÃé–Á7Um&ަ9c{íV˜Ûh(Kb°˜[ ˆ“^ï™!cäK$ÛD#ÄÜíà SSO­UÉJEï{Ò¿0 ÿ‚·ZóçÂN»$a=ülÑ4¡(Š$DËUX&•'QÈœnd½^Q#sšÐ÷­6¶Ùü涘)‚ƈmUô/  z€U!5„õM´qJ刧ÉÂøÑ–õÚ—ïÏë « µí4µQŒl4›Œ2‡¾f; ǵ±æçð™Ì’’Él6E¼ø<‡uD «œ@ˆ8Ô!¡âÈK5•~ÔP2£X¦U.1Èù4˜LFœ0I²òHÐdtÀ’&³É,;ɤÌËn8ÅH3uç–Ž}wêFõ²yn*•š¨HéÒÜ1Ã'¬OG Ѻ§ÐÛ û¾¤ùüÐ!Ÿ`'ÔzÎTLw ëv}*ìi%8íéùi%èóídŸÓM:|Ø;!Kƒ+Bvù Pùøz¹Àt-j/C–ÛÚšhˆ4‘”) üû¸€¿J¦(¾~ðÄ¢"ØŠýfRÎ f°wÈÎ P;ïÄ›äœ <)ç{¹÷~ !MWà¬Úž § W7ø¸‘w€U±p˜ÄІ˜ O‹R?…ЦÆfýàY#Ò4“ZU¿ààK=vb®@œ¬cfÃpÂ(>ûIx0Ç)¬û™¡«­áïen„`=¤PÝ{M±}¼%.å¦f“y§¼ú®ï~[ y ûoÇPM–tÜëú¨åØÅ£­-i©+Áí¶’`ùÐãļ0쟓æã°g¹%æl^âV̉ÞJTг´í‚þvX ½28G´ÃƒC?Ø^+: E]…;8Ã2:žšcªPKSr4œëµSÉd4ü„nï3ö¸d)ì=õ!iÊt Ó/‚!¤B+ô!K—;…•°”ž£ ~)°Ê´²:`ùöá0ªÚI&e<7+AL¹nôOTò©paBF ª¾ qYVßD„lç¹/škù¨ú_Á°6%ñÒ2o…SX‰[ ÙP‘~x‹h; Y’}ÈßÉ«ª\ pFv„‰X%æ,æŒ÷`T¦dþ>ƒ³{p¿ñË[ŸûÀ6œ¼+”Áš{¸ ó£ï~ÁQjç‡,vÞZ‰[¡ÜN•ÔZjNù÷Í{;Z‹–lÖ’Þ 68´¯¹åua§Å¨ X¢m•ô^é‚[äuÈê •µF¾=ÖVp˜øÅº›ñ1Z~,Jî2€\h'Pßmp>¶bxÅá†aEënè_mV<[î ¿;ÊÎ’…Ö3®°Ï!e‘/L™9ÍD)¾/ôY¸féÜ'£ñ“Q)ëEÂr;`þ_ü„fÙö­ß£ž*3aHX¸vÝC¡ß’8E´]t¹1×)¬‡ñ6¶“ˆ¿Ù6 |¿ÙƒÚV¬ë¿¨ˆWúþ´Ëôí+½Á'Ã!„.ä”퇑4^WêqƒSFœøã¹¤æ<–õÆøP̯í&p(Œù^a1‘ /˲éSè'+d™GqvK7éœ#^„ù« ì2Q”ü~Ô°ö–QÈ1vsßà0…ܼR¿e6‚«ºïÞýî¨yšh]×÷QvCØh´HSš„Çc5&ô‚¾õ D¤ëV÷©FÇLT·Ÿâ\Bs<ìîÁÊßjºÓ49Ýó{¨ú÷ŠxŠáGNHÎëHp¬K}ú0¾ÑD;[Û€¨VB°)Ò*Ñ„í>|¯±]ƒ½6ŠÍV›E$ñçó|g·Äð™žK öMSS«ï‘4¿?¬\=½Â0- ñ4K«½r´àî†Ûé2Þdµ™9§‡2bfŸ§6Z§Çé‘z‚±%øN$+)i#œ³rz¬FÎmÑŒ Ö!â l1ˆ8]’"_`Ô‡{İù=xårá€ÑeÊ^¹Žà-ga£9ûMêÏ›¼KGǦj¬ËYÖb@ä—‘,üwÕ¦²$o€oÕYŒ,Þ·JÏ‚}â-8B&í€ÅÕ&3‹|Þ"ç~WÌàoãû†<—¬M¬Ñ¢Û ‹)ñ­ü-ž¤…Œ­•-¾5f× JþËlá²p¸ âñJc`ãt,m8íêw$Ekl7ÔÇ~dZë– ‚Å“†ìQ°êq…Ðf!³Î‡ïYæíÜ@Q4>ê}™>gú ÉJ´T‘ÄáàJÌ ðŸ>gæ<Öl¤…¦øfš iKÁkü§sg½ïâñm‰AO5õàoU‰,mlþ1F…/œ?­Ìxnä™·®…I©*U²*ÿÙ¥5aÇ…­ºð4?5Y¥R!­*%9?á—o&¼3tÌ‚“r3:5¹¸L£)©+O<ÂGd¼‡­Q[EÎД1TÙØë6†ú%×xV2«æ îþì5`ò=YfyQ¥±§ÃòöÓŒ¼ýÁøé°8y˜‘¯öë5…sÏNéísAB+8"d”)ö·1{SqPx®¿ûN†cê3†ƒG÷œbèŸTÃRÃJ°úaisyÜÆá0¥ÈHþ=ÉÃ<Ã탩I¯B詳`-–£™hˆì=â®ÑBQ²–4j3†8k­€¤ZV*ï¾»ñ…Aà©>ë?(öïØ±Á òaØÌšõX(Š0 »`gç„dc‘,—aßÞ¬j¹ö=ߘV®E¯Ø_¦­p´O–)¹S„Œ ô´#¬¶¥Y…¯eÔ¶—/CÉš¶¢Å,NÎí3•”PUrûo/lIY/Ã>¢X‰µâ×D+ÁÙÚ_¾D ­7•…ŒjÎx½HsíJí]aѬùÅo/,ÎŽ¶ep£ß¥x4ެZ4/ŠãÇ)É,e2IsüãKÖ(qž [jÎ`ç°´Oá´M/hŽ}µtÕŽd-¡–8–[ü:Vóå¹éÙi¯³F]ĺÅ_œsBÈpêÏ=3âa8MêžA "=UR#”Õ¯BŸu‡_¤¡¤ßܲAÎ;±9,LÇéÛÎ>+áv UCK+}£Ë;"d”qxÁÖ.ÁZ(ùPÙ˜V™œ%JõSÜíSç÷»Á#%ZBÉC?*<¬$J™¿‡Ðˆ’¨Täí Sÿ´d÷ý/ô”1ñÐÓ„3}á}LC¬á§ªŽ™é!8DÈXjL|¢ÎެpH”êH+CO–y€ÜIƒÝÉÞÛWI+£Í`X³}ÚÚ «ržëº×ÙÑÎ`ùlÂÀi¹cbúÀLóçŠ÷>±§ÞPBÝÀ¡»{uƒE»Àkgl«39%dQJ—ëù›¯aÉàgïíFÄ%î"cêÑ\#ñ©$±và –OéìP%äÏy£ÇóqL…ÂCì2Ú¸îßFµ[:âÌ;QÙ^žÐ?Ëé²g !ÃÇì:`½NY$l‘ƒrFÁ¸:žÆ)‹ÛœÂROdT(cÍš¹`fþ,ѶÐÛ!“oÂÿvÕž½ìÅ ­¦«ïõµ‚ckÙ+IZozÀ—âïë¡o¾Œ|ü*Øá¼µÔSCñe9äÖ…0…Ö™çû)­Å¡qG]àRsçl7Ò²à’Uc‡PTG:,ÃH/<)2Òa))o¬~ÿ BJ%ä@«ÜŒq «xñ 4ºY¢©ùØs 0_ÄéSÓ†ÿQ„Œ’£\àt«0 ¦:îAÅM˜­œæ|ñ›ËÖˆel-»'Sò ð»|=V£ŠHÛŸ;ï:ƒå—sÎ禕àç­þùòwó™ë”3\\óìqOáá>ä+SçO®iŒŽ>èî„U+©Ö¸©ÙOìYÚá K³-}æTý*EóUÓ±e™ªÁlGþpHq¨S»•RîµÙøæ 8öà:ü)jÒr®uDö ½Öx ñ3s×Xµ!q82–n_’¬,œ˜¾¥`Øk;÷îÙ³÷‡(4'ÛöxEjÏTfuûÀ[²!zÛm—=ÀJlùÖ+_&™‚_Žîû1ªŸqäZÏHRw$JpŒœ¹wG±ÜÕÊSrÍ¥¿y.pN2)SÛ×x$YôŒí÷ßünEÌ+£÷ò¦˜ÖãÑJ04cyùÒŠæ)Õx¿6³‡5±¹¢÷<¥$Zã¬ÈU¢)4 Ÿç¿É¡ ¿ý.RÝÖDŠo}ùÂä4e1]ª1¼ÐJêuØQФE3*´ª:‘¡Ã½Ÿ¶R4…zÐÏñJÖ¥õäAX.ÂY 9OŒí,l5vò Jïă ${pl ™Ab,O#BÈI–¤¡~ÉM-Ô†õºb24IPÈóTO†_¬=ú[5œa¬n1‰ÈU!QæwÃR†Où{2)I1w|–¯5ØZ -…_Á°t{§_;f¨| ¦ì€§Ï]‰­CÞ©{÷¨€;!X”ð#]©¦Mí®îÑ(øõXÏÞ韆 2ež3kwÂøÍû÷o™~[̬\•„†©Èœ#6ì;¸}¶‡ÛÊ|3-4ôÔZõ2ÇÛ>Ÿ¥;íþ<ÆÝBÎîßq´­0%/''+¿ü掉¾®®>m»^^•“›©*+//+שN- rwñÛu·®N]^Q’pæØOHŽ9ñóÅ‹Îýt?þx2>+ÕR–}òó¡^à1`É‘¤ŠìœœÜÔ ¤vÜ´4§êô´N„,9';;;#­®þé…3g.D×6¤g EfÌéSHŽŸ8êä©“g/_9qâÔé—’KØ2u>ÿþk7«‰juYY¹&%½“–¯+Œ:wæìÕL]ijR¤¦ãÊ$-Í™6§3¬|害ñúÊa¸C/0˜YN®éá4g~3ÏÒœ-ë»ñx;°÷´Ý•ÈxpT<"dßVµ{F_Ô§^oÊi9|>Q~ûNì!£hcÊðùêvRòÝþ0&ÎHqø®‡ˆ—ŒÇwHÍ_÷rùäbLÚ“ãïƒï!Ž£‰„žäÙC~0æxtjÌ…©.^_k¥ýVC>ƒ§¥(÷àK<>d*„«¡pYø£»FDõøªÊd?dš=–7 ú„ZŽoZór;ÔU_µÈü}wD¹Ì©iÕ+I©zÚÖ¸.þñ‘Ü ‡m²¼:=EKæ³îó*®F¤æ¹Ÿµ 7ƒDµP|ÛÃÀÑÕRòŸÜ5Ba²×ÃÑ6SªÇlR"Ú~{‰YGˆÌ"Hþ“ÌzÞÚþò…•Åñ´Høž«A⪢XZxñò%G¶$ÏÙljÉ+æÃ˜_¼l“»Ã­¨°àtñI3O ª6ÌÏ>rà²áj<¾çãÞ‘‰P•ß=sôäífÄ)Ë6HR5gÂ6 …3+~hàk¸†Uk4b½´žw 9¼³ÕÛ{m%¸ã›alWX„p¥'X‘ð2–úbgÔÅ÷®šÞæRZJ:ÜwQÊw¤… ƒñ±=Óeøæ÷­–²gк ¯BÈ~:ÀŒ”ïÎw=¬¥´c°¢•ÜDÁ"½Œí _ò˜'&öËw>f/,ÝRS}¥/lÆÞ9-†,Z‚Ã9å~£lÛÀ]£À²-ð±Ã>·g¿Wö…/õPHàeĶÒVÙ5ˆÀØDZÅöToø‚ÇcëÖ_Ã’B»ù7a,ŒoÆÉu!«?ÐÀQ†4ðòé뉦âw/±•œjïDi+xƵWûÁšn°Ähl¥´ N†üÓQ«ð]#·Ã/Ä=špY¹kä«7{¸^gmh‘D ¿º³É¦¢Å4=ö>pÒ7ÚDHÙýCû{»y¹lÅù‹…¡‹kìC>Á>¯:Õõ “•¼ÜÎ&8Þ‘”[ò­É"X.ŠC·ŠÄâO.#ÒËÙþÊ |†¯ jûž»!úÄêKJ‹k?ˆÑ²4i¹—ª:.šú€‡¬íš˜ÎRSí$pÙÇW7ÁOÈœêíX6ÿ«;<‡~þ£«›>bVwwÓ⹟ÿX¡‚Š9©ÚEÁ•rù%Á9s>fd,;á½X»9E3ôÉ—Ÿ®¾É²] Kï˜6gΜðO~â,>Ö™þj™`eZµðu „¡*xJÏ]EÁ9Á[_¼l·`*O™6@šª)6š(Ä“hÒøò¾±Äv¢^2ÚÐö²Ýñ®Ûo/_¼xù›ÅÙRmÌñžÒ,TÇOô³=²z¾Œ_èþ¬•TîÁQ2ÆzöŠqÕæ]ð³•Q¶DÄ.ÉÖ'n‹Õ«¥ZÙºu¼kÄ~a A:¥\¢6EÝÊ*'覵r–ë?¹Dí†Mì¸á@–¹¬äÉø]árX–;Ô¢íºÏøñï$d÷{÷ý‘e“I©Óþ·„?ºk„¯ü–‹Ê•sbÒ$X¯ãô 5,«[““E©%©x LGÃ]Uò÷Ý5R8׳×êˆÇÑ‘kû¸ÏȱqrÏ÷Jœ‘ÝŽÿúüÖßÞ!M’ÀÆ7Èœd¼8ÞùÛí翟{8#'½ ®tc^¹9~×HJ™Z]RUwvÑ@üå…'kªKÔeùO¿^ÿewùjíîÔbºTÓül}¦½&oÉl,-Õ”&”©KK36Oî…ÔîaëŸ7kJ5U6ªÜAÊÒÓª³U¶tU)H’“ò žßŽŠºý,¿ ) =§¦•:ySS¨R%£¿&f–¤Ü»uóaFIZ"~?«SÓJÒ õ½”’ÌD¬HOÅ?»KrZšSµ*ç!ÃbÏF¥(Á #†ü^{v*ItÌ“7‚7#ìB“¬$˲Äö×™W/1Šš%éÎj‡Ì×õ`½ž Ê­?Ì[JO¥ÿZ-ÎäùvØ<ù…õÿDÆ8°LO%tEXtdate:create2017-06-06T01:31:14+01:00ú”*%tEXtdate:modify2017-06-06T01:31:14+01:00‹_,–IEND®B`‚puzzles-20170606.272beef/icons/singles-ibase4.png0000644000175000017500000000172013115373744020326 0ustar simonsimon‰PNG  IHDRbbŽÎYÒgAMA† 1è–_bKGDÿ‡Ì¿ oFFs¬äÔtIMEá MÓæ­ vpAgàà]èUgÚIDAThÞÍ™[’Ä EYú]K›J:1€ ˜‡5~õˆp‘@ ñçƒV#@¿µd8 ú½Ü®ª"B}m bñ$"Ö[Ç—#ýkÆÞÒ¹¦‚êŸ+Àvœ“ÄXÿ ö+ö5EÄXÿ0ÂÞøÍçˆDÿ÷óò¨Ž·íwqèëP:õå1›Þ Ùš"¬¾q‰MlkÍF6í‚ÄO¿ÝŠôàö‰÷ˆM=C(}ƒØõÅ9½£–"8Bð—ˆãºñ!Â^÷GÈc¼…8 â:.7" ç$Ý{zMÿ¼ÉÍŠÔçë¤RoqyêšíhÇÒñ„[9ФA“i»1™iýƒ¬ ®!†ú­xñ«·âÛ½ YQG–ÐäïWƒ­`:FÄúê‚pÈ[˜¾>ݲ554¢í"Úf"ÏP¾ì­dòFDQž"q]ú;GŒ^gEž#†9¦ / †™² Ï4Ì÷¹¼„P[ÓÕûýƒÐ…Ïdj#¨ôF·‹g2‡èÒ'ÒþA!ºƒ²í/ÈAÀú1D Ù0±l‹Cµ{5ˆá•‹R³bŸ0þÖöætVfO]"´Êì¢ZR~ŠðR´[õJßÍ àTD9ˆ¹ˆr ¶¿°ý.üþAúçMÝaó×Mº¨! üEº¨ ¼÷£6™ÉÇã@P`¸"/ øû¯ÞŠo÷‚ dEÅ ªÁfċ좼€Hû‹{ýÇÄnîšh´î÷UÔ|RG<‰¨âÙ»¨ ¾îsTñ4Óæzú½¨ šI±Õþ"E$ÿߎÓa8ƒàÁÅþ"C@"ºÛ´L"¤ë­¯½ º…`0eõÛëëjQE\»Dˆ0ž¼‡Àa½ô:a*¢DPâ²™¦Þúë.ÿ‚%ÂXxeÒ(¿‚`ÇÁÎ!¢QDP@ œðo¾z+¾Ý *u/¨Ä™Ïõñoû‹? òM*Q9{%tEXtdate:create2017-06-06T01:31:32+01:00Û÷¦m%tEXtdate:modify2017-06-06T01:31:32+01:00ªªÑIEND®B`‚puzzles-20170606.272beef/icons/singles-ibase.png0000644000175000017500000000335413115373744020247 0ustar simonsimon‰PNG  IHDRbbŽÎYÒgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿ oFFs¬äÔtIMEá MÓæ­ vpAgàà]èUgÊIDAThÞµ™íOEÇèí#GÊC«EcÒhŽxm¯¦…+ÆJ">Ä6Õ&6Ñb MŒ•”Xß(±í ° ‰51€ ¡ðBMYxQ k ЄRÔBN`þgfvvïn~¿ë¦óâr;óûÞgofç“%sγnÄsSêñ)(?G‡Š¶4˜­×ˆVŸ\}l/” ‘K&3šf§J3mkZæNÙˆ’y^²pÐ4õÜÙ•üÊìwº©·-–…P䃒 Û°6ÄßÛè·t{¢ „*ï—|«›ÇS¹­·ô«h„2ï•LÆÅm;}¦>D¨ónÉ‚m]¤…­×²Q ï–´;EJvrÆ!ȳ’iÃZs»¶>ï|1]Uùè÷ æ±mN"†ðòŽSŸžã=ó~¬ö.ïpÒµ BÊ ¼¼ã¤Œ‡QÄ+¿‰’e3"¤|ÂË;NEež÷¬]¿ÔDˆñïÈWU€)_€ðòl/Ìù†Ùb—^5Ÿo–0ÿBÎÇKþ¿¨OÏFnÊK¬j2ø>ƒ:³%3þ¹WÄè_îç“WY  Û- ¯¨1¨uøÛÝ-g.œ¬s/)>óÕú@„ÈÓ›==¯³®wzzÆä¼twvóXzŠßKåÝÝâHœ÷æ˜~¯cúlóžTª!{yUœójŽê/ðóþLùˆk«¦y7Ó*óî|PÏ›ï·éYÔóÈ»%‹¶ÕW¤ä¼Y}…òþ³W7{ãû±}ÞÐ'±ÏneÞ_A\ÕÍ\ôx®vXúuŠ](óÒ:¨_Z}aéÕÞ-^Æ:ªTž¯æ›–Þ>ì,ç—áv¶š;ô-¡Ê‡kÒ©&]³Ò&[“Zš~`:èůiKæåÅÿO½Í»S$UÛÒwû©ÿEós°_$Gø~¼XCùvD”öÜ8ŒPøjF¨ü3#”~€‡j?€ÇµÀã0BøÛN³IawðÝ÷ÈDôÑÐûM »ª›?[+@?`mŒHß [C|ÞÚ³C„+¶# „·‚€üAB¹ß3YÅÑ"ôJß"5G$„ç?ˆÑ¯ÖÙçcTþEH«¹BFÞ•®@þ?ÁìpJ i'êË5¤›F®@þ#ä÷r8v B?È‘½kQ„ë?D Û§ÑîÆÂ®r›F®@þ!¬w2Â(!¸üc‘34†pýò™0¿ŸºŸiÁýà¡üH f¼s¡öé÷ÆÓ„4= ~ÅC¸~ùC¸5PIH×Zˆà~°Þåµ}„¤ºº‚× yll×±v·=ˆ"ä»;v.bwwqÉoƒp/Šý áùäàา¡üG Ô~#j?@Œ#J?ÀŒ#*?@# ?À#¥ý;^ú~¼Ôâ?ñû „_`E+_` ü‡Häh¯~z¿À ú‘Ô/`Db¿€‰ýD¿hä~í BøEö ®@âµN·Ý òX¿€¡_0ÄŸÑ#ô ®âÍxù\8C!ýB„~ÁÏEÍ/âp~!B¿h¬;ñÉiö ä¹Í é"ô Ç}Ù´ÑÊz仌ó ð_DßoÐïY/·h¤_Àçb¶Áo ¤_ ¯¨‘kü@‹+ åBøÅ’~ãÓÜÓ½Ÿ_÷H¿€âî¾Âûçƒ<Ö/ „ð‹¿‡ÞÎÔUÕ´}ù/ÏcýD$÷ ‘Ü/`Db¿€‰ýHêDB¿@!’ù‘Ä/¿Ÿ€ÿÏúýÅÔÿþ…‚àB·±%tEXtdate:create2017-06-06T01:31:14+01:00ú”*%tEXtdate:modify2017-06-06T01:31:14+01:00‹_,–IEND®B`‚puzzles-20170606.272beef/icons/singles-base.png0000644000175000017500000001660213115373722020072 0ustar simonsimon‰PNG  IHDRàà•Oý¶bKGDÿÿÿ ½§“7IDATxœí{PTçùÇß½Kp和؊ èT‚,ÑšA‰1&ê Á4£)eê4$­ ÓªÓ`• ‘Lâ…§GÅÔ@½e TDQ2ˆša ÒrQ@–…uoô3Ùßùíåì9ï9ïž÷,ïç¯ÃÙ³_Þ}|÷\?ÈîÝ»\‘‹]ÀiPÖ%` iPÖ%` iPÖ%` iPÖ%` iPÖ%` iPÖ%` iPÖ(9m}ÿþ}›Í†¨Â|@.—¿ôÒK¶ç”n³Ùär„“®\.7 èò êúI>s>× ŽÛ °Ùl‰‰‰ ŒŒŒ|ýõ×—.]úþûïõz½Édò÷÷W«ÕK—.ݸqcZZÚ /¼àî½÷îÝ ÊÊÊâZK.\¸€º~s>|#Ÿœ”7n9rd``àçç'ÿ…Ba2™z{{»»»ËÊÊ–,YRTT”šš*à?-R¯ß'¦A8pÿþ}€L&Ójµ›7oŽŒŒ œœëëëûꫯ:;; :´xñbA à‰Ôë÷ahÐöööÂÂB«Õ*—ËóóóùË_ªT*ú‘‘‘‘‘‘ [¶l1ÕÕÕ§NêííÍÌ̬¨¨X½z5ÿø õú}¾{ÄçÏŸß»w¯ÍfÓjµ×®]Û³gçë€J¥ÊÏÏ¿zõjjjêÜÜÜÞ½{/\¸À³>H½~Ÿ‡Wƒ¶··—••Éd²ÜÜÜãdz|cHHÈñãÇß}÷]¹\~øðáööv>e@#õúçð :00PXX(—Ëóòò>øà™LÆéí2™¬°°ðÝwßU(………?üðt%pH½þy|ƒîß¿ßjµ¦¤¤üö·¿…),,LNN¶Z­û÷ï‡CêõÏ ’:;;ïß¿/—Ëÿò—¿Ðç«ÕZYYÙÓÓ£Óéž>}:33•œœœ““ë#“ÉÊÊÊ6lØÐÛÛ{ãÆ µZ ÿ«Q? ¥¥¥­­­··÷ÁƒF£‘ZYSSó³ŸýÌ9¢þôôôÿüç?._úðÃ÷ìÙÃý·qAÿ™3g:::†‡‡çææBCC—.]ºvíÚ¼¼#ÐÑÑ¡P(ìkÌfóo¼1<< xôè‘Ë@•JµjÕª›7oÞºukãÆ%q‚¡~ÀÉ“'©õ—/_fÙ põ/Z´ˆuÕ¬0 GŽ¡–óóóùì^‹’ï ÌWü•+Wüüü6oÞìòU{wÚl¶‰‰‰K—.Sk^|ñEw™›7oö÷÷¿qãD=\a®Ÿù<¨; êï½÷’’’’““·lÙRVV&Èôsùòe½^P©TáááYYYZ­V«Õæææ655áŸï Ì úý÷ßËåò¸¸8wô÷÷¿õÖ[+5MQQ‘»·ÄÅÅÉårwGÂâ±~ ê¢t:N§«¯¯?qâÄÊ•+ù”ÑÕÕE-ÆC‡Ñ×wuuݾ}ûÀ8ç;3ƒNMM™ÍæÈÈHöo‰‹‹«ªªZ±b…» "##-Ëôô4D=\¨ß#œê [¿~}^^^FFÆóÏ?o¯ê£>zöìŸ2èÓ°B¡ÈËË+**²qÕÖÖ~ýõ×8ç;3ƒZ,«Õê|ük'""¢´´Ôb±Œ]¹råáÇ}}}ÙÙÙ‡NOOwùFc2™¼s7´Çú!`_EEŲeËì;BF£q÷îÝwïÞŒŒŒ´µµ¥¥¥A—a6›í˹¹¹ûöílÚ´iÆ ÔK 8ç;3ƒ*•Ê€€€ÉÉIw¨ÕêmÛ¶effÔÕÕ¥¤¤ŒFãþýû§¦¦\¾e||Üßß_©òö?wx¬öõ'&&Ò"U*ýÜ¡N§ãSýjmRRµñ“Ÿü„ZÄ9ߘ V*•cccl6V(ö['§§§{{{]n666¦T*,XQW8ÕÏ¡êçzÅÕúa(=Ê~Ÿ<Ü! ×òiÐ¥K—Úl6—ÿ×[ZZþûßÿÒ×ÌÎÎ^»vÍþ£»@§ÓÙl6ÁO»¸„¡~hXÖßÔÔTWWG¿`4OŸ>mÿ‘áD^{í5ûò·ß~K-ŒÛ'6žwË£Îwæ+uãÆÝÝÝo¿ý¶ÃK{÷îMLLLHHP«ÕOž}Z©TFEE]¼xÑd2”JåŽ;pÎw¦AÓÒÒÊÊÊ:;;F£ó”>77×ÓÓÓÓÓã°^­VöÙg.¿ŒFcWW—L&{ùå—!êá sý---ÍÍÍ+¿úê+û²sƒr­_¯×;íFEE}ñÅü÷ÂKJJÞÿý˜L¦“'OÚ×+•Ê’’’˜˜Ìó€Ž^xaÉ’%ƒƒƒÕÕÕùùùô—²³³5Mww÷èè(uóꫯfffj4—ûÛßärytt´®s2×ûú·oß®ÑhÚÚÚúúú?~üôéÓ   ØØØ´´´wÞyç¹çžã_LXXXMM͹sçš››ŒFcdd¤V«ÝµkÏýïä; ãô ý©¿ÎÎÎ_ÿú×r¹üÊ•+¡¡¡|*˜˜˜ Î=;vŒ:È@úT'@_¿ÔŸºÄ*òn¦”””„„«ÕZTT477°Ùlü±Íf[¾|¹7Ÿ“”zýóø–KKK•JåíÛ·?ÿüsè£GÞ¹sÇÏϯ¤¤:©×?O€oÐÅ‹WTTX­Ö3gÎ=z”ëe@#õúç|;ÎÊÊúòË/årygggzzzee%óèF£ñäÉ“¯¿þzgg§\.?~üxff&Ïø õú}®}¯^½úâÅ‹¸wïÞ©S§*++W­Zµy󿏏¸ÈÈHF311a7sܺu‹2H-_¾¼´´ô§?ý)ÿæyý¾07g,^¼¸ººúæÍ›‡èìì¼sçŽB¡°X,Ïž= P*•V«Õb±Èd²èè袢"êLzý> çó  zããã·nÝú׿þ544d0Ìf³ŸŸß‚ -ZôÊ+¯¬ZµÊÝéz€\.×ëõAAA~. µZ´~º›} ߣ]Ðá”>ð|æ|® ŠxºÒ@üRÏç„”ü Äß9‘†”ø;ç-ðƒç|w?(ñwÎs°öƒ'_?(ñwÎ~Pâï$Áý xðàÉ“'“““*•*::ú¿øEnn.×ê|€Ø?ÊÕÿÊý t®_¿nïN\ú5Åòw¶´´üñlhhxøðáãÇ)›Í½{÷Nœ8±uëVúsžp ÎG „ÿ•'ÂûA)&''<È2ÐÁ¯)º¿S¥R¥¤¤,Y²drròêÕ«³³³€±±±’’’S§N±ü¥Ḑ@ä…ð¿òA`?¨âââÇ/[¶ìæÍ›Ì~Mý¡¡¡ûöíËÈȰï dffR=ÔÑÑa±Xø<Œ:Ÿ ÿ(œÿ•ÂûAMMMÿüç?°ÛÛ˜¡û5Eôw¾öÚk»ví¢ïª.Y²dùòåöù ÿ(„ÿ˜ššR(îüšœššzþùç9¹L)¿&uÜÜ=Ÿ=6›íÏþ3¥¦ñ÷÷ÿýï/`IèòÃÂÂ’’’-Zd0¾ùæ*Ÿò677ò¯Ð‰‹‹+//vN¡ØZWW÷Í7ߊ‹‹94¡û5ÅõwÚÑëõŸ|ò õ àïïôèQ/ˆò‘úG) ü¯Ðé5 Ô©œ¬¬¬5kÖpʤû5ÅõwRô÷÷çääPÝö׿þ•.vãº|¤þQ ÿ+4BúAggggff.\Hü‘ÆÆFêÕÉÉIjËLº_StgkkkNNN? >>þüùóvY«  Îg€§Ô–þWhöƒBC÷kŠèïœ:uê7¿ù õ·,ÒÓÓÏž=%`%HóQûG¡ý¯Ðé pÞééé¡~%???†o1º_SDgCCÃÑ£G©e¥Ri0>øàúúÓŸøôê|ÔþQhÿ+4BúAÕjuEE…ÃÆŸ|ò õ-äü*…ƒ_SD§Á`°/[,çûôè@€:Ÿ©ÂÿÊý p8ø5EôwJÔþQ8ÿ+pôƒ'É·ƒ©”ø; øúA‰¿“pöƒ'`î%þNî~PâïœçHÀJüóiøA‰¿sÞ‚xÒÿ§¤ó‘ûA ƒ¸‚Y>øÀ,õ|ä~Р  ¤ Ntÿ(ˆß”M>'„ôƒ¢Fê~P©×/ ÒhP©ûA¥^¿ˆH A¥î•zýâÂ÷D=j¤î•zý¢ƒuƒJÝ*õúqß•ºTêõc¾ *u?¨ÔëÇL’ü œü—bùAÅò›:àÑÏÊÔùÛ””%¢øAÅò›Òaég…u>Ž3(ÿ(àâ¿ô²Tt¿)àèg…u¾”pñ_zÙ*¢ßÔ'?+¨óíàøïÑ?JÁÉéM?¨ˆ~S ?+'PçÓÁ±AYúA‡††L&“ÑhÔétÕÕÕÛ¶m£n.ñ¦T\¿©ƒŸUÀ¼“ïŽ_ñý þKoúAÅõ›ÂùYÙƒ:ߔ٠ç¿ô¦TD¿)´Ÿ•%¨óÁñ+žÙ ç¿ô¦T,¿)?+Pç»Ç488Ød2A|Kº»¢HùAY ´¶¶~üñÇ”!1>>þË/¿ädœãS¿;ØÔO÷³:ßbBùYÔ]ÃÞÉw Ž3(ƒÚéM?¨¸~SÇ”Á í¿ô¦T,¿)?+Pç»ÇeöƒîþK/ûAÅò›BûYY‚:ß%8~ÅS~P¹\^]]íðÒöíÛKKKß|óÍ_|1,,L¡P'%%ýîw¿khhˆ‰‰qHùAcbb¼ãe¨/×0~P¤OuŸðƒJ½~|òqœAôý R¯0mP }?¨ÔëÇ|Tê~P©× ø6(¾TêõãÖ ¤ï•zý¢ƒãyP¤î•zýâ"Ò÷ƒJ½~‘ž~Qê~P©×Ï3¹Ô£À–>ðèõzâOeÈGîÝ߉y>ñ§2q'äŸBtùª³ÿÒl6›L&jËf³™ÍfƒÿÒ7ò½p)iýX]êæ µÿRêù¨‘zý 0ƒzô_Ò±û/­V«R©tð_úF¾—gPÔã# "Ü,‚Ú)õ|ÔH½~ðjPÔþK©ç£Fêõ³¾AQû/¥ž©×ÏøEí¿”z>j¤^?K âÝù/¹ú5Ýù/Ýå[­ÖÊÊÊžžN÷ôéÓ™™™ÀÀÀ¨¨¨ää䜜œØØXžùxô_òôwB#¢”“Ÿ•?3¨;ÿ%„_Ó¥ÿÒ]¾Åb9vìØõë×=z¤×ë­Vëôôôwß}wîܹŒŒ ʳÀ'ŸKÿ%´¿“8øG½LƒRþK›ÍæÎ©R©Ö®]›››ûöÛoR+)¿¦ËíwîÜi³Ù(ÿ¥ÇüÀÀ@­V»mÛ¶;wnß¾Ý~&Ïl6»{ªS>'ÿ¥C>j<Ö¿páÂõë×oذe \ý©©©ëþ?(ΪÂ|Å3ø/áüšþK†ü€€€ŽŽºúÆl6¿ñÆÃÃÀG¹,˜}¾NþK'pð.~V>ÀÌ  þKh¿&ÝÉì×´w§Íf›˜˜¸téÒøø8µÆV„S>€ò_ròwòDtÿ('?+403('ÿ%K¿&Ýé1¿¿¿ÿ­·ÞrX©ÑhŠŠŠÜ½…}¾ƒÿÒå~-s>jÄõÚ¢t:N§«¯¯?qâÄÊ•+¬ À5({ÿ%{¿&Ý á׌‹‹+//gøÌØçÃù/áü£pˆëP~Vh`”¥ÿ’“_“î¿ô˜QZZj±XÆÆÆ®\¹òðáþ¾¾ìììÇ;˃8åCû/!ü£Ðˆè°~Vh`öAÙø/¹ú5éþKùjµzÛ¶m™™™uuuÔÓF£qÿþýSSSÐù|ü—\ý£|Ë?Jçg…¦Aƒƒƒ•J娨˜» Z[[srrúûûñññçÏŸOJJbΤü—”ÚÅc>…Ba¿µqzzº··:Ÿî¿LüÊŒ~ô_º»‡žNãáêçzÅÕ#0 Êì¿„ókÒý— ù---”ìÏÎìììµk×ì?º –ùÐxÓß)býÐ~Vh`¾’ü—Ð~Mºÿ’!¿±±qïÞ½‰‰‰ jµúÉ“'­­­öÓLÆå=–ù|ü—,ý£‚ –ðð³BÓ  þK8¿¦ƒÿ’Ù¯977×ÓÓÓÓÓã°^­VöÙg.ϲ̇ö_²÷ ‚XþQ;\ý¬|€ùŠGí¿dÈÏÎÎÞ±cGbbbdd¤ŸŸŸŸŸ_DDDJJJaaass³V«å™/Hý¨±~8?+ ù@í¿”t>ñ§ºÃ{| ö_J=5R¯Ÿ=ð7,£ö_J=5R¯Ÿ%ð ŠÚ)õ|ÔH½~–ðzhµÿRêù¨‘zýlàûØ1jÿ¥ÔóQ#õú="Œúæ‡~ ü—2™ÌjµBû/}#ßûêÔã#ùBº™ìþ˹¹9¥RéÎãÎéùb¹™P¼Ñ õ‹¨ý—˜ç‹®_ÄÜ?Jü òEo >ø€?•øA‰¿ ý B^ÚwöSR( “ÉÔÛÛÛÝÝ]VVÆà§75R¯_ˆÔH½~™~Pâït†ùóÝŠ©×/:óÚŠ©×ó׊©× ó׊©× ûA@~JþÎþþþ3gÎttt ÏÍÍ…††.]ºtíÚµôg´òQƒÚoÊ~ShXŽ?öƒü”ÌþÎêêê­[·ÖÖÖö÷÷ÏÎÎÆáááöööªª*–ù¨Aí7eK¿)œÆŸ'03(姤öý]n°pá„„™LÆRÿ·sçÎÊÊJÊOΜ___oÿ¨âãã׬Y>===44äN°æÏî·„‡¹þÀÀÀ+VDEE…„„ÌÌÌtttPû—”ßÔå3Áõsò›rbüù °á§dÈ7 GŽ¡–óóóYîÞáãïÄoʦN~SöÀ?öƒ!ü” ù—/_¦œ%*•*<<<++K«ÕjµÚÜÜܦ¦&–ù¨Aí7õ„ß”%Ðã r?(KXú;»ºº¨£ÑxèÐ!úú®®®Û·o»s&båïäé7eÎoÊèñ‡fšš2›Í(ü”ÓÓÓÌùô½…B‘——WTTdŸxjkkÎù¨Ÿ¸¸¸ªª*=%ûúáü¦,húA9ÁÒßIý½^ŠÜÜÜ}ûö6mÚ´aÃꥆ†—~J¬ü<ý¦ @ûMY=þРòƒr…¥”~µÐ®tŒˆˆ°?5;88è15¨ý¦îàã7e ôøCƒÄ K?(ý0‚~œº¸?DÃÖß á7u¿)K Çáý p°ôwÒˆß~û-µ0>>nÿëîÀÄß)ˆßTD Çý @?%C~bbâºuë¨#ÓÓ§O+•ʨ¨¨‹/šL&€R©Ü±c‡Ëš1ñw â7u¿)K Çý @?%s~IIÉûï¿ÿàÁ“ÉtòäÉÿûM”Ê’’—@¬üüý¦î€ö›rbüù 1?( ,,¬¦¦fß¾}Ë—/_°`R©\¸páÖ­[ëêê\ÎèÎù¨Aí7ˆñçÃ|ôƒ§;|ç‘âïdFêõãÃüõƒ¢FêõcÂüõƒ¢Fêõc¼öƒ¢FêõãÀ|÷ƒ¢Fêõ‹Î|ôƒ§;0Ìææ‰Å‹WWWÛý”wîÜqç§ŒŽŽvç§+5R¯_DæTtý"æþNÔù’÷ƒŠÞ@|ðB/y?¨Ïû;‰”Ròƒ¢†øM1D~PÔ¿)¶àèõ1'ñƒòÉÇÝŠâ7Ŭý ¨!~SüÁ׊â7•øúAQCü¦’@x?hzzº;Cˇ~¸gÏú_õwzô›RxôwB:''ÿ+„÷ƒrÅ'ýlƇ¥¿b|ú;¹ú_y‚ÄJ‘ššêpÄêù;ÙŒ''§ññ‚¿“«ÿ•ÂûAí³ ø˜¿“Íøpòw²/ø;!ü¯|Þjç½÷ÞKJJJNNÞ²eKYYó__òwz'Ëññ‚¿Sp¹ 3ý CCCÔ‚N§Óétõõõ'NœX¹r¥Ë}ÉßÉœçïd9>Þ÷w¢‰4,,lýúõyyyöbjjê£>zöì™Ë·ø’¿“9ÎßÉr|¼ïïDð~ÐŠŠŠeË–Ù¿(FãîÝ»ïÞ½ ikkóy'C>´¿“åøxß߉áý ‰‰‰ôƒ •JE?÷æÎ‰çKþNwù|ü,ÇÇûþNÔxÛê/ù;Ýåóñw²ïû;Q#°´©©©®®Ž~ ×h4ž>}Úþ£»a_òw¢ö§2à}'jöƒŽŒŒ|úé§ååå)))ÑÑÑz½¾µµutt”z5&&†~w#_òwºËçãïd9>^ðwÂù_¡Þ ÐëõÎG‹QQQ_|ñ…˽(ówºË‡öwrÔþNÿ+`”ò_VWWçççÓ_Ú¾}»F£ikkëëë{üøñÓ§Oƒ‚‚bccÓÒÒÞyççž{Îe å¿ŒŽŽö¦¿ÓeýÙÙÙ¦»»{tt”:Ê ‰‰‰yõÕW333Ý=ìP?C>œÆ‡òwž;w®¹¹y``Àh4FFFjµÚ]»v1\hÀý >àï$~P¡ò1õƒ¢†øM¥¾~PÔ¿©$À׊â7•XûAQCü¦øƒ»5ÄoŠ98úA}ÏßIü ÐùÒðƒ¢†øM±;?¨èúEÌý¦óù€¡~‘[ƒÞ¿ß;·l|¹\þÒK/±ßžÛW<§h?|â ¤%` iPÖ%` iPÖ%` iPÖ%` iPÖ%` iPÖ%` iPÖ%`ÍÿhI•ÂÔIEND®B`‚puzzles-20170606.272beef/icons/singles-48d8.png0000644000175000017500000000332413115373744017650 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá MÓæ­ÜIDATHÇ­–iPgÆ—£e¦ÖN[;­N a ¥…"Ô"BÑŠ TQE°`i=*Å¢ƒ3âLÇá§¢†„$Pr@*Ê•k³ÙÍf“l’ÝDmë‡~ï&²8Ã;}>l²›ýÍÿzÞ¼/Ðóšþ zx\.Ïý…Ï¥iÅ/>€Ïá°{e …„Ïærăr¯e|—Í—(²^6‡» ð¥J¥šW–{N®oþö`þ¢ ÷Ž«äçr³Ëxê±!p”¸©”y¸æÂÞ¸FÒT‹òÖöad#cïùš#ŒRÌ$ò¦ô<ÝŸ/Šø g9ðfÀ¢w…Îr–bᯤ&/󖶺4ï…†sKn´c;ÎÓ"¬îˆEqùˆ<Ûwt”³TC//a–lö?‹áìÔjzJ²Ô{.%Ó?Ö#ZF»;' àÉÊŽ f =0Û¡3d~ø/6m‡ hW(jБß“ó<W‘]ëÔÚ+Ö¼ÕmÕÚ%Q/zÊ=$¨'²B`tÖf+¸K@îER‡¸Èˆ3ˆ$Ó€àrí ôrï–TGþœ»ð$çóèñÌ< ÓiÒ h)­kýBcœ.ÛðvÁBì©”ò–'";‹ÔiÀù†ì +º”ÓðlâHaɾçP,Gàm«ª1ÞølÎiCæ¥[ý¬•Ë·ÈæÄ¼ ‰¯áx7:WÉdƒ³¶)üÖ\-Â;ÂùÎðfÕu3ÏËÖà ÍÀq;Š ““9ðÌÙu›‚C£ââ¢BC‚#…Óþ猬ìO?iF&½Öèáÿ1(Ñ+Š"cš™ö Ï*KK•³#÷ECÒ± öÕ+7ÇÉ…=Þ”ÆÌöæþªŠÌÄߟN¡D ëë’£™ñ-NÌdD`³ƒÀ5Š—Í7jߟ:lq-XîDÔ#d9³Ïþü©UÌ8 ÀÁ(¬ƒ ´ °ÕgÓ˜aF®rME·i[˜¨ý‰üÞ†²RïgO,°ÁôĬÇ&½aÐivÜL|(žë‹2¬Û@¬­w?^t£EàI«‘²d3pÃêÓNî¶@ÓÃÑI6=ˆ§_µ˜¤LT¡e€«ÈùÅaéø¬èvilÅ1U¤vÄ&Zõ «ä” „ŒOu2Ì´PC¢‘;+€|5„y€ç¬”¿ : ·J7ís¡¯¦¤/dm6)M`ÚÉ\3`ÜJÔ%ä>•™|waV¦Åꣲ*+³¢ê-“­fYj¯ùøÂÖ_¯üV»;1¹°éú¥&±¬O5v":æÄ¸ª_"’I}ê]2Wžï^AA~Ôêܨ„ vÚŽ¢¢i÷\j•Ãî‹/%®¼xÃß³òý€°ûäåˆ6ˆ  Öðz3e>Qeh^ZŠà‘?<};b†TOMé\ÓÑmãî.™Ô°uu`ãÃä®ì÷Â?(Fl¦Ö[zÂ7¬oÀô«×3LÖ»@~µ­)×pÐ,¨LZa¾@܉ÂÜ–à_„震+<æ#¢èª)1Žw°íŸ"¿ˆóhe>Ë#Ù¸zJÑu9Vìzù°P-dÛYg×a²÷Þ¿|mY JP·“"SÄ(6º­Ïâ›¶Æiß¶6‚˜«còkjòcªqµÔý7³(úêjmoóêf¯H4Úu2'§¬kT$ŠiòmìôÇ¢>Ÿ#¤vy™ÃçS7>ÑN¯>æ»O üÿópòúBpìÃ1%tEXtdate:create2017-06-06T01:31:32+01:00Û÷¦m%tEXtdate:modify2017-06-06T01:31:32+01:00ªªÑIEND®B`‚puzzles-20170606.272beef/icons/singles-48d4.png0000644000175000017500000000145613115373744017650 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA† 1è–_bKGDÿ‡Ì¿tIMEá MÓæ­bIDATHÇmV[‚Ã@òèÍ›¹# Iw’6óÀ¢mTf¥>jßúëµÐ›öƒ/@œ‡Ç|{^ã1P ‹6pÇbF£ÿÚ^›Ê„íå`ùôê8×s -îh®]´÷s»NŸálÿç™÷É#d[M~oÚÎId+ Hœ<4ì_¦‘_IH99øðp®ÔÒŸ´)ŠÈù塼ãh@óTm‰l!±D‚œÕIŠ–â‹% V¸=ºn"ú.ÜS·>Vñ`a!¾´¤Ê‘£¾L ÂdiÉ+ó(2;+È~Ÿò]ë…ï½>s üœeMCä4D(¸ ŸpÏô+yyhÁñâ¾löÁtß@ébAd”!öð—1»­rue>ÄÓ×lQõ*؇¬=ƒ#Ñ#¡m—VS…ã^µJ–3ÊiOù,øèªi_–:qâk e΂µîH4eÂ:1‚«¦p’÷ŽUL£e¡}C4Ò&=x)GÒ€™^&œ£(H [{Kƒ´6Ùåáʘ½EW+)uXÅsh¹yÔºp±ÅžÅ—ÛH\ÏÄzÌ—0W€£N ð g•ÄÂ51㚈œï{)_Шߖ„sáo¶ž_œ ÖVÖ# Ó¨.@Ô´LDÝ ŸšhN:kL·&»œ¾Ð/ZíPÉQÕ ñð5`ò¹l²›ýÍÿzÞ¼/Ðóšþ zx\.Ïý…Ï¥iÅ/>€Ïá°{e …„Ïærăr¯e|—Í—(²^6‡» ð¥J¥šW–{N®oþö`þ¢ ÷Ž«äçr³Ëxê±!p”¸©”y¸æÂÞ¸FÒT‹òÖöad#cïùš#ŒRÌ$ò¦ô<ÝŸ/Šø g9ðfÀ¢w…Îr–bᯤ&/󖶺4ï…†sKn´c;ÎÓ"¬îˆEqùˆ<Ûwt”³TC//a–lö?‹áìÔjzJ²Ô{.%Ó?Ö#ZF»;' àÉÊŽ f =0Û¡3d~ø/6m‡ hW(jБß“ó<W‘]ëÔÚ+Ö¼ÕmÕÚ%Q/zÊ=$¨'²B`tÖf+¸K@îER‡¸Èˆ3ˆ$Ó€àrí ôrï–TGþœ»ð$çóèñÌ< ÓiÒ h)­kýBcœ.ÛðvÁBì©”ò–'";‹ÔiÀù†ì +º”ÓðlâHaɾçP,Gàm«ª1ÞølÎiCæ¥[ý¬•Ë·ÈæÄ¼ ‰¯áx7:WÉdƒ³¶)üÖ\-Â;ÂùÎðfÕu3ÏËÖà ÍÀq;Š ““9ðÌÙu›‚C£ââ¢BC‚#…Óþ猬ìO?iF&½Öèáÿ1(Ñ+Š"cš™ö Ï*KK•³#÷ECÒ± öÕ+7ÇÉ…=Þ”ÆÌöæþªŠÌÄߟN¡D ëë’£™ñ-NÌdD`³ƒÀ5Š—Í7jߟ:lq-XîDÔ#d9³Ïþü©UÌ8 ÀÁ(¬ƒ ´ °ÕgÓ˜aF®rME·i[˜¨ý‰üÞ†²RïgO,°ÁôĬÇ&½aÐivÜL|(žë‹2¬Û@¬­w?^t£EàI«‘²d3pÃêÓNî¶@ÓÃÑI6=ˆ§_µ˜¤LT¡e€«ÈùÅaéø¬èvilÅ1U¤vÄ&Zõ «ä” „ŒOu2Ì´PC¢‘;+€|5„y€ç¬”¿ : ·J7ís¡¯¦¤/dm6)M`ÚÉ\3`ÜJÔ%ä>•™|waV¦Åꣲ*+³¢ê-“­fYj¯ùøÂÖ_¯üV»;1¹°éú¥&±¬O5v":æÄ¸ª_"’I}ê]2Wžï^AA~Ôêܨ„ vÚŽ¢¢i÷\j•Ãî‹/%®¼xÃß³òý€°ûäåˆ6ˆ  Öðz3e>Qeh^ZŠà‘?<};b†TOMé\ÓÑmãî.™Ô°uu`ãÃä®ì÷Â?(Fl¦Ö[zÂ7¬oÀô«×3LÖ»@~µ­)×pÐ,¨LZa¾@܉ÂÜ–à_„震+<æ#¢èª)1Žw°íŸ"¿ˆóhe>Ë#Ù¸zJÑu9Vìzù°P-dÛYg×a²÷Þ¿|mY JP·“"SÄ(6º­Ïâ›¶Æiß¶6‚˜«còkjòcªqµÔý7³(úêjmoóêf¯H4Úu2'§¬kT$ŠiòmìôÇ¢>Ÿ#¤vy™ÃçS7>ÑN¯>æ»O üÿópòúBpìÃ1%tEXtdate:create2017-06-06T01:31:32+01:00Û÷¦m%tEXtdate:modify2017-06-06T01:31:32+01:00ªªÑIEND®B`‚puzzles-20170606.272beef/icons/singles-32d8.png0000644000175000017500000000221313115373744017635 0ustar simonsimon‰PNG  IHDR V%(gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá MÓæ­“IDAT8Ë]T[PW>u¼ôÁg:c_|è í´Ž}iglGg:}¨ÚÔBÉÆQm¢‚u(BE X¤^T*ÁnöŒ6 $ 1è¦Z Iö’ËB‚I‹Ñ¢¾÷l¶©m¿9³³gÎ7ÿ·ßÿïwI’E`QxªPÞq ')xH’p8Ü ãv NS€Çé@‡f„@ …@Üö:HW`ºWoB Lúï§‚×ëjNy8AÊáŒ4j1$Î €Ð€Ö|³qj¯ãP Æ«"ýóSë‘N°²b%è¹pLü:¥%iî.Ëós»7 Ïšö€µB#’ðmÝ&<ê¯ÅƘÒÃÆ±Eb[©rYÚÖÔÂ7Sb°’&‚]wmì~Œý‹ Ç»·ðR°ÒI(ÇŸÖíØ9ò¤iï ‰äø;›ò×j~ä´©/Íþn­ï…¥ çÛc‹òüâE)6'gª>s’'>–ÚF³vÝ 8mªîlÛ3|Ú$ W`Ö²¹Ì 8lø¹ºFô:ÆÞï?qôôXPm77ô^m°þ\ÇÁËVóÑØt˜Oþ–[$…ræ¯2™Hºý0ßüi|6úÈZí<{/‰z!p]®ËÎï[Ïå·"9ò]bédK*iÛñÚyYT8sèÚc[Å–iì+©ùÆ™¹Û™°ô^MVPc¼)o­|ébÎùj_"ûÅ®\ÔS›ŠDZIP%†Ûšs—̾{ö¥áxÝüò™ån³,ÞmI$HŒÝOÿ™ /ÓýtЖ¾ÇIÓ{Ý¢ø08qW,T€.~ù¤s|²K ÎT5Oq½»Ý\XŒÎ%bBL±IRö›nûvm€ð?<õÖë5SœËÇú¼^Ÿor6 c°bÍêÕkK€-{i9s¤I`gù0…EբΨ`}ú›k«çÂÂKñ‰"NúBõ⥲è?ê;Éþò·Hþ·X£ÿúùÉõï{242/²ÑòýÅF ë*¬™ÉPùü¨!JŸý0¤Ú|AXeþüIÛ¾²®ek½,÷€òÎøß&°JùÛK¡RßRX‹IÒ×ÍQIúŸ ûŒîJhÖQ9xŸ&2²”`•YÜ:¯&1ع‘CÚŠªA—×瘘ð²n\Éæ­bfi”`†èÑ¡ÿ‰9®¦»¸…qÇ ¸(x!¨€ñÿ ï9Y5ÂÀŠ%tEXtdate:create2017-06-06T01:31:32+01:00Û÷¦m%tEXtdate:modify2017-06-06T01:31:32+01:00ªªÑIEND®B`‚puzzles-20170606.272beef/icons/singles-32d4.png0000644000175000017500000000076713115373744017645 0ustar simonsimon‰PNG  IHDR V%(gAMA† 1è–_bKGDÿ‡Ì¿tIMEá MÓæ­+IDAT8Ëm“ ’!C9:GãfY’€ÚSëXí<™¨Ìê–ýóç¬<GµCóÊ" >HÄi๵£<‚jÛ, RÔ¥á1àž·Ú¦\ñóHz«$}™ñ\…5¹`DŠë±[Ð…(—ç\—¨2Y #xÓT`ÎϠ„”KyYo ¾òô1ýœgu¼ôÁg:c_|è í´Ž}iglGg:}¨ÚÔBÉÆQm¢‚u(BE X¤^T*ÁnöŒ6 $ 1è¦Z Iö’ËB‚I‹Ñ¢¾÷l¶©m¿9³³gÎ7ÿ·ßÿïwI’E`QxªPÞq ')xH’p8Ü ãv NS€Çé@‡f„@ …@Üö:HW`ºWoB Lúï§‚×ëjNy8AÊáŒ4j1$Î €Ð€Ö|³qj¯ãP Æ«"ýóSë‘N°²b%è¹pLü:¥%iî.Ëós»7 Ïšö€µB#’ðmÝ&<ê¯ÅƘÒÃÆ±Eb[©rYÚÖÔÂ7Sb°’&‚]wmì~Œý‹ Ç»·ðR°ÒI(ÇŸÖíØ9ò¤iï ‰äø;›ò×j~ä´©/Íþn­ï…¥ çÛc‹òüâE)6'gª>s’'>–ÚF³vÝ 8mªîlÛ3|Ú$ W`Ö²¹Ì 8lø¹ºFô:ÆÞï?qôôXPm77ô^m°þ\ÇÁËVóÑØt˜Oþ–[$…ræ¯2™Hºý0ßüi|6úÈZí<{/‰z!p]®ËÎï[Ïå·"9ò]bédK*iÛñÚyYT8sèÚc[Å–iì+©ùÆ™¹Û™°ô^MVPc¼)o­|ébÎùj_"ûÅ®\ÔS›ŠDZIP%†Ûšs—̾{ö¥áxÝüò™ån³,ÞmI$HŒÝOÿ™ /ÓýtЖ¾ÇIÓ{Ý¢ø08qW,T€.~ù¤s|²K ÎT5Oq½»Ý\XŒÎ%bBL±IRö›nûvm€ð?<õÖë5SœËÇú¼^Ÿor6 c°bÍêÕkK€-{i9s¤I`gù0…EբΨ`}ú›k«çÂÂKñ‰"NúBõ⥲è?ê;Éþò·Hþ·X£ÿúùÉõï{242/²ÑòýÅF ë*¬™ÉPùü¨!JŸý0¤Ú|AXeþüIÛ¾²®ek½,÷€òÎøß&°JùÛK¡RßRX‹IÒ×ÍQIúŸ ûŒîJhÖQ9xŸ&2²”`•YÜ:¯&1ع‘CÚŠªA—×瘘ð²n\Éæ­bfi”`†èÑ¡ÿ‰9®¦»¸…qÇ ¸(x!¨€ñÿ ï9Y5ÂÀŠ%tEXtdate:create2017-06-06T01:31:32+01:00Û÷¦m%tEXtdate:modify2017-06-06T01:31:32+01:00ªªÑIEND®B`‚puzzles-20170606.272beef/icons/singles-16d8.png0000644000175000017500000000102313115373744017635 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá MÓæ­IDATÓïþ©ª®¡­¬³³³³«¯¢­¬©ªº“–¢2441§š‘Œ³¬­“©„·ox­ÄŠª¢Ô8ÁyjâYÎœš®‘§¤»mw¯Žª©©Á…t‰®Q60N¯›Ÿ’´¬®ª›¢“²ªŸ¯ÊÕ·Ùʧ¨ŒÁPÇpª’ž· Øe©Ò¦¥Ž¨;»o±•|¾¢ÍMºÏ¦¯ª«Ê¤©™Ÿ¦ÁζÎǧ®q0&.‰ºsl¥ËÌÚÒ¿©³3F£‰¬˜¸ÒÅͧ³7,ÆsZÅÙR§Ñ¦³3<¨§Ÿ¡±ÊmÈΧ°W,7)q©˜•ÄËÒË¿¨©±´³´®® œ¯¨§¥§¨ªë?Žô¡–%tEXtdate:create2017-06-06T01:31:32+01:00Û÷¦m%tEXtdate:modify2017-06-06T01:31:32+01:00ªªÑIEND®B`‚puzzles-20170606.272beef/icons/singles-16d4.png0000644000175000017500000000045313115373744017637 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA† 1è–_bKGDÿ‡Ì¿tIMEá MÓæ­_IDATÓMOÑ!btFc³;{åI€Q¤4Mig‚ó¢`ÆSå`5âpÅc*s=‚GþeK=¢ËÌo–ÊÎ\‰75] òÆMys#¾Œšn(I;÷|ê>,?½6%tEXtdate:create2017-06-06T01:31:32+01:00Û÷¦m%tEXtdate:modify2017-06-06T01:31:32+01:00ªªÑIEND®B`‚puzzles-20170606.272beef/icons/singles-16d24.png0000644000175000017500000000102313115373744017713 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá MÓæ­IDATÓïþ©ª®¡­¬³³³³«¯¢­¬©ªº“–¢2441§š‘Œ³¬­“©„·ox­ÄŠª¢Ô8ÁyjâYÎœš®‘§¤»mw¯Žª©©Á…t‰®Q60N¯›Ÿ’´¬®ª›¢“²ªŸ¯ÊÕ·Ùʧ¨ŒÁPÇpª’ž· Øe©Ò¦¥Ž¨;»o±•|¾¢ÍMºÏ¦¯ª«Ê¤©™Ÿ¦ÁζÎǧ®q0&.‰ºsl¥ËÌÚÒ¿©³3F£‰¬˜¸ÒÅͧ³7,ÆsZÅÙR§Ñ¦³3<¨§Ÿ¡±ÊmÈΧ°W,7)q©˜•ÄËÒË¿¨©±´³´®® œ¯¨§¥§¨ªë?Žô¡–%tEXtdate:create2017-06-06T01:31:32+01:00Û÷¦m%tEXtdate:modify2017-06-06T01:31:32+01:00ªªÑIEND®B`‚puzzles-20170606.272beef/icons/signpost-web.png0000644000175000017500000003711013115373722020134 0ustar simonsimon‰PNG  IHDR––³cæµgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEá‘ëb=LIDATxÚí½yœ\Gu/þ­ª{oïӳÑ.d-–e¼aÛ€0‹ `HžClNXüà‘_Ç ÆäÅØ‚Í#D6ãlY¶eÙÖníÒh¤Ù·Þ»ï½Uç÷Gu·zö­Û!Ÿç3ŸùÌôí{ëÖ9uN½Øðøï ü¿úþ £ð"ú¯~Ÿ?ÀÌÀ+üw ÃàüÍàK"÷% êÍìÍš¹®[ø‰‘¿`F___$Qªäs6 ƒˆ¤”¥†1Ó’L(€a Ò`¶ëÊR‹1ιÇãinn.üÐ(¼‰D"‘Hyyy©_%‰˜¦éóù”R¥[¼D4<<â—g-¤x‰†aP¼QÞ* —N†ç<•JÅb±)I¨¿‡¯»îºÒ :ýäŸýìg---[·nUJ•nÚ™Tü_üöbóŸa‡‚à(>Ó8ƒêfu¾tã—Bå%BFÔîÝ»÷îÝË9/””ãI¨‡×Ì1·E‘¯D$„ "Íèz qsVJ-z¥ˆ €/…,%pE`Òh-”+ùÕ™Ÿï¼A“PcfÜ%cÒ4Z3J¥`Û¤ ••¼èË‹1&¥L&“ŽãH)c–e…B!Mæ…<ç47À ¦×kˆ0nv*7>fš¸*4ÿG$I¥R@(*ÞŒÆÀä$ä±½úª’㔇Ùå—[–ÅŠ»K !Ž;vàÀ¥”뺌1¿ß_]]½víZ¿ß_Ä-™Š à bœðæàä|ŸCXHÐ\d°Þ·b±ØŽ;‰„ã8k×®-Ñ®aLuA‹Íæf‘LÒÀ€òxJ¥v(¥****++9ç###ÃÃçOŸöz½ëÖ­+â¾¢€ð°¡Rç‹1$ÒI ±œA„³ƒ¸óßðÚ)ØûüÉ•öl5"Æíß¿?NƒÁT*eƬîœLþh¥PVÆÞúV À¾}NO%! ”rùòåË—/×Ô}á…„étºXC0Ãî!<ó†8¯—®É2–íÂS†ßìÄ_>€ý_GØ%!âÔ…±¢îÆHr³×,xüøñÞÞÞæææX,ÇKºŒO] ¸€ËÁ1«‰8zôèààà¦M›B¡P4圗ڛ8 µöÄy–lœ—„#c†aƒA~¿¿······§§§½½Ý4Í…®_W>,ª€¿¾ï¿Ý#xýêÃ0 üôûñÐKøÒÏñÛ/"è…×´2 ÛGiÐôú@î5œ Ãçóy½^¯×ëóùLÓ\ø3§˲âñøË/¿œw…}“€%²ŒX"`ŒiŒiìy<žYÞX|jíKÿž4ʼÀ'ç!÷7 #ïܹ³DTtØòœFS"(œÚìgñß)˜s. @+2Ú3M³¤Tü}†"ì…y|åí¡I¿³´jÍ¥»»;&¤˜¦9<<¬ý8y^ܲeKYYÙBf$UÎ"$p6>çF*@•àX|þ›b'“:n ?™{E á8bRk†s¾píÿÈ‘#===–e.Ó4óÞð<Ï?ÿüp8<ï|'#¤ŸÒ;!áÊ`šà ÄÔÜÒ2¦ÂÕD¼i_ñÌo;o„"ÇÑh4™LjVÐÊE^”iïÈȈmÛœs)¥eY•••óβ,¿ß?.|QÈß:¡9‘H¼üòË^x¡×2r l³HÂ/f}7D0l'?ìØ‹¤l˜±4®\³äÎa䬈¡¡!è¥UH0"êïïÏ"¥lhh(> 5$“É;vä³ä ÃÈ3Šiš}}}gΜÑDUJmÚ´Iû?ç7å ˆ©°ã8ŽÏ3g ’!ð£ßág/ƒ³l°—åÈ©mŒÛ~˜õõ(Â’:¼øp†yLˆˆ<800 %c,¯½3Æ\×ݾ}»þÛ¶í–––©H¸ uFG¥ëëë/¾øâ@  ´u²}þ-9ç>ŸÏ²,˲Î?ÿü%K–`¾îÇqÒét¦R©”Î{Ë¿”Ò4Í-[¶TVV^š5ZÂOîÀ-—A¼&L1FApxM(ÂúV<ùÔÖ!mÏÙû¯%ÖE]ÔÔÔ”GѸïx<¯×Ë9_ºté–-[0Å6´P.ÔT¬­­Ý¸qã®]»\×ç%Ò_PJ­[·nÑ¢E IÄknn.L1ÕbsdddddDªõæÍ›kjjôàsŸ”‚ø¿ƒTø×ç'‰v°®?ÿ4–Ôp޹ÖÞhýÅãñlÞ¼ù•W^œÔ€¶m»¹¹ù¼óÎ˫߿SAª‰TWW·yóæ]»vI)ó{¡~Q"Z·nÝâÅ‹ç-?õsÚÛÛ ?Ô«áðáÃÚÇæ8Nž~ Y(Œ$,ÞEx`;LqÎ"4\‰UØv'7ÂIÃäóÏWJy½Þ-[¶ìܹSS±pp§¹¹yÆ †a¸®;ÕŒŠc橸iÓ&!„ÎËFÎïèèÈÓo!0¥”,í××»H!ÿ-ÜÍÆ”„à¸ÿ6|äb82Ë‹œÁ•XÛŒ‡?ƒÅé"ø³Ä›Çã9ÿüó«««ÇÉgmÒoúÍ´Ïï‹›7oÖ£j¤kþˇQ˜”Î ŸÖP\úeñ r¼øÇ—@*X¡£Ûþ ˚ঋýÖxóz½y*rÎgO?×;SÈ‹³ëׯ×üWº.ÇqLÓ,.ýrÓ’0~p+n¾¶‹µ-xø¯ÐÞwÁü7oy*&“Éæææ7Ά~˜j/œ¯ä«¢êëë7lØÉd´þ‚)¼(FÉO8ÞºukUUÕ8Fglœ[…ÍÍBpéÂ0ðO†ÆrÜ|7e3 ô£sÏÔ)ãóÇ^žŠ6lèìì\¶lY>u¨Ðç5t–~I_EÿÑÔÔ”T᥂í:{u•"ùzÉq`ŒyÓüÔÁ‰ ¯ HiùÇR65‡ð±•MóC]0\³fMጠŸ6¹¬›–hOÕÑ£G#‘H¡a7o˜^ya`Âd–·uRD¤17a(b™˜ 5BL.¼¶ÐU:}fÜ£qÆË•¯¬(Qà)÷Æa§˜t×vt~|Ž ó.ÿ¶¶¶’VÁ3ÆÎvwE¸ 1®JRÏ@Ä8WžZ»ž rTQ´“”dF·Bkä”Irâz6@€5Èü_å¸U4FJ)=Ï–-[J]¨ýÈ£]N4”:ÞÁ¬4¨/"ÅMOšÕ¿Öîô/RŠ-Ä~›z0Fn7/?b®Üˆþ2Tš¢~Æa¿ÎšPÍ0Æó;ù^¨Íóq»”v²,´D$„0ƳÒÜ´µ Ì"$ E@#ÆL€bÌ#aPiHh0®`2„H9Gæ]‘Ó#VqMfAŒ'a¡±522‹ÅlÛ&"¯×[WWçõz¸MѹòiâD tNûàL(RDjì÷'ìsŒiY9UrOÖ>j©\Š'ÀÀÁø‚†r#àzJ ©JD’ÈËŒ³¬©ÍPCEl²ëSÖÚŸ8qâàÁƒÈùD<O ذaCUUUÑcâDŠs#šè:VSÞVnv¥öS0CJɱ¤"WºDŠ3Áùlc à¦Óg` Šà¸nÆE{Œˆ\¥ë»Á?÷|"fÓcQ*“k0Àqe4•t¤ y­€eγSúH]×­¬¬lnnöz½ƒƒƒ]]]±XìÀ—\rIQçLŒ !LÁ )Dj¤OY41˜3!¨®rqCõrÛI;³³¹vuÀ[.•«½â©L,eÇ8®kÇS#–á5„5u¡ˆà±zùàÎÝïo¹öÆ·n|n÷Ñë¾ñï1iσA†àñxêõξ֪²ÞrížÛ­çh™Æ½òNò?ûêá›ÿé?ŸøüÍÕå!eÛÒ‘ªëH×Ó}:F÷êl« —ù=JÑì_kŠ@0çgϞݵkW:.++«ªªêëëëìì+¤“ü á!¨ÂüŸR¤ ÷*¯écçªýh†² Á9ÒöÖ­O|æCÿöÂÞÞhââe-W¬jûÞÓ¯žŒlYÒÛ-ŽÏ²píÍ5`޳vI#¤"W2€ˆ>ke¨žG»8‰`bYK]aøƒ—æ"E1 ¶´´´´´Luµ8TÌΊÜ\ÔÔ'ÓÔ„LiEþ,e gÒvÖ-ªÿæª6pÇíÞ}Û» 8RJ¦çm“M 2ã@Ç ¤Í "n¤Heì1Ƒ̌é„1Ób:£bRR•¦,›ðÇl¾Ÿ÷x3%V1Æ”ãÊŒgŒ3æf"œÏ’g¯îçÉÀÆÞÁ&{É…{f0*øô’çco1©È˜YæW‰4 ¶Æ98ûÓ{Mf~ñ©÷B¸rʼƒâÔrÎGGGOœ8¡ b&6!q]·©©©¶¶¶ˆÎÎ…öÔÜd“¤µLÁãiûåÝç/n,ó{”¤…σqK¥xz×Ç®Ød2F:Ûs ú‹þõ;ö¸ùÞmÿ|Û»|–ǙԌ/ú|¾D"qäÈ˲ÆÑ‰1–J¥<nQY¬sºL.°xõ#äþUN¤ˆ Áã{çɳ[7•ù½J.(#'ÛĈ±OþÛ‡{‡ïþèÛu4Fÿ—_ßÿ»Ý:8üÐÎ72®üç?»¡Âo¨IÌ…O8_áqá…¶··ë:ïXðù|Å q «>Æ#Å4„iðÜ0LCÓà<žvvžìŽ&Ó\,È'›ðYÆwŸ|åÎç¦çÿ—GïÿÝnCpW)í8üí¡ÎÎÁ A³ÚÏteᆠ´g§°ÅýTÝùç…tA'gŒÛ÷´W h†à ƒ¤TJqÓ W<»OtÛR>š3Ke Α!X44”¯ð("ÂbŒkR™†‡3‘³ñ7MÛÓ|™ëÊ©|ßDÄMcgïGïäÌpìî_ýÁ‹:”ã²ìvJgF¢WòB§ Á<祂!x¯Xûtse º|eÛ•ë–ÊŒ3£û¯8MKâñø®]» éç8N]]]GGÇo¼ÑÝÝ] × “Ê) T·Ô­9Ý»_*ɳ!þüu¸ÒöyÊZë;<†OJ9M.•ù<ß¼å:p†T†rác›5¸ª0C™L.Žô &3g`Ìqesehc[ã ŠXQÝÆ:ÕöÁ—Ö•=ö훯aD¤JéÑ;tèÐàà`þ0;M¿M›6y<ž 68~üx1fÇ”rÃÁÚÖúµ§{÷+’Z»AV™r}ž²¶†u^ÓŸ»4ۻѿ¼šªÊ ©ODÌ4:‡#ŠÒŒqÛ•Í¡ m ‚sI6O›4_Öfî(%ƾƒÖnLC|óÃWÁ¡ R=ùU«V%‰ááa˲lÛÖu÷ÚÆ7MsÓ¦Mº5ÅÇÒÊsTܧHqÆÁ§ŸÇôK’³t“SÔyª±¯ª´WŽ”Í•¡ m ÚÀXˆ?6gTÀ•J)šXÄûûÇ^JÙÎ÷n¹–2n lJ©@  kþûûû›››7oÞlš¦æH¥”â /Ô-âni°s¼Øqºw”’yþ›=ý¦bCäŽyu\µ¤¦|C[½ÈÒoA>!€”Ï4}ç3Có¯!YGNÎO S†|gkM'ŸÏ·iÓ¦ãǯX±"O¿üUÝfkLJÈ˜ÂØ9O?/Q;{÷ú<ÁE ë<†_ƒ~“` @Æ•M•¡BúM69·¹œ]±iù”7f;»§§™Wqª|óªëׯÏ?aÜUŒõf1Rœ”ÅÌ­ÒUeþú¶:a^K¥³ÿ‘âÙâQˆ£ùîY ru}e¹ß+8ƒRy-‘ù²›{qšŠ'§Ç.Ϫ“çÍŽ%!cD¤Üt&3Ïì¼Y°/ n€À¸â–ÍMg~6U¢œˆ¥Æ5$dĸá0À&Ã…•!cÞ$ÔØ —W¹Š÷}.ñƒYfpRfYŒÉyˆY(´ Ì!!Ø ¦°PÛ:vìÈððHš•ϧ¥Ø\ (RInÙX膒ÚO"Ž´—YÅÕ¬"b ŸC ¦¸©ÌX&-‹ .œ"òY†Ïç[½fmá…‚Bm(I¦_ž}«y·OéboœäkøàHd…Ó_Å ·T™ Ę!ƒ‹'{šÜhcb€"©H10Îç¯Ó1’Ü&¨ñÌ[¶^èóûJtžˆŽ;v¬ëÌ™qÑ•1o¯ LØÍØ¥Š.É«€1Ðñ^7íOõ6ä±sæÜ´C˻ѲTo7 bDÊë ùMŸTn2Q¤æùŒ”czk­†ãMMÍ¡²`‰jܵ«²¿¿_ºît$D® ‡„(…j§'-àf÷BsÌ^Ȳ¿fâT =§Î&ÆMĘã"R^Ó¿ïįNv¿Ön\~­ÏS–O„œÛd `ù†W“FFnÓ$œUß= ©›qJuîÌBÁ‹Ð   ÎŸXa¡¶""’ŒQ†'.jÎË5VÓôãÕϳ)’:É?è«~ùÀ¶]‡)5,o¹(è­’rÎ/¡7bÙÕ”3¢>ò‘œ8qBû9ç©TjÍš5ßúÖ·Êˢw2·Nˆšlf°¸ Ô¬Îšè ÃÑý ÕËë+—8®V‰™i˜º¬"‡2JÙq]}aËks.ŽYâó”Y†O*Çà¦Ïà57‹ØIˆ~÷»ßuuuiq§k4“Éd&“AÀ `*ÓÂD"Ç~‹WN!m£­ï9‹š ÓEîÊÁç ‚ Lјl|W:ý#'*B–éSJr.l'ÑÙ³×v’º8­:ÜR_µt¶SÖ«‡~yìì+†0¯Øx‹ixHåWmcŒ…Ãá®®®oûÛ—_~y<×~p8ŒÒ$ROFB‚0ÑÕý#¶>×Öøk¿Äþ 7\•)/R¶g2ööœ° ŸÇ ðœÛš@ Héôœ ú*-Ó§ƒõ†°Zë×r&7}ºoß`ôLuy«ixf(1$å3¼?ÿ÷½tfŽ×?j™~L–ð¿pÐ/óÀüüç?/++»êª«þôOÿÔëõ–èH¢ñ‹"[¤ q׃Ø~›cÏW1rîx;¢øä00.Š"wˆ3‘JG»ú(åzL,1¨HŒÁ ÓÐ…Ú–ixÌl¡¶ÜÜ<Ý·ïTï©dMy›!f ‘ôZÁ#]/ýn÷,iÜ|ë ÷®[zußÈ %Ȧ‘‘ÎyWW×®]»üñ;ï¼óÒK/íïï×9DÅ“;ú¢øÅ.ŽãËÛpË}xí$t ã‰}€…b½I2qÜLmÅ’EçU†³¬ Ö?rêH׋½{¥rÏô¿qøô޾áYsñšòEÕáVÁ Ð̦´"² ïÉî×’éˆ!Ì·_ðñ‹×}èÃWýŸUm#×j¯ˆ ”úò—¿üÌ3ÏìØ±cïÞ½øÀìÙ³çÁ,î@y˜|/Œ¥²'&ñÛƒ À2°ª†€%ŠfôS¶ë< a€Hp3Oƒ9ñÈ„09:ÙW)ižÚÊÅ •LGú†O†üÕA_¥$w*~b€"e;)_eÀ[1ëú*˵%A¨aÜrË-È™wÝu×c=6::ºgϼ™{aeA/"I\¿ÿú×Ppg{Qìâ4TeŒù=e‚‘.Æøp´;'g¨2ÜTÃgœD,9X_¹$à«te†1OGÎ}•ŽÌ$ÒCXÙºû©G!€1îó–ˆ&ú‡£g×.¹"‘=]\TjyÞÙÙ©”Z²d‰&áñãÇÓé4­Î¼Y©De¹ß{?{ õ÷ãê Çñ«×±ývý<ÖØ>nó¦”ô{Ë›jVö Ÿè>鵂ÓÏ#@) ØJI!L¥¤+m¥¤à\03mÇ©Q‚ò{B5‹¼žÀô L8ã'±¼ekY &šøÕŽoFºNt¿zôÌK Å,ßÒ©Ö/¼ðÂwÜqÕUW]pÁýýý?úÑÒé4çüÚk¯ÅÔ†1I˜ŸÏÿ~?b)ü|'¾ñ+|óWÙS6¶´ÃcŒ±ÏçOÀ\2suyKU¸ÙP”˜”c\'‹.oÙªýaŒqEÒï ¯l»X¡10do™~ n;©¶úõ×^xǶç¿Þ;||Ûó_k«___¹´gèhÆIºÊ)Nã>@kk«ßïðÁzè!DÔØØø7ó7W^ye)è‡É¹A¹(àGŸÀ'¯Æ¡d½h­Âú6ø¬b†1r‰w@VM»wG¡™?ËWáŒgìÄeç}´µ®ãLÿAðÖ.¹b`¤óØÙWÊ5!_•REH\ÖûÜ%—\²cÇŽƒ¦Ó銊ŠóÎ;O7˜scf ’Ø´›:ò9@¦Ôa¨’c'¹¸aÊ֋ˆT*]Ò´iÕ¢K¥rS™¨šu/©A)ÕÜÜœo7 ÝQÊÒTGÓVù‚7•²EÆÙ.‚¿Ç0]B'c<í$Svgµ©LtÁ¦IAŸ¡‘/»™SÿqíV“C|ÚµÁñûU4-èv¦Ó~#g20Û(ÌŽ2ßžñùê9Ý^Ì9è˜ÆT?¥–²ãEÝo¦›PÑCâšrÛ¶m{ï{ß« 9Ë‹'Cfè慠bŠ€3Nј£å9£§º6׬¬ ·(åÒ‚E>çÆ4î7Ê5ª* ¸®kšæ³Ï>{ÓM7uŒm€?#¥¦\`8†Ý0Dv~…ÀlKëÑV éÎ_2‘aX}CÇMÃSYÖ$sÆgb`´³{ðˆ8 *Ü"Ý…ø‰s£«o2å|\í鈊!̶úu‚¡€K'i>ùä“úЇ4-çtûHH¹J¡qË›1B¹Õ!éÉR±pZœ!e£±báb›xÆIv†Yæ¯QÊåL D:»ëX1Î ¼¡HÕ”-"Ø3‰DôiöíÛ×ÚÚšKiÕÆï÷:thÒÂÛ™I¨·ºX7ÿ#~õ:6.Â/>¶:Hg¹‰vý4é¬ÔÎ@6Ö.ÆÚ5@”œ¡o¯‚ãféÇíuXÓŒÃÝ8Ú Vb"ºÒ9Ý·¿á`Íì-î‹Ö}3‘LG”š$èÏÀˆ”àfcͪ€7ÜÙ»7‘Â$"ÁÍD*rªgoký‹•ÍÛS£”úüç?@S€”rõêÕ>ú¨°úkÚñfY֤ǼÏÚ.d™ìš…!{GìA2“=펋özt4ƒ1¬jcØsº”íÑÆ„Rîé¾}­è( TÓ,tñäéÜâÉ8W‘bŒµÔ¯)Ô¨­¾£³wo"Ü çF"=’ÌD¼þŠù÷ZœJ)?ÿùÏsÎ?÷¹Ïi£Âëõ¶¶¶655§É›š‹;•Ã2Ƨ\0€ÖµbQ lŒÁQh¯Çºf=0@XÕŒ Eó)2ÍÒãŸFy*¦í8gb6håÜܘäX¯\¿ÌÖº5ÁE®"i¾¶úõ_X*`D²¹vee¨AÊùÇõ>'¥üìg?ûµ¯}Mײ맹®+ÇÂT)ŽTpœ×'û±¢k[r®­ (¬oƒR€3Ù)œs™°+íºÊ%5m“&q30%¸©0‹-qÚ¡”’mõë„04Át%”ixÛê×wöF›kWÖ„)r±°XN~_üÜç>Ç9ÿìg?«?BÌ2^1E6÷]aŠÀ9:ZPBs%€¬ß)ߤBh•2û1#6÷¶IBÁ¦sfÍqbÐY8šiç9á\¯C¹–ém©[“LG+˹zy7¦Õ;¦"r]÷3ŸùÌðððã?Ž)l³*‹Ñ_áPs.N#X‹j Ðd+“ òi7 ¤89¦â4×SDg#­ˆppF\9&æZ—5$ÆÞäºd±°7P)m`¤\ƒ¤H3ͼO²Öð•¯|åÖ[o0©³{æ²åÂê£Õ<ó(k&¹3øB LÀUÊž´U=ÈL·Dõ… Æ —¤0‚ oÍ Eˆeב]‹DR¡ƒÙßß—HÆç} r¾j0Ÿ={v\¡>4‘HLL [¨}ôÈàÀô–Ïþ\²ùÇM€÷¤³'K PLe0ÒÄ\Vº®èŒ „ib±È¤Jÿœ@ËÏIwA"òûý>ŸoÜágc©PnÚ—yc ¸[*#€RXœápâÔ’±gùuÅ…åø—ïnmXTYQ¹päN D$ #;~ôú믅B%H—G½þúë‡W›1A/ æ$CL6¢ œ× 8Yzç %Ü”_H1–„ÅkHG $ˆÈ²LÀWŠþ¨ÈF¡L&¥¤Ò,RÒBm]v:îÒ$ªã \å$q.,Ã/•tÜÔŒøU$u¥.ŸJi+t²ûõo?tÓʶKþúƒ?'‡õ!Ö~OÈ•¶“=Í3K?Ëô½zø—GϼÜ\»fóŠëç„]¨}ªwwsͪÆê厛ÉZ¸Ü¤s'j3En,>˜ÎÄÈkúËÕœ•äÀúÐ’ÝsOòÐ!·¡A èctÏå¬sÎöïwn¼qäØ1;67m2ìØáìÞínÞl)…y$ìOq(:˜F<5¬ <¦ß2|Ó—O@Üüþ÷mZqݦ•×§2Q΄"é1½{~ôëOgœäò– 7¯¸~6UðŒˆIi3Æ…0òÝ·0Æ7}¶wo}ÕR¯TJ !’Éøé¾ý‚R¹R:e -µkñûDô“Ÿ”WTðßþÖþÈGF1uî¼3zì˜síµþ¯~5TYÉ œÃçcÍ1ïij‘!Ì—üçƒO}Q‘Z½è2€Él#ÆØ±3;—4lÜAÂJÛ±Ÿ>õ…%M›:{÷Y†W?i¦ÑúGNèBmŸ§Œ»K¯\O +åæOß3 Ï¢†óBþ*ÇI?»+šÌ8I¯œ¥_ûÍ5kLÎQV6æ}”‚i²—_¶wíÊfl|èC£¸ííâSŸòüãäZTÌ&&o‘æH´ûÁ§¾èµ‚|ÛWç¶›6„G«6BX†0=VÀ4½†0uå¦ÁÍÿøíW=fàƒoûJ*cf–ŠÓŽÍx25Ò3x4à)o¨Zæ8i©\†lš3Î\p&¸®{²L_ÐW¡û<»ÊñXAËô•ÚŠ+HIùß$$GŽÈ‘bŒ=úhººš¿å-Ö‰îwD¾öµ¸^Ðó€‰\H‚‰žác'¹uÍûÞ¾õµ‹^;ò˜”Žeúž|å¾ß¼ü=CX£ñ¾‡·ó—/|»¾²ýãïù—C§wì<ø‹?½îžXrH¥íøpôlY zFgXÊŽ+RUáæšŠE®tâ©aíï<Iô1Æ])OõîQJ†ƒu5+toüd:rªg7g¢¹v•n˜ÿ_Mµ10w:“Éj­×\ãýÿ(÷ùØ¥—¿ðBúßÿ=}ûíþêj®æîŸŸHBF€ÇôÊ!RŽ´p.¤t7n¸öÂ; áyxû7Vµ]º¢õBÁMÓðô³ÝÔ½ÛþŒ@‚ÇÎìüç_}ò¯>øsg¬z9ç€>„ˆ$XöÀ·²@µ×”Êí9YjÔGÛëƒc#ñ¾3ýoø½åmukMÓ縙ÿj’Í ô^PUŽ^–N« Œ@€lÙ2ñ l`@%“ú°â95I‰¨TNcÕŠ¦ê•Û÷ý”sãlÿ\iKå¶Ô®YÚ´Å4¬_¾ð÷K7¾}ë'#ñ^©Ü5‹ßzû»ï· ß`¤ëߟ¼«±zÅ—Ý•ßæ€·Ücú{†Ž§íT$Þ/¥«ýA_¥VÆIô  jƒþl¡v"5z¢ûu"²Lß©Þ=ÖPµÔç ý^í…zÒ<ç,ÖL)ڲŬ«c8yRº. ½½  ÖV q`>GyMÂ…ºOòŸ¼ó;oÿfÿÈɵíWx­@CÕrEÊu3®›Âlo:?諈Ä{Ó™¸FeYS}e»)<ƒ‘®oüçÒ¦ó—·\˜¶ãÓ£U‘ôyB­õ#Ž“ª*k4 Ë2½º3I›H}U\™QJ Á³ÔåB*ב¶àÞ³¨À9»ûî䫯:==Šs(žýíĤ.¼Ð¼í6S“øèGý_þrô¡‡ÒápÔ¶é™g2>úQ_Ew]*ŽQ¡#«Õ+>}Óƒúh~‘¡”“ÊÄu)Ýþî8nÆvÒB˜\×vœ4@–é½ëæ_¹ÒNf¢|9E*ä¯ë@ ¨ºªvRR*W›†ð,iܤÈÕN¥¤ß[¶¢ukNscIå±À³(ðË_fž~:É9SŠxòÉ”Rúo¿ÝЗ¾4M|ÿû©ûî‹hi1ÿò/CŸø„ ùU‘NYåë*'–B>ÂÀÙ¹’Hö»cŒ±ÜÕXrŒ~yz R®+u`®€6Ù‹®ÓŸ˜ˆwL¥ÄïÛiµDôÖE"!Æw°¡¼œ1–ͶýâCû˜dD¨¬äõõBÇwç7•iÂß,NÐÄGó© ÑrE³ùÃhg†‚¥0å¥i>ys`–þk"´µMÙ´9whCƒhhÈâPJbåÓsu”¹F9ÿ¶º8Ï•vÑÛ+ˆ1^XöP"PJy½^Û¶gƒ_9YtžHúÂïÊOýü9Q±D•ÊF"5K ™†·”F1&×V$KÊš:b®ëfSÏù$?ã^°ðÒ8èîîþ/+ÔÖ ”ôY¡cgv~ó'7F}¦á-I·AgÂv’ÇÏî:Ó0—‹]|^”Rçž{îÚk¯½÷Þ{½^/æ›ã4ÃŒˆcGŽyÿûß‹Å&=ÞtR( *R¦éŠž¹ïá?Šž± q©H ÁDÚIžêÙ“q£±Þ®þƒ ÄPä4)e(zæ™gî¼óÎT*uÏ=÷Ü}÷Ý>Ÿ% ¢NºÙ¶mÛ‹/¾øÄOä?™ŠBB  p²çµû¾m8zÖS<*æé×Ù³'•‰ nn GÏž9GÅâ€R* =û쳟úÔ§týŸâî»ïþîw¿ëõzgÏ%Ó#Nå@?mçÎùßã.M Ÿ0qnX¦×4¼–áµ ¯ixMÃk €ixºúÜÿÈíƒÑ.Ëð-œŠZ~¦dgÏÞT&&„¡ÁÍ‘,Õì%ª”ÒuÝI$¥ ƒÏ<ó̧?ýéD"¡ÓUttþî»ï¾çž{<fÇ‹Dä8Τ1Æ„:)Ͳ¬×^{í¥—^ð›ßü¦··×ãñè/L¿5.P#%ÆD"5šÊDËv¹TJ&Rãñ^R¹œñξ½÷=|ûmïú~U¸9ã$Ù|ÓŸÇóŸ0 ›y nGÏh®]Í›±c*•——†‰D¤£iþÓô‹F£úØ)ä¶+ÎùÝwßMDwÜqG*•ÂLvŽ®hGo¦688xôèÑ3gÎìÛ·ïàÁƒ{öìéééaŒíÝ»÷ꫯ^»víš5kÖ®]ÛØØ¸|ùòp8<«Tà9”nEYÍÃÏý©]÷ nJåŒ}s¦‹Œ7ºú÷ÿá[o{÷ýUeÍ™tf^ÎÌÈhþ³ãB˜ãt] aD»Xsíª!„. ºòÊ+ËÊÊò™gJ©²²²gŸ}öŽ;îˆÇã¦iêúéBÔ†ñÝï~WñÉO~Òqœ©lýåd2¹mÛ6¿ßà 7äZÝeæÕW_½á†lÛ{šØ·oß¾}û4÷×ÔÔ<óÌ3ápxÒ★ RF¹C Îý `Ñi‡YWÿ<òñž¡£†°0wKƒ1žÌDOœ}5‘ ¥=nII)060ÚÙÙ»oìzZÉüéOúçþçwÝu×ßþíßâ\y<žmÛ¶}⟈Çãú8͉·kzç;ßùÊW¾2cþwÞùáøÆoüú×¿Žœ’b†”òšk®yì±ÇZ[[5± ×®UJ­]»ö©§žZ»v­^v¥ a¾²2{ê|®/Ò8ü*ÁÍS½»_Ø÷SPs&!1ÆGã}Œó²@MÀú« aå³fˆÈc‚þŠ€7Ôdœ„î72iZ¶óvìØ¡QùÜsÏåS9ç¶m?òÈ# ëׯ_½zuGG‡ƒyX¶lYGG‡–rÛ·o?}ú´×놄¿þõ¯õ¿ùÍo ‰Í9—R^qÅÏ>ûì5×\SÈaù“¬oºé¦§Ÿ~zݺuÓàY„ƒ’é\KÊ©{£p!•³~é5×lùx*õÎÚƒšE)ÙXµ´©f…ÖMÃsôÌΑh·aXseº®rImÅ¢lÞƒtI©Ì¤í›´p»á†vìØ‘L&oºé&˲4µHüáh†Æ©iš6lèííÕidJ©{ï½wýúõñx\÷ŸH§ÓCCCÓh·ÝvÛ¿øE˲tÃçÂoê.K–,ùñ¼uëÖ“'OjÎÓԽ袋~ò“Ÿ†1}zñÂHȘRÒkø-H;::yä‘ûî»oåÊ•˜ét‹I۫ϧ¬ùÜÝœ8‡TöòÖ þøß2…Ç•Î9åÎ,Îæ0°ùÄ)ÎóçàAè>sŒÛü­@DÌc.úFíKÓ¸Ö•ö[>9ïÁ™kýn—ðîw¿[Û ú^-uo½õV¥”þ[7ŒšÙ;£C’Êö0Á²ÔânzyÃ+¯¿šKá8.ƒ7ïe Ê ¸²u³ŸùC¬±|}C¸#'K‰sá¤8ÁƒlMÎ9#aZiœwLñ‘G)e~¿_G€‘+NÓZ«¦±bÞM,ÎÎóßlËb”„X|”°Àœ>bŒƒH‘š ? ÄIûâþ%G˜ó­Ÿ&}NEÁù†©È£83'êœs‚qT*äÎy:¶,ëàÁƒ–e•® Î4Íþþþ‰FN! Éo0fÕœ-µ’¦‹ù2š3%…ˆÁõÄb±ÑÑÑ… u6Æ=J›z^¯÷СC%Å›¦b ÿ>ZûÝÒçév"oB(+IÍíD˜ª@¾è£Ì®){s´;zszÌ> %:}F(ùÂù”þ@Âÿöðþ·‡ÿWÅøâoÈ?f%tEXtdate:create2017-06-06T01:31:14+01:00ú”*%tEXtdate:modify2017-06-06T01:31:14+01:00‹_,–IEND®B`‚puzzles-20170606.272beef/icons/signpost-ibase4.png0000644000175000017500000000106513115373743020531 0ustar simonsimon‰PNG  IHDRbbŽÎYÒgAMA† 1è–_bKGDÿ‡Ì¿ oFFsÁz{tIMEáûµË vpAgððüE­?IDAThÞíÖ[à Ð,½Kcgô£Sc0©õ26Ñ?;Ò#Á×&ô¶…êjþñ‹pŸÊÀÄ·”Ž0D=¢Ÿ¨†já!RÄŸîZ´ÈøŽEÏâ‹wÉNÀ‰«ìŠÐ®wÜÐLctÄØÍqÆn­A´OX=4b­<1>é|ßžº³6Á#%î¦3ã÷î»DfÚù~03#""æÑ)ꨇŒÍf³~Â0DD0J© ¸Â2ŒGŒ=6žÌ¡‰ÞfÈ…¥M˜'¸ÁI÷4[˜ÿ4å'>/~aliñëš³[µCÔgÐ~ËÎ}Ÿô?œ¬ü\•øU8W¶ADl ˆQ#<±lÏe™_7‘*~c•AøÞŠ¥tT±!'E†¤t{ Y#jBÝú­@äbÅyöoÏ'[©îˆË2dÿ ]ãW!UbX‚€È Ú„Ʌϰv«FâÎoaº‹ G(O$Ý6è¼Eâå1¸PžàýÄïLÌ€A›7\’‹ü­Œž„Ì näÀˆòÞû@Ç(ÂyQ|O"Œ\†er˜X%ÄǃܒGØ¢'Õˆ ¸,jÄUiÄã޽b %tEXtdate:create2017-06-06T01:31:14+01:00ú”*%tEXtdate:modify2017-06-06T01:31:14+01:00‹_,–IEND®B`‚puzzles-20170606.272beef/icons/signpost-base.png0000644000175000017500000002417013115373722020273 0ustar simonsimon‰PNG  IHDRðð±7~ÅbKGDÿÿÿ ½§“ IDATxœíy|åýø?;3;›Ín®Í $r‘„"¨`‹E°Ô£ ­Z[•ZO°ôõµµ´µýz| ¶ßòµX+?­Å‚Šrx *(w „„Ü!÷µ9v³Ù{gæ÷Ç„eÙÝ„ÝÍ\Ù<ï/_³ÏNžù¸óÞgŸyNYMM Á&v— ¡AT ¡AT ¡AT ¡AT ¡AT ¡AT ¡AT ¡AT ¡AT ¡AT ¡AÁI.UUUEq’bz‚ãxnnîäóᦄ¦(Š$IN²â’$%˜ÄŽâ $˜¤öùpU rSB€Íf[¿~=W¹M’]»v€Äâ ]÷‰È»àÞýâT‡FHhDP„FœÕ¡Ýèë£h½žÑëiguÉyT”_!†aõz½Á`°Ûí‡ÇñÐÐPF“––&|HR¦ªªª½½=&Iòæ›o7¿àKè–jpæ)sa¦¡¡Á5ÅápŒŒŒŒŒŒ´··/\¸0>>^¬Ø¤F__ŸÓæ©_B€R)‹ˆÀd2è鿉Çñ¨¨(¥R)—Ë)Š0@Ót}}ý”úx=¼t*.AŸàåu°é6²µÙlUUUd$| ]R"Çq€žª§‡§‹ø †a¥¥¥2™Ì™BÓô‘#GÌf3˜Lj!v#ñ1X1ÞÞàž~®>=sÇ„æŠêêj«Õ*—Ë#""¸ÌZ(øšµY:8mfÆn·kµZ«Õʦ_‡¦øËgðæ×ÐÔ!r¸1 þtÌKöræ¨Ì6/éëÃ7ŽA胜EÕÕÕÕÝÝ óçÏïïïç,_aá±Ê!5FGG=ê–H’dNNŽÀ‘lxþqH¾›탰ÿ[øºξ3ã|Í!Z `±s’Åb©®®€¤¤¤äää©+ô´n¶ [¼xqdd¤mêƒ7޼õ(|ü,œûd'ÞþDÈ(Ü©ªª²Ûí!!! ,3ŽI3Jh…B‘——Ç0ŒÅbéíí1 ÇÏÏÏOLL,Œò`€uƒu»’^Ù:vð›÷àû®¤PØå.󯞃eÙ܇ÔÖÖÆɹ¹¹r¹œû È4Z.—§¤¤°Ç™™™§OŸ¤(êüùó111ÂßÈŸ-úÊËÄË¿yipï’±ãݧ!)®Ï{Á}‡£¶¶ÒÒÒââ|®ôH•i$´+2™,::zpp‡^¯‰‰æÒEcsaã­cÇg/]yø»³î,;þ¨Šg¿†y>Bèt:¶‘ð©ÕëÄßX¦»Û½ƒ°«Ë™Bÿ)ét:Nç–(—Ë qa›Íq ž^ O¯¼ö™†zO¿o Ü·Äû[þ"—Ë.\è–XYYÙÕÕAx¾+e¦E•#--M¡P Y­V›Ír¹\­VÇÄĤ¥¥Ijîb’ð%ta!QX(•oKttttt´ØQL% ÄŽ"¦uÇ "ø@B#‚ $4"¨@B#‚ ©<·MÌgŸ}Æöf9!¢´´T¬xœ>|¸°°Pô'ÎðŸÂ¨åªuŒ¼!R4¢Þ¯©QB»}:^SDÁjµ–••±]è"âf³×!ñ~M ¡¥ EQeeeSt~Gð„æŠ¢ÊËË‘ÓR Í Èi‰€„æ ä´@Bs rZt¦F³ˆx¶@¹"“Éç¨d¸ìtII‰èmyÓTB_ƒ‰Û›ÜlfAí"‚„æT÷ ÉU9¾øâ ‹Å½WÀó—]&“±sÝ\ ùÞ÷¾Ço|>CQTeeåŠ+¸Í6åqèvO$ppPî)˜ÇòêÉQÐñ¿Ü†#¹û%¹º°° Ü¿fž¿ìž)Aäççó™ŸÁÇâwê÷D‡Çâž)*¼ÅÃd[©Ý/É ­ÑhJJJ5 O|)§…±™E"÷KºBõ>£él3ËÄN i3‹î—¤…†ñ?#d3ËxN o3‹è÷KêBƒ·ÏÙ슧ÓbÙÌ"îýšB€F£)..f×7â» Á_¤ÏÒ¹°#¨¡ 8°I4›YD¼_SChˆŽŽ.))!IRRã~ …DâY– 6A´nâe ië~I´ÙÎ+ÑÑÑRÛ3óžíɰ,´;D¹_S¦„F |AVSS3ù\*++I’d×A”ìú‹ÒŠÇ¦³A¨ØŒA‚ ÈHI}>6›“¡/A[B[ÍRÙÇÆ‚ñsø¿„€MÔ…Üà.ÎêÐ6›mýúõ\å6IvíÚ%Ãa¨¢äÚ§ ‚¦¨ÌØzûE±c—|H-NÚ1=AB#‚ $4"¨à¥Úf³õõõ éõz«Õj·Û1 S©TñññS}kG„”áEè¾¾¾óçÏ»¦Ð4­×ëõz}{{ûâÅ‹U*×õ‘.mý°¡›”‡ÎIY$b>à±§ÇñèèhµZm³Ùzzz(Š‚Ë›¤/Z4ÅL2YôZ]›ÙjpP6HÐÌŽ‰L;(©p¼±ã¥OU\êé1ÀË÷|wS©h÷—¡I’ÌÎÎNMMuÖ.233¿ùæÖ隦1LŠÕ÷º¶j¥fFœû`³mÔ`RÈ•¬Ð“¤ÄøÂþUý—´:Éb¶9”äÜ„èÛ 2Ÿø^±J!Ñ*Yâ“Y‘“ñöëÝÒϵ÷}ZÕ<71šZ\x:>>Þm·F•J)Ö:Êíèh1i1¡ Oð²: Í8ÆcÂ4@¤:.J[¿ž|<ݺѿ}Yáš2l´œnî:ÝÜõï“Õ'~}„R1ù«øÎï÷¿¼¶sØ0j±E©Bn˜›úâ]ËgŹoF:jµ™í^fX­[”óàÒ<“…>ü² ñN„@ƒ“hš6Ǿ¾Fàâ¹[[¯7öN`ºörÀ19Ð4g½s4k æÌŠ‹ŠPYìŽSM]Û¿¬ hæb÷À«‡Ê~{Çõ\]ÈŽ7tØ(jñìdÃN4v~PQWÙÖ[ûßÊqŸnS´Z o® B3 sáÂv9 ò³Ýh·›Y›5aII±skcgÙøe´ä¦ÄÕý÷£ì1E3»ã¶¼ÙC#ž­€O/4 ,ô¿]ª5˜ [e[ï]Û÷¶hue-ÝK2g'ð.´Ýn?wî»S<†a .ŒŒŒäû¢®˜íc¿ ‘a @ •2jĨužÐ7Ô¢Õµ9_êZ}Ëö8#)_Âý6à˜Lö~Eݛߜ;ÛÚ«5˜ÜÞíáüŠóáÙú-}Ó«¿ªÜ­3Àoö~ýÇ'œ‰TÔaþ‰=þjó½Ë²Ò„ŒÓøztt´¢¢bttH’,**Òh4¼^qœkh¸-¦¡T¨#Õc5~±_Ž+T!ìKç¥.ûû}Ç·|ôÍxïZ=W=â“ê.톷?e¸«8ûŽ…sGÍO¼ó9P4y©ñ÷.žÏž¹ûÌŤ(õõsRÙ—ñáb¶½ŽB÷÷÷WVVÚív/..V*•ü]nÓ Š¦Ë/õg$ÆX÷Hz꯻]ãu@)k³Éj“;êÕ=Ÿº›§¡§Ò-¡½îèè;Ò§¬ÓB–Ó½úQ¯¥¯«Í,&«¿rZºB¶£#‰ðN³¥¯«©ž6;Ïüákòƒt…äô¤Ái«}Õ¶=_Õ¶À±†ŽÛ½Ù *…|×£wð€Ô]ñ}GÇiÂgšãÏÕõÜ5žuº$#Q°¶<“;úÕ÷~{Çõ¿Ûw̫͡ ùiX‡v¢Ñh233¥¹Ž·4õ<ÿ†â§/<ÿF“ËcW&°¼íM Üîa²Ù³÷ëñlæï‰¦„ÐCCC.! YîÞ¾·ªSk§èªNíÝÛ÷r˜³ðu›·™‘*…|ÿ“wñ:µVêUŽ¡¡!qëõí'=§lÉ@Æ\½‚ dÕ—çŠ;‘й©×ù~­Úe¦¶{  xÇ…¢éʶÞ93¹ÍÖwT ù¾'ïº);׫Hº„ÝfH‰ËÁdî³!u=Rº`Öï<ßè––͢¿cÛòö?5-ëÐgÏžõjªë®Ñ®»I ƒ/u¾möqkn°N³}.ü!E¡ =MÅqÜm×hv7ié8l¾&8-E¡=Mõ´ÙõL…B¸Õ”ÇsÙ¬V¾œf²ÙìçB6~!Å:4\6•}.Ïfç™ï ïYŸF6ÀÈß7 y¹ñb ÍÂ:M’ä6‹EhHDZâ¶õð´ÄÒ±Çd„–Ò¢££o¾ùf©ÙÌ¢ ‰JKÈÅ1yZB.kH†BN”d$‰Þ¦!"­rL T!QÙéKÅŽâ*VÌ›î VIº„F üEVSS3ù\*++I’´Ù8ØòŒH’´ši.•!Ô E(p›M2Å 4H*`“ÏŠ»ÿ%›Ž³¬&¤‚+åS«–0X)ȱ£p»`8«CÛ t=ÜÇUn“d¼#ÃC%b2†¦¨ $Íëׯ;1víÚÅUVRùÑA 8 *P³„Øòæò¡‘.(ÊZýãÒÿ;œ) *¡Ø8¼øâ‹bGçÓ±„îÒÖºIy蜔EbÇ‚à˜é(t z†ô]6‡…¦8.Q„ÅE¦††Heü‡ÜtÓMn;îÍž=[¬`€G¡O5Âk_ÀñèÑÁÌ8X]O­„h5ל,um'ÔJç¦oF‹Îj78‰c¸Ýa5 ÍÙ)%$àn|eÿâì?ÎÔìí‰PÅeÝ~KÉÏ'>¼ñÆééébG8| ýÛ÷á…}àœÞf¸Ð:`ç7ðÙf˜?ƒ§Ëz‡¢= #&-áÉà1CÛ Í8o“¬£3“c³Ùd‡ Ý]Úz†¡ÍVC`B3 ýÆÁÇj.e_t}^ö÷¦Î2%~WëM7ÝÔÓÓƒãxzzziiéÓO?œœ,vP~À‹Ðÿ9øhìø¾%p{!ŒZaë'PÓ ÝðvT¿¤€•nm½ÞØ8 èÚÈÇ“E¯n¥Êb3†aJEx`ñœ¬Þã´9*,1wÖ £eøÛúO|œ„Ë+­­­ìÁÅ‹/^¼¸sç΃.^¼XÔ ü€­^:0v°¶ÞÞ0v|cÌ~ ©TŠù¸²ìv3k³&,))v®Ãamì,¿Œe7˜‡Øc'Sâç“D€¶Ç«Þe”аMëö†…F@fÊwÞ=ü\`rBllì’%KÒÓÓ çŸ~ÚÝÝ ÃÃÃ÷ÜsOCCCHˆ”ºÊLJ{¡GÌpþr!¸·0oÝág[„Úl7²‘a @ •2jÄxe·æ¾¡­îÊ °z£Vy ¤Œ¤|çXçpULÎÌå”Ã: oÐwvöÕÌL.”ûï4EÙ»êÙãù7±6À¢ìµ»¿|žik‹÷Þ{¯  À9íÍd2­X±âÔ©SÐÙÙyèС5kÖˆ˜¿pß=l¼ö9:1öKÉdn,J…:RÏþ™LN„8_øU³e¡ˆ‹Ê;ee;AüÅbe˜±…5ÂTW¶CÆ0\­Ô!'¹Nâ }ê©§œ//^¼(FPÀ} ­qiÄxô»ðËU^Î °m BH{`´è”Šp†¡M–×ÂUqáª8öx¤Uª›qõN÷4C z¢Ô F€îréØú‘!¤Z&ÃX§ Æ+ ØÑ4e4{_qTtÜŠ)ýÐa!› U퇫áåu vùYvPðÎ ø€ÃÎHB¡ŠÕµ½C-&ˈÕnö\|qb†éhìh$ˆ†¡Ù¶È"ÃâˆÇåI1s»´µP}é«Qó[0Ÿ©ÝKÑâ à~÷Ýw Ã~ô#g ´ÉdzõÕW'äææŠXðòPøËUpßÿ4÷Áu[à‘ïBJ4 BE ì-‡^=¬*€0Ÿ1’b³@†ŒFóp„:^Iªu£½¾ÿ9&Ã"Õ f«Þî°Ñ@8™p+Ç’÷ìùj ˜­†Wv}?wÖ £E÷mýÇå6yººº~ùË_nÞ¼yÙ²e™™™:î“O>a  ++Kàyõ“¡×_uÝðÇ}À0PÝ ¿ÅÇEüLj”«kž]',óÒoôL”ɰñÎŒ% ~x¡å«ÚÖo`ØÐóõ¹· 96[?Ú7z¹!Exôzý¾}ûÜÓÒÒ>üðC¹\.JHÀWkðïï„Uð÷/áx=t ÄG@Šn̆ÒxÛ_fÄfã¸<96ëÁÛþâo ž‰ìó+¯-âK—.ýä“O¤ã´ =…³â¡âŸÎ…² ¼uàÌI„†^ïïŠ[g !Ã'étLDê³ë? à1 ‹‹Êè¾äµEœïžË¥K—î߿ժUžÏ…ALð\ÈÇ×@Jía—2By³w_ ŠgÁ¬8X4Szmy‚ÔY=aŸDc"RÓò1îy‚kÛ9O,[¶ì³Ï>óÔápÐã322â5·É %).s¶Å{MÇ¡xĨ4j(ž¸—Û'¢8íÚæíº¹glýlH9©{HQè /¦â”̼jºx´JfNk§=Û¼ÙÈ=Æ0,5ž÷RpZŠB{šŠãP2ËËâì™ A¼þš{B3T§VˆQNz­{:=™¾Ýi‰eMeŸ =Ëf·3W,"¤y7qŸÉJ[2Þ[¬Óì¨)!mfa¾õÖ[ùè¼&R,¡YX§IÂ{ÙŒ˜Öi“ l3 Ûî¡R©¾.HYhˆVÃÍ Í¢ ‰ÊN_*¼Í,Ë–-;pà@BB‚Àו´Ðˆ)ͲeËœ+> TÈjj8hž¬¬¬$ÁdƒÐÉgÅ $˜¬T¸ g¹eOŠIÅ£Pb6›ø›n±$i³Ù &Ÿg%´•â~°vÀH*‚”ÐøWIÃ-œ5ÛÉpÇP…€ óOˆ¦¨ $E'%'TVVRµ~ýz±c×®]\e…êЈ  *Ј  8pÀòĆ¥K‡Ôê> ëeÿ>=îÒUuuŽÇÉÎ ëS©úÒÒ´¥¥ÃÛ¶‰?Kˆ±ï~îTÍ{qQ¿¾ÿ—»&]ÚúaC7)“²HìX¤ÂÖ­¦¯¿öµoëVãæÍ×ëTGUSãxúiº»]‘èà$'o¶©¢n?e­þqéÿˆÆàH§Á¨µØLmÇqR¥ˆˆ‹JSÁÓ)/“Aj*^X(Ç0Ø»×2Á™;wš6m2°ÇyyòÒREl¬Ì``Z[©ÎNñ§Š,ôs¯_—•ºäG¥¯x}·¢n?k³`ÔµP+5ž›¸ ê:m³'qLîpXõŽ~ƒy03e‘ü꽓§.F…†Êàý÷-m007Ž¡{î9õþ ¹¯4/B›­†÷Žl©jþB!W]Ÿw/ã6ã[íF»ÃûÇ74Òµç«-©ñóý ¾c2ñP´£g aĤÅd„&<ƇfŒ·Å"Ã"Ôq y(\Þ잦)ƒiP&ô‚Þ<ÁÚ|MÞ߬ÓÑ TÊââd%%ƒõõÈË“oØ \·NÀ-¯Ç¡ÿóů+?UHä寰S4ÍPo}º‘aèûWnݱï‘IÆÓ­­×û'°]{9ÄE¥;ÃB5ì²F¸oCþƒ‰'ÆzïÍfæÉ' ÎôãÇmÇÛŽ·oß.r-÷­ƒúÖæ% ~ø»‡¾þÍŸc˜ß7þ³ÓÛ/õ|{çòçc#Ó'ÝnfmÖ„%ÍM]<'eÑd¶bg€am&å¡aª˜IÆ6åèêºòóEðôÓªmÛÂrsÇö™}í5Ó¾}Õ¿€ûº{°=(Î^êø9)‹Ï7}î<áàÉmŸ—½æ|y®éЯÎa¿ó_™3µ÷U^öZáœ[Í[;ùxÌö±¶¤È° …J5bÔ:O`«Ηz£Vß2¶fFR¾ëxbŠv´÷UÍÃr¹2=1×ÇIYÁ„Ív¥¶ö䓪W^ €{îQ¦§kÙ·þõ/Ëš5nã8@,!IDATî…86öÅÅñ«vŠž›]”µš=þ¶áãUü¬ä"öexh ô 6Ð u¡åËMÛóÀn·°gV5þíƒ_……F³`v+¡• u¤:ž=Öûå¸BÁ¾$\žù¬vc[ϛìT„§ÅÏ'ˆ yô‹¨¨+?é×]7v[°™3ñº:47‹¼Z ÷B;×°jê*KKÈuP¶KÝ•®'äg–æg–²ÇU͇Óâxm³;¬®/iš²Ñf†ñ»a(„k5ZtJE8ÃÐ&ËUËA„«âÂUqìñH«6T6#Î}‚ôˆi°³¿†¦©HuBrì\vÁ®iÈ‚ÄÞ½cǮłsJ®RìÇBî…Ž‰HÍŸ}˹¦CNü¹µç\ÿp«nÔ¿­Í[ëZÙxá­[ú‡/ÜMÊU¬Þ¨íj1YF¬v³ÛWÅz´õ4M€ÞØÏÖÈ &"5^“@HS—U«¿ûÝX³]Y™ãŽ;´ZÚY0‘bÅÆÂK•cÝŠ?â¸üBó—gÎ]5#6»¼nò‘¤Ø,aã€Ñ<¡ŽW’j¿cÌåÒÈõ'b‚æÈ)Ç¿ÿm>wÎ Wê û›éƒ0¸ñFrÕ*,\(¿í6ÅÇ[`Û6£\©©Øo˜­VärøùÏE.¢9›± Ò‹GRã¡Àu<ôºuúÝ»Íã¿qãØóhµô-· Ÿ;ç>ÌC.‡þ3â¾ûš-­+ˆiBl,vò¤æ•WŠ‹åáá2¹RSñûïWVTÄf3·H},BÞ}7âÝw#|<9$D¶q£jãF‘Ç!y•Ј  *Ј  *¦˜Ð¿þÇ’ÆÎ3bG1†Ñ2\Ûzœï=½}§¼¼|É’%åååb2ÆÈÈÈÌ™3ùX¦¦˜Ð#FíŽ~&§Ù]¾)Ú.À>õ¾P^^¾aÃN÷è£JÄéýû÷·¶¶8p@È‹N1¡Àæ°ìøèᆎÓ"ÆàºË·;˜\“³gÏnذÁl6€ÅbÙ°aÙ3âçwîÜéü¯`L=¡Àæ0¿¾ï±œ6Zôm=ç]wùqÇ 8{öì#<ÂÚÌb6›{ì1q6 §N€“'OêõzÁ®;%…ñœö´™E,§=mfÝé}ûöÉår âàÁƒ‚]wª b8=žÍ,Â;=žÍ,â:½sçNƒÁ£££BÖ:¦v×7ëôÃkvÌIùßךØfÖéÉï‘ì ÛÌÂ:½}ûöE‹x\Än·_ºt©©©©±±±ººº¦¦¦¥¥exøÊƒò±cÇfΜ™““3þüÌÌÌÙ³ggdd°E8·HNèg·ç[íî’:Á0‚¦¯ZeÙæ0¿¾ÿ‘GÖ¼ž9ƒÇ{æ‹Í,Â8í‹Í,8™™ÙÝÝ­R©¬V«ÅâeN¡Ýnïïïïïï?}útHHˆB¡0III­­­œ#¹*Ç6€›Í,6»™×vßmf ¸îÑÞÞ¾víÚ¼¼¼µk×¶·;;Ýw›Y®{455(Š‚‚‚¦¦¦ñNÛ¿LLŒÙlöj³‹Ål6GFF~ðÁþÆã ’:0ø«Oûk3K`N?óÌ3 ‡£¡¡á™gžñzŽ¿6³æôÝwß]UUe·Û«ªªî¾ûîñNËÍÍ­®®.)) ½ö¡¡¡ìù .ô+ ¡Àæ0ÿ¿OŸæ<ÛŽþO›eྂgJ;p6773  Ã477{=gÓ¦Mž6ãûéz¦˜Íæ_ýêW~ÅS[[댧¶¶v‚35Í‘#G~øá‰ ½ë®»Nž<çW$¾#¹:tÀrå+·qžmVêuž‰Õ—×9pÂ3æòI^köìÙuuuìn™³gÏözΑ#î—€œœ·Š¢&?)''çܹsl<ž—pÇñ­[·.\¸ð¡‡òº{ I’;vì¸÷Þ{'ÕÄI MÊ•¯¢­ƒW¶nÝš••%—˳²²¶nÝ*v8°{÷îüü|’$óòòvïÞíËŸ“¤÷y²$I–”ð>)Nr%´B:a+Îξv…”+ùn冔””÷Þ{Oì(®0kÖ¬ŠŠ ¿þ¤±±Ñ³¶Ã‚ãxcccff&¡‹ä„~å±s¼ë\cÉ [6ÍÁASS“Õê}•«ÕÚØØÈw’Ú/‚£¦LÔÔÔ8ï‚Àqœ¢(‡Ã‹…“%&f ס‘ÍäÂ… ìJ¥Z¾|ùáÇ—/_îÜžººšï¦ªÐÈfiréÒ%…B‘””´gÏžC‡-]ºôСC{öìIJJR(---|0%…F6K…B±yóææææ•+W:W®\ÙÜܼyóf…‚÷.§^:hÚ4‚’¶¶6¯é …bË–-[¶lá;€)VB‡«b¥`³çÊÐâ®íÙ?çK/tP2ÅJè~vBìæeÜ vW!‘I„R`Š•ÐÄÄp¶ú(C2ÜËØNQ`($A2%òêöNpÇqÜëˆ Q IÒf³q²ú(7UÇ)Š= %•Yd¸C22P%oØl¶ñ:Ìý…›¨*Ј  *Ј  *Ј  *Ј  *Ј  *Ј  *Ј  *Ј  *Ј  *Ј  *Ј âÿg3ü-¬ÕlÙIEND®B`‚puzzles-20170606.272beef/icons/signpost-48d8.png0000644000175000017500000000203613115373743020050 0ustar simonsimon‰PNG  IHDR00`Ü µgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<¨PLTE¤¤¤ª©§­­­¼¼¼ÐÐÐÍÍÍÏÏв²²ÇÈÄþþþÄÄÃäääÔÔ÷¾¾÷ººøóóüèèûÕÕú®®÷ìììääü°°÷ÜÜÜóóóÏÏøßßû¢žªÉÊÆz¼‘vÊuÈtÇ•qá’oÜ’qÚ“nâ˜uâ†gÈ|_¹lÓ‚dÊjÍlØ~a¼tY®{_·qWªwZ²o×€c¿nT¥pU§cL”fN™ÿÿÿB5kbKGD70¸¸GtIMEáûµËsIDATHÇÍ•k—› †Qñ²í²ÕÖm²J’jÔ×µÿÿ§•ñAÌéé—ž¾1‚ÀãÌ0€†ñÏ„æ;Z7ŽmXmjÚn›E,Y¶e9u-Çžì±Õqœ»mÓñ4ùÞ†%àéÓ.\>YQ `yŸ¿Ñ7åj-Ͱ ­)èuËÛ®ï›U¦Öœ‡lÈBWÛ5­X}›yP7ά JeiXJ@†øÝKùޘƑ9\ÆŸ4J®ÿOú ‰Õh|üX²%tEXtdate:create2017-06-06T01:31:31+01:00ê¼ð%tEXtdate:modify2017-06-06T01:31:31+01:00›BLIEND®B`‚puzzles-20170606.272beef/icons/signpost-48d4.png0000644000175000017500000000100313115373743020035 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA† 1è–_bKGDÿ‡Ì¿tIMEáûµË7IDATHÇ•V ºÃ ãè-7ã½ÖŸ‚$¶sûZE1$‚›9úðûÕWØçk Ìyƒ°»áWïÐ̃ÙѸô§YŒõeB#(&÷‹ër4 «#h Ø,K%ØA¥7ñ ‡ß¼ LÄq}úþIÆþßÂf´_ ""^Á‹Rê …¾ï_Ö/Y–%¥”R^“mYÐ6ÊhG“Íf³Ù¬¢¿DdÆ·oß’Éd"‘ИˆHûìc8|þ´Þt=Dhll¬P((¥ë—[úáÃÃÃéé鉉 "ºT’ˆhsó‹jx†Ñ Ãý>~ôvwîÞ5‡)E½=2Æô@ÏóVVV„œóÙÙÙ\.âGÈQ?ÐB˜Ô02b(EŸ?K"†xYƒê ¢a333Žã¼{÷nuu5—ËõÎt¤ßˆãã,î¿hçjgYÖû÷ï›ÍæÜÜ\@¦KY·i 8¿¬7H&“ÅbqdddooOkÁßè䄪UR ö÷Éu¡ŸTç¼V«•ËåX,¦”ÚÝݽ‚‚@©66D©É$þñ‡˜›ãSSœ.ôŒˆžç­¯¯çüÞ½{¶m_¡d!R‹†fÆÑ‰&ˆ;˜O«Æøøøãǃ®€& ¨@tVˆÈu]`Œ™¦šUëu¤@äº=`DMÙ c¬Z­¾zõJJ™Ë庥!4™†È9/—Ë?þ¼uë–¾Ó9ðÒ»=ém«·è…§aL'†s¾±±ñáÇ Op¾¸FÿNuÐØfÐdž¥É~rr†aÔëuÛ¶766ˆ¨X,v:é !,Ë £Ã’Ròîz¥‰R*•VVV‚EÇãœúô æç篘!D\]]-•J¦iê]¢\.?{öÌ÷ýååeÃèåG)TY£Ñ°~üø1;;Úúå"‹EÇqjµš®—âøøøÆ©TÊ÷ýcÇ™œœÌår“““###:¯±Xlyy9‡º¨~3¤”ŠÅbCæKïà¸b™q'–$¢Öì„„á|F·P(²Ì¸T‚Hù~CJáù EJ(ÑpkBzBº„ïHkÉ‹/¾ÿî8ÎÚÚÚÁÁAŸ‡"5><{|²ïzÇñXÒ42éüÐ`&“žÛÉzãà¤yÈUª[ Ù銋°ˆ­#“Éd2)eï*dJ)'–râ¿!IåÐHê")ɰ3w@é…Ö'×B¡Ð®Ô¡^³#[§—Š(Ùº@@"uZ ’¤rÎLP$‰¢%4"Cíj ¥ó{îaj}"Œ!oºµ·Š€ñ¤mÆ#™Ùäw=<×j58ê°mÛ²¬ JDç‡Ç»[{ë€0•¹50”Âëœç#clwwwuuU÷hàyÞâââõë×û`=Cfp P¯Îº‹R÷0½Öòù<"®­­Áe^·!"c&ç&"# `È87ˆˆ@‚fÛe3§ìN$úýKÿh|áž4,sÀõOÞqµ¾çù®3DDºB†tÉJ¥ÒÛ·oƒ¶ úqØÙÿ³Þ80cö¿þ,o$œ±kñßè¼PöÕSk4;;;oÞ¼ÑÇ™™™B¡àûþ…ì!R–Ë_¿›pF•’ºÐJÉ¡Á‰ÙÜ@ áò=u`®ëæóùB¡€ˆÍf³:£$É™9½½¹ýŸzó€Îè/Ù›ˆH$.*Y'[5£3™ÌÂÂB¹\.‹ºÑžŸŸ—ò´pX”! R’sszâΟ[ÿæÜœÎÜBD¥[ Ü%C:Únm¨R*“Éd³YÍ!òÜ› ¤¶å ˆ„a3¹ÛˆŒqT$‘1DúË9@J)Û²>Zßük.jÇ:óç»îð¯ðí¢ò‘n?Ú¶`† :£²Ñî¸ézªáöX8‘€Zm¿ íTˆFÓ¢ °Ó/Hç«ja™a\åçÓ£[ﱺœ­ 9ørÎŒN×Wô7Ú?î× ÿ͇·äêT%tEXtdate:create2017-06-06T01:31:31+01:00ê¼ð%tEXtdate:modify2017-06-06T01:31:31+01:00›BLIEND®B`‚puzzles-20170606.272beef/icons/signpost-32d8.png0000644000175000017500000000234413115373743020043 0ustar simonsimon‰PNG  IHDR D¤ŠÆgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<wPLTE¤¤¤¨¨¨¥§Ÿ¥¨ ¡¡¡ŸŸŸ   ¡š¯µµµÍÍÍÎÎËËËËÈÈȼ¼¼ÒÒÒÿÿÿììýóóÿÝÝÝâââéééôôôÄÄö¿¿÷üüüúúúëëëîîîèèûàààÖÕÖÜÜù»»øùùþ¹¹¹ÊÊøóó󬬬òòòååå÷÷÷ûûû±±±ØØØ´´´¿¿¿ãããâãÞßßßËËÌÏÏÊéëåäæàæèâÁÁ¾ ŸŸÐÑÍ•ƒ¹‘xÇ“{Ç’zÄ“zÆ’{Å’²¦§¡¤£¥’xÈ•nç‘oÙŒjÖ•pâ“ná“qÜ’nÞ‘j㎼ÀÀÀŠhÑu[®€b¾…hÅ–tÞ‹jÏrW©“qÛ’qÙœŽ»‘yÄtW²x\²a¾…fÆpU§†gÉuZ°ŒlÒl݃eÅnÖŠjÍ‚cÂÛÛÛ‘pØdL•mS£ììílÓnT¤eM˜…cÍÃÃÃx[³aJ‘`Çëêì{_·cL’kÙxYº}^ÀŽgáÏÏÏž¾¥§ ’ó”¨bKGD•² ,tIMEáûµËjIDAT8ËU“_Ò@Æ™ •cŽ«Û -£«Y`!V+sâ&V`“4­T¬è÷oýã{ßÝø|àØqß=ï³½w±—ß±¸]â(†K111ž@MLÂ Š‰Œ˜$©”Ä5•’e’&áL"I$„^¸H#1…ª™ÁLJ@½I‰f/QM×à£p™$sTQtè•ìàži…æåÐbÌ\-ÀTÇ¿Ëä®)”j#)\ÏÎDŠ¢Hi_k”ˆÜ®µ($£‘?è  s~J¾OÁkQU¡ƒ ~“l©ÂøÝæÐ1ÓÍ[²‘ `5#˲e©ñÀA£³ÖmË"Œ; ËH Œ„dÔhÚ0î` tЋEHB†0+iX"”šCŠr‰1Vfå¹i6§Ü½W™/WçA0Vîc Ù4M…)UzðжÙöãZ­f/ÚKõå ›y¦GÆÕ'+ÎjcÍuÏs×›ñ(ª¢a?hÙ~úì¹Ûjo¾XÝò½NH4#1(f­n¿Üé¾ÚÝs_ï»þ8RŽ¿l €îΛ·]ÿÝî¡Ï™=2¹CJxÇžïo9Ž ͰĈæmXö]Çs6÷‡ô ¦©š´ºèàøîfïÄ 2ÄİYôȰ„÷tp|¿ñ¡÷±½Öl|ÿпžëïöOZŸ†%°ÃŸèweÛ ¾|í÷{ßšõe¾£4ØE%aƒæ¿%@í?û­FçÜS¨hTµ×=Ï;øµ¾òûOã/:àÑãíü’…¥fÃéi§9xD‚Ó;^ŹÎÎê|}xþQË£‚ù6~Ô/ÖÙ2%tEXtdate:create2017-06-06T01:31:31+01:00ê¼ð%tEXtdate:modify2017-06-06T01:31:31+01:00›BLIEND®B`‚puzzles-20170606.272beef/icons/signpost-32d4.png0000644000175000017500000000075013115373743020036 0ustar simonsimon‰PNG  IHDR TgÇgAMA† 1è–_PLTEÀÀÀ€€€ÿÿÿÿÿÿ€€€€kÖbKGDf |dtIMEáûµËüIDAT(Ï=RAvÅ c÷Ðäïyž@o€ï÷í¦ûÞÿ$†$Dqg|3 +’ÄBXaZQð¶Œû„­¡µ\"’{­ÐFDÁš»dÅ»)‰¢<”5Å“¸@ì0‚nÄÚ‰ %åØk‰ý /Å(~Ù£ÐÓc/XE²YŒwúámÎXw?Öñ¬Bw=ÿ:…0K“½Ö/¹ÈÚõQýRæ‡B³ëÐ.k¤·óá’J¡×ÐyUO¿&Ó.ØNè²ÌÁ4Rªúº’ß6NísJ651ã ]¿÷I4ïô-g¢À,z3W㼊ŒëAÿ¤+휗?ž%tEXtdate:create2017-06-06T01:31:31+01:00ê¼ð%tEXtdate:modify2017-06-06T01:31:31+01:00›BLIEND®B`‚puzzles-20170606.272beef/icons/signpost-32d24.png0000644000175000017500000000305013115373743020114 0ustar simonsimon‰PNG  IHDR üí£gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEáûµË,IDATHÇV[oWž™sŽ/ǶÒà@œÆ¤²#¥(ÜõÞ ‚?Ê/è ©2¡ŠTAUÀNâ¤ëKb{mïî9Ó‡“¬—µ!kµúæú}3k|öì ""ÂUÆÌü,­C†a ËŸ™… µŽ^Î3³”Ò‚¥¾¼¼|ãÆ ÄcîÉèggg°´´Æ=ÊÌBÊÖñ‘ë¶¥” VVJ÷îÝk·M:M¹Üüˆxpp@Dkkk®ëær9Çqf‘Æ"z«u«u¢”"Û(k {{“·oÇFÏ3ë NçðððåË—ívÛN,nc D0…€jU)…Hó ˆˆ™———S©”ã8ÙlÖ¾Œ›qC‘6`00£øþòðk­ëõúÑÑ$6ù[6…B)e$ÓxÌLDÃá°^¯#¢ÖZ)õæÍ›D°ù ¬g£Ñøøñ£MðêÕ«J¥R(fiÔZ÷z=K€”Òó¼³³³¯dqÈ—f‹­Õjãñx2™ …»wïÚ=ˆOÀã8ΣGž>}zçÎÁ`°µµU­VÃ0œv0ÝºË…Š²noo§R©^¯·³³uf‘Ó‰òù<"f³ÙÛÛ··~ÞŠkWÚ+Öï÷›Í¦ïû³ìe2™R©Ôl6‰ÈuÛ*…Ž«ü HÈu¨‹?ä?+¥<¯/ˆ˜yÊ"NÛÛiÆÎˆŒ1DB¥ð÷ßÜpè“`d¾€! Úɇ"Wd¯‘ AZö …B©TÚßßWJU*)“äÛeÊèa ½ŠoεÑiå3kÖlŒ ‚CÆÎW{0–––šÍæîî.Ø>âf7…ú§GÝ¿ãIs>9 |}Þpÿ ÁC¡> ™’l›Èårˆ¸°°P«Õ4N×)ÔÁi÷³T’zýÖ¿ÝÏ¢+ ‘6Æ€@ž:^\S)e¿ßþü9"Úbç Él:ÏÀR¦2Å|®´-GÝ y£Þ¬‹ŒF,„ØÞÞ¶³*‹vèÑZEX*V M"\+®@Z9åû„4?­ÚqœjµÝÎh3 € b—Q0›±?@¤T*“LµÖ6b”æääÄ6§µ^Y¹›LŸiâ{ù#›Î×ÖaàdÑZÅGODƒÁàLjèûþãÇ¿J)™y†”BI@ ¥õô ΙZÜnÞ¼Y,Q)EhQ">Öó£Á¨ˆÆènÿø|è"à q<¿~ýºÝnçóyf6F#"@âš²@ٺǻDrŒþ9|j‘,pª"û !„ýB•Ëå‡~úô‰Ù’€Œ8½Ú üãõ[BÊV{_Pê§òýb¦lxÏöð½kº¶¶öäÉ“ÅÅE!Äææ&"Ÿ4XKRl Ú&`€ë…[ÚÙôb1SžŒ8m.?8vËNOOÞ½¯Ã0q#•RÑ)!Ä`p–+9F— n›À3¼—6BåÏÁ _œk×m·Z'³Ûÿ;m?™k°=Ÿ7+C 64å@J©”‚«Œ™9q%ð‚£ÿö­=HŠgS%tEXtdate:create2017-06-06T01:31:31+01:00ê¼ð%tEXtdate:modify2017-06-06T01:31:31+01:00›BLIEND®B`‚puzzles-20170606.272beef/icons/signpost-16d8.png0000644000175000017500000000160413115373743020043 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<}PLTE¤¤¤¡¡¡¡¡ŸŸŸŸ   ¢¢¢ÎÎÐÜÜæâââãããåååÙÙÙÔÔÔÚÚÚçççÐÐС¡ ããäÞÞÿùùþÿÿÿþþþðððìììÒÒÒôôôýýýááâ××þïïûÿÿýîîî×××òòòûûûáááââãûûüíííøøøããâüüüÊÊÊïïïêêêÃÃÄÛÛÛùùù¿¿¿»»»ñññæææÅÅÅÁÁÀ÷÷÷àààÞÞÞóóòíîíõõõééèÝÝÜÕÕÕéé阀ʒuÏ–zÒ“wÏ“xΖxÖ™…Â¥§¢þýþòñòˆmÀyZ¼…eʇfÍ€a‘ká—~Ë¥§¡ØØØsŇfÌmÑŒlщjË“oà—€Éííì–zÓ“oß“qÛ–sà…fÅ…dÍ›‚Τ¦ ÍÍΪªª—|ÒnÚ’qÙ‘o×pW¥tW²˜€ÉÆÆÆååäjß’nß‹hÔhN kM«”{Ȧ¨¢ØØ×™†Ãš‚Í’|À’zÆŒÁ¤¦¡žžž¥¦¢¦¨£ï½VbKGD’ßÉ5tIMEáûµËIDATÓOgSÂ@|çEM1õAÌYbˆ¢¢‚öB°b{oXQ»÷ËÎììîì Ê!J©ª%QVjTN>Í´¶®Ô d(Q MÍ- M¹Õ „ÐæB¶£¶tnë`2:± µHÔDŒEºã¨„ØÓÛ'%“ý*AI™–3˜´‡†ÓúÈ(2æd¢AߘœšÎÎÌòH<Œs8¿°¸´¼²šs¨yÃÛ±¶¾±¹µ]p½RÆéݽýƒÃ£ã"PCxr*ž_\^]ßü;0u›¿ËÞ?<>=¿”€h>ÉQb¯o¹ÂûÇçWÀï}ÿ~\·ø[*ÿœ*¹„¿âu%tEXtdate:create2017-06-06T01:31:31+01:00ê¼ð%tEXtdate:modify2017-06-06T01:31:31+01:00›BLIEND®B`‚puzzles-20170606.272beef/icons/signpost-16d4.png0000644000175000017500000000051013115373743020032 0ustar simonsimon‰PNG  IHDRíÝâRgAMA† 1è–_PLTEÀÀÀ€€€ÿÿÿÿÿÿ€€ÈŽíîbKGDf |dtIMEáûµË_IDAT׋ Ä0• é¼'èY¡û/S󡓸r¦Ùj´€‹& eÔIéT{aÇWvGbOå³và2­] ¼qÒ2õ¬<°™;îÉŸwt-WYYˆÀ¥– R¤¼h%tEXtdate:create2017-06-06T01:31:31+01:00ê¼ð%tEXtdate:modify2017-06-06T01:31:31+01:00›BLIEND®B`‚puzzles-20170606.272beef/icons/signpost-16d24.png0000644000175000017500000000230713115373743020122 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<©PLTE¤¤¤¡¡¡¡¡ŸŸŸŸŸŸŸŸŸŸŸŸŸ   ¡¡¡¢¢¢ŸŸŸŸŸŸŸŸŸŸŸŸ¡¡¡¤¤¤¡¡¡ÎÎÐÜÜæâââãããâââåååÙÙÙÔÔÔÚÚÚâââãããâââçççÐÐС¡ ŸŸŸããäÞÞÿùùþÿÿÿþþþðððìììÒÒÒôôôýýýãã㟟ŸŸŸŸááâ××þïïûÿÿýýýýîîîååå×××òòòþþþûûûáá៟ŸŸŸŸââãûûüîîîíííòòòìììþþþøøøýýýåå域ŸŸŸŸããâüüüÐÐÐÊÊÊïïïîîîÿÿÿêêêÊÊÊÃÃÄÛÛÛ¡¡¡ŸŸŸãããùùù¿¿¿»»»ãããñññæææÅÅÅÁÁÀÚÚÚ¡¡¡   ÙÙÙ÷÷÷îîîòòòàààÞÞÞæææáááóóòíîíõõõìììééèÝÝÜŸŸŸ¡¡¡ÕÕÕàààéééïïïðððôôôááᘀʒuÏ–zÒ“wÏ“xΖxÖ™…Â¥§¢ŸŸŸãããÛÛÛíííþýþòñòˆmÀyZ¼…eʇfÍ€a‘ká—~Ë¥§¡¡¡¡ÚÚÚØØØôôôþþþðððsŇfÌmÑŒlщjË“oà—€É¥§¡ŸŸŸãããýýýýýýñññõõõííì–zÓ“oß“qÛ–sà…fÅ…dÍ›‚Τ¦ âââûûûÍÍΪªªâââ—|ÒnÚ’qÙ‘o×pW¥tW²˜€É¥§¡ŸŸŸããã÷÷÷ÆÆÆØØØååä–xÖjß’nß‹hÔhN kM«”{Ȧ¨¢¡¡¡çççãããàààÙÙÙêêêØØ×™†Ã—~Ë—€Éš‚Í’|À’zÆŒÁ¤¦¡ŸŸŸŸŸŸ   ¡¡¡žžž   ¥¦¢¥§¡¥§¡¤¦ ¦¨£¦¨¢¤¦¡¤¤¤wã¿bKGD$´ù™tIMEáûµËIDATÓïþ  !"#$%$&'()$*$+,-./012$345678$9:;<$=$>?@A$B$CDEFGH$I$JKLM$NOPQRSTU$$VWXYZ$$[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ$„$…†‡ˆ‰Š‹ŒŽ‘$’$“”•–—˜™š›œ$žŸ ¡¢£¤¥¦§¨©ª «$¬$­®¯°±²³´µ¶·¸¹$$º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâOýhÖšKk%tEXtdate:create2017-06-06T01:31:31+01:00ê¼ð%tEXtdate:modify2017-06-06T01:31:31+01:00›BLIEND®B`‚puzzles-20170606.272beef/icons/samegame-web.png0000644000175000017500000001253013115373722020044 0ustar simonsimon‰PNG  IHDR––³cæµgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEá‘ëb\IDATxÚí]yŒdG}þ¾_½î×sîÎÎöz½c;æŒÍ)LŒBb d"EŒ‚(2`Å@H'Q8,ËqC¬M”ˆ¶‰°Ã†Ø2çJ˜Mìå°ÍÚëY›í{ºûUÕ/¼žcgº^÷\;ûfß§Qkf^uÕ{õ½:~gqxxò Ùè(°ZD‹þVÕ¾¥m@ráŸÑ¢kQ-*Q`)œ:U%2:JA WUdt©*I5bÕ3sø(”¤@¬µ ÿ?O!IkmµZµÖ,† P‚ýå~¡(Útù¸t}=  cn#ÕûÒäTÔ«™½NÐzÛ`c```ádÙ¤PU£(ªV«?øÁvíÚåœÛè¾:CAÒy÷í#ßž±3ÂŒ„BÌ«v¾tðÀýÎ62†„zo*]¿þÝߺûÉïfB_aåº+¯3b›ÌÕÉtGªªårùèÑ£G½âŠ+jµZ1—B¡†fÆÎyâäÂb‹×Bç\­V«×ë…K¡ªFLÝÖ…ãÕ/-FRá„&IñEBªsi$ Äõ [î(…âé[Žû¨UµMlty`³s<<×z* H8/½RÀ;€síÄ´ÝE(äÂÜ£ 0÷((Ì= s‚ÂÜ£ 0÷((Ì=¢ÕWqÂЀ04-åB’ÎМɺ pùP¸)‡I8ã2l°N=°þ4.‘ß¿ìwÆ#‘”Z*ÃH¨÷Œ+=qÞ/¿å¡ p¹ð¢åË~¹zZŒ ‘¼¢Âò¶Ád½ÇaAá2  X‹|H«U ™Ò²ó·oÇ…tgӂ•ÀŒ"ÕVVZR½ƒ‰NÃ:® ΀µ ŒBP‹Óã†TÈ…¹GAaîQP˜{æ…¹GAaîQP˜{rẂˆŒBhZ%5Ih"‚ddć\÷Izñ†fé¥ÍOaÿж˜ãm{Uªªµè$vHgë<<œ¶üŽ’ ˆ³êU'¬µY®ÀHà*-¼ì79… ˆJ¦”Í"Éñúx÷`-Š˜M1˜ž¦t°þÐcÛžÞþzOÄZ¿TgѳµoëÎk^q½Q´öÊ'ØðÝ=»–ú÷nf Z–ò§øô£cÆ&0‚5W{ËoþÉ/¾àÈp#.33ˆI‚ÉɶêOªÅG>¹»è_m%ìUMx‡J/Þ=ó³ÛîP­É&ÑH°s ñ¢fhÎÜ•MM¡jÉ”n;tÛÁÇJ,-篻Wî}ùWþýò*‰H‡6¾ìñªŠ}·váÉ™„ªöî0ï¸ônù;¯a͸¼çÐÞu2â 7!¦bЃR¹ä´u¸–¡©Gad ŠÔû6ƒìÔ¿ ¢Ù{~Rm‚(IDo‚VD F-øÚìN<Ÿ„F¡§ÂC¡)1Ör­,ím™&©i1UX…†¿ Â@…\˜{æ…¹GAaîQP˜{æ…¹Çæ— %Éíűc—Ac°VyHµ‰FA""¼A!Ú/á¦ÆÄ™¢}¶Ñ©Ë s:þ%»$ÙT)¨*¬zµY 6´í73…$.yëK_ÿª¾06±è4…¬ÙÚ .Þí€lÇëÔ}ûÚkgžuAli3ncÉt²¥‹dPK:«æŽÏÄ_þµ´WsooÞÏ57”Œcw¾§úËr\A`B!>ܨÿê H¦òZ^ÃÉ{xã±êx9Š‚&$õR*ð×ïüøç´6E1Æ&Îl=ÔuÝ{^y²c“ù±hÎß̪¢á«wèÁƒ*â3•× ”›^ØšUÀñª~ñ§·?þÔ –Z§ùÆñ›¢?Úù¹¯»éq „_(©ªÑÀŽ‰×¿nÿ=Ÿ‚m—ýiçÐ-/zÿ¢K›™ÂÆ`I[ûƒsmìG0F£>ƒiD¥(dƒTï¥E% Š„cZ#5I`" Ù—éx‘xÓsv:^8`MíH­ «6è à¡ÞjÚ°ߎ¦ ÞY…ªZë3/¦B( iDrZ*ç@’èˆöT€Îgy÷.†µª  (ÒÄÎv6¦"3½:°•³ÎRFï~'ŸF©,ksŽÇ³.è·µ3Sp½=øøRŸ ˜€–Æ{Ä=ƒ;öþÍ|BÂÚ‚‰·Û»HžEù Š¯Ú{Ã϶þo—éòkÁ!‰»~¨ÕÉqH›Ã‘"úѤûµßïØ´Ã…ÎjÏ?õ¼C{Ó½Í˜Š–%…¨7pÞîÆ§ßx9ä«jdÌ=‡~tðHVLÅ2+" n—ÑIAARÇwöc|Ú‘ %RÕÞ‘}í¾¹?;¦B½—¡!è-‹®lf @aº zÅ‘ókvNȇc)Œ ÆH`)„µÞ„A›˜ ïiÎNKEjUðvmFár[w2c‘Í«P…2ÞŒt»ÂR±QP˜{æ…¹GAaîQP˜{æ›_.ì†f lôÐH`Ô4ôÒb¤&Í˜Š•·Õ‚Bïá}›ÈrÍBCVUÕvæ¯Þ«ïШàå±;0TxXçá¼µ€Ò9D{"MÓ° 3Ê)ª"ŠÐ×§Q¤Ù ŽœÃ÷«ÐJT1!õÿ\7ªï-÷Š€Œ÷à@üþ÷o¯Tê!ßgc0>./{Yýæ›ÇÆÆpS^G8u[Ê[Þwßû<~ ¿ÜŸ¥®TˆÈƒ'D„ íAx¼ú«î¼ùꃹžn*KjÃò³ÿ0ñì¾Y?Á¸”müµÉ§žÝgÁ6ÃV)îÉÚŠ;ä”Qh FFäÐ!ˆ”¼oý2ç°w¯5f½`=1Œ˜‡«~ì°©˜öç 2fÝôÂD2~ïAþˆ Îbà¦&!hG!¨úÇ~õÃO¶ÉþW˜\4rä§O{2H¡ª6Lr¼úè#‡ÔíÉ©Q³´cziW®ÂNÂtY^@åZC(@Â3¾ŠÐ»eÙÍX&bH)xÆ“÷*± 2Ò´~)tÎS€H$†wÂŒ^Æ3nqy…v²MƧÎÛÔ•a€@hö ?>€‡Ƨ)¼*ÐŒKõ>+¦Â{hzªL¶åL[‡ÃraîQP˜{æ…¹GAaîQP˜{lz gš ɆK~Ym“Ë«ˆ«k9Ï1 ¦®­¯ÎyÚQçʶO­TÃ5­Ê´`¸Âfj˜fÆûÐ]r^p¦6‹ܾßèrK¡¦®©Pˆ4{šð!eÄ| €Ð …hAjVëÔfµMH°N6oŠô'CU@Ô)ù£P(“Éä—}è—¼7“qȲõv¨÷Âá?ËOŒ!CQKÂ:óÌ ¿øÉcÓ“.[£«Êg<·žóµZ’aK…B„oÛþß¶Ù©ùå’\¼ãÜ{®¾#C5CÐy×ÓÕ+”ÜgòŽÝ}Égÿü9ߺ³²%h~hª«ëN“2˜&_ ©EÇ'xÛ¾ÑÏÖ®üñã?ï)w­¯J‹Ú¿œ{Çßô»¿ÖJøìm¯Z)ñ ûÿÅ‘+G§j‘ î9œKú¶œsWù3W^óN¥® BÌÔð5îýÎfÈþ$‚ꨞœÂxÍ»6!é@ɲX¦†Š¤Žc'G«ONÄ3!31• ­'öØq7‚ô°óå÷Æ‚—SÓ3‰|2Žq©X &11i“¤£œÃêKZ1 Ç'LbÜ×CI Å7àœGmRÕéôx˜BRU½›œJf&P+Õ3b*+ÞéÄ4¦jž”pL…ç´YÅR¸t;CÀ€ÂW…0 YÆ®u=ö·‡^* ›O”±ƒ4龑Í`ÉÙm‡̬²U1嬥‚dîàå¥-«¦­®¼+‚;ÒàqßÍýÖÚw÷zaÎþ|Õg¯d €E=¬SW™Ù \݆´íó‚ÂÜ£ 0÷((Ì= s‚ÂÜ£µPA†åBÎù™o:iÔ´ I0ó‰šöΛÚÊ…s_ ÓfcËÎ ½øÃÏÜ‘›*a¹Ð+,Ôn¤´§MO¯,õ^Sý¯ª6½á°a ÛðôÈŸOà›zÙ‡|¡Ñ2$âæÍf¤€RU ¥Žg…„ªÆå¨oÐô ×¡µþш©–Ƕ TJ¥ ã°k¹^$C"Ž"ŽVÕô—+ÝÛ±­§¯«/”ˆÝÐŒ5ÆMTƶnö‰t÷¶V°¥#µ‘°dz¶ N5ÆJ¥Š¶RCtª]±P:͵Cc00Èæ)¢-uqÂÚ ¶ ¶¸2<< @UK¥òSO>qð'Ÿ;ô"g¡É„@bu×óåÞñŸÈ²T¬Òæ>pãÔ»¯ùù‰G§¢rF¤Ô£» NÚfBøð±ÞU.xú±£q}2ÉP›¥VÀ=O/ë±Ã®Þ`øø ï5Žq²çÒ¿dO­†Pæ–ôÿýý¸ÿ{G&kZË … ÷®»«÷’g^^­VêëX*ȼ9~6â á=kš]¼ZUMÏÆèXõIM×We` @º`»ìµpaùU*Ï×sñ’ÜbG1ó¿túàYåVñŠMS ‚ka°É¥by7oè’_ÚlWnÙÝ×ÞžF!Úç…¹GAaîQP˜{æ…¹Gk¡¢C_éÓôÆRDóïÕ @ÂÔg> ÏxvN¸¸e´îB¢Ž2~p©#9 €§˜³·,½4Oaš…(-”•BwCὦýM?<×àF›ÚOíìüB?WÂû¬È{߬SCÆT#ê•êÕ'PçCÝBAM2µ3$­ÕR)Ù¹==g(…QÄêS:Ðì8‡[¶qp+Úe-i Š`b"êé=o7f†QéÉМ£nÑÝSÆžó™t¡RÊ…‰»ã½ç£6´Xh$ñòòòòòòòòòòòòòòòòòòöëM¾¿êM?ŸÕ›7™Wµòÿ=Çý¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼ãxリ¯µây§ó¶ÎÿñºtÞÙ}âååååååååååååååååååí×;«ûÞI’$²'Ûšf8€7€%tEXtdate:create2017-06-06T01:31:30+01:00Lh·D%tEXtdate:modify2017-06-06T01:31:30+01:00=5øIEND®B`‚puzzles-20170606.272beef/icons/samegame-ibase.png0000644000175000017500000000324313115373742020355 0ustar simonsimon‰PNG  IHDR^^BIàMbKGDÿÿÿ ½§“XIDATxœíÝÁqI€áa :|&Œuä¡@ȈV”ö0{qÕ¿Uš…¶%ø¾óдǪ_¯|yïæœÀK½õ€{$ @ H¤Òi‚4A€ @ H¤ïoôÛ·o?~üXw`©OŸ>===Ýøð©Aàq}øðáóçÏ·?`jØ}ùòåè?W3ÎcÑÉóynÛv«Î¿Ì¹­¼ÿ÷¿¿1.—ËÏû[üÆÁ¨I¤Òi‚4A€ @ H¤Òi‚4A€ @ H¤Òi‚4A€ @ H¤ÒiÂáMÙpÏö}ÖüçeÛ¶ÓXõþ·ëõÐ㦠H¤Òi‚4A€ @ H¤Òi‚4A€ @ H¤Òi‚4A€ @ H¤Òi‚MÙ¼°ï³~Dû¦éGw™«ÞÿÑ=ߦ ˜xaŒ£ß.÷eœÇ¢“÷yê4V¿Ï ëîýz=ô¼©Òi‚4A€ @ H¤Òi‚4A€ @ H¤Òi‚4A€ @ H¤Òi‚4A€`S6/Ìyyë+ܵ}Ÿõ:û>î{`j‚©Æy¼õîÚ§E'ïóÚi,{ÿ×ë¡ÇM @ H¤Òi‚4A€ @ H¤Òi‚4A€ @ H¤Òi‚4A€ @ H¤Ò›²y%óy¾õ~}ŸõŸÀÔ„ÃSç÷Øþ¤ÿŒqo}…Ÿ²úósý~Òi‚4A€ @ H¤Òi‚4A€ @ H¤Òi‚4A€ @ H¤Òi‚4A€pxS6¿«ù<ßú ¿Àeþ?Å G7”›€pGSÃG»vÌœ—¥çÿNc,:ùu¾ÏÇyÕý÷©jݧtÿ|®»ÿõëõÐó¦ H¤Òi‚4A€ @ H¤Òi‚4A€ @ H¤Òi‚4A€ @ H¤ÒiÂmÊæû¾æuVï³^½¯|õûyôûßÎÔSÃãôÖWøŸöïÛq«ÎžÛÊ÷ó:÷?Uço×ë¡ÇM @ H¤Òi‚4A€ @ H¤Òi‚4A€ @ H¤Òi‚4A€ @ H¤҄Û²÷}Áë<î&èG·ú7ûïÿò<מ¿ø§X}ÿûajÂá©aœÇŠ{lë{l¹Åêßïi¬:ÿ2ç¶þþë>E¯3µÝÎÔi‚4A€ @ H¤Òi‚4A€ @ H¤Òi‚4A€ @ H¤Òi‚4A€ @8¼){õ>kþËëlR^ýûÝ÷Y¯óèŸÏuïçè†oSO c­¿ÒiŒ·¾Âÿ´®ûüìSÕº÷³zÞÙóªû_¿^=oj‚4A€ @ H¤Òi‚4A€ @ H¤Òi‚4A€ @ H¤Òi‚4A€ @ Û”ýþýûïßçxØeÍî´mÛv=¶ïø~ì²W^íûyûÝg½Î4|üøñééIàA]„íÝœsÝU€åo @ H¤Òi‚4A€ @ H¤Ò„×Ú«)î¼IEND®B`‚puzzles-20170606.272beef/icons/samegame-base.png0000644000175000017500000000324313115373722020202 0ustar simonsimon‰PNG  IHDR^^BIàMbKGDÿÿÿ ½§“XIDATxœíÝÁqI€áa :|&Œuä¡@ȈV”ö0{qÕ¿Uš…¶%ø¾óдǪ_¯|yïæœÀK½õ€{$ @ H¤Òi‚4A€ @ H¤ïoôÛ·o?~üXw`©OŸ>===Ýøð©Aàq}øðáóçÏ·?`jØ}ùòåè?W3ÎcÑÉóynÛv«Î¿Ì¹­¼ÿ÷¿¿1.—ËÏû[üÆÁ¨I¤Òi‚4A€ @ H¤Òi‚4A€ @ H¤Òi‚4A€ @ H¤ÒiÂáMÙpÏö}ÖüçeÛ¶ÓXõþ·ëõÐ㦠H¤Òi‚4A€ @ H¤Òi‚4A€ @ H¤Òi‚4A€ @ H¤Òi‚MÙ¼°ï³~Dû¦éGw™«ÞÿÑ=ߦ ˜xaŒ£ß.÷eœÇ¢“÷yê4V¿Ï ëîýz=ô¼©Òi‚4A€ @ H¤Òi‚4A€ @ H¤Òi‚4A€ @ H¤Òi‚4A€`S6/Ìyyë+ܵ}Ÿõ:û>î{`j‚©Æy¼õîÚ§E'ïóÚi,{ÿ×ë¡ÇM @ H¤Òi‚4A€ @ H¤Òi‚4A€ @ H¤Òi‚4A€ @ H¤Ò›²y%óy¾õ~}ŸõŸÀÔ„ÃSç÷Øþ¤ÿŒqo}…Ÿ²úósý~Òi‚4A€ @ H¤Òi‚4A€ @ H¤Òi‚4A€ @ H¤Òi‚4A€pxS6¿«ù<ßú ¿Àeþ?Å G7”›€pGSÃG»vÌœ—¥çÿNc,:ùu¾ÏÇyÕý÷©jݧtÿ|®»ÿõëõÐó¦ H¤Òi‚4A€ @ H¤Òi‚4A€ @ H¤Òi‚4A€ @ H¤ÒiÂmÊæû¾æuVï³^½¯|õûyôûßÎÔSÃãôÖWøŸöïÛq«ÎžÛÊ÷ó:÷?Uço×ë¡ÇM @ H¤Òi‚4A€ @ H¤Òi‚4A€ @ H¤Òi‚4A€ @ H¤҄Û²÷}Áë<î&èG·ú7ûïÿò<מ¿ø§X}ÿûajÂá©aœÇŠ{lë{l¹Åêßïi¬:ÿ2ç¶þþë>E¯3µÝÎÔi‚4A€ @ H¤Òi‚4A€ @ H¤Òi‚4A€ @ H¤Òi‚4A€ @8¼){õ>kþËëlR^ýûÝ÷Y¯óèŸÏuïçè†oSO c­¿ÒiŒ·¾Âÿ´®ûüìSÕº÷³zÞÙóªû_¿^=oj‚4A€ @ H¤Òi‚4A€ @ H¤Òi‚4A€ @ H¤Òi‚4A€ @ Û”ýþýûïßçxØeÍî´mÛv=¶ïø~ì²W^íûyûÝg½Î4|üøñééIàA]„íÝœsÝU€åo @ H¤Òi‚4A€ @ H¤Ò„×Ú«)î¼IEND®B`‚puzzles-20170606.272beef/icons/samegame-48d8.png0000644000175000017500000000337613115373742017770 0ustar simonsimon‰PNG  IHDR00`Ü µgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<ÚPLTEæææçèçèççææèéééÞÞçååÜÛÛÛÜååÎÎÎר×<–>,‹$ † M”Gí=@ì$$ßLH@—;W¡W|2Œ)þþï/*Žvñíñü#ï0*<œ;5›.ŽC›9BEë%*ï&*õPLæÿ‘ýÿ,&ôý !þ2)òééæññèÿ9.ÿôE;+ž7M©RMšK)’)L¡MIHø**ú þ4)ï þXIèô)&ò"ó^Zèññ$%%Œ+ý<<""üAœCÿICñÿ64þSS"$õ"ö=Dö#&êLL+Œ*!Œ\¨X!ð.)<>öÿBDôïIC1ž:S©U%%)Ž1A<ûRGìøXWD›J55ýA@ûü>6ú$%)*ìö??þ××èùA<ø('ÿòCJ<;ýFJï:ž4'‹0CIðŒ+GšR<@øHOê83ÿþ58)-òGJáR—N+0ïK>ð0‹&H”PODìLšBRšGïCNï$/ò%/êJQQ—Pï+'ÿ 1:ýÿ+0ð/Ÿ/ ‹ò'0WWëSUüøWY\\ôôY`NRÿQ©K5œ4h³hÿÿÿ LWUbKGD»ò±tIMEጲû!IDATHÇu•_ÓFÇóri”͹íÚbKW©˜`)ƒ!Ý„ŒÙÐTjiV¶QØŒºVeN'º¹W7·9Ýëës—K.©ø|Òæ¸Þ÷žßór‡ €‰ô!&Éð%K‚,p“„CM”#!2FˆÍWð$#j’_lŒdI$cÆ‹‚ÄQ …ÃJ,Ä>t¬Ð±"ŠÐ××§HŠçJy)ÜÿBˆ ¾üÊ‘#¯ ¾æ* ÷£CM„Åx(¿žHâ‹ Ô/òðä@^$%šÄCÃñø±hgRN<8ÑHð’er2’}#G=` .àO\ ›ÇGó'Æ8™f€è’¿T.&BBTM?’Nâ $×POÁ”‚¦M€‡c ‰-CЈÖ•DÒT”&Eð0ñæØÔô[‰™ÓÈÉ ‡‘»7GfK¥·ß93qFÓ´¹ùyýÝé…÷Ζ{ƒæZ``¼¨kžYäaăps€ar`žåž ¼0,“ÍV˜ÓuÕT ç–j±©óLÒ¤¿ž¨¥z>?§iùª±<Û°†ßÏ4W>`õ ðÍ)Çää?ĸ •þ(“=•}q‹`(ˆÁÖð$­ª¦nš­µuœ.Ub±?‰Î\@=G²º\²mÛH§ñÅKº~¹bÅ> Ö·8@Z©¥Óé¦ÊÓÊ΃¿ Lš Ka9 ɦΠWv¬ß;ß»_+åç<…"yòì,‹@eÀ0¿ÄÐWõý}8ŽêuA¡wËÜþ~ýF.™…8îTo}Ýõ7ßÑlv䀸P·è°™ÉÎäîv»›7I­­{þnî'qö@ ˜i8©]XvêÀÏiè&ND ÐÐQ Qùfo¯:ÊÃÕ8þíƒÈýï¾ÿáÇŸD"?ÓžeAË¡{ Û¿ûÆ/ccÝØTã×GVkÝn~üí÷ħ=àš··l;íl±ö~ -rÀZCô÷’çÁb,‡8«H&¼æû³³»{i׵Γ§µF¥Ò¨=}Òéüu¾Rûûxÿ›ùïï®(NRCÎk²XFejd޼É)”Jõ\./´Pð:ÄÄžiç_.9ßòó›=˸÷z)i\í%tEXtdate:create2017-06-06T01:31:30+01:00Lh·D%tEXtdate:modify2017-06-06T01:31:30+01:00=5øIEND®B`‚puzzles-20170606.272beef/icons/samegame-48d4.png0000644000175000017500000000143613115373742017757 0ustar simonsimon‰PNG  IHDR00¥,ä´gAMA† 1è–_'PLTEÿÿÿÀÀÀ€€€€ÿÿ€€€€ÿ€€ÿÿÿÿÿÿcóc9bKGDˆHtIMEጲû IDAT8Ëu“Í®Ó0…íTºtéF²LmGµ Ȩ-ËÍ‚u»`{ÕŠŸåÕíÄ”bX²ä1Ð}@f쟋UQå¯çŒçL*D,%…¢ÌÄP2S™T¥¤'a™Íj@ke'è"ƒñ¯È`Z( õ6 ,ÆÇ|…ã’A´’©Cê1~l5t’áŠø!9QQÈÄT$Cø÷Vú¸pEðÅÑÚ¥ >‡XO±q—¢Š÷T8¯{ÅnèLÔ¬HQ¸ö—µw“¬ØÈok‹æ<½»|ãyùxا9ä° ׯœî‰TCû\룆Z/›¦y”0Àµå9vÏ¢#nê4ù¸¢€ÁN7h` :þH!Î}Ûu?ÊêÒ Ò‡B mjpC.kZŒµãu ö'E¸ !ÑNqGVAH›½.‚¶úwn5[…¨‘l]¸òu9«ŒŠï& œnIAk”@‹xGéN@ìAÀ%P™°Õ"´ÚçÕÒÕ}cð1uþ…פ9XšchÎ_¾À›p=CФ#ÅÖ˜_55_(Q¥Ï÷η•f«Yý1tå`±Y×¼ÁRÌøz]«´ARÀûœYû¤È6½âûicñž­ìÅ®»7ÜÛÜZ½|ié2ÏV*MÎuá5¸ð‘=oÓQ‘À…A"W\ýÑÐ2¸sŠ<¸Üù·¶yî¼¶{aŒÿ«?Éqã(Bq»í%tEXtdate:create2017-06-06T01:31:30+01:00Lh·D%tEXtdate:modify2017-06-06T01:31:30+01:00=5øIEND®B`‚puzzles-20170606.272beef/icons/samegame-48d24.png0000644000175000017500000000504313115373742020037 0ustar simonsimon‰PNG  IHDR00Ø`nÐgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEጲû 'IDATXÃÍY[[W]ëÛÇc{ÆãI'“I2ž›ç’”„4”B«èJ…H Ô‡¨ÊSß?€ŸÀR‘ZP¥ª¢——> •ŠTUj“V3™‰ÇžKœ{ÆŽ}Ž}öþx8¾&3Ó&ûÉ>ÞÛgù[k¯oíc®¯¯ãÿiÈs=àöÀëC'GOUJ€ ¨‚©„ª$¨Ú…Õ¨V«õ~v$#nâB`Õú €Ö&B€BÀªeŒ$û‰H­V+—Ë©TÊ9w… ¤éš—ÿzy£ºa©ç‡æ_}3°›ϺÝs‹?ú^mgo3°G2¼ôÝ—jÍZ„»[!UM¥R£££avðþ/L ¥a+õ•µÊˆ´ñFWjšÏá%¿ZÜ[ƒEæDƃæ~”9çÂ0´Ö YJµÖª¶„«ª (@@I´Èé]åÝö-QmŽ BP$Oß7j½jH=9tÜzô½têÔEóúâý7»»A@ἡ·þ–*0„œ«BúÌe÷ „*—®¤óy m a‡² „ #ÔgqJmé&’Qh›U !`álŸÑ ˜Ä¶I“„TÑ2E@AdƆ°NNß—&Õ·Áñ‘“ãÿ2.ÿéòµÝRç†ío­^7ñ¸sŽ[[­MôéêЃ³ï1­5ß?¸’2¢Öq8ÙLT–âù"==UíÙÔG'j Q{€8À9 +Û–ž¢«íK½ãErÎŒœªkD&}2§†ŒÅtz’i–AÕlj Ae’.Ɇ“§q/4{ó±%“Hè†c¡Õ€ÙyâgßÏ• !õâðâ[¯v}Íнä™o=ŸÚ.ïÖ=6ãý2D•­2…†U¬.'®_óDàH£Ö‚¢«{Ÿ®–ò F•‰•ºrFÌ'{•b)‹Ó£k¼'ê%QÑãCÜ7lÝvŽBC ““Z¯i2©Qx¡hP7™ ½ÖnUŽŠéI'ÖX§™‰Écõ$°Á©ôÄ=ñ!sé9S^6&Á6‚$¸·¾·ECµÚ`üió÷œ Cz¹Ý½ú\³à1°ø¦”ñ¡ÏùÐõÝ•µí‰‰S×Þ× †BcBeyÅË ÀCÆTV$ò¡µ<щÏ=¢P @ŒÀP¡¶›(œU»£gµ-=<Ez¼{LÚ²8bÕpÀ LL÷ÊU uwkz8ãÏ8ñ¦‹e2!®´›œÛ/©"×_<öÉ'ãÆ„ããî7vÕÚÁ‘¼ô;W“^ÒÁåör0„Õ™‘ìÄ;®¬ˆÏ/Ö×|+k¤^ÎÀ@,;lî02‰þÑD¢P0kk¼Zí³“>ÁµòZþf^bâàÄУ ’»îår`$!^#‡µ<(ÝìÑbŠ0†ÎFY§¤Fù!r¹ƒ”NˆAbg¶´â:èêéTtGØÎ£µC„!¤Ý,÷*ÖÙ˜‰eGf¶ž™^rÝ ÔÈÎ* âqªªJ$-JT*˜šüŒ^FêÎŽ<óÌ c4˜ÉØ·ßÞI$СN§G¦>|g"¶´ h°àîoO O_²«%UVÏÅÿÍïsyë¬9wq÷Ö¿/ß ¬{|Úýúð^FÂZär&"«Óö›Ù)H>ÏB“)iSj¡´VØÎƒ¶ãõ pl •r.¿]DˆÍcë½Ôx˜ï0uˆÔ:XÀBûuà:”Eá§C`ÏÒNo¶ŽHÎ8Ø»:“^BGÊìp¶>Ïy€kÎ.dዜÌdÍôÚ”2œMÏû  Õz3Ùf3=—r# ëg‡§Žª—ióµwü½dKçõë<¸ôD£¼ªtÍô…æ+i\Wul^¨6_x´YÚhŠó†Î½ûuÓgÐÐÇÃß9 —EáWDÛeoß¹'NôLÆú6o moyÍH¶¼YØÞ²[u6`xLë¥üö&ˆÍæq¬W°‘€­{™jdåìEÀs»žDZ?€T’ªìSFW:ÝŸÐwIIe¿ƒ" ç8­ÕÃz"¼¾=[=sË$:ÉÎ×ýáóáXStzhîß-M»}ŠT„ñà?ñý+ g¦gñÞGŒP´X4O=5¶ï^+ ©ªœš²'~úÌRùS6ÒgÞ}EäZ ªõsÕ'_x²^^u ýÔCþ¯þ\ËkÓ1øÒ.¼Å}…ÙéeJrkwg³²…)ת½µØÜ4û.ª - ]ß)nìì8抺iõÆw#½^j¬oß1n×7±¾¥·ÆôîâG›u¶õÑ!tßáÚgx§„t%ÒûõÔÓ+£5Ç‚NíÌÐÙ† ˆJ&u|Ëu«²¯ÅãúåùŠÀd³M ΦB(°0<¿7‡—E{ µ7Æ”áÜÐìûÚ– ¥vn±12Іof¹Ÿ^PûíË{%“º¤Üº ôoþ^¦œòtFÿyüÙ«irW~> bèׂ³þ£üÃJEð@µþ—ŸÐ•*5¬Þ_[l“S÷ðØó·r¥J`ý§¦k¯‡hÞÖË¢SÜÑb ²«ÎA„f倄 !„Û(¡XQÞŠ²ŽR¨N‹›%«å-XQ46ôæ½yÃt¶Ývi½´]„EùØÛÏeª­G'‘E„Ð"ã°4½ÂëêP{¯i÷Uçá¥sˆš Bô?Ñ‹eË]xñ"†‡‘HèáqQ¨AS3 ù*FÓO´¬Z„ìÂלžW§<;G ¿®§&©VæÏ?àÆ„:ËÅs¦6ýðä±RÓ&.ôÆSvþëPÕdR?ãpW«6áÅuî‘Ök¶¨Y¦‚Q'W{¤.ÀŽÖk8Þxâä)ÍË\ž  !– ¾Ü ç&áo jlöÙðû§uª¥5Ô&!(~&[!œ9ëóùÚ¡sç/\¼tY4ÁY@ ‚„{éÐuÝét†ê “<(ÃOštv9º»::ªz®\zý×4¾CbïËŒvë5Íîë7¬Öþþ˜A q6Ð4|²: €/Ànªˆ˜QBb‘[ef,„îáÛ#@»“LŽI(/Å °T 9Žè]5y5…Ãã,X0ÑæJ©„¨ÑCÃM%Ì‹6Töt>4ËØBhqIµ)‚¡À˜·$‘H”N 4³Yžö³ˆ7•Jyƒ,X¿<òìù‹— µu㯠l¦¨þÚͶŒêÃ15w"\Ç<é~Þè5SŒñ.q{VÞNd·ÄÞ-οgîêGìIòéóPúuOÅ—ê¥Õ¯½ß¾¯Žþ`Sk=k¸ÍÎ8Z7ILr(WÕŸƒ£UÁVš‹ D üZß°Ù6ÖV~onþùûo-Úg⯥!j.ÅÐÍå5þ ~ã„?‰1 ø1ú˜Sú´x%tEXtdate:create2017-06-06T01:31:30+01:00Lh·D%tEXtdate:modify2017-06-06T01:31:30+01:00=5øIEND®B`‚puzzles-20170606.272beef/icons/samegame-32d4.png0000644000175000017500000000113613115373743017746 0ustar simonsimon‰PNG  IHDR TgÇgAMA† 1è–_'PLTEÿÿÿÀÀÀ€€€ÿ€€€€€ÿÿÿÿÿÿ€€ÿÿ¹¬¦®bKGDˆHtIMEáûµË`IDAT(Ï%QÁJÃ@­Ø^7…âU¦ÆÒ[ ½xS˜PðÒ•EôP‚ ½UèvèÝP,ý„þ¦oÖI6ì¼7ï턜#(œmÈä°÷Èò"ô-yKq@äøFêkT€‚ uÝ{ÃŒë2¿”"§Xät'| NÀt÷Ø­MÊD}ý¡Y›J^l@’‡LÁSÌcÒ¤>}!„ó:H¿&S4%ÔóoÃU5ßQ•CÓUTÀŒR·)ûSnj°Û3ó,Ik†2…§ó>**FÉl:Ž)ˆ b¤àæ“"GÅ•¢ù>& O.U?Ÿ°,µŽZW¨ÐÖÑx¬ŸÖ€­wÃ2œÓKL}e”­÷#Õë¾4Yô ö¥¦˜(¸¾‡c\Q1¼UÅÅÒ&†c¬9x!<3ëã2Z»Ð@%dcˆÈYåYûìãX*Þé7ncŠ“&¼¦æ-u-Ù”ó”ìgaT‹cl!F;Ì%tEXtdate:create2017-06-06T01:31:30+01:00Lh·D%tEXtdate:modify2017-06-06T01:31:30+01:00=5øIEND®B`‚puzzles-20170606.272beef/icons/samegame-32d24.png0000644000175000017500000000361713115373742020035 0ustar simonsimon‰PNG  IHDR üí£gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEጲû“IDATHÇV[ŒUgþÖúÿ½÷ìs3s˜9s S`¢Ø@5M* ¦‰41h¼Ôx‰ò@H‘Älꃱ4šFÒÄFíKŒ‰ ÒjŶ‰Jô†¡…¶ÌLÏasfÎefßþùpf†)-ú?í½³÷úöú¾õ­µ¨R©`f|¨#ÐÍ'K"tû&!¢»‹.ÂÄŠ A˜ ¢-$å(š™ƒ hµZ¾ïcî<º›órÇÇŽÿèµrWñw§{>óâÅ Ô³gOæTôƶÞŽìþCœÄºý#¾ïg2kíkò~>Öq¥1Žª±¾VÎD Ó­ülP­ä*L¼Hc¬µÆ˜;gÉZ›(…®^½™u©ƒ@LÌP`µG¯üæN¢[±!I´8Íðõ]³?{„{9*~8 ë,x‰ ý#Þr²n–IYD&5ŸË‰vl‹K—I¬#$®|95ùVRÏ¢aìã~&>sÆbü'µÃjÄùþÏÖÏn¬ÍoìXk!hjj*‚$I>Xd0qd¢Ï_²»§kF…€” ¿Hofv^zÕly ú·6 ï.t'àÀ‹¡ a(X&À@ ¹[Šˆ^sö—¨Öœxh!DmüÔYçcÏ7mvÏD~øü´ôäÿ²½«r½oí½k¿dÅÜ€±4vâ‹““ŠY,"Àå36ü<æÔ'Ë«w]¹ˆÙ®m_Èÿ3wukßåG@w-2Ò²£prŽøÑʱê×^þ18¯©û¿‘s[ú³O®8R~«§|)Ï,ï7•„Þê…âäˆ%€Å\ oüëzÑ40“áî‹ÓÐp×/€ÁhT¹Ô9.ÓŠCÃÃÒá‹çYkÞÓ®Hºk=:67ŽæÜ{ÖmA­ŽÞ yø uv5c¨€Lß—7­ÚØ^~©½]kM̰uI"zy7€D4@¬°!@‰a²‰U±±‰±b`W,áï=­XÍ-`_N €X\ `– üÿå5Õ¹ÖóÃ%tEXtdate:create2017-06-06T01:31:30+01:00Lh·D%tEXtdate:modify2017-06-06T01:31:30+01:00=5øIEND®B`‚puzzles-20170606.272beef/icons/samegame-16d8.png0000644000175000017500000000211713115373743017754 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<CPLTEæææâââááâÝÞáâÝÞàÞÝÞáÞÞÞÞáááÞàÞéãêºÐ·›â6+¡N&,¡;æãâèèèçççìèïùõíÃÍÔJ™ë)›=œ%äååÂÕÃËÓÚœ™ðÿ¿h›D&F0æããåæåéçéÜààžDœÿ ø ÿw—ÿ$ãâçååæèèæÜÝå&7Ùû!Û~EÇ!Bœ?'=-ääáèèçéèèààæ&I´ 4ªX|’™+c’5Im}+åãäÙÙãààèããæåååÓÞÒ’‰† ‡ 1êt ›ÿ# ÷ššïÿÿãßáãóìóžÆŸ€“ JªKÖÿ ýÿý!$èãâßßâø00ûŠŠðåçâõëõ’Ô{¸QL °Ý}kvšm-kt|%äãåÝÝãõÿ66ùéêãòëñ–¼«hEãBk$Ÿ G¹…: <ÖOŽQ!âãæ% ÷;;øòñåûûäž›îü ÿnc‚4(ÿŠ7~\ÿ,äåâÝÝá-‘.?£ ÿ8:ö:;ø þ õ„QžMÈ;‹= BÌÿ"äãæÝÝâ%in (Áû1 Ú‡…xZ“-Wšn€dçB" «bÞÞã;1øÿ$$ü(%ù#ÿƒ6¨ÿ#ÿh0»;/áÿ'S&é^¦2¯0âäãââèäâæãäâãåâããççãâÿÿÿkû4bKGDÀaßøtIMEáûµË IDATÓc``„&fV6FvF—“‹›‡—_¨@P„EDÅÄ%$B @ %-#+'¯ ¨TPVQUS×ÐÔÒÖÑe`d è雘š™UXX¬¬mlíìœ]\ÝÜ=<½¼}|ýüu˜ƒ‚CBÃÂ#"£¢cbãâ“’SRÓÒ32³²sróò ‹ŠKJËÊ+*«ªkjëòë ›š[ZÛÚ;:»º{zûú'Lœ4yÊÔiÓgÌœ5{ÃÜyó .\´xÉÒeËW¬ÔeXµzÍÚuë7lÜ´yËÖmÛw°³n×®]º»÷()íÝ7g?ÇgN?B޳%tEXtdate:create2017-06-06T01:31:31+01:00ê¼ð%tEXtdate:modify2017-06-06T01:31:31+01:00›BLIEND®B`‚puzzles-20170606.272beef/icons/samegame-16d4.png0000644000175000017500000000060013115373743017743 0ustar simonsimon‰PNG  IHDRíÝâRgAMA† 1è–_!PLTEÿÿÿÀÀÀ€ÿ€€€€€€€ÿ€€€€òýsabKGDˆHtIMEáûµËˆIDAT×c`AF!EFFV³ ƒ€xK"#P µ¼Ò("ÀX¾ÔD¨>4Ì3¤‹1U (Å.À(¦Zl d2y–y&2ˆ—ˆZ†”&0°–3Š—ª«2°„—”»$•0H•——$O+™”*w¶,.(Œ c‚M ’%tEXtdate:create2017-06-06T01:31:31+01:00ê¼ð%tEXtdate:modify2017-06-06T01:31:31+01:00›BLIEND®B`‚puzzles-20170606.272beef/icons/samegame-16d24.png0000644000175000017500000000240613115373743020033 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<èPLTEæææââââââââââââââââââááâÝÞáâÝÞàÞÝÞáÞæææâââÞÞÞâââáááââââââââââââÞàÞéãêºÐ·›â6+¡N&,¡;æãâââââââèèèçççççççççççççççìèïùõíÃÍÔJ™ë)›=œ%æãââââáááçççææææææææææææäååÂÕÃËÓÚœ™ðÿ¿h›D&F0æããæææåæåéçéÜààžDœÿ ø ÿw—ÿ$ãâçâââááâçççææææææååæèèæÜÝå&7Ùû!Û~EÇ!Bœ?'=-æããâââääáèèçææææææååæéèèààæ&I´ 4ªX|’™+c’5Im}+åãäâââÙÙãààèããæææææææåååÓÞÒ’‰† ‡ 1êt ›ÿ#ãâçááâ ÷ššïÿÿãßáãóìóžÆŸ€“ JªKÖÿ ýÿý!$èãâßßâø00ûŠŠðåçâõëõ’Ô{¸QL °Ý}kvšm-kt|%äãåÝÝãõÿ66ùéêãòëñ–¼«hEãBk$Ÿ G¹…: <ÖOŽQ!âãæÝÝã% ÷;;øòñåûûäž›îü ÿnc‚4(ÿŠ7~\ÿ,äåâÝÝá-‘.?£ ÿ8:ö:;ø þ õ„QžMÈ;‹= BÌÿ"äãæÝÝâ%in (Áÿû1 Ú‡…xZ“-Wšn€dçB" «bãâçÞÞã;1øÿ$$ü(%ù#ÿƒ6¨ÿ#ÿh0»;/áÿ'S&é^¦2¯0ããææææâäãâãæââèââèââèãâçäâæãäâæããæãããåâããçäãæçãâæææÿÿÿŠÀébKGD÷«Üz÷tIMEáûµËIDATÓïþ  !"#$%&'()*+,-./0123456789:;<!1=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª›«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌ›ÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöÙÐxW$¡¬%tEXtdate:create2017-06-06T01:31:31+01:00ê¼ð%tEXtdate:modify2017-06-06T01:31:31+01:00›BLIEND®B`‚puzzles-20170606.272beef/icons/rect-web.png0000644000175000017500000000777613115373722017242 0ustar simonsimon‰PNG  IHDR––j.>gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá‘ëbIDATxÚÕ\iTS×Þ!±¶VŸÖªµu줶UKŸvX¾Z­l}(¶µÕ.]u¨8ð´Å­–*8#Š„T2ÝÜ$2ˆ¬Z±>[­¶¾U•$÷&˜`Â(XŸæå2yÏ äHïûcüVvøÖ9ûì³Ï>û^0ôJ@O p&‹îE`ɪìE¸/‹ºp±×àÕ"‹®¼<ŽŒË\{”˸XI·Éê„Yáâ_à!²`IrT4Q Ë„Ñ8>9ˆ3ÂÐå ¨¥Ýty(fº?e<ŒÚ¸AЊ›Ö!L`ð»Èhñ ÙV×ÈF½íØo¶„j¼Ýxð6Ê46Ø~Ùê1Sѯ˜i­í-ð-ËÎc#·Può8BeŸ ÆdEÕ]Ó±qÝSlÒÚ?h¯ýùç5m3©Ý®Ã 5ÆZ¯ë0ÓØB³¡®ÞšsÒ¥lHHa¸JÌ|§§§K˜¢ì@LVt£‰gú:a©…‰!·îÞ­76“t¤ {´µ$¾NoÀLãK¬4Bi3ò%r6UÂv5Á|ÊÊ/ÈS0Ÿ¤yë]“EWüy`ÝÆCW+<(KñýâùË•‘EYKGNËjô“Ed h0Œ;ªè„,ƒQ÷ý#üÝDÑž›Ä°$bìT¥·–Î}ò¡ƒ-û,f*&ù$(;3ZÔÍâÅÓ„™(ÏÉ"”Ò×`S§|Ëž[4ØjŽ=ߤËC.Ÿ2yà'”DgVbeÊÔµ~ðŠö˜oªñ0æÝ×#;3‰´Y3õégÿd¦=6‰„rÜÇ é”ËL5Õ5U7ZDxÆå5š,Mvç|Ë@SvЕ%cЩ(‰ðŒ¬6ô„¬ö¶j¥¡·ê¨úëz6Ê«bKÌ:= ]…3•ÅqÕå(W^W\‰š^k˜¾gsòÙÈ+’(ÉE¨œ²-˜¬›µŽ*[â¹»5u(jwaD]ͽ³É¶ª:Ì4ùì=ÔÔb{F­\ `‰à*„Y4 MšaÙ±!±‰ßíMâq`ö|—+ÄM÷`¦1¢ àÓ…\Â~+.e£äÜ^yÙ©R§¶•âL™lß¹’RÌtŸ 3-¾4ø8R>Ø$ m& æ» e 7Êbµì´¢ŒåfãéÄ»f fšxº5½a› /¨Rް‘.äÃ2”KQ®ÆWbƒ9Ûêj„§nRØ—ŠÀÏß”åd\­åtµq'-¨iùí7`r¡\Ɇ:]kQN^°±;‚n‹°ÎD[$nŠ[yLÜ"Z"§}Ï9"€ÕyH,“æv'nÑ•555#§,c•}ß2!á”Pi4šL’ÑÐ$+_ê¶pª¯N}å™ Û´FÚ©,Ú|ÑïéÑóŠ™]¾U–,ë›çFŽþ\Bî—¥kÜðÜêg!ŠÉXɺyÖ/ècx¹J_–4oÁ(¿‘°V#s¿,CÅe£M!Êù$Ò¦›WÔ¼™f»{µM¢"•, ‡E™-»ÓTèg÷QU9-ƒ¾*óq(®Õ³·jRA¼Æÿ>Ë£E›®¾÷`ª•âpyºòºzßÃh ¬Ñ"”¢Wû7%î–EÝ8?­ïªœk%»P­4êœýÐ*‹P$Nîó5!ñÄJÔ6®€¾óÖÚÿïÜåcÁ~ò]n¦Ø.ï}åýÓ²(kÚŠõK¹F«â—ð€M‰:¦NÐ Ô!|8oö—že jmwïÙê¸dL÷þ[ÛDÝ÷-MaAaQŽGdôåvè9eÑZ­VG#²ä2±D"–zF‹éz.ÿ-ë¶£,+.ËÐ=YÒ®Œ–oÕ OaI“}ÍGv5ßú«5±¹s!±øäàöH6"v…lÛ‰a NDìܲ ûZ;¦Û= c#CÃØØ̇9(áÖÁÛ:#3‰# fQ†®*‰¯§PŽª/©¢J×Î$ªÚ›Ä ]syƒ£oÅ9úVœƒoýÕ‘ËK¸|«YÝ’ ;_‰´kI³Ûm®®ä–E›ª[¾æYtÅïùç9eÑæß‹ ~©¨ ½$‹6]yæSFç²ô–Üûõ,Åä-YËŠG†Î7pÈÒÞY »ã` m¤½"‹¶Æ?7|î YöHÛçÙ§&™)¯Œ]qé©Ý§úÏåšDÊü³¯ÿRˆ¬ôÎ$ê«÷5Œ/XÄdéË¢)ëg`1<óâ“W&‘6®^æ×oLÓ08“Uù1 >(¯ð’oݼm;3à£ÇJ´ªÆ?ððèŒJïø–ÝkÊuWŠÎè8dÙãÖ¥‚üKMEqo¥U7 \²˜½ ¦åÁ[Ùi¯ÜY¿Ý¤Ùõ4S–kÕ@¼!†ÉNk°ìT[ŸücÉ̆Á6&ÉU,4UíÙ)Á‚Ä¡ì&´™­lTÞK(k´XQXvVáLãOI÷*QÊR³GsíÒe6~½1 žW$¥²qô°ŠH¶T²(KšC-,a£øìÙé“%(Nn+Á™Ÿ¤{Ï#Tá…¯¡C3 SEÆ!€ÅâØxbEË1YËEÈâã’¿Û—".$£â’önMF¹XÑç p©Ïÿèð,üp`Ç-F5s‹Qëp‹QßÞ-F5BYm±ÐgÅú~°î –(Õ,¨NnòØÏõ[{€Oæ¡ÈĈ¼B¥VåŠÙ./>¾ÎcBw{’ä©T"JOIZn¿B%Rô‚LžÒ d‰Dæé¸Õ$+Ueÿ+dΉ‚ìÖ˜&Çзˆ¬y*O_s¶ÉR¤o^øi0Á%‹P†öÑòà /É"²vÁ°¾ð±FÆ!KýòÐÁ0"­SíÝ-eb˜ä0ŒDN8ŸD2ù˜ìˆVyÍ·”Ç£aŠšc´ä$¹`ÿu9é-Y2uÔ U—,ñ'Sþ6%­SIÝE¨Âø=Á¹eY%çæÀ–ŒNµgtÝå3÷ |^~Û?MáÔ·EâÔwæ †Ý^ò-B½óÁCûMHp.KN›9|èį½ ìK£Vg©I®I$ÕYYj•÷¢¼\Æltœ¾%'Z¿æ%Yl8‘å,iöÀV Ý­z%ÚàâÉf–Î$6Ae9l*Ç¡K·'Ò@˜¹y ›Z³ùí^4»ÐÌâæ#†Ãq‡çH8<ÈL¶C ˆ9š’ŠâKìÿö–’È!-‰\å±ãkyã^àÍRªPlň¦ãkz¤% ƒÜ (=Õ R˜6R¢µç¯)n¡ývíÞùHºÕÌÒ¬ªz NIMvv–¢GÃ)m¨Øð·uLÙµm«V%L{rÄ;ñJ®|Ë“²¨êx?ª‚AìøÞD˜šÉ•zP]yzÔŠ±³Ù£%'EGsɾ£¥\¹¼'GË8kí…Vß"4kÀŸëäãAY”E6`á§}Çì±ÿäý¤Yž±Þ—sæ[ž”•>æÑ}ùó¬k´ˆÏ`®¸5BôÌ$Þ05œèÿž‰½ÕÀÔïY®¤Ù³ùe:¿)šFDììysÞ[”Ö£² ´éN=ó/ë@Æ4®ä+zr™ÏZ"KNˆ%vÈ{XV zE.o)8l¹¦eãjÝnà'Ê%(¤!!!’Ý' #ì{ÎE±­á·l På£8‰ùE*ºÖža0]õðæô7ؘþÖxàOô}ÃS8á;‘³=£«Í,»¿íFÖîB3K[L—FùNœ„bì¸IqŒÅ‰IÏ»ÒÓܵF)óeø² }š!·$Z\œ‡»R$Æäª\oÏ [·vq%ÒæË~×À˜:<éÒ#’|,‘XŠW`²z|ð?¾…𨘬Yس«ý—¬Æ1'–ò`¦ƒéüÅ.˜®]ÆṴ̀Å!!? )Âò<ü°—WDúÀævrù"×ryŽf€ÀlsE•žžÞü¶=!’ø-—$T*Á®¹’|` öws./EšY$ΚY: ë›b"ÓVÒ\&ÔÛÚ >8¡Jõqås NäÜá”K–"|ñ§«ân’¥m^¸h³¨EÊfYDÆKC“Çn‘EdòD_ø %Ý–Ñ"I}!FéžÑ"% ²xZIt¹Ø*K¾àyÁ &}u‡,™úð›£XÛýÑR¤Ï±ÿkGÝ$‹ÈØ?s\¿Ï»q¹Ò"K¦9õó;ÊäHîX‰òüŸŽÖréÓeY„"nêû~ðö©Ü3Zª‰Ï„ñݸ\i-òÈ´a¾ð›¡ŠxzØÐ8;’8'‘Tgª[Šî˜D…ýç2]Èå¹dÝo+qo¹˜4sÊbÿ¶d95uIVóVÍÚoUílÕÒP|ï&›¶jÜô‡XnSis3 bŠ7³ŸA_wüd”¸0ë?ÉÀ‰B&±q0= *ÂMó"0&· ©™1Å_9ðn0úú¼u›¬ZÃF­âÁÛŽ¦ËL7øãÌÆÕ>0 }iþ‚¾î¼Îн¦¼žÏåÛG«¬^úªLCo}±ho} k¯C/•õ?ÆÜá?« %tEXtdate:create2017-06-06T01:31:14+01:00ú”*%tEXtdate:modify2017-06-06T01:31:14+01:00‹_,–IEND®B`‚puzzles-20170606.272beef/icons/rect-ibase4.png0000644000175000017500000000106613115373741017617 0ustar simonsimon‰PNG  IHDRssŽ(b:gAMA† 1è–_bKGDÿ‡Ì¿ oFFsZw?_tIMEỪ¼ vpAgÍÍÆð`@IDAThÞíÙÛà `GóÍ6Ó^(Z™HÍúsµçDâèã&L˜0aÂÔ›ëã½&w6½3×Íàö0L˜zó8«ü€I¾füÀ)Q·z²wž"M/3'½ê™“®çÖ÷ =aÊ€ óŦAß§‹‡zÍmúÛ‹q˜¯7ëj³êc ͸pöŤ5fŒMksÙÇZšÜÎ3”}¬¥yÔ­eò²zöö¶êcïJJ4«gÙÇÚ™á<·už$.‹µyq?W[9ÿoû`ÂÜÑT÷·ÚñMò„ &L˜0a„¹‹IúP˜fï´ÓýíÚÏâóÞ4¨gñhê²·’»+³&ÉÃg²œïhÎÖSÆÐÞŠq˜0ÿÝ´Š†iÖß›_Ö]RJ¯vi%tEXtdate:create2017-06-06T01:31:29+01:00Zò %tEXtdate:modify2017-06-06T01:31:29+01:00dJµIEND®B`‚puzzles-20170606.272beef/icons/rect-ibase.png0000644000175000017500000000141713115373741017533 0ustar simonsimon‰PNG  IHDRssŽ(b:gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿ oFFsZw?_tIMEỪ¼ vpAgÍÍÆð`íIDAThÞíØMKAðøR±–æAI:x) ‘¢ ˆDè‚N] ê ‚"(CC¨  Hñ\Ðð}‚¢N}Ž„.»3«»ëŒÓ¢Ïs–ý1o»ü¨/I&™d’I&™ÎÍÎWïšÙ&‹Þd¼ñŽšie͇É$Ó±Y]‰öfòJÍ b #••Îó¤V+9Õû™‡çA±yöâs[ˆôm)¾+§ïâ»Rö!œH$ÎTšO?“CÕçVWd’Ùæ„Üç¬þ)kº&ß¶'³çÍ1p¶Ê™|Ž•hÎ¥7Æ1ðÁš|Ž•»¶u Î͓˱2ÍëÝi¬™î§1ÇÊ4Ó@ðÊÌdr¬Ôµý~ôâ•7Ù+Ïüüj Ã¸åL.ÇÊ3_‚™Í8ï¬ÉçXyæÛbØÉ­p¾íì<í[‹¾;™dš›LŸÖÚ\ø´‰c!“éÓZ›“É¥QøKBó4öim­m(Šî§®OkÃÜ_c^ô éû´6Ì$ í š†>­µ­yp)dû´–f©Ò@5dEL¦Oki^h©å(ïDL¦OkiÞL yB©sÑ3d¨nýö‘Ifû¦¬21¥å[Ûæ/ö"ZÎJ¸‹%tEXtdate:create2017-06-06T01:31:14+01:00ú”*%tEXtdate:modify2017-06-06T01:31:14+01:00‹_,–IEND®B`‚puzzles-20170606.272beef/icons/rect-base.png0000644000175000017500000000565213115373722017366 0ustar simonsimon‰PNG  IHDRÍÍ”Þc>bKGDÿÿÿ ½§“ _IDATxœíÝ]HTÝðe3ãT£–iJŸXf!©$QEZT¤’öåE¥4‚¢ÙÇXEsÙE]T¤%uUQMQ”Œ$ES†ÔdŽ f_:޽›ã‰Ã9½ö³×ìùÿ®^„ÙëywÿÖþhŸ·ÛÍ6Ní , g@9 ÈP@΀r3 €œä ( g@9 ÈP@΀r3 €œ}ŸILLä^„ ¾‹ý ( g@!˜ëæù½6›­¢¢BæA´zœ‘û“k×®ÉÍ;—ïBâæŒ1výúu§ÓùôéSÆX~~>BÆÝ¸qã¤1Ɔ††c:.>>žûBBçìæÍ›÷îÝcŒMš4iÅŠj—£eß¾};}ú4c¬¸¸8&&†ûñŽ?cŒ]¼xñÇ.\øõë×¾}û^¿~­vEÚäv»«««;;;KJJòòò”XBМ 2Æ"##—/_>qâDÆØû÷ïÕ®KƒœNgMMMoo¯ÅbY»v­B«zÝloo/,,\ºtilll[[Û÷ïߣ¢¢–,Y¢v]Zã÷ûëêꆆ†¦L™b·Ûív;c¬°°0%%…ïB‚ælêÔ©‹/~öìÙ?bccÍfóÞ½{§OŸ®v]Z3<<,Ýþ÷öööööJ?\µj÷…ÍYbbâ•+WÔ®BûÆ/ÿË £!èýh r3 €œä ( g@AÐ÷ð79 ‚ˆ¢gi¤‡Kkü/6›Míþ» 2#+gè«Sô8ÂöýñçŽëfùÊ~ä²Ëë8AÀsP@΀r3  ñç€@ PUUÕÚÚÚÕÕe4ÓÓÓkkkSSSU,‰K_*Yß%/ßÏ~ÿþÝØØh0Ìf³Ñh|ðàAQQ‘ÏçS±$.}©d}—¼h|?ÓëõÍÍÍYYYŒ±ŽŽŽÜÜÜžžžööö´´4µJâÒ—JÖwÉ‹Æs¦Óé¤1Ƥ¿îƒ!))IÕ¢8ô¥’õ]ò¢ñœðz½åååŒ±ššš¸¸8u‹áØ—ªtß%/¿?“ttt¬Y³æíÛ·µµµ;wîT»n}©}—¼h?g‡#//¯»»»¡¡¡¬¬LÝb8ö¥Òô]ò¢ñë¦Ïç+((ðûý MMMMMMŒ±ÊÊÊÌÌLUêáÕ—JÖwÉ‹Æs¤ÛÇãñx¤îرC­zxõ¥’õ]ò¢ñœ™L&ù_^âˆW_*Yß%/Ú¿? g@9 ÈP@΀r3  ëý—C^]ŠZ=c¬¥¥E¨ãAVÎä·( Õ/)ÚqF’*¤!ßã×M €œä ( g@9 JåìîÝ»‰‰‰‰‰‰uuu -1J¯^½*((HMM3gNNNŽÍfV·¤0¤Hμ^oEE…^/Ä—Û¶nÝúøñãìììÒÒÒžž›Ívçε‹ ;Šä¬¢¢Âd2­_¿^‰ƒÉàà ô5ÚÕ«W¯[·nÚ´iŒ±É“'«]WØáŸ³Ë—/Ûíö††“ÉÄýàce4·oßγX,f³¹³³óÔ©S*¾® [œsöáÇC‡íÙ³'##ƒï‘ƒ¶jÕª¤¤¤mÛ¶;vlâĉ‡~÷îÚE…Î9»}ûvÿ‹/¶lÙ"µÂÞºuëСC|W=¯×[RR200P__¿mÛ¶uëÖýüùóêÕ«jÕ¶8ߪÿùó‡1öðáÑŸ¸\.‡ÃÁw•Ñs¹\>Ÿ/222èõz©w2""B­zÂçýl÷îÝî‘nŒvíÚuûöm¾«ŒÞüùócbb¾ÿ^ZZjµZoܸØô4þž6::úòåËË–-kmm½téRrrò™3gð@OÁW\õõõõõõÊ”222pC¦:ïg ä ( g@9 ÈP@΀‚_ÝÑiÎǾ: ÌßDÿ¦RÇú7åê8Â&UÅÁuSAòåbKK‹üpˆpÙÅsP@΀r3 €çRÎÍ<þ|[[Ûׯ_###gΜ¹iÓ¦E‹q_û)çfº\®3fäääDGG;ÎãÇKßnç û)çfŽüÂÇS^^î÷ûûúúø®‚œ‘snæ£G>~ü(ÍËÉÉá2†œ©E¨¹™Ožû„ê»äuœ‘ó£UAü¹ãº© Ñú7eÖ#粋砀œä ( g@Ïcs÷îÝ­[·2ÆvíÚuðàÁ±~\ÀþMØÏÆ@þ\Qû7i`?i®èÊ•+ƒ|!`ÿ& ìg£Åe®¨˜ý›³Qá>WT¨þM¸nŽÊßsEß¾}Ë»uëV °Z­AM´þMÈÙ¨pœ+êt:Oœ8áóù,Knn.¯ ‡ëæ¨ðš+*õoþüù3&&Æn·[­V«Õ*mÚ†ýŒ”hý›d³1“3WT´þM2¸nä ( g@9 ÈP@΀Þküæf*ó7ÃæoÊ¥í¹™¼`þ¦Xé»äu.ßx ÈP@΀r8?ªªªÖÖÖ®®.£Ñ˜žž^[[›ššÊw•F3ïR´z8ïg¿ÿnll4 f³Ùh4>x𠨨Èçóñ]%¤ÑÌ»­Îû™^¯onnÎÊÊbŒuttäææöôô´··§¥¥ñ](tÑÌ»­Î9ÓétRÈcR›µÁ`HJJâ»J¨#˜w)Z=J½§õz½åååŒ±ššš¸¸8…V Qó.E«G‘œuttlÞ¼¹³³³¶¶vçÎJ,Òæ]ŠVÿ÷‡#//¯»»»¡¡¡¬¬ŒûñCÙ¼KÑê἟ù|¾‚‚¿ßŸÐÔÔÔÔÔÄ«¬¬ÌÌÌä»Pˆ"›w)Z=üߟI·ÿÇãñH?ܱcßUBÙ¼KÑêáœ3“É$ÿ—½kÙ¼ËQÂüMÐä ( g@9 ÈP@΀‚¬yuZxÍü:øBµBK¨öojµÏQ«ÿ_*ÂsP@΀r3 ÀÿyS´þDÑ„çù῟‰ÖŸ(šðIEND®B`‚puzzles-20170606.272beef/icons/rect-48d8.png0000644000175000017500000000246113115373741017137 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEỪ¼9IDATHÇÍ–mL[Uǯ+B²%EƶÄdšá¦nΠɲ¿êºT"F‡ÙÔ½À²˜i⇧¸M˜/HÙ…]ê ôÜ·¾Þö¶—µƒN%Ó¡6ÙÛÛ—{ËV(ˆ~óœ{ûÂKÀOþ’öüs’Îóœç29³çQrÊ;a1Ý ›`-T{0cŒ‹$:é¹s©è½[ªo¯pnÏá¼ÛÍq.®ÿÇÒÏÈõë#¦~¿,†}ù/¾¡y Q©®”WÍ›ÛÖ…SÆçEx|½^Ï%(,…ëKK---+Âà?¤dÚ²PÊàŸŠM@¤iïX<6óÏ=iê¶êÌeû%ÃîùNep³‡ÃvåƒLHbåÜ#áp=*D‡TŸYõu„Ñr Ó1F@wŽÂEDíŽÊɬ4ÛYµYÍZ¾ÄÚL¼^#—½iü•jd€uèÕT/i¸)¨/ˆè-Ù˜5’Ö¥ ÑÐ×G81ŠB2¼¾ç(ÝIV:1;‡à €ãlFÛihAs’šŠ!¤„÷xLŒHÒähÞI'E’íhÀp+Í0 Å×f ŽkýˆŸ®½?Ëâ·êã.]{{»®ó8ö¾ ªVðNá7Ì %$HŽæ%žwTN¦ ¬Y“ÎÝ@À¶T¥ÿ/†tÒ®áp  "ƒèyÃG­<ïEI§(ÑšMLOOOýÈÿÊk‡mÃmòµö̹Öd‹zûv=^^¾ RþÄ}Eerg–=’WßvÎó³o.7ü%[ªÔ»_UïQkR­_µkU“AãzœÙ_¸`̈b¼øèU—Ý|OÇ£)ãò5c,´Ëm&øšEƒL×îcÁ‘Ýg¨nШŒ1ƒù$¦3w¾WÝJf©tHZû®Ëø‰f³ PÚäìF×j6ZwОe#XÍ1 çh˹'km9 NKŃ59÷MûÖ–½¹Ohø´Ž$2†Ó0‡®ã§èy…S*Äâ<É: m:‹º–ËѰ ·2N–&ùÚôµöNJ2ñâ½ ÞwèõëñïõpkêB[8®CìG²‡s!øç6nߺMæieÝúìSžQÔöÊ0†Ü½-3 ŒÏgìOa|,©Òß¡HŠp8²ÌV8cXé×ÌŠør½eˆó„U%tEXtdate:create2017-06-06T01:31:29+01:00Zò %tEXtdate:modify2017-06-06T01:31:29+01:00dJµIEND®B`‚puzzles-20170606.272beef/icons/rect-48d4.png0000644000175000017500000000127413115373741017134 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA† 1è–_bKGDÿ‡Ì¿tIMEỪ¼ðIDATHÇ•V’„0ãé<-?ã p«Ö¹êjÕRX13ÄY·™Ã¶Ó¿ä_ÃÄq(ÖofRs¿ø«|ïÏC”ðâVXuº®ÂU`=b­Ó|ÿXð¬Abw_ë" ŒP/è–ñ‘c Hxƒ„:B…X^OFÃÆðåÑTó¡Á.v›[òI%SÂNqÀ¤& $ŒyÍFó¢=0”CBrvpµOý¦²AÚ"Íá$ªé!Ò᥀ëÍù#—–^P`¢É‡2-¨±kh_ Ô@×àɆTš{kâh'êC¤ ’ãX–D*ƒ½Øº5òáKÞ¹I(cXq¨ ÒrzvA*/aÊ­ä)ãÐä›,a ,£ÕnCSU6„  §ºâØ ½s)ÑéÅ­§ºTåTiÎG”.¨8Э§"`ŒDAúÈi†ÓåîÞ6P @ãÀ}©Áž2N»n! Řj/uYm;³ÏOå[Ýt¢-!Ôˆ0K܆H¸Ôþ q•›âæ¥àzäq!ˆ¡Lo»Å‚¦B:L¢nKXyƒ„+Z4—ï_jdúM³ª\Êþ(¸µ,¾‹Ú2iœ)šoï6°v·›Õ±y©i6ÙÝ\‚=jèÜo Íœ~¤ ýµ»N6“é>¼Ê¥¡ô_Š*—ì…@Å‘ßÿÂÓví’%tEXtdate:create2017-06-06T01:31:29+01:00Zò %tEXtdate:modify2017-06-06T01:31:29+01:00dJµIEND®B`‚puzzles-20170606.272beef/icons/rect-48d24.png0000644000175000017500000000246113115373741017215 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEỪ¼9IDATHÇÍ–mL[Uǯ+B²%EƶÄdšá¦nΠɲ¿êºT"F‡ÙÔ½À²˜i⇧¸M˜/HÙ…]ê ôÜ·¾Þö¶—µƒN%Ó¡6ÙÛÛ—{ËV(ˆ~óœ{ûÂKÀOþ’öüs’Îóœç29³çQrÊ;a1Ý ›`-T{0cŒ‹$:é¹s©è½[ªo¯pnÏá¼ÛÍq.®ÿÇÒÏÈõë#¦~¿,†}ù/¾¡y Q©®”WÍ›ÛÖ…SÆçEx|½^Ï%(,…ëKK---+Âà?¤dÚ²PÊàŸŠM@¤iïX<6óÏ=iê¶êÌeû%ÃîùNep³‡ÃvåƒLHbåÜ#áp=*D‡TŸYõu„Ñr Ó1F@wŽÂEDíŽÊɬ4ÛYµYÍZ¾ÄÚL¼^#—½iü•jd€uèÕT/i¸)¨/ˆè-Ù˜5’Ö¥ ÑÐ×G81ŠB2¼¾ç(ÝIV:1;‡à €ãlFÛihAs’šŠ!¤„÷xLŒHÒähÞI'E’íhÀp+Í0 Å×f ŽkýˆŸ®½?Ëâ·êã.]{{»®ó8ö¾ ªVðNá7Ì %$HŽæ%žwTN¦ ¬Y“ÎÝ@À¶T¥ÿ/†tÒ®áp  "ƒèyÃG­<ïEI§(ÑšMLOOOýÈÿÊk‡mÃmòµö̹Öd‹zûv=^^¾ RþÄ}Eerg–=’WßvÎó³o.7ü%[ªÔ»_UïQkR­_µkU“AãzœÙ_¸`̈b¼øèU—Ý|OÇ£)ãò5c,´Ëm&øšEƒL×îcÁ‘Ýg¨nШŒ1ƒù$¦3w¾WÝJf©tHZû®Ëø‰f³ PÚäìF×j6ZwОe#XÍ1 çh˹'km9 NKŃ59÷MûÖ–½¹Ohø´Ž$2†Ó0‡®ã§èy…S*Äâ<É: m:‹º–ËѰ ·2N–&ùÚôµöNJ2ñâ½ ÞwèõëñïõpkêB[8®CìG²‡s!øç6nߺMæieÝúìSžQÔöÊ0†Ü½-3 ŒÏgìOa|,©Òß¡HŠp8²ÌV8cXé×ÌŠør½eˆó„U%tEXtdate:create2017-06-06T01:31:29+01:00Zò %tEXtdate:modify2017-06-06T01:31:29+01:00dJµIEND®B`‚puzzles-20170606.272beef/icons/rect-32d8.png0000644000175000017500000000207413115373741017130 0ustar simonsimon‰PNG  IHDR V%(gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEỪ¼DIDAT8ËmSYOQîðÉD_LHŒ´e‰cbŒ1¾‰ÛtC£ñÁ‰‰QÁˆ>¸ÐÖDy0ñ ¥í¬µ–v µ4¸ìØÎ”Ò ¬N§ÌL¡ðà*ufŠZ_rÏÉM¾œï|çž+c˜|9x¾üÆ1ŒŒÉR¡°’c(¥DD¤HųŒŒKî«o P¡aÏ–ŠÚjUÂÙQSYçd\⛡i–$Yšžý¢Ö Û é¶À°±VSy¡Âû<“cøÉIžÉeVµ½0ŠØ{@¬U‹Â5à²L–‹D„4·¢iñ€Œ™¬Ã*U ør‚ Ch·Å~@më ¹ù\>ÍçæéošË¯ž»†p³Ãå´9k› dÒÓ‚ȤÓÓËê¦Gz½ñ¶Þ`0ïm›äelÊ Œ‚##Á‰ñ×ñ“w×)ä ¶×Ëu;7ÅxÁf¸Àrlajª@³ìíå7¨÷7tù‡\nI‚K9:K³TxÙÞ4±¦Òy¯2áòN'Á¶¿\P уϊª–ч†åŒü¶Yš¹d»4¾¦Ö::ˆËõ.^'$B‹óìüâÔÔ"»Ä}×¶zWqµÃÕ’Í—3‰Db&˜‰Ç£üÉ Î~³Ûu3Zvˆ„”'$Òç# bâCÓyÄÔÛc«½eíéí3UED r‰ã¹B,VàøÜZs«ÁÐá:#Žbv¤¦Ü&ÅÒÙÙ¯š–†\ ý#àÿë¢B ·¢Ü¦T#C¹Ù¹ô'•·‚Öçò² ‰ðËq‹)º¸²ú¹xþZpÄëyÛhzl¦FcT„LYZ;ÚÛÛîìj<(íæ»`ßÓ>ÑE‰Ê\©ÐêãÇ•RY"X,%BI"Wìh¦Ì}>?âõJß8?Mή\ozѵ÷¾³»Å&;=ºÝXÙNέ^?öêÎþ^GÏ †ˆ6õxG½õŸ cígMvÓA6§Bï¸z±ý²)̸xCùÆ3æÆ­îr9ýõý/|¥b§½ÂcML·UŸ•æ V©U§·i” RØI†™N$“ÉD’|@b FCRЉ¿›æ("¿P¾”„ïÿÆJ^uqm%tEXtdate:create2017-06-06T01:31:29+01:00Zò %tEXtdate:modify2017-06-06T01:31:29+01:00dJµIEND®B`‚puzzles-20170606.272beef/icons/rect-32d4.png0000644000175000017500000000076213115373742017127 0ustar simonsimon‰PNG  IHDR V%(gAMA† 1è–_bKGDÿ‡Ì¿tIMEጲû&IDAT8ËUS!âé>ÍŸ9ôZkW[† *{§Ç·›= ð;®þÅg!«ÀµÃû^pÎ@úÐ13‚'Œ ôWžƒèþ¸ÐÖDy0ñ ¥í¬µ–v µ4¸ìØÎ”Ò ¬N§ÌL¡ðà*ufŠZ_rÏÉM¾œï|çž+c˜|9x¾üÆ1ŒŒÉR¡°’c(¥DD¤HųŒŒKî«o P¡aÏ–ŠÚjUÂÙQSYçd\⛡i–$Yšžý¢Ö Û é¶À°±VSy¡Âû<“cøÉIžÉeVµ½0ŠØ{@¬U‹Â5à²L–‹D„4·¢iñ€Œ™¬Ã*U ør‚ Ch·Å~@më ¹ù\>ÍçæéošË¯ž»†p³Ãå´9k› dÒÓ‚ȤÓÓËê¦Gz½ñ¶Þ`0ïm›äelÊ Œ‚##Á‰ñ×ñ“w×)ä ¶×Ëu;7ÅxÁf¸Àrlajª@³ìíå7¨÷7tù‡\nI‚K9:K³TxÙÞ4±¦Òy¯2áòN'Á¶¿\P уϊª–ч†åŒü¶Yš¹d»4¾¦Ö::ˆËõ.^'$B‹óìüâÔÔ"»Ä}×¶zWqµÃÕ’Í—3‰Db&˜‰Ç£üÉ Î~³Ûu3Zvˆ„”'$Òç# bâCÓyÄÔÛc«½eíéí3UED r‰ã¹B,VàøÜZs«ÁÐá:#Žbv¤¦Ü&ÅÒÙÙ¯š–†\ ý#àÿë¢B ·¢Ü¦T#C¹Ù¹ô'•·‚Öçò² ‰ðËq‹)º¸²ú¹xþZpÄëyÛhzl¦FcT„LYZ;ÚÛÛîìj<(íæ»`ßÓ>ÑE‰Ê\©ÐêãÇ•RY"X,%BI"Wìh¦Ì}>?âõJß8?Mή\ozѵ÷¾³»Å&;=ºÝXÙNέ^?öêÎþ^GÏ †ˆ6õxG½õŸ cígMvÓA6§Bï¸z±ý²)̸xCùÆ3æÆ­îr9ýõý/|¥b§½ÂcML·UŸ•æ V©U§·i” RØI†™N$“ÉD’|@b FCRЉ¿›æ("¿P¾”„ïÿÆJ^uqm%tEXtdate:create2017-06-06T01:31:29+01:00Zò %tEXtdate:modify2017-06-06T01:31:29+01:00dJµIEND®B`‚puzzles-20170606.272beef/icons/rect-16d8.png0000644000175000017500000000102313115373742017124 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEጲûIDATÓïþäÈÃÄÅÄÃÉËÈÈÉÉÇÏæÛ•””‹“œn]yrorv[ÏÝåõòàïÿ«ˆ½¯±ŒŠ€ÆÝÚçäÕâ𢇸­¯“œ{ÇÝÎØÖÇÖê—JseVkmLÎÝÙæâ×ͦz‰b£¦mÉÝÝëçßß­…u–m³·vÈÝÔàÝÏÙì°›d«®qÉÝÑÜÚËÙçš³šcª­qÉÝÝëè×åõ¤…¹¡g±´tÈÝÚèåÚåô£‚·žf¯²tÈÝÍÖÚwo_WiXV­¯nÉÝÚèçw~©¦­žk“‹zÇÝÜëè}’³¬¶¥p“‰~ÆÞÒÜÞp†‡ˆŽƒZ“gÎåÞÝÞÕËÌÌÌÌÍÐÌÊÒæ^°€?Ž:«%tEXtdate:create2017-06-06T01:31:30+01:00Lh·D%tEXtdate:modify2017-06-06T01:31:30+01:00=5øIEND®B`‚puzzles-20170606.272beef/icons/rect-16d4.png0000644000175000017500000000045113115373742017124 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA† 1è–_bKGDÿ‡Ì¿tIMEጲû]IDATÓMOÉ1²tK£3Vwb>å°ˆ”º1ï NͨÜ]r{dÃü£€ÞG(|ÿÙr€0ÛQñCqDÏ%º‰?ÕE>ÅFr¹ÓuþGѰ—¾ç'%tEXtdate:create2017-06-06T01:31:30+01:00Lh·D%tEXtdate:modify2017-06-06T01:31:30+01:00=5øIEND®B`‚puzzles-20170606.272beef/icons/rect-16d24.png0000644000175000017500000000102313115373742017202 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEጲûIDATÓïþäÈÃÄÅÄÃÉËÈÈÉÉÇÏæÛ•””‹“œn]yrorv[ÏÝåõòàïÿ«ˆ½¯±ŒŠ€ÆÝÚçäÕâ𢇸­¯“œ{ÇÝÎØÖÇÖê—JseVkmLÎÝÙæâ×ͦz‰b£¦mÉÝÝëçßß­…u–m³·vÈÝÔàÝÏÙì°›d«®qÉÝÑÜÚËÙçš³šcª­qÉÝÝëè×åõ¤…¹¡g±´tÈÝÚèåÚåô£‚·žf¯²tÈÝÍÖÚwo_WiXV­¯nÉÝÚèçw~©¦­žk“‹zÇÝÜëè}’³¬¶¥p“‰~ÆÞÒÜÞp†‡ˆŽƒZ“gÎåÞÝÞÕËÌÌÌÌÍÐÌÊÒæ^°€?Ž:«%tEXtdate:create2017-06-06T01:31:30+01:00Lh·D%tEXtdate:modify2017-06-06T01:31:30+01:00=5øIEND®B`‚puzzles-20170606.272beef/icons/range-web.png0000644000175000017500000001026013115373722017357 0ustar simonsimon‰PNG  IHDR––j.>gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá‘ëb¸IDATxÚÍœ{TWžÇ/Ñì$Ѽ6c2'“ÍŒ““™ NÖõŒf$3®AM20É(ã¢<œÍ4™QDAw’C@\w’¸òðç˜DFƒ"Ð]u»úQÕõêênHvÇEÉ Ds¶º›¦ëÞ*èìßêùz«ësnÝúÕ÷Þúݦ° p³FÂa ,›ÁÂÎhh´–FëÓlZ£¡°¨¶úX4œlUkM§ÕZs‹J«oinPi§›ÔZëIµÖF aA[[ܪä4V%ƦáÚêEq¸–œ?O¥¥Í‹OUiq‹V§àZlâ*\[×fƒ>,{Cê€àDBêkX ÓýUùƒ˜&|PŒ·®0 bÚ`~U¿o·¾¡O´Ôûs"Yè2"a`ªÓ¤NTëæ*rp­K,)”°c»¤ÂÓ:¥œ ®×Òªv¬|‚ÆJqÑò‡2z0tìËíÅ4µ{ ÞÎØ³e·‹ðüˆïTž{ËØ›»ÏAâí2ñÓœ)“·.—†¤ë ÞÞ²eó;gd®ÐcA‚!½"Aó„‹4’!À‚6ÉaWoY[Ê+>ÊuQÊÞ‚œsˆe"XÐv꽺Ìã[Vs/o‹„blAkõZáD±Œ®m ò Çe‚Ý̇à»ç,Ê!OH @œHÜL,ù—W€õ‚矡Ƃ–s‡?1R㹈ž{1êöFšTbAKã¡ó„/¢<8ÎK5v,Bʯò¾ž y†g&>äå’C7ôX±H¦n&8b'Q¬Àïݬ,omûcéëéðÉò.'ï×Â+ð€/–d@ 5ÁÖ¦»pM¬ÌucšQÚµogpmÞ%1Í[)x»ôZפ–½aUÃ#Á~u<ó i—lìÇÚÙûölÃ5¦Ûž>;®m®m×åÌÙËp-­ÚnÄ41YáåSDR_CÖ €i_W烵sôׂÑX̵ý´øMþ÷ñ"ìß×5ôIX;EyÝ_V²‰]{r*0­´lM¢J{­–i^û~)Ú®dï’ßVÿç~$*¿˜³gÖ®,¾Ùïåé–yÛ · ±y[Æü¸¶ýW ¸V¸#iŽZR±"i‡ªÝÏÔøäü~3Önû¼Zéå±5ø~ÝëòZ56êuùoŠÀŒ(,¢ÁÅKøº<æåuÖØ8qm¤•oÏÑêÞj´„°ÆFQ;£»ÆÆ½I «‰ ]Þ‚V_íŒg Œ^cÓ¨±™t,’ùìù„… ‹~Ä’£a‘쟟Y¸pá¢%u²ç =Ö°oÂ"¸ªéQÑ1‘`—œÊ•ëòþvþq'˜=ÄÔpA±Báå)Ckó…ðýY`‘Ü—.ô"R§›;rÁKЋ¥/Å1zy¶æåÕ_XwJÙlâRð–g¡<°.ÏíYž…­Ë›mŒå PÆ“A° —TÄNØË›æ¸»™&ƒ¬ËC#÷.xÂ`Ö[ãðò„´{úì ‹äRÀ¯½µ3,WVÔãªuyóðÎÐlc4,öÙˆ1¶!UOÎŒü”Æò$ñ•f’=îk·èÈ[cõ'ŠÂ°q=xÉ÷ƒÊáo§ÀJ_/ŒŽE ;‘tzî~ð1GàXùÇ_cc?6ýÎ&šÔ8vî”"ΜÒF}øPÝ­~m °ä aÕƒ%gËTb&PAÖå­qa…¥±™˜ ÔWž18!Ó¼b;Íp¸ã¶x„î.€´S2ëÀ‚v—¨ ò.tï«§^þ±ËGÁlÏ®x­2~úìŒô"dVbBå“ñÞmô£câï_ª£œä×>šÊ*Ý)´´=õèý·¼Kk¦Cæç÷ôƒWÊ!¯\— kõòΊ|ü¾ï[5ÇÉÖ‚5ͯƒøã„²·ÄòýôŒŽÞr>´XŸúO)‰\Äb°D¨»+úsF«0äöy¶gGƒ¶[ r_µC¤ôŒ-ÆÁë[¬ƒCÆ!¥€W¿jûþHõòÖ¦ßlܺ<²Ë@iïBr'¤,e;_o±1/þ<æ™Kiî\q°—ÿ2%Ó§Së®§ïú^Ò‰‘ò–Ü/F“"¦ËÄ2 m9Ë{¯™ïÏ©}&Ê2rL/î¦K¡ñòZm‡´°JøIÚ¨wÛäåSê2Ÿi âÚ$m›Ô»Éôß’Ô¦9$¬Ÿ¤M¦º·ä¤wžhB¢ñ–´ÉÚ’«wóß¼ùfôÛAÖÿ}¯èÊdm`ÏvorÒ·{c²¯óÅÝĘß'Z©0Ä"¸ý÷Üšo'o&–ú3ÐrqY,‰ès¡Á‚Vÿ¨!üò¾ù`Šiž:,B,{ vÈa‘üð^*Èe”X„”wß³:Üiˆ°Ô56ÐÜõÐsߦ€‚Þ`56“Ù[üþ^üWeE!5ÿ~~LYí&«sWL–z_5!ÊOìˆiàYqó¾êa©v¡CÛgï¿ÿ4XXm×.ôa ÇpÍÁöýöÎÿpÝÔ¼¥Âòz~›hAê·ÂËÛ€PJ…ÖPLöº|~ /L?gž ÓOešÂõâáúÖ°‹0ÅúZŽ—v¼%tEXtdate:create2017-06-06T01:31:14+01:00ú”*%tEXtdate:modify2017-06-06T01:31:14+01:00‹_,–IEND®B`‚puzzles-20170606.272beef/icons/range-ibase4.png0000644000175000017500000000071213115373741017753 0ustar simonsimon‰PNG  IHDRbbŽÎYÒgAMA† 1è–_bKGDÿ‡Ì¿ oFFso¤ŽtIMEỪ¼ vpAg²gÜŠÔIDAThÞí×Q ! Ð}ŽæÑ ¥t»‰èãoÔg"ŠZ¡7›ÐŠõ1!⿉ßã´.¯q@­xqN‚A¸$\Ü\ôat®N"ÌA!ЊÇñw ÄUf!‰t"&‘NÄ$Ö»ÌEˆØ…ÐÿB„"&•gï-â³YÄE¢7Ѹ"DìNLù_t{ŒJ„ˆ‰Ú˜u P‰I{!"šé…ê€7’‰÷Ì8÷I&j}(§›I ¥Pm"e»{„y!{/>) ðˆj\„‚ß^:ƒkËvÛÓ %tEXtdate:create2017-06-06T01:31:29+01:00Zò %tEXtdate:modify2017-06-06T01:31:29+01:00dJµIEND®B`‚puzzles-20170606.272beef/icons/range-ibase.png0000644000175000017500000000117313115373741017671 0ustar simonsimon‰PNG  IHDRbbŽÎYÒgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿ oFFso¤ŽtIMEỪ¼ vpAg²gÜŠYIDAThÞíÙ±JÃPà¿K¤(ìì tQ§ªÔAA\G‘ í^gÑ>€‹P'gñD—•¼¹¦¤×›¶7¡í†,'÷~'çôRp‡>@\¾y"&›ØêÞO¥1&.K&6CâŠEDq dÞ©Äw8q•àO4‡çë¿y3(obãϰD3Üã‰KìëŽ|ÄÛ pçldÏúA‰3`¥M%>²@ÝU‚?Qæ[Tâk¨¸JHà*†É‹!ÂBŒ &£Q"Dˆ‘ayíˆèãµYDŸDÜCäEˆ!bÚ‰‘|_Äžáß("¦™Hw–äÆœÈþþâ8f«üYdré…í/¢×´Íâ”HäÎËÆiЈsh†Æˆ¢¬ÑÆÝ% ,âö¾ÝiT™ET°tt±oÆýÈ#¢HÕñy³[˜›]>|h„=/B„ ÁémäP*òJ%tEXtdate:create2017-06-06T01:31:14+01:00ú”*%tEXtdate:modify2017-06-06T01:31:14+01:00‹_,–IEND®B`‚puzzles-20170606.272beef/icons/range-base.png0000644000175000017500000001002113115373722017507 0ustar simonsimon‰PNG  IHDRÓ?1bKGDÿÿÿ ½§“ÆIDATxœíÝoLSWðSÐbÖu H1Áÿ6R¢)! Ù’¡î…*»¨uó &3è²MÃ’é‹m ™L­MÜBÖ±%èÐ"8A0܆…òG„›B„Ðiy^Ü<}:Äïíí½¿ïçÕñRÏù…ôË9·ÎQtuu1ªÂÄ.@L†i†i†i†i†i†i†iKýB”ÂQ(³³³èý/ŽZ­niiù÷8‚~‡&%%ý£ÿ—é? Çc ¤!@¤!@¤!@¤ü>„¸ƒ.ðNÐæÍ›ËË˃YOˆÃ ¤a›´´´ˆˆÿ+.—ëÞ½{\;99YŒ¢B 7GŽ™sÅd2qP*•ƒAŒ¢B–@2çõz«««¹ööíÛ£££Å­'ÔHxðÿØö¸~žúúú¡¡!ƘB¡0<ö,ß?f™»xñ"ר´iSRR’¨µ„"@ÎÚÛÛ;;;¹öÄ-&4!rVUUÅ5RRR6nÜ(n1¡IÂ÷Ò]wÇÀÀ@CC׿wõÏ‘Çï3€l]ºtÉëõ2ƶlÙ"v9! §±±1‹Åµ÷îÝ.n=! '³Ùìr¹cjµzÇŽb—ºr»Ýf³™kïÚµK¥R‰[O(“ðM0>>33¹zõê­[·êõz|;^Èår™L¦›7oÚl¶©©)¥R¯Óéöïߟ˜˜ÈïXüÀápTVVú_±Ûív»½¥¥Åjµž;wN¡Pð>(ȆÛíÞ·oŸÿ›eN§Óf³Ùl6‹Årùòåõë×ó8œ ß ŽŠŠJKK‹‹‹S©T###V«Õét2Ænß¾ÝÑÑ‘žž.Ä  uuu¾g¿^¯×étýýýßÿ½Çã™ššª®®þꫯxŽÿh4š¦¦&ÿ?óV«µ¨¨ˆk#°n/kÆXllì©S§¸vww7·ËÝøø8¿Ãñæ{öÏÌÌùÄãñ4"ȃÓé,**ºzõ*cL¯×Ÿ>}úðáÃJ¥²«««°°ðúõëü'ÔH£Ñh4®½sçN½^?;;kµZkjjòóód ²²²±±‘1¦Óé|7ÁÏž=»pá‚×ë={ö,¿;]ckĵk×FEE9ÆØýû÷ù €×ÍþPÿ¼š››¹Æš5k|}íÇÃãÛ©ü/êëëÇÆÆü¯´¶¶rÏ~Æïk8ß"¹§§ÇwÑ×V*•ü~˜€ÿÀl6kµÚuëÖ-Y²¤¯¯ïÎ;¾Ÿòþ2È̆ ¸/õ¶¶¶–””ètºÞÞÞ+W®p?ÍÌÌäw8A–@333mmmmmms®çååmÛ¶MˆA6:ÔÐÐÐßßϳX,¾c>cÑÑÑGåw8þ`45Mgg§ÝnúôéÒ¥KãââRSSsssy/ÈOTTÔµk×L&“Õjíëë›ššŠˆˆHLLÌÊÊ2Ë—/çw8þu¼ •JUPPPPP„±pK ¤!@¤!@¤!@¤!@ÎYÁùâ÷/\ç©ÿ~Bê÷%†i†i†iŒmQ@fÞzë­y78{ã7nݺüz^f 3,Ò²eËt:ÿ•ÈÈH±ŠY4)66¶¼¼\ì*^‹4::úÎ;ïØívµZœœœŸŸÏï®Á!὿>öï_Øôôôèè(cl||¼¹¹¹¹¹9??ÿ‹/¾à«ÿàüþ%‘F£yóÍ7_ýõÇ[­VîE¡ü1333''Gìê€@ÀÌf³ÿŸçööv£ÑÈeÀb±H+x6ç3÷éééiii\›ÛÓSB$<½.—âºßŸ(õóxtpêÇ ùé§Ÿêêêüß nooïììäÚ’;TÂ3ˆbppð‡~ˆÍÈȈ‰‰ºuë–/¼Ÿâ(4ãÉ“'µµµþW ÅÇ,¹ðÌ|ÿÇô÷÷?yòÄívÇÄÄhµZƒÁ ÕjÅ®.`&22rÏž={öì»~à&HC€4HC€4HC€4HC€4œ²‚óÐÿËö/\眪K Ò Ò Ò ß›ëàÁƒ---ÏûéæÍ›C|GX©×d˜€4Ìs¥¥¥EDDø_q¹\÷îÝãÚÉÉÉb©×dÀ\GŽ™sÅd2qO ¥Ri0Ä(*R¯?Ȱz¯×[]]͵·oß-n=’zýB“ð œýãëë뇆†c …Âh4òسÔëZp~?˜^àâÅ‹\cÓ¦MIII¢Ö²R¯_hÀBü·}=pà€¸Å,‚Ôë`!UUU\#%%eãÆâ³R¯?$| ôþñ \[ˆÕ³ÔëÎÙ¥K—¼^/c,!!AŠçJ½þà@æ766f±X¸öÞ½{ÃÃÃÅ­'PR¯?h€ù™Íf—ËÅS«Õ;v컜€I½þ Aæáv»Íf3×Þµk—J¥·ž@I½þ`’ðM°p"""šššÄ®bñ¤^0aÒ Ò Ò Ò ç€¬à|ôO½ÿ€%†i†i†iêßûõ×_[[[ÿüóÏÞÞ^ÇÃÓjµW®\ñÌäääùóç>>33¹zõê­[·êõz|ê(++{ôèÑÂq8•••þWìv»Ýnoii±Z­çÎS(BÖê KJJJMMýûï¿>|ø¼‡EEE¥¥¥ÅÅÅ©Tª‘‘«Õêt:c·oßîèèHOObÉ %¡€šššeË–1ÆJJJžFÓÔÔäÿgÞjµqíááaž'ÔÀ=ûö¿[ù™™™‘‘‘7nø®¬ZµJÊ@ @pöw÷©­­=vìØœ‹ƒaч ]?ú·N¨Ï‹öÑG}øá‡b!M>Ðjµ¥¥¥N§³¯¯ï—_~™˜˜(++ëêêúî»ïðJ(<| Ñh4 ×Þ¹s§^¯ŸµZ­555ùùùâÖ!KÀg÷y­]»6**Êáp0Æîß¿¿¸]?ú·Ž> Q__?66極µ•{ö³¾F0G¨/Ìf3wÈ¡ïïÁððð™3gc¯¾újaa!÷˜ââb­V»nݺ%K–ôõõݹsÇ×Cvv¶…ƒ4„z~ûí·ŽŽÿ+£££ÜɇÑÑÑ\c333mmmmmmsþ{^^Þ¶mÛ‚R)HR¨àß0¦³³Ón·?}útéÒ¥qqq©©©¹¹¹™™™bW!-Ô0烟óÊÎÎÆ:7ˆ@¤!@¤!@¤!@¤á|œðâþ…ëœ#õßÔûèñXi†i†i†iÂ~#Ìétæææ>~ü˜ûgiii^^ž #‚ ¸\.“ÉtóæM›Í655¥T*ãããu:ÝþýûùKØ|óÍ7¾g?À¿áv»÷íÛçÿf™Óé´Ùl6›Íb±\¾|yýúõ<'ਣ£Ãl6 ×?ÈR]]ïÙ¯×ë¿þúëÂÂBnsË©©©êêj~‡jp»ÝŸ}ö™×ë}ûí·­V«@£€üpÛ@1ÆbccO:ŵ»»»cãããü'Ô P^^Þ××÷Úk¯}þùç ²´råJ®áp8§§§{zz|sïÛ2twwWUU1Æ>ýôÓØØX!†`A?€w¨^999™™™wïÞõx<¾ÏcjµÚh4îÞ½›¯8üÏçĉ'++ ¯ù@ ÂÃÃ+** Üë+V¬HMMå}§WþPYYùðáC•Jõå—_òÞ9ÈžÓé,**ºzõ*cL¯×Ÿ>}úðáÃJ¥²«««°°ðúõëüÇóÈápTTT0ÆŠ‹‹ãââøí(¨¬¬llldŒét:ßMð³gÏ.\¸àõzÏž=»eˇã9“““ÓÓÓŒ±“'Ožú§Þ@ÇHC€4HC€4HC€4HCât:srrRþë矻"à°œo {Àsá| €ùùŸo v- `~8߀ ï $Üþú8߀Ìsá|R€¹p¾)À?à|j$| ĺçPƒH“ð œo@ ð8߀,€4Ì/†»Uà ¤!@¤!@¤!@¤!@ZÀçdddLLLT cL¡Pzþú—wÿjµº¥¥%€zð6'P†%†i†i†i†i†i†i†iÿë"YO¯G¾`IEND®B`‚puzzles-20170606.272beef/icons/range-48d8.png0000644000175000017500000000175413115373741017302 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEỪ¼ôIDATHÇ–KhAƧ›ˆàA ô XDAMÑ´ "XªLzZèMmJ¥µxð’¦ -B/öaƒ AÑ›(¥/žjIº™ÙÝIv7Y6/(âEnÍÌæÑd·æ;„|~óŸÿÌ7Cè@]¾ƒ‰ëdò½ùA÷µKÁš®Û˜þ`µÎ>N®®1-GÖ³ºYvV^‚„ ¼(du*C]05]ÏÚÒuÍ\P 6B~>þ*\ÍŠˆ ó1B9—Ï2„jŒÇlD(D`MG2•"ÎgšzûæÝÇ´Š3ó¢bÿˆ°ý!•'ÛÐø|üÄQÿRÀб+€eÌë×ûuÌ*l~U½€üHZ° (jwÐBî,œ"²L+(OžjØ@ú&H ä’åÑ2Þ?H씽zÐ+ v–TU=ðÜÀ ‘âšÝ¦ ÷Œ¬Å%ÂF`…¸üLåE*)Å3ަ$fÒæ8NŽ.Äæ©âÑPÂ1±D(gfni…¯?iª* 'r„’K`ywª> b*YˆÄ "1AfF,5‡×v‰Šín>%«¶2¤€¶¥ °RöÈØ3e©Ð:|8ûíVÒD-+(cÓÆþ´bR1p›%[†K¨]ÓÐ3|MÀ¾ð­R¡ôAîå«HU2 hp w0 S ßZô†ÎÛ,•ÜÍï4Ç[„ºxûÀÍ8ÄžôÃ`¸„Ø¡È^"©»@6ppµ á"lÚ%i'Å7ìR+@qh†zzûxÕP(\93ó:ƒÝœÙ>2V¤ïʇ=-"º$˜¶œ‡,óëX)ð®KR,ƒ½KäûøÚøÜ{@ˆõ  ûKöhºþYy3ß°­7N:dò•(Ï¥¡$ öQKÒŽ5Á€Û}µ ~pï·U¦*í.™f¬?³U  œ>V«Às&&©"SƒãìûäÄìèø¿@Wƒó׉k0ÎÿŸú 7¯:YoXÈS%tEXtdate:create2017-06-06T01:31:29+01:00Zò %tEXtdate:modify2017-06-06T01:31:29+01:00dJµIEND®B`‚puzzles-20170606.272beef/icons/range-48d4.png0000644000175000017500000000125013115373741017265 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA† 1è–_bKGDÿ‡Ì¿tIMEỪ¼ÜIDATHÇU’„0ëÓy?ã¤×:;{uV·µ ®u [5Lv\ß«?4pëò¸~×ÍóýÌi/ä# jº¯ÜÓöÑ&vý‹^Hûô›>2¸© A”óí^Ú‡g¸!ìËÜ¿¼®ÕÉÁîí!æRÿ±åcÒÀL“Æ‘é£CêP’SHÎé¨|o0Iû„t!]³4@YE 4û;_}HÕAQ2SÜ2iVyg‰"Ö 9(,øaNPƒu(ž4Ì1-t•6“C…IX£³ ¢Ì·ë ¿ýIokà0¾LY8†A¶r`xS8€2\²A¦¹4ò…Ü‚ú.ä£D„(ªXÑ܉…TêUk‘ÞSYWz;’.ãµÀVÉ€KõàdšÀècš@@-v ZõaNöÝõÀB€mdë .}I® „42IÚÑ™ÃЛ­²wz«&‘¦½ö¯îý9â ½F”X+nšs‡ôð.Å2ôŒæä!TÞj©¾Ð°ž<¬l扞<ð‹Qòh]¾xØÞ·'xˆÜ4zx¢4l§€¼^¼äŸ9ì4ø»mßa¯1’×(ÕG2†|G”pCOA«}ñ0Ü\*÷RéÛ¸Ñ;Ž\ú™Þ_ÆÖ`ÝGgXÏ>%tEXtdate:create2017-06-06T01:31:29+01:00Zò %tEXtdate:modify2017-06-06T01:31:29+01:00dJµIEND®B`‚puzzles-20170606.272beef/icons/range-48d24.png0000644000175000017500000000175413115373741017360 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEỪ¼ôIDATHÇ–KhAƧ›ˆàA ô XDAMÑ´ "XªLzZèMmJ¥µxð’¦ -B/öaƒ AÑ›(¥/žjIº™ÙÝIv7Y6/(âEnÍÌæÑd·æ;„|~óŸÿÌ7Cè@]¾ƒ‰ëdò½ùA÷µKÁš®Û˜þ`µÎ>N®®1-GÖ³ºYvV^‚„ ¼(du*C]05]ÏÚÒuÍ\P 6B~>þ*\ÍŠˆ ó1B9—Ï2„jŒÇlD(D`MG2•"ÎgšzûæÝÇ´Š3ó¢bÿˆ°ý!•'ÛÐø|üÄQÿRÀб+€eÌë×ûuÌ*l~U½€üHZ° (jwÐBî,œ"²L+(OžjØ@ú&H ä’åÑ2Þ?H씽zÐ+ v–TU=ðÜÀ ‘âšÝ¦ ÷Œ¬Å%ÂF`…¸üLåE*)Å3ަ$fÒæ8NŽ.Äæ©âÑPÂ1±D(gfni…¯?iª* 'r„’K`ywª> b*YˆÄ "1AfF,5‡×v‰Šín>%«¶2¤€¶¥ °RöÈØ3e©Ð:|8ûíVÒD-+(cÓÆþ´bR1p›%[†K¨]ÓÐ3|MÀ¾ð­R¡ôAîå«HU2 hp w0 S ßZô†ÎÛ,•ÜÍï4Ç[„ºxûÀÍ8ÄžôÃ`¸„Ø¡È^"©»@6ppµ á"lÚ%i'Å7ìR+@qh†zzûxÕP(\93ó:ƒÝœÙ>2V¤ïʇ=-"º$˜¶œ‡,óëX)ð®KR,ƒ½KäûøÚøÜ{@ˆõ  ûKöhºþYy3ß°­7N:dò•(Ï¥¡$ öQKÒŽ5Á€Û}µ ~pï·U¦*í.™f¬?³U  œ>V«Às&&©"SƒãìûäÄìèø¿@Wƒó׉k0ÎÿŸú 7¯:YoXÈS%tEXtdate:create2017-06-06T01:31:29+01:00Zò %tEXtdate:modify2017-06-06T01:31:29+01:00dJµIEND®B`‚puzzles-20170606.272beef/icons/range-32d8.png0000644000175000017500000000155613115373741017273 0ustar simonsimon‰PNG  IHDR V%(gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEỪ¼vIDAT8Ë“KOQ€PIqáF1®Ü¸ÑHdAXè/ îHÜh⦠"1l4¬ 1±åaŠv¦Nl1$$îMŒ+c¡ssçu;v VþÎÒ†€¿Å“›oΙ{ÎI:‘žÔçÒÉ#èg{AèÏ,ææ€Üü£ì\.›Íæ§ŸÍ‹­lþ¡È~Ñt9àšÍÃï{‘Wvvœ–&õIR*çb"`JÍú´²þ‘¸¥ ‹`DP('Â'&@íb-Xœh8šîQÜPŽÈt÷†ßúž¦³æìÈ8.æÓÑâšnù«³ý%ƒ?®4P]”ð›Ý9P€XŠajÂKºM1¢(J„ôB`Ù€ÅUêØŽe³på+;æ®*„þš\u²«R”—§Uväʤ­L=·k0ha‹ f¿þLE°SÕþÈ:e„2Ó)b‹Ô_Þt%Œ4‹SÐØ'âL‡ðäñ¡Fá “ðaEùL€þ_ ¢„ùÏYÛÀ5#S®Q1Uì%Ó4¨q0Í—¿š»@Ü*Û~r1à>„"p[ˉ01óøIÂ}-¡T™^z#umJ4êÂu±JàŽâªlì,}ØÒõ/›U² 2 Þ”NŸÎH·bæ0æXáÊwDY{ƒC c!&QÓÔ6¼Í‘±y(G„ùù¼A¨W/)^xL0âL&6 î·í™«ntL 4(… Áû»#÷x;ÃÅ]Á‡v!l¸j•¡wë–á„pi¸#Üþ4€°µFv£?#ÿOYç¯H=Bè•®• 7jAUdY)”'Ûïžø{wƒ¾z»$íJ‡ SäIìp%tEXtdate:create2017-06-06T01:31:29+01:00Zò %tEXtdate:modify2017-06-06T01:31:29+01:00dJµIEND®B`‚puzzles-20170606.272beef/icons/range-32d4.png0000644000175000017500000000072313115373741017262 0ustar simonsimon‰PNG  IHDR V%(gAMA† 1è–_bKGDÿ‡Ì¿tIMEỪ¼IDAT8Ë…“ Ä C{ô-7cµNg–~ÔxÚçùk`^Çí%µ,‡`_Ázz€fiL‡üÐ÷²sΖûd.t•3ÇC¢Jäñ$õësíÞœ+:5F¢EÖg•ÒKÒqÄÎE×@õ•/ìÖ[bìc¦(˜Ío!m¨¼I.µajP®ƒ¼NUƒÞp *€sGÜai”ûÁé¸ÈÝœ@̶Z‚FEì p«M®×(¹ß7IXh@A ŽÓÙ•áF½ 1¦D‡çt’!ÁB}ø§³ê·ÃaŠ›ƒÑë Ç«HI˜Ú|×@ÿ8kP—Æ“·„ñ©×ˆ¸‹Üüæ×½8|Úp?_'í·á%tEXtdate:create2017-06-06T01:31:29+01:00Zò %tEXtdate:modify2017-06-06T01:31:29+01:00dJµIEND®B`‚puzzles-20170606.272beef/icons/range-32d24.png0000644000175000017500000000155613115373741017351 0ustar simonsimon‰PNG  IHDR V%(gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEỪ¼vIDAT8Ë“KOQ€PIqáF1®Ü¸ÑHdAXè/ îHÜh⦠"1l4¬ 1±åaŠv¦Nl1$$îMŒ+c¡ssçu;v VþÎÒ†€¿Å“›oΙ{ÎI:‘žÔçÒÉ#èg{AèÏ,ææ€Üü£ì\.›Íæ§ŸÍ‹­lþ¡È~Ñt9àšÍÃï{‘Wvvœ–&õIR*çb"`JÍú´²þ‘¸¥ ‹`DP('Â'&@íb-Xœh8šîQÜPŽÈt÷†ßúž¦³æìÈ8.æÓÑâšnù«³ý%ƒ?®4P]”ð›Ý9P€XŠajÂKºM1¢(J„ôB`Ù€ÅUêØŽe³på+;æ®*„þš\u²«R”—§Uväʤ­L=·k0ha‹ f¿þLE°SÕþÈ:e„2Ó)b‹Ô_Þt%Œ4‹SÐØ'âL‡ðäñ¡Fá “ðaEùL€þ_ ¢„ùÏYÛÀ5#S®Q1Uì%Ó4¨q0Í—¿š»@Ü*Û~r1à>„"p[ˉ01óøIÂ}-¡T™^z#umJ4êÂu±JàŽâªlì,}ØÒõ/›U² 2 Þ”NŸÎH·bæ0æXáÊwDY{ƒC c!&QÓÔ6¼Í‘±y(G„ùù¼A¨W/)^xL0âL&6 î·í™«ntL 4(… Áû»#÷x;ÃÅ]Á‡v!l¸j•¡wë–á„pi¸#Üþ4€°µFv£?#ÿOYç¯H=Bè•®• 7jAUdY)”'Ûïžø{wƒ¾z»$íJ‡ SäIìp%tEXtdate:create2017-06-06T01:31:29+01:00Zò %tEXtdate:modify2017-06-06T01:31:29+01:00dJµIEND®B`‚puzzles-20170606.272beef/icons/range-16d8.png0000644000175000017500000000100113115373741017256 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEỪ¼ IDATÓeÌËJÃ@ÆñSÛ‰ AìB]¹«/!TÜû0¾„¸ÚâF°JkIb2mÈEB'P{!&—I"Z)ŸÂqíY}üøs $!„$©RFë£è\節¶ftJ_À«lARù,÷¿ØÊ@ÝlYóû“t]±'ê"úðØËΓï>@¥Xþ&¾yçYÁ(Ú,œõÉøýU›†¬#@)Ô›ò„:™Z`½ø1vÆIÚ\Étñÿ,—dDÉA)—6ê‡õƒcÓ¶[— ›Õm(C-M9uééÜØÚµ\V"krÔrD±#ŠýOžñaq¸›UXƒ=MÓå&¸—ðï~C‚U­o %tEXtdate:create2017-06-06T01:31:29+01:00Zò %tEXtdate:modify2017-06-06T01:31:29+01:00dJµIEND®B`‚puzzles-20170606.272beef/icons/range-16d4.png0000644000175000017500000000044013115373741017260 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA† 1è–_bKGDÿ‡Ì¿tIMEỪ¼TIDATÓe@1CÝÑÜÌçéÙïB†¶3³<":H^È:”}iF2qAåqÇG0ªW2¦1˜/–Sž·µH×v·Áþ0$YŸ{ð!@‚«Êœv%tEXtdate:create2017-06-06T01:31:29+01:00Zò %tEXtdate:modify2017-06-06T01:31:29+01:00dJµIEND®B`‚puzzles-20170606.272beef/icons/range-16d24.png0000644000175000017500000000100113115373741017334 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEỪ¼ IDATÓeÌËJÃ@ÆñSÛ‰ AìB]¹«/!TÜû0¾„¸ÚâF°JkIb2mÈEB'P{!&—I"Z)ŸÂqíY}üøs $!„$©RFë£è\節¶ftJ_À«lARù,÷¿ØÊ@ÝlYóû“t]±'ê"úðØËΓï>@¥Xþ&¾yçYÁ(Ú,œõÉøýU›†¬#@)Ô›ò„:™Z`½ø1vÆIÚ\Étñÿ,—dDÉA)—6ê‡õƒcÓ¶[— ›Õm(C-M9uééÜØÚµ\V"krÔrD±#ŠýOžñaq¸›UXƒ=MÓå&¸—ðï~C‚U­o %tEXtdate:create2017-06-06T01:31:29+01:00Zò %tEXtdate:modify2017-06-06T01:31:29+01:00dJµIEND®B`‚puzzles-20170606.272beef/icons/pegs-web.png0000644000175000017500000003241713115373722017231 0ustar simonsimon‰PNG  IHDR––³cæµgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEá‘ëb4IDATxÚí}y”Tõ•ÿý~ßR¯ö®ê}VPQQ„¨Ai@6“fœscŒ11NŽîNÔà¨D5ÇÄIÌÄ“IÄ3sŒ#É (Q@¢q”Md“î¦÷ª®ýÕ[¾ßß·ëõëªW éÊ9ÞÃQ¨z·Þý~ïw»÷~¾÷’={öÀgôLt¼øŒ>)}¦ÂxÇ[ÆØx‹p2$ç|¼¥¨ºÝnAÆ[Цd2Iéø/cã¬BBˆiš---n·›sNï)O(gOOÏž={&Ož<îKÈøÏBι ýýý}}}’$UÃÒv)òÆç\’¤îînMÓ(¥¦iŽïÈZýÂ9÷ ¦ „€$qB€s0M0 Bé¨"QNJ)¥´\µ¨2!d;…sàœ¦ahT0 Bx½fM K¥¨aJ¹]Ú*¡jQ¡#qÎ)¥Vеóâ¼)Ý (æ¦Mþuë‚Û·{£QA’`Ú´Ì’%‰/y82Òéj8¾äSU«PE]׳Ù,î—Š¢@…ÓT„l6«ë:H’är¹JŒÔ<üpóš5a]Q¶ªÂ;ïxwìð¾ôRðÑG{Î=7JÑjšÕ¬BBÈàààÐЪªœsQ½^occ£Ûí.=ñ”ÛÛÛ‹Å4MY–ƒÁ`CCC1KŽsp¹Ø~мfM­ pAàŒÎ ïÝë¾é¦ ¿ýíÑÓNÓTµºtX}ëBúúúºººTU%„PJcÃÃÃGM§Ó¥—DÓ4;;;ûûûu]ÇC‡®ëýýý¦i:=Oü~öÊ+5kj ƈiT4çÀEÞÓ#ýð‡Mœ!ㄱS5ªRšJ¥úûûQÖç¢(f³ÙÞÞÞbŒ¸ÿ Åb1Q-MBDQŒÅb‘H¤ðI)ÏfÉ‹/†ðïŽë´aزÅ÷þûn—‹WÁÁÙ&ÿx àLÑh-h{⎘N§S©”㹂RjÆððp¡žP»ÃÃÆaØy9—‹wuÉï¼ãÆŠÎoJÁ0Èoø…q^Eki•ª0›Í‚ÓÉ…b†®ëÅÌƘ¦iŽ+-!DÓ´¼}”s ”«*‰Å4‹öå00 T5hl¼p¦Ò»]éoKü‹1âÇ¥ƒßV¡+·JUèõzÁ©Çc²,+ŠâhçáÁ¬yßBcn·[Eûô% ƒƒæÄ‰øÒÆþ8€3ÎÈâ0Þ=4JÕ¨BÎy(’$)O¨†ššT¡##¥4CÎm1¢Újkkó¶IB@Óhk«~É%IgÝŒAM9~"“!UeàW“,9✻\®¶¶6Q Ãà92 # 566sµ ŽƒÁ`ss3çÜ4MdÄ¿477'^®ëdåÊH8l)Ô"!#á5×DÚÛ5M«.ë¾JM{ÆX ˜4iR$I&“¸~ÖÔÔÔÔÔ”õ£rÎëëëÝnw$QUE ‡Ã>ŸÏ‘‘RÈdèŒêý÷÷ÞuW«®BÐYÀsÂ9˜&Y´(þï d2´ªVQ¨ZcÌårµ´´àšIÁIV‰ƒsî÷û-Y¼ÅžžHÐ+¯ÍGm:xÐÅX–ƒ,ó¯}èæ›$‰£‚«ŠªW…‹@þ½²+¬^J!™¤óç'fÎLoÝê{ã $"H?ûluÉ’øÔ©j6KQUeQ@•«ð¥JQ‡¯X»êªaœm¦I4 w»ÚæÒg*C”‚iB2IíþJyUAóè3æSn¶UÙrYœª]…öc¥¼:—²ñ¥êU!GÜn.Ë&!`šDU©¦‘Ï™GUªBÆÀãa°oŸ»«KbŒx<æôéjs³žJ †•lNc½0'¦v‹·êlˆªFr>{ûmï³ÏÖ½û®gxXJy{»ö…/Äo¸aÐçcªZÞË%º¼c'„»!„‚€>„*ÁÕ• ªS!càó±µkÃ?ܤª%„pÆÈÑ£®gž©ë-ïO~ÒÕÒ¢—Ð"öþðð°å Âã0Ê‹Å à „x½^ô¹WÞБªK…Œ×Ë^{ÍÿàƒÍ¦IÂΠïÚå¹çžÖ_þòãbq;Ji:>~üx:Æ D)u»Ý­­­§ô”¢”F£ÑÞÞ^MÓPg‚ ƒÁ–––*¹Aá óx 0† áÉ'M“P † a,‚À·mó¾ðBÈç3M3£"„¨ªzìØ±T*…x D`¤Óé?þ‘8ޝÆ(G4íììÔu]ä€H$ÒÙÙYúƒªR!cDQضmÞ½{ î8Ú6£Ñ¼Ø@÷¦ª*Þ³±\kˆI,õ%†a  .­ðˆ¢Çc±X5¢H«L…àrñ;¼C9{ >øÀÝÛ+Ê2{ù躞H$ =ÄÝ$ ÝÉQߦR)UUq7‹ÅÆ»‡œ©ŠT”òTŠ”ñFšF Ã!zŽaÅbŒ},ö-\‹MÓ?;Î6ÞŒ!Æ@QTcE.Pˆ$C{ #š Eû¢äM—ª½YE*¤4ž~Ê`útµ¡!QDìŒÏ9ØÓ4}>ŸÃþ™ ÷{<Y– ¯9â?Àx÷P‘ol¢P®ªä’K’§Ÿžµ.9.ž‹'êêŒÂ}RWW'IjÑ"Ó4eY®««+6 c’$ÕÕÕá)ÆbÃ0|>_MMMuÚøU¤B0 ›·Ü2œƒ Œq‡¢ÈM“œ{nfåÊH*%žzp2Mœ8Ñår™¦i†a¦iº\® &”° q"ÖÖÖ¶´´ Ê‘—s 'L˜PÇQ¨6Óƒ®Ë—ÇŽ“Ÿ~º—CT$ÞS1 2yröÑG»ƒA³’Œ1æ÷û'Ož‹Å2™ ¸Ýî`0ˆ¸Ò îÆï÷ã2íóù*÷ìŒ U— €PUróÍýS§ªÏIÏ–åÅ˸_žJbF {wªñêmmm§x""ð·ð(zJ¥h"×ð«Âû¢Ûíž3g΄ N¥ÉO)ýàƒÐ:²ö1ï —ËÕßß*SÀà€Âûf… ¥¥œmãE†a„ÃaÇ388xjú ßÂ;tèP{{;#|ïâ}}}…]ÉùÈ™r¢r±s#€â*qô›Ø_ 'ˆ$ûdúyñž[OOÏÉ5öä¶Ðvýãq&ï> c@( SŽé:QUoñ•îÆ@@Q˜ËÅ)匦QU%˜Éelò<ËÀ9Hw»™$q ùª*QUÊX™½ÉåâŠbŠ"€a€ªÒlvdA.-0¥àñŒ4–s¢ë$“!èCk¤I’òxE‘+ w¹ZAÙ,QUjšåæd™»ÝL9ŽU¥ªJó\ŽÇÑé¹õ_Æ@Q8çðî»î7ÞðŠ”ò3ÎÈΟŸ8í4-“)%Æo“IaËÿŽÞTŠ* ;ÿüô%—$Ãa³„;óx½ìøqiófÿþýŠ®“PȘ;7yÁi— JÜ-b $‰KÿðCeÓ&W—D´¶ê $¦NUuèz)^·›ë:yë-ß›oz‡‡EIâÓ§g::’--z:MQ°ÂÅÿ{½,7lð½÷ž[U©×kΙ“þüçS>ŸYäVòÈK<vô¨¼i“ÿÐ!c¤®NŸ7/9sfM,‹×Q…ÄJ)Ëóù|§vÚ¾}û,ýy½ìÐ!×êÕMo¼áÃûæØï~¿ùµ¯E¾óYæšæÐ)œƒ×Ë^ÝÿØc}¤X¯&&LÐn»­ùò˜cêÎA€þ›ßÔþò—u‘ˆhñ \pAê¾ûzgÎÌ8f°Ã‰O<Ѹn]ý÷…-_»ýö¾pØtDl àã½÷Ü«W7íÜéµò*á°qãƒ_ÿúcsC’¢ðuë‚O>ÙÐÕ%Û;eŠz×]} &³0Ø?ÿyýš5ádR°xE‘wt$ï¹§wòä¬58ç{÷î=ýôÓíÇá»ßý®¥a¼=488Œ‡½ÿ¾ç†Ú?øÀÍ9AÜ!À9Ñ4úöÛÞ”Ë.KHÒÈbk—Ìïgk׆︣m`@B‹ òÆbÂ+¯æÎMæÝ©Æa.üþû[ž}¶^U)À/ẻåõëƒS§f§NÍf³$ï¥.ï듾ý퉛6ù1î/¸}à {ö¸·o÷ΟŸ ÍìÂáb56“¡[·úúú¤Ë.KàE§<^‡ýô§ «V5ÇãB^cÅõëƒá°9{v:O`ÎA!›¥·Ý6á¿ÿ;¤ëcË9|Øõ—¿fÏδµi8O8‡P($Û"¥Î*Ä_Å„[ni;|Ø%ŠEgŒ`|Ý•‡¹ ƒ,X°k›ôöÛÞ;îhËf)¾˜sbñâ€Ú¾Ý;uª:c†joÎÝçž«{öÙzAਸ਼/NDžÉÐ;= &B¡Ñ€DnÏ ÷ÞÛ²m›Ï.°•AFyo¯ÔÝ--]Ç_¶x].ÞÙ)ß|ó„ÉJ:c˜R¾{·Ûïg]”Êk¬ÏÇ6l<ð@ ¬…5M²}»wöìt{û˜4œƒ¢°ÿ¸ñÅC–ÀVcQàx\سGYº4¡(Œs À Uè¼Bãú¿ÿ[³g[¹a¼E¯ÜÀóχ÷íSp¿´Óþg]:MÁ!¿c#¹A~ñ‹úL†Úz$~ü¸ôÜsu0öhg‘iQä]]òóχñ¶¶Åëñ°­[}¯¾(Ýàx†zõÕÀÖ­>‡Y0F\.þüóµÝÝ2ºÑ ÆýêWuÇÉÖH)¤Óô¿¨Ç1äØXAàé4ýå/ëòäQ¾¿²vmÛå(°(òÝ»Ý/½Tãõõ:¨ª±˜ðê«(ºC¡U•nÜeŽá‰`ß>wé øù¾}ÊÎ+™cÄíæ›7ûûûÅwÀwËO,Ëc4±~}À’­mØ´ºƒseÖÓ#mÞì+ÝXB``@ܲÅïv6Öãa;wzöíS XãÃ;wzöïw»ÝÜj¬,óW_ ¨êÈBU‚wãÆ@,&»Dî< 1b°¿Rº;0t·gbý:çD–YW—„¯,Æ‹$]'‡»\®‘ÁYˆ/-‹9xЉ’–!eš°{·* Ý»û ,I<r•Pƒ%Ò¾}Š5 Q ‡»t”k,  ]]’,款gÛêÆb¼°¿+•¢EA—Etœƒ®þJ ²’ÎY¼%bîöÇÀ0òŒ-Ž¿V;“ëî1ÂYgæ8÷S½´@`À³k9¿‡\¦Ó“Ø0H‰dEE÷BQä¡YZ8üÝpØ´«Ù4‰×k”Q$~0{Ã#¡e¦þb§¯Å‹§ÿJz¤¶Ö´sá^èõ²¼£¦ccC!Óno˜&øý¬ÂÆz½Ì¾Ñr¹Æ–Qd(d:ÁEFÈA…˜Š%2/¾8PÞEÔÑ‘°Àd”rU¥Ó¦©“&•OcP[kœ~:“¡ø ^Ì›ÄóH±×áÃ矟niÑ5mô8#Š|Þ¼”\—ð«yóöÑ4ÒҢϚ•.ÝXtbÌ›Ìf‰%p&CgÍJ×ÖyfÕXs˜4);}ºj5–n¤£#Qºoñá‹/N…Bf±ˆˆsã^µbÅ0ö¦#'ž6§NU/¹$™ÍŽØ­lnÖ¿øÅx‰ÞDÉ-J`üyñptÁ™ /LA‘0hlÀŠÃ8¨-ÙL“\~y- Ç¡ƒm ‡ÍeËâv7…i¯—­X1 Å\Ö(ÌE¥fÍÊày³Y2yrvÑ¢D õc'|ñ‹ñ¦¦Q¼!ÍÒK/MN™¢â©Õ±±Ø–åˇKìµÎ*H&…K/M~ãC(œƂ֫iIâ÷ÜÓ ™º>:)å©”pýõƒ³f¥Ñ°w(¥#ø—É“³·ÜÒŸgÚ£{ì®»z37g2sÆ`ÅŠá+b‰µZއû)S²ßû^¿Õéyãß¿÷½¾)S²vcÓ],_[¾<†½içµÍ»ï1fÙ›oîŸ4)[¢±³g§¿ùÍÁdR°¥†]‡Pȼûî>Iâx$O`|øúëçÍÃz EБż38®?ÿùT"!¼ÿ¾Wsk1FÂaã‘Gz–-‹ç9q‡ðxøÜ¹©ýû•cÇdëóœžÈŒê“Ovvšfh[ÃÈĉúôéÙ;¼±˜`}n™½Ë—ÇV­êAÜ®~JAÓȬYEáï¼ãÑuš·á) »ýö¾ë®r ú—\’<~\Þ¿_±Ü–À­­ú~Ôuá…é<^ÜtÂasΜÌ{ïyúú¤ÂÆ^|qêG?ê®­5óܳ¨þ©S³&è;vxÒiÁê^l,!äÚk‡î¼³× ü¶RïŒõC„Àe—ŧMËf³dhHDW{»ö¥/ÅV­ê¹ôRçj¨‰PÈüÂbµµf*E# Õ3Ôk®‰>ø`Ok«nŸ vÞl–L™’]´(!<¢Q½6]”ºå–þ›oE^Ì[mdîÜÔ¤ ƒD"B*%@c£¾hQâûßïýò—cé´ƒ{—,—‹/[oo×2:4$â qÆÙú§á‡ê)æ˜ÍíÆå—ǽ^–LÒHDÄ#Òyçe®¿~èÞ{{C!gÇ,6væÌÌ¥—&9‡XLÀQ[Sc^ziòÎ;û®¿~È4‰}£-Ta)77äâ ~?ËfIw·œÉB ¦ÆliÑud2´˜½ 9¼ÏgF£b_Ÿ¨ëD ¡A¯¯7’É27uÑÿ«(¬·WŠDDô¶´è^/K$Ê öѵ„U|Øïg­­!LÒ˜ll´ßÏR)zü¸”ÍJ!6š›õL†:zóí/EðzÍÁA±¿_2M$ÞØh„BF"!”™&Á˜ÚñãÒð°À9¸Ý¼­M“eŽ@{}…B7wZï ”cÌGº¦Q€Š°¸CÈ2Ç8e.ÜS>‹^JYf’œ1¢i÷Œ²/ÅÖ¹\6M‚Á .ËØX¢ë i´r1Ô…Å‹ Ldy4^˜ÍÆòyUX(›õqWŒÆH&Cðš§ýdQšðIà º©B^T•¦Ù®P^À³Ÿ½±'$0–&9ÑÆbÊ7]'h&YiÝ+á=éI§?ú$y“Æ…×:VüC\‘ ýOV€åź²|£þÏ“ãý; üigïr¸ÂÆ–W¡iEa²ÌuX¿+Š<.ƒ A±<†'ï‘÷‰…yýH)x½ å‹PF™3äŒKE˜$®ª¥P¹Æ‚ÇÃq·"”ht–Åìœ4YØ Ã Ö’$®iDUiÙåT,ûë€ùñÇò† ×_÷÷÷K‚À§LQ—-‹/Xp»y1 z×Ün¶k—gýúÀ¶mÞdRp»ÙìÙ©Ë/_xaJÓh±C)ž?M“lÜX¿>°{·Û0H8lÌ›—¸üòø”)Ùd²èÀãèÐøâ‹ýh•Nœ¨-Y_¼8Q[kƒ± Âöᇮ ‚[¶ø¢QQ’øÙgg–-‹Í›—”$À3jY²ÌÕJ@ÕžËdȺuÁ ‚~èbŒ46ê &–.··k‰Dèzyì̺u5?üaco¯dÅðð/^˜ZµªçÌ3ÕBKÙòŽþìgõ¿úUXö0éW¿¹ë®>Ea…~?lROôÐCM7ò^ šÿïÿõ¯\qÌ{€1ô·Þò®ZÕrà€+wÊõ?è¹øâ”£y‡1ØçŸ?õTƒ=[>þeñâøô65é¥óÝ VÏÀ ‘×…{<죔lþÛß¼y/mlÔﻯïŠ+†O;cš$`ÿó?¡;îhK&¬þfý¡”wvÊ[¶ø::’uufá=?—‹?ø`ó¯]‡^DZøûï{r-[–°V?Ê2D„oœ¸}»±vÞl–nÚäW>wnª;ãõ²mÛ|7Þ8±§Gʘ_y%pÞy™É“µB^¿Ÿýâõ<Ò¤i´°±*;vx–,‰ç9fóô—N§{{{{{{‡‡‡³Ù¬Ëå*V”ÁZGޏn¸¡}ï^wac“Iá•W­­ú¬YU%/<à…ÇÃöíSV¯nB—7c`ÿƒÖ^g§üÈ#M¸#ZBbýœ?ü¡æ…ÂøÖ<^ƈ(ò¿þu­×›_¶CùO4îÞíÅ‘¤3ö?Øw?ùIÃ[oyíXŒÜ ‰«V5'“‚(ò‚—‚(òdRXµªypP´÷*êþ­·¼O=Õ¹(J¡À»w»Ÿx¢÷rGý%‰#GŽD"¼%bÆààà‘#G+áBešðÈ#M#€¼÷¢y³zuã¾}Špxµã§»ùÃj¢QÁN¸nÚä߱ë(Ì*r„^ãßý.œ›Û?ŽÒ¼ðB¨¯oôâ4ÂöïWþô§ 8ÁI EÑ4ò aû·¸ ¾újàÀF~à€²q£?ìÃ9¼ðBƒï…{ (´n]ð×Ë!SŠ®ëÝÝ݆a`ªšÜp5M;~ü¸#:^QØŽÞÍ›ýöãžpžD£âþPS¢¼ª3vF’x$"lÞìÇ‚"„cë/ñKÇÉ„GÐ={Ü{ö œ¤vÎNyǯÇÃrP¢(lóf?úNKÃI¶o÷vuÉVo¢WvãF?”Œ âW7¬=Ø*ø³}»* mÞì·Ã®ÀVJ(›ÍæMð«t:ÇónŒpN$‰£À%NæØù[¶ø#¡XÔ·(v&›¥]]”$Œ„;&ÛPhDùÐPN9?KÞ,EÀ—–ðþàÞÙß/&“Ôþ ÎÁŠŠ”¦?–í+° ðd’–Æ\Y"uuI¢èðVèsê"ÂSó"2¹Nîì”­n,A]]Â9+ÖMp²î‰OÂø y«ç§’ŠªPQX[›Vš×¥övÍÔˆ_ ‡MYæ¥+MãÑÔ4zÃ’0 hkÓ¡$Å:pûýc‡”B{{‘ÚÛ5{$Ù4‰ÏÇôÒØiÂ=…äv»[‹k©cyÆ« •ÅÎL˜ ©P ;ƒÑ¾ŽŽR5p 7Y-JXeŒÁ²™³ÎÊ@ñõ·º‰µ9sRé´;CçÏO ²´8eÑÚ:jàùkñâRhë«E‹âÖê»¶6í¢‹J…ð˜êv³ŽŽ„…É}5R¢slV(òx<…Ujp¬/^œ°ºÑ‘°ó;:’'ŒÁ3ÒUW ‡BF±p öÂÂ…‰Ù³S˜8rƒÚïg+WF¡Å t|õ«Ñ†ÃÔØ›S§ªW\ÈÏXbéc³W_ͪ*Y¼81eŠŠ9GM“L›¦.^œÈó W_Å•Ã10‹=°bElêTµ°¶VºommÅ EÖç†a`µ”Â^ T•ΞZ° ãÏQè–ºêªá%NœM{’+FU[kþå/ÆH¡µkšdâDí‰'ºB!f÷=R Ù,9çu`@üàw¡‰¼K—Æï½·ÏñÎ߬Yé¿ýÍÛÛ+ ¦ðåÅ{ç}W^K$FsjáÐ ÍÉ“³7Ž@¤óÞkšÄï7Ÿx¢ûÌ3³öã3ÎÐDÞ|Ó‡M(øÜs3«WwKR>àÃê=EQ°> jQÅP(ÔÚÚêv»òMaXÎ=7³y³? ‹ÝþÐCÇçÍKZPà^ &fÎÌLš¤½÷ž;‘ÀÜ`™/º(õä“]“&iŽø Æ®Ãï½çA£y9BÈÊ•‘ì)ìkwt$»»¥ƒûK9‡šó¾ûz¿þuü  &MÒÎ??óÁîÁA1wêTõ‰'º/¼Ð¡)ân.¼0][kîÚåÉdh^c—,‰?þxw]Y"vB¡Pmmmmmm(*iÇ «¡Á˜;7uð  O§v›šôG9¾bEÌ68aàzžŽ“7llÚäïí¦MS—./XP”ònî÷Þs¯_ܶ͛HP‡£›ûsŸKi-vWÝÜŒÁÖ­¾ ‚| è:©­5ÑÍ}晹¹7nôoÜøøcN;M[¼8¾xq".ãæöùØ® hŠI?çõòËc—\’Ä1ýé¹¹7mò¿òJàÃÓ„¦&ÝÜ'ŽqsŸ$ðâÓ6•­Ÿc]˜FgœT°ÉŠÝ À•›Þ–®Î`ÓI/g³¤àz£U!®(¡’òBƒbXðÈš7ÛðÖnÙøÖMN$NX`üqU%ö´3'Ý8QÂ[mˆt²¨ÂÆB…Q{ÇCZåòcá4=5¼'-ð'¡O"ð `gìHˆj˜ÅøIx? žåDé“|ê©"Ž7q—W9ñ“¾Âj¬®“ AˆãEeTˆã10³YÒÙ9ÍÖÖJ¡À55F4*vvʆ‚õõz}½Q¶hJ].ÖÓ#E£‚ͲPà±òT­ìa€š#™>þX¶ ÀMMz®\Ô ¼´ò÷~BÞR*DÃÀåbþsàÅC;vxâq&NÔ.¹$yÍ5‘³ÎR‹!;0$­ªôÙgëÿ¢iDøôéêâʼn•+#¡™NK( >;zT^³¦vËßáÃ.äÏš•^¾|xÅŠcPöl ”RìˆJ2Yâ9–Rxá…ðºuÁwßõ¤Ó”˜<9ÛÑ‘øÚ×"ííš#b#O”RË〱ߊÐ(ï U*jTXø—Õ«›Ö® [‡]ôãõÆè½òÊᆡþº»¥»ïnµ !öÿžu–úøãÝÓ§g -tÔßæÍþû·–ãÇ¥BÞ+®ˆ=ôÐq·›•È@ˆ &Óé´¦i ˲Çã)cAW&Cï¿¿ÎymiÑyäøüù‰ÒZÄbAX¥FÇ#Šb…Ê ”f2™l6‹î:Ç*C'fTpNÅ|øáæ5k˜ ÅžMx4*Þygk `.\8¦aöK&ém·µíÚåAü„ýT"|ï^åæ›ÛÖ¬9Z_?&¿6Ú¹»vyn½µ-ì¼$—–ì ÀOt•„èºÞÛÛÇÑ×%I’Ïçknn–Š¿)…hùÓŸ‚˜?„±1?.ÝzkÛo~sôœsÔbÞ BÈÐÐÐÀÀª e“z£7¼»»;‹á˜EÑãñ477»­d%tïø©i‚ßo¾ñ†ÿ¿þ«#vÐ ûØcö´ø°×k>÷\Ý®]|Æ.ƒU´çÈ×ÓO7äÕ ¡t<þxc<.äñâKÑ ýÇ?_~9ˆÁ¦Âî0 ãØ±c‘Hæã<ˆF£ü±cîPô¾ürÍÿD7ºiÚ›3"p<.<öXS±œR:00ÐÕÕ¥i "„d2”¤ôúËëêê0MæœÇãñ£Gfðôq*D÷ÝË/-Ž“š ¥pà€²u«ßåÅÎÈ2ëé‘ÿüç„aìíµ×ü‡¹,ð©xçÏÛo{¡àƒó‘€Ñºu5©-” þ$“Iİ؋ö¤R©Â‚?µO¥„—_@±Ü(ÌÛo{wîô†îP[ýýýV¥ «ÊôõõéE 8Yc±X4-8›Íö÷÷C9*жm+'±hË–‘lK0‚áûö¹v‘Ru—€Rß}óÎŒò¾ù¦·ØÅe»úß}×sü¸$ËcÃ%‹+î"”R\Zí½‰Ø™înéÝwK%ÊÜýž7ßô* /ÄÎÄb1 æagP¤BìŒ%0ç<: ,B2™tm”Q!äâ…Xû±lÞ™hT°0ÔP.Ï~›HŒI§B)¡Lš R)Ši ’&ñbC“ˆn-„pM#xþ,iëØŸº®ÃΘ¦©÷YÐaG^¬Ð%=æE„¦Û,{$FÓÛÎ[ l™÷äA‰×%Ç%&]shRñ1[ì«Vº¼À²ìüXÙ,ì¥t@‹iW’»½èqÆë5§MË@ygÎ>[µö-B¸¦ÑÖV­¦Æ,Á¸ ,sÌx‘ËãºN¦OÏ@Î8#ö4 +øƒõD ‹ö0Ƽ^o^Á|i8lœqF ´·Àô陼…êñù|ŽK%Šäõz‹ˆ”R5 ŒadÇÄåeT˜‹€³%KJçâ“,^ÇBר™ ™>]=»Tü|útuÖ¬´1¦”g2¤£#ÙÐ`”@"!oGG¢¹Y×4š§BJ)Võ±w þ“RZ[[›×шOhjÒçÏ/ÓXΡ¡ÁèèHf2$ï1ÆX ðz½…ØÓ4ñ«b¶ç¼¶¶6/³UFØú ŠS©lW^9|öÙLsPèGÇÇ×¾™6Í¡8ç·¾5èñ0G( ¥#‚›n°›=8!ZZôn@Ø€ƒ- ´k®‰äÁ,Uùýþ¶¶6J©išXÏÎ4MJikk«ßï/ï”òl–®\ikÓBVŠío}k°¹Ùy_#„´µµùý~Ã0XŽLÓ¬©©iii)¡œj&LEÑ.0缩©)›¥‘€å®Å˜gŸÝ²Å‡™R­”²¸1F/ŽßO^–U QScnÝ곊ö`–UL ·ÝÖwõÕÑ„'ºNfÍJ÷÷K˜Ïâµ^ZSc>þx÷Ì™GÀ6Äãñøý~<â˲ŒÅxFVø<žÝŒI“4Ä’;6ö+_‰~ï{ýV’¤BEql³ÍKÔ³k1 bŽyI’ü~KKK(*d<1à‚v­^Ý´eK~bçk¯|ç;’ÄG%z57mò?öXãc;Oœ¨Ýv[ÿW c ”BFAJùo[ûì³uCCc;Ïžºï¾ÞsÏÍ”uWæJ_ƒœcïÿþϽzuÓ;ïŒIì\[kÜxãàµ×–JìlQžX'àê,8¹òž ðÂJ¯þþûî7Þ𠈔™gfçÏO`~–€O+½ú¶mÞ;<É$u»9¦W…LÇ\Õ– ‡õôH[¶øöîuë:„Ã&¦WÅRéÕ? åÒ«ÃΞ7ßôE£‚$ÁYge::’ÍÍéÕO=U¤Âööö<ì ÖEp¹¸¢0tÁcÞM£„”‰¢aÚ ·›É2G,…¦‘L†ÉCÓ:v¨$q·s€€iÖ øô0,Ãì`U4X­"N·J?ÝÈeáN¿oß¾2nnënjÞ熉„uuS .WE/æ²YLZ;¤äñ"ö²°àaXŒÚ J?EýAΨH§i29ºk8¬°âú§(Šsg:XùBôôôtwwŸÊr‹Œ1EQjkkµ˜4©8÷Êß—ÊVy!„¨ªšH$*þÉ¿Yhq‡‚?è‘Û³g†W•O ¡ÓkΜ9§§§§p°R›“,ÚÃ?AÁ;oáDk=‘HtvvúýþS¼œz<ôž;üA»xòäÉeÁGB7`KKK$Éû ·%ŸÉòÈ^˜ÉPÄB–Vç#×ý~ÝuºNÒiŠ—7*à—‹»Ý&î…è>uÜ€ý~ÿŒ3N}±t4­æ/¤hWž2iP……#øXããðaæOÆ”šFJ¢â1aÙ×'¾þº¿¯O€ÆFcΜTc£‘J•9BË2—e~ð k×.O"AE&MÊ^pAÚçc…f ná§^…yÛXö‰O[| Ä„€×Ë6l<óLýG)ˆ€pظì²Ä­·öãß±hÞNúÙÏêÿûpOˆÎ[AàÍÍúÕWG¿ñ¡b‰01CDOô“Ÿ4¼öZÃ/œƒËŦLÉþë¿,]Ç»ãÛc…4êƒr]]ªªÉdR0•#ûÙÏx ¹¯OB³ÿL†îÙãÞ¼Ù?{v¦¥Å(,$I<“¡·ßÞ¶fMm"!àrŠþ¼DBxóMß® ’²ìP¡Èãa{÷º¿ýí‰o½åÃ[Ñè1 Ú×'­_ „|þó)Ì®oEòêêê˜ãM§SHUP•ÓFè xùåš§žjàœX©(-†(òÇ]÷ÞÛ‰…wÞE~üãÆèÔå ƒX)u1SÊÜ(Ic¼ö‰DÄ{ïm9rÄ•K' †A¬IÌ9yꩆ—_bPa¼ûi U— E‘G"âO:’ÿ%/o ªDøîÝîßý.ìõšVoæ Ey~ÿû02ÚS˜û½µ¿ÿ}øí·½öúööùÝï»w»íÙ×,^ËÏüôÓõ%2OŒU‘ x±u«ïȹ$høóm?ÿ9h„rb,ƒ¹~}Ðþ¡$ñ©tÂ\xuýõ¯~·›}¦Bgb \.öÞ{n¨ àϾ}Jÿh'Œ6ìÜé òμóŽÇžwF’øÀ€Xºî’%Ò®]n«@U•P©r7С‚Ú;ÌËŒPìĘGy¥/ ᦠå¢r#"9¦ï_ª.2F|>Dû”z ­o+å”E~E-–è±ýÚÈÅJ°36÷rµP©oB#b£,væœs2£vb®0ñHÙ¤%_œ²'-Ñ4ÒÔdœsN*ÀÎ|îsi eR%TU*äªJ/¾8uÖY*/Uï‰Àå—Ç0¡Ší:.|á qE)š²—_EáË–Åì!hà ¡qùå1(®~Œ”͘¡^xa ÃúÕCU¤BÈ]¸ýö>ÌF™—zƪŸ3wnò+_‰&£Uñ:üy祿ùÍQÜ bÿ œwÞ˜ë8‚À“Iá+_‰^|qª°hFK0æwôùýe±,§šªK…»Z¸0±jUÛ=reÂV ƒÌš•~ôÑã²Ì PñÉÐï~wàê«#–]ˆ˜FìÂù—ÈM7 N#ÓEá?üa÷¬Yi´ ±J9äPxè¡ãóç'R)ZU«(T¡ƒ 7§ .Hîs©HDŒFÅL†rN(å§Ÿ®­\]µª§¶Ö,ÌbÝ%[¼81a‚60  ºN9'ŠÂÎ>[½ãŽþ›nÌ«Ÿcñæ*ÅEÅXLÀxS(dΛzä‘ãK—&,°VU9ØFãózB Ø:uêððpoo¯e«£·öïWººdÓ¯—MŸ®65éɤP"YŠunL¥èž=î¡!jkÍ32XP  T¤‹öôôHû÷+˜p©­M›6MkíÅû½½½ÑhtÚ´iF‰{ާ„N5t B½ ¦NÍžsNO"™ aagâݶٳSV¼0“¡øaé—š& ‹ëèHâµ)M£(É)2œU© !×e™ I§ÅÜ'¼Bö~*EsYcx…’+ÚƒWÒ!ªfª^"a1£“`ÌèO’w\0;'GU­B+;N¦Jö\ʾ¿o5g,ªU!ö£¢pYf8!ТPUZ:Û ä@7XŸÄ •`P¼êrqë‰iM#è­NEV£ ñd(ËìÕW_)ø ‰K/A‚ÓÂÏ ÞzË·q£3DNœ¨-ZŸ3'-ËP¢Ü œ£Qqýzßoø"‘‘‚?K–ħMS³Ùò£g\¨êŒ Óä²ÌU•>ýtýo[‹@È™}“'gÿíßz,pN‚¦È‘#®‡nÂú–#”s˜??ñýï÷ž~z¶îÆçc¯¿îôѦC‡F‹€,ók¯ºå–—‹i!¤ºŒŠêTx'FÓÈm·µ=÷\atÍ`yiBàÐ!×7N|饚Âtx#âÀåºëÚQ¹[Q#»àæÍþë®kÿè#¬¼2潘Çö¥—jn¼q"êO¿è Ñuò«_ÕÝv[›¦ûµò*¡ªS¡ÛÍ~þóú×_÷Ûcø³Sè:yøá¦={ûÝDÔ}&CV­jîê’1añbQä]]ò~МɌÑÎÝ={”ÿ÷&4V‚»£îµ×ü?ÿy½ÛÍÊ&´?ÅTE*äd™=*¯]“©È"tCG"âÚµaûÌ]»i“ûvoé‚?Û·{7mò{_éÔÇUKÕpSmüU¸ Žûp>!ª«Å´¯’îøG¸ZTø4ý™5}ø¶ ±r%tEXtdate:create2017-06-06T01:31:14+01:00ú”*%tEXtdate:modify2017-06-06T01:31:14+01:00‹_,–IEND®B`‚puzzles-20170606.272beef/icons/pegs-ibase4.png0000644000175000017500000000113113115373741017611 0ustar simonsimon‰PNG  IHDR““÷‹Ã†gAMA† 1è–_ PLTEÀÀÀÿÿÿ€€€ÿ.dp6bKGDÿ-Þ oFFstJ™ùtIMEỪ¼ vpAgà#zõLIDATXÃíV1‚0d`¬(RùžŸ`¡ÿágúŸ@iáx&!Ï „-€3Ù†Âe½#›Û«ª‚‚×gˆuÚºìuѽRC4RD€Ü—Hµe=€²€Â”e½ò°:ËZlR[ý+ ë1çWÅÎóæ/Ы˜ï±;TPPPP°ñÚ6É:F¤ËÖeçÁí9>9‡Zêݳ–q©|,†Lã`Ör%¸91ÎÇÖ¤i_áÄ^#8kµÏo%ÓÞ¾jß ¹m´x'÷ å5ÂÀƒ–»Šö¿ò>Ñð&C2î1–-ÃÖÁ{Ž«Óêê M’×àIyQsØ9 ë1çWÅÎóæ/Ì« ï±;T°!âb¤§#9å¾R©)'þ#1åé)'ÊšŸrÉû8ÍŠ'€lq~Êýô>;söÂÂzÌùU±sÄ<ù ó*è{ìíìN£}9Ñ·%tEXtdate:create2017-06-06T01:31:28+01:00³-ù½%tEXtdate:modify2017-06-06T01:31:28+01:00ÂpAIEND®B`‚puzzles-20170606.272beef/icons/pegs-ibase.png0000644000175000017500000000240713115373740017533 0ustar simonsimon‰PNG  IHDR““½;Û'gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<´PLTEÕÕÕÿÿÿêêê²²²­­­ªªªÓÓÕ  àXXîù ýþ ýYYí  ßššá ýþÿù››àÒÒÖUUî ý ýVVîÓÓÓ«««³³³66ô77ôÆÆÆ¬¬¬TTîý¿¿¿œœàÅÅÅù¡¡ßÃÃÃWWîYYî üü ù[[í¢¢ßÔÔÕÀÀÀŸŸàÇÇÇZZí99ôÒÒÕàžžà®®®ïïïKu%¬bKGDÿ-Þ oFFstJ™ùtIMEáb¼š* vpAgà#zõ&IDATxÚí›{WÚ@Å·%A1>b›ò¨¤U*J£¶µÏïÿ½J¤Ø03é9³;›ÊÜ?Ù{¿ÂfsÏcT*•J¥R©þêW¯;ícŠâЗu[±2)Ó‹aêîí÷’ÃÞÑq·-L'½ô4«”¤ý³V0 Îßdkåo2LÃQ'G“ÑBz—g›Ê/ž¡¼2M‹"®TÓíÅ÷6R–}8`º\U_ÖOêHË+uåi¶FZBÍìÅn?ÛÖÇ®g¦á&RGö=µ—Léµg¦‘ÍTÌ­Õ›`:½õÌÔ‰mM¬Õ^©ï™©¨1EÖêÈ´ðÌ4®1Ù_”€L‰g¦ˆ¼N‡ Ó'ÏLò~êƒL¥g&úwýxÉg&z:÷§{ÏLf¶y—ןx%´øÞÇ—Ï»5Tñ¹¾x<ï¾ïLf­¨ŠèëöâM*4Lf8ŸTç§9x~º¨Ÿ¾}a"5°®T~ûŒö<þ£LW[B’–?×~o¹~,É¢¼»ØøTßï”I™”I™”I™^"•‰á†p™n–‰†P™eõÎIB½›S†P™e•‰Q†P™e•‰Q†P™eØ­ÿ]÷':£ Á21Â.à á21ܰ{çLeR¦ðj#Ó¯ßík𱑴i¦L»Ì×À 8R0`Lh LÀ€0á50„×À 0Q0€LT LÀ2Q50ÈDÕÀ U0€LT LÀ2Q50ÈDÕÀ U0€LT LÀ2Q50ÈDÕÀ ðóŽ¨ s^0`ç'´&`@Ï™X LÀ€ŸÇ‘˜€zok`†ÿìýN™”I™”I™þ‰y5J>k”x&Ö(ùLìIN§/ù‘W%§Ó—üÈ«’ÓéK~äUÉíô%?ò2Χ/ù‘—q>}ɼŒóéK~äeœO_ò#/ã|ú’yçÓ—üÈË8Ÿ¾äG^Æùô%?ò2Χ/ù‘W%ÇÓ—üÈ«’ãéK~äUÉíô%?òZÝSN§/ù‘W£‚db ‘‰5J31e’gú-\L© õ*s%tEXtdate:create2017-06-06T01:31:14+01:00ú”*%tEXtdate:modify2017-06-06T01:31:14+01:00‹_,–IEND®B`‚puzzles-20170606.272beef/icons/pegs-base.png0000644000175000017500000000725113115373722017364 0ustar simonsimon‰PNG  IHDR,ÉðbKGDÿÿÿ ½§“^IDATxœíÝMoׯñ33©¯ÐÚN(©uï&;*¡¾ ¶‚JmY”M[µÛ®»«t× RôT| (*ÝB!¨HPÁêª‚êÆ‰œ8™‰iÏÜÅpäÄŽçõxæÌÿ·Ç'Ê¿dìÇxôè‘°‹9줭d´Ñ @F+­d´Ñ @F+­d´Ñ @F+ÙȰo€j‡öMÈ’¥¥¥»wïÎÌÌ û†(•»V [·nu:aß ÕrÚŠÇû&dC+!x^ìG+­d´åôÙvN8ޏwoìÆ7îÜ[Yi·ÑQ·ZÝ>~üÅÉ“ÏÞÃä·b/´B[·oúᇩVk¤Ý6ÇðþñùsãùóÂü|õêÕJ­¶}öì±cëý)D+4Ôé³³Sׯ—76zßt:Æúº±¾^ø÷¿ÿùå—kgÏ.Z–«øF¦­èËqœÕÕUÛ¶·¶¶Ç1M³P(”ËåjµjÆôÈ#‰ˆNÇøî»ýñG©Ý| í¶yíZùéÓ•+QŒ.ZÑÛÚÚZ£ÑB8ŽãýK§Ói·Ûÿýw³Ù|ë­·Êår:#.^œòY O»m>xPš:~!Dœ–x¶ÕC³Ùl4Žãt^»¼œŸŸo6›)Œ¸}ûÐõëeÿ•ð¼|iþüsynn,hœ®h…̶íV«µÿ‡u7×u———mÛNU„ãˆK—¦‚VÂÓn›.Lx‹r„Vìá8ÎÂÂÂÁ?¯×uý\RYĽ{cËËᯬŒÜ¿?úËuB+öX]]õa×uCÜ]$ñË/o¼|i½=]í¶qãFÔ'Kz {ضíÿw³ã8!Z‘\ÄÜÜX§¾ŽcܹÃS !h…dss3ÑË'±²õÅ•+â5èVìáºÁ^³ñöƒä"Úíðwž~õ˾ {ýÛ™eþåš\ÄèhÔ?Ãñ"”´BR(½|¢ããÛAo̾kÈã;ïö£{”Ëeÿ¿ËMÓ¬T*é‰8vìE”³6,Ë=~üEè/× ­Ø£Z­ú¿°a!Z‘\ÄɓϊÅð­(Ý“'Ÿ…þrЊ=LÓœžž6ŒÁO[½K†8‡/¹ˆ£G7&&Â?ˆªÕ¶ß}w#ô—ë„VÈ*•J­V;ø§Ö4ÍZ­úÁ„" Cœ9³P*…yÆ\*9çÏ/ð&$߆&''ëõºeYûpMÓ´,«^¯OLL¤0âØ±õ¯¾Z ZŒRÉùæûƒxûÑ+œIÞ[¹\~ýõ×mÛ¶m{ss³ûæ‡J¥R©TbyEBgÎ,>yRxøÐïÉ䥒óÎ;íS§ÃÅi‰Vôešæøøøøøx¶",˽rå¯K—¦®^|Jy©ä|ýõÚéÓ Áÿî¢3Z¡!ËrÏ[øüóg³³ÓKK#/_ÒùQ–å‹îÄÄö¹s ~È'­ÐÖG­_»öŸû÷Gýõ;wµZÖÆ†9:ê¼ùfÇûŒ÷ÞÛðñJXÑ ™¦8ztãèQ^o †× ­d´Ñ @F+­d´Ñ @F+Ûî=”<£=°‡’s´böP hÅnê÷P2:£=Z±CñJv‡c´Ço‹Wï¡dw8&h…Ê÷P²;“´Bµ{(™ŽÉ Z!„Ú=”LÇä­BíJ¦‡cr‚V¡v%ÓÃ19A+„P»‡’éᘜ B¨ÝCÉôpLNÐ !Ôî¡dz8&'h…j÷P2=“´Bµ{(™ŽÉ Z!„Ú=”LÇäß!”ï¡dw8&'hÅ+Š÷P²;“œI¾CñJv‡c´G+v¨ßCÉèpŒöhÅì¡@ЊžØCÉ9ZÑ{(yÆó-@F+Y€GP‡Nîv FFF>û쳬Ÿ²´´t÷îÝ™™Ÿ—çy¢A%„·nÝ ô’À­xüøqÐ/Av5 ï¥2-èÛªx^Èh £€ŒV²ø_ƒR°‡B‰.ì=òyQïï¿ÕsÅãW}…"‚Fx?äo¿ý¶ÏÐØZ1p¥«TrÂí¡AD¸ˆá´"Њ¢TrŽiÚC!‚ˆÐA[a}ÿý÷>/ê½›qiiiÿ]¸0ýÛo‡üÒýö¶Ñj,.¾öé§~?0†"BGx?´“““>¯-†ç) öPˆ "ÞˆƒEm…‚="ˆˆ7b ¨­P°‡BñF µ öPˆ "Þˆ¢¶BÁ DÄ1PÔV(ØC!‚ˆx#ŠÚ {(DoÄ@Q¿^Á DÄ1PÔV(ØC!‚ˆx#ŠÚ {(DoÄ@Q[¡`…"â(j+ì¡AD¼Em…‚="ˆˆ7b ÎT°‡BñF,ž3É?þxý÷ßÇVVF¶·}½Øìí¡\¾<ï¿ÖD:"è™äñ´Â4Å_ÍH­ ­àSÒ­d´Ñ @F+­d´Ñ @F+«.D¤«.ƒ‘žXu€ˆôD(ÀªË`D¤'Bâ8ÎêêªmÛ[[[Žã˜¦Y(ÊårµZ5Ã>¸aÕÅ"Ò±ÛÚÚÚ“'OÖ××·¶¶\×B¸®»½½½±±Ñjµ …B±X qµ¬º‘¥ˆÝšÍf£ÑpÇÙ·áýãüü|³Ù zµ¬º¤b惈{(¶m·Z­ý}ØÍuÝååeÛ¶ý_-«.i™ù ÂgD—ã8 WÂãºîâ⢟KzXuIËÌ>#ºVWWý_³ëºþï.XuIËÌ>#ºlÛöÿëßqÿ­`ÕÅ»†áÏ|á3¢kss3Ð5û¿<«.B¤c惟]Þ‹°þu:~?=ŸU!Ò1óA„ψ® ž³|F«.Þ5 惟]…B!Ð5û¿<«.i™ù ÂgDW¹\öwašf¥RñyaV]Ò2óA„ψ®jµêÿš Ãðß V]Ò2óA„ψ.Ó4§§§ —é]Òÿ «.i™ù "ÄJ¥R©ÕjÃ4ÍZ­V.ø³«.)šù "ÄÊääd½^·,k7LÓ´,«^¯{§Zª‹ßJDz"v+‹ããã###NÇû#†eYÅb±V«Õëõp§‘ V]|""=Ã0J¥RµZ­ÕjµZ­Z­–J%?Ï:úaÕÅ/"Ò¡«.Á‘žXuâǪ ­d´Ñ @F+­d´Ñ @F+«.C‹P@£PU—áD( ÇQÄ‚U—´G( ÇQÄ(h+âyhƒ£Ý6¯]+?}ZHn¬$µ’¡ï¡¤ö(ÔGìÆª‹ÒˆÝ2±‡2PBGo«.éØM=”„ŽBqÄ~¬º(ŠØM=”„ŽBqDO¬º(ŠèÒc%¹£PÑ«.Š"ºôØCIî(TFôê‹¢ˆ.=öP’; •ý°ê¢(¢K=”äŽBeD?¬º(ŠèÒc%¹£PÑ«.Š"ºôØCIî(TFôŽøõzŒ•°‡òÿkþQ¨Œè‡UE]zì¡$w*#ú^[į×c¬„=‘š£PÑ«.Š"ºôØCIî(TFô½Âˆ_¯ÇX {(é9 ޝ3úUè1VÂJzŽBqÄ~¬º(Ø-{(%tñF í“ú;ãÒ¥©«WŸÆìmpœ>½ôõe="Ðã(bô½x¬º¨ŽP@£ˆ«.™‰P@£ˆŽU@ƪ ­d´Ñ @àÝ[ËËË7oÞŒñ½CaYÖ‰'ưoH6ø1F'î+æææ²^ !ĉ'b<¹Z p_133“ÜíP†J„àÿ5M=ð¼Ñ @ÿª‹ôŽaÕ%œg|èmš@AϕЭØCá˜#òÙ AíÐc8Fýª‹~x\¹ãâÅ)Ÿ?LžvÛ|ð 4;;•·íÑŠWôŽQ¼ê¢+Z!„.Ã1ŠW]4F+„Ðe8F媋Þh…º Ǩ\uÑ­B—á•«.z£Bè2£rÕEo´B]†cT®ºè Ǩ\uÑ­B—á•«.z£Bè2£rÕEo´B]†cT®ºèV¡ËpŒÊU½Ñ !tŽQ¼ê¢1¾ ¯è1£xÕEW´bÇ™3‹GŽ´ýÿHy{(§N-æ-B{´b‡e¹W®üåów­·‡òÓOOí¡è¡½«.z`›&PDÐ==ð¾íÞôމ‘Ï÷mÓ $Ÿ­ày £€ŒV2ZÈh £€ŒV2ZÈh ã3É{Ócr…U—p8㣇¬L®(ˆÈç´blM®(ˆÈg+xµCÉV]¢ãqå=&WXu‰ŽV¼¢Çä «.± Bè2¹ÂªK\h…ºL®°êZ!„.“+¬ºÄ…V¡Ëä «.q¡Bè2¹ÂªK\h…ºL®°ê¾ Bè2¹ÂªK\h…ºL®°êZ!„.“+¬ºÄ…V¡Ëä «.q¡Bè2¹ÂªK\h…ºL®°ê¾ ¯è1¹ÂªK,hÅ=&WXu‰ŽVìÐcr…U—èXuÙ#[“+ "XuÉV]XuˆVà ùlÏ+­d´Ñ @–»OI[^^¾yóf§Ã)Óè+w÷sssTËÝ}ÅÌḬ̀oÒ.w÷À@´Ñ @F+­d´Ñ @F+­d´Ñ @F+­dÿ.¥2 qšIEND®B`‚puzzles-20170606.272beef/icons/pegs-48d8.png0000644000175000017500000000251313115373741017136 0ustar simonsimon‰PNG  IHDR00`Ü µgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ</PLTEÕÕÕÒÒÒÓÓÕÝÝÝÜÜÝØØØÕÕÒéééíííêêêííêËËËßßÓÈÈÔ¾¾¿×רÜÜÔà11öü))ø‹‹ãÁÁ¶¶¶®®®ÎÎÎààÓÿ††äääÖ¾¾Â¦¦¦ªªª::ôþ##÷ÒÒÖú üÅÅÜÆÆÀ°°°ššá--ö%%øŠŠäØØÔÏÏÒ¬¬¬¯¯¯«««ÚÚÚÄÄÄâââàààÞÞàââÖææéêêèÁÁÙÍÍ×ÝÝϾ¾Ö••âúyyçã!!ù}}æãƒƒå……ävvè––á??òÙÙÔ55ô((÷¼¼ÚúÆÆØÂ¿FFñ««Ý§§Þ¬¬Ý““â;;ó¢¢ßŸŸà»»ÚÏÏÚqqéxxçÊÊË ýJJðBBò³³³±±Üÿÿÿi-¬gbKGDdÂÚ¸ tIMEỪ¼IDATHÇÍTm[Ú0M.¶¨D@¥- *Áù‚s¢ë†2Eqè|ÛÜËÿÿ»I[ZܺO{Jzž$'÷&çžòo%”ú•ĬOŒ´ Ùiú˜õZRµIüO%§¦¦±Ÿ¤©±ù¹è(ÓgtFÉlʈ;ÅÎ <ÉÎÍ3c!³Uä5lP’èØFw+tÊе*Bڎܿ&¹ƒÏnfU¡Û¢ÛM3@tWt‹wÌ 8Æ@x:0‚?Æm…¸3ú!µå¤é!à~Èg¨>ˆYËs‚û[WJÃ}“û£Á¼Ý¼ZaXÀæ[¥Þã™dÖÊ¥Þ‰£XT­àGnÉms, -¨$OßGTõF¡/2÷¯žÏÁn?ÿzJçóîžÒe™{UzD”S ”¾”~º„nH{ã9¥ú¡pß¼ºÁúîí¸û¾EFu·ú–?Ÿ¼zîi~ÊAú|3W—w¤¾è¥Û¨Òìúj¹¸*õBÔ*¦•rB£þì Óê ‰êÀ˜`¾¾6áö¨Áq–à¬Q QU‡ˆü6KÉÙ~dLjîNº›j%tEXtdate:create2017-06-06T01:31:28+01:00³-ù½%tEXtdate:modify2017-06-06T01:31:28+01:00ÂpAIEND®B`‚puzzles-20170606.272beef/icons/pegs-48d4.png0000644000175000017500000000066013115373741017133 0ustar simonsimon‰PNG  IHDR00*lgAMA† 1è–_ PLTEÀÀÀÿÿÿ€€€ÿ.dp6bKGDÿ-ÞtIMEỪ¼ÍIDAT(ÏÍ‘1Â0 E›J e(H°3²uGˆ‚Ô Tâ@9CŽÀ :tD2¶[QéŽå!/±o(ám›Ks]o1c{sÎÉ@I ÉB7 &ÌÙj_ÿü¹5mÛ´«Éu¶‚zN›c÷Oi3yŠ%ÅŠûõÔé)Öd4ìµ@¨¨_<¥Rr‚ä,(: ž8„9Gà†\&ùq6:Љ²'H„K"Gªé.DÃ(§ÒýÔt Sˆƒœ4†9m†A´/tÒ)xË_{ŒÖf©‚ïýr%tEXtdate:create2017-06-06T01:31:29+01:00Zò %tEXtdate:modify2017-06-06T01:31:29+01:00dJµIEND®B`‚puzzles-20170606.272beef/icons/pegs-48d24.png0000644000175000017500000000504013115373740017211 0ustar simonsimon‰PNG  IHDR00Ø`nÐgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEáb¼š* $IDATXÃÍYKlÅþýff7~­×ŽãqúHKA$P! !.œ*ÄDAé#MQO=!À;¨¥J”F¨HB¨*TÄ‘â„DPüˆ7ö¾wçÁaÇqÜ‚øÏaåøóì|;óý¾ùfƒ?ÿü3ü?5ò_nlð)åß» ""âBÄL&ó»)ƒ„qï'¶1€"„X–õ§¤DD`L ¡?KÓ4—––¢(²,ëoÏñ0!D”RÖëõÁ SJmc¹œä×שeÉtZv»Ä0èÚÚZ.—ûçÓCbŒé©RJ%IÂ#„H='R‚eɯ¿¶Ï+/-™““üرÖáÃ×ã˜QÊþæø7'¤”BÄ(ŠVVV‚ 0 £R©är9)¥ž›k׬cÇvkµÛôÌ™JÁ‘#Ýju§øŒ*ûjµÚív ‚ååeÎ9€øÞ{%¥À0PªàÂ…R·KSú7;L…AèµcŒ%I¢Ë‡RåûdiÉÎQ) V3®_§Œm×ÛNRJQJS©ç9ç†a˜¦©”3¹kWŒ)ÄÞ Ýv[R, ÎwʆF-ÙÔÔT>Ÿ€t:===Íè­ÑÑ£-H’Þ ÀììZ>/8Gý›Þpû^¦6ŽcÆ¥´o-Z×W®äÏž-//÷ªì©§®Ç±¹ºZO§Ó;âCx£Íõ&>Ç=Êf{>Ôh4vŠÐ 7ב·&\—& Ú¶P :ЏCbþSB„|¯AJ •ÿ¯ÒŠ¢H»ö Ðp$úÏÛ°åowêAe b†+++aš¦Y©T²Ùì¿>CÕjÕqœþØ|«ÉT«U×u1‚••!ÄŽYÐvBÚ©Ã0ÜîÔz›ãœDÿ-Bz˜t:Í9ιiš¦iê ÿFèŽí°]CJ©©©)¥”ïû™L¦R©0Æ-@£Ad³ÙJ¥B)Õ„v*ÅŽ dšæÌÌÌ`DÇÆÆöíÛ×G…:?‰ö?ÑÒ¥:Ø…ü‘RÀ˜¡”ÚnC¨¾c,ŸÏçr9!(…71ÌAã8Ž¢¨ï # ”*Ü#ç8ä~ÛQÎùÄÄD¡P@D!€ReÀ9pŽ„lž”){h’€Hˆ2 cqq²Ù¬~øaBRB>/|ŸÔj†m‹ñqá8dõÎóyÑíÃ`N§P(Œ^2½w~ñ…ýÆ“++F±(ž~mvv-Ž{™:›•Ÿ}V8{¶\­¥Ÿ];r¤†ˆ„0Ë’<~þ|¹Ñ0&&ø‰­gžiÑl2yùréí·ËÍ&›œLæç[O?ÝŽ"F)ä@_|ñÅA6W¯Z'Oîn·™èyôÛosé´zøaÏóˆmË/¿ÌŸ>½k}qŽ®K¯]³l[<ø ïyĶŧŸΜ™ît(çè8ôêU«\æ‡ù®K ñÑGÅ—^ªt»”sìtè•+Öôt|ï½áꪗN†¡«• ÍÐÅ‹%€^jÖÒ[X_]e¦©âß¿Œ) DÀ¥K¥v›š¦ ‚ª5§Ñ>(9S®Kô5ª¯/–|Ÿ it“!E¤Z5`kjnµØúº’ÔjÃh³É:jšÊóh½Î´êûh£Áº]jšÊuI£1ŒÖëÌó¥0è¬[›NËÛoô éã)LOÇå2"Ìåľ}ldjîÚ—J< 1Ÿ33ñºwo\,Š0DÛ{÷£33q>/8ßr*^²ãÇ[©”Ô*ÖÏqâD«PI‚ˆ07×2 ¥35çss-Ë’œ#cjn®EH/qëëÜ\3–œc*¥ææ6óøÆÝš†¡”Úb¤›¢F„8Æ={âðVW$Áýû£—_®>¼®'6ŽqÿþøÐ!¿Ñ0„À¢W^©=ùdÇu cExÇÑ=÷øõº!%<¾öZí‰'œ>zð`x÷ÝA½n(…wݾþzõÑGßg¾ïŒmŠz8SëÚ€n—f³Ò0”ãlæ0*Ž3Í夔ày4›•„(×F…@×%¹œ¤T91MZ«Õòù|&“mŒ„€>‰ê0ïyDWÜ_D]—cÒ÷%!ÐéPÃP¹œŒ"LÂØ¨Ø¾Ý© !%..š¾OŠE1ˆ*Å¢Í Fõ¨„%‡ò­îǸ¸hÆ1‹bH=º ;u6+?ù¤ð曓ժaÛâ¹çÚóóM­D^¾\Ú÷âR‰' *¥ ÃÈd2:q'I’N§MÓTJr޶½éòý¾û÷G¶ýgN}âDK—´R½yšŸoÚvï…ËÉ“MíãJõg뤤Øï*usSiù¾:jóq—úGã Ã-ܦ¾à${;n8|+E®¸i€·Ò¬ˆjPÝ o¤ê\M{ÎDóã“Ür+õãñ‹Ì­Dß’ŒÕ+¬Ì³6V}ýõ^xd&I’ôI&–µÌLõQm*½Ë×Rehÿêû\¸IÓS ŽÓt{’In… @—+LÎ!œdþ+>‘Â%M £±÷%tEXtdate:create2017-06-06T01:31:29+01:00Zò %tEXtdate:modify2017-06-06T01:31:29+01:00dJµIEND®B`‚puzzles-20170606.272beef/icons/pegs-32d4.png0000644000175000017500000000071513115373741017125 0ustar simonsimon‰PNG  IHDR ’ggAMA† 1è–_ PLTEÀÀÀÿÿÿ€€€ÿ.dp6bKGDÿ-ÞtIMEỪ¼êIDATÓAJAE…éjí…à"s“©ÁƋ鑹‡GhÝçF™€Ð# {7„XqUPUÿÿÇG`/Ü0ƒÆ)F•ˆDØA’¡z¯À-º% F Íg°ÍÈC™ Ê«7ô’`.Q ð=š"`sÃÞƒP‚´÷ÄM`€ÐF…Ø» ´`fïK÷1ÉdëÙt´&<Wòg7c8åcW.3Ü)/]ÝÏØ]Í;=ôûF6Wf–@–ŒÇkèñX~Vœwpç×¢´ÿ÷YÖ|ù…[\}ÉïêPÐw_PÒ@×¢°&«å¦‚BiókÔ%tEXtdate:create2017-06-06T01:31:29+01:00Zò %tEXtdate:modify2017-06-06T01:31:29+01:00dJµIEND®B`‚puzzles-20170606.272beef/icons/pegs-32d24.png0000644000175000017500000000346713115373741017216 0ustar simonsimon‰PNG  IHDR üí£gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEỪ¼;IDATHÇ•VKo\Å®ªó>gÆžxL’q<Ž=„HlXÁŠ[P1&Š ,@‘#ñ{ØÀ‚@l‘P,PyDZp¯‚Ç ‰g{<¯óè®bÑçŽ ÷Ê®Õ9ÕÕ]Õõ}UÕ¸¶¶Ì ‡DDÄÃXÅ6ÛÂ0üÇe`F@ËÂ,˲,;’Üã8ÃEdxºëJ2Ä1¥©³·×ß÷yãÜ3ïîî3‹ˆeY"ÌŒ¾Ï÷ﻟ~ZîvéâÅ?_|±³·×+£a‡ÊªÁ€ˆâ8®×ëY–U*•cÇÆt¿O.ÌllxüÅ›'O>ƒÀ;¼AÄF£Ñív•R?Î2EüóÏáÆ†çºây2зß}ŸEŽ2 ¿|ß­µçyD¨ŒiÈ2ÔàøquèÌ?íµÖår¹Z­ž8qbrr’z=zé¥þåËMP _yeïüùÝn×":û±,Ë`nRŒ¾Ïëëþ`@/¼0 ²¶·wÂ0ð¼#``üÑZ!èõèùç"èvÁ²ŽZdO; "­53;Ž3¤¹mS¯§™Åu-Ä£%ç)ˆ8 677 MËå²ÖÚ²¬^¯W¯×µÖ•Je||üHÇmrBDÍf³ßï3ó“'O´Ö¦í48޵ÖÛÛÛÃÔÙ‘  A‘ 6 C1JsúQû]Þ‹ M‰(˲±±±¡r||ܲ,¥T¹\fVJÛ¶f–ÿãŤÄı²ÖR*•͹Ã\3ñcãFÉÌ®ëŽŽŽØ¶ËœX -‡Ù6Æqlú®=\ö}ñ¼”D°×#D`† ÇIE@»]±,Ç÷µëŠh½3„!Û¶€R$îÞ^Ûu=ÇqÈœòà7??õÖ[3 #aÈZcò½{þ{ï~ûí™+WŠQÄI¢µn_»¦.\;¾¼° Ìís{q‘_½<77¶¸ÈJíöûIÕêêÚÝ»k7oÞ™I„Hä“Onn®,-Ý«TRA"þüóõúÊââ¿Êe âyüõ×÷ëõ; ÿ.µQ ê»ïî߸quyye}}˜1xe%øí7×uÅq®\)ŽŽê[·Â?þpüp>Ëpb"+ùÆ(ËèܹÝ>Úîõhj* ¾y3Ôßxc÷ý÷›Õj)"üòK—.ýùÎ;­vÛzî¹$Méöí€._n¾ùæn«û¾gY”wSC~ôÈé÷iz:ÕµDÞÚr“§§S¥rer½î(…33é`@Ì@žÇ¿ÿîÀÔTšev«Õ)Ú¶cÿ§4@)œžN Ë0Iв@kÐkµÄ\?Ž‘ Ó¡JE#B·KD€Zƒž=›@#3 æe‘ÓÔ0òÒ¥é×^;óå—¥0d¥0ŠøöíàâÅ™sçžýæ›Ñ(ÊqsêvÕÞ^fÛùö(⥥Âìlmv¶võj!ŠXë\]]³mi·­ÙÙg·¶S5¼ùê«í on®ÖhØ&œÏ>{øòËÝÁÀîtÚõz]DN:U*¹®úõWn®6ø>õÕÃgžyä8£®k3ú¾¬®[[Φ?üP(õòrØh؆¦píZÁuY›Í¦i'FÃéõëÑ`Ó4Žéúõ}š¢dV«irš¢RgÏ&IB§O'¶-I’+Ïœ‰ÍÅ‹Å"3k­‹Å"fÙ>N†©µZòß4­TÔñãêÖ­çæv>ø ÙéPµš•Jzy9gä»ï¶â˜$Š¢ J¥Òøø8€¤)Öj©eÁ;ëÊüüöÜ\»ÙL‚Àµ,kŸ¦…·Zv¿““Y“鎅7všâÄD6а_šç™áF¢ˆ?vàäÉt0pvvv …‚mÛû¯ f°m S¥æ‚Ìà8‚išstØñÍÌjŒ¥aùA˃C?'þÁe"P ÍÇAùûPû_–žµ´Çmœm%tEXtdate:create2017-06-06T01:31:29+01:00Zò %tEXtdate:modify2017-06-06T01:31:29+01:00dJµIEND®B`‚puzzles-20170606.272beef/icons/pegs-16d8.png0000644000175000017500000000174113115373741017133 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<éPLTEÖÖÖÚÚÚÛÛÛÙÙÚããØå娨ØÙÕÕÕÛÛÚÚÚÜááÚµµâ°°åÚÚÒÐÐÑ×××ËË˦¦¨ËËľ¾Ûüÿ¤¤ÕÚÚÏÔÔÖÏÏϱ±²ÎÎÉÉÉÚøý´´Ô××ÐÖÖØÚÚÓÍÍÙËËÜÕÕÍÒÒÒÀÀÀÉÉÆÊÊÆÎÎÐÑÑÑØØ×ÊÊËžž¢ÂÂ쬰ªª®ÏÏÎÏÏÐÒÒÕÓÓÔÔÔÔÑÑÔ××ÔÛÛÊ××ÒÔÔ×ÙÙÎÛÛÎÏÏÑÙÙÖééÙÞÞÚÙÙÛååÙ××ÙÕÕÔÎÎÖåÃÃÙààÓ§§àŸŸáÞÞÔÏÏÜ’’éÌÌÝä䨦¦ä©©æØØÑååÒddëIIñÅÅØþ¸¸Û``ëTTí¾¾Øÿ««ÓÙÙÐââÒƒƒåhhêÓÓÕ##øûÈÈØæuuèÎÎ×ùû¼¼ÒÖÖÐÔÔÕÊÊ×ßßÓÞÞÓÖÖÕÒÒÖÙÙÕÊÊÛÕÕÖ××ÌÏÏÒ˜˜áúØØÔBBò77ôÇÇÙÓÓп¿½ÑÑÏËËØ==ò>>ôÄÄÐÔÔÑ__ìEEñÀÀÙÿ¨¨áÒÒÆ£ÎÎIJ²ßþ¨¨ÕÙÙÔÂÂÙkk겲܊Šä‚‚娨ÕÎÎφ†ä‡‡æÓÓÎÑÑÒççÑÜÜÔããÒääÒÿÿÿÀz:gbKGD¢°ÝߌtIMEỪ¼õIDATÓc``dbdfaec‡v&N.n^>¨¿€ °ˆ¨˜¸L@RJZFVN^&ÀÎϤ¨¤¬¢ × ¦.©¨¡©¥ ÐÑÕÓç0042615377j±°´²¶±µ³wptbuvqe°ps÷ðôòöñõó æc  ŒŽ‹gHHMJNIMKÍÈÌÊÎÉeÈKÈ/(,*ö,)-)È++¯`(¨¬J¯®©­«ohljnimciíèìíîéíëŸ :QœaÒä)S=§MŸÁ>3oÒ¬Ùsæ2äMš7?oÁBvv~vö ØÙ`ý=…xb:1%tEXtdate:create2017-06-06T01:31:29+01:00Zò %tEXtdate:modify2017-06-06T01:31:29+01:00dJµIEND®B`‚puzzles-20170606.272beef/icons/pegs-16d4.png0000644000175000017500000000046513115373741017131 0ustar simonsimon‰PNG  IHDRbògAMA† 1è–_ PLTEÀÀÀÿÿÿÿ€€€¨b‹ÐbKGDÿ-ÞtIMEỪ¼RIDAT× È± €@ @ш•MW:@‡ˆ`aycÈMåuàŽæ5¯x¨Y¥ˆ yUŠ`h,øÎž‡â9A‹§3Çv#Å3xikv2õC-õet ¥ô­‘%tEXtdate:create2017-06-06T01:31:29+01:00Zò %tEXtdate:modify2017-06-06T01:31:29+01:00dJµIEND®B`‚puzzles-20170606.272beef/icons/pegs-16d24.png0000644000175000017500000000226513115373741017213 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<£PLTEÖÖÖÚÚÚÛÛÛÚÚÚÙÙÚããØå娨ØÙÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÛÛÛÛÛÚÚÚÜááÚµµâ°°åÚÚÒÐÐÑÖÖÖÕÕÕ×××ËË˦¦¨ËËľ¾Ûüÿ¤¤ÕÚÚÏÔÔÖÕÕÕ×××ÏÏϱ±²ÎÎÉÉÉÚøý´´Ô××ÐÔÔÖÕÕÕÕÕÕ×××ÛÛÛÖÖØÚÚÓÍÍÙËËÜÕÕÍÐÐÑÖÖÖÕÕÕÖÖÖÒÒÒÀÀÀÏÏÏÖÖØÉÉÆÊÊÆÎÎÐÑÑÑÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕÕØØ×ÊÊËžž¢ÂÂÃÛÛÚ¬¬°ªª®ÏÏÎÏÏÐÒÒÕÓÓÔÔÔÔÑÑÔÑÑÔÔÔÔÕÕÕÕÕÕ××ÔÛÛÊ××ÒÔÔ×ÙÙÎÛÛÎÏÏÑÙÙÖééÙÞÞÚÙÙÛååØååÙ××ÙÕÕÔ××ÔÎÎÖåÃÃÙààÓ§§àŸŸáÞÞÔÏÏÜ’’éÌÌÝä䨦¦ä©©æØØÑÐÐÑååÒddëIIñÅÅØþ¸¸Û``ëTTí¾¾Øÿÿ««ÓÙÙÐââÒƒƒåhhêÓÓÕ##øûÈÈØæuuèÎÎ×ùû¼¼ÒÖÖÐÔÔÕââÒÊÊ×ßßÓÞÞÓÖÖÕÒÒÖààÓÙÙÕÊÊÛÙÙÕßßÓÔÔÕÕÕÖ××ÌÏÏÒßßÓ˜˜áúæØØÔBBò77ôÇÇÙÓÓп¿½ÑÑÏËËØ==ò>>ôÄÄÐÔÔÑååÒ__ìEEñÀÀÙÿ¨¨áÒÒÆ£ÎÎIJ²ßþ¨¨ÕÚÚÏÙÙÔÂÂÙkkê²²ÜààÓŠŠä‚‚娨ÕÕÕÕÎÎÏÔÔÕÙÙÔ††ä‡‡æÓÓÎÑÑÒÔÔÕÙÙÔççÑÜÜÔÔÔÕããÒääÒÕÕÕÕÕÕ×××ÕÕÕÕÕÕããÒããÒÕÕÕÕÕÕÿÿÿûñÍobKGDà(ÿ0tIMEỪ¼IDATÓc``dbfaecçàäâ^>~A!aQ1ˆ€¸„¤”´Œ¬œ¼‚"D@IYEUM]CSK[" «§o`hdlbjf°°´²¶±µ³wptrvqusgððôòöñõó  gˆˆŒŠŽ‰‹OHLJNIMKgÈÈÌÊÎÉÍË/(,*.)-+g¨¨”­ª®‘­­“­ohljnahm“mïèìêî‘ííëŸ0qÃä)S§MŸ1sÖì9sçÍ_°pÃâ%K—-_±rÕê5k×­ß°qÃæ-²[·m—ݱs×î={e÷íg8pðÐá#G?qòÔé3gÏg¸pñÒå+W¯]¿qóÖí;wïÝ&ýc)^¦%tEXtdate:create2017-06-06T01:31:29+01:00Zò %tEXtdate:modify2017-06-06T01:31:29+01:00dJµIEND®B`‚puzzles-20170606.272beef/icons/pearl-web.png0000644000175000017500000000767713115373722017410 0ustar simonsimon‰PNG  IHDR––j.>gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá‘ëbÇIDATxÚíœ{lÅÇ÷üHÑ6•Z á‘„<h jyU‚%NZˆS•$Ѐ’’„ŠðH|¯½óÛq¯„P‰PyHE ‰ûÎÛÛÝ»}ïÞïìsb@DT”$¾îÌÞÙ··s¾³Ïâ÷‡=óÑxö«ÝßÌ÷fÎmÊÀ¦[À(²(¿y‚–Eñ!Å4!QIYÿQcK3*ÐtRqÓ–ÒdùCëžØŒˆ-å›Ç†· ñãcÀ[7îȤ,¥å Ž " â‹ÀÞÃ!°ìêB`Zv{QX©ìà8ì|VLÝ-¥y30ŽŠwtXpt¡°èô2FLŠx K®Ó,+¶]é²ס))‹ä(,Lž,J‹Âdé:™YdPEQàÈBd%;ᩉ’Er=¶[ç/-ÿD$Ç/‹d ÷ –lüv?²Hîø˜ð™.Ù¯>’³w(CYhì ª¿Ø¶ßbEj'%{%R/+½µ_ÄÛ˜´zvYÓ}3Vd±XŠ°Ò–hãXÅE œ!Ø‹@`&ìö‰'PwÂN,˜¥&ì×ÉbÓ[Gª:¥‘*Ì.K°aÅ vÉ—ÏQc6ü™sGÅ—ZŠ`'ÅØoÔ»7"‹Tîœ=7½õe#•«fTE‰l²ÄßÁGt%+Fú8ò§É ]‹eù“RÌÚ—]Ö‚T—˜¥€H]«kìÕÉZŠgù“£ÊZ:,«¨´Dq 2FÇ©>бæˆñn—fvbÉq·„M©»\È3L½EØÜÕY·ð‡È|‰&¨[ÿVSKKó¡MZ Ñ|¨|? ¿Z^°¥ù`Ýl­“¬\I‰PV1VþvhýòkÕ„…7æa–ÑdŠA—l9 G"áx"!Ë#t“?¼,§,*x9f)Áš@zÿT-^.äê%&L7Èj‰$K^.TûáÊÒ–$ e5‡ 8˳ö.Ú¸Tðs/báWWû%(«²×k‚³=HªB²Ñ$ÆÛ4‚²*4LH:Y[DÎä ”u(„Kʼn^Aà„ˆÀaÜ1].T{& -\Ýp©Àô-Ø}6‰ÝÚ "ØT;¨á¨#MVK9îawÍc{S ÖœÛáïŒP±5¶«[Õ¥ “ u°•ß^¡áêË^—Â;’¸æ €ï¯×°kÛ!í!Ý ºH8¯V³µûº ÑEÙÚP˜¶·Â^:8’ÖŽ“æ–À—HNbç ?(xùë~1‰™ŠÝéï–æ|ˆ¢4m‚ǰ´èìFØGZrvBL‡àC¬î#5Ÿˆ{ O¤"ðÝÂû5¬¸Ú¹À½ðݲÅ!¦ÂöɉQýHôF"“6+¦-A¨#±x†éò¡=­ê˜ÏL²H68ÿçób»ü&’Eq_¬y†úöÃÕ{4ŸfYAòo&.&†ç6âЧ™B%UmO|w1‘8ŸPV«¾Õ$²Hé¯z³Ô¸˜x¾>ê7¬åƒ çUÏ ¦‘UÒd]HàÖ~óÜ­íç‡À3üfÓû2iYÿɽ}‰ ß_JzPUeY4%W­aÔüpþÕmàn“ÈRé+W>Q[yÇ]]¬‰Ò©:'ž…×o0Õœ¨ ¹›9 ³G͵‚øa2DÊù@2ÒÐ!0ï耘6d† `9eÈ` 2P]¯²íoõ†Lx¡¹Ð 0 Â…œ”È‚ ã~ɈوË1ƒkùº³AXëuu˰Ð Yå †£îNˆ™¸fȾÔpÊ94CV^«1|»Í‰°^Y±b{uÒ%;Ù‘Ä5s^_ŸÂ' ÙÚ$vë YOW'²ý\¨x k[w§!¼~[+ “¶“= à BCæ´N(û 3‹áÓ5L;Žû f¡!{Aj‡µ€Þq:C£´;‡¹q—ÍiwtX3dý)C¦mÜÑICO2m㎊¦2zR Y0}$NŸ!Óm…?A¨>me‘ŒÄsœ(P…ÈòEoÒ°o‚d‘¼Ï¹áî•O~ “ã—E2ü¢Ÿ^9{æÌÝ-’?¾z'q®ÿ•V¨+SV2¼ót -êeQ\Û}Û¨ 玖=7 —ÅøÖkp]=´X²ê¿â$5„X5~à:£¬}ÿAO+T%9vA‹õ}"¸Ú ,–N–ûå5óæ«1oÁ/®ž¯JÁv…N%Õý5éÓÂe­ “‚eñ|)‹µ³ì9édeÝEÑÉ"å‡ÚR¼X|ZÁ²¸»Ïi^æû„Õ7ʲelƒeù•{â)ŸV¿ø´,²®ÂfÌÂä%keÊbíu÷éd]‹Í(‰â’‘ò,Ì¥—U&¥:©z)>wK|òͤÅúòÑ£9·¸£%ÙÉ·~ø4ô9ˆ`sM]½û8Gå–%|°êËÄE`±šQÈ´‘H1«ëëRQûxÃp­Áõí Bò•ç?U}ìä­õà“œl§F"Ñh4¦©Ê‘ (Ùº–U‡öwÍh‡käxF8:‘Á¦¸ÖKHæ-¹z5èdèíå_€«f“å'ÔÈïÔ)7¬ÞUñÒ#·sºtšì$>ÖÞJ¥ÕS3h*Ë˯\½­±îî;;¸ìéT9çİ·¥Â}Taõ“OFëÇ3|ƒ¿‚Ë ³=ôÉ¢ýLo¼O"3¦ê±Éò+Ë€OÛeN£,x¦LáqÊÊc½5VY:\¬Ñ ™Þbe1d¬Ã‹öiŸ6¼‚ÈÀÞ ™O3dûІLCða'-!p'˜ëu2GÝ=H\Ù¥€; ™ó+â~§Î¹œÆP-–…]ª!Cá6‰­£a{­fÈ`ŸŽJ½!ëòÃã³¶vq‡ÏzѼƒ°@a¿ý8 “ŽcݵЄ˰ç…ÓÓûÒ ÙŽ1†jÈ%g4bïBa÷ò†L-ÐIC6@LGìyŒDûx Yž#Ïß©RH5å}d1½õ¤$ˆä‘Å€ „C›ß‘E*Ùº°,Ÿ[É’5Ë—Ýòä±¼Ž,’ ݰ↛·|&2'æ–E²m·ÂÓD?Û/ A2¶NDÞ$X»GÅDÐó{Øú'Õ2™—,}:u¶Â,ëSrœ±¡‚ÄíXlæ¢,KÑ*&$BŠUòbïR N‘êqJ[Bþ²8{É5 .\té5‹CÃ‹æ ŸM¼­;@å”EÊ+®X<ÒÉâËh}/ž™ëlàíc;²8ܸèmÅŸ[ÖDY„³(ù+34œv6Ì)k)Vlè¼2¹d-–UœôR¥ÈÐpIJV1öJ^²–âÓl±ìïÖCc<²˜:›8žMœ¬‡È8ÓR¬^ª¨+krUUUÖnpVW¢²nƒ£ºª²fß, ¶.Å•ó‰Û‚tâ®ÐZS™ªUÛ>Mú4Dޢė€&õZ·ñÞX¬÷LÔeFïÙ:X¬‡Ek}K†!Ë– "±‘Î"_íć«Ñ¾Ôgw¨,OIµ¿V/3ç1/ã^*`õ„!|A[ÄRãÍêûuÙ#C–%¦û´Îq’N«'A–91ì9ÜØü±ÂävÕðmé|½ñåËL!“OF¯ üÁPoDðçãªS­EASu^²tkJ Y~²ÒÃß\A¬Ô„½3CFŒÏe`ƒ!3†ÁÎ÷â G]~cnWv‡8ùqc8]ÛH¼ÃŽÂîlØæÊë ÙãÞc´wWœô °õ¢ùéëqöÙŽu"0aÿ…É܆,(9ʪ!Cø4Õñ¬¸:Q8äòœ‡!#§Âe`yB>H£§0C6z‚,*(Á]“)ÈòcErTõƒËËžþHžô9q ²HîÔ}OyΆßëÎÓM‰¬ ÿO¯®ñûšÂù²)‘EI®`skè|‚\ÝÌmȦHÿ@·¶¹5”xæ@$÷Z~ŠdqËÏ¥6·ô;dÓ,kåÀð™«Ï4²Ä­ÿToØÜúºü_’i¢øþšoÏ_J¼úLše$Ò”üâ†ú¾_x}Å).C65²ÔQY¶§ /ßpŠ7Q:öítÃsïÉœ™&ìEúåÂvÈ&A–jȈ Ù膌˜(C†Â¢Þ)’1€!Cp!ŠÓHì"Cs(ÜWÙ ˜;w¦²J—1p÷';P¸RÅ8 Û‘øo67W=¥3d§ÑÖYq¢‰#š·vY¡p·ís÷Ø>Caß^!ãYc¨†ÌÏ1F,;}<+x7 ‡\‚Ân ÷ægÈÿ‚$ûHôŒÁ‰ª!£ Ø?!†ll B·Ÿf–¼E$YQdýa–i—E²Áýß³êéÒD²(Ö³~óÉ~ù𽸬ûÒÃôÊ Ö5Bûvfí~ÝwȦU%ÕoMüÚ7v•7H™D)mlMMü;ü§&‘uÏÙáïíIÿÙ4ËZIÙ7×¾~óÜ­moBû6”øö/ï(¤IdQÂÑU_köíÝu"i–‘¨Ú·ŠõÀ¾ ½·üO™F–š"ªW½P_ýøÚc‚‰Ò)°oíu»_8"òfš|h;ÅÒ\S5 í1lßÌ#K‡ÇoÈÕ!N2ª†Ì“Å¡pCÆ«†ÌŸËm £þ cÔÅ ¸Ôç p%Ab2"°¯òõ"ðxXm1$ðO}ði|©¯:_¬ã»›’x <è|íÃçsGŸ<÷ÃÊÑùäuŸ¼k³Ïœ›ÈâÅ’W.^ü×òî³’ÆûOzÔ)—êsÕˆ$>ªpY|PŸßcôÉsÕ笷n3ë~ŸÙµ+¼Ÿ9K¼y?xñÿÉóþnÒ2\{Kà¼{­·%tEXtdate:create2017-06-06T01:31:28+01:00³-ù½%tEXtdate:modify2017-06-06T01:31:28+01:00ÂpAIEND®B`‚puzzles-20170606.272beef/icons/pearl-ibase.png0000644000175000017500000000131513115373740017675 0ustar simonsimon‰PNG  IHDR^^¹ü²gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿ oFFsl"„e tIMEáb¼š* vpAgØØ¢^l\«IDAThÞíÚANƒ@àI‰.H`‰®ºm‰›]Õx•¦tg«ÐVo×` °w–Pì4™Gy“Hòþeá}!-02e3­a³¸2-O|{>šßY†5ö¹>è›,醸Àê±"=+ÏCù¨_ê;ßåÐù:^Ó—Í3P<ëåm½¼Ñ髟håÍ_ÎsW¸ï¼‚WÝ÷•|Ö>µ­ø8t÷' Bø<œùþÞ`¾Ê<ñÄw“ëre›n~¸ë_ñÄGÌ6 Ón´ÚÀù`xû¹M¿77£k%˜œ×¬ÈʯôP>¾ee–¸§@ùùcvȽÍO¿~ý„Í_l>¹ÄæÏRÿ9ïØÕO7ÿþŒÍû?Y`ó|´úÓ_ðïû8t–¥®á©ÝùÞõ:I“+OÇ;'ïçùÓÒôÆìørB<ñG<pâ‰?—ös4^ÞϱxE?GâUý\Æ×DÆ«ú9¯êçH¼ªá"ñª~Þ«Wõs$^ÕÏ‘vÝTýkSOÑÏÑö åýoKRÚÏwûJ"…;\“Ÿ‹%tEXtdate:create2017-06-06T01:31:13+01:00?¥ª¤%tEXtdate:modify2017-06-06T01:31:13+01:00NøIEND®B`‚puzzles-20170606.272beef/icons/pearl-base.png0000644000175000017500000000543413115373721017531 0ustar simonsimon‰PNG  IHDRØØBººbKGDÿÿÿ ½§“ ÑIDATxœíÝÏKiðìX\˜ ‡ :èÕŸTzSôì(xK4=i”D)ê_ Þ!JâA ¡4 ÄËxTñ"hÕ¢íE’œ4Q¨4“=¤¸Ëš˜hßÌ|ßwžÏ­Ûwß¼}ûäeföñ¯óós€Ù$³`³!ˆ@‚$ ˆ@‚$ ˆ@‚$ ˆ@‚$ ˆ@‚$ ˆ@‚$¼+èÊÊJåÖ¢úøñc9Ãp" ¯8óÊ ø¬¬¬`rÁ&/0ND AD AD A^}ûæeÙlVÓ´ííí‹‹‹L&#Ër[[›ËåRUU’¬zlKI,ƒÇ=O2™Ìd2ùr|||vv¶ºº Eaøq¼À¶”ƒÙ×1»\®D"ñ´ÝO2™L,s:‰D‚ÕÇñÛR&6AÌf³'Nëº^p€®ëétzjjªØ!a[ÊÇæÒ¬iZ2™|y7u]¿ººêêêzaÌúú:“õp4¹®ë××ך¦ ½ùÓ;::Þüï¾måÌ›jØœˆ[[[Ï/=P¦L&³½½mö*LÆ&ˆ———L汬‹‹ ³—`26AÄqø‡Òé´ÙK0› ʲÌd˲Ûíf/Ádl‚ØÚÚÊdËjoo7{ &cÄ‘‘Šo&˲Óé4{&csûFUÕÕÕÕX,öÂI’ZZZ¢Ñh±‡Z\¿Š\pr]ׇ‡‡KnKCCÃÀÀóU•s‡¥œmù“{Cåcs"J’ ív{±I’d·Û€¥­b[ÊÇìϯ(J$inn.ø»---‘HÄ‚U±-ebùETeww·àoE£QËn7¶¥Œ¯/\ƒØ~_°-%a#€H@H@H@„¿Êç»Ìr§‚¯ž{<žW,JDÝÊ“—ùˆÿÕA|Û3rVàßÌôÉ+º-d'·¡¨ø‚  "€  "€  "÷²Ù¬Íf«­­•e¹ªªJ–åÚÚZ›ÍÆWŸ‚È·x<îv»?|ø°¾¾þãÇL&óýû÷`0ØÝÝív»9êC9ÇÇÇÇgffNNNFGG«««›ššÜn÷—/_¼^ïØØ/YdÜ †Éf³óóó‹‹‹ÓÓÓx½Þ\.·°°‡éÿ? Ô×Åhšæp8Š¥0ÏçóÕÔÔhšfØªÞ A䕦i³³³%‡ÍÎÎ"ˆPAççç}}}%‡õ÷÷3/Õ¬‘W©Tª®®®ä°úúúT*eÀzþ‚È+‡Ã‘L&K»¹¹q8¬ç!ˆ¼êèè888(9lÿåÞr"D^ úýþ’Ãü~%ªÆ˜Cy¥ªêíííÚÚÚ cü~ÿÃÃAÄ m^I’´¼¼<66–Ëå|>ßó~¿ii) Ñ¿›mÉÈ5EQB¡P èîî‡Ã‰Dâññ1‘Hlnn¾ÿ> †B!^ÚÆp"òMQ”p8ÜÕÕ5==ýëׯŸ?þý÷ßUUU÷÷÷_¿~åâ,ÌC¹—OÛÝÝ]þ—O?j„£Úpi"D AD AD APKgÊÍqµt´&'Û‡Z:€!ˆ@‚$ ˆ@‚$ ˆ@ÞGü-›Íjš¶··wvv–J¥Ggg§ªªªªòõb[OwOoݾ{÷îîîN×u¶ÛbÝ-þ¯|¹[4œœ<==}xx899™˜˜ØÙÙá«Ü-#;ïÄËÝÿWîvttÄW¹CwÞYýÒ,X¹+Æo‹ÕƒXf¹ÛçÏŸ5Mbû韞=WðioE¿-VùŠ#X¹+Æo‹Õƒ(X¹+Æo‹Õƒ(X¹+Æo‹Õƒ(X¹+Æo‹Õƒ(X¹+Æo‹Õƒ(X¹+Æo ûÛ7|ýG½ªªŸ>}Z[[óz½ÅÆ0)w{ó¶TôÝòb Û–'V¿(X¹+Æo‹…6·˜§r·ÞÞÞÿ•»õôôðUîÆÁwV?óòånš¦mllÌÍÍåß¾éêêr:–: ÿËÈÎ;ñ7I’†††˜?Äãawý®5"€  "€  "€  ìké@0ÆÔÒ½ú†¶ÀÍq˜¼ ‚A,gI¯:¹piD AD AD ñûˆùr·ííí‹‹‹L&#Ër[[›Ëå¢_îÆïÊÅÀ2ˆñxÜãñ$“ɧ×'ïïïÏÎÎVWWƒÁ Ùîù]¹0˜}×ãñ¸ËåJ$O—O2™L,s:4ËÝø]¹HØ1›Íz<žt:­ëzÁº®§Óé©©©bÌÂïÊÃæÒ¬iZ2™|ù¯J×õ«««—‹*Ú¿öæÉu]¿¾¾®D-+eÖÛd|ç]AlNÄ­­­ç×5‘d2™íím³W!26A¼¼¼d2ef/Adl‚(öq˜—N§Í^‚ÈØQ–e&óPf·ÛÍ^‚ÈØ±µµ•É<”µ··›½‘± âÈȈ؇¢,ËN§ÓìUˆŒÍíUUWWWc±Ø wp$Ijii‰F£Åž˜™ò*²®ëÃÃÃ%WÞÐÐ@¹‘¯Î»‚uŠIR0´ÛíÅB&I’ÝnÔžÛò»rÁ0Û\EQ"‘Hssóók´,Ë---‘H„æ[~W.–/=(в»»«iZ$ùöí[þ–ööv—ËE¼Üß• ƒñk`ü–»ñ»r1à»$ ˆ@‚$ ˆ@‚$ ˆ@‚$ –* µt˜ÜüÉËŒK3€  "€  "€  ø1¹¿åkéöööÎÎÎò?¯¹³³SUUÔÒ[l³ÙlñxÜívG£ÑÉÉÉÓÓÓ‡‡‡“““‰‰‰·Û*0 ˆ¶x<>>>>33sxx8::ÚØØX]]ÝÔÔäv»ŽŽ¼^ïØØ²XiV¿4g³ÙùùùÅÅÅéé邼^o.—[XX‡Ã¸FWŽÕwVÓ4‡ÃQ,…y>Ÿ¯¦¦FÓ4ÃVeA¢6;;[rØìì,‚XQVâùùy___ÉaýýýonS€rX=ˆ©Tª®®®ä°úúúT*eÀz,ËêAt8Éd²ä°››‡ÃaÀz,ËêAìèè888(9lÿåöoøCVâàà ßï/9Ìï÷Sn€Õƒ¨ªêíííÚÚÚ cü~ÿÃÂXQV¿¡-IÒòòòØØX.—óù|Ïøýþ¥¥¥P(„»Ù…͵)Š …@ooo8N$‰Dbss³§§' †B!ÔÒUšÕOÄ÷ù;XÛ݉Ç㱃ÕÐïtåµ÷÷ß*†ÞmD¬¸{¾éëëëèü¼¿— îÞÃÀj¯¢¢"(×I3`­$Ȉ2$à|€~^•S€J‹2À)¨ÈZì¼y¹ò ò{1Ø¢(οûΥʋo_¾TùVn£éX´šœq]ÄB¸ù÷mz?zðS>Pç–6ñ@` ñ&в³–ȲnH³Ç2x„ÃåP4's˜wbÞµØvÜâ[–‘2OžÃØÌ0U±˜@LR”‡²yÖÐö,"ÅæÖ¢bl…rQ•%ØFƒK+Kgq—ûÀâÓZ€Ú§‹ËÁ±©µ¥ “³K+dêæ$Ð8<ïöžfdÁë÷úüîµj€ê5·o~dlλ0ÂÀï´ÏïïhJ•4—5‰”´º#«Ú¤¢ŠÏÛÚŸ‹ÊÎ|0&í¬’’$MQÕîtÓñl0ó ⰓÉë׈4-±FÓ,mº3³½9`ÜÆ^Ú®ºp¡*Š9º½9uáØuȰrgZ×§{ÔNó ëGGúGU Plè1EåÂ2l>Õ_¼Ð<Ò Ë€yñvHןÜ nZ¯]¹rM øð¾À±Æÿp€ ›a“»•Í8!Û5¼*â‘q¥¹ä-šÈö˜Û;“ÁfœtNŒŸf`Êérõº\c¾«W}cÎÉÁûǧ8=>A¦Í)«ôi\Ä(I3JйãZ÷ÖhIšQR„„›Nš-)ÁÒU’9e¡˜¸Ò*͈a±ì¯±’!‘lm-¼‰œüüG<±çÛMÄþé09²þ‰Søö ‘?¨²6Z,ï5Z쯙€¤~Òõ¾ßâò€ 8Ř^WT mI@ õê‡Gú_w$|=Žtw<(ŽÕ{•†úоJ•¿L\ë¡\ÑXíõ óàê³–¥”\´R1%QÑtIŠQÉC4s ȯ&â›{ºßA+Ë[-¾»?Š‘¥8F#7µÊn—(ÆÑ—®a¢À Ö<.„׆К`Ž(Ñ܆êª3%M¡æƒ1Œ½¬÷4Hú©ö(ÇZ¢½û¹oŽýáld¨vÂ}*qB@Uw“´ý@y˜K:·äÙj®6ÿþ…ap? þ4~ã5R÷Ä¢¿%tEXtdate:create2017-06-06T01:31:28+01:00³-ù½%tEXtdate:modify2017-06-06T01:31:28+01:00ÂpAIEND®B`‚puzzles-20170606.272beef/icons/pearl-48d24.png0000644000175000017500000000252613115373740017364 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEáb¼š*^IDATHÇ•–KLW†Ï‘ØçQ«ìºJWUÕ¨]5 RUEÙJ…xŒ1$m6­²jh¨@4RS`ÀF¨õ‹7D¬J›‚çÎñ<cJIZ©‹ª HÓ{Çöøj_Öøßù|ιs矖—Ѓ-[¹QîTh¶d)'hjÊŽÒ€µ£»³Ë”#3ììîø¨+K­I µÎ«r<1æ‰o «þ€‚3q—Å–0ÏET‘+øQ ³[ìÒ/ÛtÒE‹ˆÂ¢g1BG,ÊêÑßî/>÷ù;XÛ݉Ç㱃ÕÐïtåµ÷÷ß*†ÞmD¬¸{¾éëëëèü¼¿— îÞÃÀj¯¢¢"(×I3`­$Ȉ2$à|€~^•S€J‹2À)¨ÈZì¼y¹ò ò{1Ø¢(οûΥʋo_¾TùVn£éX´šœq]ÄB¸ù÷mz?zðS>Pç–6ñ@` ñ&в³–ȲnH³Ç2x„ÃåP4's˜wbÞµØvÜâ[–‘2OžÃØÌ0U±˜@LR”‡²yÖÐö,"ÅæÖ¢bl…rQ•%ØFƒK+Kgq—ûÀâÓZ€Ú§‹ËÁ±©µ¥ “³K+dêæ$Ð8<ïöžfdÁë÷úüîµj€ê5·o~dlλ0ÂÀï´ÏïïhJ•4—5‰”´º#«Ú¤¢ŠÏÛÚŸ‹ÊÎ|0&í¬’’$MQÕîtÓñl0ó ⰓÉë׈4-±FÓ,mº3³½9`ÜÆ^Ú®ºp¡*Š9º½9uáØuȰrgZ×§{ÔNó ëGGúGU Plè1EåÂ2l>Õ_¼Ð<Ò Ë€yñvHןÜ nZ¯]¹rM øð¾À±Æÿp€ ›a“»•Í8!Û5¼*â‘q¥¹ä-šÈö˜Û;“ÁfœtNŒŸf`Êérõº\c¾«W}cÎÉÁûǧ8=>A¦Í)«ôi\Ä(I3JйãZ÷ÖhIšQR„„›Nš-)ÁÒU’9e¡˜¸Ò*͈a±ì¯±’!‘lm-¼‰œüüG<±çÛMÄþé09²þ‰Søö ‘?¨²6Z,ï5Z쯙€¤~Òõ¾ßâò€ 8Ř^WT mI@ õê‡Gú_w$|øà’!D¨lÒÒ %¥S‘–BGJ:m™Î½³vÊ"_}1¦Þ™)ZMü'÷žÿœürΙ›å°;Lµ—½½œ°;( (êqwWד.r£«ûᓲyl«*–ò’ ssª¨KPç8ÙpêgXÂ2JÑ"Ï#„x‘Nbbx^Œ@,?×l¹QYZâÆÉÁ´¨G^Z!À½–Ú&+TÁ•b‚²Ó§m6[CÝYrŸ|—Ã:pÿXÀR—5–Æ97ù0u àtôL="Ù-Aœ>8:V.¸ëLk_[áæ.—4€ºl¡‘´â9Ê#sȸ°Û{BfN)NA-ô!å&ÙVÖ €Ž¦ZáFz1ìfÖàÔ"³ì3Ë6x•`h˜]d Œ„&¢«ýP³°ÄL„¢Œ ^®-ÍÀš¼×Ô¾˜ù¨ýP¯JÙ%[Ñ"ÆÛàΖ>¤úºõz@Æt †\A[vèØÎ¤_¨ôs$®Ò),6üæ_ÀÐÞŖþ LEK¥wŸ²ÿ«@‹ò«÷}ŠðÇÛØáÓA¡àƒ: IÁ´ @âÀlnC»–Z÷sò8Ô'7xÿ:Ç7•c Àˆ^…Æ?ã¢Ã/᤟þàš¡ƒgàY„öš+'î:Ê-ò“P‹E寤ž‡ÑMiõà¡ìàü¦àpngj8²r¬¸Ñ\Ý»YùP-‹3ïûgç_@m‰tJÀßGr¿[Pmî‘N €çC¥Ò¾«°\ŠÎêãVëÑ#Vë±Ãõ ((•6‡ ¥l"ŸÖK–™N*ogÓ½«ªÙbYàômÒA‰D”á„‹ÄÔx³«©YUUsx¾ ˜UµÎÎÃø—k.¯[—g¼Ï4noߘgò‚å©Ïã2€¶ÛeÙ+MEî6è<³Ò8ük‘t¥ÍƲhÁl±åëÚ"½D¦Î@,À”X'+»Øm‚=3E»÷™à8éí'¹Ä/`[¬ˆ“ëZ2¡ba¾zñå¤?Nò÷»Mô UC¹ÙæYå50ìÙÖ]ÈID[Æžhq =ž2½¦¢cš{‘ÜÀì^O“ØŠ“)r/ì›QûL¦•¬m(Ôn;%tEXtdate:create2017-06-06T01:31:28+01:00³-ù½%tEXtdate:modify2017-06-06T01:31:28+01:00ÂpAIEND®B`‚puzzles-20170606.272beef/icons/pearl-32d24.png0000644000175000017500000000174713115373740017361 0ustar simonsimon‰PNG  IHDR V%(gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEáb¼š*ïIDAT8Ëu’YOQÇO…Wce‰–€ ‰À/¡&¸DZÄ)ÑߌFˆO>øà’!D¨lÒÒ %¥S‘–BGJ:m™Î½³vÊ"_}1¦Þ™)ZMü'÷žÿœürΙ›å°;Lµ—½½œ°;( (êqwWד.r£«ûᓲyl«*–ò’ ssª¨KPç8ÙpêgXÂ2JÑ"Ï#„x‘Nbbx^Œ@,?×l¹QYZâÆÉÁ´¨G^Z!À½–Ú&+TÁ•b‚²Ó§m6[CÝYrŸ|—Ã:pÿXÀR—5–Æ97ù0u àtôL="Ù-Aœ>8:V.¸ëLk_[áæ.—4€ºl¡‘´â9Ê#sȸ°Û{BfN)NA-ô!å&ÙVÖ €Ž¦ZáFz1ìfÖàÔ"³ì3Ë6x•`h˜]d Œ„&¢«ýP³°ÄL„¢Œ ^®-ÍÀš¼×Ô¾˜ù¨ýP¯JÙ%[Ñ"ÆÛàΖ>¤úºõz@Æt †\A[vèØÎ¤_¨ôs$®Ò),6üæ_ÀÐÞŖþ LEK¥wŸ²ÿ«@‹ò«÷}ŠðÇÛØáÓA¡àƒ: IÁ´ @âÀlnC»–Z÷sò8Ô'7xÿ:Ç7•c Àˆ^…Æ?ã¢Ã/᤟þàš¡ƒgàY„öš+'î:Ê-ò“P‹E寤ž‡ÑMiõà¡ìàü¦àpngj8²r¬¸Ñ\Ý»YùP-‹3ïûgç_@m‰tJÀßGr¿[Pmî‘N €çC¥Ò¾«°\ŠÎêãVëÑ#Vë±Ãõ ((•6‡ ¥l"ŸÖK–™N*ogÓ½«ªÙbYàômÒA‰D”á„‹ÄÔx³«©YUUsx¾ ˜UµÎÎÃø—k.¯[—g¼Ï4noߘgò‚å©Ïã2€¶ÛeÙ+MEî6è<³Ò88púDàÆDõGÇOmÛ~îä%‰M—€{Toîºç”|ßi©5§'ÛÔoî¾ã–xuÇQ±eG@Z&+]qÂ:ëù±“Õ»ÎeµÌc–`®¾pï¿r²ÎÝ>{~ïés×nœ=—¼ër&CæÆ}ûlÚ»ïŽ ;ÅæìÌ`HKNJLLJJLJNNJKNNô"“h&‘%tEXtdate:create2017-06-06T01:31:28+01:00³-ù½%tEXtdate:modify2017-06-06T01:31:28+01:00ÂpAIEND®B`‚puzzles-20170606.272beef/icons/pearl-16d4.png0000644000175000017500000000045413115373740017273 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA† 1è–_bKGDÿ‡Ì¿tIMEáb¼š*`IDATÓ] !;zGëf|)ø1"*8"ø¨µò’,èwÒ- ]•Û+Šp5éiñvGXGpR¼·(~]‘Á0ku1èÍÐ/tœ–6yÿ²Xc‚öû|þ(©“­F”u%tEXtdate:create2017-06-06T01:31:28+01:00³-ù½%tEXtdate:modify2017-06-06T01:31:28+01:00ÂpAIEND®B`‚puzzles-20170606.272beef/icons/pearl-16d24.png0000644000175000017500000000102113115373740017344 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEáb¼š*IDATÓcH+(«,).-.**(**-IgȾqóØÍƒçn?yxùéƒëG²r¬8ל½¾ ;+9§üô™L†g)†ÙgïˆzØØ³m¹ÁñbŠÊãO<Š¿_y,»ñbCúáÕó›.;Å]Ø´WtÑA Àµ jÞ‹)»䢸†‹P»ß>8púDàÆDõGÇOmÛ~îä%‰M—€{Toîºç”|ßi©5§'ÛÔoî¾ã–xuÇQ±eG@Z&+]qÂ:ëù±“Õ»ÎeµÌc–`®¾pï¿r²ÎÝ>{~ïés×nœ=—¼ër&CæÆ}ûlÚ»ïŽ ;ÅæìÌ`HKNJLLJJLJNNJKNNô"“h&‘%tEXtdate:create2017-06-06T01:31:28+01:00³-ù½%tEXtdate:modify2017-06-06T01:31:28+01:00ÂpAIEND®B`‚puzzles-20170606.272beef/icons/pattern-web.png0000644000175000017500000001204213115373721017737 0ustar simonsimon‰PNG  IHDR––j.>gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá  ºØ*IDATxÚí\ tTEºî £,² ² * 'ŽžŠ à4‘-QÀô–tÒIšl½w:„Í…ñ‰:θÌ8£qEÐD6dÉÒ÷öí½³’ýúVýu»1—twò í{ï;œÓß©{oå㯪ÿ¯¿ªîX"‚ÞpeѲh{“£‡º®ƒ,Úöý¶“Ξ麲ÌçÜsÐÕ#]×£ÍMgÇEž,ÊùÕ]›zع®G#¶›»ÇME˜, íô0LϪ¸>~«§nëÿ”—¿¡²¨:30Ú\Ç5“ÙÌ1®æî †Àšº'‹nhmfokµCmTc Z[[ÁµÓî Í¡uyÚÞrÁΧ+dY´óåe/ÛhÄŽ¤‹ŽãÚÌM›rmè²í§Ìå·¢ÜÛ345Öº=íüV,?ÆçâB—eÿpáRÙ¶i’¶:¤àÛ‡§"Ñöï>X4·•m<ÚñuNÜAW~‹¶Ÿ,¹¥…§ÅÃE¯žN3ØD'çCp±Î˜?é['«€òÔ¥~âÁZ<“ªBŠÕTãÖ ï4ðüB–ÅÔmÈsšmEÊuà¦é¡Fdj_\8d/ëÐiûC¦¼‡ÙñšvÔÎú¬åknÓ}º =±–…yÇxÐÿìÑç×mk´×nGv£m?¾¸þov|ýSÝÇöPŒE;*o[øFG¢é"Ì hG[[üÙ:mkmkZ±>4?O;/6ñ^Ëo‘v¡ë8êó< ýwÕeæ÷p¿~/b1má+¤ƒö¯ÑLuîÌBtÝÜš(ù†ÕJ[Ï%Î^‹ cnùóLp0TÓo4‡-‹¶Ÿš2yØ~éì™ - +K1@L«­š· wâw‘ ¨ú'Ž›PÍv´º‹¢yK%¬BÚz~ÌÚ 8x™›7O#ÓÇÔ-MT¸²|UT¯Ÿ‹þTýîÁ>ïÆð¯cÙÏÆDÚµ?í‰ç‘5Íò†¦ìAÿ¦æœ(·¼ë`Šðs~híã94–rôñ¤Í¸&÷ ‰OçFR#Ñig`ÔÑô™jè³55ç뀞«ñ@­´ù44ã´Y蔙䎮s0~óùRSuÍy3×çÃq~ÊØˆ[°Z­¤.+CÚ€±Ú˜NÑ wâüã{¾sMÿ+¼üÿËúuË¢nè0dY=õžêrc¸Ð¿_P—;àÎF ~pcõØ»†"‹vœP(r1rŠBóKŠE…„–s,?—{Hœ eöœ”«)WÁÙŸsëBm?C¹=šºxÂâùóþˆÙ¢g¦'½aÌøIɘݙüÀÝc›‚aw¢&G x‘ÈÊh»r™Å%ïÞ@Y—ý]>üF¤ê__˜uÖJ_Gkug$Öµ­¼çÎADŒ,Ú¹ûù{v{¨ˆ“õZÑX¼ýQ²_nø§Á‘$Ë7ÛÜ4×· Ð|*J0t8L­|²bHáÀ‘Ü|‹u§˜Åe´yÉH¬ñv êmÙì’ߪ5"’ê ó­€Ióõ²V¶I§ÇÀ¯níâ°¼ü¬Qƒ†ñaèmIq‚¾1,úFÝ;aè Q£I¡ yÈ-ýXô¿91ýdz?Ÿñá4õîžÓ'O±øþÈ–Ÿ0;qöƒUJ`!kæ_cÒ°²JÎ~°²‡ õaxlÜöÓÇO°8v>¿_\,*>ø³¸ðøÙ—DÊ<„5+ÿ d­Üs´áðÍÇ!vèÄ»yòŒåð+/˜w Y.'a6·§c¾7}É«pnþ3o*ìð¾¯(CM£3I… ½IaçmÄrý/±âH: Ìúóþ3~w:÷é>‚¾Ç½í¨Ï^ôj1QнwAa»÷Ÿrœ8¨ôb¡Zy‰ÜÐå/A—¯òuùÐR Úv^øÅà]Á­±&¼þ–µÞËÁÃ^mÉøïñ4jøò,ËRמ¡n‹Yžîÿ¯ÕQõ òñk¯Ë¢mgSǔ’ú»Þë¢"AëC²8nöÍæÃ‰×G–…á¶}¬Ó40:ªï1ÈÖ¯‰ŸzÛ.±hóþCŽ3#V–o$"ÊŽD˜Ë³Á1_ðñÍNµbøÕ˜Â›Ë‡a­\#NwʤBm×™HSx~‹u©á¥¿ÿíÿ5¾±åU¯¼¹bDr@Zÿq£h•g Ò%B‘SÉò¿´açÖ²1Û¾ks®Œ¤#ÖÒ–‡`-ªŽ“õ¤j­‰EYEQ¦2/Ÿ…¢xŽ &šEŒ` Õ}÷êKq© UQj²©ŽV„‹õ[/_@¬Å»ÿ{°»×»~;¼âÆ`™Oÿ,¥–¤¯\ôÚŠùþôu(ì+˜àKgP71úº¼S=o—¯<ÕYæÆ· ý² ÙWë]&û>kÕAF"É|*»c-Êyòw2á®o…"ëJOdÑι©“8Ã\Hºî²,ÔÚ¹ý>¬8Yt{ÝÛŽ_ö­Þ—e©³4Ò²ÔÐåå²:­ØðÊRërWl:`ÅæÐ) W®lƒßK!Èâ„°²JLx¦iRæ•Üsý.Ý ˤå¼üu±–_žO–(O˳W­”c&U<Åç·î+)P²((Z5<¿ÏoÕ´56±hq¾³†+ÿÚßhµc¼cÿL›NÜZþcÆû_íù‡=_¿õú~ľØóÕú?ÿ á‹­+¤±4]œ… “¯˜ž0j4Âȉã’’'K}¯4GXFHþܼ`Á‡q8ˆ¬ª'ê°Á/{OU‚é¯x?lõ³+  &™Êˆ³“|jÉG et—Q-5àP®Ó‹hƒç‰LÝwÇH—¯š^ƒ·!.yO| ›KÞíÍW€1rØäPéÄEZH1²‹‰‚¼$~ ,EõM-¸½XÛy}+XVm¾ ¼_|Ö·‚Z+ü‡Z/)ÖË f-¸3¬5ˆºVùDƒ™ ±o˜,Úúí®ÿ»‘#‹ò¬JxÊihaj3š¯;ÀîhÅ®Ñ'K®Sw–õXt€,pq1~YÃøº|ðÙ)ã°p#1¨µôP±OÎÜZºnXË…•U‹ãW‡÷ä!ï%jÛ›/£t§Ýç ˆµt’5êR­Ìg-NñÈk-(Ö(Ï—b¤<˜CHÊÓ‹  9ÌIMCHM›ÿT;#ešÒLVÀ.ÆŒw÷|ºË‡O÷¾ñÊ>Äv}²¯h9lØ‹3–Épð‘d§‰?|ÒS8ôŒN9é®xà‰ÿ6*Æß“ K"YJˆ<%èæŠ¥¥•,$ñõ­ïk…&# ƒ©X^®ÇÓŠŠåÒ¡f ºî[¾0!KBVÂ*‚Ë–Š3ÄË“àÓî>íÞ-y:Ø"/Á¾ºÊ¸Ô¿™>;Št£xX‹ôMâ®+Ò„¿…nn)ºW¾‹àÓá}5ÆŸN™sCuYzèÖê–;mœ6sÞn7a²Ì­é˧¾ŠÏ F,Úv:oS×]¾7d±'Í›-¼²ÈâÌ«y:"KFò޲¥þƒ«dýkZ«À€'ë†5Y°ø¢)O÷yqœl$ÌŽ"«OüÖ*Ñk¹¾ÊŠ §ï*Yû½ÍX4{_–—!”(ÄÀ 5Ïò6â°¾¿A¸¹ßØ›nAì–˜¸‚üPQñj Eš…áŸGœ‚ðàCÒBHm WˆÀMKWs^^¶dɲt„å‹þNhZÒhìÛG'ñzù%A½‹²auIW&Ә𙧊,!9þ´.+š¯})F¨[QVÚê&3‡j·ÛO¼ oœG p²t¢RpÓZ¶ËÆ…¤P£"»*5PQLÀ Âï嵡îb¸Ízô=8&ýZÊü36úÚÖÒ‰UÚNÂ? Hö âèž9Ûô¢¥ë8%ó£=2dQ ™{Î]ê•ñ!‹rïyð%¼ÖæÐýqÊaGDȲXÏWî;ŒCŽõäîóÎÎ[è½"Ëbu{È (Žzkà:äíýÉ$K­å‰\²Ïí'ª âžD¶¹ÏЛÂ~k)ˈ·’h ˜•ÉMPXÆ-”Ë„zP)¯µàÎPv_¯áågÝfè#’Wg“èti,ze.'…ÙËÄP(_&”š>jd<žâ¾fñqãÈ2Y:!¹O_c!Élæ¬xààŽ[ Ü›U¤Ä(\•¿˜<“­V@añj¡Ó‚âU·õÇ÷4*pË(r§R¹’Òü²¬-Íä… w›‡/øa‡É Ñèf—ÁÒ¤Q «Vì"%Yµ2Iøƒ<®Óqë[טAX«ÿü&Làÿzá ðè‰$Se»÷žÀ[²˜HÛ휕†_¹²î~ãŽÏ:ŸßêYÎK2¾Âйi·ØÛH;ZZÈK] -Mþ½j>Y¢nÈŠ¹JVÈ)í÷[ü<ûù²0œ°Ö‚í€5Y(4°ë[¿Üæ4ò[«DG¶ÐEÝÝB…BÅD ÌÕÀ®¯:³˜lúæKµP¨ª-ÕŠ„¥*Lu¢›¢ñãÑ7Šú báN2”êÃ[ßš5>ï•'Ü!‰Yˆ$K2ÅÀV¥s…KŸƒBéR¡˜Ð%ɉøñÄ1“¡¢¤Ñ÷='ÁKÈYW¥Ÿé¡ü¯&S¼H¼¼Ö áŽRf9/_¢ïäåË®ååµ]zyÚÙ@Þg<®÷;JÁ̤×^MlH—'Ç3®žØð-R’³^žr¿þÐNì¡lçžy/€òüeAfµµÝ)ÍüøÐfxïÔþÊøS´½JšxªWƒÙ›ú&Jw|Á§rªŸßb'éMY”ëo·OG´µfiÿ ðƒµ™ã¿qõf#Ú÷oý}êÁÂÔìøàsüγíÀ[ßõnŠA»›š 9d›ê‰[hq„˜bèxR uð£8XŠÁÍÙÃ}^áWb$Þ>áö„Ì\ØWÎ]ž ›Í¹â )\!ƒBÅ ¡œÐåq±øñظ‰PÑÃî”Û«æõòä ’?4BR @§pù¹ø‡žxj6Á“fòÑ@¹§gÏšÝUM³þ#/è:¦¶²êÆàpåI4­ íSŒËyƒß ñà ôC8²n4"TÖ[x®<¤Û r%tEXtdate:create2017-06-06T01:31:13+01:00?¥ª¤%tEXtdate:modify2017-06-06T01:31:13+01:00NøIEND®B`‚puzzles-20170606.272beef/icons/pattern-ibase4.png0000644000175000017500000000160113115373740020331 0ustar simonsimon‰PNG  IHDRßßS’YðgAMA† 1è–_bKGDÿ‡Ì¿tIMEáb¼š* vpAg€€—TP IDATxÚíÜQrƒ0 EQ/]KóÎh€N;€N34zÊ}ŸŽ©}"J¦"¥MµÓÞ½|øð• >íàÓ>íàÓ>íàÓ>íàÓ>íàÓ>íàÓ>íàÓ>íàÓ>íàÓ>íàÓ>íàÓ>íàÓ>íàÓ>íàÓ>íàÓ>íàÓ>íàûŸX{¤ûãÖƒ#ìz~_³ygÎxóǧÞ\ß~~ߺãc¡z0þ(”y¾ýü4>óÏ·Èm­ÛÈü<¾øº7Þc62?o:ça.#¼!»ù‰|“_(·JËåÖ»ðìç'ñõµÇú­Œà½~nç§ñŸsë~Ý_´ßï I|·ŸvðiŸvðiŸvðiŸvòøÆú™›qÿ§lþNãìg^ùö}Ô4¾Á~ææ€ðJןîg^úv}Ô$¾á~浯eô ÷3/}»>jß`?sÀ7%íŸ õ3&/å>pè£jøÌ™ìŽú¨‰|·ŸvðiŸvðiŸvðiŸvðiŸvÞë³ÛƒßúšŸx>|¥}Á­¡J>³àfk _^©âkÑ¿0”ðÙ²¼û¾µ†î·qJøzm_oÅÏÏyq+|}9‘ãÇ>|ønÈÛ}ÏÖC­~øðáÃ÷BÖ¥Jû,ì–ðô?KøZÜÿ,à;íð­5 úƒ|§ýO}_oÅÏÏyq+|}9‘ãÇ>|ŸéûÐþgt@{v>>|øð ø,XÈ àË䋟ÉbøðáÃ÷šn^ݹQËù‚¥,Ü‚–ïï>|øðáÃ÷™¾êýÏg÷Ô/LJ>iŸEϰ®áë­¶/x¶|_ülù¾“gË—ðÅÏ–¯â[SÕ÷]CwŸ†/bãÇ>|ønÈÂßá… ÷¶%tEXtdate:create2017-06-06T01:31:28+01:00³-ù½%tEXtdate:modify2017-06-06T01:31:28+01:00ÂpAIEND®B`‚puzzles-20170606.272beef/icons/pattern-ibase.png0000644000175000017500000000216613115373740020254 0ustar simonsimon‰PNG  IHDRßßS’YðgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEáb¼š* vpAg€€—TPiIDATxÚíÜ=kSaÆñ[MJMŠJ;ØZ±+ˆ¸;D‰’v*ºh1CAtñøÒAqP¡« ‚‚¡S¡‡ÚMm*•ó54©ñ[{Eó"ïÌÓCÛû‹ŸÆ÷øÚq9k}2'Ù/ÆðÁ¶75‹Ï8Œ¯,Rxh{°4*wŒáÂŽ‘Ã÷ïù`|ÑêLFÞ›ãùý[nšÓÛR*ÊЕÄóø¾×À¼<5¼êÍ>±œ¿%ëK<ˆo¶0yqDv~ŽÏWz¤¿X,¾¶}Æöý4Îâûtjw¶oò­1ÿúç==Kë3ÎâëXôaGvôaGvôaGvôaŽ/Ý>³Õý£¹nù)ñ=j0¾”ûÌV—dž­¾ø5_Ê}æßªV_Û£†âK»ÏLôÅö¨øRï3}±=j ¾ÔûÌD_lˆ/õ>3ÁgìQñ5KµÏlõ¨rPF+Æ>ØØ£îsî?«ësã {Ô€|‰>ìèÃŽ>ìèÃŽ>ìèÃŽ>ìèÃŽ>ì6×7Õñ裯-ß´5ÇxzJì¹çôÑGŸj_±ù›4ûŠ¥Ò;eÇ-¾ü®±z}'+‡$· Ö÷3Š~ì“»Z}«¾¹§Õ·¼u¼rXòµúêµáÜž3³¶G*|žè£>ú裯K}Ú÷ƒ}hï>ú裯¼ûO>ÏþS…ϳÿTáóì?ø¼ûO>ïþßçßâûüûO|Ÿÿ‰ïóD}ôÑG}]êëÒýç/{Î÷ä÷3Uú裾¶r܉䜣ùw"9çh¾G}ôÑG}]êÓ¾ÿÔþÿ»ôÑG}me½[^Ï~·¼Ÿýny5>÷Ýò*|ž»åUøÜwËëð9ï–Wâk¦ùûÙ >GôÑG}ôÑ×¥¾÷]ðê6cj3%tEXtdate:create2017-06-06T01:31:13+01:00?¥ª¤%tEXtdate:modify2017-06-06T01:31:13+01:00NøIEND®B`‚puzzles-20170606.272beef/icons/pattern-base.png0000644000175000017500000001203313115373721020074 0ustar simonsimon‰PNG  IHDR€€+¥"èbKGDÿÿÿ ½§“ÐIDATxœíÝ{HTùÿÇñO^2›.ká“hfÅnýÑv“.›ÑPà ÛÃÈe·admt6Yö/Yj#Úl«m w­…ìfíÒZS ¶jìl#jaޱT^ ßaÿùµ3ãGÞçŸ?b”õÍÛ£ûâœ3㼆=þ\€„(é ]11111111111111111111111111111111111111111111111L¦¯¯o÷îÝK–,™:uêÌ™3srrêêꤗB„†=þ\z ïÞ½›2eÊŒ3¦M›vÿþýÖÖÖ?üðþýû#FŒ^ a‹‘^OLLLYYÙ‚ ”RgñâÅ/_¾|úôé¬Y³¤WCظƒÉDGGÒG)å÷û•R±±±“&M] "€`V>ŸoÇŽJ©}ûö?^zD‚‚)y<žÌÌ̆††ýû÷oÙ²EzDˆ{@0·Û½yóæŽŽŽ’’’5kÖH¯ƒÈñ,L¦»»{úôé~¿„ ©©©OîÙ³ç“O>‘] à &Ó×׸÷ÜÚÚÚÚÚød^^žèRˆg@Äp€€€€€€€€€€€€€€Ȉ çÏŸ?yòä3f¬Y³æîÝ» ÑÞŸuãÆ »Ýn·Û>,»–ãca&:>¼egg5êƒ>¨®®öz½#FŒxòäÉÈ‘#â·?ËçóeddüóÏ?½½½[·nýꫯ q-ÇÇÂLt|xGD#*++ < f8]]]ïÞ½SJ >|éÒ¥{‡Ïž=‹`”Ûív:/^¼())‰øÿöþþ~¥Ô;wnÞ¼ÙÔÔ¤”jllt»ÝRûh<>–d®ãÃáÜ2œÄÄÄÙ³gWWW¿yó&!!ÁápäççGðÛc´þ,]ûè:>Ve®ãÃ1Ü † † † † † † † † † † † † † †2.ãôp={Öáp$''Ûíö¢¢¢È†(‹ö\»vmÕªUS¦L™6mšÓé|õê•à]?/]sÞƒ2(ŸÏWPPù;Æõööž?>66ÖápÄÅÅݾ}{Æ ÝÝÝŒzüøq||üÀ›êêêÒÒÒ²²²Ünwnnnggg¸C4~_JÇqVJ]¾|9//¯¡¡Áét~öÙgJ©®®.Á9º~^ºæ¼ïˆhP†êá*..VJíÝ»×ãñD¶L€%ûÎúûû9Òßß_ZZºhѢȆhœ£ôý¼tÍy΀Œ(ÐÃURRb³Ù"¢·‡K—K—.=ztÛ¶mÊ0}g<Î^¯·¥¥%66öĉ©©© ,8uê”às!€ çß=\ZjéáÒ¥¼¼ü»ï¾«­­5TßÙ@ÖhooWJõôô455­[·®½½ýÀ¿þú«Ôs!€ §¢¢¢³³³¶¶6777Ð-wõêÕƒF6Íãñdff644ì߿˖-Z7Dii©×ë=sæLGGÇ®]»ž/ãô^ûª´Œ¢ì=C"ûB.Áˆ!€ˆ!€ˆ!€ˆ!€ˆ±~={Öáp$''Ûíö¼¥†®9‚¬@?ŽOII1ÈAÖ âââòòòôôtƒÌdý`X111ÖÿcT—ËUUUøc¹[·nµµµ-_¾ÜétJÍdýª©©q¹\Çõõõõõõ‰‰‰‡®9‚¬@ÇŽ;vì˜qæâ1111111ô‚É  –D/˜Éh©dÒÕ¥«L×zÁÌ2'â? à €€€€€(<7nܰÛív»ýðáÃÒ»¦G…ÁçóÄÄðÚ@( 6›-;;[zÀ" P;w®²²²¤¤Äf³IïX¯×{ðàÁ;wΙ3GzÀ:¸’ŠŠŠÎÎÎÚÚÚÜÜ܆†¥ÔÕ«Wûúú:$½`bPHúûû•RwîÜ ~¦±±Ñív‹-X—`!Ù¶mÛóÿÙ¼y³RjëÖ­Ò{æFÃ%XØŠŠŠŠŠŠ¤·¬€3 b b b b b b bè“A/,‰^0“ÑRÉdœ~¨À]=e{Á^U¦±ïÌ8½iJ÷q—`Ä@Ä@Ä@Ä@Äð,X¨Ö®]{÷îÝà‡III<ܰ(<‹- ô‚%&&JãÇ7Nz À"¸žôôô´´´Õ«Wß»wOzÀô PÅÇÇ/^¼xåÊ•'N|øðaNNŽ×ë•^ 07.ÁBuúô騨(¥TOOOzzzKKKeee^^žô^€‰q¿ßßÜÜüpذaÁDŒ3 ¼}û6==}Þ¼yÉÉÉ=jnn3fÌŠ+¤÷Ì3 Øl¶M›6µµµ]¾|Ùçóedd\¼x1))Iz/ÀÜ8 I\\]`€vœCCCCCC- jy`IáÖòp@ @ ¯„f¨bBãÝæhi < ˜ðÿC1!€!Š † † † õk×V­Z5eÊ”iÓ¦9ÎW¯^Io˜Ï‚…êòåËÛ¶m‹‹‹s:£GþóÏ?»ºº¤—Ì Iÿ‘#GúûûKKK-Z$½`\‚…Äëõ¶´´ÄÆÆž8q"55uÁ‚§N’^ 0=($íííJ©žžž¦¦¦uëÖµ··8p@ËËÉ€¡Œ Éøñ㊋‹=ºqãF¥Ôõë×E—L IRRÒèÑ£•RnÂèèh¥”Íf^ 09($±±±_|ñ…Rª°°ð믿þñÇ£¢¢²³³¥÷ÌgÁB•ŸŸï÷û].×É“'SSS æÎ+½`nP¨bbböíÛ·oß>éEëà €€€€€€€Š ePLK ·˜" ÓRcœz£Í ÖÅhE-Ï{†Dö…\‚CCCCcñêëëÛ½{÷’%K¦N:sæÌœœœºººÈFΟ?òäÉ3fÌX³fÍÝ»wõ® A ÞÞÞóçÏÇÆÆ:ޏ¸¸Û·ooذ¡»»;‚QuuuiiiYYY n·;77·³³SûÂÀbñ×ÅÄÄ”••-X°@)åñx/^üòå˧OŸÎš5+ÜQeee .ìîînkkKIIѼ10”X<€¢££飔òûýJ©ØØØI“&E6íÒ¥KuuuUUUJ©¬¬,Ò ‹PÏçÛ±c‡Rjß¾}ÁŽp•——ß¼yS)5vìØeË–éÜ’,~(Àãñdff644ì߿˖-Ï)--õz½gΜéèèØµkד'O4. AÖ ·Ûít:_¼xQRR²}ûöȆtuu½{÷N)5|øð¥K—Ž9R)õìÙ3‹CÅ/Áº»»×­[ç÷û'L˜páÂ… .(¥öìÙî_ß=}útýúõóçÏOHH¨©©yýúõ¨Q£¨åÈâÔ×׸÷ÜÚÚÚÚÚød^^^¸sgÏž]]]ýæÍ›„„‡Ã‘ŸŸ?qâDÍëCŒÅÈf³iyÃ#»ÝþÓO? |€³þ= †ECCCCCC/˜ zÁ`Iô‚™ ½`ƒ:‡^°ÿD/€!Š † † † Æú¤«Ï‹^0@;ë®>/zÁí¬ÿ: ]}^ô‚ÚY?€”¾>/zÁ½†Déêó¢ ÐËú÷€”¾>/zÁ½,@ºú¼èƒÅ/ÁtõyÑ  ‹®>/zÁ€Á`ñÒÕçE/0,~€‘@Ä@Ä@Ä@Ä@Ä@ÄÐ &ƒ^0X½`&C/ؠΡì?Ñ `ˆ"€ˆ!€ˆ!€ˆ!€ˆ1n={Öáp$''Ûíö¢¢"ñ9ô‚Ú7€?~?ðæ ]sè´3î뀊‹‹•R{÷îõx“°2µé»,/G›7¥ Î~Ó2+é)ñÈ!…3'ÓpÒÌq€Ñ·c¢.ʨPæ*ÛSÎA&ùy¡†K|‚ÕÇì„g9^Ã%"è¿R!ÍöV˜Ž*êºD²?¥ QÂoþÁDÏaœwÅt‹&ò®‡"»¾*`~þÀ€­SNeõ‹ÝùüñgB².W–àô±=SŠ>PÈ‹lM‚3ÓÎ’¢þ“p©GX*æ”®KD?ªb&]ÊbÈŠ\ °ÄXøL‚¥ðÙçα–‚?àÂç··;í­Îvgû -ëšššÖ­–õ÷wæq9 $§ãÐsêgC}þ¾×û¾ÁNDÃlA2¢gçø2€W?V°=èõù<Ý~¯ÏóÖ‹ˆ3Ð2+2p·¡ç–8}ú™çÿ¼Ý~Hè*yzø¼L¶õ{<^÷>¯Çãîß8ŽCf+,¦  æàabõÐîwƒ¡`Ï`(|§K_ö?¡.}ñxÛ–ÖÖ-›[!m}Ún³Ù¬kî±ØmwÔµ©KÒ*¥òGm°2ØagYë &“¡ÞΙŒfÔ²´èÜÄ+$€9θŒ1 «Y÷–pnüѱ®P°èDùeï±™»…W4%\y’)ì`À~¼„ tØ`©ð™ƒáÕCÛB^Ÿ¿¨¬¥wÅ\ú²Ãïêíuu»!ù:ïv8wÝ÷ÀZ‡ã^ëή2[…äÅÙ‹4hž½gq…åDõa,Hå!–‡Î÷¡æ´¯þA©ÿfõF3Žv²–%tEXtdate:create2017-06-06T01:31:28+01:00³-ù½%tEXtdate:modify2017-06-06T01:31:28+01:00ÂpAIEND®B`‚puzzles-20170606.272beef/icons/pattern-48d4.png0000644000175000017500000000077313115373740017656 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA† 1è–_bKGDÿ‡Ì¿tIMEáb¼š*/IDATHǵT[„0ëÑs4næÒX¨~,u¬Î¦„G»#³Ù߀µMÙpÌ“Û @æHa ‚¡² @_ŸÞlÐ$±*‰‹ÝŽ€¶“°2µé»,/G›7¥ Î~Ó2+é)ñÈ!…3'ÓpÒÌq€Ñ·c¢.ʨPæ*ÛSÎA&ùy¡†K|‚ÕÇì„g9^Ã%"è¿R!ÍöV˜Ž*êºD²?¥ QÂoþÁDÏaœwÅt‹&ò®‡"»¾*`~þÀ€­SNeõ‹ÝùüñgB².W–àô±=SŠ>PÈ‹lM‚3ÓÎ’¢þ“p©GX*æ”®KD?ªb&]ÊbÈŠ\ °ÄXøL‚¥ðÙçα–‚?àÂç··;í­Îvgû -ëšššÖ­–õ÷wæq9 $§ãÐsêgC}þ¾×û¾ÁNDÃlA2¢gçø2€W?V°=èõù<Ý~¯ÏóÖ‹ˆ3Ð2+2p·¡ç–8}ú™çÿ¼Ý~Hè*yzø¼L¶õ{<^÷>¯Çãîß8ŽCf+,¦  æàabõÐîwƒ¡`Ï`(|§K_ö?¡.}ñxÛ–ÖÖ-›[!m}Ún³Ù¬kî±ØmwÔµ©KÒ*¥òGm°2ØagYë &“¡ÞΙŒfÔ²´èÜÄ+$€9θŒ1 «Y÷–pnüѱ®P°èDùeï±™»…W4%\y’)ì`À~¼„ tØ`©ð™ƒáÕCÛB^Ÿ¿¨¬¥wÅ\ú²Ãïêíuu»!ù:ïv8wÝ÷ÀZ‡ã^ëή2[…äÅÙ‹4hž½gq…åDõa,Hå!–‡Î÷¡æ´¯þA©ÿfõF3Žv²–%tEXtdate:create2017-06-06T01:31:28+01:00³-ù½%tEXtdate:modify2017-06-06T01:31:28+01:00ÂpAIEND®B`‚puzzles-20170606.272beef/icons/pattern-32d8.png0000644000175000017500000000165713115373740017655 0ustar simonsimon‰PNG  IHDR V%(gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEáb¼š*·IDAT8Ëu“ÛKaÆ¿=›î¨uã]'ˆ  ±þ„̼¨ EPð"j+Ò -µÜUwr7•Šˆ ì@št‘‘R™!VZdêî|§gœ™]¡ ‹é›=éôÂïÅož÷yðŽ@²ˆ1UXBE”H0;ºð“’ÕyŒÅõJ~Í[‡·È¢o•hg·è‚ofhcâµ"}ÆXzñJ‘>Žk ,É‹ ÂXURI6€ a$f’˜–­ P{©’ï·"X›“Å¥X<¨-¡¸8w*ŠâOuºxrE´” $BèÊgÖï—eÖæ²µ ,A(PÂ*À,É1MÓu=ñ´ÄÛÌ„9—fžŒ%büy"&ž½¡( h”z¨é¹3Íç}k€ÓžÃÙ< JŒÝ÷kQm¤½?èâ{¸½À ŽÆ’Úœâ7m¨%p­£­»+XŸªRÓ jÃ7B}Ýa~¨ 8€‡®Œ“PŒ…÷ª¨<\QQyËçöywÛŽ§< ezRŽÆy¦ìòàÀL¶KÀØÃӛќ6OÝe/d€›îm“â×Y*üWš§¢"!vÝÁåå——””zór ʋˊU0ZcƒZ‹•ÈÉo-cäzÀ¬ñÛXZ§Iü7Qº˜%ì`Æøce¬Ò.g™;K¨ä°Ð7BÂÍ&káÝb¸ŒqMµw(B.‡D8úùóÒft â]Mлöu#Ä…°{øBð©ÅÙÃê¾Ñ¬ùðœ•lɯ¥%tEXtdate:create2017-06-06T01:31:28+01:00³-ù½%tEXtdate:modify2017-06-06T01:31:28+01:00ÂpAIEND®B`‚puzzles-20170606.272beef/icons/pattern-32d24.png0000644000175000017500000000165713115373740017733 0ustar simonsimon‰PNG  IHDR V%(gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEáb¼š*·IDAT8Ëu“ÛKaÆ¿=›î¨uã]'ˆ  ±þ„̼¨ EPð"j+Ò -µÜUwr7•Šˆ ì@št‘‘R™!VZdêî|§gœ™]¡ ‹é›=éôÂïÅož÷yðŽ@²ˆ1UXBE”H0;ºð“’ÕyŒÅõJ~Í[‡·È¢o•hg·è‚ofhcâµ"}ÆXzñJ‘>Žk ,É‹ ÂXURI6€ a$f’˜–­ P{©’ï·"X›“Å¥X<¨-¡¸8w*ŠâOuºxrE´” $BèÊgÖï—eÖæ²µ ,A(PÂ*À,É1MÓu=ñ´ÄÛÌ„9—fžŒ%büy"&ž½¡( h”z¨é¹3Íç}k€ÓžÃÙ< JŒÝ÷kQm¤½?èâ{¸½À ŽÆ’Úœâ7m¨%p­£­»+XŸªRÓ jÃ7B}Ýa~¨ 8€‡®Œ“PŒ…÷ª¨<\QQyËçöywÛŽ§< ezRŽÆy¦ìòàÀL¶KÀØÃӛќ6OÝe/d€›îm“â×Y*üWš§¢"!vÝÁåå——””zór ʋˊU0ZcƒZ‹•ÈÉo-cäzÀ¬ñÛXZ§Iü7Qº˜%ì`ÆøcfXV·yŽ¡d2‰D&Mš¤ëzª©_}iš>Ÿ¯¦¦æ…^àyÞ0Œkù]¤Œ±eY#FŒ¸ï¾û4MëNáWày˜7oÞwÞ™H$ºÍ¹vAÁ···† zÁ !ñxœçù@ `Y£Y˲ü~mmí† ***&NœÇ™;nbT”7Tõh0øè¬ÝG-_¾œþÐõó^†ùwÞùàƒ677SFY€1ŽF£ªªaŒYe !/^E±°°Ð²,Fk¦i†ÃaŸÏ·aÆ1cÆÌž=»©©‰¹ãÆE±Ø>Y†¢¢)<_BˆÂ¸ù§´=ÿüó]ÇE/mM$ÍÍÍ---Œ=¡£0‹©ªÊó<ÆÎ`!­­­‚ „ØG¡iš–e% eÙ¡Žsmmª¢€ ´r\”„2ï>!!”êo·‘ÐK[9ŽãyžçyÆù0ÆÇQƒN¤)›ì£R¯Ƙöš¹ãcžãǵGçÈ(ìɸGû€½ƒÒíÅG95CºÈ 6($„‚ IƘŽkBˆªªÉdÒe1‹H—BBÏó—.]zÿý÷Oœ8qáÂAJJJf̘QVV¦(ŠËb¶.…–eåååýáX»v-=û#„:´}ûö×^{m„ ²,»,f6:!DÅï}ï{¯¾úê»ï¾»páBA‰ÄÖ­[Ù7÷.2Fº£ã¸x<>}úô‡~X’$MÓFŒqàÀS§Nµ¶¶ªªJ÷».‘×öFa Ð4-bŒOŸ>ÝÜÜ cÆŒ ¦iºüeöV/Ó4MÓÌÏÏollüÙÏ~ÖÒÒR^^>gÎœŽŽw!Ìì=w˲òóóëêêyä‘ÚÚÚòòòuëÖƒÁ®±×6(¤›Ò÷ßîܹõõõ3fÌØºukII õ¢e»#×/l*ü~ÿÁƒúÓŸ&“É[n¹åî»ï~ï½÷::: ÇÏqœîÏ líAøä“O’É$Ïó§OŸ~æ™gh²´´tÛ¶m~¿Ÿ³Ý£ëéRˆÒu½´´ôûßÿ~^^ÝbŒ5M»ùæ›iÐÀå/+H—BŒ±¢(S¦L™1cF× 3%ÈqgÑlÁ†›!¤(J{{{ÏÏÝíLa/Ø„1vÏ} .ý.…ý.…ý½¬…toɾÃ$„P¡†iš†a8"B¤ñÓ41Ɔa8"B4 £3“Ä"Ä`Í*!Ä0,‹˜&bbb"”yS Né©Gí…BÜl=!¡¼¼<ŸÏ‰DœrßB ÃpVG †ãÇ À˜`Ì*BHð|B˜t¤„B”BÜ“Å^ÚÚÞÞFc±ãQúTÿûß×ÔÔ„B!Gƒš¦#„E‘wdª!½‰ÄëÑèÞXLã8F…8 ¥Í›?=p^~ù©¼šf1º=„°e% p5©aªªªªÊH¡iš^¯·®®®¶¶–㸾œö&´Á§“ÉÓª Œ§\Ó¿N‚º:ho?žŸª ì`:£^Â`0XTTDÕÀ,ßjF$‘$ öîÝ …سmâQš›(wüɲbŒ^ãüdr_SÓÒAƒžózçEˆ5§‚ã Ÿ{î™'žx·¸x§ |˲’,ÞÇΉaüCBô«O¤Ôù™Rf „¢óg( ‡Ã=óì!žI׉(â‚‚°e†“É€eÇãC(‚±É˜Q†PÄ瓎 !Ƹƒ%-¡”š;½µœØŽB玔þl†¦iÌ‘a`¢ë: Dt]·,€q‰51ÖtÝÐu°,@#DGˆ©û„šiZº„èš™M¨ó ÀÕ'Òo¨ì=¡6:­±ìÚ.l¦,tŽ”j9cÇ{5’ …Ý"l-ûF ^W°G! ¦Ò”¨ŠýøØué¥v×™ž>ìåTx½^BH"‘ÐuJ1‚Á ,Ë,-A×uEQhÐ?Y–Ýá˜&lhg¼^oMMÍÆOž<ÙØØèóùŠ‹‹+*****2;-P›»víZ¿~}CCƒ,ËùùùÆ ›;wî½÷ÞKåÅÙ~>ýéÎW„ÇSSSsàÀ˲FŽ 'Ož¬¬¬|ûí·©ØîwS…ÿ±cÇ>ÿüóo}ë[¥¥¥²,×ÔÔ,[¶ìŸÿü§×ëuС“ÃH—B*°2dÈêÕ«wìØQUUõÛßþ6 ÀÁƒEÉÀ•CÅóæÍÛ·oßöíÛwïÞ]YY º®Ÿ[´h‘®ëÅÅÅ ,ÁÖ§Éû‰DâÑG4hÐèÑ£UUÝ·o­â3~üxpméÁÞv&ÇqgÏž={ö,U²”””Ì™3G’$»9©ò™‡þûßÿN½w¡PhÖ¬Y3fÌp4iÂÆ¡¢££câĉEEEt•¢^M::%I²›SAÿm^^Þk¯½V__‹Å Ãðz½%%%Æ SÜQ˜l¤ÅhšVVV6vìØž9ííí™­[„üüü &ÐÃ¥išªªºÇ [°7‘vttt›ßèÁŽÅ“b†®ë©7ÀÕüÛEös*œˆ_×pß÷~—Â~k§€nºŒ-Ðu“@˜m’®6{Õ±Øìl¤#}ïÝÈ7Ha×!!ÀbS„xŽçãB!þøã7Þxîö)e øãŽ;æÏŸÿè£kš¶uëÖÇÓ,ªl?Ÿ~{Å,ËËË·oß^PPàõzëëë§M›ÖÐÐ@sÕ2.cY–üñ§Ÿ~: ú|¾¿üå/óçÏ€¶¶6wü¥ {k!Çqš¦íÚµ+øá‡‚ Lž<™çùd2“¢TÄváÂ…¿ýíoÉdòwÞ€aÆM˜0½¶Âu{)¢<Ï·´´TVV644еjþüùS§NÍøÎ&ºø}òÉ'‹-¢ëk X¾|ù°aÃÚÚÚÜ}i:°ãóù–.]ÚÜÜ\[[»ÿþM›6…B¡'Ÿ|2³;›¨¤jøðá«W¯–eyÏž=Ÿ~úé³Ï> …ÊËËÝÓE:°7‘z<ŸÏWQQã™3g=ztçÎ@ ƒòêcÇSRRRVV&Â<0eÊ”D"Q]]M·K.® {;vÌï÷swáÂzáalé}®‰DâèÑ£C‡D"ãÚÚZšžAÿïîHÓKDQüóŸÿ¼{÷î²²2žçÏŸ?ßÖÖS¦L‰D"L¤T!¾råÊD"QZZªªê¹sç4Máþûïw/Jö¶3÷ÜsÏ¿ÿýï/¾øB–å`08vìØiÓ¦UTTd¶¥‚üûï¿Ïž=Ÿ}ö™®ëEEE#GŽ|ä‘Gî¾ûnw!L6ù†aüä'?™:ujGG"~¿?//O–å Ü(tÿéõzŸ{î¹E‹išfYÇqÁ`PE7'&}Ø[ UUÅçåå¥JÑü쌷eYªªJ’äõz€¢ëº¦iîøK¶SD»EóÙëRÐl˜TqWŸo¶ƒMßÄóu9c;_õ{¸ö{ô2‘Òk Ø+÷P#ôxnv‚¹¤,"Ä4Mà8ªØ`­yM-†A= &!¬çQBLƒzɰû'H—[z¢ ý~8¶,‹]G‡A€üü|' ;žQ×c@cì@ùW„  p$É ÆØ`/ì ñùDšû1&³v¾Òïkm¥l×ÖÖú|>öli”§öíÛ—™µ0€zñ"‘ï|'©i*»ŽT’_~©9ãÆ:t‡¦µ1Ú´,ÓãÉ?q¢áìY¸÷^ÕçKšf’EGJq¹kç¿F!<7mÚ´aÃÆï놥K—:eŠã8Ó„±cÍÑ£/eV5¬[—C!ã£Z~ñ XºôÍÙ³ÿÔÒâ@NE$[·Âž=pë­Í7ÝäO&“,ã!¥æîUœýµÆÒÇ1sæÌ1cÆd<êŒq"‘Ð4-??ß‘ 0ƺ®¿øâ‹‚À…Ãaö«iÌù¶ÛF-Xð¿&D¼^)aÍ0 +Îózߨ … 2s@vÅWwÅôÆßóïMœ8qöìÙÍÍÍŒk!ED£Ñd2YTTÄþBИ³,Ë/¾ø"!(hšæHÍË¡Coyâ‰Á¢XÀó@Àd\_ Ê0®¨õùü~¿Ÿ±FAjÒ¹´Ûo{ONkjjjiia:ãX,F/žqdrGKÒ@ç.—]ˆŒ1Ö´ä¥KÑHÄ :L“uZ–ašˆ:K³SRöú{¡ã8zUŒ#rG ²»`è(LµÊW\ê ž§Ù<Ëg]̲§õ~­‘íìŦ{´ï÷¸Æå®hâGêDœÛy¹I¡Ïç£YÊt#®iš¢(¹êLÏM ?úè£?ü°¾¾^UÕH$rÏ=÷|÷»ßUU5ÛíúFSROccãC=¤ë_U×@mÙ²eéÒ¥‹/vä°Û×ký¡äâââ%K–¼ùæ›/½ôRQQlÙ²åܹs9Yï;§F!+‡Ãá7ß|sðàÁŠ¢Lž<ùË/¿\·n¦iMMM4í&ÇÅœ¢:f^¯·¹¹!ÔÞÞþÅ_À 7ÜPZZš{üAîM¤@¡bÔP(ôꫯ¾óÎ;Ç-Y²$‰8*ésȵQ–e ‚  /¼°yófI’*++§OŸÞÞÞž{{È= é%纮¯X±bçÎüõ¯=yòäx<Îó|NÞã•SRŸu2™\¼xñáÇ%Iš5kƸªªŠã¸oûÛ99—æ… BCCÃ?þñPUõ•W^I9ø×¯_ß}÷Åãñ»“-×(´,ËãñÜu×]4wœŽKJaaaaN¦Úä…4ñcÀ€o½õVÏß*Š’“©69E!…eY±X¬ç穟s 9H!8‘éÑk³Êu—Â~—Â~Þ«ƒ¥ ¨ôÁ²,ZOárbäŒëºžY¥†n ûØØ=8ô*=A)Iº 6Üì_ K&pמ¤Z%ŠâÀ©ÒŽÝf2™€p8ØÏŽº®8æ-;õ0¯ `ë¥ÿŠ¢Äb1v­»eY@`óæÍÿú׿V­Zåóùس¥8Ž“eY„Ï?ÿ|îܹÑìötLÓL&“’$ñ<Ï>¬-Ëòz½|ð´¶¶†B!§ÔܽÖ4è…BUUeYV…=]AÅãÇ?~|ñâÅ4ËX!Ÿª¹yžF£o¿ývßÁ+Š"Ë2û«–*öÙóW½P ‹ŠŠA`Ÿ£xž_½zu"‘2dÇqŒk!ýç´|f$a_oLÓ …B‡Z±bŲeËfϞ플½µµU–å²²² ®Xíµã—“Rö¾RÑ4{Æ BhÀ€ùùù‚ 8µ‘Á2DE§(,((¨««€p8\RRß]ÚÈP($˲$Iì ¡íœ èQò<ã/MÓh•f§œ“„d2iYVGG‡#z<MÓhSE¡õ¥ÍÒ-RªãŽLø—3ò ÞS‘ÚD9^‡„z;y'R÷JCgq~G,S;צ‹{´ï÷È>…tƦï~®zMüH }êÉÀN–#TêBëBkšF³J¯‡8!Äï÷[–E×uBˆÏç£ÐíNãÙ¤êçO:µiÓ¦'N´µµÅb±gŸ}vÉ’%±X,‡‰¤Ò‚½{÷þõ¯=yòd4ÍÏÏ1bÄc=V^^n—ÅlN¤tÖÕÕUWWÇãñŽŽpÄáÒÇAñx ‚pþüùèºNk}üñÇ¿ùÍoòòò¦M›–« $ †¯Zµªªª c\ZZZ[[{øðaz‰ÜÔ©SmåAfÿhæÌ™_ýêWô(8tèÐÁƒGõÀ0†ˆû,¨;íüùóôçcÇŽ;vŒ>K—.MŸ>ÝV`5ˇ MÓ†¾jÕ*ŽãhýYúà 7Ü«C0Õñ|püøñ’$Agu Ó=ëúPмˆôW?ÞÚ$/ZBÚ—~Ów´/H^´ý0®~ù´I^”„$ À<‹>ÓW¸D€SYƒùRømß)ÝE[(à‹±€uÜ’Ì`( ÄH^d±$/Ê-¾ yQ„Ò@ €æEú@’}úQk«HÒ–ÐÛ쎀â@퀋ä‹èÌ_™ÀX¥'ëâôì Ds!ý¼ÈYçEÎ:/Jr!ý¼è·¾ùR_š¶øR_¸ý»H//¢¹A^Ds!‹¼Èz º£ÔQí6 ¥þ‰˜Ù*Ôò¢˜ÙìÔò¢˜Ù®Õò¢$B^7j+÷†²iËõÌ rUýŸ00˜çךäÿHV@ùÕ€w~­àž_ÝEœãeç8ç×$@îø×ÌÒáè^K±%tEXtdate:create2017-06-06T01:31:27+01:00Ee‰T%tEXtdate:modify2017-06-06T01:31:27+01:00481èIEND®B`‚puzzles-20170606.272beef/icons/palisade-ibase.png0000644000175000017500000000253213115373737020364 0ustar simonsimon‰PNG  IHDRÀÀeœ5gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<&PLTEÕÕÕ¿¿¿ÁÁÁƒƒƒRRR+++EEE‘‘‘ÔÔÔÌÌÌ555ÈÈÈËËË<<<888yyy”””TTTªªªAAA³³³nnnzzz¾¾¾sss»»»“““gggÏÏÏ–––‹‹‹‡‡‡mmmpppÒÒÒ‚‚‚=== ˜˜˜ÀÀÀ***YYYttt›››SSS¿¿®®®rrrCCC"""LLLÑÑÑQQQ   kkk ŸŸŸÓÓÓŒŒŒ¢¢¢¨¨¨ÎÎÎÍÍÍ 777±±±ÊÊÊ///µµµ¹¹¹wwwššš¦¦¦———¸¸¸ÉÉÉ,,,ÿÿÿF¿‡"bKGDa²°L†tIMEáü؉ vpAg  OýIDATxÚíÝiSA…a4&Šƒ¢€‰"’( .ྋû¾þÿ_át$TªÒsËq:Þ¾Ö{¾P•\†~Š™0SôÈ!„B!„B!}) íH€L§\±Xê|ÖõŒ8X:T®>2vÔ$ :¾ 8qÌ" Öw;i0~|êÄôÌI'˜5¨ž:Ýý8çó½,8ÀÀº4 Î&O-ž³ X*'O-ç^à|3yf.ÿ‚´+îX ° @k&y¸|!Ä‚TµµäÑ‹ëA¤hw’/Íúç ª—Ýù¿q¥›«£ý¿’Ü ð' ÿŠYòŠ)[¾ˆ0ÔsTúÚ!æľgþÚõ7Ë•íµùZ¹/äììÏßüÚ@î ‰€Âöí(R_ȸ3±º|wýÞ}7ÿ €Üòþþ0íæEèÅßJŸìæŸD¨»5þh¾õôÙÂØóä©ÒÀë–"ÀßòÎïö^µÚ¹Ò’/^æ_P0@Z_Hü”§¢¤ö…Ræ[íF)¢‹Xè ¥_3¯^<ÙWH}!áfcˆ}¡Áù·{/=ï*¾{ŸÄb_hp~·9ùþÃÇO+Ÿ½—@n«x}ã_n_m:_s/HðíûÆíJóggsÉóˆ·”D ÈÚVÙÊ’Pób˜¿Äþ¾Üÿ1Ð’û?úBrÿÇ@_Hîÿê ùû?6úBBÿÇF_HèÿØè ý}!¡ÿc¥/”Úÿ±ÑêÆßÿ1ÑÚ‹·ÿc /$÷ ô…äþ¾Üÿ1Ð’û?úBrÿ‡¾ÿ`Ø Ò†3 Ó)WòÿÌÊz|ÚÇ }|ÚÇ }|ÚÇðǺߙ ì~g €°û©Bîw¦q ÝïLñU(Ì~gŠ€ºäÞïLf¿3=@ÆýÎ~7@= Bg%tEXtdate:create2017-06-06T01:31:13+01:00?¥ª¤%tEXtdate:modify2017-06-06T01:31:13+01:00NøIEND®B`‚puzzles-20170606.272beef/icons/palisade-base.png0000644000175000017500000000776113115373721020215 0ustar simonsimon‰PNG  IHDR  ›á9×bKGDÿÿÿ ½§“¦IDATxœíÝOHÔùÿÀñ™ßØú¯ÈQ ÖLpµº,M†ÿð“(!¬éžö" nL"^ì"Ø¡CPà¸)!E$Ò̓ÿæ°Ž‘Ö0œŠhüC‰è(ÌÇù¦ß‡Ym«­yÍçó±çã4ŸÏ à Ûç~Þóq>~¬@À@ÆOzìg"0@‚ D`€  ˆÀA"0@‚ D`€  ˆÀA"0@‚ D`€ ý_¢Þèĉ‰z+À8¾ó‡r (aKDAþ÷ÒÒRìAnn®¾“ÄmmIo˜¯óäæbžD}äá"0@‚ D`€  ˆÀA"0@‚ÿ]Äÿjeeerrrvv6 †B¡õõu»Ýîp8JKKkkk­V«Þ3ßHçÀÂápMMM4ß©ªj( …B£££N§Óãñdffê5!ð=t^"F£Ñ]uí233ÓÑÑ‘´y€ÄÒ‰h±X¬VkYY™¢(EEEápx|||xxxgg'ö¬×ë \1 3Ò90«Õª(J{{{aa¡¶SQ”¼¼¼žžmÏÜÜÁŒt^"¦¦¦öööÆ×ÓÔÔ¿¹½½Ä¡€„1èizUUã7 tø. lhhH{œ••UYY©ã0À73b`ÚfgggJJŠŽóßÌpŒŒ¸Ýnm‰èv»ô øf†8M¯éïï÷x<Úf[[[KK‹ŽóßÉ(©ªÚÝÝ­}ô²Ùl]]].—Kß©€ïdˆÀ677ÛÛÛ§¦¦b›iii·nݪªªÒw*àûéØòòrkkëüü|lÓápôõõñkeìúÙ·¹¹yaaAÛS__ïóù|>_üËŠ‹‹ËËË“>ð½tlcc#¾.‹Å288¸÷e.—‹À`F†;Mì'Òy‰˜m»{8‚‚ D`€  ˆÀA"0@‚ D`€  ˆÀA‰¿\eii)áïù EÑ{sXZ2ÄŸ?Ñþ¹ÆÆ 1O¢p (ñKÄÜÜÜ„¿ç÷0ÈÓÚJ,7—y>A[d‹%1+UŽ`€  ˆÀA"0@‚ D`€  Hÿ[È®¬¬LNNÎÎ΃ÁP(´¾¾n·ÛGiiicccmm­ÕjMæ<Á`Ðëõ¾|ùòõë×>|X[[³Ûí‡.**ªªªºpáBZZZ2ç©é Ùšššh4¿SUÕP( …FGGN§ÇãÉÌÌLÚH÷îÝ{öìÙ®y§¦¦îÞ½{çÎn!¯¤ó1îªk—™™™ŽŽŽ¤ÍóE+++W¯^D"zsЉh±X¬VkYY™¢(EEEápx|||xxxgg'ö¬×ë I;hØív§ÓYQQ‘ŸŸŸ““³µµå÷û>|¸¾¾{Áâââ‹/Μ9“œy`j:fµZEioo/,,Ôv*Š’——×Óӣ홛›KZ`ÝÝÝ?ýô{UUUIIÉ•+W´=«««Éf§ó155µ··7¾®˜¦¦¦øÍííí¤´«®˜ƒÆo=z4YãÀÜ ±DÜKUÕøÍ‚‚‚ä‰D¢ÑèÚÚšßï¿}û¶öÔ‰'Nž<™äy`R lhhH{œ••UYY™äž>}ÚÕÕµw¿Óé¼yóf’só2b`ÚfgggJJŠŽóhÊÊÊ®]»–““£÷ 0 Ã}“cddÄívkKD·ÛÝÐРïHšééé‹/>zôHïA`Æ ¬¿¿¿³³Sû-S[[Ûü¡Ë$—.] ¯^½÷x<Ú9LUUoܸá÷ûu™ ¦c”ÀTUíêêòx<±M›ÍÖÝÝÝÒÒ¢ïT6›-''çܹs÷ïß?‘øäɧ‚‰"°ÍÍÍ?ÿüS;±‘––ö×_¹\.}§Š—žž~ìØ1móíÛ·:Ñÿ$Çòòrkkëüü|lÓápôõõéõe¿7oÞ¤§§ï=ñîÝ»`0¨m8p ¹sÁ¬ôÿ²ossó‚¶§¾¾Þçóù|¾ø————'ažçÏŸ_¿~ýìÙ³ÇÏÈÈX[[›ŸŸüøñÖÖ–ö²Ó§O'aì:¶±±_—ÅbÜû2—Ë•œÀ,K$ñz½^¯÷ß^päȑ˗/'g˜!>ƒ™Hii郒yù LMÿÏ`†rþüùC‡MOOûýþÕÕÕ÷ïßG"‘ôôôüüü’’’ÚÚÚêêj¾Æ¯§s`ÙÙÙ¹ûILFFF]]]]]Þƒ`Ÿ`‰"0@‚ D`€  ˆÀA"0@‚ D`€ %þr•¥¥¥„¿ç÷XZ2Ľ¼åヱ1æù£Í“(ÁAJü1777áïù=rs qÅ´¶òažO2Ú<KbVªÁA"0@‚ D`€  ˆÀA"0@þ·/ ƒ^¯÷åË—¯_¿þðáÃÚÚšÝn?|øpQQQUUÕ… ÒÒÒ~äy`júvïÞ½gÏžÅïQUuqqqqqqjjêîÝ»wîÜIæ-›6LÍèKÄ•••«W¯F"½ùÈhóÀàô?‚Ùív§ÓYQQ‘ŸŸŸ““³µµå÷û>|¸¾¾{Áâââ‹/Μ9ócÎSÓ?°îîîŸ~úÇ´ªªª¤¤äÊ•+ÚžÕÕÕv˜šþKÄ]ÿ5ÇíêêÚ»ßétÞ¼yÓjµþàóÀ¤ŒØ'•••]»v-''GïA>2Ú<0>ý?ƒ}ÆôôôÅ‹=z¤÷ mŸQ»téR xõêÕøø¸ÇãÑ~“«ªê7ü~ÿ>LÊ(ÅØl¶œœœsçÎÝ¿?þÄÝ“'O˜fd¬À4éééÇŽÓ6ß¾}«ã0ãͳÐ9°7oÞ,//ïÝÿîÝ»`0¨m8pàÇœf§óYÄçÏŸ_¿~ýìÙ³ÇÏÈÈX[[›ŸŸüøñÖÖ–ö²Ó§Oÿ˜óÀìô?M‰D¼^¯×ëý·9räòåË?ì<05ƒ~Ó”––>xð 33SïA>2Ú<08`çÏŸ?tèÐôô´ßï_]]}ÿþ}$IOOÏÏÏ/))©­­­®®Næ×&Œ6ÌNçÀ222êêêêêêôCc´y`vF_"¦F`€  ˆÀA"0@‚ D`€  ˆÀAJüå*F»w–Ñæ[Ò{‹ÅbQ”ÆÆ ñó‰›Ç?ŸDá"0@Pâ—ˆ@ áïù ––>®4rssõ$F[©dž±±±ØƒÌc±ëç“(ÁA"0@‚ D`€  ˆÀA"0@þ7àÃç­¬¬LNNÎÎ΃ÁP(´¾¾n·ÛGiiicccmm-·S223´p8\SSFãwªª …B¡Ðèè¨Óéôx<ÜаX"Z4ÝU×.333I›ÿG0°Z­eeeŠ¢…ÃáñññáááØ³^¯7íÂmĘ¡Y­VEQÚÛÛ µŠ¢äååõôôh{æææ̘X"Zjjjooo|]1MMMñ›ÛÛÛI ÿ™’ªªñ›: ‚/ 0SÒgeeUVVê8 >ƒÀÌgbbb``@ÛìììLIIÑq|™ÌÈȈÛíÖ–ˆn·»¡¡Aß‘ðœE4“þþ~Ç£m¶µµµ´´è8¾ˆÀÌAUÕîîní£—Ífëêêr¹\úN…/"0ØÜÜlooŸššŠm¦¥¥Ýºu«ªªJß©ð5Ìè–——[[[çççc›‡£¯¯_+›Z8nnn^XXÐöÔ××û|>ŸÏÿ²âââòòò¤O‡/#0CÛØØˆ¯Ëb± î}™Ëå"0câ4= ˆÀA, -;;Û w«Á·á"0@‚ D`€  ˆÀA"0@‚ D`€ %þr•¥¥¥„¿ç7P%ö`llLßIváÏi|žAþûIŽ`€ %~‰˜›››ð÷üÚÊy>I[©äŠimehŸO¢p ˆÀA"0@‚ D`€  ˆÀAÜ]e· ŸÏçÿëëëÚSÿýwff¦Ž³a¯•••ÉÉÉÙÙÙ`0 …Ö××ív»Ãá(--mll¬­­µZ­:ŽG`»=þüÊ•+zO¯‡kjj¢ÑhüNUUC¡P(u:GÇÿ-²D„‰E£Ñ]uí233ÓÑÑ‘´yöâ¶›Õjýå—_N:uêÔ©Ÿþ¹««Kï‰ðV«µ¬¬LQ”¢¢¢p8<>>><<¼³³{Öëõ½.$'°Ýª«««««c r­þÕjU¥½½½°°PÛ©(J^^^OO¶gnnN¯ÀX"ÂÄRSS{{{ãëŠijjŠßÜÞÞNâPÿ@`؇TUß,((ÐiÃ~444¤=ÎÊʪ¬¬ÔkÃ~311100 mvvv¦¤¤è5 a_q»ÝÚÑív744è8g±ô÷÷{<m³­­­¥¥EÇy,†ýAUÕîîní£—Ífëêêr¹\úNe!0ì›››íííSSS±Í´´´[·nUUUé;U ÁÜ–——[[[çççc›‡£¯¯Ï87 °Ý677µ/p¼~ý:þ©/^¤¥¥ÅÿöÛo6›-ÙÃáŸÂápssó‚¶§¾¾Þçóù|¾ø————'}:‹…Àözûöíï¿ÿþɧZ[[µÇ333ZlÐËÆÆF|]‹epppïË\.—^qšD`€ –ˆ»ýúë¯|‰Þ,²³³ þÅ D`€  ˆÀA"0@‚ D`€  ˆÀAJüå*Æùsøü{‰â"0@Õà„¦Æ D`€  ˆÀA"0@‚ D`€  ˆÀA"0@‚ D`€  è3Äo—ªTIEND®B`‚puzzles-20170606.272beef/icons/palisade-48d8.png0000644000175000017500000000262313115373737017771 0ustar simonsimon‰PNG  IHDR00`Ü µgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<óPLTEÕÕÔÙÙ×ÌÌÌÚÚáãããÛÛÛ¤¤¤œœœ«««ââß%%%ddd^^^UUUjjjøøøéééKKKÅÅÅFFFÔÔΓ““uuuŽŽŽÕÕÚòòòµµµ222½½Á‚‚‚ÇÇÌ;;;××åHHE00¿¿FÆÆIÆÆGÈÈY»»»ºº·¼¼Ê´´{²²]»»?ÑÑ­ÓÓ¼ÝÝíÔÔ™ÊÊiÉÉJÈÈ„ÉÉgÓÓÆÏÏ“,,,ÐÐŽ××éÎÎŽ××öÓÓqÔÔ“¦¦F™™/±±VÐÐm““4‚‚#ÂÂaËËtØØúÑÑM44&}}gmmBÈÈVÿÿÿq™ùbKGDPãnL¼tIMEáü؉IDATHÇV‰zÛ6 HB²ãk%7áÜÔ±²%SÒvKÒÆnã¦ÝÚÝÇû¿ÍÀS²ïÛ™?~€T‚ üqkEꊃbwQ*©¬ø6(®C¡' D–ÿ— l“ÜÃìh4Ž2{zŸÚñY¥òÑWª°¾ U€m}Èã+XJà9…>^™•RdãÒÂ綺 ¹Ò½ Ô4¯ž±9j¿‰ÝKôè*5uÜç'ÇLƒN aŒ´c¥ ¿LòP€øzñü”wѼ ÷ œÓ¹óŽ_,-±ÁY·¨r°ó h¶ªr z¦*xpÒB%Énâ#õÅÒƒä=Ö,¤Ôë<$ZXrAÇŽ "ÉC"IFr~x¤ÔMƒ1$•OP[B‹QUF9?OjùÍ·—ß^•Ë´Ï$•YÛ¶WöwýòÕuåõ÷?°>”ä N] 1Œ›Û»~²ÞÔ†¥ËCÁE”Ù¸¨¼âv0àáæí}SÇ /Ö1=ÈÙj: šÊ–¨?/UÝlîè BZ™%TÓ¹k&{7–м¿{H—ë½ÒàUÏT€Dz²¢ºÙÞ5q[´±øœ¡&/ÊŒœÊ&«Š Ù2$Üóб„Wƒ¼EZH"Ëk†Ô„â¶° ‰Á(åYâé!kµó`¥†Cƒ"êT^ß4McøùpûøßM#ùyVë ‘ÕË›ívË¿ÛWŸn½¶Ý~üñíf»Ù„]e>!ÍeÄ¢¡úéóýݽ•ÇO_ùå;?ÿÂï_#Œ AyHCúÍiüü7Ò“A×8Rmƒ–©4|Ðc)AórÄFrâHËœóðÞ³äÎéå÷h¥ÁòÜ't¾ZÉ”‡à»çÎ4ÊÑш";šIyð Sµb:@yv²äÛÆBZä³)AJœ]v¹înºkfYÙËÙÕÒb2ÉœÁCZäkÉôYR%[ÞNm61|¢¼»Òhù¶°§»–ÎCˆ!Ò ‘Ö¸•´Ðñ½Ç’é>›”MËÊ ·åѪ,z^þùè g¿ækæŸtÍLÒŒŸv-,g*}ENÅš¥£µCHˆ†4cƒÅñ¬&„3p· Ý}ªØ°Û¯èÞ—_ô5ˆGÝz Yu² G;*ì¤Ìf}+}n¯Cï2 ©'½*Á^ÏëF‚1©yBhgËÝU¸·Çî‹UžÆý½÷¿Pì_¬Z©ÐÔ}%tEXtdate:create2017-06-06T01:31:27+01:00Ee‰T%tEXtdate:modify2017-06-06T01:31:27+01:00481èIEND®B`‚puzzles-20170606.272beef/icons/palisade-48d4.png0000644000175000017500000000114213115373737017760 0ustar simonsimon‰PNG  IHDR00¥,ä´gAMA† 1è–_PLTEÀÀÀ€€€€€€ÿÿÿÿÿ+ë“bKGDøoéÇtIMEáü؉vIDAT8ËmTK²ƒ dÔ¼õ€@ÐĪÔ[‹Roí"ÈâÝÿ ~ Ê„ÌÐÓM“ àÀ§@Ž4 %Ô¼šmVJlJˆyUœ¾BÖ°{ðcºÄা’0n’Œ ·ã‘%æTJÕ8ˆ†‡ð£ŒßÓWÄÉoqWåö…ÐÊÉ^nÒ§Šª\ŒÛ$ÆI“¢a¥Y"¼ö¦÷îP§WO?wûcð]xÀ˜Xw&ÐNÁyÀ&˜H¥Lˆ%ª"Ùý|b)6uÏTŠG¯´/Õê²ÏÖ…ª>Üê'rFà UìŠÀýDLÿRë†ý“ÖJd½·‚W?ÙEÉ\„~»…\“Nþtä°¦>’*îO ¹„h”—+JKú`;ñµKJw&ŒçÐG©Ï‘õ¥°4±Ù3KÞw¯ðfûYêê®r}¼©E¿…„5öC^Q·µ<§ÖxÖ*Ú ËÖE;çÿ±'DË+›XK_%âä¨5e_¢Ë$çùZû%tEXtdate:create2017-06-06T01:31:27+01:00Ee‰T%tEXtdate:modify2017-06-06T01:31:27+01:00481èIEND®B`‚puzzles-20170606.272beef/icons/palisade-48d24.png0000644000175000017500000000457513115373737020057 0ustar simonsimon‰PNG  IHDR00Ø`nÐgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEáü؉IDATXÃÍYMhTY>çÞ÷ªêÕo§’0fb ÑÞ¨ñ'D:L‚àÆM(p!JLÆÕ€B;3 dc ®Œ;—‘F\DbDmã!ØB:D¤cfRIêïýÝŸY\ëY©zUÚcÚ™»$ïÞó¾wÎw¾sÎ ÎÌÌÀÿÓÒJBüO@B|B"‘Hé³_i !Jß"¥Ìårå€!¦i>{ö̲,D¬f ¥”}¥”²†‘p8l𦅡P¨££ƒRª,k r$™ššºpáBww·išÕüdÛ¶®ë5¼È“R¸=ztðàÁP($¥äœ'‰}ûöQJ}<ÔÓÓséÒ¥ååeMÓ„ê#!êsquu5‹y‡Ë¼¢Œ0Æâñ8çÜ×Iˆ8444<<ÜØØèº®rR&“ñ>@+ÝZ(–——WVV!Ñh4pÎ×ÖÖ2Èd2¶m×Ä9·mÛ;RGD´m;N+wª=¥7d!DÓ4DŒD"·oß¾wï^{{û‰'t]WL¤”RJ5Móˆ:ÊÁÕXˆˆž‘J/ú³AÅëèÑ£ccc±Xì‹)‚ åùææææææÎÎÎ4ÿ€8çñxüÊ•+}}}}}}ñxœ1öeÐ@µÀììì>|855eƧÈϦ,­òO”Ò|>þüyBˆÂqœ|>ÿÅBæH‘?—Ëy‰êå‚BJ©~úš%«ò)"J ˆ €€Uy|ÅÆ0Œp8ìë-¥Cȇ Ϋê"0È."H)m@J²VWW3™L%!„a£££óóóÑh´š³¤äº•Òw0KKÿ°í?¯®8FH],ö'@n$¥Ôu=‹yZ¬â¢>TJiÆÒÒÒ©S§Z[[mÛVªï9UJNÈW–u›óùHäB¤}…ø[2ù{Bê¤d€H¨B•JM‹KÓ´`0è8Žã8ŠÝê­­­mmm–eBB¡*8ʉ„$Mó7Œ­Çb_ ± @ýœ„ét˜ÒVBê€ ™óRBÖÖÖfgg[[[·lÙbY–8Û¶-ËrGJ9==Í9ooo—R Á(µlÛaÌ ,!l_@ȘҖÒp‹tÆ ƒW¯^}þüùÛ·o/^¼ØÙÙ™Ïç½O]×nݺ5==½mÛ¶ÑÑÑlv­$%Tbú¶D,˯÷Qª!BD£Ñ³gÏ>xð@Ó´‰‰‰îîîl6[Š8?yòd|||qq1n€!¹\npp°¿¿}}½­­M%Z©{,ËÚµk—¢GG‡ëºEvm6 ÅÎùöíÛ5M#„X–庮÷HJ ¤d€öÍ7d>_D!%—RU.%¯‚O €(ñÄRæ”"„(5R ¤üA)U#"RGH’  !‚”±>ˆêz ž†¨ùŠD”Ö!&\"¥2ãˆ1fš¦išª-]Bd̲¬›¦ù[Ûv*J•¢óóÏf—öuB|u~øáí¾}7ƒAU¢ v{b­m4*cœóJ+BƸ”œóŸË1æVÖN]e³K++i)d¬jÇòî]Îq~Ò´°€#Æ~çã!5OÅãqÛ¶UÚ+Ò¨H !ÂaC×£‘È·±ØŽ@À*º Ô¨Àê÷î“òG]ÿ.‘xç›1˜JýSÓ¾El,*µbݧ–©©”s.„àœ†¡HÏçÕøÇ¹Rño!bœ[š¦Åba%H…BQ 2ËZg,ŸH¼ãü_zßúd2v"±Bˆ`ERWƒlšyMÓ¡„Mmóõ! V„¸1«|N 2Æš››»ººÆÇÇ_¾| …Ê !„¦iÝÝÝ…BallL×õ¢,|îòçç|ÿþý¯_¿nhhhjjòÜã!vgëÖ­ñx|aaaÏž=›8TmÝ''':”Ëåž>}jF©‡T÷øâÅ Û¶{zzîß¿ï8âæLþí‡ê.?~ÜßßßÛÛ›Íf+‹+ܼySJ922¢˜÷«” „ض}òäÉÓ§O !r¹œR&/.ª–íØ±ãòåË`Y–išªÚ—„î¿ ¢¯T"zW$J‡¼™ÁÛà8Žê$‹:ô¾ò`Wi-O~êTK­ZŒ¨Õ¦8¢,ö“^ÇøáÀ{@Bˆp8<99944¤& ßPÎÍÍŒŒTª€2ªëÆÒÒË#G;¶šÉø×2DýûïÝTêÑh”sÀIÆb)ƒÔGWW×ððp:ö¡æ•ç¼®®îÆ‹‹‹õõ !¯þ(_zCU*õ׆J)Qí ")ŠäÆ©ûÇÆÆF¨¬öPr¥ç{aÅ9O&“ñxüçŸUƒˆ†a„B!˲Ԭ§NE£AJ„¢ ÕUpHQÄu]U¹|qÎÕÓÊ B×u9çꉔ’RúæÍ›W¯^íܹ³¥¥Å»ßå\Hɤ$%ÔùÀRùÖ«ÆØØÃ*@ׯ_?vìØÌÌL™ºq”OBšw>TÚKy]­sVƒ‘HDµ—–e;wŽRšJ¥ …‚ǼF½ÿu¨;”²ì—.Åbdj‚Ã0¼;×Úë‡ÔHÿ™e²ô–ŠC°j>q(ÙÐ1~”jFÔ×§H_â¢î lÿ–ôµ¨KÏ;%tEXtdate:create2017-06-06T01:31:27+01:00Ee‰T%tEXtdate:modify2017-06-06T01:31:27+01:00481èIEND®B`‚puzzles-20170606.272beef/icons/palisade-32d8.png0000644000175000017500000000234313115373737017761 0ustar simonsimon‰PNG  IHDR D¤ŠÆgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<_PLTEÕÕÕÛÛÛÝÝݾ¾¾···¸¸¸ÀÀÀPPP~~~xxxuuuiiiJJJÏÏÏîîîãããêêꀀ€ÓÓÓ„„„ÉÉÉxxwBBB¡¡¡¸¸·LLLsssmmmÔÔÒäääÜÜÜÖÖÛ{{}ããêÓÓÚÖÖܯ¯µ››uuhÞÞÂÏϵÒÒ¹wwjssJyyssn——DÓÓ€ÉÉwÌÌ~ÔÔÏääã××~ââîááÞßßÁÑÑy××îÖÖá’’’ÆÆÅÐеËËxŸŸŸ¤¤¤%%%®®®ßßåËËyªªª222ÖÖÓˆˆˆÈÈÅØØÞyy|ááçÓÓ½ÏÏ~××éÖÖäÔÔ½ÑÑ€´´¶ÑÑ´Ë˾¾hÔÔÁÕÕÂttt¢¢DÓÓÞßßêääïÙÙã””’×××çççÜÜãÙÙ¾ÓӸ´´´hhh¾¾Â¸¸¾´´›ÂÂuË˶ccbÌÌÌ¢¢sÈÈÈÔÔÔÐÐÐEEEÿÿÿ-¶&bKGDtßm¨mtIMEáü؉IDAT8Ëm“‹SÓ@Æï.ך®W ¤¤mPZ©-T($¨F ¢Òªh}+¾PñÿŸq÷ 3º“ö»Ç7—Ý_ö!”ý?p`<Áõ“J† `›¦¯˜–m[–?6NmslÜ´MAãf†e2R2"uÄʲé«&á–²˜š°rJ䈂 "‡¢(wÌbƒHONI4`JJèÌhÞ’zɬiq¾ATNÿS>2ØRÍÌTéWh˜r“T¡@á,Îy …J£X*ûç9¡”àœçñ™OÁˆ×®/TªÚ0CrŠO›ÀÀ±n,.9@ÅZ¾¹R»UO^! ”¥ îl¦QZX]kJÙ,Ý^ßð[I80LjÓÙò*5¿î*UB?IªHO¶ ` w¶wvƒ°ë®Wí ÆIRàÀ8ïÞk—*aë>¬ûÁ…Aà Œx`vý*œà7 :QlàVC5^Ä–¼½RÔÚ?èy¾ï=:|Üó/s O îài°ÔÕjpxÔ–pxº¹úüâj­V ú/V°ÓA9À» “”å‹kÇ/_ {ƒ• ßF½Á%j³¸Å¸Ót_;]_×ïºèE™SÛ;šèn9¼q¡š‘A×_à±îÅ ÃÐõĉ¨Q»Ñ¹¡Zº5/f£B–IÃ|KAß½ ú€‡§OûÈù'n´?Ÿ ~ùúí¸­U® 0DßÇ‹øù-{Vß óÇ2.§âäçzx€òKÆð&Pè)³iì^nµb6ÓAüÒ÷bŽ;ØB7oÜ&¶7ôñ)ùM\w.e6ÏòÚR˜ë8#É…Hï#ö²ýox#/Æ_Ý\\E+¼Ù%tEXtdate:create2017-06-06T01:31:27+01:00Ee‰T%tEXtdate:modify2017-06-06T01:31:27+01:00481èIEND®B`‚puzzles-20170606.272beef/icons/palisade-32d4.png0000644000175000017500000000077413115373737017763 0ustar simonsimon‰PNG  IHDR TgÇgAMA† 1è–_PLTEÀÀÀ€€€ÿÿÿÿÿ€€€õÖÜ5bKGD LòtIMEáü؉IDAT(ÏMQÛm1 £ª´ßr®ù¿nÀƒ0ò‘²ÿ%•´ˆ{H&)J0PQ…ïçg‚©ƒÉdÎJbä€rõT‚›EHœ¦B#"Ï0c $ H”F›¤’úV›PVß'Œ#'£”@Ý$þ k!Uy±VÊýy;2 KášMÙb‹ÝˆíCÍîvi¢¢$¯%_UÚXsÒU¦»áÒ«z޵JkÝeLÔ¯Ì/óZ4TåpE¶ÆÈ6¶ój Úºï]Áä©Gx‘ÓQl›èö½§Æê™rªÒLk¸ÊçßlJ7ÐF/²nl"b²wÀ|7Ö}ËúÃW}Y.\hDzE ö`Á_[[$YÖƒ%tEXtdate:create2017-06-06T01:31:27+01:00Ee‰T%tEXtdate:modify2017-06-06T01:31:27+01:00481èIEND®B`‚puzzles-20170606.272beef/icons/palisade-32d24.png0000644000175000017500000000313613115373737020040 0ustar simonsimon‰PNG  IHDR üí£gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEáü؉bIDATHÇ­–;OÜJÇçœyxí5dÅJÙˆ.]DÄ* M¤|H$(¢tTi’2_ Ht AA¨£)¢ %JH¼²`Ö³Þµ=[ ³@îÕ½w4…u<>Ç3çüÎüáË—/„!"’ÿ6¬µÖZçÇZ›e™µ–¹wI’”cXk üð·vJ)c,MSB"ŽŽŽRJ™âàààÍ›7ããã.¦[ Æ­5çÜZ[8ºËÎk·Û{{{I’ø¾?==ÍcˆØëõšÍæÂÂBE÷îÝCD)¥ó’¦iµZ ”°[k}ßoµZ›››sssççç$‰1†¹oÒ4¢HJ¹¸¸ÇñÌÌL†Y–eY¦µ6Æ °»—Röûý(Š:¥Ô8ŸQJµÖÏž=ûøñc«Õ ÃéqÓî,Î{vž¯²jŒZ[[ ‚ Ùl&IRÎá¿W±ßïçyþðáÃv»Í+ßÀ¸Û^ž„Š‚kíÂÂ!¤ÛíæyŽˆBß÷o怔í.ɕЇÈ|€ ­M/¸ÊSJ)¥NNNÜnQ)u||<°e¢”ÍsëûX—µ¶Rñ¾ßͲ¥¶•êXË)%„^œƒ«¼,ËÜjDô<ïøøøíÛ·Íf3Ïsk­1†R Àù­Ôž„ô/Ù"r)O=úÖí¾ÏóDëJ¥2 À.ŽHQ­VµÖÃÃÔÒ8Ž9ç„'OžÌÏÏGQ†!ç¼Û•Zs­¿¦éûjuÎÚˆêøZ·¤Üdl. Ï kB.9(R÷îÝ»N§333S¯× !+++‡‡‡/^<¯ÕiÚɲ¾Ö‘1b™R2Ï{aÓ îÕµ—çùÓ§O?|ø°µµårèPBŒŒŒ,//ÿô}‘RZF)E$„`áùvÆÇÇ{½žã²,B EÑ"ý8 ”ºôB¬5?~ìLMM>~<Öë9í?˜ws ¥Ìó@…ÒàÕ«YDš$RkN©Çð ÉŠâ\³ÿ‰ð}_)kÌ©R­<—§§®‘R¯×Ûã“û÷[ZK€"É^¿¿Ç'ƶR€ë¸Î\æ€RÈs«ÔnšndYFˆµÖPJãq|²¿ÿ­^ßLÓ^ dŸ¦ âu8çÕjU)åê]JÉ9÷}b¢ZWêÆ×zý½sœ_ã ÑhÕë›BÌq~ÆD\]]=::šššzðà1ÖÚ¾1¢\]]9::|þü‚ƒ4íqîê½ÈA¦”,Ùoã€RZ«Õ–––ŽŽŽ„ÖZWÑ”ŠZmdiiùðð§çùÖB©ÞéåD€?rP®÷³³3W¦ÿ'޵ÉÉɱ±1wá8Êö^/ù£Ã;8`ŒU*• fgg)¥.É•JEáy^awIö}ßBÜ,¶ Œ‰AœHi·Û­VKJYn×»»»¿~ýÚÞÞ.Û+J}Î…PZ+{YEªß7qü»Ñh)_qà~ooocc#˲â€<Ï…ëëë®ëýà`¿V _¿ÎºÝ n(¥Œé8÷÷ýz}-M ¢wÁ"¦i:11áú~9·NžA0 ¶··×ÖÖƒ PJ]ÞÒÝhˆzýµç–{ƒBÏr£XJ©ýDZ1ÚE]\\<==}ùòe†iš§i—su¹c$„ ëtžçݪœôÐ?Œ1!„»?šÍæ§OŸ>þìû¾µÑA¯×ÖÖ–ÖZ)åy^Y"¿|S¹ÎèÖAàöM)u×âÀzV¨â²6)ÓwÓX^/¥tÌ»Ÿ»¹þ/ë¸ÏfkŸW%tEXtdate:create2017-06-06T01:31:27+01:00Ee‰T%tEXtdate:modify2017-06-06T01:31:27+01:00481èIEND®B`‚puzzles-20170606.272beef/icons/palisade-16d8.png0000644000175000017500000000170013115373737017757 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<¶PLTEÔÔÔÀÀÀ»»»¼¼¼½½½¾¾¾ÓÓÓ”””±±±°°°«««ªªª®®®­­­œœœ¶¶¶ÑÑѺºº¹¹¹•••âââÖÖÖÝÝÝÜÜÜÙÙÙ×××áááÄÄij³²ää㊊ŠÛÛÛÒÒÒÚÚÚ××ÖÕÕÔÞÞÞÂÂÁ¬¬°ÛÛàÓÓÔÐÐл»¼ºº»¾¾½Ã訩©©™ÛÛÆÓÓÒ±±´ªª›©©Ž­­±­­°¨¨šÁÁ‹ÔÔ¶ÔÔÑ´´´¸¸¸ÅÅŸ¸·¿¿½‘ããÌÖÖ°ÝÝãÝÝàÛÛÄÔÔ²ÖÖã‘‘‘ÆÆÆ±±µ´´¸„„ŽÚÚÉÏÏ®ÕÕàÔÔÝÒÒÁÒÒ°ÖÖà««›ÙÙÃÖÖÅÎΩËËšÔÔÄÓÓÁËË™ÔÔÆÕÕÒÚÚÙØØ±ÕÕ´ÇÇŒÓÓ²ÆÆ‹ÓÓ¶²²···½……‘ÜÜÌÑѱÖÖäÖÖáÉÉÉ··¶»»¸‹‹ààÉÐЪÖÖÛÖÖØÓÓ½ÃÃé©©šššÄÄÃÁÁÆ»»¨ËË©ÔÔÚÓÓÖÎμ²²²¦¦¦™™˜¨¨§ËËËÆÆ¨ÓÓ°ÔÔÒäääÅÅÆ¶¶·–––ÒÒØÖÖÝÕÕÕÔÔÓÿÿÿ¥¶SbKGD‘ ¾štIMEáü؉IDATÓc``dbb†V6FvN.n^.n^>~A!aFQ1q I) iY9!nyE%IeIU5u Mf.%E-Vm]=}C#fn))cS3s K+k&[;v{G'gW7wO \^Þ>¾~þAÁ!¡*@3$¥´ÃÂ#"£¢c"cãâAf$è˜%&Å&§„D¥¦Ì·OÏÈÌÊÎÉN™a'dœ—_PXT\RZ2ƒ…¯Ü»¢²ªº¦¶®¾! h+#WE/gs‹”bk[{«@§‚‚¤„hW7KBo_?› 0(*ö·öOPéf76`³ z“%tEXtdate:create2017-06-06T01:31:27+01:00Ee‰T%tEXtdate:modify2017-06-06T01:31:27+01:00481èIEND®B`‚puzzles-20170606.272beef/icons/palisade-16d4.png0000644000175000017500000000045713115373737017763 0ustar simonsimon‰PNG  IHDRbògAMA† 1è–_ PLTEÀÀÀ€€€ÿÿÿÿÿÜ:bKGDf |dtIMEáü؉LIDAT×c````d`b`ìಔ8€´ƒ€‹ƒ #S##P€AÈÀ‚ H¹;8@@Ž ‡P¿Sà  &†Ü”Œœèp%%tEXtdate:create2017-06-06T01:31:27+01:00Ee‰T%tEXtdate:modify2017-06-06T01:31:27+01:00481èIEND®B`‚puzzles-20170606.272beef/icons/palisade-16d24.png0000644000175000017500000000242513115373737020042 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<÷PLTEÔÔÔÀÀÀ»»»»»»¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼¼½½½½½½¾¾¾ÓÓÓÀÀÀ”””±±±°°°«««ªªª®®®­­­«««ªªª­­­±±±œœœ¶¶¶ÑÑѺºº¹¹¹ÀÀÀ•••âââÖÖÖÝÝÝÜÜÜÙÙÙ×××ÜÜÜáááÄÄij³²ääãÔÔÔººº¶¶¶ªªªŠŠŠÛÛÛÒÒÒÚÚÚÙÙÙ××ÖÕÕÔÙÙÙÞÞÞÂÂÁ¬¬°ÛÛàÓÓÔ¼¼¼«««ÚÚÚÒÒÒÐÐн½½¾¾¾½½½»»¼ºº»¾¾½Ã訩©©™ÛÛÆÓÓÒ¼¼¼ªªª××××××½½½±±±±±´ªª›©©Ž­­±­­°¨¨šÁÁ‹ÔÔ¶ÔÔÑ»»»´´´¸¸¸”””ÅÅŸ¸·¿¿½‘ããÌÖÖ°ÝÝãÝÝàÛÛÄÔÔ²ÖÖãÕÕÔººº¶¶¶«««‘‘‘ÆÆÆ±±µ´´¸„„ŽÚÚÉÏÏ®ÕÕàÔÔÝÒÒÁÒÒ°ÖÖàÕÕÔ¼¼¼«««ÙÙÙ×××»»¼««›ÙÙÃÖÖÅÎΩËËšÔÔÄÓÓÁÎΩËË™ÔÔÆÕÕÒªªª×××ÚÚÙºº»©©ŽØØ±ÕÕ´ËË™ÇÇŒÓÓ²ÒÒ°ËËšÆÆ‹ÓÓ¶ÔÔÑ»»»´´´¶¶¶ŠŠŠÅÅŲ²···½……‘ÜÜÌÑѱÖÖäÖÖáÔÔÄÓÓ²ÖÖãÕÕÔººº¸¸¸ºººÉÉÉ··¶»»¸‹‹ààÉÐЪÖÖÛÖÖØÓÓ½ÒÒ°ÖÖàÕÕÔ½½½œœœÃÃÃÆÆÆ©©©šššÄÄÃÁÁÆ»»¨ËË©ÔÔÚÓÓÖÎμËËšÔÔÆÕÕÒ¾¾¾²²²«««©©©¦¦¦­­­°°°™™˜¨¨§×××ÒÒÒËËËÆÆ¨ÓÓ°ÔÔÒ¶¶¶äääÛÛÛÛÛÛÙÙÙÜÜÜâââÅÅÆ¶¶·½½½–––ÛÛÛÒÒØÖÖÝÕÕÕÑÑÑÔÔÔÓÓÓÓÓÓÓÓÓÓÓÓÔÔÔÒÒÒÒÒÒÕÕÕËËËÕÕÕÔÔÓÕÕÔÕÕÕÿÿÿÓT°»bKGDü<£tIMEáü؉IDATÓïþ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝ Þßàáâãäåæçèéêëìíîïðñòóôõö÷øùúû/{°L”«Ü%tEXtdate:create2017-06-06T01:31:27+01:00Ee‰T%tEXtdate:modify2017-06-06T01:31:27+01:00481èIEND®B`‚puzzles-20170606.272beef/icons/netslide-web.png0000644000175000017500000002717213115373721020103 0ustar simonsimon‰PNG  IHDR––³cæµgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEá  ºØ-~IDATxÚí}ytTUžÿ]Þ«½’ªlˆ¨4{PÄ €"ˆ,¶-3­ ¸4žcÏ(ÚºýuKBÖÐ öh#8íQPfp™azÚ¤§AeAvÄF Å@€„T¥*µ¾÷îýýñM=ŸÉ{¯*©zÚÓßãÁ,/¯î½ß»|—Ï÷sñ™3gÐßåoYHo7àï’­äU…œsÎy®^ÅËgãóßÇ %*dŒÙívA²zÎ9!Äét^lZdŒ ‚`·ÛóÙ°<©PQÇsòäÉp8ìp8²é!ç\EI’¾øâ Çsñh‘1æp8ÂáðÉ“'=¢(ùùÜ|¨P–eŸÏ·oß¾ ,Y²$öxž2Æ(¥ãý×]°`Á–-[|>_Þ˼a6›-‹544ÔÖÖîÝ»×çóɲœ‡¦O<ñ„¥ ˲ßïß½{÷oûÛx@„ÿüÏÿ?~¼ÃáecÜ­aA„E‹y½Þ{î¹ç7Þ°ÙlÕÕÕÑh”^3ÍàŒH&“µµµC† ™6mÚï~÷»òòòÊÊÊ<4ÌZªú[¾|ùìÙ³ /½ôÒD"ñöÛowW‹ªþêëë½^ï´iÓdY1bÄÚµkEQìE-‚þ‰Ä‚  tÝu×B¾÷½ï½þúëùÑ¢…*ý}úé§/¿üò]wÝU\\ljDeeewµÈ9×êï–[n …B°wUWW¯Y³´‰Dò¬EhC"‘¨­­4hÐøñãÛÚÚà௬¬\µjU´h• cEEE{öìY¹r%è/‹B!±X¬²²R’¤÷Þ{ïúë¯w:’$™hìQ/^\PP0}úô¶¶6BÆX–eÐâºuël6ÛÈ‘#£Ñh·6çl„sîp8$Iª¯¯4hÐØ±cÛÚÚਖ$ÉëõVUU½ùæ›UUU±XÌ¢†Y¢BƘÓéüøã—.]:cÆŒ>}ú$“IuB‰Ä%—\ÒÒÒ²fÍššš·ÛÍÓí!øÉdò™gž!„L™2%«ObŒE¡”^vÙe«V­Â6Ì|BäJ`cƒ?ûÙÏúõë7vìX˜£jÃdYv:eeeÿöoÿVRR2`À‹fÕê&„lÛ¶­°°ðàÁƒË–-“$ ºÚýüóÏýë_'“Éöööƒ:#w˜sn·Û;væÌ‡ÃñÒK/íØ±TPJW¬X±uëÖ’’’;wv×Dê±À‰´´´Øl6ó¾ÁÑÒÒÒâóùà¨S—,çöÒp8Ç !”R‹z¤Û°D"º]T»—ÀB ‡ÃÁ`PëV¡U*„>PJaLµ}`Œ !‚ d271Æ‚ À²ƒ¿íô¥4ÃWåV a`[ujtFÀR;ÙBjû©¤„1ÿöx¸á ‘!„\ ¡è£Ú0ØfEÉÏ”²\…07}>_aa¡zºÝîž…ó9ç.—Ëçó©‘6‡ÃA)Ísr@·an·ÛçóþDQË9 ³V…ê|\µjUii©,Ëœs§ÓyäÈ‘ÿøÇÝ “*Šâv»wîÜ 'lÅ‘H!$Š¢¹Md©0Æ\.×æÍ›Ïœ9þŸ ÍÍÍåååH+Ä*‹TBH{{{ss³:¾àQõíÛW„îvs~îÜ9­¶cÅÅÅ………½˜²/ðìÙ³Z—†s^ZZš‡\Šå*DQJEQÔþ„sžL&{6=m6['ë@’¤^?1Æ]Mëü4,æŒ,Ë]Ó.=Þô‰D×öÖª ç<÷JÃr£BÎïæv‘Ûó¡—™5 ‚sálä@…œs»ÓÉÜnŽ6m4ìœã,G§ *9‚< FˆD" M¼·Ç’­ 9cv§óàž=›1ÓãÍn·+ŒÉ’dþNBHZ<ý´* P®lÂL–Ñ{0Ž#4å§?qõÕ‰X,ˉ˜2—ëO/¼Pü§?+(ðȲ~1æœ7E£NA(¶ÛÎ çƉdÒ&Šc¤7ô!Šq0™ IR…ËE C™“e„Ø}ÓW·ýII²Ûl(»W„Ú¡*ú“Í6ì½÷x$ÒË*DqŒ…dòë‚‚ûNœ(S‰sôíÍsN)•%©ú²Ë¦ýàÏ­[wþÜ9AÐùhι@é–­[ÇŽkärÈ’TÖ·oíSO½ý íÞݧ¼<wðÕ<ˆ1bD–IWp¶oß~ã„ r6aÎEŒÏSúö€þd’çÂØÉ ád¥LQJ“ºÄ09çc‰1Q–]ŠÒ‡1Ę ·#Á“eŒ•1&0¦«B‰±>Œy!TÊXÆâŒuUcÌÅX™¢ „Ê‹ê=Ó>b,3VÆX)cJÑAιˆ1BHPn²uGr± aÈ8—Rÿujç¼ã·©Ïèªç›'‘¾ð[YóµÄ9éò6õÕÇH6 çJê³”,†z-qFCNŽè4*T˜½ clãÆd2þ‚ùß;NBH>)êÐ!Ûcê…gcDï,ìp<,k9çÜf³Ù ƘIÂÙlqA»º€Ð9cL éè*†*”e¹¸¸øÏþó¶mÛž~úiH=[4ÚMq8Fæ ÞÁ²ÛíN§SwñC<Ýf³%“I+Ú©(Šßï_ýæ›Ëvìð——+ž±Ù"_}õâ}÷ÕŒ×g>†Œ±‚‚‚çž{nìØ±“&Mºpá‚®ˆŒT¨Åï–””0ÆdYVâ§¶b\B„x<~ôèQQuU¨(Jkkk8F=kÖ¬[o½Õn·ƒA#è›,˺qËܶ!D¢œS„”ÌNbBHqq±š WÅëõ–––Nš4é•W^Qe̘1ºZìü½¿ øëwÞyç±Çƒ&ÂørÎçÍ›çõz­¨PÅét^sÍ5iSQæ™qƘÛíœn&Ÿ›v‰Àê¿!žúVAHÑ5R4‰'ó7 ‚‡-Z‡‚:ÚÇŸ>}ú¬Y³V¬X1®©©éªÅo}£(ŠÏçÛ½{7à¯‹ŠŠâñøC=!^¯wݺu.\ðûýV¨ ‘H$­ ÍM˜j™ä9çˆRÁ`ßV[Å)%6µÛ¹¢`„¸,S»çè@áÂ… @`Ö¬YápÀ8Œ±›o¾ŠŠî¾ûî+VpÎÇŒ µ(¯oZêÙ»wïoûÛÙ³g«øk‡Ãáv»áEQ ]h© ¸ïl¢b°ág¢?ÑnGápôÔ)Án7 ža,˲|ú´ôõ×°ô%Y–b1 ¢\Xy°ò¼^oyy¹ËåR5'b<÷ûý³gÏ^¹r%¥ôª«®jooW-#Aí‰ÃáøòË/|ðAÇ£²Z#^QI’òSs•áœcJ¥`ðÿø ¡‰Ç‘y…stìXÇ׌a§“ïÞ~8WÃ!˲$I€0ÒþL<ŸÏ7gΜ_ýêW .¼âŠ+Ô FÐþ½ßï¿ôÒK;6fÌÕоÔÙëX£ŠÍáhŸÓéü.iQEÔÖv{UÕssçF‚AQL ã³õÃožÓõ½@gE9‹ÁY(ËrY,Ö.I(¡NXdÇŽûïÿþo8Âà#JKK‡ UGŽ©¯¯w:Zý¡N)ÔÙíö… ÖÕÕBFõç?ÿùŽ;î€âœ9sÊÊÊÀ¡þΨ‘`,R*"è™'¼¤‹”v<  ¡„ E!aYÖuí1¥(]fcœL&ËÊÊæÌ™ÓÞÞK 6Þyç‘#G~òÉ'°þœNg"‘èâé<ã rÌáp,\¸°¾¾> :ôG?ú‘Z}©Ö0Xº Mb¤ßÖÞpHB\týBŽÊÀ´×pÆŒ*¬üÚ#GŽlÙ²¥©©ÉHH7:Z´Ùluuu?þx2™ ‡ÃPI¤>cuõ‰(ŠiýB÷¢"ç^Çö %—_.':*äœ:ჳf±tf<ç<¨ß‚;gÖÒ¥K!F¡bÕ÷LaG…µxàÀd2)"/B) ‡Ã&*„s¾  @EÝiD„@0xïÝwßÝÒ‚CºøŒcèÿ‘EÂá´ó^û¨`öìÙÕÕÕ‡Ã$Ya\€µèóù¦L™ÒÞÞžŸa‚ÝcÆ wÜq¥ÔG Žð„ þýßÿRšM‘M–B!iòŒñî{ÒPùUÍ=L6¡”%îNŠ$Kå5`À€Ûo¿][Êûía.—kÇŽ[·nmiiéׯ_†QP+„sŽÒò² (^ìyÊ¥ÉÃç^`é2dÞ¼yFÛŽ$I.—ëé§Ÿ>|ø°u9¯‹D2Y<¹3~®Öxš[›‰D¢©©ÉH=’$õíÛ·½½eÕfÌœúʤêßüm™ŽRîp­ ¹S!Æ¥c¦‹`£”så“€â5! Ô癘3¢(f¾·Ó”è‚3A ‚€„˜4 N_µ<ÅX $søLZÉ aܲukc’Á¸ ‚pë­·0àý÷ß7ã@†ŠÓ³Ÿª0!öîÝÛÜÜ,éXœs›ËuáèQ$ЧNúàƒZc1jàÚ3ÆNŸ>½eË–,sÝ"Æç 1òz ¹Q! ;ÖD…¡›nºI–e0¬×>úH–åìµæØ°aÆ® fŒ9<ž&¯½óN¿+®¸á†εµ­BY–wîÜ9vìØ,+°A…Gm¶\Ár¶‘Bi«Ð%ЮpN:ÕjÖMn ( eÐåœPyÝl¤¢HSßví¼ üãl6Rˆáå°¹; 5¦ÑêQó&æïÈY“:7ÍТQ¿AÆ àɾ1Yfh% áóz¶kƒñb\°†â*ªÊj±È5RÓ{Ü8Ý8f‡ž½?í¢7S¡ éì˜s^XèE³œÆXQäP¨-wCšW ŸËãIŽG( õ€€  ÀñxÜ<üd¨B•æöðáÃÕÕÕÝjç\Å Þ?þ+AЇþ<žâÉ“§uw‚fîZ' úüóÏ?Û¶Ín³éVB·d„&L™Ò§¬¬c¸gÏžªª*§Ó©å!ì$ú*Ôòï¶´´¼õÖ[---ÚsÞ|kåÛíòsÏmÜ»÷J‘n¤cƹ§¬ìw{öÔBŸTKF¢£A±:®¤(Š×ãÙ°iÓ³ÂÈ‘r$¢ãê1Fý~eýú·?ýôò;ïL\¸`~jhmTQ,_¾¼¸¸¸¡¡AY–3ÍT¨ú{öÙg].̟ϧ…UE£QóAæ\¢´¡I‚`€FÁŠ$QJßGHNÍW„*™­[·i1šýû÷=zT×ʇ<ø™3g®ºê*‹V$ §Ðøñ°aÈÍ}ênmÍä…G;ÈN§ˆ[-ZôóŸÿôš>_ذ ´¾¾ÞçóÝpà +W®Ü¸q£šìgŒy<žaÆ¥ËD#Ea!Yf«PAˆÂ3àv»¯»î:óÛ¦M›Îž=;räÈòòòN@õ=P"j½%Fˆ3†EFHV]rJ˜uÀ!wíÚ¥¢ oÿäÉ“=ôÐǼpáÂÚÚZ]- Þ¢åOž:uj86lØû￯bgÇ®]»^xá…þýûg–" ÚE¦ý4øŸ,KIŒI*T¹¹-NK+Œ1I–%#šŒYV“dYQŒ¤(’,3Æ:p¤”*)=Çê©S§/^\SS3RKH’tóÍ7oذAÅ4uÒ¢ }ø¿õõõZþäÉ“'ƒþT[$ÉE|œeÚ§O_QìËXt&Š¢ÝnÏ7¶ŠsÝîòùú"$ê®~ŒeI*r:Ë}>XÖ’,»<Ó‰rQ¬ ÊaÆ͙3€ƒ0à²,G"‘¶¶¶iÓ¦mܸqáÂ… ,°ÙlZËè(0¤‰_|ñÅ©S§‚þBZ˜ 0ýÅsAµ«0ýô§ó ©s€@ýû÷7n\~ø™BLQ×»ùäIôâ‹í&Bˆ3ÖxúôOžäŒ!Œcnçã]»ÐÌ™9!xÂÇãñ .Á·úC¶·µµM™2eóæÍ =ö˜(Šª§ñ m6ÛW_}µoß¾§žzJ[ÔyçÍQ ¦E$}饵 É!ÈÔ?øàƒpíCžT(ËÄçÛm³í>t9fqQD_~©v9èÂDH®J¼TÚU]Ã5‹7®¡¡¡±±qРA*_{‡ ¦wðàÁ>ú諯¾:gÎDПZÞ{tNBìcÎQIIÉæÍ„~œ'ÕŸïÛ·/ç¢R°ÙXSÓ?Ô=øàùövÁ üé§ŸŽ7N‘eŒ±¬(¥~ÿ²drY"Ñ1³uxÕªnp3ÀGO&“«V­zä‘G†ªSSR”…“&M’eyõêÕ EI’(¥ªÂEæ¢Á!D))/ï+å B8?ÿüs µVuý Eñôí[qÕU44ÉT‡ÃÕÕpʲܧ¸Ø[^Žd9W{…$Iñx<«¥œN§SQÐßêÕ«gΜyóÍ7ý·úW¡À­­­S§N圯^½úþûïEqùòåEEEZ¾€d2é÷û3V$3°H„(Ô)J\5gdYî8“œH$ÚÛ㑈(V>'£Ñx{»ZÙw¹äd2Uc¨èXžŠ‚(E$•$IòûýÉdrÍš5êްĹsçJ’´jÕªY³fMŸ>½uõ ¡ÐmÚ´iã·Þzë¶Ûnëß¿ÿóÏ?NaèÀhŒÇãУŽsD)A 10ú©$!A 8³áç½uõR‡á`ÓQ÷7àðÂÓ”D©ˆ œ J)B ĸÓÄŠ•—_~Y5â Ê÷g?ûY X¿~ýÌ™3uõ‡t£3 Å©S§RJ_yå•>}úH’”H$Ô?ÎÀ£à Š@ècYFÆ®½W–Ï $\ÄL†fÒqV}ò‰ËѨ¾kï÷£ƒyÿþi߯Ó‚=Eq8ííío¼ñÆ<0uêT]ý!£)hqÊ”)¡PhÇŽ©Ù©Ï½¢×7žHˆO>9ñìÙ“XQd¯÷BŠº íî([ôfJi{$ró¤I…lom5D-#$9ƒFŽk #Ñ>+ÞápÜyçÓ§O‡Ê$Ý¿2ÌT€¿ÿýïO:5 u˸8èm·Í0O6!„“ÛÚ,I6§ ñ#£«²pã†>æÚkÓ&›B¡P²›n.¥4 ÕÕÕ"Là–fùBð4zòǃÁ´^¥)_•|Ý¢ón0—ž¥|ÁîítQKWIîqóyq‹QÿKJJзù\r+:±º#æä ÌRuܺ©-‡ÑxîîɆςê'3’¯TÝyG‘´4¯zÙY’80ŒsKØ“2K„ÆØår¹LAˆi¯Þ%'qu¢8—Ë…ô¦çÜár9Náu·Û%I&ÑA\.W–¤÷"Æ.5þ’e'B¹"³ûåàÁƒeŠ¢k\BØb=(*"‡Ñ5Jé‰'Bº4n>r Âùóç|öYK$"ìÿŒ±æææd‹#Eè<¥àÿåÄ—Ê3ž¢(3fÌX²dIAAA¯_+ñ]’œ±‹¢8bÄ#47!R_p]«‘—ïinnVE4¥cÊPE0`À•W^© Âãœ;Üî3¡]»ÊÊʪGjM6ÒÖÖÖêêêì7Òó„|$"Ù~Y9çÑh4jDìL©$IPǣѨ.¦›sžL&sxçZF£Q#@>Ã8‹!Œ%IJD"Ñh´kŒT;B5A6Í㜋GS™Ÿ|°wKÀ¾&Æh XlB­•s>Z÷áZ¾^]'X}JÝsÐcâTD8‡´´Äc,pŽ0æSŒB"Æ"Æ"BB"ƈs%GÌIÝn™ŠÐÑþPUgæ{8Öåº@¥®ˆ”u}±N…c‰óf„4ÉIE8oB¨!s†±—sgW-š0…u"vf…8ð+ݸþöU²:C¯ñbÓ on6¡KàŒ!»f’rê™X¢BƸÛ-Ü}÷Ïwî,öxDÆxÊèùѦMÎÊÊŠ¢‚ Ò¯ßñßÿ~1¥Îuø!n·Û¤P[%vv:ð¤Ñn·w‚ÙaŒg̘qòäIYaŒIBÑèë‚ð_Ë–)œSB"‘ȨQ£Ö­[gr»…¬(%EEËW®¬;t¨¤Y—>šsât¶>üæìÙ×ßtS(¢„r,Z…„øÙ³¾@`I(ü‹¡¯¿†¡”90~†óB…)ê_Æb±Ý»wA;‘H¸\®£Gž>}Z7~Ⱦ¿þõ¯—_~¹VœóÓ§O777wº½'ŒP8@©Ó®©©)ÍÇ9%¤-Š<þx"±s¬¥…ˆb«™´báY=ÂX!ä›ë"Sv "DQÞ5F1v:&ÜÜN§¥–£ÓéÔź »Þ›ˆRaÕBá©ú+µ¢q™l¤cÄAˆÈ²nÖžPšÍÕ$™ˆ…*L±PÍT­¬c hª:—®ÚxèС&iYY@x.¿üòŠŠ 47Ðsù¨Z+Ú è7­Mý\ ÕVLÂOÔšqÿ‚5–µÇuÑ‘~@@GÝž„hmVÇH…ãDüðC¸u £,Æï®µu[,–bçËwY…È D"Í@TR2 á’¥9ŒF£Dõd¹5k Õâ´>¢Ø‹¡Þ¦F¶P…àçšÞoyÊ•²Ö N.QSÍ!`ÁÔ}üBR!÷åSBDAÀ)ÏRJ)Üêà ÆÖI#”*óÞZ¨BÕóÓ½Žsp¿P6)–’ c¤°IªžŸ N'Ãt”ï*1]Z5ð7º4ïX¤BƘ³ª*ÞÖö˜Ûm×)BP"+*ÎcìëqaÓé„»Uº·zg\~§F®1ÆC† q»Ýv»QÃH44h¹Á¯èSZzé¯~UTQatM8±Û#'Nxï½W±¬Ö΂c1iÅŠZB"F»$¡8wAð¤gô׿þ5ábǹsçÊÊÊ´k‘s¾nÝ:_Å«™ß÷D) ¶µÝ9kÖ½?ø7Nsα͖ÅHh…i<.sîJ÷ëA¿ÔÑ¿å–[Œn% ‚°aÆNhîttžAÝ–$)i³¡tqbYæÆ¹†Lv–Ç{Ìãñi‘RÚÖÖæp8:E9\ 1û´GÝߨ9c¨.ݼyó.¹äÝÂåû÷ü,æMrÉ Ü±ùdgCwëo g’©hmmUÉLޫޒAãÕ‰»HÏz÷ Úã"$³„]™1%;¼z·Ø"%G÷ •AZQŸéj„^¯7‘H˜0y@˜›1&IR–;™19§é§œ;'“ÉíÛ·›³§l ±s 0*+‡O|õÕWÇ7jÔ(•U@÷±Ó§Ooß¾='ÄÎ&´xÝ•œ;Ûíö'L(ÕÑf.0èÿ÷ÿ—Cbç‘#GVWW;;gΜټyó°aÃn½õÖ¦¦&]€+ŸÛ·o¿ñƳǑ6ò…WÚÉ%+°¬(Jv©ÚÏœµ*EwW uý Øá[ȹ V!¼^•M{Ær>Y»%Yô¡t7,÷¸UÈØÏÓºü&¦Šbв³o³¤Î’bçt-ø®ßø’dKìÌExº;q8ç~¿ßf3?Ï0c,ZÑù|ñYÓ¯×ÇÍkµÍˆNgKKË&Nœ˜ÉñÚ϶Ùl«W¿yêÔ×FpPŒ±,+>_Á½÷Þ1Ñæ+ÌÝ/m…ÖÐÁt}’¤ðN½¦„,@”›6mª®®.))éöåw@ú•H$jkk“ÉäÔ©Sá‚Rõó:zα͖|õÕ}{÷>J)7âá¼°¬ìWwßÝ*}µ¼%p“»‚ p…à$€3gäÚƒ«cr-ÆÅ&ZC ¨ƒÖ®]ûî»ï.]º`éÝ v¶Ûíñx|Ñ¢E”eÙëõª¸1œÑE°˜s™R/BÃŒˆ Q’I*%)ˆ£Ñè'Ÿ|b´|a‰4èá‡>qâÄñãÇu[ ;9òob!bŒý~§‹`«ªªà:×gžy&Ó‹`UýÕÖÖ2dÔ¨Q¿ùÍoÞxã íuÌç†n0÷Û4ÄÎF«!DeYéÚx¿ÉBW™g#‘ˆ‘ ¶ýû÷ç°ZÑ:výúõ®c>räÈ¿üË¿ìÛ·oÁ‚]ǬÝ? tÝu×…Ãá‰'=zT{)ú»ï¾;xðàË/¿\K[Ê‚›Ì9cX’ä@+pê_†‰d2i>Eà†a5É8¸}Fì-À·‰ž™¤®ÀkÌ>À†1– Ñv ´uæÌ™Õ«W_ýõÚKÑ'Nœ˜L&një«««««ëªÅoT¡ŠX,ú?~<0 _}õÕp,á±óÙ³gµ|¯ð?JiŸ>} ÀÆv8d8„zÖÙ´–4NWh©îü~¿¿´´T÷¼„±ƒÈãñ¸\®²²2£èŒ,Ë~¿¿oß¾Y²Øˆcõ=Íû“ÉdUUÕ?üÃ?h‰%IŠÅbmmmcÇŽEÕÖÖÖÕÕÁý#ùH!²ÕÖÖ¶dÉ’¡C‡Ž3^„Ò²«×)È8DñB8uÏÔ'âñxeeåüùó_|ñÅÙ³gæ¬^‰R·¿uЧ`Œ‰D¹ËuàË/S)ñz¥›nzqï^D)é-†`¢[»víˆ#LŠ=Ä!-—,Ë;vì˜0aBöaîó„¼VYÙÕÕ†Ä'ÁO 0 g\ X³fÍSO=UUUeH쇯ºêªŸüä'Ë—/¿ë®»Š‹‹Áë …B0=¡æ®yî4[1Æ¢(ŠŒ!Îâh-x2séÀ‘êåUIë;ÂÙ¬¾'˳P첓Áɇ›ššà sغ @Ö®];wîÜÑ£G«gÈ·Öì¹£G~øá‡_~ùåÙ³g¾ôÒKT‹+!rV\\ÜÙxã\Ie*ÊÂR¸4; )J fqöf¤š©È2ID0Vºd*dY...öûý›7oƲºãÇÏ›7/ ®Y³æá‡®©© vAbç@ pÍ5×<òÈ#+W®œ:uêàÁƒýë_k‰a½v%vVcbð?’Më* c$ËäÏ–Šy¦"ó—X—©P½í%K–¨àUˆÎ<ùä“6l˜;w®®þ±s =zô#<òË_þ²¤¤$ i/˜¯¦í䉌Gè]EÁÆ®½KQN dëAU `æ€'×»œš™ X¼ßA* ç¼¹¹yݺuóçÏ=z´®þ ±s ¸úê«ò“ŸlÛ¶ ®ÃÍ<å„1Ç…††Ù­­f÷2vÁéü!¥~λ‡æ†à™Çã1Y …(** …ByQAD«!°Nûõë7kÖ¬ššb`3bç@ pÝu×7ØÌ›‚1–e©¦fœ L2·Ñ“#‘p·ú úûúë¯,X‰DLjÌB²,?ûì³Èšd²¥§ÕüùócFë$=±3êvcÜÞæ<ý èîF§(JAAÁêÕ«ÿ÷ÿׄT,:¾üm)OÛ…Lˆ©ÓdÌ»§<ÍÕuÝþ[Í;:}aôBhçÎåååFP`—ËuøðáìmÈLZÕB݈wd2†9c&À®–ÁÆ¢©÷Fø-Ü!ÅeŒè• aÎ)ç\’B6BdŒI–±iÆ a$ ã–§hèÈEÈ ,SzžR„”Á™†¯â\ äüàÁƒ“'OVy5 /ýÅ_<þøãgÏž½âŠ+æÏŸQ js*ô‰'žÈùKÁó#„|ôÑG'Nœ6mšú+œºb÷úë¯ÿúë¯ÃáðwÞ©Öl –ÏçÛ»w/Bè¾ûî»ä’K´ö'c¬¦¦¦OŸ>;vì˜6mÚàÁƒófBöoß^RRrÏ=÷©s VÞ¸qã\.×gŸ}öÃþ°_¿~])lÉYˆo¼ñé§ŸÞ¸q#¡©{)ÀëöíÛ×ÔÔ´lÙ²ÒÒR“A‡]×áp444ˆ¢øÑGy½^õU°Y)в~ýúx`æÌ™º÷Z!0‹ŠŠ–-[ÖÜÜüÙgŸy½^u§ÌG8Þ¸qãüùó'MšdR¦›¥X² QÊȾâŠ+***^{íµ€SQXX¸cǎÇ×ÕÕ9Ýš£N¯DÞ„ 6mÚôÕW_1.ºÑÕ«Wß~ûíÓ§Ooiiɧ •G¢(Ž?þí·ßŽF£ßûÞ÷m¤â¯ÿùŸÿ¹¦¦¼X‹ša• QÊá8p`¿~ý^ýõBØÎ;9²páB£²UÝÁ‚ >qâÄÍ›7õÕWLJŠÀÕ«WßqÇ·Ür ЭYÔ“†É²l³Ùn¸á†wß}7‰TVVbŒƒÁàÚµkzè¡1cƘãϲ Uˆ¾­Å×^{mÈ!`¬š–ªÅ>ø ±±ñ²Ë.{íµ×fΜ úë-Q«ÅwÞy'™L¼õÖ[sçÎ̓þPNR¾iŠ+÷ìÙÓÐÐp饗þâ¿è®þTÚ]JéóÏ?¿oß¾G}tòäÉ™Z­µ@º¾¾¾±±Ñ[ɇ QÊ„9vì˜ßï÷ù|iÏ?71766:´·¢Û]Ì®`0ªªªÌëÈs(yR¡ÚC(WÏrÐÁd·ÙlÖ™y=î#Tf3G»+ùS!úöõÙ¿ªÇÌb+}ÌPòjÂå°c9'£»û˜¡\t³øïÒ]ùÿ K…Áø7 @%tEXtdate:create2017-06-06T01:31:13+01:00?¥ª¤%tEXtdate:modify2017-06-06T01:31:13+01:00NøIEND®B`‚puzzles-20170606.272beef/icons/netslide-ibase4.png0000644000175000017500000000122613115373736020473 0ustar simonsimon‰PNG  IHDRhÿ‹gAMA† 1è–_PLTEÿÿÿÀÀÀ€€€ÿÿKsÌÕbKGDˆHtIMEá‹ß? vpAg!!òú˜IDAThÞí—kNÃ@ „NÐ ÈCü'å'¨Äý¯¤uÏÆÞDP<¿¢Qûy”ìÃ>B¡ÐVÔô>ª=]> 4>÷š’Zù8PJZiäç%­4òs´ÒÈÏRJ#?hYùk¥‘¿è±4ò×=”F>Ô0 ýüó¯‡ÎàçtýCgö †YÙ…ö¡Á)Äyzw ‚άDgñ,õ üh³ ¦#Z¨I v²€Þ„Fñ,% H$Boh‾§ Ñ`”ƒnÓEè6îT‚ĸSê@"PHÚH"Ú;¢}5Þ:¢­lÞ^£í~Þyd~t1ƒ´»¿¤u#KPá¼V’HíØ @zYÒ»Z?ôÙ~èüÝ 4‹¸Ah:’ ë§X¡yÍ ¢%¢½#ÚWã­#ÚÊæí5ÚîçGÆÒ¢ÙÚ-Rv¡yíNT€ YŸd“/æ}þq%tEXtdate:create2017-06-06T01:31:26+01:00ã‚à%tEXtdate:modify2017-06-06T01:31:26+01:00’O:\IEND®B`‚puzzles-20170606.272beef/icons/netslide-ibase.png0000644000175000017500000000151113115373736020404 0ustar simonsimon‰PNG  IHDRИŠgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<EPLTEæææ¬¬¬ddd¯¯¯ˆˆˆ¸¸¸ªªª ÿsssŠŠŠ°°° ÿÿÿÿG-ZûbKGD|ѨtIMEá‹ß? vpAg!!òúìIDATxÚíÙmoÂ0 `ºòÒÀÆ`ÿÿ¯NE›è´¸øÚØ1ôî#2äQ¤Ò6·Z1 Ã0 Ó§yiLçaO»n‘Ðy4›í®{ݾ™ÍOñtÀ èü4~t~ªG»:?Ý£[ŸãѬ€ÎÏóÜ_Ÿë¹·:?ß3¾:_Â3¶:gŸú?~¸~²/4?1i°@2˜'ˆ ‚"èé@ÇtËÑ`ža†yð$ãÀžwãà p;”ÿŠøS+lž ‚"ˆ ešS,PÓ ó•@›í.¨?O.’„Ï%O9°#û Ô´Ÿ·3ögþ \1XË”íG*‚ò}M=PÞS$xêNë.èm‡$QÅ«ìì*D5AYQUP¸{ÙïŹÛÿˆ"®¢P ^ dÿÖ‹ŒßËŠå @¥N7KÊ·ZïУŸ~DAAØT­CADÐR@ª÷²KþaùbÒ½¹¦¯lþ|µ HÙ—¹´}™ äÙ—9í¾/ógŒ. ¤/óA}™ëËìA`_fBû2 4Ì,Ú—™ƒÐ¾Ì„öeWÖ—yüA}™Ë?5Ò—-ó^†ôe^hê¾Ìí‰QÛ—ù=S+û2?ò­Ãñ5îËÄ”I!ˆ ‚"hñ o±š¼L¤­W%tEXtdate:create2017-06-06T01:31:13+01:00?¥ª¤%tEXtdate:modify2017-06-06T01:31:13+01:00NøIEND®B`‚puzzles-20170606.272beef/icons/netslide-base.png0000644000175000017500000000756013115373721020237 0ustar simonsimon‰PNG  IHDR!!¿LbKGDÿÿÿ ½§“%IDATxœíÝÏK#IÇñÊó<·4Û²fa/‹ ²‚’CãiOs[Èú(‰®<ÑA¯þ@ð sðG@ÿ7gÿiÈ2"g`!9û²qžIº»êÛVw¿_x†¤¬©ò3]Vª¿ûúõ« æ_oÝ åÈ ‹Œ²È ‹Œ²È ‹Œ²È ‹Œ²È ‹Œ²Ò™1ß÷ýõWß÷ߺ#ÿ°­?¶I÷ø¤0c¾ï×jµßÿ½V«Ù0m¶õÇ6©Ÿooo¿uLêt:µZmggç·ß~›ŸŸo6›årù矦?vÊÂø¤*cNgmm­Ùl.,,(¥~øá‡¹¹¹·š6Ûúc›ŒŒOz2öjÂFÞpÚlëm²3>)ÉØÿ°‘7™6Ûúc›LO26aÂFbž6Ûúc›¬Oâ36uÂFb›6Ûúc› ŽO²3pÂFb˜6Ûúc›lŽO‚3jÂFD§Í¶þØ&³ã“ÔŒE˜°¡i³­?¶Éòø$2c‘'lÄø´ÙÖÛd||rI¬¯¸´´ôªÛŽãÜÞÞN~×ÊÊÊ`0xù7ÅbñãÇéëm2>>ÿyëDñí@‹Å©ï Bÿ¡ØÖÛd||Rx&° d‘1@d‘1@d‘1@d‘1@d%ò,Õ·\×}÷îÝÔ×ÄÓe_l“©ñIä™` AX+²È ‹Œ²È ‹Œ²È ‹Œ²È ‹Œ²¬;K¤b0mG—ìÊX±X|~ë> érÅ¢U1³+c#¹·î’ËÂÿ£m̘ҾÜœúÿŸžžê—+·­?YÕ;Ñ`ÏEÆYd EÆYd EÆYd EÆYd e朇ïûFãÓ§OFZCÊÌÎÏŸž4É _þû_#ý bqqñÇžçé7eà:æû~­VëõzúM!•†OOêùYóK?¥¡ôz½Z­æû¾~Sºët:õz}ggG¿+€Uö÷÷ëõúýý½f;ZkÅN§³¶¶Öl64ûa³ÓÓSͶ··Gggõ›BlJ¥ÒÞÞÞÆÆÆÅÅÅòòräv¢g,#SJ9Wnêp:)“‘˜E\+f'`ȸqÌ"/£\ÇF›ïß¿/—Ëã¿tgêÝ;®ë~þü9Âw š››ë÷û“_ã8ÎøÏ¥Riwww}}½ÕjEØi ±ñ&ÇË€)¥noo§¾wêãp€ôûý»»»Po)—Ë£-‹ÆpkE–ˆÈ¬È‹Æ#`ȸh1 š1¨H1 ôûKƒåe²öqBØ ý@×±ÍÍÍjµJÀR£X,ên ñ•:¥R©Z­nmmyq ŒŸŸ·Û퇇½ŽÁ2¹\L_©ÓívÛíöÙÙYZ+V*•ëëëÕÕU–‹)O½G;ËFÖívƒoâÝóÅìää„«²,lÀT¨½{b†Œ‹0ö3hb†ÌŠ0á,U¥R¹ººúö¼âÊÊÊ`0˜ü^×uÃ~;À8×u§ësçåñÀÇÇÇ£££˜Î+*¥<Ï»¹¹yµ2 ¬z ð=A¦¿Ü§év»ÇÇÇ———ÑJD¼·…E#2"òq,z­b†ÔÓ˜Ò¬çAÌbF¦ôk¿·@4ÛAŠå …¡öi|¡`¤3ÁDÛäxÅ@}EÏóZ­V£ÑÐo ©g]DSfffLÕW4SÃÔó< ˜"M þ<[úÅbñY©œMÇŽ‚Ô6›jüùX<µÖõçùYå ̾‘þ˜báÏb­H#c€,2È"c€,2È"c€,2È"c€,2È"c€,3ç}ßo4±•›Ÿ4Éç _¾$¯î_ÍÎÏŸ´ç«Pˆ³Nãâ⢩úŠ®c¾ï×jµ^¯§ßT@Ãá“RÏš_ú)E@ç'ý·ë§4”^¯W«Õ|ß×oJ7cN§^¯ïììèw°Êþþ~½^¿¿¿×lGk­ØétÖÖÖRÿ vý{7Ò}¯MZ•J¥½½½ ÍÇJDÏXF¦L”XÝÛrzzjä^Íœ‘˜E\+f'`ȸqÌ"/£\ÇF›¯ží8ÎÔJ®ëyL( jnn®ßïO~ã8ã?—J¥ÝÝÝõõõ˜ž=Þäx0¥ÔËTÏÔ]1è÷ûwww¡ÞR.—G[ áÖŠ,‘Y‘!2FÀqÑb4c P‘bè÷±´,ÈãTì)º$ÁÈe²öqBØ ý@×±ÍÍÍjµš²€Aÿ|SЯÔ)•JÕjukk+È‹eìüü¼Ýn?<<èu –ÉåbúJn·Ûn·ÏÎ΂¼8ÐZ±R©\__¯®®¦l¹äÔEºBñÔ0MÙ#»ÝîááaðMü {£˜œœp5C–… ˜ µwOÌq¦Â~MÌYѦ"œ¥ªT*WWWßžW\YY “ßëºnØoçºîÔc}Žã¼<øøøxttÓyE¥”çy777¯¶@ƒU˾'ÈÁô—û4Ýn÷øøøòò2Zéˆ÷¶°hDFD^"ŽE¯5@ÌzúSšõ<ˆRÌHÀ”~í·ñˆf;¡äó…áP÷ô@>_0ÒL•/†Ú§=ò…¸çëàà Ú&Ç+ê+zž×jµ†~SQ1Y⬋hÊÌÌŒ©úŠfj˜zž[S ž©Å È"c “î3Ê©DÆ&Ý÷Œ¦d‘1@d‘1@d‘1@d™9Keœþ'­Aê%%”Á¡4ÅÇâ“嬺y¹X,>+•Ó®I6¾‰5žÚf‰ìÏó³Ê˜}«þ/3õóckE@d‘1@d‘1@d‘1@d‘1@dYz^q²ÙÙùáð)È+'<Á1Ÿ/¤µNãìììp8œò¢\NMŸü—/_Ìôg~~øh¾&È I¬Ó¨š±áðI)Ý'yëW¶Öô€ÅÕÈ?M==é?y]¿Òð[a­ÈJäu,fú÷nlooΧsH‘±éLÝÛrzzjä^Í3ÖŠ€,2È"c€,2È"c€,2Èbï>y&€z“oÄÇ “‘±šz.ÉÔ±#íPÿHì1(#ÈXÅö#›íl˜BÆ’gêaS‹É §R‚Ô0mqk'ö<Yd EÆYd EÆYd EÆYd •ÈŒåó¥rš_ù|á­ÿRòù¼%üÓT¡ r9ͯ|!©ó•Èsi­‹hŠ©ºˆ¦$´.¢)‰¼Ž ’ÈëXréŸÜ³ççˆëXÂp³Vⱄá:–8¬cE Ó â:È"c€,2È"c€,2È"c€,K÷îÙ¡žÀÈà©'¼)#í¤•¥³ç“V €l{æ “5kE@d‘1@d‘1@d‘1@d‘1@d™9Kåû~£Ñøôé“‘Ö¦šŸ4Éç ÔiÄ÷,..~øðÁó<ý¦ \Ç|߯Õj½^O¿©€†Ã'¥ž5¿ôSŠëõzµZÍ÷}ý¦t3ÖétêõúÎÎŽ~W«ìïï×ëõûû{Ív´ÖŠNgmm­Ùl.,,höÃfú§¹···GçÓí<Žÿ«T*ííímll\\\,//Gn'zÆ20eèFnÖJ"#1‹¸VÌNÀqã˜E^4F¹Ž69Þ¿_.—Çé8ÎÔbî®ë~þü9Âw š››ë÷û“_ã8ÎøÏ¥Riwww}}½ÕjEØi ±ñ&ÇË€)¥noo§¾÷Ý»wa¿`\¿ß¿»» õ–r¹<Ú‰°h ·Vd‰ˆÌмh ‘1†Œ‹³ #`€Š³@¿Å0ýgᥘÁÁ1ÒTÖ>N»¡è:¶¹¹Y­V¹‚#¥R©Z­nmmyq ŒŸŸ·Û퇇½Ž)ÑívÛíöÙÙYZ+V*•ëëëÕÕÕØ–‹“kkf|%©_xÔ «j˜ÆóƒÑívƒoâÝóÅìää„«²,lÀT¨½{b†Œ‹0ö3hb†ÌŠ0á,U¥R¹ººúö¼âÊÊÊ`0˜ü^×uÃ~;À8×u§ësçåñÀÇÇÇ£££˜Î+*¥<Ï»¹¹yµ2 ¬ú]øž Ó_nŸt»ÝãããËËËh¥"ÞÛ¢y‰8½Ö1CêéLiÖó fH1#SúµßÆ[ ší„’φÜ~#F:ƒ´:88ˆ¶ÉñŠúŠžçµZ­F£¡ßT@ÔE„´™™SõÍÔ0õ>ÿNâsúé§¥¥¥f³ùË/¿üøãaßn|Âlëm2>>‰Ì˜Ò˜6¡ ³­?¶Éòø$5c*Ò´‰N˜mý±MfÇ'ÁS!§-† ³­?¶Éæø$;c*ð´Å6a¶õÇ6ŸÄgL˜¶˜'̶þØ&k㓆Œ©‰Óö&f[l“©ñIIÆÔw¦í '̶þØ&;㓞Œ©o¦íÍ'̶þØ&#ã“Ès“ù¾_«Õþøã¿þú«ÕjyžGl–úñIaÆ”R¾ïÿùçŸççç–L˜mý±MºÇ'ìÁ½-€,2È"c€,2È"c€,2È"c€,2È"c€,2È"c€¬ÿDV`tê á!IEND®B`‚puzzles-20170606.272beef/icons/netslide-48d8.png0000644000175000017500000000275213115373736020020 0ustar simonsimon‰PNG  IHDR00`Ü µgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<ùPLTEæååçèèéççççêÜÛÛêêêõô죣£tttËËË‚‚ƒ‹‹‹»»»ÃÃë««”””´´´fffœœœjjj}}}áÞÞòññÖÕÕææÜñûûïùùì÷úí÷÷£zzžss uu®‚‚ª~~u!!—cc™ff…RR<¡mmO&&c88ûûûÀÊÊ5;;Ì××†ŽŽ333øööZZZIIITTT---ååÓèèÖŠŠ¦©!!µ¸GG•êéä{{©òþ++°ìÿ33µøøðzz¥•[[Gÿÿíß++¦»»Â……©ŠŠ«œœ®]ccÿÿÿ8u‹übKGDR `-tIMEá‹ß?îIDATHÇmV {›6FA„] [¶ƒÛÚY6u]ð²î»I›¦[÷‘lÿÿÏìtîÎ~@€^ݽw¯‚`ld2 8 ý¨Lí~ÄÝ"î¾;Œ†ø§2~‹’p¼ éæaÅLJ ‰Ø(rï9ÄÉ,e6 ê®3N>ÎK¿:c y÷ø(+N½ϤO a¥,„à)ëâå¥(‰¬†‘–»bÕ|!ª*{á5[ÎJ!ʹŒ}ìÔÍïÁT)^‰$ U—)Á ðç³I&(Ë+d²*’ªîÖ«SˆPFdXu ݱ¡¼¬dYw±²”C€+BÏÒK}š)K䂬»d+.å"˜Ô¼G9kÅÀ¨ZÛ e!`öv?…ŒÿÚÚf»ÛÀÿZï¶õ›Ï*ÕE³ßçûÞš}Ó<ÑàXY]ª\4»/›Ãáp¼üâx°v‰Ç«/¿º²ç£šÊ@º¹2[½1¯¾6ÛëDµ3óoÌFoµ§©Fº9lU êêšÁ) E7£ö´lUGº_œU(„íþ`™ËÆ +õÀœ2c¥K‡­S'ó€Á#½?hX¨×X&D–.ejÏ…+6µóå"“ V¡gáØ1~…Œ¾"ÂáÀš[³;骣X Ü»¡t2yÔ¸üM{úW_Y}þ3Q‡%tEXtdate:create2017-06-06T01:31:26+01:00ã‚à%tEXtdate:modify2017-06-06T01:31:26+01:00’O:\IEND®B`‚puzzles-20170606.272beef/icons/netslide-48d4.png0000644000175000017500000000116613115373737020013 0ustar simonsimon‰PNG  IHDR00¥,ä´gAMA† 1è–_PLTEÿÿÿÀÀÀ€€€€€€€€€€€ÿ‡…xbKGDˆHtIMEáü؉IDAT8ËeTÁuÃ0Ź[ª°x=ôª¤ôú²A;BGÈ9ÕÛ„‘P‹cIŸÏG@€ 6×—®y§¯ºM«ž Á`˜“º%õh–b\Õ!,QØ¡QDù K¬˜õ½+³æZ5Å#â$Zè2oYQ³B²tãt½¾Á‡¹/#Îlhfìéóò~ñöµûOì¾=™X\ðŪ+Á¯Nl’Ç€b²Âàƒ#³ð§jìŒÈFüð>5æã:\€û’ ¼:`•a«âAËT¥ÍrÈ× < â™St ¥úÛ/øª®›e"ÎS Å_t:ŠcM^¼¸VЏ„BüôLq7™ùò$Þ6G¸‰Y ês£èv¥† Û¶ýk£²6*¥œáÍ€ÎàYމ[+Àæ³â~̉Å+ã|j¸×Ø&N‰¨‹+Pc…ÌZ:€ðk½­÷÷fÂKÛ‡»¹•ä¡—Ö6_®ºãÏÜO‡Ð„*2Üèëu%tEXtdate:create2017-06-06T01:31:27+01:00Ee‰T%tEXtdate:modify2017-06-06T01:31:27+01:00481èIEND®B`‚puzzles-20170606.272beef/icons/netslide-48d24.png0000644000175000017500000000503313115373736020071 0ustar simonsimon‰PNG  IHDR00Ø`nÐgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEá‹ß? IDATXÃÍY_lÕ?ÿæßÎvg]ZÚ"·”pCh¤jâƒ7!ôæ&}2‚r£&†7xàÉ^}3æÆ\H4bªø`ZÓ®Ñ{Ñh®ÄD* H5Xð¡¥…–ÝÙÙ™s¾ï>: »Ëv‹ÞÄIÓìΜ9çw~çw¾ï÷¥óóóät±ßÞ"þ!¢¢LˆÈ£”vnü[ !|ß·, :4Ó4£(RJužÀƒ×u¿üòË'NÌÍÍåóy¥ÔýZZ–U«ÕN:õÉ'ŸB8ç÷Ãô€€1ŸÏOOO/,,<ýôÓgΜ¹|ùrOOO+OˆhYVµZ˜˜ØµkW©Tš˜˜è€éA!¢mÛ_|ñE¥RÙ½{7">ñÄß|óÍÏ?ÿlÛvv­0ß÷?ýôÓ‘‘Ï󆆆úûû§¦¦´¤~@Ëå¾ûî»3gÎ8ŽÓh4@J©”zï½÷Êår“Dc§NšŸŸgŒI)“$1 ãâÅ‹“““Žã´2J QJ£(€©©©‘‘Çq®_¿Î9ß»wo’$¦ifé!üñÇK—.ÀùóçŸzꩾ¾>Ã0~Ï%+‹ŽãPJ9çœóB¡P(Z•A)Íçóžç !ô¶·,«X,º®ÛVCâéyK)ã8‚€ã8÷ÛeJ))e†A(¥Â0ÔKL)ýÝBcƒƒƒóóó¹\. ÃÁÁA)eÛ1”R¥RÉ0Œ_ý4=÷‹[ëÐ"b†$ım}Ÿq.“¤Ñh´„„pÆ,Ûº*Á{„/îòÒ-Cˆ( Ãêí¥™½ ˆŒs‹R;ƒé½_‘hjóÅböQ}e•"”v H£Y^X¸ðöÛ8NGÒaÆÍå*Õê=Ü 2Λzòy¥TX¯§¸a<ùê«N¡RJ»¤”µaÃ…wÞ™9}zûþý‰ïSJ‘Ó0®Ý¸qöܹCÏ=—HI¡„ !Œ±ååå¢ç1Î "!ó®ûáÇ÷–JyôÑ ¥„Rউèí@S¥œ7jµ??ûìßßz«ELè1Íÿ~ÿý¿Ž}ùĉ0IR’çWfg·lÙb B¤”lû?¯½6<:úòÑ£+qÌ9'„èä__^Öô´„ˆ®ë6éN¿Ü¨TªQ,,0!€ôôÔoÞÄzÝ¿y³^¯k@zÃÅEß4 ÃÐ(¥ò†I¥ÕjþÒ’¤»eBt2­hlÛ>wîÜÈȈmÛM: Œ1!ô`BPΑR}'¤¿–•¢Rš¶”RÎ Û6,+DV£y@Ïç?ÿüó³gÏŽŽŽ†”Ò¨^ïFjéÅ‹¢è§Ÿ~Ò>‰Rª”ZZZ.‹?üðC­VÓ’Ð)vhh(Í€÷êé陞ž®T*?þøéÓ§ …BCCCûöîíì¿Z%hYÖæÍ›S†ôÍ#GŽ(¥¢(Ú¸qc¶}6áˆt¥ Ãøì³Ïnݺµ{÷îF£188H)­ÕjKKKë¢'U†¢)óGQDiÍ©Ù6"Åèûþùóç÷íÛ§E.—Ó¬fg¹® W¯,J²VQpgo+¥<Ï{á…¾ýö[DTJýòË/×®]››› ð­“ú?]"ÅEѶmÛžy景¿þZJùðÃ{žgÆÐДÒj—¤:Ó£smœsÚ±«»¢fŒù¾¿cÇ!Ä»ï¾ûÊ+¯ …;Î!ì®i–emÚ´)»·5ÊJ¥r¿Ü HÂ`ëÖ­ÇŽK’¤\.§ÅT÷Ü(¥\×™™9~üxÖö#¢išGŽŽ3 ± ÍSǺ£”í”t\íZ?ÒÿcMâ•R …Ç{,—Ë¥q¨X,žÛ·%‰Â87 Ó0 & í¥±^O,Ë%„ !*»- Mj[PÚ]û€ˆ1X"äN¥!@©Kˆ«‡Ôô¤I ubŒiÁe#B¶\iÎö–eù¾ÿþûï¿þúëº6RÆ™”ϳÿyòßo¾ÉK%O÷E) C>6võÃÿÇ–M¹\Îú!˲1I’•••r¹œõC®ëÒV?¤ÑT«Õ©©©8Ž/_¾ìy^£Ñèëë+äówCRÆ \æ++­V{¤$„Æ€mØ0-e ¥Á6Û·o§U¬>…Ñ@[9ŽÓl?tl­Õj}ôÑèèè¶mÛ.^¼hÛvµZuçå—^jq„`Œ0¦¡e‰M†gšlqq±¿¿?¤wc,—Ëmß¾ýÆÙ8”$I³ý`Œ…aøÁìܹÓó<)åøø8c¬V«éê®i{èˆ@øªœÉÜÜõƒÿ8P¯Wyä‘ÇGQ¤×B3€R*Žcm(2Ó»+ÖL…&„çy¾ï?ôÐCz“ë´¿–÷¸ûÔ¶í;v(Õ—$õR©¤¥­Ë~ÐqÔ¡£í‹/¾811A)5MóêÕ«®ëV«ÕÞÞ^–y™Þa”B…¸sƒ1ÖhM›ÞxãÙ8.š&»páB†ZÈd=×]û!¥äœ8p`rrrvvöСC…BAJ™Ïç£(JkM$„ rKJ)¥Ò¢&$E•ÅÅ¥8Ž… µZ­¯¯o]Pš—L§@ÎùóÏ??99ÙÛÛ뺮R T’¤Í8'aUíÙó'Û>ç8€Ž¢$I ¿ß&¤(D·Ay @)&ÆØÁƒÃ0l)eŒEQc||äÉ'w€~ލ9&¾¿¾úd @dÕ^AÐ>'¯Fá0Œƒ jy—pþ›Ï™ÛÞm%\g{¶Z00FëäÚÚú…4™t°ÝžQÆ"ßGÇó°‹M˱i’úH4ŸÏw¨òº>°BÔ–#=Xc-ö>ý¢sÍÙõ‘¥ óVwþº5üèÈBîclÖ¨k(i[³Íÿ‹ŒÍ£#×b%tEXtdate:create2017-06-06T01:31:26+01:00ã‚à%tEXtdate:modify2017-06-06T01:31:26+01:00’O:\IEND®B`‚puzzles-20170606.272beef/icons/netslide-32d8.png0000644000175000017500000000200513115373737020001 0ustar simonsimon‰PNG  IHDR D¤ŠÆgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<ÒPLTEåååèççëëëÛÛÛçêêßßàÕÕÙ‹‹‹¤¥¥›››”””ÓÓÓ¹··­­­´´´»»»ƒƒƒÃÃÃíðêíóó££ËÊÊôõõõûû¹››‘]]˜gg–ddº££ÔËËÎÂÃÜÕÕgaaœ““ÚÎÎË¿¿ÒÆÆÁµµŠ‚‚uooûûûuxxÞáásssVVVõõé÷÷çùùétt±]]À\\½ll¾UU´¼¼Ç((Æþ꯯Ë}}}ïòá**Èoo‹ñ__zŠŠƒ±±ÌƒƒµiiµÁÁÊÿÿÿrÏc'bKGDE޳¨WtIMEáü؉0IDAT8ËMS {”0 N“Z …ÑÑsÃqºÝ)2oSO:u~ýÿßd?€-O[àÍ›7iŒci‰/^×é#¤´p<ýŠ^Jà…U]´ác[VeeaºA%‹:º¡Q§²ÝùŠa14Ë)M·º¦Ì¬7·Ù8kŸœRÆÑÚggç}Ö÷½ßürÄ×ø¶~1l_¼¼¼Ú•ûÝÕå«×ÛaR@öüÂáøÆŒÜŠÉÙQæ#¦Ðf ‘Û~ÀÉ]WŽ¸î´¦¢Zkᘩ\ªnÓx¦i±ä”×u-K@¨‰3Ÿ$QÊRªà¡õ=_R*$GÙÔ{mûÂènqtÎáÚ jg!ˆ¤B0Þ¶ë-{Â38Ï`‚†&Ï‹·¹›¯™-…*Iõš:>ºQ6ã“¶ó'Ûï§,Q—Šf³\¡—vöp8ÜÜ"fäåªfLi‘ÛÀwï??~òi ¢á‰D¯c|šÃÍç»»»/_G8ñâÛäKƒ(ß]±P÷ßàÇiAm ,Äf¢0u)WÀχ_ ù¢{€˜GD¨¼’×pCü¸ÈÒ@:µ-³çCûçx<þý×jb“±Ë<°TÉ}š‡[ƲŒ†ÍÄÖ) =ú!ÍOF|šC,-Zï.zñuàqðçѽ>ÃÓ\,8M£Q…%tEXtdate:create2017-06-06T01:31:27+01:00Ee‰T%tEXtdate:modify2017-06-06T01:31:27+01:00481èIEND®B`‚puzzles-20170606.272beef/icons/netslide-32d4.png0000644000175000017500000000102313115373737017774 0ustar simonsimon‰PNG  IHDR TgÇgAMA† 1è–_!PLTEÿÿÿÀÀÀ€€€€€€€€ÿ€€€ÿ(^ãbKGDˆHtIMEáü؉IDAT(Ï5QÛmÄ0 =¤Ü¥¿‘.Ò ÚnƒŽÐ5îï ô£™²¤|M`ÃÖƒ"iCÀÌݹîf0ðX¼û‡Eß3Y¥‹«`ɨ»Ê"õâÈ0GhÀ!s34BUkwuÀÚÿO)øö6?úŸ·êÂ4 ËÐ+Oq!m8vØ;‘ÂÀœ‘Ž‚Ç’§hºÕ‚Ê#á“ÉKS#%?Aâ¤Ù—û¤”6ÊüJ¡T2_ŸÎ‘‡(7 =±{ˈ—žB¿²':Æ¢n¸È2žŒÌˆqÿ}ЃqRÏcÇy>ä›Ç“:?“âšMR¿ŸßLŽh굃¦q l£Bé×[ÈèÕ«×m= j£™6·6‹"à£ë"x‘<ê%tEXtdate:create2017-06-06T01:31:27+01:00Ee‰T%tEXtdate:modify2017-06-06T01:31:27+01:00481èIEND®B`‚puzzles-20170606.272beef/icons/netslide-32d24.png0000644000175000017500000000343313115373737020065 0ustar simonsimon‰PNG  IHDR üí£gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEáü؉IDATHÇ•VKoÇ®~LϾŸ\Ò$œ€TrXØ"d)‰r0,1°%ÀºØ'ÃŒÜô|öÉ¿B'ÔP)RºÈ ’¢¸ÃÙÇ<º{ºË‡^2+Ò•: vP;UÕ_}õU“xCDƘµ !§½”RBˆ1æ„—¾Otk­"Žc—ODçœgY–¦©çyÖÚÿ/"æóù îÝ»·ººJ)Ïá¢c–——ïß¿E‘ïûãwCä¾?88X[[›íõzƘN§sŒ!D)µ²²R©T„»»» årù«óO@Y__—R !ÊåòÖÖÖ‹/|ß·ÖZk}ßöìÙööv©TÊçóanllxž÷¾'p ÈçóËËË­V«ÛíNOOÏÏÏGQD)uÞR©´¹¹™$‰ïûiš.,,{€¿Ï 1I’½½½^¯711qºÉZëýý}!ĉœ“­DÈ”ºøÑGÝn·Ùh|83#ÓÑ÷7™$s³³œR˜úà%%863öNˆ½b‘rŽˆ€è !<¥”Æ';"ãÜ÷}ÐJi­W‡ˆÈϪ]”Jÿúñǯ®ŠrA)%cÌãÜç 8Σ´FD_ ­¥œ/Þ¹Sl6ùXèw/”±ÿln¶?ÿ|¦ÝN†Ãf³ùý?üåÊ•¿}úi0ž¥´Z­*­µÚO?ÿü¦Ûýç7ßtƒ€QJÅ"ÃÇùîHMA œÏ´Û¿»x1 &[­ÊÔÔä… ¿ŸŸïõzBˆüÁ¢^¯+¥šµÚäóç6—››Ÿ/rÎ ¢DŽˆ{{{ëëë·nÝBÄLk×F•$*ŽUË$1Jé4UI"㌑qÜÝßú}­Ô°×‹‡C-å«W¯‚ `Œ€Z½Îãˆèû¾›U)åÇ¥”óÜþä“‘®‘‘9ÇÍñ’s®”Z\\€4M …Â8¿9cl0TJ !_ûýþp8dŒ@>Ÿ'„ðã­½²²²½½-„ÐZÿáÂ…k5DÂ(M––¦~ù寔ZB¨1_~ùßz}¢×‹ööv=ÏÓZGQ”e™1&Š"×HBH.—£”rJ©Rjyy¹V«]½z5Š¢ƒƒƒœsí6¢=·9À­c¼Ç‡Ïû}õÙg¯ÕjRʉ‰‰b±8 fffë Ë2DÍAš¦BÆX.—ó}Þ&Éþ膇»»išcŒÖ:Ë2­µ1ÆZë^Ç•Ÿc …Âõë×=z†áÜÜç¼ÕjeY„¸ ™1e† Þ¼yó‹/þôòåvšÆdL ÇÕð­IVJ•J¥………k×®!¢’RkM)%`¬-|õÕáÎΪH•2®ÕZAð& s9Î3® årùÆQXËGb‡Öò;wþìyö˜¦ý>frÎÎþÖ$cŒ1£Iv 2„àá¡ n‚2JAïä%—Òßí3o„8 E±ÈK#çÈD)¢ÈS©TNhÑ»nv”s4ÏØ äèb1~‚ÓËçW†èÝO‹|%tEXtdate:create2017-06-06T01:31:27+01:00Ee‰T%tEXtdate:modify2017-06-06T01:31:27+01:00481èIEND®B`‚puzzles-20170606.272beef/icons/netslide-16d8.png0000644000175000017500000000157013115373737020011 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<ŒPLTEæææêêêàààèèèÈÈȨ¨¨ÑÑÑÎÎÎËËËéééåååçææ°¯¯¢¡¡¹¸¸éèèèçç¶µµ²²²æååçééñööÛÞÞ³··äèèïóóáåå²¶¶ÞââðôôÚÓÓ¿¨¨Ã®®Á««Ã­­Á¬¬Â­­Â¬¬Ä°°âààñõõÀªªÑÈȈˆØÍÍËÀÀÌÁÁÕÊʈˆÏÄÄÔÊÊäããÚÞÞØÐÐèîî ££ðóóáããÖÙÙÞáá½ÀÀÝààßââů¯ÓÇÇãå圜ÝÜÜçççòñññððÖËËæèèžžžîîîÜÜÜ···¹¹¹ÊÊÊÍÂÂÜÞ᜛ŸããåÓÓÓµµµéëàãâÒääÝØØÙôôô¡¡¡ãããÄ®¯ÐÅÁRUÜ$$äzzÔëëßÏÏÒÚÚÚ———×××ÛÛÛ±µ¶Ç±²Í¼#%ìÿ::¿¨¨•ÚÚÞâââÝááÏÄÀWYÙ*)à{{ÐææÚÜÜßį¯òõèïîÝîîåßßàßßßãààååèääèååçÿÿÿè9ÊbKGDƒü´ÏÒtIMEáü؉éIDATÓc`F&F(Ì,¬lÌÌ쬜\`>7/¿€ ¯X@XDTL\BRRJZF,/"'¯ ¨¤¬¬¤¢ª¦ÔÏ­¡©¤¥­£«§o`hdÌÀÈÂc¢`jfnaiemckÇÅÀÄÊ+mïàèÄèìâê2’‘OBÅÝÃÓËÛÇ×l+3¿¤²@`PpˆO(ÄQ@°ðˆHæ¨è vA©Ø¸ø„Ĥä”Ô´t°¡™YÙ9¹yùœ… C9„Šb‹KJËÊ+8 @Z8d+ªªkjë8Áf0pq1Ô746é:  ‹(¹mÊ‚<%tEXtdate:create2017-06-06T01:31:27+01:00Ee‰T%tEXtdate:modify2017-06-06T01:31:27+01:00481èIEND®B`‚puzzles-20170606.272beef/icons/netslide-16d4.png0000644000175000017500000000047513115373737020010 0ustar simonsimon‰PNG  IHDRíÝâRgAMA† 1è–_PLTEÿÿÿÀÀÀ€€€ÿ€€·yabKGDˆHtIMEáü؉WIDAT×5ŽÁ À0 ¡@&ˆWHFèþ;µd Äa fEÙ4 UŒ¢b㊸±–(,ƒ ¯@:i«Ò=(`¶ÏxXø=é5ºÒ懡ûô³{5hÿ¸%tEXtdate:create2017-06-06T01:31:27+01:00Ee‰T%tEXtdate:modify2017-06-06T01:31:27+01:00481èIEND®B`‚puzzles-20170606.272beef/icons/netslide-16d24.png0000644000175000017500000000234513115373737020070 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<ÇPLTEææææææææææææêêêàààêêêææææææêêêàààêêêææææææææææææèèèÈÈȨ¨¨ÑÑÑèèèèèèÎÎΨ¨¨ËËËéééåååææææææåååçææ°¯¯¢¡¡¹¸¸éèèèçç¶µµ¢¡¡²²²èççåååæååçééñööÛÞÞ³··äèèïóóïóóáåå²¶¶ÞââðôôææææææåååçééÚÓÓ¿¨¨Ã®®Á««Ã­­Á¬¬Á¬¬Ã­­Â­­Â¬¬Ä°°âààèèèçææñõõÀªªÃ­­ÑÈȈˆØÍÍËÀÀÌÁÁÕÊʈˆÏÄÄÔÊÊäããêêêÈÈȰ¯¯ÚÞÞî®ØÐÐèîî ££ðóóáããÖÙÙÞáá½ÀÀÝààßââåååààਨ¨¢¡¡²¶¶Å¯¯ÓÇÇãå圜êêêÝÜÜçççòñññððåååææææææêêêÑÑѹ¸¸äèè­­ÖËËæèèžžžîîîÜÜÜ···¹¹¹ÊÊÊéééåååææææææéèèïóóÁ¬¬ÍÂÂÜÞ᜛ŸããåÓÓÓµµµ···æææææææææèèèèççïóóÁ¬¬ÍÂÂéëàãâÒääÝØØÙèèèôôô¡¡¡ãããçççÎÎζµµáååÄ®¯ÐÅÁRUÜ$$äzzÔëëßÏÏÒÚÚÚ———×××ÛÛÛåå娨¨¢¡¡±µ¶Ç±²Í¼#%ìÿ::¿¨¨•ÚÚÞéééâââææææææêêêËË˲²²ÝááÄ®¯ÏÄÀWYÙ*)à{{ÐææÚÜÜßéééãããçççæææéééèççðôôį¯ÔÊÊòõèïîÝîîåßßàßßßééé¡¡¡ãããçççæææåååæææãààäããååèääèååçååååååæææßßßæææææææææÿÿÿTÊ‘bKGDì!¹³tIMEáü؉IDATÓïþ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’‘“”•–—˜™š›œžŸ  ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝ ÞßàáâãäåæçèéêëhmmäI÷%tEXtdate:create2017-06-06T01:31:27+01:00Ee‰T%tEXtdate:modify2017-06-06T01:31:27+01:00481èIEND®B`‚puzzles-20170606.272beef/icons/net-web.png0000644000175000017500000002203013115373721017046 0ustar simonsimon‰PNG  IHDR––³cæµgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEá  ºØ#IDATxÚí}y]Õyçw–»¼ýõ*©‘#É0–mð0 ÕÈL öe0vì klŽËÆJÊLb3…CHÈ„JL–2q9x  L‘ F6¶…À…%°%!›–F­îV÷ë~ý–»œmþ8ÝW­Ö»÷Ýîw¥V?ô•JÕýÞéïžs~÷,ߎá -f Ý3Ô*ÑY¿3Æ”R Ý«3J¦iÎúä„!ÆØ²%K Ó)º«gèBHIyxhˆ2óãc2Æ–ŸuÖµ·Ü²ï­·2é´<ƒâéD!Îy&“ùÿú¯•JeæWS2Æú–,¹öæ›ÿë¿üËG*+…’z6HöuÀ ÁíþdtRO`‚´*)µaÆ'üãòÄD°§ TJQJ>|ÀÍ–5™Í‰œˆI)¥”¥I±zÃÇ„`Œ!¡N*¥8ç†a$ÃpzÑB„DxŒÇ*•g]wh`cX -35ƒB¨õw"lR£˜æ0l‘gôHψö‹žh¬F”°¦Í”2„q"„ QM)QLñ†‚q48ÕÉÅBÍ!¤”|ùË_õ(jìûþÙgw>ðÀýõz‡¯z)e>Ÿÿå/yï½ÿ«PX";þlHb”Ë#·ÝvÃ5×\3>>>KžIBˆb±xçß|å•·ÒéLÄÕW)0Mÿ¡‡þÖ¶Sm#øÆY…lbB¸n”6!Pª61q.BMR !Ë÷ÜX¯ÿÆ|³QCF©pŸã<‡qJ©R4OŒéääa!^ªÕVJ©B^ @kµÿ T ¡LÒrà‚ÑÎÂÖùF ù÷ÞÕëΓ£ýjŽ;)ï×¢ X×™6#¥””*82¥”úçà‡IóQJ?4ý“V¤Ž÷"„–eÙ¶-Ä”¯ÿ7 ömBHër¡”Ò¶mÓ4õƒâÈ…œó˜—ùé½áÆÊÍ<>•RŒ1Ó4•R è”Ò:R„!$š'Bhrrò¾ûî[½zµ7/=Î{ÂRÉ`§ÕtÓ¦M<òH:žÇZ|/Bø‘œKHA)¼òRÊjµZ(¤”‰¬BBHµZŧR©0žRJ˲öïß?<<|æ,œýÅ_|;“Y"׿bŒëõúîݻׯ_ïû~"ga*•Ú³gmÛ«V­ ÛcK—.½çž{üñÅESZp@ž­Õ°¾Î(¥0Æ®ë–Ëå‘‘–„¥B_gÆÇÇ-ËÊçó"„ÇiûÃühÎìFðDý!B Ô\…ñc·Á™<ƒæ-ÚGü¡~¥Ô0h ÄsÎ !†a$u1 ƒN“"Œ'¥·ll‰ ¡p”šyþ›@(¥·#PŸË›„|Pª6­@Ç(¥/L©"€€æ²RëR©z¸‚­pZÝb¡æ*e,[–;'دB£££RrÓ´;::¤!ßgË–-oêsƒ’ÒM¥V¦Óÿ;ŸF_À0F®ë•ËãP,vZ–)¥"„”Ëå\î&!œè•‚÷ö®ºÔ¶S‘jneYBÙã_ÇÅMÍ!B<ðÀýþZ)eÛöþáõ££c\°æÁ¡Ô@¤D®ëFï ãjµzá…ÿñ±Ç¶(%”¢P(<÷ÜÏ¿õ­ÿwÜqûúõÿyr²‚1Bˆø>›œœŒ>í !•JåŽ;þŒãPAŽã¶™bn¤õz=øY)%„’R€¢Zuj5—Òc·»¦Ü´ØËØ”RJIˆéº¾þÕuýjÕ©ÕÍ*¦É!äºnÌKAëÇÏiE± œ9f}… TSxšæôÔYÀ äùÞ¡¶zß›² • UfªÞÕ {À”ÇÕŒÿ#ÎbÁ°áÎNæ£>ñó&3Þ±F"dF˜4£…ý3ÆØ0 -5䮿Â[–­g:æ›L©eYžç5ÜH•R–eaŒ)¥¦i&rªaŒõ`” uß´¬6“ú‰ÁôL6‘n*\În ¥Q!:=‰úFçyÞðððØØXCµ‡x¹\vçàÁƒaŠ)åÄÄDµZÕ¿NNN ÀB …Í›7_rÉ%kÖ¬q§õE£u=ôÐE]”ˆš[)•J¥vïÞmYÖûßÿ~7d&cK–,yî¹çô¯\pA˜±I;äg2ÑHíÔxtGº.„@œºBˆz½îº.ç¼á`¤”Œ1Œq¹\ŽX¬šÊå24Úô9çÕju||0›­]»ö“Ÿüd¥Rix¾êÆýèG?ðèëŒïûÅb±X,ÌGZ×/¥âÒK/Mê:cÛv¡PÐÙŸ¢c*žþyhÍ©nþ×™YùøŽÄó<½ø"ŒMZ& ¬ö•J¥R©Œ7•ÞºkµZ¹\.•JÁÔ¶Óœ‹iY¤\Øà¨ÓS\.—‰©ÐÑŠµZs^©T"ŒMårYo$§(¦b5}qô¥)ÚØ˜{4[ýktã€!BHJ‰1¦”è„«R!"¥@)ª#@fuUsŽˆˆO3mlJ͵XÏðY„þ§ïŸ-¥¡H +e4M®²ˆ¨ $„T«•Ûn»}ÿþLsøž„„aÜnš¹ïÒ Ní¡ö5úÜç®3Í››ž)J±±±±¶±4A{@ãÑÑ1¥Fã4S.Rja1Ëæ-Ò™˜ŠEO!·R*)UBîxMªaýÕÌÀ†ˆ<:ÚÆ¤ÍX±©õYÐ*ÊÃÐ\G=3TD$Bð•NOØæLc¸Î©„!;•’­gVʲ,Ã0!…BBö:Îy6›M§Óú×L&“Ïç!Ä'‘s^((¥™L¦£££uW`5 S©TRÙŸÒé4¥Ô0ŒL&Æ“1–Éd´@¬Ý"\Óé4ƸálöœbÆØÎ;À÷È\ޱçy°yóæ°pmë)•J}}}„W^yåwÞ‰hL)=räȳÏ>»}ûö¤b*8çžç½ôÒKÉ:ä+¥†††ÂxJ)MÓìííM§ÓúЇvíÚåÞÏW«U'¦B`BV¬X‘@zõjîK.¹¤Z­†)\ôk{ÕUW鞈¤´RÊL&óì³ÏjUrëQ,Z“¢_£þþþ¤Âb,Ëzûí·Ï;ï¼óÏ?¿^¯‡E6 !r¹Ü 7ÜP(´7BC†œó%½½ßݲ… 4wÈWã®înÙ²¯{àCY³fÍøøxXT $ÓçG„êŽsÞÑѱ}ûvÓ4ûúúñŸ×AÞÃÃÃ===I¥Êd2]]]«V­ŠÎ „Xºt©Þ?ÃíûþÒ¥K-Ë’Ð 'K£ëŒRœ1ÉX‹ùç5úÍrÇuÝD/ttçÜ÷ýÖµÒº“ºØcLG€´ØII¢ïe®ë†ÅJÔô½aŒ1ßW!nw!²BÉ:y%’ëfÔ'Î’‹Ö?‘gÓ¤+1ƺÎ,^ŠSÑnJ€6ŒR*ŸÏÇÁF)¥CѺˉQ;@¨ò|ðÁ½{÷Ú¶»Á4Í»îº+ˆ5ojµ°øöÛoëˆâ¦Ø$¢‚9}¨ Ô43j5¬M;ퟵ„A’—¶Ù!cÒü!lÜ¥E.Î9ÆØ÷}ß÷‘ }ß×Úm-ÆÝâ¯0Ý>@ZwRÁKJ;£³ háÕ÷ýeMÍgŽraŒ^v7ó#Õz&Ç÷1Æ™|>-J;º» J{–.ÕB1ç¼»»›Æ6ävõöf2Á¹–}1ÆN½^ ¶ØI­)¼ûnÏÒ¥ÝÝÝùŽŽ!dŒ¥LÓ4͆ÛË| Ä#€Ûo¼"°Ô 5÷?Ü?Ô¤èRš{Ä*¥¨a9r#dš¦TJgÓ¡„€xžíwÜvÛqEd’RÖjµ-¹œŒ <Ô;5(Õ¤“ãJµšËå …‚¢ O!¢gR*eÆ«¯¿ž8Ñê4g•R¡¯ýùŸ¿ýÔS eƒ†R@ìsœ&êŒ!•pœ&þØJMµbŠ'cÐÛ ×\{ö@ wîW¿÷=Èfa–YÇ0bgl0×=öô°N0Ö|~ R)à'´稧G]wݳGÅÒ‘6#$eÉó€ÔÚµÅÕ«¥ç…õrªâ@6—“acV Ûv}Ïž‘ûîÇYrÏ=©| ”§R˜J¥‚HaH)Léè Ž;~ï-·`r\¬½>½,ËŠ8P¥âðáÑk¯UŸþtþ÷?óáK× mŒïû–iÚ¶-ÃÓèÑtzlÇŽòöíäî»Ïzí5ÔÑ!&_Ã0öïß/¡A>½yž…˜R˜œüЊ~ç;#ƒƒÏ!£õî»ãoºi"¤¡¢ØÕõøßüÍg†‡Áq¾ÿþO}éKå±1Ö¸X|øá‡ J—õõ1ß}vuÝúÅ/¾¾o_¹ðïÿò/Ó™L`\ÕYÆ^}õÕuëÖùáiËìtz`ÇŽ›ýk½îã¿ùÞ{>ÜØö"e:“yùå—/ºè¢K~çw&CâC|ßïêíýò† 9‚ç¥gžÉ¯XÁYƒRŸŒ±Îžž ×­«¾ôÒ‰¬æ{#U 0RV]·æy4ÄO—²îy˜r¥R®VI£ Îi.WÓɦ0®:NÅu˵Zc9G”:¾Ï¤¬¹®N-Ì9·]WÄ–%jž§9BÏs«¹n„ãºÞò9¯ºnÍuÃÌgŠÇ÷«Ž3Q­VªÕ†cñ}?à3+€ÉZMÕj¼ÑÆËËär<äLmA.T M{•‡jþèSÞó /fSß`ý7ÇòÃÏÊ:5WÏöYy–ðt¦>Sc‰—ºøÄH„†ÍÆd†™BY5[b¬GÝpG>ãÁ¶è©M Ý6ðÛÌÚCÁF)­T*wÝuWLÕšeYgb*N;Òš ˜Ça;ám!´–q`QS›œ…ïeJÂÄpÑìâÔXðÌÕü߸ÈFHË>'~)•:öy ñH{_é ¾¡†fˆŒ„JHDU8í?H]Ñó¨•5Ñgd Fj¢Þô¸› <^õÀË…„`-*¥'RÚPÁ&¥¤á‘ 2ä+¥וáéÕAËÅéý¹¹µc<66æ+„À–U­Vµâ£R©”J¥m\S©Tž«}‹3™L­V³m»V«EäÒæ)eC`RÖtZ„|Ï«V*µZ­a'ucÌqœ±±±°´W¾ïg;;=ÏŒA©‰‰ žÍ6´ç0ÆR–¥µÍÍu¤€s¾÷ÕW¡‘²N“À8J«•ÊîÝ»ËccÑ©ïà?øAØ .¥Ìttüæ…àw„ضmÛX±XŸ˜ˆxÁ'&&Òé´Zhø\íMsèС‡~ø3ŸùÌùçŸvŒgŒ D܉ Û>:4!åò¡‰áሜŒ±—_~yß¾}nöK—¾ùæ›`ÛJ©'ž|Ò^²D†¤W/æó¥RɈS! ÃX»v­tÝ°ÔÆØ|üq`¬P,®_¿~dp0¬ÈNE†1¾å–[ÆÃVWW×ÿ­×¿W*çmذáê/}©òZ!:;;7oÞü±},È;sb3ß÷{{{/½ôRÇq¶mÛöÝï~7"??¥´T*mÙ²åöÛoËo¤”Je³oþò—õÐCP¯¯_¿þOþø=Úpຓ>úh>Ÿ¿òÊ+ËårØ*ìíí}í©§¶×ëã/|á jîžžž‡yÄ?xÅtÈ÷µC~ÈFJfl¤¾ç…9=èµãEµZ Ûv„v.çj57B®ëV]7¢±.¡ãºnµZ K2¨ÝtBO]Š@)¥›…&æD¨l¤¾ïÔjµ0MÓdŒù¾ÁÓ÷}À„@­Võš°Ë‰9©¹£Ýȧ½ÃÒå¢[ÎÐ ‡ÞzAÓjn}­ˆsSÐÍ"RºhuÀMD5½YêòhÍu0.<ã6ž9ê†Íô§³ÕÜa-ÃÕÜ &Ú WêˆbíÐp|ˆl0_ ÕÉ“7jý³ÒŸè:uJI¥‚ûsüQ/„ú®a¥Rú&Æ…H†Í‚ãB©\.kY¾ö•RÊwÝD’j¤/†më_ ß'F*!J3ù|¦PÚ^(„[¯Ë˜!"§~„ÉZmð•W°ãÆÚj`ï^ð<ð¼wûÍ/~Q' Ó\ºzuG>ÏŠ©_@Ò/îÐÈÈØ;ï!!ÆØÒåËG×_Wãã{¶mË.YÂ9GRª\®ÿÜsmȃ⩆PÑÕÝýÔãáöÛÍË/÷''§–l[_g¾:< ;w€™Íú/¼p÷W¾rç=÷ ¾ûîb71Æ–õõýÙW¾òý_üÂøà™ö“r9ø·ã½½Ÿø§¥@JšÍòŸþôÙ§Ÿ^ûÑV&'›:0.ÄFJ)”JpÓMôÿQú¾2MíH¨"¢Õ ŒQÃðï¹> íR=Y ñqxðAòÙÏ*!!@ÈÏ£–ů¸ÊeˆYÄêÔdjCäœpÏ›¥n˜’lㆌµS ÄTIÆ÷ýY¯æÔÀ}, æb[ˆ©Ö êX˜fƒ6ú[Já²DTÓmZ²8þ3@Ÿ¦µÈæ²ñ´½pÞ4¥>E(ËÉÀ(¥T:—³³ÙÓpW?!(¥¥DÊ×ö3×÷qC€Nøõ¯áÄ|´ Mg  J=ùüówìÜUâc7ÿèürù´Z‹g „1wÝýccðÕ¯BµëÂå—ÃxÂÓ‹¤4ŸÿâÇ?Žžy Û' ÓÝ·ïíÛá²Ëàt*œwBÀ»õº](ü÷{ïõ…À!V\¡·wìxà¯ÿú´Z‚°ê—]ˆÆ±HB€a€”§ LÝ”†G06¥²ÙáÇ[]Z#:4ýí\nL £æF!@!±À'Ÿ*Õ¨Îà§ëo5ì³aFk9‡ž¸Â¸ñÀ168!ñ‡½Ú¥”iÂoð;ùÀ4T~rŽûú`×.Ù×wê{x² ^|‘/[ÆK¥Æ2g‡+ȹO5„c·Z=û¢‹>õÌ3¹M›D˜˜…˜TjÍç>ç†Äç-.Â׫ÕuW_=öýïgwîl쩎¥ôÎ9§såJ/å@X­VÿÓG>òôOÚÔû”'&Ê‘É  †1Q.ßøùÏÿÉÆMŽ”u㥄]€TGÕ8p iÿ´Ù‹™ß;c·i{Ã0bšHæFŠ1¶,+þओ‰“F1ñeÑŸ1g(ªÈ„ø‘Êiï>5©?Ú@]ä`NTDÐõª#Ü‹ƒ¯0ÆÚ<Œ§v:6!Dί”Óeûž>³“-n$“¸Nˆ:Ý¿q-TJÙÚ¿_)BH*•²m;ÌX9еõÁÖÊH`º¥.rP,Ãb }ß·,+˜ßb±¨}v’R*„ „tvv†U¢UJ¥³Y]ª”J¥R@GGG˜i>Ÿ·,+•J‹Å°˜ŠøÄ³l›RË qÊ!ï^žûÁÔnö”V«Õ={öŒ=†¾RJŸxâ ×uI{mÛv©Tz饗Þ|óͰ”i:ó|ww7ô÷÷?ùä“nø!äy^¥RyôÑGY¸´•N¾ü2` –µ{÷î§~ò“±ÁÁ°Œ–e½óÎ;¦iNLL´žŒsÞÕÙY*•(ÄÌ;ƒeY Ì!ßšvÆÛ¶mYVØH!œó‰‰‰$•¡ŽRêºîÈÈÈäädÄ%„¸úê«W¯^}î¹ç¾ùæ›Öi~!ù|>,å†p2“ѿؖU(XµÚpàRÊT*ešfP×¾õ4z…B!4 `v_!+W®á‘M6!„R"•J­Zµ*ŸN‡­BÃ0†††8çþð‡#ªOÄ'=;¿úÕ¯úûû{zz"N•xÙe—9ŽQ9Z¿g•JåÀW^yeDLE:—Ûg°cøþê÷¿ÿ’uëJ¥RØFZ,'&& …ÂUW]SŸc…BCì"®ç…•QJ¡1žçyž×ðªÄhé6ÇqPÿïyžã8Mjêé‹n§•Ëå57“²ªË#亮099!!Ä÷}×uËåòd GÂhbŒeÓi¡ƒÓN –c*š¶<95 b2Œ#„ÍŒj8•1ñIÇTÀéS‘8EKéã顎¶Œy'8ݵ3‰“RªX(Ù¬ ©Ä|¬¥çMŒŸz}–>‹Åb6›•‘TÓ:Ò˜Á$í¡®ÚõÃÇ;ðâ‹&!að %„ÑßÃM7§\ïÊ9/ [~ô£ŸlÙ’%¤‰¥"Ÿÿú·¾ÕÖY^ Mw›@hÙö Ï>ûÆ×¿ŽÏ9GêhÓIÈçᦛ>_­Z]]âÔú¿!2¹ÜóO<ñøyçðl|<Ì^HûúøÆ·¾ýöªU«Üö¦v€PV >ùIrÎ9H©Ær”ªBaNîî ’ÀŒÁe—ÑO|„hìÍ­c*úûQìú‘í¡”R§æ M?,PºPø¶ÚK BpÖ !Tð¿´¿–ØÙ0MiÀ’þ~§^o± "()S©TñȑžžÆ9pÎ{–,1Ló”¹Ê{zÒ„¬8ûì0ÑÞ ¤gÙ²|>ßÕÕUèèÀûžgcœÍfAÊd=ºæ !ÓÜÿÛßÞsà N½æg†1®;N½V{®§‡GæúIºžÁÈÈH6—KÙö”²F©”eÙ¿lûäbˆÙìc÷w‡Þ}·Z.“°¼.–õÖ[o™¦ùèŠZÍ-¤Ì‹Ûþýßá¶Û’ÝÊç!B¼VƒsÏùÙÏ×Ѫ¯¿ö¶Köú§]‚<çÐÛ ×]žwr!$Ž%×]÷¢a¼ˆqÔv§ã–•:Vä€1X±^'Ù”s†!Äúæ¦M›.¾ººè´¾´ASýyp…5›)M?žR"Û‡«ØÎóµS­®¾è¢n¸ákï{Ÿµr¥Œ¼qLÝ\ÂVLJ”Ï‹]»ätù÷¤h>«P±zÕªG6m]3',‹€aG¾àüó×mݯW*eÛöoûÛ¾¾¾ÎÎN–Œ ÑÙÙùµ={Þò}<÷|2Èâ¿}úÓÿeíZ¢®œê¤ÅŽŽÿøÇ¹\îÒK/ÕjnÆØò÷½ï‹×^ûÃJ…$¸)Íó,ô’„œ1Ý=îûzà‚1©½ñô¼y^c¡BÇÚÏ%Ãñâíg*Ÿ0B`šYVc ̰Ý›ÙI  ,+,ÖÞà”žÖ1'…”’¦ ×_/º»eØö S:4uW<å„d±›6ñþg^¯‡F6årðóŸ«M›b*’ÚBBHµRùêŸþim`G`ƒH‰/¿ÜL§O}’|Ã0FGF¾öo|~ß>*„Šðå‘Rnܸúƒt⹪´„!.ÄŠåËɪUÍí…œ»eæNf'çýgµzõj-I#„„¨×j"ž§ „iGB𼘰“nxɼ™„#«\Τ6IÎËDˆfQc9ç2 ·ÏÀR¡ÿo½ˆRJ³Ò<›z°Å!í±¯Í):|‹ ËŒ6V´Î“1Æb–cÖ˜Œ{ºº„ã´jXPÊ0 ɹç8=]]Në KE>ßY,vwuqÆZWÚŒmÓ¬U«===…\'R3Ú¶»:; …Bggg6n‘'óýT&cFC§›ã TJQ€‰JåÆiõs‚Òå™L&©‚<ãZ­fšfRq‡Ú1É÷ýï|ÿû"‰Ä§Úå¼T*B …BPº»†¦aìÚ»7 ¢Ê1+e[Ö$À6Ɔ^{-) Ñì¢8‡ñ5ßÚ*a„üƒQl§Š| ¶ÆP"È¶áøƒ ꟴ‹Ü† ¼ñF6“IÊÁKMw"Aj*9Ì“g²¤œ0ÆH:½uëV8>lö„š²ú0h—ÀÚ¶"„@©Ê Á@³o¤å‰ }ó9ƒáiH £$gCع%Þkt&Ö~ÑÓ=ý”’Ô@‘å “%tEXtdate:create2017-06-06T01:31:13+01:00?¥ª¤%tEXtdate:modify2017-06-06T01:31:13+01:00NøIEND®B`‚puzzles-20170606.272beef/icons/net-ibase4.png0000644000175000017500000000076013115373736017454 0ustar simonsimon‰PNG  IHDRqqPQãgAMA† 1è–_PLTEÿÿÿÿ€€€ÀÀÀÿÿÿÿÿÊUjbKGDaf¸} oFFsP`‘ëštIMEá‹ß? vpAgÁÁ‡–ÚIDATXÃíØA Ðö%ƽzM¹€ pÞÿ*ÆPPh™±˜ÿWŽÍ+eA§Ðu6ýq\Î.ñÿ¹óÒ„ñW¦èÔuÈK5²¶T ±¼Þ™8õü}›IŠîMâ1)œgOÒyB~$Ù• ¹-iÛâ…Â6×¾ŸÊÇtµ kÈêÒ­ä|¹·/h‚lEM=í?ÉòUöÈÆd¢_ŽÙýS›0q ¹)û2^’îíY(™='/¹ý'+Ù=//MéŸ øgé@ñh*‚І ¢!¨h*‚І ¢!¨h*‚І ¢!¨hª­hšÆã8ër [CMÓÜM@ª¦1ed¾…ª„Ç  ׈”†B§Ó)íÿ«ïû··7§³ÿ¿Ûï÷ âwj¨h*‚І ¢!¨Ÿ—}w8ü†käÆu½=ߟjÿ+6YCÃpqa̯1•¾ÿã^ AECPÑT4ÕdÏËžMÚÛ“‹ð{ƒüסõóΆ â^–èÑ "«õCóÜp¹AECPÑT4Õd Õõ6„*òO]oŸmÿ+6Ùó²×Ó|=/Ð_æZdÿˆÁ½ *‚І ¢!¨h*‚І J|}¨ï{¿íã7n۶뺶möŸ&Ãý»RbCÖå ñÛ÷}ß¶müžM‡>›3=ĺÿ|Ö~|q=$îePÑT4 AECPÑT|®côòòz»]"7Þlv¿]§ 44ºÝ.ñó‡n7æýÁ½ *‚І ¢!¨hª™ž—™†t]çw$3ì¿ ÑD“à:41ï@3äÛ÷® ¹.NÊ“û½Ìš‘i Ú׃Æïߣ5h~Ǩëÿ9Ì ÑT4 AEC£Íf?h³Ù-}¼aíLjõ@ɸAECPÑT4 AECPÑTUü;Þ!„¦iî!T9­pðžS:Óùéºîóß×TEbC~ˬó‡¬òœdÚ¿ßùùú÷5UÁ½ *‚І ¢!¨h*‚ŠõC£Ãá0 CäÆu]G×ã)סQ|@ÖW† ¢!¨h*‚І rßþÙ†ñ”.á}{ßׇöû}¸Çì]Xe\ÊÏeb= !„™^cL:²X÷»ïþ™ê/õ>~ÿó3ÓëÔñ÷¾æý¸FÌzÏ}ô¥ÍÊäü¤ aâwj¨h*‚І ¢¡Q]×N¯ë‡F¬JÆu*‚І ¢!¨h*‚І J|}¨ï{¿í¾ÌôëÁXgµXOŽõ!ÞçÇÊw㸭ª×6Üï¡2ü¦&&ün«‡û÷>~Ëþ™?„eÐT4 AECPÑTŬzy}½].?ü‡ª ß>°Ùí>~?×÷‘-x~Šièv¹Ä,ð¶È'εàùá^ AECPÑT4U1ÏË ’6ù \44±®ëÖ9šè1îekÛ6T•áOù¸M/~×:îz\‡ ¢!¨h*‚ª˜ß©7»]ü»Í›ÝÎõ`2´àù)¦¡g[dµàùá^ AECPÑT4 AECP%ÎŽ‰_2.¦©*ëŸ|$Ì2í<«óÓu]Âì˜çÅwS‚öŸÏü!+æa4 AECPÑT4U1뇼~ý®×Èëíöøþîy8fçýäIçy®×øÏù}.ŒùC( AECPÑT4ÕLÏËöûý<Q¡LÃ\¿H*Á, 1gÁ§ë“œŸåŽß·¡Óé´Ï凜|œÏç¦üóã~Š_}öi©5hKÝmM«½Âã5h Ž2âwj¨h*‚І â}ûQ½ÝÆ¿_o·®“€ùCËËm=ó‡P0‚І ¢!¨h*‚*qîÖ*aîGÊëC%¬Â|l Ïçj_—„¿°.G±ÝË€ïø*‚І ¢!¨h*‚І ¢!¨h*‚І ¢!¨h*‚ê?#þZŸ‹­!IEND®B`‚puzzles-20170606.272beef/icons/net-48d8.png0000644000175000017500000000333613115373736016776 0ustar simonsimon‰PNG  IHDR00`Ü µgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<€PLTEåååæééêççòõõëëëñîîÕÕÕ¾¥¥ÄÄĺººÇÊʰ››h”››¥¥¥œœœ¢œ¡¡ËËËÓÎΙ––Ûççg¡­­³³³«¬¬±­­­±±ìññáÖÖqrr ‡‹‹Ÿªª¾ÁÁ‹ŒŒŽ’’•””ƽ½\^^¬››¹©©D}}ssddiizzCCRR kkxx"mmFssàÎÎ?}}“eddzwwqqP~~Á··ÿôôJ‹‹N||úììF††MMM»²²fooIvv®¡¡ÛÍÍ)„„—££ÜÜÜ111üûûiii***ùÖÖ†”” ‹‹$ŸŸ¡¡!rr¤°°x““ééýý®®Í»»ääÿÿv’’M‘‘õçç²¢¢Žšš¤••~)ˆˆ%……oxxÛÛ‡~~Qwwˆ~~3xxLLun††_wwG^^wzz&‹‹k §¹¹³ºº{mm„llt\\‚//rÛèèÿÿÿý1¿žbKGDH¿qåtIMEá‹ß?[IDATHÇV [EÝÙÝ,Ù@f²aRfvÒ@ &”Viå!•†4`¤­¨PkµF+´¾ŠŠXùíÞ;Mû}žLvvfsr_gvÆq,|]â¸xïê©ôž¨‹î†ßryì:Äó?…¾õ.Æ> ƲW†WçrƆ7>‘§Œ"¦ƒÉ — àpÎÇIÎ Œ—\ צ„”qœ)à¦ìúÄ'ð$ÌȘV´…2d *GràÃF,*0 ˜NP \šŠG#i!”†ÓÕë€jMHtÉX˜Q¿Õ–…çg2Ï÷¼Œï 9;]U¨‡150­¿¨5²³€pn6ÌÎfë5ö¶&Lç뵒Ϋ׼6„Öü……›¼,ܺ…ƒø¼£ ï..Ü6eÄ,!áÎ{MÎy£1Y,æ––——rÅ\ÀWèjõzÚûoTl!^»ûA¢c þz»½N Ø±œKcÔÈÄZXÛha–(º¹¹µµ©³$j*ðD²ŠŽº<>YBGÈàB–E¨€u(iå&T:V„DB¥AtD»¤*mê¾2#lo|;_ˆòÍ‚\±¸³»A'™ÅÓ¶?*0¦¨²"sgyy'›Ëå(¤*×_ý8€AQVˆbxÊ¥D¹k—Ê{íö®„REöî?ØCÿÂ>j´ÔTÒhu1èXiiéáüüCȺ+Ô?¼÷ chnÏ$Ã,Iâ}²ÿéþþgŸOúNˆ <`#ÁÆpËm ›‡¾<þ²L„%`Q¾ob˜º„ëÁ;|ò•&h— Á+i¥gjihÁ|b ëj5õSµN -HJ2‡,Aǰj,¨,‘Š_WkI’õ¯m κT¶ò¾k\ÊD[OÛí§¹ƒY¢4ƺ–àøß 6Á¼&¬Ú,¹..!ŒAÉ •;|ÅàÕ]ßwT¥ ”Ý´D)í­Í +Ð~ÐTƒüût}ÑOß|ßržÿ®{¯Úä5¦ßt¨SVWo¾F-â8cÖ4¬‡!’V–(Èž Pb" ÉDp™à)<‰#-ïT|ºp²!GÀñÁøø`Ð2o¾‹kú*¡!“gkßïíÞYCh)V•VË1æ%z‚׆ Ÿc_ü dw¨‘×L÷DZ`/ƒžÆJ³5ýuòâ'!#+oS‡Ÿo,n.^Â/O”…šuIk œùã—'€ã“üzòò7åÒc°@Ížg´$eØÑáBv:Bt ñÜïi ̱⛘ÙPJPØ0KT<»ýÇÑÑQ²¥ h;R?Âì5̾"mŽÍ4˜aéþðêÏðÔ@œFê -/;-éWh鯳!þ>{ÓàÌnds¯ÿù?xõÚžH©T:W°½ÁÅÑùyzÌp}ATGô=Á&=Vsvs½|€_Ù½èŽZ–8iŽ*º¹ØÈÈá…\8åèC vÿ´îeDéûV%tEXtdate:create2017-06-06T01:31:26+01:00ã‚à%tEXtdate:modify2017-06-06T01:31:26+01:00’O:\IEND®B`‚puzzles-20170606.272beef/icons/net-48d4.png0000644000175000017500000000130113115373736016760 0ustar simonsimon‰PNG  IHDR00¥,ä´gAMA† 1è–_PLTEÿÿÿÀÀÀ€€€€€€ÿÿf†bKGDˆHtIMEá‹ß?ÕIDAT8ËeTA’£0 ”’š»g0©š;.›=‡ÂÃyg6¼ )þÿ„mɆ˜Œ `Ót·$‹9&f"&çt®§#:ïCü0X0ñ"^::ØÁŒ”IJ.OpdcÖWð¶>†(”2Ô[Îó<‹ÐÛ«ÔÀ–Æâ;¼ŽÁáÀßj~Îësþš>oùjŒ¿è½õÞƒñ/ú’ÇñjQÍ7H9“Jfά€y|×póÆpZ”ˆ`œ…k &mKrؤè8ìJ¢€åÁböOF´ì~°\)ƈUJ£BYÞ­lû¨ èqJ“‡øQˆÁì2ÞÖÌ9M±›TaLËòàG(ÀŸe¹€“ÑUG¯[iæ¹Ü&Õsó¸Wvϲw”¦|‰*Öí§³ºº|}ݸè¦:ýCÒ‹ÿd'tb­B6å%tEXtdate:create2017-06-06T01:31:26+01:00ã‚à%tEXtdate:modify2017-06-06T01:31:26+01:00’O:\IEND®B`‚puzzles-20170606.272beef/icons/net-48d24.png0000644000175000017500000000476113115373736017057 0ustar simonsimon‰PNG  IHDR00Ø`nÐgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEá‹ß?õIDATXÃÍYßk×>?îÌìŽdïÆ’V¶SDZd.N!LòÐä­ÉC_JS$„þé?BÒö-IJòj)$hBAòâÚ©ìÔQ£XÒjwµ;3wî=§W»ÉÒʲ›Ò‹£™{ï|s~|ß9W¸ºº ÿOÃŒ®TUE€¾‹ªâ‘—ª*"VšÑÇQšBžëшÈ=˜DU­µ»47oþûóÏy~Þ õû}˜˜˜8*&U¢èìÙ³»‰H21ñå忼ðÂß|³àtHˆX–%]ºt©,Ë`jDŒ¢’$ ¾ ¯ùôÓOE$Š"UÕ;6¹)˲|0L»í2PDŽ¢'NŒDDEQ0ó™3gŠ¢mºÇeªš$É•+W¼÷I’Œ&T‡÷^U‰¨ÝnWáš`Pçœsщì¡"âœSÕ¢(¬µEqxsÎ{oŒ)Š"˲=“Ó4efï½÷¾zßìÙ+D|u± Á)…dŽ1‘†÷¾^¯/--½öÚkišzïCNEñÊ+¯<òÈ#yžïÙÇÀ˜¡ŠÌé02‚å ‘™''&Š(¢!îðxô¢šÄq½Vc¢´^þ*Š"UÕ“ÖëPäùÝR%cò^oåÖ-Šc {Ù²d¢¾ø¢¹ 5FAÇWWVJç6{½µ[·Fæú×êjmb"˲QrHÓ²üý•+Ë2êõ„y×ã+Wn_—%Ìά­Aí :¨×á›oÀ«îÀ€ß­¬PYJ¿ÿÐÌÌ/†_2ÖBˆ$rc0x àW=ÖvŽ‘ÈZKD?þxj¯ÚŠ¢_¾û.ü饗¾+KFTÕ8Ž?ù䓲,§¦¦þÚëý föC 9ç~³°p~q1Ëó<ϽsE°+íÀ¤"Íæ©‡Š‹‚‰B<2óÃóóEQ¢SmÕëišÀÙóçëYfE5I’kׯ—ÖδZÇ›Mð"£€ffNž9“eY§ÓÙ/íÞû¢(ìPi­'ʳ¬( "r"VÕ‹€ ò<7D"¢"¶(œsÛ½Þ©S§ž~úéZ­&Ã@ôÞ›œôûÎ9W–ã‚:d³ªf‚Qú ­½ç7T¤÷L#"kíÂÂÂÅ‹÷¤w¿ßwÎÝÉdµ@DcL7AdU@$"cŒaDDdff®ÕjQX5J’ØQ’$ª1053U‘n·;1³1†ˆöøm@ "ív[œªyk½÷Ežonnn•ep™µ–™¿úê«®NµEƒÁþyíÚweEQ´µµåœ‰ÔÍSpÈ!i?r™ˆÈTÂ5Š„½DdDù^Õ!ª­p‰M×ëõ¹¹9f”===ýꫯ.//¿óÎ;[[[Á0Ƙ••ï}Ǻ'Ë€ˆFâ*ˆ 瘹V¯OOO£µŒ8×ÅÅÅ fnÕë“ ‹/6û}ã½0s·Û››3ƨªsnvv6IkíâââÆÆÏnmmUål—ËÂJ•ÎjTçœ"Q×<Ï­µ¨Z®¯Û$ñ››`¯^ÍM³©"Ì\–eQι`Ò±Á‹ˆív{}}½ÚL^¸paaaáý÷߯湵öÑGÕ;kê ˆ­V«1Ô²FYš«WÓ4=yòdd-©êôôô¡€¬µSSSÁÊ S³³¡ U ñÐn·«'G×(Ôãψ(ÌfNz=õ>|v €QTÔjâ\Øp\–í+®PùsÏä}ÑŒŒ'ªÇÒôïŸ}öçN'™‘ /QTÞ¼ùë¹¹s ¶r@°? }3C £ƒÆàÁB$Bc€ÙÄq'Ë®¿ø"ÏÏ{UAf]Z|ø!Uún!"å9u:T–A(H•º]LS:,†¨Û¥8FÊsP%õ>´ç^õ üÈ«NÕj—ËòÃ¥%Ï Ã8SUºqc¼@Áë×1ŽÝµkÇ%0ƒH¨ªZ~ )“äù¹¹Kß~KÓÓUÖîv»F#”Zû® :Îäädš¦_ln~àœû±"–ÎlµÎ:•*GDÖÖÖNŸ>-œ!ÁP2WWW§gfN?N¨*€Ü…`x€WT”DµW,“±1Dˆ½¢ˆó\™Mýàõ×'Z- Mj—_]øañÆ4Š;ð^B]Q± ã¨É_f #fYö£ ~Üï«÷8”gœµišójè[kFÑ=Kò¼ÞhÊÔI¿_k6)x§Ù¼Ýq€jmØçgé!bžùÞ{“ªþàÒXU;έfóÐ,kom­5ãOÓE˜úÄ»¢ËóÖùó³çÎm¿ývF4¾ê#¢»8&¢öØiHTfÙôü<¿üòív;ü¯#T["zpî|OUÓ;ë¡ ÎÇCÛv”¢øþ‡Tƒ¨¢öˆàŒæÎq_]Ç÷1þ´º`¶J©%tEXtdate:create2017-06-06T01:31:26+01:00ã‚à%tEXtdate:modify2017-06-06T01:31:26+01:00’O:\IEND®B`‚puzzles-20170606.272beef/icons/net-32d8.png0000644000175000017500000000205713115373736016766 0ustar simonsimon‰PNG  IHDR D¤ŠÆgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<PLTEäääêëëÛÛÛÖÑÑx33¡¡£££ÖÊÊÌÌÌ«¬¬œœœs**´­­¦ªªóòòÅÅų³³»²²»»»–šš222)((srróççóêêúó󎽜““hbbª¡¡…––.tt2tt&‰‰I……AƒƒAŒŒ1zz)aaDD÷·[……•••·ÈÈÁÊÊr››²ÃÃ’££t||LVVŽŽV‚‚̸¸üøø›¶¶]’’“±±UŽŽúïבּ±¹¯¯Ž¬¬Nzz}žžWWW¤³³AAA¾ÃÃc¤¤@——ââÿÿÞÞ®®ÉÉp''b……bŒŒ••ÊÊõõêê$qqIkkÔÔ‘ŽŽ~++ÿÿÿj‘äbKGDZ»¥¢tIMEá‹ß?IDAT8Ëu“‰vÒ@†g’&d¦s“I ¬VÑТUS´ZCQÚ ¥@[µøþ/â,l§þ!!“|ç¿KîB(ÅßFdë_â¡­¥Ç§¾y DôÃL•³1Ž Ã0L®¡ƒ~Ș`(iÛ1¥t=O3@½œ~Ì’tÃÞ™²LŸ>hÅüüèüK± ™ƒ†.¨$+_/¾Z5™ŒX$XV ÃpD+]^”4âq0A`/Ò>ä¹?ù¼Æ­~î{;×·"×søÇsDŒUˆk¥t0ƨEè@^ HÙÚË¡|}ó³usm;±å•M耴Ǔéôv\éo²ð`‚Éý‡É¶Ã€ÑìînÙÖÿr $‡"ÔÙw€ ÀYPe"P¡©Ãœ'âÇñÜ`?8N/F™;!Çnû ûÁ E0° à·àj®ÔÉ/–ËÞ½4Ó>`‹3×õÝDÔ¦¿–ÃÌ!rÃß½0…©F៧éôqé®CH#y¾ U[Ÿƒ©¬³xS›Ý>=,6"Î.I™Ì`p¿Z­x¶/p+¯.ªÌ¼QIñ¾ÐþÎך¬sµÒâÍ«+%W}ï>ÞhÙxN„ü)SOÚeºº%tEXtdate:create2017-06-06T01:31:26+01:00ã‚à%tEXtdate:modify2017-06-06T01:31:26+01:00’O:\IEND®B`‚puzzles-20170606.272beef/icons/net-32d4.png0000644000175000017500000000104013115373736016751 0ustar simonsimon‰PNG  IHDR TgÇgAMA† 1è–_PLTEÿÿÿÀÀÀ€€€€€€ÿÿf†bKGDˆHtIMEá‹ß?4IDAT(Ï-RA’ƒ0 ³›Ù{Œé Ý{¼w˜dûƒþ ÃÿŸ°rX˜ ‘%[@,’s–k 3M*jXTMµÆIˆ˜ØpšÌEœ…²ês3ƒ‘)éûmêÕýp¯Ûï»4´{«µµº}0Ä3q!žQ"„×&ÆigQw—Ð0à)ŠãŠW“´ç`4ÔPºâT$Ó—é3ìÄ<4¨ª ³ôV‚þ& F:Ï’á˜/¢$«Ñ°ýgÀVƒa–^Ÿ¢tõ!Î醆Ҁ«\.°ute¢ÉÐp„ˆ\ÅÀ½cZG‰0 Ý¢1‹|U?=†?Pk>O‰õŽkëÀ%êˆið˜v”×Wã-Œ…ï'Ýaa£°¶Óò³<×e]°×uyPüwüÂùw¾=@_‹@O%tEXtdate:create2017-06-06T01:31:26+01:00ã‚à%tEXtdate:modify2017-06-06T01:31:26+01:00’O:\IEND®B`‚puzzles-20170606.272beef/icons/net-32d24.png0000644000175000017500000000341013115373736017036 0ustar simonsimon‰PNG  IHDR üí£gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEá‹ß? IDATHÇ•VKoÇ®GÏcÅ%ER” ˆ$ˆ$„Šˆ¹†l ŽŸ#Çœ ÃWC¿ÀÈoÈAF. $ÈÅ!‡<àƒÊ%°‘H‰ RÒŽ¹"Å]r¹³»ó詪Z»\’bâÔ¡w¶»çûªë«ªilµZ@Ρcˆfvôá¸WÌLUÀ…?ÃÝ]aÆcv×uUÕ̘9¼ÅÌaþ(:5 p.Š:››¿z÷Ýï|ðA¬#ï‚©*-//«*"Öu-"I’¨jÇkkkN'I’±«ªºuëÖÔÔ”DSõy~bj*eÖ‰S#¢ˆ0óùóçE$@ b8~š¦Ýnw04›Í8ŽÇ¯”e)"Á9Dtc0›´Ñ!ÄÌÌŠª Tˆªº&çžmmýü£‘™ýþÞyçæë¯ïeYpÈÃöâ fŽTC¤€f£HˆÌ@˜U5¢&bI”Ń€™EäçÏ碨o0ݤ8j–2ÿ}só·kk±ˆfîñc33Lˆ"Ë2 "¢¬×«T«v;¨D"òû¯¿þËgŸEUõë›7ñ¤D:Óˆ?¾|¹W× JD×®_¯ëz¶ÑøÝÇ77úöÛ¢H“äŸOŸîeYçĉÇ"@Ìpm~þ‡W®ì¶Ûdf‡^Ä]uiffåܹNY‚*3¿±¼\y?7=ý´Ý~žç7¯]ëdYóĉ٪Ún·ÛQ´¸¸4èõzWo,.¶ˆ‚Œû82@,E†U•{ª¬Ú/Šª®QTx_‰ø¢”%0çuÝËó¹……»wï†ÔbfUmïíù‘¨nï=yP€²,+ï ç¼÷"REY–ŽÈ{_!Šˆs.I’,Ë‚—UUM ªê`0ˆˆœs•÷eÙ`¤ÁÖæfU×y¯·Ûë Ëòß­ÖNQ¤qœçùÒÒREI’óìô¾ùÆÅ±áË)^à:GDfæ^º=}éܹPn/Ï"h2/„:d†(šc"²Q ŽQ;=5µ¶µõ‹·Þ‚•. é÷ßûøãï™éh§;Šž0ÿ¹Ý¶/¾¨b‘çIšâ‘m„˜çycc£×jÑíۈȆ˜3Lœõ Dn.. ÀPäV¹F˜ÔƒR @ÄZäÌÌÌ{ssã™ÙÙÙ£"s»Ý>½°°63óǧO!I ,¡ß‡²„‰Ín Dˆ¡á¨jw”ˆ¸W×àýáœ1g"6L9ó³õu\[D™_ZÊU#¢jV„œ9è&"z¯zˆÀÌÑ«V"q/^¼ˆ`†ˆÞû¡÷¥Hr&7›MÄ~èâøhA…ËÝK5U"ƒn¢Š$ÍæíÕUCÄÖÆ1÷ƒrt;lá¾õR;fɈhf~]Üt³yòäÉc/ãÿ§!€™ÕÞÀ¶ÝËeš5ÈÜ%tEXtdate:create2017-06-06T01:31:26+01:00ã‚à%tEXtdate:modify2017-06-06T01:31:26+01:00’O:\IEND®B`‚puzzles-20170606.272beef/icons/net-16d8.png0000644000175000017500000000202013115373736016756 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<þPLTEåääÝÛÛÝÞÞÝÝÝÜÜÜÞÞÞååå×ËË–zz­²²«ªª­¬¬°¯¯ÝÜÜÜÛÛàßßµ´´­­­®­­ÕÈÈ’tt°´´ª©©Ÿ¤¤¤©©ÖÜÜÞááØÝݳ¸¸VXXFHH§¬¬ÛÛÛ²µµ^††a‡‡h‹‹Œ¬¬s¡¡k­­r™™,<<))s––ÙÛÛ“uu®´´fˆˆ±­­´±±øðð¹Ë˦¾¾ýõõ½ºº€]^^zyy²¯¯ÕÉÉŽpp¦««_ƒƒ¡¢¢£¥¥àÛÛ±½½Ÿ³³äßß°²²½½½¦¦¦¹¹¹²³³’ssc††¨¨¨¯¯¯ßÞÞ³³r««àÞÞÖÖÖïï‡ÙÙÙààà“tt®³³d‡‡¨©©¸´´¾ÎÎîîÝÙÙíî‰©ªªÁÏÏÛÛîïïÚÚÚ‘ss«°°b……§§§ßßßÕÓÓÓÓÓìí톉‰ÖØØpp`ƒƒ¥¥¥¡¡¡´´´³³³¯®®¦§§¶¯¯§’’²¨¨®¯¯”uu¯´´c‡‡¬¬¬©©©§©©«¡¡h££(ÊÊX¨¨°¦¦ÜÞÞ_……aˆˆfzz-¦¦ÿÿ3ÁÁ´¡¡ÛààÔÈÈ”xx²½½«²²¬ªªzªªBÀÀl¬¬²°°ÚÑÑŒ]]“vvštt mmšpp–{{ÞÛÛæççÔÇÇÓÈÈÑÊÊÒÈÈÿÿÿæxÑ€bKGD©'tIMEá‹ß?IDATÓc``dbÉÌÊÆÀÎÁÉÅÍÃËËÇ/À%È-ÄÊ ,"*&.!)%%-#+'¯ PRVQUS×ÐÔÒÖÑÕÓg60426153·°´²¶±ef°³wptrvqus÷ðôòöaföåôó  ˆ DEÇÄÆÅ'$Ä'&%G0³ cRâRÓÒRÓ“3X™YÙ9‚¹yy¹ù…EÌ@C‹JJËË+*«ªkjë€fÔ746•æ¤4·´¶µwtv1Øùúu—dÇÄôôöõO˜8‰aò”©> Y†ÑӦϘ9kvܹó|ë‹3£¢|íç/X¸h1Ã’9Kí&Û ݲå+Ø%FI‘¼º³:%tEXtdate:create2017-06-06T01:31:26+01:00ã‚à%tEXtdate:modify2017-06-06T01:31:26+01:00’O:\IEND®B`‚puzzles-20170606.272beef/icons/net-16d4.png0000644000175000017500000000050713115373736016762 0ustar simonsimon‰PNG  IHDRíÝâRgAMA† 1è–_PLTEÀÀÀÿÿÿ€€€€€ÿÿl ðbKGDÿ-ÞtIMEá‹ß?^IDAT×Á À0mKý£N@éUÈytÿYj@"qÇAÒNd\’ŸzZT­ûM¨š”…Ò–dù œÊcÓÔ䨑C@^l³ÓÜ¥êãÖÿ†VçLµqvó ÷ωÒ%tEXtdate:create2017-06-06T01:31:26+01:00ã‚à%tEXtdate:modify2017-06-06T01:31:26+01:00’O:\IEND®B`‚puzzles-20170606.272beef/icons/net-16d24.png0000644000175000017500000000236413115373736017047 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<ÖPLTEåääÝÛÛÝÞÞÝÝÝÝÝÝÝÝÝÝÝÝÜÜÜÜÜÜÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÞÞÞååå×ËË–zz­²²«ªª­¬¬°¯¯ÝÜÜÝÜÜÜÛÛàßßµ´´«ªª­­­­¬¬®­­ÞÞÞÕÈÈ’tt°´´ª©©Ÿ¤¤¤©©ÖÜÜÞááÞááØÝݳ¸¸VXXFHH§¬¬ÛÛÛÕÈÈ’tt²µµ^††a‡‡h‹‹Œ¬¬s¡¡k­­r™™,<<))s––ÙÛÛÕÈÈ“uu®´´fˆˆ±­­´±±øðð¹Ë˦¾¾ýõõ½ºº€]^^zyy²¯¯ÝÝÝÕÉÉŽpp¦««_ƒƒ¡¢¢£¥¥àÛÛ±½½Ÿ³³äßß°²²½½½¦¦¦¹¹¹²³³ÝÝÝÕÈÈ’ss­²²c††¨¨¨¯¯¯ßÞÞ³³r««àÞÞÖÖÖïï‡ÙÙÙàààÝÝÝÕÈÈ“tt®³³d‡‡¨©©¸´´¾ÎÎîîîî¾ÎÎÝÙÙíî‰ÙÙÙÝÝÝÜÜÜÕÈÈ“tt®´´d‡‡©ªª¸´´ÁÏÏÛÛÛÛÁÏÏÝÙÙîï‰ÚÚÚÞÞÞÜÜÜÕÈÈ‘ss«°°b……§§§­­­ßßßÕÓÓÕÓÓßßßÓÓÓìí톉‰ÖØØÝÝÝÝÝÝÕÉÉpp¦««`ƒƒ¥¥¥¡¡¡­­­´´´³³³¯®®¦§§¶¯¯§’’²¨¨®¯¯ÝÝÝÕÈÈ”uu¯´´c‡‡¬¬¬¥¥¥§§§©ªª©©©§©©«¡¡h££(ÊÊX¨¨°¦¦ÜÞÞÕÉÉ’ss²³³fˆˆ_……d‡‡aˆˆfzz-¦¦ÿÿ3ÁÁ´¡¡ÛààÔÈÈ”xx²½½²³³¯´´®´´«²²¬ªªzªªBÀÀl¬¬²°°ÜÞÞÚÑÑŒ]]“vv”uu’ssŽppštt mmšpp–{{ÞÛÛæççÔÇÇÔÈÈÕÈÈÕÈÈÕÈÈÕÉÉÓÈÈÑÊÊÒÈÈ×ËËåääÿÿÿX/4bKGDñB¿ßÂtIMEá‹ß?IDATÓïþ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄ£“ÅsÆÇÈÉÊËÌÍÎÏÐÑ¢’ÒrÓÔÕÖרÙÚÛÜÁÝ¡‘qÞßàáâãäåÚæÀç èéêëìíîïðvEy÷Y ã²%tEXtdate:create2017-06-06T01:31:26+01:00ã‚à%tEXtdate:modify2017-06-06T01:31:26+01:00’O:\IEND®B`‚puzzles-20170606.272beef/icons/mines-web.png0000644000175000017500000005540413115373721017406 0ustar simonsimon‰PNG  IHDR––³cæµgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEá  ºØZIDATxÚí}w|œÅµö™™·ì»MÍ*–{Û ÆØ¸€ÁÆ—Þ1„@(&á#tI¸„^’Ð!”›n°1îÝ’«$Ë–m¹©Ø*V×jûÛg¾?FZ­VÒJp¹7—ÜÌü°öÙÙ™9SΜçœ3¨®®þ]~Èÿ³ðïò_-Bü?cŒ±v“þ]’„B(þ/"dŒ ‚ Šâ¿¥ø¿¶ „lÛ6 #^Ší"äòkmmmll$„üËK1a"ÿ BȲ,—Ë5lØ0˲b]è¡(Š………Š¢0ÆúßÉ"Ø4MJiðß¶ ÐïùñÀN§sÖ¬Y M겑BEq:¦iÆË9IABLÓüÞÁ ‚eYý¾þƒcƒ–$©Ï͆I?U„o ÆC‡lú,c]×§L™2dÈÆÆFþÝöŽ'ÔË3M3%%%##£O)"„4M …BÙÙÙÌ ±/Å7!d†ßï>|¸mÛ! B€€cŒþO°m»µµ5''§?`ÆXSSÓСCÚ×ÞÞŽŽfY–5gΗ˕|…ñO[[[ù´îS$¡¶¶6A<OÀ@RRRú³Ð#‘H(ÊÉÉÑu=á#!áß|ÃÍÈÈ8í´Ó4MK^5?>Oœ81iÒ$UUB‚eöøoBB¡Ð‘#GN;í4]×1Ƹ0(£! &5ù¬Äkš¶ÿþ‰&¦‘"c`~ÈG"‘ &PJùBÀP L¥`ÛL)•eÙ0Œ@ €1n¯„R`ŒÉ2E¤iÀÆØ0Œ 6\pÁN§³©©)¦% JR&ËL–‘ªc¼Ú 6œsÎ9§W°¦¥\«Ü¸qã„ RRRš››c« 1¶Í$‰910ÆxëÖ­C† ÉÉÉiï`Ƥ¨iZDh†mÛªªF£šËœ²hQjuµ¨ªèÌ3Õ>:iš€qêºN)U5Õ2¬¨ý¼âóUÕ«*• ؘ”1?÷ÓK‡]j3:ö ¶-[§úW•_}sâ›ò@¹E­‘Þ‘7½éš‘×ÄDH)¥”jšFmÁûÅiï¼#66‚e™C†„çÏo»ývêv#Û„lÛæKAÓ4BØ60FÝneR]››­Q£€$ŠÍÍÍõõõ|ËÕ4Mf.s»Im-®¯·GŽd„„øýþšššY³f@°ÓÉÜn\_Ojjì#˜(Œ£ÑhUUÕgœ|B#Æ€R¦(4%…46’ýûí¡C™¢`˲Ž?>|øðž¥Ðã_QG‰ßs»Œq €e™mØà©¨³²ì@@ˆD„Øç¼ÎöÚ8Ge¸ò­}oaO0±Â_±·aoIS Âè†Q7ø vL¨«êê@;í4&I8ílcÌáðüú×ÊçŸ#U„˜,ƒ®CãE)s¹\Ï?ïúë_Q$,3ÓÆzXŒ1ÇõÖ[î×^Cá0€$1Æiò‘J„{<Ê¢EžçžÃÁ 0’ÄBÝÔ–ÿv2†0UÅCôd(jEmf§ÉiŸ”}²§iâV.z1Ä€u«–j3;UN]Z¹t{ývâ$— ¿LÀB`˲e9óÍ7Ó>ø€‚l;rÁ¾Ÿÿ‡Ã,þ\@©jàÙgÕ+®p¬_/oÝ*> =¶aŒÂáÐo~£ÍŸïX·NÞºUÜ¿!=àBÁ`ø—¿ÔÏ;ϱfœ—''Ñ)p ½õVcêT– Ñ·1­|o"ìh|ç¾ÂõA~ÍèaP€!„¼¢÷‹Ê/~»í·–i==ëéssÎ ™¡„…Ø”"¥¬®YýXÞc‘hä7Ó3oȼ ìŒ1‡Ã—\b (VUy—-snÛ–öþû­÷ßC!è8®¸ÊŠ0ÖçÎÕæÏŽq•–6¼ü²çða‚qLĘ1s¦~Á¤¬ÌUZÚü曎;DBhO`°mãì³õY³He¥ëàÁÖ¿þUX»V!Äì>m›§ŸnLŸNNœp<øì3ºd‰c£cþ½1\x„€(2>J(‚ÐÓ$aŒ HPˆòÁáîÏ»cüö…oß6î6‹Z%6‰#ˆ8Eç'åŸÜ³ùžˆyéü—î=í^Êh"˜‚À%:}zÛ]wÕ¿ý¶ÿ–[axV¯kk™$uŸà(Ä>Ÿ6hxË-/}öHËêÍlÃP8Œ[[õ¬,ñ¦›>œ={@@èqí"„¢QÜÒb¤§“ –Ο? @f,Qäü UUÜÜl¦¤ ë®Û|å•Ã8»ƒ»•ïy# ‡±¦!MC@)ø|„Rp¹hw5ÂbÖ›ûßüãÞ?Ê‚üÐY‘qÆÞ–½Ñ“©d&Èo­9ô—犞cÀžüðÌœ™%-%NÁ™åÌê¢û0Føýž¯¿Ö'L°ÓӅ𩬠xkºm!ÀwW¤i2€àpD\.W8î~ƒX×’¢€Ëí†^4ÆÕ<Ãppã€âvc„’ƒÝ–åv:ÀávŒ{lF|ùÞV¡eAZšýæ›éçŸ?â£RààAÇ¥—}àœP c¬)PqT+ÿ~ðï`òNé;—¯ºüÊÕW¾¼ïe›ÙñRaŒIXª‹Ô}xàCK·D$.:¶ˆƒ_ô{ÝÖ1ÂÇ!cLH óÐCƒ,ü£ »ür÷ºu™;×2$A)å“Éãñ¸ÝnA’–-[¶{÷n+V(Šâv»úˆr»ÝGV”U«Vmܸ–/_.ŠbVœÎõë×/ÿúkøæ›oc^¯Å ’¯y—Ëåñxœn÷ÖmÛ>ýäX¹b…®ë©©©1ûï¸]E£Øí¦#FƒYªŠ £ÝêÖ©o¢ŒJX‘>bØ€a™®LʨSp*‚"1±N@ ˜ˆÅáiÇf ÍqçPFAQE"R÷ ð23[|Ð3†’ž7¯þÏn½÷^¬ª§ÎĬ‰Ë—/¿í¶ÛF}õÕWïٳǦô¦›nš4iÒ§Ÿ~¿¡RJmÛ^»víÂ… G}饗æçç#„îºë®SO=õƒ>ˆe¾t6oÞüË_þrìØ±]tÑê5kB>øà˜1c^ýõ{$nAܾ}ûÃ?|Ê)§Ì™3gÉ—_"„~÷ä“£Fzî¹ç4MK"ÅムÆÛsc‚Àš›ÉSO5>÷\¥ˆR@0f”"UE¦ Ü —ŠažaË.^Æ…Ô~÷d2S³4ŒrÜ,`R3SÉüô¢OùêlÿÅ,ÍÒø‰H~ QJe¹õþû[z¨ÓÆF)Òõö6ulzc—Ë¥iÚæÍ›%IºöÚkAˆÙ©£ÑèÁƒg̘³K(Š‚Ú²e‹mÛW]u!$fBSUõСC]tQl E‘e9///‰\vÙeñ5ëº^VVfš¦Ð¡&Ȳìv»wìØÑÚÚúÿññ5†qâĉH$’„ÇíÕ:#‚ I¬3œb$„ „DQ´, clš`‰*(Æ€1ã-³m›Ã°ê^-—ÇX–Å»mS;l‡{3ƸÍLJ)£›*Ç­¦½Ã·µµmß¾n¿ývÔí|â9pà_O†aìٳǶí[o½5&§˜yƒËÊʸÅ4ÍÂÂB]ׯ¹æÞ¤„šàرcš¦ñ¿”––rI_sÍ51pÌöª¯¯7 #fúé[„œhmmM`‡»BH04 £¥¥¥O0ÆXUU¯×ËMŽIv†vkÆ^¯WÅØõfŒÉ²Ìkmm…~Ƙßïß·o_[[B¨¹¹¹ÇÊB’$åææúýþíÛ·WTT „JKK{«ÖápX–¥ªê¾}ûššš0Æ>Ÿ¯·f˲œ““cYÖ† öïß:räHo¦,Ëœàì—9é …Nœ8ÑÎòt×Â㦳aÑh4îáVߦ”:ŽK.¹¤?CŒjllœ?~oS/ÜÔÔ¤ëzMMM× ¦íÇ·Ù4Í1cÆ\xá…ý!›¢ÑèÒ¥KeY;vlû_{6´› T—Ë5zôè)S¦ôY³mÛË—/×4mܸqñµÆý{¼\½ê^md“išÙÙÙœ?"˜HXâë€2 ”Qƒ'ú[ZZNœ8qÎ9稪Š1f’Ô~+d CŒ!ÃàÚ<Ÿ ª*·Ã8$Ë|F0Bˆßïß±cǵ×^kÛv8NK`ÌÁãH$²eË„ÐÔ©Sc|2סd™ðA1MJ©Ûí¶,‹“M±¿c ŠLaĆbûöí‘HdæÌ™|6#B° @œµmÚ·,+--1Æ×w—šIRûh@QQÑÉ“'çÍ›çr¹øAÀ›-˄ղ¨m³XÍ è—c_ˆF£–a5MK+—n®Û\ª°0!}§Þqf智­#@–eµ“MѨ¦ë˜±Ô·Þò,_.´¶2Q4FŒÞpCèâ‹'w¸ ÈD"cfÛ€óx!RS¦I33©e)ŠRVVÖÒÒ"Šb8‡Ã!ŒWâñ!¸®©*ÍÎf–åP”ãÇ766fgg«ª#î1FѨõÀÛ÷îmÉÊR^}æèÑ)†A1F¶móã3‰´×Ìs¹@–qSììlƘ$IõõõÕÕÕn·[UUŒv8N|ùeÁO.5 @ÈÖ´‘×^{Î3Ϙ¡"IJ,J)c,‰`ŒRÄù#§û|¤¹ÙÎÌA …#‘²²2A8áÅ÷0Û¦.—øì³…Ÿ}VaYô‰'κúꑚfcŒ,ËêÍ'¡Wu†!æÛš¶½RôŠËéÊqåTû«×´­Ùݰûosÿvæ€3ÃV8F6a„ @À»fX_o $VWKÛ¶¹·m«ãà5×@€vÐ%íÄ(Ò´4¤iba¡XTäúðCšÝ¼iihàŠO;cBšš –%‹EEÎE‹cM»v!ŸS<±šÛ7 Ê\.éwJ7o®lÛ¶,Î2±Ž@0!Ô댥ÄÂBeéRqÿþ¦’*ÝkÆ[ª …¼¢Ó ¥XÚ?‹ã!cêr,‹GJòúõʲeM»vÅÈ&®vÆj¶m–’"çåÕðA©ªZv4jó6Çsvý!th홎Ì_Oûõ¹9çt ÜÙ°ó¡µÛv5ì:3óL¾—ÆdŒ1EiúýïíŒ +3Sª¬tÛmBCƒT^žháö¤¶6çgŸÉ›6É;wâÆF0²²øöÛå¸áÿ…œË–É6H;wrJÈ:õTèYÛf.—°kWÃ{ï7.§®.B)`Ü­ÿ¼f]wlÜèX»VÞ±ƒTTõzcvÞî÷“Ÿœzç¶®¥X’,UE]UwƳ,yëVÇêÕòöíW‚X§ "¡rJ™(bŸOþù=n·#7Wª¨h%¤F½}€Öm}LʘÉ&óóï’a—ü¾è÷a#„ù>ó%I=óLâóŸOªªÂÑ(#G'/bR$©jÚwˆÈ0€æt¢x¨[Íi÷Ü#mÙ‚ 0fŠ‚T•õ2%)QÄѨõä“E™™Î‡:ýÿý¿|QìI'bŒ)Š÷Á•Ï>CšÖI6%-Œ1 P±tiõêÕRZÚÐùóÇþä'!ÖqédÛÌëu?÷œûõ×{ ›z)yíµý%%MùË…ï¼S Чq´/òæLBfˆ1–"§üýèßO†Nð˜•;‹2Ê©†N0Bȶ‘mçÞ}·sçNÀ(m[¸0tÕU8d„@œ:Á¥íÝwkÖÈ›6I¸¥PoÀØÿÚkòúõò† rA®¯çO2¯¿~èÀº?¾L–±aPY&\¥HœªüÏÿÔÏ?ß±v­´k9qz!›Ú¿`éº {½ºßï;~üdq±¯´t櫯RÛŽÐ!(ŠÜ}·qæ™ÊªUÒÎÂÑ£Ic (BQQók¯í½í¶‰³få¾üò¾˜7ÏI„!›Ùa§è\tlÑS;žðÔô§Æ§ZÑî, Ó .X q†|ð kÇ÷Š‘Y³"çG"‘Æœ¾ûîÈO*íÞíØ³Ç÷‡? èÍ9‘1šš¹í¶èÍ7‹……Jq±ï…˜&˜%A–ÉÁƒ¾_Ü{Ûm§_ý¨åËóÎã% †Ý¹áñÍßåR¯½V½öZaß>gqqÛÛo§VVöL6!d›fÎ9çÌýÛßRÇÄxóÍÒ¿ÿýä¶m-{÷fžu–ÝqUoŸy’¤Ï«]r‰p賨(ôÉ'μ<ÒÙ„èºýÛßî7nÀOLÁ˜oûLQˆÓ)jšÖÛôæ%™”1&bQÂÒk^{lÛcn‡û½¹ï];òZƒÝ)!Ä“$êt®»®å׿®ýøãè9çˆ'Oz—.ŪʺYymcŸiZtútöÄ× rµ¦¥ôLÔQŠÛÚP$=ë,üØcwŽ{~4ê°»÷£Š ?cêŠU#F,¾óÎ-”‚®Ûsæ|ýÉ'e©©²e±„šQ €uÜ8á¾û^<÷Ü1¦I{3„µ¬ô‰G\u•cÀ€”±cG\y¥$Iv(©«ÃÝ `Œ¡H·¶êƒã»ïþòŠ+ÔÈ]qŒ à††h]] ²2pþù_OúeEE!ù‘GvÞqÇf¯WâW‹ï"B„nëÏ?ÿRáK©Jê“çù¤fÝ:3 WW׬[gq»]¹¹Ô²ºK!D1fѨ‹1Éí¶n7 ]kf Aǧ§¥94ÍŠ ~7'›žK¯©Íl—àÚX·ñ¥ÿðÞxeß+a3|˸[î™xE-Öõ¶¬ìÛ—óÀƘ1Ôë++I[D.¼z<$N`y!², ‚à÷û?ûì³€ßo™fIIɨQ£ ›*ˆ1v8‚ „B¡eË–Õâápxýúõ_|ñÅÖ­[ƒÁ 7N™2eΜ9O>ù¤ ñ¦dMÓ¶nݺdÉ’M›6ùý~n˘1cÆŒ3ž|òI·ÛÏ™8¨Q^ÛfTSÉÌt:âˆ^GTU+v»àt˲¶oß¾téÒU«V577sèŠ+®˜4iÒO[’$n"§”†B¡Í›7/X° ~ÕÚ6³, >Ÿ6aBÚÎ×€eQMë"?„ËåRUuñâÅmmm“&M’$‰_·)¥Ñhtýúõ&Lˆ›ÐŒ :ÿüAsæÄ¦Â˜Yíˆ\ˆ5ÃápH’´dÉ’òòòqãÆMœ8‘OJîR¼qãÆ™3g ‚`Æ Ž®Û±å°hÑ\~Á ‡Í˜má[ˆ÷·šRJ{¿ p$?68w™°“ð¡J¨6 –––:ŽçŸ>k¨eYÇŽs8\\\,IÒ“O>‰âªŠmÛ>tè $au‚@b!ápxïÞ½Œ±G}4fU‰¯™RZ^^ÎY=nmaŒÅwÿ<·ò@Ì܃1o’®ë·ß~{ŒLˆc:yò$Øf/#Ûîs ½æ "ŒuÏápÄ›—z+üˆr8ñ&±Þ ¥TQ”ÚÚÚ7rV¨7£gyœNgKKKaaa}}}ŸàÔÔTÆX(j'Lºö?¾wüÍÍÍ;vì8~ü87'¡„øaÆMí½qRqCo’’ÎI%©YE‡Ã!Š¢(ŠÉ]æc?!½XCyº>¾¥¥¥………#GŽ¼êª«úW×ÔÔ4`À€>Ák«®®^·n]ZZZl'ìÞV^?K.¹äY–ûS³Ïç[±b…ÓéìÜÐ*shGùý~·Û-Š"3`1(veân·»“-‰×ŠwæÀûý~NÙ'¯™;JΜ9sذa¼³É»FyÄ™®ë---½§Å—H$Ò9£ùˆp¯B½Á˜ õõõ¼êª«øt¡W€‡9Ù6ßâÀæÍ›ÓÒÒf̘F%IŠ©!<®x„ ÿ„?â1S=× €Ò4mË–-0}út~ºY&Ä®wÙšfi'Œ0Æ»wïž2e ~÷%˜eÔ¤¦në1Š¢¸k×®I“&ɲÌ(e¢HŽv±QŠ,+æÒÁ Ñ]»vrÊ)n·Û¶m‘ˆ–$ʨE-ÝÖ)PÔ¾Ûœ? …BäCMtDÕ€ ;wîLOOŸ_¼öŒcŸyƱj•¼q£¸?nkë£WŒ™º.X¡P°ªJÛ³§rÍš)=4éÁÍ`o­±¡ÁSF[Ô·èÞÛ¼wóÉÍ@`vîì49ͯûqW2²m*Š©û[öãs6M?唦ßÿ¾»8ÆÄµh-â¨U/?±¦gO䤚jç6C…Ôk¯µTV¬ŠŠÈñã¨/µ"Œ­ÓN LJZZä…Ý»õwßuQÚÛmÃ:å”àäɸ­MÞ¼YÚ½[}ã OÚ]ŠÜ¿}Û¶m6l$馛nRU5ÁeûñÛC‡†x ²p¡”Ÿïص+òöÛ^Ó„û‰µ¬!^˜=eJú„ V4ºçÙgoÙRùÍ7#¯¹Æ9p m ²™í•¼Õáꇶ=t¨öÐeã/»kÂ]a#LP¢¡€aŒtÝ7.ðã“æfç¶mbm­gÙ2ß½÷öà> `3Û-¸fà·»~»ùØæ)æ_º,W‹b(ö fL„ÚÚÚåË—À‚ DQì5Š!†±Íø|.€V‡ãÆnEénþÀ„˜ÑhÅ_´””PÃ8Ѹs§ x½Ž´4jYñk…GkloØ~Ç–;Ž4Y0qÁã“áV­µÇ6€m+»w‹558$¡ŽDøô"¡PB´ˆX<Üvø®-wm¯Ú>gôœgÎynˆ6ÐÞ„‚1EÈŽD<º.y½Aìra€>SõîþÔ¡ÓK’¤(ŠÏç[²d A¨¶ºº¡±1++«ûps°ÃáK—.µt½¥©©º¦&;;»;˜1æp8>ýôÓP(tÖYgM™2¥Ç%óEæ–Ó‘iÆvÆcdÛ¹wÞIÝncÌÒÖ&8Ú„ ú©§"]Oа0Âoxë`ýA¡Ym¾7ÿ^ÍÖR¤”§¦>56e¬A÷HQeY&„./߸~=L˜0c õ¹Ð·ù G"‘­[·~ñÅ»wïnhh°(Ý´eËi'Þpà <ð@|tcLUÕ;v,Y²dûöí< `ÏÞ½§OštõÕW?òÈ#ñ6F¾¹UåÊ+¯8p`‚"Còø£ýû÷õÕW›6mª­­ådÛ´iÓæÏŸÿØcuZ·b¦)¦¤œqß}Ÿ^¿c5ÍôÑ£G]wݘ›n¢|8ÿmÃ0òóó'OžJ’ÔÛÀBa1Ü‚~ã7ò–¼´´´x<žë¯¿¾76+¾477{½Þ>ù#^ÚÚÚx$TòfÄ“M<Ê øÚ¥_£¦iš]tQFFFòðš¹0> Ò´íÎl3„tQbBáp¸¼¼ÞŠÁ€1W\qŸ¤ùë¸BÄ&ÎÑhtûöí—\r o}§*Ä» žêI~~>tM@p:§³òd ²¢Q³C¥”¦¤¤PJ9»ÒÙ ¾%rÒ ãÀÞ½{·ßïŸ;w.ƘRFs:™(¶¯­PÇôhN6íÞ½{ܸqn·Û¶)!àtRA`\‹ …p,“«#FŒÈÈÈ0Mcà5s0O<Û;cÌÔ·a8NâÍS¥¨¨ˆo¶áp˜+qSSÀ4 Ù6#„Qª(ÊÞ½{@UÕ.ü‘¢! ªÈ¶Þ·ýû÷×ÔÔðÈ&ŸÏ×`ŠÂ…BȲxÍœlª¬¬ÌÊÊ2 Ã2MÁá(ýë_}ô‘èñ0ÓäLŘ›oûã"„ïW¦i¶µµÅÒè1Yf’„t™&`ÌxŽÝC‡¹\.Ã00&„к:aÉ’”Fˆ=ùdóøñz4Š0æ!p&w©2M Àòù„/¿ôîÝëðû‰mÃcµœsN”‡Úq0o†®”šÑ(ùàïž=Jk+1 ¸ÿþÖ /Œƒ˜öiÚÛ^š”l"¤·#”ëÁ1õ"ðXž´4dšäøqñÀ÷k¯YãÆùþö7\Wcš #X‰`L32€RñÄ ¡´ÔýöÛÔãñ}ù%ijŠçÚÉ&„hZ $VW ‡¹>øE£-«VßÇ Æ8X]]]Zê>K(cƒ/¼ Ä¥'çœAˆy½L’„ÚZáèQå³Ï¤¢¢–)! 5 ‡JK•?þq€¢0Nô>Qì\K Y†ãÇ¥çŸÏ”eƳ{¶¶ ¢ˆ0ÏÑOIª¨ÿð‡,¾[[jhÉr„ƒã™©o!‚ˆõöi‚H! À±j•”—§|ó ©ª;'§»¶Í!ò† òÖ­Ž•+…²20Î=—uhœ]šÀ$IÊÏ—·nUV­âQBwì%‹ "À”ÇvñÅ–ªZª*§¦šá0N ›cŠ"ìÛÇÓJ»wC|dSbô=˜&9Òx饆´4zï½9š†¹C÷±åÉ?´^x¡qà@ëþûs|>’$ ±mCzºýüóC‡š>š][+ÊrŸ gúaJ"Ùtçbq1Òu $Yü!HUÓ.”¶oGšÖÉõø<²ég?“7nDÑ(`Ìd¹»)¤ÇR½fMÓîÝrzúðË/púéV4Úe°)eŠâ}ì1åÓOq($±øã¿k:B`hÄcòdmß>ƒéQ$qÊ͵n¿½­¢BjwìE~|rddØ·ßÞV_ÿ­%ò=e²,êõŸxBùúkiÛ6¡²’Ç:÷<ë(e²züqÇ×_Ë[· œlëu½czè!sìXÇæÍBY÷¢,)Ùd TVÖ š”–}úéÙO<1áî»`Åç`ÓõÈw؃9Ö®ŽÁmm¨Óy¼[[‰®÷1øÒ4MðùÏ…•¼ðTÊ­­DUñ·}àûK£Gˆ9mš>{6ijr¬Z%íÚe-^,õF6!džy¦1möùä5kä;¬¿ýMî)ô‚‡uÚi¡³Î ?ø ¼~½cÛ6ó£–•„lÊ=÷Ü´1c2'O6B¡½/¼P½kWÙ’%Ã.½Ô‘•ÅbÞ·!JíQ£Â>¾çyËeËsÙ2¥µñê—±N¸$¡ÖyJ®^úÔ˜«Ãq€~…ˆ~ÙŸCš†ÛژúõVõ/¹Ìãy\×Óë9XIÓßÏ!tãÖühذ»U5¥·È&]G„®¼’¾÷ÞÏÇÿQ4êîl²ía—\rêm·¹‡ 2oÞè D­±1|ò$éÄB†‚A¤ëá9sà7^¼à‚Ùš–üåÔ)J‚ŽOPÞõRØsͱÉÿÿÉË÷™À‹u0S¨©)Ãá(•¤C‚à£Gà B !Û² ©É‹q¹Ã±c·$™IÀ¶ÍZZÜÕŠRˆK–»“Mˆ+­^³Æ_VÆ,+Z_ßZRb—Köz™mwµw1>ùmÆlŸÏ ÐæñìPœN^sRn°v»ÝáHdÃÆ¶®û}¾æææœìì)CI’xTöüüH0ˆl»¶¶–'Ôé~ˆŠ¢èJM5 £  À×ÔdÆñãÇsssùU¬s±5mÛƒYΙ6M­¯¯/,´Íœ™2vl{P|WUâñxXJÊÁƒ+ŽC‡žÿü󬬬ٳgWVVrpzzzIIÉÃ? …TUœ––öþûïóä{ñ”wˆ>zô¨$I ªjEE… ï¼óNw0ÏYYYɳ¯išvôèQBÈ믿ÞøÄ‰]2Æl[àñ1Ji×¼æü³,«¼¼œ1öôÓOóœ±í!Fc¾™i'Œ_8Ö.ŒaÀ€DAñRú6Áiœ‹immÍÏÏommí3\#77·­­-??¿±±‘Û…{#n!ééé~¿Û¶mµµµ}‚=OVXYY™ÌãƒbLd{Gâãc‘!Ô4mÇŽ<þ¨Ë·^´ÎÄÉ(å§`b¢ˆ; ♣ý)ÛÌ“ƒ“tz‹lºâŠ+TUíóa*"äñx(¥}>|ÈóGòP˜>™©o&„ø|>I’¼^or$—Ÿªª+V¬‡Ã±ÐT^,«Ý`Àó9A\Œ±Ûínÿ 0Êx<%ãD<³Ïɦ„#&IC¡@ïsè¢ÑèÔ©SO9垤²ïÈ&Œ±(Š ±z cÁ®¤¤ä¢‹.âvô$`Œq0ܳgßMòxZÌE¿¨¨è /E‘ûwÇ>î4Jò¼v麾gÏžY³f!„¢ñN=q³Œ±;v¹sç&X!½^I– cÌï7xœ0lânH²,SJE,*‚"b#l3;jE5K‹Õ,ËraaáØ±cydSòÉäp8öìÙ3tèÐôôôäo¾ñmŸŸÓß‚lòûý<Ã[²içÎ~¿‚Á`$é ÌÝï‹ŠŠª««B¡P( &©Ùápl{û(™Fš$+0'› ÃcÜpB°Ro`od`ABÌãa MM¤¢Âõþû8lýâ bàöx"A Ìãa¢Hš›…C‡œ‹ ­Ë–1]O‹û/¥ÌíW¯®~é¥"SÅ›o;v,æÄSBŒ±—Š_Z_¹ž(Ä6l°áÓòOsæoîGČă{\.ñ%ž™Šÿ®ÂŠFQ0ÈŽà-·X_~yßĉwG".„zܹª¢`‰bpÁúùçOL›vS($õÀÜ0BðÑ£mUU­‘ˆuë­›{l—®Û¡ܾdI…Ç#&ä¯ãO¢øuÿƒÛüdÿ'“Oz{ÎÛCÝCMj¢þq{ÿå‡ Bèd¦ì¦&7À!—k=€K’Œxš"Œ±mÛvS“  Òë]ɘS–ÍD0O;ÁDÑyð`ÓgŸÎϯµm†ìÝ{âÈ¿#ÆÐ< ª:Tý󼟯*[5k䬿œÿ—\gî?q åå°‘ƼªSSR,Û>TZhm¥¦ÙÐØØã ÓŒ1‚±×ãa))ÇŽk®«#'OžñÄyóç MBârʦ@_ÚûÒîÚÝ’"IXznÏs+2À1àÞI÷æ(9&5ûß©ï±ôM6õöQ‚ý­ÀIn²Ý/3¶móE‹åååÕ××#„æ^xáÕW_}çw&ÐX±ìŠ[¶l)**âþüóçÏ¿òÊ+.\y¥”¥¥Éóæ ±mêñHn·H©E)=ûì¬#<¡Ù¥(¥Mj00MscÅFˆQ6À=à–Snäd@brÿEˆ1–e9ÉmSQ± â·'¹Ús³aLœœlúùÏ^__ï÷ûN'¿Þçó½óÎ;ápxáÂ…±)âñxš››.\XUUÕÖÖ‡Ãá?ü°µµõW¿úU×ùÁ"t]2ĽjÕŒAV–ÂUÓ„*ôÊŒW"Væ90 ™ŽL“šÿë4ÒH$Â_­éíΓjÆ^©««K‡Ã¬iZMMM°$IÜÝ›Û9ËøÆoH’ÄŸ@â¢åÏ;0ÆNž<É Öüñpxå•Wè Bg¦êë뻤cˆãqE3& ÃŽÏY q7à\WnBFk̰ X§yº‘Ý»OüWœ™›Ñ8Ð:LY{Èù£C‡Í™3Çáp$·"„TU---=ÿüóEINÄð(C‡Íœ9Óår%'b¸`:4uêÔ´´´DplHâ¢8 'MšÄ“9ã¸ð«N|‹‚1Þ³gO[[Û¬Y³øÂ°àœœl¢Œ†Í°fküRÈÏ‹âââQ£Fq²IÀ‚"(–88bETKÇÞ½{‡ ›8T–w= 1‹±ïJ6ù|¾Îv+|Õîܹ“G…·µµµ§Ñë\\\\UUuÁøýþ$dSl?à“£lê…å£VYYYRR2cÆ UU›šš83Õî®$ª,Y‚›š:}å»åõáÃÆÅûÔSÊâŤ¾>Žw O0°1Æ~5ùW9ΜèX®~æä36µCf(MN‹'› “š÷žvoŽ3'bF2•LŸî{¸öaÆXÀ ¸E·yÀ#›rr¬§Ÿnjh^ziôÛ•~06ÒþJõóÏ×.¼Ð4„Ýãx „,KŸ9S¿è"{Ø0Eî¬i÷>xa—èjÑZlf×Gë´€±©c:Z´ÓÏ!ÄÓè¹Ew«ÖjRÓ§ùö¶ì£RF q ±˜•`E6E£ÿÄȦÿ ! T›?_›775)_íX¿oÛ†»æíꛦ~þùí4ÖÊ•ŽÕ«É®]¸§„x±bRÓA Ø {_X~dù¨ìQùP»i¦ÛÐ[Ô’‰LyíÀkü(7=÷±³ãÂë®›$ ƒJ^þåV!‡Q4ÊRRwÞi®[÷ô¹çÞË=† !„Ãa‰0—+ø“ŸX«W¿:þO£Ñ^õ2F¢h¶öëÝ¿~oÏ{£³F¿5ç­1Þ1üMÕî`‰H6³¿ç÷,øcnjî[sÞ:=ýt~ a=;v$üÿÿppÚÿž‚1° ÃjjrìOIYD©CÍ™)Œ!Û²Ìæf7@yzúG¢$ÙÝ"›ø¥°Yk¾wÛ½Ÿ—~~öгÿ>÷ïãSÇk––|6v‘Á‡w<ü×’¿NÈ™ð¹ÿ˜’9EµTNL)Ä$©=ãHíö8\å_k#m†JIM…ÔÔÚÚÚ@s³À˜ÏçËÊÊÒ4­;˜1æõzqjj}}}s]477><Ç‹œ‹ó…â6ß$;å,gÖ_Jÿ2CŽŒŸò³,%«“lâþÄXxuÿ«ß”#È ÷ EG…ͰGôÜvêmC\CtŸôa¡yóÍTÃ@‘€Õ«ÝUUâ™gjçžMTüÝɦ„¾8É¥¢û½¢Ÿ7îWnƲeËòóó¹×=B誫®ºöÚküã£8=3v»]½zõÖ­[wîܹoß>¸îºë®¹æš[n¹%ÞÔÉ_Æ­ V†f¬<¼b6Ëðd\5âªÎ dv"pL°™½îØ:Ä£Ìåp]2ü’ážá Ñ­„@4Š_{­3›ÑêÕžU«< ú.¸ ÒmâõO„Üvœä¶{; :²hõ,v\œ{Ç®Õûgpl ].WKKËÂ… 9ÒÔÔ¤(Jjj*B¨´´tÿþýGŽyüñÇc²WEUÕ»îºkÿþý ‡ƒƒËËËŸyæ™ýû÷?óÌ3Fs`ð3ÓŸ œÀÐnåTþ0÷°îd“MíßžýÛ_LúEf ýÃù«òñ`Ë‚´4{éÒj ”@dg[F© @ ??Ÿ{ðc˜¯p‡ƒlÞ|r÷î&„à²Ë†rJ¸‰mø <³»c„€$1‡ùýȲƶmoÚ´iúôé=Ný¾É¦ÇŽÓ:±Ç±bdSrpÙÔ˜‡6Bìñ#AHÉÆoÐÁ°3Æ@êûï§|ò #„‡±ÙM¿ÿ}ðÊ+q(Çd{ï'Ÿ¤¿ó#Ù6Ø))-¿þµÿæ›q8Œ:~·=ç“e&ËÈ0p àøäyÆÀë¯Ûéx“ kF¶Íd™?|è¡m-->5Ê=~|'ébÍ&‚€)e‚À™&ŠDäµk}|úisìX¢ëŒ1Ó4{SËÿçȦ~º÷t÷J®O%ÖŒضvÆæÐ¡Ú„ Bccú›oJ'Nx¿ú*xÅБž4F–¥ŸrJëCi§†ýþô·ß–õ~ñEà†øtÖL)MOÇ--ÒîÝÊ×_;¾þùýˆR??#{ö)øÒKûZZÔ2ZZTYæÞu(l›¦¤ pX*(p¬Y£|ú)nkCª ¿þu|rÔÞá_‹lê¹À7R·›É2=+VH'N0QBxXp0@誫8iš{ãFùèQ&ŠŒ„,öÌår¿ù¦ë¯Ž‰–uUââ„RæõŠŸ}V±bEù}÷M^»¶¦¥%ÔÀÙ6óxœ_~é~í5ñÀö´«ñ !–Tßù4°m3BÒÞ}7uÑ"¤ëRe¥>~|ë/‰ ƒu϶eÛLR>þ8ýwaH••ƈ­?Ì_•Œ_¯`ÛöÈ‘æÄ‰ØçÃ--ÐÐÛcE!ÕÕ‘gžÙ=gÎàë¯ýÕWÇeÑ„8 Î3Ù¹¹Æ¤I¸¥…ÔÕñ¬ úfó/(B®„`Uø{Þ¬÷ #M‘a¥Œ_¥BJù-gþ|í ICƒcåJDzeâ¡C¤­­G~ˆ?kñì³E‘×_?ßãá `Ž´4¹¡!ÚùÎ9ÆHU©SsÎ µ´È›69?ý”;&ÔÖö“wúd*!8 ÜtÓñ¼¼ª•+#sæ8JJ2Ÿ~š¿—øf!8 _qÅñ-[N¬Yºì2ùèÑÌßýŽ+>]ÀãPiÍÈþìgF^Þâ î°ù’ñu2\]^³¦jà@×’%Ï=W dñâcK–T8BWcŒQ4Š"æñD®¹F]¿~óÃÿÀGˆØµø/'BnÌÐuª(ÌéTÏ>[›4 „ÆF¡¾žñì `M£s:µÉ“Õ³ÎÁçkj˜$%˜&ù9J Ãlmu”gg¿ ` M40„@U-Ihxê©-ï¼Sè‚ ¬][úõ×GELðç›65MÓïW4­57÷#Ÿ(r«`rMð_k#eŒÉ²TY™û³ŸEgÌ0ÆŒ«ª¼_}æ AVnnâ³<‚@ÚÚýøÇÚäÉú©§ Þ%KÀÊÎ6‡E†EQXG5þÓº®G£Qç£ ünÉ(ŠpÁƒ A‘ˆeš”‡SÅ,UU#‘ÈÍ7ß|ÓM7¹\®XÍ܉DA°mû[¼ÙÄ¿¶iÓ¦šššä¹ÄcÙÙÙªªnݺµ²²²O²)%%%æçç9r¤O²Éét†Ãá;w–””ôI6µ?s%Ë$6lñÑ¿¢¬Kl”;")í&â.!<@õرcùùù¶mÇgÕKh°iš’$ñùÇíg±™gYLÓ Æø3õo6ñ‘ëׯWUU–e>e»÷ζmUU{[…‰dSAAÁèÑ£çÎÛØØØ'ÙÄghJJŠÏçëÙdÛvFFFsssÀ”RŽ¥lJ"oþæ¢(¨#éa¼¶@6@0ŒÅý0Æ(tª%+Adz1|‹Á8„‚;ü±¦iÓ§OŸ0aBŸüç@DQlkkã[Nò9jFjjjZZZßd7»\®#FôiÕ4Msß¾}C‡MIIéHŠŠŠ† 2bĈ>ÁPXXÈMLãZFQQ¥ô”SN±¹iC©¢pþq²IÓ7°`ŒKKKG VrG,3^Ø ›ÔÄÇNâ½{÷N:UŽ{üƒ1æv‹Š"0Á aí{£iš#FŒèùÜ¢QÊ:˜)BÈáÇLj#Xñ¡”BdžªªªjiiIKKûÞÈ&Î)655}öÙœlJžoÿþýS§NMN6ñýðرc%%%S¦L …BüuÑÞÀ’$UWWïØ±###ÃãñX¦ „õõŽmÛˆßLÓözµ3Î0FÆ‘ÃãT‰Ûíæ½óëþIC¤AµU¯èš=uˆwHÔŠbÀ”QQE‘$)Æñ„5;v4:Ô&øÂ  ä¶íNþˆûàx3OìtâÆF°mLˆa6l˜7oTWW“x3Oìrá@LaL)]¹rå´iÓà{$›8ËÃ@ƒ¾ø#®7¯†õ æ,(tD·&'›DQäN cÛ²lJ¡ŒwßMýÇ?€Ó{Œ™C†4=õTxÞ<³Ž¼ÂœÏ2móÉÝO~Sù ²XÀ$6jÀ¨g§>;-gŒ1GñüQeeðÿý¿->ŸôC‡ºM³ ÔÎ “eÄ躼j•òÍ7ÁßýÎÎÊ"¶Í‹éwíV„0YF`šÒ–-ÎÏ?=ú¨5r$1 3ܽü—Ȧ„5š\—é,ùw'›øvfÛÆÈ‘mwß­všP_Ÿúá‡bMMÊLJ/ººÒ<|ÍàEÃ/ºrø•Õáê÷¿_ÑPñÚצåLëéçÚëÅ‹}>=%%-2%‰lœ›=B`Û4- E"bi©cåJå‹/pc#‡C¿ú`ÌéˆÎfÛ6MK]Žs¬]ëüøcÜØˆðÏÎgaòT‰ÿšd“ÿ§?¥^/U;·oëê¸×v"Bè…é/ q Ñl-SÉlÑZ>hý hý†ßIœ6K0Ͱ”éï?ºn]ÕÝwO\µª:P;+ƒN‘0—ËùÅÎ>ŠŠxÒ¸Î_ï6hÔív­\éz÷]© ñløß†lú—³‘B´hѰùó‡ÏŸïÌÏ7Fj»ë.ăcâI•°”éÈ “šmz[³Ú CÜC8$Ä1N§P^|ñÅÂyó†\ýèHÄ@–Ål›%²¸Œ1Ea))÷d*哾{@ cLQhJ s8:+ø?M61¢(ÖÕ¹¶mc„ ˲ÓÒ쌌ÄÄôÀSŽPCÄ¢HÄW÷¿ºüØòܹ÷Nº×´MÜu~c †AŸ~ ˆ¯¾zži¶/ÐŒ Ùã[Z´N› !(Õ.½T›7O¨©q¬Z¥|þ9©®Æmm=î‡(ÕçÌÑgÏ&µµŽõë•?&ÕÕ¤¹ùÿ0Ù$8òÿä'•……Õ_>])*Ê|â ˆóh;@”Q™È ØÓ{žþãî?NüÚy¯O¯ÙZbLŒ€+*«V?>}Æš¿ý툦Q¼dIå¶mõŠB:“ 0Æ“I ð.\ݽ{Í]w=  Ò]?d£Piš=p`è§?nßžÿÈ# ú±ÿåVa‡wŒšJMS4ɽq£sçN±¾^¬­5‡ Cq† TÄbØ ÿ®àwK.˜;ñÍÙožšzjÈ DâÇBá°IÙºõøÖ­Ç0€"dñâÝ3g^ ªj—ü¥ü¹WM3uÝéõ–úÀ-‚eÛ‰Q¨¬ýub¦i–a8œÎºaÃþ p½ ¤Ù¶úŽl’$ñĉ¿üetÖ,côh±º:eñb°²²¬œœ² #l1ë™=Ï,-[êrºÎÌÁñÏneÙéé'ÿö7±ªŠ„à €¦§k'Z™™ üP 2–?ûñ&­‰»`À³¼’·]#íºƒ1Æ4Íb ,‹¥¦JÏ??SÓì‘#STÕêÎI’ôÀ¬X±¢¡¡!æ¿mÛ¶üüüéÓ§¿÷Þ{±ÇYxÉoûÛ%K–œ_âàa4‚ dgg÷'††RÚÚÚš‘‘ÑO›_KKKzzzŸ/ñfȲ\__Ï#/»{¦Ç V8p`(â¡^½ùÚ5M3+++##£¿d“×ë?~|Ÿ=dŒíß¿äÈ‘ý!› ¤¤døðá§ò'é“V‹Ú¿¿$IãÆëøàÁƒC† q:ýófôç.^svvvJJ ë+¿(BèèÑ£§Wþ¨+¸¦¦& 2¤?à†††@ ‘‘ñíÈ&ND$ኋ‹N?ýôþM¥¥¥eee§Ÿ~zȦòòò}ûöMœ81û|¾äÏ(ÖÖÖîØ±cÔ¨QüͦÞ,úœÖhjjÊËË6l˜eYíÁJ½€y‚èM›6Ýpà Œ±ÚÚÚ$`BH4]¿~ýå—_ÕÕÕIÞCãKpÅŠ\p$÷Žà‹jåÊ•S¦LoE6áŽÒã§œ?Š=SÖ²‰Ÿáýó×ÒbçyÀ|#å¾I¼4!º®†ËÔ—lšf,{jŸ`˲bÁè]ôäžÀ†a¨ªÊ›‘ÌåF{;}þK¶:ÙkFòhÖîà~¶„ÃqNi}t°Ïó2¾ž8yµ|4’ɸŸIÒ”zù¾¬ÿÃ-ù¾ªý4sÿ_+ÿá¾ü[„?øòoþàË¿Eøƒ/ÿ4~dÓÿXÍßKw¾w­5Ù”äÕ“xã}ì/ý'¹&w·'$¯9þž»B%±tô³Ð홌º=Bð}{þŠb¶üîq>:î§ÜHŸ£K¸9˜õÈã~À±G¸“ƒjæÜSo`ž¯?`è[‰5#9:hâ{Ñ›Á;"Ç_í“€1Æ|l{³HôÙdÛv~~~ò—•À4ÍÌÌL˲vìØqôèÑ>™)·ÛmšfAAÁþýûûd¦DQÔ4­¸¸¸¨¨(¹=…Ûøu]?zôèöíÛ¡¯bY–aÇß¼ysòå9ógšæ±cÇÖ­[Ë~Ôcáa1–eUUU­\¹2æ½Þ˜^ +W®ŒöžM:žâ3»òŸÔu½¹¹yèСÇO>v”R·Û‡srr ”|à8ŸFÓÓÓç̙ӧTxfXÇsþùç÷ æFTY–gÏžÝ+5àÏø$G2ÆœNg 8÷Üs{3sÇŠmÛ©©©ÍÍÍÓ¦Më8;;Ûï÷O™2%9ûKØ=Ù);ùB§ÓYRRrèСK.¹¤Ïx¢—Vé•/ä{½Ëåš={ö°aÃt]ïç[%\Aøï@QÞ'¸ÿ^U?D0'mº§Ml_…ÐÁÅŽÖ~Ü¿ËÿpéîÃÿž&âÇu®òßåaér˜Ç»þý»üPÊ¿ l?øòoþàËÿÖ=”6ý€S%tEXtdate:create2017-06-06T01:31:13+01:00?¥ª¤%tEXtdate:modify2017-06-06T01:31:13+01:00NøIEND®B`‚puzzles-20170606.272beef/icons/mines-ibase4.png0000644000175000017500000000141613115373736020000 0ustar simonsimon‰PNG  IHDRnn4u;ÈgAMA† 1è–_PLTEÿÿÿ€€€ÀÀÀ€€ÿ5þ$bKGDˆH oFFs‚‚€çùÔtIMEá‹ß? vpAgððüE­øIDATXÃí–ÁŽÂ †ÞQ³gaÛpy`cÒ»^úþ°meõ 5ÙsšLøD(óešÆ‡LFÃ…Øk ”±œÚÈÉiÍÁœÝê­e¹îwá”1Ëò8Ó–åÄ08î<­p>Ó—#Ãé¸)¾ Êg-à ¹­û…óMa~ˆóY»zŸnýœ%¸ÝíÁ©eý”åpC¯$dœ2g)Ýw§l~0§¾î'z/Æ¿ãß‹í'ä8Ž÷S1·ç¸Éú¡„SÔÑeœÛ8d «4àªep Õ7õÑ5^³œTÍ-ªan 5¾3ÚÀ-5Äiâ¢N´Ä¹<_÷à¢ÎWÄQ rn¿È4mï¸ç:º—h?»_ßÏs‘I­Î9ßÛ}¶½^¿O/ïü6Æp×r®¢ÿI¦‘Ò^ök\x/dšùÃ÷O5Ì=Þp0Mà¨ÏçÞþ»iB-ʍ–à€iBçikŒ¢Yî—´Š(âÈfÞ*à^¢Y[…é‡hVAVIõÍÀ*I¿¬2äpÀ*Éýܬ­’8Í*ŒU8¿øY…±ç?«”qÑÔ‚­Âr~æ€Váü‚¸`•u¿`«¬û%i•<.X%Ã/È*¢ÈE!2³×P™ÙkÈ̬r•«Ü;‡\’áä’ñK5jÔ¨ñyü®ÐO[Â_%tEXtdate:create2017-06-06T01:31:26+01:00ã‚à%tEXtdate:modify2017-06-06T01:31:26+01:00’O:\IEND®B`‚puzzles-20170606.272beef/icons/mines-ibase.png0000644000175000017500000000331313115373736017712 0ustar simonsimon‰PNG  IHDRnnñ…ÖÉgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<.PLTEÿÿÿõõõ™™™æææûûû³³³ÚÚگȯfªf1”1‰†9—9–¾–ÔÔÛmmí>>õýÿ!!ùæããí¤¤÷DDýQ¡Q€s¯sÉÉÝêÁÁôhhýý ÿÿ†^§^»ƒ¶ƒ ‚ÌÔÌËËÜ//÷^^ïppìçØØï‘‘ú11þ ÿ¢Ã¢ÐÖмμ¨Æ¨±±áüØÙص˵‘¼‘%%þ¥Ä¥ „ ƒ­È­³ì•¾•ƒŸÂŸ€µ€k¬k‹·Ì·m­m€]¦]’’æwwëû««âÙÙÙ”””;;;```ÐÐÐJžJJJòÝÝÝ¡¡¡FFF VVVÏÏÏööö๹ñQQù$$ýÿý÷22ê||Û××XX¤€œœÀæ’’òLL¢¢Ã€äœœóHH興ö22ÝÆÆÑÑÖŒƒÝÇÇß¼¼^^§<<™99—ÚÙÙÝÈÈímmúÚ×ר¨Å „ÀÀÏõ99÷00൵ÓÓ×!!‚‚¶ö66á³³dd©ß¿¿äžžüÜËË»»Í ƒ¿¿Ï犊§§ÅÐÐÖÜÍÍúù""óFFê{{斖艉⨨ÄÄÑzz² ÖÖÙúñUUé‚‚ô??ûþþûôBBþþþÔU7bKGDˆH oFFs‚‚€çùÔtIMEá‹ß? vpAgððüE­pIDAThÞí˜×sÓ@‡ƒED UÔ U½‡!D `zïB1 =ÔPBo¡÷¡×ÿÉÑØÒÝÊÚ“Ï~`î÷à‡õ}ÖÜÉ÷Íæä°iI#Ö÷ÿ´Æ¹• ¶ˆ£K¹‘¬â" ¸&M›5o‘ײ•{i¨ÖºMÛvšÖžסc§În\Ò|×ÒP­«f‡×­{ž½t®wŸ‚¾ý)ìïµ æÃ :løÝŠ7r”õ1Úz”¢äÒPÍÊ>ÜX݉ϸBBÆSÇ‚­qâÀ§‹g!éSÈÖ8qÎÞMbp“§â©¨ñãì“YRJá¦M'Å3¨w ª…Á)Šaxq3g‘¼"ꕆjbp³ ™S¦z—†jbps ™7?ßJYri¨¦F£ 4ma4ºˆ·xÉÒeËW¬LâV9ÿ ¤ ¹4TS5'«Ñ¸5k×­ß`ÆÆM›·d·ÕHd›ç½K&Ó7B†pÖmÊ$s¸í,mGq>¾ò¨/ÿB”¿@}¡ptì/P·sWùî={÷Åöû-ã:>¦iðïÃà*뵊Z†ö+8WwøH¬òè1‹wܽ ë/ªZ} î¥ýQûJ×cYÁ½~óöÝ{{û>¤Ä}¬·óÉ4+ê?§ƒûâæ¯Þ=aü%vïÜ}Ü·ï?~þúý§Òý× ù „£úÂÞú„\@ä‡ô¨/ë/P_Wáð®Âá%"\ï%P-ÍKìzI¸“ ÍKTŒ—@5˜— ¼ªãày ÂKB» ;/ÁxIXWQ™y ÊKÂ?=/Ay TCáèy ÎK ÇÌKp¢Õ8v^’I0/ÁyI88À°ä%PMŽñE„«à½Dá*x/jbp—ˆq¬—„pá*"ÂUð‚­qOüÒ«IœÄIœÄIœÄapXã*XÉœ«¤›ÿ÷7NÉj$Nâ$Nâ$Nâ$Nâ$Nâ$Ž7ÿ¹5« ksE%tEXtdate:create2017-06-06T01:31:13+01:00?¥ª¤%tEXtdate:modify2017-06-06T01:31:13+01:00NøIEND®B`‚puzzles-20170606.272beef/icons/mines-base.png0000644000175000017500000001224313115373721017535 0ustar simonsimon‰PNG  IHDRðð±7~ÅbKGDÿÿÿ ½§“XIDATxœímPT×ýÇÏ>°°»Ê*Z Ó¨2bŠ:1‘„A&:Æ´™êÐÆjÒÒ8ÓNRg˜ŽvlÇQ&/Ê´‘NÑÊJô…ö¯ñ1²Ij$F2øPŒˆJ–e€½»}qq³jܽ÷ž{ï¹çÜßçÕîÂwϽË×õîîýìÏpëÖ-¬`$½ 'Ph€) ÐS@¡¦€BL…˜ 0` (4ÀPh€) ÐS@¡¦€BL…˜ 0` (4ÀPh€) ÐS@¡¦€BL…˜ 0` (4ÀPh€)̲ßãáÇ9Ž“ýnö°ÙlÅÅÅòÞ§üÏÐÐf@ ‹-’ýná @BBÂâÅ‹ÓÓÓe¿gù9 ¼õÖ[ ‚^¯×b±P—u»ÝJ´)]袢"iA—Ë¥«¬´fƒA—˵lÙ2d…ÏÐâÛo¿õû.\ˆ|½7Y% £Ð##†ºº”¶¶¤¶¶$·Ûˆš6m䨱ëB²—ï_>rãȹ;çnyoÝ Ü³'ØgNœùËœ_–L-Q4ké陸}{R{»¹¿ß84²ÛG²²kLjiIjiIjm½½m›ˆà¸Ä/¾°Õ×[.\è»|YDÒ,tÚh çåòò))\uõ$±ñ – ¯M{mÎä9C£C]ùèšçBè¯íýyöÏ“-É eC6ÛÐ’%þ矦¦}¾ä½{­--¡ñ‡õWVr“'ÇÝlsW—mÏkc#â8ãÐ ‡ï1•YY £ÐGhß¾›¡+WÅú§Óú§y²™müÕü§òKþ¿!4íìž;y®BY_a¡¯°0rÕ»`Áôü|þ²Ñç‹ñ^½ap0éØ1{}½¹£Ã ¢ÑQ{IqV^è(4ó§Ì¾:Õ>5Á˜0EO¯\ö{ÂaÓÀÀ§“¿6š™9š‘ã×TTdùJ‹ê¬¼èc7ñÌvdg;²•Îf¬]›“3}þü”ÚZ„P`öì[Û·£˜/ û]®ïjjFçÌ [­HäÛy4fåE_…>wç\åéJ„P’)é½ü÷TËF[,†P(Îï$'ûW®¼ûé§wõþúס BãÇ <¥1+/:*ô‰ÿžø•ëWÞ 7É”ôÁ‚žKyN…쪪ö~ü±gÙ2„õìٌիn·l0;{pÓ¦¾ööï>øàS„î ß\:³² —B;»œïüûanØaqÔ׿üÔËêdG32†sr|··mÉÊB™Ün»Ë%bÓM¦áE‹þ¡øo‹°‘Ńý…¡šK5ûêo¡t{úGEÍHž¡BÖèñ„ÆG½pä8Ã×þ¦ÁAሂšB=:!ÔÛ;ö‚Ãë5ò·¤¥óò1‚µíµ|# ÈPœQüÙÍÏ>CŸñ?*É,‰]PœlæÊ•#YYþyó‚Fgü ×Ç>Ú Ìš%`)PSèwßM‹¾z玙¿eéROuõíÁoÜßðÂ(üÏÎFÿh긩±K‰“5ƒãŽwüø#·®\˜ë ìh<ω'öìÙc6› CeeåúõëSSSYÍâCM¡©c ¬Ì~òdbg§i`ƒÜ¤Iù¹ƒ+V -Y7ë÷ûO:ÕÐÐðå—_šL&¯×Ëßît:÷ìÙ³|ùòŠŠŠ)S¦0“•j ÝÙÙ%-X]P]ªÕϺKKÝ¥¥Ò²………½½½ß>22‚Ú»wï©S§ÎŸ?ÏLVF¨)´®8w²2…Ö Á`Pò¹Â4f ­ |>_SS“´fP—5›lAö^”÷ÅBÊÏkhhäÁÙf×}ûí·ù b…—¸0è’òóÆþâl3ë*³‡4zrz[W Ô+´žý¼M›Î66vó—?üpaa¡<ÿ®{ÿ«¯Ž¾þúã·§¾ðBÉîÝÊ­Bû+õNNÚuu×?¾þÇÅ»ûü}Áp÷ó~ûåoë.×ÅÍò~ž¥»Ûèv#Žãý¼mÙ2å·—ØÔ4qÍš)¹¹¢w@jöôé¾O>é½öº¸Ú_Ëÿ¨÷óÏZW–ý•µ9œ]ÎÍç7‡Â!‡ÅQ·°.ökÁG;\ÎÉñ$vtXº»y?ϳb…лxàº!„D¿í,&{÷n€ãÂ~?WTô¯G~TVö9B¨µu•Í&ìÁ»Í(L¦É³g×Ñ Üó™Ôþâ¡ê3tÍ¥š?Ÿûs(J·§7¾Ò(¼ÍFç¡ëàç=™{mmá¨! aŽ»wéÙ*àýMÚQïZW~^fæ¸Êʇþ¹:]×®yB¥¥YÓ§'[,ò|Àù8—ëê®\™¶|ùÄ™3¹@ çÀ¯¿æ4µ$þ‡²Ò ¸¿ ^¡uå祦Zß|óÙè[\®^þ\R2UøGÁÒ¶ÙÛÛûÕßÿþÈ3ó›Iyy ­+×þâCÇÉI4úy8à¬û“õë“g̸ýŸÿønß°$'Ozî¹ì_ü"CÀ„x8({>4‘ÓG³³³QÔdóæÍûA×-BzzúùóçùÍæÏÓ•–Eû‹³Íô®‹¨;Z ÐèÉém]a³Ð4zrz[W!,4)ÇêÖ5›ÍÁ`P‰MÂDÁchpûØ&âŠÅçóÙlc']Òt nŸphœ­(`0ØÔÔDñœBpûØFk•採ewûJJJnܸñƒ¿_^^¾n]œél’×ÅqûHù—8ë Déù„¾ðœ„Û÷8†˜'¼+·n\Hù—8ë>)Rýghõݾ²²2wÔ)¦ÇÕÖÖr‡z饗”Þf$Õí#å_âÌtDú™SHÐí+}ø+@>Ì·yîܹ³bžØDÊíC„üKœuu7§P;3ðvîÜÉ_X»v­:ëŠuû!ÿg]íÌ)T©ÐݾhÚÛÛ/^¼ˆJKK{å•WÔYW¬Û÷8êø—8ëÊø7ÂD¥…™W__Ï_X½zµ)Þ_—”Û÷ªù—8ëêwN!ÁxýýýGŽAY­ÖU«V)½.¾Û‡ù—8ëêuN!‰x üéË—/w8НûCnY ÛGj>"κcÀœB¥nllä/¯Y³F…ïµµ¥Ìšexp`#Öí#5g¦£ÐK¡¶ÑÈc¥l¡Áíc >V Ü>¶ñûý'OžÔÚœBe,i¦×ëÅÉâøˆ8ë644¸„}rñ88.#BHòº˜Yi(j×2è’Ê"p5³N!¸ŒúDsŸ*:/PÍ,©y##†ºº”¶¶¤¶¶$·Ûˆš6m䨱ëBîTVF4Wèøp\â_Øêë-.ô]¾LG‘ëz½ÆÚÚiK‘ÊÊM…&5k®yFc8//—HI᪫'‰ÚTRY¡ Ð¤|DJç:¡}ûn"„®\I[,RY¡ Ð¤|DzçêB'ø‹¡ßåú®¦ftΜ°ÕŠD¾½E*M ¿?42ôùîµµÙ¸ñÌÿ¨Îºú„‚B“ò)¨s((tR>"Eóš = QJÛ)”¸®¾¡°Ð” óy¤ à]J!2/çèÑq¡ÞÞ±”^¯‘¿%--˜—ÐfV.(+4QrVýy<ï¾›}õÎ3ËÒ¥žêêÛÚÌÊ…&å#¼@ꠣФ|DRN!¦Ÿ×ÙÙ%aQ²Y¹ £Ð¤|Dp©ƒM§\FÝ S¨+—Q³óIÁàœB³ºqs ÙÌ" ½@p ¡/FàÑÜ»šòµÝ´élcc7ùÃÆ^T˜5¨eà\Á˜­xútß'Ÿt‹ŠÈ6kN4÷ ­AHùˆ~pãÆ3á0JL4 ÇÈö˜³© ýDˆûˆï¿ßvóæPAAÇ…š›û¦pf2ú‰õ[Zúwïî´ÛÍ[¶¼PQqZxPž‡ÔÇÐO„ 8<ÌUTœ…Â6ÌMO·‹G#aÆ!Õ@¡ŸA±¦æRO'?Ji)Ö8YfÒ:>*ûˆ×¯{vìè°ZMUUóãÿö“‘„è·ÅdïÞ p\Øï犊þõÈÊÊ>Gµ¶®²Ùâüáœ]ÎÍç7‡Â!‡ÅQ·°Žùׂ Ð Bû¬A Ðš#3s\eåCO¨Ng×µk„PiiÖôéÉK¬)å ÌÄ -5}ÄÔTë›o>}‹ËÕ˺¤djܾe™5H/PèXœ­H  ‚³£Ù¹³Xø6ãÌd(t,hôu8…ZɲN!ù,x2N¡lY›ÍfˆùMæOÂçóÙl6 A>»[¦DjN!ËÙ¦¦&œ,¢ÐGTp É<š{—C³n-Y§' s õ„Šów]ݵ¿gä*ï6÷5—畯Ë]§\æê">"ŽS(9 s Y† ˆãâdaN!ËôqœB|D0VA óypœB}D(´"Ç)¤ÔG„B+ ©ÙŠÏ)¤×G„B«‚ê³]ÎwþýÎ07ì°8ê‹ë_~êeu²Ä… ‚ãÒî#B¡YÇ)ÄôaN¡.Py>"ŽSˆé#œB–‘Ph¥ å#â8…˜>"Ì)dð‰N! Y 8…òdÍf³ßï?yò¤úYð£§ð¡,ŽHÊí‹øybÁÜfœu#%8…Ítû¤¿Í8ëJ{œ…N¡ÌYRÚf­=Vš{—CS~NÖÒÓ3qûö¤övs¿qh(d·dey–.u¿ñFØëëC1³8ÛØùˆr­‹‰æ Í –«W“÷ïç“ZZ’ZZ’Z[ooÛ¦\ö!¤ºŒæ#ʲ.>Ph¥ÙlCK–øŸ>˜šjôù’÷îµ¶´ „Æ:Ô_YÉMŽuòN–‡È|DÌue ­¾ÂB_aaäªwÁ‚éùùüe£Ï»&’³¤æ#ʲ®,@¡•'6 Lp:ùk£™™£ eIÍGÄ_W. ÐÊ’±v­­¹9r50{vßÖ­HØ ; Ù~— ç™Rò|DÌueŒU [,†PH¹,©ùˆ2z˜@¡•åNUÕƒ{?þسlBÈzölÆêÕF·[é,©ùˆ˜$>pÈ¡,c‡¼99¾‚‚ÄŽKw·Éí¶»\ž+ÍŽ¡ú|D ëÊ ¢F€B+…!wüø¸ãǹ}påÊÀÜ8ƒŠq²Tž(y]yB+Å@Y™ýäÉÄÎNÓÀ ¹I“†ssW¬Z²DÑ,)Q#$Z)Ü¥¥îÒRõ³¤æ#ʸ.PhÖ å#jă§PÎ,)Hm³+p ¿‡R·Ô6ã¬+yѸ0è¼@áÈââdÁ)T0 ó‚ÿXSHM–FXz¬4÷.‡¦¼@œ,Žˆ3/0 zàÒ Žˆ3/0I/œBöÀôqf "r^ 8…Ì‚ãâÌ äQÙ §POˆw 1çªï‚S¨pœÂ¢æñÁ)Ô)œB±ó‰xàê/‰ŸHÜ §qp¼@g—sóùÍ¡pÈaqÔ-¬òZP+^ 9§ ­F'4>êœH/öy¤€B+Ž(y^ ^ Ph¥Àñ%Ï Ô‚N!›àx¤``¶"Z)p¼@ÌyѨæ‚Shf+‚S(g–F{¬Xs a^ (H=Vb#ÂѨSHÊ „¬ÊYÙB?úÆq ¥µ9âöA–ɬÀ)„,SN¡æNNÒ”YMe… ¹BPh€) ÐS@¡¦€BL…˜ 0` (4ÀPh€) ÐS@¡¦€BL…˜œBÈ‚S( ½@Ȫ“ŽRNaBBÂâÅ‹ÓÓå™R° N¡Ùl†6DÿÉßjµC›¸„)$ÿ!Þ¶˜ 0` (4ÀPh€) ÐS@¡¦€BL…˜ 0` (4ÀPh€) ÐS@¡¦€BL…˜ 0` (4ÀPh€) ÐS@¡¦€BL…˜ 0Åÿ'éâà 0YÃIEND®B`‚puzzles-20170606.272beef/icons/mines-48d8.png0000644000175000017500000000427513115373736017326 0ustar simonsimon‰PNG  IHDR00`Ü µgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<PLTEåååãììêæåêêêðìì×רÖÙÙÖÙÖÕÕÕÛããýýýø÷÷µµµÃÃÃÌÆÌÓÉÓËËËÓÓ¿«««»»»¿Á¾ÈÅÅÇÎÀÚÅÅãóó鯯ãÛÛ”””‘½‘M¡MŒºŒßß๹Éw²wCœC®Ê®ÌÌÔÈÈÝggîBBùwwðããÝÜÜÜëÕÕ즦öXXý é¹¹ìõõÚÚ×Z¥ZuâÞâ5–5e©eŠ ƒ ÅÑŹ¹ÝKKóü44öøEEÿòæòÌÔÌéÞéÿêÿ»Í»ôôÖééÔçÕÕêôKK;—;S¢S--÷ää×ôýýN++¾²²ôôô=™=(‘(êãë´Ê´‰==õœœœHžH ~ żÃJII jjjÅÅÞ¤¤¤š––ž¡¡Â¿¿ÏÚÚÚêéýû##䤤çÂÂí””êêã——ÀWW¥ß²²ø44×ääðûÃÃÑ""BB›ëªªôccæúú攔猌«ª§HHvv°;;™ìúúöHHòvvïWWÐŒŒº‹,,’Òá®®Öôô&&&|„ ƒeeªêffedd,,Ž[[[{{{222*))‹‹‹¤¤ÅTUUªÆª˜¾˜¨¨Æk¬k}‚¶‚é´´1166•ˆss¯‡}}³¸XX©RRœ##Ç››}††9>>ÿÿÿ±¡jXbKGD±4cžRtIMEá‹ß?¤IDATHÇVý[GÞ»Ín.÷—ÛDã!b´ÍªHä(ÒŠ ÒÆ®5ŠŠ ~P "Jª¨µÔ‚¶TÔª­ÖÖÖ~ÿ‰Ýû ôÑœ'¹››Ûwgfߙ݀‹à^ÄàèËò¿ß"¾Éúy}œ!º7~]ú6à>…‘¸foH •$„ÆE¥h4ŠQ Å`8?”eEQd.ªªUTVêZ\3H¼²²²"¡#¹*¾z•¦,‹Ê@H¥Ö˜P¯Â`muõ: ›5–´¾¶zˆ¥ã`ã¦wÞÍ*ÊAP@”Áæ-[ë¶Õ'«P¶v{mÃ:©Ö†ÆMÍ-¶^“y¯ug[!Àž¢¼ùý\.ç0nÏ7¬ïÀ#üÁº†N;Ÿ°è®¶¶Ý˜Ä€Òž®î`â½MyJ EvgsM+1”ý°í#ŠEßGA€TaßÇL«’,iÿ'¨7JUl÷ØÞn£|‚rwQ\ÉõÒ¡¢œä€½ ‡{ÖZ˜ØGŽôôôÙzfã¦;7mô^Ö°Q:v|€èŽêÃëlJ¬ÎêêÚý}v¾?sâ`kkë 3ÈÁ IwŠŽãÁ<µ{;:lŒí½ííÀ–Æ»¹d˫ĪâÐP±84hpºÝÚ‚•h„ÑNâzA/„L‰F$‹¤Jé”$‰2SX¡ÀdìHº.U$uIRÆMŠó2ôËbm¸kdäô™X2Ξ¢á<úéù Û H¥Ìsgë55\%i±‹g.Ö#XØóYwÝ„ Ç¢“—ÎOe•ÁåéÓ¹-W’ª´ ŒjtøjwÝ̸ ÛÆr¹Ó%;óùµ©ëÀL×år—g}€—ÖèøÌ‘›ã^Hkn}ÁÎèí/'çæ$lÉbÊìúêŽ ‚’úÁjúõØDE…SóÌ,ܽ·ðÍ(÷À«s߬‘0ˆOß™È}ËsàEBáØéšþKߥ³.@¼¿DõrHbT‹­¾:s‡òúRÄ=œÿ^åIÇ2g0•™qtþáüBVä£ÃÃã˜"ˆJ†ÊÅt(BR†wÍÃsmFÑ[V¯£±AH¿Jˆjð )•ø%Ëéâ¢(b&¥ @Êléé}66‰dÓLÍP…Á›eªÓ³L¡I—iÑ#.ž5xþ“Mµ<îNfƒœòé™âLƒËÝ/\¦ƒm¢Ð×B›~6©–ÎH¿Ì½œ4c]cu¹éY³T7'r¹-³I"‡ýƒã”ö¶<ÖAúè…_o/D-¤Ô¿Ø:‘›¾Bœ»Q2ígÁ«Õîü­§ã¸4¹pmjá•ePH‰¿ÿ1ËâaóŸ­, Ò }Y‹H“×ç^.LñˆÈ?‘M§ ŠLþÇ‘WâpGCӿتÑ)}u/Ís¨7ÅûÇHƒ¨êè±GÅåZÓÄ’ZZòyœ%ÍÒtqõÉ¥ÅÅ%‡JKKKêr-Q³bÛv$¥µ\šbLux‹ª‰’8Ñ„“:” W o/æ»1²·'Ë2„ŠOu0¥Àç*sp÷%ŸMó4"*eîiÁG ?nÒIØq€z¢)¥d1ßfrüY+ÊÅ· p=@|€+)~ª0dZ\@„Ó•Ló4Û)‚]CX¨ÑB͈…ÂêËÇ“-ø“xB¦>ÀÌò:Á¢çAV F ŒˆLKÈþñÈ ZðORàü“”-÷4÷ '“:#Á4ÝÓŠÀLzšVd’gÑÕ r.Ý?–<…«@ LIà[TUrËÛßñå·”p»ÃSŸïó‘ÿxûº·‹¡;@àOÁôV_˯}¸¬ü¨ñLBø¦üB(WÌ#x5°<"èð:»7ùg³°%tEXtdate:create2017-06-06T01:31:26+01:00ã‚à%tEXtdate:modify2017-06-06T01:31:26+01:00’O:\IEND®B`‚puzzles-20170606.272beef/icons/mines-48d4.png0000644000175000017500000000145013115373736017312 0ustar simonsimon‰PNG  IHDR00¥,ä´gAMA† 1è–_$PLTEÿÿÿÀÀÀ€€€€€€€€€ÿÿ€€€qÞ´øbKGDˆHtIMEá‹ß?-IDAT8ËuS±Ž1µ-íÌ6:ª·‰ê¢E¢=E èàhÒ&‚TÉ5n9Dúû€ûSæwasÖÆòúå½ñ¼}!„?¡Ž¨,¬¢¶£‚IÉ·CÒØcwv£Ä,3€xIIŸ¯>pv±2j·sàY)Æ`¾…¿À•‘J¡d[¯¼h©ÓA Y²Ï×`T©žX ¾‡’Ü;­€(þ eÏWm–Ý@\¬'–7PŸõKºÎœ³·f}a_’í«JVyd ÉbŽ¢ª½è`ÓijQ£5 Àšzž6ÐË=[—Àû­±¹ìàùüÜFë`»eŠeJ±Å[0ÔÈ r@ 1 ë¶ú·†@ÊÞA´Ùí¤ˆ¸T5Yñ§›hë|çRð#¤oÇŸ/Ý ‹õ[õSEF—êÚ¤Xœ_çl±er¤ú:† ÃÍyé†o—ÜÄh€ôïÔ€æ;é`ž…ymPϯŒ¯ cAͶÁ«ÙµM› ì§ÀÊXºÔÜ€M ÅÏ df<àTw(ž>¹%}Œç>WüŒâ°¬/®p\Hñâ¸Ñ Ç#ÌŸÞkÚxÖøC;$ vnQµ¦,h­Ý ‰ÈmˆÕ.\À-´_¬y¼ò‘j®|£zÕžäQËo¢"§ ¥øTj`ÐÄIqr8>’Ê'5h"EÓO‹Œ²zÎÞ·š ˆO4g4ã"fMŠàx|Úð¿ñöbwHz|#%tEXtdate:create2017-06-06T01:31:26+01:00ã‚à%tEXtdate:modify2017-06-06T01:31:26+01:00’O:\IEND®B`‚puzzles-20170606.272beef/icons/mines-48d24.png0000644000175000017500000000724213115373736017401 0ustar simonsimon‰PNG  IHDR00Ø`nÐgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEá‹ß? ¦IDATXÃÍYkp\Å•>çtßÇÌhFk$Œ$#Ù2`¯Xc*8ˆò¦œM0ÿ±BIÅâlœâT¥ ’J•üXQ Å«*PN*!¡ŒC•œÂåEÈZ?0µÈvQÆÙz{ìÑÌhÒ<îíÛÝûãÚòH– ?v³é_3}úö=ýõw¾sº/ÆãqøGjüËÕZÿ¯¿oäÐõ^©µ&"Ã0nàëµS«RJJYiãaˆ¨µDеD Às'™L‘TRƒ$$ÿAƘ”¤–³K' ÿ"*¥@JD Ò~§mÛ‘HD1ß!­µauuužçÖ  jÓD)AkèííEÄP( €Å,p”SÿñT*U[[ˈ…0C¦A½bÉ+1ÆJ¥R±X¬­x‘ˆBÇÁ™"B!ÄâÅ‹c±X"‘˜Å©!DÏó& 0 €ÖüÄ š‹ ;788xÿý÷í`×ù®žñG9.yð[­ßòÑr]·å––¼ÈÿñôO¤O„xèÉÛŸ¼§é¼™é™tzªµõ–‹åË/dž‡5kJO?.—I)‡ç1‰*·€ˆ²ÙÀž=‹¶n­[·Î8w‚Aåyˆ(=9SžÙ;´7Ìžë=Ûól×`—©Í²Sö¤†2CÆ, -ˆ|÷ýïe†P¢+\Ï“R:ɤœœ”lÿ~C)×u…ëºþF/LjÔ£\.º}»ÕÛ D ”&B­gýgÄ^þ———„— æï¾+]J3b€@HŽrn­¹uçúËk–wVwþìß•¼#DàºléR÷/¹pß}-Èú캖æWÒˆ ¥ª®Î¾òJæ(nØà€RW€›ÛñB|ûíM‹š6¶n,ŠâUj# Á}ãû~ÝÿëÍÿ´ùöèíe¯|Ū¥„TŠ•Ë¨ø¸,y4ï?jíÅbÓ›6é={ik;)DQ^qÈ cZLÿ ïi7ýAÇÍUÍŽrüW*­,ðiòÓÇ÷?Þ±¬cÇ¿îÐZûkð'f êë¥eiËÒµµ’1¨€~!‡|¥RAΫ¥ùì³þLæ|"²m"Ò ¶õm;|æpK¸åçÿýóƒ;C<¤´Ò mfæÛûXq¦(´ØÚ·õTæ”Íl¥•ÖÀ¹žšbO?½xdÄ?::ºjÕª…IMD¡@ÀˆF9²òÁW®_¿bӦؑ#fMmš†a …d&“H:NîСҫ¯¦R©©LæØ±c®ëF£ÑP(ÜÔ;|8ÛÞ¾·³ót, ‡#ápD)•žšJ ‘˜+½òJöèÑl¹|æôéÑÑQ˜›Ôç’Zkåºn}ý…ßüFÕÔ,Ù²¥ú7òë×k)µRdšf&|÷]{ß>sÿ~ÙÐà<ú(#2 Ãóý´Æ.g›ËëCÛf/¼Ð¿e˲þþIÇQ–ÅK%ï² awwÞ~çr¾Ü¾@”"Ç)‘'“~æ",•Ä]w%÷íK:tñûß?)„VÊŸO)‰˜»wþùÔ¦MˉR±(’Éc XVö·¿½tüxöõ×?«®Î•J׫žæ;¤3‡‡ó?<ÞÕå¶¶VïÚE…‚öÁ ÇÁb1²vmâ¹çþͲª#F¤¯`49Y+lذwx8âDâÕW?‹D,)/£ˆ¹ÕÖÖlÛöï«Wa¬Ö0¼… ·¹[&¥ªªª}íµpo¯ …ŒÑÑ©íÛU(„ù<(¥QxÞ‘ÞÞ]ï¼311±k×® 6øºW(ˆŽŽ–¯~õ¦@€oݺ? ýøÇwLO»Œ1ÿYdìÂÈÈ{ýëÉ'Þïîn¿÷^¾TÏuˆˆ …©Ÿü¤´v-–ËîòååÕ«±\D¥µaœó×^{­§§gfffÅí·wvvf2™¶¶¶b±¨5TW[uuÆè…Ú ƒÅbv©$ˆ@k]SSÓÝÝýÆoLLL4·´xî¹çžzê©kuãñ¸¯C©T*•J-iZâ€V¡€F$ÇeÅyžW__ŸJ¥Ž;†ˆÁ`‘”ÒDà8N*• ƒíííB¿Š‰D ­afFhÛ¶«««/„ ¢L& q"Ìç"ƒÁ5kÖ477 !üúYJD±Q¹\–R®^½šˆ´RZJÐDD~Ø/Pä#¢”²¶¶ö–[n™.MŸÉžI—ÓÍ5Í+£+Ë^Ù4Íááá+VD£Q!<Ó¤äÌŒ·fMe1!¼¦¦&W§X$" ‚mC¹Lå²Ôú“þþuëÖÙ¶­„Îu0ˆP,D‰Dbxx¸±±±’Is¢Lª2ªvœÚ±õ¿¶þòè/ÚóÐ[gß !Ê?W”JŽeÁÁƒ7vmßÞ399£”B(­Ri†±ÆÄ'ŸÛ¶Ñ‹/L3—NONN@6—›"Êær¥Ý»±££¸o_^©‰±±l6{£°'¤’Wúfã7ß{è½¶|ÔXÕ¸ûÌn ¯ –ÅÒéòK/[µêf" .W}ˆZ£m‡ººýë7ÝxÇ>6F¦Éˆ8çHÄ•ŠþêW7··×?úhÕž=¬T"Ã08÷cðº! §¼¶Emm‹Úâ…x²¼§é R­!äÇÖ­kzòɹœS[kWÀ«T]hk“õõà;¾û'E¯¹Ù[¹R…B³¤ùRJí×~ý“ýßߨ±¼ãwÿbFÌ’ÖÚ¶ÙçŸgººÃ>÷<µk×9ÿPé'çk_›üÝïòüÁcíÍdl —³p^øÞ÷.½óNî£~ßÚ:8=m,xLžË!­c,ÚÖöfCÃY˪6 ½P•ÏçÁc’¹|Ù+_(]ØÒ½å+u_yëoÁå N56Fþô§oÔ×:;¿þúg/½´Ö^_S=¥z>üp_OÏî®.O©çŸþ‘Gáœ+¥8çÉdòÝ®®žîîOþtZ+uÛm·}Aê@Àiwú§ÿüÓ¶ýP)è—Ûþ–#B*Uþö·—oÚ´´ªÊB^éÇñññ¾¾¾B±øðæÍˆ844túôi"òöÇ?zôh¸ºú©ý¨X,=z4Z–µ°Cþý†eZÄ)bG¢õýS „œó@ À9çœ#úZÌ£QBùâ&„øøã3™ÌÆ9ç~éÈK§Óœó\.wèÐ!˲žxâ _ð|\/^¼¸lÙ²R‡ïç<‹ù«©8O#æ8N&“ihhð<ïêþj@ÆX&“€p8ìyžäì?#ÕÔÔøWi%"­u6›]¸È÷Y¢”J&“•ûªµ¶mûÔ©SþMÅ¥K—*k<ßzðàÁ;ï¼Ó¶íl6[©+ˆèºî‘#G:::òù|å=ÖÚ²¬‘‘‘D"1O©çWó„Á_“ëº *‡Ï-×u}¢øY³’žçùK—RVZýÁŽã¨Š£úamÃ+­²çÚ7x/kù“,øì8tm›á^<ÞxÀ—¨©ÿ¿ÛR/€O£ëqh¶§òw¥µrž9WÔëºùf˲ü€œí´mÛ?y‘mÛ•…°oõãÎ0 Û¶cóÛ—Ó4çùjÛ¶iš_€ëºÃÃÕÌ÷ã3×ÕÕMOOŸ={¶rjÿŠbjj ‰ÄÄÄ„a³VÂR©$¥u§!Ó4ÇÇÇg3Ï|‡|x’Éä¬ÍÞ¤€mÛ ccc™L¦!ÿ¹©©‰s><<ìëP¥U)uë­·f2™D"áoYå´DÔÒÒ2Ï¡9J]__ÿDÕ·…¯c”R“““׋Ò)_i½AxߨJD•">‡Ô•©êïÖnôiáß+þníNÿª$x†9LT%tEXtdate:create2017-06-06T01:31:26+01:00ã‚à%tEXtdate:modify2017-06-06T01:31:26+01:00’O:\IEND®B`‚puzzles-20170606.272beef/icons/mines-32d8.png0000644000175000017500000000302713115373736017311 0ustar simonsimon‰PNG  IHDR D¤ŠÆgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<éPLTEåååâÝâççëëëëçéçëâëíóóðïïö÷ìßàØËËËÙÕÙÓÓÓÒÍÓßßÏÜÜÔÖÙÖôôôëüü¬¬¬³Æ³‚¯‚¨¿¨ÑÏϺºº¡¡×ÛÄÄÑÕÕÙûûûêêäèÅÅí‚‚õ33íÇÇÔÛÛz³zW£WФĤÃÄÃÜÛÛcªcN¡N‹ÅÒÅÆÈÈiiïÿ¯¯äåå×ÞÞáûþ££¢ŸÂŸÍÑÍ…³ÇÇàÙ×%%ù§§âäëë§\\ÛÆÆ>š>½Í½,’,µ¹¹/44{{{FžFHGµËµââÜ??õÇÇÝïî𧧨^SS`\\ ŸŸÄÄ¿ÃÏþÝÓÎØ¥¬¬ôîòøöýË»»ÊÆÊÙÔÓöòç÷ûïËËÕÎÔÔêffézzìÛÛ±­­˜˜½y{¯çüüæ¹¹úímm×èèëããì””ö;;ö""†$$äËËðuuòddã÷÷´´´Õãã圜aa§{{³88—óûûòWWº¶¶|UU44•}mmÎÛÛ………ˆˆ¸..“MMM///Üãã“““onowssÉÄÅÈÈ¿¨Ç¨FFíÖÖ4“4ÀÀÏôKKñåñZZ¦¹¹Ìì??h«hmm­rgg…µ…ŽŽŽÿÿÿå+CbKGD¢°ÝߌtIMEá‹ß?+IDAT8ËmSûWGžäÎn;È‹î´ì†H™ñ±Ú±Mi‰i%mPSQ­D‘F*ÄG1´6n±•Öšj©>ÿÓÎì¦?ôœ~gϹ;3ßùî¹÷C(D$ 8ŠÕ0D1€¦Ž°ƒx"iD "†Ž}„˜ ”ê]:Åéހ،ØßM’Œ¼ñfq\œBhoú`_ÿ@äÐà[C‡=&ü½¸ùäœËPÙÍýá¨šÛøsR6ºâ{;{%J³m±(nùë SØH– ‰xëïÖ´ð[ö<(”Qä”Â,ćq4>› Û z #¨&©ú_0)ÂѲ¬Aµ)H!Ôì“ðÌP“,ðŠ$(gÐ`+éÑ’ ÜT<©8‚©^„ @<Šdç<³­üv‘Ë’ ÇËsÔ*TÀPj Äg>³ìdƒ1f¼Á ìº[Œ5B_ÈÛÍѦ;§®éºô?!toàf*  ½Â¥Ð¿ÐÐÿ#ÿ¨n™x^zo?%tEXtdate:create2017-06-06T01:31:26+01:00ã‚à%tEXtdate:modify2017-06-06T01:31:26+01:00’O:\IEND®B`‚puzzles-20170606.272beef/icons/mines-32d4.png0000644000175000017500000000106713115373736017307 0ustar simonsimon‰PNG  IHDR TgÇgAMA† 1è–_'PLTEÿÿÿÀÀÀ€€€ÿ€ÿÿ€€€€€€€€OÃó0bKGDˆHtIMEá‹ß?9IDAT(Ï-Q1R1Ûu™JòeR¤ÂG˜ÀÐä’Ìð†žÂ ¥!iùOC2ñùîìµ´«•#‚P#¡‰HMÖd:FdDNÉÕ>Ë3¹hÞSöB]!_„@´‚y#F¥8šÂuòв>^(QߟÊ,^™‘­ÕÕ_ ­"£ Q@«º¤)îHG×änSù¸žºÌ­Þ gKbhEˆùËåù1ÒJwˆûš3äüG‰™™Çæ^õû/ë½tÙ=PŽ^Æ(°J.ÕË.Q]qCž¾‚ “›-ÉÏ3¢(—\΢äÂ;x«¤p8©öG¬]Ö.¦©vXïe ;~ ‹1ÌK:nEð=id?¶u† \ì²õZ´ ¦tûh0M±cµ_¬›Žèmú~º½Tô;þã#ôHÃ;§%tEXtdate:create2017-06-06T01:31:26+01:00ã‚à%tEXtdate:modify2017-06-06T01:31:26+01:00’O:\IEND®B`‚puzzles-20170606.272beef/icons/mines-32d24.png0000644000175000017500000000452413115373736017372 0ustar simonsimon‰PNG  IHDR üí£gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEá‹ß?XIDATHÇ–]lÕÇÏý˜™™µ³ö®½¶± )AvZ‚IBT­D"ñÑ žEAÊ‹«BAˆV<@hAEBmT9‘qÄG¢š6²I7‰•8ll¯½ÞÏìÎÎǽ§ã'H¨íyÝùÏ\{ÏùÝsÉf³ ¥„5†ˆœsιD)Q ”P€€€%%”Y"%AÆ@ß÷ !À€Rªë: ‚”@)Â[ZZªT*ºªÌhˆ†8„D:Ó#,R jžðVD ¦)ÃZ* O&“žç•Rªªªë:ÄãDÓJFêlнT¹ôÞ…÷Rù”B”@ù|ž IåSïžw¦:£Rµá6 …"c01¡ŒD«U D B, w@€â¸nýÔ)æ÷ÞÛH§*•åJ%Ñš8¹trÒž|êôSg¬3­º¡k†v¼püÌò™}ÿÚW‚R|]Ü0õh´éôéŽçŸ_ŸÏ·¶µE #º:†œrnœ8Ñôúë´Ri„ `Ür­ý÷«TÝòáÇsP¢”RñêO_½\½¼ë»<á¡D!¤â™grããz£!…RŠUaêú¾õä“liéý{— URªT-5J|üÈ£î¹eOÕ«€¡g‹gÿüñƒ?;8Ð2àÎJþ¤$Ñ(2°ÆAÈŒW(Œ~üñ+.üel¬^­N Å>=|*{ê«ÂWG3G£J<}âéìrvdf$UHé\G@ÎÉK/µg2ÊÁƒ‰LFÕ4D\q@æææLÓD€±cÇÆ#ˆ¨(;î¿_Qø]C›çkó–o-»•þu·&õd¾˜Ov$¯ÚWm·f{µŸ´oÔP[È-tuu|ó ß'ëä¶´(½½}…BÉÂÂBÃuSgÎ4šº»‰Ô¶Ëù|GgçæÍ›YœrÑ]·HjjJQFš›5Má‹KU/𺺺â­q7@Qg [ÄbëŠÅâÊyª,,ômØÐV(D‰„µgèïoomåŠR7UH¯\RÚ“‹¹\©TØÑq||öÛŒýèÞ ¤³£Ã°Í]ªr‰&Û.?wǦM”Ò ("rÆ(çÔ²dwwüý÷ãGŽˆæf¢Q«‘·ßŽÞÿsã—;]Û.•Ëžç·´˜ YïÅߥFþv™1Eå\Pæ^¼¨>ûlóàíüà«6çåBáú$B§~÷Ý´Ñ ®ë ÏJ!¬P ß~Ëj5`Œ1J\78tèß=v{K‹I)H))£Ì÷ÙÜËåˆ@ãüzL‘15“±zÈÛ°¡éèQT‚(óŸ{ŽÌÎßwSθ¢ÒÙYûóϳŸ~:ÿå— ãã³f³&×»õÖȤŽ?¤ëÝ‘ˆ¿¦²ñ`ŒFÍÑQãèQZ¯×ö+u]×´oNŸþÓØØÛ'OFÚ±c‡$™4ŽùÅÄĢ㈡¡¶†¬kæJ£~ldäÏGŽœO§ÆÆtÃXå”äóùÅÅE)¥ir©(£Q².†–ho_*ÇÇÇ/_ºl&¼í¶Û¢ÑèÐÐ¥B t꾦+4§R©Ï>ûÌsF©‹mܵkW¥RBB¡Ífsù\b]Bሠî.û }ß/•Jœ+ñxç`ÛA¹Tüñ`_ïÍnÝ¡ºN4êŽç{A,W*M¦IL ‘¶]µ¬õë×—J%)%EDìíèÓÎþæï7Éž›zgï¹ghzš gÚÚz¶l½«ç¦nÇ÷-1¯÷NœÒé4 ÑÙßϺ»Õ……È… zKK±PïD¼VFPJ”¿ºý×——fÞšz«IiBÎe&SyóÍ©S§f-«ø^@ˆ\\4÷í‹÷÷›/¾è)Š[«œ»_m<ø`lp>\cÌ®VÃZ½B%´Ôwß¼{Sb“àâ¾A8g¯½6µ{w_ww¬V (£tÝ»óNgëÖšª‚„Rб˜·m›sË-`Œ]‡©Dipã‹Å/¶ý}ÛÖö­wÄï¨u…1Ûös¹úèhfrrqt4£i! CÛ¿?ûÑG¿M$â‘0†¾tt4¿ðÂ?ßyçJoŠDüÕRÀ8°l/Üødñ“+ËWêAÝöííÛ‹Õ%Ó0~¸ûöŽ\Î}â‰A]§¦ÙÄ)ýë_¾üòñ‰ ÐÕÕÕÑÑA¥|ÿðá?¾ñÆD*Õ‹ÅãñîînÏó¤”+˜ )±EêK_¢ ù|¾¹¹YÓ4BPU™ë )¡µµåܹsSSSB]×]×M&“[¶l™žžN§Óª¢0Æ„”===;wî,—ËB2??¯(J4R `Ø@ø¾oYV"‘AH‰œ³z½(ŠB)•Rr΋Åb4EDíÚ%@)‹½½½årySEQ|߯V«5«f-[Žãd2™l6+„¨V+–eYÖ²ã8/^,—˦iz×LJyõêÕ TUu]×÷}Ïó|ß¿råJ!¦ßU%@À5~-,W¡A”RD Çàû¾âÚÅ)¥”«˜®qðƒ¶:!‡¯k7<¯¯¦ÿ…áò~X¼ÁøÚE­]B¸ÍU‘RŠ”Òµbºµâµ^ïz333sssŠ¢„Û¶Ý××wþüù\.·*Z–ÕÚÚ:99iÛvèâ8Žã8étzµ»ED!ç|ªùùyMÓ¢ÑèÚþ— ø]4)¥”®vµ+•1™ùnÕœ‡°""'„xžW­V¿ÜÒõ?‰«ø­„è†Å~?”ÿ‡þuyó ÷¸*Î%tEXtdate:create2017-06-06T01:31:26+01:00ã‚à%tEXtdate:modify2017-06-06T01:31:26+01:00’O:\IEND®B`‚puzzles-20170606.272beef/icons/mines-16d8.png0000644000175000017500000000217713115373736017320 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<aPLTEçææëïïèüüëîîßÞÞßÝßæàæÚÛÚÝÜÝåàåÚÚÚääÛÝÝÚãããèèçïââ÷žžãÓÓÃÅÇ“º’Œ·Œ×ÐײŲv®vÄËÃÑÏÐ}}å¼¼ÕîîèêêëéïïôÚÚæVVϺ¹ËÌÑŽ¼s°ráØá¾Î¾V¥WÄÎÇãáÕttî§§áööêèèëíììÙààd‚‚†ŠŠËÇÉyµz›Ãžž¾Ÿz·vÐÒÏÔÓÑ~ퟡãõõëèéëßââÀ³³È¾µ¶øìóóæéÊÍÌÖÒÓ¹²ÍÍÍÎéêëöîãíæßçèéëêêÛÜÜØÕÕøQQè§§êþþ÷hfõ……Å×Ò¨¥À78”ÐÒÚòëéüRUë¢¤ØææíêêÛßߨÇÇò]^ᨧðýý·¨©‚rsÆÈÄ›»D@—¾¾Ï÷øôŠŠ‰áããëëëÛÝÝÊÃÁϾ¼ÖÕØÍÍÍŸ¢ŸŽ’‘¸¶¶îöòàóóæåæÝÞÞ¤¼¼¤­­ÞÝÝìííÞÜÞÆÏÈk°pªÂ«ßÚÙ™šÁ†„¸òùñí¿ÁüÛÚÚäààÿŠŠðÀÀÜææìêêÉÏÈU£TµÊ´ÖÑ×LMžUTœíòíïËÌÀaaÈÈÈêççÖyyº––ÞååâÞâ¿Í¿‰»‰ÍÕÍ×ÖÖÅÅÓ­­ÈîìêÂÊÊdvv¦¥¥àáá““xìììèéèòðòüóüôôñôôïÞÞÞäããîëëÜÜÜàßßëèèæääßààæèæÙÚÙÛÛÛêêêããäÒÒÒÖÖÖàààÙÙÙæææÓÓÓ×××ÝÝÝÎÎÎâââáááÏÏÏíííØØØçççÿÿÿ4~mbKGDÊó´6ætIMEá‹ß?IDATÓïþ   !"#$%&'()*+,-./01234%56789:;<=>?@=ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™Kš›œžŸ ¡¢£¤¥¦§z¨©ª«v ¬­®¯°±²³´µ¨kk¶·¸¹º»k¹¼ ¨½¾¨k¿½ÀÁ ÂÃÄÅÆ±ÄÁ¼Ç¹½È¾Å È®ÂÈ ½¾ÁÉk¿kÇǨ¨Ç¨¨ÇǨ¨Çk¿!lÍ•¡uâ%tEXtdate:create2017-06-06T01:31:26+01:00ã‚à%tEXtdate:modify2017-06-06T01:31:26+01:00’O:\IEND®B`‚puzzles-20170606.272beef/icons/mines-16d4.png0000644000175000017500000000051013115373736017301 0ustar simonsimon‰PNG  IHDRíÝâRgAMA† 1è–_PLTEÿÿÿÀÀÀ€€€ÿÿ€€ÿ\('CbKGDˆHtIMEá‹ß?\IDAT׌A €@ ÏÉ¢÷­‚ÿØÿÊT(%í h(“å*5f²àÛóa-3¼v_X¬W7aoÕ.ÏÓjt”¹þ¶9RHPtd&1M¹£¶ì&ޱÍQq/Ô2í%tEXtdate:create2017-06-06T01:31:26+01:00ã‚à%tEXtdate:modify2017-06-06T01:31:26+01:00’O:\IEND®B`‚puzzles-20170606.272beef/icons/mines-16d24.png0000644000175000017500000000243613115373736017374 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<PLTEçææëïïèüüëîîßÞÞßÝßæàæÚÛÚÝÜÝåàåßÝßÚÚÚääÛÝÝÚãããèèçëîîïââ÷žžãÓÓÃÅÇ“º’Œ·Œ×ÐײŲv®vÄËÃÑÏÐ}}å¼¼ÕîîèêêëéïïôÚÚæVVϺ¹ËÌÑŽ¼s°ráØá¾Î¾V¥WÄÎÇãáÕttî§§áööêèèëíììÙààd‚‚†ŠŠËÇÉyµz›ÃžáØáž¾Ÿz·vÐÒÏÔÓÑ~ퟡãõõëèéëßââÀ³³È¾µ¶ßââøìóóæéÊÍÌÖÒÓ¹²ÍÍÍÎéêëöîãíæßçèéëêêÛÜÜØÕÕøQQè§§êþþ÷hfõ……Å×Ò¨¥À78”ÐÒÚòëéüRUë¢¤ØææíêêÛßߨÇÇò]^ᨧðýý·¨©‚rsÆÈÄ›»D@—¾¾Ï÷øôŠŠ‰áããëëëÛÝÝÊÃÁϾ¼ÖÕØÍÍÍŸ¢ŸŽ’‘¸¶¶îöòàóóæåæÝÞÞ¤¼¼¤­­ÞÝÝìííÞÜÞÆÏÈk°pªÂ«ßÚÙ™šÁ†„¸òùñí¿ÁüÛÚÚäààÿŠŠðÀÀÜææìêêßÝßÉÏÈU£TµÊ´ÖÑ×LMžUTœíòíïËÌÀaaÈÈÈêççÖyyº––ÞååëêêâÞâ¿Í¿‰»‰ÍÕÍ×ÖÖÅÅÓ­­ÈîìêÂÊÊdvv¦¥¥àáá““xÞÝÝìììèéèòðòüóüæåæãããôôñôôïÞÞÞäããîëëÜÜÜàßßëèèæääßààìììëëëëëëæèæÙÚÙÛÛÛêêêããäÒÒÒëëëêêêÖÖÖãããìììàààÙÙÙìììëëëæææàààÓÓÓ×××ãããÝÝÝÎÎÎâââáááÏÏÏÜÜÜâââ×××ÖÖÖíííêêêàààØØØÙÙÙáááÚÚÚØØØÞÞÞÝÝÝØØØÚÚÚàààÙÙÙ×××çççëëëæææëëëííííííììììììíííììììììííííííììììììíííæææÿÿÿÕe‰ëbKGDÿ¥òÅtIMEá‹ß?IDATÓïþ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýïþTq”×ZY%tEXtdate:create2017-06-06T01:31:26+01:00ã‚à%tEXtdate:modify2017-06-06T01:31:26+01:00’O:\IEND®B`‚puzzles-20170606.272beef/icons/map-web.png0000644000175000017500000002602113115373721017041 0ustar simonsimon‰PNG  IHDR––³cæµgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEá  ºØ+IDATxÚíyp\Çyàûëw¿9pß R¤DÊ’#Ÿ²EÙ–lÓme³ÙÚÄvþÙªÝ8ëªì®£8¾ËÙ›Ôfk«’XÙÊf½±.Z´+Žlk­Ø•8EŠ)oÄ\3ï~ýí=3˜û ÙújŠó^÷ëß{¯¿¯¿£ann޼%of¡;Ý·d«"fýŸ1¶Ó]zKJ¥^BÐ:ìPÏ‚ªm‘T{<"D’u4xßvðžX–¸Ù£M„àºîôÔÆØöN#¥0Ä* !À÷\ß÷« ˆˆ‚ PQbŒ‘MŒH)EF|Æ€ìÔÛO:4Ø/IRŠb!cLèÓSW¾þ?ÿKï`›ãxUßÎÕõL–ÅÛ³QqÖèëjv\¯¢!C‚²$Þš_zûþÕû ÃÈzÕƘ®ëçÏ¿~óåSÃ=–ã"ª²85»Ô2#{Z,{[¤Ð(iªxþòâÃÿú÷œˆÇ—™öÂëjÛwpÀ2 Ûˆ¡¢É’&)¸>6ØmÚ­d¼ ªÈ”àÛî¹çÝïzçúúº åîû~8V5M¿úO‡Gûã–Cb@•E Ýôî;zâÆ¶H^a C™þV̹ؔ€c{–騦 Û¨«"C‚ı=p=ËqmÇ«èŽG$„€ãzñx|mm-‹UúÄxXééê´’üR£a9^W{èPëàÓÏLÆm[‘EÆvÝ ^öëŽR*Bj½ŸR*Š¢mÙ°Všb}®®ú'cLMñ£+Ý]†eç¾<(€i¹Ým»šbY3¥4—"c 7… $$ñ¬‘0V/~¥ø%¯ŒоŸ0¾ªûÔa¹¦}:Å?ø³/-àBOo·çyÜ’BDE•dY%QUdÉREo0Ó0ã†J$²xÛ®¥ý (ʺiãKóË¢HÈàÓ''Om ëžÏªœ1,ÛËÖ~· ¬ÎpŠÁ°öÛÿþ÷þû_þþÅè¤(&ƒpH<øe>&s\¯²ÞA$¥ˆï3H†Œ¥®c ý¿ù¹/ÔŠŸ@iÌ0þúO¢Ý]%ù%¯=A‘±=÷wWiõÝj¼"@ˆÏØÞfU–œé}•-°QJ-ˆõÿøï~çô«¯P ˜Ô4í7Þ°öZ‡6 * Ü@dš¦_¸ðºëywÝygêpâyÞwnlÕdý5]åÕ3Áèõ=ûGWcñòJÁ°Ýîö¾1xå§KBª) `ÛÞ¹³SÇ?6¢I’ãú[Wq+^#¥”:Ž#ÉâûßÿþÔ‹1 ƒÁ`<?zôhÊ&)Sc¡PHÓTÇqÞ÷¾÷¥â— Ã0M«vëŸH)PQr=¯Ò‡€ØŽÔå{öõW§»!!’(\›]~úäåO<²O­Åj–¹yŒÞúúzê7Œ1ÆX,3 ƒÛ$•"dŒÅãqÇq¸%“æp@€ŠcaŠw“+jÕ];c·œª›G {;ÙóÔ3—?q¢«÷Td +Mn“Tz¶,©ºceŒâVO°¥9 À°ÜÞŽp­(V?R,M‘ÿ»Å¡áç©Z*Ê-v¶záÊQoGø@Óž§ž¹l¹®" UÕ<…<|=¤˜ñÉL×uÓ4·rmš¦…B!D¬î)´,«$È„S ÖæYe’¢HÈž§N^þøñ}Zµ:jÅcŠ¢†qæÌ™Ô„ÇcÚÏ;×ÛÛ[µ¹C)½pႦiñx¼ÂàtÓŠ+>###š¦¡ÈD1Q  ɺR‘ |çù+|lD…*(V†ó‹ÅbÏ>ûìž={(¥|ì!¶m÷ôôLLT€D)µ,kïÞ½†aD£ÑâÐuýµ×^cŒ:tˆÃæ¿<{ö¬ëºï|ç;3µ¡Œc5U]^Yû‡SODg†z:4Ev*×Kk(ÜPéíh–…'žºôñGF«˜+@ÈùÅãñ'žxâèÑ£¶mg­ ›¦éyÕdp ï{ßûŠO¨Œ±p8¬(Šçy÷ßÿúú:G‡eYŽÇãÅ:/ˆíþ·¯}>ì-4í8õ³ ÇîžÐTe‡)˜¶ÛÑÜï T§Ý”‹0Åï[ßúÖƒ>844´¸¸˜{³o%Ã1–n¨ú"Æãqß÷Sæs–É/èÌ·µ·#²¡®S§/;²;(:Õë¨ei ¹ü666DQ̵¶¸îGËAøR¦’Éo®³£ÃvÇõZÃÁÁ®S§/š–-‹bÍWŸ+»pÈÖQeI(Ó%Ra^~Û+–×ÌHMÀ%¿ìyž¢dð3m›ß–ë¶6ì&Šù,,—²<™'åd;(±Xì‰'žØ~‚ hš–n½ƒA]×c±Xî—5M ƒÈ(I†,¯¬ÿÉ×/Ån”€å¸­á ì:õÊÅ™Ð5Å­j"¯•dZ“'Ž4uŸ1H¬b]—UED’±´T¡ †aœ:uêèÑ£ÛÌ1¦ªêúúú«¯¾šn½sçÎ ç\?½øÆ%M¤Û$@é '¿°f;;;Óù%°]·% ÃÝ/œ›|èÎ}²$Ö(ÁªJIQdØÿÂw¯¼«Åq‰¦ŠWnFî¦ó sQ×õóçÏ÷÷÷OLL,..Šâv$³‘$¿•••çž{nxxØó¼Dl+¢ Ž“½D‰ˆT^:ùøÕŸ>·éêð}¿§­!ÜÑnÙJ<üÕcŒ§ùï¸KžRˆ[ÎposäÂú·NÞìïh¶]€ YnÎÇøxF~Ji$|æpgÛbÝ9¿µµµ§Ÿ~ú¡‡q‡¿ßø2,ËYG!âžž¶ñáËv“LÏw2ƒbÒ‘%q-nMNÞúÈ]cAMqÜÏ©'¼t…Ç@ {ûÚ‡zÛxÚ3"Q aˆé},ë©*¤>ÔCRüž|òɇ~¸¯¯oii)u÷¤ŒŠ|ýÇõ,ÛM"ÜŽ¢üÌ©©Ùo j–»“¦EöÅBØžkÙn !AÌu§oÓ‹±LÉå‹Å²ÞÞܨȻŠ )AÎïÃwí6~›WDÒ¯ùYßÙEóò«L{*oÛq~ykëTýžÛ-‘ë/O?ýtuüP('¯_–ÄÕ¸959³#ïO  ÊRn¿lׯNÞ-AØØØxî¹çzè¡êø1Æ<×E1k.Ìiˆ®ÅÍWç™êêöó3wj&’ñÌ!…¾öfIª ¸+rkïÌ™3######KKKY/`šÖèè>±©þöB[[«U¸ø` I¤¸½CÔdéõóÿÈÖzz[]Ç%QR¤™+ ék· (ÏEd·äÄr/ "Va½€çû áàg>÷•(i^ZZR¹Ðj™çûM!½wOÇɹ`ZŽ"íÀºÚÀpçèþ¾áñÞ½ã½Ãã½£úzö´cn¿òd· $Éò4ÕÍêÀ²ìÆpà³}u™£Žëµ†ƒÃ]ßyåbܰ·Ÿ¢c»–騦c[Žm:–Ḷ[õÙvÂ- ¥Ô4­†P೿[š¢åz-¡Àžá®ïœÞЉ‚WÜçd l?? !‚ dP\\R%¯‚@óQô3²D*Ìý¨ôÈù:OMÉìAYgzó!äKEòÛ›ûê2iŽD"é¥;3®<â«7âVXWUYÒ9í“õß‚]‘Ë™ ABTYÒIOS•Y,â®ÐHËƘ$‰ ÁcD–$ÆX®îÃ)6†ƒ¿õ¹¯üùŸ|5_)•¤ÄÁ®_Ÿ>ÐÓî³ £›gw”ó8@_G“,st ¢(PÂavõc$dj&â2–\KCM–®Í/KÍ’M¿™2Æt]_X}õ'O!óÆÆïhmÖ Ã„<ã†ÑÕÑúã¿úìŸel8hÙùË=pSs(  Š—"+$êDò*··æ—½«¯u³ø@Ž Yo]‹|0û:,;¿UÀ5EŽ,®½n®÷w¸É¢½@Áu¼®¾–ÛËÔ!˜:'»µÊÆËx ß4cª*¯m8ó—_zϸ À7¿ñÅó_l)@‘R깞çØPÊD×ó4YìN½ê¸[؃á¡}Ý–é@a_•ªÉˆ„E°P1c†¨ÈÒÚjüÙkW{ß³WS$7Í%Â+êŽìïM=Àˆ¨ê2óÞ,—ûæ@¸Éï/¾ôŽñÕÖÖv‚ä½w,}óñ/þê§ RLÔ6-C€!Zö¦’¿×sl×2Û*X˜'<;¶ “ó[_ûÊ•¾ûGt5×¥… -ÓÉ9§WNçßêL:¿ûÆV»;;,˱l§­½íÝŒo>þÅ娡ëÊÖ·g€l!)¥ÓÈ•ä_ów>—_ºçyN[ž¡±Ûfóëê0L›—é5M»=¢¦)žçeJm*é¤bm½°dÛ,3H)ù¯Ï˜šË¯Ö53vË‹”› Ù¯DUQV׬ÿóø—Óùñ¿¦Q\üæã_ú•O}¾¯»55Çø‰4M–DîìÞ<7×+í(ôw•MW2T5YVDUuE‚äçX\\{öÚÕúñ#»!cL’$ÆXú.ˆ(t=f>õ¿¿þK£+Ý݆agEǦ(¾kbáÔßþÁ÷ý2óí„Ç›¡®ëçÎ_˜]ˆŠ‚è8^JÕ ­’TÜ ‚@INÐ8¶;s=’:2"«âü­åð:õ nÖ† >;[í}ÏÞúñ#»!wSÌÍÍ]¼xñرc©” TxæìùÎÀÁ={WV\……¤Q|§ãÕ?JåO3†š*-]Y2»±ݱ»OÈŠ4s=B–Ö†ú6 ew QQÄèòƬgNô¤ ~øÍ+·c¯Î÷v¶8îæm±K#oDWy„¢HâõÙÅöwíii ñ:VIÝa„©Hµgžyæá‡njj2ÓjŠ" ”€èº~ñòo¶ãjšvß‘=)«€1 dQ" dïD/· ¸@€àÔz!e!ʲ¸±f¼277öÀ˜ªÈnŽ9ÐÝ:<Ði;n‘“h²Œˆ†¾_³âye'r~«««O=õÔ‡?üáÞÞÞÜ´4®…$j`M‹Û郈„˜–ç8„»€BÊ ¬uq~±5óg³scŒ‡ª›/¦Ív=ËvŠì§Á€ãx¤þ©¨;†0—_Å‘29’1S2Bas׋„ÞO7ÚrG6ßl‚_ ¬dœå Ûgó»TÒsVv–áU~S®ÅÆç¿•••òË/,EÅP’´1HZzÂærŒ¢ˆkÆæóWXIžƒZ¸f‰oÔþ‚r%s·D]×C¡cLžÀ|ßOý212–e•ãa€P(”ÕŠ$I³³³Ï<óL}ùBȲ¨j2IêP5Y–EYUY&ÉÂ\ÿŒ.o¼2Wš!DI^ð+ QU$Y«|“!H€”µûXZIYDAΟ?ŸJ•fŒñ‚@†a¨ªšš¨ø6y£££mmmfÑŠæ`ÛöÙ³g³êU1Æ._¾üðÃ×—!0scâØ CYgo.ê·-BÈæBôجgŽ=0V’!äæü2ãQ¹…NeIœ¹½Ü2¬"@ "e±Œü´<µ¹SoNBˆišƒƒƒ$™€ÉÉ_¡§NúЇ>T$ÚŒ?į¿þúùóçÓËÔò§ǎkjjŠÇãuͳA C+8º@,¹G•‰%W»ÕxÀIÓGÃñ„þY€¸Ž×ÙÛ²° „¥HÓ!==­íï¼Á*ª‰¬Å®,O ô¹¥Jjg—”=xðà{ßû^ž]p\%I/g&ãIñYçä)Ýf÷$Bq¤§ýν½†•0*tU&„Øídïxoºÿ€8¶ç–Ê©à¦áÐXO™}p¯¢õ<ÆPQ¤•µøôK“÷ö÷J²èy¬ø ½¬a…*¤µÄ}ôÑ'Ÿ|²8EˆÇã95OÓ­¨Rb¹ža9†@H±×±!ei¤w©,Ï;¢]võ§ŠŸ?EZY‹OýðÒÛú´&M–äq³•#¢(Z–ÕÐÐðè£>ÿüó333Á`Ð÷ýümä“m˳­‹LgCž_UÐ([êÍlÅSÁ+¤(Þºu+ æú ¶,‰Â²Œÿ[þ'VsR¶+^­Üè)ŸUÇlÑ´O§øä“OæÍÔuÂá0É,ÛV²c, t]S¥ ž° *»€.kªHH¶bŸp&Ô™"_¦—d©t;ˆ‚(Dצ_š¬”Ùúê §ØØØxâĉ^xaff&ý4M»pá‚mÛ’$eäOP*‡G†š®½þúÅÅ+K¢(šVe‘ꈨ©âÅ©Å04cÚòÂzHQ@Óú”B†’,ÆbVdú¶ Т<ŸmL.ÝÛß[)?R“6J©išMMMÇíµ×Ò9ñšN„”ò‰ˆšª¾qyò‡'¿1ÐÕZ"«(Ð^^\«t¤¹evó¶ùŽÁÍ_€íy{:šÏNM/v66…4Ç®½ÊŠ´²»öòtŸ,YšßUãý½’"VÊÔj4QgV’Þýîwÿ&7U=0ýO©¤ê’=®æ‡ˆª,Í!B|Ÿ걡¡oÿhÞ³·±ÖùêÁêz|ꇓ÷öõ44¥ªK‰ãúžWO£fËÜ\eÏMÏÆòê±ù’ªk(œíxDV³úi»^¨A?¾wï·4MjJ1ÉϘüÁå{û{õ 7ì2/°BvSjì©(ÇÔ£¥”Br-¿nÖRëy}æPƒV[йü\w;v—ÙíáOµüÑø)г?š^Ý0eEd~žœŠrÛ`(+R¿í±}w! (­»mÆÃÞ!ÿîuY£ëF ¤)ª¤¨rê£j2-/ù[’Å•µøöó#;ãò`ˆ®cK¢P¿¹¾{"CI t„|ûùpŠþûŸÞ\l$>¦îû¬£·%RÝ¢¯YA ±˜yíå©{ûz¶™Ù~„`™æèèH kß­Ù›]ùêjÕª!×õ;[ÎMÏö¶665;_Z=°l·µ5|ÇJãšÝ?Òž4@˜?:7íínn,8Y"¢(K‘Éù=z8ÜÌ ³«·l÷‹|ÆtMýÌþ¢¡õÎß^Ð¥Né™>cAMê~þÌ¥õ˜Y(”ø>óMìk¿ûPÏ]wt¾£ûð=wîïº÷Hÿ'ŠžŸŽ®šŠ"ôÞ! Œ +Ï~¨­ìÀ\¶íèŠôÙßù²¡öÔ"Ïwi j{Gzž+L1¹p¦éÆâŽa8qÉŽa¹«kf¸Qÿô‡£ç§—‹PÜÑÒm;£‘RJmÇÑdé³Õ¢íz“½Jø@¨ey¡r(îœì˜Q‘—b= IÒŠj2';+¢@?Á΢¨fš©³äKÞÈ+5¾Àzà)·íMŠ_‰«ÝsóóŠ,mÅÕ £A×4E (r@‘uE¨²*‹…Z΢¸5‚amÓöÐdU“eERdIUdU‘J~j«¯îp47§¨Hâoþkÿ㾺²z+ro©¡$Åááîï_¼2ÑÙæc*üUYšœ]|ûXká~‚myáÆÀ§>0ôÍÝ|#Ò@ÓÂ%Eš½Y‰8Žï;®Ÿ¬¤™X3KÝ”‰xf€îöFI¬YíÚÏ© ɰÆ©§8®×Ô”¡î+‹+)‘Èž{Û²Š?”‚e¹áÆÀ¯š¼¶,PHvñ¡¥¤ÑbHtUó»ÛšBmmÖ[ü¶,õ} yVCwÛØp¯e§%0âx¾ãÖÑ~øÅ‘ú"äš¶ãz–픹}Ä[R©Ôý)$‰èéºF:ýBKžDmß÷«Á*%cÌçY„$³–K,lãô…˜º¸¶Qò$jçæ?T'©cŽÏDQ°¬Äú0Oèõ=& ÔÆ‚†2CT$qmݸ½¼&4UíM…[óË ²í˜«¿†dVÃÍ©[ --!ÛrËÌ7àØº*ß?6k™$€!‘qæúâݸ_»iS»xðÿù3ѸéjªThc+Ü6ØÑüϧ§û{Ú‚¦]n?‹4mÚÞøPË?ïÊíHCk³f[ß’¢³¿õÒô¥Öh(Öò&ÐðúmK‹ë¯¯/·wz~ROFBÑ£dÖõ¬ïSÈ*ªtO_ï?ÿ¿)¸¤¹¹2Šžç ƒ#]›/FMò=iewMtÇ §È ‘ô6ž<9u˜ u´M;¿Šëû,TßÖ=üg§n ¶H€ø> …µO>8ôøßOÃ{[š4Ûò|Ä`@½ßÏ~péè „4'óÝÀUYZ^Z?ÜqtHW}–ÜמE“]Óe,#}¿¾ê ñ<_ Èoì»òÒd4º¡¨+; ÛrlËM|lǶ\×qMÛ‹›Ža:qÓ-ô1-wuÝ ëê‰#¯F®.,Å4%¿ŠËãö›µ·÷œúö•¥õ¸¦TÐÏB·m/Ô ÿƇöFÏO/¯˜Š*B\×kjcŒýtf6¾aÊi  ~Ëëg–#îW%Ñ0lÇN^»åØ–ã8^V NÝ5Rð\_Ñå·öWA‘ä+µDøæ4aú€ PÛñBšzâ‘)€åxM j )R ¶íÃÚ&EE$„8®hãiy\:?E=Ïϰ} lˆ±FÅÖ)æJù{¸R ÕST%Ïg¹¥¥Êïg™EIPd1‹_™¦ê6Ù…é§_šŒF7Ô-P„d|x,‹_âJ\דuù‘±Ñç~vU¼o 9pʶ4RñΑÿûãëŸ|`PÕ¤¬]±«†¨Êâòšq}a9µc"ª’ty&ò®ýí5£˜eiT^Í/-v†ÏM¦ãq÷Ž"‹Wç–Õ>÷®ý†éRšðü%?þé¼ã¶öt4Z;FDIo/ïïnkk­¦oM:¡ûéòñ}{Ÿzù²ß@E:*P°m·µ%°ÒÜ4u}ùmwöÆâÎk2†º*ÍFÖßX»uøÞÖÌÔì8ر§§É²ý­…¤[ñw“ì@BG­¨ÿiF†ØßÞ<1з\J C¢+cDïswmÄ6KS ”õ7ýõ“gH1Š\ô™ÇŠK¥žç‹²x|lôäO.Wji€ï3Âd:Òª¾ñáÜâÆ¹åë'm 랟îBÐrª´+ò\{ÒÒøô÷~#ÍÒ(ŸbÖc¶ë™¶k:\“v ÛµÏr<Ãt ËåÓr×ã¶(ˆ¿öèþ wiva­  YF½ Þó|9S»©D=š¸Û9¿ùųK×>~b4¨*k¶i¹ñÍ·ÜÚoQ»É³‘xšM(Hü›é àz¾(¿þèþXQŠå dj7•Sܪ¤óûĉр¢ØŽ'yü!5oz+·°O$(þZ:ÅŒP%RF‰œsæP,ÿ~LmOQ…Wa~ÛYÓ0/że¦²ÜR«™gn¯…š"gت,–í“qÎ,K£\ЍkR( Ó ¡€\DÔdi~qãìâÎðK\{&ÅÅåd™)-ñQuYVÄ,exËûT¸ž/‰Â¿ýÄÄ“§&_»„”NÁ·ˆ6twH"E KæÅlž³rKξqÛv}ÓJ¤pŸÆøÞÖâ«áHˆ$ ‘•عèõ_ùå1‰Šö¶ÔÔÎíIKãSþÛ—o^\Ñ͘E”dqæj„Rš~1µØ§Àó|IåøØÔõå´õ'$Ó?‹\‰öu6e+™)Kãc£åZ”’+SžsøÞ|Uèúܲ¦Š‡tÇ ‡MJ ÓmK®W†V7I kÐíèÐÕ+‚x‡!C]“^‹^fêÚx*€ïÑv`´#ëO¥ý= OŸœ$Ðß×QE×ó%E<16úL–"éílh7—ðd¿ŒW0âù¬)¤ÁáoŸœúèdžڛ‚å{?ê!”‚ãz¢$Üß•òl3FB)ºá°Ìµ‹š-sów$79Ò?ë1[•¤OœØwaõÆ­…5½%3ñ|—­£:®g9žm{–íÚ¶g9žãx嬢€åz ê}£ßyöjd%V¿uó²Ç1n:¦åšfâc˜®m{@2t‹{*ró&×WDñÑcUP¬ÈÒHϯ45œ—Zo +»‡bÎxæ/PPBÆHnPJ&ݤx1E±ìäµ4ÊѶOß;1U.ó5dí>Š¥Ç§œ/éš *éñ?¡ ,Vd*$)~âľ‹«7oÞ^Så ¼ 9–ÆZ>m[Ê= Ñ5)LZº ʺ&a­÷²(.D7jëý¨‡”PgJáÜ¥bš^jS4Ÿ±±áÖ† â•íHP”¤Œ>ÿüÕÀº(~%ó"·4Ž~÷ôµ }ë©Íó‰,‹s·–†AË9Šœ½pÛ²<Óò(%ŒMߘ^l£mé;âe5Ä)þRÿȾwýÃÔj‘#W?)¥‘"¡®OyÄv%P‘Ȳps.*PúŽ»ûÜJÜ”‚íúíÐá–kÿ=2Ò·ò׫(€í¸áý`CË[:8ÖašÏÒTñ‚'ÍÍd€„±fEƒÈV²‹.èìël,’%CLÛíh ´E¯ÜX9r ;nVÐÏm–ÒF"v·7Œ ´›–Ãw¿QärÊWä ÄgÌqXuþ À³}hO˱Θápû!¨Ë¦ëÏάe|"ên90Ø™u¯Øn Wð|ô‘QZÇ=Ûk"eÙ…Žç[¶k;^*YÎv<Äj® S»¼Uÿf Ķ=ÃtMÓ¥C `Û95a“]5l7ËVRSM½cwùDHÊD˜Y¾©à¦rÛ)‘ø] $¾¹ù½ŸGÉD$¹ia$-*­|SÒÿÀÓ ‘!’JêD¤Ü˜ (ª¤»˜Ù4o=e0ðN¦úÉë5lRaC ‘!ALT;¸ä–:’·€x&BDUªL’YËš"©²$‹¢ªHˆÈS5UYR$QSÅP@&y«†]Ö5I•!ÕP%—UVeI×XªuÆ0¨Ëº*)’¨Ê!øÖŠ(ª²PªlH“D]¥¡€LÔ|ËßJ…—l×TI¡5R$”ÒË3‹„ËÙ\)¾µ¸rs#F€ðòMHP–ÄÙ…UPED’r ”)ˆ¨*âôèâŒï#ò†*;\¯Ì-‡):ã­ósN^_¾>oúÈ6û)Š3‘¨¥Æmϯ®¡©Ù¥ˆ qóìmÝÏ®P—4U<y±ÿH†§æææ?¸®{íÆMŸÇ¹$|Öa™¶00F|ƪˆ‹E‚¥@yÍî*Æ)¥˜Ù:?'¥$½ŸÈß%¤– í¬ðKCƒý’´¹­Î&BB¨Š’[¾sM$<´½ u-qnÁ¡“Ó:$J|d÷3±Ê_»†vVxO,ËNŸ³+!Æ c§ûù–”¬"•bñ?¿%»_Þö¦—ÿ óYÊC8%tEXtdate:create2017-06-06T01:31:13+01:00?¥ª¤%tEXtdate:modify2017-06-06T01:31:13+01:00NøIEND®B`‚puzzles-20170606.272beef/icons/map-ibase4.png0000644000175000017500000000717113115373734017444 0ustar simonsimon‰PNG  IHDR¹¹6?ôgAMA† 1è–_bKGDÿ‡Ì¿tIMEáeÑ^3 ­IDATxÚíÝY’Û: P-½—¦å%©T*ÉI̸/>2Ø4«Û–(òúƘWwÆ ÜÔ ÜÔ ÜÔ ÜÔ ÜÔ ÜÔ ÜÔ ÜÔ ÜÔ ÜÔ ÜÔ ÜÔ ÜÔ ÜÔ ÜÔ ÜÔ ÜÔ ÜÔx”»X!—ûê O»žOí^7NPŽr”£å(G9ÊQŽr”£å(G9ÊQŽr”£å(G9ÊQŽr”£å(G¹h9ñ| ÊaÉE¿¢á(× wS.\ŽrSá(7ŽrSá(7ŽrSá(7ŽrSá(7ŽrSá(7ŽrSá(7ŽrSá(7ŽrSá(7îMrŽ9"%p¡nßîG¹¯n/“œtx=rpPt>9)]¾\ðÊå¸pèœrBºt¹*8 :¯œŒ.[®‡Î-'¢K–«„ƒ¡óËIèråjáPèät©rÕp tr’wé›à0èBäŽÃM”뀃 ‹‘;ÿR]ÜaÈir]ptQr§ï@oƒë§ “Û;I®®.NnÊè}pÝtr›¡§ÈuÃ5ÓEÊíΰ¿®—.Tn9ü9¸VºX¹õÉwÂuÒË-R.‡×85%Z®hÿžP7ßì(×8Gl¼Òk+ä|?;ìt”k•sÐQ®WÎNG¹f93åºå¬t”k—3ÒQ®_ÎFG99åä,t”ƒ3ÐQCNOG995åPä´t”ƒ‘SÒQGNGG9 9åä4t”ƒ’SÐQKN>¯%\7R0_Å1(NxÔÅÏýr ¹â>ö7.|¾eìtº ¹ŸGÜ<ºè9Împf¹_?*ÇÑßWÐg•ûý;n]콜 £ ½®Î&÷×§ÊYt‘÷¬¶Â™äþù:0Š.ð>ñ^8‹Üÿ¾ÇM¢‹[›¡Î ÷ð|]Øz(Ýpz¹Åª±8±§‹Zƒ¨N-Wv“f]к_ýpZ¹Ò{Ú3èbÖÚ€SÊ•/N²¾%œN®eŤXºˆ5e!àTrm ÌÒ¹åPà4r­ëqFÑyå`àríˇÐ9åpàär«½ûé|r@pb9˜Í1tñrMSÄs]ž× ‘¾ÓqB<Ç\Nþvsd î±3å?¢cå à^"·úÝ*‡÷¹å‡¢H90¸WÈ­?ÍÊ¡Á½Anó5$Nîr»ïarxpóå¶_ü£äáÆËíÏØÉ!ÂM—;œj‹‘ƒ„.w:G"‡ 7[îxr;Bn´ÜùªD€*Üd9Áå$¿,Ü`9Éu@·.Ü\9Ñ\¯0ÜX9Ù•w§2ÜT9á” Ÿ4ÜP9é\—6ÜP9i¹.8é<™Ï“Sl2Ý#çyìÕrèt”[—æ£Ü¦4åvåé(·-LG¹}9\:ÊÊÁÒQîT•ŽrÇr t”;—䣜 $å$åé('*HG9Y9<:Ê ËÁÑQNZŽrâr`t”“—â£Ü7Å¢:b:Oxä¤sS^"÷coá±àcÄQNÜ•Ë}‡»…t8ròž¼Wîþ¹¨™ŒFNÑ‘×ÊÝ¿V£Ñ¡ÈiúñV¹û÷2‚:9U7^*wÿ±þ£€CN׋wÊÝ-Üy¦ƒSvâ•r÷?+®éä´}x£Üý¿¥rOtrê.¼Pî~Xãø@×/§ïÁûäîÇÅ©÷tír†¼Nî^,¿¥ë–³´ÿ6¹{¹ÆŽ®YÎÔüËäîÍvCº^9[ëï’»·»³­éZ匿Jî>lf¹¤ë”³¶ý&¹Üš®QÎÜô‹äÎpKº>9{Ëï‘“Àý ƒ’s4Wn·O¹ÜexæSå¶{ðTË]¦§>Sn¿O±Üe|îå{ðÔÊ]æ'?Oî´O©œçÙO“;îÁS)wH9åp¥r§ŒSNW)wL8åp…rç|SNW''H7åper’lSNW%'J6åpEr²\SNW#'Lõ9iH×%y ¡°K.znÊÈy(®ãFX_¸\ðñPÝ‹—óìG91\†œcFÊÉ;—!gß•rò¾¥È™÷"¦œ¼k9rÖý¿)'ïY’œä|?åIn{§Wñl–Art[¹Ý'ËõÓíåöt-×NwÛÒ}¶\7ÝInG÷árÍtG¹ ݧËõÒåÖt/×J'[ÒQ®“N"·¢£\'HnAG¹2º§É)öùqÌk™(W÷œ¡œ4žòb¹>8ÊM…£ÜT8ÊM…£ÜT8ÊM…£ÜT8ÊM…£ÜT8ÊM…£ÜT8ÊM…£ÜT8ÊM…£ÜT8ÊM…£ÜT8ÊM…£Ü2¢çeP®L®›†r”£TPŽr”£å(G9Êáå(G9ÊQŽr”£^PŽr”£å(G9Êáå(×.×JŽõPÈEg+¼`lW(§J—³ddO(§Ë—·h\G(§L˜»lT?(§Í˜¿pL7(§NY@éˆz)§ÏYDq­”3$-¤¼·NÊY²ó_”3¥-èžú(gË[ÔKìµQΘ¸°×X뢜5sq/²ÕD9sê_e©‡rÁ1ÝÔB¹h‚ˆ~Hê \¸€¿#¢(àí‰ìõ”KÈ¿¯+ÂWS.#ýóZ®/¹Çq´ÉEŸÌ’#òtÅÒ=¶+ëËc©F¹è“Y®>÷ƒî¹L§\,XnÝ¢D«\ìyHg Ÿû×O·z¾W.’N!7‰nùl³\ä)dw Ÿû×K·~®[.ŽN%7…nÓËv¹¸³ÿ)|î_Ý®ýrQtJ¹ tÛÈE]¸ IásÿzèöýC‹¡SË¡Óz!sÍ-(…Ïý«§;õ C.‚Î ‡Lwìˆ\ÄåÒ°"Ðû…"ç§3É¡Ò z#ç¿Ò˜Ân:IŸpä¼tF9D:Q€ä¼“BSØI'ë’œÎ,§  •[Ñ {%ç››â8"ÄtÁë¦<Ó ”¿ß¢é\ÍFuÒv䮯®£ÎÕªCÎC$wýñ§µ†ir:¹ëŸ¿muL“³ÓÁÈ]ÿ²Ô2MÎL‡"w-þ­¯gšœ•DîÚüO[Ó49#†Üuø¿®®ir6:¹Kðˆ¦¶ir&:¹Kø˜¼¾ir:¹Kñ¨´Æirº~¹Kù¸¬Îirzºv¹ËðŒ¤Öirjºn¹ËøÜ¹ÞirZ:è{y\ ÕйŠ’SÒaß?çʨ‚ÎÕN˜œŽüžUWJåt®fâäTtè÷‰»r*¦sµ(§¡ƒ_›¡$©%Ó%ìË WC'îKÓþ=N9afÄs—Ä金‹FzŒš¹_—£i9ˆ.V.zU"]‚œ°i…‡™.T®Nœ¿9YÓ+]¤\œ4r¢¦UFº@¹B8aþRä$Më0ltqr¥p²üåÈ šVZ˜èÂäŠáDùK’;7­¥°ÐEÉ•ÃIò—%wlZ-a  ’k€ä/MîÔ´ÂðŠ¹¸sþòäMë ‡i„\Ü1‰rû¦ rúßrmp§üeÊm›¶È©?úåáùK•Û5m’Ó~ t˵Âíó—+·iÚ&§<õâ•k†Ûæ/YnÝ´QNw¾Ó)×·Ë_¶Ü²i«œê"ƒOn“¿t¹UÓf9Í•=—Ü:ùr‹¦írŠËé9¸eþ ä¾gÆ1_ÅC'7ò86¸UþJääï¤X:iŸ¯çwƒí5Ûä*è\ràtrt>9lºN¹|:§4]«\:W™®W.›Î-L×,—Lç—Ã¥ë–Ë¥ ƒ¥k—K¥‹C¥ë—ˤ ‘¥K¤‹‘äCË£ ’ƒ¤ƒK£‹’C¤ÃË¢ “¤‘K¢‹“ãC‘Ë¡ ”ƒ£ƒ‘K¡‹”C£Ã‘Ë  •£’K ‹•«Y›¡H®`Ÿ1p®‹k —n®8¹àѹä„õE·A9ÊQŽr”£å(G9ÊQŽr”£å(G9ÊQŽr”£å(G9ÊQŽr”£åÚäX!–c ÊM ÊM ÊM ÊM ÊM ÊM ÊM ÊM ÊM ÊM ÊM ÊM ÊM ÊM ÊM ÊM ÊM ÊM ÊMÿâÇÉ–(%tEXtdate:create2017-06-06T01:31:24+01:00t“É%tEXtdate:modify2017-06-06T01:31:24+01:00Ð+uIEND®B`‚puzzles-20170606.272beef/icons/map-ibase.png0000644000175000017500000001422113115373734017352 0ustar simonsimon‰PNG  IHDR¹¹œ6ÝbKGDÿÿÿ ½§“FIDATxœíÝMoTW‚‡ñÃh¾I©P,[AQdÉ §µÆ†îô`&¼¥CÒ€c0É®mž M-Ø În;Ðá%‰»ÐLLÒ°{1%¡¥+tDbÙ`Oɱ¿Ä,îˆNˆísëž{Ïëó[°+×q¹ê±ïeñ_V­V`Iÿ`úàZ r´äh%ÈÑJ£• G+@ŽV€­9Z r´äh%ÈÑJ£• G+@ŽV€­9Z r´äþQåÁù|>­s@ÖTæÅ”Z)„( îUü *‡Žwo7}ŠÚô ;7{—ÏçGJ ßÏí¥¡;#|¬ÖÜ>¤òp®Á@ŽV€­9Z r´äh%ÈÑJ£• G+@ŽV€­9Z r´äh%ÈÑJ£• G+@ŽV€œê†D8¦îWÏ\3} 7LLÏ™>2ZËÔýê¥S£ÎÞ11=÷É—·Û–Æ5¸Üƒïf/Žîøu‹éƒ8`rf~ø¿¾úàôÓRF+%|7{éÔõ߾ز²îIÓg±ÝäÌüÇ_ÞúàôÚµkMŸH­\ ¡ŒPÂo´rQ„2>B ïÑÊ…Êø%B@+@(ã#”­|¡ŒP"´ò'e|„A¡•G(ã#” ­ü„2>B‰ÑJ!e-%ÂD+ e %‚z+ e|„! º•„2>B‰À…ÛJB¡m%¡ŒP"ÌVÊø% ®•„2>B <¢º!Q*%~lG÷†úgòЍՇÇ?c "މ鹓Ç™‚(—ËŠ_á¯ãÕ5MºßÏÐFµ•‰?K·oßîx}׿vüS󼽬ÚfN¹\îÚÝ9RÚ›ø+ôwnŸ723ÏÛþ1°J8SBˆ|>¯2aD{)ùh•AƒG7¸µ/ÔÜ>¤òYPÝÛ1ž«pñ̈Ϲ¸ !î=œ m_È¥kp–ð~+­Dh¹¤• *—´@ráä’VPH.i%U!ä’VH÷¹¤•Òáw.i%€ÔxœKZ M¾æ’VH™—¹¤•Òç_.i%€Lx–KZ +>å’VÈ7¹¤•²åG.i%€ÌyKZ @×÷…ÜÛ(—Ë[·n5} Ý\œÒ¿{Q.—…ãSÕ¦z÷^®4Õç/tïl{õ|o›[[=¹V–Ëåb±ÚøŒ©ïWeçGÜËåòîÎ×ß|¥­ïâèÁmmöï8«wÛz·z\º¯T*ûöí;yò¤éƒÀ:•JeÏîÎí¿|®aÅò×ö_½;Ö/T‡8zïÒ™VV*•®®®'N²sø*•Êë»^Yß¼²îI!¹´Ÿ‹¹t£•„‹y,”ri?çré@+ %³`(#äÒ~nåÒöVJ,f‰PFÈ¥ýÊ¥Õ­$”XŒ4”ri?Wrio+ %3”ri?'rii+ %SS(#äÒ~öçÒÆVJ,&A(#äÒ~–çÒºVJ,&q(#äÒ~6çÒ®VJ,F1”ri?ksiQ+ %“J(#äÒ~væÒ–VJ,&ÅPFÈ¥ý,Ì¥­$”XLꡌKûÙ–Kó­$”XLF¡ŒKûY•Kí$”XL¦¡ŒKûÙ“K“­$”XŒ†PFÈ¥ý,É¥±VJ,F[(# +–¿¶áù¾K®îÀ„À†­že*ûŠ¡MAè§¾MdjCâx÷v•‡'01=wòâØHi¯æçEMÚKC*WiŽc{;ˆO}›È¹Þ%61=÷ѵ[„Ò ‰ßW=Ã*ÏkþÿÁ‘¶‰â›œ™ÿøÚ­CÛÚLV£•â^p|“3óFn²û)ZéB¡D|´Ò+„2>B‰šÐJÊø%jE+=A(ã#”H€Vú€PÆG(‘ ­t¡ŒP"1Zé6B¡„ Zé0B¡„"Zé*B¡„:Zé$B¡D*h¥{e|„i¡•Ž!”ñJ¤ˆVº„PÆG(‘.Zé B¡Dêh¥e|„Y • ”ñJd„ lÚ´ÉÅm¢‰é¹§ŸzBó“þÇGvlhª'”ÙRܽqq®ƒV"W¯^íØµSÛã#o¾ÒÖwq”¿+5( &ì]©¨ÔYS¸G& …ÂÙsçÿpýÎ÷Ðù¼ì}##´Y!—ð ­D†È%¼A+‘-r ?ÐJdŽ\´:K¸ŽVBr §ÑJèC.á.Z ­È%E+¡¹„‹h% —p­„än¡•0†\Â!´&‘K¸‚VÂ0r 'ÐJ˜G.a?Z +KXŽVÂ…Báô™ß_¿£ùyV,mÃó}—F5?/܆V.—£[ZZ´=iKKËßþöm>Ÿ?Þ½]Û“ !ž~ê‰ß¿IqCÆýÛ5ãSªƒ»øRÓJ, \.ïíê<Ý¿±ØÕyrðt û‘*îN¼?£BÿvÍøTõØåQ•oV鱿¶z¸Çã*•Jqoç;=/¬nÌõúÅþâž›7oš>¬ð̓Ùc—Ç6wµ™>ˆ´?Q©TöìÞu¤û…çVå…ä|ó`öK76wµ6<âF&­Äß=ʹ„>”‚Vâ‘C!—#”‚V"²D(#ä2X„2B+!e„\ˆP>B+C3”rBùc´2h5…2B.A(C+Õ ”ré=Bùs´2P‰C!—#” ¢•!R e„\z‰P.†V'•PFÈ¥gåheXR e„\zƒP.V$õPFÈ¥¥­ EF¡ŒK§Ê8he2 e„\:ŠPÆD+ý§!”réB­ôœ¶PFV7æŽxa_q·†ç‚"BY6$líÞ$¶iÓ¦;#Z· Ö4察ߞÏ+}üz†?VóVbbzNåኻ*Û5Fv/E+­V.—‹ÅbµêÞ«J ›Û‡†õï±LLÏÿü–btô÷]¨ýB ×àöªT*ûöí;yò¤éƒ`Q“3󾸵uoˆû3¡¡•–ªT*]]]'NœdCÑE“3óç>¿¹¥«û}! •6"”ö#”¡¡•Ö!”ö#”¢•v!”ö#”a¢•!”ö#”Á¢•¶ ”ö#”!£•V ”ö#”£•æJûJÐJÃ¥ý%­4‹PÚP"B+!”ö#”x„VšA(íG(ñc´ÒBi?B‰ÇÐJÝ¥ý%~ŽVjE(íG(± Z©¡´¡Äbh¥&„Ò~„KPÝP™UQyìåË—[ZZ?<Å § LQ™‚P™F0µ?ÜCS÷M~‚T[iäóûöí={öùÞé1RJجöRò­Sœ;°S÷«—N&Š8y ^(NŸ>ýÆo°C „àÁw³—GwüZ÷¥ä9ÙJA.`<ønöÒ©ë¿}±eeÝ“áj+¹`I(…Ó­äðš=¡®·RKÀSV…RxÐJA.ïØJáG+¹µRKÀqÖ†RxÖJA.gÙJá_+¹dy(…—­äpŠý¡¾¶RKÀN„RxÜJA.ë¹Jáw+¹,æP(…÷­ä°’[¡!´RKÀ2Î…RÒJ!D¡P8uêÔþýûM‹¡êiiiWÜÌQ|¸ÍíÉ·k\4u¿ZÿŒ{?&ͦîWÏ\3õì§  ¨•Sƒ9ù|ÞÅ÷‡*C]ý ÞØÜÕÊãŒo׸(”kp¢±.wøåuW>›ü–¹…Ù°]ã"Z ßË%8z¯Ð´"— "”*h%üD.C(ÑJx‹\>B(ÕÑJøŒ\ B™Z ÏžKB™Z ÿ›KB™"Z‰ ˜KB™.Z‰P•KB™:Z‰€’KB™Z‰°xŸKB™Z‰àxœKB™Z‰y™KB™)Z‰@y–KB™5Z‰py“KB©­DÐ<È%¡ÔƒV"tu¹Þ­­W†FM$ B©MpMLÏ=ýÔ¦Oá†ñ©jS½¾ˆ¦úü'v¶•†‰:º7èßùùðøgLAèA+5¹zõjÇ®¯¬oæ÷¿Ô›¯´õ]=¸­mUƒîôÜÙ›ì_ß›í~çÆK»Ùùñ×àš …³çÎÿáúïþ`ú,¶kX±|ÇÆµý—FïN:squcnàíuWÏ8|ßK£•úËøÈ%lC+µ"—ñ‘KX…VêF.ã#—°­4€\ÆG.a Zi¹Œ\´Òr¹„q´Ò$r¹„Y´Ò0r¹„A´Òr #h¥-Èe|äúÑJ‹ËøÈ%4£•v!—ñ‘KèD+­C.ã#—ІVÚˆ\ÆG.¡­´¹Œ\BZi¯B¡púÌß1}4¬XþÚ†çû.¹´™³º1÷î¡Ö?qéÌ![V­&ÿµ–ÏçUŽ8ÊåòÖ­[ÙT‰©g`Xåá‰7$T4·+íü˜âÜ{²g`X¥WìíX­\.ïî|ݹ7¥A*¯•bg3h!DsûPi0áS—ÔvÜ\Ä5¸½*•ÊžÝÛùœéƒ •¶ªT*¯wìb÷°­´¡lC+­C( ÑJ»JÀN´Ò"„°­´¡lF+­@(ËÑJó%`?Zi¡œ@+M"”€+h¥1„p­4ƒPn¡•JÀ9´R7B ¸ˆVjE(GÑJ}%à.Z© ¡œÆ†D òù¼ÊÙ‚ÜE+kCï€0q r´äh%ÈÑJ£• G+@ŽV€­9Z r´äh%ÈÑJ£• G+@ŽV€­9Z r´äT7$'hœÓ30läy÷¿ÜúôSOyj‡LLϼ8fúð“j+ƒÚŸé. îÕÿ¼¿Ÿ=òúŽ[Ø€\ÂÄôÜG×n”’ÿ€ÚKC)žžáÜu+s¿Ù¿þŸËß?üÁôY,593ÿñµ[‡¶µ™>¼E+Ý@.—093aäæÁmm«º#h¥3Èå‚%ô •.!—!”ІV:†\>B(¡­t¹„ÚÑJ'žKB ýh¥«‚Í%¡„´Òaæ’PÂZé¶ rI(a­t^ ¹$”0‹VúÀû\JG+=áq. %l@+ýáe. %,A+½âY. %ìA+}ãM. %¬B+=äA. %lC+ýT·2·­Øvዲéƒ$A(a!Õ ‰ÐLݯÖ?ãÆ¸þ™ü÷wöÜE8Ú±¡©ÞÀëü×ñêš&7~¾©Py?OLÏiÞ€2»§´¬Z­&~p>ŸjogòçÏÜܲ·­áÙ >N¥âÐûB_ß›=päFÏæVÍWÞ{8{ìÒc‡ZŸ[ÄÏ÷ë{³ÝïÜxiwk‚÷óÃïgÿ¨wjbzîüç·¼¿3ñW(‡TrÇ5x V,ßÕ¾öÓ¡ÑÉo“¿âZݘ{ïðºãWÆîNj}ër½ÛÖõö}u7ˆŸïêÆÜÀÛ뮞Kð~Ö|O|rfþ·¶î5¹§D+kC.õ —z8‘ËÉ™ùsŸßÜÒeøzŽVÖŒ\êA.õ°<—–„RÐÊdÈ¥äRksiO(­LŒ\êA.õ°0—V…RÐJäRr©‡U¹´-”‚V*"—zK=,É¥…¡´R¹Ôƒ\êa<—v†RÐÊTK=È¥sim(­L ¹Ôƒ\êa$—6‡RÐÊ‘K=È¥šsiy(­L¹Ôƒ\ê¡-—ö‡RÐÊÔ‘K=È¥réD(­Ì¹Ôƒ\ê‘i.] ¥ •!—zK=2Ê¥C¡´2;äRr©Gê¹t+”‚VfŠ\êA.õH1—Î…RÐʬ5¬X¾ã_ž¿<4jú ž[ݘëëm}ïŠî×¹±.÷Ö–ÖÞ¾P~¾«sïjýÓ™$ßï£ (C)ØÐ#Ú éèÞàÊVO¤T<ºÁ­ý™æö¡‘’Ý‹ö’Ò®‘‘­ÿüÚùÍ]mÉÞÏ¥âPiÐÀ÷«¸!Á6Yæ&¦ç>ºv«¿sã‘Á›»’l›˜Òy`ã¾ýCÙŸQ¡hÅÎñþÛëoõ ¥:®Á³593ÿñµ[‡¶µ5Ö忼îÊIîõ˜R·2·µ¸î`(÷ãŸÊ½KGÑÊ =¶sM.á“ÐrI+³òX(#ä> *—´2 †2B.á“prI+Ó·D(#ä> $—´2eÒPFÈ%|B.iešb†2B.áïsI+SSS(#ä>ñ;—´2 B!—ð‰Ç¹¤•)Hʹ„O|Í%­T¥Ê¹„O¼Ì%­T’J(#ä>ñ/—´2¹C!—ð‰g¹¤• ¥Ê¹„O|Ê%­L"£PFÈ%|âM.ieÍ2 e„\Â'~ä’VÖFC(#ä>ñ —´²ÚBi¬Ëõnm½âÔVOÝÊÜæ®Ö·ú]:3ôPÙê±êÞNŠG©Éþ—[Ÿ~ê ÍOÚ30ldËåÕ÷ÎoÙ—pÛÄ”RqÈȆŒ‘½ñ©ê¿½¦òœÛÛQ¡²Õ£ÂðÞNâ÷e{)ùgéë{³ÝG®oÿUËʺ'“}·þÍzç¶zÂ1>U}÷ÓÑ b§He«Ç '¯ÁW7æ¯þò'ÓìsñÞe ¾y0ûî§cǵ™>ˆK½wéd+¹„¾y0ÛwùƱCì\ÖÌÅ\ºÚJA.a¡Tä\.n¥ —0„P¦Â­\ºÝJA.¡¡L‘C¹t¾•‚\B#B™:WréC+¹„„2#NäÒ“V r‰ŒÊLÙŸKZ)È%2C(5°<—^µRKd€Pjcs.}k¥ —H¡ÔÌÚ\zØJA.‘Bi„¹ô³•‚\B¡4ÈÂ\zÛJA.¡€Pg[.}n¥ —H„PZª\zÞJA.Q#Bi{ré+¹Dl„ÒB–ä2ˆVŠh룷í“?—MD·zŒ#”Ö²a«GuCÂ!kšòÞÙÜ>¤òEƧªMõn|šêóŸØùêïŒmõ¨¼ÔF&}øÙàÑ kšÜøù†fMSþ/«~~UÔʈʇðë{³ŽÜèÙܪgÇ1·zŽwoOöÀžátOSçÆƒÇø»Òj*Ÿ_ÅΆr žŠÕ¹÷¯;~eìî¤3÷¹w_c]®wÛºÞ>öͱZYré7r‰ÅÐÊš‘K¿‘K,ˆV&A.ýF.ñs´2!ré7r‰ÇÐÊäÈ¥ßÈ%~ŒV*!—~#—x„Vª"—~#—ˆÐÊK¿‘KZ™ré7r Z™ré7r8Z™&ré7r2Z™2ré7r,Z™>ré7r&Z™ ré7r Z™ré7rZ™!ré7rZ™­Õ¹¾ÞÖ÷®¸´{ÃVO|u¹·¶´ööñZùÏ䆄s{,ɬiÊ~²³¹}h¤äÌ™£­žö¢±mƒ³*µjªÏ_èÞÙÜ>äÐ{ ˜l¥s{,JüùWŒC¿W®Á@ŽV€­9Z r´äh%ÈÑJ£• G+@ŽV€­9Z r´äh%ÈÑJ£• G+@ŽV€Ü²j5ù]>ŸOñ()•Ü)µÁ58ÈÑJ£• G+@ŽV€­9Z r´äh%ÈÑJ£• G+@ŽV€­9Z r´äh%ÈÑJ£• ÷×·í v†RIEND®B`‚puzzles-20170606.272beef/icons/map-base.png0000644000175000017500000001422113115373721017175 0ustar simonsimon‰PNG  IHDR¹¹œ6ÝbKGDÿÿÿ ½§“FIDATxœíÝMoTW‚‡ñÃh¾I©P,[AQdÉ §µÆ†îô`&¼¥CÒ€c0É®mž M-Ø În;Ðá%‰»ÐLLÒ°{1%¡¥+tDbÙ`Oɱ¿Ä,îˆNˆísëž{Ïëó[°+×q¹ê±ïeñ_V­V`Iÿ`úàZ r´äh%ÈÑJ£• G+@ŽV€­9Z r´äh%ÈÑJ£• G+@ŽV€­9Z r´äþQåÁù|>­s@ÖTæÅ”Z)„( îUü *‡Žwo7}ŠÚô ;7{—ÏçGJ ßÏí¥¡;#|¬ÖÜ>¤òp®Á@ŽV€­9Z r´äh%ÈÑJ£• G+@ŽV€­9Z r´äh%ÈÑJ£• G+@ŽV€œê†D8¦îWÏ\3} 7LLÏ™>2ZËÔýê¥S£ÎÞ11=÷É—·Û–Æ5¸Üƒïf/Žîøu‹éƒ8`rf~ø¿¾úàôÓRF+%|7{éÔõ߾ز²îIÓg±ÝäÌüÇ_ÞúàôÚµkMŸH­\ ¡ŒPÂo´rQ„2>B ïÑÊ…Êø%B@+@(ã#”­|¡ŒP"´ò'e|„A¡•G(ã#” ­ü„2>B‰ÑJ!e-%ÂD+ e %‚z+ e|„! º•„2>B‰À…ÛJB¡m%¡ŒP"ÌVÊø% ®•„2>B <¢º!Q*%~lG÷†úgòЍՇÇ?c "މ鹓Ç™‚(—ËŠ_á¯ãÕ5MºßÏÐFµ•‰?K·oßîx}׿vüS󼽬ÚfN¹\îÚÝ9RÚ›ø+ôwnŸ723ÏÛþ1°J8SBˆ|>¯2aD{)ùh•AƒG7¸µ/ÔÜ>¤òYPÝÛ1ž«pñ̈Ϲ¸ !î=œ m_È¥kp–ð~+­Dh¹¤• *—´@ráä’VPH.i%U!ä’VH÷¹¤•Òáw.i%€ÔxœKZ M¾æ’VH™—¹¤•Òç_.i%€Lx–KZ +>å’VÈ7¹¤•²åG.i%€ÌyKZ @×÷…ÜÛ(—Ë[·n5} Ý\œÒ¿{Q.—…ãSÕ¦z÷^®4Õç/tïl{õ|o›[[=¹V–Ëåb±ÚøŒ©ïWeçGÜËåòîÎ×ß|¥­ïâèÁmmöï8«wÛz·z\º¯T*ûöí;yò¤éƒÀ:•JeÏîÎí¿|®aÅò×ö_½;Ö/T‡8zïÒ™VV*•®®®'N²sø*•Êë»^Yß¼²îI!¹´Ÿ‹¹t£•„‹y,”ri?çré@+ %³`(#äÒ~nåÒöVJ,f‰PFÈ¥ýÊ¥Õ­$”XŒ4”ri?Wrio+ %3”ri?'rii+ %SS(#äÒ~öçÒÆVJ,&A(#äÒ~–çÒºVJ,&q(#äÒ~6çÒ®VJ,F1”ri?ksiQ+ %“J(#äÒ~væÒ–VJ,&ÅPFÈ¥ý,Ì¥­$”XLꡌKûÙ–Kó­$”XLF¡ŒKûY•Kí$”XL¦¡ŒKûÙ“K“­$”XŒ†PFÈ¥ý,É¥±VJ,F[(# +–¿¶áù¾K®îÀ„À†­že*ûŠ¡MAè§¾MdjCâx÷v•‡'01=wòâØHi¯æçEMÚKC*WiŽc{;ˆO}›È¹Þ%61=÷ѵ[„Ò ‰ßW=Ã*ÏkþÿÁ‘¶‰â›œ™ÿøÚ­CÛÚLV£•â^p|“3óFn²û)ZéB¡D|´Ò+„2>B‰šÐJÊø%jE+=A(ã#”H€Vú€PÆG(‘ ­t¡ŒP"1Zé6B¡„ Zé0B¡„"Zé*B¡„:Zé$B¡D*h¥{e|„i¡•Ž!”ñJ¤ˆVº„PÆG(‘.Zé B¡Dêh¥e|„Y • ”ñJd„ lÚ´ÉÅm¢‰é¹§ŸzBó“þÇGvlhª'”ÙRܽqq®ƒV"W¯^íØµSÛã#o¾ÒÖwq”¿+5( &ì]©¨ÔYS¸G& …ÂÙsçÿpýÎ÷Ðù¼ì}##´Y!—ð ­D†È%¼A+‘-r ?ÐJdŽ\´:K¸ŽVBr §ÑJèC.á.Z ­È%E+¡¹„‹h% —p­„än¡•0†\Â!´&‘K¸‚VÂ0r 'ÐJ˜G.a?Z +KXŽVÂ…Báô™ß_¿£ùyV,mÃó}—F5?/܆V.—£[ZZ´=iKKËßþöm>Ÿ?Þ½]Û“ !ž~ê‰ß¿IqCÆýÛ5ãSªƒ»øRÓJ, \.ïíê<Ý¿±ØÕyrðt û‘*îN¼?£BÿvÍøTõØåQ•oV鱿¶z¸Çã*•Jqoç;=/¬nÌõúÅþâž›7oš>¬ð̓Ùc—Ç6wµ™>ˆ´?Q©TöìÞu¤û…çVå…ä|ó`öK76wµ6<âF&­Äß=ʹ„>”‚Vâ‘C!—#”‚V"²D(#ä2X„2B+!e„\ˆP>B+C3”rBùc´2h5…2B.A(C+Õ ”ré=Bùs´2P‰C!—#” ¢•!R e„\z‰P.†V'•PFÈ¥gåheXR e„\zƒP.V$õPFÈ¥¥­ EF¡ŒK§Ê8he2 e„\:ŠPÆD+ý§!”réB­ôœ¶PFV7æŽxa_q·†ç‚"BY6$líÞ$¶iÓ¦;#Z· Ö4察ߞÏ+}üz†?VóVbbzNåኻ*Û5Fv/E+­V.—‹ÅbµêÞ«J ›Û‡†õï±LLÏÿü–btô÷]¨ýB ×àöªT*ûöí;yò¤éƒ`Q“3󾸵uoˆû3¡¡•–ªT*]]]'NœdCÑE“3óç>¿¹¥«û}! •6"”ö#”¡¡•Ö!”ö#”¢•v!”ö#”a¢•!”ö#”Á¢•¶ ”ö#”!£•V ”ö#”£•æJûJÐJÃ¥ý%­4‹PÚP"B+!”ö#”x„VšA(íG(ñc´ÒBi?B‰ÇÐJÝ¥ý%~ŽVjE(íG(± Z©¡´¡Äbh¥&„Ò~„KPÝP™UQyìåË—[ZZ?<Å § LQ™‚P™F0µ?ÜCS÷M~‚T[iäóûöí={öùÞé1RJجöRò­Sœ;°S÷«—N&Š8y ^(NŸ>ýÆo°C „àÁw³—GwüZ÷¥ä9ÙJA.`<ønöÒ©ë¿}±eeÝ“áj+¹`I(…Ó­äðš=¡®·RKÀSV…RxÐJA.ïØJáG+¹µRKÀqÖ†RxÖJA.gÙJá_+¹dy(…—­äpŠý¡¾¶RKÀN„RxÜJA.ë¹Jáw+¹,æP(…÷­ä°’[¡!´RKÀ2Î…RÒJ!D¡P8uêÔþýûM‹¡êiiiWÜÌQ|¸ÍíÉ·k\4u¿ZÿŒ{?&ͦîWÏ\3õì§  ¨•Sƒ9ù|ÞÅ÷‡*C]ý ÞØÜÕÊãŒo׸(”kp¢±.wøåuW>›ü–¹…Ù°]ã"Z ßË%8z¯Ð´"— "”*h%üD.C(ÑJx‹\>B(ÕÑJøŒ\ B™Z ÏžKB™Z ÿ›KB™"Z‰ ˜KB™.Z‰P•KB™:Z‰€’KB™Z‰°xŸKB™Z‰àxœKB™Z‰y™KB™)Z‰@y–KB™5Z‰py“KB©­DÐ<È%¡ÔƒV"tu¹Þ­­W†FM$ B©MpMLÏ=ýÔ¦Oá†ñ©jS½¾ˆ¦úü'v¶•†‰:º7èßùùðøgLAèA+5¹zõjÇ®¯¬oæ÷¿Ô›¯´õ]=¸­mUƒîôÜÙ›ì_ß›í~çÆK»Ùùñ×àš …³çÎÿáúïþ`ú,¶kX±|ÇÆµý—FïN:squcnàíuWÏ8|ßK£•úËøÈ%lC+µ"—ñ‘KX…VêF.ã#—°­4€\ÆG.a Zi¹Œ\´Òr¹„q´Ò$r¹„Y´Ò0r¹„A´Òr #h¥-Èe|äúÑJ‹ËøÈ%4£•v!—ñ‘KèD+­C.ã#—ІVÚˆ\ÆG.¡­´¹Œ\BZi¯B¡púÌß1}4¬XþÚ†çû.¹´™³º1÷î¡Ö?qéÌ![V­&ÿµ–ÏçUŽ8ÊåòÖ­[ÙT‰©g`Xåá‰7$T4·+íü˜âÜ{²g`X¥WìíX­\.ïî|ݹ7¥A*¯•bg3h!DsûPi0áS—ÔvÜ\Ä5¸½*•ÊžÝÛùœéƒ •¶ªT*¯wìb÷°­´¡lC+­C( ÑJ»JÀN´Ò"„°­´¡lF+­@(ËÑJó%`?Zi¡œ@+M"”€+h¥1„p­4ƒPn¡•JÀ9´R7B ¸ˆVjE(GÑJ}%à.Z© ¡œÆ†D òù¼ÊÙ‚ÜE+kCï€0q r´äh%ÈÑJ£• G+@ŽV€­9Z r´äh%ÈÑJ£• G+@ŽV€­9Z r´äT7$'hœÓ30läy÷¿ÜúôSOyj‡LLϼ8fúð“j+ƒÚŸé. îÕÿ¼¿Ÿ=òúŽ[Ø€\ÂÄôÜG×n”’ÿ€ÚKC)žžáÜu+s¿Ù¿þŸËß?üÁôY,593ÿñµ[‡¶µ™>¼E+Ý@.—093aäæÁmm«º#h¥3Èå‚%ô •.!—!”ІV:†\>B(¡­t¹„ÚÑJ'žKB ýh¥«‚Í%¡„´Òaæ’PÂZé¶ rI(a­t^ ¹$”0‹VúÀû\JG+=áq. %l@+ýáe. %,A+½âY. %ìA+}ãM. %¬B+=äA. %lC+ýT·2·­Øvዲéƒ$A(a!Õ ‰ÐLݯÖ?ãÆ¸þ™ü÷wöÜE8Ú±¡©ÞÀëü×ñêš&7~¾©Py?OLÏiÞ€2»§´¬Z­&~p>ŸjogòçÏÜܲ·­áÙ >N¥âÐûB_ß›=päFÏæVÍWÞ{8{ìÒc‡ZŸ[ÄÏ÷ë{³ÝïÜxiwk‚÷óÃïgÿ¨wjbzîüç·¼¿3ñW(‡TrÇ5x V,ßÕ¾öÓ¡ÑÉo“¿âZݘ{ïðºãWÆîNj}ër½ÛÖõö}u7ˆŸïêÆÜÀÛ뮞Kð~Ö|O|rfþ·¶î5¹§D+kC.õ —z8‘ËÉ™ùsŸßÜÒeøzŽVÖŒ\êA.õ°<—–„RÐÊdÈ¥äRksiO(­LŒ\êA.õ°0—V…RÐJäRr©‡U¹´-”‚V*"—zK=,É¥…¡´R¹Ôƒ\êa<—v†RÐÊTK=È¥sim(­L ¹Ôƒ\êa$—6‡RÐÊ‘K=È¥šsiy(­L¹Ôƒ\ê¡-—ö‡RÐÊÔ‘K=È¥réD(­Ì¹Ôƒ\ê‘i.] ¥ •!—zK=2Ê¥C¡´2;äRr©Gê¹t+”‚VfŠ\êA.õH1—Î…RÐʬ5¬X¾ã_ž¿<4jú ž[ݘëëm}ïŠî×¹±.÷Ö–ÖÞ¾P~¾«sïjýÓ™$ßï£ (C)ØÐ#Ú éèÞàÊVO¤T<ºÁ­ý™æö¡‘’Ý‹ö’Ò®‘‘­ÿüÚùÍ]mÉÞÏ¥âPiÐÀ÷«¸!Á6Yæ&¦ç>ºv«¿sã‘Á›»’l›˜Òy`ã¾ýCÙŸQ¡hÅÎñþÛëoõ ¥:®Á³593ÿñµ[‡¶µ5Ö忼îÊIîõ˜R·2·µ¸î`(÷ãŸÊ½KGÑÊ =¶sM.á“ÐrI+³òX(#ä> *—´2 †2B.á“prI+Ó·D(#ä> $—´2eÒPFÈ%|B.iešb†2B.áïsI+SSS(#ä>ñ;—´2 B!—ð‰Ç¹¤•)Hʹ„O|Í%­T¥Ê¹„O¼Ì%­T’J(#ä>ñ/—´2¹C!—ð‰g¹¤• ¥Ê¹„O|Ê%­L"£PFÈ%|âM.ieÍ2 e„\Â'~ä’VÖFC(#ä>ñ —´²ÚBi¬Ëõnm½âÔVOÝÊÜæ®Ö·ú]:3ôPÙê±êÞNŠG©Éþ—[Ÿ~ê ÍOÚ30ldËåÕ÷ÎoÙ—pÛÄ”RqÈȆŒ‘½ñ©ê¿½¦òœÛÛQ¡²Õ£ÂðÞNâ÷e{)ùgéë{³ÝG®oÿUËʺ'“}·þÍzç¶zÂ1>U}÷ÓÑ b§He«Ç '¯ÁW7æ¯þò'ÓìsñÞe ¾y0ûî§cǵ™>ˆK½wéd+¹„¾y0ÛwùƱCì\ÖÌÅ\ºÚJA.a¡Tä\.n¥ —0„P¦Â­\ºÝJA.¡¡L‘C¹t¾•‚\B#B™:WréC+¹„„2#NäÒ“V r‰ŒÊLÙŸKZ)È%2C(5°<—^µRKd€Pjcs.}k¥ —H¡ÔÌÚ\zØJA.‘Bi„¹ô³•‚\B¡4ÈÂ\zÛJA.¡€Pg[.}n¥ —H„PZª\zÞJA.Q#Bi{ré+¹Dl„ÒB–ä2ˆVŠh룷í“?—MD·zŒ#”Ö²a«GuCÂ!kšòÞÙÜ>¤òEƧªMõn|šêóŸØùêïŒmõ¨¼ÔF&}øÙàÑ kšÜøù†fMSþ/«~~UÔʈʇðë{³ŽÜèÙܪgÇ1·zŽwoOöÀžátOSçÆƒÇø»Òj*Ÿ_ÅΆr žŠÕ¹÷¯;~eìî¤3÷¹w_c]®wÛºÞ>öͱZYré7r‰ÅÐÊš‘K¿‘K,ˆV&A.ýF.ñs´2!ré7r‰ÇÐÊäÈ¥ßÈ%~ŒV*!—~#—x„Vª"—~#—ˆÐÊK¿‘KZ™ré7r Z™ré7r8Z™&ré7r2Z™2ré7r,Z™>ré7r&Z™ ré7r Z™ré7rZ™!ré7rZ™­Õ¹¾ÞÖ÷®¸´{ÃVO|u¹·¶´ööñZùÏ䆄s{,ɬiÊ~²³¹}h¤äÌ™£­žö¢±mƒ³*µjªÏ_èÞÙÜ>äÐ{ ˜l¥s{,JüùWŒC¿W®Á@ŽV€­9Z r´äh%ÈÑJ£• G+@ŽV€­9Z r´äh%ÈÑJ£• G+@ŽV€Ü²j5ù]>ŸOñ()•Ü)µÁ58ÈÑJ£• G+@ŽV€­9Z r´äh%ÈÑJ£• G+@ŽV€­9Z r´äh%ÈÑJ£• ÷×·í v†RIEND®B`‚puzzles-20170606.272beef/icons/map-48d8.png0000644000175000017500000000354513115373734016765 0ustar simonsimon‰PNG  IHDR00`Ü µgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<8PLTEæææèèçåæêéêêçéêÚÚÚÖ×ÚÙØ×רר××רÜ~”hyŽaƒnX†pZŒsZÈÇŦk¤yb³žb¬h¿©bšf}™ey_{“ct†Z„mT«{cÀ§`Ò¸gͳfζhзhȯ`vxU~jRv\¡–ŠÖÕÕªz_Áªe‰qW‚iMŸ“‡ÆÅÞ©“yŽ_ƒiµŸ”²~e©‰ZÓ¹iðððuŠ\‹lU¬vZ´f¾¨_Áª_ÉÉÇÒÐϹ„i·‚h¦x_ßßàÌÌÌ£˜Ž‰fO¦œ’¸‚g¨‡Z‡pV¢u\¯ižsZ¿´“¾²Ž{hO†|ZÈ®\¾¦a²œ\xwUѶfw]‰zY’’Zv•d¨ž”½¦_®šY‚gLµ bvuT‘Z¢wa®—Y›…U¬hÀ§_·¡[·¤iÿÿÿïüu¼bKGDg[Óé³tIMEáeÑ^3*IDATHÇuV ÒHgI6›ðJmÃ#l ”‚áaC!Ç«Ô6O¥ô¤âéU9ýþáf6 UÞ„„M2ÿÌ{fc±XŒÄöq o‚¿pù‘ß>!¿a‡/ !þÁ‚‡ŒË¸,Ë’„'>۩˜ ¤iªÆÊŒ²¢,’O“”Jg2ºž9 *¥Œ¬‘Å_Ö0Œ#* ˆšÌåò98 ¦Yä:WA?I³¬RÙ¶+HöqÕ6h ”D€ü'¼Æ‘¿Î ««QªØÔ DM™&ò·êz¿ß~"#@R ¶ -ÐSö´Ó5…2¨Ï“Pò3×íÙgFH „%úòÓΠÖj¥Ó^ºò“g ‡Vo4Ç#h² ºu`¡NNéÔ9h²„1#Îáùн°H³^Å£C¡¸˜;ƒG9ºb–;¼p/.†@ Ù‹…êQqTºX,h_zþÂE^ /Ãs@” $JXÌ¥0w™OctB_¶[žñ»î¥uÕ<¢‹œ Ô‰ò„Ä&lAÕŒÏë¾'D ?ʸnûJ`t®ìz2ïSªòºÞò†ÃWÀü ‡–{˜Öid4E³ÅÄp³Bž·ëžçž/³Aѵ¸®"%2VR‚Jòc®û^c6³f3pîÌ4—KD^úÀ¤øë?ã}*bþ¦˜2‹Ö¹û6ŸLÌCLjÂä×ïÞ½¦§5ŽYhæÌârö6ŸÏAêd”Э :‡,•[uU¶«ÆÍ`ÀëÞ:Y¨ù¼VÈ%sIÈ5E ½´˜.èÓC™Ì‰Ó¼µíòª3xÃ×ùn§æû€zéì„.¨¢,æýÄtN¤>5Ê\/‹,¬N§SÈusÝü‰—Q$¡z•aŽãÜ”V«ÒÕ0EYo®ÓIýuÒÒÑ­hC­$¦ªt’Ñ[¾Ç¹ßjφoÍnP‰k†€Ó2aI D¢Qé|vî¾/ R¹µ<ªëZè|Æ¢žE^¶CdÞyãf¼¹ëx=|–Ñä}¶FJúà‡o!ÎËñ™½)¡3€`O¯gXX¢Ô‘ƒ&ôAˆh ­øªf»Ê~)‘ 4UŸÿÉGÄ"R±Ï²fJØæÓ€"Ý'’L |¿¾ ×½6ûv[숼DØå?UO!ªíVô}¿YUª@˜K,“öôZÑì¤N¼ÈMkT ”Z%;»iPÇ2‹tNuE˜|8¸7¼lŒP-6´xm_¢‘ŸóØ” ƒãѨg ­+»,:ØÆ\·Zk3µÏÖÈ÷Þç<Èèšg•r¥]¬·Uân KŠšŽÇ$M¯GÁzgþƒ¦fØ•®WÛ¨ÜnðyR%ÂI=ð”½û>”»ÛTíÊZ’Õ@tII5°AÒî—_Œ¯¼Îá›"•=C€ÕkŽ£á°¹Ë%Y8ÉÙ¹¥rå+¯A†^""g~ÜÚÛ†Û»­< ”M*Å" ;«tlÛ«fÏr]”ÑMÕxÕ°Ü+TÇâß#MT¾|YUq–õ¬ Ô &]ëææðܽªÞVƒùSd4ãd¶kð6æMyl]ºÐ©¿}ã|Ùp]FÖ1ïØ¾ÅÓ Q=:̤qÀŸîw;kw¿úÎÓ÷în·»?‚i‹/Œ’a4¿kQ݈ÑÍ(µªÂT‡E‰&º]\X8Øã¢†d܈ Dœˆ•ØKH¸¯ÄÖˆýùisBþg·ò»m ùuõ ,üý%5Ònƒ¢C%tEXtdate:create2017-06-06T01:31:24+01:00t“É%tEXtdate:modify2017-06-06T01:31:24+01:00Ð+uIEND®B`‚puzzles-20170606.272beef/icons/map-48d4.png0000644000175000017500000000121713115373734016753 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA† 1è–_bKGDÿ‡Ì¿tIMEáeÑ^3ÃIDATHÇ}U à óè97c«@ˆŸÖíU[ù„€8ÜÍÍ|Nÿ_¬ç3>ÎÉk2{Fx½PÇ÷!OHÁK02b¾Ù§ƒ`ÈBmÌ-$Axþ«¼˜™^·½øßÂ:h•_†¤‡^RÁ\px¿‘.Ö§ªŽvGªzˆHðĶz^$:)AäÕ'ÑO·Û;T’m¡XkG»£xñ¯Ð2ÁP"RU2Tåuü~žFND‚à¾üçÃ¥¥à=Xçv67î|óïUý“ÐïEÌQI^™k¿òssó!D´v@PE++¨BDQ­‹ H¨iêT½dT0„¾ªƒþâpØ4 ¸(ߤ$"ÜM°Ÿ)9—І@@[c7Y+AIµÕ9²jõÞnw*@±Bì+€1f:Ù[yúÙ¹…Ų,÷%x Á  ² 3°ày¶kÙ!rìïøš’Æq""¢ZÝ sŒ:É¡ïˆ*€còÉÞå§n=ÿ•?a@D%BãbUUU2@ˆ €³¼?樀z‚¥öÒ ÏüÑp¸ôý×_úÉÚËýþ —½©ÄiX÷ù„„4ì]~êÖ ðgÂ^DTɘôÞËßràÁÄë÷§ÝÎY£zÌÊ*°0.,]\\Zü_ÿCü.¾³ú®µ¨–cŽÁ+OÝzþ+*¡aj½ Q‘^ûæ×Ë·¿ßÉzÀ»é{oå®Fʇ Uèõ‰è™¦<Æ!|]W"úÛ·¿ü¹ñoì÷¸ñsss¸%ÍÞxˆƒÁüpÙ°’3†™UÕ:·µ¾:ùñö»=€$1~’­¾ÞÌFaÝ\ȯ=’Ì„˜³!""0KHâÔÇ¡3Ÿ‡ÃXk’4›L§¬·;ÚQÕÖ ²,B462Öî0Qµ{Йe !#w÷­üñ›1É© z,¦©*1óêêjQäÖÙ8Žªªð¾ñ¾)Ë2Š¢È¹"ÏsEQäyžçyY–iš*šÿøî‹ïml(èDDET/œtŒÛKï¼™+IdÉ|˜†Z4ËËËY–‰´®vdlcÌÒÒR¡,ËÖv°¹±Žˆ/ëŸ?xã;®›½½±ýäâüy¾Ž€Ì'FwÓ»oå\u“Ü,ŸÈ3N³,˲¬®ëý°4«O¢²,×ÖÖƒ÷ž™9ø—¾þ7B“õú•øqÉÕR…,u››ö;÷F.É®öˆõöÄ݈HD­'Ÿ@ƒˆ!„õõõååå~¿ßÞ ªê‹$MÔ&µQßZ*‚ ̺úᩨNËzILcYçfŜʋªgÖ-½¦Ói·ÛMÓ´®kÁ/,.?vãsÓÉá(õ$kÐZÜ?@ â´i^„×{¾ñÁÉ)qþ'«Õ™ˆC NU Áï«/©~ôö¿ÇIRþdsçr¯+ p€ÒÈ!¡€ëÆ(º7ªå BêOG¡&˜Õw¾¡*½þW{™ûìoþî?½ûª&Özä»ù´ô¡\I“,FÂ&o~iŠsN]6÷'‘ÀË®Wó§vÂ.g¢iíh­UUe¡w^ùZê_„w_u+?ÿÂÖÆGeãAä¬!ŠS'Eºq”ÅUٰ긬õŽm¦+YŒ¤¤I/QØhÈ,kí±*ÎZD¬ëz<¯¬¬ŒvÖaúƒ¤Ÿ±`ê_]{ý­Ñ¸.¯$9Ãüƒº›ÄuÙŒ;¦Q¹WÚ;ã…Èn)¾_ͧ]cB`às"õ¡böööˆÈ{ˆI’DQÔ¦…ñx¬ª“ÉdyyÉX *H±ˆˆ ±qš€÷`µhPÝë@|}Þ*´ùA IQTPA ‘ÐÕï1 ‰H¯×cfY[[»páB¯×ÛÞÞ.Šb0¬¬¬8çɺȰ–PTˆ>µ‚ÀW2I£¤ã ‰³¨~¼¿×: v’,FD0`êÀ°š'ÖòñŒv,Û÷ûýápè½'¢,ËÖÖÖZ3µ!gg{KE¬s£Ñöh¯ò ˆ´†Æ½qÓO’ ບõ;¡öÚÖ¸ˆi¿£ªDÈ¢å¤j%)‚>ȃŽTÎ×3‡˜™™s/^œL&Y–k777^úÚ_[Ф* á°@ºöOÜ Ž{“il’–þªª A°öÜÜõJm+OPH¬%G*' Ü“¹ìðDDŒ1 ªê\$€«8q" €`£Ã§QÀ8s#d?ú°/;RÀ(Š, (‹4wGK5™Ž;ìjt6KíöØ£ª­ÂªªÌ-\½ùùÉx‚DzÚ%"ÖÒG“¼iB’FOhôLêë-ù¼hØF¶)šA .‰Z4mÚ?¯k{ 8,û”×~ÿŸ|æùª,O4b `ñμ³=M˽ºYèÇ sÉí+é%)ŠIÉuÓH(ë:¯›¼nÞÚ~¢HíœCÄ–§zÇ}]FÖÄ;Ó©þJp5æÙ+Ùnîu)v×’í½êßv™_mÒ8’s`ŒÔ'’+°ÈöÖ¦±î•yñÞkßîöçDäôFªj£$ª< ¶¥• âp«‚µÄ @ì ó×1@ι(Šˆè 9WëÜöææ7þî/Ijèæƒðy{'èþ[ù°Ï—À" ÂW-ÁL¤ÞÜX÷MÅ÷µª³vgg»öuD¢hê²LŒ5Öœ®Ï10‡Ú{ºO¡íÂPO¢ÖS€ÚýTäÛÿø·FÃa'×VÇeÝL.EI/Q%œ®NKu±›5-!VÞG^®ö{¹¯éL¢`«ÅƒÑ"€è¸É :À£à @„!`ÜÓ~‡=as=Úº;ê啚ö‚HèÓ¬5P* ¢ªÌ†6UhÛ|e…¶¹ Rp#ûïLRèÑû±Blíø¿&uâQðl ѵù¢ô¡ªo-ÂB/fV ݺïë±*‰C»~¯ÈnÚ(²ªÊ¬ˆXzÑ¥íüC—æ]Jª  [©ÐÅ4fFà‰8¤§¬ªJ†.W¾»]1K"‚i/‰Òx¡ç;ƒA<t®ÞÌ|?^¢ÈD“ôÞ›ÅΨÜU"û;"ѳWÒ-ä±ÁvÌ[ '×ç³ngѹ55áÁ:ºÞ >šãàüb6D  ÑÚWWëºl@¡nØ‘Y¾UÜ€BSRf£ÙÞà¼ðÆ ˆ¨’ùücéJ(äçæ²'Œ Q>‘hÖc«Ú—e]û¦nêÆKÛïf×ð oÚÞàƒ¼&BU,­Ûì{ïÂÜŽ‘Tà`"ˆª (ˆûΨ ˆ ¢BæÙ+ée)ªæˆ«gh¨Åx5ËM’§ŸŠ~õ×Ã%.Ê` AíeDÄnšî&b‘46kM+Nâ£ö“ëŠën¾xSW~Ñe™kiÔ†€VO·¯f„iÑYÚÏÿgš¬Û‰û¸ß‹úÝø—?³pá’æUå¹ A÷ßÏÒ Ó|PT†HE èÎnµ¹U´CDhóùã7³A/ôâS͈¨ ݾš=*y9)¹jÎí:XDE ”ñ3¿0?ž4H°q¿)vC’!K7!{óƒéîJ–Å‘(¾ñFe±zî¹ù82 € ( "zÆè³ÅDdn]É&e“W³3Í“Ùpg·ÚÚ.=‹*úÉ\/¹v#ãù¢ BD¢Ê–n˜î܇E1-¸jbç"çF£zw·V(2nœÝýaΠˆxf¦8ÔÓ|?égñ¹&#TP}ó‡å÷þu7ÏëÈ 3sdèâU×pmUŒ£ëân÷ýs—@„eûm©ï»,²Ì!MÇ®˜6‘ƒJtÆaŒTUÖã5ìÉT±R„l”´2QN¨ÁInj…\P”€s4}뀑¢º¤dR¬Ñä5˜™Rr!äu›Ë澇ß:Tu:™&¨Ó¶×ÙAúÁÈñÈEgÍú3 ήãÜü<Ì$²SOžº¢ç\?o‡sî;ûÓ´£»ÿûuîÇü¤Zþ_\ÿ ȸK+ø¾%tEXtdate:create2017-06-06T01:31:24+01:00t“É%tEXtdate:modify2017-06-06T01:31:24+01:00Ð+uIEND®B`‚puzzles-20170606.272beef/icons/map-32d8.png0000644000175000017500000000263513115373735016756 0ustar simonsimon‰PNG  IHDR D¤ŠÆgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<ªPLTEåååéééåèêèèçרÖÛÙÖÙÖÕÜÜÜ~“i€—e~šf|wYŒtZ†u]…mTŸ’…Ø×Ùż·¤t\¶žf̳eìeÄ®k¾ªl|”dšg|}Y}vV|yW„rUs[ƒiN¶­¤îñóîïðÊÆÁ¬v[Á¤eÒ¶fƱkŒœ{‚›jŒoZ­£˜Èÿ¼£bÌ´jÞÞᇚrtŒ\}lPŠnU¬¢—ÓÑÏ´‚i´€f­‚`Á§_ƱcÈ®cÁż½ºµÍÉÆ¹›Œ³~f¬|cªz^¹¡]ÒºiÖÖÙÍÍ̦‰xßáâÕÕÔ§šŒ›s[ºž]¼§h³©ž‹rV’mU¼i£}a„„]w`óöú¸°§’oX›|_Ÿ~`t—b”~^ƹv†\{‹^Ñſê\µ¥nz…\}œhÓºf´£_±v`¤|]’k ˆX£ž^Œ”_…oZжi’–\‚Œ^xUåæéŽ™_ľ®’yV‘›a±§œ‘‰v„gL} iµh™`¨Ÿ_°^´”^ϸh´¥`­‚_²‹a¦zh’˜_ª~i¹›b{U¦W‹‚V«‹Y®ƒl¨“bÿÿÿ `UbKGD âÕtIMEáÖn¥ðIDAT8Ë}”ûWÓ0Ç“umFÉâ˜a´{²«2…Ê:‡èÊ™ÊSñAm€ ¼| ""ñ…´i6Îá'¿'§=9÷Óï½In €×ä‚^ILn·È‡[’D!$²E†nO“,ËÙÓŒ½äðÿMÚÚhejC@Q‘›T9 Gp4Ö‰ŽÎ®$eJÒ¤Æ[)E ¦1ŽâX· €ÄmO’f2”fh ¢;âÝÞ>=v/ÁRögÜ}šp<ŽB=ìèè|ÈÊðQ§Q0s¹ÜPq˜6I "¡ëqÁàÊšÅz ÎÂ×XÉÝ/=‰•†Ìñ ^ƒ8Â0G¥ÒØdŸe•²S^ È Jk‰aÝÈÓ,>3k–çê)|¬v DýóO ~æ_x¾`L/¼xia¸POáv½jCn‚1Y”{‡flYbî úØö¸ ,-Sm¥74‘+1½RUS `´¿„ (¡øR¾V[ž ‡µâ Ûª*‡5@PB£>i¤¥¸\\]›­ªjUV[ ê °eÉ-Ý"…uÅ9½ !˺`ÌkF0¦<½±ùFVH”žÕHÁÛŠs¶0~[^ߨÞÙ„0¾ràÛ´×n±0dw€µ}·˜¶{ñ8œïÕ¹¨Ó +lu_÷äþ~û§PsÄâEè@9å9 ±ƒÐgU k—Lø²˜ÆÄËç;q6Æ>hýZ0é7JOìfb7ñÀd‡›µ­üiÖ<=¦tøÄVÔ”sÜ’5µ«cÝ4mµI9JÒ³C“y°†~!ú‘8TæÞ?^…ƒ]ÌÛIP½ëu˜áƒY:O„Õõ4:^ÔC/P輋×WÎfg²²ÝŽ1"b¯×3Æìïõœsiš®­­5!ìí÷Ú6 IÁB\¤û6õÉ ë ¢áp("e»€j2žÕk©]6McLÓÔ5õîîÎÛyéÆíë§ZåfÛÄYâ"ɬíßp1L1Ór$E1Æc§Óá• «ªªªJ)J²Ö·¯½ùÚo³,ÍÒ Dä8e¹°éoÇ œÿ2 ‚—hvfaÌ<™LVWWŠ¢ Äåµ BPÚ çÓe®Dh€ûÑ¿¡¦Uð™ÑŠÔ#5€G¼#"3k­•2ÞWãÑþž~n2¼õÚo(1·úÃ%k¼A2„ e )ðèdÒ½ïšPÛù½ñ~ôEØù¸sówý¿Ø½籋W˜‰DC÷¦Õ‡%ß:c¯·cãƒÐ|²Œ¥2ÛgÒ^‰ŠçìЋûÎŒˆ˜™ˆ±¿¿Ÿ¤Åþöû|ðÏ2Kwßûi¢öΘ¼çWLL:wÇK=wÇKÿ¤±ei¢± -tP#¢ˆ ‡C¥”÷>Ïó¢(úý¾÷>M“•ÕµftÛZ«tÚ¶!¸Ñ ‡c‚-‘ÂZÕhô¹n@¨L”€hŠ"ÜD¤9ô,'ív»,ËÂ`0ðÞF£¢(\]ítïíïíMœµ„ã±|n¤¯wÔäT–:aÏödÁ'…yꛃÊ^½4ÉæyJ©•••étº¶¶Ö{°óò/b413Œ!øødgùô4~Я§©5ŠEºIº]+"°D¤IŠ¿>Z[fFÄ¢(ˆhíÄz¹¼ZõЌ"د›secu®ÚžRߤ<õi·.“DPfÄð§G 9 ã½Ëóâ›ßû‘Ê–„£‹hM»ÎÝ쇧6²«§õºÔ­àÚŒÉp`™‹öq-aafŽ3³HíÜÍ÷Þˆnªiö¿sA6Fíù0ñ\¶‰¾ºI‘E}6ùÓýp¿ó]O¤Ž6 ¹T$i‘æ%ÇÈÂY«üûÿæ«/Н´&A„ãÔJ !2‹¢"dVDêˆJ~Œˆ!øýõkˆˆˆ1ÉÍÞíá ].¡òíÀ¨IfUCµ“$™õfÀc (43@ÃûûA @ÀÀöI.o¢gïÃàö(m¢"P„>pÁúüj§Ö5ó\M  ˆB¬B0L[…BD!Dô~¸=NÖZ‰ÖñüòÁ¸yf…×ÛÖ1îF?`tz÷ŽÛxÂ"’DE—rx0Áaжv㳩MóC ÇÈÑ3Ç QùŸ©ì×@Ø<2–-]æÉ©‹ÖÛÚö;öξûQ­4„(­$_ÝPn=™~¦ÈVZÆê™æÓ\û}TäM¼g"ä/u–.(ܯ½B‹x}jÞÝ®•"jƒ"‚€Ñc 2ëu³Ëöê:)M³ýP*@ˆðñVYlÖ§.¤ï¼=ºs×µIeÖÈÖ@Þƒ:®¤ÖêÝÚ_ðA ÑœvçÎÃê ­$ õµ}a¥SH¤Jóù­öWžÎÏoÙih¢@‘$[ ÷ë i{;¼þç—¨4æ¤ÀĘÅÈ„P9³’}ý]ió ÞzF3M|ïîd¯®./7N$JC×Vã[€F·¾´´ê ºTjj‹$|’¤ZZ²1Êb~$„À²Zê<ÕG˜ŒÄ6ìe½ÀgÏZðH„”‘×Bd<‚2ê©%Þ³ç|¿0©i´€¨Imnge8ª8u´k³E·Û‘ºª›÷‚4Gçú"xt¨þ´Áwñ&I3DœKE^–óÁZŽu4S±ÿ½Ç#Æà¿ 0È{Ùð{%tEXtdate:create2017-06-06T01:31:25+01:00Òú˜}%tEXtdate:modify2017-06-06T01:31:25+01:00£§ ÁIEND®B`‚puzzles-20170606.272beef/icons/map-16d8.png0000644000175000017500000000232013115373735016747 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<²PLTEåååÜÞÛÚÜÙÛÝÙÚßÚÚÚØÛÙØÞÝÜáááÞÛÚÞÜØßÝØßÞÚƒ™l‚›j„•jƒŠeŒ{aˆoVÇÁ»êîò¼¢”Á¦cÍ·pʳnʲkÈ´vàßÜßßß±»¦™isU‹nW†mR´¨›éêëääã¶Ž|¼™[˳dɯcεaàßÛéçëÑÓÐÐÎÊÖÓÐÎËÉÞÞßíòõʼ´«uZ²h±ƒd°d½`ιpâââÙÙØääåêëëêëìàááØØØ·­£yb©z`¹‚i´f³g±{a©gÞÞÛÛÛÛæææãââÝÝÝáã嶬¥ˆiP¦za§€c±‚f¨d‚\”vdÛÜÛèèçãäæÜÛÖ͹}ÌÅ „z^†oUxŒ^ŒtXŒ‰by›dŠdßÛÛàààÞÞÞÚÚÚÕÔÕÑÌÀÁ©^¾¡YŽ€\xb€•e~ˆ]{’b}Ž^|cÞÜÛââáäããæçè¹°¦ˆoUv[rY§za””bœey‡_‰oWˆpU’zdÝÜÛìîïîïðÐÊÇŒsZŒsYuZ‹mX·•^¿°d§—]ˆZˆpV’|dßßÞÈþÐÊŹ³©„z\‰rW‹pY‡oX†kW¯—^Õºhзfˆ“`ˆnU“ycÛÙ׊s\‡kPƒpRx”a|bƒZª[§|`¹‘cʳeͳf”_}pUЇfÝÝÛ“{bŠmZ˜|_~™g‡eϺfÁ e­ye³`͵fȰfˆ”^œqÝÞÜÜר´Žg¾¦\¡†Y¶}b£`va˜’Y½˜_°†_ʱb̲cдeǯ_ ¡iÝÞÛáÜÛ¥…oµŸgÒ¾qµ•lµp«’k’ƒa¬„j³ˆnÄ­n˵pɳpË´mͶxæååÝÛÜÜÛÚàÞÛâßÜÞÛÜßÜÜßÞÛßßÛßßÜÿÿÿéÝ›àbKGDåXe ¿tIMEáÖn¥IDATÓïþ   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGH9IJJKLMNOPQRSTUV9?WXYZ[\]^_`abcd?efghijklmnopqrstuvwxyz{|}~€u‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®_¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞrßÞàáâã䢱k0R!äô%tEXtdate:create2017-06-06T01:31:25+01:00Òú˜}%tEXtdate:modify2017-06-06T01:31:25+01:00£§ ÁIEND®B`‚puzzles-20170606.272beef/icons/map-16d4.png0000644000175000017500000000053313115373735016747 0ustar simonsimon‰PNG  IHDRíÝâRgAMA† 1è–_PLTEÿÿÿÀÀÀ€€€€€ÿÿÿ€€AÜ–rbKGDˆHtIMEáÖn¥oIDAT×Á1 ehÀ¾Ìýc9ð&®L¤ÿb¼µÚ…ˆª9ÍË`ý2Ê5iô×U|¸ÃTìÆõ€ˆXfvìo%ùƒ[2Øa۴Θ»/Ztµ™FŽs¼7Ó8ËÇõ3Ȳ翵úÏFW‚ˆî3%tEXtdate:create2017-06-06T01:31:25+01:00Òú˜}%tEXtdate:modify2017-06-06T01:31:25+01:00£§ ÁIEND®B`‚puzzles-20170606.272beef/icons/map-16d24.png0000644000175000017500000000157113115373735017034 0ustar simonsimon‰PNG  IHDR‘h6gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEáÖn¥}IDAT(Ï-Á»n\Uà­½ö>gÎxL_ↈƒ °04©ò¼¼  A‡ ˆ")$ÂX1ñLœxœxÎÌ™sÙ—EÃ÷Ñh4ªÛEJ‰ÊŸHaDŒØØµ D„ÿ»¬/U=ÿêÇÏ”wÐÊ÷¦!Ì«[òæÍî}ÿ¥•»KÃA ÷7n|ÊÖ¸w¯¤IãÑY~Rvåt÷ÃÛ×ß~¯[L»É©Ÿ5)Ì5Tb¬  ÂÌû»·¯m¼£{³®iÚK+ë’Ç÷ª§Gai¹z4Ñ`K‡[ ÑEy¾2\s™h±¨šºþ퇯þqgÓºŒÈVÐü(NfõÞŽ2fÃLÁû¶^Äzý*·/"èEê¢AÅñ0ógã@ŒQU™ ,šÚɃÏׯø0\~\Íÿ\ò—åIž&WòE¢”€¶mC¾ó¡9›_ÇÓÙçëƒÜšrUc2댷J"*Šç½âþÁOwï|c3‡€ÍÜ:Áy_ò¥*¥d §€›¹,c¢Ë›Û"Vc"C'³z—ÜU>õé¸3x©`”⿇ò,{öìä÷_¿³9±I“6Œ× ^ããÐáÜSTºö—o¿ˆÍù„É9gïÙß³Ö^kíõ@_~ù%ôQo&|¹'ÐGÉR„½žú ìõÔa¯§>{=õAØë©Â^O}özꃰ×S„½žÄŽþÀã¿ „ô?.|×ÅÞØ5ºÄÃõÌyv¡$I|0UUõÏRŒ1PJ5Mã¿wߺ„‡cŒ©ªŠê@†ç‰¢”BRûü!lnnæ8=ë"Š¢ >ŸOQJ©Ùl¶Ûí~¿¿›Ö!d0ü~0$„Ȳœ––¦( !¤§¡(˲¢(^¯WÓ4Y–m6[$S&Oq dŒÉ²}|>ß+¯¼‚1¦”^sÍ5“&M2›Í”Òž°#r¿ÌæÍ›·mÛÆ¥×©S§žzê©ÜÜÜqãÆ‰¢˜’y^ ‘BÜ4Æçççkšf³ÙdYAŎÇB¡Áƒ¯_¿žÏI„¦iÜI¹QÁ÷Ýÿþïÿöûý¸!6›Í`0ôüøT !óçÏ¿ï¾ûøKÆ'f2™dYNÕÂ#b†—ΫpÏÓ÷îÝ»{÷nƒ‡Z¹råòåËÊñ¼!%ȧa ‰"mi±îÙsËeAÎËܺõ†/¿$ËjB‘$Ñ'ò.@>Ÿ|ð`þ[oÝâ÷E<¿Wzg.–.àBA<ÏÌ™3.\˜““c0æÏŸ¿uëÖ“'O&ΞíZ!„!Èb >ðÀÞŒFuÓ¦ÛΫªJ1%¾QUñÕWW ^1p`Ceeæë¯§µÕÜØh-("öZçhW(:9MÓ´º\®Ã‡+ŠRQQcÇŽ5™Lq«8‡3&;;;¼ÉEÆx÷îÝÈ”b»=àtú0fuuÎÚZ'Æíæ{P$(Å60†(Ååå9˜–HKóœo†ÑŠ?lܵk×SO=ÅÓûìªíÛGšLtòä#‡?u*´ÿ2§ˆL ¸öÚk—-[¶`Á‚:tè¿øEbÃ%â G§²sçõ§O[¯»®fÊ”ýzv1Æ$‘ÆFÇŒPU¸ë®CÇŸûâ±\Èü£Fºé¦›l6[^^ÞÒ¥K÷ïß_VVvÕUWÅnphß~ûí'NÄî—Ü&ᎎ`Aˆ©ª8räÙÁƒk ªJq§H ÄC’¤ýàŸK’6thU0( ñƒ¨êO¢(¶¶¶¾ùæ›C‡íׯŸªª|ððšxq Ì›o¾™ä<ššì55iN§7;»UÏõŒBLÓ„ªª YÖòól6?¥ø[¥ÈpŠæB„Ð{ï½÷»ßý.œÐe±Xüñ$(Ä“ë;C‡õŠŽÉ;~<#=ÝsõÕ•¡žÓ~„1s¹Ì\hµ’#Î:a]æÛET¼ „X­Ößýîw%%%‘‘Q\\\XXÈ tô”¤«Ã±[o=}íµµƒרª ‡“b„àôtïÔ©Ç%‰X­XñÛ5Ó¾×…kÄqe :tøðá\·äðŸÎ|îH.ŒË‘#Gž ‰ªªW%¡ÙíþÛo?ÎR‰ÒøB^ÿÉ;ÿ.½Î!Â`0ÂîØÌ6Œ±¢(ùùùyyy{BÀã1Æ4R„òbŽƒb6›¹uÔ)¼Ò–Åb^åÙ‰a§É›÷=}ZO5`X P `HüžóRf³yúôé“&Mây‘”Ò†††î‹G»ÝžžžÞ‹6Bèz¹A·;ôÄäØ1„1‹<á8jøÇJpg†i×®]ÿû¿ÿ;yòd¿ß_SSÓØØØ}J#BÈårB²²²zŠ]…Ðd¢GŽÐcÇ(c(ìÝf¬-ü!t!krh…öŸzD@zÿý÷ï¹ç—Ëår¹û’'JikkkVVV/’¥]…(m+—Àíz^.ÁjEW^ ±ÆFV^Î?Œ¼•´ÿÔ¯0p{ ÑÓ­ü¥QRªó…Yû˜ k¯5nßnܱCZ²„wIá\{g\JJºh ÿ cD0Æ\.À¸)ñ#óÛ)AažXnèuüqi(Ei1”!Œÿ"ã6G5!Œ¼“عڣzôXJA¹ Dzê)Sd¶¬¶VÛ¸¢Ÿ}ÖV.!áÁÍEÅ6^üºúˆÅ•,&éžµWXM„<;Àn·OŸ>Ýï÷˲œžž^WW×}¼ÂÄ3Èùü322xÉ^=7Z,‡Ã¡išÉdr:ÍÍÍúeff&Ù¼¶Ãn1çÂ@@ûë_IÙi„…N£ÿ(€`ÀyCgW#@”Q³Ù<åS† ÆÛ}!„\­­~=ç…EÅ12`‰‡dÀBv›Ýjµ†ã†|>/¯ž€QøyrZZ/ÆÂÏ5[[[ck¿ÆÞh6›¼ÆRÔU€1Š@¶§ #0]™( À êÈ[aÀ8ŠÍžf%¨´ 7J±,cƒ¡ó¹ÂKñóG1Æd,cÔ¹jAhüJnÛèqòñüÐÈO:jQE)é‘Þuu†!0cScC¹[u!Àzbp€¦/VbÀD$° Icbf3q¹´sçÞ‰€Räp œðGÉX®TI%~sär‚Q¡ Ä#ó:­;Ã÷³ÈüKÞ‡¬Ó¼h^./ne¼‹¢.BH5 ¦ê>X]¾º.XÇW<™yÄ,&bÀ Øðìï<1ø 2P£LTùKzêTì1dÄCYYÒ“O S§²€_ä׿~ýO•r©. 8î<ùpF:G.¹bIž1OcšªªUUU‰Ë:pÍE„ÌÌ̬¬,þIkkkmmmHG£ÑØ¿ÿ$Kä .Œúˆ‡… b´2 Ô(¿|½ôÄÒ†Pƒ0Æ0B#õOÄbG `Aœ?a„,PFµrJŽ›2o ø]ê¢ÿ 'O¢È¶&\ï„ ¬O„Àç#û÷£‰lyƒ?«û䙯þÆ4 I:œ B'='=ªçŽì;(¢ÕUÕ---\cìˆÂ(z<“Éd±XxR¦ªª‰oäÄF¦¥¥Åå×H  cÝ8ʲl4y‚5!$NóP"ë•ú¦P“CrFZ@Â’„%Ê¢Š®!Ÿæ3`ƒ€„¨×"Œ(D1 æ¨?a„UªªDµŠV‰eÞ2A”™ÏÇΜáU.ø–í›Pd¢;ˆ"x<´¶Va>ï?¯PÅ&ÙTªú5¿Q0Fñ"Dµ Y0[Ëß PE§ÃQä׫ªªišÎr <²„Û§‚Ëg›ÍÆKƒ(ŠÂ;°Å)FÝ&ÂÙ³g?ýôÓ³gÏú|¾ôôôI“&3&^m}ŒbÀ4¦Ý›wïæ•J³hæ(rÑ ûúßw¸õpe RÆrxá  0 (vÿ¥ú/FÁÅa?ñçónJ¿é½Ú÷¸|kƒ(òKrYj±–.³™UW«/¾ø€ ÓຠaDÆò¿õû·÷jß Ò Œe>O Xeª„¥f|Tÿ‘ŸøÛ†»HŠZÜ$íz¾M­[·9rDÅ›o¾yòäÉœ#£€ˆæBAž{î¹O>ù„o³”ÒuëÖ=óÌ3=ôPlG{®7FÊýå³ÍzõÜ« ¡“`â«ã#¾Yù³d$×*µ–"_|LÂRM°Æ&ÙÊhÃù Á‚!„$)gÎ4{GÝ‚ö axÚÚµ‚L&áÁQZ=qB}ñŶÖQß,k ˜‚WóºT×Ü‚¹/Ÿ{Y¥ªˆDИ|ÅŠŸ~úéŽ;Š‹‹`ãÆ'në¾/h>ðnÍ»s çfÉYàÕ¼³ògIHZS±⪂¡õëÁìüÙ>âÃI0CΘW8z÷þÙüO£`Œ³ œÕ(eŒhjb¬¥¥-f ²9Í7àWŽÞ­}÷ ÷ ‹b„ #(¶ hÁiïé¿Tÿ%RN\Fâ´›7oÞ·o_AAÁG}ôÆoX­Ö?ÿùÏ»víâý²;„ßÿ“ŸüdÚ´i‹eôèÑ·Þz+ÿðHÁ#ɱ­vÛa×a®%ÅÙ–0f”J?þ±ôÓŸ²†à …‚A”—gܵ 4 ee)sæhï¿÷uãoÛöºí0;6zÊsj[í6þº žQ'ƒ—©«©©€´´´P($Š"¯DÖÐÐà÷û£¼ q áy$óæÍûꫯîºë®… úýþĆ*eÔ.Ú?kþŒ»#çŽíuÛcn-\[Am¯Û>){’€„}Mûì¢=>ÿ…IÁdƒ¡­³%` FcÛ' ÕHƘE´|TÿQ¡¥ðÛ5ÖhLmk×3 ÏSç•q©Ãá8xðà¬Y³Ž?þðÿôÒKvŠç_Þ­¹çÎkP–µ|~ÑücŽŸø»µ¸þ™)g.,Zø|éóUªE <š§ÃåÑÀååt÷núé§tÿþ¶þ²Ý»—îÛGvïfM”+_”ÑÅCo¯ÛþVÕ[‹‡,æ6LGÒþÒwºæææ@kk«(Šc·Û ±Å/£k°™L¦>øàç?ÿyKKË£>º`Á‚úúzè´¤ —xgåÏÂo©Ú¢RUÆò£¾rî•H5¿ dÈ>¶­vÛq×ñOÉCš?{Ãù f!^-WÆBÚ¦MêæÍ|S4}ü1X,ììÙàÌ™m§< ,Æ÷ÈñãúË)ï©]õ»0³`^P´àå³/«L•±|¹ákCÁf³7îÀÿøÇ?ª««kjjNœ8ãÇõÛ}Ã"Ü–TUõµ×^kiiaíÚµÅÅÅ7ß|ó”)SjkkcÍOhçn?HHZ[±Ö€ NÉy¤õÈ;5ïp5®s ’`¦œ9¯pÞ¶šm‡Z9%§7œß³ógH…@ãí»¸­• OÓ$ÕZ Œ×?ß©yÇ&Ù’ƒk7 ‹ HИÖd)B( Θ1£¸¸¸¬¬lâĉ÷ß¿Ëåš2eÊwÜ›4A¹äèÑ£EQ4ü|UÓ´´´´ØH¡ÊþãgÌÆ4»d?Úzz´ðÑÕçV»T—ˆÄHÓ^cZºœþhÁ£aý“¯ E°l8¿aΠ9|pKÕ 7*8“1N'JKc<΃DmMÌ-˜[æ-ãú' NÉùAÝ¡Ç {åÜ+=A–ruÆét®^½zëÖ­‡–$iܸqwß}wÜ&™qê‘.Y²$|ôÅ?¤”z<ž(»‚B[ç Ë'\'J½¥‘ú'aÄ&ÙŽ¹Ž%ðwHØRµå´÷´]²sá:ªI0ýéë? µ5`CùŸ f¢ÀÜneÆ Eà‡ˆãG±ñã†OzNFªK„»hßY¿³*Pe ~â¿Ü´ŸuX,–yóæq,TUõù|qM»8>R—ËÛW6J‘Õ˜–)g¦Éi^ÍkL%ž6´oEáxf­çüç$,Eþ $,µ„Z•F«hRè¹[â)1 Fi…æBÂ:°J5:¤ç¬V¨rÒsÒˆ£Ý ˜OzN°AÏ™â¥!î cÁ‹VèíSÑé!'w£ 2Z4xÑêòÕõJ½€…*ñ§HM#ZGípÏ Œþ{¿Ÿš7Õ¯ù1`וּ·ÅˆJSe1YŒP,~œ8Š=-v-–sâRWË% ¢¡»ûÝ]ì(nVš1Ò«‘ëLå(ˆHÌ·b„U ¡ô¸÷v|ꈉÐI0I ±ž¡NJâÔž1?õÉb6˜uâ‡\q{Ìt4¥Aw“ J¢ÁËØ2E_F$ðüà¶‹ÉEí¥ÔÕn1Œ‰¢¨ªê†Ξ=«çx „fä„:E! L&ñûwâ!C¦©íP"jâ' Þ=£¥=Nç_›ºÔ-†1¾Ù.]ºô½÷Þë´ú'^"aÀU3!ŒÑ76J«W‹£G#J¹îK5`C­RûJù+s æƒãîã0Ì6lzÞôµk«UÑÒClEÉBÈ™oúô郎›E š5kZZZPL®=JK“yc~?¾òJ câôéÂ7‚ÃÁÊÊ´-[bGdŒ?þ¶Ûn‹ Ç¢”Z,–·ÞzëÔ©SÑóD1 ¦¥á•òWæÎ ±JÕf¼Zþ*ǯ“sæžJÉBÈqêÔ© úTlݺ5.„–&=ù$( óûAQ@˜:0Fv;ùè£X¹3~üøŸÿüçuuu‘í×@Ó´ììì/¾ø"BN<½IiúŸ3ÿ³hÈ"‰«ÊV5…šÌ¢™0‚{‚fpñ”²vÌq«k鈺LwÌAÜáÊí‡L93@p¦œY¯Ô÷Rs‚S²ò=iÕªU›6mê¨á?÷gFa«¯WæÍðxÄGÁ7Þ”j/½D¿ü9´ºº£áÞ~ûíÒÒÒØ¶¼mØçŸÞÑl$pýåþ÷¯>·:DC~ü¯U=ê:j—: Øé©”,„˜}ûöé¼2ü¯W{ûm$ŠLӄɓᦛ€|ú)9x°­˜ Äz±B%%%%%% ÆŠ[g#ìVÝÃìæçMµüUÎ|<÷ǹsÁ‘Ö#='ñ¢è2(žQ :½;|9\”QÁkà@[òJP w ¿·ÿ½k+ÖVªÍ¢¸v3·`®Â ωÞ(Q/³QšÖ&T++éÉ“@)x<ªÊ˹]xyÛ{ ×¨ÇãFÌ‚yBÖ„×οÆõO `LõJýºŠu÷ö¿·Ü_Þ¢¶t×Jwu©s{Rè>–„•€C‚ ¾ð‚Ê+®aÜV?QÚ)/“Ù®ýêŽ7då3Ä#@cëÊ×F¬¢• [ñVÁÚ¨4®-_+aI@ŽIRп&{—þ ¨‹¡C‡^sÍ5%%%:O*XÌÏøY$Š ~ï{š×›–‘qÇw¼ûî»±M䣈Çá]yå•îÖäi*N+Î7åW«8fPF'îòDÆ´‰YE$jLs8<\E’$Y­VMÓŒF£ÅbIùucZZÚå)—Àu¿óçÏÿñ,--ÕyRáø¿Wøõ8gC‹pÿýÂ÷¿Ï‚AQ’|>ßš5k>ûì³Nç6dÈyóæúƒ~³h>á>±©rIp:¾-ã¶{úßâjii‰$Š…A’¤ÌÌL0Í#—£“2ã‘ÙlÎÊÊÒ™ŒØu½\7Û zŠ„ð_äI#„W§å‡ÌF£ÞEQxEžÓ$!IÏ]hÃ0ë¯qYZg¤Ø»FIô©@( uZM а¾c÷Èa ½„¦iGçÇ{ñH× Ó;ÏHO7¥TçpQù¡ú]¸—g/ŒþR·û‚¡‹7Boh¿–2´¿}áº;Ýnøe—÷Ò¯†ç™ØÄì”JùÖÈ[ëðèã”(ÍN]yYž5àõz !zðÏ“wžê4ﮇSÊ DUVV–––655BòòòÆŽˣܺcBÍÍͧNâ^222ÆŽëp8:-›UUU¥¥¥555~¿Ĉ£GŽ-.Ý‹(rÕôÌ™3Ó§O÷xüð÷ÜrK0ì½ÕøS³ `ŒƒÁàСCýë_ÿùÏ^°` »wï~çwbÓûS2\(JOO_¼xñæÍ›Ÿ}öY‡ÃQZZúꫯJ’”`8.Ø¿÷½ïýú׿1bH’Ôù/qÁ¡¨‹SÀ…ܺ(**â…(¥ÅÅÅÛ¶m«¨¨÷™Lí×㩬øÃG(úÎw¾óÉ'ŸìرÃår…B¡=ky1‰Ÿüä'v»}çÎÐS[&p Å¢˜¢ÚÜŒñªÆÆÆôôôýû÷×ÖÖÀ¨Q£ ªù†û655Y,–’’’ÒÒR(..6JE¿ßOéÖº¦]þ^ƒ¡¢¢búôé±_cìõzo¼ñÆõë×G:ðR¦ÎðÓƒŒŒŒƒ>ù䓊¢,\¸p„ ^¯·;¶^?ÒápTWW/Z´¨¼¼|òäÉqëÅ7xz ü ‡ÉÇ­HËA[[[£ªF§R#u:ûÛßžzê)¯×»dÉ’yóæ)Š’ü“ã/ËqôèÑE‹;wî¾ûîûÕ¯~%Š¢NÕ)lFÚˆ—ÚŽV0¶Z­q¹ÐãñÄ–ML¥ ]³fͳÏ>k±X~ÿûßO:ÕãñtS—îdß¹sç’%KZZZž|òÉE‹©ªªªªž½Í`0X,.ŠeY¶X,Á`°Óò¡—€xÑŸ~ýúñºAq×cìóù"N¢*pÄsFã_|1mÚ4~Ú’ŸŸÏëM:uÉ’%iù]NÇ3uêÔóçÏ ‚PPP@)õz½£Fzá…¸R;"ÿþ¡Phùòå§N*//w»Ýýû÷ÏÌÌ;vìÏ~ö3¿ßßC<5‰§ÑIõ§./+B(//B)mllEÑçóuŸ eŒegg+Š"I¯Ïá÷û@'ák1ƪ««ËÊÊÒÒÒxAôÒÒÒ!C†ôð8%ÖH£?Iž ÃŽj)ª=Ý……IXÏŽ­‘—x©ÕpõnlôÞ¶4©Œ# ¯Â¥YŽ.Ò͉d¨I>êõAØë©Â^O}özꃰ×S„½žú ìõÔa¯§>{=õAØë©Â^O}özꃰ×Óÿ©c÷ÁirÂ%tEXtdate:create2017-06-06T01:31:12+01:00™Ò¡%tEXtdate:modify2017-06-06T01:31:12+01:00è¬IEND®B`‚puzzles-20170606.272beef/icons/magnets-ibase4.png0000644000175000017500000000110213115373734020311 0ustar simonsimon‰PNG  IHDR``¶j gAMA† 1è–_PLTEÀÀÀ€€€ÿ€ÿÿÿ‹[çúbKGDøoéÇ oFFs$dG†_MtIMEáeÑ^3 vpAgèÉQM4/IDATXÃí—mƒ †uz3=Àä. ‰÷?Ó‚P°›¨cÆþëàáµT—eØ[@“ÐzlÿK„ÙE<“ ˜à À.»Š; Ö!MàÌ+Ê3ìAÆ•·°f šò’Òj¿ ¼´hIÂɺ–Ió[ç* _xøþ}™j¼Zã>¨éH•›ÜXæ#ô€>Ì @?èÓ€ðC€Ê¡ðýÙkêP9Ö®€õS`ÇÀÍ»ÜJ³{‰Ý­ìû@ØW´¡ö+()`@€Ø¨Ü;ˆ¾Uã@íüâ<@‹… ú}°j h@R€H°ýÿ °öY±Î,•þ·øM€ëðÀ‘W´¦€Ö[ïw 2g½Û1*áú%ÿ'¾ c+|ä !Û%tEXtdate:create2017-06-06T01:31:24+01:00t“É%tEXtdate:modify2017-06-06T01:31:24+01:00Ð+uIEND®B`‚puzzles-20170606.272beef/icons/magnets-ibase.png0000644000175000017500000000216513115373734020237 0ustar simonsimon‰PNG  IHDR``ÕF‡ gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<ÿPLTEÕÕÕÕÍÍÐddÍÌdddÍÍÍÔÔÔ¾¾¾¯¯¯ªªªÔÆÆÍÌ ÆÆÆÒÒÒ¬¬¬ÏWWÌWWW»»»«««Í­­­ÌÐYYXXX¼¼¼ÕÇÇÎÍÇÇÇÔÍÍÑggÍfffÓÓÓ¿¿¿ÎÓÎqµq. .™rµrÈÑÈ/ /!œ!f²fš''!›!"œ"¾Î¾H¨HE§EÅÐÅJ¨JF§Fk³kg²gÔÕÔn´nj³jh²h›ÉÑÉ1 1 › ÎÒÎt·ts¶sYYYÐXXÌgggÑffÿÿÿNû bKGDT䈥 oFFs$dG†_MtIMEáeÑ^3 vpAgèÉQM4IIDAThÞíÙiW‚@`*&-)³Õ²Ý²ÒÖIÊöÅ·öÿÿ_r@ ˜¹V:s¿áõ¾Ï¡F†ñª¯ÀäâÖ`"éÎ §,nµû#£i ±Ì8ÉŸHMZB`jÚ„h&K€Ù9K äL(€æ °`I X‘œU¡ ê ¨¾âÄ™j *]?,Âp7ý%ø¶e™+²mËj~ ¬60‘šÆæV”¶;[Ç]ñÖQWjoÿêàpÏç<_ ô÷¹ý²}ÉÇøÈ.“yîóEztÄŽ+°|Œ+Çdžÿ|1=å'Ð|ŒOȼàù"çð|ŒÉ¼èBãN£áŽÃgç¾ù‹ó3ß1§ŒÀž3¸¼ºöÌßøŽø}À—@çsú*€'•Ïî+_ ì|f_ è$ðòY}EÀIàç3úßyÔŽ ´nùt_ÀÕ»{,ª@_¸¹zžA°¯ ¿ï¥@ úŠ€ûÿã t_mu×O`ô•€ïõÇX}À»¾Y³¯ø_´Àî‡~ÿ~ð‹w´^oúRà±ͯUCõF–ßlÔCFëɆäÛÏ-#ÐcÅ=æþL ò¿Â?ýîþ_ ŒgÆèîÿ¥@vÁ€Îþ_ Ì#(àîÿ¥‚fü€à/Kð¼k˜/šºJËæ5) þËTq‚ èᦿ(™wÞ//ðmË«xÞ}¿`lÖaÀ[~U8ßy¿ÐÞ:¾— @ñcS8ÿõ~!æõ ô£Ñ1å¢w;%tEXtdate:create2017-06-06T01:31:12+01:00™Ò¡%tEXtdate:modify2017-06-06T01:31:12+01:00è¬IEND®B`‚puzzles-20170606.272beef/icons/magnets-base.png0000644000175000017500000001363613115373720020066 0ustar simonsimon‰PNG  IHDR蜧ížbKGDÿÿÿ ½§“SIDATxœíÝ}LwúðÙÙ·á€v¥•‚6ºÚ–Òjøµé5àKJ+ÈÙ&b%ög­ Æ„ôN>žß¤‚ õü§#†ß©6— Pý0°££ÃjµÒË)))iiiHÂòFêùÏX":b²X,ÌÖòòr’uÂ~¤žÿL&ÞýÔ××WTT400@¿,//ÏÍÍ6¥ H=ÿND'ßLíííeee6› ’$wìØ1Å-’zþ@Œ…ÑØØ¸sçN§ÓIEQ{÷îÍÉÉ:© H=@p,ŒÀ3iw¾iµµµ555ô²V«=tèÑhDœRÏÐDtÄp¹\ÕÕÕgΜ¡_ †ÚÚÚ””a³âNêù&Í•jkk+--õ½T©Tr¹Üo›ÊÊÊ5kÖ„ÿ^8H=œ?þèÑ£ôrooïýû÷éå… ªT*‚ æÏŸ¿gÏÁòcÑÃ7×’611¸ =p'©çÏ‹ÅÒÝݸþÚµkô‚oŠ€àÄ{¹‰h(€x„XD6JÀ P°€Â€, 0`… ( X4WÊáp>ì>wÎk6‡C–”$ÏËSnÙBP”ߟ¼^ï;wl6›˜ç&)•ʸ¸8½^/“Éüþ„$Üñq›"pçÛk³=,,ôZ­„Ýn¬¨(Y|¼ú«¯dqq¾un·»··×ív{<žpãcF’¤\.OKKcÎÃE˜?îø¸±æÏÓ[óü~A8÷íó#¨ ‚ ìvïð°sß>溡¡!—Ë%þ½N„Çãq¹\CCCÌ•óÇ7Öüù!@axš› ¶)Ù!š˜ð473WŒŽŽúÍ3¯×;::Ê\ƒ6Üñq ÌŸ†÷·ç,a (ž9ýù%Œ<Üñq$a¸* ý‚)jò%ûtBm‘ÁºzõjII‰ßÊ‘‘‘¶¶¶¶¶¶S§NÕŸ†R Ò éOG 9ö'ÂmJ¶?‰(ŽQÓMK Ü®S.BîOG ±ÂéO…"S˜ýID1”­ðû“@a€Hƒ¤?‰( #ðL¦„€Ð êO"ŠÂ |hû“@a€ÑÞÞî« ‚ óóóý¶áÞŸ D´ýIàr-,àˆ"ÄòåË>ÙC¤…—¡€°"p(Åÿ£VÂÄsÂðùp…'È#ºB#“ÉâÅâ|>\D`aèõz…B!‰}O’¤B¡Ðëõ|¾)|>\ˆô#r¹<==Ýb±X­V‘?‚2>>>11‘û”O$àóá" ƒ ’$õz½ ÿ§‘ø|¦C)Â'Àã9 1¡%3@ ްˆÌs èÿ05Iôß¶?F†Tú?8Α‘›ÍÆsÿTŸÏãòÇŸ8”‚þS“Pÿ™Õ7èÿ05iõߘAý1pƒþ<¿Ïý=ø…@ø‚;ùþöÛoüñÇŸ~ú‰žPàñxbccçÍ›·lÙ²7ß|“û3Ö…2>Nýüsr_ßìáḱ±(‡ŒŽ¶''gfþüä“Ãâx\a:t¨¯¯¹fddddd¤³³ó³Ï>;pà@VVÒôëî6üðÃbæ›-Úf‹¾vmîÊ•íK—ö=î_I|À›P†R±±±éééK–,™5k–oåøøxEE…$®¡ÑàM¸W¥ZZZ|U±`Á‘Ïdf~k ‚xð@ÝÓ“L/ËdÞÙ³ï‰<>àM(SBêëëoÞ¼i·Ûoܸa2™è•sæÌùè£BK"„‡;, ûi ããÔ—_¾øàE¿Ìʺý0̘|ÆX…R.\èîîf®1~øajj*š¤ð:qâå{÷5àY°àæË/wOý¯ˆ*>À Í >“É”ŸŸöìY$Ñxðõ×Ë}ßÚ¥KûÖ¬i“ÉPÎ"ÁàÊãäÉ“AŒ œ8q‚~`¨Ó鬪ªÊÌÌ ù1º¼±X4ƒƒ ô²^o[¹²í¼fÜñBŸvóÔSOíÞ½»¿¿¿½½ §ÓùÝwß½õÖ[èÒÃÂã! 3½l0 !ÿÖâŽx€à÷Z­Ö·l±XBˆþ™tPôzëoü Ýø€AÆéÓ§>|˜››ë»&ëõz/\¸ÐÒÒâÛFÌw÷|î܉ÿþûGÍD sVÖuiÅ<¢0úûûëëë?øàƒ'žx"))Éãñ 2 +W®Ä$bv»º¯ïQôØX»äâ„2”º}ûöíÛ·ýV&%%íß¿ŸÙlé ¢0 ¢££;;;oܸqïÞ½¨T*N—‘‘ñÒK/ååå‰|>ÜQƒaóæÍøRáͼyCùË—Òx¿à€……5 Ôû? Ï_rˆP«W¯V©T¨¢©TªU«V1×H½ÿÚü…ê/!uFYY™N§£(*üPEétºmÛ¶1WJ½ÿÂüì/!u†F£ihh(..NNN'NrròÆ4 s=Ýÿ!11Q©õOI•JeBBBzzzàP Iþ‹¸!lt $ÇgNêÁŸpU P°€Â€…@mçáÃîsç¼f3¨h{5%%%åååmÙ²%ðô߈x1¼6›#/Ïuü8Úª@Îl6?~¶Ýnö=QŽý7f ÃÓÜLLLðÿ¾¡™˜˜hnnf®þ3C)«•ÿ7 ‡urÂ’™H.a1€«R°isʨÉwOí¼ßø31`… ( X@aÀ ¢¸*5Ý þÀ ‚ºN%Hÿ ipÄ€, 0`… Qœ|žI£gÒ XpÄ€, 0`… ( XˆâªT øe–G Ôý1pƒþ¢ŠÏ C±z5®?nÐClñù!@a(ËÊHN†¢?nÐC„ñù!L¯Ã᮫s}ó÷Ö-„aÑ>¢3999//oóæÍèôx<‹ÅjµŠùa„J¥2>>>11‘$ýÿ÷‡$ãóúcÀ.×À P°æßCÏÃÏú?»x÷â݇wI€ Z—£ËÙ0wƒšTûÿ EYR’8ùsmîÜ<êu¸<¿u°(9¥QhŽ|¸­­í×_s¹\###mmm»vízã7îÞ åÚ¢Ýmÿûÿý½raå3qÏL»±Qc¬\XùžØÝ\Ï}qÇÇMêùóÉãñTUU½ýöÛçÏŸr:V«õòåË{öìY·nÅbá*”¡”L&KMM5±±¿_ìé驨¨!AWF¯¼ÿÓû;îœzß5ƪ§ªö\ÛÓiëU|ܤž?o̽Ž;>nRÏŸCCCŸ|ò ½¬ÑhNžzèßã¾¾¾¢¢"ßIEyyynnnÈÑü\½ò¯þm™¿åó›ŸãØë¸ãã&õüq NJˆ…ÑÞÞ^TTD•H’ܹsgIII˜©05Æs7úåЛ)or¹~/¶ø¸I=˜çºǤ)˜<ð-û†US ¥07mÚd³Ù‚ (êŸÿüçúõëCˆó8¾qóný‡Ëõ{±ÅÇMêùcb0|ËÌ ¹‡Ã7ÊR*•)))\¢]µµµï½÷}j¯Õj;–““l)øMr¼·%l|û¢E~ÿ»°ùG†çžûý)1&“É·ÜÕÕå[6J¥’K´àæJUVVÖÔÔÐ/ ÃÉ“'F#÷Ób½Æ‚pß㎛ÔóÇêµ×^S(]Lúúë¯éq¾Ó鬫«óm³víZŽÑ‚(Œöövæý‘ÁÁÁüüüç&;{ö,÷€~¦¸òˆdß㎛ÔóÇmöìÙ›6m¢—GGG׬Y³aÆÜÜܶ¶6zåâÅ‹™5¦DaøéOLLØ„<ÇvÚëñaî{Üñq“zþüx÷Ýw ée‡ÃÑÙÙ雨š‘‘qðàAî?‘Åï18Þ¥ yß㎛Ôóç\.ßµkW]]]NNŽN§S(æÙgŸ­¨¨øâ‹/¹‡ âßòåËq<9!Jõ×Ý}mw—­kÚ¯Œ^Ù}m÷{ïmêØÄqf5îø¸I=þeggggg‡D€§„äü×ÿ*ERO¿ýçû ÿsÁ·Œ£ws’ŽÏ‡™?Ž=Îì‹‹;>?JiþwX‚Úëüo˜0Ïpÿ÷‚@ÆuT‘ÒéAª^Ö½,t€oFɼ­RËòx?ñQ“j­Rûçy:À7 #FSÿlýŸRþ¤W Є;½Z_ødaý³õ1 ÿ_¡€ˆ'̳kÕruÉÜ’’¹(ç€(îc 6"mg,fhšÑ «•ØÀÂ1ÇáÇÏ;òãvXµ#Œ5eÿ ñ( ›ÍVXXhµZíHž¤×lv?înlôë_f†RûöíyU<ÂÖ¿ÌFssóÂþ¸ô¯3…aEÝ_7ä 1€øÁU) €þü›¡…°nÐC3´0$úc C ?ÿ 0¤úcð C2 ?Ÿ 0¤úcðF³kCøù|P¿ŽŸöºSàA=ñwþL¾t%@U`"ŠÂAþ<€¡”$A Ü 0$ úcà…!=Ѓ¢8ÇÀýœ¹À3i¿³í0.ÈçsòXûcøÎÅyK#âÁCJ ?o 0$úcð C ?Ï 0$úcð Cì|ý1¸œ[Óý1Ê3Êá÷aÅU)þáèq‰Ým/½\ÊýÉþ]¶® ¶¬8bÄÇÇóÿ¦a™œ0òüý"ïâ{:ŽüâŽÏ cõêÕ*•dúc*•bÕ*æ ´ù«TªU“ã£íØß#..N&“¡Š/“Éâ&?t w|~Peee:Ž’Äãý(ŠÔé”Û¶1×!ÌŸ¢(N·mr|„ýCXû{èõz…Bä»K’¤B¡Ðë'µsÀŸò­[·òü–jµzݺun·ûöíÛccc#ÿ/ÂX!KNV®[§üøcYt4s=ªü“““×­[÷ñÇGOޝ"U¯&½ê–¹‡C÷Ý÷CޝWëóžÈûÛ‚¿ýAñæz’$gÍšE„Óéôx?hN €øÁåZX@aÀ P°€Â€, 0`… ( XˆhÚ¹Ëåêèè¸téRgg§Ùl¦ûôi4šŒŒŒ+V¬]»V©T ãTxÈ`` ¥¥Åd2™L¦þþ~¯×K¯ojjš;wnØÿàw"šÒÕÕµ~ýúÇý5##£®®N§Óñ™RPxÈÿþýGŽ \…œ‡R2™,55Õh4ÆÆÆúVöôôTTT˜w<äOQ”Z`ú-x ¥‚ÐjµÅÅÅ A8Žêêꆆú¯­­­f³9))IЧ‚;ÿÌÌÌ]»v-^¼8==½¸¸¸³$…‹ˆ†R£££$IÆÄÄ0W:ŽçŸÞívÓ/;–••%DvÓã9ÿ 6ø †Rȉh(¥Ñhü¾UAPňùg±RÏ0‰k(¨££Ã×<%%%--MØ|‚%õü%!„G¤N;PÑ#Åbaž°–——“¤¨ö#õüg2ñî§¾¾¾¢¢¢úeyyynn®°)EêùÏp"Jµ··—••Ùl6‚ H’ܱcÇ·DHêù1FccãÎ;N'AEíÝ»7''G褂 õü!¨­­­©©¡—µZí¡C‡ŒF£°)EêùKŽ["* —ËU]]}æÌú¥Á`¨­­MII6+?`Ñ ¾¶¶¶ÒÒRßK•Jø@¡ÊÊÊ5kÖð›W<äþüù£GÒ˽½½÷ï?zêÔÂ… é‡#Ο?Ïž=!Ç>":bøæŠÒ&&&·¡îâÄCþ‹¥»»;pýµk×èß-v&ñ^®@@"J pÄ€, 0`… ( X@aÀ P°€Â€, 0`ñÿ”ÉÂíÛ(5£úû{ïnŸ„ýxØ8¶{Ÿ=ïs÷7„F£"4r$BÂ?W‚sPˆâÿ)’,ËôdMØÁXx ¡FCÒ–B’)qEa_ñk×.nÀSÇ“É$=)ÂD*íbòæ”Óáq5“QUNhµȲÐ\N‡ï¼M(°óÖL]hØGH¥YW¡À”à‹ÏˆÌ¸„|:­OH9ŸÇ€‚Híc¦+•4Wšç„…ÛÓ€;‹ƒ rSZZ¾‹Pyy…§¤Ý»¸wcja&PðJ%Qš+­r(€ÆíÅ@JªkZf¦õâW!$ì¡ zPÃjÏÃä€Â0ż™¤TPq%Ãf™ªW’Ñ5ë7<ŒC ¢æ Rqã#›Õê&ûT«Ò#Pž²Pt »Õ*lÕ†âñö^Éé)º¾ëÄãB ƒ˜„‹0¼!{õ'<{é¨l'ôÔ$}b¶Mˆf“^Vc¯ýD¡‘‡´Y“™ëG‘§„4ê4²Ý4 1ÉQÇ0­Z½9·\Jë” Ø Ä´ZuÓ²ãMÓF·ÞµŒWxv÷9mŽe¾°)Á4Zíö¶A£iNF³ÝÙ·j{”Ëf'ÐÄJ6 ®úÔ­„=žr¬ÚKȪfP³å²„¤rÙO #ÔnìƒÂ¬î«Z³c™L!¥,•—bºKhJím‹´ê5¦Aº¯ºœã5÷PÓ€7ž‚uÔ´ «Æ[žT§K¯Žš{¯ËŒpR< ŒÒ;È„M™=oöHé=VNJmÕÌ¡µñaGŽç=¬IÎß%ü X¹…¤*+DAþøÉƒãAÀè³WÒ_Ö¡Æi¯Ÿn†¾åñ5ì¤ÔóÝý6é%­¯}ø ÂÉ©+éÕ³! ÂX§‘³Qy=½TCÃ!¶|J›ù€ÂFØ#œ_0üà)]^þ”³—¹O‰w]\ Ü™A!Œg68á”._\>a„ Œ#‡ð…«Â4®ôûô‹¢b¶´Ë šÖ×ú} ~NÐÓ1y–=#Ø=çt”„+‡Uá¦wL‹nJƒ„ÜÒ!­Ïù³Åa3]9ÿgXm@­Šh4DFŒ»ÔÄ_ƒÔ Ï-çÈC%tEXtdate:create2017-06-06T01:31:24+01:00t“É%tEXtdate:modify2017-06-06T01:31:24+01:00Ð+uIEND®B`‚puzzles-20170606.272beef/icons/magnets-48d4.png0000644000175000017500000000113313115373734017631 0ustar simonsimon‰PNG  IHDR00¥,ä´gAMA† 1è–_PLTEÀÀÀ€€€ÿ€€ÿÿÿ€€€€€Ë*ºíbKGDaf¸}tIMEáeÑ^3fIDAT8Ë“Ánƒ0 @¢¡q‹AÜ!_0)LÓn]÷AS¤é~h»ošú¿³“>`ÅÛqll‰(•í¤›ÁAÅ@›-ðƒFl/U*=¾ïöà/y|°®b0З=`Èäh%´ä¡¯ˆ¸÷VÃh]㈴òãüXd,'ðºòÌì{—OkoàÄ©¶Â&r mhà!&„LM6Ò}Í 9{@VäŸ,iž¨Gúµ'‡ok Ò3 }ü+º®?ôá¬ïÈ¡HиP(A†äÞ¥¯9m"pâ©q€Œ={ܦ:Jb«ò€ xÉá>6H;”MCš­ÜP´ŒÄ \{d+@?§ÀUœé°t3Ð Ð+€K¨ø>ð™öäÈ`X¿'™~Ã_äPRÒ @¿'qŽCœ£ˆlܪU+  •Ëp¾¸Bÿü“” DÅ繺ܚ\ˆŸ{|EÈ%tEXtdate:create2017-06-06T01:31:24+01:00t“É%tEXtdate:modify2017-06-06T01:31:24+01:00Ð+uIEND®B`‚puzzles-20170606.272beef/icons/magnets-48d24.png0000644000175000017500000000543413115373734017723 0ustar simonsimon‰PNG  IHDR00Ø`nÐgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEáeÑ^3 IDATXÃÍY]lÔUÿ{ïÌ¿3†~¥¥¶€Ù5®CˆÄn"FÂ*QA@ bxÀ€&H$ kâ’M|؇}1º/ˆ ‰º†E¢VMÐÚ¤!ë6ˆ„„ÒNK™Î×ÿãÞ³ÿ™ç³T×d=™‡éí½÷üî9¿sî9wèìÙ³ø-‰ø(Uò—1`ž~f&‚ˆðí6àϬČh”Âái01¢ÀôJ˜9Nc„RÊÛÒZW2‘ˆùæïÐ!8|ÈD ‚É[ÄQà4ðO ¾†ˆÈuÝûï¿ûöíJ)ÏóFGGmÛžP[[[8öm©ò¶ ‡ùúu{÷n'¢ªv6 à4 ]cw)e___4}饗¾ÿþûD"!¥¬å8_×üùó¥@JñÄÆÇIJÄ )©£ƒ¤4CCS6+DÁ4± ”ÒZ I)mÛ–RNïµ2¬S;SÁŸþ,ª¯¯ûøc«»[ÜqŒÐZ³ÖÐÚhí;ž*ăOƒsó´Rrž*˜afx{y{¤«¸HWTJçžIˆ•/¯B‚U«DW<, Z‡¶mãL†/\ÐGŽ@ˆ€ã¶oßÞÒÒâ8ŽocL,ûüóÏûûû…ø…®3ËÕ«C{öðÄÃóÔŽÔÔä}ò Ž ˜"0¿øâ‹K—.M¥R¾zÏóâñx"‘èïïŸI´Ï3úË/ùÖ-xžÚ¸‘ˆ÷Ö[¾…ü ÁLû÷ﯴP-oþB—é'¼ãÇ)“k×R,æ¾÷ž¹t‰|˜’ìóî»ïVÙQ)ܯB1¤)¥H) %*tH)‹³¾/A|¡ƒÿ ßDœNç6m")Í•+y.û)ÊŸU˜^GÅt¢zæ°”¯¶M Ê•+½“'}ÂÂsñb€ݬ¦F¦&"­u,[½zu6›mjjÊe³žëbÆ€(_1#¤L.'þýØ„sÞZÌ—ΪÆýêZtç¢E‹Ù9[ålÛ1¦&×Q´¾>°+1ª.ö<Ô\Ï€ºímO{a×q=v©.BŽC©Tþ„Þ¥¦&¸®vÝR— V"tèòûÿúÈWÇ¥J Äùñ©{>œR¡Yß¿ëo¿ßÛ2»Ó>óû×½<4¥ò,ôéèLJ1rýúÐÞ½åõƒ-a e†Þ¹|À°ñØS¤$I_ ŒcKXe'Ì™\¨›BCÂ1Ž€8™8ù‡ú»þÒú÷ÉwÞæóçIJd³(²+ì}ðzäzè!LNú ˜™@¶± $H,mXÚnÔ¬C"!–°–7.$”Ÿ HI’–°h|€$©H…EØ1N{¤ýžø="gr8ò£ßP¹lYhǹlH ) àl–Š*ÀD‚a“Ó¹µ­k£2êǰ10ëZ×I’®q}s2˜@Y‡âOÌ"«³D”Ñ™yÖ¼ÕóV'½$‚QÞñÌ‚¹fµ¿\³†ŸU~J(uzc™Ù’Ö“?œJœÚÔ¾)""¶±7·oL öŽõÖɺ€1 ‹p÷î[î­§<=áL´X-O¶>ùÙðgW2WB"Äy¦•\5H¥8™D*55Rü¥˜Ô6³Ô¬ © o}Œ³É³§'NÇCqÃ%™šÁñPüÄè‰sVléØ" Ž]?vþ1KÍÊØ™Yjo·Þ|“m›ZZxdD®[W×ÕE–eïÜÉ?þˆÒº J‘`ØDeô|ê|C¨aqýâ3É3•tž:©3·ÎÜ7û>_Î\ŽÈˆaCA6õɉˆ®.¹bµµ!›¥¶6¹b…èê¢HE‰·: iÖ.»Ïu<×;Ö{xèðÖŽ­u¢ÎÖ6•®$2^f®5÷™ög^|í§ÜO›ïØœöÒ žšh_½joØ[µJ=Jóçë£Gs«VÙ6ðÕ«˜¦„åóŠ$¹iÁ¦s“çn \Í^íIôllßÅ5ëã,ˆ,X;íÑëG“^òTâÔMçæ†¶ šu~³‡8›Õ½½z`€GGiî\Õº·—³ÙJ‰€yÌLDŽqºšº.¦/ö÷ÍR³êUý`j°o¼ïÁæ54‘ß‘אַ¦®/n|1lGd$¦bÇGާ¼ÔÒ†¥¶¶+¯\xdÄ|÷Œ€%¥‚_Šƒ-aùÖûvüÛ¬ÎFUÔ1€ˆŒœKž»˜º(‘üÀeŸ^ÿÔcÏÏ@þÌã#ÇëU=€ˆ¨ œÁ€sð sð`~½ã ZU©|óÚÆn´¿°è…üP³Ž¨H1¢*<Üìgqá߉EÌc÷OsW­k[—Öéde¹Tæ#*½UÀ Ïx[;·nùÝS»y'À²¡Q,Lˆ{aÊæ {W‰’€,VY„† ,â€.ìY¸\™C¡P2—øvÀq!DeåE€Ì–^MÈDZ{w.ÒŒ_×nsýñ·Ç€ @€˜Yá8Ξ?ïééé©ÕJûëÿ¼LÖW3Åbjß><ö~~e¿\-˺|ùrOO²¨!%¤RRÙGȇ9•ÒÝ݉üB@% `6ÆTv»ÆSh¢|h-î¾Ûúè£Ð«¯Bë©ò²¨Î ªIU@ª~N Ìš›ÕúõzÎÈ¿î+HÕ®HÖ û2innnll,îô„étúÆðpÙLZ°€‡æÌáD¶Móø8£ …Be‡$¢k×®i­ËU6‰™wîܹk×®D"á·|Z놆†cÇŽmÛ¶ R¢¨uð ¸÷^žœä‰ Z¼¸î«¯hî\çå—Íûïç{&!ttttww{žèff¥Ô£>:888 ÿét:‘HŒù&5Ƹ®›L&«øëæMë"ƒÖ<>¹\žCÑZ'‰²æZJYýñ¤rhß¾}(¶0yž'Sº…óüóœJÉ•+­Ã‡u¿ý쳤{ž`hhèᇮTä?õ•ÑKUWõU°’œÉø/IÔÒB³g#›e*ß|ú·µ¯2åW‰eúnÆe¨Ñ®ûÞ€.ËBÖ|íšûúëæÒ%! %<EÑZkO!„ÖºÊ šï‘†††æææ±±±Z™Ú—À¾ @kô… ú•W ÿ6äWî0¦sá¯ûútáý¯X|¥RÊyóæ¹® Îr§µµõ7Þ8tèPðÞS~ Ü[è_EÁty«0çyãyrùr¹eKfxx×îÝʲΟ? …ªò©§žZ²dI6›­ÒJ3s$ Þ‹«ÊLnûü^™ k­”ŠF£ÓLÔZg2™â‘)Q&“I§ÓÓëòë¡Û'r!|§LLLL·QÙ¢J7ù•‹!¢ŸûØø›û5è¿…QŒÖ‡ëÉ%tEXtdate:create2017-06-06T01:31:24+01:00t“É%tEXtdate:modify2017-06-06T01:31:24+01:00Ð+uIEND®B`‚puzzles-20170606.272beef/icons/magnets-32d8.png0000644000175000017500000000241413115373734017631 0ustar simonsimon‰PNG  IHDR D¤ŠÆgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<˜PLTEÔÔÔÚÖÙÕÛÛÕÌÌËÐÑÝÛÝÓHHÍÖÌ¢ŒŒŒßàß¼¼¼«««±±±ÖââÓ©©ËÌ Õ›:::ÓŒŒÔÅÅÇÎ&&Î<<Ô¥¤ÏEEÍ--767DDDLLLÐ[[ÖööÒ››óóóããã***%%%§¤¤Ò„„Ó²²Ùœ¡Ýt}âu~Æv~}v~‚z‚ÃÃÄÊÑÊÂÎοÉÉÂÐдվ–Ѧ™Ñ§¦Ñ¦ªÒªÔ»»Ó““½Î½™ ‘ “ •‘Že²fßÏÖ­È­;¤;1¡1˜#›"B¦Bš A«GÞÂÉÑyy—Z®Z+Ÿ+/ /W­W8£7L¯QÐppÖìì–j³jNªNÎ55Îvv!š†¿ŠÚÎÙÎÈÚÒÅÙÎÜââ‚}»““aaa2/2969957]57Ù57Ó58Ò46“““2ÔBBÔ== øøø››ÓUUÐbb€€€SSSLSSqSSÏRRÏKKŽŽuuuÿÿÿ?æS·bKGD‡ûÙ ËtIMEáeÑ^3qIDAT8Ë]“‹_ÒPÇï6W6ÜÑÄ©1ê@é©@VÒdÎMET41³4*{勬¬þîîc ì·»»íÜïçœsÏî‹,ºèÛy°ô#³O~pI\O 7àùÞ+Wû¨® ý¢ ÑÖCa¡€0r]v5DWAÑA¨tB ††G¸1 ¨ñx<¡©¬ˆHŽ0:†þq]O¥üÿyðcÜt*Nɘp”ƒ'3$Iæ 2ÝX´¡ÒdB'¨DRˆ›·ˆnß¹KuoŠ™Îfsù|>7EŠ{æÁ 3©ÿl´€ ¨ôÌccnÎ,š%³„†iš¥'óOyH|À¿`Z‹¶á,†±Œ&ÛrVÊ„ë’ !ôg*ÎÚº½¶aãŪ¹Y5·Ê „϶%¨¸@­Vwкa7v¶ ÀXxd¢° ÀFÀz•Åç6v3 –;!ÖL«ZüÂJ›ëÛ°lö-Û.ZÆJUn÷I’Œo íÁÁöcݵ—åÈ+*ì0Â>ÖÁþþkªƒúષï0ßPUõ£úés£Ñh6›‘œ÷WZhuÑûúqë÷5§É-¡ P Ä%!<ÊižÃÀ1>&}Ø¿Zí…GYù„š\‡§º~z†ÁmÀŽÆšYy™ÆûåV}è¨ÆSh¶ÙÉaå('c“êy 5šû­“ƒF<øƒ—v@îÉž¸Çó w!sžøŽõãgûâ¢Ýóë"™©ÿ&¦ÄÚœº§+Ô] |îjÎ×ÕäL{íÿò¡ùY„§l%tEXtdate:create2017-06-06T01:31:24+01:00t“É%tEXtdate:modify2017-06-06T01:31:24+01:00Ð+uIEND®B`‚puzzles-20170606.272beef/icons/magnets-32d4.png0000644000175000017500000000120013115373734017615 0ustar simonsimon‰PNG  IHDR TgÇgAMA† 1è–_$PLTEÀÀÀÿÿÿÿ€€€€€€€€€ÿ€€€øg[ØbKGDÿ-ÞtIMEáeÑ^3…IDAT(Ï5RMK1}ÙQ«·lUêqÍš{º]]zêGÁ‹ÆêY¬P½‰³‹7QzÜú„ÞõàÏs²­C`ÈË›™—Ç@„ÂJ„€”@'qš¦‡CIð\he "À2ZïÔ€çlÚíDÍ`‚AÉÍ>Ä:¨K"öÈ À:[k9ràÀ©©©r¹¬”‘ú¿ÌìºnWWßç7’¯¾"¥ÀLmmð<™Mo  ÐZ[kÏž=;88X(ˆ¨ojÌœÒHDj™hcpÞ~Ûûì³4R*%m…lz¨”RJQƒ©šÕ(@$€zâ ½i­[GƘ}ûìü¼Œƒ" ô÷÷·µµ%IÀó¼K—.Åq¼¸¾Î˜©×Þ½ÛûðCžšB’x_|}ü1†† 5¬‘ãÇ÷öö–ËemmmÕjõçUfì¹s•®.÷wÔŽAO-•\ÖB„€Ã‡û¾Ÿ’kŒ¹uëÖÀÀ3ÿ\R*Éýûù„oÝ ­gë§[q¹:/ ?aJ i…4›æ½{ÇÆ?Ÿû¼¿½¿ÓïL$!b‰ŸÊ>µ-»íÔô©|˜ßÓ±G“^êPÇðÍ›ÁþýÉùó´aCðâ‹áÑ£ ÖƒŠ@ .'å5îšo‹ßÞ«ÞÈH~$k²,lÅ&’hÒ†Ì×ù¯}íçJ¹ï+wÚLëbR!" ±" Ä££ÁØ$a¥’†¾1!‡›üMÏ®~v¢4á(g•YÀн]¾Ý¬[IIœ*Mf”O@³ÊÜ[œaNö­ý5‰¬”ˆpíš\»F´N›?S&ád•·jx×ðƒà"Åà×0ƒÂÆFKÅSD+§#ÓQ˜œøi K"P J!Iˆ€_›0J© Žÿíø±žç¥å‘f¿lþi†EÀ ¥ˆÈ G¯ÿ±Ôõ‹¿2ÇéàcN‡¦,pèÀø¾ýúõáááÆéˆšL* ‚Õ¦5[kþ>Œ÷ÞÓ"0 š¬‰lCK«TÁ¬P"‚ÖKŠh jkËŒ9/½k €µu®cæå_ªhõ$£6Í[[[ׯ_Ÿ$ i­KÅâÌì¬Ð3êÉ'iô·Sg§Ú¸‘gf`-ˆ˜Ù÷ý-[¶Ô£ ÃðÎ;hHcŸ'¢öööÓ}ô»×^SZ§Ü;uJõôÈô´rŽ«îÜ)‹‹Úq¬H__ß… ŠÅ"€l6;::ºwïÞ†½¨¶e\¾|yÿþýQpg~v§òDo¾IîûïÛO?µ_~É““Ô×ÇI¢€ñññƒÆq À³°°ÐHµAm˜››»{÷îr"‰`Œªm•öúušš‚ãðíÛÉÕ«À±Öuœ‡^¼xqùF³|'ÃÌžç¨éã’‰’dI,Óå°X žyF‚€”fñ}Çó× â¸±S>šššÒÊårJ©3gÎŒ¹®»¬ã@l†€0-;„!Z“Öêå—ýíÛÏŸ={ed¤îHDQuww:t(M-år9---ƘÆ>H1 Ü¸`+ˆ€H*„a¦¥ÅuœŽÌ\.—ÓC“‹Å/Õ1ôãVŠ%0¥J ÿë˜zúü_2§!Üåñ%tEXtdate:create2017-06-06T01:31:24+01:00t“É%tEXtdate:modify2017-06-06T01:31:24+01:00Ð+uIEND®B`‚puzzles-20170606.272beef/icons/magnets-16d8.png0000644000175000017500000000231513115373734017633 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<¯PLTEÕ××ÕÒÒÕÊÊÔÊÊÕÍÍÏËËÌÍÍÎÎÎÍÍÍÔÔÔ×××ÓÓÓÕÕÕÔÄÄÍ##ÍÊÙ^ EEEÈÈȬ¬¬¯¯¯®®®³³³Ô¶¶ÌÐhhÎ}}ÛK855&&&,,,¼¼¼¦¦¦©©©¨¨¨Ó±±ÌÑ«ªÏ½¼Ü'&E):9ŽŒvxv999º¹¹©§§«©©Ô»¼ÒÕ#%Ò13âQ+*+ÁÄĦ®®©³³¨±±®±±ÓÒÒÖÕÖ·¥’¬u¯x±˜‘•~z—}ƒš‚z”y¢²¤×ÌÎÇ£¢ÉÈ¡¡Ë¾¾½Î½*§2¥$¥$ ¦+¢-§-"£"  K¼YÒmnÍÏ--ÑUUÖää¸Ì¸ ™<¢9B¤?˜–™C¥B1›.6²FÐ^^Î((ÓÃÃÏRRÏJJÖãã·Ë·—5Ÿ5;¡;–”—A£>0™)4°BÎ_^Ë((ÑÃÃÍRRÍKKÂÏÂF°F4¬44«4>®=&ª//®>&­5#©/RÅlÙde×Ù..Ø×KKÕääÕÓՇއs~sy‚xnt¥~uÆuÂyo½sgׯªˆgh8I :vMMßãã···€ÝÎ45ÍÞ--ceeLLLããㆆ…Œ"22wÝ44ÑÊÉΘ—ßCC^YYFEE˜••ebbRPPâââ´´´***1..{Û΃ƒÌMMÝ..aaa 655MMM>>> '$$!,,’22Ø((Ì88Ë$$Úaa””'''|||àààØØØÞÞÞÝÝÝÜÜÜ×ÛÛÕÝÝÕÙÙÕÛÛÛÜÜÿÿÿu"=bKGDä/b;)tIMEáeÑ^3IDATÓïþ   !"#$%&'() *+,-./01234565 789:;<=>=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`a`bcdefghijklmnopqrstuvwxyz{|}~€‚sƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤=¥=¦§¨©ª«=¬=­®$¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊË®ÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÝÞßàáâàãÝÝÝÞ ?ndz:¸%tEXtdate:create2017-06-06T01:31:24+01:00t“É%tEXtdate:modify2017-06-06T01:31:24+01:00Ð+uIEND®B`‚puzzles-20170606.272beef/icons/magnets-16d4.png0000644000175000017500000000060513115373734017627 0ustar simonsimon‰PNG  IHDRíÝâRgAMA† 1è–_$PLTEÀÀÀÿÿÿÿ€€€€€€€€€€€ÿ€é4WbKGDÿ-ÞtIMEáeÑ^3ŠIDAT×c`d`````2R Kg`g``bPKKa3”Ê€Ò LÊii )örÉÀÀÚÙ®¤ÔÈÀº|嬨rvE®ðÒUE@ûÔ¥ÓË” Ä9Ê œ ØÒ’•4ÊÒ€ öd¦rv ##Ù hPD,{º’:Á È(ÀÀ(ÈŸÅ7»öfM%tEXtdate:create2017-06-06T01:31:24+01:00t“É%tEXtdate:modify2017-06-06T01:31:24+01:00Ð+uIEND®B`‚puzzles-20170606.272beef/icons/magnets-16d24.png0000644000175000017500000000241713115373734017714 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<ñPLTEÕ××ÕÒÒÕÊÊÔÊÊÕÍÍÏËËÌÍÍÎÎÎÍÍÍÔÔÔ×××ÓÓÓÓÓÓÓÓÓÓÓÓÕÕÕÔÄÄÍ##ÍÊÙ^ EEEÈÈȬ¬¬¯¯¯®®®³³³Ô¶¶ÌÐhhÎ}}ÛK855&&&,,,¼¼¼¦¦¦©©©¨¨¨®®®ÓÓÓÓ±±ÌÑ«ªÏ½¼Ü'&E):9ŽŒvxv999º¹¹©§§«©©©§§¯¯¯ÓÓÓÔ»¼ÒÕ#%Ò13âQ+*+ÁÄĦ®®©³³¨±±®±±ÓÒÒÖÕÖ·¥’¬u¯x±˜‘•~z—}ƒš‚z”y¢²¤×ÌÎÇ£¢ÉÈ¡¡Ë¾¾Õ×׽ν*§2¥$¥$ ¦+¢-§-"£"  K¼YÒmnÍÏ--ÍÑUUÖää¸Ì¸ ™<¢9B¤?˜–™C¥B1›.6²FÐ^^Î((ÓÃÃÏRRÏJJÖãã·Ë·—5Ÿ5;¡;–”—A£>0™)4°BÎ_^Ë((ÑÃÃÍRRÍKKÖããÂÏÂF°F4¬44«4>®=&ª//®>&­5#©/RÅlÙde×Ù..Ø×KKÕääÕÓՇއs~sy‚xnt¥~uÆuÂyo½sgׯªˆgh8I :vMMßãã···€ÝÎ45ÍÞ--ceeLLLãã㯯¯&&&††…Œ"22wÝ44ÑÊÉΘ—ßCC^YYFEE˜••ebbRPPâââ´´´***1..{Û΃ƒÌMMÝ..aaa 655MMMãããÈÈÈ>>> '$$!,,’22Ø((Ì88Ë$$Úaa””'''|||àààØØØÞÞÞÝÝÝÝÝÝÜÜÜ×ÛÛÕÝÝÕÙÙÕÛÛÕÝÝÛÜÜÝÝÝÝÝÝÝÝÝÜÜÜÕÕÕÿÿÿÐßíGbKGDúÕmJtIMEáeÑ^3IDATÓïþ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFEGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯E°E±²³´µ¶E·E¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øù¨@zýÛtŒ@%tEXtdate:create2017-06-06T01:31:24+01:00t“É%tEXtdate:modify2017-06-06T01:31:24+01:00Ð+uIEND®B`‚puzzles-20170606.272beef/icons/loopy-web.png0000644000175000017500000003115413115373720017430 0ustar simonsimon‰PNG  IHDR––³cæµgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEá  ŠN1pIDATxÚí]yxTU²¯s÷îtBBöE D4‘*THØQ€,ŠŠŒò„A‡ÕEŸв(E$!¢,’@è„N§»oßå¼?Š4! }:N¤gõÍ7_ÌIsêž­êW¿"ç΃òŸ,ÜõîÀ ù³RÑ„”RJiÍþÖuiûÿGium… ¿Áqœ$IªªRJ !ýuI’ÀëõÔEQ¯×h[J©¢(‚ ¸\.Ó4ÙÛâH­V«®ë§#•$ÉãñèºRBˆÅb·ÛÐ SJAÀYª0Râ; )¥¢(z<ž¼¼¼† rgš&»Y–óòò(¥qqqªª²wŽã8JéÙ³gcccëׯoF@zúôé’’’–-[Z,F+¢ýÜn÷‰'BCC›6mÊ®ŽRÊóü¹sçòòòš5kÁØa4˜a'Nœ „ÜtÓM<Ï3Z•ÚíöÓ§OÇÆÆ*Š¢iš¯¡P~TgìØ±[·n9räܹs?1Ó4CBBöîÝ;lØ0MÓÞÿý®]»–––rœÿƒ¿èéÓ§/[¶,%%å¾ûîc\ˆ¸Ÿp·~ýúß~û-===66–±ÃøEçåå­Zµê¦›n0`~¬Œm%IÚ¹sçÞ½{ póÍ7³w¿›÷Þ{çùáÃ‡Ë²ÌøÍ™¦)Ëò‘#G6nÜØ£G·ÞzK_ÛË«w¤“'O¶oßÂÃÿûî;ÔáW®ë1113fÌX¶l >|Á‚ùùù‚ øm‹Ò¥K—‚‚BH‰ÿWrðàÁæÍ›ûöÿ˳LQUµAƒ£Fú裞~úéúõë3ir÷è£fddèº>tèPžç#""XV¡iš6›møðáóçÏïÚµkzzºËå"„øÕë[…|ðAffæ³Ï>Û°aÃòÛ˵ۊ¢˜““óÆo$$$<þøãŒ«o²,oÙ²eëÖ­O<ñDRR’ªªŒû Çq.—ëÍ7ßaüøñŠ¢0®BÃ0l6Û¶mÛV¯^Ý·oß&Mš”?¿¯: yžç8®   ..Îëõ²¯ \ÄÅÅÅ”ÒÈÈH·ÛÍxžéºµuëÖLš4iÞ¼y%%%‚ °›ðÂ… ‡£I“&x¦²K¦iž9s&,,,**ŠÝ„¨Ôápäçç7nÜX’$v¥¨"77—R¿~}ßOXfÉf³}üñÇ=öØŒ3¦M›–››+Š"þ×+{ŽJ×u¼‘2Ï×\Íì÷Ü<=x<·Û}áÂöû,Šbqq±aõ™çyQ Ã(,, t'„Ȳìt:k —ìÅ‹Ùo‹º®€Óé¯×[áUq²pRª<–LÓôý㸠vò5©Ü¶|CBHåmBçù€Lˆ»Ïó¾dpÕ€ šÐ4M<>þŒRvâïó¢( !D×u¯×˾Íþ·Ê¿wøL6Ó4-Ëúõë×®]»Ù³g{<|Ö\»!®uëÖõìÙ399yРA;wî”eùÆÍóß(L—F‹ÅrìØ±‡~8;;;>>~þüù/½ôúb®-¸-¯]»–Ršœœ¼}ûöÁƒ:t/c×{ìÿ%ÂdÂÏ?ÿÜétÎ;wÆ íÚµûè£rrrDQô»žLÓ\ºtéºuëV¯^=~üx¯×›••uc!þÅ¿ ÑksöìY¨S§Žªª5B—ËE€I)=sæLFFFXXXJJŠÛífyKÝašGB^‡ ÜUÊ÷“k :‡ŠŠŠú÷ïôèÑwÞy§E‹=3žþù_~ùE„É“'·nÝzÆ 6›-ÐGñ ©Nü¯B|>7lØpýúõï¿ÿ~nnî3Ï<Ó¯_?Æ0›iš]ºtiذ¡®ëªªFEE…‡‡Û»!צ§=Þh5j´`ÁŒ¯–””°8£€R:uêTt{¢;Ãáp8Î{é¿KpeišVPPWßnXýhoŸ3ýzü¿G*š=ÝUntèüÆßÒu½JpÏóÕ™ùϼ Ã@½6¤”êºÎî­|øm·ÝƸEàJòz½IIIç§Ÿ~ e“I’tìØ±÷Þ{¯GÝ»wgß—wÓ³gϽ{÷îÚµ+11‘6'Šb^^Þ²eËâããyä‘€à–’$íØ±ã믿1bD@6AJJJ’’’Eùé§Ÿ$IbÇÎDFF¾ûî»ãÇŸ8qâœ9s }Ë÷*à…ªª]»v½ûî»ñ|b‡”麎Ñ`ŽãBCCÙƒŠm.\X¥¢(bÌ+,, ߌ€a 4˜3g~|m†aôèÑ£[·n¸åô¾ å8Žçyõ2Ö0 J©Õj‹ÅR!R{ÕFJ)--½téì=ø oGåy> ÿ‹Ûí.** «½òm5Uz(¥¸€på÷¥òÿ®Ü–RªiZQQ‘¢(‹¥:¥Õé-))ÁÛýƒÃ½ w{ìv »7ŽçùZØŽãAðA<’ËÈÔrÿÏ(×P*Š"Bµ4M«¼\|ó[YÇq¢(âëñx* ú)DQ)RåÆ^ƒYªñäTi ±3×E!ÅÅÅ………†aDGGGGG³_=LÓÌÉÉq8¢(6iÒD’$ÆC ·¢üü|¯×ѰaC¼Í­©£Ë4MEQŽ?Þ­[·Î;wéÒåž{îùüóÏY^œ3X²dI‡î¾ûî»îºkÈ!yyy~1xã(..4hP§Nî¾ûîŽ;¾ùæ›ø\¹ÞSR­© ÷±Þ½{ïÙ³gùòåùùù ,¸xñ" Úáϯ¼òÊ?ü0pàÀŒŒŒµkײvð…Ó¾}ûÍ›7öÙg‹eáÂ…Çf°On¤ˆ]¿õÖ[;tèÀó|ãÆcbbðFÀÒÖív7¡å÷ÝwߺuëXîøXŒŽŽž;w."Œ[µjuøðá€îœ×a®®wªœÐÒÒRÇóâ‹/æåå=ýôÓuëÖeIœ „”””p·ÿþ_|±I“&>ú(£ÏÁ4M‡ÃÁqÜÂ… ÷íÛ7zôèøøø`ûi· ÌÕ`ƨQ£Ö¬Y³lÙ²‘#G2>ÞMÓ ÿç?ÿ™ššZ¿~ý-[¶4jÔˆå:ãK}ùå—g̘ñüóÏÏž=;È‘>AjB¼Y¥§§oܸñ…^¸í¶ÛöîÝËâôAàë×_ýðÃK’4cÆŒÂÂÂÌÌL–ë >p'Ož¼hÑ¢Gy¤_¿~ßÿ}II îùzIšÍpäÈ‘o¾ù†²pá»îºkàÀ………è—ºF[ô­[·Îét 4èÞ{ï]¸p¡ÕjõÛP–åóçÏúé§°nݺ”””îÝ»9rÄoÛë(AzáyÞårÝvÛmèyŒðùõ‡ñ<_ZZ:uêÔ1cÆøœæuëÖõ» £³-::úË/¿ÄÈ®øfÍš¹\® = ƒÔ„Pö0h×®”¹3(¥Œ‘Ã07nÜ¢E ŸiО˜˜Xþ7¥Eø‹%xMˆÑ5LªóI…¥P9Ñe_Þ«ÂÖ¿YA){Ûë"Mˆ“‚Cö1—ÿGÍ%è/öó+ÿ †aøöØÊ•ßy÷õ#p×øå*GD¡Ô¤4€Y"„£Ô„QÏøú~°3H:ãt:m6‹¤¼`’&!D’$vŠ¢(‡Ãb±X­Vv¥˜¾Œa3EQê-¦K:NI’"""ºªB\.Wii©¢„z½¥”ň”bn°AÈåy(ÔŒyÅ IÒµ‚M0}úôµk׎=ºC‡ŒoaxÂãñ¸\®cÇŽ%&&2¾…1Iÿí·ß~å•WúôéÓ»woöGž[¹¹¹pøðá¦M›2îx¦iZ­Ö¯¿þÁéééém9²,oÚôå_lžô'Ÿ|ræÌ™Œ³„Wå”””ââb¨Ž´¼^oLLLçοûî»ûî»/99™a‡P¾ÿýßÿ---íÞ½;ÏóaaaŒ«Ðb±ôèÑcõêÕ·Þzë<(sÔ—_~ùûï¿÷îÝ[QŒ‰ûm…Î^½zíß¿?..nàÀ/ä={¶ÿðÑ´´îõê%ª*cbH÷À¥6¼ÏóÜý÷ßÐ,…‡‡wïÞý“O>éܹ3bŸ|ÿõ ïŒ×ë­_¿~×®]¿ûî»ôôôÇ{Ìív³#e)¥C† ¡”¶iÓÆív3¥†aX­Ö´´´Õ«W?ðÀóçÏw¹\>:Ž1¢°°ðÖ[oeï-º`ÒÒÒ¦M›Öºuë×_?A©&ŠÖÌL8~üÈí· é#ËnBXôRJùÔTõË/?済¤¤{Ýn·( l+X ëÕ«×'Ÿ|Òµk׸¸¸sçÎUKZ‚æÅ¬‰ .°;é1ž@)Åeg ‚qUUu¹\yyy1^Ô­[7<<¼<äŽE#ªÃ0©Îq±Š¢¶n N]¿dšvBü·ÅëŒÛ !¦ª"p†q `š&v¸2^EìŒ/º/”‰oØ>tL•9Çás*Ы,”ƒ#ˆ¢ˆ ö†øþ ¯ŒŽñrU¢ª©_á8Ñå"n7Øl!"!"K$ Ç™ªZÇf`À‹*~OÂÂÂÐ?éñxœNge;Õ qó'¥J"¼7â“ý•Ïõ+X5™ÍËÿ«Q‡kÒðV÷ÿé!HþâÅ‹K—.ÍÎΖeùŽ;îèÝ»7R'¡ÛÙÙÙ›6m:sæLݺu{õê…o¤ ìíŸV¾ÉS§N}üñÇÙÙÙ_ýõSO=µxñâ E”à…sÙ²eo½õÖï¿ÿþÎ;臘¦îÚµ+ Lÿ aÂ1x½ÞÖ­[óÍ7?þøãêÕ«à×_ Î%e 'žxbÏž=û÷ïŸ={¶a;vì¨Á!ý!Lg8&¾;vlÚ´iÇŽ‹ŽŽž0a;óà_,èoÛ¶­®ën·;''Ú·o´ßÜŸÖ40ŽãŠ‹‹ÿõ¯ØíöþóŸÁi?_‡½^¯¢(sæÌY¼xñèÑ£ÓÒÒ‚9æ÷g„iH‚ \ºt©S§N™™™Û·oEqåÊ•ÁŒÂûÛK/½ôÊ+¯Ìœ9sÙ²e5 ;üOÿ)²¾¾öÚk_}õU»ví²²²Ünw‡|‰×{Å0Œ:uê¼üòËK–,‰‰‰ùã?عsçáÇÿW.D&«ªª Û¶mÛ¾}{HHÈóÏ?ÿÄOííÝL‚ ´mÛVÅÝ»w»\®Æ9´ÆÂdB—ËuÏ=÷ôìÙgÇ0 ·Û´XŽãJKK§L™2}út(ËrVUõ¿•)…Õ/¬ª*fÄû¦)8íçëpiiiùïJ'·T ¼¨ÝgášñÁ þJÁ]¡JoßµVÀ‹¨ ƒ)LXe[€š`SªÃµT» ™Â®ƒçù:uê s™xQcÖßÀBBB°„ûÝ óÖÿ„RPˆŒž§¦©SªÂø§¥†ÿ0 a‡§ÕÚâ*Ò(ûxA°ÙlP†ˆñ;#˜…´yófÃ0Ð}ÊòjD{#NÊâ AÍdY>xðàéÓ§ûõëËøxGàÅùóç¡lƒ D)‘e.;›Û¿RSŸ¸0Uå8ŽðÛœð„¸ví¢ë\Y…ÈÇpâÄ ÈÎÎÎÎÎføÓUÈ÷ß_³†'Ož,((gä±X,gΜÁ(ÿáÇk ‘çy§ÓyæÌäêð{Øcaƒ‚‚‚S§N@fæq§ó8ã~¬ëÇ_þKÙÙ{ \.` Sš™™'Nüæp8"##}§Õà…Çãiܸñüùó×®];vìØ@lgñâź®Oœ83÷4EQ~üñÇ%K–ôïß?11Q×õððp¥Ð·oß·ÞzëСCk×®mÛ¶-;l þ,X°à–[néÕ«!¤rиºwèÐaðà!kÖ¬ùÛß^iÞ¼_qñ%–'¥Tù =EQ~ê©MŠb‰‹cÜ« E©3þÇ‹Ï<8½qã–Ï%Tà*à…¦iˆšÁÂ~R,_¾G3YÓ¦M»wï®(J@Uý¼^oll,Ú»mÛ¶7Ýt»ó…RÚ¼yóöíÛc>v˜å‚£išÅb‰‰‰€FZIRkžg-oC)©_Ÿþã"!’Í–¨ë:#6JKKÇ—вeËnݺ}ñÅÁLwAkBE1??_Q”×_}ôèÑûöí›6mV7¬½eÁó¼Ãá())™6mÚôéÓ³³³'MštêÔ©`¶bæâå(99yíÚµ6›Ín·þùçyyyªªZ­ÖZ*€ö˜˜˜5kÖ(Š"ŠâÎ;wïÞít:ƒ9P¼«Åívkš¶bÅŠ?þøãñÇ/O¥ZKBÁ˜Ì§Ÿ~š‘‘ñÐCÝ|óÍÁ+ÒnAÙÉ2kÖ¬Y³f?þoûVú­mÕ~øá°aÃzôè±hÑ¢×™š^G5M›2eÊ‚ &L˜0iÒ¤ÂÂÂÚ®Q‚ßÍ’%Kž|òÉ´´´7ß|Óív3J‚Ö„èÅ>pàÀÊ•+ !«V­jܸqJJ ’–ÔÒ²@oßÙ³gçÍ›»víJHHˆÿñÇkïþó¼×ÇÓªU«¥K—â 3ÑC_KJÑÅñÚk¯¹ÝnTÊq\³fÍ+Ÿ_ RâlÆÆÆ¦§§C™Æ4ÍK—.ÕÞ^Š*BBB{ì1R&”R‡ÃÁÿº^¤&„2+^ÕÝw HLÓ¼páBùŸÔ \÷_)Uü rá“2‚l °W°isH…s®ÂöUþ}]>å±fL)¨ÔÇRÒ ”ßZ)B)¥„ŽNbÃÓ¤ 7Mˆ9y5 6!~‚Éë ,Ødµ Çšy¤ëºÕjÅGw )/ˆ½ˆŒŒDnö¶š¦É²Œ´ü8^æ¶”R1"‚QÄf+€ÕjU"#!$DàÊ3¥\…‘$éÝwßÅïwÜhÈwÑ¢×½^}öìçëÕ³jc0ÓT嫯/\¸´OŸÞ½{÷AöÜ ¥ôüùóH‘““Ó¼ysÆ"X0àÈ‘#Ó¦M»õÖ[Gމ»‹RÓ4ív;2¥` c…"J©$‰çÏç¾ð‚W¹¹sDFZ˜gÉP”‹›7ŸX´† ÉKOwÆW‘–œ>}ºC‡5¾= è: 3f@a!¤^½àüyVöJJ]×»téòé§Ÿ1’–DDD 4èÛo¿­i Çq¦i6lØp×®]ìU5¢££_|ñÅ•+WcÇê“&±Î/zõ‚ @ø~hÚ´i¤%H«ÐªU«¬¬¬šÁŸ<¨ëfBB{AP¬VV`( mÛæž?ŸU¿~ƒ6mâu=°²ü±¸¸ø–[n‘$ k¾ùm‚Õ‰Û¶mûí·ßÖ©S'11‘]âµ²²²rsso¾ùf›ÍÆÈ²‚Eâã》Oáy‰}–¬V!!á={~mÙò¦ /«+4M‹‹‹›9sæœ9sÞÿýaÆ¡{—„¨iÆúõÍLÓ–v–R+€Á¯£ÔE[^Þº-[¾óÎç:uz]UKñ»÷A&wïÞ}æÌ™^½z±G0ð‰yòäÉäää{ï½7##ákŒJAøñÇ8ðàƒFDD°¿7ðÐmÕª•Å¢dfžÒ4V¢i²lËÉYýÕWÃSR^lÓf†Û}žãª"-²+Ÿ®ëN§3 ÒŽ»t!Dׄ8Ë”^¯¦õë’dæåyLóB@µMÛµk—””„@Vöåù0JKK z®4kÖ ólØ‹öøTcÇ £Ä45&êJ U…ˆ½$Óë…òk·Ú~céÏòóáÞ«¹5p%%”R°Zˆ@Ëõ€úÊÔTøØ !'±Û!<ÂÃyÓäË÷ ¡P=ñò¯3âϪ,ýÙªª¾‚?WÏõ•'Ç5îV”RŽp5Çñºv;DF‚¢\ui*ývÕä&XO ý“ˆ5ªª NÕ\8’$Y­VA4Ms:•»ˆ(©<^BˆÍfS<Oiii•µwp·¯Ù NZ‚ßb•Jyž÷Í~[UZ±F_!„ î¦Â`Ílr¹\»ví:{ö¬  íÚµcôUr—““sèÐ!»Ý’’R§NƘŸ®ëÈÊÊ2M³M›6·ß~ûŸÉ…¨mÁYÚ·oß©S§dYNNNÆêµíÙñoB|>|øé§ŸFÆJÃ0æÏŸ?jÔ(–@(!dâĉûöí³X,—.]JNNþàƒ¢¢¢®}t†ºwïÞG}˰«ª:eÊ”^x!8£¯øPùàƒ¦N^\\,ËòŠ+ÒÒÒ 3ÔXüÿiôU6iÒdóæÍN§síÚµ‘‘¡ë:‹ýt]vìØW_}ºfÍšüüüàä»AÐÆÍ7ßüñÇŸ8qbÙ²e.—kÍš5A"-e¨¦iõë×ÏËË[±bÅž={ÂÂÂFŒåW¯mE<6¨ªjhh(Qlܸ±ßa‚@‹-âããyž¯W¯žiš±±±¡¡¡Á·CRÝ»îº ]?X6»iÓ¦‚ Ôv¥F$9åyþèÑ£ãÇG¼6{ [JiII‰Íf{õÕW׬Y3zô蔔ƟŸŸ?räHMÓ¦M›RÛûR¯Çaaaûöí3fL‹-žzê©Ú‹nú„i.1¡gÏžº®ïÝ»×ãñÌ™3Çívû}5¢ãF’¤éÓ§Ïœ9ó¥—^Z²d £íñ >}útŸ>}NŸ>‘‘ѳgÏà<} ݹsgïÞ½[´h‘‘‘ѲeË¿ VìâA½jÕª_~ù¥cÇŽ‡òz½ 6D=¿Í%Iš,¦Z¹Ú;”PJy^ Œ41šÍ÷ÝרàB­Vœ¥j°3¾Ȳ•çC9N@¢ ² YYÄ0àöÛëz½2Ç±Ä R]-ªjËΆ֭åÈH«ªÆ”¿L)È2—““YPŸ”t‡®[˜Í`rœ¬(vA–C9Nä8Æ"T–ù¢¢3¿þš}ûí·7hÐ š d¹´à¥ œiÊÇCB‚T§§ª•°3xç<þ|FÆNØ´éÝ.]ްÑ ávïö<ñ„C×õ•+ŸëÚ5¤´Ôd9+)¥²¬ÌœùÓ{ïA§NÛV¬‹Ee™ÓEìlnøð§OŸš5kpzz¬Ó©³(5MJ©ôÙg9™™¹oßÄ&ML§ü¶¥xž^¸ »{ß¾¥¦öŠOðzY/˜®åõz].WFFF×®]™i᥎3¶¬Y÷Ý·sÕª‘²,†Yx!IRNNÎwßí€íÛ3&NÌ$`9etDvì,·}û[))PTÄŠ q8`óf€}û~þõן[µ·Û Ô0 "„Ó§6múhÐ (.–µa!°u+À¹sç~øaQl,S[JÁb_…}û€ؼyËæÍ[XŒW^´?##ãî»ïv8Ì.mÞ¼ vîÜ[Pß¼ysø\Úï i‰ªz5j6nÜ€?\ÿÜsO4iÒËãqÂ1,*Ëܰaî~xFÓ´ôô(JXLŒÁ‚ 1MÓb ùÛßv¼òÊÒHN~Ài³ùWJ)píÕK\µjzVÖñ±c_ o%*Ï3±øX,ò³Ïþ:qâÔÄÄø=fY,š$ù_K”!frrHzúŠÏ>Û6nÜøääû<&‡Ÿ/…xñâÅ„¡C‡rÉŒó‹™81}Á‚ׇ بQ³òäì ¥š(6ðxþžŸ?³Aƒµ‚ð¨a8#Ë”‚(òyyM(uÇÅå–¡BXjšssûEEM ™§ë—ÏBMÓccÃzôè¶cÇŽ#G²7nív3ΦIHÇeçä´±ÙîŒüÆëu0Ÿúš Ôq¹þ§ `~“&Ÿ‡†ö5Í–R#—§›üü|Žãl6{ÑJuž¯gëÎ{<:z†Å2MÓr}³T¡àáñxÀí.µZ¦ig¬Fª*†I)õxŠðŠÈxAu ªYv›¦ù:£{½>X=žK”^0M7[Ù“ãÜÏ%JAÓtMsRj7MVêºäñx’’R¯·Ä4/2è”çy„’”èJPJ=,‹ä•å«. BÅ_.s‚"Âû¾¯ ÷àÊOCB.SÉqÀÊãA‚)ø7¯R eP%¼¸W™QBø²#â†gŒ€eìI„þJ+¡b"ÀŽRàyNxÓØW¡Ï?Uù)â{àVI½RÞ·Uam°~>¢(Z­V„À†ñ×T(&„„…… ‚àûr+xõþM¨XIŒÀ0 MÓþ‚23Èêˆ) HºÌþpd:‡eYÎÎÎ6lXRRRÇŽgÏž]Û̸æœNç3Ï<Ó¶mÛÛn»mĈ™™™2ºjS©ªªsçÎíØ±cRRÒðáÃúé§Ú¦»À°Ì·ß~Û½{÷víÚ 2¤¤¤¤Bµ×kkÁÆýû÷gff¦¦¦Š¢¸`Á‚ Ôvñ¤)t:ݺukӦ͆ &Mš„ñÂÚÓ‹\•›6mJLLLNNþì³Ïžx≼¼¼¿`°üñ\¼xñçŸh‡cŠT”””ôíÛwРA5Ú¿JJÊÑ£Gk5b€QªèèèåË—GEEeggïܹSÓ;[[{â_¢¢¢6n܇¼•çÎkРAíe‰â“ÿ‘G}út<“jµf&PJ-ZTTTôóÏ?ïÙ³§  yGkI5®Â-[¶Œ5*)) !¯A Ľ…††bþiTT”¢(~ã(þ{fFXXاŸ~º|ùrQ?ûì³øøøaÆAmK¸u8pàŽ;îHJJJLLÌÊÊêÓ§Oƒ jïŠwïÜÜÜ &”––æææöêÕ+))éèÑ£~¯r°¡¡¡Ÿ|òIÛ¶m;vþüùÛn»í7Þ@¶q¿ÍYq¤7ÝtÓ¨Q£ð¢¯ëz³fÍ ¦ÁRñq°=÷Üs§N!99955BkõÓQå±Ç+--ÅŠ8˜&QÛàUÓ4ÃÃÃccc !çΫW¯£RÖ‚?;wîÑ£¾œÀb·ÛkoH¾é”)S0¥Ýívã×S«7RMÓÂÃÃ_}õÕòIXv»1g½f‚3üàƒ4oÝ¢(:NÆ”õ,,--u8åRÛü!xûHK|ÉDµ­Ô4ÍüüüòL@tÓ5Ö‹6CEèMeüh*˜š&Õõ*˜1X˜ðU¹`É_Å_ƒ2¥Øù+ÁB¿Ê5ÊàøWL«)\“ݵ™&”µ…@ª÷Päõ.s^5Eþf¸ZÓW+ !!œ(‚,ó”r„Í 8Ý|d$zœL‘dkÇQJd™‰IâøÊÜÓÕk¼Âè¨Ë†R*\½z Ï>RB¥|H'I8KH±ÍŽŸà£¢¢!š¦ãW„RNQ.Ï¥WA„®L´iI2öìqOšG:$I7M `²üêõ–üãÆ¢E¦Çã IÝý74MSãÇ“'Ã7ß”ò¼j—_H~0i ÿædB8I ]/¿ ì!ÄE)0ŽÔ4A’ÔŒŒÒÉ“áøq‡(¦ÉÔR“ãÀårΛ÷êk¯-PU&Ƴ)¥’¤=ê˜4 öìqK’ašå|ý>ÒÄÎÜsO»½¸E yýz™ñË6 ˆŒ„+Ìyó\ôÙgCž{Ž»x‘ }Þyç€HKFõÅ_ˆo¿-ß{/q8˜°3² gÏÂC¹N=!AþäÙ0˜V¿a@ݺ°h‘ùÆ¥äþÇ:v,g·3Í!`šdÀõ÷ßÕÈÈðÝ»÷ÄÅÅù"ŽWmú>'I ±Â¶%„BDÑpQTxü!‹áDÑPy^@|F@ž(¾+Tp­ÔaR® 'Ü ÙÚRž'‚ è¢Ø,à,yp–a%B(!œ$™ª(ŠŽÌ+Ø·ÛÝ¢E‹¡C‡½öÚkO?=¯U«Q/^dd¼ „3FHÔuϸqÿ’¤ÐØX¦7 ¥†,G.Y²vÕªôѣǪzÁWÊÆ¯ð<¿nݺììì1cÆ€Ífc„¢"Μ9!*j}›6íSS¿özK¬VF_£µbų_½<=ý͸¸Ç<;c‡ áŸ~ºDÚ ‚2fÌAcc™Ü˜-ûôÓï<ùäSC‡kÑ¢Eaa¡ïÎuŽ”çyY–@Q,„˜ˆŠ`˜.ò¨Q<¥œ$É”jŒ÷4BtM3Z´°L›’¤x<`šûÞ4ÍAƒa=þÓë5#"”I“€ç%]ç јßWš× :)íÛƒ¢X¼^ƒ½ !¥¦$ÉcÆp„ð‚ Sêe¾鄘ŠbY–+Ä1ÊC ˆ/öxÁB©i·S»=àû=! ªfA”–š5x}úä'tÝ,,‡Ã¬ŒÔÂy@žÄ*Û––š ªw˜Rj·ƒÝN±Eºå@!¾ÿtÕ§ç;K• Âó$ðç¾Cˆ \¾MªsnjFZ"PåFI’xž×uÝãñTnËqPÖ²TI<ÂÒÛêL¼”²×KÐQ’››‹e›6mz½{äG‚.Qïú zõÕW»té’ššúÒK/áσcÃ'7Lx• ö¢[·nK—. ¯Y!¸¿X‚½± o½W¯^÷ß?Þh®wüË V< K0¸·P”&¬(»·Z­2´X,Á\s n˜°²pwîܹììlä|~Ãñã¿ 8Âf‹ÐÙV!µÙ„ó\S§NdÙŒŒdY…Àó´MéþûwîØ±wàÀ117{{ödttlHHc11œPI»ýLI‰£Q£–†a` …SŽçÝgÏž ‹Œlâõ²†š)¥¢È•–ž/(ÈkÔ¨9Ç…›&UΓ$çÎ „kÑ¢iìä_v»ýôéÓqqq²,—O²¼bB(GÃ(vÅb±€ªº9ŽäŠmYV4ÍkÕ¬7M*Š Ï ªê ëµÈ²Õ0tMó°Õ¾*?¡’(Jªê¡4 ÷"5M‚@K$D¨Ã‚ (Šâõz+¬Ý«LX6¶f]—¶ÿ”V×¶ê‚?5“ëÒöÿÒêÚÞpsÿÇËÿßzÝ%Àœ®%tEXtdate:create2017-06-06T01:31:12+01:00™Ò¡%tEXtdate:modify2017-06-06T01:31:12+01:00è¬IEND®B`‚puzzles-20170606.272beef/icons/loopy-ibase4.png0000644000175000017500000000111513115373733020020 0ustar simonsimon‰PNG  IHDRqqÇ gAMA† 1è–_bKGDÿ‡Ì¿tIMEáõnC¢ vpAg` >nlIDAThÞí˜[ DYz––UíÃc …pH¦Z‡?:N¯:¦ =‰$’H"‰÷"jJI+_÷Ð? e—úõÆ(8ô|˜ô~"´Fü:>¯MõÑÐëS03I$ñD•çDÏôYÞë£ÄµKè‰.¹>H”W¯3]–Vú¡û¾ˆ¬^q$j‹øžg¢T‰ê¹Žâñ°ŸÕìt Þ9…ã0øéÐíÄØê…‰à.@,9ê2‰$’èFüÒüØž2ᎃù°å¿ºÆ/Ìí½Øí'‘Ä$Úò¥'Ñ–/]‰¦|é:«k¡8ât ±/‰†|éK´äKW¢)_ºîUS¾ô$ÚÒÞom~I$±ì¿(?f§>»G> ºÖˆ_LjÝd’H∅üMÜÚލYþC¬£ ‰ ÕíßÏA„Ö¸nvIDAThÞíÙ¿Kað¯!Q’` ñGiµ´ƒ.‚KE*´¥œ„m‡viiK»¸tuppVP‘¢¡Áé(Z0º ]:ÜßÑ#f¸»Ü½Ï{½ç^hú¼Ë‘÷Í7ryó’/mz@DEQÄö­Rºd)žÎ°îG;Ð1ªHë ‡7ÑéÌt^†õhb9…TYñÈõÈ¢UΔ•Ÿµî¼"‘oÙ«—¶zë-ï¡%/¢ˆí!Ö_fŠ ?ÂÖ×îå³#/k|âÏûC¢÷¸Ä}`ܹ<VÃÅó[ȹæb‹cÎå™J<@—ëÄ¿«wœËCÅ]ý–GnÇ=Á²súCw޽օþª'ÎñíøþíøšB~­R©œ±‰Í vL5GL²‰vý•ò”K@ J¨—EQD61v?¤zGôþ¨Ñ¨¼w†£Ry¯ÈÑ©¼ï>Çï‡dÞ?{/F΋(âÿ(êõKNQ¯_rŠzý’SÔë—ì;‡ì—Ü"Ý/™E~É+êôKVQ«_rŠzý’SÔk{ÿ¶¨—QDƒó ýÌ{g8ú!5¼ Ž~Mäè‡ÑDŽ~Häý;/ÝïË‹(b[ˆ{³™¾§‡æÄåæ±vbLÜX>½ÚÞc xgRü]-!g{œÇÇžDÂâPÖ™(¸ëQòŸcmxlT´€ÆÄ¹•êõá40kLì¹9ºŒ‰' éìÈ Ë“HT Lˆ(¢ˆ†DŽ~Häÿ¢?R#úÿqÑ/ÿ¸é 3¾ Ú%tEXtdate:create2017-06-06T01:31:12+01:00™Ò¡%tEXtdate:modify2017-06-06T01:31:12+01:00è¬IEND®B`‚puzzles-20170606.272beef/icons/loopy-base.png0000644000175000017500000000735513115373720017573 0ustar simonsimon‰PNG  IHDR÷އªbKGDÿÿÿ ½§“¢IDATxœíÝohUuðßlK.Ì;jwWºsê˜lám¾ˆIhw ö&Ès)nC„KÄ F´‚ °BDÖ %Zá¿eƒ.õ"²ÀÙd›Ý©+õº;wµõ—Öe·GÆÐãÙ=w¿çì<çù~^oùœ¿íë¹Î}ž‚d2©[±Ü XfÈH‡ €tÈH‡ €tÈH‡ €tÈH‡ €tÈH‡ €tÈH‡ €t62011±mÛ¶µk×nÛ¶mbbBûRPõ—¥~Aî÷Noß¾}dd$›Í„Ãáx<žÏJ—µþðð°ÞšàNÏ<óLî¿?…¹×Ëf³J©l6;66–J¥òYݲÖ×[\ËÖÏÚFjjjFFFæææV¬XQSS³zõjûk[æúCCCzk‚;ÕÔÔäþ?Ûx.411±oß¾D"ñôÓOðÁëׯÏguËZëÖ­Æñ÷ßÏqý¨o]?¿Ÿ¯ R©”ö¡« …Œºo²Þîõóûùâ½Qééél|FfËÌÌLGGGooo*•zâ‰'êëëßzë­ù·®–¨¿¿¿§§çÒ¥KSSS³³³ååå‘H$‹ƒA-õA’ üùçŸ;vì5þ855ÕÝÝýí·ß~ùå—kÖ¬Yzý®®®o¾ùfþãããããã===ñx1»Hž uvvxíµ×~øá‡(¥R©T{{»–ú=öXCCÃ_|188ØÝÝm|æ255õÉ'Ÿh©¢dàóÏ?WJµµµ­]»ö7Þ(//WJ}ýõ×333K¯ßÙÙùÞ{ï=ÿüóÁ`ðÅ_Ü¿¿ñø/¿ü²ôâ þ ܺukzzZ)UQQáóùŒ{˜2™Œ–»ÖJJJþñŸþ1*++—^¤ÑŸ;wî~¿þÁU«VétZïénÞ¼ùᇧ{õÕWõ ß5¾ ðð±Fccc;vì¸{÷îÊ•+;Fz³x•þ ”••¿ÿþûüƒüñ‡qPZZªëD?þøã+¯¼’L&ý~ÿ§Ÿ~ú /èª ¢èÏ@yyy PJݼysþ™z"‘PJÖÖÖj9ËW_}µk×®™™™§žzêìÙ³[¶lÑR"y.ÔØØ¨”úï¿ÿÚÚÚ~ýõ×ŽŽŽÛ·o+¥^zé¥^ÎæçäÉ“ûöíû÷ßKJJÞ}÷Ý¿þúk`````ß–„<|Föæ›oöõõŽŽž8qâĉƃÁ`ðwÞÑR¿§§gnnN)533ÓÜÜ<ÿø–-[N:¥å Éu ¸¸øìÙ³ÍÍÍkÖ¬)** ƒMMM½½½Z>$Ћê~¡’’’ööv] ?Àø @ Ü7 Ò! 2Ò! 2Ò! 2ÒÙž?°yófÒþñ¤õM5Öç¾?Üë›/Ê]ó›`«?}Ž0ß wÔûÏxþ€Þ‚Öçb½~î¨÷ŸñüÇæp_?wÔûÏxþ÷ùÜ×Ï}¼0€û|îë§®O½?˜?d¤C@:d¤C@:d¤£ú>1kÔó ¸×÷dÀõ|îõ=Ï…LPÏ7à^ßcp0ÑÙÙ9ß/ îß¿¿­­Mé›oÀ½¾Çà:`‚z¾÷úƒ ,‚z¾÷ú€ X¡žoÀ½¾7 D=߀{}Ï@ÌQÏ7à^ßK𾉓'O8p`nnná|¥ÔªU«ª««QßcÔó ¸×÷<ép0A=߀{}Áu¤C@:d¤C@:d¤C@:d¤s×üÓcõ±þå­oz¼ìõíÍÀ|€q_Múì3Í5wíR££÷ϰ½®|qŸÀ}ýׯÓÖd<ór?ëõWU‘ÔüùçûÇŒçpï¯õ[×F·Ž«ª*õñÇ,ë;1€{}¬ßZ*u¿þêÕ,ëcþ@>ééŽäûÄ/^€«<ŠF£uuu@ °°ÐçómذaïÞ½ñx¼¶¶–âtKArhiiÁ?ù0ÀUpß(H‡ €tÈH‡ €tÈH‡ €tÈHgoþ€é±.èÏ}ýMMjófÕÔĵ¾éñ¢\:€÷ùÔë'š?06¦²YUP ª«]4ßÀ¥ó¨qŸ@½~¢ùÙ¬RJe³NÌ7Èý/ºtþ5îó¨×O4 ‘¸p`¾AîÑÞüêþúÜëc¾u}wÎ7°7@÷×ç^ó ¬¹s¾Þééé޶ß(SÜçp_¿ÃÜçp_¿Ãð\È÷ùÜ×ï0\LpŸÀ}ýÃuÀ÷ùÜ×ï0d`Üçp_¿+Üçp_¿3Gâ>€ûúƒ ˜ã>€ûú„÷…LpŸÀ}ýCLpŸÀ}ýÃs!×Üçp_¿ÃpééééìÍ î¯Ï½¾é±ÆúÜ×ïÎù.?@Ôÿ~¾?=5Ì7x˜“ó Âaþó¨ûÓSÃ|ÓšóÇÔó ¼0€º?=5Ì70­éØ|Âù2ûÓç^Ÿû|îëwbþ€Ìþô6OÁx>€b¾~ÌÈ2Ò! 2Ò! 2Ò‘|ŸøâÅ‹G½råJ:Îd2¥¥¥uuu±XlÓ¦MZêS÷×Gÿ~kےϺººZ[[xðñÇïííݸq£Å_ÌñýÝ={ö,ì¯oƒ‹ö×§®¯˜¿¿®r[Þû#èóÊÊʃöõõ]¾|ùܹsUUUJ©ÙÙÙ3gÎh©OÝ_ýû­ylHž E"‘H$b—••íܹóСCJ©¢¢"-õ©û룿5ím¡L&cLRJùýþÆÆF-e©û룿5íaÂáð½{÷ŒãP(tüøqí·I)úþúèßoÍûCøÞ¨ßï÷ù|Æq2™Ü½{w"‘Ð{ êþúèßoÍûC˜ .\½zupp°¡¡A)5==}äÈõ©û룿5ÏìùgdÁ`0Ç×®]ÓU–º¿>ú÷[óÒþ¼ˆÅbõõõáp8$“Éǯ[·NK}êþúèßoÍcûC’þþþÓ§O?ð`qqqKK‹–úÔýõѿߚÇö‡ä¹P4­«« ………>ŸoÆ {÷îÇãµµµ§X |—Rû)¼¯DÞÜùûƒûFA:d¤C@:d¤C@:d¤C@:{óLuqmúÜësŸÀ}ýŽÎ î_]Ͳþü|êù ˜Ïð°íÛ·Œ ;7€º<Óú¦ÇëS#šoàèüêþñLëÏÏ7à^ŸÑ|ƒáá!òùÜçP×wg}÷Ô§žoàÄüî÷´Q×wç=aˆïÉÃ=sù@@:d¤C@:d¤C@:ª¾¬ûÓSÏO Æ}ÿÓétggçO?ý4<<<;;«”êèèhjj":Iºººö§7:ïæÒ¿ß †††Þm299yþüùx<¾èü—à¾ÿ“““}ô‘c§#y.Ľ?=õüjÜ÷ßï÷777¿ÿþû¯¿þº§#¹pïOO=?÷ý¯¨¨hooWJݸqÃÓ‘dÀ3ý鉿'PóÌþ;ƒv‡âÜŸÞ™ù Ôøî¿chßeÝŸÞù ÔXï¿c3À½?=õüjÜ÷ß1TðLz¢ù Ô<³ÿ y=À½?=õüjÜ÷nnî·ß~S ^Íÿý÷ßwïÞUJ=ùä“ÚOGò𯯯ï¾ûîáÇíOï’ïˆ,|5<¯¸¸øÔ©SÖíã]ò×î¿Êí;47nÜxî¹çLÿÓõë×W®\ùèâø&˜Ÿ ¾K©“K®®­¯ð]JB@:d¤C@:d¤C@:d¤³7€û|êú¦Çësßêù˜?°x}Ïô×g:ŸÁ±Ÿ¯­ý—5À1Ôýõ™î¿c?_Ìxd}Ïô×gºÿŽý| ç ¿¾u}wö×—S?¿ßO{÷Ìáž°Náº{ÂäÔÏï÷ï‚tÈH‡ €tÈH‡ €tÈH‡ xP:~ûí·_~ùåõëׇB¡P(ÔÝݽ܋r/ò~£à<‡û÷s‡ xÑ¿ÿÙgŸ8vìØr/Çír¸?wx=Ò! 2Ò! 2Òá}!r¸?wÈ€ݺuëþý­­­­­­j±þý2á¹H‡ë€UTT}ÙÕ“pééééìÍ0=Öýõ­Ï}Ü9ÿ!ÏùÔ˜Î7@}ëúîœÿ`ã:`«§û1íúÖõcëwÕFlõt_"¢þôJ)Âþ÷¨o]ß1„ó¨ûë£>ê;_ßÞüïÁ{£ 2Ò! 2Ò! 2Ò! 2Ò! 2Ò! 2Ò! ÝÿK ÍŸ»¸‡NIEND®B`‚puzzles-20170606.272beef/icons/loopy-48d8.png0000644000175000017500000000226213115373733017344 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEáõnC¢ºIDATHÇ•VßkE_*6i¼Ë¥oõMj¡HQÑ6¡¾øP Áþ€¾Û‡@Q|¨ j ŠöA«HÓÆ4ä¹”S¤€> -¦ ·Ç5»;ó;w—ä6—»¤çìÎÜÜƸù<,÷Ù™Ï}¿óÏ|g-²MXáAìM;Á PS@WEkR!A‰2 ÊV¨P4ûHªÀð­ùìް¸÷< Ðê-ë´° lÆ:iÏZ;_èÒHíØã2Þ/{êo_8>#ƒwÆ&"ŒOþøþ"‹RQ* y@©"ùªÔ3Ù¨T5j>¦ºJv˜¬>óA(m¬KBY÷µÀA8ßЖO1òñcY €øí“K¦¼ûz ™úâTýbï‰W …à•«îå„l!ÀÕ7?"¿,á(°Æ¹EØZðÖ9èøU pðõùòÿ¤tå¥c½r¹Y½búü)Ý*!ʼn‹Oô¢qéîÐ…!ï¿6ŠÊºÁ!"2¥åúzamSVæ‡3à —ëû4Ú8,½ägn¬yz>0†µùðLÌ|dúÏ&!Œd†kØ8qΉ¬‚6óM[é”F:m øz$ïOïFÚ|µüæÏ??˜U¸9:0ܹ ÀA™¯™O­Ltg•5Z±åD GrJ Í§VFIj¤Òò[äÄâF]:‘9}¶¨}Ðhjt­­ô ~¿pùo™Û—K$À+ß=tšT ÓlœßïoC€ƒ«¯?YJž ¾µN}Y`‰#àòÜ¥óØfFXÖ¸ 9q}c]EÇçM+ÆÒ7h4’o˜×ßÀÌBIŠB0Ÿ¤Gß(7#ÂíW‡‚¬Õ•éÖÈd¬M'æù¬µËŒôt¼¨:.>xnpòÚu…ÃG[~ãw¾7eF¾?£;å©; V ‚jMúM”Í‚dç›’# ku®N0Ô5Vq<^«Ry8îİó-j#zÍÎ wMT=ñǧC >´oʦM@ Ü¥Û—ªÍ$ (þÔ{¶‚G@xùö;oÓäÜåo¾xhrAéÞŸý%’.z8ú§ç¦~¨›Î‡çÜ(^ù¹çµ#}ý‡w¿Ò"ý™3<¯ÈîîSæ#Ôs 9;ÁÎÙÈIÝElàºúK@^–<†vÂÌÑÓˆľ?þÁvðB#M_h 8d%tEXtdate:create2017-06-06T01:31:23+01:00±*­G%tEXtdate:modify2017-06-06T01:31:23+01:00ÀwûIEND®B`‚puzzles-20170606.272beef/icons/loopy-48d4.png0000644000175000017500000000107013115373733017334 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA† 1è–_bKGDÿ‡Ì¿tIMEáõnC¢lIDATHÇ­V ’à ÓÓõ4ýŒrØYét&)E²N‘’ÒáÐÜA†g€ú‰™›]€Ê°Ú,5¼ƒrw<2@£¤© N‘Îð-`dP˜qÐBën% ´±oIHî$åNùUcÐK€ñE’œš¤gâ6K¢-±¢A¸féïww—Ô–þ×u8Î^šÖA©¹µ‹ [Z=‹ŸçÅqÀ-êh¨fèN`æÃÅÏó¨– ¦ÁaL/ŽxË w;W63¯0Vm%Ùöf· _Ç௠²´˜§½ÅܾÄp]‡(†S­]bØf©c¸xie(Žd× ŸæÅ˜pëV·ZAí>ìòº=Ø5-õkÖ°V býÌtQrÀ%-A™±GD˜ÿ jÍ{I] Š@’„À‰ÒÚø4ˆÁª4|h1ï¸#¯i þ°ÍÒ£òR9«[ëéF»ýùïQݪòRù‡ªvÕ.Š–þLó²hŠ3ÖÛ%tEXtdate:create2017-06-06T01:31:23+01:00±*­G%tEXtdate:modify2017-06-06T01:31:23+01:00ÀwûIEND®B`‚puzzles-20170606.272beef/icons/loopy-48d24.png0000644000175000017500000000226213115373733017422 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEáõnC¢ºIDATHÇ•VßkE_*6i¼Ë¥oõMj¡HQÑ6¡¾øP Áþ€¾Û‡@Q|¨ j ŠöA«HÓÆ4ä¹”S¤€> -¦ ·Ç5»;ó;w—ä6—»¤çìÎÜÜƸù<,÷Ù™Ï}¿óÏ|g-²MXáAìM;Á PS@WEkR!A‰2 ÊV¨P4ûHªÀð­ùìް¸÷< Ðê-ë´° lÆ:iÏZ;_èÒHíØã2Þ/{êo_8>#ƒwÆ&"ŒOþøþ"‹RQ* y@©"ùªÔ3Ù¨T5j>¦ºJv˜¬>óA(m¬KBY÷µÀA8ßЖO1òñcY €øí“K¦¼ûz ™úâTýbï‰W …à•«îå„l!ÀÕ7?"¿,á(°Æ¹EØZðÖ9èøU pðõùòÿ¤tå¥c½r¹Y½búü)Ý*!ʼn‹Oô¢qéîÐ…!ï¿6ŠÊºÁ!"2¥åúzamSVæ‡3à —ëû4Ú8,½ägn¬yz>0†µùðLÌ|dúÏ&!Œd†kØ8qΉ¬‚6óM[é”F:m øz$ïOïFÚ|µüæÏ??˜U¸9:0ܹ ÀA™¯™O­Ltg•5Z±åD GrJ Í§VFIj¤Òò[äÄâF]:‘9}¶¨}Ðhjt­­ô ~¿pùo™Û—K$À+ß=tšT ÓlœßïoC€ƒ«¯?YJž ¾µN}Y`‰#àòÜ¥óØfFXÖ¸ 9q}c]EÇçM+ÆÒ7h4’o˜×ßÀÌBIŠB0Ÿ¤Gß(7#ÂíW‡‚¬Õ•éÖÈd¬M'æù¬µËŒôt¼¨:.>xnpòÚu…ÃG[~ãw¾7eF¾?£;å©; V ‚jMúM”Í‚dç›’# ku®N0Ô5Vq<^«Ry8îİó-j#zÍÎ wMT=ñǧC >´oʦM@ Ü¥Û—ªÍ$ (þÔ{¶‚G@xùö;oÓäÜåo¾xhrAéÞŸý%’.z8ú§ç¦~¨›Î‡çÜ(^ù¹çµ#}ý‡w¿Ò"ý™3<¯ÈîîSæ#Ôs 9;ÁÎÙÈIÝElàºúK@^–<†vÂÌÑÓˆľ?þÁvðB#M_h 8d%tEXtdate:create2017-06-06T01:31:23+01:00±*­G%tEXtdate:modify2017-06-06T01:31:23+01:00ÀwûIEND®B`‚puzzles-20170606.272beef/icons/loopy-32d8.png0000644000175000017500000000167613115373733017345 0ustar simonsimon‰PNG  IHDR V%(gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEáõnC¢ÆIDAT8Ëu“OHQÇç^×nuŒ"°S´4\l¥Äþ·¼yPÈD—n‚D!ARQIëžÚL:µflZQd´;óæý›ÙÙ;oÆöÐôÞÌ.X°æ7/óû½ïû>‰Ä`6 ‘RJ$BBD¸Q”t×vÇv1¤’®œ˜7‹Š"õÔŒÍ EFg{:»8WÎ|®H„ÌÊHÓ…¼UÕZbê]n‹³½úSç-Ì2!®o`jòÇeµ>°šQ ‹ŠWŸÜýb"¤èáHA RKž*†Ä%>šùÄäp€¤•§=–Zö¡Ø õ¦îŽ`kíúrøŸ@F¤<Ýÿ¶ŠDQ_ß ÃÿW@&ÔªVÿ„ª€r¤¢Ö7LuÙ ˜Ç|7¼µæ#á˜T*iàä‚0JrûÅd‚Ó{ýX:rLA·?V%Šg¸?Âx³}úe&›ÍnlÎnÇŽYû&Ò6ˆ8%$s¡Sãx_©•MìX‘QÑB–È8±?E•ÒG£´Úx$PpS­¡æðòÞÐ(sZ °ù:µ×ú $å«—×Ën$ ² UŽìönÄ¢Hé—bqÖ W?ä°0µéáÈäð•z…é¼%irGÏ@Jpóøc»÷'yi0ZhÛç‰ÒÎO=[Z|º´¼ö`ÛÛv÷Hfq™³2{P– Û³zÂß,þp`}0Ö|ßgˆ„ìΜ©Ì¥÷(ä‰#ª‡©Å?Y‘Hrº¶”=·âñÀ†àh„ÀÒ æYkÁ+ïûýkÏÜB`wåªê·b î˜@æ‰b°a)¸ÝùÐ ˜ë1b1c‡7V‘(ª‰«GaÛÐäØ8g"yoB¼ÇÒ§gíà–áqn…_ßïÄvãwþÓŠšÁý(ö†iŘ͢ªÇžV(ù Äv6O±F‡î%tEXtdate:create2017-06-06T01:31:23+01:00±*­G%tEXtdate:modify2017-06-06T01:31:23+01:00ÀwûIEND®B`‚puzzles-20170606.272beef/icons/loopy-32d4.png0000644000175000017500000000100213115373733017320 0ustar simonsimon‰PNG  IHDR V%(gAMA† 1è–_bKGDÿ‡Ì¿tIMEáõnC¢6IDAT8ËeS‰‘A"tB33OAí¹ÚžgÝ~PAFd˜kîô\ݰöh‘ =µœÔÆ^a8LVäÁDdÜCfLªBè(¸Ù{­_žV ý[ÙfG—´Ç”ƒ 4ÕAÕ°-”ܪîo Â+S¿ ®a!°¹†0 þ¯aûж?U´˜4¸é« Øeº‹áù™€Î6³ õÑO ‰u¥õvšÁWïu´ÚQùìð¡',©5è¾´ îuŽ€1‡9ëHúÅÑÂÏëNQ¹æÆYÆÿ£—‘ã¾â«[Çâ”O.b¼c¦+ø±g5—pÈ€<ÙÕȳDvOåqÞ”mÎjMô<ÓZCŸù·?®Ñ/ñq »rù‘Ÿ„kø|}eúÙ-…ÀŸ±.±T„ž‰øùâ{”%ZükJ%tEXtdate:create2017-06-06T01:31:23+01:00±*­G%tEXtdate:modify2017-06-06T01:31:23+01:00ÀwûIEND®B`‚puzzles-20170606.272beef/icons/loopy-32d24.png0000644000175000017500000000167613115373733017423 0ustar simonsimon‰PNG  IHDR V%(gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEáõnC¢ÆIDAT8Ëu“OHQÇç^×nuŒ"°S´4\l¥Äþ·¼yPÈD—n‚D!ARQIëžÚL:µflZQd´;óæý›ÙÙ;oÆöÐôÞÌ.X°æ7/óû½ïû>‰Ä`6 ‘RJ$BBD¸Q”t×vÇv1¤’®œ˜7‹Š"õÔŒÍ EFg{:»8WÎ|®H„ÌÊHÓ…¼UÕZbê]n‹³½úSç-Ì2!®o`jòÇeµ>°šQ ‹ŠWŸÜýb"¤èáHA RKž*†Ä%>šùÄäp€¤•§=–Zö¡Ø õ¦îŽ`kíúrøŸ@F¤<Ýÿ¶ŠDQ_ß ÃÿW@&ÔªVÿ„ª€r¤¢Ö7LuÙ ˜Ç|7¼µæ#á˜T*iàä‚0JrûÅd‚Ó{ýX:rLA·?V%Šg¸?Âx³}úe&›ÍnlÎnÇŽYû&Ò6ˆ8%$s¡Sãx_©•MìX‘QÑB–È8±?E•ÒG£´Úx$PpS­¡æðòÞÐ(sZ °ù:µ×ú $å«—×Ën$ ² UŽìönÄ¢Hé—bqÖ W?ä°0µéáÈäð•z…é¼%irGÏ@Jpóøc»÷'yi0ZhÛç‰ÒÎO=[Z|º´¼ö`ÛÛv÷Hfq™³2{P– Û³zÂß,þp`}0Ö|ßgˆ„ìΜ©Ì¥÷(ä‰#ª‡©Å?Y‘Hrº¶”=·âñÀ†àh„ÀÒ æYkÁ+ïûýkÏÜB`wåªê·b î˜@æ‰b°a)¸ÝùÐ ˜ë1b1c‡7V‘(ª‰«GaÛÐäØ8g"yoB¼ÇÒ§gíà–áqn…_ßïÄvãwþÓŠšÁý(ö†iŘ͢ªÇžV(ù Äv6O±F‡î%tEXtdate:create2017-06-06T01:31:23+01:00±*­G%tEXtdate:modify2017-06-06T01:31:23+01:00ÀwûIEND®B`‚puzzles-20170606.272beef/icons/loopy-16d8.png0000644000175000017500000000100613115373733017332 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEáõnC¢IDATÓÎ;KÃP€áïú+¬›à ‹KG±4 ÐÉ¡›AÄÖ.µ$Š HP1I/ m“sΗsNšKãeèd]_xà Ig $lâùþ'àŠ‹R7Ëux ªêù³ÇHÈwk©|çeÆ€âÇÞ½äýãäLSHsÚŸäÛW«T3†a¦ó¬j×úÅ‘Œù8€…™.ëNÇL\mz6¤éW÷y[TRjŽi£»FA(ÉNÜÿFSÑ1*Ê¢ÐMzLmM;4% -¥ÝôÀÓê1Y#Ѝ]‰L0ð•Íþ [Qœ·$e ïòçnQeÊnŒ#§Æ“qÓ>Ü6EÂÝ9°7ûűmDZ=¶sñtlÌýƒ­|%tEXtdate:create2017-06-06T01:31:23+01:00±*­G%tEXtdate:modify2017-06-06T01:31:23+01:00ÀwûIEND®B`‚puzzles-20170606.272beef/icons/loopy-16d4.png0000644000175000017500000000046313115373733017334 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA† 1è–_bKGDÿ‡Ì¿tIMEáõnC¢gIDATÓ5O‰À btFc³”Çz‰ "î”RÊã H‹¤›fÅ8w0³½Œ±Ux  ñ¶<Àd_ªÕ%Š›b.U,ÇŒ£`Æ æ òü³vp@iÒ_Ñ+™û¹¥Ð ¶_ë%Ó}g˜Ìâ°Áe`%tEXtdate:create2017-06-06T01:31:23+01:00±*­G%tEXtdate:modify2017-06-06T01:31:23+01:00ÀwûIEND®B`‚puzzles-20170606.272beef/icons/loopy-16d24.png0000644000175000017500000000100613115373733017410 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEáõnC¢IDATÓÎ;KÃP€áïú+¬›à ‹KG±4 ÐÉ¡›AÄÖ.µ$Š HP1I/ m“sΗsNšKãeèd]_xà Ig $lâùþ'àŠ‹R7Ëux ªêù³ÇHÈwk©|çeÆ€âÇÞ½äýãäLSHsÚŸäÛW«T3†a¦ó¬j×úÅ‘Œù8€…™.ëNÇL\mz6¤éW÷y[TRjŽi£»FA(ÉNÜÿFSÑ1*Ê¢ÐMzLmM;4% -¥ÝôÀÓê1Y#Ѝ]‰L0ð•Íþ [Qœ·$e ïòçnQeÊnŒ#§Æ“qÓ>Ü6EÂÝ9°7ûűmDZ=¶sñtlÌýƒ­|%tEXtdate:create2017-06-06T01:31:23+01:00±*­G%tEXtdate:modify2017-06-06T01:31:23+01:00ÀwûIEND®B`‚puzzles-20170606.272beef/icons/lightup-web.png0000644000175000017500000002654413115373720017751 0ustar simonsimon‰PNG  IHDR––³cæµgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEá  ŠN,hIDATxÚí}y`Eöÿ«ªî92IÈ áB"Dà$Ê! ._‘tEÅõ`<ð@E嫮拂.òS9\d5®,(r‹(Ë)A@Ž$\BI&3“™é®ªß•i†ÉLÒ=db–õý¡$é×Uý^¯ÞûÔ{èÔ©Sð;ý'þ­;ð;],ý®Âÿx’~F!„Âz/0ÌÆ! ”†ý ãfîóoÈË9çœûÿ&P…^¯€!T'Y}/ñ<ç¡pxƒ¨(›$‘ û¦—œN'çª!-úÚÅq„¸þ_ ïÅ ŠsÀ²,ûÿé¼ B^¯÷›oÖºÝcBÄÉ9˜šÍ.·Ûƹ±)ÁX­¼°pkyy•,Kܰùµ×^KHcÔP»œ#³ÙÉQ‹¡¼‹CUMªj2((@ˆ[,N'Š1b\ȪŢp“ÉdÒu ˜Û- ø^RÒIU5ûæ{£„dÙ}æÌe7þùÖ[ÿj2Õ2FúÍ˜Ö `ìÿ',Ëö²²_}õð±c{0ÆL{TOÃ8· 5jÔÊšÆt˜1ÐÆÆŒwαÕj_³fB«Ve×^»Øåj…v%É»|ù³={®ÊÊÚâvGëçŘz½Ö+ž0`vJÊQE±è²$y**ÚoØ0€!1ýT蓈w&>þ´˜ìzÞ-žôz£“5™jΞ1F0¦Ng%€ !†¦0BLUeYöFE•šÍ˜½¢íBÍæÚèèʨ(;Æú7cñu8:º*6¶":ºR7/à^¯•19.îL\\™Q!«ª‰s)@BÒ…ÏÛ,çH§½ê[9ç\ãEŒqB-.æ{ö@u5X,™ Ý»ƒ$I”2ŒÅ“B¦ (¥Fg!Ã…sÄ9Æ€ìõª{öÀ‘#àñ@\\utìˆ9ÇŒQŒ‘Ö®& C 8B\£Z»:9G-äÐ*ô©—‹Æt¯¢  Bœ1N*)Qç̉¥t@çΰZ“ìöÚåË7}ðÁ²1cJóòc¾~…Øê›Çõí1é ÄBкuê’%Ú¶Ù¶m®$Y~ýõ̦MˬÖM?ìhß1Æ^‹3²j¼F…4ùÄeTÈÜOMÁTØTÄ`Œ7nd \óàƒsú÷ï!Æç¡1%%1㙽{?š87|”¨¯°†—YÎcôÖ[üäÉ /¾øzûö­xÝèå¬[·ãÙgÇOœ¸ûÚk±ªr|©‰#òãƒÙ‚7¼ùæêþý{pÎcb‘䜥§'¼÷Þ‚’’ÉŸ}ÆÁ¡Þ999_ýõ¾}û>¼nݺ»ï¾»2áùóyeå+ûÛ»íÛÇ´;xpß×__ûî»W?Î$‰À¥BŠô½÷’&N|?5µ•¢(aŒ‰ „0c€¿üòkk׿<©cŠªêÙ³gnnnii©Ûí8pàÇœ93wêÔÂÌL¬ª ‰×£D10ÆzôÀÏ=·5?ÿºÙ³•”œácL\.uûö_žyæÉ’’;ÞxÃ…1º”TX?Rá9Ñ…·Þç³ÇŒÍ†¦M£ëÖýߊs-Êq»£dYŽÞŸ]òÎ;Øf#”Ö¹¹âŠZ0†Á”BdæÌcK–Ü3wn§3KU‰ÅâhÕê‡áëo¸0†ý<ÿrC‘ ÎÁ˜¬ë¼ÁHÅyA…©€F"¾x“a':B‰]M Ä߆ÁƒÏ)Ê:$ ,uç@„œw­ gŠÑx!ÆTQ„Ç®®ÃâL ÷Ýœv:S f³Ö.&Œh—R&F‰¡H…è¡hÔ  ´°Œ¿ ŒE*êc5üUÈ9ŒYee*!TUÍþã´á·K’»ª*cµ¢"͵×ì„1’$„òz¡¦†©*ǘ‹~pNdÙ^S“PÆã…Œ€bµ&\îñ˜0úñzD²X0BÀ¯­åœ3Íå[­511‰‹ p™ÇÓ !!_YV¢££jjâ««[»ÝѺy‘ˆÚc¬VU¥J’GU-F„쩬LŘiÓ¬î¥cäv{¿ùf¥×K“u´Î©f³ÃíŽ µ*†"ÎÁje»wo-/·Ë²aBìäÉr—ËþÅlvrN¼^«!ÔBÈãQ22b† áp>™ Ä-»Ç͘d\ÈŠÉD n±˜´e@ºà刹ݶ[oýk›6Å^¯E?&Àdª--Í\±â™»ï~ÚlvùÏÂÆx‰ÙìÜ»÷ƨ¨;ÆŒyŽóúh¢€qþ¯ŒŒ«wï¾óºë¶ÕÖžð‡“D”ÀçÌ™žo¼ñyZÚ¯×fhzÕ²ý„ì>}ºÓ²e/!Äü¡-õ÷B$I^„˜Éä6ëà’äåɲG’¼†°3 IªÓé¨aaߟ ¨³šÒºÏ9 µµçÄöDiNbLñ"²ì6„aŒø„Ì ™ !7µ$„÷‘œƒAl.Âù:€âìrÑᅦ}ûÀá€ØXèÞrs‘Å‚)ešv…@9B“ÏZ|§ø cÌO>º>6j1& &¼°ïØg΀,Cz:äåA›6˜Ò õßÐ0ðB/>Îïa ÜaHššuW' BÐ_Е+¯ìÚuL·nl¶VGÕ®]k >¿í¶ý7ߌ9` H`v|Æêù×{LûF]ëÖÜŸ…1Ž1Þ¿ŸÍÛ&*jDïÞ#»vMSåèÑ]ÿû¿Ÿ]~ù¦‡òÚlgüµÁÎ\ üËŒ¼¬ì™7ß|9!!Jøt8çÆ][V6éõ×§¿7q" µÒ6 1ÆL&!Äãñ¸T$ViJA’ðæÍlΜþ“&}““éûX@¨Ç¸qž?ÿ“'Ÿœ8sf•ÕJ‚/×-ËÑK)`Œ?ù„Ÿ=ûâôéoÆÇ›£œsÆçœ1š’=kÖ»EEO,[Æe¹é(&Jttô[o½UZZZSS³qãÆ~ýúq£u}$IøØ16gÎÕ3f|•““I©êûXÆPzè®>›:UjàìѲTH./g7^ÿì³/BÝ™’øù׈°¤Ÿ{îÕ+zUUy›¼BOÓ§OòÉ':ôÉ'ŸôïßÉ’%;wŽŒÕ9s¢î¹gV›61ªª"ù,ÆDU•1c†òôêÕbòŠ–¥B¾aôìyW\œYUÕúø6B¥jëÖ1ݺýiãF€&OË(++ëÎ;ït»ÝãÆ»÷Þ{ÿùϦ¤¤Ü}÷ÝÐžÃøwr%%àv0 /“¤@Bc#FÜõïÇƨþrÞÒTÈöíKì×ï¦ä%¾êºë†íÙÓ ‚¡ßÂ&1ÉÚ·o{øðásçÎÀO?ý]ºtƒ>ÛF¾“ìÙ]ºŒ¤óîº`]â99Ùv{_·$)Ȩ©úÔTTU É>–RUui×Td6›@UU´€Õj€ú0ð‹¤êj°Z!$&BŒQ³<ž(E ~Tkq*´Z‘Ëålô1—ËaµŠÎ7ñþd·Û &&FÀ'ccc@ÌÈ&÷X­ (®†¿B eY%$8^«Å©°sçs»wo…Ы–øýO?}Ÿ™Y ¡ïc„AB=<|øpFFF¯^½,Ë!C@ X›p Š7edÀ‰›@ólÔÿX„ðÇl¶}QQ@i™´4JyylóæÅPZ âÁ(…­[çåqhRü cŒR^^>}útX²dÉéÓ§ûôé³aÆE‹\ÔmòÇž=¡ªêËN!üb%cÖ¬Y×µk1¨j~ËR!côòËQ›6Ÿ~øá?1–£šÛLÿ DÞAVÖ—ééM¡”"„>øàƒÁƒlܸñ©§ž9r¤Çã‰Ìé^úãKß}÷áÐÐ6`ðŒ$I.,,úùç—G€à®Œ–åúxê)xüññ‹uìØÚÕ$„!}ðÁg‡?ú·¿‰ûSMßÑâúõëׯ_ï×±ygX^Ú¿ÿïO=•øúëoX­’vÅS€Œ ¼ùæè©SmÀ;ÓâTÈ9·XÐÌ™ÕÓ¦š4éþ¡CÿÔ£G¯˜˜èêêšÂÂÖ¬ù¸uë…o½Å J#—àœ‹ÓµðŽ ßP$Âã?Œ?ÿü­‰wöï?!7·›6­E9|øàÚµ_ž<ùΫ¯–ué‚(å¡¥A°3¾»²z3pŽaœ¨ czgç€jØÁȘÍè•WøÎs7múäë¯Û»\Äf£ii'þügçUWJ¥\›ŒF˜u’Ð\cÏÔ¡`ô1¦‚B©*Œ-åæ~·jÕ–yóÒ*+­² ­[—÷ésfòdl2Iª*–"æCÜ„V¡ˆŠÆzá$â½1ÎA?1fºã…uÿÝ `ìÓúôqür!ãQð"Ä1&áÅ ÅóFíLáÄAûð/ÌH¼rBBupvíàT€â 0IÒ„LÓ Nu€A’ä=zôªÊÊv”êÇ^ B”ªª› NŸÎ“$ÈÉ¢‡“1l6׺\WB¼6ð¡E{ü$Îýñ/&Smee[ŒÝ‘ˆ†"_8Ì}útw—+›R›èS³ÕÊÎëËXU•5A‰½ð€ÈÒ@FˆÅnomµò-bg6løc76äõ ”ÅÄØ–.ýzƃ6[´AGQÕªGùŸN:»ÝîP'¤ZRRdÔ4E¹ÝnŒ±Ä—$èÐ!›R_ÒÛ6c,::jûö/>ýt}TT<çN)—«òŽ;Múª¢(ÚȾ;ƒ1s»m·ßþÉÉÇæÓp»»ÏœÙ¶¢â—ÊJbèüDˆØØÊÿô§wSô™"ñÈæÍ#â㟽ùæ.—‚u33ƬVëÚµk[µjuÍ5׸\.ý¼œsY–¾øby—.í/¿¼Km­Gÿ°ãœ[,–U«þQQq„£‚"”ÒÊÊ« !Šrþ–r 9ðBãÿms]Ÿ0F”ŠÄM ¯6Õ=ér9ív{m­jH…ªª:NBHMMQJ’äv×2†©*èT¡Hþ I(\Aaql ø}Ф%çÕ%Hž@•Ô_H5…Jb!ö9ƒˆ ®½œBˆxB¨>Úß4µ¶ 5êÿ££7„ . æ8ú§åP”KéJÃoNW¡8''''%%ÕÖÖž8q¢ ="1?´Qoôš@3Sd}¤bÂ=ôÐC{÷îÝ¿ÿ¡C‡ Z·n MêõoZâœGGG''''$$$$$$''‡a²6'EpŠõó†n˜;wnEEÅO|x=Î;÷å—_‡º+Ôc\]]]YY©í%Í­Ù"©9¼3^¯wéÒ¥K—.Õ~Ób÷A"‹éoÝ ½qú¤D8æ›-0ûßC `gô:9Çv&QJs"Â5>%SΑ¸Ðe-¯]xßQÇÐÂ.öEu1Ún“à°3TwÈ·BrÑØxŠ13n4pBˆÕjå\5zµZ­"J~á0=¼²,#„dYg$C¼_ £å±B=ˆ‘e÷îÝC­VG@Å—Æzæ5›;ÈòNý,~¼u8~øá^‡£Öˆá‡$É[Vv™ÇS¾sçªjl6H’äñx***6oÞl4x"6…_ýÕáp Æ"áÀÓú`hF†z8`!EÓêêÖNg¢!pcjtt²‘ì;õß@**RNC*h¢VÏ?ÿô™3§eYÖ/„¢()))Ó¦M«ªª2´2Æ¢¢¢Ž=úàƒZ­V£+°Óé¼ñÆ?ýôS·Û­" h«Çãñz½N§Óÿc±3-/oaxØ™W^i«ÿcü¤ÉÀbq :/ ìÌöí£**@Q4»ŽFçüìÙ³:tèÓ§!àc,&&¦°°1æv»â_@Q”›nºI–eýCG¬ÞåååkÖ¬ ðÕÇÎð(0c IЦ øB 3ÆÅ%ÆXo®™>1U¿Û–1,ÌrÇØ¾"Ƶªª.—K@ÙtòRJ%IÒþaìgœs§Ó)I’Q:ÎF€>Yœ‡ ý+«VÉ%%—Ûí6IâII§{ô8uóÍÈj­Ë¹¡q]qŠ17RþJô–k÷f€ !Møm‚B4dM}tŒÖUí%†Ҡ㬡s!c€1úè#¶eËð!C&üÏÿ\Û¦Mœ×Ë‹ŠŠ×®]õè£oNšt¢[7¤ªÐ"ãh¿ ‰³os¶Rö¢~Õ[oñÊÊWfÏž*Iu+°$Avv§îÝ'þòË­¯¼2zòä­={¶PçáoBqqq]»vmÛ¶­,Ë;vìÞĈz3BJŸ¼z5?yrÂk¯M%„©*õ•lCœsUU/¿¼ý‹/~öÿþ_zM …K¥æÃÅ0U>þøã-[¶Œ1š4OFPj`©+VtxôÑ—€sðwõbŒ%IRU¥[·´^½þwñb€&Í<ñJbÛ[¹rå<ðý÷߀Ãáh†vƒ¨PlÀ;wBJÊ­:%q΂î¢"yÈàÁê<ŸÆ‰ÕrÞ¼yóçϯ®yšC&At#–Ä¢"hß¾@È”(cÎYVV‡#Ëá€PeìþÛH,›Íè)w$©‘‚J¾Ì,„ÒK¤æÃÅ“¿åbèØ6…Ta|<¸\e:çcârQ‹Åa2…œ¬ÿmä»§‹Hׂnr=zÀ¡C˸¶#úºs瞸¸íV+¨j Â7‰Ù–=pàÀ¤¤$ÈÊÊÊÍÍЯÈÍÅ *muìÑÑ߬Yóoì›M¸ˆ+V,ÌËs@ †£5‰e3??ýúõ¹¹¹ðøãoÞ¼yðàÁÉݱ·ŠôÈ#îÉ“ÍÎ^×±câ…ÞKÀ ‘,Xb³ÍºñFäú¿–IJ”ŸŸÿé§ŸjƒÞd2‰Fä\6!UH)mÛ?öXáóÏ{øá®¿¾‡_ÂZp»éûïÏ>vì™3¸Ñ[Ý—*‰uhëÖ­[·n õ×HPHbŒc}ûâ×^Û9{ö€åˇôì9*!!MU½ÇŽý°gÏg½{ÿ0}º*Ë(B)|þC©þM¶HÃ…UȹV aŒUÒÓ¥éÓ«öï/ر£`ï^eèÔ î¼%U%"%ŠÆaÆ_„ë3¦·†\lBV°IüWDÍôK¹áÛ¹:LðÎE>/äc±ïÂ})Q\q\qEo]WÎ1B@ò闦߳,Ü`„Ñ.Ô%®ÀQQB’‘x!²Z 'Ø ³ÙFÈ×l67/äœ#$QZ¹rå@«ÕàódLBª ùb|Áy‘sÕdJ1›H0™bDþ>Ý: ŒUS»jÕ‹.—aàEmmlRÒ§O·•e©ƒBŠBÉñãå§OïfL1¼°Ù¢Ýn/„»Ãɲ¼sçN»ÝnÔL¥”ÖÇ—œW!cÌf³mݺõ“O>%$Æx>š{î¹}Ïž‘GÆz㇜#Yö–—w,-͈‰Ùn³ú$$IžS§²¦O03s«¢(Û$ Û:t,¶o_¨(ý¼Œ±èhË?$’þ…­s›ÍæŸsA ìŒÃáàª/k±¯¸ a™0&”ç¸{÷¯8/ómozÄA0¦ô/-Íè×ïSý•‚4Þï¾»ûìÙ99_Š ñ?Þ=1ñ×k®Yc0–W®ü„›ÐVUÕnݺ…±ž9sF\ ó')ƒ±øŸßî.rÊaÃKƒó Yè¯×¥ñjàU-wcÁÝnµª T¬Vˆ‹Ã„JëR£S»!Ä%c\Di.†Ün·¢(†ÖaEQDZÔ€ß79b‚b,p4:§án0¦Æ˜Zö†1e $ UT°Ï?çGvóx²)%&SÕº¥_¿³C‡Š#¬¿#B¤¦ͨýÔ²`BƒåÄÆÐ, µð^R 1ÿ¶mcsæ\1`Àë“&ÝšŠÂ8¾xñG7¾ñâ‹žØØ"!Œ&ºxºtT(ÀvÛ·³wßøÆÿj×.ÎwåÉ2éÞ=íÊ+_ùüóë&O3kVµÉÔôÎqÊÌÈȸþúë;vìh2™–.]úÃ?è¿I©Ý+¤3;Ã¥£BIBN'ýàƒÎ/½´°]»8UUëêæ,ŽŒ”ª£G9sæí÷ß¿ÿ‰'š¾"GÚ¼yón¼ñFEQrW¿ B)))þ™;+++õ¬—’g }õtï>9+«¢(’tþ´.*çH’Ä9}è¡?ïßß¿¼¼é![š›;77wíÚµPSS£·ëy½Þûî»ïüãwÜqûí·7NçíðKg({÷¶3f „Žìp&ôèqûæÍßÙ”õžÀwÌß°açÜëõ‚Á {Œ±•+WÚív1kcbbòóóÁ‡Wn€÷Ò™…œÃÙ³­32:ðЃ@ÇŽ½Ž­cirÒª»‡Á+6?£è›KJ…” \y#š!D®§HG©/;cà‚@d?¢ cˆ‹s”–žh$UkyyqëÖM]¦DÐÅ`gü¹¬ÓèRÚ ¥N~÷Ý÷cÇÞ*.{†à]»þ5a4qYq¨òÈé'žx33³5!À)E+Vl\ºôá§ž:˜šŠ)eB”8qâĉõ¯g>…iÇFä;~#B(e& ÿûãY³¾Ž‘’r!·ûÌñãË·ýíož¤$ÄC(RÀúç™H$*ñ§@ŠÍó"òï‹‹ÈF-i$Àà†€ýv¥¹•µFUyn.ºæšŠ-ðx .î¼RSçHUÅåò:^­ú3®pε6zå&‚èêðÊÕ')èsáæß¯‹1¬U\TÐÅØ&…P‹ÅêKþ"ûÏBPv6ÊÎF¾0²ˆrŸ¡Š¨ÙlÑ\’ú;ì_k@”U3*(Æ€e`Œëü^ι,CÐZ°¨R—’’b³Ù æâ@Ngm||üâÅ“œN‡Á¤ ¡˜£G½òÊ]„HFÆ&Bˆy<cg~üñnÎᬌՕG´âG/¥ôlÇŽ½‹ŠrŒôã‹¡¢ÔÔ.’ª¬`ˆc—ËÑ¡CÊ·ßî­©ñŠ£¿>V€ò˜Í8då4BˆËåêի׸qãl6›þŒ8¢ €ÃáØ»÷çÔÔ+%Iæ\¯ú9çË/ßU\\Òl.…Õg³µþ׿Fgdl÷z­FÒ= ŒUýÓŠÒÒöz<±ŸçåüSöøÎÆLU7n¼%#cV\ÜiU5é„npŽ$I©®NùñÇÑ]°f\€`ûÝîØØØäädÿÂN½½ÖáñÔvéÒÖd2éF3ÆL&Sii©XŽ1†A…ºäQ†1,!J9cæøøS; agÄʼe˘¨¨ý))[ŒðŠqýÜ Aa¤bÑŒú÷B¤I¨7 ˆ»–îP—´¯`Œ…:Y‹ék;£áÖµ=a _}ÅׯO¶ÙFÈòeàõÕÖ®:ôÜ!H³\4п¥ž&µ:ŸPϩԢυBµþ_ý @š3ÿ BÈë…×^#”>óØcO]vY¢¨yN)*.>3oÞ´íÛgN™‚ôDQ æˆT° I¿\8çéééÓ¦M[¾|ùÛo¿ÝµkW=n_ñ@ZZÚóÏ?_PP°råÊ)S¦@¸AŸFId.{õU)5u~~~~zzÁYpŠø,ÄÛl6íGÆXmm­.ÆXffæ·ß~›ššzöìÙ#FÜwß}ƒ ÚµkWÆ«$IŠ¢ÜvÛmùùùv»=66Öb±äççG(…!hùr@è™G¹GUB$QÏ\û^ÆÔ§žÿôÓÖ¬ygȦÏîÁYÈ3›ÍÇŽëÓ§O¿~ýúõë'N,ú@Nš4)55uöìÙIIIùùùqqq/½ô4æ× ï矞ššú /@Äó¿(ß~›rß}“ãÀ›icáÌ7îéuëâ AÊÈ.¤c¯×{èСŸþyß¾}EEEEEEzŒaÓ:¾ùæX³f ôíÛ766¶áåT(¸¬¬ìôéÓáúb <QQèÜ9)àCtõŠ+Ú2ìäI¨6¿X!GâÛê“–s^φ$ž‰ŠŠ tív;8‘999YÏ{¸th”„&Ξ“é2PÕPF/RUc ¤ã¹sÐä2o&‹4Œ Æâl ²,‹ÿ YˆUQç ý9uêÿ¸Ht¡™f¡f‹ê½¢(………૽ֽ{w8yò¤Îªy¾´FÌÿ"ô‘”^ï¤PÈG.I’ª¥E ®Ü6!E¶¥ÛíNKKÛ´i“V?Íb±ÔÖ6~TefÏž=tèÐgŸ}6++ëæ›o€Y³fAc§Ca¯æääŒ;V(¾{÷îsæÌÙ¹sçüùó›Ð +T˜™ n÷W–eeµ®öôçŸ2¶º];ðxX>šòeõˆsn2™®¼òÊìììììì+¯¼2##C…“}ÅŠ÷ÜsOuuõøñã)¥'N\¸p!46Ÿ„³²²}ôÑÜÜ\§ÓÙºuëñãÇ6 "bÚȃŸ]°àMõ8#ÞWþ‚Àßÿ>mذˆò±9ªÅ8Nÿß袼‹-*((0™LŠ¢hžw=‡Š‚‚‚%K–7›ˆ›‹ßë÷é$JÙ°a°cÇÌ·ßÎ|òÉñœ3„@UU„!$åçÏLM;`€HÐÓÄ:l޽0ìòñþÐE1Ä+¸œNgMMÃáp:'_'L¥^൵yúéÇ÷ï/UU.I!’¢ð½{O<þøxYžôÌ3M|–ШÉf¡–8t\ðçjZâô0º‡ô¡VDœA÷—j†¥v 0†^Àë×Ïú装’t3Æ—pJ‹[5jTMÿþ˜R~!—ÖÜÅnŒÁ#†¢ þÏgZ¤B»ŠÐ¯˜î„£e$ýKVÍT¨Am}?"ŠÐCŸ„¨*UÕ¨ƒÂ ƒ*t÷ …íPöØ£ÿ” ¯Ã¡ž¯ÿ§ ƒCàn⺌B8ìÂ.èsÐß·hìÌE’¦cCë3„(¦Õb3W·è[¾â¼¨‘ÑÉ-j@‹j¯F›>øà¶mÛ<8wîÜôôt£ƒ 9©E«RZëG^¯W§EdÑår F—Ë¥ÓÀqé©S§Î›7/--Íáp<ôÐC+V¬HLLl±Zl¡*¤”¶jÕêÛo¿MOOÏÉÉÉÉÉIOOî¹çâãã=x¨ªÿá‡vêÔIðvêÔéÃ?l”WViiiãÇ€[o½5''gõêÕÙÙÙãÆƒæ­£ŸZ¨ Å·Ûí{Q[[«sˆÔPSS#ò÷x<žFâå:ujÛ¶íŽ= [¶l_À¹™“«é¤jÎø›þf§NvmÑóçÕiˆéZ‘^·Û ±±±`Äq؜Ԣg¡öoÿ0ˆÒæÏ«Súâ¼o±XT”¡SÙèÍÙæ¡ªB¡!Ę˜˜èèh°X,úÑø&“ ¢££¯Ÿ‘x ¸¸¸´´´k×®iii ê¾ìÙ³"f¼Hj¡ )!Än·ßpà EEEÚÙN’¤ÊÊÊFSwî\üŒ1BÈñãÇçÎûòË/ñÅ¥¥¥½{÷Þ·oŸ|4s‘^ÔBU¾›§ÑÑÑZùqý.´€’".¡g %½úê«eee÷ß||üüùóóóó+**Zìé¾åª4À‹ £í,†wfΜ9sæÌñoºeêZ¸ áâð»a˜²Úóz|¤-„BeÈ710 ñ6ð£~vã%jŠŠè|›ˆ‡©ðï‚¡ýSBDüÏP(KX ’$I’¬"n',=ñ£ñBÁ^¼Pì„/ôK9l8RÁy˜Bê ¢BQ Úhµ˜ªª*„°ú .“É$€¦†åœ;ÇC)-//7µ×\#¼x!€×ሯ¬LP”XýÙ2DÔc¨®®FÈØ=dBˆPMÇΈôÐ6lo)"·áag„åI1ŠßICàEÂØðTU Zk°QFEQ““ãzö¼¶¶:+rq³Ù­(œsÑl68Ðÿ˜{^…‚£¿@ö>~^„ÿ d#Œ ªÔårbì+m´Ÿu™6Dà>l+°F ©ÉdjnÀç\¸@Ã#‹Åª_-‡®o×H>qiÓÅŒWßu»ð¸›LÈ-Ñé÷;¢ßUøOÿN«h€B%tEXtdate:create2017-06-06T01:31:12+01:00™Ò¡%tEXtdate:modify2017-06-06T01:31:12+01:00è¬IEND®B`‚puzzles-20170606.272beef/icons/lightup-ibase4.png0000644000175000017500000000101313115373733020327 0ustar simonsimon‰PNG  IHDRpp4ÎéxgAMA† 1è–_PLTEÿÿÿ€€€ÿÿ€€ÀÀÀKG?ïbKGDˆH oFFsÇL tIMEáõnC¢ vpAg²gÜŠøIDATXÃí×Q‚0 àÂ;Š@åâàÂ0Üÿ.²M¬º FÍß·‘~dݺˆÄܱ Œôm¸Þ?ÄîÙðóPü™SNˆáËSý;˜+UJ`S´tQu0Ì+™”Áð<¤FõLû©ø`n’7c¨‡™6&7®GhK‘V&79¹° Xµ‰M.`E]?[´%ê"xì ôÂCka7 3´Žâ™¡ ‡ìâp5²ÛÁ­*ßÌ>ò-Çtßä\¯²ÇŠ;òó¸Ì ¾sä·ÜÝø‹àlÿî‹-¼µþ°Éîp¨þ>7 `(”~殟 Cgõä%tEXtdate:create2017-06-06T01:31:23+01:00±*­G%tEXtdate:modify2017-06-06T01:31:23+01:00ÀwûIEND®B`‚puzzles-20170606.272beef/icons/lightup-ibase.png0000644000175000017500000000233113115373733020247 0ustar simonsimon‰PNG  IHDRppñ>ygAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<’PLTEæææ™™™ŸŸÿÿýý¿¿pp33 qqÀÀ¸¸00 00#……‚ÉÉÉúúú„„//"11 ººûûmm&&°°°ÿÿÿ®®®$$nnKK KK@ñññðððHH=LL (((¡¡¡ãããùùùêêê³³³DDDllüüüHH>oo KKKøøø|||%%ïïï##»»ÚÚÚŒŒŒÂÂÂBBB¬¬¬// ………ËË˼¼¼þþþ..!ÁÁÑÑÑwwwýýý oo‚‚rr‹‹‹TTT555ÇÇÇ55~~~GGGHHH èèèååå UUUäää ¯¯¯yyy44ÎÎλ»»ƒƒ€€€|ttÃÃÃÂÂþþ33 ªªª00 )))¢¢¢ìììµµµEEE""¾¾ûûûGG)+T<}–XYR—Sõ¼ÚXSût0˜Yï…«ihlâ‚Í>€–ÖtôKAPÉÉm^µ)<ð5€÷ÜÞÐ)¦ºut»yà[º¼héè}'öeéAxßÏèc¤õ<$:< 0æ€ÃtЭi?}f€‘¨pŒÖQqÐ`€qSÚJë„ø”:%8ùÅÀ¢™¢eZ|ÑÌ$ô ϷŬÜ>0/¸-Òàâ\þ·ñ¿&°ñ3˜ûp…&~´­®èÀoß¹',¯oLfonm‹Þ¹…>íYº³Kø #ß}þ«o‹½ýÄTP-õ_¾ÇŸû¿Ì‰šÖxØ[/¿wúˆÉ !Ž‚ ¡H :®\ô͉Ò}Žº¢á¿+«ÄÝGP›ÿ\³Ç¿ÀÎësgH ê~дy}DÁ$cƒDÁÛYˆ ‚"xA«?×ÎnbÇ $½Ò%tEXtdate:create2017-06-06T01:31:12+01:00™Ò¡%tEXtdate:modify2017-06-06T01:31:12+01:00è¬IEND®B`‚puzzles-20170606.272beef/icons/lightup-base.png0000644000175000017500000001163713115373720020103 0ustar simonsimon‰PNG  IHDRÓ?1bKGDÿÿÿ ½§“TIDATxœíÝLgþðg—ålj.z,V@±šRýÃ9c·‚ ×²@×Jbµb¨‰ßDrölùZjõª9‚BIÎÆ_QC9ûÇ*Ý,ÊQS!5žäÔ´jª•?Ü€'.þ@Ðî²ÌÞÓÛ¬œèÎî>3ÏÌó~ý5™ežy÷½3³?>]oo/à•^é ( ®!À5¸†×à\C€kp ®!À5¸†×àšAÒ_·´´x½^JSŸÁ`xóÍ7%ü½¤Ñ½^oLÌcgœÄY+&æ1!„êø¥¥›) .:t¨NÕÇGíãK\Z!ϸ þOêVAÚ·o/!„öøTiàø¨}|Ip\C€kpMò=€âœ=KìöØŽŽ¸ÞÞáþ~wbblJJ´ÙükQ‘{ñb¢g;ÔjŸ¿Æ¨,­­¤¢bü0®µ5q×®¿>”œœœœœ<þüO?ýKSSÓÆeo½u¯¶Öm`é§öùk•:N·^/yûíøîî.\õìÅjµvu]»~}¾ÕÏÎGvjŸ¿†©#›7Çò»ý”Ñh|á'$$47Ÿñzç•—ÿ.„}ƪªªööö[·n=~üØãñܾ}ûÔ©S6l0„úš,çüAœe[[IkëﻺìQQQAnuô¨=3ó5‹åIn®´ÝMž<¹¢¢"pÍ”)S¦L™²téÒ‚‚ŸÏ'i@™ç’°~òÉ'ãwïÞÌkg ‰'VW×——É;u¹\‡ã«¯¾Úµk×Ñ£G‡††Äõùùù‹-’4”"ó‡à±€³g‰Ï÷Òó¯›Ç²bÅ Ÿ/©³SÚVÝÝÝ“'O.,,ܸqãǼzõêÕ«Wû>}º¤ÑäŸ?HÂz¾ý6¶¸x]hÛêtº•+KìöXI[ ‚à¿È‰ŽŽž1cÆÊ•+ý^½zUÒhòÏ$a=q¹¹ËCÞÇóË/¿¬]»V\Y__ñâEIã(5ëèé–zÕ(--­§g8üi‚ðÙgŸmÚ´IꆌÌÆÂú»@÷î¹'Mšòæ&“©¿ß†?üðCiii||ü«¯¾ºvíÚ‰'VVVΛ7ïwÞ‘ô“ ¥æAb=‰‰±ýýýÉÉÉ¡m~÷î]“)Ž!©vwwwww‹Ëû÷ï¿|ù²N§+,,|ÿý÷÷íÛü8JÍ‚Äú%Pjj´Óé ys§Ó™’nÈüñG—Ë%.›ÍfIÛ²0xÖ°xñ¯ß}×òæ­­'Þx㉤M¬V«Éd \“””$. ß–—þ ë(*r;ÖÚ¶>ŸïøñÆÂB¤­ÊÊÊz{{Ïœ9óå—_ÖÔÔ8޶¶6ÿ£--ÒžÍòÏ$aýôj6“¨¨;MMMV«Uê¶6›M¯ï“øÑ-!„DGG/Y²dÉ’%£Ö>|ø›o¾‘4”"ó‡à±~ÐéHUÕà–-e>”´áƒ**þôÅCR_R[[{àÀŸ~úÉårŒŒ<~üøúõëË—//--•úE ùç’°~ „äå‘üü{«V47Ÿ òûd^¯wÕª«õAv¶äݵ´´H½Îy>™ç’¨ã奦Æm0üËbÉæuôþýûKv\ÜÅêjVÞAWûü5L0HSÓPzú?çÍK?~üøX×!>ŸÏf³ef¾6gÎ…cdž‚þö1ujŸ¿†©àHd0º:·Åòï-[ÖUV–¯ËÍ]ž––&þ¦öÖ­[mm-6[CtôÝýûsr”žîÿPûüµJ5-]J.\ìì´ÛÿºiS]OϰËå6™bSS£Íæ'õõž¬,¢Ó)=˱©}þÚ£²Bôzb6³ÙCˆÿ òÇJNH"µÏ_cÔq@ \ÓõööÿׇåÑŸåÑ•ßãWPPü&ê»í'(í€ÑvèPÒSý˜ªOÏ üÿJ‚{à\C€kÜÝ¿ê÷+Kæã<õû•%ÿñG~ƒúýÊRêøãtNê÷+MÁã¢ÅúýéééGŽq:n·»¯¯Ïápä2\g]ÁãüV¿ÿï—\¿¿¹9áÔ)ªS Q~~þ¥K—JJJ¦N“””d±XÚÚÚ¶mÛ¦ôÔžAÙãÏ{´W¿?%%¥±±166–rãÆÚÚÚŽŽñ¡;vä0ö[Å?ïÐ^ýþ²²²„„BÈÀÀÀÂ… ËËË—,YÒÕÕ%>ºuëVEg7šâÇŸ÷h¯~¿ÅbNŸ>-VtÁf³‰+³³³ããã›ÜÿPüøóÕš3gޏ|óæMÿzÿ²^¯Ÿ={¶3ƒâÇŸ÷h¬~¿ÑhôßJ>zôÈ¿>p911QîiMñãÏ{4\¿_ðëz«¿´Wüøó±~È›ÿ·~?+FFFÄå &ø×.‡óï8Å?ïÐXýþ‘‘‘+W®ˆË3fÌð¯Ÿ9s¦¸ ‚Ô>T)~üy€öê÷777‹ 999âå¾^¯/..W¶··ûÛ³@ñãÏ{´W¿¿¾¾^¬@j4Ï;·{÷îï¿ÿ>##C|´ªªJÑÙ¦øñç=þúý!lËfýþÛ·o¯Y³ÆívBfÍšU^^ž••%>´}ûööövEg7šâÇŸ÷h²~ÿ‰'222zzz†‡‡ûûûOž<¹lÙ²;w*=µÑ?þ ÝÀ)E“õû¯]»VRR¢ô,‚¢ìñgïåK ¨ß¯,?@ê÷+MÁãK ß ~¿²”:þÀSP¿_Yò`4ÔïW–ÌÇ÷À5¸Æ]Úãk <ºª¿êûÈÐÀ‚êøôR+d0!TÇB­ñÁ¸~ýzJƒ‹öî•V!ÅþTÑŸ¿WÒ+$‡ƒ¢öñ™‚{à\C€kp ®!À5¸¦Ö¨«þ=0K•PWý{`™ú ®ú÷À8æ¾ ôB£êß»\.½^þüùÌÌLBÈÖ­[Y«ü!¿”””g®—ôÅGN¨ï  ®ú÷À8•@uõïq* €êêßãT€@ª¨ŒSYTWÿ§²¨®þ=0Ne j«ŒSßçõõõâGbý{»Ý¾`Áfëß+ï÷O}guÕ¿Æ©/DUõïq껩¨þ=°L•g€HA€kp ®!À5¸†×$ó˜^ g±~_gg§Ò“ Q®BZ[Ikëﻺìþ¢…/uô¨=3ó5‹å úZ¨Neee`Q&U ÷ ä“OÆïÞ½'˜×þ@'N¬®®///aNä&ÂÏ?ÿüõ×__ºtI鹄+Üœ=K|¾—žÝ?–+Vø|Iª=yòkîܹééék×®½|ù²Òs W¸øöÛØââu¡m«ÓéV®,±ÛcÜÈìÉ“'JO!b @gg\nîò7ÏËûcGG\˜sY¸èéž>}zÈ›§¥¥õô ‡9€…€{÷Ü“&M ys“ÉÔßïs! 7‰‰±áÔã¿{÷®É„K PL¸HMv:!oît:SRðPL¸X¼ø×ï¾k yóÖÖo¼¡·@uÂ}õ-*rÿùÏ Û¶}¶>ŸïøñÆúzO˜s™•••½òÊ+„±73!äå—_®©©!„ |þùçJNN¢p`6“¨¨;MMMV«Uê¶6›M¯ï[´(Ì)€ÜÞ}÷ÝEOÿ·¥¦¦~ôÑG„;wî¨+á^ét¤ªjpË–²‡JÚðÁƒúâ‹!ü>g_^ÉÏ¿·jU¿ã y½ÞU« ¬ÖÙÙáïä–••¥Ô)S”ž4‘yù­©q ÿ²X²ƒ9Ü¿ßbÉŽ‹»X]O@a‘ €Á@šš†ÒÓÿ9o^úñãÇ}>ß3ÿÌçóÙl¶ÌÌ×æÌ¹pìØPÐßž %bïÁ ¤®Îm±ü{Ë–u••åÅÅërs—§¥¥‰¿ ¾uëV[[‹ÍÖ}wÿþÁœœHí ,þjéRráÂ`gç Ýþ×M›êzz†].·É›šm6?©¯÷de.²û]ä?…Õë‰ÙLÌf!þ7ø©—¼ Þƒ®!À5ôˆðà”Fö3 ª®ßO{þÔË£—–n–º‰$‡Õy<ã( .Ôþü¡5¾^?@idf1÷Udê÷cüçOú0®!À5æî4ý˜‚È ýXƒÈý؄ӭÐ?Y€4Ö?ý@íõO@–&û'h©?Ît…Ù?áóÏÿ¿³sÐlŽø¼Â2wî\±BúáÇ_ýõˆŸ’’òÌõ½½½ßÎti²ú@°Ð?q]èŸÀ8€.ôO`@ú'0  ý‡Ð…þ ŒÃ« ]šìŸ@»?÷ûǂХÉþ èÁBÿÆáèR§½þ èÒ ³9 ³p,ôO` +ôO`  7ôO` î€kp¹K ê÷cüçO•êû‚g0Bk|A0®_¿žÒàò8t¨Žöø*ïo mpÉ¡¾;SõãYƒþ /_Ü×à\cî] `œÆú öú ­ö7PÕé ¢áþÀ³¥§§9rÄétºÝî¾¾>‡Ã‘¹:媫¯¯±þÔp–’]~~þ±cÇbc«J›””d±X,ËöíÛwîÜþøêª¯¯½þp-%%¥±±Q|ö߸q£¶¶¶££C|hÇŽ9‘ø­ŠŠêëk²¿A Už¨Ö/++KHH „ ,\¸ÐåréõúóçÏ‹5p¶nÝÚÞÞæ.h×× Mö7„3Àh‹E\8}ú´Ëå"„‚`³ÙÄ•ÙÙÙñññaîBEõõ5Ùß 𔨨¨9sæˆË7oÞô¯÷/ëõúÙ³g+03…h¾¿ð£Ñè¿Õ{ôè‘}àrbb¢ÜÓRŽæû cÒü:]Çë/Õ5ßßxÊÀÀ€¿~Û„ üë—é÷¯:šïo€>íþ´û‚‘êñ‘Z½\ÚaTŸý„æSG3ãïÝ»—ê.<žÿMƒ£×€âõzÅ× àI;h î€kp ®!À5¸†×à\C€kp ®!À5¸†×þút³úíIEND®B`‚puzzles-20170606.272beef/icons/lightup-48d8.png0000644000175000017500000000246413115373733017662 0ustar simonsimon‰PNG  IHDR00`Ü µgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<SPLTEåååééæååêëëêÛÛçÎÎÔÉÉÝÓÓÓÊÊÊ··UÆÆLÂÂP®®q®®n¾¾O¶¶c§§{¦¦›ëëþþúú ÊÊPÑÑFââ,»»e­­šõõÉÉOíí*ÿÿÿÿÏÏ_òòÙÙ9ººióóó¶¶¶33*@@6>>4CC?²²r­­{¦¦…¦¦¦¨¨¨ÓÓ4µµžž'³³ ììððí¥¥©×׊ŠNÄÄÏêêûŠŠWÍÍ ôôÿþþþŠŠeäävvvAABÛÛÛ¦¦ÓÓ碢ÆÆÅŽŽŽ––H™™S––R››_±±››(ââóžž ÄĬ¬µžž»»šš0žž…‘‘DÀÀk333===²²{®®…uu^tt>vvA||Cmm8ŽŽ‡½½ÅÝÝêÓÓÝaaa½½½ƒƒƒ$$$ÐÐÏ)))ÿÿÿTdbKGDpØlttIMEáõnC¢ÞIDATHÇ•ViCÓ@Íì¶M,ˆØÄƒÖ“Ô)UV9z(  x¡V¤jùÿßœÙ+)$^·›L²/ofv³Ë’Ñ ÒÎ㋉ðt@t\RÁÊdsÙ\62дcwr6‰ wÎ䇆°a—ÏŸÍåGÈÂã¹QqYbä<Ðã¸]p5<÷ÂE7Â¥Ë1Ãc"‹g 8ý‘à ‹~š .%Á„t/º—Dp¸Dø?!R ØiNCœ§‹Á=mФĉOœë–Rƒ¦Äòë¡T”Vé’}åê5 ïzÉ»¡áÝ÷ Æ*Œ1ÉðË·nß!ˆþîèD„{“â0,­ŠÊ’?UáþƒAw;=3ópVfI¼Cµú@…Gçæç³ ‹1…zµQ­6*V¹™@˜]hµ­'O½±Ô^Ê „•\[àÙóH¡B'¬®ú „-Ih¿,ö+8Nu•#Œ»¯ÔøöëâÄÒ\Z#Çϯk—IhlXåÍÂâ†$Ôßzf¦+ça¥NQ¼{->™VQ¯à~ø¸µõiZ½q`‚NPÀmæ3î9¸ÁiëñÖt–Ê_:βhØM~5˜øö}{g{{gw—ú{\/ïÀ7›¯vYFãç¯f\ü·¯vrÇæzWÏð^—nŸ@àÁf4¼aÜF‚®¼rS NÐ øz·|"‚Ô\Bar‰‡öVq¹ ‚‘;NÚ½Q!ão —¶&€(4Iƒ ŠÀT=;êRMÈ%j¿y@ ìHК ¸®‘¬ÖY/yJ–Ä<`ÚÙÑ´ò”,ÙvT…ã.±Ä´b–þT‡iz9ø½/“ÍÐLËR× ¹á„s岆ò[§y px¸¿T3Ÿ+°££é,ºB²(¥Ö_ÕD‰Ðc_*b.@ôŒ1¢Oµ$Ôs˜:eÚ¤,Ò—€ å”˜y 3ÎXìæ±Ñ†RñôC%tEXtdate:create2017-06-06T01:31:23+01:00±*­G%tEXtdate:modify2017-06-06T01:31:23+01:00ÀwûIEND®B`‚puzzles-20170606.272beef/icons/lightup-48d4.png0000644000175000017500000000116513115373733017653 0ustar simonsimon‰PNG  IHDR00¥,ä´gAMA† 1è–_PLTEÿÿÿÀÀÀ€€€€€ÿÿ€D-&>bKGDˆHtIMEáõnC¢‰IDAT8Ë…TA–‚0 M@\'Œº†ÊìGÄ z‡÷ØÏÆû_a’´ÔZõM¤¶ôóÿoB  üH;ý_.‚¹Z¯ÞÙÀGíê‹ÅØ…Þw—Va”KΨŸßï<6a4䆉ý?«r¹TîÑBù:8L,æçÜc“3êwR+¥"Pô{×KÔ­Ý=ZØÎ>†K7>0ªêèh¯$"¾ï/.þûÞ½?nÚÉ~!ß¿øb³îé¹ÇQ¢—H©øÞ½-KK=Û·_‹ãLJ3!Žåóχ_´Ã] ™Þ /LmÞü_JìÂZÅl®^ÍAñ¹çþj-3'DD„‰ì×_÷}úé@ÿy÷V"@ÂP]¸pHäay5ÁZv§bf#B"@D¹|jv¤RV„]’‰°MI$f±V5$£WßÂ`6iN@$î)‘Ió"[ifS<äFl|ÄxÊì@?ú¿Ô ®î›ÖÖ©šf‰<ÇrÕN› JШZ@RQ Iä¡ ÑUIšt$ œ:»d@"ð<¥Ô@&EóXÎd~EÇÙbqS 1RK¥‚1™(j)• ‰ÍÐ0T þ[×L&óÍ7_¾ù& …^kSkk·Á—o¿ýÓ»w·Ã)Ž$f†­år~rò7NˆD\ÝâÆæUõÒÚã×V«€<Ï»ù“Of•RÆ$3=‰ˆï÷¼ÿþƒ¾¾®+®ssýCC§ÒÅÂP??*ÂD¦Ní¥"¸J­ÖDDDÆ¥”D¬»eæª' jRWo^Z²ÓÓÁââE¨»{¾¿¿ÔÙ©ÓÜ×΀1¶ú‰cm­Ä±ÖZ»_DP (‘TÖA݇ê‡PŠnܰ§N½ÚÖöC‡®¿òÊõ®®«|ðƵkIEs9Wår¹Ó§O/,,\¼xqÛ¶m¨¯|Ýõ‡¾ñÎ;Ù·ï']]ÞæÍÞK/í~÷Ý?ONþúömj€”ÈåøñãGŽéííÝ W-MMµ8ð‡BZÇîw­Màå—ÿÑG]DQÃ*Keêƒ^¹råòåËããã¾ï§%{š¹‰Ý¿ßß×× XÏ󉈞çf×®žRiÿƒ.kPm7¶=ªx4h 6ñ<0çit|* ‰‰‰½{÷OOOÇq¬”z,@.ý}ööío‡¥ªˆ©»wµÈ¿òySÇœÖÑÉ“'Ïœ9366vóæÍcÇŽa#ÛH àùço\º4@ÄX«­Õ" ÉÉs»w_cöDêyÍݸ‹ÅâÑ£G›œÀ‹/ÒgŸýnl¬ýõ×éyÀZ:wîBþvß>„!¸Þ'ÍĨ*ÝÕ£X·ç0š™›U·Móq=‘µ ŠxdäÛK—~5:ú§Bá篬ü}çο½öš¶ÆHò®£†MÃjª2¡ˆTˆÑQyšÚ¯– AnM©¡! M‹Sr9>Ú÷3¾ï‹€yµšð­u{{ûž={òùüšâj‚ ufæg_}õ c’‰IÌ6Žó<7>ÞOb-”âL†D‘5Æ2ƒ™ŠÅò3Ïüg`€£h5Ä«€¢(ÚºuëÙ³g;;;k·þ 9”Íf¯_Ÿ)•°sç³aXND$"JyÅâÊ{Ÿgæ´:!ë­g³Ù \.¹ly2­u¹\Ž¢(Žã´‘˜¹X,e³A[›”JÂI¤!"J `™]R’»HDͽ»¤B±9:S­š!¨y”•Ïkqk<Ë4³UÊݳsºw1›Çw>W(2„£µôÀt„m:Né_6²;[¸¬$ÀÀ˜ìÿ(©dªf”áâÑãZ½^«Õ'ËNYQOWEYI4kÏš­f³Õj­/º6×]-lØn»Ý±7ð ä¦g´µŽa§[Õ.ð=oêó°³gõ^ì'€ç½ívùÑ£ Á xñææ`uD”<|xiq±Q¯¿&(ED¨Žî÷}Ÿ•rÙ¸&“v?N•£jUff¾__ªÔËÙÙßfg‡óDн3˵k¿ž9sf~~~zzÚ“µ´_M¶+EÌðøñôùó¿3Ë‘#?Þ¾½ïÕ«‰¡!`FÈëÀS©T.\¸pöìÙcÇŽ>}· 3/.ÂÈÈAÆX·=6öíË—#ˆë޾[Ûã×¶Órš‚ï»"€x0—Dx@k½¼¼|óæÍ;wîÌÍÍÝ¿Dx{ï$ºR¥¥?\ÅD@-,ÌíÞýŒ¨ä†˜ÎâED"ºzõj¥R©Õj̬0g-U"}ïmlp¹ {öü23³o||Òóðùóù••ï&&àÁ Cék²µ–™ Z­æKíô…h5Dö}€ññ¨Ñ˜ªVfÞ»wþĉ<¯Sm­-—Ëccc¥R‰™1š‹øÕê—Ì_Å1öë„г³»w#ADë"«DŸG‘gÌÏãÉIËŒX¯××ÖÖÂ0 ÃÐZ›÷áûþë×ËïßÇû÷LÓ8뼈p©TœœÛì¸@VWW£(rJîe§u«Õ2Ƽ}ûÖî¼—b±†at ¢f³Y.—; Õj5‰ãxkÀpV qlîSèJR( ÓA±XÜY·#«Ã€¥ èæP$%tEXtdate:create2017-06-06T01:31:23+01:00±*­G%tEXtdate:modify2017-06-06T01:31:23+01:00ÀwûIEND®B`‚puzzles-20170606.272beef/icons/lightup-16d8.png0000644000175000017500000000204713115373733017652 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<PLTEää䨨Ü××ÜØØÛ××ÛÙÙÜåååÞÞÒææ,îîìì!ííÕÕCëë!ìì îîää,ÙÙ=ïïëë#ððÙÙNÝÝéßßÐ÷÷ÿÿÿÿáá,þþôôææ%ýýåå9ÛÛëòòüüúúûûßß-ýýóóææ'üüää;ÛÛêààÑãã.çç%ÔÔÌšš œœ™™™™¬¬:èè,ââ*åå'ÛÛ5ÒÒEêê ââêêÓÓVÝÝèÀÀÀhhÿÿ ööüüïïää%ááÏÏ€ÝÝ(áá7ÜÜìÃÃÃZZV¢¢š eeÿÿûûøøÖÖ"ââ½ÿÿÿééÕÌÌHááæYYY¢¢ž ddÿÿûûùùÐÐ%ââÌëëâÇÇOááå iiÿÿ÷÷þþññèè"êê.ââ¦èè>ää5ÜÜíÓÓÓŽŽŽŽŽ‹‹Ž¢¢‘ÛÛ¥ÕÕ£××£ÔÔ¦ZZ4EECCDD]]:ááäàààïïïõõõòòò÷÷öååñççòèèó%%&&&%ÚÚÚíí툈ˆ000ÍÍÌååâååãææã))'ÝÝÝæææÎÎβ²²ëëëÐÐÐçççèèè%%%ÞÞÞØØØéééÌÌÌ777888áááßßßÙ$ñÆbKGDZ»¥¢tIMEáõnC¢IDATÓc``dbddfb ÁÂÊÆÀÎÁÉÅÍÃËÇ/ ($,"*Æ .!)%)-#))+')/© È ®¤¬¢ª&¯.©¡)©%©­Ã  R¡R¡Qa`hdlbjfnaiemckgÏààèäìâêæîáéåíãëçÏà& ˆ‹OHLJ–LIM‹JÏÈdpÈÊÎqÉÍË/(,*.)-+g¨¨¬ª®©­«ohljnimkgèèìêîaéíëï›à2ÑeÃä)S§M™>c欙³]æ¸Ìf`˜;oþ‚…‹/^²x©Ë2—¥ ËW°­\¾jîòåËW¯Y»fÛú Ë;ÖwÁä+VLžJJRµ·…NÖ%tEXtdate:create2017-06-06T01:31:23+01:00±*­G%tEXtdate:modify2017-06-06T01:31:23+01:00ÀwûIEND®B`‚puzzles-20170606.272beef/icons/lightup-16d4.png0000644000175000017500000000053713115373733017650 0ustar simonsimon‰PNG  IHDRíÝâRgAMA† 1è–_PLTEÿÿÿÀÀÀÿÿ€€€€€€¶›’bKGDˆHtIMEáõnC¢sIDAT×;Â@ DÇ|úñJé³>ì²@@ ܧ÷¿¦°ŸFO6ÌÜ$JD.¨8¨RfüwœžÖ¢9F¾CrŹdð‚éºé+¦TSÊŒcïî·mAZæýɼù èü¾–ÝÀÎ?¤Þ+Øò}Q%tEXtdate:create2017-06-06T01:31:23+01:00±*­G%tEXtdate:modify2017-06-06T01:31:23+01:00ÀwûIEND®B`‚puzzles-20170606.272beef/icons/lightup-16d24.png0000644000175000017500000000232613115373733017730 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<¸PLTEää䨨Ü××ÜØØÜØØÜØØÛØØÜØØÜØØÜØØÛØØÛØØÜØØÜ××ÛÙÙÜåååÞÞÒææ,îîìì!ííÕÕCëë!ìì îîää,ÙÙ=ïïëë#ððÙÙNÝÝéßßÐ÷÷ÿÿÿÿáá,þþÿÿôôææ%ýýåå9ÛÛëßßÐòòüüúúûûßß-ýýýýóóææ'üüää;ÛÛêààÑ÷÷ÿÿãã.þþÿÿôôçç%ýýåå9ÛÛëÔÔÌšš œœ™™™™¬¬:èè,ââ*åå'ÛÛ5ÒÒEêê ââêêÓÓVÝÝèÀÀÀhhÿÿ ööüüïïää%ááÏÏ€ÝÝ(áá7ÜÜìÃÃÃZZV¢¢š eeÿÿûûøøÖÖ"ââ½ÿÿÿééÕÌÌHááæÃÃÃYYY¢¢ž ddÿÿûûùùÐÐ%ââÌëëâÇÇOááåÀÀÀ iiÿÿ÷÷þþññèè"êê.ââ¦èè>ää5ÜÜíÓÓÓŽŽŽŽŽ‹‹Ž¢¢‘ÛÛ¥ÕÕ£××£ÔÔ¦ZZ4EECCDD]]:ááäàààïïïõõõòòò÷÷ö××Ûååñççòèèóççò%%&&&%äääÚÚÚíí툈ˆ000íííÍÍÌååâååãææãååã))'))'äääÝÝÝæææÎÎβ²²ëëëÐÐÐççççççèèèççç%%%%%%äääÞÞÞØØØåååéééÞÞÞÌÌÌÝÝÝÞÞÞÞÞÞÞÞÞ777888äääåååáááßßßÞÞÞàààáááààààààààààààÚÚÚØØØØØØØØØÚÚÚæææÂ(bKGDn"QtIMEáõnC¢IDATÓïþ  !"#"$%&"'(")"*+,-./0123"45"6"789:";"<=>"?@"A"BCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdXefghij"klmnopqrXstuvwx"yz{n|}~€‚Xƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨X©Xª«¬­®¯°±²³´µ¶X·X¸¹º»¼½¾¿ÀÁÂÃÄXÅXÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæç¼ànÿ?ü&%tEXtdate:create2017-06-06T01:31:23+01:00±*­G%tEXtdate:modify2017-06-06T01:31:23+01:00ÀwûIEND®B`‚puzzles-20170606.272beef/icons/keen-web.png0000644000175000017500000003061013115373720017204 0ustar simonsimon‰PNG  IHDR––³cæµgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEá  ŠN0ŒIDATxÚí}y|TEÖö©»õžtö„„B ‘U`DeP…a1 Žàø¹!.8,qwØD_D`@aPGQqxà ˆ²‡=ì[HH Y{½Ý}—ªïj›@š$Ý·%ðÏüH:}î©:U§NÝzNTVV7q#ƒinnB+¸º?BTUmn•n¢! „X–­û›K&$„èõz³ÙŒ1nn=o"8BŠ¢Øív„Pà—~Rû8qbË–-f³9‚O%„B&’[Q”úƒQ£’Š¢°,A=UU%„p§]BÈãñ$$$ 8P–倹ÀóŒFãîÝ»óòò8ŽS%R¾‰HaŒqÇŽ‡*IÒ•&ôÿÀqðôÓO÷êÕ !d4†q:.—‹aBHH$„ †'Nœ8qbäÈ‘v»]ûgÆçóM˜0!;;ûå—_–$ÉjµBl6›¢(V«U§ÓQN'Bˆ¶c|µGcŒÍfóž={æÎ;vìØAƒ±,+ÆX–e»Ýj«@UU«ÕºpáÂ-[¶Ì™3'))I¯×ët:—Ë%Š"B(::Z§ÓÙív¯×ÛÄŽ¥myæ™gèÿ/³Zý¿îիרQ£–-[vàÀQýôÓ±±±£G>zôh~~>˲?üpbbâòåË÷îÝ+Šâ AƒFEÍ@ןÏtWUÕl6›L¦¹sçöèÑcäÈ‘o¾ù¦ËåÒét¹¹¹Ô]#„TUm¢ëVÅb±¬Y³fË–-úÓŸÒÓÓ?ûì³ÂÂÂ{ï½·wïÞ²,¯\¹rß¾}¹¹¹;w¦FeYVUÕÀ˜ jBxá…$Iºâ£ }êt:=ÏìÙ³[¶lÙ¶mÛêêêêêꘘ˜>ø@Q”gŸ}öÂ… M8„I’ìv»ÛíE±ªªJûÂÀqœËåY–%I***Z·nÝþýû»víj0fÍš•ššš••U[[[QQ±hÑ¢‡zˆeÙåË—3F§ÓÕ·¢ªªc‡Ã.—«ººúÂ… ^¯wݺumÚ´]V½^/Øl6†aöîÝûÏþÓápÜyç3gÎüàƒ:wî¼lÙ²uëÖµoß¾¨¨hÁ‚3fÌÀ»Ýî ó2àN‚ôIý_1 Ãqœ -Z´ÈÊʪ©©ùþûï7lØ ªj|||§N’’’ꮨA1æ8Ža*B‹ý!,ËR!,Ëú|¾{î¹ÇjµŽ=šçyê©Îz½¾¢¢â•W^á8Îd2Y,Y–ë+€¢JÒÍfóûï¿ïr¹~úé§'Ÿ|V¬Xñý÷ßWTT´lÙ²C‡iii6œ5ú7„˜˜˜·ß~»°°NµuëÖ 0`þüùéééÛ·ow:7nܱcÇòåËsrrn½õÖºëÜ& Šà.QQ”wÞygþüùGŽ™½oß¾ŠŠ Y–õz=Bhüøñýúõ6lØÓO?-Ër£ cŒA(//_¶lÙŸÿüg“ÉýücĈ½zõúè£rrr<OH gF’¤U«V•””lß¾½°°°OŸ>›6mzã7DQ¼í¶Û&L˜0}úôŒŒŒ%K–俿ТjÇñl„NwñâÅü±S§N'NTUµ¶¶6==]UU›Í†1Žàž,lêtºâââƒõéÓ§   W¯Þ555óçÏïܹóĉ}>ßÝwß=`À@–eÖ¬YC½h£œã¸¢¢¢®]»>ø`.Ãm6[rr2ýOÓ#šº&”eyýúõ999²,¯]»6//OUÕíÛ·ÏŸ?¿}ûöpÛm·Ñ€±QD砽òììÙ³ilír¹dYVeذa Šb³ÛX–E±wïÞ¤­v:]wÞÙ‡ã8ª³¢(¹¹#Ýn7!ꃎp¹ÄFíÇ0Œ×ëíÖ­Û¿ÿý•ÃáÀXaYÖíï½·?ð¢(rèaB )úÏÅ‹ÓÕÑëõz<žwÞy‡ã8Çãv»B©©©yyyn·;¼®_Bjjj¨©†¡CCEúc³Ø¬¾†!I’ªªª…‚t:FQ¼² ùu®ªr"Ä „ª«<Ï4a|„¢ÈÕÕUªÊ2 `äñøË2ª ŠTÃ@G2!¤¶¶–þŸ*VSSCßXÑÎTUÕáp„=1®"2 s…ÐëÄxuºXmÝÊîß„@r2ôëÇ&'ƒ¢Ë‚Û _}ÅTV!`42= @ |uˆeÁá@ßÏUUBй3ôé ƒAgÏ·ßÆàóAVŒÑTUÖ¢¸¢c5¾,ŒØ¼k„cHN†#Àí†/¿‹FŽIòÏQ„ž=!'<0›AU¡Ñ‰È0àóARôí ÂÆ–·Ü¢=Å:tº¦NÁk€Ø„íÛƒÇ%%­[_f'Œáøq¨­…œÐë¡Ñc4„@–!1Z¶“ $ vîB îú'ŠPP±±ð»ßË^ò«ÍˆëË7†Ÿ>ÿ–/Žƒ„ÀøRŸæä@v6ÔÖ—_BQB#ýTU(+ƒµk!;Z·Ÿ0ƒºuƒ”8v V¬·ûº˜‹7¼ øË_à¹ç@–á§ŸüöÃŒF4FŒ€¡CAàÂ…ÆE!„€ €Ý+V€Õ cÆ€^ïŠéé0läæBß¾`³Au5°l“âÒß7°#¥Ýºa¤¦‚ÇøÍpþ<:mÛÂÉ“àõBBBã Ž‡¾üìvèÖ †ädHJYƒ À톔8p ˆŽnÜ9_ÜÀ&$Xjkáða@Ú·‡»îú˜ÎB‡Ö®–…{ï…ìl¤FÖ-B€aÀéEèhر\.¸ï>HMIŒÁl†ÂB(,‹† èèëb-¼MÁˆþ©@}šªÀªBL Œ}é#ºÂ5 †Y†¤$?ÞÅP×êóË‚,CNääøý*Ã\öƒÝ„àÈ2\Ž¢Ó†·ƒAAÿþ «lFÇÊõ`?ø?`Âêwhà7‘êëºr®ûÁÿˆô&nšð†ÇMÞð¸iÂ7MxÃ#HDŠ1VE{r¥HSŠ˜¢(ÚéÅôÌ6 cLùdZdR!T2!ÿ í2:Sùe6ÀO b¨¨(‹ÅB©]ZžJ©À111&“Éh4&$$D„„èt:€eY“É$˲F å‘FÐëõƒ!**J£žŠ¢èõzJ»5›ÍT ÆÓVj¿ B.ӕμٳgüñÇA©p¡‚ã¸šššššš;wú|>í)k œNçæÍ›‡Æ®ÁGEE9rNŸ>½mÛ¶]!l¨ªwñâEصk%¦jl;…>Ÿ¯~{¯LN€Ã‡8p@Ëó꣸¸8R¢hìvûæÍ›=Æ®¡®âرcTÉŸ~ú‰²ž´È¤$j½{÷7…zÚ0¨ ƒÊ ’S1wîÜ‘#GÒIC9ttF†‘Sa±XvìØQPP——WQQ¡7ÅqœÛíîÒ¥KFFÆ«¯¾êñx´ÏƒÁðŸÿügÅŠƒ?~¼(ŠÚ©Ñh,**:tèÐĉ333µ{ úõùóç×Q‚èj±Xbcc}ôÑcÇŽ%''¿öÚkWð'XZë‚ú¨¨¨(£Ñ§(ŠöÅ•ÒÌÀçó9Žêêj2UU¥ô$‡Ãáv»+**´›0))Éãñ@ee¥Ùl•}Z¡òUUu»ÝmÛ¶ÍÍÍýë_ÿ:sæÌ/¾ø"ÀE‰¢H3ü~*ÆX’$”Ò©¬1*£q,ËT žç)_c×pG…P†µöĨCÈç8Žçù¦‘ÕóªÏ ÚS<ÏçååUVVz½Þ®]»º\®~øAUU†aEéÖ­[bbb£þ½îdE¿"àŒ¯øj]'Ý€Ôúà ï^÷Ã&Ê ÖWýbØ2;\•ͽwïÞ§žzjìØ±¯½öÚÁƒ7lØàv»)5==½E‹a„¬ ã'°`ì? @€ãü) 4qºÒú _DCßçk*C!Ðëý'…WèÉ0ÀóþsDU…zib̓à™M^¯wĈ••• ûÛß&MšôþûïSW€¢Ùk¡z†ÚZزjj 5î»ïÒ1ÃÀ®]pø0@«Vг'èõ÷8=µß³B =zö£0–Q„ü|¨ªUƒ†ØØFi驽Ç›7Ci)Üz+Ür ` „ÏÃùóðã I IЪÜ{os[ïj&BÈäÉ“1&ÕÕ5mÛ¶U¥¶¶–¨ÁÖ#zxÝôyÈ0 ŠÀ0`³ù €’k33ÁãM›î»ÜnhxP©Ï­Z$ÁæÍ ªpÿýàrËÆðóÏв%¤§ƒ× <ߤ1Áq`³ÁŋЮœ< +W¸qк5x<À0àvCi)ôî , Fcs›îW\u-|ì±Ç žeYYöUW_FøŒCp&Š))0|8|ôQÖPïÞ`±Àùópð  Muz„Àw€Ù eepð  ÒQE¹tödfBttãÜ™tÔ(ˆ…ÔTøðCp:/$†ñË´Z¡mÛë…GzÕYXUUe·³µµÀ0¨uk60ŠΞŸÌfhÑ¿l4’Aß•J,X%%˜íÛ7•*A;}ñb8wââ C‡K}Š1$$€Û 6!0f ¤¦6"–6!`Y°Ù`çNHN†Œ ¿í©›ML„sç`ófhÕ Fò/ÃÍ‹à&dPvãF®¤0†gžØXÿÂ.pð üô€Ç=z@¿~! F–õÿeݽB`0@ÿþPQë×ÃöípÿýÐÄ·âôë••°~=lÛC‡úíg2ÁÈ‘ §OÃÒ¥PT-[6.®¯ª ß~ /˜1í§Ë2´n YY`±Àºu°iTT@zzã“û·FðՆޏûï‡Þ½çýÞ~¥n¶jÏ<û$$ÀáרÆàrÆ€18þè‘Τ#G 6RR@UÁélÒЦaááÃ`µB‹€18þœ1Žƒš8z.^„ÒRå&-]´Õ’«VAQÜ{/°,Øíþæsœ9EEðË/P^,ëg 7;®æHýüöcÇ®\·Tââ ¸Μ¯~ÿ{à¸&Q49ÊÊà‹/üÞüùðàƒ‘áŸmÛ·Ãþ„@|<ôêÕ$R§WPàÿ¢Õ }ú\²®¢À¶m°q#HtéíÛ7>­éÂYY ǃNß}v;<ðÜ~;ˆ¢ß»nÛæï¾}!>þºà±]õ5åOÒvÅXC~ùNžŸª«›Ô :c`ìØK<¾šãࡇÀí„Àbƒ¡©k!ÃÀ¨Q@s+_ ÐAÇóG§V«Ÿ\Ú”p&!žzÊ?› ‹ÅŸ*åóA÷îЮx½ ×ƒÕz]P¹¡"f3ètþÿ‚#¢wß ƒÁ²e°gôì KãD·á))—~£(—f›Ñ‹ÿ—M§}Ð ÇTõ²/>"¥©ãŒNĤ¤K¿TÕK#˜»˜ÿ–¿ÙçEpÒ™·z5;’_ ·Þ ÙÙþÔ‚õ롦L&8u 22. åíñº›º_QÕKƒºé]C'÷Õ¾ø(¤ýkJBæñub?h˜ ìõBR´n vû¥˜SU!+ NœE>} sg×Ä&]íÏÂ7 ×Ìß …3<àŸŽ, ’t)¶ÎΆNÀÿž°ééMüh(œq¹.ýðEùÍyÅïo¢¹Ð#½Ú+Ê›f»®p“GzÃ㦠oxÜ4á ›&¼áqÕæÀ¿ZPW½g]»Æ!äWh”V_`e^'^ð<àuii e˜EêJY¡Ì3íJR&\€ÁF®]Ožç÷«ÑK¯)ƒÍçóÑ+Õ5¶„Þâ-Š¢×ëu:”=¥E å‘Ò !.—Ëívk§ ‚@9Ÿ´áÚõTÅétR²d|||bbbP"}H §Ô½ B­Ù¤(JBBÂâÅ‹'NœÙ"”¹«(Êg“çž{.!!A;!†yã7²³³ œNgÀœ— 7ú˜víÚÅÅÅÏ󊢄Cáðáõµµ=zô8gʦ—ˆSnjÓ+(P‚dII‰Éd²Z­jÇUUU?~<333--ªMž@*áĉíÛ·OMM!Ÿúüúu™ ©Szùå—G}áÂ…ÚÚÚ˜˜˜”””ð4 wý0`ݺuùùù±±±%%%n·;--Íb±Ð2 ’$Ñûµ›"S–娨¨Y³fuëÖ­ÿþô>y-]C•ÌÏÏ2dÈĉ'L˜pþüùêêj«ÕÚ²eKù ¶kÓ@•|ä‘G>ýôÓ¾}ûfee…q]s]iÐKþƒ8}·Ûm³Ù† VQQáp8fΜ9bĈºi`KfíšUgÓ¦M?þ8!Äd2}üñÇ™™™ã·ÞzkÀ€:th¢1Eáy^E‡Ãa·Ûµ—/Q…B‹Ð,//ïĉçÎ{òÉ''OžL«„ÔpY–yž÷ù|àp8l6›FBEX–>}z¯^½î¹çžüüüqãÆQ7H‡ƒÛínŠs§DÓ?SU5##ã믿¶Z­ÙÙÙ‡ÎÎζÙlEEE555M¯—D#š@ᄈTY äoR'ôâ‹/–——O:õäÉ“ƒÆçô_·ÛÝ”e¥nÙ:ÐnÂàú_Mƒ¾}û~óÍ7%%%/¿üriiéüùó}>­1vìØ[n¹%$B·,ËÉÉÉF£ñÅ_ìØ±ã Aƒ¾þúë¥K—vëÖmÉ’%+W®œ5kVùo‘Ýñ<¿páÂ’’’§Ÿ~ºººzÞ¼yN§“NýQ£FuïÞ]û”Š,‚›P¯×ÏŸ?ÿõ×_Ÿ={v¯^½***ÚµkG#cY–M&S¨IîÔ£Ž?~Ïž=Ÿ~ú)ÏówÞyçm·Ý6eʔѣG÷éÓ§Ùí,Ë:N¯×ûÕW_=ôÐC~øá<••år¹¨c´X,Ú³û#Ž &dYÖår½þúëã™3gnÙ²åý÷ß7n\ §Âáp„¦šÍæ‚‚‚/¾ø"33säÈ‘S§N;v¬,Ë·ß~{vvvbb¢ÝaÇÄïè4)±‰ „ Ts¤bɲüâ‹/ÖÔÔ¸Ýîgžy&**j̘1— N§ÓãõFƒ®‹¹|r÷ã?bŒ½^¯Åbñù|¢(Ò…°®£o:Ünw÷îÝ÷ïßOßV$$$¸ÝnUU_zé%§Ói³ÛtœŽgxÚ)–|ªE¸q—³¼ŽÕ€¬Ê>ìkÀŠôê„Å‹»\.«Õš˜˜(Š"-Ch¸žÓó  ÅCGó"¸ B)))´òít/A0Æz½>===3Nw„ سM²]ô\ô(H6&§™Ò\²KËáWûUz*výŒ%“[[(D¹š©âââRSSE¡wŽ‚ OE…§Â‡}âÚYÛñˆov+^õM’Ïç ¤uGĭѤߺI£€Xdá-KO,wd^©«TõªŒÀ$[’Ÿºå©§Û?-a©a××1>Õ7nÓ¸=¿ìžïñüŒÛgÔøjžß´^^ÐV¿ºçÕÏ‹>½"!ÄÀvÜdH’±¶’ÁU½9ªƒˆ< ]G"p¾Ò}ç+Ï÷iÑçþìû­zk™½ìÕ¯~ûó·Þ¢’0ù¶˜`3ož{hîž²=zƒø¦ÖÙ¨ßj®9œhLìšÜXàøëåÐf^ÄxdOÿ6ý¿öÝW÷|µüîå ï\¨ÓéÁÖ²­ 8½†¡5ŠÚR¾åüO¿ÖýRM© áM]ùBKîZ²gèžÑY£!œ—6¿Y6óããQ=C2†Ü‘t‡Œe¯âíßÝÈA…X]lx Â3¼]¶ÿuÇ_ã ñoõx‹c¸ˆ,X úgÕëÉ€ÍnB@€ÜŠÛ)9BÎ0ïȼZWm”9jhæP‡ãE1Á&ÎôváÛ'~91óŽ™­-­EE4KB‹ª’*©DmÖ…/šß„@€èXŽÑMÝ=uá…FÁ8¯Ï¼.±]ÜŠ;Ô½&ØÂ[~*ûiÁÁwyxl»±–8ÄÏðzV¯EÏëmSOÑük2&ØÈEE|nÇsßû&1:qÁ] ¦ ´I¶0)&ØÀöVí¶•okÿïö VJÝ¥`€EÇ\,øàÎâ ñá…‘äÒ{€Á‚@óÎËf6!]·JÝ¥ã·ßöó¶V‰­>¸óƒÛo¯òUÑ©0`#g”¹Ëè¶„aÆåsýìúY%*^¿ Œ`äŒ<ÃÓõ¬ÞÀÜŠ»y_ 6³ 1ÁfÁ<¥`ʶsÛX«cusÎq+nŸê»+宼®y¡N–a’cpúà®q]9†cãQ™4ç;¶æw¤WñbÀõ{!RCÛ-»©SÕØÑ¢"^ñ›ˆˆÕˆæ7!Ðb¶ðsŒÔP¸N¯Ôª¹¸ ­¸F³PUUz·¬ÆT­"@jÜ“Ñê ”ÖìÌðüÈ7âÙ!111qqqÚoÝWÅ`0ƨ¨¨èèhí 6EQhQ‡€Î²a£®„€@-2<Ò Ÿ1!Ïó:N§ÓiL-`YV§ÓÑSïï¾ûÎb±h祫ªsèÐ!§Ó)Š¢ÛíÖ^jÄb±P…õz½^¯×Øp†a A¯×Óô-2ý'äÁ{™®ÔŸ,_¾|×®]ÚoÇ †ãÇ%k‘ö›‚¶ôÿ÷‹‹‹#Òp£Ñ¸gϘ1cFTTTS®2o”Õ²Þm€—™ª>|øðÜÜÜêêj|šjsòäÉ’’’7ß|Óh4J’Íó¼ÍfSUÕjµ ‚`³ÙÙ ÃPN ¥±Ô»†›P2ãË/¿Ü¦M›çž{NUÕ¨¨(JÇ&†¡TÁ B®€ªª&“éСCK—.4hгÏ>©ò+++OŸ>ýüóÏ·nÝZ{= úõ+VÔO# îH ƒvB×-:,žxâ‰ØØXŽãÖ¯__RRòä“OšL¦U«V•”” >¼eË–tµ$É`0И¥¾@JÕu:Ó¦MKIIyöÙg:´eˆaþô§?¥§§Sƒy½^ƒÁ@ãF•TUÕh4®^½zéÒ¥:Î`0  —eÙ`0Ð @=3|a ¬…;ÒÀ"X}ŠÎŒ‹/ †­[·<8&&¦W¯^+V¬X¸paZZÚ¢E‹~øá‡M›6%%%õíÛwñâÅ:uÊÊʪŸ‹S7¿ÐëõÀòåË ª««çÌ™³uëÖ;w ‚0xðà>ú(##£S§NVÚ¡u*l6[@aí ¯E¤æV@lÐÅèí CmmígŸ}6yòäÔÔT£Ñ¸jÕªGydõêÕçÏŸß·oBhúôéï¼óÎgŸ}f4ë&×лúüñÍ›7?ÿüóçÏŸ§ýõöÛo¿ûî»K–,ÑëõuëN4Œ@ ŽkÓ‘Å5ÚÆ%K–=zÔ`0œ9sæÛo¿¥L§Ó ‚P^^þÄOL›6mãÆ;v,//oØ›Q‚kRRR~~þœ9s>ÿüs“ÉôàƒžŸ|òÉÑ£G_{íµ·ÞzëèÑ£týh@ e^õÕWC† éÞ½;M‡X¹rå† Þ|óÍ÷Þ{¯  À`0\Ïap¤p©×ë>|øØ±c7nÜøÞ{ï=öØcµµµ/½ôR~~þ»ï¾Û:³uÁž‚)ySúõëŸïö¸UP){ój©mN:•]ZZ:gΜ¥K— ‚0iÒ¤!C†¤¦¦J²D œî2ˆ‰àN…(TŽáš÷7\3Ò{ª««;vìøùçŸ;θ¸¸O?ý!$É’»Öý—Ü¿`KÕÒ„ÿ7Aõ©ª¬:°£³!ŽãDQœ2eÊ«¯¾J÷!.—+55!D£\¢Fe,F ƒL°GñˆŠ+ ñºxŽáÀ&ÙšÍ}LH£jžç1ƇƒeYEQl6å®9‹¦NgÃ1œ?û ÁÈÌ‘™–LŸhBÿ£UÏëOÚN¾·÷= @YÒ 0pç¸Îí­í=ª§s(š\W¸ßÞ†o~²ü$ƒŒ1ðÀ虩]¦Nê2É«„_ÐS!JŒóÉ©O¦þ4•eXUQÿò‡¬¨¬«³kƒæ?µzV´Žn=¾ÃxBˆŒe·ânÕΫz™Ð.„¬Ê’"ÝÓæžû3î·KöEÇ•;ËçÎé—ÖïÖ¸[=Š' Š 6²Æ“ö“¯ïyÝl2+Œ¢Ê*Ëü†ÇœMÄusSî&¸\,1Çš3¶ÝXo ““Bþu÷¿:Æv o± Öç7?¯°ÊiûéÛnA Y&Ä fÚîiNÉ9¹Ûäf¾.Χ®"± ülûùÝ‚wA„'óŽÌûòž/3-™^Õª)7µ}L{·ì–°¤ctÕ$d[³Ã‹>T¢ÆèbþyâŸßŸøþ»Þè™ÔËÀ€ÉÉÍ…æ?µ§dµÜ[r?¼ûÃ?ðï?wý3#0g*ϼwè½°È@ n¢>qó/›ß)|0<šóh—Ø.^%ä1AâGkŽNÛ5­gfOÊn¥ÃÀÀô¬¾y³D›Ÿ„èQ<·'Þþ‡ Á¾-úž°Ø}a÷ŽŠÕÃ"6ìŠÕÅ~}îë¶¼Pí¬~¨ÓC¯wÝ«zÈiØüî¡w]>×c9¶Ÿ.rQ9Eö¢tsº…·4c6¿# láe,«X5ñ&«`+„°cõh!zѱE/¼$«òÔ^S_éúŠŒeŸê ÛïužžÚô”ª¨ÀðÀ füúñ÷·»ÿã{>ÖèjDsçT¢çô3ÌÔ³ú!­†XxË¿Ïþ{[ù6èÓYÏé}ª/Ô¥‹¢cu?ð÷ÙûgÀ¸öãF´±§rŠÕTSjŒ.ÆŸVÑd @*Q»Åwóª^gbc“lÇj@›ä6ã;b‚›qsßÜ9€y–?S}æë#_ÏM˜Ë0ŒKt•D™¢&tšÀÓè™í 0NÙù¯#ÿXž]yfå§§>E)Š2ûŽÙãÛ5gŠAŒ¨ˆ¯t{Œ[xËÆ s׿b„ßéùÎ])wEê½OxhþµÐ«xŸìòdŒ%foåÞJOeË„–]ã»>žóxxù…éÕ2¦% 0‚„¥h!òª^#k {eeË2,&˜E¬™7'[“ ojö#ªæßÚËXî‘Ø£gbOË4W`Lpö£ Žtõ}«ý¨ÓŘ`—ì /ÿ¦Öw+î®ñ]?*Q›w B³›h¢¶ì†_og"@$UÍÔéKWeD(à¿bù Èÿo9©hu­ÙÛ»þÐü[û›Ðˆ›&¼áÄ‘R ök¯©@É‹H1ü‹:TH¤N«P™Š¢h/r2!ßjµZ,JÿÒÒEQ(Á ŒF£Ñhä8NË:Gsi×°,k4EQÔ¨$¥ëõzˆŠŠ2™LIIIi¸Á`€„„„ÄÄD¯×B~P!—éJïÍ[¸páš5ke`6 z5maa!9r$&&FcN…ÿD^ÀårÚl6íu*¬Vkqq1|òÉ'»víŠHà Ö-[`âĉf³YÕ\¹™ÎB‡Ã‘––vÅG—™ð;vÐÇG ,Ëæçç›L&Éi”½Ao­¯ªªúòË/#›ø±wïÞÝ»wG°áŸŸ)Q´¥õ B\fBê@fΜ9dÈÚÚZíÌfóÎ;÷íÛ·`Áz¥µöYèr¹,X™™9kÖ¬ˆTv1™Lùùùùùùyyy>ú¨$I´<Š(ŠáUw ³ðرck×®}饗jjj4ö$üêHï¼óÎúž,Hû³²²ªªª´ü‰ŠŠºpáÂÙ³g½^oyy9ÏóZÖ%äK’äp8´÷ŽªªªªÒ"±±±mÚ´™JQʇ{øá‡çÎ;iÒ¤Õ«Wï !äóùhšYÃa0ý”6Üãñh¹à×Ñô¹\п¦Oû2£Ñs^cPU_yåA,XЦMUU÷îÝK‡ ¢(YYYñññîèš(”¥½H„Z§â¿cžçKJJÆßµk×E‹={öË/¿¬©©ÁétN˜0!555"5´"ˆ›&¼:irss ‡úæ›o>óÌ3óæÍ $I{½^íU¢"ŽMH€`rå5?‘:m©ËŠÐ(ó =-RA!ËòðáÃl³ÙbbbÀårù‹üZìâÒë!Í÷ùoǼMT5€ÐLH€pˆ3ðþŒ!J{!@ÜŠ[û™ &XÏêy†§½ïU½ZºFÇèV †ÒóÞFoú¦³mâĉ´®¨$Iukn!@ÎÀ :Û2¢,½·ª‰`«çôpù‰UST­‹LHíWã«YurÕîŠÝggBæŒÜ6¹ýÓú{U¯+ªD¢×œ_óæ¾7¢tŒé¸èÎE¡’\zò ´öèʳ+TpH‡ì˜ÕcÖ€ôÉÑèyo ×>;¨—ðɱO6ÿ²¹ÜSNI1¦ôOëÿ`æƒ ÃÔwKlà û«öO.˜L©­ôwI•¦ß6½Z‡Ü¸ª!›lŒëϯÏû>µ°˜ÇD"…¤pUñªwû¼ûxÎãvÉæ8Á:FWê.Í+È;W}tD†¿ é©ý™Õó æ³a¤x›¯©|™úµ| !#\ð^˜µw–M²1ƒ%|Z[´ö¸íøœÛç8eg‹X§ì<\qXÅ*bƒl“l!ñüC0!Dá9þ¾Î÷=žóxkKë;_ÙóJ«fùÉå#3GòˆÛ«è8Ý[;Þ*q–´KjwªêLJŸ·GÇò]-ïj×ÎÌ›ŸØò„Kqi‰AB Q¢ø¨é½¦·2·J0$”‹åSwO=^q|ó…Í]*h=™v@x†WY5=:}AïÀ3<˰©ÆÔ2B0!½;ôޤ;ú¥öÓ±:—âzò–'ל_óý;/özNÐ…ÁÒ¤.tÕÙUŸùü…/ˆŠxªìTØÝ „¥^I½¢„¨½{U¢-„kJBŒ¢Ç¶KcdCrŒDë£Í¼9ln*!„C\…X1u×T…(m£Û>–ýXjBª[áJ¤ÓVða_•·J`„¶'m'C÷øîÉÆä0Òì(×ý‚ûÂä“ÓbÓ&w™LS ?8ÜN±Æ[ãÃaÞhZ*Q²srÁäŽ+;öú¶×޲٩ٳ{Φd­ð®¾•±LT¢çõ½‹kŠ¿;ýÝðµÃW¯iX„ì^!*V­‚µÊ[õì¶g‹/·Om?ùÖÉ’*…—H¯îyµÂWñÙ?kÓ‚®X<Ã'“t¬.l+2Àp †J €c¸rOù™Ú3åb9°ˆuHŽðDÑk†[˜Z,¼ká†v Ýõq¿c¢b€À’cKœŠ³éQEÈ-T‰jÕYOÙOX?âÇÓ?vIíòIßOZ[„‘&I§`±£x噕·ÄÞ²ý—íÓ ¦ª9<ü"þò÷ý/² ¬ž$@T¢bðeB&š²`¼ªwîs‹Ço¼ñö”Û•{aë åb¹À¡5êí³£³ÇdiiniäŒ#2GôO늜E¢,2ˆibÃCÛÒZVÛË·?¶ù±2[ÙŽCõY§sËnŽáÂè ȇ} ÂñòãÓÎO`ÐC™£ìõ_O˜Ô1¶£Wõ†èÒH!Š2q&ú³žÕ[‹Gñ„]J!J”Å£%3.³_i¿]¥».x/;ŠÓLi>ì õV\±gg“ IQB”JTI•*=•€@`…Ú⦂3î¯ÚŸ»1×áu¤Æ¤Þ–pÛŠânÅ%D l9ÐÌ›C ÌB2‘ãõñ“ºM¢MÒ±ºÿœÿÏþòýiÑicºé×9ŒD_„Gü9×¹SöSåb9<¨>`(6Xk·øn¡®Ùtà~zúÓu%ë§ŽÑÅœ¶Ÿ^vbÄóñ©¦Ô0‚•¨Þ²ðèÂÝ•»ŸÈy"Á°á†-¿lîJ¾+ZÝôd’жö<ËŸ©9ã¨r°F¶´¦ôåŸ^F€&V³µÇ°1º˜®üC€¬Äêb_éö mU´.úœíÜþ“ûâ¦u›&Ê¢„C¾Â¬ô~Þ0mã4ÖÀªŒ ÷,œ'ÎÖqØg>óx<ô¾Š¦7œAŒCr¬9±fí©µcšÇª3è¦t›Ò&ªKv…ñ:¾î9RrdbÙD«H—Ô.y]óè›·&6<´}¡¤J­cZî>ÚÀ0Á bB*V£…h+o £„íq§ì¤o ¢ôHéáìîìÛF aFzªÜ!¡Ãè£MœI! àέ¸{&öô©¾P»›¦ÅŒÈÑÂÔâxíq›dã—fN»»ÅÝ9Öœðè¾~RçI¿OùýªÕÞj:Ät˜>ÐÌ™CÊmm_èU½·Æßú¯”¶ðòŒ6Éö2ãWŒåGÚ=òTû§|ªÏ.ÙÃÐó÷É¿ÔrP]=i<âa¤Ú`‚­‚uxëá|žA PˆâQ<áÍ? ÄÀîM»÷Œè«WË.Åjnzhá äS|erY]SQ+Fä$È.Ùk}µ¡°k6Á¯ûB§ì¼BO1aWyVˆb—ìÈ!Ä€Ö¥hšN`g‚ ã–ª» !Ä#M˜†Á"6"µ´#{c @,b#ž£]Ïëëôò&ÂÀ lBíl|¸¼°AÄ/‘‰ˆ†Ê NŠH-m àhEJÉ6ç5r¿b½e%tEXtdate:create2017-06-06T01:31:22+01:00]¦ó%tEXtdate:modify2017-06-06T01:31:22+01:00fOIEND®B`‚puzzles-20170606.272beef/icons/keen-ibase.png0000644000175000017500000000320513115373732017515 0ustar simonsimon‰PNG  IHDR``ÕF‡ gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<”PLTEæææãããZZZ$$$ AAA½½½ßßß)))OOOÞÞÞ333&&&®®®ÃÃø¸¸ÓÓÓÑÑÑÉÉÉÏÏÏÒÒÒ(((¬¬¬………<<<222|||ddd ²²²žžž¯¯¯•••555ÛÛÛÐÝÐŽÃŽX­X//‘Œ–K¨KœÈœåæåÜâÜŠŠ:¡:ØáØÛáÛA¤A<¢<ƒ¿ƒªÎª Ê [®[‹¸Ô¸F¦FÁ×Áwºw„¿„ÍÜÍ|»|ÊÛÊŸÊŸo¶o’àäà¡Ê¡—Ç—’Ä’Œv¹vyºyâäâZ®ZÃB¤B ¤Ì¤ÏÝÏ-œ-“•`±`}¼}§Í§Y­Y¡¡¡hhh\\\888RRR"""???ØØØššš›››äääEEEVVVÊÊÊzzzªªªlll‹‹‹³³³aaaiiiNNNwwwuuuƒƒƒjjjÆÆÆpppŒŒŒsss999mmm```~~~@@@DDDeee”””}}}...:::yyy™™™QQQ^^^ŽŽŽPPPCCC×××±±±KKKåå奥¥ÚÚÚ666¶¶¶àààááávvvÜÜÜ5Ÿ5i´iz»z”Å”ÆÙÆ+›+“áäá*›*ÉÚÉ&™&ÞãÞV­V¬Ï¬p·p€½€»Õ»3ž3M©MlµläåäN©N PªPÇÙǽֽE¥E‰Á‰­Ï­¦Ì¦t¸t 9¡9ãåãÌÜÌŒG¦GØàؑđT¬T)š)‹"—"ÿÿÿûm½sbKGDÛ™ oFFsxÒIÅÆtIMEá‚is4 vpAg  OýÄIDAThÞíØ÷SAð÷ FDDiQ@Å( ¨*6EQPT,(ŒÅ‚]E¬Ø{ï½7ÄŠ½÷Þÿw/É 0ìâ=™ýþr37o÷sû6—K e"[/= z€“³¡Ž±® E½m@=p­ï Ü«Sß°‘Èy zx ¯À¡ÞÛG°§.`j, ”Õ7ñÕâ'0À¿)4Cl ¥…h½Ùö9lY5àÙ*°5;´ Òâ-Z¢Å£J ­ÑÔN ?Õ·wà nf³9Xp¬Úä¶V†ˆõÿèNV@XxÇN#ºtíÖ½ e)Mt k±'ŽˆêÙ+¾wŸ.$R´¨o?í˜Äþ@ip` !ÌA„À`6ÿ¡t@J†É\‘0<•ÍŸ$µd)`߀‘RK–FfÓG¤I-YˆÃæ·Ž•Z² 0n<›B¢øI r"ïÿ¤t-“ €0‡/;ËÔÎg² ”«¯y!_yKk&0•ýaž6}F¦WõÕügÎâÀl˜3æÍG\ÀO.ÌÒX”ÀŹ~˜ y¸–"æA¾nÀ²‚å++WÁjÄ5P¸ÖéÖ¢õAÁ€¸ 6³ó[¶ê·Û`ûŽ½Ë¾Ü  °Çvíõå{°ö#(8x(ð°noÃQð9†ÇM'œNæäžÒ8íl =sñ\áyĬ õÄëÀ’nÿõ~I•—¯h¹JUZ¯p­8õz\Ú :À–›·ˆËí;$@qIøÝ”{V.ܧ’m—ý€¿1zH”æçB <æ=zBÔ‰’¢m%tEXtdate:create2017-06-06T01:31:12+01:00™Ò¡%tEXtdate:modify2017-06-06T01:31:12+01:00è¬IEND®B`‚puzzles-20170606.272beef/icons/keen-base.png0000644000175000017500000002215513115373720017346 0ustar simonsimon‰PNG  IHDR  ›á9×bKGDÿÿÿ ½§“ IDATxœíÝ{TgÞð_B.PP D]*XDï·¢¬ «R–JÕ¶ºVºv•B‹¸Vízvëq{ìmÛ­¾ÚBßáµU[ºThE# XEÓUîj’s}ÿ6¦!P/yf†øûü±gfòlŸïIòu&“ Ãikk„\¦ dϰ`„Cˆ ,BaÁ" †AX0„‚!D !‚°`„Cˆ ,BaÁ" †AX0„‚!D !‚°`„Cˆ ,BaÁ" †A<›üW$‰Mþ;±ÊÃÿQC܃!D !‚lsˆhž¿,‘HX†Z`I$Ì3<~äÁ=B‘*تU«$f¦OŸNh¢êÈ‘#qqq~~~‰äoû›i;#Ï[]]d¼¼<¦ÊPÏR©ÌÌÌ ?~üòåË/^¼È`È{aãCD ³fÍâñxàååeñÐöíÛûûûÿþ÷¿ ÀZ?þø£³³³¿¿¿L&ü¨ÕçíĉøÃL«'OžŒçrmðO¤H$š7oµ¬×ëËÊÊÀÛÛÛ| ͯ×PÏOVVVaaa```XXØ?üœœ\QQ!‰˜Êù›Èìƒ>ðôô´úPGG‡R©$:;›íÝ»²²²¬lðóvæÌ™õë×§§§gggÀöìÙó¯ý+>>þáÃŒ?Þ´¿:~üxYYÙøñãM•£ÐüzY}~ZZZŽ;Æáp ÄbñòåËËËË>œžžÎTÎßD¶`3fÌ0?þøk¯½ ]]]jµúûûÕjuss3±XL4ÉÈ2øy›5kVVVVnn®³³³H$Ú³gÏK/½d“vYøç?ÿ /¼ðµodÕëÕÐÐ`0|||¨Ù#""ÊËË/]ºÄ¶œæHÌÙÙyöìÙ>>>555çÏŸOMM-)) Ø´iÓ™3gL⣣ 22òĉ„’Œ,C=o°yóf•JõÖ[oÀš5krrrl>{uuuuuµ»»{rr2µ…U¯WWW…BjÕÅÅÅ´‘U9Í‘*ØÁƒ©µZíŒ3Z[[KJJÖ­[—™™¹nÝ:x÷Ýwïܹ³eËxì±ÇÅq†zÞ¨Gƒƒƒ©…‰'’˜Ú}=ûì³Ô{XõzQŸHMG€*•Ê´‘U9Í)˜F£éèèðóó£V9Žé£¢¢¨J¥rÉ’%$ŒPÃË^¯ÇœËåvttÈår±X\WW¡¡¡lËiŽHÁ ÅŒ3¦OŸîççWWW×ÒÒ"‰ž|òIsP_|ñ…T*­ªª€S§Nuuu-\¸pæÌ™C=oçÏŸOOO_²dÉ;ï¼ÃårÕjuFF†X,ž?¾­"}üñÇz½>11ÑÇÇÇVÿÍfõùIHHHLL÷Üs§OŸ®­­ … ,xõÕW}}}IÌ5BUWWñÅÔò•+W®\¹âåå7ÔóþÊ+¯¤§§;88À¾}û¨O6¡P(òóó`ýúõ¶úo> «ÏOBBÂÞ½{]\\¾þú릦¦éÓ§¿ñÆîîîÌFÇ&§°íRÀK¥†…y†gð¬ÕBk+´¶ÂüùÉLû€cŒX ññàí ÈdpêP_?\ÁD"Xºôî꯲ "#!4\\àÒ%8{ ²r¸‚Íc°`ŒùïeOááPQ}}Àöqpoo0ÁÁÁöy–-GÇ嘸|nߥtº!SÍc°`ÌÓéàúuP(ÂÇÙÓÿø àê “'Cl¬õlÆÔ.Š^ ×y¢yìŒI==ðñÇwW##!6v¸ñÃÀ‚BååðË/`ö L[ª­…¾¾HlÈ3raÁ˜Äå‚£#èt»‹ @ €™3­Œôô„%KÀÏœ¡¥Nœ€;wàêUˆ…Q£lœêòe() ‚iÓ¬¡3ψ†c’›¤§ƒÑííðÕW TBe%L™bålÁ¸qw— <*+ººlü†®­…’0!(á¿—ò3–g¤ÃCfæq8 ‘€¿?€Á==VƘÆ,V‡*Àƒ©¬8™ ‰‰Ã} ¢'À=cއI“`ôhàñ ½¨¿=Áá€Ù_p¹ëèQ€ÀÀC²ººÁ6üeɹs •øø@d$tt l‹­œ$¤!}À‚1†ºr”)àêje°BeePVö«QQÖÛø`®]Xho‡üü»ÛŸÿ2˜†<ö Ƙ¨(hj‚žÐjA // ÐPëƒç̓úzèè…¸\ðò‚°°!Ó€myX Ƙ¹sïcp` ‹÷õË`òØ<ÉAX0„‚!D !‚°`„Cˆ ,BaÁ" †AX0„‚!D !‚°`„Cˆ ,BaÁ" †A6þE³éÖ€lÀª0èÑdã[È"dO¾ø79he÷ ¶ Öæyx6.Kž `ëMÐÑ£Or D‘‚éõúŒŒŒ9sæ…„„¤¦¦644˜!–#R0N———ÇçóãââKKKSRRÔj5‰¹b3"'9x<^aaaLL Èd²Ù³gwvv666†……‘˜!Ö"²spp Úø|þرcIÌ…›‘=MßÝݽiÓ&ÈÎÎ5jH¥Ò«W¯Z srrJII!š!F,˜L&KMMmnnÎÉÉÙ°aµ±¨¨(//Ïb¤§§' Ù%R«¨¨X»v­R©Þ¯û𢮾ûÎrcx8,Zd³<ÔýÊärP*ÇOOˆŠ‚ ¬¦!} R0½^OÛËår¹œÚ¸nÝ:sÝ»înøñÇ{ÜÒMMËtuAW(°`ÍòÐ0Å}©ª‚ööe­Z[¡µæÏ‡ÈHfòØ" …ì¹LÉÄÕ¢£ÁÇ**†"C|þøîjd$ÄÆ2<…Á0° P@y9üò üá6ŽD©­…¾¾HlÈ3r,ÛÎÚÝ/.A§ø·üÂ`æLf¦ðô„%KÀÏœ¡¥Nœ€;wàêUˆ…Q£l ._†’€  ˜6Íú:óŒh ƶ³v÷ËÍ ÒÓÁh„övøê+P*¡²¦L±åGù{Ÿbܸ»Ë••]]6~C×ÖBI ‰‰ÀáXF[ž‘Žà‚:k÷ÔSàãóÛƒ©Sjk׆ °hÑÀëZ_O.ݽâp@"ƒzz˜™Ât0f±:TLeåÀÉÌà`HLîðžƒÑpÖ!ú,ÛÎÚ!D?Öä@Èž`Á" †AX0„‚!D !‚°`„Cˆ ,BaÁ" †AX0„‚!D !‚°`„Cˆ ,BÙøÍ‰Ä¶ÿÁ‡Áª0¶Eb[ûÖ¿ÉØcá±`ˆEXrkoöÜÆcÛÄ’< ‘HX†Z`I$ûÛq™àI„"R0½^Ÿ‘‘1gΜ   ÔÔÔ††Ð<,´mÛ¶èè耀€I“&%%%9s†éDv‚HÁt:]^^ŸÏ‹‹stt,--MIIQ«Õ$æ²Už„„„yóæ1y ÁÁÁ‰‰‰iii*•ŠéPö€ÈIWXX2™löìÙaaa$¦³I¹\ÞÛÛËH<6(,,¤nÞ¼«V«»ººü©{p ‡@¤`Ô»4 ðùü±cÇ’˜ë!ótuuQ»²‚‚hnn@ ‹™JË”‚‚‚††©T ‰‰‰Ø.› {š¾»»{Ó¦M=jÔ(J¥W¯^µæää”’’B4ÉPy6mÚ4øóFddä‰'hÈÃ*_~ùåwß}îîîóçϧ62ûzÙ‚“Éd©©©ÍÍÍ9996l 6åååYŒôôô¤á³š'33sݺu#|OâGÀáÇ5Í?üðüóÏÿå/ 3-v=_2Ÿ¶©{4=åÀξØ}"ž1°`÷¤¸¥øÝúwM«»§íp´Ížs>GÞ/€´ß¥Íñ™CÛ¼èáaÁ~ÛÑŸŽ¾púAG­fMÉZ濌¶Ù‹š‹ þSnÛ#·Ó6/² <‹øöÿ¸oÝ^ÓêëS^yòËtØya'p9Üý±û]x.tNlH:ƒîµÊ×ò®üž—ÇååFç¦ÑýKÞ^M/Œ†§þýÔPc¦N€ÕWçFç51 fR«ÜP¶¡¤­„Zò…Îþpd³©Ðˆƒ³BÞ/O+MûñÖÔª—³×‘ùGè¿nÙ,˜%•N•P”Тl1mYê·ôlÇÙ³g͇…x„Ìõ™KCž‘;ÔzË/µ»Ô]o_|Û´š‘-â‹‚ ¦!(µÊº[pÈzeæUÈ+„|!µ=&Úã@O$Ö‚YRhæí€CW –”BOÁV­¼ñzïuó‚==þi:®rCqcEñ «=÷ýs¦åkÉ×Le{dáiz„‚!D"Zã<¦íY¶ÿ…œ ¢ † õeÿSĸCˆ ,BaÁ" †AX0„‚!D !‚°`„Cˆ ,BaÁ" †Av~±¯énÖlÀª0ˆ›Ü[ß:È.=|;l¼cÉ­±ð÷ˆm¯Ûò<<;?DdÛ Æ¶<ˆ4<ÉAVÁŠ‹‹%‰D"ÙµkµE©Tfff†††Ž?~ùòå/^¤!†^¯ÏÈȘ3gNPPPHHHjjjCC ó"ú=BëîîÞºu+÷«£â¬¬¬O?ýÔÃÃ#&&¦¼¼<99¹·wà–Þ'Nœ0yòäIƒÁ`“$:.//ÏçÇÅÅ9::–––¦¤¤¨ÕjÒó"ú=BÛºu«P(\¾|¹iKKK˱cÇ8NAAA~~~LLLOOÏáÇàÌ™3ëׯ߳g5òÀ/¾øâ·ß~k“$<¯°°ðÔ©Sï¿ÿþÑ£G ³³³±±‘ô¼ˆ~v~’Ãä³Ï>+))9vìXaa¡icCCƒÁ`ðññ‹ÅQ^^~éÒ%˜5kVVVVnn®³³³H$Ú³gÏK/½o“0111Ô²F£>Ÿ?vìXÒó"ú=»qãÆŽ;^~ùå©S§š¬«« „Â?ŽéââbÚ›7oV©To½õ¬Y³&''ÇæÁº»»7mÚÙÙÙ£F¢m^D›G¢`EEE*•ª¶¶6--íêÕ«ðÍ7ßèõúY³f€R©¤†©T*ðòò2ýƒƒþõĉ–·l~x2™,55µ¹¹9''gÆ æÑé‘(˜Ñh€ï¿ÿÞ´åæÍ›/¼ð—ËíèèËåb±¸®®BCC©1Çß¼ysRR’››[NN޳³ó3Ï}úo¼áîîáá᯼òJzzºƒƒìÛ·/ ::Ú&“êõzê܆\.—ËåÔÆuëÖ‘žÑÏÆû²íR Ìcæž ómÃórö ó K HŠ÷‹ç‡¶0ƒIåÒ•Å+`4m©^^Mç Ù Æv**¢ Âüí :Ð5+š›Í'›NÎÏødÞ'"¾ˆ‘xJ­r˹-ñ "²Ñhþí+•K7–m¤-…]v5)š˜šýpö6†lôpô°Ø(q¡û‹àÌôž¹xÜâ`÷`•NUÜRœ/Ë7®²/m+½xëb˜gÍ©N·Ÿ>rí¸ACóì#ì7¬ž¸:À-€Á'Î7n[͉îw/›ŠóóuõÍ­Í5m©êª¢¹`}Ú¾-ç¶PË™á™oÖ¼Içì#"þ†O¿8é‹IþyþS ¦¤–¤æËòµ-\x.‡æ2oeUà*óUµNMc(€U;ÚTm”7.ŽæÙG ,Øo¸üËåMÖ íìï,m+Ýznkü7ñÍŠf¦sÞ¨7_ r¢söS­§>—}ÉΩ;éœzdÁ‚Ý·ú_êW—®VëéÞcXøìÚg¦åÑN£çKè»X±GÓ“Qžàì‹Ý'0ssDÀÏ`Ö¹ Ü[3&ÆÏÕO©UÖü\óÑ•”Ú¶4ö4n<¼~Òz¦â·¿[ÿ®iu÷´Ý®€¶ÙsÎçÈûåö»´9>sh›w$‚Y‘àŸ°6x­“ƒ“iË“¾O.õ[úûo~oúvüæq¦ vô§£[Ë·ê :j5kJÖ2ÿe´Í^Ô\TðŸp ع¶yG(ŸçèèXZZš’’¢V3|ûû`ç'9нàñx………111 “ÉfÏžÝÙÙÙØØF÷=iíîÁ888PíF|>ìØ±Œ†²¸CwuwwoÚ´ ²³³GR©ôêÕ«ÜœœRRè¾éÄ…Cd2YjjjsssNNΆ ¨EEEyyy#===±`÷ †***Ö®]«T*8””dÚ¾k×®]»v1l¤ÃÏ`ÔjurròíÛ·===óóóW­ZµjÕªªª*¦sÙ܃!ÐëõÔ¹ ¹\.—Ë©ëÖ­c4”À‚! …ì¹LÉÎà!"BaÁ"ˆ‡ˆý%m%•• ·šM}Ú>‡çåìæ–ïσñ¤réÊâ•F0š¶T/¯¦ós ­B*—Öt×Ôü\SÛ]Û«í5=t%ùŠˆ/¢- ¥þ—úÒ¶ÒêîjY¯ìÖ[=š>—ïéèì¼`ì‚äÀd!_Hgž÷ëßß}a÷0¦yMûrñ—´å1Ç|ÁT:UDA„ùÛt kV47+šO6œ!žñɼOèQ”Zå–s[,âÑìœüÜšï×0ÀÂ{õïþ§Ð|‹Î kÕµ¶*[KÚJÞ¹ôÎÿÌûŸðQáLÅcæFãðo_©\º±l#my,캰«IÑÄÔì#Qgç §_0¿Ÿõ£Œù=…œ™Þ3[ì¬Ò©Š[Šóeù£z´´­ôâ­‹ažt_{zºýô‘kG@Àh šg7ár¸ãÝÆGŒŽˆáäàôjù«L%¡ð¹üâs}æú¹ùy9y©õêšîš>2»¶*[+;+gzϤ?ÛÆŽ%.Œý‚›ù‚q8œ8߸mÛ&ºO4mŒóóuõÍ­Í5m©êª¢¹`}Ú¾-ç¶PË™á™oÖ¼IçìæŽ]¸pìBj¹îç:¦b˜¼ó6—ó«cŸ’Ox>a~ûóŸéŽ«'®p `dj«˜?DtṚwȼ]”U¿º›½ZG÷Ï“vTíhSµ@rPrܸ8šgg3‹vQÜîæ«ã„ãèŠó+/ž~qÒ“üóü§LI-IÍ—å3{°Êül(z£Þ|5È=ˆÎÙOµžú\ö9H\$;§îìTwÒ9ûˆ 7êuÁh¸­¹]Ó]³§fé¡ðQáSFOa$Õå_.S ýý¥m¥ÿºò¯ƒsŽse¦ðì-Øg×>3-v=_2Ÿ¶©{4=åÀξØ}" 6ØÿÊþ—z–,ÄŠcß›õ³ß¬˜«ÿ¥~uéê¢ß998Ñ?;K VÜRüný»¦ÕÝÓv ¸ÚfÏ9Ÿ#ï—æüž”IDAT@ÚïÒæøÌ¡m^;0Ë{Öî¨Ýbg1Íóº Ü[3&ÆÏÕO©UÖü\óÑ•”Z%õhcOãáÆÃë'­§9°³`G:ºµ|«Î £V³¦d-ó_FÛìEÍEÿ)€·€í‘Ûi›×>œé8³èä¢7¢Þx>øyÚ&MðOX¼Ö|õ¤ï“Ký–þþ›ß›>€¿yœ‘‚1’ÃÂþ÷ÿYúgÓóòú”×7OÞLg€v—Ãݻ߅çBçÔ#Ë'ü±íÙ¶¦?6Õ<]spÞAÓ7Ëz£~ûùí5Ý5´%ñú>ü õ]2n‰iõJÏÚò˜cÑLgнVùZÞõßÏò¸¼ÜèÜ” º9Û«éƒÑðÔ¿ŸjÌÔ©°zâêÜèÜ¡Æ<"x\žØY¼ØwñLñÌiÿ7­GÓCmÿôÚ§£#˜ÍæïêoZVj•£ÁêùO¢Ø²Sj•k¾_cj—/<4ïýíBÌ•ï:Á}‚iõ†âsY˜_‚ãÆw£¿]À’‚ÉûåË‹——´•P«^Î^O,,`6²ê§¾Ÿ¨3@šMõ¿Ô›Vi;ew£ïÆKg^ºÙwÓb{Ãí†oš¿1­>áù=y,0ˆ¨Ò©ŠZ”-¦-Ký–ží8{¶ã¬ù°¹>siȳ#r‡Zoù¥v—ºëí‹o›V³#²E|QðcÁ4ä¥VYwkàY¯Ìü¡ y…éÒõè1ÑÒaÊåå¯W¾>Ë{Ö\Ÿ¹¿sÿßí¶æöÅ[7î×õ›†ÅŒ‰!ÄäØc_Ýüj¡dá"ßEDîèï\è¾ðAÃæ_1¯\A[sÌL¡U˜· ]=4xXJP =[´jðÆë½×Í öôø§éü¹Ê ÅÅÖßÏ}ÿœiùZò5z~'¢5hKÛJKÛJ‡àãâó\ðsC=J‚Áh(n-.n-¶úh¬8veàJ:ó˜°âÙ“'<Ÿ(x²€¶Ÿ ÃGºØwñÁ¹iØ·[Åü , þ î÷³ò³µÝµ]ꮟÕ?ëz!O8ÎuÜdÉñ~ñ Ç.¤ó2‰‹äâÊ‹ß6[ÖQvùÖåVe«R§tâ9‰ÄQc¢VŒ_1Ë{maãØä¯°ísÀÖûM±$Ûò€ý¾^xˆˆAX0„‚!D !‚°`„Cˆ ,BaÁ" †AX0„‚!D !‚l|±/Bö/öEˆÕ°`d›CD„U¸Cˆ ,BaÁ" †AX0„‚!D !‚°`„Cˆ ,BaÁ" †AX0„‚!D !‚°`„Cˆ ,BaÁ" †AX0„úä ^ÓÉ›ÒIEND®B`‚puzzles-20170606.272beef/icons/keen-48d8.png0000644000175000017500000000231213115373732017117 0ustar simonsimon‰PNG  IHDR00`Ü µgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<ØPLTE%%%333+++ìëìµµµ›œ›ÜÜÜéçéåæåôôôƒƒƒ{{{MMMCCCÇÇÇlllúúúŠŠŠ’’’ºººbbb¬¬¬ÑÞѤ¤¤ÞãÞ]]]ÌÌÌTTTñçñÄÙÄÌÜÌB¤BŠT«T‚¾‚§Í§-›-~ŠÁŠóëóÿóÿv¹v†À†’¹Õ¹‘ Ž %˜%q·qúîúŽ`°`Z®ZšÇšprp>>>ÕÕÕÏÑϕƕ„ — ·Ó·À×ÀiµiI§I¬Ï¬:¡:ÿÿÿnÉèbKGDG`½É{tIMEá‚is4ïIDATHÇÅV[{š@fEcЃM ZZR›¦MM/ÿÿ'u/,,‡öëCŸŠËž9sÙ þÖ_®ÿ‰IÛq†vwè85[kØàùDâ“uCð=@þ ßÀ¿lMÀèÕå |ƒØâ†£±íÇ/–+Ê\CˆÃq0™NI~Ïb8;ŸÎf $j%çsß_úW`îeŒ§Œ0m§Q€ñe„•KD–«Ù]€)h]Ã¥˜Vª  Q,,ð çWk7‘+X•c¤ H¢8)¸Î²lÃP^7 õ>ñ†JA¹±y}óf{›ËLõ2cˆb¥ én¿}K;AwÂZA\®‹bFZ-¥Ð„*gù»÷ÅUÚMkk³8Ê%aææðaެC¨ †¨9î]©V‹í}q¸“hÄ€M‘µK¥È%²ýÇãqó ª:tƒF•ZôNúi¹ËK =B' ­ÀÁjcKÒwƒ¢ÓЦ²yZQ˜‘ǃ)›LÎŒÍp)ÚÄœÀ òŠKMH¦=ø®åöÔ==⸙X&ga4‰ÂI…Q…p¥§†M¥v®ä•nVè­¼øKÁ4Ac«r2K0zÎÄ9˜„ ú4€Å 9hÖM&Sg8þü8| ­¥*,]èá×;Þòh~⇳/~„šÐ¯4…£K$Ió8-ñ%ópÈãˆa_kì)ˆMfcëŽK7Oߊû_c]B{Ì$¼Dêòãa»†N ½˜¹ÂC)Æ ƒMvÈŠgÞ1-4Œ×SCF…§gò}{äÇò&h3â*…¼Yͼܲëü…  5ääc?nþÚîÓ^Z§Ä9„"_gOÙ†˜iµ:£’¨J5ùÄ0žC¯p­Ž®b A™ Œê£×HÕ UPmµ¨ûšÓC •³ë¸»®»&ÕˆfM…*RÐ)ØÏ˜€4®1!-I¼i ‚¹³%šh/  M ”& ØjÔù(4¥zXrQ£1ùHÊר¬ºugÿsÞïbBÜlÜî§µÏÅ2svÞ3ÏyÎ;ç}Î Bÿ0àäBHv½!0Æã¬Ã·[‡ôX“Ëå …BG’$EQlÛ^çˆ1Æ?ÎÏÏ/**’eÙ¶íD"±!µž>}jš¦sÌB„!D(ŠD"ccc³³³~¿ß4M§_JéšBH–å²²²ÎÎή®®þþþÒÒÒºº:˲0Æa*pÆX]]ÝÌÌŒC㥤QUõÞ½{CCCn·Ûçóåååy½^Û¶-˲ÓÀ²,`ŒMOOŸ?¾¿¿¿°°ðæÍ›÷ïß÷ù|†ḁؑˆùòåÞÞÞÙÙÙÙÙÙÛ·oBdYnii‘$ÉÉÜ”ë !‰DâÀ{öì™™™)//¿víÚÔÔÔôô´¦iªª¾úÄ8á)« !¼^ï™3g®_¿ÞÚÚjF0 ~¿ßᱦòN£B–å'OžTUUïÞ½»©©ÉëõVWWïß¿_Ó5„‘±fxJ·« B4Móù|‡=wî\{{;€¢(¯%”ÒÅÅņ†—Ë511qìØ±³gÏúò|>ŸO˜‚1&@è¶Ž0Â(S¾³”ó+W®`ŒmÛŽÇã‹‹‹/n–™ !DUÕÚÚÚ[·naŒ5M‹F£¥¥¥‚ Û°çô¹¸Ïe¹e¾2.¸VN©„¢Ñ¨£$¥ôµ}ZQ”šššªªªS§NÕÔÔ覾´¼ôÕõ¯‡mx½ü›³0bŒ-˪¨¨(**ª¯¯/..>zôèÄÄDeU¥?Çßûqo®/7¾—‰üûëoªeާ^ZZ*--5M“1v¨þ7xߣ¾±¹1ÁatUwíóï3l#݃¼™¥ÃÙ†ádU<ÏsçÝýãîS?¼¹ëMÿ\Q”Â@á·MßV«5[KÇi #ÁD·õŽÊŽ_Ã¿Ž·TûÑ|tþ멯ÝÔ (m1ÞZ“o ë¢w*ó—…w‡‘„ž©Ï2‡lÕ”†™j«'~>Ѱ«aŸßÕñ«ÈDµ;k·‡F˜—™¬s½û^7HbÒ‰·O|XùaÂÚ> K0ù®é»?WþT,Å+yCÞ%,ìí1ù!0Á,ñ”PB¹àª­bŒ7ö:fÓ6¸0™í}*¡­óÔ¯UemBÿ§¦”fáó_Ýr<'ä´*Š200â2×·Û­(ŠËåzaqÖˆ1–$)å]T–Rú€;wlhÆ€Rª(ʳg««åKÁÙ½8Ce¡kÚámZGÙ~|Y3“þAøðÈÍÑFX '%tEXtdate:create2017-06-06T01:31:22+01:00]¦ó%tEXtdate:modify2017-06-06T01:31:22+01:00fOIEND®B`‚puzzles-20170606.272beef/icons/keen-32d8.png0000644000175000017500000000235613115373732017120 0ustar simonsimon‰PNG  IHDR D¤ŠÆgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<‰PLTE 666<<<999...000444333 '''888ØØØvvvºººýýýñññîîîðíðúúúµµµ™™™ŽŽŽÔÔÔïïïöööÑÑÑ|||ƒƒƒÄÅÄ›››ÊÊÊéééääääåäáááÀÀÀZZZ___   ÃÃÃ***±±±¬¬¬ÏÏÏíëíèçèPPPrrrßáߌŒŒ¿¿¿çççÚáÚÒÞÒãåãõìõ‹Á‹•’G¦G·Ó·ÇÚÇy®Í®òëò³³³òòòÿñÿnµn”ÛâÛg³g)š)¾6 6?£?¯Ð¯¹Ô¹ŽÃŽ~¼~ÈÚÈúîúíéí»»»ÖÖÖ%%%¥¥¥¦¦¦@@@AAAEEEˆ‰ˆ©©©¯¯¯²²²mmm]]]ôôôþùþ•••RRR===aaaqsqSUSäæäàÖàÞÔÞëìëº×ºL«LS«SK©K—Ä— † }¼}¢Ë¢#˜#+›+3ž3…ªÎª@¤@„½„‘‘‘‹‹‹###ÿÿÿÞ–_bKGD‚‹³ÿDtIMEá‚is4bIDAT8Ë…“iWÓ@†k›¦jK3“–Økf©Z&J­MPÓºEEÁ AWPEEEüçÞ™¤ËѾ9wÚ3ó䮓Hä¿:iñ¸.•Ð;‹éI=T\Zj(mcl"œ‰e‡­Ì‰2ìä Et4r²tÊ&”QÊÍd¶|ºj­UV+d}=·±©€°ÕÊÌØð‹—k¯¬×oÞ2ºÕ®‚2‰*SËÒš½œÚÞv£yK‰~«%PÍ›ï6ÞØùØ<`ÒZˆs÷ÓÎg×é¹AÉj›ºþÞ—¯ßš= ßꆫ†¤Ç÷;ÞdÏCïÂ0u˜¿Ûéìïy9y#å•ËÉi2ñýÇÜOÁB йº°2…†Ì~}ÏóX?NavVº…“U> ㄌ|_F,,EŒ ü:°êð€­ÃÍß•Bɶ'l¥ÔˆþR1R,JSÿ­Aýó´‚áEàÂ%tEXtdate:create2017-06-06T01:31:22+01:00]¦ó%tEXtdate:modify2017-06-06T01:31:22+01:00fOIEND®B`‚puzzles-20170606.272beef/icons/keen-32d4.png0000644000175000017500000000104113115373732017102 0ustar simonsimon‰PNG  IHDR TgÇgAMA† 1è–_PLTE€€€€ÿÿÿÀÀÀ€€ÿfÇ@¼bKGD LòtIMEá‚is45IDAT(ÏURËrƒ0 t~ tš3‘Õ; å–Ò{§ùvúÿßЕ'—z ±Þ‡L)¥œú5=ŸÎjfwUÞÃæ2ì0skUZ®{9KS7ŸE%N„˜¶(Ë\÷2ø!¶jþ¡†¹|±¥äâáY¹W"OC°°€Ÿäx%Yæê~ÔT9ÓÇR—oK÷øVaÞO<ÜBGq'³L†•ö ¤±A£…Æ~úœÞ߯—© ¤ä\2Š4™ÒU±…Š{ÏdL·ÈIö>‘4c£©ÊÚe®wŠNA#D8rËÊŽÞF÷$ÍŽ¡Õˆ«Ü‚ôvÌ䊮BYúP=<º,;Äc€·NÊöf¦xûíi3U EÏ–**€Ü%tEXtdate:create2017-06-06T01:31:22+01:00]¦ó%tEXtdate:modify2017-06-06T01:31:22+01:00fOIEND®B`‚puzzles-20170606.272beef/icons/keen-32d24.png0000644000175000017500000000275513115373732017201 0ustar simonsimon‰PNG  IHDR üí£gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEá‚is4ñIDATHǵVKoW¾¯Û3žÚNM'NET’MPHE-*D5¡êª6T¬P~KV°B‰ÄcAX‚²@€"T°ˆ,¤ ä TJSJ,?ÆžñÌÜG'$.¯~ K¶¿{¾sν绀ÿ iZ2™TU•1V.—á;Ôò„ã¹¹¹–––ÆÆF€išªªzž·APÇ™žžB@WW×èèè¥K—úúúÒé4¥Ôq×uk58ç†aìß¿ÿĉKKKåryppðùóçñx\Ê×2ÀÂÂBww7cŒlÛŽÅbªª>|øP×õ™™™íÛ····×j!B2ßÎÎ΋/f2™ÑÑÑ}ûöõì÷\O-„BpÎmÛ– ‘lÑ“'OÆÆÆR©B(«ª !D5¨~B 555%‰T*µõÛ­ R|Ä'S©eJp]·­­mdd$‰ttt$“É÷[T…çy'Ož,‹~¿ÿÈoG¨dKY‡9Íz3ÌãkV¥4‰ìرƒ1fš¦Ü¥ £ !!Û¶m+‹¶cEðüÔù¡gCsvFwžûáœF4 hí$ÃQJËå²ëºÕ†lvì„–eÙ¶r¸“lH^ûéÚå/ßž¿ý8ûX#|½@5å:q׬AH’+´²»q÷žoöÜùóNk´5µ%eS{]ò9C„ b‚{pìÁßîÿr?êÜ‚hƒ >Tа/<òläÂÄ…:zÿèø_ã†b0Á¾L`‹Z½M½g~>C9-y¥˜£œnpŠ> B‡:»¶ìÚÛ Àݢô¶+ gO~nŽs.ÿ•´*ÓtÍ‚[€ 0Ä@þ«cMÓdRut]GišfcŒÂ9¯Nl-SÓ´`0¸*ÏçoÞ¼é8N}MÓòùüàà`KK‹ôK]×K¥’LVºˆ$#„*•Šüt]ïéé±,«Î(p΃Á ¦i‡nooŸ››ëè蘜œìíí•ÕÛ¶-58ç¡PhllìÑ£Gc „444øýþú†aBzzz2™Ììì¬Ïç{ýúõÊÊ BèÍ›7º®3Æc‘HdzzZöüí&SJ)¥õ<ÏSUuff&“Éd³YÎ9!$—Ï=zº¸¸˜îOçò9 ¥TUU˲ÖS·¾U@]×ÇãÃÃÉDâÞï÷úüÀÏ9÷QŸð zU‡_#ðá`Œ…Ãá¾¾>Êèñ®ãw_Þ=ûì,AÄ£Þ©ïNÅ´˜Å¬ZþG[…´ÞR©T©T̼ùâŸã ã˜ãCjˆŠõ“üÑBygAB>Å×ÜÐ<›Ÿ½µx«à0ĈϨClzæÖS¿NÝè¿1¹Ý‹¸à†b\Y¸’srpÀAÛWm”Óu´Ïº8àÆ«/¯ÚÌ>ýý郭‹^CüeD–g¥ãéC‰C\p.¸é™ëvTÝ”Rʫ璉Òê³G2!„¦kĪ›Êh«„h4*½¨Ž€®ëŠ¢¨ª<Ï{ßG%(¥@@Q”Ul6;<<ìº.Ø|˜9ç~¿ÿÕ«WËËËóóóåry3ÆX.—Ëf³²šzF¬i}ÝGMÕëë­aŒÿsÌ®öû!ø“깿Ô%tEXtdate:create2017-06-06T01:31:22+01:00]¦ó%tEXtdate:modify2017-06-06T01:31:22+01:00fOIEND®B`‚puzzles-20170606.272beef/icons/keen-16d8.png0000644000175000017500000000174013115373732017116 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<×PLTE '''!!!$$$)))###***———©©©ÐÐÐàààÜÜÜëëëššš†††µ´µæâæÞÞÞæææÆÆÆ ¦¦¦¿¿¿ØØØéééåååôôôŸŸŸ»»»ÆÊÆËÜËèçèïïïÎÎÎîîîãããóóó•••¿À¿ûøû×â×h³hs·súòúÉËÉ"""ççç–––º»ºæäæt¸t”Ä”øñøÊËÊäääââ⸹¸õðõ¼Ó¼B£B¤É¤ïìïÈÉÈíííèèèùùù™™™ÇÇÇûüûóòóý÷ýûûûÙÙÙ ÅÅÅÍÍÍÊÊÊËËËÈÈÈ××ׂ‚‚}}}œœ„„„ÒÒÒÚÚÚÕÕÕ“““ooofffuuu”“”µµµÆÇÆ’‘’ööö   ‘‘‘‰Š‰ŸžŸ®­®àãàþþþºººßßß”””ÀÁÀÿýÿÄÛÄ6¤6¨Ë¨úôú¯°¯¹º¹óðóÐÜÐi³id°dýöý°±°ÝÝÝáááñññÍÚÍoµo»¯±¯òòòÿÿÿÁÁÁ÷÷÷êêêáèáòíò···­­­´´´²²²°°°½½½ÔÕÔÎÍÎÉÉÉÖ×Öžžž û6CbKGD‰a&ÌtIMEá‚is4IDATÓc``dbbffaecbgfæàäbàæáåã—”b`—–‘•“WPTRVQUS×b`–×”“×ÒÖÑÕÓ7042–b07•—ÐR03×´°´²¶ ØÊÛiëØ;8:9»¸lÝÝ=<½¼}|}üü8ƒ‚CBÃÂ#x##u„¢¢cbeeãlã“’SRÓÒL´åäL32³²sróò €…î [ŠŠKJËÊ+*áfUÕ5µuõ é ÌZ¶MÍEÕ-­míé ‚ Íê"]Ý=½}ýé l&Nš4yJïÔiÓgÌLgH‡‚YRR³¥¤æ¤CèCNµPWÆ%tEXtdate:create2017-06-06T01:31:22+01:00]¦ó%tEXtdate:modify2017-06-06T01:31:22+01:00fOIEND®B`‚puzzles-20170606.272beef/icons/keen-16d4.png0000644000175000017500000000052513115373732017112 0ustar simonsimon‰PNG  IHDRíÝâRgAMA† 1è–_PLTE€€€€€€ÀÀÀÿÿÿÿ2W bKGDøoéÇtIMEá‚is4iIDAT×5Œ=Â0ƒMv*½¡HÍÜ'9÷¿ iž>ù¸m/l Ô8/pP e(Õë‰S^ÎÈúfÃS£Ë³|ŒˆÇšïû {7vê3»•Ìú;¬½®9åÙ)dŸÔð׊àŸûXh%tEXtdate:create2017-06-06T01:31:22+01:00]¦ó%tEXtdate:modify2017-06-06T01:31:22+01:00fOIEND®B`‚puzzles-20170606.272beef/icons/keen-16d24.png0000644000175000017500000000236113115373732017174 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<ÓPLTE ''''''!!!!!!$$$''')))!!!!!!###***———©©©ÐÐÐàààÜÜÜëëëššš†††µ´µæâæÞÞÞæææÆÆÆ )))¦¦¦¿¿¿ØØØéééåååôôôŸŸŸ»»»ÆÊÆËÜËèçèïïïÎÎÎ !!!åååîîîéééåååãããóóó•••¿À¿ûøû×â×h³hs·súòúÉËÉ """ÞÞÞçççåååæææãããôôô–––º»ºîîîæäæt¸t”Ä”øñøÊËÊ """ÞÞÞçççäääåååâââóóó•••¸¹¸õðõ¼Ó¼B£B¤É¤ïìïÈÉÈ """äääíííëëëëëëèèèùùù™™™ÇÇÇûüûóòóý÷ýóòóûûûÙÙÙ ÅÅÅÍÍÍÊÊÊËËËÈÈÈ××ׂ‚‚}}}©©©œœœœ•••ššš„„„ ÒÒÒÚÚÚØØØØØØÕÕÕäää“““ooofffuuu”“”µµµÆÇÆ’‘’"""ãããëëëééééééçççööö   ‘‘‘‰Š‰ŸžŸ®­®àãàþþþººº"""ßßßèèèåååæææãããôôô”””ÀÁÀÿýÿÄÛÄ6¤6¨Ë¨úôú¯°¯"""ßßßèèèåååæææããã–––¹º¹óðóÐÜÐi³id°dýöý°±°ÝÝÝæææãããäääáááñññ”””ºººóðóÍÚÍoµo»úôú¯±¯###ëëëôôôñññòòòïïïÿÿÿÁÁÁ÷÷÷êêêáèáòíòùùù···­­­´´´²²²²²²°°°½½½uuu©©©ÔÕÔËËËÎÍÎÉÉÉÖ×Öžžž Á¬¢bKGDÐÖÏœtIMEá‚is4IDATÓïþ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³F´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïð)Éx‡–ì:µ%tEXtdate:create2017-06-06T01:31:22+01:00]¦ó%tEXtdate:modify2017-06-06T01:31:22+01:00fOIEND®B`‚puzzles-20170606.272beef/icons/inertia-web.png0000644000175000017500000005112213115373720017716 0ustar simonsimon‰PNG  IHDR––³cæµgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEá  ŠNQVIDATxÚí½g|TÕö?¼O™–ié•tHPB¤—ND"¢ˆ@èE¤(*(pÁŠÀE ‚ô*-éÒ’B !ôéýœó¼XÌöd&erñçÿ¹ûŸ0sæì²ö^{­õ]…ÈÌÌDÿkÿäFþÝø_{Þö?þãíð’ü?MT‚ êõ<Çq÷F,Ëò?q$¡ÑhdY¿/|ÿå÷ÊqI’ÇqçâhàI‚ ø¹8[«ÕZ¯ÙREQ”óŒjú/4’$†á?CÇq ÃÀ|)ŠâÏ·ÚEÀoÆ?wèþ¶ÙlõšMÓ‰¤z’$i4‹‹‹e2Ìþ‰D‹F+b6›0tF#•J]<¾ð“ÉÄ0ŒT*u¦"|âLZŽãL&SXXX½f«V«KJJd2„eY’$…B!Lž!Âl6“$‰·©N§“Ëåô iZ¡Pa4µZ-ž/ÌH¯×S%‹aü ÃÐ4MÓ´ÅbŽÇq‹wd³Ù8Ž áo—Úg$Š‹‹B°tŽ$„å“Éd6›eY öƒI’Z­¶²²2::Úd2Áh(ŠbÆÇLJ¦i¹EQjµÚb±øúúò÷ Ì\&“Y¬V‹Ù ;Åq\EEETT”ë$$âÏ?ÿ´X,>>>0#¹\®×ëŸñPYY©V«ù_Õ²QÒÒÒ"##­V«Õj•Ëå—/_>vìXÓ¦MCCC- EQååå;wîlÖ¬Ù믿Ž Œ ¿ßf³)•JµZ½råJ„PRRRBBÂãÇ)Šþ ƒgf$“ÉNŸ>}òäɶmÛBG °°ðàÁƒ­[·:t(BÈjµÂ®Bó7DM‹&ŠŠŠþüóÏØØXþuHM›6 Ó¦*‘Hd2Ùµk×víÚõÚk¯ :Ôf³ÁĤRi¯^½t:ÝŽ;š6mêååe³Ùôz½T*¥( ^Rg#IÒb±0 ãææ†Ù&˲îgRRÖ_º”y÷n›ÐPw‹¿Á¦3›ÍÁÁÁF£Q¯×ÃO¸œ'•JUZZ B.—>|ø·ß~{÷Ýw{ôèKf³Ù|}}{ôè‘}øðáøøx‘HÄ0ŒÁ`ËåÈ~uÉd²´´´Ÿ~úéÞ½{0 ‰D)l6I’$I š¦…B¡T*ݹsç;w’’’:vìh4)вÙlMš4éÖ­ÛíÛ·OŸ>ݱcGŠ¢à^ÐjµxëÔ>£ââb­Vëëë « Í‘òÀ?ø mÛ¶†Ïèôzý€ÆŒ“œœ¬Õj‹œ­–Æ0Œ‡§çÉÇwß¿ÿîÆ-fÎ\¾qcYA›LÆ0Œóó˜®uîx¹B¡8þ|ZZÚÇܤIF´!Âb±X­ÖwÞy§[·nëÖ­£išÏN8Ž“H$ëׯíµ×öíÛßÞ½{wÊ”)S§NÕh4B¡³5èèØ±c .ôööÖjµ¸#“ÉÄqÜ”)S¢¢¢6lØ ‘Hø\Ä•éà9®†Ãi….÷íÛ7räH•JÅ'8¼¥´´´M›6]ºtÙ·oŸD"qqF¿Ô_~Ù—ýÚ¿ÿÍr\³-â>üpYrò_T¬zU¸®*À5VQQqêÔ©‰'²,k0fDDqqñÀ===SSSAá8Îl6»¹¹mÛ¶mÅŠ ‹by˜¦ésçÎÍ;×jµ å8N$åçç_½zuÒ¤IF£Ñl6W9+$Éq\IIÉo¼Á²ì… @llÀ¤j#!BH$=xðÀÍÍ­M›6jµöC•••¯¼òJEEEii©ë‚ŒC#‚aYw;ý^]¶Œ „ô ݲeÜœ9Ë’“ËòóݤR¶º³è" %É­[·¢¢¢‚‚‚€­9?FQ”N§0`@VV–Ùl†OBBB*++×­[‡ŠŠŠZ¿~ýÂ… ‘ý.*¦¦¦FDDÀ>‹Åׯ_o×®‡‡ÈzÎó%IÒl6÷ïß?--­±tVÛHA26 žžž,ËV;U‡Y­VŠ¢JKK½¼¼ê%‘j4‹Åâéé)•JO?¾çþý¡+V„B› ° #£¨ûé_~ùѤIžþþ&ƒA£Õ¾ôÒK•••µw—IIÉÝ»w›7o.‹‘ V à«p‰"„Ž;vÿþýdz,Û»wïS§Nåä䄇‡ã‡9ŽkÙ²eŸ>}âããcbbl6›››Öjo6› În»víŠŠŠŒFcâŒP(|ôèQ~~~ll,¨(Ïç0˜¼+Jð¨A–eerù¹S§vܽ;üÛoiÀÆ“­IŠÒ1LT«Vm.ülíZ­JEñ]¯3rQj …!@PVV¶bŊÇC§¿ýö[PPPÇŽù#„²²²¾ûî»óçÏ»¹¹1 #‰\•P(¬¯]¦¦VÝõH’®HØàŽA8r÷ð1Œª¬Œ¶Û/ª<ƒPEa¡B!¸ç¸qÁ"áʨiF‹¥°°°´´´ÎްšÑ°ŽÐÅŠ¢´Zmyyyís†'‹‹‹An@ÇA †ÖññÓúô99o^ii©„$ñõÎ2Œœ¢.Ÿ<©úùçÓ§ %’úZãøËZQQ¡Õjë¼8Ž+**BY,–   Ÿ~úiæÌ™ØèÀ!QuëÖmÓ¦M¯¿þºF£¥¥¥âRµeÙ¢¢¢Æº O!EQ•••›7o‰DµôAQ”Ñhܸq#²³ß†-®Z¥ŠŸ5dÈéùóKJJ€Š@¿K'Nèvï^øÁ„PhmèF)ãþýû{÷î•Ëå5$AžÌËËÛ±c‡›››ÅbQ(}úô™0aBdd$˜Ð@iƒçñ`Þ~ûí¡C‡6kÖÌl6Ëd²›7o;vL¡PÔÔ˲nnn÷îÝ;pà€ƒDÚ8$katt´R©<{ö¬§§gµfe«Õêîî~øðḸ8OOOPüÐ7°bZ?sÈÓ –<}*&IE]NIÑíÛ·ðý÷  ÁôCv­K—.åååwîÜQ*•΋ гH$:räHÏž=á´±,[ZZ*‘H>üðCš¦ùfLl‹xóÍ7»wïž——†½^V‚œœ©Tê¬ÑbF’ššú¯ýËEÓhýHˆìJèo¼ñ믿¦¥¥ùúú:Ì–$I??¿cÇŽååå 4ˆoðm)ŠÒ¨T±ññ3>µpa¥JuíÔ)í¾} gÏú='þeذa?ýôSii©‡‡Ÿg€°ãíí½eË™LÖ¥KNTƒ¡oß¾kÖ¬ñ÷÷ÇJ3Œy„ ‹-»#_µ8pà?ü`4 …CG"‘H©Tþðá¡¡­Zµ2 BÂj l"‘H.—7mÚtË–-Z­6,, †fÒÌÌÌéÓ§ƒh«Óé@˜v±KÐø6’$MFcpxx¤»{ò_ÈòóçϘü“ÿZl`3™LµsoŒ”••ùøø „‚‚‚är9\AAAð[¬ø¯_¿Þb±Lœ8”B½^/“É-ÅÄÄ$&&Êd²Ë—/#„ºvíšœœœ€œØÀÆq\DDBhëÖ­J¥Òßß&­[·N¡PŒ3@=Žãt:Õj­]‚ÅW©T¦LÞ`0„„„Ì;÷éÓ§kÖ¬v ×õwß}'•JçÎ+‘H¬V+Þ˜õmüŸEµ:ºU«/¦N5~<¦~ÿ3MÓ‚ºÌËh:t˜6mÚ•+W¶nÝ*†‘H$÷îÝ[³fM«V­¦N ¦‡éšæííÝ»woplll||¼Z­v°ðýzõ7nÜÉ“'÷îÝ+‹A_¼~ýzrrr·nÝÆg4ñ¤BE ‚:gDÓtµç¤ÕÞÏÏìô4M»¹¹•–– …BŠ¢`K"„¼¼¼´Z-0’$‹ŠŠ 6áMeY‘XÌØlÎ÷Çq•••/½ôRVVVvvvÝž®Õj›5k¦P(B‰D°ÝÜÜ`ðz½^,Ëår­V‹ì¢Yqqq`` ÿý$IªÕꌌ †a‚ƒƒ###±€Í|°I"‘Q^^.“É0KJ¥‰® š¶mÛöúõëÅÅÅüU DT \¯ÚW!¡Ñh,))‘Ëå°‚pÏëñ @yžù]$¡#uf5Ýf³ÙÛÛ»  ÀðÕ6Œ¤»»»c$º£i‹—ð Ã0ü ®ÑhÜÜÜœwÞl6Ðñ—}„$A—‰DøCGX¨ÁH$tDœ¥R™——ç@*xžçÃΰȑ‘‘B¡°ÂáËå111ГIøÞ˜$yýúu÷žç8ªJÌÖ¬V+`Uß:ÿ÷þôéS///‘Hä|@«íÝÐÐÐ&MšT«V:ÏÈ|ùòeèzƒ;‰ɻР£òòr@€wÿ³¯Bö±¡ª§ HXVVæççe³ÙL&BH(‚µˆßÑÓ§Oe2÷;ÚàþÐétÈ…¢¨’’’¢¢¢ÈÈHgÿ ±XÌ1 G’ûñÇX?X(ðY–¥Š ’4[,$!¶9ªjÔIcY¡jË0#ŒûÔÞhš~ôèˆ üí»D*•r,ËpœÍju˜80€%?#¡HD°,AQ .<#K‘[þí·ßÞyç–e?ùä“É“'!«å®ÕZEEEÚÜwïÞÅ~(ø+†a<<hPÿ*++©ªÇ78ýb±X äææÂ {òä ø˜x}9¹zM€¢(Ú…9, à'~ùå—ììvË–}½}ûã¬,™BÁÔ =£ŸF³tÕª&S§ÞóôÜ´~½R¡àjEÑ–õððØ»}û½¾ÅÇ/ß°¡´f”Ø•éÀŒØŒ@©Pü˜œœ©TOŸ¾tÕ*ƒZ-ª(eF¦PäþùçW?ÿÜnéÒ#?xÐÃÓ³Ú±aˆ‡Ž5jùòå jìØ±cðàÁ—/_®ÝŽS= ]W –ã·û=¸xq\‹>ýôë]»rj "Œþý¾ÿ>0)©S×®ý§OÏðòÚl§"ªŽŠ@¿}Û·ŸÖë}ôQÛ6mbçÎ]ÎC‰oÃfÄ"¤T(¶$'ßV(ΚձK—&“&-]½Ú R‰j°Üýžüùç—Û·w\´(.6vÀâŇžuêpnîàÅ‹Eb1Æo ’´0Œ·§§¢U«C[¶Dxyùøùé °(V–•­ÚºÕï­·Úwï®eÒîÇ!Äp\‹®]/§§ß¼ÙªeK–eu:T*‰ÅG>g0$|ò "Æ.¤$if˜@*"âèO?5oÒÄÝÓS«ÕzzzÊår•Jå¢8STTDÓ´‡§'E’»öì¹-“ ™3Çʲœ]Ô„ŽBBC >>§¶mk)“Ëu:EQr…"ûÏ?×üòKû? oÚTÏ›Ëq4M7ëÞýØñãTii³¨(£ÑHÓtFFF¿~ý.\¸ÌS …ÂS§N]¹roY„PZZÚêÕ«}}}Ûµkg±Xø*\#B‚àfoJJ‹ÄD‰ÄTUš%)JgµÆDFR­ZOIq“H8–å8ÎM*½rùr®HÔ¥{w-OL6g„„º¾ýö‘«WUee´@ÀqIQf½~ÿ™3íG“¤µêUDR”ÆjmÛºµ6(èÌéÓ|—çz5ÐÔååG®\éúöÛBLUiž$IÕÚ¹k×<‰äÊ¥KnR)Ëq,˺I$ÇOœ ccc›5ÓZ­dU?+³Í¦‹[&&î=q‚eP?°c õÖ­[ãÆûî»ïPUž ¼·Zt¶‘HÈqI.œ6-sݺ?³³å4ÍwXbF)œJIQ¦§O˜0Ac·0i4šC†t‹÷¯['\ž¯c¤F§KùôÓFŽôòó“)Ë0b™lARÒå+ ‹‹Ý(ŠO$èèÈ®]ÍJKG¾ù¦F­®}­aC6«ÕÓÏoΛo¦~ö™Z£ñàh„Dz2`ÿúõ]‚¯¾ªÑh(˜‘V›4~¼çÝ»'U ‹ £éìÇÓ׬Y0u*²Û¹”Je|||hh(ÞB¡éÍ|}}[·nèl™ja1›ƒ#">1âêçŸçääH) &ÀÚlrŠºtò¤aß¾9Ó¦ D"Î~t„ÌVkÒ„ aÙÙÇÖ¯w£(ð®úé †cóæmß¾S·nØ;ˆ “Ñ7}àÀ3}TÂÃú(>½w¯äÂ…™S§r ¢ñŒŒC‡—^×¹ó±ùóµz=¦"Ç0RŠ:¾qc“û÷'%%Y­VÂþŽe)¡ðƒ©SÍ¿ür1%EŽaÜ(*ïɓˋ¿ÿÆ¡M›BÄÁ`hÙ²ejjêŠ+Ýg±Xø &ì™3gž;wnàÀÆa_6š8C’¤N« Žþpôè+Ÿ}–óè‘”¢l‹œ¦_ðþûdUüæ¬7§Î˜úàÁ±~p£(Öf‘¤N§;:wîØŽ»öé£V©ø<0ØöígŒ±~Æj•SÔéÝ»EgÏΙ=ÛʲLCh~Gj•ªK¯^ã»t96w®V«‘$kµJ)êxrràÝ»3fÎÔ›L|½‚ «Å‚‚³g¸xü¸œ¢l‹Eååä\ú䓹£F…ÇÄèì +0Òüüü¸¸¸AƒEO– š¦m6[«V­úö훟Ÿo±£7ÿœuMHTÔ‡£G_Y²äñƒ~BáÅãÇõ<üOŒgÇéôú©3f„fg[·Î¦uÍÑyóÞíØ±kïÞªª ä€rzáÂâ¢"oà×;EçÏÏ™=ÛÂ0lU³uÃt¤ª¬|FÅyó´*•»@plýú {÷fÌœ©3/ð oe›ÅÂÑô‚Ù³þvô¨ŸP˜›}é³ÏæŽÖ¼¹®ê1Ã!ÇqŸ}öYçÎù±!›ÍþÕW_€Œ£ª,{M)Æ*k™$xv[­V€UŸ½Ädò Œ 8´yóÂBÁùóΜIòð[gÈqœÅjíÚµëÃ_=wçÎãGßnÛ¶[Ÿ>|ú)LàJ.•ܺõnNŽ×íÛïÏœ ÎÕ0ràTr¹¼²²ÒEÊD δ †f11ÞVëÁÝ»ïÝ»‘›;uút½Ñˆ­¸|¤ö%c³‘A·Ž/nßþGAAáÁƒ³‡ ‰Áô›Þ€Õ0`€R©,))©¨¨@¾ùæ›K–, ÌFz½^(òÁ&GŠD" @ÖÚÀ5¡¤¤Äl6cb*úFz{_¾<}Ò$J$ÂôƒšÍfpú+šã,6[—Î .^ìÛ½wïÊŠ |«Ãpu:L&ûË×”$CHDD€H¤KK›6eŠã› Ÿ?XY !\!d]¢¨ÂÂBŠ¢0 Ÿ½G¯Š‰Q˜LDnîÄI“ &ß ‘$ `Ó3QÓf£„ÂNíÚ=LM=xpÓ-Î˲F£Q.—.Féþýû{zz>|!”””´téRˆúþI’¤N§s ¡£™†e0\ñ/†˜˜y•£MQ&£1"*j^ëÖ­–cY=ãŒTà~9Ž3[­Sg̰Z,:­lÍü #>¡(Ê ×·nÛ¶c—.†@È¡#<½^†°å:Äñ‚Ç~×=zöé£Õh(žC"¬Œ½Pű,-Í›?ß`4 >r„ÑV|(aMÔjµ——W‡l6[XX(è0)Ü‘#ÈÇ 5 ¸èüþûï˜òpå‚0æhFˆ ‰D\-a9ã…z½ýjróªVQ«ÕžžžÎ_R\mG*•*88Øl6ß¼y³Núáæááälh­¥#ˆ?Ç5Œæã_ñ%üC†a4 ÿ¸ÃÃ4Mƒ- ¼„ø¸ˆzzzV¶-,,ÔjµÁÁÁx‚8@,#¡R©j‰p¬Öªk±X”J%„»¸¬4M\îìr\œ;›Ž——xÖÙ ,SVV–Ñh¬I ­vFXõ†•eÔ;ðÔ²ÙlàÏ_(‰ÂAðð¯D"1›Í€×‚Ÿ8Já@;çå¨-—˰û(\³/^| –æ©ýç-Â0Œ›LV^T´,99jÚ´I_}ÃÍíÇ 0Öï,vÕÞÞ‹ ¶ 0 £T*÷ïßo±XæÎ+ ùáF£Ñ`0Œ=ú¥—^Z¿~=2…BaIIÉöÛ§¾;õè•£oZÞ<þáñ¼y+ .~rqJÀ”•ÇVN3ý·Ë¿¥§¥Wk¸wŒlB<ž°`Á‚‹/‚Ê[dß]»v}óÍ7B¡®âFñ*¯½9û¸I¥å……ËÖ¯o9gNóV­T6ÛÐ9sÒ==7»à±Q¯¾\ÿ•X,~øðá;wƯV«áÂûk¡Iò 4H&“:u €x‘H´gïž!‡<0ù¥dj*Ez‘K,AÈ ú úäø“ŸïÿüÍaoþrøœÅ¦Fb'œÈÈÈ .œ>}!4bĈóçÏOž<?@ÄÖ­[=z>™ÿmò˲nRiyQѲ b?ø &.NÏ0E™0Ö¿aƒB.Á‰»à~üØf³A>¡X¨ kEk‰W ÖÆ2ˆáHŽ#9±Œ•¡ÛÒ‡Û.Ì+ ÏÎÎvŽB­BBÈÈtéÒ¥I“&­Y³×½{÷N:!»ã,BÈl6/^¼xÖ¬YÙÙÙàhûâVJ$ª(.^¶aC‹Ù³cZ·Ö1 IQAÖÿê¤)?mÞ,k(Xذv“^½zõìÙÓLÀ |Ì›4iòöÛoƒ³¨ØM‡à„¢¢"¾gñ›~$IZM¦ÏV­Š=;¶M ôÃê ‚0ÚlÃçνÌq{vîT(•âAãbÃñMuÞ,`"À2²¡|xذa|tÃÁí€ã¸Ù³g9râä^L ÌgÛœe§N˜pçÎñõë%$‰ìX?˲’,/+;¹`ÁÄîÝÛuìhªËÌÛˆ l[yyyufã—§ììlô o1ÝϹßÞ¿=úqˆC\ƒA"PêìÖ¹ ² ²¼Ò™ŠŽâ ä´êСÃ[o½%‹!^„ï° ¹!CBBFÕºuk°s¾ÐÍβ:£qÚÌ™¡Öñ#’,+/ÿuþüÄuêäÿ×GÅqêväȈ¬¨ö1°vedd¤¤¤€D* 6mèÓ)ü\ø³\1 BBB "9’AŒøñÐÖCÜþ£A_M 5ÙŸl6[qqqllì¬Y³PU!û™ç§P¸páBŠŠŠ,ŽÂþB‰<8öÃbŠr#ÉÒÒÒ_çÍ›>`@«Ž5*U#¦”p¥8óÊ+¯deeUn&l‹ÅròäÉÁƒƒAÕÓÓ3¾MüÅŒ‹ÿnûoòc’a‚"(DÑMR$Gsh5Z"[R )ðPzDEEѵFb=”¦iƒÁ0qâÄ%K–xzz";/å8.44ô?ÿùO¿~ýôz}£$`{N*†}ݦM‡Þyç£ñã[´i£©š4Îõ^jéËÅq qqqf³ù›o¾éÛ·oûöíùƒ¹wïÞ¾}ûbbb† †s@ÌÛŒ3Ö®]ëí뽡׆ŒìŒÌß3Y–ð‰èØ©ã¼;ûÙ?}ÚôšÔMG:°MÀÛZ´h$ŒW*•eeeÏsþ0[ÎÉýĹñqJL ø•ÁdûÖ[‰*•§¯¯¶f…̾Š_ë<ÎÚ…ͰpªÚ·o¼{÷îüüüÑ£GCŽáK—.9sfذaqqqüpsÑ4ýþûïÿúë¯ÛmŸ6yÚèÀÑ6›Í`1|»úÛŸ€ùóænU­þVc 6X¥¥¥ÅÅÅAƒ£ÿÛÂÂÂúæ`«¨¨hÒ¤‰¿¿ÿÙ³gÁɼÎeÒëõ‰$::ÚAzz²Ó´³oø…4mÚT&“?Þ•ä*6)Šˆˆ“±€,ZVVh9àB¡P$©T*Øë Ñƒ×0CÂ"€eHZl6›)šâ8Žc9Š¢ ¸ÀW\\ìææÆ7–V!¡Éd*,,üË+‰·@p[r8ƒÁÝÝÝu¾ È'¼¤¢¢ÂEo]8s …‚³M`‚ï'v£Ñ(•J­V«F£q]@¥(ÊÛÛÛEI ö1 €Øw†ãŸ#»QHŇ|F#΄î0xijðgd0ù±jrs;¸"^$ßû¯lEEEçÎ]¤P½¤¤äÞ½{þþþþþþ..+A………>>>0ðž9ŸSE*•êt:XpSpH´]g/`ÊèØ±£ë×'AÙÙÙ%%%.Úƒà–——»Ž-söáu9 ìÉÆø£¯e&øþw:Ï"ÊoÞ¼)—Ëa®/â ÆJ¥233óСCýû÷oݺµÁ`‰D?ýô“X,6l„{AØ4ì-וWœIxZ3‚“‘™™ä:nÚ0¨µÚL™Õ\òõ•Ê8{Ý‚òòò:oDHÕSRRâîîîzGüyr'•JwïÞ}÷îÝ!C†€t»aÈ!çÏŸ_¶lÙ„ ‚ƒ«±׫#½^ëZÆ Fµ¼¼<µZÜ` ÊE*VûþÆÑŠà]Xûcà©×`½eY¥R ÂÞ¢E‹à ûEèîîþöÛoß¼yó‡~˜9s&?ëVxº8£i rgc½ˆè\ß`hÜ™™™wïÞ5köôÂa˜ÒÒÒ¶mÛ&$$l߾݋³ëS«sRWû?]¡©šá’ä¡C‡† ^5¦ š.++ëÞ½;ÇqW®\ipˆá?¨½PCâs6?û÷ï߬Y³ZàÈõ—˜˜H’¤+y¢þéíŸDB¸q[·n xwM ôèàà`pkø ÿ5ïáŠ;DÞü?O?ô» 9މDuŠðØß‚W¼øöO"!Hð?ýôS-þEÈž755õúõëÕ&[ü¬ý“HY®ÄbñùóçkJa]µZ}íÚµðððÿ?ˆ3ÿ$‚D:lذŒŒŒ›7oz{{;„5ƒ÷­B¡Ø¼ys|||HHˆ+0È?½5& ]QŸGÆ‘ãÇÿùçŸÏ;çéé‰!4°ÎØl¶¯¾úÊÍÍ-!!¡v~û·O§±Zo½Fv,œ»–ÇøF¸úZj “ÉìÒ¥ Çq@{¸=<<ø‡Üp>úè#­VÛ­[·±cÇjµZÌ6ñÇÝaó)•J£Éd6™HŠBU¯%³Ùìëë[/0.c¥ËQpZ­VH— ŒÕj½råJtt4Do[,–›7o¶mÛ600ø„×Úæ{òäIœÈ••¥R©üüü âJ¥Z³fÁ`:t(p$š¦µZí±cÇbbb†$‡AãúÓG޹xñbëÖ­9ŽÃ1ßW®\9{öìˆ#""" V1WìðéÓ§¿üò Ã0b±xÖ¬Y:*(qöÙ!\ºû™[ AˆE¢ÍÉÉí;tˆnÑB«VSv¤û°ÀÞrñÁ¯p ¶ë$Ä Å;wöïßïíímµZá=Ož<9uêTŸ>}zôè§ÎgÝ1uD"ñòò‚ãBÔÚBE=}úÔf³y{{CuØï¿ÿ¾S§NãÆsww‡Ü ÃÄÄÄtíÚõúõë/^ìܹ3lsd”J¥;vìxøðáôéÓ;vì²6ôêÕK*•nݺ5((2 Èþc“H$©©©«W¯†€ýÊÊʈˆoooè¸+<ùW2+‚¹¹mذáª@~ëV3¿à`³ý ÃRð+j×Ù¯àäÊqåW0˜‘T*ýã?öîÝûÖ[o 2Ùon‚ :uêÔ¼yó¨Tª¸¸8«Õj4‚ožW/ä )6lù$~Μ¯vïΩ+ûû¯q'‹óóó<øþûïGEE•——óÏYEE…——×Â… oÞ¼ùÇ€¨ÃKAµgF.—;v,00°G¥¥¥Î9š8Ž+++3fLvvöÝ»w% ¸§ž={vüøñF£ÑáÆ&‚¦éÊÊʦM›vïÞ}Ïž=¸t·ÅbqssÛ´iSrr2ˆKøžƒÒVï½÷^~~>d¦â/"™TºvÍš'Íš ž2¥Âj ïúùçü¼á/Þ”CÓôž={† âçç§Ñhôš¦F#BhìØ±Gí…«%²©a 8peeeïÞ½!¿±ó3ذҽ{wúÁãÇ[·níëëËOdã0FóÒK/˳7iÒD­VoÙ²!yýúõ””777¸A^^ÞîÝ»±×2L"Y»zõ“fÍMšd`R 0°lppðK‹µsgν{²š#’þ³;ÊåòvíÚ9ÓÄv‡……EFFæååñ³€=›™CÁww÷¨¨(×Å™;wîèõz(÷s-¿ÂÊiee¥Õjõõõå8Î$±ŠŠ ’$¿þúëÂÂÂëׯ3 Ó²eËôôô‚‚‚˜˜P4¡__ß–-[öèÑcèСZ­ÖËËK(lLNÎ OR”žaBÃÃ;-X°ä?ÿ1 ä GkwBà¯pµÊ^£™¹]©BÉqœP(Äåtðßu¾ ¢!×=þpH“ÉÔ¾C·’’ûºUM™ÍqM6„2OœèÙ®]í5`þ$I¸ê\:‰DR­›n£‘0==½ö#¬àéÓ§<€ê:………=r%ÛÂíÛ·A·óöö>wîÜ?üW‚swp_öìÙóܹs~ø!$(4›LÍš7Ÿ™på‹/r=ÂyÃ9Ž#8NH’G¾þ:¦¸xì˜1hûÅ5œ½®aFFFí.Ô°Ýïß¿_ZZêüdãH¤2™ìÂ… ·nݪ¥. |¸}ûöQ£F!^TÛ¨Q£.^¼xþüy‡°S©T*—Ë×®]СCÁDQ”Ùl Û¼ysÏž=1bE„··÷Â… çÌ™1Ðü1<.0?ýôaNNÊ÷ß·ª¨Àô{ñJ!I’Z­¶W¯^EmÚ´ÉÓÓgðƒ& }||Ž9rÿþýÄÄÄjë—7NÁ???“É«ÕjwìØ/Øý‰'><11ñéÓ§ÀýkzƒT*½zõê_|³i …Â;v¬]»V«ÕJ$¾–Rß6 !;³Á#„ªïK—.>|ø;ï¼Û½Úå%‰Ž?¾bÅŠÊÊJŒÀ¬]»vûöí ÚÃ¥ã̪Éþ„ÿ®—8ãbãÿ–¿o”JevvöƒàÃk×®Ÿ_ëÇ¿’H$?þøã™3gÞzë­èèhP!¬VëÈ‘#CCC¿úꫬ¬,ÙsTm˜xÂÇr)Š’Ëå·oß...F™Ífp¶sÎÝ ‡˜eÙo¿ýöÑ£G&Læ„ …ãÆcYößÿþwyy9Æ“úýû½¹AÿÏþÓ·oßóçÏÃ%ºxñâW_}õÚµk”€ó·uëV‹ÅòñLJ‡‡ó_% &Ož¼uëÖÇ¿È\·üÒ4mµZ-Z” Wò¤I“ÆŒóäÉIU3,)k×®mÖ¬ÙìÙ³Áq ¾â8N&“7nРAkÖ¬Ñëõÿ]ið ±Xüå—_~ýõ×|I`bþùçĉÿýwàŠÈN¿›7oN™2E­VÊayyyDDĈ#víÚÅÏáòb®32wîÜ;vàJ0£+W®Œ?þÉ“'Ì!{aÔÔT¥R9bÄP²^X\\ Y™÷ìÙSm”ÏßFB` —/_NNNFÅÄÄ 80"" iZ§Ó-]ºÔjµ*•JLŒ”””„„¸Tª Ô®¬¬ìر£D"¹|ù2–/lFB¡ÐßßïÞ½©©©$I¶k×®ÿþ¾¾¾ÈnåÏÍÍýúë¯e2˜@í¹råʰaÃÓvæ“ ¬¬lÀ€£‰+Hÿ' ­«Tªüøã>D­\¹òË/¿4™L§N‚}JDII‰EQb±Øf³QZ " Â^XX¨‰ÇIj(@_Sk€ujÒÝ»wï‡~())á8î—_~ùðÃoݺuçÎ(ô‚zúôiHH¬³Åb …M›6õññ©c'I2""L94Móá*z¡Á`ÐëõÎÙŸjjXp]©@ölîîîß|óÍÆp›N:ÅÅÅ]»v---´W]eÙH¥R777³Ù\çÀhš:ÎÃã^JETûââb__ߤ¤¤‹/µ8ŽëÛ·oppð©S§rss1©Éd²_ýÕb±€ nÐ7gÞ(,,tPíÿþ@m¬]½zõêÕ«ð!Ÿ³ †M µ¼8Jý÷fÔ:yò$ÿC‡?ðk)ZÆŸœgô÷ÀöíÛëõúk×®eggöŠ—ü²R°s{öì ' Ù-Uµ`/R%îׯ_PPЙ3gJKKñŒp4š¦û÷ï>à`Ére¨ø1®Ñ!ß4Xéß¿rrò¸qãà¨øõ—WIrçáá±|ùò¯¾ú* Üû7mÚT{ s(¼sôèѨ 6¶±cÇnذaàÀüáq‚¾µzõêE‹A’|£Ñ¸aÆÚ%g¨²uëÖüü|g¶¿/íIêõúG 8°}ûö؈¿…?’’’¼½½sssáv‘H$§Nª)…9˜iJKKÓÓÓ[´hñ"£|I’T©TcÆŒ t˜P” ˆiÓ¦Ùl¶¢¢"„$³§(êòåËßêüZ€…ïÝ»WRRî,üz!ÌP*•~óÍ7mÚ´áOܽ'Ožœ””Ùp/étº!C†<~üøÂ… ;Âß¼!%‘H’““_~ùeˆôx‘×!Òááá«W¯ Â3"ìié—.]:`À£ÑGüÒ†~êÔ©ììlOOO‡Ả^¯ÿùçŸ_{í5°:ÌèïQ*pEm¥»»û Aƒ‚ƒƒsss+**‚èׯßâÅ‹GŒ=ï0RAÓtllì¶mÛ Cll,aRä8N¡P”——ÿý÷!!!C‡Å!p/@©À/B 0ÀËËëÏ?ÿvĈŸþ9xKƒÍ ‰D¢T*7mÚ$—Ë›6mÊwÇU*•dwmÅÈ%|Â0ŒJ¥êß¿?Áu~{HüÄl6‡††ÎŸ?ÿöíÛ^hµZ;uê Ѳ=ÖVQdª’’ˆ<ÂDu°c9T¼&B­VËd²z1R£Ñ>‰üãÒ œN笌k4Œ-ÃÀ ~»ô‹Åb‹Åb³—¶‰ !T¯|ˆÇiµZ~pWf%&l°Sƒ—¥V«åœ\ôt:R©ä« PŽÃÝå˜I’Ôh4¾¾¾üŽªI—ÐÜ1"‘¶þÖÍÍ Hì+ÍOLàÊáÜþ ïØnü¯`J ×8ì'¼µÁ‡:ùÍ¡#d·'ÕÕ …a€Ëuôë<#ü·³$Yr„B!ÿž¶Ùl"‘ÈËË Ù‹¢c-wä°I(‹zé ??ÿòåË=zô …8œ¬G …¶ëõz¹\îbþV0G!„ .:>jV«ÕÝÝ}Ë–-û÷ï—H$K–, ·ØëpvO8÷Æ:;™ß²ª) ³Éälá8Î`0(•J% è¬3’ËåË—/¿zõª¯¯ïÊ•+±Šì’‡Ùl†ØnÂd"‘Hnß¾½|ùr›Íöî»ï:GŸG/çðáÓ'O¾{÷.†v RRR C={PØ›V«:uêîÝ»á¤ÂR߸qãìÙ³]»võõõµX,4MªU£+0p[•JuòäɱcÇ‚häp¼ ¨š\.OLLܳgÏóØ>à>/**úàƒJJJ…ùKÝ¡é“'O®\¹R(:G\Ô·±, ôûêÛo ݺõ=ºÌjõö÷ÿײekRR2®]S¸»?ˆ¯Õj‹Å7nÜX°`ØöðŒ@nظqã¶mÛ ? ^s`¤Ÿ~úé•+W€ëü%mÒôãÇçÌ™.ΘöU6à \½mÛ¶5 `¤nÙ²epp°+µ)ªmÀ–:)+–-[Æ0Ìœ9s`Â0ܽ{÷>zô(00ð¹ µÙùçWß~kxùå¥cJ 0±¬·Ï¿V¬X“’’~íšB©|›8ðOww÷­[·B¤ýû÷ †Áƒã)#„¶lÙb00”OQT“&MÒÒÒNœ88p Á`8pàâUäÊÈÈøõ×_›4iâ ¾VCB@LBCCÁ:UËõo5j8 ×÷,‚n¾cÇŽ=zlÙ²¥Ú··Ùlž6mÚ!Crss]Xpx"¡ï×­Ó¿ôÒ¿FŽÔ1 AQ4T–õöòê³|ùºÔÔÌÛ·ÅIÃ6 øõ,_¾¼OŸ>gΜ©6"öG~~þˆ#Þyçä322úõë7þ|>™Ö !´jÕªž={?~ÜÙaÜQ©€Ój4ë´Ñ€|áŒ}¸¸¬àH’žžŽSÏÍŸ?Ï'B=|ø"H°\ßÅU(•Ö­»ïé™4zt‰ÕJñB¨H’40Œ¿O· þ=kÖ>ÿœlPp¸ƒ233ÓÓÓ±ê6lØ0ü6ys—™™ Ø‹H$R«Õ7nÜÀÜGÓ1²ãÞðªÒÒÒ¢¢¢ÂÂB@àà"åx aq]ñâ8N.—7¸J 0RÄÕ{¹(‡'!=[ƒ)(”½_yEYXxãÖ-¹S ¶€$M,ûÇöíÃ^yE$•² ½9ŽƒÕçCf5ÍÌL@x‚ p`Š~±ÚˆhGqb©oÞ¼ ÛZ†KÓôåË—«Í„Rgƒœ‰'¦§§>!ªCŒ$èkÖ¬ùã?"""\qPpnAØ,–€àà÷GºûÝw÷ÒÒd¼@m !’ ~Y²¤E½ž˜êSd4V®\yýúõŽ;"{ÝjþŒàµžžžLII‘J¥¦mÛ¶ééé_|ñ²£Ü|qÙ3ÉMœ81###11QåT&µóEQÄê¤ópA‰yúô)Œ£±–©P(Þxã ðuHrs×®]»wï6ë‹3Iôzï  &MÊüæ "c³ý~öY/±xĘ1•jõó@‹0#??¿‘#G>[\Þ†ƒˆ„РAƒâââ0_"‘¨_¿~-[¶7b¾ý yyy 6ÌÍÍ ¤—ę֭[ïÞ½ÛËËË9t&‘HvíÚ5pà@Éó¥ˆP«Õqqq}ôÁËM Íjµ†……}úé§!€ýžG¡(Ê ×{úû獵»Ó4²Óï·ß®¬¬¤ž¯t O¥R 80))ɼµ»K—.ï½÷Ô«Ä_™L&‰DòùçŸcW|Üà¾\²dIXX$fq^„j¬3 yóæ§OŸ.,,lß¾=ŸøR©üç EBBÔŽ}È×b±ÄÇÇGGG?zô¨²²’³×ºìÝ»÷—_~Š£®ŸGµc¿ÅlVxz¶Ž>¸f9,ìÚ?v§écÆ8ЯÁª=Xg†éÞ½»§§gvv6^www÷áÇþùç`Ð6 6¬|ppðË/¿œŸŸ_\\ †V@ЪU+r(Æ«µEù‹ã8nÆŒOžÈ,êðÛúvçð+š¦MF£»·÷wË–%¼úªF£¡y]4 #¾ØIØ\‚ 4‡‡Tºuww þIUíÿ|† ± $$D @4 _R­ ò5 jµê? ;b ¦<´‚. —QZZZ­77p!«º‚Aø®‹ÑN±Xì wQ\\ŒkùºÒ a:b`Vç0ðæööövñØAGb±ØÁÐn¾€­ŠÅbéµ]ñm6x …B¾ÚÍÙ#•JemÞÜX¨…—œÄMÕj5²{•ÃK9Ž+++s !A`û†@\þñ]è =#»"…‚°fÆòòrG6B’pAZ,@9ø_Á]ÈwOEv÷б œŠß Fš\wȇ‹V¥RAzud?(°&°zxÊxëÌ„£Jñ )Š‚›Øa}0Lí0ÇÐá&MšDEEÕ *»ví^ü•Õj½uë–ÙlöòòjÙ²%£AÊE‹Åâëë뜑«!ž¨¨Í§ëíÛ·!qJLL ÿ´ñµ±ÛîÞ½{ÅÅÅ M›6žQ A¯×·mÛ¶^‹ð矪T*ˆ‡4A”••ƒ«B*‡íÅ0L›6mêÕÑ;wvjõ¹¹‹‹‹]Ùƒ4MçæææååÅÄÄàÜ “$9sæLµZýòË/8p   <—8{P䋱bŽã¬V«¿¿ÿ–-[kÖ,­V X‰+«½ý~ÿý÷¡C‡.^¼Ö====!!á£>‚<‡ŽÀða±X.\8tèÐÌÌL¼/^œpåÊgïYÒ决¦ÈåòßÿýìÙ³ .ŒÇ\xF@@ÀÇlµZ·oßÎï®Î¥vèÈ‘Xµ¬TÑCügl6›P(¼{÷nRRRVV £)))³fÍáâ9‘U€U¯\¹2iÒ¤œœÜrÏž=óæÍs°4²ö6oÞ¼½{÷ǹ¹¹'N¼zõªX,®Wm¼Ð õñãÇ'Ož,‹¡&~Œ ³Ù¬R©&Ožœ“““‘‘¥JüWúrþ°ÑTZwwwˆŽ(++S(#FŒ9r$Ø_°M|×®]AAA’†br@'///’$¿üòK½^ïíí=zôèÄÄD¸É€U¦¤¤=z488箋ÅÁÁÁGXõå—_ž0aÎXÞ +W®¤(ÊÓÓÓEÆî<677·sçÎ5mÚ4,,¬Z´ßvàåýÄ7nÜÈÊÊu6((hÛ¶mjµúäÉ“å Öh×®]J¥2 ÀÏÏ!”™™YTT´k×.xÕ¼yó 0{öìû÷ïc§ÖôôôM›65oÞ<::ºö Ъããã…BaM‰Òñc111µÛ\^ 9{B®É“'c{[III¯^½B¥¥¥ˆ²›=eÊ”nݺ%''ã‚X®w$T*Õ˜1cÈÎÎîÓ§ÙlÆÅž€„iii'N:t(€8›6m:tèNƒ5þüÕ«Wgdd Ë0ÌÒ¥K ‚HMMõññiÀR°,ëããÞšµe’$ýýýu:Ýs:Akä(_“Ùl>wî\Mß6bG:îôéÓõýUzzzzzz£ Ù]C]aÅÕ†6¬=/ I ‚>ø 77wç΀šÂ)Á’ lÿ×^{-**ªà-V.\øèÑ£={öÀÕ²¸CGaaaƒ ™!4pàÀcÇŽAD8 Ï 9rdDD¸í6l5œMص<ÙX»§N! À“'O¶ÙlPeûŸáÐå!C–-[¦R© ë+5€Ò-—ËgÍš¥R©þøãH¬ä°ÜÐш#æÏŸ_QQQPP€êׯxj-[¶ àëfþÙgŸyxxC I}A&“~ür¢¡ÓérrrÛ¶m[mü4BhÖ¬Y4M4Ls%ì nÞ¼YYYY­ ªäØmݺuÃD_çÖhJ…P(4™L=zôøæ›oÜÝÝùWºÍfkÑ¢ÅÚµkýüü@Å~ÎŽ CBB²eË m>¿£:¬ZµJ&“…Ïá…B±jÕ*ˆëÇëÈóòåˇ b0øõj`g êÔ©Óúõë%‰Cšy¸#}}}÷ìÙC’äË/¿ÜXiõ¯à\nUÞE’:nРAœ6m%ÿþ÷¿þùçÈÈÈÆÂo¡£Q£F:tèÝwß…w†‡‡¯ZµjóæÍ~~~ÎE À¬ìïï¿yóæï¾ûòï‘$ùî»ï:thäȑΠZßE€à¿Aƒ-]º´¬¬L.—cäMÿÏþ¹åLÕ®ôâìS= 1J"t¡aƒ2nu†„„L™2| #""’’’Îí@{×WÊ¡#µZ””‹;v,Óò; ”ŽãÞ}÷ݸ¸8øURRRtt4¸»;Œ â&Aí+a{ø,ÂÞêÖ­ÛÚµk÷íÛyÇÄbñ­[·¾øâ ©TúÞ{ï!» ÇÙ1vW–:r¦bõfî§OŸºrÌA׿GeùA7zï½÷´Zmxx8Üí¸{ç@mWˆ‘üHeš¦M&“@ ˜7ožÑhŒ‰‰¬Ô¸#ç@mˆŸ.++8p`xx¸D"&“ —àÇ+++óóóë¬ã6Ø0!Ç–Ñh|å•WÚµk÷ôéSõB³fÍ‚jßpmC|2B¨¼¼¼¸¸Ø•ŽÔjµ³”Tµ‡"‘èþýû.®,ŒÛÛÛÛ-áîîqh|ù…³§Ì†È&×Ã0 ‚ÐjµpÉ9L ò$šÍf~JqlÍAN/À }jµÚAói@@À½{÷\I[c IÒËË Ç<ÀÃ:aw°æ8´x'Á½½½ïÝ»çJù8ÜQTTTõiô Ai½Üìùj™Ã‡œ=’›ã¡šœÝ$]/T˜@µb^-ERžÃÇÎIðúÖK´ÁÃàw„x0WÊÆOB>šzuä€W8²2pb¨¯`ÝXòñÿö¡9ð[G6L+âÕLõm×"üý¹¹ÿמ³ý„ÿøöÿ‘UPêª>%tEXtdate:create2017-06-06T01:31:12+01:00™Ò¡%tEXtdate:modify2017-06-06T01:31:12+01:00è¬IEND®B`‚puzzles-20170606.272beef/icons/inertia-ibase4.png0000644000175000017500000000137313115373732020316 0ustar simonsimon‰PNG  IHDR€€1|øgAMA† 1è–_PLTEÀÀÀÿÿÿ€€€€ÿà •«bKGDÿ-Þ oFFsÁž{ßtIMEá‚is4 vpAgAAŸ{èIDAThÞíWQnƒ0 ’ ¬;AF¶DoЩ˜Æý¯2 ì bÓ·vÒ–'¡òŠülÛ ÆTTTTTTTT<'ާ{ ئ¡ÔÍ×w£p#±! è‚f.¥@×4íJ’j«hFø@º1A+ÐM)†nù A#à¢}_Ýøõ‰× ØY æÑ­É0g@²Y°TZ+ðrz^:*ÐjÜ"6žÊ£å,°.åQž…ÿ'°â­«Òñ:À+î¸áy€O$|&âSùg÷¾3éö €öÙ*ÝCÀ–¹,|‘³^ÙÀ¶¾3p |ìÝÎçÅ^¨KÎ]ah¯™KÎùÌÜ €ºÌxaÛ¡‰ËŒóóÃn«ËŒ—ÏÄáâ’sáü`hÑE—6_–}ç7¸,G È ¯‚TŠ>KFÆåB‚+î¼áy€O$x&âSYÀï T9¥mrÑžœ·¸hOOª\;+G>õï·B>Ý…Ä›kß_¼Q†À¿FÞ öƒB« Ág·Þ½õ}Txâæ•á}ß™Š/ôŠŽÓzΙ%tEXtdate:create2017-06-06T01:31:22+01:00]¦ó%tEXtdate:modify2017-06-06T01:31:22+01:00fOIEND®B`‚puzzles-20170606.272beef/icons/inertia-ibase.png0000644000175000017500000000345413115373732020234 0ustar simonsimon‰PNG  IHDR€€ôà‘ùgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<§PLTEÕÕÕªªªýýýÿÿÿüüüÊÊÊËËËûûûÀÀÀÇÇÇbbb >>>===cccßßßŽŽŽWWWÁÁÁVVV­­­ÔÔÔjjj®®®¬¬¬¶¶¶999 :::···---ÃÃÃ,,,––– ˜˜˜Â«««ÈÈÈ ¸¸¸XXXTTTddd<<<¿¿¿¯¯¯???ggg;;;‘‘‘ÌÌ̹¹¹fff———™™™llleeekkkUUU   SŠŠ¢¢¢q½½™ÿÿuÃÞžž£££tÂÂcgc!1!  9E9  xÄæú  :F:  ‹øÿŠ  ÈÇ  :E:‹ˆ/B"""""""""""""""'>Ò!‡Ù/?•æðàú‰’BHNQž¤¤Ò œNã'žáÉTžfy²ÓgˆIszrróÎj/¦ËU¿ XÀáIèÍŽd{1|ßù ¦·úòy ]ô"q‰EÀw©ÔòîÒ2gòŠËIj*+ªL9WJ±÷WÖp(¯M2¦¶Ê žëµ9âjnG¢Š$sêtŒk¶Ç49 WZ*›4dOší1ÍžTn^ÿAу¥C3ð‡Të7G5ÕpÈ` ö@á! Õ4 (k’«x„À 'Àjß¼-àŽ@t0E_R2 Gµ´ò[ [°•0 ©©¤•ðv?ìZЮ  ì<Ûcïðû ê0_ ýH¨³½J]<¯†aƒ ýW¨¬ïD”b»hE\PC“¶#Êj×?gäÑWVm­_Ö8 ê‰ô„Œ_tä1ÿnaùû/ìæ¾'<ˆ²ú`ÕtÝkÖ^lnìjU¹[¨.èQö(¨Å¬Ó¸kµÕ(OZÛ œ¯Š¥8|ÿu”wÇ ‰Íl·çǾ?ÀÈÿ7ð¿èxôöõ‚18³@oÿ@/ð`Nî/Ðæþàƒ¡‡ƒˆ ‡ú êY*H´ê/8ªo© Qr¨¿à°¾¹‚DÇÁþ‚Óú¦ ‡ú Îë+HTì/ÄQßPA¢âñ÷õõ Rl®ÕŒ§¿@ª¯Ubs¦›Ûhú†ð ôi0ç ðØæʆoæl*Ȧsä<° ²å¿ ¿¿@0±uæ`!Ùf%„9Ô_pn Û^ @öœÈ„«!È¡þ‚C™¸9Ô_pd ;"Cýê°í ÉýG¼+ÆsânLœó@@ôŽ‘€ýü=g ÍÐrVâü%gæ Ü;<2:6:2ìÅ8³0? ñ¢'ã“SO§&'¦Ÿ•X8«4? òò™ç³sÑÌο¨2qVp~@áå /çô,.T8³8?åE3Æúaƒ¥³ ÀóQþêõœ9Ë+g€ç"Ü;>kX] ©œý'ˆÍß¼³æÝ{ªã9 ŒLbëÜøø ØuS`lØüì¦Àè&ðå«›#ßðs`ËMï˜ÀŸÜàù÷N¯Ú¬ g€ç¢ü×¼E`{GãÌðü@”—Ì,šêï.µëœYœPxÇ®±þïNgçTÞ1³¬ž«ÛK&Î,Íh¼aemo}csãÏÞÚN»…3 óÚß ï ·öCgæ(9³q~€–3 æè9³À¡ð£ø ªuáXjÇ%tEXtdate:create2017-06-06T01:31:12+01:00™Ò¡%tEXtdate:modify2017-06-06T01:31:12+01:00è¬IEND®B`‚puzzles-20170606.272beef/icons/inertia-base.png0000644000175000017500000001720113115373720020053 0ustar simonsimon‰PNG  IHDRAAflŠfbKGDÿÿÿ ½§“6IDATxœíÝmLTYšðK‘ÂA;´šô¬òaÆ.Qg·CEÚQ+hJ$ˆi]ÁT“¬;^´ÜÁ’B˜Nw•Äm„ì¥ZÒÓ$:4|-ц`ifXÂ`ÒKº»“®6㜠„—BöÃí&L½ÞºuÏ9÷9÷ù}š@Õã™sëß·¸õòB`½Áz¡¨`†‚ 3Œl˜a„`à #f!Ø0ÃÁ†F6Ì0B°a†‚ 3Œl˜a„`à #f!Ø0ÃÁ†F6Ì0B°a†‚ 3Œl˜a„`à #f!Ø0ÃÁ†F6Ì0B°a†‚ 3Œl˜a„`à #f!Ø0ÃÁGúÀ~c¤q»wï&:Ÿx†ÂÿÆÇÇ¡ÏÏËË{ã ROˆzzz ïôý'4y>—fÜhyy™Ðdž@ßöž››ëïïø«þþþùùyÊëá†×ë}üøqØ›QÛÿÝK©±ª}üHÜÿèÑx.ÌÌÌL{{{OOOZZZVV–ÿ z{{kkkÍfsQQц 诲o¾ùFÁigjj*Ä  ï¿âë§¼ÿJav¾ÿþ±cÇæææîÝ»÷É'Ÿ¼Í7îÞ½;;;{ìØ±`ÿ­U•‘‘‘ƒ&ÓÈÈë…‚ „~Aßõ¯ŸN€&çá••‡ÃqçÎŽŽŽ;v„¾ñæÍ›/]ºd6›ËÊÊ&''-KLL uFjddä¼Í–YUuÞfkilLOOg½¢Àèï¿Ûíîëëóù¡ÝnÏÉÉIMMt¯Ùœ‡‡ËåúüóÏÀU;wîìîî~ôè‘Ãá º6ÙFGG­…_|‘uñbÉ­[ÖŠŠááaÖ‹ Œæþ{<ž¢¢¢Ó§Owvvúüª³³óôéÓÅÅÅß~ûmD3¹|üDƒv†ïß¿ûöm‡Ã‘œœÑ“““Ç­[·njúÍDãI—«#7—㿇+˜áˆÉˆ±<þ½¢¢¢¸89×JãããKKKWç(¾B^ÑËpÿÙ³gURRòðáCEFÉQŒU`jûôèÑøøxcãââB¼zÄÓãGYô2l4ÇÆÆ^¼x圩©©¯¾úêÀЬJ6‰1VI€ŠûŸššj0bcc#»gÏž`/ Ü=~D/ɉ‰f³9ØÇµ¥kmmÍÏÏ×étЬ*ac¬ž t÷¿ººzݺuMHH¨®®qþ?J¡ú÷pqqñƒÜn·ì ããッƒ……… ®*!b¬ª‹¨íJJJcccBB‚ı:În·oݺ5ôÍø{ü(‚j†“’’jjjÊÊÊ^¾|)ãîÓÓÓV«µ¶¶6))IñµÉ0Æ* °@wÿ322šššC?©Ž]¿~}ss³Ñh ;“ËÇOôh_—ÎÊÊ:qâÄÙ³g§§§#ºãôô´ÅbÉÍÍÍÌÌ$´6Ù|b¬Î‹hîFFFooï¾}ût:ÿ•길8N·ÿþÞÞ^)qùø‰ƒ×–,ËÁƒóóó¿þúk‰wÏÏÏ?tèPô=#Ä`0474|j6÷_»Ö~òdsCƒ ,¢¹ÿÛ¶mkkkëêê*((ðùUAAAWW×7Â>…öÁåã' >óc±XÞyçÒÒR“Éd±X¶lÙìÆSSS­­­ƒƒƒµµµ*ÿ/hzzzKccEU•š¿O`±ÿz½^¯×···¯ý¡Õj•7×ÇlÌÞãqäȧӹqãÆãÇ—––¼MIIÉñãÇß|óM§Ó ⤧§ ¨9À« ï?ôõ+ˆåg“’’.\¸pæÌ™`_‡o6›[ZZxz@U ï?ôõ+…ýç‡u:Ý‘#GþŠãÿvúóz½ÔšÖ¢¶ÿ„Þ>©ÔúYíôØg ‚°¼¼üøñãèß„„ä½ÿ1¤ß\Žo^GÇCÿ0öë²ûÏv>¹á"×¥¡÷»B‡ûÏ7À{½^ž¾a­í¿ÏéZ=$RÍ0Ð~Wnàþs ð÷xÈx‘î†>?"ÜuœáH‰ýÀm¶ó6‰Ã }>ip÷ÇívÛívŸÚíöh>© ­d˜t?0ôù¤ÝýÉŠÓD†I÷CŸOÐý!ÑŸLÿ&Ý }>i@÷‡D2!œg˜t?0ôù¤ÝBýÉ„ðœaÒýÀÐç“wHô'“Ãm†I÷CŸOÜý!ÔŸLŸ–ÓÉa†>Ÿ4Ðûe²Œ;F‰Ã Ëï–v˜¡Ï' èþìþÞ§Ÿ~êZ ±?yuŽŒ òð–aÒýÀÐç“Æåþ¨¼?™· “î†>Ÿ4ÜúxË0é~`èóIÃý¡· “î†>Ÿ4Üúx˰@¾ú|Ò€îÜþd3,ï†>Ÿ4ÐûC¨?™>3,ï†>Ÿ4¸ûC¨?™n3,ï†>Ÿ4¸ûC¢?™ž3,ï†>Ÿ4 ûC¨?™Î3,ï†>Ÿ4 ûC¢?™þ3,ï†>Ÿ4 ûC¢?™„ØsçÎý^¼x±úÞÑ¿þõ¯ N~þü¹ø?BTW®zûí·ÿá'?¹Z\¼óŸ¿üeKcã{ï½'å_yñâôù¸ÿ²çoܸñý÷ß?tèÐ~ðƒ?üákõ‹_üâW¿úÕÏþó 6D¿þhhâ<,û‡ õCŸOÜýÑëõþmÉV«•ÉUh€¿#^±糂ûC‚†ÎÃq‰Þyn¿+pÿ£¤žr”2 ºß•¸ÿÃþa„Èâ¡z,ôþ^èë‡>ŸÜp^Ó z/ôõ£ÐT”áÝ‹õrˆóz½?f½ ùT²þ¹¹¹þþþ€¿êïŸWùüèiëõá(Aïï…¾~333ííí===iiiYYYþ7èíí­­­5›ÍEEE¡ßMÅd¾RTtÖö÷F„m€ïß¿ìØ±¹¹¹{÷î}òÉ'osãÆ»wïÎÎÎ;v,ع”Õ|©â<ìv»ûúú|~h·ÛsrrRSS™,I…Ä~Ý̪ªó6з[*beeÅápܹs§££cÇŽ¡o¼yóæK—.™Íæ²²²ÉÉI‹Åöûeýç»Ýî¾þ¾ÿøóó?Ï¿œOLNÜôÃM¦÷L9Y9©©©‘ÎWã {<ž+W®<}úÔÿ›õ;;;»ººÒÒÒjjjRRR˜,O=VûuSM¦íÛg=yÐç–”åp8\.×矞œœ,ñ.;wîìîî>{ö¬ a?ä³v¾Çã¹Òtå©ûéÒ?-y?ö ?„MÂìŸggÿ8Ûy¯³ë|WÚ®´š 5ÍWËçÒPú]™ƒÞ?¬ û÷ïß¾}ÛápH°(99ÙápܺuëÁƒç úÙ©á¬á…ÉïU¯p@Þ„xAx[Þ«Þ…ÿYÎÎûYžËå’8ŸfÔïÊôþaÍÌÌÔÕÕ]¿~=Ò‹Þzë­–––Ë—/ÏÎΆ?44Tþoåó÷æ_W¼‚}-Ï:aùâòüyë%«Ëå ;Ÿ6†ÕïÊôþaeµ··geeEs‰d×®]&“©££#ô|ÇSQ[±x{QòÇÊO…Å[‹¶Û³gÏBÏ'„M†aõ»²½XYsss===gΜ‰rιs纻»ý_×];¿®©îUÕ+IýTX´-Ö5Õ…˜Oƒ ƒëwezÿ°â\.—Á`ؼys”s¶lÙòî»ï>yò$Ø|·Û=æ[þedoA[>¿<úߣÁæ“Ãàºt”ý®*ùò¢äôëò~¥:;;[©o`okk 1ßyß¹ôÏKAÿ&AX:½äìwêõú€óÉ¡w†ÛïJôþaèG½9²ŸÇ¼¿gð-"ªxŸ–Êû]i‚Þ?Ìz!üXÖ=,¼xÎàÚªÈ0Z…ýºÌ-üeAóÒ• læÿÂà#˜auÁ~]æ“…iY÷|!¬O^¯ðj$À « öë2·é‡›„ÿ•uÏ? ›íesèen¿+eÐû‡¡;¼÷pœSÖãón|æ¾LÅ׃ó0¸~Wú ÷“Ðßß/~¨ z%%%> 6ÿè‘£ñ¿¤¾‡ð{‹B\W\vfv°ùä0È0¸~W& ÷+Îh4ŽEÿÕœSSS_}õÕ‚ÍOMM5ì4Ä~áã³9vÏßïÑëõÁæ“ÃæïaXý®¬@ïVVbb¢Ùlöq|éZ[[óóóu:]ˆùÕåÕëê× ¿—<ôwB‚=¡úBuˆùä°É0¬~W† ÷+«¸¸øÁƒn·[ö„ñññÁÁÁÂÂÂÐóSRR¯4&üc‚ð; C'èNêìuö­[·†žO³ëÒ€ú]Ù‚Þ?¬ ¤¤¤ššš²²²—/_ʸûôô´Õj­­­MJJ ;?##£é_›'Æ~ôoãE!ößcןXß|¹Ùh4†OË×– ô»2½XAYYY'Nœ8{öìôtd¯áNOO[,–ÜÜÜÌÌP—Ž×ÎÏÈÈèýmï¾Á}ºíº¸ª8Á%Ïáÿá¹ <âªâtÛuû‡ö÷þ¶W °”ù$0þ.žmÛ¶µµµMLLôõõµ··¯ýUAAANNŽv.b…f0šΛ͙UU?úHËß§%~gU~~þõë×wîÜ)å.ãããV«577WÊG}æ·ÙÛ&&&úúû¬Sš¿OkËßm1í5åüÇwψæ+N߉§×ëõz½O†ý_5Nì×­¨ªÒr€Aˆ‰‰±X,ï¼óNii©Éd²X,!Jº§¦¦Z[[kkk%ž!ýç‹Oë¿x@ʘ¯8|Ÿ$b¿®–¼êÈ‘#N§sãÆÇ/-- x›’’’ãÇ¿ùæ›N§3Ò€‘ž¯ Uœ‡’!))éÂ… gΜ V7a6›[ZZd¿ÌCz¾RT”a•¿}z/ôõ£ÓéŽ9ðWŠœIÏžŠ2¬fÐû{¡¯…€ýÑ…ýÃa`¿.óù¸ÿ¡ç“.âáº4öë²…ûÏ&D#ýºª¥’ýW?®®ia¿.[œí?xŠï~]õÃKÄÕy˜¤ûugð<¬:«ý·a¼Jì¿}ôè‘Ãá º6¤B˜au!ݯ‹øƒVÒýºˆK˜a!ݯ‹¸„V ÒýºˆW˜aµ ݯ‹x…¯-©é~]Ä+<#f!Ø0ÃÁ†F6Ì0B°a†‚ 3¬¤ûu¯0ÃjAº_ñ 3¬¤ûu¯0Ã*Bº_q 3¬"¤ûu—0ÃêBº_ñ3¬:‹åàÁƒùùù_ýµÄ»Œççç:tˆIÿ-b ?·¤:¤ûugð<¬R€úo[xV/(ý·ˆ-~2ŒýºlñºÿêÇI†±_—-܆°!²xèÆ~Zœ¯åù䆋h\—Æ~Z„ÈüÚ’Ä~ZÒý½Ôúwÿ-¥Æ¢ÐÔßÿLõšå~ZÒý½àúQD _ÀçáÐ&ÝßËe?ðÈÈÈA“idd„õBØt|9ymi-Òý½ôûÝnw__ŸÏív{NNN4åL>FFFÎÛl™UUçm¶–ÆÆôôt¥&îÿðy8Òý½4û=OQQÑéÓ§;;;}~ÕÙÙyúôéâââo¿ý6¢™ŽŽZ+* ¿ø"ëâÅ’[·¬ÃÃÃÑ…\ÿ3o&ÝßK³xhhèÔ©SÃÃà ^¯×ç·^¯waaaxx8//ÏårE´£££eååÝÝ©&“ ÛÆâ›7Ë++5cˆýÏ\e˜t/Í~à¡¡¡òòòùùùׯ_‡¸Ùòòòüü¼Õj•cŸ‹´c ýÏ\e˜t/µ~`ÇSQQ±¸¸(qìââ¢Íf{öìY¤ë `‘c ´ÿ™Ÿ “îï¥Ù\WW÷êÕ«ˆÆ...ÖÕÕEt—i*ÆpûŸùÉ0éþ^jýÀn·{lllí[ÐVÖv¯åååÑÑщ‰ ‰Ë`‘vb ·ÿ™Ÿ×–H÷÷Rëv:KKK2Æ.--9N½^ö–,ú.Æ'OÚëë÷îÝ+ca Àíæ'ÃÐEÿöI¯×ÛÑѱúÇX°wÛG`‘Fb ?Ï¥9³F”£dX¤'Õà`†µ¥üâÅÕ•‘X´Ýh<\YYùᇊ¯ E3¬-M _Ö×»dÜwÒåú²¾¾þêUÅW…¢ÖƒÁðqSÓo>ø ÒOº\¹¹ø÷° a†Õbü{EEEqqr®5ÆÇÇ—––®Î v31Æ«?&ÝßK­øèÑ£ñññ2ÆÆÅÅI|u$¢k$ÀpûŸùÉ0éþ^jýÀ©©©ƒ!666¢±±±±{öì‘òâ°HbŒ5`rÿ3?&ÝßK³¸ººzݺuMHH¨®®Žè.ac¬ ûŸùɰ@¾¿—Z?pJJJcccBB‚ı:În·oݺ5Òõ„ˆ±¦,ÚÿÌU†I÷÷ÒìÎÈÈhjjJLL ý¤:66výúõÍÍÍF£QÆ’„ 1Ö`€°ýÏ\eX ßßK³8##£··wß¾}:ÎÿJu\\œN§Û¿oo¯ì‹|b¬Í‹ ö?ó–a|/Í~àmÛ¶µµµuuuøüª   ««ëÆ2žBû3 Í ŸšÍý×®µŸ<ÙÜРÁ‹Àõ?sø™Òý½ôûõz½^¯ooo_ûC«Õ*oZ0ééé-UUZþB<`ÿ3‡çaéþ^.ûÓÓÓ‡´àU€Ž/‡çáU¤û{±˜oPŽ/½ ³ê§%ÝßK­$™Pÿ3¥ c?-B„`ÿ0BdñÐ? ½?çãühæ“.âöº4BÁóuiÊ|þs®Ô€çææž|øæÍ›oÐÛÛk2™ìvûÌÌ åµi”ýÇ « þ[.Ú|.­eûÁõß2§ñýÇ GÅãñ\¹råéÓ§þÍ ]]]iii555)))Òg®ößJoßûoů’9wîœô :ÜŸKGƒD?0Äþ[VpÿE˜a™Hôí¿e÷fXBýÀ@ûoéÃý_ 3,‰~`¸ý·ôáþ¯…Ž¡~`¸ý·”áþûÀëÒ#Ô ·ÿ–2ܘa©¨õ£€pÿƒÁ +@ƒo«Pï?þ=Œl˜a„`à #þ=,Õê%¦¦¦Ï>ûÌÿÍ}aÅÇÇ–••)½4MÀýÏÃ#Ô ·ÿ–2ܘáˆê†ÛKî¿̰$úáößÒ‡û¿fXBýÀ@ûoéÃý_ 3,‰~` ý·Làþ¯Â ËG¢bÿ-+¸ÿ"ÌpTHôƒë¿e÷_Àׇ¡l?0¸þ[æ4¾ÿxV)@ý·\´ÿxV/(ý·¼‚²ÿ˜aÅú<ªúûoUB³ûÏ¥‚ û‡" û‡Ãà Ÿçó=ŸÜp>—F6ö×´Ôßï*¡þ[$éýWíñey†Ò1Ë0 ~Wí9h2ŒŒ°^Šƒ ¯¬¬´¶¶ÚíöŽŽŽÚÚÚM›6…¸±Øïúë_ÿúÚµk­­­!¾ÈŸ!·Ûm·Û}~h·Û£ù}###çm¶ƒ6Ûy› VŒIï¿Ê/ƒ¿‡Áõ»†@¢ÿ–‰ÑÑQkEEá_¤šL?Ú·Ïzò¤½¾~ïÞ½¬×éýq|iŸ‡!ö»C¢ÿ–‰ÑÑѲòò‚îîT“I„íFcñ͛啕ÃÃì— éý‡r|©fh¿k@$úo™ð °Hý1&½ÿ€Ž/Õ íwõG¨ÿ–¾€©9Ƥ÷Öñ¥—a¸ý®þHôßÒ"À"ÕÆ˜ôþÃ:¾ô2 ·ßÕ¡þ[ÊÂX¤Â“ÞpÇ—^†³³³‡"£ÚÚÚ‚}Œ‚(ûo_ ,R[ŒIï?¸ãËþ½–PpÓQ€EßŘé N¤÷îñÅÏ<( f Ök CF€Ej;¯EzÿU~|1ÃÚR~ñâáÊÊH,Ún4®¬¬üðCÅW…¢Ö–¦††/ëëÝ2î;ér}Y__õªâ«BÑÀ k‹Á`ø¸©é7|iŒ']®ŽÜ\oÀÔ̰Tãß+**òo">>¾´´tuŽâ+”HFŒÕ`Òû÷øÒË0Ü~W„úoiŠ(ÆjðZ¤÷Üñ¥—a¸ý®>õßR&1Æj °@~ÿÁ_z†ÛïêDÿ-}ac¬Â‹Hï?¬ãKõïa ý®þõßÒ"ƪ °@~ÿa_ªÚï‰þ[&ÆXÍ‘Þ@Ç—öuiˆý®Áè¿eÂ'Æê°ˆôþC9¾ Þ/m±Xbbbòóó¯_¿¾sçN)w·Z­¹¹¹jë×ûo'&&úúú|º3 rrrÔs+4ƒÁÐÜÐpÞlάªzøÑG-ééé¬éýq|d\¿kXÊöß²’žžÞÒØXQU%À«Hï¿Ê/³÷xêwÕŽôôô¡XF,?{¥ß!5cÿùaõ÷»J¤žòmÒlƒ'¾_!ذ!²xèÎËË{ã R'üžžèý´ÐçC?¾¤×Ohò*Ï¥ÉmÐÚ/D¬@?¾Ð×Ïþš–l^¯7¢o¨Um¬DZëוx|UÛ_éãS6ªþæ›oœæñx¦¦¦ˆ¢DùøÎÌÌ´··÷ôô¤¥¥Ìpooomm­Ùl.**Ú°aCØèãðui 0ßB_õ÷WS{|~.-Ûíîëëóù¡ÝnÏÉɉ¦ü‰Ò뇵?+++‡ãÎ;;vì}c±¿Úl6—••MNNŠïÕ§³Nj8Ï0ˆþذ_×OýÕŠü\:,(ý±Á`¿®?žú«•Âm†õÇ„ýºþxê¯VŸ†Õëûu⦿ZY|fV¬?ì×õÇSµ²8Ì0¸þXد7ýÕŠã0Ãàúc}`¿n@ÜôW+ŽŸ×–àöÇŠ°_ÉÃO†C€þ²>éõCßãð¹4Bš‚F6Ì0B°ñó÷ðê%–¦¦¦Ï>ûÌÿ̓aÅÇÇ–••)½4IH¯úþ `8<ƒëõýºqÓ_­83 ®?ÖöëÄMµâ8̰­?Ööëúã©¿ZY|fV¬?ì× ˆ›þjeñ™aTl@دë§þjq›aNl0دë§þj¥ðóÚR@ úcCÀ~]<õW+‚ó ‹TÞ–Æûu}ð×_%žŸK#Žaõ*Mœ‡—°¿ZD/Ã^¯—m3ôÏ»ª¼¡’ÕñUª¿šùãS6J^^^~üøqôo²Aêýø‚^?ö#DéþaâF…×¥‚ 3Œl˜a„`à #f!Ø0ÃÁ†F6Ì0B°a†‚ 3Œl˜a„`à #f!Ø0ÃÁ†F6Ì0B°a†‚ 3Œl˜a„`à #f!Ø0ÃÁ†F6Ì0B°a†‚ 3Œl˜a„`à #f!Ø0ÃÁ†F¶ÿÿ2FÚâ±éIEND®B`‚puzzles-20170606.272beef/icons/inertia-48d8.png0000644000175000017500000000277013115373732017640 0ustar simonsimon‰PNG  IHDR00`Ü µgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<PLTEÕÕÕ×ÙÙÔØÔÛÜÜÊÊÊÄÄÄÈ¿¿¼¼¼ÏÐÏñññìììêçê<<<­­­âââ´³³}€}…ˆ…¤¤¤üüü·¸·ŠŠŠNNNàÞÞœ››|||æØæ ž¡ž]]]333EEEuuu§ª§µ­­………$$$cccjjj“““+++“ˆ“ͼÍjuuakkaœœ{ÓÓjyya||~ÜÜ_‰‰TTT›þþ£ÿÿ^zzˆçç“ööZ„„]–––ûû‹ìì^ššµ¨µ¬¤¬8’8 ¢ FŒFœ“œ¬þœŽœŸ5“5‹”‹Î¼wŒwâÐÁ°£ž£ìOO$”$Ù¢—¢=Œ=x‰xæ×æÿÿÿ¼ ˜sbKGD^Öa»tIMEá‚is4ØIDATHÇU‰vÛ6ˆIØ Z’e”ìÄ‘•XÜ8M#å¨ÒÆ®›;=Ò+ÍÿÿFgAñP¿¾f©Gàvvw Ñ6)®4ùãf>(‚¶‹†›P)?Ú°r¦Ð'¦ý=ô? t9¥©&âßG±÷ á$ ?a:4[µmo™Š›J®¥¡‰›íÝž•Fõ„Ým¤ì¥ÃØq4›¡©;p4êK¥”Ä¥¬î´Ša®¥°q®„Yᘪ´ƒ})ûÊYga#ê´åÖAzý{:!*¨ªe¡]_Y笲Ày€Ç¨ìðf:鿍F½iÕ#ë¯D©õ ;e:쟦·ˆTS ÎU„jÞå×Koøß&j$ ”àìA–ŽZ5½±dÛšõô98¤`=ˆZU’ÙMïŒ*É|–øÂ%½}ií: µÄáâá8½5àò“ÜÉY7jr(Ð8騬ïC[¡2ù*ím3m#Ô™O§>i[5 ~¦7ÓüBb :3‡SIVÙn'«—×:ÔšŒžë0Œc­#ÒQHbÈboj& ã÷‡“1Û@™áß2º @3N|ß}œþ:1QØ<gÜM½Þþnó»§÷Œ2Š8‡ù7÷¿e! Ä_pxé ½þÝÅòôÄ(D*|øhùøÉ‘"öAÙÒc‹lü¿[,3Âiòþ«Å 1OS›±3£k€÷‡-2ôðébÅ×Ô‘5s<ô1բɿ_µ¼‚ÌX®V«e XÛ05%[QŽ˜ÒÓŠRÈ”¼íuL³QJÄòô×®IZqꤓÍ>¬ËÊ}ÅËj×¥gÄe ÂÆÊÆIß8‰Æ)4ŽøøpûØ'%z³Õ8+$kÛ©âÄÇ$AÌ\¯Y@¡½Êâ#ÂÍ¡¾˜ßË“_Uk†e…¯ÜRÞäå­#)Â,þÚ”dõƒZÁbƨÛEÙµpâ‡ùüY±;ú4‡ê  µ“³6G¼Eõ¨7ŸÿxQtTÔ,ß÷öêbBŸûNIM­Ñöõ›ðv_]™C+r”¼û¹ü2K¢Ë|< YŸ 1ûµüöÞl–µ˜¢>] 9œyÿßÿ¸3¡KîÎ ¦ú $ƒ´‹‹?A꯳¿wd$>²8MÊhï>|øçææF^†°ZÑ\ ¦='Í­ïf?>{-¤ïtëà¨# ¾P| ¬sÏ–Ä—™Û,ë®ò?b]¢úâŠá^¢f#‰%tEXtdate:create2017-06-06T01:31:22+01:00]¦ó%tEXtdate:modify2017-06-06T01:31:22+01:00fOIEND®B`‚puzzles-20170606.272beef/icons/inertia-48d4.png0000644000175000017500000000106113115373732017624 0ustar simonsimon‰PNG  IHDR00¥,ä´gAMA† 1è–_PLTEÀÀÀÿÿÿ€€€€€€ÿ‡œ=‰bKGDÿ-ÞtIMEá‚is4EIDAT8Ë’Qnƒ0 †Ë²í™¡}®ðºçŠN<#z…*÷?B“Ø D„ò‡óû·pt}È2ỹÆZ*cü#Aˆ€™“æ;Ä`€3@f¾IB 38u}{…øWeæ„î“ù™ÿËàÄqÙMpûáÿ’b“ƪ*h-îýqtUJžtáÝ® æ^à²%@Ö¨2@©q|áxÞõãl“–X5§{“:‡: ¿Ú¢N²¹(Ût_Ì©†´²_=`íQ5i¯((°Ôã4C÷Ðc’IQ¢šg‹½ÎU¥úQ‡õÌ7€ÖÎi§Wqì%Ì|.¿<9tÎ}¿ Ùä¯{Q²ûÚ9×…¥»K^[÷aðÀÙ pÙðrj ØR}ÎéËt÷0™Ü€$€DAE ƒB-„ñ’ BÅRÊlIåðB­¨V>胩^¨ZÑ-* Ö $³ ° Z !â–d&Ó3™™îé>§÷á@Ó|Xÿ‡ÔL÷™>_ÿ—ïûÏ®­­ ü‘ þ¿¤v>qá|¶m;·Ò.:WÜ_mÛv_wÿê&fÛ6¥4Çq–e%“I÷R„Çq„[é|e „l{öh÷[¹8žç=Ïàbæ ŽÇã”RQ1Æl?„P,Ã{<˲E¡”êºÎ0 ‚ B?BÈ0 Y–ÇŽKÊU¶mcŒÛÛÛ-Ëâyþêë9÷B^¯×ëõ*Šâõz‹ŠŠV­Z5kÖ¬K—.3FEvW–eY–EÉÏÏïêꪯ¯‡fddȲüí·ß=z4//-cëݯê6ÆXÓ´P(„1v|‰Ýx™cxž'„|õÕW'OžlÚ´Éçóõ÷÷(¥–eI’´k×®ÎÎβ²2EQ Ãà8nîܹÁ`ðÂ… Ï<óŒeYÇ™¦ÙÝÝ*Xç΋ÅbB'd1¥”ã¸d2ùâ‹/®\¹2‰@ÊËË›ššE1M“Rª(ʱcǺºº–.]š““Ã~PUµªª °wï^¯×Ëò !„‡6žçÓ*i@ ‚PPPðñÇ8p`òäÉ¥¥¥¬ô’Éä›o¾ÙÝÝ=|øp€iš‡*//×uù†=Ò××W^^~úôiw ì¡íFÏ]Ï!Q;::ª««wíÚX½zuss3K[Œq___uuõ¶mÛ „†a”•• 6Ì4M÷û9¸`Áöù+@„Y–:TSS‡‹-ÊÈȈÅb˲Bï¿ÿ> ;Rnc4á÷û%IúÍš¿ a*•=ztII Ïó€D"¡išÃ{„¢¢¢™3gRJY^õöl1!äÐ ÇgÌ˜ÑØØ8uêT€ ,Îß>ú¨¦¦†ñJCCà[2Þ ñx!tNº®kš¶bÅŠÜÜÜT*åNÉ—_~yÒ¤I—.](Šâ÷û÷íÛ—™™I)uv%„deeýøã„ÜÜ\Ó4ï<‡˜!„R©Tqqqmmmyy¹$I€ñãÇ×ÔÔ,_¾<™LbŒ™/çÌ™ …¶oß.˲ã UU÷ïßäÈV€,¯oRh`0mˆã8„P"‘(,,ܰaCQQ`õêÕ‹/N$nõµ,«²²Ò0Œ/¿ü2³´Û²eKGGÇ /¼ Š"Ky!ÏóŒon4ŒñœÉ9ý[u§µ¶¶†Ãá|Ðï÷³[¡h4Ê´ŒRªªêÅ‹%Iòx<¦ijš6räHÃ0˜ÀeeeɲÜÒÒ‚1fÏgi瀀& aqq±³õU@Œæ£Ñ¨»eaœˆÇd@ ‚À^@VSBŒq*•bޱ,‹‚1vb!ôù|”RMÓœ]8Ž£”Ž9Òñv¶Çggg_¯Ûx Š¢M){(cHžça2_ò‚ dRš2 SŽãR©T,ËÉÉqô1¾óÎ;ªª¾ýöÛmB»»»)¥N"¦k3Ó4½ŠòŸýû?øôS;•‚Y–E)e½‘{™(I½—/¿óÁí'N(Š’2Mç.«»T*ŸàèÑ£ õõõííí’$Y–•J¥˜8™ÔW«—Ò ¿¿iÇŽƒ¶í­ªúûæÍ4™äE1M !²ªöœ?ÿù®]#ßxã_'Oþ÷ðaŸÏçæ'ÖÕPJ_ýõÅ‹³˜>ûì³ÕÕÕ‚ */è•W^IGãó5ïܹ—?-YR›ËËÛ¿eËÃÅÅHmJ Ã@!„<ŠÒ{þüú`ðžeËÆŽåè¡@¾e*,Ôu`†ªªgÕªU_ýµÓ|Ú¶ÝÒÒB)}ì±ÇLÓL$’$9õ›² Ÿ¯yÇŽfË*}é%J©fY&MòWVþ­®ÎN&ùk¹ì‘åÞsç>Ù¹s⫯æççk„ÈÏô+þÙÖÖöÓOîùÉ0Œ={öÔ××cŒÏŸ?œ*«­­miiq7 ébΞ¦¦}üyéR“R›ã B)BòóòR£Gï©«+¹çÃ4EQÔB¡O‚ÁV¬ÈÉÎÖ)EÛ05}ú¿‡Sš™“ÃóüÊ•+?üðCµH$ràÀööv–¼„Í›7'“ÉÙ³g[–Ũ¸;Æt‚ Dݬ:T›<è£8ζí/¾øÂI,0´]ÙUM˜;w–m7¯_ „¶M,KAè—¶¶žÿúÜsX’lÛ6M3wĈWæÌ9¶fMww·BBÏq†a쯮®œ0aâäÉ)ÈÅbkÖ¬Ù¸q#Ë\žçY°Xº¨ªºmÛ¶×^{-‰8îIÏ!aDÓf?ùälŒ÷­_!ôa|êøñ¾ÚÚeÏ?Ïy<æ5ÞK&Ù£F½üÄmëÖ]¾|9¡D2ypíÚ¿Lœ8qÊ”¨¦±½EQœ={öüùóM» °²²òá‡E1ÍaéU9.©ë÷ÞwŸÝÑñ]kk¿(Æêê–-\eÙJ¥óBEQ4tÝ—“sovvpëV£°ðäÆ 'L˜4eJTÓ0Æ„Ó4EQ4MsæÌ™¡PèÔ©SBæª%K–,_¾<t]wW7èÙÞ"Äïó›š~>qbÙ¢EP™oBš¦aŒSBdEé¾xñó-[*|Òý÷kÑ(Fˆ1u<ÏÌÌ´, B8lذ¦¦¦ªª*dzuëÖÉ“'G£Q“P(”‘‘á0õ@î™Ú¶$ŠˆãtÓ¤„Ütô÷÷gee1ÖÆG£Ñwß}WUÕ·Þz‹•:‹~OOÏçKt£¸²r°Y–]»x[âj†¢(lãRY–mÛN$„çÐmF^^ž³ïuqEù|¾›$[¸•öƒEÊç󙦩ªj$I¦’ª èšž1,C‘•x<Î\îg{wù ˆuŒBA@ ··wÁ‚<Ïs÷ý÷ßSJçÍ›çñxXOÍNÙ?ùùè‘£L|DNÈÇ…/„›;š§OŸ^<¡˜õCÀu„JŸ¿ü¦]}Œëêê$Iªªª’eÙ4MÀÂ… Ç·iÓ&Ã0XÔTE=ðÝ­'†ç ïâ{¥—Kg]˜µ¡gØü1÷lmm•e9Míoæ’A)ÌîÝ»³²²ž~úéÞÞ^gxÐßß?cÆ JicccEE… g:Ït´wdäg,Ë_F+(8@Ð þP÷ÃÚ‚µ---ia¹½ küâñx___iii8fÔÂî"„z{{KJJBW®\ñx[ʾÒsåwå¸6µùæ›o¢Ñ(Ïóîð;t²}ûvBˆª¨?´ü $…GZ!Á#!aŒíýÔÙ§BÝ¡¶“mŒÒ~ žç§N$IrË5BÈï÷ñãÇgggÇb±iS§uEº^â_÷qÖy‹Jmjþb–Ô–TˆÝz÷”§8TtÕ·>8gĉDB¹¹¹Á`ðìÙ³eeeìɪ/ ‚PQQ¡iZ<1bDgggpwðîü»[õÖÃð0²Ñ£ö£ãÄq¿öü:Þ|¿ßåÊ•!ÅõV1q•eÙãñ?~¼¥¥…a2 £¡¡¡°°pÚ´iº®3qÍÌÌäy>‰›ƒÝûÐã8xäàÙ‹gŸxì I’LÓ ‡Ãw!t…Ï2^f§Ag,lšf2™ôù|lä+B,ƒÚ¶ (ðª^]×ÙLÓ4UU£ºuŸS}Æœ7.K»ž6_wÛmK‡ÛÒN0ކ܏,íúPhÀðŸ/8@ÿ*‡ÄÞ±Õû…%tEXtdate:create2017-06-06T01:31:22+01:00]¦ó%tEXtdate:modify2017-06-06T01:31:22+01:00fOIEND®B`‚puzzles-20170606.272beef/icons/inertia-32d8.png0000644000175000017500000000200313115373732017616 0ustar simonsimon‰PNG  IHDR D¤ŠÆgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<ÞPLTEÕÕÕÛÜÛÞÖÞÌÌÌÍÐ͵µµuuuÆÉÆÄÄÄ»»»òòòîîî[[[œœœããã’‰’·¸·”””¬¬¬âßß+++lllš“šTTT&&&JJJ <<<²¯²FFF£££åÛå¿Â¿¢¢¨¦¦ÕÆÕÓÌÌi³³|››Šëë¢ÿÿtÃÃz••aaaðð—ûûžÿÿwÈÈ«¢«ÛËÛãÒ㢛¢O£OI¨Iuˆut…t Ò þÑbb¼­¼-­-Á¼ ¹ »òÊŠƒŠz zw¥wÿÿÿº+¦bKGDI‡ä|tIMEá‚is4"IDAT8ËS sÚ0 •"§¶Ç„@5lhø(-ŒuÝw×íÿÿ¢Évlw»›8rvôîééI@þCÿ8 ?H‚ 8ø&*ÄüJ* ”F‚F³ÁÑl@Ø2‰eµS¤NØèZqHSÏsiõ‰KÛAfØE´ˆ@C¿0&zi¬eDêîöÊ䣜9Ú] Œ\‚lÍ€Ùȸ¸TJI©gp5^ú»Õ¹ÉÍ+ ²ïÚ·ã18m'•Àbd.\·ºÏã)—°ç]ÙÙœA¨3(2¸¶¨¸ÿ2/Z’V)Å––ì ”Jë4ÕµQ4CGÁú3g…l¶z,“ª¼ȩ̀Žç‹2b504f¤ °\,W7É„¤Þ¬–ëT³•ßæfdÉO«\Üm6Û×SÎo¶w ¢+Ó°5½ A,–ÛÍêX;€ €bJÐ$©Kܺ<—(1ˆè̪D"wDÖ]0GñCÔmòûæÛ„ ’ám“Þ(¿jTH*UÁªz¥@øÝÄ"‹Ø^¡ Ü½y Çóv†aí> Öïîß·©ÞÚŠEUãžÁþáÃáðøq@Ç$‘(Tø4}ú|àø²£sÖŽ¢šÝõWxLÎE€ÖAK&v÷ðm/ÿdkßíÄ]|zúñ°ÿ»õcý %ŽŸþz„ x´S Ð(:5E4Qp’pBÕGð_ñU¦*Qÿ*$Ž%tEXtdate:create2017-06-06T01:31:22+01:00]¦ó%tEXtdate:modify2017-06-06T01:31:22+01:00fOIEND®B`‚puzzles-20170606.272beef/icons/inertia-32d4.png0000644000175000017500000000102113115373732017611 0ustar simonsimon‰PNG  IHDR TgÇgAMA† 1è–_PLTEÀÀÀÿÿÿ€€€ÿÿ€€€€€ÿ€`SkébKGDÿ-ÞtIMEá‚is4IDAT(ÏUQAnÃ0 £bgeîV»«õ%ÇØC¶'ìvÉ~°çŽTÒÃÑe’¢e3³àg°} j…få§„¹5ÃŒ˜‰~dX $øó¹'óhˆÐ>º÷3%ƒjà´Ö9jƒ2õ~R¡¦d½ÃR$Te:‘ O"Šb %…OñÏ8g#UxÊ \¿½Òs‘oï\ò€˜®òŒÔõýÍÒ¯Ù_ ù<Óòh·Í³Ín~ÁÁnåù+¤1x1,'Ï4ü$ƒ.×ÓÇÊòtÐlë°x£›CðÌ KÆÎ&ðå; êG³±®£ÔÔ‰,¿ë}/#iIJ®wõZ2•]ÖŸÜ:ÅWšçÔxÙ`½‹ùÅV¦DÝ*6ö÷œ…µ¸Ö %tEXtdate:create2017-06-06T01:31:22+01:00]¦ó%tEXtdate:modify2017-06-06T01:31:22+01:00fOIEND®B`‚puzzles-20170606.272beef/icons/inertia-32d24.png0000644000175000017500000000424613115373732017707 0ustar simonsimon‰PNG  IHDR üí£gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEá‚is4ªIDATHÇVKLTY>Ï{ëÞ*êB6(A‚#(ŠÚS4bȤÆ×˜Ø Óq"Ú‘ÄGâÎèÂ… £ VnzåJÆL&ic"‘à8Õe€†¶¡}"# C…*.·ê>Ϲ³8Lµc‹ö·ªÜ[u¾Sÿ÷}ÿÿÃÑÑQBàœsÎ !àwð}Bèû>B˜}–xE „Œ1Ó4Åé²,«ªšJ¥>8!Dq‡‚²m[Ü){³!¤”B‰àÁ3Ærrr^½z500pðàAÆ„в,ι¦iétzvv¶´´4™LZ–UVV¦ëz0¬¬¬dïÿBÈÄÄ„ã8@€ˆÓ!„ªª"„®_¿ÞÑѱjÕª]»v†Á“$É4Íx<^SS£(Šã8CCCº®×ÕÕaŒ=ÏK&“„,„sþæÍ›’’ß÷€1¦ªª®ëèèè ”¶¶¶^¹rEÓ4„iš±X¬©©iíÚµ¦iªªºÿþ¹¹¹'OžÈ²ì} ®ë2Æœ©Tª­­mll¬³³³¢¢píÚµ;wî@u]¯­­-((0 !$khh`Œ Ù—ÃcLÓ´ .ܺuKQ”K—.MOO Ö'NÄb±ÊÊʪªªt:1ÏcŠ¢ÔÕÕ9Ž“=h9 „P:nmmmllÌd2½½½â¦Žãœ9s¦¾¾~jjêÝ»w²,sγUö<ïõë×ï—~Y¡ã8Ñhôâŋ𦠧rÎwîÜyîܹH$èïïçœqœ¦i?N$”RüF \•H$*++oß¾ÝÔÔdÛöÙ³g¯^½ªëºiš‘H¤®®®³³svv–»ÿ¾eY[¶l1M“"Iý²Ÿ³¥#"_BÌ5kÖœ:ujÅŠÇŽó}ßó<¡aåååãÙÙÙ‚‚‚d2©ªj]]]:–$)‘HLNNB„°Œ1a„¬<ðéÓ§žç™¦ !t]7 Fòóß¾}‹ ÄÛ¶  ”B B!ΘH²¸À²,ñ[Q^ß÷1ÆœóÂÂB"T‡Ãaι$Ë‹ÉdO<þçhÔ´mŒø‚ªªcª,þòËêŠ 5'GaqqQÓ4ÀÊ•+[[[GFFº»»MÓô<Ï0 ¡ÄR'ñ<Sj¥R·‡‡cáð¿>T%Éãœsîû¾ÇX0ø±§§[QnŒXÉ$¦Ôó<ß÷E5ZZZ:::ÆÇÇ:455p]÷7‘}ß§²Ìoþô“²woÓÞ½O++»c±°¢øø¾VÕ?þ8RV¶m߾о}7<]—d™1VTTÔÖÖÖÕÕuôèQJi<?þ|(Ê:ÆŽaÜÈûöÛ_|¡{Þú¦¦µµ÷âq™RY’º>¯®ÞÐܼèy……‡ÿýçŸM]—dùÈ‘#íííåååÑhT˜¥¯¯oÏž=óóóÂÄü@–I,çc<>>~òäÉvoàŒI¡Ðá/¿LݼùŸÙÙ0!OâñªÑÑ]Û·Û®k;ÎŽmÛþôë¯#±X!sss‰7þ¶u«;¶ÝÞÞÞÒÒÂ9—$‰Â9ohh¸{÷n$q]BˆOŸ> !džGTµ¶°p(:5µifæëíÛ Ûfž!d¾_½f9:Ú;9IÕ×SMsl›1æºn4M&“ÂîÍÍÍ—/_–e9NSJ1Æ0;2…M……—/^lÙº5cÛ!Ó4?°iEEE(7×u‘ÁœœÎyQQÑñãÇÇÆÆººº,ËbŒ†!RýA•e9“Ɉd:Žó‰ Y–¥( ð•©‘1cáœ0s™ïûŽãhšFAbÞ*Š‚Á ˆ¢ªªŠ¢¨ª$IŠD"º®¿~õ* Ë‹‹‹ÏŸ?×4MUUI’rB950ùz²X*®Ê­šž˜æçææfmºT¢ß·uAœÉdÀÌÌÌððp4ÍÏÏwgppÐqœæææT*¥Õžö¼M½Z=äPgýÄúRXÚ°£" !”$i‰`¹ÍÀqÃ0úûûwïÞM±mB¨iÚƒ0Æë7>ê}4<=üý_¿ÏlÈ@ýûßý㻯ðW7ÊT¦”"ð9xžFB¢©6mÚTXX˜13+µ•÷ÖÝËlÈPN1àü°ù‡ÜÜÜìHø˜\yyyÅÅÅÙEHTRQQáû~qqñ´6 ð|σh>w>´"RCŒ³Ïø¾O)››{öìY0‹‚辦icŒ_¾|¹nv€`B倯~·zþÍü‚±@0ù @¬£££‰D" +ŠÒ×ׇ1HK²v<ßQÞ]î.¸nÆ „¿yô‹\™.ÍðO‰,öI’,ËŠÅb555ÕÕÕ ===EEE›7ož››‹äGzf&f’åIFYd"’§å5þ¥Ñ2-1M?C ’¬iša‰D¢¬¬l~~Þ¶í’’’L&cšf(Âϼ›)+(“©übæE~A>ÅT×õ¥$‚àƒL|tù]’J¢ŽëpŸ¤€çzb!oÿP»[»˜ãŒ1ÏóÞoËB×qD"×qß_ëÿd?nxbà%tEXtdate:create2017-06-06T01:31:22+01:00]¦ó%tEXtdate:modify2017-06-06T01:31:22+01:00fOIEND®B`‚puzzles-20170606.272beef/icons/inertia-16d8.png0000644000175000017500000000173713115373732017635 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<×PLTEÕÕÕÎÎÎÙÙÙÜÜÜÏÏÏÐÐÐÔÔÔÑÑÑÒÒÒÓÓÓÖÖÖäää–––qqqââ⸸¸ÇÇǾ¾¾¿¿¿æææèèèééé555oooÌÌ̺ººØØØåååàààÝÝÝáááÈÈÈOOO ¹¹¹×××ÍÍÍÞÞÞËËË<==­­­ÑÒÒÆÆÆ²²²çççßßßÊÊÊÓÒÒÔÕÕÉÈȸµµÙÛÛÉÉÉÇÈÈÌÉÉÇÆÆËÌÌÄÄÄÛÖÖ¸ÁÁ¨½½ØÑÑÎÐÐÝÕÕ¥¹¹¹ÂÂØÓÓÚÛÛµµµ"""¥¥¥ÚÙÙ¹¿¿ŠÞÞŒôô¢¼¼ÖÎÎôô‰ÞÞ¼Ãꨨ***žžžÚÚÚ‹ßßõõ¡¼¼¼Â¯­­ ÓÔÔÝØØ·¿¿¢··ÛÓÓÍÐÐÙÔÔÛÛܶ¸¶#'#¦¨¦ÎÏÏÓÑÑÕÑÑÌËËÆÈÈÈÆÆÊÊËÌÍËÓÉÓμÎÒÇÒÌḬ́°°ÅÅÅ´¶³ÊÁÊeŸe!×!Y£YùÃÔ×ÔÑÒѾ·¾Úÿ â ³·³Ø×غ¼ºÂ·Â4µ4ù&½&¹²¹ÖØÖ¼¼¼ÁÁÁÔÒÔ¶°¶ž¹ž²¯²ÐÎÐÒÓÒÔÕÔÚÛÚàÙàÛÛÛÕÖÕÿÿÿh$º‰bKGDœq¼Â'tIMEá‚is4IDATÓc``dbfaecçàäàbn^>F~A!aaQ.Vf1q I)iv~Y9yEFy%e U5.&u> >M55-mUN]=}CC#FcS3s K+kVM[)A;{G'gW7wO/o_?ÿÿÀ àÐаð @dT4H &6.>A,‚!1)9%5 ¨%=#3+Û…-'7/'¿Àª°¨¸¤´¬œƒ‹ÁDM³B·²ªº¦¶®¾ì|. 65¦Æ¦æ–Ö¶v°€š€´KGgWwOoX€½ßh‚íÄI“§L``bP“™>cæ¬Ù fü8GÉÓ%tEXtdate:create2017-06-06T01:31:22+01:00]¦ó%tEXtdate:modify2017-06-06T01:31:22+01:00fOIEND®B`‚puzzles-20170606.272beef/icons/inertia-16d4.png0000644000175000017500000000051613115373732017623 0ustar simonsimon‰PNG  IHDRíÝâRgAMA† 1è–_PLTEÀÀÀÿÿÿ€€€€€ÿÿ€ÿ€€zV ®bKGDÿ-ÞtIMEá‚is4\IDAT×-Ù €@ Dßx Ÿcj–`#Ö ‚훸;„9’€…±Ñ.’ಠÉtå@©è$ÚBö¨€ÿq˜}øCéËV®Hd¤-Áp'±<=ªÊü¦ÕNDÎñJj ,Zɶ%tEXtdate:create2017-06-06T01:31:22+01:00]¦ó%tEXtdate:modify2017-06-06T01:31:22+01:00fOIEND®B`‚puzzles-20170606.272beef/icons/inertia-16d24.png0000644000175000017500000000240613115373732017705 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<èPLTEÕÕÕÎÎÎÙÙÙÜÜÜÏÏÏÐÐÐÔÔÔÑÑÑÒÒÒÓÓÓÒÒÒÖÖÖÕÕÕÕÕÕÕÕÕÕÕÕÒÒÒäää–––qqqâââÎÎθ¸¸ÇÇǾ¾¾¿¿¿æææèèèæææéééÖÖÖÐÐÐÜÜÜ555oooÌÌ̺ººØØØÑÑѸ¸¸åååàààÝÝÝáááÈÈÈÎÎÎÝÝÝOOO ¹¹¹×××ÖÖÖÙÙÙÍÍÍâââáááÞÞÞâââËËËÏÏÏ××××××<==¹¹¹ÓÓÓ­­­ÑÒÒÆÆÆ²²²çççßßßßßßáááÊÊÊÎÎÎÓÒÒÔÕÕÉÈȸµµÙÛÛÉÉÉÇÈÈÌÉÉÇÆÆËÌÌÐÐÐËËËÄÄÄÌÌ̾¾¾ÒÒÒÔÕÕÛÖÖ¸ÁÁ¨½½ØÑÑÎÐÐÝÕÕ¥¹¹¹ÂÂØÓÓÚÛÛµµµ"""¥¥¥áááÏÏÏÚÙÙ¹¿¿ŠÞÞŒôô¢¼¼ÖÎ΢¼¼ôô‰ÞÞ¼Ãꨨ******žžžÚÚÚÚÙÙ¹¿¿‹ßßõõ¡¼¼ÖÎ΢¼¼ôô‰Þ޼¯­­ ÚÚÚÓÔÔÝØØ·¿¿¢··ÛÓÓÍÐÐÝÕÕ¥¹¹¹ÂÂÙÔÔÛÛܶ¸¶#'#¦¨¦ßßßÏÏÏÔÔÔÎÏÏÓÑÑÕÑÑÎÏÏÌËËÆÈÈÌÉÉÈÆÆÊÊËÌÍËÓÉÓμÎÒÇÒÌÍÌÒÒÒÕÕÕÖÖÖÕÕÕÔÕÕ×××ËË˰°°ÑÒÒÅÅÅ´¶³ÊÁÊeŸe!×!Y£YùÃÔ×ÔÕÕÕÕÕÕÕÕÕÕÕÕÖÖÖÉÉÉÔÔÔ×××ÙÙÙÑÒѾ·¾Úÿ â ³·³Ø×ØÕÕÕÕÕÕ×××ÇÇǺºº×××ÏÏϺ¼ºÂ·Â4µ4ù&½&¹²¹ÖØÖÕÕÕÕÕÕÑÑѼ¼¼ÊÊÊÁÁÁÄÄÄÔÒÔ¶°¶ž¹ž²¯²ÐÎÐÒÓÒÕÕÕÕÕÕÙÙÙÕÕÕ×××ØØØÔÕÔÚÛÚàÙàÛÛÛÕÖÕÕÕÕÿÿÿ7M%8bKGD÷«Üz÷tIMEá‚is4IDATÓïþ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÐÐÑÒÓÔÕÖרÙÚÛÜÝÐÐÐÞßàáâãäåæçèéêÐÐÐÐëìíîïðñòóôõöúã}þq/ר%tEXtdate:create2017-06-06T01:31:22+01:00]¦ó%tEXtdate:modify2017-06-06T01:31:22+01:00fOIEND®B`‚puzzles-20170606.272beef/icons/guess-web.png0000644000175000017500000004704013115373720017415 0ustar simonsimon‰PNG  IHDR––³cæµgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEá  ŠNM$IDATxÚí½y|\G•/~ªên½¯Rk·$ËÚ¼/qVgsv’„u²0À@xü –a&ð„À ïÁ°’„„ì«÷x_dI¶µï-uK½Þ¾[Uýþ(»#˶Ìç 2ˆG}üñGW:÷Vw[Uç|Ï9ßB„¿¶ùÜðŸúüµýw›ô§þÿ71œ:ÚN*Ã9çŒBáS¾©œsÎ…>Õ£Žö`¶ÿTmž©Qª¢x„ ª¯¯_èv[ºn•Í9óz½ñ¸Õß¿?ŸË²+k©«+c,gY cœsŒ±×ëeŒ†Q¼äœ …302h^˜3€pÎÝî·ž~Zùá÷õË"ÔQQ‘º÷Þ‹ï½×eÛ6c@“å ËÚòïÿ^õôÓ‹’I `B’ÚZ[=>xÁ%—XÙ,`Ìóx<ôtu}³¥ecuuspwv^ØÔô‹/Èçóc&˾_7Œï.YÒ:†‡GGFn9ÿüOD"Ä0„@’$Ã0ÚÛÛÝnwSSBȶíöövBHkk+ˆUá¯*ư×ûüÃ_ôýï¯Eˆ Œ9c “ógn¹å}ÿú¯r¡@I8ÎÆ}ìž-[Ê0æœ#Œ1àüE€ž‡ºæ¶Ûò©)¯Ï·sçÁTê¾}(!IqqËâ?ùI¬´ô§+W6æry·;øâ‹¿hjúâWç!Ì9C ³_ü⢋/þA8Œ‡;Žóú믯Y³&‘H$‰K/½ôùçŸ_ºt©iš}}}—_~¹mÛsº¢’O|âjýœN}”züþ ¯¾ºøK_º€q.^mŠq)!¾6F£-gåÈò›ÿöow<ÿ|…,SÆŠ¶ '¤‰ó¾Í›Ç.º¨¡¦rh(¤ëï>ö±~BdJ…ÂC²,¯\™yýõƒÀõ¥¥žíÛ÷ƒ\{-£”ˆÇcÈÕÕ=¯¾J-ºTÓðÁƒí—]vYKKËÁƒÇÆÆJJJ®¹æšÆÆÆÎÎN„P8vgî´8œ ¡)Jó=vÃâŸÄel€üØcS¦904Tý쳕ŽãÎ… À”‚$]^( <ñ8xCíß¼à‚ƒÆlB8Æ€1Â)µ !ç··½}çÁ¡¡__v™ aL ¢˜ã8 @yùÓ½½Ã²L<O"‘]×óù|$™œœJi.—s»Ý”Ò9…îæ ç\V”ÞÑѪ}û°°ôŽ@ŒÀÂC‡â££™îîÖT 0&Œ'À „¶oI¨³mÑ"€¾†0la÷îí##×F"ïúýÀ›!†1ÀÍ͉ýû65UÖÕÕŽÿÇü‡išuuuÍÍ͉Dâ‡?ü!¥´¢¢"‰˜¦ùÿ´ clÙ¶«P±–Øòpž³,Ç0<p²ñ ¯šÏEw»OÙÛ å ƒ©jNfŒ ÈëËÒ1&¶m¯[·nddDÓ´p8œÉdÎ;ï¼ÑÑQBHII‰®ësíZÌRJ½^o<…‘‘ƒ#œ»\^ŸÏ‡Ç2ÆfHb„€óLYùb¯BYùä$D£˜ö(A2 Œ•ƒÊ¡Ce ŒÑŒ7‡s@ˆÅãàñ”0fcLöíÛ×ßß/LÐššš¶¶¶žž„PSSÓ‚ æt#„?ÿ½!dYVEiiüüóó˜éÃyÔ4è[½º¬¬,ÖÜÜ^WwÔiŸÖÂxÀ¸d}Ì/yý8œÒãF–RÀÀ>ߺXLÖõõ##€>~UÆ0ïèXT]½”1K×õžžÆX¡PèééÑu½»»Ûq˲ºººæZðç¯Bà©¶]{ß}¿õûÁq@’Æ!†1—$Léó„DþîïÜŒU†BÆG>²@`„0„„–$pœçVÜzknb|åªsvì¸ab‚IaŒPŠ(EŒI"cc|ïÞ›W¬X£ëË–Ýþì³ Œ%Æ0¥ˆ1!›6¥«ªò›¦C!„PJc²,B$I¢”RJeY>Í^(8±X0•ZóÎ;o74dÜn@ˆc œó×^ã{öüÃå—ßcÛ9Αªª.—+—Ëùýþ––¯×ër¹òù¼Çãimmõx<l›Ãñ™®=gÌíõèé9ò“ŸD7mö$'€|íÚª{ïY³|¹‘Í K‘p޽Þ-3úå/K÷ï• …LyEzýe+î½·.Éë:&„Qªir:¶lyR"Ï–D»€ÃD²‘²Ï?ÿfŸ†ƒ1fŒz<î®®‰û ¾ðZ¶gl|e8|×¹ç^à8¹¢j!E=QJ%IbŒƘR:×#3oTÔq\š[‰„'³‰B!¯ª®H „¦2ù|–HïÙeÌq¼a?S½©xƱ©'àö}b¶)–ˆ0Mç±€/:¥£ñL”|AMg“Œ¿aSF]ŠärEÇÒfJ/¨’TòÉ(—Îe0žÖ#cB…c„Ќ˹–y£BƘ,kûöìÝ×–K¥Áë…%ÍÚê³–câ7Í‚À¦c.Ë5¶vlÞcï)€^ UçG.h^Þšçyîð£cʘæóÜ´@ÐÜTsÁE‹be…lV8Œœscîvè88µy#án¼jUË9ç—*J¾p´Gι$I>Ÿ1–Ífc’$ ˜[\εç‡ 9g²¬å²cßyt˶ƒk@^ Ø,ÏíCKlù‡–•U4<Oû®öÏ ®íÂ6T@>Åå]òý‡îÿôúO;‡Ù q.û|¯ÿö·î¯ý‚d² !á|SI‰õOÿ´þúë­l–#$cœÅøÍo}«õç?_eÛA„L€nÎ7._¾à¡‡V46æóy„¢(ãããÏ<óL8¾þúë5M›œœ|æ™gE¹é¦›4M›k£t¨sŽ±Äœô?~õíöÑ—ÆÂÀ9ç€#‚’I#¦<úYåõWÈ2î9ÐsgâÎć0„žŠ8ëfwŒ0®¨¨X¼x±a°fÍšªªªåË—Û¶Í9_»v­ßïÿ+ÌÍEIL¤*\aàìÄ×Iùš‰Ñlo~ÀiuŠgšòŒ1¡=x0™ÖÑÁ¶JqçŒ@jk‹çóÑöv@#Ç‹aÎzÃØÒÕÅ[[=n÷£>úÌ3Ï„B¡n¸Áqœï~÷»¿ýíoUU½é¦›Ç™ë!úsW!‹b8é«ÌŘs`ÀN¹¬_1‘Y3ËâsÔ®=™EŒ3&`‡’’’;3¢(Šiš¡Pè¶ÛnCHÌ :މ„Ãþ#YdŒNpJÁ–[æÔhpüÜÁSJ¥šB~kjßU ˆušŒ¸`MM¥n÷ÆF˜˜ÀÃñî9 ”öÉr ®Ž[ ´}ûö¡¡!„Ð’%KZZZ¶oßÞ×ׇjll\ºté_andÛv$R~ö²tzj@V1çï (çT–I:Z¾h8+i¬j<«í,à a ŠSˆr{àZå:Y¥—¬ßêñ¥cþžPŒÒ­@ù%—„(Å×]·!äLSÀ’DÚ×®­oiql[×õ‰‰ ŸÏ§ªêØØX>Ÿ0ÛØØ˜mÛÏí ÿ¹«0½Àî¸yuµÿ©DÒPT"B탢’t¼ü×÷ß¹Ø4d)Š?Sú×.9Gÿa ;ãÎÕo^}Ý9×ŧâËšš‡?ùÉb zOŠHÛ&>õ©Å SçÜxã+ë×'G˜“A„ ÇyÜë­øÌgB[”º\.ŸÏW(,Ë ƒ.—Ëï÷ Ó4ƒÁ $Isþ4?`nJ7²viß÷Bÿ°Ûa!›J†ae&—{ûòßWÕ/\bÇqêjë–u/Û¶}[&š/0Ìxžóíüý¿{ÿ7Ö}Sà–µðœsÞPÕøŽ%¶íÎŒ½¬ªíÿøWÜ?Íå(BŒÃë×?70€Žp®pî 0öDU•ü½ï³fžËaŒ%IŠF£㊊ŠE‹B"‘ˆˆ÷655BþÛpºñùówíEcŒišÛ6'ßÙ¸kÏ{*C|¶¬]|Ñ Ÿ¿\×EÚ PN}nßD÷ÄË/î’vèX¯¶«/ñ\vÞšó-Õ¢&E 4\òùö<é%¥£²Z[Ë®¾zEK‹•Í LŒ1¦ÉrA–wnÜXxýuehˆy½ÎÚµÍW_]êÙl1c,Tå8cL„ŸÄå\OA˜G*„¨m»\.(:™M ]UÔH ¬§SÙ|Nšs;Ž d)4/8óUo&“c¶Åˆ$çÀ9G”FJK3ª/ Ìíö ‰ñq$a} „ÇÑ0”—Ç›²,ãJ— &'§2"ËÅE8B$cŒù±»3“Ð=oTÈõx<½#“ûß|RÚ Y–ÌÅÎm¾øÖ–…Õz.‹0àLuû÷ìoØú„j¡º®U³Ú+ÏZS©_Ö ¦bc[Ó¶½ñ†þÌ3C‡ ÕÒâ½ñÆs/½” 6c"ààÖ´1ÃØõôÓò«¯z†‡m'½ví‚[o]ÑÒbLCÃ].!!dš¦eYÒ±—@„,æzdæ‡ EþõŽ=O}â¦ÈPYq™#M¦ù³c!tÕw.ºèb=ŸÁÉ.ßËÏüªbçW®ª´<^Ä1GêšàÏ+–ÜûýÆšX¾`¨„d1~ýK_ºèÉ'× $qBïr¾éÎ;¯øò—ݶm1æÑ´Î‘‘ÎO|âÆ¶¶:„8ç¡ç/ªêÄ×¾vå-·˜Ù,p»Ý6lxôÑG#‘Èg>ó™ÚÚÚ±±±®®.BHcc£Ïç›k×p˜3œs—¦î‰ÿìÞµŒxƒçÀ8B¹üdU©Þ±éµx麚Š2YÕÞ~ý¥†-Ÿ¾v“Â9p@H‘²ZyqãžÐÊë|2bn÷+_ÿú-=¶D’DÌž#„1®!¤lß¾—L³iýzɶÇ,ëÀý÷?ÐÖ‘$ލsQYbÛ‰×^;¸dIcSç|bbâ¾ûîëêêêêêêïï¿öÚk·nÝšL&3™L.—«ªªšëñ™NpF‰«ãåÿóªQef:†€å—>°(?ôÊ¿[ ŒMæÍß»¼¨¥XˆqJuG ÉïóìÙùêShlïž=‹ñ‹Z„J¥˜1Ì¢Ô¡´ ñ¿þkßþýþÒÒÝ?~][›,ËÔq¥„1Ä8%ä€Â#Œ .YN¥R‰DB–e1 Ã4MEQdY. g9Ó*,nõ¸¼¢È#c‘ÄÛ‘0ËÁÓ! U=P£o‹öv´J !ÄËM#¸A›J÷¾2a²É·ß\E)`LŽÿ$„s d•eM¾óÎ¥ò+¯,à”Nw ¢ZÛÚÚÛBõõõ7Ýt“mÛpçwêêjašÖÖÖʲ<×Ûá™Øc˜sE’„¥`S X^‚D¤t:c£@€Ÿ#à€PÊŽ§SFj¼JàÁ 07çDp¡?©›réÑ{g< @úû“¦8zã‰b„TSÚ=<ŒÎ>› ßøÆ7î¸ã¯×»hÑ¢\.·dÉ’ÚÚZ„×ëýËIBäŒy=Fl»Oדká°z,Mè4÷r.IÄB2p8Å`p@’$,ÉÆ)ž‡Q‚™ªZ§îÎàª*#d«*À)zä¼@E¸(“““’$Ù¶N§ !™L¦§§§··7—ËÍ5ºg`r̹âómÞ¾=ùØc%»w˺>XVöî%—,½ë®úh4¯ë³|O„e[±XÙv¹¬€0?Ã8` ¬‡×.‰•!‡Mw+ÖGäx<cœË±ÉÀê Ÿ{ÿªÕ=O>Õ*Ïi2â²­ZUáñìXµª0<ì:æFˆ0vØï/ime–e;ÎîÝ»Óé´ÈY¹råž={&''9ç¹\níÚµs=ÂsþŽ Qøã‡n¹åãÏ=wûàà’ɵ·ßõýïwÞtÓÎövÛ=û\t(‹úU¼äÖý€ÝÈa˜qàŒƒÃq“#C]xs$àYP[Û¸zjˆK¢ ñ¢Ç ÑwIé9·HffÑúË6ÖÕ¥ IT”¦‰÷B’€ÒÍ—\¢ärá[oÝœ;³¢BD’}×^»°¶Ö¶,˲ …‚ÛíÖ4-›Í†¡ëº¦iâò ˜3sëT0JÝ~ÿ›¿ûÝâÏþ ŒEª'Gò²6~gëVò¾÷EÝnçÔ™^aÇ6«–¾Ò/;PR‚@B @4:@w.½ðž/JÜT0¸¬~ù­MËȸÀ€1"$ ˜o=È÷6ÿÃ¥WߔˤJCááúúΗ^ZjY!D Æóx”ï|giCC&^ÐØ¸‘syÛ¶j€£Bd(ýÉÒ¥«z(„±Í˜ªª¹\N¤544”••麞L&9çõõõ±Xl~û…2ÆqÛÿìgoN$(Æ„R‘^8gŒ!Y®œœ|Ûëmºè"§P˜•—̬¼ì•!¹ÿÐA’3¬âG\ïDîºðCÿq›2‡ÒÒ°_i¾òùýñìp7.P=Ë{“ü¥±²ÕÿtåîefabÆÂÆÆÁµkßîì¤ñ8HsÞÆù3+Vøy䜳Î*ärX’À²­[·±´´£­ årçŒm“¤—®¿~õÃ/ –%2Ec±X8®­­­¨¨`Œ•””D"‘êêêêêêù„Èóz<[·o¯¼í¶ bœÏPÇ1öãeË–=ñD±ÙÓž9çFHõt÷Ç“}ûœü$ÑüÁš¥‹ê«1Õ-‡ác˜–¦*&õôÉu0ÛP±ØÂe5±ˆUÈ18ê’pÆ\n÷„i´µ½½€«®®fÉ’¨,޽LGwq·/‘ŒïßoDZËåkYÜÐP¯Ù–q| Pä8wsŸTn˜[s†s$Iù‰‰`ŒèÉ }€ÀèhÎ0"šæÌºà „,Ê=à,©u i‹²yÓíRªÊ¼;Yƒ!d;–OUkb qÉï8¶Ïã/Fꔽ'ÆÓ,ñùø’%ÉòrˆD"QÇÉf‹¡|@Û^óºW6¦³UŠ,UÄÂ.ÂsúqUD'Äcq)4:ï-Rι¬iÅJË“úa¦Ç£üizœƒÏ«nÚ´ù‰çR½£u˯Êùª’ö¯R®ºb]ÁÊ9È2.ä7Þø¹ª>V» Ëå¦É„×Îó,øäªU­ºžEHbŒº]®þ©©ÝßúVÙK/UŒ@Wyùæ÷½oÍÇ?^íóé†1fŒ{üž½ûw¿þý¹­ d(iЗÜUvÍ­W€%QæˆX„ÛíUU5 Ó&B¢Ñh¡P˜Ç )ç\“¤®©©äõ×ß11á”ßk’”wœß|ó•?ÌÓi8ut”1îõª?ñâž\ä‰\ívÆÀ87 ”ßtë[ÿî#×é:“eÈç¥W_ýÜûßÿLK‹ ¨D)üq·eýàâ‹/Îå2—ûÐèè¡ûï¿çÈ‘BÅÀP’󟵴,þßÿ»¡¤$_0üï믾ñÚÿ8²Ð8׋¼ˆ#n#ÚÇÛý·Œäëw"“PN].×÷¿ÿýüà~¿ÿë_ÿúõ×_ÿè£>üðò,ùË_¾ñÆQ ÌU›CsFÄÛ¢¥¥»‰Ê]»Â²ìS!`„`Æ^&DýêWkËʬS3{0Æ<ï»ïn}èÇe¥5ïS%Êç€sEâhíÖ¬Ô·kÉ’EŒi¯½öèõ×ÿ´¹Y¢ôèÄf !$-_nîÛ·Yׯ¨*'ºëSŸúøÞ½^Y¦Ç?ޱG’–Çã/öô”_{m@Võt>ý‘Ý+rW‰;ܤ`Sd¢¤nô€>êi_uÞ2¸¯¯÷Á´m»P( ^|ñÅ<ð@.—3M³££ãƒü È½˜·Œó\îüøõºu£¶-!„0F„ „¥oqÞû…/¬9ë,}vβO¿0á ]‰8P† @'ÔbÁغ߾lS;ÕߟˆFkjÇa„°£)6„#äHW_8tèqÅÝ¿yãy›7«„PÛ&Œ@£¶íÆxíÛoïÛ²Õñ¼õ«U©•L²¨CÇ0âγT=´þEzxb@‘ŽÖ„ŠO*ÐmùX4XUÕ3°Îm!‹±¨,_üÃþê£}"ØËX'¥›úQcc×£^}ß}v&ƒN½„rÎEí®t¹JÙŒ-•qÐTIÖ &“ÉöÖÖ8ÆøxÆ œ³X üž£iÃܲ©fæ)„ZŒ-ÛÆ ™äF+!‡ÙhÆ&Î0B\.ínëçˆWWWÿÏÿù?«ªªZ[[|ðÁÒÒÒÏþóµµµŸÿüç].×¼ÏæÆ™ŽÆøºÏnè#÷uîq †«$¼²qQ‰¬cß³=cÃ(˜¶ÏÓ¬Eº>eÛ™`ŽÑ±?ìŒ.×dÎtðÔ”ÿd‰›ühjJw,šBˆÍ-t"PйDÕ|º@dœÏ›÷ÜsÏÙgŸíõz«««“Éä>ðË.»L0±˜ô E*â’ÔœKvû@UìU22„GpÚ÷“Qær¹4%ÅœDç J)GÍæSS ÌßZĺñj ‡3Á:6s€GÂI!aî$(Bè$T) 9`xƒæpŒñï~÷»p8, íóÎ;¯³³³»»!ÔÜÜ\^^>ïS9çŠBr9òüïÿ½§ïÊÒèu |@V®Ú¼í– 7©ª`6€Td¼——W,¬Ñu“<ƒB#0L¨ŒôÖT‡#ÑÖöörážÿ!<6YýÂò€ªž¿®`fDŠçí®óÎ+ÕÑuJ&%,ó:ÄŒsdV/\R‹tuuUTTÜ~ûíýèG3™ÌèèhWWW.—Ëd2‡š÷!_ι$¡t^ýS7Þøð]wÇÏ9V®Â—]æ<ðÀžÒÒ{_~ùqUõOOÐ>Y£€=¼®ÔL½ÄÂ(p @1¦XÆ©ø;7_£a¬]™œ¼«½$ S*¨,€1Ĺà¼øb¬¥åv3ŸX~Þ[.¼°@)‘eŠ1Ï"²œclûe—-?÷ì\2wégEv#G‘$ÂãÀ8b@¸»¡­åžpE´Êv,Qå{t41.VÙOOe›Ó6×¹3L–¯½ö½oüU}½L)?F׋8'MM|``ãèèº ª,Ë:5Ì,Ë®««õÝooŠ3©YV0‘0.89òöß\³ë–›/Ïë6BvUÕY/¼”—C‘ʶÙ/é#ä‘Õ«—æô¼OVäsÏ}qëÖEñ¸Wâ0BqJ²lÙŠï|§LÓò†QQV!-Ò7½¾Õc–»G•€Ì³½á;'ï|ð&Gg6³£Ñèž={¶nÝêr¹/^Ì9O¥RŠ¢´¶¶yÌxÁ9WU©·7¿ÿoþfÌq$ñi„¤LÆùÉOn¿êª‡K`!ÿ.pðzÔmÛ¶=ñÜD÷ðÝôkJ¾¦´ÿ¦«=ë×_ (&ÐÓT6lxŠ_Ö,8¤¨öd2<8pÁÂ…ŸX¾¼ñ=tFÓ†²ÙÿùŸ%/¼P14Ä©®N^wÝÚ¿ýÛr·»`šcF™Çç9бÿµ¼›Ù,ñ” “›õewU]uÓzn Ê©@g0ƽ½½.—«²²Ò4MI’(ó›ñ‚1êõú7lx£µõþ5kð‰|tPüùÏëëêž++#¶Í`Vã†RîñhªlŽŒ$³9ÓíR*+Ô»²YƒT|oâšÇ—IóTÎy>ŸŸký͵ çÔíŽLL@S;QC!žÉÄjjÔÙ7 ι,ã\޼õÖÿZ°à¿Î='ç |Ž··«¿ÿýÍçŸÿ¥¥Ši:œs—Û?ÿçÿüÚŠ×Øj†TÄ<º;ú©ŽOݹþNèˆ!ΘËçÛ¼eKæŸÿù¬ÎÎ*„8ÀçÛ[[Ã_þò¹gŸ]Èd!˜câBOþô™¶ï'ÜÉ y·ß%m¾+·Ýò¥«*#Õ£€ɆÏ<óL 8÷Üs9ç¶m¿ð ²,¯[·ŽÖ›Îa›[s!JHIGÇë«W')ÅÓÊù€1À˜Äãl÷î®X±Þ²ôÔôÇ}J¦©¾üòçn¾ùgçŸï„ÃÈç%¡45±E‹ö?÷\[,ö>·ENt'îé¼gÇßí@M0öa(}…þ&~½Ž.l¹°`ë^Ÿÿ·Þò|øÃ÷Æã•ùñ#TpöÄDû /ô._Þ°h‘©š_ùÙÃOô|Ki1Î∗ø(TÊ؇ýooz­ùªJ¿;$¢œŸüä'ô£=û쳄K.¹äÓŸþôw¾óçŸ^×õK/½tKíÒæÐ©@™¦SUå§ô#[¶€$!Æc‚³#$8¿û]eKËíé³|ƨªú7o~úŠ+~[_/9çœqî0Çᥥò?¸qëÖÿ%bHß<ðÍ®{»d—Ì)§@î0΃ðYø‘%lÙ¶%uOŒ;_ùÊÍ–E%‰q·SJ9g’t›aè_ùJ_26oØÒ÷¼Ÿe¢¬É DZmjx6"‡Ë:ÏyêáW‘Ê4Eëééyûí·UU€—^z©¯¯ïÕW_nÆóÏ?ŸJ¥æºÄpŽ P11ŒÌÅß¼e˧Þz‹bÌ0æâ_.çüøÇQç»…Âlï©,ãD¢ðäªUÀ“$Ž1 $qJi}=OO$òýý½¯,zàP‡~Ì]&1ˆ_È“xRA¾Ão¾¾n`AŽƒ9¢˜ ¹ »ûÈ[ïpÙùøáXl ,bä˜å‚0'GBlê%¥»·R-©©©1Mc±X}}½`Ihjjòx<ó#e ’¿þú7o^ñÈ#?/«Ø«ªz:KŒ_ÜÚúáææª|>W4OlœsYVÆÇǪª:áä½ jëÒ£ƒÙ®ÂŠÂI/8ãà†}Á=É”{v×À ﯸ¬Ø´wo<Un//eæ Tq ˜jÙð`çhs}k0üÞ÷¾÷øãƒÁ»îºK’¤oûÛ=ö˜¢(wß}÷¼·H!` 9Núâõ9Ö5©‘´c:µå®àÅnÛœÌçrøtu°!Ç¡šfÏ"¢ª\OS›9 ž\BèÞ’,‡2dYÊ©Ÿ¥ Ór8e–p8œ ˜E@lËÁÙ¶½dÉ’Ûo¿ÝëõVTTèºÞØØxÛm·É²\SSs¢ög"››1¦¹Ýö¸µsÛ«¿9ò£_ö?òÂþŸuïÜ«0VNŸrá8N0«€“¹&‚ÉkdØïö‡*´2ìD`a¤ê>Í©­‹‹{g< Æh]mXó¨µ`ÃIWxÛ8­ :6Ø|êSŸzÿûß¿~ýúÿøÇ¡Pè _øÂµ×^{å•W~ûÛßv¹\sm‘ι cn{ðàà=î½£á®ÿõþïüð¶ÿü§+¾ò>|ýC¿{HÒ%,ãY´(еòòh2yÉÄÄLò{Æ€b00p^IYisESëÁVœprœ~(D ®€+Ýnˆ^|É.IÆèñê¡¥»Tµä¢ صàÊà8 iÄͦáá8&Ø›-M4¶.Dõööüþ÷¿Wž~úéÞÞÞgŸ}V€O<ñD:žßæ ç\u©ÃÃ÷ ܳíSÛð9G1ñREì÷Û?¼ñ‡_~åËš­q<û7Ä„èK–|ø©§ªlŒ%Î c˜ó£fío~㯭ý¤¦˜ZÌóÿ©ÿ¼”P æ3L8‘ˆdì³^<ëæµ7ÇSñUËWvÜ{oç‚Ê‚ +‹ ãCÝ÷ß¿|ÉâÉñÔ•·^œ_Ñ1e§Ý’̃,É õvàM?¸8 ELË…B±X̲,¨®®‡ÃåååbæÕÔÔˆY8S9ænÛýOÛþiÇý;dM¦”rÄb8P Qr€hÚÝ´´iiÁ,àSø…!ÛvÊÊBéô¹o¼±¥¢b28 aOL°_ý*JÈ¿Ÿ}öê‚^°©Ýº°µrgåÆÞö4àˆvˆõ˳¾·ü{ÞJ¯cQâ8ÕëÖ½05Å÷í+kœÛ{óCºâ³Ÿ• ÃáÌçò×_TºyÏÙ¦‚p…Ÿb“]îÍë¾Y}ÙUëó¹ã, µ¶¶Æãñ•+W~ö³Ÿ---]²dÉøøxSSÓ¾ð…H$2×þÌ1ÌíRûÛú¯G×ë×éˆ"NfÔóÊèe?¼ì?/üϼœÇ|¶%1æñ¸ÒûöýVQÞRÕqÛ ´´|`Ñ¢r]Ï"D€ói¾Ãû?ÕÿÔïŽ<É×j®€+®;ë:&æ´Z{êr½»aCö¹ç<km ÜpÃÙçŸtÝá\TÐiª+ç¤ÞúݦžW“ú•¼¸t­vÞÍ+ZZóY½°¹\.Q_/êC].—`B4Ms®Ï™[RFƒ¾à o¾ðñµ'‹ åt†e'”ZþxùK±—Ôj•š§ñŸ£ª*kZ0¶ GUI0¨ÚvZ×Íéô.s<^¼FÊ`S< öá©ü³Ù´Sí8bÌ ’”1 hšjÛ™tzzÕ#cLÂ’/ä3hÞ° K>Íoæì|>O$2탱éa—sª?8NetöN(¦ÈnÏ9—$Ù¶ÙààÁÉÉ Ë²dY#å劢“8皬eSÙCc‡¦ÒS”R—æ*–ÆJcˆ â¶„’Tudd$>2’ÏåÀëóÅÊ˃¡P‘»sN]‡»&â Ã0!ÁP°¢²|ׯ$IÓyg¦_žïª!d1«6P+÷Ëv“}"µˆoH6xzMÇœæ&„†±wïÞ‰‰‰i¿ìëë_±b…ßïC/Ër<?pà@.—+*µ¿§¿ªªjÉ’%EvWBÈ‘#G>\ܨøèhw__ccãÂ… EOðÛïß¿dd¤¨‰Áá¾þÞeË–•””ˆ{1Æ™L¦¯¯OUÕºº:QèÔÛÛ‹1®¯¯×4mÃÜ!‡9åÞòí;·ž5(a‰qöÞZê€D$v}¤÷#k–­™Åœ£é8Îöíۓɤ¢(dZÓu}||¼¬¬Ló199¹}ûv1G‹2ãd2Y(Då‘,ËÝÝÝmmm"´(Æ9SU5‰Tl÷îÝÃÃÃ3z4Msll,º\.#ܾ}ûØØØøø8¥4‹ bDÑceeå\OÄ9v*ŽBèïËþÞý¤û=j;N'’$Ùû‚/¸yíÍ+CÐl›$I½½½“““ªªò㛢(ù|þðáÃâ°ˆÎÎNÇq„+6½©ª:<<<<<¬ªj&“9r䈰8¦Ë „$I:|øp6›UUuhhhttTÓ´’eÙ¶íÎÎN8š iäóy—Ë¥(J:6 #›Íjš¦ªj:ž÷µö㼞_½võ¬•ý¸ŒQÆE”YÌÙé\ò£K¾{Öwqs›Ï®Ilccc'õ‘ÅÞ311ašf&“™šš:•+ÁÇãqÓŸƒ¡U«V ~’`0è8βe˪ªª0Æ¡Pè/„˜ ’ÎfJšb¿â}bŠZ¶êóHAïX"I öˆ?Í>E;svQ”{Ú1=íÓfˆ†‘ÉddYöz½"÷)›Í Ò‘S3§Ã{&TÈú}GíûýkÝí½nÔ"Â9Ëáš+Îr¹K CŸ}2Æ4Móx<§Z$c.—KlZ'‚E1¿ßO ³+;H’ä÷ûs¹ÜI(‰ÇqvíÚ%΂Íd2K—.ݳgÏØØLNN®ZµjÞ«1îõj/¼øê~ᵤ{]žFã{yõç¿ô‹+*g×¢° ªªªOÖŒÁ[–%vAä*l–é;PqºTUU £Ñår™¦9C=!J©Çã)--¥”VUUŒŒœøyÄ~Y]]]<¼>N{<Û¶''' …B*•r»ÝŒ±d2é8Îü>§‚1æõz6mÚü¿þO™«ôÎh4¨)\‘™Ç åUƒ¹O~é¡ö|vL’>k°Â¶íšššÊÊJqšÖ Ã())ihh~aKK‹Çã°V±1ÆLÓ\¸paii©išn·[$슪ØÄ/^ìr¹,Ë*++«¯¯áøéb¦iú|¾ææfQŠíñx¢Ñ¨0gJKKÝnwII‰ v®Î<ö !‰ÚSÿúH­Ý­JŒR‘ä€8GŽC}~yh¼DeÎ^Û\(ØŸf·+++£”f2Û¶‚ª¬¬\±b…)ι¦i%%%ù|>ŸÏ;Ž#ðY–›šššššÄ-”Ò`0èóù„ Ž‹dŒù|¾+V”—— Ÿs‹Å0ÆétºØ#”––®Zµª˜Q!¦¾(kª­­qYYYY__?§Ê;:2s™ Ì=÷žÝ;>ÿíp ô2j38ÞyGˆ›ªðüè;_[ÃÁwB™ÊI´(4™L ¶ÁP( …Äl(b1ÂAœœœL¥R”R—ˉD|>ßôS?„^ ÃH$Â@õù|Ñht:V'š$IÙl6‘8°ƒ‘HD¼E1áPŠ}±x ‚[o®Ûî…œsI£ñ¬ÅV t’ƒ®9g²LS‘|.í Oë‹I‰DŠ… ÂËžƒ+Ëryyy4Êôji±8»ÝnÁZb—‘0([1e…ÎdY“{ã…ˆŠ'ϸœÇ*„£/;Á`‡“P ÆA–lL$§e¼à²,g2™¶¶61 eY‡Ãuuu¡PhzLN’¤x<ÞßߟN§)¥š¦•––ÖÕÕ±i~,å¾»»{xxXä\‹¥¯ººŽ%ÚT¨P(tvvŽ ó' .X° ´´túœ‡÷ŠRœ"*.ÏÌ)¢s¨BŒ‘iÑEõQ·|˜ò¥ÀgB0ã|Þj¬LƒËtÃÁ§Éæ–ãñøîÝ»ÅP ëc```dddÙ²e555B‹„C‡>|øhœ ›ÍNMMŽŽ®^½:8Ž#FvÏž=###A€d29111>>¾råJ0’$)•JíÚµK¸¢Ç‘‘‘ÑÑÑæææE‹ -J’488xäÈEQ/^‰D†††>Œ1nmmF£ó¸D!df]ýÂÕÍ}“ɤ¢àEÖ:†ÀÁ2è©MW]âÇÄ §.1ÊÈd2»wïvGpˆw\d¬ìÛ·obbB,˜’$ T(UÓ´\.'Ô/~yàÀ‘‘MÓD¨Vì^Gmkkq>Ã0vïÞÏçUU* )!¤½½}hhH–eŒ±®ëÔu=‘HtvvZ–uðàAõž'2‘$$$Iˆci¨wß íºèÂsryý´[OO¨ûšn£‹%‘1ÖÕÕ%¶·îîn1ùŠ^Š0vEÉd2š¦%“É‘‘á;Îè¶ÀÓûûû³Ù¬¢(3ÄÄkÑÕÕ%æ=cŒR*´.,[Áþ$.Ï@¼pî/,#RZûÍ//[S÷h:þÚD| 'âÎÔc¾áí>vuÁ€ÏÒš¡?a:J'£ ;V*•(×,x Æx||œ16111ËE)˜˜`ŒŸæÊçó©TJÀÜ‹-B¹\®… º\.qfŒ¢(gàÀŸ¹g¼ÀØ(èÑÒÚùBÉáC‡w¿Y0y4L–´”–Wž­ÎO³ÔˆMhöâÛ¶mÛ¶,KX' ˆÙcš&cLà³4á,ŠUw˜[„;Çinn®©©‘$I~×ÐÐPYY‰1VUu®kbàÌ`¤aÇ,hÞpUóyîÈc›nO(9v†1{–l|ÑÄ^(IÒ,Ã1=º{ŠÏ€Ä|ûÙì=ŠMN8Ž§Ò¢kæððpOOB¡8§cÜÔÔ ç}Mç\"ÈÁÞWŸŠíûyÕ¡qs‡·ùÏ­½ü+—µê¹,ú`î@ 066v"F*æh p¹\!MÓNšô'6­H$"I’ 9Uwãp8L ‡Ã©Tê¤çf `Ýï÷€aû÷ï7MSì|kÖ¬i¢Ðð¼óÎ›ßæ ¨/üø«gíúôÇ«ö½¯Ù\ß lœú¤ç÷…_ÞüÖ[o¸½¾Óq‘BHpÎÏ 3+ž«#þêr¹ª««Å‘3Ä(¥ªªŠ$Á{âÉ‚1D"%%%–e-X°@̳ÂÛ¶]]]-Ò|…§/˲X'DZm[\ ßXHç6ä‹2-ÔõîK+£iJñt†sÀ2™L³mžëV¬»Ê6gc¼ƒ~èСˆ=Ixx–eŽŽÚ¶]VVV¤6ß¹sg?s@×õááa—ˇ…õ˜N§ß}÷ÝÉÉIq†«tR©T<9¾”REQúúúvïÞm†èQ8òããã¹\®¬¬¬h!Ÿ­­­^¯×ívëºîñx/^,2óçT‘sÌx!«}ñî_\¿¥9u¡røø“1Ajå¯ÛóÀ¿ßaeÙ¬n±éÞÞÞD"!RÅ©@`Fb"‘èïï©Àš¦Åb1QoYV4u»ÝápX×uQ»ú—‘ Œôláý¼vá²[žØ7²ÝròàªDu—/½éö+Z(œ>_@اŠì#„ …‚a"=bÆ‹L&#ŠLgVιËf³³ôhYV.—Åû«W¯ŽÇã²,Çb1ÆØÊ•+ËËË1ÆeeeóÛœyï c”Ëä[ë—,þê⬞v˜£).¯â/dÂ鸦ìÿõ_gHžV¸hõüb/QI1•EíÎàЃ3v~!&X7 Pà2v+1eòY„Ñò%‹)L™LæTEbï˜Ö©æHÇ’$ÉçóÍÒBÈçó ¸5ŸÏŸ*Â%˲Çã/Ä®]»FFFB---­­­Û·o@544,]ºt§Íì #L0GŒÌ1ÁàÄ©Îr±ÜÒÒRÁ" …D’ËIŸSYY)Àná­ÏxšP³ªª±XLŸ*îhÛv8öûýœs]×'&&<H-Èçóãããn·[UU±CÏï¨ý¥ ¥¶¶6Š"‡ü~¿Ñ¢EÂ×nii¸Ì 1[———‹|ߦ¦¦"áB± ÐUd@™¦YYY)NB›ñ(oiicÅ~¿_lÃÁ`ÐårÁx …΀93×çþqšØob±˜®ëÙl¶˜È‹F£«W¯9¸œsáÕMMM‰<`Å@]]À¯Å¸‡ÃaUU'''-Ë*†‹eY^²dImmmqº Òm‘¾VìÑï÷¯ZµªXï"IR4•$©¢¢¢¡¡".c±XSSÓØç#ýã6a&pÎ'&&iž,ËÑhTðŠÌØíÞää$¥TÐ܉L²éB’¤L&366VØDð}À†1N$ãããE€­¬¬l1†@à¥ìØæ á˜c0=çZPYÌ€¹…ß&Ž·ˆ…ô¤0w‘Ñ@DfļŠ)kÅLmŸÍØáŠVn±_UU• î*ö(n9räÈØØ˜˜…áp¸ººúÄ𳆊5ªâr~›þˆ­X½{÷náq‹—1æv»—/_.2µ@@qmmmÅø¾X?£ÑèªU«.&G[[›Hlœ~nr}}}kkko+ »wïN&“Ó{TeÉ’%‚c$I0wSS“ÏçK$GŽ%¢~¿®++æ‡9#ˆ¹ß}÷]Á?5½q"BÈØØØîÝ»…•!dHÍfÓétEE…X ÛÛÛ»ºº•EQŒ"Èd…S!ðkAPìQ¬·£££@@8–emß¾=•J¥R)Á»&òijÙl>Ÿ¯ªªšëÁ™N…˜ÝÝÝù|¾È?!š5X–%ÞzÇq> Ó&VQLUÕD"188¨ªj*•lèü„&ÐðT*¥ªêàà Ðßôù1ڡÇ‹ °(ºèŒaâRdÔ …yOZòÇùˆ†!˜eNÜZ„“ɤÈÍ=cXЄŠÀÓIGV¸}œó±±±SA„1­EaMMÈ’Z°`Ç㉇Œ±ººº¿bçÿ~›N/q*‘oš¦à:é¸ 4œRª;pùTM×u!6;ã…w&纺:I’Ün·eY"9 c\,’šÓñ™*„cǮ̲(áií¤âF$§;1ñ.£˜Ü“““"7Àãñˆ…c,.ÿ: ‚XÂÒ;¯T^¯WÓ4`÷IŸ#8 …{^,²9±!„„X0å×' RªªZ4göìÙ“Íf£ÍªU«öîÝ+Ê6r¹ÜÙgŸ=×ã3öBñ¦ êOĦÇ©®®¥÷eeeb[š!#Üá Äb1‘ùr"ã…mÛ@@ŠÅŸP!,Ä***D¤B0ókš¦(J.—3MS×uQö-˜öÿjÎUReeåÂ… }Sqæœ þ‰ºº:aA477G"‘üÏ¢»¥¥%‹˜ð²eË„) Ó0”âŸdY!øææfÛ¶§ó?€Ç766 ÔTœÿ*’«««Ýnwee¥`/©©©9æÌüpíEdz½½½Â9¥555Ųia+Z–ÕÑÑ!²Äo< 3)V`‹³B:::D¹Ȳ,N"éŠÅ½spp°««+ŸÏ E*ŠRQQÑÜÜ\L,èHøÅœóÉÉI„P8þ+F:³ ßkjjJø^¡PH kÅåN¬ºÂè/;‡B!Q6V\Óø1òŒt:]Ø‚Á œ@Œ!f¤}H’CðŒp£Ø¤‹ÛðŒË9móF…bߪ†pÎ…Ï=c³/>Æб*–YÅ•-ãü¤{-?Ê-„àÀ9gü=±éÙûÓïq9§íÏÝ"ó ™L~õ«_u€+Š$I`”¦iécÅ9çˆ+ª¢a rÀ)ØjQr|-*cLBHÕ4Pf‰sì]yOŒ2Y’MÁÎmÃ1M0µ¹¹ù³Ÿýì‰5=gFyGûš³Pd•aÌÅß×—ÞkIEñ—•­hh(§4g;!”1&©’›º{ô˜8Pp +¼•ÞŒžÁÂ|CˆSêv»S]¦»ºB†††Å‹Œé….: <~÷D6~ho×ÔhFuËuK«ëk::‰“‚¨ä lx³´ù¡BPUɲԷÞúY0øã¥K‡ƒAžÍ¢ööèÈÈß\xáǰ,Ê9W]jv(û­ßúÝ¢ße3 ™ ÷.|=xíÅ׿œÌ(uû|»ÚÚ†¿þõå;vT›&PÕý眳à _XÙÜœÏå0!À@ñÊ/?ûÚŽGúåÞR™zØ…@¢ôFvË?\r•˜–!ÌÝ?íÈÌ"Äs¿ðÂ×®¹æ¿–.EœB˜s†êëc¿þõû®¼òa—ËF’”ÎxLJ÷þí^ÄÀ!Ä8ãˆÃ[ð¥}_ºïÚûRzÊïõmÙ¹“þíßÞÉBGùR8çœÿ4tÿä'g/_žÍæ¼Aϯÿã©öo8Íh­À1È(JŸµçÿyk@‹8tÎKéOÛæ_Èu¹ü[¶ü~ݺÿZºTrá?PιãðÚZùýïÿý¦M¿TŸf«ïúöÞ{öÊA™SÎ8£œrΉCàøFí7vïÜÒéô¿xw&Ã%‰pƸ Ó”¤ûR©Ä¿8”Í…þíÛ·ü¦¾­c¸`ò‚EM‹™ÏUÊU+óÈ˲Ÿ¶>ù ´y BI““–eýú¼ó€1.I c@0Iâ”ÒÖVp¹O& C/Ô>¥àP‡` •@²/µŸyÂEío¿±îÈ „;á\BD8玄œßÞÞùÎâW¶ýú` ]fPŒ#@æDwråP=þôôh'ƒÔÏpûsW¡H¤«ªj€™¯=B êë»Sã£S‡³MY„ã“ šà‡]É”ÎvîXx²//.èÎ]ñ|:³“yÀËNØêÇ€©:é=8$k2gUáéBȶU5ào1W JÁv*´Sw§ BÁb/ øäÇØ À [†…f'÷?#m¨RÇï÷%18ɹOÀ9àcc·/Ó¢0 ؉Ã.Šß*ÓU>J«ªâÞ€ Z]TÝr%·á¤Ö †lȇÊÌfjkæÏ^…!˲ËËKÇÇ×¥Ó€1™sÇþµÑ²XKYË¢öE89ž—(`„¡ÖÓË}^ºð’½côøá§c{%)´n]XòT]îKÀ˜J4vüêr8£-ãMKŒÂ)Ñg¬ý¹«8ÇŠb46ÞÿÔSQ!‰sL)b H9Ï>«–•}­9ž ÿÇÙÇámà„F0È"̱D$Çq¿°ø–Õ·ŒgÆW­^³÷Ö[‡9—á„P„(Bœ‰~ÎÞqÇŠ•˧ÆSWÜ~ádãþ¼mº$`Î̉„]ÌßÛÎ} !ì)qè™8Þnö62ØB–åTVÆFF–oÛöÎÂ…9— âC>Ï~óO6ûðºuFÞ¢öòú垞ɬžq‰@À†XÓO›~°ð% KLÃR9]xásýýÞC‡Ê0çÂtÝÅØs7ÜpéW¾â²m“:!_¸â\ï†-oÚIÕ>™k(Ër‡È–•_ö_wËÕz¶€ÉŸ~Ì×£÷ðáÑŽŽ_\® Ó NM[WwDze‹t=‹s¯ìݵc×ããïïÖe½2Wy¹~ù­«nõVx z`B9S )ÈòÖßÿž>÷\ðða@hª©I¾á†s¯¾Z5M›1Br»Ü㙱ןØ8ôzÎâA¡ÕøœÛ¯ZµZÏèO¯>€y¤B8zÀ‡Â¹'‘È ¦¦ÉѨC× Óé)§G.ÈÙd–:Tój®ˆ+çäó½0=çœh>_šÒT>!¯×q!›eÓ@jƘ")ªWÉRº‘—ˆò…-åó:&j3æX›O*„£¾“$BbŒÛ6‰H3ÄcsI’ssF')gd”„$QÑB)åŸò$bU­àu¨ˆÿÉM˜éíÏ=Ø4£!„¥à8"ýâ””¯À.˜2É)(O1!ÀÎæ)Ô‚Bq`£!LÀŸËü;ú-þÔàÿ²ýà2úã ÷ŸÎ>U›¯*ük+¶ÿÐéÚñý %tEXtdate:create2017-06-06T01:31:12+01:00™Ò¡%tEXtdate:modify2017-06-06T01:31:12+01:00è¬IEND®B`‚puzzles-20170606.272beef/icons/guess-ibase4.png0000644000175000017500000000340413115373731020005 0ustar simonsimon‰PNG  IHDR²²¤ˆ[gAMA† 1è–_$PLTEÀÀÀ€€€ÿÿÿ€ÿÿÿÿ€ÿ€€€€-f´bKGDaf¸} oFFsKìloqtIMEá`"Ž vpAg¤e •ßßIDAThÞ훽rÛ8€A©I&g/¹suÖäìQÀIçê®Q7ìSÛ«¢ò2£FÝòå¿ä.v%-eÐ3‰´ f0à‡Å Àîza¥¼u=ɬ¬ëvH†PÉêóÙlVOúž²ÖWu0oæóy HÅDw\ãɸœY¹ê¾+Î]O÷]VέÜôC¦®g+ºüì8³O~Tvá;>„ex°F‡!ÓІÎX°Yæ4:zN×q•Gœê¦ se“WÙ¤kbŽ©ü\=ǃÀT~®òÕbq’‡&VÙƒÀTn.Èq 0•Ÿ«X,ç¡qäÏtkzNAÇKœùµòöXP¥‘U¡‰áTD‹°«€ZÑ"Ü*~ÓÈE+ˆ3Ó'¨ã*ÖШˆáVÁè, # çfê¸áíŒ×n_br®2¬³>,Ö9g÷F†8³?•z{òhífñx*ûÒýŒ×n¡íƒ×nÍ3¯Ø3˜ŒLä ÉYQ€&áÞPEQä}“p?k]¶¾Iz «­oRÞ 9Ñ]ÇÝÏù#ò)±or[ ùµœÈ2{#‘ï¦ûY ‹7º!a®a9ƒjÌi¼¸N‹å¥d¼lâ¬išîº÷Ëå?p×íÞ˜¸l¬Ü÷ÇàýÒÈ7pRv&NÊ3GnJ?*s`ƒCv_\6ñ® ®›O^~u£$—V][ùÆêÀͽ•ý¾ìdq6_´©î›Xe¯t¯²WZp°ä3@¶?ÐÛ¼üfÉ»š2ĺ Ml gh gæÈÐM£?;y€ä¯J8ì&›Ï xù¯LíŒÌl ý‘µ¡KFàæ GF6¨äöó &ß+…~Àå²’ÂÜLF&rÐdšM$ÚL6‘h?3c¢3ÈD¹‰î .›Hs×q1šû™#¿ÃfŽ|Jì›6$|6‘IJÙDßÍgIâ >›ð¶H#éïŒÖ0UHשc6ñãËxÙÄéz½BÙÄän½¾MMhŒ–Oý1¸°«gg¬Ñ~Tvá;Vó xº;Nê¦ sɳ t#•ëN¾ÛÎì¾gh6oÑ^å t¯²Wz@6| à¬++Kx+’# 8ÖÐβ H¾XG*žÀEØUH¢†Œ4\›ÏPÇw!™Ú9ûÌjQÇò °7ÐhŠ:Vò °ŸñÚÍâ±yÖ³‰þ &#9h2Í&í &›H´Ÿ™ˆ1Ñd¢ÜD÷—M ÷¾ë¸˜ÿ.Òp¿û™#CŸRŸû¦AÙ6Æž~Í&’øn>›¸Ãœýâ >›pèô1’þÎÆu¨ð '»_³‰ƒ•—«Mr·ëÚ¶}\›ˆKtÌI¹l­ ¬ML£ &sº'Ü>«MÄ¥PæFjƒ<ù!¢Ú)ßÒ[ô²#·CjQÝœË&z°WZT› erê­ @~´ Qm‚”ö©‡ÆðæÔ&ès@pû$"WÜ YR› Ï>˜è “s%«Mà×s.bü‘ÛœÝÏôoæSLæ¢ÜKL®Ø3˜ŒLä É$kK¶7üó·mµ‰=÷³{²·½6±× ¯ ·Õ&ßãŸFn¯Mìu×ùçœÛk{ÝÏŒÎLm"23—MÄfæìœÊÒ½‘Êw“ý¬¶Å‡Ç»jý܉©MˆãºãK§Ÿ^FË&Èã9QE¬dþ(ªâIN ý§AåQ”ML£›MT-%7—MÌ£«MR᥷(óCç$~é»n–ûSI%]–M  —Uÿ©‡eÈ8$Êe/h¼ÁqWÉ^YP2óc…/C˜è‹’q|x-zÍÂEŒ4›ÀäÑ œ-Q.È&R‘‰4™Øy¼½1Þ~ï &¸7_ü®ï~fþ)âC”M0vÏŽè»™ŠHoŒ#='®;f?½(]VQO:d}—¹žaC6‚ÁwYè2ÉÿB¾ä73Ÿ%tEXtdate:create2017-06-06T01:31:21+01:00&µ¼n%tEXtdate:modify2017-06-06T01:31:21+01:00WèÒIEND®B`‚puzzles-20170606.272beef/icons/guess-ibase.png0000644000175000017500000002216113115373731017722 0ustar simonsimon‰PNG  IHDR²²iè?gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“ oFFsKìloqtIMEá`"Ž vpAg¤e •ß#KIDATxÚí}TSwºïŸìð²H Å—ÊK‚(¤Ôu×ø’‚G­ÒR<¥•áåœ3ã½êtÅAÄŠ&—h«’D´¢rÑ5óÇÜé9=Ëe”C¯­.|éèmx±wqfx;&$È¢A$1ì@’½ïq(†6ÉÎêþü—½Ÿä›_ò½Éþý>aýíoÒ Ü¼y³éÚ5V;d2™&&xAA x¼¡P’‘±iÓ¦èèhò6‚š®i4Ú¡!“É4Áã-XÀKHJ$/d%°H¶Essó¹ãÇõzýɰ• xFÀ}€ç‹-º46ö¦‡ãˆØl»nÞÜ”‘沆֠¢.]{Ó‹¤ˆHl»vÝÜ´ÉÿApòäÉ>úè½÷Þ›v÷.—[WW—žž>×J®"Êòr9†¥y>®g¬b˜ª¼|¦ú‚”år9–æuÒºu •b*•ÿƒàîÝ»~ø¡Ë]|ðAkk«•\´ÅÝ»w 8îíÈ`Ž÷ut477û9ÈÐYP@Qм¯ÏÏA†‡‡_{í5—»¢££‡‡‡=¨tà¢-ª %†R22€@ÅØØùÊJU+”J,¢¤À@P(ÆÎŸ÷g@000àr×ÀÀ@DD„•éE:½~+5ãzF€N§szZ´éô[)MÊÉñgÐ$k×®uùÔ×ׯY³ÆƒJÎmqãúõ÷„ü‰d`d²X·nÝòOÐëï¿ÿ/‘T23ý4ÉÎ;=ÚÝÝí´½»»ûèÑ£;wîô Òs[476fa•#€,‹¥éÚ5ÿ57feù (ËÒÔ䟠I–/_^ZZºnݺS§Nét:›Í¦ÓéN:µnݺÒÒÒåË—{PéÀ¹·5Zm å#HÐöôø'H£MñARJ hµþ šÊ|°bÅŠ/¾øâäÉ“ƒƒƒQQQk×®ýý˜èq%Lo‹A£q1õCƒÅƒ££þ 4.öAÒâÅ08èŸ '+**È<ùJ烈ÅfãP?4Àl6ÿYl$…„†ù'ˆœÛ  þð`à<2F_àƒs0›ÃñO 8çEñùýCC‰=–ú¢žÿ—¾ (~ÿP"ÕIýýåŸ 'L&ÓƒFFF¬Vk`` @ HHHàñxÞT:Z$…÷)À}‘P蟠á}$Ý¿"‘‚¦Ò×××ÒÒòèÑ#«Õ V«õÑ£G---}}}WÂô¶dd|íƒ#d‡“š‘០IÆ×_û ¨“šêŸ IŒFcgg§ÝnwÚn·Û;;;F£•œÛbÓ¦MWpœÚ3ÀUß°q£ß‚®à6J“l6¸zß°Á?A“Þi +­Aq±—)Mª«¡ÐoA“ŒŒŒárA###T:pq©¬H&+ãp&(˜@Æåî.+ógP‘¬¬Œ3AQ’Õ 2w÷n9˜~P˜ŠmÊùJ.ÚbõêÕ1II5È,Ó?**ÊjµZ,‚ ^{íµ”””éï4ùJ ³ª¬··W%—?loW`XA¸ùvÞP CÑ8±ø@EÅÒ¥KI½~ RÉ>lW(°œÂÍÄ› jkA&CãâÄÌß Ê!»µµµµF¥êÑé2§, 0´4p8ßâ¸(>¾ðàÁÕ«W{ü„h ªQõôè23Z££`0@[44p¾ý‰â _Œ !Û¾ûî;õÕ«Ž…äÆñq~pp$Ÿ/ Sß{oãÆ3M/ž+t©¯:’ã|~pd$_$¦¦¾A”0·¶`xE æ‹†— ¦-\À´ƒ æ6Ìaúi¼ÑÔ£ÕG‡,Šòøa „¢„ôMÊ•Bך®i5ZÓiÂ4Ä â-à „¾p½DÚ'J˜ƒ$éÄÉs½½úðè-¨ ‹Ë_¼À³ÛŒÖqf¼4<1|·ÿ“B/•BÇÏ×ëõÈËÂ`š%‰ÓÀÁ¿Ácãbzï.z¹´OBJ’tøSÕ­!"N¾0›Åšñ;‚°?1\z¬‘&.[rôˆÔ¥\%ï2t™f aIB¥hÒ’$…gKûD9³K’þù_v<²ä %í‚E¹nzX,¶`Q^BZÇ#,;ÿŸ¶ÏU)”¿#ÿ^Þ=s»ÈY’,–¶ì¶\ÜE/—ö©³³³¸¸X"‘ˆÅb‰DR\\ìF’D²ÒÝ5‘¯þTwøÓÊ%o^,Ìe±Èžœ²XìpI0ï­¯þ­ <,T,Nžõ.ë.–W–c—1"—˜ÃI0 a}ËÚXÐ(ˆ“ųޣîâÅÊòòË–KsÉ A¼eµ46† ÉâùTWWZZúàÁƒññq˜˜˜Ðëõõõõ‘‘‘ÉÉÉžU‚{IÒÞRyÜju0×CÕÏø˜¦§5ítÕ±Y•BÅòbL–$4 ­&ã.z¹´OÛ¶m³X,Ów¡(úå—_N•$‘¬tຕu:]é>Ù’”Z{‚¹¢×߬-Ý'ëíí©F§Ó•ÈJ°Z/zD`©µ”ÈJÜÉJJj½x«@Pk±ÈJæEÔÔÔ8þô§3>>^SSãA¥×mqè°R+ðVõ±N#=ü©j¦‚re9&Ç€ K&ÅÊUóÀÆDWüðÃn&îþðÃT:p-Iz 1DÆx=4€ÈØ=]Ý}3)…: 8EJ!|ÞÑ7lL´9ss÷©{ÉW:pѪãÕ „J‹Õ‹¸ ^ñù©óÓw)ª˜ê,IcбÊó~µ1Ñä€Ë庹ûÔ½ä+¸$éõºð…[)@ø¢—J!½NTæäøÛÆDKÐ$«W¯v3CsêÔ ò•Ï6:ݾ~ý†`Ñû,•K¤Y,vXt¦“éçúëÈûÈ¿|Ÿ 6°2ýgc¢+h’={ö¹Ü´gÏ*LsgÝjFó(GuýFÓÔ-͘”B–,˵&?Ù˜è šdùòår¹EÑ©Ÿ‚ (*—Ë$I$+ŸírºÝ£ÕpøÔ«~8¼mvê­F ¾±$õhýdc¢+h*[·n½páBzz:ŸÏG„Ïç§§§_¸paë4ãùJ˜~uôÉà’`êU?èâÑ‘Á©[ŒƒFð%itÐO6&º‚œHLL¬ªª"óPä+?-¬V ‹Mýj|„21ñܬÍbßX’l˜ŸlLtÑ€s[¢„ú$n7=÷¢ àKRÇO6&º‚hÀ9/,¦éûK~Õ)¥{¥ÐiÅi4ï,Ih>zfVwÑË¥}I’ÂÃB¯Ô |IgÎËžßîýÏ̲OŠÞ}÷÷•K—.„ Z ZlxdIB3Qi‘ô]2KûäI’Xœ,N^Vûå.œà†­r¿HdŸx¬«z¬)9S¥œµ'ž%‹S–¥ÜÜuÓ`'V@Ú’„T!!%!ÕÊêY{ÂÁ˧}ò§$éð§ª®î‡ „Šð…9nfè„mäÇÚÇZYÒò¸#Ÿð@)$WÉÛ¶c ŒÈ!`6K*CÅqâ ÏÜE/—ö‰ræ I:q²¦§§'|a&'<‹Ã_ˆ.d„Ùm£V‹3¶Yž4Œ¾ Eû?)ôR)¤ªQéztHæ”5¨S,Iœþ-/Š?è½»èåÒ>Qˆ'’¤Æëj­V3::dÁŒ(‡)ŠÞIO¥\)tU}Õ±b}Ü8ÌæGò…"á{¾p½DÚ'J`$I .`´' .`Ú‚ÁL[0¸ÀIRÓw×4ZíГil‚Ç ZÎK %| ¢-ˆ‘$=Ï$I窎ëõú-Ë‘,!¶2†/Œã`x ÷ AÃù¦‹‹-ÜëµRˆ¶ F’4¤$Iª£rƒ®K±Þœ½Ø3vì8\êéŸÑ%Â$éa”B´1’$·ÌÒjµZ¶¿DžŠí^…;±Ú¡æDÙÌ©¨<íÞÚá· ’9†íÆq’GP+@ ‚(9œŠÓó1¨³³óܹs­­­&“‰Çã­Y³¦°°púB1˜Ë_w×Dêþt±òhùå,7™@X@6’׉·[ Î6†† ’ɸ‹h z…%I}}}mmmOŸ>uÌÞÃqÜl6÷÷÷ñù|çg2S[¨ÕêÊcrõvË› Å„Av¢­àw-Ë’RÜÃOk\®¶XÞô$b²m¶‚––e)ó%¨££cïÞ½ŽK_“ ‚°ÙlMMMëׯŠz¶Ãh4¶µµMŸ£EÄððpdddppðÔí3J’dûKj³±xxŒ(jn‘íŸM)D[Ð+,IòvНå‘ry*–æõyϺJ0Õ‘™•B´½Ú’$ ¦øÞ½{× ë,øE¦ŸÕxŸff¥mA¯¶$‰‚)¾Õ'Ê X É©#³Èņ±óg\)…h zå%IÞNñ}fúYAÑÈ 'if¥mATæ¼x’$o§øÞ¸~ýýåÉoHÂF 3Á•Rˆ¶ W^’4×)¾Î¥Í·³„>0ýˆ,Mß=¯¢-ˆ‘$ðx¼¤¤$6›=õ3crŠïôo´œ›[£Õ¦ü7ʇ)Ñ UOS ÑD}Î<’$%''Ÿ?¾¹¹ùéÓ§¡¡¡‰d÷î݉‰ÎF…%K–ðù|­Vûøñc»ÝÎf³###…B¡Ëo9Ûbpظ˜”³˜ƒ#Ï+…h b$I‡Çã­\¹’L¥óAÄ2aãø@½ØøóJ!Ú‚IÒÜqn 4(óÁs0[ü¼Rˆ¶ F’4wœó¢"øý¦¡ÄÇô› Jð¼Rˆ¶ F’4÷JçO‹‘ð¾ë’½âþˆœÜE´1’¤9VÂô¶lÈøZëÓ†“ºñy¥mAŒ$‰IÒ•.ÜFÍ—úϰápõ¿\)…h b$ITH’b/wP9¶ºvºtÑÄH’¼¿‚Z´OVögÂÝ%·9`µƒì6w÷o])…h b$I”H’bDI5w)2ý´"±ËfV ÑÄH’ÈU:p=éá e3çŽÞÛÝÑCe+÷à¡™•B´1’$J$IЧó.£šaϦ†ü˨òälJ!Ú‚I‰Jî$I¡a‚‚ßµHÛbÜ}›âšÛzȼˆ퓾CÆ]D[#Iš­Ò»ÉÉâeI)»ÎÞ ûªE›ÜsÂU-HÉåçÕ³¾Ut1’$ %Iª#ò‡švÅz,'™p3qƆCm;ÈþŒÆ-8ä‘Rˆ¶ F’ä–9H’jªT==ºÌeH–èÙÒÐ0F-`x mРá|Û‹Dñ…{½V ÑÄH’fÀI’úÖUV;4b2Žó¹Á‘¾H$L}ÛJ!Ú‚IÒó0’$0Ú0mÁà¦-\à‰$©ñFSVc²XL(Êã‡-ŠÒ7I¨W 5]Óh´CC&“i‚Ç Z°€— ”H^Hw‘#è»kw´ZÍÓÈØ„™Îˆ„¢ ÿðK’Nœ<×Û«Þ‚ ²¸ü•Á Ù<»Íh7`ÆûØHÃÃ7qqqû?)ôV)tî¸^¯ß²ÉÊÂV®„… Ç£ ¸8ß|ƒÇÅÅ¾î¢æææªãgõzýrdµûY4ć‚ 8ã0öF@§áüÐß‹Û{ð·/’$éð§ªZCDœ"|a¶!dã€w€úÏè—¤ØÃ ¹ß%I³œ[¨Õêþ—,yBI»`Q®û `±Ø‚Ey i°ìüÚ®V«É?µZ½cG~^Þ½övsn.¸½ l6äåAG‡%;»mûöÜ9åççÝ»×n6çÂ,?FÀÈè°X²ÛÚ¶çÎ9è—ùÿ=â^Ê.su2¤!n_j1¬ûØò¿mâ_än›SPgggqq±D"‹Å‰¤¸¸¸««ËËJw×D¾úSÝáO+—¼yY°0—Å"{rÊb±CÂ%Á¼·¾ú·‚ð°P±8yÖ»ÔÕ]¬¬,¿|ËÍ%ÈÏU`³A"!ÞzËZPÐ:¿$IºX{´\‘ƒH&ÒX¤Ïë@^'–/¶&žmü,LÀK&õÒ‘•$‘¯7µZ½·T·ZÌõÐë2>¦éiM;]u̽L­VËåÅj5ï©?F£´4ôرêÙƒŠ‹Õ^xj4i(z¬zö ²béÿÀTðð,r~üWTz¢Zå>¨££cÛ¶m‹eú.E¿üòˤ¤¤¹V:˜Q’TºO¶$¥Ö㞀`®èõ7kK÷ÉfQ ÉJjk=ï ‰ ¶Ö"“Í w‘N§Û_r +ó¸' ýÜR¶¿äU’$ò•\·Å¡ÃJA¬<4Â[×OhÄ:AŒô𧪙 ”Êr¹KóÚ)´nH¥˜JåwÑ‘òc©X^ $ÍåQ]ÉìçGÊ+ÜÔ—$‘¯tàZ’ô@cˆŒ)ðú5ˆŒÝÓÕÝ7£RÈÐYP@‘RhÞ×çI’®óáÏð÷( Zÿ£¦CG‰$‰|¥m¡:^½@¨d±¨qý°X ⟟:?}WuµB©Ä)r ‚B1vþ¼?ÝE'U°mì9~I8lØ0öË3•Õ3—$‘¯tàB’¤×ëÂn¥d`Âå¸V éô[©Ìœ?K’ôzÝ P”©”H’ÈW>Ûètûúõ‚Eï»ù:`±ØaÑ™ÎJ¡×ß¡v)6› ™™~s]¿~c9²!û»Œ¤@I`ýÌ{IùÊ¿ç>Ï[Íhx¥¯!GuýFÓÔ-ÍÍYY>P eYššüã.ºÝø…Ø*ʃD–Uß]s½À€¼$‰|å³]N·{´Ÿzׇ—¢íÑNÝ¢ÑhS|àJI­Ö?î"­V ±”ECœÓK7•­[·^¸p!==Ïç#ÂçóÓÓÓ/\¸°uÚá™|%L¿‚:údpI0õ®Ÿ@tñèÈàÔ-ƒƒÆÅ>p -^ ƒƒþq ‡x@µ¯€#£Cn ÈK’ÈW:ZX­›úÕø;dbâ¹Or‹ÅæƒUÿæwÑ„m<‚<}¼ tÜfñþqæ„s[¢„ú#1n7=÷î h€Žø`6‡ãwQP@° ¨Z–üV° >;œ"aáQãýhÅ®«¥?L5uKT¿¿(‘j§P?DEùÇ]Á_`ZK¨ 2Á° Ìݱ©³³ó‹/¾p˜n^{íµµk×îØ±ÃËŸ™qþ´Š0#õ®Ìx_$MÝ’ ¼ï§Ðýû~“$‰„¢ÐQ4:§—n*õõõ»wïÞ¼yskk«ÝnommݼyóÇ\__ïTé•$)}“Ä2ò5åc³øàƒÖÖÖÉ›H’” jÊœš“j‚°õÈö•îž¾«¨HVVÆ™ èäÝj™Œ»{·?ÝEûd{¿ãü«¨ùl²ƒí6÷ß[V4SÁðððLK£££‡‡r†P#IZ‘ó¸·¨à±þìŠå±3*…b’jj(R Ebcý/I%ÅßE®PÔŠüŸeb¡›¹à`¦«h“7©‘$ùL:Ò«|:ì­ëçéð'+|vp¦©´B©äÜñÚ)tçTVrô¿»èp…¼™sIÞ®ìÕÃßZ¹õ‡Ž¹û­²µk×NÿÃA}}ýš5k&oR&I:õ¹¢ï/yãcž»~ÆÇ4}ɯ:¥œE)¤8—‡j¼p i4Ÿ*•óÂ]sâôñËè‰aøÑã aøñ2zòä™J÷’¤;w=z´»»Ûi{ww÷Ñ£GwîÜ9¹…JIRxXè•Ú”/ âÌyÙÂÓáÛ½ÿ™YöIÑ»ï¾ã¾réÒ¥¡¡‚‚‚‰ÄæÁòˆÛ·!3-*š_’¤0ïw-ŠÅ¶Ä0ˆ"÷ð?¡‡¿^Dî“–¼3ÛKñë_ÿšÍf/Z´(44´··÷øÃ¯~õ«ÒÒÒ´)s!ç*IšýÇ´K÷É1ÒÈØ=$çkøÄcýÙ'}'ªN)%²sRÔjµLV"•b{öà$çkMLÀٳȉ\¥òÌÜ‚JJ¤¶ÇIÎך8‹ '¸\噹í/9 Á~¾ÿG’óµì`kE¾nåþÇÉ3•䃺»»ßrFEE­]»vûö퉮¾?6™L$f†”$éð§ª®î‡ „Šð…9nfè„mäÇÚÇZYÒò¸#ŸðD)¤’?|Ø®P`99„›:6ÔÖ‚L†ÆÅ‰˜¿î¢ÞÞÞ#òcšvÝzì—ÉDª›:8ØÛáû?£ÿ¾L,:Tñ?_$IÒ‰“5===á 39áYþÊ@t!; ÌnµZ ˜±Íò¤aÄð­P(ÚÿI¡·J¡UO.3ó§5¨aa0: ´µACçÛoq‘(¾°ðÅpµ¶¶V©Îôèz–!«Dتhˆ…pB,`~ O Ç±U/Ú{ð·/°$©ñºZ«ÕŒŽY0#ÊᇅGŠ„¢wÒS©W ©¯:V¬ã|~pd$_$¦¦¾î"GЭ«·µZ͈idlü)78TÀ Eo¿·ž‘$1¼0Ú0mÁà¦-\à‰$‰6wѵ¦kZÖ4dš0Mñ‚x xÂa#Iò=s$Ñæ.:~î¸^¯G¶ XÓäEœþ {‘$ù R’$ÚÜEr•¼ËÐeV˜„¼•¢IK’Œ$ÉÌ.I¢Í]”¿#ÿ^Þ=s»ÈÉ‹,–¶ì¶\F’D³$‰6wÑź‹å•åØeŒÈ%æpÌBBXß²64 BbF’D$‰6wQ±¼Scà…¼MC«IÒ|%I¢Í]T"+Áj½è ¥ÖRÂH’¦àImî¢re9&Ç€ y&ÅÊIÒßñ‰$‰6wQ§¡§(߃w0’¤öR I¢Í]¤¨V`J ¨“)Æ*I’«½H’hséuz 4IÒß¡X’D›»èúëÈûEW“IÀb$I@¹$‰6wQcs#æƒ K–å#I¢\’D›»H«Ñ‚oäE=Œ$‰rImî"ã |#/e$I^W:ZÐæ.²Ylày‘‘$ys[Ðæ. @À7ò¢F’ä5ÎmÅïï§>fº»ˆÅA?„M—$ù$Ç•$ †<}¼!#I¢ü ªs[Ðæ.&Á7ò"á«$Iª««Û¶mÛ­[·L&˜L¦[·ný⿨««ó¸¦·mî¢ IÇAœNÆ«$IR(†M5Ýà8n±X ÅTIùJ.$I´¹‹ð+8E‚É$À¯â_I}WPétÅÆÅÕò¢øWI’DëTÚÜE²"§ŒCÙÉ»¸2nÙ«$I¢õ *˜$„¢ ä,"~Å$Iô]Au@›»¨BZÁQr€ y·’{ì“$ÑwÕî¢ÓŠÓh ÞÉ‹Ð|ôÌ«'IòÝTw’$ÚÜE‚PAKA‹MbäEh&*-’¾ûJJ’¢££Õj5Žã“g”‚ËåòuëÖyPéÀÝ‚€ädñ²e)»vÝ °¯ZE°ÉM$˜˜€ª*¤¤$D©¬žµ'ˆ“Å)ËRnîºi°«²3&©BBJBª•Õ³öij‰ÅËRRvݼ`·¯"Ò9P… %!!ÊêêY{âïAÉI)ËÏÞüìÈ""!·&À¶ä?n„üïÏ«+gí +V¬xûí·‡‡‡­V+Ç[¿~½J¥J›6—|%”$Ñæ.’«äíÛ1Fä0›¼•¡â8q#Iòs$Ñæ.RÕ¨t=:$sÊÔ)ò"NÿÅd$I>ÃIm꫎ëãÆñ`~0?’/ ßc$I¾‡‘$1¸€Ñž0¸€i 0mÁà‚¹­Ÿ0 cccV«ÇqACBB¢£££££ƒƒƒ)yZL!{Ê944ÔÕÕe6›Y,–Ëß,a³ÙA„„„¬X±bê/YÌ&Èã ™½-Ìfó_ÿúW“Éäþl&A$,,ì7ÞpÕŽ ¢0ˆrþ?0%zâæ]ñ½%tEXtdate:create2017-06-06T01:31:11+01:00¨:»%tEXtdate:modify2017-06-06T01:31:11+01:00Ùg1IEND®B`‚puzzles-20170606.272beef/icons/guess-base.png0000644000175000017500000004571613115373717017570 0ustar simonsimon‰PNG  IHDR¤³Aw°bKGDÿÿÿ ½§“ IDATxœíy\Sg¾ÿ¿Y€ Á j e)u츤è¨cm-UÚ"Î:jgîµXÄ¢eùIíT ˆZT.v¶NGï´ jé­K]GÛÈÒûª:–mLÈØ †’œüþ Ã@€ääääNž÷&OžO„|ÉYžïóf}÷Ýw€@ †Àvõ@ ƨ*KPU – ª@ ,AU@X‚ª°Ua ª ÂT„%¨*KPU – ª@ ,AU@X‚ª°Ua ª ®«ßÀø¢µµõòåË7ΟWªTí===ýý|OÏÉ|~¸X,]¾|éÒ¥AAA2èÆy¥RÕÞÞÓÓÓÏç{NžÌK¥2ˆX¨o€ŠŠŠÃ{ö455½Äf'èt³‚øÝ€Ûå<Þ IËÊš?þÄ:¼§©©é¥—Ø ºY³ 8ø|èîn߆òrÞ™3xhhHZÚÄ¢ T V«óss5õõr­6€3öHÀI€l ›•-—‹D¢ñ”Ÿ«ÑÔËåÚÄDàŒd2ÁÉ“MŸ•=~ƒhÆÝÏ+ ź””ä›7k´Z™ÕO*p’jõúÄ[·ÖÊd …bœ­KIN¾YS£•ɬ}R€Ãäd¨­Õ'&ÞZ»vœÕÕÕegg/]ºô©§žZºtivvv}}½ƒ#­ãÖUQVR’›ž~Z«MÇqâ'X8^¦ÕnOO/;~||••俦Ÿ>­MOǹ„“<< #/+Ónßž^V6¾‚NŸ>½aÆçž{®ªªÊd2UUU=÷Üso¾ùæéÓ§I´‰ûA)ŠÜM›:]Ù” 0lWQQ\\Üx ÊݤPèÂÈ&)•°`¶k×x ª­­}ë­·¾þúëððð¡ß½{wÁ‚‡ŽŠŠ²w$8iiiÄG3µZþ«_ìí}ÚIü¤FãúË——._îçççú ô_<Ùû´Iþþ •ׯ¿¼t©ëƒ`ß¾}¿úÕ¯^|ñÅ/÷÷öö.++[¶l™½#‰à¦GPyÛ·çêt žg!@¶N—¿}»ëƒò¶çæê8œ´p!dgëòó]ÕÕÕ¯¼òʨO½üòËUUU$FÁ«¢ººZSW—Šã”̶Ç[jk+**\¤©KM¥(h#ÞÒââ :::¦L™2êSAAA$FÁ«¢H.ÏÓé<(šÍ@ÞÛûaA+ƒŠäyy:Š’<<@.ïýðCW  [[[G}ªµµÕßߟÄH"¸]U´¶¶ª›š^¥tÎ$µZmñ[¡5HÝô*¥III® dþüùc]A:}úô¼yóHŒ$‚ÛUÅ¥‹W²ÙÔ.táijXW®\qMÐ¥‹+W²‰_%Äøx— òÆoìܹ³¡¡Áâñ†††;w¾ñÆ$FÁíª¢âÂ…ŽòiôúçÏ»&¨âBB‚‚ô7n¸&h™3gnÙ²eáÂ…|ðZ­6jµúƒ>X¸pá–-[fΜIb$Ünu R¥Šu´±ªÆF×)U±NHŠ•Ê5ACyùå—###9²oß¾¶¶¶ÀÀÀùóçÿþ÷¿Ÿ1cé‘6q»ªhëîžæ„i§´uu¹&¨­{š’¦Mƒ¶6×Y0cƌݻw™ŠøHë¸Ý”Þhä9aZÑèš ½‘ç„$Ðé\ärÜ®*0.—úCc-oøy(}A× ç/ Õçš —3¾Þ  ÷ÛÛí>Ò´Å}€Àá+è Ü¿ßnÿÁ³­ ûèš zzzîÞ½ÛÙÙi0<<<„Baxx8ŸÏwd¤uÜî»"\,¾í„ioHÄb×…‹o;!éömH\4”–––ÊÊÊ 0 <¨¬¬lii!=Ò&nWÒåË?wÂÑq9·|¹k‚¤Ë?ÿÜ A弸8× ÒÝÝ]WWg2™,7™LuuuÝÝÝ$FÁíªbéÒ¥_à8µ'wF€s8¾xÉ—})M2áÜ9|ñb× r÷î]|ŒUd8Ž+•J#‰àvUrŠÒ9ËÄaaÝú´…†œ¢4©¬ Äb— ÒÙÙi6›G}Êl6wvv’I·« HÏÉÙÆãõS4› ÇÛ{öm® JÏÙ¶×OQ’Á99Þ6¸2h€‘GDC1ùÚ">’îXsçÎEE³©ù¿b³CbbFݺ‚Ö QTq1EA‡Ø!!.€cµœ;ä 5ñ‘DpǪ€ìÝ»óx¼ëÏs ÀÛ;k×.×eïÎËã]w8éúu((ðÎÊr}øûû³X¬QŸb±XB¡ÄH"¸iUˆD"ùÉfßYØp”)–wðàO<1.‚ä’“1;O,‡)!%ËËAÎã›–ÍfmÑ&>’nÚ· O>ù¤¯P˜ZY)5IlNt ÃÒ³³Ÿá…qä+LM­”J$ö[ºv âã±ôôìçŸ/A^^^^^^íííCd±X'*** €ÄH"¸oU@tLLDlìúË—¹&Ó³ÙúMƒô²Ù>>yEE6?©tEÇDDÄ®_™Ë5Í™c¶¾GÓ¿ƒú¡°‘á“—Wdó“Js@  4 z½Þl6s¹Ü)S¦ÄÆÆŽü i÷ÝùfæææüÜÜ{55r.Él¶r^f(ÈÁ°Ð˜˜ÌÝ»Ÿ|òÉñ”Ÿ{ï^\®KJ2[9Õ4¡´rr°ÐИÌÌñD3¨*~ ªªª8?¿Q­Ž²ý«@€à@9wÇ%aaiYYsçÎAÅùêøøoÿêç]] ÑÀ­[P^Î;{—HÂÒÒ&Fm ªFkkëÕ«WçÎ lÞÝ×'ðò $bqÜ‹/.Y²d¬$Æ{âÜÀVáÝÝ}W@€@"ÇÅMÈ @U@Xâ¦Wf+ ª@ ,AU@Xâv½xÖÐX]¸t£Q¥ìîj×ë{0Œ/ð›,–„/[*¥Ü—uþÆy•RÕÓÞÓßÓïÉ÷äOæ‹ÃÅË!æbÓŒÐÙöTTTìÝw¸¹¹iRÐK˜0Á[0‹ëÌáòMÆnCŸF×}[×YþHs&44të¯Óôeí9¼§©©‰ý[— ƒ 0^9?ƒ‡„†d9.æb–ÓŒ6PU€Z­Þñ^þ]•Æ?T>)8‘Åó>­Ùlz¤9ùP™=#búÎ÷³Iø²rósë5õZ¹(À°l,jz”œœ˜‹YN3šq÷ó …Bñ³ÿX÷@Ÿ,–֧ʬ”°XáÔäðµt‰)¯­µ×—•².åfòMmˆ)Àôµú[‰·d$Ä\ÌršÕÕÕmÚ´I*•ÆÄÄH¥ÒM›6Y1€i·^uüDÙŽ÷ ¦?}J,c±ˆþ`±8>“¤^ügÿOê$?ߘ˜h›/))+Ù^°]wJg–™íøCijÔlxÖp!õ‚ÐWcóe%%Û·ŸÒédf³=9 5›Ÿ5R/\ð £cÆSPYÙ–-[îÞ½Û××ýýýMMM§OŸˆŽŽ&7Ò&î{¥P(6oÉ «ðò&é±êëU6V-8P¸Ë¦/kSî&B(À°X1³œfµµµ«W¯Öëõ#ŸÂ0ì/ùËPÁ‘DpÓ#(µZ½åœé±¥¤K¼¼%O<]ºåœææf+A9ºRJ$ /ÕgädXÊÉÈ(uà“ €R½>'c\@qqñÀþ‘ôõõ“I7­Šwwä Cr}ýõXùú/вw¼—?Ö€íyÛu¹: B¦ËÖm·"æbœÓ ¾ùæ+{|óÍ7$FÁ«¢ººú®R J¥d¶€õ -cù²ê4u8E¾,|#^kEÌÅ,§Ù½½½V^>ôYâ#‰àŽU‘¿§h²8Å¢ÆcÅbyL“ïÿàÑOÉ‹äº<P§ë•÷Œ*æbœÓlooo+/ú,ñ‘Dp»ªhmmmjRO ¦Òc5ijÒ¨¾¬&uP­s±jŒ– AæÎk¥{h«ñ‘Dp»ª¸xñ’pêJ‹Ê¥.,Ç/(ÞBcuñÒEöJ6ÅKj8À)æbœÓl7zzzŽú”§§çÆIŒ$‚ÛUÅ¥+ؤʧå .^º1ô‘ tNðeéôço¸H5FWÐ 3gÎÌÍÍÅ0lè÷›ÍÆ0,77×ÂFp$Ü®*UJž€z«jT }D¥Ts`*©Æè Ê«¯¾zìØ±eË– 6›-–-[vìØ±WG¸\‰´‰Û­™ízÔ6Ý‹z•6­«³mè#ÝmÝàXW›‹TctY0cÆŒÂÂB"Si·û®0ô,õÛͳ9>ýýÃŽ.Œz#8GfÔ¹H5FWËq»ªððÀÌ&êŽq“ÖÓsØg†‹qÁ9 0.ÏEª1º‚\Îøz74à7)°¿ï>Æ¥ØceÐß÷}D(h¿ßNP€ùºH5FWÈætÄ’p]7õ+]÷m‰X2,(\ ÎQ€‰-Ä\Œsš Àè`ÙR©¾ósʧÕ?*_öܰåŸË¥ËyNðeñÊyËã\¤£+hd£‰¥K—vj¾0›©<½3›­ç–,Yl„Õ 0ü¾d¤˜‹YN³AŒ&‚‚‚BCCi¨ôX=ú¾L&éË ª`a£Š¹˜å4Àè#s[z›r›§Æce6ÚsÞÙ²aäS9é9¼m< Næã½mT1ãœf }Ì;7r†èa³}(cñ°éPä̱|YQ¢(6E¾,ö!vŒ1³œf ­¼ÿ›ìÎæ¼ÇŽz¬w\t¯àýßd5`wön^¨P€yxï²"æbœÓ ŒfD"Ñûå-Oîë%ï±êëU¶ü=¥ðƒ<뾬òX2Ž)À°ì M1³œf€ `ôóä“ONòóý¢4H=yvoOô¸ãZó·ñÛ~þ ÏÛ ú +S+R#R€añXvzö DÄ\Ìrš!˜ ˆ‰‰Ž‰Ž(ýËzÜÌõö›c}3¨AÌxÿCuáCeÆÁÂ<›%ñCPtLlDìåõ—M\“yŽÙÆÞIƒô»í“áS”Wd³$`žÓ À\CssóŽ÷òëîMË''YiH2›ß—>TåDÍ }ÿ7™$|Y¹ù¹5÷jtr9Élmµ °,&4f791³œf4ƒªâªªªöî+nllœÏ›”ÀÌòÀ‚9\?“±Ë ×èºoé•wjΊŒ­¿NsЗ•_œ¯nT³ã‡ì3;DÆ+çágñ0IX–ãb.f9ÍhUÅ04V.*T*eWW»^×ñ~“$bÉóËâ(÷eSœØ“¼¯»ÏKà%ˆ%â!æbÓŒPU –¸é•Y ¨*KPU –¸]/žu~ÐX]=¯T©Úõôôöó½='Oâ‡KÄÒÅNðeÑ„ `ö€Î¶ ¢¢âpឦ¦¦—f²ĺYAì |/èîÍc¸Ý åJÞ™<44$m³Ã¾,Ú‚Œ¨*@­VçïÌÕ¨ëå‹´‰‘Àû Ò„ÃÉZÈþ6]•½ƒ”/‹¶ dsw¯ …B‘³5#7N·aÎ%v’e0Añ7ì¼ Þî‚Ö¥$. ÊÈÈÕé6à8Áãc@1›Çãí>0ƒêêê>\UUÕÓÓÃçóçÍ›—––6êv€TífàÖë ÊN”ìÜ~*I'‹6³G_†< 6HŸ0?;Íz肯Ÿ0šˆ˜‹¶ 76€µ´´ÜºuëñãÇ­ª8ŽkµÚû÷ï{zz ÂïÀ«B¡PìÊU¬Õ?Mê$Pä‰3Œ©¿«ŒˆŠµ¾ª‡Ö Ü\…^ÿ4™$©••±ã%¨¶¶vóæÍ«ý4›ÍF£ñÆ‹- üa·¡îîî[·nìÈ3›Í^^^Äß¡›^™U«Õ9[3Juaöµ£ C⥫ô9[mù²h rcÚÍ€òÞßž§[àð)ßBdKuùïíË¢-Ƚ `h7G©®®Ö¨ëRL‘Æj.Þ¢Û—E[{ÀÐnŽR´Ož·XçA°SÆ/îýðàh¾,Ú‚ÜÞ†v3pˆ4V‘TΙ5¶/‹¶ *s&ž ífà—.^\9“MðŽA8lˆÍ—E[ÛÀ¨ÝÍÀíª¢âÚ…±4Vý«Ã}Y´!ŸÏŠŠâp8C¿1w3°÷FžÛ­TªT±³©Ÿ66Tо,Ú‚¨ÏG°èèè?ü°¢¢âñãǾ¾¾R©tÆ 3fX*¦OŸ.T*ÕÇM&‡Ã ‹Å$îm»]U´utO³û§d›i|hëîË¢-ÀþŸÏŸ5k–ãoÉ펠ôýFžþøx€®o¸/‹¶ d£·« Ì“«s¯@kž×p_mAÈF5ãëÝÐ@ ¿à~OûŒÉO{¿…Ã}Y´!˜ý#­ãvßáñíÑ/Ž;ÄíVXˆ¹h B0;GÚ„âªhmm=vìØ¦uëV,Z$=;&&F:{öŠE‹Þ^·îرccݬ¡éâ埫œ ±Ròâ– ÷eÑ„ `ãÖVQQ±&11%>¾yÿþÔêê/ÛÛÿÙßohéï?ßÞþfuuÓþýÉññk+++© %ÁÒ¥K¿¨ÇÔ,äù#çþ1š/‹¶ dokfÕjuê/~‘¿iSVCƒ¦¯ïˆN'ˆ8šÌÕéZûú2v¿õÖ†Õ«­/!vAAA¡¡!§j©œ³¬ģйh B°qµfV¡P¬KII¾y³F«•YíÜ@2@­^ŸxëÖZ™L¡P8˜NŽôwr¶]åõ[[diä\óÞðöh¾,Ú‚lü¬™-+)ÉMO?­Õ¦îÜ€ /Ój·§§—?îÈ ÇܹsE’¨âjŠ4VU숱}Y´!±‘D ÿßS(‡÷îUèõD›Ò‡³àk½¾xÏ—|cdïØWÁ»Þäè<×›  Ê;ëݱ}Y´!˜Ë×ÌÒÙ¦è D"‘|ïäS˜²ƒü$ÊH9…åí³åË¢-ÀŒ$ÉÝ 27n|«¥E6Æù qD\“é£ÚÚ‰‰Ne/O>ù¤¯Ÿ0õw•ÒiF‘µ›H£s­ âK°ôw²Ÿ'"æ¢-Àl$™ª¨®®>säÈÇ%MfsÌæ¼®®°§Ÿ¶þgÃDGÇDDÅ®?t™ ¦9SÍV¶-J¿ +Ù—|òöÙü¤Ò„ `®2€­ILÌjhÙû²±9°wæÌ#'OR7¥477翟{OY#_¤KŠ6[é2âPZ9ÃB#b2ß%åË¢-ÀÀîªhmmMŽ×ôõQ¸‚ÊìåuüìYnÐ[UUU\˜ßبŽ`'H~ØþÕƒ.=híV(WòÎ6àIXÚf‡}Y´!)쮊O?ù¤¥°ðÏT÷d­Á°Ð­[ö³ŸQ;­½ü ±ºrN©Rµwöt÷ö ¼½„‰D÷S'ø²h B0{°»*6­[·¡º:‰ê÷qà÷óæüøcª'F ìÆî+³.iSD èÄîªpU›"AvW…û´)"Ü»¯$a\®Î`ð¥ú}Œ“6ÅÕ…K7UÊî®v½¾Ãø¿ÉbIø²¥Rê}Y7Î+•ªööžžž~>ßsòd~x¸X*b® «ç¯«TÊG=½ýZoOŸI|¡D,Y¼ü' 7€­X´è¼ÚëV~~õ*Õ¥¢¢bï¾ÃÍÍM“‚^„ Þ‚Y\¯`—o2vú4ºîÛºÎòGš3¡¡¡[æ¨/ë𞦦¦—^b'$èfÍ‚à`àó¡»4¸}ÊËygÎà¡¡!iiCÌUQQQ¸çPSSÓLö\±îÇAæ B/àõAïcèlµ’÷M^º9ëmfÀÞ^·îÍêj oá pàóçøÓŸ¨žØ6jµzÇ{ùwUÿPù¤àDk̵f³é‘æäCeöŒˆé;ßÏ&ãËÊÏÕhêårmb"XYåi2ÁÉ“MŸ•=~Å\jµzgînuý½EÚ×#áYöØä8ൠøöqTÈyî87€Ù}^A›¢SQ(?ûuôÉbipªÌJI‹ÅNM_Pû@—˜òÚZ»Vû*ŠuëR’“oÖÔhe2k%$'Cm­>1ñÖÚµö5¢ÐÖñ¢P(^Où…ÿÍØõÚ¢hX`¥$€ ìXø¦þ¿…·b~.[mWP]]ݦM›¤RiLLŒT*Ý´iS}}½ƒ#­c÷:¨)S¦ìþË_¶˜Lv|R9œ­Û·ûúR~Âbã'Êv¼W0ýéSÂ`‹Eô?Äbq|&I½øÏÿŸÔI~¾11Ñ6_RVVRP°ýÔ)Lf&Þ›Àá€Tj~öYCjê_ßñe;QRºs»¯pÏ!›Aµµµr¹\§Ó íÉÆq\¯×ËåòÚÚZ#‰@æ/>ÍmŠÎ@­Voy'gzl©—7ù/oÉO—ny'dž/+'£´Tæ@'ŠD¥¥úœœq!æR«Õ[32uÛ„@þ¯˜?L]¥ß¶5#“*ñ‘D S4·):ƒwwä Cr}ýYùú/вw¼—?Ö€¼¼í¹¹º ³.„ìl]~¾ëÅ\ïoß§K‘ú–Š¢¥ºUïoßme qñ‘D ùɦ³M‘rª««ï*5¢TJf ÙXßÐ2¦/KS—šJ‘/k#ÞÒâz˜ºîÞñ) š‹¯PÖª)1€I’UAg›"åäï)š,Îc±¨Y±X“Ãäû?øpäSEEò¼<EÂ,Ë{?üЕb®}òÂźÕŠ6båwqïë ŠÆ@ÜF|$ÈÅÅÅ¥ef.À°¯H½üÀ Û˜-•JI¿´¶¶65©'S)²š45it_–ºéUJ…YII.6€55©#ÊßWÄQb#>’$¥¤ì**ZåãSÈf¿ª`›ìë+/.N”Q~?Ð/^N]ÉbQ¹º„ÅâøÅ[ú².]\¹’Mí*âã]&æºxñÒLö<¶[ öÁv8ëÇŽÀˆ$ö®#..îhiégÏ<éí]ÂbY_ßgø+@$†™=ûhi)Íß\ºRMJ |Zž0áâ¥C©¨¸à_V‚þÆ ×ˆ¹®]øJ¬›CyD?çêùÑOQ‰Àˆ$בD"Ñá#Gr‹‹÷͘ìåõ ï8@=ÀÀºð.€z€ã«y¼ /¯"#wüö·ÿ}ô¨«:wUJž€ú?VÕ¨úˆR©ŠuB'Jl,¨T®s©TÊ ¡<(B-~tCyõÕW;¶lÙ2@Àf³Á²eËŽ;öêˆcSâ#mBÙï¼yóæ<9Цø‡1ÚËÆA›b×£¶é^Ôwˆx`Óº:Û†>ÒÖÖ=Í (Ó¦A[›kÄ\Ýí| ÚÇÀÿήv+ˆÀˆ´Å‹·ƒ‚‚^{íµ×^{Úi)Ä`г8Ô¯ãbs|úû‡ÆèõF'¬Ðé\#æê7öqaôcwGð¬Ï¨§|ZGp;«‹‡f6QŽ›´žžÃ>œÆuÂÑ>hµÀã¹FÌåÉõ2UKþô^\ŒòiÁõ>4ã7)°¿ï>Æ¥¸CÄ ¿ï' úH` àþýöþ[G¹]#æòLîioŸ Ó© ꡟµ³ººº#GŽ xŒ¦L™2þüuëÖz `$KÂuÝÔ‹¬tÝ·%bÉÐGÂÃÅ· ̺}Ûe0‰XÒ jʃZAmñ£ÊéÓ§7lØðÜsÏUUU™L¦ªªªçž{îÍ7ß<}ú´ÅH `WÐÖxIšeK¥úôs˜Jñ}ý£òe+‡­U•J—þù™Œâ£›òr^\Ü1×;2ª×Fv¼,^þ“sw*£)Xl5 %ËúTmmíÁƒ¿þúëÁí“E"ѦM›^zé¥ Ìœ93*ê‡åXÖ `@ K”ÀÖ$¦¤Ä77ïOM­þòËöþ³ßl†––þóçÛß|³º©irrüš5®7€uj¾0›©Ü9Ál6v¶ž[²d±EÐ_àÔîÐ`4¹søâÅK,ƒè2€ÕãU8Pd©LÿÀ¿±øÑ òç?ÿùÝwß¹£xxxø»ï¾{äÈ‘ÁGÆ¥,õùù›²²4š¾#Gt2DDÀÀáœ@3f€LGêZ[û23vï~kÃ×ÀBi¨ìyô}™8L<ºŒÒN”²2—ÀBkáÆX¯"A (Fþè©®®~å•WF}êå—_®ªªüçø3€ÑÒxI!™ÛÒÛ”ÛÌ85—SÌfC{cÎ;[6Œ|*==gÛ6^?E—m ÈÉñÞ°Á•b®wr6_å55ßL&0^óþäíméc èèèëWPPPGÇ¿ ãÉVVG÷ÞÆ IDAT’››~ú´6='¾àÇÃ22ð²2íöíéee®1€EÎ=l¶¯e,6Šœ2¦/KU\LQ#Ê!vHˆë `’¨°jö”U±ÿ7"Fl¥µF(޵p°µµÕßßðŸãÉFKã¥3xÿ7ÙÍy;íyÜqýѽ‚÷“5Ö€ììÝyy¼ëw¢\¿ÞYY®síØ[Á;Ùv ,h‚謁O¿»kÌö&˜?þÈkMœ>}zÞ¼yƒÿ70Z/„H$ú`¿¼åïÉ}½ä;Dúz•-O)ü φ/K~ 9³ó|oJ%¤¤`yyãBÌ%‰öØs ÛÛß“ê€ïOaûö,°ÞZóÆoìܹ³¡¡Áâñ†††;w¾ñƃŒXæÆ·Þj‘É6€‰€Ë5}ôQíŠ.0€Mòóý¢4H=yvoOô¸ãZó·ñÛ~þ ÏÛ òõ¦¦VJ¥FÛ ]»ññXzúø2€ù ù¿«”O3Îðƒ@ëƒGÒwJ°ïdg|h2™8N@@€X,&qo›”lMbVV…ýBÇÃÞ½3q™lÇ{ùõ ÷&‹å“‚“¬4$™ÍÆÎïKªr¢f†¾ÿ›L2¾¬üÜ{÷jär]R’Ùʠѥ¥“ƒ…†ÆdfŽ_1Wssóû¹»”5êEº×£ÍqV’p0ÕÀ×Ã>‰ˆ‘¼»ûÿ1Ñ–¯ÑôQØef2Ap°×ñã.6€íÝWÜØØ8)8ž7)'˜ås¸~&c—A¯ÑußÒ?*ïÔœ‹%[æ¨/«8¿±Qÿï}fýü « 4¸u ÊËygÏâIXZÚÄsUUUælT7F°çHts‚ Ì&aà£ícxÔ ûÌJÂ$›³Þf¨ìÓOZZ ÿügª `k°ÐÐñb»pQ¡R)»ºÚõºnŒ'ð› Kž_G½/Kqn`iLwwŸ@à HÄqqRÌ5tåÜ5•JÙÙÓÙÛ÷ØÛËW(ð—ˆ%?}qÓ `›ÖmØPDµìÄ øýïç<ˆ `×c¿Œ®ÆKÂUØo£«ñpöÀèj¼D \…ý0Œ«Ó(ßQdã¥K YÌuþÆy•RÕÓÞÓßÓïÉ÷äOæ‹ÃÅË‘ÌÕØo[±èüyê/ëê`ÅŠÀÏ?¿Jñ¼„¡S̵ç𞦦&öKl]‚F˜¹xå<ü ’… `.Â~ØÛëÞ|³šò-ÿއ?þqþ®1€Ñ&æÊÍÏ­×ÔkåZ `æÂ²±¨éQrd£û `ÒåŸî؈ÆKz SÌ•².åfòMmˆ™¹ôµú[‰·dÈF»l\ÜÛ6!8ØëÄ ºïm—••>\PVFf1üW_L†¥¥e&%¥Ø\RVRp¸@_¦«î¿L†e¦e¦*+)9\PPFJwô€ ÃÒ23“Rl()=PP”¤ßFBwÔ 5'±‚Í™›d)¶9ÊÊÊòòòúúúPÙl¶§§gNNNÒð»fÄGÚÄî5³¾¾¾W®œ›<¹€<('N@]]ÄêÕ¿¤lF(Š‚‚\…BÿôÓd^.Ab¢15µ2""Öúª…B‘[«WèTˆÀ˜h¬L­Œ%T›«ÐëÉæ@¢Ñ˜ZYk;hW®|­>?BIùAà ãüßUÊ£bgZª­­Ý¼y³^¯Ú}j6›Fã7-ZhïH"2€ÑÕxé<èseädèJuà˜™K_ªÏ@°!ŒK-—΃61×ö¼íº\PaæÒeë¶#Ø¿—0º/b®:MNQ¾¯E°1ž70Z/mb.y‘\—§êÌ\½òÞdíÙñdKË\°ûŠ”ìÚ5X°Û¸Ñ0ÚÄ\Mê& ÚÌ… `ŒcXRÊ®]E«Vù² „`ýý°o;9ÙW./NL¤ÛF›˜ë⥋ì•lŠ·,å À`ÀŽ–~öÙ3‘‘Þ%%,ë»Qð׿Bd$væÌì£G]c£MÌu¡â‚Î Aúýyds²Œ‚?1"‘èðá#UUUûöå§¥Ùn¼Ü±Ã¡~H¡­?D¥TsÌ\®3€Í†ÿ <(BÇÆzöÕW_ŽŽþðÃ+**?~ìëë+•J7lØ0r7â#mB©lÞ¿ `½ñ²¬ÌõmŠ´õ‡t·uƒsÌ\]ÈæðH브¶þ£ÞÎ1s‘ÌɸՅ61ã‚sÌ\\ds2nW‚û÷©Ÿv¤˜K('Á}ðisJÎh0°v¨C"0š×̺]UÐ&懋Á9f.±;ÀÊÊÊV¯^}åÊ•žžèéé¹råÊÏþó²²2Ò#mBqU´¶¶;vlݦu‹V,š-3[:{ÑŠEëÞ^wìØ±±nÖÐ mý!Ë¥ËyNâ•ó–4€9áTiT˜Š÷”)yß,Û&—Ëu:ÝPŽãz½^.—×ÖÖ’I* `‰kãSâ÷7ï¯N­nÿ²½ÿŸý`†þ–þöóíÕoVïoÚŸŸ8 `´‰¹ð/pŠü'ƒI€ŸÃ—¸l"­™µ@­Vÿ"õ›ò75d5ôiútGt ˆØôV0@º£º¾Ö¾†Ì†·v¿µÚÅ0šÄ\!¡!@µ™+Ì `lÍì ´5^Rmý!9é9¼m<Ê.ÛÀ;Ç{›;À&ØšÙJÊJÒsÓµ§µx:nÇÀ3pm™6}{úqÀhsE‰¢Ø±±cÜÌ6ñÖÌ*н‡÷ê¤z‘`!è¿Öïq‘Œ¶þÝÙ»yy< ÂÌå]à½ËÍ `lÍ,m—N‚N1×ù,ÇÌ\X vÐý `®Z3KÒ¶1scË[-f‡ ` ×TûQm¢+ `´‰¹„¾ÂÊÔJ£Ô¤Ì\X<–žý‚[À‚‚‚ Žãƒ'Ól6ÛËË+77wáÂ…$FLUTWW9sÄð±’•öæ9殼®§Ãž¦¹#¢£c""bׯ¿ÌåšæÌ1[ß jþ~(,dgdøäåÙ,‰b¢cb#b/¯¿lâšÌsÌDnýÀ.dûdøåÙ,‰¢cb"bc×_¾Ì5™æ˜Í„s ÍÎðñÉ+*²Yÿ ŠŽŠyèò{`bO5‡[ß j+ÙŸ]òùxQÍ’ 22ò§?ýiGGG[[›Á`àóù‹-ÊÏÏ_0¢éžøH›1€%®IlÈj û…ŽÃ̽3OºÎF›˜+7?·æ^N®3'™­]Ÿ0”–ƒÅ„ÆìF0Ú!³KZ|r|Ÿ¦Êå¶&ð ö:ëjmb®üâ|u£š?dŸÙ!f.^9?‹‡I²ÌEØ]Ÿ|úIaK¡Žj¶Û:n `´‰¹Î)Î ìIÞ×Ýç%ðÄñ‹Èæj쮊u›ÖUo¨ª `pæý~ÞÇȆØ}e–¶ÆKÂUØ]´5^"®Â­ñpv_Hâb\ƒÎTÀF6^º„¾¾¾ÖÖVFÓÛÛk0pg³Ù>>>AAAAAA^^^(ȵA4`÷Ùö¢‹ÚÏ·Õ0¨ƒÀW]gkoo¯¯¯×jµ,Ëd¥…€Ãá˜ÍfŸÈÈHDmØýçY.n¿í„ªÑxIZ­öÎ;===£þFx¶§§çÿþïÿüüüžzê){Wb¢ ÒA4c÷wűcÇö7ïסø~o5okøÖ×RèÞ2§½½ýÛo¿ºx†,‹ÃáÌš5+ 9;¨§§çîÝ»ƒÁÃÃC(†‡‡óù|GFÚx“ãâÞ¶¼‚½ÎÒn»wï^}}½õ¿sVàp8‘‘‘D–o¡ ÒA---uuuA£¾œøH›Ø} жÆKg3p4Lú÷ &“©®®îáÇ(ÈIAÝÝÝ#?èƒ/ïîî&1’dú+hk¼tZ­öÛo¿uä÷:€Édºyó¦•HD:îÞ½‹¡ªÁq\9¤9†øH"4€ÑÓxé<îܹ3ÖÑ^L&Ó;wPåAÐÙÙie‚ÎÎN#‰@ò“M[ã¥3èìììéé±ëÑ:ÝÝÝíí£lª‡‚H `ýÉ8dÿ"â#‰@ÞFOã¥3¨­­uü`(&“iÔQé 8VÁ¸CZaˆ$‚C°Ì´Ll¤ `p °X6í0½^¯Õj)ŸV«ÕZìÒ…‚H âïïÏb±F}ŠÅb …B#‰àйAJRJÑ®"ŸU>ìB66€A?°÷±}“}‹åÅ2Ú `<ëÇç,Ëb¿PD:hððp+;w„‡‡“I `¥GKŸùìïHoV ËÆöYF€¿‰Í>3»ÔE0FCí1À&“ÉâW‹‚H Âçó£¢¢8ÎÐj¸5ôöñ‘D Ævä𑪪ªü}ùê4—.5€Ù»q,Ž.Pé ¡LŸ>] ¨Tª‡šL&‡ ‹G~Љ´ •°“ÿ2€û×ãÀf .{ulfD:È>Ÿ?kÖ,"ói·3€Qu­}$×+Qé —ãvV—±ÎÉÇâL‘r9®oô¡±®:>3 ¢$Èú×̺]Uøøø8éWëãヂ( ŠÅJXƒÁðàÁƒööv›kf­Œ´ ÅUÑÚÚzùòå —n4ª”Ý]íz}†ñ~“Å’ðeK¥K—.uá>huuuQ~…‘ÃᣠJ‚±¾V {GJX’lÍÊ„”?}ÚÜÖŸ:%úËÈ%ÿüñJsä’–ÀèóúÞüèÓ¦+“eÉk\k›2eŠ3ÎíÌf³Åå5D:hW­™¥à»B­Vïx/ÿ®Jã*\’Èb [‘Âá 8\æ3C8U65ÊôHs2cKöŒˆé;ßÏ‘Ø Üa0 óññÐlRˆE·> "4È[3;ˆB¡øÙ¬{ OKk„Se%a‹ÅNM_Pû@—˜òÚZWÀ"##­/&³—†/DaÐlÍìÇO”mÞ’;-öt`H:‹Eôk‡Åò ͘öTYÆ–í'NØíBv»Ž2m"Fݺ‘`â­™U(û÷«ð’Q€ùú/ ›ûõÞ}Å.ùÆxê©§¨ú›ÇårccÇÜc‘‚ ·fV­Voy'gzl©—7y˜—·ä‰§K·¼“C¿ÌÛÛûG?ú‘ã¿]‡ó£ýˆ7¶‘×­™%iÛôv&îû–pª£ëÀ=y"ÜÌýFñÑ«¯¬pp*{ñöööôôìèè }]e`=¦ÍkÍ(ˆt——————E³ÞàJØ¡{çIèí‘3€}zìÌO}lýÜš Þ~sþq3/&:Œ~ØÀeìØûÛe±X\.wöìÙo¿  G‚ ƒ^¯7›Í\.wÊ”)±±±#?èÄGÚ~“$ `I²5ýÞYŽQ Òyÿ8Ö·÷Äñ#TMh½½½wîÜéîî&xŠÃáà¡ ÒA4Cf—´+“£~ª!~ÑÉ&f³©îjðÿ~~Ü…w¾;::êêêˆl–eïÙ ¢$ˆ6ì7€}òéŸKZ¦Fý™Ú÷q¿f;êr˜^¯okkÓh4?6™LÍ+\.×ÇÇ'88800Ã0äÚ °»*~ùŸ›Úú7§R¬ëüþD×ïÿø‡ƒÔN‹@Àî+³*%O@½ŒÇU5ª(Ÿ ÝUÑõ¨ÍÓ‹z˜6­«³òiØ]ƒžÅ¡^Ææøô÷S¼û?A»¯#yx`f“ŽÅ¥X†›´žžÎðíÙó|YÌ ¢»Ï¶ºtE`ôẏbÙ‘þqÝÃú—/~Ní´Äaž/‹yA´a¿Lþ û6åU¡ë¾-K¨“ Ìóe1/ˆfÈÀþôióÔhŠïC_³ú?W‡¿öZ µÓÚ„y¾,æM ˜îmk¯ñù dCALXhhè# • °Gß—‰ÃÄȆ‚,˜H°ÌmémÊmfœ˜ÙlhoÌygËJf#ó|YÌ ‚ g‹œ!zØ\Lâµ#yØt(rf2€¡ ‘L°Ý ÞÿMvgsÞãG`;®?ºWðþo²œÇ.˜çËb^Ðl7‘HôÁ~yËß“ûzÉ+Àúz•-O)ü ÀPШL¼Ý âââ¶¾“ÖX½àqØãŽkÕ ¶ýz#2€¡ FÀ’““|°ëþUmêB³™¨ÜÀŒ÷·5îûþ»äCä2Y¢#o€Ìóe1/h l;^r4Øç3¥"²óû³ÙÚœÙlì¸ÿ×("ƒ}Ï/9Š `(hÔ A&¶ìã?®ªªÚ»o_í•´IÁñ¼I <Á,,˜Ãõ3» z®û–þQy§æ¬X,):°ÀP• ¡Lx؉ãó `.þAU§ìêj×ëº1žÀoR€D,y>!nÉ’2dCA6ƒ,@0§Ã<_ó‚\2€QãÅ\ÈÆX˜çËb^Èæt˜çËb^ÐP˜c»qõ¼R¥jÔÓÓÛÏ÷öœ<‰.K/G0D$h&ÀÖ¼–˜òJ|ó¹ý©Óª¿LjÿçÛýæ÷ åíþóIíoN­n:»?ù•ø5?KD0d=h‰mËß™«Q×ËiWgx¡ ¼@à3&ƒ,ZgÂádmCvÖ[ÓÅQÙ;äȆ‚F d‚­™D¡P¬{=%ÙÿfÍz­,Ú²$,à°!9jßÔ' o­ý¹ ÀP `e'Jr·¦ŸNÒ¦Ïù„gòà@Æ|¼,Q»}kzYéqGÞ9˜çËb^ÐoͬB¡8|p¯b­>îI2/_(‚¯×è‹ ÷  ‹ ¶fV­VçlÍ(MÔ…9°ïºÄJWés¶f  • fËܲñ­™-²hG¯Hˆü€ ¦¾¬]ñ2ÝKÊ™çËb^Ð3€)=òq‚Áú¹5AæL5ç]è ‹|ÀPШAöæµÄ¬èY´½¯“ãßÁÞú™GޤlF{`ž/‹yA4Cf—´äWâ5›ûˆ_t²‰ ‡à^ÇOŸE04°»*>ýä“–/ ÿ¼’â]õ×”c¡+¶" Ø]›Þ\·aZuu‡Oœø~¯™wð·S…);ÈM ì€”SXÞ¾ƒÈ†‚Feâíf—¶9sÁQì+RM×ך`ÁQlã;ÙȆ‚eK’¥ìÚ[´ê¤OaÛ@ø/H¿ öÝ`'Ÿö•ï/N\%sä €y¾,æ 2 `G•~ÖõLäï¼Kî°ŒVOÃŒ8üõDþ;Ó3ûè±RdCA£ 2± `‡ÿx¤ªªj_a~Úyu|;A¢›Á¾à‡A—4áV+”+ygp‰$lÇÞ,dCAV‚†2á `óŽ0€ýáÊ9¥BÕÞÙÓÝÛ'ðö  $q\‹eK–  ²d2€9æù²˜ärŒ2/æB0ÆÂ<_ó‚,@0§Ã<_ó‚†ÂØÕó×U*壞ÎÞ~­·§Ï$¾P"–,^þdCAD‚q•Œ²ª¨¨¨(Üs¨©©i&{®X÷ìlø¹/½€××ßû¸½³µ]}öNÅÁ½E¡!¡›³Þ¦y-àP¦L™be‰iFõe¡ rAƒØ\ ;{öl{GØÎÜÝêú{‹´¯¯‚gÙÃÏà½ÀÛ ¼'ÃôhÝðÚEÖ[¹â¨ò\dCA£ 2ÁÖÌ¢P(^Où…ÿÍØõÚ¢hXÀ¶:!Ø1°ðMý oÅü\¶ÀP `'JJ·¦g'i³æá+Ù@ô‡Åî|üåDí¶­éY¥ÇKyä`ž/‹yAL¼5³ …âàÞ¢µúü'!ŠÄËE½FŸW¸ç2€¡ ±˜`kfÕjõÖŒÌDÝ6!¿¦äSWé·mÍÈD04*̶eã¯g¶,6/ ñÚ¡øA ˜Ø_Öžz91ÁÁ©ì…y¾,æM0Xé‘Ó †MÖÏ­ 2Õ~¡ëXäÓȆ‚F š°×Ý Ž~Q ò|U?óü±“ŸP5¡]0ϗż š!³KÚ+ñ‰›ûŽ¿èdð^kOŸ=‰ `(h<`wU|òɧ_V­Ôm¢ö}”cVlC04°»*Þ\÷Ö´ê¸hˆ£ö}|_iæUþöãbj§E H`÷é²J¥ ‚ÊßG„ªU”O‹@ÀîªèènçÕûôðÁ¿³kÌݲ:±»*ú}\ ÚtàXŸQOù´ ì^3ëÉõ2ú=â3'轸®?cž/‹yA4`wUø &÷´·O†éÔ¾èúQ`Fœ±4V8Ž÷õõõõõuuuÕ××;Ï—…‚ÆvW…D,imWS^­ –ˆ%ÔÎIæù²˜D3v¯øèÑuWWWÏ0RÜLWÁ;ùšŸ<õT µÓÚ¤½½½ººZ¯×ßÖÅl6÷õõýóŸÿÄ»(ˆtPOOOMMMmmmCCCssó£G|}}G=#>Ò:ãäÞ¶©ÐkíggO! ²`âÀBBkᆽ/´B (ÄabdCAL$Ø;9›¯òŽšÀ¾®¿±0ñš÷'ooK§d6‚0ϗż ˜p0ITX5û ¯Iû#bÄȆ‚F2Áv3ر;·‚w² ì^…nA|Wå}úÝ]ÛœÇ.˜çËb^Ðl7‘H´÷ÀžSØÞøžÜ ÐߟÂöí;X€ `(hT&Þnqqq›37Ų›¡†ÄË›àÎQ,ûì·‘ 1Ê&K‘í-Ê?é³§‚ýñ“oo°OöÝ·¿¸`•l•#o€Ìóe1/h l;VúI×3µ¿óÞx‡uk_¯8˜îÀµßbi=³ÿq¬ôdCA£ 2± `<òûªªªÂüƒçÕ¿‹`Ï‘èæA˜/LÂÀGÚÇ𨕼oðjI˜do–ÀP• ¡Lxر“Ÿ À®œ»¦P}ÚÙÓÙÛ÷ØÛËW(ð—ˆ% /.Z²d;2€¡ ›A ˜Óaž/‹yA.À(ƒñb.dc,Ìóe1/Èds:Ìóe1/h(.1€¹ÝTPPµ†Fõe¡ rAƒL¤5³š)S¦8ãÜnT_ "4ÈDZ3;¡ÐXQ>íX¾,D"h ¶fvBÃ<_ó‚˜`kf'4Ìóe1/h€‰·fvBÃ<_ó‚`‚®™¸0ϗż ˜p0À<_ó‚\e#ã:b>¼yó¦½ ¤~Ü?úÑ&O&ºß! "ÔÓÓCp%,ñ‘6Þ¤›W0їż šAUñÌóe1/ˆ6PU ƒy¾,æѪ Â7½2‹@XUa ª ·ë:²ó|YÌ ¢t¶ýci¬¼¼è$_ ? ª ª±„Íf;Õ—…‚\Ž»WE{{û·ß~‹ã¸]Kz–-Ìš5‹øD:ˆþÝ Üwu Ü»wïÎ;äv‰ÄqüÁƒžžžDú Pé –––[·n=~üx Çq­V{ÿþý‘/'>Ò&î{ Šy¾,æ¡Ý h…y¾,æÚÍ€f˜çËb^ Ý è„y¾,æ €v3 æù²˜4ÚÍ€&˜çËb^Ð h7š`ž/‹yAƒLTØ„ƒy¾,æ 2 ` æù²˜4”‰m›(0ϗż è7€¹Ýó|YÌ r9nWÌóe1/Èå¸Ýó|YÌ ²Àœó|YÌ  2€Ñó|YÌ ­™¥ æù²˜4Z3KÌóe1/h´f–>˜çËb^ÐhÍ,}0ϗż КYZaž/‹yA€ÖÌÒ ó|YÌ d£æù²˜„ `®y¾,æ!˜ `ž/‹yA4ƒªâ˜çËb^m ªó|YÌ ¢T„%nze°ª ÂTæì\– kIDAT„%¨*KÜ®/&&ÆÕoa—_Bß„%èÊ,a ú®@ ,q»ó ë´¶¶^¾|ùÆóJ¥ª½½§§§ŸÏ÷œ<™.–J—/]ºÔæ2O»‚Îß8¯RªzÚ{ú{ú=ùžüÉ|q¸x¹‚nœ?¯T©Ú{zzúûùžž“ùüp±Xºœú «ç¯«TÊG=½ýZoOŸI|¡D,Y¼ü'Ñ:‚úŠŠŠÃ‡÷455½ô;!A7kŸÝÝ ÑÀíÛP^Î;s IKËš?¾#A{ïijjb¿ÄÖ%è`@0 @pxå<ü ’åpÐá={ššš^b³tº9PÎãÁñд,Gƒ ÷jjjšÉž+Öý8Â|Aè¼>è} ­ Vò¾iÀ«CCB7g½íHm ªµZŸŸ«ÑÔËåÚÄD°ÒNc2ÁÉ“MŸ•-‰DöåæçÖkêµr-$XéÛ1œ,‹š%'”Ÿ›«©¯—kµr æGEeËÉíÌÝ­®¿·Hûz$<Ëû€¼Ãþ"Ž Ù!ϵ7ˆfÜý¼B¡P¬[—’œ|³¦F+“Y+ àp 9jkõ‰‰·Ö®•) »‚RÖ¥ÜL¾©­Ñ‚ÌêG8É ¯ÕßJ¼%³?h]JJòÍ›5Z-±¨ÕëoÝZ+³;èõ”_øßŒ]¯-ІVJØÀŽ…oêÿ[x+æç²ÕvÑûöâ@YYIAÁöS§t2™™øªH¥ægŸ5¤¦^ðõFGÛ¾RRV²½`»î”Î,3Ûñ‡ˆf©Ùð¬áBꡯ0†@PYIIÁöí§t:™ÙlOHÍæg †Ô |…Âh·tN””îÜ.OÒeF›°ÿ—ØÀ~Âi=(· W¯Ð© 1ÑX™ZK ¨ 7W¡×“ÍD£1µ²2"ÖvЮ\ùZ}~„’òƒÀÆù¿«”GÅδä*Üô¼B­V¯[—rê”vÁ‡æùê+XµÊçèÑÒ±”Õjuʺí)-8_Ï*ŸR«AëRRNiµçÀ*Ÿ£¥Ö‚^OùÅ*m–¢ j†š“>{Ž•~2Ï1Üô»"3sã[oµÈdŽî)—kúè£Ú+G°1scË[-f‡ƒ@&®©ö£ÚÄ1‚27n|«¥EæðŽ—"®ÉôQmíŠÄу¶lüõÌ–¥Ñf«ü Lì/kO½œ˜ààT”ãŽgÛÕÕÕM]j*5Ž’ñ––ÚŠŠŠQƒê4u8EAøF¼vì M]]*EÖ•8ÞR;fºîÞñ) š‹¯PÖªG r-îXEEò¼ÒÝÖ N‚iÐ5<¨­»Û99ÐÖ5,¨£»D·Á$ü;»Úm£·« ½Þhul’øø€N7LbÔÁ AàÆáAz£Ñ99 .Cé7öqÁ“ò ÀúŒzʧu·« ã:á ´Zàñ†ñr1.8!´À„q¹ÎÉÞð‹ž\/#ôSd½w|m+èvU(¸Ÿúiï߇À@¿¡à„ ¸~Ãçä@ ß° Áä þP§:„~Ô˜9‚ÛUEx¸øömê§½}$ñÐGÄábpBÜñð p±Ø99  ’ˆ%­ ¦<¨Ô±„òiÁíªB*]þùçÔ‡——óââ–}d¹t9Ï A¼rÞòáAÒåË?w©R9·|XÐâå?Qñþò %ï›%ËQ>­#¸]U,]ºô‹/p;š60áÜ9|ñâ%Aø8PFÀÏáKF}ãTçÀ9_¼Ä2¨¯ÂÁ>‹up0ýÿfÉ’ÅÎé8nWAAA¡¡!§NQ9gYˆÅaÝúAAA!¡!@i”AØhA¡!!Tç€8lÔ ÐZ¸AaP (Äaâñ¶ÑÛU¤§çlÛÆë§èjŠÁ99Þ6lùTNzo²Ë6ðÎñÞ6ZPzNÎ6ºÈñöÞ°m” wr6_å5Qô hã5ïOÞÞ–NÉlâŽU1wî\‘(ª¸˜šÿû¡Cì˜Q·®˜;wn”(ŠMQû;fì QTT1ñ.[«b³CbÆ ’D…U³¿ $¨Šý¿1âq¸ë‡›öâ577¯Y#++Óþä'Ísý:Èd¾ÿó?eO<ñÄXA²52m™ ‚ëà+ó-³´F&+ÓjΙ¯ïÿ”Y úÙë‰Úm!àÐŽ½MðÝiß½-ût¬ âŽß ‰äòÉɘRI~¥RR°¼¼ƒV~¯"‘è€ü–ŒA ,;h+H~à@2†9–)–wÐFÐÞ{Na{;à{ÒAðý)lß¾ƒã°$Àm;TàÉ'Ÿôõ¦¦VJ¥FÃ×®A|<–žžýüó/Ø ú +S+R#hQ¾X<–žý _¡0µ²Rj4’Êx KÏÎ~þÛA~Bþï*åÓŒ3ü ÐÞ &¸S‚í|';ãùž·ÿmÒûVDGÇDDÄ®_™Ë5Í™c¶¾Ô ýýPXÈÎÈðÉË+²YÄDÇÄFÄ^^ÙÄ5™ç˜‰v(ô»í“áS”Wd³$ˆŽ‰‰ˆ]ù2×dšc6ÎB6;ÃÇ'¯¨ÈfIü+(:*væ¡Ëï‰=Õn}3¨AL`¬dvÉçãýEã¶$Àm ‰‹‹;z´ô³Ïž‰Œô.)aY¿a4Â_ÿ ‘‘Ø™3³-•JíèJ‹‹‹+=ZúÌgÏxGz³JX6®âþ X$6ûÌìRûƒŽ––~öÌ3‘ÞÞ%,ˆÄ°3³g-µ;èXé']ÏÔþÎ{ãÖuë÷1p0Ýk¿ÅÒzfÿãXé'vÑ›žm¤ªªª¸8¿±Qÿï}fýü « 4¸u ÊËygÏâIXZZÖܹs Ê/ÎW7ªÙñCö™õèÐÜ^9?‹‡I²*ÎÏoT«ã‡ì3;$Êy¼³8. KËr4¨0ÿ`£º1‚=G¢›a¾0 =hãVhØgV&Ùœõ¶#A´ªb­­­W¯^U(Î ìIÞÝÝ'x$q\Ü‹K–,™2e …Aççö$ïëîóx b‰øE')ÎØ“¼»¯Oàå HÄ⸩ºrîšJ¥ììéìí{ìíå+øKÄ’Ÿ¾¸ˆÂ @U@XâîçÄHPU – ª@ ,AU@X‚ª°Ua ª ÂT„%¨*KPU – ª@ ,AU@X‚ª°Ua ª ÂT„%ÿ§’Pî¸çIEND®B`‚puzzles-20170606.272beef/icons/guess-48d8.png0000644000175000017500000000435713115373731017335 0ustar simonsimon‰PNG  IHDR00`Ü µgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<UPLTEÕÕÕרÖÛÛÛÛââÚÛÖÙÖÖÕââ¼Âõª¨ÃÄÄÔÝÝ»»¼ÄÍÍÔÚãÍÍܶ·­ÃÄÍ···´³³ÌÙÙ«iiÒ ÜÉ «zz«WWä뇇­­GØØÉÈ­®‘ÙÙ㾾Ű¯>ãã¹¹$·µ¦ÔÓÛ«««óþÜì쬓“þþÿÿÿÌÌËË06¼JJ÷û±±Uóó®­pÉ((£££ëê±³SÊÆÅ²43·ÉθXW»Çɶ¸w³©†………ÝâÛ³˜—Ó³££»þ³³e³´7ÇÈÓª¦ªÎ4/ÔÓË­œÂÃIÅÊ;âåÛ—£¶²Á»±äÙäÊÚ㥘¨äæä[g±,=Ø$<ìmu¬<®;ÞôÔm±n×Éå¸('ì¼!XXX#>ü9Rÿ3Lþ9òš‡¥R°Wþè444aaa½3FÌEUÌ?ÂB¸©´ÚØÍ5È:²•§Â¸¼KW³)DÿÓÍË)¸)”}›šš|{{5F¿»qi­EE«¬µjs³[mÊ{„²\»bCÄN¿TNËÓÕÀRL³††ÑÍÓ¾²™¶™{²‹‹±t7ælôs¯{H·o'ípûv¯V•””;;;ÿƒ²‰hý}ÈÓÙÔn Ìy&Â< i³xx˜š·s„Âs¦AO·)Cü½½i“t¤w¬‹g™!!!7Pÿh Ž…¼‚´ˆ¼jš|±„Y–EEE²Ž”kŒ¹fc È qqq ÍË%nnn@²>ª¸°™eãbKGD.TÓ‡tIMEá`"Ž—IDATHÇUù_GßdI²›s‚@ƒ+º6FIA¢ R15O´JÅ+Š)ö0AQ–¶ÊáñjÕÖ¿«3“˜,Ô_Úù$Ÿo6ó¾óÞ¼ï{o â-ò¿ïH"ÀÛb>=‹?gNeI¤2š"(š‘ÊÐLɨԡ†UÃ# ›Dß4A›“›§£)y~޾`MÉ †¢b#(Yn(-+7‘ŒY­63 mŸ•m±Z­zÝŠ|Ö\›¢°.ƒJY†°ˆ!T+Íæ•,—ö /@†ÖU’<Œ•CU´\]^Šöj…ŠÓ°›¹°$~Áç&‰ÅkaÅ—ÅvŒ«ž x.¥]›<¹&éÉY[„O®ÓcÍ:#_ϲõ|æÎ®†Fh—×´br±ž1V£XÊÜŠ Е}c³Ø\Ïhê==hsåWN–n¡[+W9a6LÅ›Ú6¸”r][[5Ê«Œ$Õ‹ô2›%^œqK{M¼•Ïc«™ úýÍ"øÜ àG =·uÛöm]œKöõŽîÀìÒst4Éî l@Ìïa˜=|†áíÚêíÝûÀu°Ýˆ“ÐØ¤ÝÑÜyèðž#‡¥ ¦¾£½h+߉¾9®Of«)‰Ù+t'xþDWÿ§Z)ÂQþ &|{2iXi³`ÌϪшÅýýé[÷Ÿê õ†No=sÍXq˹>”mkÐ&Šœ7›ážŒÔæm§Oï½ éh‡1uŸu‹–µrï te¹¨G¿c†ŽS™4‰™KßÿÐÀþøSÀ Z꼬‹QÝà¼r"'ÈJ@¾kà Š&éÈì  mµI²àÿ±V[-DLHÂ$¿~côÆMy'sëöØ;1»>hÉͦAkAÐÒ¨£Áø„™ã·dtðÝ›œœ½ë»>ñöˆo{¸¥Hö|% {µ÷'§ éƒ(Døë¡'¥Ck0¥ÃÐ!Ç÷¥³JJ°áä3ÂÉ©‡þ$árJg§!âQ.sgíMd?vÇwk ‡vo=ÎÿÕZ¬‡¾êà9ˆ˜2IbŒŽÞr‹¤÷ǦF¯«E6¨XðbL´ ¢>Ÿ¦Øq™{œ”7(þyXNÃf¾Û# šùe°A õ`›´(‘¤ÉdHnú×Í-$A©‹ëÊ•ðõˆNjD…c]hœªCÐ`ËïÛm?åèP=¶W¬)T‹šò,0-ðÏÌÎÍÌ»@ýžRŸaôoÝzÚ×ElLŽ•{¸ô#ògω ~¨Ãa?Àò~ «ûé±r+mþdþ/OÏ&/s¯¼ük†tp¤úª !¥ƒÚ'^¾r•0Ž8ËQ‹B …¥CRâÒп‘¿…!=_ðìÊ(^¨C_òÒ.ö±½ª´°ÙØT`±æ¢K?C—Ë2²#LSËô¥h¿˜Í×êL°¼åotª,ˆŽp˜qÁŠã฾LêºM×ÔpIûÛãÐ þñ Øùy? *шôËhŠìö2¦ƒÿ·h* ËŘøÜÌÜÜB×êÝûÈøûwÊÉi­ÄC ;Ç}`¹ª~–€:̆½X‡ W¦’ð´®øàYººÿäÔl)téÖL‰¶:©K;eéh!$[þ£~ßɲ íÄIß{÷Þçý "Rx˜VyêŃ‘"oÔ'îXElSˆ,ònõ9Šê¹µ3šX¨sz_ G¢^§c-Û‰My®æFø 1êwìÌzNhuU$CÜb· ˆ”ÀA Q៨ʓ›*>«ƒÞÕP§Øz)^†6«aâ5iýyzN¤«_0]¤ÄîH·,Ïiï{¥ž!d’(¼øókeyѪªjøSL"ý€íXê1D¸óMŸ²Õ€]¤„'¨õ RÂùG¢Àq°$=E¾D¹ÚÑAÜ” ¨N$íEfþ4ü-¥½,/]Ÿ yXEîíHï¡x",`›ŠeSA\%c±à¼(2BªÐ*˯4™Yå²;-BÅóºw»2H\`´ü"G¸ôŸµiQê¤/¨õ §#€?dÝ;Ó^U‘']’ç…jPIfÒõ•« 82?^"/’ +ÂÕB FÒz«Â0/r»$bˆSéö+©9yn¶—Ú+Á9GCÑ®â›ýG‰j‚ÑÛ¯ q ç‡y3t5ÒšKmÞÌrDÕ ÔúÒAþ¢²I—p^B%tEXtdate:create2017-06-06T01:31:21+01:00&µ¼n%tEXtdate:modify2017-06-06T01:31:21+01:00WèÒIEND®B`‚puzzles-20170606.272beef/icons/guess-48d24.png0000644000175000017500000001136413115373731017407 0ustar simonsimon‰PNG  IHDR00Ø`nÐgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEá`"ŽøIDATXÃÍYip\Õ•>wyïõë]Ý’zÑÒZ,/’m [^Æ61ƒYb›%ƒc'€Y &‚Ê$E˜Éd&Ì“*R¦R3Ca&±3`ÈB²¼È²ŒdI¶eÉÚÕÚ[½¾î÷Þ½w~4¶ec¨ÉTÍÔœ_¯¾÷ºÞ÷î9÷;ß=:;;áÿSÐë¢BBýwq_Å9 „ÿç„bLQ$I\× ]B²¯ÄBÈŠ‚(噌nèNˆ Ô‚a,m&BYœ‚(UÂŒi†Á³´„×¼ñšo¸Š‚bÌ\®ÁA}lÌRX!‘0… ɨêðÅ‹æÌŒµ¤ÄŸ—Çãq ÈR2)OL\`,îpÌóù\†dÙ‹¡©©nÎ3n÷üÜ\›a$°$I—ie©˜¦y¿Ë5$(@’Ò‹¯¿>ÿwr4mÒáè}üñùO¾nÅé§¾W&ËîH8òƒéGÔ4!"#èÉÖ§ž[ðsˆ‘ôóÏÞÔÞ¡\TåÖ—^©Ü±ÃÂyw{'Ù»gýÅ pÞåøâµ¿Yt÷ݲi;vìƒ>xòÉ'àÍ7ßܺuëêÕ«5MÃ_«CB «ÊÞümß¡–;=y>Ù¢JÖüÖ³A"Z×W…öôÿððwꈇ€ Â'rN„Εû—ïÞy×é6! BAÔ?ÿüâò娠Àܾ}c߀•¡¢tF¯«\»6X\¼÷ùç?««#„œ9sæÝwߺï¾ûc—‰ÎÑ!y||ôDGa®We&€b9žœ–3E­5'6θÀ‚0A8w¨¦qAUK+Â8ÇBpJ+L³ï“O†Öô÷¥Â4HR¥®_üãÍ5k6oÚ419¹~ýz¨««»óÎ;BBˆk Æ(1 fÁ ”}Ì0ÔˆÕÕ ,@b–d&±€Xt©C‘xÜœµÌÙÂs @c1M×ï¿ÿþ›Ö­+..€·Þz+èº~9_Wéa˜þ|WÐ;šÊ€$!Œ„,á”ßÐòPuq_$!N(¦ CíØ’¼•Ëû½nà\PÊ Á„ÄÒ55žeËÓä”rBÆæªUÎ77766vvvvvv666677gWè::Ä9“÷®ûÑOÏ@JCÓÜEë·ßCíy£? mÄÀ†ÀB7ôy‡çí²íÌ)õŒ<ÿƒnÌBÓõúÚZÏ–-Å¡ÐÙgžº„G £éöÛ‹6o扄7/Ï='¼^ï7é ZHÿÅþCGH8â*Îܹ‚Å©Œn'¶Žþ¶÷èÁ°:uCtáwí[~¯®kÈj8~œ~ôÇ“ÕÕ¹[¶x¬Vf¦Å2xø°òÙg$“I®Zå¿ûnÆŒs!„®ëŠ¢`Œ3™Œ,Ë×8¤«üaš(¯xÁµuæT·ä_âÜl˜),@§FQÑ’ï·¦xdT.­¶˜ž€νµµÃºÎff\µµ9‹Ç¹*B9ßúV˜s¡ižÕ«]6› „¬V«ÛíÖ4Í0 ›ÍÆcŒ}B’èøL|æý§WèÍ.O§ùIçÆà¶ðçØ.ö¥<±Ÿ·Jx,ÉOç?XöWsòù3Ò“OÖŽŽ*rÞöÔS ÷îµbÜuäHÎsÏÕÌ΄z:ÿ£UîÚ¥2öÑÇïÛ·oïÞ½eeegΜ …B@àú~ƒ0ˆmä?~rûÔ•G%¹sp(ÖÓ>Á•E›"ÿþø]–/ln*ÉÈëF¾ñ3)/-¯Í|oÇÆ¾~…RŠP.€£¹ùBe%å‡^;=-S*aìgŒ44ô®^]0oÞË/½ÔÜÜŒ1.--=}ú´" qί«CÒøÄXqô0Í–a –Æ6Ì6\h?µÜl0$#¹9à™®ï;¶ô¦sçaš€SZÌyw}}X’n™˜JÁ4@PZašç26nܱ};•¤-[¶TUU}m !„831˜YÊò†©§)f ¸Œc0X:M³é³é:O§É•º€®§u}ݺu /.,,ÔuÝétZ­V¸Úç_Ñ!ÓÐÝùaË2È–$(‘%¦Á¨å†’ÅË{Ø|`€¨$% I&aÆV[¸º¶ÛïÎ…$ J1ÆSÚÊ•¹+Wö¨*˜¦ TPŠ„àkתŒ8y²¾¾¾«««···¹¹¹­­íkuˆ pJB^ÿrÝŒ?=£ƒ&’“úŸ’ólëö8°vóŽ9XÌ@3>ƒZϸ­S?þI+¥`ˆó)Ãh¸í6ß=÷ú|}/¿ÒŒç#Œxè¡’ÍD¢°¸8 æçççååùýþ`0øM:$§²:>5›9û%Ñ£¹Û*ïÍs©†ž–,Öpx4Ñö ŽOð`U~Í—JŒNl¶Ñ‹µ?ý G£bÙ²ÀºuV!˜i‚Õ>ÒÕê>ÄM_½Þ¿zÅÌp!Îy¶Wd/¾I‡ ¦Çf·Ä7U¸uÖ E.dâ`^x$. Á !9 ¯×ÄXöx(¥"“á€TÈH.g‡g£‘æ9.;Íè:ˆ[K– di¥Óé¹æÚ¡ÈòèèðË?O~rtEï@iCsÎé/ºVÖ˜99þ :X{ãUÇÝÎýmí½Íïìjh´?øàÍ~¸ðèQë{ï}Û7Üê²Ò†?´z¸'ó™šl‚Ž}Ãc™Ák‹-ÔºïÝ}{÷î­¨¨Þµk¥tÙ²eº®_G‡°Dµ×ßœ<Þœ—g‘%âpZûÇKµx[õ"÷lô¹Ûnë¡’„0Øí¤  ·óŒ«ËèîGnž˜"’„raìíèè.-3ý¾C;» µ¥2¥’<à<9+WÇË+C¯þäÕ®³].—«¯¯¯¾¾>‘HlÛ¶íkü,‡ÇÂ†ŠœÐu@¸Îœù\IooKåâÂÀÃN'x‚Ç›–¯ëBÀ0'Äà8z¸ÃZn‹å ª3“ ¦Ü<¿¯.¼ööì3{öýÛ;Û·oBD"‘mÛ¶eß~?B @pÕÉÿri!ñÕâʬCÀ•Û¡Ë{w.Ž1Îèz(z饗²Îú±ÇËÏÏ7 ãú~H7̀߳°x0²L’L¢±LUÙÀ¼òÚóç—B’”ÂLø¦â5+Ï–…€1”Õ!€0@b͆¥« ’® dÊ”L‘Ì­³0^q{~2’Ž'b6l˜œœlooojj:}úô5:4·†&–e™¶ö®‘ ¯ÉH<:³¤¤þé¹N·72SÕ×_Ÿë‹Aãã¬áóÛ ‚?ÌÏUF*L|úi~*…†8?öÐC¡G˳)¼(ÞùÙEnȆ0'Äà¼=èæjÁÀ±x´»»Ûjµú|>Ó4KKK].×Ü^ví1H–©¡Ç>oJ Œù¥lÍ·œì†aHŠev:­M4`æòRwá2‹¢3IVu2jh‘ˆeùò¢%Kˆ¦™\X¬òøÄع†A3ÍJWJ+BFÊD„MÓ²ƒÂ9Ÿ{ކ¯ ¬çtb’Ï+ýp颞djñøÄVŸ¤Ë§µÉý´„LÔšÎ{µØbaÈäiccòÀŽFÍÜÜtE…cÄ9'M–æ‘`¼ $C°Ä—e²S"MÓTU5 ãúE!¸¢¨½½çeç7NÉ2ÖÒ¼±¡“ß.*¯8Ü^·Û÷DjE cÌ“¼º®úŸ]ÿä.´½¿¿ü…–rŽ0Žp^Ë-Á7~åsJÿùV㙿N»Q#ã3y÷%¶ýízqþã¯ÞøÍo~óúë¯À‹/¾øøã?ûì³Édòr]_)oBP,¦ù‹õë§$I©ùÖ[û“ÚÓÃæÏm?K­JIHBÉ6¹mCÛï"¿‹Ž&rÿîgÕÙæŠqŽ$­=|xòÀïûÂÓ¿ˆ‡`¡HL‹hhê}Ç©;›ÔØp$™L¶´´´´´$“ɦ¦¦¹t•Q*E"áÂÂÓ—ôF0Æ P°­õ쩞›zÀ`L€ŽNÝy¼eÉØ$`Œ.éÀq²©ÓYeÏä2šá&@†jNð  ³õŸþô§rhûöí`·Ûï¸ãŽkzÙ•B"›¦ _ÈŠˆaÊVÉJ H €/ÅJ5jµ€Ð¥Çp‹ªX Ž ÙçbE‘îóݧN:uêTww÷õíBÈ4u¯×?8¸A×"!'00rKmÅò•çVe÷Àlûvàæ]‹+1D© sÞüö¦êÕ…šœ™D¢!„šj,Øäô¯ï¼ÝÔÔtðàÁƒ655½ýöÛpµA»êl/Ë¡•mm]G?Æ(fw¼bó°ÚÔÊ–®–1×ÄùŽã;ž(}Š:ÄlͲ¾£G]33  íùçËü®K¢êbÖÙp^O ŒÈLK5¯:Vnªæðx=‰DâÑG­¬¬ ‡Ã<òHyy¹a_«C’$%dl¬™ó~JçËT5“Ñ UQÙ,;6qlLŒ-–/)X’’R\g²UJ§gššÄì¬rà …  DÜä Ú”éÙÉ G‡4+Yá+ f†aµZeYÖ4 TUÕu=•J]s)q&¥IJ}ñ¸[U-GMS&˜è†®IZ!.ôk~ծάÄ$D°‘N+©”–ꌹ,"B0†LJæTX9gQÒqa„%“ÉD"‘ÝäÙÉÐÜFví eƒ1¦ëŒ³IT²?@†¡:`@)—p0 ƒF¶fuY\׿ìö#‹åÚÑÝ×Åuþë ”f•4›ÄìÈf3«³pÉòeC–etiT8WYÐWñ?›ÐeÿKø7ÇŸñ?ÍÿMüVµyÏßtý%tEXtdate:create2017-06-06T01:31:21+01:00&µ¼n%tEXtdate:modify2017-06-06T01:31:21+01:00WèÒIEND®B`‚puzzles-20170606.272beef/icons/guess-32d8.png0000644000175000017500000000322513115373731017317 0ustar simonsimon‰PNG  IHDR D¤ŠÆgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<CPLTEÕÕÕÙ××ÚÛÛÖÚÕÝãÛÄÃü¼ÕææÎÙÙ¶µÌÌÕÔÜÝØÙæÇÉÇÂÁ¸»»»ÚÚáºzzÜä¿LLÈ10ëÖ»©–µµyÙÚ åäÉÏHÉÉ5ééÖÕ½½–ÔÔܸÁ·¾½ÁÌÍ̸«µþô¼ˆˆÄ[[×$%µµ´þþó󻼆ÃÃfɼËÑÒÍÛâ亙™¸ffÉGGå ¨¥ƒ¸Áa¨¦¦»ÆËŶ¬ŸŸœ•••¬¬¬ˆˆˆÓLAÚÏWcÂÁÀÄÃÐ`ÍÐÍwˆÊg„ÍÚÚ֚ʦYÄdzÊŠÖÍÙ²rzºQc»ª©»K]ºw‡ÒÎÓÑÍÌJYÆ#>û*Cý/CÔµµÇÂŒæþöU¿S978%%%iii¡½&>ì9Qÿ{tÈA×3 멆…zzzYYY¬©¹‹‚ÉIÌKã«›œÜ¤¤¤ÖØÏlzÉ'Bô½Ä­Ô½WTÉ'&ÍÕÕ˜œ´‘°àÙè°|«»¸É×Úµgæé什åéwÄ‘aÊ‚;îtØ|%èÇVRË==“zœº¹«þ‚ôtÿvþ}â ÃoiȈNÖqÁ›xÂeXÙŒ4Ñ|8¼Ã“º²¾…V®Á¾Wµ±r£‚´†N›àßÙ×Ö0ä焹u¥6Oÿßä|²js½q™ãä㻼b+Ô,©½¤©€&¤Å¬“‡‚’o¬Æµf/Ê@}F¯nÁuy,™g¿gÿÿÿK—{ÞbKGDÀaßøtIMEá`"ŽOIDAT8ËE“iWÓP†ïMÚ’¤)h¡¥R´)‹Úb‹Š[E¨" *X ¸DT@DeiÁ”â‚¢ˆŠ¸þ5ïMóaÎÉ™÷̼óÜÐ •! $ãÿOCÅi©ÓÇÓ€a ñkÄâ•<°Æ”¨£’’Í&%Õj‹gÓìéüZŠrXCdšDÑ™µNÅõ.»$eçl$)=Wp»hŠD‚¼üd”+(Daã¦l”Ûl“²%«Ááb=JH™EÑ”™àÅBoº$Y‹r,ßâó+-­ßºm»FW²c'Ëèm¶]<¿Û¶‡å°¼b’ ”îõ–ûö(‡ÂÁCzš®8|„$€Â*áѪêšcµuõÁã'Ê“Dq>ß$:µ 'O90›²ÓMÍÍ5g΃Ás-«~Mlq«ç¼€;”… úB\lÇ‚<ñ%–óÇ…UP]]UG/_ Ö×å]Mv^ôfÑ”ç s>Y…I^ïÀìÍ[7€¶½¥‡0z{CÚ€¦Xyævÿ™º{ï¾%/kppHÇ®Ï׌´R~%ODîD££–±èøýÐL}y0ë&]>mFÇ{FÇ£ý-ÎÕ)â(—àRPÆÆF#GÇÇžxõäŠ$K¢ÿ¡æ,zúÔb¬|ülÀÀè ‡·“rɶ!ƒBRÊ¥‚¿¼ù9¡‘{ 415ÝMBY€©Ü ê]V)ûEF÷r&63Û‡QsØä«ë]uçk´ o“O¦c±·slkcø<ö µMïš«KmHð£vNLÏ#ç‘ î]5UB$U²§h‡œâ5vêãüÌHG…THÒݙܔ1j¨aGü@ }jžÏycÿİmç?³Ìƒëz„Ù/_C}ÅÅžFå¹yΊVyi?zîÅLŒúÛòL,ö®NaÌÀ«üý‡²0Ê?߯bsTØÇµ*·©TI²ý:Ž*äâ_Bæk&Qõ&#i¯sz*ÿ,¶ŒÃ;²èŽå¯³Ü‚?ìð­Ü_;ÅCPž™Kè½¥$éb! Œä¿ët nD,@-…Jä\û@V)¬Ü¼zͤêkõülØÍº"‘²%tEXtdate:create2017-06-06T01:31:21+01:00&µ¼n%tEXtdate:modify2017-06-06T01:31:21+01:00WèÒIEND®B`‚puzzles-20170606.272beef/icons/guess-32d4.png0000644000175000017500000000120213115373731017304 0ustar simonsimon‰PNG  IHDR TgÇgAMA† 1è–_-PLTEÀÀÀÿÿÿ€€€€ÿ€€ÿÿ€€ÿÿ€€ÿÿ€€qZjbKGDÿ-ÞtIMEá`"Ž~IDAT(Ï-R=OÜ@}³óQÍ]C;\Œï’(MDuJa™!´Ç Q„,˜š¸É•Ñ64ˆÎM ø¹†–†ÿ•Ù…ÕJÖμ}oÞ[ °0Òbö/m(ÇTÕç®êBubÌ2 ªí¡6fÙ•8G ÑœÌD‚#ЧAÙaóƒÃ%XF¼ï`Ê*Û3ú<àLÓî¿x9ÞË0È™Šêé f5‹Ãp zâ…<]Œ ‘§Hâ˜ÒÎ#Š¡EV)1Y޼@¡òQP)UŠçDRuWõÏEæ8Æø¦mÚºSº¤»×KT…«„¤â^8t°¥«Pñ3‚Ý‚øæñ-QŽwûµ%#qoÉËÝìŸÙDU~G™ò³øäY©.¿¾Ü¦1B\‰§éˆÕÚO„þ \b³á~š&÷µ ±K{’Úð'¦Jý ¯—NZZ7 ®²è×òÏï@ýýý-Ó¤’„062Ž1看…kša€1€I©„1MÅ4„X8× C Ù6œs„|[8{ îp„"‘éñqÍfÃQLQêŒ* ¶Ù0G8žUU+!˜!•üþ¡h4qB<Ûbš&Æø{Ęi±Ž-[¿¾ª½=öôÓJc€±{wíæÍ¹þógAöø}(.ÞP]Ý?©(hv6ªi?©­Ýät¶ûý§¬Ñh8‹…B¡x<žJ¥²”3F­ÖPOOÍ¡C¥Œ!ÎO?½ØÚjïéYyý:O$‚_þÕP™{ù’Ã%¥*ÉËûüâÅu²<ºvíUΩÇ3ƒÐ@`INŽ c.\ …rrrLÓÄÀ9‚áó9I2)µ˜ƒƒÂä$èG(–÷çºTÁ0¨$iQ:†ˆÍ„L"‘òûýn·»§§Çív†€1(ŠÜÔ4QPªJtÝ ··§[Z’"çÀÀ·¬ÖSõ£±ÁR=Qܨªëæ Àœšj²ÛŒßš˜˜ôûý###Š¢`Œ9稿¿CkôÆ€ó÷GĹÙàž½®öͪ®hükñß¿ŒÕU)Ïìuç•„ýÄý¶`‰'ýäÞ­ëz<óQNÉ™tÜKÓå¹ ’ÉY!“ÉØíöì)p„C•JKþ¼áW‰º¿†•°´U³žÙ¶è¥]ÃÆ¢‡¨ &ZKg[¡°ôp%.æìú¢™—yÝ¢ü‡]1ŒÉ¥Ô4MBHö‹ ¯¯ÿÆ›ÝÝÿ¾{çåʶø.^×ÖßõÏ«¯_8 ~ œBv|¹­·ûÖ¥†:ÀºEHשSçß|s€SªœÛ¼y(\µbEUUUgg'œ9sfhh¨··—2Îí2|u%5Zá)@,2·øôW.íýŠİ§ê/l{ûÄ–ž>(äBUG>þØáó„ŒU|ñE`pðþ;b‘HCcc"‘p¹\ÙPÀ²[0Õ`9a]WäÐÀ0«"[s󄬺)0p¹ÌD0cÀ˜n·›”6.]ª¤Óy.צM›!YJcŒQ:Úêó:š{ÒÉÄ\J«/»ÚqðhìIW¿Sù¡sà‘Åï¹¶gç,€fßTWçîÜÉz¨ÏíæºÝ·ÏU^Ÿ™™K&5MK$Œ±ÛÑßßÏ9P‚D»ºn&™»6ÔÚE"€u,îò}R“·r•·Y1šË3üÏ ¿¿t÷nc\§b±È‰ò²e•kÖðPÈárŒS©!DUÕ,éììÄÀ jºð^Ëèó+”Æ'Ãdá†XlJ:÷ìÖ©Ïm“]cBIÎ†б£µV^¼†¶¶T$"<ûì²Ï>³vuM65½ûÖ[gÏóz½ƒƒƒyyy„ œ3*YC#½5½/•䙀H³ïƒ¯®¯´FzVÏ]â¹Bu&nvf®¦W_-U2@ˆãĉ¯V®”GFZ.\JóãqíÅçZ[OŸ>=<:ÚÖÖ611áõzA`ŒQà°`D'r%ˆd˜`Í1õÀ 13 6Ðu$ŠË£É§’A00¶˜¦yó&õù€†±H©3žðù¼òJrv¶´¬ŒR*Ë2c !„a0©¼Á§¹!­RS΀¼h½R¸Z™‘pH‚ª=m›&Š Aש®‡„¶6uÍšTVK Ã__o›7olhhÒçíîîþ¡Tp†kd¤Ç=ðšd&¦æ?ên¸O×R³_¿—7Ù•Ì­@«æ.›¼Þ-{KœoÝê¹w‹¦©÷ÿTxîäìüJíñgòËJf£Qƹ$IŠ¢8ެíPà€PmEÞ÷zÌ%áÞBb¡i0læ’æéš‚ÆB{1¨Š\Y5³l„ÃÖ¦&ÂqŽÌ'VüøÂôuöÕ%.0 I–c²,›¦I)Í õõõcB´Ìì ‡Ø ¯Y°Œû>§Ê⿪*Ÿ**¡™´qåò.ÁõK¼÷æo®#€AQŠžüØ?FºÏ#E)3é¾7ýà±ö[öÌÄg:::Þxã³gÏΛ7/“ÉÇŸØg·’KW"»Øï–e™'5žžj[ûê¯ß4Q2iNhà“¼5ï¼+QÊ!_SÇmèò•jëP.ÁÆÑáô¼û,Ó<OKK !dãÆY2g¥,L7`Œt]·ÛÀ4ì€0]‰Í©€i`„LÈq6®“eˆÒJj×îÝ”ÐñññíÛ·SJ¿— %ÚêmwôÌÍÍ%挪’«Ûî"3ûûoÚ0Ò§CpkàAoû–ží[ç8˜º~mWÚõÈŠŸ:ÓŽ@F×c¬xL*^P „gffÒét8ÎîèÿIEˆ“³†“©ÌúuÕ¹NÌMÛ¬/8ûÄ#7—U¬2 ¢:Ý#'OšÓÓÅ»wå˜ tŸ,[–ßÐR«D Ic’$I’dzC&3Ó´NMÔ²êùæåNøf)iK%ω/ü®áT—ôõâ@YyQÝÔûïÔ~má¥KÑ i]—ŒÅÎÿ|(qÒ6ýu Šo]Ù_Þÿ°ûZw&“9vìXcc£(ŠŒ1²oß”ZB¡ªÊÇËËç¬VÓ•ßüoկɩÏV›.öª7[®ÕW>³ßŽäd2îÿôLx ¯œ·c‹î0CÖ‘«¾ú=E‡¾|å² GݱcGÖ( cÌéÔ$ÇÝ4õÞñ @Â"ø=áéÁ««’ia»iš}=Ñ©º°2¤ÊTRÖˆ?¾oÿ3ÑØ’%K\.WII‰¦ic €2’Tï÷稔êÁ0Pé®;• 9X2^QÑÜ1VèM§† w®/_IbG\JºP“.òæ¿þÚoŽ9rüøñLNNJ’Ä#Œ6›gzzi<>‹åŽ ?å,ÞÜŒka×âÍCÍ/*¿(©X諯‹MMÅíö[û÷»·l+¯‘’8ššIÛ–§[T¸Ýîóç·¶¶®]»vùòåK—.Í.ú6ürŒ-##AUÍTVΣ4ƒ0A 4>:^à)°—ÚUM¡VÛH(¤¤Ó•óç ªŠ0Ñ‘261êÎÏ÷8ŠÔ´j³ÛBº®Ë²œL&9ç·×4ëmŒ™¦©Æ”TCeœ!@"1&Ì0LMLEÐU1DQ@1“Bˆ1–u›Ûbw;cB©-›³à² #„8pÎ8pŽ ¡¶\e1Ë&Æpø.Q×þø_] <=c%tEXtdate:create2017-06-06T01:31:21+01:00&µ¼n%tEXtdate:modify2017-06-06T01:31:21+01:00WèÒIEND®B`‚puzzles-20170606.272beef/icons/guess-16d8.png0000644000175000017500000000237513115373732017327 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<ßPLTEÖÕÕÓÛÛÊÄÄÒÜÜÑØØÊÅÄÕÝâÎÍÏÌÌÊÕÕãËËÈÏÏÓÕÕÙÓÓÒÔÔÔÕÕÕÓááÒðÑpqÖ_]ïÉŽ‹ãì4êæÇÇ’íëàß7ÇÇËÅÅÅËËÊÑääÖ]^ÿÕFFÝ76ÈjZðÿûøÆÅ`ÿÿðð¼»·°°²¾¾½ØØØØÚÙÍÈÈœ[|ÌÁÈÁº®–PÑÕáÇ®…Æ¡kÍÜéÅœ`ɵ“ÈÎÕµ´²ÂÂÂàÞÑ{‡ÖBÿjpà<ç.ÿr½eþ õÆllûõ!"˜––\]]ŒŒßßßßÞÒˆ“×Bÿz}âLåFýƒÃ~ó$.ìÇ„„ñæ32ÄÅŹººÀÀÀÖÙÛÒɼ·ƒYÑĹͺ©¶‘JÔÖÚÉÉeeÍááÈZZιÅÅ«¨¨ÎÎÎÖÖÖÑÛäÕ“XÿrÓ…?܃0ÿwÇ‚Rñ üÄWWþø•~€€¾¾¾ÔÙàÖ·“îƒ ×±…Ñ¢}àz#˸©ÙQTÜ==̰­ç3(ÞZQÏÕÕÊÉÉÉÉÉ×××ÜÛÔ¬´×J`Þ›¦á×Û†ÔÙ6ÌÖ½ÒagÖOLÆÅ͆C±¢vï´¯zyz¢¢¢ÜÜÜâàÑiuÔ.ÿK[Ûêè Ç´Pïÿ¡Ur·¬§¤¨…†…ÝÝÝÛÛÕ¶¹Ö[iË©­ÞÛÒ–ÍËBÔÖÍÌqtÎ[ZÍÔÓQ¨¤|´ÛàÙÒÑÓÍÍÍÓÓá×Ö…úúã×sSÔkì“È”é:Eæ/(»›¯ƒ#¯œP¹£¥£jjj———ÞÞÞÑÑäÕÕ\ÞÔD&Ü4i¸Xÿþ¦^‡o´†³ŒNOMƒƒƒáááÖÖÙÏÏÉÃÄvÔÎŴ͸{ÃxÐÙØÊ›œÆ‹‹ÔÝÚ¥ƒ±¹¥ÁËÎɲ²³ÁÁÁÕÕÔÕÕØÎÎßÔÕØÚÔÙßÏߨÕÖÑÜÜÐÝÝ×ÖÖ×ÞÔÖÛÔÙØÙÚÚÚÿÿÿM\Ë;bKGDô2Õ+MtIMEá‚is4IDATÓïþ  !"#!$%&'()*+,-./0123456789:;<-=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[-\]^_`abcdefghijklmnopqrstuvwxyz-{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ( ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸k¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊ(ËÌBÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäå-æçèéêëìíîïðñòÈó— v†°ØM%tEXtdate:create2017-06-06T01:31:22+01:00]¦ó%tEXtdate:modify2017-06-06T01:31:22+01:00fOIEND®B`‚puzzles-20170606.272beef/icons/guess-16d4.png0000644000175000017500000000055713115373732017323 0ustar simonsimon‰PNG  IHDRíÝâRgAMA† 1è–_PLTEÀÀÀÿÿÿÿ€€€ÿÿ€€ÿÿ€€ÿÿw£\bKGDÿ-ÞtIMEá‚is4zIDAT×=Â0 …_ó"Áè#gaLT:VîQ‰°tEݸ5n%˲¾÷c`ð-ÎÝ/ªÝ^NjzhãúÉÊ/¸œ,©¹µ¸öTU:Iió*”ÈÒèÁ±?ò¯9Y"êY2ßÃujì«¥7‹kÜû÷'Ã1÷… áKChì%tEXtdate:create2017-06-06T01:31:22+01:00]¦ó%tEXtdate:modify2017-06-06T01:31:22+01:00fOIEND®B`‚puzzles-20170606.272beef/icons/guess-16d24.png0000644000175000017500000000242213115373732017376 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<ôPLTEÖÕÕÓÛÛÊÄÄÒÜÜÑØØÊÅÄÕÝâÎÍÏÌÌÊÕÕãËËÈÏÏÓÕÕÙÓÓÒÔÔÔÕÕÕÓááÒðÑpqÖ_]ïÉŽ‹ãì4êæÇÇ’íëàß7ÇÇËÅÅÅËËÊÕÕÕÑääÖ]^ÿÕFFÝ76ÈjZðÿûøÆÅ`ÿÿðð¼»·°°²¾¾½ØØØØÚÙÍÈÈœ[|ÌÁÈÁº®–PÑÕáÇ®…Æ¡kÍÜéÅœ`ɵ“ÈÎÕµ´²ÂÂÂØØØàÞÑ{‡ÖBÿjpà<ç.ÿr½eþ õÆllûõ!"˜––\]]ŒŒßßßßÞÒˆ“×Bÿz}âLåFýƒÃ~ó$.ìÇ„„ñæ32ÄÅŹººÀÀÀØØØÖÙÛÒɼ·ƒYÑĹͺ©¶‘JÔÖÚÉÉeeÍááÈZZιÅÅ«¨¨ÎÎÎÖÖÖÑÛäÕ“XÿrÓ…?܃0ÿwÇ‚Rñ üÄWWþø•~€€¾¾¾ÔÙàÖ·“îƒ ×±…Ñ¢}àz#˸©ÙQTÜ==̰­ç3(ÞZQÏÕÕÊÉÉÉÉÉ×××ÜÛÔ¬´×J`Þ›¦á×Û†ÔÙ6ÌÖ½ÒagÖOLÆÅ͆C±¢vï´¯zyz¢¢¢ÜÜÜâàÑiuÔ.ÿK[Ûêè Ç´Pïÿ¡Ur·¬§¤¨…†…ÝÝÝÛÛÕ¶¹Ö[iË©­ÞÛÒ–ÍËBÔÖÍÌqtÎ[ZÍÔÓQ¨¤|´ÛàÙÒÑÓÍÍÍÖÖÖÓÓá×Ö…úúã×sSÔkì“È”é:Eæ/(»›¯ƒ#¯œP¹£¥£jjj———ÞÞÞÑÑäÕÕ\ÞÔD&Ü4i¸Xÿþ¦^‡o´†³ŒNOMƒƒƒáááÖÖÙÏÏÉÃÄvÔÎŴ͸{ÃxÐÙØÊ›œÆ‹‹ÔÝÚ¥ƒ±¹¥ÁËÎɲ²³ÁÁÁØØØÕÕÔÕÕØÎÎßÔÕØÚÔÙßÏߨÕÖÑÜÜÐÝÝ×ÖÖ×ÞÔÖÛÔÙØÙÞÞÞÚÚÚÔÔÔÿÿÿU[nbKGDû¢j6ÜtIMEá‚is4IDATÓïþ  !"#$"%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}>~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢)£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎ)ÏÐDÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúîb{†Nzøã%tEXtdate:create2017-06-06T01:31:22+01:00]¦ó%tEXtdate:modify2017-06-06T01:31:22+01:00fOIEND®B`‚puzzles-20170606.272beef/icons/galaxies-web.png0000644000175000017500000001012713115373717020066 0ustar simonsimon‰PNG  IHDR––j.>gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá áoí_IDATxÚíœùwW–Ç+Àœ3Ý?O÷éžú—9Í2ÐÒIÿ}ºû·™a’blcc0›mb:à@Kº“4ÀH/À!’`á,¯2¶–*í–dI6²±!€7IµÜyU%ÙõžÊvÙHX?pàHׯJ^UÝ÷}÷ÝW”5-Zh€™°˜42–+l ‹Öë[¬YÅÕ¤âT±&ý¼ÕëéãÒ/y…Òb¯,ÒÖnÑ¢yúʽ‹‰cQÿúë•„­ZJzþóÕ£–¾±f-f¯¿ºê¿Ö®ÕÔ‰fkÞXJýì·Ä¡k׬xô¼ñcj «…úõ#o/nÁ÷ôŒæSuÀ‚ÒxèFÿà®ÇÔkÀa>ê¨=Ü¢fâPtÔZªEµÒk¢1³Xk ÝÝ¿‘ÒA˜S ý °„kˆZ écx"?„á6µ &°vœ0ÞAÊE` ŽÕKヱ×[l¸ËÚDÕ&ôÖ€øizKö Ât½¹?ko¥‹‡ÞªýGêYäI#,ªs¯¶5Î÷‚>XÂ"f&ÕÞêA' ©ê­Ý0ƒp'ê[ÌXkUÐjÇÍÙÀ8p=˜K}Øô] fõÿ8:KÿÌÁÁz@XK¿¿¥SÚ-ý‡Ho͵·š©¥-µõ¸5ܬ#<ºÎÿ¦–$ªïÅ Ýî#§ä^dáÔQWwÃâÄVK¨ Oû}Ü:t]„Ǿ¿ˆ“7¦ÎHãSϧÌÏÃ-wËO‡8Ð}ï­ã:ˆ<Ë)¬(Ǭô@U£Ì¢£|w“êÔOÛ0³:êi»ðõt= `Ö?²Šz0\4"rq0²åú×;L\T>‰V›QG›Ì˜ÝË gt<+R:‘¨ÒÆA—€%À IÀ²ÔÛÜE÷.GXèÜKmgÝsHŠôöÙ{ 5ˆt‰ÿ—Tb P[^PP^'þš&,†ÏnË(»ÅZ&½·P(F!6<ÎŽÅCgæßû'\Ç ±¦IÇ1ÜkÃBãø;.Ô E)½·°ë£ëÏ×PÐ>ïëzm±€ÛöDîc0¼§Ï+¼Yn!€o{añÛÇz«ã€bX_ð{ë㫱{«²6}î-¼ãžÄ¯‹ÓèIDmº³.Æì=LmÜšjô¸ºäíòlj£ü\±æ9&Zmºn ®Ì–nI*b r!¬® v'*ì ‚Ô[Œ§«o „Û@_—‡!šù{KH¢Þòq%êüú÷Ù9›pËÉþÃM'®b=+©âÒ]»•¶«,+¿l÷¥íÚ÷µF˜EG:¸ Ü…«ÓD-»ý •¨ÈS´ÝÆÚÕ6ÿ’ZDi0¤å½„–ï2èº uo ´<9óaúÏQ5µJ«éx“ºÐÏ`íl=Õ‡/Vãöù j™þvÒn·ÇÌ'qžhž¥ÊˆóDa7U0ÓI¦;*-0À$mžH>‰–`U ã,ËED¶h„cÙqØIU-ø£èhk´™±ÛÍlk–gÕ\2fÕ‰XRo¡ñjÈ?,«O±·°:î9ñXƸÚ&sOý!6™9ˆ8–¦wK¶•TXЧ9b :ŠÝ¥{ž¡ŽÅCCV; lkf#ðsÃâ!˜ym ÏöÉËoÉXd>’RzC™ýèÛÜ.b~«œ Ü¡KZ6PÆ Ã§W!Ц[Q¸|}›V*c¹S&y¹Ó8Vñ`lpÙ˜É(Âü_üÕ"¦bXŒÍu0§â½¹:/=cÜBõBå±Fîùòò´çËuâ:[åV÷$V,Û!%>âXî¢CÏP»¶ÿùÊCÏ„•”µj‹Íô¦ `ß_FIALÈËóá°´?»°1ŽïG°,Ž7Í6ÆÞ~×nÁkì-HAH úl$,¯ìGÔWö ³­ì¯ Ò}'KÙÜ›­¶Õªzëb¿ÎóJú€…#§û¬.‹¡Ï‡•KøúÍI«ƒXÁè]…-ñø·åÛû¶¿Pÿþúê×”¶úõŸSŸØºnÉ¿ÉCS‘«Ùò»_¬\ŽÛŠ¥ÔÖ‡®ýê§Äéwùo×ê5?ªF–uÖ›7&±®6w}¨¢åÿ…:v¿ùJ‘œbá¡-Ç\oXª¢å—$úÊM’Ÿ¢5)/b?:z!–óÎP5•éзaÖ®¿fuötÈÓ-ªŽ‡˜¾•”çÙð#¥ ¶ÚF=ÆìÑÓ†?à®AØA]çb¾¡èjâ–7;šÖ?ñ¾ƒÓûüÆÀYjó0Y×eûÞA[ü{«äf×7;Ì>µYµs¼ièŽw”S:b I-@ô~²ù™ø8ßxÛl§¹!Q‡f®³[»ñÍ›b³'¹'ă–SÃÄD[ˆœ;ðÐ9¸+‚°jPÄžmŠÁøNfœ¸qig^§ Å-„5`Ƈe9A» ¹».ßø4ã´Öšƒ@_ï‡ç×[bBÁprß¡>‡8øL‹eeÞ/í;Ù)’z,+m<ðÐŒuF,4(z íÒ/ËÊXÌZ63`!ÔNúôb°2pF¬I{‰õë%ÖK¬´ÂRª±T‡êdaIÊi… Nj™NØð¸q¢‚À]a(æ‹’Å,ý6§ÒlHf2°µ É@ÖÌiW•-®$õÖ²ÎÆ{JkìžF4wáíæÅÔ¯üDÉŽÍÙ@“%;ó¨*"qÍVSŒ¶¥µ1U?_¹·å«~‚¦­X»vµ)ÆrêW#ýxuIhHÄ]A®˜º2ч¡Œ¾Jæå˜Ù{ZzˆÂt÷Èfê¼]Û„ì9nyüclµ&FšŽšF£Yü`ìϦÎð 1Íôõ5±š Í+Q4ëdÑÌE#,¯%/?¹p‡$_¨ß#¦gÌ¡sÊjí­ØÚ¯!nű»÷‹½[Þ½îEq4EX°wŽUVD.XŒÃ\Pr«ã»í…“,ü…‡ê[®äЉ4­½åÜô7)ív>Çe5¥+ CY-b”Êί ‹î=õ°¼˜i¬8ÓkLVŽ_‚ƒp^´ÝòLÏK,¥Û]äI –T¶.ç.U#HMXΠ㱓Œlp¥«¯8žjÝÚ°\‡bgØäN ÖÀöøªÂ£ÖvoùÞ½&-®DàJEjî-öX¤à…Êzˆjë-wÃÛÅÄ% ¿Õè~ž'‘ƒŽ1U¬0Ô•€´dÕR 9nѾsØö·/øèùÇ-qؼ#·x8µÍ-ÀØ™­BTŸ_ÜDŸ7–¸fpø½7'06åkw—l+960‡pj¥½=÷j›zÄü|±PWT”êýÆòÛ‘UtØí6[p,iLlŒ* °ÅÔî±3/ °^tÚí%ÖK¬ùc1ŒÍn“ WÒ‹vûÌ]æ^7VX´÷ûÒܬܲ{¢jN,Ú{}ÝWOáé—ÿ{q¥ VÈäjù?4t¸Öµ9•­m&¦åŽ÷™¬zÍXßÁ8VÀ>¡Aoå ˜üûÿ.I¥0\¨ô3*CCnó0î ;’×[ĶIcï*¯¯Ë¾)–}9Žn•m“y›³Ö“¾ülQâû!üa„Å]£Hf(ŶW–íÿÕ<“–o;L½Õ©k\ÿ?Ž­»[£¾ÉT¥…Z®Ðò’uvë:ˆ"ôvϵÓáÅ,‰3Ÿòo G>î5N·9ñ…1«óÄxœ¬ BÏy“)šU›lŒÎ¸-Mˆo­·ÚL*Û½'`Ð Q|øCM½0ÑØ‘b»¦Æ0®Ö »÷+ßiw1*›ã‘°37òòD]Ù[Ú°æ¿%—vÙOoÍÜzÆá¤Õöìó×wí8õLyúeel¾@0à³2*¯àý}A€ÎnVr½,±pÅ"¸X|þ>b"ïz¹B§¿ ¬I#°-IÅ‹<ì²Lq-0¦Šø–ø|®Ä]`,ßäo|q&m°ð”Ê‘ƒO¾âX`,Ô]ewååšÜÑ©Xh,œë]b&v¬àÛôy¥›~ÓÇMí7~­œÇ/8‚»µwëåA,»°ðXâ`8잇TaÍû•s~“\„®öÊ9¥Ó0.pdaú¬¯œKñ ú@Zó!m¶Âô”¿Î9WžÙ_gø^þ¨Õ¦^þøB^•©Õ¦^•iM׋¦ëkXÓÎÒëÿ·D[ÃÉ%tEXtdate:create2017-06-06T01:31:11+01:00¨:»%tEXtdate:modify2017-06-06T01:31:11+01:00Ùg1IEND®B`‚puzzles-20170606.272beef/icons/galaxies-ibase4.png0000644000175000017500000000134213115373731020453 0ustar simonsimon‰PNG  IHDR¥¥@bgAMA† 1è–_bKGDÿ‡Ì¿tIMEá`"Ž vpAg  OýIDATxÚíÙáVà †a.KãÎôlÕ¶0ÒÝÇ|óKe©œ” „4C„wP¢D‰%JÉ@‰R1P¢T ”(%JÅ@‰²×”w*¯UT_‡‘އ—|”(Q¢D‰%J”(Q¢D‰²T.ÿX'ie ññ]Š;§œ2­¸í+9eÚpeª)³r\ÉbʳÇ$© ù’ô‹¾My?œBVå=gnm§~/Ê,ÿýJ¹lø+ër©[¥ñŽ‹)õRMYï=jÊz—SV÷DzÊ'0„˜½í‚J«ƒ¢D‰%J”(Q¢D‰%ÊOP6Ÿüç;œ¹¡tU–ÕÕº.çê(Q¢ôQ. K’V÷ÛZJë~[JiÞoK)Íûm%¥}¿­¤´ï·¥”åB‰òÓ•SÔåïøëå$½gŽ>®³'ŠÏýc4”µûí³ü?Pnse(_ã,ß]wuó§4)«ùîÊüîWVó½•ÅzØ­¬ç;+cÑ[b§ÒÈwV–}:ìŸÒ 4ò½•å¯_ÇÛÎËÆó·g ¼UiÖecÕu繺ýŽ·)׈ÞÓs½lS®·ÝwVïiTŽõ®n¥ÕÇ[•Cû€ûžúž¨U9´§¹•ŠÏe!šãçÓYÉwWöŸN/J”(Q¢D‰%J”(Q¢üOÊKçe ùs(ŸÒW:ÌåYøÔ-J?å7nÍl‘ý‘^i%tEXtdate:create2017-06-06T01:31:21+01:00&µ¼n%tEXtdate:modify2017-06-06T01:31:21+01:00WèÒIEND®B`‚puzzles-20170606.272beef/icons/galaxies-ibase.png0000644000175000017500000000200213115373731020361 0ustar simonsimon‰PNG  IHDR¥¥@bgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá`"Ž vpAg  OýõIDATxÚíÚMNÛ@ðlHo`'n%—S@³‚æ….Q$v%H•(âã m‰Xðq‹ÄQV¾I KÂظ”€åqçyÆöˆ¼¢ÿ[Eÿ•ŸF#åi^ þÿP…I „J(¡„’eA %Ç‚JŽ%” J(9”PÆÖy”/©L~¡­Ì‰ÕN^ç¡„J(¡„J(¡„J(¡„2¦¼Þ›wŠÎÂþˆ³òGiå|x?<[.ÿä«Üœé?}ê¹[\•ßß_…/Ý#žÊëR?òÔsF,•{+ÂãÆKåü¹ðøôã +U5æ”~ Ê*õîÜÚyJC9~qêNPÞ…<—½t†‚òâ]ʽ̥Ô>· g‚ò¤=·l”ûË‚ré¥rTîE·7,•Á‘{"WžÊ`Ëõžw²ú%ઠÚNótp78i8Ç_e0:¨?ô—õÛ€³’ü…J(¡„J(¡„J(¡„ò5(5îÔòæ Ü_jßOfϸd³—¹ÎUÞs]0r¯%”PQÊçÛÌ”Ä|›—’šo³R’ómNJz¾ÍIIÏ·9)éù6'%=ßæ¤,ÆæÛoX*éù6'%1ßf¦$æÛÌ”Ä|›™’˜osSÊçÛì”Òùö”õY{ÊžÛèÊ•²ù¶*o^¹m5ûdžõU®””*o\ùÙí?}u¯²šA)Í›VnW#ýce'µRž7¬ìXýÈ—{v7¥’ÈV®7…o_l¥TyÃÊÙXÿø!¥’ÈVZ±þÑ×õî˲çõîÜtþ™TyózÊñ;Ö?–Sîeö|å\¬¬ÅÖ©z>wt>ñ\§¼WßháO­ØºJIçM*»–Ð?–¼”J:oRéïT"ýãôî?ë %7ªôW+aÿ8½&YW(ɼY¥ÿÍ^zìí]éºBIå +ýn«öÐÖZ±®PyÓÊ ël&|PB %”PB %”PB %”PrPæº/ÓÈë)'ýÿË¿o½–½L~A}îòæ¡4ªüž½d×ËQP®%tEXtdate:create2017-06-06T01:31:11+01:00¨:»%tEXtdate:modify2017-06-06T01:31:11+01:00Ùg1IEND®B`‚puzzles-20170606.272beef/icons/galaxies-base.png0000644000175000017500000001116313115373717020224 0ustar simonsimon‰PNG  IHDR  ›á9×bKGDÿÿÿ ½§“(IDATxœíÝAHéûðôÏŠ1{1± ¢§˜C¶‡R-i`MDVªØ˜t”4‚B‘ E{ØTïîA mÝu…ÒcUÄXPyÎ$“IÐø?­ à@ „€BÀ!`„0B! €@ „€BÀ!`„0B! €@ „€BÀ!`„0B! €@ „€BÀ!`„þŸôè?þø#éñTA7Ä W0B!Ú-âºKp2™¤ÛˆùË—/D/111!Š"ÑÁÏœ9“û¢ú©obu~èà @ „€BÀ!`„00íííýþûï?ÿüsyyùÙ³gËËËþøãL&£ui†‡€º±±1‡ÃñæÍ›žžY–3™Œ,Ë·nÝzýúµÃáxúô©Ö£ç` O‘HdnnîÂ… ?,++óù|>ŸoeeEÅÍÍÍþþ~ ‹44¬pÅãñÇ/..–––~wÁÅ‹Ýn·Ýnomme\°E,P{{{·oßžœœ<*]9çÎïííÅç±ÿ+P‘H¤¾¾þðÎð(ÕÕÕµµµÑh”AUüAÀ T"‘ƒ _¿~=‘HÖÃ+¬@%“Éšš…‹kjjè~]›oXúçŸJJJ.¶Z­étš´^!`Êf³)ÏL*•Ê/Ž‚€(§Ó)˲ÂŲ,;NÒzx…€(¿ßÇ.õûý¤õð +P’$­¬¬»ryyyaa¡££ƒAUüAÀ ”Åb¹ÿ¾(ŠŸ?γìÓ§Ommm<(..fVO°ÂÕÚÚzãÆ ·ÛýöíÛï.X^^v»Ý7oÞ Œkã~± õ÷÷WUUµ´´x<ž`0XSSc³ÙR©Ôòòr<ùòåðð0Òu¸‚i¿–(Šÿý÷O?ý422réÒ¥~øáÒ¥Kþù§ÇãY__GºN Ó;ýZ‹¥»»{~~~{{ûßÿÝÞÞžŸŸÿå—_ð¹ëô°EÔ5ôk¦_è×ⶈ:…~-> `:…~-> `:…~->à3˜"ÔS¾ž n¿ƒ)ð]†Ÿ®B}p6&&&¾úI:>Q¿V*•úö ̾´†ÿ_§w†ôoçÁø£/¢öí¬¼¼\–å²²2%|{{ûòåË?~üêçÌ.\F_D÷÷[Ä|’ɤVÎõkù|>%Ç9ª_ëË—/FŸ¯et¸É¡Sè×â¦Sè×â¦Sè×â¦_è×ânrèúµŒW0½+À~­Ãýo¡PÈÐóÊ0(¨~­¯úß²Ù¬¡ç•a‹:Â_ÿzÁeÿ¶ˆ  ¼ö¿!`  ¼ö¿!`  ¼ö¿!`  ¼Î+CÀ@xW†€.ð:¯ ]àu^ºÀkÿºÀkÿºÀkÿzÁeÿ~t„¿þ7 ôEŦ¦¦h4:22²¶¶¶³³SZZzþüy¿ßÿèÑ#£ì  ` ;¹þ·îînñ÷"2€Ï`„0B! €@ÈØw™M?¡î>Â^ñ0Œ£×O óÁŽÂ(`Ì.5DŒ^?5ºGUFfì-â¢pÔ;7fóÇ z~8€›„0B! €@¨ vxÞÔÙ³g =oŠÎþöÕ¼©L&cèySªÃù!ÅÉs°£ð7oJ]8?Ôx—ó¦T„ó÷[D^çM©ç‡ nÆë¼)µàü°ÁmÀx7¥œ6¸ ¯ó¦Ô‚ó÷ãuÞ”Zp~Øà6`¼Î›R ÎÜŒ×ySjÁùaƒÛ€ñ:oJ-8?lp0^çM©ç‡ nÆë¼)µàü°ÁmÀLœÎ›RÎ<ÿ.¢‰ÇySêÂù¡¦‹€e³ÙééiI’677sÏgìv{]] f³ù”ÿjÞT*•²ÙlêΛ"­ŸƒóSÈ´ØìììÐÐP}}}___uuuî_PY–c±Xssó¯¿þÚÔÔtÊ—8³Ú”0zýÀ†f›žžVÞäñxôÖ.aôú Í&IR(R¸¸½½]’$ÊrNÌèõš}ÛØØ8Q?Òû÷ïó,`?…@•ú™ m¡>?˜qÍæƒíîiwwWÞ?£×ZÑl>XIII:.++SòÇS©”ÕjÕpH—Ñë­h¶E´Ûí²,û|>%‹eY¶ÛíyÐ]Žšß¥nýDó»LôìH°ó4î|3ÍnrÔÕÕÅb1…‹Ÿôõõ­®®f³ÙÕÕÕp8¼±±ÑÜÜ<77§up*ccc‡ãÍ›7===²,g2Y–oݺõúõk‡ÃñôéSmËãü öðáÃgÏžÍÏÏ_¸páà‡eee>ŸÏç󭬬­­­®®. ‹„ÿl`` ‰ÌÍÍõþŠ¢¸¹¹Ùß߯U…<lvvvfffii©´´ô» .^¼¸´´är¹***—§Ç?~¼¸¸˜çý]\\t»Ýv»½µµ•qy9Ün³ÙìÐÐÐÔÔÔQg?çܹs“““ƒƒƒûûûÌjƒÓÛÛÛ»}ûöäää±ïïøøxooo&“aVÛaÜlzzº¾¾þðÎá(ÕÕÕ'‘H0¨ Ô‰D”¿¿µµµÑh”AUßâ6`’$…B!…‹ÛÛÛ%I¢,T–H$”O¿~ýºVÿ€r°šš…‹kjjÞ¿OZ¨+™LžèýÕªáˆÛ€íîî–””(\lµZwwwIëuåžg*\lµZÓé4i=Gá6`%%%ÊÏi*•²Z­¤õ€ºl6Û‰Þßü÷Bèp0»Ý.˲ÂŲ,ÛívÒz@]N§óDï¯Óé$­ç(ܬ®®.‹)\üäɯ×KZ¨Ëï÷Çãq…‹GGGý~?i=Gá6`‚ <þ|ee娕ËË˯^½AU –ÎÎNI’¾¿  ªú·3›Íáp8|þü9ϲOŸ>‰¢xç΢¢"fµÁéY,–û÷ï‹¢xìûÛÖÖöàÁƒââbfµÆmÀL&Scc£ .—ëíÛ·ß]°¼¼ìr¹®]»ÖÐÐÀ¸68½ÖÖÖ7n¸Ýî<ï¯Ûí¾yóf `\ÛžÑd2uuuUVV677{½ÞP(TSSc³ÙR©Ôòòr,{ñâE__Òe\ýýýUUU---' ~ãñøË—/‡‡‡5L—Éd:Cúîà[è^EÉ·2íïï'‰¿þúk}}=÷üÄápx½^Aòï uRÿvpdu¿xôpÿÕÎÎNii)QÿÕÁ÷±æ¯?“ÉD£Ñ™™™µµµ\?Øùóçý~GGGþáÁñéÞß‚ØÆMý*lll¬···¾¾> VWW箲,ÇãqI’îÝ»×ÖÖ¦Ök) ØéO÷þr¾Eué¿ÿJo0PÊýWzÃó]DP‘Qú¯ôEŒÒ¥7(b”þ+½1ög0 7`Æ(ýWzƒù`ŠÖÏàäœ~¾V:>QÿU*•Rq¨—qçƒû9³+žƒ•——˲\VV¦dñöööåË—?~üxÊÅs0½0h $×åóù”,Ö°ÿJop“1Jÿ•Þ ` ˆQú¯ôEŒÒ¥7(eˆþ+½áä&°¡ÿþ+½AÀàdDQljjŠF£###kkk¹~°\ÿÕ£G°3ü 'f±Xº»»»»»M&ÓÄÄ„(ŠZW¤_ø @ „€BÀ!`„0B! €@ „€BÀ!`„0BÑ®’Íf§§§%IÚÜÜÌͳÛíuuu‚ ˜Íf­«žñ›½zõê‡úúúVWW³Ùìêêj8ÞØØhnnž››Óº@àçW°‡>{öl~~þ¨yV@`kk«««KÃ"c<lvvvfffii)Ï<«¥¥%—ËUQQÑØØÈ¸<(Ün³ÙìÐÐÐÔÔÔ±ó¬&''÷÷÷™Õ…ƒÛ€MOO+Ÿgåñx0n(p0I’B¡ÂÅííí’$Q–ŠÛÏ`'šgõþýûoޱ:q0Åp8™öíñwwwO4Ïjww×èCÌò ¯eÜá] 0 õ¥àÛã—””¤Ói…ó¬R©”ÕjåøzE÷Õ…ø^ÄüŒý,™LŽ÷Êc·ÛeYVxY–ív{ž_ÈŒÓü¿œS=áàü;`yÔÕÕÅb1…‹ŸËéêꪬ¬lnnöz½¡Pèð<«X,öâÅ‹¾¾>¤ èp0“ÉtåÊ•ÚÚÚD"q÷îÝõõõ\?˜Ãáðz½ápX“áÞÞ^$I$ïÞ½ÛÙÙéééq:~¿¿³³Ób±°¯èð0“Éd6›ƒÁ`0Ôº“Édëíí­¯¯ïéé©®®Î]QeYŽÇã¿ýöÛ½{÷ÚÚÚ´®TSÓH$277wTš(Š›››ýýý *BÀ؉Çã?^\\ÌÓŸ¶¸¸èv»ív{kk+ãò€ÏwueooïöíÛ“““Çö§÷ööf2fµŒ‘H$¢¼?­¶¶62¨ ¨!`Œ$ åwY®_¿ŽP> `Œ$“Éõ§qÜ;SP0FrÏß.¶Z­étš´`cÄf³)ÏL*•Ê/ŒcÄétž¨?Íét’Öl `Œøýþx<®pñèè¨ßï'­Ø@Àéìì”$IaÚÂÂBGGƒª€ƈÅb¹ÿ¾(ŠÇö§µµµ=x𠸸˜Ym@c§µµõÆn·;OšÛí¾yóf `\Áï"2Õßß_UUÕÒÒâñx‚Áàáþ´x<þòåËááa¤‹'k¢(655E£Ñ‘‘‘µµµÒÒÒóçÏûýþGagÈL‹¥»»»»»Û„ïä>ƒBÀ!`„0B!N¦«P3î|ª£×o\¸‚BÀAk:\Á!`„0B! €@ „€BÀ!`„0B! €@ „€BÀ!`„0B! €@ „€BÀ!`„0B! €ÐÿˆåÆC(¾3IEND®B`‚puzzles-20170606.272beef/icons/galaxies-48d8.png0000644000175000017500000000246613115373731020003 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá`"Ž>IDATHÇ–MlUÇsGˆJ@âÔ@4¶ãªˆ¦‰Ï„ž@BHµ›^ ¤ Á¡H½RAKáÂ6)!ri,'mšPÒ†TvR;­³ëÝ}ûÖ^{ã$ŽuâJ$$ĉcïí[;ßÐð;¬G#ý53oÞŒ_…¼O*è=&%ŽOì`§+ŸÀL€Åî ÜîbÜ.·ú{yL(>ðdµ‰Õj¶'Ž«1xÙ4޾zàÐQDÝö)5FÑD¤Ñ_U“­:²œeÆ:ÔÞd&¨V%£(ÇÌà,³P(`iŽù-‚˜qH q˜¼…E ‚ùÝ"0L 3J’ÒÿМö#(Ðܶ×@¤h#³†XËçók…?u±¯/ PÛŸ) 4¬p” G™!T—"üé×üJWêˬbÈ€ó8fŒU~ôyå³]ëže€l'¼y"¬˜³¢qŽyŽÑxöÊÙsÇб wC{c(‚Ê)a–aÉ)²ž¡¤ó?8AéZxÔ‘‚ùÕ8Ú¥qì¼d¿ Røé/PÔúï$ÒKÛÇ*ËAæÓMNX£ÇZ=—O/Hëö#ãVí.`5 ­){«¯ì¬aœ5Ž0Vœ*EÈlŽ ›ÆÂ®R"úñ¡Œ°]àøpöõ@®º$?`c.N×ü¾‹àt«9‚ÀZòô.œ¼d´•œÒá‘X³¸pÇ=!Eõ4%¹üúF‹æŠäZ¦O¿ß×vÝÓîjÿù ¿ï>ÙEî ·‰Ñx¹òœ"›®RZÒd™\SÎ<÷^má·?¹9X…ÎÀåg>t8)§œÎò2¶%‡ZötUì÷ùóè?ÿÊËZ%tEXtdate:create2017-06-06T01:31:21+01:00&µ¼n%tEXtdate:modify2017-06-06T01:31:21+01:00WèÒIEND®B`‚puzzles-20170606.272beef/icons/galaxies-48d4.png0000644000175000017500000000130313115373731017764 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA† 1è–_bKGDÿ‡Ì¿tIMEá`"Ž÷IDATHÇ}U‚à ãé<-?ãTAíÎm­µ"$fpøã®i>Þ>ÌÌ××8ó|ðœ¯E×ú0p6À ,>ÆXãD~Cóó˜=Æ16­" "öÅÿõ°÷µûoÃyÆÒ~`aà§õÐC È ¼ÿð€RÛÏqcVÜ ØÙã{•yè>Òtät!fhîY!™ì?ÖÆ6À–¢„†á¸p%Q™ˆž–‹(Â@ÐÑhâ×~©õ ¨ð\„ ;œËBç“V ÅV‰ñTÉ•i¦ºËýñà<ÅÖ)÷CÅŠF·˜"¬Ö‘Šhèç§ë”†èÀnc²ó·¶^j= yºè…E:ºZÇ‚WNa»X«¡ŠS’éšì%-Ne–>ܯN’?ö¥¨Jù‡¬a½k¨ãðÕ%,†pƒž¯IDATHÇ–MlUÇsGˆJ@âÔ@4¶ãªˆ¦‰Ï„ž@BHµ›^ ¤ Á¡H½RAKáÂ6)!ri,'mšPÒ†TvR;­³ëÝ}ûÖ^{ã$ŽuâJ$$ĉcïí[;ßÐð;¬G#ý53oÞŒ_…¼O*è=&%ŽOì`§+ŸÀL€Åî ÜîbÜ.·ú{yL(>ðdµ‰Õj¶'Ž«1xÙ4޾zàÐQDÝö)5FÑD¤Ñ_U“­:²œeÆ:ÔÞd&¨V%£(ÇÌà,³P(`iŽù-‚˜qH q˜¼…E ‚ùÝ"0L 3J’ÒÿМö#(Ðܶ×@¤h#³†XËçók…?u±¯/ PÛŸ) 4¬p” G™!T—"üé×üJWêˬbÈ€ó8fŒU~ôyå³]ëže€l'¼y"¬˜³¢qŽyŽÑxöÊÙsÇб wC{c(‚Ê)a–aÉ)²ž¡¤ó?8AéZxÔ‘‚ùÕ8Ú¥qì¼d¿ Røé/PÔúï$ÒKÛÇ*ËAæÓMNX£ÇZ=—O/Hëö#ãVí.`5 ­){«¯ì¬aœ5Ž0Vœ*EÈlŽ ›ÆÂ®R"úñ¡Œ°]àøpöõ@®º$?`c.N×ü¾‹àt«9‚ÀZòô.œ¼d´•œÒá‘X³¸pÇ=!Eõ4%¹üúF‹æŠäZ¦O¿ß×vÝÓîjÿù ¿ï>ÙEî ·‰Ñx¹òœ"›®RZÒd™\SÎ<÷^má·?¹9X…ÎÀåg>t8)§œÎò2¶%‡ZötUì÷ùóè?ÿÊËZ%tEXtdate:create2017-06-06T01:31:21+01:00&µ¼n%tEXtdate:modify2017-06-06T01:31:21+01:00WèÒIEND®B`‚puzzles-20170606.272beef/icons/galaxies-32d8.png0000644000175000017500000000202313115373731017761 0ustar simonsimon‰PNG  IHDR V%(gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá`"ŽIDAT8ËeR]OAí/òÅwâ+Äcƒʗ ´T %Q@C‚(ø"Á•£ PÂV­Xv»Û™™ÝRºKÛÝ,†-g»ˆDÏÃÝääÜ{Ï=L´ø1hñÄÑbI%ØA oøå_ø†‡òuðõ˜Dšïd³¶¶¶Ú*.÷‰«­ÍÍ-×[š›ot–Ä#>R·×õTlÉÐu=}qƒæ(57)+´ÿÙ2pÄ_:ã"„'HT²NM3»·z`š{´w mjuˆ1ÁË¥›y… «G Ù$—®Ó}¦°F³»´ïP!%¢ˆP&ìSf+lÑo °ªcœ ˆAN„:}óaW×ý¶©(¡i¥ÿ‚†¬!— ‚„ѫGOëpT•ô fka°²Ý‚ d2™Xó7Pð•Ëîm(èŸ-0% .Žz¨™ËÑŸëÿxÄvQÇãú’WàÙÄÀh<$™0‚²Lç¶œŸ•ˆyŒÐ[^ä ®ôÔÄä²wš ¢F«‚üø„@ ¦ªÑL{¾ÅÈ•P€róMOV"D]<÷ijw}¼õùFý®{:rÄíWiê}SûbUe¹ûÃGJ§ß\«÷xœM˜­9r9æ[^{žaùOÈÊ;!ði²þ¸Q®4?=¿â}¼fÑ "yf6î«§¿²fnóϱ¤(2z“s€kA‰Z}t,ËɆ)Ày„‘¤Ž1“)ØÇr³LJé«ÃÛIÃHEXh°6î=>CÊ‹¼æ-¾ÓzóVK‡ Š/êëï膋’CõÆBaOÞî¼ËP4Å0à´wt´wŸd>0O­,âÝ‚ÁÖKN†¡§42›ÜŠF0lÃ~Xû  4èíu‹%tEXtdate:create2017-06-06T01:31:21+01:00&µ¼n%tEXtdate:modify2017-06-06T01:31:21+01:00WèÒIEND®B`‚puzzles-20170606.272beef/icons/galaxies-32d4.png0000644000175000017500000000076113115373731017764 0ustar simonsimon‰PNG  IHDR V%(gAMA† 1è–_bKGDÿ‡Ì¿tIMEá`"Ž%IDAT8ËmS‚à ãé<-?c²»¹«@àùK[¦Þë߆Ár²2´|9#ŽÈç^Í€‡Ñ??£cè“‚§ SÖ¯ƒpzˆõÆ~„ Ÿç°@ÄB˜Ãús0™Ú¤T*L’˦Žö” y@ŒW±å±Z0ÉÐaL´£…Š!±Œ}Øtˆ%úWPYİx¡€©E•¶ùåSXÒãh©Ç»9ºQJTFrŒd1JzG7mM&”¡=„ª¤3*DH¯”¾}JP»’Ü~˜:ûVeªYI–?µ²)‰¯¦eòÖCWIÖÊ^§Üb½~pܶP±@€¶N»|yè §Z§\4mnË¿~PâË b)*/ÉÖAöòVyÏÍÒ-Þdóífü œÉT)Ì%tEXtdate:create2017-06-06T01:31:21+01:00&µ¼n%tEXtdate:modify2017-06-06T01:31:21+01:00WèÒIEND®B`‚puzzles-20170606.272beef/icons/galaxies-32d24.png0000644000175000017500000000202313115373731020037 0ustar simonsimon‰PNG  IHDR V%(gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá`"ŽIDAT8ËeR]OAí/òÅwâ+Äcƒʗ ´T %Q@C‚(ø"Á•£ PÂV­Xv»Û™™ÝRºKÛÝ,†-g»ˆDÏÃÝääÜ{Ï=L´ø1hñÄÑbI%ØA oøå_ø†‡òuðõ˜Dšïd³¶¶¶Ú*.÷‰«­ÍÍ-×[š›ot–Ä#>R·×õTlÉÐu=}qƒæ(57)+´ÿÙ2pÄ_:ã"„'HT²NM3»·z`š{´w mjuˆ1ÁË¥›y… «G Ù$—®Ó}¦°F³»´ïP!%¢ˆP&ìSf+lÑo °ªcœ ˆAN„:}óaW×ý¶©(¡i¥ÿ‚†¬!— ‚„ѫGOëpT•ô fka°²Ý‚ d2™Xó7Pð•Ëîm(èŸ-0% .Žz¨™ËÑŸëÿxÄvQÇãú’WàÙÄÀh<$™0‚²Lç¶œŸ•ˆyŒÐ[^ä ®ôÔÄä²wš ¢F«‚üø„@ ¦ªÑL{¾ÅÈ•P€róMOV"D]<÷ijw}¼õùFý®{:rÄíWiê}SûbUe¹ûÃGJ§ß\«÷xœM˜­9r9æ[^{žaùOÈÊ;!ði²þ¸Q®4?=¿â}¼fÑ "yf6î«§¿²fnóϱ¤(2z“s€kA‰Z}t,ËɆ)Ày„‘¤Ž1“)ØÇr³LJé«ÃÛIÃHEXh°6î=>CÊ‹¼æ-¾ÓzóVK‡ Š/êëï膋’CõÆBaOÞî¼ËP4Å0à´wt´wŸd>0O­,âÝ‚ÁÖKN†¡§42›ÜŠF0lÃ~Xû  4èíu‹%tEXtdate:create2017-06-06T01:31:21+01:00&µ¼n%tEXtdate:modify2017-06-06T01:31:21+01:00WèÒIEND®B`‚puzzles-20170606.272beef/icons/galaxies-16d8.png0000644000175000017500000000100013115373731017755 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá`"ŽIDATÓ-ßKÂ@€ïÿî¡§^¢0%¬(‰Æ¶+–Z[Û9p¦)5Ý»ÛÏ[“0Ä’ ) ×}ïß÷ŒT£«—œ ´¡ˆ‚¨¬«ƒnç¶·Mz>cI6…Óâ{Y¬ê!ÐDæ¼ôxR,?ŸçJ4!ÙNx¶+WÐËcÓš”c‡Œ™a-Þ>¸"ç8ʲ˜dèºX-Â?ÅO¤ÚCd–­«&áÑ|xÄÐJ=«ÝÚ‰S[˜Õ»”°ÉXŠ^Ëû{®/êl`êVôý™½&CáæµQ½k·x’ûƒq–ø®ñ‘žÜ ñ]œ£Nñó#¯T®nöƒ^I>:ecJc8˜†ïé/k^Å!á\ôU%tEXtdate:create2017-06-06T01:31:21+01:00&µ¼n%tEXtdate:modify2017-06-06T01:31:21+01:00WèÒIEND®B`‚puzzles-20170606.272beef/icons/galaxies-16d4.png0000644000175000017500000000045413115373731017765 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA† 1è–_bKGDÿ‡Ì¿tIMEá`"Ž`IDATÓMO‰ 1rtFs3NÆ3ÚÆÄêŸa¢æ…<¥ê¦¼¹Öœ &_”î°Qå¦mA•†pâ‰]KÂ3[cŒÇ%ð´JÇJÈãèÈÒZëÀéð-R™¯|ȉûdBÅ Kª²%tEXtdate:create2017-06-06T01:31:21+01:00&µ¼n%tEXtdate:modify2017-06-06T01:31:21+01:00WèÒIEND®B`‚puzzles-20170606.272beef/icons/galaxies-16d24.png0000644000175000017500000000100013115373731020033 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá`"ŽIDATÓ-ßKÂ@€ïÿî¡§^¢0%¬(‰Æ¶+–Z[Û9p¦)5Ý»ÛÏ[“0Ä’ ) ×}ïß÷ŒT£«—œ ´¡ˆ‚¨¬«ƒnç¶·Mz>cI6…Óâ{Y¬ê!ÐDæ¼ôxR,?ŸçJ4!ÙNx¶+WÐËcÓš”c‡Œ™a-Þ>¸"ç8ʲ˜dèºX-Â?ÅO¤ÚCd–­«&áÑ|xÄÐJ=«ÝÚ‰S[˜Õ»”°ÉXŠ^Ëû{®/êl`êVôý™½&CáæµQ½k·x’ûƒq–ø®ñ‘žÜ ñ]œ£Nñó#¯T®nöƒ^I>:ecJc8˜†ïé/k^Å!á\ôU%tEXtdate:create2017-06-06T01:31:21+01:00&µ¼n%tEXtdate:modify2017-06-06T01:31:21+01:00WèÒIEND®B`‚puzzles-20170606.272beef/icons/flood-web.png0000644000175000017500000000664713115373717017410 0ustar simonsimon‰PNG  IHDR––³cæµgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEá áoí «IDATxÚí_Œ]Ç]Ç?¿ùsïÝ»þÛ¸nŒ“"’Њ %‚6 ¨ÿ(}ˆúPÚ¾ ‚"ùÈC^¨„ â…"( BH´UBúàô¥‚VB‰¨êØikÙnÜ;ì$޽׻Þ{fæÇÃÙµ×Þ»NÎܽìN2Ÿ‡Hë“sîœùœ™s¯Î÷üFŽ?N¥dÌV7 2-Uañ¸þ‘­nRå PÕµÞ¨0ÆcL)U—Û U5ƈˆµv­k E$ÆxâĉápØï÷U«BP”dš{Œ¤$)îZŠZìh4 \;¯…1ÆápxøðácG ú$Íkó[ ã܎ņ&‘wQ+ô,sŽ´yÀ³üàƒ_ü³/>ûì³k§Éëªj¯×;uòÄwµ½»c“ÿ¡o Dh4ý‰9öz‚vîgxù ÿ»ŒÜEæÔ¦øožiÞû¾÷ZkC“'ÒUŒ¦%é¿ïO}oy)ŠØ­îÄ­CUŒÐœòð¿ø5ýÔ/Já:N†MÄïæoç·¿ÁàûŒ}VK"ÖÚæŽÆ,Møøõ Iš´‰ËKŒ—ÂÛ{ªÇ8B ‹°@u¾ŸÅ„7„%Pb :ˆÝ§¶€±†@Ò´~£›¼ˆˆ{[BTÄÖ€ÁlG…IA0­3²a—¿1ˆ¯?í‹§*,žª°xªÂâ© ‹§*,žª°xªÂâ© ‹§*,žª°xªÂâ© ‹§*,žª°xªÂ7…j›ƒê¾ãú?¦=Êd?üÿ`SrúF]ðf[béüÀ] ˜Õ½Öþ·ÛQn¶qû*T)Ž{v Bˆš°Æô¦hˆ@/¨d9;^ MÄ¢‚ cD2ƒ2th3qãvT¨|Ͻrö±ù¤˜=šš¼ãˆ8Õ‹{nýÄ]8Ü,‘œ“m’Âø7¾ÎÃ_ÏÏ‘F–÷LÑ'^Y‚û'lÚŽ ÛóN€?ùðå]½&¤Î“jLì¸?~‚ç—¯!k2UŒÝqðgÿ:*ª¹‰LÅ´ñ™˜Ùª©?ØsúØoiZ^¿u»*\åádßNÑØ¹÷š„ßÅ?~ž“=+ÆÍ¸ów¦¿+ç_€ÆÁ¼=}ì'NHÛ]a3RT›<…Šé¾Ì(͕̙|³PÖX˜œDÞî ½‹Ï¸‚ìæ|§“àÝ<Ôˆ°QÔß…ÅSOUXšöÝ¯à˜Ø;äå‹XGÚB‹šÄš¥…Ó£ O;ÔIå›Þ©?Ø ¯‰™àkóŠRóü±Ï¦xy¥äz,7ö"¨²ë[©P5:g.ÿæÙ<"¦§iœwï=4bë7Ídö )ú?ý¨ùÜúŽSHH쟗¯‡‹g<ûË9éYö  <¶,À$D±}xNüœÑŒK2Â~ñ?IsyÒÖÙÅŸšù^bg³OÕw¬ãf;»ÃÈ\w… +§·•µ@5*Ü¢M?+ÖA”në3L°i‚ˆÆÎ3©F+ÁÙÙ¼I²5Ìè\f¨°ýÙýM’Õ·OVwÏ<ÈìN,»Crvó]êOûâ© ‹§*,žª°xªÂâ© ‹§*,žª°xªÂâ© ‹§*,žª°xªÂâ© ‹§*,ž>/Œ Mêüˆ,$\$&€6ʘ‘£ à¯>3W4…-¹\UU&  >«T»ñƒßÙ(ÀÙ9Øe½Ò5x! vbç$g@³ê΂D0Òp"™åc˜ÜùJ½ÞÀY1&ç8°È™™( _z‚{&.íUz–/|4àr z†ßyòÛÒ”½¨­ ^ÎP)fÀåÓj‚Í ^ …çá&mÝ|… ŠÙ{ëGž»²xêœÍªŸ¥HŸæ,<“n—l‡â4½@oñÊmç^¥£BEIÄ3œ¹Þ WBžƒ“–ÿøPÒ\‡~‡±“fáŒBELïÎ6WWÏìz€üÀ½ô£ùá替éöíh2Ëèí´¿üWñ䩟ûœùòkéUÛñduø%^ù}>ñ觑н¿ðÂߤôÈ ¾A3è¸KÄZšŸ‚¥ gõu¦YÙ)2M!$׌#FM÷@~ˆx _Ôs zÁÒíž¼ªðÕ•;4ÝO©m„;4„^æ÷ÙxøÎJa^ýÖŒˆYYD×0x›ukK1#k±¦£BPƒmÅ·{úÜþj¿ÂˆÏý^´²ÿÍ6V ¦*,žª°xªÂâ© ‹§*,žª°xªÂâ© ‹§*,žª°xªÂâ© ‹§*,žª°x¶û²[í2®+Ç­- §¨¶Ž­«‡ÑkÿÒ½ý7üñ¶ZË—ö¹¯Cº¯ë+¶-¾$ŽžÃw}äÛ>µoã›S;åí¶–¯ˆ^»ì=Œ»ggBâVµ!F…KrqÁ,d/,n™‰K–h9¯9Ù™Âh ¯zf­å‘ýžÐ”¶~¡&àg¾Ôd¯å»<òùøñ)Ûr(r(¿ž‹Œß_ N=4ðK6mG…"6æ÷¾ÿöŸÿÚ aõrÏ 1¶-qQ/œyú¯ÀëtÎßxü+ò•þí÷~YR5 ÕÕÔì=ùÔg4]Y¿u;*ÑDþ¶áîÏne+TÅÊ8œ?óô!Þ‡ìâiܾ÷|Ò¤AÆå¤ç†öäSïÐ4¡ÖòöT I›å°•ÅÔTÅøÐöÚÕbWµbX&æTxV ι–¯d¿±IŸ¯bu0E ±s+)B'Æ ¿Å¥®åûV¦*,žª°xªÂâ© ‹§*,žª°xªÂâ© ‹§*,žª°xªÂâ© ‹§*,žª°x6xü¥ª M ’zPqÈ—ˆ&Õ€Hþ"híú—"SUPi¹ZÎ/¯ðL» œ6)y4ã‘oì²–o{ÚFzs(¾-þ’×{1¦xê.ÖxßËÜy )³ë¯­é'!¿ðŒZ€ÞÀ›dU»w©?Ç›^ËWU¬'œ}ñûÿ0_”¼a$6é®ý¿:¿çîR籨ÉX³´púõ—«ìМ…7[Œ°4·ã޽J±{3ZÚièqô2\êа[ùO”æ¥ã'©—ÚçÄLˆ1¬¿¨ÔÈ^ûŸSǘÙwbz:´Ã·Ü›Øõ:P’qfñâÓ?>ñ»}ïU3³{FÜ•&ìzçÇn¹í¡£äÝø#@ÿ«ø¯fÎèc3~áÔ£y'µµ|ûë7­Sh`¤Ü‰œêÉb̉ŠXdÉë-c’ÍÉ?_מ;Ó;p«,»×`k˜Ÿ·ùpøÖ9kirÛÑ.Dü÷Ÿæ×ïc4Âu…Mdç.þòßyôqz¯û¦/9Qà€ ïiMØ8Q‘`PÆÚç–~ûþÁêR®yõI@¯7iú½Î N "L¹2lOà:¦í¿•^î5ê²î¦Ý ¾Æ/ïŽi×AŸº 3@Úý½M®!&ãš¾é‡ÞôöýÇ&f?·Çš¼íòÂÓ¾Ð2›×bêOûâ© ‹§*,žª°xªÂâ© ‹§*,žª°xªÂâ© ‹§*,žª°xªÂâ© ‹§*,žBˆÀjò® veGÕ„¢»–éP ª®-àÕÆwbìüÔ>F¼_³–¯Æî׫¢®Í´ë‡Ô½zšâ•tµ?]V ¶p³Å|oT¨¨±Ç×}½8ű÷n05V:&UÕ÷é,ବí¬0%À:lÏÏ A»75u¼›Wv‹3ØŽ—AJ°7‹s¨dÆ®ñµvÒ¦ëûNTÒ q„æ®&6¹é? ,súØçOûsÈÈ’¶cy¸çž%çTsŠ^á\óâ‹Ä¥oëkwd5!@óÈ?ñ{ÿœ3~\XºÍ!ôáYâ}Œ\§ÐZ»xyñžûîy×þwÍ¥¹Ô=ñ¸ÒjAî7)-iZÎLoªŠñÆG£”Rç!Ø’÷Þ+Ά%愈qîÁņ¦ûd¾Ò ¥ï˜³¤Q~Ì{ñ§/Þÿàý¬–‚ºÊ£pnnî ô…ùùyUÍ<íÊ,I)9çB¸ö=EŽ?~õU5ƈHÓ4Õßv£µãœ»!¢}Ý(UM)Sll;ÚAB¸ÙDºö­”BmÅSÏÿ;ä½Ás,ä%tEXtdate:create2017-06-06T01:31:11+01:00¨:»%tEXtdate:modify2017-06-06T01:31:11+01:00Ùg1IEND®B`‚puzzles-20170606.272beef/icons/flood-ibase4.png0000644000175000017500000000076413115373730017767 0ustar simonsimon‰PNG  IHDRààèwÒgAMA† 1è–_PLTEÀÀÀÿÿÿÿÿÿÿÿ€€Fæí›bKGDÿ-ÞtIMEálgIDATxÚíÚ½ Â0€ÑÀ0„Ÿ>l€˜‰(€†õ©}VäÄ„ð¾òÐQLÓH’4VéËåvä6_ÛSQÝî’tÞß’®@ @ ø`ׯ6s^º®ÕãÈzþ@ ÎÌ®_¹/Øw]«ÆI÷ß@ óûŸçPûáÐàLj∯¤gañ•,@ þ$X}]« æêâÃózß@ @à4Á¸^Åô=Ï®kÕÁÜHâÊ;Ï@ Ày€¥×uÅûáØàb=vÝ‹ $é‡zÒ” æF6@H%tEXtdate:create2017-06-06T01:31:20+01:00€Â·Ú%tEXtdate:modify2017-06-06T01:31:20+01:00ñŸfIEND®B`‚puzzles-20170606.272beef/icons/flood-ibase.png0000644000175000017500000000202613115373730017674 0ustar simonsimon‰PNG  IHDRàà•Oý¶bKGDÿÿÿ ½§“ËIDATxœíܱQc†QÉò 4€ „ zX§Ô£žì6j¨†„áÀ>ª“Ÿât:-üäöx<޾ ü¿ƒ’&PÒJš@I(i%M ¤ ”4’&PÒJš@Iû ¾~XñéQÓIEND®B`‚puzzles-20170606.272beef/icons/flood-base.png0000644000175000017500000000202613115373717017530 0ustar simonsimon‰PNG  IHDRàà•Oý¶bKGDÿÿÿ ½§“ËIDATxœíܱQc†QÉò 4€ „ zX§Ô£žì6j¨†„áÀ>ª“Ÿât:-üäöx<޾ ü¿ƒ’&PÒJš@I(i%M ¤ ”4’&PÒJš@Iû ¾~XñéQÓIEND®B`‚puzzles-20170606.272beef/icons/flood-48d8.png0000644000175000017500000000346713115373730017312 0ustar simonsimon‰PNG  IHDR00`Ü µgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<PLTEÔÔÔÖÖÙÙ×ÕÕÙÕÒÑÌÒÐÅÎÑÒÄÍÕÊÏÕÕÅÕRUj7C…=FƒTC=…X+eK,*y,-„-téßé$Fÿ-Iÿ3Lþ@ÿtE2þ„ü~ª\Üþÿöpšp9Mþ9Rÿ§\î1Iõ5Qÿãÿ‹ôƒ¨`(<É$7ºY74Êi·[zC¦ºpŽpéàéáaÑgÛt“I"<Ü9Õ+4Õ+9×$Évz—èçâmB:²Z%J÷çæß;Ý#;íx|šçæá)CüeB;$MÿS š¢l(8»]+p>m;åéçö‹þ³BÜ(8¨ášppßäê)3¨Üíáéé¾w*˜%5²#t•§ ‡wt9êRzr‘j×ÂÍp•pj¦Œ†»uÀƒ#`œ±‚´p·_¤…§0*H9i88h. *34q1i!H A\Slt{†5Dÿ y2ª13ä4;ÿ+5å4©$;ª":§0Gñ V2µª#>þbg8íìÞÜàßœ›4Ýj90ògÙmms<ýý²²,÷¦¦:úþtìnPáãéÒÏÒk•lˆˆuššpš…p«²«áßáßßêÿÿÿ¨œ‰JbKGD²­jÏètIMEálgIDATHÇu–CeÇï—+Ô u»ÃÃÝÆ½r7†0BÇ`¡“56t™$ÖµTJ°"±URVV’¹Ô‚Y¥ý¢©ü‡=ÏûÞÝî¶ñ…ÛöÞû~îû>Ïûã^ŽñœÀq"~óøeI 5ìbwy®‘§Ï §ÄžŠ?øÍ%0‰¢È‰¼`?TÚ²™|O žl¢²›óÒÖmÛkÛSO£žiÞÚ¹ËϺÈoÙÙ+ZVZv«­­­êž ¦i¡p›Ÿ €¬+D ØKö6¿(…€j9hÀc—<€azÇ!oÅàLb*DÑ- CU£ÔÆ xð{_•AîXOOOìÙÞý ÞqV[èîK$ýI‚Åäs¨ä èà¡Ôa‰Íw—ôÀôBíH'­D):„Àÿó©ŒãàÔ(Ä™öæ z˜Ímб®’Ͱöõ€ŠÄÝZeS#œÇ@GZŽªÑhTíôyT‹ÀÀöu޾p ôâñd £/;1¶õ¤äqèJ`~^>ö ªðªk(Ç'è½S§9÷Ô ] ì}ÔCVÌ3¯á­×Ou¦7TÈ@‚ š%óÌNŠ®¹dÔ2M?\UWZÑÁ ®‰ —ípÖ´ =étzÏñs…BáÜùÉ7l¾y¡P˜*LMSÑÉ’1 J^ìîÅbýo½ýèüÄÌÌÌÄ…w#Á`äÒl¼fj€½NòC0õ`ò]~¯X,¾ÿíßT„-Ñ8nPvZ#;SãÃâ•+s¹X¢q ó*xWœÌÕèà«_Dm‡¢„Ü»† tz«jú㹫W?¹ìîR¸° óÓÏP×>G}ñåõùùùë_Ýøtãæa®~›‘MØóò²læMPé|´vë¶^*•ìõ ÔíKŠnÌíaíÖAÓ0MX¢×`_rëŽí`š¸DÝ€¡È†½3Š¡8at¸M ™\dAa[‰½õè>²¦íð-0ú“®}·°°¸¸ø=m?:N…&f釥åå奓  É›,hQljŽá¯w2Dî®”,ÿTþùÞî?ø¥¯ïÁ€gòñbÓj¼î¨ßî¶à vì †ÜS£ ˜¬T½æ…gYªÄð:°7ÊÍr`@(D $‰®ünÕ ] ÙðþmjÖÚÛ#ÚÒ¡#Ùlö÷•Õr¹¼ú-üyÿ¯µµµÖ¿/i‘öpp¶b½wîzÔ:Jår¹ÔãPYaú_Ôô,Ö?úoÝ>QTüþ8h$“ÉŒd*ëë• +œFU š¬WÏ’äóA@>Îç³Îöo‰{(Áç³kXØé9ÊÐÓ_sÏ>½¸îð.˜w×`Aøƒ›Z—..ûó%tEXtdate:create2017-06-06T01:31:20+01:00€Â·Ú%tEXtdate:modify2017-06-06T01:31:20+01:00ñŸfIEND®B`‚puzzles-20170606.272beef/icons/flood-48d4.png0000644000175000017500000000143513115373730017277 0ustar simonsimon‰PNG  IHDR00¥,ä´gAMA† 1è–_*PLTEÀÀÀ€€€ÿÿÿ€€€€€€€€€ÿÿÿÿÿËî!zbKGDf |dtIMEálgIDAT8Ëu”MoÓ0ǽRVŽÉÖvR¥}‚ÉK'OLêX€2àÖVˆ©RKÛ°qB  ‰Ãzà-§)V‡J9ùºË¿7pówá‰ý4ŽÛÍ•¢Ô¿üÿöób2=œä‘#dŽî,ºÔ{¾á-U½%oÃïÖ×ëÇǹ6²Æ)çü¡b|° v™@8$óð/šµ"$o+¾"xvõâs8ÁH@ìs?áTás3½^?£x cÙI¿m`ÜE«p“óqFAR°9m•¿ÜjA)n¿y´Ój–Z˜š“†·¯×þXÊ¿øõ–”²£¬¾hð€­`F¡#O· xg)ÀêZy ¬0YãgªXóÇ~©YjFl-: [ACXTŒyÜ*ú²-÷Dš\}†Èƒ €Ížê’L=ÆÕ ø"eû €¡UPôA±¢º$[ ¬¬ö­N„zÄ`ÕÅ5LÚ“š¿ÿ7¸›‚Uë´·Øc‡ÕWG÷ïÑêëS_²jŽã‡ÑBǤEü²újÒ©WY"|`µŽ3´‚ RÊ–áBÆ“ùðQô(c5’ââ\k7é+8±>x.c®Fé°]xžcvAq¢OÔDŽûË(«¹`Swû€ºªG÷÷fŒ(ò °ÑS­8å±CBú5·ëtÝ—NÛqË®Stæ‹n  ^C9¼–*¤S¹ÿ}€GÔ(ðPã%tEXtdate:create2017-06-06T01:31:20+01:00€Â·Ú%tEXtdate:modify2017-06-06T01:31:20+01:00ñŸfIEND®B`‚puzzles-20170606.272beef/icons/flood-48d24.png0000644000175000017500000000476113115373730017366 0ustar simonsimon‰PNG  IHDR00Ø`nÐgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEálgõIDATXÃÍ™MŒeÇUÇÿSußëîé™îcg&aÇ(J&ˆ•-…V^yDˆEV„±A H%^D l"b!‘ùŠDćPŒY–Ip¢ 6Îôô÷t÷û¨:‡Å}Ÿ=Ï=Ó6ˆ”^·î}¯nÕ¿þuêüÏ9W7nÜàû©Ùÿ7€ã-ÏÞHö¿QTSÌ~A5Ð|·ªˆi·<Ó;j9$ŽŽ?ñÎÐ(†œ;f1yÐM¬öˆ:ž!TVŠuLãIó„›Zíó¿ûæí‡»y¼ ÓfЫö^¾üøÅ~m¤ˆ ›x}—ü0Ý5¢¤”¶w¶Ÿ¹ôÌ3{fsw3§<˽ïm_Ú¶_Y²ðxW$eÅÆ@O¦?ý¥k¯–¾ey r—?þ7¾ôIòû)F&—²}}»‰&ˆã[äÄ’ÑmÜãÝXRd£[e!D(…@„A``Ž™áhÞBæy´‹wÅ""œÁ¨Â5ú„ƒ Ç1&Ü,tß8ÜeeJó·D€S]2ª“¨THã‹w Ȳé.뱡%X!Y¤ÜÖŒ½Jš¹˜êÔ€$ö7¿6lJÍB²³>jy™PMâ»[¼ðuö &>p©º+YøÐY`U^ã„‘Â<ùÀ#böÙwtÊBÂ4Z±{ ;A„D V=ßÞ-lI®1ÉÉ" ­FiÂÜý1œ"&£e”Âu*?$±3°ê£™³|³G/‰GA5XmäûÃ$m'ùx 9±™¬J³1ÁÛ ·lû›_{|ø³ž]-ÅF¥´õê7~ï5úr‡3âÅ#škÄ ˜¢Z“ößúÊÞøÌz³^£9ç[«OüdMÝÉÃ'0e¸ûË¿òá«ÉûÕÁQ‡?|Ÿ¹I(THpVw´õÒß•äƒ@…}H÷H©VÎ^øèoì}«îâ$ßé/?õèO<ö‰—w†–äîœ[âWyò/þóöc(H°C:Ï‘7öP"ª8üQ—O~•ô^¯}¹¡lðééôpÁ:‘¡ÀòòÅ›,4™w{öð`鱇¨%Q´Â£ÿÍ¿òÁËvµç=a‰èЬ±z.’^D.)¸êù 8 Ê9xyÎŽîµee8c æÃ¡E †ø wÒ(Žq0ˆ¾°L ÉNœ*¼õÎÞÞŠZÇzʈqN9ÕþIq©¸JÓO{;¶÷q6z|4ÈüÅ}Z„Q !å1GId)Ku¢ Ux9¨ÐîR‹B…Óª¡sþiócOÿõ«–…G­#íüàðû¯ÖgJÔ^Ú»<üóÇ{!A^âö¿§õO|¼ûÀ9/qÝH?vžN™ ; 6•Е_¸9!dcå}DŒ=JŽt[·?òû7Ÿ}ƒ*RPD»ÞüȳÏvW®øÀ…åÌêÁNǯ»†ÇsûÓ`B^Wæy'úÒ¤†à¨ŸTH…TˆŒ*¥SRWEnJ·„ÅiŽýâ–üîïfMShµ¦æiòe E&Pd0µ¡bê6þ/S™ ¤»’¹¨ÇU>ÚÌu¦Û8NU  œ DTäAŽ('µ¤&‘Sž­~¸-§c­v׿3×^ä­2’åœð”åDNYÒÂ- ©é÷n~ïàO–»>)6Dµõ§sç\Ä4ÁÚ¿ýù[¨Ã¸ªQݖןÎÍê¨[@‡ôm:…@ë‘Ïâ/ÖÍýç;·òáÑäfcc£”;š© Œ…U;HîÂÌžzßSOüð»wvÛýÑä]Gë«ëèL¥% M/ÂGÆHQ}i0H“Œ<‚œiò±nT–ÕæºÝáMÛÍÌýpÿ`_ºK\…6w7ç„® b¦B0j{fÓ"SËS,¨$ïÚÌš¬æ›ÉZnØP[Kÿ?mé^¾ïÞýÆ@“_TïÀ²%tEXtdate:create2017-06-06T01:31:20+01:00€Â·Ú%tEXtdate:modify2017-06-06T01:31:20+01:00ñŸfIEND®B`‚puzzles-20170606.272beef/icons/flood-32d8.png0000644000175000017500000000267113115373730017277 0ustar simonsimon‰PNG  IHDR D¤ŠÆgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<þPLTEÓÔÓÕÕÙÔÙÔÙÖÔÖÕÌÖÔÇÉÑÚÇÐÛÙÊÙÚÇÚ^cˆAM¤HS£GR£AQ«VAe²t1¥k1–`02Œ2/¨01£1&¢&a–aáØá$Fÿ-Gÿ4CÿhIdþƒû}àlÊþCµCäÓä8Pü4Mþ8Mø+Jÿö~Üm È÷6Qþ&IÿÿŠ÷†-BÛ.?È(DÆ1IöÑgÅgÎkµY  ÓÇ B£BjHUér)?Ô,Eë$:Û&Cà&=à/>Þ.=à$4ãW]¨tLUÓkZfµàÞÒ×Ï×DÿÒq&RÿWfºáàÔ)AØxMTn)¾*¶+™#_XwUo MwNhÜâÞßsþÓÈöµBCÓää¶#5°8»§à£BB`>F¯YX{nšk“džo:ۢ䆷ŠÁ†F¯~Ɔ«{½ÒÒäC=ŒpGL:ŽDšA¤;%ÒÊʲ2S {PJiYYögöÛØˆOž±Ë>»ßϹg;w†åŽ8N` 2÷‘yyÇòò5MFÀüñZ­V:•ádaQqñ©’Ó¥gÊt`«¥hZOg‰20Fæl¹Édª0K@]É*²X,0pcc­6Ëê<‚Yøã 6» T@«5‡ÓébY®Ð][Wßàñ–7ê@FxŸßê¯àª)Ð ¶„ZZÛÕA"ø°±µ êb!.ÍÊ`áÂŒÝèØ‰©Ñ¡f (®ÓÙº2×ÝÝÙÓ‹Ë6æëëóïèT¦ CC/ c àõâñ¸( 4Ð|9~%~õš’9¬ŒÑžäÀz ÓÓ¯:Ä+ÄH‡t!G½ÕÝ5(ŠâèXŠÕ\¿1.Š7Õ%8Ü Ü²º­·'§¦ï̈3£³sO£™Ì¼„¨0R%¿ê©ùûd¹Í¥l€{ø(Üç{¼¼üäéÊÊʳç/VW_®‘Ye±4ÅóÜ+´®ß€å7_¿Ñ'¶2e)&yLl€û¦­gÚ„f•y™H;8Q%'·I¾mm…ä~Á`PÞÍmÎÍŽ½µ¶õbÞQRîõ4„‹ÿü˜ü$°.®°½¶nb¶Ü6<&®)Co b;©T*)È›–aüeÛãù¥ÉB•;©Ï©d Á¶·Ù™uWKh:í ] ƒÑÈ|Q¬£l·bo»-ÙúúmÿûHOÏÏ¢ƒƒ_Û{»¿¥¯wÍl^2Ñèá(ʼnµ? 3H'}ÜFÊ?¸’F ‡Cºƒc²þÄ`ĺ)¯ñ%tEXtdate:create2017-06-06T01:31:20+01:00€Â·Ú%tEXtdate:modify2017-06-06T01:31:20+01:00ñŸfIEND®B`‚puzzles-20170606.272beef/icons/flood-32d4.png0000644000175000017500000000131013115373730017260 0ustar simonsimon‰PNG  IHDR TgÇgAMA† 1è–_-PLTEÀÀÀÿÿÿ€€€ÿ€€€€€€€€ÿÿÿÿÿÿÿÿ€ вêbKGDÿ-ÞtIMEálgÄIDAT(ÏROkA»“XüsXK?@²¯5$^†÷uë 5KêEB¥Xo)ä‹6doŠž¼HPBæ0ËÎQ„æ" ~„~=ù-|#ËÀÌ›ß{¿?;A"@%·!’MLÃ!í¦éÑÑ«‹Ó÷oÚÐdbDÍÌYýŹwÐÐ^SÎþ–>4¥s-ˆ5 DÉêÔ ç¶¥!5ÝX–¡%Î)ÏggR,¨ J‡ÛÚH™‘Xh™=w̹ÌѤ¹--J«¬6©P¡§Ç#rö-÷Z1²ÐÍËNUI?ÿ²@y,ÍÚN(Ç|`íë€xQ—Ö"“êDÌiÏkI¡jL6SØ!ž­Ï62£Ï#k…Vtûårü¼7©Ü'aaüIÙªz48±ç !fÕýÚì]†B$¼ò÷ÌúÏÕ‰];7 æ<7ß^àøÎéù÷§a†xc#~è>(¯$Áé»î‡VÁ‹D†ìµé.½ä!¼W„è‘KÍߩ؎ˆ¤—ã½l9Gú懲ºSÙ lÇ9$Ý]RÑ3³º ØwçsÍÇ«EPºíœæìóÂSVýÿs[»ÏZ‹ëéµé×›O¢DBQ$yÉ?l€œ/¦*Äd%tEXtdate:create2017-06-06T01:31:20+01:00€Â·Ú%tEXtdate:modify2017-06-06T01:31:20+01:00ñŸfIEND®B`‚puzzles-20170606.272beef/icons/flood-32d24.png0000644000175000017500000000350713115373730017354 0ustar simonsimon‰PNG  IHDR üí£gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEálgKIDATHÇ•–Ol]GÆçÌÜûÞ³_§ùÓ[Ū(¥MB›5…,Ú¸BHeK6l*•Ê?eÓEEÅ!v,JÄBH° (, ¨RE‘ÚX.MCL"7m¿÷üÞ»wæÏŽÄDaWw4£ùæ|ßùæ™››@Aù?‡ƒØèß!)Èú’ GSa€÷7ÖïâpÁjÚKuK1GT™"5®.&¹•s™‰ Âà‡?~máÒt£t÷»<Þ‡ÖºßÿìÔ[C+‚]ïrb?išPk×»GºG^:úÒJ^‰ øàâÕ© «_m&s»+¢‚¤¥?¡øò½ï¥c™Î_à…§¨SH1OŸœŽuôè#ŠˆfA³0Û"üÑ€ ÖT‚ NMˆxÍh Ĭë]pÇsu¿5QõMÒ¸ã¨9ˆÓ H™Fp°`j7üáˆTÝ3ž.‰DÀÝãø£[îDåZ/¾ó!=+›….\‚9h ½@èËb`\îÄ–S8ªÇ_þÌo®§¸­Lï~Ä·æÚ“X’1e¾øÁ—æ¿'á¡ð*èvî}oäÙ%Y wŽ€l´[²ë^¶WR4äjí,¬§‘ÓhílíÜÐ ‚x“Кp3$n à#ûIQƒdcˆ×îÕÍûÌóºþ8Jq©K1™j+‘岕«Ö0ŽUÐÀ[·n½áMQ:A“Ä;™APñ-LT«î™§å;“c¥e¶Jξù§¨µ”3}˜^OØÔré/>ýü^¯ëêå~óèT¿+Þ‹7ßÇ] ]ûþ¡ßÍìºsêCfç055öÀO¦ogÔE¥Ê«Çû„U)ĘÓÉî쪖Ñ;[RD]CëÚ­Â<;nŠ‚;`l|×ÕuÅ=I@´ÖrÊr³ÑnE TàÞ@504¨F@Y?G$zÆ­°,|+£ùZļ¿HªTx‹ó}æ Ã|ýÎhx^)ì˜j³ß?÷/÷ÝÐ…Wáãà·E܈ãŸ~aá]þ£¼œ¶?3õõ/|ñÔR(³_â‰_¾µ‡2ý!ãüìüm€6ÅÎ;Ïþ‚ú³ÄާÈìß9ºÌÕx;EŽÆV{Ç~ H®ª°;NÌLQWR4Ânf¦ùd¢;`ÇBF” À $ˆp2Ä-5p, bžCFRW¡€TyM=A¦2,ÄP*h u¤"µ³ØE^/Ÿî j”dÊ JRËsM‚T¸a”€P€Ç x¿›×Ô\Æ þ±üäñ¿ô†>Q†|y•ù¥y.šÔV«ÉÁÙÇÉÉcdù:­WgÇOí U^Jƒf˜ò¯U2Ô;8ZÂåí/þº~QÏ„’æ“tM¡ÿ}àÏoü诒ԣsÎùÊ+ÛÏvIÝ^ÜñðÉ» 6=v>²ÌMáP’›åzëàxAP1#kˆäšÜNõxÊh5'FQ4¢QÍÇó&_k@ÃèñÇ2€‹˜`ŠC.,¢¸AnˆìŽhêw—i Ü•bb¯H‘~ïò°ß î®ÊøÄ^‘b-È.\Ä{x ¨–Ã+ÈÊ [æÝ+¢Š{ôbgòÊÓ'ÞæX´r»–·›ûNÌ5î¹_‡{×ÒÓEWÕ3Mú!IÿPN©ÿŽã 4Gâ+Jý#Iÿ-Jþ(?ÿJZÞÖÕËTN®eDtàSÃM 3Eá2Mÿ6K÷5Nÿ@AËR.ŸePŸÔÖÐHXÒEÿ‰YdÙUøâ4Eâ3Pÿ6Lù$Tÿ{&wÿÛ*-ËÙÙ!Fÿó~ÃM éÓ2<Ì0Eí6BÞ)Hòq$lñÆ0/ÍØØ.Iÿ5Ié-FîRF˜ðsÑe o•i±ª(ûk\õ2Æ,ØÍØ6Nú*LÿVM©ÿ„åt~—x´À#ud-Ú)EYÓ-Lÿ4Mù2Lÿ9Iß[OŸTL§;5È:)Ô1x.;´)uDa°Au›×ÓÐÏÏÅHNÕ2;ÿ6Iý4Mÿ>ÿ Aÿ0Tþ2Cÿ ¶:Šg8$ÿQUÚÖÖËÑËÌ4€x‹m(_³3Gÿ?TÍŠjs}y5Lë0DÿN}7q®:2 …y<‹yÒÅÒ"Ó%†s'3ÿQf¥ÿÿãä 2GáBÿ®^4ÿot™E¿I!è=‰}JRöes áá!ÇÈ4P_ÉC[ç£sNð„!z™.ã&NÇNÙÊÚÖÖÊÔÓÐËËÙÍÍØÖÕÍ×ÕËÐÓÖÊÒÙÓÐØÚÊÙÿÿÿ-¹bKGDÒàØ®°tIMEálgIDATÓc``dbV6vN.Fn^>^~A!aQ1q fI)iY9yE%eU5uf^ M-m]=}C#cfS3s K+kM[;{G  Y-'gW7wO/o_f?ÿËÀ àаðˆÈ¨h @ŒNl\|BbRrJjZzЌ̬ìœÜ¼ü‚¢â’Ò2@yEeUuMm]d½jÐÚÆ¦æ–Ö¶öŽÎ®îžÞ¾~† 'Mž¢7uÚô3UgÍž3—aÞü -^²tÙò+W­^c°vêú 7mÞ²uÛö §sîܵ{ÏÞ}û‡{×ÒÓEWÕ/Iÿ3Mú!IÿPN©ÿŽã 4Gâ3Mÿ+Jý#Iÿ-Jþ(?ÿJZÞÖÕËCIÈTN®eDtàSÃM 3Eá2Mÿ6K÷5Nÿ@AËR.ŸePŸÔÖÐHXÒEÿ‰YdÿŽÙUøâ4Eâ3Pÿ6Lù$Tÿ{&wÿÛ*-ËÙÙÏÎÅHXÒ!Fÿ}Sjó~ÃM éÓ2<Ì0Eí6BÞ)Hòq$lñÆ0/ÍØØEWÕ.Iÿ5Ié-FîRF˜ðsÑe o•i±ª(ûk\õ2Æ,ØÍØEWÕ.Iÿ6Nú*LÿVM©ÿ„åt~—x´À#ud-Ú)ÏÎÅEYÓ-Lÿ4Mù2Lÿ9Iß[OŸTL§;5È:)Ô1x.;´)uDa°Au›×ÓÐÏÏÅHNÕ2;ÿ6Iý4Mÿ/Kÿ>ÿ Aÿ0Tþ2Cÿ ¶:Šg8$ÿQUÚÖÖËÑËÌ4€x‹m(_³3Gÿ?TÍŠjs}y5Lë0DÿN}7q®:2 …y<‹y×ÒÓÒÅÒ"Ó%†s'3ÿQf¥ÿÿãä 2GáBÿ®^4ÿot™-Ü)ÒÉÒE¿I!è=‰}JRöes áá!ÇÈ4P_ÉC[ç£sNð„!z™.ã&NÇNØÏØØÏØÙÊÚ×ÒÓÖÖÊÔÓÐËËÙÍÍØÖÕÍ×ÕËÐÓÖÊÒÙÓÐØÚÊÙØÏØÕÖÕÿÿÿÃå;qbKGD︰â¡tIMEálgIDATÓïþ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKL$MNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘f’,“.”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®,¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄ,ÅÆÇÈÉÊËÌÍÎ,Ï.ÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíî7pî㾪%%tEXtdate:create2017-06-06T01:31:20+01:00€Â·Ú%tEXtdate:modify2017-06-06T01:31:20+01:00ñŸfIEND®B`‚puzzles-20170606.272beef/icons/flip-web.png0000644000175000017500000001416213115373717017226 0ustar simonsimon‰PNG  IHDR––j.>gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá áoízIDATxÚíœù[Óø·Ç¿ؽw@h“¦MQPAA…" "¢ãŽ ˆ# :‹Î\E”­ С¬”¦ieAh?7iKÛ¤ t}Æû<¾ðN›¼8ý,眜Oÿcÿ&õŸ`-,ì’Ë1#¬iФH^ы۶Ö5×°‘>,LjN/$±[X]a[§^X&a“¶ÇáÅÂft&|‚_ãÍöØmüŠ‹QìÙ"d‹.¶MÉöllRÀ49^û°ô“Àxå(ŒHx%8²U,d ;#tIú÷ºe (µÝ5œ.^­€¾29Ê+9”‡ð›Ð¨È3B—t9öp IÅÂôV”•ñ go“ð›dòˆµ¼¥]Ã[ß±¾c}Çò¼Ë£`,ÿôÆâÚ°&ë÷Ÿç-‚af¥„aXÊÅ’pm_Ü[ι·oçp_â`I·$ÄïŠÝ¿+JÊÆ’Æ&ÄïôØvʹXsvœz÷öí ŽSN.ÖŒŸ~÷vna=,˜+¿qý¶¥_Ù œX(\˜ž_UYU~(ýdªecÊJ?^]Yu5#½x/„²°–ë»ûJo–>ìëF¹çÇúP×Ûÿ´´²D œëa½½qëÆ='À¸XH.WUqû¢(|Ï~š …ï¹SQu:"<%IÌÆZÔ0p­º¬€nœƒ5o ãZu©>¬ë7ÊkÀÖÍÅÊC#wܹY} ŽL: â`åI"knÞ=#Š<ÌÅÒÒX%•Wh,‹‹e ±J*KBÀš»}¿¶Fkjä~ˆ9'+®••ææ'Al,¤0?§¸âjÙEÎéx˜ålЙêª~¾óÀh|6ËÁZ|®7=®þ¥2,Ü€vni1h&¢1hjŒæoÞ´@È7Ëîƒ6DÇl Z V>€NøÐ¾òáSÐL\þŒ˜5­åèÀð‘gIE‰)áb… ‘aIe‘©{‘\‰T¼œ:A¯,|?.NÐ9ÞšCð–’Âù°PqRþöÝE¾5ŸµœŠÓÛO"«F6VWç̰Êwk6–¡oƺîL`©··{ðaɘC™)RÞÍÙš™‘™„ðm>.0ÛÕ×5Åë- h°ô~Æž(‰DÀžˆˆÄ¶/¿':i `Éü›^ðVͲ±±\ô%]XlÛÿ»â;ÖzXã`ÅÉ«e:!C²(8{;"dN­€ö%—Ñ© Ñ[ˆó ËŠÙ ñ ú¯SÿØ[ÓFÍP_?¯ú†š¦¥§ñ*=µ87#“_Yi%½¼¥ Kw_ÿà“.á²F½¯Auo—mŒâÕFÉÁ¹Å~½í;âù•°íÜ@O/W==½ÖÝ-Å]ÒŽ ÈÞè«Aݱ°LÊ+T”öQø6ˆaI~85GRl‘äÌ[Òr/;&ýOʇHuoCë é Âõ ½P •‹Š v5͆䛯s»aX|G³J ‚ìÞ&\ÒÖð"Z "‹IÌ_sÄ0œÂ»ÎÙÃr$ÁÔ¶Š·¾6f'¨qÍÕ½¨XJ;>cW}X´£ˆþ?ò·Asé¦Ó-οÅÙŽYX¬\“ƒÅÞª}Xøô¤îF #+½5¼!±¸ù«–Fø3¼…H‰$ }r*ŠDßKkI»òo{ ÙR˜›W€òa¹ÀL³¾MÇ‹… 'پˬbaäý8©Hq<Óz ’½"ˆZ J+o€…B ÙZã”}Xô‚0Ò>©—ýõ *§ï—Ä“új, Ɇ¢¡¬$Il,G™ë—ÐôaÑ×4â€äÏ|±àøôðÈT$Fx¼5þ “Ç[0–¼7Qˆ HÊšnˆà°´áòì Dg›±JÊæÇ¢¯ñR0Å`aíÊÛq251)FÊÁšÁL¦YGãÈøø"Kºs_ÂѬ¸Ý§“7J°pÛy(a_±ô¸Ä¢=É{å28oÌù±°¬åõìkãºX’تª;i)ù‡¼™³Ëš{Þ˜J˯Ö+WS[Ö©ô”¼»·ï–¤¦%zjn,ŒìØ%;s åDÍíš ©)Å»`ô!…ù?Ä÷φ޼¸RqqýQ²­²âæ58|{K÷ à׫oüÀè ͇奄~ûô†°}Þ„ë6¼)'",õNyÕ±ð𴄈ý½D–»Qz§,¬ØªÛÕe¨xw&«íp\½qõÃV.V Jª©¬ù§'û±0bðxSžDœ^[Y[‰³DåLØâÃz§§±.ÿt9¬¸ò‹—JóE)×[jCcíîk /<=üXȱÅéÒ %WŽæï„ýXäÓRya¾âìµ W.çæoÙª¥°¬¥F­áÑÏjB™‰‡DpîfºZñóÏÄe0j ýÓj¾0¥QpZR$š'‹’ÎÄ©“ôß&‚2ã#£"Q¨¨h·³ˆe`¦g¢)Äb“oA m¡¢ý{Â$¹þ¬šÆ²QÚíLöŠ2v„É´£ÿdœeg-!.'÷$GKù±”¶‘.^,ñüÝûO²WyG…ûgT”©Ø~–‹ AX†NÌ¢]‹vyêþI{ââà u’OD6ØŸ–è-Â1êg2dkÚô"Ùî¸g÷Ü|f­CÖ™õ6šK,fÕBÞªé÷ù·x‹ú]Tuøn'„¬Ï lXõ‚µ›SÓ£žÉŒÒAIüÙÃé YXÂ5ˆ¯žšUm¥<Š"⨌[¦©i‡ãà Õ[_ ‹*蘖l/|üŠ$qÌÚÿ‹Xgû’$RM)m›" ,*d,ª;N%çUœþA¸>¡—Ê%úñW±xsîo½‰ÙlìÔÌ®\¥Avoª%ˆÿ'eôUÁÿ.Q$ôCá±Äòö©wsÓÔ4[5«)ó¡ºòr (çŒþ¥™_&ËcE.Š£Çr3.ýt_Ó®Q*Ul)Umm­L¼×3™»ºLulýBÒ ° ½Ÿå×̇¶!Ò,‚š|©Öý2:6484ô:@CCƒoFßèʾóúU¬Ö¡áÁÖk‡P~¬5 Iݸ°Í<ÈÅÂp’Òi¬Çk0‚#1=‹i+ö£‡»÷…¶ÍÌNiJ÷¡Š@oMçga½"g†9¨©nµab8µÏÇp¯ÍNŽÇAø¾j’eblŽÞ‡y±t†ûGˆEʵ±¼…Ñ÷1hzÞ1;Ý„I3êào¥£°D.ÙÓ¥œÄm5A;Q#QðÞ–/ŠEß×Þצ[dòd Ãj½f‘ä›çgv ³CÁMSx€zZ´Ím“!×ñFü‹a1µQ³ÊBºuJJK.ÌÚ½ÿtÊÔ(||Âë-Ì1š§¤%eìÎÈñ`eŠ)XoKK¯TL,ÞÌÙ‡Õ<8Ùuµ´äÞØTÛ+¯ÁÂ(ókð|xÒXRvùÁÄ”r|T3®pc‘†è餽ùµUµçöî)Їå(Ì‹EªbbN'î=y¯êç\‘œ©^6ÒÛ¡ ÖOU•÷ÀÞÇÅÒ»k?ýÀØP–S-£åw*êC&úÖ,â'È]ƒ¨fjai éV‹eÇ/‹boˤm¹":ºç ;ÖÀ*+¿z÷ò–f`W¯_ù͆¬~,Œì¥_©^×+.? g´8<Þˆ4hSмwëÞIDr$A|Ó=h,ŒìJÇæI‘Úæöz\ãCœý¹¾î—VCÓwl™Õ††_ëŸþÚ®o²ûÇF´’tªÝj¬Pÿä7¾ñíL+S«qc‘ÿ%E òg/>w)÷hQLœ‘ùœÜXD­TºñDžâü…â˹b•$v¯…µÖL³rg"ávO?'ôÌD€ðŒ-Ÿ8Fe‰,2c׆(…X†ˆÎØìoÙÇ!·ípì†ÍôLD¡«nž5±¼ÛkÝr‚1fXñÛh,JϸյŠåó÷Õ,JˤdrqÆŽ0T!‘Ëbž11ƒ…M?ß$u×\o Û”-ŽB¶©ÜñŸñ|xðÙ¿·&‡ž³VyjR³èùÿ r¤§‘iŸípßšjuà×<ÕeÑ¡üä¬ã0™ñÚáÅrØ~ôT E9¹É9yytÆ`erlØ?MŒ’,¬YK¯7‚\¬Í6Üã­Qª'ÙSƒÆ$%ïÛ*ŠÚÿÄyÒX“¤y—'D¶$''oElðD”Ø l¦ÕïV7qúŸ¹µÙ³ÝÑX#3¿¬&›2hCÄ–c¿x˺åÍLQ©xCĶ“¾òF`Ø„``ñ™Þ¼1ø _·j0Ê{kªibLá­A °l_iëI¬FŒöWáU›|ÿ “ᮃõ7¼e62õJÆ>Ó­6 Ó7^½:Õ4Õ²™ð2 ´9÷—;åK÷i,üÉFæamÛzìá'ú²î/Õѧu2ŽZžÐµö`”ßo`tq ¢#)HºûBãÈ´×Õ4~Òm“%•¨ÆX¶/‚eQÑÆù>³’ B£KD8:³ªÃNó²l¸Z³‘À1Gj»$ÛÆÆ¢ÓW¡¿L¸a¬û&õÊ®1·MÙ5åPVÀÐŽ¢º!TƒÀ¯FJvýøbØAØ86Ìö¼ÕÞè0¼};?7Ã͸§ß·J¯îÀßÎÉyNÍ×Ȭµào§I"èÑäÚ6=7 0?ý³©A@Í¿]¯xXW÷øÑã`=©©|¨V·45³ÕÔ¬l}^W[õ¨­UÕ¢ –ªù áϪ_¯¼ÿÀ«÷+é]#Û ñ5 a§È‰ÑÑѱ@Ñ?NM¨š›~Ÿ>ò+Äôµ­CÛ$ ¤ÝÁŽ“Óx›~¼z„õ%:’â;’Ø î —d2\ÊEG¯¡U¿F£ ËÝamk³äÞÔ_†Öñ•±0Œ '^ªÍL†K/¾Î¶±Ðª_ ÃIÇ V3øžtÍÑbDèXR©T‹eóaaÄ”Em´9Wë.`²RŸ3¶–;)£¢£;)7Ú| DŸºN9—>zC\ðNcw°°–—ÖÅr¹z£®a… …ãOçäò¶Ã¢PbqvAAP>¥zOgi/Ì*ƒ7S±¾¤ìOÈzšÌÍë7Û»èx= áoµ–ÃûDHò£xÎb QPZRš/“sú HKXXh§·V悚 Üÿ¸€ÞWMÓ`θ>7óñaAâ°„”0±‰.$þ!yo¢ˆ‹Ø}õªãXT-­t_¼~±aÅip¸Ô«uyEñú…¼5óP­|ÐnTMqÆ–$³ »è±ÂËGÇwÁœ³Gò³OŸ;vò’BqÜó Ð;ä5ô’eКŸ>U7üaÔ«—&ô¬>ˆåvéq½æ‰áÌDÞ°'5ÊE`(x&JÂSö†#¹âU›‹èðÔ'z<3Ѵ쮑ՙÂY o ‚oÝ‚’SÂŹQ2žuKØ&9* ìß²‘­“®­¸±t`mîT1`ÝZ¡aQÏú{ž}â]塽ÅiYż›*N=™v„Ýái_-Ó+­5ã™^2¨ÂÜjm_wÈÓ/¤óâY=Q¾3>!–ÿ,†4jW|ÂVŸi8 Mo¼—]ÂíŽE0óRÃÓpðÇíëž!ãŠs†! ¯·<6ÿ£k÷‡¨òîÁLìà´i5½Þ:CˆÏª×¬Aü³Í©¹n ð=êQéú ØOF¾~8£¡<·tÚLjË$õ·û ¾ Ö™1OCÏûWí Aâ Ç¿ˆqÞ4\N¢CÝ1ÁôAfAK°ù¼?J† æ‰Û…!6Â'ŒŸ–^·µZ1 gCÑѽr城G%¿¤‘‡7†EðKôß9«ºctšRA'UHÞš6=3jùÕnxš4O@Š ¥e*­|ø@Ù¦æ«3(UÚn§Õµ>ÙŸ–yµz£åQç4à<Á¿ÚôtིÂß[Ѿ¸²,¤PÔÈ¡s‘¹+B½2+ – òW=%]Û[ß±¾c…Ž…H$Ò ëÃü;߉\.Öæ­[£°\ïçç?Ü:Ëù×üür€-ke~~~e=,:Ũ{i|¾Ì‡… §çIù°\`äyg»2àØ­Ë »ZÛN wµt)C9Àl@'TƒHÝåmDåAXô:eËm`µ ;˹ ºéX^ë©A°±h›ù Õ àÕD ·|O_y½å«Aðx+ÄÌgú©¥ó±±Ë@póÄýŠÌÂS™GÎgVÄyrA?Ö€©»¡ÉbzÔùÒø×j#À*V©»^eÑ?îê0ä`­t™»Ÿ¶u«CÈ™D55ß”UŸˆßšZS]{5nËaOV€ÕDÍ÷^*»øÇÛ¿ £¬¥¦¹yóŲ‹õóµ}ñBË»ù¶ ¡Õ *«+ªAÜ*¿yÞWƒðc¹ôŒ]¿{ãƒ\,¦Q~·B @¯ƒ‹eàeyÍõ¼5WRZR9»` öÖΘÔ{Õµe[7ey«yn¡ç|ùÅï?š‚¼Õ<¿`<_~áÉÂB{Ð÷A(ß/¨Ï_?׺~ž¸ e¾ «C‹sÇVZnvÓVš“·;¶z f£N¯7˜ÌºyîØê426mÓ/pÇ–Ùd6è ­c¼ýò¡­òÌ“¦o—ò/¬òÞˆ)xÝbÂwÏëàu˯ ,›Ý ¼×çyëÞª¿c}ÇúŽõ5±ÖúÞ@:¾8o!^+}5¬¥ K;.ŒÕ G ¸ÿ÷aA,'ó8K«m ¬fÙS¯QñK©~^u[@U·î+UBR×µÚTuÂïknY­AØíœ]ê ¬ú8f…5m· ¿OØf_ß¶þ×°Ú„…­ñ¶fû¦¿ö›Ó7Šõ}ê‘ÆÛwY%tEXtdate:create2017-06-06T01:31:11+01:00¨:»%tEXtdate:modify2017-06-06T01:31:11+01:00Ùg1IEND®B`‚puzzles-20170606.272beef/icons/flip-ibase4.png0000644000175000017500000000245413115373730017614 0ustar simonsimon‰PNG  IHDR‘‘æ³ÿgAMA† 1è–_bKGDÿ‡Ì¿ oFFsxHûüotIMEálg vpAg  Oý6IDATxÚÍ›a–³: CYz–¦å=¾4$¶cvšD|-ÓB«3[ùµµÑgTÿ©ßW$èB‰€ž8¿@ôµgW¯'ÂEŒÕD@'^L„A‹º’‚v!Ñ0®S»†Škˆ{i: %V™ÊD˜+E"åxhn‘BdzDä°è—ˆ°‚È1´\"ÏÐr‰<õe5»_!rY4µ\©DX@d[ôsD¨ ˆ|%Á#ª™ï5§EyŸG^‹~„+ˆ¼CK#r-ÈmQÖ3¤ß¢¬çl‹u‘Žƒ¡B ‘f¤ )D~ž$"É"@«°†F…¢0+¤aV!ÈmOÑ×¢9NÅ“GäW*‘'wjQk£ò²ÿWd¾’û´"|zfõ^"àsõx‰Ø|í«÷íã:N$Ú-Þ|­Õ;ˆ{öåÉËØ|­ÓO‰N{>/¦Úí=iÖ ·‰Z{å¹ò2w»÷ôÛ©ÂÿsÜíÞÓo?åÏÇuœAíC¿}Â"/óÚW¿OÍ/ÿ«ªßʯ-žˆè—Íãnzäç!ó¸`"6‹&bó¸`"6‹&bó¸`"6‹&bó¸h"6 &bó¸h"6 &bó¸h"6 'bó¸p"6;Ëêo’§DÇ6BqXDÆ¡GDl·–HJ¿â‰ŠQa ›ÇÅ)?ÄHýž£Øý ›ÇµGƒˆªN$åqáDl—@dzT•ªa›Ç/¥æ^":¿T$õ¯±yÜZ")ýŠ'*F…%Dl—@Ôm3h5ô¯±y±^'’ó¸x"¥ Öýÿšh‘žÇÅ UÌ<.œˆÍ㈜ö¤±y\™Çűy\8›Ç%ýMË›—¥Qy\ÆÔ¸<.ž(zý5¼¤§t%tEXtdate:create2017-06-06T01:31:19+01:00›Õõê%tEXtdate:modify2017-06-06T01:31:19+01:00êˆMVIEND®B`‚puzzles-20170606.272beef/icons/flip-ibase.png0000644000175000017500000000363113115373727017534 0ustar simonsimon‰PNG  IHDR‘‘æ³ÿgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿ oFFsxHûüotIMEáò‡» vpAg  OýwIDATxÚÍ›ïkSgÇó¦Õ‘9,LÇÊXßl¾6„Ž¡8Ü%´·UrMjmZ%v³­mÓbXI¡vU"‘¤”±PFµÍz$÷>÷yνç´7Ï“ó"oü†ó!x._î‡&Œn›„‘¤ÁÐS/™©ËF“6$z=7úÝ@Oª[ˆ6W²#_œL&ÏšÝAôæÉõ?éµÒ—JÝ@´:9òÕNøÄh];ÑÛçékƒÇ[áó¿0ÍDë…ÑoÏxÙÞá ­Dr&uî=vàÓHä;Ÿý¾¬¨uìüœkh"òŽŸ ˜"ß±ósl¤ªˆ?v~ï0õDµ±¡~0yµ#‘[ "‰‡à|ÿMÈÍSˆ|ŸaD7NÃùoLäûŒ•¨rÎ÷5 D“ŸÂùÏï1õDUã8˜ïI­i ztΟ5YLD’*5ÆNÁùK%9—Äù¹d¿”GT¾çª@ä犛(û1œ?¨jê‰^ ÷‚y«ª©'úõ<œ·ªšr¢úèI8oUµØˆ°·Vºçíª×­q¿”ôŸÜMæ‡pÞ®jq=°Dk)8ïT5ÕD÷>ƒóNUSLT3úàüO D­ª&Ë»U-f¢¨Ùªj²¼[ÕB‰È·2WÕÄé«E…Ì!‰ÚU-0Ç~¸þ„RDäU5nÞÿr8WÞdL‘WÕ¼éùèÊØ|• £„È®jüœ87üórƒ1MDvUóÿŠèmi<ÿr·uš/2²_£æÃ‰ÖçÒó ïY±wsƒ‘ý5ŸóeùÜÊŽÿéUfŒìרyÈ>ö}þyZ(Ã@¿FÍ'_æ;?gÀ†0¿FÍˈ¼cççÙc&Ýîרy‘ÈwìüìšUÙ†(¿F͈øcçg½À„ ¿FÍóD5³¸ö„|EØ€ñkÔ®I›Nþýšë㺄Èç㺂ˆóq]@ðqº‰D§—Hæã4>Nèãô…ù8Dá>N=Q”SL„ðqj‰0>."á}3@„ñqÒµ’|‘ï3Œãã¤k%ùXˆP>N)ÊÇ©$Âù8•D8wT"é;|9ÒÇ ÉH"áúá¿_Ãù8é¯Ó"¤SG„õqꈰ>NÚÇ™{khwÔ[C?Ð>Nº–ÏÇB„÷qªˆð>NÁÇ)""ø¸˜ˆ¢:$ÁÇI×’o-dÈ>®I›CQ|œ"’SBDòq*ˆh>NÍÇ© ¢ù8DD§€ˆèã:ODõq'¢ú¸ÎQ}\牨>®óDTG'ê¶ù/ŒW”Å;F%tEXtdate:create2017-06-06T01:31:11+01:00¨:»%tEXtdate:modify2017-06-06T01:31:11+01:00Ùg1IEND®B`‚puzzles-20170606.272beef/icons/flip-base.png0000644000175000017500000001252013115373717017357 0ustar simonsimon‰PNG  IHDR  ›á9×bKGDÿÿÿ ½§“IDATxœíÝKSYpˆC4ÁK0Š®®NR)§¬TjªLi*U±Rã*ßa>”Ÿ •í,³É:»hADÀÐ ñ‚c0ê»è¼ŽC·xì>O÷þÿ–›GÚlÏÓÇY.—@ãŽÕt3 €@ „€BÀ!`„0B! €@ „€BÀ!`„0B! €@ „€BÀ!`„~áu ¿þú‹×¡D°¼¼lü Üæp8þüóOŽG3heeE¨Ì///‹VhçK´z¸—ˆ„0B! €@ „€BÀ!`„0B! €@ „€BÀ!`„0B!ž÷ä0‚ñD·mÐ}{¢ÛlˆVîT/kZnE”€ijyƒx݇DS˦æ8Ësºµ–saæù2óµŒÀ%"! €@ $t“ÃÌO®,Ò.‚Ž×2³–saæù¶«ÑB €©ûB¦µYÕÝmõ®Í¼÷µhõ¨O„úì˜y¾ë1§˜öp‰@ „€BÀ ÔääSé%3{t,D«G´ó%Z= Q&º̫„Ú,Ï!^=¢/Ñ깄KDB! €@ „€BÀ!`„0B! €@ ä,—Ë\$Úroƒ¸ÌñW*cËËËB0¬¬¬ˆöþX;`vvv¶µµ•ÉdF£Ñí|q9Ž(ó``FcssS’¤ýýýl6»½½½´´duQT00ÉÅÅÅîîn:><<”$)ŸÏ;¯×ëv»¿ÿnu$0 wrr"Ër.—;::Z__/—Ëççç—ÿ‹ÅâñøêꪅÒAÀ€P­VËd2{{{ÛÛÛÙlöàà å }}}ÃÃÃ~¿`uzzZ*•2™Œò+«T*ýøñCó™ÓÓÓ>Ÿ¯§§Çä Mƒ€OJߢR©T«Õ\.W­VÛ<ùÎ;SSS‘HÄ´ò̇€ççç•JEi`äóùB¡Ðl6oüªñññ*´ †¨{îŒ_›H$‰iy–CÀ@ëzîì”ß]ãããD ƒÛißsg÷èÑ£©©©;wº|5,¬nì¹³ëééñûýSSSË7`ï¹³óûýÃÃÃ÷îÝãR¡È0h§Ùl~øðAù•U¯×y6Çãq^G™(Ó\ÙmáòsÍÅÔ.÷¶êý‘ey{{ûÓ§OëñxaÙBOÉ—¨ßŸ6³•šXê!š­Ô$ÚùRˆ0¡6§sˆ1m~õûsÛÙÊëñx<Ñht||ÜœÙJÑÎ×%QÖâ5[ÙÓÓ366–L&"‘H8¶Ïl¥& øÌVö÷÷OOO¡¡¡X,611aΕ¡à004[ét:½^ïÌÌÌàà`(zôè‘m;òš0»k™­d××× £Ñèýû÷‰„Ïçëúû`뀀Ùz¶²=§Ó922‹Å†‡‡}>_$$­°£!`vÇ>[ér¹&''‰D<v›žÔ³5ÆÙÊD"‘‰‰‰‘‘‘h4jç?ßfkíg+Ñs7³¯6³•è¹ó‚€Ù—z¶=wî0ûº:[‰ž;̾ÆÞÞÞèè(zît0ûj4KKKn·;ûý~ôÜ)8yÝÝ_´åðq™âùL¨‘3ïQÃbeeÅÚ·³³³R©$IÒÙÙYooo­V³¼ž­­­L&Óh4ÆÐÐhõp9,.»_£Ñ(‹²,?|øpnn.¿ÿÞÚz677%IÚßßÏf³ÛÛÛKKKÝZÖµ...vww …Âááa<ûöm¿ÃáØÚÚ²äZJ=étúððP’¤|>¯ü…ÀëõºÝîïß¿we=X:99ÙÚÚ’$éÞ½{Ož<‰D"W{î©T*þüÙÌzdYÎårGGGëëëårùêÚå®8«««]YÖUjµš,ËÕjuzzúÍ›7ÃÃÃ-O8::ªT*¿þú«9«Õj™Lfooo{{;›Í´<árO#sf~=X78==-—Ë…BÁårÍÌ̼~ýú—_´Ïìúúº {žž–J¥L&£üŠ(•J×Msš³§‘…õ `m_–år¹ìóùæçç}>_›'ŸŸŸ¯¯¯?{öŒ´žl6[©TªÕj.—«V«mžlžF–׃€u¤óóóJ¥R(šÍf2™|ñâE__ß_U(Ün7ÅBJ=Jà ŸÏ+…ÝøUt{‰SÖa®öÜggg§¦¦Ø[‚©T* r¯§¥Ç}qqÁøµ{‰V֮빳ûöíÛ·oß~ûí7Žõ¨{Üìøîi$Z=—0ѵﹳK¥R@Àøùö=nv¼ö4­ž˜¸nì¹³ûñãG.—›ŸŸ7XOû7;.{‰V&L8ì=wv¹\N÷Bì=nvFö4­žö0±4›Í?ƒÁ—/_z½^^‡M¥RÑhT_=>|P~EÔëu^õÄãq}{‰VÏD ˜æÖ.‡·ªžb± 9Ö³»»ûýûw}·‚’ey{{ûÓ§O-k®|gYòx>®ï~†¼ö4º*uG=,0Q({q_˜—N§õ­ÞಧQ §Ó‰Dôµ[D«‡& Y–#‘ˆñŽüUÊl¥ÇãÑñµFö4ºÎèè¨ÛíîŽz ÔäPjW?BÔÇÓl˜YÏùùy±Xüã?øÖ£ÌVê«çêžFš õƒêGZÊ,£iõÜHw=ì ˜š™}<–×¢«§R©> ÖÎ2öôôŒ%“ÉH$‡»£Ý0 p™­ÜßßÏd2_¾| ƒº¯|¸Ì2ö÷÷OOO¡¡¡X,ÖMõ€YÀÈlåÅÅ…,ËkkkõzÝï÷ÏÏÏï8™et:^¯wfffpp0 =zô¨ûê13[Ël%»ãããL&“N§].W8žå²¡e–‘]___0ŒF£÷ïßO$>Ÿ¯+ë13›z¶òF¥R)N—J¥ÉÉɹ¹¹ÁÁA¾õ´Ì2¶çt:GFFb±Øðð°Ïç‹D"Ý]A˜ÙdY~úô)Ë3›Íf>Ÿ_[[s:@àÕ«WÓ쳌.—krr2‘Hô÷÷Çãñ@ `‡z BÀLÅ8[Y«ÕÒéôæææèèh2™¤ûÃ(ã,ãƒ"‘ÈÄÄÄÈÈH4µO=Æ!`¦j?[ÙÒs_\\¤î)·Ÿe4¿Ç-Z=Æ!`æQf+Ÿ?®þ'Ž=÷[ÕsÝ,£%=nÑêá3z¶’¢çÎN=Ëhm[´z¸@ÀÌsu¶’¨ç~+WgEèq‹V˜y”ÙJÒžû­4½½½ÑÑQAzÜ¢ÕÃfžÞÞÞwïÞõôô„B¡d2iyO¹Ñh,--¹Ýîx<î÷ûQ'¯»é3nvÐ)ŒÜWçÏß`Bœ¬¬¬•ù6÷„±Äòò2— Ý”žª$Iggg½½½µZM´Ÿ.ÇÁ%"˜­Ñh‹EY–>|877‡ß¿ouQT00ÉÅÅÅîîn¡P8<<ŒÇãoß¾Uþb¡ì±duuT0 wrr²µµ%IÒ½{÷žþla…t0 T«ÕdY®V«ÓÓÓoÞ¼nyÂåK«ÓÓÓr¹\(\.×ÌÌÌëׯ¯›.5²ÇRG@À€§ýý}Y–Ëå²Ï盟ŸoÓbe¥gÏž™Vžù0ààüü¼R© …f³™L&_¼xÁr¿G#{,u  ¹ÚsŸššbo êÞc©ƒ ` Çu=wvFöXê ÜNûž;;#{,u XÝØsg§ì±4??ϱ<1!`pöž;;#{,u Úi6›?~ ƒ/_¾d¿“þR©T4åu4‘‰0ÍÅË.¯Ö\inárx«ê)‹Á`pqq±åq#çËÈK×íçç’(shíÑlU% ö=ÍaI=möXÒ}¾Œì±Ô†h??Š.ïá€ÕjõîÝ»¯ ÇÉɉ$I@€ã1E†€Áµ$Izüø1ßcnllŒ‹?C^0ÐÆe%µt:Ýõ«7®BÀ@›‘=–®£ÌVÞjã‹N'P“Cý©TýQ_H³a ~PýQÏòzZöXÒlè8_Êl¥ñòë@S3³/ÄÒ£3³gm=ê=–XÎEûç\ÎVr©PÌž¡.Aƒ,˼’p©ëg+5!`Њq¥[Qf+mÕÞP `ЪýKúØa¶Rÿ¡Ü4‘Hð=¬f+5 Ýä0ó“+K‡ÀÌÕRVÕ£ÞcIÁr.®{Ål¥°]LÝ2m±¦º»­¾Óµ™÷¾¶°ž«{,]RŸõÙis¾¸ÏV2ÖÃëåŒÀ%"ü«^¯+{,q<¦2[iÏëCW)Ýy¾ëÜí3[© ƒŸšÍf¥R‰Åb|›J¥B¡ßcv ~*‹¡Pˆå~†ì(f+;‹@MA>•^²|²u=mf+5±œ/¢ÙJÝõ˜O”€‰0Ý}•P›å9èë©V«½½½ì³•7ž¯ÝÝÝT*%Ëò‚ÑâxÔcQÖ’$‰Ëâó³3I’VWWÀ‚}f+5!`Àg¶r?“É|ùòepp0 NLLtñ¶zì004[yqq!ËòÚÚZ½^÷ûýóóó¶íÈkBÀì®e¶’Ýññq&“I§Ó.—+ÏÎÎvý}°u@ÀìN=[y£R©”N§K¥ÒäääÜÜÜàà ]y³;Y–Ÿ>}ÊòÌf³™Ïç×ÖÖœNg xõê•ݦ'u@Àlq¶²V«¥ÓéÍÍÍÑÑÑd2iç?ßfkíg+[zî‹‹‹6ï¹ë€€Ù—2[ùüùsõ?¡çÎ f_êÙJôܹCÀìëêl%zîD0ûRf+Ñs'…€ÙWooï»wïzzzB¡P2™DÏ‚³\.s9hËÏ â2Äó7˜P#+++Be~yyY´÷õ´Ákº d!`„0B! €@ „€BÀ!`„0B! €(ó`š‹—-\^­9ª`áò|ÑÞÔÃH”€9´öh¶ª…zOd«*Qˆöþ ¸D „€BÀ!`„jr¨?•ª!ê i60Ôª!ê+j~@·ðýéÐzD PÀÔÌì ±ô Íì+²|ïf¾?Xp‰@ „€BÀ Ýä0ó“+KÇÂÌÕR,ß»™ïO'Ö#QfíºL¡n²í°úÝPC=ºá€@ „€BÀ!`„0B! €@ „€BÀ!`„0B! €@ ä,—Ë\$Úm- âr#n5\"BÀ!`„0B! €@ „€BÀ!`„0B! €@ „€BÀ!`„0B! €Ðÿ‚RR‚9dßIEND®B`‚puzzles-20170606.272beef/icons/flip-48d8.png0000644000175000017500000000302613115373730017130 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEálgIDATHÇ•–ëSWÆó—eZa¹Èâ%hœÜt¬iÚ4ÒD§íô[û­±§QÔfPbb5©i;Mӆ鴹MjcÀ]î—eÙÝsdÔ¨`{¹IH§y>œ™ç·ïîyßó¼çØÌ[êXó¶™ÙÆél£jÀ\£lÓUM]›š™jT°Y'¬5M\w,”5ow¬ÜœYlÔì!0gíÒwTÕ©qnÑ ÃÐ4LÇ»2# ÅCŠùÅ©Ù20¡×á:ŽËƒ^µ&²€‚HΟǺ¥ºŠUÀÚË«µ2£W;†¸_ô*4Н¢µå%©Pä¥'Îd@µ&0põb_—®³£ý¯È¼rßoŠ€•éŒY]~¥4¿Žµ› ZÕ%Þ›“:•@ã‘WÒ0X,&ƒ[éI×?>§XÎyIzÉl¬GšíÙ3–ŸGOµ*g&Ô?xÒn?9x6˜"ÒO?ÙŠM f˨Å܃"ü¾[Ù?<6v¡÷‘ó"`7ñüq¸)úµéÔá783#˜¶ÇlÒ+Ÿ¥€  oH'^t#z>®Çþü§]߉ú†n»`ïÍyÀ~ÛÖ®èúôZàkH\=zYåQ÷Ù¶©çé ä(Ghls•Zu(ÿü£e?ÏÅb¥’þÝW¹¼¬ÜÁA©úJ¶ëÎ5çÚšÓét¹îß½ù“/D¼p{Ün2L,}ç÷Ê" o$ú¨r€f§[¢ bVä¢t>¶!p(f#·-ú[Iˆ&\2›|xõÄå›Såòž^ Y†qß&µ#6­Õu±÷c¾HÚÚþÁõªÀրŋö§˜ 4Ñð Ö¥mï¬FÑþÁv=¦4Zÿ†l= ONz'¼(I #FŽ+O]}E”2.tG¡ÔYî„ÅšTÛODX!+ˆ]Â/-‡²"ªßùžñG¨084ã9ÇtÅ*—Wu¹PñÉøÀ¶´öºÝÏ&¹ùüÞô“hÄKrúÈJæ¬Z¦RÞjÍ;²±(EQt"J¼ýñªtpP)ðü~ýáµÔ¡q ,IHùƒIiûÙ«ÿe•€ èm´$äÉ·<¢&€¬’¥ –Qjv|\kh´™5»{€Ý‘$*æÏµ¶™F#sŠñ`2øäiˆ/ü›ŒìˆUf}<µmµnS0ò¾Ñ*ëfì7Q•¬¯·‚t9B+3n´{“¤†Ûß!aÕ*S-¬²ÖP\‘ôo–Kl&¸ŠU¾ÞPò ¹Gk2”?Ì#VÙв›"®Ỳ߇<à8Þ—k™éƶ«ýžñ¨Ðeqä~éõ¶{´±[ms7+½}Á1ߪ±7]fêwùúÐêêð_j}9yý ªþ ô×r%tEXtdate:create2017-06-06T01:31:20+01:00€Â·Ú%tEXtdate:modify2017-06-06T01:31:20+01:00ñŸfIEND®B`‚puzzles-20170606.272beef/icons/flip-48d4.png0000644000175000017500000000106713115373730017127 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA† 1è–_bKGDÿ‡Ì¿tIMEálgkIDATHÇ•V‘Ã0ó茦ÍÜ61dœüû®×8A•àt0ücíÎÌË·à>¶>9Zñß{ãDÐñ’0x¸-þÀÐ$„ `)& ˆ/Àª­-®NRÞxœ_/9ìzP °âw†åË¡†gI i·<&á«ñŠŠ…ÁÐ, l%™§0ËVx’ÿWFüòTóä¯Çã~S‡ @• ¹/¹'­6³# ØNnÇĻϯ\$ ¯z.ÇíFÛ;5ò X7£üv`˜3$úk{cʾÉ!:K-šwÒ8"»Üî;ƒö·ä3ÖØ«¥²ÏÝúÜp[ÿ À›ÜýÏ‹õðÞŽG.ÿžÎôóû!i¦YUcùKßjІãú1c2*…Ð3P¼$ÔhG>k¢²ÀP#À|IZü­ –K'ãݺ” Á—ÎæÒ‹¤ìd[‡ Q58K¢¦Ú~ï­¶¿¯ë˜îЫWYͳ%tEXtdate:create2017-06-06T01:31:20+01:00€Â·Ú%tEXtdate:modify2017-06-06T01:31:20+01:00ñŸfIEND®B`‚puzzles-20170606.272beef/icons/flip-48d24.png0000644000175000017500000000302613115373730017206 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEálgIDATHÇ•–ëSWÆó—eZa¹Èâ%hœÜt¬iÚ4ÒD§íô[û­±§QÔfPbb5©i;Mӆ鴹MjcÀ]î—eÙÝsdÔ¨`{¹IH§y>œ™ç·ïîyßó¼çØÌ[êXó¶™ÙÆél£jÀ\£lÓUM]›š™jT°Y'¬5M\w,”5ow¬ÜœYlÔì!0gíÒwTÕ©qnÑ ÃÐ4LÇ»2# ÅCŠùÅ©Ù20¡×á:ŽËƒ^µ&²€‚HΟǺ¥ºŠUÀÚË«µ2£W;†¸_ô*4Н¢µå%©Pä¥'Îd@µ&0põb_—®³£ý¯È¼rßoŠ€•éŒY]~¥4¿Žµ› ZÕ%Þ›“:•@ã‘WÒ0X,&ƒ[éI×?>§XÎyIzÉl¬GšíÙ3–ŸGOµ*g&Ô?xÒn?9x6˜"ÒO?ÙŠM f˨Å܃"ü¾[Ù?<6v¡÷‘ó"`7ñüq¸)úµéÔá783#˜¶ÇlÒ+Ÿ¥€  oH'^t#z>®Çþü§]߉ú†n»`ïÍyÀ~ÛÖ®èúôZàkH\=zYåQ÷Ù¶©çé ä(Ghls•Zu(ÿü£e?ÏÅb¥’þÝW¹¼¬ÜÁA©úJ¶ëÎ5çÚšÓét¹îß½ù“/D¼p{Ün2L,}ç÷Ê" o$ú¨r€f§[¢ bVä¢t>¶!p(f#·-ú[Iˆ&\2›|xõÄå›Såòž^ Y†qß&µ#6­Õu±÷c¾HÚÚþÁõªÀրŋö§˜ 4Ñð Ö¥mï¬FÑþÁv=¦4Zÿ†l= ONz'¼(I #FŽ+O]}E”2.tG¡ÔYî„ÅšTÛODX!+ˆ]Â/-‡²"ªßùžñG¨084ã9ÇtÅ*—Wu¹PñÉøÀ¶´öºÝÏ&¹ùüÞô“hÄKrúÈJæ¬Z¦RÞjÍ;²±(EQt"J¼ýñªtpP)ðü~ýáµÔ¡q ,IHùƒIiûÙ«ÿe•€ èm´$äÉ·<¢&€¬’¥ –Qjv|\kh´™5»{€Ý‘$*æÏµ¶™F#sŠñ`2øäiˆ/ü›ŒìˆUf}<µmµnS0ò¾Ñ*ëfì7Q•¬¯·‚t9B+3n´{“¤†Ûß!aÕ*S-¬²ÖP\‘ôo–Kl&¸ŠU¾ÞPò ¹Gk2”?Ì#VÙв›"®Ỳ߇<à8Þ—k™éƶ«ýžñ¨Ðeqä~éõ¶{´±[ms7+½}Á1ߪ±7]fêwùúÐêêð_j}9yý ªþ ô×r%tEXtdate:create2017-06-06T01:31:19+01:00›Õõê%tEXtdate:modify2017-06-06T01:31:19+01:00êˆMVIEND®B`‚puzzles-20170606.272beef/icons/flip-32d8.png0000644000175000017500000000176513115373730017131 0ustar simonsimon‰PNG  IHDR V%(gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEálgýIDAT8Ë]“]OÚ`†ùc#‚ mA¢CTbOLfÔm'²ÏŒK¦& U'àüD1Š˜,&žá–Åů–Ú—RZ±Ú¢N„²wµŠ¢wzxåÉÛç¹nŽO•ã÷éŸÀ}åà¸÷•3 3ù¹ÉÙr&qÃÔ˜³Ûv{£e+˲¼”ÞퟅbQûÔÛYŸ` ˆÍjCкm™Wâó½õèOø˜¢Øê¶7`¦È%óå-b2e Þ]ŸÚÞÕ¡¦Íü÷ºÎ®7Ö=®Õ4yUVw×dobÚºòº‡‡Ýº³¹ç öŽÞNZ÷ãÍÕÓ]¿ ÄUxÇ\=¿¡ks4`ƽÉZ êò&Z…ð6[((†"(†YW=Õž‘˜$¤ï=°Ô™îc¶xßÍ’d³Ì]IU‹…‚>Á?½µ‰D£›k‹ë  @¯|ch:Ns™_mÕ¾PV–/ÏÒbéì4ËIJ"üÞΦEÜBûç& ¾ Ë'Éä üwz ûccUÅ ‰ÅÖÚúÝùq à8p-æà%AHû˜³µÑ¸ ’’·ÞÝlîM|_€c86|¤¤˜ceÔ98Ðê¡ aßÕ=ÜR³ Íh@0 &„DФ=­ƒÎQåPA{>75Óú„%Â1dz,L"HÅÕb‘Ùà=pró€¤y†ê«6¶Ä,Ö‘Oë@àÿÊÃó´x)_\¯Zú–hEâÏãM£±¬œÉp€û—Ö6¢ÑH$²3µJò˜89Ž3)*N'È€¾j“Y_uÕÎ5R I¦—îSÕRþÁD?–ݹàA"%ÃÜQé•rç6EdšeY²ôâÜea4'Éq”»¡’/…yR.*²âJXd@âµrÒF¹¿74{Me4a*¥-koÞ8ƒPá£+W¡ýcqÓZ©xÆ&9!“P_üÅcõ–%ñ„Úñ92¯>W¯¢¼þéP(j ®,oEýq¿ïupü?f!´¶ã˜Ž‘%tEXtdate:create2017-06-06T01:31:20+01:00€Â·Ú%tEXtdate:modify2017-06-06T01:31:20+01:00ñŸfIEND®B`‚puzzles-20170606.272beef/icons/flip-32d4.png0000644000175000017500000000076213115373730017121 0ustar simonsimon‰PNG  IHDR V%(gAMA† 1è–_bKGDÿ‡Ì¿tIMEálg&IDAT8ËeT Ã0òè›9HÓ.¯Û|ñh9ûôüBŸ¶ÆŒ¾Œ£ú Z<¹ž}¢3Ö›'ª°ßt+òT@¸@¢ÖìwÀ6p"­õ7@·º3JÌgµ`X‘;à°ñ$iÔ…±€ðÂÑÁ?½µ‰D£›k‹ë  @¯|ch:Ns™_mÕ¾PV–/ÏÒbéì4ËIJ"üÞΦEÜBûç& ¾ Ë'Éä üwz ûccUÅ ‰ÅÖÚúÝùq à8p-æà%AHû˜³µÑ¸ ’’·ÞÝlîM|_€c86|¤¤˜ceÔ98Ðê¡ aßÕ=ÜR³ Íh@0 &„DФ=­ƒÎQåPA{>75Óú„%Â1dz,L"HÅÕb‘Ùà=pró€¤y†ê«6¶Ä,Ö‘Oë@àÿÊÃó´x)_\¯Zú–hEâÏãM£±¬œÉp€û—Ö6¢ÑH$²3µJò˜89Ž3)*N'È€¾j“Y_uÕÎ5R I¦—îSÕRþÁD?–ݹàA"%ÃÜQé•rç6EdšeY²ôâÜea4'Éq”»¡’/…yR.*²âJXd@âµrÒF¹¿74{Me4a*¥-koÞ8ƒPá£+W¡ýcqÓZ©xÆ&9!“P_üÅcõ–%ñ„Úñ92¯>W¯¢¼þéP(j ®,oEýq¿ïupü?f!´¶ã˜Ž‘%tEXtdate:create2017-06-06T01:31:20+01:00€Â·Ú%tEXtdate:modify2017-06-06T01:31:20+01:00ñŸfIEND®B`‚puzzles-20170606.272beef/icons/flip-16d8.png0000644000175000017500000000102113115373730017114 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEálgIDATÓc˜1yòäIÓ,X½döâ…‹Îb˜îäÑòæÎÆâ‹ÿþú¸a²`‚CÛ£Rï¼oÿŸÿþ J¨v°,4aË÷_'¾üXÈ0ÉÃÑò"5vñóÿýÿ±ˆazksc]׆'_Ï^ùôýûÅÙ ^~øò÷ñû“-qgŸmÉ/^°àîÝOóoùº$ÞeÃj†yÞ]ºÿ²Í?íäÓÄðÂ{ æ¾ý÷î˕ضcïWF̼ö`ôÆú憩W^>ºsòÕ¯ÏÏ0Lòtò0køòàó§Wÿ‚¬9Ì£ùÝ¥[Ï_ÿ9ñå'ÄéNõÞ>xüþÿ °Óžól|÷ðþ½ç¿~<öþ´¹óÌ_°ä}'­8§Bé%tEXtdate:create2017-06-06T01:31:20+01:00€Â·Ú%tEXtdate:modify2017-06-06T01:31:20+01:00ñŸfIEND®B`‚puzzles-20170606.272beef/icons/flip-16d4.png0000644000175000017500000000045713115373730017124 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA† 1è–_bKGDÿ‡Ì¿tIMEálgcIDATÓMN À0âé>Ÿ9@kÖ-¦rTIbA¿€öÒ:Ù4  ²AÛ(F^N¼PÝ­Ý‘ÆcdX3‘:|²˜Á [úɼyÅpɯ)R½¯XmíŸ%Š­zMk¾úL¬ù^w&%tEXtdate:create2017-06-06T01:31:20+01:00€Â·Ú%tEXtdate:modify2017-06-06T01:31:20+01:00ñŸfIEND®B`‚puzzles-20170606.272beef/icons/flip-16d24.png0000644000175000017500000000102113115373730017172 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEálgIDATÓc˜1yòäIÓ,X½döâ…‹Îb˜îäÑòæÎÆâ‹ÿþú¸a²`‚CÛ£Rï¼oÿŸÿþ J¨v°,4aË÷_'¾üXÈ0ÉÃÑò"5vñóÿýÿ±ˆazksc]׆'_Ï^ùôýûÅÙ ^~øò÷ñû“-qgŸmÉ/^°àîÝOóoùº$ÞeÃj†yÞ]ºÿ²Í?íäÓÄðÂ{ æ¾ý÷î˕ضcïWF̼ö`ôÆú憩W^>ºsòÕ¯ÏÏ0Lòtò0køòàó§Wÿ‚¬9Ì£ùÝ¥[Ï_ÿ9ñå'ÄéNõÞ>xüþÿ °Óžól|÷ðþ½ç¿~<öþ´¹óÌ_°ä}'­8§Bé%tEXtdate:create2017-06-06T01:31:20+01:00€Â·Ú%tEXtdate:modify2017-06-06T01:31:20+01:00ñŸfIEND®B`‚puzzles-20170606.272beef/icons/filling-web.png0000644000175000017500000003076613115373717017730 0ustar simonsimon‰PNG  IHDR––³cæµgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEá áoí0úIDATxÚí]w|”UÖ¾o›ÞÒ'„$@‚„:¢AAzYi.*ð×Â",eý¬ , ‚+("P $¡‚HB }f2}æ-÷ûã˜Ù!‰™û$~ìó¿Ì{Ï=·žóœçRׯ_GwävúnÀ¹YaëücüG7鎄Š¢‚ÿ[ׄ …âná !<Ïÿ÷J’TZZŠbFît¤(J’$Š¢(Š’U>1¦i:ŒJo¦lx þ•E!IÓÿÙ3!ÆX¡P”––vïÞ]Åð–Ó0úâæËªò‡”ýC”e&;;;>>Þï÷Cûë.¤‚ ¨Õê´´4Q묹Ƙa˜ââb³ÙÌqœÜÉó|YYYRR’ÜJY–µÙl§E‹<ÏË*ËqÜõë×ÕjµÉdáÿ¿² Ãäçç{<ž:ºÁ„ à „ÒÒÒ²³³kjj‚gkã"Š¢Édš2eÊ’%Kbbbê,Ö Çqååå‹/^»v­Ífƒ6ˆ$IF£qçÎ999‹-²Z­,Ë–!""bñâÅݺu5jTÊ>õÔS‹-Š‹‹“«leeåÂ… ×­[†²Ý»wÏÉÉ©Sêa@‰¢XSS#K+I’B~¿ßn·s'‚,­ìv»ßï‡JeiEÓ´Ëåòz½>Ÿ¯¦¦F– 5×ëu¹\‡C® )ŠeU*•,², ÊÚl6»Ý.·‡a/¬3ïЙ¢(š¦iš&ïM„MÓPPîQˆa˜à²ä•ÂÆg ¦V˺\–¼7ë( †²áõp¿'ÿŠ;òÿSî˜ð¶—;&¼íåŽ o{¹cÂÛ^î˜ð¶—;&¼íåŽ o{¹cÂÛ^î˜ð¶—;&¼íåŽ o{!uí7©H’$I’(Šà‰'QA$ âàÍÙ`Œ14XòX#Æ"ï·¶Á ˜c,Š¢,<| ʵBH¥Ri4“É$+Ú I’N§3 jµš¢(Ya[hdÀ²€ ‚ p§V«#""¢¢¢äÆ EQT«ÕrCrÐÎyƒ ¡ †1™L!YÑ,£Ñ¨P( ƒÑh$× c¬ÓéNŸ>——÷ïÿÛårɪT¯×>|¸¨¨cInBA”J¥R©Ôjµz½^EÂz!Ü_]]}þüù]»vEDDȯ ÃÔÔÔœ;w®ªª*66–i I qTÁF°3eee;wŽŒŒ5jTšA¨˜B¡ÈÊÊêÖ­›J¥"ŸÁ’$i4šÃ‡çççÓ4-kêÿGŠzä‘GÔjµ¬zµZí‰'"##“““}>ùb¨T* üñÇð ¥ú÷ïߺukYõ*Š;wZ,–3gÎ˜Íæ†±3ð«øøø%K–ÈŠ)‹¢h0^~ùåÙ³gGEE‘/‚ ÄÆÆÎŸ????èС‰‰‰rµÚ¶m[uuõK/½kaYAÌfó;ï¼Ó±cÇ!C†Øl6BeEQŒˆˆØ½{÷?þØ¥K—{î¹Çív–…ñzôèÑììì‰'>Üjµn’$ †ãÇ[,–Æp¤ð7Žãbbb8Ž#ß–DQ4*•****::šÜ„<ÏÇÆÆªÕj„ФI“†n±XȵÒëõYYYUUUQQQ111ä+‡ 111Æ`0ÄÄİ,KnÂÈÈHØhz÷î½lÙ²²²2BÀŒ›W^y%;;Ûh4ÆÆÆ’ïýØá85†ÝcÌó¼ ä;¼(Š<ÏK’$Ô aAø0,G6›­¬¬Œ$I’Ûí†}7P/¡ AÁàS%¡ ƒt»Ý¥¥¥•••ä&„Rãyž°“áóÿ©9.ÁG)@¬4ø1†aX–eY6Ø„pß@Ø$øó’$±,K¾aKã¥à€ hOŠ¢‚-á_š¦9Žƒ6×o0 rê|séÜ 8CGÕW¶išL&X*}>ŸÃá ÇORe0 EQN§Óëõ†g0Y‚16 Z­Õ¢¶«««É-F­VÓ4 ð8òzY–ÕjµJ¥cìv»].¡²MnBI’¾úê«ãÇcŒSRRFŽIxîá›o¾9þ¼Ïç{衇ºuë&뜆ÀaÇŽ‡‚ètº™3g †#Pq¿üò˱cÇìv{—.] Db{(hµZ·nÝš——§P(î½÷ÞþýûÞV›Ð„Е••~øáµk× aãûï¿_·nÇq°R5R–eÙªªª5kÖ”——»ÝîøøøÞ½{“ŸWÃn3˲™™™6lhÓ¦×ë5 S§N%¯ô³Ï>;|ø°Ç㩬¬}Úb±„ıà ¦×ë×­[÷Úk¯¡fL¹‚.‹ßµk×¾}û:KrPÑüùó×®]«R©2J2hšöx<½zõúî»ï²³³7mÚDÓô×_ít:I@¹M»J’¤V«†Y²dɯ¿þjµZçÏŸŸœœL2¸àÚwøðaÔŒ‰/--íØ±#MÓ“'O^´hlQ$ŇÏçk|™ Š¢|>_ûöíá(ä÷û%IêСƒV«õx//O«Õ’ìó4MGFFêõz„V«•å »Á<Ï6ìé§Ÿ9räSO=…*..†Í›äŒFcDDEQJ¥2::Z¡PL_pøíÞ½ûá‡îرãþýûÛ·oïóùH®M8 a3;tèК5k222,Ë©S§âââ õ‰dkñù|ëÖ­ËÊÊB8p@„Aƒi4šð\©!Î2‡còäÉíÚµ‹‹‹[»v-B¨G‡dågYv×®]ÇŽ“$©  `ÕªUýû÷OJJjü !—~øaâĉ ä§§¯^½Z¯×?ùä“$™ˆM»B˜ÅbY¹r%Æøî»ï~ñÅ“’’¼^oã=y°<ϯY³Æn··lÙòرcÇŽëׯŸN§“•™G.°fh4š^½z}õÕWÕÕÕ‰‰‰kÖ¬ŸOV\0<™;wîܹs^!’3E@ßÕ«WÓ4 d†çùægÆn·;vܸq¨6ƒ c çš?ø8ã:ØIÓ‹üü~?üÐ g™€€g$8/ž¼lp¬TnP7¼ ¢9N¤Á㨸ÀÉ8­#„ÈW`ÀÎ\¹r!tæÌ™S§NÉ­ì½eË–ãLJ7^3!|{rròÚµkå2^Æ0HK0ÆZ­vÿþý‹/ž3gŽ\›F£yñÅ W¬X¡×ë ïps:ùË_’““×­[G®l€ìfܸqO<ñDDD„,)”]¿~ýgŸ}& ì -±X,ušÚ0i‰Íf“Åan ‘‹t¹\­ZµJKK5j”ÃáU©^¯_´hB¨ÿþQQQ„+Œèªª*„ßï·Z­‡ƒ|èd+--mÈ!f³Y.iIeeå‘#G"##ËËËÉYVÀ_*ƒ´D.ªET@)Y-Žã¼^¯Çã cÜ`,A#ÔȬ©©eê!ëò'‚Çã±Z­ÇÉZ„9޳Z­°«Õ˜öpýßË»Tœ,²)–úã#,áß6H Q4uð$€‚Á¾ \+¨c DÉeu_ ΰ,+—d'Àws«zO† aßR(<Ïò©#ÌR¬†Ó°4K!Ê+zÝQ½°ëþNËÍéÜif‘öÕétï¿ÿ~zzúܹs厾0#ÌQ\¿æµã¯uÝֵ˶.ÿÈûC1…¨Ö«âââ3fŒ5jâĉrùîn#!š…p‹úå—_Þyç—Ë× n' Q~ìú§§•šÞiº„¥JO¥ 4E7nE˜‚eee¥¥¥‡ãܹsN§“0È|;JèY~^AæÍ›—‘‘Ñ qW„ˆE§ûáꇊÍJŸ5>eü”vS^ïñzHû¡ÚˆA×®]·lÙÒ·o_˜”ÍÖ¡Í/¡Møª÷ßÿúõëï¼óŽÇãã@“6 c¬d”g,g…¶^Þ:ô»¡½·ö^tbC‡^HSŒ¦Á£þÛ ÇCG¢•J寿þúücÁ‚F£ÑëõbŒ}>_34Ž¢($ ûâî;7îÜÝæ»ß?õþÅš‹Jš‰Ðø9ì8Îm!¡MÈqÜÅ‹«ªªæÌ™Ó©S'…BqäÈ‘'žx¶–&àEñŸjHEºËtWRtR’> aäI/ïÜ>刈Hdù¯”ÇàN½ë®»–.] è÷Þ{/&&fÒ¤I”ƒ¦hMÑNÞ9¸åàÎ —ŸZ~Ærfçå‰i¦4Ÿ¯+ǹsç¦M›véÒ%„Ð_þò—>}ú¼úê«M$þC$´ AˆŸ5k0Ú´oß~âĉà j"¡%J¢QaÜ8`ãGç?:k9ûJ·WžI{†¦h "2ƒßïOOOW*•Mäÿ%ô¥pyp4ýüóÏ!Eîß O(ŠòI¾8uÜ{}ÞSÐ ¯èuðûµ;vì×"˲!ú¯´"‘‚´***êäk5Pˆ°Pé­DQES4áüƒõB3ß4õ)úÙ–hã„BK±d†»±`s³?\&-S8ù²Ÿ$?ÁÃâ\6 â‘@‹êBµ -²<¨ÁÊBÙ°;*Œ‚õÿÔv†eY£Ñ(‹¿BwJ¥Òd2A”¼G8ŽóûýJ¥Rn¥àöƒ©¦Óéôz=yè*eM&y®}e!WR®²ÇFTû0a¥F£±AÒ’B¾6›mçÎäY¦¨6% ¨¨èûᅦlJr­X–µZ­EEE;vìµÇk4»ÝŽzì±Çd½‚Pc„Ýnß±c‡ÛíOYYãX+¶oß¾eË–Ó§OË…¶°,{áÂTRÛ€ ÝnwNNެ¬h¸ŠY,–¼¼<¹9 Ã8N‹Å’››F¥à'*((ë±âóùrrrdÝ1Æ*•Êb±œ;w² äîܹs^¯÷Ô©Sá9Œêñ°3 ‹-òù|²¦¹R©¼víÚ¼yóbbbd-¤Up:áUš’’râĉ “‡ Zþ¿þõ¯={öœ¹ÃPLÈ™ÐHƒù|cýB³$ßF¥Ï×/^ga þS#5¼ i|t²‚MÏC€\+„°±È"Aµ¼3¯á8N¡PI€’{e1äCk!†•Êò­z‰a…BAN–"IÒïÕÕp¼°¢¢B.i P§SÕ¢E òB2u5MDD„F£‘zõù|v»½²²’ü±00Ÿù|>ˆÖ8„;Žêêj²*…c Ãᨪª’òõûý ÖuÃ?¥¥¥]»v “ ŒeA¸çž{†.‹}€=ztÀ‹O>ùäúõëa¼½EZ´hñì³ÏÊ"Q«ÕçÏŸß¼y3¨F_ÝŒÐ4››ßðƒ?!I’Í ÷5)—ËUTT Ää“ àOgΜéÚµkð'põ¥¦¦†úõ×_•Je·nÝÈáO€7˜ÉdŠ‹‹“ Q(--µX,-[¶”‹cæÒ¥KõsÊÀδmÛvÏž=²‘"##wíÚõôÓOßu×]C‡…˜"aË8Ž+++;zôèèÑ£e‘–HK6nÜ(ë:xý¬W¯^ƒaôèÑL¨¬^¯›ýéOz÷ÝwÉsAˆ‹‹›?þÇüÆoŒ1BÖëFƒaðàÁgÏžm ;h¥Ãá ïM­ÀÀôz½>ŸØŸ¯¦¦&lÒ§Ó <ä©k€aÁf³ÙívÂz¡:‡Ãòûý‡Ãét’›P£Ñ~ÕãñØív¦Ú€²Шÿ§†±3pÌ»NR+õK  `x£k…ÐPQ#ƒŸÁ©Sœ¢A‚?ð{Á¡¸r‚ë­ÓSÁŃ?Ü`›é¨àzø†zƒâ!õHê«ÿ»&ü½ŽV*•,ËŠ¢¹Ú„oR`oV«Õã‰À)æ‡,ÒŠ¢L&SpgÁÒB¸áÁMø€!MœPhŠÖ²ZÑaš¢}¢Ï+yI|C¤™M.—ëüùó6›M§Ó¥¥¥5i ªeº)***(( iºM›6qqq$õBüÊ•+UUUE¥¥¥éõz’#+äSîÝ»Öd8õ´iÓ&99™¾ªªª¤¤ÄétÆÅŵiÓ†°—(D¹÷IëIpÉò˜OÒ$%k’I’ñB›N ëÖ­[µjB(%%eݺu&“©©9²÷ÏàÀÞ3f̘>ø d§½ÞÉ“'ŸþyŸÏÇqܧŸ~Ú»wﬓpa·Ûí?þ¸Óé„5V„9sæ,Y²¤¢¢¢ñ=Š¿ýöÛ{÷îE 2dÙ²e$†Ç+hÅe×å¿Ìp n–eŸðLÚ3sÚÏqðŽ[ðNd\öîÝ{Íš5©©©‚ 4CÒ€Þóòò^xá…»ï¾ûêÕ«EEE3gÎ$œ pöûûßÿ>räHžç Ñ`PP«Õffffee8q¢OŸ>4M2„ä¶Sܸqï¾û®B¡ø½­«a}VÐ í{µó«?üyÏ =O¶yÒ-¸IÐD&äy¾Gýúõ ñ5µÀcO™™™€Ÿ8qâ /¼ïÊ…l48))iøðá–”‡c é6mÚtíÚÕï÷gee 2¤[·n!_eÁ80==0¾²V) IñÉ¥Oûå±/ì<$TWˆ„ÏÑÀj†ªÞrS®ÅbA8q¢sçÎ{öì?~<\WBÖY¾v»=Àþ(«Á^¯W’$ © €Ë:Np@!y¥ Å<”ðиÄq-T-¶]Ú¶ðìB $€Ò%‘ã8F;¼Z­ßRÓí…pŽ€$¼§Ÿ~záÂ…6›í‹/¾¸|ùr¯^½H–S†a´Z-¬ùàµ'<‚ ­°°pÓ¦MݺuËÈÈå3R©T0õ†5#ät¤å—ü­µ­Wu]¥bT>É7Ð3ðHõïˆPDð8DÌ™”ÛÛb±”––BâÂ… &“©‰^mÝnwFFBèØ±cgÏž=sæŒJ¥Š'|‡Îãñ”––BöaQQQDDDdd$IÕ.‡ Ë)S¦èt:rg4MÓ%%%W®\ œáá˜Æ§£„%=§ß]º»ÀYð`܃çìç®8®´Ò´R²DˆËЃ 87oÞ<~üøk×®UTTLš4iݺur]|²LØ«W¯7ß|óÀ;w.--]¾|yBBBÈ)(I…† ¶gÏš¦_zé¥^xäá{pÜ”——øá‡f³yøðáäS®° ,˜1cB(++käÈ‘'NœÐjµ!; \ŸþHÖ#¯å¾– M˜ßa¾ŽÑ Ò­¸T€ {ܸq €Áo»Ëòg†!Õ™>}ú¨Q£l6[LLŒÙl& e@ÁŽ;nß¾> ç[’#IÀ׳qãF£Ñ鮄+ MÓ~¿ÿõ×_w¹\ŽŠü÷w R´[t÷‹é·ó¾V¿!­Œ6q&¯ä%9‘’ò£¢¢Ìf3 àÈ'+(¶¸Ýî„„„¤¤$AÈŸ€ F‡ †ˆ&IYXHÓÓÓ!LVk1Ɖ‰‰jk¸n7–Lœ)Zâ%Þ#zñã¤ÞHà þMó@+á©­0ؤ­0 eÃÓZÜ~ò/á1ïüÐZrüÃØ™`>%øOðaØf ‘T¶ п7²gÔo D*¬þó‡ÔÁ¡Ð4¸o@¸£þZ× úðá@Ù¤%ÁwTƒB¡pMC‰¿,AN[£N§C©ÕjµZ)+^u&“Ië9„îàÚd)²9€®eÉÑÓ‚  xØT©TFFFúý~ò`Sdd¤J¥BµïÚÊ¢Zø½IÕ@Ý555»wï–õŽN§ËÉÉA]ºti÷îÝ‹…P«ÀëEEE;wî$Ÿ¡Z_(¼Uðã?êõzò´BÈápi‰¬/»¥ÑhŽ;Õ¦MYð'¥RYXX¸wïÞŽ;fddÏà€²YYY3fÌHJJ"|pÕ.u¹¹¹6›­1ö'ø[BBÂÒ¥Kà -™9sæÜ¹s£££åòÎTTT,[¶Ln¥€D:räˆÅb™?~tt4ùÞ™%K–tîÜyĈä¤%úöÛo÷îÝ›‘‘±bÅŠÒÒRòŸeÙªªª¥K—fddTWWƒ‘\YRÒ •$„P¾Ç㩪ª’ËJZy<xqO– Ýn7 —ÊÊJ .!7!BÈétÚl¶²²2ò¸,Úl6„Ûí.--•…_eÆjµºÝn·Û-ë•Ààãwݬÿ«ïL0,IH¢PÝdƒ:T, ö£ˆEŒ0è:7ž@]ð΀ªu-ʘà/ N–ƒ—‚ XS¿RTûô% Áë( jþÖéìâ ¼ñ„j!áu¨v@Íß>\¯£ÊÖOÍÄ߀¹±ÍQ¬ŽPLËjµ¬Ö'ú‚ƒ¼ ´ÏÄ™”ŒÒ%¸Ü¢›<]îp111E9Òk Z¡cu ÅHXr‹nè!¯TÃj4Œ†¦hA\¢Ë/ùÉËF("8Š£( â5| aA–b#‘4¢¡¬Kp¹D×-ÃΠZû®:¼¿b{Cû‘-F’gKc„•´róÕÍùŽü~1ýÜ{ŽÇ•+W:ŽÑ£G§¤¤„ƒ˜ct‹Dé¥À±aÆ•+W"„:uêÔ¡CÇÓø~‰1V0ŠŸ«þç•8C©«ôÃK®ì¶ò¡¸‡BB ñë’¯3+2µ¬öšãÚ¦âMŸôü$Y“ÜxÜö‹[¯l=ï8ßÊØÊâ³ôŽê=!qäº6®)C1V¿õ“ Ÿ°¥ŽªðV´P·;Ћ ÜúD&ÄXŨÖüºFÃi´F­‚U.,0¾œ¢sõ…Õ"; 5R³jÂ:œûO:µuëÖ.]º „ÙthŠöI¾bø±ßùCòg·Ÿ-y¤üš|Ây/bñÙ”gO <‘óPÎÀ„¥5¥Åîb}ï„ñ ?0aà¶{¶}×÷»U]WIX"é+˜$<Ëϸkƶ{¶ýÔÿ§im¦¹Å[„±hà ?”ýðcù¯tx…B/ñ¤fÀ’3üïÅÿ•°45e*âãQ«Û2šF½õÖ[$)A5‰gìg^:õÒ7׿iÓöá–“>S‚p²&yûµí¯ž~5×–;4yè=Q÷ö&y%Rf–döÌì9Pq!ÔFÛ&ôÛ•³kçíož³­®­†Õì/ß8ÔRÝ2$ïœØsl9ï]x¯L§èÜV¼-Ê•¨Mô‰!N•Ðß~öCùãž­9[`)¸;în§#93†2!¢ü’¿­®í§=?UÐ otpP÷ˆîK:.©ôU†,ë“|Å>4*~”žÓª<ôè‘GgµõTë§®y®Åhc"IÓ¦M›1cFDDÄòåË—.]ºtéÒ=zzC ¬akÉV—èŠà"¦¶Ÿ:¥Õ¯ât4zJFI!jSñ&ŸäKT'.éºäþ˜û]b6x'̬2·P·ØP´Á+zÓ#ÓŸOy>Y“ì“|!Á~ÑŸfHû¾ìû5×P5,yØÌԙŅ„¯…6!TÀc¾Ê_?×÷; KåÞr6 QÑã]Uþª$MRöCÙJ=¥!íb·Û1ÆUUUcÆŒ;v¬ $a,𢽢wzêô©30Â0·|’dDéòï]ÿÇ.p¯xÅÐé)°F*"—¥/ ÜOHR[hŠöJÞN†Nÿêý/(ËPŒˆEB—ðžlA![9›MÑ:‘<|ÿ“$IðÂ'ùPí)Ç}àò )ˆ¸r0Âcr x‚Â( ó„›s~ä4>¤ü×>‰¬¿\Ê@Ù0a—½Á+‡¯¨aìŒ\ð£‡ÁÙü\Ox¤%²ª«Su€š\YÐ4lmØ=”jÀ„ÇÅÅÅ©T*¹ñBF£Óé æ@Þ8†at:F£‘[ip 8Éiý r«ÕjM&“ÙlV*•²â…ð&)h /$©”$,Ó @„„”wæÚµkóçÏ'(C)…BqèС: <˜œ}®ð{öì9xðàüùóçHyW*•ð¼MHžkOQÔ… öíÛ—“““••Eµ¨xQQBÈívWUUY­VY&´Z­^¯·ººZP(°ZÔÿÓ-ÃÎ@úOÛ¶m{öìéñxÈM¨V«?y¼áUMQÔðáÃÉùÈQ-â{×®]á-kÐÔÔÔÔ^½z‘+¨7//0¹' ` ÐØhYRRÒ¢E‹d!Ø´ZmnnîêÕ«|ðÁ·ÞzK.Çܹs fΜ٥KY9 jµú7Þ())Y¸p!9𺣺ºúÛo¿MJJZ¸p¡¬1PöþûïÿÛßþ&ëAU–e«««ß{ï½+VÈÂEHKB`g@ŒFãˆ#Èa,„Ÿ!«Ïáp›P­VÃúÙ½{÷aÆY­VrLŸÁ`X±bBÈår)•JY¼3BÔét#FŒ |h>,‚,eB,Ë:NžçF– e–À š¼øÞú©’²Á„'ð~š,Z²Àá°AÒ’F* °…ˆ¢h±XdQaŒÁüÂò- >`;‘uœ‘AZÒ K gµÁ܆ö¤‘G#ïñ‚Juz¤Ò™ÆiQƒ“lÏÇ«lã8÷àh…d¤F ÑûäɤG©ù‹(Šn·;ŒS€žÓ3CN§=fŒ±Ç㑜U(r'A çʹIeu¬Ž£9¸×óišÖét0G!ÅÕãñèKÄÍ­T*>üÙgŸUWW§¦¦Î;ÒI;a†bœ]mÍžœú(9_-(ëóùäÒ³Xаš“Ö““ž<öàØygæA²|H+‚kÉ`0lܸqÒ¤IÇ_»v-!ã‘ Gvà¼Ôxöh@$,iíe?œ´žœÓnŽWôÂ/e½p|ƒKš° “É”œœœœœœ““³wï^òƒ? }÷`'–b_kÿÚ¾~û2ÌìÓýë+_ŸµŸÕ²ÚÆAÀ:e6›?øàƒC‡mÙ²E«Õ~ðÁ„OzAµZmLL 0‚GGGkµZ¢î P~M¾Ãé˜plÂóÙÏsjîãK¯º¸*¤VÝ¢¢¢ BH¯×GGGN#†aJJJFõý÷ßÏ™3G’¤ÌÌLò­T£ÑÄÄÄpP–üØBÝ¢•¶U[]ÛDM"‘W$¿ „xžOMMMHHèСƒÉdª©©!܆‰hô4ÍŽ;6mÚé&LxôÑGÇ׸Sƒ¢(¿èï×—c9­¸ä¸ôUÁWéæô¾Ñ}ýRèë¼Ê8uêÔÓ§O#„>þøãŸ~úiÁ‚F£±qêp¿üòËÅÅÅf³^»ÿþûIÌþ³o¾ùfãÆEEE’$M˜0aìØ±&Lh\Y€ëu•;+MŸæœ¹•¹â:´7´ `7ÓæÍ›?þøãnݺ\½zõá‡6™L$~TRºx;8##ƒ¢¨’’×>D¢;:õŠè¥a5§l§Š=Å·züÞ¨{+|„q‡Ãa6›Ûµk)ÂÖ ‚¤3v»½OŸ>ƒ êׯ¹#výûî»O†²å=)º”ÿió?Gª Mk7íÑÄG#!ñ4M»\®|Ðf³åååµnÝú±ÇûÓŸþtË^…CÚØ±cŸ|òIpBrçr¹HüŠì öáXeìW÷|å„öƒ ±~ýz„$4Se±XB./@2lذGy®ö^¯x§ •}øá‡üqYÊÂ^¨¢U·züÙ6Ï"„xÌ»¢”šuãË/¿ $>ŸüòF: N'aT%Ñ¿ag($!©ÜWN#šwƒ1.//¿¡¹deàÏ‚Y Gr‡òÍ(‹¶óv@h‚wÜ%‚Õj ÖÔÉÄkDd<¯r“ïlc¨È%lîÓ›iðM• ‚{ÉëŸp_Âj;#ëðÎÀÏ„ëx0‡T+„£/˜ÃEVYP0¸¬,eeÁ‰J®l0ÉŽ,MÊ’fù2 çxòø Е!„”J¥Ñhôz½äñB£Ñ¨P(PX<z½>¬Óé ƒ¬/)AYò•6€B) YÊ¢Z§B¡U)’EZ’žž®R©RSSex±1fY¶¦¦¦¸¸8::ZÖ›Màá½víZuuurr²Á` §9§TAA×ëm×®,ÆwØ{.\¸ž²v»½¨¨(**Š„™±~½ ²¼¯ÁÊž>}:øÁŸº&ìÞ½;¡ó¥~ã·ÑÌea ‡÷ ¯ìÍ4ÕRÏ„Wa˜ìììL"Ip)‡·™ž¿”[ЕaWz3 n~eQÐóká58222¸ÍuáOññña|õiN©ª»Ëeà¼#Í/!lÍÃ2zGn¡4í«Øw¤äÿÅyÏ#Ej%tEXtdate:create2017-06-06T01:31:11+01:00¨:»%tEXtdate:modify2017-06-06T01:31:11+01:00Ùg1IEND®B`‚puzzles-20170606.272beef/icons/filling-ibase4.png0000644000175000017500000000144013115373727020306 0ustar simonsimon‰PNG  IHDR……‡ô&gAMA† 1è–_PLTEÿÿÿÀÀÀ€€€€&Ë;>bKGDˆH oFFsNŽÚµ5tIMEáò‡» vpAg²gÜŠIDAThÞíØav‚0 `ÄÀÀhË„q€=ÌýÏ´úæIjZDŸÂÚ_æI¾²"Y‹th¸K– \7b+åšØ:<¨ÝHéO6¶o”ªá›‰ázaìu£DÄãÄ0!ÃèF‹Ö’:>tª1Œ¬N{0ª'c†©"ëGÈ€c̰?…Ü6JðÕŒ±ˆ~Õº1,5ÚS‰_‘~œ7ˆÖ¤ûÔo'¨fÅ@ÿ¶aƒåÜŠ×ðìgcíÆkæ´:æ¡8Û7RçÍH?4#uþÐŒÔùC1’çÅHž?#yþ¸m¤Ïš‘:,0®ó‡º×çÆuþXÃs›-ò=®åBŒ@O±§9<†^¢´Ì`1XÙ‘~¦ÝùǦ&†]lô¾NnXV»Œi?0´Çf~ŸöÒø]•¯âÙÏÆ›|ñœØ÷Ïš?î©C¿ßxÜ|îš*ÕL˜Gˆ%tEXtdate:create2017-06-06T01:31:19+01:00›Õõê%tEXtdate:modify2017-06-06T01:31:19+01:00êˆMVIEND®B`‚puzzles-20170606.272beef/icons/filling-ibase.png0000644000175000017500000000353713115373727020233 0ustar simonsimon‰PNG  IHDR……BËgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<‹PLTEæææÏÏÏÜÜÜ<<<¶Ó¶K¨K“Œ’9¡9£Ë£¾¾¾YYY---eee’Ä’‹Šo¶o¨¨¨··· ÄÙÄŒ–§Í§ÝâÝ×àץ̥µµµ[[[ˆˆˆZZZããã,,,€€€a±a¯Ð¯nnn|||EEEÍÍÍ$˜$q·q(š(’3ž3“Å“ÉÉÉ Ž v¹vAAA„„„E¥EØáØ Ž ±±±¹¹¹»»»§§§222ÕÕÕ“G¦G­Ï­¥¥¥D¥D©Î©´Ò´˜Ç˜S«SäåäÊÛÊàäà¿¿¿www‹Šáäá{»{%™% =¢=ªÎª¶¶¶KKK999£££’’’oooÄÄÄÝÝÝ×××aaa¯¯¯$$$qqq(((333“““vvvØØØGGG­­­DDD©©©´´´˜˜˜SSSäääÊÊÊàààááá{{{%%% ===ªªªÆÌÆ’6œ6ÆÆÆ666 ¿ ?Ÿ?‹‘D¡D¦Â¦[¨[w±w©Â©¥Á¥Š •»•ªÃª¼È¼Ÿ¿Ÿ • a«aÍÏÍ(—(s°ssssl®le¬ep¯p¸Ç¸ppp???¸¸¸ÌÎ̫ë&—& Ž ²Å²µÆµ Ž ’§Â§::w²w:::”“¦Á¦¨Â¨–¼–-™-ÀÊÀŸŸŸ¦¦¦–––ÀÀÀ¼É¼K£KC¡C•¼•{³{•••$–$J£J„¶„½É½;;@Ÿ@i­i/š/ ” V§V³Æ³ÿÿÿ5Ù#ÒbKGDØ G® oFFsNŽÚµ5tIMEáò‡» vpAg²gÜŠ§IDATxÚíÚçWÔ@ðÌY(Œ¢Ò¬ž ÄŽ`ÃŽ‡]±wE6TDlØE,ˆÁÞ{ÿw<@Úy™ ÙÜËÝcçcæ%óKvßæ2·’¬4€ e××@ÁÚ\E†Ý< .…6óF(„B(QQ¯>@õІNœ7i*£hÖÜÅ [ÑxnîX­dek%[ÑÚÓ‹CÑÆÛ¶kïãë+£ðóè @ѱtæPtAìj™¶˜ Ý (˜CÑ=zöê݇OÚ7˜G†åÑKÑH< găFgÅ 0,b¸:ÅDóĉ8ŠCUùÃ#@b4âIrB«§bâø £1z’uE°Éd^bL&æ Î3/J#l2Nq«–®±^TÜeˆMS§Mwž1sVõ´:Y¥öyG~§ …PEU(ûf×=ìèYØT¡,/B!Ž¨Ðº¡N¡uÿB•Bóþ……öý 5 íû*6è_¨PØ Q{…-úµWØ¢¡ƒÂJÿBå ®qÿBÅÿý G~› …P…P ßÔê«(þf×=ìèY(è;q)”õµ„B(„±²û#+bãfÇÏ™;OFAí¿¨:$»?B©"Á³ì óeÔþ‹ªC²û#*¸BxäÂĨ(µÿ¢Æ8ò(,fÌ‹@Û+–@ÒÒäeËWè«ý÷–\©«" hU¬Ä'ê©X `ž˜kÖê©X°^’â6ð(d÷G(TlØ´yK ¤lµ® ö_T’Ý™ PQ:¡©°-AfvR;4TlOÛ¿s×n‰Ka%êì;U(„B(ìW¡{……Â@œ+¯äúB!Bᘊ=éˆ{‰*¬ü¾ýä3Ò‡Éd*Ž"]…•÷B‘Uþ7¼÷1†"ûø ² +•J(Nf:sñ,­8w/PUXùàd¸H(ÊââeZq3r©*¬üU¸–G+®çßÀ›·HÅmcA.U…•÷Kº“G+ ÍÓâî=‹ó-÷ñªÂÊ?„­xd43Šò)E>..y‚ø´ä™Õ*¬üsxñÒ》ÇkÙ1¼y‹øŽR¼ÇŠø`µ +ÿ±òwKš¼ÂøIWÅç/ù_3¿!~§e‘K¯JÌ<5/ Ëï¡ XWÅŸEîÆ_¿ÿXœo¯o3¡ ¡ BÁ Vîóí¨s`Ï‚k\µÈÿÔ4±V‰Ì%tEXtdate:create2017-06-06T01:31:11+01:00¨:»%tEXtdate:modify2017-06-06T01:31:11+01:00Ùg1IEND®B`‚puzzles-20170606.272beef/icons/filling-base.png0000644000175000017500000001306013115373717020051 0ustar simonsimon‰PNG  IHDRÓ?1bKGDÿÿÿ ½§“åIDATxœíÝkPSçÖðÅ-B Ê%ŠÅb£R­¨eÚŽëÔZD;^«£2mí¨µ‡/^ƙҋԩ:ZZ-‡ŽŒV†[ªÈ[ߢÑB£( ƒÊÅK€lß[óæh¤€Ï“dçY¿Oa·¬ý¸ÉŸM²×rÒh4€«œm½„l €˜†@Là ¦aÓ0ˆiÄ4 b1 €˜†@Là ¦aÓ0ˆi®ƒú¿•J%¥u DÐÀ?ägÄ4 bÚà^™Ð»L©TR½I ë;pý!¼DÇ3b1 €˜†@Là ¦aÓ0ˆiÄ4 b1 €˜†@Là ¦aÓ0ˆiÄ4 b1 €˜†@Là ¦aÓ0ˆiÄ4 b1 €˜†@Lbs\â›§Òžr@»¿,= §A-d Aø³š­öèV 0ŸþQú' aýl½2ù믿h”8q"²ÖÇÎñÁ‹`Ä4 b1 €˜†@Là ¦aÓù>ÀŸþ¹{÷îêêêÛ·o ooïI“&¥¥¥ÅÄÄ©ßÑÑ‘••uéÒ¥ÚÚZ½^[·nMNN&RÜ Nž<¹dÉ’'·ÿöÛoãÆ{öú´Ï©S§ *++ÛÚÚôz}@@@BBBZZš©]˜2UUUEEE¦/oܸñóÏ?Ž?þÙë·µµåææ>{GEûøùÜÜ܈ÔW*•6lš鱎èèh©TêáááääD°,íãóå—_Êårþ±Ïš5k¶lÙMMMÄ÷%ì‹`ƒÁPSSSPP2™lÁ‚¶^‘}yñÅÇŒ²`Á‚òòr[/g LÏ~^ww7ÿ $$„ø¾yàEEEuttð•Jåwß}Gêï0îß¿z½þÌ™3gÏž=tèдiÓl½¨ÁiiiÉÊÊ™L¶xñbâõ|Édb±˜¬ÑhRSSkjjl»$;¡T*·oß~úôék×®•––&&&€Á`øôÓOm½´Á©««{ã7ÚÛÛÝÝÝ¿ùæ___â»pÊÊÊ®^½ªV«çÏŸ·nÝúüóÏm½(»µbÅŠ1cƸ»»ïܹ“ß~áÂÛ.lPÊËËçΫÑhd2½s—€ÀóññY±bÿ¸¡¡Á¶‹±ƒÁâ—...¶XÎPüòË/)))]]]þþþ?þøãÔ©S)íH×iii3gÎŒŠŠ1b„F£ùì³Ïøí£G&RŸã¸;wî€Ùå—N§ëììó¿*Ú­åË—GDD¼öÚk£GÖh4Û¶mã·O™2…H}ÚÇçûï¿ß¼y3Çqr¹|Û¶m÷ï߯¨¨©TñìõÍ ñž`ÛÞòg~ùkâåå•——ÝqþAÿwÀ‘Ð @FFÿ윣 G×—­7>0ò_Þî¹]ÖS¦©"œ?`?(àÂ… ðôôÔétôöBCÃ݆ g7ƒ¼‚2&g¨Fªôœ¾òV%©ú3ÀÐ €Ñhܸq£ÑhÜ´ißÜ]@¾­ùVÏé`Wü®É>“@ â™Ê™¤ê;Ìü@ë"xÿþý—.]JLLLJJ¢´ zN·ž’Ö’Y?ÏŠ9“t<)ïZ=É@Q9477ñÅ^^^üàÁ¹®»=ƞ̪L~Ë­ž[·*šï5ýM—†£rؼysww÷æÍ›ýýýiÔ§ÍÀ=l§œXóvMák…ž®žY•Ù¥ï²éÒaäpþüùS§N½ð —/_®««ã·ëtºË—/?ÙÔÖ wÎ?X:v©ÌMë;Ýo:ôq}ÕÕ6]"Œ|îÝ»ÿý÷+¯¼’˜˜¸páB~{eeebbâ±cLjÅÃyîή=pwq·ÍšøN°óCçóŽ\=Â=àZî·œ¹qä"ùÅ„g¯Ïq\gggggçcýõùûÈšÈ_Ïœ9Óü¯{­­­qqq ¨w‚“G'ç_Ë?Ñr"ïZ^asa¯±—{À9ÓöIÛEÎOm~?p7nÜx¬¿~FFFFFüS}Dž,ûú¥¯Ó'¦‡Ëà œAâ*™î7ýðˇMgä0¨ßìïï/Ä·{ÜœÝÖE­[µŽFq¥RIé¦a4Xx@Là ¦aÓ0ˆiÄ4 b1 €˜ÆVs\«a§¿þ ð̓íªG7Î@çئ¾Ðû냣ŸÃ—@$1Ø_hìg~^#¦aÓ0ˆiÄ4 b1 €˜†óžŠÞ|Ú¢~ˆêèµÐ€,X\:·Ôúë,kÎOÀù–Q`+nÎn¶^€Xs~ΰ€ö|ÚrgçöûL_i8’óŸH-ŒNÝÖœŸ€ó, =€6SkGàpi¥i r- _b»E ‚5ç'à| i>À‰–Mw›`^ȼ‘â‘¶^ŽÝÁù8Ò|€¬+YüƒwǽkÛ•Ø'œ`Ą̃j¯:Ûv¦ùM?|¼­—cp>€3 «ýÿœ`cÌÐvkjü B¥¡/zÙÖ˱SøN°´çXGv]v×+Ç­t'[/g¬9?çX@{>€ô{ÿ]÷o‹ä Æ,°õrÇšóð `™Ðçä]Ëkïm€Åá‹ù+xdΰŒê|+H KM Kµõ*†Èšó𠀘†@Là ¦aÓ0ˆiÄ4 b1ÍNÛ£c÷ãþQú'Øa÷æ¡øñ±Ó ô,¨Ï  ÏýÃ3)C €ýôw·OB?>´×o?Ç/‚Ó0ˆiÄ4 b1 €˜†@L£òF˜5û»Ó£V«÷ìÙsîܹÎÎN™L±víÚÙ³ ´G§}|¢¢¢,6 .-%0€öúKn–¼¯~ÿÉí?Lý!Ì+ŒÔ^xT`Íþî”=ztýúõFã£ù·o—••©T*"°Õñqs#3À~¾&T`Íþî4444lذÁh4edd¨T*½^_YIl>íã“››Û×g6àÈ‘œœ Õ©Ûj?߯&~%w“›¾ ô $¾ *°fw¾ýö[þ̾k׮ɓ'€X,ž9“Ø|ÚÇ'&Æl>Ç¥¥¥€H$Z²„Ì|«ý|#e‘‰»‹;½ÎvxlÁéÓ§ÀÃ㤤dÖ¬Y111IIIyyœpâDSSÌ›7oäHÍHþ#yêoS§üϔի+;¨Lè±ÓOƒÚÖõë× §§'3óÑ|€[·***š››?ø@hó²5ˆ~Wx ¢uè9ý¹ös{Ÿß«R¨ÈîÏ æ$&ÖÔÔzzz@fffW— æTU={¦M›6~¼`æøzøn·)?>¿|vyÁ‹/| ŒŒ{¯î%¾/ €Ç?š°t©L&‹>}:ôõõUW j>€0ý•Ž]¸0X,rzn¿…ß^}‡üÁÇX`ºˆtuu}ì»»pæhµ?ýô„††¾ü²æ˜¦Óò ž)<]©ÀšýÝi˜?ÿÑ|€#G8Žkii9sæ Èåò ̰ÎñÉÎÎæÿºråJ''’E¡½þõêõ_þç˪®ªv}û•»WþUõ/~{œ"ŽH}sC¼'¸ÿ;z4ÍcýÝMúïïnº£Çæ·D.[¶ìĉ ‹{{{9ŽsrrÚµk—)O+Î?°ùñéíí‹‹koo—Ëåü5Ì?²Úúû¯¿ìü2u§ú±^®^&—†÷óCxþàK ˾þúëôôôððpƒÁ ‘H¦OŸ~øðáþŸýv%//¯½½/^<Àg¿ýX3fÍÊ7‚=ƒ%.W'W¥X9/`Þá)‡ûö •3ÀÙÏ`ÈÅù=>V[¿ý< ¦aÓ0ˆiÄ4 b1 €˜†@LÃöèÈìç0¼!Ù€ý´Ç °Ÿöèö5&NœH¯8íú´?ë¸~Òð"1 €˜†@Là ¦aÓ0ˆiÄ4ºo„u»ß,}³µ§T Õþ¸ý«ßÝýæ›o¶¶¶€J¥Ú¿ŸLý 6¬»[×Ñ×aà ‘"fXÌòå‘ÒHAԧݿߚóèžöÔïáŸB­¿gÿì'ëÊ+¿ßü½µ§µÇØcx`hëm+Ö/=·´în ê;Šg€ê;Õ¹çŠ]ÄÝÆnAÖ¯®ÎÍ͋ŦöO¤y}4ö£8EœÂMÑÜݼµzkãýF=§?®=!°ÿú&´û÷[a>­3ÜöêípkǬd}ŽÛ¾};Çqk×’¯?">%(%Ü+ÜÛÝ;vXìëþ¯óÛ]Èü>¢]ß$Rî>A>!Z-vw&Ü7’v} €œÆœš»53FÎHôMdýœœššš3f$&R©Ï3>0Öß«/Ò€ÔUšäOf‚‹ÕêÓîß/Ôùšn;†}WÉÇã>d}fß¾}‰äã©Ôç%üoBWßÃfë~~™±™dOñ´ëýþýB°ãÊŽcOZX𝇝 ëïØÑÓÓ“––æëK¥>Oê&õpñàßè¹±®r]ý½zAÔ§Ý¿_ØóÔêÒÛ¥â€çäÏÕÞ­m¸ßÀoï6v×Þ­5ýN²ßújuiii@@ÀsÏ=W[[ÛÐð¨~wwmm-ÁÇ^J#3Av}sx°Ô ÔÒۥͺ殾.7g7?w?•·êÑïú M»þš1k~mýUÝ©¾Ù{³—ëõñ𙬘¼2d¥RL¦iíúæ¨À×Ã×ü¶ðêûú¿‡uUè*R¿ŒmR_¥Pÿs¤5ë›ÃOƒ"¦aÓ0ˆiÄ4 b1 €˜†@LâaTÛ[ÓëŸÊ/Û~zs–Ð×o‡p@r@‚a?ýã‡×ÿ4Öiï>pö5@è?`\¿ààE0b1 €˜†@Là ¦aÓ0ˆiTÞëèèÈÊʺtéRmm­^¯€­[·&''ߥù´×áÂ…ƒÖÕÕutt …B³|ùòÈH2ýûi¯Ÿú|€’’÷ß·Tÿ‡ÂÂÏ €¶¶¶ÜÜ\•Ci>íõ_¹rå÷ß7ß]qqqIIINNNDöåV;þ€J¤Ré¢E‹¢££/^¼xèÐ!»šóh¯?((è£>Š‹‹S(ÍÍÍ[·nmllÔëõÇ'ë°Â|€¯¾’ËÍê’Ÿ@%J¥rÆ 0˜Ï$ –ù|€/ê¾ [œöúããããããùÇÞÞÞ¯¿þúîÝ»ÀÕ•Ìà ǟ)‹”¸HÜ]ÜÀ‰JýÈH‰DâîîîäD¥>Øí‡áþ‘ù|â°£ÑxíÚµ¢¢"J¥II„û÷Ó–üG²Î 9‹b‡Å®]ýüðç ×ONÖét"‘(66võêÕÏ?O¸>4´çXGBB‚©×´ŸŸ_ff&S’óè¡>`ìØ… ‹D¢ÀÀÀ-[Õ¯&?@x0Ÿr6emåÃ!vü|€“Ú“6]Ý y{{›45‘Ÿ@ƒñÑüKòóŒÿ]ß𨾳@æpwçÎ0 Õét0lØ0{$‹öúÓÓÓãããÇŽ«P(´Z­éÌ>j™îÍ´×O}>Àúõ¡¡¡³gÏÐjµ;w>ªG~>Àï îÿŽ$Fß֟T^^.‰žö¦;’~ÇÓ æ °>íõ›_þšH$’¬¬¬þß ¶“õ/;¿LÝ©~l£—«×IÂ¥áý|# ì–ÈeË–©ÕOÔ÷ò:pà@xxõMëü=ÁŽ-55µ´´´¹¹¹««ËÍÍÍÏÏO¥R½óÎ;¤Î´QŸ°fͯ¿þªV«oÞ¼ÙÛÛëãã3yòä•+WÒèÉ@ë0z7>?†Æ|Úë_µjÕªUû÷Ó^?õù*ñ?w>ð.‚"€˜†@Là ¦aÓ0ˆiÄ4 b¶GGhàÏj< ¦aÓ÷!ƒgÄ4 b1 €˜†@Là ¦aÓ0ˆiÄ4 b1 €˜†@Lû?â%´âXAIEND®B`‚puzzles-20170606.272beef/icons/filling-48d8.png0000644000175000017500000000321113115373727017624 0ustar simonsimon‰PNG  IHDR00`Ü µgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<êPLTEåååéæéçéçìììÔÔÔòëòòòòÃÃÃ$$$§¨§¤¤¤«««ŠŠŠ„„„---222 ===tttÛáÛר×ÚÚÚ¸·¸”””¼¼¼´´´¼È¼›››KKKkkkûûûýöýÌÌÌÑÏѕƕ£Ë£yyydddY®Y;;SSSBBB,™,mµmD£DçÝçQªQN©N¯Ð¯´Ò´›È›4œ4v¸v„¾„]]]èÝès¯s¹Ç¹t°t{³{ÚÒÚ…¶… Š Ÿ¿Ÿ&•&Œ¹Œ¦Á¦µÆµ«Ã«f¬f’ºS¥Sm®mÿÿÿ%mbKGDM€h etIMEáò‡»œIDATHÇmV‰zÛ6 æ%Ê-Y‰%ê°,•jìÖiã%Û²yíêl]Òîzÿç@êð¾ ¾ Á @üÀ/B(™„]^À~ð5©N™uêØh¢£?è 8þ¯EÌ·ø…Í­H<€£ðåtA¸†F Šd”y?.”ŠPô2ÖQ„ºNViš€¤ÉUš¦×øY¬¥Ï‰‡I–çFä9)4É1¹ÈJ] õ¦ÄÕš(jêm+}nA˜B.¤ã”‡•d(4PDrùêUÐÙ °oÛnL)ÅÅ=ã›BúZp•3’¿¾c"¬ÝÅš½w D† #²¼ª% îkÇ#Â7oo8¯ÀA´©°ÙäHPnKÉ«" ­rÎß½¿Ë$F0ÕÖØ£s ~}»ZsˆÌ)'"ôbÿЗ’CÜíu–L{À”`äÛŒº”lÔhKÀ!s›–X%Ø;£2W%© Ü 8ƒ”2“ €ÛÎ{€Ê9!uM­±î ¢éqptH#¾*ŽAA]íw#Rå"dµ“¾1%èl[uÌu•ÔFú^"zP:@u.Á_¨”uèM‰a6L4t0çÖ`$°iÅù¦«¤ ãß½yM©‰øèPñ ¤Y¼˜öÀ±àîî{t`4n56ô’T×Én@zÄ>þð˜1Áá[Mái&ê-´FXË9¿¹ÿ‘’‹”ŠÙ¢B/jy$ ˜¯³ãÑU„ eíœÈ®;7£¼ÓDJVIôh¡‹Å —VíºY¯OqXT›ª*¸®Š dSÖ`„÷îPÂt¹ðöaÚÃûÔ&' +ÐA‡øÿ*lÀ¶S»ØOH'Ì ¹n!%˜M—:P  ²’éÖ¾ù("m­Õµ Í~?6$"ͪªŸôÖªÚZsBß|8…˜BÒú–‡¢ƒƒŒo†óÐ÷θŸIŠ[˜ÂvŽ8$‡7šŒ8ÓÆmÂ¥$ 5D6;@/Ém›éHŒ>÷ ìîT 7çtŽq»®Yhl¼qÚ„ÍrXd?ìi†Aµˆ›éÞd&44“ä¥Ç±õt,‘ù`ª¡¬‰ XéÌ|ö*qÄ›¤×Ã<.’A2öÖôêvlåp¡•“z¹Ô8ÒJi˜i7ûz9õ²œÈä&ÿ ؤöÎ 5±†€ÍêxýF yCo?|ì…Ž@«î­(C¬f)„B"ûôac…ÖÍ8úà…çb0§áƒv¼ocØx0™Oÿ=:°ÿ1²ñØ1ŸP†;Óñ„úK÷êÏãɇg:U†¥½å>pmð´g„±%tEXtdate:create2017-06-06T01:31:19+01:00›Õõê%tEXtdate:modify2017-06-06T01:31:19+01:00êˆMVIEND®B`‚puzzles-20170606.272beef/icons/filling-48d4.png0000644000175000017500000000135713115373727017631 0ustar simonsimon‰PNG  IHDR00¥,ä´gAMA† 1è–_PLTEÀÀÀÿÿÿ€€€€€€ÿ!T¹bKGDÿ-ÞtIMEáò‡»IDAT8ËmTÍzâ0 ”£ö.ã1Üc+ô Üw?úÝ÷†É ¤?& vÆ#F¢h#ØC‚D‘6Ô1)óˆk¬ƒƒ?ñ†!B"™˜¹ T[C’ïé‰í u°1’SÁ H`ˆ}¦÷´3@†°2Òãx4†Æ]-±´Ã“^,Tß©ÆcÈì¡ò·Ãů~ Õù«r3Ô>€åŒ5S7Œ õöÍd†äÁVø˜@ £$ìúâUÚD]¼zœñtg±„ÚJÞÜ„` ·DBÛn–”µP°$Ä%ôyY¦OK|›hY§Â¦´ õÍ’Un·©ù€ÜZët¬g‚3hi>¾5ƒ¡ӞРw £½¨…Ô̤ý3ÔK«¹ÄûŸõ¨D¨òß…1—¨Ôµ.!#õnHLÙk~6ÆÉK¨t¿ð§1ø@´zu+Ö>Ùk.Å«*~vÉëOUäª&K#•ÖpÞWѺ¡¦[Õ!g-a½çÃp׌Ìë©b}œ«æ¡êéªG½æ `‹iÙ ûw=ŒÑ%8ÞûÔU©H@-]5ªþmg|’‡zq†bE¯Î scðÕ€i¶¦~CO:ÐA‚ÑÄܘíàÅ5­ªè‹*ˆ\€ ˆ¨hÜÍ:²žffUÆóV3.Ì“ÛGΣŽÚ•ö¯ôËøA Vªë”òÿ%tEXtdate:create2017-06-06T01:31:19+01:00›Õõê%tEXtdate:modify2017-06-06T01:31:19+01:00êˆMVIEND®B`‚puzzles-20170606.272beef/icons/filling-48d24.png0000644000175000017500000000622713115373727017714 0ustar simonsimon‰PNG  IHDR00Ø`nÐgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEáò‡» ›IDATXÃÍY[lTÕ^·}ß3;í)mkÐ@r¤*`#ÞBŒ–c|1 ñÅø ñÁðЀ`à]C0ÑhŒD%Æ D4"Z’«0-‡KGZJgfß÷ºœ‡†ÝÝiAŸÎÿ0Ù³×^ÿþÖ¿þõý—¯\¹‚þŸ„dÿ(¥þ™¥Ô2sÿ–ZÖ¼ÂkšÇqkà„ „¤”-G Ãàœ·%„´T‹1VJÚ€0ÆišÎÎÎööö.^!$Žc¥”ã8RJŒqnôòåË¥Rɲ¬ìhsbµZ]µjÕb;aŒã8B¸[€”R¦iNNN¾òÊ+»víÊ-F+• ç|Íš5QåY–µ{÷nÏóÊå2ç<( Ãéééûî»/H)¥iZµZŸŸ§”.Ø2!„®ë7nB4ï€ImÛ¶m;Žã 6ø¾Ÿ$¥´mûÕW_ííí-‹RH…”PcŒ¶,ë?þ8pàÀŽ;8ç !D)B”ËåƒzžgÆ 5w”1v×]wqÎaq¥R©Ñh$Iâ8N¡PÐu½T*1Ʋ€º»»7nÜX.—Ó4¥„ºšË%÷ÏqÛ¶]×Ý´iS’$ãb±(¥ô™?2u¤×é}ºçi)¥ïûBÏóÒ4E}òÉ'¦iGQV7 cÁ!Èy¼£P(=ztÿþýÕjÕ0Œ¥Wv"!diÖî±Ý_]øJ££ “«3hšV«ÕŽ9BnJÖ6-¯¹®ûóÏ?÷Ýw<òH¥RÉ™t)QHDbÿví·;üøIƒbÚD,¥4MsëÖ­¥Rɶí¥È‰,¾%¥Ôu}õêÕ“““·…rã•K$ b<¹òÉé`šF UH5× npøðáñññcÇŽY–ÕÓRJaŒ£(Z»víàààË/¿\.—ƒ ÈmóRB xðÖú·N]=µî®uµš{ Tž$Éã?>44îß’ßÂH)gffî¾ûnpgÆ¥”B)…‹ÜpÆXªR‚É–Õ[B&"±˜E)eŒ9Ž“¦)ÆxóæÍcιïû®ë†‘ó–µ¢^¯7y¨I9œsÏóâ8®Õj¾ïçŽ=ç<‚F£ÁB(¤æÕ<ÆXI%¸‚Àó¼3gÎg‚Íà¢\._¼x1Gâ·,D ‚àäÉ“`I`&ø5 £R©¤iÊ9Ã0È0Œ‰‰ Îy¡P¸ÀuÒ4mffc|àÀ–L $ÇqÓN·ˆQQ,Ÿ{î9°À"„(¥lÛãxppÐó¼ Çq0Æ?ü0„©$Æ#Œ¢”6ÎÎN ž\ÌqçÌ™3I’À2Zø”2 C >MÓ Ã‚âeÇq‡a¸ØBã$I¢( Ã0å©ÍìXÄ\rŠ)¡$Š¢$IÂ0Œ¢(7Î]ÓCnžŒ…N sǹtéÒSO=511aÛ6ºÉld ¹1#GsN^=ùæ©7^<ªQ ß™,yÊš°’$ùæ›o|ߢˆ1¬‡²|?#L':¨ÉCw.yb„¸ñÓO?;vLÓ´'N ›!eyQHa„¥’6tn8øŸƒ×ã댰ÛN¼ È`Ö®]ûÆoôõõõõõÝ6ݰ+ÂIJèëÿ~ý÷Úï[ïÙZÒKBŠ;™›•ûì³½{÷†ÑT›ÿ»kƶmÛà|¡;“fNøÅ_tvvNLL€I²j-ËÚ¾};0#……È?66vñâÅsçÎ1Æî¤8‡DE×õžžžÎÎÎãÇû¾Ÿu„çÔž?^Ó´–j[$ùÛÆÐÐÐÔÔÔIÓtÏž=¶mïÚµ |}úÞ{ï- 0˜ clšæ¹sç:4:: +J „&H!ˆ9mmmÙ¨’7þÀÀT‘6­Íã^"Çq éÝ„‘IM“˜µ´혹¹¹x Ù¨(‹PèÀDÛ¶’$!˜´FØç>¨Ã,×l€ÞÁ$‘É{ÿ}ï™Ïô˜= Õ€ÔØó<Ï÷\Í=U;5v}ìÅÕ/ )¤”qA ëz’$®ë~ðÁííí›7on4a‚ZžòD&O‰èÙîgÛµv…T†¹n‘ )¬\Íýþê÷ïŸ{ÿZrÍ Æ­ì—`F™@⣩¾ºô%”@?cà!×u+•Ê»ï¾{öìÙl®‚ɤ»Óìüzúë_æ~q5a´8§^”Â*é0çôÜé³'ÊSÁ4ÍÑ+|8õ!£¬h«Q5[ÀCewèС™™™¬«b„¹â%½tsNtFØRév«fƒ’&5û쾊_¹^^À Ç2^i­Ô±~¾qþZrá¥fš¦kÖ¬™½páBRÊ$æ¤?ùýÕï-jÕÓzvKòB)аßîßyßÎz_(i%Ÿû3nÔ˜"î~¶ûÙ)ª×ê Eh#F9皦½öÚkÏ?ÿ<8G¶»•ª´Cï( <ÖñØýÅûëiÝÖl´(\ˆRêº.h PÐ_îJ)€â€W4ª*@õú™0Ä(¥š¦9Žsƒ (—Ë”Ò8Ž]×µmc ¼jRó±=&E MÓrN½Àà¾ïÿú믷z(73Qè‹ÅZ­¸aÕa4MÓ¿þúkll jûì¢i8çµZ Š»ëè:l=Xtff¦ï‚@=77·ÿþÅL­ëz¥RÙ´i“eYõz=Kö÷ÓO?ã¢i¶-Ì«ÕjRʳgÏæ^,¥,•J_~ùe½^饗n¹)|릞ŸŸïééÉ;•R”Ò¹¹9!DGGÇâ\2==ÝÞÞnšfËÆùììlww÷â8 jYs%¸ùñv2ßÎÏB(Èš¢ëú2Ÿ–R Q!”µë‚º ZÉ-Á—ª7à}-ç.£²x´LèX¦†_¾¼ÿÇ£‹‡þ{Ö(9Iu_%tEXtdate:create2017-06-06T01:31:19+01:00›Õõê%tEXtdate:modify2017-06-06T01:31:19+01:00êˆMVIEND®B`‚puzzles-20170606.272beef/icons/filling-32d8.png0000644000175000017500000000212713115373727017622 0ustar simonsimon‰PNG  IHDR D¤ŠÆgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<ÆPLTEäääêçêæêæëëëÔÓÔáÛáÛÛÛÌÌÌÒÌÒÕÜÕÜãÜóó󶸶[[[ÃÄõµµ›››¤¤¤¼¼¼dddTTT$$$;;;|||lllüüü»Ã»ñîñttt§Ì§–Å–¬¬¬666D¡D`°`ÍÒÍ”””LLLþÃu¹uU¬UDDDÅÍÅ{º{+++„„„t¯tÛÖۣģ»Ê»™À™·±È±à×à1š1–½–œ½œ+˜+j­jZ§Zz²zd«d[«[®°®ÿÿÿå[žÎbKGDA‰ÞlNtIMEáò‡»ŽIDAT8Ë5T‹r›0üøñ#B€¢”QJ]×½qãÆË—/MÓdŒ !ø€ !c! ±Â÷fïýþßß•PŒ3}wÆØµk×>}úDBDéúÀuÝçϟߺuknnÎ4MúAÓ;1Â]ÖýíýoÏjÏÚ¬MQ@ !R©””ryyYûFÈ`e8ç…BÁó< õ· ÂI*i"sg~çbw‘ Ž úýþÒÒ!„sþ†!„˜œœœœœ Ã0 C˲ Èž"¥4 ƒb†eZgþu†I–Š¥ª´jYV:¦”ž;wN•L&uV „ºÝn¥R©×ë„€eYõzÝ4ÍX,¦Q¤‹Üh4R©T§ÛQRAÛ¨Ýív«Õêýû÷5¦¥”ÓÓÓÏž=ÓŒ¬ÀÜ÷ýååeÏótd˲Z­–a¶mð<¯ÑhØ}› Ž!!6mÚôéÓ§ˆ˜†aA0>>® „P‘ËåvìØQ¯×c±X†¶m›¦iYÖ L-Ë¢”ŽmKÄë˜ØL†±wï^ML¢J¥2??ÏC­Ô€sÞëõBgΜ9xðàáÇ}ßø¾R†aèû¾kº¿¼ù#|rëIŸúív{yy9‚¦aµZÍ÷}íE"˜Æãñ{÷î=~üx||\WBˆBEú!4°Ña?˦ÜT5¨®1Ö Œ¢ýJ)­%_Y›ïû£££GM$ajúD0¾¹à’9²ùÈ|wÞÅ.—\ ©i%ƒsÉÑ•q]×¶ímÛ¶íÚµ‹sNÉf³Z³ôÅu ,˲m›Xä§þ„ b’4H¥R¹\ŽsaAÑï÷õ£‰”Ò¶í'Ož\¾|¹×ëI)B–eU*•={öôz½ "ÏÙÙYιã8Œ3ÁD y÷îÝh®@u &&&&&&|ß'úÛ¶W¯^mÛ¶eYA$‰W¯^ÕjµÉÉI]ÀqœD"á8Ž.&ç¼Ûí¾{÷î‡~€š¦I)µm{aaaffF“”@c›7o>vìØÂÂB³ÙÌçó¹\®T*¥Óé‘‘‘x<®X–U­V‡††Òé´æW¡Ph6›CCCGŽ¡”...ær¹µk׺®ûîÝ»/b! ‚Àó¼f³yåÊ•b±Øív{½ç\Ë0Æ¥ôìÙ³·oßfŒ1ÆÂ0l6›¾ï_¿~ýéÓ§aFjöEMu–3™Œã8µZÍ0 ÍÌoÔT×÷ýN§333S©T´$@ÇÉf³Õjcaô LuG¬×룣£RJ!„eÔ§"eåœ'“É©©©jµšËåZ­–V3Ïór¹\<× ý*€Ó4óùüéÓ§5¥µT¸®«œ®A,s]—²ÿ~BHAB´ôž8q‚1FÑà^ÉçyoÞ¼9yòäŽ;Â0ä’#ˆÛùøñ£ëº7n¤”J @ãZ­–J¥4~¤”¦i†aøâÅ Ý“™`@×qggg·lÙrõêÕV«Et…·oß~êÔ©¦×LšI&  T*aŒsksŒ±Iôxxfzfýúõ±X !‹Å‚ h·ÛÝn÷çÿ,…t±ËP4 ¡VS¤yÇóCù±á±9sަha}!I¯É®Y?¼~Ã?6¼Çï3ë2†7d³Ù|>_(\מžÉçóŽã  ¯^»ú|å¹ÞÈðH6›µmû+˜rÁµÿúõ?¿~h|€RF)¥ÃÇ•ÇW?\mô’I½È9¿sçÎíÛ·9ç”R!E¦4?4?ü1÷8dá·0UJȘëÍI(KA ‚PJ ‹ý¢Bj)XÒýcÜn·kµZ¿ßoµZ„ F¸'zTRŒ°_Í}+05 “c~ `{n»’Š!f™F˜þãÆ¿[÷]’$©¢1!ñxüÂ… KKK«V­jµZc!€àûußÛá "¯´þ•–ÙétJ‹¥–ײˆ¥”šoÏ×—ëéL: Â0 38Ã)÷ßëöÊå²ã8z(•JžçQJýÀlµ·†"ìû}ß÷{½ž~B$“Éb±xýúuθ‚ (`F¹\>pà€”Ò÷}PÀ¶íGµÛíd2©™ˆ1î÷ûœóÏŸ?SFXÙ6==]©T:¤”‚årYo5 cp`¦”J)£áW¯3ÆLÓT¥c cüÍh-„XyA4$ë.:¨úÄAO„¥4 õÑo¶iÉÒ5øÄ~H×Êý%tEXtdate:create2017-06-06T01:31:19+01:00›Õõê%tEXtdate:modify2017-06-06T01:31:19+01:00êˆMVIEND®B`‚puzzles-20170606.272beef/icons/filling-16d8.png0000644000175000017500000000200513115373727017617 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<éPLTEâââÚÚÚÝÝÝÜÜÜßßßÖÖÖÉÉÉËËËÎÎÎÏÏÏÍÍÍ×××çççÅÅÅ¥¥¥áááÒÒÒ¼¼¼ÑÑѵµµŸžŸµ±µ™™™vvv¢¢¢ššš†††ååå¿¿¿¾¾¾£££ìììÚØÚÝâÝÎÍÓÍ«©«¬¬¬···¡¡¡àààÁÁÁ¸¸¸ºººÇÇÇÕÕÕêêêÔÓÔ×ÙרҨÅÊÅ£¡£²³²²²²ÃÃÞžžèèèÔÔÔ¶¶¶ÇÆÇèÜèÃÁÃ}}}–––ˆˆˆæææÄÄÄÐÐÐãããÖØÖ°Ñ°ØÛØÐÏПŸŸíííØ×ØØÝØ}Á}ÕÜÕÞÜÞóôóòòòäääŽŽŽ³³³­­­ØØØÎÍÎàÞà§§§¹¹¹´´´®®®©©©‡‡‡ÛÛÛÆÆÆƒƒƒ¦¦¦ÀÀÀïïïyyy¯¯¯®¯®‘‘ÙÚÙ”””“““ttt¤Ÿ¤–”–{|{›˜› › ‰‰‰‘‘‘«««jjj ž –“–‹‹‹æåæÁÂÁ­¨­žÈž¯Æ¯ÍÄͶʶ•Á•ÊÅÊÈÉȧ¢§¬Í¬§Å§ÍÇÍãä㪦ª É ±Ç±ÈÀȰŰ•½•ÇÂÇ¢¢«É«§Á§ÊÊÊ}~}¤ž¤’”’ÄÁÄÊÇÊÁ¾Á¥¦¥ÚÙÚÕÖÕÖ×ÖàáàßáßÝÜÝÿÿÿÂùmXbKGD¢°ÝߌtIMEáò‡»IDATÓc``dbbfbaecgçàäâæaàåãâ—”’f‘•dä‘WPTRVQUS×`ÐÔÒÖÑ•ÖÓ7042615Ó`0·°´²æ´±µ³·pptbÐvfsqårs÷ðägášaî%ÃÂãíãëç¤ÌàâÆnÉëÄàì'ÏœÈÉꜗÌbª®Å'Ÿšž¦“eÂÇÂ`.iš‘™• Ã¡)““žÃϘ›—_PXT\RZ\V^QYÅP]S[WßÐØÔbÒÒÚÖÞÁPÝÙÕÝÓÛׯ“:aâ¤þ†ÉS¦VL›Þ$’ì8cæ¬Ù® ÒsæÎ›3ÁBV]n–ù ¥3[E8ÊÿûX%tEXtdate:create2017-06-06T01:31:19+01:00›Õõê%tEXtdate:modify2017-06-06T01:31:19+01:00êˆMVIEND®B`‚puzzles-20170606.272beef/icons/filling-16d4.png0000644000175000017500000000045013115373727017615 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA† 1è–_bKGDÿ‡Ì¿tIMEáò‡»\IDATÓENAòôžÖϺˆÛf‡EQ4þ &D?Õ´ä#¢ŠØÊ*‹¸ºÁ'Վ錈Ëü,±•=´LÄ'Á ©·<‡v@¨šÉW³æ‚=£—}žå¾[ÀÈ"%tEXtdate:create2017-06-06T01:31:19+01:00›Õõê%tEXtdate:modify2017-06-06T01:31:19+01:00êˆMVIEND®B`‚puzzles-20170606.272beef/icons/filling-16d24.png0000644000175000017500000000163513115373727017705 0ustar simonsimon‰PNG  IHDR‘h6gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEáò‡»¡IDAT(ÏÁ[OÚPàso)–K± dk¶eØ&4Ù£ÿÂçOØûˆÛƒÉž“QD©Ò‹µ ´ÇsÚÓ}¼»»ãœcŒeYBBY–½¼¼ „c¡RÊ0ŒF£AîïïoooŽŽ‹E¶m3Æ&“Ià[­­Ù|vssÓï÷9çQžž!D§Ó‡NÇqÓ4)¥âo;?¢ÇŽ­†1´m[Ó4)%B !¶··«Õª”R)¥”RˆL´I›gœsÎ4&¥Ìó€B»»»¦iN§Sß÷çþgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá áoíƒIDATxÚíœ tÕÇ¿$ ¯j”ð¡©/¨ò0@¥PµTÅZèQ<Ç*ÒcÛÓ­¢¤öÔú<Ö* ¤P!!! ”’wBRH6ÉÎÌ÷Ì>’ìÎ&AÔ*% 0ݯ! 'GÂþ2•§p ¾JÔ%2í°¸ü Ä*ì,ç Ö Ö Öa!’ ô»·+¨ÐĈRè1â"cƒ%ûü~A§7bI­¿‡ KŒX|k Ð*é1Á¢\ŠÓI°XˆË¸{ÁÂ\QwÐh,æƒûçÝúûc|¯$ q?<î}Yº/gÄ"=¯Ìþñ‘Š !á®a#`£LYb1Ô÷¿3+Òœ ²À¢ä¿¦\ Ãw…¿œ‹? Ã÷ºcÃÒâPñRÈÀa‘´n5t§›´À¢ÙêŠ6ç î¡,±¸ìꔑ…®X±L/†-,šv³ò‘ä+J”È#?½˜·ì-²ùõ¡Ó 嘱P“–“%—Á“a‰‹ôdÀX¥ëœ(,J¨÷°wìÐ"OìX ‹`ÁBrí"x”ÕýÂÐ[rÝßßœDÊýË{ŠR†lÖ%6XïRÈþ„AVXˆ;|¬óÖXˆ-#>k[ ÷µ’X4w/$Ab¼ž\X,J\¿xÜü“²Þ³Û0åé…0jYÚ-¹.«¹E¶Þ9mùü$ýùÅîx&}íeðXixùÃc¹î‡+§Ž¹ä d‰EþxÒä˯¸|«×êL¤\¯^7fܒͨ×ceóRI.ÊKh¥Ì&þy²¶ßHY;is˜Rw–`ç~­àßWÏ«¯ì'¿°iD=Ý¡2Qs‹Ç„\]®ÊN"çÛ±B¢Í-ìaŠë£¦¼Q˜àö•©‰“°¹ª‚m„nÜÑÑÙ„= ›Ûp!&%tmLÊ*[“’Ȳ5)¿-Ëé Ö Öÿ3V0Urb3Ma±‚mNĈm)Úa5¥Í±Ý´Ë¢xti¡!OlnSJÀ‹I_Û¬(®ØMJôÞÚôôßçð–„Ö"—õ↚žCtV-m~6ý…ôç¶YÛnHplLÿC.ÏĆ¥]¯Í‡¤!ðxز0X#¬s%$˜ý–þáOƒ$íß2a…غ%ZIé|lŽ b¨£ÖWé¿X$%§ÃOI!»‚·2)WZppï,xßÒ!›·ÀUŽí0ÕÉÆˆEÎOxxÕ; k9ˆ y-¤ÿæé*—µíFóBsÌÔí’Ñþ–T”<•Ë…yº­EÜ:âÒDøg‰Å6^ #/ƒIdK“R;ͤÛá:c4znQî7GÀ„¢f­/öV¹þÃJEd‰• OxWÀ“KKWëÂa+DK,J:8~ÄK` GdžE#ÑÛz|’­ý­ëaÓégà Yb‘Íš‚¶Â"” °B%/RÍÇd»Qîüž{g1ÜPÏYaQò:X’s ü¥Ù²·(©|Üý¦|Ë»0eÛór<Ü]ع%”§%@âÜEÌA<6 ’ŸF´eoQòZ¸Û¥_£†x2¦¾ã¼Ž¬*)!$Ì*8¾âHµ ó {bEQ]ÄhXN9¾ª¸ø˜Þ0´Ù|Q’7P”„»E 2§oÓdóA‚,qúVíLÊ(Ñl«ŽR±PTåŽÉDÔa¾¥6ƒXƒXÿûX±¸8EÈ tö¹ˆpN çÚ_¦ŠN!Õz ëLjHÃBXÇF2`ÕTUWYGÍžr•¨À*~”§¶”ãÚ¨®ØÑÞYY…‹šG¤Èååæá"çh{A>~Z’›äçšðGÉß…tX(·š&±ƒNîs6~¡zòŒâ‹SvгŸëÜ@”W%àKbÊ«¶+ëP¾Ò¯¿ðp’ŽJEõáMN}oåUñø‚X†ô¨¬SK‚­ÂI—窾Œ‚ ¶wt:p ír\0–ˆë …ê|5@²I—ˆS0‘n`lXÂÅ^N±±±pXáÄ œE˜aEå‘X¨ç³zU\XŒ Ë¡ q²ÄXa…R6ëô•“dÑ Š ‹8zøƒ ¢Ô}ìḏÇU×X³8ÊŠÊ´¤œå+ŠöªâÀBÂjH€÷dí¢P¸F}ؕа˜º•ÃaôK¢©wŠø’I0§ž¥©Ç‡CÊ‹=¥Oñ`±¿}ðÚ`-åy/-4Ç"›×ÀÛgÀv ™bºç!˜ã`¤u0÷å)°¥ÛŠgµáY,häþ™|ï•C̱âÛÎý~nQVF5çÃlÃÏ„­gŸ‚{½}€Å8ƒ•ƒ¤wEjåä¤Ù´·(×-ð¼ë6Xà6÷N)9SÃjÆB^û+° »R4~,AÎHÊðúq×5b½;¾3æâ°ê…Ê ëU˜ÛÈÆÅÓ?„­aeÂŒJ¼ç`è£FË]ðøºÇàgVƒèÍ9NºrN¯‡å"Š‹n¨\ o;èUC“àíÐä2àü¡}-e×ÂÉüvѸ%qNYëax¨rlè63ãÀ¢\wÁm‰8ÀÕ“uã!ÏüL¤äM0ìYÁbøx(hßj¾¯üF­©åÝ‹_\ ÿ·§×§¿°¶V`9úÏ/ë:°±xøØÆõ/X-§l]úºôõϼÃóuo¥o¢8óu+·Z lh)FïÜò¶)Š5åSº[4n>\‹â—-7V ÞíjÑéV¥¹×î­JÚ‰»ô'ÈFWxn…nÉu•ß÷Vá›—ñG\sD`!¢û¶ÒûGy9ÔÙSÿÆÅéSÿRÅ‹nd‹ê—X¬ÎÄÅ¿Þ z¸1tÒJûÇH¢pž¨¶[_<Úö?äþ×±zÜ@\#ßK Yë`Äê”S ^pÂÿe{^¡|U؋Փœêï’…ñŒM8ÏžëĽßyŽkW±Š3_+¼Eo1.w('åܺgBXtn@•¹ªÏSYm§q ­‘ÝõæXLãêï[PÉq…‹Çÿ&«?ñn`¨6ãõõ<)ŒkÄêfÄU_?3ab)'n¼æö› akWµJß,§q<ÀÌ8žPÎÓuÎ/…9°Á݇Xñ¬òÈóÑe©å)ËXŸ<¿¶+Qê,J8˜œZΡ'ÓV4t«”#]TÉž9ð»îä´ÿ±ü£'×µ°ûªüò XÙ20°˜†E©‰C&.RnyÍD™) Œ¹Å4.¹6-mÖ2WÆ]7Ï[õawö‰| «ç•2Í|´_‡Þèy5ÁB½ Ki=ˆŒ¿Í¯ýG²/héɉ#±D+hR2¢Ëãñòfy"¯)xíUÐ^9S,Æí™”‚Û«ý€l±èн"’¦ôOkë±ÿêõ“§n™c‹ÇŒNIz͘ì#a÷âïŽyF „Œ›§¤¾ÑãBè“}¶æþc~ÚÀp·N˜|÷^Ùb™Îœ0Bü}SÆÀûS;õ’Ý:{³dHö)×˦Ãc)ÿzâ•°^6Á\5 f×3Ò’ñw΂q=îÆsÑŒj/… ‰9>i¶Ô$‰&ƒÈk\ k´=´¶a¼d‚¥YõÙ0ÇÁ2{«üÓáµf2~,Z[$¦f$^rG9ob0ž§à !N|À‹FÍY0ÛÁR#44¿»P4.,:øx³ÈÔÜ¿ú©«à'f8%jXÚùB±VOmj)MJœóx<þ¹ÕµY$yÉÓ±F5°&XÂS°š£´lçØ ˜aQÒ¸±Ž¡äš°šgúË%/…LE<œI¹þ©MF,ĵ­ƒß(<%ø×ÚºëW#±mÌåÜÌG×Á³|o½uX”¼füH˜0¥ö½„é3†À³¢É™¸iR ¤Œå“ôÔd71³ë‘ï7°üúT‘zŸr$M›<öË)O`±x=Ö¯¦¥-¼ifIã KoZþ.×£ÐaÉÓæ-\0åõ¾»`Ἣ²Ý,®â³¦ÍxÐ÷äü´ç\÷¶Ç q¸ÄR:PÄæv¿?ÐÆ1À'ÓF,IíŠ_iw‘îЫh2ˆl à÷··R^­©@›l1·äSû÷|¸×:öeé6ª«8 ¸æÅè«Â€éQ±è.“±kOéu £ÝÀ¦¦ÃÅØ8ÜÔ·9+°…B_ïÊÇEή¯šðŠü­%?'س-â/áåÔ´+øð}ÖV߀ ú¼ÉU4:>åñ4ÖùÂn C9i÷dq,q¾êW:“’áû í¢O¬nid«¿¸1°ÿ ë@‹Šõ{À«r´%tEXtdate:create2017-06-06T01:31:11+01:00¨:»%tEXtdate:modify2017-06-06T01:31:11+01:00Ùg1IEND®B`‚puzzles-20170606.272beef/icons/fifteen-ibase4.png0000644000175000017500000000105513115373727020304 0ustar simonsimon‰PNG  IHDRxxigAMA† 1è–_bKGDÿ‡Ì¿ oFFsx=ÌE0tIMEáò‡» vpAgððüE­7IDAThÞíÚë ƒ0 à<úy´¾Ù¦—J 4 Ô“n…âgœR'ePüŒ!IpÛæ&L˜0a„ÝaÈ8”%‚`9Ä(,pM»‹xùRRàÕÌ€ëG\Ràz+]n®Iá]Óámþtp7çÃÖ? ™qÚ©&L˜0áéaÛô‘Z¯v†gøàS‡/­v× Ö^Ò”Ý2>:|`;ÄÀçÿ>ˆ„ãNõuM#ðâzÀoéÌ÷K\·k£-±åÐXÐp„»ñy½¢âw«™[ÆZÍW¢#¬ žÏõ0¸UTÂà;ä—uû”àÍùüRͼàn5ó‡ooû¼ánÖÙö3ÁB9a„ ž6Î…íoSǬW{»ãþØm „ &L˜0aÂÃÜãóù‹ŸŽ/%tEXtdate:create2017-06-06T01:31:19+01:00›Õõê%tEXtdate:modify2017-06-06T01:31:19+01:00êˆMVIEND®B`‚puzzles-20170606.272beef/icons/fifteen-ibase.png0000644000175000017500000000153113115373727020217 0ustar simonsimon‰PNG  IHDRxxigAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿ oFFsx=ÌE0tIMEáò‡» vpAgððüE­7IDAThÞíØ=KQàV—‰ 6 j³E4¢…0b±mÑ"i,„ )DìBúˆ XcqutAÙB×ìÚE‹MîŸÈˆÂæÃY×u/~-ïœkô¼Å0‡yŠ;3gÎ…¾4JibrÿHù[0ÍÍ¥,”ê”r+X`¾?púeKxwzõ­xÊûȧ‚ N޾9ƒUäd¢gŸ`Ò üÏ·]ÀI¯zÛ ü ÓÚ¼ˆ¦eÿÐâïñÂó(f†þžÉŒñL†Nµƒ“K¾5v—‹À·þC›´­ÁÔ ß"L¹QŠXo ¦× ,°À—ês;Škð!Í]µÿ%v3‹kli¿:܇+uëŸjcÂÿÒÓàU<ìW×Ö[ƒ ?^øaŽ®²ÀÆ„ÿ1¾öu1¼fµ1hçósgͨÝä‡ë‚%~´R®>¸É äú?¬õî ÐçÖ xÌ—&|=0›H«. —6íºÂIõ27<ÞZñb/¶®­·—¿Ñ}‡nöát‘ν÷!ÁF7ã…nÀsKAöY`]úàðîþ õ,p¢Ÿ]ÀùD¸ajã`³hå†O’*¹álþ°x,°Ñͺ_-¥U;ÐÉM¥­pR»Æ / Åj*‡“çêïZ“¸ ü›6i[ƒ‰þÊÿ¿Q.°À ,px0±›Yƒ,íWû?iûÀä\¯‡í^‡X`X`ï0| ã´vV/Šø%tEXtdate:create2017-06-06T01:31:11+01:00¨:»%tEXtdate:modify2017-06-06T01:31:11+01:00Ùg1IEND®B`‚puzzles-20170606.272beef/icons/fifteen-base.png0000644000175000017500000001247413115373717020055 0ustar simonsimon‰PNG  IHDRðð±7~ÅbKGDÿÿÿ ½§“ñIDATxœíÝ{LSçÿð¶X seTqêTăÆ/3ÆÛ£è؃ n YÜs‘„Ð%Î,SÔ›¨ ¼0u†² $P±Ç/\¤eE@J©=õ÷ÇñÛñC¥hç9>~^žÖÓ·‡7§íésìêêê!ZŒ!!.a¡U°Ðˆ*XhD,4¢ Q ¨‚…FTÁB#ª`¡U°Ðˆ*XhD,4¢ Q ¨‚…FTÁB#ª`¡U°Ðˆ*XhD,4¢ŠØöM444˜ÍfÛ·ƒÞrÓ§O·q#ŒÐØfd;‘Häççgûv8¡YëÖ­‹9Ûšìíí1Ï‹0O__Ÿ››[WW—›âìZ8{Çd2UUUažf777N¶Æñÿª¾¾žÛ ¾­V«ÑhØeÌó,!ç±…ïrp¸w8yFÆm ÞfXhD,4¢ Q ¨‚…FTÁB#ª`¡U°Ðˆ*XhD,4¢ Q ¨‚…FTÄYÞ:.==]­V766FP*•ÁÁÁ¤ò”••ªÕê®®.£ÑèîîíêêJ$Ommí‘#Gnݺ¥ÓéL&“L&›7o^ttôœ9sˆä±P(íííàï‘A6¤Ð&;;›tŠÿœ´ÉdÒh4Z­–ÃmÚóŒLhy8ÁY¡ Cee¥pöæ™ òˆÅœõÐÎö¯°[X·n‡±l400`ooy^d``ÀÁÁÁÎÎŽt§ ;åH}}½›âìZ8?-“ÉTUU…y^„Í#œ6›L¦ëׯsµ5Ž÷²í¿a¶Ójµ†]Æ<ÏrÛQø.‡{‡˜gdÜæ¡°Ðèm†…FTÁB#ª`¡U°Ðˆ*XhD,4¢ Q ¨‚…FTÁB#ª`¡U°Ðˆ*XhDAœu^ZZºmÛ¶g×çææÎ˜1ƒÿ<¬¿þúëÈ‘#*•ª§§ÇÙÙyúôé[¶lY¼x1ÿI†^y¨É“'³×ýæ_iiiVVVCCC__ßøñãgÍšºjÕ*"a†D¡è?þøî»ï†aoêt:N7þ|"…~{{{"Ï[\\l¹Ú££c___uuuuuu__ÙË¡ƒÐ }øðaËMR—-»sçNRRÃ0žžžIIIóçÏ7jµšHøùçŸM&“åfnnîo¿ý+W®$’çüùóìÂîÝ»7mÚT^^Î^O6'' ýÿøøø899I$²ßxËÎÎ6ðý÷ß/X°‚‚‚Hå™3gŽeÙl6óÍ70vìØÐÐP"yD"»°dɉD à É3”°^®^½zÁ‚óçÏß²eKMM ©•••àààP^^¼hÑ¢Ï>û,//Tž¡JJJZ[[`Íš52™ŒH†¶Ó.\0 yyyì±ÙÇL$ÏP¡õz=ÆëׯWWWÿòË/~~~üÇèèèƒÁ––Æ®ÑétµµµmmmŸþ9ÿy†ÊÊÊb"""HeX¼xñ¡C‡vîÜ™ššššš öööÛ·o'ÉB#´\.OLLÌÏÏW©T………ì2†aØÅ?ËëÒ¥K+++srrÆiii½½½D"±êëë«««ÀÏÏoÖ¬Y¤bÔÔÔ|ýõ×=—1cÆ<~ü¸¢¢âÎ;¤"Y¢ÐÞÞÞaaaS§N•H$^^^)))ìzR×Ü}çwØ…ÐÐP©Túá‡ÀãÇoݺE$Ë2‘H”]^^ž——'•JëëëãããŸ}úñãÇFö] 777èèèP©TÐÒÒÒÐÐb±ØÉɉ`0È‹ÂÞÞÞ£G=ztèJ©TºsçN"yV­ZUPPPRR’——W\\l4Íf³]bbâØ±c‰DÌÉÉggçàà`",¢¢¢RRR† —J¥=b4BBBØ ¢Ðqqq*•J«Õ ¹\ãááA*ÒO?ý”™™™››{ÿþýñãÇÏ;7::ÚßߟTž¼¼¼îînFiBCCe2ÙéÓ§úûûÇ?mÚ4…BñÉ'Ÿ )´ŸŸ‘·çF ‹£¢¢¢¢¢HyjÆ 6l â?+V¬X±béÏ!ˆch„¸‚…FTÁB#ª`¡U°Ðˆ*XhD,4¢ Q ¨‚…FTÁB#ª`¡U°Ðˆ*XhD,4¢ —çC›L&F£Õj9ܦ-0ÏȆTNpVhƒÁPYY)œ½ƒyF ‹+**„“‡«MÙÙ>U»…¡ÓU ÁÌ™39ÜM6ppp ûÍÖ¡ ƒƒƒéÿ±ä©¯¯·qSÔC §Í&“©ªªJ8m6™Lì—Ø‚ÛüçŸjµZ—   ¸¸¸‰'òo,4h4šìììÑ<255•m3ÏÊËËcccÙ둎7îÞ½{iiiUUUÇŽãá‹9V÷Oxxø?ÿüÃÞìêêÊÍͽvíÚÉ“''Mšôºã ƒ‡ •J#""öîÝ>ÂÃêêêNœ8Aä’jJ¥Òd2‰Åâßÿ½ººš½6—J¥:uêÏnuÿ¤§§³mÞ¸qcQQ{ {­VûÃ?ðo,4xxx$$$¬Y³ÆÕÕõEa&))‰a˜øøx>³@gg'{Qxö‚õëׯgïºpá¬îŸóçÏ€X,NHHðôôŒ‰‰qww€’’’ÞÞ^……•ÌÌ̆††¥K—®\¹’ç§d,WD·,üý÷ߖ뢓ÒÑÑ¡ÓéÀÓÓÓrLÿÁÃ0ì%“ù„…¶®­­íСCŽŽŽ»wïæÿÙ=<<\\\ ¡¡áÚµkýýý™™™ì] Ãð?óï¿ÿ² C¯ò-•J‡ÝË,´uÉÉɃaûöír¹œÿg‰D;vì³ÙóÑG={Ör¯½½=ÿ‘ž‹½Ü÷³Ë<ÃB[qãÆ²²2OOO__ßÆÆÆææfv½^¯oll|øð!6nܸÿ~___//¯ˆˆöWK*•‰Édì£G,+ûúú†ÝË|ÛΊþþ~hmm º^­V¯_¿~÷îÝ›6mâ!ÆòåË—/_Î.ß¿?++ üüüˆÏ_ãîîþî»ïêtº¶¶6ËHMMM ‰fÏžÍs¡Ál6wwwwww °kôz=»†l0 µZ]RRòðáC£ÑX[[ÿäÉ;;»ÈÈHžÝêþY·n˜L¦={ö´¶¶¦¥¥uvvÀ²eËœyH8µsÛùøøÀèfjkk[±bÅsïR©T‰dèšÎÎÎeË–ÁË|RÈîv€µ™ŠÎž=›””4låW_}ž!ý²^6ÕýÓßßÿé§ŸZ>Xa¹ººž:uj4¬Ø¾†Âú 0cÆ ™L&‹]\\/^œ‘‘ñjm~³²²"""&Mš$‹]]]ƒƒƒsrrøÿ˜ð<<lòäÉü§Eo…îèè6#¼R©T*•ð¿áËÊÊòóó‡ý+GGÇØØXþR¢7“ßå +++»wï^OO½½½»»»¿¿ÿæÍ›q„FV‘ù`eäácccq0F¯Fè/ z)B<äà™Õ³ÿJKK·mÛöì?ÌÍÍ1cÿy¬>€ç0?yD"‘B¡X·nÝ´iÓššš¾ýö[FÓÕÕuêÔ©¸¸¸×o,´õ³ÿ,|||œœœ$Éký¢Õ<£ÌO¥Ri¹b¬««kddäž={ µµ•‡xÃ`¡_ÂêÕ«õzýرc}}}¿øâ‹ N$îlù¼ŒÈÉdø.ÇKÐëõ`4¯_¿)¨ïN D{{;{X"•JÙ«ó m\.OLLÌÏÏW©T………K–,†aRSSIG–æææðððîîn‰D²oß>777þ3à!‡uÞÞÞÞÞÞì²——WJJÊ¢E‹àW]G¬ššš/¿ü²··W*•8p`áÂ…DbàmÃ0CošL&vA$‘ˆ#DÅÅÅ[·nííí•ËåYYY¤Ú 8BÃ(Îþ‹‹‹›>}úòåË'OžÜÑѱwï^öa¯éE¡Õ}:çyFfgûßMv ì+!ÌÄó²yÚÚÚ†ýgÁžývãÆawI¥Ò_ýuæÌ™üç±úžóDEEUVV>{ïÂ… ?nuûÜöGhëâââ T*•V«5 r¹< &&ÆÃÃt44ÚúÙ~~~~~~ÂÉcõ<çÉÈÈà-ŒUø¢Q…ËšÊáÑ›…³B jÆü1cð/Ï[гBß¾}ÛÍÍȇCYàH†¨‚…FTÁB#ª`¡U°Ðˆ*XhD,4¢ Q ¨‚…FTÁB#ªÐ|>´ÐÎþÃ<< ¶Ðƒƒƒùi‰ÅbÌ3±˜³róB‘H´hÑ¢÷Þ{“Lè­%ˆïJ$’€€l3²‘Ùl¶}#ŒÐ ¾Ë¨‚…FTÁB#ª`¡U°Ðˆ*XhD,4¢ Q ¨‚…FTÁB#ª`¡U°Ðˆ*XhD,4¢ Q ¨‚…FTÁB#ª`¡U°Ðˆ*ÿ ֶ˱¹³IEND®B`‚puzzles-20170606.272beef/icons/fifteen-48d8.png0000644000175000017500000000175413115373727017632 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEáò‡»ôIDATHÇ–ËkAÀ‹ˆÔƒB‘âA±'AÁS‘ŠôbVzh/Vÿ‹9‹'ÁÞ‹ >ŠEZÛš4IÛ˜MbÚÝyíÌ>š&M“Ôké½ã)àrgþk ;%êíÛ:qk˜¿Þ½ä…¾›?§ßøŽ„tÈ 2æ[“~qR"¡öKsï^?>4ÜB°ÆÜPsÊ é»Üñp¬«sˆO)5ÿt˜cftÃÙÖÄZÚÔÓé¿­Òlü«å‘~éöcëÅΚ:eêNýqÏìA&€á¼„æÃ®”ÂÔ#‚a½ܨh/¥ NT‘â̤Ÿgr¼|§1'»Û;¿·‹%ÍbE°”ÚÏ¢ÒÔªPS2®LI±2¼ßÇI,üÚ(MÙFÊ­O%tEXtdate:create2017-06-06T01:31:19+01:00›Õõê%tEXtdate:modify2017-06-06T01:31:19+01:00êˆMVIEND®B`‚puzzles-20170606.272beef/icons/fifteen-48d4.png0000644000175000017500000000122213115373727017614 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA† 1è–_bKGDÿ‡Ì¿tIMEáò‡»ÆIDATHÇ•UQ–Ä ËÑ=7cUì|lû¦*%…Û>}ýÎ_«ÿÆkûÄ]¨åëáó0\¾cÄÝø‡ýÅýBÐàN~¹ÞvÓÜñÚ™!÷t’÷ x’¶õ4œhÕýB¨·%éN y#n¹…{l`Ìgì«"<Ñ>§©õÚI–lˆ¨’•1–×õBÒªÚËÒ"NÓyXÒú+éSØ~¼vaݰIäzJKÖ1ªîâ¿•_ e™À¥¤ªÞPFßÍ(ÚÍb‚ŸY—î¬áªJdO‘÷ä$*ÍáTÁ™ÐâK’f·‡©âìH-Ýêm6ϧ[["[šÇP¦Ì¬ñŠô9–§ò%4–ýÓ@ÛtàUˆäê­}i.Cà‚#TŠHÙw—Ì€–úE#*ÜrtX‰¼x¢«ó¨$!fÌ—Ù›|à¤÷jÎ0o,©2=%²&ÒØs)v¡kÝÖ˜Y”\@Òm“¸`Jf²ì}pÿªj=*?_°=jˆÖæU¿m(È7NL¯Z©AkoéÏûS…&_Oú ùîþµY9§ •ô߇‡£ý?CkŸÝÿh#úAèkpÊÀÝÚ%tEXtdate:create2017-06-06T01:31:19+01:00›Õõê%tEXtdate:modify2017-06-06T01:31:19+01:00êˆMVIEND®B`‚puzzles-20170606.272beef/icons/fifteen-48d24.png0000644000175000017500000000175413115373727017710 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEáò‡»ôIDATHÇ–ËkAÀ‹ˆÔƒB‘âA±'AÁS‘ŠôbVzh/Vÿ‹9‹'ÁÞ‹ >ŠEZÛš4IÛ˜MbÚÝyíÌ>š&M“Ôké½ã)àrgþk ;%êíÛ:qk˜¿Þ½ä…¾›?§ßøŽ„tÈ 2æ[“~qR"¡öKsï^?>4ÜB°ÆÜPsÊ é»Üñp¬«sˆO)5ÿt˜cftÃÙÖÄZÚÔÓé¿­Òlü«å‘~éöcëÅΚ:eêNýqÏìA&€á¼„æÃ®”ÂÔ#‚a½ܨh/¥ NT‘â̤Ÿgr¼|§1'»Û;¿·‹%ÍbE°”ÚÏ¢ÒÔªPS2®LI±2¼ßÇI,üÚ(MÙFÊ­O%tEXtdate:create2017-06-06T01:31:19+01:00›Õõê%tEXtdate:modify2017-06-06T01:31:19+01:00êˆMVIEND®B`‚puzzles-20170606.272beef/icons/fifteen-32d8.png0000644000175000017500000000142513115373727017616 0ustar simonsimon‰PNG  IHDR V%(gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEáò‡»IDAT8Ëu“K‹ÓPÇû5ÜèJ£ ˆ@q-‚"î܉`DÔÙ ¢  —2¢‚2ˆ0*Z¦c_óÈ”¶6¹÷žûHn“>g†i§uçÚ“ä&MÅþ ÉMòãœsÏ=ÿÿGÀ€á‚ó~š¤ÎJðœp*2ƒÀt2J5ñ©ÈI»¬²À1§I ÊÚ2æ"+.ð)ÂKUþ˜7¼ƒ,/´ÅB€¯Ïÿß¾Õ£‹"€¾’ÿzùfŸ(`Y©8¢uaõîÅÓ5Ev èLd,™ÿþú2yûPšZ;ƒŒ~cqz¿+ƒ>‡8E“L{Ãä÷¸¸ Â8¶ÉDh’Ž&à[m=«È­Ä@ŸaX.p÷ܵ|n;F6-Ä@rÙQ¼«+K’F3U‰­O5öaSÚí †‰™ĵÎ>"÷Îmhiù’¤Áf’‚LVüY]*„€$§FÎ¥«ùûg>Âò=7àªëãt•Àµ^¼Úx¹†5 ÀÔögÖX[ipjÐ×Àó íw'JOO>×,àqeØÜ]LAG× _îÜpD ¸’FzSxßO=^_^jHPo¯aToCàÛ³7…'E,&ž‡zu+ÑvõP´‡]½}5UòTFœ/FYT‘*ó¾ðdÂJ]€âÌ*h–£F-U=¿¦3³Æ%3 Có‚š³«dä‹ÈÝ3ãå3kÚÿ/fô=34Yn&{‡ó'AôEs ![ Á¤O~7Õ¼½34Ög{u¢9/v—7Z#®µÅäå;VGXtHÚ*’$‹ffHñjt&Öô¨ÇWyKˆ/’+ÚûÊ›jAÈ» ÇÚ/?옅δ0+^¡ŠªÞå0«¶Ž÷Ów¨‚YW¡R°cÈZêOsL½3µCÃLQ”º'—ð”/‚ᔜv¢"NQ*’N»ƒ³¾†’?c¼CÓžç‘ R¯ã¶š'k¹ˆÎ¥f›$å½BY÷­Üç$Múwüé»}91E†¾%tEXtdate:create2017-06-06T01:31:19+01:00›Õõê%tEXtdate:modify2017-06-06T01:31:19+01:00êˆMVIEND®B`‚puzzles-20170606.272beef/icons/fifteen-32d24.png0000644000175000017500000000142513115373727017674 0ustar simonsimon‰PNG  IHDR V%(gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEáò‡»IDAT8Ëu“K‹ÓPÇû5ÜèJ£ ˆ@q-‚"î܉`DÔÙ ¢  —2¢‚2ˆ0*Z¦c_óÈ”¶6¹÷žûHn“>g†i§uçÚ“ä&MÅþ ÉMòãœsÏ=ÿÿGÀ€á‚ó~š¤ÎJðœp*2ƒÀt2J5ñ©ÈI»¬²À1§I ÊÚ2æ"+.ð)ÂKUþ˜7¼ƒ,/´ÅB€¯Ïÿß¾Õ£‹"€¾’ÿzùfŸ(`Y©8¢uaõîÅÓ5Ev èLd,™ÿþú2yûPšZ;ƒŒ~cqz¿+ƒ>‡8E“L{Ãä÷¸¸ Â8¶ÉDh’Ž&à[m=«È­Ä@ŸaX.p÷ܵ|n;F6-Ä@rÙQ¼«+K’F3U‰­O5öaSÚí †‰™ĵÎ>"÷Îmhiù’¤Áf’‚LVüY]*„€$§FÎ¥«ùûg>Âò=7àªëãt•Àµ^¼Úx¹†5 ÀÔögÖX[ipjÐ×Àó íw'JOO>×,àqeØÜ]LAG× _îÜpD ¸’FzSxßO=^_^jHPo¯aToCàÛ³7…'E,&ž‡zu+ÑvõP´‡]½}5UòTFœ/FYT‘*ó¾ðdÂJ]€âÌ*h–£F-U=¿¦3³Æ%3 Có‚š³«dä‹ÈÝ3ãå3kÚÿ/fô=34Yˆ¾"’Ú•,Õƒ–²¾A ™‹%׺…qù6@cù‰!X–•Ѹ÷9GñP[Ï7oQ §%tEXtdate:create2017-06-06T01:31:19+01:00›Õõê%tEXtdate:modify2017-06-06T01:31:19+01:00êˆMVIEND®B`‚puzzles-20170606.272beef/icons/fifteen-16d24.png0000644000175000017500000000072213115373727017675 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEáò‡»ÚIDATÓ5MN1 Fs=Á®±A±à©]±T ©ˆ]f:Äùqg’LÁS©oçOŸŸlá¿2­x¡Ç°Îᯖ:/B×ÀųïÕµ[ØÉ­µÐƒ· Öòpsš”PÐf¦-á£û„¯PÍ™J"Wæ9•€à"R˜<(­ÌBcyï^¥%Š1dÃÿ}~Ùt1¸DÙìÀô½?8ˆémû”FØ0ç q¹{¼K§AJÙ÷9|~S½3Æl†RÄÕáΕ9W0VYqý;] üiÄÏDý.¬%tEXtdate:create2017-06-06T01:31:19+01:00›Õõê%tEXtdate:modify2017-06-06T01:31:19+01:00êˆMVIEND®B`‚puzzles-20170606.272beef/icons/dominosa-web.png0000644000175000017500000001540513115373716020105 0ustar simonsimon‰PNG  IHDR––j.>gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá –h/{ IDATxÚíœy|ŶÇOwÏLH¢4lQ  €"ˆ,p_à ^¹rAPT¸¢¸ñUE…‹ @Ad3€ìa‘Uö,@2Ý===ûL2™,„zÝ=KWõô ï~>ÏÏûPRS]ýͩӧ~§ªzÀò—,ð p ëÖ-¬[X·°þX<¯ðÕlR­6ÕÇâ9‡ËéŠ]Îbá„8 œ.‡|SΧ§ËÊÕ Ëê:uähìrÄìây—9n“S.+/¸ÏÄmsÅÍ×KS (ˆU(h¿Ïnß÷`Ü&‰cÎ>©NÜ6-²]\õ±Øâ¥@Å'ìö'¤±‹t}Öõ_hˆßÍý¬ÀX¼Y*<áOR«üÏ\>ŒòeF£‘!:b F†’ûK³ZÓ,ÆhÔÞ™V.2Â$”¡t´AÓM¨‚‚:y"‰e-­¨¬1.Þ^Vq-Ä*›†8¶Ç±t?—‹AÂÊTº¡b÷T;ŸÀâmgúwïüèI{„‹sîx¶G‡\ØZé¦ývþvr~súìÍoJ^GC3«µ™òÉÛÙk[|4tÝ5Qºc‹†v+s>5©t4<ºjû  u°Gj=7nØŸ6Ë» †Ï ,>/›ºp¸Ú)3w É@‡±(HXü'zÇ’|ýÚÂÊPþºJ·›‚c½yÍbåi°þH4÷7gQ±~€ä99 ë3ߘ¿ ×J„&¾*–TƒQw‹¯÷üyÃb`™ð‹)øPÒШx–>֑ΓMÙ*çùéþNÐ\±_xÇ:~²Ãi¨08Öè ‹†‡¯Þ~âuµ™î®øZú Kry:#+ÌX̓¥¥æ0–ò§/FÍÏù¢âEéwk(êJÜ1ûh/ñJg Œ¬½×o{ kÔ$ð•çÙðÉžqð™?‚Źçýû·Þ°Ù˪Xã_èvÁy{ÄZÒÏEèËN†E7™ŽF܉ûßb·­-ıƣg>D=T, ê÷®XÑܨƒåÞܪnò°«BÄåYïœÆÉ ¦+!#ˆEÁW¢?ï9ÕRwE~;ÚF<‰G‘­& 'waƒ(=‹¼¶p…O3`¿Mº^;ˆ¼M(¸ê"â–ƒË7»"n™’É0H%Ö©[;‘ˆ[Iujש¥‰GÉIš¸•¤iaªS§Nm*:@H‚(rd”·ÚB3z8ÊSŠ蔸á4Tƒ²qõ›ê¸¼„A@)¡s`&˜Œƒ4÷HÿâŨTMÐZ[GÚhä ©Íh(ŸE5 ]d„;.GaÅ.¼x¾}¼9–æ[§ó[&~›öçlWžˆ;US0¹& Bò³ÜY'Å)[d½µuê´iSc”iS¾Îu°ö“É&Ó¦b½L\ëTnW],QÜRb–ŸæòØ¥¬¼TR¼à—þ‡—@ÞM€­o/Z¾ 3#FÉÌÌÈ‘e%gŽ[dGåY²®Èz黌Ìp7 ~s׋·<ßoê.ǦÓêÞög<ô&|í®o™Kç€öé"Š ´ñÕë‹ì8ð!˜°š^µjâ/¥7š¿%ru8nÑJÌÁ-«%n…ÚJ±ãcôu+sùÈH$£ôâoóØ¿Xt‹¡{…£<¥3|‘pºÊå´{¬dX¶‹ù»Ëîp“X‘pJFyι§[jó)Øå¼ãPçO)6̉õ—:>Dȃ6»œ?ßœƒý¸VµNy›0.¶8#±¿ªz¥&ߥ5hûƒÃ° “8÷r¢±ëûqЊÇ`¥—U±ö¿·ù ‹†e׆œ4'a Âp&`IvPÿº£¦ž3`B «R8N7…î‹w®ú÷Š;_ ¹‘JÇ“®êÚÖÕ[.I},õ©ýñbå³wªX={áL{JÆBSa]iI±Xÿ·° 5}È®Nd\És|ÈkWÑÁûz+.§`I]Ñ™Y³ëXKêѳ¿n·>gy,í²€a¥”þÃÑ‹¡DCôdUµT±Š§Â/®¶- #ÞÅù¾kí¹¯K9ö4±Åƒ>qEQ‚ñUdZ ’t„ çÞvû >v5/¢žéÅ.NÅ¢Ýá}Ô³V+ôlò×ìµ6¢;:9yÕ4O5]¯ÞL2ñ.£’{aíÀdÔZê&Jneê|ðÞf§R‘^Â!¦åç¢É—Ï›puzÐ:±r9æ[öÓõ~ f¨¾Å‹“ºõH†ñLoÌ;_4K9cçTßšF¹Z+ÚZ¬ï§¶Z5ú¶˜U¯Þ—öàÃ)Ë‹YõILþìÒÏ-°'‘‚f?äΩG<‰Û»wºÕ‚_ê;¬§µmùÜ6ìI”:þüÒ/mô|‹·ûü¥NÜ3ÅÒb_@ù+ñ¸EEÅ-"œòο§²H³ ÇÅb¼·Ô_¼StÜÒº<ÏJ… ƒ‘šH”g†Œòr&ÊKY4…#§¹‰&Ê;ÖU§± ëÏ&^1@WûM͉!¬x¢9NÌ/Ç•²mrÞŒ‚ˆÅÆ“IE’PâEëŽõc— çÜ7c¬`WÄÑ•‘8Ûõ¸êÔÏÞ U<,ÞjÍ12v>ñ¼ƒu{o؈á1Ëëß;þÓXœëí¸  í.ºŽ¥Ý e™æùÏú/Ü”žF“I+:MÁ/ M‡„` mž¬1Aº¾¥9>º†Ä¢hš¦4Xyµƒ– ¢í¤d I`Œc,"nÙ]¤ì.‡¦Æá …“xÖÊaïn¢™-(X™–òG5LO!y Óë’X®³G-D ãÏ>)â‹{êðY‡€c5HoÞ²¾®µ…N“MðÎ¥´–¼4°-'ݾ¬@ÿ’>PçDçä$ú‘³ØZ§kËFºßU1qžÙµŒµ>²ñuª^ˆJÐÀDcÑ~®ä–®3нeh-ÍÃa, Úô×àXtÆaXœg'ŒÙ ¯«ñ‚·ÿ±ÕöOؤ>¼mwNÁ})çì˜:]q<õÞºzÖ¢aóÌ”zS,EÙyïG|Ë \eù™°' XlÉ,ØR™~¿`ÁŒslN»'͘¾ä|;>m4Ɖ[k 2ÿÞAΡ4X ô?Û ÇZƒ¦Šúƒa5°®Õ,nwFïáXÅÓ ÛÛ¦e‘šûHóiCS· ˜s±þ1õé×TÑ,õÛkÀ+ž³t´µ$àª#ôÊe€™¨Ù}h<•Xø½«íõQ„µ–Áò²ä^5ˆ WÜh6Ì+Åe¯”¡—áwwD“LÁV”ˆËÀ O™PP5¿ã½¾ÃËÛª.OÓ{Ë,ëá ê#£¼yt‹·^nW¿ü &PæÒ‰mžoXoŸ:“sî~{ÛˆjŠ‘°×>´„‘AÃÉøÐvÞ¼vÊ¢gfëñu³¬¼Ç±fæÒ9ö$:Îe¦&9ÇîÑÆíÇjxûª¡/O>gW} àɹK†%*Xù,Æ([“ä þ£Æ­j„S^,»F¨ ÞYYUî j¼×ªJEB†îD`åÕ‘8¥#EÆhd¤&eMRÆ$¼Hó“Iº §¼ÙLÎŽòF›FFöâd,£r'“AéOÝ!,]âoB­í•?BÜ©šÞNÁÅEÙ&«Ø’oÈðÜÅ"GEA8ï–\;vIºkž“µÚ()N›ÚÏžÐÍ‚“(.‘]dÄ0>Eí8¹ÛïÎÈúïà/^ÂJ^~~.öëÅ+N)#pàmróóóðK.YE³œ8`…ã…¢={ñ²ëœãÒn¢æ·ËVÁ}9/?O)RŸV§ºWÍ[}~¬‹6«§«(ñø|^O VS겊6¼Âï•ÚÅk±^]»+ë:æ>óÓz¼jM®Ès¢M ›EÝÙçm—FvèøP°tìÐ}‰Ãì8з}¸F®” ökûWNÚYÛ×]:t$›`å¡®slÕD«ÆC£¯`Ù{“aeÉù7Ы] ‹çÄß³ aŽå5EûÄJKÂQ^Îõdq*ýH€áh#¥tÒ`J0‘ù mL0Ðr¦™ƒžƒàg¦†&™äLÐ;žox3™€ðQ.Ï1„áà)c1ú6ˆœ:± ‘˜« (Á)µO‹dúo+ xÉü]ªqñºX¦G‡ü#U™j‚X¤öüúó92í7WîÆ¢à‰õI¶„¾}L8o»¸`#¶XÂ[/®š¿ÉŠ­¯òÖ³+æïÁ4¦ Úäó× [Ês‹ç‘Ù~׫44¼,郊Å@÷Jôn[¼„†²v "çÝðµSï«õšÀP^3!Fc©&šk§Âûèﲌ cõ®x¤)¹aYÇ«ÆbX÷»ö7b{÷Þ3g…Û1,¶dq«;»ák§â¯§ÝO:0ñsnWí7}zXÒø¬á·€Ü_ëïÈw}!!£û^ì†p,¾ÚØuư(Øóß³ÊëªX¼­ Ùòà¾äð™ïéˆ/×sÞÓÆQ1°\qÂÑUDIжKžƒžŽÜSr» #Ú ” ‹†V¶¶ÃÑ“j¨``@‘iEY‹-yãQkZ{÷x¥å²ŒaÉYˆ§¬ÊÙ6ÂÅÀTä.CÇ’¥´RÁâyûÓP'ú«£(1Ü×⤜÷|âØJ, õ_­Ìo¥ZËÓݗѶ$ÌåMþ6 -RNL)XÔ{¤ãWè- ÃÆOtÜŠž]?ä[ÂÁu¿4nvX݈`}ý åÎF‡UsI€‰Ih•+òÑÖª×ëÕçëc ù©!O'?I/kDÓ·i’¡/ðá*öÿ´Ñ‡¹¼më¢s3òÔ€À;vÎZ²`^¡e­Xá”<µ%/HkBX”\Cä £¬¨X’²(öâ1œ÷”ÊÄ!w¹?P ŠaQŒA^ aƒ³ˆfíä#MQšÉ‡6j'‹f®á̬™\¦Uj,–XÖR°FTkuƒ©ºkañܸrUúp®ïæ–âba,s^Œ+lŸ’„Íœ®q…Í\»î«# b`Uïfe ^ᬘ踚a¹ /ÖL4 Ñ¢Y÷†ž¢°D–~²±Öõ±¶å-UÝŸ”ö­“µMK›bXakiÕ)¶H©4[QVÿµ 2Ù·ªÊ‚3¢ŒeÀb4£b•Tù-:2Pª7~œÙL6Ü3cÙôû°¥é¿­gÿ8„€ª5úû—iÀWlf½WW¶S“?\d bQöÙª· ò¢Z‹„yýgqª^űÖûço|Fªix!g㵫 ÕEJ.=°hQ"~Ìcéµ]hŠºÍÉz³Óz§Â:õ ëŸqwc#%ébIJDüsÁŠ‹ó¼0¯º¢±xMêÔˆDiŽù¹¸1¾¾•->Õ>wôfh.ìòÕR’¬ùP6|Œíì[/\F“aµ|ÿ ó˟"/z¢pÚ¥ Œ0åq¥=UÑ,uð®MT$Nh5ò¯Ÿ½¶Cݦ¡»²…žÙ«–tŒÍó²a®ñWaÛV^Å:€ÎNܱçÌ×Ñxر1¦·F¡‘t`-ÐÆ0 ÷ÚS|¯j-€·qê†m¡·GŸÀåU,Þf}9aC FŹ.t¸ë”’?„±~G©½Ð?%=²–ã$ AïÀW–¤’ÐÄÆh±j-žiY¨»ºvJCVeêdt‹‚Ú¶½Mùã¸Ë_éß?…i)ûÑæ·o‘Uß‘ž@¸¼¡IzJP…LÍS5«^óÚ€Å-áê±#‡rÎcÙª5ïèáC‡ ¬XÜÃÝM(‹*ŽÞuƒmÎéÕØæŒ`AÔäCe}K°f ïîŽx}ì~‡g³+«Äv||¼Máá?èn [ÉÂÖK²Wß wú¢°J k¾….ÍK—aåûE*Õ‹wŸPlø•³z£°üëö 5=p pgðröϼÀâêcq®ïàŽóÌÅ’M¬Å¥WúÇñ,9‰ÍÖš‚݆;ç¯þ òÖ¢`ÀÏ¥LÔÑ[ónt˜¥‹ý†Û|M\>¸¹<}|K(·¨Ð9,nEý¡õŽþ€¼zÐ'ŒEo…cq¬þ"¥j›QÖʨþV”Åç÷‰–Õç/-p¬ðÝp,¯Ï¦å)H]séÈÛ Fy š­=óC‚¢NÃsâЋl3‰8?ñü™øO‹åÝ:îÂt ïØß)½IÇ\uª–z|rßÕʼnêœ( WZmðrQX4´üzÄï¨'® XrõR"†ÅÀ ïk<‹SÃÄwç¢ùêT-͉c{Àz,´rî­0næç—Õ9QRiUKú¼_Ã2ûg,Tµ#9'~êk§Šfù®Ùù&ëÓ²Ùcêi–º•ǰ,lÕBÈÆßbrm£û¾¿ß…ë­ÕÅï~x|ö?¬ œ'ÒÞ„¬b,yeeÓª°‘o¹ãr"1ˆ#·lAû ¸¹ê^E–¶–{&lÀ‚çÜýtߺ¦ÊÎtë Ú™[Ü\rüpŠáéýáXSnÖ³VBòX4Z]¤”oº9—Á°Ç›šï¶%?\² ÷-öz&ì.Ç{±ý ŸÊ÷ cíªL~JÒîLD4ïeƆ~F¯2ÐkJ·L4Tõ-I­ý×Ia@ªšù|5v _¤¾IÁ_=û†”R`Xܶ×àCléŸõ-½¢'üˆ§#Ѱ¯QLjµä§¢U#h¸5Z43ðt®­`£>‰4´ó˜ ªþ!Û/|jäÃ<ñwl«–‚ÛvX…Ui8–еNºéŸª÷rîõî¸çKQÍ%óOáò^Å|Ë"zÐÎÚ›ºƒ‰R±³êêÄ-›ÍjÇx·¤ˆË‹¼®:•BÅènE#Q^’…šcü”r’ÇÒ™"‡ö%,üm€L>QÖÚAQêñ1#+Ñìø/=¡}5^z`‹WËç"QÔoî®ØD°Þ(³Œ& òg-x*þ+"õVTëî%¢›Ñ1þýe·rÖ¾q~øõ™Ì«Y¾P¸º{¡fá⬬¬E™Ø 5íE:¯ÏD§h]·(+\m²[k‚UQÈ_Ã¥gYYy œ£¥Òì[‰WT´¯é.¨ñ¼¯T-Þm k¬Åó ±W³&+oUáïT}oáŠì§}¢VMѾ‚õùý…QüämÌr}ß*7÷»Až3ÊæØÖ ¾·5ØvSlj£°(Š ?‰¿*ŒQÿ½?ù¹K8Zõ$Ä|5Pú7DöªyW £*øXΡ‰¬š´¶EŽº£GEçÙ¾ç#ˆ6›¨a­K’‹ô„°IJÐDyC²A;4¦ä D«V’v(‰Án"[Qùùùäjª£€uö®æó.Ý-ôÎçÜÎYØœÈÀ³—I$܆îŠ5 ¶Ÿ˜¸ÎY¼+x!iˆ%°"YÝ}å\;ëš ;È‹¹/$4ZèÂìØZµZ­uê©ÓǧܿõÅÕéз;ž ´Äw|ßCý=ž€aÕÿ¢Ç(´Lm"¿ù“ÕÍç÷0ÖvÈØ½ÝŒms–Œ€U}á(öD?ì\C=nÓDù¨D~WÁq^ žÆŸƒhtâ~hÄ/¡gÁ±ON ÂÛœ¬m ªÓ`áÜmïDK`ñ^²§§š­:êô1äÍXù,~jdÊûæûV¸)^GßœnÃ|+é4ZŸõ1.îë_É]†È¾:pàŸÑùÍ4f¶Rïû7ô½«yAä!2Õg†„žßÊW\¾GöºÝ‡_ÄO ݼaßžû‰Ð5xwˆ3„U÷»uÛŽÌ"¶—Z.ÙÑTßâí9Ãy1›Ø¨²Ïô•cø¡îãÇûè’ÂÂ'Ÿ1O$©ÍrPoý6Thˆ Ç-Þ^VYFF)‹¯²Œ\²ðWVú£Žþ(Iƒüõ&F:¸±Ayʹ† –ÒœD+ÏßÁÐξ!êKQBßf‚HŠÚ3³°ZÝ#Uh× ö"łϯ¨sƒ©ºéÙòÅ:ãvÄwnòmKx}kS+ühÈà"ÞùMÃ8\Õr§péùøX}.‰ÕØeáÝWÔo:rÂ!uç¹x8ÎwÎóð¼]<ç{…Žoêí- ËÂY#ß§ät9d‰ÁÙâ~Ã’¼†Î[œ±ÛHYnž*üV3ßG¿ ÷¿ úðµ`·°naݺ…õ—(·°jRþ1·½ì-FÜH%tEXtdate:create2017-06-06T01:31:10+01:00M°9%tEXtdate:modify2017-06-06T01:31:10+01:00…IEND®B`‚puzzles-20170606.272beef/icons/dominosa-ibase4.png0000644000175000017500000000207013115373726020472 0ustar simonsimon‰PNG  IHDR˜˜=©ýgAMA† 1è–_bKGDÿ‡Ì¿ oFFs˜+"àtIMEá…·- vpAg0üßÉvBIDATxÚíÛmš« `–ž¥egNýh«çÄ8soø7C‰¯€iÍ£i´¥Þ€€,` XÀ°€Ù°€Öæ‚Ir5y¹;¾S_عéâîø*Ìy¾Ÿs¾;¾ óÇMËF¸;>`¦J¯²c~È`s­FÈâ[a<]*„m—¿ÖFgñÍ3&J`„­I}ÆÎñí{L0L'0åNÚÀä…°×.R lþ0€½ƒÂSkÓ¹Ãô½Ñ…-ŸÅ0!;­ ìû[@ö÷3:¥V0½¾”Îtñù/h()ÙüYü§`iN ŠÆ:a—; Ëø€¬LüqÛÞ¾©?pÛÞaKc¶€ìJ“17?H',]t™/2gÀP* XÀF-eQv˜ZßšÎã³±+nXa<½‡ÇçéA¯Âd>]AéEa8[–žŽ+—õ3#ì3´:e¯.n;» ,/Ø`JaÂa –2¯Ÿ]‚I¦sy‡+lÑœqu))lî0Àª36eE—K°êR.¶,¸ló‹ç“ãN³ÁØæÿ^å(ÓeSzÞüI&[º¨ÁĹ”– ÷XÙÒù„.ç1ËW‚­D_Içú™Ö¤%а€,` XÀ°€= #7#º»ÚÿeHö+lûxíÈêêÿ˜úX¹þÅú0q-e¢õ±©Pÿbý˜k©¦‰ß©ã¥T/L`E»Jý÷÷˜dxó'Y;Õ#KIöª}0M6¿&^„ýmKåúëÿ’T}KIlrõï`Ù¬0ò•´fÇ«ýi?eSÔǰþ0©»ú>Þ uXßB†}„Æ× 0ÍÒÿÿÁú4”dä~ø60üƒ±+¬ãœaXǰ€=›²—Uòµ`ëS; ~&öTÊ\&ÆÒŸ^HŽ¥µ0… œ„ÔÏ–Ûi¬ôþäñ㊖r³ƒ¼ì„ߟ<…e—„´€ߟÜÍ}~Œö|°òû“û³çÇhÁÑ+¿?yœ°åȰ ì‚É~xfÈø¸}`ël‚_Ôº¤ Ó/î”5’ùÑÃŽgöoÁNÊ^-`ë öömÐÞ¾%‚žÿ“°VÙ‹“vå(ž%tEXtdate:create2017-06-06T01:31:18+01:00=¢þ^%tEXtdate:modify2017-06-06T01:31:18+01:00LÿFâIEND®B`‚puzzles-20170606.272beef/icons/dominosa-ibase.png0000644000175000017500000000323713115373726020414 0ustar simonsimon‰PNG  IHDR˜˜=©ýgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿ oFFs˜+"àtIMEá…·- vpAg0üßÉv}IDATxÚí›_lUÆ¥í²•´¶.…n©ZÅŒ› #ÄX±4•hBˆø ØDjŒ Ú(¡1<BÃK5šSß £´Ä µÚ´(Z¥v#Ũÿ<QJÚŠgv·ÝîΜsgîììÔíý:gι¿íܹw÷˹ ÍSß L)0¦À˜S` l~J)06ߤÀdÀÎí ƒ„»Ï%j¸Í§Àƪƒ2u‚ÕcF ·ù$ØŽb¹ºÅ;ŒnóI°rÙºåF ·ù$˜|]ˆ¿:nóØB[úÊÐ$b3WéêOÒ`kþ:ýû@‘l®o,ІX°äÀ¶_‰W8H$›ëÛ«éxäelÍ•K ØÍ“8ÞPRÞØHd›ëÛŸcm,Ø¢/±•{ qðjól/vE°^>pö·ÁGsV3ñg„›À„ö笟l±ëšµ—pŠÞ¥<»Çë¢ ˆCÑk­Á~AÔçý‡ˆ÷ä¬gô¤5ØqÄGïÌ2XA(tqw($ ö0â›+/à…€us}»ëØÌÀ‹ÉOÌÎ1ã)Nüƒÿn'rÍõsV´olêbß}T®4˜se€Iå+°ü«¯[a”p›O‚5dë3J¸Í'Áb+d°®ˆ%Üæ“`Úø3™º‘=ã‰nóI°y)¦ÀˆðÏ„þ˜×"ý3‘?æµhÿLày-Æ?ãý1¯Å-² lÁÅžˆUnû‚å{}¿^O»"Á¢å›{i°LÿÌ&Øw«âw/;Mßß X{r8I™ü3›`Oé©Cm·÷,*aÀÞj?õõ±v`fÿÌ&XŠô]¢ ©/p?­†°¸ôö,föÏì}pƒ~©x—¸{?܆û±ÿV($ÀÌþ™=°¢úå!€ÃÖ7—œáÁŒU>üqƳ2ûg¶Án×/’`÷ÂA[iìס~ÌìŸÙÓåõñá‰Gy ®;Ñ÷6@]ß·tÁ‘­M˜Ù?³–œüUÔä?2;ÂKtA­àÌìŸÙ‹/{ÉåB¶åÕþozõwgföÏl‚%ØJfeçXrê,9A€™ý3›`Z¬E´%±`ϯ k›3†HÉäŸÙóDÙØÄ˜S` L)0¦À˜S`¹ðǬý/Q<…±9i¬v &òǬý/Q< `"ÌÚÿÅÓÀšÖé :úc†Lþ—(ž¶¼ä*çsLìYú_¢xØ_8yjƒS0¡?fí‰â¦9öw½s0Þ³ö¿DñXtϪŵ݈Ÿ9”¬?—ÙÿÅ3–®¥ˆSr“¿ŠŸü&ÿKO1ˆ—¥– Ú#ü/Q<vüкÊ;>Aì•\`IÌÚÿÅS`Ÿ&&ÿ·9ß’xÌÚÿÅS`õoÄ.NŸï¬É£M\)0NLß?æµèþ2Aÿ˜×"ûË„ýc^‹è/Ëßþ±×Ù‰/<0Ä,~|—`|—Ÿ`l—¯`\—¿`>¾ ,oÁ,ÎO¦‰í;²í¦²`íÎ*~öñºb€)0‹ó“ibûÇ6&’*)²¾Ä2`Vç'çŠïÛ´õ½‘w–´ñá–Ã;åÀ,ÏOΑ ,þ½O¿a =Þ r`–ç'çHÜ?¦iûžË6˜õùÉ9BØ?¦i§+ ô«lƒYŸŸLIÜ?¦ „!À˜Xr`ÄùÉYÙèû  JßçÆ“#Ž)ÎJÜ?Ö€ª~v<À@Ygww÷1ØÏ££­í££ÁâŠð ,;ÇÖ'³î"âÃ3eÏçXºlüÏ=’[ `îðŒó¯ücý+ÁxÿÊs0Çþ‚ý AM*j%tEXtdate:create2017-06-06T01:31:10+01:00M°9%tEXtdate:modify2017-06-06T01:31:10+01:00…IEND®B`‚puzzles-20170606.272beef/icons/dominosa-base.png0000644000175000017500000002345113115373716020242 0ustar simonsimon‰PNG  IHDR0¸5¿’bKGDÿÿÿ ½§“ IDATxœí{PçþÆßB#!Š¢€!A¬7Ô‚r=\thS´jéÔ[ujáh±=Ö¢tFsõr¦79Lo…ŠíŒZ+Ê( V¥ C¹‰(*îD$\’ ¿?Þ™ýEÄ4’÷ÝìÒïç¯Í‹yöënž¼›wß}ŸWÜÀÂÜðÿ€!€C€!€C€!€C€!€C€!€C€!€C€!€C€!€C€!€C€!€C€!€C€!€C€!€C€!€C€!€C€!€C€!€C€!€C€!€C€!€C€!€C€!€C€!€C€!€CÌ]çèéé‰?{ö,—×twrrz÷Ýw£££…Bá ?Aý,` ~y…ËÿmöiooW(mmm===æ®åO …ãÇ¿pá¸qã˜F¨Ÿ5†¬ßtà’õ¾øâ‹‡rÿÓ€êééyøðá_|¡ßõ³Æõ›ôÏàîîþøñcsWñØÙÙUTT0/¡~–T¿é@ù üú4 ç †úY†xÁ`Hà`Hà`Hà¬òÂ… NCQYYÉ ý%K– ŬY³ˆè/\¸099ùÖ­[mmmÝÝÝ·oßNHH˜8q"q„ƒƒÃòóó{{{qå¤Äõ±±±©®®Æ»¸xñ"YqooïŸ~úI¥Rõõõµ´´üöÛoo½õeÖŽ`b‡Ø´iÓâÅ‹™—Ó§OŸ>}úªU«<==U*•éúÎÎÎQQQ¦ëü){öì‘Éd4”×®]›œœlii‰_:88ÌŸ??///++ËtqÖŽÌcÈÔÔTýÛ©r¹œ_ú‹/nkkc^Þ¿Ÿˆ¬N§KMMMNN¾}ûö¬Y³¾ÿþ{''§‰'nܸqçΦ뷷·'$$øùùmÞ¼ÙtÁ!ñòòúôÓO»»»mllÈ*O:õÈ‘#–––J¥òã?ÎË˳¶¶öõõ%¥ÏÎñ1Œy 9{öl[[ÛÑ£G¿òÊ+|Ô/..îèèèéé (ûüƒFW©Tß|óM|| ÇçO1Ï N@@€›››««ëÊ•+ x§ïÞ½îîîžžžœœœ   R²ƒnj3oTUU‘Úm>ûì3OOÏŒŒŒÓ§Oýõ×B=== …¢¼¼¼¹¹ùÚµkï¿ÿ>ñ™ó²»»!Ô××———·bÅŠ¼¼<~é‹D"„µµuHHHnnnHHY}„L&Û²e BH­V>|˜¸> äry\\\ggçÆi軸¸ „„Ballì¬Y³$‰¿¿jjêŽ;hìÎ,°jH''§Ý»w_½zU©T^»vM¡P „t:ÝW_}Å ýúúúÍ›7OŸ>](¾úê«™™™!@°{÷n"ú 3gμzõª½½}ooï²eËø2½ñàÁƒcƌپ}{}}= }+++¼‘‘‘aggçãヿycccíììhì‘}Xý éîîîîåry||üìÙ³Beee¼Ð/-----ÅÛUUUëÖ­kiiAyyyÑÇ¥§§ÛÙÙ©Õê°°°Ë—/§G@@ÀÂ… •Jåï¿ÿîáá!‘Hp»H$òð𨫫{ô葉»xôè¾ ôí·ß¶··^¼x1,,lÔ¨QsæÌáË2 «=¤N§ò%3ŠÍq}à™ï/æ »¿¿Ÿˆ>BhÙ²eÙÙÙvvvõõõ<úÙÚÚ"„\]]‹ŠŠJJJΟ?Û}}}KJJV¬Xaú.ŠŠŠðsf™ÞÞ^Óõ¹«=äºuë¦NºhÑ"™LÖØØ¸k×.ÜîççÇ ý´´´[·nýüóÏmxxxnn®T*Å¿Þ?~Ì\¹˜Ž«_………j‹ÅgÏž1côœœ ü5/// `P£Z­ *//©R‡äâÅ‹x q—/_^°`Á‹Þ¥ ×/—Ë•Jå …d;™I“&ÕÕÕ!„rrrÞxã ÿÒøúBiiiaaa!F3zôh ‹ðððÔÔTÓkÞñ!ë V/Y·nݺzõê)S¦ØÚÚZYYI¥Ò5kÖ\¸pˆYÐß¹sç±cÇ*++;::´ZmuuõÑ£G=<<ˆ¸0†+VÄÄÄܾ}[ tuu]¼xQ¡Pq#G€”ŸáO¿¡9ÈKõ0d$Õo:ð´p0$p0$p0ä3àQo1¨`¨Ÿeˆ †|†·ß~?OÀ ¬­­—.]ªßõ³Éóõ›Œ²>ƒZ­~óÍ7[[[¹¿4¨P(´··ÏÎÎ;v,Óõ³Æõ›ôÏ0vìØË—/oذaÒ¤Iæ®Å“&MŠŒŒ¼|ùò OÔÏ/ªßt ‡=$p0$p0$pXr0ñ|‘ó ù,ù„#‚çò!Ùò G6Ï/äC²äŽlˆŸ_ȇ¤ ¿ÜˆxX°y!~¸ F2`Hà`Hà¬òÒ¥KÑÑÑóçÏŸ1c†››[ppðÎ;ñZÃDxôèQllì’%Kär9N†}º´´ôäÉ“&L@µ´´|ÿý÷DôÅbqddäÁƒ?üðC"‚ƒØ±cvË¡C‡&OžŒ?ŽŽŽûöíã…~BBvãÚµkóóócbbBÍÍÍŸþ9}LYYÙwß}Ǭ5LWW×½{÷æä䔕•¥§§»¹¹!„úúúΞ=KD_?244ÔÆÆfüøñ‹-"ÖdV{HµZ­ÿüØáÇãââBï¾ûnRRÁ%%%ý÷¿ÿE¤{Èææf‰D¢ÕjǧÑhB555...:N"‘˜>><}ãÏàœ9sZ[[­¬¬*++ñœ/oo@P^^NäѾþþþE‹ݼy3..Ÿ\‚=ä ñ}ù-[¶l۶͘·>¿IIIŸ|ò B(88çO{ÈA§œ™0áêêÊfÃÃÅÅ_W+•J섾),<==9®ßÐЀ××J¥Ì ÌiÓ¦!„t:©µž:tóæM…BA|m }t:]eeå/¿ü‚‹Å¤~¦r!Òl“ËëëëñÏ ±XÌ‹ÌM|R«ÕL#³múo`Úú>Äb±˜iÄ 9!Ó£©Buuuûöí‰DT'ôé϶qrrJII!x¬Ÿ?‰[p¥\.ß³g‘]ü)æ¹íq÷îÝwÞy§­­ÍÚÚúèÑ£Ìg‘èǤӈL§­¯ÃN6’=&&¦§§'&&ÆÑÑ‘ ì Äb1ÓÃ766®Y³¦²²’ˆ2ò'Í`È‚‚‚°°°ÆÆF±Xüã?²_Ã0hnnÆúÞ̶é7ohë;88àŽŽ¦±³³oüío3Q¿°°ðÒ¥K...ÞÞÞwïÞÅí¦¢¢‚à³ëׯ߿¿´´tùòå¡ÖÖV&†ÌD˜ËýüI„Ο$²‹?…mCþúë¯ï½÷žZ­vttLKKó÷÷g¹€aS[[‹]!—Ë™!ÄY³f!„t:]II Çõq²Z}}=óë÷-'ÛšBWWB¨¶¶644T¡P¬^½·+ŠŒŒ õ!‘HÖ¯_·}ÚÖÖ¦ÿ´›F£Á-DôSRRBVVVñññ®®®±±±øö]zz:‘€¶>üÐjµqqqµµµû÷ïojjB…††_=›6m:sæLeeekkë7¾þúkÜ.“Ɉè?~o„‡‡[XXÈd2²ù“ÆÀêm•+WyKÇßßÿÌ™3¦ë×ÕÕùúúù'¥RiÌ ¼Ã˜ R©üüüèM øS}'H$’ÌÌLâË.655Í›7½í1äÃS"‘èÌ™3Föð4ò'y|Ûƒïtvv%$$ÔÔÔhµZ•J•’’âããCÄ,è‹D¢´´´ÈÈÈI“&YYYI$’U«Veeeq|T†õë×{yyÙÛÛ ¡P8eÊ”ˆˆˆììlÓ¯·Ìž? (?äŽlhœ_è!`Ɔ†|È'Ì ò Ÿ0/`Ègø×¿þ%‘Hx±¸P(”H$ø™F`Ć|È'Ì Ü‡þBÀ}H^0$p0$pòKxð=_‘ïõ¼†ð ßóù^?`˜¿Ü ßóù^?Àw÷|ÏWä{ý€aþr=$¿>Í蹂ù^?Àw`”888„y iccS]]=00000ð|@‰ÐË÷spp8pà@~~~oo/.>""‚ˆ2;úˆr>$íüFÚúK–, ¼:.;˜'ÛcÏž=¤ÖÒÄ |?‡ùóççååeee™.îììeºŽ¹ô»ººÞyçfÈ–––“'OþöÛo¤ò!ËË˳³³™—*•*333;;ÛøüFóês3ô^^^Ÿ~ú)NM í|¿ööö„„„Õ«W8p€ˆ Ëú´ó!iç7ÒÖgX¼x±¿÷ïß'«o¶{HKKËÇ[ZZÆÆÆÆÇÇ“ŠŠÂÏû‡‡‡ã|?FsîÜ9RúÕÕÕÑÑÑ!RqK,ëã‹­¬¬âââ„BaTTTjjjCCÃùóçEw ,X°o;88¬X±Ï[`Bl8®ÏP\\ÜÑÑÑÓÓC6ŒÈØî!?ûì3OOÏŒŒŒÓ§OçB¾ga'C)¿‘5ý{÷îuww÷ôôäää‘7 «=¤\.‹‹ëììܸq# }.äûqò!1ôòÙÑG‰D"„µµuHHHppphhhnn.Ù]¼V{ȃŽ3fûöíõõõ4ô¹ïÇ}èåCbèå7ÒÖ¯¯¯ß¼yóôéÓ…B᫯¾š™™‰»wï&¢o ì2 `áÂ…J¥ò÷ß÷ðð`†ÅD"‘‡‡‡éù„ˆù~œ…v>$½üFÚú¥¥¥‰‰‰wîÜéíí­ªªZ·nn÷òò"¢o ì_¹ºº•””œ?·ûúú–””¬X±Âô]p!߳зüFÚúÁ3¿à˜ ®þþ~"úÆ0¢fêÐÎ÷³°°°·····gUE"n1]œ}Úù´óië§¥¥}õÕW~~~‰dÞ¼y?üðn¿rå }c üø•ñ·Lš4©®®!”““óÆo*ÀÄ|?ÃõËår¥R9䟄B¡éððô¹“iz~#m}Ãç7/// `P£Z­ 20 Íéǯ̎Ùóý¸ í|HÚù´õwîÜyìØ±ÊÊÊŽŽ­V[]]}ôèQ²÷„ c¶’;ßCr.¯ýÃ5þr(` `Hà`Hà„ É»¸ÂAó½~À0ÄqA†ä{¾"ßë CöüÒ8þ„GYÕjõ›o¾ÙÚÚÊý¥M…B¡½½}vv¶þ=q¾×†àù¥tü ÷|ÏWä{ý€aH_zÇò!€C˜gM€§ddd×ÔÿF[ŸûÀmàpÉ ‚£ù#8¿‘ïõTán>äˆÌoä{ým¸›9"óù^?@®çCްüF¾×Іëù#,¿‘ïõ´ÛÀ!ÀÀ!ÀÀ!X5äßÿþ÷ôôôêêêîîî¾¾¾úúúÓ§OÏ›7”>kù~Tó-G€¾F£ñññqrrrrr"¼qéÒ¥èèèùóçϘ1ÃÍÍ-88xçÎ---¤ô=z»dɹ\Ž‹?yò$)q#au.ëܹsß~ûm楳³óòåË—.]êëë[VVÆf%&B/ßrdèùå—4Ò"’““õ¿>ªªªªªª~ùå—ììl‰Dbº¾J¥:vì˜é:¦ÀjyïÞ½O?ýôµ×^›8qb`` ^ ÔÚÚzõêÕdwD5ß^¾åÈÐ/++ûî»ï˜µž bii¹|ùòÓ§O—––ž‘HÄ„»úúú#GŽ „ÄbñHÊä5ƒ!ÕjµF£ÁÛR©ôܹs¤FAiçûÑηä»~LLLOOOLLŒ££# }†»wï¾óÎ;mmmÖÖÖGÅ?&Gf0¤›››££#ŽÜH$Ÿþ9eªù~´ó-ù®_XXxéÒ%ooïŠŠŠ»wïâvFSQQAp ^AAAXXXcc£X,þñÇI)s³M P©T‰‰‰x{êÔ©D4©æûÑηä»~WWB¨¶¶644T¡P0#çÅÅÅ …‚ÔÚ¿þúë{ï½§V«ÓÒÒüýý‰ÈrVïCž8qâܹs¥¥¥---R©t×®]¸Ôm‰´´´[·nýüóÏ¿‡gƒ:?É0"óiŸ_îóKVÈŸd‘ù´Ï/÷áY ù“ƒaù´Ï/÷áY ù“ƒà]Á†¡}~¹Ï #0$p0$p3ÒÛÛû§Ÿ~R©T}}}---¿ýöÛ[o½ED™vþ$†^ý!;;»øøøêêê'Ož455%''K¥RRâ´óiëc¨µZçãã#“É<<<¢££Y¾Íö(ëÚµk“““---õ÷îÝ»cÇŽ½ÅøE¢6mÚô¿ÿýoPã“'O çO¾Ô"Tèßxlmm¯_¿îîî®ßØÔÔäïïo àÉø3øÁ<Ï*‘HHå+š®Oûóc˜®®®¥K—â”D† &ddd°öt«=äÔ©S9bii©T*CCCmllÆ¿hÑ¢!Û´ó'i׿cÇìÆC‡MžêÓ†Ëkÿ¼,°®/<í  ‚°!‰Ç ²œOÈ»8DÞ †°!Éæ²ŸOù€y!<ÊJ0ÿpÈ|BÈŸd‘ù0ÊJ¸‡$•h®|BÈoÌ á’6ð :²óË¿°ÀŒdddׄŸÁúÀmàÐC/ôf´!oH¾çûA>$`FêÐÎ÷ãQþ$mxšhÔ!ü’ïù~ ˜†ÌÈÈèëë#¥Ö××GcXÏdë§ ûÇ  aCò=ßwq‚¼+0 Üö††Áª!iç7:888p ??¿··w````` ""‚”8BhÉ’%CAjetÚÇçÑ£G±±±K–,‘ËåNNNNNN'Ož$%Žºpá‚ÓPàÕMIA5£Ñh|||pñxmHÖ`u¦Îܹsß~ûm楳³óòåË—.]j8¿Ñxœ£¢¢L×1´J¥:vì˜é:fdP>¤ƒƒÃüùóóòò²²²îåË/¿¬¯¯'(h<¬ç7^¹r¥¹¹yÊ”)ÇŽ›6mÎo$òkooOHH(((ðóóÛ¼y³é‚/bñâÅmmmÌKR 1Ó>>b±822rîܹEEEG5]ðE¤¦¦êOWËåDdõó!?þøã¼¼~ü8ÎoÔjµDô«««£££¹OÀ‹(..îèèèéé!ÆBûøH¥RsRWWGDðEÌž=ÛÖÖvôèÑd¢¢¢ðzááá8R£Ñœ;wŽà.úûû·nÝÚßß¿mÛ6nÉ2æÔ¡”ßÈ÷îÝëîîîééÉÉÉ "®Ï÷ãàæææêêºråÊ‚‚R²,ä‹:tèæÍ› …Â\ÓèÍð´½üFÖ‰D!kkëàààÐÐÐÜÜ\Râ#àøà”¸¾¾¾¼¼¼üü|RX´óEëêêöíÛ'‰Ì8!Ñ =$½üFÚÔ××oÞ¼yúôéB¡ðÕW_ÍÌÌD ‚Ý»wÜ ““ÓîÝ»¯^½ªT*¯]»¦P(B:¾"¢O;2&&¦§§'&&ÆÑÑÑtµáaCÒËo¤Miiibbâ;wz{{«ªªÖ­[‡Û½¼¼î…¿ÇÇÝÝ}ýúõnnnÖÖÖr¹<>>·‘B”ó! /]ºäâââíí]QQÁ$vi4šŠŠ Ö¦(šmbüFÚÏ\á3_ØýýýÄ÷ÅÇãä5zÉÜ¥0ªù]]]¡ÚÚÚÐÐP…B±zõjÜ^\\¬P(X›ÄÏêoÈ'Nœ;w®´´´¥¥E*•Ïo´°°À 3§"‘§p¶¶¶š®Ÿ––vëÖ­ŸþùÁƒR©ô›o¾ÁíW®\1]Ñ?>OŸ>mooG1Ï—i4|ÿ†È‚ËëÖ­›:uê¢E‹d2Ycc#S¿ŸŸŸéâ¡ãÇ/^¼!ž››+•JÉæCrVÓ¯hç7Êår¥R9䟄BዾD×ÏËË Ô¨V«ƒ‚‚ÊËË ¼ÑHL?>†©««{Ñ];¥Riú Ñaaa………ƒÅbñÙ³gg̘aŒ‚yó!õêÿÒIDATijjÂs¤O:5 …áÁê%+ ùTÙ¹sç±cÇ*++;::´ZmuuõÑ£G=<<ˆ¸ñÿølݺuõêÕS¦L±µµµ²²’J¥kÖ¬¹pá‚‘n4ªù\ò!!’CÀð´p0$p0$pž’vþ$ïâyW°aøž/j:<3$íüIȇ4/|Ï5ž²ÒΟ„|HóBûüržõ´ó'!Ò¼ð=_ÔtxÖCÀȆg=$ŒlÀÀ!ÀÀ!øØÊ÷üF¾×P…gƒ:|Ïoä{ýmxvÉÊ÷üF¾×Іg=¤»»;¿Øììì***˜—|¯  ÏzH~}šÑsó½~€6<3$ŒlÀÀ!ÀÀ!X5äÂ… “““oݺÕÖÖÖÝÝ}ûöí„„„‰'òEC/Ÿ…úíììâãã«««Ÿ¨qÔ¨QYYY3gÎ4]ßXí!u:]jjjHHˆ£££B¡Àgzâĉ7nä…¾~>ahh¨Íøñã-Z”——GDŸvý;vìÀn¡1p§þææf‰D¢ÕjLJó|jjj\\\t:D"yÑŽaô¥¥¥4ò!çÌ™ÓÚÚjeeUYY‰çôy{{744‚òòrâ>&&&ây[¶lÙ¶mYñÁj9è”3 þ“Š[£­O;Ÿjý...‰!¤T*™t-|Ó_ xzzš¾ ù 8B*•23l§M›†Òét¤ÖªÆètºÊÊÊ_~ù!$‹qP';˜mr¹L&Û²e BH­V>|˜ú´ó õ!^ÿ„ ð†Z­f™mìURÐȇ|øð!Þ‹ÅL£­­-Þ`‚±LG6•““SJJ í@n}ÌsÛcæÌ™W¯^µ··ïíí]¶lñç(éÓÎ'd z|ô/#É^RÒ·ÄèÇÈ“”LjÅb¦nll\³f ÁQâ?Å † ÊËË“J¥jµzáÂ…999|ѧšOÈ@©þææf¼¡ÿ[‹Ùnii1}Tó!ðFGGÓØÙÙ‰7ž)6ׯ_¿ÿ~iiéòåËB­­­LÌ °mÈeË–eggÛÙÙÕ××^¾|™GúTó 1ô꯭­Å®“Ëå̯SœÍ¬ÓéJJJLßÕ|Hgggœ,X__Ï<.ƒû.@0{ölÓw¡D"Y¿~=Þ~ðàYq°jÈ 6œ:ujôèÑ?Þ²e‹H$òóóóóó#u“‡¶þñãÇñFxx¸………L&#›OH»þ””„••U||¼««kll,¾}—žžNdùºuëöìÙSTTÔÚÚzãÆ <"ÈåCâÁ­VW[[»ÿþ¦¦&„Phh(‘!ÖM›69s¦²²×ÿõ×_ãv™Lfº¸‘°zÛãâÅ‹x r—/_^°`Á‹Þeümƒáé¿&æš·þ!'¨T*???"Lχ4Ì$Iff&‘‰C>'‰Îœ9C¼~0—õåàu>agggPPPBBBMMV«U©T)))>>>ÜøRз‰Diii‘‘‘“&M²²²’H$«V­ÊÊÊ"µˆîúõë½¼¼ìííP(œ2eJDDDvv6knD¼{@™ïù|¯  ôÀ!ÀÀ!ÀÀ!ò1ÂêhCØß¨ÏÈ«  áQVÈod‘õ´!ÜCB~#f¤ÖІp €)À(+p0$p0$p0$p0$p0$p0$p0$p0$p0$p0$p0$p0$p0$p0$p0$p0$p0$p0$p0$p0$p0$p0$p0$p0$pˆÿ·<³<åüIEND®B`‚puzzles-20170606.272beef/icons/dominosa-48d8.png0000644000175000017500000000263313115373726020017 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá…·-£IDATHÇ•{lSUÇí½KÇVYðH|N×ÍçFÄ,€2sÀÔˆ Áù^‡ãQ >5K˜º&ò‡™1° ¨Hâ|ìI«›e²°´÷žsß·íèº þÑsÎíín7ߤÍ/¿žÏ9¿×9iž‚ÿ <Ó±„f­E6€MSVd‡Ù4äøLŸKÈìXv»¯¨°ÀVQaþ¿©[oñM;}wú ò›bˆÂd-ð!ÞéW¦Ï EŠ”üÀçlYœ›‰ßt£ vw*oÛJæä dû"Ÿ< ¸rÚÛÉD<ñ×: €Ž­`ç¸a ~  }B x êY äw_SÛÓ €%bÓ>;œöUpœÀÇgÓÝ8Xó:dž_Þíæ©Ów„êœ'®ÝÓPœ‹ ¶ƒ•CÉGÅà&Ö7¼å…By:¤YUb9̨’н~AîÂN_ f(8j¨’íû}4ŽD"a”œž%E×5U·¥jºB†‰ú4ò5v`mUÕ† ë×1‘=­‹zTÄ–©°iÄ(—RC‹R͸OÃéñÆÑ¾Ž¨5³Xÿõ¢Â,å§HFú ×Å»–Ýϧ;McŠ^¹üË„HLqü|Ã,YØ÷puBÐsÞ8]ퟒīuo·>6E–am¨nõÁ$y¡l縜?¼7;]V L~²Ñÿ2ÄÄÁÒ[7ÓúIräÔ¶²¸È€Ž]ý…Î$Y¬«Ñœ$9<´³•X}óÙæ,ýê9pž@OjVÒŠ‘ˆ¥¬±Dc ¸2:mÕFqÚ´¯3"–¸9n0§æ:¾ÿhYÑ )ªˆ®Ù„¦ã¹NÀFx$Õiy ”²”?L ÏÍ‹]Ng+<§ÅTC»–7[?x¤þ²UÖ–Ž3Ê*^©ýóǧXŽâFÖi¬Ëk“V§›ÏTgS{ªßßÂIøqÕ+“Ì›+ÇØ Üm«…ëœÆÚ…§ÖvÒqÇFïó¿¶‚ymSC”¹døŽíçðÂÐ v °‘bˆ”X¢ÇHÌqñœ²¦C‚(F"B„ôU1 ÝÔ5ÃPeƒŠîö±÷€ƒŠ¨u°:‘dšˆÉ#Ý}½D}ÝÃBO5ûz‚focѧûCÖÃZè³@ ¥%h>i^ìêaêRVWPÖ''˜TÌBBñï­‡š|OhhD& I§¦FB„ù`)üYï’XK2‚‘# Ó¤%Ua驺’þËb'pPÖ@ )"óü½ÇYY•pmÅìî¡X`éÏQäÜÝ0|7™€¤€õ÷ò¿e–/¡½åãt–GJÛ.;,ØÑÜNp¢õÑÒcÖ¾g*{M¶ ]©<1î8(öÿù )¢÷î/©g!Éè®{>f•A±Kž +Τyäñ4iëWÕÊ ÷Ÿ“­A8'ÊΤS:}Á° Û7Žô9=9†lW ý/ùý55þW_h´œŽ+ŠgYl4¦&™¦ÆÿíEH_Jâæ¥ytvy¸¿ƒ%tEXtdate:create2017-06-06T01:31:18+01:00=¢þ^%tEXtdate:modify2017-06-06T01:31:18+01:00LÿFâIEND®B`‚puzzles-20170606.272beef/icons/dominosa-48d4.png0000644000175000017500000000107613115373726020013 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA† 1è–_bKGDÿ‡Ì¿tIMEá…·-rIDATHÇÝUQ’Å ãè9Znæ"¢ÄúºÓíìþ,Óéó)1)Z;í³Ö`f°þƒ>sÚr!è€ô¼˜¯|´[ÚÝtcü låJe k“GH¾OmÄ;ÁÉàÙ¨íAŸ 9'@^gˆ|ŒY²ÌÒã:xˆ®´?þŠwŒû4e.-¤ñÔÜý 8TÇ|m•~²÷vè0ìÔÓ@@<ÅåeÅŠ.¡6å†xá‡ÏK,˜ =_Rpù[îƒÐ‚°9™ CnóÐ[B믇¶×iýo€³ñÕ7ßC(k¢uëÂu¸å%Z‚JÃ>k‰…U-aµ™@ß`£­Î’ZŽŒ‹íU–þ¨pÑ;C¯<œŒ·qÅÄ'd&ñá-@¾¸[@Þ£Xª’ÒU.' «¢+-Ú´ŠRÞ°‘ ÜúR `¤„g‘*`Éú˜3·-Ÿí<øµ´Þ€eO~re ûA^ãWÙ %tEXtdate:create2017-06-06T01:31:18+01:00=¢þ^%tEXtdate:modify2017-06-06T01:31:18+01:00LÿFâIEND®B`‚puzzles-20170606.272beef/icons/dominosa-48d24.png0000644000175000017500000000263313115373726020075 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá…·-£IDATHÇ•{lSUÇí½KÇVYðH|N×ÍçFÄ,€2sÀÔˆ Áù^‡ãQ >5K˜º&ò‡™1° ¨Hâ|ìI«›e²°´÷žsß·íèº þÑsÎíín7ߤÍ/¿žÏ9¿×9iž‚ÿ <Ó±„f­E6€MSVd‡Ù4äøLŸKÈìXv»¯¨°ÀVQaþ¿©[oñM;}wú ò›bˆÂd-ð!ÞéW¦Ï EŠ”üÀçlYœ›‰ßt£ vw*oÛJæä dû"Ÿ< ¸rÚÛÉD<ñ×: €Ž­`ç¸a ~  }B x êY äw_SÛÓ €%bÓ>;œöUpœÀÇgÓÝ8Xó:dž_Þíæ©Ów„êœ'®ÝÓPœ‹ ¶ƒ•CÉGÅà&Ö7¼å…By:¤YUb9̨’н~AîÂN_ f(8j¨’íû}4ŽD"a”œž%E×5U·¥jºB†‰ú4ò5v`mUÕ† ë×1‘=­‹zTÄ–©°iÄ(—RC‹R͸OÃéñÆÑ¾Ž¨5³Xÿõ¢Â,å§HFú ×Å»–Ýϧ;McŠ^¹üË„HLqü|Ã,YØ÷puBÐsÞ8]ퟒīuo·>6E–am¨nõÁ$y¡l縜?¼7;]V L~²Ñÿ2ÄÄÁÒ[7ÓúIräÔ¶²¸È€Ž]ý…Î$Y¬«Ñœ$9<´³•X}óÙæ,ýê9pž@OjVÒŠ‘ˆ¥¬±Dc ¸2:mÕFqÚ´¯3"–¸9n0§æ:¾ÿhYÑ )ªˆ®Ù„¦ã¹NÀFx$Õiy ”²”?L ÏÍ‹]Ng+<§ÅTC»–7[?x¤þ²UÖ–Ž3Ê*^©ýóǧXŽâFÖi¬Ëk“V§›ÏTgS{ªßßÂIøqÕ+“Ì›+ÇØ Üm«…ëœÆÚ…§ÖvÒqÇFïó¿¶‚ymSC”¹døŽíçðÂÐ v °‘bˆ”X¢ÇHÌqñœ²¦C‚(F"B„ôU1 ÝÔ5ÃPeƒŠîö±÷€ƒŠ¨u°:‘dšˆÉ#Ý}½D}ÝÃBO5ûz‚focѧûCÖÃZè³@ ¥%h>i^ìêaêRVWPÖ''˜TÌBBñï­‡š|OhhD& I§¦FB„ù`)üYï’XK2‚‘# Ó¤%Ua驺’þËb'pPÖ@ )"óü½ÇYY•pmÅìî¡X`éÏQäÜÝ0|7™€¤€õ÷ò¿e–/¡½åãt–GJÛ.;,ØÑÜNp¢õÑÒcÖ¾g*{M¶ ]©<1î8(öÿù )¢÷î/©g!Éè®{>f•A±Kž +Τyäñ4iëWÕÊ ÷Ÿ“­A8'ÊΤS:}Á° Û7Žô9=9†lW ý/ùý55þW_h´œŽ+ŠgYl4¦&™¦ÆÿíEH_Jâæ¥ytvy¸¿ƒ%tEXtdate:create2017-06-06T01:31:18+01:00=¢þ^%tEXtdate:modify2017-06-06T01:31:18+01:00LÿFâIEND®B`‚puzzles-20170606.272beef/icons/dominosa-32d8.png0000644000175000017500000000177613115373726020017 0ustar simonsimon‰PNG  IHDR V%(gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá…·-IDAT8ËmSmKQ>;;kh¡¥Ñ‡~AhÆnõ!Ð £ HÒB0­ M{A·uÅÚ¤7„J’”Þ ƒ¾…T›¥‘«™ÎÜ{çmgg×]w¬O¹®aÑóåÌ™ûÌ=ç<Ï`Œü*/KdÆ€Q3µ¢BcHgѸ€Xý…Þ¯Ïçóú¼Þ׿îðz |6yó«T’] YÀ!fÀîû ˆ™<Ë!{B)urŸmÑí ö>„œÇÇ1¡ã4¬ux· Àæ÷· èäÞY.7”\„\N8ëzÊ ÃãÊ­8 E ³¦VEÔ_sçð5 BnØû„¥Ìya ¨>h ´ùmíí¯éÕ–ö€¿5pãúÍ®+/ Š:èvj!e;HÙ ¦’²Ù©Ÿæù#套5ŠÑYõ;“%›‘>“ó9VrÓJ}s¨Ë»ÑoËL! uFl„à9Xà ²Ýyá”J‰5¸¥:F±º‹µø Xÿª'/ó›C ‘Py¯E¨þ¥õB„R-ÜЬÄÀU{yÅJN`Ô0L’–‚‘ÉQâ„E©7”RdâìBžÃ÷¿ìw9ÁåZ"¤KàùbM§„ž4›<ê4©M¹ŠS(Rc³ŽcºûªÒ:¤Çd4(Mà˜±îboð4ôf¬ú¶L(óTS”P5|¾–á Y=™Ùœ s©‰ª+S–®*º6ejIÓ-@ŽC@w³Ì鱉ðøØäìb˜ªÜ³oQ“FAýq©Å4˜ …¾N‡†CCGÔùd"1ŸÀß^ŸÈFÛÜpÈVµäœ®+F$–2t*K†&Éœ+@ÝA8ü‘ºÝ5'Su²åŠNp]Zúâ„VÃÆwõp0¡ ï¬MÈ(K¥IIÞëø)qBøžt"A[v̤TÞŒ !ÖxXcK=¸€‡ÿçw’“öª– ¦Ëç¡-?cÀºw_ 'Äë3 PQ}V‘å¨ÂGS‡%о‡ Ya¾ÃÈÒ´hG[‡@Ùf€Cðô’_y%yg¹ÕežöŒ¼Ü®æ¾ÏD¹uP’¢õýJReruÆ#˜Sæ¤, lààêÀMRÖÏénç°e¾Yþèàë¦xl=ø$˜+#^äÎ7W®ƒºÒéKNÕ-‹ÐøºÝy3Þ!`€ÛÞz)¼_ƒ'žÏwô˜é‚RÀ3×× ÇÞæž&ÿ^ºpÿøÈ~¾%tEXtdate:create2017-06-06T01:31:18+01:00=¢þ^%tEXtdate:modify2017-06-06T01:31:18+01:00LÿFâIEND®B`‚puzzles-20170606.272beef/icons/dominosa-32d24.png0000644000175000017500000000177613115373726020075 0ustar simonsimon‰PNG  IHDR V%(gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá…·-IDAT8ËmSmKQ>;;kh¡¥Ñ‡~AhÆnõ!Ð £ HÒB0­ M{A·uÅÚ¤7„J’”Þ ƒ¾…T›¥‘«™ÎÜ{çmgg×]w¬O¹®aÑóåÌ™ûÌ=ç<Ï`Œü*/KdÆ€Q3µ¢BcHgѸ€Xý…Þ¯Ïçóú¼Þ׿îðz |6yó«T’] YÀ!fÀîû ˆ™<Ë!{B)urŸmÑí ö>„œÇÇ1¡ã4¬ux· Àæ÷· èäÞY.7”\„\N8ëzÊ ÃãÊ­8 E ³¦VEÔ_sçð5 BnØû„¥Ìya ¨>h ´ùmíí¯éÕ–ö€¿5pãúÍ®+/ Š:èvj!e;HÙ ¦’²Ù©Ÿæù#套5ŠÑYõ;“%›‘>“ó9VrÓJ}s¨Ë»ÑoËL! uFl„à9Xà ²Ýyá”J‰5¸¥:F±º‹µø Xÿª'/ó›C ‘Py¯E¨þ¥õB„R-ÜЬÄÀU{yÅJN`Ô0L’–‚‘ÉQâ„E©7”RdâìBžÃ÷¿ìw9ÁåZ"¤KàùbM§„ž4›<ê4©M¹ŠS(Rc³ŽcºûªÒ:¤Çd4(Mà˜±îboð4ôf¬ú¶L(óTS”P5|¾–á Y=™Ùœ s©‰ª+S–®*º6ejIÓ-@ŽC@w³Ì鱉ðøØäìb˜ªÜ³oQ“FAýq©Å4˜ …¾N‡†CCGÔùd"1ŸÀß^ŸÈFÛÜpÈVµäœ®+F$–2t*K†&Éœ+@ÝA8ü‘ºÝ5'Su²åŠNp]Zúâ„VÃÆwõp0¡ ï¬MÈ(K¥IIÞëø)qBøžt"A[v̤TÞŒ !ÖxXcK=¸áäQ¥/WÁç€%tEXtdate:create2017-06-06T01:31:18+01:00=¢þ^%tEXtdate:modify2017-06-06T01:31:18+01:00LÿFâIEND®B`‚puzzles-20170606.272beef/icons/dominosa-16d24.png0000644000175000017500000000102313115373726020060 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá…·-IDATÓïþçèáãäåâèêâãääáçèï]"(%$Vp*#(';Ýñ-@+u4 ŒËx7{˜¥âÏ~‚ˆÆ˜›½JÌ|!|ÿ:kמcººº:::Œ1ÂòšP¼>ö7™„hG!"Ân•¸„Öúüùó³_¿ª»ºº^ý·ßþG&“F´Ú ÐU‘ y^¨”&²]‚ ÐÚn!!„Rª¿¿ttk¯_UhŒI$’'Nüó­·¶ûþ Ö%kG®èØðÀ*€›…òQôÄÑ£O'“}Æ(;UÀ“J¥víÚõüóÏg³ÙÙ;·µ‘ïû»wï.—ËAÔ—Ù½*I)VûþÈÚžU@``¥½BBh­ý0ìº+•ú>bÅÎæ€1&“Éär¹ÁÁÁ\.§µ¶Tˆˆ¢(J§Óuç+³ D@ZƒÖö:„xÉXýÅn!¥°Tš(ÙSˆˆBˆJ¥255ÕV¨”Rª¾;ñÞ)ª–Z¡¸þë…D;U@áy^ Å%_äëBça…Îà ‡:+tVè<¬ÐyX¡ó°Bça…Îà ‡:+tVè<¬ÐyX¡ó°Bça…Îà ‡:+tVè<¬ÐyX¡ó°Bça…Îà ‡:Oc,FU­†Ó@[.¤|RJ+¥•¥À "*¥ˆHW±TÈ/¹nù ƒê£Õر¨–¶W(ÞZ¯··'îÓºlOa2™Œ¢¨§§§P(ØËc‰„”2NlÏõ¼`«ç­ð<[i< ú„h@ÀV/ŽƒkýÙcm–2Id1z.¥o;¨]סñ³P륦•š¶§°R)3ûPµÔóÁÌÌŒ”ÓV³öq>{fffzzÚªÂ9o äÏùn›ãÚ²ëÛ­/T­gus®nÒœ¿[-Tƒ¯ ‡:+tVè<¬ÐyX¡ó°Bça…Îà ‡:+tVè<¬ÐyX¡ó°Bça…Îà Ç_ú"þ˜g*$cLÝ8Ò%Öò}ÿ†þõÏ Æ“Ëå‰Dm0îl1•Ô××ZÊØ "ºtéR¹\Žïºß ¬p±³³óå—_þàƒR©Tc[Œ'q9yòäÆÃ0\Ê8R" ÃpdddõêÕß|ó”²™¿b… ïÖ'NlÛ¶mÅŠår¹î ñàÍýû÷OMM-Å"æóùM›6íܹóÕW_hÒ"+\"’R®]»våÊ•333oB ¢çy³ÇÉß(ñÌg·ÝvÛ<°wïÞÑÑÑ5kÖ4c‘6"–J¥R©ÔØ [X" ÃË—/oذ¡¯¯¯X,ŽÝqÇ Zd…Írmü«‘¢ñÄAžç]¸paýúõJ©b±xàÀ-òuá-DÜ K)c‹;wî,‹_|ñÅüQ Vx+âûþÅ‹ׯ_ÿÌ3ϋʼn‰‰L&ómWœ¬ð%n‹6lˆ-ÎÓYá­KÍbÜ£NLLd³ÙƯêOgí¥µÖÚ˜ZP[ÛjkZkÄE~掠ÖÛ0ðœÔ>‰hÏž=¯¼òJ*•ªk‹õ s¹\>Ÿ¢È’B¥T2Ù†!€¬®€Õ(×ÝO§ ZW·AJ©t:µÄ¯]–B­-Q±XœœœL$³WæšÂ8DºyóæþþþJ¥b/óEÑøøgO"¦ìå§ ,—?½ÿþÍR&ˆ9Ó;‘ ‚pbâdã$ºm#¶xï½÷cöîÝ«™3kZë}ûö –J%«)ßM›6¿÷Þ‹ž7€8³ôe~ 7æÁ>ú À÷*‹mî Û÷æû%¢›vêPk‹‡*—˳b}P{Ù²eË—/·§P)Õ××—H$º…ÈÙjDR~ ¿”U& „mvMáy^¹\Ž?çîH¯®¯R•JÅ^Gª”ªTÊí쑪ŸýK:Vâù–Û¶Î߯-’òm j·©î’—psNg„¯ ‡:+tVè<¬ÐyX¡ó°Bça…Îà ‡:+tVè<¬ÐyX¡ó°Bça…Îà ‡c1M"´ÖJYœÏ'ïJD7:Ú‘6…ÐÓÓ›Ïwkm1œ–L¦¢(Š¢Ä -b…M¡5>òÈσ`€èRus‹‰ÇñŽþùø}÷=xñâ9)›²Ã Ä¢±÷ßÿÀF€uçíì7"$ú÷ŽO>LëÖ=téÒyj·`~$åߊ«ÖZþ*„1¦ïܹ7¶oßòÚkbݺ/_^Ø"Ÿ‘6ƒ€ˆkÿ€øâ¿""Rk´Æ ç ~õÕO>ùÒñãÇ:;ó zXa“H0p`?ÀgD«¤1FÊŸœ=û·§žúóñãÇ:; óÏÆÆ ›Ç@€A€ƒE€O|;£ô=DíywŸ9sxûö—ÞyçX6›ç v«ˆ[Þ/ìø¸êµåøÕõ¯Û¶½ôî»óõ¨¬ðF‰{Ô!€1€}ŸV½¶¾1(å=çÎŽ{Ôl¶ÀAíVáh€»ìø¸êµåHDíyC_}8>»ÉfóßÝÔ_TcŒ1ˆh-"ŠˆHñ‘+ZËÇ €ODB˜êÓ"*wü `7À‹D÷Q±pÕ/Œ©øþà™3¯oݺõÍ7e"ѱÀ,¢ét:“ÉÄ·±iõÚ(¥‰¤ïûq@$­)ŒVQÍu¶|çÆ-ïn€×FöýØÎõ¢ÔÚñÓ Žlݺ=þO2™"ºvDÖµ·lÙµ[¿K«U¢(Ÿ{è¡áƒÿ¸|ùw+{3j«L¦ïá‡yèÐh.gu:fHä}ô‰+WJQ͵'¢ÎÎÎ\.=……B!!º¤,xž­yŸ‰´”!B)sR¤\tÖ~APʤÂó ž—“ÒÞ¤èFˆ ñ¼iŽûÎh­íÎÄ·>&""$ÒD¶î;S]8¡1Ú[ÿç#BcÈÄgJµºÉÆ&¶û¢Âê„ÓómÿD×mƒ¯ ‡:+tVè<¬ÐyX¡ó°Bça…Îà ‡:+tVè<¬ÐyX¡ó°Bça…Îà ‡:+tVè<¬ÐyX¡ó°Bça…Îà ‡:+tVè<×EDã‰Dq3¾æ‰ƒàm(T[8ÕŠZ*Ôž-2ÆÄŽê^¯Ÿ6 Ã(Š”R–6Øó¼xºî0 Ã0´—‚« ‚ÀÞဈµ-Š¢ÈfD”Â0l|]œ>}ªáÛ]»v}øá‡½½½JÙÊÄ€”rrr²P(DQduFX)å—_~ÙÓÓãû¾Õ)Í=Ï›œœìíí•RÚ+$„ˆ›Ö‘#Gfï·« kÛ\.Ûh7nëqCoÃŒ¾QU*•6LIß¶B‰Db¾;^ b¶WBaŒi[¡9;§ Õ½XÔnÃqT;ËàB‹+T_T8+tžÿØ¡ìµî—Ù=%tEXtdate:create2017-06-06T01:31:10+01:00M°9%tEXtdate:modify2017-06-06T01:31:10+01:00…IEND®B`‚puzzles-20170606.272beef/icons/cube-ibase4.png0000644000175000017500000000102413115373725017574 0ustar simonsimon‰PNG  IHDRððÌ{ô¡gAMA† 1è–_PLTEÿÿÿÿÀÀÀ€€€€$]+bKGDˆHtIMEá æ—+IDATxÚíÚÍmÂPFQ#7`(ÀTPýÃw3QƉÎ]> GŸä-†A’$IÒª}÷ÁûÓû¢óè‡~zƒÁ`0 ƒÁ`0 ƒÁàMÂm﫣ʃÁ`0 ƒÁ`0üà]ôD~®†ƒïï¦.ørn‚Ç© –É ð2¹^&wÀ¯Éðkr üœÜ?'÷ÀÉ=ðcrƒÁ`0 ƒÁ`0 ƒÁ`ð&á¶÷Õ’$IÒßîÃt6¸»¼%tEXtdate:create2017-06-06T01:31:17+01:00Ëꎷ%tEXtdate:modify2017-06-06T01:31:17+01:00º·6 IEND®B`‚puzzles-20170606.272beef/icons/cube-ibase.png0000644000175000017500000000240413115373725017513 0ustar simonsimon‰PNG  IHDRðð±7~ÅbKGDÿÿÿ ½§“¹IDATxœíÜ¿jWÆá³á¨Ý2Åôå¶X\¥2iS©—ÐUÜÒJXª£&mº8.BW°½Ti`S(A&…‰Ñ™?¼ó<¨ß| ¿¦Îj·ÛHñÝÔ @K‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰R[ zóæ‡ÇÇÏ­¦µpTÊÓÔ;¼¨µö}?õ/æ¶Ïz½~xxxýœfA?>~.åÐjZ «YíÓ÷«YéÓuÝÜöi2Ç+QMAEÐD4QMAEÐD4QMAEÐD4QMAEÐD4QMAEÐD4QMAEÐD4QMAEÐD4QMAEÐD4QMAEÐD4QMAEÐD4QMAEÐD4QM”ÚlP­}¿j5­…ZÊŒö©µv]7õ/f¸O›9M¦”Rú¾ßív­¦½^×u¥¦ÞâE߯ævæ¶O“9^9ˆ"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(Í·frÇÇÇûýþÿÿÿО×Zïîî¶Ûí WùïEǼƒÚï÷s;Ãüüüüúúz̦½r0 ÛÛÛ‹‹‹ûûûÑ®(h´Ùlnnn.//GkZÐ kä¦ÍàÆlZÐŒa´¦ÍHÆiZÐŒg„¦ͨ†nZÐŒmЦ͆kZÐLc ¦Íd†hÚÇILé¹éÓÓÓV›]kúsÄoTKYM½Ã—ævæb³Ù\]]œœ4™Ö,è¾ïçöíb)‡©·øÒjø}fõþÛíöéé©É(ïÐD4QMAEÐD4QMAEÐD4QMAEÐD4QMAEÐD4QMAEÐD4QMAEÐD4QMAEÐD4QM'ø'9šÙ™êõãÇgggc^Ò:ɧR¾/åÏRóøûëýû_®®®Æ¼‚Nò¶”ßK9)åÓÔ›<{{8üñáïc6-è0KoZÐyÝ´ #-·iA§ZhÓ‚¶Ä¦mqM :Þ²šô,¨iA/ÄRšôr,¢i'-ÊsÓ?—ò[)?N½Lù·éŸNô„^š™>§[kö„®µÎêÛÅZk߯¦ÞâÅÜö)å])OSïðá”rÔdT³ û¾ßív­¦½^×uöùŠîÓdŽW¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(µÕ õzÝu]«i¯WkµÏWÌmŸõzÝdÎj·Û5sà•ƒ(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&ÊßbkSÔqníåIEND®B`‚puzzles-20170606.272beef/icons/cube-base.png0000644000175000017500000000240413115373716017342 0ustar simonsimon‰PNG  IHDRðð±7~ÅbKGDÿÿÿ ½§“¹IDATxœíÜ¿jWÆá³á¨Ý2Åôå¶X\¥2iS©—ÐUÜÒJXª£&mº8.BW°½Ti`S(A&…‰Ñ™?¼ó<¨ß| ¿¦Îj·ÛHñÝÔ @K‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰R[ zóæ‡ÇÇÏ­¦µpTÊÓÔ;¼¨µö}?õ/æ¶Ïz½~xxxýœfA?>~.åÐjZ «YíÓ÷«YéÓuÝÜöi2Ç+QMAEÐD4QMAEÐD4QMAEÐD4QMAEÐD4QMAEÐD4QMAEÐD4QMAEÐD4QMAEÐD4QMAEÐD4QMAEÐD4QMAEÐD4QM”ÚlP­}¿j5­…ZÊŒö©µv]7õ/f¸O›9M¦”Rú¾ßív­¦½^×u¥¦ÞâE߯ævæ¶O“9^9ˆ"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(Í·frÇÇÇûýþÿÿÿО×Zïîî¶Ûí WùïEǼƒÚï÷s;Ãüüüüúúz̦½r0 ÛÛÛ‹‹‹ûûûÑ®(h´Ùlnnn.//GkZÐ kä¦ÍàÆlZÐŒa´¦ÍHÆiZÐŒg„¦ͨ†nZÐŒmЦ͆kZÐLc ¦Íd†hÚÇILé¹éÓÓÓV›]kúsÄoTKYM½Ã—ævæb³Ù\]]œœ4™Ö,è¾ïçöíb)‡©·øÒjø}fõþÛíöéé©É(ïÐD4QMAEÐD4QMAEÐD4QMAEÐD4QMAEÐD4QMAEÐD4QMAEÐD4QMAEÐD4QM'ø'9šÙ™êõãÇgggc^Ò:ɧR¾/åÏRóøûëýû_®®®Æ¼‚Nò¶”ßK9)åÓÔ›<{{8üñáïc6-è0KoZÐyÝ´ #-·iA§ZhÓ‚¶Ä¦mqM :Þ²šô,¨iA/ÄRšôr,¢i'-ÊsÓ?—ò[)?N½Lù·éŸNô„^š™>§[kö„®µÎêÛÅZk߯¦ÞâÅÜö)å])OSïðá”rÔdT³ û¾ßív­¦½^×uöùŠîÓdŽW¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(µÕ õzÝu]«i¯WkµÏWÌmŸõzÝdÎj·Û5sà•ƒ(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&Š ‰"h¢š(‚&ÊßbkSÔqníåIEND®B`‚puzzles-20170606.272beef/icons/cube-48d8.png0000644000175000017500000000310113115373725017112 0ustar simonsimon‰PNG  IHDR00`Ü µgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<#PLTEæææãããäääããäëëììììëëëììëÐÐÎÏÏËÏÏÌÈÈÍËË˽àÚ ÙàÁ¾ܬ¬®ÅÅÅÅÅȰ°¯­­­ÿáßõõóóóõÒÒÐüÜÉÉÅÁÁÇñññçÄ謬°±±±ÏÏϨ¨­ÇÇÍÂÂÈ¿ÚèèèØØØ½½¾ªªªÃÃÃèèÙ××פ¤­œœœððð···ÓÓÓ“““À»ÜÜÓææê°°ÉÒÊʾÕØØÎÜÜÑññëòòìúúóÒÒÔή®Ë««Á¬¬Ã¡ÕÕÍô«QQ«ööàÎôXX»ãÒ£×@@z³³±§§±ÿÿÿ¨7oBbKGD`Å·|tIMEá æ—IDATHÇVébÛ6 –,4A.IS›JmYò¡´‰µZÜk[—Õ]º%ëÎì¾ßÿ-”ì¥ûUØ–aØŸq|¡$y7I» _{=~v–Ì_ƒ%ˆ ¥TBH)”’J±Î&)}«¤Õú5 ²è> ¢ÑhÐÒK[¾Ò3þúïíí³Ü9¼»´ÁáÐ:’Ü™á‘לÓ÷Pø•ÞE­6À …DRb5áx¥( Š$FÓét4šŽŠiþÃ,§ã4ÁYHXKÁHUÿ<V†âHge,ÓÁPHÓÛ€YÞ0ä…·‰ÀìmÖ´g ¸Â.¤¢PÊ&ïþw ˆ!I<ù”CÒA/r•1Ç)åÓW‹X¥;Ic Ĺ„«’û ¶ <<.Æczß¿ÿ (H+ŽONÑz©Ž–«¨ 1äxöþâá"¸0§Æ³¢˜³1œ¥1½Dçl>wx³«KåYTƒ.8,½IÓ­fµê…²:‘eI–¥`Ÿ23í8é$M…³¾K{ÌtèWa\,œ²ƒ–‘¦ìý—B‰Nú.ÌÐV)ÿ–r/ñ·= U²vÇÃ(gU¨çà3ü€<„ÖC"M’gÎ×ùã¡{B²~Z/4Änqà'7 Io™Nåzý¬ªªÕ Ÿ=ÿæ6xH¬§ʪÙaš§ÇÅLùG¹ýx[C&ÉM¸|tLÄž¸Užçøøø–Jäú<ù¤ë¥aŸ~ŸÛ9./ ŸœÖŒ?}¹‰­úª*ŸDF„6ðRn™.B~ö"—/j‡ÀŒô”iyðIOCY Ÿ>¢‡ËUML{ UGœ´Í-¯?!‰uU·L @ÇCK\ôðÅ&ÍHR¸ÝK™ÔÛ^*<îõÓÉÕÕõõõÕ—ó7õn/µ€Û!}õüëo¾eyõÝ÷å†@($H)‰ØÞ!éY˜î›Š›^ŽüÉ€ Çâ[eMþ%Zn~½ì’Òæ4ޏ¼;nšf0h~»¸ØkôØûýº²éΟõw™Ö<æËeEoZÛ~ÐHÞœþµê“6¶ö»ÊN¨ i§Ô}¬i¯ÐB¡c¦&…fz¢M ]à‚Ly”œeJ0h2·@ï\C

ík„Údj›O¢ ê*´ û¥_μKþVˆR‡R‰gš×ªuxtÏðª¥;’mîܹüÚ=Cïxmk£­ßÞ~Ÿ{Íïv¯D[7{Â7|‡À!Ð=ƒ¿O$à¯R´¶MÒI8=½´·%Y°f[ۻɿŽD~ÛŒü—9%tEXtdate:create2017-06-06T01:31:17+01:00Ëꎷ%tEXtdate:modify2017-06-06T01:31:17+01:00º·6 IEND®B`‚puzzles-20170606.272beef/icons/cube-48d4.png0000644000175000017500000000103513115373726017113 0ustar simonsimon‰PNG  IHDR00¥,ä´gAMA† 1è–_PLTEÿÿÿÀÀÀ€ÿ€€€¹”|ÙbKGDˆHtIMEá…·-7IDAT8Ë}T‹uÃ0„4 $ô… p+ï?SAŸl«$AOÆw‡€ˆ€Pý êW7¶¿qá·°È;UCs¼šSô— ÀH=Àæ$ n'ªžhüCåÄʼn*>§{ŸixÄRÊVX+"òcÅx%[VŘ•cVÍ@ rˆ(Ž.0CÄ“× \”½­Ï]ã~I…µ¯éeý?fe¯# Äsœ£· “ýÒo."™ÈÆ£VÐç˜HK.,™{Êñä.åÔÏѲâ½^#«S³ê¸zªQ–PD£Ê0_¨U*œ\̵‰¯˜˜.×(6Š,‡Z} jV³²-Û¶ ¯6ÆgüÔÁðÏð\£F3¶•È…Õ 1úá÷®€G’ ª¨3v¥¤aÝXšõ"óT/¥d·Ò„SŠ:Ý%tEXtdate:create2017-06-06T01:31:18+01:00=¢þ^%tEXtdate:modify2017-06-06T01:31:18+01:00LÿFâIEND®B`‚puzzles-20170606.272beef/icons/cube-48d24.png0000644000175000017500000000334613115373725017203 0ustar simonsimon‰PNG  IHDR00Ø`nÐgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿÿÿ ½§“tIMEá æ—êIDATXÃíYËnG=·jº«zlÇEFÏØž,‘Ø!±bË"b ‰ŸÀ¿°GD¤HðY!¡lX!”d‘ø13ðÂøHvev€ž‡¯‚@T„Ñ9§” RJaôèh4êv» „œ£›7_®®Î×õT©p8Ü»re1I¢”¹¢R f–8Wº6MS¯7iš&IRÙ_Óì!f>y²{æÌ†1¢’´Öí¶$šV•HÖÖ¾9}ºªÔ¹K)ûý~£R{ñlž2câñØc+Ïá& Ìùqš‚ÚÅqƒRû;Yk¥”JMD‡)µäåËÚ3Ç4u³R8\©ëý+Aý!™s~Fò£¢è¼º}DBRJ¥”ÖZ)Õjµ´ÖE‘1¦Në£bf)åÛ·oG£Q»ÝöË~<çë—ˆ¦ÓéúúúÜÜ\1÷@=§nÔSç|ãaJíûøÀì”RÃሠ~œv»íûDQôøñãÍÍÍK—.A0s•ejË•UæÝ~hP ­Uh13G‘n·õ‘#KÇo6µ¿¿àÑ£GJ©¥¥¥jNí ­V«²8½0CæE ª)µ×ñáÖÖk~Ù3sªÁàéüüBÇÓé´âr!Äx<>qâD·Û½wïÞùóçó;~˜rŽ._> ,Æû(Mõ±c/>n6!D’$RJÿ¦kðPÇMzz ¶‡*5 :@é "úGegeUò¡µ%B¦Ý‡)5æÍÓ˜] Da¦ìÅbvišKÉ'$D$Ã…•$¢Lˆ£HÍÏ+@|"¥öÇö—_þh·ß¦é¸œÏp¨­­?/^ü^ÊàýJ]|¢ ÔYÆíŠ£çéGáT ›7§¯^ý øXla)°¹΃oß>úýJ]$äk­”RYÆ-Ê•¿(Qê9àà7¢ãÀRqrœc!èþý‹×®ýzýºb†Rooo{½ª+ýp8hµ™•¦¶¡l4SXbð3pe sa¨îÞ]yñâ§7~ÌÇ,yHfV™2)¥òÎ7ëë¯éno¿°¶VA‰9UjnkkAÊß;Õ8®¢Q4÷äɹÉÄå7,)õÊÊJ¿ß7ÆÔ•@š¦½^ßSΚYkísª’$ö9u"Ç%—W•ÚZ[÷‡’$1ÆÖ3nÖÆ|N]CÉZ+ek:™ÄZÏÈ©gåÅyc=ãö•ažvÕQßR‡5|ZðO`­ý,„š?¾ V¬|û=ÁH9Kû%tEXtdate:create2017-06-06T01:31:17+01:00Ëꎷ%tEXtdate:modify2017-06-06T01:31:17+01:00º·6 IEND®B`‚puzzles-20170606.272beef/icons/cube-32d8.png0000644000175000017500000000226213115373726017113 0ustar simonsimon‰PNG  IHDR D¤ŠÆgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<;PLTEæææîîêîîëèèèêêêååèãããÆÆÒÆÆÐÒÒÓÒÒÊÏÏÏ×îêå ÒÄÄÄ××ÙÓÓÔØØØ½½½ÅÅÃ×××ÿâííîèèêýããäÍÍÎÌÌÍãÙÙÖéääÜÜØððð é ä ÎÓÃÃÃÕÕÒººº´´ÁÙòòï¾¾ÏËËËÂÂÑäääÁÁÐÇÇÇÆÆÔáá×óóðËËÉÝÝÝ»»»ººÁ®®»²²ÁÂÂÔÜÜܬ¬¬ðÛ11ÌëëÝ44Úááèû11×ééÛÃÃÆýüüáôôëõõéôôèúúí!!Мœ½˜˜Ï——ˉ‰±éééõÑ]]̯¯ºÑãËäݼäYY™ÉÉÆÂ¿¼¼¼ÿÿÿ©(qbKGDhËlô"tIMEá…·-tIDAT8Ë]S {Ò@Ü+©KJR²¡,FŽ€Rª¶•ž¢m½ëÑÚªÅzÿÿà{»é‡º|dòöÍ̃B)ƒE)"¥œ3ìB0áBü9»n8˜“²$¥ ìHxÎææËa–ççËÀB%VJ%ÕE  «š!LqEjIý¦àL&ŒsN(ð¹&hž‘Œx•ø¢;B:#ÜÊá y„™¸6´å Õô5€{D4ë¡‘¶; weÒu  ÂÂÒòòòÒÊjEQ¸ÒS1ýiU½D)Ù¹sת]XL”™­µÌ«p„šqʇ…Ú¶ÕWw2‡Øƒ”at­PáºiÏ638BÂO]/Û&º«£Q#$¿äûNE­Ï3®Fƒªy0êyŒb*r!†…“›[´û°ïÇc°=²=ìÈRè]ÙjE+{ûkë»>Ô'¢yð(¡„šÊŽUgd–ÃÉêãI8yrH0犇† 3m Õ`(öztxŒ*ÄÄ… —Dò4}öü8Ë|ï…/­Š>ª@Bê*¼L^½>9yó¶”9£°‚ïE¨ïÞŸž~8”úœ0çÉV!³…=\|¼€HŸJH0Ui ¿Ï—íÚ´ÖþrÙžÖ®¾~›ÂºúþcUT’¾ÖIïg'ÏóÎ?°¹“irÞUq ϤY{qhA‡ ’ãªÍ¯˜57´v&­ ÂJÊ> Ôÿ3‰Fexoýâ{Gð9:ÉÁjìAÇ8X0Cu À£ÒÊ”ÛUÙ4#9Øqð ÀÈß –uçw×l×yrncÅûìKÿº‡÷ÿ SÔ‰‡%tEXtdate:create2017-06-06T01:31:18+01:00=¢þ^%tEXtdate:modify2017-06-06T01:31:18+01:00LÿFâIEND®B`‚puzzles-20170606.272beef/icons/cube-32d4.png0000644000175000017500000000073313115373726017110 0ustar simonsimon‰PNG  IHDR TgÇgAMA† 1è–_PLTEÿÿÿÀÀÀÿ€€€€èlÑbKGDˆHtIMEá…·-õIDAT(Ï5Q‹qÅ0ƒ» ²A/P¿^9ï?S%pœ¿’Í=<‚÷^°k5x‚?ÜvZÜÜwÉ @ð³*C† ÝØ Õ² (RR©°¼~rϱžy|4 û£|P Y-$1)±9 ª‚î^€¡Š§´ eÌCÖBnqQ—!˜æ¡V Wrœ_Z à­Âñn‰¨Â¼Ç»Q$ÞÞ¦ÔXt·\’ÃÞ–9>ãX?ëkŠ~î¹wæÞ×þSÎŒ â®T; Ä]è<K¢†…ük+ÍËA5E©£À¶®µ¢í'Þgy’I)Ž©QJÇÎʼ!‚ª’ï=}züt€@½wïÞ={æ‰f^bz||Ûa4HS=û}OäV»iAdˆJÀL¤¥Üªªˆþ‚˜c¸êåËÌû¿Ÿ?ÿ‹™–XkÓ4Õ8›W¯Nƒdu¾Ÿãò<ŠÄŒIŽŽd’|ʲ¦ÙkÓsš¶0Íó¼1ˆS[)Ýïœsñ;0ÆœžÎ±½ÞÀûFÔ³ÙY’¤½^ÞˆÖê7Nc27`Ú´C€œóMBPì6Þ»5Ñ{·&–¥×ÚnÆ´u¼l±k}ãÐ_ÝM7±{Õ;W¾ƒ5Lcºãà¾â|ÿÅÐPÅ|>˜6S[JyqqÑÇã±ÖzMFÖÚóóóFTJœœÜºu‹™©(ŠÂl6Ãï[Ì,¥ÜÞÞ^F „Ȳì7Dªªüo¥ª–aN@#%tEXtdate:create2017-06-06T01:31:18+01:00=¢þ^%tEXtdate:modify2017-06-06T01:31:18+01:00LÿFâIEND®B`‚puzzles-20170606.272beef/icons/cube-16d8.png0000644000175000017500000000175113115373726017117 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<ÝPLTEããäÎÎÜÌÌÜÍÍÜÍÍÛÎÎÛÚÚÚÛÛÛåååé ö ò â óæÎÎÕààÞÛÛÜÍÍÍÝÝÝÞÞÞÓÓÓÿþìÿñÙÙßííêççç×××èèèëëëÜÜÜ óþðÖÖÝééçäääÕÕÕÓÓÚrr×nnãyyß11ÖíïàÇÇÍÙÙ×ÓÓÔÅÅÅÖÖÖÌÌÌÜÜÛëëÛõõçÿÿákkáÕÕÝééèææçØØØéééìììÛÛßããëõõæddãÜÜßññëÊÊËÙÙÙÒÒÒÙÙÝêêÙ``×ôõæ¾¾ÕÈÈÎááàààáÃÃÃÔÔÔììÚ``Øö÷é ê‹‹ÜôôéããêÚÚßÒÒÓççëøøæggãÿóõ••Üÿÿâõõãíí×ÞÞÖÝÝßããèõõâddáÿóô##Û@@à;;è77ࣣÍååÞÖÖ×ÜÜÔ——ËnnàxxâppÕppÖwwãllÝ^^Ñhhäccæ„„ÈààÙääåÝÝÕ÷÷äùùçëëÙììÛùùæèèÕúúäýýæççÜÛÛÝèèçÖÖØääéÚÚÞääçÔÔ×ååéÚÚÝÝÝÜÑÑÑÿÿÿf©pbKGDžŸ²£ tIMEá…·- IDATÓc``dbfafbecggBFN.n^.>~A!aQaf^1q I1)iY9yaEf% €²˜Šªšº‡,›"ƒ¦–¶Ž®ž¾¡‘±‰†©™"ƒ¹…¥•µ˜˜”­½ƒ£¢"»“³‹+PÀÍÝ܃ÍSN„ÍËÛÇ×Ï? )(8Ä+(æãŸ(ÌÀ.’”œ"–š–.–‘™•“ËÀΞ—_ VXT,VRZV^QÉÀ&TU]S[WßÐØÔÜÒÚÖÎÀ.lÛÑÙÕÝÓÛ×Õ?aâ¤É@3¦L–4Ý)iÆÌYI³ç0°‹ ³™± ÏRBìŠ^ ŠH@˜Fy:a¼v%tEXtdate:create2017-06-06T01:31:18+01:00=¢þ^%tEXtdate:modify2017-06-06T01:31:18+01:00LÿFâIEND®B`‚puzzles-20170606.272beef/icons/cube-16d4.png0000644000175000017500000000047313115373726017113 0ustar simonsimon‰PNG  IHDRbògAMA† 1è–_ PLTEÿÿÿÀÀÀÿ€€€ûߣbKGDˆHtIMEá…·-XIDAT×ctaÈZåè$]´V³°0Ô® apxÅÊÊ ¸ÊÅ‘Á%+$ÁñÕZ‘WKV­~Êþ-•Ñ‘1!À%€…!ÔÑÕ…AÀ%Pj™”ù2Kø%tEXtdate:create2017-06-06T01:31:18+01:00=¢þ^%tEXtdate:modify2017-06-06T01:31:18+01:00LÿFâIEND®B`‚puzzles-20170606.272beef/icons/cube-16d24.png0000644000175000017500000000234213115373726017172 0ustar simonsimon‰PNG  IHDR(-SgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<ÄPLTEããäÎÎÜÌÌÜÍÍÜÍÍÛÍÍÜÌÌÜÎÎÛÚÚÚÛÛÛÛÛÛÚÚÚÛÛÛÚÚÚÛÛÛåååé ö ò â ó öæÎÎÕààÞÛÛÜÍÍÍÝÝÝÞÞÞÓÓÓÝÝÝÍÍÜ óÿþìÿñÙÙßííêççç×××èèèëëëÝÝÝÜÜÜÍÍÜ óþìþðÖÖÝééçäääÕÕÕåååçççÚÚÚÜÜÜÓÓÚrr×nnãyyß11ÖíïàÇÇÍÙÙ×ÓÓÔÅÅÅÕÕÕÖÖÖÌÌÌÜÜÜÜÜÛëëÛõõçÿÿákkáñÕÕÝééèææçØØØéééìììÜÜÜÛÛÛÛÛßããëõõæddãñÜÜßññëÜÜÛÊÊËÚÚÚÙÙÙ×××ÞÞÞÚÚÚÒÒÒÙÙÝêêÙ``×ôõæ¾¾ÕÌÌÜÈÈÎááàààáÒÒÒÃÃÃÞÞÞÚÚÚÔÔÔÛÛßììÚ``Øö÷é êõ‹‹ÜôôéããêÚÚßÒÒÓÝÝÝÛÛÛÞÞÞççëøøæggãÿóõ••Üÿÿâõõãíí×ÞÞÖÝÝßÛÛÛÛÛÛããèõõâddáÿóô##Û@@à;;è77ࣣÍååÞÚÚÚÍÍÍÖÖ×ÜÜÔ——ËnnàxxâppÕppÖwwãllÝ^^Ñhhäccæ„„ÈààÙÛÛÛééèääåÝÝÕ÷÷äùùçëëÙììÛùùæ÷÷äèèÕúúäýýæççÜÛÛÝÛÛÛÞÞÞëëëèèçÖÖØääéççëÚÚÞÛÛßççëääçÔÔ×ååéççëÚÚÝÝÝÜÝÝÝÌÌÌÛÛÛÝÝÝÑÑÑÓÓÓÝÝÝÚÚÚÍÍÍÛÛÛÜÜÜÒÒÒÝÝÝÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÝÝÝåååÿÿÿ§¿òãbKGDë¿Ý&¸tIMEá…·-IDATÓïþ  !"#$!%&'()*+,-./!012!3456789:;<=>?@ABCDEFGHIJKLMNOP!!QRSTUVWXKYZ[\]!!^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹!ŒŽ!‘’“”•–—˜™!š›œ!žŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒ:ÓÔÕÖרÙÚÛÜÝÞß;àáâãäâåæçèéê}né˜ù€%tEXtdate:create2017-06-06T01:31:18+01:00=¢þ^%tEXtdate:modify2017-06-06T01:31:18+01:00LÿFâIEND®B`‚puzzles-20170606.272beef/icons/bridges-web.png0000644000175000017500000002126013115373716017707 0ustar simonsimon‰PNG  IHDR––j.>gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá –h/{!¸IDATxÚí|xU÷÷I¯zèH•Ž4)Ò•&¢ Eª Xè½(R¥I“:„IvæNÙ¾»l@@HH¹ß ”Ýdãû~ÿÿû=ß{x–‡Ý;÷7çž{Îïœ{f€ýøßPLXˆ¦häú+†¦(š)ö0Ï/âbD»Ã®°."dÖÝ‚«a&“Ï"@!$Ø•w÷C—°F±[1ÉVãòON êÍ ¬½¤ˆ¨à0áð²ùK~áT®p!I>¿zÁ¢-‰š…öÃ[lä Þ•¿BÖ¼ÐÊ•¡¥¼Èw!ÝŽ©yo™…µ üÈW>Õ¿a¬…àbXeß›ä‡^¥ÇÅÉ.q¹€ÅðÌ{ÔçɃÊB‹Ëy”‚Ô­å¡úgë7Ìn Aß(¹q1fª/v[ºqõ{%áõë"ù–§øzwÚxòèìêPý B{‹µ¼ ],8‹ü¹?êÆZ^NŽäþ_³Š¦ÉÂÆHøVÍ ™ïíÏJª¦J1 Ñ-†¢]K’ô94¸æ¼~Úbï’ÇDä ,Zû¤‘1gfá…Ð_~q߬9¾ºÏKq‚™ÑÎTòËuIZ›½X‘F‚…³ÈãaØ}Ew)ÊŸ‡ Ù]œ™nL€÷CS†ócŽ/_Ññ©×ªLÅ™¸ì³&QÙ’¨N‡©:E˪¼~“Q7BO²ŒSåFDÅÍXß‹X¬ ®%P8»’,Übqz^[z&NÃSa‰.R~„¹ä翎 yg¥ã30?úÛ)Ÿ¤´ޱ5ƒòäShrUäx§°újøÜFÑúr€)öD}-4{§{Ò½Gwx׸_SI€Ÿa : LѰhû`¸m,ßã*V~ÙgdË3,@oÑŽñͺ„ÆZhå X+%˜œ’ ¿Ǭ´p=r4LÓ)þz0ö«+ñ]†"ß[™À#ºó½QWX”£+üaàù£|o¢ðLÜ|½rÄF'›Ä¨²Wû1e[“ë+oŽ5#µÏàë0÷ÅX#«;ͳ€<ÃËȦáï[â’ýqF:W¬žÀê÷ X)‘}ÉG&níÛµmgHÛö-a”#Ië_i}=ß%ˆÖWA­VÍŸK«0ÿ¼pÂwò$èrG–Jbcã Êu~mø¬Ú‡;üÆ”C᪰hÛ¸@”üו2˜Ç;JµÏ¹íLl joFÖQ¡áÐø+ƒ=T›SÔ‡#`·U8Z5<Ô KüÙðBq-Æ;F„ûÂT‚¯eø-KѰ¼Æâ§x5„ÁMŒwÂw)ºÝaˆÝö{'8+"ž»Ó3<ÑÌҕ˾ðN&ëvøH§8N?s’lß° +V¹’5K½ÛÛÍ©¥ß'‹y ú)WAÁ¡FÞq8ýÉŸýõG*þ£nÀi³)ÇÊË 7F3\|,MÛ¾„ÑZÎÞT×÷¨B1,“H[c*FèD»®$„=øöW ù«7lU=€ÅÒêh :ŽlÇAð¹Ž^¸SŽo 3e‘¡^Ð×ûDƼT?­­‡ú5ž¦9³šð̾˘] §^ 'Ö•ù̘a6ô‘\°Á§Yå—ÇTêµ6ÐÓÌæ >ÖKÕ¡ïÞá®Nð Þ•;ž!å3¨´:AMÖM?7€~„ø¸“²Î»ÄŠ?É2>cûA£›fÏ`±Œ¼ jŒž1±ÀH–Ï= ‰—ßÿ7†x»Ô<7Ê2Ò×APeà¨ê€×Ç<ï*¦8…Cê¶H¨4dúç¡ÛM—\Ã5ßR/Œ®NvRé~{.{Ì+:ÎÓ|v’”7h0Œzf¸1¬ü€ù‡å[«°¢$W÷úYÅì’¹f§H°'œ=qú†& ˆÕ-·œ5ÛxTp:ûí3Q§bu©pzÊ™îà–~ŽÄݳžÓ@ãÎi^’%‹KZNS÷šùZxŠq5ÌìvXnX´7÷ÅÇ`f]ãw›b0Ä8ÝÜ2­5ö5qÅ– •Œ_óÅGa7æŠ «¡õ&¾4ÿæƒuü¿°þ ëÿ/XÇSp¹Œ*ºô¸ðãä½ àmÆmø'Ôµ3ÔYuMâ6·…:—Ý@yDÌ>ËÔþ÷ ÄÎ<ÄL:Q ºýœ ›Ï/¬ý-¬¾ÅðT XL¨b&¡~)Â…¢]8š’‡À; :g¿Ì“ 5â܆ÍùÐèœM·Û¬¢ºÚ·Ü…—7À˜oÕ…9¢Ê˜6ýFGøLuSƒ0Ê“1!±úÖèLüô ¸ê–†GC d¡¬¿]q™W>€9šëýÈWÂÃ/ȦÃK–ž²PöùÐ÷%3F꘨#“p~Þ.FˆÅë¨è†Ë3•Ëün$Òý NÇ×àñv’+¹mí û“ø©Wµò d.6´†›%¤õ¯àÍ|²l…`ÿ$ÚÚ.ää‚ »Te“Q–k]”$í'Ẕ]0ÑÈo7½Z¶ ÑHÚëàí&Åó†×h$„1(1Cò øEqm]æV!ÑóµŸÉoß)u>|­?Ÿ›V×Ã' MÛ§Öí¦ÐüíªÕÌ®òDʾ~%émräéúmjÈD˜4î×eî‚Oa¸-Ññ%4 ­sD4é+`¹Ýå*òtHCÂPÍÖäÄv(ñ N¦²¿¢’gÂv•’N–Ù^ú-•¤æ=ÜdÕ”c>œ"‰äÐq…7Iš‹g€Ù¥qe`c“’gÀ ƒ>m¬õ°ÈA¹2-žòkFÌ©;ý;R<²^„þ/aM½Vû¬þ]D%¿ —]¢í+HÈzÚ( 2Æã õš4lTP6© ï«&íXþwdC ­ÎƒÕ6×ÚBux ë*$…a9ø)ÇWð#±ËÈà20ÒJKàºËŠ Cœ™yzã†ðò—1~PË+,0È•†yÕˆçYS³Ð60W£ÄŽ>']{T†ì£Vád4ze€…Ò'Áš7€ä_` ÑÒºogûWÞÏZ®†6wá'~ËÚÔ-eá•ÛÈb8Ý¥ƒHÇS`•f²Üœ9d‹@IG¡¥È8Ù{*¹¾ F©Ü•‰ã?4‡%f]"ÎÂ8h¨|Q@ú]ý³µÉIú˜nw] DÊèü§¦d©X(W‚M»ÿïôŒô§¤ä–‡iTpÙ󪉵ߓL¢©l&[Š“Ùš&0Õ6Û8{òÝ{O|ð•¦QVD–¦Õ¥ÐÕlI4Q9I?Xá†ÙM5?„w4£ì…o¼ ‹¥^;~èèI0™¨\’$͇Úût‰çÛ…ö0L¢ÍvtæØñ‹b>š€ä½%WJ"ÇñJâPhM K.;v޳qÈÒz]·‰oÕ¶V‚uŠ»J3óý ü̘{É'‡x}!#õìðª$=ï³[áóÔ×y:ôÛ|åÚ/##` ÇH7?o@~Ô~•EÈsuZÝíWF_?6µ´ˆ1[Ø…müˆãk6+IäL]¡â„_¯]ZßÝÛo¾ê>ÙgxËÊW 'êm÷(Hú6jŸ=¥ÀP&¯Šu[c£ æU[y{%‚}쨶~ðæu1®“] ìaŸQfë¹æØiô˜î%à•ƒÇÏ)›}‘ÖûÔB“}ú7܆t‡ÙXKR¦@õƒFÅ&=®tãòFx¤²ûÆõê9ls¢F)|ƒgܰè:w¦Ô¾–wŸÓ¢prÚ;=­¸¡²Â™ŠðA4§ëÂõ ¾¡¿HH‹_÷aÞór¡É>G)¸à8X…‘¼ š(Ïë[O†ÀgùÂ1±q›ÃaWÌ”õBɺâHÖ«ô9¼•Ïý¥;’íª…øÕfð"êv·è?xW‰3SfÅîpèë†åÀ¢uÜ2¯ÃJl¡úÆãÌ3£.ù ãû üÏäóM 2Ž¡Ùƒ`±ÎÖuÔI {ÂùùÄóÒúw0TeföxÁLÙfÀι[$¬çÚÒvÁ8œžÕ¥s/èAäøÂ5{aÌ1!õxZR¯§WÅ+œÝ$×¾•1¿æsÙÂ_jSÁç€Ds¦ò‘I\y@AXÉ# šø|¢©Ž%ï¾Zº©àr$­¯ Í]gŽŸ ýlâ"Š:“NCwò ¥N­<vªEäMaÝíjÔåI¬NðFàá¥x—Õ*yl%Šä¤›Õj'ò”cœw©.¤€‰$$"í8""Ú¶ÖÚ‹« ünðçk¡=Rφ%ÝÁú ¶k4’/׊¼(*ð>œs kR²ëS8*!Ú¾ÖVò`ˆ'&ʧÇHh¼YÇâzmË`žB Q‘•£â8ÆÒÁÇÅ)‰KŽ‚0’>…Cc”~·jņ¥ÿHœW:n%}ÃŒOÂ×Îù¶MÚ@‚õŠ9Ú«­ÙeŠÉpt½’7Í|Lð¾6š«qÃ\l“·ÞªX^ÇéI—Ο½ôgv…ƒùƒÖó^†P¥m*sjûÖÍ›¯²êh˜çš|½N‚™:mÚ¶eç†Ã¬¶Þ+ ,D.*«,€wS³Ïy²ð7ðžœBf=9Ù& J:Õ/¨VEVTA_ )w…Ks\e¿í6NQdMÒŽ–9›7¿$ ¿ìHv(ÜK7V–™úCGÖy–üÇXh¯œO[•˜µs¾ZvN–LÊ,¨²Ù"©ªÕ4Í+ì°ä.™EòvßÀoQUEnuiXž×= VåöΛýÝNæeŸ‚+X<û¼»%jÏØhs5¾00Ø8ûòï@Wþ*šÌZ·vLE¨¶OqoÆHÝ\ªOüþ‡éu!li^£@~Q5ãŠ^ç¾hop 1¼ðk;gðåG6¯¾‘º!êÎØºm^+/¿/e¤éb$jåÜ54äÜreh„1wØ»§óî $Äw†ˆÑG.ŸXZ_>+XK=É*Qãl?0å+ô y«wèB^VUIÜ^ ¾"©¬zé‡ÅK·ºmÿxKÐnmZ²øÇëª5ï‰ G·ƒÁwœ&ó×ÇÐ8>Ûd\Á"|âa–3<hœ÷ÄvýwèfÑbY5ºš÷a‰B‚î°«<]T1žA¼«ÖZ›°““´~|”½Ân`=ÂþMñ—ùaѶ)$p›´)Wm22øº‘‹wA Ê ÌE²^l‚ñîºe¿"Î2ãMˆrn÷° j‹(¼a‰XNý¾ûª¶°H¥„fÁ—O¹¤.„H¶õËx¿FÇÆ~˜®’ÎÀ;ÆÍXS¶­þá½èjaBë]A4"ï½’#Œâ̽°æ2S\XÊ1’쓘k«Qẅ²­ƒÅ.“ýbÀ²½æŸjôhÁÆȪR±aÉÇa”ƒFÒÅWjßБA¸–EŠÔV+¿ÇNm•ch W¨Q|XÖ‹þoòH8Y1`Ѧ£ZCbâ¿K{â_¹s8¨gâßó¾åâÚIs;Ài‹ºƒC}ªbùDþ_4ye LÇOñ\ˆñ²`¼–;ø;X™NaÂy#¶ úH¬évüíÛI´> Æ9s"EŸ!æ“çÃ9ñ• §§=&’†å²e³›\Ã2=ÄþÍÚÊgÑæŽ0Y”Í ÃKÚj¨k¦Õf·ë2_¬ÅdèçÃ8£,Õ\u:y²;Á‚ì­í2ø î©:°6ÁyC®Õ†îÇ»Ã=Ò+l?ÉCcV¼ûf‡a;iµèS™——á´kËú´ë8b7R)BV«íM! ¯=/ýº€Å )vtø¯7ôˆÊGBĘNàÓ|ÐàöAPÿ¨ÄqÓó³öú›T× hrÉìa Éž‘¾ ªC?þ øO³²naQÒ™ÚðÆf%%ùÐ(ñ£Šr×F`]×=À¯í<$r‰ ÚÔ¨›7v| Ódq!K|;¨9#êfÌö÷½f)´znœQ_©32JÍaÝañ|lX”݈Eîуgm¢$áòéSѬB'ñ½ oœMt]?Xz¶Ž Ëu÷â횦HúÞš„š;ÞMfv¼,ú„ÅIÃaNOÇ¿3¿eâÓÐòÑÓ'yäñßéYYO=›ám‹…â’Ž_$w^"Ú£‰ÔyÐÇjI¸Í1êÉЈ«šÂ§`+F/í¥ ,9Z‘XŽŸ¶„ùÄ£L†CøÉ³<’–J$-íYZCÿ‹V©¡³”¤/ƒq¹|Ž©Zâ*/.ôóñzŸ¦ôùð¹bH‚µ%÷ÙbAX¶oàG£Ñq^y˜‡Sqœ¿¯»Ãƒè/#ZÛPΧ£D›o–«›äsEòN¬R–CGM­áˆ•)Õ˜¤Nm ëNÓÓqB]ðAêCûv®¤m§Z°Z¥Ì‰5æVn#!¤ö†‹bÑÖE9fÁO ùùéÕµº2,-w†k‚°î¾{ï´ôOXˆÓ3qƒ2.«Îøþvh&mX—;%;Þ!ÉþpVòVòا"Ú6Ê zS\öq'Úê Ƭ_û^UN{ÕïóI®dâÌÎ$™f«Vë<ÓBi}!Ú#m}Û©å…z’Ö ®z¢-ûtØqògv‡jÑÓ%ÜözÃ0™>ëÑ- à3—P½j|Q9 À÷x“²Ç»bœ3ËÄLØ ºe§NEvÎ0$ñÎ#BƳGŽrIRÚ}è‡%Ï67:»ùíë¯e¥ãÛ~5x·\þÿ¾pTúK%Ê‚18+µe¥HøŠ$ý_Áz÷™Ïÿ¬þXMÒ‡ee¥Å¤=®U%ãèã>Oü„ekã÷Ðy8¡‡ö%ŸåkIÿÛ‹è„Õ<ÀYƒª6p†Yå?VG/; cI‘è„7’ÿ`i³aÎLm u^}ã/ŒOÀx¥€meÅü˰\µäþŠÉ Ë$73pê¦Esg,~„q?8–†»ÚZù¢-Šª®€14+©ªÄe»ÂX4#!$8ã9%ùzŠyJº&î ‰;uyÎsùP‰úÃû]Vå‘q:êàÈæ\°XKl]˜óÄY‚x¶Ì«ÒEkî’.²²‹ÂÆúº;­Â?TÃ*Gû—#œµd·Ÿå|9-Òs›Tý)ñFÿ,IçëA£´Â®kՎʹc"R·U‚*ÏÿnPIxí¼ôJi kæO2öÉ7ø0oŸ-Ÿl!=&~Ö/ªí1Ž;^À"ˆãÇbî~CcrΜ°hu£O‰ÕˆÛȰ•Î[ÿ‰¾<^Ùd’u•9кñ¹Ÿ,£Êˆ«f]ã>Ü¡Ð/µeÐ%ö`_è²7Fzð=6Ö‹¥Â®äœ‰ý­yŽåŠ+H_ÍbTÕaWÍê “_Ö 7 U«n×8³þ“_Å “ –ñL‚“ tž2¤~@þßêÛµÝÀYx,‘sWC<&¾fÐ)­íÑ~b g¹U#èÜ fOë_ÃH•¹=ù­ÞçÌ&Ûl«!:,â:plÆl.ϘcÃf¦ãÃ0üãñ$\ÊðÖ_wîÜ-ž$§ìƒQ:¢Zwî 8J_ô²Ë’aùf~W-üåöUœ tdÅžÊËUæCk`I’º3)FèéïpÓáé^2ðDØ+2(V³7‰ˆ5›/·ŸÏ‚¤SÐÓh8П7Œ!ÙxR‘°(ÇBˆ"\çxd-¨¥‘LW]6á& ›†8ÞÕwÀ 1B¥Š9íÆÉþgFÃ: Ë`=Ñ#X'p:NŒwÃ÷ø ž %K„W¼‚,FÛèÛÛÌ3ŒµR…<°ŒÃ}"“Ÿ7 ‹&™íjë\\Æ<’¸¦áþ {Óñ8b¥…eÐõúUŠ5_ kj}±ˆ' Ÿ„XÚ<öñ„ý Û±:D¬‘is#ç°€÷/“¹ƒÅ2RÌØðò‚²óM•ƒ²QY'@@ß½7®­y Â7)¬¼µu0™. á ‹÷H¹1¦¢¤Ìàh•FCЀ×.¯l e·«´{X¬ÉŽ{Á‘e„ ”§4ÉŸ@‹„l_²=Ìg§h¢¾_¾æ 'Ñ&:Ͼ “XùÖÖ•+6]—ùëxÎöSpÀ>â|Ý—ÝÔlÒ¼sž* É; åïÙÄ#GûÖ”ïÙ>þûñ}‡=¹€8ìwþýwÊ=»þh/´»Ÿ=,“À©gâ˜Â«™ÅJ1±5ÜÂxOý2 w'¼˜Dˆt\o;/ ã#UKÖÚ@†Í…ïìž)=……¬'¡7ñ ¾<\Ë/ѦùkHKD†Ywº^‡±æ×ÎÌüaÑöÅ$ÅË0Vb*ÑZ:¾žˆì3†¥§¼ÕôùGw¯*ÍžÂ2z/’ËfàËðñPÂP=¥ÆâŒ'?>˜i<.c¼áàß Ëñ5œ5Þ7qÜ|–ñÇXØvæèñ¢äð¥ÑpÅÐÖÓG£á2NÅzv\àñ"jëa>±Ù=Ððè~QW;‰=’#?ëvÆv…’ç7-oþ7Â"‘®D½géx’d°× Œã¡Ã‘»‹”]{¶ù6#}F©ZO ÒèÂL¾»QƒX鹃@êXƒÓÓÓÒÒÓÓ³2zÀ97/=É+™ÄÂϲ²2 w—Ö v)4Oƒ)x\ð²œõØo ×"}5³Ì,œ>úiˆ‘5›Í¦),ãžs0âÕ2's»LûÞ—i$mmÃ2Ê\À ?½ZÀdìy× ­ì õž®’»~rómh~›1[Oi×´ÍØ¼H1n…R¶úÍÒa1 ‰¬QK[AãGͲ0_” _ÿ¨û½äái„ëp}î2|hS€¾ ¼x¥7øø´=VX=ŸVûöð!Þ3qRtw’è— èpRÍì3–ÄNPoÿ4%ö‹Òð±ÈzÊ‘„¶÷ˆ¸CæÄÕ Ûþ{O?1Bóõ)ä&SóÚôeíVXièuðΣߢBÉ-Ïq9Ÿóa-½aÔ_ÙO®ðoÀ,“j:‰VÙ«Ñoˆb"w©Š÷úÌì‚Á‘ˆ Ö$Úý0¤2dX¬dMäÏWðÛü¼Î°?¬ÄQéE! ©+ %ña‚˜ïÔð5áÔgJÚ“4rÍ̧OSñG°ÎèSpܾkƒ×Ÿ>K+t~>l lÁ¡$6û7²K*NmYꈆ¿o;³ë øÁcåQJJÊ£G)Ið&›þAXF|÷'$iyXô°‡™7¡ñãÀ;h-™;§Ãßx†Lú†àŒ U-Ðx>ñQCÝu^ñ%;=ϨLœx*¾æëååÑ0Ø3²bSl Ÿb|ñy‡§ó‰»eð Ñà“ú^}øáqоçÛÝŠ'o÷ŽðÓÉE.×ÚG´•ŽÓjz÷ôhXXÈ]è/. _KTò¤L½œxÎó‰3záÊ {>±ð¬º<"fÛj£ÝHѳpÍ*nÎ’óUT:ø:ÛyºÂ£,óò¸€¶/% (óYƒÊ]‚¾%L€AU<9¡²¯ãï×_óªtg¦× üØ£a‚w®dµó½‡qjÙº9ÚBò>M.´fÔÈÐÀMÿÝÜí³¯…‰ìÅØ>ýãw¡~Æqà™mÙø~·ñ£½Û<Ë"{ð˺<_3ÔfÆ£g“Ýp†>|þB&ÏEûý’±¥È2ÜétœXÄtØ~߃‹hœÄp¾îØþ ;™ûSØš³‰ßšÉ1žO|Šï7€øb›–aÈVL3úÒSñhúÄÛ"?éE¶¢35!Lõ4Ë~´Óé·8®L{jœ›ebGw˜$›èb‹Ér¦tÐ^£ìŸ‘…/WöÞ!%y4Lˆ*YâñÆ$BCΕ÷ß+¿<.@Blsh½çÆÂª*ð¾…ý'‚Ôá0äÂcœ;ÉÏo‰æ)ÉU·”€á—žàÔë|Vi/c¢‘\% ÷ƒÈ ñçùùÄ©¶à^©Œ¼ºÛóÆJZ=Þ¼"*•ö†Æ/žVÌ9\áÕS_´¨Z½ã’ëÅéÈ7hÙ3¢~•Ú7ÓWWŒa¿ë£zU꼿•‘óò-£d/©²$ÉÅìÈ+ˆQr¥¨7eæÆöò]#o%ôè9BføGaèüÃþ_{;ìa¹ÿÃGP5yFã%tEXtdate:create2017-06-06T01:31:10+01:00M°9%tEXtdate:modify2017-06-06T01:31:10+01:00…IEND®B`‚puzzles-20170606.272beef/icons/bridges-ibase4.png0000644000175000017500000000157113115373725020304 0ustar simonsimon‰PNG  IHDRkkUÔ#ÐgAMA† 1è–_bKGDÿ‡Ì¿ oFFs¿=GtIMEá æ— vpAg–íÔïƒIDAThÞíÙ[’¬ Ð,=KËμ¶8’„ðªn•|9L7G0@f ð"+‰ŽãȈoMYgÁ«1”>þ T¨Äf­³µ³©« ™ÊÒ£EXXP cw³ *aþÖ¯©ùë9âÉQô³R·ðN«c~VjÏPd`©§EÏ(ŠŽEYi©ðû»¶D/c-9 ¡ÏKR¡±ñ4fåA|vš°ù•;&­¨uƒG=‹ kç:¿uÿrÙ—USµîüBJòk0\i­åQ²`Ûj~¾c‰[Ó÷iY­qh[úóòoÛ"#o°Œ;ãU5«z ÍAÈ7ìiY¯²l,ò‘Ë×¾kÊú =ó² W‹b_ÈÛîg}Öf ÙõŠEdVC¾bÓyúmA³:|gÍÿºíÜ—{ùF-¯˜³ˆ'^(S£z¾4iUó½ZýŠ5sN8oeNVÔÏ —,Ënüñ´° äﬦu¼*dPâ÷££…êœ0§»õtë‰Õ±Î^ù²ÜÃFéœó=ø[³»(‹ʘõöqñkãì.Ðz°Xë`3`ÐZŒ }8aá/æ±<¯Ž˜_ІøuuÈ;¯‡ísBG‹M_];`Ñ»‚°°½´`Û¾Ü='Ä;h\¬{š˜y”œ‰ÖTÞ8km¿\ ŸÛÆs\±,;èý².½y—¬w ÇìzrY8ÑrY°—7¦av± —7²pr(÷°UòFWkäo€ÅE[>‹_×ÞùÆXEÞcfÞ:oŒ°°’7FÌ/ECüºVÈ;®‡#ï—],‚‘u~ëþåT¶íËëï—ßc‘GÕŒC}3ŽVDÞ;™ÿò¶Z·ñYŸõYaåñ4½ØA±º%tEXtdate:create2017-06-06T01:31:17+01:00Ëꎷ%tEXtdate:modify2017-06-06T01:31:17+01:00º·6 IEND®B`‚puzzles-20170606.272beef/icons/bridges-ibase.png0000644000175000017500000000326713115373725020224 0ustar simonsimon‰PNG  IHDRkkUÔ#ÐgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿ oFFs¿=GtIMEá æ— vpAg–íÔï•IDAThÞí™MlE€_³ÛIê4QÛ#ÔªIAphÃOZÛ)mUÒ *¡V©ZŠ8".ˆ‚Ä •Zƒ„„T’6ZàZnQPâüอk¥ÚÉ ˆŸ+œbiïìz×Îij;~¾å,Ïh¼ŸfgöÍç· D4èò ¯ëèíœh¯¨é¾±¸š[]¼¬p·Oý DXŠ2ýÍ©}„´¯÷Ûi½gbW-ÀÉÅlNÍG.›9 ï.‚ ²r=Â"ŸzûáþZ¿\SÍXûB¹=YÖYÈ?YQ6.ƒç>kÔðU1JUÿ» à‰¢³üœÔPÑ·:šëÛß]¦3;R›sAMF»|/ÝžQØR ¸¦‘YW ;«]ýôÅñå{„´V6õadÖ€ºÙÿÉ|pnýa€2kÀ¢eS\¤ßÒ>dÖv€MÔ¯»`Çoôë É,È, W@‘Yz~Ô¿¯HÈ,’W ÔD3ìøÙhy5"³Z2úÕïxàÉTaŽd½ÚY~€ëô&Þ¬æ;333 ½…ׂȬpéóuL?k‚ôùòCÃ'Ȭ)l{Ä`eª7”€'JS/ɇGAî6ƒÄŠ=oŸ iõJÞVxªK¯^ø.õG¢à4½…×xÞ(ÄÒë„;iË{Ÿ>_~ž7:_¯¿ÜFðrW‹\ßþÎíÏØËŽXê)™S'Ddeê8uBñüâÕ 1Y¼:!&‹S'ÜÔ…Xåê„e¼QŒ%æ‚,!of xc¬ QÍ÷Ë¥aëýò¢Š\oÔX½(,®7j,÷ß(¾7j,¬àx#*‹ã¨,Ž7RVÂzñ½‘²dßñæÕÄõFÔõâx#*‹ã¨,Ž7âå ¾7j¬WP6¼Qc-¡°¸Þˆy~Uóýri ¼_¶•¾_v«äý²ãÛ(þ~Y ˜ÞX%Ë«Ç*[¬-Ö«zñ?ˆÜŽKP¸%tEXtdate:create2017-06-06T01:31:10+01:00M°9%tEXtdate:modify2017-06-06T01:31:10+01:00…IEND®B`‚puzzles-20170606.272beef/icons/bridges-base.png0000644000175000017500000003303413115373716020046 0ustar simonsimon‰PNG  IHDR,”ý¨bKGDÿÿÿ ½§“ IDATxœí{T×¾ø·’@Œ¼8J+TУ޶"W‹¥yUA+õÕjÏqõ«¥]]½¾«(ku­ÊñU[íÕìËDÛ(J¼(è©–ŠDEJC"7 üþØëîßœÉ0’É$„ýù+“íww¾™Göþ̨›7o óï¸Ø; ÆÁ…ÁЀ ƒ¡C. †\ ¸00pa`04àÂÀ`hØ; R©*++øá‡ÖÖV•J¥Õj=<<¼½½'Nœ˜””íåå…ãqœx¸ÂÁû5ÊŽSBZZZ²³³ëêêV«5ÝA"‘ôööFDDlÞ¼yâĉ8ûÆÃâ_ö) £Ñ¸oß¾’’’ÞÞ^‚ ˜wvuuuss[´hÑ–-[ÜÜÜp<üÇÃè_v(ŒÎÎδ´´èt:€‹‹Ë¼yó–-[7nܸѣG«Õê?þøãâÅ‹ùùù—.]êïïˆD¢àààãÇûøøØ:žðððÄÄÄÈÈHooo­V«R©jjjärùÕ«WGZ<\áhãÎ ß…ÑÙÙ¹dÉ’®®®ÞÞ^@BBÂáÇýýý=<<\]]É{¡ÕjÛÛÛß{ï½ÒÒR€@ ðööþÇ?þÁaŽ(ñÈd²mÛ¶ùúúº»»»¸üÛ‰þþ~N§P(öîÝ[SS3Bâá Gw³ðZF£qÅŠ÷îÝëííG}ã7$ ó»4M^^Þ† úúúAHHÈ·ß~Ëɱ•««ëöíÛ,XàááÁü.NWRR²wï^‚ œ;®p´qgƒë{ï½ÇÏÿسgÏ•+WŒF£@ (--MLL4›€P(œ:ujLLÌéÓ§ûúúÔjµB¡ˆŽŽæ0WW×'NÌ;×ì§àææöÜsÏEDDœ;wŽ 'އ+mÜÙÀߣ¥¥%55U¯×Ž?¾råJ6ÙAhµÚ¼¼¼µk×Äbqaaá³Ï>ËU<»wï^°`»»;û·ëõú³gÏîÞ½Ûãqww¿qãFHHˆ5ñpÅíÛ·g̘¯+aÜYÂß|ÙÙÙèü’’?þøcÓ¦Mb±xÔ¨Q£F:uêåío¾ùæüùó½½½û÷ïç*™L6اP§ÓÅÅÅMŸ>}úôéo¿ý6ùOb±899yΜ9ÑhÌÈȰ2®ÈÈÈ0€nÜ&((=bçãΞ C¥RÕÕÕáâârèÐ!Jv?~|ðàÁºº:ƒÁÀЈD"9v옋‹ Aµµµ]]]œÄ³uëÖÁ¾›<ØÖÖ6X#îîî;wîtÌxÊÊÊ”J¥Åñp…B¡(//lÜÛ¶m{ðàÁ`p8îìáé— 777£Ñ8oÞ¼€€Ê_½¼¼222^zé¥ÚÚÚ¿ÿýï íøùùEEEUVV …Âæææ·Þz˲xNž<)‰ŒFcxxøØ±ci÷¹yóæéÓ§ÝÝÝái-¾¾¾3gά¯¯‹-²,”®â1 ¾¾¾–c hÇR__kF£Ñ öv4îVæ™=<1är9ìöòåËM/(ƒ‚‚8°bÅŠÁr‡ðððX¶l@­V÷ÝwÇ“ŸŸßÓÓHJJ‹Å¦;±sçN‚ 6nÜÈÐŽX,NLLhµZ¹\nq<(?\ÅãhÐŽ;€ ˆ´´4‚ öìÙÃðv4îVæ™=<:PΟ?ŸrßzH¸ººÆÅÅÁ×·oß¶¸ææføbΜ9´ñ|ùå—¿þúëË/¿œÀÐŽ‹‹Kdd$|Íp2`ô^ãq(÷O>ù¤¡¡!99yéÒ¥ o'»5yfO§R*• ¾ðóó³²)ÔÂ;wFeek´¿=~üøÈ‘#‰dÇŽì[xðàÁôéÓ'///”v{áééÙÝÝ ÷–––]»vI¥Ò£Gšm µÀϵOG tZ<¤[u´Œ=Úêpþ?´—¹}ô‘^¯ß´i“¿¿¿ÙØüÔ`—xÔj5‡Yºl ÷uëÖiµÚ¬¬¬ÀÀ@³M¡q§wÈ9<‡£Åíx›f¹¡¡¡ªª*000,,¬©©éîÝ»hϦ¦¦§OŸRög¸d´o<Ü~ƒX†T*…/LG­ººZ.—Ëd²ÆÆÆ[·n¡=;;;)û£¬ÿneO§RÞÞÞðb·££ÃÓÓÓš¦:::à‹É“'ÿöÛo–5zç΀J¥Bƒ¬GQÎzoܸ‘ššºcÇŽåË—“·£Ó•   óçÏ[ORRRkk+·ñ<}úÔúSM®0wøy¸ÿ~xx8y{]]]XXاŸ~úî»ïRZ€/ø™1ÅÓͪ/--5oÜß߯P( ú¾„¿ÿ+ Êž}}}è¦Dhh¨Åñ ÷ÖÔÔÀYœ–AÄ¥K—àkkV ÷rCA;îì!;?+4x*Œ¤¤$xÌÏÏ7=[hmm7nܸqãÐ=»ôôt¸N‘@ètºï¿ÿ •JW¬Xaq<Ë—/‡_Ìr¹œò³@TTÔMåååp{DDÄÍ›7)_Ïz½þâÅ‹‰D’””dq<(?\Åãh˜Ž{bb≇Âí±±±”Ãw+óÌžN¥¢££wíÚ¨¬¬lkk›2eŠeí´··WWW äI“ЉéP …¿²×××wtt[ÖŽB¡hhhôööΛ7ϲF)?\Å#‰ÚÚÚì>ÿ¼³³s„ ƒ«q·2Ïìáéˆáååáêê:00žžN¹` ò¯]fíÚµýýý 22Òškr<ûöícø-Ùßß~UñÅ”?étº]»v9f@llìÑ£Gÿô§?™®ýíëëÓétmmmëׯ‡·bÜÜܼ½½ 8<{¦Ä±}ûv???±XL‚ ôz}GGÇž={êêêFH<\áhãn;XB”JeZZZKK ²EDEE-]º4>>ÞÏÏO*•öôôttt\¸páÌ™3UUU‘H4iÒ¤Ï>ûŒóì˜Æ3sæÌ„„™Læãã­J¥²ªªêÂ… ×®]iñp…£;3öñJõööfgg±÷ -Y²$33S °ÉEއ`¿Š‹‹{{{ᡃ@àææöÚk¯Ù¥_ö4¶¶¶fgg_¾|ÙÍÍöf4ÒÉd²ÌÌL®ºp<ü  ßÿýÒÒR†›"‘(>>þÀÌ‹:m‡= ÒÕÕUQQñã?¶¶¶*•Jè0õññAS~î[ÓÆƒ¦þOœ8Ñâq„üXÏ´iÓJ¥­1ôòòêéé‘J¥hNdgg'ûì³¶Šu(ÇËúåhñ°Äü|ÙÙÙèºb°ªÐh4AAA£F5jÔüùóÉòððxóÍ7áF£ÑŸŽãdddF€L&£­_~ù%##cÞ¼y/¾øâܹsÿú׿VVV¢¿ŠÅâäää9sæz{{÷ïßÏgð  ñ2íWUUÕÖ­[aØááá .ÌÎΦ<3šó~1ăÐétqqqÓ§OŸ>}úÛo¿mÓxXb¦0T*U]]A...‡ìX±mÛ6ä?6E"‘;vÌÅÅ… ˆ²²2¥RiUÈ\ P(ÊËËa¿¶nÝj:ZgÏž}ã7JKK;;;ûúú”Jåÿþïÿ666’÷qwwß¹s'ìWmmmWW= ‡<^¦ýúúë¯‹ŠŠîÝ»×ÝÝ­×ëïß¿Ÿ›››ššJ© ûÅâàÁƒmmmƒ5b—<›)ŒŠŠ x¹3oÞ¼€€Ú}êëëjâçç0 ¾¾¾£ì͸qãà¯KááácÇŽ¥DÛÒÒ²sçN‚ ?~õêÕË—/öÙg3gΤìéëë 7 ‚ŠŠ ædò/Ú~¹ºº¦¤¤œq℟Ÿ@¡P|óÍ7”=¹ês<›7ož>}šùüŠÿ<›) ¹\ŸÌ°|ùrÚ &‚ ÒÒÒ‚@Ï®§ÅÃÃcÙ²eÖj#’’’ÈOL†äååÁ³¬}ûöEFFŠÅâ1cÆDEEÁÚ&#‹Z­V.—ó3h¼hû•••µÿþÙ³g;vΜ9kÖ¬Û=zDÙ“«~1Ç ~mܸ‘¡þól¦0Ð Òüùó)¿W@>ù䓆††äää¥K—2´ãêêgq”¶cΜ9¦ýª­­ˆÅâšššÅ‹Ï;÷Í7ß,))1}»‹‹Kdd$|Íp2É(Ú~3†üOôÄdÓËY®úÅàË/¿üõ×__~ùå„„†vøÏ³™I„*• ¾€‡] ---»ví’J¥G5û?¡¼¼¼P³öÂÓÓ³»»@û›Ñ“'Oz½þرcp‹R©lll|üøñ»ï¾KÙµà×N(±f kkkËÍÍH¥RÚ/5NúÅÏãÇ9"‘HvìØa¶)žól戾Th/!Ö­[§Õj³²²ÍþO£G†/Ôjõƒäôä.ÚS[ôx¸—_~¹¶¶ö»ï¾ƒ»;v –t†I;?gÐx1Ÿ²ß½{wõêÕ*•J$åääÐ~ëqÒ/æx>úè#½^¿iÓ&³Mñœg3…¢1ý4WWWËåòàà`™LÖØØˆž|£V«;;;)û£P…Ø4Ù6ËhöÊ•+¥RéüÇ Û…¿ýöegTcCúyÇF°ùô\½zuÕªUíííR©ô³Ï>‹ˆˆ Ý“~1ÄÓÐÐPUUÖÔÔt÷î]´gSSzæ·ñ°ÇLax{{Ô?õôôîß¿†ÎëêêÂÂÂΜ9CÙµðôéS{ß”…òN{R‡ž0†N‹Ñ ‘HDÙ™ýÙ  ñìdµ´´ôwÞéîîö÷÷ÏÍÍ5kÖ`MqÒ/†xàýÑ£GK—.MMM}çwàö7n¤¦¦^¸pÁñ°ÇLa Ùù¥¥¥fç 3Ð××ç7mL©©©³8ɤ¤¤ÀÅÅÅýýýmmmð ócÆŒùóŸÿLÞ“ ˆK—.Á׎°BÅ@Û¯3gÎ|ðÁƒa̘1[¶lÑjµ×¯_¿~ý:ú¶FpÕ/æxØÃžÍFRR|·ÇÆÆ P.Ru:Ý÷ßÏiäÜ —ËÑy0"111&&PRR2kÖ¬„„„îîîQ£FmÙ²E(’÷Ôëõ/^H$’¤¤$Þ 4^´ý’ËåðÓÙÝÝ‘‘ñÆÿaz««~1Äu“Dyy9ÜqóæÍåË—Û"ö˜)Œèèhø{~ee%Ão“fioo¯®®ˆD¢ÎÎÎ{£P(àIQ}}½éY"àÀ|ðÁsÏ=G„‡‡Çœ9sNœ8Ž$…BÑÐÐèíí7ožÅùá 4^ƒõ‹%\õËÑâaùI„ëÖ­«®®&"..®°°Ð‚KF“œœüÓO? ‚ÄÄDÚøgÁ‚/^ìë닌Œíëë;}úôøñã§M›F¹ 5E£Ñœ:ujÕªUA¸¹¹…††8p€²ŽÑ¾ ~qîÜ9??¿I“&™]#¦Ó銊Š233q¿†iÿÞ¯sçÎQnÞ¯_¿þ矦¼eìØ±—ÌÇ_}õÕáÒ¯¦¦¦ÔÔTò–¬¬¬Å‹›¶ãhýbOG f?•@ X½zuyyù“'OJKKÇhoo7u, ?ö8Ùæ~I¥Ò·Þzëã?^½z5s;ŽÖ/öðTÌ~ª“'O~õÕW¯¼òJ@@Àüùó?üðC¸ýÞ½{”=‘Ÿ {œl s¿&L˜™™ùꫯæPC8Z¿ØÃSa0û©ÐÊ`šn`ª&û©°ÇÉv˜õA±ÄÑúÅž ƒÙOEæÁƒp͆§§gZZšé¨ìq²šª_ìá©0˜ýTˆ[·nÍ;W¡PˆÅâ‚‚x±AÙw°ÇÉv°ìª_ìá©0üTˆK—.EEE=|øÐÓÓS.—ÇÆÆÒî†ZÀ'ÛÁá§Ù¡úÅž ƒÁO)((ˆW©TUUU ÎA-`“í0Û/ö8T¿ØÃSa0û©>ÿüóeË–éõzooµZ][[[[[kº–ì§Â'ÛÁܯþþ~•J¥R©Ðœ`kZEŽÖ/öð4Í=))éÚµk&??õêÕÈ ÉÏχÙW©T¯¿þ:ÚM¹ùüTŽãq‚ý’ËåÉÉÉ”³ŠÇ mŸ5kÖ©S§È{: ŸŠ¡_Ož<‰'oÉÊÊÊÊÊ\»v,kt´~±‡§#ç~*ìq²)ÎÚ/öðtÄðòòŠˆˆ€~¡ôôtŠŸª¬¬ŒM#fíÚµýýý 22Òæûµoß>Š7é‹/¾`ÓˆN§Ûµk×0êׄ ØÌ$rÀ~±‡¿I„ú©°Ç‰œµ_,á¯0 _Î/HOO¿rå ûÚ ø©Ðãû•••õ¯ý‹ýgÈñýTÎ×/–ðºPiË–-ÁÁÁp½Q||üW_}Ŧ6 Ÿ*11ú…&Mš”™™ÉC´ìAý"âoû[qq1›Ïô&­]»÷Ëáui+°¥ŸŠ+Fˆ7‰%Žß/ù»ø. `?WŒ(o{¶_6õwÙ¡0w~*®Þ¤!áhýâÁßeŸÂ€Xé§âŠ‘éM²é?^2{†5~*®±Þ$‹±o¿xó’Ù¿0¬oÇbF²7i8§—Ìäõü3’½IÃ>½d#·0F¸7iØÁ³—l䆳ú œ/Ùü±iÓ¦ˆˆ±X ŸãN™¼ †î%¡…¡R©êêê‚pqqÙºu+åXñõ×_Ý»w¯»»[¯×ß¿?77755•Rîîî;wîtqq!¢¶¶¶««‹ßNŒ ÈãuèÐ!ʱâñãǬ««c¾u)‘HŽ;Ær¼Fha8«ÊYaö’yyyedd|óÍ7›6mbn‡½—l„†³ú œf/YPPÐV¬XaZ3Ø{ÉFha8«ÊYaö’±‡½—l„†³ú œö^2³°ô’ÐÂpV”³ÂÒKÆ–^²ZÎêƒrVØxÉXÂÒK6B ÃY}PΊY/{XzÉFha8«ÊYaö’õ÷÷+ …BŽÿjµn¡ìÉÞKæÐËl‡³ú œf/Ykkkpp0yKzzzzz:@§Ó‘odz÷’Ð#ö& /ø÷’Ð#†³ú œf/YPPZžÀÀ¼d#ôˆF¼7iØÁ³—läÆ÷& ;xö’ÜÂ#Û›4áÓKfÿ¥­ …bܸqp‹§§§Z­&¯ùV(pE¸Ö|ÛΛd#ß‘ÓÀ‰¿Ëv^2{†@ ÈÈÈ(//g¶„ÄÆÆæääÀ›¶€so’M}GNçþ.[xÉìSÐ tþüyƒÁ`Ö ½R)))Cò ®¼I<øŽ†5ÃÈße‡ÂàÇ dVz“8÷S9¶ów‰D¢žžÓÿQ*• Ë}úôéo¿ý6ùONï§bðw566nذ!...<<üÅ_Œ‰‰yÿý÷)ßÔöÊO…ÁìBlÛ¶a‰:Ù TVVæk¬ Eyyù`~*ÄÁƒæ„:±ŸŠÙßuëÖ­Ÿ~ú©­­M¯×÷õõýþûï/^\µjÕo¿ýFÞÍ.ùá©0˜½@úúz†š /Á`ðõõeoƤõSAnÞ¼yúôiæógõS1û»&Nœ¸uëÖÂÂÂÊÊʼ¼<¸¦Âh4ž?ž²'ÿùá©0˜½@‚ ÒÒÒ‚سgC;È ähÐú©Aìܹ“ ˆõ0±ÅIDAT72¼ÝYýTÌþ.™LöÆoLž<Ù××7,,,%%n7½õÄ~x* ³^ O>ù¤¡¡!99™VQƒ { Z?àË/¿üõ×__~ùå„„†·;«ŸŠÙß… ¢¹¹~â¥Ré¢E‹(;ðŸž*1{ZZZvíÚ%•J=j¶)Ô‚——×`*Þðôôìî¬üøñ‘#G$ÉŽ;Ì6å”~*6¦™L†æŒ>|˜ö¾ÏùáéˆÁìZ·nV«ÍÊÊ 4ÛòYoR±4s„öâ£>Òëõ›6mò÷÷7Û”Sú©Øø»FβÚÛÛÓÒÒÐØdxÎO…Áમ®–ËåÁÁÁ2™¬±±ÝxV«Õ”ýQ ¨BìZ•o:Z UUUaaaMMMÈ0¢Õj›ššÐw$Â)ýTl>Í.\¸zõêÏ?ÿ ¯1”JåáÇMwã9?<ƒNÿºÿ~xxxXX:¯«« ;sæ eÔÂÓ§Oí}Sjú|›žÔÁ|ôèÑÒ¥KSSSßyç¸ýÆ©©©.\ ìï”~*³þ.ÄØ±cW­Z_Ó^E𜞠ƒÙ IJȡ õS±ÇYýTÌþ®ÌÌÌ’’’ææf¥RyóæÍC‡Áí¦3aùÏOß ^ ÄÄD²âáÑ£G0/±±±eee”vÈÑ0õSEEE‘Äýý÷ßcbb¦gõS1û»ªªªÎ;Gy‹D"Y·ne#ÿùáéˆÁ¹H$uvvØ…B!‰öS ³¿kÕªU3fÌðññquu‹ÅÁÁÁ+W®,((@sŸü燧#³ˆL``àÀ Ž ²(..ÎÎÅ}}}ccc/^¼Ø××gê§"ãïï?Ø|M'öS1û»Ö­[gzp0Å.ùáo!‡^ ¡P˜““c“(‡NNNöS10Lý]ü™¡¨¸¸X¯×§§§O™2eöìÙ,o½Q¼@‹/6 6ò†X@JJ ìWVVVpp0û'#?y܇Q~x]¨Ä§ˆO°ŸŠ™á˜¾×|óæâÛù©œ›ú»îܹóí·ßÞ¹sçÎ;pcHHHhhèòåËCCC-ówÙÁˆ8÷S9¶ów …BÚùAÐb™¿Ë>^)¼@vÁYûÅÃÈßeO¡•'‡ÅYûÅVú øñ’Ù³0 –yœgíWXæƒâÍKfÿÂÀŒX†j÷àÓK6¢€^ðé%Ã…´´´”””@?Õ§Ÿ~:kÖ,ö 3$ÉK/½täÈ€^¯/**jmme~ . Ìð€ÁK&—Ë׬Y3mÚ4‰D2uêÔŒŒŒöövòÛÉ^26~*|±ì¯1T*ULLŒÑhtqqijj %ÿuáÂ…¦Æ€€€††Š«éîÝ»“'Oîïï … ÷?ð3 `ö’ ‚Õ«W———?yò¤´´tüøñ€öövS·ò’™õSáÂÀ ˜½d'Ožüꫯ^yå•€€€ùóçøá‡pû½{÷({"/™Y?. Ì0€ÙK†V–CxÁTûMö’1û©pa`†Ì^22<€ku<==ÓÒÒLw@-0û©pa`†Ì^2Ä­[·æÎ«P(ÄbqAA¼Ø €¬KÌ~*\˜aƒ— qéÒ¥¨¨¨‡zzzÊåòØØXÚÝP Ì5† 3 `ð’A âããU*U```UUUttô`M¡˜gLáÂÀ ˜½dŸþù²eËôz½··wNNŽZ­®­­­­­5ý ì%c^¡1"–`†; ^2@~~>œ[®R©^ýu´=::šòcò’™õSá#fÀ¹—̬Ÿ fýT®®®ééé”å_eee´:<Êá‚ì%3ë§Â…pè%cã§Â…@?|’Fzzú•+WØ×ÅKÆÆO… 3làÓKfù])…B^{yy©Õjò½‚ÎÎN___‹Ç T*Ueeå?üÐÚÚªR©àÚqooo´vÜ2oÒpŒÇÍÍíóÏ?G~ªõë× ÕKvìØ16NKÖc‚ŒŒŒòòrø$_ZD"QlllNN¼™€±äM´ó mÄ2o’#Ä3Ô5ß~¼dC+ èó9þ¼Á`0ëónnn)))Còù`/Þ$GˆÇ²Â¼ø»†Püø|0¦yOLLŒŒŒôöö†Æ>•JUSS#—˯^½jë<Û.‹ b¥ŸŠ¶…Á›Ïg„CɳL&Û¶m›¯¯¯»»;ÅñÚß߯Óé ÅÞ½{kjj€mòlÓx¬, ˆe~*³°* >}>#rž]]]·oß¾`ÁÓkt:]IIÉÞ½{ ‚à6Ï¶Ž‡“Âà°2¬n×òéóÉ <»ººž8qbáÂ…f?…ww÷äää'N¸ººr›gG‹‡OÌÏ>Ÿ 9Ï;vì`ÿt€»»û /¼°mÛ6À]ž-ž1_ >ŸsçÎÑ>ýú—_~Aû Õç3bAy–Éd ,  «ªª¶nÝšœœÄùóçÉw&MšDÙú|*++…Bassó[o½eMÐÎÇÉ“'E"‘Ñh ;v,寮®®)))¯½öÚsÏ=×ÜÜüßÿýß …â›o¾IOO'ïéëë;sæÌúúzèMZ´h‘eñ q§G*•¾õÖ[Ï?ÿü7rssÚá*þ1sÄ`öù fΜù /¼ôÒK¦'£Èç£V«¿ûî;«Ãv6òóóáø¤¤$8OŽLVVÖþýûgÏž=vìØ9sæ¬Y³nôèeO±Xœ˜˜Xx“˜AãNÏ„ 233_}õUÓš±Q<üc¦0˜}>ˆÐÐP‰Dâîî{éÒ%ÓÈ>ŸÛ·o[­Ó‚nÀÏ™3Ç4ÏcÆŒ!ÿ)3ž}öYÊž...‘‘‘ð5³7‰ô^ÚxØÃU<ücæTŠ¥Ïš Cyyyeeå… bbb(û îܹƒî7c(˜ým®­­ ž½H¥Ò¥K—2´ÀìMb»õ¿rÿ˜9b0û|ÿþ÷¿755étºæææ… úúú¶oßnº3òù``¾%z÷îÝÕ«W«T*‘H”““Cûm…Îx™½IÌ qg‹v08‰‡Ì1<<<๯Z­6ýi}ÆŒ3fÌ€¯CBBþçþU}}½iS F B«ÕRVú#®^½ºaÆîîn©TzèСY³fÑ(Xv ‚Æ!–pÿ˜9b0û|à3›h†9íY)jaòäÉ´+tG2ȲŠÎa(”––¾óÎ;ÝÝÝþþþ¹¹¹ƒUàè,û`ñ°‡Ã³2>1SÌ>ŸÅ‹ÿ×ýWmmmGGÇÕ«Wß|óM¸ÝÔ¿@öùPn€¤œÔÔÔÀÙ©dΜ9óÁ †1cÆlÙ²E«Õ^¿~ýúõëwïÞ¥ìIºùaÍ ô^ÚxúûûU*•J¥Bg\p‚­iqÿ˜9•böù<}úôã?þøãÉ===)[Éç#•JW¬XÁEäNÅòåË«ªªzzzäryrr2å¬C.—ÃOgww7\¸ ™5kÖ©S§È{êõú‹/Þ$fÐ¸ÓÆóäÉ“øøxò–¬¬¬¬¬,Àµk×D"çñð™ÂˆŽŽÞµkø?ŸÏ”)SÈý裾þúëêêê¶¶6N7a„ùóçoݺ5((ˆÒòù †I“&áÇ,Q …Ë!ëëë;::‚ƒƒ-kG¡P444Þ$fи;H<üc¦0 Ï§ººš ˆôôôÂÂBò—GLLŒémYS†äó™ó¼oß¾ƒ’o}ñÅlÑét»víâ$ÏÌñL˜0Íjãáó“yöùŒXPžkjjΞ=‹NßY¢Óé ¯\¹8ʳ£ÅÃ3æ ƒgŸÏˆ…œç¬¬¬ýë_ì?‹:®±±.{à*ÏŽϰZ¨Ä§Ïg$ƒòLÄßþö·ââb6ŸENWTT´víZÎóìhñð Û5ßJ¥ù|±±±Cõù ¯;ÙVb™‰’爈ˆíÛ·ûùù‰ÅbÊk‚ ôz}GGÇž={êêê€mòl»xT*Õ;w¾ýöÛ;wîܹsn ]¾|yhh({?•-–¶ÁÂÏÇ °Ò¿dšç™3g&$$Èd2håP*•UUU.\¸víš­óÌy<(?B¡v>´{ØÚOÅÌмRÐçS\\ÜÛÛKùÙÛè•zíµ×†äóÖpå_âÁ›4$¸ŠÇÑüT Xb" …ï¿ÿ~ii)³‰0>>þÀ û8œ{·7ÉÍÍö¢y,ó&Y€•ñØÎKæ(…ãP*•ÈNëååÕÓÓ#•JŸ>} ·tvvžŒßòlçÝêêꪨ¨øñÇ[[[•J%¼VñññA×*<ÿ>`Y<6õ’9VaÐÆÁadÃìÝbÆÖù±›W à ön13óƒÖÒÒÒ’šš ýKǧ†Ì¢ÕjóòòÖ®] pww¿qãš‚îܾ}{ÆŒðºÂÊüˆÅâÂÂBÓ½øˆáˆ0x·ärùš5k¦M›æãã#‘H¦Nš‘‘ÑÞÞN~;Ù»e4É“gƒŒŒ hÙ1ÍOMMÍ¢E‹‚‚‚$‰P( \ºtéÕ«WÉo·—— 1¬B¥RÅÄÄF—¦¦&ÊR“… ž?žò–€€€††Š‹èîÝ»“'Oîïï‰DmmmNó›B¡ 4 ´ù9|ø0Eÿ‰Duuu/¾ø"y#ÊP(¬¨¨ \ßã#†ÃýKZï–@ X½zuyyù“'OJKKÇhoo?zô(eOèÝ ___Z¿ãpdܸqð~=m~BCC:týúõöööªª*¸¨Á`0|óÍ7ƒåú©8=&paX³wëäÉ“_}õÕ+¯¼0þü?ün¿wïeOäÝrVhó“°aÆ^xÁßß_&“! Ÿé­'”ÞüT#âiÛÁìÝB+§!hzˆéå5Ù»å”0{Éúúúšššòóó^^^ùË_(;óß †U°ôn>^¥RVUUEGGÖjáéÓ§ö¾™ÄhîÜ`ùAlܸ¾¦µ£ø¹— Ã*˜½[Ÿþù²eËôz½··wNNŽZ­®­­­­­5½¹Nön9%´ùYµjU^^Þ/¿ü½d;vì€ÛM#AÎ?~*|ñmÌÞ­üü|8wZ¥R½þúëh{tt4åf<òn9+´ù‘Ëå§OŸ¦ì)•JQ… P~xóSá#†UDGGÃù лeq;È»%‰:;;yW„Ú …Býk´ùÙ¸qcdd¤ŸŸŸ@ ðððøóŸÿ¼~ýú†††™3g–ÞüT¸0¬ú—\]]ÒÓÓ)ËwÊÊÊh?.”ÃÙ»ç4óA¾¾¾±±±€6?;v쨮®þý÷ß{{{5ͯ¿þzäÈÓó(»xÉpaX ‡Þ-¡Pëp&rrr†£— _cX ô/ëõúôôô)S¦Ìž=›å-EŠwkñâŃÁù¦]¦¤¤p’>ýTøˆÁØ»ÅÌpÌåÓÎ ŸqãàOOOµZM^ó­P(àŠpçûþ£ÅvÞ-ËüTކMóÕŸŠŒ%…!222ÊËË™-!±±±999èi2NçÞ-+ýTކíòÕŸŠÌÐ zΟ?o0Ìz W*%%ŬÈippÿ’ÝFùBaØÎ äd8¬ÉAùa[6õ9%è_r(óÃêvípô Gpž™á3?æØ›Äú—œ2Ï<ø©È˜?b0x“&((NÁ‡ „Ó{“¸‚Á¿„ÉyæÙOe¦0T*U]]A...‡¬F·mÛÆ°D]"‘;vÌÅÅ… ˆ²²2~Öì/ Eyy9Îó`0ççÚµkgÏž}ðàV«ííí}üøñ÷ß/“É®_¿NÞœŸÚÚÚ®®.†ÿÑLa0{“ õõõ c qVoW0û—pžù÷S™) fo€ ˆ´´4‚ öìÙÃÐŽÓ{“¸ç™ÞüTf ƒÙ›øä“O’““—.]ÊÐŽÓ{“¸ç™³~ª_~ù…?•™içÌÞ¤–––]»vI¥RSç¤)NéMâ fÿÎ3ÿ~*3G foÒºuë´ZmVVV`` s;ÀI½I\Áì_ÂyæßOe¦0¼IÕÕÕr¹<88X&“566¢éåjµº±±Õ.Â)½I\Áà_ÂyöðS™9•òööîééÿ eî Ü~ÿþýððpòöººº°°°O?ýôÝwß%o§x“˜ÿß Î33¦ù¡ýT¹¹¹À:?•™#³7‰=NïMâ œgfxóS™)Œ¤¤$xÄÉÏϧœ“%&&’Í>„Ûccc(_cNïMâ œgfLóËå«W¯~þùçýýýÿó?ÿóÇVû©Ìö&ñ³ ç™?•™Â`ö&‘ „}(++£üɉ½I\Áì_"32óÌ¿ŸÊü$BìMâýKN™gžýTæ½RØ›Ä\ù—œ5Ï|ú©X-TŽ^ áÎ33|æ‡íšoÛy0dpž™á-?C°„pîÂЂóÌ ?ùšWŠ+/†œgfxÈ%&B+½@–à<3cÓüXR˼@˜¡‚óÌŒòcya`0N ~ C. †\ ¸00pa`04àÂÀ`hÀ…ÁЀ ƒ¡áÿqp+§—ô}IEND®B`‚puzzles-20170606.272beef/icons/bridges-48d8.png0000644000175000017500000000252613115373725017625 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá æ—^IDATHÇ•”}LeÇ(âxqefŒ˜¸–`6‹…¹175Q7p™3cÄÄèØ¢Æq›f¼„  s![ܨ¢‰ 3° H6CAÊ(íÝs×»ëÛõúÂ&èt™FFéÏë ޶lŸôkîùÜóüžïïy0òÁB¾A¸!<à8òü#VÁa·9LÂï4„ÉÉaD÷645×]¢Hö\íOF¶ó¤Ò„ÂΠ¿ö}Κ‹}„õ¬þ6¸maÇy<| p4ô%ö#X;ÇÝpë1aJ‡ å·¼ ®ò¢äÏÅ<Ü 8’ ¤6á[¸wv¾ pê1¹¢@EÂ,4çN|O¯,xr@ÖŒ»àX†gŸÄB .Ÿ µ¿’ P±«ð8¸2©gìN§ƒCÈ/èŒ=M0ÂïƒØ!vÙ „u¤r‹b÷E3CP^À­ X)º÷ßø«Øyn>Ï5Æ$¿øºËS³È'ßhO‹N_%ûÁ;Þ# šò¯ÇÚˆ½Kÿó/9M†ëÇ}IXX${Ž1˜q/!vp”öÖË Çþc¸ú„Ú6&-·ù×Áóe  t+nû¼•÷¾°W¦ÆËÏ&þB:Ž%iµó©ƒ‚ý0AgíÁ›:àÌ/tLp=©4Ó'é¤ Û,jÞºåÅ7'ø+k4F½*ê;&¤àh¨ô$"<”d[HÕþU£Våª2”@X”ÝÞ³ApíÝ“Ý{Ê÷^›~a3§ö&– ÂHÈ´uƒzêÏßïLÀ”&Žæ‚7óeB õÆ„êÞëv§Ë|¡DúÐK§ D@>H‚!Þ–J"c²”VjVÐØZ¹YÍ!„pÒ6q©£Ïb´”$¨`Î œ<‹¢D…óà†%¸`»ƒ{ß#Á)ýЮíמþdf¹L&—+¤¯ôuçTo`E3 và“ºÚ¥4F7ìûLFÀ¯%ªÒü&B—ܳs£Eù#‘C"çÏ`1’%D=ŒøôãœMkÛKMXÁµ”èˆ1‚êÔ7ÁÌã„Ff¸±°$Ds1¶ÜÌ[àvÃìîÔ–ó´·™Z¸Œ!FG«eñUƒªÓi‰]vmÅÆ¨è¬*š%±‚t4ùþºÈˆ”}öþuIÕ}½Gbå£ ò/‰1ŒbXã´õƘaš'3¶Þñ,n23›ñç`ì¶Š£^”yMêmhÍ+Ö€9®Þ†û·5ꑸ`ÄÆÆÅ&a5àBòCeOs„ïˆÖ©{®§¿+¢àï²G¯|µš™?¢ù­gƒòe[3ö3¸îrÛ ÎI™ù¤S2ÒB°þ IÌ”íK? °'÷. ®N†,z¾ˆwÙ¥sÝÂãþme¨èÙMrá¼Ì¹v‡ -œÝ$)=ßö¶ §ç…pPÃÖ?µ:ñ™³>ÐáA¤ÍÊ0<y‚p%z.}<Ƚt_<°ð?q¨‹#Ò;ø%tEXtdate:create2017-06-06T01:31:17+01:00Ëꎷ%tEXtdate:modify2017-06-06T01:31:17+01:00º·6 IEND®B`‚puzzles-20170606.272beef/icons/bridges-48d4.png0000644000175000017500000000141713115373725017617 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA† 1è–_bKGDÿ‡Ì¿tIMEá æ—CIDATHÇ…V‚#!ãé<-?〢í^íVKW þÊim¸¨¿ù”;äçrbTÑøD}13ôi3¸š NÔ8â ´Ñ^û¥Úöˆ³¹•ר RÌþ½#OSÇ•.?= X£Ä+œÄ>BÄÓ丄öà, 5öÑxTÍà˜5qÈ|ÿàÑ€¿-’¬éãbÎùHÅC_Ò•QÐ@¸óÒ`N©"4ÏäZ’(F“2J¤agދޔx$Ú{JÊ@EÉÊYE:™ª—!úFš'^d¼"?.õõÁ¹Îl~åóîKW‘2—%tEXtdate:create2017-06-06T01:31:17+01:00Ëꎷ%tEXtdate:modify2017-06-06T01:31:17+01:00º·6 IEND®B`‚puzzles-20170606.272beef/icons/bridges-48d24.png0000644000175000017500000000252613115373725017703 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá æ—^IDATHÇ•”}LeÇ(âxqefŒ˜¸–`6‹…¹175Q7p™3cÄÄèØ¢Æq›f¼„  s![ܨ¢‰ 3° H6CAÊ(íÝs×»ëÛõúÂ&èt™FFéÏë ޶lŸôkîùÜóüžïïy0òÁB¾A¸!<à8òü#VÁa·9LÂï4„ÉÉaD÷645×]¢Hö\íOF¶ó¤Ò„ÂΠ¿ö}Κ‹}„õ¬þ6¸maÇy<| p4ô%ö#X;ÇÝpë1aJ‡ å·¼ ®ò¢äÏÅ<Ü 8’ ¤6á[¸wv¾ pê1¹¢@EÂ,4çN|O¯,xr@ÖŒ»àX†gŸÄB .Ÿ µ¿’ P±«ð8¸2©gìN§ƒCÈ/èŒ=M0ÂïƒØ!vÙ „u¤r‹b÷E3CP^À­ X)º÷ßø«Øyn>Ï5Æ$¿øºËS³È'ßhO‹N_%ûÁ;Þ# šò¯ÇÚˆ½Kÿó/9M†ëÇ}IXX${Ž1˜q/!vp”öÖË Çþc¸ú„Ú6&-·ù×Áóe  t+nû¼•÷¾°W¦ÆËÏ&þB:Ž%iµó©ƒ‚ý0AgíÁ›:àÌ/tLp=©4Ó'é¤ Û,jÞºåÅ7'ø+k4F½*ê;&¤àh¨ô$"<”d[HÕþU£Våª2”@X”ÝÞ³ApíÝ“Ý{Ê÷^›~a3§ö&– ÂHÈ´uƒzêÏßïLÀ”&Žæ‚7óeB õÆ„êÞëv§Ë|¡DúÐK§ D@>H‚!Þ–J"c²”VjVÐØZ¹YÍ!„pÒ6q©£Ïb´”$¨`Î œ<‹¢D…óà†%¸`»ƒ{ß#Á)ýЮíמþdf¹L&—+¤¯ôuçTo`E3 và“ºÚ¥4F7ìûLFÀ¯%ªÒü&B—ܳs£Eù#‘C"çÏ`1’%D=ŒøôãœMkÛKMXÁµ”èˆ1‚êÔ7ÁÌã„Ff¸±°$Ds1¶ÜÌ[àvÃìîÔ–ó´·™Z¸Œ!FG«eñUƒªÓi‰]vmÅÆ¨è¬*š%±‚t4ùþºÈˆ”}öþuIÕ}½Gbå£ ò/‰1ŒbXã´õƘaš'3¶Þñ,n23›ñç`ì¶Š£^”yMêmhÍ+Ö€9®Þ†û·5ꑸ`ÄÆÆÅ&a5àBòCeOs„ïˆÖ©{®§¿+¢àï²G¯|µš™?¢ù­gƒòe[3ö3¸îrÛ ÎI™ù¤S2ÒB°þ IÌ”íK? °'÷. ®N†,z¾ˆwÙ¥sÝÂãþme¨èÙMrá¼Ì¹v‡ -œÝ$)=ßö¶ §ç…pPÃÖ?µ:ñ™³>ÐáA¤ÍÊ0<y‚p%z.}<Ƚt_<°ð?q¨‹#Ò;ø%tEXtdate:create2017-06-06T01:31:17+01:00Ëꎷ%tEXtdate:modify2017-06-06T01:31:17+01:00º·6 IEND®B`‚puzzles-20170606.272beef/icons/bridges-32d8.png0000644000175000017500000000171013115373725017610 0ustar simonsimon‰PNG  IHDR V%(gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá æ—ÐIDAT8Ëm“íKSaÀ÷TBj2Ô•®dš1ñ‹‰D*¾|ÈÊÀÖ ¤Î]+hš¦æÑ\Dà+ME|k¯ÞûÜ«w÷n¶Í1uš:§ÓžÍ—éÖïëùç9‡sŽ€…ÃÐËÓŒ™¡hZgÕê!džè§t=” … TFFïl‹p¼uñ,  ;„§›p”v€½v`í\U ˆ[®ÄŸ>ûΦÅÂÆ™z¡º,¦ä…_`fùýÇËh¶íD ¿NËu'æŒZq®€ýÎ!š²_­X-¼»Ò3êU­ƒ¢Î5=Nð}­bÇ4–)gO¯9áÑ3ú­ü÷‹F¿`î»g%‘i8Á8Û–Œ™Ï¡B±…•+ pƒ­fŠF¼¤ýO¡ä /üæ#žmh ¸ ikŽèqºèK¹NWñ¿ftH §Œ=ÿ"â²ôäùºXiZlM¦—]˜Åíù®N£I S¯¹­}!U­m~ZT]_;>ˆ «O²W "o_˜6”Éx(+-˾ Ð-2Cª òì”g'ƒó³pRT×¾tô ?­EFgÅЈ4PÔ±¢ß-riù€Åí·Ñ Š®_ “e–ÙÝ¥ÕN7½ŒLJŠTþ¾)º+JiÃÓd¨¯ç€M7¬kµksms,1MVOSFÈ+ƒ”W*•U2ñ_,µ„GNÞXóê05Êæ¬€–‹n¯dˆ˜†%¹yGȽ-¾L­Ðî±v¢kD=x”¡qœ£N iv¼“ŒÝŠm¥:j¼M<…Û$Ã1Z›Ϥô[¨ðÛÜ;«yhÌÎÿïº÷ Ç’8Nÿ¨¥áß+É%tEXtdate:create2017-06-06T01:31:17+01:00Ëꎷ%tEXtdate:modify2017-06-06T01:31:17+01:00º·6 IEND®B`‚puzzles-20170606.272beef/icons/bridges-32d4.png0000644000175000017500000000101413115373725017601 0ustar simonsimon‰PNG  IHDR V%(gAMA† 1è–_bKGDÿ‡Ì¿tIMEá æ—@IDAT8ËeS ’Ä@âé>ÍŸ±šdj»&ÇDit³ï¢Ÿßņ¾=!ß ºU“óÆùC&i·°kBÕûÀ˜ÄÍD€ œý‚Sä¡•@™òAh¿®r†@ }ô\aKLts·‹e/j&éVØ×…iô„Ú*¡ÍÉÇi€ ¹¼pˆ³!…‘¯•vÇÁaékЏ„ZtLÉãWÔL«e‹B«.k™¬žN¨¢Ú‘¼ÌpG ûŠˆæ«šó„ű¾¹¡"áüRÃDܱ%4ÂäW¬¤X iÛÌîC©ŒhK„IÖ>U#U"õ õ ðàÝn½“;O/ä§à•ø]’Û¶“+azÏ=¿«E¶Î^ÌôåI¼*Ò/Âú}m½¯¢÷œ¬=6ŸóçffxÍs|âOqõͯ §ÏÁÑ̲Xg°k%tEXtdate:create2017-06-06T01:31:17+01:00Ëꎷ%tEXtdate:modify2017-06-06T01:31:17+01:00º·6 IEND®B`‚puzzles-20170606.272beef/icons/bridges-32d24.png0000644000175000017500000000171013115373725017666 0ustar simonsimon‰PNG  IHDR V%(gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá æ—ÐIDAT8Ëm“íKSaÀ÷TBj2Ô•®dš1ñ‹‰D*¾|ÈÊÀÖ ¤Î]+hš¦æÑ\Dà+ME|k¯ÞûÜ«w÷n¶Í1uš:§ÓžÍ—éÖïëùç9‡sŽ€…ÃÐËÓŒ™¡hZgÕê!džè§t=” … TFFïl‹p¼uñ,  ;„§›p”v€½v`í\U ˆ[®ÄŸ>ûΦÅÂÆ™z¡º,¦ä…_`fùýÇËh¶íD ¿NËu'æŒZq®€ýÎ!š²_­X-¼»Ò3êU­ƒ¢Î5=Nð}­bÇ4–)gO¯9áÑ3ú­ü÷‹F¿`î»g%‘i8Á8Û–Œ™Ï¡B±…•+ pƒ­fŠF¼¤ýO¡ä /üæ#žmh ¸ ikŽèqºèK¹NWñ¿ftH §Œ=ÿ"â²ôäùºXiZlM¦—]˜Åíù®N£I S¯¹­}!U­m~ZT]_;>ˆ «O²W "o_˜6”Éx(+-˾ Ð-2Cª òì”g'ƒó³pRT×¾tô ?­EFgÅЈ4PÔ±¢ß-riù€Åí·Ñ Š®_ “e–ÙÝ¥ÕN7½ŒLJŠTþ¾)º+JiÃÓd¨¯ç€M7¬kµksms,1MVOSFÈ+ƒ”W*•U2ñ_,µ„GNÞXóê05Êæ¬€–‹n¯dˆ˜†%¹yGȽ-¾L­Ðî±v¢kD=x”¡qœ£N iv¼“ŒÝŠm¥:j¼M<…Û$Ã1Z›Ϥô[¨ðÛÜ;«yhÌÎÿïº÷ Ç’8Nÿ¨¥áß+É%tEXtdate:create2017-06-06T01:31:17+01:00Ëꎷ%tEXtdate:modify2017-06-06T01:31:17+01:00º·6 IEND®B`‚puzzles-20170606.272beef/icons/bridges-16d8.png0000644000175000017500000000077113115373725017620 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá æ—IDATÓ=Ê]O‚PÇñÿ{ìm”]4¸êa•˜³-C|À‡™®©%­ÕŽ™J¶Ô¨ §apBG­ë^AŠ[Ÿ»ßw?°—ˆÑ5GÖ›á@81&¯ÛOÑ—^Œ„Ár>ÌIEB×sy0Õ×ÉkñŽÎ¼[´°±y8ågÒÎVË}öw›g‰Û’õsÑ LP®üvL„vÙ§r1Øî$öÜÉz1h"jhÚ¨ZË••tãæŽb0ØÕÈË®ü2z^nyó‡ÖWUe˜Çb=W˜a ÁWè4UgÓIT†ÛŸ‹ñ‘ËÇZÁà #,‹Låù!ÓâO—üï¤À)Øæ?ï¾Gñ4¸•¤öoÁ%tEXtdate:create2017-06-06T01:31:17+01:00Ëꎷ%tEXtdate:modify2017-06-06T01:31:17+01:00º·6 IEND®B`‚puzzles-20170606.272beef/icons/bridges-16d4.png0000644000175000017500000000045513115373725017613 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA† 1è–_bKGDÿ‡Ì¿tIMEá æ—aIDATÓ=O!rtFc3^Oë.І¤öìÍk `“ЈI¦¸Œ…a‰°¡ƒa0­˜GR?KÇòÄ©4|#ã=lûŠ¨Äœ 9Sy1;ŸÏ“è´çB7Íwoyîß1ñ¢#¸˜ó°ææ%tEXtdate:create2017-06-06T01:31:17+01:00Ëꎷ%tEXtdate:modify2017-06-06T01:31:17+01:00º·6 IEND®B`‚puzzles-20170606.272beef/icons/bridges-16d24.png0000644000175000017500000000077113115373725017676 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá æ—IDATÓ=Ê]O‚PÇñÿ{ìm”]4¸êa•˜³-C|À‡™®©%­ÕŽ™J¶Ô¨ §apBG­ë^AŠ[Ÿ»ßw?°—ˆÑ5GÖ›á@81&¯ÛOÑ—^Œ„Ár>ÌIEB×sy0Õ×ÉkñŽÎ¼[´°±y8ågÒÎVË}öw›g‰Û’õsÑ LP®üvL„vÙ§r1Øî$öÜÉz1h"jhÚ¨ZË••tãæŽb0ØÕÈË®ü2z^nyó‡ÖWUe˜Çb=W˜a ÁWè4UgÓIT†ÛŸ‹ñ‘ËÇZÁà #,‹Låù!ÓâO—üï¤À)Øæ?ï¾Gñ4¸•¤öoÁ%tEXtdate:create2017-06-06T01:31:17+01:00Ëꎷ%tEXtdate:modify2017-06-06T01:31:17+01:00º·6 IEND®B`‚puzzles-20170606.272beef/icons/blackbox-web.png0000644000175000017500000001065613115373716020064 0ustar simonsimon‰PNG  IHDR––j.>gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá –h/{¶IDATxÚíœ{t×Ç%;„6'”%í²iÓn›n“f!ÉI“¦›Í浜žÓt99i“Ò°ÁzKÖËìð~¿lÀ0~Æð#{d#[†@lH,ŒmŒ±fîÌHòC²Á›nþß³§ýkgF3s²d#c”žüŽOȇ{™ûõý]ýîo :!Mñ°|íeQFÎ Cd¼²‚¡`H²`ÀLšŒ—B“¡Ð,œd¨8{‹•a)ŠûÏ,D"ICòF€Äø®‘L<²¨„»˜îïN¥ûú!y!õBŸ ƒ§PŸ"¯A/z?AqõêÙ›,M3ÈëåÇ;p“åk€`ûoñe”×Kqÿ‚í»Ír¹14{ÝË?… ×d<~&C{ t%>'ƅƾørZ–…F¿¸ÃWaoð²Pð/_N"AC#ÿ4KO"š¹>ÂW™üŸ)áaè(Ô û]™oo¡@›U½‡kT…]YùFY(PkN+â„ð²PàÓ7¼ÛºF©°,tÚt1èÉ"ïd[Qt‡ ÷ø¿—×N=(YÈù¼MùÉ%É*YIùEYÈw¡åwOxY$È Ö$½õ®, 1SšU7ýʉÈ_Ú¶[qI”…˜[ÖågH ²²à“”å#¢¬ÉŠG¦•ywÃN¤}ï?zâ"ÿ˜"‹?ðÒ y’©ÐñŸ½ü‹kJì-Ë ¿¬¥'Rͯtß~©:–åøÕ/W¥Œ=¨Þ¢Ñ7!Ñr€ðOLLHŸDšææq)@Ð,W0á“[¸Þ’+"^fo’9â#6O7„šT˜˜¾aŽ…hî1!nññ>, 6Ð (u… ®Œh43›,&ª·€Èp”—(Ü[RM¡·ä§„édsõÖ%ot>!Ê¢6 ÈBѲÍ5 eyâ”Åý“ØBSI²¨ 50ÌYZY!Ùiqºá€Ô~®S©«PYg]¦rwu9†Ê®*L},P‰z€,1ÀJSuZÑt J7*-€T}8SJýîM˜65çnÖʦn±«dÐè “¯_Ñ#—YVˆÅc[©³ZÂf¶jOUjUž‚Tw ÔÔ5Ô[$²» ˜Ò‰\“EF›33Ù{XèÒ+tLYœUh-颙Õ'+Ô€*NªÍ˜êò5˜4´˜tŽz™ÒDŽA“Õi7a²uUY–¯ƒ,Ë|eYSV‚öÖ7²E–9B–yáeã’ÅÀpŠ*tV³h|8Õ`Òðá—ñáT&!œJ§2 áT‚p8•‹ìÝ a¡½@Vx>½Q«M»¡ t=¦õ¥@YõaPscý®DšÔæœM2©U-¶Í2©t„Q%WTºý¸i‚½Eõßæ(8uR´SMäh‚Dœ-8)[A{M!¦BWU¦âŽ2Lŧ:KŠ1•t â¶°,2Dõ #pQYêˆ Â©­ ’«ä e‘D È*ÝU ¨ìmߘˉØë¡5œ׃²êC0m˜éÄTìÄ4ΉjèÄ4LúÙ‡<â‡ü"f³ù¿« âï-Ê“A|#+ád%`!„S³îÂá“AÈ$d…3)f†3‰ÂDD8•hŽp:{9ùh#&íž|uªNÌÄæa¤Í™ Cž"ù-‡ž4›¹!ŸWÒ,46}7”p5Öðëÿ8Ê/V'T8¥&JöÙÎq*Á2äÿkáã=Eu_“*þ‘ó.™`N$' ïdv&XoQãoVÐ9–`²h4ñ—/¾  „Ë ¨¯I„9¡3ˆ9'.ƒÀ/ºsN>iáÉGÅÙŒ5õì“9Izúo`k¯®“­šhƒÔF@ºà€ÔÑ\ƒ©ÆÝ¨¶«¾¶®¦¶¡©ñlMmÝ™®3µ¸èL7l»: Þ’lèÖ­s‡å‹vìðÙ¦C˜5e‡5°¦³â¦#í§Ê”Ÿç*>š_t|«=s_щ£Ç;NäÉEùÇ»‡‡äÖo ÎâD†eKStÑø]Œ ˜6𻸬úpŠV¦”†Ý©2i…] ‰4ª{šñ?—+ŠGžþ³AG˜ÔrEµ±Û‡Okø¨YrynøEd'#3ˆ“ ƒÐÔÓZpÍÄNœA˜Ó‰ËË …2)I©xl]‘‘Ž‹Â¢øn@-êDËŽ7J®³8eŠeÚö¨¸…FÇobÑ_ÈœöǼ*Î’¿rÛfÈ¢BÖ¦Ë_açÕ[ó–ep}(©âþ\Ù’1#œ’wÞ{ñ ·|‹,Ëý×K’=ZŸ5SÖäúä×´bhÑe½ e)‹šZ÷ÏgS—-zouü8ñ{Ž™N¤î¬}ño'‹Ý[Æ6ëR<ä_‰òh´êø˜kÉЋ»ѲãßIʰªo«Ú£2œ¢F§™ÙÄ}„Óûz!3¯æWr²RñèûÙDô.÷.Hy¹æ½‹<ù¨ ÿþ-¾·¾ÿ¡1ÎÉ‡Ë zû€¹ê›Ekªo W;¤g¦w+¤.GC#¶‹Í -õÇ÷,uœohºx5õô]Çm{ é¡Û’ ß®ß}ð€hwÕÔïT_©¹ÔÜÝZ²ç€l{Ú ÷bÚ!ß}ŽæçÞ¿ÿ!×áý¸èP÷ȰÜúí¡N„ç 6é¥S ú”²@e…jޤbJmØÎAl>ÿQ&Mk†š#ÞiZÖ@¤ktr‘‰s¢l윬š“@'!Á ¢m:þ>"ƒ0¹Fœ3ðkQ„pb(áÎA°~z‚{¿I¬%]ä¿öÆO×\õ£“å»ÞI$åM‘‰%‹ËlªŸþio¢õN¬ññì» Ö[T¨fͺ¥E¡“…|7ŽîpŽÞ듸èkÈ7ýÅø\qëa…S’ä5DÈ ²N>e› :Ñ ©…e©€Ê !Õ575ìÙ¬—HŸv~«J&¶5S-“ÖH˜µéµé³M>ä¤÷³ë’y®{:›²5»: u¸ ¹Û!uµÇtþ"A­€—Z õpmÊ÷FdÃÞlu¹»vж+§ª.P]¤ÆÓ¹;eÊu~$ÓέDÞVLÛÛn“aÇî {·cÚÓM⦽ÑNŽÈЇeË6ô¢6qN”)µ¬h(«9 jnnØ›†Iu~«Z&=çD :ïD™$'Ò³dŒ Ÿô­ÐÎkÈ7ÎòæY†¼Õ™aš9ä¹ÖQìOâÈÍ[cìÃÊ ˜‘Ì ‚yë‰'ÿ€„±øá4ÐóÚO^¾ ¢eùŸ6Ô):ÒJ3Ûµ#ùX¬ ·êµu¯z™‡Ò[4y·låÓ13ö…çžy}üá8‘Ó5ܹÌ6£·ü?¶ø”9SäÃÉ ª_ýõòŠ`Œ±Åœë'šýgȳC•WÆbfÁ1j"¸H»ѯSwGcÇ-Šâ"ã–%º·,±eY8YºÙd™ˆ£9¦,³´¹B‘ˆŽ–¿¡P®N7 œéªâò4ŽÂ–žV^¬T›HÕ¸_c’Ȥ=¿]‹ÉкEoŸi2š6ƒI.²Î¶çÃg`puº;Û[[[:8’­ÅÝ©Ëéâ…VL­Û!]rrjëp»]DK+q‰Àe­Dl;"ƒ`Føm}ɪí9Ûs6¬yû·úí[­e5¶ÜÑrm5eê‹í˜ìÍù˜2[fÊ”³Å¹'+w»qíÛkþ”½=û£öm[pÑÖn„›¦nG8…þ‡aÊÓlï­ÖŸÕ¨ Ë7› ¢™6—AªÍKÔָOm”Ȩ>¿MƒIßšeЭVO¿ó®ÅDXõF¹ÈÂ9çÑCÞïC>¿0¶ÒÿKÉï8$)+SJf y &!ƒI1äõpÈ›M­¹ºŠT¼“MpòLì±%Êêdúøï:~üÇo‹ëÂIŠ—–/È.ÆöçÅG*Éë]¶øw_ý«Òþú§ç§¸(Q»Z^­NRì©V-Ä’®1Y!?ruçýÈzæ÷ÁßþœÿŽcÙ2yµ:Y‘V—¶ àkåßT©ø‡æÌø6……©ú¥GŸK~5H!æ”R^ÙOV|pf!dEl,‰Ú.˜«·žýpjí¿Nq²J½µnad­²–Ö߬Ùø·Æ9}ü$e­]Y®?ƒ]ŒÄ»³/d=OÝ,â†ü›Ò¯¦T†<=@£ãB¡û‰"Iɇ.¥âòòø›¹§ê–ï*„m e’âŸÌm1¦êزøx…˜ð—Ëuº§Â¿›òu}q…Êlͬª(†T›¯N—Iݸ_+SºÖ±C'“‰ë-Ë;Éânâ&;a3ÊÖ9Žg4øÞd¥.úæ©o-ùÎÏÿ¸EwªRg³Z-VÞlºÊSÎ×cÒ72Ø„ÿåþÂftì6Y%²š‰LÙV-_²ôûoší6g–Y.³drï‰ø‹€Þˆ âš§[A8Ým gÏu¸¢ÓM8e#ܺ: ]tAºtóR;Áå$Ígë¹ÎKm ÈÙÚö|Ù[ø+¦U™2í6{VV¦Í–i,©2fÚEË4V•309a’)Ãtîp:&sË^³Lv±ÍšÁ=-+‹{°-«m‹M®hËî†_qõΙš„4s½ª¸"M#\âÇ-LªÚ<5&nli0 i lB(=3œÊEÒØBˆŽ{» :iÖÄ—4ëï7iF¾q&ñv1ÀM1 ¶‹A#†~vio ÑÖåÉiËê•WM5qî7M÷'š,òŽuÅ/)‰& ù®6lYR}/Y‹þ²wý=£qùµÓ¹â2÷›ˆ[âÚ©\~óA$µŒåÅ ž‹ò*@ Ês3ˆˆ(?3ƒ£¼8X`”ÇDt”s"7+V¹ù+lvCI¥^¦ }e‰Á.“áÌq£LvcÓ!¦tÇžt™lVb«C¦3ÛŠ)«‡W x/Yƒ¯ÈvùÓžîyYÏü¨ç“ËW`ëò üÉ<0‡|Šƒñ úñRþÁ!HýÃøÀãët‡AXbÁC=ð s™Í‹ƒ<êR†š¤Á~;y{Æ p׈°›%Ý5"–1ׇ!yFpûDÌ»FÂKZÂ]#3-ú®Nx^øf™Â7³øBøê&¹ì~ïAþðŒëF)æÞ²ØþúŠùª²PÀS›÷˜{Ë¢‚ÇWü@¾ºi¾²í{Qá§LM®üª²ÈéŒ×þѵ²È»Eßúв¨qâMçc Û[GŸð°_M9µwÙóŠß0 7¶ÈPþwWœà<@WÒ´b4/ªI‰¨$e¢”Šön€¦‡|å²i©æ sN û:€þe†}Z½^°+Ð|† \´·ãG ŠÔSŠÌSŠÄSŠyO!ÈîÎulZ³à÷Aë´qKÚÎ @€ @€ÐfPãìA¯j }ƒâöœÖ$7PDxžÿW ÎA÷× ½o @š @Õ¨u'ÿs}à—æi%tEXtdate:create2017-06-06T01:31:16+01:00m…%tEXtdate:modify2017-06-06T01:31:16+01:00À=¿IEND®B`‚puzzles-20170606.272beef/icons/blackbox-ibase.png0000644000175000017500000000170413115373724020363 0ustar simonsimon‰PNG  IHDRÂ-½dgAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿ oFFsÐ[sÑtIMEák Ö vpAg``ßn¸w¢IDATxÚíÛ»oÓPà?b)8‰‹‰­ffܽ3M[5ñP;R%˜YXêÄ”‰3"K"ÕHLU%ä¿n+ubßëÔØçÄ9¿!Ë‘z¿çá{r q2?gSify}R´ó i,Ít:’¦pAë  æ­×·CA¡bÁ\õ•ê"惽¯¤@"Ýït@O?µ^å…£Âuè4Ž®©tHP/é€üÙ»û°qNt•‡ï‰½Ëî¾%:½|­ƒõ…(ŽvI¾Ýø@ ?xL”å…Š ÔkÒ!Š P±àmëõéÐÍgf,x›:ý‘Ç‘»dK€†žc7–íxC  }G7oÜLÝícƒN6ü‹fl¨ ãŽÉtÁrçCÇ-棵h º‹!ºw‚Ú4 -Æ6Ò|h?Ý#DýJnò#€väh †‹êÝÇ=13A¦WÁ|hä@vܲ;´7Ïæ@¶dW2cœ5% Ô€4Œµ…Ù¡4ì5ÔÆ¡¾ËÒ@žäshw½>©Órõݬï2­‡sûq€õmŸmeÜí`͇‚nÚEÓ:ÚMþ µ(Ò6ðî©…hq×ÑMî:ªžÛÆÍ&iÆî¾L¤ßû»smê½ÔkÕó!ßsmKìí]ÏÏßžñ|ˆAµñù¡U­ßù!ýPÉç‡jÐ!1ˆA bŸZEŸÊâóC$Æ1Q‹Ö!^.êKZ°Î 1ˆAk :?xÔLüo6èóõoI„@“£7‡¤@"ÏÄ • úEÀ‹(¢šüùÙÿ‚Aùë bƒ´r rãÕü¨h–•1ˆA ƒĠ²ó î–ÊQ/wlÛ%tEXtdate:create2017-06-06T01:31:10+01:00M°9%tEXtdate:modify2017-06-06T01:31:10+01:00…IEND®B`‚puzzles-20170606.272beef/icons/blackbox-base.png0000644000175000017500000001577213115373716020225 0ustar simonsimon‰PNG  IHDR`` 4bKGDÿÿÿ ½§“¯IDATxœíÝml[Õáðã›ØI”÷&J¨šº’5µ‡ºjêÖ) «Ø[Õ¦*Pè„h«–-€"¤ªC*Rµ|¨&:Ön ¥€ŠWAX²ØÄ\œ“ÖR¢’&¥i^››Ê/¡8¶ã—}¸šÿù§9Ÿã{ÎõóûäZñsÉõù×ç^›\.XŽ¢÷@\( BA ¨P@…‚*P¡ € T( BA ¨P@…‚ªl½°”ÕjÕ{º±Ûí6›MïQüá ÂápÄb1Ná&“‰‚|䋜/á "‹UTTp WU•‚|䋜/œƒ*P¡ € T( BA ¨P@%ÜB)8ާŸ~úöçß{コººÔóÝn÷©S§C¡!¤££ãá‡N=YÃuüÇŽëìì$„´µµíß¿_{Òãñ466BJJJúûûSÜ„Óéìëë¸yóf(Z½zuccãž={ÊËËSL†d¡ t ªê™3gô…¸Þzë-‡Ãÿçµk×®]»Ö××wîÜ9tDš¡ îä÷¿ÿ}qqqüŸÕÕÕLb wïÞ}ï½÷ tuu1É\§ñó–••ÕÜÜü³ŸýìßøÆððð¯~õ+UUoÞ¼ùöÛo·µµé=ºÌ‚‚¸«ÕZPP““Ãö*š5kÖWD>òudü‚€CAU¦„ìG’ÈG¾.2¥ d?’D>òu‘)+€‚*P¡ € T( BA ¨P@…‚*Ñ Bö5ðÈG¾ÔD/Ù×À#ùR½ @GÒ„ìsEä#_FÒ„ìsEä#_FÒÄb´¶fÕâÈG¾Èùé$eAÐÚšU‹#ù"ç§“Éår%þÓV«•÷ד‡B!~_¯¾°°@x~};ò‘Ÿb¾ÅbáúþRUÕf³%þ)gÙɾ ‹UTTð !DUU³Ùl·Û9å·´´B|aóy¿¿’} f@…‚*P¶ d_9‡|ä‹À°!ûÊ9ä#_†-Hñ Bö¹"ò‘¯#ã„ìsEä#_GÆ/X1PeJAÈ~$‰|äë"S Bö#Iä#_™R°( BA ¨P@…‚*P¡ € T( ½ d_|äKMô‚} <ò‘/5Ñ t$MAÈ>WD>òe$MAÈ>WD>òe$MA,FkkV-Ž|䋜ŸNR­­Yµ8ò‘/r~:™\.Wâ?mµZ¿"4™L¡PÈl6sÊ_XX „ ùÂæ[,®ï/UUm6[â/‘ré‘ì b±XEE¡BTU5›Ív»S~KK !ùÈ6Ÿ÷û+Ù—`T( BA•a Bö•sÈG¾ [²¯œC>òE`Ø‚€Ô¿ dŸ+"ù:2~AÈ>WD>òu”ôB©D8ξ¾¾›7o†B¡Õ«W766îÙ³§¼¼œÇæ€.ñÖ[o9Žø?¯]»víÚµ¾¾¾sçΡ#$Âå#++«¹¹ùOú“Ãá8}ú´¶tôæÍ›o¿ý6Í%Bö#Iä#_\fEEEÚãòòò'Ÿ|òèÑ£„‰‰ ›K„ìG’ÈG¾.¸Ì âí ™ŸŸ×ÔÔÔðØpÂýSŒ©©©®®.BHaa¡v1È‚oA\½zõ‰'žðx<999/¿ü2¿ëX€ŽqñâÅÖÖÖ7nž:ujË–-ü¶<ð*ˆ>úhïÞ½sss•••]]]›7oæ´!à‡Ë§v»ýÈ‘#Ñh´¨¨èСC~¿ÿ³Ï>#„¬[·ŽÇ€.qþüùh4J™››{î¹çâÏoÞ¼ùõ×_ç±EàÁø×bÀŠq™Atvvòˆ€4à ¨D/Ù×À#ùR½ d_|äKMô‚IS²Ï‘|IS²Ï‘|IS‹ÑÚšU‹#ù"ç§“”AkkV-Ž|䋜ŸN&—Ë•øO[­V‡ÃÁ¯M&S(2›Íœò!ÈG¾°ù‹…ëûKUU›Í–øK¤œA@z$½Ô:‹ñ»ï‹ªªf³Ùn·sÊ×ni…|ä ›Ïûý•ìK¸\‹ ¬@ pýúõááaŸÏ7??¯Íêsss‹‹‹ëêêjkksssõ£@P)¼^¯Ó霜œTE;›  ƒÁ`ÐçóMOOG£ÑªªªÆÆÆââb‡*_$ùä“O®\¹‰Db±X$YöÇ´Ö?{öìúõ뛚š%ÓOÒ¶ b±×O•/K¾ßïïééñz½áp8‘ŸF£ÑhthhhfffÇŽyyy©ty¼?¬¶ e_9‡|&ù~¿ÿwÞñx< ¶C\8v»ÝgÏž« [R´1pAD£ÑÞÞÞ`0H;¦øŸ/ï¿ÿþÊ^n Æ/Ù¯ÒAþŠó/\¸àñxRy{G£QŸÏ×ßß¿â„ÿIðõׯ/AæºÈOs¾×ë½råJ²G· ‡Ãƒƒƒ>Ÿ/ÅÁ5Œ_™œN§vkõÔE"§ÓÉ$*uÇŽ³Ùl6›íÕW_?éñx´'Øn&''YD,›˜˜ƒLÒä’)aà#mäßž?::Êv ƒ¢(£££ —öLD¦„Q´‘¿lþÈÈÈâµ’©[XXa¸„°g" »P 2sŠ^¯—yf*ÆÆÆâgFnݺÅi+(0 «›óÌTtwwwwwóÞJ¦b@Fa{|Á/S|˜A€Y,æ:ð»‘ÔÊ´µµíß¿_{ìñxyl30 ÷tàtÕ–àP`@<îæ™wˆ@A€ÕÕÕ±="0›Íuuu e‚ª­­eµŒRFkkkÊ')Á€rss«ªªÆÇǙԄ¢(ÕÕÕ999©G¥®½½½½½}É“¥¥¥I}Eâ0ƒcbxÃ8EQ˜_% Ñ Â`× ?mùEEEëׯÏÎNuŽœ½aÃÚJa¯¡`Eô‚0Ø5ÈOg~SSSiii*óEQJJJî0}ö VD/€Seûöí¹¹¹+ëEQòòòvìØ‘É÷¶–æ¿\Þ¹.òuÌÏËËÛµkתU«’=ÖÈÎÎ.++{ôÑG\eÔc i Bê¹.òuÌÏËË{ä‘Gêëë³³³™ (Š¢wعsgâ«'z¬!åÇœ´ï`õ]È7X¾¢(÷Ýw߯ûûûÇÇÇ—|³VœÅb‰D"ÕÕÕ ©¬›äýûI') ‚ö[fõÛG¾!ó‹‹‹·mÛ GGGGFF¼^o …BÚws–””ÜsÏ=wß}wêëxÿ~ÒÉ”Ôú «Õêp8øn™L¦P(Äï²9íÿÈG¾°ù‹…ëûKUU›Í–øK¤9é—ô!F,«¨¨à1Bˆªªf³Ùn·sÊoii!„ ùÂæó~%ûÌ € T( 2lAHºòùÈŠa BÞ•ÈG¾8 [:ã„ìsEä#_GÆ/ÙçŠÈG¾Ž¤¼ “]¾|ùôéÓCCCn·;—••mܸqÏž=I­¡NñgóùçŸüñÇSSS@ ÏÌÌ|øá‡­­­CCCÌ·•)!û‘$ò‘W[[û /¼ûî».\8sæÌÚµk !¡P¨··—ùÀ2åCö#Iä#?®¡¡!~›Ì²²²æææßýîw„Ïe¦™RƉD¾üòËóçÏB zè!æ›@AH©¡¡Áëõjïºë®“'OÖÔÔ0ßJ¦œƒ0˜‚‚‚ø—˜ß¸qcß¾}ÃÃÃÌ·‚‚Ò|pñâE‡ÃÑÜÜLq»Ý'Ožd¾€ÄÊËË[[[µÇׯ_gžs’9xð`ccc}}}YYÙôôô‰'´ç«««™o  §ÓÙÓÓ³äÉüüü0ß @2­­­N§sllÌçó™ÍæÕ«WoÙ²åç?ÿ9f@8Àc²°,œ¤*Ñ B¨5ðÈG~šóu'zAµùÈOs¾îD/Б4!û\ùÈ—‘4!û\ùÈ—‘4±­­Yµ8ò‘/r~:IY´¶fÕâÈG¾Èùédr¹\‰ÿ´Õju8üŠÐd2…B!7ÆÑ,,,>7ÞA>ò™ä[,®ï/UU“º·­”3H¤—ZÇb±ŠŠ C!„¨ªj6›ív;§ü––Bò‘/l>ï÷W²/Á ¨P@…‚*Äì+ç|¶ d_9‡|ä‹À°©3~AÈ>WD>òudü‚}®ˆ|äëˆý=);ÖÙÙÿ§Ùl.//ÿîw¿ûôÓOWUU1ß@¦¹|ùòéÓ§‡††Ünw8.++Û¸qãž={’ZC î3ˆ………éééîîîÖÖÖ¯¾úŠ÷æ ïóÏ?ÿøã§¦¦@8ž™™ùðÃ[[[‡††˜o‹cA<öØcþóŸ_z饒’BÈìììßÿþw~›»3Ù$‘ü¸ÚÚÚ^xáÝwß½pá™3gÖ®]K …B½½½ÌƱ ÊËË7lØð“ŸüDûî@BÈ7ømîÎd?’D>òãüño~ó›eee›6mŠ¿¿x\fšŽïÅÈÊÊÒ”••¥as"‰|ùå—çÏŸ'„>ôÐCÌ7Á± ü~ÿìììØØØ_ÿúWBH~~þøC~›È( ^¯W{|×]w¸xñ¢ÃáÐÎA¸Ýî“'O2ß Ç‚hkk»|ùòÑ£G³²²æææžþù±±1~›È@ååå­­­Úãëׯ3Ïç;ƒ0›ÍÛ·oüñÇ !Á`ð¥—^âº9€LpðàÁ¿üå/ÃÃÃn·Ûår8qB{^Öo÷Þ¿ÿ{ï½÷ÕW_ýíoû÷¿ÿý­o}+ 0*§ÓÙÓÓ³äÉüü|_ùŽs%%%O=õ”öø·¿ým¶``­­­ßþö·W­Z••••››»víÚÇ{ìܹsV«•ù¶ØÏ ÚÛÛÛÛÛ—<¹wïÞ½{÷2ß@:pàɲŒ5'¬˜è!Ôxä#?Íùº½ „Z|ä§9_w¢èHš‚}®ˆ|äËHš‚}®ˆ|äËHš‚XŒÖÖ¬ZùÈ9?¤,Z[³jqä#_äüt2¹\®ÄÚjµ:~Eh2™B¡ãhŸï ùLò- ×÷—ªªIÝÛVʤGÒK­c±XEE¡BTU5›Ív»S~KK !ùÈ6Ÿ÷û+Ù—¤ãjN¶Àõëׇ‡‡}>ßüü¼6+ËÍÍ-..®«««­­ßfàvØ’"SAx½^§Ó999©(Šv4¨ ƒÁ`ÐçóMOOG£ÑªªªÆÆÆââb‡ Âþ³rD$ùä“O®\¹‰Db±X$YöÇ´¿úøøøÙ³gׯ_ßÔÔ¤(8ÉØVN‚‚ðûý===^¯7'òóÑh4 ÍÌÌìØ±#//Ǩb±×O­Ï*?3÷VD/H¿ßÿÎ;ïx<žÿºqápØívŸ={v~~žÇÀd_™—!ù»ÿ°"tAD£ÑÞÞÞ`0H›þÏ—÷ße/ÙaÿIÐqáÂǓʟ'ú|¾þþ~†£ZBö«€ œý'uâ„×ë½råJ²3ÃÛ…ÃáÁÁAŸÏÇdT·d.ü%°ÿ0Á¾ Ž;f³Ùl6Û«¯¾ÒãñhO644$˜ãt:£Ñ(“!E"§ÓÉ$ dý‡ Ag@`rr’Õ8‹MLLƒA&i >ì?¬Z£££l?‚Vett”aà>’—1û+‚ÄÈÈÈâµn©[XXa¸„Qä%ÍÇþà DžRcccñ#·[·n%õZç„âß•†‡ý‡ŽÑÝÝÝÝݽ²×òX˜g‚˜°ÿ°"è!Ûù!¿LöV8D[[›ë¿’ý”Èb±0¿h°ÿ°"è ‚Ç5ùœ®ºaÿaEЂàq5>®ðÏØX´ êêêØÎèÌfs]]Ã@öV-ˆÚÚZVËà4Ñh´¶¶–a ˆ û+ì?ælooooo_òdiiiR÷×ÏÍÍ­ªªgògV¥ºº:'''õ(öVABÞðKQ”Ä/cÀþĸQTT´~ýúììTç8ÙÙÙ6l a2Ø5È3Æþ£;q ‚ÒÔÔTZZšÊÿE)))¹Cýìä/f€ýGwB„¢(Û·oÏÍÍ]ÙßXQ”¼¼¼;vàÞÄ™ ûOêDÿ/ÏËËÛµkתU«’+fgg—••=úè£ ®o‘w.ü;0Ìþ£Ñ ‚’——÷È#Ô××ggg'Ò劢hÇ;wîL|õ›Ôsiäß1ö½Hð½„EQî»ï¾7ö÷÷/ùf¤8‹Å‰Dª««RY÷FûÎVße€ü4çlÿI'9 BS\\¼mÛ¶`08:::22âõz@(Ò¾[±¤¤äž{î¹ûî»Sÿ¼šöWdõ×E¾.ù†ÙÒÉ”Ôú%«Õêp8øn™L¦P(Äï²9íÿÈG¾°ù‹…ëûKUU›Í–øK$8zIú#‹UTTð !DUU³Ùl·Û9å·´´B|aóy¿¿’} f@…‚*P¶ $]ù‡|ä Ű!ïÊ?ä#_†-Hñ Bö¹"ò‘¯#ã„ìsEä#_GÆ/£šŸŸÿñl³Ùl6ÛSO=Åc(Y?~|jjŠë&2¥ d?’D>ò—p¹\o¾ù&ïïûÊ”‚ýHùÈ_,‰¼øâ‹‘Hä™gžá4$M¦€‘¼ñÆ_|ñÅÖ­[|ðA®BAHfrrò•W^ÉÏÏ?|ø0ïm¡ $säÈ‘@ ðì³ÏVVVòÞ @&Ÿ~ú©Ó鬪ªÚ´iÓàààÕ«Wµçý~ÿàà ×ëe»9™îI _ý5!dbbB»{MÜÀÀÀÎ;>¼k×.†›Ã ¨0ƒIccãâMÏÌÌÜÿý„-[¶tvv2ßf@…€Ä*++“úæŠdaT¢„€kà‘ü´åëNô‚m <ò‘ŸÎ|݉^ #i Bö¹"ò‘/#i Bö¹"ò‘/#i b1Z[³jqä#_äüt’² hmͪő|‘óÓÉ”Ô* «Õêp8ø¡Éd …Bf³™SþÂÂ!ùÈ6ßb±p}©ªj³ÙIÒ+)Wð âI©¨¨à÷ ²X,„çLùÈO1Ÿ÷û+YÉÍ x³Z­ÿøÇ?***8åk¿}ä#_ØüÙÙÙ¤þÏ›”ç =P@…‚*P¡ € T( BAîI©·Û}êÔ©ÁÁÁP(Déèèxøá‡õ06??ßÜÜ<55E¸Ýuš7„TU=sæŒÞ£îŽ?®µƒ¼P:(,,ܽ{÷½÷Þ;00ÐÕÕ¥÷p€ —Ëõæ›oæååÍÏÏë=–•Ã9¬Y³æàÁƒÛ¶m+//×{,ÀE$yñÅ#‘È3Ï<£÷XR‚‚`ï7Þøâ‹/¶nÝúàƒê=–”  ›œœ|å•Wòóó>¬÷XR…‚`ìÈ‘#@àÙgŸ­¬¬Ô{,©BA°ôé§Ÿ:ΪªªM›6 ^½zU{Þï÷z½^}‡—,|ŠÀÒ×_M™˜˜hiiYüüÀÀÀÎ;>¼k×.†¶(D£QŸÏG‰æ÷û=!¤´´TÏ‘ü(LOO?ðÀ‹Ÿéèèèèè „\ºt)''G§q‹oã833sÿý÷iWRâPa¡ƒ5kÖu¯`à§²²Rê¿5f@…‚*P¡ € T( BA ¨„[(e2™ø}ºÉd"ÿýŽfä#_Ì|¡Wü~û,“Ôë@€+œƒ*P¡ € T( BA ¨P@…‚*P¡ € T( BAÕaÀ.žÊþü<IEND®B`‚puzzles-20170606.272beef/icons/blackbox-48d8.png0000644000175000017500000000205713115373724017771 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEák Ö7IDATHÇÍ–KOAÇ—¿€'ÆèÉ<ã¥|j¤ÐÇn -¡ ¢\@úÚ(Û„ EÁh¼ ékwgf»}!ÏÏá´;»جíÍßaók·ÿLgÿ™™¥`ƒPç>‚¶)¤"ê¢D>“%¤’„”†¥I”Žç²Yžç9ÖÕ߇éwNM9‰M‡U“€("¥?eüÏà„µË鲃Ù̬_¶n ›Wˆ»‰o8|´«ã²±¬X8 Xè4À½¾Ûâ=à—vVn:+Ù¬¡±Úôê‘1²/ÔàŽFîµ¼i ìÅc?\PwÅ¢´/àI3.'ÆE³,M,”­‡«Ü0Ä7=ÞÁX1ŒÉï714†1¼ªä€PJïìÊì¬Dãïçß%Ñx•èêŠlsÑ♦ù,¾NŒ âÃ0ù7 á­CF|+Hì* $jWöpæbªK®Yù]è ášRûICÜQò´z„/ºgfD>ðmYƈî`q»Q Ý>Egs¤ó¼ J£µzˆˆªdt/ssZ„ò­¬¦s„Ä8Éü¡—\ ïö¡¡±v$d<µL êo‘s„¬tÏLnDé\‡Ì¾O¯¢kkD5WÓZxi«A¿Œl†ýìCê#d„º/ý2ÜÚ÷ö¶Ô|0z¤5¶±ñ¦]Ö^šö9¢q2Öp”+îj+žuà2ü‘¦t»·¡[J”Ö›­µiàfš%›%.(Hfˆò‹íaæcìÛ›EnK#Æ¡hVü‚+CW] ä”xMKꥈ`…~ÂçRÊPñìÒ¡w¡xÍc¾óc°"³=‚%»\âˆæcé,–Vã¼—<}’6W­þEÁC4ÞâÕT—´ÒZ%ÿ¥ð˜ Ü Z%tEXtdate:create2017-06-06T01:31:16+01:00m…%tEXtdate:modify2017-06-06T01:31:16+01:00À=¿IEND®B`‚puzzles-20170606.272beef/icons/blackbox-48d24.png0000644000175000017500000000205713115373724020047 0ustar simonsimon‰PNG  IHDR00ri¦[gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEák Ö7IDATHÇÍ–KOAÇ—¿€'ÆèÉ<ã¥|j¤ÐÇn -¡ ¢\@úÚ(Û„ EÁh¼ ékwgf»}!ÏÏá´;»جíÍßaók·ÿLgÿ™™¥`ƒPç>‚¶)¤"ê¢D>“%¤’„”†¥I”Žç²Yžç9ÖÕ߇éwNM9‰M‡U“€("¥?eüÏà„µË鲃Ù̬_¶n ›Wˆ»‰o8|´«ã²±¬X8 Xè4À½¾Ûâ=à—vVn:+Ù¬¡±Úôê‘1²/ÔàŽFîµ¼i ìÅc?\PwÅ¢´/àI3.'ÆE³,M,”­‡«Ü0Ä7=ÞÁX1ŒÉï714†1¼ªä€PJïìÊì¬Dãïçß%Ñx•èêŠlsÑ♦ù,¾NŒÔ77ž¼îêZS«¿4zQLä°œÞû\£ÞPZ‹6»±6~bx›²$%Wµéóá‹LÔÅ_1‚ÿ·É˜9È{±6›ñ˜Ô÷}ÊÚ”S’˜­%$†|42MÓ°N5½­·Ž‡€þIôÆRêŒmv¹~À&ôÐ$B^!v);ö|¶ÅlÓœ38D@†²/+0Ÿ~¾Bÿ œ…`Œç©O³%åi¹æ°BãywÙÒ®PàÏ.|/.°G†a˜ßÏÌkœŒó?¶º ƒ¢çðw_+|¸–AÈo2d—xþާä%tEXtdate:create2017-06-06T01:31:17+01:00Ëꎷ%tEXtdate:modify2017-06-06T01:31:17+01:00º·6 IEND®B`‚puzzles-20170606.272beef/icons/blackbox-32d4.png0000644000175000017500000000070413115373725017754 0ustar simonsimon‰PNG  IHDR V%(gAMA† 1è–_bKGDÿ‡Ì¿tIMEá æ—øIDAT8ËuS‰Ã0ÓèÍTóCërÎ]lˆ$dJý©¥8¥œg\èl]Ë)V§0äBß(‚Bgáо0ÈŠ-à hxFΦr qžW87d“¨$–Ç/ÂÍšÁ(@.§0(Xˆ.¬C² 0UxT_†Q¬6>Èéþ¶AbJ¾ Û‰pZ5Ä!¦S>Q, ~4…É<èûž>Ôœ¾4ôuÿ›ÙyÝ#–‘!rý¾ÍB¢ÑÔtEãúŠ.—þ.FÈ&Þ!ù¹½YR¿Vý›¹?¡¡Œƒ­| ¼ÙZõ˜Sí|¦ã{QZs%tEXtdate:create2017-06-06T01:31:17+01:00Ëꎷ%tEXtdate:modify2017-06-06T01:31:17+01:00º·6 IEND®B`‚puzzles-20170606.272beef/icons/blackbox-32d24.png0000644000175000017500000000147213115373725020041 0ustar simonsimon‰PNG  IHDR V%(gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá æ—BIDAT8Ëu“_kÓPÆ#›ŸB?^y3¼?€Ž5M ëæ¡ÿÒ–þIÓ5ÕuÕµ°Ê®¿‚·êÅ\Òœ$çœ$ÝF[õƒxΛS­oB~„<<ç<<'!„ÂÕ#‚]6ž‹á/ƒ pH×s|œ-)J¾ÝË•”R^?´1ø„Ú¶Ä´œÞÎ7’Å x:|¤^Q]ÚÍì¦KšÌQV¥HðãíÝW3ÒNev2²Ò”8Ê*@‰ö0=­Ô¼`É¡sN'd¢mI/Rb®ž%Y,TE†dÔ77ž¼îêZS«¿4zQLä°œÞû\£ÞPZ‹6»±6~bx›²$%Wµéóá‹LÔÅ_1‚ÿ·É˜9È{±6›ñ˜Ô÷}ÊÚ”S’˜­%$†|42MÓ°N5½­·Ž‡€þIôÆRêŒmv¹~À&ôÐ$B^!v);ö|¶ÅlÓœ38D@†²/+0Ÿ~¾Bÿ œ…`Œç©O³%åi¹æ°BãywÙÒ®PàÏ.|/.°G†a˜ßÏÌkœŒó?¶º ƒ¢çðw_+|¸–AÈo2d—xþާä%tEXtdate:create2017-06-06T01:31:17+01:00Ëꎷ%tEXtdate:modify2017-06-06T01:31:17+01:00º·6 IEND®B`‚puzzles-20170606.272beef/icons/blackbox-16d8.png0000644000175000017500000000077113115373725017766 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá æ—IDATÓ-ÍNÂ@…ïÎWpá+ø¾‰iŒPh+ÁØ?:m šbâ+¸Ò˜j©.t‹ W”™é S°ˆâxrïæË9'9 …cœããIP2_dNÐúdúgäºvû¦é'žÞŒÌºÏ`¾¸›d†Ý ¬V¯m† [ÿ¼´÷Q÷²8:®ßï·`74Žº­&ÁHE®n¶Ý†Y:v¨B,³½-vƒ˜¸CJÐ2õ‚Á©ãûv«¤f:ÃÂŽ#ó¢zÐêÇö¡N–Ò)ýxLÒô)?gã$jYU¥Z}•ìõ{”œáÆÏXm€¤,ÏÎò™ø‚ý }¿Ø¥ÒY4¬l%tEXtdate:create2017-06-06T01:31:17+01:00Ëꎷ%tEXtdate:modify2017-06-06T01:31:17+01:00º·6 IEND®B`‚puzzles-20170606.272beef/icons/blackbox-16d4.png0000644000175000017500000000045013115373725017754 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA† 1è–_bKGDÿ‡Ì¿tIMEá æ—\IDATÓ]Ž À0B9ºGãf ÑeíÚÄÏ * )¾Á]Ô÷·'QD×ðâš1h Å‚b!dÀì@Ýà>+qsÅýÏX¬5L†¾¬Lf?·O.ƺN§S|63¥àäÞ5t%tEXtdate:create2017-06-06T01:31:17+01:00Ëꎷ%tEXtdate:modify2017-06-06T01:31:17+01:00º·6 IEND®B`‚puzzles-20170606.272beef/icons/blackbox-16d24.png0000644000175000017500000000077113115373725020044 0ustar simonsimon‰PNG  IHDR:˜ ½gAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<bKGDÿ‡Ì¿tIMEá æ—IDATÓ-ÍNÂ@…ïÎWpá+ø¾‰iŒPh+ÁØ?:m šbâ+¸Ò˜j©.t‹ W”™é S°ˆâxrïæË9'9 …cœããIP2_dNÐúdúgäºvû¦é'žÞŒÌºÏ`¾¸›d†Ý ¬V¯m† [ÿ¼´÷Q÷²8:®ßï·`74Žº­&ÁHE®n¶Ý†Y:v¨B,³½-vƒ˜¸CJÐ2õ‚Á©ãûv«¤f:ÃÂŽ#ó¢zÐêÇö¡N–Ò)ýxLÒô)?gã$jYU¥Z}•ìõ{”œáÆÏXm€¤,ÏÎò™ø‚ý }¿Ø¥ÒY4¬l%tEXtdate:create2017-06-06T01:31:17+01:00Ëꎷ%tEXtdate:modify2017-06-06T01:31:17+01:00º·6 IEND®B`‚puzzles-20170606.272beef/icons/win16pal.xpm0000644000175000017500000000056013115373615017174 0ustar simonsimon/* XPM */ static char *win16pal[] = { /* columns rows colors chars-per-pixel */ "16 1 16 1", " c #000000", ". c #800000", "X c #008000", "o c #808000", "O c #000080", "+ c #800080", "@ c #008080", "# c #C0C0C0", "$ c #808080", "% c #FF0000", "& c #00FF00", "* c #FFFF00", "= c #0000FF", "- c #FF00FF", "; c #00FFFF", ": c #FFFFFF", /* pixels */ " .XoO+@#$%&*=-;:" }; puzzles-20170606.272beef/icons/screenshot.sh0000755000175000017500000000121213115373615017514 0ustar simonsimon#!/bin/sh # Generate a screenshot from a puzzle save file. Takes the # following arguments, in order: # # - the name of the puzzle binary # - the name of the save file # - the name of the output image file # - (optionally) the proportion of the next move to redo before # taking the screenshot. # # This script requires access to an X server in order to run, but # seems to work fine under xvfb-run if you haven't got a real one # available (or if you don't want to use it for some reason). binary="$1" save="$2" image="$3" if test "x$4" != "x"; then redo="--redo $4" else redo= fi "$binary" $redo --screenshot "$image" --load "$save" puzzles-20170606.272beef/icons/crop.sh0000755000175000017500000000222513115373615016307 0ustar simonsimon#!/bin/sh # Crop one image into another, after first checking that the source # image has the expected size in pixels. # # This is used in the Puzzles icon build scripts to construct icons # which are zoomed in on a particular sub-area of the puzzle's # basic screenshot. This way I can define crop areas in pixels, # while not having to worry too much that if I adjust the source # puzzle so as to alter the layout the crop area might start # hitting the wrong bit of picture. Most layout changes I can # conveniently imagine will also alter the overall image size, so # this script will give a build error and alert me to the fact that # I need to fiddle with the icon makefile. infile="$1" outfile="$2" insize="$3" crop="$4" # Special case: if no input size or crop parameter was specified at # all, we just copy the input to the output file. if test $# -lt 3; then cp "$infile" "$outfile" exit 0 fi # Check the input image size. realsize=`identify -format %wx%h "$infile"` if test "x$insize" != "x$realsize"; then echo "crop.sh: '$infile' has wrong initial size: $realsize != $insize" >&2 exit 1 fi # And crop. convert -crop "$crop" "$infile" "$outfile" puzzles-20170606.272beef/icons/square.pl0000755000175000017500000000611513115373615016647 0ustar simonsimon#!/usr/bin/perl # Read an input image, crop its border to a standard width, and # convert it into a square output image. Parameters are: # # - the required total image size # - the output border thickness # - the input image file name # - the output image file name. ($osize, $oborder, $infile, $outfile) = @ARGV; # Determine the input image's size. $ident = `identify -format "%w %h" $infile`; $ident =~ /(\d+) (\d+)/ or die "unable to get size for $infile\n"; ($w, $h) = ($1, $2); # Read the input image data. $data = []; open IDATA, "convert -depth 8 $infile rgb:- |"; push @$data, $rgb while (read IDATA,$rgb,3,0) == 3; close IDATA; # Check we have the right amount of data. $xl = $w * $h; $al = scalar @$data; die "wrong amount of image data ($al, expected $xl) from $infile\n" unless $al == $xl; # Find the background colour, by looking around the entire border # and finding the most popular pixel colour. for ($i = 0; $i < $w; $i++) { $pcount{$data->[$i]}++; # top row $pcount{$data->[($h-1)*$w+$i]}++; # bottom row } for ($i = 1; $i < $h-1; $i++) { $pcount{$data->[$i*$w]}++; # left column $pcount{$data->[$i*$w+$w-1]}++; # right column } @plist = sort { $pcount{$b} <=> $pcount{$a} } keys %pcount; $back = $plist[0]; # Crop rows and columns off the image to find the central rectangle # of non-background stuff. $ystart = 0; $ystart++ while $ystart < $h and scalar(grep { $_ ne $back } map { $data->[$ystart*$w+$_] } 0 .. ($w-1)) == 0; $yend = $h-1; $yend-- while $yend >= $ystart and scalar(grep { $_ ne $back } map { $data->[$yend*$w+$_] } 0 .. ($w-1)) == 0; $xstart = 0; $xstart++ while $xstart < $w and scalar(grep { $_ ne $back } map { $data->[$_*$w+$xstart] } 0 .. ($h-1)) == 0; $xend = $w-1; $xend-- while $xend >= $xstart and scalar(grep { $_ ne $back } map { $data->[$_*$w+$xend] } 0 .. ($h-1)) == 0; # Decide how much border we're going to put back on to make the # image perfectly square. $hexpand = ($yend-$ystart) - ($xend-$xstart); if ($hexpand > 0) { $left = int($hexpand / 2); $xstart -= $left; $xend += $hexpand - $left; } elsif ($hexpand < 0) { $vexpand = -$hexpand; $top = int($vexpand / 2); $ystart -= $top; $yend += $vexpand - $top; } $ow = $xend - $xstart + 1; $oh = $yend - $ystart + 1; die "internal computation problem" if $ow != $oh; # should be square # And decide how much _more_ border goes on to add the bit around # the edge. $realow = int($ow * ($osize / ($osize - 2*$oborder))); $extra = $realow - $ow; $left = int($extra / 2); $xstart -= $left; $xend += $extra - $left; $top = int($extra / 2); $ystart -= $top; $yend += $extra - $top; $ow = $xend - $xstart + 1; $oh = $yend - $ystart + 1; die "internal computation problem" if $ow != $oh; # should be square # Now write out the resulting image, and resize it appropriately. open IDATA, "| convert -size ${ow}x${oh} -depth 8 -resize ${osize}x${osize}! rgb:- $outfile"; for ($y = $ystart; $y <= $yend; $y++) { for ($x = $xstart; $x <= $xend; $x++) { if ($x >= 0 && $x < $w && $y >= 0 && $y < $h) { print IDATA $data->[$y*$w+$x]; } else { print IDATA $back; } } } close IDATA; puzzles-20170606.272beef/icons/icon.pl0000755000175000017500000002075413115373615016304 0ustar simonsimon#!/usr/bin/perl # Take a collection of input image files and convert them into a # multi-resolution Windows .ICO icon file. # # The input images can be treated as having four different colour # depths: # # - 24-bit true colour # - 8-bit with custom palette # - 4-bit using the Windows 16-colour palette (see comment below # for details) # - 1-bit using black and white only. # # The images can be supplied in any input format acceptable to # ImageMagick, but their actual colour usage must already be # appropriate for the specified mode; this script will not do any # substantive conversion. So if an image intended to be used in 4- # or 1-bit mode contains any colour not in the appropriate fixed # palette, that's a fatal error; if an image to be used in 8-bit # mode contains more than 256 distinct colours, that's also a fatal # error. # # Command-line syntax is: # # icon.pl -depth imagefile [imagefile...] [-depth imagefile [imagefile...]] # # where `-depth' is one of `-24', `-8', `-4' or `-1', and tells the # script how to treat all the image files given after that option # until the next depth option. For example, you might execute # # icon.pl -24 48x48x24.png 32x32x24.png -8 32x32x8.png -1 monochrome.png # # to build an icon file containing two differently sized 24-bit # images, one 8-bit image and one black and white image. # # Windows .ICO files support a 1-bit alpha channel on all these # image types. That is, any pixel can be either opaque or fully # transparent, but not partially transparent. The alpha channel is # separate from the main image data, meaning that `transparent' is # not required to take up a palette entry. (So an 8-bit image can # have 256 distinct _opaque_ colours, plus transparent pixels as # well.) If the input images have alpha channels, they will be used # to determine which pixels of the icon are transparent, by simple # quantisation half way up (e.g. in a PNG image with an 8-bit alpha # channel, alpha values of 00-7F will be mapped to transparent # pixels, and 80-FF will become opaque). # The Windows 16-colour palette consists of: # - the eight corners of the colour cube (000000, 0000FF, 00FF00, # 00FFFF, FF0000, FF00FF, FFFF00, FFFFFF) # - dim versions of the seven non-black corners, at 128/255 of the # brightness (000080, 008000, 008080, 800000, 800080, 808000, # 808080) # - light grey at 192/255 of full brightness (C0C0C0). %win16pal = ( "\x00\x00\x00\x00" => 0, "\x00\x00\x80\x00" => 1, "\x00\x80\x00\x00" => 2, "\x00\x80\x80\x00" => 3, "\x80\x00\x00\x00" => 4, "\x80\x00\x80\x00" => 5, "\x80\x80\x00\x00" => 6, "\xC0\xC0\xC0\x00" => 7, "\x80\x80\x80\x00" => 8, "\x00\x00\xFF\x00" => 9, "\x00\xFF\x00\x00" => 10, "\x00\xFF\xFF\x00" => 11, "\xFF\x00\x00\x00" => 12, "\xFF\x00\xFF\x00" => 13, "\xFF\xFF\x00\x00" => 14, "\xFF\xFF\xFF\x00" => 15, ); @win16pal = sort { $win16pal{$a} <=> $win16pal{$b} } keys %win16pal; # The black and white palette consists of black (000000) and white # (FFFFFF), obviously. %win2pal = ( "\x00\x00\x00\x00" => 0, "\xFF\xFF\xFF\x00" => 1, ); @win2pal = sort { $win16pal{$a} <=> $win2pal{$b} } keys %win2pal; @hdr = (); @dat = (); $depth = undef; foreach $_ (@ARGV) { if (/^-(24|8|4|1)$/) { $depth = $1; } elsif (defined $depth) { &readicon($_, $depth); } else { $usage = 1; } } if ($usage || length @hdr == 0) { print "usage: icon.pl ( -24 | -8 | -4 | -1 ) image [image...]\n"; print " [ ( -24 | -8 | -4 | -1 ) image [image...] ...]\n"; exit 0; } # Now write out the output icon file. print pack "vvv", 0, 1, scalar @hdr; # file-level header $filepos = 6 + 16 * scalar @hdr; for ($i = 0; $i < scalar @hdr; $i++) { print $hdr[$i]; print pack "V", $filepos; $filepos += length($dat[$i]); } for ($i = 0; $i < scalar @hdr; $i++) { print $dat[$i]; } sub readicon { my $filename = shift @_; my $depth = shift @_; my $pix; my $i; my %pal; # Determine the icon's width and height. my $w = `identify -format %w $filename`; my $h = `identify -format %h $filename`; # Read the file in as RGBA data. We flip vertically at this # point, to avoid having to do it ourselves (.BMP and hence # .ICO are bottom-up). my $data = []; open IDATA, "convert -set colorspace sRGB -flip -depth 8 $filename rgba:- |"; push @$data, $rgb while (read IDATA,$rgb,4,0) == 4; close IDATA; # Check we have the right amount of data. $xl = $w * $h; $al = scalar @$data; die "wrong amount of image data ($al, expected $xl) from $filename\n" unless $al == $xl; # Build the alpha channel now, so we can exclude transparent # pixels from the palette analysis. We replace transparent # pixels with undef in the data array. # # We quantise the alpha channel half way up, so that alpha of # 0x80 or more is taken to be fully opaque and 0x7F or less is # fully transparent. Nasty, but the best we can do without # dithering (and don't even suggest we do that!). my $x; my $y; my $alpha = ""; for ($y = 0; $y < $h; $y++) { my $currbyte = 0, $currbits = 0; for ($x = 0; $x < (($w+31)|31)-31; $x++) { $pix = ($x < $w ? $data->[$y*$w+$x] : "\x00\x00\x00\xFF"); my @rgba = unpack "CCCC", $pix; $currbyte <<= 1; $currbits++; if ($rgba[3] < 0x80) { if ($x < $w) { $data->[$y*$w+$x] = undef; } $currbyte |= 1; # MS has the alpha channel inverted :-) } else { # Might as well flip RGBA into BGR0 while we're here. if ($x < $w) { $data->[$y*$w+$x] = pack "CCCC", $rgba[2], $rgba[1], $rgba[0], 0; } } if ($currbits >= 8) { $alpha .= pack "C", $currbyte; $currbits -= 8; } } } # For an 8-bit image, check we have at most 256 distinct # colours, and build the palette. %pal = (); if ($depth == 8) { my $palindex = 0; foreach $pix (@$data) { next unless defined $pix; $pal{$pix} = $palindex++ unless defined $pal{$pix}; } die "too many colours in 8-bit image $filename\n" unless $palindex <= 256; } elsif ($depth == 4) { %pal = %win16pal; } elsif ($depth == 1) { %pal = %win2pal; } my $raster = ""; if ($depth < 24) { # For a non-24-bit image, flatten the image into one palette # index per pixel. $pad = 32 / $depth; # number of pixels to pad scanline to 4-byte align $pmask = $pad-1; for ($y = 0; $y < $h; $y++) { my $currbyte = 0, $currbits = 0; for ($x = 0; $x < (($w+$pmask)|$pmask)-$pmask; $x++) { $currbyte <<= $depth; $currbits += $depth; if ($x < $w && defined ($pix = $data->[$y*$w+$x])) { if (!defined $pal{$pix}) { my $pixprintable = unpack "H*", $pix; die "illegal colour value $pixprintable at pixel ($x,$y) in $filename\n"; } $currbyte |= $pal{$pix}; } if ($currbits >= 8) { $raster .= pack "C", $currbyte; $currbits -= 8; } } } } else { # For a 24-bit image, reverse the order of the R,G,B values # and stick a padding zero on the end. # # (In this loop we don't need to bother padding the # scanline out to a multiple of four bytes, because every # pixel takes four whole bytes anyway.) for ($i = 0; $i < scalar @$data; $i++) { if (defined $data->[$i]) { $raster .= $data->[$i]; } else { $raster .= "\x00\x00\x00\x00"; } } $depth = 32; # and adjust this } # Prepare the icon data. First the header... my $data = pack "VVVvvVVVVVV", 40, # size of bitmap info header $w, # icon width $h*2, # icon height (x2 to indicate the subsequent alpha channel) 1, # 1 plane (common to all MS image formats) $depth, # bits per pixel 0, # no compression length $raster, # image size 0, 0, 0, 0; # resolution, colours used, colours important (ignored) # ... then the palette ... if ($depth <= 8) { my $ncols = (1 << $depth); my $palette = "\x00\x00\x00\x00" x $ncols; foreach $i (keys %pal) { substr($palette, $pal{$i}*4, 4) = $i; } $data .= $palette; } # ... the raster data we already had ready ... $data .= $raster; # ... and the alpha channel we already had as well. $data .= $alpha; # Prepare the header which will represent this image in the # icon file. my $header = pack "CCCCvvV", $w, $h, # width and height (this time the real height) 1 << $depth, # number of colours, if less than 256 0, # reserved 1, # planes $depth, # bits per pixel length $data; # size of real icon data push @hdr, $header; push @dat, $data; } puzzles-20170606.272beef/icons/cicon.pl0000755000175000017500000000153513115373615016443 0ustar simonsimon#!/usr/bin/perl # Given a list of input PNGs, create a C source file file # containing a const array of XPMs, under the name `xpm_icon'. $k = 0; @xpms = (); foreach $f (@ARGV) { # XPM format is generated directly by ImageMagick, so that's easy # enough. We just have to adjust the declaration line so that it # has the right name, linkage and storage class. @lines = (); open XPM, "convert $f xpm:- |"; push @lines, $_ while ; close XPM; die "XPM from $f in unexpected format\n" unless $lines[1] =~ /^static.*\{$/; $lines[1] = "static const char *const xpm_icon_$k"."[] = {\n"; $k++; push @xpms, @lines, "\n"; } # Now output. foreach $line (@xpms) { print $line; } print "const char *const *const xpm_icons[] = {\n"; for ($i = 0; $i < $k; $i++) { print " xpm_icon_$i,\n"; } print "};\n"; print "const int n_xpm_icons = $k;\n"; puzzles-20170606.272beef/icons/untangle.sav0000644000175000017500000000112013115373615017326 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :8:Untangle PARAMS :2:10 CPARAMS :2:10 SEED :15:761628688787632 DESC :63:0-1,0-5,0-8,0-9,1-4,1-8,2-6,2-7,3-5,3-6,3-9,4-5,4-7,5-7,6-7,8-9 AUXINFO :182:01bee8258e3164fe966f294b2837b6584b965b8d8e97571ba48f26c9bc0a91ac4b49fb4652bfaa5c340c82c57afbaa4620f2f6d49d7a7b330a66594d2b88c499d57c4093379b7dc322f2afa1ebab81004585751c39c19f8f9930c4 NSTATES :1:7 STATEPOS:1:6 MOVE :12:P8:168,16/64 MOVE :12:P0:186,85/64 MOVE :12:P2:47,254/64 MOVE :13:P5:131,153/64 MOVE :12:P3:75,126/64 MOVE :12:P7:93,303/64 puzzles-20170606.272beef/icons/unruly.sav0000644000175000017500000000064613115373615017063 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :6:Unruly PARAMS :5:6x6de CPARAMS :5:6x6de DESC :10:faCADAJeBd NSTATES :2:15 STATEPOS:2:15 MOVE :6:P0,1,2 MOVE :6:P0,4,2 MOVE :6:P0,3,3 MOVE :6:P0,3,0 MOVE :6:P0,5,1 MOVE :6:P0,2,1 MOVE :6:P1,4,0 MOVE :6:P1,1,1 MOVE :6:P1,5,2 MOVE :6:P0,0,2 MOVE :6:P1,0,3 MOVE :6:P1,0,0 MOVE :6:P1,0,4 MOVE :6:P0,2,4 puzzles-20170606.272beef/icons/unequal.sav0000644000175000017500000000103213115373615017165 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :7:Unequal PARAMS :3:4de CPARAMS :3:4de SEED :15:143029490219212 DESC :37:0D,0,0L,0,0,0,0,0,0D,0U,0R,0,0,0,0,4, AUXINFO :34:f51274dc41e0a39caa38942fc525ed0108 NSTATES :2:16 STATEPOS:1:6 MOVE :6:R2,1,4 MOVE :6:R1,2,4 MOVE :6:R0,0,4 MOVE :6:R2,3,1 MOVE :6:R3,2,1 MOVE :6:R0,2,3 MOVE :6:R2,2,2 MOVE :6:R0,3,2 MOVE :6:R1,3,3 MOVE :6:R0,1,1 MOVE :6:R1,1,2 MOVE :6:R3,1,3 MOVE :6:R3,0,2 MOVE :6:R2,0,3 MOVE :6:R1,0,1 puzzles-20170606.272beef/icons/undead.sav0000644000175000017500000000044413115373615016761 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :6:Undead PARAMS :6:4x4de2 CPARAMS :6:4x4de2 DESC :48:5,2,2,aRLgLLaLRL,2,0,1,2,1,1,2,5,0,0,0,2,1,3,1,1 NSTATES :1:7 STATEPOS:1:7 MOVE :2:G0 MOVE :2:V0 MOVE :2:G2 MOVE :2:G3 MOVE :2:V3 MOVE :2:Z3 puzzles-20170606.272beef/icons/twiddle.sav0000644000175000017500000000125713115373615017160 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :7:Twiddle PARAMS :5:3x3n2 CPARAMS :5:3x3n2 SEED :15:635499951462226 DESC :17:3,7,2,6,5,1,8,4,9 NSTATES :2:27 STATEPOS:2:22 MOVE :7:M0,0,-1 MOVE :7:M1,0,-1 MOVE :6:M1,1,1 MOVE :6:M0,1,1 MOVE :6:M0,0,1 MOVE :6:M0,0,1 MOVE :7:M1,1,-1 MOVE :7:M0,1,-1 MOVE :7:M0,1,-1 MOVE :7:M1,1,-1 MOVE :6:M0,1,1 MOVE :7:M0,1,-1 MOVE :6:M1,1,1 MOVE :6:M1,1,1 MOVE :6:M0,1,1 MOVE :6:M0,1,1 MOVE :7:M0,1,-1 MOVE :7:M1,1,-1 MOVE :7:M0,1,-1 MOVE :7:M1,1,-1 MOVE :6:M0,1,1 MOVE :7:M1,0,-1 MOVE :7:M0,1,-1 MOVE :6:M1,0,1 MOVE :6:M1,1,1 MOVE :6:M1,1,1 puzzles-20170606.272beef/icons/tracks.sav0000644000175000017500000000126713115373615017014 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :12:Train Tracks PARAMS :5:6x6dt CPARAMS :5:6x6dt SEED :15:145870397370785 DESC :31:l6t9b,3,2,1,S4,5,4,2,6,S3,2,3,3 NSTATES :2:23 STATEPOS:2:20 MOVE :5:TD0,0 MOVE :5:TR0,0 MOVE :5:TL5,5 MOVE :5:TU5,5 MOVE :29:TS1,1;TS2,1;TS3,1;TS4,1;TS5,1 MOVE :29:NS2,0;NS2,2;NS2,3;NS2,4;NS2,5 MOVE :5:TU1,1 MOVE :17:NS0,3;NS0,4;NS0,5 MOVE :23:NS1,2;NS1,3;NS1,4;NS1,5 MOVE :5:TL2,1 MOVE :5:TL3,1 MOVE :5:TS4,4 MOVE :5:TS3,4 MOVE :17:NS3,0;NS4,0;NS5,0 MOVE :5:TS4,2 MOVE :5:TS4,3 MOVE :5:TU3,4 MOVE :5:TL4,4 MOVE :5:TL5,1 MOVE :5:TU5,2 MOVE :5:NS5,3 MOVE :5:NS3,2 puzzles-20170606.272beef/icons/towers.sav0000644000175000017500000000104613115373615017043 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :6:Towers PARAMS :3:4de CPARAMS :3:4de SEED :15:888431554483015 DESC :31:2/2/1/3/2/2/3/1/3/1/2/2/2/3/2/1 AUXINFO :34:297d7a2fcf9e14403a74c976fe0fefd306 NSTATES :2:17 STATEPOS:2:10 MOVE :6:R2,0,4 MOVE :6:R0,1,4 MOVE :6:R3,3,4 MOVE :6:R1,2,4 MOVE :6:R0,3,3 MOVE :6:R1,0,3 MOVE :6:R3,2,3 MOVE :6:R2,1,3 MOVE :6:R3,0,2 MOVE :6:R3,1,1 MOVE :6:R1,1,2 MOVE :6:R1,3,1 MOVE :6:R2,3,2 MOVE :6:R2,2,1 MOVE :6:R0,2,2 MOVE :6:R0,0,1 puzzles-20170606.272beef/icons/tents.sav0000644000175000017500000000121313115373615016651 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :5:Tents PARAMS :5:8x8de CPARAMS :5:8x8de DESC :45:ea_ddidfaabkd,3,0,2,1,2,2,1,1,3,1,1,1,1,1,3,1 NSTATES :2:25 STATEPOS:2:25 MOVE :9:N5,6;N6,6 MOVE :14:N5,7;N6,7;N7,7 MOVE :9:N0,7;N1,7 MOVE :4:N1,6 MOVE :14:N6,2;N6,3;N6,4 MOVE :9:N7,2;N7,3 MOVE :14:N1,0;N2,0;N3,0 MOVE :4:N3,1 MOVE :4:N0,3 MOVE :4:N3,4 MOVE :4:N5,4 MOVE :4:T6,0 MOVE :4:T4,0 MOVE :4:T0,0 MOVE :4:N1,1 MOVE :4:N4,1 MOVE :9:N6,1;N7,1 MOVE :4:T2,1 MOVE :9:N1,2;N3,2 MOVE :4:T5,2 MOVE :4:N4,2 MOVE :4:N5,3 MOVE :4:N0,2 MOVE :9:N1,3;N1,5 puzzles-20170606.272beef/icons/solo.sav0000644000175000017500000000133313115373615016473 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :4:Solo PARAMS :3:3x3 CPARAMS :3:3x3 DESC :73:a2e9a5b6a2b3_7a1_4a9_6a2b4_1a7_2b1_7e6_9b2_5a8_1b6a5_9a3_8a7_2b8a6b1a1e4a NSTATES :2:29 STATEPOS:2:29 MOVE :6:R7,1,1 MOVE :6:R4,6,1 MOVE :6:R5,0,1 MOVE :6:R0,0,4 MOVE :6:R2,0,6 MOVE :6:R1,2,3 MOVE :6:R0,3,9 MOVE :6:R1,3,5 MOVE :6:R2,4,8 MOVE :6:R0,5,3 MOVE :6:R1,5,6 MOVE :6:R1,6,4 MOVE :6:R4,7,4 MOVE :6:R7,6,2 MOVE :6:R7,7,5 MOVE :6:R8,8,6 MOVE :6:R7,3,3 MOVE :6:R8,3,7 MOVE :6:R8,3,8 MOVE :6:R6,4,5 MOVE :6:R7,5,7 MOVE :6:R8,5,4 MOVE :6:R7,2,8 MOVE :6:R8,0,5 MOVE :6:R4,2,5 MOVE :6:R4,3,6 MOVE :6:R5,4,4 MOVE :6:R4,5,9 puzzles-20170606.272beef/icons/slant.sav0000644000175000017500000000157613115373615016651 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :5:Slant PARAMS :5:8x8de CPARAMS :5:8x8de DESC :47:a10h23a32a02b22e3a2c1g3a20d32a0c221a210i0a101b0 NSTATES :2:44 STATEPOS:2:44 MOVE :4:/7,0 MOVE :4:\7,1 MOVE :4:\1,0 MOVE :4:/2,0 MOVE :4:\0,4 MOVE :4:/0,5 MOVE :4:\0,6 MOVE :4:/0,7 MOVE :4:\1,7 MOVE :4:/7,7 MOVE :4:/3,7 MOVE :4:\4,7 MOVE :4:\5,7 MOVE :4:/2,7 MOVE :4:/7,4 MOVE :4:\7,5 MOVE :4:\7,3 MOVE :4:\7,2 MOVE :4:/6,2 MOVE :4:\6,3 MOVE :4:\7,6 MOVE :4:/3,0 MOVE :4:/2,1 MOVE :4:\3,1 MOVE :4:/2,2 MOVE :4:\3,2 MOVE :4:/2,3 MOVE :4:\3,3 MOVE :4:\1,1 MOVE :4:/0,1 MOVE :4:\0,2 MOVE :4:\1,2 MOVE :4:\1,3 MOVE :4:/0,3 MOVE :4:\1,4 MOVE :4:\0,0 MOVE :4:\5,3 MOVE :4:\6,4 MOVE :4:/5,4 MOVE :4:/5,5 MOVE :4:\6,5 MOVE :4:/4,5 MOVE :4:\4,6 puzzles-20170606.272beef/icons/sixteen.sav0000644000175000017500000000131413115373615017175 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :7:Sixteen PARAMS :3:4x4 CPARAMS :3:4x4 SEED :15:601798566229573 DESC :38:2,16,3,10,13,8,7,4,9,14,12,11,15,1,5,6 NSTATES :2:31 STATEPOS:2:24 MOVE :5:C3,-1 MOVE :4:R0,1 MOVE :4:C1,1 MOVE :5:R0,-1 MOVE :5:C1,-1 MOVE :5:C3,-1 MOVE :4:R2,1 MOVE :4:R2,1 MOVE :4:C3,1 MOVE :5:C2,-1 MOVE :5:C2,-1 MOVE :4:R1,1 MOVE :4:R1,1 MOVE :4:C2,1 MOVE :4:C2,1 MOVE :4:R3,1 MOVE :4:R3,1 MOVE :4:C1,1 MOVE :5:R2,-1 MOVE :5:R2,-1 MOVE :5:C1,-1 MOVE :4:R2,1 MOVE :4:C0,1 MOVE :4:R3,1 MOVE :5:R2,-1 MOVE :5:C1,-1 MOVE :4:R2,1 MOVE :4:C1,1 MOVE :5:R3,-1 MOVE :5:C0,-1 puzzles-20170606.272beef/icons/singles.sav0000644000175000017500000000144113115373615017163 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :7:Singles PARAMS :5:6x6dk CPARAMS :5:6x6dk SEED :15:781273601054598 DESC :36:361566412253452144234115163346553461 NSTATES :2:37 STATEPOS:2:22 MOVE :4:B1,0 MOVE :4:C0,0 MOVE :4:C1,1 MOVE :4:C2,0 MOVE :4:C0,1 MOVE :4:B0,2 MOVE :4:C0,3 MOVE :4:C1,2 MOVE :4:C4,3 MOVE :4:B3,3 MOVE :4:C3,2 MOVE :4:C2,3 MOVE :4:C3,4 MOVE :4:B2,4 MOVE :4:C1,4 MOVE :4:C2,5 MOVE :4:B1,5 MOVE :4:C0,5 MOVE :4:C0,4 MOVE :4:C1,3 MOVE :4:C3,5 MOVE :4:B5,4 MOVE :4:C4,4 MOVE :4:C5,5 MOVE :4:C5,3 MOVE :4:C4,5 MOVE :4:B4,0 MOVE :4:C3,0 MOVE :4:C4,1 MOVE :4:C5,0 MOVE :4:C5,1 MOVE :4:B4,2 MOVE :4:C5,2 MOVE :4:C3,1 MOVE :4:B2,1 MOVE :4:C2,2 puzzles-20170606.272beef/icons/signpost.sav0000644000175000017500000000074713115373615017375 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :8:Signpost PARAMS :4:4x4c CPARAMS :4:4x4c SEED :15:230468784719861 DESC :19:1eceebecfbfhgcaa16a NSTATES :2:15 STATEPOS:2:11 MOVE :8:L2,1-3,1 MOVE :8:L0,1-1,0 MOVE :8:L2,2-1,1 MOVE :8:L1,2-0,3 MOVE :8:L0,2-2,0 MOVE :8:L1,3-1,2 MOVE :8:L1,1-1,3 MOVE :8:L1,0-3,0 MOVE :8:L0,0-0,1 MOVE :8:L3,0-3,2 MOVE :8:L3,2-0,2 MOVE :8:L3,1-2,2 MOVE :8:L2,3-2,1 MOVE :8:L2,0-2,3 puzzles-20170606.272beef/icons/samegame.sav0000644000175000017500000000176013115373615017302 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :9:Same Game PARAMS :9:10x10c3s2 CPARAMS :9:10x10c3s2 SEED :15:785412408200083 DESC :199:1,1,3,1,2,2,1,2,3,2,2,2,3,3,2,1,1,1,3,2,3,3,2,3,1,3,2,1,1,3,1,2,2,2,3,2,3,2,3,2,1,3,1,2,1,2,3,2,1,3,2,3,1,1,3,3,1,3,3,3,1,1,3,2,2,1,1,2,1,2,2,2,3,1,3,2,2,1,2,3,3,1,2,3,1,3,3,2,1,3,3,1,3,1,2,2,1,3,1,2 NSTATES :2:26 STATEPOS:2:13 MOVE :6:M94,95 MOVE :6:M83,84 MOVE :9:M83,93,94 MOVE :6:M93,94 MOVE :6:M20,21 MOVE :15:M20,21,22,31,32 MOVE :6:M70,71 MOVE :6:M80,90 MOVE :9:M73,82,83 MOVE :18:M72,73,74,82,83,92 MOVE :12:M51,61,62,72 MOVE :9:M35,36,46 MOVE :12:M49,57,58,59 MOVE :6:M59,69 MOVE :9:M69,79,89 MOVE :12:M78,79,89,99 MOVE :24:M45,46,47,54,55,57,64,67 MOVE :36:M36,46,55,56,57,66,67,68,77,78,88,98 MOVE :9:M76,77,87 MOVE :6:M97,98 MOVE :6:M94,95 MOVE :45:M50,60,61,70,71,81,82,83,84,85,90,91,92,93,94 MOVE :12:M73,81,82,83 MOVE :6:M92,93 MOVE :9:M81,90,91 puzzles-20170606.272beef/icons/rect.sav0000644000175000017500000000056613115373615016463 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :10:Rectangles PARAMS :3:7x7 CPARAMS :3:7x7 DESC :33:a3d2b2a3_2a4a8h2a3c4_2b2c3a3_3c3b NSTATES :2:10 STATEPOS:2:10 MOVE :8:R0,6,3,1 MOVE :8:R6,4,1,3 MOVE :8:R3,6,3,1 MOVE :8:R4,4,2,1 MOVE :8:R3,5,3,1 MOVE :8:R6,1,1,3 MOVE :8:R5,0,2,1 MOVE :8:R5,1,1,2 MOVE :8:R4,3,2,1 puzzles-20170606.272beef/icons/range.sav0000644000175000017500000000122413115373615016612 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :5:Range PARAMS :3:7x7 CPARAMS :3:7x7 SEED :15:989032078841515 DESC :22:d7b3e8e5c7a7c13e4e8b4d UI :1:0 NSTATES :2:27 STATEPOS:2:27 MOVE :5:W,4,2 MOVE :5:W,4,3 MOVE :5:W,4,4 MOVE :5:W,4,5 MOVE :5:W,4,6 MOVE :5:W,4,0 MOVE :5:W,3,1 MOVE :5:W,2,1 MOVE :5:W,1,1 MOVE :5:W,0,1 MOVE :5:W,6,1 MOVE :5:W,5,1 MOVE :5:W,5,5 MOVE :5:W,1,5 MOVE :5:B,5,2 MOVE :5:W,5,3 MOVE :5:W,6,3 MOVE :5:W,3,6 MOVE :5:W,2,6 MOVE :5:B,3,5 MOVE :5:W,2,4 MOVE :5:W,2,2 MOVE :5:B,2,3 MOVE :5:W,1,3 MOVE :5:W,3,3 MOVE :5:W,0,5 puzzles-20170606.272beef/icons/pegs.sav0000644000175000017500000000056413115373615016462 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :4:Pegs PARAMS :8:7x7cross CPARAMS :8:7x7cross SEED :15:103342250484448 DESC :49:OOPPPOOOOPPPOOPPPPPPPPPPHPPPPPPPPPPOOPPPOOOOPPPOO NSTATES :1:8 STATEPOS:1:8 MOVE :7:3,1-3,3 MOVE :7:5,2-3,2 MOVE :7:5,4-5,2 MOVE :7:3,4-5,4 MOVE :7:6,4-4,4 MOVE :7:4,0-4,2 MOVE :7:2,0-4,0 puzzles-20170606.272beef/icons/pearl.sav0000644000175000017500000000163013115373615016622 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :5:Pearl PARAMS :5:6x6dt CPARAMS :5:6x6dt SEED :15:901944054393278 DESC :17:BbBfWcWbWBaBeWgWa AUXINFO :72:f8bbe71b9be753d5fa143df207d7797ba62a9b3996eb8b8889487e1a2bd659d91a5e73e1 NSTATES :2:14 STATEPOS:1:7 MOVE :55:F4,2,0;F1,1,0;F4,1,0;F1,0,0;F8,0,0;F2,0,1;F8,0,1;F2,0,2 MOVE :27:F1,0,3;F4,1,3;F1,1,3;F4,2,3 MOVE :27:F8,3,0;F2,3,1;F8,3,1;F2,3,2 MOVE :97:F2,4,2;F8,4,1;F2,4,1;F8,4,0;F1,4,0;F4,5,0;F8,5,0;F2,5,1;F8,5,1;F2,5,2;F8,5,2;F2,5,3;F4,5,3;F1,4,3 MOVE :13:F4,4,2;F1,3,2 MOVE :13:F4,3,0;F1,2,0 MOVE :69:F2,2,3;F8,2,2;F2,2,2;F8,2,1;F4,2,1;F1,1,1;F8,1,1;F2,1,2;F4,1,2;F1,0,2 MOVE :41:F8,0,3;F2,0,4;F8,0,4;F2,0,5;F1,0,5;F4,1,5 MOVE :27:F1,1,4;F4,2,4;F1,2,4;F4,3,4 MOVE :13:F8,1,4;F2,1,5 MOVE :55:F1,3,5;F4,4,5;F1,4,5;F4,5,5;F2,5,5;F8,5,4;F4,5,4;F1,4,4 MOVE :13:F2,3,5;F8,3,4 MOVE :13:F2,4,4;F8,4,3 puzzles-20170606.272beef/icons/pattern.sav0000644000175000017500000000121013115373615017166 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :7:Pattern PARAMS :5:10x10 CPARAMS :5:10x10 DESC :67:3.4/2.2/4.1/2.3/2.3.2/4/6/6/3.1/1/5/5/1.1/4/5/6/2.3/3.3/1.1.3/1.1.4 NSTATES :2:22 STATEPOS:2:22 MOVE :8:F6,4,1,2 MOVE :8:F7,4,1,2 MOVE :8:F4,5,2,1 MOVE :8:F5,4,1,1 MOVE :8:E0,5,2,1 MOVE :8:E0,4,3,1 MOVE :8:F0,6,1,4 MOVE :8:F0,1,1,2 MOVE :8:F0,1,5,1 MOVE :8:E1,2,1,1 MOVE :8:F2,0,1,4 MOVE :8:E3,2,1,1 MOVE :8:F3,0,1,1 MOVE :8:F4,0,1,1 MOVE :8:F3,3,1,1 MOVE :8:E6,3,4,1 MOVE :8:F6,6,1,4 MOVE :8:F7,6,1,4 MOVE :8:E6,0,1,4 MOVE :8:E7,0,1,3 MOVE :8:E5,1,1,1 puzzles-20170606.272beef/icons/palisade.sav0000644000175000017500000000245413115373615017306 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :8:Palisade PARAMS :5:5x5n5 CPARAMS :5:5x5n5 SEED :15:930059588777257 DESC :13:2d23c33e2c1b2 AUXINFO :52:14a191be1282597737537139d11d87fb4f21ad4a8f31e67b4441 NSTATES :2:41 STATEPOS:2:27 MOVE :14:F0,1,16F0,0,64 MOVE :15:F0,0,32F1,0,128 MOVE :12:F1,1,8F0,1,2 MOVE :12:F1,0,4F1,1,1 MOVE :14:F0,2,16F0,1,64 MOVE :12:F1,2,8F0,2,2 MOVE :12:F0,3,1F0,2,4 MOVE :15:F2,0,128F1,0,32 MOVE :12:F2,0,4F2,1,1 MOVE :12:F3,0,8F2,0,2 MOVE :15:F1,4,128F0,4,32 MOVE :14:F1,4,16F1,3,64 MOVE :15:F2,4,128F1,4,32 MOVE :14:F0,3,64F0,4,16 MOVE :15:F1,3,128F0,3,32 MOVE :12:F1,3,1F1,2,4 MOVE :15:F4,4,128F3,4,32 MOVE :14:F4,4,16F4,3,64 MOVE :12:F3,4,8F2,4,2 MOVE :12:F2,4,1F2,3,4 MOVE :12:F2,3,8F1,3,2 MOVE :14:F2,2,64F2,3,16 MOVE :15:F2,3,32F3,3,128 MOVE :12:F3,3,4F3,4,1 MOVE :12:F4,3,8F3,3,2 MOVE :14:F4,3,16F4,2,64 MOVE :12:F1,2,1F1,1,4 MOVE :15:F2,1,128F1,1,32 MOVE :15:F2,2,128F1,2,32 MOVE :12:F2,2,1F2,1,4 MOVE :15:F3,2,128F2,2,32 MOVE :14:F3,2,64F3,3,16 MOVE :12:F4,2,8F3,2,2 MOVE :12:F3,2,1F3,1,4 MOVE :15:F2,1,32F3,1,128 MOVE :14:F4,2,16F4,1,64 MOVE :12:F4,1,8F3,1,2 MOVE :14:F3,0,64F3,1,16 MOVE :15:F4,0,128F3,0,32 MOVE :12:F4,1,1F4,0,4 puzzles-20170606.272beef/icons/netslide.sav0000644000175000017500000000152613115373615017332 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :8:Netslide PARAMS :3:4x4 CPARAMS :3:4x4 SEED :15:344208514520242 DESC :16:49b59aca247714b4 AUXINFO :34:60d28a22f68cdb6078d67a4d6069b9ff54 NSTATES :2:38 STATEPOS:2:31 MOVE :4:R0,1 MOVE :4:C1,1 MOVE :4:R1,1 MOVE :4:R1,1 MOVE :4:C3,1 MOVE :4:C1,1 MOVE :4:R1,1 MOVE :4:R1,1 MOVE :4:R3,1 MOVE :4:R0,1 MOVE :4:C1,1 MOVE :5:R3,-1 MOVE :5:R0,-1 MOVE :4:R0,1 MOVE :4:R0,1 MOVE :4:C0,1 MOVE :5:R0,-1 MOVE :5:R0,-1 MOVE :5:C1,-1 MOVE :4:R1,1 MOVE :4:C1,1 MOVE :5:R1,-1 MOVE :5:C0,-1 MOVE :5:C0,-1 MOVE :4:R3,1 MOVE :4:C0,1 MOVE :4:C0,1 MOVE :5:R3,-1 MOVE :4:C0,1 MOVE :5:R3,-1 MOVE :5:C1,-1 MOVE :4:R0,1 MOVE :4:C0,1 MOVE :5:R0,-1 MOVE :5:C0,-1 MOVE :4:C1,1 MOVE :4:R3,1 puzzles-20170606.272beef/icons/net.sav0000644000175000017500000000160713115373615016311 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :3:Net PARAMS :3:5x5 CPARAMS :3:5x5 DESC :25:1115337157375775157135131 UI :9:O0,0;C2,2 NSTATES :2:45 STATEPOS:2:45 MOVE :4:C0,0 MOVE :4:L0,0 MOVE :4:L0,1 MOVE :4:C0,2 MOVE :4:L0,2 MOVE :4:A0,3 MOVE :4:L0,3 MOVE :4:L0,4 MOVE :4:L1,4 MOVE :4:A2,4 MOVE :4:A2,4 MOVE :4:L2,4 MOVE :4:C1,0 MOVE :4:L1,0 MOVE :4:L3,0 MOVE :4:L2,0 MOVE :4:A4,0 MOVE :4:A4,0 MOVE :4:L4,0 MOVE :4:A4,1 MOVE :4:L4,1 MOVE :4:L3,1 MOVE :4:A3,2 MOVE :4:A3,2 MOVE :4:L3,2 MOVE :4:L2,2 MOVE :4:A2,1 MOVE :4:A2,1 MOVE :4:A1,1 MOVE :4:A1,1 MOVE :4:A1,1 MOVE :4:A1,1 MOVE :4:A1,1 MOVE :4:A1,1 MOVE :4:A1,2 MOVE :4:A1,2 MOVE :4:A1,3 MOVE :4:C2,3 MOVE :4:A3,3 MOVE :4:A4,4 MOVE :4:A4,4 MOVE :4:A4,3 MOVE :4:A4,2 MOVE :4:A4,2 puzzles-20170606.272beef/icons/mines.sav0000644000175000017500000000221413115373615016631 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :5:Mines PARAMS :6:9x9n35 CPARAMS :6:9x9n35 SEED :15:698938038698621 DESC :26:0,0,me0691ca8a278f3c371688 PRIVDESC:22:me0691ca8a278f3c371688 UI :3:D0C TIME :7:75.2958 NSTATES :2:56 STATEPOS:2:41 MOVE :4:O0,0 MOVE :4:F1,2 MOVE :4:F0,2 MOVE :4:O2,2 MOVE :4:F2,1 MOVE :4:F3,1 MOVE :4:F3,2 MOVE :4:F3,3 MOVE :4:F1,3 MOVE :4:F2,3 MOVE :4:C1,0 MOVE :4:C2,0 MOVE :4:C3,0 MOVE :4:F5,0 MOVE :4:F5,1 MOVE :4:C4,1 MOVE :4:O6,1 MOVE :4:O6,2 MOVE :4:O6,3 MOVE :4:F7,1 MOVE :4:O7,4 MOVE :4:O5,4 MOVE :4:F5,3 MOVE :4:F5,5 MOVE :4:F6,6 MOVE :4:C6,5 MOVE :4:F8,6 MOVE :4:C6,3 MOVE :4:F8,2 MOVE :4:C7,2 MOVE :4:F8,0 MOVE :4:F7,0 MOVE :4:F6,0 MOVE :4:C4,2 MOVE :4:F4,4 MOVE :4:F4,5 MOVE :4:F3,4 MOVE :4:C5,6 MOVE :4:F7,7 MOVE :4:F8,7 MOVE :4:F7,8 MOVE :4:O4,8 MOVE :4:F3,6 MOVE :4:C4,6 MOVE :4:F3,8 MOVE :4:F5,8 MOVE :4:C6,7 MOVE :4:C3,7 MOVE :4:F2,5 MOVE :4:F2,4 MOVE :4:F1,8 MOVE :4:F1,7 MOVE :4:C2,7 MOVE :4:C2,6 MOVE :4:C1,6 puzzles-20170606.272beef/icons/map.sav0000644000175000017500000000200113115373615016265 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :3:Map PARAMS :10:20x20n30dn CPARAMS :10:20x20n30dn SEED :15:794003990129265 DESC :264:dcbakatgcaaedaccabfabadbaaaagaiaaaeaiadcaaaafabccbdcaaecabggedfaebqbadgbngcblabdaadaaaeagabaaaacaacacbcaebabaabaebaafaaakabdhcdanaaceagakacbbajaaadbacbaaccbcbicdafbadgbaccbkcdaafbacbcaaabcddacaaaaddbabcdbbacabbhagajabbobcdjaecaafabahaaaffead,23a01c3c1a3d2a20b01a3a AUXINFO :282:738e7a68c5d32445002968f3726646962b3604ef27a3657e0fdc0fd8180d5b747febd4619487bbc8bec5a48c709b154eb8da39c9b49be1e312a381fc2394e53126714079bd82e8444dad92419429635d1c816c53774b8c77b4ce03884c94d12bfb757cd93b5600471cb9726b3f2afe74d9932abeaa2efd6a496cad793ce5b221f943d620e883794f9d56741908 NSTATES :2:18 STATEPOS:2:12 MOVE :4:3:20 MOVE :4:0:24 MOVE :4:3:10 MOVE :4:1:18 MOVE :4:2:11 MOVE :4:3:17 MOVE :4:1:23 MOVE :4:3:27 MOVE :4:1:29 MOVE :4:0:16 MOVE :4:2:13 MOVE :3:1:6 MOVE :3:2:2 MOVE :3:0:7 MOVE :3:2:9 MOVE :4:0:15 MOVE :3:3:5 puzzles-20170606.272beef/icons/magnets.sav0000644000175000017500000000126013115373615017154 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :7:Magnets PARAMS :6:6x5dtS CPARAMS :6:6x5dtS SEED :15:705856238774945 DESC :56:2.2..1,.3.2.,2.21..,2..0.,TLRTLRBLRBTTLRLRBBLRTTTTLRBBBB AUXINFO :60:ebae280db3eec279c628b6cfe4aca5a03ba24d7eba91169f1bdf275fce3f NSTATES :2:24 STATEPOS:2:15 MOVE :4:.1,3 MOVE :4:.0,1 MOVE :4:?0,1 MOVE :4:.2,1 MOVE :4:?2,1 MOVE :4:.2,4 MOVE :4:?2,4 MOVE :4:+2,3 MOVE :4:.3,3 MOVE :4:.0,2 MOVE :4:?0,2 MOVE :4:+1,4 MOVE :4:+0,2 MOVE :4:+0,0 MOVE :4:+1,1 MOVE :4:.2,2 MOVE :4:+2,0 MOVE :4:+3,1 MOVE :4:.4,0 MOVE :4:+5,1 MOVE :4:.5,3 MOVE :4:+4,3 MOVE :4:.4,2 puzzles-20170606.272beef/icons/loopy.sav0000644000175000017500000000352513115373615016666 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :5:Loopy PARAMS :7:7x7t0de CPARAMS :7:7x7t0de DESC :31:02g222b3b2e2a2b322b2a2a3a2a1d1b NSTATES :3:113 STATEPOS:2:75 MOVE :2:3n MOVE :2:0n MOVE :2:1n MOVE :2:2n MOVE :2:4n MOVE :2:6y MOVE :2:5y MOVE :3:25n MOVE :2:9n MOVE :3:28y MOVE :3:27y MOVE :3:42n MOVE :3:30n MOVE :3:45y MOVE :3:44y MOVE :3:59n MOVE :3:47n MOVE :3:62y MOVE :3:61y MOVE :3:76n MOVE :3:64n MOVE :3:79y MOVE :3:78y MOVE :3:93n MOVE :3:81n MOVE :4:110y MOVE :4:111y MOVE :3:99y MOVE :3:98y MOVE :3:24n MOVE :3:39y MOVE :3:23y MOVE :3:22y MOVE :3:26n MOVE :3:37n MOVE :3:38y MOVE :3:54n MOVE :3:69y MOVE :3:53y MOVE :3:40y MOVE :2:7y MOVE :3:88y MOVE :3:87y MOVE :4:102n MOVE :3:90n MOVE :3:52n MOVE :3:41y MOVE :3:55n MOVE :3:43n MOVE :2:8n MOVE :3:10y MOVE :3:12y MOVE :3:11n MOVE :3:13y MOVE :3:29n MOVE :3:15y MOVE :3:14n MOVE :3:16y MOVE :3:32y MOVE :3:31n MOVE :3:18y MOVE :3:17n MOVE :3:19y MOVE :3:20y MOVE :3:21n MOVE :3:33y MOVE :3:35y MOVE :3:36n MOVE :3:50y MOVE :3:57y MOVE :3:58y MOVE :3:72n MOVE :3:60n MOVE :3:74y MOVE :4:104y MOVE :4:107n MOVE :4:106n MOVE :3:92n MOVE :4:109n MOVE :3:89y MOVE :3:77n MOVE :3:75n MOVE :3:73y MOVE :3:85n MOVE :3:70n MOVE :3:56y MOVE :3:67n MOVE :3:71y MOVE :3:68y MOVE :3:84n MOVE :3:82n MOVE :3:83y MOVE :3:97n MOVE :3:86y MOVE :4:101y MOVE :4:100n MOVE :4:103y MOVE :4:105y MOVE :4:108y MOVE :3:96n MOVE :3:95y MOVE :3:94y MOVE :3:91y MOVE :3:80y MOVE :3:66n MOVE :3:65y MOVE :3:63y MOVE :3:51n MOVE :3:46n MOVE :3:34y MOVE :3:48n MOVE :3:49y puzzles-20170606.272beef/icons/lightup.sav0000644000175000017500000000072313115373615017175 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :8:Light Up PARAMS :10:7x7b20s4d1 CPARAMS :10:7x7b25s4d1 SEED :15:538922615851330 DESC :25:b3gB0c0dBaBaBa1aBd1c01g0b NSTATES :2:16 STATEPOS:2:16 MOVE :4:L1,0 MOVE :4:L2,1 MOVE :4:L3,0 MOVE :4:L0,3 MOVE :4:L6,1 MOVE :4:L3,4 MOVE :4:I6,5 MOVE :4:I1,5 MOVE :4:I2,6 MOVE :4:I3,6 MOVE :4:I4,5 MOVE :4:I5,6 MOVE :4:L5,5 MOVE :4:I6,4 MOVE :4:I4,2 puzzles-20170606.272beef/icons/keen.sav0000644000175000017500000000231713115373615016444 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :4:Keen PARAMS :3:5de CPARAMS :3:5de SEED :15:846699649745236 DESC :48:a__a_3a_5a_a_a_3b_bac_,a5m15a7a10s2s2d2s3m40m2s2 AUXINFO :52:6105af67c6ebc8de056b59ebc9a463aa54e75f647055c0a6c1bd NSTATES :2:53 STATEPOS:2:39 MOVE :6:P0,4,2 MOVE :6:P0,4,4 MOVE :6:P0,4,5 MOVE :6:P1,4,2 MOVE :6:P1,4,4 MOVE :6:P1,4,5 MOVE :6:P1,3,2 MOVE :6:P1,3,4 MOVE :6:P1,3,5 MOVE :6:R2,2,4 MOVE :6:R1,2,2 MOVE :6:P1,3,2 MOVE :6:P1,4,2 MOVE :6:R0,4,2 MOVE :6:R2,3,2 MOVE :6:R2,4,1 MOVE :6:R1,4,4 MOVE :6:R1,3,5 MOVE :6:P3,4,3 MOVE :6:P3,4,5 MOVE :6:P4,4,3 MOVE :6:P4,4,5 MOVE :6:R4,4,5 MOVE :6:R3,4,3 MOVE :6:P3,1,2 MOVE :6:P3,1,5 MOVE :6:P3,0,2 MOVE :6:P3,0,5 MOVE :6:R3,2,1 MOVE :6:R3,3,4 MOVE :6:P2,0,3 MOVE :6:P2,0,5 MOVE :6:P2,1,3 MOVE :6:P2,1,5 MOVE :6:P0,1,1 MOVE :6:P0,1,3 MOVE :6:P1,1,1 MOVE :6:P1,1,3 MOVE :6:R2,0,3 MOVE :6:R2,1,5 MOVE :6:R3,0,5 MOVE :6:R3,1,2 MOVE :6:R4,1,4 MOVE :6:R4,2,3 MOVE :6:R4,0,2 MOVE :6:R4,3,1 MOVE :6:R0,2,5 MOVE :6:R0,3,3 MOVE :6:R1,1,3 MOVE :6:R0,1,1 MOVE :6:R1,0,1 MOVE :6:R0,0,4 puzzles-20170606.272beef/icons/inertia.sav0000644000175000017500000000101213115373615017144 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :7:Inertia PARAMS :3:8x8 CPARAMS :3:8x8 SEED :15:739970145068932 DESC :64:sbgwsmswwgggwggmmbwgwbssbwbsbwbbwsSmgbbsbbmsgbmssgmggbmmwmbmmwsw UI :2:D0 NSTATES :2:21 STATEPOS:1:5 MOVE :1:6 MOVE :1:5 MOVE :1:3 MOVE :1:1 MOVE :1:6 MOVE :1:0 MOVE :1:5 MOVE :1:7 MOVE :1:5 MOVE :1:6 MOVE :1:1 MOVE :1:3 MOVE :1:4 MOVE :1:2 MOVE :1:6 MOVE :1:5 MOVE :1:3 MOVE :1:1 MOVE :1:5 MOVE :1:3 puzzles-20170606.272beef/icons/guess.sav0000644000175000017500000000047713115373615016655 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :5:Guess PARAMS :9:c6p4g10Bm CPARAMS :9:c6p4g10Bm SEED :15:313100730915729 DESC :8:b5f3faed UI :7:0,0,0,0 NSTATES :1:6 STATEPOS:1:6 MOVE :8:G1,1,2,2 MOVE :8:G4,3,1,1 MOVE :8:G5,5,1,1 MOVE :8:G4,2,1,6 MOVE :8:G2,3,1,6 puzzles-20170606.272beef/icons/galaxies.sav0000644000175000017500000000160013115373615017311 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :8:Galaxies PARAMS :5:7x7dh CPARAMS :5:7x7dh SEED :15:483644862786314 DESC :13:ikrqfedzljjsp NSTATES :2:43 STATEPOS:2:37 MOVE :5:E12,9 MOVE :5:E8,11 MOVE :5:E5,12 MOVE :5:E7,12 MOVE :5:E4,13 MOVE :5:E2,11 MOVE :5:E3,10 MOVE :4:E2,5 MOVE :4:E4,5 MOVE :4:E6,7 MOVE :4:E8,1 MOVE :5:E10,1 MOVE :4:E9,2 MOVE :4:E6,3 MOVE :4:E7,4 MOVE :5:E10,3 MOVE :5:E10,5 MOVE :5:E11,6 MOVE :5:E13,6 MOVE :5:E8,13 MOVE :5:E12,7 MOVE :6:E12,11 MOVE :6:E13,12 MOVE :4:E8,9 MOVE :4:E7,8 MOVE :4:E7,6 MOVE :4:E9,6 MOVE :4:E8,5 MOVE :4:E9,4 MOVE :4:E5,2 MOVE :4:E4,1 MOVE :4:E3,6 MOVE :4:E2,7 MOVE :4:E3,8 MOVE :4:E3,4 MOVE :4:E4,9 MOVE :4:E2,9 MOVE :5:E5,10 MOVE :5:E6,11 MOVE :4:E2,3 MOVE :4:E2,1 MOVE :5:E1,12 puzzles-20170606.272beef/icons/flood.sav0000644000175000017500000000045213115373615016623 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :5:Flood PARAMS :7:6x6c6m5 CPARAMS :7:6x6c6m5 SEED :15:967543368167853 DESC :39:032242034203340350204502505323231342,17 NSTATES :1:6 STATEPOS:1:6 MOVE :2:M3 MOVE :2:M2 MOVE :2:M0 MOVE :2:M5 MOVE :2:M3 puzzles-20170606.272beef/icons/flip.sav0000644000175000017500000000101513115373615016446 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :4:Flip PARAMS :4:5x5c CPARAMS :4:5x5c SEED :15:158897339725978 DESC :165:c400007100001c4000071000018400043100011c400047100011c400046100010c400047100011c4000471000118400043100011c400047100011c400046100010c000047000011c0000470000118,5c18b48 NSTATES :2:12 STATEPOS:1:4 MOVE :4:M4,3 MOVE :4:M3,0 MOVE :4:M2,2 MOVE :4:M3,2 MOVE :4:M2,3 MOVE :4:M0,2 MOVE :4:M0,3 MOVE :4:M1,4 MOVE :4:M0,0 MOVE :4:M1,0 MOVE :4:M1,1 puzzles-20170606.272beef/icons/filling.sav0000644000175000017500000000126213115373615017144 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :7:Filling PARAMS :3:7x7 CPARAMS :3:7x7 SEED :15:279172739852696 DESC :49:0000000031051240010004000001106171000400001013105 NSTATES :2:30 STATEPOS:2:13 MOVE :4:38_3 MOVE :4:39_3 MOVE :4:36_4 MOVE :4:43_4 MOVE :4:35_4 MOVE :4:47_5 MOVE :4:40_5 MOVE :4:34_5 MOVE :4:41_5 MOVE :4:25_7 MOVE :4:23_6 MOVE :4:16_6 MOVE :4:18_7 MOVE :4:19_7 MOVE :4:20_7 MOVE :4:26_7 MOVE :4:24_7 MOVE :4:29_6 MOVE :4:22_6 MOVE :4:15_6 MOVE :3:7_4 MOVE :3:0_4 MOVE :3:1_3 MOVE :3:2_3 MOVE :3:6_2 MOVE :3:5_5 MOVE :3:4_5 MOVE :3:3_5 MOVE :4:10_5 puzzles-20170606.272beef/icons/fifteen.sav0000644000175000017500000000235613115373615017145 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :7:Fifteen PARAMS :3:4x4 CPARAMS :3:4x4 SEED :15:307905346810973 DESC :37:8,11,3,6,14,13,4,2,0,9,12,10,5,1,7,15 NSTATES :2:66 STATEPOS:2:47 MOVE :4:M1,2 MOVE :4:M1,3 MOVE :4:M0,3 MOVE :4:M0,1 MOVE :4:M1,1 MOVE :4:M1,2 MOVE :4:M0,2 MOVE :4:M0,0 MOVE :4:M1,0 MOVE :4:M1,1 MOVE :4:M0,1 MOVE :4:M0,0 MOVE :4:M1,0 MOVE :4:M3,0 MOVE :4:M3,1 MOVE :4:M1,1 MOVE :4:M1,0 MOVE :4:M3,0 MOVE :4:M3,1 MOVE :4:M1,1 MOVE :4:M1,0 MOVE :4:M2,0 MOVE :4:M2,1 MOVE :4:M1,1 MOVE :4:M1,3 MOVE :4:M0,3 MOVE :4:M0,1 MOVE :4:M1,1 MOVE :4:M1,2 MOVE :4:M0,2 MOVE :4:M0,1 MOVE :4:M2,1 MOVE :4:M3,1 MOVE :4:M3,2 MOVE :4:M2,2 MOVE :4:M2,3 MOVE :4:M3,3 MOVE :4:M3,1 MOVE :4:M2,1 MOVE :4:M2,2 MOVE :4:M1,2 MOVE :4:M1,3 MOVE :4:M2,3 MOVE :4:M2,2 MOVE :4:M1,2 MOVE :4:M0,2 MOVE :4:M0,3 MOVE :4:M1,3 MOVE :4:M1,2 MOVE :4:M2,2 MOVE :4:M2,3 MOVE :4:M0,3 MOVE :4:M0,2 MOVE :4:M1,2 MOVE :4:M2,2 MOVE :4:M2,3 MOVE :4:M1,3 MOVE :4:M1,2 MOVE :4:M3,2 MOVE :4:M3,3 MOVE :4:M1,3 MOVE :4:M1,2 MOVE :4:M2,2 MOVE :4:M2,3 MOVE :4:M3,3 puzzles-20170606.272beef/icons/dominosa.sav0000644000175000017500000000175713115373615017342 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :8:Dominosa PARAMS :1:6 CPARAMS :1:6 DESC :56:55521461210004364611033535444421636022603153156422620503 NSTATES :2:46 STATEPOS:2:33 MOVE :6:D18,19 MOVE :6:E22,23 MOVE :6:E22,30 MOVE :5:E9,17 MOVE :6:D38,46 MOVE :6:E14,15 MOVE :5:E6,14 MOVE :6:E33,34 MOVE :6:E34,42 MOVE :6:E26,34 MOVE :6:D34,35 MOVE :6:E42,50 MOVE :6:E16,24 MOVE :4:D4,5 MOVE :4:D6,7 MOVE :6:D15,23 MOVE :6:E17,25 MOVE :6:D16,17 MOVE :6:E11,12 MOVE :6:D51,52 MOVE :5:E3,11 MOVE :6:D10,11 MOVE :4:D2,3 MOVE :6:E37,45 MOVE :6:D49,50 MOVE :6:D40,48 MOVE :6:D25,26 MOVE :6:D24,32 MOVE :6:D33,41 MOVE :6:D42,43 MOVE :6:D27,28 MOVE :6:E21,29 MOVE :6:D31,39 MOVE :6:D47,55 MOVE :6:E13,21 MOVE :6:E13,14 MOVE :6:D12,13 MOVE :6:D20,21 MOVE :6:D14,22 MOVE :6:D29,30 MOVE :6:D36,37 MOVE :6:D44,45 MOVE :6:D53,54 MOVE :4:D0,1 MOVE :4:D8,9 puzzles-20170606.272beef/icons/cube.sav0000644000175000017500000000054513115373615016441 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :4:Cube PARAMS :4:c4x4 CPARAMS :4:c4x4 SEED :15:125146248070163 DESC :6:C461,3 NSTATES :2:14 STATEPOS:1:5 MOVE :1:D MOVE :1:D MOVE :1:D MOVE :1:U MOVE :1:L MOVE :1:L MOVE :1:D MOVE :1:U MOVE :1:D MOVE :1:U MOVE :1:U MOVE :1:U MOVE :1:L puzzles-20170606.272beef/icons/bridges.sav0000644000175000017500000000447313115373615017146 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :7:Bridges PARAMS :15:10x10i30e10m2d2 CPARAMS :15:10x10i30e10m2d2 SEED :15:944199396008454 DESC :49:a1a4a4b4k4b6b2a4b2b2b1e2e1a4b4c3j25d2a1f2c3a4d4c3 AUXINFO :838:bd75eb5f7b129109b5cdcff0925c77ca5c0a135365002b93b44c5013c7a307b9504affcfb8ad934263196fc3e6d0b023abe48d254d46d29520e50a5e423c0fb1bc01ccc51cad61045c439e7c2bb8e5788bc7f3622aaa3a8125ebde11c9cd69b6f2393246fd094ad91e81ae58cd557b73bd1c9839cfad5835c8519e44298204eaca58dfd79289546959bfbabdc5f3cb7a27b8d3fb2d0b062bd5c2e469493c19f8c89989df73d8a3ab02d9afcbfedf245306d15881a01d153122f8374c7526abecc90919f99ff62e9789cabc402249af095ceb14c8c59c0d9ffbcdd731d50114e7c30c31ef0638f4d352abbfd04b4315d368d65bbfe005b6586245bc5244e5050098cf4c1b6986120f40d5ce038c10a3f309286f950cdc287e495aa13c70ab0c1f113a135556d7ce895fd8244afcbad43fe51f275837f223a1cb95151de8a158cb0add7fa8c9f1fa0e09a1ce842136c1679144cead56b164c4ef1a09ed36fd9704ba191b5957bc3d5bb97d8a1f7451d357a6638ac320b0beb0cd35aa404c8f1621c6d400960aa97bf6ce3a944339d7e401c4d98c31773b2a8881352d5653fdb5e8f7c04b NSTATES :2:63 STATEPOS:2:41 MOVE :10:L8,0,5,0,1 MOVE :10:L8,0,5,0,2 MOVE :10:L8,0,8,2,1 MOVE :10:L8,0,8,2,2 MOVE :4:M8,0 MOVE :10:L0,2,3,2,1 MOVE :10:L0,2,3,2,2 MOVE :10:L0,2,0,7,1 MOVE :10:L0,2,0,7,2 MOVE :4:M0,2 MOVE :10:L1,0,3,0,1 MOVE :4:M1,0 MOVE :10:L3,0,5,0,1 MOVE :10:L3,0,3,2,1 MOVE :10:L1,3,1,5,1 MOVE :10:L0,7,5,7,1 MOVE :10:L0,7,0,9,1 MOVE :10:L0,9,5,9,1 MOVE :10:L0,9,5,9,2 MOVE :10:L0,9,0,7,2 MOVE :4:M0,9 MOVE :4:M0,7 MOVE :10:L4,8,8,8,1 MOVE :10:L4,8,8,8,2 MOVE :4:M4,8 MOVE :10:L5,9,9,9,1 MOVE :10:L5,9,9,9,2 MOVE :4:M5,9 MOVE :10:L9,9,9,6,1 MOVE :4:M9,9 MOVE :10:L8,8,8,5,1 MOVE :4:M8,8 MOVE :10:L9,6,9,4,1 MOVE :4:M9,6 MOVE :4:M9,4 MOVE :10:L1,5,4,5,1 MOVE :10:L1,5,4,5,2 MOVE :10:L1,5,1,3,2 MOVE :4:M1,3 MOVE :4:M1,5 MOVE :10:L3,4,3,2,1 MOVE :10:L3,4,3,2,2 MOVE :4:M3,4 MOVE :10:L4,5,8,5,1 MOVE :10:L7,7,5,7,1 MOVE :4:M5,7 MOVE :4:M7,7 MOVE :10:L7,3,4,3,1 MOVE :4:M7,3 MOVE :10:L5,0,3,0,2 MOVE :4:M5,0 MOVE :4:M3,0 MOVE :10:L3,2,6,2,1 MOVE :4:M3,2 MOVE :10:L6,2,8,2,1 MOVE :4:M6,2 MOVE :10:L8,2,8,5,1 MOVE :4:M8,2 MOVE :4:M8,5 MOVE :10:L4,5,4,3,1 MOVE :4:M4,3 MOVE :4:M4,5 puzzles-20170606.272beef/icons/blackbox.sav0000644000175000017500000000075013115373615017306 0ustar simonsimonSAVEFILE:41:Simon Tatham's Portable Puzzle Collection VERSION :1:1 GAME :9:Black Box PARAMS :8:w8h8m5M5 CPARAMS :8:w8h8m5M5 SEED :15:999785320716678 DESC :24:c8b9f8528193756b9a2fd24d UI :2:E0 NSTATES :2:18 STATEPOS:2:13 MOVE :2:F2 MOVE :2:F4 MOVE :2:F5 MOVE :3:F25 MOVE :3:F26 MOVE :3:F11 MOVE :3:F12 MOVE :3:F15 MOVE :4:T7,7 MOVE :4:T7,4 MOVE :4:T1,7 MOVE :2:F3 MOVE :2:F9 MOVE :3:F27 MOVE :4:T5,7 MOVE :4:T1,8 MOVE :1:R puzzles-20170606.272beef/icons/Makefile0000644000175000017500000001374713115373615016460 0ustar simonsimon# Makefile for Puzzles icons. PUZZLES = blackbox bridges cube dominosa fifteen filling flip flood \ galaxies guess inertia keen lightup loopy magnets map mines \ net netslide palisade pattern pearl pegs range rect \ samegame signpost singles sixteen slant solo tents towers \ twiddle tracks undead unequal unruly untangle BASE = $(patsubst %,%-base.png,$(PUZZLES)) WEB = $(patsubst %,%-web.png,$(PUZZLES)) IBASE = $(patsubst %,%-ibase.png,$(PUZZLES)) IBASE4 = $(patsubst %,%-ibase4.png,$(PUZZLES)) P48D24 = $(patsubst %,%-48d24.png,$(PUZZLES)) P48D8 = $(patsubst %,%-48d8.png,$(PUZZLES)) P48D4 = $(patsubst %,%-48d4.png,$(PUZZLES)) P32D24 = $(patsubst %,%-32d24.png,$(PUZZLES)) P32D8 = $(patsubst %,%-32d8.png,$(PUZZLES)) P32D4 = $(patsubst %,%-32d4.png,$(PUZZLES)) P16D24 = $(patsubst %,%-16d24.png,$(PUZZLES)) P16D8 = $(patsubst %,%-16d8.png,$(PUZZLES)) P16D4 = $(patsubst %,%-16d4.png,$(PUZZLES)) ICONS = $(patsubst %,%.ico,$(PUZZLES)) CICONS = $(patsubst %,%-icon.c,$(PUZZLES)) RC = $(patsubst %,%.rc,$(PUZZLES)) BIN = ../ PIC = ./ # Work around newer ImageMagick unilaterally distorting colours when # converting to PNG. CSP = -set colorspace RGB base: $(BASE) web: $(WEB) pngicons: $(P48D24) $(P32D24) $(P16D24) winicons: $(ICONS) $(RC) gtkicons: $(CICONS) all: base web pngicons winicons gtkicons # Build the base puzzle screenshots from which all the other images # are derived. Some of them involve showing a move animation # part-way through. fifteen-base.png : override REDO=0.3 flip-base.png : override REDO=0.3 netslide-base.png : override REDO=0.3 sixteen-base.png : override REDO=0.3 twiddle-base.png : override REDO=0.3 $(BASE): %-base.png: $(BIN)% $(PIC)%.sav $(PIC)screenshot.sh $(BIN)$* $(PIC)$*.sav $@ $(REDO) # Build the screenshots for the web, by scaling the original base # images to a uniform size. $(WEB): %-web.png: %-base.png $(PIC)square.pl 150 5 $^ $@ # Build the base _icon_ images, by careful cropping of the base # images: icons are very small so it's often necessary to zoom in # on a smaller portion of the screenshot. blackbox-ibase.png : override CROP=352x352 144x144+0+208 bridges-ibase.png : override CROP=264x264 107x107+157+157 dominosa-ibase.png : override CROP=304x272 152x152+152+0 fifteen-ibase.png : override CROP=240x240 120x120+0+120 filling-ibase.png : override CROP=256x256 133x133+14+78 flip-ibase.png : override CROP=288x288 145x145+120+72 galaxies-ibase.png : override CROP=288x288 165x165+0+0 guess-ibase.png : override CROP=263x420 178x178+75+17 inertia-ibase.png : override CROP=321x321 128x128+193+0 keen-ibase.png : override CROP=288x288 96x96+24+120 lightup-ibase.png : override CROP=256x256 112x112+144+0 loopy-ibase.png : override CROP=257x257 113x113+0+0 magnets-ibase.png : override CROP=264x232 96x96+36+100 mines-ibase.png : override CROP=240x240 110x110+130+130 net-ibase.png : override CROP=193x193 113x113+0+80 netslide-ibase.png : override CROP=289x289 144x144+0+0 palisade-ibase.png : override CROP=288x288 192x192+0+0 pattern-ibase.png : override CROP=384x384 223x223+0+0 pearl-ibase.png : override CROP=216x216 94x94+108+15 pegs-ibase.png : override CROP=263x263 147x147+116+0 range-ibase.png : override CROP=256x256 98x98+111+15 rect-ibase.png : override CROP=205x205 115x115+90+0 signpost-ibase.png : override CROP=240x240 98x98+23+23 singles-ibase.png : override CROP=224x224 98x98+15+15 sixteen-ibase.png : override CROP=288x288 144x144+144+144 slant-ibase.png : override CROP=321x321 160x160+160+160 solo-ibase.png : override CROP=481x481 145x145+24+24 tents-ibase.png : override CROP=320x320 165x165+142+0 towers-ibase.png : override CROP=300x300 102x102+151+6 tracks-ibase.png : override CROP=246x246 118x118+6+6 twiddle-ibase.png : override CROP=192x192 102x102+69+21 undead-ibase.png : override CROP=416x480 192x192+16+80 unequal-ibase.png : override CROP=208x208 104x104+104+104 untangle-ibase.png : override CROP=320x320 164x164+3+116 $(IBASE): %-ibase.png: %-base.png $(PIC)crop.sh $^ $@ $(CROP) # Convert the full-size icon images to 4-bit colour, because that # seems to work better than reducing it in 24 bits and then # dithering. $(IBASE4): %-ibase4.png: %-ibase.png convert -colors 16 +dither $(CSP) -map $(PIC)win16pal.xpm $^ $@ # Build the 24-bit PNGs for the icons, at three sizes. $(P48D24): %-48d24.png: %-ibase.png $(PIC)square.pl 48 4 $^ $@ $(P32D24): %-32d24.png: %-ibase.png $(PIC)square.pl 32 2 $^ $@ $(P16D24): %-16d24.png: %-ibase.png $(PIC)square.pl 16 1 $^ $@ # The 8-bit icon PNGs are just custom-paletted quantisations of the # 24-bit ones. $(P48D8) $(P32D8) $(P16D8): %d8.png: %d24.png convert -colors 256 $^ $@ # But the depth-4 images work better if we re-shrink from the # ibase4 versions of the images, and then normalise the colours # again afterwards. (They're still not very good, but my hope is # that on most modern Windows machines this won't matter too # much...) $(P48D4): %-48d4.png: %-ibase4.png $(PIC)square.pl 48 1 $^ $@-tmp2.png convert -colors 16 $(CSP) -map $(PIC)win16pal.xpm $@-tmp2.png $@ rm -f $@-tmp2.png $(P32D4): %-32d4.png: %-ibase.png $(PIC)square.pl 32 1 $^ $@-tmp2.png convert -colors 16 $(CSP) -map $(PIC)win16pal.xpm $@-tmp2.png $@ rm -f $@-tmp2.png $(P16D4): %-16d4.png: %-ibase.png $(PIC)square.pl 16 1 $^ $@-tmp2.png convert -colors 16 $(CSP) -map $(PIC)win16pal.xpm $@-tmp2.png $@ rm -f $@-tmp2.png # Build the actual Windows icons themselves, by feeding all those # PNGs to my icon builder script. $(ICONS): %.ico: %-48d24.png %-48d8.png %-48d4.png \ %-32d24.png %-32d8.png %-32d4.png \ %-16d24.png %-16d8.png %-16d4.png $(PIC)icon.pl -24 $*-48d24.png $*-32d24.png $*-16d24.png \ -8 $*-48d8.png $*-32d8.png $*-16d8.png \ -4 $*-48d4.png $*-32d4.png $*-16d4.png > $@ # Build the .RC files which bind the icons into the applications. $(RC): %.rc: echo '#include "puzzles.rc2"' > $@ echo '200 ICON "$*.ico"' >> $@ # Build the GTK icon source files. $(CICONS): %-icon.c: %-16d24.png %-32d24.png %-48d24.png $(PIC)cicon.pl $^ > $@ clean: rm -f *.png *.ico *.rc *-icon.c