summaryrefslogtreecommitdiffstats
path: root/utils
diff options
context:
space:
mode:
authorSimon Rettberg2021-04-06 14:23:46 +0200
committerSimon Rettberg2021-04-06 14:23:46 +0200
commit26b6e4255d4b9ff79a6dca10de5bec7bfc8691f9 (patch)
treea51e1637554bcd84e63cccb1cb220c898a2c4ee8 /utils
parent5.44 (diff)
downloadxscreensaver-26b6e4255d4b9ff79a6dca10de5bec7bfc8691f9.tar.gz
xscreensaver-26b6e4255d4b9ff79a6dca10de5bec7bfc8691f9.tar.xz
xscreensaver-26b6e4255d4b9ff79a6dca10de5bec7bfc8691f9.zip
xscreensaver 6.00
Diffstat (limited to 'utils')
-rw-r--r--utils/Makefile.in73
-rw-r--r--utils/aligned_malloc.c259
-rw-r--r--utils/aligned_malloc.h8
-rw-r--r--utils/async_netdb.c4
-rw-r--r--utils/font-retry.c630
-rw-r--r--utils/font-retry.h14
-rw-r--r--utils/grabclient.c21
-rw-r--r--utils/grabscreen.c19
-rw-r--r--utils/grabscreen.h4
-rw-r--r--utils/images/logo-180.xpm4
-rw-r--r--utils/images/logo-360.gifbin0 -> 7868 bytes
-rw-r--r--utils/images/logo-360.xpm390
-rw-r--r--utils/images/logo-50.xpm2
-rw-r--r--utils/images/logo.pdf1156
-rw-r--r--utils/logo.c52
-rw-r--r--utils/minixpm.c2
-rw-r--r--utils/minixpm.h3
-rw-r--r--utils/queue.h638
-rw-r--r--utils/textclient-mobile.c2
-rw-r--r--utils/textclient.c129
-rw-r--r--utils/textclient.h4
-rw-r--r--utils/thread_util.c239
-rw-r--r--utils/thread_util.h2
-rw-r--r--utils/usleep.h4
-rw-r--r--utils/utf8wc.c6
-rw-r--r--utils/version.h4
-rw-r--r--utils/visual-gl.c350
-rw-r--r--utils/visual.h6
-rw-r--r--utils/xdbe.c5
-rw-r--r--utils/xft.c110
-rw-r--r--utils/xft.h7
-rw-r--r--utils/xftwrap.c206
-rw-r--r--utils/xftwrap.h35
-rw-r--r--utils/xmu.c197
-rw-r--r--utils/xmu.h8
-rw-r--r--utils/xshm.c29
-rw-r--r--utils/yarandom.c4
37 files changed, 3859 insertions, 767 deletions
diff --git a/utils/Makefile.in b/utils/Makefile.in
index dbb593b..d624e2f 100644
--- a/utils/Makefile.in
+++ b/utils/Makefile.in
@@ -1,4 +1,4 @@
-# utils/Makefile.in --- xscreensaver, Copyright (c) 1997-2010 Jamie Zawinski.
+# utils/Makefile.in --- xscreensaver, Copyright © 1997-2021 Jamie Zawinski.
# the `../configure' script generates `utils/Makefile' from this file.
@@ -102,35 +102,33 @@ X_CFLAGS = @X_CFLAGS@
INCLUDES_1 = -I$(srcdir) -I..
INCLUDES = $(INCLUDES_1) @INCLUDES@
-SRCS = alpha.c colors.c fade.c grabscreen.c grabclient.c hsv.c \
+SRCS = alpha.c colors.c grabscreen.c grabclient.c hsv.c \
overlay.c resources.c spline.c usleep.c visual.c \
visual-gl.c xmu.c logo.c yarandom.c erase.c \
xshm.c xdbe.c colorbars.c minixpm.c textclient.c \
textclient-mobile.c aligned_malloc.c thread_util.c \
- async_netdb.c xft.c utf8wc.c pow2.c font-retry.c
-OBJS = alpha.o colors.o fade.o grabscreen.o grabclient.o hsv.o \
+ async_netdb.c xft.c xftwrap.c utf8wc.c pow2.c font-retry.c
+OBJS = alpha.o colors.o grabscreen.o grabclient.o hsv.o \
overlay.o resources.o spline.o usleep.o visual.o \
visual-gl.o xmu.o logo.o yarandom.o erase.o \
xshm.o xdbe.o colorbars.o minixpm.o textclient.o \
- textclient-mobile.o aligned_malloc.o thread_util.o \
- async_netdb.o xft.o utf8wc.o pow2.o \
- font-retry.o font-retry-xft.o
-HDRS = alpha.h colors.h fade.h grabscreen.h hsv.h resources.h \
+ aligned_malloc.o thread_util.o \
+ async_netdb.o xft.o xftwrap.o utf8wc.o pow2.o \
+ font-retry.o
+HDRS = alpha.h colors.h grabscreen.h hsv.h resources.h \
spline.h usleep.h utils.h version.h visual.h vroot.h xmu.h \
yarandom.h erase.h xshm.h xdbe.h colorbars.h minixpm.h \
xscreensaver-intl.h textclient.h aligned_malloc.h \
- thread_util.h async_netdb.h xft.h utf8wc.h pow2.h \
- font-retry.h
+ thread_util.h async_netdb.h xft.h xftwrap.h utf8wc.h pow2.h \
+ font-retry.h queue.h
STAR = *
LOGOS = images/$(STAR).xpm \
images/$(STAR).png \
images/$(STAR).gif \
- images/$(STAR).eps
+ images/$(STAR).pdf
EXTRAS = README Makefile.in ad2c bin2c
-VMSFILES = compile_axp.com compile_decc.com vms-gtod.c vms-gtod.h \
- vms-strdup.c
-TARFILES = $(EXTRAS) $(VMSFILES) $(SRCS) $(HDRS) $(LOGOS)
+TARFILES = $(EXTRAS) $(SRCS) $(HDRS) $(LOGOS)
default: all
@@ -185,49 +183,24 @@ TAGS: tags
tags:
find $(srcdir) -name '*.[chly]' -print | xargs etags -a
-echo_tarfiles:
- @echo $(TARFILES)
-
+list_tarfiles:
+ @find $(TARFILES) -type f -print | sort
# How we build object files in this directory.
CCUTILS = $(INCLUDES) $(DEFS) $(CPPFLAGS) $(CFLAGS) $(X_CFLAGS)
.c.o:
$(CC) -c $(CCUTILS) $<
-# Two versions of this: driver/ does not link with Xft, but hacks/ does.
-font-retry-xft.o: $(srcdir)/font-retry.c
+font-retry.o: $(srcdir)/font-retry.c
$(CC) -c $(CCUTILS) -DUSE_XFT $< -o $@
-# Rules for generating the VMS makefiles on Unix, so that it doesn't have to
-# be done by hand...
-#
-VMS_AXP_COMPILE=$$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-])
-
-compile_axp.com: Makefile.in
- @echo generating $@ from $<... ; \
- ( ( for c in $(SRCS) vms-*.c ; do \
- c=`echo $$c | tr a-z A-Z` ; \
- echo "$(VMS_AXP_COMPILE) $$c" ; \
- done ; \
- ) | sort -d ; \
- echo '$$ lib/cre utils.olb_axp' ; \
- echo '$$ lib utils.olb_axp *.obj' ; \
- echo '$$! delete/noconf *.obj;' ; \
- ) > $@
-
-compile_decc.com: compile_axp.com
- @echo generating $@ from $<... ; \
- sed 's/axp/decc/g' < $< > $@
-
-distdepend:: compile_axp.com compile_decc.com
-
-
##############################################################################
#
# DO NOT DELETE: updated by make distdepend
aligned_malloc.o: $(srcdir)/aligned_malloc.h
+aligned_malloc.o: ../config.h
alpha.o: $(srcdir)/alpha.h
alpha.o: ../config.h
alpha.o: $(srcdir)/hsv.h
@@ -256,11 +229,6 @@ erase.o: $(srcdir)/resources.h
erase.o: $(srcdir)/usleep.h
erase.o: $(srcdir)/utils.h
erase.o: $(srcdir)/yarandom.h
-fade.o: ../config.h
-fade.o: $(srcdir)/fade.h
-fade.o: $(srcdir)/usleep.h
-fade.o: $(srcdir)/utils.h
-fade.o: $(srcdir)/visual.h
font-retry.o: ../config.h
font-retry.o: $(srcdir)/font-retry.h
font-retry.o: $(srcdir)/utils.h
@@ -286,11 +254,11 @@ hsv.o: $(srcdir)/hsv.h
hsv.o: $(srcdir)/utils.h
logo.o: ../config.h
logo.o: $(srcdir)/images/logo-180.xpm
+logo.o: $(srcdir)/images/logo-360.xpm
logo.o: $(srcdir)/images/logo-50.xpm
logo.o: $(srcdir)/minixpm.h
logo.o: $(srcdir)/resources.h
logo.o: $(srcdir)/utils.h
-logo.o: $(srcdir)/visual.h
minixpm.o: ../config.h
minixpm.o: $(srcdir)/minixpm.h
overlay.o: ../config.h
@@ -328,12 +296,17 @@ xdbe.o: ../config.h
xdbe.o: $(srcdir)/resources.h
xdbe.o: $(srcdir)/utils.h
xdbe.o: $(srcdir)/xdbe.h
+xdbe.o: $(srcdir)/xmu.h
xft.o: ../config.h
+xftwrap.o: ../config.h
+xftwrap.o: $(srcdir)/utils.h
+xftwrap.o: $(srcdir)/xft.h
+xftwrap.o: $(srcdir)/xftwrap.h
xmu.o: ../config.h
+xmu.o: $(srcdir)/xmu.h
xshm.o: $(srcdir)/aligned_malloc.h
xshm.o: ../config.h
xshm.o: $(srcdir)/resources.h
-xshm.o: $(srcdir)/thread_util.h
xshm.o: $(srcdir)/utils.h
xshm.o: $(srcdir)/xshm.h
yarandom.o: ../config.h
diff --git a/utils/aligned_malloc.c b/utils/aligned_malloc.c
index b345ad1..8c45fc8 100644
--- a/utils/aligned_malloc.c
+++ b/utils/aligned_malloc.c
@@ -13,6 +13,10 @@ software for any purpose. It is provided "as is" without express or
implied warranty.
*/
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
#include "aligned_malloc.h"
#include <stddef.h>
@@ -21,6 +25,254 @@ implied warranty.
#include <assert.h>
#include <errno.h>
+/* Might be changed by thread_util.c:threads_available()
+ */
+unsigned int aligned_malloc_default_alignment = sizeof(void *);
+
+
+#if HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if defined __MACH__ && defined __APPLE__ /* OS X, iOS */
+# include <sys/sysctl.h>
+# include <inttypes.h>
+#endif
+
+#define IS_POWER_OF_2(x) ((x) > 0 && !((x) & ((x) - 1)))
+
+/*
+ arraysize(a). Also known as countof(x), XtNumber(x), NELEMS(x), LEN(x),
+ NUMOF(x), ARRAY_SIZE(x), etc., since the fine folks behind C never got
+ around to including this incredibly useful macro in the standard library,
+ which is where it belongs.
+
+ Much of the code here assumes that multiple processors in a system all use
+ the same cache line size...which might be wrong on occasion.
+*/
+
+#define arraysize(a) (sizeof(a) / sizeof(*(a)))
+#define arrayend(a) ((a) + arraysize(a))
+
+/*
+These numbers are from:
+- Linux: arch/(arch name)/include/asm/cache.h, note
+ L1_CACHE_BYTES/L1_CACHE_SHIFT/SMP_CACHE_BYTES.
+- FreeBSD: sys/(sys name)/include/param.h, note
+ CACHE_LINE_SHIFT/CACHE_LINE_SIZE.
+
+Preprocessor symbols come from:
+- TARGET_CPU_CPP_BUILTINS() in the GNU C preprocessor
+ <http://code.ohloh.net/?s=%22TARGET_CPU_CPP_BUILTINS%22&fp=304413>
+- http://predef.sourceforge.net/
+*/
+
+/*
+Several architectures need preprocessor symbols.
+
+Qualcomm Hexagon: 1 << 5
+Imagination Technologies META: 1 << 6
+OpenRISC: 16 (Linux has the cache line size as a todo.)
+Unicore: 1 << 5
+*/
+
+#if defined __MACH__ && defined __APPLE__ /* OS X, iOS */
+# include <TargetConditionals.h> /* For TARGET_OS_IPHONE. */
+# ifdef TARGET_OS_IPHONE
+# define _CACHE_LINE_SIZE 64
+# endif
+#endif
+
+#if defined __FreeBSD__ && !defined _CACHE_LINE_SIZE
+# include <machine/param.h>
+# ifdef CACHE_LINE_SIZE
+# define _CACHE_LINE_SIZE CACHE_LINE_SIZE
+# endif
+#endif
+
+#if !defined _CACHE_LINE_SIZE
+# if defined __alpha || defined __alpha__
+/* DEC Alpha */
+# define _CACHE_LINE_SIZE 64 /* EV6 and above. EV4 and EV5 use 32 bytes. */
+# elif defined __arm__
+/* ARM architecture */
+# define _CACHE_LINE_SIZE (1 << 6)
+# elif defined __AVR || defined __AVR__
+/* Atmel AVR32 */
+# define _CACHE_LINE_SIZE (1 << 5)
+# elif defined __bfin || defined __BFIN__
+/* Analog Devices Blackfin */
+# define _CACHE_LINE_SIZE (1 << 5)
+# elif defined _TMS320C6X || defined __TMS320C6X__
+/* Texas Instruments TMS320C6x */
+# define _CACHE_LINE_SIZE (1 << 7) /* From L2. L1 data cache line is 1 << 6. */
+# elif defined __cris
+/* Axis Communications ETRAX CRIS */
+# define _CACHE_LINE_SIZE 32
+# elif defined __ia64__ || defined _IA64
+/* Intel Itanium */
+# define _CACHE_LINE_SIZE (1 << 7)
+# elif defined __M32R__ || defined __m32r__
+/* Mitsubishi/Renesas M32R */
+# define _CACHE_LINE_SIZE (1 << 4)
+# elif defined __m68k__ || defined M68000 || defined __MC68K__
+/* Motorola 68000 */
+# define _CACHE_LINE_SIZE (1 << 4)
+# elif defined __MICROBLAZE__ || defined __microblaze__
+/* Xilinx MicroBlaze */
+# define _CACHE_LINE_SIZE (1 << 5)
+# elif defined __mips__ || defined __mips || defined __MIPS__
+/* MIPS */
+# define _CACHE_LINE_SIZE (1 << 6)
+# elif defined __mn10300__ || defined __MN10300__
+/* Matsushita/Panasonic MN103 */
+# define _CACHE_LINE_SIZE 32 /* MN103E010 has 16 bytes. */
+# elif defined __hppa || defined __hppa__
+/* Hewlett-Packard PA-RISC */
+# define _CACHE_LINE_SIZE 64 /* PA-RISC 2.0 uses 64 bytes, PA-RISC 1.1 uses 32. */
+# elif defined __powerpc || defined _ARCH_PPC
+/* Power Architecture (a.k.a. PowerPC) */
+# define _CACHE_LINE_SIZE (1 << 7) /* Linux has a list of PPC models with associated L1_CACHE_SHIFT values. */
+# elif defined __s390__ || defined __370__ || defined __zarch__ || defined __SYSC_ZARCH__
+/* IBM System/390 */
+# define _CACHE_LINE_SIZE 256
+# elif defined SUNPLUS || defined __SCORE__ || defined __score__
+/* Sunplus S+core */
+# define _CACHE_LINE_SIZE (1 << 4)
+# elif defined __sh__
+/* Hitachi SuperH */
+# define _CACHE_LINE_SIZE (1 << 5) /* SH3 and earlier used 1 << 4. */
+# elif defined __sparc__ || defined __sparc
+/* SPARC */
+# define _CACHE_LINE_SIZE (1 << 7) /* Linux and FreeBSD disagree as to what this should be. */
+# elif defined __tile__
+/* Tilera TILE series */
+# define _CACHE_LINE_SIZE (1 << 6) /* TILEPro uses different sizes for L1 and L2. */
+# elif defined __i386 || defined __x86_64
+/* x86(-64) */
+# define _CACHE_LINE_SIZE (1 << 7)
+# elif defined __xtensa__ || defined __XTENSA__
+/* Cadence Design Systems/Tensilica Xtensa */
+# define _CACHE_LINE_SIZE (1 << 5) /* 1 << 4 on some models. */
+# endif
+#endif /* !defined _CACHE_LINE_SIZE */
+
+#if defined __NetBSD__ && !defined _CACHE_LINE_SIZE
+/*
+NetBSD defines COHERENCY_UNIT to be 32 on MIPS, and 64 for all other platforms -- which is wrong. Still, this is what the kernel
+uses; if this value didn't work, the system wouldn't run.
+*/
+# include <sys/param.h>
+# ifdef COHERENCY_UNIT
+# define _CACHE_LINE_SIZE COHERENCY_UNIT
+# endif
+#endif
+
+#ifndef _CACHE_LINE_SIZE
+# define _CACHE_LINE_SIZE 256 /* Fallback cache line size. */
+#endif
+
+static unsigned _get_cache_line_size(void)
+{
+ /*
+ The general idea:
+ - Try to get the actual cache line size from the operating system.
+ - In the interest of keeping things simple, this only checks with
+ glibc and OS X.
+ - A few other methods that could be added:
+ - Query x86 CPUs directly with the CPUID instruction.
+ - Query various ELF systems through the auxillary vector.
+ (Power, Alpha, SuperH)
+ - Query Linux through
+ /sys/devices/system/cpu/cpu?/cache/index?/coherency_line_size
+ (x86 only, AFAIK)
+ - Query Linux through cache_alignment in /proc/cpuinfo
+ - Query Solaris through PICL.
+ - If that fails, return a value appropriate for the current CPU
+ architecture.
+ - Otherwise, return a sufficiently large number.
+ */
+
+ /*
+ sysconf(3) is not a syscall, it's a glibc call that, for cache line sizes,
+ uses CPUID on x86 and returns 0 on other platforms. If it were to work on
+ most other platforms, it would have to get cache information from the
+ kernel, since that information is usually made available by the processor
+ only in privileged mode.
+ https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/i386/sysconf.c;hb=HEAD
+ */
+
+ /* uClibc, newlib, dietlibc, musl, Bionic do not have this. */
+
+# if HAVE_UNISTD_H && ( \
+ defined _SC_LEVEL1_DCACHE_LINESIZE || \
+ defined _SC_LEVEL2_CACHE_LINESIZE || \
+ defined _SC_LEVEL3_CACHE_LINESIZE || \
+ defined _SC_LEVEL4_CACHE_LINESIZE)
+ {
+ static const int names[] =
+ {
+# ifdef _SC_LEVEL1_DCACHE_LINESIZE
+ _SC_LEVEL1_DCACHE_LINESIZE,
+# endif
+# ifdef _SC_LEVEL2_CACHE_LINESIZE
+ _SC_LEVEL2_CACHE_LINESIZE,
+# endif
+# ifdef _SC_LEVEL3_CACHE_LINESIZE
+ _SC_LEVEL3_CACHE_LINESIZE,
+# endif
+# ifdef _SC_LEVEL4_CACHE_LINESIZE
+ _SC_LEVEL4_CACHE_LINESIZE
+# endif
+ };
+
+ const int *name;
+ long result = 0;
+
+ for(name = names; name != arrayend(names); ++name)
+ {
+ long sysconf_result = sysconf(*name); /* Can return -1 or 0 on
+ failure. */
+
+ if(sysconf_result > result)
+ result = sysconf_result;
+ }
+
+ if(result)
+ return result;
+
+ /* Currently, this fails for every platform that isn't x86. Perhaps
+ future versions will support other processors? */
+ }
+# endif
+
+# if defined __MACH__ && defined __APPLE__
+ {
+ uint32_t result; /* sysctl.h says that hw.cachelinesize is a
+ CTLTYPE_INT. */
+ size_t size = sizeof(result);
+ static const int name[] = {CTL_HW, HW_CACHELINE};
+
+ if(!sysctl((int *)name, 2, &result, &size, NULL, 0)) /* (int *) is for OS X. */
+ {
+ assert(size == sizeof(result));
+ return result;
+ };
+ }
+# endif
+
+ /* Guess based on the CPU type. */
+ return _CACHE_LINE_SIZE;
+}
+
+unsigned get_cache_line_size(void)
+{
+ unsigned result = _get_cache_line_size();
+ assert(result >= sizeof(void *));
+ assert(IS_POWER_OF_2(result));
+ return result;
+}
+
/* aligned_alloc() (C11) or posix_memalign() (POSIX) are other possibilities
for aligned_malloc().
*/
@@ -28,10 +280,15 @@ implied warranty.
int aligned_malloc(void **ptr, unsigned alignment, size_t size)
{
void *block_start;
- ptrdiff_t align1 = alignment - 1;
+ ptrdiff_t align1;
+
+ if (alignment == 0)
+ alignment = aligned_malloc_default_alignment;
assert(alignment && !(alignment & (alignment - 1))); /* alignment must be a power of two. */
+ align1 = alignment - 1;
+
size += sizeof(void *) + align1;
block_start = malloc(size);
if(!block_start)
diff --git a/utils/aligned_malloc.h b/utils/aligned_malloc.h
index b3f43c9..0ec675f 100644
--- a/utils/aligned_malloc.h
+++ b/utils/aligned_malloc.h
@@ -18,9 +18,13 @@ implied warranty.
#include <stdlib.h>
+extern unsigned int aligned_malloc_default_alignment;
+
+unsigned get_cache_line_size(void);
+
/* This can't simply be named posix_memalign, since the real thing uses
free(), but this one can't. */
- int aligned_malloc(void **ptr, unsigned alignment, size_t size);
- void aligned_free(void *);
+int aligned_malloc(void **ptr, unsigned alignment, size_t size);
+void aligned_free(void *);
#endif /* __ALIGNED_MALLOC_H__ */
diff --git a/utils/async_netdb.c b/utils/async_netdb.c
index 930da40..d9e2102 100644
--- a/utils/async_netdb.c
+++ b/utils/async_netdb.c
@@ -48,10 +48,10 @@ int _async_netdb_is_done (struct io_thread *io)
# define _get_addr_family(addr) ((addr)->x_sockaddr_in.sin_family)
# define _get_addr_len(addr) ((addr)->x_sockaddr_in.sin_len)
-static const int _has_threads = -1;
-
# if ASYNC_NETDB_FAKE_EAI
+static const int _has_threads = -1;
+
const char *_async_netdb_strerror (int errcode)
{
/* (h)strerror should return messages in the user's preferred language. */
diff --git a/utils/font-retry.c b/utils/font-retry.c
index f8e6507..3122969 100644
--- a/utils/font-retry.c
+++ b/utils/font-retry.c
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 2018 by Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 2018-2021 by Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
@@ -9,11 +9,56 @@
* implied warranty.
*/
-/* Like XLoadQueryFont, but if it fails, it tries some heuristics to
- load something close.
+/* The value of XScreenSaver's font resource strings is a comma-separated
+ list of font names that look like this:
+
+ Helvetica Bold Italic 12
+
+ We parse that into an XLFD and pass that along to the underlying systems:
+ XftFontOpenXlfd or jwxyz.
+
+ Xft does aggressive substitution of unknown fonts, so if we don't get an
+ exact match on the font name, we move on to the next element in the list.
+ For the last element, we take whatever substitution we got.
+
+ XftNameParse uses this syntax:
+
+ "Helvetica Neue-12:style=Bold"
+ "Helvetica Neue-12:style=Bold Italic"
+ "Helvetica Neue-12:slant=110:weight=200"
+
+ Cocoa uses PostScript names, with hyphens:
+
+ [NSFont fontWithName:@"Helvetica-BoldOblique" size:12];
+ [NSFont fontWithName:@"Times-Roman" size:12];
+
+ Alternately, with separated styles:
+
+ [[NSFontManager sharedFontManager]
+ fontWithFamily:@"Helvetica" traits:NSBoldFontMask weight:5 size:12];
+
+ Android separates names from styles:
+
+ Paint.setTypeface (Typeface.create ("Helvetica", Typeface.BOLD));
+ Paint.setTextSize (12);
+
+ See android/xscreensaver/src/org/jwz/xscreensaver/jwxyz.java
+
+
+ In XScreenSaver 6, USE_XFT is always true, as all programs now use Xft.
+
+ In XScreenSaver 5, this file was compiled in two different ways:
+ - As font-retry.o for programs that did not link with libXft;
+ - As font-retry-xft.o for programs that did.
+
+ #ifdef USE_XFT is whether Xft code should be called.
+ #ifdef HAVE_XFT is whether libXft is natively available.
+
+ The reason there are two defines is that if HAVE_XFT is not defined,
+ the Xft API is still available through emulation provided by "xft.h".
*/
-#define _GNU_SOURCE
+#define _GNU_SOURCE /* Why is this here? */
#include "utils.h"
#include "visual.h"
@@ -26,194 +71,471 @@ extern const char *progname;
#define countof(x) (sizeof((x))/sizeof((*x)))
#undef DEBUG
+#undef SELFTEST
+
+#ifdef HAVE_JWXYZ
+# define USE_XFT 1
+#endif
+
+#ifdef SELFTEST
+static void xft_selftest (Display *dpy, int screen);
+#endif
+
+
+/* Parse font names of the form "Helvetica Neue Bold Italic 12".
+ */
+static char *
+font_name_to_xlfd (const char *font_name)
+{
+ char *name = strdup (font_name);
+ char *xlfd = 0;
+ char *s, *s2, *b, *i, *o, c;
+ float size;
+
+ if (name[0] == '-' || name[0] == '*')
+ return name; /* Already an XLFD */
+
+ /* Downcase ASCII; dash to space */
+ for (s = name; *s; s++)
+ if (*s >= 'A' && *s <= 'Z')
+ *s += 'a'-'A';
+ else if (*s == '-')
+ *s = ' ';
+
+ /* "Family NN" or "Family-NN" */
+ s = strrchr (name, ' ');
+ s2 = strrchr (name, '-');
+ if (s && s2 && s2 > s) s = s2;
+ if (!s) goto FAIL;
+ if (1 != sscanf (s+1, " %f %c", &size, &c)) goto FAIL;
+ if (size <= 0) goto FAIL;
+ *s = 0;
+
+ /* "Family Bold", etc. */
+ b = strstr (name, " bold");
+ i = strstr (name, " italic");
+ o = strstr (name, " oblique");
+ if (b) *b = 0;
+ if (i) *i = 0;
+ if (o) *o = 0;
+
+ xlfd = (char *) malloc (strlen(name) + 80);
+ sprintf (xlfd, "-*-%s-%s-%s-*-*-*-%d-*-*-*-*-*-*",
+ name,
+ (b ? "bold" : "medium"),
+ (i ? "i" : o ? "o" : "r"),
+ (int) (size * 10));
+ free (name);
+ return xlfd;
+
+ FAIL:
+ fprintf (stderr, "%s: XFT: unparsable: \"%s\"\n", progname, font_name);
+ if (name) free (name);
+ if (xlfd) free (xlfd);
+ return 0;
+}
+
+
+#ifdef USE_XFT
+
+/* Xft silently substitutes fonts if the one you requested wasn't available.
+ This leads to the deplorable situation where we ask for a fixed width font
+ and are given a variable width font instead. This doesn't happen with
+ Courier, since Xft special-cases that one, but it happens with any other
+ fixed width font that is not similarly privileged.
+
+ Even worse: when Xft substitutes fonts, it makes no attempt to return fonts
+ that are capable of displaying the language of the current locale. For
+ example: if your locale is set to Japanese and you request "Helvetica", Xft
+ silently substitutes "Nimbus Sans" -- a font which is not capable of
+ displaying Japanese characters. If instead you requested "asdfasdfghjkl",
+ you get "Noto Sans CJK JP", which does work. So that's just spectacular.
+
+ Since there does not appear to be a way to ask Xft whether a particular
+ font exists, we load the font and then check to see if the name we got
+ is the name we requested.
+
+ In more detail:
+
+ - XftFontOpenXlfd is defined as:
+ XftFontOpenPattern (XftFontMatch (XftXlfdParse (xlfd)))
+ - XftFontOpenName is defined as:
+ XftFontOpenPattern (XftFontMatch (XftNameParse (name)))
+ - Calling XftFontOpenPattern with a pattern that has not been filtered
+ through XftFontMatch does not work.
+ - XftFontMatch substitutes another font if the pattern doesn't match.
+ - If the pattern has family "Courier", it substitutes a fixed width
+ font, e.g. "Liberation Mono".
+ - Otherwise it substitutes a variable width font, e.g. "DejaVu Sans".
+ It does this even if the pattern contained "spacing=100" or "110",
+ indicating a monospace or charcell font.
+ - XftXlfdParse does not translate "spacing" from XLFD to XftPattern,
+ but that doesn't matter since XftFontMatch ignores it anyway.
+
+ Xft source is here:
+ https://opensource.apple.com/source/X11ForMacOSXSource/X11ForMacOSXSource-1.0/xc/lib/Xft1/
+
+ Courier, Helvetica and the other historical PostScript font names seem to
+ be special-cased in /etc/fonts/conf.d/ in the files 30-metric-aliases.conf,
+ 45-latin.conf and/or 60-latin.conf, which uses an idiosyncratic scripting
+ language implemented as XML! Some incomplete documentation on that baroque
+ mess is here:
+ https://www.freedesktop.org/software/fontconfig/fontconfig-user.html
+
+ The Xft configuration files seem to special-case the names "monospace",
+ "serif" and "sans-serif" as generic fallback fonts.
+
+ However, "sans-serif" is problematic because it does not survive the trip
+ through XftXlfdParse and XftFontOpenPattern -- XLFD font families cannot
+ include hyphens. So we have no choice but to turn it into "sans serif",
+ which is *not* special-cased by the Xft config files.
+
+ In summary, everything is terrible, and it's a wonder anything works at all.
+ */
+static Bool
+xlfd_substituted_p (XftFont *f, const char *xlfd)
+{
+# ifndef HAVE_XFT
+ return False; /* No substitutions in the Xft emulator. */
+# else /* HAVE_XFT */
+
+ Bool ret = True;
+ const char *oxlfd = xlfd;
+ char *s = 0;
+ char *xname = 0;
+ char fname[1024];
+
+ if (*xlfd == '-' || strchr (xlfd, '*')) /* it's an xlfd */
+ {
+ if (*xlfd != '-') goto FAIL;
+ xlfd++;
+ s = strchr (xlfd, '-'); if (!s) goto FAIL; /* skip foundry */
+ xlfd = s+1;
+ s = strchr (xlfd, '-'); if (!s) goto FAIL; /* skip family */
+
+ {
+ char buf[1024];
+ XftPattern *pat = XftXlfdParse (oxlfd, True, True);
+ XftNameUnparse (pat, buf, sizeof(buf)-1);
+ }
+ }
+ else /* It's an Xft name */
+ {
+ s = strchr (xlfd, '-'); if (!s) goto FAIL; /* skip family */
+ }
+
+ xname = strdup (xlfd);
+ xname[s - xlfd] = 0;
+
+ *fname = 0;
+ XftNameUnparse (f->pattern, fname, sizeof(fname)-1);
+ s = strchr (fname, ':'); /* Strip to "Family-NN" */
+ if (s) *s = 0;
+ s = strrchr (fname, '-'); /* Strip to family */
+ if (s) *s = 0;
+
+ ret = !strcasestr (fname, xname);
+
+# ifdef DEBUG
+ if (ret)
+ fprintf (stderr, "%s: XFT: requested \"%s\" but got \"%s\"\n",
+ progname, xname, fname);
+# endif
+
+ FAIL:
+
+ if (!s)
+ fprintf (stderr, "%s: unparsable XLFD: %s\n", progname, oxlfd);
+ if (xname) free (xname);
+ return ret;
+# endif /* HAVE_XFT */
+}
+#endif /* USE_XFT */
+
static void *
-load_font_retry_1 (Display *dpy, int screen, const char *xlfd, Bool xft_p)
+load_font_retry_1 (Display *dpy, int screen, const char *font_list, Bool xft_p)
{
# ifdef USE_XFT
# define LOADFONT(F) (xft_p \
- ? (void *) XftFontOpenXlfd (dpy, screen, (F)) \
+ ? (void *) XftFontOpenXlfd (dpy, screen, (F)) \
: (void *) XLoadQueryFont (dpy, (F)))
+# define UNLOADFONT(F) (xft_p \
+ ? (void) XftFontClose (dpy, (F)) \
+ : (void) XFreeFont (dpy, (F)))
# else
# define LOADFONT(F) ((void *) XLoadQueryFont (dpy, (F)))
+# define UNLOADFONT(F) XFreeFont (dpy, (F))
# endif
- void *f = xlfd ? LOADFONT(xlfd) : 0;
+ char *font_name = 0;
+ void *f = 0;
+ void *fallback = 0;
# ifndef USE_XFT
if (xft_p) abort();
# endif
-# ifdef HAVE_JWXYZ
- return f;
-# else /* !HAVE_JWXYZ */
- if (! xlfd) xlfd = "<null>";
- if (f)
- {
-# ifdef DEBUG
- fprintf (stderr, "%s: loaded %s\n", progname, xlfd);
+# ifdef SELFTEST
+ xft_selftest (dpy, screen);
# endif
- return f;
- }
- else
+
+ if (! font_list) font_list = "<null>";
+
+ /* Treat the string as a comma-separated list of font names.
+ Names are XLFDs or the XScreenSaver syntax described above.
+ Try to load each of them in order.
+ If a substitution was made, keep going, unless this is the last.
+ */
+ if (font_list)
{
- Bool bold_p = (!!strcasestr (xlfd, "-bold-") ||
- !!strcasestr (xlfd, "-ocr"));
- Bool italic_p = (!!strcasestr (xlfd, "-i-") ||
- !!strcasestr (xlfd, "-o-"));
- Bool fixed_p = (!!strcasestr (xlfd, "courier") ||
- !!strcasestr (xlfd, "-ocr") ||
- !!strcasestr (xlfd, "-m-") ||
- !!strcasestr (xlfd, "-c-"));
- int size = 0;
+ char *token = strdup (font_list);
+ char *otoken = token;
+ char *name2, *lasts;
+ if (!token) abort();
+ while ((name2 = strtok_r (token, ",", &lasts)))
+ {
+ int L;
+ token = 0;
+
+ /* Strip leading and trailing whitespace */
+ while (*name2 == ' ' || *name2 == '\t' || *name2 == '\n')
+ name2++;
+ L = strlen(name2);
+ while (L && (name2[L-1] == ' ' || name2[L-1] == '\t' ||
+ name2[L-1] == '\n'))
+ name2[--L] = 0;
+
+ if (font_name) free (font_name);
+ font_name = font_name_to_xlfd (name2);
# ifdef DEBUG
- fprintf (stderr, "%s: failed %s\n", progname, xlfd);
+ fprintf (stderr, "%s: trying \"%s\" as \"%s\"\n", progname,
+ name2, font_name);
# endif
- if (!strcmp (xlfd, "vga")) /* BSOD uses this: it has no XLFD name. */
- fixed_p = True, size = 120;
+ f = LOADFONT (font_name);
- /* Look for the first number in the string like "-180-" */
- if (! size)
- {
- const char *s;
- for (s = xlfd; *s; s++)
- if (s[0] == '-' && s[1] >= '0' && s[1] <= '9')
- {
- int i = s[1] - '0';
- const char *s2 = s+2;
- while (*s2 >= '0' && *s2 <= '9')
- {
- i = i * 10 + *s2 - '0';
- s2++;
- }
- if (*s2 != '-') continue; /* Number ends with dash */
- if (i < 60 || i >= 2000) continue; /* In range 6pt - 200pt */
- if (i % 10) continue; /* Multiple of 10 */
-
- size = i;
- break;
- }
- }
+# ifdef USE_XFT
+ /* If we did not get an exact match for the font family we requested,
+ reject this font and try the next one in the list. */
+ if (f && xft_p && xlfd_substituted_p (f, font_name))
+ {
+ if (fallback)
+ UNLOADFONT (fallback);
+ fallback = f;
+ f = 0;
+ }
+# ifdef DEBUG
+ else if (!f)
+ fprintf (stderr, "%s: no match for \"%s\"\n", progname, font_name);
+# endif
+# endif /* USE_XFT */
- if (! size)
- {
- fprintf (stderr, "%s: unloadable, unparsable font: \"%s\"\n",
- progname, xlfd);
- xlfd = "fixed";
- return LOADFONT(xlfd);
+ if (f) break;
}
- else
+ free (otoken);
+ if (!font_name) abort();
+
+ /* If the last font in the list was an Xft pattern that matched but
+ was inexact, use it. */
+ if (!f)
{
- const char *variable[] = {
- "helvetica",
- "arial",
- "bitstream vera sans",
- "gill sans",
- "times",
- "times new roman",
- "new century schoolbook",
- "utopia",
- "palatino",
- "lucida",
- "bitstream charter",
-
- /* Don't use a wildcard family. If none of the above worked, then
- then almost none of the X11 fonts are installed, and it's not
- unlikely that "-*-*-medium-r-*-*-*-140-*-*-*-10646-1" will
- match an Arabic or or Japanese font that contains no Latin
- glyphs at all, even in a Latin locale. So in that case, just
- let "helvetica" fall back to "fixed".
- */
- /* "*" */
- };
- const char *fixed[] = {
- "courier",
- "courier new",
- "courier 10 pitch",
- "lucidatypewriter",
- "american typewriter",
- "fixed",
- "ocr a std",
- /* As above, but "can't happen" because we already tried fixed? */
- /* "*" */
- };
- const char *charsets[] = { "iso10646-1", "iso8859-1", "*-*" };
- const char *weights[] = { "bold", "medium" };
- const char *slants[] = { "o", "i", "r" };
- const char *spacings[] = { "m", "c", "p" };
- int a, b, c, d, e, g;
- char buf[1024];
-
- for (a = 0; a < countof(charsets); a++)
- for (b = (bold_p ? 0 : 1); b < countof(weights); b++)
- for (c = (italic_p ? 0 : 2); c < countof(slants); c++)
- for (d = 0;
- d < (fixed_p ? countof(fixed) : countof(variable));
- d++)
- for (g = size; g >= 60; g -= 10)
- for (e = (fixed_p ? 0 : 2); e < countof(spacings); e++)
- {
- sprintf (buf,
- "-%s-%s-%s-%s-%s-%s-%s-%d-%s-%s-%s-%s-%s",
- "*", /* foundry */
- (fixed_p ? fixed[d] : variable[d]),
- weights[b],
- slants[c],
- "*", /* set width */
- "*", /* add style */
- "*", /* pixel size */
- g, /* point size */
- "*", /* x resolution */
- "*", /* y resolution */
- spacings[e],
- "*", /* average width */
- charsets[a]);
-# ifdef DEBUG
- fprintf(stderr, "%s: trying %s\n", progname, buf);
-# endif
- f = LOADFONT(buf);
- if (f)
- {
-# ifdef DEBUG
- fprintf (stderr,
- "%s: substituted \"%s\" for \"%s\"\n",
- progname, buf, xlfd);
-# endif
- return f;
- }
- }
-
- fprintf (stderr, "%s: unable to find any alternatives to \"%s\"\n",
- progname, xlfd);
- xlfd = "fixed";
- return LOADFONT(xlfd);
+ f = fallback;
+ fallback = 0;
}
}
-# endif /* !HAVE_JWXYZ */
+
+ if (!font_name) abort();
+ if (!f) abort();
+
+# ifdef DEBUG
+ if (f && font_name)
+ fprintf (stderr, "%s:%s loaded %s\n", progname,
+ (xft_p ? " XFT:" : ""), font_name);
+# if defined(USE_XFT) && defined(HAVE_XFT)
+ if (xft_p && f)
+ {
+ XftPattern *p = ((XftFont *) f)->pattern;
+ char name[1024];
+ char *s, *s1, *s2, *s3;
+ XftNameUnparse (p, name, sizeof(name)-1);
+ s = strstr (name, ":style=");
+ s1 = (s ? strstr (s+1, ",") : 0);
+ s2 = (s ? strstr (s+1, ":") : 0);
+ s3 = (s1 && s1 < s2 ? s1 : s2);
+ if (s3) strcpy (s3+1, " [...]");
+ fprintf (stderr, "%s: XFT name: %s\n", progname, name);
+ }
+# endif /* USE_XFT && HAVE_XFT */
+# endif /* DEBUG */
+
+ if (fallback) UNLOADFONT (fallback);
+ if (font_name) free (font_name);
+ return f;
}
+
+#if 1 /* No longer used in XScreenSaver 6.
+ (Used by retired flag, juggle, xsublim) */
XFontStruct *
-load_font_retry (Display *dpy, const char *xlfd)
+load_font_retry (Display *dpy, const char *font_list)
{
- return (XFontStruct *) load_font_retry_1 (dpy, 0, xlfd, 0);
+ return (XFontStruct *) load_font_retry_1 (dpy, 0, font_list, 0);
}
+#endif
-#ifdef USE_XFT
+#if defined(USE_XFT) || defined(HAVE_JWXYZ)
XftFont *
-load_xft_font_retry (Display *dpy, int screen, const char *xlfd)
+load_xft_font_retry (Display *dpy, int screen, const char *font_list)
{
- return (XftFont *) load_font_retry_1 (dpy, screen, xlfd, 1);
+ return (XftFont *) load_font_retry_1 (dpy, screen, font_list, 1);
}
+#endif
-#elif defined(HAVE_JWXYZ)
-XftFont *
-load_xft_font_retry (Display *dpy, int screen, const char *xlfd)
+
+#ifdef SELFTEST
+static void
+xft_selftest (Display *dpy, int screen)
{
- return XftFontOpenXlfd (dpy, screen, xlfd);
-}
+ int i;
+ const char *tests[] = {
+ "-*-ocr a std-medium-r-*-*-*-480-*-*-m-*-*-*",
+ "OCR A Std-48",
+ "OCR A Std-48:style=Bold Italic",
+ "OCR A Std-48:spacing=100",
+ "OCR A Std-48:spacing=110",
+ "-*-courier-medium-r-*-*-*-480-*-*-m-*-*-*",
+ "-*-courier-bold-o-*-*-*-480-*-*-m-*-*-*",
+ "Courier-48:style=Bold Italic",
+ "Courier-48:style=Italic Bold", /* seems to be illegal */
+ "Courier-48:spacing=100",
+ "Courier-48:spacing=110",
+ "-*-helvetica-bold-o-*-*-*-480-*-*-m-*-*-*",
+ "Helvetica-48:style=Bold Italic",
+ "Liberation Mono-48:style=Bold Italic",
+ "Liberation Sans-48:style=Bold Italic",
+ "-*-sans serif-bold-o-*-*-*-480-*-*-m-*-*-*",
+ "-*-sans-serif-bold-o-*-*-*-480-*-*-m-*-*-*",
+ "-*-sans\\-serif-bold-o-*-*-*-480-*-*-m-*-*-*",
+ };
+
+ const char *tests2[] = { "Helvetica 10",
+ "Helvetica Bold 10",
+ "Helvetica Bold Italic 10",
+ "Helvetica Oblique Bold-10.5",
+ "Times New Roman-10",
+ "Times New Roman Bold-10",
+ "Times New Roman-Bold Oblique Italic 10",
+ "Times New Roman-Oblique Italic Bold 10",
+ "Times-20:style=Bold",
+ "Times-Oblique-20:style=Bold",
+ "sans serif-20:style=Bold",
+ "sans-serif-20:style=Bold",
+ "sans\\-serif-20:style=Bold",
+ };
+
+ fprintf (stderr, "\n");
+ for (i = 0; i < countof(tests2); i++)
+ fprintf (stderr, "%s\n%s\n\n", tests2[i], font_name_to_xlfd (tests2[i]));
+
+ fprintf (stderr, "\n");
+ for (i = 0; i < countof(tests); i++) {
+ const char *name1 = tests[i];
+ XftResult ret;
+ XftPattern *pat1 = 0, *pat2 = 0, *pat3 = 0;
+ char name2[1024], name3[1024];
+ XftFont *ff;
+ Bool xlfd_p = (*name1 == '-');
-#endif /* !HAVE_JWXYZ */
+# define TRUNC(V) do { \
+ char *s = strstr (V, ":style="); \
+ char *s1 = (s ? strstr (s+1, ",") : 0); \
+ char *s2 = (s ? strstr (s+1, ":") : 0); \
+ char *s3 = (s1 && s1 < s2 ? s1 : s2); \
+ if (s3) strcpy (s3+1, " [...]"); \
+ } while(0)
+
+ *name2 = 0;
+
+ /* Name to Parse */
+
+ if (xlfd_p)
+ pat1 = XftXlfdParse (name1, True, True);
+ else
+ pat1 = XftNameParse (name1);
+ XftNameUnparse (pat1, name2, sizeof(name2)-1);
+ TRUNC(name2);
+ fprintf (stderr, "%s (\"%s\")\n\t-> \"%s\"\n",
+ (xlfd_p ? "XftXlfdParse" : "XftNameParse"),
+ name1, name2);
+
+
+ /* Name to pattern to Open */
+
+ ff = XftFontOpenPattern (dpy, pat1);
+ if (ff) {
+ pat2 = ff->pattern;
+ XftNameUnparse (pat2, name3, sizeof(name3)-1);
+ } else {
+ pat2 = 0;
+ strcpy (name3, "NULL");
+ }
+ TRUNC(name3);
+ fprintf (stderr, "XftFontOpenPattern (\"%s\")\n\t-> \"%s\"\n",
+ name2, name3);
+
+
+ /* Name to pattern to Match */
+
+ pat2 = XftFontMatch (dpy, screen, pat1, &ret);
+ XftNameUnparse (pat2, name3, sizeof(name3)-1);
+ TRUNC(name3);
+ fprintf (stderr, "XftFontMatch (\"%s\")\n\t-> \"%s\", %s\n",
+ name2, name3,
+ (ret == XftResultMatch ? "Match" :
+ ret == XftResultNoMatch ? "NoMatch" :
+ ret == XftResultTypeMismatch ? "TypeMismatch" :
+ ret == XftResultNoId ? "NoId" : "???"));
+
+
+ /* Name to pattern to Match to Open */
+
+ strcpy (name2, name3);
+ ff = XftFontOpenPattern (dpy, pat2);
+ if (ff) {
+ pat3 = ff->pattern;
+ XftNameUnparse (pat3, name3, sizeof(name3)-1);
+ } else {
+ pat3 = 0;
+ strcpy (name3, "NULL");
+ }
+ TRUNC(name3);
+ fprintf (stderr, "XftFontOpenPattern (\"%s\")\n\t-> \"%s\"\n",
+ name2, name3);
+
+
+ /* Name to Open */
+
+ ff = (xlfd_p
+ ? XftFontOpenXlfd (dpy, screen, name1)
+ : XftFontOpenName (dpy, screen, name1));
+ *name2 = 0;
+ if (ff) {
+ pat1 = ff->pattern;
+ XftNameUnparse (pat1, name2, sizeof(name2)-1);
+ } else {
+ strcpy (name2, "NULL");
+ }
+ TRUNC(name2);
+ fprintf (stderr, "%s (\"%s\")\n\t-> \"%s\"\n",
+ (xlfd_p ? "XftFontOpenXlfd" : "XftFontOpenName"),
+ name1, name2);
+ fprintf (stderr, "\n");
+ }
+
+ exit (0);
+}
+#endif /* SELFTEST */
diff --git a/utils/font-retry.h b/utils/font-retry.h
index 83ba0e0..2611a18 100644
--- a/utils/font-retry.h
+++ b/utils/font-retry.h
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 2018 by Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright © 2018-2021 Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
@@ -12,13 +12,17 @@
#ifndef __FONT_RETRY_H__
#define __FONT_RETRY_H__
-/* Like XLoadQueryFont, but if it fails, it tries some heuristics to
- load something close.
+/* Like XLoadQueryFont, XftFontOpenXlfd or XftFontOpenName, except that the
+ argument can be a comma-separated list of font names. Each name can be
+ either an XLFD or Xft pattern. Returns the first exact match it finds, or
+ if there is no exact match, applies heuristics to the last font in the list
+ until it finds a substitution.
*/
-extern XFontStruct *load_font_retry (Display *, const char *xlfd);
+extern XFontStruct *load_font_retry (Display *, const char *font_list);
# ifdef __XSCREENSAVER_XFT_H__ /* if xft.h has been included */
-extern XftFont *load_xft_font_retry (Display *, int screen, const char *xlfd);
+extern XftFont *load_xft_font_retry (Display *, int screen,
+ const char *font_list);
# endif
#endif /* __FONT_RETRY_H__ */
diff --git a/utils/grabclient.c b/utils/grabclient.c
index abe069b..58db732 100644
--- a/utils/grabclient.c
+++ b/utils/grabclient.c
@@ -127,11 +127,11 @@ typedef struct {
XtInputId pipe_id;
FILE *pipe;
-# if !defined(USE_IPHONE) && !defined(HAVE_COCOA) /* Real X11 */
+# if !defined(HAVE_IPHONE) && !defined(HAVE_COCOA) /* Real X11 */
pid_t pid;
# endif
-# if !defined(USE_IPHONE) && defined(HAVE_COCOA) /* Desktop OSX */
+# if !defined(HAVE_IPHONE) && defined(HAVE_COCOA) /* Desktop OSX */
char *directory;
# endif
@@ -236,7 +236,6 @@ checkerboard (Screen *screen, Drawable drawable)
win_width = xgwa.width;
win_height = xgwa.height;
cmap = xgwa.colormap;
- screen = xgwa.screen;
}
else /* it's a pixmap */
{
@@ -564,7 +563,7 @@ load_random_image_x11 (Screen *screen, Window window, Drawable drawable,
#elif defined (HAVE_COCOA) /* OSX or iOS */
-# ifndef USE_IPHONE /* HAVE_COCOA && !USE_IPHONE -- desktop OSX */
+# ifndef HAVE_IPHONE /* HAVE_COCOA && !HAVE_IPHONE -- desktop OSX */
# define BACKSLASH(c) \
(! ((c >= 'a' && c <= 'z') || \
@@ -699,7 +698,7 @@ xscreensaver_getimage_file_cb (XtPointer closure, int *source, XtInputId *id)
}
-# else /* HAVE_COCOA && USE_IPHONE -- iOS */
+# else /* HAVE_COCOA && HAVE_IPHONE -- iOS */
/* Callback for ios_load_random_image(), called after we have loaded an
image from the iOS device's Photo Library. See grabclient-ios.m.
@@ -753,7 +752,7 @@ ios_load_random_image_cb (void *uiimage, const char *filename,
free (clo2);
}
-# endif /* HAVE_COCOA && USE_IPHONE */
+# endif /* HAVE_COCOA && HAVE_IPHONE */
static void
@@ -774,7 +773,7 @@ osx_load_image_file_async (Screen *screen, Window xwindow, Drawable drawable,
clo2->callback = callback;
clo2->closure = closure;
-# ifndef USE_IPHONE /* Desktop OSX */
+# ifndef HAVE_IPHONE /* Desktop OSX */
clo2->directory = strdup (dir);
clo2->pipe = open_image_name_pipe (dir);
clo2->pipe_id = XtAppAddInput (XtDisplayToApplicationContext (
@@ -782,14 +781,14 @@ osx_load_image_file_async (Screen *screen, Window xwindow, Drawable drawable,
fileno (clo2->pipe),
(XtPointer) (XtInputReadMask | XtInputExceptMask),
xscreensaver_getimage_file_cb, (XtPointer) clo2);
-# else /* USE_IPHONE */
+# else /* HAVE_IPHONE */
{
XWindowAttributes xgwa;
XGetWindowAttributes (DisplayOfScreen (screen), xwindow, &xgwa);
ios_load_random_image (ios_load_random_image_cb, clo2,
xgwa.width, xgwa.height);
}
-# endif /* USE_IPHONE */
+# endif /* HAVE_IPHONE */
}
@@ -828,13 +827,13 @@ load_random_image_cocoa (Screen *screen, Window window, Drawable drawable,
geom.width = xgwa.width;
geom.height = xgwa.height;
-# ifndef USE_IPHONE
+# ifndef HAVE_IPHONE
if (filep)
dir = get_string_resource (dpy, "imageDirectory", "ImageDirectory");
if (!dir || !*dir)
filep = False;
-# endif /* ! USE_IPHONE */
+# endif /* ! HAVE_IPHONE */
if (deskp && filep) {
deskp = !(random() & 5); /* if both, desktop 1/5th of the time */
diff --git a/utils/grabscreen.c b/utils/grabscreen.c
index 77fe3c9..e2742bf 100644
--- a/utils/grabscreen.c
+++ b/utils/grabscreen.c
@@ -25,10 +25,8 @@
On MacOS systems running X11, which nobody does any more:
- "driver/xscreensaver-getimage" runs the Perl script
- "driver/xscreensaver-getimage-desktop", which in turn runs the MacOS
- program "/usr/sbin/screencapture" to get the Mac desktop image as a
- PNG file.
+ "driver/xscreensaver-getimage" runs "/usr/sbin/screencapture" to
+ get the Mac desktop image as a PNG.
On MacOS systems running the native Cocoa build, or on iOS or Android
systems:
@@ -48,14 +46,6 @@
#include <X11/Xatom.h>
#include <X11/Xutil.h>
-#ifdef HAVE_XMU
-# ifndef VMS
-# include <X11/Xmu/WinUtil.h>
-# else /* VMS */
-# include <Xmu/WinUtil.h>
-# endif /* VMS */
-#endif
-
#include "usleep.h"
#include "colors.h"
#include "grabscreen.h"
@@ -264,10 +254,7 @@ install_screen_colormaps (Screen *screen)
{
XWindowAttributes xgwa;
Window client;
-#ifdef HAVE_XMU
- /* #### need to put XmuClientWindow() in xmu.c, sigh... */
- if (! (client = XmuClientWindow (dpy, kids[i])))
-#endif
+ /* if (! (client = XmuClientWindow (dpy, kids[i]))) */
client = kids[i];
xgwa.colormap = 0;
XGetWindowAttributes (dpy, client, &xgwa);
diff --git a/utils/grabscreen.h b/utils/grabscreen.h
index 40054c8..a17e671 100644
--- a/utils/grabscreen.h
+++ b/utils/grabscreen.h
@@ -92,14 +92,14 @@ extern Bool osx_load_image_file (Screen *, Window, Drawable,
const char *filename, XRectangle *geom_ret);
#endif /* HAVE_JWXYZ */
-#ifdef USE_IPHONE
+#ifdef HAVE_IPHONE
extern void ios_load_random_image (void (*callback) (void *uiimage,
const char *filename,
int w, int h,
void *closure),
void *closure,
int width, int height);
-#endif /* USE_IPHONE */
+#endif /* HAVE_IPHONE */
#ifdef HAVE_ANDROID
char *jwxyz_draw_random_image (Display *dpy, /* utils/grabclient.c */
diff --git a/utils/images/logo-180.xpm b/utils/images/logo-180.xpm
index b093c8f..c61837c 100644
--- a/utils/images/logo-180.xpm
+++ b/utils/images/logo-180.xpm
@@ -1,13 +1,14 @@
/* XPM */
/* XScreenSaver Logo, designed by Angela Goodman <rzr_grl@yahoo.com>
- Copyright (c) 2001, 2002 by Jamie Zawinski <jwz@jwz.org>
+ Copyright © 2001-2021 Jamie Zawinski <jwz@jwz.org>
Unauthorized use or reproduction prohibited.
https://www.jwz.org/xscreensaver/
*/
static const char * const logo_180_xpm[] = {
+/* columns rows colors chars-per-pixel */
"180 180 16 1",
" c None m None",
") c #FF0000 m #FFFFFF",
@@ -25,6 +26,7 @@ static const char * const logo_180_xpm[] = {
"% c #37332D m #000000",
"& c #2D0C05 m #000000",
"* c #A46E00 m #000000",
+/* pixels */
" ",
" . ",
" .. ",
diff --git a/utils/images/logo-360.gif b/utils/images/logo-360.gif
new file mode 100644
index 0000000..cb53a2c
--- /dev/null
+++ b/utils/images/logo-360.gif
Binary files differ
diff --git a/utils/images/logo-360.xpm b/utils/images/logo-360.xpm
new file mode 100644
index 0000000..b80da2a
--- /dev/null
+++ b/utils/images/logo-360.xpm
@@ -0,0 +1,390 @@
+/* XPM */
+
+/* XScreenSaver Logo, designed by Angela Goodman <rzr_grl@yahoo.com>
+ Copyright © 2001-2021 Jamie Zawinski <jwz@jwz.org>
+ Unauthorized use or reproduction prohibited.
+
+ https://www.jwz.org/xscreensaver/
+ */
+
+static const char * const logo_360_xpm[] = {
+/* columns rows colors chars-per-pixel */
+"360 360 16 1",
+" c None m None",
+"# c #000000 m #000000",
+". c #929291 m #000000",
+"X c #A30204 m #000000",
+"o c #604D28 m #000000",
+"O c #600204 m #000000",
+"+ c #37332D m #000000",
+"@ c #2D0C05 m #000000",
+"_ c #A46E04 m #000000",
+"$ c #DBDBDA m #000000",
+"% c #ED9E04 m #FFFFFF",
+"& c #797977 m #000000",
+"* c #B0B0AE m #000000",
+"= c #FEFEFC m #FFFFFF",
+"- c #4F3504 m #000000",
+"; c #FD0204 m #FFFFFF",
+/* pixels */
+" ",
+" ## ",
+" #### ",
+" ###### ",
+" ###### ",
+" ###### ",
+" ###### ",
+" ####### ",
+" ####### ",
+" ## ####### ",
+" ### ######## ",
+" #### ####### ",
+" ############ ",
+" ###+######### ",
+" +O++######## ",
+" ++X#+######## ",
+" @XX@######### ",
+" @+;O@######## ",
+" ##;;O@######## ",
+" @X;;+@######## ",
+" @+;;;+@####### ",
+" #@X;;X#+#++#### ",
+" @O;;;X@#o###### ",
+" ++;;;;O#oo@#### ",
+" @X;;;;+@_+@#### ",
+" @O;;;;;#+o+##### ",
+" ++;;;;;X#+o@##### ",
+" @X;;;;;O#o+@#### ",
+" @O;;;;;;+@o++#### ",
+" ++;;;;;;;++o@##### ",
+" #+X;;;;;;X@++@#### ",
+" @X;;;;;;;X#++@#### ",
+" @+;;;;;;;;++o#+#### ",
+" ++;;;;;;;;;+++@##### ",
+" @X;;;;;;;;X@++@#### ",
+" @O;;;;;;;;;O@o++#### ",
+" ++;;;;;;;;;;++o@##### ",
+" ##X;;;;;;;;;X@++@#### ",
+" @X;;;;;;;;;;O@o+@#### ",
+" @O;;;;;;;;;;;++o@##### ",
+" @+;;;;;;;;;;;X@oo@#### ",
+" ++;;;;;;;;;;;;O@_+@#### ",
+" +X;;;;;;;;;;;;++_#+#### ",
+" @X;;;;;;;;;;;;X#oo@##### ### ",
+" @O;;;;;;;;;;;;;+@_+@#### ##### ",
+" @+;;;;;;;;;;;;;X@o%++#### ## ##### ",
+" ++;;;;;;;;;;;;;;O#__@##### ### ###### ",
+" +X;;;;;;;;;;;;;;++%+@#### ### ####### ",
+" @X;;;;;;;;;;;;;;O#_%@+#### #### ###### ",
+" @X;;;;;;;;;;;;;;;++%o@#### ### ####### ",
+" @O;;;;;;;;;;;;;;;X#_%+@#### +++# ####### ",
+" @+;;;;;;;;;;;;;;;;++%_@##### #+O# ####### ",
+" @+;;;;;;;;;;;;;;;;O#_%o@#### @O++ ####### ",
+" ++;;;;;;;;;;;;;;;;;@o%%+@#### @+X@ ######## ",
+" ++;;;;;;;;;;;;;;;;;O@%%_@#### #+X+@ ####### ",
+" #X;;;;;;;;;;;;;;;;X@o%%+@#### @OX@# ######## ",
+" @X;;;;;;;;;;;;;;;;;++%%_@#### ++;O@ ######## ",
+" @X;;;;;;;;;;;;;;;;;O#_%%+@#### #@X;++ ######## ",
+" @X;;;;;;;;;;;;;;;;;X#_%%_@#### @+;X+ ######## ",
+" @X;;;;;;;;;;;;;;;;;;+o%%%+@### ##X;O@ ######### ",
+" @X;;;;;;;;;;;;;;;;;;++%%%o@#### @O;;+@######### ",
+" @X;;;;;;;;;;;;;;;;;;O+%%%_@#### ++;;;++######### ",
+" @X;;;;;;;;;;;;;;;;;;X#_%%%++### @O;;X+########## ",
+" @X;;;;;;;;;;;;;;;;;;X#_%%%+@### ++;;;X@########## ",
+" @X;;;;;;;;;;;;;;;;;;X#_%%_@+### #@X;;;O@######### ",
+" @X;;;;;;;;;;;;;;;;;;O@%%%+@#### @+;;;;+@###+##### ",
+" @X;;;;;;;;;;;;;;;;;;++%%_@#### #@X;;;;++##@+++### ",
+" @X;;;;;;;;;;;;;;;;;X@o%%+@#### @+;;;;;++#++_+#### ",
+" #;;;;;;;;;;;;;;;;;;+@_%_@#### #@X;;;;;###@o_@#### ",
+" ++;;;;;;;;;;;;;;;;;X@o%%o@#### @+;;;;;X@#++%o@### ",
+" ++;;;;;;;;;;;;;;;;;+@%%_@+### #@X;;;;;X@#@o%o@### ",
+" @+;;;;;;;;;;;;;;;;X#o%%o@#### @+;;;;;;X@+#%%o@### ",
+" @O;;;;;;;;;;;;;;;;++%%%#+### #@X;;;;;;X@@o%%+@### ",
+" @X;;;;;;;;;;;;;;;X#o%%o@#### @+;;;;;;;X@+_%%+@### ",
+" +X;;;;;;;;;;;;;;;+#%%%+@### @X;;;;;;;X#o%%%++### ",
+" ++;;;;;;;;;;;;;;;X#_%%_@#### ++;;;;;;;;X@_%%%++### ",
+" @+;;;;;;;;;;;;;;;++%%%+@### @X;;;;;;;;X@%%%%#+### ",
+" @O;;;;;;;;;;;;;;X#_%%_@#### ++;;;;;;;;;X@%%%%++### ",
+" #####################################################################################################+X;;;;;;;;;;;;;;++%%%+@#################@O;;;;;;;;;X@%%%_@+########################################################################################################################## ",
+" #######################################################################################################++;;;;;;;;;;;;;;X#_%%_@#################++;;;;;;;;;;X@_%%_@############################################################################################################################## ",
+" ########################################################################################################@O;;;;;;;;;;;;;;++%%%o@#################@O;;;;;;;;;;X#_%%_@############################################################################################################################### ",
+" #########################################################################################################@X;;;;;;;;;;;;;X#_%%_@###################X;;;;;;;;;;X#_%%_@################################################################################################################################ ",
+" #########################################################################################################@+;;;;;;;;;;;;;;++%%%o@#################@+;;;;;;;;;;;X#_%%_@+################################################################################################################################ ",
+" ##########################################################################################################@X;;;;;;;;;;;;;X#_%%%+@#################@X;;;;;;;;;;;X#_%%_++################################################################################################################################# ",
+" #########################################################################################################++;;;;;;;;;;;;;;++%%%_@#################++;;;;;;;;;;;;X@_%%%++################################################################################################################################## ",
+" ##########+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#@X;;;;;;;;;;;;;X#o%%%+@##+@@@@@@@@@@@@@+@O;;;;;;;;;;;;;+o%%%#+##+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@########## ",
+" ########+@@++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++@+;;;;;;;;;;;;;;+#%%%_@###++++++++++++++++X;;;;;;;;;;;;;+o%%%++##+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#@@######## ",
+" ########@@&$=============================================================================================&#X;;;;;;;;;;;;;X#o%%%o@##@&============$++;;;;;;;;;;;;;;++%%%++#@+$===================================================================================================================$&#@######## ",
+" #######+@*==============================================================================================*#O;;;;;;;;;;;;;;++%%%%#+##@*============*#X;;;;;;;;;;;;;;++%%%+@#@+======================================================================================================================*#@####### ",
+" #######@+==============================================================================================$++;;;;;;;;;;;;;;X#o%%%o@##@+=============&@;;;;;;;;;;;;;;;O+%%%+@#+@$======================================================================================================================&@####### ",
+" #######@o==============================================================================================o@X;;;;;;;;;;;;;;O@%%%%+@##@*============$+O;;;;;;;;;;;;;;;X#_%%o@##@*======================================================================================================================&@####### ",
+" #######@o=============================================================================================&#X;;;;;;;;;;;;;;;@o%%%_@##@+=============*#X;;;;;;;;;;;;;;;X#_%%o@##@*======================================================================================================================&@####### ",
+" #######@o============================================================================================&#O;;;;;;;;;;;;;;;O@_%%%+@##@&=============o+;;;;;;;;;;;;;;;;X@_%%o@##@*======================================================================================================================&@####### ",
+" #######@o===========================================================================================&#O;;;;;;;;;;;;;;;;++%%%%++#+@$============$@O;;;;;;;;;;;;;;;;;@o%%_@##@&======================================================================================================================&@####### ",
+" #######@o==========================================================================================*#+;;;;;;;;;;;;;;;;X#_%%%_@##@+=============*#X;;;;;;;;;;;;;;;;;++%%_@##@o======================================================================================================================&@####### ",
+" #######@o=========================================================================================$@+;;;;;;;;;;;;;;;;;++%%%%+@##@*=============&@;;;;;;;;;;;;;;;;;;O+%%%#+#@+======================================================================================================================&@####### ",
+" #######@o========================================================================================$+@X;;;;;;;;;;;;;;;;X#o%%%_@##@#$============$+O;;;;;;;;;;;;;;;;;;O@%%%++#@+======================================================================================================================&@####### ",
+" #######@o========================================================================================o#X;;;;;;;;;;;;;;;;;O@%%%%o@##@o=============*#X;;;;;;;;;;;;;;;;;;X#_%%+@#@#$=====================================================================================================================&@####### ",
+" #######@o=======================================================================================&#O;;;;;;;;;;;;;;;;;;@o%%%%+@##@*=============&@;;;;;;;;;;;;;;;;;;;;@o%%o@##@*=====================================================================================================================&@####### ",
+" #######@o======================================================================================*#+;;;;;;;;;;;;;;;;;;X#_%%%_@##@+==============+O;;;;;;;;;;;;;;;;;;;;++%%o@##@&=====================================================================================================================&@####### ",
+" #######@o=====================================================================================$++;;;;;;;;;;;;;;;;;;;++%%%%o@##@&=============*#X;;;;;;;;;;;;;;;;;;;;O+%%_@##@&=====================================================================================================================&@####### ",
+" #######@o=====================================================================================+@X;;;;;;;;;;;;;;;;;;;@o%%%%+@#+@*=============*@X;;;;;;;;;;;;;;;;;;;;X#_%_@##@+=====================================================================================================================&@####### ",
+" #######@o====================================================================================&#X;;;;;;;;;;;;;;;;;;;O#_%%%_@##@+==============++;;;;;;;;;;;;;;;;;;;;;X#o%%+@#@#$====================================================================================================================&@####### ",
+" #######@o===================================================================================*#+;;;;;;;;;;;;;;;;;;;;++%%%%o@##@&=============$+O;;;;;;;;;;;;;;;;;;;;;;+o%%+@##@*====================================================================================================================&@####### ",
+" #######@o==================================================================================$++;;;;;;;;;;;;;;;;;;;;X@o%%%%+@##@*=============*#X;;;;;;;;;;;;;;;;;;;;;;++%%o@##@&====================================================================================================================&@####### ",
+" #######@o==================================================================================&#X;;;;;;;;;;;;;;;;;;;;X#_%%%_@##@+==============&@;;;;;;;;;;;;;;;;;;;;;;;X#_%_@##@o====================================================================================================================&@####### ",
+" #######@o=================================================================================*#O;;;;;;;;;;;;;;;;;;;;;++%%%%_@##@&==============++;;;;;;;;;;;;;;;;;;;;;;;X@_%%++#@+====================================================================================================================&@####### ",
+" #######@o=================================================================================+@;;;;;;;;;;;;;;;;;;;;;;+o%%%%o@##@*=============$+O;;;;;;;;;;;;;;;;;;;;;;;;++%%+@#+@*===================================================================================================================&@####### ",
+" #######@o==============================================================*+&=====$=========*#X;;;;;;;;;;;;;;;;;;;;;X#_%%%%+@#@#$=============*#X;;;;;;;;;;;;;;;;;;;;;;;;O+%%o@##@*===================================================================================================================&@####### ",
+" #######@o=============================================================*@@@$==$+@+*======$++;;;;;;;;;;;;;;;;;;;;;;O@%%%%_@##@+==============*@X;;;;;;;;;;;;;;;;;;;;;;;;X#_%_@##@o===================================================================================================================&@####### ",
+" #######@o============================================================$++O@$==+@+@+======&#X;;;;;;;;;;;;;;;;;;;;;;++%%%%_@##@&==============&@;;;;;;;;;;;;;;;;;;;;;;;;;;@o%%#+#@+$==================================================================================================================&@####### ",
+" #######@o============================================================&#XX@$=*@##+@$====$#O;;;;;;;;;;;;;;;;;;;;;;;@o%%%%o@##@*==============++;;;;;;;;;;;;;;;;;;;;;;;;;;++%%+@##@*==================================================================================================================&@####### ",
+" #######@o=======================$*&&ooooooooooooooooooooooooooooooooo@O;O@oo+@###+ooooo+@X;;;;;;;;;;;;;;;;;;;;;;X@_%%%%+@##@+oooooooooooooo@O;;;;;;;;;;;;;;;;;;;;;;;;;;O#_%o@##@+ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo&&*$=======================&@####### ",
+" #######@o=====================$&+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#;;O@@@@#####@@@@@#O;;;;;;;;;;;;;;;;;;;;;;;X#_%%%%++###@@@@@@@@@@@@@@@@X;;;;;;;;;;;;;;;;;;;;;;;;;;X@o%_@###@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+&$=====================&@####### ",
+" #######@o====================*+@@###################################@O;;++############+#;;;;;;;;;;;;;;;;;;;;;;;;O@_%%%_@###################+X;;;;;;;;;;;;;;;;;;;;;;;;;;;++%%+@#############################################################################################@@+&====================&@####### ",
+" #######@o===================&@@####################################++;;;##############@O;;;;;;;;;;;;;;;;;;;;;;;;O+%%%%_@####################;;;;;;;;;;;;;;;;;;;;;;;;;;;;O#_%o@###############################################################################################@@&===================&@####### ",
+" #######@o==================&@@#####################################@X;;X@##############;;;;;;;;;;;;;;;;;;;;;;;;;++%%%%_@##################++;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#o%_@#################################################################################################@&==================&@####### ",
+" #######@o=================*@@#####################################++;;;O@############@O;;;;;;;;;;;;;;;;;;;;;;;;;++%%%%o@##################@+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%%+@################################################################################################+@*=================&@####### ",
+" #######@o=================+@######################################@O;;;+@############@X;;;;;;;;;;;;;;;;;;;;;;;;;++%%%%o@##################@O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O@_%o@#################################################################################################@#$================&@####### ",
+" #######@o================*@######################################++;;;;++###########@+;;;;;;;;;;;;;;;;;;;;;;;;;;++%%%%o@##################@O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X@o%_@##################################################################################################@&================&@####### ",
+" #######@o================+@######################################@O;;;X+############@X;;;;;;;;;;;;;;;;;;;;;;;;;;++%%%%+@##################@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%%+@#################################################################################################@+================&@####### ",
+" #######@o===============$@+######################################+X;;;X@#############;;;;;;;;;;;;;;;;;;;;;;;;;;;++%%%%+@##################@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#_%o@##################################################################################################@*===============&@####### ",
+" #######@o===============*@######################################@+;;;;+@###########@+;;;;;;;;;;;;;;;;;;;;;;;;;;;++%%%%+@##################@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;@o%_@##################################################################################################@&===============&@####### ",
+" #######@o===============&@######################################@X;;;;++###########@X;;;;;;;;;;;;;;;;;;;;;;;;;;;++%%%%+@##################@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%%+@#################################################################################################@o===============&@####### ",
+" #######@o===============&@#####################################@+;;;;X@###########++;;;;;;;;;;;;;;;;;;;;;;;;;;;;O+%%%%o@##################+X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#_%_@#################################################################################################@+===============&@####### ",
+" #######@o===============&@#####################################@X;;;;O@###########@+;;;;;;;;;;;;;;;;;;;;;;;;;;;;O@_%%%o@###################X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%%++################################################################################################@+===============&@####### ",
+" #######@o===============&@####################################++;;;;;++###########@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#_%%%o@#################++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#_%o@################################################################################################@+===============&@####### ",
+" #######@o===============&@####################################@O;;;;X#############+X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;@o%%%o@#################++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;@o%%++###############################################################################################@+===============&@####### ",
+" #######@o===============&@####################################+X;;;;X@###########++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%%%_@#################++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O@%%+@###############################################################################################@+===============&@####### ",
+" #######@o===============&@###################################@+;;;;;O@###########@+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O@%%%_@#################++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#o%_@###############################################################################################@+===============&@####### ",
+" #######@o===============&@###################################@X;;;;;+@###########@O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#_%%%+@################++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+#%%+@##############################################################################################@+===============&@####### ",
+" #######@o===============&@####################################;;;;;;+############@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%%%+@#################+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#_%_@##############################################################################################@+===============&@####### ",
+" #######@o===============&@##################################@O;;;;;X@#############;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O#_%%_@##################X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%%+@#############################################################################################@+===============&@####### ",
+" #######@o===============&@##################################@X;;;;;O@###########++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X@o%%%#+################@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#_%_@#############################################################################################@+===============&@####### ",
+" #######@o===============&@#################################++;;;;;;O@###########++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O@%%%+@################@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%%+@############################################################################################@+===============&@####### ",
+" #######@o===============&@#################################@O;;;;;;++###########@O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X@o%%_@################@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#_%_@############################################################################################@+===============&@####### ",
+" #######@o===============&@#################################@X;;;;;;++###########@O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O#_%%++###############@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%%+@###########################################################################################@+===============&@####### ",
+" #######@o===============&@################################++;;;;;;X###+#########@O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;@+%%o@###############@O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#_%_@###########################################################################################@+===============&@####### ",
+" #######@o===============&@################################@O;;;;;;X@#+++########@O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O#_%%#+##############@O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%%+@##########################################################################################@+===============&@####### ",
+" #######@o===============&@#################################X;;;;;;X@##o+########@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%%o@##############@+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#o%_@+#########################################################################################@+===============&@####### ",
+" #######@o===============&@###############################@+;;;;;;;X@@+_@########@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#o%%#+#############++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+#%%o@#########################################################################################@+===============&@####### ",
+" #######@o===============&@###############################@X;;;;;;;O@@__@########@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O#_%o@##############+X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#o%%++########################################################################################@+===============&@####### ",
+" #######@o===============&@###############################+X;;;;;;;O@@%_@########@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%%+@#############@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+@_%_@########################################################################################@+===============&@####### ",
+" #######@o===============&@##############################@+;;;;;;;;+@+%_@########@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#+%_@#############@O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X@+%%+@#######################################################################################@+===============&@####### ",
+" #######@o===============&@##############################@O;;;;;;;;+#o%_@########@O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O#_%o@############++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O#_%_@+######################################################################################@+===============&@####### ",
+" #######@o===============&@##############################+X;;;;;;;;+@_%_@###+@@@@@O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+#_%+@#####@@@@@@@+X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%%o@#####+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@######################################@+===============&@####### ",
+" #######@o===============&@#############################@+;;;;;;;;;++%%%++#++++++@O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%_@####++++++++@O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#o%%+@###++++++++++++++++++++++++++++++++++++++++++++@@####################################@+===============&@####### ",
+" #######@o===============&@#############################@O;;;;;;;;;++%%%#+#@+====++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X@+%o@###@&=====$++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O#_%_@+##@+$========================================$*o@@##################################@+===============&@####### ",
+" #######@o===============&@#############################+X;;;;;;;;;++%%%++#@+====&+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#o%+@##+@*=====&@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#+%%_@###@+===========================================*@@#################################@+===============&@####### ",
+" #######@o===============&@############################++;;;;;;;;;;++%%%++#@+====&@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O#_%+@##@@*====*#X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#o%%o@###@o===========================================*@+################################@+===============&@####### ",
+" #######@o===============&@############################@O;;;;;;;;;;++%%%+@#@#$===*@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+#__@+##@+$====++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O#_%%+@###@&===========================================&@################################@+===============&@####### ",
+" #######@o===============&@############################@X;;;;;;;;;;++%%%o@##@*===$@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+@__@###@+$===*#X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+@_%%+@##+@&==========================================$+@###############################@+===============&@####### ",
+" #######@o===============&@###########################++;;;;;;;;;;;++%%%o@##@*====+O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X++%o@###@o===$++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X@+%%_@+##+@&==========================================&@###############################@+===============&@####### ",
+" #######@o===============&@###########################@+;;;;;;;;;;;++%%%o@##@*====o+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X@+%+@###@&===&@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#+%%_@+##+@&=========================================*@###############################@+===============&@####### ",
+" #######@o===============&@###########################@X;;;;;;;;;;;O+%%%_@##@&====&@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#o%+@###@*==$@O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O#o%%o@###+@&========================================*@###############################@+===============&@####### ",
+" #######@o===============&@###########################@X;;;;;;;;;;;X@%%%_@##@+====*#X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O#o_@+##@@*==&@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O#o%%o@###+@*=======================================*@###############################@+===============&@####### ",
+" #######@o===============&@##########################++;;;;;;;;;;;;X#_%%%++#@+=====++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+#__@+##@@*=$@+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+#_%%o@###@+$======================================*@###############################@+===============&@####### ",
+" #######@o===============&@##########################@O;;;;;;;;;;;;X#_%%%+@#@+$====&@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+#_o@###@+$=&#X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%%%o@###@&======================================*@###############################@+===============&@####### ",
+" #######@o===============&@##########################@X;;;;;;;;;;;;X@_%%%o@##@*====*#X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+@_o@###@+$=++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X@+%%%o@##+@*=====================================*@###############################@+===============&@####### ",
+" #######@o===============&@###########################X;;;;;;;;;;;;;@o%%%o@##@&=====++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#+_+@###@o=*#X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#o%%%+@##@o=====================================*@###############################@+===============&@####### ",
+" #######@o===============&@#########################++;;;;;;;;;;;;;;+o%%%_@##@&=====&@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X@+_+@###@&=+@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+@_%%_@###@*====================================*@###############################@+===============&@####### ",
+" #######@o===============&@#########################@O;;;;;;;;;;;;;;++%%%%++#@+=====$#O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#o%+@###@**#O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;@+%%%+@##@o====================================*@###############################@+===============&@####### ",
+" #######@o===============&@#########################@X;;;;;;;;;;;;;;O@%%%%+@#+@$=====++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O#o_+@##@@*&@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#_%%_@##+@$===================================*@###############################@+===============&@####### ",
+" #######@o===============&@##########################;;;;;;;;;;;;;;;X#_%%%o@##@&=====*#X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O#__@+##@+&+O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%%%+@##@&===================================*@###############################@+===============&@####### ",
+" #######@o===============&@########################++;;;;;;;;;;;;;;;;@o%%%_@##@o======++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+@%_@###@++@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#o%%_@##@+$==================================*@###############################@+===============&@####### ",
+" #######@o===============&@########################@+;;;;;;;;;;;;;;;;++%%%%#+#@+$=====&@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%o@###@+@O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O@_%%+@##@*==================================*@###############################@+===============&@####### ",
+" #######@o===============&@########################@O;;;;;;;;;;;;;;;;O@%%%%+@##@*=====*#O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#o%+@###+#+X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;@o%%_@##@+==================================*@###############################@+===============&@####### ",
+" #######@o===============&@########################@X;;;;;;;;;;;;;;;;X#_%%%o@##@&======++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O#_%#@####@+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O#_%%++##@*=================================*@###############################@+===============&@####### ",
+" #######@o===============&@########################+;;;;;;;;;;;;;;;;;X@o%%%_@##@+======*#X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%_@+####+X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;@+%%o@##@&=================================*@###############################@+===============&@####### ",
+" #######@o===============&@#######################++;;;;;;;;;;;;;;;;;;++%%%%+@##@*======++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#o%o@####@+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O#_%_@##@+$================================*@###############################@+===============&@####### ",
+" #######@o===============&@#######################@O;;;;;;;;;;;;;;;;;;O@%%%%o@##@&======&#X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O#_%+@####@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;@o%%+@##@*================================*@###############################@+===============&@####### ",
+" #######@o===============&@#######################@X;;;;;;;;;;;;;;;;;;X#_%%%_@##@+======$++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%%#+###@+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O#_%o@##@&================================*@###############################@+===============&@####### ",
+" #######@o===============&@#######################@X;;;;;;;;;;;;;;;;;;;++%%%%+@##@*======&@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#o%_@####@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;@o%_@##@+================================*@###############################@+===============&@####### ",
+" #######@o===============&@######################++;;;;;;;;;;;;;;;;;;;;O@_%%%o@##@&======$@O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O#_%+@###@+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O@%%+@##@*===============================*@###############################@+===============&@####### ",
+" #######@o===============&@######################++;;;;;;;;;;;;;;;;;;;;X#o%%%_@##@+$======&@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%%#+###@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#o%o@##@&===============================*@###############################@+===============&@####### ",
+" #######@o===============&@######################@+;;;;;;;;;;;;;;;;;;;;;++%%%%+@##@&======*#O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#_%o@###@+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%_@##@+===============================*@###############################@+===============&@####### ",
+" #######@o===============&@######################@O;;;;;;;;;;;;;;;;;;;;;X#_%%%_@##@+=======+@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%%+@###@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#_%+@##@*==============================*@###############################@+===============&@####### ",
+" #######@o===============&@######################@O;;;;;;;;;;;;;;;;;;;;;;+o%%%%++##@*======*#X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#_%_@###@+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%o@##@&==============================*@###############################@+===============&@####### ",
+" #######@o===============&@######################@X;;;;;;;;;;;;;;;;;;;;;;O@%%%%o@##@&=======++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%%+@###@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O#%_@##@o==============================*@###############################@+===============&@####### ",
+" #######@o===============&@#######################X;;;;;;;;;;;;;;;;;;;;;;X@o%%%_@##+@$======*#X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#_%_@###@+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X@o%++#@#$=============================*@###############################@+===============&@####### ",
+" #######@o===============&@#####################++;;;;;;;;;;;;;;;;;;;;;;;;++%%%%+@##@&======$++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%%+@###+X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%+@##@*=============================*@###############################@+===============&@####### ",
+" #######@o===============&@#####################++;;;;;;;;;;;;;;;;;;;;;;;;X#_%%%_@##@@$======&#X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O#_%_@###@O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#__@##@&=============================*@###############################@+===============&@####### ",
+" #######@o===============&@#####################@+;;;;;;;;;;;;;;;;;;;;;;;;;++%%%%+@##@&======$++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;@o%%+@##++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+o_@##@+=============================*@###############################@+===============&@####### ",
+" #######@o===============&@#####################@O;;;;;;;;;;;;;;;;;;;;;;;;;X#_%%%_@##@+$======&#X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O@%%_@###@O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%+@#+@$============================*@###############################@+===============&@####### ",
+" #######@o===============&@#####################@O;;;;;;;;;;;;;;;;;;;;;;;;;;++%%%%+@##@&======$@+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#o%%+@##++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#_o@##@*============================*@###############################@+===============&@####### ",
+" #######@o===============&@#####################@O;;;;;;;;;;;;;;;;;;;;;;;;;;X#_%%%_@##@+$======&@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%%o@###@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;@o_@##@&============================*@###############################@+===============&@####### ",
+" #######@o===============&@#####################@X;;;;;;;;;;;;;;;;;;;;;;;;;;;++%%%%+@##@&======$@O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O@_%_@###@+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O+_++#@+============================*@###############################@+===============&@####### ",
+" #######@o===============&@#####################@X;;;;;;;;;;;;;;;;;;;;;;;;;;;X#o%%%_@##@@$======&@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X@o%%+@####;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#_+@#+@$===========================*@###############################@+===============&@####### ",
+" #######@o===============&@#####################+X;;;;;;;;;;;;;;;;;;;;;;;;;;;;+@%%%%+@##@&======$#O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%%_@###@O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+oo@##@*===========================*@###############################@+===============&@####### ",
+" #######@o===============&@######################X;;;;;;;;;;;;;;;;;;;;;;;;;;;;X@o%%%_@##+@*======o@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#_%%+@##++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++o@##@&===========================*@###############################@+===============&@####### ",
+" #######@o===============&@######################;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O#_%%%+@##@o======*#O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%%o@###+X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X@o+##@+===========================*@###############################@+===============&@####### ",
+" #######@o===============&@#####################+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%%%_@###@*======o@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O#_%_@###@O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X@o+@#++$==========================*@###############################@+===============&@####### ",
+" #######@o===============&@####################++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#_%%%+@##@+======*#O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;@+%%+@##@+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++o@##@*==========================*@###############################@+===============&@####### ",
+" #######@o===============&@####################++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%%%_@###@&======++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#o%_@##++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O+o@##@&==========================*@###############################@+===============&@####### ",
+" #######@o===============&@####################++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X@o%%%o@##@+$=====*#X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+#_%+@##+X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X@o+##@o==========================*@###############################@+===============&@####### ",
+" #######@o===============&@#####################+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O#_%%%++##@&======++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+#__+##@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++++#@+==========================*@###############################@+===============&@####### ",
+" #######@o===============&@######################;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%%%o@##+@*=====*#X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+#o+@#@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++++#+@$=========================*@###############################@+===============&@####### ",
+" #######@o===============&@######################X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X@o%%%+@##@+=====$++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O#+#+#;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O@++##@*=========================*@###############################@+===============&@####### ",
+" #######@o===============&@#####################+X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O#_%%_@###@&=====&#X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X+#+O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X++###@&=========================*@###############################@+===============&@####### ",
+" #######@o===============&@#####################@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%%%o@##@#$====$++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+####@+=========================*@###############################@+===============&@####### ",
+" #######@o===============&@#####################@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X@+%%%#+##@o=====&@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O@###@+$========================*@###############################@+===============&@####### ",
+" #######@o===============&@#####################@O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O#_%%o@###@*====$@O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X@###+@*========================*@###############################@+===============&@####### ",
+" #######@o===============&@#####################@O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+@_%%+@##@+=====o@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X+####@*========================*@###############################@+===============&@####### ",
+" #######@o===============&@#####################@+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%%_@###@&====*#O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++###@&========================*@###############################@+===============&@####### ",
+" #######@o===============&@#####################++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#o%%o@##@@$====++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+@###@o========================*@###############################@+===============&@####### ",
+" #######@o===============&@######################+X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O#_%%++##@o====*#X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O@###@+========================*@###############################@+===============&@####### ",
+" #######@o===============&@######################@O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+@_%_@###@*====++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X@###+@$=======================*@###############################@+===============&@####### ",
+" #######@o===============&@######################@+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X@+%%+@##@+====&@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#####@*=======================*@###############################@+===============&@####### ",
+" #######@o===============&@######################++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#o%_@+##@&===*#X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++###@&=======================*@###############################@+===============&@####### ",
+" #######@o===============&@#######################@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O#_%o@##@@*===++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+@###@o=======================*@###############################@+===============&@####### ",
+" #######@o===============&@#######################@+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+@%%+@##@+===&@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O@###@+=======================*@###############################@+===============&@####### ",
+" #######@o===============&@########################+X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X@+%_@###@*==*#X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X@###@+$======================*@###############################@+===============&@####### ",
+" #######@o===============&@########################@O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#o%+@##@+===++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#####@*======================*@###############################@+===============&@####### ",
+" #######@o===============&@########################++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+#_%@+##@*==o@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++###@*======================*@###############################@+===============&@####### ",
+" #######@o===============&@#########################@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%o@##@+==*#X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+@###@&======================*@###############################@+===============&@####### ",
+" #######@o===============&@#########################@O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#o%#+##@*=*#X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O@###@&======================*@###############################@+===============&@####### ",
+" #######@o===============&@###########################;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O#_o@##@+==++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O@###@+======================*@###############################@+===============&@####### ",
+" #######@o===============&@##########################@O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++_++##@*=o+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X@###@+$=====================*@###############################@+===============&@####### ",
+" #######@o===============&@##########################++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#oo@##@+=*@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X+###+@$=====================*@###############################@+===============&@####### ",
+" #######@o===============&@###########################@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++_#+#+@$*#X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#####@*=====================*@###############################@+===============&@####### ",
+" #######@o===============&@###########################@+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#_o@##@&$@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++###@&=====================*@###############################@+===============&@####### ",
+" #######@o===============&@############################+X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++_@##@+=+O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+@###@&=====================*@###############################@+===============&@####### ",
+" #######@o===============&@############################@O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#o+@#+#$o+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O@###@+=====================*@###############################@+===============&@####### ",
+" #######@o===============&@##############################;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+++@##@&o+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O@###@+$====================*@###############################@+===============&@####### ",
+" #######@o===============&@#############################@O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X@+###+#++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O@###+@$====================*@###############################@+===============&@####### ",
+" #######@o===============&@#############################++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+@####+@+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X@++##@*====================*@###############################@+===============&@####### ",
+" #######@o===============&@##############################@O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X@#######;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X+++##@&====================*@###############################@+===============&@####### ",
+" #######@o===============&@##############################++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+@+#####;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X++###@&====================*@###############################@+===============&@####### ",
+" #######@o===============&@###############################@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X++++##+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+++##@o====================*@###############################@+===============&@####### ",
+" #######@o===============&@###############################++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X@+++++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+o++#@+====================*@###############################@+===============&@####### ",
+" #######@o===============&@################################@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+@+#@+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+o+@#@+$===================*@###############################@+===============&@####### ",
+" #######@o===============&@################################@+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+@@@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+oo@##@*===================*@###############################@+===============&@####### ",
+" #######@o===============&@###############################@+@O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O+O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+oo@##@*===================*@###############################@+===============&@####### ",
+" #######@o===============&@###############################@*o@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+o_@##@*===================*@###############################@+===============&@####### ",
+" #######@o===============&@###############################@**#O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+o_@##@&===================*@###############################@+===============&@####### ",
+" #######@o===============&@###############################@*=o@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+o%@##@+===================*@###############################@+===============&@####### ",
+" #######@o===============&@###############################@*=*#O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+o%++#@+===================*@###############################@+===============&@####### ",
+" #######@o===============&@###############################@*==o@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+o%+@#@+$==================*@###############################@+===============&@####### ",
+" #######@o===============&@###############################@*==$@+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+o%+@##@*==================*@###############################@+===============&@####### ",
+" #######@o===============&@###############################@*===&#X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+o%o@##@*==================*@###############################@+===============&@####### ",
+" #######@o===============&@###############################@*===$++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;@o%o@##@&==================*@###############################@+===============&@####### ",
+" #######@o===============&@###############################@*====*#X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;@o%_@##@&==================*@###############################@+===============&@####### ",
+" #######@o===============&@###############################@*=====+@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X@_%_@+#@+==================*@###############################@+===============&@####### ",
+" #######@o===============&@###############################@*=====*#O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X@_%%++#@+==================*@###############################@+===============&@####### ",
+" #######@o===============&@###############################@*======&@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O@%%%+@#@+$=================*@###############################@+===============&@####### ",
+" #######@o===============&@###############################@*======$++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%%%o@#@+$=================*@###############################@+===============&@####### ",
+" #######@o===============&@###############################@*=======*#X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;@o%%%o@##@*=================*@###############################@+===============&@####### ",
+" #######@o===============&@###############################@*========+@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#_%%%_@##@&=================*@###############################@+===============&@####### ",
+" #######@o===============&@###############################@*========$@+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O@%%%%_@##@&=================*@###############################@+===============&@####### ",
+" #######@o===============&@###############################@*=========&#X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%%%%+@##@o=================*@###############################@+===============&@####### ",
+" #######@o===============&@###############################@*=========$+@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#_%%%+@###@&=================*@###############################@+===============&@####### ",
+" #######@o===============&@###############################@*==========*#+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O@%%%o@###@+==================*@###############################@+===============&@####### ",
+" #######@o===============&@###############################@*===========&#X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;#+%%o@###@+$==================*@###############################@+===============&@####### ",
+" #######@o===============&@###############################@*============+@;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#_%_@+##@+$===================*@###############################@+===============&@####### ",
+" #######@o===============&@###############################@*============*@+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%%+@##@@*====================*@###############################@+===============&@####### ",
+" #######@o===============&@###############################@*=============&#O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#o%+@###@*=====================*@###############################@+===============&@####### ",
+" #######@o===============&@###############################@*==============+@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++%o@###@&======================*@###############################@+===============&@####### ",
+" #######@o===============&@###############################@*==============$++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#o_@###@+=======================*@###############################@+===============&@####### ",
+" #######@o===============&@###############################@*===============*#+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+#_#+##@+$=======================*@###############################@+===============&@####### ",
+" #######@o===============&@###############################@*================&#X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X@++@##+@*========================*@###############################@+===============&@####### ",
+" #######@o===============&@###############################@*=================+@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+@+@###@&=========================*@###############################@+===============&@####### ",
+" #######@o===============&@###############################@*=================$++;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X@#+###@+==========================*@###############################@+===============&@####### ",
+" #######@o===============&@###############################@*==================*#+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+@####@+$==========================*@###############################@+===============&@####### ",
+" #######@o===============&@###############################@&===================&#O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X@####@@*===========================*@###############################@+===============&@####### ",
+" #######@o===============&@###############################@o====================o#X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++####@*============================&@###############################@+===============&@####### ",
+" #######@o===============&@###############################@+$===================$+@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O@####@&=============================+@###############################@+===============&@####### ",
+" #######@o===============&@################################@&====================$+@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X@####@+=============================*@################################@+===============&@####### ",
+" #######@o===============&@################################+@*====================*@+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;++###@#$============================$#@################################@+===============&@####### ",
+" #######@o===============&@#################################@+*====================*@+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+@###@@*============================*+@#################################@+===============&@####### ",
+" #######@o===============&@##################################@@&$===================*@+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X@###+@*===========================$&+@##################################@+===============&@####### ",
+" #######@o===============&@###################################+@@+oooooooooooooooooo&+@O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#+###+#ooooooooooooooooooooooooooo++@@###################################@+===============&@####### ",
+" #######@o===============&@#####################################@@@@@@@@@@@@@@@@@@@@@+#@O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+@######@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#####################################@+===============&@####### ",
+" #######@o===============&@#############################################################@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O@#########################################################################@+===============&@####### ",
+" #######@o===============&@##############################################################@X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O@##########################################################################@+===============&@####### ",
+" #######@o===============&@##############################################################+#X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X@###########################################################################@+===============&@####### ",
+" #######@o===============&@###############################################################++X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X#+###########################################################################@+===============&@####### ",
+" #######@o===============&@################################################################@+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+@############################################################################@+===============&@####### ",
+" #######@o===============&@#################################################################@+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+@#############################################################################@+===============&@####### ",
+" #######@o===============&@##################################################################@+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+@##############################################################################@+===============&@####### ",
+" #######@o===============&@###################################################################@+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+@###############################################################################@+===============&@####### ",
+" #######@o===============&@####################################################################@+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+@################################################################################@+===============&@####### ",
+" #######@o===============&@#####################################################################@+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+@#################################################################################@+===============&@####### ",
+" #######@o===============&@######################################################################@+X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X+@##################################################################################@+===============&@####### ",
+" #######@o===============&@#######################################################################@+X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X+@###################################################################################@+===============&@####### ",
+" #######@o===============&@########################################################################@#X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X++####################################################################################@+===============&@####### ",
+" #######@o===============&@#########################################################################++X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O@+#####################################################################################@+===============&@####### ",
+" #######@o===============&@##########################################################################+@O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O@#######################################################################################@+===============&@####### ",
+" #######@o===============&@############################################################################@+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X+@########################################################################################@+===============&@####### ",
+" #######@o===============&@#############################################################################@+X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O+@#########################################################################################@+===============&@####### ",
+" #######@o===============&@##############################################################################+@O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X+@###########################################################################################@+===============&@####### ",
+" #######@o===============&@################################################################################@+X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;O+@############################################################################################@+===============&@####### ",
+" #######@o===============&@#################################################################################+@+X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X+@##############################################################################################@o===============&@####### ",
+" #######@o===============*@###################################################################################@#O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X+@+###############################################################################################@&===============&@####### ",
+" #######@o===============$@+####################################################################################@+O;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X+@@#################################################################################################@*===============&@####### ",
+" #######@o================+@#####################################################################################+@+OX;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X+@@##################################################################################################@+================&@####### ",
+" #######@o================*@#######################################################################################+@#+X;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;X+@+####################################################################################################@&================&@####### ",
+" #######@o=================+@#########################################################################################@@+OX;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;XO+#+++###################################################################################################@+$================&@####### ",
+" #######@o=================*@@##########################################################################################+@#+OX;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;XO+#@+_o++##################################################################################################+@*=================&@####### ",
+" #######@o==================*@@############################################################################################@@+++OX;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;XX++#@+o__+@@##################################################################################################+@&==================&@####### ",
+" #######@o===================*@@##############################################################################################+@@@#+OOXXX;;;;;;;;;;;;;;;;;XXOO+@###+_%%%o@@###################################################################################################@@&===================&@####### ",
+" #######@o====================*+@@#################################################################################################+@@@@#+++++++OO+++++++@@##++o__%%%%o#@+##################################################################################################@@+*====================&@####### ",
+" #######@o=====================$&+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#####################+++@@@@@@@@@++oo___%%%%%%%o#@+#################+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+&$=====================&@####### ",
+" #######@o========================**&ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo+@#################################+o_%%%%%%%_o#@+##################++ooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo&&*$=======================&@####### ",
+" #######@o=========================================================================================================$+@#################################+@@#+o_%_o@@+####################+@$=========================================================================================================&@####### ",
+" #######@o=========================================================================================================*@#####################################+@@@+@@+#######################@&=========================================================================================================&@####### ",
+" #######@o=========================================================================================================+@#########################################+##########################@+$========================================================================================================&@####### ",
+" #######@o========================================================================================================*@######################################################################@&========================================================================================================&@####### ",
+" #######@o========================================================================================================+@######################################################################@+$=======================================================================================================&@####### ",
+" #######@o=======================================================================================================*@########################################################################@&=======================================================================================================&@####### ",
+" #######@o=======================================================================================================+@########################################################################@#$======================================================================================================&@####### ",
+" #######@o======================================================================================================&@##########################################################################@+======================================================================================================&@####### ",
+" #######@o=====================================================================================================*@+###########################################################################@&=====================================================================================================&@####### ",
+" #######@o====================================================================================================$+@############################################################################@@*====================================================================================================&@####### ",
+" #######@o===================================================================================================$+@##############################################################################@+$===================================================================================================&@####### ",
+" #######@o===================================================================================================o@################################################################################@+$==================================================================================================&@####### ",
+" #######@o==================================================================================================&@##################################################################################@+$=================================================================================================&@####### ",
+" #######@o=================================================================================================o@####################################################################################@+$================================================================================================&@####### ",
+" #######@o===============================================================================================$o@######################################################################################@+$===============================================================================================&@####### ",
+" #######@o==============================================================================================$+@########################################################################################@+*==============================================================================================&@####### ",
+" #######@o=============================================================================================*+@##########################################################################################@@*=============================================================================================&@####### ",
+" #######@o============================================================================================&@@############################################################################################@@&$===========================================================================================&@####### ",
+" #######@o==========================================================================================*+@@###############################################################################################@+*==========================================================================================&@####### ",
+" #######@o========================================================================================$&@@##################################################################################################@@o*========================================================================================&@####### ",
+" #######@o======================================================================================$&+@+#####################################################################################################@@&$======================================================================================&@####### ",
+" #######@o====================================================================================$&+@@########################################################################################################+@@&*====================================================================================&@####### ",
+" #######@o=================================================================================$*o@@@############################################################################################################@@@+*$=================================================================================&@####### ",
+" #######@o==============================================================================$*&+@@+################################################################################################################+@@+&*$==============================================================================&@####### ",
+" #######@o============================================================================*++@@@######################################################################################################################@@@++*============================================================================&@####### ",
+" #######@o===========================================================================$#@@+###########################################################################################################################@@@*===========================================================================&@####### ",
+" #######@o===========================================================================&@################################################################################################################################@+===========================================================================&@####### ",
+" #######@o===========================================================================o@################################################################################################################################@+===========================================================================&@####### ",
+" #######@o===========================================================================&@################################################################################################################################@+===========================================================================&@####### ",
+" #######@o===========================================================================$#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*===========================================================================&@####### ",
+" #######@o============================================================================*o+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*============================================================================&@####### ",
+" #######@o===============================================================================$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$==============================================================================&@####### ",
+" #######@o==========================================================================================================================================================================================================================================================================================&@####### ",
+" #######@o==========================================================================================================================================================================================================================================================================================&@####### ",
+" #######@o==========================================================================================================================================================================================================================================================================================&@####### ",
+" #######@o==========================================================================================================================================================================================================================================================================================&@####### ",
+" #######@o==========================================================================================================================================================================================================================================================================================&@####### ",
+" #######@o==========================================================================================================================================================================================================================================================================================&@####### ",
+" #######@o==========================================================================================================================================================================================================================================================================================&@####### ",
+" #######@o==========================================================================================================================================================================================================================================================================================&@####### ",
+" #######@+==========================================================================================================================================================================================================================================================================================o@####### ",
+" ########@*========================================================================================================================================================================================================================================================================================*+@####### ",
+" ########@@&$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$&#@######## ",
+" ########+@@++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#@@######## ",
+" ##########+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@########## ",
+" ######################################################################################################################################################################################################################################################################################################### ",
+" ######################################################################################################################################################################################################################################################################################################## ",
+" ###################################################################################################################################################################################################################################################################################################### ",
+" #################################################################################################################################################################################################################################################################################################### ",
+" ################################################################################################################################################################################################################################################################################################## ",
+" ############################################################################################################################################################################################################################################################################################## ",
+" ########################################################################################################################################################################################################################################################################################## ",
+" ",
+" ",
+" ",
+" ",
+" "
+};
diff --git a/utils/images/logo-50.xpm b/utils/images/logo-50.xpm
index 2661a96..b96acc7 100644
--- a/utils/images/logo-50.xpm
+++ b/utils/images/logo-50.xpm
@@ -1,7 +1,7 @@
/* XPM */
/* XScreenSaver Logo, designed by Angela Goodman <rzr_grl@yahoo.com>
- Copyright (c) 2001, 2002 by Jamie Zawinski <jwz@jwz.org>
+ Copyright © 2001-2021 Jamie Zawinski <jwz@jwz.org>
Unauthorized use or reproduction prohibited.
https://www.jwz.org/xscreensaver/
diff --git a/utils/images/logo.pdf b/utils/images/logo.pdf
new file mode 100644
index 0000000..fcb4e5d
--- /dev/null
+++ b/utils/images/logo.pdf
@@ -0,0 +1,1156 @@
+%PDF-1.5 %
+1 0 obj <</Metadata 2 0 R/OCProperties<</D<</ON[5 0 R 28 0 R 50 0 R 72 0 R]/Order 73 0 R/RBGroups[]>>/OCGs[5 0 R 28 0 R 50 0 R 72 0 R]>>/Pages 3 0 R/Type/Catalog>> endobj 2 0 obj <</Length 56941/Subtype/XML/Type/Metadata>>stream
+<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
+<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.3-c011 66.145661, 2012/02/06-14:56:27 ">
+ <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+ <rdf:Description rdf:about=""
+ xmlns:dc="http://purl.org/dc/elements/1.1/">
+ <dc:format>application/pdf</dc:format>
+ <dc:title>
+ <rdf:Alt>
+ <rdf:li xml:lang="x-default">jwz 8.5x11 CMYK</rdf:li>
+ </rdf:Alt>
+ </dc:title>
+ </rdf:Description>
+ <rdf:Description rdf:about=""
+ xmlns:xmp="http://ns.adobe.com/xap/1.0/"
+ xmlns:xmpGImg="http://ns.adobe.com/xap/1.0/g/img/">
+ <xmp:CreatorTool>Adobe Illustrator CS6 (Macintosh)</xmp:CreatorTool>
+ <xmp:CreateDate>2021-02-04T18:07:40-08:00</xmp:CreateDate>
+ <xmp:ModifyDate>2021-02-04T19:52:55-08:00</xmp:ModifyDate>
+ <xmp:MetadataDate>2021-02-04T19:52:55-08:00</xmp:MetadataDate>
+ <xmp:Thumbnails>
+ <rdf:Alt>
+ <rdf:li rdf:parseType="Resource">
+ <xmpGImg:width>228</xmpGImg:width>
+ <xmpGImg:height>256</xmpGImg:height>
+ <xmpGImg:format>JPEG</xmpGImg:format>
+ <xmpGImg:image>/9j/4AAQSkZJRgABAgEASABIAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABAASAAAAAEA&#xA;AQBIAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK&#xA;DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f&#xA;Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgBAADkAwER&#xA;AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA&#xA;AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB&#xA;UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE&#xA;1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ&#xA;qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy&#xA;obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp&#xA;0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo&#xA;+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq7FXYq7FXYq7&#xA;FXYq8K/5yh1eK78tS6DaXU1tqmnG31aa23RLqzLPA3pkEeoYZCrsOw37VCrIv+cevzK/xj5NS0vp&#xA;ueu6MFt73kfilipSGf35KOLH+YE9xir1PFXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXYq7FXY&#xA;q7FXYq7FXYq7FXYq7FXYq7FXkf8Azkd5MtdY8rW+tlP9I0aQrNInwuLS6pFLv4IxRzXbiG8TkZ3W&#xA;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&#xA;0Yq7/Ankf/qXtM/6Q7f/AJoxVNLDTdO062Frp9rDZ2yklYLeNYkBO5IVABviqIxV2KuxV2KuxV2K&#xA;vBv+cvyP8E6KK7nUqgfKCTFIeD/+UR/8GX/sQxVkP5vfk35r8neZ7nV9GtZ59CluDdWF9aBme2Yt&#xA;zCSen8UZjb7L9DtvXYKseH53fmyo4/4mvfh23ZSdvGq1xWm/+V4fmz/1M1596f8ANOK07/leH5s/&#xA;9TNefen/ADTitO/5Xh+bP/UzXn3p/wA04rTv+V4fmz/1M1596f8ANOK07/leH5s/9TNefen/ADTi&#xA;tO/5Xh+bP/UzXn3p/wA04rTv+V4fmz/1M1596f8ANOK07/leH5s/9TNefen/ADTitO/5Xh+bP/Uz&#xA;Xn3p/wA04rTv+V4fmz/1M1596f8ANOK07/leH5s/9TNefen/ADTitO/5Xh+bP/UzXn3p/wA04rTv&#xA;+V4fmz/1M1596f8ANOK07/leH5s/9TNefen/ADTitO/5Xh+bP/UzXn3p/wA04rTv+V4fmz/1M159&#xA;6f8ANOK07/leH5s/9TNefen/ADTitO/5Xh+bP/UzXn3p/wA04rTv+V4fmz/1M1596f8ANOK07/le&#xA;H5s/9TNefen/ADTitO/5Xh+bP/UzXn3p/wA04rTv+V4fmz/1M1596f8ANOK07/leH5s/9TNefen/&#xA;ADTitO/5Xh+bP/UzXn3p/wA04rTv+V4fmz/1M1596f8ANOK0hHm/M38ydSt4na/8w3UdY4AeTxxV&#xA;oW32ijrtyY098VfRn/Qvkn/Kkf8AB/rR/wCIfX/S3r1Po/XuPD0+VK8PS/dcv9l7Yof/2Q==</xmpGImg:image>
+ </rdf:li>
+ </rdf:Alt>
+ </xmp:Thumbnails>
+ </rdf:Description>
+ <rdf:Description rdf:about=""
+ xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/"
+ xmlns:stRef="http://ns.adobe.com/xap/1.0/sType/ResourceRef#"
+ xmlns:stEvt="http://ns.adobe.com/xap/1.0/sType/ResourceEvent#">
+ <xmpMM:OriginalDocumentID>uuid:9E3E5C9A8C81DB118734DB58FDDE4BA7</xmpMM:OriginalDocumentID>
+ <xmpMM:DocumentID>xmp.did:F77F11740720681183D1DC35A180BA8D</xmpMM:DocumentID>
+ <xmpMM:InstanceID>uuid:32b9882d-d735-f340-9045-3cc9a9725e9f</xmpMM:InstanceID>
+ <xmpMM:RenditionClass>proof:pdf</xmpMM:RenditionClass>
+ <xmpMM:DerivedFrom rdf:parseType="Resource">
+ <stRef:instanceID>uuid:5043498c-ce3d-7641-8f33-296bf1a24f51</stRef:instanceID>
+ <stRef:documentID>xmp.did:0380117407206811822ACFB88DCA4B7E</stRef:documentID>
+ <stRef:originalDocumentID>uuid:9E3E5C9A8C81DB118734DB58FDDE4BA7</stRef:originalDocumentID>
+ <stRef:renditionClass>default</stRef:renditionClass>
+ </xmpMM:DerivedFrom>
+ <xmpMM:History>
+ <rdf:Seq>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>saved</stEvt:action>
+ <stEvt:instanceID>xmp.iid:0280117407206811822ADEA6FFA93920</stEvt:instanceID>
+ <stEvt:when>2014-06-05T18:45:01-07:00</stEvt:when>
+ <stEvt:softwareAgent>Adobe Illustrator CS6 (Macintosh)</stEvt:softwareAgent>
+ <stEvt:changed>/</stEvt:changed>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <stEvt:action>saved</stEvt:action>
+ <stEvt:instanceID>xmp.iid:F77F11740720681183D1DC35A180BA8D</stEvt:instanceID>
+ <stEvt:when>2021-02-04T18:07:40-08:00</stEvt:when>
+ <stEvt:softwareAgent>Adobe Illustrator CS6 (Macintosh)</stEvt:softwareAgent>
+ <stEvt:changed>/</stEvt:changed>
+ </rdf:li>
+ </rdf:Seq>
+ </xmpMM:History>
+ </rdf:Description>
+ <rdf:Description rdf:about=""
+ xmlns:illustrator="http://ns.adobe.com/illustrator/1.0/">
+ <illustrator:StartupProfile>Basic RGB</illustrator:StartupProfile>
+ </rdf:Description>
+ <rdf:Description rdf:about=""
+ xmlns:xmpTPg="http://ns.adobe.com/xap/1.0/t/pg/"
+ xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#"
+ xmlns:xmpG="http://ns.adobe.com/xap/1.0/g/">
+ <xmpTPg:NPages>1</xmpTPg:NPages>
+ <xmpTPg:HasVisibleTransparency>False</xmpTPg:HasVisibleTransparency>
+ <xmpTPg:HasVisibleOverprint>False</xmpTPg:HasVisibleOverprint>
+ <xmpTPg:MaxPageSize rdf:parseType="Resource">
+ <stDim:w>8.000000</stDim:w>
+ <stDim:h>8.000000</stDim:h>
+ <stDim:unit>Inches</stDim:unit>
+ </xmpTPg:MaxPageSize>
+ <xmpTPg:PlateNames>
+ <rdf:Seq>
+ <rdf:li>Black</rdf:li>
+ <rdf:li>PANTONE 485 CVC</rdf:li>
+ <rdf:li>PANTONE 152 CVC</rdf:li>
+ </rdf:Seq>
+ </xmpTPg:PlateNames>
+ <xmpTPg:SwatchGroups>
+ <rdf:Seq>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:groupName>Default Swatch Group</xmpG:groupName>
+ <xmpG:groupType>0</xmpG:groupType>
+ <xmpG:Colorants>
+ <rdf:Seq>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>White</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>0.000000</xmpG:cyan>
+ <xmpG:magenta>0.000000</xmpG:magenta>
+ <xmpG:yellow>0.000000</xmpG:yellow>
+ <xmpG:black>0.000000</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>Black</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>75.020996</xmpG:cyan>
+ <xmpG:magenta>67.968300</xmpG:magenta>
+ <xmpG:yellow>67.022202</xmpG:yellow>
+ <xmpG:black>90.164001</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>RGB Red</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>0.000000</xmpG:cyan>
+ <xmpG:magenta>99.398796</xmpG:magenta>
+ <xmpG:yellow>100.000000</xmpG:yellow>
+ <xmpG:black>0.000000</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>RGB Yellow</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>6.198197</xmpG:cyan>
+ <xmpG:magenta>0.000000</xmpG:magenta>
+ <xmpG:yellow>96.514801</xmpG:yellow>
+ <xmpG:black>0.000000</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>RGB Green</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>62.764900</xmpG:cyan>
+ <xmpG:magenta>0.000000</xmpG:magenta>
+ <xmpG:yellow>100.000000</xmpG:yellow>
+ <xmpG:black>0.000000</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>RGB Cyan</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>51.793701</xmpG:cyan>
+ <xmpG:magenta>0.000000</xmpG:magenta>
+ <xmpG:yellow>12.539900</xmpG:yellow>
+ <xmpG:black>0.000000</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>RGB Blue</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>88.366501</xmpG:cyan>
+ <xmpG:magenta>76.916100</xmpG:magenta>
+ <xmpG:yellow>0.000000</xmpG:yellow>
+ <xmpG:black>0.000000</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>RGB Magenta</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>26.990200</xmpG:cyan>
+ <xmpG:magenta>81.640297</xmpG:magenta>
+ <xmpG:yellow>0.000000</xmpG:yellow>
+ <xmpG:black>0.000000</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=193 G=39 B=45</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>16.961897</xmpG:cyan>
+ <xmpG:magenta>97.897301</xmpG:magenta>
+ <xmpG:yellow>92.724503</xmpG:yellow>
+ <xmpG:black>6.744498</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=237 G=28 B=36</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>0.445598</xmpG:cyan>
+ <xmpG:magenta>99.142403</xmpG:magenta>
+ <xmpG:yellow>97.323601</xmpG:yellow>
+ <xmpG:black>0.094599</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=241 G=90 B=36</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>0.000000</xmpG:cyan>
+ <xmpG:magenta>79.803200</xmpG:magenta>
+ <xmpG:yellow>96.874901</xmpG:yellow>
+ <xmpG:black>0.012201</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=247 G=147 B=30</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>0.036597</xmpG:cyan>
+ <xmpG:magenta>50.066399</xmpG:magenta>
+ <xmpG:yellow>98.565605</xmpG:yellow>
+ <xmpG:black>0.000000</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=251 G=176 B=59</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>0.021398</xmpG:cyan>
+ <xmpG:magenta>34.848602</xmpG:magenta>
+ <xmpG:yellow>87.130501</xmpG:yellow>
+ <xmpG:black>0.000000</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=252 G=238 B=33</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>4.513597</xmpG:cyan>
+ <xmpG:magenta>0.000000</xmpG:magenta>
+ <xmpG:yellow>93.188400</xmpG:yellow>
+ <xmpG:black>0.000000</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=217 G=224 B=33</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>18.896801</xmpG:cyan>
+ <xmpG:magenta>0.039703</xmpG:magenta>
+ <xmpG:yellow>98.232994</xmpG:yellow>
+ <xmpG:black>0.000000</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=140 G=198 B=63</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>50.109100</xmpG:cyan>
+ <xmpG:magenta>0.137299</xmpG:magenta>
+ <xmpG:yellow>99.038704</xmpG:yellow>
+ <xmpG:black>0.000000</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=57 G=181 B=74</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>74.615097</xmpG:cyan>
+ <xmpG:magenta>0.000000</xmpG:magenta>
+ <xmpG:yellow>99.703995</xmpG:yellow>
+ <xmpG:black>0.009203</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=0 G=146 B=69</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>86.385902</xmpG:cyan>
+ <xmpG:magenta>17.578400</xmpG:magenta>
+ <xmpG:yellow>100.000000</xmpG:yellow>
+ <xmpG:black>3.823900</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=0 G=104 B=55</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>90.218994</xmpG:cyan>
+ <xmpG:magenta>33.475197</xmpG:magenta>
+ <xmpG:yellow>98.764000</xmpG:yellow>
+ <xmpG:black>26.065498</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=34 G=181 B=115</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>76.195900</xmpG:cyan>
+ <xmpG:magenta>0.000000</xmpG:magenta>
+ <xmpG:yellow>74.978294</xmpG:yellow>
+ <xmpG:black>0.000000</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=0 G=169 B=157</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>78.441994</xmpG:cyan>
+ <xmpG:magenta>9.085202</xmpG:magenta>
+ <xmpG:yellow>45.755695</xmpG:yellow>
+ <xmpG:black>0.027502</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=41 G=171 B=226</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>69.720001</xmpG:cyan>
+ <xmpG:magenta>14.846998</xmpG:magenta>
+ <xmpG:yellow>0.000000</xmpG:yellow>
+ <xmpG:black>0.000000</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=0 G=113 B=188</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>87.536400</xmpG:cyan>
+ <xmpG:magenta>52.645100</xmpG:magenta>
+ <xmpG:yellow>0.000000</xmpG:yellow>
+ <xmpG:black>0.000000</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=46 G=49 B=146</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>99.130203</xmpG:cyan>
+ <xmpG:magenta>96.548401</xmpG:magenta>
+ <xmpG:yellow>3.494298</xmpG:yellow>
+ <xmpG:black>0.500500</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=27 G=20 B=100</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>100.000000</xmpG:cyan>
+ <xmpG:magenta>100.000000</xmpG:magenta>
+ <xmpG:yellow>26.251602</xmpG:yellow>
+ <xmpG:black>24.524302</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=102 G=45 B=145</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>74.520500</xmpG:cyan>
+ <xmpG:magenta>98.516800</xmpG:magenta>
+ <xmpG:yellow>0.940001</xmpG:yellow>
+ <xmpG:black>0.228900</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=147 G=39 B=143</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>49.558197</xmpG:cyan>
+ <xmpG:magenta>99.191299</xmpG:magenta>
+ <xmpG:yellow>1.370299</xmpG:yellow>
+ <xmpG:black>0.109899</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=158 G=0 B=93</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>34.891300</xmpG:cyan>
+ <xmpG:magenta>100.000000</xmpG:magenta>
+ <xmpG:yellow>37.204506</xmpG:yellow>
+ <xmpG:black>10.815602</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=212 G=20 B=90</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>11.844099</xmpG:cyan>
+ <xmpG:magenta>100.000000</xmpG:magenta>
+ <xmpG:yellow>49.249996</xmpG:yellow>
+ <xmpG:black>0.872803</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=237 G=30 B=121</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>0.000000</xmpG:cyan>
+ <xmpG:magenta>97.000099</xmpG:magenta>
+ <xmpG:yellow>20.495903</xmpG:yellow>
+ <xmpG:black>0.000000</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=199 G=178 B=153</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>22.854996</xmpG:cyan>
+ <xmpG:magenta>27.426601</xmpG:magenta>
+ <xmpG:yellow>39.942001</xmpG:yellow>
+ <xmpG:black>0.000000</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=153 G=134 B=117</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>39.844398</xmpG:cyan>
+ <xmpG:magenta>42.853401</xmpG:magenta>
+ <xmpG:yellow>52.529198</xmpG:yellow>
+ <xmpG:black>6.808603</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=115 G=99 B=87</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>50.398998</xmpG:cyan>
+ <xmpG:magenta>53.136497</xmpG:magenta>
+ <xmpG:yellow>60.897202</xmpG:yellow>
+ <xmpG:black>23.593498</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=83 G=71 B=65</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>57.598198</xmpG:cyan>
+ <xmpG:magenta>60.415001</xmpG:magenta>
+ <xmpG:yellow>63.738503</xmpG:yellow>
+ <xmpG:black>41.934799</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=198 G=156 B=109</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>22.671902</xmpG:cyan>
+ <xmpG:magenta>38.394703</xmpG:magenta>
+ <xmpG:yellow>63.668297</xmpG:yellow>
+ <xmpG:black>1.181000</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=166 G=124 B=82</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>31.595303</xmpG:cyan>
+ <xmpG:magenta>49.182903</xmpG:magenta>
+ <xmpG:yellow>73.931496</xmpG:yellow>
+ <xmpG:black>9.890902</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=140 G=98 B=57</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>36.234100</xmpG:cyan>
+ <xmpG:magenta>57.402897</xmpG:magenta>
+ <xmpG:yellow>84.057404</xmpG:yellow>
+ <xmpG:black>22.613901</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=117 G=76 B=36</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>39.169895</xmpG:cyan>
+ <xmpG:magenta>64.104698</xmpG:magenta>
+ <xmpG:yellow>93.441704</xmpG:yellow>
+ <xmpG:black>35.580997</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=96 G=56 B=19</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>41.538094</xmpG:cyan>
+ <xmpG:magenta>69.994698</xmpG:magenta>
+ <xmpG:yellow>97.024498</xmpG:yellow>
+ <xmpG:black>49.155403</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=66 G=33 B=11</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>47.794300</xmpG:cyan>
+ <xmpG:magenta>73.476799</xmpG:magenta>
+ <xmpG:yellow>83.712502</xmpG:yellow>
+ <xmpG:black>68.157501</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>PANTONE 485 CVC</xmpG:swatchName>
+ <xmpG:type>SPOT</xmpG:type>
+ <xmpG:tint>100.000000</xmpG:tint>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:cyan>0.000000</xmpG:cyan>
+ <xmpG:magenta>100.000000</xmpG:magenta>
+ <xmpG:yellow>91.000000</xmpG:yellow>
+ <xmpG:black>0.000000</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>PANTONE 152 CVC</xmpG:swatchName>
+ <xmpG:type>SPOT</xmpG:type>
+ <xmpG:tint>100.000000</xmpG:tint>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:cyan>0.000000</xmpG:cyan>
+ <xmpG:magenta>51.000000</xmpG:magenta>
+ <xmpG:yellow>100.000000</xmpG:yellow>
+ <xmpG:black>0.000000</xmpG:black>
+ </rdf:li>
+ </rdf:Seq>
+ </xmpG:Colorants>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:groupName>Cold</xmpG:groupName>
+ <xmpG:groupType>1</xmpG:groupType>
+ <xmpG:Colorants>
+ <rdf:Seq>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>C=56 M=0 Y=20 K=0</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>55.742699</xmpG:cyan>
+ <xmpG:magenta>0.000000</xmpG:magenta>
+ <xmpG:yellow>19.989300</xmpG:yellow>
+ <xmpG:black>0.000000</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>C=51 M=43 Y=0 K=0</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>51.079601</xmpG:cyan>
+ <xmpG:magenta>43.097603</xmpG:magenta>
+ <xmpG:yellow>0.000000</xmpG:yellow>
+ <xmpG:black>0.000000</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>C=26 M=41 Y=0 K=0</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>26.440800</xmpG:cyan>
+ <xmpG:magenta>41.147499</xmpG:magenta>
+ <xmpG:yellow>0.000000</xmpG:yellow>
+ <xmpG:black>0.000000</xmpG:black>
+ </rdf:li>
+ </rdf:Seq>
+ </xmpG:Colorants>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:groupName>Grays</xmpG:groupName>
+ <xmpG:groupType>1</xmpG:groupType>
+ <xmpG:Colorants>
+ <rdf:Seq>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=0 G=0 B=0</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>75.020996</xmpG:cyan>
+ <xmpG:magenta>67.968300</xmpG:magenta>
+ <xmpG:yellow>67.022202</xmpG:yellow>
+ <xmpG:black>90.164001</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=26 G=26 B=26</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>72.576500</xmpG:cyan>
+ <xmpG:magenta>66.600998</xmpG:magenta>
+ <xmpG:yellow>65.191101</xmpG:yellow>
+ <xmpG:black>78.161301</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=51 G=51 B=51</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>69.482002</xmpG:cyan>
+ <xmpG:magenta>63.180000</xmpG:magenta>
+ <xmpG:yellow>62.151497</xmpG:yellow>
+ <xmpG:black>58.361202</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=77 G=77 B=77</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>65.377304</xmpG:cyan>
+ <xmpG:magenta>57.988899</xmpG:magenta>
+ <xmpG:yellow>56.878002</xmpG:yellow>
+ <xmpG:black>36.661304</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=102 G=102 B=102</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>59.728401</xmpG:cyan>
+ <xmpG:magenta>51.235199</xmpG:magenta>
+ <xmpG:yellow>50.771301</xmpG:yellow>
+ <xmpG:black>20.132797</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=128 G=128 B=128</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>51.647198</xmpG:cyan>
+ <xmpG:magenta>43.149502</xmpG:magenta>
+ <xmpG:yellow>43.149502</xmpG:yellow>
+ <xmpG:black>7.547098</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=153 G=153 B=153</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>42.636799</xmpG:cyan>
+ <xmpG:magenta>34.787498</xmpG:magenta>
+ <xmpG:yellow>35.315502</xmpG:yellow>
+ <xmpG:black>0.985700</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=179 G=179 B=179</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>30.679798</xmpG:cyan>
+ <xmpG:magenta>24.246597</xmpG:magenta>
+ <xmpG:yellow>24.765402</xmpG:yellow>
+ <xmpG:black>0.000000</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=204 G=204 B=204</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>19.366800</xmpG:cyan>
+ <xmpG:magenta>15.005702</xmpG:magenta>
+ <xmpG:yellow>15.533697</xmpG:yellow>
+ <xmpG:black>0.000000</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=230 G=230 B=230</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>8.459598</xmpG:cyan>
+ <xmpG:magenta>6.131101</xmpG:magenta>
+ <xmpG:yellow>6.576598</xmpG:yellow>
+ <xmpG:black>0.000000</xmpG:black>
+ </rdf:li>
+ <rdf:li rdf:parseType="Resource">
+ <xmpG:swatchName>R=242 G=242 B=242</xmpG:swatchName>
+ <xmpG:mode>CMYK</xmpG:mode>
+ <xmpG:type>PROCESS</xmpG:type>
+ <xmpG:cyan>3.704900</xmpG:cyan>
+ <xmpG:magenta>2.508599</xmpG:magenta>
+ <xmpG:yellow>2.508599</xmpG:yellow>
+ <xmpG:black>0.000000</xmpG:black>
+ </rdf:li>
+ </rdf:Seq>
+ </xmpG:Colorants>
+ </rdf:li>
+ </rdf:Seq>
+ </xmpTPg:SwatchGroups>
+ </rdf:Description>
+ <rdf:Description rdf:about=""
+ xmlns:pdf="http://ns.adobe.com/pdf/1.3/">
+ <pdf:Producer>Adobe PDF library 10.01</pdf:Producer>
+ </rdf:Description>
+ </rdf:RDF>
+</x:xmpmeta>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<?xpacket end="w"?> endstream endobj 3 0 obj <</Count 1/Kids[7 0 R]/Type/Pages>> endobj 7 0 obj <</ArtBox[63.4517 35.4053 512.534 541.376]/BleedBox[0.0 0.0 576.0 576.0]/Contents 74 0 R/LastModified(D:20210204195255-08'00')/MediaBox[0.0 0.0 576.0 576.0]/Parent 3 0 R/PieceInfo<</Illustrator 75 0 R>>/Resources<</ColorSpace<</CS0 76 0 R/CS1 77 0 R>>/ExtGState<</GS0 78 0 R>>/Properties<</MC0 72 0 R>>>>/Thumb 79 0 R/TrimBox[0.0 0.0 576.0 576.0]/Type/Page>> endobj 74 0 obj <</Filter/FlateDecode/Length 1386>>stream
+HIn\7}
+^)ik%"0@
+_A RoA`Y/\KJ.`\HbM򱞀ڵyf)cʎ9v 6qGvSg?4ѳe>g֡,2|܆ެAh;5G<מ,EK E/b_nl6l#5px?y# N,ǔWy>l=,<K۟/k\M?ĀCf6S^i~,ja}H,KV"wzto b3{_SR90^ կ~RP: {z<2m6%ЗS
+j$c u
+yu%nύ.q0 5A&0r%Va*<+e T<UWV .)\H>_5
+UtK/18q?& J5b~и( } QԺDnd$}S|QhUشR#!Sb^+E}!WAy?P.{qJ@JU#/AI uRyc#I~'[Ec
+8;Z]"4-mc,$q4<X4"XRb<*9E2)J9:kBD?s-$&b0+E&]1!_9Ymn7%F.>0+7-7`dl_t
+&"$(CG"m(k@EV&h\B,oL,KM!FM&G4jiCMdPrDjH+Qp"pccm$+FW-O%]e8q'DdeR"k
+#pF0sghHa)eA%;n!(]HbVn[OXoNlFrfg%%lIc?X)RjufQ*,+bBO_[]&RARQJU-FSX
+167F_,[FH<LuLE'bUO6YWQ4TTkjb\Z9(OOhZ1"l0g\7g1cIFoG(onRWj:nT+*n(t3
+OdYEjru?C,Zbsi,bk.DF4$5aHRHdE&p]ssXTc6-S\q2=j,fQgc.c8RT"E"4G6SE,*
+UI,YY`L6M]VP81kY=s&A-T^9h<H0<=KV`&3a::f><'=l8,q,eLnes;IQ(QHhYf^^q
+r(P"(G/@Xb@RX)OV`<'D_WFmJ^4r7P0BZ/\^4m`H:%(o-0b$@4Q-LOh%Oq(HI>9d]
+gAu$X4[1MVSO43F[/;1&^`ob>Nt%!FLKRb1HFj'1Y,mY[0NbmcO=9dae&?*ALoWP>
+./"`@:*&(]INXcsYS6j.FEqc<rtsp0719$HgS-n?r5:]XF%=DLbNblTjf]%\K0(UZ
+X(6L1SMA%>n\Zk\b,8_R(S-ucj2_n3eOf\#17i]W!K-KKUM"=Z"IY\WK4%K.lZtNd
+'RJ^6)42)re]"$Lo.4p?H?;U6B=W!ZaT&MWNCmGbR<@gsjRPM8Khc$4~> endstream endobj 80 0 obj [/Indexed/DeviceRGB 255 81 0 R] endobj 81 0 obj <</Filter[/ASCII85Decode/FlateDecode]/Length 428>>stream
+8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0
+b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup`
+E1r!/,*0[*9.aFIR2&b-C#s<Xl5FH@[<=!#6V)uDBXnIr.F>oRZ7Dl%MLY\.?d>Mn
+6%Q2oYfNRF$$+ON<+]RUJmC0I<jlL.oXisZ;SYU[/7#<&37rclQKqeJe#,UF7Rgb1
+VNWFKf>nDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j<etJICj7e7nPMb=O6S7UOH<
+PO7r\I.Hu&e0d&E<.')fERr/l+*W,)q^D*ai5<uuLX.7g/>$XKrcYp0n+Xl_nU*O(
+l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~> endstream endobj 72 0 obj <</Intent 82 0 R/Name(Layer 1)/Type/OCG/Usage 83 0 R>> endobj 82 0 obj [/View/Design] endobj 83 0 obj <</CreatorInfo<</Creator(Adobe Illustrator 16.0)/Subtype/Artwork>>>> endobj 78 0 obj <</AIS false/BM/Normal/CA 1.0/OP false/OPM 1/SA true/SMask/None/Type/ExtGState/ca 1.0/op false>> endobj 76 0 obj [/Separation/PANTONE#20152#20CVC/DeviceCMYK<</C0[0.0 0.0 0.0 0.0]/C1[0.0 0.51 1.0 0.0]/Domain[0 1]/FunctionType 2/N 1.0/Range[0.0 1.0 0.0 1.0 0.0 1.0 0.0 1.0]>>] endobj 77 0 obj [/Separation/PANTONE#20485#20CVC/DeviceCMYK<</C0[0.0 0.0 0.0 0.0]/C1[0.0 1.0 0.91 0.0]/Domain[0 1]/FunctionType 2/N 1.0/Range[0.0 1.0 0.0 1.0 0.0 1.0 0.0 1.0]>>] endobj 75 0 obj <</LastModified(D:20210204195255-08'00')/Private 84 0 R>> endobj 84 0 obj <</AIMetaData 85 0 R/AIPDFPrivateData1 86 0 R/AIPDFPrivateData2 87 0 R/AIPDFPrivateData3 88 0 R/AIPDFPrivateData4 89 0 R/AIPDFPrivateData5 90 0 R/AIPDFPrivateData6 91 0 R/AIPDFPrivateData7 92 0 R/AIPDFPrivateData8 93 0 R/ContainerVersion 11/CreatorVersion 16/NumBlock 8/RoundtripVersion 16>> endobj 85 0 obj <</Length 1127>>stream
+%!PS-Adobe-3.0 %%Creator: Adobe Illustrator(R) 16.0 %%AI8_CreatorVersion: 16.0.0 %%For: (Jamie Zawinski) () %%Title: (logo.pdf) %%CreationDate: 2/4/21 7:52 PM %%Canvassize: 16383 %%BoundingBox: 81 -649 531 -142 %%HiResBoundingBox: 81.4517 -648.5947 530.5342 -142.624 %%DocumentProcessColors: Black %AI5_FileFormat 12.0 %AI12_BuildNumber: 682 %AI3_ColorUsage: Color %AI7_ImageSettings: 0 %%DocumentCustomColors: (PANTONE 152 CVC) %%+ (PANTONE 485 CVC) %%CMYKCustomColor: 0 0.51 1 0 (PANTONE 152 CVC) %%+ 0 1 0.91 0 (PANTONE 485 CVC) %%CMYKProcessColor: 1 1 1 1 ([Registration]) %AI3_Cropmarks: 18 -684 594 -108 %AI3_TemplateBox: 306.5 -396.5 306.5 -396.5 %AI3_TileBox: 34.3765 -881.1035 613.1768 -126.3032 %AI3_DocumentPreview: None %AI5_ArtSize: 14400 14400 %AI5_RulerUnits: 0 %AI9_ColorModel: 2 %AI5_ArtFlags: 0 0 0 1 0 0 1 0 0 %AI5_TargetResolution: 800 %AI5_NumLayers: 1 %AI9_OpenToView: 15.1631 -118.1631 1.96 1225 1158 18 1 1 310 161 1 0 0 1 1 0 1 1 0 1 %AI5_OpenViewLayers: 7 %%PageOrigin:-0.223633 -791.7031 %AI7_GridSettings: 72 8 72 8 1 0 0.8 0.8 0.8 0.9 0.9 0.9 %AI9_Flatten: 1 %AI12_CMSettings: 00.MS %%EndComments endstream endobj 86 0 obj <</Length 19373>>stream
+%%BoundingBox: 81 -649 531 -142 %%HiResBoundingBox: 81.4517 -648.5947 530.5342 -142.624 %AI7_Thumbnail: 116 128 8 %%BeginData: 19220 Hex Bytes %0000330000660000990000CC0033000033330033660033990033CC0033FF %0066000066330066660066990066CC0066FF009900009933009966009999 %0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66 %00FF9900FFCC3300003300333300663300993300CC3300FF333300333333 %3333663333993333CC3333FF3366003366333366663366993366CC3366FF %3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99 %33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033 %6600666600996600CC6600FF6633006633336633666633996633CC6633FF %6666006666336666666666996666CC6666FF669900669933669966669999 %6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33 %66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF %9933009933339933669933999933CC9933FF996600996633996666996699 %9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33 %99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF %CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399 %CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933 %CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF %CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC %FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699 %FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33 %FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100 %000011111111220000002200000022222222440000004400000044444444 %550000005500000055555555770000007700000077777777880000008800 %000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB %DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF %00FF0000FFFFFF0000FF00FFFFFF00FFFFFF %524C45FD27FF5252FD72FF27F87DFD6FFFA8FF7D2720FD70FF277D202752 %FD6FFFA8272720277DFD6EFFA8522727F827A8FD6EFF7D764B27F852FD6E %FFA84B932727F87DFD6EFF7D939A272727A8FD6DFF7D759376272721A8FD %6CFFA84BB59376272752FD6DFF526F939352F82752FD6CFF7D9A93B59352 %27277DFD6BFFA84B9393936F51F827A8FD6AFFA87693B593B551522752FD %6BFF52FD05932751F87DFD0DFFA8FFA827A8FD58FF7D6FBB93B5939A5227 %20A8FD0BFF7D52FF27277DFD58FF7D75FD059376512727FD0AFFA8F8A852 %2752FD59FFA875B593B593B56F7C522752FD09FF277D7D2727A8FD59FFA8 %76FD06934BA0F827A8FD07FF52517D27F852FD5BFF76B593BC93B593767C %7C207DFD06FF7D76765220277DFD5AFFA876FD06936F7C9F2727FD05FFA8 %526F52F827F8FD5BFFA951B593B593B5939951C22727A8FD04FF7D6F76F8 %272752FD5BFFA876FD06936F76752727FD04FFA84B934B27F82752FD5BFF %A851BB93B593BC93767B5227A8FD04FF529A93522776277DFD5BFF7D75FD %05939A51A0F852FD04FF7D519393277651277DFD5BFF7D6FB593B593B54B %A05127A8FD04FF7D6FB593529F76F8FD36FF7EA87DA87DA87DA87DA87DA8 %7DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA851FD0593 %6F76752727A87DA8A87D4B9393934BC127277DA87DA87DA87DA87DA87DA8 %7DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA8 %7DA87DA8FD05FFA87D272720272727202727272027272720272727202727 %2720272727202727272027272720272727207693B593BC93529F52272720 %272727209A93B593769F5220272727202727272027272720272727202727 %27202727272027272720272727202727272027272720272727202727527D %FFFFA827F827F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F8276FFD049376759FF827F827F827F852FD %04934BA04B27F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F827F827F82752FF7D2727F8 %FD25274BB593B593934BC252FD072775B593B593769F52FD2E27F8272727 %A8F827F852A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8 %FFA8FFA8FFA8FFA8FFFFFF5299FD04936F76992727A8A8FFFFA84BFD0593 %4BA051277DFFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FF %A8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFA8FFFFA82727F87D272727A8FD23 %FF527693B593BC93529F7C277DFD04FF7D7693B593BC93767B7C27A8FD2D %FF7D272752F827F8A8FD22FF7D75FD05937675C12027A8FD04FF766FFD05 %936F7C75277DFD2DFF5227F87D27F827A8FD21FF7D7693B593B593B54BC2 %762752FD05FF52B593B593B5939A76A0F87DFD2DFF7DF82753F827F8A8FD %20FF7D51FD06936F529952F8A8FD04FF7D75FD079376752727FD2DFF5227 %F87D272027A8FD1FFFA85293BB93B593BC93767BC22752FD05FF7D6FB593 %BC93B593BC51A02727AFFD2CFF7D202753F827F8A8FD1FFF526FFD079351 %C1752752FD05FF51FD0893767552F8A8FD2CFF5227F87D2727277EFD17FF %A8FD06FF7D4BB593B593B593B56F7C9F52F8A8FD04FFA87693B593B593B5 %93B56F7C76277DFD2CFF7D272752F827F8A8FD0CFFA8FFFFFFA8FFFFFFA8 %FFA8277DA8F87DFFA84BFD08937575C12627A8FD04FF7D6FFD09934B7CF8 %52FD04FFA8FFFFFFA8FFFFFFA8FFFFFFA8FFFFFFA8FFFFFFA8FFFFFFA8FF %FFFFA8FD0BFF5227F87D272727A8FD07FFA87D5252275252522752285227 %5227526F5227272752279A93BC93B593BC93B551C29F2727522852275227 %9A93BC93B593BC93B593767C522052525227525252275252522752525227 %522852275228522752285227522852275252527DFD08FF7D272752F827F8 %A8FD06FF7D27F827F827F827F827F827F827F8276F75F827F827F852FD09 %93529FA0F827F827F827F827FD0A936F765127F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F82752FD07FF52 %27F87D27F827A8FD05FFA8272727F8272727F8272727F8FD0427B55127F8 %2727276FB593B593B593B5939A51C175272727F82727274BB593B593B593 %B593B593B551A02727F8272727F8272727F8272727F8272727F8272727F8 %272727F8272727F8272727F827272752FD06FF7DF82753F827F8A8FD05FF %7DF827F827F827F827F827F827F827F876934BF827F8274BFD09936F769F %76F827F827F827F852FD0B93755152F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827A8FD05FF5227F8 %7D272027A8FD05FF52272727202727272027272720272727939A27272027 %277693BC93B593BC93B593BC52C2752727272027272751BB93B593BC93B5 %93BC93B59376762720272727202727272027272720272727202727272027 %272720272727202727272027272720A8FD05FF7D202753F827F8A8FD05FF %52F827F827F827F827F827F827F8274B934B27F827F827FD0B93769F7CF8 %27F827F827F876FD0C934B7C2727F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F827F827F827F8277DFD05FF5227F87D2727 %277EFD05FF5227F8272727F8272727F8272727F89A9352F8FD0427B593B5 %93B593B593B593B56FA09F27F8272727F82751B593B593B593B593B593B5 %939A517C2727F8272727F8272727F8272727F8272727F8272727F8272727 %F8272727F8272727F82727A8FD05FF7D272752F827F8A8FD05FF52F827F8 %27F827F827F827F827F85193932727F827F852FD0C934B9F2727F827F827 %F876FD0D93767527F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F8277DFD05FF5227F87D272727A8FD05FF52 %2720272727202727272027272775BB99272027272775BB93B593BC93B593 %BC93B593767C7C20272727202751B593BC93B593BC93B593BC93B56F7C76 %272027272720272727202727272027272720272727202727272027272720 %272727202727A8FD05FF7D272752F827F8A8FD05FF52F827F827F827F827 %F827F82727939376F827F827F876FD0C936F527527F827F827F852FD0E93 %4B7C2727F827F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F8277DFD05FF5227F87D27F827A8FD05FF52272727F82727 %27F8272727F87693B54B515127F82775B593B593B593B593B593B593B56F %7C5227F8FD04279A93B593B593B593B593B593B59399517C2727F8272727 %F8272727F8272727F8272727F8272727F8272727F8272727F8272727F8A8 %FD05FF7DF82753F827F8A8FD05FF52F827F827F827F827F827F8276F9393 %515152F827F876FD0E934B762727F827F8276FFD0E93757576F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F8277D %FD05FF5227F87D272027A8FD05FF522727272027272720FD0427BC93B551 %A05227525275B593BC93B593BC93B593BC93B593BC51762727527D277693 %B593BC93B593BC93B593BC93B593767C5220FD04527D5252527D5252527D %FD0452272720272727202727272027272720A8FD05FF7D202753F827F8A8 %FD05FF52F827F827F827F827F827F876939393769F76F8A8A876FD109351 %52F852FFFF51FD0F936F527527F8A8FD10FF2727F827F827F827F827F827 %F8277DFD05FF5227F87D2727277EFD05FF5227F8272727F8272727F82775 %B593B575A05127A8FF51B593B593B593B593B593B593B59393939A5152F8 %52FF7D6FB593B593B593B593B593B593B593B56F7C7627F8A8FD10FF2727 %F8272727F8272727F82727A8FD05FF7D272752F827F8A8FD05FF52F827F8 %27F827F827F82727FD0493769F76F87DFF766FFD1093994B27F852A852FD %10934B7C7527F8A8FD0FFF27F827F827F827F827F827F8277DFD05FF5227 %F87D272727A8FD05FF52272027272720272727207693B593BB75A07B2752 %FF7D7693B593BC93B593BC93B593BC93B593BC939A5152277D7D7693B593 %BC93B593BC93B593BC93B593BB517C752727FD0FFF272720272727202727 %27202727A8FD05FF7D272752F827F8A8FD05FF52F827F827F827F827F827 %6FFD049376759FF852FFFF4BFD1293752727F85252FD11934B9F512752FD %0EFF52F827F827F827F827F827F8277DFD05FF5227F87D27F827A8FD05FF %52272727F8272727F827279A93B593B56F7C9F51F8FFFF7D6FB593B593B5 %93B593B593B593B593B593B593765151275275B593B593B593B593B593B5 %93B59393939A51A02027A8FD0DFFFD0427F8272727F8272727F8A8FD05FF %7DF82753F827F8A8FD05FF52F827F827F827F827F84BFD06934BC151277D %FF7D51FD1393764B27F8276FFD1093767576F87DFD0DFF27F827F827F827 %F827F827F8277DFD05FF5227F87D272027A8FD05FF522727272027272720 %2751B593BC93B593769FA02059FFFF529A93B593BC93B593BC93B593BC93 %B593BC93B593765227207693B593BC93B593BC93B593BC93B593BC93767B %2727FD0DFFFD0427202727272027272720A8FD05FF7D202753F827F8A8FD %05FF52F827F827F827F827F876FD06936F7C9F27F8FFFFA84BFD13936F76 %5127F89AFD10936F7C51277DFD0CFF27F827F827F827F827F827F8277DFD %05FF5227F87D2727277EFD05FF5227F8272727F82727276FB593B593B593 %9351C276277DFFFF5293B593B593B593B593B593B593B593B593B593B56F %7C51274BB593B593B593B593B593B593B593B593B5517CF87DFD0CFF2727 %F8272727F8272727F82727A8FD05FF7D272752F827F8A8FD05FF52F827F8 %27F827F82727FD08937675A0F827A8FF7D75FD14934B7CF8276FFD109376 %5127F8FD0CFF27F827F827F827F827F827F8277DFD05FF5227F87D272727 %A8FD05FF5227202727272027275293BC93B593BC93B56F769F5220A8FFFF %529A93B593BC93B593BC93B593BC93B593BC93B5939A767C205293B593BC %93B593BC93B593BC93B593BC9376512784FD0BFF27272027272720272727 %202727A8FD05FF7D272752F827F8A8FD05FF52F827F827F827F82727FD09 %934BA0752727FFFF7D4BFD1493767527F89AFD10937552F87DFD0BFF52F8 %27F827F827F827F827F8277DFD05FF5227F87D27F827A8FD05FF52272727 %F8272727F87693B593B593B593B5939A51C251277DFFFF5293B593B593B5 %93B593B593B593B593B593B593B56F7C52274BB593B593B593B593B593B5 %93B593B5939A512727FD0BFFFD0427F8272727F8272727F8A8FD05FF7DF8 %2753F827F8A8FD05FF52F827F827F827F8274BFD0A937675A0F827A8FF7D %75FD14934BA0F8276FFD1093522727A8FD0AFF27F827F827F827F827F827 %F8277DFD05FF5227F87D272027A8FD05FF5227272720272727207693B593 %BC93B593BC93B593529F76207DFFFF529A93B593BC93B593BC93B593BC93 %B593BC93B593767C52207693B593BC93B593BC93B593BC93B593BB752720 %A8FD0AFFFD0427202727272027272720A8FD05FF7D202753F827F8A8FD05 %FF52F827F827F827F8274BFD0B936F769F27F8A8FF7D4BFD13936F767527 %27FD10939A272752FD0AFF27F827F827F827F827F827F8277DFD05FF5227 %F87D2727277EFD05FF5227F8272727F827277693B593B593B593B593B593 %B54BA0762752FFFF5293B593B593B593B593B593B593B593B593B593B56F %52272793B593B593B593B593B593B593B593B593522752FD0AFF2727F827 %2727F8272727F82727A8FD05FF7D272752F827F8A8FD05FF52F827F827F8 %27F8274BFD0D934BA04B277DFF7D75FD14936F766FFD11934B27F8A8FD09 %FF27F827F827F827F827F827F8277DFD05FF5227F87D272727A8FD05FF52 %27202727272027277693BC93B593BC93B593BC93B5939A52A02027A8FF52 %9A93B593BC93B593BC93B593BC93B593BC93B593BC93B593BC93B593BC93 %B593BC93B593BC93B5939A27277DFD09FF27272027272720272727202727 %A8FD05FF7D272752F827F8A8FD05FF52F827F827F827F82727FD0E937675 %76F852FF7D4BFD27936F27F87DFD09FF52F827F827F827F827F827F8277D %FD05FF5227F87D27F827A8FD05FF52272727F8272727F82793B593B593B5 %93B593B593B593B593767652F8A8FF5293B593B593B593B593B593B593B5 %93B593B593B593B593B593B593B593B593B593B593B593B593B54B2752FD %09FFFD0427F8272727F8272727F8A8FD05FF7DF82753F827F8A8FD05FF52 %F827F827F827F827F876FD0F93525127F8FF7D6FFD279352F852FD09FF27 %F827F827F827F827F827F8277DFD05FF5227F87D272027A8FD05FF522727 %272027272720274BB593BC93B593BC93B593BC93B593BB937651277DA84B %BB93B593BC93B593BC93B593BC93B593BC93B593BC93B593BC93B593BC93 %B593BC93B593BC93B5752727FD09FFFD0427202727272027272720A8FD05 %FF7D202753F827F8A8FD05FF52F827F827F827F827F8276FFD0F936F5227 %277D76FD279375F8277DFD08FF27F827F827F827F827F827F8277DFD05FF %5227F87D2727277EFD05FF5227F8272727F8272727F85293B593B593B593 %B593B593B593B593B57552F87D769993B593B593B593B593B593B593B593 %B593B593B593B593B593B593B593B593B593B593B593B59327F884FD08FF %2727F8272727F8272727F82727A8FD05FF7D272752F827F8A8FD05FF52F8 %27F827F827F827F827F899FD10934B27F87D6FFD2793272752FD08FF27F8 %27F827F827F827F827F8277DFD05FF5227F87D272727A8FD05FF52272027 %272720272727202751B593BC93B593BC93B593BC93B593BC93762727279A %93BC93B593BC93B593BC93B593BC93B593BC93B593BC93B593BC93B593BC %93B593BC93B593BC93522052FD08FF27272027272720272727202727A8FD %05FF7D272752F827F8A8FD05FF52F827F827F827F827F827F8276FFD1093 %4BF8276FFD27934B2727FD08FF52F827F827F827F827F827F8277DFD05FF %5227F87D27F827A8FD05FF52272727F8272727F8272727F87693B593B593 %B593B593B593B593B593B57527F89A93B593B593B593B593B593B593B593 %B593B593B593B593B593B593B593B593B593B593B593B593762727A8FD07 %FFFD0427F8272727F8272727F8A8FD05FF7DF82753F827F8A8FD05FF52F8 %27F827F827F827F827F827F899FD10936F516FFD27934B4BF8A8FD07FF27 %F827F827F827F827F827F8277DFD05FF5227F87D272027A8FD05FF522727 %272027272720272727207D52B593BC93B593BC93B593BC93B593BC93B593 %BC93B593BC93B593BC93B593BC93B593BC93B593BC93B593BC93B593BC93 %B593BC93B593BC93B593764B277DFD07FFFD0427202727272027272720A8 %FD05FF7D202753F827F8A8FD05FF52F827F827F827F827F827F8277D7D6F %FD39934B76F87DFD07FF27F827F827F827F827F827F8277DFD05FF5227F8 %7D2727277EFD05FF5227F8272727F8272727F827277DFF5293B593B593B5 %93B593B593B593B593B593B593B593B593B593B593B593B593B593B593B5 %93B593B593B593B593B593B593B593B593B593B59376752752FD07FF2727 %F8272727F8272727F82727A8FD05FF7D272752F827F8A8FD05FF52F827F8 %27F827F827F827F8277DFF7D52FD389351A0F852FD07FF27F827F827F827 %F827F827F8277DFD05FF5227F87D272727A8FD05FF522720272727202727 %272027277DFFFF529A93BC93B593BC93B593BC93B593BC93B593BC93B593 %BC93B593BC93B593BC93B593BC93B593BC93B593BC93B593BC93B593BC93 %B593BC93769F5227FD07FF27272027272720272727202727A8FD05FF7D27 %2752F827F8A8FD05FF52F827F827F827F827F827F8277DFFFFFF4BFD3693 %7675C12727A8FD06FF52F827F827F827F827F827F8277DFD05FF5227F87D %27F827A8FD05FF52272727F8272727F8272727F87DFFFFFFA84BB593B593 %B593B593B593B593B593B593B593B593B593B593B593B593B593B593B593 %B593B593B593B593B593B593B593B593B593B551A0522727FD07FFFD0427 %F8272727F8272727F8A8FD05FF7DF82753F827F8A8FD05FF52F827F827F8 %27F827F827F82753FD04FF7D4BFD33936F76512727FD08FF27F827F827F8 %27F827F827F8277DFD05FF5227F87D272027A8FD05FF5227272720272727 %20272727207DFD05FF526FBB93B593BC93B593BC93B593BC93B593BC93B5 %93BC93B593BC93B593BC93B593BC93B593BC93B593BC93B593BC93B593BC %9376512727FD09FFFD0427202727272027272720A8FD05FF7D202753F827 %F8A8FD05FF52F827F827F827F827F827F8277DFD05FFA852FD3193992727 %F8A8FD09FF27F827F827F827F827F827F8277DFD05FF5227F87D2727277E %FD05FF5227F8272727F8272727F827277DFD06FFA85293B593B593B593B5 %93B593B593B593B593B593B593B593B593B593B593B593B593B593B593B5 %93B593B593B593B593B54B27277DFD0AFF2727F8272727F8272727F82727 %A8FD05FF7D272752F827F8A8FD05FF52F827F827F827F827F827F82752FD %07FF7D51FD2E936F27F853FD0AFFA827F827F827F827F827F827F8277DFD %05FF5227F87D272727A8FD05FF52272027272720272727202727277DFD07 %FF7D7693B593BC93B593BC93B593BC93B593BC93B593BC93B593BC93B593 %BC93B593BC93B593BC93B593BC93B593BB934B207DFD0AFFAF5227272027 %272720272727202727A8FD05FF7D272752F827F8A8FD05FF52F827F827F8 %27F827F827F827F827277D527D527D527DF876FD2B9352F827527D527D52 %7D527D527D5227F827F827F827F827F827F827F8277DFD05FF5227F87D27 %F827A8FD05FF52272727F8272727F8272727F8272727F8272727F8272727 %F87693B593B593B593B593B593B593B593B593B593B593B593B593B593B5 %93B593B593B593B593B593B59376F8272727F8272727F8272727F8272727 %F8272727F8272727F8272727F8A8FD05FF7DF82753F827F8A8FD05FF52F8 %27F827F827F827F827F827F827F827F827F827F827F827F876FD279376F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F8277D %FD05FF5227F87D272027A8FD05FF52272727202727272027272720272727 %20272727202727272027277693BC93B593BC93B593BC93B593BC93B593BC %93B593BC93B593BC93B593BC93B593BC93B5937627272027272720272727 %202727272027272720272727202727272027272720A8FD05FF7D202753F8 %27F8A8FD05FF52F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F876FD239376F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F8277DFD05FF5227F87D2727277EFD05FF5227F827 %2727F8272727F8272727F8272727F8272727F8272727F827277693B593B5 %93B593B593B593B593B593B593B593B593B593B593B593B593B593B59352 %2727F8272727F8272727F8272727F8272727F8272727F8272727F8272727 %F82727A8FD05FF7D272752F827F8A8FD05FF52F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F84B6FFD1D936F27F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F8277D %FD05FF5227F87D272727A8FD05FF52272027272720272727202727272027 %2727202727272027272720272727202775B593BC93B593BC93B593BC93B5 %93BC93B593BC93B593BC93B5939A51272027272720272727202727272027 %272720272727202727272027272720272727202727A8FD05FF7D272752F8 %27F8A8FD05FF7DF827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F8272776FD1793762727F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827A8FD05FF5227F8 %7D27F827A8FD05FFA8272727F8272727F8272727F8272727F8272727F827 %2727F8272727F8272727F827274B4B9A93B593B593B593B593B593B593B5 %93B5939A51522727F8272727F8272727F8272727F8272727F8272727F827 %2727F8272727F8272727F827272752FD06FF7DF82753F827F8A8FD06FF52 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F84B4B756F99FD0793996F754B764B27F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F82727 %A8FD06FF5227F87D272027A8FD07FF7D52FD2027202727272027274B2752 %27524B7676A0757C51272027272720FD212752FD08FF7D202753F827F8A8 %FD0AFFA8AFA8A8A8AFA8A8A8AFA8A8A8AFA8A8A8AFA8A8A8AFA8A8A8AFA8 %A8A8FF2727F827F827F827F827F827F82720527552F827F827F827F827F8 %7DA8A8A8AFA8A8A8AFA8A8A8AFA8A8A8AFA8A8A8AFA8A8A8AFA8A8A8AFA8 %A8A8FD09FF5227F87D2727277EFD27FFA8272727F8272727F8272727F827 %2727F8272727F8272727F8FD0427FD28FF7D272752F827F8A8FD27FF27F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F82752FD27 %FF5227F87D272727A8FD26FF7D2027272720272727202727272027272720 %27272720272727202727272027A8FD26FF7D272752F827F8A8FD25FF7DF8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27A8FD25FF5227F87D27F827A8FD24FF7DF8272727F8272727F8272727F8 %272727F8272727F8272727F8272727F8272727F827A8FD24FF7DF82753F8 %27F8A8FD22FF7E52F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F827F82752FD23FF5227F87D272027A8FD20FFA8 %522727272027272720272727202727272027272720272727202727272027 %27272027272720FD0427A8FD21FF7D202753F827F8A8FD1DFFA87D52F827 %F827F827F827F827F827F827F827F827F827F827F827F827F827F827F827 %F827F827F827F827F827F82752A8A8FD1DFF5227F87D2727277EFD1CFFA8 %2727F8272727F8272727F8272727F8272727F8272727F8272727F8272727 %F8272727F8272727F8272727F8272727F8272752A8FD1CFF7D272752F827 %F8A8FD1CFF5227F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F8A8FD1CFF %5227F87D272727A8FD1DFF7DA87DA87DA87DA87DA87DA87DA87DA87DA87D %A87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87DA87D %A8FD1DFF7D272752F827F8A8FD6CFF5227F87D27F827A8FD6CFF7DF82753 %F827F8A8FD6CFF5227F87D52202752FD6BA87D2720277D7D27F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F8FFFF5227F8272727F8272727 %F8272727F8272727F8272727F8272727F8272727F8272727F8272727F827 %2727F8272727F8272727F8272727F8272727F8272727F8272727F8272727 %F8272727F8272727F8272727F8272727F8272727F8272727F8272727F827 %2727F8272727F8272727F82727A8FFFFFF7D52F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F827F827F827F827F827F827F827F827F827F827F827F827F8 %27F827F827F82752A8FFFF %%EndData endstream endobj 87 0 obj <</Filter[/FlateDecode]/Length 25623>>stream
+HWko
+ E
+4=ɥDqW,w< <y"nlS7gur4z\^?ͺ33e&S_eȾKq<U)sLm=[->tBm0W1߽xk^TREZmT̕=r |xf#BkS7c4͚K26M}q]̍拃C(som\ӆĿEx]~qr.}=Lon>_b2ln0Ypu}yzv"kgq $F7F]V<=7S#=}~[D f<Wˬ&N 'õlDM0g=JtV/Q1)>QrBgDplA|>ݹz\ȿo*o#6<Ayw;~[͇شQU7"/~}Zf&RF*\emr1 
+wnlwU]7ZfcFehg7SSl8+VwFn`hyX?ǥ{4L@*\~67wOM[\T xr[lEr{yrӛh^5Z]OOʍ*kU-
+P"_8#F W$*#(:ji]k.4ˮ#փz=؊Mq=.n  0>=#C{ za^D/җ2z {z{IzvB=Dj')w9זBj8,(҈4s^
+O@0R(H"sGғnL[r)J2L\SΤ*PLq%TJ*RJpHcz݇X[BGX,8柰DZFZYx%sKR['GMϟo5pO#Id%X:0!f4E X
+$@BD( C0
+%a<*R
+)(d"GFL$ʓ)dڪB. 4Cn#r"=9R?F Q
+
+@a`*E )*G
+(. A,59N0ګwJxlOXc.A
+FP|cUO!}(`h_4e` k;E ST3dHã>TUv715:0*@sn L
+SCS]Z `=HC@ Ly7fqJp@@Ӫ#fy
+4};,SƾLrӬO3pg3( $q(A!ToS$<LіHٓ>iS0vxӎ}?W 3 &6@8&ӱ0w=o݃ݝ>{Hw dx@3 ë;?|lsݶ{|;ova>..#;5ƹxwv-;!3!kM?&)'E-8ִ~pbS݊oVr^uxػqAq
+gI |
+ iQhgR@h`
+a68!DY+TmHU$p,X@%
+b7D1a,n6ƜGa?tY&CJӠ,*ܫ+(6DS}SќtءSB LA @1Hɍ6_f:sVHSr\ϫ]_TGkEkjk4|2sh}nPajR,Wp ,
+$-OوsVS\(e8p]
+vTY )ʖЁck%Ԕ"$DX*J`ъ-HE21iqUv(>J.e嬯VM[+Lt1ȷ/^+,H++M+8:rQ(^R
+6z t}X)UTO K?VGLRiRs|:sC|Ö1чd)y&ϽsxJUrGzXA<>9PsxD[(ǗȨM9-Ŝ'@ps۬ m-2JD-Tr9K 0HqN^,v`Ҳnhf5u6yIœiv/8G,),{x
+8lbTcwfw!P^9Aaw ]+kpP 2W+>FZA#KGJX1BD=Nmycꄫ*?߆iR9Ubr*;GQs*C*ڙP=Q*f9&LIGVR8-fb<(Z]F/
+ѱAJ""
+P/ș5ۗo/eqÒw3{X gO-nP-%,+}ȯ
+@T] ==g7cmߣ;(ы\ռ~ڊY@Ρz @%77m}%~Ypw`ך~Ze:}1)ce\r, Ԙ|?`4+@w<
+iǭi/f
+%
+䃸60^vbN@
+ĬtBumS
+vK 4rfIIى:q?o8]8 9].#0
+<"uYϑ?|'`ǗߜeFӨr[ 48ҹ~G9,\CsAsfR :YAn="eGtA4Z Ȱ+Cl1˾|*" =e5Hb v^Ġf;JPl<@l`0VY# ;vnГ:i͔&ytRܡoQnct.
+@BPj=tgKF9KOx<݅r\1$䐑597pmhJlT/,cU'ѝ˩Sy}@Yµ
+\)$LMRha#T?H>
+p >UTR[`Xz@t' w}z@/ /4Y56 (JdT-|\lsԇ:fQԂ<ςBtWR7ϹsO2  #աP`'*yS/VGDߺZ5/V5['ȿ:ӣ0^ׁ~%T,>.
+|UIhѬjf$q׺)Wc3K@hˀk0?ZW_F͡B/WwZ!y>(LyJfĭ b+[j=L` z Esװ
+V@Z,<<]n0}7
+DO `T9[׻g+8}ŅS8+Y-MANpS=Go?cf5-M`F
+7]OԐxa}nXuS7(60nndtwWMՋLŽLi:0 ^
+ "P₾H@ħ{2@T`_+_WK Λ]<BŴFKXM8mT$ .h=-] XLn&p :UZ
+9
+ϓ;Ɂyd6.ٷOS%Q:as9^=_ "z9RE!GY8TINJ-&ǮQpOW\+Vd7u{[K.,}WiQEM* $x6ŧ8^.D+g
+ Fs6mo7gp
+D8k:%ήgS]c
++rP;mq<Dpd$Njn֭j·ND +P{^[(h:%]f9
+9KZcvE0[4@;!!ï#1Ox+ՕywBpમ
+9!e'R?8w9zAu:'ӤcP0[Ur t;3VhX!ɯ"JS+Dn}@[qy-Т2+d;ү *^T7LᔮVMq 6<+.[@R0^JDV OU)bdF;7DC D.48@tpxT /3mɏ~__>~o_ v_޽~/˧~|7ӿp/?bp7k;ס&S%&o~̤.zN`7M*3(
+eS8*
+RcgmMy}Pcma lOTLTJm5| ij؞6MBYZhG<ūZ
+P=A]ZR MĮFCj[\G=:.=촬7^@k\FMPp|X5ݪEq)qp:X&8Ĩ4$0`7#{Yϸ\b8 .1&yWfԸ6~t㚝a>d=7iƤ1
+%@&\uA`ɀcuhDϋ ֯B׏N5[ţR_3[Tm${
+6v#NT[CI1vvw?'8`
+"If4]8\%y"rQj (D"N=Z{pJ!\s/ >B @A?"}EK2N~P܇
+'|E&Q|j^I ,
+sqS PvڧCyוϱR 5;E+j;"BO4ѪMHsu̿+|"Ee(A=U[R\hDV4ry!2
+FSu64x
+CMjGdK6!!VKiy t
+)Jq7#@7
+`eO G
+~7*ѮBhN{RL9kIpْ1b'xr@"32 )'tÀ-Ae,d+r ،m$(NVlq DYb?f̸/(cAsIUKU-ki~Q1;5ԏJE1?W{ L: ynhUdz
+)!4V 7ᑱ`'JA {W1utq4#ȅ6l#67.? ܷ+Y"iuo@UWpC1$׈ }/乞 Tv"2JV0%MXܫ?fs:3]2sE> "۰c._zh>xѦN0a]a~<VQT|t$lƤw
+vxD"JFyxGND' Dm+И>ZѺU>JR Ll4i_Ǡ
+Cu
+cɚSL]Gc2Ɨ2)‚TiDU*0e0Z+_&+t7V hKRCZhٯS)\h͚ȕ{2 U=LjqhOr!i:8!jO{ SרYt?Nd~a$V[nDbIrWo켟9'=FwQ֯]TL Q deO쾸[b(#`Y1DT*L,׳"OBdQxN5Ejych[Εr%pj4ԞFsjRbb$K,;'Q [JUs' 
+]*`hyl7RS ʴ
+3oQCJTd;/܊UztlHo- r~_sNE[;3E!iPۋ$ңT+`Jm\-mvw'c:ݯn%+L$|Dt&@ |ҕzVQx+$70bfǀsl3ov\ړ +v:%:8&1X0_AЏ T>)4b5ev-TDEЃNsI.||1"5؉=mR<";u\B=%Pb!n1hVT^~ c'r0gQUC XK8BZ6=Qt
+PtƲVpvV]0^fSz`9;zŒ\!NsXlfA=9-cQ"m8?6+0kMt`8݆g^jUc+yKC5KmxK\{($PnҲIm4Qw:K2mt%Xo!lʙeu+x'탒"nӃ~zBCZ0ۀ-H j*zYKxC#C蠍L{F- UO
+< K`ҍBv%-~VmC R,\},5B0lqZo5OC]B,K./p$6oJ~O_>ۯ|}W(-b}/?W?_~ۯ_З?ϺC*#_L[VA;Ÿ
+m1:F;¸`+C^F4FC /I68Zq>gޠ+>B 4j92}qH̜J“⋞1x;Vj]XEOfT%f`w%qDcw?0a(,̃'fV5$+zytEӐ{2:  
+TGKZ{@q6'#]H4TMyFdV(gZG_\>
+Aei$SFsNĨf5 Ћέ ρ yOm=b
+*e-K#"Y;ZGWŤ:bZ5m1|rR`!zg>6Rx3@`j=iN 0Jٯ30MPTetXDc+M,.P(,)@bKwz*ǻ"F`\w`ZbqcQ<Gg00o(<36AS/!͢}{7" ܝ[dJ;hEADp- Ԃc!
+h&Aө{L^
+4׺(6RO"lKy$T뫈vKu(}K3Mi:}e5fa
+S橻<KefeҔh״i.{98
+>[Hh_iQָ@8ԑf0J 85ZgJk ʜ Xܰ=<6A9Z!C3`vQ*MTf@r$0b֯ȊpB6 ¯r)S #B}}s$jʶ4^CS
+7p{wHf*fFDoDH'hR3˿Ɯ)1Ī.I7L5 x߿T^ M2>@A}Ze:~hK^öjFݎ!/5[=Ɖq_n[ΩTc:x Jk@sn
+U-*w6·A"t++Vkp)'V~U+X΍H,ϸUV 0֪qRws,Z>qRw3aR"HBTJJo_ MK/^}mQL"$`ƚocOyBk*Xf~<|{q3HNՈ
+UۇP&6F1;875` Y1+G nX&;c[թEzX>nQQI)Phi*}o=rb\z UβB] !$DwGQ
+D%Y3y vQx^ef\!k15M[Z R}d@zf(FK+>2(`BJB.dW"F1ȴ' h8l"8KqbܟV%T+BmzzEgrXrX,VX=h[yj)^,cz{nJ a'sx&e?5hYn5a@hIR,=O <ъB~MLפtB Y[xd{2 m7Ow.!j<Ф$%ȆwB)Sp36t&A&]}-װy"w2=ar7MOs,1v)oڡ&+SjŢ0AYq#ð57F8Ӭ2-j4[twe;4%6z-kR ZsU-Mzǫ=\l,F묵dU gS .rMW{EAsfνP:JF}Ե}a 5иMc:R J9-kP$w5{oKZ Ȭ-$B kdrx,^9` \)s
+j<`s no PA B-Z [ؐJta%IsCU
+;=iF!z J9I;OZU_bV|lv 7Y*< u;8_ +6>`I92I
+|LLB
+ tSZH@րѱ:Z4f,:VP%n7WDRJX b&i Lt\$=pC2ک\ LYlYz_e\ 1*2ḅ@
+ NVP[yo5NUT
+qɝbBGm5[
+[Hvem#'weGKerՎ<
+f(-ed;~ wѾ%H
+$FaвnX%Ua9x+q4^$"?Y"M<@bOn# c
+QMIhs#(aF({@K 3wz/?T-N$rS-'^c)9':]k2T3}w~
+E((7VC
+W@nC!Bf] "1|PH"@5 b+ĩ+{G> G[54؞Hh)Չ+1Ol3ZKuQTv%oW/4'YTWR72PȰ5<HM!҂D +/NPUMmrS6,wūO=H],ң~L/7
+Nɼ<(OisZpV2EqYx$pZ .VBNA15u4^!{cBjn";*ѡx_nB~+2h+䮌+ƥB8 ] u=sCϓ|tQJJ LEZVf:!0VQLH96hǶ$sr-gTߴ%On P<,\Fڙ!9Y}X #ҝf )JiʂqM:
+o%˶ԈSԂPVVf*
+4ޯb ;=S5J2 v[ 9ʂU&UAB(2_ /ku*B&?rOwM:1fОI*]UyϲSg0iRJnk 辤wf$d@iB5 Sԋܝ<1TWb*ԘvVTT{~oq׶llYynҚks4ˊ  .U c ào RiYXlsA`kn1}yꓺc;HD# -Y$Z5㱒&@(<Pi9&3س#YfŖ+B$]3ķ1yaC!YBRۅ<Jϒi&9%'1V}|m֕M&\Х(\fc
+g8ֲ"k=&fW6i.i9r!3ឮn YN|Tu4(I
+.sXf8ac@,9w28 erj\`)! 6":}T;Tv"c A㾺"v ~|3cD3ӱœ~X1 CFIxMy7
+D{ m0^mLx~2-?EIL9?DeJeLNfkHܷM8
+Rݻ:]{YW$:z~W.?{ٶx4̋+:`j@ Qsz .p2Y$[rSMnĭ`hDjin6pRm1y$[Fy-:hy:#ڣXrBeQxH
+HdWۮ]Ga %Vfg)
+Pt=QdDlriiR-(X_-P%!QMFs`dN2__I~@"
+K,Ml)"VQ wjؽu.oq?57bY^lI׭-G\jPpBZW3LYiZ 4%=e
+
+xOV
+&,t;GH*bĈ܍;fVȜ/;GNՙ-MAJ7Τ~ik`b"6 ;js
+eWrtN5dHMrDX e&(e5f(YkcfجaBJ
+n/ 7-t[3Zd:NI$ '$& FuPD,X
+I\=6fii[9;؈L+?Q 6e6α*1{؟vϓQfvi`X5N
+()-j5JW,A<
+dD?yĖW@Q6G;8Z܀mW PO sA ^#*)pF0w(q)| ,#/%/DߎO?||~πqD*|o?}߯۷_~ϟگ_ʿt[6d}!7(xTjd?ι<ca@Bv+̪DHHyPFFvRbӓۗR6$=%/U'Ɣm}1mF sa&jz  :Iߝ0Q %Rr
+WyqcLgRT(2YyiKHOV|5;E-Oy"y x@C /B Nl"ĝPRb(ȎFE]Q.#1щze$
+z1b7x!SdeP<@쓝Q|?Q<T
+NaWHm"TxZ
+ 5 j<ٕ%$Ao>Lt4)*ً8 ҏiDhHĒJ\ħҔic%A0#s Ӆ3y
+C8\)*:^g-DLn :ţeyإt+ܢl8WYr0Xv̮r sKZffLp!!sb{bWpϧ0Ud;39D"J+HbR &RcvʻxXiR9v,c~YV8HRCh#9Y'l+/\@Ē"dK%Ǚ|+Qx9аHy&W:uM`̼bYC+xQ):VcD7cb݉(<I'+ZO;Bu.$5ӡx7<Y \RH%-m B%>ϸJ)Rg\$•IB1_hIW|Tu3h .vED"9O
+QcBN=|]/)tfab02j$[9IҼ%hZ G[MOIJVk#ްrvOq«92U[d잘)$[(JT!tK=e: -rDfd$YMwǝAI(V*IL\M)& qY,N1|֤B:
+[ƬCB,VxV5Y?gi @|QA;$5gszz dw!w FHG&
+r-څ'`bU$kmw3!-|Db<JGȽ<a;5g+2n7hٻ;*~oKGRQ{^5x+ŷO[r_`Übȭ4>d!((k!V##:L/B
+8|u!!nV{ؤ͑
+IyAKRiY/^C$<PǸ6a~è/k^S"գtrf
+= *DIOʸU t3d,OHT3D( 1?JvAc˃,vZޠStGWi.d-6*Tc[K4bɊ&ΦS" tdEkݧzyX[ЦԜ.-EF !*7E-8b+l#Ɖ HOMSF]FKGLI$UrLͰT\ǩl. i}dvL<[aUG+t >] :=:оF N_,dETGKHܒQ<l $=X1}n<3fL;=Q@X[md2(nu hCCK>:js*>Zуy(<mq/8Rpg S'6VQ"ӈuzV1ŋNATB+aB+ۆLL%3dg6Zq9z=AŬm
+rv_l*_x(\sBrl/;/MyAKw!HXw̡
+Xq 1QTY)酸z1nwNĹA^찪mZ_~/_᛿O?~׿}߽jB?{ۿ^珿w|o>s^YPU*VF[ҋoȅK߻a}U5 ږ(ڪyBN !kh-[:m v!29B&MzB<WL3C>GhnS[߼6MdI$)C~1(o[_{de($Zv-޾#e˴jV5dBԠhp!DD]wB
+#P1:lklt><z }?
+8Œ }ɝ5-ՊvUFxw=Ό}1Z=ܞHt\E
+^mPsDzt.:.H~;Cfr)A^!͗ H$ `w{[m1*HdS^lD2:$[!l \Ĵ7F~KFMy2^*uGd
+!V&x((3mKUw|i]%av#{o}G E-.%<9+и|u4ߌT~76Xj˰?v)5{Jjt)i=xrs/Ӻ)KESUKcT{gtYz(1Y6@#׽`VͲz:ci#,1w|E Jέ_#Aң^>E^gHiUzK^k+l
+{lɖ|&`9\h`UX2϶50-dҝJ3}CsFi\Ϙ
+_|.G;. CB 8z |o g>GAusjK1F܍J)$LpFJEV(Zm%0 -.sg3aFÎ&
+pq}X=]'%cDB N2z6N:UcC%Kj ,,rm( l9+=xXfl~:}[sIrً R_W)"UB.cƪ9f?(߁Yb`I)39WiE{Q:v]uUVCb@(]=QZ3KVoNw9 |W]gL-JS@ؤt( KTЫkf`=0T[л]}ECiDF#>3Q@!%%=PIiOnAPuj#ե7DU9
+(<P5r8-qj%?Rn`&w6_ǝec|SN,5LgC1AJqI̍jӚbņ"hjmPM Q;+3qE}vZV=Ä7r~ *@ JInrDWYz/+O~Wpw|_iڬ, Dܝ2"g\5}:aٸOqӁFUGk¼*mflQGN٪c=H-w-( )
+TUjn 1=ҕQy+ܔs
+¯rvH_-=AB SAA6yO}/cN/kժϠ=@fSD/_
+ z KAvBAʭGE㔶:ȫ,}8N.ܽ!}TWӄN (dׁ -M0;3C2{bw*?YP&»Pg0DUhqH5,Y8DcM9N1AY4ĩ};gP-ho }
+ Ě,d=M0> d
+L5K:]+5+D/RE =\C@]}{7Bh;~֐H$nAA]A,"BuGaFz;Mt
+At-3A"im-uphVծx*u죲ǔu:%Ri@vbl;HjK,}0㲫Ӎty+ХâzAZ$f'dFT׌-d;'O(郄.^h\ICo6ps3l5@KXp!x+h?h鼁J 9[hi¨ѳ
+s4)۴+(hzV\N~
+<LT8_0BFwN'" |57EmF񱅺K,̱bߑ8jd\cn_aPȤ%u { eRO6.糠֟oe^'LlR )ǿj^fRQn!'?_tցU7zVq7$Ρkrtcz>^/h>LL8)Luȭ%1&8Jhه՟}rK Q?in)KQqS63 K:k&Sgguyj *FbR;PpsD܏DPU3+Z
+H-hB@݉\r["x\#!,VyH:T/w+X=W!2vwGXv_)TR?`+ɍ 7>^[KX{ܲ[%HZ>jIaP聑|{LliBLΎiyӛRD(3sF
+xL-dQQ
+胱OkРP|
+}o~aGk*EՃpTgmcvb/HSVT֤(hatޛ1
+vZӔغw kkhQKGm}x n<Đ-Ӣi]EeDbrkJ%A鑄z^QGPBf.CL![LD;]&|yGDt' ԉf!8x3Ph%jQױ`< #|6vcmgk?O~Vj}_?OO?oןo쥞ݥid70k~UQ
+n'YRj(I
+Lƚ=x4y4NOxWb];R}vWچy>\0J\"~u2W |%Š}*+.y~≯53jDh)PgB)+J8V"KIk lW+?4Wsnޜ?f
+Ԛo[O%zf^K <*=N~@9m31 ~/-ˈaoZcCN T"(&C3?e..HEܥw<$,TD<02Jt6>JD<8U^tEU
+Zzr~:0g ȥ~jܨ#m+𪪚{4ph2b6b), >
+eNHMj2;x`~k@_~~bxm >+p<=$.71{yh:@:ʃP;҈1DpPQ0Qt 92LWwf.5) ^f0a
+lݣ0
+>ωI9j\ڟ ['-ENIQTE AKY
+,! %H30i0&{S^څF]'==Nr墦+Kz=lqUBEy+v!?>{6mqЮb m_<Ƌ"7nbAlyZCz+b2aѦn-Xpp=3ʥE#%[Z56Գ
+@1H#f
+sê< p-2 q5b1h+b;f}% IѬi;@fjbE$30yfёi'F)q[%;k @SUqC@pp
+n7a$X:Qi Y j 0HGs9$<<,2OP|V<4Rlu2o"HPhnF^L: O&l,V
+@hDr,1,rc;ӘF<`s
+oX4~Xwٞ#a PQ#b\
+;y4/4Q6GD:s xK',uwK
+XZ?N'_GO_|ssھ|v~_>ܲחG,MzK1~˴6ɫݛS}nO?~a rҳyyї׻_/v?~f=Bp?^Ym{J_n |߮?<}ϯީ =W/Qd7Ǐ'lq>_˳OG?\]ܽ[7gny^>n^/yI˷˿wriDHk1 dmncDS~{5fPc?)ZWDWO4a`rOe0[׳ d:F˝ޏEC^dK˜xoಙ*CnN٨kpI[Ig 6Q*tPc˼Ɍ`RԠ(%d#cס{L1ox] E-G
+'epuM~qinMh^+]T;
+!J<0P GABwQkh _5QzFueA4VRy5,ipOXB&b-P qѳ1eY~XnvtX9+.İN0A}]fxZi_pt6zmZ9%FhlRW'KL5atqiq)\eBnu2dkY X 5^$ $ze9lg<QS|
+pu^skujփ `! `j-(s5PuǮ^*>;zh%zP}B(VA<èK -Ջ)Avkreke-EYNzpn|cyusvXjgM ;5cd{o,['rұcXh`i-{.ٗvFwL g{ɾb5T-c+ ŵ@na;=9IQ)j::tߞ)kP/Nug\Z1>TW5NmIZΚwp1gkUޘ~
+S#r[Gn^wՏ"9md%
+fVuCY+6&J7Rɑ|VJ$XY2 žg(7#5ha9{F\02a-Ka<[qmwgBJs9o'ܦxx` Ø{g!t1fo9G$yLS;5>
+Z\1$Kc
+:{ƞ%R]l5J֑M1 ő]9Jy("<PְN)f:Ǫzs9 7`jh2e3T ,<!WFMxo"૮y[)̶r`g 6W2]$6/>I}tńVQ[(并bJs
+w>V7E3kM%c vgq=-<a/`DREn=X*IY3 NePZk>)3G1u;\4\<_Kb!P&Hp95V Qs#$ju?:$j[2N"ZW
+T-J*ٍ-W3uS@st;77]h6w`jVOFK0g,YW>)F`[k JYBG̰@KiRJc;|~Œ9>ӷudͭG92G0N„">ٲTU4Hm H+$bEgwG֬FfNMWǢf08u+ӡ*JLڴ `<Y`iԵB( 531(u ˶<խ^ؑ8l+O>>ScE@דTE@yͶ.;MnA%:
+2|_ Zkf -)dK?\] rYgu1gYO9K(z[r^GC @v3{_cQ^ !@pc,Z2<Z9{b~W-Ys-·n`eP[TyK=t/J-?f5 PCF<}z4l*
+ԅvʛ9|[;3`MClK`
+ʧ;N`T
+=?܏aB\3t₳>fhV
+2
+C~6܊]
+ R(^ok9 YsƝ{]k[>Y3c~+lfRTY=G2- |Ѡ|f05׀9J;ߓF :ߠU/yڪ! &4RF]X#VܖRVRnޟyS_w_Y
+I,~T2AYŔV}|0k="*Ôb
+
+Q{=ۺE#DZR8A3UU4cR.I\RfjQ64^hNX
+0?v) l62X3$F-WO0}gG3a'9,,^%V>zB$>OV߷tA\j68 45tX^kF0)ļUvLi3`K5Ozkfh~M<V 2Y@gwi2VnyGC }$, yg}bZ
+;UAFvuwQ}ypXW@01GÆ(wu Si'_;.3Q'k
+f_ƃ53e)!]!_|VO
+`ۘA4.eA 'K{S٪
+}'8'>|~w #} NC 豣$cj<yKGxВ^p| Q%‡mnF3+ mRD]MԸ{k`5jt5T5|\( pښMxHUp538hX8&Tp5vjΪʐu*
++YAtR5v8ZZ%;Ģ%K\"%f|Ե{LB۪$V$xEhh+(BL P
+-^OU(W. J
+tEY>qh P {\ #kg'
+-IG}&Vm&mk~YLpOqG0Q4zIY(ioƅ*?uט▲` )%`s_U~ߟڝNp$[ 3D)!. JZKx=Hs k' w%N{`P O,C,,]`+c% LFMvV9e
+Mr%,:ثOrz^7C4󶠴@gXU=MFx~<98׽^$/tmoO{[= ,3d|-7`ѕyw{Z ނ`l4_ZW6SW}}D.LQ[5"[Mqe6IpZg^럸a2N(pL>a/6-n0
+R-Fwcv6-DŽ70?3tm|?M<]cNk6KB29H]B':3
+*a7H!򠻬> f3Ta" 2[ۦO
+t^021V-9k~
+.oq\, wffHrKyLǢ~o#|IY|M_<=Lr?*褋E6e\ac'9T;M}Z
+HWkoI%#qOv2eEOv#VVh$_?nu7/$-d‡[ܺ-MeI[[X0!&Ai@KGP_ gs4Fh"0MtO8Uֺ=oA}aZ"Ly
+@I
+ Vv)tyJ*.(d\;rB3n%-Mh1_X~ u Bu
+]\ 5p05[+V"9 SZxGX\=rm+SzI ۔ZT\pWٖ g+LʹL2.E7BؘxƄvXFP#m3rFr+!h
+A()hA+QW 6.~m4I; /Ij ̃D%d!q:Q!F}fX m@`%&X(b
+EbXWmDn.x*5*
+WI j\lJvh+Pd n/Ѷl/1]G6*6]=iE n/ YY~,x`˵$<yLϥ7iWfDA pi5Ve ]_uCC
+|=\72=~%k~J`Ɋ$.4xIw
+5kFT^cjݵH#7ՑMW*CrUMkJ+ƽ K68pxFؠy=`=VWlVma ǧ-K\&^N]jRzQ^MzWGwOet5UKHڞm)Bj֔URrjZtA>Nw
+l>lk7ŠlZ_`5/8 {56v[T =7Z~oXN*`*]ܭ{i'{9M'AT@6~|M"6Sm8X<G|6(vȝÏdM)\zɳ5y|@O4q&#ހ7౽<WDހ $pM x+: oi7zx=ڷ.WhH^ 'cȾ RGhi>[wxhBxgA:ުam^织(ͅ4ݻ#ϕc/jy7ˊpWfut˷I>fu']E>dz""{9txɇ0q7lP63NvIwQT o[g/X$qm>bb‚ZlChhi>1pyE5!r=MG7|ɮ~ڼ4j3;|fJI>ɦio5=Նc\z&lz5[sBu\?u!BWax9M'Att:(h!ux$|j[v }^oYx|M?eΓ_mH~.{XrVdYcUSV*W6%d@@C4O%Ť=@PalnDv!99=`?Qܻzw6:-E_h.HxK88ӓF[{'z au ןoÔϚ.c_dYhq3VEن_Gnj28\iuPĒ9e,ћH5fi`xZIrG)43\Fm tRa gmuuiǠ NE_$>G %t-Óm% qcv`doi@9rǧ6?,) H/P"$+B;%lrKʁXgbәyENwFY0HNIwY^;zrV׎éc$Ls:%Tie8F%/ҶEi$dRf–I vS~{8<>ƶIߍ:
+E,E8|c=;x'cmh
+oXv޹g4E@ $G?dpFKTmC S"q>b3eį-=?ib8=O#BG)8>o8&x6|gȘ ^_8cݦ%qu~pֽY<)=5ʕ_WN8l&X./6YdJFY0HNI7_X^;zOrV׎étdx8i UcZ0λaKmUl)ezR>mT;| #J\<<`^llh !<pKw2h%@DZq&8ڦcfL05PC\+PN('.u89=`?Qܻzw6:-O#!G|΂؞.ç,')qʖ Oe6LEiRf4\%$VER7Y`N:}U[Ѝo.oMN:usWnxԭSNNMf`j(mx3 hD+˧X Q\D0|WD]UX,qWg=F UQ~^D+>Q/˾=L)+x!ˍ,TDȓ JiǏp,{xSZdsXVvΖ߫dNj"aD];xGH3Ռ5yx"r&$zvNJ)3,5ұRy}Ww^iG7:~/ʟWz(fO2Dа~ϱnY/,SmSNr`0޳iXQD#Z =Tu{yҩa ALcfL05e Qv4Nr!8^Ktx… u{&KJd3a{{>]1ߛP> R\ r\e
+ sEC,f'vRX~VZJ~ShN(2͞AHC֜(];~%bMdǚVW藿rF H}#nڪ(?PQ]DsSXz]“
+;h{8Djġr-Fdq*XNZP;
+&cJOlJq(FԥoFJf4wpyPj*晉3'P2%V8:-;{\`O+wzy9H~ԈCyw޿r`'|z97+1%&0xL֥Ћ%
+|u쌽XbDD_9c%|J+qn+w^e.u0^ #ҷ ;Z?Cf4wѽw)T
+HWn:_p
+4K([@ņ"u(҉Cq,Ei)
+vqi.B@7Gbɛ^߂aiޟOq@Yu|ԫ=~}<L
+hS{3iQU\(^)DQQ,2_G,~} 2E {9gT۫cɥ{mUUpspqlp0Kʹ|b41A\LrGTH`>9P w`EBOx;`=Ky0ZEC1-uɖU[
+*zcaxoWRTCrSU(LQ
+C=tp< ` ؟am
+#C-ݲ:X[_
+pH_;W`P2|(iF5QT37b$NؑK(H
+WNB ˨/'w
+YwP7X׻[P;oE۹{4{5sLL?:TF4)">O}NI|*g(֗bv)VGuĭJ4
+ PlÖm邡B`HE͸q0M{ `H\:1<B8(q0Q%#YF+Lr3%^t6VapX9+4Q(O҅CttNS)\ǃ !=xxF7MŋxN^>y4af(֗bv)o5}أ
+dL C.:ҵ-L)
+ĥc6-f 9"YF+Lr3%^t6="{sǶV|C( w}=CEWi_'ˆؤSva0H[
+
+m^ЪfO
+ x 0mc<<:xw2C?
+ 
+"}u`DBN58*_pܪ p8b&\V/i*(Xq BfJќ"=6`[Wh`Qd#׻AĬ|1ûE̵^ƙȱ0dq|#Vh -yHy|/p/k۵~mu{mWzD_d\;_y+>y}!_n"x4
+ e+1DD ҈"9UHKn
+Zބ^,]{cFGɧ0
+R`M)l>إ2QZG~+Yq`9𬋁] -] b`{d:?聩1xx@A?RBpR`)g6θqڄ&fw&
+)Ç}ɡdL HE|o0ې S K'3L:v{Dn5H^XdNѫ])\Qr*X!F6K5Xr>8G2G;]r!3Ya=ӶTbVHW4f8'u
+.mȜ*]kx6-QޕrY0 xh$1!8Op_IQh$C]ps6095jyxحܨam(8eCQeOjܣh"-8a;ˌNx^~
+rs
+|pFݑ38$
+)ÇH1fTIE9#&: OBD.p$4rrCAb_$՗(ESml7TiFNiѾH[
+7`WX?)04
+P`HP(3TOcK0WU~1jf}8xw 9LNa|6VM
+Gdwr% t:cd ?tH> OO\oEƮj[Z`eA. `c$Qgp&c`
+׋F)Jֶ S k6<v #AHcw1bcNb_'6HdN,MਮdXƊC,GxbľHw`F^oۻRcvFb @̓%'Fvg ,-)ft1&%eY ,vWW9uӞD|?^,R༺tjhWRWzW3V[^͇gO|wd+}.n'&۟m|<_[^?blxz?_-cq&/1N=9Ϧ_ovZ-c HHfoW)>NV{7S!ތ7@XB8偸ʀS4kdڿ8^K1x9zȒdv1*VRIL[aҧϳ4{ֻ[LGgv=wx1xCg.E&E>SgsP
+!l^HƋӬج(B!~F UCR1Ɯx?KB[EZԳ~.9͚7Ȥ=\:δ=BlPx:Mo9rZNOVn;+%NY^'e*ДW]QꍡVYDo#'N5@}v1'^h3n uwn9.
+(JNܰ/W7W(u<O'jy=Tik9|=R/=m^~],WFOyGƀp->Wj"߯VΉz2׼t[PJf ^"dUiI\'5[3SU|#kcUݛ>vaܥ콚۴muF@64܎U3HWO@8T5o`-zAZ"[lݖ_ȄV Z/? *aC޺GݫuKS|SJh5DO - 72L0j`iqJkN-e||~hEr]YŪ
+HHA{ǭ,D 7WepRW Dy :ЌN;lpT0jhY Y&6hxI7pG .6QJY)VyCq'3 *o(
+&9"5'%x'!0[@ +}NjAod v9J9l6T.X/w: ߂܄2g7܈%x#r.E Dg$
+FEuHA%8.bhL8ᇐ1` 84 $A4/^!nDܠ5O>'111rX@ q"2 ‰I5ƴtȸ$߄*)mFvG4#0HXN(~c1@Y 2R?S)4n4`iC^_LSoZ)%eL^R<sT+dTK,MG<=()|" @Lþ?"jg9!"Ƙ"KU]xTMshR75\Oळ&I: Qb<+)c8mԞO;\㐰
+!%f0zTPd!\@NH&]3Ѻv[ќUnȷ0i6S]|Q'HSt<gU
+HWkOKJ +6$DFZ{زM=U=~lV+:u:ϫŠׅWE(Ɗv3҈":*6"JaV)eJ$ l2кT*hTiB2) y6eVN[HIF(lsJ(lCT<_]n5?,p#6Szet&/T54W; ^( YJ邧2b[FelX}2et-_d`{8#$-B[> .PvQ% T+[NtLJ7&CWŔpB_Qy҂Nq{GK8 |f갰eP*7 U֔))j~X.ƴ LY>y
+NU2JIe6j \9Jb7Jyˁp
+`C3q&aݤwDN1E 0`B3F7p\WR} Β1" HZ)abUA.'do5$ii
+-[ Br2G.880^ y$e1<
+Ad<-F
+ ,P`Hց̎n󁺃f&KqY
+CQΑ nY=$^*ϵ~`T
+۱$Kc&+TVeݸ$@!]dTdDǍNJp =Z*#DŵmlAtp,,J:~U9E _QBJ4 \cp?h
+ژ-j^[9
+"Iĕ$Mm#% \<ԆdZhCS$kY@ Ğ5xDw2ABL9($X":M]ɤfQ\+2"s
+:~ǭ F mx@Ң·q5JˀG~EDpC˹@阣<dь>zP]4<= 4ה?fWaT:X)Pv $nD+HI=ЬQ$Hp'{>pQ)L%Սރh2:JHJN*" a @O+7=)H3C**-У](8 gL_Zu|~o:۱e֝|#bpiuU/!-{w7k1\
+t҂
+igoa0\ԣzr>'
+yo&[n
+r8C]gBj߻8#KxKN9yHMQ@*OG=~_;mdIx_fe`2?␵2
+T!0`eɍng/L:bojH7Y̧e$/2)y'EyM^rR-RБߑ|f1Xyf7B]#'X3~7B$NC%ÔXJ{y :> oV4{;$l姖>ZٱѐΛlD^F "gyXܹl9nqH)LbzLjDFln{gyfЈ7F<0H3|<ۓB['D( {dh"k|[A@K'7jfbK67%o.)E?Y{V,{e)Lt`׬(XpW#EFbDY<a=[_Qd: IzaBx|nl_1- o]8{<>c3g<ڪ/=emzD
+ +Taj=Qw#pِNz
+2( q`Mi6+ӊy
+i
+^m{ vOJG|6`CRH0
+aK㬖FU\\ݰZ9rT^IR RR 5U
+ZށTbO,QWyC,pU\8DkϔډPo,@!S:AŘ;ȂJ+7gHv:9( @`BWi-m`b
+5 DOu :0Z- s5V\*9[ajOKn0IHeD:z}洚8'N(Z/
+QU.qx)ѵƆj8M8cMT1(%^K>wX pDγn _FHqV1u
+S*caM! XCn2
+*LB*l
+h
+ [u$@R"$OQ(9%9`rYl,hADc<ca
++PYQ
+
+eBoԩl
+^%7qŵ277_wIq50cֺemݵᡢ>u)6mO¿jn䓠0i7'|МѭÅ xSL.AeL!u9,&bDO-!+,NO v 9ԧGۇ'~$Gd627ɳk.7:H5+?,T(Rfߒ=p G.ˊx4цH"qm0UւHqrVDKi$~IcHdI3Z0
+Jp=bϫ,S%2䪂Œ{a-+/ҿK].ؙ5)C$gn4@)+v$<G!![E<sjw ?0lh\FY.4
+n=[@KTe/hl24+}HV)@+(ex4RC^41&B֯h yr
+`*IRSU1@ .Td vx4\8,G-UEAZ:t&c9{fimK5bn ݒ[k4 ůS `gEhF}&qEѠ@ۻSȅBl 3NZ=In
+nouХGXܱQ1*wP$Iv! aS ;e0\Q^69`h\2pYպV /HZYF~T LU
+(_yP|l$B4+GQIMa"=orr _('T'tf޴6(?i4pVOIM~Jj\Q}[zPZN&m'B]fxCRxyt׭ n&ţyCMuuWE*ʷpYS.@PŇdـ_jzfDqk=fEP X/g?GO|O}
+՗h8Y]~{ Zfs.EтQ,A!닫Fw#O,1RL &2J%
+@6PD~Õ^ Tۙ"up{t)-P 5ReX}LX*2 #}G4@^GfG} at)"_z:N{ZVO ({_I%O4ADN喫%;J+(,)\&o2 ޤ Yǁ-=G:}q7R+*e^Iz^1iXr]dBχ,lTuVFRAՆ^sP0;&}=0k_}&y#hpgқ4&V=FvֆU<]7cEat:lCʣt 6p ]$h5eؤ0[U`IQ
+T'G$=Q&ԎGע1=eU>;OR:.fюpy
+]`X=Ӈ1'svc
+{;ZMCj=8䡦rp>WYYWNW $Ōbin: ]TҒE"|r50)'w\GkuHQ)--AӼ׍(ȩ%A>= C_?΃3^j׺}(D?,Ħ
+ټjq1'g=yE٪ L̙p_V"CH9Y=pt~b :S! Q+o^8V?[s] q_LEsw`h{0MD|\lܬ}[Qtu oOk9b~#M.7q{po]l7)I;aC0~xhZ-'7+6 ϵ#cwG6,!1߻2Z
+s?J\ 4Wyta7jZ=5Yoj֠מda6^<*`q(*v(#Y^k Y((MN <[sh#͔=(LyV .Ɖ!/=|^~۳H[6]fOodJG. SaLzdz
+D؁0kJҲ
+yGT@%HHjg􋋶v*\m?FӤ QwνM"X~pQT㓭Zq/I_LbZB
+Ռ`ĄA|R (ܜ,tދhWS c;JSҍGGI.5O1U}#=:P
+8l+hZotS,p> ta;tZ Bf:ipҁ4 \ai
+lXss"Z}:fP|3[];c)IT 2w b{0铉{$x *9Yk`O3'3 K+Obq14N$Z]o~w AqEy~~LVg"Z If*LMjʀC
+ nl"
+!`-V/ RlU{/Gű^-}&^FTW="1TK+=a77DqZ?MAV4"
+2ٷF<m&s;Tlq5H@CQsA?VNxhYgΔ%UUG>|yc#4g"|Oa >>cK;ON+<?ZxVS^X:(QP%Ah>biSEgƧIѬ@ wYhnkFQR]L-P9E'ϕOC^ $uFƤ¡y:Qՠ4gѷBhA pԢ2eC7 Ov:R+
+34g/\%}=$͐+i*iWf\$ .LNVJ)g \DI5L錝 9IEdf=ϔBy@&ѲE5mf-kLJҰb=ICSs@!P1.@q4KC=$ҫ%J>2|܀k{dRbJt*a0ܕ+'4N} :a4]o#~2<xNߏ3ֶmqb*UrOM[ix}q~|BaY
+[]
+e@;g]
+g 6:_ !@=̑"hqn0G쭴N)ϧet6`4f\Zz{M@+
+WRc30hҿNnM]A͵J5^?>:ߙ<}> Vmɓ)5YP߬W疢}~L@VɬڢmY|ճ8SkO2Gz!55Ő:UP/d"d9,l,ʏvUdTo0&8T̒$n @PoCNt^l
+;,V#6l^!9- q$01ަLdݑAVJ\ヅmn^{jZI{Amrks}~6?b#a$%tZj7gXww<|vwĕ#ԃL9d}
+^L 'g ` &8vjJX/DٱF^Z+X~?lNj, 5OZtٿMoDcs~J&0D+WyE쫡A(GǍf^mQ*Y|چ6}z _ʚq$M9@K{љrm&̶t>SP9B .sl8-tƊғKcVG(\ 3#ک8R$pGNYkiXtcP 8W`o߷}]YRCyw')&.E>6脣iB 
+:c/5e-L^nY*_rgzV@yX{؎*_mwgU7g!6][olIQ9tma=߫Ese|/<a/G~
+,'X;rz6/ 'M_WJx.T#*6p$G=Oak.|q}J?_tq@d L%?+",|ĠIO?[f$_qœQtp < q #ϟJ2]PE5G8; d.,e5تH}2N(*7tb2Ur'9N&w9(Q=}=R}@˩?]D,@6qӤ>˟PK,q!wjL))~8i)c5z7ux/Krź +uj[z_uhC*s^
+2)ϙZƺ۾˜mmO x
+v#i~@5ե ܢ@}"])mVbDS'9'8IbY)6fםQ{ɇz
+;uAHݜKlf3vRT/̩;,'4P.3=ygǤofmT#@Ă)|;W=>'{:r)wqWj2HS{$., ^VdH-~I7;LŇ'RNLZ y53n%d[LfS9?8-YU)4^BqV( fox 5B>,=ݨĶLҌӰW
+a@k㫉.۔axkf]XQvx8/ӵu.
+"r@C P)Mw[oEl`w+:prb@B>Ry"bDžJp*f`.O*N`84xJ/.$bio9|zu:?{4) 1Oxĸ\mˢİ~t>Ģ{ǾEi_5tr L3CeeZe?K9Gޅn73?WφZS]+$ .ٳ-DR쌟zq̠ ;=FM=w0;l_|yy?G!Z C9gMeOjҎy-]!v]@пgk,u:G7 m0+mΫB5]`49$T5JBΕC,hV;wNu_ᚤw 1d4]$pHGL1s̽5_)n0BZ㭄
+Rߘ#z DTH'*9HD?Ȣ@f@:nt"IjbX&P@3 Y$H16Fҗ3AvҜZ^%뼪&ꪎ\0ZL2 -6t!!6!
+-E"bUD] x&n{~һ%Hkƹ G~Z+koAF ۜyZej<۹G{ '673z:ս*z3>ݟeL[\,w)
+E2]m\;?y⼠) /b
+Ƴ(~?/-.R)\Nm}0$>ڷ/C#ᘎRg?cU0oe>ԉ#F* ho*\ZN]B1Pl` DҘK,3z- #&
+4|͈YC"]1PT$,lRjH
+wf!uV4p@1lF%M9@7j_ rƤ)Ij2|` 0A)]aʁxN)eS#Xylr8==Su~uQls/§@4s_o:,u`4t+犠\tUC:>Cr.ƺFgI;Uo_O_*1ٶV\j[.
+8{ J̑}ٲq."A Zz6n60"zki-ISzcq:}L
+1ڧ4ޱO6҈nt[yeHw8~<ӻЯP)QINĘB](
+Ĩdw(>*('>mo 3Ā('6ܗ-5|Cȯ85㚯
+Mjɸ}ZuV̵oFm[3Ǝ@V
+HWz8}?bVC;Hٳd#02$$HBe?8w?]\%L)njn^υ ?uMoUf>G2C-_z)gړ^~3}s
+,'_izm<je񙃦$9-jjCe/::U+i:VӋy]ѵ=,Z*a@@,יx"NBT2gJV6.(0Eg2K29e/.]b
+ a$CtrMsmN!OB1 KTՐ.$W#d |G#m
++N$:Fd.Xp ̆*c'kLIDD&g&|P_POIvCy?h㿦 ҃$Vx*P*c1$cD30R3F 1ַ 9/hihT_hj,F<
+Z)v;H)(j`G_q@zG,+ɱP;Z[㏡sT.m>MXN=5)dˣYPݷ'}څe kzbj^lA?Cv[ 0= ź^98y"yކ.o]OnC#b4ÚhcWj 4M %Sv2?>Cvm
+$[ODW]*wY[U( Z}_lŷX(?;K|P+`,;?#tinO
+zb llw/$/QDӥ"NFfBkT6YL yb~)<3h&z)JξiV-LQ .ooV؈kc-d~s~{o32*D<h+2̣,FO 6/#\[_pN
+ ҄x;'#zj2zcVDL
+J8|"q.gC.\L)L[3dNl==J gitEYO\k7{[,ܣRQY-Td`QupWy.\kNcK21{bB pX˹gX6y6 &shIځx}A :4`]݈H-̠ bNF8ԡ5|Pa #P5z\JG pbȴ|B "1<Ifg L/-'z"HZ o@St-Vrx
+g"P'\0ZtZPN0`>6Xll
+x+pȥw7{3wKNs1>q>r\:26-6o"mQrA(9oi%ΔڧG@i)Df@ .n*s*]D@Pí+y-ѷX7}$ޏˢ(=Ӯz-?`ϋKr~e@ tϸ$ N­8I?I}ITi+)PKf3r 5jخNڞ}1+N!̥b 5?ch6hL?
+!_JRV5ޓi]/Q `Z]<&?5tTP]:x{WA0:Gb7?ic;=//[in8; jiZUn)F] y)|s:qqaNgօb7$ s۩;FqrN$6]Ӽ$}#!. 2״N#rjNo|΅7=SU@X+kYAP_F-!XZ<C^WRI۾ u)C
+;IE*KR׏5OE-yc;YG}')wP 'lWڅZo}( _VHmI)$*}VPNJ`¼bxL`[`rC
+jN_aph5@H2ƷEEZS_ /zݩT-9ƹ`S n 341.96bf;
+5S;1Uf<S;NK'A*(#fVjN
+Z޵Z*Zwћ+ݽ@j)bqdRS ]2AYiӫ6|c0˟AٕlPבefMm2jw#+| EQ"D%j)`j.Ŋ\z=]Ruc#ah]4D C`4h gL'9 ^>~=ݲč5-E V>9,U\(_) H{~Լ')DLXtO%Ȯ3-
+q-Ͱ^`u<1σE<.߅0D̔yve*lk*u0ŝŬQɬ`<0+`
+:
+ɜcAQ!K5"N)D E^[{D^Ӷ52#/XSQ6t$ɒsWv+_:o&7phJ2$oews 4S+n߂$1H %)JoFa5|Cᒜ;c ʈ9-ye90$g9q;(l,  Cs'%r Cp{
+ KڛƪG1)󮴌n_<=8s.N8ĮW~B~{8D2wBM
+
+9 i-}8Knt8:ekZ\4TÝ^ĐS hp89E"rO"+ipz<Eˏo,0 ϕtԞ\iy8Kumb8 ũi lRo pn;=nj_3 O8/Wb>l5{rX!`1^XlT&A-:_ jw ً{>'#
+ I"Fɒ:^{rQ xEMKC3KӬLӮ_V*f
+?{S c޷v6UNػREh'F~€tmLՈ%Kaª^JqEpK5"˫k[WņK`/_5>o48 j
+Iuw]5fq*=*c)ؼ
+9﯎rH}{wj3p/NI"d}4.-Fg{E[B_ S]M1\frp6
+Ppui<M:TcpWc0FMhaPc8BQ9
+
+A5BnUe=*5)P4q=.Bv* (=^A$o<+ !Jֺ(`Q|vxe`=ݳ+Zy9ZI }7HWXT<gA*Tˠc(_)
+ 
+cpxkll q_E V/ c=d +H-J锤K~q|g&lmOMqO0OX3dmYf9ce2
+OYj  oD,0+ˣ:A+[-
+\UI><A_2Um\Bwʬ4h),Yce>bY,x/켒 -;e }OWl`
+p DjF`gWW_+XW1#U 85ƲԈ/2ڜxnGvS˰KA_iop{
+]Մ8ߖ΢Phܳ+ &
+Q+ Z CLd
+J&X m2s9[Wg3_JeYO;A$@0d$(A$D`>а7g?:MuuW_Uk2&l}͆(G!ׯha :ӌbA"2z%tf<BhنOTrxhy^IgmᲪ){ul4c(6}v|N,9@oKig/URb5cXMaz=f֥?#Am̑1~s̩6lkp捥9h=zs6ؽ& ?HT z&8A1ơ' 6܃~Sֹg;m2?bD8+@wvpI W{EI;p ͇'i!N=4
+U
+Y$HQ#r)J[ӜQmը]L{X'$ɭ**
+OD̲{M4*t/fG_T**3x0EԼX.npAO̘W!+57
+%r]_yϫHJqn1'+Az Ҏ*<C
+nI4sSeʮij.dP<uFQ˶&Ak۫Í%`Ğ
+8L[ȁԑVi$+dcj6~;)b:- ɟ
++ܽM". 4IWVz>
+
+É P) ! d'] ALP&`2AP6kK[c͛]6£St Cfsl1;48U;2Btg] -'FH坉~F(${8@E1A- p/vPi#<ns6;җ &/XDqA8   $I<RB> ;*y9AA%ǔzTtD;a`SFsb讏Or"-v|wpY\ARA0Kі8c%AG
+
+N.5$Bs6EԳ:"ao^h 
+)vX 5ƹ%_$]~&[z$͞UveAR3T%ZK~pSnC/'8bډh6Fp#ʬ^kz Ѹkr"Ј*ڮCH+XkHX"u#0~'#(&?|S`~mptdB?§-!Q\=AvGFcw6ajk66 ֊^~$j狰6ߐqOt\ݩp.tRc}<,c CqHG d{, dD齟;檷*.vJS`Q.qTBBpG#yc=8*1-3w$%9wfH ]e!:Jqeb0 C|T '0ɕ 4)ZĔo '$OY=r%l౾!OG U"p4;]oVz* D&F
+KAűԗu^Ko9bB%i/`FC!u7(Wa7BJ
+Qū#uqH$+6[/brtZa5[EəfTf:գ cI&;{7btҍ¢xH--#!B.eq83o2NDSxwzG唅tҘ}ꇜpS}0*%i IޅףV!qY#-qU^ʆ@84@L,,De}%#${.~d\Kj\}h#3)#t 8o#&˟ /͏s
+PqxJ*>n
+J(-ƒ<<k}@xz.ڠy1зZJM0ABӹG_W8!S/ Z|AHRJ8Le=t#B%-NJ}ȳjz.t8"TqU:q8OT:c*\"B>okH Mg-9v%`~,bj$sPyےЕ<솛j͛^M̚<e_@2KF3]<y=v8]J lU6ݜ:/xAFE8A8%Qͮl&9EI
+TQ<VΕpىkҋFXK#8!jr;*/ӕ`YZ/\`O:=}S[35VGeT!g0[jIPVmc#o>):ȧgnJwLblk&s|;-9p(؇q_07C<tfM34GF"T%DIU@q .ps L&M3B*#5"3ae)$!IGtUR:)nho( "i1|@RqX”1w}c rۈa(za.PBHJZtMEѤ2,IvKD}~~UŞ jj*5kv#.ўNt6|]U~˵#}0lw~ގڊ_$]*oAڧ?X G:5( Q5S T[)Y1WidgOF&x$6ìR+Q
+JQ`6yuȹ5</ H*i+u
+b_[H1}r(w.ႈ\HWjȷLJwry܍zqicc ""Y6Ĉ2˜bTJMRu[pC@K 9!K=l^WԬT{͕8)!9< ZJ[}}z3^WĨh 5:!ֈn0[Q烺,(|6ו#?9 {<\lv#}ߗsaK,@y_jž9u8!㝽 0
+HUnG~YɖK_
+c$$ oY9Fk9=@,!%H{Ƽg3ɽKM[K {\jեbΗߗŏ'gח׷7Czһ߾x_.qzN^Ha<9N?S]ZJ:J$tW/ϒTMx8QjOu<5\F&8)[˥&[j7lc-Wk.ɢa4֑?*_u<k8
+֒b]г"pU!Eޓ:~Tb= yj2/w)lc[{
+yCJ&xTX(Ae\Y;vBI+- f1|A|/1 (`e}%cZUg>;Rlp%Q)$렆;:k &X YF92 l7 t'
+@X[u<rIT ahq,0=jRQޘB/Տ >24
+7]o^^.JVސ$8 CYA=3hӊ`
+j R9)3!\$-wC%h0ͳĞR
+0000000016 00000 n
+0000000187 00000 n
+0000057205 00000 n
+0000000006 00000 f
+0000175537 00000 n
+0000000008 00000 f
+0000057256 00000 n
+0000000009 00000 f
+0000000010 00000 f
+0000000011 00000 f
+0000000012 00000 f
+0000000013 00000 f
+0000000014 00000 f
+0000000015 00000 f
+0000000018 00000 f
+0000175981 00000 n
+0000176012 00000 n
+0000000019 00000 f
+0000000020 00000 f
+0000000021 00000 f
+0000000022 00000 f
+0000000023 00000 f
+0000000024 00000 f
+0000000025 00000 f
+0000000026 00000 f
+0000000027 00000 f
+0000000029 00000 f
+0000175607 00000 n
+0000000030 00000 f
+0000000031 00000 f
+0000000032 00000 f
+0000000033 00000 f
+0000000034 00000 f
+0000000035 00000 f
+0000000036 00000 f
+0000000037 00000 f
+0000000040 00000 f
+0000175865 00000 n
+0000175896 00000 n
+0000000041 00000 f
+0000000042 00000 f
+0000000043 00000 f
+0000000044 00000 f
+0000000045 00000 f
+0000000046 00000 f
+0000000047 00000 f
+0000000048 00000 f
+0000000049 00000 f
+0000000000 00000 f
+0000175678 00000 n
+0000000000 00000 f
+0000000000 00000 f
+0000000000 00000 f
+0000000000 00000 f
+0000000000 00000 f
+0000000000 00000 f
+0000000000 00000 f
+0000000000 00000 f
+0000000000 00000 f
+0000175749 00000 n
+0000175780 00000 n
+0000000000 00000 f
+0000000000 00000 f
+0000000000 00000 f
+0000000000 00000 f
+0000000000 00000 f
+0000000000 00000 f
+0000000000 00000 f
+0000000000 00000 f
+0000000000 00000 f
+0000000000 00000 f
+0000060505 00000 n
+0000176097 00000 n
+0000057630 00000 n
+0000061161 00000 n
+0000060805 00000 n
+0000060983 00000 n
+0000060692 00000 n
+0000059086 00000 n
+0000059944 00000 n
+0000059992 00000 n
+0000060576 00000 n
+0000060607 00000 n
+0000061235 00000 n
+0000061543 00000 n
+0000062721 00000 n
+0000082146 00000 n
+0000107842 00000 n
+0000132259 00000 n
+0000137352 00000 n
+0000142455 00000 n
+0000159547 00000 n
+0000174275 00000 n
+0000176122 00000 n
+trailer <</Size 95/Root 1 0 R/Info 94 0 R/ID[<A62AE6DC91EF49CD9CCFC2B959900A7D><33F4B4E6B4824F3C934AA9C126304E54>]>> startxref 176316 %%EOF \ No newline at end of file
diff --git a/utils/logo.c b/utils/logo.c
index 9e3078f..ef6ba95 100644
--- a/utils/logo.c
+++ b/utils/logo.c
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 2001-2006 Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright © 2001-2021 Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
@@ -21,13 +21,13 @@
#include "utils.h"
#include "resources.h"
-#include "visual.h"
#include "minixpm.h"
#include <stdio.h>
#include "images/logo-50.xpm"
#include "images/logo-180.xpm"
+#include "images/logo-360.xpm"
/* Returns a pixmap of the xscreensaver logo.
*/
@@ -37,39 +37,41 @@ xscreensaver_logo (Screen *screen, Visual *visual,
unsigned long background_color,
unsigned long **pixels_ret, int *npixels_ret,
Pixmap *mask_ret,
- Bool big_p)
+ int size)
{
Display *dpy = DisplayOfScreen (screen);
- int depth = visual_depth (screen, visual);
- int iw, ih;
+ int x, y;
+ unsigned int w, h, bw;
+ Window root;
XImage *image;
Pixmap p = 0;
unsigned char *mask = 0;
+ unsigned int depth;
+ XGCValues gcv;
+ GC gc;
+
+ XGetGeometry (dpy, drawable, &root, &x, &y, &w, &h, &bw, &depth);
image = minixpm_to_ximage (dpy, visual, cmap, depth, background_color,
- (big_p ? logo_180_xpm : logo_50_xpm),
- &iw, &ih, pixels_ret, npixels_ret,
+ (size == 0 ? logo_50_xpm :
+ size == 1 ? logo_180_xpm : logo_360_xpm),
+ &w, &h, pixels_ret, npixels_ret,
(mask_ret ? &mask : 0));
+ if (! image) return 0;
- if (image)
- {
- XGCValues gcv;
- GC gc;
- p = XCreatePixmap (dpy, drawable, iw, ih, depth);
- gc = XCreateGC (dpy, p, 0, &gcv);
- XPutImage (dpy, p, gc, image, 0, 0, 0, 0, iw, ih);
- free (image->data);
- image->data = 0;
- XDestroyImage (image);
- XFreeGC (dpy, gc);
+ p = XCreatePixmap (dpy, drawable, w, h, depth);
+ gc = XCreateGC (dpy, p, 0, &gcv);
+ XPutImage (dpy, p, gc, image, 0, 0, 0, 0, w, h);
+ XDestroyImage (image);
+ XFreeGC (dpy, gc);
- if (mask_ret && mask)
- {
- *mask_ret = (Pixmap)
- XCreatePixmapFromBitmapData (dpy, drawable, (char *) mask,
- iw, ih, 1L, 0L, 1);
- free (mask);
- }
+ if (mask_ret && mask)
+ {
+ *mask_ret = (Pixmap)
+ XCreatePixmapFromBitmapData (dpy, drawable, (char *) mask,
+ w, h, 1, 0, 1);
+ free (mask);
}
+
return p;
}
diff --git a/utils/minixpm.c b/utils/minixpm.c
index 997e628..55f25be 100644
--- a/utils/minixpm.c
+++ b/utils/minixpm.c
@@ -60,7 +60,7 @@ XImage *
minixpm_to_ximage (Display *dpy, Visual *visual, Colormap colormap, int depth,
unsigned long transparent_color,
const char * const * data,
- int *width_ret, int *height_ret,
+ unsigned int *width_ret, unsigned int *height_ret,
unsigned long **pixels_ret, int *npixels_ret,
unsigned char **mask_ret)
{
diff --git a/utils/minixpm.h b/utils/minixpm.h
index f027894..8777f36 100644
--- a/utils/minixpm.h
+++ b/utils/minixpm.h
@@ -20,7 +20,8 @@
extern XImage * minixpm_to_ximage (Display *, Visual *, Colormap, int depth,
unsigned long transparent_color,
const char * const * data,
- int *width_ret, int *height_ret,
+ unsigned int *width_ret,
+ unsigned int *height_ret,
unsigned long **pixels_ret,
int *npixels_ret,
unsigned char **mask_ret);
diff --git a/utils/queue.h b/utils/queue.h
new file mode 100644
index 0000000..94bbf23
--- /dev/null
+++ b/utils/queue.h
@@ -0,0 +1,638 @@
+/* $NetBSD: queue.h,v 1.68 2014/11/19 08:10:01 uebayasi Exp $ */
+
+/*
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)queue.h 8.5 (Berkeley) 8/20/94
+ */
+
+#ifndef _QUEUE_H_
+#define _QUEUE_H_
+
+/*
+ * This file defines five types of data structures: singly-linked lists,
+ * lists, simple queues, tail queues, and circular queues.
+ *
+ * A singly-linked list is headed by a single forward pointer. The
+ * elements are singly linked for minimum space and pointer manipulation
+ * overhead at the expense of O(n) removal for arbitrary elements. New
+ * elements can be added to the list after an existing element or at the
+ * head of the list. Elements being removed from the head of the list
+ * should use the explicit macro for this purpose for optimum
+ * efficiency. A singly-linked list may only be traversed in the forward
+ * direction. Singly-linked lists are ideal for applications with large
+ * datasets and few or no removals or for implementing a LIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A simple queue is headed by a pair of pointers, one the head of the
+ * list and the other to the tail of the list. The elements are singly
+ * linked to save space, so elements can only be removed from the
+ * head of the list. New elements can be added to the list after
+ * an existing element, at the head of the list, or at the end of the
+ * list. A simple queue may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * A circle queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the list.
+ * A circle queue may be traversed in either direction, but has a more
+ * complex end of list detection.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ */
+
+/*
+ * Singly-linked List definitions.
+ */
+#define SLIST_HEAD(name, type) \
+struct name { \
+ struct type *slh_first; /* first element */ \
+}
+
+#define SLIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define SLIST_ENTRY(type) \
+struct { \
+ struct type *sle_next; /* next element */ \
+}
+
+/*
+ * Singly-linked List access methods.
+ */
+#define SLIST_FIRST(head) ((head)->slh_first)
+#define SLIST_END(head) NULL
+#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
+#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
+
+#define SLIST_FOREACH(var, head, field) \
+ for((var) = (head)->slh_first; \
+ (var) != SLIST_END(head); \
+ (var) = (var)->field.sle_next)
+
+#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = SLIST_FIRST((head)); \
+ (var) != SLIST_END(head) && \
+ ((tvar) = SLIST_NEXT((var), field), 1); \
+ (var) = (tvar))
+
+/*
+ * Singly-linked List functions.
+ */
+#define SLIST_INIT(head) do { \
+ (head)->slh_first = SLIST_END(head); \
+} while (/*CONSTCOND*/0)
+
+#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
+ (elm)->field.sle_next = (slistelm)->field.sle_next; \
+ (slistelm)->field.sle_next = (elm); \
+} while (/*CONSTCOND*/0)
+
+#define SLIST_INSERT_HEAD(head, elm, field) do { \
+ (elm)->field.sle_next = (head)->slh_first; \
+ (head)->slh_first = (elm); \
+} while (/*CONSTCOND*/0)
+
+#define SLIST_REMOVE_AFTER(slistelm, field) do { \
+ (slistelm)->field.sle_next = \
+ SLIST_NEXT(SLIST_NEXT((slistelm), field), field); \
+} while (/*CONSTCOND*/0)
+
+#define SLIST_REMOVE_HEAD(head, field) do { \
+ (head)->slh_first = (head)->slh_first->field.sle_next; \
+} while (/*CONSTCOND*/0)
+
+#define SLIST_REMOVE(head, elm, type, field) do { \
+ if ((head)->slh_first == (elm)) { \
+ SLIST_REMOVE_HEAD((head), field); \
+ } \
+ else { \
+ struct type *curelm = (head)->slh_first; \
+ while(curelm->field.sle_next != (elm)) \
+ curelm = curelm->field.sle_next; \
+ curelm->field.sle_next = \
+ curelm->field.sle_next->field.sle_next; \
+ } \
+} while (/*CONSTCOND*/0)
+
+
+/*
+ * List definitions.
+ */
+#define LIST_HEAD(name, type) \
+struct name { \
+ struct type *lh_first; /* first element */ \
+}
+
+#define LIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define LIST_ENTRY(type) \
+struct { \
+ struct type *le_next; /* next element */ \
+ struct type **le_prev; /* address of previous next element */ \
+}
+
+/*
+ * List access methods.
+ */
+#define LIST_FIRST(head) ((head)->lh_first)
+#define LIST_END(head) NULL
+#define LIST_EMPTY(head) ((head)->lh_first == LIST_END(head))
+#define LIST_NEXT(elm, field) ((elm)->field.le_next)
+
+#define LIST_FOREACH(var, head, field) \
+ for ((var) = ((head)->lh_first); \
+ (var) != LIST_END(head); \
+ (var) = ((var)->field.le_next))
+
+#define LIST_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = LIST_FIRST((head)); \
+ (var) != LIST_END(head) && \
+ ((tvar) = LIST_NEXT((var), field), 1); \
+ (var) = (tvar))
+
+#define LIST_MOVE(head1, head2) do { \
+ LIST_INIT((head2)); \
+ if (!LIST_EMPTY((head1))) { \
+ (head2)->lh_first = (head1)->lh_first; \
+ LIST_INIT((head1)); \
+ } \
+} while (/*CONSTCOND*/0)
+
+/*
+ * List functions.
+ */
+#if defined(QUEUEDEBUG)
+#define QUEUEDEBUG_LIST_INSERT_HEAD(head, elm, field) \
+ if ((head)->lh_first && \
+ (head)->lh_first->field.le_prev != &(head)->lh_first) \
+ QUEUEDEBUG_ABORT("LIST_INSERT_HEAD %p %s:%d", (head), \
+ __FILE__, __LINE__);
+#define QUEUEDEBUG_LIST_OP(elm, field) \
+ if ((elm)->field.le_next && \
+ (elm)->field.le_next->field.le_prev != \
+ &(elm)->field.le_next) \
+ QUEUEDEBUG_ABORT("LIST_* forw %p %s:%d", (elm), \
+ __FILE__, __LINE__); \
+ if (*(elm)->field.le_prev != (elm)) \
+ QUEUEDEBUG_ABORT("LIST_* back %p %s:%d", (elm), \
+ __FILE__, __LINE__);
+#define QUEUEDEBUG_LIST_POSTREMOVE(elm, field) \
+ (elm)->field.le_next = (void *)1L; \
+ (elm)->field.le_prev = (void *)1L;
+#else
+#define QUEUEDEBUG_LIST_INSERT_HEAD(head, elm, field)
+#define QUEUEDEBUG_LIST_OP(elm, field)
+#define QUEUEDEBUG_LIST_POSTREMOVE(elm, field)
+#endif
+
+#define LIST_INIT(head) do { \
+ (head)->lh_first = LIST_END(head); \
+} while (/*CONSTCOND*/0)
+
+#define LIST_INSERT_AFTER(listelm, elm, field) do { \
+ QUEUEDEBUG_LIST_OP((listelm), field) \
+ if (((elm)->field.le_next = (listelm)->field.le_next) != \
+ LIST_END(head)) \
+ (listelm)->field.le_next->field.le_prev = \
+ &(elm)->field.le_next; \
+ (listelm)->field.le_next = (elm); \
+ (elm)->field.le_prev = &(listelm)->field.le_next; \
+} while (/*CONSTCOND*/0)
+
+#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
+ QUEUEDEBUG_LIST_OP((listelm), field) \
+ (elm)->field.le_prev = (listelm)->field.le_prev; \
+ (elm)->field.le_next = (listelm); \
+ *(listelm)->field.le_prev = (elm); \
+ (listelm)->field.le_prev = &(elm)->field.le_next; \
+} while (/*CONSTCOND*/0)
+
+#define LIST_INSERT_HEAD(head, elm, field) do { \
+ QUEUEDEBUG_LIST_INSERT_HEAD((head), (elm), field) \
+ if (((elm)->field.le_next = (head)->lh_first) != LIST_END(head))\
+ (head)->lh_first->field.le_prev = &(elm)->field.le_next;\
+ (head)->lh_first = (elm); \
+ (elm)->field.le_prev = &(head)->lh_first; \
+} while (/*CONSTCOND*/0)
+
+#define LIST_REMOVE(elm, field) do { \
+ QUEUEDEBUG_LIST_OP((elm), field) \
+ if ((elm)->field.le_next != NULL) \
+ (elm)->field.le_next->field.le_prev = \
+ (elm)->field.le_prev; \
+ *(elm)->field.le_prev = (elm)->field.le_next; \
+ QUEUEDEBUG_LIST_POSTREMOVE((elm), field) \
+} while (/*CONSTCOND*/0)
+
+#define LIST_REPLACE(elm, elm2, field) do { \
+ if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
+ (elm2)->field.le_next->field.le_prev = \
+ &(elm2)->field.le_next; \
+ (elm2)->field.le_prev = (elm)->field.le_prev; \
+ *(elm2)->field.le_prev = (elm2); \
+ QUEUEDEBUG_LIST_POSTREMOVE((elm), field) \
+} while (/*CONSTCOND*/0)
+
+/*
+ * Simple queue definitions.
+ */
+#define SIMPLEQ_HEAD(name, type) \
+struct name { \
+ struct type *sqh_first; /* first element */ \
+ struct type **sqh_last; /* addr of last next element */ \
+}
+
+#define SIMPLEQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).sqh_first }
+
+#define SIMPLEQ_ENTRY(type) \
+struct { \
+ struct type *sqe_next; /* next element */ \
+}
+
+/*
+ * Simple queue access methods.
+ */
+#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
+#define SIMPLEQ_END(head) NULL
+#define SIMPLEQ_EMPTY(head) ((head)->sqh_first == SIMPLEQ_END(head))
+#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
+
+#define SIMPLEQ_FOREACH(var, head, field) \
+ for ((var) = ((head)->sqh_first); \
+ (var) != SIMPLEQ_END(head); \
+ (var) = ((var)->field.sqe_next))
+
+#define SIMPLEQ_FOREACH_SAFE(var, head, field, next) \
+ for ((var) = ((head)->sqh_first); \
+ (var) != SIMPLEQ_END(head) && \
+ ((next = ((var)->field.sqe_next)), 1); \
+ (var) = (next))
+
+/*
+ * Simple queue functions.
+ */
+#define SIMPLEQ_INIT(head) do { \
+ (head)->sqh_first = NULL; \
+ (head)->sqh_last = &(head)->sqh_first; \
+} while (/*CONSTCOND*/0)
+
+#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+ (head)->sqh_first = (elm); \
+} while (/*CONSTCOND*/0)
+
+#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.sqe_next = NULL; \
+ *(head)->sqh_last = (elm); \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+} while (/*CONSTCOND*/0)
+
+#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+ (listelm)->field.sqe_next = (elm); \
+} while (/*CONSTCOND*/0)
+
+#define SIMPLEQ_REMOVE_HEAD(head, field) do { \
+ if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
+ (head)->sqh_last = &(head)->sqh_first; \
+} while (/*CONSTCOND*/0)
+
+#define SIMPLEQ_REMOVE_AFTER(head, elm, field) do { \
+ if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \
+ == NULL) \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+} while (/*CONSTCOND*/0)
+
+#define SIMPLEQ_REMOVE(head, elm, type, field) do { \
+ if ((head)->sqh_first == (elm)) { \
+ SIMPLEQ_REMOVE_HEAD((head), field); \
+ } else { \
+ struct type *curelm = (head)->sqh_first; \
+ while (curelm->field.sqe_next != (elm)) \
+ curelm = curelm->field.sqe_next; \
+ if ((curelm->field.sqe_next = \
+ curelm->field.sqe_next->field.sqe_next) == NULL) \
+ (head)->sqh_last = &(curelm)->field.sqe_next; \
+ } \
+} while (/*CONSTCOND*/0)
+
+#define SIMPLEQ_CONCAT(head1, head2) do { \
+ if (!SIMPLEQ_EMPTY((head2))) { \
+ *(head1)->sqh_last = (head2)->sqh_first; \
+ (head1)->sqh_last = (head2)->sqh_last; \
+ SIMPLEQ_INIT((head2)); \
+ } \
+} while (/*CONSTCOND*/0)
+
+#define SIMPLEQ_LAST(head, type, field) \
+ (SIMPLEQ_EMPTY((head)) ? \
+ NULL : \
+ ((struct type *)(void *) \
+ ((char *)((head)->sqh_last) - offsetof(struct type, field))))
+
+/*
+ * Tail queue definitions.
+ */
+#define _TAILQ_HEAD(name, type, qual) \
+struct name { \
+ qual type *tqh_first; /* first element */ \
+ qual type *qual *tqh_last; /* addr of last next element */ \
+}
+#define TAILQ_HEAD(name, type) _TAILQ_HEAD(name, struct type,)
+
+#define TAILQ_HEAD_INITIALIZER(head) \
+ { TAILQ_END(head), &(head).tqh_first }
+
+#define _TAILQ_ENTRY(type, qual) \
+struct { \
+ qual type *tqe_next; /* next element */ \
+ qual type *qual *tqe_prev; /* address of previous next element */\
+}
+#define TAILQ_ENTRY(type) _TAILQ_ENTRY(struct type,)
+
+/*
+ * Tail queue access methods.
+ */
+#define TAILQ_FIRST(head) ((head)->tqh_first)
+#define TAILQ_END(head) (NULL)
+#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
+#define TAILQ_LAST(head, headname) \
+ (*(((struct headname *)((head)->tqh_last))->tqh_last))
+#define TAILQ_PREV(elm, headname, field) \
+ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+#define TAILQ_EMPTY(head) (TAILQ_FIRST(head) == TAILQ_END(head))
+
+
+#define TAILQ_FOREACH(var, head, field) \
+ for ((var) = ((head)->tqh_first); \
+ (var) != TAILQ_END(head); \
+ (var) = ((var)->field.tqe_next))
+
+#define TAILQ_FOREACH_SAFE(var, head, field, next) \
+ for ((var) = ((head)->tqh_first); \
+ (var) != TAILQ_END(head) && \
+ ((next) = TAILQ_NEXT(var, field), 1); (var) = (next))
+
+#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
+ for ((var) = (*(((struct headname *)((head)->tqh_last))->tqh_last));\
+ (var) != TAILQ_END(head); \
+ (var) = (*(((struct headname *)((var)->field.tqe_prev))->tqh_last)))
+
+#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, prev) \
+ for ((var) = TAILQ_LAST((head), headname); \
+ (var) != TAILQ_END(head) && \
+ ((prev) = TAILQ_PREV((var), headname, field), 1); (var) = (prev))
+
+/*
+ * Tail queue functions.
+ */
+#if defined(QUEUEDEBUG)
+#define QUEUEDEBUG_TAILQ_INSERT_HEAD(head, elm, field) \
+ if ((head)->tqh_first && \
+ (head)->tqh_first->field.tqe_prev != &(head)->tqh_first) \
+ QUEUEDEBUG_ABORT("TAILQ_INSERT_HEAD %p %s:%d", (head), \
+ __FILE__, __LINE__);
+#define QUEUEDEBUG_TAILQ_INSERT_TAIL(head, elm, field) \
+ if (*(head)->tqh_last != NULL) \
+ QUEUEDEBUG_ABORT("TAILQ_INSERT_TAIL %p %s:%d", (head), \
+ __FILE__, __LINE__);
+#define QUEUEDEBUG_TAILQ_OP(elm, field) \
+ if ((elm)->field.tqe_next && \
+ (elm)->field.tqe_next->field.tqe_prev != \
+ &(elm)->field.tqe_next) \
+ QUEUEDEBUG_ABORT("TAILQ_* forw %p %s:%d", (elm), \
+ __FILE__, __LINE__); \
+ if (*(elm)->field.tqe_prev != (elm)) \
+ QUEUEDEBUG_ABORT("TAILQ_* back %p %s:%d", (elm), \
+ __FILE__, __LINE__);
+#define QUEUEDEBUG_TAILQ_PREREMOVE(head, elm, field) \
+ if ((elm)->field.tqe_next == NULL && \
+ (head)->tqh_last != &(elm)->field.tqe_next) \
+ QUEUEDEBUG_ABORT("TAILQ_PREREMOVE head %p elm %p %s:%d",\
+ (head), (elm), __FILE__, __LINE__);
+#define QUEUEDEBUG_TAILQ_POSTREMOVE(elm, field) \
+ (elm)->field.tqe_next = (void *)1L; \
+ (elm)->field.tqe_prev = (void *)1L;
+#else
+#define QUEUEDEBUG_TAILQ_INSERT_HEAD(head, elm, field)
+#define QUEUEDEBUG_TAILQ_INSERT_TAIL(head, elm, field)
+#define QUEUEDEBUG_TAILQ_OP(elm, field)
+#define QUEUEDEBUG_TAILQ_PREREMOVE(head, elm, field)
+#define QUEUEDEBUG_TAILQ_POSTREMOVE(elm, field)
+#endif
+
+#define TAILQ_INIT(head) do { \
+ (head)->tqh_first = TAILQ_END(head); \
+ (head)->tqh_last = &(head)->tqh_first; \
+} while (/*CONSTCOND*/0)
+
+#define TAILQ_INSERT_HEAD(head, elm, field) do { \
+ QUEUEDEBUG_TAILQ_INSERT_HEAD((head), (elm), field) \
+ if (((elm)->field.tqe_next = (head)->tqh_first) != TAILQ_END(head))\
+ (head)->tqh_first->field.tqe_prev = \
+ &(elm)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+ (head)->tqh_first = (elm); \
+ (elm)->field.tqe_prev = &(head)->tqh_first; \
+} while (/*CONSTCOND*/0)
+
+#define TAILQ_INSERT_TAIL(head, elm, field) do { \
+ QUEUEDEBUG_TAILQ_INSERT_TAIL((head), (elm), field) \
+ (elm)->field.tqe_next = TAILQ_END(head); \
+ (elm)->field.tqe_prev = (head)->tqh_last; \
+ *(head)->tqh_last = (elm); \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+} while (/*CONSTCOND*/0)
+
+#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ QUEUEDEBUG_TAILQ_OP((listelm), field) \
+ if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != \
+ TAILQ_END(head)) \
+ (elm)->field.tqe_next->field.tqe_prev = \
+ &(elm)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+ (listelm)->field.tqe_next = (elm); \
+ (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
+} while (/*CONSTCOND*/0)
+
+#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
+ QUEUEDEBUG_TAILQ_OP((listelm), field) \
+ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
+ (elm)->field.tqe_next = (listelm); \
+ *(listelm)->field.tqe_prev = (elm); \
+ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
+} while (/*CONSTCOND*/0)
+
+#define TAILQ_REMOVE(head, elm, field) do { \
+ QUEUEDEBUG_TAILQ_PREREMOVE((head), (elm), field) \
+ QUEUEDEBUG_TAILQ_OP((elm), field) \
+ if (((elm)->field.tqe_next) != TAILQ_END(head)) \
+ (elm)->field.tqe_next->field.tqe_prev = \
+ (elm)->field.tqe_prev; \
+ else \
+ (head)->tqh_last = (elm)->field.tqe_prev; \
+ *(elm)->field.tqe_prev = (elm)->field.tqe_next; \
+ QUEUEDEBUG_TAILQ_POSTREMOVE((elm), field); \
+} while (/*CONSTCOND*/0)
+
+#define TAILQ_REPLACE(head, elm, elm2, field) do { \
+ if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != \
+ TAILQ_END(head)) \
+ (elm2)->field.tqe_next->field.tqe_prev = \
+ &(elm2)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm2)->field.tqe_next; \
+ (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
+ *(elm2)->field.tqe_prev = (elm2); \
+ QUEUEDEBUG_TAILQ_POSTREMOVE((elm), field); \
+} while (/*CONSTCOND*/0)
+
+#define TAILQ_CONCAT(head1, head2, field) do { \
+ if (!TAILQ_EMPTY(head2)) { \
+ *(head1)->tqh_last = (head2)->tqh_first; \
+ (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
+ (head1)->tqh_last = (head2)->tqh_last; \
+ TAILQ_INIT((head2)); \
+ } \
+} while (/*CONSTCOND*/0)
+
+/*
+ * Singly-linked Tail queue declarations.
+ */
+#define STAILQ_HEAD(name, type) \
+struct name { \
+ struct type *stqh_first; /* first element */ \
+ struct type **stqh_last; /* addr of last next element */ \
+}
+
+#define STAILQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).stqh_first }
+
+#define STAILQ_ENTRY(type) \
+struct { \
+ struct type *stqe_next; /* next element */ \
+}
+
+/*
+ * Singly-linked Tail queue access methods.
+ */
+#define STAILQ_FIRST(head) ((head)->stqh_first)
+#define STAILQ_END(head) NULL
+#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
+#define STAILQ_EMPTY(head) (STAILQ_FIRST(head) == STAILQ_END(head))
+
+/*
+ * Singly-linked Tail queue functions.
+ */
+#define STAILQ_INIT(head) do { \
+ (head)->stqh_first = NULL; \
+ (head)->stqh_last = &(head)->stqh_first; \
+} while (/*CONSTCOND*/0)
+
+#define STAILQ_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.stqe_next = (head)->stqh_first) == NULL) \
+ (head)->stqh_last = &(elm)->field.stqe_next; \
+ (head)->stqh_first = (elm); \
+} while (/*CONSTCOND*/0)
+
+#define STAILQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.stqe_next = NULL; \
+ *(head)->stqh_last = (elm); \
+ (head)->stqh_last = &(elm)->field.stqe_next; \
+} while (/*CONSTCOND*/0)
+
+#define STAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ if (((elm)->field.stqe_next = (listelm)->field.stqe_next) == NULL)\
+ (head)->stqh_last = &(elm)->field.stqe_next; \
+ (listelm)->field.stqe_next = (elm); \
+} while (/*CONSTCOND*/0)
+
+#define STAILQ_REMOVE_HEAD(head, field) do { \
+ if (((head)->stqh_first = (head)->stqh_first->field.stqe_next) == NULL) \
+ (head)->stqh_last = &(head)->stqh_first; \
+} while (/*CONSTCOND*/0)
+
+#define STAILQ_REMOVE(head, elm, type, field) do { \
+ if ((head)->stqh_first == (elm)) { \
+ STAILQ_REMOVE_HEAD((head), field); \
+ } else { \
+ struct type *curelm = (head)->stqh_first; \
+ while (curelm->field.stqe_next != (elm)) \
+ curelm = curelm->field.stqe_next; \
+ if ((curelm->field.stqe_next = \
+ curelm->field.stqe_next->field.stqe_next) == NULL) \
+ (head)->stqh_last = &(curelm)->field.stqe_next; \
+ } \
+} while (/*CONSTCOND*/0)
+
+#define STAILQ_FOREACH(var, head, field) \
+ for ((var) = ((head)->stqh_first); \
+ (var); \
+ (var) = ((var)->field.stqe_next))
+
+#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = STAILQ_FIRST((head)); \
+ (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \
+ (var) = (tvar))
+
+#define STAILQ_CONCAT(head1, head2) do { \
+ if (!STAILQ_EMPTY((head2))) { \
+ *(head1)->stqh_last = (head2)->stqh_first; \
+ (head1)->stqh_last = (head2)->stqh_last; \
+ STAILQ_INIT((head2)); \
+ } \
+} while (/*CONSTCOND*/0)
+
+#define STAILQ_LAST(head, type, field) \
+ (STAILQ_EMPTY((head)) ? \
+ NULL : \
+ ((struct type *)(void *) \
+ ((char *)((head)->stqh_last) - offsetof(struct type, field))))
+
+#endif /* !_QUEUE_H_ */
diff --git a/utils/textclient-mobile.c b/utils/textclient-mobile.c
index 4d0d891..8745cb0 100644
--- a/utils/textclient-mobile.c
+++ b/utils/textclient-mobile.c
@@ -16,7 +16,7 @@
#include "utils.h"
-#if defined(USE_IPHONE) || defined(HAVE_ANDROID) /* whole file */
+#if defined(HAVE_IPHONE) || defined(HAVE_ANDROID) /* whole file */
#include "textclient.h"
#include "resources.h"
diff --git a/utils/textclient.c b/utils/textclient.c
index fe40928..4a4c895 100644
--- a/utils/textclient.c
+++ b/utils/textclient.c
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 2012-2016 Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright © 2012-2021 Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
@@ -22,7 +22,7 @@
#include "utils.h"
-#if !defined(USE_IPHONE) && !defined(HAVE_ANDROID) /* whole file */
+#if !defined(HAVE_IPHONE) && !defined(HAVE_ANDROID) /* whole file */
#include "textclient.h"
#include "resources.h"
@@ -117,6 +117,72 @@ escape_str (char *s, const char *src)
}
#endif
+
+/* Let's see if we're able to fork and exec at all. Thanks, macOS.
+ */
+static Bool
+selftest (void)
+{
+ static Bool done = False;
+ pid_t pid;
+ char buf [255];
+ if (done) return True;
+
+ pid = fork ();
+ switch ((int) pid)
+ {
+ case -1:
+ sprintf (buf, "%s: textclient: selftest: couldn't fork", progname);
+ perror (buf);
+ return False;
+
+ case 0: /* child */
+ {
+ char * const av[] = { "/bin/sh", "-c", "true", 0 };
+ execvp (av[0], av);
+ exit (1); /* exits child fork */
+ break;
+ }
+
+ default: /* parent */
+ {
+ int status = -1;
+ int i;
+ /* Busy-loops are bad mmmmkayyyy */
+ struct timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 100000L; /* 0.1 sec */
+ for (i = 0; i < 50; i++) { /* 5 sec max */
+ pid_t pid2 = waitpid (pid, &status, 0);
+ if (pid == pid2) break;
+ (void) select (0, 0, 0, 0, &tv);
+ }
+
+ if (status != 0)
+ {
+# ifdef DEBUG
+ fprintf (stderr, "%s: selftest: textclient: status %d\n",
+ progname, status);
+# endif
+ return False;
+ }
+ else
+ {
+# ifdef DEBUG
+ fprintf (stderr, "%s: textclient: selftest ok\n", progname);
+# endif
+ done = True;
+ }
+ break;
+ }
+ }
+
+ return True;
+}
+
+
+static void start_timer (text_data *d);
+
static void
launch_text_generator (text_data *d)
{
@@ -142,6 +208,15 @@ launch_text_generator (text_data *d)
char *cmd = s = malloc ((strlen(oprogram)) * 2 + 100);
# endif
+ if (!selftest())
+ {
+ if (!d->out_buffer || !*d->out_buffer)
+ d->out_buffer = "Can't exec; Gatekeeper problem?\r\n\r\n";
+ start_timer (d);
+ free (cmd);
+ return;
+ }
+
strcpy (s, "( ");
strcat (s, oprogram);
s += strlen (s);
@@ -204,26 +279,39 @@ launch_text_generator (text_data *d)
free (text_mode);
}
- strcpy (s, text_mode_flag);
- s += strlen (s);
-
- if (value_res)
+ /* If the 'program' resource already has a text-mode option in it,
+ don't override that! 'gltext' does this. */
+ if (! (strstr (cmd, " --date") ||
+ strstr (cmd, " --text") ||
+ strstr (cmd, " --file") ||
+ strstr (cmd, " --url") ||
+ strstr (cmd, " --program")))
{
- size_t old_s = s - cmd;
- char *value = get_string_resource (d->dpy, value_res, "");
- if (!value)
- value = strdup("");
- cmd = realloc(cmd, cmd_capacity + strlen(value) * 2);
- s = cmd + old_s;
- *s = ' ';
- ++s;
- s = escape_str(s, value);
- free(value);
+ strcpy (s, text_mode_flag);
+ s += strlen (s);
+
+ if (value_res)
+ {
+ size_t old_s = s - cmd;
+ char *value = get_string_resource (d->dpy, value_res, "");
+ if (!value)
+ value = strdup("");
+ cmd = realloc(cmd, cmd_capacity + strlen(value) * 2);
+ s = cmd + old_s;
+ *s = ' ';
+ ++s;
+ s = escape_str(s, value);
+ free(value);
+ }
}
# endif /* HAVE_COCOA */
}
+# if 1
strcpy (s, " ) 2>&1");
+# else
+ strcpy (s, " )");
+# endif
# ifdef DEBUG
fprintf (stderr, "%s: textclient: launch %s: %s\n", progname,
@@ -477,6 +565,13 @@ textclient_open (Display *dpy)
d->program = get_string_resource (dpy, "program", "Program");
+ /* Just in case the resource is blank, e.g. gltext. */
+ if (!d->program || !*d->program || !strcmp(d->program, "(default)"))
+ {
+ if (d->program) free (d->program);
+ d->program = strdup ("xscreensaver-text");
+ }
+
# ifdef HAVE_FORKPTY
/* Kludge for MacOS standalone mode: see OSX/SaverRunner.m. */
@@ -670,4 +765,4 @@ textclient_putc (text_data *d, XKeyEvent *k)
return False;
}
-#endif /* !USE_IPHONE -- whole file */
+#endif /* !HAVE_IPHONE -- whole file */
diff --git a/utils/textclient.h b/utils/textclient.h
index 0fe582d..5be8079 100644
--- a/utils/textclient.h
+++ b/utils/textclient.h
@@ -14,7 +14,7 @@
#ifndef __TEXTCLIENT_H__
#define __TEXTCLIENT_H__
-# ifdef USE_IPHONE
+# ifdef HAVE_IPHONE
# undef HAVE_FORKPTY
# endif
@@ -29,7 +29,7 @@ extern void textclient_reshape (text_data *,
extern int textclient_getc (text_data *);
extern Bool textclient_putc (text_data *, XKeyEvent *);
-# if defined(USE_IPHONE) || defined(HAVE_ANDROID)
+# if defined(HAVE_IPHONE) || defined(HAVE_ANDROID)
extern char *textclient_mobile_date_string (void);
extern char *textclient_mobile_url_string (Display *, const char *url);
# endif
diff --git a/utils/thread_util.c b/utils/thread_util.c
index 71c8633..7d7fd10 100644
--- a/utils/thread_util.c
+++ b/utils/thread_util.c
@@ -28,13 +28,8 @@ implied warranty.
# include <alloca.h>
#endif
-#if HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-
#if defined __MACH__ && defined __APPLE__ /* OS X, iOS */
# include <sys/sysctl.h>
-# include <inttypes.h>
#endif
#include "thread_util.h"
@@ -42,238 +37,12 @@ implied warranty.
#include "aligned_malloc.h"
#include "resources.h"
-#define IS_POWER_OF_2(x) ((x) > 0 && !((x) & ((x) - 1)))
-
-/*
- arraysize(a). Also known as countof(x), XtNumber(x), NELEMS(x), LEN(x),
- NUMOF(x), ARRAY_SIZE(x), etc., since the fine folks behind C never got
- around to including this incredibly useful macro in the standard library,
- which is where it belongs.
-
- Much of the code here assumes that multiple processors in a system all use
- the same cache line size...which might be wrong on occasion.
-*/
-
-#define arraysize(a) (sizeof(a) / sizeof(*(a)))
-#define arrayend(a) ((a) + arraysize(a))
-
-/*
-These numbers are from:
-- Linux: arch/(arch name)/include/asm/cache.h, note
- L1_CACHE_BYTES/L1_CACHE_SHIFT/SMP_CACHE_BYTES.
-- FreeBSD: sys/(sys name)/include/param.h, note
- CACHE_LINE_SHIFT/CACHE_LINE_SIZE.
-
-Preprocessor symbols come from:
-- TARGET_CPU_CPP_BUILTINS() in the GNU C preprocessor
- <http://code.ohloh.net/?s=%22TARGET_CPU_CPP_BUILTINS%22&fp=304413>
-- http://predef.sourceforge.net/
-*/
-
-/*
-Several architectures need preprocessor symbols.
-
-Qualcomm Hexagon: 1 << 5
-Imagination Technologies META: 1 << 6
-OpenRISC: 16 (Linux has the cache line size as a todo.)
-Unicore: 1 << 5
-*/
-
#if HAVE_PTHREAD
# if !HAVE_UNISTD_H
# error unistd.h must be present whenever pthread.h is.
# endif
-# if defined __MACH__ && defined __APPLE__ /* OS X, iOS */
-# include <TargetConditionals.h> /* For TARGET_OS_IPHONE. */
-# ifdef TARGET_OS_IPHONE
-# define _CACHE_LINE_SIZE 64
-# endif
-# endif
-
-# if defined __FreeBSD__ && !defined _CACHE_LINE_SIZE
-# include <machine/param.h>
-# ifdef CACHE_LINE_SIZE
-# define _CACHE_LINE_SIZE CACHE_LINE_SIZE
-# endif
-# endif
-
-# if !defined _CACHE_LINE_SIZE
-# if defined __alpha || defined __alpha__
-/* DEC Alpha */
-# define _CACHE_LINE_SIZE 64 /* EV6 and above. EV4 and EV5 use 32 bytes. */
-# elif defined __arm__
-/* ARM architecture */
-# define _CACHE_LINE_SIZE (1 << 6)
-# elif defined __AVR || defined __AVR__
-/* Atmel AVR32 */
-# define _CACHE_LINE_SIZE (1 << 5)
-# elif defined __bfin || defined __BFIN__
-/* Analog Devices Blackfin */
-# define _CACHE_LINE_SIZE (1 << 5)
-# elif defined _TMS320C6X || defined __TMS320C6X__
-/* Texas Instruments TMS320C6x */
-# define _CACHE_LINE_SIZE (1 << 7) /* From L2. L1 data cache line is 1 << 6. */
-# elif defined __cris
-/* Axis Communications ETRAX CRIS */
-# define _CACHE_LINE_SIZE 32
-# elif defined __ia64__ || defined _IA64
-/* Intel Itanium */
-# define _CACHE_LINE_SIZE (1 << 7)
-# elif defined __M32R__ || defined __m32r__
-/* Mitsubishi/Renesas M32R */
-# define _CACHE_LINE_SIZE (1 << 4)
-# elif defined __m68k__ || defined M68000 || defined __MC68K__
-/* Motorola 68000 */
-# define _CACHE_LINE_SIZE (1 << 4)
-# elif defined __MICROBLAZE__ || defined __microblaze__
-/* Xilinx MicroBlaze */
-# define _CACHE_LINE_SIZE (1 << 5)
-# elif defined __mips__ || defined __mips || defined __MIPS__
-/* MIPS */
-# define _CACHE_LINE_SIZE (1 << 6)
-# elif defined __mn10300__ || defined __MN10300__
-/* Matsushita/Panasonic MN103 */
-# define _CACHE_LINE_SIZE 32 /* MN103E010 has 16 bytes. */
-# elif defined __hppa || defined __hppa__
-/* Hewlett-Packard PA-RISC */
-# define _CACHE_LINE_SIZE 64 /* PA-RISC 2.0 uses 64 bytes, PA-RISC 1.1 uses 32. */
-# elif defined __powerpc || defined _ARCH_PPC
-/* Power Architecture (a.k.a. PowerPC) */
-# define _CACHE_LINE_SIZE (1 << 7) /* Linux has a list of PPC models with associated L1_CACHE_SHIFT values. */
-# elif defined __s390__ || defined __370__ || defined __zarch__ || defined __SYSC_ZARCH__
-/* IBM System/390 */
-# define _CACHE_LINE_SIZE 256
-# elif defined SUNPLUS || defined __SCORE__ || defined __score__
-/* Sunplus S+core */
-# define _CACHE_LINE_SIZE (1 << 4)
-# elif defined __sh__
-/* Hitachi SuperH */
-# define _CACHE_LINE_SIZE (1 << 5) /* SH3 and earlier used 1 << 4. */
-# elif defined __sparc__ || defined __sparc
-/* SPARC */
-# define _CACHE_LINE_SIZE (1 << 7) /* Linux and FreeBSD disagree as to what this should be. */
-# elif defined __tile__
-/* Tilera TILE series */
-# define _CACHE_LINE_SIZE (1 << 6) /* TILEPro uses different sizes for L1 and L2. */
-# elif defined __i386 || defined __x86_64
-/* x86(-64) */
-# define _CACHE_LINE_SIZE (1 << 7)
-# elif defined __xtensa__ || defined __XTENSA__
-/* Cadence Design Systems/Tensilica Xtensa */
-# define _CACHE_LINE_SIZE (1 << 5) /* 1 << 4 on some models. */
-# endif
-# endif /* !defined _CACHE_LINE_SIZE */
-
-# if defined __NetBSD__ && !defined _CACHE_LINE_SIZE
-/*
-NetBSD defines COHERENCY_UNIT to be 32 on MIPS, and 64 for all other platforms -- which is wrong. Still, this is what the kernel
-uses; if this value didn't work, the system wouldn't run.
-*/
-# include <sys/param.h>
-# ifdef COHERENCY_UNIT
-# define _CACHE_LINE_SIZE COHERENCY_UNIT
-# endif
-# endif
-
-# ifndef _CACHE_LINE_SIZE
-# define _CACHE_LINE_SIZE 256 /* Fallback cache line size. */
-# endif
-
-static unsigned _get_cache_line_size(void)
-{
- /*
- The general idea:
- - Try to get the actual cache line size from the operating system.
- - In the interest of keeping things simple, this only checks with
- glibc and OS X.
- - A few other methods that could be added:
- - Query x86 CPUs directly with the CPUID instruction.
- - Query various ELF systems through the auxillary vector.
- (Power, Alpha, SuperH)
- - Query Linux through
- /sys/devices/system/cpu/cpu?/cache/index?/coherency_line_size
- (x86 only, AFAIK)
- - Query Linux through cache_alignment in /proc/cpuinfo
- - Query Solaris through PICL.
- - If that fails, return a value appropriate for the current CPU
- architecture.
- - Otherwise, return a sufficiently large number.
- */
-
- /*
- sysconf(3) is not a syscall, it's a glibc call that, for cache line sizes,
- uses CPUID on x86 and returns 0 on other platforms. If it were to work on
- most other platforms, it would have to get cache information from the
- kernel, since that information is usually made available by the processor
- only in privileged mode.
- https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/i386/sysconf.c;hb=HEAD
- */
-
- /* uClibc, newlib, dietlibc, musl, Bionic do not have this. */
-
-# if HAVE_UNISTD_H && ( \
- defined _SC_LEVEL1_DCACHE_LINESIZE || \
- defined _SC_LEVEL2_CACHE_LINESIZE || \
- defined _SC_LEVEL3_CACHE_LINESIZE || \
- defined _SC_LEVEL4_CACHE_LINESIZE)
- {
- static const int names[] =
- {
-# ifdef _SC_LEVEL1_DCACHE_LINESIZE
- _SC_LEVEL1_DCACHE_LINESIZE,
-# endif
-# ifdef _SC_LEVEL2_CACHE_LINESIZE
- _SC_LEVEL2_CACHE_LINESIZE,
-# endif
-# ifdef _SC_LEVEL3_CACHE_LINESIZE
- _SC_LEVEL3_CACHE_LINESIZE,
-# endif
-# ifdef _SC_LEVEL4_CACHE_LINESIZE
- _SC_LEVEL4_CACHE_LINESIZE
-# endif
- };
-
- const int *name;
- long result = 0;
-
- for(name = names; name != arrayend(names); ++name)
- {
- long sysconf_result = sysconf(*name); /* Can return -1 or 0 on
- failure. */
-
- if(sysconf_result > result)
- result = sysconf_result;
- }
-
- if(result)
- return result;
-
- /* Currently, this fails for every platform that isn't x86. Perhaps
- future versions will support other processors? */
- }
-# endif
-
-# if defined __MACH__ && defined __APPLE__
- {
- uint32_t result; /* sysctl.h says that hw.cachelinesize is a
- CTLTYPE_INT. */
- size_t size = sizeof(result);
- static const int name[] = {CTL_HW, HW_CACHELINE};
-
- if(!sysctl((int *)name, 2, &result, &size, NULL, 0)) /* (int *) is for OS X. */
- {
- assert(size == sizeof(result));
- return result;
- };
- }
-# endif
-
- /* Guess based on the CPU type. */
- return _CACHE_LINE_SIZE;
-}
-
const pthread_mutex_t mutex_initializer =
# if defined _GNU_SOURCE && !defined NDEBUG
PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
@@ -304,15 +73,9 @@ int threads_available(Display *dpy)
if(_has_pthread >= 0)
{
if(get_boolean_resource(dpy, "useThreads", "Boolean"))
- {
- _cache_line_size = _get_cache_line_size();
- assert(_cache_line_size >= sizeof(void *));
- assert(IS_POWER_OF_2(_cache_line_size));
- }
+ _cache_line_size = get_cache_line_size();
else
- {
_has_pthread = -1;
- }
}
}
diff --git a/utils/thread_util.h b/utils/thread_util.h
index 6dff8de..a8faf2d 100644
--- a/utils/thread_util.h
+++ b/utils/thread_util.h
@@ -161,7 +161,7 @@ unsigned thread_memory_alignment(Display *dpy);
/* int thread_malloc(void **ptr, Display *dpy, unsigned size); */
#define thread_malloc(ptr, dpy, size) \
- (aligned_malloc((ptr), thread_memory_alignment(dpy), (size)))
+ (aligned_malloc((ptr), 0, (size)))
/*
This simply does a malloc aligned to thread_memory_alignment(). See
diff --git a/utils/usleep.h b/utils/usleep.h
index 3225d66..f32a9c9 100644
--- a/utils/usleep.h
+++ b/utils/usleep.h
@@ -12,10 +12,6 @@
#ifndef __SCREENHACK_USLEEP_H__
#define __SCREENHACK_USLEEP_H__
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
diff --git a/utils/utf8wc.c b/utils/utf8wc.c
index c948f22..b445f30 100644
--- a/utils/utf8wc.c
+++ b/utils/utf8wc.c
@@ -266,7 +266,7 @@ utf8_split (const char *string, int *length_ret)
unsigned long uc;
long len2 = utf8_decode (in, len, &uc);
char tmp[10];
- strncpy (tmp, (char *) in, len2);
+ memcpy (tmp, (char *) in, len2);
tmp[len2] = 0;
ret[i++] = strdup (tmp);
in += len2;
@@ -299,8 +299,8 @@ utf8_split (const char *string, int *length_ret)
long L1 = strlen(ret[i-2]);
long L2 = strlen(ret[i-1]);
char *s2 = (char *) malloc (L1 + L2 + 1);
- strncpy (s2, ret[i-2], L1);
- strncpy (s2 + L1, ret[i-1], L2);
+ memcpy (s2, ret[i-2], L1);
+ memcpy (s2 + L1, ret[i-1], L2);
s2[L1 + L2] = 0;
free (ret[i-2]);
ret[i-2] = s2;
diff --git a/utils/version.h b/utils/version.h
index 7a20c66..8e38585 100644
--- a/utils/version.h
+++ b/utils/version.h
@@ -1,2 +1,4 @@
static const char screensaver_id[] =
- "@(#)xscreensaver 5.44 (20-Mar-2020), by Jamie Zawinski (jwz@jwz.org)";
+ "@(#)xscreensaver 6.00 (01-Apr-2021), by Jamie Zawinski (jwz@jwz.org)";
+#define XSCREENSAVER_VERSION "6.00"
+#define XSCREENSAVER_RELEASED 1617303600
diff --git a/utils/visual-gl.c b/utils/visual-gl.c
index c4b940b..cca4ecf 100644
--- a/utils/visual-gl.c
+++ b/utils/visual-gl.c
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 1999-2018 by Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright © 1999-2021 Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
@@ -21,21 +21,78 @@
*/
#include "utils.h"
-#include "visual.h"
#include "resources.h"
#ifdef HAVE_GL
# include <GL/gl.h>
-# include <GL/glx.h>
+# ifdef HAVE_EGL
+# include <EGL/egl.h>
+# include <EGL/eglext.h>
+# else
+# include <GL/glx.h>
+# endif
#endif /* HAVE_GL */
+#include "visual.h" /* after EGL/egl.h */
+
+#undef countof
+#define countof(x) (sizeof(x)/sizeof(*(x)))
+
+
extern char *progname;
+
Visual *
get_gl_visual (Screen *screen)
{
#ifdef HAVE_GL
+
Display *dpy = DisplayOfScreen (screen);
+
+# ifdef HAVE_EGL
+
+ Visual *v;
+ EGLint vid;
+ EGLDisplay *egl_display;
+ EGLConfig egl_config = 0;
+ int egl_major = -1, egl_minor = -1;
+
+ /* This is re-used, no need to close it. */
+ egl_display = eglGetDisplay ((EGLNativeDisplayType) dpy);
+ if (!egl_display)
+ {
+ fprintf (stderr, "%s: eglGetDisplay failed\n", progname);
+ return 0;
+ }
+
+ if (! eglInitialize (egl_display, &egl_major, &egl_minor))
+ {
+ fprintf (stderr, "%s: eglInitialize failed\n", progname);
+ abort();
+ }
+
+ /* Get the best EGL config on any visual, then see what visual it used. */
+ get_egl_config (dpy, egl_display, -1, &egl_config);
+ if (!egl_config) abort();
+
+ if (!eglGetConfigAttrib (egl_display, egl_config,
+ EGL_NATIVE_VISUAL_ID, &vid))
+ {
+ fprintf (stderr, "%s: EGL: no native visual ID\n", progname);
+ abort();
+ }
+
+ v = id_to_visual (screen, vid);
+ if (!v)
+ {
+ fprintf (stderr, "%s: EGL: no X11 visual 0x%x\n", progname, vid);
+ abort();
+ }
+
+ return v;
+
+# else /* !HAVE_EGL -- GLX */
+
int screen_num = screen_number (screen);
# define R GLX_RED_SIZE
@@ -61,7 +118,6 @@ get_gl_visual (Screen *screen)
# define SM GL_SAMPLES
# endif
-
int attrs[][40] = {
# ifdef SB /* rgba double stencil multisample */
{ GLX_RGBA, R,8, G,8, B,8, A,8, D,8, DB, ST,1, SB,1, SM,8, 0 },
@@ -107,12 +163,134 @@ get_gl_visual (Screen *screen)
return v;
}
}
+
+# endif /* !HAVE_EGL -- GLX */
#endif /* !HAVE_GL */
return 0;
}
+#ifdef HAVE_EGL
+/* An X11 "visual" is an object that encapsulates the available display
+ formats: color mapping, depth and so on. So is a GLE "config".
+ So why isn't there a one-to-one mapping between visuals and configs?
+ Once again, I can only assume the answer is that the people responsible
+ for every post-2002 version of the OpenGL specification are incompetent.
+
+ Under GLX, there will be multiple X11 visuals that appear (and behave)
+ identically to X11 programs, code but that have different GL parameters.
+ Two RGB visuals might have different alpha, depth, or stencil sizes,
+ for example, that would matter to a GL program but not to an X11 program.
+
+ But EGL has dozens of 'configs' for each visual, so we can't just pass
+ around a Window and a Visual to describe the display parameters: we need
+ to pass around the 'config' as well. Or, do what we do here, have both
+ sides use the same code to convert a visual to the best 'config'.
+ (It goes down a list of parameter settings, from higher quality to lower,
+ and takes the first config that matches.)
+
+ SGI solved this problem in like 1988, and like so many things, GLES went
+ and fucked it all up again.
+ */
+void
+get_egl_config (Display *dpy, EGLDisplay *egl_display,
+ EGLint x11_visual_id, EGLConfig *egl_config)
+{
+# define COMMON \
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT, \
+ EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER
+# define R EGL_RED_SIZE
+# define G EGL_GREEN_SIZE
+# define B EGL_BLUE_SIZE
+# define A EGL_ALPHA_SIZE
+# define D EGL_DEPTH_SIZE
+# define I EGL_BUFFER_SIZE
+# define ST EGL_STENCIL_SIZE
+# define SB EGL_SAMPLE_BUFFERS
+# define SM EGL_SAMPLES
+
+ const EGLint templates[][40] = {
+# ifdef SB
+ { COMMON, R,8, G,8, B,8, A,8, D,8, ST,1, SB,1, SM,8, EGL_NONE },
+ { COMMON, R,8, G,8, B,8, A,8, D,8, ST,1, SB,1, SM,6, EGL_NONE },
+ { COMMON, R,8, G,8, B,8, A,8, D,8, ST,1, SB,1, SM,4, EGL_NONE },
+ { COMMON, R,8, G,8, B,8, A,8, D,8, ST,1, SB,1, SM,2, EGL_NONE },
+# define SB_COUNT 4 /* #### Kludgey count of preceeding lines! */
+# endif
+ { COMMON, R,8, G,8, B,8, A,8, D,8, ST,1, EGL_NONE }, /* rgba stencil */
+ { COMMON, R,8, G,8, B,8, D,8, ST,1, EGL_NONE }, /* rgb stencil */
+ { COMMON, R,4, G,4, B,4, D,4, ST,1, EGL_NONE },
+ { COMMON, R,2, G,2, B,2, D,2, ST,1, EGL_NONE },
+ { COMMON, R,8, G,8, B,8, A,8, D,8, EGL_NONE }, /* rgba */
+ { COMMON, R,8, G,8, B,8, D,8, EGL_NONE }, /* rgb */
+ { COMMON, R,4, G,4, B,4, D,4, EGL_NONE },
+ { COMMON, R,2, G,2, B,2, D,2, EGL_NONE },
+ { COMMON, R,1, G,1, B,1, D,1, EGL_NONE } /* monochrome */
+ };
+ EGLint attrs[40];
+ EGLint nconfig;
+ int i, j, k, iter, pass;
+ Bool glslp;
+
+ i = 0;
+# ifdef SB
+ if (! get_boolean_resource (dpy, "multiSample", "MultiSample"))
+ i = SB_COUNT; /* skip over the multibuffer entries in 'attrs' */
+# endif /* SB */
+
+ glslp = get_boolean_resource (dpy, "prefersGLSL", "PrefersGLSL");
+ iter = (glslp ? 2 : 1);
+
+ *egl_config = 0;
+ for (pass = 0; pass < iter; pass++)
+ {
+ for (; i < countof(templates); i++)
+ {
+ for (j = 0, k = 0; templates[i][j] != EGL_NONE; j += 2)
+ {
+ attrs[k++] = templates[i][j];
+ attrs[k++] = templates[i][j+1];
+ }
+
+ attrs[k++] = EGL_RENDERABLE_TYPE;
+# ifdef HAVE_GLES3
+ if (glslp && pass == 0)
+ attrs[k++] = EGL_OPENGL_ES3_BIT;
+ else
+ attrs[k++] = EGL_OPENGL_ES_BIT;
+# elif defined(HAVE_JWZGLES)
+ attrs[k++] = EGL_OPENGL_ES_BIT;
+# else
+ attrs[k++] = EGL_OPENGL_BIT;
+# endif
+
+ if (x11_visual_id != -1)
+ {
+ attrs[k++] = EGL_NATIVE_VISUAL_ID;
+ attrs[k++] = x11_visual_id;
+ }
+
+ attrs[k++] = EGL_NONE;
+
+ nconfig = -1;
+ if (eglChooseConfig (egl_display, attrs, egl_config, 1, &nconfig)
+ && nconfig == 1)
+ break;
+ }
+ if (i < countof(templates))
+ break;
+ }
+
+ if (! *egl_config)
+ {
+ fprintf (stderr, "%s: eglChooseConfig: no configs found\n", progname);
+ abort();
+ }
+}
+#endif /* HAVE_EGL */
+
+
void
describe_gl_visual (FILE *f, Screen *screen, Visual *visual,
Bool private_cmap_p)
@@ -121,8 +299,13 @@ describe_gl_visual (FILE *f, Screen *screen, Visual *visual,
#ifdef HAVE_GL
{
+# ifdef HAVE_EGL
+ EGLDisplay *egl_display;
+ EGLConfig config = 0;
+# else /* !HAVE_EGL -- GLX */
int status;
int value = False;
+# endif /* !HAVE_EGL -- GLX */
Display *dpy = DisplayOfScreen (screen);
XVisualInfo vi_in, *vi_out;
@@ -134,6 +317,108 @@ describe_gl_visual (FILE *f, Screen *screen, Visual *visual,
&vi_in, &out_count);
if (! vi_out) abort ();
+# ifdef HAVE_EGL
+
+ /* This is re-used, no need to close it. */
+ egl_display = eglGetPlatformDisplay (EGL_PLATFORM_X11_KHR,
+ (EGLNativeDisplayType) dpy, NULL);
+ if (!egl_display)
+ {
+ fprintf (stderr, "%s: eglGetPlatformDisplay failed\n", progname);
+ return;
+ }
+
+ get_egl_config (dpy, egl_display, vi_out->visualid, &config);
+ if (!config)
+ {
+ fprintf (stderr, "%s: no matching EGL config for X11 visual 0x%lx\n",
+ progname, vi_out->visualid);
+ abort();
+ }
+
+ {
+ int i;
+ const struct { int hexp; EGLint i; const char *s; } fields[] = {
+ { 1, EGL_CONFIG_ID, "config ID:" },
+ { 1, EGL_CONFIG_CAVEAT, "caveat:" },
+ { 1, EGL_CONFORMANT, "conformant:" },
+ { 0, EGL_COLOR_BUFFER_TYPE, "buffer type:" },
+ { 0, EGL_RED_SIZE, "color size:" },
+ { 0, EGL_TRANSPARENT_RED_VALUE, "transparency:" },
+ { 0, EGL_BUFFER_SIZE, "buffer size:" },
+ { 0, EGL_DEPTH_SIZE, "depth size:" },
+ { 0, EGL_LUMINANCE_SIZE, "lum size:" },
+ { 0, EGL_STENCIL_SIZE, "stencil size:" },
+ { 0, EGL_ALPHA_MASK_SIZE, "alpha mask:" },
+ { 0, EGL_LEVEL, "level:" },
+ { 0, EGL_SAMPLES, "samples:" },
+ { 0, EGL_SAMPLE_BUFFERS, "sample bufs:" },
+ { 0, EGL_NATIVE_RENDERABLE, "native render:" },
+ { 1, EGL_NATIVE_VISUAL_TYPE, "native type:" },
+ { 1, EGL_RENDERABLE_TYPE, "render type:" },
+ { 0, EGL_SURFACE_TYPE, "surface type:" },
+ { 0, EGL_BIND_TO_TEXTURE_RGB, "bind RGB:" },
+ { 0, EGL_BIND_TO_TEXTURE_RGBA, "bind RGBA:" },
+ { 0, EGL_MAX_PBUFFER_WIDTH, "buffer width:" },
+ { 0, EGL_MAX_PBUFFER_HEIGHT, "buffer height:" },
+ { 0, EGL_MAX_PBUFFER_PIXELS, "buffer pixels:" },
+ { 0, EGL_MAX_SWAP_INTERVAL, "max swap:" },
+ { 0, EGL_MIN_SWAP_INTERVAL, "min swap:" },
+ };
+ EGLint r=0, g=0, b=0, a=0, tt=0, tr=0, tg=0, tb=0;
+ eglGetConfigAttrib (egl_display, config, EGL_RED_SIZE, &r);
+ eglGetConfigAttrib (egl_display, config, EGL_GREEN_SIZE, &g);
+ eglGetConfigAttrib (egl_display, config, EGL_BLUE_SIZE, &b);
+ eglGetConfigAttrib (egl_display, config, EGL_ALPHA_SIZE, &a);
+ eglGetConfigAttrib (egl_display, config, EGL_TRANSPARENT_TYPE, &tt);
+ eglGetConfigAttrib (egl_display, config, EGL_TRANSPARENT_RED_VALUE, &tr);
+ eglGetConfigAttrib (egl_display, config, EGL_TRANSPARENT_GREEN_VALUE,&tg);
+ eglGetConfigAttrib (egl_display, config, EGL_TRANSPARENT_BLUE_VALUE, &tb);
+ for (i = 0; i < countof(fields); i++)
+ {
+ EGLint v = 0;
+ char s[100];
+ eglGetConfigAttrib (egl_display, config, fields[i].i, &v);
+ if (fields[i].i == EGL_RED_SIZE)
+ sprintf (s, "%d, %d, %d, %d", r, g, b, a);
+ else if (fields[i].i == EGL_TRANSPARENT_RED_VALUE && tt != EGL_NONE)
+ sprintf (s, "%d, %d, %d", tr, tg, tb);
+ else if (fields[i].i == EGL_CONFIG_CAVEAT)
+ strcpy (s, (v == EGL_NONE ? "none" :
+ v == EGL_SLOW_CONFIG ? "slow" :
+# ifdef EGL_NON_CONFORMANT
+ v == EGL_NON_CONFORMANT ? "non-conformant" :
+# endif
+ "???"));
+ else if (fields[i].i == EGL_COLOR_BUFFER_TYPE)
+ strcpy (s, (v == EGL_RGB_BUFFER ? "RGB" :
+ v == EGL_LUMINANCE_BUFFER ? "luminance" :
+ "???"));
+ else if (fields[i].i == EGL_CONFORMANT ||
+ fields[i].i == EGL_RENDERABLE_TYPE)
+ {
+ sprintf (s, "0x%02x", v);
+ if (v & EGL_OPENGL_BIT) strcat (s, " OpenGL");
+ if (v & EGL_OPENGL_ES_BIT) strcat (s, " GLES-1.x");
+ if (v & EGL_OPENGL_ES2_BIT) strcat (s, " GLES-2.0");
+# ifdef EGL_OPENGL_ES3_BIT
+ if (v & EGL_OPENGL_ES3_BIT) strcat (s, " GLES-3.0");
+# endif
+ if (v & EGL_OPENVG_BIT) strcat (s, " OpenVG");
+ }
+ else if (fields[i].hexp)
+ sprintf (s, "0x%02x", v);
+ else if (v)
+ sprintf (s, "%d", v);
+ else
+ *s = 0;
+
+ if (*s) fprintf (f, " EGL %-14s %s\n", fields[i].s, s);
+ }
+ }
+
+# else /* !HAVE_EGL -- GLX */
+
status = glXGetConfig (dpy, vi_out, GLX_USE_GL, &value);
if (status == GLX_NO_EXTENSION)
@@ -146,7 +431,7 @@ describe_gl_visual (FILE *f, Screen *screen, Visual *visual,
if (!glXGetConfig (dpy, vi_out, GLX_LEVEL, &value) &&
value != 0)
- printf (" GLX level: %d\n", value);
+ fprintf (f, " GLX level: %d\n", value);
if (!glXGetConfig (dpy, vi_out, GLX_RGBA, &value) && value)
{
@@ -155,22 +440,22 @@ describe_gl_visual (FILE *f, Screen *screen, Visual *visual,
glXGetConfig (dpy, vi_out, GLX_GREEN_SIZE, &g);
glXGetConfig (dpy, vi_out, GLX_BLUE_SIZE, &b);
glXGetConfig (dpy, vi_out, GLX_ALPHA_SIZE, &a);
- printf (" GLX type: RGBA (%2d, %2d, %2d, %2d)\n",
- r, g, b, a);
+ fprintf (f, " GLX type: RGBA (%2d, %2d, %2d, %2d)\n",
+ r, g, b, a);
r=0, g=0, b=0, a=0;
glXGetConfig (dpy, vi_out, GLX_ACCUM_RED_SIZE, &r);
glXGetConfig (dpy, vi_out, GLX_ACCUM_GREEN_SIZE, &g);
glXGetConfig (dpy, vi_out, GLX_ACCUM_BLUE_SIZE, &b);
glXGetConfig (dpy, vi_out, GLX_ACCUM_ALPHA_SIZE, &a);
- printf (" GLX accum: RGBA (%2d, %2d, %2d, %2d)\n",
- r, g, b, a);
+ fprintf (f, " GLX accum: RGBA (%2d, %2d, %2d, %2d)\n",
+ r, g, b, a);
}
else
{
value = 0;
glXGetConfig (dpy, vi_out, GLX_BUFFER_SIZE, &value);
- printf (" GLX type: indexed (%d)\n", value);
+ fprintf (f, " GLX type: indexed (%d)\n", value);
}
# ifndef GLX_NONE_EXT /* Hooray for gratuitious name changes. */
@@ -189,36 +474,36 @@ describe_gl_visual (FILE *f, Screen *screen, Visual *visual,
if (!glXGetConfig (dpy, vi_out, GLX_VISUAL_CAVEAT_EXT, &value) &&
value != GLX_NONE_EXT)
# ifdef GLX_NON_CONFORMANT_EXT
- printf (" GLX rating: %s\n",
- (value == GLX_NONE_EXT ? "none" :
- value == GLX_SLOW_VISUAL_EXT ? "slow" :
- value == GLX_NON_CONFORMANT_EXT ? "non-conformant" :
- "???"));
+ fprintf (f, " GLX rating: %s\n",
+ (value == GLX_NONE_EXT ? "none" :
+ value == GLX_SLOW_VISUAL_EXT ? "slow" :
+ value == GLX_NON_CONFORMANT_EXT ? "non-conformant" :
+ "???");
# else
- printf (" GLX rating: %s\n",
- (value == GLX_NONE_EXT ? "none" :
- value == GLX_SLOW_VISUAL_EXT ? "slow" :
- "???"));
+ fprintf (f, " GLX rating: %s\n",
+ (value == GLX_NONE_EXT ? "none" :
+ value == GLX_SLOW_VISUAL_EXT ? "slow" :
+ "???"));
# endif /* GLX_NON_CONFORMANT_EXT */
# endif /* GLX_VISUAL_CAVEAT_EXT */
if (!glXGetConfig (dpy, vi_out, GLX_DOUBLEBUFFER, &value))
- printf (" GLX double-buffer: %s\n", (value ? "yes" : "no"));
+ fprintf (f, " GLX double-buffer: %s\n", (value ? "yes" : "no"));
if (!glXGetConfig (dpy, vi_out, GLX_STEREO, &value) &&
value)
- printf (" GLX stereo: %s\n", (value ? "yes" : "no"));
+ fprintf (f, " GLX stereo: %s\n", (value ? "yes" : "no"));
if (!glXGetConfig (dpy, vi_out, GLX_AUX_BUFFERS, &value) &&
value != 0)
- printf (" GLX aux buffers: %d\n", value);
+ fprintf (f, " GLX aux buffers: %d\n", value);
if (!glXGetConfig (dpy, vi_out, GLX_DEPTH_SIZE, &value))
- printf (" GLX depth size: %d\n", value);
+ fprintf (f, " GLX depth size: %d\n", value);
if (!glXGetConfig (dpy, vi_out, GLX_STENCIL_SIZE, &value) &&
value != 0)
- printf (" GLX stencil size: %d\n", value);
+ fprintf (f, " GLX stencil size: %d\n", value);
# ifdef SB /* GL_SAMPLE_BUFFERS || GLX_SAMPLE_BUFFERS_* */
if (!glXGetConfig (dpy, vi_out, SB, &value) &&
@@ -226,7 +511,7 @@ describe_gl_visual (FILE *f, Screen *screen, Visual *visual,
{
int bufs = value;
if (!glXGetConfig (dpy, vi_out, SM, &value))
- printf (" GLX multisample: %d, %d\n", bufs, value);
+ fprintf (f, " GLX multisample: %d, %d\n", bufs, value);
}
# endif /* GL_SAMPLE_BUFFERS || GLX_SAMPLE_BUFFERS_* */
@@ -234,12 +519,12 @@ describe_gl_visual (FILE *f, Screen *screen, Visual *visual,
value != GLX_NONE_EXT)
{
if (value == GLX_NONE_EXT)
- printf (" GLX transparency: none\n");
+ fprintf (f, " GLX transparency: none\n");
else if (value == GLX_TRANSPARENT_INDEX_EXT)
{
if (!glXGetConfig (dpy, vi_out, GLX_TRANSPARENT_INDEX_VALUE_EXT,
&value))
- printf (" GLX transparency: indexed (%d)\n", value);
+ fprintf (f, " GLX transparency: indexed (%d)\n", value);
}
else if (value == GLX_TRANSPARENT_RGB_EXT)
{
@@ -248,10 +533,11 @@ describe_gl_visual (FILE *f, Screen *screen, Visual *visual,
glXGetConfig (dpy, vi_out, GLX_TRANSPARENT_GREEN_VALUE_EXT, &g);
glXGetConfig (dpy, vi_out, GLX_TRANSPARENT_BLUE_VALUE_EXT, &b);
glXGetConfig (dpy, vi_out, GLX_TRANSPARENT_ALPHA_VALUE_EXT, &a);
- printf (" GLX transparency: RGBA (%2d, %2d, %2d, %2d)\n",
- r, g, b, a);
+ fprintf (f, " GLX transparency: RGBA (%2d, %2d, %2d, %2d)\n",
+ r, g, b, a);
}
}
+# endif /* !HAVE_EGL */
}
#endif /* HAVE_GL */
}
@@ -262,13 +548,15 @@ validate_gl_visual (FILE *out, Screen *screen, const char *window_desc,
Visual *visual)
{
#ifdef HAVE_GL
+# ifndef HAVE_EGL
int status;
int value = False;
+ unsigned int id;
+# endif
Display *dpy = DisplayOfScreen (screen);
XVisualInfo vi_in, *vi_out;
int out_count;
- unsigned int id;
vi_in.screen = screen_number (screen);
vi_in.visualid = XVisualIDFromVisual (visual);
@@ -276,6 +564,7 @@ validate_gl_visual (FILE *out, Screen *screen, const char *window_desc,
&vi_in, &out_count);
if (! vi_out) abort ();
+# ifndef HAVE_EGL
status = glXGetConfig (dpy, vi_out, GLX_USE_GL, &value);
id = (unsigned int) vi_out->visualid;
@@ -295,6 +584,7 @@ validate_gl_visual (FILE *out, Screen *screen, const char *window_desc,
return False;
}
else
+# endif /* !HAVE_EGL */
{
return True;
}
diff --git a/utils/visual.h b/utils/visual.h
index 18ff7a6..4fd1b95 100644
--- a/utils/visual.h
+++ b/utils/visual.h
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 1993-2014 by Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright © 1993-2021 Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
@@ -33,4 +33,8 @@ extern Visual *get_gl_visual (Screen *);
extern void describe_gl_visual (FILE *, Screen *, Visual *, Bool priv_cmap_p);
extern Bool validate_gl_visual (FILE *, Screen *, const char *, Visual *);
+#ifdef __egl_h_ /* EGL/egl.h included */
+extern void get_egl_config (Display *, EGLDisplay *, EGLint vid, EGLConfig *);
+#endif
+
#endif /* __VISUAL_H__ */
diff --git a/utils/xdbe.c b/utils/xdbe.c
index d62183e..347e625 100644
--- a/utils/xdbe.c
+++ b/utils/xdbe.c
@@ -18,13 +18,10 @@
#include "utils.h"
#include "xdbe.h"
#include "resources.h" /* for get_string_resource() */
+#include "xmu.h"
/* #define DEBUG */
-#ifdef DEBUG
-# include <X11/Xmu/Error.h>
-#endif
-
extern char *progname;
#ifdef HAVE_DOUBLE_BUFFER_EXTENSION /* whole file */
diff --git a/utils/xft.c b/utils/xft.c
index 9245752..6decd22 100644
--- a/utils/xft.c
+++ b/utils/xft.c
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 2014-2018 Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright © 2014-2021 Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
@@ -37,6 +37,50 @@ struct _XftDraw {
};
+Display *
+XftDrawDisplay (XftDraw *draw)
+{
+ return draw->dpy;
+}
+
+
+Bool
+XftDrawSetClipRectangles (XftDraw *draw, int x, int y,
+ _Xconst XRectangle *rects, int n)
+{
+ if (!n)
+ return XSetClipMask (draw->dpy, draw->gc, 0);
+# if 0
+ else
+ /* #### unimplemented in jwxyz, so clipping is a no-op */
+ return XSetClipRectangles (draw->dpy, draw->gc, x, y,
+ (XRectangle *) rects, /* discard const */
+ n, Unsorted);
+# else
+ return False;
+# endif
+}
+
+
+Bool
+XftDrawSetClip (XftDraw *draw, Region region)
+{
+ if (!region)
+ return XSetClipMask (draw->dpy, draw->gc, 0);
+# if 0
+ else
+ /* #### unimplemented in jwxyz, so clipping is a no-op */
+ {
+ XRectangle rect; /* #### untested */
+ XClipBox (region, &rect); /* #### unimplemented in jwxyz */
+ return XftDrawSetClipRectangles (draw, 0, 0, &rect, 1);
+ }
+# else
+ return False;
+# endif
+}
+
+
XftFont *
XftFontOpenXlfd (Display *dpy, int screen, _Xconst char *xlfd)
{
@@ -60,8 +104,9 @@ XftFontOpenXlfd (Display *dpy, int screen, _Xconst char *xlfd)
{
unsigned i;
- // In the event of -*-random-* (under JWXYZ), get the actual XLFD,
- // otherwise we'll get another random font that doesn't match ff->xfont.
+ /* In the event of -*-random-* (under JWXYZ), get the actual XLFD,
+ otherwise we'll get another random font that doesn't match ff->xfont.
+ */
char *xlfd_resolved = NULL;
char **missing_charset_list_return;
@@ -111,6 +156,62 @@ XftFontOpenXlfd (Display *dpy, int screen, _Xconst char *xlfd)
}
+/* Very approximately convert an XFT-style name to an XLFD style name
+ and then call XftFontOpenXlfd on that.
+ */
+XftFont *
+XftFontOpenName (Display *dpy, int screen, _Xconst char *xft_name)
+{
+ XftFont *font;
+ char *name = strdup (xft_name);
+ char *xlfd = 0;
+ char *s, *b, *i, *o, *c;
+ int size;
+ char dummy;
+
+ /* Ignore any ":keywords=" */
+ c = strchr (name, ':');
+ if (c) *c = 0;
+
+ /* Downcase ASCII */
+ for (s = name; *s; s++)
+ if (*s >= 'A' && *s <= 'Z')
+ *s += 'a'-'A';
+
+ /* "Family-NN" */
+ s = strrchr (name, '-');
+ if (!s) goto FAIL;
+ if (1 != sscanf (s+1, " %d %c", &size, &dummy)) goto FAIL;
+ if (size <= 0) goto FAIL;
+ *s = 0;
+
+ /* "Family Bold", etc. */
+ b = strstr (name, " bold");
+ i = strstr (name, " italic");
+ o = strstr (name, " oblique");
+ if (b) *b = 0;
+ if (i) *i = 0;
+ if (o) *o = 0;
+
+ xlfd = (char *) malloc (strlen(name) + 80);
+ sprintf (xlfd, "-*-%s-%s-%s-*-*-*-%d-*-*-*-*-*-*",
+ name,
+ (b ? "bold" : "medium"),
+ (i ? "i" : o ? "o" : "r"),
+ size * 10);
+ font = XftFontOpenXlfd (dpy, screen, xlfd);
+ free (name);
+ free (xlfd);
+ return font;
+
+ FAIL:
+ fprintf (stderr, "%s: XFT: unparsable: \"%s\"\n", progname, xft_name);
+ if (name) free (name);
+ if (xlfd) free (xlfd);
+ return 0;
+}
+
+
void
XftFontClose (Display *dpy, XftFont *font)
{
@@ -132,7 +233,8 @@ XftColorAllocName (Display *dpy,
XftColor *result)
{
XColor color;
- if (!dpy || !visual || !name || !result) abort();
+ if (!dpy || !visual || !result) abort();
+ if (!name || !*name) name = "#FFFFFF";
if (! XParseColor (dpy, cmap, name, &color))
{
diff --git a/utils/xft.h b/utils/xft.h
index 385e28b..0da0188 100644
--- a/utils/xft.h
+++ b/utils/xft.h
@@ -118,7 +118,7 @@ typedef unsigned char FcChar8;
XftFont *XftFontOpenXlfd (Display *dpy, int screen, _Xconst char *xlfd);
-#define XftFontOpenName XftFontOpenXlfd
+XftFont *XftFontOpenName (Display *dpy, int screen, _Xconst char *name);
void XftFontClose (Display *dpy, XftFont *font);
@@ -143,7 +143,10 @@ XftDraw *XftDrawCreate (Display *dpy,
Drawable drawable,
Visual *visual,
Colormap colormap);
-
+Display *XftDrawDisplay (XftDraw *);
+Bool XftDrawSetClipRectangles (XftDraw *, int x, int y,
+ _Xconst XRectangle *rects, int n);
+Bool XftDrawSetClip (XftDraw *draw, Region region);
void XftDrawDestroy (XftDraw *draw);
void
diff --git a/utils/xftwrap.c b/utils/xftwrap.c
new file mode 100644
index 0000000..e880407
--- /dev/null
+++ b/utils/xftwrap.c
@@ -0,0 +1,206 @@
+/* xftwrap.c --- XftDrawStringUtf8 with multi-line strings.
+ * xscreensaver, Copyright © 2021 Jamie Zawinski <jwz@jwz.org>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation. No representations are made about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "utils.h"
+#include "xft.h"
+#include "xftwrap.h"
+
+#undef MAX
+#undef MIN
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#define MIN(a,b) ((a)<(b)?(a):(b))
+
+
+#ifdef DEBUG
+static void
+LOG(const char *ss, const char *s, int n)
+{
+ int i;
+ fprintf(stderr,"####%s [", ss);
+ for (i = 0; i < n; i++) fprintf(stderr, "%c", s[i]);
+ fprintf(stderr,"]\n");
+}
+#else
+# define LOG(ss,s,n) /**/
+#endif
+
+
+/* Returns a new string word-wrapped to fit in the width in pixels.
+ */
+char *
+xft_word_wrap (Display *dpy, XftFont *font, const char *str, int pixels)
+{
+ const char *in = str;
+ char *ret = (char *) malloc (strlen(in) + 2);
+ char *out = ret;
+ const char *line_out = out;
+ char *word_out = 0;
+ while (1)
+ {
+ if (*in == ' ' || *in == '\t' ||
+ *in == '\r' || *in == '\n' ||
+ *in == 0)
+ {
+ Bool done = (*in == 0); /* To wrap the *last* word. */
+ XGlyphInfo overall;
+ Bool nl = (*in == '\r' || *in == '\n');
+
+ if (nl) in++;
+ while (*in == ' ' || *in == '\t') in++;
+ in--;
+
+ XftTextExtentsUtf8 (dpy, font,
+ (FcChar8 *) line_out,
+ out - line_out,
+ &overall);
+ if (overall.width - overall.x >= pixels &&
+ word_out)
+ {
+ word_out[0] = '\n';
+ line_out = word_out + 1;
+ word_out = 0;
+ if (done) break;
+ *out++ = *in;
+ }
+ else
+ {
+ if (done) break;
+ word_out = out;
+ *out++ = *in;
+ if (nl)
+ {
+ line_out = out + 1;
+ word_out = 0;
+ }
+ }
+
+ if (done) break;
+ }
+ else
+ {
+ *out++ = *in;
+ }
+ in++;
+ }
+
+ *out = 0;
+
+ return ret;
+}
+
+
+/* Like XftTextExtentsUtf8, but handles multi-line strings.
+ XGlyphInfo will contain the bounding box that encloses all of the text.
+ Return value is the number of lines in the text, >= 1.
+ */
+int
+XftTextExtentsUtf8_multi (Display *dpy, XftFont *font,
+ const FcChar8 *str, int len, XGlyphInfo *overall)
+{
+ int i, start = 0;
+ int lines = 0;
+ int line_y = 0;
+ for (i = 0; i <= len; i++)
+ {
+ if (i == len || str[i] == '\r' || str[i] == '\n')
+ {
+ XGlyphInfo gi;
+ XftTextExtentsUtf8 (dpy, font,
+ str + start,
+ i - start,
+ &gi);
+ if (lines == 0)
+ *overall = gi;
+ else
+ {
+ /* Find the union of the two bounding boxes, placed at their
+ respective origins. */
+ int ox1, oy1, ox2, oy2; /* bbox of 'overall' */
+ int nx1, ny1, nx2, ny2; /* bbox of 'gi' */
+ int ux1, uy1, ux2, uy2; /* union */
+
+ ox1 = overall->x;
+ oy1 = overall->y;
+ ox2 = ox1 + overall->width;
+ oy2 = oy1 + overall->height;
+
+ line_y += font->ascent + font->descent; /* advance origin */
+
+ nx1 = gi.x;
+ ny1 = gi.y + line_y;
+ nx2 = nx1 + gi.width;
+ ny2 = ny1 + gi.height + line_y;
+
+ ux1 = MIN (ox1, nx1); /* upper left */
+ uy1 = MIN (oy1, ny1);
+ ux2 = MAX (ox2, nx2); /* bottom right */
+ uy2 = MAX (oy2, ny2);
+
+ overall->x = ux1;
+ overall->y = uy1;
+ overall->width = ux2 - ux1;
+ overall->height = uy2 - uy1;
+ }
+ lines++;
+ start = i+1;
+ }
+ }
+
+ return lines;
+}
+
+
+/* Like XftDrawStringUtf8, but handles multi-line strings.
+ Alignment is 1, 0 or -1 for left, center, right.
+ */
+void
+XftDrawStringUtf8_multi (XftDraw *xftdraw, const XftColor *color,
+ XftFont *font, int x, int y, const FcChar8 *str,
+ int len,
+ int alignment)
+{
+ Display *dpy = XftDrawDisplay (xftdraw);
+ int i, start = 0;
+ int lines = 0;
+ XGlyphInfo overall;
+ if (len == 0) return;
+
+ XftTextExtentsUtf8_multi (dpy, font, str, len, &overall);
+
+ for (i = 0; i <= len; i++)
+ {
+ if (i == len || str[i] == '\r' || str[i] == '\n')
+ {
+ XGlyphInfo gi;
+ int x2 = x;
+ XftTextExtentsUtf8 (dpy, font, str + start, i - start, &gi);
+ switch (alignment) {
+ case 1: break;
+ case 0: x2 += (overall.width - gi.width) / 2; break;
+ case -1: x2 += (overall.width - gi.width); break;
+ default: abort(); break;
+ }
+
+ XftDrawStringUtf8 (xftdraw, color, font, x2, y,
+ str + start,
+ i - start);
+ y += font->ascent + font->descent;
+ lines++;
+ start = i+1;
+ }
+ }
+}
+
diff --git a/utils/xftwrap.h b/utils/xftwrap.h
new file mode 100644
index 0000000..25a55bb
--- /dev/null
+++ b/utils/xftwrap.h
@@ -0,0 +1,35 @@
+/* xftwrap.h --- XftDrawStringUtf8 with multi-line strings.
+ * xscreensaver, Copyright © 2021 Jamie Zawinski <jwz@jwz.org>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation. No representations are made about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ */
+
+#ifndef __XFTWRAP_H__
+#define __XFTWRAP_H__
+
+/* Returns a new string word-wrapped to fit in the width in pixels.
+ */
+extern char *xft_word_wrap (Display *, XftFont *, const char *, int pixels);
+
+/* Like XftTextExtentsUtf8, but handles multi-line strings.
+ XGlyphInfo will contain the bounding box that encloses all of the text.
+ Return value is the number of lines in the text, >= 1.
+ */
+extern int XftTextExtentsUtf8_multi (Display *, XftFont *,
+ const FcChar8 *, int L, XGlyphInfo *);
+
+/* Like XftDrawStringUtf8, but handles multi-line strings.
+ Alignment is 1, 0 or -1 for left, center, right.
+ */
+extern void XftDrawStringUtf8_multi (XftDraw *, const XftColor *,
+ XftFont *, int x, int y,
+ const FcChar8 *, int L,
+ int alignment);
+
+#endif /* __XFTWRAP_H__ */
diff --git a/utils/xmu.c b/utils/xmu.c
index 2f273d4..051ac95 100644
--- a/utils/xmu.c
+++ b/utils/xmu.c
@@ -1,173 +1,46 @@
-/* This file contains compatibility routines for systems without Xmu.
- * You would be better served by installing Xmu on your machine or
- * yelling at your vendor to ship it.
+/* xscreensaver, Copyright © 1991-2021 Jamie Zawinski <jwz@jwz.org>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation. No representations are made about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
-#ifndef HAVE_XMU
-/*
- * Copyright 1989 Massachusetts Institute of Technology
- *
- * Permission to use, copy, modify, and distribute this software and its
- * documentation for any purpose and without fee is hereby granted, provided
- * that the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of M.I.T. not be used in advertising
- * or publicity pertaining to distribution of the software without specific,
- * written prior permission. M.I.T. makes no representations about the
- * suitability of this software for any purpose. It is provided "as is"
- * without express or implied warranty.
- *
- * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
- * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
+#include <stdio.h>
+#include <X11/Xlib.h>
#include "xmu.h"
-#ifndef NEED_EVENTS
-# define NEED_EVENTS /* to make Xproto.h define xEvent */
-#endif
-#ifndef VMS
-# include <X11/Xproto.h> /* for xEvent (used by Xlibint.h) */
-# include <X11/Xlibint.h> /* for _XExtension */
-#else /* VMS */
-# include <X11/Xlib.h>
-#endif /* VMS */
-#include <X11/Intrinsic.h> /* for XtSpecificationRelease */
+extern const char *progname;
-/*
- * XmuPrintDefaultErrorMessage - print a nice error that looks like the usual
- * message. Returns 1 if the caller should consider exitting else 0.
- */
-int XmuPrintDefaultErrorMessage (Display *dpy, XErrorEvent *event, FILE *fp)
+int
+XmuPrintDefaultErrorMessage (Display *dpy, XErrorEvent *event, FILE *fp)
{
- char buffer[BUFSIZ];
- char mesg[BUFSIZ];
- char number[32];
- char *mtype = "XlibMessage";
- _XExtension *ext = (_XExtension *)NULL;
- XGetErrorText(dpy, event->error_code, buffer, BUFSIZ);
- XGetErrorDatabaseText(dpy, mtype, "XError", "X Error", mesg, BUFSIZ);
- (void) fprintf(fp, "%s: %s\n ", mesg, buffer);
- XGetErrorDatabaseText(dpy, mtype, "MajorCode", "Request Major code %d",
- mesg, BUFSIZ);
- (void) fprintf(fp, mesg, event->request_code);
- if (event->request_code < 128) {
- sprintf(number, "%d", event->request_code);
- XGetErrorDatabaseText(dpy, "XRequest", number, "", buffer, BUFSIZ);
- } else {
- /* XXX this is non-portable */
- for (ext = dpy->ext_procs;
- ext && (ext->codes.major_opcode != event->request_code);
- ext = ext->next)
- ;
- if (ext)
- strcpy(buffer, ext->name);
- else
- buffer[0] = '\0';
- }
- (void) fprintf(fp, " (%s)", buffer);
- fputs("\n ", fp);
-#if (XtSpecificationRelease >= 5)
- if (event->request_code >= 128) {
- XGetErrorDatabaseText(dpy, mtype, "MinorCode", "Request Minor code %d",
- mesg, BUFSIZ);
- (void) fprintf(fp, mesg, event->minor_code);
- if (ext) {
- sprintf(mesg, "%s.%d", ext->name, event->minor_code);
- XGetErrorDatabaseText(dpy, "XRequest", mesg, "", buffer, BUFSIZ);
- (void) fprintf(fp, " (%s)", buffer);
- }
- fputs("\n ", fp);
- }
- if (event->error_code >= 128) {
- /* let extensions try to print the values */
- /* XXX this is non-portable code */
- for (ext = dpy->ext_procs; ext; ext = ext->next) {
- if (ext->error_values)
- (*ext->error_values)(dpy, event, fp);
- }
- /* the rest is a fallback, providing a simple default */
- /* kludge, try to find the extension that caused it */
- buffer[0] = '\0';
- for (ext = dpy->ext_procs; ext; ext = ext->next) {
- if (ext->error_string)
- (*ext->error_string)(dpy, event->error_code, &ext->codes,
- buffer, BUFSIZ);
- if (buffer[0])
- break;
- }
- if (buffer[0])
- sprintf(buffer, "%s.%d", ext->name,
- event->error_code - ext->codes.first_error);
- else
- strcpy(buffer, "Value");
- XGetErrorDatabaseText(dpy, mtype, buffer, "", mesg, BUFSIZ);
- if (*mesg) {
- (void) fprintf(fp, mesg, event->resourceid);
- fputs("\n ", fp);
- }
- } else if ((event->error_code == BadWindow) ||
- (event->error_code == BadPixmap) ||
- (event->error_code == BadCursor) ||
- (event->error_code == BadFont) ||
- (event->error_code == BadDrawable) ||
- (event->error_code == BadColor) ||
- (event->error_code == BadGC) ||
- (event->error_code == BadIDChoice) ||
- (event->error_code == BadValue) ||
- (event->error_code == BadAtom)) {
- if (event->error_code == BadValue)
- XGetErrorDatabaseText(dpy, mtype, "Value", "Value 0x%x",
- mesg, BUFSIZ);
- else if (event->error_code == BadAtom)
- XGetErrorDatabaseText(dpy, mtype, "AtomID", "AtomID 0x%x",
- mesg, BUFSIZ);
- else
- XGetErrorDatabaseText(dpy, mtype, "ResourceID", "ResourceID 0x%x",
- mesg, BUFSIZ);
- (void) fprintf(fp, mesg, event->resourceid);
- fputs("\n ", fp);
- }
-#elif (XtSpecificationRelease == 4)
- XGetErrorDatabaseText(dpy, mtype, "MinorCode", "Request Minor code %d",
- mesg, BUFSIZ);
- (void) fprintf(fp, mesg, event->minor_code);
- fputs("\n ", fp);
- if (ext) {
- sprintf(mesg, "%s.%d", ext->name, event->minor_code);
- XGetErrorDatabaseText(dpy, "XRequest", mesg, "", buffer, BUFSIZ);
- (void) fprintf(fp, " (%s)", buffer);
- }
- XGetErrorDatabaseText(dpy, mtype, "ResourceID", "ResourceID 0x%x",
- mesg, BUFSIZ);
- (void) fprintf(fp, mesg, event->resourceid);
- fputs("\n ", fp);
-#else
-ERROR! Unsupported release of X11
-#endif
- XGetErrorDatabaseText(dpy, mtype, "ErrorSerial", "Error Serial #%d",
- mesg, BUFSIZ);
- (void) fprintf(fp, mesg, event->serial);
- fputs("\n ", fp);
- XGetErrorDatabaseText(dpy, mtype, "CurrentSerial", "Current Serial #%d",
- mesg, BUFSIZ);
- (void) fprintf(fp, mesg, NextRequest(dpy)-1);
- fputs("\n", fp);
- if (event->error_code == BadImplementation) return 0;
- return 1;
+ /* The real libXmu version of this does localization and uses private,
+ undocumented fields inside the Display struct to print things about
+ errors from server-extension events. But the following is sufficient.
+ */
+ char xerr[1024], opname[1024], num[20];
+ const char *b = progname;
+
+ /* Convert the error code to its name, e.g. "BadWindow" */
+ XGetErrorText (dpy, event->error_code, xerr, sizeof(xerr)-1);
+
+ /* Convert the request's ID number to its name, e.g., "XGetProperty" */
+ sprintf (num, "%d", event->request_code);
+ XGetErrorDatabaseText (dpy, "XRequest", num, "", opname, sizeof(opname)-1);
+
+ fprintf (fp, "%s: Failed request: %s\n", b, xerr);
+ fprintf (fp, "%s: Major opcode: %d (%s)\n", b, event->request_code,
+ opname);
+ fprintf (fp, "%s: Resource id: 0x%lx\n", b, event->resourceid);
+ fprintf (fp, "%s: Serial number: %ld / %ld\n\n", b,
+ event->serial, NextRequest(dpy)-1);
+ return 1;
}
-
-#else /* HAVE_XMU */
-
-/* Shut up the stupid "gcc -pedantic" warning */
-int _I_dont_care_that_ISO_C_forbids_an_empty_source_file_ = 1;
-
-#endif /* HAVE_XMU */
diff --git a/utils/xmu.h b/utils/xmu.h
index 48084f7..e4cf7e6 100644
--- a/utils/xmu.h
+++ b/utils/xmu.h
@@ -1,14 +1,8 @@
-/* This file contains compatibility routines for systems without Xmu.
- * You would be better served by installing Xmu on your machine or
- * yelling at your vendor to ship it.
- */
+/* A relic of the past. */
#ifndef __XMU_H__
#define __XMU_H__
-#include <X11/Xlib.h>
-#include <stdio.h>
-
int XmuPrintDefaultErrorMessage (Display *dpy, XErrorEvent *event, FILE *fp);
#endif /* __XMU_H__ */
diff --git a/utils/xshm.c b/utils/xshm.c
index 8992140..14e5e43 100644
--- a/utils/xshm.c
+++ b/utils/xshm.c
@@ -33,6 +33,7 @@
/* #define DEBUG */
+#include <assert.h>
#include <errno.h> /* for perror() */
#ifdef HAVE_JWXYZ
@@ -42,12 +43,8 @@
#endif
#include "xshm.h"
+#include "aligned_malloc.h"
#include "resources.h" /* for get_string_resource() */
-#include "thread_util.h" /* for thread_malloc() */
-
-#ifdef DEBUG
-# include <X11/Xmu/Error.h>
-#endif
extern char *progname;
@@ -68,7 +65,7 @@ shm_ehandler (Display *dpy, XErrorEvent *error)
{
shm_got_x_error = True;
-#ifdef DEBUG
+#if 0
fprintf (stderr, "\n%s: ignoring X error from XSHM:\n", progname);
XmuPrintDefaultErrorMessage (dpy, error, stderr);
fprintf (stderr, "\n");
@@ -89,7 +86,7 @@ shm_ehandler (Display *dpy, XErrorEvent *error)
XSync((DPY), False); \
if (old_handler) \
XSetErrorHandler (old_handler); \
- old_handler = 0; \
+ old_handler = 0; \
} while(0)
#endif /* HAVE_XSHM_EXTENSION */
@@ -117,8 +114,8 @@ create_fallback (Display *dpy, Visual *visual,
/* Sometimes the XImage data needs to be aligned, such as for SIMD (SSE2
in Fireworkx), or multithreading (AnalogTV).
*/
- int error = thread_malloc ((void **)&image->data, dpy,
- image->height * image->bytes_per_line);
+ int error = aligned_malloc ((void **)&image->data, get_cache_line_size(),
+ image->height * image->bytes_per_line);
if (error) {
print_error (error);
XDestroyImage (image);
@@ -291,11 +288,13 @@ void
destroy_xshm_image (Display *dpy, XImage *image, XShmSegmentInfo *shm_info)
{
#ifdef HAVE_XSHM_EXTENSION
+ Status status;
+
if (shm_info->shmid == -1) {
#endif /* HAVE_XSHM_EXTENSION */
/* Don't let XDestroyImage free image->data. */
- thread_free (image->data);
+ aligned_free (image->data);
image->data = NULL;
XDestroyImage (image);
return;
@@ -303,8 +302,6 @@ destroy_xshm_image (Display *dpy, XImage *image, XShmSegmentInfo *shm_info)
#ifdef HAVE_XSHM_EXTENSION
}
- Status status;
-
CATCH_X_ERROR(dpy);
status = XShmDetach (dpy, shm_info);
UNCATCH_X_ERROR(dpy);
@@ -312,10 +309,10 @@ destroy_xshm_image (Display *dpy, XImage *image, XShmSegmentInfo *shm_info)
status = False;
if (!status)
fprintf (stderr, "%s: XShmDetach failed!\n", progname);
-#ifdef DEBUG
+# ifdef DEBUG
else
fprintf (stderr, "%s: XShmDetach(dpy, shm_info) ==> True\n", progname);
-#endif
+# endif
XDestroyImage (image);
XSync(dpy, False);
@@ -329,10 +326,10 @@ destroy_xshm_image (Display *dpy, XImage *image, XShmSegmentInfo *shm_info)
(unsigned long) shm_info->shmaddr);
perror(buf);
}
-#ifdef DEBUG
+# ifdef DEBUG
else
fprintf (stderr, "%s: shmdt(shm_info->shmaddr) ==> 0\n", progname);
-#endif
+# endif
XSync(dpy, False);
diff --git a/utils/yarandom.c b/utils/yarandom.c
index f450735..0f51cb6 100644
--- a/utils/yarandom.c
+++ b/utils/yarandom.c
@@ -118,9 +118,9 @@ ya_rand_init(unsigned int seed)
#define ROT(X,N) (((X)<<(N)) | ((X)>>((sizeof(unsigned int)*8)-(N))))
seed = (999U * (unsigned int) tp.tv_sec);
seed = ROT (seed, 11);
- seed += (1001 * tp.tv_usec);
+ seed += (1001 * (unsigned int) tp.tv_usec);
seed = ROT (seed, 7);
- seed += (1003 * getpid());
+ seed += (1003 * (unsigned int) getpid());
seed = ROT (seed, 13);
}