summaryrefslogtreecommitdiffstats
path: root/utils
diff options
context:
space:
mode:
authorSimon Rettberg2018-10-16 10:08:48 +0200
committerSimon Rettberg2018-10-16 10:08:48 +0200
commitd3a98cf6cbc3bd0b9efc570f58e8812c03931c18 (patch)
treecbddf8e50f35a9c6e878a5bfe3c6d625d99e12ba /utils
downloadxscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.tar.gz
xscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.tar.xz
xscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.zip
Original 5.40
Diffstat (limited to 'utils')
-rw-r--r--utils/Makefile.in341
-rw-r--r--utils/README6
-rwxr-xr-xutils/ad2c42
-rw-r--r--utils/aligned_malloc.c48
-rw-r--r--utils/aligned_malloc.h26
-rw-r--r--utils/alpha.c215
-rw-r--r--utils/alpha.h22
-rw-r--r--utils/async_netdb.c449
-rw-r--r--utils/async_netdb.h223
-rwxr-xr-xutils/bin2c46
-rw-r--r--utils/colorbars.c130
-rw-r--r--utils/colorbars.h25
-rw-r--r--utils/colors.c732
-rw-r--r--utils/colors.h147
-rw-r--r--utils/compile_axp.com34
-rw-r--r--utils/compile_decc.com34
-rw-r--r--utils/erase.c811
-rw-r--r--utils/erase.h21
-rw-r--r--utils/fade.c962
-rw-r--r--utils/fade.h21
-rw-r--r--utils/font-retry.c189
-rw-r--r--utils/font-retry.h24
-rw-r--r--utils/grabclient.c1037
-rw-r--r--utils/grabscreen.c937
-rw-r--r--utils/grabscreen.h109
-rw-r--r--utils/hsv.c81
-rw-r--r--utils/hsv.h27
-rw-r--r--utils/images/logo-180.gifbin0 -> 3328 bytes
-rw-r--r--utils/images/logo-180.xpm207
-rw-r--r--utils/images/logo-50.gifbin0 -> 857 bytes
-rw-r--r--utils/images/logo-50.xpm77
-rw-r--r--utils/images/logo-big.gifbin0 -> 17019 bytes
-rw-r--r--utils/images/logo.eps8058
-rw-r--r--utils/images/screensaver-cmndln.pngbin0 -> 1040 bytes
-rw-r--r--utils/images/screensaver-colorselector.pngbin0 -> 1104 bytes
-rw-r--r--utils/images/screensaver-diagnostic.pngbin0 -> 1307 bytes
-rw-r--r--utils/images/screensaver-locking.pngbin0 -> 944 bytes
-rw-r--r--utils/images/screensaver-power.pngbin0 -> 973 bytes
-rw-r--r--utils/images/screensaver-snap.pngbin0 -> 1272 bytes
-rw-r--r--utils/logo.c75
-rw-r--r--utils/minixpm.c251
-rw-r--r--utils/minixpm.h28
-rw-r--r--utils/overlay.c158
-rw-r--r--utils/pow2.c51
-rw-r--r--utils/pow2.h20
-rw-r--r--utils/resources.c296
-rw-r--r--utils/resources.h41
-rw-r--r--utils/spline.c319
-rw-r--r--utils/spline.h51
-rw-r--r--utils/textclient-mobile.c813
-rw-r--r--utils/textclient.c673
-rw-r--r--utils/textclient.h37
-rw-r--r--utils/thread_util.c1043
-rw-r--r--utils/thread_util.h446
-rw-r--r--utils/usleep.c64
-rw-r--r--utils/usleep.h28
-rw-r--r--utils/utf8wc.c928
-rw-r--r--utils/utf8wc.h47
-rw-r--r--utils/utils.h27
-rw-r--r--utils/version.h2
-rw-r--r--utils/visual-gl.c309
-rw-r--r--utils/visual.c555
-rw-r--r--utils/visual.h36
-rw-r--r--utils/vms-gtod.c31
-rw-r--r--utils/vms-gtod.h85
-rw-r--r--utils/vms-strdup.c25
-rw-r--r--utils/vroot.h156
-rw-r--r--utils/xdbe.c75
-rw-r--r--utils/xdbe.h27
-rw-r--r--utils/xft.c364
-rw-r--r--utils/xft.h167
-rw-r--r--utils/xmu.c173
-rw-r--r--utils/xmu.h14
-rw-r--r--utils/xscreensaver-intl.h36
-rw-r--r--utils/xshm.c340
-rw-r--r--utils/xshm.h54
-rw-r--r--utils/yarandom.c139
-rw-r--r--utils/yarandom.h103
78 files changed, 23168 insertions, 0 deletions
diff --git a/utils/Makefile.in b/utils/Makefile.in
new file mode 100644
index 0000000..56fc602
--- /dev/null
+++ b/utils/Makefile.in
@@ -0,0 +1,341 @@
+# utils/Makefile.in --- xscreensaver, Copyright (c) 1997-2010 Jamie Zawinski.
+# the `../configure' script generates `utils/Makefile' from this file.
+
+
+# The utilities in this directory are used mostly by the demos in ../hacks/.
+# The Makefile in that directory builds executables by simply referencing
+# the .o files in this directory.
+
+
+##############################################################################
+#
+# Some rambling about dynamic libraries follows, ignore it if you don't care
+# (which is almost assuredly the case.)
+#
+#
+# It would probably be sensible to just build a single .a file in this
+# directory, and link the hacks against that (statically.) I haven't done
+# that for two reasons: first, it works now, and why fix what ain't broke;
+# second, it wouldn't actually improve anything for the end user (it would
+# just make the Makefiles be a little smaller.)
+#
+# People sometimes suggest that the stuff in this directory should be in a
+# dynamic library, and that the hacks should be linked dynamically against
+# it. I haven't done this for a number of reasons:
+#
+# * First, the only thing that would improve would be disk space, in that
+# the executable files themselves would be smaller. That's it. Many other
+# things would get worse if we used a dynamic library:
+#
+# * Complication of installation procedures: suddenly, before any of the
+# hacks will work, you need to have a dynamic library installed, and
+# the system configured to use it. This is, basically, rocket science.
+# Most people don't know how to do this, it's a huge pain, and on many
+# systems, it requires root access.
+#
+# * Complication of the Makefile: every system builds dynamic libraries
+# differently. Every compiler takes different flags. I don't want to
+# do the hand-holding for the scores of Unix systems and compilers on
+# which people try to build this program.
+#
+# * Reduction of maintainability: gdb is remarkably bad at dealing with
+# debug info in dynamic libraries, and when debugging a hack, one would
+# constantly be fighting the linker and the debugger (or linking
+# statically when debugging.)
+#
+# * Version skew: when things are statically linked, it's perfectly ok to
+# make incompatible changes to the APIs defined in this directory, so long
+# as the current version in ../hacks/ is in sync. Much more care would
+# need to be taken with such things if dynamic libraries were involved,
+# to make sure that the major and minor versions of the library changed
+# at the appropriate time. This isn't too hard, but it's more work, and
+# yet another opportunity to screw up.
+#
+# * Runtime memory usage goes *up*. That's right, up! When a program
+# links in a dynamic library, the whole library is brought into the
+# address space, not just the files that are actually used. Normally,
+# this is ok, because if several programs are using (for example)
+# libX11.so, chances are that the savings outweighs the overhead. But
+# the nature of xscreensaver is that only one of the hacks ever runs at
+# a time -- so there would never be a second program using the utils/
+# dynamic library with which things could be shared.
+#
+# * Runtime speed decreases slightly, since dynamic code is marginally
+# slower. On modern machines, this probably doesn't make a perceptible
+# difference, however.
+#
+# So basically, I just don't think using libraries would be a win, and it would
+# definitely cause more of a maintenance and portability headache. However,
+# if someone else wants to do the work to make it be an option to configure,
+# and verifies that it works on several (more than three) different Unixes,
+# I'd be happy to take the patches.
+# -- jwz, 30-Jun-98
+#
+##############################################################################
+
+
+@SET_MAKE@
+.SUFFIXES:
+.SUFFIXES: .c .o
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+datarootdir = @datarootdir@
+
+CC = @CC@
+CFLAGS = @CFLAGS@
+DEFS = @DEFS@
+
+DEPEND = @DEPEND@
+DEPEND_FLAGS = @DEPEND_FLAGS@
+DEPEND_DEFINES = @DEPEND_DEFINES@
+
+SHELL = /bin/sh
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_DIRS = @INSTALL_DIRS@
+
+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 \
+ 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 \
+ 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 \
+ 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
+STAR = *
+LOGOS = images/$(STAR).xpm \
+ images/$(STAR).png \
+ images/$(STAR).gif \
+ images/$(STAR).eps
+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)
+
+
+default: all
+all: $(OBJS)
+
+install: install-program install-man
+uninstall: uninstall-program uninstall-man
+
+install-strip:
+ $(MAKE) INSTALL_PROGRAM='$(INSTALL_PROGRAM) -s' install
+
+install-program:
+install-man:
+uninstall-program:
+uninstall-man:
+
+clean:
+ -rm -f *.o a.out core
+
+distclean: clean
+ -rm -f Makefile TAGS *~ "#"*
+
+# Adds all current dependencies to Makefile
+depend:
+ $(DEPEND) -s '# DO NOT DELETE: updated by make depend' \
+ $(DEPEND_FLAGS) -- \
+ $(INCLUDES) $(DEFS) $(DEPEND_DEFINES) $(CFLAGS) $(X_CFLAGS) -- \
+ $(SRCS)
+
+# Adds some dependencies to Makefile.in -- not totally accurate, but pretty
+# close. This excludes dependencies on files in /usr/include, etc. It tries
+# to include only dependencies on files which are themselves a part of this
+# package.
+distdepend::
+ @echo updating dependencies in `pwd`/Makefile.in... ; \
+ $(DEPEND) -w 0 -f - \
+ -s '# DO NOT DELETE: updated by make distdepend' $(DEPEND_FLAGS) -- \
+ $(INCLUDES_1) $(DEFS) $(DEPEND_DEFINES) $(CFLAGS) $(X_CFLAGS) -- \
+ $(SRCS) 2>/dev/null | \
+ sort -d | \
+ ( \
+ awk '/^# .*Makefile.in ---/,/^# DO .*distdepend/' < Makefile.in ; \
+ sed -e '/^#.*/d' \
+ -e 's@ \./@ @g;s@ /[^ ]*@@g;/^.*:$$/d' \
+ -e 's@ \([^$$]\)@ $$(srcdir)/\1@g' \
+ -e 's@ $$(srcdir)/\(.*config.h\)@ \1@g' ; \
+ echo '' \
+ ) > /tmp/distdepend.$$$$ && \
+ mv /tmp/distdepend.$$$$ Makefile.in
+
+TAGS: tags
+tags:
+ find $(srcdir) -name '*.[chly]' -print | xargs etags -a
+
+echo_tarfiles:
+ @echo $(TARFILES)
+
+
+# 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: 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
+alpha.o: $(srcdir)/alpha.h
+alpha.o: ../config.h
+alpha.o: $(srcdir)/hsv.h
+alpha.o: $(srcdir)/resources.h
+alpha.o: $(srcdir)/utils.h
+alpha.o: $(srcdir)/visual.h
+alpha.o: $(srcdir)/yarandom.h
+async_netdb.o: $(srcdir)/aligned_malloc.h
+async_netdb.o: $(srcdir)/async_netdb.h
+async_netdb.o: ../config.h
+async_netdb.o: $(srcdir)/thread_util.h
+colorbars.o: $(srcdir)/colorbars.h
+colorbars.o: ../config.h
+colorbars.o: $(srcdir)/../hacks/ximage-loader.h
+colorbars.o: $(srcdir)/resources.h
+colorbars.o: $(srcdir)/utils.h
+colors.o: $(srcdir)/colors.h
+colors.o: ../config.h
+colors.o: $(srcdir)/hsv.h
+colors.o: $(srcdir)/utils.h
+colors.o: $(srcdir)/visual.h
+colors.o: $(srcdir)/yarandom.h
+erase.o: ../config.h
+erase.o: $(srcdir)/erase.h
+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
+font-retry.o: $(srcdir)/visual.h
+font-retry.o: $(srcdir)/xft.h
+grabclient.o: ../config.h
+grabclient.o: $(srcdir)/grabscreen.h
+grabclient.o: $(srcdir)/resources.h
+grabclient.o: $(srcdir)/utils.h
+grabclient.o: $(srcdir)/vroot.h
+grabclient.o: $(srcdir)/yarandom.h
+grabscreen.o: $(srcdir)/colors.h
+grabscreen.o: ../config.h
+grabscreen.o: $(srcdir)/grabscreen.h
+grabscreen.o: $(srcdir)/resources.h
+grabscreen.o: $(srcdir)/usleep.h
+grabscreen.o: $(srcdir)/utils.h
+grabscreen.o: $(srcdir)/visual.h
+grabscreen.o: $(srcdir)/vroot.h
+grabscreen.o: $(srcdir)/yarandom.h
+hsv.o: ../config.h
+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-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
+overlay.o: $(srcdir)/utils.h
+overlay.o: $(srcdir)/visual.h
+pow2.o: $(srcdir)/pow2.h
+resources.o: ../config.h
+resources.o: $(srcdir)/resources.h
+resources.o: $(srcdir)/utils.h
+spline.o: ../config.h
+spline.o: $(srcdir)/spline.h
+spline.o: $(srcdir)/utils.h
+textclient-mobile.o: ../config.h
+textclient-mobile.o: $(srcdir)/utils.h
+textclient.o: ../config.h
+textclient.o: $(srcdir)/resources.h
+textclient.o: $(srcdir)/textclient.h
+textclient.o: $(srcdir)/utils.h
+thread_util.o: $(srcdir)/aligned_malloc.h
+thread_util.o: ../config.h
+thread_util.o: $(srcdir)/resources.h
+thread_util.o: $(srcdir)/thread_util.h
+usleep.o: ../config.h
+utf8wc.o: ../config.h
+utf8wc.o: $(srcdir)/utf8wc.h
+visual-gl.o: ../config.h
+visual-gl.o: $(srcdir)/resources.h
+visual-gl.o: $(srcdir)/utils.h
+visual-gl.o: $(srcdir)/visual.h
+visual.o: ../config.h
+visual.o: $(srcdir)/resources.h
+visual.o: $(srcdir)/utils.h
+visual.o: $(srcdir)/visual.h
+xdbe.o: ../config.h
+xdbe.o: $(srcdir)/resources.h
+xdbe.o: $(srcdir)/utils.h
+xdbe.o: $(srcdir)/xdbe.h
+xft.o: ../config.h
+xmu.o: ../config.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
+yarandom.o: $(srcdir)/yarandom.h
+
diff --git a/utils/README b/utils/README
new file mode 100644
index 0000000..2f5bc11
--- /dev/null
+++ b/utils/README
@@ -0,0 +1,6 @@
+
+This directory contains various utilities that are used both by the
+screensaver driver and by the demo programs; for example, a portable
+implementation of usleep(), and code for manipulating color maps.
+
+If you have compilation problems, check the parameters in ../config.h.
diff --git a/utils/ad2c b/utils/ad2c
new file mode 100755
index 0000000..0a543ba
--- /dev/null
+++ b/utils/ad2c
@@ -0,0 +1,42 @@
+#!/bin/sh
+#
+# ad2c : Convert app-defaults file to C strings decls.
+#
+# George Ferguson, ferguson@cs.rcohester.edu, 12 Nov 1990.
+# 19 Mar 1991 : gf
+# Made it self-contained.
+# 6 Jan 1992 : mycroft@gnu.ai.mit.edu (Charles Hannum)
+# Removed use of "-n" and ":read" label since Gnu and
+# IBM sed print pattern space on "n" command. Still works
+# with Sun sed, of course.
+# 7 Jan 1992: matthew@sunpix.East.Sun.COM (Matthew Stier)
+# Escape quotes after escaping backslashes.
+# 22 Oct 2004: jwz:
+# Convert CR to LF.
+#
+
+#sed 's/\r/\n/g' "$@" |
+perl -npe 's/\r/\n/g' < "$@" |
+sed '
+/^!/d
+/^$/d
+s/\\/\\\\/g
+s/\\$//g
+s/"/\\"/g
+s/^/"/
+: test
+/\\$/b slash
+s/$/",/
+p
+d
+: slash
+n
+/^!/d
+/^$/d
+s/"/\\"/g
+s/\\\\/\\/g
+s/\\n/\\\\n/g
+s/\\t/\\\\t/g
+s/\\f/\\\\f/g
+s/\\b/\\\\b/g
+b test'
diff --git a/utils/aligned_malloc.c b/utils/aligned_malloc.c
new file mode 100644
index 0000000..b345ad1
--- /dev/null
+++ b/utils/aligned_malloc.c
@@ -0,0 +1,48 @@
+/* -*- mode: c; tab-width: 4; fill-column: 128 -*- */
+/* vi: set ts=4 tw=128: */
+
+/*
+aligned_malloc.c, Copyright (c) 2014 Dave Odell <dmo2118@gmail.com>
+
+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.
+*/
+
+#include "aligned_malloc.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#include <assert.h>
+#include <errno.h>
+
+/* aligned_alloc() (C11) or posix_memalign() (POSIX) are other possibilities
+ for aligned_malloc().
+ */
+
+int aligned_malloc(void **ptr, unsigned alignment, size_t size)
+{
+ void *block_start;
+ ptrdiff_t align1 = alignment - 1;
+
+ assert(alignment && !(alignment & (alignment - 1))); /* alignment must be a power of two. */
+
+ size += sizeof(void *) + align1;
+ block_start = malloc(size);
+ if(!block_start)
+ return ENOMEM;
+ *ptr = (void *)(((ptrdiff_t)block_start + sizeof(void *) + align1) & ~align1);
+ ((void **)(*ptr))[-1] = block_start;
+ return 0;
+}
+
+void aligned_free(void *ptr)
+{
+ if(ptr)
+ free(((void **)(ptr))[-1]);
+}
diff --git a/utils/aligned_malloc.h b/utils/aligned_malloc.h
new file mode 100644
index 0000000..b3f43c9
--- /dev/null
+++ b/utils/aligned_malloc.h
@@ -0,0 +1,26 @@
+/* -*- mode: c; tab-width: 4; fill-column: 128 -*- */
+/* vi: set ts=4 tw=128: */
+
+/*
+aligned_malloc.h, Copyright (c) 2014 Dave Odell <dmo2118@gmail.com>
+
+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 __ALIGNED_MALLOC_H__
+#define __ALIGNED_MALLOC_H__
+
+#include <stdlib.h>
+
+ /* 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 *);
+
+#endif /* __ALIGNED_MALLOC_H__ */
diff --git a/utils/alpha.c b/utils/alpha.c
new file mode 100644
index 0000000..5b18e85
--- /dev/null
+++ b/utils/alpha.c
@@ -0,0 +1,215 @@
+/* xscreensaver, Copyright (c) 1992, 1995, 1996, 1997, 2006
+ * 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.
+ */
+
+/* Beauty is only skin deep, unless you've got an alpha channel. */
+
+
+#include "utils.h"
+#include "alpha.h"
+#include "visual.h"
+#include "hsv.h"
+#include "yarandom.h"
+#include "resources.h"
+
+#include <X11/Xutil.h>
+
+#ifndef countof
+# define countof(x) (sizeof(*(x))/sizeof((x)))
+#endif
+
+
+/* I don't believe this fucking language doesn't have builtin exponentiation.
+ I further can't believe that the fucking ^ character means fucking XOR!! */
+static int
+i_exp (int i, int j)
+{
+ int k = 1;
+ while (j--) k *= i;
+ return k;
+}
+
+
+static void
+merge_colors (int argc, XColor **argv, XColor *into_color, int mask,
+ Bool additive_p)
+{
+ int j;
+ *into_color = *argv [0];
+ into_color->pixel |= mask;
+
+ for (j = 1; j < argc; j++)
+ {
+# define SHORT_INC(x,y) (x = ((((x)+(y)) > 0xFFFF) ? 0xFFFF : ((x)+(y))))
+# define SHORT_DEC(x,y) (x = ((((x)-(y)) < 0) ? 0 : ((x)-(y))))
+ if (additive_p)
+ {
+ SHORT_INC (into_color->red, argv[j]->red);
+ SHORT_INC (into_color->green, argv[j]->green);
+ SHORT_INC (into_color->blue, argv[j]->blue);
+ }
+ else
+ {
+ SHORT_DEC (into_color->red, argv[j]->red);
+ SHORT_DEC (into_color->green, argv[j]->green);
+ SHORT_DEC (into_color->blue, argv[j]->blue);
+ }
+# undef SHORT_INC
+# undef SHORT_DEC
+ }
+}
+
+static void
+permute_colors (XColor *pcolors, XColor *colors,
+ int count,
+ unsigned long *plane_masks,
+ Bool additive_p)
+{
+ int out = 0;
+ int max = i_exp (2, count);
+ if (count > 31) abort ();
+ for (out = 1; out < max; out++)
+ {
+ XColor *argv [32];
+ int this_mask = 0;
+ int argc = 0;
+ int bit;
+ for (bit = 0; bit < 32; bit++)
+ if (out & (1<<bit))
+ {
+ argv [argc++] = &pcolors [bit];
+ this_mask |= plane_masks [bit];
+ }
+ merge_colors (argc, argv, &colors [out-1], this_mask, additive_p);
+ }
+}
+
+
+static int
+allocate_color_planes (Display *dpy, Colormap cmap,
+ int nplanes, unsigned long *plane_masks,
+ unsigned long *base_pixel_ret)
+{
+ while (nplanes > 1 &&
+ !XAllocColorCells (dpy, cmap, False, plane_masks, nplanes,
+ base_pixel_ret, 1))
+ nplanes--;
+
+ return nplanes;
+}
+
+
+static void
+initialize_transparency_colormap (Display *dpy, Colormap cmap,
+ int nplanes,
+ unsigned long base_pixel,
+ unsigned long *plane_masks,
+ XColor *colors,
+ Bool additive_p)
+{
+ int i;
+ int total_colors = i_exp (2, nplanes);
+ XColor *all_colors = (XColor *) calloc (total_colors, sizeof (XColor));
+
+ for (i = 0; i < nplanes; i++)
+ colors[i].pixel = base_pixel | plane_masks [i];
+ permute_colors (colors, all_colors, nplanes, plane_masks, additive_p);
+
+ /* clone the default background of the window into our "base" pixel */
+ all_colors [total_colors - 1].pixel =
+ get_pixel_resource (dpy, cmap, "background", "Background");
+ XQueryColor (dpy, cmap, &all_colors [total_colors - 1]);
+ all_colors [total_colors - 1].pixel = base_pixel;
+
+ for (i = 0; i < total_colors; i++)
+ all_colors[i].flags = DoRed|DoGreen|DoBlue;
+ XStoreColors (dpy, cmap, all_colors, total_colors);
+ XFree ((XPointer) all_colors);
+}
+
+
+Bool
+allocate_alpha_colors (Screen *screen, Visual *visual, Colormap cmap,
+ int *nplanesP, Bool additive_p,
+ unsigned long **plane_masks,
+ unsigned long *base_pixelP)
+{
+ Display *dpy = DisplayOfScreen (screen);
+ XColor *colors;
+ int nplanes = *nplanesP;
+ int i;
+
+ if (!has_writable_cells (screen, visual))
+ cmap = 0;
+
+ if (!cmap) /* A TrueColor visual, or similar. */
+ {
+ int depth = visual_depth (screen, visual);
+ unsigned long masks;
+ XVisualInfo vi_in, *vi_out;
+
+ /* Find out which bits the R, G, and B components actually occupy
+ on this visual. */
+ vi_in.screen = screen_number (screen);
+ vi_in.visualid = XVisualIDFromVisual (visual);
+ vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
+ &vi_in, &i);
+ if (! vi_out) abort ();
+ masks = vi_out[0].red_mask | vi_out[0].green_mask | vi_out[0].blue_mask;
+ XFree ((char *) vi_out);
+
+ if (nplanes > depth)
+ nplanes = depth;
+ *nplanesP = nplanes;
+ *base_pixelP = 0;
+ *plane_masks = (unsigned long *) calloc(sizeof(unsigned long), nplanes);
+
+ /* Pick the planar values randomly, but constrain them to fall within
+ the bit positions of the R, G, and B fields. */
+ for (i = 0; i < nplanes; i++)
+ (*plane_masks)[i] = random() & masks;
+
+ }
+ else /* A PseudoColor visual, or similar. */
+ {
+ if (nplanes > 31) nplanes = 31;
+ *plane_masks = (unsigned long *) malloc(sizeof(unsigned long) * nplanes);
+
+ nplanes = allocate_color_planes (dpy, cmap, nplanes, *plane_masks,
+ base_pixelP);
+ *nplanesP = nplanes;
+
+ if (nplanes <= 1)
+ {
+ free(*plane_masks);
+ *plane_masks = 0;
+ return False;
+ }
+
+ colors = (XColor *) calloc (nplanes, sizeof (XColor));
+ for (i = 0; i < nplanes; i++)
+ {
+ /* pick the base colors. If we are in subtractive mode, pick higher
+ intensities. */
+ hsv_to_rgb (random () % 360,
+ frand (1.0),
+ frand (0.5) + (additive_p ? 0.2 : 0.5),
+ &colors[i].red,
+ &colors[i].green,
+ &colors[i].blue);
+ }
+ initialize_transparency_colormap (dpy, cmap, nplanes,
+ *base_pixelP, *plane_masks, colors,
+ additive_p);
+ XFree ((XPointer) colors);
+ }
+ return True;
+}
diff --git a/utils/alpha.h b/utils/alpha.h
new file mode 100644
index 0000000..4ff9903
--- /dev/null
+++ b/utils/alpha.h
@@ -0,0 +1,22 @@
+/* xscreensaver, Copyright (c) 1992, 1995, 1996, 1997
+ * 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 __XSCREENSAVER_ALPHA_H__
+#define __XSCREENSAVER_ALPHA_H__
+
+extern Bool allocate_alpha_colors (Screen *screen, Visual *visual,
+ Colormap cmap,
+ int *nplanesP, Bool additive_p,
+ unsigned long **plane_masks,
+ unsigned long *base_pixelP);
+
+#endif /* __XSCREENSAVER_ALPHA_H__ */
diff --git a/utils/async_netdb.c b/utils/async_netdb.c
new file mode 100644
index 0000000..930da40
--- /dev/null
+++ b/utils/async_netdb.c
@@ -0,0 +1,449 @@
+/* vi: set tw=78: */
+
+/* async_netdb.c, Copyright (c) Dave Odell <dmo2118@gmail.com>
+ *
+ * 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.
+ *
+ * Threaded versions of get(name/addr)info to replace calls to
+ * gethostby(name/addr), for Sonar.
+ */
+
+#include "async_netdb.h"
+
+#include "thread_util.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <unistd.h>
+
+/* This is very much system-dependent, but hopefully 64K covers it just about
+ everywhere. The threads here shouldn't need much. */
+#define ASYNC_NETDB_STACK 65536
+
+#if ASYNC_NETDB_USE_GAI
+
+# define _get_addr_family(addr) ((addr)->x_sockaddr_storage.ss_family)
+# define _get_addr_len(addr) ((addr)->x_sockaddr_storage.ss_len)
+
+static int _has_threads;
+
+int _async_netdb_is_done (struct io_thread *io)
+{
+ if (_has_threads >= 0)
+ return io_thread_is_done (io);
+ return 1;
+}
+
+#else /* ASYNC_NETDB_USE_GAI */
+
+# 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
+
+const char *_async_netdb_strerror (int errcode)
+{
+ /* (h)strerror should return messages in the user's preferred language. */
+
+ /* On Solaris, gethostbyname(3) is in libnsl, but hstrerror(3) is in
+ libresolv. Not that it matters, since Solaris has real gai_strerror in
+ libsocket. */
+
+ switch (errcode)
+ {
+ case EAI_NONAME:
+ return hstrerror (HOST_NOT_FOUND);
+ case EAI_AGAIN:
+ return hstrerror (TRY_AGAIN);
+ case EAI_FAIL:
+ return hstrerror (NO_RECOVERY);
+ case EAI_MEMORY:
+ return strerror (ENOMEM);
+ }
+ /* case EAI_SYSTEM: default: */
+ return strerror (EINVAL); /* No good errno equivalent here. */
+}
+
+# endif /* ASYNC_NETDB_FAKE_EAI */
+
+#endif /* !ASYNC_NETDB_USE_GAI */
+
+static int _translate_h_errno (int error)
+{
+ switch (error)
+ {
+ case HOST_NOT_FOUND:
+ case NO_DATA:
+ return EAI_NONAME;
+ case TRY_AGAIN:
+ return EAI_AGAIN;
+ }
+
+ /* case NO_RECOVERY: default: */
+ return EAI_FAIL;
+}
+
+/* async_name_from_addr - */
+
+#if ASYNC_NETDB_USE_GAI
+
+static void *
+_async_name_from_addr_thread (void *self_raw)
+{
+ /* The stack is unusually small here. If this crashes, you may need to bump
+ the value of ASYNC_NETDB_STACK. */
+
+ async_name_from_addr_t self = (async_name_from_addr_t)self_raw;
+
+ /* getnameinfo() is thread-safe, gethostbyaddr() is not. */
+ self->gai_error = getnameinfo ((void *)&self->param.addr,
+ self->param.addrlen,
+ self->host, sizeof(self->host), NULL, 0,
+ NI_NAMEREQD);
+ /* Removing NI_MAKEREQD would require a call to inet_ntoa in
+ async_name_from_addr_finish. */
+
+ self->errno_error = errno;
+
+ if (io_thread_return (&self->io))
+ thread_free(self);
+
+ return NULL;
+}
+
+#endif /* ASYNC_NETDB_USE_GAI */
+
+static void
+_async_name_from_addr_set_param (struct _async_name_from_addr_param *self,
+ const struct sockaddr *addr,
+ socklen_t addrlen)
+{
+ self->addrlen = addrlen;
+ memcpy (&self->addr, addr, addrlen);
+
+#if HAVE_STRUCT_SOCKADDR_SA_LEN
+ _get_addr_len (&self->addr) = addrlen; /* The BSDs need this. */
+#endif
+}
+
+async_name_from_addr_t
+async_name_from_addr_start (Display *dpy, const struct sockaddr *addr,
+ socklen_t addrlen)
+{
+ assert (addrlen);
+ assert (addrlen <= sizeof (async_netdb_sockaddr_storage_t));
+
+#if ASYNC_NETDB_USE_GAI
+ _has_threads = threads_available (dpy);
+ if (_has_threads >= 0)
+ {
+ async_name_from_addr_t self, result;
+
+ if (thread_malloc ((void **)&self, dpy,
+ sizeof (struct async_name_from_addr)))
+ return NULL;
+
+ _async_name_from_addr_set_param (&self->param, addr, addrlen);
+
+ result = io_thread_create (&self->io, self,
+ _async_name_from_addr_thread, dpy,
+ ASYNC_NETDB_STACK);
+ if (!result)
+ thread_free (self);
+ return result;
+ }
+#endif /* ASYNC_NETDB_USE_GAI */
+
+ {
+ struct _async_name_from_addr_param *result =
+ (struct _async_name_from_addr_param *)
+ malloc (sizeof (struct _async_name_from_addr_param));
+
+ if (result)
+ _async_name_from_addr_set_param (result, addr, addrlen);
+
+ return (async_name_from_addr_t)result;
+ }
+}
+
+#if ASYNC_NETDB_USE_GAI
+void
+async_name_from_addr_cancel (async_name_from_addr_t self)
+{
+ if (_has_threads >= 0)
+ {
+ if(io_thread_cancel (&self->io))
+ thread_free (self);
+ }
+ else
+ {
+ free (self);
+ }
+}
+#endif /* ASYNC_NETDB_USE_GAI */
+
+int
+async_name_from_addr_finish (async_name_from_addr_t self_raw,
+ char **host, int *errno_error)
+{
+#if ASYNC_NETDB_USE_GAI
+ if (_has_threads >= 0)
+ {
+ async_name_from_addr_t self = self_raw;
+ int gai_error;
+
+ io_thread_finish (&self->io);
+
+ gai_error = self->gai_error;
+ if (gai_error)
+ {
+ if (errno_error)
+ *errno_error = self->errno_error;
+ *host = NULL; /* For safety's sake. */
+ }
+ else
+ {
+ *host = strdup(self->host);
+ if (!*host)
+ gai_error = EAI_MEMORY;
+ }
+
+ thread_free (self);
+ return gai_error;
+ }
+#endif /* ASYNC_NETDB_USE_GAI */
+
+ {
+ struct _async_name_from_addr_param *self =
+ (struct _async_name_from_addr_param *)self_raw;
+
+ const struct hostent *he;
+ int error;
+ const void *raw_addr;
+ socklen_t addrlen;
+
+ switch (_get_addr_family (&self->addr))
+ {
+ case AF_INET:
+ raw_addr = &self->addr.x_sockaddr_in.sin_addr;
+ addrlen = 4;
+ break;
+#if ASYNC_NETDB_USE_GAI
+ case AF_INET6:
+ raw_addr = &self->addr.x_sockaddr_in6.sin6_addr;
+ addrlen = 16;
+ break;
+#endif /* ASYNC_NETDB_USE_GAI */
+ default:
+ return EAI_NONAME;
+ }
+
+ he = gethostbyaddr(raw_addr, addrlen, _get_addr_family (&self->addr));
+ error = h_errno;
+
+ free (self);
+
+ if (!he)
+ {
+ *host = NULL; /* For safety's sake. */
+ return _translate_h_errno(error);
+ }
+
+ if (!he->h_name)
+ return EAI_NONAME;
+
+ *host = strdup (he->h_name);
+ if (!*host)
+ return EAI_MEMORY;
+
+ return 0;
+ }
+}
+
+/* async_addr_from_name - */
+
+static char *
+_async_addr_from_name_hostname (async_addr_from_name_t self)
+{
+ return (char *)(self + 1);
+}
+
+static void
+_async_addr_from_name_free (async_addr_from_name_t self)
+{
+#if ASYNC_NETDB_USE_GAI
+ if (self->res) /* FreeBSD won't do freeaddrinfo (NULL). */
+ freeaddrinfo (self->res);
+#endif
+ thread_free (self);
+}
+
+#if ASYNC_NETDB_USE_GAI
+
+static void *
+_async_addr_from_name_thread (void *self_raw)
+{
+ /* The stack is unusually small here. If this crashes, you may need to bump
+ the value of ASYNC_NETDB_STACK. */
+
+ async_addr_from_name_t self = (async_addr_from_name_t)self_raw;
+ self->gai_error = getaddrinfo (_async_addr_from_name_hostname (self), NULL,
+ NULL, &self->res);
+ self->errno_error = errno;
+
+ if (io_thread_return (&self->io))
+ _async_addr_from_name_free (self);
+
+ return NULL;
+}
+
+#endif /* ASYNC_NETDB_USE_GAI */
+
+/* getaddrinfo supports more than a hostname, but gethostbyname does not. */
+async_addr_from_name_t
+async_addr_from_name_start (Display *dpy, const char *hostname)
+{
+ async_addr_from_name_t self;
+ if (thread_malloc ((void **)&self, dpy,
+ sizeof(struct async_addr_from_name) + strlen(hostname) + 1))
+ return NULL;
+
+ strcpy (_async_addr_from_name_hostname (self), hostname);
+
+#if ASYNC_NETDB_USE_GAI
+ _has_threads = threads_available (dpy);
+ self->res = NULL;
+ if (_has_threads >= 0)
+ {
+ async_addr_from_name_t result =
+ io_thread_create (&self->io, self, _async_addr_from_name_thread, dpy,
+ ASYNC_NETDB_STACK);
+
+ if (!result)
+ thread_free(result);
+ self = result;
+ }
+#endif /* ASYNC_NETDB_USE_GAI */
+
+ return self;
+}
+
+#if ASYNC_NETDB_USE_GAI
+void
+async_addr_from_name_cancel (async_addr_from_name_t self)
+{
+ if (_has_threads >= 0)
+ {
+ if (io_thread_cancel (&self->io))
+ _async_addr_from_name_free (self);
+ }
+ else
+ {
+ thread_free (self);
+ }
+}
+#endif /* ASYNC_NETDB_USE_GAI */
+
+/* async_name_from_addr_finish does sockaddr_in or sockaddr_in6. */
+
+int
+async_addr_from_name_finish (async_addr_from_name_t self, void *addr,
+ socklen_t *addrlen, int *errno_error)
+{
+#if ASYNC_NETDB_USE_GAI
+ if (_has_threads >= 0)
+ {
+ int gai_error;
+ io_thread_finish (&self->io);
+
+ gai_error = self->gai_error;
+ if (errno_error)
+ *errno_error = self->errno_error;
+
+ if (!gai_error)
+ {
+ struct addrinfo *ai = self->res;
+ if (!ai)
+ gai_error = EAI_NONAME;
+ else
+ {
+ assert (ai->ai_addrlen <=
+ sizeof (async_netdb_sockaddr_storage_t));
+ memcpy (addr, ai->ai_addr, ai->ai_addrlen);
+ *addrlen = ai->ai_addrlen;
+ }
+ }
+
+ _async_addr_from_name_free (self);
+ return gai_error;
+ }
+#endif /* ASYNC_NETDB_USE_GAI */
+
+ {
+ struct hostent *he =
+ gethostbyname (_async_addr_from_name_hostname (self));
+ int error = h_errno;
+ void *raw_addr;
+ async_netdb_sockaddr_storage_t *addr_storage =
+ (async_netdb_sockaddr_storage_t *)addr;
+
+ _async_addr_from_name_free (self);
+
+ if (!he)
+ return _translate_h_errno (error);
+
+ switch (he->h_addrtype)
+ {
+ case AF_INET:
+ {
+ struct sockaddr_in *addr_in = (struct sockaddr_in *)addr;
+ addr_in->sin_port = 0;
+ raw_addr = &addr_in->sin_addr;
+ *addrlen = sizeof(*addr_in);
+ assert (he->h_length == 4);
+ }
+ break;
+#if ASYNC_NETDB_USE_GAI
+ case AF_INET6:
+ {
+ struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)addr;
+ addr_in6->sin6_port = 0;
+ addr_in6->sin6_flowinfo = 0;
+ raw_addr = &addr_in6->sin6_addr;
+ *addrlen = sizeof(*addr_in6);
+ assert (he->h_length == 16);
+ }
+ break;
+#endif /* ASYNC_NETDB_USE_GAI */
+ default:
+ return EAI_NONAME;
+ }
+
+#if HAVE_STRUCT_SOCKADDR_SA_LEN
+ _get_addr_len (addr_storage) = *addrlen;
+#endif
+ _get_addr_family (addr_storage) = he->h_addrtype;
+
+ memcpy (raw_addr, he->h_addr_list[0], he->h_length);
+ return 0;
+ }
+}
+
+/* Local Variables: */
+/* mode: c */
+/* fill-column: 78 */
+/* c-file-style: "gnu" */
+/* c-basic-offset: 2 */
+/* indent-tabs-mode: nil */
+/* End: */
diff --git a/utils/async_netdb.h b/utils/async_netdb.h
new file mode 100644
index 0000000..a72f4d5
--- /dev/null
+++ b/utils/async_netdb.h
@@ -0,0 +1,223 @@
+/* vi: set tw=78: */
+
+/* async_netdb.h, Copyright (c) Dave Odell <dmo2118@gmail.com>
+ *
+ * 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 ASYNC_NETDB_H
+#define ASYNC_NETDB_H
+
+#include "thread_util.h"
+
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+/*
+ Both async_name_from_addr_* and async_addr_from_name_* follow basic pattern
+ for io_thread clients as described in thread_util.h:
+ 1. async_*_from_*_start
+ 2. async_*_from_*_is_done (repeat as necessary)
+ 3a. async_*_from_*_finish to retrieve the results, or:
+ 3b. async_*_from_*_cancel to abort the lookup.
+
+ On systems that can't do asynchronous host lookups, the *_finish functions
+ do the actual lookup.
+ */
+
+#ifndef NI_MAXHOST
+/*
+ From the glibc man page for getnameinfo(3):
+ Since glibc 2.8, these definitions are exposed only if one of the
+ feature test macros _BSD_SOURCE, _SVID_SOURCE, or _GNU_SOURCE is
+ defined.
+ */
+# define NI_MAXHOST 1025
+#endif
+
+#if HAVE_PTHREAD && HAVE_GETADDRINFO
+/*
+ If threads or getaddrinfo() are unavailable, then the older gethostbyname()
+ and gethostbyaddr() functions are used, and IPv6 is disabled.
+ */
+# define ASYNC_NETDB_USE_GAI 1
+#endif
+
+#if ASYNC_NETDB_USE_GAI
+
+/* Without using union, gcc-6 warns for
+ breaking strict aliasing rules
+ */
+typedef union {
+ struct sockaddr_storage x_sockaddr_storage;
+ struct sockaddr_in x_sockaddr_in;
+ struct sockaddr_in6 x_sockaddr_in6;
+} async_netdb_sockaddr_storage_t;
+
+int _async_netdb_is_done (struct io_thread *io);
+
+#else
+
+/* Because the definition for the above case is now union,
+ the definition for this case must also be union...
+*/
+typedef union {
+ struct sockaddr_in x_sockaddr_in;
+} async_netdb_sockaddr_storage_t;
+
+# ifndef EAI_SYSTEM
+/* The EAI_* codes are specified specifically as preprocessor macros, so
+ the #ifdef here should always work...
+ http://pubs.opengroup.org/onlinepubs/009604499/basedefs/netdb.h.html */
+
+# define ASYNC_NETDB_FAKE_EAI 1
+
+/* Even without addrinfo, the EAI_* error codes are used. The numbers are from
+ Linux's netdb.h. */
+# define EAI_NONAME -2
+# define EAI_AGAIN -3
+# define EAI_FAIL -4
+# define EAI_MEMORY -10
+# define EAI_SYSTEM -11
+
+const char *_async_netdb_strerror (int errcode);
+
+# define gai_strerror(errcode) _async_netdb_strerror (errcode)
+# endif
+
+# define _async_netdb_is_done(io) 1
+
+#endif
+
+/* In non-threaded mode, _async_name_from_addr_param is used in place of
+ async_name_from_addr. */
+struct _async_name_from_addr_param
+{
+ socklen_t addrlen;
+ async_netdb_sockaddr_storage_t addr;
+};
+
+typedef struct async_name_from_addr
+{
+ /*
+ Stupid memory trick, thwarted: The host string could be at the beginning
+ of this structure, and the memory block that contains this struct could
+ be resized and returned directly in async_name_from_addr_finish. But...
+
+ There is no aligned_realloc. In fact, aligned_realloc is a bit of a
+ problem, mostly because:
+ 1. realloc() is the only way to resize a heap-allocated memory block.
+ 2. realloc() moves memory.
+ 3. The location that realloc() moves memory to won't be aligned.
+ */
+
+ struct _async_name_from_addr_param param;
+ struct io_thread io;
+
+ char host[NI_MAXHOST];
+ int gai_error;
+ int errno_error;
+
+} *async_name_from_addr_t;
+
+async_name_from_addr_t async_name_from_addr_start (Display *dpy,
+ const struct sockaddr *addr,
+ socklen_t addrlen);
+/*
+ Starts an asynchronous name-from-address lookup.
+ dpy: An X11 Display with a .useThreads resource.
+ addr: An address. Like various socket functions (e.g. bind(2),
+ connect(2), sendto(2)), this isn't really a struct sockaddr so
+ much as a "subtype" of sockaddr, like sockaddr_in, or
+ sockaddr_in6, or whatever.
+ addrlen: The (actual) length of *addr.
+ Returns NULL if the request couldn't be created (due to low memory).
+ */
+
+#define async_name_from_addr_is_done(self) _async_netdb_is_done (&(self)->io)
+
+#if ASYNC_NETDB_USE_GAI
+void async_name_from_addr_cancel (async_name_from_addr_t self);
+#else
+# define async_name_from_addr_cancel(self) (free (self))
+#endif
+
+int async_name_from_addr_finish (async_name_from_addr_t self,
+ char **host, int *errno_error);
+/*
+ Gets the result of an asynchronous name-from-address lookup. If the lookup
+ operation is still in progress, or if the system can't do async lookups,
+ this will block. This cleans up the lookup operation; do not use 'self'
+ after calling this function.
+ self: The lookup operation.
+ host: If no error, the name of the host. Free this with free(3).
+ errno_error: The value of errno if EAI_SYSTEM is returned. Can be NULL.
+ Returns 0 on success, otherwise an error from getnameinfo(3).
+ */
+
+/* In non-threaded mode, async_addr_from_name contains different stuff. */
+typedef struct async_addr_from_name
+{
+#if ASYNC_NETDB_USE_GAI
+ struct io_thread io;
+
+ int gai_error;
+ int errno_error;
+
+ struct addrinfo *res;
+#else
+ char dont_complain_about_empty_structs;
+#endif
+} *async_addr_from_name_t;
+
+async_addr_from_name_t async_addr_from_name_start (Display *dpy,
+ const char *host);
+/*
+ Starts an asynchronous address-from-name lookup.
+ dpy: An X11 display.
+ host: The hostname to look up.
+ Returns NULL if the request couldn't be created (due to low memory).
+ */
+
+#define async_addr_from_name_is_done(self) _async_netdb_is_done (&(self)->io)
+
+#if ASYNC_NETDB_USE_GAI
+void async_addr_from_name_cancel (async_addr_from_name_t self);
+#else
+# define async_addr_from_name_cancel(self) (thread_free (self));
+#endif
+
+/* sockaddr must be sizeof(async_netdb_sockaddr_storage_t) in size. */
+int async_addr_from_name_finish (async_addr_from_name_t self, void *addr,
+ socklen_t *addrlen, int *errno_error);
+/*
+ Returns the address from an asynchronous address-from-name operation. If
+ the lookup is still in progress, or the system can't do an asynchronous
+ lookup, this blocks. This cleans up the lookup operation; do not use 'self'
+ after calling this function.
+ self: The lookup operation.
+ addr: A sockaddr. This must be as large as or larger than
+ sizeof(async_netdb_sockaddr_storage_t). (Hint: just use an
+ instance of async_netdb_sockaddr_storage_t itself here.)
+ addrlen: The length of the obtained sockaddr.
+ errno_error: The value of errno if EAI_SYSTEM is returned. Can be NULL.
+ Returns 0 on success, or an error from getaddrinfo(3).
+ */
+
+#endif
+
+/* Local Variables: */
+/* mode: c */
+/* fill-column: 78 */
+/* c-file-style: "gnu" */
+/* c-basic-offset: 2 */
+/* indent-tabs-mode: nil */
+/* End: */
diff --git a/utils/bin2c b/utils/bin2c
new file mode 100755
index 0000000..7ed5e4c
--- /dev/null
+++ b/utils/bin2c
@@ -0,0 +1,46 @@
+#!/bin/sh
+# Copyright © 2018 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.
+#
+# Converts a binary file to a C source code string, e.g., to embed the
+# contents of a PNG file by including a .h file.
+#
+# Created: 7-Feb-2018.
+
+usage () {
+ echo "usage: $0 in.png out_png.h" >&2
+ exit 1
+}
+
+if [ $# != 2 ]; then usage; fi
+
+IN="$1"
+OUT="$2"
+
+NAME=`echo "$OUT" | sed \
+ -e 's@^.*/@@' \
+ -e 's/\.[^.]*$//' \
+ -e 's/[-.]/_/g' \
+ -e 's/^\([^a-z]\)/_\1/'`;
+
+if [ x"$PERL" = "x" ]; then PERL=perl ; fi
+
+# On Linux, we could do this and put the raw image into a .o data segment:
+# $(LD) -r -b binary $< -o $@
+# but that doesn't work on MacOS.
+
+exec $PERL -0 -pe "
+ BEGIN { print \"#ifdef __GNUC__\\n\";
+ print \"__extension__\\n\";
+ print \"#endif\\n\";
+ print \"static const unsigned char ${NAME}[] =\\n \\\"\"; }
+ END { print \"\\\";\\n\"; }
+ s/([^ -\041\043-\076\100-\133\135-\176])/sprintf(\"\\\\%03o\",ord(\$1))/gse;"\
+ < "$IN" > "$OUT"
diff --git a/utils/colorbars.c b/utils/colorbars.c
new file mode 100644
index 0000000..3e2bc87
--- /dev/null
+++ b/utils/colorbars.c
@@ -0,0 +1,130 @@
+/* xscreensaver, Copyright (c) 2001-2018 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.
+ */
+
+/* This file contains code for drawing NTSC colorbars.
+ A couple of things use this.
+ */
+
+#include "utils.h"
+#include "resources.h"
+#include "colorbars.h"
+#include "../hacks/ximage-loader.h"
+
+static const char * const colors[7][18] = {
+ { "#CCCCCC", "#FFFF00", "#00FFFF", "#00FF00", /* tall bars */
+ "#FF00FF", "#FF0000", "#0000FF", "#000000",
+ 0
+ }, {
+ "#000000", "#0000FF", "#FF0000", "#FF00FF", /* short rev bars */
+ "#00FF00", "#00FFFF", "#FFFF00", "#CCCCCC",
+ 0
+ }, {
+ "#000000", 0 /* blank */
+ }, {
+ "#FFFFFF", "#EEEEEE", "#DDDDDD", "#CCCCCC", /* gray ramp */
+ "#BBBBBB", "#AAAAAA", "#999999", "#888888",
+ "#777777", "#666666", "#555555", "#444444",
+ "#333333", "#222222", "#111111", "#000000"
+ }, {
+ "#000000", "#111111", "#222222", "#333333", /* gray rev ramp */
+ "#444444", "#555555", "#666666", "#777777",
+ "#888888", "#999999", "#AAAAAA", "#BBBBBB",
+ "#CCCCCC", "#DDDDDD", "#EEEEEE", "#FFFFFF"
+ }, {
+ "#000000", 0 /* blank */
+ }, {
+ "#FF00FF", "#FF00FF", "#FF00FF", /* blacklevel row */
+ "#FFFFFF", "#FFFFFF", "#FFFFFF",
+ "#0000AD", "#0000AD", "#0000AD",
+ "#131313", "#131313", "#131313",
+ "#000000", "#000000", "#262626",
+ "#000000", "#000000", "#000000"
+ }
+};
+
+static const int heights[7] = { 63, 10, 1, 5, 5, 1, 15 }; /* percentages */
+
+
+void
+draw_colorbars (Screen *screen, Visual *visual,
+ Drawable drawable, Colormap cmap,
+ int x, int y, int width, int height,
+ Pixmap logo, Pixmap logo_mask)
+{
+ Display *dpy = DisplayOfScreen (screen);
+ int ypct = 0;
+ int j;
+ XGCValues gcv;
+ GC gc = XCreateGC (dpy, drawable, 0, &gcv);
+
+ if (width <= 0 || height <= 0)
+ {
+ Window root;
+ int xx, yy;
+ unsigned int bw, d;
+ XGetGeometry (dpy, drawable,
+ &root, &xx, &yy,
+ (unsigned int *) &width,
+ (unsigned int *) &height,
+ &bw, &d);
+ }
+
+ for (j = 0; j < sizeof(colors) / sizeof(*colors); j++)
+ {
+ int i, h, ncols;
+ int x1 = 0;
+ int y2;
+ for (ncols = 0; ncols < sizeof(*colors) / sizeof(**colors); ncols++)
+ if (!colors[j][ncols]) break;
+ ypct += heights[j];
+ y2 = height * ypct / 100;
+ h = y2 - y; /* avoid roundoff fencepost */
+ for (i = 0; i < ncols; i++)
+ {
+ XColor xcolor;
+ const char *color = colors[j][i];
+ int x2 = x + (width * (i+1) / ncols);
+ int w = x2 - x1; /* avoid roundoff fencepost */
+ if (! XParseColor (dpy, cmap, color, &xcolor))
+ abort();
+ xcolor.flags = DoRed|DoGreen|DoBlue;
+ if (!XAllocColor (dpy, cmap, &xcolor))
+ continue;
+ XSetForeground (dpy, gc, xcolor.pixel);
+ XFillRectangle (dpy, drawable, gc, x1, y, w, h);
+ x1 = x2;
+ }
+ y = y2;
+ }
+
+ /* Add in the xscreensaver logo */
+ if (logo)
+ {
+ Window r;
+ int x, y;
+ unsigned int logo_width, logo_height, bw, d;
+ int x1, y1, w, h;
+ XGetGeometry (dpy, logo, &r, &x, &y, &logo_width, &logo_height, &bw, &d);
+ w = width;
+ h = height * heights[0] / 100;
+ x1 = x + (w - (int) logo_width) / 2;
+ y1 = y + (h - (int) logo_height) / 2;
+ if (logo_mask)
+ {
+ XSetClipMask (dpy, gc, logo_mask);
+ XSetClipOrigin (dpy, gc, x1, y1);
+ }
+ XCopyArea (dpy, logo, drawable, gc, 0, 0,
+ logo_width, logo_height, x1, y1);
+ }
+
+ XFreeGC(dpy, gc);
+}
diff --git a/utils/colorbars.h b/utils/colorbars.h
new file mode 100644
index 0000000..e7d9d81
--- /dev/null
+++ b/utils/colorbars.h
@@ -0,0 +1,25 @@
+/* xscreensaver, Copyright (c) 2001-2018 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 __COLORBARS_H__
+#define __COLORBARS_H__
+
+/* Renders colorbars (plus an xscreensaver logo) onto the
+ given Window or Pixmap. Width and height may be zero
+ (meaning "full size".)
+
+ Colors will be allocated from the cmap, and never freed.
+ */
+extern void draw_colorbars (Screen *, Visual *, Drawable, Colormap,
+ int x, int y, int width, int height,
+ Pixmap logo, Pixmap logo_mask);
+
+#endif /* __COLORBARS_H__ */
diff --git a/utils/colors.c b/utils/colors.c
new file mode 100644
index 0000000..e6abd48
--- /dev/null
+++ b/utils/colors.c
@@ -0,0 +1,732 @@
+/* xscreensaver, Copyright (c) 1997-2013 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.
+ */
+
+/* This file contains some utility routines for randomly picking the colors
+ to hack the screen with.
+ */
+
+#include "utils.h"
+#include "hsv.h"
+#include "yarandom.h"
+#include "visual.h"
+#include "colors.h"
+
+extern char *progname;
+
+void
+free_colors (Screen *screen, Colormap cmap, XColor *colors, int ncolors)
+{
+ Display *dpy = screen ? DisplayOfScreen (screen) : 0;
+ int i;
+ if (ncolors > 0)
+ {
+ unsigned long *pixels = (unsigned long *)
+ malloc(sizeof(*pixels) * ncolors);
+ for (i = 0; i < ncolors; i++)
+ pixels[i] = colors[i].pixel;
+ XFreeColors (dpy, cmap, pixels, ncolors, 0L);
+ free(pixels);
+ }
+}
+
+
+void
+allocate_writable_colors (Screen *screen, Colormap cmap,
+ unsigned long *pixels, int *ncolorsP)
+{
+ Display *dpy = screen ? DisplayOfScreen (screen) : 0;
+ int desired = *ncolorsP;
+ int got = 0;
+ int requested = desired;
+ unsigned long *new_pixels = pixels;
+
+ *ncolorsP = 0;
+ while (got < desired
+ && requested > 0)
+ {
+ if (desired - got < requested)
+ requested = desired - got;
+
+ if (XAllocColorCells (dpy, cmap, False, 0, 0, new_pixels, requested))
+ {
+ /* Got all the pixels we asked for. */
+ new_pixels += requested;
+ got += requested;
+ }
+ else
+ {
+ /* We didn't get all/any of the pixels we asked for. This time, ask
+ for half as many. (If we do get all that we ask for, we ask for
+ the same number again next time, so we only do O(log(n)) server
+ roundtrips.)
+ */
+ requested = requested / 2;
+ }
+ }
+ *ncolorsP += got;
+}
+
+
+static void
+complain (int wanted_colors, int got_colors,
+ Bool wanted_writable, Bool got_writable)
+{
+ if (got_colors > wanted_colors - 10)
+ /* don't bother complaining if we're within ten pixels. */
+ return;
+
+ if (wanted_writable && !got_writable)
+ fprintf (stderr,
+ "%s: wanted %d writable colors; got %d read-only colors.\n",
+ progname, wanted_colors, got_colors);
+ else
+ fprintf (stderr, "%s: wanted %d%s colors; got %d.\n",
+ progname, wanted_colors, (got_writable ? " writable" : ""),
+ got_colors);
+}
+
+
+
+void
+make_color_ramp (Screen *screen, Visual *visual, Colormap cmap,
+ int h1, double s1, double v1, /* 0-360, 0-1.0, 0-1.0 */
+ int h2, double s2, double v2, /* 0-360, 0-1.0, 0-1.0 */
+ XColor *colors, int *ncolorsP,
+ Bool closed_p,
+ Bool allocate_p,
+ Bool *writable_pP)
+{
+ Display *dpy = screen ? DisplayOfScreen (screen) : 0;
+ Bool verbose_p = True; /* argh. */
+ int i;
+ int total_ncolors = *ncolorsP;
+ int ncolors, wanted;
+ Bool wanted_writable = (allocate_p && writable_pP && *writable_pP);
+ double dh, ds, dv; /* deltas */
+
+ wanted = total_ncolors;
+ if (closed_p)
+ wanted = (wanted / 2) + 1;
+
+ /* If this visual doesn't support writable cells, don't bother trying.
+ */
+ if (wanted_writable && !has_writable_cells(screen, visual))
+ *writable_pP = False;
+
+ AGAIN:
+ ncolors = total_ncolors;
+
+ memset (colors, 0, (*ncolorsP) * sizeof(*colors));
+
+ if (closed_p)
+ ncolors = (ncolors / 2) + 1;
+
+ /* Note: unlike other routines in this module, this function assumes that
+ if h1 and h2 are more than 180 degrees apart, then the desired direction
+ is always from h1 to h2 (rather than the shorter path.) make_uniform
+ depends on this.
+ */
+ dh = ((double)h2 - (double)h1) / ncolors;
+ ds = (s2 - s1) / ncolors;
+ dv = (v2 - v1) / ncolors;
+
+ for (i = 0; i < ncolors; i++)
+ {
+ colors[i].flags = DoRed|DoGreen|DoBlue;
+ hsv_to_rgb ((int) (h1 + (i*dh)), (s1 + (i*ds)), (v1 + (i*dv)),
+ &colors[i].red, &colors[i].green, &colors[i].blue);
+ }
+
+ if (closed_p)
+ for (i = ncolors; i < *ncolorsP; i++)
+ colors[i] = colors[(*ncolorsP)-i];
+
+ if (!allocate_p)
+ return;
+
+ if (writable_pP && *writable_pP)
+ {
+ unsigned long *pixels = (unsigned long *)
+ malloc(sizeof(*pixels) * ((*ncolorsP) + 1));
+
+ /* allocate_writable_colors() won't do here, because we need exactly this
+ number of cells, or the color sequence we've chosen won't fit. */
+ if (! XAllocColorCells(dpy, cmap, False, 0, 0, pixels, *ncolorsP))
+ {
+ free(pixels);
+ goto FAIL;
+ }
+
+ for (i = 0; i < *ncolorsP; i++)
+ colors[i].pixel = pixels[i];
+ free (pixels);
+
+ XStoreColors (dpy, cmap, colors, *ncolorsP);
+ }
+ else
+ {
+ for (i = 0; i < *ncolorsP; i++)
+ {
+ XColor color;
+ color = colors[i];
+ if (XAllocColor (dpy, cmap, &color))
+ {
+ colors[i].pixel = color.pixel;
+ }
+ else
+ {
+ free_colors (screen, cmap, colors, i);
+ goto FAIL;
+ }
+ }
+ }
+
+ goto WARN;
+
+ FAIL:
+ /* we weren't able to allocate all the colors we wanted;
+ decrease the requested number and try again.
+ */
+ total_ncolors = (total_ncolors > 170 ? total_ncolors - 20 :
+ total_ncolors > 100 ? total_ncolors - 10 :
+ total_ncolors > 75 ? total_ncolors - 5 :
+ total_ncolors > 25 ? total_ncolors - 3 :
+ total_ncolors > 10 ? total_ncolors - 2 :
+ total_ncolors > 2 ? total_ncolors - 1 :
+ 0);
+ *ncolorsP = total_ncolors;
+ ncolors = total_ncolors;
+ if (total_ncolors > 0)
+ goto AGAIN;
+
+ WARN:
+
+ if (verbose_p &&
+ /* don't warn if we got 0 writable colors -- probably TrueColor. */
+ (ncolors != 0 || !wanted_writable))
+ complain (wanted, ncolors, wanted_writable,
+ (wanted_writable && writable_pP && *writable_pP));
+}
+
+
+#define MAXPOINTS 50 /* yeah, so I'm lazy */
+
+
+static void
+make_color_path (Screen *screen, Visual *visual, Colormap cmap,
+ int npoints, int *h, double *s, double *v,
+ XColor *colors, int *ncolorsP,
+ Bool allocate_p,
+ Bool *writable_pP)
+{
+ Display *dpy = screen ? DisplayOfScreen (screen) : 0;
+ int i, j, k;
+ int total_ncolors = *ncolorsP;
+
+ int ncolors[MAXPOINTS]; /* number of pixels per edge */
+ double dh[MAXPOINTS]; /* distance between pixels, per edge (0 - 360.0) */
+ double ds[MAXPOINTS]; /* distance between pixels, per edge (0 - 1.0) */
+ double dv[MAXPOINTS]; /* distance between pixels, per edge (0 - 1.0) */
+
+ if (npoints == 0)
+ {
+ *ncolorsP = 0;
+ return;
+ }
+ else if (npoints == 2) /* using make_color_ramp() will be faster */
+ {
+ make_color_ramp (screen, visual, cmap,
+ h[0], s[0], v[0], h[1], s[1], v[1],
+ colors, ncolorsP,
+ True, /* closed_p */
+ allocate_p, writable_pP);
+ return;
+ }
+ else if (npoints >= MAXPOINTS)
+ {
+ npoints = MAXPOINTS-1;
+ }
+
+ AGAIN:
+
+ {
+ double DH[MAXPOINTS]; /* Distance between H values in the shortest
+ direction around the circle, that is, the
+ distance between 10 and 350 is 20.
+ (Range is 0 - 360.0.)
+ */
+ double edge[MAXPOINTS]; /* lengths of edges in unit HSV space. */
+ double ratio[MAXPOINTS]; /* proportions of the edges (total 1.0) */
+ double circum = 0;
+ double one_point_oh = 0; /* (debug) */
+
+ for (i = 0; i < npoints; i++)
+ {
+ int j = (i+1) % npoints;
+ double d = ((double) (h[i] - h[j])) / 360;
+ if (d < 0) d = -d;
+ if (d > 0.5) d = 0.5 - (d - 0.5);
+ DH[i] = d;
+ }
+
+ for (i = 0; i < npoints; i++)
+ {
+ int j = (i+1) % npoints;
+ edge[i] = sqrt((DH[i] * DH[j]) +
+ ((s[j] - s[i]) * (s[j] - s[i])) +
+ ((v[j] - v[i]) * (v[j] - v[i])));
+ circum += edge[i];
+ }
+
+#ifdef DEBUG
+ fprintf(stderr, "\ncolors:");
+ for (i=0; i < npoints; i++)
+ fprintf(stderr, " (%d, %.3f, %.3f)", h[i], s[i], v[i]);
+ fprintf(stderr, "\nlengths:");
+ for (i=0; i < npoints; i++)
+ fprintf(stderr, " %.3f", edge[i]);
+#endif /* DEBUG */
+
+ if (circum < 0.0001)
+ goto FAIL;
+
+ for (i = 0; i < npoints; i++)
+ {
+ ratio[i] = edge[i] / circum;
+ one_point_oh += ratio[i];
+ }
+
+#ifdef DEBUG
+ fprintf(stderr, "\nratios:");
+ for (i=0; i < npoints; i++)
+ fprintf(stderr, " %.3f", ratio[i]);
+#endif /* DEBUG */
+
+ if (one_point_oh < 0.99999 || one_point_oh > 1.00001)
+ abort();
+
+ /* space the colors evenly along the circumference -- that means that the
+ number of pixels on a edge is proportional to the length of that edge
+ (relative to the lengths of the other edges.)
+ */
+ for (i = 0; i < npoints; i++)
+ ncolors[i] = total_ncolors * ratio[i];
+
+
+#ifdef DEBUG
+ fprintf(stderr, "\npixels:");
+ for (i=0; i < npoints; i++)
+ fprintf(stderr, " %d", ncolors[i]);
+ fprintf(stderr, " (%d)\n", total_ncolors);
+#endif /* DEBUG */
+
+ for (i = 0; i < npoints; i++)
+ {
+ int j = (i+1) % npoints;
+
+ if (ncolors[i] > 0)
+ {
+ dh[i] = 360 * (DH[i] / ncolors[i]);
+ ds[i] = (s[j] - s[i]) / ncolors[i];
+ dv[i] = (v[j] - v[i]) / ncolors[i];
+ }
+ }
+ }
+
+ memset (colors, 0, (*ncolorsP) * sizeof(*colors));
+
+ k = 0;
+ for (i = 0; i < npoints; i++)
+ {
+ int distance = h[(i+1) % npoints] - h[i];
+ int direction = (distance >= 0 ? -1 : 1);
+
+ if (distance <= 180 && distance >= -180)
+ direction = -direction;
+
+#ifdef DEBUG
+ fprintf (stderr, "point %d: %3d %.2f %.2f\n",
+ i, h[i], s[i], v[i]);
+ fprintf(stderr, " h[i]=%d dh[i]=%.2f ncolors[i]=%d\n",
+ h[i], dh[i], ncolors[i]);
+#endif /* DEBUG */
+ for (j = 0; j < ncolors[i]; j++, k++)
+ {
+ double hh = (h[i] + (j * dh[i] * direction));
+ if (hh < 0) hh += 360;
+ else if (hh > 360) hh -= 0;
+ colors[k].flags = DoRed|DoGreen|DoBlue;
+ hsv_to_rgb ((int)
+ hh,
+ (s[i] + (j * ds[i])),
+ (v[i] + (j * dv[i])),
+ &colors[k].red, &colors[k].green, &colors[k].blue);
+#ifdef DEBUG
+ fprintf (stderr, "point %d+%d: %.2f %.2f %.2f %04X %04X %04X\n",
+ i, j,
+ hh,
+ (s[i] + (j * ds[i])),
+ (v[i] + (j * dv[i])),
+ colors[k].red, colors[k].green, colors[k].blue);
+#endif /* DEBUG */
+ }
+ }
+
+ /* Floating-point round-off can make us decide to use fewer colors. */
+ if (k < *ncolorsP)
+ {
+ *ncolorsP = k;
+ if (k <= 0)
+ return;
+ }
+
+ if (!allocate_p)
+ return;
+
+ if (writable_pP && *writable_pP)
+ {
+ unsigned long *pixels = (unsigned long *)
+ malloc(sizeof(*pixels) * ((*ncolorsP) + 1));
+
+ /* allocate_writable_colors() won't do here, because we need exactly this
+ number of cells, or the color sequence we've chosen won't fit. */
+ if (! XAllocColorCells(dpy, cmap, False, 0, 0, pixels, *ncolorsP))
+ {
+ free(pixels);
+ goto FAIL;
+ }
+
+ for (i = 0; i < *ncolorsP; i++)
+ colors[i].pixel = pixels[i];
+ free (pixels);
+
+ XStoreColors (dpy, cmap, colors, *ncolorsP);
+ }
+ else
+ {
+ for (i = 0; i < *ncolorsP; i++)
+ {
+ XColor color;
+ color = colors[i];
+ if (XAllocColor (dpy, cmap, &color))
+ {
+ colors[i].pixel = color.pixel;
+ }
+ else
+ {
+ free_colors (screen, cmap, colors, i);
+ goto FAIL;
+ }
+ }
+ }
+
+ return;
+
+ FAIL:
+ /* we weren't able to allocate all the colors we wanted;
+ decrease the requested number and try again.
+ */
+ total_ncolors = (total_ncolors > 170 ? total_ncolors - 20 :
+ total_ncolors > 100 ? total_ncolors - 10 :
+ total_ncolors > 75 ? total_ncolors - 5 :
+ total_ncolors > 25 ? total_ncolors - 3 :
+ total_ncolors > 10 ? total_ncolors - 2 :
+ total_ncolors > 2 ? total_ncolors - 1 :
+ 0);
+ *ncolorsP = total_ncolors;
+ if (total_ncolors > 0)
+ goto AGAIN;
+}
+
+
+void
+make_color_loop (Screen *screen, Visual *visual, Colormap cmap,
+ int h0, double s0, double v0, /* 0-360, 0-1.0, 0-1.0 */
+ int h1, double s1, double v1, /* 0-360, 0-1.0, 0-1.0 */
+ int h2, double s2, double v2, /* 0-360, 0-1.0, 0-1.0 */
+ XColor *colors, int *ncolorsP,
+ Bool allocate_p,
+ Bool *writable_pP)
+{
+ Bool wanted_writable = (allocate_p && writable_pP && *writable_pP);
+
+ int h[3];
+ double s[3], v[3];
+ h[0] = h0; h[1] = h1; h[2] = h2;
+ s[0] = s0; s[1] = s1; s[2] = s2;
+ v[0] = v0; v[1] = v1; v[2] = v2;
+
+ /* If this visual doesn't support writable cells, don't bother trying.
+ */
+ if (wanted_writable && !has_writable_cells(screen, visual))
+ *writable_pP = False;
+
+ make_color_path (screen, visual, cmap,
+ 3, h, s, v,
+ colors, ncolorsP,
+ allocate_p, writable_pP);
+}
+
+
+void
+make_smooth_colormap (Screen *screen, Visual *visual, Colormap cmap,
+ XColor *colors, int *ncolorsP,
+ Bool allocate_p,
+ Bool *writable_pP,
+ Bool verbose_p)
+{
+ int npoints;
+ int ncolors = *ncolorsP;
+ Bool wanted_writable = (allocate_p && writable_pP && *writable_pP);
+ int i;
+ int h[MAXPOINTS];
+ double s[MAXPOINTS];
+ double v[MAXPOINTS];
+ double total_s = 0;
+ double total_v = 0;
+ int loop = 0;
+
+ if (*ncolorsP <= 0) return;
+
+ {
+ int n = random() % 20;
+ if (n <= 5) npoints = 2; /* 30% of the time */
+ else if (n <= 15) npoints = 3; /* 50% of the time */
+ else if (n <= 18) npoints = 4; /* 15% of the time */
+ else npoints = 5; /* 5% of the time */
+ }
+
+ REPICK_ALL_COLORS:
+ for (i = 0; i < npoints; i++)
+ {
+ REPICK_THIS_COLOR:
+ if (++loop > 10000) abort();
+ h[i] = random() % 360;
+ s[i] = frand(1.0);
+ v[i] = frand(0.8) + 0.2;
+
+ /* Make sure that no two adjascent colors are *too* close together.
+ If they are, try again.
+ */
+ if (i > 0)
+ {
+ int j = (i+1 == npoints) ? 0 : (i-1);
+ double hi = ((double) h[i]) / 360;
+ double hj = ((double) h[j]) / 360;
+ double dh = hj - hi;
+ double distance;
+ if (dh < 0) dh = -dh;
+ if (dh > 0.5) dh = 0.5 - (dh - 0.5);
+ distance = sqrt ((dh * dh) +
+ ((s[j] - s[i]) * (s[j] - s[i])) +
+ ((v[j] - v[i]) * (v[j] - v[i])));
+ if (distance < 0.2)
+ goto REPICK_THIS_COLOR;
+ }
+ total_s += s[i];
+ total_v += v[i];
+ }
+
+ /* If the average saturation or intensity are too low, repick the colors,
+ so that we don't end up with a black-and-white or too-dark map.
+ */
+ if (total_s / npoints < 0.2)
+ goto REPICK_ALL_COLORS;
+ if (total_v / npoints < 0.3)
+ goto REPICK_ALL_COLORS;
+
+ /* If this visual doesn't support writable cells, don't bother trying.
+ */
+ if (wanted_writable && !has_writable_cells(screen, visual))
+ *writable_pP = False;
+
+ RETRY_NON_WRITABLE:
+ make_color_path (screen, visual, cmap, npoints, h, s, v, colors, &ncolors,
+ allocate_p, writable_pP);
+
+ /* If we tried for writable cells and got none, try for non-writable. */
+ if (allocate_p && *ncolorsP == 0 && writable_pP && *writable_pP)
+ {
+ *writable_pP = False;
+ goto RETRY_NON_WRITABLE;
+ }
+
+ if (verbose_p)
+ complain(*ncolorsP, ncolors, wanted_writable,
+ wanted_writable && *writable_pP);
+
+ *ncolorsP = ncolors;
+}
+
+
+void
+make_uniform_colormap (Screen *screen, Visual *visual, Colormap cmap,
+ XColor *colors, int *ncolorsP,
+ Bool allocate_p,
+ Bool *writable_pP,
+ Bool verbose_p)
+{
+ int ncolors = *ncolorsP;
+ Bool wanted_writable = (allocate_p && writable_pP && *writable_pP);
+
+ double S = ((double) (random() % 34) + 66) / 100.0; /* range 66%-100% */
+ double V = ((double) (random() % 34) + 66) / 100.0; /* range 66%-100% */
+
+ if (*ncolorsP <= 0) return;
+
+ /* If this visual doesn't support writable cells, don't bother trying. */
+ if (wanted_writable && !has_writable_cells(screen, visual))
+ *writable_pP = False;
+
+ RETRY_NON_WRITABLE:
+ make_color_ramp(screen, visual, cmap,
+ 0, S, V,
+ 359, S, V,
+ colors, &ncolors,
+ False, allocate_p, writable_pP);
+
+ /* If we tried for writable cells and got none, try for non-writable. */
+ if (allocate_p && *ncolorsP == 0 && writable_pP && *writable_pP)
+ {
+ ncolors = *ncolorsP;
+ *writable_pP = False;
+ goto RETRY_NON_WRITABLE;
+ }
+
+ if (verbose_p)
+ complain(*ncolorsP, ncolors, wanted_writable,
+ wanted_writable && *writable_pP);
+
+ *ncolorsP = ncolors;
+}
+
+
+void
+make_random_colormap (Screen *screen, Visual *visual, Colormap cmap,
+ XColor *colors, int *ncolorsP,
+ Bool bright_p,
+ Bool allocate_p,
+ Bool *writable_pP,
+ Bool verbose_p)
+{
+ Display *dpy = screen ? DisplayOfScreen (screen) : 0;
+ Bool wanted_writable = (allocate_p && writable_pP && *writable_pP);
+ int ncolors = *ncolorsP;
+ int i;
+
+ if (*ncolorsP <= 0) return;
+
+ /* If this visual doesn't support writable cells, don't bother trying. */
+ if (wanted_writable && !has_writable_cells(screen, visual))
+ *writable_pP = False;
+
+ RETRY_ALL:
+ for (i = 0; i < ncolors; i++)
+ {
+ colors[i].flags = DoRed|DoGreen|DoBlue;
+ if (bright_p)
+ {
+ int H = random() % 360; /* range 0-360 */
+ double S = ((double) (random()%70) + 30)/100.0; /* range 30%-100% */
+ double V = ((double) (random()%34) + 66)/100.0; /* range 66%-100% */
+ hsv_to_rgb (H, S, V,
+ &colors[i].red, &colors[i].green, &colors[i].blue);
+ }
+ else
+ {
+ colors[i].red = random() % 0xFFFF;
+ colors[i].green = random() % 0xFFFF;
+ colors[i].blue = random() % 0xFFFF;
+ }
+ }
+
+ /* If there are a small number of colors, make sure at least the first
+ two contrast well.
+ */
+ if (!bright_p && ncolors <= 4)
+ {
+ int h0, h1;
+ double s0, s1, v0, v1;
+ rgb_to_hsv (colors[0].red, colors[0].green, colors[0].blue, &h0,&s0,&v0);
+ rgb_to_hsv (colors[1].red, colors[1].green, colors[1].blue, &h1,&s1,&v1);
+ if (fabs (v1-v0) < 0.5)
+ goto RETRY_ALL;
+ }
+
+ if (!allocate_p)
+ return;
+
+ RETRY_NON_WRITABLE:
+ if (writable_pP && *writable_pP)
+ {
+ unsigned long *pixels = (unsigned long *)
+ malloc(sizeof(*pixels) * (ncolors + 1));
+
+ allocate_writable_colors (screen, cmap, pixels, &ncolors);
+ if (ncolors > 0)
+ for (i = 0; i < ncolors; i++)
+ colors[i].pixel = pixels[i];
+ free (pixels);
+ if (ncolors > 0)
+ XStoreColors (dpy, cmap, colors, ncolors);
+ }
+ else
+ {
+ for (i = 0; i < ncolors; i++)
+ {
+ XColor color;
+ color = colors[i];
+ if (!XAllocColor (dpy, cmap, &color))
+ break;
+ colors[i].pixel = color.pixel;
+ }
+ ncolors = i;
+ }
+
+ /* If we tried for writable cells and got none, try for non-writable. */
+ if (allocate_p && ncolors == 0 && writable_pP && *writable_pP)
+ {
+ ncolors = *ncolorsP;
+ *writable_pP = False;
+ goto RETRY_NON_WRITABLE;
+ }
+
+ if (verbose_p)
+ complain(*ncolorsP, ncolors, wanted_writable,
+ wanted_writable && *writable_pP);
+
+ *ncolorsP = ncolors;
+}
+
+
+void
+rotate_colors (Screen *screen, Colormap cmap,
+ XColor *colors, int ncolors, int distance)
+{
+ Display *dpy = screen ? DisplayOfScreen (screen) : 0;
+ int i;
+ XColor *colors2;
+ if (ncolors < 2) return;
+ colors2 = (XColor *) malloc(sizeof(*colors2) * ncolors);
+ distance = distance % ncolors;
+ for (i = 0; i < ncolors; i++)
+ {
+ int j = i - distance;
+ if (j >= ncolors) j -= ncolors;
+ if (j < 0) j += ncolors;
+ colors2[i] = colors[j];
+ colors2[i].pixel = colors[i].pixel;
+ }
+ XStoreColors (dpy, cmap, colors2, ncolors);
+ XFlush(dpy);
+ memcpy(colors, colors2, sizeof(*colors) * ncolors);
+ free(colors2);
+}
diff --git a/utils/colors.h b/utils/colors.h
new file mode 100644
index 0000000..526a38a
--- /dev/null
+++ b/utils/colors.h
@@ -0,0 +1,147 @@
+/* xscreensaver, Copyright (c) 1992-2013 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 __COLORS_H__
+#define __COLORS_H__
+
+/* Like XFreeColors, but works on `XColor *' instead of `unsigned long *'
+ */
+extern void free_colors (Screen *, Colormap, XColor *, int ncolors);
+
+
+/* Allocates writable, non-contiguous color cells. The number requested is
+ passed in *ncolorsP, and the number actually allocated is returned there.
+ (Unlike XAllocColorCells(), this will allocate as many as it can, instead
+ of failing if they can't all be allocated.)
+ */
+extern void allocate_writable_colors (Screen *, Colormap,
+ unsigned long *pixels, int *ncolorsP);
+
+
+/* Generates a sequence of colors evenly spaced between the given pair
+ of HSV coordinates.
+
+ If closed_p is true, the colors will go from the first point to the
+ second then back to the first.
+
+ If allocate_p is true, the colors will be allocated from the map;
+ if enough colors can't be allocated, we will try for less, and the
+ result will be returned to ncolorsP.
+
+ If writable_p is true, writable color cells will be allocated;
+ otherwise, read-only cells will be allocated.
+
+ If allocate_p is false, screen and cmap are unused (OpenGL usage).
+ */
+extern void make_color_ramp (Screen *, Visual *, Colormap,
+ int h1, double s1, double v1,
+ int h2, double s2, double v2,
+ XColor *colors, int *ncolorsP,
+ Bool closed_p,
+ Bool allocate_p,
+ Bool *writable_pP);
+
+/* Generates a sequence of colors evenly spaced around the triangle
+ indicated by the thee HSV coordinates.
+
+ If allocate_p is true, the colors will be allocated from the map;
+ if enough colors can't be allocated, we will try for less, and the
+ result will be returned to ncolorsP.
+
+ If writable_p is true, writable color cells will be allocated;
+ otherwise, read-only cells will be allocated.
+
+ If allocate_p is false, screen, visual and cmap are unused (OpenGL usage).
+ */
+extern void make_color_loop (Screen *, Visual *, Colormap,
+ int h1, double s1, double v1,
+ int h2, double s2, double v2,
+ int h3, double s3, double v3,
+ XColor *colors, int *ncolorsP,
+ Bool allocate_p,
+ Bool *writable_pP);
+
+
+/* Allocates a hopefully-interesting colormap, which will be a closed loop
+ without any sudden transitions.
+
+ If allocate_p is true, the colors will be allocated from the map;
+ if enough colors can't be allocated, we will try for less, and the
+ result will be returned to ncolorsP. An error message will be
+ printed on stderr (if verbose_p).
+
+ If *writable_pP is true, writable color cells will be allocated;
+ otherwise, read-only cells will be allocated. If no writable cells
+ cannot be allocated, we will try to allocate unwritable cells
+ instead, and print a message on stderr to that effect (if verbose_p).
+
+ If allocate_p is false, screen, visual and cmap are unused (OpenGL usage).
+ */
+extern void make_smooth_colormap (Screen *, Visual *, Colormap,
+ XColor *colors, int *ncolorsP,
+ Bool allocate_p,
+ Bool *writable_pP,
+ Bool verbose_p);
+
+/* Allocates a uniform colormap which touches each hue of the spectrum,
+ evenly spaced. The saturation and intensity are chosen randomly, but
+ will be high enough to be visible.
+
+ If allocate_p is true, the colors will be allocated from the map;
+ if enough colors can't be allocated, we will try for less, and the
+ result will be returned to ncolorsP. An error message will be
+ printed on stderr (if verbose_p).
+
+ If *writable_pP is true, writable color cells will be allocated;
+ otherwise, read-only cells will be allocated. If no writable cells
+ cannot be allocated, we will try to allocate unwritable cells
+ instead, and print a message on stderr to that effect (if verbose_p).
+
+ If allocate_p is false, screen, visual and cmap are unused (OpenGL usage).
+ */
+extern void make_uniform_colormap (Screen *, Visual *, Colormap,
+ XColor *colors, int *ncolorsP,
+ Bool allocate_p,
+ Bool *writable_pP,
+ Bool verbose_p);
+
+/* Allocates a random colormap (the colors are unrelated to one another.)
+ If `bright_p' is false, the colors will be completely random; if it is
+ true, all of the colors will be bright enough to see on a black background.
+
+ If allocate_p is true, the colors will be allocated from the map;
+ if enough colors can't be allocated, we will try for less, and the
+ result will be returned to ncolorsP. An error message will be
+ printed on stderr (if verbose_p).
+
+ If *writable_pP is true, writable color cells will be allocated;
+ otherwise, read-only cells will be allocated. If no writable cells
+ cannot be allocated, we will try to allocate unwritable cells
+ instead, and print a message on stderr to that effect (if verbose_p).
+
+ If allocate_p is false, screen, visual and cmap are unused (OpenGL usage).
+ */
+extern void make_random_colormap (Screen *, Visual *, Colormap,
+ XColor *colors, int *ncolorsP,
+ Bool bright_p,
+ Bool allocate_p,
+ Bool *writable_pP,
+ Bool verbose_p);
+
+
+/* Assuming that the array of colors indicates the current state of a set
+ of writable color cells, this rotates the contents of the array by
+ `distance' steps, moving the colors of cell N to cell (N - distance).
+ */
+extern void rotate_colors (Screen *, Colormap,
+ XColor *, int ncolors, int distance);
+
+#endif /* __COLORS_H__ */
diff --git a/utils/compile_axp.com b/utils/compile_axp.com
new file mode 100644
index 0000000..d205d8b
--- /dev/null
+++ b/utils/compile_axp.com
@@ -0,0 +1,34 @@
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) ALIGNED_MALLOC.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) ALPHA.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) ASYNC_NETDB.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) COLORBARS.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) COLORS.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) ERASE.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) FADE.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) FONT-RETRY.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) GRABCLIENT.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) GRABSCREEN.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) HSV.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) LOGO.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) MINIXPM.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) OVERLAY.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) POW2.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) RESOURCES.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) SPLINE.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) TEXTCLIENT.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) TEXTCLIENT-MOBILE.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) THREAD_UTIL.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) USLEEP.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) UTF8WC.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) VISUAL.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) VISUAL-GL.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) VMS-GTOD.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) VMS-STRDUP.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) XDBE.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) XFT.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) XMU.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) XSHM.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) YARANDOM.C
+$ lib/cre utils.olb_axp
+$ lib utils.olb_axp *.obj
+$! delete/noconf *.obj;
diff --git a/utils/compile_decc.com b/utils/compile_decc.com
new file mode 100644
index 0000000..c80f303
--- /dev/null
+++ b/utils/compile_decc.com
@@ -0,0 +1,34 @@
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) ALIGNED_MALLOC.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) ALPHA.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) ASYNC_NETDB.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) COLORBARS.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) COLORS.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) ERASE.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) FADE.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) FONT-RETRY.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) GRABCLIENT.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) GRABSCREEN.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) HSV.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) LOGO.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) MINIXPM.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) OVERLAY.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) POW2.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) RESOURCES.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) SPLINE.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) TEXTCLIENT.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) TEXTCLIENT-MOBILE.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) THREAD_UTIL.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) USLEEP.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) UTF8WC.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) VISUAL.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) VISUAL-GL.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) VMS-GTOD.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) VMS-STRDUP.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) XDBE.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) XFT.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) XMU.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) XSHM.C
+$ CC/DECC/PREFIX=ALL/DEFINE=(VMS,HAVE_CONFIG_H)/INCL=([],[-]) YARANDOM.C
+$ lib/cre utils.olb_decc
+$ lib utils.olb_decc *.obj
+$! delete/noconf *.obj;
diff --git a/utils/erase.c b/utils/erase.c
new file mode 100644
index 0000000..ae15ac8
--- /dev/null
+++ b/utils/erase.c
@@ -0,0 +1,811 @@
+/* erase.c: Erase the screen in various more or less interesting ways.
+ * Copyright (c) 1997-2008 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.
+ *
+ * Portions (c) 1997 by Johannes Keukelaar <johannes@nada.kth.se>:
+ * Permission to use in any way granted. Provided "as is" without expressed
+ * or implied warranty. NO WARRANTY, NO EXPRESSION OF SUITABILITY FOR ANY
+ * PURPOSE. (I.e.: Use in any way, but at your own risk!)
+ */
+
+#include "utils.h"
+#include "yarandom.h"
+#include "usleep.h"
+#include "resources.h"
+#include "erase.h"
+#include <sys/time.h> /* for gettimeofday() */
+
+extern char *progname;
+
+#undef countof
+#define countof(x) (sizeof(x)/sizeof(*(x)))
+
+typedef void (*Eraser) (eraser_state *);
+
+struct eraser_state {
+ Display *dpy;
+ Window window;
+ GC fg_gc, bg_gc;
+ int width, height;
+ Eraser fn;
+
+ double start_time, stop_time;
+ double ratio, prev_ratio;
+
+ /* data for random_lines, venetian, random_squares */
+ Bool horiz_p;
+ Bool flip_p;
+ int nlines, *lines;
+
+ /* data for triple_wipe, quad_wipe */
+ Bool flip_x, flip_y;
+
+ /* data for circle_wipe, three_circle_wipe */
+ int start;
+
+ /* data for random_squares */
+ int cols;
+
+ /* data for fizzle */
+ unsigned short *fizzle_rnd;
+
+};
+
+
+static double
+double_time (void)
+{
+ struct timeval now;
+# ifdef GETTIMEOFDAY_TWO_ARGS
+ struct timezone tzp;
+ gettimeofday(&now, &tzp);
+# else
+ gettimeofday(&now);
+# endif
+
+ return (now.tv_sec + ((double) now.tv_usec * 0.000001));
+}
+
+
+static void
+random_lines (eraser_state *st)
+{
+ int i;
+
+ if (! st->lines) /* first time */
+ {
+ st->horiz_p = (random() & 1);
+ st->nlines = (st->horiz_p ? st->height : st->width);
+ st->lines = (int *) calloc (st->nlines, sizeof(*st->lines));
+
+ for (i = 0; i < st->nlines; i++) /* every line */
+ st->lines[i] = i;
+
+ for (i = 0; i < st->nlines; i++) /* shuffle */
+ {
+ int t, r;
+ t = st->lines[i];
+ r = random() % st->nlines;
+ st->lines[i] = st->lines[r];
+ st->lines[r] = t;
+ }
+ }
+
+ for (i = st->nlines * st->prev_ratio;
+ i < st->nlines * st->ratio;
+ i++)
+ {
+ if (st->horiz_p)
+ XDrawLine (st->dpy, st->window, st->bg_gc,
+ 0, st->lines[i], st->width, st->lines[i]);
+ else
+ XDrawLine (st->dpy, st->window, st->bg_gc,
+ st->lines[i], 0, st->lines[i], st->height);
+ }
+
+ if (st->ratio >= 1.0)
+ {
+ free (st->lines);
+ st->lines = 0;
+ }
+}
+
+
+static void
+venetian (eraser_state *st)
+{
+ int i;
+ if (st->ratio == 0.0)
+ {
+ int j = 0;
+ st->horiz_p = (random() & 1);
+ st->flip_p = (random() & 1);
+ st->nlines = (st->horiz_p ? st->height : st->width);
+ st->lines = (int *) calloc (st->nlines, sizeof(*st->lines));
+
+ for (i = 0; i < st->nlines * 2; i++)
+ {
+ int line = ((i / 16) * 16) - ((i % 16) * 15);
+ if (line >= 0 && line < st->nlines)
+ st->lines[j++] = (st->flip_p ? st->nlines - line : line);
+ }
+ }
+
+
+ for (i = st->nlines * st->prev_ratio;
+ i < st->nlines * st->ratio;
+ i++)
+ {
+ if (st->horiz_p)
+ XDrawLine (st->dpy, st->window, st->bg_gc,
+ 0, st->lines[i], st->width, st->lines[i]);
+ else
+ XDrawLine (st->dpy, st->window, st->bg_gc,
+ st->lines[i], 0, st->lines[i], st->height);
+ }
+
+ if (st->ratio >= 1.0)
+ {
+ free (st->lines);
+ st->lines = 0;
+ }
+}
+
+
+static void
+triple_wipe (eraser_state *st)
+{
+ int i;
+ if (st->ratio == 0.0)
+ {
+ st->flip_x = random() & 1;
+ st->flip_y = random() & 1;
+ st->nlines = st->width + (st->height / 2);
+ st->lines = (int *) calloc (st->nlines, sizeof(*st->lines));
+
+ for (i = 0; i < st->width / 2; i++)
+ st->lines[i] = i * 2 + st->height;
+ for (i = 0; i < st->height / 2; i++)
+ st->lines[i + st->width / 2] = i*2;
+ for (i = 0; i < st->width / 2; i++)
+ st->lines[i + st->width / 2 + st->height / 2] =
+ st->width - i * 2 - (st->width % 2 ? 0 : 1) + st->height;
+ }
+
+ for (i = st->nlines * st->prev_ratio;
+ i < st->nlines * st->ratio;
+ i++)
+ {
+ int x, y, x2, y2;
+
+ if (st->lines[i] < st->height)
+ x = 0, y = st->lines[i], x2 = st->width, y2 = y;
+ else
+ x = st->lines[i]-st->height, y = 0, x2 = x, y2 = st->height;
+
+ if (st->flip_x)
+ x = st->width - x, x2 = st->width - x2;
+ if (st->flip_y)
+ y = st->height - y, y2 = st->height - y2;
+
+ XDrawLine (st->dpy, st->window, st->bg_gc, x, y, x2, y2);
+ }
+
+ if (st->ratio >= 1.0)
+ {
+ free (st->lines);
+ st->lines = 0;
+ }
+}
+
+
+static void
+quad_wipe (eraser_state *st)
+{
+ int i;
+ if (st->ratio == 0.0)
+ {
+ st->flip_x = random() & 1;
+ st->flip_y = random() & 1;
+ st->nlines = st->width + st->height;
+ st->lines = (int *) calloc (st->nlines, sizeof(*st->lines));
+
+ for (i = 0; i < st->nlines/4; i++)
+ {
+ st->lines[i*4] = i*2;
+ st->lines[i*4+1] = st->height - i*2 - (st->height % 2 ? 0 : 1);
+ st->lines[i*4+2] = st->height + i*2;
+ st->lines[i*4+3] = st->height + st->width - i*2
+ - (st->width % 2 ? 0 : 1);
+ }
+ }
+
+ for (i = st->nlines * st->prev_ratio;
+ i < st->nlines * st->ratio;
+ i++)
+ {
+ int x, y, x2, y2;
+ if (st->lines[i] < st->height)
+ x = 0, y = st->lines[i], x2 = st->width, y2 = y;
+ else
+ x = st->lines[i] - st->height, y = 0, x2 = x, y2 = st->height;
+
+ if (st->flip_x)
+ x = st->width-x, x2 = st->width-x2;
+ if (st->flip_y)
+ y = st->height-y, y2 = st->height-y2;
+
+ XDrawLine (st->dpy, st->window, st->bg_gc, x, y, x2, y2);
+ }
+
+ if (st->ratio >= 1.0)
+ {
+ free (st->lines);
+ st->lines = 0;
+ }
+}
+
+
+static void
+circle_wipe (eraser_state *st)
+{
+ int rad = (st->width > st->height ? st->width : st->height);
+ int max = 360 * 64;
+ int th, oth;
+
+ if (st->ratio == 0.0)
+ {
+ st->flip_p = random() & 1;
+ st->start = random() % max;
+ }
+
+ th = max * st->ratio;
+ oth = max * st->prev_ratio;
+ if (st->flip_p)
+ {
+ th = max - th;
+ oth = max - oth;
+ }
+ XFillArc (st->dpy, st->window, st->bg_gc,
+ (st->width / 2) - rad,
+ (st->height / 2) - rad,
+ rad*2, rad*2,
+ (st->start + oth) % max,
+ th-oth);
+}
+
+
+static void
+three_circle_wipe (eraser_state *st)
+{
+ int rad = (st->width > st->height ? st->width : st->height);
+ int max = 360 * 64;
+ int th, oth;
+ int i;
+
+ if (st->ratio == 0.0)
+ st->start = random() % max;
+
+ th = max/6 * st->ratio;
+ oth = max/6 * st->prev_ratio;
+
+ for (i = 0; i < 3; i++)
+ {
+ int off = i * max / 3;
+ XFillArc (st->dpy, st->window, st->bg_gc,
+ (st->width / 2) - rad,
+ (st->height / 2) - rad,
+ rad*2, rad*2,
+ (st->start + off + oth) % max,
+ th-oth);
+ XFillArc (st->dpy, st->window, st->bg_gc,
+ (st->width / 2) - rad,
+ (st->height / 2) - rad,
+ rad*2, rad*2,
+ (st->start + off - oth) % max,
+ oth-th);
+ }
+}
+
+
+static void
+squaretate (eraser_state *st)
+{
+ int max = ((st->width > st->height ? st->width : st->height) * 2);
+ XPoint points [3];
+ int i = max * st->ratio;
+
+ if (st->ratio == 0.0)
+ st->flip_p = random() & 1;
+
+# define DRAW() \
+ if (st->flip_p) { \
+ points[0].x = st->width - points[0].x; \
+ points[1].x = st->width - points[1].x; \
+ points[2].x = st->width - points[2].x; \
+ } \
+ XFillPolygon (st->dpy, st->window, st->bg_gc, \
+ points, 3, Convex, CoordModeOrigin)
+
+ points[0].x = 0;
+ points[0].y = 0;
+ points[1].x = st->width;
+ points[1].y = 0;
+ points[2].x = 0;
+ points[2].y = points[0].y + ((i * st->height) / max);
+ DRAW();
+
+ points[0].x = 0;
+ points[0].y = 0;
+ points[1].x = 0;
+ points[1].y = st->height;
+ points[2].x = ((i * st->width) / max);
+ points[2].y = st->height;
+ DRAW();
+
+ points[0].x = st->width;
+ points[0].y = st->height;
+ points[1].x = 0;
+ points[1].y = st->height;
+ points[2].x = st->width;
+ points[2].y = st->height - ((i * st->height) / max);
+ DRAW();
+
+ points[0].x = st->width;
+ points[0].y = st->height;
+ points[1].x = st->width;
+ points[1].y = 0;
+ points[2].x = st->width - ((i * st->width) / max);
+ points[2].y = 0;
+ DRAW();
+# undef DRAW
+}
+
+
+static void
+fizzle (eraser_state *st)
+{
+ const double overshoot = 1.0625;
+
+ unsigned int x, y, i;
+ const unsigned int size = 256;
+ unsigned short *rnd;
+ XPoint *points;
+ unsigned int npoints =
+ (unsigned int)(size * size * st->ratio * overshoot) -
+ (unsigned int)(size * size * st->prev_ratio * overshoot);
+
+ if (st->ratio >= 1.0)
+ {
+ free (st->fizzle_rnd);
+ st->fizzle_rnd = NULL;
+ return;
+ }
+
+ if (! st->fizzle_rnd)
+ {
+ unsigned int chunks =
+ ((st->width + size - 1) / size) * ((st->height + size - 1) / size);
+ unsigned int i;
+
+ st->fizzle_rnd =
+ (unsigned short *) malloc (sizeof(unsigned short) * chunks);
+
+ if (! st->fizzle_rnd)
+ return;
+
+ for (i = 0; i != chunks; i++)
+ st->fizzle_rnd[i] = NRAND(0x10000) | 1; /* Seed can't be 0. */
+ }
+
+ points = (XPoint *) malloc ((npoints + 1) * sizeof(*points));
+ if (! points) return;
+
+ rnd = st->fizzle_rnd;
+
+ for (y = 0; y < st->height; y += 256)
+ {
+ for (x = 0; x < st->width; x += 256)
+ {
+ unsigned int need0 = 0;
+ unsigned short r = *rnd;
+ for (i = 0; i != npoints; i++)
+ {
+ points[i].x = r % size + x;
+ points[i].y = (r >> 8) % size + y;
+
+ /* Xorshift. This has a period of 2^16, which exactly matches
+ the number of pixels in each 256x256 chunk.
+
+ Other shift constants are possible, but it's hard to say
+ which constants are best: a 2^16 period PRNG will never score
+ well on BigCrush.
+ */
+ r = (r ^ (r << 3)) & 0xffff;
+ r = r ^ (r >> 5);
+ r = (r ^ (r << 11)) & 0xffff;
+ need0 |= (r == 0x8080); /* Can be anything, really. */
+ }
+
+ if (need0)
+ {
+ points[npoints].x = x;
+ points[npoints].y = y;
+ }
+
+ XDrawPoints (st->dpy, st->window, st->bg_gc,
+ points, npoints + need0, CoordModeOrigin);
+ *rnd = r;
+ rnd++;
+ }
+ }
+ free (points);
+}
+
+
+static void
+spiral (eraser_state *st)
+{
+ int max_radius = (st->width > st->height ? st->width : st->height) * 0.7;
+ int loops = 10;
+ float max_th = M_PI * 2 * loops;
+ int i;
+ int steps = 360 * loops / 4;
+ float off;
+
+ if (st->ratio == 0.0)
+ {
+ st->flip_p = random() & 1;
+ st->start = random() % 360;
+ }
+
+ off = st->start * M_PI / 180;
+
+ for (i = steps * st->prev_ratio;
+ i < steps * st->ratio;
+ i++)
+ {
+ float th1 = i * max_th / steps;
+ float th2 = (i+1) * max_th / steps;
+ int r1 = i * max_radius / steps;
+ int r2 = (i+1) * max_radius / steps;
+ XPoint points[3];
+
+ if (st->flip_p)
+ {
+ th1 = max_th - th1;
+ th2 = max_th - th2;
+ }
+
+ points[0].x = st->width / 2;
+ points[0].y = st->height / 2;
+ points[1].x = points[0].x + r1 * cos (off + th1);
+ points[1].y = points[0].y + r1 * sin (off + th1);
+ points[2].x = points[0].x + r2 * cos (off + th2);
+ points[2].y = points[0].y + r2 * sin (off + th2);
+/* XFillRectangle(st->dpy, st->window, st->fg_gc,0,0,st->width, st->height);*/
+ XFillPolygon (st->dpy, st->window, st->bg_gc,
+ points, 3, Convex, CoordModeOrigin);
+ }
+}
+
+
+static void
+random_squares (eraser_state *st)
+{
+ int i, size, rows;
+
+ if (st->ratio == 0.0)
+ {
+ st->cols = 10 + random() % 30;
+ size = st->width / st->cols;
+ rows = (size ? (st->height / size) : 0) + 1;
+ st->nlines = st->cols * rows;
+ st->lines = (int *) calloc (st->nlines, sizeof(*st->lines));
+
+ for (i = 0; i < st->nlines; i++) /* every square */
+ st->lines[i] = i;
+
+ for (i = 0; i < st->nlines; i++) /* shuffle */
+ {
+ int t, r;
+ t = st->lines[i];
+ r = random() % st->nlines;
+ st->lines[i] = st->lines[r];
+ st->lines[r] = t;
+ }
+ }
+
+ size = st->width / st->cols;
+ rows = (size ? (st->height / size) : 0) + 1;
+
+ for (i = st->nlines * st->prev_ratio;
+ i < st->nlines * st->ratio;
+ i++)
+ {
+ int x = st->lines[i] % st->cols;
+ int y = st->lines[i] / st->cols;
+ XFillRectangle (st->dpy, st->window, st->bg_gc,
+ st->width * x / st->cols,
+ st->height * y / rows,
+ size+1, size+1);
+ }
+
+ if (st->ratio >= 1.0)
+ {
+ free (st->lines);
+ st->lines = 0;
+ }
+}
+
+
+/* I first saw something like this, albeit in reverse, in an early Tetris
+ implementation for the Mac.
+ -- Torbjörn Andersson <torbjorn@dev.eurotime.se>
+ */
+static void
+slide_lines (eraser_state *st)
+{
+ int max = st->width * 1.1;
+ int nlines = 40;
+ int h = st->height / nlines;
+ int y, step;
+ int tick = 0;
+
+ if (h < 10)
+ h = 10;
+
+ step = (max * st->ratio) - (max * st->prev_ratio);
+ if (step <= 0)
+ step = 1;
+
+ for (y = 0; y < st->height; y += h)
+ {
+ if (st->width <= step)
+ ;
+ else if (tick & 1)
+ {
+ XCopyArea (st->dpy, st->window, st->window, st->fg_gc,
+ 0, y, st->width-step, h, step, y);
+ XFillRectangle (st->dpy, st->window, st->bg_gc,
+ 0, y, step, h);
+ }
+ else
+ {
+ XCopyArea (st->dpy, st->window, st->window, st->fg_gc,
+ step, y, st->width-step, h, 0, y);
+ XFillRectangle (st->dpy, st->window, st->bg_gc,
+ st->width-step, y, step, h);
+ }
+
+ tick++;
+ }
+}
+
+
+/* from Frederick Roeber <roeber@xigo.com> */
+static void
+losira (eraser_state *st)
+{
+ double mode1 = 0.55;
+ double mode2 = mode1 + 0.30;
+ double mode3 = 1.0;
+ int radius = 10;
+
+ if (st->ratio < mode1) /* squeeze from the sides */
+ {
+ double ratio = st->ratio / mode1;
+ double prev_ratio = st->prev_ratio / mode1;
+ int max = st->width / 2;
+ int step = (max * ratio) - (max * prev_ratio);
+
+ if (step <= 0)
+ step = 1;
+
+ /* pull from left */
+ XCopyArea (st->dpy, st->window, st->window, st->fg_gc,
+ 0, 0, max - step, st->height, step, 0);
+ XFillRectangle (st->dpy, st->window, st->bg_gc,
+ 0, 0, max * ratio, st->height);
+
+ /* pull from right */
+ XCopyArea (st->dpy, st->window, st->window, st->fg_gc,
+ max+step, 0, max - step, st->height, max, 0);
+ XFillRectangle (st->dpy, st->window, st->bg_gc,
+ max + max*(1-ratio), 0, max, st->height);
+
+ /* expand white from center */
+ XFillRectangle (st->dpy, st->window, st->fg_gc,
+ max - (radius * ratio), 0,
+ radius * ratio * 2, st->height);
+ }
+ else if (st->ratio < mode2) /* squeeze from the top/bottom */
+ {
+ double ratio = (st->ratio - mode1) / (mode2 - mode1);
+ int max = st->height / 2;
+
+ /* fill middle */
+ XFillRectangle (st->dpy, st->window, st->fg_gc,
+ st->width/2 - radius,
+ max * ratio,
+ radius*2, st->height * (1 - ratio));
+
+ /* fill left and right */
+ XFillRectangle (st->dpy, st->window, st->bg_gc,
+ 0, 0, st->width/2 - radius, st->height);
+ XFillRectangle (st->dpy, st->window, st->bg_gc,
+ st->width/2 + radius, 0, st->width/2, st->height);
+
+ /* fill top and bottom */
+ XFillRectangle (st->dpy, st->window, st->bg_gc,
+ 0, 0, st->width, max * ratio);
+ XFillRectangle (st->dpy, st->window, st->bg_gc,
+ 0, st->height - (max * ratio),
+ st->width, max);
+
+ /* cap top */
+ XFillArc (st->dpy, st->window, st->fg_gc,
+ st->width/2 - radius,
+ max * ratio - radius,
+ radius*2, radius*2,
+ 0, 180*64);
+
+ /* cap bottom */
+ XFillArc (st->dpy, st->window, st->fg_gc,
+ st->width/2 - radius,
+ st->height - (max * ratio + radius),
+ radius*2, radius*2,
+ 180*64, 180*64);
+ }
+ else if (st->ratio < mode3) /* starburst */
+ {
+ double ratio = (st->ratio - mode2) / (mode3 - mode2);
+ double r2 = ratio * radius * 4;
+ XArc arc[9];
+ int i;
+ int angle = 360*64/countof(arc);
+
+ for (i = 0; i < countof(arc); i++)
+ {
+ double th;
+ arc[i].angle1 = angle * i;
+ arc[i].angle2 = angle;
+ arc[i].width = radius*2 * (1 + ratio);
+ arc[i].height = radius*2 * (1 + ratio);
+ arc[i].x = st->width / 2 - radius;
+ arc[i].y = st->height / 2 - radius;
+
+ th = ((arc[i].angle1 + (arc[i].angle2 / 2)) / 64.0 / 180 * M_PI);
+
+ arc[i].x += r2 * cos (th);
+ arc[i].y -= r2 * sin (th);
+ }
+
+ XFillRectangle (st->dpy, st->window, st->bg_gc,
+ 0, 0, st->width, st->height);
+ XFillArcs (st->dpy, st->window, st->fg_gc, arc, countof(arc));
+ }
+}
+
+
+static Eraser erasers[] = {
+ random_lines,
+ venetian,
+ triple_wipe,
+ quad_wipe,
+ circle_wipe,
+ three_circle_wipe,
+ squaretate,
+ fizzle,
+ spiral,
+ random_squares,
+ slide_lines,
+ losira,
+};
+
+
+static eraser_state *
+eraser_init (Display *dpy, Window window)
+{
+ eraser_state *st = (eraser_state *) calloc (1, sizeof(*st));
+ XWindowAttributes xgwa;
+ XGCValues gcv;
+ unsigned long fg, bg;
+ double duration;
+ int which;
+ char *s;
+
+ st->dpy = dpy;
+ st->window = window;
+
+ XGetWindowAttributes (dpy, window, &xgwa);
+ st->width = xgwa.width;
+ st->height = xgwa.height;
+
+ bg = get_pixel_resource (dpy, xgwa.colormap, "background", "Background");
+ fg = get_pixel_resource (dpy, xgwa.colormap, "foreground", "Foreground");
+
+ gcv.foreground = fg;
+ gcv.background = bg;
+ st->fg_gc = XCreateGC (dpy, window, GCForeground|GCBackground, &gcv);
+ gcv.foreground = bg;
+ gcv.background = fg;
+ st->bg_gc = XCreateGC (dpy, window, GCForeground|GCBackground, &gcv);
+
+# ifdef HAVE_COCOA
+ /* Pretty much all of these leave turds if AA is on. */
+ jwxyz_XSetAntiAliasing (st->dpy, st->fg_gc, False);
+ jwxyz_XSetAntiAliasing (st->dpy, st->bg_gc, False);
+# endif
+
+ s = get_string_resource (dpy, "eraseMode", "Integer");
+ if (!s || !*s)
+ which = -1;
+ else
+ which = get_integer_resource(dpy, "eraseMode", "Integer");
+ free (s);
+
+ if (which < 0 || which >= countof(erasers))
+ which = random() % countof(erasers);
+ st->fn = erasers[which];
+
+ duration = get_float_resource (dpy, "eraseSeconds", "Float");
+ if (duration < 0.1 || duration > 10)
+ duration = 1;
+
+ st->start_time = double_time();
+ st->stop_time = st->start_time + duration;
+
+ XSync (st->dpy, False);
+
+ return st;
+}
+
+
+void
+eraser_free (eraser_state *st)
+{
+ XClearWindow (st->dpy, st->window); /* Final draw is black-on-black. */
+ st->ratio = 1.0;
+ st->fn (st); /* Free any memory. May also draw, but that doesn't matter. */
+ XFreeGC (st->dpy, st->fg_gc);
+ XFreeGC (st->dpy, st->bg_gc);
+ free (st);
+}
+
+eraser_state *
+erase_window (Display *dpy, Window window, eraser_state *st)
+{
+ double now, duration;
+ Bool first_p = False;
+ if (! st)
+ {
+ first_p = True;
+ st = eraser_init (dpy, window);
+ }
+
+ now = (first_p ? st->start_time : double_time());
+ duration = st->stop_time - st->start_time;
+
+ st->prev_ratio = st->ratio;
+ st->ratio = (now - st->start_time) / duration;
+
+ if (st->ratio < 1.0)
+ {
+ st->fn (st);
+ XSync (st->dpy, False);
+ }
+ else
+ {
+ eraser_free (st);
+ st = 0;
+ }
+ return st;
+}
diff --git a/utils/erase.h b/utils/erase.h
new file mode 100644
index 0000000..1e720f9
--- /dev/null
+++ b/utils/erase.h
@@ -0,0 +1,21 @@
+/* erase.c: Erase the screen in various more or less interesting ways.
+ * Copyright (c) 1997-2001, 2006 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 __XSCREENSAVER_ERASE_H__
+#define __XSCREENSAVER_ERASE_H__
+
+typedef struct eraser_state eraser_state;
+
+extern void eraser_free (eraser_state *st);
+extern eraser_state *erase_window (Display *, Window, eraser_state *);
+
+#endif /* __XSCREENSAVER_ERASE_H__ */
diff --git a/utils/fade.c b/utils/fade.c
new file mode 100644
index 0000000..7a2ce2b
--- /dev/null
+++ b/utils/fade.c
@@ -0,0 +1,962 @@
+/* xscreensaver, Copyright (c) 1992-2011 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.
+ */
+
+#include "utils.h"
+
+#include <sys/time.h> /* for gettimeofday() */
+
+#ifdef VMS
+# include "vms-gtod.h"
+#endif /* VMS */
+
+#include "visual.h"
+#include "usleep.h"
+#include "fade.h"
+
+Colormap
+copy_colormap (Screen *screen, Visual *visual,
+ Colormap cmap, Colormap into_cmap)
+{
+ int i;
+ Display *dpy = DisplayOfScreen (screen);
+ Window window = RootWindowOfScreen (screen);
+ int ncolors = CellsOfScreen (screen);
+ XColor *colors = 0;
+
+ /* If this is a colormap on a mono visual, or one with insanely many
+ color cells, bug out. */
+ if (ncolors <= 2 || ncolors > 4096)
+ return 0;
+ /* If this is a non-writable visual, bug out. */
+ if (!has_writable_cells (screen, visual))
+ return 0;
+
+ if (! into_cmap)
+ into_cmap = XCreateColormap (dpy, window, visual, AllocAll);
+ if (! cmap)
+ cmap = DefaultColormapOfScreen (screen);
+
+ colors = (XColor *) calloc(sizeof(XColor), ncolors);
+ for (i = 0; i < ncolors; i++)
+ colors [i].pixel = i;
+ XQueryColors (dpy, cmap, colors, ncolors);
+ XStoreColors (dpy, into_cmap, colors, ncolors);
+ free (colors);
+ return into_cmap;
+}
+
+
+void
+blacken_colormap (Screen *screen, Colormap cmap)
+{
+ Display *dpy = DisplayOfScreen (screen);
+ int ncolors = CellsOfScreen (screen);
+ XColor *colors;
+ int i;
+ if (ncolors > 4096)
+ return;
+ colors = (XColor *) calloc(sizeof(XColor), ncolors);
+ for (i = 0; i < ncolors; i++)
+ colors[i].pixel = i;
+ XStoreColors (dpy, cmap, colors, ncolors);
+ free (colors);
+}
+
+
+
+static void fade_screens_1 (Display *dpy, Colormap *cmaps,
+ Window *black_windows, int nwindows,
+ int seconds, int ticks,
+ Bool out_p, Bool clear_windows);
+
+#ifdef HAVE_SGI_VC_EXTENSION
+static int sgi_gamma_fade (Display *dpy,
+ Window *black_windows, int nwindows,
+ int seconds, int ticks,
+ Bool out_p, Bool clear_windows);
+#endif /* HAVE_SGI_VC_EXTENSION */
+
+#ifdef HAVE_XF86VMODE_GAMMA
+static int xf86_gamma_fade (Display *dpy,
+ Window *black_windows, int nwindows,
+ int seconds, int ticks,
+ Bool out_p, Bool clear_windows);
+#endif /* HAVE_XF86VMODE_GAMMA */
+
+
+void
+fade_screens (Display *dpy, Colormap *cmaps,
+ Window *black_windows, int nwindows,
+ int seconds, int ticks,
+ Bool out_p, Bool clear_windows)
+{
+ int oseconds = seconds;
+ Bool was_in_p = !out_p;
+
+ /* When we're asked to fade in, first fade out, then fade in.
+ That way all the transitions are smooth -- from what's on the
+ screen, to black, to the desktop.
+ */
+ if (was_in_p)
+ {
+ clear_windows = True;
+ out_p = True;
+ seconds /= 3;
+ if (seconds == 0)
+ seconds = 1;
+ }
+
+ AGAIN:
+
+/* #### printf("\n\nfade_screens %d %d %d\n", seconds, ticks, out_p); */
+
+#ifdef HAVE_SGI_VC_EXTENSION
+ /* First try to do it by fading the gamma in an SGI-specific way... */
+ if (0 == sgi_gamma_fade(dpy, black_windows, nwindows,
+ seconds, ticks, out_p,
+ clear_windows))
+ ;
+ else
+#endif /* HAVE_SGI_VC_EXTENSION */
+
+#ifdef HAVE_XF86VMODE_GAMMA
+ /* Then try to do it by fading the gamma in an XFree86-specific way... */
+ if (0 == xf86_gamma_fade(dpy, black_windows, nwindows,
+ seconds, ticks, out_p,
+ clear_windows))
+ ;
+ else
+#endif /* HAVE_XF86VMODE_GAMMA */
+
+ /* Else, do it the old-fashioned way, which (somewhat) loses if
+ there are TrueColor windows visible. */
+ fade_screens_1 (dpy, cmaps, black_windows, nwindows,
+ seconds, ticks,
+ out_p, clear_windows);
+
+ /* If we were supposed to be fading in, do so now (we just faded out,
+ so now fade back in.)
+ */
+ if (was_in_p)
+ {
+ was_in_p = False;
+ out_p = False;
+ seconds = oseconds * 2 / 3;
+ if (seconds == 0)
+ seconds = 1;
+ goto AGAIN;
+ }
+}
+
+
+static void
+sleep_from (struct timeval *now, struct timeval *then, long usecs_per_step)
+{
+ /* If several seconds have passed, the machine must have been asleep
+ or thrashing or something. Don't sleep in that case, to avoid
+ overflowing and sleeping for an unconscionably long time. This
+ function should only be sleeping for very short periods.
+ */
+ if (now->tv_sec - then->tv_sec < 5)
+ {
+ long diff = (((now->tv_sec - then->tv_sec) * 1000000) +
+ now->tv_usec - then->tv_usec);
+ if (usecs_per_step > diff)
+ usleep (usecs_per_step - diff);
+ }
+
+ then->tv_sec = now->tv_sec;
+ then->tv_usec = now->tv_usec;
+}
+
+
+
+/* The business with `cmaps_per_screen' is to fake out the SGI 8-bit video
+ hardware, which is capable of installing multiple (4) colormaps
+ simultaneously. We have to install multiple copies of the same set of
+ colors in order to fill up all the available slots in the hardware color
+ lookup table, so we install an extra N colormaps per screen to make sure
+ that all screens really go black.
+
+ I'm told that this trick also works with XInside's AcceleratedX when using
+ the Matrox Millennium card (which also allows multiple PseudoColor and
+ TrueColor visuals to co-exist and display properly at the same time.)
+
+ This trick works ok on the 24-bit Indy video hardware, but doesn't work at
+ all on the O2 24-bit hardware. I guess the higher-end hardware is too
+ "good" for this to work (dammit.) So... I figured out the "right" way to
+ do this on SGIs, which is to ramp the monitor's gamma down to 0. That's
+ what is implemented in sgi_gamma_fade(), so we use that if we can.
+ */
+static void
+fade_screens_1 (Display *dpy, Colormap *cmaps,
+ Window *black_windows, int nwindows,
+ int seconds, int ticks,
+ Bool out_p, Bool clear_windows)
+{
+ int i, j, k;
+ int steps = seconds * ticks;
+ long usecs_per_step = (long)(seconds * 1000000) / (long)steps;
+ XEvent dummy_event;
+ int cmaps_per_screen = 5;
+ int nscreens = ScreenCount(dpy);
+ int ncmaps = nscreens * cmaps_per_screen;
+ Colormap *fade_cmaps = 0;
+ Bool installed = False;
+ int total_ncolors;
+ XColor *orig_colors, *current_colors, *screen_colors, *orig_screen_colors;
+ struct timeval then, now;
+#ifdef GETTIMEOFDAY_TWO_ARGS
+ struct timezone tzp;
+#endif
+
+ total_ncolors = 0;
+ for (i = 0; i < nscreens; i++)
+ total_ncolors += CellsOfScreen (ScreenOfDisplay(dpy, i));
+
+ orig_colors = (XColor *) calloc(sizeof(XColor), total_ncolors);
+ current_colors = (XColor *) calloc(sizeof(XColor), total_ncolors);
+
+ /* Get the contents of the colormap we are fading from or to. */
+ screen_colors = orig_colors;
+ for (i = 0; i < nscreens; i++)
+ {
+ int ncolors = CellsOfScreen (ScreenOfDisplay (dpy, i));
+ Colormap cmap = (cmaps ? cmaps[i] : 0);
+ if (!cmap) cmap = DefaultColormap(dpy, i);
+
+ for (j = 0; j < ncolors; j++)
+ screen_colors[j].pixel = j;
+ XQueryColors (dpy, cmap, screen_colors, ncolors);
+
+ screen_colors += ncolors;
+ }
+
+ memcpy (current_colors, orig_colors, total_ncolors * sizeof (XColor));
+
+
+ /* Make the writable colormaps (we keep these around and reuse them.) */
+ if (!fade_cmaps)
+ {
+ fade_cmaps = (Colormap *) calloc(sizeof(Colormap), ncmaps);
+ for (i = 0; i < nscreens; i++)
+ {
+ Visual *v = DefaultVisual(dpy, i);
+ Screen *s = ScreenOfDisplay(dpy, i);
+ if (has_writable_cells (s, v))
+ for (j = 0; j < cmaps_per_screen; j++)
+ fade_cmaps[(i * cmaps_per_screen) + j] =
+ XCreateColormap (dpy, RootWindowOfScreen (s), v, AllocAll);
+ }
+ }
+
+#ifdef GETTIMEOFDAY_TWO_ARGS
+ gettimeofday(&then, &tzp);
+#else
+ gettimeofday(&then);
+#endif
+
+ /* Iterate by steps of the animation... */
+ for (i = (out_p ? steps : 0);
+ (out_p ? i > 0 : i < steps);
+ (out_p ? i-- : i++))
+ {
+
+ /* For each screen, compute the current value of each color...
+ */
+ orig_screen_colors = orig_colors;
+ screen_colors = current_colors;
+ for (j = 0; j < nscreens; j++)
+ {
+ int ncolors = CellsOfScreen (ScreenOfDisplay (dpy, j));
+ for (k = 0; k < ncolors; k++)
+ {
+ /* This doesn't take into account the relative luminance of the
+ RGB components (0.299, 0.587, and 0.114 at gamma 2.2) but
+ the difference is imperceptible for this application... */
+ screen_colors[k].red = orig_screen_colors[k].red * i / steps;
+ screen_colors[k].green = orig_screen_colors[k].green * i / steps;
+ screen_colors[k].blue = orig_screen_colors[k].blue * i / steps;
+ }
+ screen_colors += ncolors;
+ orig_screen_colors += ncolors;
+ }
+
+ /* Put the colors into the maps...
+ */
+ screen_colors = current_colors;
+ for (j = 0; j < nscreens; j++)
+ {
+ int ncolors = CellsOfScreen (ScreenOfDisplay (dpy, j));
+ for (k = 0; k < cmaps_per_screen; k++)
+ {
+ Colormap c = fade_cmaps[j * cmaps_per_screen + k];
+ if (c)
+ XStoreColors (dpy, c, screen_colors, ncolors);
+ }
+ screen_colors += ncolors;
+ }
+
+ /* Put the maps on the screens, and then take the windows off the screen.
+ (only need to do this the first time through the loop.)
+ */
+ if (!installed)
+ {
+ for (j = 0; j < ncmaps; j++)
+ if (fade_cmaps[j])
+ XInstallColormap (dpy, fade_cmaps[j]);
+ installed = True;
+
+ if (black_windows && !out_p)
+ for (j = 0; j < nwindows; j++)
+ if (black_windows[j])
+ {
+ XUnmapWindow (dpy, black_windows[j]);
+ XClearWindow (dpy, black_windows[j]);
+ }
+ }
+
+ XSync (dpy, False);
+
+ /* If there is user activity, bug out. (Bug out on keypresses or
+ mouse presses, but not motion, and not release events. Bugging
+ out on motion made the unfade hack be totally useless, I think.)
+
+ We put the event back so that the calling code can notice it too.
+ It would be better to not remove it at all, but that's harder
+ because Xlib has such a non-design for this kind of crap, and
+ in this application it doesn't matter if the events end up out
+ of order, so in the grand unix tradition we say "fuck it" and
+ do something that mostly works for the time being.
+ */
+ if (XCheckMaskEvent (dpy, (KeyPressMask|ButtonPressMask), &dummy_event))
+ {
+ XPutBackEvent (dpy, &dummy_event);
+ goto DONE;
+ }
+
+#ifdef GETTIMEOFDAY_TWO_ARGS
+ gettimeofday(&now, &tzp);
+#else
+ gettimeofday(&now);
+#endif
+
+ /* If we haven't already used up our alotted time, sleep to avoid
+ changing the colormap too fast. */
+ sleep_from (&now, &then, usecs_per_step);
+ }
+
+ DONE:
+
+ if (orig_colors) free (orig_colors);
+ if (current_colors) free (current_colors);
+
+ /* If we've been given windows to raise after blackout, raise them before
+ releasing the colormaps.
+ */
+ if (out_p && black_windows)
+ {
+ for (i = 0; i < nwindows; i++)
+ {
+ if (clear_windows)
+ XClearWindow (dpy, black_windows[i]);
+ XMapRaised (dpy, black_windows[i]);
+ }
+ XSync(dpy, False);
+ }
+
+ /* Now put the target maps back.
+ If we're fading out, use the given cmap (or the default cmap, if none.)
+ If we're fading in, always use the default cmap.
+ */
+ for (i = 0; i < nscreens; i++)
+ {
+ Colormap cmap = (cmaps ? cmaps[i] : 0);
+ if (!cmap || !out_p)
+ cmap = DefaultColormap(dpy, i);
+ XInstallColormap (dpy, cmap);
+ }
+
+ /* The fade (in or out) is complete, so we don't need the black maps on
+ stage any more.
+ */
+ for (i = 0; i < ncmaps; i++)
+ if (fade_cmaps[i])
+ {
+ XUninstallColormap(dpy, fade_cmaps[i]);
+ XFreeColormap(dpy, fade_cmaps[i]);
+ fade_cmaps[i] = 0;
+ }
+ free(fade_cmaps);
+ fade_cmaps = 0;
+}
+
+
+
+/* SGI Gamma fading */
+
+#ifdef HAVE_SGI_VC_EXTENSION
+
+# include <X11/extensions/XSGIvc.h>
+
+struct screen_sgi_gamma_info {
+ int gamma_map; /* ??? always using 0 */
+ int nred, ngreen, nblue;
+ unsigned short *red1, *green1, *blue1;
+ unsigned short *red2, *green2, *blue2;
+ int gamma_size;
+ int gamma_precision;
+ Bool alpha_p;
+};
+
+
+static void sgi_whack_gamma(Display *dpy, int screen,
+ struct screen_sgi_gamma_info *info, float ratio);
+
+static int
+sgi_gamma_fade (Display *dpy,
+ Window *black_windows, int nwindows,
+ int seconds, int ticks,
+ Bool out_p, Bool clear_windows)
+{
+ int steps = seconds * ticks;
+ long usecs_per_step = (long)(seconds * 1000000) / (long)steps;
+ XEvent dummy_event;
+ int nscreens = ScreenCount(dpy);
+ struct timeval then, now;
+#ifdef GETTIMEOFDAY_TWO_ARGS
+ struct timezone tzp;
+#endif
+ int i, screen;
+ int status = -1;
+ struct screen_sgi_gamma_info *info = (struct screen_sgi_gamma_info *)
+ calloc(nscreens, sizeof(*info));
+
+ /* Get the current gamma maps for all screens.
+ Bug out and return -1 if we can't get them for some screen.
+ */
+ for (screen = 0; screen < nscreens; screen++)
+ {
+ if (!XSGIvcQueryGammaMap(dpy, screen, info[screen].gamma_map,
+ &info[screen].gamma_size,
+ &info[screen].gamma_precision,
+ &info[screen].alpha_p))
+ goto FAIL;
+
+ if (!XSGIvcQueryGammaColors(dpy, screen, info[screen].gamma_map,
+ XSGIVC_COMPONENT_RED,
+ &info[screen].nred, &info[screen].red1))
+ goto FAIL;
+ if (! XSGIvcQueryGammaColors(dpy, screen, info[screen].gamma_map,
+ XSGIVC_COMPONENT_GREEN,
+ &info[screen].ngreen, &info[screen].green1))
+ goto FAIL;
+ if (!XSGIvcQueryGammaColors(dpy, screen, info[screen].gamma_map,
+ XSGIVC_COMPONENT_BLUE,
+ &info[screen].nblue, &info[screen].blue1))
+ goto FAIL;
+
+ if (info[screen].gamma_precision == 8) /* Scale it up to 16 bits. */
+ {
+ int j;
+ for(j = 0; j < info[screen].nred; j++)
+ info[screen].red1[j] =
+ ((info[screen].red1[j] << 8) | info[screen].red1[j]);
+ for(j = 0; j < info[screen].ngreen; j++)
+ info[screen].green1[j] =
+ ((info[screen].green1[j] << 8) | info[screen].green1[j]);
+ for(j = 0; j < info[screen].nblue; j++)
+ info[screen].blue1[j] =
+ ((info[screen].blue1[j] << 8) | info[screen].blue1[j]);
+ }
+
+ info[screen].red2 = (unsigned short *)
+ malloc(sizeof(*info[screen].red2) * (info[screen].nred+1));
+ info[screen].green2 = (unsigned short *)
+ malloc(sizeof(*info[screen].green2) * (info[screen].ngreen+1));
+ info[screen].blue2 = (unsigned short *)
+ malloc(sizeof(*info[screen].blue2) * (info[screen].nblue+1));
+ }
+
+#ifdef GETTIMEOFDAY_TWO_ARGS
+ gettimeofday(&then, &tzp);
+#else
+ gettimeofday(&then);
+#endif
+
+ /* If we're fading in (from black), then first crank the gamma all the
+ way down to 0, then take the windows off the screen.
+ */
+ if (!out_p)
+ {
+ for (screen = 0; screen < nscreens; screen++)
+ sgi_whack_gamma(dpy, screen, &info[screen], 0.0);
+
+ for (screen = 0; screen < nwindows; screen++)
+ if (black_windows && black_windows[screen])
+ {
+ XUnmapWindow (dpy, black_windows[screen]);
+ XClearWindow (dpy, black_windows[screen]);
+ XSync(dpy, False);
+ }
+ }
+
+ /* Iterate by steps of the animation... */
+ for (i = (out_p ? steps : 0);
+ (out_p ? i > 0 : i < steps);
+ (out_p ? i-- : i++))
+ {
+ for (screen = 0; screen < nscreens; screen++)
+ {
+ sgi_whack_gamma(dpy, screen, &info[screen],
+ (((float)i) / ((float)steps)));
+
+ /* If there is user activity, bug out. (Bug out on keypresses or
+ mouse presses, but not motion, and not release events. Bugging
+ out on motion made the unfade hack be totally useless, I think.)
+
+ We put the event back so that the calling code can notice it too.
+ It would be better to not remove it at all, but that's harder
+ because Xlib has such a non-design for this kind of crap, and
+ in this application it doesn't matter if the events end up out
+ of order, so in the grand unix tradition we say "fuck it" and
+ do something that mostly works for the time being.
+ */
+ if (XCheckMaskEvent (dpy, (KeyPressMask|ButtonPressMask),
+ &dummy_event))
+ {
+ XPutBackEvent (dpy, &dummy_event);
+ goto DONE;
+ }
+
+#ifdef GETTIMEOFDAY_TWO_ARGS
+ gettimeofday(&now, &tzp);
+#else
+ gettimeofday(&now);
+#endif
+
+ /* If we haven't already used up our alotted time, sleep to avoid
+ changing the colormap too fast. */
+ sleep_from (&now, &then, usecs_per_step);
+ }
+ }
+
+
+ DONE:
+
+ if (out_p && black_windows)
+ {
+ for (screen = 0; screen < nwindows; screen++)
+ {
+ if (clear_windows)
+ XClearWindow (dpy, black_windows[screen]);
+ XMapRaised (dpy, black_windows[screen]);
+ }
+ XSync(dpy, False);
+ }
+
+ /* I can't explain this; without this delay, we get a flicker.
+ I suppose there's some lossage with stale bits being in the
+ hardware frame buffer or something, and this delay gives it
+ time to flush out. This sucks! */
+ usleep(100000); /* 1/10th second */
+
+ for (screen = 0; screen < nscreens; screen++)
+ sgi_whack_gamma(dpy, screen, &info[screen], 1.0);
+ XSync(dpy, False);
+
+ status = 0;
+
+ FAIL:
+ for (screen = 0; screen < nscreens; screen++)
+ {
+ if (info[screen].red1) free (info[screen].red1);
+ if (info[screen].green1) free (info[screen].green1);
+ if (info[screen].blue1) free (info[screen].blue1);
+ if (info[screen].red2) free (info[screen].red2);
+ if (info[screen].green2) free (info[screen].green2);
+ if (info[screen].blue2) free (info[screen].blue2);
+ }
+ free(info);
+
+ return status;
+}
+
+static void
+sgi_whack_gamma(Display *dpy, int screen, struct screen_sgi_gamma_info *info,
+ float ratio)
+{
+ int k;
+
+ if (ratio < 0) ratio = 0;
+ if (ratio > 1) ratio = 1;
+ for (k = 0; k < info->gamma_size; k++)
+ {
+ info->red2[k] = info->red1[k] * ratio;
+ info->green2[k] = info->green1[k] * ratio;
+ info->blue2[k] = info->blue1[k] * ratio;
+ }
+
+ XSGIvcStoreGammaColors16(dpy, screen, info->gamma_map, info->nred,
+ XSGIVC_MComponentRed, info->red2);
+ XSGIvcStoreGammaColors16(dpy, screen, info->gamma_map, info->ngreen,
+ XSGIVC_MComponentGreen, info->green2);
+ XSGIvcStoreGammaColors16(dpy, screen, info->gamma_map, info->nblue,
+ XSGIVC_MComponentBlue, info->blue2);
+ XSync(dpy, False);
+}
+
+#endif /* HAVE_SGI_VC_EXTENSION */
+
+
+
+/* XFree86 4.x+ Gamma fading */
+
+#ifdef HAVE_XF86VMODE_GAMMA
+
+#include <X11/extensions/xf86vmode.h>
+
+typedef struct {
+ XF86VidModeGamma vmg;
+ int size;
+ unsigned short *r, *g, *b;
+} xf86_gamma_info;
+
+static int xf86_check_gamma_extension (Display *dpy);
+static Bool xf86_whack_gamma (Display *dpy, int screen,
+ xf86_gamma_info *ginfo, float ratio);
+
+static int
+xf86_gamma_fade (Display *dpy,
+ Window *black_windows, int nwindows,
+ int seconds, int ticks,
+ Bool out_p, Bool clear_windows)
+{
+ int steps = seconds * ticks;
+ long usecs_per_step = (long)(seconds * 1000000) / (long)steps;
+ XEvent dummy_event;
+ int nscreens = ScreenCount(dpy);
+ struct timeval then, now;
+#ifdef GETTIMEOFDAY_TWO_ARGS
+ struct timezone tzp;
+#endif
+ int i, screen;
+ int status = -1;
+ xf86_gamma_info *info = 0;
+
+ static int ext_ok = -1;
+
+ /* Only probe the extension once: the answer isn't going to change. */
+ if (ext_ok == -1)
+ ext_ok = xf86_check_gamma_extension (dpy);
+
+ /* If this server doesn't have the gamma extension, bug out. */
+ if (ext_ok == 0)
+ goto FAIL;
+
+# ifndef HAVE_XF86VMODE_GAMMA_RAMP
+ if (ext_ok == 2) ext_ok = 1; /* server is newer than client! */
+# endif
+
+ info = (xf86_gamma_info *) calloc(nscreens, sizeof(*info));
+
+ /* Get the current gamma maps for all screens.
+ Bug out and return -1 if we can't get them for some screen.
+ */
+ for (screen = 0; screen < nscreens; screen++)
+ {
+ if (ext_ok == 1) /* only have gamma parameter, not ramps. */
+ {
+ if (!XF86VidModeGetGamma(dpy, screen, &info[screen].vmg))
+ goto FAIL;
+ }
+# ifdef HAVE_XF86VMODE_GAMMA_RAMP
+ else if (ext_ok == 2) /* have ramps */
+ {
+ if (!XF86VidModeGetGammaRampSize(dpy, screen, &info[screen].size))
+ goto FAIL;
+ if (info[screen].size <= 0)
+ goto FAIL;
+
+ info[screen].r = (unsigned short *)
+ calloc(info[screen].size, sizeof(unsigned short));
+ info[screen].g = (unsigned short *)
+ calloc(info[screen].size, sizeof(unsigned short));
+ info[screen].b = (unsigned short *)
+ calloc(info[screen].size, sizeof(unsigned short));
+
+ if (!(info[screen].r && info[screen].g && info[screen].b))
+ goto FAIL;
+
+ if (!XF86VidModeGetGammaRamp(dpy, screen, info[screen].size,
+ info[screen].r,
+ info[screen].g,
+ info[screen].b))
+ goto FAIL;
+ }
+# endif /* HAVE_XF86VMODE_GAMMA_RAMP */
+ else
+ abort();
+ }
+
+#ifdef GETTIMEOFDAY_TWO_ARGS
+ gettimeofday(&then, &tzp);
+#else
+ gettimeofday(&then);
+#endif
+
+ /* If we're fading in (from black), then first crank the gamma all the
+ way down to 0, then take the windows off the screen.
+ */
+ if (!out_p)
+ {
+ for (screen = 0; screen < nscreens; screen++)
+ xf86_whack_gamma(dpy, screen, &info[screen], 0.0);
+ for (screen = 0; screen < nwindows; screen++)
+ if (black_windows && black_windows[screen])
+ {
+ XUnmapWindow (dpy, black_windows[screen]);
+ XClearWindow (dpy, black_windows[screen]);
+ XSync(dpy, False);
+ }
+ }
+
+ /* Iterate by steps of the animation... */
+ for (i = (out_p ? steps : 0);
+ (out_p ? i > 0 : i < steps);
+ (out_p ? i-- : i++))
+ {
+ for (screen = 0; screen < nscreens; screen++)
+ {
+ xf86_whack_gamma(dpy, screen, &info[screen],
+ (((float)i) / ((float)steps)));
+
+ /* If there is user activity, bug out. (Bug out on keypresses or
+ mouse presses, but not motion, and not release events. Bugging
+ out on motion made the unfade hack be totally useless, I think.)
+
+ We put the event back so that the calling code can notice it too.
+ It would be better to not remove it at all, but that's harder
+ because Xlib has such a non-design for this kind of crap, and
+ in this application it doesn't matter if the events end up out
+ of order, so in the grand unix tradition we say "fuck it" and
+ do something that mostly works for the time being.
+ */
+ if (XCheckMaskEvent (dpy, (KeyPressMask|ButtonPressMask),
+ &dummy_event))
+ {
+ XPutBackEvent (dpy, &dummy_event);
+ goto DONE;
+ }
+
+#ifdef GETTIMEOFDAY_TWO_ARGS
+ gettimeofday(&now, &tzp);
+#else
+ gettimeofday(&now);
+#endif
+
+ /* If we haven't already used up our alotted time, sleep to avoid
+ changing the colormap too fast. */
+ sleep_from (&now, &then, usecs_per_step);
+ }
+ }
+
+
+ DONE:
+
+ if (out_p && black_windows)
+ {
+ for (screen = 0; screen < nwindows; screen++)
+ {
+ if (clear_windows)
+ XClearWindow (dpy, black_windows[screen]);
+ XMapRaised (dpy, black_windows[screen]);
+ }
+ XSync(dpy, False);
+ }
+
+ /* I can't explain this; without this delay, we get a flicker.
+ I suppose there's some lossage with stale bits being in the
+ hardware frame buffer or something, and this delay gives it
+ time to flush out. This sucks! */
+ usleep(100000); /* 1/10th second */
+
+ for (screen = 0; screen < nscreens; screen++)
+ xf86_whack_gamma(dpy, screen, &info[screen], 1.0);
+ XSync(dpy, False);
+
+ status = 0;
+
+ FAIL:
+ if (info)
+ {
+ for (screen = 0; screen < nscreens; screen++)
+ {
+ if (info[screen].r) free(info[screen].r);
+ if (info[screen].g) free(info[screen].g);
+ if (info[screen].b) free(info[screen].b);
+ }
+ free(info);
+ }
+
+ return status;
+}
+
+
+/* This bullshit is needed because the VidMode extension doesn't work
+ on remote displays -- but if the remote display has the extension
+ at all, XF86VidModeQueryExtension returns true, and then
+ XF86VidModeQueryVersion dies with an X error. Thank you XFree,
+ may I have another.
+ */
+
+static Bool error_handler_hit_p = False;
+
+static int
+ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
+{
+ error_handler_hit_p = True;
+ return 0;
+}
+
+static Bool
+safe_XF86VidModeQueryVersion (Display *dpy, int *majP, int *minP)
+{
+ Bool result;
+ XErrorHandler old_handler;
+ XSync (dpy, False);
+ error_handler_hit_p = False;
+ old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
+
+ result = XF86VidModeQueryVersion (dpy, majP, minP);
+
+ XSync (dpy, False);
+ XSetErrorHandler (old_handler);
+ XSync (dpy, False);
+
+ return (error_handler_hit_p
+ ? False
+ : result);
+}
+
+
+
+/* VidModeExtension version 2.0 or better is needed to do gamma.
+ 2.0 added gamma values; 2.1 added gamma ramps.
+ */
+# define XF86_VIDMODE_GAMMA_MIN_MAJOR 2
+# define XF86_VIDMODE_GAMMA_MIN_MINOR 0
+# define XF86_VIDMODE_GAMMA_RAMP_MIN_MAJOR 2
+# define XF86_VIDMODE_GAMMA_RAMP_MIN_MINOR 1
+
+
+
+/* Returns 0 if gamma fading not available; 1 if only gamma value setting
+ is available; 2 if gamma ramps are available.
+ */
+static int
+xf86_check_gamma_extension (Display *dpy)
+{
+ int event, error, major, minor;
+
+ if (!XF86VidModeQueryExtension (dpy, &event, &error))
+ return 0; /* display doesn't have the extension. */
+
+ if (!safe_XF86VidModeQueryVersion (dpy, &major, &minor))
+ return 0; /* unable to get version number? */
+
+ if (major < XF86_VIDMODE_GAMMA_MIN_MAJOR ||
+ (major == XF86_VIDMODE_GAMMA_MIN_MAJOR &&
+ minor < XF86_VIDMODE_GAMMA_MIN_MINOR))
+ return 0; /* extension is too old for gamma. */
+
+ if (major < XF86_VIDMODE_GAMMA_RAMP_MIN_MAJOR ||
+ (major == XF86_VIDMODE_GAMMA_RAMP_MIN_MAJOR &&
+ minor < XF86_VIDMODE_GAMMA_RAMP_MIN_MINOR))
+ return 1; /* extension is too old for gamma ramps. */
+
+ /* Copacetic */
+ return 2;
+}
+
+
+/* XFree doesn't let you set gamma to a value smaller than this.
+ Apparently they didn't anticipate the trick I'm doing here...
+ */
+#define XF86_MIN_GAMMA 0.1
+
+
+static Bool
+xf86_whack_gamma(Display *dpy, int screen, xf86_gamma_info *info,
+ float ratio)
+{
+ Bool status;
+
+ XErrorHandler old_handler;
+ XSync (dpy, False);
+ error_handler_hit_p = False;
+ old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
+
+ if (ratio < 0) ratio = 0;
+ if (ratio > 1) ratio = 1;
+
+ if (info->size == 0) /* we only have a gamma number, not a ramp. */
+ {
+ XF86VidModeGamma g2;
+
+ g2.red = info->vmg.red * ratio;
+ g2.green = info->vmg.green * ratio;
+ g2.blue = info->vmg.blue * ratio;
+
+# ifdef XF86_MIN_GAMMA
+ if (g2.red < XF86_MIN_GAMMA) g2.red = XF86_MIN_GAMMA;
+ if (g2.green < XF86_MIN_GAMMA) g2.green = XF86_MIN_GAMMA;
+ if (g2.blue < XF86_MIN_GAMMA) g2.blue = XF86_MIN_GAMMA;
+# endif
+
+ status = XF86VidModeSetGamma (dpy, screen, &g2);
+ }
+ else
+ {
+# ifdef HAVE_XF86VMODE_GAMMA_RAMP
+
+ unsigned short *r, *g, *b;
+ int i;
+ r = (unsigned short *) malloc(info->size * sizeof(unsigned short));
+ g = (unsigned short *) malloc(info->size * sizeof(unsigned short));
+ b = (unsigned short *) malloc(info->size * sizeof(unsigned short));
+
+ for (i = 0; i < info->size; i++)
+ {
+ r[i] = info->r[i] * ratio;
+ g[i] = info->g[i] * ratio;
+ b[i] = info->b[i] * ratio;
+ }
+
+ status = XF86VidModeSetGammaRamp(dpy, screen, info->size, r, g, b);
+
+ free (r);
+ free (g);
+ free (b);
+
+# else /* !HAVE_XF86VMODE_GAMMA_RAMP */
+ abort();
+# endif /* !HAVE_XF86VMODE_GAMMA_RAMP */
+ }
+
+ XSync (dpy, False);
+ XSetErrorHandler (old_handler);
+ XSync (dpy, False);
+
+ return status;
+}
+
+#endif /* HAVE_XF86VMODE_GAMMA */
diff --git a/utils/fade.h b/utils/fade.h
new file mode 100644
index 0000000..bedae93
--- /dev/null
+++ b/utils/fade.h
@@ -0,0 +1,21 @@
+/* xscreensaver, Copyright (c) 1992-1997, 2003 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 __FADE_H__
+#define __FADE_H__
+
+extern Colormap copy_colormap (Screen *, Visual *, Colormap from, Colormap to);
+extern void blacken_colormap (Screen *, Colormap cmap);
+extern void fade_screens (Display *dpy,
+ Colormap *cmaps, Window *black_windows, int nwindows,
+ int seconds, int ticks,
+ Bool out_p, Bool clear_windows);
+#endif /* __FADE_H__ */
diff --git a/utils/font-retry.c b/utils/font-retry.c
new file mode 100644
index 0000000..c3e91a0
--- /dev/null
+++ b/utils/font-retry.c
@@ -0,0 +1,189 @@
+/* xscreensaver, Copyright (c) 2018 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
+ * 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.
+ */
+
+/* Like XLoadQueryFont, but if it fails, it tries some heuristics to
+ load something close.
+ */
+
+#define _GNU_SOURCE
+
+#include "utils.h"
+#include "visual.h"
+#include "xft.h"
+#include "font-retry.h"
+
+extern const char *progname;
+
+#undef countof
+#define countof(x) (sizeof((x))/sizeof((*x)))
+
+static void *
+load_font_retry_1 (Display *dpy, int screen, const char *xlfd, Bool xft_p)
+{
+
+# ifdef USE_XFT
+# define LOADFONT() (xft_p \
+ ? (void *) XftFontOpenXlfd (dpy, screen, xlfd) \
+ : (void *) XLoadQueryFont (dpy, xlfd))
+# else
+# define LOADFONT() ((void *) XLoadQueryFont (dpy, xlfd))
+# endif
+
+ void *f = LOADFONT();
+
+# ifndef USE_XFT
+ if (xft_p) abort();
+# endif
+
+# ifdef HAVE_JWXYZ
+ return f;
+# else /* !HAVE_JWXYZ */
+ if (f)
+ return f;
+ else
+ {
+ Bool bold_p = (!!strcasestr (xlfd, "-bold-"));
+ 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;
+
+ if (!strcmp (xlfd, "vga")) /* BSOD uses this: it has no XLFD name. */
+ fixed_p = True, size = 120;
+
+ /* 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;
+ }
+ }
+
+ if (! size)
+ {
+ fprintf (stderr, "%s: unloadable, unparsable font: \"%s\"\n",
+ progname, xlfd);
+ xlfd = "fixed";
+ return LOADFONT();
+ }
+ else
+ {
+ const char *fixed[] = { "courier",
+ "courier new",
+ "courier 10 pitch",
+ "lucidatypewriter",
+ "american typewriter",
+ "fixed",
+ "ocr a std",
+ "*" };
+ const char *variable[] = { "helvetica",
+ "arial",
+ "bitstream vera sans",
+ "gill sans",
+ "times",
+ "times new roman",
+ "new century schoolbook",
+ "utopia",
+ "palatino",
+ "lucida",
+ "bitstream charter",
+ "*" };
+ 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]);
+ /* fprintf(stderr, "%s: trying %s\n", progname, buf);*/
+ f = LOADFONT();
+ if (f)
+ {
+ /* fprintf (stderr,
+ "%s: substituted \"%s\" for \"%s\"\n",
+ progname, buf, xlfd); */
+ return f;
+ }
+ }
+
+ fprintf (stderr, "%s: unable to find any alternatives to \"%s\"\n",
+ progname, xlfd);
+ xlfd = "fixed";
+ return LOADFONT();
+ }
+ }
+# endif /* !HAVE_JWXYZ */
+}
+
+XFontStruct *
+load_font_retry (Display *dpy, const char *xlfd)
+{
+ return (XFontStruct *) load_font_retry_1 (dpy, 0, xlfd, 0);
+}
+
+#ifdef USE_XFT
+XftFont *
+load_xft_font_retry (Display *dpy, int screen, const char *xlfd)
+{
+ return (XftFont *) load_font_retry_1 (dpy, screen, xlfd, 1);
+}
+
+#elif defined(HAVE_JWXYZ)
+
+XftFont *
+load_xft_font_retry (Display *dpy, int screen, const char *xlfd)
+{
+ return XftFontOpenXlfd (dpy, screen, xlfd);
+}
+
+#endif /* !HAVE_JWXYZ */
diff --git a/utils/font-retry.h b/utils/font-retry.h
new file mode 100644
index 0000000..83ba0e0
--- /dev/null
+++ b/utils/font-retry.h
@@ -0,0 +1,24 @@
+/* xscreensaver, Copyright (c) 2018 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
+ * 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 __FONT_RETRY_H__
+#define __FONT_RETRY_H__
+
+/* Like XLoadQueryFont, but if it fails, it tries some heuristics to
+ load something close.
+ */
+extern XFontStruct *load_font_retry (Display *, const char *xlfd);
+
+# ifdef __XSCREENSAVER_XFT_H__ /* if xft.h has been included */
+extern XftFont *load_xft_font_retry (Display *, int screen, const char *xlfd);
+# endif
+
+#endif /* __FONT_RETRY_H__ */
diff --git a/utils/grabclient.c b/utils/grabclient.c
new file mode 100644
index 0000000..abe069b
--- /dev/null
+++ b/utils/grabclient.c
@@ -0,0 +1,1037 @@
+/* xscreensaver, Copyright (c) 1992-2018 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.
+ */
+
+/* This file contains code for running an external program to grab an image
+ onto the given window. The external program in question must take a
+ window ID as its argument, e.g., the "xscreensaver-getimage" program
+ in the hacks/ directory.
+
+ That program links against utils/grabimage.c, which happens to export the
+ same API as this program (utils/grabclient.c).
+ */
+
+/* This code is a mess. There's two decades of history in this file.
+ There are several distinct paths through this file depending on what
+ platform it's being compiled for:
+
+
+ X11 execution path:
+
+ load_image_async CB
+ load_random_image_x11
+ fork_exec_cb
+ "xscreensaver-getimage 0xWINDOW 0xPIXMAP"
+ "xscreensaver-getimage-file --name /DIR"
+ draw_colorbars
+ XPutImage
+ XtAppAddInput xscreensaver_getimage_cb
+ ...
+ xscreensaver_getimage_cb
+ get_name_from_xprops
+ get_original_geometry_from_xprops
+ CB name, geom, closure
+
+
+ MacOS execution path:
+
+ load_image_async CB
+ load_random_image_cocoa
+ osx_grab_desktop_image (grabclient-osx.m, MacOS version)
+ copy_framebuffer_to_ximage
+ XPutImage
+ draw_colorbars
+ osx_load_image_file_async
+ open_image_name_pipe
+ "xscreensaver-getimage-file --name /DIR"
+ XtAppAddInput xscreensaver_getimage_file_cb
+ ...
+ xscreensaver_getimage_file_cb
+ osx_load_image_file
+ CB name, geom, closure
+
+
+ iOS execution path:
+
+ load_image_async CB
+ load_random_image_cocoa
+ osx_grab_desktop_image (grabclient-osx.m, iOS version)
+ CGWindowListCreateImage
+ jwxyz_draw_NSImage_or_CGImage
+ draw_colorbars
+ ios_load_random_image
+ ios_load_random_image_cb
+ jwxyz_draw_NSImage_or_CGImage
+ CB name, geom, closure
+
+
+ Android execution path:
+
+ load_image_async CB
+ load_random_image_android
+ jwxyz_load_random_image (jwxyz-android.c)
+ XPutImage
+ draw_colorbars
+ CB name, geom, closure
+ */
+
+#include "utils.h"
+#include "grabscreen.h"
+#include "resources.h"
+#include "yarandom.h"
+
+#ifdef HAVE_JWXYZ
+# include "jwxyz.h"
+# include "colorbars.h"
+#else /* !HAVE_COCOA -- real Xlib */
+# include "vroot.h"
+# include <X11/Xatom.h>
+# include <X11/Intrinsic.h> /* for XtInputId, etc */
+#endif /* !HAVE_COCOA */
+
+#include <sys/stat.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h> /* for waitpid() and associated macros */
+#endif
+
+
+extern char *progname;
+
+static void print_loading_msg (Screen *, Window);
+
+
+/* Used for pipe callbacks in X11 or OSX mode.
+ X11: this is the xscreensaver_getimage_cb closure,
+ when waiting on the fork of "xscreensaver-getimage"
+ OSX: this is the xscreensaver_getimage_file_cb closure,
+ when waiting on the fork of "xscreensaver-getimage-file"
+ */
+typedef struct {
+ void (*callback) (Screen *, Window, Drawable,
+ const char *name, XRectangle *geom, void *closure);
+ Screen *screen;
+ Window window;
+ Drawable drawable;
+ void *closure;
+ XtInputId pipe_id;
+ FILE *pipe;
+
+# if !defined(USE_IPHONE) && !defined(HAVE_COCOA) /* Real X11 */
+ pid_t pid;
+# endif
+
+# if !defined(USE_IPHONE) && defined(HAVE_COCOA) /* Desktop OSX */
+ char *directory;
+# endif
+
+} xscreensaver_getimage_data;
+
+
+#if !defined(HAVE_COCOA) && !defined(HAVE_ANDROID) /* Real X11 */
+
+static Bool error_handler_hit_p = False;
+
+static int
+ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
+{
+ error_handler_hit_p = True;
+ return 0;
+}
+
+
+/* Returns True if the given Drawable is a Window; False if it's a Pixmap.
+ */
+static Bool
+drawable_window_p (Display *dpy, Drawable d)
+{
+ XErrorHandler old_handler;
+ XWindowAttributes xgwa;
+
+ XSync (dpy, False);
+ old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
+ error_handler_hit_p = False;
+ XGetWindowAttributes (dpy, d, &xgwa);
+ XSync (dpy, False);
+ XSetErrorHandler (old_handler);
+ XSync (dpy, False);
+
+ if (!error_handler_hit_p)
+ return True; /* It's a Window. */
+ else
+ return False; /* It's a Pixmap, or an invalid ID. */
+}
+
+
+static Bool
+xscreensaver_window_p (Display *dpy, Window window)
+{
+ Atom type;
+ int format;
+ unsigned long nitems, bytesafter;
+ unsigned char *version;
+ if (XGetWindowProperty (dpy, window,
+ XInternAtom (dpy, "_SCREENSAVER_VERSION", False),
+ 0, 1, False, XA_STRING,
+ &type, &format, &nitems, &bytesafter,
+ &version)
+ == Success
+ && type != None)
+ return True;
+ return False;
+}
+
+
+/* XCopyArea seems not to work right on SGI O2s if you draw in SubwindowMode
+ on a window whose depth is not the maximal depth of the screen? Or
+ something. Anyway, things don't work unless we: use SubwindowMode for
+ the real root window (or a legitimate virtual root window); but do not
+ use SubwindowMode for the xscreensaver window. I make no attempt to
+ explain.
+ */
+Bool
+use_subwindow_mode_p (Screen *screen, Window window)
+{
+ if (window != VirtualRootWindowOfScreen(screen))
+ return False;
+ else if (xscreensaver_window_p(DisplayOfScreen(screen), window))
+ return False;
+ else
+ return True;
+}
+
+
+static void
+checkerboard (Screen *screen, Drawable drawable)
+{
+ Display *dpy = DisplayOfScreen (screen);
+ unsigned int x, y;
+ int size = 24;
+ XColor fg, bg;
+ XGCValues gcv;
+ GC gc = XCreateGC (dpy, drawable, 0, &gcv);
+ Colormap cmap;
+ unsigned int win_width, win_height;
+
+ fg.flags = bg.flags = DoRed|DoGreen|DoBlue;
+ fg.red = fg.green = fg.blue = 0x0000;
+ bg.red = bg.green = bg.blue = 0x4444;
+ fg.pixel = 0;
+ bg.pixel = 1;
+
+ if (drawable_window_p (dpy, drawable))
+ {
+ XWindowAttributes xgwa;
+ XGetWindowAttributes (dpy, drawable, &xgwa);
+ win_width = xgwa.width;
+ win_height = xgwa.height;
+ cmap = xgwa.colormap;
+ screen = xgwa.screen;
+ }
+ else /* it's a pixmap */
+ {
+ XWindowAttributes xgwa;
+ Window root;
+ int x, y;
+ unsigned int bw, d;
+ XGetWindowAttributes (dpy, RootWindowOfScreen (screen), &xgwa);
+ cmap = xgwa.colormap;
+ XGetGeometry (dpy, drawable,
+ &root, &x, &y, &win_width, &win_height, &bw, &d);
+ }
+
+ /* Allocate black and gray, but don't hold them locked. */
+ if (XAllocColor (dpy, cmap, &fg))
+ XFreeColors (dpy, cmap, &fg.pixel, 1, 0);
+ if (XAllocColor (dpy, cmap, &bg))
+ XFreeColors (dpy, cmap, &bg.pixel, 1, 0);
+
+ XSetForeground (dpy, gc, bg.pixel);
+ XFillRectangle (dpy, drawable, gc, 0, 0, win_width, win_height);
+ XSetForeground (dpy, gc, fg.pixel);
+ for (y = 0; y < win_height; y += size+size)
+ for (x = 0; x < win_width; x += size+size)
+ {
+ XFillRectangle (dpy, drawable, gc, x, y, size, size);
+ XFillRectangle (dpy, drawable, gc, x+size, y+size, size, size);
+ }
+ XFreeGC (dpy, gc);
+}
+
+
+/* Read the image's original name off of the window's X properties.
+ Used only when running "real" X11, not jwxyz.
+ */
+static char *
+get_name_from_xprops (Display *dpy, Window window)
+{
+ Atom type;
+ int format;
+ unsigned long nitems, bytesafter;
+ unsigned char *name = 0;
+ Atom atom = XInternAtom (dpy, XA_XSCREENSAVER_IMAGE_FILENAME, False);
+ if (XGetWindowProperty (dpy, window, atom,
+ 0, 1024, False, XA_STRING,
+ &type, &format, &nitems, &bytesafter,
+ &name)
+ == Success
+ && type != None)
+ return (char *) name;
+ else
+ return 0;
+}
+
+
+/* Read the image's original geometry off of the window's X properties.
+ Used only when running "real" X11, not jwxyz.
+ */
+static Bool
+get_original_geometry_from_xprops (Display *dpy, Window window, XRectangle *ret)
+{
+ Atom type;
+ int format;
+ unsigned long nitems, bytesafter;
+ unsigned char *name = 0;
+ Atom atom = XInternAtom (dpy, XA_XSCREENSAVER_IMAGE_GEOMETRY, False);
+ int x, y;
+ unsigned int w, h;
+ if (XGetWindowProperty (dpy, window, atom,
+ 0, 1024, False, XA_STRING,
+ &type, &format, &nitems, &bytesafter,
+ &name)
+ == Success
+ && type != None)
+ {
+ int flags = XParseGeometry ((char *) name, &x, &y, &w, &h);
+ free (name);
+ /* Require all four, and don't allow negative positions. */
+ if (flags == (XValue|YValue|WidthValue|HeightValue))
+ {
+ ret->x = x;
+ ret->y = y;
+ ret->width = w;
+ ret->height = h;
+ return True;
+ }
+ else
+ return False;
+ }
+ else
+ return False;
+}
+
+
+static void
+hack_subproc_environment (Display *dpy)
+{
+ /* Store $DISPLAY into the environment, so that the $DISPLAY variable that
+ the spawned processes inherit is what we are actually using.
+ */
+ const char *odpy = DisplayString (dpy);
+ char *ndpy = (char *) malloc(strlen(odpy) + 20);
+ strcpy (ndpy, "DISPLAY=");
+ strcat (ndpy, odpy);
+
+ /* Allegedly, BSD 4.3 didn't have putenv(), but nobody runs such systems
+ any more, right? It's not Posix, but everyone seems to have it. */
+# ifdef HAVE_PUTENV
+ if (putenv (ndpy))
+ abort ();
+# endif /* HAVE_PUTENV */
+
+ /* don't free (ndpy) -- some implementations of putenv (BSD 4.4,
+ glibc 2.0) copy the argument, but some (libc4,5, glibc 2.1.2, MacOS)
+ do not. So we must leak it (and/or the previous setting). Yay.
+ */
+}
+
+
+/* Spawn a program, and wait for it to finish.
+ If we just use system() for this, then sometimes the subprocess
+ doesn't die when *this* process is sent a TERM signal. Perhaps
+ this is due to the intermediate /bin/sh that system() uses to
+ parse arguments? I'm not sure. But using fork() and execvp()
+ here seems to close the race.
+
+ Used to execute "xscreensaver-getimage".
+ Used only when running "real" X11, not jwxyz.
+ */
+static void
+exec_simple_command (const char *command)
+{
+ char *av[1024];
+ int ac = 0;
+ char *token = strtok (strdup(command), " \t");
+ while (token)
+ {
+ av[ac++] = token;
+ token = strtok(0, " \t");
+ }
+ av[ac] = 0;
+
+ execvp (av[0], av); /* shouldn't return. */
+}
+
+
+static void xscreensaver_getimage_cb (XtPointer closure,
+ int *fd, XtIntervalId *id);
+
+/* Spawn a program, and run the callback when it finishes.
+ Used to execute "xscreensaver-getimage".
+ Used only when running "real" X11, not jwxyz.
+ */
+static void
+fork_exec_cb (const char *command,
+ Screen *screen, Window window, Drawable drawable,
+ void (*callback) (Screen *, Window, Drawable,
+ const char *name, XRectangle *geom,
+ void *closure),
+ void *closure)
+{
+ XtAppContext app = XtDisplayToApplicationContext (DisplayOfScreen (screen));
+ xscreensaver_getimage_data *data;
+ char buf [255];
+ pid_t forked;
+ FILE *wpipe;
+
+ int fds [2];
+
+ if (pipe (fds))
+ {
+ sprintf (buf, "%s: creating pipe", progname);
+ perror (buf);
+ exit (1);
+ }
+
+ data = (xscreensaver_getimage_data *) calloc (1, sizeof(*data));
+ data->callback = callback;
+ data->closure = closure;
+ data->screen = screen;
+ data->window = window;
+ data->drawable = drawable;
+ data->pipe = fdopen (fds[0], "r");
+ wpipe = fdopen (fds[1], "w"); /* Is this necessary? */
+
+ if (!data->pipe || !wpipe)
+ {
+ sprintf (buf, "%s: fdopen", progname);
+ perror (buf);
+ exit (1);
+ }
+
+ data->pipe_id =
+ XtAppAddInput (app, fileno (data->pipe),
+ (XtPointer) (XtInputReadMask | XtInputExceptMask),
+ xscreensaver_getimage_cb, (XtPointer) data);
+
+ forked = fork ();
+ switch ((int) forked)
+ {
+ case -1:
+ sprintf (buf, "%s: couldn't fork", progname);
+ perror (buf);
+ return;
+
+ case 0: /* child */
+
+ fclose (data->pipe);
+ data->pipe = 0;
+
+ /* clone the write pipe onto stdout so that it gets closed
+ when the fork exits. This will shut down the pipe and
+ signal the parent.
+ */
+ close (fileno (stdout));
+ dup2 (fds[1], fileno (stdout));
+ close (fds[1]);
+
+ close (fileno (stdin)); /* for kicks */
+
+ exec_simple_command (command);
+ exit (1); /* exits child fork */
+ break;
+
+ default: /* parent */
+ fclose (wpipe);
+ data->pid = forked;
+ break;
+ }
+}
+
+
+/* Called in the parent when the forked process dies.
+ Runs the caller's callback, and cleans up.
+ This runs when "xscreensaver-getimage" exits.
+ Used only when running "real" X11, not jwxyz.
+ */
+static void
+xscreensaver_getimage_cb (XtPointer closure, int *fd, XtIntervalId *id)
+{
+ xscreensaver_getimage_data *data = (xscreensaver_getimage_data *) closure;
+ Display *dpy = DisplayOfScreen (data->screen);
+ char *name;
+ XRectangle geom = { 0, 0, 0, 0 };
+
+ XtRemoveInput (*id);
+
+ name = get_name_from_xprops (dpy, data->window);
+ get_original_geometry_from_xprops (dpy, data->window, &geom);
+
+ data->callback (data->screen, data->window, data->drawable,
+ name, &geom, data->closure);
+ if (name) free (name);
+
+ fclose (data->pipe);
+
+ if (data->pid) /* reap zombies */
+ {
+ int status;
+ waitpid (data->pid, &status, 0);
+ data->pid = 0;
+ }
+
+ memset (data, 0, sizeof (*data));
+ free (data);
+}
+
+
+/* Loads an image into the Drawable.
+ When grabbing desktop images, the Window will be unmapped first.
+ Used only when running "real" X11, not jwxyz.
+ */
+static void
+load_random_image_x11 (Screen *screen, Window window, Drawable drawable,
+ void (*callback) (Screen *, Window, Drawable,
+ const char *name, XRectangle *geom,
+ void *closure),
+ void *closure)
+{
+ Display *dpy = DisplayOfScreen (screen);
+ char *grabber = get_string_resource(dpy, "desktopGrabber", "DesktopGrabber");
+ char *cmd;
+ char id[200];
+
+ if (!grabber || !*grabber)
+ {
+ fprintf (stderr,
+ "%s: resources installed incorrectly: \"desktopGrabber\" is unset!\n",
+ progname);
+ exit (1);
+ }
+
+ sprintf (id, "0x%lx 0x%lx",
+ (unsigned long) window,
+ (unsigned long) drawable);
+ cmd = (char *) malloc (strlen(grabber) + strlen(id) + 1);
+
+ /* Needn't worry about buffer overflows here, because the buffer is
+ longer than the length of the format string, and the length of what
+ we're putting into it. So the only way to crash would be if the
+ format string itself was corrupted, but that comes from the
+ resource database, and if hostile forces have access to that,
+ then the game is already over.
+ */
+ sprintf (cmd, grabber, id);
+ free (grabber);
+ grabber = 0;
+
+ /* In case "cmd" fails, leave some random image on the screen, not just
+ black or white, so that it's more obvious what went wrong. */
+ checkerboard (screen, drawable);
+ if (window == drawable)
+ print_loading_msg (screen, window);
+
+ XSync (dpy, True);
+ hack_subproc_environment (dpy);
+
+ /* Start the image loading in another fork and return immediately.
+ Invoke the callback function when done. */
+ fork_exec_cb (cmd, screen, window, drawable, callback, closure);
+
+ free (cmd);
+ XSync (dpy, True);
+}
+
+#elif defined (HAVE_COCOA) /* OSX or iOS */
+
+# ifndef USE_IPHONE /* HAVE_COCOA && !USE_IPHONE -- desktop OSX */
+
+# define BACKSLASH(c) \
+ (! ((c >= 'a' && c <= 'z') || \
+ (c >= 'A' && c <= 'Z') || \
+ (c >= '0' && c <= '9') || \
+ c == '.' || c == '_' || c == '-' || c == '+' || c == '/'))
+
+/* Gets the name of an image file to load by running xscreensaver-getimage-file
+ at the end of a pipe. This can be very slow!
+ */
+static FILE *
+open_image_name_pipe (const char *dir)
+{
+ char *s;
+
+ /* /bin/sh on OS X 10.10 wipes out the PATH. */
+ const char *path = getenv("PATH");
+ char *cmd = s = malloc ((strlen(dir) + strlen(path)) * 2 + 100);
+ strcpy (s, "/bin/sh -c 'export PATH=");
+ s += strlen (s);
+ while (*path) {
+ char c = *path++;
+ if (BACKSLASH(c)) *s++ = '\\';
+ *s++ = c;
+ }
+ strcpy (s, "; ");
+ s += strlen (s);
+
+ strcpy (s, "xscreensaver-getimage-file --name ");
+ s += strlen (s);
+ while (*dir) {
+ char c = *dir++;
+ if (BACKSLASH(c)) *s++ = '\\';
+ *s++ = c;
+ }
+
+ strcpy (s, "'");
+ s += strlen (s);
+
+ *s = 0;
+
+ FILE *pipe = popen (cmd, "r");
+ free (cmd);
+ return pipe;
+}
+
+
+static void
+xscreensaver_getimage_file_cb (XtPointer closure, int *source, XtInputId *id)
+{
+ /* This is not called from a signal handler, so doing stuff here is fine.
+ */
+ xscreensaver_getimage_data *clo2 = (xscreensaver_getimage_data *) closure;
+ char buf[10240];
+ const char *dir = clo2->directory;
+ char *absfile = 0;
+ *buf = 0;
+ fgets (buf, sizeof(buf)-1, clo2->pipe);
+ pclose (clo2->pipe);
+ clo2->pipe = 0;
+ XtRemoveInput (clo2->pipe_id);
+ clo2->pipe_id = 0;
+
+ /* strip trailing newline */
+ int L = strlen(buf);
+ while (L > 0 && (buf[L-1] == '\r' || buf[L-1] == '\n'))
+ buf[--L] = 0;
+
+ Display *dpy = DisplayOfScreen (clo2->screen);
+ XRectangle geom;
+
+ if (*buf && *buf != '/') /* pathname is relative to dir. */
+ {
+ absfile = malloc (strlen(dir) + strlen(buf) + 10);
+ strcpy (absfile, dir);
+ if (dir[strlen(dir)-1] != '/')
+ strcat (absfile, "/");
+ strcat (absfile, buf);
+ }
+
+ if (! osx_load_image_file (clo2->screen, clo2->window, clo2->drawable,
+ (absfile ? absfile : buf), &geom)) {
+ /* unable to load image - draw colorbars
+ */
+ XWindowAttributes xgwa;
+ XGetWindowAttributes (dpy, clo2->window, &xgwa);
+ Window r;
+ int x, y;
+ unsigned int w, h, bbw, d;
+ struct stat st;
+
+ /* Log something to syslog so we can tell the difference between
+ corrupted images and broken symlinks. */
+ if (!*buf)
+ fprintf (stderr, "%s: no image filename found\n", progname);
+ else if (! stat (buf, &st))
+ fprintf (stderr, "%s: %s: unparsable\n", progname, buf);
+ else
+ {
+ char buf2[2048];
+ sprintf (buf2, "%.255s: %.1024s", progname, buf);
+ perror (buf2);
+ }
+
+ XGetGeometry (dpy, clo2->drawable, &r, &x, &y, &w, &h, &bbw, &d);
+ draw_colorbars (clo2->screen, xgwa.visual, clo2->drawable, xgwa.colormap,
+ 0, 0, w, h, 0, 0); /* #### logo missing */
+ geom.x = geom.y = 0;
+ geom.width = w;
+ geom.height = h;
+ }
+
+ /* Take the extension off of the file name. */
+ /* Duplicated in driver/xscreensaver-getimage.c. */
+ if (*buf)
+ {
+ char *slash = strrchr (buf, '/');
+ char *dot = strrchr ((slash ? slash : buf), '.');
+ if (dot) *dot = 0;
+ /* Replace slashes with newlines */
+ /* while (dot = strchr(buf, '/')) *dot = '\n'; */
+ /* Replace slashes with spaces */
+ /* while ((dot = strchr(buf, '/'))) *dot = ' '; */
+ }
+
+ if (absfile) free (absfile);
+ clo2->callback (clo2->screen, clo2->window, clo2->drawable, buf, &geom,
+ clo2->closure);
+ clo2->callback = 0;
+ free (clo2->directory);
+ free (clo2);
+}
+
+
+# else /* HAVE_COCOA && USE_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.
+ */
+static void
+ios_load_random_image_cb (void *uiimage, const char *filename,
+ int width, int height, void *closure)
+{
+ xscreensaver_getimage_data *clo2 = (xscreensaver_getimage_data *) closure;
+ Display *dpy = DisplayOfScreen (clo2->screen);
+ XRectangle geom;
+ XWindowAttributes xgwa;
+ Window r;
+ int x, y;
+ unsigned int w, h, bbw, d;
+ int rot = 0;
+
+ XGetWindowAttributes (dpy, clo2->window, &xgwa);
+ XGetGeometry (dpy, clo2->drawable, &r, &x, &y, &w, &h, &bbw, &d);
+
+ /* If the image is portrait and the window is landscape, or vice versa,
+ rotate the image. The idea is to fill up as many pixels as possible,
+ and assume the user will just rotate their phone until it looks right.
+ This makes "decayscreen", etc. much more easily viewable.
+ */
+ if (get_boolean_resource (dpy, "rotateImages", "RotateImages")) {
+ if ((width > height) != (w > h))
+ rot = 5;
+ }
+
+ if (uiimage)
+ {
+ jwxyz_draw_NSImage_or_CGImage (DisplayOfScreen (clo2->screen),
+ clo2->drawable,
+ True, uiimage, &geom,
+ rot);
+ }
+ else /* Probably means no images in the gallery. */
+ {
+ draw_colorbars (clo2->screen, xgwa.visual, clo2->drawable, xgwa.colormap,
+ 0, 0, w, h, 0, 0); /* #### logo missing */
+ geom.x = geom.y = 0;
+ geom.width = w;
+ geom.height = h;
+ filename = 0;
+ }
+
+ clo2->callback (clo2->screen, clo2->window, clo2->drawable,
+ filename, &geom, clo2->closure);
+ clo2->callback = 0;
+ free (clo2);
+}
+
+# endif /* HAVE_COCOA && USE_IPHONE */
+
+
+static void
+osx_load_image_file_async (Screen *screen, Window xwindow, Drawable drawable,
+ const char *dir,
+ void (*callback) (Screen *, Window, Drawable,
+ const char *name,
+ XRectangle *geom,
+ void *closure),
+ void *closure)
+{
+ xscreensaver_getimage_data *clo2 =
+ (xscreensaver_getimage_data *) calloc (1, sizeof(*clo2));
+
+ clo2->screen = screen;
+ clo2->window = xwindow;
+ clo2->drawable = drawable;
+ clo2->callback = callback;
+ clo2->closure = closure;
+
+# ifndef USE_IPHONE /* Desktop OSX */
+ clo2->directory = strdup (dir);
+ clo2->pipe = open_image_name_pipe (dir);
+ clo2->pipe_id = XtAppAddInput (XtDisplayToApplicationContext (
+ DisplayOfScreen (screen)),
+ fileno (clo2->pipe),
+ (XtPointer) (XtInputReadMask | XtInputExceptMask),
+ xscreensaver_getimage_file_cb, (XtPointer) clo2);
+# else /* USE_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 */
+}
+
+
+/* Loads an image into the Drawable, returning once the image is loaded.
+ */
+static void
+load_random_image_cocoa (Screen *screen, Window window, Drawable drawable,
+ void (*callback) (Screen *, Window, Drawable,
+ const char *name, XRectangle *geom,
+ void *closure),
+ void *closure)
+{
+ Display *dpy = DisplayOfScreen (screen);
+ XWindowAttributes xgwa;
+ Bool deskp = get_boolean_resource (dpy, "grabDesktopImages", "Boolean");
+ Bool filep = get_boolean_resource (dpy, "chooseRandomImages", "Boolean");
+ const char *dir = 0;
+ Bool done = False;
+ XRectangle geom;
+ char *name = 0;
+
+ if (!drawable) abort();
+
+ XGetWindowAttributes (dpy, window, &xgwa);
+ {
+ Window r;
+ int x, y;
+ unsigned int w, h, bbw, d;
+ XGetGeometry (dpy, drawable, &r, &x, &y, &w, &h, &bbw, &d);
+ xgwa.width = w;
+ xgwa.height = h;
+ }
+
+ geom.x = 0;
+ geom.y = 0;
+ geom.width = xgwa.width;
+ geom.height = xgwa.height;
+
+# ifndef USE_IPHONE
+ if (filep)
+ dir = get_string_resource (dpy, "imageDirectory", "ImageDirectory");
+
+ if (!dir || !*dir)
+ filep = False;
+# endif /* ! USE_IPHONE */
+
+ if (deskp && filep) {
+ deskp = !(random() & 5); /* if both, desktop 1/5th of the time */
+ filep = !deskp;
+ }
+
+ if (filep && !done) {
+ osx_load_image_file_async (screen, window, drawable, dir,
+ callback, closure);
+ return;
+ }
+
+ if (deskp && !done) {
+ if (osx_grab_desktop_image (screen, window, drawable, &geom)) {
+ name = strdup ("desktop");
+ done = True;
+ }
+ }
+
+ if (! done)
+ draw_colorbars (screen, xgwa.visual, drawable, xgwa.colormap, 0, 0,
+ xgwa.width, xgwa.height, 0, 0); /* #### logo missing */
+
+ /* If we got here, we loaded synchronously, so we're done. */
+ callback (screen, window, drawable, name, &geom, closure);
+ if (name) free (name);
+}
+
+
+#elif defined(HAVE_ANDROID)
+
+/* Loads an image into the Drawable, returning once the image is loaded.
+ */
+static void
+load_random_image_android (Screen *screen, Window window, Drawable drawable,
+ void (*callback) (Screen *, Window, Drawable,
+ const char *name,
+ XRectangle *geom, void *closure),
+ void *closure)
+{
+ Display *dpy = DisplayOfScreen (screen);
+ XWindowAttributes xgwa;
+ XRectangle geom;
+
+ if (!drawable) abort();
+
+ XGetWindowAttributes (dpy, window, &xgwa);
+ {
+ Window r;
+ int x, y;
+ unsigned int w, h, bbw, d;
+ XGetGeometry (dpy, drawable, &r, &x, &y, &w, &h, &bbw, &d);
+ xgwa.width = w;
+ xgwa.height = h;
+ }
+
+ geom.x = 0;
+ geom.y = 0;
+ geom.width = xgwa.width;
+ geom.height = xgwa.height;
+
+ XGCValues gcv;
+ gcv.foreground = BlackPixelOfScreen (screen);
+ GC gc = XCreateGC (dpy, drawable, GCForeground, &gcv);
+ XFillRectangle (dpy, drawable, gc, 0, 0, xgwa.width, xgwa.height);
+ char *name = jwxyz_draw_random_image (dpy, drawable, gc);
+ if (! name) {
+ draw_colorbars (screen, xgwa.visual, drawable, xgwa.colormap, 0, 0,
+ xgwa.width, xgwa.height, 0, 0); /* #### logo missing */
+ }
+ XFreeGC (dpy, gc);
+
+ callback (screen, window, drawable, name, &geom, closure);
+ if (name) free (name);
+}
+
+#endif /* HAVE_ANDROID */
+
+
+
+/* Writes the string "Loading..." in the middle of the screen.
+ This will presumably get blown away when the image finally loads,
+ minutes or hours later...
+
+ This is called by load_image_async_simple() but not by load_image_async(),
+ since it is assumed that hacks that are loading more than one image
+ *at one time* will be doing something more clever than just blocking
+ with a blank screen.
+ */
+static void
+print_loading_msg (Screen *screen, Window window)
+{
+ Display *dpy = DisplayOfScreen (screen);
+ XWindowAttributes xgwa;
+ XGCValues gcv;
+ XFontStruct *f = 0;
+ GC gc;
+ char *fn = get_string_resource (dpy, "labelFont", "Font");
+ const char *text = "Loading...";
+ int w;
+
+ if (!fn) fn = get_string_resource (dpy, "titleFont", "Font");
+ if (!fn) fn = get_string_resource (dpy, "font", "Font");
+ if (!fn) fn = strdup ("-*-times-bold-r-normal-*-180-*");
+ f = XLoadQueryFont (dpy, fn);
+ if (!f) f = XLoadQueryFont (dpy, "fixed");
+ if (!f) abort();
+ free (fn);
+ fn = 0;
+
+ XGetWindowAttributes (dpy, window, &xgwa);
+ w = XTextWidth (f, text, (int) strlen(text));
+
+ gcv.foreground = get_pixel_resource (dpy, xgwa.colormap,
+ "foreground", "Foreground");
+ gcv.background = get_pixel_resource (dpy, xgwa.colormap,
+ "background", "Background");
+ gcv.font = f->fid;
+ gc = XCreateGC (dpy, window, GCFont | GCForeground | GCBackground, &gcv);
+ XDrawImageString (dpy, window, gc,
+ (xgwa.width - w) / 2,
+ (xgwa.height - (f->ascent + f->descent)) / 2 + f->ascent,
+ text, (int) strlen(text));
+ XFreeFont (dpy, f);
+ XFreeGC (dpy, gc);
+ XSync (dpy, False);
+}
+
+
+/* Loads an image into the Drawable in the background;
+ when the image is fully loaded, runs the callback.
+ When grabbing desktop images, the Window will be unmapped first.
+ */
+void
+load_image_async (Screen *screen, Window window, Drawable drawable,
+ void (*callback) (Screen *, Window, Drawable,
+ const char *name, XRectangle *geom,
+ void *closure),
+ void *closure)
+{
+ if (!callback) abort();
+# if defined(HAVE_COCOA)
+ load_random_image_cocoa (screen, window, drawable, callback, closure);
+# elif defined(HAVE_ANDROID)
+ load_random_image_android (screen, window, drawable, callback, closure);
+# else /* real X11 */
+ load_random_image_x11 (screen, window, drawable, callback, closure);
+# endif
+}
+
+struct async_load_state {
+ Bool done_p;
+ char *filename;
+ XRectangle geom;
+};
+
+static void
+load_image_async_simple_cb (Screen *screen, Window window, Drawable drawable,
+ const char *name, XRectangle *geom, void *closure)
+{
+ async_load_state *state = (async_load_state *) closure;
+ state->done_p = True;
+ state->filename = (name ? strdup (name) : 0);
+ state->geom = *geom;
+}
+
+async_load_state *
+load_image_async_simple (async_load_state *state,
+ Screen *screen,
+ Window window,
+ Drawable drawable,
+ char **filename_ret,
+ XRectangle *geometry_ret)
+{
+ if (state && state->done_p) /* done! */
+ {
+ if (filename_ret)
+ *filename_ret = state->filename;
+ else if (state->filename)
+ free (state->filename);
+
+ if (geometry_ret)
+ *geometry_ret = state->geom;
+
+ free (state);
+ return 0;
+ }
+ else if (! state) /* first time */
+ {
+ state = (async_load_state *) calloc (1, sizeof(*state));
+ state->done_p = False;
+ print_loading_msg (screen, window);
+ load_image_async (screen, window, drawable,
+ load_image_async_simple_cb,
+ state);
+ return state;
+ }
+ else /* still waiting */
+ return state;
+}
diff --git a/utils/grabscreen.c b/utils/grabscreen.c
new file mode 100644
index 0000000..77fe3c9
--- /dev/null
+++ b/utils/grabscreen.c
@@ -0,0 +1,937 @@
+/* xscreensaver, Copyright (c) 1992-2016 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.
+ */
+
+/* This file contains code for grabbing an image of the screen to hack its
+ bits. This is a little tricky, since doing this involves the need to tell
+ the difference between drawing on the actual root window, and on the fake
+ root window used by the screensaver, since at this level the illusion
+ breaks down...
+
+ The hacks themselves use utils/grabclient.c to invoke the
+ "xscreensaver-getimage" program as a sub-process.
+
+ On "real" X11 systems:
+
+ "driver/xscreensaver-getimage" runs the code in this file to grab
+ the X11 root window image as a Pixmap.
+
+ 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.
+
+ On MacOS systems running the native Cocoa build, or on iOS or Android
+ systems:
+
+ "driver/xscreensaver-getimage" is not used. Instead, each saver's
+ "utils/grabclient.c" links against "OSX/grabclient-osx.m",
+ "OSX/grabclient-ios.m" or "jwxyz/jwxyz-android.c" to grab
+ screenshots directly without invoking a sub-process to do it.
+
+ See the comment at the top of utils/grabclient.c for a more detailed
+ explanation.
+ */
+
+#include "utils.h"
+#include "yarandom.h"
+
+#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"
+#include "visual.h"
+#include "resources.h"
+
+#include "vroot.h"
+#undef RootWindowOfScreen
+#undef RootWindow
+#undef DefaultRootWindow
+
+
+#ifdef HAVE_READ_DISPLAY_EXTENSION
+# include <X11/extensions/readdisplay.h>
+ static Bool read_display (Screen *, Window, Pixmap, Bool);
+#endif /* HAVE_READ_DISPLAY_EXTENSION */
+
+
+static void copy_default_colormap_contents (Screen *, Colormap, Visual *);
+
+#ifdef HAVE_READ_DISPLAY_EXTENSION
+static void allocate_cubic_colormap (Screen *, Window, Visual *);
+void remap_image (Screen *, Window, Colormap, XImage *);
+#endif
+
+
+static Bool
+MapNotify_event_p (Display *dpy, XEvent *event, XPointer window)
+{
+ return (event->xany.type == MapNotify &&
+ event->xvisibility.window == (Window) window);
+}
+
+extern char *progname;
+Bool grab_verbose_p = False;
+
+void
+grabscreen_verbose(void)
+{
+ grab_verbose_p = True;
+}
+
+
+static void
+raise_window(Display *dpy, Window window, Bool dont_wait)
+{
+ if (grab_verbose_p)
+ fprintf(stderr, "%s: raising window 0x%08lX (%s)\n",
+ progname, (unsigned long) window,
+ (dont_wait ? "not waiting" : "waiting"));
+
+ if (! dont_wait)
+ {
+ XWindowAttributes xgwa;
+ XSizeHints hints;
+ long supplied = 0;
+ memset(&hints, 0, sizeof(hints));
+ XGetWMNormalHints(dpy, window, &hints, &supplied);
+ XGetWindowAttributes (dpy, window, &xgwa);
+ hints.x = xgwa.x;
+ hints.y = xgwa.y;
+ hints.width = xgwa.width;
+ hints.height = xgwa.height;
+ hints.flags |= (PPosition|USPosition|PSize|USSize);
+ XSetWMNormalHints(dpy, window, &hints);
+
+ XSelectInput (dpy, window, (xgwa.your_event_mask | StructureNotifyMask));
+ }
+
+ XMapRaised(dpy, window);
+
+ if (! dont_wait)
+ {
+ XEvent event;
+ XIfEvent (dpy, &event, MapNotify_event_p, (XPointer) window);
+ XSync (dpy, True);
+ }
+}
+
+
+static Bool
+xscreensaver_window_p (Display *dpy, Window window)
+{
+ Atom type;
+ int format;
+ unsigned long nitems, bytesafter;
+ unsigned char *version;
+ if (XGetWindowProperty (dpy, window,
+ XInternAtom (dpy, "_SCREENSAVER_VERSION", False),
+ 0, 1, False, XA_STRING,
+ &type, &format, &nitems, &bytesafter,
+ &version)
+ == Success
+ && type != None)
+ return True;
+ return False;
+}
+
+
+
+/* Whether the given window is:
+ - the real root window;
+ - a direct child of the root window;
+ - a direct child of the window manager's decorations.
+ */
+Bool
+top_level_window_p (Screen *screen, Window window)
+{
+ Display *dpy = DisplayOfScreen (screen);
+ Window root, parent, *kids;
+ unsigned int nkids;
+
+ if (!XQueryTree (dpy, window, &root, &parent, &kids, &nkids))
+ return False;
+
+ if (window == root)
+ return True;
+
+ /* If our direct parent is the real root window, then yes. */
+ if (parent == root)
+ return True;
+ else
+ {
+ Atom type = None;
+ int format;
+ unsigned long nitems, bytesafter;
+ unsigned char *data;
+
+ /* If our direct parent has the WM_STATE property, then it is a
+ window manager decoration -- yes.
+ */
+ if (XGetWindowProperty (dpy, window,
+ XInternAtom (dpy, "WM_STATE", True),
+ 0, 0, False, AnyPropertyType,
+ &type, &format, &nitems, &bytesafter,
+ (unsigned char **) &data)
+ == Success
+ && type != None)
+ return True;
+ }
+
+ /* Else, no. We're deep in a tree somewhere.
+ */
+ return False;
+}
+
+
+static Bool error_handler_hit_p = False;
+static XErrorHandler old_ehandler = 0;
+static int
+BadWindow_ehandler (Display *dpy, XErrorEvent *error)
+{
+ error_handler_hit_p = True;
+ if (error->error_code == BadWindow || error->error_code == BadDrawable)
+ return 0;
+ else if (!old_ehandler)
+ {
+ abort();
+ return 0;
+ }
+ else
+ return (*old_ehandler) (dpy, error);
+}
+
+
+/* XCopyArea seems not to work right on SGI O2s if you draw in SubwindowMode
+ on a window whose depth is not the maximal depth of the screen? Or
+ something. Anyway, things don't work unless we: use SubwindowMode for
+ the real root window (or a legitimate virtual root window); but do not
+ use SubwindowMode for the xscreensaver window. I make no attempt to
+ explain.
+ */
+Bool
+use_subwindow_mode_p(Screen *screen, Window window)
+{
+ if (window != VirtualRootWindowOfScreen(screen))
+ return False;
+ else if (xscreensaver_window_p(DisplayOfScreen(screen), window))
+ return False;
+ else
+ return True;
+}
+
+
+/* Install the colormaps of all visible windows, deepest first.
+ This should leave the colormaps of the topmost windows installed
+ (if only N colormaps can be installed at a time, then only the
+ topmost N windows will be shown in the right colors.)
+ */
+static void
+install_screen_colormaps (Screen *screen)
+{
+ unsigned int i;
+ Display *dpy = DisplayOfScreen (screen);
+ Window real_root;
+ Window parent, *kids = 0;
+ unsigned int nkids = 0;
+
+ XSync (dpy, False);
+ old_ehandler = XSetErrorHandler (BadWindow_ehandler);
+ error_handler_hit_p = False;
+
+ real_root = XRootWindowOfScreen (screen); /* not vroot */
+ if (XQueryTree (dpy, real_root, &real_root, &parent, &kids, &nkids))
+ for (i = 0; i < nkids; i++)
+ {
+ XWindowAttributes xgwa;
+ Window client;
+#ifdef HAVE_XMU
+ /* #### need to put XmuClientWindow() in xmu.c, sigh... */
+ if (! (client = XmuClientWindow (dpy, kids[i])))
+#endif
+ client = kids[i];
+ xgwa.colormap = 0;
+ XGetWindowAttributes (dpy, client, &xgwa);
+ if (xgwa.colormap && xgwa.map_state == IsViewable)
+ XInstallColormap (dpy, xgwa.colormap);
+ }
+ XInstallColormap (dpy, DefaultColormapOfScreen (screen));
+ XSync (dpy, False);
+ XSetErrorHandler (old_ehandler);
+ XSync (dpy, False);
+
+ if (kids)
+ XFree ((char *) kids);
+}
+
+
+void
+grab_screen_image_internal (Screen *screen, Window window)
+{
+ Display *dpy = DisplayOfScreen (screen);
+ XWindowAttributes xgwa;
+ Window real_root;
+ Bool root_p;
+ Bool saver_p;
+ Bool grab_mouse_p = False;
+ int unmap_time = 0;
+
+ real_root = XRootWindowOfScreen (screen); /* not vroot */
+ root_p = (window == real_root);
+ saver_p = xscreensaver_window_p (dpy, window);
+
+ XGetWindowAttributes (dpy, window, &xgwa);
+ screen = xgwa.screen;
+
+ if (saver_p)
+ /* I think this is redundant, but just to be safe... */
+ root_p = False;
+
+ if (saver_p)
+ /* The only time grabbing the mouse is important is if this program
+ is being run while the saver is locking the screen. */
+ grab_mouse_p = True;
+
+ if (!root_p)
+ {
+ double unmap = 0;
+ if (saver_p)
+ {
+ unmap = get_float_resource(dpy, "grabRootDelay", "Seconds");
+ if (unmap <= 0.00001 || unmap > 20) unmap = 2.5;
+ }
+ else
+ {
+ unmap = get_float_resource(dpy, "grabWindowDelay", "Seconds");
+ if (unmap <= 0.00001 || unmap > 20) unmap = 0.66;
+ }
+ unmap_time = unmap * 100000;
+ }
+
+ if (grab_verbose_p)
+ {
+ fprintf(stderr,
+ "\n%s: window 0x%08lX root: %d saver: %d grab: %d wait: %.1f\n",
+ progname, (unsigned long) window,
+ root_p, saver_p, grab_mouse_p, ((double)unmap_time)/1000000.0);
+
+ fprintf(stderr, "%s: ", progname);
+ describe_visual(stderr, screen, xgwa.visual, False);
+ fprintf (stderr, "\n");
+ }
+
+
+ if (!root_p && !top_level_window_p (screen, window))
+ {
+ if (grab_verbose_p)
+ fprintf (stderr, "%s: not a top-level window: 0x%08lX: not grabbing\n",
+ progname, (unsigned long) window);
+ return;
+ }
+
+
+ if (!root_p)
+ XSetWindowBackgroundPixmap (dpy, window, None);
+
+ if (grab_mouse_p)
+ {
+ /* prevent random viewer of the screen saver (locker) from messing
+ with windows. We don't check whether it succeeded, because what
+ are our options, really... */
+ XGrabPointer (dpy, real_root, True, ButtonPressMask|ButtonReleaseMask,
+ GrabModeAsync, GrabModeAsync, None, None, CurrentTime);
+ XGrabKeyboard (dpy, real_root, True, GrabModeSync, GrabModeAsync,
+ CurrentTime);
+ }
+
+ if (unmap_time > 0)
+ {
+ XUnmapWindow (dpy, window);
+ install_screen_colormaps (screen);
+ XSync (dpy, True);
+ usleep(unmap_time); /* wait for everyone to swap in and handle exposes */
+ }
+
+ if (!root_p)
+ {
+#ifdef HAVE_READ_DISPLAY_EXTENSION
+ if (! read_display(screen, window, 0, saver_p))
+#endif /* HAVE_READ_DISPLAY_EXTENSION */
+ {
+#ifdef HAVE_READ_DISPLAY_EXTENSION
+ if (grab_verbose_p)
+ fprintf(stderr, "%s: read_display() failed\n", progname);
+#endif /* HAVE_READ_DISPLAY_EXTENSION */
+
+ copy_default_colormap_contents (screen, xgwa.colormap, xgwa.visual);
+ raise_window(dpy, window, saver_p);
+
+ /* Generally it's bad news to call XInstallColormap() explicitly,
+ but this file does a lot of sleazy stuff already... This is to
+ make sure that the window's colormap is installed, even in the
+ case where the window is OverrideRedirect. */
+ if (xgwa.colormap) XInstallColormap (dpy, xgwa.colormap);
+ XSync (dpy, False);
+ }
+ }
+ else /* root_p */
+ {
+ Pixmap pixmap;
+ pixmap = XCreatePixmap(dpy, window, xgwa.width, xgwa.height, xgwa.depth);
+
+#ifdef HAVE_READ_DISPLAY_EXTENSION
+ if (! read_display(screen, window, pixmap, True))
+#endif
+ {
+ Window real_root = XRootWindowOfScreen (screen); /* not vroot */
+ XGCValues gcv;
+ GC gc;
+
+#ifdef HAVE_READ_DISPLAY_EXTENSION
+ if (grab_verbose_p)
+ fprintf(stderr, "%s: read_display() failed\n", progname);
+#endif /* HAVE_READ_DISPLAY_EXTENSION */
+
+ copy_default_colormap_contents (screen, xgwa.colormap, xgwa.visual);
+
+ gcv.function = GXcopy;
+ gcv.subwindow_mode = IncludeInferiors;
+ gc = XCreateGC (dpy, window, GCFunction | GCSubwindowMode, &gcv);
+ XCopyArea (dpy, real_root, pixmap, gc,
+ xgwa.x, xgwa.y, xgwa.width, xgwa.height, 0, 0);
+ XFreeGC (dpy, gc);
+ }
+ XSetWindowBackgroundPixmap (dpy, window, pixmap);
+ XFreePixmap (dpy, pixmap);
+ }
+
+ if (grab_verbose_p)
+ fprintf (stderr, "%s: grabbed %d bit screen image to %swindow.\n",
+ progname, xgwa.depth,
+ (root_p ? "real root " : ""));
+
+ if (grab_mouse_p)
+ {
+ XUngrabPointer (dpy, CurrentTime);
+ XUngrabKeyboard (dpy, CurrentTime);
+ }
+
+ XSync (dpy, True);
+}
+
+
+/* When we are grabbing and manipulating a screen image, it's important that
+ we use the same colormap it originally had. So, if the screensaver was
+ started with -install, we need to copy the contents of the default colormap
+ into the screensaver's colormap.
+ */
+static void
+copy_default_colormap_contents (Screen *screen,
+ Colormap to_cmap,
+ Visual *to_visual)
+{
+ Display *dpy = DisplayOfScreen (screen);
+ Visual *from_visual = DefaultVisualOfScreen (screen);
+ Colormap from_cmap = XDefaultColormapOfScreen (screen);
+
+ XColor *old_colors, *new_colors;
+ unsigned long *pixels;
+ XVisualInfo vi_in, *vi_out;
+ int out_count;
+ int from_cells, to_cells, max_cells, got_cells;
+ int i;
+
+ if (from_cmap == to_cmap)
+ return;
+
+ vi_in.screen = XScreenNumberOfScreen (screen);
+ vi_in.visualid = XVisualIDFromVisual (from_visual);
+ vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
+ &vi_in, &out_count);
+ if (! vi_out) abort ();
+ from_cells = vi_out [0].colormap_size;
+ XFree ((char *) vi_out);
+
+ vi_in.screen = XScreenNumberOfScreen (screen);
+ vi_in.visualid = XVisualIDFromVisual (to_visual);
+ vi_out = XGetVisualInfo (dpy, VisualScreenMask|VisualIDMask,
+ &vi_in, &out_count);
+ if (! vi_out) abort ();
+ to_cells = vi_out [0].colormap_size;
+ XFree ((char *) vi_out);
+
+ max_cells = (from_cells > to_cells ? to_cells : from_cells);
+
+ old_colors = (XColor *) calloc (sizeof (XColor), max_cells);
+ new_colors = (XColor *) calloc (sizeof (XColor), max_cells);
+ pixels = (unsigned long *) calloc (sizeof (unsigned long), max_cells);
+ for (i = 0; i < max_cells; i++)
+ old_colors[i].pixel = i;
+ XQueryColors (dpy, from_cmap, old_colors, max_cells);
+
+ got_cells = max_cells;
+ allocate_writable_colors (screen, to_cmap, pixels, &got_cells);
+
+ if (grab_verbose_p && got_cells != max_cells)
+ fprintf(stderr, "%s: got only %d of %d cells\n", progname,
+ got_cells, max_cells);
+
+ if (got_cells <= 0) /* we're screwed */
+ ;
+ else if (got_cells == max_cells && /* we're golden */
+ from_cells == to_cells)
+ XStoreColors (dpy, to_cmap, old_colors, got_cells);
+ else /* try to cope... */
+ {
+ for (i = 0; i < got_cells; i++)
+ {
+ XColor *c = old_colors + i;
+ int j;
+ for (j = 0; j < got_cells; j++)
+ if (pixels[j] == c->pixel)
+ {
+ /* only store this color value if this is one of the pixels
+ we were able to allocate. */
+ XStoreColors (dpy, to_cmap, c, 1);
+ break;
+ }
+ }
+ }
+
+
+ if (grab_verbose_p)
+ fprintf(stderr, "%s: installing copy of default colormap\n", progname);
+
+ free (old_colors);
+ free (new_colors);
+ free (pixels);
+}
+
+
+
+/* The SGI ReadDisplay extension.
+ This extension lets you get back a 24-bit image of the screen, taking into
+ account the colors with which all windows are *currently* displayed, even
+ if those windows have different visuals. Without this extension, presence
+ of windows with different visuals or colormaps will result in technicolor
+ when one tries to grab the screen image.
+ */
+
+#ifdef HAVE_READ_DISPLAY_EXTENSION
+
+static Bool
+read_display (Screen *screen, Window window, Pixmap into_pixmap,
+ Bool dont_wait)
+{
+ Display *dpy = DisplayOfScreen (screen);
+ XWindowAttributes xgwa;
+ int rd_event_base = 0;
+ int rd_error_base = 0;
+ unsigned long hints = 0;
+ XImage *image = 0;
+ XGCValues gcv;
+ int class;
+ GC gc;
+ Bool remap_p = False;
+
+ /* Check to see if the server supports the extension, and bug out if not.
+ */
+ if (! XReadDisplayQueryExtension (dpy, &rd_event_base, &rd_error_base))
+ {
+ if (grab_verbose_p)
+ fprintf(stderr, "%s: no XReadDisplay extension\n", progname);
+ return False;
+ }
+
+ /* If this isn't a visual we know how to handle, bug out. We handle:
+ = TrueColor in depths 8, 12, 15, 16, and 32;
+ = PseudoColor and DirectColor in depths 8 and 12.
+ */
+ XGetWindowAttributes(dpy, window, &xgwa);
+ class = visual_class (screen, xgwa.visual);
+ if (class == TrueColor)
+ {
+ if (xgwa.depth != 8 && xgwa.depth != 12 && xgwa.depth != 15 &&
+ xgwa.depth != 16 && xgwa.depth != 24 && xgwa.depth != 32)
+ {
+ if (grab_verbose_p)
+ fprintf(stderr, "%s: TrueColor depth %d unsupported\n",
+ progname, xgwa.depth);
+ return False;
+ }
+ }
+ else if (class == PseudoColor || class == DirectColor)
+ {
+ if (xgwa.depth != 8 && xgwa.depth != 12)
+ {
+ if (grab_verbose_p)
+ fprintf(stderr, "%s: Pseudo/DirectColor depth %d unsupported\n",
+ progname, xgwa.depth);
+ return False;
+ }
+ else
+ /* Allocate a TrueColor-like spread of colors for the image. */
+ remap_p = True;
+ }
+
+
+ /* Try and read the screen.
+ */
+ hints = (XRD_TRANSPARENT | XRD_READ_POINTER);
+ image = XReadDisplay (dpy, window, xgwa.x, xgwa.y, xgwa.width, xgwa.height,
+ hints, &hints);
+ if (!image)
+ {
+ if (grab_verbose_p)
+ fprintf(stderr, "%s: XReadDisplay() failed\n", progname);
+ return False;
+ }
+ if (!image->data)
+ {
+ if (grab_verbose_p)
+ fprintf(stderr, "%s: XReadDisplay() returned no data\n", progname);
+ XDestroyImage(image);
+ return False;
+ }
+
+ /* XReadDisplay tends to LIE about the depth of the image it read.
+ It is returning an XImage which has `depth' and `bits_per_pixel'
+ confused!
+
+ That is, on a 24-bit display, where all visuals claim depth 24, and
+ where XGetImage would return an XImage with depth 24, and where
+ XPutImage will get a BadMatch with images that are not depth 24,
+ XReadDisplay is returning images with depth 32! Fuckwits!
+
+ So if the visual is of depth 24, but the image came back as depth 32,
+ hack it to be 24 lest we get a BadMatch from XPutImage.
+
+ I wonder what happens on an 8-bit SGI... Probably it still returns
+ an image claiming depth 32? Certainly it can't be 8. So, let's just
+ smash it to 32...
+ */
+ if (image->depth == 32 /* && xgwa.depth == 24 */ )
+ image->depth = 24;
+
+ /* If the visual of the window/pixmap into which we're going to draw is
+ less deep than the screen itself, then we need to convert the grabbed bits
+ to match the depth by clipping off the less significant bit-planes of each
+ color component.
+ */
+ if (image->depth > xgwa.depth)
+ {
+ int x, y;
+ /* We use the same image->data in both images -- that's ok, because
+ since we're reading from B and writing to A, and B uses more bytes
+ per pixel than A, the write pointer won't overrun the read pointer.
+ */
+ XImage *image2 = XCreateImage (dpy, xgwa.visual, xgwa.depth,
+ ZPixmap, 0, image->data,
+ xgwa.width, xgwa.height,
+ 8, 0);
+ if (!image2)
+ {
+ if (grab_verbose_p)
+ fprintf(stderr, "%s: out of memory?\n", progname);
+ return False;
+ }
+
+ if (grab_verbose_p)
+ fprintf(stderr, "%s: converting from depth %d to depth %d\n",
+ progname, image->depth, xgwa.depth);
+
+ for (y = 0; y < image->height; y++)
+ for (x = 0; x < image->width; x++)
+ {
+ /* #### really these shift values should be determined from the
+ mask values -- but that's a pain in the ass, and anyway,
+ this is an SGI-specific extension so hardcoding assumptions
+ about the SGI server's behavior isn't *too* heinous... */
+ unsigned long pixel = XGetPixel(image, x, y);
+ unsigned int r = (pixel & image->red_mask);
+ unsigned int g = (pixel & image->green_mask) >> 8;
+ unsigned int b = (pixel & image->blue_mask) >> 16;
+
+ if (xgwa.depth == 8)
+ pixel = ((r >> 5) | ((g >> 5) << 3) | ((b >> 6) << 6));
+ else if (xgwa.depth == 12)
+ pixel = ((r >> 4) | ((g >> 4) << 4) | ((b >> 4) << 8));
+ else if (xgwa.depth == 16 || xgwa.depth == 15)
+ /* Gah! I don't understand why these are in the other order. */
+ pixel = (((r >> 3) << 10) | ((g >> 3) << 5) | ((b >> 3)));
+ else
+ abort();
+
+ XPutPixel(image2, x, y, pixel);
+ }
+ image->data = 0;
+ XDestroyImage(image);
+ image = image2;
+ }
+
+ if (remap_p)
+ {
+ allocate_cubic_colormap (screen, window, xgwa.visual);
+ remap_image (screen, window, xgwa.colormap, image);
+ }
+
+ /* Now actually put the bits into the window or pixmap -- note the design
+ bogosity of this extension, where we've been forced to take 24 bit data
+ from the server to the client, and then push it back from the client to
+ the server, *without alteration*. We should have just been able to tell
+ the server, "put a screen image in this drawable", instead of having to
+ go through the intermediate step of converting it to an Image. Geez.
+ (Assuming that the window is of screen depth; we happen to handle less
+ deep windows, but that's beside the point.)
+ */
+ gcv.function = GXcopy;
+ gc = XCreateGC (dpy, window, GCFunction, &gcv);
+
+ if (into_pixmap)
+ {
+ gcv.function = GXcopy;
+ gc = XCreateGC (dpy, into_pixmap, GCFunction, &gcv);
+ XPutImage (dpy, into_pixmap, gc, image, 0, 0, 0, 0,
+ xgwa.width, xgwa.height);
+ }
+ else
+ {
+ gcv.function = GXcopy;
+ gc = XCreateGC (dpy, window, GCFunction, &gcv);
+
+ /* Ok, now we'll be needing that window on the screen... */
+ raise_window(dpy, window, dont_wait);
+
+ /* Plop down the bits... */
+ XPutImage (dpy, window, gc, image, 0, 0, 0, 0, xgwa.width, xgwa.height);
+ }
+ XFreeGC (dpy, gc);
+
+ if (image->data)
+ {
+ free(image->data);
+ image->data = 0;
+ }
+ XDestroyImage(image);
+
+ return True;
+}
+#endif /* HAVE_READ_DISPLAY_EXTENSION */
+
+
+#ifdef HAVE_READ_DISPLAY_EXTENSION
+
+/* Makes and installs a colormap that makes a PseudoColor or DirectColor
+ visual behave like a TrueColor visual of the same depth.
+
+ #### Duplicated in driver/xscreensaver-getimage.c
+ */
+static void
+allocate_cubic_colormap (Screen *screen, Window window, Visual *visual)
+{
+ Display *dpy = DisplayOfScreen (screen);
+ XWindowAttributes xgwa;
+ Colormap cmap;
+ int nr, ng, nb, cells;
+ int r, g, b;
+ int depth;
+ XColor colors[4097];
+ int i;
+
+ XGetWindowAttributes (dpy, window, &xgwa);
+ cmap = xgwa.colormap;
+ depth = visual_depth (screen, visual);
+
+ switch (depth)
+ {
+ case 8: nr = 3; ng = 3; nb = 2; cells = 256; break;
+ case 12: nr = 4; ng = 4; nb = 4; cells = 4096; break;
+ default: abort(); break;
+ }
+
+ memset(colors, 0, sizeof(colors));
+ for (r = 0; r < (1 << nr); r++)
+ for (g = 0; g < (1 << ng); g++)
+ for (b = 0; b < (1 << nb); b++)
+ {
+ i = (r | (g << nr) | (b << (nr + ng)));
+ colors[i].pixel = i;
+ colors[i].flags = DoRed|DoGreen|DoBlue;
+ if (depth == 8)
+ {
+ colors[i].red = ((r << 13) | (r << 10) | (r << 7) |
+ (r << 4) | (r << 1));
+ colors[i].green = ((g << 13) | (g << 10) | (g << 7) |
+ (g << 4) | (g << 1));
+ colors[i].blue = ((b << 14) | (b << 12) | (b << 10) |
+ (b << 8) | (b << 6) | (b << 4) |
+ (b << 2) | b);
+ }
+ else
+ {
+ colors[i].red = (r << 12) | (r << 8) | (r << 4) | r;
+ colors[i].green = (g << 12) | (g << 8) | (g << 4) | g;
+ colors[i].blue = (b << 12) | (b << 8) | (b << 4) | b;
+ }
+ }
+
+ {
+ int j;
+ int allocated = 0;
+ int interleave = cells / 8; /* skip around, rather than allocating in
+ order, so that we get better coverage if
+ we can't allocated all of them. */
+ for (j = 0; j < interleave; j++)
+ for (i = 0; i < cells; i += interleave)
+ if (XAllocColor (dpy, cmap, &colors[i + j]))
+ allocated++;
+
+ if (grab_verbose_p)
+ fprintf (stderr, "%s: allocated %d of %d colors for cubic map\n",
+ progname, allocated, cells);
+ }
+}
+
+/* Find the pixel index that is closest to the given color
+ (using linear distance in RGB space -- which is far from the best way.)
+
+ #### Duplicated in driver/xscreensaver-getimage.c
+ */
+static unsigned long
+find_closest_pixel (XColor *colors, int ncolors,
+ unsigned long r, unsigned long g, unsigned long b)
+{
+ unsigned long distance = ~0;
+ int i, found = 0;
+
+ if (ncolors == 0)
+ abort();
+ for (i = 0; i < ncolors; i++)
+ {
+ unsigned long d;
+ int rd, gd, bd;
+
+ rd = r - colors[i].red;
+ gd = g - colors[i].green;
+ bd = b - colors[i].blue;
+ if (rd < 0) rd = -rd;
+ if (gd < 0) gd = -gd;
+ if (bd < 0) bd = -bd;
+ d = (rd << 1) + (gd << 2) + bd;
+
+ if (d < distance)
+ {
+ distance = d;
+ found = i;
+ if (distance == 0)
+ break;
+ }
+ }
+
+ return found;
+}
+
+
+/* Given an XImage with 8-bit or 12-bit RGB data, convert it to be
+ displayable with the given X colormap. The farther from a perfect
+ color cube the contents of the colormap are, the lossier the
+ transformation will be. No dithering is done.
+
+ #### Duplicated in driver/xscreensaver-getimage.c
+ */
+void
+remap_image (Screen *screen, Window window, Colormap cmap, XImage *image)
+{
+ Display *dpy = DisplayOfScreen (screen);
+ unsigned long map[4097];
+ int x, y, i;
+ int cells;
+ XColor colors[4097];
+
+ if (image->depth == 8)
+ cells = 256;
+ else if (image->depth == 12)
+ cells = 4096;
+ else
+ abort();
+
+ memset(map, -1, sizeof(*map));
+ memset(colors, -1, sizeof(*colors));
+
+ for (i = 0; i < cells; i++)
+ colors[i].pixel = i;
+ XQueryColors (dpy, cmap, colors, cells);
+
+ if (grab_verbose_p)
+ fprintf(stderr, "%s: building table for %d bit image\n",
+ progname, image->depth);
+
+ for (i = 0; i < cells; i++)
+ {
+ unsigned short r, g, b;
+
+ if (cells == 256)
+ {
+ /* "RRR GGG BB" In an 8 bit map. Convert that to
+ "RRR RRR RR" "GGG GGG GG" "BB BB BB BB" to give
+ an even spread. */
+ r = (i & 0x07);
+ g = (i & 0x38) >> 3;
+ b = (i & 0xC0) >> 6;
+
+ r = ((r << 13) | (r << 10) | (r << 7) | (r << 4) | (r << 1));
+ g = ((g << 13) | (g << 10) | (g << 7) | (g << 4) | (g << 1));
+ b = ((b << 14) | (b << 12) | (b << 10) | (b << 8) |
+ (b << 6) | (b << 4) | (b << 2) | b);
+ }
+ else
+ {
+ /* "RRRR GGGG BBBB" In a 12 bit map. Convert that to
+ "RRRR RRRR" "GGGG GGGG" "BBBB BBBB" to give an even
+ spread. */
+ r = (i & 0x00F);
+ g = (i & 0x0F0) >> 4;
+ b = (i & 0xF00) >> 8;
+
+ r = (r << 12) | (r << 8) | (r << 4) | r;
+ g = (g << 12) | (g << 8) | (g << 4) | g;
+ b = (b << 12) | (b << 8) | (b << 4) | b;
+ }
+
+ map[i] = find_closest_pixel (colors, cells, r, g, b);
+ }
+
+ if (grab_verbose_p)
+ fprintf(stderr, "%s: remapping colors in %d bit image\n",
+ progname, image->depth);
+
+ for (y = 0; y < image->height; y++)
+ for (x = 0; x < image->width; x++)
+ {
+ unsigned long pixel = XGetPixel(image, x, y);
+ if (pixel >= cells) abort();
+ XPutPixel(image, x, y, map[pixel]);
+ }
+}
+
+
+#endif /* HAVE_READ_DISPLAY_EXTENSION */
diff --git a/utils/grabscreen.h b/utils/grabscreen.h
new file mode 100644
index 0000000..40054c8
--- /dev/null
+++ b/utils/grabscreen.h
@@ -0,0 +1,109 @@
+/* xscreensaver, Copyright (c) 1992-2014 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 __GRABSCREEN_H__
+#define __GRABSCREEN_H__
+
+/* This will write an image onto the given Drawable.
+ The Drawable (arg 3) may be a Window or a Pixmap.
+
+ The Window must be the top-level window. The image *may or may not*
+ be written to the window, though it will definitely be written to
+ the drawable. It's fine for args 2 and 3 to be the same window, or
+ for arg 2 to be a Window, and arg 3 to be a Pixmap.
+
+ The loaded image might be from a file, or from a screen shot of the
+ desktop, or from the system's video input, depending on user
+ preferences.
+
+ When the callback is called, the image data will have been loaded
+ into the given drawable. Copy `name' if you want to keep it.
+
+ If it is from a file, then the `filename' argument will be the name
+ of the file. It may be NULL. If you want to keep this string, copy it.
+
+ The size and position of the image is in the `geometry' arg.
+ The image will generally have been scaled up to fit the window, but
+ if a loaded file had a different aspect ratio than the window, it
+ will have been centered, and the returned coords will describe that.
+
+ Many colors may be allocated from the window's colormap.
+ */
+extern void load_image_async (Screen *, Window, Drawable,
+ void (*callback) (Screen *, Window,
+ Drawable,
+ const char *name,
+ XRectangle *geometry,
+ void *closure),
+ void *closure);
+
+/* A utility wrapper around load_image_async() that is simpler if you
+ are only loading a single image at a time: just keep calling it
+ periodically until it returns NULL. When it does, the image has
+ been loaded.
+ */
+typedef struct async_load_state async_load_state;
+extern async_load_state *load_image_async_simple (async_load_state *,
+ Screen *,
+ Window top_level,
+ Drawable target,
+ char **filename_ret,
+ XRectangle *geometry_ret);
+
+
+/* Whether one should use GCSubwindowMode when drawing on this window
+ (assuming a screen image has been grabbed onto it.) Yes, this is a
+ total kludge. */
+extern Bool use_subwindow_mode_p(Screen *screen, Window window);
+
+/* Whether the given window is:
+ - the real root window;
+ - the virtual root window;
+ - a direct child of the root window;
+ - a direct child of the window manager's decorations.
+ */
+extern Bool top_level_window_p(Screen *screen, Window window);
+
+
+/* Don't call this: this is for the "xscreensaver-getimage" program only. */
+extern void grab_screen_image_internal (Screen *, Window);
+
+/* Don't use these: this is how "xscreensaver-getimage" and "grabclient.c"
+ pass the file name around. */
+#define XA_XSCREENSAVER_IMAGE_FILENAME "_SCREENSAVER_IMAGE_FILENAME"
+#define XA_XSCREENSAVER_IMAGE_GEOMETRY "_SCREENSAVER_IMAGE_GEOMETRY"
+
+/* For debugging: turn on verbosity. */
+extern void grabscreen_verbose (void);
+
+#ifdef HAVE_JWXYZ
+/* Don't use these: internal interface of grabclient.c. */
+extern Bool osx_grab_desktop_image (Screen *, Window, Drawable,
+ XRectangle *geom_ret);
+extern Bool osx_load_image_file (Screen *, Window, Drawable,
+ const char *filename, XRectangle *geom_ret);
+#endif /* HAVE_JWXYZ */
+
+#ifdef USE_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 */
+
+#ifdef HAVE_ANDROID
+char *jwxyz_draw_random_image (Display *dpy, /* utils/grabclient.c */
+ Drawable drawable, GC gc);
+#endif
+
+#endif /* __GRABSCREEN_H__ */
diff --git a/utils/hsv.c b/utils/hsv.c
new file mode 100644
index 0000000..cf1cc8d
--- /dev/null
+++ b/utils/hsv.c
@@ -0,0 +1,81 @@
+/* xscreensaver, Copyright (c) 1992, 1997 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.
+ */
+
+/* This file contains some utility routines for randomly picking the colors
+ to hack the screen with.
+ */
+
+#include "utils.h"
+#include "hsv.h"
+
+void
+hsv_to_rgb (int h, double s, double v,
+ unsigned short *r, unsigned short *g, unsigned short *b)
+{
+ double H, S, V, R, G, B;
+ double p1, p2, p3;
+ double f;
+ int i;
+
+ if (s < 0) s = 0;
+ if (v < 0) v = 0;
+ if (s > 1) s = 1;
+ if (v > 1) v = 1;
+
+ S = s; V = v;
+ H = (h % 360) / 60.0;
+ i = H;
+ f = H - i;
+ p1 = V * (1 - S);
+ p2 = V * (1 - (S * f));
+ p3 = V * (1 - (S * (1 - f)));
+ if (i == 0) { R = V; G = p3; B = p1; }
+ else if (i == 1) { R = p2; G = V; B = p1; }
+ else if (i == 2) { R = p1; G = V; B = p3; }
+ else if (i == 3) { R = p1; G = p2; B = V; }
+ else if (i == 4) { R = p3; G = p1; B = V; }
+ else { R = V; G = p1; B = p2; }
+ *r = R * 65535;
+ *g = G * 65535;
+ *b = B * 65535;
+}
+
+void
+rgb_to_hsv (unsigned short r, unsigned short g, unsigned short b,
+ int *h, double *s, double *v)
+{
+ double R, G, B, H, S, V;
+ double cmax, cmin;
+ double cmm;
+ int imax;
+ R = ((double) r) / 65535.0;
+ G = ((double) g) / 65535.0;
+ B = ((double) b) / 65535.0;
+ cmax = R; cmin = G; imax = 1;
+ if ( cmax < G ) { cmax = G; cmin = R; imax = 2; }
+ if ( cmax < B ) { cmax = B; imax = 3; }
+ if ( cmin > B ) { cmin = B; }
+ cmm = cmax - cmin;
+ V = cmax;
+ if (cmm == 0)
+ S = H = 0;
+ else
+ {
+ S = cmm / cmax;
+ if (imax == 1) H = (G - B) / cmm;
+ else if (imax == 2) H = 2.0 + (B - R) / cmm;
+ else /*if (imax == 3)*/ H = 4.0 + (R - G) / cmm;
+ if (H < 0) H += 6.0;
+ }
+ *h = (H * 60.0);
+ *s = S;
+ *v = V;
+}
diff --git a/utils/hsv.h b/utils/hsv.h
new file mode 100644
index 0000000..e0fdfb0
--- /dev/null
+++ b/utils/hsv.h
@@ -0,0 +1,27 @@
+/* xscreensaver, Copyright (c) 1992, 1997 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 __HSV_H__
+#define __HSV_H__
+
+/* Converts between RGB and HSV color spaces.
+ R, G, and B are in the range 0 - 65535;
+ H is in the range 0 - 360;
+ S and V are in the range 0.0 - 1.0.
+ */
+extern void hsv_to_rgb (int h, double s, double v,
+ unsigned short *r,
+ unsigned short *g,
+ unsigned short *b);
+extern void rgb_to_hsv (unsigned short r, unsigned short g, unsigned short b,
+ int *h, double *s, double *v);
+
+#endif /* __HSV_H__ */
diff --git a/utils/images/logo-180.gif b/utils/images/logo-180.gif
new file mode 100644
index 0000000..1355767
--- /dev/null
+++ b/utils/images/logo-180.gif
Binary files differ
diff --git a/utils/images/logo-180.xpm b/utils/images/logo-180.xpm
new file mode 100644
index 0000000..b093c8f
--- /dev/null
+++ b/utils/images/logo-180.xpm
@@ -0,0 +1,207 @@
+/* XPM */
+
+/* XScreenSaver Logo, designed by Angela Goodman <rzr_grl@yahoo.com>
+ Copyright (c) 2001, 2002 by Jamie Zawinski <jwz@jwz.org>
+ Unauthorized use or reproduction prohibited.
+
+ https://www.jwz.org/xscreensaver/
+ */
+
+static const char * const logo_180_xpm[] = {
+"180 180 16 1",
+" c None m None",
+") c #FF0000 m #FFFFFF",
+", c #FFFFFF m #FFFFFF",
+". c #000000 m #000000",
+"- c #ED9E00 m #FFFFFF",
+"' c #4F3504 m #000000",
+"= c #DBDBDB m #000000",
+"> c #B0B0B0 m #000000",
+"+ c #929292 m #000000",
+"; c #797979 m #000000",
+"@ c #A30000 m #000000",
+"# c #604D28 m #000000",
+"$ c #600000 m #000000",
+"% c #37332D m #000000",
+"& c #2D0C05 m #000000",
+"* c #A46E00 m #000000",
+" ",
+" . ",
+" .. ",
+" ... ",
+" . ... ",
+" .. ... ",
+" .&..... ",
+" &&.... ",
+" .@&.... ",
+" $)..... ",
+" .)@.... ",
+" .@)@.... ",
+" &))$.... ",
+" .)))&... ",
+" .@))@&... ",
+" $)))@.... ",
+" &))))$.... ",
+" .)))))&... ",
+" @))))@.... ",
+" $)))))$&... ",
+" .)))))).&.. ",
+" .))))))@.... .. ",
+" .)))))))&'... .. ... ",
+" .@)))))))%'.. . ... ",
+" @)))))))$#&.. .. ... ",
+" $))))))))&#... .& .... ",
+" &))))))))$*%.. &. .... ",
+" $))))))))@#*... .$..... ",
+" &)))))))))&-'.. .@$..... ",
+" $)))))))))&-*.. &)...... ",
+" &)))))))))@*-... .@@..... ",
+" .)))))))))$*-&.. &)@..... ",
+" .)))))))))$**... .@)$..&.. ",
+" .)))))))))&-'.. &))$.&'.. ",
+" $))))))))$'-... .@))$.*'.. ",
+" $)))))))).-'.. $)))&%-... ",
+" @)))))))$#-... .))))&*-.. ",
+" .@)))))))&-#.. &))))&-*.. ",
+" .)))))))$*-... .@))))&--... ",
+" ....................................................$)))))))&-*.........&)))))&-*............................................................... ",
+" .....................................................@))))))$#-&.........$)))))&--................................................................. ",
+" .....................................................&)))))))&-*..........))))))$--.................................................................. ",
+" .....................................................@))))))$*-'.........$))))))$*-.................................................................. ",
+" .....+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,+&))))))).--..;,,,,,,#@))))))@*-..;,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=#.... ",
+" ....%,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=&)))))))@'-#..=,,,,,=&)))))))$*-..;,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=.... ",
+" ....;,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,%@)))))))&--&.%,,,,,,+$)))))))@#-..;,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=.... ",
+" ....+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,%$)))))))@'-*..+,,,,,,%)))))))))&-%.#,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=.... ",
+" ....+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,+$))))))))$*-'.&=,,,,,=&)))))))))&-'.&,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=.... ",
+" ....+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,>.)))))))))&--..#,,,,,,;@)))))))))$-#..=,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=.... ",
+" ....+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=&@))))))))$*-*..>,,,,,,#@)))))))))$**..>,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=.... ",
+" ....+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=%@)))))))))&--'.&,,,,,,=&))))))))))@#-..+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=.... ",
+" ....+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,;$))))))))))%--..;,,,,,,>$)))))))))))%-&.#,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=.... ",
+" ....+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=&))))))))))@#--..+,,,,,,;@)))))))))))&-'.%,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=.... ",
+" ....+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,>=,,,,,,,%@))))))))))$--#..=,,,,,,%))))))))))))$*#..=,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=.... ",
+" ....+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,;.>,&&=,,+$)))))))))))&--'.%,,,,,,,&))))))))))))@'*..>,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=.... ",
+" ....+,,,,,,,,,,,,=>>>>>>+>>>>+>>>>+&$;#..;>>&)))))))))))@'--..%>>>>>>+&)))))))))))))&-&.%>>>>+>>>>+>>>>+>>>>+>>>>+>>>>+>>>>>>>>>>>>>>=,,,,,,,,,,,=.... ",
+" ....+,,,,,,,,,,+...................@&.......$)))))))))))@#--..........$)))))))))))))$*#...............................................%>,,,,,,,,,=.... ",
+" ....+,,,,,,,,,#...................&)........@)))))))))))@*-*..........@)))))))))))))@#*.................................................+,,,,,,,,=.... ",
+" ....+,,,,,,,,+....................@@.......$))))))))))))$*-*..........@))))))))))))))&-&.................................................=,,,,,,,=.... ",
+" ....+,,,,,,,=....................&)@.......)))))))))))))$--#..........@))))))))))))))$*#.................................................%,,,,,,,=.... ",
+" ....+,,,,,,,>....................@)$......&)))))))))))))$*-*..........)))))))))))))))@'*..................................................,,,,,,,=.... ",
+" ....+,,,,,,,+....................)).......$)))))))))))))@*-#..........))))))))))))))))&-..................................................>,,,,,,=.... ",
+" ....+,,,,,,,+...................@)).......@)))))))))))))@#-*..........))))))))))))))))$#'.................................................>,,,,,,=.... ",
+" ....+,,,,,,,+...................@)@......&)))))))))))))))%-*..........)))))))))))))))))&-.................................................>,,,,,,=.... ",
+" ....+,,,,,,,+..................$))$......$)))))))))))))))&--..........)))))))))))))))))$*'................................................>,,,,,,=.... ",
+" ....+,,,,,,,+..................@))&......$)))))))))))))))$*-&.........)))))))))))))))))@%-................................................>,,,,,,=.... ",
+" ....+,,,,,,,+..................))).......@))))))))))))))))&-#.........))))))))))))))))))&*'...............................................>,,,,,,=.... ",
+" ....+,,,,,,,+.................$))).......@))))))))))))))))$*-.........))))))))))))))))))@'*...............................................>,,,,,,=.... ",
+" ....+,,,,,,,+.................@))@.......))))))))))))))))))&-&........)))))))))))))))))))$*'..............................................>,,,,,,=.... ",
+" ....+,,,,,,,+.................)))@.%.....))))))))))))))))))$#*........@))))))))))))))))))@&-..............................................>,,,,,,=.... ",
+" ....+,,,,,,,+................$)))$.*.....)))))))))))))))))))&*&.......$)))))))))))))))))))$*#.............................................>,,,,,,=.... ",
+" ....+,,,,,,,+................@)))$'*.....@)))))))))))))))))))&*.......&))))))))))))))))))))&-&............................................>,,,,,,=.... ",
+" ....+,,,,,,,+...............&))))$**..&%&@)))))))))))))))))))@%#...%&%.))))))))))))))))))))$#*...&%%&%%&%%&%%&%%&%%&%%....................>,,,,,,=.... ",
+" ....+,,,,,,,+...............$))))$*-..+,;@))))))))))))))))))))$#%..+,,#@))))))))))))))))))))&-#..%,,,,,,,,,,,,,,,,,,,,=+..................>,,,,,,=.... ",
+" ....+,,,,,,,+...............@))))$--..+,+@)))))))))))))))))))))&#...=,=&))))))))))))))))))))).-&..#,,,,,,,,,,,,,,,,,,,,,=.................>,,,,,,=.... ",
+" ....+,,,,,,,+...............)))))$*-%.#,>$))))))))))))))))))))))&#...=,'@))))))))))))))))))))@%-%..;,,,,,,,,,,,,,,,,,,,,,#................>,,,,,,=.... ",
+" ....+,,,,,,,+..............$)))))$--&.#,,&))))))))))))))))))))))@&'..%,>$)))))))))))))))))))))$#-...+,,,,,,,,,,,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+..............@)))))@*-#.%,,#@))))))))))))))))))))))@&'..%=%))))))))))))))))))))))&**...>,,,,,,,,,,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+..............@)))))@#-#..,,+$)))))))))))))))))))))))@&%..;+$)))))))))))))))))))))@&--..#,,,,,,,,,,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+.............&))))))@#-*..=,=&))))))))))))))))))))))))$'&..;%))))))))))))))))))))))@'-#..>,,,,,,,,,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+.............&)))))))&--..+,,'@))))))))))))))))))))))))&#...#$))))))))))))))))))))))&*-..#,,,,,,,,,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+.............@)))))))&--..#,,>$)))))))))))))))))))))))))&#....)))))))))))))))))))))))&-#..>,,,,,,,,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+.............@)))))))@#-#.&=,,&)))))))))))))))))))))))))@&#...$))))))))))))))))))))))$#-..#,,,,,,,,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+.............)))))))))#-*..>,,;@)))))))))))))))))))))))))@''...)))))))))))))))))))))))&-'..,,,,,,,,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+............&)))))))))&--&.#,,=&))))))))))))))))))))))))))&*&..&))))))))))))))))))))))@#*..>,,,,,,,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+............@)))))))))$*-'.&,,,#@))))))))))))))))))))))))))&*...@))))))))))))))))))))))&-..#,,,,,,,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+............@)))))))))@#-*..>,,=&))))))))))))))))))))))))))$##..$))))))))))))))))))))))@##..=,,,,,,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+............@))))))))))%--..#,,,%)))))))))))))))))))))))))))&-&..@))))))))))))))))))))))&*..+,,,,,,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+............)))))))))))$*-#..=,,>&))))))))))))))))))))))))))@#*..$))))))))))))))))))))))$*&.#,,,,,,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+............))))))))))))&--..#,,,%@))))))))))))))))))))))))))&-&..@)))))))))))))))))))))@''.%,,,,,,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+...........$))))))))))))&*-'..=,,+$))))))))))))))))))))))))))@#*..$))))))))))))))))))))))&#..=,,,,,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+...........$))))))))))))@'-*..;,,,&)))))))))))))))))))))))))))&-&..))))))))))))))))))))))$#..>,,,,,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+...........$)))))))))))))&*-'..=,,+$))))))))))))))))))))))))))$**..$))))))))))))))))))))))&..;,,,,,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+...........@)))))))))))))@'-*..;,,,.))))))))))))))))))))))))))@%-...))))))))))))))))))))))&%.%,,,,,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+...........@))))))))))))))$*-%..=,,;$))))))))))))))))))))))))))&-'..@)))))))))))))))))))))$&..,,,,,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+...........@)))))))))))))))&-*..%,,=&))))))))))))))))))))))))))@'-..$)))))))))))))))))))))@&..>,,,,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+...........@)))))))))))))))$#-#..>,,;@))))))))))))))))))))))))))&*&.&))))))))))))))))))))))...;,,,,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+...........@))))))))))))))))&*-&.&=,=.)))))))))))))))))))))))))))&&..))))))))))))))))))))))$..%,,,,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+...........@))))))))))))))))@&-#..+,,#@)))))))))))))))))))))))))))$.$))))))))))))))))))))))@...=,,,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+...........$)))))))))))))))))$#-%..=,>&)))))))))))))))))))))))))))))))))))))))))))))))))))))...>,,,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+...........$))))))))))))))))))$**..#,,#@))))))))))))))))))))))))))))))))))))))))))))))))))))...+,,,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+...........&))))))))))))))))))@&-'..>,>$))))))))))))))))))))))))))))))))))))))))))))))))))))$..#,,,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+............)))))))))))))))))))@%-..%,,&))))))))))))))))))))))))))))))))))))))))))))))))))))@..%,,,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+............@)))))))))))))))))))$##..;,#@)))))))))))))))))))))))))))))))))))))))))))))))))))@...,,,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+............$))))))))))))))))))))&*&.&=>$))))))))))))))))))))))))))))))))))))))))))))))))))))...=,,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+.............)))))))))))))))))))))%#..;,&))))))))))))))))))))))))))))))))))))))))))))))))))))&..>,,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+.............@))))))))))))))))))))$''..=#@)))))))))))))))))))))))))))))))))))))))))))))))))))$..;,,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+.............&)))))))))))))))))))))&#..#+$)))))))))))))))))))))))))))))))))))))))))))))))))))$..;,,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+..............@))))))))))))))))))))@&'..=$)))))))))))))))))))))))))))))))))))))))))))))))))))@..&,,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+..............$)))))))))))))))))))))$'..+&)))))))))))))))))))))))))))))))))))))))))))))))))))@...=,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+...............))))))))))))))))))))))...#%))))))))))))))))))))))))))))))))))))))))))))))))))))...=,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+...............$)))))))))))))))))))))$....))))))))))))))))))))))))))))))))))))))))))))))))))))...+,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+................))))))))))))))))))))))....))))))))))))))))))))))))))))))))))))))))))))))))))))...;,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+................$)))))))))))))))))))))$...@)))))))))))))))))))))))))))))))))))))))))))))))))))&&.#,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+.................))))))))))))))))))))))&..))))))))))))))))))))))))))))))))))))))))))))))))))))$%.%,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+.................$))))))))))))))))))))))&&))))))))))))))))))))))))))))))))))))))))))))))))))))$'..,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+.................&))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))$#..=,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+.................+$)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))$*..>,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+.................=%)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))$*..>,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+.................,+&))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&-..;,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+.................,,#@)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&-%.#,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+.................,,=&)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&-'.%,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+.................,,,;$)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))@'-#.&,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+.................,,,,&@))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))@*-*..=,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+.................,,,,>$))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&--&..=,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+.................,,,,,#@)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&-'..#,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+.................,,,,,=&))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))$**..%,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+.................,,,,,,>&))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))).*..&=,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+.................,,,,,,,;$)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))$'...=,,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+.................,,,,,,,,%@)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))).&..;,,,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+.................=,,,,,,,=&)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))$...#,,,,,,,,,,,,,>................>,,,,,,=.... ",
+" ....+,,,,,,,+.................>,,,,,,,,>&))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))...%,,,,,,,,,,,,,,+................>,,,,,,=.... ",
+" ....+,,,,,,,+.................;,,,,,,,,,#$))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))&..&=,,,,,,,,,,,,,,%................>,,,,,,=.... ",
+" ....+,,,,,,,+..................+,,,,,,,,,#$))))))))))))))))))))))))))))))))))))))))))))))))))))))))))@...=,,,,,,,,,,,,,,;.................>,,,,,,=.... ",
+" ....+,,,,,,,+...................#+>>>>>>>>%@))))))))))))))))))))))))))))))))))))))))))))))))))))))))@...#>>>>>>>>>>>>>+#..................>,,,,,,=.... ",
+" ....+,,,,,,,+...............................@)))))))))))))))))))))))))))))))))))))))))))))))))))))))&.....................................>,,,,,,=.... ",
+" ....+,,,,,,,+................................@)))))))))))))))))))))))))))))))))))))))))))))))))))))&......................................>,,,,,,=.... ",
+" ....+,,,,,,,+................................&@)))))))))))))))))))))))))))))))))))))))))))))))))))$.......................................>,,,,,,=.... ",
+" ....+,,,,,,,+.................................&@)))))))))))))))))))))))))))))))))))))))))))))))))@........................................>,,,,,,=.... ",
+" ....+,,,,,,,+..................................&@)))))))))))))))))))))))))))))))))))))))))))))))$.........................................>,,,,,,=.... ",
+" ....+,,,,,,,+...................................&@)))))))))))))))))))))))))))))))))))))))))))))$..........................................>,,,,,,=.... ",
+" ....+,,,,,,,+....................................&@)))))))))))))))))))))))))))))))))))))))))))$...........................................>,,,,,,=.... ",
+" ....+,,,,,,,+......................................@)))))))))))))))))))))))))))))))))))))))))&............................................>,,,,,,=.... ",
+" ....+,,,,,,,+.......................................$))))))))))))))))))))))))))))))))))))))@..............................................>,,,,,,=.... ",
+" ....+,,,,,,,+.........................................@)))))))))))))))))))))))))))))))))))&...............................................>,,,,,,=.... ",
+" ....+,,,,,,,+..........................................$))))))))))))))))))))))))))))))))@.................................................=,,,,,,=.... ",
+" ....+,,,,,,,=............................................$))))))))))))))))))))))))))))$&.................................................&,,,,,,,=.... ",
+" ....+,,,,,,,,%.............................................$@))))))))))))))))))))))@$&...................................................;,,,,,,,=.... ",
+" ....+,,,,,,,,=................................................$@@))))))))))))))@@@&'#%..................................................%,,,,,,,,=.... ",
+" ....+,,,,,,,,,=&...................................................$$@@@@@@@$$&''**'...................................................%=,,,,,,,,=.... ",
+" ....+,,,,,,,,,,=+%%%#%%%%#%%%%#%%%%#%%%%#%%%%#%%%%#%%%%#%%..................#----'............%%%#%%%%#%%%%#%%%%#%%%%#%%%%#%%%%#%%%%##+,,,,,,,,,,=.... ",
+" ....+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,&..................&''..............=,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=.... ",
+" ....+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,+....................................;,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=.... ",
+" ....+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,&.....................................=,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=.... ",
+" ....+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#......................................%,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=.... ",
+" ....+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,+........................................;,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=.... ",
+" ....+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,>&.........................................>,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=.... ",
+" ....+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,>............................................>,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=.... ",
+" ....+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,>..............................................;,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=.... ",
+" ....+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,#................................................#=,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=.... ",
+" ....+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,>%..................................................&+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=.... ",
+" ....+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,>%......................................................%>,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=.... ",
+" ....+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=;%..........................................................&;=,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=.... ",
+" ....+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,>................................................................+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=.... ",
+" ....+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,.................................................................%,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=.... ",
+" ....+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,%................................................................#,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=.... ",
+" ....+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+=,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=.... ",
+" ....+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=.... ",
+" ....+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=.... ",
+" ....+,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=.... ",
+" ....;,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,=.... ",
+" ....&,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,>.... ",
+" ....%;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>;..... ",
+" ..................................................................................................................................................... ",
+" ................................................................................................................................................... ",
+" .................................................................................................................................................. ",
+" ............................................................................................................................................... ",
+" ",
+" ",
+" "};
diff --git a/utils/images/logo-50.gif b/utils/images/logo-50.gif
new file mode 100644
index 0000000..fcfcfd7
--- /dev/null
+++ b/utils/images/logo-50.gif
Binary files differ
diff --git a/utils/images/logo-50.xpm b/utils/images/logo-50.xpm
new file mode 100644
index 0000000..2661a96
--- /dev/null
+++ b/utils/images/logo-50.xpm
@@ -0,0 +1,77 @@
+/* XPM */
+
+/* XScreenSaver Logo, designed by Angela Goodman <rzr_grl@yahoo.com>
+ Copyright (c) 2001, 2002 by Jamie Zawinski <jwz@jwz.org>
+ Unauthorized use or reproduction prohibited.
+
+ https://www.jwz.org/xscreensaver/
+ */
+
+static const char * const logo_50_xpm[] = {
+"50 50 16 1",
+" c None m None",
+"& c #FF0000 m #FFFFFF",
+", c #FFFFFF m #FFFFFF",
+". c #000000 m #000000",
+"= c #CCCCCC m #000000",
+"- c #B0B0B0 m #000000",
+"+ c #989898 m #000000",
+"; c #707070 m #000000",
+"@ c #A30805 m #000000",
+"# c #5E4D34 m #000000",
+"$ c #A6531B m #000000",
+"% c #620805 m #000000",
+"* c #A63013 m #000000",
+"> c #523410 m #000000",
+"' c #AC6C44 m #000000",
+") c #24221C m #000000",
+" ",
+" .. ",
+" .. ",
+" @. ",
+" @@. ",
+" %&% ",
+" &&. . ",
+" &&*. .. ",
+" &&@> %. ",
+" &&*. @) ",
+" %&&#. @&# ",
+" ..............@&*)..&&#................. ",
+" .+,,,,,,,,,,,,'&&$;,'&@#=,,,,,,,,,,,,,,,-. ",
+" .+,,,,,,,,,,,-&&*#=,@&&>-,,,,,,,,,,,,,,,-. ",
+" .+,,,,,,,,,,,@&&$#,=&&&*;,,,,,,,,,,,,,,,-. ",
+" .+,,=;;;;;>)*&&&'>;#&&&*>;;;;;;;;;;;;+,,-. ",
+" .+,=.....%..&&&&'..%&&&&>.............+,-. ",
+" .+,-.....@..&&&&$..%&&&&*.............;,-. ",
+" .+,+....%@.%&&&&$..%&&&&@)............;,-. ",
+" .+,-....@@.%&&&&&).%&&&&&*............;,-. ",
+" .+,-....&*>$&&&&&@);&&&&&@>#==-==;....;,-. ",
+" .+,-....&*>-&&&&&&%#*&&&&&*>-,,,,,....;,-. ",
+" .+,+...%&@#=&&&&&&&%)&&&&&&*#,,,,,....;,-. ",
+" .+,-...@&&$;'&&&&&&&)@&&&&&@>=,,,,....;,-. ",
+" .+,-...&&&$>=&&&&&&&@)&&&&&&*;,,,,....;,-. ",
+" .+,-...&&&&#-$&&&&&&&>@&&&&&@#,,,,....;,-. ",
+" .+,+...&&&&$>-&&&&&&&*%&&&&&&),,,,....;,-. ",
+" .+,-...&&&&&#+*&&&&&&&@&&&&&&%=,,,....;,-. ",
+" .+,-...&&&&&@>+&&&&&&&&&&&&&&%+,,,....;,-. ",
+" .+,-...@&&&&&%#&&&&&&&&&&&&&&@;,,,....;,-. ",
+" .+,+....&&&&&&)@&&&&&&&&&&&&&&>,,,....;,-. ",
+" .+,-....@&&&&&%%&&&&&&&&&&&&&&),,,....;,-. ",
+" .+,-....%&&&&&&&&&&&&&&&&&&&&&),,,....;,-. ",
+" .+,-....;*&&&&&&&&&&&&&&&&&&&&>=,,....;,-. ",
+" .+,+....;=&&&&&&&&&&&&&&&&&&&@#-,,....;,-. ",
+" .+,-....;,'&&&&&&&&&&&&&&&&&&*#,,,....;,-. ",
+" .+,-....;,,*&&&&&&&&&&&&&&&&@),,,,....;,-. ",
+" .+,-.....#;#@&&&&&&&&&&&&&&&.#;;;)....;,-. ",
+" .+,+.........@&&&&&&&&&&&&&%..........;,-. ",
+" .+,-..........@&&&&&&&&&&&............;,-. ",
+" .+,-...........%&&&&&&&&@.............;,-. ",
+" .+,,#)))))))))))..%@@@*)...))))))))))>,,-. ",
+" .+,,,,,,,,,,,,,,).........;,,,,,,,,,,,,,-. ",
+" .+,,,,,,,,,,,,,#...........-,,,,,,,,,,,,-. ",
+" .+,,,,,,,,,,,=#.............+,,,,,,,,,,,-. ",
+" .+,,,,,,,,,,#.................-,,,,,,,,,-. ",
+" .+,,,,,,,,,,==-=-=-=-=-=-=-=-=,,,,,,,,,,-. ",
+" .;++++++++++++++++++++++++++++++++++++++;. ",
+" ........................................ ",
+" "};
diff --git a/utils/images/logo-big.gif b/utils/images/logo-big.gif
new file mode 100644
index 0000000..5ea3da2
--- /dev/null
+++ b/utils/images/logo-big.gif
Binary files differ
diff --git a/utils/images/logo.eps b/utils/images/logo.eps
new file mode 100644
index 0000000..4843e79
--- /dev/null
+++ b/utils/images/logo.eps
@@ -0,0 +1,8058 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%Creator: Adobe Illustrator(R) 8.0
+%%AI8_CreatorVersion: 8
+%%For: (rzr Grl) (evol engel)
+%%Title: (xscreensaver.eps)
+%%CreationDate: (1/30/01) (8:38 PM)
+%%BoundingBox: 179 249 429 531
+%%HiResBoundingBox: 179.3335 249.9619 428.666 530.8477
+%%DocumentProcessColors: Black
+%%DocumentFonts: Device
+%%DocumentSuppliedFonts: Device
+%%DocumentSuppliedResources: procset Adobe_level2_AI5 1.2 0
+%%+ procset Adobe_typography_AI5 1.0 1
+%%+ procset Adobe_ColorImage_AI6 1.3 0
+%%+ procset Adobe_Illustrator_AI5 1.3 0
+%%+ procset Adobe_cshow 2.0 8
+%%+ procset Adobe_shading_AI8 1.0 0
+%AI5_FileFormat 4.0
+%AI3_ColorUsage: Color
+%AI3_IncludePlacedImages
+%AI7_ImageSettings: 1
+%%DocumentCustomColors: (PANTONE 152 CVC)
+%%+ (PANTONE 485 CVC)
+%%CMYKCustomColor: 0 0.51 1 0 (PANTONE 152 CVC)
+%%+ 0.91 0.01 0.93 0 (PANTONE 354 2X CVC)
+%%+ 0 1 0.91 0 (PANTONE 485 CVC)
+%%CMYKProcessColor: 1 1 1 1 ([Registration])
+%%AI6_ColorSeparationSet: 1 1 (AI6 Default Color Separation Set)
+%%+ Options: 1 16 0 1 0 1 1 1 0 1 1 1 1 18 0 0 0 0 0 0 0 0 131071 -1
+%%+ PPD: 1 21 0 0 60 45 2 2 1 0 0 1 0 0 0 0 0 0 0 0 0 0 ()
+%AI3_TemplateBox: 306.5 395.5 306.5 395.5
+%AI3_TileBox: 30 31 582 761
+%AI3_DocumentPreview: Header
+%AI5_ArtSize: 612 792
+%AI5_RulerUnits: 2
+%AI5_ArtFlags: 1 0 0 1 0 0 1 0 0
+%AI5_TargetResolution: 800
+%AI5_NumLayers: 4
+%AI8_OpenToView: -109 667 1 718 623 18 0 1 153 44 0 0
+%AI5_OpenViewLayers: 3733
+%%PageOrigin:30 31
+%%AI3_PaperRect:-30 761 582 -31
+%%AI3_Margin:30 -31 -30 31
+%AI7_GridSettings: 72 8 72 8 1 0 0.8 0.8 0.8 0.9 0.9 0.9
+%AI7_Thumbnail: 116 128 8
+%%BeginData: 12612 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
+%524C45FD2BFF2727FD71FF2052F87DFD70FF76F8F8F8A8FD6FFFA8FD04F8
+%FD70FF4B69F8F852FD6FFFA84468F8F87DFD6FFF27FC44F827A8FD6EFF27
+%8C8C20F827A8FD6DFFA844B08C27F852FD6DFFA820FCFC4426F87DFD6DFF
+%20B0FCB0204AF8FD09FFA1FFA8FD61FF4B8CFCFC8CF8F827FD07FF7DF87D
+%F87DFD60FF528DFCB0FC4B26F8A8FD06FF204B27F8FD61FF7D68FCFCFC8C
+%4AF827FD05FF27F827F852FD61FFA869FCB0FCB02074F8FD04FFA8204BF8
+%F8A8FD61FFA844FD04FC4492F87DFFFFFF2068F8F8F8FD62FF7D69FCB0FC
+%B02050F8A8FFFF526944F8F852FD62FF7668FCFCFC684AF827FFFFA8208C
+%68F8F852FD62FF27B0FCB0FC274AF87DFFFF7644B02050F87DFD45FFA852
+%FD1B2720FCFCFC6820F8F8272727F8FCFC206EF8F8FD202752A8FD22FF7D
+%FD1CF82044B0FCB0F874FD04F82069FCB0449EFD23F827FD22FF27F8F8F8
+%FD1927F8FCFCFC4474F8F8272727208CFCFC6844F8F8FD1F27F8F8F87DFD
+%21FFF8F8F8FD19FF4B69FCB08C206EF852FFFFA844B0FCB06898F87DFD1F
+%FFA8F8F827FD21FFF8F827FD18FF2744FCFCFC684426F8A8FFFF4B68FCFC
+%FC8C44F827FD20FFF8F827FD21FFF8F827FD17FF764BFCB0FCB0F8C0F852
+%FFFFFF27FCB0FCB0FC4B2027FD20FFF8F827FD21FFF8F827FD16FF7D20FD
+%04FC8C4A44F87DFFFFA844FD05FC204AF8FD20FFF8F827FD21FFF8F827FD
+%16FF278CB0FCB0FC696E26F8FFFFFF768DFCB0FCB0FC444AF87DFD1FFFF8
+%F827FD21FFF8F827FD10FF4BA1A8FFFF5268FD05FC20C0F852FFFFFF4B8C
+%FD05FC6844F852FD1FFFF8F827FD21FFF8F827FD05FF7D52275227522752
+%2752274B27F8F85220B0FCB0FCB0FC4B92F8F852275220B0FCB0FCB0FCB0
+%2026F852275227522752275227522752275227522752275227522752A8FD
+%05FFF8F827FD21FFF8F827FD04FF52FD0AF8206820F8F8F88CFD05FC8C44
+%74FD05F820FD07FC44FD1CF87DFD04FFF8F827FD21FFF8F827FFFFFFA8FD
+%0AF8204444F826F820FCB0FCB0FCB08C744AFD05F844B0FCB0FCB0FCB068
+%4AFD1BF827FD04FFF8F827FD21FFF8F827FFFFFFA8FD0BF88CF8F8F82068
+%FD06FC8C444AFD05F868FD08FC2020FD1BF8FD04FFF8F827FD21FFF8F827
+%FFFFFFA8FD0AF8458C20F8F820B0FCB0FCB0FCB0FC266EFD05F844B0FCB0
+%FCB0FCB0FC6944FD1BF8FD04FFF8F827FD21FFF8F827FFFFFFA8FD09F820
+%6868F8F8F820FD08FC449EFD05F868FD08FC8C20FD1BF8FD04FFF8F827FD
+%21FFF8F827FFFFFF7DFD0AF8B044F8F8F820B0FCB0FCB0FCB0FC8D2026FD
+%04F844B0FCB0FCB0FCB0FCB0446EFD1AF8FD04FFF8F827FD21FFF8F827FF
+%FFFFA8FD09F844FC20F8F8F820FD09FC4420FD04F820FD0AFC2020FD19F8
+%FD04FFF8F827FD21FFF8F827FFFFFFA8FD08F8218CB02026F8F820B0FCB0
+%FCB0FCB0FCB0FC20FD04F820B0FCB0FCB0FCB0FCB0FC6944FD19F8FD04FF
+%F8F827FD21FFF8F827FFFFFFA8FD09F8FCFC444AF85220FD0AFC8C20F8F8
+%274B8CFD0AFC2020F8F87D527D527D527D527D527D27FD0AF8FD04FFF8F8
+%27FD21FFF8F827FFFFFFA8FD08F845FCB02074F8A820B0FCB0FCB0FCB0FC
+%B0FCB06820F827A84BFCB0FCB0FCB0FCB0FCB08C2020F852FD0BFF27FD09
+%F8FD04FFF8F827FD21FFF8F827FFFFFFA8FD07F82068FCFC206EF87D4B8C
+%FD0BFC4420F827208CFD0AFC6820F8F852FD0AFFA8FD09F8FD04FFF8F827
+%FD21FFF8F827FFFFFFA8FD07F820B0FCB0209EF87D7D69FCB0FCB0FCB0FC
+%B0FCB0FCB0444BF87620B0FCB0FCB0FCB0FCB0FCB0685120F8A8FD09FFA8
+%FD09F8FD04FFF8F827FD21FFF8F827FFFFFFA8FD07F844FCFCFC686EF827
+%FF20FD0DFC2026F82068FD0BFC2074F852FD09FFA8FD09F8FD04FFF8F827
+%FD21FFF8F827FFFFFF7DFD06F82068B0FCB0686E26F8A87668B0FCB0FCB0
+%FCB0FCB0FCB0FCB0204AF820FCB0FCB0FCB0FCB0FCB0FCB0204AF8FD09FF
+%7DFD09F8FD04FFF8F827FD21FFF8F827FFFFFFA8FD07F88CFD04FCF874F8
+%7DA820FD0DFC8CF8F8F868FD0BFC4420F852FD08FFA8FD09F8FD04FFF8F8
+%27FD21FFF8F827FFFFFFA8FD06F820FCB0FCB0FC4B98F827FF4B8DFCB0FC
+%B0FCB0FCB0FCB0FCB0FC8D44F8F8B0FCB0FCB0FCB0FCB0FCB0FC27F827FD
+%08FFA8FD09F8FD04FFF8F827FD21FFF8F827FFFFFFA8FD06F820FD05FC68
+%4A44F87DFF20FD0EFC20202044FD0BFC444AF8A8FD07FFA8FD09F8FD04FF
+%F8F827FD21FFF8F827FFFFFFA8FD06F821FCB0FCB0FCB0209EF827FF4C8C
+%B0FCB0FCB0FCB0FCB0FCB0FCB0684AF820FCB0FCB0FCB0FCB0FCB0FCB020
+%F87DFD07FFA8FD09F8FD04FFF8F827FD21FFF8F827FFFFFFA8FD06F844FD
+%06FC684426F8A8A820FD0EFCF84AF868FD0BFC20F852FD07FFA8FD09F8FD
+%04FFF8F827FD21FFF8F827FFFFFFA8FD06F869FCB0FCB0FCB0FC4B74F827
+%FF4B8DFCB0FCB0FCB0FCB0FCB0FCB0FC694AF820B0FCB0FCB0FCB0FCB0FC
+%B0684AF8FD07FFA8FD09F8FD04FFF8F827FD21FFF8F827FFFFFFA8FD06F8
+%44FD07FC8C2644F87DFF20FD0DFC8C20F820FD0BFC8C20F8A8FD06FFA8FD
+%09F8FD04FFF8F827FD21FFF8F827FFFFFF7DFD06F869FCB0FCB0FCB0FCB0
+%4474F826A84B8CB0FCB0FCB0FCB0FCB0FCB0FCB08C2020B0FCB0FCB0FCB0
+%FCB0FCB0FC20F87DFD06FF7DFD09F8FD04FFF8F827FD21FFF8F827FFFFFF
+%A8FD06F844FD09FCF874F8527D44FD0EFC8C8CFD0CFC44F827FD06FFA8FD
+%09F8FD04FFF8F827FD21FFF8F827FFFFFFA8FD06F821FCB0FCB0FCB0FCB0
+%FCB0204AF8A821B0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0
+%FCB0FCB0FC8DF827FD06FFA8FD09F8FD04FFF8F827FD21FFF8F827FFFFFF
+%A8FD07F8FD0AFC8C20F8F87D44FD1BFC8C20F8FD06FFA8FD09F8FD04FFF8
+%F827FD21FFF8F827FFFFFFA8FD06F82068B0FCB0FCB0FCB0FCB0FC6920F8
+%5227FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0
+%20F87DFD05FFA8FD09F8FD04FFF8F827FD21FFF8F827FFFFFFA8FD07F820
+%FD0BFC20F8F820FD1CFC44F87DFD05FFA8FD09F8FD04FFF8F827FD21FFF8
+%F827FFFFFFA8FD07F8208DFCB0FCB0FCB0FCB0FCB08C26F8528CB0FCB0FC
+%B0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB044F852FD05FFA8
+%FD09F8FD04FFF8F827FD21FFF8F827FFFFFFA8FD08F820FD0BFC44F8F868
+%FD1BFC68F827FD05FFA8FD09F8FD04FFF8F827FD21FFF8F827FFFFFF7DFD
+%08F8208CB0FCB0FCB0FCB0FCB0FCB020F844B0FCB0FCB0FCB0FCB0FCB0FC
+%B0FCB0FCB0FCB0FCB0FCB0FCB0FCB0684AF8FD05FF7DFD09F8FD04FFF8F8
+%27FD21FFF8F827FFFFFFA8FD09F820FD0BFC8CF868FD1BFC8CF8F8FD05FF
+%A8FD09F8FD04FFF8F827FD21FFF8F827FFFFFFA8FD09F8208DFCB0FCB0FC
+%B0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FC
+%B0FCB0FCB08C4BF8A8FD04FFA8FD09F8FD04FFF8F827FD21FFF8F827FFFF
+%FFA8FD09F82720FD28FC8C20F87DFD04FFA8FD09F8FD04FFF8F827FD21FF
+%F8F827FFFFFFA8FD09F8277644B0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0
+%FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB08C74F87DFD04FFA8
+%FD09F8FD04FFF8F827FD21FFF8F827FFFFFFA8FD09F827FF278CFD26FC44
+%6EF827FD04FFA8FD09F8FD04FFF8F827FD21FFF8F827FFFFFFA8FD09F827
+%FFA84BFCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FC
+%B0FCB0FCB0FCB0FCB0FCB02074F852FD04FFA8FD09F8FD04FFF8F827FD21
+%FFF8F827FFFFFFA8FD09F827FFFF5268FD24FC684AF8F8A8FD04FFA8FD09
+%F8FD04FFF8F827FD21FFF8F827FFFFFF7DFD09F827FFFFFF208DFCB0FCB0
+%FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0
+%FC20F827A8FD05FF7DFD09F8FD04FFF8F827FD21FFF8F827FFFFFFA8FD09
+%F827FD04FFF88CFD21FC8CF8F87DFD06FFA8FD09F8FD04FFF8F827FD21FF
+%F8F827FFFFFFA8FD08F82727FD04FFA820B0FCB0FCB0FCB0FCB0FCB0FCB0
+%FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB020F852FD07FF52FD09F8
+%FD04FFF8F827FD21FFF8F827FFFFFFA8FD0AF8277D7DA87D7DF8FD1FFC20
+%2027A87DA87DA87DA852FD0AF8FD04FFF8F827FD21FFF8F827FFFFFFA8FD
+%10F82020B0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FC
+%B0FCB06820FD14F8FD04FFF8F827FD21FFF8F827FFFFFFA8FD11F82020FD
+%1BFC6820FD15F8FD04FFF8F827FD21FFF8F827FFFFFFA8FD12F82120B0FC
+%B0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB0FCB06821FD16F8FD04
+%FFF8F827FD21FFF8F827FFFFFFA8FD13F820F88CFD16FC4420FD17F8FD04
+%FFF8F827FD21FFF8F827FFFFFF7DFD14F820F88DFCB0FCB0FCB0FCB0FCB0
+%FCB0FCB0FCB0FCB0FC8DF820FD18F8FD04FFF8F827FD21FFF8F827FFFFFF
+%A8FD17F82068FD0FFC8C44FD1BF8FD04FFF8F827FD21FFF8F827FD04FF27
+%FD17F82120698CB0FCB0FCB0FCB0FCB0FC8D4427FD1BF852FD04FFF8F827
+%FD21FFF8F827FD04FF7DFD1AF820F820446844684444202620FD1CF827A8
+%FD04FFF8F827FD21FFF8F827FD05FFA87D527D527D527D527D527D527D52
+%7D527D527D527D527DFD0AF82050FD07F827527D527D527D527D527D527D
+%527D527D527D527D52A8FD06FFF8F827FD21FFF8F827FD1CFFFD15F8A8FD
+%1BFFF8F827FD21FFF8F827FD1BFF52FD16F8FD1BFFF8F827FD21FFF8F827
+%FD1AFF52FD18F8FD1AFFF8F827FD21FFF8F827FD19FF2727FD19F8A8FD18
+%FFF8F827FD21FFF8F827FD17FF7DFD1DF827A8FD16FFF8F827FD21FFF8F8
+%27FD15FFFD23F8A8FD14FFF8F827FD21FFF8F827FD14FF52FD24F8FD14FF
+%F8F827FD21FFF8F827FD15FF2727F827F827F827F827F827F827F827F827
+%F827F827F827F827F827F827F827F827F8A8FD14FFF8F827FD21FFF8F827
+%FD4DFFF8F827FD21FFF8F827FD4DFFF8F827FD21FFF8F8F8277D527D527D
+%527D527D527D527D527D527D527D527D527D527D527D527D527D527D527D
+%527D527D527D527D527D527D527D527D527D527D527D527D527D527D527D
+%527D527D527D527D527D27F8F852FD21FF52FD51F87DFD22FF52FD4EF827
+%7DFD25FFFD4CA8FD91FFCACACAFFFFFF9AC3CAFFFFCA93B59ACAFD05FFCA
+%FD06FFCACACAFD04FFCA93B593BC6FFFFFCA93B593BC93FFCABC9AFFFFFF
+%93BCFFFFFFCA9AB593CAFD05FFB6A1FFFFFF94CAFD04FFCAFFFFFF93B593
+%BC93FD04FFCAC4FD13FF9A448DCAFFA18C44BCFFBC6820F8208CCAFFFF93
+%93688D93FFFFFF8C68448D8CCAFFCA8C20F8F8F8449ACA8C20F8F8F8449A
+%BC448CCAFF9A6868CAFFBC6820F84468FD04FFCA688CCAFF9A6868CAFFFF
+%8C688DFF8C20F8F8F82093FF9AB044688CBCCAFD10FFCA6944BCFFB62068
+%CAFF8CF82069444493FF8C44F820F8689AFF9320F86944208CFFCA68F893
+%8CB58CCACA68F8938CB58CCA9A4420BCFFC32069CAFF8CF82068204593FF
+%FFFF9A4444C3FFC320459AFFCA6920B6FF93F8938CB58CBCFFB5F8444445
+%68C3FD11FF8CF88CFF8CF88CFFC368F8B0C3B0F8B5FF8DF8208C68F8B5FF
+%B5F88C9ABC208DFFCA442093FD04FFCA442093FD04FFBC20F88CFF762020
+%CAA144F8B5C38CF8B5FFFFFFB5F8208CFFC368F8B5FFC4442093FF8CF88C
+%FD04FFCA68208CCA8C208CFD11FFB5F893C393F8B5FFCA44449AFF934493
+%FF68F88CFF93B59AFF68F88CFF764444CAC46920BCFD04FFC46920BCFD04
+%FF9320F893A1BC204493CA204493FF934493FFFFFF8CF8F8B5FFFF8CF88C
+%FF932044CAFF8DF8B5FD04FFCA68F8B5FFB5F893FD11FF9A4420FC20449A
+%FFC368F8BCFFCA93CAC368F8B0FD05FF69F88DFFA12068C3CA442093FD04
+%FFCA442093FD04FF93F8F82093932020BCC34420BCFFCA93A1FFFFCA8DF8
+%F844CAFFB5F88CFF93F88CCAFF68F88CFD04FFCA44F88CFF8CF88CFD12FF
+%8CF844F88CFFFFCA44F894FD04FFCA44F88DFD05FF68F88CFFCA4544CACA
+%6920BCFD04FFCA6920BCFD04FF8CF8F8F88CBD20449ACA442093FD06FFCA
+%44F8F8449AFF932068CA8CF88CFFFF68F8B5FD04FFCA68F8B5FFB5F8B5FD
+%12FF93F8F8F8B5FFFFC368F8B093CACAFFC36820BCFD05FF6FF88DC39320
+%68CACA44208CCAC3CAFFCA20208CCAC3CAFFB5F8F8F8688C2020BCC368F8
+%FC6FCACAFFFFFF93202044F8B5FFBD20449393F893FFCA44F88CCAC3CAFF
+%CA44F88CCA8CF88CFD12FFA144F84493FFFFFF8C20F84444B5CAFF444493
+%FD05FF68F8446920F88CFFCA44F84444688CFFA144F84444688CFF8DF820
+%4420B020449AFF8C20204444B5FFFFFFB5F89368F88CFFC46920B544449A
+%FFC469F82044698CFFC469F868442020BCFD12FFCA44F844CAFFFFFFC38C
+%68202020BCFF682093FD05FF6FF8F8F82068BCFFCA20F8F820688DFFA120
+%F8F820688DFFB5F86868F88C2020BCFFC38C68442020BCFFFF8CF88C8CF8
+%68C3FF8CF88C2044CAFFCA44F8F82044B0CACA44F8F8F8208DCAFD12FFA1
+%68F8699BFD05FFCACA8C2093FF44F88CFD05FF69F8F8F844BCFFFFCA44F8
+%4593CAFFFFA144F84593CAFFFF8DF844B5F868F8459AFFFFFFCAC38C2093
+%FFCA93F8938C2044C3FFB5F868F893CAFFCA69F8208CCAFFFFCA69F8F8F8
+%93CAFD13FF9420F8F8B5FD07FFB5F893C368F8B5FD05FF9AF8F8F8208CFF
+%FFCA44208CFD04FFCA20208CFD04FFB5F8689344F8F820BCFD05FFB5F8B5
+%FFBC202093BC202093FF8C20F8F88CFFFFCA44F88CFD04FFCA44F8F8F844
+%C3FD13FF8CF868208CFFFFFFA1C3FFFF8CF868CA44F88DFD05FF6FF86893
+%F8B5FFFFC46920BCFD04FFC46820BCFD04FF8CF88CCA68F8F84493FF9AC3
+%CAFF8DF86FFF932068B58C44F8B5FFBC20F8F8B5FFFFCA68F8B5FD04FFCA
+%68F8B0442093FD12FFCA68F8FC44449AFFC38C44BCFF93F88DC368F8B5FF
+%FF68B0FF93F86F8CF844CAFFCA442093FD04FFCA442093FD04FF93F88DFF
+%93F8F820BCC38C449AFFB5F869FFB0FD06F868FFA168F82093FFFFFF44F8
+%8CFD04FFCA4420938DF88DFD12FFBC2045BC93F8B5FFCA442193FF8CF88C
+%CA44F893FF9A4568FF6FF88CC3444593FFCA69209AFD04FFCA69209AFD04
+%FF8CF88CFF9321F8449ACA442093FF8DF868FF8CF820934420F8699BFF8C
+%F844C3FFFFFF6FF8B5FD04FFCA6820BD8D2068CAFD11FF8CF868FF8CF868
+%FFCA68F8B09BFCF88DC368F8B593B5F868C39AF88DCA68F8B5FFCA442093
+%FD04FFCA442093FD04FFB5F88DFFCA44F820BCC368F88C9AB5F86F9A4420
+%93CAC38C20F893FF93F868C3FFFFFF68F88CFD04FFCA442093BD204493FD
+%10FFCA93F8B5FFBC20449AFF8CF8206920208CFF8CF8204444F88CFF6FF8
+%8CFF8CF868FFCA68F8938C8D8CC3CA68F8938C8D8CC38DF88CFFFFB5F844
+%9AFF8CF82068F82093BC2093CAFFFFCA68F88CFF8DF88CFD04FFB5F8938C
+%B568B5C469F8BCCA93F8B5FD10FFCA688DA1FFCA8D2093FFBC6820F82068
+%A1FFBC44F8F8204493FFB5F88DFF93204494CA44FD05F88CCA44FD05F88C
+%93208CFFFF934444BCFFBC6820F82068CA9A8C93FD04FFB020FCCABC4493
+%FD04FF8CFD05F868CA682093FF8CF868CAFD10FFB5CAFFFFFFBCB59AFFFF
+%CA93B593CAFFFFFFC38DB593C3FFFF9AB59AFFCAB593FFFFB58CB58DB58C
+%CAFFB58CB58DB58CCACAB59AFFFFFF93CAFFFFFFCA93B593CAFFFFC3FD05
+%FFCAB5CAFFFFB59AFD04FFBC8DB58CB58DBCFFB68DCAFFCA8CBCFDFCFFFD
+%FCFFFDFCFFFDFCFFFDFCFFFDFCFFFDECFFFF
+%%EndData
+%%EndComments
+%%BeginProlog
+%%BeginResource: procset Adobe_level2_AI5 1.2 0
+%%Title: (Adobe Illustrator (R) Version 5.0 Level 2 Emulation)
+%%Version: 1.2 0
+%%CreationDate: (04/10/93) ()
+%%Copyright: ((C) 1987-1996 Adobe Systems Incorporated All Rights Reserved)
+userdict /Adobe_level2_AI5 26 dict dup begin
+ put
+ /packedarray where not
+ {
+ userdict begin
+ /packedarray
+ {
+ array astore readonly
+ } bind def
+ /setpacking /pop load def
+ /currentpacking false def
+ end
+ 0
+ } if
+ pop
+ userdict /defaultpacking currentpacking put true setpacking
+ /initialize
+ {
+ Adobe_level2_AI5 begin
+ } bind def
+ /terminate
+ {
+ currentdict Adobe_level2_AI5 eq
+ {
+ end
+ } if
+ } bind def
+ mark
+ /setcustomcolor where not
+ {
+ /findcmykcustomcolor
+ {
+ (AI8_CMYK_CustomColor)
+ 6 packedarray
+ } bind def
+ /findrgbcustomcolor
+ {
+ (AI8_RGB_CustomColor)
+ 5 packedarray
+ } bind def
+ /setcustomcolor
+ {
+ exch
+ aload pop dup
+ (AI8_CMYK_CustomColor) eq
+ {
+ pop pop
+ 4
+ {
+ 4 index mul
+ 4 1 roll
+ } repeat
+ 5 -1 roll pop
+ setcmykcolor
+ }
+ {
+ dup (AI8_RGB_CustomColor) eq
+ {
+ pop pop
+ 3
+ {
+ 1 exch sub
+ 3 index mul
+ 1 exch sub
+ 3 1 roll
+ } repeat
+ 4 -1 roll pop
+ setrgbcolor
+ }
+ {
+ pop
+ 4
+ {
+ 4 index mul 4 1 roll
+ } repeat
+ 5 -1 roll pop
+ setcmykcolor
+ } ifelse
+ } ifelse
+ }
+ def
+ } if
+ /setAIseparationgray
+ {
+ false setoverprint
+ 0 setgray
+ /setseparationgray where{
+ pop setseparationgray
+ }{
+ /setcolorspace where{
+ pop
+ [/Separation (All) /DeviceCMYK {dup dup dup}] setcolorspace
+ 1 exch sub setcolor
+ }{
+ setgray
+ }ifelse
+ }ifelse
+ } def
+
+ /gt38? mark {version cvr cvx exec} stopped {cleartomark true} {38 gt exch pop} ifelse def
+ userdict /deviceDPI 72 0 matrix defaultmatrix dtransform dup mul exch dup mul add sqrt put
+ userdict /level2?
+ systemdict /languagelevel known dup
+ {
+ pop systemdict /languagelevel get 2 ge
+ } if
+ put
+/level2ScreenFreq
+{
+ begin
+ 60
+ HalftoneType 1 eq
+ {
+ pop Frequency
+ } if
+ HalftoneType 2 eq
+ {
+ pop GrayFrequency
+ } if
+ HalftoneType 5 eq
+ {
+ pop Default level2ScreenFreq
+ } if
+ end
+} bind def
+userdict /currentScreenFreq
+ level2? {currenthalftone level2ScreenFreq} {currentscreen pop pop} ifelse put
+level2? not
+ {
+ /setcmykcolor where not
+ {
+ /setcmykcolor
+ {
+ exch .11 mul add exch .59 mul add exch .3 mul add
+ 1 exch sub setgray
+ } def
+ } if
+ /currentcmykcolor where not
+ {
+ /currentcmykcolor
+ {
+ 0 0 0 1 currentgray sub
+ } def
+ } if
+ /setoverprint where not
+ {
+ /setoverprint /pop load def
+ } if
+ /selectfont where not
+ {
+ /selectfont
+ {
+ exch findfont exch
+ dup type /arraytype eq
+ {
+ makefont
+ }
+ {
+ scalefont
+ } ifelse
+ setfont
+ } bind def
+ } if
+ /cshow where not
+ {
+ /cshow
+ {
+ [
+ 0 0 5 -1 roll aload pop
+ ] cvx bind forall
+ } bind def
+ } if
+ } if
+ cleartomark
+ /anyColor?
+ {
+ add add add 0 ne
+ } bind def
+ /testColor
+ {
+ gsave
+ setcmykcolor currentcmykcolor
+ grestore
+ } bind def
+ /testCMYKColorThrough
+ {
+ testColor anyColor?
+ } bind def
+ userdict /composite?
+ 1 0 0 0 testCMYKColorThrough
+ 0 1 0 0 testCMYKColorThrough
+ 0 0 1 0 testCMYKColorThrough
+ 0 0 0 1 testCMYKColorThrough
+ and and and
+ put
+ composite? not
+ {
+ userdict begin
+ gsave
+ /cyan? 1 0 0 0 testCMYKColorThrough def
+ /magenta? 0 1 0 0 testCMYKColorThrough def
+ /yellow? 0 0 1 0 testCMYKColorThrough def
+ /black? 0 0 0 1 testCMYKColorThrough def
+ grestore
+ /isCMYKSep? cyan? magenta? yellow? black? or or or def
+ /customColor? isCMYKSep? not def
+ end
+ } if
+ end defaultpacking setpacking
+%%EndResource
+%%BeginResource: procset Adobe_typography_AI5 1.0 1
+%%Title: (Typography Operators)
+%%Version: 1.0 1
+%%CreationDate:(6/10/1996) ()
+%%Copyright: ((C) 1987-1996 Adobe Systems Incorporated All Rights Reserved)
+currentpacking true setpacking
+userdict /Adobe_typography_AI5 68 dict dup begin
+put
+/initialize
+{
+ begin
+ begin
+ Adobe_typography_AI5 begin
+ Adobe_typography_AI5
+ {
+ dup xcheck
+ {
+ bind
+ } if
+ pop pop
+ } forall
+ end
+ end
+ end
+ Adobe_typography_AI5 begin
+} def
+/terminate
+{
+ currentdict Adobe_typography_AI5 eq
+ {
+ end
+ } if
+} def
+/modifyEncoding
+{
+ /_tempEncode exch ddef
+ /_pntr 0 ddef
+ {
+ counttomark -1 roll
+ dup type dup /marktype eq
+ {
+ pop pop exit
+ }
+ {
+ /nametype eq
+ {
+ _tempEncode /_pntr dup load dup 3 1 roll 1 add ddef 3 -1 roll
+ put
+ }
+ {
+ /_pntr exch ddef
+ } ifelse
+ } ifelse
+ } loop
+ _tempEncode
+} def
+/havefont
+{
+ systemdict /languagelevel known
+ {
+ /Font resourcestatus dup
+ { exch pop exch pop }
+ if
+ }
+ {
+ systemdict /FontDirectory get 1 index known
+ { pop true }
+ {
+ systemdict /fileposition known
+ {
+ dup length 6 add exch
+ Ss 6 250 getinterval
+ cvs pop
+ Ss exch 0 exch getinterval
+ status
+ { pop pop pop pop true }
+ { false }
+ ifelse
+ }
+ {
+ pop false
+ }
+ ifelse
+ }
+ ifelse
+ }
+ ifelse
+} def
+/TE
+{
+ StandardEncoding 256 array copy modifyEncoding
+ /_nativeEncoding exch def
+} def
+/subststring {
+ exch 2 index exch search
+ {
+ exch pop
+ exch dup () eq
+ {
+ pop exch concatstring
+ }
+ {
+ 3 -1 roll
+ exch concatstring
+ concatstring
+ } ifelse
+ exch pop true
+ }
+ {
+ pop pop false
+ } ifelse
+} def
+/concatstring {
+ 1 index length 1 index length
+ 1 index add
+ string
+ dup 0 5 index putinterval
+ dup 2 index 4 index putinterval
+ 4 1 roll pop pop pop
+} def
+%
+/TZ
+{
+ dup type /arraytype eq
+ {
+ /_wv exch def
+ }
+ {
+ /_wv 0 def
+ } ifelse
+ /_useNativeEncoding exch def
+ 2 index havefont
+ {
+ 3 index
+ 255 string
+ cvs
+
+ dup
+ (_Symbol_)
+ eq
+ {
+ pop
+ 2 index
+ findfont
+
+ }
+ {
+ 1 index 0 eq
+ {
+ dup length 1 sub
+ 1 exch
+ getinterval
+
+ cvn
+ findfont
+ }
+ {
+ pop 2 index findfont
+ } ifelse
+ } ifelse
+ }
+ {
+ dup 1 eq
+ {
+ 2 index 64 string cvs
+ dup (-90pv-RKSJ-) (-83pv-RKSJ-) subststring
+ {
+ exch pop dup havefont
+ {
+ findfont false
+ }
+ {
+ pop true
+ } ifelse
+ }
+ {
+ pop dup
+ (-90ms-RKSJ-) (-Ext-RKSJ-) subststring
+ {
+ exch pop dup havefont
+ {
+ findfont false
+ }
+ {
+ pop true
+ } ifelse
+ }
+ {
+ pop pop true
+ } ifelse
+ } ifelse
+ {
+ 1 index 1 eq
+ {
+ /Ryumin-Light-Ext-RKSJ-V havefont
+ {/Ryumin-Light-Ext-RKSJ-V}
+ {/Courier}
+ ifelse
+ }
+ {
+ /Ryumin-Light-83pv-RKSJ-H havefont
+ {/Ryumin-Light-83pv-RKSJ-H}
+ {/Courier}
+ ifelse
+ } ifelse
+ findfont
+ [1 0 0.5 1 0 0] makefont
+ } if
+ }
+ {
+ /Courier findfont
+ } ifelse
+ } ifelse
+ _wv type /arraytype eq
+ {
+ _wv makeblendedfont
+ } if
+ dup length 10 add dict
+ begin
+ mark exch
+ {
+ 1 index /FID ne
+ {
+ def
+ } if
+ cleartomark mark
+ } forall
+ pop
+ /FontScript exch def
+ /FontDirection exch def
+ /FontRequest exch def
+ /FontName exch def
+ counttomark 0 eq
+ {
+ 1 _useNativeEncoding eq
+ {
+ /Encoding _nativeEncoding def
+ } if
+ cleartomark
+ }
+ {
+ /Encoding load 256 array copy
+ modifyEncoding /Encoding exch def
+ } ifelse
+ FontName currentdict
+ end
+ definefont pop
+} def
+/tr
+{
+ _ax _ay 3 2 roll
+} def
+/trj
+{
+ _cx _cy _sp _ax _ay 6 5 roll
+} def
+/a0
+{
+ /Tx
+ {
+ dup
+ currentpoint 3 2 roll
+ tr _psf
+ newpath moveto
+ tr _ctm _pss
+ } ddef
+ /Tj
+ {
+ dup
+ currentpoint 3 2 roll
+ trj _pjsf
+ newpath moveto
+ trj _ctm _pjss
+ } ddef
+} def
+/a1
+{
+W B
+} def
+/e0
+{
+ /Tx
+ {
+ tr _psf
+ } ddef
+ /Tj
+ {
+ trj _pjsf
+ } ddef
+} def
+/e1
+{
+W F
+} def
+/i0
+{
+ /Tx
+ {
+ tr sp
+ } ddef
+ /Tj
+ {
+ trj jsp
+ } ddef
+} def
+/i1
+{
+ W N
+} def
+/o0
+{
+ /Tx
+ {
+ tr sw rmoveto
+ } ddef
+ /Tj
+ {
+ trj swj rmoveto
+ } ddef
+} def
+/r0
+{
+ /Tx
+ {
+ tr _ctm _pss
+ } ddef
+ /Tj
+ {
+ trj _ctm _pjss
+ } ddef
+} def
+/r1
+{
+W S
+} def
+/To
+{
+ pop _ctm currentmatrix pop
+} def
+/TO
+{
+ iTe _ctm setmatrix newpath
+} def
+/Tp
+{
+ pop _tm astore pop _ctm setmatrix
+ _tDict begin
+ /W
+ {
+ } def
+ /h
+ {
+ } def
+} def
+/TP
+{
+ end
+ iTm 0 0 moveto
+} def
+/Tr
+{
+ _render 3 le
+ {
+ currentpoint newpath moveto
+ } if
+ dup 8 eq
+ {
+ pop 0
+ }
+ {
+ dup 9 eq
+ {
+ pop 1
+ } if
+ } ifelse
+ dup /_render exch ddef
+ _renderStart exch get load exec
+} def
+/iTm
+{
+ _ctm setmatrix _tm concat
+ _shift aload pop _lineorientation 1 eq { exch } if translate
+ _scale aload pop _lineorientation 1 eq _yokoorientation 1 eq or { exch } if scale
+} def
+/Tm
+{
+ _tm astore pop iTm 0 0 moveto
+} def
+/Td
+{
+ _mtx translate _tm _tm concatmatrix pop iTm 0 0 moveto
+} def
+/iTe
+{
+ _render -1 eq
+ {
+ }
+ {
+ _renderEnd _render get dup null ne
+ {
+ load exec
+ }
+ {
+ pop
+ } ifelse
+ } ifelse
+ /_render -1 ddef
+} def
+/Ta
+{
+ pop
+} def
+/Tf
+{
+ 1 index type /nametype eq
+ {
+ dup 0.75 mul 1 index 0.25 mul neg
+ } if
+ /_fontDescent exch ddef
+ /_fontAscent exch ddef
+ /_fontSize exch ddef
+ /_fontRotateAdjust _fontAscent _fontDescent add 2 div neg ddef
+ /_fontHeight _fontSize ddef
+ findfont _fontSize scalefont setfont
+} def
+/Tl
+{
+ pop neg 0 exch
+ _leading astore pop
+} def
+/Tt
+{
+ pop
+} def
+/TW
+{
+ 3 npop
+} def
+/Tw
+{
+ /_cx exch ddef
+} def
+/TC
+{
+ 3 npop
+} def
+/Tc
+{
+ /_ax exch ddef
+} def
+/Ts
+{
+ 0 exch
+ _shift astore pop
+ currentpoint
+ iTm
+ moveto
+} def
+/Ti
+{
+ 3 npop
+} def
+/Tz
+{
+ count 1 eq { 100 } if
+ 100 div exch 100 div exch
+ _scale astore pop
+ iTm
+} def
+/TA
+{
+ pop
+} def
+/Tq
+{
+ pop
+} def
+/Tg
+{
+ pop
+} def
+/TG
+{
+ pop
+} def
+/Tv
+{
+ /_lineorientation exch ddef
+} def
+/TV
+{
+ /_charorientation exch ddef
+} def
+/Ty
+{
+ dup /_yokoorientation exch ddef 1 sub neg Tv
+} def
+/TY
+{
+ pop
+} def
+/T~
+{
+ Tx
+} def
+/Th
+{
+ pop pop pop pop pop
+} def
+/TX
+{
+ pop
+} def
+/Tk
+{
+ _fontSize mul 1000 div
+ _lineorientation 0 eq { neg 0 } { 0 exch } ifelse
+ rmoveto
+ pop
+} def
+/TK
+{
+ 2 npop
+} def
+/T*
+{
+ _leading aload pop
+ _lineorientation 0 ne { exch } if
+ Td
+} def
+/T*-
+{
+ _leading aload pop
+ _lineorientation 0 ne { exch } if
+ exch neg exch neg
+ Td
+} def
+/T-
+{
+ _ax neg 0 rmoveto
+ _lineorientation 1 eq _charorientation 0 eq and { 1 TV _hyphen Tx 0 TV } { _hyphen Tx } ifelse
+} def
+/T+
+{
+} def
+/TR
+{
+ _ctm currentmatrix pop
+ _tm astore pop
+ iTm 0 0 moveto
+} def
+/TS
+{
+ currentfont 3 1 roll
+ /_Symbol_ findfont _fontSize scalefont setfont
+
+ 0 eq
+ {
+ Tx
+ }
+ {
+ Tj
+ } ifelse
+ setfont
+} def
+/Xb
+{
+ pop pop
+} def
+/Tb /Xb load def
+/Xe
+{
+ pop pop pop pop
+} def
+/Te /Xe load def
+/XB
+{
+} def
+/TB /XB load def
+currentdict readonly pop
+end
+setpacking
+%
+/X^
+{
+ currentfont 5 1 roll
+ dup havefont
+ {
+ findfont _fontSize scalefont setfont
+ }
+ {
+ pop
+ exch
+ } ifelse
+ 2 index 0 eq
+ {
+ Tx
+ }
+ {
+ Tj
+ } ifelse
+ pop pop
+ setfont
+} def
+/T^ /X^ load def
+%%EndResource
+%%BeginProcSet: Adobe_ColorImage_AI6 1.3 0
+userdict /Adobe_ColorImage_AI6 known not
+{
+ userdict /Adobe_ColorImage_AI6 53 dict put
+} if
+userdict /Adobe_ColorImage_AI6 get begin
+/initialize {
+ Adobe_ColorImage_AI6 begin
+ Adobe_ColorImage_AI6 {
+ dup type /arraytype eq {
+ dup xcheck {
+ bind
+ } if
+ } if
+ pop pop
+ } forall
+} def
+/terminate { end } def
+currentdict /Adobe_ColorImage_AI6_Vars known not {
+ /Adobe_ColorImage_AI6_Vars 41 dict def
+} if
+Adobe_ColorImage_AI6_Vars begin
+ /plateindex -1 def
+ /_newproc null def
+ /_proc1 null def
+ /_proc2 null def
+ /sourcearray 4 array def
+ /_ptispace null def
+ /_ptiname null def
+ /_pti0 0 def
+ /_pti1 0 def
+ /_ptiproc null def
+ /_ptiscale 0 def
+ /_pticomps 0 def
+ /_ptibuf 0 string def
+ /_gtigray 0 def
+ /_cticmyk null def
+ /_rtirgb null def
+ /XIEnable true def
+ /XIType 0 def
+ /XIEncoding 0 def
+ /XICompression 0 def
+ /XIChannelCount 0 def
+ /XIBitsPerPixel 0 def
+ /XIImageHeight 0 def
+ /XIImageWidth 0 def
+ /XIImageMatrix null def
+ /XIRowBytes 0 def
+ /XIFile null def
+ /XIBuffer1 null def
+ /XIBuffer2 null def
+ /XIBuffer3 null def
+ /XIDataProc null def
+ /XIColorSpace /DeviceGray def
+ /XIColorValues 0 def
+ /XIPlateList false def
+end
+/ci6colorimage /colorimage where {/colorimage get}{null} ifelse def
+/ci6image systemdict /image get def
+/ci6curtransfer systemdict /currenttransfer get def
+/ci6curoverprint /currentoverprint where {/currentoverprint get}{{_of}} ifelse def
+/ci6foureq {
+ 4 index ne {
+ pop pop pop false
+ }{
+ 4 index ne {
+ pop pop false
+ }{
+ 4 index ne {
+ pop false
+ }{
+ 4 index eq
+ } ifelse
+ } ifelse
+ } ifelse
+} def
+/ci6testplate {
+ Adobe_ColorImage_AI6_Vars begin
+ /plateindex -1 def
+ /setcmykcolor where {
+ pop
+ gsave
+ 1 0 0 0 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ 0 1 0 0 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ 0 0 1 0 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ 0 0 0 1 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ grestore
+ 1 0 0 0 ci6foureq {
+ /plateindex 0 def
+ }{
+ 0 1 0 0 ci6foureq {
+ /plateindex 1 def
+ }{
+ 0 0 1 0 ci6foureq {
+ /plateindex 2 def
+ }{
+ 0 0 0 1 ci6foureq {
+ /plateindex 3 def
+ }{
+ 0 0 0 0 ci6foureq {
+ /plateindex 5 def
+ } if
+ } ifelse
+ } ifelse
+ } ifelse
+ } ifelse
+ pop pop pop pop
+ } if
+ plateindex
+ end
+} def
+/ci6concatprocs {
+ /packedarray where {
+ pop dup type /packedarraytype eq 2 index type
+ /packedarraytype eq or
+ }{
+ false
+ } ifelse
+ {
+ /_proc2 exch cvlit def
+ /_proc1 exch cvlit def
+ _proc1 aload pop
+ _proc2 aload pop
+ _proc1 length
+ _proc2 length add
+ packedarray cvx
+ }{
+ /_proc2 exch cvlit def
+ /_proc1 exch cvlit def
+ /_newproc _proc1 length _proc2 length add array def
+ _newproc 0 _proc1 putinterval
+ _newproc _proc1 length _proc2 putinterval
+ _newproc cvx
+ } ifelse
+} def
+/ci6istint {
+ type /arraytype eq
+} def
+/ci6isspot {
+ dup type /arraytype eq {
+ dup length 1 sub get /Separation eq
+ }{
+ pop false
+ } ifelse
+} def
+/ci6spotname {
+ dup ci6isspot {dup length 2 sub get}{pop ()} ifelse
+} def
+/ci6altspace {
+ aload pop pop pop ci6colormake
+} def
+/ci6numcomps {
+ dup /DeviceGray eq {
+ pop 1
+ }{
+ dup /DeviceRGB eq {
+ pop 3
+ }{
+ /DeviceCMYK eq {
+ 4
+ }{
+ 1
+ } ifelse
+ } ifelse
+ } ifelse
+} def
+/ci6marksplate {
+ dup /DeviceGray eq {
+ pop plateindex 3 eq
+ }{
+ dup /DeviceRGB eq {
+ pop plateindex 5 ne
+ }{
+ dup /DeviceCMYK eq {
+ pop plateindex 5 ne
+ }{
+ dup ci6isspot {
+ /findcmykcustomcolor where {
+ pop
+ dup length 2 sub get
+ 0.1 0.1 0.1 0.1 5 -1 roll
+ findcmykcustomcolor 1 setcustomcolor
+ systemdict /currentgray get exec
+ 1 ne
+ }{
+ pop plateindex 5 ne
+ } ifelse
+ }{
+ pop plateindex 5 ne
+ } ifelse
+ } ifelse
+ } ifelse
+ } ifelse
+} def
+/ci6colormake {
+ dup ci6numcomps
+ exch 1 index 2 add 1 roll
+ dup 1 eq {pop}{array astore} ifelse
+ exch
+} def
+/ci6colorexpand {
+ dup ci6spotname exch
+ dup ci6istint {
+ ci6altspace
+ exch 4 1 roll
+ }{
+ 1 3 1 roll
+ } ifelse
+} def
+/ci6colortint {
+ dup /DeviceGray eq {
+ 3 1 roll 1 exch sub mul 1 exch sub exch
+ }{
+ dup /DeviceRGB eq {
+ 3 1 roll {1 exch sub 1 index mul 1 exch sub exch} forall pop 3 array astore exch
+ }{
+ dup /DeviceCMYK eq {
+ 3 1 roll {1 index mul exch} forall pop 4 array astore exch
+ }{
+ 3 1 roll mul exch
+ } ifelse
+ } ifelse
+ } ifelse
+} def
+/ci6colortocmyk {
+ dup /DeviceGray eq {
+ pop 1 exch sub 0 0 0 4 -1 roll 4 array astore
+ }{
+ dup /DeviceRGB eq {
+ pop aload pop _rgbtocmyk 4 array astore
+ }{
+ dup /DeviceCMYK eq {
+ pop
+ }{
+ ci6altspace ci6colortint ci6colortocmyk
+ } ifelse
+ } ifelse
+ } ifelse
+} def
+/ci6makeimagedict {
+ 7 dict begin
+ /ImageType 1 def
+ /Decode exch def
+ /DataSource exch def
+ /ImageMatrix exch def
+ /BitsPerComponent exch def
+ /Height exch def
+ /Width exch def
+ currentdict end
+} def
+/ci6stringinvert {
+ 0 1 2 index length 1 sub {
+ dup 2 index exch get 255 exch sub 2 index 3 1 roll put
+ } for
+} def
+/ci6stringknockout {
+ 0 1 2 index length 1 sub {
+ 255 2 index 3 1 roll put
+ } for
+} def
+/ci6stringapply {
+ 0 1 4 index length 1 sub {
+ dup
+ 4 index exch get
+ 3 index 3 1 roll
+ 3 index exec
+ } for
+ pop exch pop
+} def
+/ci6walkrgbstring {
+ 0 3 index
+ dup length 1 sub 0 3 3 -1 roll {
+ 3 getinterval {} forall
+ 5 index exec
+ 3 index
+ } for
+
+ 5 {pop} repeat
+} def
+/ci6walkcmykstring
+{
+ 0 3 index
+ dup length 1 sub 0 4 3 -1 roll {
+ 4 getinterval {} forall
+
+ 6 index exec
+
+ 3 index
+
+ } for
+
+ 5 { pop } repeat
+
+} def
+/ci6putrgbtograystr
+{
+ .11 mul exch
+
+ .59 mul add exch
+
+ .3 mul add
+
+ cvi 3 copy put
+
+ pop 1 add
+} def
+/ci6putcmyktograystr
+{
+ exch .11 mul add
+
+ exch .59 mul add
+
+ exch .3 mul add
+
+ dup 255 gt { pop 255 } if
+
+ 255 exch sub cvi 3 copy put
+
+ pop 1 add
+} def
+/ci6rgbtograyproc {
+ Adobe_ColorImage_AI6_Vars begin
+ sourcearray 0 get exec
+ XIBuffer3
+ dup 3 1 roll
+
+ /ci6putrgbtograystr load exch
+ ci6walkrgbstring
+ end
+} def
+/ci6cmyktograyproc {
+ Adobe_ColorImage_AI6_Vars begin
+ sourcearray 0 get exec
+ XIBuffer3
+ dup 3 1 roll
+
+ /ci6putcmyktograystr load exch
+ ci6walkcmykstring
+ end
+} def
+/ci6separatecmykproc {
+ Adobe_ColorImage_AI6_Vars begin
+ sourcearray 0 get exec
+
+ XIBuffer3
+
+ 0 2 index
+
+ plateindex 4 2 index length 1 sub {
+ get 255 exch sub
+
+ 3 copy put pop 1 add
+
+ 2 index
+ } for
+ pop pop exch pop
+ end
+} def
+
+/ci6compositeimage {
+ dup 1 eq {
+ pop pop image
+ }{
+ /ci6colorimage load null ne {
+ ci6colorimage
+ }{
+ 3 1 roll pop
+ sourcearray 0 3 -1 roll put
+ 3 eq {/ci6rgbtograyproc}{/ci6cmyktograyproc} ifelse load
+ image
+ } ifelse
+ } ifelse
+} def
+/ci6knockoutimage {
+ gsave
+ 0 ci6curtransfer exec 1 ci6curtransfer exec
+ eq {
+ 0 ci6curtransfer exec 0.5 lt
+ }{
+ 0 ci6curtransfer exec 1 ci6curtransfer exec gt
+ } ifelse
+ {{pop 0}}{{pop 1}} ifelse
+ systemdict /settransfer get exec
+ ci6compositeimage
+ grestore
+} def
+/ci6drawimage {
+ ci6testplate -1 eq {
+ pop ci6compositeimage
+ }{
+ dup type /arraytype eq {
+ dup length plateindex gt {plateindex get}{pop false} ifelse
+ }{
+ {
+ true
+ }{
+ dup 1 eq {plateindex 3 eq}{plateindex 3 le} ifelse
+ } ifelse
+ } ifelse
+ {
+ dup 1 eq {
+ pop pop ci6image
+ }{
+ dup 3 eq {
+ ci6compositeimage
+ }{
+ pop pop
+ sourcearray 0 3 -1 roll put
+ /ci6separatecmykproc load
+ ci6image
+ } ifelse
+ } ifelse
+ }{
+ ci6curoverprint {
+ 7 {pop} repeat
+ }{
+ ci6knockoutimage
+ } ifelse
+ } ifelse
+ } ifelse
+} def
+/ci6proctintimage {
+ /_ptispace exch store /_ptiname exch store /_pti1 exch store /_pti0 exch store /_ptiproc exch store
+ /_pticomps _ptispace ci6numcomps store
+ /_ptiscale _pti1 _pti0 sub store
+ level2? {
+ _ptiname length 0 gt version cvr 2012 ge and {
+ [/Separation _ptiname _ptispace {_ptiproc}] setcolorspace
+ [_pti0 _pti1] ci6makeimagedict ci6image
+ }{
+ [/Indexed _ptispace 255 {255 div _ptiscale mul _pti0 add _ptiproc}] setcolorspace
+ [0 255] ci6makeimagedict ci6image
+ } ifelse
+ }{
+ _pticomps 1 eq {
+ {
+ dup
+ {
+ 255 div _ptiscale mul _pti0 add _ptiproc 255 mul cvi put
+ } ci6stringapply
+ } ci6concatprocs ci6image
+ }{
+ {
+ dup length _pticomps mul dup _ptibuf length ne {/_ptibuf exch string store}{pop} ifelse
+ _ptibuf {
+ exch _pticomps mul exch 255 div _ptiscale mul _pti0 add _ptiproc
+ _pticomps 2 add -2 roll
+ _pticomps 1 sub -1 0 {
+ 1 index add 2 index exch
+ 5 -1 roll
+ 255 mul cvi put
+ } for
+ pop pop
+ } ci6stringapply
+ } ci6concatprocs false _pticomps
+ /ci6colorimage load null eq {7 {pop} repeat}{ci6colorimage} ifelse
+ } ifelse
+ } ifelse
+} def
+/ci6graytintimage {
+ /_gtigray 5 -1 roll store
+ {1 _gtigray sub mul 1 exch sub} 4 1 roll
+ /DeviceGray ci6proctintimage
+} def
+/ci6cmyktintimage {
+ /_cticmyk 5 -1 roll store
+ {_cticmyk {1 index mul exch} forall pop} 4 1 roll
+ /DeviceCMYK ci6proctintimage
+} def
+/ci6rgbtintimage {
+ /_rtirgb 5 -1 roll store
+ {_rtirgb {1 exch sub 1 index mul 1 exch sub exch} forall pop} 4 1 roll
+ /DeviceRGB ci6proctintimage
+} def
+/ci6tintimage {
+ ci6testplate -1 eq {
+ ci6colorexpand
+ 3 -1 roll 5 -1 roll {0}{0 exch} ifelse 4 2 roll
+ dup /DeviceGray eq {
+ pop ci6graytintimage
+ }{
+ dup /DeviceRGB eq {
+ pop ci6rgbtintimage
+ }{
+ pop ci6cmyktintimage
+ } ifelse
+ } ifelse
+ }{
+ dup ci6marksplate {
+ plateindex 5 lt {
+ ci6colortocmyk plateindex get
+ dup 0 eq ci6curoverprint and {
+ 7 {pop} repeat
+ }{
+ 1 exch sub
+ exch {1 0}{0 1} ifelse () ci6graytintimage
+ } ifelse
+ }{
+ pop exch {0}{0 exch} ifelse 0 3 1 roll () ci6graytintimage
+ } ifelse
+ }{
+ ci6curoverprint {
+ 8 {pop} repeat
+ }{
+ pop pop pop
+ {pop 1} 0 1 () /DeviceGray ci6proctintimage
+ } ifelse
+ } ifelse
+ } ifelse
+} def
+/XINullImage {
+} def
+/XIImageMask {
+ XIImageWidth XIImageHeight false
+ [XIImageWidth 0 0 XIImageHeight neg 0 0]
+ /XIDataProc load
+ imagemask
+} def
+/XIImageTint {
+ XIImageWidth XIImageHeight XIBitsPerPixel
+ [XIImageWidth 0 0 XIImageHeight neg 0 0]
+ /XIDataProc load
+ XIType 3 eq XIColorValues XIColorSpace ci6tintimage
+} def
+/XIImage {
+ XIImageWidth XIImageHeight XIBitsPerPixel
+ [XIImageWidth 0 0 XIImageHeight neg 0 0]
+ /XIDataProc load
+ false XIChannelCount XIPlateList ci6drawimage
+} def
+/XG {
+ pop pop
+} def
+/XF {
+ 13 {pop} repeat
+} def
+/Xh {
+ Adobe_ColorImage_AI6_Vars begin
+ gsave
+ /XIType exch def
+ /XIImageHeight exch def
+ /XIImageWidth exch def
+ /XIImageMatrix exch def
+ 0 0 moveto
+ XIImageMatrix concat
+ XIImageWidth XIImageHeight scale
+
+ /_lp /null ddef
+ _fc
+ /_lp /imagemask ddef
+ end
+} def
+/XH {
+ Adobe_ColorImage_AI6_Vars begin
+ grestore
+ end
+} def
+/XIEnable {
+ Adobe_ColorImage_AI6_Vars /XIEnable 3 -1 roll put
+} def
+/XC {
+ Adobe_ColorImage_AI6_Vars begin
+ ci6colormake
+ /XIColorSpace exch def
+ /XIColorValues exch def
+ end
+} def
+/XIPlates {
+ Adobe_ColorImage_AI6_Vars begin
+ /XIPlateList exch def
+ end
+} def
+/XI
+{
+ Adobe_ColorImage_AI6_Vars begin
+ gsave
+ /XIType exch def
+ cvi dup
+ 256 idiv /XICompression exch store
+ 256 mod /XIEncoding exch store
+ pop pop
+ /XIChannelCount exch def
+ /XIBitsPerPixel exch def
+ /XIImageHeight exch def
+ /XIImageWidth exch def
+ pop pop pop pop
+ /XIImageMatrix exch def
+ XIBitsPerPixel 1 eq {
+ XIImageWidth 8 div ceiling cvi
+ }{
+ XIImageWidth XIChannelCount mul
+ } ifelse
+ /XIRowBytes exch def
+ XIEnable {
+ /XIBuffer3 XIImageWidth string def
+ XICompression 0 eq {
+ /XIBuffer1 XIRowBytes string def
+ XIEncoding 0 eq {
+ {currentfile XIBuffer1 readhexstring pop}
+ }{
+ {currentfile XIBuffer1 readstring pop}
+ } ifelse
+ }{
+ /XIBuffer1 256 string def
+ /XIBuffer2 XIRowBytes string def
+ {currentfile XIBuffer1 readline pop (%) anchorsearch {pop} if}
+ /ASCII85Decode filter /DCTDecode filter
+ /XIFile exch def
+ {XIFile XIBuffer2 readstring pop}
+ } ifelse
+ /XIDataProc exch def
+
+ XIType 1 ne {
+ 0 setgray
+ } if
+ XIType 1 eq {
+ XIImageMask
+ }{
+ XIType 2 eq XIType 3 eq or {
+ XIImageTint
+ }{
+ XIImage
+ } ifelse
+ } ifelse
+ }{
+ XINullImage
+ } ifelse
+ /XIPlateList false def
+ grestore
+ end
+} def
+end
+%%EndProcSet
+%%BeginResource: procset Adobe_Illustrator_AI5 1.3 0
+%%Title: (Adobe Illustrator (R) Version 8.0 Full Prolog)
+%%Version: 1.3 0
+%%CreationDate: (3/7/1994) ()
+%%Copyright: ((C) 1987-1998 Adobe Systems Incorporated All Rights Reserved)
+currentpacking true setpacking
+userdict /Adobe_Illustrator_AI5_vars 112 dict dup begin
+put
+/_?cmyk false def
+/_eo false def
+/_lp /none def
+/_pf
+{
+} def
+/_ps
+{
+} def
+/_psf
+{
+} def
+/_pss
+{
+} def
+/_pjsf
+{
+} def
+/_pjss
+{
+} def
+/_pola 0 def
+/_doClip 0 def
+/cf currentflat def
+/_lineorientation 0 def
+/_charorientation 0 def
+/_yokoorientation 0 def
+/_tm matrix def
+/_renderStart
+[
+/e0 /r0 /a0 /o0 /e1 /r1 /a1 /i0
+] def
+/_renderEnd
+[
+null null null null /i1 /i1 /i1 /i1
+] def
+/_render -1 def
+/_shift [0 0] def
+/_ax 0 def
+/_ay 0 def
+/_cx 0 def
+/_cy 0 def
+/_leading
+[
+0 0
+] def
+/_ctm matrix def
+/_mtx matrix def
+/_sp 16#020 def
+/_hyphen (-) def
+/_fontSize 0 def
+/_fontAscent 0 def
+/_fontDescent 0 def
+/_fontHeight 0 def
+/_fontRotateAdjust 0 def
+/Ss 256 string def
+Ss 0 (fonts/) putinterval
+/_cnt 0 def
+/_scale [1 1] def
+/_nativeEncoding 0 def
+/_useNativeEncoding 0 def
+/_tempEncode 0 def
+/_pntr 0 def
+/_tDict 2 dict def
+/_hfname 100 string def
+/_hffound false def
+/Tx
+{
+} def
+/Tj
+{
+} def
+/CRender
+{
+} def
+/_AI3_savepage
+{
+} def
+/_gf null def
+/_cf 4 array def
+/_rgbf 3 array def
+/_if null def
+/_of false def
+/_fc
+{
+} def
+/_gs null def
+/_cs 4 array def
+/_rgbs 3 array def
+/_is null def
+/_os false def
+/_sc
+{
+} def
+/_pd 1 dict def
+/_ed 15 dict def
+/_pm matrix def
+/_fm null def
+/_fd null def
+/_fdd null def
+/_sm null def
+/_sd null def
+/_sdd null def
+/_i null def
+/_lobyte 0 def
+/_hibyte 0 def
+/_cproc null def
+/_cscript 0 def
+/_hvax 0 def
+/_hvay 0 def
+/_hvwb 0 def
+/_hvcx 0 def
+/_hvcy 0 def
+/_bitfont null def
+/_bitlobyte 0 def
+/_bithibyte 0 def
+/_bitkey null def
+/_bitdata null def
+/_bitindex 0 def
+/discardSave null def
+/buffer 256 string def
+/beginString null def
+/endString null def
+/endStringLength null def
+/layerCnt 1 def
+/layerCount 1 def
+/perCent (%) 0 get def
+/perCentSeen? false def
+/newBuff null def
+/newBuffButFirst null def
+/newBuffLast null def
+/clipForward? false def
+end
+userdict /Adobe_Illustrator_AI5 known not {
+ userdict /Adobe_Illustrator_AI5 100 dict put
+} if
+userdict /Adobe_Illustrator_AI5 get begin
+/initialize
+{
+ Adobe_Illustrator_AI5 dup begin
+ Adobe_Illustrator_AI5_vars begin
+ /_aicmykps where {pop /_?cmyk _aicmykps def}if
+ discardDict
+ {
+ bind pop pop
+ } forall
+ dup /nc get begin
+ {
+ dup xcheck 1 index type /operatortype ne and
+ {
+ bind
+ } if
+ pop pop
+ } forall
+ end
+ newpath
+} def
+/terminate
+{
+ end
+ end
+} def
+/_
+null def
+/ddef
+{
+ Adobe_Illustrator_AI5_vars 3 1 roll put
+} def
+/xput
+{
+ dup load dup length exch maxlength eq
+ {
+ dup dup load dup
+ length 2 mul dict copy def
+ } if
+ load begin
+ def
+ end
+} def
+/npop
+{
+ {
+ pop
+ } repeat
+} def
+/hswj
+{
+ dup stringwidth 3 2 roll
+ {
+ _hvwb eq { exch _hvcx add exch _hvcy add } if
+ exch _hvax add exch _hvay add
+ } cforall
+} def
+/vswj
+{
+ 0 0 3 -1 roll
+ {
+ dup 255 le
+ _charorientation 1 eq
+ and
+ {
+ dup cstring stringwidth 5 2 roll
+ _hvwb eq { exch _hvcy sub exch _hvcx sub } if
+ exch _hvay sub exch _hvax sub
+ 4 -1 roll sub exch
+ 3 -1 roll sub exch
+ }
+ {
+ _hvwb eq { exch _hvcy sub exch _hvcx sub } if
+ exch _hvay sub exch _hvax sub
+ _fontHeight sub
+ } ifelse
+ } cforall
+} def
+/swj
+{
+ 6 1 roll
+ /_hvay exch ddef
+ /_hvax exch ddef
+ /_hvwb exch ddef
+ /_hvcy exch ddef
+ /_hvcx exch ddef
+ _lineorientation 0 eq { hswj } { vswj } ifelse
+} def
+/sw
+{
+ 0 0 0 6 3 roll swj
+} def
+/vjss
+{
+ 4 1 roll
+ {
+ dup cstring
+ dup length 1 eq
+ _charorientation 1 eq
+ and
+ {
+ -90 rotate
+ currentpoint
+ _fontRotateAdjust add
+ moveto
+ gsave
+ false charpath currentpoint
+ 5 index setmatrix stroke
+ grestore
+ _fontRotateAdjust sub
+ moveto
+ _sp eq
+ {
+ 5 index 5 index rmoveto
+ } if
+ 2 copy rmoveto
+ 90 rotate
+ }
+ {
+ currentpoint
+ _fontHeight sub
+ 5 index sub
+ 3 index _sp eq
+ {
+ 9 index sub
+ } if
+
+ currentpoint
+ exch 4 index stringwidth pop 2 div sub
+ exch _fontAscent sub
+ moveto
+
+ gsave
+ 2 index false charpath
+ 6 index setmatrix stroke
+ grestore
+
+ moveto pop pop
+ } ifelse
+ } cforall
+ 6 npop
+} def
+/hjss
+{
+ 4 1 roll
+ {
+ dup cstring
+ gsave
+ false charpath currentpoint
+ 5 index setmatrix stroke
+ grestore
+ moveto
+ _sp eq
+ {
+ 5 index 5 index rmoveto
+ } if
+ 2 copy rmoveto
+ } cforall
+ 6 npop
+} def
+/jss
+{
+ _lineorientation 0 eq { hjss } { vjss } ifelse
+} def
+/ss
+{
+ 0 0 0 7 3 roll jss
+} def
+/vjsp
+{
+ 4 1 roll
+ {
+ dup cstring
+ dup length 1 eq
+ _charorientation 1 eq
+ and
+ {
+ -90 rotate
+ currentpoint
+ _fontRotateAdjust add
+ moveto
+ false charpath
+ currentpoint
+ _fontRotateAdjust sub
+ moveto
+ _sp eq
+ {
+ 5 index 5 index rmoveto
+ } if
+ 2 copy rmoveto
+ 90 rotate
+ }
+ {
+ currentpoint
+ _fontHeight sub
+ 5 index sub
+ 3 index _sp eq
+ {
+ 9 index sub
+ } if
+
+ currentpoint
+ exch 4 index stringwidth pop 2 div sub
+ exch _fontAscent sub
+ moveto
+
+ 2 index false charpath
+
+ moveto pop pop
+ } ifelse
+ } cforall
+ 6 npop
+} def
+/hjsp
+{
+ 4 1 roll
+ {
+ dup cstring
+ false charpath
+ _sp eq
+ {
+ 5 index 5 index rmoveto
+ } if
+ 2 copy rmoveto
+ } cforall
+ 6 npop
+} def
+/jsp
+{
+ matrix currentmatrix
+ _lineorientation 0 eq {hjsp} {vjsp} ifelse
+} def
+/sp
+{
+ matrix currentmatrix
+ 0 0 0 7 3 roll
+ _lineorientation 0 eq {hjsp} {vjsp} ifelse
+} def
+/pl
+{
+ transform
+ 0.25 sub round 0.25 add exch
+ 0.25 sub round 0.25 add exch
+ itransform
+} def
+/setstrokeadjust where
+{
+ pop true setstrokeadjust
+ /c
+ {
+ curveto
+ } def
+ /C
+ /c load def
+ /v
+ {
+ currentpoint 6 2 roll curveto
+ } def
+ /V
+ /v load def
+ /y
+ {
+ 2 copy curveto
+ } def
+ /Y
+ /y load def
+ /l
+ {
+ lineto
+ } def
+ /L
+ /l load def
+ /m
+ {
+ moveto
+ } def
+}
+{
+ /c
+ {
+ pl curveto
+ } def
+ /C
+ /c load def
+ /v
+ {
+ currentpoint 6 2 roll pl curveto
+ } def
+ /V
+ /v load def
+ /y
+ {
+ pl 2 copy curveto
+ } def
+ /Y
+ /y load def
+ /l
+ {
+ pl lineto
+ } def
+ /L
+ /l load def
+ /m
+ {
+ pl moveto
+ } def
+} ifelse
+/d
+{
+ setdash
+} def
+/cf
+{
+} def
+/i
+{
+ dup 0 eq
+ {
+ pop cf
+ } if
+ setflat
+} def
+/j
+{
+ setlinejoin
+} def
+/J
+{
+ setlinecap
+} def
+/M
+{
+ setmiterlimit
+} def
+/w
+{
+ setlinewidth
+} def
+/XR
+{
+ 0 ne
+ /_eo exch ddef
+} def
+/H
+{
+} def
+/h
+{
+ closepath
+} def
+/N
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ {
+ _eo {eoclip} {clip} ifelse /_doClip 0 ddef
+ } if
+ newpath
+ }
+ {
+ /CRender
+ {
+ N
+ } ddef
+ } ifelse
+} def
+/n
+{
+ N
+} def
+/F
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ {
+ gsave _pf grestore _eo {eoclip} {clip} ifelse newpath /_lp /none ddef _fc
+ /_doClip 0 ddef
+ }
+ {
+ _pf
+ } ifelse
+ }
+ {
+ /CRender
+ {
+ F
+ } ddef
+ } ifelse
+} def
+/f
+{
+ closepath
+ F
+} def
+/S
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ {
+ gsave _ps grestore _eo {eoclip} {clip} ifelse newpath /_lp /none ddef _sc
+ /_doClip 0 ddef
+ }
+ {
+ _ps
+ } ifelse
+ }
+ {
+ /CRender
+ {
+ S
+ } ddef
+ } ifelse
+} def
+/s
+{
+ closepath
+ S
+} def
+/B
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ gsave F grestore
+ {
+ gsave S grestore _eo {eoclip} {clip} ifelse newpath /_lp /none ddef _sc
+ /_doClip 0 ddef
+ }
+ {
+ S
+ } ifelse
+ }
+ {
+ /CRender
+ {
+ B
+ } ddef
+ } ifelse
+} def
+/b
+{
+ closepath
+ B
+} def
+/W
+{
+ /_doClip 1 ddef
+} def
+/*
+{
+ count 0 ne
+ {
+ dup type /stringtype eq
+ {
+ pop
+ } if
+ } if
+ newpath
+} def
+/u
+{
+} def
+/U
+{
+} def
+/q
+{
+ _pola 0 eq
+ {
+ gsave
+ } if
+} def
+/Q
+{
+ _pola 0 eq
+ {
+ grestore
+ } if
+} def
+/*u
+{
+ _pola 1 add /_pola exch ddef
+} def
+/*U
+{
+ _pola 1 sub /_pola exch ddef
+ _pola 0 eq
+ {
+ CRender
+ } if
+} def
+/D
+{
+ pop
+} def
+/*w
+{
+} def
+/*W
+{
+} def
+/`
+{
+ /_i save ddef
+ clipForward?
+ {
+ nulldevice
+ } if
+ 6 1 roll 4 npop
+ concat pop
+ userdict begin
+ /showpage
+ {
+ } def
+ 0 setgray
+ 0 setlinecap
+ 1 setlinewidth
+ 0 setlinejoin
+ 10 setmiterlimit
+ [] 0 setdash
+ /setstrokeadjust where {pop false setstrokeadjust} if
+ newpath
+ 0 setgray
+ false setoverprint
+} def
+/~
+{
+ end
+ _i restore
+} def
+/_rgbtocmyk
+{
+ 3
+ {
+ 1 exch sub 3 1 roll
+ } repeat
+ 3 copy 1 4 1 roll
+ 3
+ {
+ 3 index 2 copy gt
+ {
+ exch
+ } if
+ pop 4 1 roll
+ } repeat
+ pop pop pop
+ 4 1 roll
+ 3
+ {
+ 3 index sub
+ 3 1 roll
+ } repeat
+ 4 -1 roll
+} def
+/setrgbfill
+{
+ _rgbf astore pop
+ /_fc
+ {
+ _lp /fill ne
+ {
+ _of setoverprint
+ _rgbf aload pop setrgbcolor
+ /_lp /fill ddef
+ } if
+ } ddef
+ /_pf
+ {
+ _fc
+ _eo {eofill} {fill} ifelse
+ } ddef
+ /_psf
+ {
+ _fc
+ hvashow
+ } ddef
+ /_pjsf
+ {
+ _fc
+ hvawidthshow
+ } ddef
+ /_lp /none ddef
+} def
+/setrgbstroke
+{
+ _rgbs astore pop
+ /_sc
+ {
+ _lp /stroke ne
+ {
+ _os setoverprint
+ _rgbs aload pop setrgbcolor
+ /_lp /stroke ddef
+ } if
+ } ddef
+ /_ps
+ {
+ _sc
+ stroke
+ } ddef
+ /_pss
+ {
+ _sc
+ ss
+ } ddef
+ /_pjss
+ {
+ _sc
+ jss
+ } ddef
+ /_lp /none ddef
+} def
+/O
+{
+ 0 ne
+ /_of exch ddef
+ /_lp /none ddef
+} def
+/R
+{
+ 0 ne
+ /_os exch ddef
+ /_lp /none ddef
+} def
+/g
+{
+ /_gf exch ddef
+ /_fc
+ {
+ _lp /fill ne
+ {
+ _of setoverprint
+ _gf setgray
+ /_lp /fill ddef
+ } if
+ } ddef
+ /_pf
+ {
+ _fc
+ _eo {eofill} {fill} ifelse
+ } ddef
+ /_psf
+ {
+ _fc
+ hvashow
+ } ddef
+ /_pjsf
+ {
+ _fc
+ hvawidthshow
+ } ddef
+ /_lp /none ddef
+} def
+/G
+{
+ /_gs exch ddef
+ /_sc
+ {
+ _lp /stroke ne
+ {
+ _os setoverprint
+ _gs setgray
+ /_lp /stroke ddef
+ } if
+ } ddef
+ /_ps
+ {
+ _sc
+ stroke
+ } ddef
+ /_pss
+ {
+ _sc
+ ss
+ } ddef
+ /_pjss
+ {
+ _sc
+ jss
+ } ddef
+ /_lp /none ddef
+} def
+/k
+{
+ _cf astore pop
+ /_fc
+ {
+ _lp /fill ne
+ {
+ _of setoverprint
+ _cf aload pop setcmykcolor
+ /_lp /fill ddef
+ } if
+ } ddef
+ /_pf
+ {
+ _fc
+ _eo {eofill} {fill} ifelse
+ } ddef
+ /_psf
+ {
+ _fc
+ hvashow
+ } ddef
+ /_pjsf
+ {
+ _fc
+ hvawidthshow
+ } ddef
+ /_lp /none ddef
+} def
+/K
+{
+ _cs astore pop
+ /_sc
+ {
+ _lp /stroke ne
+ {
+ _os setoverprint
+ _cs aload pop setcmykcolor
+ /_lp /stroke ddef
+ } if
+ } ddef
+ /_ps
+ {
+ _sc
+ stroke
+ } ddef
+ /_pss
+ {
+ _sc
+ ss
+ } ddef
+ /_pjss
+ {
+ _sc
+ jss
+ } ddef
+ /_lp /none ddef
+} def
+/Xa
+{
+ _?cmyk {
+ 3 npop k
+ }{
+ setrgbfill 4 npop
+ } ifelse
+} def
+/XA
+{
+ _?cmyk {
+ 3 npop K
+ }{
+ setrgbstroke 4 npop
+ } ifelse
+} def
+/Xs
+{
+ /_gf exch ddef
+ 5 npop
+ /_fc
+ {
+ _lp /fill ne
+ {
+ _of setoverprint
+ _gf setAIseparationgray
+ /_lp /fill ddef
+ } if
+ } ddef
+ /_pf
+ {
+ _fc
+ _eo {eofill} {fill} ifelse
+ } ddef
+ /_psf
+ {
+ _fc
+ hvashow
+ } ddef
+ /_pjsf
+ {
+ _fc
+ hvawidthshow
+ } ddef
+ /_lp /none ddef
+} def
+/XS
+{
+ /_gs exch ddef
+ 5 npop
+ /_sc
+ {
+ _lp /stroke ne
+ {
+ _os setoverprint
+ _gs setAIseparationgray
+ /_lp /stroke ddef
+ } if
+ } ddef
+ /_ps
+ {
+ _sc
+ stroke
+ } ddef
+ /_pss
+ {
+ _sc
+ ss
+ } ddef
+ /_pjss
+ {
+ _sc
+ jss
+ } ddef
+ /_lp /none ddef
+} def
+/Xx
+{
+ exch
+ /_gf exch ddef
+ 0 eq {
+ findcmykcustomcolor
+ }{
+ _?cmyk {true}{/findrgbcustomcolor where{pop false}{true}ifelse}ifelse
+ {
+ 4 1 roll 3 npop
+ findcmykcustomcolor
+ }{
+ 8 -4 roll 4 npop
+ findrgbcustomcolor
+ } ifelse
+ } ifelse
+ /_if exch ddef
+ /_fc
+ {
+ _lp /fill ne
+ {
+ _of setoverprint
+ _if _gf 1 exch sub setcustomcolor
+ /_lp /fill ddef
+ } if
+ } ddef
+ /_pf
+ {
+ _fc
+ _eo {eofill} {fill} ifelse
+ } ddef
+ /_psf
+ {
+ _fc
+ hvashow
+ } ddef
+ /_pjsf
+ {
+ _fc
+ hvawidthshow
+ } ddef
+ /_lp /none ddef
+} def
+/XX
+{
+ exch
+ /_gs exch ddef
+ 0 eq {
+ findcmykcustomcolor
+ }{
+ _?cmyk {true}{/findrgbcustomcolor where{pop false}{true}ifelse}ifelse
+ {
+ 4 1 roll 3 npop
+ findcmykcustomcolor
+ }{
+ 8 -4 roll 4 npop
+ findrgbcustomcolor
+ } ifelse
+ } ifelse
+ /_is exch ddef
+ /_sc
+ {
+ _lp /stroke ne
+ {
+ _os setoverprint
+ _is _gs 1 exch sub setcustomcolor
+ /_lp /stroke ddef
+ } if
+ } ddef
+ /_ps
+ {
+ _sc
+ stroke
+ } ddef
+ /_pss
+ {
+ _sc
+ ss
+ } ddef
+ /_pjss
+ {
+ _sc
+ jss
+ } ddef
+ /_lp /none ddef
+} def
+/x
+{
+ /_gf exch ddef
+ findcmykcustomcolor
+ /_if exch ddef
+ /_fc
+ {
+ _lp /fill ne
+ {
+ _of setoverprint
+ _if _gf 1 exch sub setcustomcolor
+ /_lp /fill ddef
+ } if
+ } ddef
+ /_pf
+ {
+ _fc
+ _eo {eofill} {fill} ifelse
+ } ddef
+ /_psf
+ {
+ _fc
+ hvashow
+ } ddef
+ /_pjsf
+ {
+ _fc
+ hvawidthshow
+ } ddef
+ /_lp /none ddef
+} def
+/X
+{
+ /_gs exch ddef
+ findcmykcustomcolor
+ /_is exch ddef
+ /_sc
+ {
+ _lp /stroke ne
+ {
+ _os setoverprint
+ _is _gs 1 exch sub setcustomcolor
+ /_lp /stroke ddef
+ } if
+ } ddef
+ /_ps
+ {
+ _sc
+ stroke
+ } ddef
+ /_pss
+ {
+ _sc
+ ss
+ } ddef
+ /_pjss
+ {
+ _sc
+ jss
+ } ddef
+ /_lp /none ddef
+} def
+/XK
+{
+ 3 -1 roll pop
+ 0 eq
+ {
+ 1 exch sub
+ 3 {dup 3 1 roll mul 5 1 roll} repeat
+ mul 4 1 roll
+ K
+ }
+ {
+ 1 exch sub 4 1 roll
+ 3 {1 exch sub 3 index mul 1 exch sub 3 1 roll} repeat
+ 4 -1 roll pop
+ XA
+ } ifelse
+} def
+/Xk
+{
+ 3 -1 roll pop
+ 0 eq
+ {
+ 1 exch sub
+ 3 {dup 3 1 roll mul 5 1 roll} repeat
+ mul 4 1 roll
+ k
+ }
+ {
+ 1 exch sub 4 1 roll
+ 3 {1 exch sub 3 index mul 1 exch sub 3 1 roll} repeat
+ 4 -1 roll pop
+ Xa
+ } ifelse
+} def
+/A
+{
+ pop
+} def
+/annotatepage
+{
+userdict /annotatepage 2 copy known {get exec} {pop pop} ifelse
+} def
+/XT {
+ pop pop
+} def
+/Xt {
+ pop
+} def
+/discard
+{
+ save /discardSave exch store
+ discardDict begin
+ /endString exch store
+ gt38?
+ {
+ 2 add
+ } if
+ load
+ stopped
+ pop
+ end
+ discardSave restore
+} bind def
+userdict /discardDict 7 dict dup begin
+put
+/pre38Initialize
+{
+ /endStringLength endString length store
+ /newBuff buffer 0 endStringLength getinterval store
+ /newBuffButFirst newBuff 1 endStringLength 1 sub getinterval store
+ /newBuffLast newBuff endStringLength 1 sub 1 getinterval store
+} def
+/shiftBuffer
+{
+ newBuff 0 newBuffButFirst putinterval
+ newBuffLast 0
+ currentfile read not
+ {
+ stop
+ } if
+ put
+} def
+0
+{
+ pre38Initialize
+ mark
+ currentfile newBuff readstring exch pop
+ {
+ {
+ newBuff endString eq
+ {
+ cleartomark stop
+ } if
+ shiftBuffer
+ } loop
+ }
+ {
+ stop
+ } ifelse
+} def
+1
+{
+ pre38Initialize
+ /beginString exch store
+ mark
+ currentfile newBuff readstring exch pop
+ {
+ {
+ newBuff beginString eq
+ {
+ /layerCount dup load 1 add store
+ }
+ {
+ newBuff endString eq
+ {
+ /layerCount dup load 1 sub store
+ layerCount 0 eq
+ {
+ cleartomark stop
+ } if
+ } if
+ } ifelse
+ shiftBuffer
+ } loop
+ } if
+} def
+2
+{
+ mark
+ {
+ currentfile buffer {readline} stopped {
+ % assume error was due to overfilling the buffer
+ }{
+ not
+ {
+ stop
+ } if
+ endString eq {
+ cleartomark stop
+ } if
+ }ifelse
+ } loop
+} def
+3
+{
+ /beginString exch store
+ /layerCnt 1 store
+ mark
+ {
+ currentfile buffer {readline} stopped {
+ % assume error was due to overfilling the buffer
+ }{
+ not
+ {
+ stop
+ } if
+ dup beginString eq
+ {
+ pop /layerCnt dup load 1 add store
+ }
+ {
+ endString eq
+ {
+ layerCnt 1 eq
+ {
+ cleartomark stop
+ }
+ {
+ /layerCnt dup load 1 sub store
+ } ifelse
+ } if
+ } ifelse
+ }ifelse
+ } loop
+} def
+end
+userdict /clipRenderOff 15 dict dup begin
+put
+{
+ /n /N /s /S /f /F /b /B
+}
+{
+ {
+ _doClip 1 eq
+ {
+ /_doClip 0 ddef _eo {eoclip} {clip} ifelse
+ } if
+ newpath
+ } def
+} forall
+/Tr /pop load def
+/Bb {} def
+/BB /pop load def
+/Bg {12 npop} def
+/Bm {6 npop} def
+/Bc /Bm load def
+/Bh {4 npop} def
+end
+/Lb
+{
+ 6 npop
+ 7 2 roll
+ 5 npop
+ 0 eq
+ {
+ 0 eq
+ {
+ (%AI5_BeginLayer) 1 (%AI5_EndLayer--) discard
+ }
+ {
+
+ /clipForward? true def
+
+ /Tx /pop load def
+ /Tj /pop load def
+
+ currentdict end clipRenderOff begin begin
+ } ifelse
+ }
+ {
+ 0 eq
+ {
+ save /discardSave exch store
+ } if
+ } ifelse
+} bind def
+/LB
+{
+ discardSave dup null ne
+ {
+ restore
+ }
+ {
+ pop
+ clipForward?
+ {
+ currentdict
+ end
+ end
+ begin
+
+ /clipForward? false ddef
+ } if
+ } ifelse
+} bind def
+/Pb
+{
+ pop pop
+ 0 (%AI5_EndPalette) discard
+} bind def
+/Np
+{
+ 0 (%AI5_End_NonPrinting--) discard
+} bind def
+/Ln /pop load def
+/Ap
+/pop load def
+/Ar
+{
+ 72 exch div
+ 0 dtransform dup mul exch dup mul add sqrt
+ dup 1 lt
+ {
+ pop 1
+ } if
+ setflat
+} def
+/Mb
+{
+ q
+} def
+/Md
+{
+} def
+/MB
+{
+ Q
+} def
+/nc 4 dict def
+nc begin
+/setgray
+{
+ pop
+} bind def
+/setcmykcolor
+{
+ 4 npop
+} bind def
+/setrgbcolor
+{
+ 3 npop
+} bind def
+/setcustomcolor
+{
+ 2 npop
+} bind def
+currentdict readonly pop
+end
+/XP
+{
+ 4 npop
+} bind def
+/XD
+{
+ pop
+} bind def
+end
+setpacking
+%%EndResource
+%%BeginResource: procset Adobe_cshow 2.0 8
+%%Title: (Writing System Operators)
+%%Version: 2.0 8
+%%CreationDate: (1/23/89) ()
+%%Copyright: ((C) 1992-1996 Adobe Systems Incorporated All Rights Reserved)
+currentpacking true setpacking
+userdict /Adobe_cshow 14 dict dup begin put
+/initialize
+{
+ Adobe_cshow begin
+ Adobe_cshow
+ {
+ dup xcheck
+ {
+ bind
+ } if
+ pop pop
+ } forall
+ end
+ Adobe_cshow begin
+} def
+/terminate
+{
+currentdict Adobe_cshow eq
+ {
+ end
+ } if
+} def
+/cforall
+{
+ /_lobyte 0 ddef
+ /_hibyte 0 ddef
+ /_cproc exch ddef
+ /_cscript currentfont /FontScript known { currentfont /FontScript get } { -1 } ifelse ddef
+ {
+ /_lobyte exch ddef
+ _hibyte 0 eq
+ _cscript 1 eq
+ _lobyte 129 ge _lobyte 159 le and
+ _lobyte 224 ge _lobyte 252 le and or and
+ _cscript 2 eq
+ _lobyte 161 ge _lobyte 254 le and and
+ _cscript 3 eq
+ _lobyte 161 ge _lobyte 254 le and and
+ _cscript 25 eq
+ _lobyte 161 ge _lobyte 254 le and and
+ _cscript -1 eq
+ or or or or and
+ {
+ /_hibyte _lobyte ddef
+ }
+ {
+ _hibyte 256 mul _lobyte add
+ _cproc
+ /_hibyte 0 ddef
+ } ifelse
+ } forall
+} def
+/cstring
+{
+ dup 256 lt
+ {
+ (s) dup 0 4 3 roll put
+ }
+ {
+ dup 256 idiv exch 256 mod
+ (hl) dup dup 0 6 5 roll put 1 4 3 roll put
+ } ifelse
+} def
+/clength
+{
+ 0 exch
+ { 256 lt { 1 } { 2 } ifelse add } cforall
+} def
+/hawidthshow
+{
+ {
+ dup cstring
+ show
+ _hvax _hvay rmoveto
+ _hvwb eq { _hvcx _hvcy rmoveto } if
+ } cforall
+} def
+/vawidthshow
+{
+ {
+ dup 255 le
+ _charorientation 1 eq
+ and
+ {
+ -90 rotate
+ 0 _fontRotateAdjust rmoveto
+ cstring
+ _hvcx _hvcy _hvwb _hvax _hvay 6 -1 roll awidthshow
+ 0 _fontRotateAdjust neg rmoveto
+ 90 rotate
+ }
+ {
+ currentpoint
+ _fontHeight sub
+ exch _hvay sub exch _hvax sub
+ 2 index _hvwb eq { exch _hvcy sub exch _hvcx sub } if
+ 3 2 roll
+ cstring
+ dup stringwidth pop 2 div neg _fontAscent neg rmoveto
+ show
+ moveto
+ } ifelse
+ } cforall
+} def
+/hvawidthshow
+{
+ 6 1 roll
+ /_hvay exch ddef
+ /_hvax exch ddef
+ /_hvwb exch ddef
+ /_hvcy exch ddef
+ /_hvcx exch ddef
+ _lineorientation 0 eq { hawidthshow } { vawidthshow } ifelse
+} def
+/hvwidthshow
+{
+ 0 0 3 -1 roll hvawidthshow
+} def
+/hvashow
+{
+ 0 0 0 6 -3 roll hvawidthshow
+} def
+/hvshow
+{
+ 0 0 0 0 0 6 -1 roll hvawidthshow
+} def
+currentdict readonly pop end
+setpacking
+%%EndResource
+%%BeginResource: procset Adobe_shading_AI8 1.0 0
+%%Title: (Adobe Illustrator 8 Shading Procset)
+%%Version: 1.0 0
+%%CreationDate: (12/17/97) ()
+%%Copyright: ((C) 1987-1997 Adobe Systems Incorporated All Rights Reserved)
+userdict /defaultpacking currentpacking put true setpacking
+userdict /Adobe_shading_AI8 10 dict dup begin put
+/initialize {
+ Adobe_shading_AI8 begin
+ Adobe_shading_AI8 bdprocs
+ Mesh /initialize get exec
+} def
+/terminate {
+ currentdict Adobe_shading_AI8 eq {
+ end
+ } if
+} def
+/bdprocs {
+ {
+ dup xcheck 1 index type /arraytype eq and {
+ bind
+ } if
+ pop pop
+ } forall
+} def
+/X! {pop} def
+/X# {pop pop} def
+/Mesh 40 dict def
+Mesh begin
+/initialize {
+ Mesh bdprocs
+ Mesh begin
+ /emulate? /AI8MeshEmulation where {
+ pop AI8MeshEmulation
+ }{
+ systemdict /shfill known not
+ } ifelse def
+ end
+} def
+/bd {
+ shadingdict begin
+} def
+/paint {
+ emulate? {
+ end
+ }{
+ /_lp /none ddef _fc /_lp /none ddef
+
+ /AIColorSpace AIColorSpace tocolorspace store
+ /ColorSpace AIColorSpace topsspace store
+
+ version_ge_3010.106 not systemdict /setsmoothness known and {
+ 0.0001 setsmoothness
+ } if
+
+ composite? {
+ /DataSource getdatasrc def
+ Matrix concat
+ currentdict end
+ shfill
+ }{
+ AIColorSpace makesmarks AIPlateList markingplate and not isoverprint and {
+ end
+ }{
+ /ColorSpace /DeviceGray store
+ /Decode [0 1 0 1 0 1] store
+ /DataSource getplatesrc def
+ Matrix concat
+ currentdict end
+ shfill
+ } ifelse
+ } ifelse
+ } ifelse
+} def
+/shadingdict 12 dict def
+shadingdict begin
+ /ShadingType 6 def
+ /BitsPerCoordinate 16 def
+ /BitsPerComponent 8 def
+ /BitsPerFlag 8 def
+end
+/datafile null def
+/databuf 256 string def
+/dataptr 0 def
+/srcspace null def
+/srcchannels 0 def
+/dstchannels 0 def
+/dstplate 0 def
+/srctodstcolor null def
+/getplatesrc {
+ /srcspace AIColorSpace store
+ /srcchannels AIColorSpace getnchannels store
+ /dstchannels 1 store
+ /dstplate getplateindex store
+ /srctodstcolor srcspace makesmarks {
+ dstplate 4 eq {
+ {1 exch sub}
+ }{
+ {srcspace tocmyk 3 dstplate sub index 1 exch sub 5 1 roll 4 {pop} repeat}
+ } ifelse
+ }{
+ {srcchannels {pop} repeat 1}
+ } ifelse store
+ /datafile getdatasrc store
+ /rdpatch168 load DataLength () /SubFileDecode filter
+} def
+/getdatasrc {
+ /rdcmntline load /ASCII85Decode filter
+} def
+/rdpatch168 {
+ /dataptr 0 store
+ 49 rdcount
+ 4 {
+ dup {pop srcchannels getint8} if
+ dup {pop srctodstcolor dstchannels putint8 true} if
+ } repeat
+ {databuf 0 dataptr getinterval}{()} ifelse
+} def
+/rdpatch3216 {
+ /dataptr 0 store
+ 97 rdcount
+ 4 {
+ dup {pop srcchannels getint16} if
+ dup {pop srctodstcolor dstchannels putint16 true} if
+ } repeat
+ {databuf 0 dataptr getinterval}{()} ifelse
+} def
+/rdcount {
+ dup 0 gt {
+ datafile databuf dataptr 4 -1 roll getinterval readstring
+ exch length dataptr add /dataptr exch store
+ }{
+ true
+ } ifelse
+} def
+/getint8 {
+ mark true 3 -1 roll
+ {
+ dup {pop datafile read} if
+ dup {pop 255 div true} if
+ } repeat
+ {
+ counttomark 1 add -1 roll pop true
+ }{
+ cleartomark false
+ } ifelse
+} def
+/putint8 {
+ dup dataptr add /dataptr exch store
+ dataptr exch
+ {
+ 1 sub exch
+ 255 mul cvi
+ databuf 2 index
+ 3 -1 roll put
+ } repeat
+ pop
+} def
+/getint16 {
+ mark true 3 -1 roll
+ {
+ dup {pop datafile read} if
+ dup {pop 256 mul datafile read} if
+ dup {pop add 65535 div true} if
+ } repeat
+ {
+ counttomark 1 add -1 roll pop true
+ }{
+ cleartomark false
+ } ifelse
+} def
+/putint16 {
+ dup 2 mul dataptr add /dataptr exch store
+ dataptr exch
+ {
+ 2 sub exch
+ 65535 mul cvi dup
+ 256 idiv databuf 3 index 3 -1 roll put
+ 256 mod databuf 2 index 1 add 3 -1 roll put
+ } repeat
+ pop
+} def
+/srcbuf 256 string def
+/rdcmntline {
+ currentfile srcbuf readline pop
+ (%) anchorsearch {pop} if
+} def
+/getplateindex {
+ 0 [cyan? magenta? yellow? black? customColor?] {{exit} if 1 add} forall
+} def
+/aicsarray 4 array def
+/aicsaltvals 4 array def
+/aicsaltcolr aicsaltvals def
+/tocolorspace {
+ dup type /arraytype eq {
+ mark exch aload pop
+ aicsarray 0 3 -1 roll put
+ aicsarray 1 3 -1 roll put
+ dup aicsarray 2 3 -1 roll put
+ gettintxform aicsarray 3 3 -1 roll put
+ counttomark aicsaltvals 0 3 -1 roll getinterval /aicsaltcolr exch store
+ aicsaltcolr astore pop pop
+ aicsarray
+ } if
+} def
+/subtintxform {aicsaltcolr {1 index mul exch} forall pop} def
+/addtintxform {aicsaltcolr {1 sub 1 index mul 1 add exch} forall pop} def
+/gettintxform {
+ /DeviceRGB eq {/addtintxform}{/subtintxform} ifelse load
+} def
+/getnchannels {
+ dup type /arraytype eq {0 get} if
+ colorspacedict exch get begin Channels end
+} def
+/makesmarks {
+ composite? {
+ pop true
+ }{
+ dup dup type /arraytype eq {0 get} if
+ colorspacedict exch get begin MarksPlate end
+ } ifelse
+} def
+/markingplate {
+ composite? {
+ pop true
+ }{
+ dup type /arraytype eq {
+ dup length getplateindex gt {getplateindex get}{pop false} ifelse
+ } if
+ } ifelse
+} def
+/tocmyk {
+ dup dup type /arraytype eq {0 get} if
+ colorspacedict exch get begin ToCMYK end
+} def
+/topsspace {
+ dup dup type /arraytype eq {0 get} if
+ colorspacedict exch get begin ToPSSpace end
+} def
+/colorspacedict 5 dict dup begin
+ /DeviceGray 4 dict dup begin
+ /Channels 1 def
+ /MarksPlate {pop black?} def
+ /ToCMYK {pop 1 exch sub 0 0 0 4 -1 roll} def
+ /ToPSSpace {} def
+ end def
+ /DeviceRGB 4 dict dup begin
+ /Channels 3 def
+ /MarksPlate {pop isCMYKSep?} def
+ /ToCMYK {pop _rgbtocmyk} def
+ /ToPSSpace {} def
+ end def
+ /DeviceCMYK 4 dict dup begin
+ /Channels 4 def
+ /MarksPlate {pop isCMYKSep?} def
+ /ToCMYK {pop} def
+ /ToPSSpace {} def
+ end def
+ /Separation 4 dict dup begin
+ /Channels 1 def
+ /MarksPlate {
+ /findcmykcustomcolor where {
+ pop dup 1 exch ToCMYK 5 -1 roll 1 get
+ findcmykcustomcolor 1 setcustomcolor
+ systemdict /currentgray get exec
+ 1 ne
+ }{
+ pop false
+ } ifelse
+ } def
+ /ToCMYK {
+ dup 2 get mark exch 4 2 roll
+ 3 get exec
+ counttomark -1 roll tocmyk
+ 5 -1 roll pop
+ } def
+ /ToPSSpace {} def
+ end def
+ /Process 4 dict dup begin
+ /Channels 1 def
+ /MarksPlate {
+ isCMYKSep? {
+ 1 exch ToCMYK 4 array astore getplateindex get 0 ne
+ }{
+ pop false
+ } ifelse
+ } def
+ /ToCMYK {
+ dup 2 get mark exch 4 2 roll
+ 3 get exec
+ counttomark -1 roll tocmyk
+ 5 -1 roll pop
+ } def
+ /ToPSSpace {
+ 4 array copy dup 0 /Separation put
+ } def
+ end def
+end def
+/isoverprint {
+ /currentoverprint where {pop currentoverprint}{_of} ifelse
+} def
+/version_ge_3010.106 {
+ version {cvr} stopped {
+ pop
+ false
+ }{
+ 3010.106 ge
+ } ifelse
+} def
+end
+end
+defaultpacking setpacking
+%%EndResource
+%%EndProlog
+%%BeginSetup
+userdict /_useSmoothShade false put
+userdict /_aicmykps true put
+userdict /_forceToCMYK true put
+Adobe_level2_AI5 /initialize get exec
+Adobe_cshow /initialize get exec
+Adobe_Illustrator_AI5_vars Adobe_Illustrator_AI5 Adobe_typography_AI5 /initialize get exec
+Adobe_ColorImage_AI6 /initialize get exec
+Adobe_shading_AI8 /initialize get exec
+Adobe_Illustrator_AI5 /initialize get exec
+%AI3_BeginRider
+currentpacking true setpacking
+%%BeginFont: Device
+%!PS-AdobeFont-1.0: Device 001.000
+%%CreationDate: 3/28/94 at 10:55:02 PM
+%%VMusage: 1024 52339
+% Generated by Fontographer 4.0.2
+% ©1994 InFonts. 619-234-9400. Created by Gary Hustwit
+% ADL: 800 200 0
+%%EndComments
+FontDirectory/Device known{/Device findfont dup/UniqueID known{dup
+/UniqueID get 4115447 eq exch/FontType get 1 eq and}{pop false}ifelse
+{save true}{false}ifelse}{false}ifelse
+20 dict begin
+/FontInfo 16 dict dup begin
+ /version (001.000) readonly def
+ /FullName (Device) readonly def
+ /FamilyName (Device) readonly def
+ /Weight (Medium) readonly def
+ /ItalicAngle 0 def
+ /isFixedPitch false def
+ /UnderlinePosition -133 def
+ /UnderlineThickness 20 def
+ /Notice (©1994 InFonts. 619-234-9400. Created by Gary Hustwit) readonly def
+ /em 1000 def
+ /ascent 800 def
+ /descent 200 def
+end readonly def
+/FontName /Device def
+/Encoding 256 array
+dup 0/NUL put
+dup 1/Eth put
+dup 2/eth put
+dup 3/Lslash put
+dup 4/lslash put
+dup 5/Scaron put
+dup 6/scaron put
+dup 7/Yacute put
+dup 8/yacute put
+dup 9/HT put
+dup 10/LF put
+dup 11/Thorn put
+dup 12/thorn put
+dup 13/CR put
+dup 14/Zcaron put
+dup 15/zcaron put
+dup 16/DLE put
+dup 17/DC1 put
+dup 18/DC2 put
+dup 19/DC3 put
+dup 20/DC4 put
+dup 21/onehalf put
+dup 22/onequarter put
+dup 23/onesuperior put
+dup 24/threequarters put
+dup 25/threesuperior put
+dup 26/twosuperior put
+dup 27/brokenbar put
+dup 28/minus put
+dup 29/multiply put
+dup 30/RS put
+dup 31/US put
+dup 32/space put
+dup 33/exclam put
+dup 34/quotedbl put
+dup 35/numbersign put
+dup 36/dollar put
+dup 37/percent put
+dup 38/ampersand put
+dup 39/quotesingle put
+dup 40/parenleft put
+dup 41/parenright put
+dup 42/asterisk put
+dup 43/plus put
+dup 44/comma put
+dup 45/hyphen put
+dup 46/period put
+dup 47/slash put
+dup 48/zero put
+dup 49/one put
+dup 50/two put
+dup 51/three put
+dup 52/four put
+dup 53/five put
+dup 54/six put
+dup 55/seven put
+dup 56/eight put
+dup 57/nine put
+dup 58/colon put
+dup 59/semicolon put
+dup 60/less put
+dup 61/equal put
+dup 62/greater put
+dup 63/question put
+dup 64/at put
+dup 65/A put
+dup 66/B put
+dup 67/C put
+dup 68/D put
+dup 69/E put
+dup 70/F put
+dup 71/G put
+dup 72/H put
+dup 73/I put
+dup 74/J put
+dup 75/K put
+dup 76/L put
+dup 77/M put
+dup 78/N put
+dup 79/O put
+dup 80/P put
+dup 81/Q put
+dup 82/R put
+dup 83/S put
+dup 84/T put
+dup 85/U put
+dup 86/V put
+dup 87/W put
+dup 88/X put
+dup 89/Y put
+dup 90/Z put
+dup 91/bracketleft put
+dup 92/backslash put
+dup 93/bracketright put
+dup 94/asciicircum put
+dup 95/underscore put
+dup 96/grave put
+dup 97/a put
+dup 98/b put
+dup 99/c put
+dup 100/d put
+dup 101/e put
+dup 102/f put
+dup 103/g put
+dup 104/h put
+dup 105/i put
+dup 106/j put
+dup 107/k put
+dup 108/l put
+dup 109/m put
+dup 110/n put
+dup 111/o put
+dup 112/p put
+dup 113/q put
+dup 114/r put
+dup 115/s put
+dup 116/t put
+dup 117/u put
+dup 118/v put
+dup 119/w put
+dup 120/x put
+dup 121/y put
+dup 122/z put
+dup 123/braceleft put
+dup 124/bar put
+dup 125/braceright put
+dup 126/asciitilde put
+dup 127/DEL put
+dup 128/Adieresis put
+dup 129/Aring put
+dup 130/Ccedilla put
+dup 131/Eacute put
+dup 132/Ntilde put
+dup 133/Odieresis put
+dup 134/Udieresis put
+dup 135/aacute put
+dup 136/agrave put
+dup 137/acircumflex put
+dup 138/adieresis put
+dup 139/atilde put
+dup 140/aring put
+dup 141/ccedilla put
+dup 142/eacute put
+dup 143/egrave put
+dup 144/ecircumflex put
+dup 145/edieresis put
+dup 146/iacute put
+dup 147/igrave put
+dup 148/icircumflex put
+dup 149/idieresis put
+dup 150/ntilde put
+dup 151/oacute put
+dup 152/ograve put
+dup 153/ocircumflex put
+dup 154/odieresis put
+dup 155/otilde put
+dup 156/uacute put
+dup 157/ugrave put
+dup 158/ucircumflex put
+dup 159/udieresis put
+dup 160/dagger put
+dup 161/degree put
+dup 162/cent put
+dup 163/sterling put
+dup 164/section put
+dup 165/bullet put
+dup 166/paragraph put
+dup 167/germandbls put
+dup 168/registered put
+dup 169/copyright put
+dup 170/trademark put
+dup 171/acute put
+dup 172/dieresis put
+dup 173/notequal put
+dup 174/AE put
+dup 175/Oslash put
+dup 176/infinity put
+dup 177/plusminus put
+dup 178/lessequal put
+dup 179/greaterequal put
+dup 180/yen put
+dup 181/mu put
+dup 182/partialdiff put
+dup 183/summation put
+dup 184/product put
+dup 185/pi put
+dup 186/integral put
+dup 187/ordfeminine put
+dup 188/ordmasculine put
+dup 189/Omega put
+dup 190/ae put
+dup 191/oslash put
+dup 192/questiondown put
+dup 193/exclamdown put
+dup 194/logicalnot put
+dup 195/radical put
+dup 196/florin put
+dup 197/approxequal put
+dup 198/Delta put
+dup 199/guillemotleft put
+dup 200/guillemotright put
+dup 201/ellipsis put
+dup 202/nbspace put
+dup 203/Agrave put
+dup 204/Atilde put
+dup 205/Otilde put
+dup 206/OE put
+dup 207/oe put
+dup 208/endash put
+dup 209/emdash put
+dup 210/quotedblleft put
+dup 211/quotedblright put
+dup 212/quoteleft put
+dup 213/quoteright put
+dup 214/divide put
+dup 215/lozenge put
+dup 216/ydieresis put
+dup 217/Ydieresis put
+dup 218/fraction put
+dup 219/currency put
+dup 220/guilsinglleft put
+dup 221/guilsinglright put
+dup 222/fi put
+dup 223/fl put
+dup 224/daggerdbl put
+dup 225/periodcentered put
+dup 226/quotesinglbase put
+dup 227/quotedblbase put
+dup 228/perthousand put
+dup 229/Acircumflex put
+dup 230/Ecircumflex put
+dup 231/Aacute put
+dup 232/Edieresis put
+dup 233/Egrave put
+dup 234/Iacute put
+dup 235/Icircumflex put
+dup 236/Idieresis put
+dup 237/Igrave put
+dup 238/Oacute put
+dup 239/Ocircumflex put
+dup 240/apple put
+dup 241/Ograve put
+dup 242/Uacute put
+dup 243/Ucircumflex put
+dup 244/Ugrave put
+dup 245/dotlessi put
+dup 246/circumflex put
+dup 247/tilde put
+dup 248/macron put
+dup 249/breve put
+dup 250/dotaccent put
+dup 251/ring put
+dup 252/cedilla put
+dup 253/hungarumlaut put
+dup 254/ogonek put
+dup 255/caron put
+ readonly
+ def
+/PaintType 0 def
+/FontType 1 def
+/StrokeWidth 0 def
+/FontMatrix[0.001 0 0 0.001 0 0]readonly def
+/UniqueID 4115447 def
+/FontBBox{12 -148 648 974}readonly def
+currentdict end
+currentfile eexec
+d8061d93a824652cab7761a8dac65b57ec3fe6381b068e57a586b08ef37fe40b49b7d7633b8ad558cfeda279bfa8db2693a95b593a4473e0e0f38e654ad86ce1231549719ea44878ff49585a89f37ddb79b56f99b7d19a6f1acf5bae20ca0c10d8ed181b136c268f5815bb0b476c700d50e8d29a6c215ecd2f8dc20a8607af
+2d7ea45a72aa45d6134609a1958b1c5eb3371c235e02c89fc6c20f6d9d89e7de177924fa6330368f5fe19f98a087d7eca80136d901279d0a430b7318a2c7cd321fae1e0a6d7b61e387f08c3ef3c1af63d5b419648455e43086bc0f48779a66c5282b6305c0ba8613d66f3fb7dcbf4f6993d06a8341171e0b6716dec273b955
+3282dbdf7725e2adbfeecc4cb50c0bc17354017a7ed420764d36644dc641e5ad23b874d1afce9e0d21c8a51de06eb32f7596def184be868771c0b9c40f9f473a95b361a8f9440635cbfbdc756e9ab670bb141d723e2d00b774782034fc49c519e7c63b4e3c831b0b3c7940a6b493ed4d7b2f633f0e953d09d843ba3fd0a6c4
+1820e5ca93a99ded985442f057bf442caf1ffbdbbf70cf5788351bd1445566488a9beb9419fa93b418dfbee8ca9752a50f79165b62281a7a17ed89c099d068ba53d667d632f5cebcd874b18d88b90f0254fc7f8567a15a50b4a183b123a054cebc9ea1a7ce89bd58774ff507d6eb0e11a447f7527679ff9665257d5f9a7518
+be658907cdad9d68c196bc411b35395d66cc9ef105609942dca7a1833b182aa820c6490eba6c87a1acc52a7391465235c249598578cdfdd7bf1219c8ea8496efec282c08b54127cb1675aced783aca8f6e2520857d1692c18f6a60881693c0e3811089aff3e70ab7e72de2b1f4ad0e3a664dfd0858970ddbeba4e8ab877322
+26616c2f7dabd2421d5efcd3666728fc69fcaebf926af2c3174aab7bdec6e0d8431449eb938d33b68992e6c36984e05fd2d74e837708b42d4899c0614df95303b2b33e22a3b0dc6883d6516e6804b2d5ba6ce94db57ee254b840490b82ee2a847fbc1e2957d3ffa335f026167c05562a79c4ca7467990ab22f816c47061417
+cf969ca6f300a72c7d2e3aacc12dba2477170a4999e8624d924717f9cd83dab168eab77a1b41631f986be5587beee9ffa5c9ea5cac6cc6d3429d57a10149fe4d81a8a5a27e68f193765cc7c1db653647271ceb9ee3ab6be87989888457ce0861f3ecfb57abb2b33776cc54ca83c846ddfcb0d31065224b0735a85536e334ba
+7cfe1f29ec0a17c3c0120bb269f115213d4e2cc9bba6a6188dcb51efe797904b6953943b7c823c9966437973cf0da10d500db5b19f492119b5f8dc1efb27c38666a1982ab013ca68654b6de603f315ba15c9056260935613fc97312d41a8f6c36e31e3df887a73065d555cb3fb914d03b0f6e0fa179e1330bddcf8461c400e
+ec3c58c0279ab5226cc73f3376db7ff98d3aac32808b595120873be783c9a56690a01dff3b5cf183490cb8200318bffac052eef361834649ea9430efefbd981dbb5aa7052f67fb96399fab7070195a8a85989b4565d136fc4ee2f5060a6d48823041f44bb3e27415f81538b2dfa16afcce8ad23e885d4bead26c16fbe97f14
+40cc98ab1a5af166133fab2ed572f805b4084b21e4cd289bc2c93b44e01200d1b0611d704e814b856d48c6377128fa2f90e4dc173f97e5a677f44084b6dbc25014ab7ae1e8539511c2ad200cb4b9e1f60b3c82a22434a8bff68779166190883f9624580d26230e61d06a692b09101c1f60fab7672b5d6a168519f9061f1311
+c662b6033166660875692c7cb400a45f49a9058d0eec60158000c1b3ff6cb6ada7e3cb0f549696060766d6c88417de185e8f92fd0b95b3e60a8d5d92d3eb3fa7ff4e0268ef612cd93e6b70f2fa393ebf3f15cb105696464ea23e7ee2c467539c3df167859fb8318cedd23cfbf8d8acb1cd7cf1d07e6023873d0f7d6236c412
+79de21b2cfff6b2c22c5fb824880bb115bd80bdc923c6d0aec0d30ff65024fb9fd55b0eb0163055138b9f140dc7fc02a7206b3d48f240bdaed454e73798e57e898ede3c3c90cebf437a11d2587322a026889cecae0580f851c3b24f776ecc40454fa2a4a18d6a9f7acf0eb1ed77aa874666426892829b27806d58bfcbb2fe8
+bfaa8ffbe9af08035a80e38fec7d365f7bbb0252c977b6067ca276c7f8eb1fedd4992730ac0bf1eb423e11f23110c40a05f2962a58e6f945caa0353668c1a748bc96ebbc31dcf33811139bb4a09bd798670ecd4bf27b69632f24c43a7e9932d23b3c5ac161b588e5510bd34aa9fca0effdb0d04648d0938f0604bee4053952
+889b115efb5874087ea4d968898243af4f823470154a5ff87bd5b7ff15e503a202b7c1a6ea95972f6e41cb541e4d64b51cc9cde37dc8829d0dd5c5e15de63b23b275ab2a2dd8677909a97f2b7298a88f01934587e99dbab11efaedd8ffbcf7cc71dd15d6899c6b9b5d0c116ce2905164a99526068aa57b92e5288128a75759
+9f51a287484491c727e258bc146e14e139ade61d957b2bccfdbf1d7251c9c6c11bb59ea4896c9ab6901a11454acc95098ec9b1072bc3043fbb0f532ba75aa47aa61e340f1cf1d679648c3b5d0eecef05212c571dcdee915e54fddeb48574433f25ec49b5e51aff9096dcc37f3ecc251e324ab189c0d9900873e4a25af639f9
+9cd818f0bf3b2e7ccfc9eef7094b49ad6e912cdcce96189cb646369683084148de4c6a4f5e6e55a322164f063072ab7010367f3b0d7f544ad8072f54badd32cc5bf51e0f7203780041db263fe150af7300895f1fb7be300853c264a2777076fee6f9e56619a1b7d44154b95c3a3e0433ce02a1db6262f3d9f5438838ffb362
+b963da4f4e438a1a01d74ff6ecc56bfc4cb4b1a135ab81431dc7c81ace913fbd056e5f2266ef565d4464c9ecab8094d638bfbe0a640f7f892a46572b5db1f618e6a71b727937a672c95e604a6bad1977a907616c8aa3af17ace4d9530d02a992314728455be5f207c13cf209499c748ce2f7c4bcc8756e9579bac1ce84eebb
+02d9fe35ed80ac2a4323bbd15d91e2c214c4bdb0e1dc8101f349f0328c371754eb08f5508d3b6a14afde9181e85611ecb2de720c2bb332ee6b6eeb928a5e3cc5a1b7a0bc72116aba7cc9684c7d3bb96203ab60f550bdb279129576aba4b2657aae837efcb4e56a711c56d6ac6777bf68b91a4fdeda09f9ea528f532a45f291
+258957255cca6ebd4534ede89c2bc397c91388ceb8655995b8ce792a4d617063645bcbe7a2770be9cda1a0161cd5f33e36a71ca94883a1067ea9c97571832a8892cfc6ac2c9fee7f115b306817f3d2f8eba2c52f9150503087bd7c6d118980418e0682767c287b23ac1474cb820d17b9991335c3ab932cecc7901c50daaa83
+8aedd750d8f2655f2500151319600e3ec08d1ab3d4e529bcca3e87fcdff2fa0eb4903c23e7ca155e7dc021bdfd981581303ddcd133563ab65e99b93dffe49fc52a394e6650ae60df8bf615237b78aa426d3da8b8db58dbc54c38543771a0ed633d5ee39cfdcaeb824f266348c21d4e456cee8ded74af8d20e73186f1228258
+7ecfa09ea725b674ba887e7efb22a5644abbeb890670f6263e3b9eb011f6940148f46c29b4145192521d8247a4c6066a02dd4d90353c170ab70163269e12972640b34efcd9298f86e9fe6b83ad0628ec8b803c32bf2c2a550f8e89c71d47f2a63c0792677373048be1c8729ac277545334e7b460958491daae755f6af3c06a
+8b848ca70336e5b585908d93422f3da947090ffd9175c98b08e523fde5ccc9043acc4c9960af2ecef6aaebcd12ff4c9af27f0a5e3b3a772195c1bace42a568a535e30b5aab6729fa405de74d4a649af84d70e10ba0b69f76e0234c4fbcc5ec377d0ffb49c67208ef3f0aac2c477e726009fcd49bdb0387d134983d12f51df2
+21057c51753a0ecdca14ae8c9f2eaf2b4ac7516d72d8ae78e950cbfb19aa676dfc03e3c923c4d8ce25e4a7c9cadfe5fbf9fadfa382da04cbb47829b988ed99f208d60f915f52a3564efd3462d68e54aebe58cb5678817415f2e00d698c1469bbabfbf6919d7ef821dfc497df4b8db1dd53c70906f8e518f3b7f34c8b26171b
+590829a68bd7be76dab9db6239955c04942e2b261be108aaeeedbe77f2f4d05e4902ae99eba1cd4f482bd36f72fffc124e3c90ed48ade35a25e673841c149113ad0da2fe2bab1207bd002323509ba5d29ae00285e8909dfbe7ea3bcc73998346dde576a41ac98939c174a973b41e1a0666dd247ebd5e00a4e408d39503f490
+de243866ea7893643495cf9bf551bca3200baeac4e0f1955adb174416b29900bdc2def860e7ab7bd013de0dcd8679e183aa2e7693a86659caae141afe8ec7f357e9713b0e7d07de7e38e2259e558643413ed046fa3aeb75fb7fabcbcc3dd89ea664f5e5e811041a31384f420656c62f5128ceb1289cb807d0cc41359d61cda
+741f98f967e29eae00fd8dc3741869e37d84734817f8d8efe8289ddcac1cf7453a5f847817f1904a3d12c06c6ec290df8136fbc0234f4e3408d1470c3ecbe6e5f5667974b01eb6ee6e59dd577375bf21696bfa4d5e4a3941a326187dd3ac06f6612bc53dc31bd7199f13a4fc3bc565b7aeb3ab7715c6d54441e8a88ba29ca9
+4c1afba6770d72d0e20710c4bd382b1ffe3d47a6c54be048d93d7da86f8f385eb30f79d6821087ac542a1da642a1fca38c7236eb55471a55f85d95e3325c145623d017167eca2909721302bfc6a6023967c6c3513c2c69ccbaf875801138640fc1f47fe28b9d8bcdb948135e74050d60db4b3b583dbf2c6a627d1b46d39ca6
+88b8413c95d0935ff58d8b5ced048fa04a5890dc4e1e257c0ab5a8200532ea3a11611c170d7834b23ded19d0f6438906b7a7d6ca1ec1b3216a5e651e270583970b96da93617b82932dabe11feaf993a93ead759dfb34f4cb9bda39c2b5910808a8ab41168c2773a0fbbcb896a85913ddbc41446d1a2fa208df5ff3660e2095
+fe17138d0b735eca1aebeb34fe0311c4df5ff111f6f5d7e2be085afc3f231f2cabd5a4e7b7fe5996e7ee2fc56ec6a4b593b400c3707ec7d954807fc1f8013174286daf55d9d03c0b1a6e6de0af0067b4f42b13b767777398f6fa494ab448c08d603238434c8b2de9c140e890b9da0cb80529c58eaccb50eb7a560eaa32c9d9
+e179b39fb7d8b18b523966763d2cb6bbc0273db6ad7a29b31fdb9ced9943d9f2c3348d3a5fb22939f84609af0cbd5078bfce54b52c45cdfffafba11f221bb43b31848dee06579182715fa0aaee8492ba378f03afcee8823e00c06a4012ababe9a78a3a3288ace313061084dde37b21d34cdcd02ea1117d3acfa3245eccf86c
+6315e71e446687e6d9517910c440c838aafba25779151e4a64fa43f39abec747260a6ede4ae9b8a38c94ea57ee4ad5734d4d8a32d3b087c1331bed493f5482552252aeb7de7c0d9adb11882b96f074ff1b41f558987af3f081d64704721d3c0219f9e762f74c65d7420067527328b1e2913b772e82330d22ac35b7677c96ee
+8eaed8b99f2d7b8c28a42b3a7d22e79a2c3818c8bedfb3e3ef42215c21e338cb8cbedc151ba547f7c6592bf7e13cfb8081ff8fcdc1e54fcb6708f3e28374fb366953157eeee486f706253ba18af4623f38c1a74cd46dc01fa49a12dff6a6fe59ef589c2c0b55b7c16e35fa8184b1aab386ae793bea13fa656a8fdfbf712831
+5c4806d00cd2df4afb6a5e84b237b5a68415479531a47afbd5a00bc1ccd5fd1f4f9c95a426a553ef445615de74bc01dcd1226971233099ee75d0ee5cb06321e0c96aafde7ca90b8153d0c81758238af7c55402116abdb470ef76e025125bbe6d91ffbe99263494c65c59eb9cba650c957bee2250e79757eee857f07bea6023
+569590e1348049bf932e0422edfc51751310368da04e96ce80729eacb63fa140fa83e759655153a590fd44840abc6ec60aef47489fecd48fa953103a5f642aee55e28cab055da0d15e3d750e93e08cbe9d5277e61fd55312f518c293c1cf98fc9eea0d2f6d7b0c26df869b36bc869664bef19b6d2577106d7dc9b15a69bdc1
+d0b2263926b249bcbbd392c7b55e59aa9066022733ee075a7ac0d407c56659660bbf4d051c793fc4ae5f3984fc8bad99d5d8aa6141501960c52efb0a75219c934e4e989f23844fc319bade151406a45afe6a34450367bc34cce43fb8f18e20a3451d999548121cc552abf976489c60ce14b164321285e67c76ffe46211e557
+109742bd3861b74fbc28a26e16cc367f83eb08f3399d01114b78c615757f768934edf990fdbcbe160ba0be780723dd5558ab3274c09e76b4086efaffa891826e5c94c4355aec9caf4eec8b557b28163b809180a7754ed0edc212a4e6e7aa42cfd842202c320341889709b351309fe55e2d96c3b433ca7e70a4c68cdd424b88
+0f9c9379b41075bfa77f72808718a26a509f708427be64c8c9d82f5eb45f64079ef03613a19e6ad4a231d1e5dce672cc69a8ccec7773bd07c5d29a78c17797831ff7111f73a47fc637f32eed55d42c869eda61049308d43a1854ce98a2ba7b2819911beaa1b375a52cf825364681f7b9d0aa55e377fd7792db37c59b3193e7
+b7203b5764616b5efe8bb2f63c248118fe52aaf104f2a0554dbc013ff95753f7a64da8d877f265870c0ec98e9eab430286d0b8616c5e1731d32ffd85888b904b1861f2ba9e74dc3f2a4f3faa8f6425ff88aa2f1498a98be44748d6100f20c704323ec200a47f3de3a850097410674ebc0de4c0bbd6c781dfacf665c18f327e
+f6166d933838aec0583fa35fd3321db29f27af50b4d158e5d9a875b45286c19c675d92d56936c603c5cc533da08683e13bd35e2a1a02690cf4b0c9e25d2357fda47dec700321e4e2b9a1afe0b9210736b970cdb25bb9b4802d06697892aad68e825b9d2efe0be08593279d78271c42f2f7ec281c009c6cf34f2b71e8adb0b7
+39431882a521cff5001ca81a1fce7f46b87b6a7e793e4327a244f3ef16019febd705c463979b60ee6ea6f87c2c9202c060bf5521ed2b61a729697fadb707fd2eca5b5bb74580228a7cac3579a0707175bf10e35b6f5a4f72497390564d2c0a9e30614bfd1982cd528faf0081ddf57e2311315cd5b21de66f5eb01582c6c9d5
+7c4bc18687638c120c9dfe0fa4565f7f4ff2facdbc455ead34703595dec11b94c866791ec7594471a2addb3fe7e3a4ff3baffa0e4793e2fc6b6d2a991baa3d2277ae71d3e200c9e66f9acc298793021e0146019a0be4f7f393d6530bc397b71b6a4b6bd57d25deb41dd8748b6a49bf110615acafe1924be715616af387267c
+3032c9dc819206d67bf16c005b8406697e31dcc27cb978896c86d151043a6284bcdbd3491adfaed4d752ab0545040722dc822ebeb86aabc704547026c5f7ed488a96e40c80fd1318a12d1f08807ccdffc4ca2f28c7a6e4610d31879be015f6e5dc654e13ac2e6c978a3e8caefa23b84ea909f82af078f9bdb6efb13f614107
+7a70a9cbb32f3c44858aada1fc329e53fed7b91dfc087e9e99ead0add11e1f6f1b64f8c01f63f0f66d8b0e72532131fa0e5a8491d9104a8e469165466b51381ad969ba3f40180d0d248b2b12d3e7400dcf7f6a79a773e237318ce8da78cca61f8d47e916f87e5c796be484cc75ca49e111e8669516de77ddb5f11e33f60205
+5654b1bca7cade5774593cc239cd4fcb3d5e4f3a92992dbaeb54823260f6b39a9b5ccc95dcc870f5b06ddebd1d5efd8793d69d30abac25586345ff9c770a92e65a04105b21198e72fff5bb2701511cac912935a3ae9633a4fcf046db1ccd4d95b5223d62a452ce58a5df0382f0caf9021490c540c4bdcbf4e93ce337781069
+82268503d6238c5c738884f95bdd5ff4a21c0c09afc08d520dd5811066a94707911fb57ee495284aafd51f747924b1bc7dbe035a81b5cf83b8307830e760271dc5f23e8892a55d8dcf43bdc5fbe96b1107f6059318260a090882912cb9bb134d19bad158f23d9d7524d75b0c4895a2c51d0fd8d727b6830bce8bf2a946206d
+4bde47d871d2f2e0765768d751c3c176f142b7c935e9b56a9eb4629ebcca59b11fc4e8ee672e8dd7b86c32ca8b14ac3cfd38010f11b24bd8195861bf04af8406c846305993922fca7525e2d41a2155df3ce5e69d65b023fc516e122aeea9a60fddfa366671530867c9ea775560ede353f845f069a97f99bf0fd36a745aa244
+efe7a6cdefd3223fa50b4c7202ff06cdd500957d22ef4ceb99f7209f47edbad226d803c59060522cb64d75d33a0a528234a5a08624295588ee5f43571b6eb3005ffd9f3c6aa25b47ccc54899f8d2c92e873eb8428cd87224253f7425d921a88e0274a5ecc536845f4109dcb58d549be8ecde36fc996a681142d9eaf8eeb6a1
+860e88a98ef857f4b85d247cdb4c320f39a565b568b5fabbe86cfe097c6500ddcaa28216422c0b3f59d1c965cf0d75b487f1fd16a22815cacec8cac0f87e9eae79c0bfd4b60750dcd740bde980a11f4ad2499505a259f7619151fd5c0ae1eef55eac375251121f9651994c31534632458c92d3ef9549ba7556a8c65bf13d70
+e20583b41c57a460ebcb92fb2f36c567763f1e40da89ac94c4b89aa148431e294854a85835e73a730cd6c53202b5065ddf04d784f8d4326b7adc1e9b2a4e0265fd236f6d186cfa6c93a469486bc341ce64b12fb2f4c2e8c981e208888b748d944231dc1fb5362db890ef1edfdc15420a10020d15fa3ba1acc41c3ed0a0e295
+b366ffb47505aff24ee0ade40f070260c863515afbcd8a93637f2f7a82b7802c05a310b6b4c0da22a4c1e8ff47e739656282a57f97af84c04d645b5dba2d9a763fe2e18d7a92d00b4c95b314726889ff51543429de1d2d8a3819dfbe42cccda4466d20569e3d036f86428a1ed1b801fe287da0c91060e14b149dafba38ee6d
+fb2a790cdbeb4747b89d2afb44d86100a9f228a00f8019812d4d79bd400dd2643bf59475c882c83fa8837d8ddf5c602cda009303a7344576bd14db7cf1f42a9915e49586dd6216d86d53f644a245fbacabb985ce746169509ef0067a98528ab696b88814d791dac614373e7a14761e7c860bb86e7016ae11c3fd99aa935dbe
+e4773b2fa8317da780ee188914274b3cb4b2ab2590b0478abadba0f6db801be4488bae80e0bd16425d8a10f3975c5b0e4eaa3c17e30343aa04fcfb0d1bd3a5c6ad6ec33174ecfd9cc6ceaf1ddd0a0c2763be7ba3aa580ec4c0e4efe578fffd37dd044285ee207e728469a8f79d541945a70141851ab25530bb5a09be0e2d40
+3b56e6a5152dc75a59d70afb83af949c13898b3ae3da49455c92b2ee0337fca9613d147c492df5ea23e9a72d3e003b374c409ecb50d8f5895df1f017c30e8095573ee46395195961a5addd97c2237c54d3086e430da34ee6e1ae85b32a98d7212a6e072ffe73e57d065e2497508c0899e3309945a8e0c48f6b908fe569911e
+f443a5a39f72a474536945731a0358a18aacb46df1c1e8b27857aa9dbff6322c7ee3555f657daa27e78aa1f57a67b2b3286ed4d5c50446e0c8116acfa2350633acf375471b0328708854e7d6e92265f3e74e0a16c6bbaa81544e9cca44c351a477b2202d64b47fa89bafb043b2b704c4848eb349cdbff9cf31ea28a813918c
+117b259d343aa5f03a2bad1724bff9cc7dc9686eae637673438c20de1ec832eba488006c16b771a4be83c2880d378a73312a0ba07c246a72f03fb55214e205b59b2cf1826fa459c2f1d55a420ab9bdf1ce11f8fd7c659e3d43edcfeec64f591651ee7e7ca23c4b78f6f17362f6ab27701b8c84db6ce89c571603d2171cf5b7
+3300357abb2920e5652bd859ee437581870eb729858f65e8356856956fe1dcf617de21f80cb69977f0aaa02260e306d672f5f9196c06b08a4126be7cbf431bea44e03a3ab86bfbd685099658369680a307313fa23e4ed89b02b4062fbd40fe42d270344a916530749c56ddc245183607b4a07d4f1ffb4599e8460ce525d6ab
+19af4b561fa987401d2160cfc9e78ff4d211d84863e09d3f8c6f906c1c42c3dd8bdd0ecd709a5e90cbc4679d0ecedd20014694015f36a20eadfca4c818b0a2fc0353d4c576e7e94c308c08ed67236858bb88f180611dcf38cae8d14bdc3ad0f40a5f9695c11f584d4801390b885b544c3f3a5b07a6d3821724c09137260dde
+72224f90f206921b38768da87d0df7721b7a5cde0735d7164a4cf429ce3584da362454c6e389c8c2073e49564b245aac532e0a3631e868a3ac174f7a62c0e8cd8e4b6932e7cecd5618ba937e637ba20ea131863012a5688315520270e866b85c0ef3a450a292f9fc8052766240f632263fee77f3538b5e1058787cb65295af
+7e5eea99d41a84beadfdccff9f4fab6879ee0eb54654ac5cb345e830ef22a5bf9a00026e526086a27264d70e181aa2336e96e987d341ea74c7212048092af199b711cad5195e64ff60789ee873d301dc3fac7b681ed94aff52490ee6aeba217d5861a39a148dda37e2ccb876065c47818e49ae05272f6038b3a58f3f4824b9
+5538d791c678305ebd5c5aaa346658bae0c2d3f4f0f1f04a2941a1fa7c3e14ff067e9ad1e1e95a72d267c6394353320c4b4d31ab1d090a0d53bdc3df6dfba09642adb22c18a5d66dba104bd9a6331efaa34853f299fc0e9d435fb251b48bfbc56acfb79bd032dbe2ab2303538bdddb3c8083ef4696b569b070de832afe8e99
+d8869d408702e052001e5b39280136384653693b35ace3fc01c9f859f709d1078c17c75d32c9a00fb3db97c4d3ae4445507e238e5c0b7806d9c8492b9b843e3f0cc5e2cc5dd817e081c00d6d83378297f27c4131a29b9437323175bf5b9d3cf86e250578387df3e342f97e7cccafcd0bc229e22a9cf8fd48a3b28f82adff7b
+65e654706d8d79fa6b0d4e6754651dc2235f37ba47984e6e26cb99f46056ab74da43b1cc76561fe82aa233263b05126e66cf6f4f6aa3c52c3c6bafac90494e266fc7f47212f164e041761211f73514363cef69d5e1fe3155d19260fa622e41431584bf71212f42cdb6ecc2bce920591e6a06abc72c70863a116877aec33aed
+235f43f01bbb320ec12da7c95744f604544988ad2b68936db008c324e500b1e614c5035559957d3307d8d57028da029826e09a601d667ff635dac374e390e70b968511b5b859a029a3d80b22eba03bb4d4dda966139e927d62fa9869f6bc3b65d19fb81d1509a23bb396e6ec9df76555781ff2e595648c73a05133476f8339
+e71c97b2e7478e15e11c553178dc901a5b5aedcfe928cbbf46db104402d1b0224893c67f3efed78acd7193fc4a960850b6c4c167594a528576d1ae64c0e88ea5b57bffd4e1bfb56cea85436ef0bbb8846076dcbd88be89727c6277bfa4502c121d6eafc514332daecf17f681a36d1860263f9e3bb24483f84451acdf849067
+2f497e5c656dea475d9df57046c0ce4577e2f5f76ec273aacf56b12cd527db47bf88c7dec117b9500a3c4d1842a1b61fc7bd430de6d563526fca71b341fd97613802812b4c1b77ddced234619b459867b3201a9f1da37b8db636ad07c70968976e5e33df49d4bb2c74bb6d2c472f624032d47f1309d5139dfe6e6804987058
+a227fc0adc716e6ceb2401b4158929e5634e8b329facdea8c8f6edf33d52c5ccce8db18bae293c19bce6a1caff9af9d3a1a4c9125735d97090e212427c5cd2462127b1756f9b2b1968517f9b06ecedfa1a890328a7a68554f727240e7828e9bb54b788fd49ccb0ab90386f1ceea196e588a6ad17155b25fcd5071a4cd4fc98
+1a2ac8a930f85d9e70ccc6f5f2eef51c144e5f4c1523f5cc9de9027a6a96b14280ffbfa12bdf07ddae577b7b0559a500451ed1e254b05e29b7fbcb09a908ef2dc5054224ea7f9c91288d1f4c1bfdce151331e0a8841cb41296525e2d51ff2bc7ee6430b40f15c64f0ab35ba1917e35e0a2c9c1afddfd64049cd3b1544bc1f8
+95cb3e653160b62c93046dba6c49bce6d0026f06cc771e462c9796c6657ccdf4c9db0d346e1574a5181e52493bd08c7196845359be3f837eeeb3ab445c348502da48d840b8887d239a51f84ef32cc9699d27f4f783ee311f8639dfa8a5ce0c33c518a45c5f6474a8d7765d25e0453f3f60f88bb40ed5e2dc2344160c171b6b
+66d8894342502baf13f63532314bf2ed29576a7584df8e3d5a44eea8185fd3ec095e8bed72520b9334d1431d9f3004f17202b98b3409419b6f8747854a104a5f0afb9da9bc8c93bc4391e33cf99c3c8b9bdb3ccb251341c5979be14d8a9b1213219c2947e2604cab41f00a7226db4c1ae3d65739afdefd62ce3d268d854540
+549fceb1c46a3d37fec17a3bd01631ebc63cfc36c576bd41118ff2524bc6361bb52799425c93f2dc275c1a988b2083c82a2cdb5d6aa311b135a38721e46e57e00e518a0f06e09622d86301727a3ee674aab7267fd680f2b4c0379d96818422e41634d568ff18538a4eb4aa309bc1bd174dd987047b817733424d4392ed9236
+3dd395f517c2ba622ea25dda82738e9a942558bdf278f96508a6ef4c2a457e845667caa84173b11c46e8a8a4f9c33aaabe426295baebaae0eac62f8dbd68b71362d4076a503cfe9f95b26d744fc9a7186953cac74a4b5ebd605e702278a5c6f5b6311fd50a39625e63319d932cbc5353833822fec28824eed4a8793eda8d5c
+081711ddeb87a5f915eb07189931ef1b015af1cf555c99208ca09d3c802b2f1593a23a8774410947c39c116697e4edeb29954fee933d2c46f1c2f61449e08a0df628f100bd986869b4812e259dc5ef37a59b56e938da476ca294a430f1fe1e836aed44fcdba589689e90dd6e1e215eff05e70c0df258056303238260b26797
+48aa26a396d7bcf99a086e5ed03c1a48ea3fd63d61daf7c1c56faa45f824f011b594af1569f2c1ebf0fc4cf99c692442c0957fbe6561728774c0860debc7e265a98297f6bdab8d18b0938993777bf50ecd3ca6395074ea555fc3a925b8433bcd68ea6366c9bc148268f68dbd9c292d8c821a108c3a1b8a194e7f3e745d1428
+7441c7e9c8895b15c6a9abbc42292bc373056079083360cb3481d749ef439e788303d500ac098dd88903f487ab6b198126675dcf021367d32e24680d58dbf551ec5c92acc019ac5e170705190dd7b89338514c3f102afce6409fd3ac4d95ad85b809f920579a2b6697d2424cd7a6324e2fcb6daa2a5f4c5e80970275567393
+4a599e605aed017aba72d3b84390d7336c1c39f2199f732befcdb6532bc2bdfbc92ce17316e5519b53abce88d54f6877fd0a00bba4192197a89b61e6076d521ef6bacf588d19aed7cbdba39819c9a4019ab0641227eea491e5a0aee1eef458571ba706342fe0876d0419704118b18d1ee9e4e055c286c1fa59ca2fd375346a
+fb75570429922b44b376006e2a23c3228dff653e6ee6ae109c82655c18c02908efe8f447784e5719f3aef0ea4040774200ecb72e96f7752c3d89a7bac7b1da38452f820315b39441e0300944c657cded958620ed0178b0901e03e349bced5bb23ae9e4294deb84e5031116633483e5af73d30e221d1b9d0bc05d6a7507fd52
+f6f6db80bcc9116adc6c34eb6e037d4bf40bf04f282005d8539bcc32ff7719a5256e0cc263724a645973a8be965cb20a5d87b53ee0ac408af6c89dc54f79f04ded7cde96a166c30bef69fb320ca5ceafbbdf8252ffb2c0ac82558f65bffb8022bc9c7c8f373e1cd7819a3375c29646557ac306b47f9ff2cb91e0679029110f
+a583655f8d29a7def1e84ae42480a4b79d23c9d7b1e000a913d26522ed86aa3497d93345139dd461ee93bad486fb47229ea75607c51206cc994e3efb187aafaadc9ec1a905eac775ea8debe6faabd7ff22b11e06fe8554576575b337065ac891761a25975b9b59284f842dbbb3b2c1a27016113a1c13bcb6e552d5204a1f41
+a0775987910fee7eaf8cfadf31c537b85bb4853ba8a3fe6aa222f09233cf8d72f573b1651c90ca32aa7ba49185b8afd79c483e0a6241a89aa7dc18ba9d9ed6576b2e81e0168d57c496bcae44e9d07875a6f3c447c622d1d9004020acbe566047055435279a093cebd7c4bd6ed9a29721f1eec21c4ae24199876541d113f744
+6219637f4477e6977287e704ef7edfa1bdde7fd4be8ff57439ea8f2146b0629d8e98a5a80c2b8763f7189bcbfdb3222b9003d92dcc07bb7f1215b27c1b5a9a6b3595eca046df1ca827400c216f2f6da33bbcd47300ba4c4bf6d5b61fa5172f0813868d7a684e1adc3740e4e22a9e430141d68db63d6c40b5b8b837a9a27e3b
+a41eb6cfdc48765ca00b5f88b5ca84f19dc5b7e481a9fdafa504a673f0871c5a44f2d44f726d6f042cfd5b76828bee85dfada1a721533771e995d24ac9bef9e40dec0c0d0ab444dfeb55cd83048eedef09501f1f0e3b7ceb5f96686d571eac8f5c710e551c350560a85b68931d3ec66bba5c3673e59ac0cef367f9bb5b63a2
+98c1900e13569a540affc04c8a42768636c45469ca2d2173073e40a743d78cd8f58449efd6662978a3d58d73d05ecde6daad772894d9d2b27ceb04afae35f3a18854c61968cc052943109c2358b66a31aeeffae17b9112758796e41470498ccba8009bdb2e400d8177af4ab29e57c67e2a816a7a682e6f89ac9d4c0d3c5fcd
+c353523354221aa5f227d902a8fd6ea1ee63fc6df9cdadd1373d516c6d00a80d46472eee97d0393100db54a0034635d772766b1533a0b41186d87727a64c3e90e02d0a00deda7e91b72f752661a5e8da1ee320c97781f804b4fc9169a67ad3713eaf027e64dba1b4c1ac04ebb31b91b0b287e235f9ed9786e5b509d8b73b80
+75f74c95c8e269af91c5d38e45486fcec38e00abdd2c82f241142331709d78d7ad32c0237ac3e04eb79d78962d9bd014e2c1a58803b17ef22f0e05e234253b665ec0a813ed61e93733414c065693b7f6d78ee298356ff8f7a275ed990fa6d2ed7e52e9a5465acbfdd07be9affd4b4731314b5e80d1564212863e5498ba1eaf
+7508a899fc41ac1b33e7b20aec88de070c9a490d7a573f11bbc260ec929478cdd1348ee0a9356e16a22563222f89cc049828d3d07bfcd566f2e075915a7b709375ea963ae4a226d430200e227f8e7b602496fae39d595d9e34a642dc8c16efbb51f13e8f3026d4c4adbc7f6ff14321066e996f256a9cc9b6115a9ffa9aae77
+e794ddfb7d5efd704c61adfab6588dd8e42b988e332757a4876eae9aac89e7f86b89f48ccae16adb137eb79a9289cf391a95dd4e73719ea2ccec34bcb59754b939b5a99d3077de748cb4df3b8b534dce94ac3b7a709a3ee13859d215ebfad213687f75a9988f23607b2dd603c2cd3e2af8d49d659bf1e7d214fd6b92db86cd
+af8878d0002e2a050009d9db2d4a0700728870d2d3165e7611d7eb20058f27fb7f7922db96a92b8573fdc8b6e0d1bb9e8df799621a1615bc5dfb089eb220fc4a8085efa031436c767a63731200728aff1c8047848108becb8e554e05f6140159a40b1073bede345010aeade337f2d502383fbd036a500bb5c1ddf42204f2b8
+4b5c339bc5e269c1704bc1b95661d4b633540c50162f56661689cfcfcee775de2126d729a37c31bdc4fcc06c540ef8f6cc9ba978f85bf8270c1bbb9c2d49707c1695d4fa8381520b2511e40d890a50282376639e70b2145f1ba4738275951bd6e1427f9612c78260bdab1e2315d41c6f5ccb7ebcd9e9b6ab9be818a3485604
+2369744103a0210c2ab48be9235c2344efb570e82e16ebe934790d6acfa8606db201ba275cd3592a0c2b7c627808a0f08e181af74e4dd0dcff9a54fc1af11688e3b550991700b3693dfdf834657ac3e4977f75cc120679b35e4b0d82359e57b4a6ad12b3199e6e54068bc65dee5760ca3a813df048bd8503348a660bc4550a
+8f504649dfedb69031ea44343daeb2f994022cd2d70f828f355f0f35d5fd031408b6f0be5876da5e993c23e8d3118f2436408b99aee857a02824b2c66591f31bfd41e91fa3252739ac5359bfb1212fbb8a244b6d41354c42fdf0c3109e950ba4bc24124caaaeac7ba166b8c8c67198ece4dc222bfa6b866325e792d552a5e0
+ede88df12921b03d1ef2fe0aa5201b294582ffd3f132739afcf97e2a1feb9dbf490173530dbd7155da05e86b3e1fcf1237ad6ddc2059633b6134bdaa312427327958fe100989d4043219275b63a00612dcf4e50cc5ab5c9d634906bab562e5303f2fca751eb973bd8cbe505db334f5952aac5bb4eed480196d3b8556226b98
+6f2bd57a77fae30252e1c6de72cdaeefe3c23897dc796ece0bf11aa3cc72ee4c54481f426e2d4934dfbe34798961855bfcaa2174fee48565da40c617c84070dbda70ceea64631821f11183d25cfa78f0a7b4d6a50908a39cd090ca5c932f4c96b92ddb0933867be413dde51d795aed8e9abb4559ed0ef83fb6676f353fc383
+52ed0fab4da9d5cc60701b83e6e67640233a6d47b33063f08f758960d8b0efaf21a1843a771c760fd9dc4169f4464ac7a2c6ddaf0fb748ef6f66d541c669f2f3a3fdda3f638517c74925e8780901e61eebcbac3db53c36e6848e16e4b99dd9fe3c0d4f42aec5218f4cb6c9ba80153d53e77726fa110b61b137718e608da99d
+4fe056bb4b05d69143fc87f52d4aa130ab026b5c8afae8df0be26c260f807e1626f38ea644865ff8a6838eca7c0dd98314cbdc861bd06ffe8d8b8fc1b5ed1f4e643a4bbff318f16aa5f1e122a18ccf5becda91b97c3ff4b068a71d8b1492718c282e84932578fa10d3500c35a25f62781e3f85b5ce786530a5e95a815e6a58
+df70cd2bf2fcff4003152bebd49e7191a31a298b124407e39097335e5559b67415c7c695128caad080553ebc9dcf39f80fdb4b1e6f119ae487f809130e177586307004c46ca5d6e669fca92251d598577a9b53975f19a3748b23c429e033e27dcb4b79309f02a07063e4e5c085984a436cc61d86ac36692066c49522ca78c4
+4d0f4e94bed0327104958798f1c1e813727b4e5a1f722921b210d9e55debf6b0165b4139082bd20126c5f07bb145974c776bfbde92bd0b258ecbf6484bc8e7fc85594a68f8f21a48651044d367f0dc843963d4676f5ab892a4b2b54c8ad5f3e6ad73d32247495e2df10a4b937d6a0b3bce9828bf147f845e2edf9290c605a0
+24452fab80be623d1415433a48a2fda1ef272133cd4ad4cef69ff078b3d1036abef3121014e89456446c115a7b5d5ea3233173239ad9677ac6f2bf1afafb2c47c83443ab90b8e6558b7861d38f1b77f121ed2a4825e9f5a41f12ab36e1520244d790ca5823aae2a74efc30982a47c761bd8870699e70ccdb5dc90388b2fba2
+fc13f32c15ea3db5ec31cdc76c19c1ffd71590a2a0867e30674d9e0f71239f36e5afec527e3b67bd50c2c0ad98a96ea16e1306ed31f807a2b08bb72adf690974e8fc148b559731b0a2cb98b7ca2d610db0ea0c875891ec8e12be3ff4d16658596399332244d9a6468e501622caa053ca43ae0e7b9fcb9fd98b99d964478b93
+793ceefea54a96bdf2663c64eee639375f7d4ad7127f0f816ec8a7512b83b3cb83e5b40c7ab4fb1afd590008a522e548e39b64f5d31e42b15989e736f9b0e1e542b0b0acd5e1df5fb712d66e939fc2359f720587e24d7046f39ebeb464dbb353d19cc64ebbd2a3463064d9b4ab3b9b5de3d8805aa62cf477a18359c661a199
+0d27393a1dbbd7b38b4b56a13e9be9cac64b5edf3465db6f0773d65e86dae5dbe5b6dd4b579c532866fa94775ad1d992e20e6b828a68536a7baed097965941f92130d454a17f1740cdf1b2fb7537d1c02e1ffb06e30104bbbd7957c83a5bdd3af99819c0d2e95894fc463a6111532457c72e61bc801e1869d4175b2a6d031c
+82bd15c12fff28c31f766dd362ef74960e2ef41852b21d5b052bceab43de4d7501cd80d0ed60613cca8b875fada6d3746b8e6cea1f0d507d80a2f89bc42e75caa36da8f7095189f81c87fd24fd533e0528b942cccaca578b8481785edb2845063012ce78aa93afa6a8b39139b1cdac135d1a30a59a3130275f28ab74be35cf
+8fcf6cead29c4295bb3db61feadc8f6e5d333c81c133ad9c765f3f432cf31f0ad3a1806fd34f409dc6537c998ef3b63253012ccbe3edac76663602bedd2c28abfb1f3f883b7383ac09dc42802639ebb83db822802b53214963eb988e4d1fb430c86445d4cb24d2bb3d7fd7e191a62221a4e0c24d2af499655d79ee67d642aa
+49f63fd82a7cc170500f964c7c33165291bef814a1cc0362f9b36e733049e9c0030fb2679c75b5f4c36d7e7b4b86230f8ef88467f39b772b646344e0c3f010c3d1e0e32f58d91f2501f47184f5106ff250b431816d4de7c09b0355718cd7722e531cfd1cd922730b7f71db7b882fb52f495c241bf1cf4f0ec77a059757d2c9
+7a9fb187d48e997086c55bc2bd04a061db81985b6a37f721d7c55aebbc36b5fdf99558d07823f53b007858e38146a62e5ca25f100e0d26f644d2c5e5949afa8b03d322f626eef137a54ba8ba9937233509e3db69ef2ab64518e57ddad3cf3f230b7b889f613e9037c49ee18c0ed3fa60dbd4ffb887d08619711e2926f57f27
+1dbc112d9cb068f7346236d0b168e31728f3c005ed22beb18f0708c345c23582e86e4306c944e1b2183013dcf7ae4d72dd6705671f6566440ed19622d619822c643e98c7c361c78aa1cf4d216493854fb3ef4635c3c265fbd43c6096f3eb459cbc8474a44998492bdd286c14e328df8a73e421ff5ea5ba8003fdbba9cff842
+2e0a8e32f7ea5c60be79ba96d87242201c0e83cb1db0582c5e548acd0e5c79b0f6025521a22af244b7490a8aab533fae10d22655c08f65f36ff668811de6cbcd6912b88f1df605ee4ed92606e405d44338a781cf0c55b55e1c61dca12c5b6714e23963712a6f6cc39976d3cd3f5156b0af67d59fb1f394a0909eda39c97cf7
+e96cb1a12606dd36ba6c07c41b00f5528c20bbce7acebdffd14d298ba83dd3af61a1da522b4ee302a811df4878806395249ae13345294501640f8e5c9192b616a49d5d1bf30c48315b33def4ac77ad6291be2be111c8bceb45463d961c5da3a0dbc6e7618c7478781c84320bcc32ba0c725f599ea2fca47c9480617c03bb23
+9426619c2caab2547fc917066e9ad80ef1d0b365b859ebfe662c81fe19d3f7beb819c3c122a1b88d6df0d4afafef05ddf49cdc2e8802432d29eacfa8f3d7dfdbe3776179aba4dc7fa113b1a63bb6ba896516adf6a6ab2e09feee2b93a493f0e65f969d255e24f72671a3f76b27cd20a86d0438a0ddc70f7501973235d99949
+14224f86bb91bbe36c9a60fc43dc75ee6901914cd332e1d511c2167e748f2f8b2399f33d52782b6a587617d6eb0877ce02123b097af276d012eef72e8e785477cd37dd04a287a0d1f9d32ea95e12a30408dfe61efae276b3569aa9cc355b3cbed0b56e671fbdfcad47b3249ad477ce7e823669a8e0f317f1b9f8f9c5a7a787
+0d5d87e057747e2bb07378064e3b1fcf2cebf2ef865c1bb9fcb567c5c2d6ecbfdf9ec7805e4bf36e09f3ec3c4e696a2910d382497b1ea650aca0291965be3f893994626769aebfb03d19f9ca084d62d8453a637c4791211f9e4a4b9efdc6669e4b0328a33274cc3de6248132b01ea2ac56160497a19f1759057ecf9d0daf9f
+054f10d9203c2cb2f2d53d357ccc1fc400be9f20481f0e2c095e2df843d8d393521d3b2d6ffd8db68c1468e75f15c4378d07783a7d3a956b4f5a9698f368059e84f406cbf60a9157cd734e81ad0b07e8c67f96a408bb246d2d47f6bed1af8c9df5bc2263d9ce0418ca8e57ec7030bc820c1fdc8f8e0ef1703d3eaad05d19db
+e49d20a80b44e6b5fbe8f1dca5b53e7de7a0d699a64b35ba61546e8aefe6f608dcaf4ca7e202726d1f118773d4e161da4dc6867956439bfc4da4e1b4d45d98674c395d01be779a22c12f1b9f77628399acd7e9f9f100669d57aa992434523f8a1942dd69ea3b1090474c3b9e1482f53a9e0c9d43517165416327f98b6424b8
+1e37aa1dbf1d976c809a8fce1a713b625883b2233ae2e7949196d41785307e538bf1c2b1f1dcc71ac96d76bd34f26085752a616930940a2cd6fe5d1ea6599d6f3a92fa9272fbd899f4d6ae7d6173b933cbb95c49ed8ba27cbb20d639b692d9160d4d41543f504ff04ace06759403db8bd42abb37225b1b72c04a6367e2edd8
+aeaa29249bafb5353331f4cd42b373f45184c5bbedadc4b31ddb226c607e1e68f82070850194d31e9368bd2881e2a9fc7760378b44f7ade27aec4ba4a74de72d2753558ef5840b8f1ca013afb4eb9272ea0a6e9916817ab0ba9691a015e348fa3d500685ff999f91c74a9a72ed499b8efe4b8e5bebdb6bf6557dfc8fee44ea
+c6c9c94a28191c714b524c3c62eb285b0b93dc4162d13c1fd1c3ea2a6209566f2b8d8725ba60ee78231fc7f7d54b8f7095575453850fa30fc4f35ed7d13b624d9d4f1ed0c624ea561d8362ef397d31610e06fb18c2a64dbab31df2779af4134756f1e1a0de30f9bf9a12a3377e72717fcabb6de9e207ddc511eec03dae3f3b
+9d710b9c5df8eee0773ab5af103d383a83ff26f92d29702802d3dc7e33c53626d41c06459de547d9bfe8d62e4adc9aca779aac7048954a42a97de0c13aa3298f2d4a1bcf6c3b012f49ecb90fc37a17c16e35a81d04d5fdd3a8ebad6292a1cd5edf831a7d3ae35045c12e3e7ecf9fbe2331dd8b7650987da815f01f9e0dc261
+1fcee1b811987a752ebedd4857bf39c2688ebc2235c997ffc2e2aa833f132b61241c48b4b84c61ffd4fcd3cbf7b569e42624e02e80f471fb1fed83e9c6eafac8ea5bd0d33b033661bf1ac89a13056a21a42349a37bb094fc5097b306087a77cde8f9b85df6082d62938f539cacd3bb3eb690c729767712801c272ffd0bcede
+ae1f2dc6808322930287a020a2d843058e4b562cde75b0f37ac94fc9abf0cd7f8248a1f0fc70c3d58c21064018c3ee44272fd8d56c6527af50e47cda397ac4cd3bcc365fd8f441af41edc41fcf081f7e73f38f98872cf95f1915e66c43f06c68cce9868e69c570ac36a2bb4d818a46c985804fce150637749cde4495cb2620
+7dc942dbc2c929f80313b14d27327fba035214d915282d319d8e36e243632f71cf917ff964b97d26a00f793e452e64fd4aa229b40755011c6016984fb12375b74397f7ed824ebdf86648d9997ec708f30f985ef7f100fb309148eb12dcf8a6582c1a1cae6ada5e06acf0a562d79b78008575a547505182630390d4e0c4e1fd
+def9e529d96a92bb602962f54866a7b29107c949f1388013093c3e34e7ac8351249d90b30a60587cf4aa7411b1f526f991d72a631a2105307b12008283f5ee36baa88345d3859d821b03c097ded9df4122b0a4b294350fa3404179ff2daac414a973fc51fb4a250d320aae115ab384726b2e1b9096e26c864df7360b516cbc
+0afcdca17101fb4f65d0895aa2ab801a97e26cf024b656ee6785e1847cf2b135287987b9ac2efbb673883317ec4886551a892e83f1be0c61febfaec860736509d9e9b4c756e7a0b5ad5993266aa6d1ee11be77d8b90f3fe2e8a0f9917ab42d28609db7fa218000d840d7714a9fc30c41cf0a7b0b3e78f7ca7c907b289b5fef
+f4619e200ce56090a0de35544137c83aee3c6289f99fbaae9ad8ead6416206b1c03ec59062ddf5ed123b37e34948cd2b2ea8164b06be73d0d54cc98304d6432a3f6f3bf3f6d8ebbffdee3e47bd9bd22c4f9dbe42a926c09199a6b17db66b61c0593d766b7bf2aa63241384c0f32d61e020082118e08dac70f5034dafbde839
+db49b6826cf37832ac11829f2aebba2e06bcb179c2e6fa5b3a1a4976081469d50d64ab44e8e2f94764bf3c1a3454f057fd45ede47c9ebfc034cd07cb5d6eb2a27057af83d6b123402de65ee88fd55c30795270d122fade06b80cc4b237818085e62e2b8603638b910baa4e5f688cb31238568b3e6e307ced895a6684eb7fca
+bb54c91ea12e6a8d996868adae73cac1237425c00ca1c09a1f29bbc89e59fff8d2069916b51976c89aaa64bc58116e49d92bfc8140644210bcf4b3e785a2b6485ddd2157815fd425d421dc69e1b8f1ea1bb6fa6380b9e27fe67c792b05333acb05aa8f95323eae7ebb406ecf96cdd213231c943b02e3c3385df462e6c1b504
+6d58f94cdd30ed7747797ee142d44968ce450dd46352003b858e73e4d07b0f1d3fa872d2419a88be3889f87d7ba0d31052cfd4f0c6644f24dee7fab7c9bac7d8043a253c83d4fa4f6a5da82868e43064d50924cd155ec5751f44768e249c96e78bf703fee7b49c63cc57a8097125e11878e8410487860481077a950605a604
+a65c43e955eff1dcafbdb807afcc4d780b9cf39188e217698a0e09b761b3cac7bd578ec4bf5169b45a5d82506b019b93598d01521a00eba75863aba9e360fa24e90bb62a02f64bd9caf4339f787ed8f2a0e6be587e622caf7c9994336a16f96c1f1e82e932895100f49cba410bc594506b6142c2af6aba49dedfcb99e3bd23
+f6e1013c96f3163c55411a4b64ecdcfe9c718c931ddfe9599bcd6670e831f6d7c3451381a44e6c83827aa688e1be4e002ba0251555756bcdee6488229d4ff0b6462a38acd17990788293df3405b667a9466a954275bd1c148125fcb5623da03027a61ef99523cc99ba5718f25e3c124fab4f38ec79b5157739bcad24e069af
+bd59ef843125a07bd83745d9664f79b412b40ce53254308be8672f73f7f1e047107f5e385534c881479fff9d713d26f1286de459c153c6328ba44e526d3bbba2b6475799e84499195aec9da34be296b21002c2182f826bed70ded6c5234c13ed40653c88da4e2685afc022e22f6b33989d19d6cf06cb6025106e42892c2655
+24071a67147c254a904a10bd7abfe3eb13bf474ddd385753e537c97a5ff42fe7d6409eabfefda62e14e58fbe4e6a961b55475ee469f97cd04437b0fe4375a95a33730aad517b540173e42042e4bb38bce522f68138fd35cd036a986e36e9e5e9b2d2aa9f6fc2ba39816738104bc9d3d12843773f51a1e227e949bb7981bb16
+b1423ab3cc0dee9a025971722e0078f8e2a505dc93d8f5793ddc91683637c7892041a465be94741c335c7cb30f8d4a195c6fc350a99f665afb964248d63dc236fab7e201dc6400043213437147fce4f849f598fa21735aed8a5e42a8bfbd786137044fadbe0c41d982f312ffbefcf9341f6f1e8d18374d933fc20f2a5e82c7
+08e707763f9330014b7b6339c71d5f08041fe1500e268da79ac61e24bb4ffa3967242a8c688edec625ae14379ad5532b33be8d513db0405915da79141c23d0f46299e4e39fbcdd4704f9b618b1e73b8b618f1b9d53b31d34f11c91fd786331c0bce3a63575a616d949044fc241a125b4426f185c8cde39d68c0d094da11440
+76e777c9958e3e9db8e80afdc36f30f1596766bc7357c5bf4400f843038f0e9dcf43b0207227875e306b44bfa7e2c92288880e76ca80a24975be7a55bf27bfbedf0234c20e5f3a5dfa7cb174e4533d7f685f61dbf1ef23318537332896866275b60ebd8a036a1d01d9cfd8bc6e7814c18e928ff189405ae91707ba995b6a5e
+a0aecabd94029b34e09aca3adef0c9f48e362feb00caf969c5922a54003394abeac728b7d68f17b3ae58f6503b8697ca4668ff9df3f328d922f7d6e3a58172db6d1bf9a1dc110059e25bfb18829a0121c417420676bf90f37bf7e3c9eb7e3b65bab1e6484935ab1cd496932676a33c02829cc39bd386074c9639be07b4859b
+64af2b428c79c25ed460ccbee77725afae2119b1f9196cc30ecfae5a9effa104eb71689f2e0afa38ae1a5b08045886aab635e6a62646a1526890cc276b00828db6abfab88dc2f14ce5966dff518693813396d8d0f8cb1f437a800e5150b8fdec1d431f81ec7cddb4eadf22eb3e9c0116d36e175093391668d3befe49194bf7
+fd4dc5a27dec66c19d88bf40e0abab2297ac18e63daaff6cd571c717cfcd79e8c0811f4ba50d191d7b0b92bf93228b3a288cc363beb68a055520e8e1bad3b65b7c9acd753e11df768a763dbeb8df640a788dbd8659f44342cd17128ff47e1b372c95c562f1d31211ba6871c8a877ad39b4edbe382499b254b778d6c01720c4
+b86f8c3da6f212cc62ae297721212d9e033935ec7130c7a6f98bd28a8028c8cc5644dc06a1fddedbc0c6ca77370ac2f016025bc2f53663a7c83a55cd1d21fbdd983fcec08660c881ba1d01b2d2685eaa278213f71a58e07eb2892a0493cf269963854584f1c452d6762aaa05d482c75f61bd2d13952e3b04eb359d6204ce4f
+1abd87f33581b93305f67bc32fd92779ed3f95ef120fd44207fc47b3e8ad65f7ba4a22885b9d0d217bf34bc169b738abe0a2abb7a0d2465c95d6d16526937db61b8563af385706f1c2f970f13e321e7d8621edb9e444f2a3a9f46b2d9d17228d670e2a131e016672049161b837730cafc10617b0d20b562dc85b97516a64e2
+0a38952519dc5d8bd2827a8b8ab6555e2c86a8a3e07447e0bf8e0d393eae352435a70ad83f38bd657820e028c40e2c7267c91b9826f5210737b6999ce841410b526f8782c8816a612c8b9457fd19e41c9ce4972946738f6461d33302be7978e8bbf9aaad56f02ab4e8ec01364ceca2bfa62dacc60e7abd9fe72a55420f7c89
+a9a326b55d239a3070fc4c316cb852c7f28e4481236af2caa71ed3a8088a3e77e027f8b42d1bdd7e7334cf2ad3be330510ff3ab45f16cf114415a14e104c900e3b87afbdc3f0f3af28f25306c1416f314138da6e4585d16cab538c6255284c4d05520a1aa959b62d9d8b917b44997ad2abf563ed70ef00beab3bb9562839ae
+f7e4abb3dc9f5e5734b44bf7dcb257795891325bf746a9ced8ceeeff486769ebcfa27fac8a2353947b2bd378327dbfddba3a67a378099809b6c6fc5f4e18ffb8a7d3e1af912381dab3113ac87a24adbc08f1b6dc8076a29b88932918e8fcbe52b705daac632e176e6044ee7f4587d6d0370532c702c9dc92eb3ee8938c08e1
+e23a9e1ceefbd05dcc3f048ac631e38c6b46ace97e893ec455dffd1bb3873b1a85703126d7bf0a47f5e0633bd0e7dca7f174137cdd5508bd1c6493cb7b619f482c541ebe705f83c03719de967e083f1c9e3a4e357155a4b20553fec360ea773258ef477f8952c5172b10062958f72f2964f653ead7d3e1c4b1c9efb2bfc324
+ac2de310776b8cd5d910afa419c441ad7d239fe39f6179d20e0bb0db05f89ef02baaae6d53f39522fbc48e613aea450926d42560cb970b2d18c9ef992aa73843242fd5b3730ccb7da14e6dacd48cf0e08a22750ab9046034f494e4909c07b0e9de13794247f497e5a0e9c1354bbcbb71625f19a5ce5d94cf5af1ef5ca0feb1
+7c0a097882d41b7889a1e4da2476abf38521c490bdf845ea0e246da370a2f68029f4ba1ad7c183b442d63eaff498aa2b33604edb786030d033a37a251b09f55fa77b88ca7e77b0f9fa91e323049b344c82ce7d79acbeb379c4b23a8510e20566878268b2d835273cf5b36614528a4693960b27df4f0b93458dabca1badfd74
+0c380d30512e68713b88d193899de03552567267a9f99deac408fbb832258bdba1765bf12c0ab5e020ba228363170cda6aafbe8eaf50596aa41635d6a32dd60ae3ea3dc2d2850184fc2e9567e2d827c2509386b01a10d255e317a2b5d7354d325d52c542b3b3fc740c9872bced1b4833e7f2788e959847a002eececa271dbf
+fca11fb781880c82f5ab623456e8f70264de2a8ca5297ee960cedb48de05f41a66a5b4a60d427f281e71e19a5c2c176a004ba276f6e2fb8023227a8a46354938c656e0d1fc9b6d825584b43b73ab00f3b2b265af5a56208f8b8392cb954e207ee90e73782592cccf684d7d3a4982fa925195df7b21cebacee35227e9d58a84
+f6f035ceb665160084ba5dd53a2a1f5614a5830c28ad191886692067d5e2a505db188afc8e074a0c8d31c6a8726440f841c53a93f87f0ca724a6a7f4dcf166a376df218596050473e3eee63a9d0a1f40f9a59dc400dc6688d3fad7c7637ed6bacd16dbd80b27f4f8161d38c70f2f776519abca443e2ea6f6668080ffffc680
+81d96a16fe53a299cddc74f53169a10bf4c09613d88a6a12730e9728d00f1bd91efe8bf2331885589c047b1a94be3350d3afe43b35892c45c4d7dde587c1adbfe18afd376aab2ba652c512eed5ebf8f2da844fb30ac4c86dc0838f204847db7420deb9e059e185f968d134a4a7a6bfc09ab4b93e6e1cae167f6c984cc99b97
+c1feb59e31e3f5c87979ad351a5497554dcaa314aa4d35cd296d372e6f9344655cdac01a7c804e6aa229fb65684e7693dccdb7bdc018e9eb5d7c4eb739cde06ae9833ec2aa9d437e226e0adc91b6e0f15e848c36d7f61214daf57bc1bb10c51f8e2d99b0d8d04c68572da6b5ac1871911f18f024e80cd1c77e2b1596b221ac
+c4da476a4a54c91097d77393a51626b2ab5ebefc17e69c47c854b856a5b17402c55ad9c587509116eb49b3f7629b64ebd9d6a49fdb03318238de4a7a7351394225a80f28bba86937399ab6b1b02464958ebb832d3c1843713309ddbdda3afbcd1f2abdd6510075388585635cbdcfd6d3c59f71e90b287daaff8689d0a3266c
+f1470d27051f024eb406dd6861b2212026cb1cc188c309dc1659309c970b6316b066796844e605e606c7c050b548fcd702a7de57df2656ad727fa271f9ef79393c3fc8b2bbdc43214616c3db1587e317676750a3c0ab61b2160d55d18614e35276cbc77d0bcf0a5b14301dc7d6b5ca78876fcd00d843d6023b52fed7c390c6
+4c68850bca9f1623ff9508c312fe2d6e597850bebd23f705295e606651f021e1554810229fc9a98ed50c9a61bbc464ae8c5c6563a0ac09ba85a33f7ad555b51e59c32c7147b140822b9182d29521652ea64a22e40b2456c6044d28cc00f835e83d7560a146a7ca3d76911e72d01d69d0eb8a139c1fa62f69aee3c9642c08af
+6cba103bbfe56fc46451d775a826f54a949011924ea3ced9d739643c9ce3a45ce94998c69b6baaeb5c17e12119ddbeae483ede540c1912b153ee7522fe3f8bdfa76db94eba99005440ddd907c59aebf5cc76a7c5e1a60d40eb9e56a028c5293356a7bbe3cfb02350dfa177525c7637d885f3eced08dbbfbb365d1cca0a60db
+572d07e0a6829ce8ffe562c04553258b7ae406546b8d9a676d931f30355e17963a3f11eb4c9e190ce2c28347c164faeb9051a815d47c2986ba2cf3094caf2c5f64a2422f2222743c1700a21b79b1ffd8ce31a3589239af38be807dcdcd355c8e7cf3e8671764bb23031b5ada1acabb63928267cd26b2c9cacd1b4f4b0a71c9
+426161788e7ee7f32fb5520ab759938beefa4fcdd968bd53701ae9c27429b5d6e059342b9adef7b56b4c5eee2f46e0cd472d48f4b9d47d04dd0a390f88a2be3e275b65c3b7049431f94d850d63b2b2154105edb0527a4f712cf523b75aec52c4816683d59ecccb03a26e151114dae625f446a713af28d7d8173e4c44624ec3
+30f84446f46752fb18ca83e19392b1570739b4d02cef8427ae082b2cc31d8115bc18f2d71940437f77c1f98046b243b41f0ec5b8db811f1e8785fa163b58703e813161ea55c4ec7bd96206f318d2ca177d2d00df885cde32a2c589323bb40ff941da9726655daded4d7758dcca859606892ffbddb1889a4a0b2cca0470051a
+799292acbcf80ec3d459dc25208c73b0923bfa81e73e558c0a86c805bc450293ae9fd058a5f860074c6a200517a59c51582ef0c3ff883ab42cf184e7501919c9249e4cf3cee68a5df88e6c3d25f865df22ab77383427e73fc409cc5f24112251389c58d40dce86648cbb4abe34ca5aa1627202e281aa2261a37f6ab2e46856
+cb978aec861908094a865447eb1db7460287e2c4aade4853895eccbab40eeb427631087b3602286d2d2756894d74753afd3a82e61d33cb0cf748dc9321d7909abf4c362a3d00f1fb2bdb29ffe13427db353790f94629ff9756b2c3a4fdb544946d95d67f0b8e4253bc0272e7bdf1b84ea04aaab353a83bc2db356ef30f14d6
+ca7c6a280e8305a8874ac689d49c297c6a71fe61caa17ca8c1912701dced09cfc9436ec44c18b239c173e9f235e301a9aa2b23011d64a84a78d6f279e836257dee1dd4b6e44c92b06cd5a1a14a6dda6b7edaa4581203049333fa934279f0f4978f3c4508e78d348fd9f19ed2c0e7e39338b724ef376e351659dd0ced44defe
+1eae9b5e53a8b71726c08ba2660a50c5a2dfab6453d60d03662addd8aeac2453a1366b46f3d8133896382636aa4b401005a3fc9dd7722badea24dc1388fcb9ce23bf480621b513ee70e2d2cf1493a7a32343bf24cca354f6bda4ce719baae7d2563529f3026a6df7fcc843f735d1ada133f59f131053bce12b4d5f28bf87f9
+52034379a9759ea86ba5ae959d98408305b3c4e03142868ec2e9a7474a17d67964c115ab811f7a6b11425c1ca749effafcd6fe5e2cd8f709460902a2cb94111691d1f775142590fef526b3c7c12d0c525b7c95ac270a7375918c01b10bd5c0fb9479d4d4ec1cbbf11b893a6f78dbef8aa7e59cb014951015c89341c09e09a3
+e498cf9d17653bd0d93f4ff0457e499988e5109dde6b58d09491910869d7fd39d11a9d5223116b05bb766fcc9083f5f70a9d061d678c1655261b98b0697253b5e141a9d47d119384361241f3a1bbc7d80e6a454762e54400ba253cc72a37e27504731399a4d0b32316c32ca317bb22b4663f464dcbbe0bf81e1e0192c24365
+cca2cf7f329ea990a8657775a2bdea4773d2f61f4d0c75e3c5d85064ee3b042204b77feab4e3cfcb7877e8019c7a94c69e309c617dd1fe9faac9975e52cac77342e5fe156a5660abac1c3b4717779650c8d347322e8df24f47dbe690a78683bf67c01fff514f6317f8e52f78bfd780459818f32ece4124f16c6d43877e9d81
+e2061bbdcf8dc6aa52b9381528ea453ca9ff79a476a157cd2c5fd48f21421ae7d1447158ba806dffcc23cc37182a1ec042d8c9ccdc1457e579a1d07fb1ea4b76656e725a1cd26d675ba20ca83500ce9833da0c6125722f676c181164d442058ec5554c11ed6e4fdcbaba1241ff49bae20dce32e390bb0b50c2b815903a8e8a
+ffecc0676f6e5e86fdd36360040c9910faf0444df024d5c7bda00c59a4515f928c93d21a94ee872fe678059c8630bf7f81e9ae18c367456942f630c06cd0964b9684277cd2be69ec352ecfcdaf9b831dde441bc3ea50b8017590e68a79ba7eb827756e43d0ef9930cf498081a35546779536fba79bf3a27f05d32a905e7059
+f9f021026254d242c6660df02c95013c117c6d24ebe13841361d37bd46ae35e9666fe1d038ab598d9d9b390cb84f392160e25118164d28c6fd26ba993a34e9c43438f23f3a0ba3ca8bc64930ea374933d1e78303222529ce0e863b6b23e986bf56273f3fb30e0713e480e10db649efbaaf6e1639d350b248774b104e7faebc
+be52194905e54e132b02bcf999fa2467d0d35b913f81b23b6779ca937d80d225935e3c84bc5d0351789b514e08a6371a092a3745c36a6047173ee1c00f08acb111bb0d51ff4636fdd5278aa4c47980cf4782747aa0f5c48f95554977acd04e4bc95e9f3e57c04add8299fde93cf0ce05f03d5f795572892abf04d5e9350c9b
+d5ab7dfed8a30a55b73abcd420552acfe07a306333e4cee21e14eb790d3275e85af87db5ebdf952ce6a87fd1ff3413a7dc2ae3239f5ba51638e0ddc0e8bf8cbd73352856d0c71286c4670b24bc7e45f9e94afa897b24fb32dde0adad6edecfda7ed4ad98e2d3b3ab70fb48146dbbdbba0cd135c5eafe5a39edcf57ef873d52
+cf6924d2b449d199e3b902bbb475b7753ddd39f211a7fc6846b6d47203c4560a9b2304c86dc7a45dd5764d150ebcd4154e03410c453ee7e50b9156b7c1100534be5febc06046f1c2b7b28a17d1bc83a812ac100233b08daf42fe4130b7f650ba2e456f83c54b688f57fc4577dc2433aa2003dafa0390fd8d554e01b4863d64
+55e65dfdca016c9cc4df2749a736829211c192258e278f8e7b93089554647c545f50f5e7e2dd6addf75c20574c96f8182f102feead3f2fedeb26ac1dc75d93296d87c2983402551d21ec439ab0221a2c8be1f6ce0de9e44eef0a2e21f7471cc2f2ad9be8682b4f48e91aa07c49743225705e541b09015788e511ca78a1d537
+044e211b7b69d6c3f1e5d1489f9d909b08ad05a6488c79ab27578375b4ce7187646501dd31e0bcf7eefe884cb43ffff02dd9d0495f9c896bf2bedaa1fd88cf2f81a2626e6b9ff3640458b833ad44c6611695a9bd5ccbd6bb0f119d394b2ab32afb571a9cf3aa3119eb6b653d746dd90a8a79375474d96fc8bc274ebb15525f
+de953cb11a30556cc9c158f28d274a1b0bba86edcb16deccf8ceaad0e6e296296d3650eeb9e31977631147dc46b4ee8e98a8f2dd98dda6bc34160a90b0853aee24b31fb51bb9e59648d491708295e22c9428539deba079170f84a0956e8e6d85aac3218b2c0cb14d86af8512bfa0ee21b8dd8461716d539129fd604def7e0d
+64299308cda32c03bb63a5bae0465938d656fbbee6218080c3646853e30553b4b7e413be75334c607ade51b0111342419e48abf43a336fc56d27f1d826e3814376c7981dacc200a068fcd1bfa7e5466766fde52d26e23f05de090b134f6abc8e7891685670b646e3f08c5938c058a0d28463643895137745ef1cb9ec10d96c
+99deb3909b48b545d9f105e115e339543e058fef584a5eb28c465bce0972d57704db6b7a9a76deb1e0b09ef4102586e99c01f8e5b4ddb6871ee426e2b14464d4b0f9fb6efa1d26cefd389e7e3abe64f472a7b26cfd2d01e925e55d8e16b1a3f724cc03564f4b02a95c1159b9bbca97b698489861f971def07536dca84e9893
+9f49e1481e717384e4af2a3d8401434857c6afd424518f073a0c6611d0640b381c7ecfd17e1ffe8ffeeaf029991aa8b94814ad301cee7f9ab2f81471747d55c3bc61ba3de62827cab35b11c70f6dae3ecae2ac474b7cbfa5f39e382e979b63bd4a11de546c8be9b31773711b5e67913c18226f84643afa17b91d9b324a7330
+9a38ca8d98cb7f004bf1e9b587463cf9210a0a7ceed051573e312322712f5229a7a6d560c3503fa045a0682266b92c0136e0b3c29cbfd6fbd95c6c9c4be00480e892590bb12cc2240c98813283f65ed0886f781f520d36b037a7d08ca5513d4a90e4a883829999943f2a7fea006f074c898e7116176671691a2c95ae13f83e
+394c79c281dda817b542b762a39ee76e224af79c6a43776f09ec76604d3b4b240f0bad91e4d856e61011dfbd53c06141def0d1d0ec98123831c693cec547a0194ab274a7a2b9397b490f2dc1da0ec2d0c180cbed2ee5fe7e366070fffb3627eb8ef42eb9469828472769c2ad188584487254cd2af779be1f6730684cbfff9e
+e6c1b7bf5ac833e7fc34b7193f9d51296c0d719003471533da36f1130855177b7ed3e60760155c86377b20ab674b69e32365967e28703e3922b23a15b021091e07c0b75fa538090b235dd96be442c3baa1ea8add831b97d211c2ff5b3fe53f038a1c12144dcc8361c31ffbcbab2167a4f0e51da23642480214498125011a1d
+711771b41153fcf6b934c0c25c35d5dcd02db5349dd083518aaa14f32543ed076e9fd2ebf53d4e88892feca7b3a5189470b21d142b154d75e1ede154bdc78592ecb14d82c6715ba1624088c2b90357f3416c01b34397aaa942bab61df55396ec5ce23407d3dd3c2eda7f107a401017f232dfbd1b150f6c0ec3b93152c74e9d
+2591f3c6909f378b4947de867eba25f89d9e69de798b652103bad8bd49260f8492b622c282d635270144a12d58e0492713ed4609b1d609dfa57b9201939e9f18f524b019357f3cafd9f6c12679d8d9400475f66b93ce1135667370068a5b527dffad644143fe8741d56807e046368b91dd66e75a88f74637d0b5a59c04baab
+6dbf44b5b89e702e074d7dc6feffc48697a74797d773f4d8c960bb99344bd458751c4754cc2b4eab9c563b750098110697e586fd3b9c4bb33296e34de4ec1eb86d8974722e53559e301495d26c3197e65440582e5f54dccc5dad10a14cce792602c8c6c7c617f55a759981e358bd1d33e659d5c77cf30687e502126429171d
+da8c596be3395a78af1bd6cf2b643c2de81ba7e1e22078c91746a3bb40adf99553ed61c621e2b24387394f18a66d7caeb16daa0ffb60ad9b9d425090a9b6a5e0d035303b137fd254cd27733d8b67058685fb62e343f874a7941162fd5580cadad88c7608ac4487a0f14058a9196d884da3a1916d7079617213d5f89db244fc
+ab39c41bd7f51b18d9c9257b16ab12b8d921020105007a5b2d02421a34af52bcd2ddde0f344d50d90565119b889595dc8dbb37c9c9b8cfb965ba3839e735ff91f72374c1eeeab92d472733a3d6978840ed61465fe61979ba2379029ba59c50aef02892a39d8320113f019d32c34c27312089826ccc562fb970982fdd14de3b
+dfe77f5ae32d49c99adfd6978d6aa7fd7fa6071073f8f9bba55fbc95b54e7992b953da492bed8a5728d14393bab1f54e739de8c3025a5f8b61d171255e3517ef9e19314b8d107c6ad9d41f1e40ee4bde3dfb0efd4ab519007a77b0e023e08492a6de7155233d041d5cf7b7e9e82039906ddc523cb8810217bcc199925f31b5
+0fb6a8d47d3ebeb1560f5ede57d549b0763e0c67a40295b84e8ab7692d05c13989967e616a427dd96f4e077428125be951b10b1e5817cdd22bd232ff958c526d256a5670e3219e6d2a3ddeb6e1ab790176bada7032aeec3a9aabcc2ace9aeac918c01f337455ed11cb724e5e258d0628853eca184210dabb0c6ed6b95023be
+9057833399b78aa2aeff5dde3f0aaa2c2009f9efbc48eb0d9d4765dbf07b4663f228ed941f59a76d55fc9f67c07810748456b8e334e77e6d4f74277e9261d9ffc2da1cdd3128bf863691fce8cc48a100359b65666ba38069d3b29912546ea0a16e305db0d1545226c50628d4f6a08c408d64f2474eaccc41695dc2aef0d4bc
+683c40a3f0f94f9948d58efe7822a240e172491acdd6e8ca1b68f271ac6dfaf2e1705951485f15f8b9432b9a72e8c1bfbd0402a0e50bd3e71cbe8cf62503794ca877ebe9dbfbab545adaf15cc37a2a97d01449214036423409ff042a1dc07ad4882dd5a8d10b141153e451a4af2c2662bdc8a79061c9603b38e9b5ac67f5cd
+aacf5fcd6836a2de4d2ce94d9cfff1c2bbe4f98ada627d7f27b8d44b7f0e37393c19ee16038dd6346f5e7bf07e0cd51f3604732359109b8996146c40ece11bdb91c86f4b6e7e74d8d8918b625705ae75ff05bff1dc185fdbd897241b0b74d37591875cf7dffbd6da4a4fb3bb516e141f0f7ead76025343d328965e3315df4f
+56217f9f55afbe29bb5523ccf7ff4aa3f42889a5f3e85a7a22f0475aacc8c4fab17c4443ae7a72024749c5a40a5bf8c82b4f58a8c09f9a4ee0cba8f21f1e178e8232600a43e2ff86c61c5982227f95c93cee2d4674058d2127bf050fa113d478cd1485934eb9e37b55aeed7cd56e4db12cbebe8e666f679824c09ecf92aa2e
+09fc84edd85473d49de862a62f78ac63d87d53e61dbbe5b74932fe27e2b8fb73d60b154f8a456bd2f570e94ed58bd8201e460eef859d800c58c3b59d8cffc122d6a334d96f52cd88491ecaabbc25b414fc2b9efee56a0ba1c673151ff35de2d810dc1c7b0f9ec2c823a8b8d835210cdb55cb2e959533ee6b54dfda46722d85
+e3794c50c5c9dcf1dd618b2035e8bb8f0d99520a9864f2e96021aa1db1aab35f3e32e45c0bb457e5e117f313fcfe6938b9974207c10775f906eeffc4176fce43c79cc555edb26dbd02c54cd3df65838b6ce17a6604ac71036e882eca31325344fcde4371b928e47b55595bc299827908e617bb4b82e5bcd954c439c84fadfb
+0bfc9cb00ee1e5d41dac337699fa4c49b1a3d2214aada8a7dd63dfa83663660094d6d753493c1310da086f069ecac792e1e8598850af44f9719912be8463fed1d7ec2544245f70b1833d1af7114596ee3063e3ddaee634022a6fb39a0a2137681fc136ff3a21ff9d032089b9089a7dbcacf55945108f30607bab327a9de8c1
+31d1484c2463a8ec2e7072a2c0b14617e2bdbc332113a1f3c5d6f680af024929045070fd4d49f1d12015f8049a449835457b4b9eeebf04ed5f805020a428d607d7e4b8c8c406ef9faad69fcbed1ae04e4d69eaaff06b91d73b6aafa2f6d5378daccd9c6681dce4383e48501681ad611917f734b3d97174c2fc5c32bd3cc987
+172ac14aea7ed03f4ee707ccbfcc64b29d2909379bd95c96caa59217e8e33b6ac95e1218d6c3ebcdf6479c7f7fece2905e402a85df4430e44fe77e8d6ce4e4ada1031482c5e423dcc6c1a7b6dcf308b2f5a88e8c617acd02644ac99ce42beae85ab78473d01cf6a4830e8e83febacfad50fe475ad206654e567d26abf4766d
+cb8e75a9f62aaed4cb0d65d6af505e05dcb6f2e9b54f76f2f40f6dbc25b60d647d96133edeeb0673f74bcf1a3bda8c9c74f92f7f3f9026ee2b84ddf074d5b0d305d45253a56b33cd66b515e4a747c2ea5b53956044bdbab253d8a52fccaf0d6aa108b793840f6d0daccf8839204daaa69b3cb2cadfd063417168cbe3bebf55
+719fc878f02aaa2cdd1d32ee97747b5f5adc46d13d15e986360ac7991e65075b2cf47dfe8d35c9d47ae8d20cf5fa1b235852660722e87179910378bb654f214666338884eb2f0bb7524bc12dc072cbc192520c7c62a193b5649b3993578d799eae9cb034044e93b61f80946ec63ce375443d8054620fadb5d3c894f1e15b13
+7adcdc4de399976680989537b849876eeaa2b443433a4db069e42eeec7c596ed6bcb020dab6a476fd5aaf4c3c2a3bbf301b249f5a0a8bbdd54b328d13f6f930f4a0fee218be4f192a8854fd9ba70b99a30f1709988abf51cd282896a4542f5835ffa7b9188cbdcc381a9400911ec727fa7942d47405a469f09552f51a60179
+81a7fc216110b492662e23919146a0baee38a5526705a1434306031d4914041964763c55f4214b07a5a43bf6917f34a7b00cbd233ec93a2d4500a601b25a0b215ce4d6405e1aa53a459e6e4ecede606ec4b8ba535e27d7df3902f0517f6eeeead89841d1b32095348bb19178169740fbfc3cf2f8619efea7dcbf4b0f95a4ad
+15939056f09a9eb4f79783d82c2e18a5686eaed7ff7381bdfed64f2b364c0329745148b86911cde3e293f30ae05db48637bd22d0bd8e2fe5a236229213736068513b9c8e691f7b2a659495c81a6b70774140c628586d25588f3e6d16434ec06c058fba057b593151d10c869f55797d313e06afb3fb16d01c4c291058e7583d
+6398ea0cb269ac8d2aed9c9b14b5054cd1410d61f4aece806a6b3cb7d6db1394153b6e46d755c148b7f9a923db78a9ddd36df5dcdaa70d40c12fe125935765ce3297a24b50acc37cd98d05b49c141e19c71c55b9a807a0788b79d6b6fb3bbfc4312e76f50ca414895430419ada545ac3b632cb9aedfae267e75fba42d213d6
+50ea89afc6259499bf1ab0cc9cc47e8a323ceaa6018b1f14561f66e6e450be7b99ef54b39eed97b9674dd6ff5967b450f3ea40f26f222605a07c5235683b8709165a57324fb8b68b0b328f083505ed8f18a67be25c64c5c837fd218f85580d31bc4a88a296a07d0f8052f86944fceb8492ad0baf0bd911e927088853a01ff5
+a2fdbecccfc31abcbd7f50dd1a958512bdbb34a0df4c08fa597f1e736e3c118b2d1b3c79f199cb3adf45782c514134ae761e0b74bf3a1cb791212bd92b5d90a097425ee12161e0073ae64eb111bb2443fa5faa7b22aa1735a4eb83dfca07c7dd90aeb8fbc357ca7af634dbcb9ede0751e9196657ccecbfc8e5eacf760965d2
+ca09cf01259945f5fd92f5ccbe2f63bd939ee89f2eb4bf6ffee83a1d04b6fbe2676f5a266d06b7e9d762e79f280f3acced9672c9dde6aa50c68a4627c59abd96460a3839f5a7ef734c1021f4aad7a481911e71ed9f8c7fce0dde8f1d68fc7d2ce95947ac080378954246b8a09a1c53c11111323b1f04ffc08fc330ff65c590
+f5b186342c0618d617c9a9b3ad4a58a37fd8e2f96d8c7f8be066eaea8db5155607b6e0678b9f8c1d20100d4b1e5f8063f90484747f5ba080f40cc0ab075e5b6605a296c1effdd9a3db89b9c564fa2e5033737d084929ec3402e5dfb594b9c69e57e9aa53b12f242303ec7c3acfaffb3bd4a23718a5b4ccebb09e0c4c770a7c
+131233f6e402e1fa7f8f9fe3b8572a7fcf5074735c984e4d7d26ae626c609ffec1e1342df9cd6c2409b1c9dfb7945914ad4571bf97b6ccfbdb527f749f09c1ceaf3edb56f06e2bb4f75a99f35145fbaa2604f339a095e734dc504e3a017c1a69c0f545d61a0b2e5eb476e64ec60e7f5f101b6d1c2039c58a383b337d57b31e
+49bbf407c98f2cb09f45bbf07c9f6d43636f61f6fb9cc72b0a1e66665c3bfadc795b274b28c862fefbd8c9df6415494712f4d39b6c9e8b6840ff6a53d06c00b89fd41bb3155c38d873e9da1fdeb144c40bed42d56b7d9369f7bf4edfbb9a7335cf9cd8f9dd7d1cbd555eb8e0dfa95599d3e8cb39852de35f3fca0f6d1d24a9
+56f93f4fd1a6619d112f30822c0a7fe9c2c844c5bbd59b6fbd8a056d88d22af574c272a8b0be09d988d37472d4094585e837f36ab119aeb02b9d3b4d4454f19f755c41dd926a4856bfa3c2ba360f72ad13e8d18506e30a9b01b83deb9c89b09184dc68a2bd29c54ede5444c90fb369e0ca546255d1b25a97ddc37092ccaf79
+8a4df6ae1ab1f6fe5978f58ab0f12d3a18253a661a527db5e4bb6b68b35ab57f4d351b0c3143b6231ddd0ae6fc7781da577a421b15c9adcfa0b7a850be966de93ac1a1e7f0aadfb026d2d275c3d37604b2174dd3bb7982ec4430122462c21591313e0aa701a10e8f580712abc662a71fcae9baf937b67c16195c040f02aaf6
+de17db5b302c189eb0cd7dde487eb7a897a006c5506af24f65c42d639d82fb78499b8c6212e32e14079c420c86ef3f0acccddf7ae63921adcb7f64cc084e6aeaea1f5c0b2b67ff411b86c6e788da96c68bfa68c6093219b2d9d80f854cb946cd702d076ce093e5d2cb2943540a45d145c0e22c52a3dc69ff278a46751e1ba4
+db39a4c5246714fccf80a49a520d887a8f2e33f5e6dec99cb3d8b717b95ec797b7f7ba2691485154171352c4d8d348faaa50f72168a0a8ac4922761cdac42e9f97305e253730d6ce6bf2e72e5c88b30d86e9d0372bf385fd5864b4aa9b492333e0eb6d90e194fad705b9a9800239b53f3055eb976d6372431e9694c4e9b469
+6d49a3e4182f09e34758fb925efa2e6b89fc2e7b820e8ff605df9446a6960d099f014a2c541950a71aee75677a871c2d81ecc8654518e3e13226dd0e7ed9c6e0aaa7b2be4c2af2118bd4c3058e0ca8d6043eda24c69c3751524493a1787c20c3780c51230fad06300cd2d161906190ba01956b4aed0b0b2b1938d12bd12c3c
+6ebcb75fb6e0ce53dc25429733cb2bc11542715ddf9aed35302f942c9ac1bc0ea1ee18a4d1b09c32a7501c45a91881b60cea11ef61ddfe0cac4bc73caf3a8ef7a0fd5c8e6bcfbb81dc0adec060503519b151e1a7504a53cfe8f0704044c4cbf6a4c06eccc11f7aef476aaf8319488be982467bf55917a403726930d92a240d
+c3af32db6f83e06f3964f8b22329b7eab6c51b419ecacec0cb45e82eea7af08890a85df3dd8a078c94352cc9bb22de7cfbf06fdc59ce5198d62138d563c5ea959d6950ab0334134c3deb6b78babc9746ef3d66ada708edcc4f70d20252ea79b4c195e9710f558a60b0bbf28ff9d34a400a76ba580cbf8f2f2aea376a82d740
+22bb9ea003a3b5962948ccbfb92574683c45db36edf0376cd8a5a83c9032044e23f695d700014054ad65037a273fd8c876f229902e4b64d6f660d28e412276cad4971f1927d85f8c89e7c7afdb59fc341aa415e83d9fee5a0b9b2dba23b499a4593e564758333700aee0565348d981cdb87d394b5bd72eae7ce76c4208e044
+9cea3a959243051bb44583223bce68b50719a47f783c9705f461ff40f40de2d284bec99048f8b9558b5aa3bd55771eb45a04d94555e6fdf1be530c1d0d39b8e112704b41ce0d7f86540165aa9dfcfc6aac9e2c1f1adaf871a937aea0b5cb6ecdaf64042d33e4b8e67a8e27ab68946c23a69703eaa4cdf02977273b775e7cac
+1071ed89fe72282620873c5c8f501060b6a5a4478f43b19f63833372b5a45b0bb8ba292c97acc3ae6ea644c0bf01565c1a4324a6ef5420dc3b1058c186d5b373ef3cf7e5606b6fffdeebe23d36a634f3d5a87543d2e79b7c4d56c424fcfb06629fa126e6b5b7efa57b809cf83cf078b13ae067da2f9ca4e17c43c413cc4db0
+4865b15989d63481cd055414b4d35abec549c0b8d0ccc748d0b617481e44accf8136072a0a736a35f55467fb482d56d5c6115078eb2fdfa1b35d9262fe7efa40cbcffa8548463afc1bd47062a66598269b4af1a3c4ae0bf91f759b9dc51cc18e9205268436b29100e529424aec36e21b34c5b1a81480115a0fb0abc00bf73e
+b90761bd52b1253382752af2916ea7a938e26843ee420dcd820b5ae0c32f3a96c586e3ac08b55adaa81f8887410a7e4b00db81f2143c59074627753055bdc3c7a2e6146823e7dd932bd4e4ded28bc218ed865c9f8d7a69c760d00dbac27bc455c254d539066ea5551e2654afc675cfd2e17acab2123ab0c65e3e99521ca52f
+dcb7d5c044fdbd8871d447e395e1de2c9362e8eaef9065c1176a1995d70020318caed30d4edf4ab45986cd3e7cd64d57783523c3b892d27410a3d4bcad5c01a0ef6a92694c9a98b7c040b2783f9a1074d9e16fe6853af21d2ab3e985d904a0e04749565c956ec0ca450c67e6f826c4480c339b6b732909db08ab4550c0cd80
+5a585b9d3c52673bbe79f23e0083d1135030dea216596a2ca5e2f4feaf6783238197c21dfe92075a556a793d1aac9d2ebee27da1294665ea9b1edb71c15de79fec422c9d516511315742c97fd880f6717f303d058ff1ea803578291eecc227366d3361f08ac7ba33c47ff14739421098d38eb1da367104667607eb192cc561
+e8a80f2ce7726a65ed75f5f0c0b18bbb676cf82a468251d983352bd1a147134294762579018705cb98379c606754bf75149dd2e300aa5ecc8812edbac86a622cef1f51b8cd2b6cb8bdc081f730abbcb33091d4ac5a90d183e16278c69192247db4882da8c58b75dd93a77ce01fc76f55caadaa7017f91c6f4b2e2e7a3f0bb3
+f0c839f13d73cc8d8293bc981eb9c5866b9a3b1534c064384e1437023528fa6e6169775882522275040c3e373cda0c2743d078d7a04f5d29b622ff4e55c460909d18ed428078916824488bb49f197ed81d96b67cbb7f36f03039fd1d9bfc5b4bb7091c6584fa240d6d706d43f68c1643524cb0ce831ea345309574cab2ee1f
+bf1567a9760e4975b57af854ad3f8b95a76718a01d1a5fa977ee6f7d41db653f822953e52cffb8d914143b7cf599e4935b73426e8d55eb7f630d3c2fbf03358cd08fdf9ec23fc4b759455f5ad2936344c2cb4709cf5778bbe53c42a2fdff9df9494e08c26b099fd64e58f06b7b044283b34b220d6f223ca0765396c432a3bc
+662e21925679e63e149ea48b0a3591ff9d03a973b74fcf109ba19483eb66187a9556df04bfc88980079080025539219b580c7f7b6f85595f017729a426a4c670ef41ed5570c74b1d6dee3c1a20d6dd4117737519fe81496dbceb0cb6f54326786efd14eeae887cd226f7398a3e316d25f52d5f37b323828d416a50517b6e4a
+e7dcdebe12cd7ace92823aea4e3e99c39b2b45e978f3e3d4b68576f4a57b28b5c8e3a9925c600cf28170750cb89793543045690d32248b9ba3c7f592cabb34b6cb49fcb022bd128739dd758b432a5ef1bd01c110e6ba2fe7e90c8c3aceae45189eddac411090e34ea00b76969ec399e84948b8b317af70d4e8e429e46fbc8c
+ee535d79e72056f14fdf84bdd95fb6f1418ec8cf97b48880f7f91ff7e7d12f1988d8d17d70176643d880a2ce377d27f9efcd971d19dfa6b8f17ab7bc4ef1a90192c5d9a21b4bda44adb6b2e57933a60d2f7f44679ab7f59f86530aac0813920c24baa47e3a8cc1e6e2cb49d4968668564624e310230851723e309660ef3ded
+dca8cb501c6ba2fe14b086d96344fddeb0e209b7877d7bd5d4fe878cb6082de69d5d5f6d516a06932aaa40411633b4b7e3feb851f94394845c661074094cecda80d302d2a5a7e9cb683b9c34fc4cec21092322933fd6bdb6835282ad8e20e0c46ef3601704b4e0153fe1a08d08c4846dcc8d77fa464b899b7d3c06be15dd62
+7dea14d40c447fdc6f80a18a1264c480895d8b03d8e660366cf34e526451f0146bfbd5b34d8f85a1597f298ada965187780d0d2f280889b50c00d18e4ea710c1d03b361d0a7b4b9a8d4725dd9d92a40f8b817f7dd7257f2d15795688d36ccaa4c5ca2758acda97542f24232bb30b92d4f4992d788c6904e848b5ffd60d3e77
+ded7ea6165f84978c879f8f453710bbb5d19198b38c563cf9670d91cff10d6d381172febce3335bd186995e3673e8920fa73b43cb5fe34d301ab247e9fd7f795f67b2805947ac022cfda235665598aaf238b887cf84fa4cbc8214fb930166fcfc30a921c1f123338101d1d1679ecb7bb3b1e51e00dafa82bb986f9f61406c9
+b571aeb79066a84cdcd6cdcfd70d98bf53799a1a1269a888ba4c24e470840a498f101764f5d92a5d6f575894bc6be6527ea89f2b0e387251c9c8a34af1fb6478f49a482de89dfb5215fd77bcd1dd94ebb068b062a9992a4108f3f1ebf313440394f09fb2715d95c9e995c157330702fcac08a1366d675630eb6bb8402f8327
+e54a8022b1409e5594c3649ff14443058e5a0ddccb421ffd1697979a900d924be3c6f7568483802f119da1686738079b96e3d6aa432f9c2eb233af9d8c0adf1c257da8d5b7ee0388e51817fe50b0d7a5f9dd8649c3f8283ff52034f2e6828436b9b29876d9ecb6fa0a3cb8f861380e482bf56dffa994f7225d3d1dc03b667f
+a65ee3a1298b8ff5f5315abef5de514b3f58cd2b83c28aab17f8581d146fbf9e248f4eb056f01ec41e689739ac72d6f055382420743fbb279a1f855121511cd17971580ea4b1a809df10ecec464444acafc6e7e2d96014198ed9bf3a891c61d71db5b00d451550adda9c225aac412be9aa65dbb1539c8918117458307cf0e3
+3a50d04720b30c752bab5774028dec340a53c9b9ccd62d6ecb9142fd0f598a4cf4a0c26c8d5f7e5ec8bb283d13201a17b449cfd95405b1d3b8860aad3796fab1e3a3a94805013bf17764cc230a97428bafd855b045fb04095783a84908670a6dab743a0d3318270dde32fe787fb352932e219cad6e02b6072b2e0f69949313
+c12f95a256c71ae06d285756dac443fa7a6e6332f640e48fae5948b4528a1aa9947825c8ee43ca95b59b0eace71574c07dacd10c01916fa61e3c4904b5baf81ddaf8157ed27600b1f547efe0b17478a90c4b41f139a427e06a4afdaea2d49fc65769bef1b1a31d789de62f6f657eb1819cc684018018b1bbc0e050c0f4d074
+f176760a6a834dbe624c63951e6977b09bb28c7f928c787b01ae8101b77f022617e010e2a13e137468a7dee42d2534eeddcf7b5f377f621e3e653f98a964da7f375991b063ae81bd4586b89a5559bccf1e9deb68966857375a3f312fb7f595d5f1cef91ae58bae549a5e054b4c247bef7bfd3b829124e3e39b6993c9f168e8
+65e7dea0b0063052efbbb22b01ed459cd09770b71ece09a6a115667d9e86028ce21c696ef46920c230f478ff62a4fadd93bd3dc09e9436141650b6251e01259fcc48800c883665b7ed6abe106ac781f96f5913154eadf17a95fe937ab883b7119c03ed1b77210646c088c0c569c73398ecda80aafea7a07dcce9e4b4119859
+336ab79ddb8aa826afe882b6ac8549042726aaeb294081568aa220e6b264ec8333f1363a848e965c913c860d8f468b57b2e963a42f28cbf4871ac8419e297b4bea4ebbb9663ffa1fe6159250a214c88258756d90c83747e84ba9555511d02adb9bd5be7910763cc502509a2c0909ae5adb592ad760dadc9b5cabd6b5425e6a
+dfca15a0904ed052af61e409d77976009a5b9bc2a262cfce4ea086857ec043c20c8129e20e5649c838895aec54af9d0bf4dc6c464d9b6b67b24667e6b36e699e135a92a51bfa85f8c7e530a50641582ce89baa2d8596664e83d2d52f55618f0303d589b91ddadda7b87fdfe331a88a7dd29f47f00ed3bf3bcc8021cb63c90a
+802dd8dfc62104c58df37b0270ba95037b82402a3ecb6898f1474bf51b91f97c420e0c517f03b61e3b6544856c4bb4c5e426e167e314b4f77323125794f0786ca00081ae0345ef0075ad9a454ec3b38add9ef11c2f31fcaad866f7cd5cb6d20d07b514795dbdc89f77a00ab8af90634a3cb8d31bce450e8ce5ef362bda0b3f
+cb25aa983c21fd82a4ee68a45fa2e5c1483fd27e02455142371614b5633e5aa22b2dcf4607ec925d60a461c8598a8dd4f66f7d8f274f11ef129373624add11a097334630e43873a9eb99ac8495b0dc83dc20d2756892ae42b6730f228ed47b7672cbae329052454b1e7e0febb380adc51ba89d0743c908c263f1b4b60e4b7f
+4844cc8d24c342b8fca2be5395ede85f872bf99f71d9289a721719b48eecc37d16e512cf94e30270e592d2b9ea12db08607f1c3033b0bd0cb65a045466a8e454e2d0b1d619b6767ea791a5022f7caa72f9568f3244f47b38c2f3ce4ba191c09cfaed4d6777c6c3fb54e1b45f272e3cda7c94fa8a23da81061880beb0925e01
+622d6a4d1ab1d637a0e35a27ed1ae46d4501d511b3e0616e7f4f791b9fa8725d194aed5b0496c00a7c87f376fc5befcd54375d96c8907c58ab707c6c004a5d263d22ca106d6744d8b9af3fecdb292941d00646ec96c9e9b4c75eb7b2c636d5a9eaa7e209ed2f2608bd14f54a9f313c7551ee688489699f4f523d427fe02797
+481e69dc8063dffbec8f76136a32dbb93ff555f631e54a21ce87d2751333c1b5059265c8715229a5fe02fa731ae37a5b7dd0142f353b4434cb1e693b0119bd31c7ca7d211703bc1df0bcadc6a33ae167889d8d6fe2a22884766546911956febdc6661ec3ffc59b4fcd0fa7c3b0775887f251f919a35f941aa56488dc98dc62
+5ef65019913809e33e5abda90d4fe37120a4da79d61e3676cdeb6f895bc46e012228bb306beef82e2e6ad40ee1da4cd8dc5919e626c31c8a3e6754422f35770fee9659cb742cf8f7642362fe2bb9752bf15158d6d5c67e42b617050818d1709629475ba093335c2687f3cf90a04805af3528211dfa3c9ac93ccfd78cf82abb
+21c8b717c5bbe37d6741acf7b2c17fe0ff1ea23f9a538f0aa76d89bea204b5d054f336551779300e51faddb9ef11b680d21a7430512b5ffc9ebe6d684b3bc9cda6025e9ac6460c51f374e36d4c35522eb5176697c2e03c9d213e12ec32f1b7187dfb4066c3ca80ceee0923c01075fc1c9862a206b45ba3021bd7f4147fd0f6
+bccd893602d07fde9976e33be17bec186af2870e312625f9832364613345263fb4d98813b39dee77cccca0410613f7a9f538a70131245f6d1289ff2002bd21994253d5f1c58180c1e8a2b8fa5fca661260043c7a9d5d8a525bddd960cc9e158d6cd58e51e9053800941fc906a4bb969f096196a48c100b7378afcd56372f17
+aa8deb5c891ae09bd79af8b6453622b2697a84d494064acfe74e09cee528dfe3b218b96f0beec9d41b53f6e648705ccccfaaf72eb00028edf3d4fb0fe4c7633bb93999e2fcfae53ff072468a8ada44e0090e7dc3b5dd4fa284a936e72e2f9fc600ef23e24364f2c17ae8ad548b4e19ce7082be7439d9e948f31b939d0cbca5
+21a24ef72cec3eae0b3bf708fd3313c5a60aa5d60defc56eea51508fdf5c02a366d76699ff03d5e86f3451313cee71c3d7413c441ce9f00b2bc5959e0e2dc4e5288caf3cadf7f4af729471acc283d5db5cc63dd26a6389508784c7320b6c5f0e48e8978070cbf418edb7ba5b84a28aac19b345ce4c50a1f066413c24b5df9c
+1fa9d26d73749c1af1af0eecb0d7549820cc7d3796f15e98e1a9ec2f03dc864f6e57a3e7c6e714e170a5aeacdf02a02279fd4c68b683c83192ecd3b459775c81acb661689e65542e5466a9524a03774a20547758d5cf86daac6b0fb47b4eb0ec9d007645ed2a3a1282583789c5c615b32affc5085561091317cf53e64d7d9a
+688f5c61608b042ce2902af5cf42c0799e35aaef0a7b2da4453135a8b08d9d051ed73aa1b64388c8469242ad2fe61154d3715b4aea1cc9c055824c28a3aa05cec976484569b3086b43e22e7d656bb263f5402c8d6509f8e165589098638b4eb466b85026521d70bfa96f1890ad481d2f12ca27fcb75ad53138a430232f5d03
+b68024be7d4063a26fb5812606d295577a1cc0d642536882b16d70c95a69027a8ebea67c2ed63fa51e5f2687e35337eb6afdf9ff763d6b7155d5616d1f66df53f264ee1ceb52143cb481aff34aad961beb6a466f011a97906f7235ac1482b59caf4f35bf10c106a17849b9eab63dee84e84389ca872f0c55f9c88122b6d6f0
+c758d0dbb717bf7c66b04db20b2ba106bb7b51a01f4f60a45431157c3767fbf164604167583f3ebffa0d874d78e54e673d922091584593f45c0653eec563a7115b497984ade01c733126c968a156d562f14b9d1bc3555565f84af0cbf9b67d390d1eea546bf8f53abce45dcb31de4e15aecb10c71437efc777537e89c2d906
+249d55ac4d17fe2346b1b68a1696953fa4484d0408e2c8ca96d0b6a04bf78cdf672d99c3d8697a6c388c31bba5f487d68d516e0f5f9d0f71f7d0c12d9030c7440f3f8219d1fce3cd87f1ab5a2ab38288b99f98253a648a350bd78bef72ca7f334c1e92a2cf4f274827648efe4d4c986d6b28683878990269e0d695cc93a18c
+7f8f64c4a1a89e4568e43c8e0118bc039c271146e047511ea911a4afe7e01885f69d310c37d0ba5257f0d1a025dc9dc32d23c9580a0ee224ed267bfd6501907720b19126f43b5844267e73aa9ff473382388810eb339c7ab6766fc56ccf74caa2a7c0d66294a6c5cb210fcfb6232584cf7016c3328c54295ede965bf88a6e5
+e0cc3d5bb9e023da53ceaed73ab6053f58f0c31258a1b74c90d2402dbc638e4f7e235c9a81c91adbe55f2e4f9cf8de445a6fcf0c7f4d33cf5e7eb89fb1fe6bf6e8aaaa3cba72b90965807ec54d18617b0af0bb4a1308aac8e957b52e5d395f0831f2906557f1ece3c17063cd73e1c31c50f2e2f81aae3412be4fa3c08164f4
+d8803936644a984eced76fc2fd3eb150d8f5792bb61351b84d59b9d01b32391848c87932d99074424d0824db25a0c994646c66115f9c47ee44477893342ae1a7b7031ce6d859470e583b8c75e71f34463ea780c87c50db3623b344013bbb98fc8172fe9018487921ed239a9bcb44acfa7f8a69fbcb6131f883be0483fdaf75
+6bc76e3eb32e3b353272e9d8187398ae8114e6874319adecb93bc38f2f8c1aa0e10ee71d69d64f3a149a7ec6a80663d80fa5e2253df2b2b4489713f10c337ef9d480854742234e6b715daebea54b2719546999fa791dcaf99c162962a488a0b54de92543bdd0dc09ca49ed58afb252476e3933cace812e910ddf8d88ff4a77
+292928b547a23ac37e2fdcf1595f6183c6b69b5fcb4af16ee950750819842d44457a4ecfa9b0401c914116ad58d5b73a4573d22a029c3693b6ecb62e13d7e788181facbfb7ca5dae15be9386758149d49a3565af847ce37e8b9f4f2b1c9f3da84b4c6fe37d03479da226e7feaa71fb1ea7b6ac7fa1ded0f474337888f6df18
+1f2adb07179da391f95b5663712ed86bcceae06626b53408b89a00e9ab7d97866bec9f47fc4be2885d7c5757438a886866500f803d0e228ee3e5f83287415814e0525b5c12ccf748b34fa769bf76001fbcc764bdcaef33f75a2fb1a064f9893842385111a6116879c29686939c8682071adbb78c6f7c28e57ffae6568419e2
+6b58505a631092c46b49a64951e05d0be79d2034598f03587a322c214c064413810072f4ba8cb847c9b1a6fef06a55a2dc915edff4308e911cdb1f1d09ccf9be8481a014670dd438b17773d8cfa065bb84aaeb476a5467905da4980b7a1c9311fdea5b6a627977041bf74aaa1bd0b239455118899f53291a0c0e4b3c8d0d58
+f01ac3c7fac9530025720609865d9f242573414f23a4c184884cadabfe4b5409e7ca3e607a1ea0868217e77f404570388cc484df144649a0504abd9e8c06ef4e8fe3ca6863842bebff55fff6751dd3c17e0083b9eaa3bc6e5ca60fd81f82fd2b2a662563a6dbce2cedc61d270ee9c96b543226f900e720f0c60b784b258c9e
+5499f664312b77d1e4eb6d92709c306f796e7027228be42b5b900e414736aa94c8a2f9b8a9c5099751b720a0b1417ded6fcf1d4e091aa8c3e474b7b111b1e51c6caf82c8af141d425e65475af041335ef8cdb22c4816e0518759982776fbd91378a2c98eecdc23d36ebb93a6af735e063f9f0698ca7a24a098b9fea98f0c71
+c8abd33b6df1bc8cf2c1f387aa6480c32b978b31a8e72fa9724f7ffa07dbcd1058da143c6110ae8626d427f1efc6bf7e61d98c79b860e468aa22c5dbad1db9d6c81c4cd6c2c0ffdd78ec68b23eb64031b17725b6d59176340fcd113cb6af9ad9825851c82dac499f01669f541364a978ecbc8f0596b218accb1b4fa860130a
+2cc6cc108b71d54b78092469172096c9d3d81b502f747355cbacc6747573b002da8d63a30bb08be6565e77e6f8de66aef8c388ba228022bb054d0c6bde488fedbde7bc556e29ac4f6c3335597f5379ebfd24c3e36cde88b49a4e72ac4980da7c17a6492b4193c04827e3bfe7795107e25df2121aaed1886060640777d8fd46
+dafa1d4ebe76d5d7b45f8a6a907e69cc66d55c38e7a3071e67ad47fa326c3a6efadf5aafbb5b76eb4658ad84d52d563cd5e53a4558085af5005ad11036c67f96680d882d24a611fea4cde2fd25cf6c925a94071f4bf6ff3322f8129d8660a73328b20287bc2e80157fcb64990b3a2ee994ea93b4666d2968b9624902e9366a
+c1d297b2b1c71b2a03c61121bd42e8513960ca64d54aac073b72b965b3d20f3fd355d21317eb15698c8a8b9a4f84f8d61040ab20b90bb6c82645f7d261c825e874f25a3dcb1f10b4db4bd43abab67b4b7061f419cb350c923208e8ca8c65398a7c7928209fc6abf82d08c913f9373fb5faeff071e79ff75fb7937e5e276195
+8b37f6b0c6c17462fbcc88ddf758bdf1fd344e36cd4d6947a6ba2cc35c0a9939d36cce7683e58641eef683ea29b30e311f128f695950be5e83d892a004678ebde3c8f8d8d8916a7f12d65ef50df425196285b0be8ff4b8b939342dbd843e3cab919212178e2fc5c3627a225e41274485dc7f28e4642410382a5c92438cb4e3
+2ddc7263e3afbb76362d6e9542504dc427950df6a80336d76165d5b93774319dd6428f3dd5ce365801b75252ac934856cf75c69f9dcdae1209c6c2cfae1f139911d92d0f154a5d5f21c00c0cde4ba030af503e424827c1b7057399e5f1503d170242cb3bffa736f5f4966fbeb8c9333fcdcb91486800f6d13462bdceca6282
+45abddbb1cece414f8107ce640512c1360a01e8784a14155ffa9be5ba9422312bf08ee622683841bb42f561188876d072be23fb02646e63161119f01a691faf0655e6875928f12d461d352ec5018ea94678f74a18bf610d3080f0264f31b6ab50741493db8c0805037c7308954b2657b5d3c2f6f982a8a86537cbfd551cb4c
+4c1bddc2ecaf4b800084462464c52380b756fe9d323ac82868f0b476843b6b12cf7888d7e45be3fe8ab2168d0a4b9cf1a9c82d2c53d94097dcc8a9c95ba808757b8ad42bdf4f525419a27d16619e30ff31be2b5464165507bf1be59a66fa379db86d16ce98c6a95e3d27825fa01c90d16c88ff86755cbbac54579b637e94b1
+e8db989c65b8b4af9daf4e71d15f75aa65be4e79a9440a62e7021bd412ff18cbba097a341526d66eb035eae1a541db3b21f5cbbc4b8cb2c4b6f0e5e45e0927811242e0f4d2863be6933bdbb87179f354d99e899e3e1d010085c50c59d23653bdf35e881a9ae4352f176e9938931d724d7e5e795ef8e8cd2b47cc8f9eb253c9
+02591b57fb345d48ae00d8cd5d8fdd82db9b92ccbb66d9b4f89d5133abec9e5a933f89452426cae8c2bb4984e64f6790f410cc4cc113ce680fbd43cab83886c2a31ede57811e61da4dc51c0e9d965f36a45983041057252632fe7e38a20ba5fc66bfb02349a1321667c6a07f6fef33a97a8e2e9f3e3348c8fc32f230fc2473
+feb6169e1448deaf125ba0e0742830bcb698b1f992d1f3a07a6bc286a52aa03e65aa72b4ac989951e8dfa34c6cd1984f180f7175ed611dc5ab87303c7a2961de9bb50dfd1a789b6c048b3bff4a36cc8756007ad771d9c09d6ea718a6fc42618f94e619332eec80de01d30bb169318a19e44fb6852097238d221d4102f76285
+cc3df433b21150c0f400537aa52056aea9cb5f8030c5e5b49d8210753f5926f6d85ef9006b3ebdc4f66f4b23270edc9663303a27abc38ef56020b3fdc01716585747456c9cac8987305fee9786bf59170f4241b38c1ad0d4294b84cea35b015bf52a0a73f142d278df4f1011c8696c38a2fc0867240a5190a5730a582874f9
+fe454c49bd989be6952ac9bfd7d219d718d2d08547defb57e793e339bfa32a3e44425a365776a1df8e568d1b838855e826f7822427d99a82f19bcb8aa14b5ecb6570fa85871c10e59c10074793aec3e0e22bc98d709780758687e5cb818aa59f3f759401c7a5ed92298d5f59b74f6b184eea9b9168c908609e1d8245e44a33
+727679c49f9ee78371843ff1105bcd8ab15a1bb52926bbe0f81dcf9666299bb89f3237e60077c5bb2fcff808839b3be0991161f62794929f9aeb5e5459e97e24496f2e1af05000a6d12957ffadfde6d6d2bc67404f04faec739caabc9fc004ecb08937af3a110e3d341c7d865303c3741a74e02c937403137a4f37cdbbbca9
+24c1252efabdb73adddc933bfb6d7eee605e79262f98d747d4f5e62c0ead33d2778c1559889ed63125ef5ba53b6cea71e9ee844101eefdc455c2d11dc6d1252670124a168c55fd43aedec416ed01856344966e70c89f6a6f372eeee25884bf84d52d563cd5e53a4558095906115b7b6e942ec369d377d18000da1dbe1cc4be
+ad068874d9222d0d3a3f266639ac0466fc5f6a672f176640b42b761954ad82a7574fb389d0ca69c0715c30e72b37d7178dc2b00092c0bb689b400e91c7433951133627bd61b23221c6deb012414d4c3550a061f6c37515a0f23c54e46aadcb641c5d8bed81f511c801c7e13b54398ef8a2e5df59f82df5dd075349fba603ff
+0271319f79f573bcee0ec9f545e49f9b083b8d61c33c55f2286dcaf20fcd22a7bc94e8bc193707ec31eeab18a57c5619d815f1bb17860c1f8732465a574a668e35f47b1d2a805878309f59f5b64a5217b399215a0076384ba874beafb8135caea2185ade836552d1495389b0ec6f230272a507ebf00f33c4ca1c5b85a395ae
+5b924065aecaa169085c2864ad4329bc054731a8b510e814443d091027fdd6c35e100d46967a2fb9f2a6018a3e9a973dc91fd9e8741bf4f6d1f4ccf29f35aa37ba439587f04ed97e0bd53624028156bc5ae38bc65325143672f08b41ef2196e2d47a60fc778332054765a60bcbda40ef1a192faff26a811d65a729325db934
+d95838e444b51fe5d2780eeae5fe444028f9e291c637aa64e988402eb2e7d4d6d32925f93d18eab3ade01ecb66fa8eb298202a94c9e3f24024030dd162897b08c66756bf2cd92f3fdc294012500bd2383313376ba6e559593f9ba2437d420c173fb60b3274c4ccd091ca96d276d63435563fea10663753c3bb859c07a8b8b5
+d60b723aba33dad8d1926092dddae3e31010acc1d69900c2cc66a029a91e10e018b3cbaabd813eb1202714b1f221dbcd735fdd75ad90d32036197a8f7684dee75171d9eafb518dfcb3870cac88eae93b509302f3da384ab4250de9ae074495135cacda458861b8478d7bae74bed7b035cb268c04ae5488ab9fb86d839b69f1
+38705abbf82f01b0f7139b976bdc09f80a9cf584725a39b2735415ee4a1cacaa3da06e242d339382ec35949be25dd673a2c62995df7d0ac79a45bde93b91f400821eabcd3aa1c5534d3f8e79770de25c76e28460c65162756e55b9f3bb137c74710722aa0468598a3cb7afebb1dbfe77cad22e9654f93790f94629e0d4882b
+24b79ee955fec15120b0f2cd29f59ca860ea833e7023ab716d3a15e43fc5130ac41161bc94fa860d077964e589210ee8e383e3fc2222ce1486f0b52634f6a7f003b7a1a37f1ed3bfc0ff5336c36a3ab2910f513b98cc1df9acc3c5d0585245e605cf2ddeb6b07bb822d5f72796b17ff35e822e523dd24a6069ef8baf345175
+d46225f77a129154e9dc985cc74238d307a4d8272aa2ff736c428e1a3ff734badbeebaf7114d1afe2c7dcf390eabcc5d54686b1a3ddca593eac4b9a5737a14e6f16cc20c4986070da4b9431d8efb42f6003792044b5984073be785906d74ba0bbfb2a19bc1d465d1024af069c2e6092628ec67feb230f288829b8b83633925
+b9242a35a44fb2f946795c125917c9554063cb6e740b7e6d56ed4e070861dffecf723a2ca1dac1ed59a642cc55afb63a54e41fc27ed61ce27ba656107e25fbb53d779201e62034a95a07618666940e42357e342dfdfed3c38d448b9f0f818098ba08dbb645c85e0107c1d4912ac2a3445fadf63731721aec26fd81bcc7859e
+1058c9dd448f5eadef0a47915598bf58db577f172c462ee5ec69d3b1e3e8dbee0d46b5196c36dac3140889b89a8f53b11b92caf302f71a62a5c3909806ae315866f4ebe2c05773898697443ace1a3757a79f96b713dca1ec16e053d11e6ed5f27b1ac42a877f32fd2eecda6e44e04808bf109b777702c6c3b9d10c06ca4210
+5f15a31995a472a811348b3f68671ac7760af3b5b9eca0d80f3a3cba3fc4f008cae55b377f7ab315dbe2338ebc38b165ad38d4ac6aaea58f46a0882defb5aa4fce2c2c13749a5115bf210197ed59107f58be06cf234b82dbb7ceeb9da3c8b7a1f055f3009dd620c6a43eba73d1b21b5435d5389274dfd82460cf63a26a2c54
+8d75a402913c812aa2974ce87850a4560c24ddeef1ec53a1ea9356ab26b148a6aa4e9e30c3fd94effb017d41e5a1c9b11b1e92d25874a17239f0ebfb8e131a7465b09946d9ca665a78d940f0d367e73b18768809eeda4c4365230cce7ffee67d5e850ca8754c97bd579ac36c6605f2121995b6f0d1d212fece438ade5d7525
+56024bcc58acaa3338299c419d99d3ece454ca23064139d89dd65937e12eee7d859fd6bbaeb697fb074015e5e10719b3aa0de6e02e38425e9970403bd58286dd868063efc25d08418a9856b8649ce4a9e7d7d7c5510ca5858f3faa4387d4bb11177772747a78e928bb36b3879b2ef749f9b7a831ce5761ef228e660eb8aeb1
+f0ae24433d9af3a555afc08c3dfbdc9f74f1db0cd64b8101453a2944364d902fef71d1cac0f97515f39601157dbf76a310bd8bf13c4690e85bcf962507848a27be29cb7ff0e0fc7230b141f8558d06a194c5e799fc0e803a8b9bd5f9558bdfc955d2146ea5ef9f05759590437cf0571f942a71e9643ef081de4c80a096ca0f
+bb5a234109311865c88bff1eccd8be1dc394d9f099a8600c3e1d850568d2b54fc758d88b6af9e960a18162cd793a8de95fd0a58392e26e6cd662c9cc1a12589a8e0bfa1df1f466c9c575d7b7868d0d3ba22782a6a0f63a50f03d10e606749377e6672f606e32b55022fc9b329f6d50334994cc53c13fed75053054095e66fc
+5fc6297fa80154541c5b34afab967fda3dcdaf387074a99f3ba7767bc2a20ed0391f07c17e5b0bc3235d88324859d01a2ebb6b72d3eb0b6aaafc3df45da43651c331be0f4e5ff8c8f0974d98b97678aebee35bc3d66f46306150e8fef0690732ea21975a05668b1aec7dc955b0a3a2a02c8c75dfb1a3138b5711e2a8d920f3
+185ff967e4a7ce7df4343a5f642480a2807be5c686aec981ddec06bcf5c46619c51d4cb34ec0de9325a6ee9693d6f3849efce363c4e6d187c0b1095aecd2a9c29caeeb9627465f6fbabeb7c63a2650f6f77d636012445690c032459661e9f4c330f733744626646af8dd235a4ae2e841a3c0637ddc3cb3e93fa48c51a84206
+0ccbe19ded9d784571db78235115dd2bacf6fa0579b1e77fcbf19fd1b88aa57551e869f0aaed338d2db14d0968fab6a02907e0e5aefc2fb8aff9748576d2fd1490e50425e6ea36e3536d696709f072e0046a271fb772b8d9c0812834ae6b42124d29ef360ac09152de058adc9afaacbca9f9012247b74459bd84ff3aabc1ae
+de433d7a4efbb169fc51e12f2b9bee837e4888ac1b76739d82e99e8d8056479cbb9a957cfa8499594bcaac8899d270e149d664c55648af1ca0d56de23aad43be627bc3ee7051cd1e17cf12caef2f4de2578e06170a13c01ef38ff72ca985114212dc6aff41c50f87150f2fd3db8c6273f2ca478a19a7cb92427c9c339447da
+84b6297c2f95d04ddb2440d227e55023f2d2fdfda574404e0b274b7dafcf4d993756b8b56094da880ed11be1dcada1080cf8a912c0f6e206307590f797414ecfec6c691254f520a2516610697817a4ef0e1354b7f3b66226c8b403f4955426a651c0237b54da17e15598f62977a0f0a4bafa09f64c730c016ec8b163413749
+2d0429e247d1374e3d1cac75fbc0e8820158e776004e542e7f50934c9f4b477776ff5c567561a2100f08af0343d4131e5713fd49c996aab67c0b1c0947c280fb78973c06bd9f590f9cb25cdbda2e342aa22f9d45cd441f130d206dcc38ad026ecd85c0258ee98de88cf1ac5a8c038ddf87c48ac6c5e64708759968b9887a4e
+fc00e5d08ce8842b3c1649b5e54a00411b1587d76acb57e3dbded888141e4c3f90ced5b3c5ade78e6b6d12297584eda04e1ff673ef825437abb45f32f721b2803bbbfeb31d93d7573ce70f8f61391e3a1af911375434db1054fff2a0503529b48b891680e15e3f16d46556365314dd5d81629dcb31ed07dc32c2b1bfeb1935
+685e406fb5fc31ca37a306c213053ade935c9bea95fc2f6227fb3e10d5d617f3d64b31641d8ff54ce1c6c960061e02908b3c1e4f088c457f345ceac29cb05986c09b51565ae11d89c807376503c6a152642b693367326a0ce6e65b48b2b07d9395e3daa04d30d5fa14b0c4d35ef65db3519aa866cfbd9035d157639259a34c
+21bf729e12537bd5107566b8d089a6fc47fd3ebe25e9884cfd77579d3ac5f9d5f3d0f26ddde548193f8df07fad054a6145dcd353a53aa7b4134dc06df0a7431d92e4e826be68def13a2c904595d08bb71360a29a5e915a0320d019ae20f0cbe9c215fbab7313bfad387ac60f766e26ced406062dc33e908be782abacc9bb16
+f68a468b4edf4dd11bcdda9712575249c2aef455a6c4281426df8fd595ae3543a33b8ac9ff42f202b11472bf35006ca1e953f3f8cbdf4828402ccbc7351409193d18bbedc5e44d4359cd46dd6af0dff1ab9c361a319e628e7daae57d145b5633325c4454d821ebcd57f14e8d475f157e7b7e32ce47fd0d1c2c5b6d46005e93
+5cad8e4b9736db6533ad14736270d8ebd87172293a1ba351ebb1b49df031f97b4db7d2bc8b7c8b660a4fe78af4816a5e123651eb5e804ae2e94ae54c17b5be968a5af1438a965a57e9f2f9ba168e55c346c11dafc8d2f4bbde2afa19d0576340a865a3da4cc556ff2a7e620333b6e5a83c601d4ceeeb6242ed3a07e0b18dc3
+c1aed25b27a74e8e5d5ecd5afe2bdcd57f0248b1d0c6e26bbcb040f7f20d1149884aef92014465eb9a205716577ca2e93cbb953711317884960ed05d4896c6419ccbf960e7a29790a14ea30390614a4f843c22f253c070c41e70e67e323f74452b6c4f1a598f8b84d9353443db4fc7721b5f3e6432f68fd9619aca2cb8fa0b
+e2f56c57d004f068e4780940a4f7986d26beab8c6bd3753feef6dc34e0957f1265438c1f5279630eabcdeed9ed7e8d22efc60fa98761fa930b7cc14a2fa087ace3dc45473459298f61820cc6f7a9028585ea1fed8d25528ff063d8d4c131da0b99b03a8414bfb286a3e41c013ce5055e93b2889a8034f0cb51b00e657970c5
+de52e263dede0861497404b86694437ac2643a753f1682002e947a5822e0b52c1cf9c9f52904f6e2b1998c0e0f880327e35eac4252d52e52ab2c5f4d440a40a69ec8bd2b0efa87f4283ef1ef9ad3414429d572bef98a6df87c0d24c0b8d9f33c5430cf12d627f9372e0fdb25a28af925c1ec95921813bdacacf7c1f6195a9a
+1ed7d7fed7df9a3df68b1366f9eea34fc437b4dd78738c2701c6322bf732d61ea1dd3eeb38c3ac10de840fb4a7cfb03c1b23d815d51fc77ad6551c6782e2a1206adeac949ed0ae6cdbbb1f20150f2e1a75a8730d70f0083c070fce79541ec0b2c6e6f1a91ec8c509a525b0be7f76ea7f4f17981a0eaf9c0af95d8e45da4be9
+8a07e567d7b5a31b161c14ba138a29fc704fffeb42d1f2f7d6ee3e31adcf5f323ba3b6466e77e1751e390ef49f682f865ae68788c7da3c2bff07828010b072bc1fb9a163c6e2796adaa6e2a623cdadcfbab371c2bcaf7adb2f8da46c07692cd097013c8fc2377c15a75b5e8cecfbcb8483def7a4cc62e2305e26df4b0a8e1c
+79de4361a16586a4f1bfcad1b44aa103ea3bb553094d689f5532bebdfd6e0cb21b0d071656a69d5321679712e3957547a4e6bbe527a734ba59af93ae82b803e0b0ccbb1d5c771ea0ca8602b51b89c22fba82cda89ef3dde6dadf07ecbdc3ee1528a40566b22bef138eb95985da8e2e9b9a8b6d839999b048d481a460914b61
+75a3f8dbe10d7e44acd6b7e7c394bd717e7edf4e670858c0d84c5bbff06c9fffb0231fc4d7563cd79320729e8d03ab47ccc8d7016f13ac6ce5862bfbac90eaec0ae22222bd838a9be96d2fa24cf80636e5ad658f45a3ea63a588a14550ef3a81f898b4afe83c8bc2f04954471feb715374712539158ee5567b2b3d3e454ffe
+d3c0eab4202ae27cfaadd673da7f9655888efe008a07f50168d1e8ae5368f5af3b9eef2a2fbb0808773a22149815bc5902aadbf6ab7bffe6e1cab56a99d671fbb2d8375614388bc2f452d46aca0d318afba07ffc17831ce7f8da474c995aba7af56583a2425236b568b7aaf216131bcfcf099aa14db701854218e746b40dca
+a974b9f3b63a7f6b8dc348ccab4fd21edb7150876f27ffd5d09d27dc365f5e08468f178f8005133a14459059cffb60dc48da774b7583344395ecf7a274caee349725143548875cd9cfc74e14e8c4a5c7c03cda2baea7b463724cc6028addd5bd71d2630574a5fc96f8c13a75cc2804f1b1f7f195c1166900157466537f761f
+f51eb0db89174a040bf2dd160f92f24896c998139a115ce941ec46e1aeefbaac7b0cbfa26d764070acdf094cad687f209090f98d38d4f3918b2acad3b5b342c94d2114acc977e40990e2ef16413e03c8442d8186987b0adf0bbe2836aa434a6d44f3ccd7eae175fc02abb0db726ce79c65cee83c9ac23ee37e3bba34d8c03d
+fcdc68c7a130b13e566ea129d8af8cb271fc2519421e9c4c55c6d029a99093f3290a9bafa66ae6a22882731e6cb62d16c6c23590583c0c21e6e0ffbe466f15e0cace20727ec72e06c7b03a3db3620b8cb12123f8f2648e7c606ee233404462681b8979e20fd8e47e6c42f0e4705f60b444c299b6e4f9200dd60b086b166e3b
+05c3aa67bf2625eea32fa4facc8fe18f980d2871a0fa6cec81e90c0c7d0d88fac1d91af8377917bb8834c6d428d7e6dd0febcf651ff687ca55a6d207003f30e1d1da0a19e560f0121b3da29e3ba68248728f453a7829ef70993743e153dba668df62c043bd8904406c80f4b396a7a134b1addc90934cf3ee949fd26a6ff9e5
+e01d72540caf415f97f26dab45d861b70129187c07bc667856c74c39f9d27b6060f47f5e16df2e611574b3148cb4ce1e7c431142d4a992f3ca7b66e524c0aade577dc4c22d27ef10aae6dc4bb0a106a2fe2fe379c752f91dd4a98146ed35d4470746a9fb8949cbef8b6017f960baa82db48f5f71142e9442bcb5452980b9a0
+c7e699a663bd99e8df94f5591aca08b8e1031952e1a8d0c141b819f9cdcb39f952b27e2026a18e8e3f6ec026c987f4a124d18a383f9ba4f9dc883e3f1b8c9262687a84cb854c7764699538519fa10a804a54aa7feb1426d80919f8ed1cfda18ee5cd138afd66a9ae0f0882a28a207fe355a2270701057e40e7f83d43ebd5b8
+3aa2e6c1435e4e3f12f2540e70b2da3e356163586ea6a41be1a782b0e460d5e1a3cc317b96435c3ce0e1f147959bcb5f74e42fef522cabf2334b8fa3971c894ea0842306f4a9dea99e46163557ca4c93c3eb10493643782bda19511e8e763faf815051af4b30dd72ad3fb775fd29e33b9109b22a8682426e36671366b0f615
+def2a72b09286139acd2cf7dcd487d068485c559b0d5adf247bcffc542c9bacca6271a46e9a5906db57ea691fb85cfd966f40422997d9c67a39117804f4da3a9158add2cdb25a98ffedb70fb947c221b0ca1f3d24a89871fc16cd1fa0aa5dd312f8153ec3c1bb9ff62ced28f56a064947bd0559221a9c478e341b5681569d3
+35444b2b357d2f142c34fb86e5bd5df49c1837034c95b12b3979cf08f54330a1ea420e597bbefaadddf284671057e243f2a48a3e7993a116c0b806ba232b0e31897349961ba6516bca4c3bcf482b0f05f27bd36b30580623048de317b82f7dc41c9b45091044a51db54fb1fa728a70ea90ebf6f7f812b5fbc9a3cafdbfa54f
+16d53f2c155129bb21d94c22a7f9c444ed47c87f0a0988ce25c802ffb20da648085e706fe36c01b8baa3371fa2f11df97aa9d08b7fa819049b607cce3c16a7a5ed4848778105724f7bf2ea2d7b04d0368284b143a3e7e03ca448e4ad7765bac6718a6fcb285fa415671c24159fe77788d9b4213f27ecd65935f0d2d4c92b18
+37ecfd8b513c5b77a5aef7d3102ce4b862671a13b1fc29284e36652744aa7c9545499008d56e6d1b42c8ffbe54586a464a0a834b95fbbdb449164c8dcd4cf18c7150f78d6420257c1ba47ad7b86d1bd91aa88b284f604d455852c3551fd10cb4917835965e87a0a42f86eaea2d4571876df9d5237965dca6e4332efc683e3a
+6376b09c4ab9c9cac459910044dde61b776f87b9353f9c93e68072f9947a54fe6ad8ff874a12653badfe2f6f1a21d47dab6c808bbf32cf3dd3ceb95a2bd0b273ccc79549c590377df9c4d1b2e056033cd694b3ca7923abc563d9aa27f85fd895b69a3f1152410cbe526e704ac4d568548893b0a16fdb7645aef7ad09c33064
+e82a457f5ee84634032f63e229792b952b65c909513ac03ecd1a4a22ae605e087fccdd1e17a22586248ffbae45cd3b8c80814722bc46451d15e97ded57ca354d85ba70bff0cdca4a47d876593eaf84c59e9abb3b10aedeb9e8aac86ce8019b5c7831b1a3241d88f56e8d436620503fb86d035da5068a34f7a6ef6f1d25d695
+9e8451a7cad54bf85624eeb2355978713578dbb847ec7605d1ebe0aa238a4de8545ee6d4d6d9b719044a39989867ce69bbc8445c20466a7e4f5161d0a6ae263717db731e1eb08f4e1f24d28ea2d55a63d6d2b1c717e4c171511b51c3ee46b039179fbf69fcd3c5c84318add0a76771650e8d1d3ba948abd048e2281d5a0ed8
+ca90a7196ba4fdcb202265f0b6faa659267a492009a28dba3787f07f4af3770d64301ed11e13a9ab9762b1a110729f9db5d39562a1a5aa96e34082fcd4279c7a0646e3fad1380269d0d9cdf546a08ecc22b9a6dbe08d75568de8540e9c1e6a4795bd39bc712810a80a6fdea258e4936481c7a4b7d293eab715a331af11df78
+4a66f2ca8241982d24e5ccdc3bd775bd08e00d873ed022384b63a5f023ff9cc9cc5c60f3ecb64bac383f380cc3de3a2746b4225db983663d179bbb063fd5bf8cd6a3a7a84b9a273087691e1e89b7c7d65f18d2454d3704993843b285cfb54557cfc8647ec40f90234ef022576dd05ba17b07c45caf035873a18647618962c0
+f37583a907bbdce2afee783a8a8b46bfae16c33e19b34ab8c2926e568b3e16ba66feb54ffab3c3fd353d15cf35085f1d59cbead0192698e5c26bfe498119340df867ab86ff3e58f061ba5a061d274e809aae1f7513a28eed3d279f3f34f2de44cfa12aab0303d311b7c0e4b4cb66dc3959fb21b9c26348068311738cf2258d
+5381f9dc01cdc49dcff5e588d9fe854fa4759395cb1dc51b58c83d4b55fcd3da70272881575b5acd9c11de97b79702ef417d0ac199bd5185533911dc5b4c8ec0db6e96e1a3c00477ce553b81a0f610d19c837699cbbf9c0bc4ed8dd9ffe6d13a8008b20d4c52135b6a9e515ea4fdf2057d9d4312ac75337abe16da9d7ef1bf
+07aa4e4e8a5dff5381619fd1f2353a4de0ca3330417f3ebf9f86cb5921a1635f2da48f8aea9fba25db2f4d86ea8ff54ad165b68a0f30c1835b944221e4a674e9f805857bf7c93298f147a529636ce2b6aab94e37abef08e8261d74633ceaf5ae110455a53ac96a14637677d4f9392b8927a6031d0eee4b004ea1d41cd5c4f8
+904c389bcf5c7ae18f77dc22438742eef46e018040a03144134968c92b82f88e22a9f9846f506444d5fd43f72c9272235fbf0845b5a0676c803bc61d66d5a18a2fbd447761c41fb79a30c90cbcab35840fb14a9bc8d5d6edb19f70b420d81df60713b6cac192bc9ef006f7af35114461cc87fc50a2323cf30af4788312239e
+8546618038952f0e93de5ac06ad51551b8e968d49c16e7d59c7738e7e69798bc9f04b2b6175d24f33ba2eafa0bc36a5226b368c6636bc33334ab4b94ae08c4f9370bb31da42f53c3b76cee0da4146e99ae0f57086c479500c6d2342297e3d4f49f556d6934c312bd3ddc9beb1c07119dc1d91c20f678e7e52d1e0494859f6c
+9dacb7ec450aa2047ac38fc0d3f1fb9b794eefb18e62daedafaac5bc083c5a8a0ef03c176195dab2c5dbc8aae1803e3a811369d1ea946c0eba323ff60e5affc5b60194997eaf8be304b65256d10ad5bfde7da1378a94902ee2005981d9c9ca902875fb9354c1ddd201484fbfb851e86a5d6dc541819e67d8ba415912f7f2e7
+b1def89c663dedf9b5f2633f1c45f5529f944466bb5c0cd03ae26c78ab1c5491ff310f335d53d967214b2a5e2f0ac75a66048ebab664c15a69ea7c256c40783cc9f001aedfb315e16607a06f4c9cde1034f27e05a0e6a73381d83a5e678ba952308a6c9b73c98cefa070d3c52b2ecaf706b9b247fc88028c710c8d5d0aa49e
+b35b5f4006d43e554937605e1f5712667e46e63eff3f1082257c82669b1cfc8815b3c3e87069977dc980d23a145e33f43dbf5e90cdbdb684f7db8d66f84c50a594f6f4b4057b58e6c5e27b34df4ea6849d4668efd8d402eaf6dfcbf5c54e4f52d15f7236def60a892a9e300091e438d447fa6fd26435692a457e5eea4e2d69
+ef8bb74daf6aecf57616fb6be91598ac5fa15d4dcb0c5806d4e43db6e526564cc3e2122b6ce50b5c637de8fb1b5bafffdf51214a8355f74cadd668f0d9b20e5bcee2a1485f2599088cfade4f5496f612de6f7607bd76d152c3f26944de667ca264af64eaba6f6f0fa1841e860a73075cb8e98792361b23a4cc2150cb9842d2
+59f78e62959a21a5873e190356117a31e75377908e48f249345f9727c0c9d1231bb2ac7a4533b9f2f3c2f479fb24f38cde23dd8e29a7d1d381b92ca4557225b4a796cd5abe2cdb90d032189388fcbf9848b0602efd6aa662162b53a8c83ce3cf06a9dfd0f0ecd017e7c0a1c1adb88f64c85809fead4bea4b639ce4e74e008d
+a9f35970a1e9b973a878d5d419b43b8073c3dbbd829f07c45694edaa1ab98dfdd823830d663930ac316ea0c52f5e290e02b26fbb07d18f57d7bc4e572822f494304d6458efa42222bc6486acb53674595a913d613952fdba9e59f433641f01dbb7a7a2a16ca96480c229feaac7242ec15a7291637f09a99b3160c6ada9a478
+e1b276f6d77329cb2f9569b539b24f174e2ff12218aafd06abd1b663dd42d1089ee817719ea0e7bba089e167bec881b68a59bab6556106b128126bfcc1be67017a2beb29e307d5a9ca5e6d916b2f829964f13a06249e1bbc41264eb0217462365451e96f4e9ac13941d9fd2fc1fd8d4aa2e6f14ef4b99d9b4c16a3850e2423
+a84130f218a5cf5a64d467f7fe0f027c12f79c1ec8db81a4e4d584559d169ce624cad2d3c53bc2293e4de6e70a1f516e28d96710fcdade6a305816673be3f463cf03e98941162c265ba8dc5b88d2cd7d6e9ce00857cd7fa9498655eefa74e85a2b8ef749ce35ae966a9064052ad5a192bf7c5d9e9f7bf0f4254dbfed25b52d
+c0c98ea598b6decd079783a2524a25e7054e0280923537f3e00d05baab5bc51d67442e6bb14986248a6543e90ea9b14f777b6d575bb07a11996c311c98ae4a90d983415e0e6d14b2f509acb555e605644dc9cde6968e290fa223441dee889d832773e4b0b66404d7b583fb76bfc4a9b5a708c852613ab2212032ae4c59c922
+2cf397dca566147a468838e2267fd4a55f2daf9b54f0cc55db9ca1ecc1a997a596a82812de11f0770b5eb5dde5412df05e9e02039e6d5e7d428c493b36d76b8208375861343469c5af66ff26ef2ee0e8b21f6c81be86d5bfe42d563901d8efd57f9ac0cf1acba4ca506b3499a790677792a528890c0562f44b6aa0b1608ee3
+fc66c4e0e0b8432ea1b2c8adf009c14d6bd099e5d55457d0143628b907d3aa00fb6dfd690b7f6fc45c60cc937e99a3945719987c4108186762dfe0140731e12169d6b3cf6fc5cbcf1db786aa88068044b5260aa9bf8fd767f50691b123208d7cfd3d8805076a456b3455d36c569a3e7fc38d466f57f29e38aa97d030e0f4c2
+fcaf77081fb37259948ef21c4c51b5b2661acb8b8e5e230346e19b03233fff6ed14c73092237cc8becda676e0c3d4205689d9b506bd0a079ab0f9ca49bb06e383896fb00f2a6b9b3485849fa6f8b3dd14946dcf5c5dc260800d54365fc619f594733f55fbb7e6b8c208d09a480a1ba1193f48f56416d6c36351861eff0ccf2
+3990ff8a012f1652d082d061011cfc98bfa9d089fad96f48b275267710da5ec1e1ce243b609bcb72ef943521be21fdda9f24a9da985a6df8f0300ded2c5416313dff090042b1434952fe7ba55f07c19d97b2a8587e90431ab7375dff1a818e218340116c51c0a2c96ce249221a3f9c29f1f9bd7cb7b6e4595fa7764640ab41
+9a2d69249c0fd1a2fd964f101bb46e61680bc62b1f55ae93a027b7c777611891566d89c1a33b999317c2a196cbfd4a6f8ec7f53ea3a9ca213f6dfe86f6ee51dff65aaa56612b1d78d55b23834a629c1f8b5347e8179e33ce883e0540d1a3036c163f2ce26ee6042fed8eede235251acc8904d71825ba22be8e34c2e06b0b01
+6cb4584614c59abc462ddec40a9d43cb74e1d61b99e60a1dad094a33528cfb83bad8e7ce451c41b2a9c1c0fb554c62793e27553534ecf0af92ff48492fb4565f05cfdc2ff70f3299833c5c62912601ed94572c03430f4906d9d9298619d22b421b198f8323d5dc6c48a193a856f22b2a3f7adc218733d2dd9e6540879bb5c8
+aa75b45fd299a6711eadb04410121076e0372b3cf7e22c949b51bf5c1d02f6fddd7a997fe2dfbb863bb96314cf130fd0a76dcdb21ea3d04f24d2948d4bb54e5070161f92e5212bec9da48827d791a83390aef110183038837cb513d717bc6b5619047157185121910a60cd0d6ebd5e6139d630be33d660e5380c11dadf1275
+2f34d2cd155aa8d6e38553dfa89e2dd9964e0ade344e0d8ce50ece046db1496839859b4bdd3b4971af731ab12da964b0f7d4f220ad692c94473e176eeac031f237d8f0d576076ea791a6b670cd5fb4936a10acddeb44f4275183424b437245ec1729004edfe5e7e60d9ff533a606c69c52adb0d78732997f4d62551faaec01
+e49094465d6fcf339ffe4b841fb20bb75f67f54d5e30993d1e24502d602b55948720411530024b3e5d8ac52f9a840fc5c7c15a2a9f652261e5d144eed3fca65d283db21c90cf1bc9c98dbbf6d2b0113a7d4c237d255b2704c5f7cd8d1f575d11bfcb3cd27a416605388b500681e3a41ebc1125a8a3fffda2db0dd3c7ca9eab
+670823e8afe16f5628a879482838c09f00e780288bc2b470f39298d666e33142cb8068c4c99434368fc19638844e2fb241a18fdea88a6578cd9c311f6b36125d953c9d1d6850c006d1a9ad0bba7c4bed86b92befc612414e6ad90f8b1380a7d22a48f1cafd8cc6f8cd3f7dd17a61a5336caaa3a7d8ba40925585d41d4f1172
+ecdcc2c3f613d6b2c0bce2c177b3445337fa2ac0038cb13e5636e5af3f5e82b387d6aed0814370dce2899abd93db3f6c576f7e3c9564c89dfbe904ab963e41716d9bd730cd79916a3de3b72fc19a4bbf350050388c7aa3b3a7f6bbb92208e09d48401d9e5af523aced2e3663abb00f34aada3e7a234e9f316bdf66dc19f95a
+c5d434e7c0f669524cf617426aacec209138d160d0ebce8ffa1f36a308937c09b84babf87a9e12ce22dcf4f74d766690c538bfd7e2f12c2507a9b8ef2941ba1103452b860c89d9e9ce5856eb68724d0e179a7c56509973502700879fc3c62dfbf427d9fddbb826884e4ecec9b9fbf52ac0550e9754ec76a5714a12a8832e10
+755e0952b3f4758af045dd6050a930512f9b3120949349b9e8b88fe8d8f95650687ecca00e5882bace4deaf25ea5215cd4d150b675a5e74118e40b0647e54590262e0aa4b01a7cc80401ca6b3f064d9ebae831e5b4a318e0a3fc710887f3877ecbaf0d8a379ab23bc9b19d9478ed552c1bcb5f70e03b34ed8429af033fa1b0
+8d99da8c61c26bedfdbbd22bad46b97a731d94ef4c8641e0d7f2734f6ab08c896d2c0b1d4531bad9d880882d5cde429616015ca37bf416e2b5fa7c68cb32af6d16d1980f1baf477d6a5205c640ee82f29df0eb4c4522b54a01989ba42fe0bf94912cb426ce2da3d0fcaa730b9cecbbf12a9577
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+0000000000000000000000000000000000000000000000000000000000000000
+cleartomark{restore}if
+
+%%EndFont
+setpacking
+%AI3_EndRider
+[
+39/quotesingle 96/grave 128/Adieresis/Aring/Ccedilla/Eacute/Ntilde/Odieresis
+/Udieresis/aacute/agrave/acircumflex/adieresis/atilde/aring/ccedilla/eacute
+/egrave/ecircumflex/edieresis/iacute/igrave/icircumflex/idieresis/ntilde
+/oacute/ograve/ocircumflex/odieresis/otilde/uacute/ugrave/ucircumflex
+/udieresis/dagger/degree/cent/sterling/section/bullet/paragraph/germandbls
+/registered/copyright/trademark/acute/dieresis/.notdef/AE/Oslash
+/.notdef/plusminus/.notdef/.notdef/yen/mu/.notdef/.notdef
+/.notdef/.notdef/.notdef/ordfeminine/ordmasculine/.notdef/ae/oslash
+/questiondown/exclamdown/logicalnot/.notdef/florin/.notdef/.notdef
+/guillemotleft/guillemotright/ellipsis/space/Agrave/Atilde/Otilde/OE/oe
+/endash/emdash/quotedblleft/quotedblright/quoteleft/quoteright/divide
+/.notdef/ydieresis/Ydieresis/fraction/currency/guilsinglleft/guilsinglright
+/fi/fl/daggerdbl/periodcentered/quotesinglbase/quotedblbase/perthousand
+/Acircumflex/Ecircumflex/Aacute/Edieresis/Egrave/Iacute/Icircumflex
+/Idieresis/Igrave/Oacute/Ocircumflex/.notdef/Ograve/Uacute/Ucircumflex
+/Ugrave/dotlessi/circumflex/tilde/macron/breve/dotaccent/ring/cedilla
+/hungarumlaut/ogonek/caron
+TE
+%AI55J_Tsume: None
+%AI3_BeginEncoding: _Device Device
+[/NUL
+/Eth
+/eth
+/Lslash
+/lslash
+/Scaron
+/scaron
+/Yacute
+/yacute
+/HT
+/LF
+/Thorn
+/thorn
+/CR
+/Zcaron
+/zcaron
+/DLE
+/DC1
+/DC2
+/DC3
+/DC4
+/onehalf
+/onequarter
+/onesuperior
+/threequarters
+/threesuperior
+/twosuperior
+/brokenbar
+/minus
+/multiply
+/RS
+/US
+/space
+/exclam
+/quotedbl
+/numbersign
+/dollar
+/percent
+/ampersand
+/quotesingle
+/parenleft
+/parenright
+/asterisk
+/plus
+/comma
+/hyphen
+/period
+/slash
+/zero
+/one
+/two
+/three
+/four
+/five
+/six
+/seven
+/eight
+/nine
+/colon
+/semicolon
+/less
+/equal
+/greater
+/question
+/at
+/A
+/B
+/C
+/D
+/E
+/F
+/G
+/H
+/I
+/J
+/K
+/L
+/M
+/N
+/O
+/P
+/Q
+/R
+/S
+/T
+/U
+/V
+/W
+/X
+/Y
+/Z
+/bracketleft
+/backslash
+/bracketright
+/asciicircum
+/underscore
+/grave
+/a
+/b
+/c
+/d
+/e
+/f
+/g
+/h
+/i
+/j
+/k
+/l
+/m
+/n
+/o
+/p
+/q
+/r
+/s
+/t
+/u
+/v
+/w
+/x
+/y
+/z
+/braceleft
+/bar
+/braceright
+/asciitilde
+/DEL
+/Adieresis
+/Aring
+/Ccedilla
+/Eacute
+/Ntilde
+/Odieresis
+/Udieresis
+/aacute
+/agrave
+/acircumflex
+/adieresis
+/atilde
+/aring
+/ccedilla
+/eacute
+/egrave
+/ecircumflex
+/edieresis
+/iacute
+/igrave
+/icircumflex
+/idieresis
+/ntilde
+/oacute
+/ograve
+/ocircumflex
+/odieresis
+/otilde
+/uacute
+/ugrave
+/ucircumflex
+/udieresis
+/dagger
+/degree
+/cent
+/sterling
+/section
+/bullet
+/paragraph
+/germandbls
+/registered
+/copyright
+/trademark
+/acute
+/dieresis
+/notequal
+/AE
+/Oslash
+/infinity
+/plusminus
+/lessequal
+/greaterequal
+/yen
+/mu
+/partialdiff
+/summation
+/product
+/pi
+/integral
+/ordfeminine
+/ordmasculine
+/Omega
+/ae
+/oslash
+/questiondown
+/exclamdown
+/logicalnot
+/radical
+/florin
+/approxequal
+/Delta
+/guillemotleft
+/guillemotright
+/ellipsis
+/nbspace
+/Agrave
+/Atilde
+/Otilde
+/OE
+/oe
+/endash
+/emdash
+/quotedblleft
+/quotedblright
+/quoteleft
+/quoteright
+/divide
+/lozenge
+/ydieresis
+/Ydieresis
+/fraction
+/currency
+/guilsinglleft
+/guilsinglright
+/fi
+/fl
+/daggerdbl
+/periodcentered
+/quotesinglbase
+/quotedblbase
+/perthousand
+/Acircumflex
+/Ecircumflex
+/Aacute
+/Edieresis
+/Egrave
+/Iacute
+/Icircumflex
+/Idieresis
+/Igrave
+/Oacute
+/Ocircumflex
+/apple
+/Ograve
+/Uacute
+/Ucircumflex
+/Ugrave
+/dotlessi
+/circumflex
+/tilde
+/macron
+/breve
+/dotaccent
+/ring
+/cedilla
+/hungarumlaut
+/ogonek
+/caron
+/_Device/Device 0 0 0 TZ
+%AI3_EndEncoding AdobeType
+[161/degree 173/notequal 176/infinity/plusminus/lessequal/greaterequal
+181/mu/partialdiff/summation/product/pi/integral 189/Omega
+195/radical 197/approxequal 198/Delta 214/divide/lozenge 240/apple
+/_Symbol_/Symbol 0 0 0 TZ
+%AI5_Begin_NonPrinting
+Np
+%AI3_BeginPattern: (Brick)
+(Brick) 0 0 72 72 [
+%AI3_Tile
+(0 O 0 R 0.3 0.85 0.85 0 k
+ 0.3 0.85 0.85 0 K
+) @
+(
+%AI6_BeginPatternLayer
+800 Ar
+0 J 0 j 1 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+0 0 m
+0 72 L
+72 72 L
+72 0 L
+0 0 L
+f
+%AI6_EndPatternLayer
+) &
+(0 O 0 R 1 g
+ 1 G
+) @
+(
+%AI6_BeginPatternLayer
+800 Ar
+0 J 0 j 0.3 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+0 68.4097 m
+72 68.4097 l
+S
+0 61.209 m
+72 61.209 L
+S
+0 54.0088 m
+72 54.0088 L
+S
+0 46.8076 m
+72 46.8076 L
+S
+0 39.6084 m
+72 39.6084 L
+S
+0 32.4072 m
+72 32.4072 L
+S
+0 25.207 m
+72 25.207 L
+S
+0 18.0059 m
+72 18.0059 L
+S
+0 10.8057 m
+72 10.8057 L
+S
+0 3.6064 m
+72 3.6064 L
+S
+68.4102 68.4097 m
+68.4102 61.2217 l
+S
+54.0098 68.4097 m
+54.0098 61.2217 L
+S
+39.6094 68.4097 m
+39.6094 61.2217 L
+S
+25.21 68.4097 m
+25.21 61.2217 L
+S
+10.8105 68.4097 m
+10.8105 61.2217 L
+S
+68.4102 53.9717 m
+68.4102 46.7842 l
+S
+54.0098 53.9717 m
+54.0098 46.7842 L
+S
+39.6094 53.9717 m
+39.6094 46.7842 L
+S
+25.21 53.9717 m
+25.21 46.7842 L
+S
+10.8105 53.9717 m
+10.8105 46.7842 L
+S
+68.4102 39.5967 m
+68.4102 32.4092 l
+S
+54.0098 39.5967 m
+54.0098 32.4092 L
+S
+39.6094 39.5967 m
+39.6094 32.4092 L
+S
+25.21 39.5967 m
+25.21 32.4092 L
+S
+10.8105 39.5967 m
+10.8105 32.4092 L
+S
+68.4102 25.2217 m
+68.4102 18.0342 l
+S
+54.0098 25.2217 m
+54.0098 18.0342 L
+S
+39.6094 25.2217 m
+39.6094 18.0342 L
+S
+25.21 25.2217 m
+25.21 18.0342 L
+S
+10.8105 25.2217 m
+10.8105 18.0342 L
+S
+68.4102 10.7842 m
+68.4102 3.5967 l
+S
+54.0098 10.7842 m
+54.0098 3.5967 L
+S
+39.6094 10.7842 m
+39.6094 3.5967 L
+S
+25.21 10.7842 m
+25.21 3.5967 L
+S
+10.8105 10.7842 m
+10.8105 3.5967 L
+S
+61.1973 3.5967 m
+61.1973 0 L
+S
+46.7969 3.5967 m
+46.7969 0 L
+S
+32.3965 3.5967 m
+32.3965 0 L
+S
+17.9971 3.5967 m
+17.9971 0 L
+S
+3.5967 3.5967 m
+3.5967 0 l
+S
+61.1973 18.0342 m
+61.1973 10.8467 L
+S
+46.7969 18.0342 m
+46.7969 10.8467 L
+S
+32.3965 18.0342 m
+32.3965 10.8467 L
+S
+17.9971 18.0342 m
+17.9971 10.8467 L
+S
+3.5967 18.0342 m
+3.5967 10.8467 l
+S
+61.1973 32.4092 m
+61.1973 25.2217 L
+S
+46.7969 32.4092 m
+46.7969 25.2217 L
+S
+17.9971 32.4092 m
+17.9971 25.2217 L
+S
+3.5967 32.4092 m
+3.5967 25.2217 l
+S
+61.1973 46.7842 m
+61.1973 39.5967 L
+S
+46.7969 46.7842 m
+46.7969 39.5967 L
+S
+32.3965 46.7842 m
+32.3965 39.5967 L
+S
+17.9971 46.7842 m
+17.9971 39.5967 L
+S
+3.5967 46.7842 m
+3.5967 39.5967 l
+S
+61.1973 61.2217 m
+61.1973 54.0347 L
+S
+46.7969 61.2217 m
+46.7969 54.0347 L
+S
+32.3965 61.2217 m
+32.3965 54.0347 L
+S
+17.9971 61.2217 m
+17.9971 54.0347 L
+S
+3.5967 61.2217 m
+3.5967 54.0347 l
+S
+61.1973 71.959 m
+61.1973 68.4717 L
+S
+46.7969 71.959 m
+46.7969 68.4717 L
+S
+32.3965 71.959 m
+32.3965 68.4717 L
+S
+17.9971 71.959 m
+17.9971 68.4717 L
+S
+3.5967 71.959 m
+3.5967 68.4717 l
+S
+32.3965 32.4092 m
+32.3965 25.2217 L
+S
+%AI6_EndPatternLayer
+) &
+] E
+%AI3_EndPattern
+%AI3_BeginPattern: (Confetti)
+(Confetti) 4.85 3.617 76.85 75.617 [
+%AI3_Tile
+(0 O 0 R 1 g
+ 1 G
+) @
+(
+%AI6_BeginPatternLayer
+800 Ar
+0 J 0 j 1 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+4.85 3.617 m
+4.85 75.617 L
+76.85 75.617 L
+76.85 3.617 L
+4.85 3.617 L
+f
+%AI6_EndPatternLayer
+) &
+(0 O 0 R 0 g
+ 0 G
+) @
+(
+%AI6_BeginPatternLayer
+800 Ar
+0 J 0 j 0.3 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+10.6 64.867 m
+7.85 62.867 l
+S
+9.1 8.617 m
+6.85 6.867 l
+S
+78.1 68.617 m
+74.85 67.867 l
+S
+76.85 56.867 m
+74.35 55.117 l
+S
+79.6 51.617 m
+76.6 51.617 l
+S
+76.35 44.117 m
+73.6 45.867 l
+S
+78.6 35.867 m
+76.6 34.367 l
+S
+76.1 23.867 m
+73.35 26.117 l
+S
+78.1 12.867 m
+73.85 13.617 l
+S
+68.35 14.617 m
+66.1 12.867 l
+S
+76.6 30.617 m
+73.6 30.617 l
+S
+62.85 58.117 m
+60.956 60.941 l
+S
+32.85 59.617 m
+31.196 62.181 l
+S
+47.891 64.061 m
+49.744 66.742 l
+S
+72.814 2.769 m
+73.928 5.729 l
+S
+67.976 2.633 m
+67.35 5.909 l
+S
+61.85 27.617 m
+59.956 30.441 l
+S
+53.504 56.053 m
+51.85 58.617 l
+S
+52.762 1.779 m
+52.876 4.776 l
+S
+45.391 5.311 m
+47.244 7.992 l
+S
+37.062 3.375 m
+35.639 5.43 l
+S
+55.165 34.828 m
+57.518 37.491 l
+S
+20.795 3.242 m
+22.12 5.193 l
+S
+14.097 4.747 m
+15.008 8.965 l
+S
+9.736 1.91 m
+8.073 4.225 l
+S
+31.891 5.573 m
+32.005 8.571 l
+S
+12.1 70.367 m
+15.6 68.867 l
+S
+9.35 54.867 m
+9.6 58.117 l
+S
+12.85 31.867 m
+14.35 28.117 l
+S
+10.1 37.367 m
+12.35 41.117 l
+S
+34.1 71.117 m
+31.85 68.617 l
+S
+38.35 71.117 m
+41.6 68.367 l
+S
+55.1 71.117 m
+58.35 69.117 l
+S
+57.35 65.117 m
+55.35 61.867 l
+S
+64.35 66.367 m
+69.35 68.617 l
+S
+71.85 62.867 m
+69.35 61.117 l
+S
+23.6 70.867 m
+23.6 67.867 l
+S
+20.6 65.867 m
+17.35 65.367 l
+S
+24.85 61.367 m
+25.35 58.117 l
+S
+25.85 65.867 m
+29.35 66.617 l
+S
+14.1 54.117 m
+16.85 56.117 l
+S
+12.35 11.617 m
+12.6 15.617 l
+S
+12.1 19.867 m
+14.35 22.367 l
+S
+26.1 9.867 m
+23.6 13.367 l
+S
+34.6 47.117 m
+32.1 45.367 l
+S
+62.6 41.867 m
+59.85 43.367 l
+S
+31.6 35.617 m
+27.85 36.367 l
+S
+36.35 26.117 m
+34.35 24.617 l
+S
+33.85 14.117 m
+31.1 16.367 l
+S
+37.1 9.867 m
+35.1 11.117 l
+S
+34.35 20.867 m
+31.35 20.867 l
+S
+44.6 56.617 m
+42.1 54.867 l
+S
+47.35 51.367 m
+44.35 51.367 l
+S
+44.1 43.867 m
+41.35 45.617 l
+S
+43.35 33.117 m
+42.6 30.617 l
+S
+43.85 23.617 m
+41.1 25.867 l
+S
+44.35 15.617 m
+42.35 16.867 l
+S
+67.823 31.1 m
+64.823 31.1 l
+S
+27.1 32.617 m
+29.6 30.867 l
+S
+31.85 55.117 m
+34.85 55.117 l
+S
+19.6 40.867 m
+22.1 39.117 l
+S
+16.85 35.617 m
+19.85 35.617 l
+S
+20.1 28.117 m
+22.85 29.867 l
+S
+52.1 42.617 m
+54.484 44.178 l
+S
+52.437 50.146 m
+54.821 48.325 l
+S
+59.572 54.133 m
+59.35 51.117 l
+S
+50.185 10.055 m
+53.234 9.928 l
+S
+51.187 15.896 m
+53.571 14.075 l
+S
+58.322 19.883 m
+59.445 16.823 l
+S
+53.1 32.117 m
+50.6 30.367 l
+S
+52.85 24.617 m
+49.6 25.617 l
+S
+61.85 9.117 m
+59.1 10.867 l
+S
+69.35 34.617 m
+66.6 36.367 l
+S
+67.1 23.617 m
+65.1 22.117 l
+S
+24.435 46.055 m
+27.484 45.928 l
+S
+25.437 51.896 m
+27.821 50.075 l
+S
+62.6 47.117 m
+65.321 46.575 l
+S
+19.85 19.867 m
+20.35 16.617 l
+S
+21.85 21.867 m
+25.35 22.617 l
+S
+37.6 62.867 m
+41.6 62.117 l
+S
+38.323 42.1 m
+38.823 38.6 l
+S
+69.35 52.617 m
+66.85 53.867 l
+S
+14.85 62.117 m
+18.1 59.367 l
+S
+9.6 46.117 m
+7.1 44.367 l
+S
+20.6 51.617 m
+18.6 50.117 l
+S
+46.141 70.811 m
+47.994 73.492 l
+S
+69.391 40.561 m
+71.244 43.242 l
+S
+38.641 49.311 m
+39.35 52.117 l
+S
+25.141 16.811 m
+25.85 19.617 l
+S
+36.6 32.867 m
+34.6 31.367 l
+S
+6.1 68.617 m
+2.85 67.867 l
+S
+4.85 56.867 m
+2.35 55.117 l
+S
+7.6 51.617 m
+4.6 51.617 l
+S
+6.6 35.867 m
+4.6 34.367 l
+S
+6.1 12.867 m
+1.85 13.617 l
+S
+4.6 30.617 m
+1.6 30.617 l
+S
+72.814 74.769 m
+73.928 77.729 l
+S
+67.976 74.633 m
+67.35 77.909 l
+S
+52.762 73.779 m
+52.876 76.776 l
+S
+37.062 75.375 m
+35.639 77.43 l
+S
+20.795 75.242 m
+22.12 77.193 l
+S
+9.736 73.91 m
+8.073 76.225 l
+S
+10.1 23.617 m
+6.35 24.367 l
+S
+73.217 18.276 m
+71.323 21.1 l
+S
+28.823 39.6 m
+29.505 42.389 l
+S
+49.6 38.617 m
+47.6 37.117 l
+S
+60.323 73.6 m
+62.323 76.6 l
+S
+60.323 1.6 m
+62.323 4.6 l
+S
+%AI6_EndPatternLayer
+) &
+] E
+%AI3_EndPattern
+%AI3_BeginPattern: (Leaves - Fall )
+(Leaves - Fall ) 0 0 64.0781 78.9336 [
+%AI3_Tile
+(0 O 0 R 0.05 0.2 1 0 k
+ 0.05 0.2 1 0 K
+) @
+(
+%AI6_BeginPatternLayer
+800 Ar
+0 J 0 j 1 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+64.0781 78.9336 m
+64.0781 0 L
+0 0 L
+0 78.9336 L
+64.0781 78.9336 L
+f
+%AI6_EndPatternLayer
+) &
+(0 O 0 R 0.83 0 1 0 k
+ 0.83 0 1 0 K
+) @
+(
+%AI6_BeginPatternLayer
+800 Ar
+0 J 0 j 1 w 4 M []0 d
+%AI3_Note:
+1 D
+0 XR
+29.7578 0.9902 m
+30.4346 1.1914 30.7246 1.3428 V
+29.2559 4.0547 33.707 8.3359 34.627 9.0762 C
+35.2275 8.8506 35.3477 6.3184 34.6699 4.9805 C
+35.5137 5.1035 37.7031 3.7256 38.4609 2.4365 C
+38.5254 3.125 40.0957 6.0664 40.9219 6.4434 C
+40.002 6.8408 39.3359 8.3135 38.5742 9.7617 C
+39.5957 9.9287 40.9961 9.0078 42.4668 8.1025 C
+42.9814 8.9043 44.3555 9.875 45.6143 10.3916 C
+44.5264 11.0781 44.0313 11.8203 43.5352 13.2793 C
+42.4922 12.7139 40.3057 12.5645 39.7764 12.8516 C
+40.291 13.9648 42.5371 14.5078 43.2676 14.4551 C
+43.0137 15.3164 42.8652 17.4697 43.0391 20.0625 C
+41.3789 18.7461 39.834 17.4297 38.1738 17.4883 C
+38.4434 16.0664 37.8076 14.2607 37.4307 13.7676 C
+36.8574 14.5117 36.4463 15.3389 36.8008 17.3164 C
+35.3486 17.8008 34.1113 18.3467 32.7373 19.6045 C
+32.7373 17.7734 32.166 16.5723 31.2969 15.2959 C
+32.5576 14.8076 33.8301 13.6045 33.8252 12.5664 C
+32.9775 12.7178 31.2852 13.4619 30.793 14.4551 C
+30.0742 13.707 28.3906 12.3984 26.7871 12.3945 C
+27.9746 11.5391 28.8945 10.5059 28.9893 8.5938 C
+30.2422 9.5645 32.6953 10.1797 34.0752 9.582 C
+29.2344 5.3457 29.7031 2.3125 29.7578 0.9902 C
+f
+13.8525 29.9844 m
+13.3281 29.5127 13.1309 29.25 V
+15.623 27.4326 13.3691 21.6074 12.8555 20.5439 C
+12.2168 20.4883 10.8096 23.2285 10.8457 24.7266 C
+9.7129 23.9707 8.0488 24.0918 6.4463 24.3779 C
+7.0186 23.2891 6.6172 21.3447 5.8164 20.5439 C
+6.8184 20.5801 8.1699 19.8652 9.4785 18.8838 C
+8.6436 18.0645 6.8164 18.2246 4.9004 18.8838 C
+4.9004 17.5107 4.0781 15.7734 3.2412 14.5918 C
+4.5576 14.6484 5.7031 13.9629 6.5605 12.9316 C
+7.2256 14.5 9.2598 15.6133 10.166 15.5645 C
+10.1826 14.1992 8.6094 12.1094 7.5879 11.7109 C
+8.1875 11.041 9.207 9.5107 10.166 7.0947 C
+10.9648 9.0205 12.1348 10.2627 13.3672 11.1953 C
+12.2256 12.7578 12.3994 13.6289 12.7988 15.1074 C
+13.541 14.5664 14.5723 14.1338 14.7441 12.1309 C
+16.4609 12.416 17.5957 12.3447 19.0938 11.4434 C
+18.6387 13.1055 18.6348 14.707 18.9551 16.4063 C
+17.1055 16.2666 15.5449 16.4795 14.5156 17.9688 C
+15.3457 18.1953 17.6055 18.2549 18.4795 17.3223 C
+18.8066 18.3047 19.7012 19.7109 21.1475 20.4043 C
+19.707 20.6641 18.7227 21.7637 17.8135 23.4492 C
+17.1006 22.0332 14.873 20.3691 13.3711 20.3145 C
+15.373 24.3779 15.373 27.2959 13.8525 29.9844 C
+f
+41.2324 26.0742 m
+41.5518 26.7021 41.7549 26.959 V
+44.1523 25.0176 48.958 28.3262 49.8535 29.0957 C
+49.7432 29.7266 47.6182 30.8643 45.9004 29.834 C
+46.3408 31.123 45.4395 33.084 44.2402 34.126 C
+45.9805 34.0254 48.126 35.3867 48.6484 36.1289 C
+48.8701 35.1514 50.0527 33.8809 51.3379 32.8672 C
+51.6895 33.8398 50.9941 35.958 50.0781 37.5605 C
+51.3125 38.0605 52.4248 38.9912 52.8828 40.25 C
+53.3398 38.9336 54.3428 38.2598 55.6875 37.5039 C
+54.5273 36.0762 53.7471 33.9023 54.0273 33.0391 C
+55.3496 33.374 56.9209 36.0918 57.0439 37.1816 C
+57.9189 36.415 59.4727 35.7285 62.0537 35.4219 C
+60.3535 34.3438 59.9902 32.3516 59.4063 30.9219 C
+58.2588 31.3682 56.0898 31.4277 55.1152 30.8643 C
+55.8281 30.2852 57.168 29.7344 59.1777 29.7207 C
+59.1777 28.1758 59.6406 27.043 60.8945 25.8281 C
+59.1719 25.8418 57.0723 25.3555 55.5762 24.9629 C
+55.3281 26.292 54.4844 27.8887 53.3398 28.2891 C
+53.334 27.4277 53.5996 25.1797 54.4844 24.5117 C
+53.6201 23.9443 52.3672 22.5674 51.9102 20.8496 C
+51.2881 22.1758 50.4268 23.4805 48.5645 23.9238 C
+49.749 24.9766 50.584 26.9941 50.25 28.4609 C
+45.1973 24.4785 42.5215 25.7773 41.2324 26.0742 C
+f
+27.7578 38.7324 m
+28.4346 38.9316 28.7246 39.084 V
+27.2559 41.7969 31.707 46.0776 32.627 46.8169 C
+33.2275 46.5918 33.3477 44.0586 32.6699 42.7227 C
+33.5137 42.8457 35.7031 41.4678 36.4609 40.1787 C
+36.5254 40.8652 38.0957 43.8066 38.9219 44.1846 C
+38.002 44.582 37.3359 46.0547 36.5742 47.5039 C
+37.5957 47.6709 38.9961 46.7485 40.4668 45.8438 C
+40.9814 46.6445 42.3555 47.6177 43.6143 48.1328 C
+42.5264 48.8198 42.0313 49.5615 41.5352 51.0205 C
+40.4922 50.4556 38.3057 50.3057 37.7764 50.5938 C
+38.291 51.7056 40.5371 52.2485 41.2676 52.1958 C
+41.0137 53.0576 40.8652 55.2109 41.0391 57.8037 C
+39.3789 56.4878 37.834 55.1719 36.1738 55.2285 C
+36.4434 53.8076 35.8076 52.002 35.4307 51.5088 C
+34.8574 52.2529 34.4463 53.0796 34.8008 55.0576 C
+33.3486 55.5425 32.1113 56.0879 30.7373 57.3467 C
+30.7373 55.5146 30.166 54.314 29.2969 53.0366 C
+30.5576 52.5488 31.8301 51.3467 31.8252 50.3076 C
+30.9775 50.46 29.2852 51.2036 28.793 52.1958 C
+28.0742 51.4497 26.3906 50.1396 24.7871 50.1357 C
+25.9746 49.2817 26.8945 48.2466 26.9893 46.335 C
+28.2422 47.3057 30.6953 47.9209 32.0752 47.3237 C
+27.2344 43.0869 27.7031 40.0547 27.7578 38.7324 C
+f
+13.5195 70.3916 m
+12.9941 69.9209 12.7988 69.6587 V
+15.2891 67.8418 13.0352 62.0146 12.5225 60.9517 C
+11.8828 60.8955 10.4766 63.6367 10.5117 65.1348 C
+9.3809 64.3789 7.7148 64.4995 6.1133 64.7856 C
+6.6855 63.6987 6.2842 61.7529 5.4834 60.9517 C
+6.4854 60.9878 7.8359 60.2729 9.1455 59.2925 C
+8.3105 58.4717 6.4834 58.6338 4.5674 59.2925 C
+4.5674 57.9189 3.7461 56.1816 2.9082 54.9995 C
+4.2246 55.0576 5.3691 54.3706 6.2275 53.3408 C
+6.8926 54.9097 8.9258 56.0215 9.832 55.9727 C
+9.8496 54.6079 8.2764 52.5176 7.2539 52.1187 C
+7.8545 51.4497 8.873 49.9189 9.832 47.5039 C
+10.6309 49.4297 11.8008 50.6719 13.0342 51.6045 C
+11.8926 53.1655 12.0664 54.0366 12.4648 55.5146 C
+13.209 54.9746 14.2393 54.5415 14.4102 52.5386 C
+16.127 52.8247 17.2637 52.7529 18.7598 51.8525 C
+18.3057 53.5137 18.3027 55.1147 18.623 56.8149 C
+16.7725 56.6748 15.2129 56.8887 14.1826 58.377 C
+15.0117 58.6035 17.2725 58.6626 18.1465 57.731 C
+18.4736 58.7129 19.3691 60.1187 20.8145 60.8125 C
+19.375 61.0728 18.3896 62.1719 17.4805 63.8579 C
+16.7676 62.4429 14.541 60.7769 13.0371 60.7227 C
+15.041 64.7856 15.041 67.7046 13.5195 70.3916 C
+f
+41.2324 64.4824 m
+41.5518 65.1113 41.7549 65.3682 V
+44.1523 63.4272 48.958 66.7354 49.8535 67.5034 C
+49.7432 68.1362 47.6182 69.2725 45.9004 68.2422 C
+46.3408 69.5313 45.4395 71.4922 44.2402 72.5342 C
+45.9805 72.4341 48.126 73.7954 48.6484 74.5371 C
+48.8701 73.5601 50.0527 72.29 51.3379 71.2754 C
+51.6895 72.249 50.9941 74.3662 50.0781 75.9683 C
+51.3125 76.4692 52.4248 77.3994 52.8828 78.6582 C
+53.3398 77.3423 54.3428 76.667 55.6875 75.9111 C
+54.5273 74.4844 53.7471 72.3101 54.0273 71.4473 C
+55.3496 71.7822 56.9209 74.5 57.0439 75.5903 C
+57.9189 74.8232 59.4727 74.1372 62.0537 73.8311 C
+60.3535 72.7534 59.9902 70.7612 59.4063 69.3301 C
+58.2588 69.7773 56.0898 69.8364 55.1152 69.2725 C
+55.8281 68.6934 57.168 68.1431 59.1777 68.1284 C
+59.1777 66.583 59.6406 65.4512 60.8945 64.2373 C
+59.1719 64.249 57.0723 63.7632 55.5762 63.3721 C
+55.3281 64.7002 54.4844 66.2974 53.3398 66.6973 C
+53.334 65.8364 53.5996 63.5874 54.4844 62.9214 C
+53.6201 62.353 52.3672 60.9751 51.9102 59.2583 C
+51.2881 60.583 50.4268 61.8882 48.5645 62.333 C
+49.749 63.3862 50.584 65.4033 50.25 66.8691 C
+45.1973 62.8872 42.5215 64.1851 41.2324 64.4824 C
+f
+%AI6_EndPatternLayer
+) &
+] E
+%AI3_EndPattern
+%AI3_BeginPattern: (Stripes)
+(Stripes) 8.45 4.6001 80.45 76.6001 [
+%AI3_Tile
+(0 O 0 R 1 0.07 1 0 k
+ 1 0.07 1 0 K
+) @
+(
+%AI6_BeginPatternLayer
+800 Ar
+0 J 0 j 3.6 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+8.2 8.2 m
+80.7 8.2 L
+S
+8.2 22.6001 m
+80.7 22.6001 L
+S
+8.2 37.0002 m
+80.7 37.0002 L
+S
+8.2 51.4 m
+80.7 51.4 L
+S
+8.2 65.8001 m
+80.7 65.8001 L
+S
+8.2 15.4 m
+80.7 15.4 L
+S
+8.2 29.8001 m
+80.7 29.8001 L
+S
+8.2 44.2 m
+80.7 44.2 L
+S
+8.2 58.6001 m
+80.7 58.6001 L
+S
+8.2 73.0002 m
+80.7 73.0002 L
+S
+%AI6_EndPatternLayer
+) &
+] E
+%AI3_EndPattern
+%AI5_End_NonPrinting--
+%AI5_Begin_NonPrinting
+Np
+%AI8_BeginBrushPattern
+(New Pattern 1)
+0 A
+u
+1 Ap
+800 Ar
+0 J 0 j 1 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+-7834.75 8587 m
+-7834.75 8563 L
+-7884.75 8563 L
+-7884.75 8587 L
+-7834.75 8587 L
+n
+u
+0 Ap
+0 O
+1 g
+-7854.75 8585 m
+-7866.96 8588.0527 -7875.4434 8578.0605 -7884.75 8570.9512 C
+F
+-7844.75 8585 m
+-7861.1279 8589.0947 -7870.8008 8569.7227 -7884.75 8565.3154 C
+F
+-7884.75 8565 m
+-7864.75 8560 -7854.75 8590 -7834.75 8585 C
+F
+-7874.75 8565 m
+-7858.3721 8560.9053 -7848.6992 8580.2773 -7834.75 8584.6846 C
+F
+-7864.75 8565 m
+-7852.54 8561.9473 -7844.0566 8571.9395 -7834.75 8579.0488 C
+F
+-7844.75 8565 m
+-7841.1279 8564.0947 -7837.835 8564.3408 -7834.75 8565.3154 C
+F
+-7874.75 8585 m
+-7878.3721 8585.9053 -7881.665 8585.6592 -7884.75 8584.6846 C
+F
+-7844.7817 8565.125 m
+-7850.9009 8563.6162 -7854.7817 8565.125 V
+-7858.877 8563.6484 -7864.7817 8565.125 V
+-7869.7446 8563.4492 -7874.7817 8565.125 V
+-7880.7969 8563.5742 -7884.7817 8565.125 V
+-7884.7817 8584.8096 L
+-7881.6958 8585.7842 -7878.2969 8585.9912 -7874.3799 8584.9082 C
+-7868.2134 8586.4912 -7864.4634 8584.9082 V
+-7859.4634 8586.4912 -7854.3799 8584.8242 V
+-7850.0474 8586.4082 -7844.3799 8584.9082 V
+-7838.8799 8586.3242 -7834.7817 8585.125 V
+-7834.7817 8565.4404 L
+-7837.5254 8564.4287 -7840.6514 8563.9287 -7844.7817 8565.125 C
+f
+0 R
+0 G
+1 J 1 j 0.5 w
+-7864.75 8585 m
+-7872.54 8586.9473 -7878.813 8583.585 -7884.75 8579.0488 C
+S
+-7854.75 8585 m
+-7866.96 8588.0527 -7875.4434 8578.0605 -7884.75 8570.9512 C
+S
+-7844.75 8585 m
+-7861.1279 8589.0947 -7870.8008 8569.7227 -7884.75 8565.3154 C
+S
+-7884.75 8565 m
+-7864.75 8560 -7854.75 8590 -7834.75 8585 C
+S
+-7874.75 8565 m
+-7858.3721 8560.9053 -7848.6992 8580.2773 -7834.75 8584.6846 C
+S
+-7864.75 8565 m
+-7852.54 8561.9473 -7844.0566 8571.9395 -7834.75 8579.0488 C
+S
+-7854.75 8565 m
+-7846.96 8563.0527 -7840.687 8566.415 -7834.75 8570.9512 C
+S
+-7844.75 8565 m
+-7841.1279 8564.0947 -7837.835 8564.3408 -7834.75 8565.3154 C
+S
+-7874.75 8585 m
+-7878.3721 8585.9053 -7881.665 8585.6592 -7884.75 8584.6846 C
+S
+U
+U
+%AI8_EndBrushPattern
+%AI8_BeginBrushPattern
+(New Pattern 2)
+0 A
+u
+800 Ar
+0 J 0 j 1 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+-7884 8586 m
+-7819.187 8586 L
+-7819.187 8521.9023 L
+-7884 8521.9023 L
+-7884 8586 L
+n
+u
+0 O
+0 g
+-7849.6978 8544.4297 m
+-7851.6094 8521.9023 L
+-7853.5215 8544.4297 L
+-7852.9033 8544.3066 -7852.2642 8544.2402 -7851.6094 8544.2402 c
+-7850.9551 8544.2402 -7850.3159 8544.3066 -7849.6978 8544.4297 C
+f
+-7861.2402 8552.3975 m
+-7884 8554.3301 L
+-7861.1138 8556.2734 L
+-7861.2856 8555.5469 -7861.3848 8554.793 -7861.3848 8554.0156 c
+-7861.3848 8553.4629 -7861.3281 8552.9248 -7861.2402 8552.3975 C
+f
+-7856.519 8545.5723 m
+-7870.1626 8536.8047 L
+-7860.2153 8549.377 L
+-7859.3574 8547.791 -7858.0718 8546.4766 -7856.519 8545.5723 C
+f
+-7853.481 8563.6074 m
+-7851.5786 8586 L
+-7849.6768 8563.5967 L
+-7850.3018 8563.7227 -7850.9473 8563.791 -7851.6094 8563.791 c
+-7852.25 8563.791 -7852.873 8563.7246 -7853.481 8563.6074 C
+f
+-7841.9609 8555.5068 m
+-7819.187 8553.5732 L
+-7842.083 8551.6289 L
+-7842.083 8551.8506 L
+-7841.9258 8552.5488 -7841.834 8553.2695 -7841.834 8554.0156 c
+-7841.834 8554.5234 -7841.8848 8555.0195 -7841.9609 8555.5068 C
+f
+-7860.1138 8558.8262 m
+-7870.1641 8571.5293 L
+-7856.2778 8562.6055 L
+-7857.8823 8561.7305 -7859.2114 8560.416 -7860.1138 8558.8262 C
+f
+-7842.9961 8549.3945 m
+-7832.875 8536.6055 L
+-7846.7666 8545.5313 L
+-7845.1768 8546.4414 -7843.8633 8547.7793 -7842.9961 8549.3945 C
+f
+-7846.6895 8562.4512 m
+-7832.873 8571.3281 L
+-7842.9658 8558.5732 L
+-7843.8198 8560.1895 -7845.1152 8561.5313 -7846.6895 8562.4512 C
+f
+-7842.8887 8558.6133 m
+-7842.3862 8557.6641 -7842.043 8556.6211 -7841.875 8555.5195 c
+-7841.7993 8555.0293 -7841.748 8554.5273 -7841.748 8554.0156 c
+-7841.748 8553.2637 -7841.8398 8552.5352 -7841.998 8551.8311 c
+-7842.1958 8550.957 -7842.5049 8550.124 -7842.918 8549.3545 c
+-7843.7954 8547.7246 -7845.1191 8546.374 -7846.7241 8545.4561 c
+-7847.6294 8544.9375 -7848.6226 8544.5537 -7849.6802 8544.3457 c
+-7850.3047 8544.2207 -7850.9497 8544.1523 -7851.6094 8544.1523 c
+-7852.2695 8544.1523 -7852.915 8544.2207 -7853.5391 8544.3457 c
+-7854.623 8544.5605 -7855.6382 8544.957 -7856.5625 8545.4961 c
+-7858.1313 8546.4102 -7859.4282 8547.7363 -7860.291 8549.335 c
+-7860.7969 8550.2695 -7861.145 8551.2969 -7861.3262 8552.3828 c
+-7861.415 8552.916 -7861.4727 8553.459 -7861.4727 8554.0156 c
+-7861.4727 8554.8008 -7861.3711 8555.5605 -7861.1978 8556.293 c
+-7860.981 8557.207 -7860.6406 8558.0732 -7860.187 8558.8701 c
+-7859.2793 8560.4727 -7857.939 8561.8008 -7856.3174 8562.6826 c
+-7855.4487 8563.1553 -7854.5 8563.498 -7853.4961 8563.6934 c
+-7852.8848 8563.8115 -7852.2554 8563.8779 -7851.6094 8563.8779 c
+-7850.9414 8563.8779 -7850.29 8563.8086 -7849.6602 8563.6826 c
+-7848.5786 8563.4668 -7847.5664 8563.0654 -7846.6455 8562.5273 c
+-7845.0566 8561.5977 -7843.751 8560.2441 -7842.8887 8558.6133 c
+f
+U
+U
+%AI8_EndBrushPattern
+%AI8_BeginBrushPattern
+(New Pattern 3)
+0 A
+u
+1 Ap
+800 Ar
+0 J 0 j 1 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+-7874.75 8587 m
+-7874.75 8563 L
+-7884.75 8563 L
+-7884.75 8587 L
+-7874.75 8587 L
+n
+u
+u
+0 Ap
+0 O
+1 g
+-7875.4058 8578.5361 m
+-7874.9878 8577.4355 -7874.75 8576.2471 -7874.75 8575 c
+-7874.75 8573.1377 -7875.2681 8571.4004 -7876.1543 8569.9072 c
+-7877.897 8566.9736 -7881.0898 8565 -7884.75 8565 C
+-7884.75 8585 L
+-7884.4297 8585 -7884.1143 8584.9814 -7883.8018 8584.9521 c
+-7881.9121 8584.7754 -7880.1807 8584.0645 -7878.7441 8582.9824 c
+-7877.2471 8581.8545 -7876.0801 8580.3184 -7875.4058 8578.5361 c
+f
+0 R
+0 G
+1 J 1 j 0.5 w
+-7884.75 8565.3174 m
+-7881.7207 8566.2744 -7878.8926 8567.9326 -7876.1543 8569.9072 C
+S
+-7884.75 8570.9512 m
+-7881.5991 8573.3564 -7878.543 8576.0869 -7875.4058 8578.5361 C
+S
+-7878.7441 8582.9824 m
+-7880.8105 8581.8916 -7882.7993 8580.5342 -7884.75 8579.043 C
+S
+-7883.8018 8584.9521 m
+-7884.1191 8584.8682 -7884.4375 8584.7852 -7884.75 8584.6865 C
+S
+-7878.7441 8582.9824 m
+-7880.1807 8584.0645 -7881.9121 8584.7744 -7883.8018 8584.9521 C
+S
+-7875.4058 8578.5361 m
+-7874.9878 8577.4355 -7874.75 8576.2471 -7874.75 8575 c
+-7874.75 8573.1377 -7875.2681 8571.4004 -7876.1543 8569.9072 C
+S
+-7884.75 8585 m
+-7884.4297 8585 -7884.1143 8584.9814 -7883.8018 8584.9521 C
+S
+-7878.7441 8582.9824 m
+-7877.2471 8581.8545 -7876.0801 8580.3184 -7875.4058 8578.5361 C
+S
+-7876.1543 8569.9072 m
+-7877.8975 8566.9736 -7881.0898 8565 -7884.75 8565 C
+S
+U
+U
+U
+%AI8_EndBrushPattern
+%AI8_BeginBrushPattern
+(New Pattern 5)
+0 A
+u
+800 Ar
+0 J 0 j 1 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+-7726.3994 8587 m
+-7726.3994 8573.4199 L
+-7885 8573.4199 L
+-7885 8587 L
+-7726.3994 8587 L
+n
+u
+u
+0 O
+0.285 0.228 0.171 0 k
+-7741.0786 8585.4844 m
+-7741.043 8586.6895 L
+-7727.5103 8587.5176 -7726.8418 8586.2822 v
+-7726.7441 8586.1016 -7726.647 8585.7148 -7726.561 8585.1934 C
+-7728.584 8585.8242 -7738.291 8585.5713 -7741.0786 8585.4844 C
+f
+0.44 0.352 0.264 0 k
+-7741.4063 8574.0234 m
+-7741.3711 8575.2676 L
+-7738.4912 8575.0488 -7728.1914 8574.3164 -7726.543 8574.8652 C
+-7726.7031 8574.2188 -7726.9199 8573.7646 -7727.2046 8573.6152 c
+-7728.8306 8572.7656 -7741.4063 8574.0234 Y
+f
+0.145 0.116 0.087 0 k
+-7741.3711 8575.2676 m
+-7741.0786 8585.4844 L
+-7738.291 8585.5713 -7728.584 8585.8242 -7726.561 8585.1934 C
+-7726.1519 8582.7773 -7725.9258 8577.3604 -7726.543 8574.8652 C
+-7728.1914 8574.3164 -7738.4912 8575.0488 -7741.3711 8575.2676 C
+f
+U
+u
+0.155 0.124 0.093 0 k
+-7766.9375 8579.2734 m
+-7765.897 8579.6563 L
+-7747.0728 8575.1465 L
+-7747.481 8574.3145 L
+-7766.3633 8576.7246 L
+-7767.252 8577.0059 L
+-7767.6504 8576.8936 -7768.1934 8576.8242 V
+-7767.6094 8577.2373 -7767.1426 8578.1406 -7766.9375 8579.2734 C
+f
+u
+0.085 0.068 0.051 0 k
+-7771.7993 8583.666 m
+-7772.5977 8583.7217 -7769.749 8583.6641 Y
+-7770.3481 8583.0176 -7770.771 8581.8203 -7770.8105 8580.4375 c
+-7770.8169 8580.2246 -7770.8105 8580.0176 -7770.7993 8579.8135 C
+-7771.041 8579.707 -7771.0918 8579.7734 -7771.6289 8579.5645 C
+-7771 8583.6113 -7771.7993 8583.666 v
+f
+0.305 0.244 0.183 0 k
+-7770.3442 8576.8672 m
+-7770.5527 8576.8105 -7770.4937 8578.9307 Y
+-7769.4785 8579.7588 L
+-7767.8359 8578.9434 L
+-7766.9375 8579.2734 L
+-7767.1426 8578.1406 -7767.6094 8577.2373 -7768.1934 8576.8242 C
+-7768.6094 8576.7715 -7769.874 8576.7998 -7770.3442 8576.8672 C
+f
+U
+0.115 0.092 0.069 0 k
+-7766.9375 8579.2734 m
+-7767.8359 8578.9434 L
+-7769.4785 8579.7588 L
+-7770.4937 8578.9307 L
+-7770.793 8579.708 -7770.7993 8579.8135 V
+-7769.5137 8580.3789 -7768.1831 8580.7402 -7766.8398 8580.9258 C
+-7766.79 8580.7275 -7766.7842 8580.543 -7766.79 8580.3369 c
+-7766.7998 8579.9717 -7766.8218 8579.6182 -7766.9375 8579.2734 C
+f
+0.41 0.328 0.246 0 k
+-7747.4512 8575.3965 m
+-7749.377 8576.6426 -7758.3862 8582.0986 -7766.8398 8580.9258 C
+-7766.9038 8582.0928 -7767.248 8583.0908 -7767.75 8583.6631 C
+-7767.1895 8583.6621 L
+-7746.7402 8586.7559 L
+-7747.0366 8576.4258 L
+-7747.0728 8575.1465 L
+-7747.2046 8575.2373 -7747.4512 8575.3965 v
+f
+0.395 0.316 0.237 0 k
+-7770.8105 8580.4375 m
+-7770.771 8581.8203 -7770.3481 8583.0176 -7769.749 8583.6641 C
+-7767.6807 8583.6631 L
+-7767.1782 8583.0908 -7766.8218 8582.0713 -7766.8398 8580.9258 C
+-7768.1831 8580.7402 -7769.5137 8580.3789 -7770.7993 8579.8135 C
+-7770.8105 8580.0176 -7770.8169 8580.2246 -7770.8105 8580.4375 c
+f
+U
+u
+0 0 0 0.11 k
+-7741.2642 8574.2012 m
+-7740.2407 8574.0352 L
+-7741.2642 8574.2012 L
+-7741.2642 8574.2012 L
+f
+0 0 0 0.34 k
+-7747.481 8574.3145 m
+-7747.0728 8575.1465 L
+-7745.6714 8574.918 L
+-7744.5234 8574.7314 L
+-7742.6758 8574.4307 L
+-7741.2642 8574.2012 L
+-7740.2407 8574.0352 L
+-7740.2954 8573.7168 -7740.3672 8573.498 -7740.4648 8573.4199 C
+-7747.481 8574.3145 L
+f
+0 0 0 0.32 k
+-7745.8042 8579.207 m
+-7746.041 8586.8613 L
+-7740.7144 8587 L
+-7739.7266 8583.5146 -7740.1816 8579.1543 V
+-7745.8042 8579.207 L
+f
+U
+0.025 0.02 0.015 0 k
+-7739.3223 8576.3848 m
+-7736.373 8576.9199 -7733.2402 8577.1602 -7730.3159 8576.3613 c
+-7730.2856 8576.3496 -7730.2754 8576.3184 -7730.2871 8576.2969 c
+-7730.2881 8576.2656 -7730.3198 8576.2559 -7730.3418 8576.2559 c
+-7733.2422 8577.0645 -7736.375 8576.8242 -7739.3042 8576.2783 c
+-7739.3262 8576.2793 -7739.3574 8576.291 -7739.3672 8576.3223 c
+-7739.3662 8576.3438 -7739.355 8576.375 -7739.3223 8576.3848 c
+-7739.3223 8576.3848 l
+f
+-7737.8374 8575.3076 m
+-7737.7295 8575.3789 -7737.6313 8575.4941 -7737.5234 8575.502 c
+-7733.7886 8575.832 -7730.1631 8575.7813 -7726.4746 8575.6641 c
+-7726.4526 8575.6641 -7726.4209 8575.6426 -7726.4214 8575.6211 c
+-7726.4214 8575.5879 -7726.4551 8575.5684 -7726.4766 8575.5684 c
+-7729.3223 8575.6816 -7732.1401 8575.6992 -7735.0039 8575.5352 c
+-7735.9336 8575.4766 -7736.9082 8575.7402 -7737.7778 8575.2207 c
+-7737.7993 8575.2109 -7737.8306 8575.2109 -7737.8506 8575.2334 c
+-7737.8618 8575.2559 -7737.8594 8575.2871 -7737.8374 8575.3076 c
+-7737.8374 8575.3076 l
+f
+-7733.373 8577.3672 m
+-7731.5098 8578.6797 -7729.3022 8579.374 -7727.1001 8579.8867 c
+-7727.0679 8579.8965 -7727.0474 8579.8848 -7727.0366 8579.8535 c
+-7727.0273 8579.8203 -7727.0488 8579.8008 -7727.0703 8579.79 c
+-7729.2617 8579.2656 -7731.459 8578.6035 -7733.3105 8577.2803 c
+-7733.3433 8577.2598 -7733.375 8577.2715 -7733.3848 8577.293 c
+-7733.4058 8577.3145 -7733.3945 8577.3457 -7733.373 8577.3672 c
+-7733.373 8577.3672 l
+f
+-7738.9321 8584.0566 m
+-7736.7295 8584.5703 -7734.5298 8585.0303 -7732.2798 8585.2754 c
+-7732.2598 8585.2852 -7732.229 8585.2637 -7732.229 8585.2422 c
+-7732.2183 8585.209 -7732.2407 8585.1777 -7732.2729 8585.1787 c
+-7734.5122 8584.8809 -7736.7305 8584.5176 -7738.9126 8583.9502 c
+-7738.9351 8583.9512 -7738.9673 8583.9629 -7738.9766 8583.9941 c
+-7738.9751 8584.0156 -7738.9648 8584.0479 -7738.9321 8584.0566 c
+-7738.9321 8584.0566 l
+f
+-7738.439 8583.3604 m
+-7736.3457 8584.1973 -7734.1016 8583.9297 -7731.9023 8583.9629 c
+-7731.8706 8583.9609 -7731.8496 8583.9395 -7731.8506 8583.9082 c
+-7731.8521 8583.875 -7731.873 8583.8555 -7731.8945 8583.8555 c
+-7734.0928 8583.8438 -7736.3374 8584.0996 -7738.4209 8583.2529 c
+-7738.4434 8583.2539 -7738.4746 8583.2656 -7738.4834 8583.2969 c
+-7738.4834 8583.3184 -7738.4722 8583.3506 -7738.439 8583.3604 c
+-7738.439 8583.3604 l
+f
+-7737.707 8584.7051 m
+-7736.3833 8584.752 -7735.1504 8584.5469 -7733.8271 8584.209 c
+-7733.3594 8584.0996 -7732.9199 8584.2266 -7732.4609 8584.2129 c
+-7731.897 8584.1973 l
+-7731.874 8584.1963 -7731.8633 8584.1855 -7731.8535 8584.1738 c
+-7731.834 8584.1523 -7731.8442 8584.1211 -7731.8662 8584.0996 c
+-7732.0625 8583.9453 l
+-7732.0742 8583.9453 -7732.085 8583.9355 -7732.0962 8583.9355 c
+-7732.5 8583.9473 l
+-7733.9551 8584.1914 -7735.457 8584.6719 -7736.8926 8584.0742 c
+-7736.9258 8584.0645 -7736.957 8584.0859 -7736.9673 8584.1074 c
+-7736.9673 8584.1396 -7736.9551 8584.1602 -7736.9336 8584.1709 c
+-7735.647 8584.6992 -7734.1714 8584.4756 -7732.8818 8584.0547 c
+-7732.0918 8584.043 L
+-7732.124 8584.0332 L
+-7731.9282 8584.1875 L
+-7731.8984 8584.0898 L
+-7732.4639 8584.1064 l
+-7732.9321 8584.1406 -7733.3848 8583.9834 -7733.8398 8584.1035 c
+-7735.1543 8584.4609 -7736.3975 8584.625 -7737.71 8584.5986 c
+-7737.7422 8584.5996 -7737.7642 8584.6211 -7737.7617 8584.6533 c
+-7737.7617 8584.6855 -7737.7402 8584.7061 -7737.707 8584.7051 c
+-7737.707 8584.7051 l
+f
+-7738.5718 8585.0605 m
+-7735.8711 8586.2207 -7732.9023 8585.5703 -7730.1279 8585.1816 c
+-7729.7832 8585.2891 l
+-7729.7617 8585.2988 -7729.7417 8585.2871 -7729.7207 8585.2656 c
+-7729.71 8585.2441 -7729.7217 8585.2129 -7729.7422 8585.2021 c
+-7730.0801 8585.0098 l
+-7732.7754 8584.3926 -7735.5391 8584.7813 -7738.271 8584.7852 c
+-7738.3022 8584.7871 -7738.3232 8584.8086 -7738.3223 8584.8398 c
+-7738.3198 8584.8721 -7738.2983 8584.8926 -7738.2681 8584.8926 c
+-7735.6738 8584.9355 -7733.0303 8584.4434 -7730.4727 8585.0742 c
+-7729.7954 8585.2891 L
+-7729.7534 8585.1914 L
+-7730.1406 8585.0859 l
+-7732.9058 8585.4424 -7735.8418 8586.1348 -7738.5313 8584.9746 c
+-7738.5537 8584.9648 -7738.585 8584.9648 -7738.5962 8584.998 c
+-7738.6055 8585.0195 -7738.605 8585.0508 -7738.5718 8585.0605 c
+-7738.5718 8585.0605 l
+f
+-7735.6895 8578.3945 m
+-7734.3945 8578.9004 -7732.9834 8578.6465 -7731.6802 8578.3438 c
+-7731.647 8578.3418 -7731.6367 8578.3203 -7731.6382 8578.2891 c
+-7731.6504 8578.2568 -7731.6714 8578.2461 -7731.7031 8578.248 c
+-7732.998 8578.5303 -7734.377 8578.8154 -7735.6504 8578.2969 c
+-7735.6826 8578.2871 -7735.7144 8578.2988 -7735.7246 8578.3311 c
+-7735.7222 8578.3525 -7735.7114 8578.3848 -7735.6895 8578.3945 c
+-7735.6895 8578.3945 l
+f
+-7736.1401 8580.2207 m
+-7734.2266 8580.6895 -7732.3145 8581.1035 -7730.355 8581.3242 c
+-7730.3242 8581.334 -7730.3022 8581.3125 -7730.293 8581.2803 c
+-7730.2954 8581.2598 -7730.3159 8581.2285 -7730.3374 8581.2285 c
+-7732.2959 8581.0078 -7734.209 8580.582 -7736.1206 8580.1133 c
+-7736.1426 8580.1152 -7736.1738 8580.126 -7736.1831 8580.1582 c
+-7736.1831 8580.1797 -7736.1719 8580.2109 -7736.1401 8580.2207 c
+-7736.1401 8580.2207 l
+f
+-7736.9336 8582.6348 m
+-7734.499 8583.4609 -7731.8647 8583.0547 -7729.3457 8583.0879 c
+-7729.313 8583.0879 -7729.293 8583.0664 -7729.293 8583.0332 c
+-7729.2954 8583.0117 -7729.3159 8582.9922 -7729.3481 8582.9922 c
+-7731.8574 8582.916 -7734.481 8583.3848 -7736.8945 8582.5264 c
+-7736.9282 8582.5273 -7736.959 8582.5391 -7736.9688 8582.5605 c
+-7736.9678 8582.5918 -7736.9561 8582.624 -7736.9336 8582.6348 c
+-7736.9336 8582.6348 l
+f
+-7732.0542 8583.8496 m
+-7730.6582 8584.5449 -7729.0503 8584.4033 -7727.5342 8584.4668 c
+-7727.502 8584.4648 -7727.4824 8584.4434 -7727.4824 8584.4121 c
+-7727.4834 8584.3906 -7727.5054 8584.3594 -7727.5366 8584.3594 c
+-7729.0137 8584.2207 -7730.6489 8584.5234 -7732.0039 8583.7617 c
+-7732.0366 8583.7529 -7732.0679 8583.7637 -7732.0786 8583.7861 c
+-7732.0879 8583.8076 -7732.0767 8583.8398 -7732.0542 8583.8496 c
+-7732.0542 8583.8496 l
+f
+-7731.3418 8580.4248 m
+-7730.3926 8580.3975 -7729.4336 8580.3701 -7728.4839 8580.3428 c
+-7728.4526 8580.3418 -7728.4312 8580.3203 -7728.4336 8580.2881 c
+-7728.4336 8580.2559 -7728.4551 8580.2354 -7728.4878 8580.2363 c
+-7729.437 8580.2637 -7730.397 8580.291 -7731.3457 8580.3184 c
+-7731.377 8580.3184 -7731.3975 8580.3418 -7731.3975 8580.373 c
+-7731.397 8580.4043 -7731.374 8580.4258 -7731.3418 8580.4248 c
+-7731.3418 8580.4248 l
+f
+-7729.1592 8578.0361 m
+-7728.6895 8578.0645 -7728.209 8578.0723 -7727.7383 8578.0918 c
+-7727.7168 8578.0908 -7727.6855 8578.0684 -7727.6865 8578.0371 c
+-7727.687 8578.0039 -7727.71 8577.9844 -7727.7417 8577.9844 c
+-7728.2114 8577.9873 -7728.6816 8577.9375 -7729.1514 8577.9395 c
+-7729.1831 8577.9297 -7729.2031 8577.9512 -7729.2134 8577.9844 c
+-7729.2129 8578.0156 -7729.1914 8578.0371 -7729.1592 8578.0361 c
+-7729.1592 8578.0361 l
+f
+-7736.9702 8580.2344 m
+-7736.5688 8580.5107 -7736.125 8580.6797 -7735.645 8580.751 c
+-7735.6113 8580.7607 -7735.5918 8580.7383 -7735.5806 8580.7168 c
+-7735.5703 8580.6855 -7735.5928 8580.6543 -7735.6152 8580.6543 c
+-7736.0854 8580.5723 -7736.5176 8580.4023 -7736.9209 8580.1475 c
+-7736.9521 8580.1377 -7736.9849 8580.1387 -7736.9946 8580.1709 c
+-7737.0039 8580.1934 -7736.9922 8580.2246 -7736.9702 8580.2344 c
+-7736.9702 8580.2344 l
+f
+-7738.1904 8586.085 m
+-7735.7344 8586.5273 -7733.2983 8587.001 -7730.7993 8586.7266 c
+-7730.7778 8586.7266 -7730.7568 8586.7041 -7730.7578 8586.6719 c
+-7730.7578 8586.6406 -7730.7798 8586.6191 -7730.8022 8586.6191 c
+-7733.291 8586.873 -7735.7344 8586.4844 -7738.1719 8585.9775 c
+-7738.1934 8585.9785 -7738.2256 8585.9902 -7738.2344 8586.0215 c
+-7738.2344 8586.043 -7738.2222 8586.0752 -7738.1904 8586.085 c
+-7738.1904 8586.085 l
+f
+0.195 0.156 0.117 0 k
+-7738.166 8574.6445 m
+-7735.7969 8574.2676 -7733.4058 8574.3477 -7731.0298 8574.5898 c
+-7730.998 8574.5879 -7730.9766 8574.5664 -7730.9766 8574.5352 c
+-7730.9785 8574.5137 -7731 8574.4824 -7731.0215 8574.4824 c
+-7733.4082 8574.2422 -7735.791 8574.1602 -7738.1694 8574.5391 c
+-7738.2026 8574.5391 -7738.2222 8574.5605 -7738.2217 8574.5938 c
+-7738.2207 8574.625 -7738.1992 8574.6465 -7738.166 8574.6445 c
+-7738.166 8574.6445 l
+f
+0.335 0.268 0.201 0 k
+-7737.4351 8574.1113 m
+-7734.9282 8574.1152 -7732.4146 8574.2773 -7729.918 8573.8965 c
+-7729.8862 8573.8945 -7729.8647 8573.873 -7729.8662 8573.8418 c
+-7729.8672 8573.8086 -7729.8896 8573.7891 -7729.9209 8573.7891 c
+-7732.418 8574.1699 -7734.9297 8574.0293 -7737.4375 8574.0059 c
+-7737.46 8574.0059 -7737.481 8574.0273 -7737.4785 8574.0596 c
+-7737.4785 8574.0918 -7737.457 8574.1123 -7737.4351 8574.1113 c
+-7737.4351 8574.1113 l
+f
+0.205 0.164 0.123 0 k
+-7738.9766 8574.3262 m
+-7737.5039 8574.668 -7736.0078 8574.4023 -7734.5391 8574.2207 c
+-7734.5078 8574.2207 -7734.4873 8574.1973 -7734.499 8574.166 c
+-7734.5 8574.1348 -7734.5215 8574.1133 -7734.5537 8574.125 c
+-7736.0103 8574.2842 -7737.4961 8574.583 -7738.9473 8574.2188 c
+-7738.9785 8574.2207 -7739.0103 8574.2324 -7739.0098 8574.2637 c
+-7739.019 8574.2852 -7738.998 8574.3164 -7738.9766 8574.3262 c
+-7738.9766 8574.3262 l
+f
+-7732.3535 8573.7949 m
+-7731.1978 8573.9219 -7730.0273 8573.8145 -7728.8926 8573.5898 c
+-7728.8711 8573.5781 -7728.8506 8573.5566 -7728.8618 8573.5244 c
+-7728.8623 8573.5029 -7728.8945 8573.4824 -7728.916 8573.4941 c
+-7730.0503 8573.7402 -7731.1914 8573.7939 -7732.3462 8573.6885 c
+-7732.3794 8573.6895 -7732.3984 8573.7109 -7732.4087 8573.7324 c
+-7732.4082 8573.7646 -7732.3862 8573.7852 -7732.3535 8573.7949 c
+-7732.3535 8573.7949 l
+f
+0.335 0.268 0.201 0 k
+-7739.2681 8576.4473 m
+-7737.9214 8577.1885 -7736.3066 8576.5977 -7734.855 8576.6416 c
+-7734.8223 8576.6406 -7734.8022 8576.6191 -7734.8022 8576.5859 c
+-7734.8042 8576.5654 -7734.8262 8576.5449 -7734.8574 8576.5449 c
+-7736.2886 8576.4902 -7737.8823 8577.0801 -7739.2168 8576.3506 c
+-7739.2383 8576.3398 -7739.2695 8576.3516 -7739.291 8576.374 c
+-7739.3008 8576.3955 -7739.2886 8576.4277 -7739.2681 8576.4473 c
+-7739.2681 8576.4473 l
+f
+-7737.8945 8578.5645 m
+-7735.6719 8579.0449 -7733.3896 8578.6162 -7731.1504 8578.5625 c
+-7731.1177 8578.5615 -7731.0977 8578.5391 -7731.0977 8578.5078 c
+-7731.1001 8578.4863 -7731.1318 8578.4668 -7731.1519 8578.4668 c
+-7733.3833 8578.4775 -7735.6519 8578.9805 -7737.875 8578.457 c
+-7737.8975 8578.457 -7737.9287 8578.4688 -7737.9375 8578.502 c
+-7737.9375 8578.5225 -7737.9258 8578.5547 -7737.8945 8578.5645 c
+-7737.8945 8578.5645 l
+f
+-7732.0273 8575.1406 m
+-7730.3496 8575.9688 -7728.499 8576.502 -7726.603 8576.3613 c
+-7726.5718 8576.3613 -7726.5513 8576.3389 -7726.5527 8576.3066 c
+-7726.5527 8576.2754 -7726.5742 8576.2539 -7726.6074 8576.2559 c
+-7728.481 8576.416 -7730.3198 8575.8604 -7731.9873 8575.0547 c
+-7732.0078 8575.0449 -7732.041 8575.0449 -7732.0503 8575.0781 c
+-7732.061 8575.0996 -7732.061 8575.1309 -7732.0273 8575.1406 c
+-7732.0273 8575.1406 l
+f
+u
+0.5 0.85 1 0.45 k
+-7885 8581.9082 m
+-7885.0254 8582.4883 -7884.5664 8583.1875 -7883.167 8583.9902 C
+-7882.8521 8584.0029 -7881.3945 8584.0234 -7879.0889 8584.0488 C
+-7879.0889 8581.8223 L
+-7881.1382 8581.8457 -7883.1177 8581.8867 -7885 8581.9082 C
+f
+-7884.5088 8580.9688 m
+-7879.0889 8580.8447 L
+-7879.0889 8579.8145 L
+-7882.644 8579.959 L
+-7883.8145 8580.3301 -7884.5088 8580.9688 V
+f
+0.5 0.85 1 0.32 k
+-7879.0889 8580.8252 m
+-7884.4746 8580.9434 L
+-7884.7695 8581.2148 -7884.9849 8581.5566 -7885 8581.9277 C
+-7883.1177 8581.9063 -7881.1382 8581.8848 -7879.0889 8581.8613 C
+-7879.0889 8580.8252 L
+f
+0.5 0.85 1 0.45 k
+-7774.1504 8580.6172 m
+-7852.3584 8581.541 -7879.1079 8581.8418 V
+-7879.1079 8584.0488 L
+-7862.8145 8584.2324 -7803.9902 8584.707 Y
+-7769.749 8583.6641 L
+-7770.457 8580.5684 L
+-7774.1504 8580.6172 L
+f
+0.5 0.85 1 0.12 k
+-7879.1079 8579.8145 m
+-7879.1079 8580.8447 L
+-7770.4258 8579 L
+-7770.3833 8576.8633 L
+-7803.6553 8576.7129 L
+-7879.1079 8579.8145 L
+f
+u
+0.065 0.052 0.039 0 k
+-7747.0728 8575.1465 m
+-7747.0366 8576.4258 L
+-7747.2954 8575.1172 L
+-7765.897 8579.6563 L
+-7766.9375 8579.2734 L
+-7766.8794 8579.6055 -7766.8398 8579.957 -7766.8306 8580.3223 c
+-7766.8242 8580.5283 -7766.8281 8580.7285 -7766.8398 8580.9258 C
+-7758.3862 8582.0986 -7748.9634 8577.6719 -7747.0366 8576.4258 C
+-7746.7402 8586.7559 L
+-7746.041 8586.8613 L
+-7745.8042 8579.207 L
+-7740.1816 8579.1543 L
+-7740.0898 8577.0137 -7740.0718 8575.0215 -7740.2407 8574.0352 C
+-7747.0728 8575.1465 L
+f
+0.4 0.7 1 0 k
+-7770.457 8580.5879 m
+-7770.4258 8578.9805 L
+-7879.1079 8580.8252 L
+-7879.1079 8581.8613 L
+-7852.3584 8581.5605 -7770.457 8580.5879 Y
+f
+U
+U
+0.025 0.02 0.015 0 k
+-7734.7344 8583.0293 m
+-7734.7344 8583.0625 -7734.7129 8583.082 -7734.6802 8583.082 c
+-7731.6714 8583.1133 -7729.4214 8582.9453 -7726.415 8582.8594 C
+-7726.4087 8582.7656 L
+-7729.3262 8582.8701 -7731.7607 8583.0078 -7734.6841 8582.9746 C
+-7734.7168 8582.9766 -7734.7358 8582.998 -7734.7344 8583.0293 C
+f
+-7726.3994 8582.7656 m
+-7726.4082 8582.7441 L
+-7726.4087 8582.7656 L
+-7726.4063 8582.7656 -7726.4033 8582.7656 -7726.3994 8582.7656 C
+f
+-7730.4487 8581.4238 m
+-7731.4458 8581.292 -7732.3394 8581.7656 -7733.2114 8582.1973 C
+-7733.2441 8582.208 -7733.2534 8582.2402 -7733.2422 8582.2715 C
+-7733.2305 8582.293 -7733.1982 8582.3027 -7733.1777 8582.291 c
+-7732.3262 8581.8301 -7731.4312 8581.4199 -7730.4678 8581.5195 c
+-7729.1079 8581.6621 -7727.9038 8582.375 -7726.5254 8582.4531 C
+-7726.4463 8582.3594 L
+-7728.04 8582.2656 -7728.8647 8581.623 -7730.4487 8581.4238 c
+f
+U
+U
+%AI8_EndBrushPattern
+%AI8_BeginBrushPattern
+(New Pattern 6)
+0 A
+u
+1 Ap
+800 Ar
+0 J 0 j 1 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+-7884.75 8563 m
+-7884.75 8587 L
+-7874.75 8587 L
+-7874.75 8563 L
+-7884.75 8563 L
+n
+0 Ap
+0 O
+1 g
+-7874.75 8565 m
+-7875.0703 8565 -7875.3857 8565.0186 -7875.6982 8565.0479 c
+-7877.5879 8565.2256 -7879.3198 8565.9346 -7880.7559 8567.0176 c
+-7882.2529 8568.1465 -7883.4199 8569.6816 -7884.0942 8571.4639 c
+-7884.5122 8572.5645 -7884.75 8573.7529 -7884.75 8575 c
+-7884.75 8576.8623 -7884.2319 8578.5996 -7883.3457 8580.0918 c
+-7881.6025 8583.0273 -7878.4102 8585 -7874.75 8585 C
+-7874.75 8565 L
+f
+0 R
+0 G
+1 J 1 j 0.5 w
+-7874.75 8584.6816 m
+-7877.7793 8583.7256 -7880.6074 8582.0674 -7883.3457 8580.0918 C
+S
+-7874.75 8579.0488 m
+-7877.8999 8576.6436 -7880.957 8573.9131 -7884.0942 8571.4639 C
+S
+-7880.7559 8567.0176 m
+-7878.6904 8568.1084 -7876.7017 8569.4668 -7874.75 8570.957 C
+S
+-7875.6982 8565.0479 m
+-7875.3809 8565.1309 -7875.063 8565.2148 -7874.75 8565.3145 C
+S
+-7880.7559 8567.0176 m
+-7879.3193 8565.9355 -7877.5879 8565.2256 -7875.6982 8565.0479 C
+S
+-7884.0942 8571.4639 m
+-7884.5122 8572.5645 -7884.75 8573.7529 -7884.75 8575 c
+-7884.75 8576.8623 -7884.231 8578.5996 -7883.3457 8580.0918 C
+S
+-7874.75 8565 m
+-7875.0703 8565 -7875.3857 8565.0186 -7875.6982 8565.0479 C
+S
+-7880.7559 8567.0176 m
+-7882.2529 8568.1465 -7883.4199 8569.6816 -7884.0942 8571.4639 C
+S
+-7883.3457 8580.0918 m
+-7881.6025 8583.0273 -7878.4102 8585 -7874.75 8585 C
+S
+U
+%AI8_EndBrushPattern
+%AI8_BeginBrushPattern
+(New Pattern 8)
+0 A
+u
+800 Ar
+0 J 0 j 1 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+-7883.9521 8584.3125 m
+-7776.7954 8584.3125 L
+-7776.7954 8570.1855 L
+-7883.9521 8570.1855 L
+-7883.9521 8584.3125 L
+n
+u
+0 O
+0 0 0 1 k
+-7882.2832 8583.623 m
+-7882.8535 8586 -7882.8184 8582.0039 V
+-7883.0479 8578.8027 L
+-7883.6167 8576.4551 L
+-7883.4502 8574.123 L
+-7881.9502 8573.4551 -7865.2832 8572.123 V
+-7858.6167 8570.7891 -7849.6167 8570.7891 V
+-7784.3936 8571.4766 -7779.4912 8572.8848 v
+-7820.3882 8570.875 -7822.9688 8571.5117 v
+-7783.8569 8573.1602 -7780.8545 8574.4316 v
+-7818.79 8572.5469 -7822.167 8574.1777 v
+-7787.249 8575.9102 -7783.021 8577.5313 v
+-7789.7217 8576.8828 -7791.5127 8577.082 v
+-7788.3896 8577.5703 l
+-7793.4194 8577.502 l
+-7796.3218 8577.1289 l
+-7788.4521 8578.2422 -7787.9033 8578.8086 v
+-7784.3154 8578.1309 -7798.5186 8578.3848 v
+-7832.1177 8574.4551 -7882.2832 8583.623 V
+f
+/BBAccumRotation (5.805971) XT
+0 R
+0 0 0 0.5 K
+0.025 w
+-7883.9502 8573.123 m
+-7863.667 8571.2949 -7843.9727 8570.2207 v
+-7801.1514 8570.502 -7796.5737 8570.9004 v
+-7784.1631 8571.0313 -7776.7959 8572.0273 v
+S
+/BBAccumRotation (5.805971) XT
+0 0 0 1 K
+-7821.8369 8570.4082 m
+-7825.2959 8570.0273 -7851.2607 8570.2793 Y
+-7861.627 8570.1602 -7883.9502 8573.123 Y
+S
+/BBAccumRotation (5.805971) XT
+-7820.9873 8573.6641 m
+-7790.3608 8574.582 -7783.6606 8575.2324 v
+S
+/BBAccumRotation (5.805971) XT
+0 0 0 0.5 K
+-7829.6201 8578.2051 m
+-7794.3706 8579.6172 -7791.4058 8580.1406 v
+S
+/BBAccumRotation (5.805971) XT
+U
+U
+%AI8_EndBrushPattern
+%AI8_BeginBrushPattern
+(New Pattern 10)
+0 A
+u
+800 Ar
+0 J 0 j 1 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+-7884 8586 m
+-7833.8921 8586 L
+-7833.8921 8529.9756 L
+-7884 8529.9756 L
+-7884 8586 L
+n
+u
+0 O
+0.1 1 1 0 k
+-7846.9014 8551.5752 m
+-7848.7178 8545.0957 -7858.8247 8548.4658 Y
+-7858.791 8548.5303 L
+-7868.8999 8545.1611 -7870.7144 8551.6396 V
+-7876.6758 8569.0068 -7871.4922 8575.7451 V
+-7864.7529 8585.3369 -7860.6055 8585.3369 V
+-7857.0103 8585.2705 L
+-7852.8638 8585.2705 -7846.125 8575.6816 Y
+-7840.9409 8568.9424 -7846.9014 8551.5752 Y
+f
+u
+0 0 0 1 k
+-7851.3926 8529.9756 m
+-7852.1167 8531.4199 -7852.9238 8532.4756 V
+-7852.4058 8532.0635 -7851.5151 8531.1924 -7851.3926 8529.9756 C
+f
+-7865.064 8532.4854 m
+-7865.8711 8531.4307 -7866.5942 8529.9863 Y
+-7866.4727 8531.2021 -7865.582 8532.0732 -7865.064 8532.4854 C
+f
+U
+0 0.61 0.74 0 k
+-7850.5977 8554.4609 m
+-7851.9038 8549.7959 -7859.1816 8552.2217 Y
+-7859.1567 8552.2686 L
+-7866.436 8549.8428 -7867.7417 8554.5078 V
+-7872.0337 8567.0117 -7868.3018 8571.8633 V
+-7863.4487 8578.7686 -7860.4634 8578.7686 V
+-7857.875 8578.7227 L
+-7854.8887 8578.7227 -7850.0366 8571.8174 Y
+-7846.3042 8566.9639 -7850.5977 8554.4609 Y
+f
+u
+1 Ap
+0.73 0.43 1 0.22 k
+0 R
+0 0 0 1 K
+-7854.6226 8557.2754 m
+-7853.813 8557.2754 -7853.1558 8556.6182 -7853.1558 8555.8096 c
+-7853.1558 8555 -7853.813 8554.3428 -7854.6226 8554.3428 c
+-7855.4321 8554.3428 -7856.0889 8555 -7856.0889 8555.8096 c
+-7856.0889 8556.6182 -7855.4321 8557.2754 -7854.6226 8557.2754 c
+b
+-7854.3638 8568.9971 m
+-7853.0806 8568.9971 -7852.0415 8568.1201 -7852.0415 8567.042 c
+-7852.0415 8565.9619 -7853.0806 8565.0869 -7854.3638 8565.0869 c
+-7855.645 8565.0869 -7856.6846 8565.9619 -7856.6846 8567.042 c
+-7856.6846 8568.1201 -7855.645 8568.9971 -7854.3638 8568.9971 c
+b
+-7853.834 8580.7861 m
+-7852.2817 8580.7861 -7851.0239 8580.1299 -7851.0239 8579.3213 c
+-7851.0239 8578.5117 -7852.2817 8577.8545 -7853.834 8577.8545 c
+-7855.3862 8577.8545 -7856.645 8578.5117 -7856.645 8579.3213 c
+-7856.645 8580.1299 -7855.3862 8580.7861 -7853.834 8580.7861 c
+b
+-7849.6104 8552.5264 m
+-7848.8687 8552.5264 -7848.2671 8551.8154 -7848.2671 8550.9365 c
+-7848.2671 8550.0596 -7848.8687 8549.3477 -7849.6104 8549.3477 c
+-7850.353 8549.3477 -7850.9546 8550.0596 -7850.9546 8550.9365 c
+-7850.9546 8551.8154 -7850.353 8552.5264 -7849.6104 8552.5264 c
+b
+-7848.0034 8574.083 m
+-7848.8818 8573.7354 -7849.1494 8572.335 -7848.603 8570.9541 c
+-7848.0566 8569.5752 -7846.9014 8568.7363 -7846.0234 8569.085 c
+-7845.145 8569.4326 -7844.877 8570.833 -7845.4233 8572.2139 c
+-7845.9702 8573.5947 -7847.125 8574.4316 -7848.0034 8574.083 c
+b
+u
+-7863.0566 8557.1592 m
+-7863.8662 8557.1592 -7864.5239 8556.502 -7864.5239 8555.6934 c
+-7864.5239 8554.8828 -7863.8662 8554.2266 -7863.0566 8554.2266 c
+-7862.248 8554.2266 -7861.5913 8554.8828 -7861.5913 8555.6934 c
+-7861.5913 8556.502 -7862.248 8557.1592 -7863.0566 8557.1592 c
+b
+-7863.3159 8568.8799 m
+-7864.5991 8568.8799 -7865.6382 8568.0049 -7865.6382 8566.9248 c
+-7865.6382 8565.8447 -7864.5991 8564.9697 -7863.3159 8564.9697 c
+-7862.0342 8564.9697 -7860.9951 8565.8447 -7860.9951 8566.9248 c
+-7860.9951 8568.0049 -7862.0342 8568.8799 -7863.3159 8568.8799 c
+b
+-7863.8457 8580.6709 m
+-7865.3975 8580.6709 -7866.6558 8580.0146 -7866.6558 8579.2041 c
+-7866.6558 8578.3936 -7865.3975 8577.7383 -7863.8457 8577.7383 c
+-7862.293 8577.7383 -7861.0352 8578.3936 -7861.0352 8579.2041 c
+-7861.0352 8580.0146 -7862.293 8580.6709 -7863.8457 8580.6709 c
+b
+-7868.0679 8552.4092 m
+-7868.811 8552.4092 -7869.4121 8551.6982 -7869.4121 8550.8213 c
+-7869.4121 8549.9443 -7868.811 8549.2334 -7868.0679 8549.2334 c
+-7867.3262 8549.2334 -7866.7241 8549.9443 -7866.7241 8550.8213 c
+-7866.7241 8551.6982 -7867.3262 8552.4092 -7868.0679 8552.4092 c
+b
+-7869.6758 8573.9678 m
+-7868.7983 8573.6201 -7868.5298 8572.2188 -7869.0762 8570.8379 c
+-7869.6226 8569.457 -7870.7778 8568.6201 -7871.6558 8568.9678 c
+-7872.5342 8569.3164 -7872.8032 8570.7178 -7872.2568 8572.0967 c
+-7871.7104 8573.4775 -7870.5552 8574.3154 -7869.6758 8573.9678 c
+b
+U
+U
+0 Ap
+0 0 0 1 k
+-7859.1318 8552.6553 m
+-7859.1318 8585.3145 l
+F
+u
+-7843.3906 8538.5303 m
+-7844.0815 8537.8369 -7847.019 8538.7021 Y
+-7848.229 8538.874 -7848.0562 8541.2939 Y
+-7847.019 8543.3682 -7847.7104 8543.1943 Y
+-7848.2998 8543.1943 -7849.855 8543.1143 -7850.7822 8543.0635 C
+-7851.1226 8541.6689 -7852.6128 8540.4756 -7854.7217 8539.7695 C
+-7852.7578 8536.4775 -7854.5176 8535.7949 -7856.2935 8535.79 C
+-7856.3096 8535.7021 -7856.332 8535.6162 -7856.3599 8535.5332 C
+-7854.1089 8535.5791 -7853.6392 8533.2588 Y
+-7853.4048 8533.0635 -7853.1606 8532.7861 -7852.9238 8532.4756 C
+-7853.1416 8532.6475 -7853.2944 8532.7393 Y
+-7854.2583 8532.7393 -7855.8774 8534.4941 -7856.4966 8535.207 C
+-7856.9194 8534.4434 -7857.853 8533.9111 -7858.9434 8533.9111 c
+-7860.0698 8533.9111 -7861.0322 8534.4795 -7861.4312 8535.2852 C
+-7861.9985 8534.624 -7863.6968 8532.751 -7864.6943 8532.751 C
+-7864.8462 8532.6572 -7865.064 8532.4854 V
+-7864.8281 8532.7939 -7864.583 8533.0732 -7864.3481 8533.2686 C
+-7863.8638 8535.6563 -7861.5254 8535.5342 V
+-7861.5449 8535.5889 -7861.5674 8535.6436 -7861.5806 8535.7021 C
+-7864.9238 8535.6924 -7863.937 8538.3174 -7863.2104 8539.6602 C
+-7865.5918 8540.376 -7867.2646 8541.7012 -7867.5239 8543.25 C
+-7868.4473 8543.2998 -7869.6729 8543.3584 -7870.1802 8543.3584 C
+-7870.8726 8543.5313 -7869.835 8541.458 V
+-7869.6626 8539.0391 -7870.8726 8538.8662 V
+-7873.8096 8538.002 -7874.501 8538.6934 V
+-7875.1919 8539.5566 -7876.0562 8538.3467 V
+-7875.1919 8540.0752 -7873.291 8539.5566 V
+-7870.6982 8538.8662 -7871.3906 8540.5938 V
+-7871.9087 8544.0498 -7870.1802 8544.7402 V
+-7868.0342 8545.8545 -7866.2822 8546.0889 V
+-7865.9087 8546.4141 -7865.4639 8546.7109 -7864.958 8546.9766 C
+-7867.5562 8547.0469 -7870.2246 8547.9209 -7871.0752 8550.9561 C
+-7871.5151 8552.2432 -7872.0518 8554.2432 V
+-7873.1025 8554.8252 -7874.3022 8556.0078 -7875.541 8558.2627 C
+-7876.394 8561.4502 -7877.167 8556.7129 V
+-7878.3975 8553.6494 -7879.6504 8553.5381 V
+-7878.4702 8555.2871 -7878.9038 8556.416 V
+-7877.2998 8560.917 -7875.6138 8559.8994 V
+-7874.0986 8559.2197 -7872.688 8556.8154 V
+-7873.0698 8558.4971 -7873.4326 8560.417 -7873.6743 8562.3906 C
+-7874.4888 8562.3975 L
+-7876.3506 8561.4795 -7876.3262 8564.959 V
+-7877.1226 8568.9453 -7876.3594 8571.6826 V
+-7875.647 8574.1504 -7878.1274 8572.9307 V
+-7879.2842 8573.3242 -7879.9839 8572.7881 V
+-7882.3882 8571.4131 -7884 8573.124 V
+-7882.147 8572.8799 -7881.4482 8573.417 V
+-7879.9785 8573.5615 -7879.897 8574.1787 V
+-7876.9561 8574.8555 -7876.188 8574.0771 V
+-7874.417 8573.2139 -7875.1304 8570.3604 V
+-7875.8799 8562.4814 -7874.3198 8564.4053 V
+-7874.1182 8564.4219 -7873.8784 8564.5176 V
+-7874.1519 8568.4326 -7873.8018 8572.3252 -7871.9961 8574.8516 C
+-7875.4536 8567.333 -7870.2974 8552.3037 Y
+-7868.9609 8547.5303 -7863.127 8548.1016 -7860.145 8548.7344 C
+-7860.0718 8550.1299 -7859.8374 8551.9492 -7859.1318 8552.6553 C
+-7858.2134 8550.6963 -7858.2358 8549.0732 V
+-7857.0762 8548.7217 -7850.2817 8546.8447 -7847.4487 8550.3369 C
+-7848.4312 8547.8135 -7850.8262 8547.0186 -7853.2007 8546.9189 C
+-7852.667 8546.6318 -7852.2041 8546.3047 -7851.8257 8545.9502 C
+-7850.041 8545.7861 -7847.7104 8544.5771 Y
+-7845.9814 8543.8857 -7846.5015 8540.4307 Y
+-7847.1919 8538.7021 -7844.5991 8539.3936 Y
+-7842.7002 8539.9111 -7841.835 8538.1836 Y
+-7842.7002 8539.3936 -7843.3906 8538.5303 Y
+f
+-7837.9082 8572.9521 m
+-7838.6074 8573.4893 -7839.7632 8573.0938 Y
+-7842.2446 8574.3135 -7841.5327 8571.8467 Y
+-7840.769 8569.1104 -7841.564 8565.1221 Y
+-7841.541 8561.6445 -7843.4014 8562.5596 Y
+-7844.0342 8562.5557 L
+-7844.3198 8560.6123 -7844.7046 8558.7549 -7845.0898 8557.1699 C
+-7843.7129 8559.4199 -7842.2778 8560.0635 Y
+-7840.5913 8561.082 -7838.9878 8556.5791 Y
+-7839.4214 8555.4502 -7838.2417 8553.7021 Y
+-7839.4937 8553.8125 -7840.7246 8556.876 Y
+-7841.4976 8561.6152 -7842.3511 8558.4268 Y
+-7843.5776 8556.1904 -7844.769 8555.0098 -7845.814 8554.4229 C
+-7846.2026 8553.0635 -7846.4858 8552.2393 Y
+-7846.7002 8551.4727 -7847.0337 8550.8486 -7847.4487 8550.3369 C
+-7847.3799 8550.5127 -7847.3174 8550.6982 -7847.2632 8550.8916 C
+-7841.3022 8568.2588 -7846.4858 8574.9971 V
+-7853.2246 8584.5869 -7857.3721 8584.5869 V
+-7860.9663 8584.6514 L
+-7865.1138 8584.6514 -7871.853 8575.0615 Y
+-7871.9038 8574.9961 -7871.9463 8574.9219 -7871.9961 8574.8516 C
+-7871.7378 8575.4141 -7871.437 8575.9404 -7871.0752 8576.4092 C
+-7864.3359 8586 -7860.189 8586 V
+-7856.5942 8585.9346 L
+-7852.4482 8585.9346 -7845.709 8576.3447 Y
+-7843.5801 8573.5771 -7843.3306 8569.0176 -7843.7769 8564.6055 C
+-7843.6553 8564.5752 -7843.5698 8564.5684 Y
+-7842.0112 8562.6475 -7842.7598 8570.5244 Y
+-7843.4746 8573.3789 -7841.7026 8574.2402 Y
+-7840.9351 8575.0186 -7837.9946 8574.3428 Y
+-7837.9136 8573.7256 -7836.4434 8573.5811 Y
+-7835.7446 8573.0449 -7833.8921 8573.2881 Y
+-7835.5024 8571.5771 -7837.9082 8572.9521 Y
+f
+U
+U
+U
+%AI8_EndBrushPattern
+%AI8_BeginBrushPattern
+(New Pattern 34)
+0 A
+u
+800 Ar
+0 J 0 j 1 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+-7884.0254 8586.0264 m
+-7828.0542 8586.0264 L
+-7828.0542 8524.5342 L
+-7884.0254 8524.5342 L
+-7884.0254 8586.0264 L
+n
+u
+u
+0 O
+0.0745 0.9 0.9019 0.18 k
+0 R
+0 0 0 1 K
+1 J 1 j 0.0518 w
+-7857.5991 8562.7217 m
+-7857.3594 8573.5215 -7862.8794 8583.8398 v
+-7862.4009 8586 -7860.959 8586 v
+-7861.2002 8582.6406 -7860.2393 8582.1611 v
+-7855.9199 8570.1602 -7856.6382 8562.2402 v
+-7857.5991 8562.7217 l
+b
+-7857.5991 8562.7217 m
+-7859.2793 8568 -7871.0391 8569.2012 v
+-7875.3594 8569.6807 -7875.5991 8571.1211 v
+-7869.1206 8561.5195 -7868.1602 8561.7607 v
+-7881.3594 8556.001 -7884 8550.7197 v
+-7878.959 8553.6006 -7875.5991 8551.4404 v
+-7867.6802 8551.2012 -7862.6406 8553.3613 v
+-7858.8008 8555.2813 -7866.7202 8539.2012 v
+-7862.8794 8550.9609 -7859.2793 8524.5605 v
+-7858.3198 8529.8408 -7856.8799 8531.2813 v
+-7850.8799 8538.9609 -7851.8398 8541.1211 v
+-7852.3198 8544.9609 -7847.7598 8538.7207 v
+-7848 8548.3213 -7850.4009 8551.6807 v
+-7852.5591 8555.2813 -7846.5591 8553.1211 v
+-7840.5591 8551.2012 -7835.2793 8552.8809 v
+-7829.7598 8554.3203 -7828.0801 8551.4404 v
+-7839.8398 8563.9209 -7845.5991 8563.6807 v
+-7843.9194 8567.2813 l
+-7841.519 8572.0811 -7842 8573.2813 v
+-7857.2681 8563.8828 -7857.5991 8562.7217 v
+b
+-7857.5991 8562.7217 m
+-7854.959 8544.2402 -7857.5991 8536.5605 v
+-7859.998 8526.001 -7859.2793 8524.5605 v
+S
+-7856.1602 8551.4404 m
+-7850.1602 8546.6406 -7848.959 8541.3604 v
+S
+-7856.1602 8550.7197 m
+-7865.0391 8543.041 -7866.7202 8539.2012 v
+S
+-7828.0801 8551.4404 m
+-7829.2793 8553.6006 -7857.3594 8561.7607 y
+-7862.4009 8556.2422 -7873.9199 8553.8408 v
+-7881.5986 8552.8809 -7884 8550.7197 v
+S
+-7874.6382 8569.6807 m
+-7863.1191 8560.5615 -7857.3594 8561.7607 y
+-7843.1992 8568 -7842 8573.2813 v
+S
+U
+U
+U
+%AI8_EndBrushPattern
+%AI8_BeginBrushPattern
+(New Pattern 36)
+0 A
+u
+800 Ar
+0 J 0 j 1 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+-7883.8496 8585.9961 m
+-7833.96 8585.9961 L
+-7833.96 8534.9258 L
+-7883.8496 8534.9258 L
+-7883.8496 8585.9961 L
+n
+u
+0 O
+0.025 0.1 0.475 0 k
+-7862.1504 8553.9043 m
+-7864.4766 8552.8125 -7866.6914 8552.4434 -7868.373 8552.9238 c
+-7869.0518 8553.1172 -7869.645 8553.4473 -7870.123 8553.9238 c
+-7870.6006 8554.4023 -7870.9297 8554.9951 -7871.123 8555.6729 c
+-7872.0088 8558.7715 -7870.0103 8563.6777 -7865.9233 8567.7666 c
+-7861.834 8571.8535 -7856.9297 8573.8516 -7853.8286 8572.9668 c
+-7853.1519 8572.7715 -7852.5586 8572.4424 -7852.0806 8571.9658 c
+-7851.603 8571.4883 -7851.2754 8570.8955 -7851.082 8570.2168 c
+-7850.5176 8568.2461 -7851.1226 8565.5449 -7852.6855 8562.7891 c
+-7853.582 8561.21 -7854.791 8559.6133 -7856.2793 8558.123 c
+-7858.1504 8556.2539 -7860.1914 8554.8242 -7862.1504 8553.9043 c
+f
+u
+0.0035 0.014 0.0665 0 k
+-7861.2183 8552.9727 m
+-7863.8306 8552.0215 -7866.3975 8551.9688 -7868.373 8552.9238 C
+-7866.6914 8552.4434 -7864.4766 8552.8125 -7862.1504 8553.9043 c
+-7861.6191 8554.1543 -7861.0806 8554.4434 -7860.543 8554.7676 C
+-7858.8984 8554.0537 L
+-7859.667 8553.6172 -7860.4434 8553.2539 -7861.2183 8552.9727 c
+f
+0.015 0.06 0.285 0 k
+-7858.8984 8554.0537 m
+-7860.543 8554.7676 L
+-7859.0962 8555.6348 -7857.6426 8556.7607 -7856.2793 8558.123 c
+-7856.1538 8558.25 -7856.0327 8558.3779 -7855.9102 8558.5059 C
+-7855.2153 8556.8633 L
+-7856.3706 8555.7236 -7857.6191 8554.7813 -7858.8984 8554.0537 C
+f
+U
+u
+0.039 0.156 0.741 0 k
+-7849.687 8541.4043 m
+-7849.9746 8541.6914 -7861.2183 8552.9727 Y
+-7860.4434 8553.2539 -7859.667 8553.6172 -7858.8984 8554.0537 C
+-7845.4146 8540.5703 L
+-7847.061 8540.0996 -7848.6406 8540.3555 -7849.687 8541.4043 c
+f
+0.025 0.1 0.475 0 k
+-7845.4146 8540.5703 m
+-7858.8984 8554.0537 L
+-7857.584 8554.8027 -7856.2969 8555.7754 -7855.1143 8556.957 c
+-7855.084 8556.9863 -7855.0586 8557.0156 -7855.0278 8557.0449 C
+-7841.3408 8543.3574 L
+-7841.5264 8543.1328 -7841.7202 8542.9141 -7841.9302 8542.7012 c
+-7843.0103 8541.623 -7844.2305 8540.9082 -7845.4146 8540.5703 C
+f
+U
+u
+0.0115 0.046 0.2185 0 k
+-7835.9346 8550.3926 m
+-7833.5337 8547.9893 -7833.335 8544.0898 -7835.1382 8540.6973 C
+-7836.2954 8541.1182 L
+-7834.0938 8544.4961 -7833.8398 8548.2949 -7835.9346 8550.3926 c
+f
+0.015 0.06 0.285 0 k
+-7843.5337 8535.5957 m
+-7842.582 8534.9258 L
+-7845.2046 8534.3516 -7847.8306 8534.9141 -7849.6206 8536.7061 c
+-7848.1719 8535.2578 -7845.9082 8534.9307 -7843.5337 8535.5957 C
+f
+0.0295 0.118 0.5605 0 k
+-7843.5337 8535.5957 m
+-7845.9082 8534.9307 -7848.1719 8535.2578 -7849.6206 8536.7061 c
+-7851.019 8538.1055 -7851.3706 8540.2637 -7850.7954 8542.5469 C
+-7848.8672 8539.5449 -7845.4082 8540.5537 V
+-7843.585 8535.6309 L
+-7843.5337 8535.5957 L
+f
+*u
+0.048 0.192 0.912 0 k
+1 D
+-7835.9346 8550.3926 m
+-7837.2817 8551.7383 -7839.332 8552.1133 -7841.5234 8551.627 C
+-7851.6714 8561.7734 L
+-7851.7695 8561.5684 -7851.7695 8561.5684 -7851.6714 8561.7734 c
+-7850.2246 8564.8145 -7849.9702 8567.916 -7851.082 8570.2168 C
+-7850.5176 8568.2461 -7851.1226 8565.5449 -7852.6855 8562.7891 c
+-7853.5054 8561.3438 -7854.5918 8559.8848 -7855.9102 8558.5059 C
+-7855.2153 8556.8633 L
+-7855.1816 8556.8945 -7855.1465 8556.9238 -7855.1143 8556.957 c
+-7855.084 8556.9883 -7855.0566 8557.0176 -7855.0273 8557.0469 c
+-7855.0278 8557.0469 -7855.0278 8557.0469 -7855.0278 8557.0449 C
+-7841.3408 8543.3574 L
+-7836.3262 8541.1289 L
+-7836.2954 8541.1182 L
+-7834.0938 8544.4961 -7833.8398 8548.2949 -7835.9346 8550.3926 c
+f
+*U
+0.0215 0.086 0.4085 0 k
+0 D
+-7842.582 8534.9258 m
+-7843.5337 8535.5957 L
+-7841.6846 8536.1113 -7839.7656 8537.2285 -7838.1138 8538.8828 c
+-7837.4063 8539.5889 -7836.7998 8540.3418 -7836.2954 8541.1182 C
+-7835.1382 8540.6973 L
+-7835.6553 8539.7246 -7836.3374 8538.793 -7837.1802 8537.9512 c
+-7838.7695 8536.3594 -7840.6758 8535.3428 -7842.582 8534.9258 C
+f
+0.0205 0.082 0.3895 0 k
+-7836.2954 8541.1182 m
+-7836.7998 8540.3418 -7837.4063 8539.5889 -7838.1138 8538.8828 c
+-7839.7656 8537.2285 -7841.6846 8536.1113 -7843.5337 8535.5957 C
+-7843.585 8535.6309 L
+-7845.4082 8540.5537 L
+-7844.2114 8540.9219 -7842.9878 8541.6436 -7841.9302 8542.7012 c
+-7841.7202 8542.9141 -7841.5264 8543.1328 -7841.3408 8543.3574 C
+-7836.3262 8541.1289 L
+-7836.2954 8541.1182 L
+f
+U
+u
+0.445 0.356 0.267 0 k
+-7883.8496 8585.9961 m
+-7861.957 8562.9688 L
+-7862.2007 8562.6494 -7862.5752 8562.6133 -7862.8887 8562.6592 C
+-7867.1802 8567.2891 -7878.3145 8579.4561 -7882.7266 8584.2793 C
+-7883.5649 8585.3516 -7884 8585.9932 -7883.8496 8585.9961 C
+f
+0.15 0.12 0.09 0 k
+-7883.834 8585.9961 m
+-7882.6606 8585.7031 -7861.6934 8564.0029 Y
+-7861.6934 8563.502 -7861.7993 8563.1758 -7861.957 8562.9688 C
+-7883.8496 8585.9961 L
+-7883.8442 8585.9961 -7883.8418 8586 -7883.834 8585.9961 c
+f
+0.2 0.16 0.12 0 k
+-7882.7266 8584.2793 m
+-7878.3145 8579.4561 -7867.1802 8567.2891 -7862.8887 8562.6592 C
+-7863.2002 8562.7041 -7863.4526 8562.8301 Y
+-7864.603 8563.1328 -7878.5742 8578.9619 -7882.7266 8584.2793 C
+f
+U
+U
+U
+%AI8_EndBrushPattern
+%AI8_BeginBrushPattern
+(New Pattern 37)
+0 A
+u
+800 Ar
+0 J 0 j 1 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+-7882.9502 8585.2324 m
+-7833.0391 8585.2324 L
+-7833.0391 8521.1152 L
+-7882.9502 8521.1152 L
+-7882.9502 8585.2324 L
+n
+u
+0 O
+0 0 0 1 k
+0 R
+0 0 0 1 K
+0 w
+-7833.2358 8521.1152 m
+-7833.6064 8521.248 -7833.9858 8521.2832 -7834.3833 8521.2031 c
+-7834.4863 8521.168 l
+-7834.5254 8521.1602 -7834.5703 8521.1787 -7834.6025 8521.1992 c
+-7834.9434 8521.3926 l
+-7838.7129 8523.2959 -7842.0962 8525.8965 -7844.5 8529.4473 c
+-7845.9634 8531.5918 -7847.123 8533.8789 -7848.7993 8535.8564 c
+-7849.1729 8536.209 -7849.1758 8536.7725 -7848.834 8537.1309 c
+-7848.4951 8537.501 -7847.918 8537.5078 -7847.561 8537.165 c
+-7847.4038 8537.21 l
+-7847.2642 8537.1289 -7847.0742 8537.0703 -7847.0234 8536.957 c
+-7845.853 8534.2031 -7845.1895 8531.5137 -7843.4336 8529.1387 c
+-7841.1719 8526.0947 -7838.1777 8523.9941 -7835.0298 8522.0234 c
+-7834.3672 8521.6055 L
+-7834.4966 8521.6348 L
+-7833.7695 8521.6426 l
+-7833.791 8521.6113 -7833.8008 8521.5957 -7833.8223 8521.5645 C
+-7833.6064 8521.5234 -7833.377 8521.4746 -7833.1626 8521.4336 c
+-7833.0762 8521.4238 -7833.0186 8521.3389 -7833.0391 8521.2383 c
+-7833.0503 8521.1523 -7833.1382 8521.1084 -7833.2358 8521.1152 c
+-7833.2358 8521.1152 l
+b
+-7849.2222 8534.9951 m
+-7849.5742 8534.8066 -7849.9658 8534.6719 -7850.248 8534.3887 c
+-7856.4521 8528.1719 -7866.6802 8527.2734 -7874.0488 8533.6855 C
+-7874.1582 8533.7813 -7874.1582 8533.957 -7874.063 8534.0645 C
+-7871.0527 8532.9434 -7862.8838 8534.375 -7859.3223 8537.4121 C
+-7859.2534 8537.4668 -7859.1465 8537.4531 -7859.1055 8537.3711 C
+-7859.0503 8537.3047 -7859.0664 8537.1953 -7859.1328 8537.1563 C
+-7862.5625 8534.0859 -7867.0674 8532.29 -7871.6729 8532.748 C
+-7868.8535 8531.1855 -7865.6313 8530.4941 -7862.3984 8530.6885 c
+-7857.7144 8530.9717 -7853.4634 8533.1191 -7849.3711 8535.2793 c
+-7849.291 8535.3193 -7849.1978 8535.293 -7849.1553 8535.2109 C
+-7849.1016 8535.1309 -7849.1426 8535.0352 -7849.2222 8534.9951 c
+b
+-7858.647 8536.3359 m
+-7860.2266 8540.3613 -7862.3911 8544.3203 -7865.8018 8547.0762 c
+-7865.9648 8547.2119 -7865.9946 8547.4492 -7865.8711 8547.6055 c
+-7865.7344 8547.7676 -7865.5049 8547.7793 -7865.3481 8547.6563 c
+-7861.123 8545.5967 -7858.1904 8541.1309 -7858.1626 8536.4014 c
+-7858.1626 8536.4014 l
+-7858.1328 8536.2676 -7858.2354 8536.1348 -7858.3633 8536.1221 c
+-7858.5039 8536.1055 -7858.6318 8536.1973 -7858.647 8536.3359 c
+-7858.647 8536.3359 l
+b
+-7852.9414 8541.0176 m
+-7853.042 8541.1816 -7853.1152 8541.3838 -7853.2617 8541.4824 c
+-7856.0806 8543.3906 -7858.9785 8544.6309 -7861.8848 8546.1328 c
+-7862.0503 8546.209 -7862.1118 8546.418 -7862.0313 8546.5703 c
+-7861.9512 8546.7227 -7861.7559 8546.7793 -7861.5898 8546.7041 c
+-7858.439 8545.3232 -7854.313 8544.5 -7852.6729 8541.1797 c
+-7852.6289 8541.1113 -7852.6455 8541.0146 -7852.7266 8540.9648 c
+-7852.7959 8540.9199 -7852.897 8540.9492 -7852.9414 8541.0176 c
+-7852.9414 8541.0176 l
+b
+-7852.6602 8541.918 m
+-7852.4438 8542.4297 -7852.1431 8542.8896 -7852.0503 8543.4355 c
+-7851.2183 8548.2773 -7851.1152 8553.042 -7852.248 8557.6875 c
+-7852.248 8557.6875 l
+-7852.3418 8557.9531 -7852.2114 8558.2441 -7851.9438 8558.3389 c
+-7851.6777 8558.4336 -7851.3882 8558.3125 -7851.2935 8558.0479 c
+-7849.293 8552.8115 -7849.897 8546.7373 -7852.3711 8541.7832 c
+-7852.4063 8541.7002 -7852.498 8541.6689 -7852.582 8541.6914 c
+-7852.6641 8541.7275 -7852.6978 8541.835 -7852.6602 8541.918 c
+-7852.6602 8541.918 l
+b
+-7851.5352 8557.5938 m
+-7848.8984 8555.2275 -7846.6816 8552.252 -7845.853 8548.7363 c
+-7845.853 8548.7363 l
+-7845.7246 8548.1816 -7846.0742 8547.623 -7846.6416 8547.4902 c
+-7847.1992 8547.375 -7847.7578 8547.7246 -7847.8862 8548.2793 c
+-7848.5649 8551.5313 -7849.8711 8554.6729 -7851.7954 8557.3867 c
+-7851.7954 8557.3867 l
+-7851.8462 8557.4551 -7851.834 8557.5576 -7851.7695 8557.6201 c
+-7851.6992 8557.6699 -7851.5977 8557.6582 -7851.5352 8557.5938 c
+-7851.5352 8557.5938 l
+b
+-7836.3711 8550.1826 m
+-7837.7114 8545.8301 -7840.2598 8542.0693 -7843.689 8539.1533 C
+-7843.729 8539.0723 -7843.8242 8539.0322 -7843.9038 8539.0859 C
+-7843.9863 8539.127 -7844.0122 8539.2207 -7843.9722 8539.3018 C
+-7843.957 8539.7891 -7843.7144 8540.2334 -7843.4458 8540.5313 c
+-7838.4063 8546.1621 -7834.9902 8554.7197 -7837.3433 8561.9551 C
+-7837.0762 8556.4512 -7838.7241 8550.3008 -7842.1362 8545.6738 c
+-7843.1606 8544.2695 -7844.7422 8544.1211 -7846.3081 8544.2031 C
+-7846.4023 8544.1895 -7846.4834 8544.2432 -7846.4961 8544.3369 c
+-7846.5098 8544.4189 -7846.4551 8544.5137 -7846.3623 8544.5254 C
+-7843.1479 8545.7695 -7841.4878 8549.2246 -7840.084 8552.1943 c
+-7838.415 8555.7441 -7837.7017 8559.6387 -7838.0054 8563.5 C
+-7838.0454 8563.6777 -7838.1138 8565.3975 -7837.9775 8565.4102 C
+-7837.8306 8565.4395 -7837.709 8565.3438 -7837.6802 8565.1943 C
+-7837.645 8565.0449 -7834.6426 8555.7988 -7836.3711 8550.1826 c
+b
+-7844.4863 8537.4912 m
+-7843.3945 8533.6211 -7841.1094 8530.251 -7838.4824 8527.2383 c
+-7838.3306 8527.1045 -7838.3145 8526.8867 -7838.4502 8526.7354 c
+-7838.5752 8526.6006 -7838.8047 8526.582 -7838.957 8526.7178 c
+-7842.3306 8529.332 -7843.4487 8533.541 -7844.7954 8537.375 c
+-7844.7954 8537.375 l
+-7844.8262 8537.4648 -7844.7754 8537.5586 -7844.6982 8537.5869 c
+-7844.6094 8537.6191 -7844.5166 8537.5684 -7844.4863 8537.4912 c
+-7844.4863 8537.4912 l
+b
+-7838.5313 8562.1094 m
+-7838.5991 8562.0566 -7838.707 8562.083 -7838.748 8562.1504 C
+-7838.9634 8562.4746 -7840.6914 8564.5195 -7841.3926 8565.1406 c
+-7846.1719 8569.3945 -7849.5137 8573.9609 -7857.5391 8577.7227 c
+-7864.4512 8580.9639 -7867.1113 8583.5957 -7874.3862 8581.8262 c
+-7877.687 8581.0293 -7879.0313 8580.5313 -7880.4351 8575.4551 C
+-7881.9473 8569.2988 -7880.8672 8571.7832 -7881.084 8564.4385 c
+-7881.2222 8559.6973 -7884 8548.4551 -7871.5254 8534.2598 C
+-7871.4199 8534.1484 -7871.4336 8533.9961 -7871.5337 8533.9072 C
+-7871.6328 8533.8027 -7871.7959 8533.8164 -7871.8862 8533.916 C
+-7877.5786 8538.7168 -7881.0234 8545.6582 -7882.3145 8552.9424 c
+-7883.2871 8558.4668 -7882.9199 8563.25 -7882.666 8569.6367 c
+-7882.5688 8572.0938 -7883.6855 8579.0723 -7878.9102 8583.0625 c
+-7875.3926 8586 -7870.3911 8585.5469 -7866.3545 8584.1563 c
+-7860.6992 8582.2119 -7855.9727 8579.1465 -7850.8711 8575.6094 c
+-7847.2656 8573.125 -7839.2881 8563.2852 -7838.4785 8562.3262 C
+-7838.4351 8562.2588 -7838.4502 8562.1504 -7838.5313 8562.1094 C
+b
+-7873.0503 8549.3057 m
+-7872.168 8548.5029 -7871.7017 8549.8457 -7871.4297 8550.6016 c
+-7871.1626 8551.3574 -7870.189 8551.25 -7870.5127 8551.5732 c
+-7870.8369 8551.8975 -7870.8369 8551.9521 -7871.3232 8551.5195 c
+-7871.8086 8551.0879 -7871.8086 8551.7363 -7872.5649 8551.25 c
+-7873.3198 8550.7627 -7873.645 8549.8457 -7873.0503 8549.3057 c
+b
+-7865.6519 8553.9492 m
+-7865.3657 8553.5918 -7864.6802 8553.5723 -7864.4648 8553.8945 c
+-7864.25 8554.2197 -7863.3306 8554.2734 -7863.4937 8554.5967 c
+-7863.6543 8554.9219 -7863.6016 8555.1387 -7864.0874 8554.9219 c
+-7864.5737 8554.7051 -7864.4121 8555.2998 -7864.897 8555.084 c
+-7865.3833 8554.8672 -7865.8687 8554.2197 -7865.6519 8553.9492 c
+b
+-7857.6074 8559.0791 m
+-7857.1206 8558.7559 -7855.8794 8559.5117 -7856.4727 8559.5117 c
+-7857.0674 8559.5117 -7856.311 8560.2676 -7856.8521 8560.4834 c
+-7857.3906 8560.6992 -7857.2832 8560.4297 -7857.6074 8560.6445 c
+-7857.9297 8560.8613 -7858.3633 8561.2393 -7858.5239 8560.4297 c
+-7858.6855 8559.6191 -7858.3633 8559.6191 -7857.9849 8559.3496 c
+-7857.6074 8559.0791 -7857.6074 8559.0791 y
+b
+-7872.2402 8559.3496 m
+-7871.1074 8559.2422 -7871.8633 8559.998 -7871.269 8560.4834 c
+-7870.6738 8560.9697 -7869.918 8561.6172 -7870.729 8561.4004 c
+-7871.5391 8561.1855 -7872.9961 8561.6719 -7872.9434 8560.5381 c
+-7872.8887 8559.4033 -7872.6328 8559.3867 -7872.2402 8559.3496 c
+b
+-7866.5703 8567.6113 m
+-7866.1016 8567.3438 -7866.6802 8567.7197 -7866.0303 8567.6113 c
+-7865.3833 8567.5039 -7864.7886 8567.6113 -7865.2207 8567.8281 c
+-7865.6519 8568.0439 -7866.3008 8568.1523 -7866.4634 8567.9893 c
+-7866.625 8567.8281 -7866.9473 8567.8281 -7866.5703 8567.6113 c
+b
+-7857.0674 8567.1797 m
+-7857.4785 8566.1797 -7856.0962 8566.4238 -7855.4473 8566.7461 c
+-7854.7998 8567.0723 -7853.8262 8566.4775 -7854.4209 8566.9102 c
+-7855.0137 8567.3418 -7854.7998 8566.9102 -7855.3926 8567.2334 c
+-7855.9873 8567.5566 -7856.6895 8568.0977 -7857.0674 8567.1797 c
+b
+-7872.6738 8573.0664 m
+-7872.7222 8572.0752 -7871.8086 8572.957 -7871.269 8573.0117 c
+-7870.729 8573.0664 -7870.0801 8573.0664 -7870.2432 8573.2813 c
+-7870.4038 8573.498 -7870.459 8573.498 -7871.1626 8573.7129 c
+-7871.8633 8573.9297 -7872.6191 8574.1445 -7872.6738 8573.0664 c
+b
+-7873.1582 8567.6113 m
+-7874.0664 8567.9746 -7874.293 8567.8809 -7874.5625 8568.2051 c
+-7874.834 8568.5293 -7875.1558 8569.2314 -7875.5352 8568.0977 c
+-7875.9121 8566.9629 -7875.4282 8565.7764 -7875.0479 8565.9375 c
+-7874.6714 8566.0996 -7874.293 8566.7461 -7873.8618 8566.9629 c
+-7873.4297 8567.1797 -7872.6191 8567.3945 -7873.1582 8567.6113 c
+b
+U
+U
+%AI8_EndBrushPattern
+%AI8_BeginBrushPattern
+(New Pattern 41)
+0 A
+u
+800 Ar
+0 J 0 j 1 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+-7884 8586 m
+-7803 8586 L
+-7803 8481 L
+-7884 8481 L
+-7884 8586 L
+n
+u
+u
+u
+0 O
+0 0 0 1 k
+-7865.8057 8498.4258 m
+-7866.0742 8496.6621 -7867.1602 8495.291 -7868.5239 8495.3965 c
+-7869.8862 8495.502 -7870.707 8497.0234 -7870.7432 8498.8066 c
+-7870.748 8499.0693 -7870.6743 8500.2441 -7870.6304 8500.4775 C
+-7870.6382 8500.582 -7870.6191 8500.6738 -7870.6104 8500.7803 c
+-7870.5142 8502.0254 -7869.3574 8503.3604 -7867.9414 8503.25 c
+-7866.5249 8503.1406 -7865.4897 8501.8613 -7865.6367 8500.4727 c
+-7865.644 8500.4072 -7865.6958 8499.626 -7865.707 8499.5625 C
+-7865.6816 8499.2852 -7865.7598 8498.7256 -7865.8057 8498.4258 c
+f
+-7876.2646 8507.7334 m
+-7876.9946 8515.916 -7871.5015 8515.1191 v
+-7868.3682 8514.0186 -7869.4414 8511.1211 v
+-7869.6426 8509.752 -7871.7847 8508.498 v
+-7872.146 8508.25 -7872.7632 8507.1016 v
+-7873.1294 8505.5977 -7874.5186 8505.2979 v
+-7876.0762 8505.251 -7876.2646 8507.7334 v
+f
+-7850.7646 8516.4971 m
+F
+-7850.0762 8514.3408 m
+-7850.7847 8513.1934 -7853.8848 8513.6279 Y
+-7854.811 8513.6885 -7855.3799 8513.1113 Y
+-7857.8394 8509.0918 -7861.0386 8509.8857 -7861.4082 8509.9932 C
+-7861.4097 8509.9863 L
+-7864.999 8510.6045 -7865.2666 8515.6035 V
+-7865.4912 8516.3828 -7866.335 8516.7695 V
+-7869.2695 8517.8613 -7869.3481 8519.208 V
+-7869.8999 8521.1152 -7867.6006 8521.7422 V
+-7865.6792 8522.2568 -7863.7886 8519.8945 V
+-7862.6113 8518.6797 -7859.5762 8517.9395 V
+-7859.5728 8517.9531 L
+-7856.3594 8517.0459 -7854.6392 8517.5889 Y
+-7851.8521 8518.7676 -7850.4063 8517.4014 Y
+-7848.6826 8515.7559 -7850.0762 8514.3408 Y
+f
+-7863.9834 8497.8789 m
+-7864.5854 8496.2002 -7864.2822 8494.4775 -7863.0327 8493.9229 c
+-7861.7842 8493.3672 -7860.3384 8494.3164 -7859.4585 8495.8672 c
+-7859.3286 8496.0957 -7858.8359 8497.165 -7858.7632 8497.3906 C
+-7858.7065 8497.4785 -7858.6792 8497.5684 -7858.6362 8497.667 c
+-7858.1289 8498.8086 -7858.5122 8500.5303 -7859.8105 8501.1074 c
+-7861.1089 8501.6855 -7862.6279 8501.0527 -7863.1582 8499.7617 c
+-7863.1831 8499.7002 -7863.5078 8498.9883 -7863.5298 8498.9268 C
+-7863.6831 8498.6963 -7863.8809 8498.166 -7863.9834 8497.8789 c
+f
+-7849.7129 8500.9316 m
+-7845.1802 8507.7822 -7850.3911 8509.6943 v
+-7853.6714 8510.2168 -7854.103 8507.1572 v
+-7854.5786 8505.8564 -7853.29 8503.7354 v
+-7853.0903 8503.3447 -7853.0938 8502.04 v
+-7853.4858 8500.5449 -7852.4082 8499.6182 v
+-7851.0591 8498.8359 -7849.7129 8500.9316 v
+f
+U
+u
+-7824.7358 8550.1074 m
+-7824.3687 8548.3623 -7824.9048 8546.6963 -7826.2183 8546.3164 c
+-7827.5322 8545.9375 -7828.8345 8547.0752 -7829.4937 8548.7324 c
+-7829.5903 8548.9775 -7829.9326 8550.1025 -7829.9746 8550.3369 C
+-7830.0176 8550.4326 -7830.0322 8550.5244 -7830.0625 8550.6279 c
+-7830.4087 8551.8271 -7829.7935 8553.4805 -7828.4282 8553.875 c
+-7827.063 8554.2695 -7825.645 8553.4365 -7825.2969 8552.085 c
+-7825.2793 8552.0205 -7825.0552 8551.2705 -7825.0425 8551.207 C
+-7824.9214 8550.9551 -7824.7983 8550.4053 -7824.7358 8550.1074 c
+f
+-7838.2705 8554.6172 m
+-7841.8242 8562.0244 -7836.3999 8563.2061 v
+-7833.0801 8563.2754 -7833.0688 8560.1846 v
+-7832.7778 8558.8311 -7834.3433 8556.9072 v
+-7834.5942 8556.5459 -7834.7695 8555.2539 v
+-7834.5854 8553.7188 -7835.7793 8552.9492 v
+-7837.2222 8552.3594 -7838.2705 8554.6172 v
+f
+-7817.4648 8571.7695 m
+F
+-7816.063 8569.9912 m
+-7816.3247 8568.6689 -7819.3799 8567.9883 Y
+-7820.27 8567.7197 -7820.5986 8566.9795 Y
+-7821.4922 8562.3535 -7824.7666 8561.9746 -7825.1494 8561.9453 C
+-7825.1494 8561.9395 L
+-7828.7271 8561.2588 -7830.731 8565.8467 V
+-7831.2153 8566.4961 -7832.1416 8566.5625 V
+-7835.272 8566.5557 -7835.8169 8567.7891 V
+-7837.0039 8569.3809 -7835.0713 8570.7764 V
+-7833.4526 8571.9316 -7830.853 8570.3818 V
+-7829.3242 8569.6582 -7826.2222 8570.0293 V
+-7826.2231 8570.042 L
+-7822.896 8570.3213 -7821.4766 8571.4326 Y
+-7819.2793 8573.5146 -7817.4463 8572.7432 Y
+-7815.2554 8571.8057 -7816.063 8569.9912 Y
+f
+-7822.8374 8550.2354 m
+-7822.813 8548.4512 -7821.9258 8546.9453 -7820.5601 8546.8633 c
+-7819.1943 8546.7803 -7818.1743 8548.1768 -7817.895 8549.9385 c
+-7817.854 8550.1973 -7817.7666 8551.3711 -7817.7778 8551.6094 C
+-7817.7559 8551.7109 -7817.7617 8551.8037 -7817.7559 8551.9121 c
+-7817.6807 8553.1592 -7818.644 8554.6367 -7820.0625 8554.7217 c
+-7821.4814 8554.8066 -7822.6826 8553.6826 -7822.7246 8552.2871 c
+-7822.7271 8552.2217 -7822.7822 8551.4404 -7822.7798 8551.375 C
+-7822.8433 8551.1045 -7822.8423 8550.54 -7822.8374 8550.2354 c
+f
+-7811.0186 8557.5625 m
+-7809.1777 8565.5684 -7814.7271 8565.5303 v
+-7817.9834 8564.8691 -7817.3154 8561.8516 v
+-7817.3032 8560.4668 -7815.353 8558.9326 v
+-7815.0278 8558.6377 -7814.5742 8557.415 v
+-7814.417 8555.876 -7813.083 8555.3877 v
+-7811.5454 8555.1279 -7811.0186 8557.5625 v
+f
+U
+U
+1 Ap
+-7884 8586 m
+-7884 8481 L
+-7803 8481 L
+-7803 8586 L
+-7884 8586 L
+n
+U
+U
+%AI8_EndBrushPattern
+%AI8_BeginBrushPattern
+(New Pattern 42)
+0 A
+u
+0 Ap
+800 Ar
+0 J 0 j 1 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+-7857.4609 8559.085 m
+-7885 8559.085 L
+-7885 8586.624 L
+-7857.4609 8586.624 L
+-7857.4609 8559.085 L
+n
+0 O
+0 0.55 1 0.12 k
+-7871.7598 8577.3623 m
+-7871.7598 8587 L
+-7870.6343 8587 L
+-7870.6343 8577.3623 L
+-7871.7598 8577.3623 L
+f
+0 0.55 1 0.3 k
+-7875.4233 8572.876 m
+-7874.3096 8571.1553 -7870.8809 8569.457 -7866.4966 8569.457 c
+-7862.1152 8569.457 -7858.6138 8571.1064 -7857.5718 8572.874 C
+-7857.5718 8572.874 L
+-7858.6138 8574.6006 -7862.1152 8576.2979 -7866.4966 8576.2979 c
+-7870.875 8576.2979 -7874.3242 8574.5615 -7875.4233 8572.876 C
+f
+U
+%AI8_EndBrushPattern
+%AI8_BeginBrushPattern
+(New Pattern 45)
+0 A
+u
+800 Ar
+0 J 0 j 1 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+-7885 8543.918 m
+-7885 8587 L
+-7798.2217 8587 L
+-7798.2217 8543.918 L
+-7885 8543.918 L
+n
+u
+u
+0 O
+0 0 0 1 k
+-7825.2217 8573.2363 m
+-7825.2217 8581.0742 L
+-7813.2217 8574.1445 L
+-7801.2217 8567.2168 L
+-7813.2217 8560.2891 L
+-7825.2217 8553.3613 L
+-7825.2217 8561.4824 L
+-7883.9351 8547.7168 L
+-7870.9878 8566.8027 L
+-7885 8587 L
+-7825.2217 8573.2363 L
+f
+0 1 1 0.1 k
+0 R
+0 0 0 1 K
+-7823.2217 8570.2363 m
+-7823.2217 8578.0742 L
+-7811.2217 8571.1445 L
+-7799.2217 8564.2168 L
+-7811.2217 8557.2891 L
+-7823.2217 8550.3613 L
+-7823.2217 8558.4824 L
+-7881.9351 8544.7168 L
+-7867.2754 8564.3594 L
+-7881.9351 8584 L
+-7823.2217 8570.2363 L
+b
+U
+U
+U
+%AI8_EndBrushPattern
+%AI8_BeginBrushPattern
+(New Pattern 50)
+0 A
+u
+800 Ar
+0 J 0 j 1 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+-7884 8586 m
+-7756.877 8586 L
+-7756.877 8538.415 L
+-7884 8538.415 L
+-7884 8586 L
+n
+u
+*u
+0 O
+0.9529 0.949 0.1961 0.0745 k
+-7857.793 8570.417 m
+-7857.8232 8570.2676 L
+-7859.9849 8564.3643 -7860.9438 8561.6377 -7861.2754 8560.2891 c
+-7861.3657 8560.2891 L
+-7861.6953 8561.6074 -7862.7754 8564.335 -7864.9673 8570.2676 c
+-7864.9966 8570.417 L
+-7857.793 8570.417 l
+f
+1 D
+-7868.1182 8578.9678 m
+-7869.6191 8582.5371 -7870.3994 8584.709 -7868.1182 8584.917 c
+-7868.1182 8585.9678 L
+-7870.6992 8585.9375 -7873.5806 8585.917 -7876.3418 8585.917 c
+-7880.0649 8585.917 -7882.5273 8585.9375 -7884 8585.9678 c
+-7884 8584.917 L
+-7882.1064 8584.709 -7881.0542 8582.5674 -7873.5513 8565.5029 c
+-7861.6953 8538.415 L
+-7859.8638 8538.415 L
+-7848.1582 8565.5029 L
+-7840.8047 8582.5078 -7839.7246 8584.709 -7837.8887 8584.917 c
+-7837.8887 8585.9678 L
+-7839.5142 8585.9375 -7841.916 8585.917 -7845.5767 8585.917 c
+-7848.5488 8585.917 -7851.6694 8585.9375 -7854.7026 8585.9678 c
+-7854.7026 8584.917 L
+-7852.481 8584.709 -7853.3218 8582.5078 -7854.7617 8578.9678 C
+-7868.1182 8578.9678 l
+f
+*U
+*u
+0 D
+-7813.0762 8554.0811 m
+-7813.0762 8550.4717 -7815.3535 8548.0947 -7819.1294 8548.0947 c
+-7820.2383 8548.0947 -7821.0767 8548.2158 -7821.5273 8548.2451 c
+-7821.5273 8560.5479 L
+-7820.8672 8560.6084 -7820.208 8560.6084 -7819.729 8560.6084 c
+-7818.2002 8560.6084 -7816.7026 8560.127 -7815.6841 8559.4053 c
+-7814.3945 8558.5332 -7813.0762 8556.7881 -7813.0762 8554.1416 C
+-7813.0762 8554.0811 l
+f
+1 D
+-7832.0806 8558.3926 m
+-7832.0806 8542.6445 -7832.0806 8540.4287 -7834.542 8540.2783 c
+-7834.542 8539.3184 L
+-7833.042 8539.2588 -7830.3174 8539.1992 -7827.5664 8539.1689 c
+-7825.6538 8539.1084 -7822.3945 8539.0186 -7820.1479 8538.9775 c
+-7816.582 8538.9775 -7813.585 8539.4258 -7811.0049 8540.2627 c
+-7806.353 8541.8477 -7801.9702 8545.8525 -7801.9702 8553.6602 c
+-7801.9702 8558.7432 -7804.4014 8562.3193 -7806.5034 8564.0605 c
+-7807.583 8565.0215 -7808.8135 8565.832 -7809.7744 8566.3125 c
+-7809.7744 8566.4629 L
+-7807.5234 8569.4912 -7805.6025 8572.0625 -7799.3906 8580.6426 c
+-7797.5 8583.0645 -7795.9102 8584.7383 -7794.7402 8584.9775 c
+-7794.7402 8586 L
+-7796.6602 8586 -7799 8585.8848 -7801.1294 8585.8848 c
+-7803.3511 8585.8848 -7804.8521 8586 -7806.4424 8586 c
+-7807.6729 8586 -7808.7241 8585.9404 -7809.5039 8585.2725 c
+-7813.0151 8579.8477 -7816.9121 8573.7559 -7820.1182 8568.7139 c
+-7820.5078 8568.7139 -7820.957 8568.7139 -7821.5273 8568.7139 c
+-7821.5273 8571.2852 L
+-7821.5273 8582.5264 -7821.437 8584.7686 -7819.1895 8584.9775 c
+-7819.1895 8585.9697 L
+-7820.6279 8585.9404 -7823.9194 8585.915 -7826.6992 8585.915 c
+-7829.9287 8585.915 -7832.8921 8585.9404 -7834.5122 8585.9697 c
+-7834.5122 8584.9775 L
+-7832.0518 8584.7686 -7832.0806 8582.5264 -7832.0806 8565.5918 C
+-7832.0806 8558.3926 l
+f
+*U
+*u
+0 D
+-7781.4561 8565.5928 m
+-7781.4561 8582.4941 -7781.4561 8584.6484 -7784.2832 8584.9775 C
+-7784.2832 8585.9697 l
+-7782.3887 8585.9404 -7779.0542 8585.915 -7775.7822 8585.915 c
+-7772.6294 8585.915 -7769.5688 8585.9404 -7767.2881 8585.9697 C
+-7767.2881 8584.9775 l
+-7770.2578 8584.9775 -7770.2881 8582.5244 -7770.2881 8565.5928 C
+-7770.2881 8548.1514 L
+-7762.8193 8548.1514 l
+-7759.999 8548.1514 -7758.5298 8548.96 -7757.8994 8551.2627 C
+-7756.9072 8551.2627 l
+-7756.9072 8546.4697 -7756.877 8542.415 -7756.877 8539.1709 c
+-7761.3486 8539.2012 -7766.748 8539.2314 -7772.0601 8539.2314 C
+-7779.7446 8539.2314 l
+-7784.5537 8539.2314 -7789.9966 8539.2012 -7794.9614 8539.1709 c
+-7794.9614 8542.3848 -7794.9326 8546.4697 -7794.9326 8551.2627 C
+-7793.9072 8551.2627 l
+-7793.3657 8549.1094 -7791.771 8548.1514 -7788.9438 8548.1514 C
+-7781.4561 8548.1514 l
+-7781.4561 8565.5928 L
+f
+*U
+U
+U
+%AI8_EndBrushPattern
+%AI8_BeginBrushPattern
+(New Pattern 62)
+0 A
+u
+800 Ar
+0 J 0 j 1 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+-7885 8587 m
+-7885 8548.7305 L
+-7846.7305 8548.7305 L
+-7846.7305 8587 L
+-7885 8587 L
+n
+0 O
+1 0.14 0.09 0 k
+-7846.7305 8569.9043 m
+-7846.7305 8561.3408 L
+-7885 8561.3408 L
+-7885 8569.9043 L
+-7846.7305 8569.9043 L
+f
+-7846.7305 8573.0967 m
+-7846.7305 8572.4229 L
+-7885 8572.4229 L
+-7885 8573.0967 L
+-7846.7305 8573.0967 L
+f
+U
+%AI8_EndBrushPattern
+%AI8_BeginBrushPattern
+(New Pattern 63)
+0 A
+u
+800 Ar
+0 J 0 j 1 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+-7885 8587 m
+-7885 8548.7305 L
+-7846.7305 8548.7305 L
+-7846.7305 8587 L
+-7885 8587 L
+n
+0 O
+1 0.14 0.09 0 k
+-7846.7305 8565.8262 m
+-7846.7305 8574.3896 L
+-7859.3408 8574.3896 L
+-7859.3408 8587 L
+-7867.9038 8587 L
+-7867.9063 8565.8262 L
+-7867.9038 8565.8262 L
+-7867.9038 8565.8252 L
+-7846.7305 8565.8262 L
+f
+-7846.7305 8563.3076 m
+-7870.4233 8563.3076 L
+-7870.4233 8587 L
+-7871.0967 8587 L
+-7871.0977 8562.6328 L
+-7846.7305 8562.6328 L
+-7846.7305 8563.3076 L
+f
+U
+%AI8_EndBrushPattern
+%AI8_BeginBrushPattern
+(New Pattern 64)
+0 A
+u
+800 Ar
+0 J 0 j 1 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+-7885 8586.999 m
+-7885 8548.7285 L
+-7846.7305 8548.7285 L
+-7846.7305 8586.999 L
+-7885 8586.999 L
+n
+0 O
+1 0.14 0.09 0 k
+-7846.7305 8561.3389 m
+-7872.3896 8561.3389 L
+-7872.3896 8586.999 L
+-7863.8262 8587 L
+-7863.8262 8569.9033 L
+-7846.7305 8569.9033 L
+-7846.7305 8561.3389 L
+f
+-7846.7305 8572.4219 m
+-7861.3081 8572.4219 L
+-7861.3081 8587 L
+-7860.6338 8587 L
+-7860.6338 8573.0957 L
+-7846.7305 8573.0957 L
+-7846.7305 8572.4219 L
+f
+U
+%AI8_EndBrushPattern
+%AI8_BeginBrushPattern
+(New Pattern 65)
+0 A
+u
+1 Ap
+800 Ar
+0 J 0 j 1 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+-7857.0625 8559.4609 m
+-7884.6025 8559.4609 L
+-7884.6025 8587 L
+-7857.0625 8587 L
+-7857.0625 8559.4609 L
+n
+0 O
+0 0.55 1 0.12 k
+-7856.8418 8572.7002 m
+-7885 8572.7002 L
+-7885 8573.8252 L
+-7856.8418 8573.8252 L
+-7856.8418 8572.7002 L
+f
+u
+0 0.55 1 0.3 k
+-7883.9814 8560.5215 m
+-7884.4102 8562.5254 -7883.1865 8566.1514 -7880.0874 8569.251 c
+-7876.9878 8572.3496 -7873.3457 8573.6602 -7871.3594 8573.1455 C
+-7871.3594 8573.1455 L
+-7870.875 8571.1895 -7872.1519 8567.5117 -7875.25 8564.4141 c
+-7878.3457 8561.3184 -7882.0122 8560.1064 -7883.9814 8560.5215 C
+f
+0 0.39 0.7 0.12 k
+-7883.9814 8585.9912 m
+-7884.4102 8583.9883 -7883.1865 8580.3613 -7880.0874 8577.2617 c
+-7876.9878 8574.1641 -7873.3457 8572.8535 -7871.3594 8573.3672 C
+-7871.3594 8573.3672 L
+-7870.875 8575.3242 -7872.1519 8579.001 -7875.25 8582.0996 c
+-7878.3457 8585.1953 -7882.0122 8586.4063 -7883.9814 8585.9912 C
+f
+U
+u
+0 0.55 1 0.3 k
+-7870.1782 8585.9912 m
+-7870.6074 8583.9883 -7869.3838 8580.3613 -7866.2842 8577.2617 c
+-7863.1855 8574.1641 -7859.543 8572.8535 -7857.5576 8573.3672 C
+-7857.5566 8573.3672 L
+-7857.0718 8575.3242 -7858.3496 8579.001 -7861.4473 8582.0996 c
+-7864.543 8585.1953 -7868.209 8586.4063 -7870.1782 8585.9912 C
+f
+0 0.39 0.7 0.12 k
+-7870.1782 8560.5215 m
+-7870.6074 8562.5254 -7869.3838 8566.1514 -7866.2842 8569.251 c
+-7863.1855 8572.3496 -7859.543 8573.6602 -7857.5576 8573.1455 C
+-7857.5566 8573.1455 L
+-7857.0718 8571.1895 -7858.3496 8567.5117 -7861.4473 8564.4141 c
+-7864.543 8561.3184 -7868.209 8560.1064 -7870.1782 8560.5215 C
+f
+U
+U
+%AI8_EndBrushPattern
+%AI8_BeginBrushPattern
+(New Pattern 67)
+0 A
+u
+0 Ap
+800 Ar
+0 J 0 j 1 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+-7857.4609 8559.085 m
+-7885 8559.085 L
+-7885 8586.624 L
+-7857.4609 8586.624 L
+-7857.4609 8559.085 L
+n
+0 O
+0 0.55 1 0.12 k
+-7871.7598 8577.3623 m
+-7871.7598 8587 L
+-7870.6343 8587 L
+-7870.6343 8577.3623 L
+-7871.7598 8577.3623 L
+f
+0 0.55 1 0.3 k
+-7875.4233 8572.876 m
+-7874.3096 8571.1553 -7870.8809 8569.457 -7866.4966 8569.457 c
+-7862.1152 8569.457 -7858.6138 8571.1064 -7857.5718 8572.874 C
+-7857.5718 8572.874 L
+-7858.6138 8574.6006 -7862.1152 8576.2979 -7866.4966 8576.2979 c
+-7870.875 8576.2979 -7874.3242 8574.5615 -7875.4233 8572.876 C
+f
+U
+%AI8_EndBrushPattern
+%AI8_BeginBrushPattern
+(New Pattern 69)
+0 A
+u
+800 Ar
+0 J 0 j 1 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+-7857.4609 8559.4609 m
+-7885 8559.4609 L
+-7885 8587 L
+-7857.4609 8587 L
+-7857.4609 8559.4609 L
+n
+0 O
+0 0.55 1 0.3 k
+-7875.4233 8573.252 m
+-7874.3096 8571.5313 -7870.8809 8569.833 -7866.4966 8569.833 c
+-7862.1152 8569.833 -7858.6138 8571.4824 -7857.5718 8573.25 C
+-7857.5718 8573.25 L
+-7858.6138 8574.9766 -7862.1152 8576.6738 -7866.4966 8576.6738 c
+-7870.875 8576.6738 -7874.3242 8574.9375 -7875.4233 8573.252 C
+f
+U
+%AI8_EndBrushPattern
+%AI8_BeginBrushPattern
+(New Pattern 83)
+0 A
+u
+800 Ar
+0 J 0 j 1 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+-7884 8585.9355 m
+-7670.4009 8585.9355 L
+-7670.4009 8578.1348 L
+-7884 8578.1348 L
+-7884 8585.9355 L
+n
+0 O
+0 0 0 1 k
+-7884 8582.0352 m
+-7873.9858 8584.5273 -7867.187 8585.875 -7855.2007 8585.9355 c
+-7842.2183 8586 -7777.2002 8585.9355 y
+-7712.1816 8586 -7699.2002 8585.9355 v
+-7687.2129 8585.875 -7680.415 8584.5273 -7670.4009 8582.0352 C
+-7680.415 8579.543 -7687.2129 8578.1953 -7699.2002 8578.1348 c
+-7712.1816 8578.0693 -7777.2002 8578.1348 y
+-7842.2183 8578.0693 -7855.2007 8578.1348 v
+-7867.187 8578.1953 -7873.9858 8579.543 -7884 8582.0352 C
+f
+U
+%AI8_EndBrushPattern
+%AI5_End_NonPrinting--
+%AI5_Begin_NonPrinting
+Np
+4 Bn
+%AI5_BeginGradient: (Black, White)
+(Black, White) 0 2 Bd
+[
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+0 %_Br
+[
+0 0 50 100 %_BS
+%_0 0 50 100 Bs
+1 0 50 0 %_BS
+%_1 0 50 0 Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Chrome)
+(Chrome) 0 6 Bd
+[
+0
+<
+464646454545444444444343434342424241414141404040403F3F3F3E3E3E3E3D3D3D3C3C3C3C3B
+3B3B3B3A3A3A39393939383838383737373636363635353535343434333333333232323131313130
+3030302F2F2F2E2E2E2E2D2D2D2D2C2C2C2B2B2B2B2A2A2A2A292929282828282727272626262625
+2525252424242323232322222222212121202020201F1F1F1F1E1E1E1D1D1D1D1C1C1C1B1B1B1B1A
+1A1A1A1919191818181817171717161616151515151414141413131312121212111111101010100F
+0F0F0F0E0E0E0D0D0D0D0C0C0C0C0B0B0B0A0A0A0A09090909080808070707070606060505050504
+04040403030302020202010101010000
+>
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+<
+1F1E1E1E1E1E1E1E1E1E1D1D1D1D1D1D1D1D1C1C1C1C1C1C1C1C1B1B1B1B1B1B1B1B1B1A1A1A1A1A
+1A1A1A19191919191919191818181818181818181717171717171717161616161616161615151515
+15151515151414141414141414131313131313131312121212121212121211111111111111111010
+1010101010100F0F0F0F0F0F0F0F0F0E0E0E0E0E0E0E0E0D0D0D0D0D0D0D0D0C0C0C0C0C0C0C0C0C
+0B0B0B0B0B0B0B0B0A0A0A0A0A0A0A0A090909090909090909080808080808080807070707070707
+07060606060606060606050505050505050504040404040404040303030303030303030202020202
+02020201010101010101010000000000
+>
+1 %_Br
+0
+0.275
+1
+<
+6B6A696867666564636261605F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544
+434241403F3E3D3C3B3A393837363534333231302F2E2D2C2B2A292827262524232221201F
+>
+1 %_Br
+0
+<
+00000101010102020202030303040404040505050506060607070707080808090909090A0A0A0A0B
+0B0B0C0C0C0C0D0D0D0D0E0E0E0F0F0F0F1010101011111112121212131313141414141515151516
+161617171717181818181919191A1A1A1A1B1B1B1C1C1C1C1D1D1D1D1E1E1E1F1F1F1F2020202021
+212122222222232323232424242525252526262626272727282828282929292A2A2A2A2B2B2B2B2C
+2C2C2D2D2D2D2E2E2E2E2F2F2F303030303131313132323233333333343434353535353636363637
+373738383838393939393A3A3A3B3B3B3B3C3C3C3D3D3D3D3E3E3E3E3F3F3F404040404141414142
+42424343434344444444454545464646
+>
+<
+000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
+28292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F
+505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F7071727374757677
+78797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F
+A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7
+C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF
+F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
+>
+<
+00000101020203030304040505050606070708080809090A0A0B0B0B0C0C0D0D0D0E0E0F0F101010
+1111121212131314141515151616171718181819191A1A1A1B1B1C1C1D1D1D1E1E1F1F1F20202121
+222222232324242525252626272727282829292A2A2A2B2B2C2C2D2D2D2E2E2F2F2F303031313232
+32333334343435353636373737383839393A3A3A3B3B3C3C3C3D3D3E3E3F3F3F4040414142424243
+434444444545464647474748484949494A4A4B4B4C4C4C4D4D4E4E4F4F4F50505151515252535354
+54545555565657575758585959595A5A5B5B5C5C5C5D5D5E5E5E5F5F606061616162626363646464
+6565666666676768686969696A6A6B6B
+>
+1 %_Br
+1
+0 %_Br
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+<
+4D4C4C4C4B4B4B4A4A4A4A4949494848484747474746464645454544444444434343424242414141
+414040403F3F3F3E3E3E3E3D3D3D3C3C3C3B3B3B3B3A3A3A39393938383838373737363636353535
+35343434333333323232323131313030302F2F2F2E2E2E2E2D2D2D2C2C2C2B2B2B2B2A2A2A292929
+282828282727272626262525252524242423232322222222212121202020201F1F1F1E1E1E1D1D1D
+1D1C1C1C1B1B1B1A1A1A1A1919191818181717171616161615151514141413131313121212111111
+101010100F0F0F0E0E0E0D0D0D0D0C0C0C0B0B0B0A0A0A0A09090908080807070707060606050505
+04040404030303020202010101010000
+>
+0
+0
+1 %_Br
+[
+1 0 50 92 %_BS
+%_1 0 50 92 Bs
+0 0.275 1 0.12 1 50 59 %_BS
+%_0 0.275 1 0.12 1 50 59 Bs
+0 0.275 1 0.42 1 50 50 %_BS
+%_0 0.275 1 0.42 1 50 50 Bs
+1 0 50 49 %_BS
+%_1 0 50 49 Bs
+1 0 50 41 %_BS
+%_1 0 50 41 Bs
+1 0.3 0 0 1 50 0 %_BS
+%_1 0.3 0 0 1 50 0 Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Rainbow)
+(Rainbow) 0 6 Bd
+[
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+1
+0
+0
+1 %_Br
+1
+<
+0708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E
+2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F50515253545556
+5758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E
+7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6
+A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCE
+CFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6
+F7F8F9FAFBFCFDFEFF
+>
+0
+0
+1 %_Br
+1
+<
+00000000000000000000000000000000000001010101010101010101010101010101010101010101
+01010101010101010101010101010202020202020202020202020202020202020202020202020202
+02020202020202020202030303030303030303030303030303030303030303030303030303030303
+03030303030304040404040404040404040404040404040404040404040404040404040404040404
+04040505050505050505050505050505050505050505050505050505050505050505050505050606
+06060606060606060606060606060606060606060606060606060606060606060607070707070707
+07070707070707070707070707070707
+>
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+0
+1 %_Br
+<
+000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
+28292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F
+505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F7071727374757677
+78797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F
+A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7
+C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF
+F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
+>
+0
+1
+0
+1 %_Br
+0
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+1
+0
+1 %_Br
+[
+0 1 0 0 1 50 100 %_BS
+%_0 1 0 0 1 50 100 Bs
+1 1 0 0 1 50 80 %_BS
+%_1 1 0 0 1 50 80 Bs
+1 0.0279 0 0 1 50 60 %_BS
+%_1 0.0279 0 0 1 50 60 Bs
+1 0 1 0 1 50 40 %_BS
+%_1 0 1 0 1 50 40 Bs
+0 0 1 0 1 50 20 %_BS
+%_0 0 1 0 1 50 20 Bs
+0 1 1 0 1 50 0 %_BS
+%_0 1 1 0 1 50 0 Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Yellow & Orange Radial)
+(Yellow & Orange Radial) 1 2 Bd
+[
+0
+<
+0001010203040506060708090A0B0C0C0D0E0F10111213131415161718191A1B1C1D1D1E1F202122
+232425262728292A2B2B2C2D2E2F303132333435363738393A3B3C3D3E3E3F404142434445464748
+494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F60606162636465666768696A6B6C6D6E6F
+707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C
+>
+<
+FFFFFFFFFEFEFEFEFEFEFEFDFDFDFDFDFDFCFCFCFCFCFCFBFBFBFBFBFBFAFAFAFAFAFAF9F9F9F9F9
+F9F8F8F8F8F8F8F7F7F7F7F7F7F6F6F6F6F6F6F5F5F5F5F5F5F4F4F4F4F4F3F3F3F3F3F3F2F2F2F2
+F2F2F1F1F1F1F1F0F0F0F0F0F0EFEFEFEFEFEFEEEEEEEEEEEDEDEDEDEDEDECECECECECEBEBEBEBEB
+EBEAEAEAEAEAE9E9E9E9E9E9E8E8E8E8E8E8E7E7E7E7E7E6E6E6E6E6E6
+>
+0
+1 %_Br
+[
+0 0 1 0 1 52 19 %_BS
+%_0 0 1 0 1 52 19 Bs
+0 0.55 0.9 0 1 50 100 %_BS
+%_0 0.55 0.9 0 1 50 100 Bs
+BD
+%AI5_EndGradient
+%AI5_End_NonPrinting--
+%AI5_BeginPalette
+0 0 Pb
+0 0 0 0 k
+(WHITE) Pc
+1 1 1 1 ([Registration]) 0 Xs
+([Registration]) Pc
+0 0 0 1 k
+(C=0 M=0 Y=0 K=100) Pc
+Bb
+2 (Black, White) -7885 8587 0 0 1 0 0 1 0 0 Bg
+0 BB
+(Black, White) Pc
+Bb
+2 (Chrome) -7885 8587 0 0 1 0 0 1 0 0 Bg
+0 BB
+(Chrome) Pc
+Bb
+2 (Rainbow) -7885 8587 0 0 1 0 0 1 0 0 Bg
+0 BB
+(Rainbow) Pc
+Bb
+0 0 0 0 Bh
+2 (Yellow & Orange Radial) -7885 8587 0 0 1 0 0 1 0 0 Bg
+0 BB
+(Yellow & Orange Radial) Pc
+(Brick) 0 0 1 1 0 0 0 0 0 [1 0 0 1 0 0] p
+(Brick) Pc
+(Confetti) 0 0 1 1 0 0 0 0 0 [1 0 0 1 0 0] p
+(Confetti) Pc
+(Leaves - Fall ) 0 0 1 1 0 0 0 0 0 [1 0 0 1 0 0] p
+(Leaves - Fall ) Pc
+(Stripes) 0 0 1 1 0 0 0 0 0 [1 0 0 1 0 0] p
+(Stripes) Pc
+0.91 0.01 0.93 0 (PANTONE 354 2X CVC) 0 x
+(PANTONE 354 2X CVC) Pc
+0 1 0.91 0 (PANTONE 485 CVC) 0 x
+(PANTONE 485 CVC) Pc
+0 0.51 1 0 (PANTONE 152 CVC) 0 x
+(PANTONE 152 CVC) Pc
+PB
+%AI5_EndPalette
+%AI5_Begin_NonPrinting
+Np
+%AI8_BeginPluginObject
+(Adobe Brush Manager Order)
+(Adobe Brush Manager Order)
+( Adobe Calligraphic Brush Tool/ 6 pt Flat / Adobe Calligraphic Brush T) -
+(ool/ 10 pt Oval/ Adobe Calligraphic Brush Tool/ 12 pt Oval / Adobe Cal) -
+(ligraphic Brush Tool/ 20 pt Oval/ Adobe Calligraphic Brush Tool/ 25 pt) -
+( Round / Adobe Calligraphic Brush Tool/ 50 pt Flat/ Adobe Scatter Brus) -
+(h Tool/ Dog Tracks/ Adobe Scatter Brush Tool/ Fall Leaf/ Adobe Scatter) -
+( Brush Tool/ Ladybug/ Adobe Scatter Brush Tool/ Push Pin/ Adobe Scatte) -
+(r Brush Tool/ Strawberry/ Adobe Scatter Brush Tool/ Twinkle Star / Ado) -
+(be ArtOnPath Brush Tool/ Marker/ Adobe ArtOnPath Brush Tool/ Tapered S) -
+(troke/ Adobe ArtOnPath Brush Tool/ Arrow/ Adobe ArtOnPath Brush Tool/ ) -
+(Paintbrush/ Adobe ArtOnPath Brush Tool/ Type/ Adobe PatternOnPath Brus) -
+(h Tool/ Double Lines/ Adobe PatternOnPath Brush Tool/ Laurel/ Adobe Pa) -
+(tternOnPath Brush Tool/ Rope /) .
+%AI8_EndPluginObject
+%AI8_BeginPluginObject
+(Adobe Calligraphic Brush Tool)
+(6 pt Flat )
+(1 4 8 10 10 90 90 2 0 0 0) .
+%AI8_EndPluginObject
+%AI8_BeginPluginObject
+(Adobe Calligraphic Brush Tool)
+(10 pt Oval)
+(1 1 19 15 15 130 130 2 0 0 0) .
+%AI8_EndPluginObject
+%AI8_BeginPluginObject
+(Adobe Calligraphic Brush Tool)
+(12 pt Oval )
+(1 7 17 45 45 0 0 2 0 0 0) .
+%AI8_EndPluginObject
+%AI8_BeginPluginObject
+(Adobe Calligraphic Brush Tool)
+(20 pt Oval)
+(1 20 20 20 100 40 80 0 2 1 0) .
+%AI8_EndPluginObject
+%AI8_BeginPluginObject
+(Adobe Calligraphic Brush Tool)
+(25 pt Round )
+(1 10 40 100 100 0 0 2 0 0 0) .
+%AI8_EndPluginObject
+%AI8_BeginPluginObject
+(Adobe Calligraphic Brush Tool)
+(50 pt Flat)
+(1 40 60 0 0 44 44 0 0 0 0) .
+%AI8_EndPluginObject
+%AI8_BeginPluginObject
+(Adobe ArtOnPath Brush Tool)
+(Arrow)
+(1 / New Pattern 45/ / / / / 5 0.898039 0 0 / 2 0 1 0 1 0 0 0) .
+%AI8_EndPluginObject
+%AI8_BeginPluginObject
+(Adobe ArtOnPath Brush Tool)
+(Marker)
+(1 / New Pattern 8/ / / / / 0 0 / 1 1 1 0 1 0 0 0) .
+%AI8_EndPluginObject
+%AI8_BeginPluginObject
+(Adobe ArtOnPath Brush Tool)
+(Paintbrush)
+(1 / New Pattern 5/ / / / / 1 0.5 0.85 1 0.45 / 0 0 1 0 1 0 0 0) .
+%AI8_EndPluginObject
+%AI8_BeginPluginObject
+(Adobe ArtOnPath Brush Tool)
+(Tapered Stroke)
+(1 / New Pattern 83/ / / / / 1 0 0 0 1 / 1 1 1 0 1 0 0 0) .
+%AI8_EndPluginObject
+%AI8_BeginPluginObject
+(Adobe ArtOnPath Brush Tool)
+(Type)
+(1 / New Pattern 50/ / / / / 1 0.952941 0.94902 0.196078 0.0745098 / 1) -
+( 0 1 0 1 0 0 0) .
+%AI8_EndPluginObject
+%AI8_BeginPluginObject
+(Adobe PatternOnPath Brush Tool)
+(Double Lines)
+(1 / New Pattern 62/ New Pattern 63/ New Pattern 64/ / / 1 1 0.14 0.09 ) -
+(0 / 1 0 1 0 1 0 0 0) .
+%AI8_EndPluginObject
+%AI8_BeginPluginObject
+(Adobe PatternOnPath Brush Tool)
+(Laurel)
+(1 / New Pattern 65/ New Pattern 42/ New Pattern 67/ / New Pattern 69/ ) -
+(1 0 0.55 1 0.3 / 1 0 1 0 1 0 0 0) .
+%AI8_EndPluginObject
+%AI8_BeginPluginObject
+(Adobe PatternOnPath Brush Tool)
+(Rope )
+(1 / New Pattern 1/ / / New Pattern 3/ New Pattern 6/ 5 0 0 0 / 1 0 1 ) -
+(0 1 0 0 0) .
+%AI8_EndPluginObject
+%AI8_BeginPluginObject
+(Adobe Scatter Brush Tool)
+(Dog Tracks)
+(1 /New Pattern 41/ 1 0 0 0 1 / 0 1 1 0 1 1 0 0 0 0 -90 -90 0 1 0) .
+%AI8_EndPluginObject
+%AI8_BeginPluginObject
+(Adobe Scatter Brush Tool)
+(Fall Leaf)
+(1 /New Pattern 34/ 1 0.0745 0.9 0.9019 0.18 / 0 0.602793 1 1 0.1 1 1 -) -
+(1 1 1 -180 180 1 0 0) .
+%AI8_EndPluginObject
+%AI8_BeginPluginObject
+(Adobe Scatter Brush Tool)
+(Ladybug)
+(1 /New Pattern 10/ 5 0.898039 0 0 / 0 1 1 0 0.803911 1.2 1 -1.55 1.55 ) -
+(1 -180 180 1 0 0) .
+%AI8_EndPluginObject
+%AI8_BeginPluginObject
+(Adobe Scatter Brush Tool)
+(Push Pin)
+(1 /New Pattern 36/ 1 0.025 0.1 0.475 0 / 0 1 1 0 0.401676 1 1 -1.06145) -
+( 1.06 1 -180 180 1 0 0) .
+%AI8_EndPluginObject
+%AI8_BeginPluginObject
+(Adobe Scatter Brush Tool)
+(Strawberry)
+(1 /New Pattern 37/ 1 0 0 0 1 / 0 0.803911 1 1 0.803911 1 1 -0.5 0.5 1 ) -
+(-75 75.419 1 0 0) .
+%AI8_EndPluginObject
+%AI8_BeginPluginObject
+(Adobe Scatter Brush Tool)
+(Twinkle Star )
+(1 /New Pattern 2/ 0 1 / 1 0.5 1 1 0.25 1 1 -0.5 0.5 1 0 0 0 0 0) .
+%AI8_EndPluginObject
+%AI5_End_NonPrinting--
+%AI5_Begin_NonPrinting
+Np
+%AI8_PluginGroupInfo
+(Adobe Path Blends) (Adobe Blends Plugin) (Live Blends)
+%AI8_PluginGroupInfo
+(Adobe PatternOnPath Brush Tool) (Adobe Pattern Brush Plugin) (Art Brush Tool)
+%AI8_PluginGroupInfo
+(Adobe ArtOnPath Brush Tool) (Adobe Art Brush Plugin) (Art Brush Tool)
+%AI8_PluginGroupInfo
+(Adobe Calligraphic Brush Tool) (Undo New Calligraphic Brush) (Calligraphic Brush Tool)
+%AI8_PluginGroupInfo
+(Adobe Scatter Brush Tool) (Adobe Scatter Brush Plugin) (Scatter Brush Tool)
+%AI5_End_NonPrinting--
+%%EndSetup
+%AI5_BeginLayer
+1 1 0 1 0 0 1 8 0 0 0 0 50 Lb
+(border) Ln
+0 A
+1 Ap
+0 R
+0 0 0 1 K
+800 Ar
+0 J 0 j 5.2327 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+390.7588 335.9102 m
+390.7588 333.4834 388.5283 331.5156 385.7754 331.5156 C
+220.209 331.5156 L
+217.457 331.5156 215.2256 333.4834 215.2256 335.9102 C
+215.2256 481.3916 L
+215.2256 483.8184 217.457 485.7856 220.209 485.7856 C
+385.7754 485.7856 L
+388.5283 485.7856 390.7588 483.8184 390.7588 481.3916 C
+390.7588 335.9102 L
+s
+LB
+%AI5_EndLayer--
+%AI5_BeginLayer
+1 1 0 1 0 0 1 20 102 102 0 0 50 Lb
+(tv) Ln
+0 A
+0 O
+0 0 0 1 k
+0 R
+0 0 0 1 K
+800 Ar
+0 J 0 j 3 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+377.3408 366.4893 m
+377.3408 363.1758 374.6543 360.4893 371.3408 360.4893 C
+234.6743 360.4893 L
+231.3608 360.4893 228.6743 363.1758 228.6743 366.4893 C
+228.6743 461.1563 L
+228.6743 464.4697 231.3608 467.1563 234.6743 467.1563 C
+371.3408 467.1563 L
+374.6543 467.1563 377.3408 464.4697 377.3408 461.1563 C
+377.3408 366.4893 L
+b
+0 0 0 0 k
+360.3711 382.1641 m
+360.3711 378.8506 357.6846 376.1641 354.3711 376.1641 C
+253.0381 376.1641 L
+249.7246 376.1641 247.0381 378.8506 247.0381 382.1641 C
+247.0381 444.1641 L
+247.0381 447.4775 249.7246 450.1641 253.0381 450.1641 C
+354.3711 450.1641 L
+357.6846 450.1641 360.3711 447.4775 360.3711 444.1641 C
+360.3711 382.1641 L
+b
+u
+0 Ap
+0 0 0 1 k
+1 w
+325.7354 369.5391 m
+322.2354 375.0391 318.2354 351.5391 342.2354 344.5391 c
+265.4619 344.5391 l
+289.4619 351.5391 285.4619 375.0391 281.9619 369.5391 c
+325.7354 369.5391 l
+b
+1 Ap
+1.0096 w
+342.9453 343.0273 m
+342.9453 342.1924 342.2539 341.5156 341.4043 341.5156 C
+266.0039 341.5156 L
+265.1523 341.5156 264.4639 342.1924 264.4639 343.0273 C
+264.4639 343.0273 L
+264.4639 343.8623 265.1523 344.5391 266.0039 344.5391 C
+341.4043 344.5391 L
+342.2539 344.5391 342.9453 343.8623 342.9453 343.0273 C
+342.9453 343.0273 L
+b
+U
+LB
+%AI5_EndLayer--
+%AI5_BeginLayer
+1 1 1 1 0 0 1 1 255 79 79 0 50 Lb
+(flames!) Ln
+0 A
+u
+0 Ap
+0 O
+0 0.51 1 0 (PANTONE 152 CVC) 0 x
+0 R
+0 0 0 1 K
+800 Ar
+0 J 0 j 3 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+268.1118 375.1055 m
+278.0723 371.9902 285.0166 362.1172 307.6953 356.7012 C
+328.5361 364.6758 339.9619 383.5098 345.8936 389.666 C
+343.8018 403.9888 340.0576 432.1499 332.6553 443.0522 C
+319.5771 453.9092 308.0566 485.27 318.7891 505.4521 C
+325.9775 515.9902 288.2168 468.6289 304.229 442.3589 C
+318.9365 416.1494 313.5049 417.688 311.5088 418.7856 C
+306.4565 424.1489 308.7578 428.8916 297.6426 440.9727 C
+282.4565 457.4297 280.1528 461.7734 296.6025 495.0522 C
+301.0166 499.0298 277.292 523.6685 275.7539 530.4106 C
+277.292 523.6685 293.3374 492.3101 277.8828 480.4922 C
+265.1763 462.8696 265.939 450.7354 264.7095 445.1323 C
+268.3765 438.5493 275.417 425.7495 278.5762 413.9326 C
+284.3765 406.5493 284.7471 391.6973 275.8027 404.2261 C
+273.8164 414.5488 252.376 431.5088 257.4292 460.0386 C
+269.9766 491.3496 240.8564 433.4292 244.603 410.4658 C
+256.2168 392.4688 270.3921 380.3086 268.1118 375.1055 C
+b
+0 1 0.91 0 (PANTONE 485 CVC) 0 x
+1 w
+263.0464 378.707 m
+271.0464 370.041 280.3799 358.707 303.0464 360.041 c
+325.7129 361.373 339.7129 382.041 341.7129 392.707 c
+343.7129 403.374 337.7129 432.708 327.0459 444.041 c
+316.3799 455.374 304.3794 488.041 313.7129 504.041 c
+323.0469 520.041 283.7129 470.707 299.7129 443.374 c
+315.7129 416.041 310.0547 417.644 306.7129 420.7075 c
+302.7129 424.374 305.1094 429.314 293.3799 442.041 c
+277.7129 459.041 275.3135 463.5659 292.3799 494.041 c
+297.0464 502.374 272.333 528.0396 y
+289.0469 495.3745 274.3799 480.041 v
+259.7129 464.7075 260.5073 452.0679 261.7129 446.041 c
+263.0464 439.374 270.3799 426.041 275.0464 416.041 c
+279.7129 406.041 280.0986 390.5684 272.3799 406.7075 c
+268.7129 414.374 246.3794 432.0405 254.7129 460.374 c
+264.7129 494.374 234.3799 434.041 242.3799 412.7075 c
+250.3799 391.373 263.0464 378.707 y
+b
+U
+LB
+%AI5_EndLayer--
+%AI5_BeginLayer
+1 1 0 1 0 0 1 2 79 255 79 0 50 Lb
+(text) Ln
+0 A
+1 To
+1 0 0 1 179.3335 327.2939 0 Tp
+0 Tv
+1 Ap
+800 Ar
+0 J 0 j 1 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+428.666 249.9619 m
+428.666 327.2939 L
+179.3335 327.2939 L
+179.3335 249.9619 L
+428.666 249.9619 L
+n
+TP
+14.3068 -43.125 Td
+2 Tr
+0 O
+0 0 0 1 k
+0 R
+0 1 0.91 0 (PANTONE 485 CVC) 0 X
+%_ 0 50 XQ
+/_Device 48 46.752 -7.1038 Tf
+0 Ts
+100 100 Tz
+0 Tt
+%_0 0 100 100 Xu
+%AI55J_GlyphSubst: GlyphSubstNone
+1 TA
+%_ 0 XL
+0 TY
+0 TV
+36 0 Xb
+XB
+0 0 5 TC
+100 100 200 TW
+25 TG
+0 0 0 Ti
+1 Ta
+0 1 2 2 3 Th
+0 Tq
+240 Tg
+0 0 Tl
+0 Tc
+0 Tw
+(XSCREENSA) Tx 1 91 Tk
+(VER) Tx 1 0 Tk
+(\r) TX
+TO
+LB
+%AI5_EndLayer--
+%%PageTrailer
+gsave annotatepage grestore showpage
+%%Trailer
+Adobe_Illustrator_AI5 /terminate get exec
+Adobe_shading_AI8 /terminate get exec
+Adobe_ColorImage_AI6 /terminate get exec
+Adobe_typography_AI5 /terminate get exec
+Adobe_cshow /terminate get exec
+Adobe_level2_AI5 /terminate get exec
+%%EOF
diff --git a/utils/images/screensaver-cmndln.png b/utils/images/screensaver-cmndln.png
new file mode 100644
index 0000000..fdb8e13
--- /dev/null
+++ b/utils/images/screensaver-cmndln.png
Binary files differ
diff --git a/utils/images/screensaver-colorselector.png b/utils/images/screensaver-colorselector.png
new file mode 100644
index 0000000..f18c86f
--- /dev/null
+++ b/utils/images/screensaver-colorselector.png
Binary files differ
diff --git a/utils/images/screensaver-diagnostic.png b/utils/images/screensaver-diagnostic.png
new file mode 100644
index 0000000..52de31a
--- /dev/null
+++ b/utils/images/screensaver-diagnostic.png
Binary files differ
diff --git a/utils/images/screensaver-locking.png b/utils/images/screensaver-locking.png
new file mode 100644
index 0000000..61ee436
--- /dev/null
+++ b/utils/images/screensaver-locking.png
Binary files differ
diff --git a/utils/images/screensaver-power.png b/utils/images/screensaver-power.png
new file mode 100644
index 0000000..38c861d
--- /dev/null
+++ b/utils/images/screensaver-power.png
Binary files differ
diff --git a/utils/images/screensaver-snap.png b/utils/images/screensaver-snap.png
new file mode 100644
index 0000000..720f51a
--- /dev/null
+++ b/utils/images/screensaver-snap.png
Binary files differ
diff --git a/utils/logo.c b/utils/logo.c
new file mode 100644
index 0000000..9e3078f
--- /dev/null
+++ b/utils/logo.c
@@ -0,0 +1,75 @@
+/* xscreensaver, Copyright (c) 2001-2006 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.
+ */
+
+/* XScreenSaver Logo designed by Angela Goodman <rzr_grl@yahoo.com>
+ */
+
+/* If you are looking in here because you're trying to figure out how to
+ change the logo that xscreensaver displays on the splash screen and
+ password dialog, please don't. The logo is xscreensaver's identity.
+ You wouldn't alter the name or copyright notice on a program that
+ you didn't write; please don't alter its logo either.
+ */
+
+#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"
+
+/* Returns a pixmap of the xscreensaver logo.
+ */
+Pixmap
+xscreensaver_logo (Screen *screen, Visual *visual,
+ Drawable drawable, Colormap cmap,
+ unsigned long background_color,
+ unsigned long **pixels_ret, int *npixels_ret,
+ Pixmap *mask_ret,
+ Bool big_p)
+{
+ Display *dpy = DisplayOfScreen (screen);
+ int depth = visual_depth (screen, visual);
+ int iw, ih;
+ XImage *image;
+ Pixmap p = 0;
+ unsigned char *mask = 0;
+
+ image = minixpm_to_ximage (dpy, visual, cmap, depth, background_color,
+ (big_p ? logo_180_xpm : logo_50_xpm),
+ &iw, &ih, pixels_ret, npixels_ret,
+ (mask_ret ? &mask : 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);
+
+ if (mask_ret && mask)
+ {
+ *mask_ret = (Pixmap)
+ XCreatePixmapFromBitmapData (dpy, drawable, (char *) mask,
+ iw, ih, 1L, 0L, 1);
+ free (mask);
+ }
+ }
+ return p;
+}
diff --git a/utils/minixpm.c b/utils/minixpm.c
new file mode 100644
index 0000000..997e628
--- /dev/null
+++ b/utils/minixpm.c
@@ -0,0 +1,251 @@
+/* xscreensaver, Copyright (c) 2001-2014 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.
+ */
+
+/* I implemented this subset of libXPM here because I don't want the
+ xscreensaver daemon to depend on libXPM for two reasons: first,
+ because I want the logo to show up even if libXPM is not installed
+ on the system; and second, I don't want to have to security-audit
+ libXPM. The fewer libraries that are linked into the xscreensaver
+ daemon, the more likely to be secure it is.
+
+ Also, the Cocoa port uses this code since libXPM isn't available
+ by default on MacOS.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_JWXYZ
+# include "jwxyz.h"
+#else /* real Xlib */
+# include <X11/Xlib.h>
+# include <X11/Xutil.h>
+#endif /* !HAVE_JWXYZ */
+
+#include "minixpm.h"
+
+extern const char *progname;
+
+static Bool
+bigendian (void)
+{
+ union { int i; char c[sizeof(int)]; } u;
+ u.i = 1;
+ return !u.c[0];
+}
+
+static const char hex[128] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,
+ 0, 10,11,12,13,14,15,0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 10,11,12,13,14,15,0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+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 long **pixels_ret, int *npixels_ret,
+ unsigned char **mask_ret)
+{
+ int w, w8, h, ncolors, nbytes;
+ char c;
+ int x, y, i, pixel_count;
+ struct {
+ char byte;
+ int cr; int cg; int cb;
+ int mr; int mg; int mb;
+ } cmap[256];
+ unsigned char rmap[256];
+
+ unsigned long *pixels;
+ XImage *ximage = 0;
+
+ memset (cmap, 0, sizeof(cmap)); /* avoid warnings */
+
+ if (4 != sscanf ((const char *) *data,
+ "%d %d %d %d %c", &w, &h, &ncolors, &nbytes, &c)) {
+ fprintf (stderr, "%s: unparsable XPM header\n", progname);
+ abort();
+ }
+
+ if (ncolors < 1 || ncolors > 255) {
+ fprintf (stderr, "%s: XPM: ncolors is %d\n", progname, ncolors);
+ abort();
+ }
+ if (nbytes != 1) {
+ fprintf (stderr, "%s: %d-byte XPM files not supported\n",
+ progname, nbytes);
+ abort();
+ }
+ data++;
+
+ for (i = 0; i < ncolors; i++)
+ {
+ const char *line = *data;
+ cmap[i].byte = *line++;
+ while (*line)
+ {
+ int r, g, b;
+ char which;
+ while (*line == ' ' || *line == '\t')
+ line++;
+ which = *line;
+ if (!which) continue; /* whitespace at end of line */
+ line++;
+ if (which != 'c' && which != 'm') {
+ fprintf (stderr, "%s: unknown XPM pixel type '%c' in \"%s\"\n",
+ progname, which, *data);
+ abort();
+ }
+ while (*line == ' ' || *line == '\t')
+ line++;
+ if (!strncasecmp(line, "None", 4))
+ {
+ r = g = b = -1;
+ line += 4;
+ }
+ else if (!strncasecmp(line, "white", 5))
+ {
+ r = g = b = 255;
+ line += 5;
+ }
+ else if (!strncasecmp(line, "black", 5))
+ {
+ r = g = b = 0;
+ line += 5;
+ }
+ else
+ {
+ if (*line != '#') {
+ fprintf (stderr, "%s: unparsable XPM color spec: \"%s\"\n",
+ progname, line);
+ abort();
+ }
+ if (*line == '#')
+ line++;
+ r = (hex[(int) line[0]] << 4) | hex[(int) line[1]]; line += 2;
+ g = (hex[(int) line[0]] << 4) | hex[(int) line[1]]; line += 2;
+ b = (hex[(int) line[0]] << 4) | hex[(int) line[1]]; line += 2;
+ }
+
+ if (which == 'c')
+ {
+ cmap[i].cr = r;
+ cmap[i].cg = g;
+ cmap[i].cb = b;
+ }
+ else
+ {
+ cmap[i].mr = r;
+ cmap[i].mg = g;
+ cmap[i].mb = b;
+ }
+ }
+
+ data++;
+ }
+
+ if (depth == 1) transparent_color = 1;
+
+ pixels = (unsigned long *) calloc (ncolors+1, sizeof(*pixels));
+ pixel_count = 0;
+ for (i = 0; i < ncolors; i++)
+ {
+ if (cmap[i].cr == -1) /* transparent */
+ {
+ rmap[(int) cmap[i].byte] = 255;
+ }
+ else
+ {
+ XColor color;
+ color.flags = DoRed|DoGreen|DoBlue;
+ color.red = (cmap[i].cr << 8) | cmap[i].cr;
+ color.green = (cmap[i].cg << 8) | cmap[i].cg;
+ color.blue = (cmap[i].cb << 8) | cmap[i].cb;
+ if (depth == 1 ||
+ !XAllocColor (dpy, colormap, &color))
+ {
+ color.red = (cmap[i].mr << 8) | cmap[i].mr;
+ color.green = (cmap[i].mg << 8) | cmap[i].mg;
+ color.blue = (cmap[i].mb << 8) | cmap[i].mb;
+ if (!XAllocColor (dpy, colormap, &color)) {
+ fprintf (stderr, "%s: unable to allocate XPM color\n",
+ progname);
+ abort();
+ }
+ }
+ pixels[pixel_count] = color.pixel;
+ rmap[(int) cmap[i].byte] = pixel_count;
+ pixel_count++;
+ }
+ }
+
+ ximage = XCreateImage (dpy, visual, depth,
+ (depth == 1 ? XYBitmap : ZPixmap),
+ 0, 0, w, h, 8, 0);
+ if (! ximage)
+ {
+ if (pixels) free (pixels);
+ return 0;
+ }
+
+ ximage->bitmap_bit_order =
+ ximage->byte_order =
+ (bigendian() ? MSBFirst : LSBFirst);
+
+ ximage->data = (char *) calloc (ximage->height, ximage->bytes_per_line);
+ if (!ximage->data)
+ {
+ XDestroyImage (ximage);
+ if (pixels) free (pixels);
+ return 0;
+ }
+
+ w8 = (w + 7) / 8;
+ if (mask_ret)
+ {
+ int s = (w8 * h) + 1;
+ *mask_ret = (unsigned char *) malloc (s);
+ if (!*mask_ret)
+ mask_ret = 0;
+ else
+ memset (*mask_ret, 255, s);
+ }
+
+ for (y = 0; y < h; y++)
+ {
+ const char *line = *data++;
+ for (x = 0; x < w; x++)
+ {
+ int p = rmap[(int) *line];
+ line++;
+ XPutPixel (ximage, x, y, (p == 255 ? transparent_color : pixels[p]));
+
+ if (p == 255 && mask_ret)
+ (*mask_ret)[(y * w8) + (x >> 3)] &= (~(1 << (x & 7)));
+ }
+ }
+
+ *width_ret = w;
+ *height_ret = h;
+ *pixels_ret = pixels;
+ *npixels_ret = pixel_count;
+ return ximage;
+}
diff --git a/utils/minixpm.h b/utils/minixpm.h
new file mode 100644
index 0000000..f027894
--- /dev/null
+++ b/utils/minixpm.h
@@ -0,0 +1,28 @@
+/* xscreensaver, Copyright (c) 2001-2006 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 __MINIXPM_H__
+#define __MINIXPM_H__
+
+
+/* A dead simple XPM parser that knows how to make XImage structures.
+ Only handles single-byte color XPMs.
+ */
+
+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 long **pixels_ret,
+ int *npixels_ret,
+ unsigned char **mask_ret);
+
+#endif /* __MINIXPM_H__ */
diff --git a/utils/overlay.c b/utils/overlay.c
new file mode 100644
index 0000000..0f42dcd
--- /dev/null
+++ b/utils/overlay.c
@@ -0,0 +1,158 @@
+/* xscreensaver, Copyright (c) 1997, 2001, 2004 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.
+ */
+
+/* If the server's root window contains a SERVER_OVERLAY_VISUALS property,
+ then that identifies the visuals which correspond to the video hardware's
+ overlay planes. Windows created in these kinds of visuals have the
+ property that one or more particular pixel values is transparent.
+
+ Vendor support:
+
+ SGI: - Supported on all systems since IRIX 4.0.
+ - Their version of the Motif toolkit renders menus into the overlay
+ visual, so that they don't cause exposure events on occluded
+ windows.
+ - 2 bit overlay plane with Indigo Entry graphics (e.g., Indy).
+ - 8 bit overlay on O2 with Indigo 24 graphics or better (e.g., O2).
+
+ HP: - Supported on workstations with CRX24 and CRX48Z graphics hardware.
+ - 8 bit or 24 bit overlay plane.
+ - The default visual is the overlay visual, with a transparent pixel.
+ That way, all Xlib programs draw into the overlay plane, and no
+ Xlib program causes exposures on occluded OpenGL windows.
+
+ IBM: - Supported on some graphics hardware (which?)
+
+ DEC: - Supported on some graphics hardware (which?)
+
+ SUN: - Some systems apparently implement it VERRRRRRY SLOWLY, so drawing
+ into the overlay plane is a performance killer (about as bad as
+ using the SHAPE extension.)
+
+
+ On my Indy, there are two transparent visuals, one of which is at layer 1,
+ and one of which is at layer 2. This is apparently the ordering in which
+ they are overlayed (1 being topmost.) The other difference between them
+ is that the topmost one only has 2 planes, while the next one has 8.
+
+ This code selects the topmost one, regardless of depth. Maybe that's not
+ the right thing. Well, in XScreenSaver, we only need to allocate two
+ colors from it (it's only used to display the stderr output, so that the
+ text can overlay the graphics without being obliterated by it.)
+
+ Documentation, such as it is, on SERVER_OVERLAY_VISUALS found on the web:
+
+ http://www.hp.com/xwindow/sharedInfo/Whitepapers/Visuals/server_overlay_visuals.html
+ http://www.xig.com/Pages/Ed-Overlays.html
+ */
+
+
+#include "utils.h"
+
+#include <X11/Xutil.h>
+#include <X11/Xproto.h>
+
+#include "visual.h"
+
+
+struct overlay_data
+{
+ CARD32 visual_id;
+ CARD32 transparency; /* 0: none; 1: pixel; 2: mask
+ ("mask" means "any pixel with these bits set
+ is a transparent pixel")
+ */
+ CARD32 value; /* the transparent pixel or mask */
+ CARD32 layer; /* -1: underlay; 0: normal; 1: popup; 2: overlay */
+};
+
+static int
+get_overlay_prop (Screen *screen, struct overlay_data **data_ret)
+{
+ int result;
+ Atom actual_type;
+ int actual_format;
+ unsigned long nitems, bytes_after;
+ unsigned char *data = 0;
+ Display *dpy = DisplayOfScreen(screen);
+ Window window = RootWindowOfScreen(screen);
+ Atom XA_SERVER_OVERLAY_VISUALS =
+ XInternAtom (dpy, "SERVER_OVERLAY_VISUALS", False);
+
+ *data_ret = 0;
+ result = XGetWindowProperty (dpy, window, XA_SERVER_OVERLAY_VISUALS,
+ 0, (65536 / sizeof (long)), False,
+ XA_SERVER_OVERLAY_VISUALS,
+ &actual_type, &actual_format,
+ &nitems, &bytes_after,
+ &data);
+ if (result != Success ||
+ actual_type != XA_SERVER_OVERLAY_VISUALS ||
+ actual_format != 32 ||
+ nitems < 1)
+ {
+ if (data) XFree(data);
+ return 0;
+ }
+ else
+ {
+ struct overlay_data *d = (struct overlay_data *) data;
+ *data_ret = d;
+ return nitems / (sizeof(*d) / sizeof(CARD32));
+ }
+}
+
+
+Visual *
+get_overlay_visual (Screen *screen, unsigned long *transparent_pixel_ret)
+{
+ struct overlay_data *data = 0;
+ int n_visuals = get_overlay_prop (screen, &data);
+ Visual *visual = 0;
+ int depth = 0;
+ unsigned long pixel = 0;
+ unsigned int layer = 0;
+ int i;
+
+ if (data)
+ for (i = 0; i < n_visuals; i++)
+
+ /* Only accept ones that have a transparent pixel or mask. */
+ if (data[i].transparency == 1 ||
+ data[i].transparency == 2)
+ {
+ XVisualInfo vi_in, *vi_out;
+ int out_count;
+ vi_in.visualid = data[i].visual_id;
+ vi_out = XGetVisualInfo (DisplayOfScreen(screen), VisualIDMask,
+ &vi_in, &out_count);
+ if (vi_out)
+ {
+ /* Prefer the one at the topmost layer; after that, prefer
+ the one with the greatest depth (most colors.) */
+ if (layer < data[i].layer ||
+ (layer == data[i].layer &&
+ depth < vi_out[0].depth))
+ {
+ visual = vi_out[0].visual;
+ depth = vi_out[0].depth;
+ layer = data[i].layer;
+ pixel = data[i].value;
+ }
+ XFree(vi_out);
+ }
+ }
+
+ if (data) XFree(data);
+ if (visual && transparent_pixel_ret)
+ *transparent_pixel_ret = pixel;
+ return visual;
+}
diff --git a/utils/pow2.c b/utils/pow2.c
new file mode 100644
index 0000000..9cce3d8
--- /dev/null
+++ b/utils/pow2.c
@@ -0,0 +1,51 @@
+/* pow2, Copyright (c) 2016 Dave Odell <dmo2118@gmail.com>
+ *
+ * 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.
+ */
+
+#include "pow2.h"
+
+#include <limits.h>
+
+int
+i_log2 (size_t x)
+{
+ /* -1 works best for to_pow2. */
+ if (!x)
+ return -1;
+
+ /* GCC 3.4 also has this. */
+# if defined __GNUC__ && __GNUC__ >= 4 || defined __clang__
+ return sizeof(long) * CHAR_BIT - __builtin_clzl(x) - 1;
+# else
+ {
+ unsigned bits = sizeof(x) * CHAR_BIT;
+ size_t mask = (size_t)-1;
+ unsigned result = bits - 1;
+
+ while (bits) {
+ if (!(x & mask)) {
+ result -= bits;
+ x <<= bits;
+ }
+
+ bits >>= 1;
+ mask <<= bits;
+ }
+
+ return result;
+ }
+# endif
+}
+
+size_t
+to_pow2 (size_t x)
+{
+ return !x ? 1 : 1 << (i_log2(x - 1) + 1);
+}
diff --git a/utils/pow2.h b/utils/pow2.h
new file mode 100644
index 0000000..3927e84
--- /dev/null
+++ b/utils/pow2.h
@@ -0,0 +1,20 @@
+/* pow2, Copyright (c) 2016 Dave Odell <dmo2118@gmail.com>
+ *
+ * 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 POW2_H
+#define POW2_H
+
+#include <stdlib.h>
+
+extern int i_log2(size_t x);
+extern size_t to_pow2 (size_t x); /* return the next larger power of 2. */
+
+#endif /* POW2_H */
diff --git a/utils/resources.c b/utils/resources.c
new file mode 100644
index 0000000..7b54adc
--- /dev/null
+++ b/utils/resources.c
@@ -0,0 +1,296 @@
+/* xscreensaver, Copyright (c) 1992-2014 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.
+ */
+
+#include "utils.h"
+#include "resources.h"
+
+extern char *progname;
+
+
+#if !defined(HAVE_COCOA) && !defined(HAVE_ANDROID)
+
+#include <X11/Xresource.h>
+
+/* These are the Xlib/Xrm versions of these functions.
+ The Cocoa versions are on OSX/XScreenSaverView.m.
+ */
+
+extern char *progclass;
+extern XrmDatabase XtDatabase (Display *);
+
+static unsigned int get_time_resource (Display *dpy,
+ char *res_name, char *res_class,
+ Bool sec_p);
+
+#ifndef isupper
+# define isupper(c) ((c) >= 'A' && (c) <= 'Z')
+#endif
+#ifndef _tolower
+# define _tolower(c) ((c) - 'A' + 'a')
+#endif
+
+char *
+get_string_resource (Display *dpy, char *res_name, char *res_class)
+{
+ XrmValue value;
+ char *type;
+ char full_name [1024], full_class [1024];
+ strcpy (full_name, progname);
+ strcat (full_name, ".");
+ strcat (full_name, res_name);
+ strcpy (full_class, progclass);
+ strcat (full_class, ".");
+ strcat (full_class, res_class);
+ if (XrmGetResource (XtDatabase (dpy), full_name, full_class, &type, &value))
+ {
+ char *str = (char *) malloc (value.size + 1);
+ strncpy (str, (char *) value.addr, value.size);
+ str [value.size] = 0;
+ return str;
+ }
+ return 0;
+}
+
+Bool
+get_boolean_resource (Display *dpy, char *res_name, char *res_class)
+{
+ char *tmp, buf [100];
+ char *s = get_string_resource (dpy, res_name, res_class);
+ char *os = s;
+ if (! s) return 0;
+ for (tmp = buf; *s; s++)
+ *tmp++ = isupper (*s) ? _tolower (*s) : *s;
+ *tmp = 0;
+ free (os);
+
+ while (*buf &&
+ (buf[strlen(buf)-1] == ' ' ||
+ buf[strlen(buf)-1] == '\t'))
+ buf[strlen(buf)-1] = 0;
+
+ if (!strcmp (buf, "on") || !strcmp (buf, "true") || !strcmp (buf, "yes"))
+ return 1;
+ if (!strcmp (buf,"off") || !strcmp (buf, "false") || !strcmp (buf,"no"))
+ return 0;
+ fprintf (stderr, "%s: %s must be boolean, not %s.\n",
+ progname, res_name, buf);
+ return 0;
+}
+
+int
+get_integer_resource (Display *dpy, char *res_name, char *res_class)
+{
+ int val;
+ char c, *s = get_string_resource (dpy, res_name, res_class);
+ char *ss = s;
+ if (!s) return 0;
+
+ while (*ss && *ss <= ' ') ss++; /* skip whitespace */
+
+ if (ss[0] == '0' && (ss[1] == 'x' || ss[1] == 'X')) /* 0x: parse as hex */
+ {
+ if (1 == sscanf (ss+2, "%x %c", (unsigned int *) &val, &c))
+ {
+ free (s);
+ return val;
+ }
+ }
+ else /* else parse as dec */
+ {
+ if (1 == sscanf (ss, "%d %c", &val, &c))
+ {
+ free (s);
+ return val;
+ }
+ }
+
+ fprintf (stderr, "%s: %s must be an integer, not %s.\n",
+ progname, res_name, s);
+ free (s);
+ return 0;
+}
+
+double
+get_float_resource (Display *dpy, char *res_name, char *res_class)
+{
+ double val;
+ char c, *s = get_string_resource (dpy, res_name, res_class);
+ if (! s) return 0.0;
+ if (1 == sscanf (s, " %lf %c", &val, &c))
+ {
+ free (s);
+ return val;
+ }
+ fprintf (stderr, "%s: %s must be a float, not %s.\n",
+ progname, res_name, s);
+ free (s);
+ return 0.0;
+}
+
+#endif /* !HAVE_COCOA && !HAVE_ANDROID */
+
+
+/* These functions are the same with Xlib, Cocoa and Android:
+ */
+
+
+unsigned int
+get_pixel_resource (Display *dpy, Colormap cmap,
+ char *res_name, char *res_class)
+{
+ XColor color;
+ char *s = get_string_resource (dpy, res_name, res_class);
+ char *s2;
+ Bool ok = True;
+ if (!s) goto DEFAULT;
+
+ for (s2 = s + strlen(s) - 1; s2 > s; s2--)
+ if (*s2 == ' ' || *s2 == '\t')
+ *s2 = 0;
+ else
+ break;
+
+ if (! XParseColor (dpy, cmap, s, &color))
+ {
+ fprintf (stderr, "%s: can't parse color %s", progname, s);
+ ok = False;
+ goto DEFAULT;
+ }
+ if (! XAllocColor (dpy, cmap, &color))
+ {
+ fprintf (stderr, "%s: couldn't allocate color %s", progname, s);
+ ok = False;
+ goto DEFAULT;
+ }
+ free (s);
+ return (unsigned int) color.pixel;
+ DEFAULT:
+ if (s) free (s);
+
+ {
+ Bool black_p = (strlen(res_class) >= 10 &&
+ !strcasecmp ("Background",
+ res_class + strlen(res_class) - 10));
+ if (!ok)
+ fprintf (stderr, ": using %s.\n", (black_p ? "black" : "white"));
+ color.flags = DoRed|DoGreen|DoBlue;
+ color.red = color.green = color.blue = (black_p ? 0 : 0xFFFF);
+ if (XAllocColor (dpy, cmap, &color))
+ return (unsigned int) color.pixel;
+ else
+ {
+ fprintf (stderr, "%s: couldn't allocate %s either!\n", progname,
+ (black_p ? "black" : "white"));
+ /* We can't use BlackPixel/WhitePixel here, because we don't know
+ what screen we're allocating on (only an issue when running inside
+ the xscreensaver daemon: for hacks, DefaultScreen is fine.)
+ */
+ return 0;
+ }
+ }
+}
+
+
+int
+parse_time (const char *string, Bool seconds_default_p, Bool silent_p)
+{
+ unsigned int h, m, s;
+ char c;
+ if (3 == sscanf (string, " %u : %2u : %2u %c", &h, &m, &s, &c))
+ ;
+ else if (2 == sscanf (string, " : %2u : %2u %c", &m, &s, &c) ||
+ 2 == sscanf (string, " %u : %2u %c", &m, &s, &c))
+ h = 0;
+ else if (1 == sscanf (string, " : %2u %c", &s, &c))
+ h = m = 0;
+ else if (1 == sscanf (string, " %u %c",
+ (seconds_default_p ? &s : &m), &c))
+ {
+ h = 0;
+ if (seconds_default_p) m = 0;
+ else s = 0;
+ }
+ else
+ {
+ if (! silent_p)
+ fprintf (stderr, "%s: invalid time interval specification \"%s\".\n",
+ progname, string);
+ return -1;
+ }
+ if (s >= 60 && (h != 0 || m != 0))
+ {
+ if (! silent_p)
+ fprintf (stderr, "%s: seconds > 59 in \"%s\".\n", progname, string);
+ return -1;
+ }
+ if (m >= 60 && h > 0)
+ {
+ if (! silent_p)
+ fprintf (stderr, "%s: minutes > 59 in \"%s\".\n", progname, string);
+ return -1;
+ }
+ return ((h * 60 * 60) + (m * 60) + s);
+}
+
+static unsigned int
+get_time_resource (Display *dpy, char *res_name, char *res_class, Bool sec_p)
+{
+ int val;
+ char *s = get_string_resource (dpy, res_name, res_class);
+ if (!s) return 0;
+ val = parse_time (s, sec_p, False);
+ free (s);
+ return (val < 0 ? 0 : val);
+}
+
+unsigned int
+get_seconds_resource (Display *dpy, char *res_name, char *res_class)
+{
+ return get_time_resource (dpy, res_name, res_class, True);
+}
+
+unsigned int
+get_minutes_resource (Display *dpy, char *res_name, char *res_class)
+{
+ return get_time_resource (dpy, res_name, res_class, False);
+}
+
+
+/* A utility function for event-handler functions:
+ Returns True if the event is a simple click, Space, Tab, etc.
+ Returns False otherwise.
+ The idea here is that most hacks interpret to clicks or basic
+ keypresses as "change it up".
+
+ This isn't really the right file for this, but whatever.
+ */
+Bool
+screenhack_event_helper (Display *dpy, Window window, XEvent *event)
+{
+ if (event->xany.type == KeyPress)
+ {
+ KeySym keysym;
+ char c = 0;
+ XLookupString (&event->xkey, &c, 1, &keysym, 0);
+ if (c == ' ' || c == '\t' || c == '\r' || c == '\n' ||
+ keysym == XK_Left || keysym == XK_Right ||
+ keysym == XK_Up || keysym == XK_Down ||
+ keysym == XK_Prior || keysym == XK_Next)
+ return True;
+ }
+ else if (event->xany.type == ButtonPress)
+ {
+ if (event->xbutton.button == 1)
+ return True;
+ }
+
+ return False;
+}
diff --git a/utils/resources.h b/utils/resources.h
new file mode 100644
index 0000000..cbfc8d1
--- /dev/null
+++ b/utils/resources.h
@@ -0,0 +1,41 @@
+/* xscreensaver, Copyright (c) 1992-2014 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 __XSCREENSAVER_RESOURCES_H__
+#define __XSCREENSAVER_RESOURCES_H__
+
+extern char *get_string_resource (Display*,char*,char*);
+extern Bool get_boolean_resource (Display*,char*,char*);
+extern int get_integer_resource (Display*,char*,char*);
+extern double get_float_resource (Display*,char*,char*);
+extern unsigned int get_pixel_resource (Display*,Colormap,char*,char*);
+extern unsigned int get_minutes_resource (Display*,char*,char*);
+extern unsigned int get_seconds_resource (Display*,char*,char*);
+extern int parse_time (const char *string, Bool seconds_default_p,
+ Bool silent_p);
+extern Pixmap
+xscreensaver_logo (Screen *screen, Visual *visual,
+ Drawable drawable, Colormap cmap,
+ unsigned long background_color,
+ unsigned long **pixels_ret, int *npixels_ret,
+ Pixmap *mask_ret,
+ Bool big_p);
+
+
+/* A utility function for event-handler functions:
+ Returns True if the event is a simple click, Space, Tab, etc.
+ Returns False otherwise.
+ The idea here is that most hacks interpret to clicks or basic
+ keypresses as "change it up".
+ */
+extern Bool screenhack_event_helper (Display *, Window, XEvent *);
+
+#endif /* __XSCREENSAVER_RESOURCES_H__ */
diff --git a/utils/spline.c b/utils/spline.c
new file mode 100644
index 0000000..1a73ea6
--- /dev/null
+++ b/utils/spline.c
@@ -0,0 +1,319 @@
+/*
+ * Copyright (c) 1987, 1988, 1989 Stanford University
+ *
+ * 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, and that the name of Stanford not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. Stanford makes no representations about
+ * the suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * STANFORD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+ * IN NO EVENT SHALL STANFORD 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.
+ */
+
+/* This code came with the InterViews distribution, and was translated
+ from C++ to C by Matthieu Devin <devin@lucid.com> some time in 1992.
+ */
+
+#include "utils.h"
+#include "spline.h"
+
+#define SMOOTHNESS 1.0
+
+static void grow_spline_points (spline* s);
+static void mid_point (double x0, double y0, double x1, double y1,
+ double *mx, double *my);
+static int can_approx_with_line (double x0, double y0, double x2,
+ double y2, double x3, double y3);
+static void add_line (spline* s, double x0, double y0, double x1, double y1);
+static void add_bezier_arc (spline* s,
+ double x0, double y0, double x1, double y1,
+ double x2, double y2, double x3, double y3);
+static void third_point (double x0, double y0, double x1, double y1,
+ double *tx, double *ty);
+static void calc_section (spline* s, double cminus1x, double cminus1y,
+ double cx, double cy, double cplus1x, double cplus1y,
+ double cplus2x, double cplus2y);
+
+spline*
+make_spline (unsigned int size)
+{
+ spline* s = (spline*)calloc (1, sizeof (spline));
+ if (!s) abort();
+ s->n_controls = size;
+ s->control_x = (double*)calloc (s->n_controls, sizeof (double));
+ s->control_y = (double*)calloc (s->n_controls, sizeof (double));
+
+ s->n_points = 0;
+ s->allocated_points = s->n_controls;
+ s->points = (XPoint*)calloc (s->allocated_points, sizeof (XPoint));
+
+ if (!s->control_x || !s->control_y || !s->points)
+ abort();
+
+ return s;
+}
+
+static void
+grow_spline_points (spline *s)
+{
+ s->allocated_points = 10 + (s->allocated_points * 1.3);
+ s->points =
+ (XPoint*)realloc (s->points, s->allocated_points * sizeof (XPoint));
+ if (!s->points) abort();
+}
+
+static void
+mid_point (double x0, double y0,
+ double x1, double y1,
+ double *mx, double *my)
+{
+ *mx = (x0 + x1) / 2.0;
+ *my = (y0 + y1) / 2.0;
+}
+
+static void
+third_point (double x0, double y0,
+ double x1, double y1,
+ double *tx, double *ty)
+{
+ *tx = (2 * x0 + x1) / 3.0;
+ *ty = (2 * y0 + y1) / 3.0;
+}
+
+static int
+can_approx_with_line (double x0, double y0,
+ double x2, double y2,
+ double x3, double y3)
+{
+ double triangle_area, side_squared, dx, dy;
+
+ triangle_area = x0 * y2 - x2 * y0 + x2 * y3 - x3 * y2 + x3 * y0 - x0 * y3;
+ /* actually 4 times the area. */
+ triangle_area *= triangle_area;
+ dx = x3 - x0;
+ dy = y3 - y0;
+ side_squared = dx * dx + dy * dy;
+ return triangle_area <= SMOOTHNESS * side_squared;
+}
+
+static void
+add_line (spline *s,
+ double x0, double y0,
+ double x1, double y1)
+{
+ if (s->n_points >= s->allocated_points)
+ grow_spline_points (s);
+
+ if (s->n_points == 0)
+ {
+ s->points [s->n_points].x = x0;
+ s->points [s->n_points].y = y0;
+ s->n_points += 1;
+ }
+ s->points [s->n_points].x = x1;
+ s->points [s->n_points].y = y1;
+ s->n_points += 1;
+}
+
+static void
+add_bezier_arc (spline *s,
+ double x0, double y0,
+ double x1, double y1,
+ double x2, double y2,
+ double x3, double y3)
+{
+ double midx01, midx12, midx23, midlsegx, midrsegx, cx,
+ midy01, midy12, midy23, midlsegy, midrsegy, cy;
+
+ mid_point (x0, y0, x1, y1, &midx01, &midy01);
+ mid_point (x1, y1, x2, y2, &midx12, &midy12);
+ mid_point (x2, y2, x3, y3, &midx23, &midy23);
+ mid_point (midx01, midy01, midx12, midy12, &midlsegx, &midlsegy);
+ mid_point (midx12, midy12, midx23, midy23, &midrsegx, &midrsegy);
+ mid_point (midlsegx, midlsegy, midrsegx, midrsegy, &cx, &cy);
+
+ if (can_approx_with_line (x0, y0, midlsegx, midlsegy, cx, cy))
+ add_line (s, x0, y0, cx, cy);
+ else if ((midx01 != x1) || (midy01 != y1) || (midlsegx != x2)
+ || (midlsegy != y2) || (cx != x3) || (cy != y3))
+ add_bezier_arc (s, x0, y0, midx01, midy01, midlsegx, midlsegy, cx, cy);
+
+ if (can_approx_with_line (cx, cy, midx23, midy23, x3, y3))
+ add_line (s, cx, cy, x3, y3);
+ else if ((cx != x0) || (cy != y0) || (midrsegx != x1) || (midrsegy != y1)
+ || (midx23 != x2) || (midy23 != y2))
+ add_bezier_arc (s, cx, cy, midrsegx, midrsegy, midx23, midy23, x3, y3);
+}
+
+static void
+calc_section (spline *s,
+ double cminus1x, double cminus1y,
+ double cx, double cy,
+ double cplus1x, double cplus1y,
+ double cplus2x, double cplus2y)
+{
+ double p0x, p1x, p2x, p3x, tempx,
+ p0y, p1y, p2y, p3y, tempy;
+
+ third_point (cx, cy, cplus1x, cplus1y, &p1x, &p1y);
+ third_point (cplus1x, cplus1y, cx, cy, &p2x, &p2y);
+ third_point (cx, cy, cminus1x, cminus1y, &tempx, &tempy);
+ mid_point (tempx, tempy, p1x, p1y, &p0x, &p0y);
+ third_point (cplus1x, cplus1y, cplus2x, cplus2y, &tempx, &tempy);
+ mid_point (tempx, tempy, p2x, p2y, &p3x, &p3y);
+ add_bezier_arc (s, p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y);
+}
+
+void
+compute_spline (spline *s)
+{
+ int i;
+ s->n_points = 0;
+
+ if (s->n_controls < 3)
+ return;
+
+ calc_section (s, s->control_x [0], s->control_y [0], s->control_x [0],
+ s->control_y [0], s->control_x [0], s->control_y [0],
+ s->control_x [1], s->control_y [1]);
+ calc_section (s, s->control_x [0], s->control_y [0], s->control_x [0],
+ s->control_y [0], s->control_x [1], s->control_y [1],
+ s->control_x [2], s->control_y [2]);
+
+ for (i = 1; i < s->n_controls - 2; i++)
+ calc_section (s, s->control_x [i - 1], s->control_y [i - 1],
+ s->control_x [i], s->control_y [i],
+ s->control_x [i + 1], s->control_y [i + 1],
+ s->control_x [i + 2], s->control_y [i + 2]);
+
+ calc_section (s, s->control_x [i - 1], s->control_y [i - 1],
+ s->control_x [i], s->control_y [i],
+ s->control_x [i + 1], s->control_y [i + 1],
+ s->control_x [i + 1], s->control_y [i + 1]);
+ calc_section (s, s->control_x [i], s->control_y [i],
+ s->control_x [i + 1], s->control_y [i + 1],
+ s->control_x [i + 1], s->control_y [i + 1],
+ s->control_x [i + 1], s->control_y [i + 1]);
+}
+
+void
+compute_closed_spline (spline *s)
+{
+ int i;
+ s->n_points = 0;
+
+ if (s->n_controls < 3)
+ return;
+
+ calc_section (s,
+ s->control_x [s->n_controls - 1],
+ s->control_y [s->n_controls - 1],
+ s->control_x [0], s->control_y [0],
+ s->control_x [1], s->control_y [1],
+ s->control_x [2], s->control_y [2]);
+
+ for (i = 1; i < s->n_controls - 2; i++)
+ calc_section (s, s->control_x [i - 1], s->control_y [i - 1],
+ s->control_x [i], s->control_y [i],
+ s->control_x [i + 1], s->control_y [i + 1],
+ s->control_x [i + 2], s->control_y [i + 2]);
+
+ calc_section (s, s->control_x [i - 1], s->control_y [i - 1],
+ s->control_x [i], s->control_y [i],
+ s->control_x [i + 1], s->control_y [i + 1],
+ s->control_x [0], s->control_y [0]);
+ calc_section (s, s->control_x [i], s->control_y [i],
+ s->control_x [i + 1], s->control_y [i + 1],
+ s->control_x [0], s->control_y [0],
+ s->control_x [1], s->control_y [1]);
+}
+
+void
+just_fill_spline (spline *s)
+{
+ int i;
+
+ while (s->allocated_points < s->n_controls + 1)
+ grow_spline_points (s);
+
+ for (i = 0; i < s->n_controls; i++)
+ {
+ s->points [i].x = s->control_x [i];
+ s->points [i].y = s->control_y [i];
+ }
+ s->points [s->n_controls].x = s->control_x [0];
+ s->points [s->n_controls].y = s->control_y [0];
+ s->n_points = s->n_controls + 1;
+}
+
+void
+append_spline_points (spline *s1, spline *s2)
+{
+ int i;
+ while (s1->allocated_points < s1->n_points + s2->n_points)
+ grow_spline_points (s1);
+ for (i = s1->n_points; i < s1->n_points + s2->n_points; i++)
+ {
+ s1->points [i].x = s2->points [i - s1->n_points].x;
+ s1->points [i].y = s2->points [i - s1->n_points].y;
+ }
+ s1->n_points = s1->n_points + s2->n_points;
+}
+
+void
+spline_bounding_box (spline *s, XRectangle *rectangle_out)
+{
+ int min_x;
+ int max_x;
+ int min_y;
+ int max_y;
+ int i;
+
+ if (s->n_points == 0)
+ {
+ rectangle_out->x = 0;
+ rectangle_out->y = 0;
+ rectangle_out->width = 0;
+ rectangle_out->height = 0;
+ }
+
+ min_x = s->points [0].x;
+ max_x = min_x;
+ min_y = s->points [0].y;
+ max_y = min_y;
+
+ for (i = 1; i < s->n_points; i++)
+ {
+ if (s->points [i].x < min_x)
+ min_x = s->points [i].x;
+ if (s->points [i].x > max_x)
+ max_x = s->points [i].x;
+ if (s->points [i].y < min_y)
+ min_y = s->points [i].y;
+ if (s->points [i].y > max_y)
+ max_y = s->points [i].y;
+ }
+ rectangle_out->x = min_x;
+ rectangle_out->y = min_y;
+ rectangle_out->width = max_x - min_x;
+ rectangle_out->height = max_y - min_y;
+}
+
+void
+free_spline(spline * s)
+{
+ free ((void *) s->control_x);
+ free ((void *) s->control_y);
+ free ((void *) s->points);
+ free ((void *) s);
+}
diff --git a/utils/spline.h b/utils/spline.h
new file mode 100644
index 0000000..a5a366c
--- /dev/null
+++ b/utils/spline.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 1987, 1988, 1989 Stanford University
+ *
+ * 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, and that the name of Stanford not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. Stanford makes no representations about
+ * the suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * STANFORD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+ * IN NO EVENT SHALL STANFORD 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.
+ */
+
+/* This code came with the InterViews distribution, and was translated
+ from C++ to C by Matthieu Devin <devin@lucid.com> some time in 1992.
+ */
+
+#ifndef _SPLINE_H_
+#define _SPLINE_H_
+
+typedef struct _spline
+{
+ /* input */
+ unsigned int n_controls;
+ double* control_x;
+ double* control_y;
+
+ /* output */
+ unsigned int n_points;
+ XPoint* points;
+ unsigned int allocated_points;
+} spline;
+
+spline* make_spline (unsigned int size);
+void compute_spline (spline* s);
+void compute_closed_spline (spline* s);
+void just_fill_spline (spline* s);
+void append_spline_points (spline* s1, spline* s2);
+void spline_bounding_box (spline* s, XRectangle* rectangle_out);
+void free_spline(spline *s);
+
+#endif /* _SPLINE_H_ */
diff --git a/utils/textclient-mobile.c b/utils/textclient-mobile.c
new file mode 100644
index 0000000..c321487
--- /dev/null
+++ b/utils/textclient-mobile.c
@@ -0,0 +1,813 @@
+/* xscreensaver, Copyright (c) 2012-2016 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.
+ *
+ * Loading URLs and returning the underlying text.
+ *
+ * This is necessary because iOS and Android don't have Perl installed,
+ * so we can't just run "xscreensaver-text" at the end of a pipe to do this.
+ */
+
+#include "utils.h"
+
+#if defined(USE_IPHONE) || defined(HAVE_ANDROID) /* whole file */
+
+#include "textclient.h"
+#include "resources.h"
+#include "utf8wc.h"
+
+#include <stdio.h>
+
+#undef countof
+#define countof(x) (sizeof((x))/sizeof((*x)))
+
+
+extern const char *progname;
+
+struct text_data {
+
+ enum { DATE, LITERAL, URL } mode;
+ char *literal, *url;
+
+ Display *dpy;
+ int columns;
+ int max_lines;
+ char *buf;
+ int buf_size;
+ char *fp;
+
+};
+
+
+text_data *
+textclient_open (Display *dpy)
+{
+ text_data *d = (text_data *) calloc (1, sizeof (*d));
+
+# ifdef DEBUG
+ fprintf (stderr, "%s: textclient: init\n", progname);
+# endif
+
+ char *s = get_string_resource (dpy, "textMode", "TextMode");
+ if (!s || !*s || !strcasecmp (s, "date") || !strcmp (s, "0"))
+ d->mode = DATE;
+ else if (!strcasecmp (s, "literal") || !strcmp (s, "1"))
+ d->mode = LITERAL;
+ else if (!strcasecmp (s, "url") || !strcmp (s, "3"))
+ d->mode = URL;
+ else
+ d->mode = DATE;
+
+ d->dpy = dpy;
+ d->literal = get_string_resource (dpy, "textLiteral", "TextLiteral");
+ d->url = get_string_resource (dpy, "textURL", "TextURL");
+
+ return d;
+}
+
+
+void
+textclient_close (text_data *d)
+{
+# ifdef DEBUG
+ fprintf (stderr, "%s: textclient: free\n", progname);
+# endif
+
+ if (d->buf) free (d->buf);
+ if (d->literal) free (d->literal);
+ if (d->url) free (d->url);
+ free (d);
+}
+
+
+/* Returns a copy of the string with some basic HTML entities decoded.
+ */
+static char *
+decode_entities (const char *html)
+{
+ char *ret = (char *) malloc ((strlen(html) * 4) + 1); // room for UTF8
+ const char *in = html;
+ char *out = ret;
+ *out = 0;
+
+ const struct { const char *c; const char *e; } entities[] = {
+
+ { "amp", "&" },
+ { "lt", "<" },
+ { "gt", ">" },
+
+ // Convert Latin1 to UTF8
+ { "nbsp", " " }, //   160
+ { "iexcl", "\302\241" }, // ¡ 161
+ { "cent", "\302\242" }, // ¢ 162
+ { "pound", "\302\243" }, // £ 163
+ { "curren", "\302\244" }, // ¤ 164
+ { "yen", "\302\245" }, // ¥ 165
+ { "brvbar", "\302\246" }, // ¦ 166
+ { "sect", "\302\247" }, // § 167
+ { "uml", "\302\250" }, // ¨ 168
+ { "copy", "\302\251" }, // © 169
+ { "ordf", "\302\252" }, // ª 170
+ { "laquo", "\302\253" }, // « 171
+ { "not", "\302\254" }, // ¬ 172
+ { "shy", "\302\255" }, // ­ 173
+ { "reg", "\302\256" }, // ® 174
+ { "macr", "\302\257" }, // ¯ 175
+ { "deg", "\302\260" }, // ° 176
+ { "plusmn", "\302\261" }, // ± 177
+ { "sup2", "\302\262" }, // ² 178
+ { "sup3", "\302\263" }, // ³ 179
+ { "acute", "\302\264" }, // ´ 180
+ { "micro", "\302\265" }, // µ 181
+ { "para", "\302\266" }, // ¶ 182
+ { "middot", "\302\267" }, // · 183
+ { "cedil", "\302\270" }, // ¸ 184
+ { "sup1", "\302\271" }, // ¹ 185
+ { "ordm", "\302\272" }, // º 186
+ { "raquo", "\302\273" }, // » 187
+ { "frac14", "\302\274" }, // ¼ 188
+ { "frac12", "\302\275" }, // ½ 189
+ { "frac34", "\302\276" }, // ¾ 190
+ { "iquest", "\302\277" }, // ¿ 191
+ { "Agrave", "\303\200" }, // À 192
+ { "Aacute", "\303\201" }, // Á 193
+ { "Acirc", "\303\202" }, // Â 194
+ { "Atilde", "\303\203" }, // Ã 195
+ { "Auml", "\303\204" }, // Ä 196
+ { "Aring", "\303\205" }, // Å 197
+ { "AElig", "\303\206" }, // Æ 198
+ { "Ccedil", "\303\207" }, // Ç 199
+ { "Egrave", "\303\210" }, // È 200
+ { "Eacute", "\303\211" }, // É 201
+ { "Ecirc", "\303\212" }, // Ê 202
+ { "Euml", "\303\213" }, // Ë 203
+ { "Igrave", "\303\214" }, // Ì 204
+ { "Iacute", "\303\215" }, // Í 205
+ { "Icirc", "\303\216" }, // Î 206
+ { "Iuml", "\303\217" }, // Ï 207
+ { "ETH", "\303\220" }, // Ð 208
+ { "Ntilde", "\303\221" }, // Ñ 209
+ { "Ograve", "\303\222" }, // Ò 210
+ { "Oacute", "\303\223" }, // Ó 211
+ { "Ocirc", "\303\224" }, // Ô 212
+ { "Otilde", "\303\225" }, // Õ 213
+ { "Ouml", "\303\226" }, // Ö 214
+ { "times", "\303\227" }, // × 215
+ { "Oslash", "\303\230" }, // Ø 216
+ { "Ugrave", "\303\231" }, // Ù 217
+ { "Uacute", "\303\232" }, // Ú 218
+ { "Ucirc", "\303\233" }, // Û 219
+ { "Uuml", "\303\234" }, // Ü 220
+ { "Yacute", "\303\235" }, // Ý 221
+ { "THORN", "\303\236" }, // Þ 222
+ { "szlig", "\303\237" }, // ß 223
+ { "agrave", "\303\240" }, // à 224
+ { "aacute", "\303\241" }, // á 225
+ { "acirc", "\303\242" }, // â 226
+ { "atilde", "\303\243" }, // ã 227
+ { "auml", "\303\244" }, // ä 228
+ { "aring", "\303\245" }, // å 229
+ { "aelig", "\303\246" }, // æ 230
+ { "ccedil", "\303\247" }, // ç 231
+ { "egrave", "\303\250" }, // è 232
+ { "eacute", "\303\251" }, // é 233
+ { "ecirc", "\303\252" }, // ê 234
+ { "euml", "\303\253" }, // ë 235
+ { "igrave", "\303\254" }, // ì 236
+ { "iacute", "\303\255" }, // í 237
+ { "icirc", "\303\256" }, // î 238
+ { "iuml", "\303\257" }, // ï 239
+ { "eth", "\303\260" }, // ð 240
+ { "ntilde", "\303\261" }, // ñ 241
+ { "ograve", "\303\262" }, // ò 242
+ { "oacute", "\303\263" }, // ó 243
+ { "ocirc", "\303\264" }, // ô 244
+ { "otilde", "\303\265" }, // õ 245
+ { "ouml", "\303\266" }, // ö 246
+ { "divide", "\303\267" }, // ÷ 247
+ { "oslash", "\303\270" }, // ø 248
+ { "ugrave", "\303\271" }, // ù 249
+ { "uacute", "\303\272" }, // ú 250
+ { "ucirc", "\303\273" }, // û 251
+ { "uuml", "\303\274" }, // ü 252
+ { "yacute", "\303\275" }, // ý 253
+ { "thorn", "\303\276" }, // þ 254
+ { "yuml", "\303\277" }, // ÿ 255
+
+ // And some random others
+ { "bdquo", "\342\200\236" }, // ~
+ { "bull", "\342\200\242" }, // ~
+ { "circ", "\313\206" }, // ~
+ { "cong", "\342\211\205" }, // ~
+ { "empty", "\342\210\205" }, // ~
+ { "emsp", "\342\200\203" }, // ~
+ { "ensp", "\342\200\202" }, // ~
+ { "equiv", "\342\211\241" }, // ~
+ { "frasl", "\342\201\204" }, // ~
+ { "ge", "\342\211\245" }, // ~
+ { "hArr", "\342\207\224" }, // ~
+ { "harr", "\342\206\224" }, // ~
+ { "hellip", "\342\200\246" }, // ~
+ { "lArr", "\342\207\220" }, // ~
+ { "lang", "\342\237\250" }, // ~
+ { "larr", "\342\206\220" }, // ~
+ { "ldquo", "\342\200\234" }, // ~
+ { "le", "\342\211\244" }, // ~
+ { "lowast", "\342\210\227" }, // ~
+ { "loz", "\342\227\212" }, // ~
+ { "lsaquo", "\342\200\271" }, // ~
+ { "lsquo", "\342\200\230" }, // ~
+ { "mdash", "\342\200\224" }, // ~
+ { "minus", "\342\210\222" }, // ~
+ { "ndash", "\342\200\223" }, // ~
+ { "ne", "\342\211\240" }, // ~
+ { "OElig", "\305\222" }, // ~
+ { "oelig", "\305\223" }, // ~
+ { "prime", "\342\200\262" }, // ~
+ { "quot", "\342\200\235" }, // ~
+ { "rArr", "\342\207\222" }, // ~
+ { "rang", "\342\237\251" }, // ~
+ { "rarr", "\342\206\222" }, // ~
+ { "rdquo", "\342\200\235" }, // ~
+ { "rsaquo", "\342\200\272" }, // ~
+ { "rsquo", "\342\200\231" }, // ~
+ { "sbquo", "\342\200\232" }, // ~
+ { "sim", "\342\210\274" }, // ~
+ { "thinsp", "\342\200\211" }, // ~
+ { "tilde", "\313\234" }, // ~
+ { "trade", "\342\204\242" }, // ~
+ };
+
+ while (*in) {
+ if (*in == '&') {
+ int done = 0;
+ if (in[1] == '#' && in[2] == 'x') { // &#x41;
+ unsigned long i = 0;
+ in += 2;
+ while ((*in >= '0' && *in <= '9') ||
+ (*in >= 'A' && *in <= 'F') ||
+ (*in >= 'a' && *in <= 'f')) {
+ i = (i * 16) + (*in >= 'a' ? *in - 'a' + 16 :
+ *in >= 'A' ? *in - 'A' + 16 :
+ *in - '0');
+ in++;
+ }
+ *out += utf8_encode (i, out, strlen(out));
+ done = 1;
+ } else if (in[1] == '#') { // &#65;
+ unsigned long i = 0;
+ in++;
+ while (*in >= '0' && *in <= '9') {
+ i = (i * 10) + (*in - '0');
+ in++;
+ }
+ *out += utf8_encode (i, out, strlen(out));
+ done = 1;
+ } else {
+ int i;
+ for (i = 0; !done && i < countof(entities); i++) {
+ if (!strncmp (in+1, entities[i].c, strlen(entities[i].c))) {
+ strcpy (out, entities[i].e);
+ in += strlen(entities[i].c) + 1;
+ out += strlen(entities[i].e);
+ done = 1;
+ }
+ }
+ }
+
+ if (done) {
+ if (*in == ';')
+ in++;
+ } else {
+ *out++ = *in++;
+ }
+ } else {
+ *out++ = *in++;
+ }
+ }
+ *out = 0;
+
+ /* Shrink */
+ ret = realloc (ret, out - ret + 1);
+
+ return ret;
+}
+
+
+/* Returns a copy of the HTML string that has been converted to plain text,
+ in UTF8 encoding. HTML tags are stripped, <BR> and <P> are converted
+ to newlines, and some basic HTML entities are decoded.
+ */
+static char *
+textclient_strip_html (const char *html)
+{
+ int tag = 0;
+ int comment = 0;
+ int white = 0;
+ int nl = 0;
+ char *ret = (char *) malloc ((strlen(html) * 4) + 1); // room for UTF8
+ char *out = ret;
+ *out = 0;
+
+ for (const char *in = html; *in; in++) {
+ if (comment) {
+ if (!strncmp (in, "-->", 3)) {
+ comment = 0;
+ }
+ } else if (tag) {
+ if (*in == '>') {
+ tag = 0;
+ }
+ } else if (*in == '<') {
+ tag = 1;
+ if (!strncmp (in, "<!--", 4)) {
+ comment = 1;
+ tag = 0;
+ } else if (!strncasecmp (in, "<BR", 3)) {
+ *out++ = '\n';
+ white = 1;
+ nl++;
+ } else if (!strncasecmp (in, "<P", 2)) {
+ if (nl < 2) { *out++ = '\n'; nl++; }
+ if (nl < 2) { *out++ = '\n'; nl++; }
+ white = 1;
+ }
+ } else if (*in == ' ' || *in == '\t' || *in == '\r' || *in == '\n') {
+ if (!white && out != html)
+ *out++ = ' ';
+ white = 1;
+ } else {
+ *out++ = *in;
+ white = 0;
+ nl = 0;
+ }
+ }
+ *out = 0;
+
+ {
+ char *ret2 = decode_entities (ret);
+ free (ret);
+ ret = ret2;
+ }
+
+ return ret;
+}
+
+
+static char *
+copy_rss_field (const char *s)
+{
+ if (!s) return 0;
+ while (*s && *s != '>') // Skip forward to >
+ s++;
+ if (! *s) return 0;
+ s++;
+
+ if (!strncmp (s, "<![CDATA[", 9)) { // CDATA quoting
+ s += 9;
+ char *e = strstr (s, "]]");
+ if (e) *e = 0;
+ unsigned long L = strlen (s);
+ char *s2 = (char *) malloc (L+1);
+ memcpy (s2, s, L+1);
+ return s2;
+
+ } else { // Entity-encoded.
+ const char *s2;
+ for (s2 = s; *s2 && *s2 != '<'; s2++) // Terminate at <
+ ;
+ char *s3 = (char *) malloc (s2 - s + 1);
+ if (! s3) return 0;
+ memcpy (s3, s, s2-s);
+ s3[s2-s] = 0;
+ char *s4 = textclient_strip_html (s3);
+ free (s3);
+ return s4;
+ }
+}
+
+
+static char *
+pick_rss_field (const char *a, const char *b, const char *c, const char *d)
+{
+ // Pick the longest of the fields.
+ char *a2 = copy_rss_field (a);
+ char *b2 = copy_rss_field (b);
+ char *c2 = copy_rss_field (c);
+ char *d2 = copy_rss_field (d);
+ unsigned long al = a2 ? strlen(a2) : 0;
+ unsigned long bl = b2 ? strlen(b2) : 0;
+ unsigned long cl = c2 ? strlen(c2) : 0;
+ unsigned long dl = d2 ? strlen(d2) : 0;
+ char *ret = 0;
+
+ if (al > bl && al > cl && al > dl) ret = a2;
+ else if (bl > al && bl > cl && bl > dl) ret = b2;
+ else if (cl > al && cl > bl && cl > dl) ret = c2;
+ else ret = d2;
+ if (a2 && a2 != ret) free (a2);
+ if (b2 && b2 != ret) free (b2);
+ if (c2 && c2 != ret) free (c2);
+ if (d2 && d2 != ret) free (d2);
+ return ret;
+}
+
+
+/* Strip some Wikipedia formatting from the string to make it more readable.
+ */
+static void
+strip_wiki (char *text)
+{
+ char *in = text;
+ char *out = text;
+ while (*in)
+ {
+ if (!strncmp (in, "<!--", 4)) /* <!-- ... --> */
+ {
+ char *e = strstr (in+4, "-->");
+ if (e) in = e + 3;
+ }
+ else if (!strncmp (in, "/*", 2)) /* ... */
+ {
+ char *e = strstr (in+2, "*/");
+ if (e) in = e + 2;
+ else *out++ = *in++;
+ }
+ else if (!strncmp (in, "{{Infobox", 9)) /* {{Infobox ... \n}}\n */
+ {
+ char *e = strstr (in+2, "\n}}");
+ if (e) in = e + 3;
+ else *out++ = *in++;
+ }
+ else if (!strncmp (in, "{{", 2)) /* {{ ...table... }} */
+ {
+ char *e = strstr (in+2, "}}");
+ if (e) in = e + 2;
+ else *out++ = *in++;
+ }
+ else if (!strncmp (in, "{|", 2)) /* {| ...table... |} */
+ {
+ char *e = strstr (in+2, "|}");
+ if (e) in = e + 2;
+ else *out++ = *in++;
+ }
+ else if (!strncmp (in, "|-", 2)) /* |- ...table cell... | */
+ {
+ char *e = strstr (in+2, "|");
+ if (e) in = e + 1;
+ else *out++ = *in++;
+ }
+ else if (!strncmp (in, "<ref", 4)) /* <ref>...</ref> -> "*" */
+ {
+ char *e1 = strstr (in+4, "/>");
+ char *e2 = strstr (in+4, "</ref>");
+ if (e1 && e1 < e2) in = e1 + 2;
+ else if (e2) in = e2 + 6;
+ else *out++ = *in++;
+
+ *out++ = '*';
+ }
+ else if (!strncmp (in, "<", 1)) /* <...> */
+ {
+ char *e = strstr (in+1, ">");
+ if (e) in = e + 1;
+ else *out++ = *in++;
+ }
+ else if (!strncmp (in, "[[", 2)) /* [[ ... ]] */
+ {
+ char *e1 = strstr (in+2, "|");
+ char *e2 = strstr (in+2, "]]");
+ if (e1 && e2 && e1 < e2) /* [[link|anchor]] */
+ {
+ long L = e2 - e1 - 1;
+ memmove (out, e1+1, L);
+ out += L;
+ in = e2+2;
+ }
+ else if (e2) /* [[link]] */
+ {
+ long L = e2 - in - 2;
+ memmove (out, in+2, L);
+ out += L;
+ in = e2+2;
+ }
+ else
+ *out++ = *in++;
+ }
+ else if (!strncmp (in, "[", 1)) /* [ ... ] */
+ {
+ char *e1 = strstr (in+2, " ");
+ char *e2 = strstr (in+2, "]");
+ if (e1 && e2 && e1 < e2) /* [url anchor] */
+ {
+ long L = e2 - e1 - 1;
+ memmove (out, e1+1, L);
+ out += L;
+ in = e2+2;
+ }
+ else
+ *out++ = *in++;
+ }
+ else if (!strncmp (in, "''''", 4)) /* omit '''' */
+ in += 4;
+ else if (!strncmp (in, "'''", 3)) /* omit ''' */
+ in += 3;
+ else if (!strncmp (in, "''", 2) || /* '' or `` or "" -> " */
+ !strncmp (in, "``", 2) ||
+ !strncmp (in, "\"\"", 2))
+ {
+ *out++ = '"';
+ in += 2;
+ }
+ else
+ {
+ *out++ = *in++;
+ }
+ }
+ *out = 0;
+
+ /* Collapse newlines */
+ in = text;
+ out = text;
+ while (*in)
+ {
+ while (!strncmp(in, "\n\n\n", 3))
+ in++;
+ *out++ = *in++;
+ }
+ *out = 0;
+}
+
+
+/* Returns a copy of the RSS document that has been converted to plain text,
+ in UTF8 encoding. Rougly, it uses the contents of the <description> field
+ of each <item>, and decodes HTML within it.
+ */
+static char *
+textclient_strip_rss (const char *rss)
+{
+ char *ret = malloc (strlen(rss) * 4 + 1); // room for UTF8
+ char *out = ret;
+ const char *a = 0, *b = 0, *c = 0, *d = 0, *t = 0;
+ int head = 1;
+ int done = 0;
+ int wiki_p = !!strcasestr (rss, "<generator>MediaWiki");
+
+ *out = 0;
+ for (const char *in = rss; *in; in++) {
+ if (*in == '<') {
+ if (!strncasecmp (in, "<item", 5) || // New item, dump.
+ !strncasecmp (in, "<entry", 6)) {
+ DONE:
+ head = 0;
+ char *title = copy_rss_field (t);
+ char *body = pick_rss_field (a, b, c, d);
+
+ a = b = c = d = t = 0;
+
+ if (title && body && !strcmp (title, body)) {
+ free (title);
+ title = 0;
+ }
+
+ if (title) {
+ strcpy (out, title);
+ free (title);
+ out += strlen (out);
+ strcpy (out, "\n\n");
+ out += strlen (out);
+ }
+
+ if (body) {
+ strcpy (out, body);
+ free (body);
+ out += strlen (out);
+ strcpy (out, "<P>");
+ out += strlen (out);
+ }
+
+ } else if (head) { // still before first <item>
+ ;
+ } else if (!strncasecmp (in, "<title", 6)) {
+ t = in+6;
+ } else if (!strncasecmp (in, "<summary", 8)) {
+ d = in+8;
+ } else if (!strncasecmp (in, "<description", 12)) {
+ a = in+12;
+ } else if (!strncasecmp (in, "<content:encoded", 16)) {
+ c = in+16;
+ } else if (!strncasecmp (in, "<content", 8)) {
+ b = in+8;
+ }
+ }
+ }
+
+ if (! done) { // Finish off the final item.
+ done = 1;
+ goto DONE;
+ }
+
+ char *ret2 = textclient_strip_html (ret);
+ free (ret);
+ ret = ret2;
+
+ if (wiki_p) {
+ strip_wiki (ret);
+ ret2 = decode_entities (ret);
+ free (ret);
+ ret = ret2;
+ }
+
+ return ret;
+}
+
+
+static void
+wrap_text (char *body, int columns, int max_lines)
+{
+ int col = 0, last_col = 0;
+ char *last_space = 0;
+ int lines = 0;
+ if (! body) return;
+ for (char *p = body; *p; p++) {
+ if (*p == '\r' || *p == '\n' || *p == ' ' || *p == '\t') {
+ if (col > columns && last_space) {
+ *last_space = '\n';
+ col = col - last_col;
+ }
+ last_space = p;
+ last_col = col;
+ }
+ if (*p == '\r' || *p == '\n') {
+ col = 0;
+ last_col = 0;
+ last_space = 0;
+ lines++;
+ if (max_lines && lines >= max_lines)
+ {
+ *p = 0;
+ break;
+ }
+ } else {
+ col++;
+ }
+ }
+}
+
+
+static void
+rewrap_text (char *body, int columns)
+{
+ if (! body) return;
+ for (char *p = body; *p; p++) {
+ if (*p == '\n') {
+ if (p[1] == '\n')
+ p++;
+ else
+ *p = ' ';
+ }
+ }
+ wrap_text (body, columns, 0);
+}
+
+
+
+static void
+strip_backslashes (char *s)
+{
+ char *out = s;
+ for (char *in = s; *in; in++) {
+ if (*in == '\\') {
+ in++;
+ if (*in == 'n') *out++ = '\n';
+ else if (*in == 'r') *out++ = '\r';
+ else if (*in == 't') *out++ = '\t';
+ else *out++ = *in;
+ } else {
+ *out++ = *in;
+ }
+ }
+ *out = 0;
+}
+
+
+/* Load the raw body of a URL, and convert it to plain text.
+ */
+static char *
+mobile_url_text (Display *dpy, const char *url)
+{
+ char *body = textclient_mobile_url_string (dpy, url);
+ enum { RSS, HTML, TEXT } type;
+ if (!body)
+ return NULL;
+
+ if (!strncasecmp (body, "<?xml", 5) ||
+ !strncasecmp (body, "<!doctype rss", 13))
+ type = RSS;
+ else if (!strncasecmp (body, "<!doctype html", 14) ||
+ !strncasecmp (body, "<html", 5) ||
+ !strncasecmp (body, "<head", 5))
+ type = HTML;
+ else if (strcasestr (body, "<base") ||
+ strcasestr (body, "<body") ||
+ strcasestr (body, "<script") ||
+ strcasestr (body, "<style") ||
+ strcasestr (body, "<a href"))
+ type = HTML;
+ else if (strcasestr (body, "<channel") ||
+ strcasestr (body, "<generator") ||
+ strcasestr (body, "<description") ||
+ strcasestr (body, "<content") ||
+ strcasestr (body, "<feed") ||
+ strcasestr (body, "<entry"))
+ type = RSS;
+ else
+ type = TEXT;
+
+ char *body2 = 0;
+
+ switch (type) {
+ case HTML: body2 = textclient_strip_html (body); break;
+ case RSS: body2 = textclient_strip_rss (body); break;
+ case TEXT: break;
+ default: abort(); break;
+ }
+
+ if (body2) {
+ free (body);
+ return body2;
+ } else {
+ return body;
+ }
+}
+
+
+int
+textclient_getc (text_data *d)
+{
+ if (!d->fp || !*d->fp) {
+ if (d->buf) {
+ free (d->buf);
+ d->buf = 0;
+ d->fp = 0;
+ }
+ switch (d->mode) {
+ case DATE: DATE:
+ d->buf = textclient_mobile_date_string();
+ break;
+ case LITERAL:
+ if (!d->literal || !*d->literal)
+ goto DATE;
+ d->buf = (char *) malloc (strlen (d->literal) + 3);
+ strcpy (d->buf, d->literal);
+ strcat (d->buf, "\n");
+ strip_backslashes (d->buf);
+ d->fp = d->buf;
+ break;
+ case URL:
+ if (!d->url || !*d->url)
+ goto DATE;
+ d->buf = mobile_url_text (d->dpy, d->url);
+ break;
+ default:
+ abort();
+ }
+ if (d->columns > 10)
+ wrap_text (d->buf, d->columns, d->max_lines);
+ d->fp = d->buf;
+ }
+
+ if (!d->fp || !*d->fp)
+ return -1;
+
+ unsigned char c = (unsigned char) *d->fp++;
+ return (int) c;
+}
+
+
+Bool
+textclient_putc (text_data *d, XKeyEvent *k)
+{
+ return False;
+}
+
+
+void
+textclient_reshape (text_data *d,
+ int pix_w, int pix_h,
+ int char_w, int char_h,
+ int max_lines)
+{
+ d->columns = char_w;
+ d->max_lines = max_lines;
+ rewrap_text (d->buf, d->columns);
+}
+
+
+#endif /* whole file */
diff --git a/utils/textclient.c b/utils/textclient.c
new file mode 100644
index 0000000..fe40928
--- /dev/null
+++ b/utils/textclient.c
@@ -0,0 +1,673 @@
+/* xscreensaver, Copyright (c) 2012-2016 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.
+ *
+ * Running programs under a pipe or pty and returning bytes from them.
+ * Uses these X resources:
+ *
+ * program: What to run. Usually "xscreensaver-text".
+ * relaunchDelay: secs How long after the command dies before restarting.
+ * usePty: bool Whether to run the command interactively.
+ * metaSendsESC: bool Whether to send Alt-x as ESC x in pty-mode.
+ * swapBSDEL: bool Swap Backspace and Delete in pty-mode.
+ *
+ * On iOS and Android, textclient-mobile.c is used instead.
+ */
+
+#include "utils.h"
+
+#if !defined(USE_IPHONE) && !defined(HAVE_ANDROID) /* whole file */
+
+#include "textclient.h"
+#include "resources.h"
+
+#ifndef HAVE_COCOA
+# define XK_MISCELLANY
+# include <X11/keysymdef.h>
+# include <X11/Xatom.h>
+# include <X11/Intrinsic.h>
+#endif
+
+#include <stdio.h>
+
+#include <signal.h>
+#include <sys/wait.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+# include <fcntl.h> /* for O_RDWR */
+#endif
+
+#ifdef HAVE_FORKPTY
+# include <sys/ioctl.h>
+# ifdef HAVE_PTY_H
+# include <pty.h>
+# endif
+# ifdef HAVE_UTIL_H
+# include <util.h>
+# endif
+# ifdef HAVE_SYS_TERMIOS_H
+# include <sys/termios.h>
+# endif
+#endif /* HAVE_FORKPTY */
+
+#undef DEBUG
+
+extern const char *progname;
+
+struct text_data {
+ Display *dpy;
+ char *program;
+ int pix_w, pix_h, char_w, char_h;
+ int max_lines;
+
+ Bool pty_p;
+ XtIntervalId pipe_timer;
+ FILE *pipe;
+ pid_t pid;
+ XtInputId pipe_id;
+ Bool input_available_p;
+ Time subproc_relaunch_delay;
+ XComposeStatus compose;
+
+ Bool meta_sends_esc_p;
+ Bool swap_bs_del_p;
+ Bool meta_done_once;
+ unsigned int meta_mask;
+
+ const char *out_buffer;
+ int out_column;
+};
+
+
+static void
+subproc_cb (XtPointer closure, int *source, XtInputId *id)
+{
+ text_data *d = (text_data *) closure;
+# ifdef DEBUG
+ if (! d->input_available_p)
+ fprintf (stderr, "%s: textclient: input available\n", progname);
+# endif
+ d->input_available_p = True;
+}
+
+
+# define BACKSLASH(c) \
+ (! ((c >= 'a' && c <= 'z') || \
+ (c >= 'A' && c <= 'Z') || \
+ (c >= '0' && c <= '9') || \
+ c == '.' || c == '_' || c == '-' || c == '+' || c == '/'))
+
+#ifdef HAVE_COCOA
+static char *
+escape_str (char *s, const char *src)
+{
+ while (*src) {
+ char c = *src++;
+ if (BACKSLASH(c)) *s++ = '\\';
+ *s++ = c;
+ }
+ return s;
+}
+#endif
+
+static void
+launch_text_generator (text_data *d)
+{
+ XtAppContext app = XtDisplayToApplicationContext (d->dpy);
+ char buf[255];
+ const char *oprogram = d->program;
+ char *s;
+
+ size_t oprogram_size = strlen(oprogram);
+ size_t len;
+
+# ifdef HAVE_COCOA
+ /* /bin/sh on OS X 10.10 wipes out the PATH. */
+ const char *path = getenv("PATH");
+ size_t cmd_capacity = (oprogram_size + strlen(path)) * 2 + 100;
+ char *cmd = s = malloc (cmd_capacity);
+ strcpy (s, "export PATH=");
+ s += strlen (s);
+ s = escape_str (s, path);
+ strcpy (s, "; ");
+ s += strlen (s);
+# else
+ char *cmd = s = malloc ((strlen(oprogram)) * 2 + 100);
+# endif
+
+ strcpy (s, "( ");
+ strcat (s, oprogram);
+ s += strlen (s);
+
+ /* Kludge! Special-case "xscreensaver-text" to tell it how wide
+ the screen is. We used to do this by just always feeding
+ `program' through sprintf() and setting the default value to
+ "xscreensaver-text --cols %d", but that makes things blow up
+ if someone ever uses a --program that includes a % anywhere.
+ */
+ len = 17; /* strlen("xscreensaver-text") */
+ if (oprogram_size >= len &&
+ !memcmp (oprogram, "xscreensaver-text", len) &&
+ (oprogram[len] == ' ' || !oprogram[len]))
+ {
+ /* strstr is sloppy here. Technically, we should be parsing the command
+ line to identify flags and their arguments. This will blow up if one
+ of those pesky end users could set .textLiteral to "--cols".
+ */
+ if (d->char_w && !strstr (oprogram, "--cols "))
+ sprintf (s, " --cols %d", d->char_w);
+ if (d->max_lines && !strstr (oprogram, "--lines "))
+ sprintf (s, " --lines %d", d->max_lines);
+ s += strlen(s);
+
+# ifdef HAVE_COCOA
+ /* Also special-case "xscreensaver-text" to specify the text content on
+ the command line. defaults(1) on macOS doesn't know about the default
+ screenhack resources that don't make it into the
+ ~/Library/Preferences/ByHost/org.jwz.xscreensaver.*.plist.
+ */
+
+ char *text_mode_flag = " --date";
+ char *value_res = NULL;
+ char *text_mode = get_string_resource (d->dpy, "textMode", "String");
+
+ if (text_mode)
+ {
+ if (!strcmp (text_mode, "1") || !strcmp (text_mode, "literal"))
+ {
+ text_mode_flag = " --text";
+ value_res = "textLiteral";
+ }
+ else if (!strcmp (text_mode, "2") || !strcmp (text_mode, "file"))
+ {
+ text_mode_flag = " --file";
+ value_res = "textFile";
+ }
+ else if (!strcmp (text_mode, "3") || !strcmp (text_mode, "url"))
+ {
+ text_mode_flag = " --url";
+ value_res = "textURL";
+ }
+ else if (!strcmp (text_mode, "4") || !strcmp (text_mode, "program"))
+ {
+ text_mode_flag = " --program";
+ value_res = "textProgram";
+ }
+
+ free (text_mode);
+ }
+
+ 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 */
+ }
+
+ strcpy (s, " ) 2>&1");
+
+# ifdef DEBUG
+ fprintf (stderr, "%s: textclient: launch %s: %s\n", progname,
+ (d->pty_p ? "pty" : "pipe"), cmd);
+# endif
+
+#ifdef HAVE_FORKPTY
+ if (d->pty_p)
+ {
+ int fd;
+ struct winsize ws;
+
+ ws.ws_col = d->char_w;
+ ws.ws_row = d->char_h;
+ ws.ws_xpixel = d->pix_w;
+ ws.ws_ypixel = d->pix_h;
+
+ d->pipe = 0;
+
+# ifdef HAVE_COCOA
+ if (getenv ("MallocScribble"))
+ /* This is here to stop me from wasting my time trying to answer
+ this question the next time I forget about it. */
+ fprintf (stderr, "%s: WARNING: forkpty hates 'Enable Guard Malloc'\n",
+ progname);
+# endif
+
+ if ((d->pid = forkpty(&fd, NULL, NULL, &ws)) < 0)
+ {
+ /* Unable to fork */
+ sprintf (buf, "%.100s: forkpty", progname);
+ perror (buf);
+ }
+ else if (!d->pid)
+ {
+ /* This is the child fork. */
+ char *av[10];
+ int i = 0;
+ if (putenv ("TERM=vt100"))
+ abort();
+ av[i++] = "/bin/sh";
+ av[i++] = "-c";
+ av[i++] = cmd;
+ av[i] = 0;
+# ifdef DEBUG
+ {
+ int j;
+ fprintf (stderr, "%s: textclient: execvp:", progname);
+ for (j = 0; j < i; j++)
+ fprintf (stderr, " %s", av[j]);
+ fprintf (stderr, "\n");
+ }
+# endif
+ execvp (av[0], av);
+ sprintf (buf, "%.100s: %.100s", progname, oprogram);
+ perror (buf);
+ exit (1);
+ }
+ else
+ {
+ /* This is the parent fork. */
+ if (d->pipe) abort();
+ d->pipe = fdopen (fd, "r+");
+ if (d->pipe_id) abort();
+ d->pipe_id =
+ XtAppAddInput (app, fileno (d->pipe),
+ (XtPointer) (XtInputReadMask | XtInputExceptMask),
+ subproc_cb, (XtPointer) d);
+# ifdef DEBUG
+ fprintf (stderr, "%s: textclient: pid = %d\n", progname, d->pid);
+# endif
+ }
+ }
+ else
+#endif /* HAVE_FORKPTY */
+ {
+ /* don't mess up controlling terminal on "-pipe -program tcsh". */
+ static int protected_stdin_p = 0;
+ if (! protected_stdin_p) {
+ fclose (stdin);
+ open ("/dev/null", O_RDWR); /* re-allocate fd 0 */
+ protected_stdin_p = 1;
+ }
+
+ if (d->pipe) abort();
+ if ((d->pipe = popen (cmd, "r")))
+ {
+ if (d->pipe_id) abort();
+ d->pipe_id =
+ XtAppAddInput (app, fileno (d->pipe),
+ (XtPointer) (XtInputReadMask | XtInputExceptMask),
+ subproc_cb, (XtPointer) d);
+# ifdef DEBUG
+ fprintf (stderr, "%s: textclient: popen\n", progname);
+# endif
+ }
+ else
+ {
+ sprintf (buf, "%.100s: %.100s", progname, cmd);
+ perror (buf);
+ }
+ }
+
+ free (cmd);
+}
+
+
+static void
+relaunch_generator_timer (XtPointer closure, XtIntervalId *id)
+{
+ text_data *d = (text_data *) closure;
+ /* if (!d->pipe_timer) abort(); */
+ d->pipe_timer = 0;
+# ifdef DEBUG
+ fprintf (stderr, "%s: textclient: launch timer fired\n", progname);
+# endif
+ launch_text_generator (d);
+}
+
+
+static void
+start_timer (text_data *d)
+{
+ XtAppContext app = XtDisplayToApplicationContext (d->dpy);
+
+# ifdef DEBUG
+ fprintf (stderr, "%s: textclient: relaunching in %d\n", progname,
+ (int) d->subproc_relaunch_delay);
+# endif
+ if (d->pipe_timer)
+ XtRemoveTimeOut (d->pipe_timer);
+ d->pipe_timer =
+ XtAppAddTimeOut (app, d->subproc_relaunch_delay,
+ relaunch_generator_timer,
+ (XtPointer) d);
+}
+
+
+static void
+close_pipe (text_data *d)
+{
+ if (d->pid)
+ {
+# ifdef DEBUG
+ fprintf (stderr, "%s: textclient: kill %d\n", progname, d->pid);
+# endif
+ kill (d->pid, SIGTERM);
+ }
+ d->pid = 0;
+
+ if (d->pipe_id)
+ XtRemoveInput (d->pipe_id);
+ d->pipe_id = 0;
+
+ if (d->pipe)
+ {
+# ifdef DEBUG
+ fprintf (stderr, "%s: textclient: pclose\n", progname);
+# endif
+ pclose (d->pipe);
+ }
+ d->pipe = 0;
+
+
+}
+
+
+void
+textclient_reshape (text_data *d,
+ int pix_w, int pix_h,
+ int char_w, int char_h,
+ int max_lines)
+{
+# if defined(HAVE_FORKPTY) && defined(TIOCSWINSZ)
+
+ d->pix_w = pix_w;
+ d->pix_h = pix_h;
+ d->char_w = char_w;
+ d->char_h = char_h;
+ d->max_lines = max_lines;
+
+# ifdef DEBUG
+ fprintf (stderr, "%s: textclient: reshape: %dx%d, %dx%d\n", progname,
+ pix_w, pix_h, char_w, char_h);
+# endif
+
+ if (d->pid && d->pipe)
+ {
+ /* Tell the sub-process that the screen size has changed. */
+ struct winsize ws;
+ ws.ws_col = char_w;
+ ws.ws_row = char_h;
+ ws.ws_xpixel = pix_w;
+ ws.ws_ypixel = pix_h;
+ ioctl (fileno (d->pipe), TIOCSWINSZ, &ws);
+ kill (d->pid, SIGWINCH);
+# ifdef DEBUG
+ fprintf (stderr, "%s: textclient: SIGWINCH\n", progname);
+# endif
+ }
+# endif /* HAVE_FORKPTY && TIOCSWINSZ */
+
+
+ /* If we're running xscreensaver-text, then kill and restart it any
+ time the window is resized so that it gets an updated --cols arg
+ right away. But if we're running something else, leave it alone.
+ */
+ if (!strcmp (d->program, "xscreensaver-text"))
+ {
+# ifdef DEBUG
+ fprintf (stderr, "%s: textclient: reshape relaunch\n", progname);
+# endif
+ close_pipe (d);
+ d->input_available_p = False;
+ start_timer (d);
+ }
+}
+
+
+text_data *
+textclient_open (Display *dpy)
+{
+ text_data *d = (text_data *) calloc (1, sizeof (*d));
+
+# ifdef DEBUG
+ fprintf (stderr, "%s: textclient: init\n", progname);
+# endif
+
+ d->dpy = dpy;
+
+ if (get_boolean_resource (dpy, "usePty", "UsePty"))
+ {
+# ifdef HAVE_FORKPTY
+ d->pty_p = True;
+# else
+ fprintf (stderr,
+ "%s: no pty support on this system; using a pipe instead.\n",
+ progname);
+# endif
+ }
+
+ d->subproc_relaunch_delay =
+ get_integer_resource (dpy, "relaunchDelay", "Time");
+ if (d->subproc_relaunch_delay < 1)
+ d->subproc_relaunch_delay = 1;
+ d->subproc_relaunch_delay *= 1000;
+
+
+ d->meta_sends_esc_p = get_boolean_resource (dpy, "metaSendsESC", "Boolean");
+ d->swap_bs_del_p = get_boolean_resource (dpy, "swapBSDEL", "Boolean");
+
+ d->program = get_string_resource (dpy, "program", "Program");
+
+
+# ifdef HAVE_FORKPTY
+ /* Kludge for MacOS standalone mode: see OSX/SaverRunner.m. */
+ {
+ const char *s = getenv ("XSCREENSAVER_STANDALONE");
+ if (s && *s && strcmp(s, "0"))
+ {
+ d->pty_p = 1;
+ d->program = strdup (getenv ("SHELL"));
+# ifdef DEBUG
+ fprintf (stderr, "%s: textclient: standalone: %s\n",
+ progname, d->program);
+# endif
+ }
+ }
+# endif
+
+ start_timer (d);
+
+ return d;
+}
+
+
+void
+textclient_close (text_data *d)
+{
+# ifdef DEBUG
+ fprintf (stderr, "%s: textclient: free\n", progname);
+# endif
+
+ close_pipe (d);
+ if (d->program)
+ free (d->program);
+ if (d->pipe_timer)
+ XtRemoveTimeOut (d->pipe_timer);
+ d->pipe_timer = 0;
+ memset (d, 0, sizeof (*d));
+ free (d);
+}
+
+int
+textclient_getc (text_data *d)
+{
+ XtAppContext app = XtDisplayToApplicationContext (d->dpy);
+ int ret = -1;
+
+ if (XtAppPending (app) & (XtIMTimer|XtIMAlternateInput))
+ XtAppProcessEvent (app, XtIMTimer|XtIMAlternateInput);
+
+ if (d->out_buffer && *d->out_buffer)
+ {
+ ret = *d->out_buffer;
+ d->out_buffer++;
+ }
+ else if (d->input_available_p && d->pipe)
+ {
+ unsigned char s[2];
+ int n = read (fileno (d->pipe), (void *) s, 1);
+ if (n > 0)
+ ret = s[0];
+ else /* EOF */
+ {
+ if (d->pid)
+ {
+# ifdef DEBUG
+ fprintf (stderr, "%s: textclient: waitpid %d\n",
+ progname, d->pid);
+# endif
+ waitpid (d->pid, NULL, 0);
+ d->pid = 0;
+ }
+
+ close_pipe (d);
+
+ if (d->out_column > 0)
+ {
+# ifdef DEBUG
+ fprintf (stderr, "%s: textclient: adding blank line at EOF\n",
+ progname);
+# endif
+ d->out_buffer = "\r\n\r\n";
+ }
+
+ start_timer (d);
+ }
+ d->input_available_p = False;
+ }
+
+ if (ret == '\r' || ret == '\n')
+ d->out_column = 0;
+ else if (ret > 0)
+ d->out_column++;
+
+# ifdef DEBUG
+ if (ret <= 0)
+ fprintf (stderr, "%s: textclient: getc: %d\n", progname, ret);
+ else if (ret < ' ')
+ fprintf (stderr, "%s: textclient: getc: %03o\n", progname, ret);
+ else
+ fprintf (stderr, "%s: textclient: getc: '%c'\n", progname, (char) ret);
+# endif
+
+ return ret;
+}
+
+
+/* The interpretation of the ModN modifiers is dependent on what keys
+ are bound to them: Mod1 does not necessarily mean "meta". It only
+ means "meta" if Meta_L or Meta_R are bound to it. If Meta_L is on
+ Mod5, then Mod5 is the one that means Meta. Oh, and Meta and Alt
+ aren't necessarily the same thing. Icepicks in my forehead!
+ */
+static unsigned int
+do_icccm_meta_key_stupidity (Display *dpy)
+{
+ unsigned int modbits = 0;
+# ifndef HAVE_COCOA
+ int i, j, k;
+ XModifierKeymap *modmap = XGetModifierMapping (dpy);
+ for (i = 3; i < 8; i++)
+ for (j = 0; j < modmap->max_keypermod; j++)
+ {
+ int code = modmap->modifiermap[i * modmap->max_keypermod + j];
+ KeySym *syms;
+ int nsyms = 0;
+ if (code == 0) continue;
+ syms = XGetKeyboardMapping (dpy, code, 1, &nsyms);
+ for (k = 0; k < nsyms; k++)
+ if (syms[k] == XK_Meta_L || syms[k] == XK_Meta_R ||
+ syms[k] == XK_Alt_L || syms[k] == XK_Alt_R)
+ modbits |= (1 << i);
+ XFree (syms);
+ }
+ XFreeModifiermap (modmap);
+# endif /* HAVE_COCOA */
+ return modbits;
+}
+
+
+/* Returns a mask of the bit or bits of a KeyPress event that mean "meta".
+ */
+static unsigned int
+meta_modifier (text_data *d)
+{
+ if (!d->meta_done_once)
+ {
+ /* Really, we are supposed to recompute this if a KeymapNotify
+ event comes in, but fuck it. */
+ d->meta_done_once = True;
+ d->meta_mask = do_icccm_meta_key_stupidity (d->dpy);
+# ifdef DEBUG
+ fprintf (stderr, "%s: textclient: ICCCM Meta is 0x%08X\n",
+ progname, d->meta_mask);
+# endif
+ }
+ return d->meta_mask;
+}
+
+
+Bool
+textclient_putc (text_data *d, XKeyEvent *k)
+{
+ KeySym keysym;
+ unsigned char c = 0;
+ XLookupString (k, (char *) &c, 1, &keysym, &d->compose);
+ if (c != 0 && d->pipe)
+ {
+ if (!d->swap_bs_del_p) ;
+ else if (c == 127) c = 8;
+ else if (c == 8) c = 127;
+
+ /* If meta was held down, send ESC, or turn on the high bit. */
+ if (k->state & meta_modifier (d))
+ {
+ if (d->meta_sends_esc_p)
+ fputc ('\033', d->pipe);
+ else
+ c |= 0x80;
+ }
+
+ fputc (c, d->pipe);
+ fflush (d->pipe);
+ k->type = 0; /* don't interpret this event defaultly. */
+
+# ifdef DEBUG
+ fprintf (stderr, "%s: textclient: putc '%c'\n", progname, (char) c);
+# endif
+
+ return True;
+ }
+ return False;
+}
+
+#endif /* !USE_IPHONE -- whole file */
diff --git a/utils/textclient.h b/utils/textclient.h
new file mode 100644
index 0000000..0fe582d
--- /dev/null
+++ b/utils/textclient.h
@@ -0,0 +1,37 @@
+/* xscreensaver, Copyright (c) 2012-2016 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.
+ *
+ * Running "xscreensaver-text" and returning bytes from it.
+ */
+
+#ifndef __TEXTCLIENT_H__
+#define __TEXTCLIENT_H__
+
+# ifdef USE_IPHONE
+# undef HAVE_FORKPTY
+# endif
+
+typedef struct text_data text_data;
+
+extern text_data *textclient_open (Display *);
+extern void textclient_close (text_data *);
+extern void textclient_reshape (text_data *,
+ int pix_w, int pix_h,
+ int char_w, int char_h,
+ int max_lines);
+extern int textclient_getc (text_data *);
+extern Bool textclient_putc (text_data *, XKeyEvent *);
+
+# if defined(USE_IPHONE) || defined(HAVE_ANDROID)
+extern char *textclient_mobile_date_string (void);
+extern char *textclient_mobile_url_string (Display *, const char *url);
+# endif
+
+#endif /* __TEXTCLIENT_H__ */
diff --git a/utils/thread_util.c b/utils/thread_util.c
new file mode 100644
index 0000000..5ad5d47
--- /dev/null
+++ b/utils/thread_util.c
@@ -0,0 +1,1043 @@
+/* -*- mode: c; tab-width: 4; fill-column: 78 -*- */
+/* vi: set ts=4 tw=78: */
+
+/*
+thread_util.c, Copyright (c) 2014 Dave Odell <dmo2118@gmail.com>
+
+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.
+*/
+
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h> /* Only used by thread_memory_alignment(). */
+#include <string.h>
+
+#if HAVE_ALLOCA_H
+# 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"
+
+#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
+# else
+ PTHREAD_MUTEX_INITIALIZER
+# endif
+ ;
+
+const pthread_cond_t cond_initializer = PTHREAD_COND_INITIALIZER;
+
+static int _has_pthread = 0; /* Initialize when needed. */
+static int _cache_line_size = sizeof(void *);
+
+/* This is actually the init function for various things in here. */
+int threads_available(Display *dpy)
+{
+/* This is maybe not thread-safe, but: this should -- and generally will --
+ be called before the program launches its second thread. */
+
+ if(!_has_pthread)
+ {
+# if _POSIX_THREADS
+ _has_pthread = _POSIX_THREADS;
+# else
+ _has_pthread = sysconf(_SC_THREADS);
+# endif
+
+ 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));
+ }
+ else
+ {
+ _has_pthread = -1;
+ }
+ }
+ }
+
+ return _has_pthread;
+}
+
+#endif /* HAVE_PTHREAD */
+
+/*
+ hardware_concurrency() -
+
+ Various platforms offer various statistics that look like they should be
+ useful: sysconf(_SC_NPROCESSORS_ONLN) (i.e. the number of 'online'
+ processors) in particular is available on many Unixes, and is frequently
+ used for functions like hardware_concurrency(). But 'online' is somewhat
+ ambiguous; it can mean:
+
+ 1. The number of CPU cores that are not (temporarily) asleep. (e.g. Android
+ can sometimes put cores to sleep if they aren't being used, and this is
+ reflected in _SC_NPROCESSORS_ONLN.)
+
+ 2. The maximum number of CPU cores that can be provided to this application,
+ as currently set by the system administrator. (2) is the one that
+ hardware_concurrency() ultimately needs.
+*/
+
+/*
+ Shamelessly plagarized from Boost.Thread and Stack Overflow
+ <http://stackoverflow.com/q/150355>. GNU libstdc++ has some of this too,
+ see thread::hardware_concurrency() in thread.cc.
+ http://gcc.gnu.org/viewcvs/gcc/trunk/libstdc%2B%2B-v3/src/c%2B%2B11/thread.cc?view=markup
+
+ This might not work right on less common systems for various reasons.
+*/
+
+#if HAVE_PTHREAD
+# if defined __APPLE__ && defined __MACH__ || \
+ defined __FreeBSD__ || \
+ defined __OpenBSD__ || \
+ defined __NetBSD__ || \
+ defined __DragonFly__ || \
+ defined __minix
+
+/*
+ BSD Unixes use sysctl(3) for this.
+ Some BSDs also support sysconf(3) for this, but in each case this was added
+ after sysctl(3).
+ Linux: sysctl is present, but strongly deprecated.
+ Minix uses the NetBSD userspace, so it has both this and sysconf(3).
+ QNX: sysctl is present for kern.* and net.*, but it doesn't say anything
+ about hw.*
+*/
+
+/* __APPLE__ without __MACH__ is OS 9 or earlier. __APPLE__ with __MACH__ is OS X. */
+
+/*
+The usual thing to do here is for sysctl(3) to call __sysctl(2).
+ http://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libc/gen/sysctl.c?only_with_tag=HEAD
+ http://svnweb.freebsd.org/base/head/lib/libc/gen/sysctl.c?view=markup
+*/
+
+/*
+ OS X: Xcode Instruments (as of Xcode 4; Apple likes to move things like
+ this around) can disable CPUs as a debugging tool.
+ Instruments -> Preferences... (Command-,) -> General -> Active Processor Cores
+ FreeBSD, OpenBSD: It doesn't look like CPUs can be disabled.
+ NetBSD: CPUs can be disabled manually through cpuctl(8).
+*/
+
+# include <stddef.h>
+
+/* FreeBSD: sys/sysctl.h needs sys/types.h, but the one doesn't bring the
+ other in automatically. */
+# include <sys/types.h>
+# include <sys/sysctl.h>
+
+static unsigned _hardware_concurrency(void)
+{
+ int count;
+ size_t size = sizeof(count);
+
+# if defined __APPLE__ && defined __MACH__
+ /* Apple sez: sysctl("hw.logicalcpu") is affected by the "current power
+ management mode", so use hw.logicalcpu_max. */
+ /* https://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man3/sysctl.3.html */
+ if(!sysctlbyname("hw.logicalcpu_max", &count, &size, NULL, 0)) /* Preferred on more recent Darwin. */
+ {
+ assert(size == sizeof(count));
+ return count;
+ }
+# endif
+
+# if defined HW_NCPUONLINE
+ /* NetBSD has this. */
+ {
+ static const int name[] = {CTL_HW, HW_NCPUONLINE};
+ if(!sysctl(name, 2, &count, &size, NULL, 0))
+ {
+ assert(size == sizeof(count));
+ return count;
+ }
+ }
+# endif
+
+ {
+ static const int name[] = {CTL_HW, HW_NCPU};
+ if(!sysctl((int *)name, 2, &count, &size, NULL, 0)) /* (int *) is for OS X. */
+ {
+ assert(size == sizeof(count));
+ return count;
+ }
+ }
+
+ return 1;
+}
+
+# elif HAVE_UNISTD_H && defined _SC_NPROCESSORS_ONLN
+
+/*
+Supported by:
+Linux 2.0 was the first version to provide SMP support via clone(2).
+ (e)glibc on Linux provides this, which in turn uses get_nprocs().
+ get_nprocs in turn uses /sys/devices/system/cpu/online, /proc/stat, or /proc/cpuinfo, whichever's available.
+ https://sourceware.org/git/?p=glibc.git;a=blob;f=posix/sysconf.c;hb=HEAD
+ https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/getsysstats.c;hb=HEAD
+ Linux usually isn't configured to auto-enable/disable cores.
+SunOS (Solaris), sometime between 4.1.3 and 5.5.1.
+ This includes all open source derivatives of 5.10. (Illumos, OpenIndiana)
+ sysconf(_SC_NPROCESSORS_ONLN) call _sysconfig(2).
+ Not sure if CPU power management (enabled by default, see cpupm and
+ cpu_deep_idle in power.conf(4)) affects this.
+ psradm(1M) can bring up/down CPU cores, which affects
+ sysconf(_SC_NPROCESSORS_ONLN).
+ http://src.illumos.org/source/xref/illumos-gate/usr/src/lib/libc/port/gen/sysconf.c
+ Minix 3.2, at the latest. (This is the first version to support SMP.)
+ AIX 7.1, probably earlier.
+
+Also:
+Mac OS X apparently has this on 10.5+.
+FreeBSD 5.0, NetBSD 5.0 also have this. They both call sysctl(3).
+ http://svnweb.freebsd.org/base/head/lib/libc/gen/sysconf.c?view=markup
+ http://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libc/gen/sysconf.c?only_with_tag=HEAD
+
+QNX has sysconf(3), but it doesn't have _SC_NPROCESSORS_*.
+*/
+
+static unsigned _hardware_concurrency(void)
+{
+ long count = sysconf(_SC_NPROCESSORS_ONLN);
+ return count > 0 ? count : 1;
+}
+
+# else
+
+static unsigned _hardware_concurrency(void)
+{
+ return 1; /* Fallback for unknown systems. */
+}
+
+# endif
+#endif
+
+unsigned hardware_concurrency(Display *dpy)
+{
+#if HAVE_PTHREAD
+ if(threads_available(dpy) >= 0)
+ return _hardware_concurrency();
+#endif
+ return 1;
+}
+
+/* thread_memory_alignment() - */
+
+unsigned thread_memory_alignment(Display *dpy)
+{
+ (void)threads_available(dpy);
+#if HAVE_PTHREAD
+ return _cache_line_size;
+#else
+ return sizeof(void *);
+#endif
+}
+
+/* Thread pool - */
+
+static unsigned _threadpool_count_serial(struct threadpool *self)
+{
+#if HAVE_PTHREAD
+ assert(_has_pthread);
+ if(_has_pthread >= 0)
+ return self->count ? 1 : 0;
+#endif
+ return self->count;
+}
+
+static void _serial_destroy(struct threadpool *self)
+{
+ void *thread = self->serial_threads;
+ unsigned i, count = _threadpool_count_serial(self);
+
+ for(i = 0; i != count; ++i)
+ {
+ self->thread_destroy(thread);
+ thread = (char *)thread + self->thread_size;
+ }
+
+ free(self->serial_threads);
+}
+
+#if HAVE_PTHREAD
+
+static void _parallel_abort(struct threadpool *self)
+{
+ assert(self->count > 1);
+ self->count = self->parallel_unfinished + 1 /* The '+ 1' should technically be _threadpool_count_serial(self). */;
+ PTHREAD_VERIFY(pthread_cond_broadcast(&self->cond));
+}
+
+struct _parallel_startup_type
+{
+ struct threadpool *parent;
+ int (*thread_create)(void *self, struct threadpool *pool, unsigned id);
+ int last_errno;
+};
+
+static unsigned _threadpool_count_parallel(struct threadpool *self)
+{
+ assert(_has_pthread);
+ assert(self->count >= 1);
+ return self->count - 1 /* The '- 1' should technically be _threadpool_count_serial(self). */;
+}
+
+static void *_start_routine(void *startup_raw);
+
+/* Tricky lock sequence: _add_next_thread unlocks on error. */
+static void _add_next_thread(struct _parallel_startup_type *self)
+{
+ assert(!self->last_errno);
+
+ if(self->parent->parallel_unfinished == _threadpool_count_parallel(self->parent))
+ {
+ PTHREAD_VERIFY(pthread_cond_broadcast(&self->parent->cond));
+ }
+ else
+ {
+ pthread_t *thread = self->parent->parallel_threads + self->parent->parallel_unfinished;
+ self->last_errno = pthread_create(thread, NULL, _start_routine, self);
+ if(self->last_errno)
+ _parallel_abort(self->parent);
+ }
+}
+
+static void *_thread_free_and_unlock(struct threadpool *self, void *thread)
+{
+ PTHREAD_VERIFY(pthread_mutex_unlock(&self->mutex));
+# if !HAVE_ALLOCA
+ thread_free(thread);
+# endif
+ return NULL;
+}
+
+static void *_thread_destroy_and_unlock(struct threadpool *self, void *thread)
+{
+ self->thread_destroy(thread);
+ return _thread_free_and_unlock(self, thread);
+}
+
+/* At one point, one of the threads refused to destroy itself at the end. Why?! And why won't it happen again? */
+
+static void *_start_routine(void *startup_raw)
+{
+ struct _parallel_startup_type *startup = (struct _parallel_startup_type *)startup_raw;
+
+ struct threadpool *parent = startup->parent;
+
+ void *thread;
+
+ PTHREAD_VERIFY(pthread_mutex_lock(&parent->mutex));
+ ++parent->parallel_unfinished;
+
+# if HAVE_ALLOCA
+/* Ideally, the thread object goes on the thread's stack. This guarantees no false sharing with other threads, and in a NUMA
+ configuration, ensures that the thread object is using memory from the right node. */
+ thread = alloca(parent->thread_size);
+# else
+ startup->last_errno = thread_malloc(&thread, NULL, parent->thread_size);
+ if(startup->last_errno)
+ {
+ _parallel_abort(parent);
+ PTHREAD_VERIFY(pthread_mutex_unlock(&parent->mutex));
+ return NULL;
+ }
+# endif
+
+/* Setting thread affinity for threads running in lock-step can cause delays
+ and jumpiness. Ideally, there would be some way to recommend (but not
+ require) that a thread run on a certain core/set of cores. */
+
+/* Neither Linux nor libnuma seem to support the concept of a preferred/ideal
+ CPU for a thread/process. */
+
+/* Untested. */
+/* {
+ cpu_set_t cpu_set;
+ CPU_ZERO(&cpu_set);
+ CPU_SET(&cpu_set, &parent._threads_unfinished);
+ pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpu_set);
+ } */
+
+ startup->last_errno = startup->thread_create(thread, parent, parent->parallel_unfinished);
+ if(startup->last_errno)
+ {
+ _parallel_abort(parent);
+ return _thread_free_and_unlock(parent, thread); /* Tail calls make everything better. */
+ }
+
+ assert(!startup->last_errno);
+ _add_next_thread(startup); /* Calls _parallel_abort() on failure. */
+ if(startup->last_errno)
+ return _thread_destroy_and_unlock(parent, thread);
+
+ for(;;)
+ {
+ for(;;)
+ {
+ /*
+ This must come before the '.threads' check, otherwise if
+ threadpool_destroy is called immediately after a run starts, then
+ it's possible that not all threads would be launched for the final
+ run. This can cause deadlock in conjunction with things like
+ barriers.
+ */
+ if(parent->parallel_pending)
+ break; /* Start a run. */
+
+ if(!parent->parallel_threads)
+ return _thread_destroy_and_unlock(parent, thread); /* Threads are shutting down. */
+
+ PTHREAD_VERIFY(pthread_cond_wait(&parent->cond, &parent->mutex));
+ }
+
+ --parent->parallel_pending;
+ if(!parent->parallel_pending)
+ PTHREAD_VERIFY(pthread_cond_broadcast(&parent->cond));
+ /* All threads have started processing, other threads can finish. */
+
+ PTHREAD_VERIFY(pthread_mutex_unlock(&parent->mutex));
+
+ parent->thread_run(thread);
+
+ PTHREAD_VERIFY(pthread_mutex_lock(&parent->mutex));
+# if 0
+ if(!parent->parallel_threads) /* I don't think this is necessary anymore. */
+ break;
+# endif
+ /* Don't loop around until all other threads have begun processing. */
+
+ /* I suspect it doesn't matter whether this comes before or after the threads_unfinished check. */
+ while(parent->parallel_pending)
+ PTHREAD_VERIFY(pthread_cond_wait(&parent->cond, &parent->mutex));
+
+ --parent->parallel_unfinished;
+ if(!parent->parallel_unfinished)
+ PTHREAD_VERIFY(pthread_cond_broadcast(&parent->cond)); /* All threads done for now. */
+ }
+
+ /* return _thread_destroy_and_unlock(parent, thread); */
+}
+
+static void _unlock_and_destroy(struct threadpool *self)
+{
+ pthread_t *threads;
+
+ threads = self->parallel_threads;
+ self->parallel_threads = NULL;
+
+ if(threads)
+ PTHREAD_VERIFY(pthread_cond_broadcast(&self->cond));
+
+ PTHREAD_VERIFY(pthread_mutex_unlock(&self->mutex));
+
+ if(threads)
+ {
+ unsigned i, count = _threadpool_count_parallel(self);
+ for(i = 0; i != count; ++i)
+ PTHREAD_VERIFY(pthread_join(threads[i], NULL));
+
+ free(threads);
+ PTHREAD_VERIFY(pthread_cond_destroy(&self->cond));
+ PTHREAD_VERIFY(pthread_mutex_destroy(&self->mutex));
+ }
+
+ _serial_destroy(self);
+}
+
+#endif /* HAVE_PTHREAD */
+
+int threadpool_create(struct threadpool *self, const struct threadpool_class *cls, Display *dpy, unsigned count)
+{
+ (void)threads_available(dpy);
+
+ self->count = count;
+
+/* If threads are not present, run each "thread" in sequence on the calling
+ thread. Otherwise, only run the first thread on the main thread. */
+
+ assert(cls);
+
+ self->thread_size = cls->size;
+ self->thread_destroy = cls->destroy;
+
+ {
+ void *thread;
+ unsigned i, count_serial = _threadpool_count_serial(self);
+
+ if(count_serial)
+ {
+ thread = malloc(cls->size * count_serial);
+ if(!thread)
+ return ENOMEM;
+ }
+ else
+ {
+ /* Might as well skip the malloc. */
+ thread = NULL;
+ }
+
+ self->serial_threads = thread;
+
+ for(i = 0; i != count_serial; ++i)
+ {
+ int error = cls->create(thread, self, i);
+ if(error)
+ {
+ self->count = i;
+ _serial_destroy(self);
+ return error;
+ }
+
+ thread = (char *)thread + self->thread_size;
+ }
+ }
+
+#if HAVE_PTHREAD
+ assert(_has_pthread); /* _has_pthread should be either -1 or >0. */
+ if(_has_pthread >= 0)
+ {
+ unsigned count_parallel = _threadpool_count_parallel(self);
+ self->mutex = mutex_initializer;
+ self->cond = cond_initializer;
+ self->parallel_pending = 0;
+ self->parallel_unfinished = 0;
+ if(!count_parallel)
+ {
+ self->parallel_threads = NULL;
+ return 0;
+ }
+
+ self->parallel_threads = malloc(sizeof(pthread_t) * count_parallel);
+ if(!self->parallel_threads)
+ return ENOMEM;
+
+ {
+ struct _parallel_startup_type startup;
+ startup.parent = self;
+ startup.thread_create = cls->create;
+ startup.last_errno = 0;
+
+ PTHREAD_VERIFY(pthread_mutex_lock(&self->mutex));
+ _add_next_thread(&startup);
+
+ if(!startup.last_errno)
+ {
+ while(self->parallel_unfinished != count_parallel && self->parallel_threads)
+ PTHREAD_VERIFY(pthread_cond_wait(&self->cond, &self->mutex));
+ }
+
+ /* This must come after the if(!startup.last_errno). */
+ if(startup.last_errno)
+ {
+ _unlock_and_destroy(self);
+ }
+ else
+ {
+ self->parallel_unfinished = 0;
+ PTHREAD_VERIFY(pthread_mutex_unlock(&self->mutex));
+ }
+
+ return startup.last_errno;
+ }
+ }
+#endif
+
+ return 0;
+}
+
+void threadpool_destroy(struct threadpool *self)
+{
+#if HAVE_PTHREAD
+ if(_has_pthread >= 0)
+ {
+ PTHREAD_VERIFY(pthread_mutex_lock(&self->mutex));
+ _unlock_and_destroy(self);
+ return;
+ }
+#endif
+
+ _serial_destroy(self);
+}
+
+void threadpool_run(struct threadpool *self, void (*func)(void *))
+{
+#if HAVE_PTHREAD
+ if(_has_pthread >= 0)
+ {
+ unsigned count = _threadpool_count_parallel(self);
+ PTHREAD_VERIFY(pthread_mutex_lock(&self->mutex));
+
+ /* Do not call threadpool_run() twice without a threadpool_wait() in the middle. */
+ assert(!self->parallel_pending);
+ assert(!self->parallel_unfinished);
+
+ self->parallel_pending = count;
+ self->parallel_unfinished = count;
+ self->thread_run = func;
+ PTHREAD_VERIFY(pthread_cond_broadcast(&self->cond));
+ PTHREAD_VERIFY(pthread_mutex_unlock(&self->mutex));
+ }
+#endif
+
+ /* It's perfectly valid to move this to the beginning of threadpool_wait(). */
+ {
+ void *thread = self->serial_threads;
+ unsigned i, count = _threadpool_count_serial(self);
+ for(i = 0; i != count; ++i)
+ {
+ func(thread);
+ thread = (char *)thread + self->thread_size;
+ }
+ }
+}
+
+void threadpool_wait(struct threadpool *self)
+{
+#if HAVE_PTHREAD
+ if(_has_pthread >= 0)
+ {
+ PTHREAD_VERIFY(pthread_mutex_lock(&self->mutex));
+ while(self->parallel_unfinished)
+ PTHREAD_VERIFY(pthread_cond_wait(&self->cond, &self->mutex));
+ PTHREAD_VERIFY(pthread_mutex_unlock(&self->mutex));
+ }
+#endif
+}
+
+/* io_thread - */
+
+#if HAVE_PTHREAD
+/* Without threads at compile time, there's only stubs in thread_util.h. */
+
+# define VERSION_CHECK(cc_major, cc_minor, req_major, req_minor) \
+ ((cc_major) > (req_major) || \
+ (cc_major) == (req_major) && (cc_minor) >= (req_minor))
+
+# if defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 7) || \
+ defined(__clang__) && \
+ (!defined(__apple_build_version__) && VERSION_CHECK(__clang_major__, __clang_minor__, 3, 1) || \
+ defined(__apple_build_version__) && VERSION_CHECK(__clang_major__, __clang_minor__, 3, 1)) || \
+ defined(__ICC) && __ICC >= 1400
+
+/*
+ Clang 3.0 has a partial implementation of GNU atomics; 3.1 rounds it out.
+ http://llvm.org/viewvc/llvm-project/cfe/tags/RELEASE_30/final/include/clang/Basic/Builtins.def?view=markup
+ http://llvm.org/viewvc/llvm-project/cfe/tags/RELEASE_31/final/include/clang/Basic/Builtins.def?view=markup
+
+ Apple changes the Clang version to track Xcode versions; use
+ __apple_build_version__ to distinguish between the two.
+
+ Xcode 4.3 uses Apple LLVM 3.1, which corresponds to Clang 3.1.
+ https://en.wikipedia.org/wiki/Xcode
+
+ Earlier versions of Intel C++ may also support these intrinsics.
+ */
+
+#define _status_load(status) (__atomic_load_n((status), __ATOMIC_SEQ_CST))
+#define _status_exchange(obj, desired) (__atomic_exchange_n((obj), (desired), __ATOMIC_SEQ_CST))
+
+/* C11 atomics are around the corner, but they're not here yet for many
+ systems. (Including mine.) */
+/*
+#elif __STDC_VERSION__ >= 201112l && !defined __STDC_NO_ATOMICS__
+
+#include <stdatomic.h>
+
+#define _status_load(status) (atomic_load((status)))
+#define _status_exchange(obj, desired) (atomic_exchange((obj), (desired)))
+*/
+
+/* Solaris profiles atomic ops on at least Solaris 10. See atomic_swap(3C) and
+ membar_ops(3C). This would probably also need a snippet in configure.in.
+ http://graegert.com/programming/using-atomic-operations-in-c-on-solaris-10
+*/
+
+# else
+
+/* No atomic variables, so here's some ugly mutex-based code instead. */
+
+/* Nothing ever destroys this mutex. */
+pthread_mutex_t _global_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+#define _lock() PTHREAD_VERIFY(pthread_mutex_lock(&_global_mutex))
+#define _unlock() PTHREAD_VERIFY(pthread_mutex_unlock(&_global_mutex))
+
+static enum _io_thread_status _status_load(enum _io_thread_status *status)
+{
+ enum _io_thread_status result;
+ _lock();
+ result = *status;
+ _unlock();
+ return result;
+}
+
+static enum _io_thread_status _status_exchange(enum _io_thread_status *obj, enum _io_thread_status desired)
+{
+ enum _io_thread_status result;
+ _lock();
+ result = *obj;
+ *obj = desired;
+ _unlock();
+ return result;
+}
+
+# endif
+
+void *io_thread_create(struct io_thread *self, void *parent, void *(*start_routine)(void *), Display *dpy, unsigned stacksize)
+{
+ if(threads_available(dpy) >= 0)
+ {
+ int error;
+ pthread_attr_t attr;
+ pthread_attr_t *attr_ptr = NULL;
+
+ if(stacksize)
+ {
+ attr_ptr = &attr;
+ if(pthread_attr_init(&attr))
+ return NULL;
+# if defined _POSIX_SOURCE || defined _POSIX_C_SOURCE || defined _XOPEN_SOURCE
+ /* PTHREAD_STACK_MIN needs the above test. */
+ assert(stacksize >= PTHREAD_STACK_MIN);
+# endif
+ PTHREAD_VERIFY(pthread_attr_setstacksize(&attr, stacksize));
+ }
+
+ /* This doesn't need to be an atomic store, since pthread_create(3)
+ "synchronizes memory with respect to other threads".
+ http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_11 */
+ self->status = _io_thread_working;
+
+ error = pthread_create(&self->thread, attr_ptr, start_routine, parent);
+ assert(!error || error == EAGAIN);
+ if(error)
+ parent = NULL;
+
+ if(attr_ptr)
+ PTHREAD_VERIFY(pthread_attr_destroy(attr_ptr));
+
+ return parent;
+ }
+
+ return NULL;
+}
+
+int io_thread_return(struct io_thread *self)
+{
+ if(_has_pthread >= 0)
+ {
+ enum _io_thread_status old_status = _status_exchange(&self->status, _io_thread_done);
+ assert(old_status == _io_thread_working ||
+ old_status == _io_thread_cancelled);
+ return old_status != _io_thread_working;
+ }
+
+ return 0;
+}
+
+int io_thread_is_done(struct io_thread *self)
+{
+ if(_has_pthread >= 0)
+ {
+ int result = _status_load(&self->status);
+ assert(result != _io_thread_cancelled);
+ return result;
+ }
+ return 1;
+}
+
+int io_thread_cancel(struct io_thread *self)
+{
+ if(_has_pthread >= 0)
+ {
+ enum _io_thread_status old_status =
+ _status_exchange(&self->status, _io_thread_cancelled);
+ assert(old_status == _io_thread_working ||
+ old_status == _io_thread_done);
+
+ PTHREAD_VERIFY(pthread_detach(self->thread));
+ return old_status != _io_thread_working;
+ }
+
+ return 0;
+}
+
+void io_thread_finish(struct io_thread *self)
+{
+ if(_has_pthread >= 0)
+ {
+# ifndef NDEBUG
+ enum _io_thread_status status = _status_load(&self->status);
+ assert(status == _io_thread_working ||
+ status == _io_thread_done);
+# endif
+ PTHREAD_VERIFY(pthread_join(self->thread, NULL));
+ assert(_status_load(&self->status) == _io_thread_done);
+ }
+}
+
+#endif /* HAVE_PTHREAD */
diff --git a/utils/thread_util.h b/utils/thread_util.h
new file mode 100644
index 0000000..6dff8de
--- /dev/null
+++ b/utils/thread_util.h
@@ -0,0 +1,446 @@
+/* -*- mode: c; tab-width: 4; fill-column: 78 -*- */
+/* vi: set ts=4 tw=78: */
+
+/*
+thread_util.h, Copyright (c) 2014 Dave Odell <dmo2118@gmail.com>
+
+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 THREAD_UTIL_H
+#define THREAD_UTIL_H
+
+/* thread_util.h because C11 took threads.h. */
+
+/* And POSIX threads because there aren't too many systems that support C11
+ threads that don't already support POSIX threads.
+ ...Not that it would be too hard to convert from the one to the other.
+ Or to have both.
+ */
+
+/* Beware!
+ Multithreading is a great way to add insidious and catastrophic bugs to
+ a program. Make sure you understand the risks.
+
+ You may wish to become familiar with race conditions, deadlocks, mutexes,
+ condition variables, and, in lock-free code, memory ordering, cache
+ hierarchies, etc., before working with threads.
+
+ On the other hand, if a screenhack locks up or crashes, it's not the
+ end of the world: XScreenSaver won't unlock the screen if that happens.
+*/
+
+/*
+ The basic stragegy for applying threads to a CPU-hungry screenhack:
+
+ 1. Find the CPU-hungry part of the hack.
+
+ 2. Change that part so the workload can be divided into N equal-sized
+ loads, where N is the number of CPU cores in the machine.
+ (For example: with two cores, one core could render even scan lines,
+ and the other odd scan lines.)
+
+ 2a. Keeping in mind that two threads should not write to the same memory
+ at the same time. Specifically, they should not be writing to the
+ same cache line at the same time -- so align memory allocation and
+ memory accesses to the system cache line size as necessary.
+
+ 3. On screenhack_init, create a threadpool object. This creates N worker
+ threads, and each thread creates and owns a user-defined struct.
+ After creation, the threads are idle.
+
+ 4. On screenhack_frame, call threadpool_run(). Each thread simultaneously
+ wakes up, calls a function that does one of the equal-sized loads,
+ then goes back to sleep. The main thread then calls threadpool_wait(),
+ which returns once all the worker threads have finished.
+
+ Using this to implement SMP won't necessarily increase performance by
+ a factor of N (again, N is CPU cores.). Both X11 and Cocoa on OS X can
+ impose a not-insignificant amount of overhead even when simply blitting
+ full-screen XImages @ 30 FPS.
+
+ On systems with simultaneous multithreading (a.k.a. Hyper-threading),
+ performance gains may be slim to non-existant.
+ */
+
+#include "aligned_malloc.h"
+
+#if HAVE_CONFIG_H
+/* For HAVE_PTHREAD. */
+# include "config.h"
+#endif
+
+#include <stddef.h>
+
+#if HAVE_UNISTD_H
+/* For _POSIX_THREADS. */
+# include <unistd.h>
+#endif
+
+#if defined HAVE_JWXYZ
+# include "jwxyz.h"
+#else
+# include <X11/Xlib.h>
+#endif
+
+#if HAVE_PTHREAD
+int threads_available(Display *dpy);
+#else
+# define threads_available(dpy) (-1)
+#endif
+/* > 0: Threads are available. This is normally _POSIX_VERSION.
+ -1: Threads are not available.
+*/
+
+unsigned hardware_concurrency(Display *dpy);
+/* This is supposed to return the number of available CPU cores. This number
+ isn't necessarily constant: a system administrator can hotplug or
+ enable/disable CPUs on certain systems, or the system can deactivate a
+ malfunctioning core -- but these are rare.
+
+ If threads are unavailable, this function will return 1.
+
+ This function isn't fast; the result should be cached.
+*/
+
+unsigned thread_memory_alignment(Display *dpy);
+
+/* Returns the proper alignment for memory allocated by a thread that is
+ shared with other threads.
+
+ A typical CPU accesses the system RAM through a cache, and this cache is
+ divided up into cache lines - aligned chunks of memory typically 32 or 64
+ bytes in size. Cache faults cause cache lines to be populated from
+ memory. And, in a multiprocessing environment, two CPU cores can access the
+ same cache line. The consequences of this depend on the CPU model:
+
+ - x86 implements the MESI protocol [1] to maintain cache coherency between
+ CPU cores, with a serious performance penalty on both Intel [1] and AMD
+ [2]. Intel uses the term "false sharing" to describe two CPU cores
+ accessing different memory in the same cache line.
+
+ - ARM allows CPU caches to become inconsistent in this case [3]. Memory
+ fences are needed to prevent horrible non-deterministic bugs from
+ occurring. Other CPU architectures have similar behavior to one of the
+ above, depending on whether they are "strongly-orderered" (like x86), or
+ "weakly-ordered" (like ARM).
+
+ Aligning multithreaded memory accesses according to the cache line size
+ neatly sidesteps both issues.
+
+ One complication is that CPU caches are divided up into separate levels,
+ and occasionally different levels can have different cache line sizes, so
+ to be safe this function returns the largest cache line size among all
+ levels.
+
+ If multithreading is not in effect, this returns sizeof(void *), because
+ posix_memalign(3) will error out if the alignment is set to be smaller than
+ that.
+
+ [1] Intel(R) 64 and IA-32 Architectures Optimization Reference Manual
+ (Order Number: 248966-026): 2.1.5 Cache Hierarchy
+ [2] Software Optimization Guide for AMD Family 10h Processors (Publication
+ #40546): 11.3.4 Data Sharing between Caches
+ [3] http://wanderingcoder.net/2011/04/01/arm-memory-ordering/
+*/
+
+/*
+ Note: aligned_malloc uses posix_memalign(3) when available, or malloc(3)
+ otherwise. As of SUSv2 (1997), and *probably* earlier, these are guaranteed
+ to be thread-safe. C89 does not discuss threads, or thread safety;
+ non-POSIX systems, watch out!
+ http://pubs.opengroup.org/onlinepubs/7908799/xsh/threads.html
+ http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_09.html
+*/
+
+/* int thread_malloc(void **ptr, Display *dpy, unsigned size); */
+#define thread_malloc(ptr, dpy, size) \
+ (aligned_malloc((ptr), thread_memory_alignment(dpy), (size)))
+
+/*
+ This simply does a malloc aligned to thread_memory_alignment(). See
+ above. On failure, an errno is returned, usually ENOMEM.
+
+ It's possible for two malloc()'d blocks to at least partially share the
+ same cache line. When a different thread is writing to each block, then bad
+ things can happen (see thread_memory_alignment). Better malloc()
+ implementations will divide memory into pools belonging to one thread or
+ another, causing memory blocks belonging to different threads to typically
+ be located on different memory pages (see getpagesize(2)), mitigating the
+ problem in question...but there's nothing stopping threads from passing
+ memory to each other. And it's not practical for the system to align each
+ block to 64 or 128 byte boundaries -- it's not uncommon to need lots and
+ lots of 8-32 byte allocations, and the waste could become a bit excessive.
+
+ Some rules of thumb to take away from this:
+
+ 1. Use thread_alloc for memory that might be written to by a thread that
+ didn't originally allocate the object.
+
+ 2. Use thread_alloc for memory that will be handed from one thread to
+ another.
+
+ 3. Use malloc if a single thread allocates, reads from, writes to, and
+ frees the block of memory.
+
+ Oddly, I (Dave) have not seen this problem described anywhere else.
+*/
+
+#define thread_free(ptr) aligned_free(ptr)
+
+#if HAVE_PTHREAD
+# if defined _POSIX_THREADS && _POSIX_THREADS >= 0
+/*
+ See The Open Group Base Specifications Issue 7, <unistd.h>, Constants for
+ Options and Option Groups
+ http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/unistd.h.html#tag_13_77_03_02
+*/
+
+# include <pthread.h>
+
+/* Most PThread synchronization functions only fail when they are misused. */
+# if defined NDEBUG
+# define PTHREAD_VERIFY(expr) (void)(expr)
+# else
+# include <assert.h>
+# define PTHREAD_VERIFY(expr) assert(!(expr))
+# endif
+
+extern const pthread_mutex_t mutex_initializer;
+extern const pthread_cond_t cond_initializer;
+
+# else
+ /* Whatever caused HAVE_PTHREAD to be defined (configure script,
+ usually) made a mistake if this is reached. */
+ /* Maybe this should be a warning. */
+# error HAVE_PTHREAD is defined, but _POSIX_THREADS is not.
+ /* #undef HAVE_PTHREAD */
+# endif
+#endif
+
+struct threadpool
+{
+/* This is always the same as the count parameter fed to threadpool_create().
+ Here's a neat trick: if the threadpool is zeroed out with a memset, and
+ threadpool_create() is never called to create 0 threads, then
+ threadpool::count can be used to determine if the threadpool object was
+ ever initialized. */
+ unsigned count;
+
+ /* Copied from threadpool_class. No need for thread_create here, though. */
+ size_t thread_size;
+ void (*thread_run)(void *self);
+ void (*thread_destroy)(void *self);
+
+ void *serial_threads;
+
+#if HAVE_PTHREAD
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+
+ /* Number of threads waiting for the startup signal. */
+ unsigned parallel_pending;
+
+ /* Number of threads still running. During startup, this is the index of the thread currently being initialized. */
+ unsigned parallel_unfinished;
+
+ pthread_t *parallel_threads;
+#endif
+};
+
+/*
+ The threadpool_* functions manage a group of threads (naturally). Each
+ thread owns an object described by a threadpool_class. When
+ threadpool_run() is called, the specified func parameter is called on each
+ thread in parallel. Sometime after calling threadpool_run(), call
+ threadpool_wait(), which waits for each thread to return from
+ threadpool_class::run().
+
+ Note that thread 0 runs on the thread from which threadpool_run is called
+ from, so if each thread has an equal workload, then when threadpool_run
+ returns, the other threads will be finished or almost finished. Adding code
+ between threadpool_run and threadpool_wait increases the odds that
+ threadpool_wait won't actually have to wait at all -- which is nice.
+
+ If the system does not provide threads, then these functions will fake it:
+ everything will appear to work normally from the perspective of the caller,
+ but when threadpool_run() is called, the "threads" are run synchronously;
+ threadpool_wait() does nothing.
+*/
+
+struct threadpool_class
+{
+ /* Size of the thread private object. */
+ size_t size;
+
+/* Create the thread private object. Called in sequence for each thread
+ (effectively) from threadpool_create.
+ self: A pointer to size bytes of memory, allocated to hold the thread
+ object.
+ pool: The threadpool object that owns all the threads. If the threadpool
+ is nested in another struct, try GET_PARENT_OBJ.
+ id: The ID for the thread; numbering starts at zero and goes up by one
+ for each thread.
+ Return 0 on success. On failure, return a value from errno.h; this will
+ be returned from threadpool_create. */
+ int (*create)(void *self, struct threadpool *pool, unsigned id);
+
+/* Destroys the thread private object. Called in sequence (though not always
+ the same sequence as create). Warning: During shutdown, it is possible
+ for destroy() to be called while other threads are still in
+ threadpool_run(). */
+ void (*destroy)(void *self);
+};
+
+/* Returns 0 on success, on failure can return ENOMEM, or any error code from
+ threadpool_class.create. */
+int threadpool_create(struct threadpool *self, const struct threadpool_class *cls, Display *dpy, unsigned count);
+void threadpool_destroy(struct threadpool *self);
+
+void threadpool_run(struct threadpool *self, void (*func)(void *));
+void threadpool_wait(struct threadpool *self);
+
+/*
+ io_thread is meant to wrap blocking I/O operations in a one-shot worker
+ thread, with cancel semantics.
+
+ Unlike threadpool_*, io_thread will not 'fake it'; it is up to the caller
+ to figure out what to do if the system doesn't have threads. In
+ particular, the start_routine passed to io_thread_create will never be
+ called.
+
+ Clients of io_thread implement four functions:
+ - state *process_start(...);
+ Starts the worker thread.
+ - bool process_is_done(state *);
+ Returns true if the I/O operation is complete.
+ - void process_cancel(state *);
+ "Cancels" the I/O operation. The thread will continue to run, but it
+ will detach, and clean itself up upon completion.
+ - int process_finish(state *, ...)
+ Waits for the I/O operation to complete, returns results, and cleans up.
+
+ Or: /---\
+ \/ | /--> cancel
+ start -> is_done --+
+ \--> finish
+
+ These functions follow a basic pattern:
+ - start:
+ 1. Allocate a thread state object with thread_alloc. This state object
+ contains an io_thread member.
+ 2. Save parameters from the start parameters to the state object.
+ 3. Start the thread with _io_thread_create. The thread receives the state
+ object as its parameter.
+ - On the worker thread:
+ 1. Do the I/O.
+ 2. Call io_thread_return.
+ 2a. If the result != 0, free the state object.
+ - is_done:
+ 1. Just call _io_thread_is_done.
+ - cancel:
+ 1. Call io_thread_cancel.
+ 1a. If the result != 0, free the state object.
+ - finish:
+ 1. Call io_thread_finish.
+ 2. Copy results out of the state object as needed.
+ 3. Free the state object...or return it to the caller.
+
+ Incidentally, there may sometimes be asynchronous versions of blocking I/O
+ functions (struct aiocb and friends, for example); these should be
+ preferred over io_thread when performance is a concern.
+ */
+
+enum _io_thread_status
+{
+ _io_thread_working, _io_thread_done, _io_thread_cancelled
+};
+
+struct io_thread
+{
+#if HAVE_PTHREAD
+ /* Common misconception: "volatile" should be applied to atomic variables,
+ such as 'status', below. This is false, see
+ <http://stackoverflow.com/q/2484980>. */
+ enum _io_thread_status status;
+ pthread_t thread;
+#else
+ char gcc_emits_a_warning_when_the_struct_has_no_members;
+#endif
+};
+
+#if HAVE_PTHREAD
+
+void *io_thread_create(struct io_thread *self, void *parent, void *(*start_routine)(void *), Display *dpy, unsigned stacksize);
+/*
+ Create the thread, returns NULL on failure. Failure is usually due to
+ ENOMEM, or the system doesn't support threads.
+ self: The io_thread object to be initialized.
+ parent: The parameter to start_routine. The io_thread should be
+ contained within or be reachable from this.
+ start_routine: The start routine for the worker thread.
+ dpy: The X11 Display, so that '*useThreads' is honored.
+ stacksize: The stack size for the thread. Set to 0 for the system
+ default.
+ A note about stacksize: Linux, for example, uses a default of 2 MB of
+ stack per thread. Now, this memory is usually committed on the first
+ write, so lots of threads won't waste RAM, but it does mean that on a
+ 32-bit system, there's a limit of just under 1024 threads with the 2 MB
+ default due to typical address space limitations of 2 GB for userspace
+ processes. And 1024 threads might not always be enough...
+ */
+
+int io_thread_return(struct io_thread *self);
+/* Called at the end of start_routine, from above. Returns non-zero if the
+ thread has been cancelled, and cleanup needs to take place. */
+
+int io_thread_is_done(struct io_thread *self);
+/* Call from the main thread. Returns non-zero if the thread finished. */
+
+int io_thread_cancel(struct io_thread *self);
+/* Call from the main thread if the results from the worker thread are not
+ needed. This cleans up the io_thread. Returns non-zero if cleanup needs
+ to take place. */
+
+void io_thread_finish(struct io_thread *self);
+/* Call from the main thread to wait for the worker thread to finish. This
+ cleans up the io_thread. */
+
+#else
+
+#define IO_THREAD_STACK_MIN 0
+
+#define io_thread_create(self, parent, start_routine, dpy, stacksize) NULL
+#define io_thread_return(self) 0
+#define io_thread_is_done(self) 1
+#define io_thread_cancel(self) 0
+#define io_thread_finish(self)
+
+#endif
+
+#if HAVE_PTHREAD
+# define THREAD_DEFAULTS "*useThreads: True",
+# define THREAD_DEFAULTS_XLOCK "*useThreads: True\n"
+# define THREAD_OPTIONS \
+ {"-threads", ".useThreads", XrmoptionNoArg, "True"}, \
+ {"-no-threads", ".useThreads", XrmoptionNoArg, "False"},
+#else
+# define THREAD_DEFAULTS
+# define THREAD_DEFAULTS_XLOCK
+# define THREAD_OPTIONS
+#endif
+
+/*
+ If a variable 'member' is known to be a member (named 'member_name') of a
+ struct (named 'struct_name'), then this can find a pointer to the struct
+ that contains it.
+*/
+#define GET_PARENT_OBJ(struct_name, member_name, member) (struct_name *)((char *)member - offsetof(struct_name, member_name));
+
+#endif
diff --git a/utils/usleep.c b/utils/usleep.c
new file mode 100644
index 0000000..f065729
--- /dev/null
+++ b/utils/usleep.c
@@ -0,0 +1,64 @@
+/* xscreensaver, Copyright (c) 1992, 1996, 1997, 2003
+ * 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"
+#else /* !HAVE_CONFIG_H */
+# ifndef NO_SELECT
+# define HAVE_SELECT
+# endif
+#endif /* !HAVE_CONFIG_H */
+
+#ifdef __STDC__
+# include <stdlib.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if defined(VMS)
+# include <descrip.h>
+# include <stdio.h>
+# include <lib$routines.h>
+#elif defined(HAVE_SELECT)
+# include <sys/time.h> /* for struct timeval */
+#endif
+
+
+#ifdef __SCREENHACK_USLEEP_H__
+ERROR, do not include that here
+#endif
+
+extern void screenhack_usleep (unsigned long usecs); /* suppress warning */
+
+void
+screenhack_usleep (unsigned long usecs)
+{
+# if defined(VMS)
+ float seconds = ((float) usecs)/1000000.0;
+ unsigned long int statvms = lib$wait(&seconds);
+
+#elif defined(HAVE_SELECT)
+ /* usleep() doesn't exist everywhere, and select() is faster anyway. */
+ struct timeval tv;
+ tv.tv_sec = usecs / 1000000L;
+ tv.tv_usec = usecs % 1000000L;
+ (void) select (0, 0, 0, 0, &tv);
+
+#else /* !VMS && !HAVE_SELECT */
+ /* If you don't have select() or usleep(), I guess you lose...
+ Maybe you have napms() instead? Let me know. */
+ usleep (usecs);
+
+#endif /* !VMS && !HAVE_SELECT */
+}
diff --git a/utils/usleep.h b/utils/usleep.h
new file mode 100644
index 0000000..3225d66
--- /dev/null
+++ b/utils/usleep.h
@@ -0,0 +1,28 @@
+/* xscreensaver, Copyright (c) 1992, 1996 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 __SCREENHACK_USLEEP_H__
+#define __SCREENHACK_USLEEP_H__
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+extern void screenhack_usleep (unsigned long usecs);
+
+#undef usleep
+#define usleep(usecs) screenhack_usleep(usecs)
+
+#endif /* __SCREENHACK_USLEEP_H__ */
diff --git a/utils/utf8wc.c b/utils/utf8wc.c
new file mode 100644
index 0000000..c948f22
--- /dev/null
+++ b/utils/utf8wc.c
@@ -0,0 +1,928 @@
+/* xscreensaver, Copyright (c) 2014-2016 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_JWXYZ
+# include "jwxyz.h"
+#else /* !HAVE_JWXYZ */
+# include <X11/Xlib.h>
+#endif
+
+#include "utf8wc.h"
+
+
+/* "Unicode Replacement Character", displayed in lieu of invalid characters. */
+# define INVALID 0xFFFD
+
+
+/* Mask the number to be within the valid range of unicode characters.
+ */
+static unsigned long
+uc_truncate (unsigned long uc)
+{
+ uc &= 0x7FFFFFFFL; /* Unicode is 31 bits */
+ if (uc > 0x10FFFF) uc = INVALID; /* But UTF-8 is 4 bytes */
+ if (uc == 0) uc = INVALID; /* no nulls */
+
+ if (uc >= 0xD800 && uc <= 0xDFFF)
+ /* Reserved for use with UTF-16: not a real character. */
+ uc = INVALID;
+
+ return uc;
+}
+
+
+/* Parse the first UTF8 character at the front of the string.
+ Return the Unicode character, and the number of bytes read.
+ */
+long
+utf8_decode (const unsigned char *in, long length, unsigned long *unicode_ret)
+{
+ const unsigned char *start = in;
+ const unsigned char *end = in + length;
+ unsigned long uc = INVALID;
+ unsigned long min = 0;
+ unsigned char c;
+
+ if (length <= 0) goto DONE;
+
+ c = *in++;
+
+# define PREMATURE_EOF { in = end; goto DONE; }
+
+ if ((c & 0xC0) == 0x80) { /* 10xxxxxx - lonely continuation byte */
+ uc = INVALID;
+
+ } else if ((c & 0x80) == 0) { /* 0xxxxxxx - 7 bits in 1 byte */
+ uc = (c & 0x7F); /* 01111111 */
+
+ } else if ((c & 0xE0) == 0xC0) { /* 110xxxxx - 11 bits in 2 bytes */
+ if (in+1 > end) PREMATURE_EOF;
+ min = 1 << 7;
+ uc = (((c & 0x1F) << 6) | /* 00011111------ */
+ (in[0] & 0x3F)); /* 00111111 */
+ in += 1;
+
+ } else if ((c & 0xF0) == 0xE0) { /* 1110xxxx - 16 bits in 3 bytes */
+ if (in+2 > end) PREMATURE_EOF;
+ min = 1 << 11;
+ uc = (((c & 0x0F) << 12) | /* 00001111----+------- */
+ ((in[0] & 0x3F) << 6) | /* 00111111------ */
+ ((in[1] & 0x3F))); /* 00111111 */
+ in += 2;
+
+ } else if ((c & 0xF8) == 0xF0) { /* 11110xxx - 21 bits in 4 bytes */
+ if (in+3 > end) PREMATURE_EOF;
+ min = 1 << 16;
+ uc = (((c & 0x07) << 18) | /* 00000111--+-------+------- */
+ ((in[0] & 0x3F) << 12) | /* 01111111----+------- */
+ ((in[1] & 0x3F) << 6) | /* 00111111------ */
+ ((in[2] & 0x3F))); /* 00111111 */
+ in += 3;
+
+ } else if ((c & 0xFC) == 0xF8) { /* 111110xx - 26 bits in 5 bytes */
+ if (in+4 > end) PREMATURE_EOF;
+ min = 1 << 21;
+ uc = (((c & 0x03) << 24) | /* 00000011--------+-------+------- */
+ ((in[0] & 0x3F) << 18) | /* 00111111--+-------+------- */
+ ((in[1] & 0x3F) << 12) | /* 00111111----+------- */
+ ((in[2] & 0x3F) << 6) | /* 00111111------ */
+ ((in[3] & 0x3F))); /* 00111111 */
+ in += 4;
+
+ } else if ((c & 0xFE) == 0xFC) { /* 1111110x - 31 bits in 6 bytes */
+ if (in+5 > end) PREMATURE_EOF;
+ min = 1 << 26;
+ uc = (((c & 0x01) << 30) | /* 00000001------+-------+-------+------- */
+ ((in[0] & 0x3F) << 24) | /* 00111111+-------+-------+------- */
+ ((in[1] & 0x3F) << 18) | /* 00111111--+-------+------- */
+ ((in[2] & 0x3F) << 12) | /* 00111111----+------- */
+ ((in[3] & 0x3F) << 6) | /* 00111111------ */
+ ((in[4] & 0x3F))); /* 00111111 */
+ in += 5;
+ } else {
+ uc = INVALID; /* Unparsable sequence. */
+ }
+
+ DONE:
+
+ length = in - start;
+
+ /* If any of the continuation bytes didn't begin with the continuation tag,
+ the sequence is invalid; stop at the bad byte, not consuming later ones.
+ (It's easier to check this after the fact than up above.) */
+ {
+ int i;
+ for (i = 1; i < length; i++)
+ if ((start[i] & 0xC0) != 0x80) {
+ uc = INVALID;
+ length = i+1;
+ break;
+ }
+ }
+
+ if (uc < min)
+ /* A multi-byte sequence encoded a character that could have been
+ encoded with a shorter sequence, e.g., hiding ASCII inside a
+ multi-byte sequence. Something hinky's going on. Reject it. */
+ uc = INVALID;
+
+ uc = uc_truncate (uc);
+
+ if (unicode_ret)
+ *unicode_ret = uc;
+
+ return length;
+}
+
+
+/* Converts a Unicode character to a multi-byte UTF8 sequence.
+ Returns the number of bytes written.
+ */
+int
+utf8_encode (unsigned long uc, char *out, long length)
+{
+ const char *old = out;
+
+ uc = uc_truncate (uc);
+
+ if (uc < 0x80 && length >= 1) /* 7 bits in 1 byte */
+ {
+ *out++ = uc; /* 0xxxxxxx */
+ }
+ else if (uc < 0x800 && length >= 2) /* 11 bits in 2 bytes */
+ {
+ *out++ = (0xC0 | ((uc >> 6) & 0x1F)); /* 110xxxxx */
+ *out++ = (0x80 | (uc & 0x3F)); /* 10xxxxxx */
+ }
+ else if (uc < 0x10000L && length >= 3) /* 16 bits in 3 bytes */
+ {
+ *out++ = (0xE0 | ((uc >> 12) & 0x0F)); /* 1110xxxx */
+ *out++ = (0x80 | ((uc >> 6) & 0x3F)); /* 10xxxxxx */
+ *out++ = (0x80 | (uc & 0x3F)); /* 10xxxxxx */
+ }
+ else if (uc < 0x200000L && length >= 4) /* 21 bits in 4 bytes */
+ {
+ *out++ = (0xF0 | ((uc >> 18) & 0x07)); /* 11110xxx */
+ *out++ = (0x80 | ((uc >> 12) & 0x3F)); /* 10xxxxxx */
+ *out++ = (0x80 | ((uc >> 6) & 0x3F)); /* 10xxxxxx */
+ *out++ = (0x80 | (uc & 0x3F)); /* 10xxxxxx */
+ }
+ else if (uc < 0x4000000L && length >= 5) /* 26 bits in 5 bytes */
+ {
+ *out++ = (0xF8 | ((uc >> 24) & 0x03)); /* 111110xx */
+ *out++ = (0x80 | ((uc >> 18) & 0x3F)); /* 10xxxxxx */
+ *out++ = (0x80 | ((uc >> 12) & 0x3F)); /* 10xxxxxx */
+ *out++ = (0x80 | ((uc >> 6) & 0x3F)); /* 10xxxxxx */
+ *out++ = (0x80 | (uc & 0x3F)); /* 10xxxxxx */
+ }
+ else if (length >= 6) /* 31 bits in 6 bytes */
+ {
+ *out++ = (0xFC | ((uc >> 30) & 0x01)); /* 1111110x */
+ *out++ = (0x80 | ((uc >> 24) & 0x3F)); /* 10xxxxxx */
+ *out++ = (0x80 | ((uc >> 18) & 0x3F)); /* 10xxxxxx */
+ *out++ = (0x80 | ((uc >> 12) & 0x3F)); /* 10xxxxxx */
+ *out++ = (0x80 | ((uc >> 6) & 0x3F)); /* 10xxxxxx */
+ *out++ = (0x80 | (uc & 0x3F)); /* 10xxxxxx */
+ }
+
+ return (int) (out - old);
+}
+
+
+/* Converts a null-terminated UTF8 string to a null-terminated XChar2b array.
+ This only handles characters that can be represented in 16 bits, the
+ Basic Multilingual Plane. (No hieroglyphics, Elvish, Klingon or Emoji.)
+ */
+XChar2b *
+utf8_to_XChar2b (const char *string, int *length_ret)
+{
+ long in_len = strlen(string);
+ const unsigned char *in = (const unsigned char *) string;
+ const unsigned char *in_end = in + in_len;
+ XChar2b *c2b = (XChar2b *) malloc ((in_len + 1) * sizeof(*c2b));
+ XChar2b *out = c2b;
+ if (! out) return 0;
+
+ while (in < in_end)
+ {
+ unsigned long uc = 0;
+ long L = utf8_decode (in, in_end - in, &uc);
+ in += L;
+
+ /* If it can't be represented in a 16-bit XChar2b,
+ use "Unicode Replacement Character". */
+ if (uc > 0xFFFF) uc = INVALID;
+
+ out->byte1 = (uc >> 8) & 0xFF;
+ out->byte2 = uc & 0xFF;
+ out++;
+ }
+
+ out->byte1 = 0;
+ out->byte2 = 0;
+
+ if (length_ret)
+ *length_ret = (int) (out - c2b);
+
+ /* shrink */
+ c2b = (XChar2b *) realloc (c2b, (out - c2b + 1) * sizeof(*c2b));
+
+ return c2b;
+}
+
+
+/* Split a UTF8 string into an array of strings, one per character.
+ The sub-strings will be null terminated and may be multiple bytes.
+ */
+char **
+utf8_split (const char *string, int *length_ret)
+{
+ const unsigned char *in = (const unsigned char *) string;
+ long len = strlen (string);
+ const unsigned char *end = in + len;
+ char **ret = (char **) malloc ((len+1) * sizeof(*ret));
+ int i = 0;
+ int zwjp = 0;
+ if (!ret) return 0;
+
+ while (in < end)
+ {
+ unsigned long uc;
+ long len2 = utf8_decode (in, len, &uc);
+ char tmp[10];
+ strncpy (tmp, (char *) in, len2);
+ tmp[len2] = 0;
+ ret[i++] = strdup (tmp);
+ in += len2;
+
+ /* If this is a Combining Diacritical, append it to the previous
+ character. E.g., "y\314\206\314\206" is one string, not three.
+
+ If this is ZWJ, Zero Width Joiner, then we append both this character
+ and the following character, e.g. "X ZWJ Y" is one string not three.
+
+ #### Hmmm, should this also include every character in the
+ "Symbol, Modifier" category, or does ZWJ get used for those?
+ https://www.fileformat.info/info/unicode/category/Sk/list.htm
+
+ Is it intended that "Latin small letter C, 0063" + "Cedilla, 00B8"
+ should be a single glyph? Or is that what "Combining Cedilla, 0327"
+ is for? I'm confused by the fact that the skin tones (1F3FB-1F3FF)
+ do not seem to be in a readily-identifiable block the way the various
+ combining diacriticals are.
+ */
+ if (i > 1 &&
+ ((uc >= 0x300 && uc <= 0x36F) || /* Combining Diacritical */
+ (uc >= 0x1AB0 && uc <= 0x1AFF) || /* Combining Diacritical Ext. */
+ (uc >= 0x1DC0 && uc <= 0x1DFF) || /* Combining Diacritical Supp. */
+ (uc >= 0x20D0 && uc <= 0x20FF) || /* Combining Diacritical Sym. */
+ (uc >= 0xFE20 && uc <= 0xFE2F) || /* Combining Half Marks */
+ (uc >= 0x1F3FB && uc <= 0x1F3FF) || /* Emoji skin tone modifiers */
+ zwjp || uc == 0x200D)) /* Zero Width Joiner */
+ {
+ 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);
+ s2[L1 + L2] = 0;
+ free (ret[i-2]);
+ ret[i-2] = s2;
+ i--;
+ zwjp = (uc == 0x200D); /* Swallow the next character as well */
+ }
+ }
+ ret[i] = 0;
+
+ if (length_ret)
+ *length_ret = i;
+
+ /* shrink */
+ ret = (char **) realloc (ret, (i+1) * sizeof(*ret));
+
+ return ret;
+}
+
+
+/* Converts a null-terminated XChar2b array to a null-terminated UTF8 string.
+ */
+char *
+XChar2b_to_utf8 (const XChar2b *in, int *length_ret)
+{
+ int in_len = 0;
+ const XChar2b *in_end;
+ int out_len;
+ char *utf8, *out;
+ const char *out_end;
+
+ /* Find the null termination on the XChar2b. */
+ for (in_end = in; in_end->byte1 || in_end->byte2; in_end++, in_len++)
+ ;
+
+ out_len = (in_len + 1) * 3; /* 16 bit chars = 3 bytes max */
+ utf8 = out = (char *) malloc (out_len + 1);
+ if (! out) return 0;
+ out_end = out + out_len;
+
+ while (in < in_end)
+ {
+ unsigned long uc = (in->byte1 << 8) | in->byte2;
+ int wrote = utf8_encode (uc, out, out_end - out);
+ if (wrote > 3) abort(); /* Can't happen with 16 bit input */
+ out += wrote;
+ in++;
+ }
+ *out = 0;
+
+ out_len = (int) (out - utf8 + 1);
+
+ if (length_ret)
+ *length_ret = out_len;
+
+ /* shrink */
+ utf8 = (char *) realloc (utf8, out_len);
+
+ return utf8;
+}
+
+
+/* Converts a UTF8 string to the closest Latin1 or ASCII equivalent.
+ */
+char *
+utf8_to_latin1 (const char *string, Bool ascii_p)
+{
+ long in_len = strlen(string);
+ const unsigned char *in = (const unsigned char *) string;
+ const unsigned char *in_end = in + in_len;
+ unsigned char *ret = (unsigned char *) malloc (in_len + 1);
+ unsigned char *out = ret;
+
+ if (! ret) return 0;
+
+ while (in < in_end)
+ {
+ unsigned long uc = 0;
+ long len2 = utf8_decode (in, in_end - in, &uc);
+ in += len2;
+
+ if (uc == '\240') /* &nbsp; */
+ uc = ' ';
+ else if (uc >= 0x300 && uc <= 0x36F)
+ uc = 0; /* Discard "Combining Diacritical Marks" */
+ else if (uc >= 0x1AB0 && uc <= 0x1AFF)
+ uc = 0; /* Discard "Combining Diacritical Marks Extended" */
+ else if (uc >= 0x1DC0 && uc <= 0x1DFF)
+ uc = 0; /* Discard "Combining Diacritical Marks Supplement" */
+ else if (uc >= 0x20D0 && uc <= 0x20FF)
+ uc = 0; /* Discard "Combining Diacritical Marks for Symbols" */
+ else if (uc >= 0xFE20 && uc <= 0xFE2F)
+ uc = 0; /* Discard "Combining Half Marks" */
+
+ else if (uc > 0xFF)
+ switch (uc) {
+
+ /* Map "Unicode General Punctuation Block" to Latin1 equivalents. */
+
+ case 0x2000: /* EN QUAD */
+ case 0x2001: /* EM QUAD */
+ case 0x2002: /* EN SPACE */
+ case 0x2003: /* EM SPACE */
+ case 0x2004: /* THREE-PER-EM SPACE */
+ case 0x2005: /* FOUR-PER-EM SPACE */
+ case 0x2006: /* SIX-PER-EM SPACE */
+ case 0x2007: /* FIGURE SPACE */
+ case 0x2008: /* PUNCTUATION SPACE */
+ case 0x2009: /* THIN SPACE */
+ case 0x200A: /* HAIR SPACE */
+ uc = ' ';
+ break;
+
+ case 0x2010: /* HYPHEN */
+ case 0x2011: /* NON-BREAKING HYPHEN */
+ case 0x2012: /* FIGURE DASH */
+ case 0x2013: /* EN DASH */
+ case 0x2014: /* EM DASH */
+ case 0x2015: /* HORIZONTAL BAR */
+ uc = '-';
+ break;
+
+ case 0x2018: /* LEFT SINGLE QUOTATION MARK */
+ case 0x2019: /* SINGLE LOW-9 QUOTATION MARK */
+ case 0x201A: /* SINGLE LOW-9 QUOTATION MARK */
+ case 0x201B: /* SINGLE HIGH-REVERSED-9 QUOTATION MARK */
+ uc = '\'';
+ break;
+
+ case 0x201C: /* LEFT DOUBLE QUOTATION MARK */
+ case 0x201D: /* RIGHT DOUBLE QUOTATION MARK */
+ case 0x201E: /* DOUBLE LOW-9 QUOTATION MARK */
+ case 0x201F: /* DOUBLE HIGH-REVERSED-9 QUOTATION MARK */
+ uc = '"';
+ break;
+
+ case 0x2022: uc = '\267'; break; /* BULLET */
+ case 0x2023: uc = '\273'; break; /* TRIANGULAR BULLET */
+ case 0x2027: uc = '\267'; break; /* HYPHENATION POINT */
+ case 0x202F: uc = ' '; break; /* NARROW NO-BREAK SPACE */
+ case 0x2038: uc = '^'; break; /* CARET */
+ case 0x2039: uc = '\253'; break; /* SINGLE LEFT ANGLE QUOTATION MARK */
+ case 0x203A: uc = '\273'; break; /* SINGLE RIGHT ANGLE QUOTATION MARK*/
+ case 0x2041: uc = '^'; break; /* CARET INSERTION POINT */
+ case 0x2042: uc = '*'; break; /* ASTERISM */
+ case 0x2043: uc = '='; break; /* HYPHEN BULLET */
+ case 0x2044: uc = '/'; break; /* FRACTION SLASH */
+ case 0x204B: uc = '\266'; break; /* REVERSED PILCROW SIGN */
+ case 0x204C: uc = '\267'; break; /* BLACK LEFTWARDS BULLET */
+ case 0x204D: uc = '\267'; break; /* BLACK RIGHTWARDS BULLET */
+ case 0x204E: uc = '*'; break; /* LOW ASTERISK */
+ case 0x204F: uc = ';'; break; /* REVERSED SEMICOLON */
+ default:
+ break;
+ }
+
+ if (uc > 0xFF)
+ /* "Inverted question mark" looks enough like 0xFFFD,
+ the "Unicode Replacement Character". */
+ uc = (ascii_p ? '#' : '\277');
+
+ if (ascii_p) /* Map Latin1 to the closest ASCII versions. */
+ {
+ const unsigned char latin1_to_ascii[96] =
+ " !C##Y|S_C#<=-R_##23'uP.,1o>###?"
+ "AAAAAAECEEEEIIIIDNOOOOOx0UUUUYpS"
+ "aaaaaaeceeeeiiiionooooo/ouuuuypy";
+ if (uc >= 0xA0)
+ uc = latin1_to_ascii[uc - 0xA0];
+ }
+
+ if (uc > 0)
+ *out++ = (unsigned char) uc;
+ }
+ *out = 0;
+
+ /* shrink */
+ ret = (unsigned char *) realloc (ret, (out - ret + 1) * sizeof(*ret));
+
+ return (char *) ret;
+}
+
+
+/*************************************************************************
+
+ cd ../hacks ; make test-utf8wc
+
+ *************************************************************************/
+
+#ifdef SELFTEST
+
+/* Convert a UTF8 string to Unicode and back again.
+ */
+static char *
+split_and_join (const char *string)
+{
+ const unsigned char *in = (const unsigned char *) string;
+ int len = strlen (string);
+ const unsigned char *end = in + len;
+ unsigned long *unicode = (unsigned long *)
+ malloc((len + 1) * sizeof(*unicode));
+ int i = 0;
+ char *ret, *out, *out_end;
+
+ while (in < end)
+ {
+ long len2 = utf8_decode (in, len, &unicode[i]);
+ i++;
+ in += len2;
+ }
+ unicode[i] = 0;
+
+ i = i*6 + 1;
+ out = ret = (char *) malloc(i);
+ out_end = out + i;
+ i = 0;
+ while (unicode[i])
+ {
+ int len2 = utf8_encode (unicode[i], out, out_end - out);
+ out += len2;
+ i++;
+ }
+ *out = 0;
+ free (unicode);
+
+ return ret;
+}
+
+
+static void
+LOG (FILE *out, const char *prefix, const char *s)
+{
+ fprintf (out, "%6s: \"", prefix);
+ while (*s)
+ {
+ unsigned char c = *s;
+ if (c == '"' || c == '\\') fprintf(out, "\\%c", c);
+ else if (c < 32 || c >= 127) fprintf(out, "\\%03o", c);
+ else fprintf (out, "%c", c);
+ s++;
+ }
+ fprintf (out, "\"\n");
+}
+
+
+int
+main (int argc, char **argv)
+{
+ /* Adapted from http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt
+ */
+
+# define URC "\357\277\275" /* 0xFFFD, "Unicode Replacement Character" */
+
+ static const struct { const char *name, *in, *target, *target2; } tests[] = {
+ /* 1 Some correct UTF-8 text */
+
+ /* The Greek word 'kosme': */
+ { "1", "\316\272\341\275\271\317\203\316\274\316\265" },
+
+
+ /* 2 Boundary condition test cases */
+
+ /* 2.1 First possible sequence of a certain length */
+
+ { "2.1.1", /* 1 byte (U-00000000): */ "\000" },
+ { "2.1.2", /* 2 bytes (U-00000080): */ "\302\200" },
+ { "2.1.3", /* 3 bytes (U-00000800): */ "\340\240\200" },
+ { "2.1.4", /* 4 bytes (U-00010000): */ "\360\220\200\200", 0, URC },
+ { "2.1.5", /* 5 bytes (U-00200000): */ "\370\210\200\200\200", URC },
+ { "2.1.6", /* 6 bytes (U-04000000): */ "\374\204\200\200\200\200", URC },
+
+ /* 2.2 Last possible sequence of a certain length */
+
+ { "2.2.1", /* 1 byte (U-0000007F): */ "\177" },
+ { "2.2.2", /* 2 bytes (U-000007FF): */ "\337\277" },
+ { "2.2.3", /* 3 bytes (U-0000FFFF): */ "\357\277\277" },
+ { "2.2.4", /* 4 bytes (U-001FFFFF): */ "\367\277\277\277", URC },
+ { "2.2.5", /* 5 bytes (U-03FFFFFF): */ "\373\277\277\277\277", URC },
+ { "2.2.6", /* 6 bytes (U-7FFFFFFF): */ "\375\277\277\277\277\277", URC },
+
+ /* 2.3 Other boundary conditions */
+
+ { "2.3.1", /* U-0000D7FF = ed 9f bf = */ "\355\237\277" },
+ { "2.3.2", /* U-0000E000 = ee 80 80 = */ "\356\200\200" },
+ { "2.3.3", /* U-0000FFFD = ef bf bd = */ URC },
+ { "2.3.4", /* U-0010FFFF = f4 8f bf bf = */ "\364\217\277\277", 0, URC },
+ { "2.3.5", /* U-00110000 = f4 90 80 80 = */ "\364\220\200\200", URC },
+
+
+ /* 3 Malformed sequences */
+
+ /* 3.1 Unexpected continuation bytes */
+
+ /* Each unexpected continuation byte should be separately signalled as a
+ malformed sequence of its own. */
+
+ { "3.1.1", /* First continuation byte 0x80: */ "\200", URC },
+ { "3.1.2", /* Last continuation byte 0xbf: */ "\277", URC },
+ { "3.1.3", /* 2 continuation bytes: */ "\200\277", URC URC },
+ { "3.1.4", /* 3 continuation bytes: */ "\200\277\200", URC URC URC },
+ { "3.1.5", /* 4 continuation bytes: */ "\200\277\200\277",
+ URC URC URC URC },
+ { "3.1.6", /* 5 continuation bytes: */ "\200\277\200\277\200",
+ URC URC URC URC URC },
+ { "3.1.7", /* 6 continuation bytes: */ "\200\277\200\277\200\277",
+ URC URC URC URC URC URC },
+ { "3.1.8", /* 7 continuation bytes: */ "\200\277\200\277\200\277\200",
+ URC URC URC URC URC URC URC },
+
+ { "3.1.9", /* Sequence of all 64 possible continuation bytes (0x80-0xbf):*/
+
+ "\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217"
+ "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237"
+ "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257"
+ "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277",
+ URC URC URC URC URC URC URC URC URC URC URC URC URC URC URC URC
+ URC URC URC URC URC URC URC URC URC URC URC URC URC URC URC URC
+ URC URC URC URC URC URC URC URC URC URC URC URC URC URC URC URC
+ URC URC URC URC URC URC URC URC URC URC URC URC URC URC URC URC },
+
+ /* 3.2 Lonely start characters */
+
+ { "3.2.1", /* All 32 first bytes of 2-byte sequences (0xc0-0xdf),
+ each followed by a space character: */
+
+ "\300 \301 \302 \303 \304 \305 \306 \307 \310 \311 \312 \313 \314 "
+ "\315 \316 \317 \320 \321 \322 \323 \324 \325 \326 \327 \330 \331 "
+ "\332 \333 \334 \335 \336 \337 ",
+ URC URC URC URC URC URC URC URC URC URC URC URC URC URC URC URC
+ URC URC URC URC URC URC URC URC URC URC URC URC URC URC URC URC },
+
+ { "3.2.2", /* All 16 first bytes of 3-byte sequences (0xe0-0xef),
+ each followed by a space character: */
+ "\340 \341 \342 \343 \344 \345 \346 \347 "
+ "\350 \351 \352 \353 \354 \355 \356 \357 ",
+ URC URC URC URC URC URC URC URC URC URC URC URC URC URC URC URC },
+
+ { "3.2.3", /* All 8 first bytes of 4-byte sequences (0xf0-0xf7),
+ each followed by a space character: */
+ URC URC URC URC URC URC URC URC },
+
+ { "3.2.4", /* All 4 first bytes of 5-byte sequences (0xf8-0xfb),
+ each followed by a space character: */
+ "\370 \371 \372 \373 ",
+ URC URC URC URC },
+
+ { "3.2.5", /* All 2 first bytes of 6-byte sequences (0xfc-0xfd),
+ each followed by a space character: */
+ "\374 \375 ", URC URC },
+
+ /* 3.3 Sequences with last continuation byte missing */
+
+ /* All bytes of an incomplete sequence should be signalled as a single
+ malformed sequence, i.e., you should see only a single replacement
+ character in each of the next 10 tests. (Characters as in section 2) */
+
+ { "3.3.1", /* 2-byte sequence with last byte missing (U+0000): */
+ "\300", URC },
+ { "3.3.2", /* 3-byte sequence with last byte missing (U+0000): */
+ "\340\200", URC },
+ { "3.3.3", /* 4-byte sequence with last byte missing (U+0000): */
+ "\360\200\200", URC },
+ { "3.3.4", /* 5-byte sequence with last byte missing (U+0000): */
+ "\370\200\200\200", URC },
+ { "3.3.5", /* 6-byte sequence with last byte missing (U+0000): */
+ "\374\200\200\200\200", URC },
+ { "3.3.6", /* 2-byte sequence with last byte missing (U-000007FF): */
+ "\337", URC },
+ { "3.3.7", /* 3-byte sequence with last byte missing (U-0000FFFF): */
+ "\357\277", URC },
+ { "3.3.8", /* 4-byte sequence with last byte missing (U-001FFFFF): */
+ "\367\277\277", URC },
+ { "3.3.9", /* 5-byte sequence with last byte missing (U-03FFFFFF): */
+ "\373\277\277\277", URC },
+ { "3.3.10", /* 6-byte sequence with last byte missing (U-7FFFFFFF): */
+ "\375\277\277\277\277", URC },
+
+ /* 3.4 Concatenation of incomplete sequences */
+
+ /* All the 10 sequences of 3.3 concatenated, you should see 10 malformed
+ sequences being signalled: */
+
+ { "3.4", "\300\340\200\360\200\200\370\200\200\200\374\200\200\200\200"
+ "\337\357\277\367\277\277\373\277\277\277\375\277\277\277\277",
+ URC URC URC URC URC URC URC URC URC URC URC URC URC URC URC },
+
+ /* 3.5 Impossible bytes */
+
+ /* The following two bytes cannot appear in a correct UTF-8 string */
+
+ { "3.5.1", /* fe = */ "\376", URC },
+ { "3.5.2", /* ff = */ "\377", URC },
+ { "3.5.3", /* fe fe ff ff = */ "\376\376\377\377", URC URC URC URC },
+
+
+ /* 4 Overlong sequences */
+
+ /* 4.1 Examples of an overlong ASCII character */
+
+ { "4.1.1", /* U+002F = c0 af = */ "\300\257", URC },
+ { "4.1.2", /* U+002F = e0 80 af = */ "\340\200\257", URC },
+ { "4.1.3", /* U+002F = f0 80 80 af = */ "\360\200\200\257", URC },
+ { "4.1.4", /* U+002F = f8 80 80 80 af = */ "\370\200\200\200\257",
+ URC },
+ { "4.1.5", /* U+002F = fc 80 80 80 80 af = */ "\374\200\200\200\200\257",
+ URC },
+
+ /* 4.2 Maximum overlong sequences */
+
+ { "4.2.1", /* U-0000007F = c1 bf = */ "\301\277", URC },
+ { "4.2.2", /* U-000007FF = e0 9f bf = */ "\340\237\277", URC },
+ { "4.2.3", /* U-0000FFFF = f0 8f bf bf = */ "\360\217\277\277",
+ URC },
+ { "4.2.4", /* U-001FFFFF = f8 87 bf bf bf = */ "\370\207\277\277\277",
+ URC },
+ { "4.2.5", /* U-03FFFFFF = fc 83 bf bf bf bf = */ URC },
+
+ /* 4.3 Overlong representation of the NUL character */
+
+ { "4.3.1", /* U+0000 = c0 80 = */ "\300\200", URC },
+ { "4.3.2", /* U+0000 = e0 80 80 = */ "\340\200\200", URC },
+ { "4.3.3", /* U+0000 = f0 80 80 80 = */ "\360\200\200\200", URC },
+ { "4.3.4", /* U+0000 = f8 80 80 80 80 = */ "\370\200\200\200\200",
+ URC },
+ { "4.3.5", /* U+0000 = fc 80 80 80 80 80 = */ "\374\200\200\200\200\200",
+ URC },
+
+
+ /* 5 Illegal code positions */
+
+ /* 5.1 Single UTF-16 surrogates */
+
+ { "5.1.1", /* U+D800 = ed a0 80 = */ "\355\240\200", URC },
+ { "5.1.2", /* U+DB7F = ed ad bf = */ "\355\255\277", URC },
+ { "5.1.3", /* U+DB80 = ed ae 80 = */ "\355\256\200", URC },
+ { "5.1.4", /* U+DBFF = ed af bf = */ "\355\257\277", URC },
+ { "5.1.5", /* U+DC00 = ed b0 80 = */ "\355\260\200", URC },
+ { "5.1.6", /* U+DF80 = ed be 80 = */ "\355\276\200", URC },
+ { "5.1.7", /* U+DFFF = ed bf bf = */ "\355\277\277", URC },
+
+ /* 5.2 Paired UTF-16 surrogates */
+
+ { "5.2.1", /* U+D800 U+DC00 = ed a0 80 ed b0 80 = */ URC URC },
+ { "5.2.2", /* U+D800 U+DFFF = ed a0 80 ed bf bf = */ URC URC },
+ { "5.2.3", /* U+DB7F U+DC00 = ed ad bf ed b0 80 = */ URC URC },
+ { "5.2.4", /* U+DB7F U+DFFF = ed ad bf ed bf bf = */ URC URC },
+ { "5.2.5", /* U+DB80 U+DC00 = ed ae 80 ed b0 80 = */ URC URC },
+ { "5.2.6", /* U+DB80 U+DFFF = ed ae 80 ed bf bf = */ URC URC },
+ { "5.2.7", /* U+DBFF U+DC00 = ed af bf ed b0 80 = */ URC URC },
+ { "5.2.8", /* U+DBFF U+DFFF = ed af bf ed bf bf = */ URC URC },
+
+ /* 5.3 Other illegal code positions */
+
+ { "5.3.1", /* U+FFFE = ef bf be = */ "\357\277\276" },
+ { "5.3.2", /* U+FFFF = ef bf bf = */ "\357\277\277" },
+
+
+ /* 6 Some other junk */
+
+ { "6.0", "" },
+ { "6.1", "\001\002\003\004\005 ABC" },
+ { "6.2", /* every non-ASCII Latin1 character */
+ "\302\241\302\242\302\243\302\244\302\245\302\246\302\247\302\250"
+ "\302\251\302\252\302\253\302\254\302\255\302\256\302\257\302\260"
+ "\302\261\302\262\302\263\302\264\302\265\302\266\302\267\302\270"
+ "\302\271\302\272\302\273\302\274\302\275\302\276\302\277\303\200"
+ "\303\201\303\202\303\203\303\204\303\205\303\206\303\207\303\210"
+ "\303\211\303\212\303\213\303\214\303\215\303\216\303\217\303\220"
+ "\303\221\303\222\303\223\303\224\303\225\303\226\303\227\303\230"
+ "\303\231\303\232\303\233\303\234\303\235\303\236\303\237\303\240"
+ "\303\241\303\242\303\243\303\244\303\245\303\246\303\247\303\250"
+ "\303\251\303\252\303\253\303\254\303\255\303\256\303\257\303\260"
+ "\303\261\303\262\303\263\303\264\303\265\303\266\303\267\303\270"
+ "\303\271\303\272\303\273\303\274\303\275\303\276\303\277" },
+
+ { "6.3", /* Christmas tree */
+ "\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020"
+ "\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\040"
+ "\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057\060"
+ "\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077\100"
+ "\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117\120"
+ "\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137\140"
+ "\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157\160"
+ "\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177\200"
+ "\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220"
+ "\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240"
+ "\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260"
+ "\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300"
+ "\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320"
+ "\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340"
+ "\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360"
+ "\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377",
+
+ "\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020"
+ "\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+ " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\177"
+ URC URC URC URC URC URC URC URC URC URC URC URC URC URC URC URC URC
+ URC URC URC URC URC URC URC URC URC URC URC URC URC URC URC URC URC
+ URC URC URC URC URC URC URC URC URC URC URC URC URC URC URC URC URC
+ URC URC URC URC URC URC URC URC URC URC URC URC URC URC URC URC URC
+ URC URC URC URC URC URC URC URC URC URC URC URC URC URC URC URC URC
+ URC URC URC URC URC URC URC URC URC URC URC URC },
+ };
+
+ int i;
+ int ok = 1;
+ for (i = 0; i < sizeof(tests)/sizeof(*tests); i++)
+ {
+ const char *name = tests[i].name;
+ const char *in = tests[i].in;
+ const char *target = (tests[i].target ? tests[i].target : in);
+ const char *target2 = (tests[i].target2 ? tests[i].target2 : target);
+ char *out = split_and_join (in);
+ XChar2b *out16 = utf8_to_XChar2b (in, 0);
+ char *out2 = XChar2b_to_utf8 (out16, 0);
+ if (strcmp (out, target))
+ {
+ LOG (stderr, name, target);
+ LOG (stderr, "FAIL", out);
+ fprintf (stderr, "\n");
+ ok = 0;
+ }
+ if (strcmp (out2, target2))
+ {
+ LOG (stderr, name, target2);
+ LOG (stderr, "FAIL2", out2);
+ fprintf (stderr, "\n");
+ ok = 0;
+ }
+ free (out);
+ free (out2);
+ free (out16);
+ }
+
+ /* Check conversion from UTF8 to Latin1 and ASCII. */
+ {
+ const char *utf8 = ("son \303\256le int\303\251rieure, \303\240 "
+ "c\303\264t\303\251 de l'alc\303\264ve "
+ "ovo\303\257de, o\303\271 les b\303\273ches "
+ "se consument dans l'\303\242tre");
+ const char *latin1 = ("son \356le int\351rieure, \340 "
+ "c\364t\351 de l'alc\364ve ovo\357de, "
+ "o\371 les b\373ches se consument dans "
+ "l'\342tre");
+ const char *ascii = ("son ile interieure, a cote de l'alcove "
+ "ovoide, ou les buches se consument dans "
+ "l'atre");
+ char *latin1b = utf8_to_latin1 (utf8, False);
+ char *ascii2 = utf8_to_latin1 (utf8, True);
+ if (strcmp (latin1, latin1b))
+ {
+ LOG (stderr, "LATIN1", utf8);
+ LOG (stderr, "FAIL3", latin1b);
+ fprintf (stderr, "\n");
+ ok = 0;
+ }
+ if (strcmp (ascii, ascii2))
+ {
+ LOG (stderr, "ASCII", utf8);
+ LOG (stderr, "FAIL4", ascii2);
+ fprintf (stderr, "\n");
+ ok = 0;
+ }
+ free (latin1b);
+ free (ascii2);
+ }
+
+ /* Check de-composition of emoji that should all be treated as a unit
+ for measurement and display purposes. */
+ {
+ static const char * const tests[] = {
+
+ /* 0: "Man" */
+ " \360\237\221\250 ",
+
+ /* 1: "Blackula" = "Vampire, dark skin tone" = 1F9DB 1F3FF */
+ " \360\237\247\233\360\237\217\277 ",
+
+ /* 2: "Black male teacher" = "Man, dark skin tone, ZWJ, school" =
+ 1F468 1F3FF 200D 1F3EB
+ */
+ " \360\237\221\250\360\237\217\277\342\200\215\360\237\217\253 ",
+
+ /* 3: "Female runner" = "Runner, ZWJ, female sign" = 1F3C3 200D 2640 */
+ " \360\237\217\203\342\200\215\342\231\200 ",
+
+ /* 4: "Woman astronaut" = "Woman, ZWJ, rocket ship" = 1F3C3 200D 1F680 */
+ " \360\237\217\203\342\200\215\360\237\232\200 ",
+
+ /* 5:
+ Group of people displayed as a single glyph:
+ Woman, dark skin tone, ZWJ, 1F469 1F3FF 200D
+ Man, light skin tone, ZWJ, 1F468 1F3FB 200D
+ Boy, medium skin tone, ZWJ, 1F466 1F3FD 200D
+ Girl, dark skin tone. 1F467 1F3FF
+ */
+ " \360\237\221\251\360\237\217\277\342\200\215"
+ "\360\237\221\250\360\237\217\273\342\200\215"
+ "\360\237\221\246\360\237\217\275\342\200\215"
+ "\360\237\221\247\360\237\217\277 ",
+ };
+ int i;
+ for (i = 0; i < sizeof(tests)/sizeof(*tests); i++)
+ {
+ int L = 0;
+ char **out = utf8_split (tests[i], &L);
+ char name[100];
+ int j;
+ sprintf (name, "SPLIT %d: %d glyphs", i, L-2);
+ if (L != 3)
+ {
+ LOG (stderr, name, tests[i]);
+ ok = 0;
+ }
+ for (j = 0; j < L; j++)
+ free (out[j]);
+ free (out);
+ }
+ }
+
+ if (ok) fprintf (stderr, "OK\n");
+ return (ok == 0);
+}
+
+#endif /* SELFTEST */
diff --git a/utils/utf8wc.h b/utils/utf8wc.h
new file mode 100644
index 0000000..d91567c
--- /dev/null
+++ b/utils/utf8wc.h
@@ -0,0 +1,47 @@
+/* xscreensaver, Copyright (c) 2014-2015 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 __XSCREENSAVER_UTF8WC_H__
+#define __XSCREENSAVER_UTF8WC_H__
+
+/* Utilities for converting between UTF8 and XChar2b. */
+
+/* Converts a null-terminated UTF8 string to a null-terminated XChar2b array.
+ This only handles characters that can be represented in 16 bits, the
+ Basic Multilingual Plane. (No hieroglyphics, Elvish, Klingon or Emoji.)
+ */
+extern XChar2b * utf8_to_XChar2b (const char *, int *length_ret);
+
+/* Converts a null-terminated XChar2b array to a null-terminated UTF8 string.
+ */
+extern char * XChar2b_to_utf8 (const XChar2b *, int *length_ret);
+
+/* Split a UTF8 string into an array of strings, one per character.
+ The sub-strings will be null terminated and may be multiple bytes.
+ */
+extern char ** utf8_split (const char *string, int *length_ret);
+
+/* Converts a UTF8 string to the closest Latin1 or ASCII equivalent.
+ */
+extern char *utf8_to_latin1 (const char *string, Bool ascii_p);
+
+/* Converts a Unicode character to a multi-byte UTF8 sequence.
+ Returns the number of bytes written.
+ */
+extern int utf8_encode (unsigned long uc, char *out, long length);
+
+/* Parse the first UTF8 character at the front of the string.
+ Return the Unicode character, and the number of bytes read.
+ */
+extern long utf8_decode (const unsigned char *in, long length,
+ unsigned long *unicode_ret);
+
+#endif /* __XSCREENSAVER_UTF8WC_H__ */
diff --git a/utils/utils.h b/utils/utils.h
new file mode 100644
index 0000000..09b4da8
--- /dev/null
+++ b/utils/utils.h
@@ -0,0 +1,27 @@
+/* xscreensaver, Copyright (c) 1997-2014 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+#ifdef HAVE_JWXYZ
+# include "jwxyz.h"
+#else /* real X11 */
+# include <X11/Xlib.h>
+# include <X11/Xutil.h>
+# include <X11/Xos.h>
+#endif /* !HAVE_JWXYZ */
diff --git a/utils/version.h b/utils/version.h
new file mode 100644
index 0000000..5ad7580
--- /dev/null
+++ b/utils/version.h
@@ -0,0 +1,2 @@
+static const char screensaver_id[] =
+ "@(#)xscreensaver 5.40 (12-Aug-2018), by Jamie Zawinski (jwz@jwz.org)";
diff --git a/utils/visual-gl.c b/utils/visual-gl.c
new file mode 100644
index 0000000..c4b940b
--- /dev/null
+++ b/utils/visual-gl.c
@@ -0,0 +1,309 @@
+/* xscreensaver, Copyright (c) 1999-2018 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
+ * 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.
+ */
+
+/* This file contains code for picking the best visual for GL programs by
+ actually asking the GL library to figure it out for us. The code in
+ visual.c might do a good job of this on most systems, but not on most
+ high end 3D cards (e.g., Silicon Graphics or nVidia.)
+
+ There exists information about visuals which is available to GL, but
+ which is not available via Xlib calls. So the only way to know
+ which visual to use (other than impirically) is to actually call
+ glXChooseVisual().
+ */
+
+#include "utils.h"
+#include "visual.h"
+#include "resources.h"
+
+#ifdef HAVE_GL
+# include <GL/gl.h>
+# include <GL/glx.h>
+#endif /* HAVE_GL */
+
+extern char *progname;
+
+Visual *
+get_gl_visual (Screen *screen)
+{
+#ifdef HAVE_GL
+ Display *dpy = DisplayOfScreen (screen);
+ int screen_num = screen_number (screen);
+
+# define R GLX_RED_SIZE
+# define G GLX_GREEN_SIZE
+# define B GLX_BLUE_SIZE
+# define A GLX_ALPHA_SIZE
+# define D GLX_DEPTH_SIZE
+# define I GLX_BUFFER_SIZE
+# define DB GLX_DOUBLEBUFFER
+# define ST GLX_STENCIL_SIZE
+
+# if defined(GLX_SAMPLE_BUFFERS) /* Needs to come before GL_SAMPLE_BUFFERS */
+# define SB GLX_SAMPLE_BUFFERS
+# define SM GLX_SAMPLES
+# elif defined(GLX_SAMPLE_BUFFERS_ARB)
+# define SB GLX_SAMPLE_BUFFERS_ARB
+# define SM GLX_SAMPLES_ARB
+# elif defined(GLX_SAMPLE_BUFFERS_SGIS)
+# define SB GLX_SAMPLE_BUFFERS_SGIS
+# define SM GLX_SAMPLES_SGIS
+# elif defined(GL_SAMPLE_BUFFERS)
+# define SB GL_SAMPLE_BUFFERS
+# 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 },
+ { GLX_RGBA, R,8, G,8, B,8, A,8, D,8, DB, ST,1, SB,1, SM,6, 0 },
+ { GLX_RGBA, R,8, G,8, B,8, A,8, D,8, DB, ST,1, SB,1, SM,4, 0 },
+ { GLX_RGBA, R,8, G,8, B,8, A,8, D,8, DB, ST,1, SB,1, SM,2, 0 },
+# define SB_COUNT 4 /* #### Kludgey count of preceeding lines! */
+# endif
+ { GLX_RGBA, R,8, G,8, B,8, A,8, D,8, DB, ST,1, 0 }, /* rgba double stencil */
+ { GLX_RGBA, R,8, G,8, B,8, D,8, DB, ST,1, 0 }, /* rgb double stencil */
+ { GLX_RGBA, R,4, G,4, B,4, D,4, DB, ST,1, 0 },
+ { GLX_RGBA, R,2, G,2, B,2, D,2, DB, ST,1, 0 },
+ { GLX_RGBA, R,8, G,8, B,8, A,8, D,8, DB, 0 }, /* rgba double */
+ { GLX_RGBA, R,8, G,8, B,8, D,8, DB, 0 }, /* rgb double */
+ { GLX_RGBA, R,4, G,4, B,4, D,4, DB, 0 },
+ { GLX_RGBA, R,2, G,2, B,2, D,2, DB, 0 },
+ { GLX_RGBA, R,8, G,8, B,8, A,8, D,8, 0 }, /* rgba single */
+ { GLX_RGBA, R,8, G,8, B,8, D,8, 0 }, /* rgb single */
+ { GLX_RGBA, R,4, G,4, B,4, D,4, 0 },
+ { GLX_RGBA, R,2, G,2, B,2, D,2, 0 },
+ { I, 8, D,8, DB, 0 }, /* cmap double */
+ { I, 4, D,4, DB, 0 },
+ { I, 8, D,8, 0 }, /* cmap single */
+ { I, 4, D,4, 0 },
+ { GLX_RGBA, R,1, G,1, B,1, D,1, 0 } /* monochrome */
+ };
+
+ int i = 0;
+
+# ifdef SB
+ if (! get_boolean_resource (dpy, "multiSample", "MultiSample"))
+ i = SB_COUNT; /* skip over the multibuffer entries in 'attrs' */
+# endif /* SB */
+
+ for (; i < sizeof(attrs)/sizeof(*attrs); i++)
+ {
+ XVisualInfo *vi = glXChooseVisual (dpy, screen_num, attrs[i]);
+ if (vi)
+ {
+ Visual *v = vi->visual;
+ XFree (vi);
+ /* describe_gl_visual (stderr, screen, v, False); */
+ return v;
+ }
+ }
+#endif /* !HAVE_GL */
+
+ return 0;
+}
+
+
+void
+describe_gl_visual (FILE *f, Screen *screen, Visual *visual,
+ Bool private_cmap_p)
+{
+ describe_visual (f, screen, visual, private_cmap_p);
+
+#ifdef HAVE_GL
+ {
+ int status;
+ int value = False;
+
+ Display *dpy = DisplayOfScreen (screen);
+ XVisualInfo vi_in, *vi_out;
+ int out_count;
+
+ vi_in.screen = screen_number (screen);
+ vi_in.visualid = XVisualIDFromVisual (visual);
+ vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualIDMask),
+ &vi_in, &out_count);
+ if (! vi_out) abort ();
+
+ status = glXGetConfig (dpy, vi_out, GLX_USE_GL, &value);
+
+ if (status == GLX_NO_EXTENSION)
+ /* dpy does not support the GLX extension. */
+ return;
+
+ if (status == GLX_BAD_VISUAL || value == False)
+ /* this visual does not support GLX. */
+ return;
+
+ if (!glXGetConfig (dpy, vi_out, GLX_LEVEL, &value) &&
+ value != 0)
+ printf (" GLX level: %d\n", value);
+
+ if (!glXGetConfig (dpy, vi_out, GLX_RGBA, &value) && value)
+ {
+ int r=0, g=0, b=0, a=0;
+ glXGetConfig (dpy, vi_out, GLX_RED_SIZE, &r);
+ 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);
+
+ 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);
+ }
+ else
+ {
+ value = 0;
+ glXGetConfig (dpy, vi_out, GLX_BUFFER_SIZE, &value);
+ printf (" GLX type: indexed (%d)\n", value);
+ }
+
+# ifndef GLX_NONE_EXT /* Hooray for gratuitious name changes. */
+# define GLX_NONE_EXT GLX_NONE
+# define GLX_TRANSPARENT_TYPE_EXT GLX_TRANSPARENT_TYPE
+# define GLX_TRANSPARENT_INDEX_EXT GLX_TRANSPARENT_INDEX
+# define GLX_TRANSPARENT_INDEX_VALUE_EXT GLX_TRANSPARENT_INDEX_VALUE
+# define GLX_TRANSPARENT_RGB_EXT GLX_TRANSPARENT_RGB
+# define GLX_TRANSPARENT_RED_VALUE_EXT GLX_TRANSPARENT_RED_VALUE
+# define GLX_TRANSPARENT_GREEN_VALUE_EXT GLX_TRANSPARENT_GREEN_VALUE
+# define GLX_TRANSPARENT_BLUE_VALUE_EXT GLX_TRANSPARENT_BLUE_VALUE
+# define GLX_TRANSPARENT_ALPHA_VALUE_EXT GLX_TRANSPARENT_ALPHA_VALUE
+# endif
+
+# ifdef GLX_VISUAL_CAVEAT_EXT
+ 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" :
+ "???"));
+# else
+ printf (" 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"));
+
+ if (!glXGetConfig (dpy, vi_out, GLX_STEREO, &value) &&
+ value)
+ printf (" 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);
+
+ if (!glXGetConfig (dpy, vi_out, GLX_DEPTH_SIZE, &value))
+ printf (" GLX depth size: %d\n", value);
+
+ if (!glXGetConfig (dpy, vi_out, GLX_STENCIL_SIZE, &value) &&
+ value != 0)
+ printf (" GLX stencil size: %d\n", value);
+
+# ifdef SB /* GL_SAMPLE_BUFFERS || GLX_SAMPLE_BUFFERS_* */
+ if (!glXGetConfig (dpy, vi_out, SB, &value) &&
+ value != 0)
+ {
+ int bufs = value;
+ if (!glXGetConfig (dpy, vi_out, SM, &value))
+ printf (" GLX multisample: %d, %d\n", bufs, value);
+ }
+# endif /* GL_SAMPLE_BUFFERS || GLX_SAMPLE_BUFFERS_* */
+
+ if (!glXGetConfig (dpy, vi_out, GLX_TRANSPARENT_TYPE_EXT, &value) &&
+ value != GLX_NONE_EXT)
+ {
+ if (value == GLX_NONE_EXT)
+ printf (" 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);
+ }
+ else if (value == GLX_TRANSPARENT_RGB_EXT)
+ {
+ int r=0, g=0, b=0, a=0;
+ glXGetConfig (dpy, vi_out, GLX_TRANSPARENT_RED_VALUE_EXT, &r);
+ 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);
+ }
+ }
+ }
+#endif /* HAVE_GL */
+}
+
+
+Bool
+validate_gl_visual (FILE *out, Screen *screen, const char *window_desc,
+ Visual *visual)
+{
+#ifdef HAVE_GL
+ int status;
+ int value = False;
+
+ 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);
+ vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualIDMask),
+ &vi_in, &out_count);
+ if (! vi_out) abort ();
+
+ status = glXGetConfig (dpy, vi_out, GLX_USE_GL, &value);
+
+ id = (unsigned int) vi_out->visualid;
+ XFree ((char *) vi_out);
+
+ if (status == GLX_NO_EXTENSION)
+ {
+ fprintf (out, "%s: display \"%s\" does not support the GLX extension.\n",
+ progname, DisplayString (dpy));
+ return False;
+ }
+ else if (status == GLX_BAD_VISUAL || value == False)
+ {
+ fprintf (out,
+ "%s: %s's visual 0x%x does not support the GLX extension.\n",
+ progname, window_desc, id);
+ return False;
+ }
+ else
+ {
+ return True;
+ }
+
+#else /* !HAVE_GL */
+
+ fprintf (out, "%s: GL support was not compiled in to this program.\n",
+ progname);
+ return False;
+
+#endif /* !HAVE_GL */
+}
diff --git a/utils/visual.c b/utils/visual.c
new file mode 100644
index 0000000..c6764ba
--- /dev/null
+++ b/utils/visual.c
@@ -0,0 +1,555 @@
+/* xscreensaver, Copyright (c) 1993-2017 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
+ * 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.
+ */
+
+/* This file contains some code for intelligently picking the best visual
+ (where "best" is biased in the direction of either: high color counts;
+ or: having writable color cells...)
+ */
+
+#include "utils.h"
+#include "resources.h" /* for get_string_resource() */
+#include "visual.h"
+
+#include <string.h>
+#ifndef HAVE_ANDROID
+#include <X11/Xutil.h>
+#else
+#include "../android/android-visual.h"
+#endif
+
+extern char *progname;
+
+#ifndef isupper
+# define isupper(c) ((c) >= 'A' && (c) <= 'Z')
+#endif
+#ifndef _tolower
+# define _tolower(c) ((c) - 'A' + 'a')
+#endif
+
+
+static Visual *pick_best_visual (Screen *, Bool, Bool);
+static Visual *pick_mono_visual (Screen *);
+static Visual *pick_best_visual_of_class (Screen *, int);
+static Visual *pick_best_gl_visual (Screen *);
+
+
+#define DEFAULT_VISUAL -1
+#define BEST_VISUAL -2
+#define MONO_VISUAL -3
+#define GRAY_VISUAL -4
+#define COLOR_VISUAL -5
+#define GL_VISUAL -6
+#define SPECIFIC_VISUAL -7
+
+Visual *
+get_visual (Screen *screen, const char *string, Bool prefer_writable_cells,
+ Bool verbose_p)
+{
+ char *v = (string ? strdup(string) : 0);
+ char c, *tmp;
+ int vclass;
+ unsigned long id;
+ Visual *result = 0;
+
+ if (v)
+ for (tmp = v; *tmp; tmp++)
+ if (isupper (*tmp)) *tmp = _tolower (*tmp);
+
+ if (!v || !*v) vclass = BEST_VISUAL;
+ else if (!strcmp (v, "default")) vclass = DEFAULT_VISUAL;
+ else if (!strcmp (v, "best")) vclass = BEST_VISUAL;
+ else if (!strcmp (v, "mono")) vclass = MONO_VISUAL;
+ else if (!strcmp (v, "monochrome")) vclass = MONO_VISUAL;
+ else if (!strcmp (v, "gray")) vclass = GRAY_VISUAL;
+ else if (!strcmp (v, "grey")) vclass = GRAY_VISUAL;
+ else if (!strcmp (v, "color")) vclass = COLOR_VISUAL;
+ else if (!strcmp (v, "gl")) vclass = GL_VISUAL;
+ else if (!strcmp (v, "staticgray")) vclass = StaticGray;
+ else if (!strcmp (v, "staticcolor")) vclass = StaticColor;
+ else if (!strcmp (v, "truecolor")) vclass = TrueColor;
+ else if (!strcmp (v, "grayscale")) vclass = GrayScale;
+ else if (!strcmp (v, "greyscale")) vclass = GrayScale;
+ else if (!strcmp (v, "pseudocolor")) vclass = PseudoColor;
+ else if (!strcmp (v, "directcolor")) vclass = DirectColor;
+ else if (1 == sscanf (v, " %lu %c", &id, &c)) vclass = SPECIFIC_VISUAL;
+ else if (1 == sscanf (v, " 0x%lx %c", &id, &c)) vclass = SPECIFIC_VISUAL;
+ else
+ {
+ fprintf (stderr, "%s: unrecognized visual \"%s\".\n", progname, v);
+ vclass = DEFAULT_VISUAL;
+ }
+
+ if (vclass == DEFAULT_VISUAL)
+ result = DefaultVisualOfScreen (screen);
+ else if (vclass == BEST_VISUAL)
+ result = pick_best_visual (screen, prefer_writable_cells, False);
+ else if (vclass == MONO_VISUAL)
+ {
+ result = pick_mono_visual (screen);
+ if (!result && verbose_p)
+ fprintf (stderr, "%s: no monochrome visuals.\n", progname);
+ }
+ else if (vclass == GRAY_VISUAL)
+ {
+ if (prefer_writable_cells)
+ result = pick_best_visual_of_class (screen, GrayScale);
+ if (!result)
+ result = pick_best_visual_of_class (screen, StaticGray);
+ if (!result)
+ result = pick_best_visual_of_class (screen, GrayScale);
+ if (!result && verbose_p)
+ fprintf (stderr, "%s: no GrayScale or StaticGray visuals.\n",
+ progname);
+ }
+ else if (vclass == COLOR_VISUAL)
+ {
+ int class;
+ /* First see if the default visual will do. */
+ result = DefaultVisualOfScreen (screen);
+ class = visual_class(screen, result);
+ if (class != TrueColor &&
+ class != PseudoColor &&
+ class != DirectColor &&
+ class != StaticColor)
+ result = 0;
+ if (result && visual_depth(screen, result) <= 1)
+ result = 0;
+
+ /* Else, find the best non-default color visual */
+ if (!result)
+ result = pick_best_visual (screen, prefer_writable_cells, True);
+
+ if (!result && verbose_p)
+ fprintf (stderr, "%s: no color visuals.\n", progname);
+ }
+ else if (vclass == GL_VISUAL)
+ {
+ Visual *visual = pick_best_gl_visual (screen);
+ if (visual)
+ result = visual;
+ else if (verbose_p)
+ fprintf (stderr, "%s: no visual suitable for GL.\n", progname);
+ }
+ else if (vclass == SPECIFIC_VISUAL)
+ {
+ result = id_to_visual (screen, id);
+ if (!result && verbose_p)
+ fprintf (stderr, "%s: no visual with id 0x%x.\n", progname,
+ (unsigned int) id);
+ }
+ else
+ {
+ Visual *visual = pick_best_visual_of_class (screen, vclass);
+ if (visual)
+ result = visual;
+ else if (verbose_p)
+ fprintf (stderr, "%s: no visual of class %s.\n", progname, v);
+ }
+
+ if (v) free (v);
+ return result;
+}
+
+Visual *
+get_visual_resource (Screen *screen, char *name, char *class,
+ Bool prefer_writable_cells)
+{
+ char *string = get_string_resource (DisplayOfScreen (screen), name, class);
+ Visual *v = get_visual (screen, string, prefer_writable_cells, True);
+ if (string)
+ free(string);
+ if (v)
+ return v;
+ else
+ return DefaultVisualOfScreen (screen);
+}
+
+
+static Visual *
+pick_best_visual (Screen *screen, Bool prefer_writable_cells, Bool color_only)
+{
+ Visual *visual;
+
+ if (!prefer_writable_cells)
+ {
+ /* If we don't prefer writable cells, then the "best" visual is the one
+ on which we can allocate the largest range and number of colors.
+
+ Therefore, a TrueColor visual which is at least 16 bits deep is best.
+ (The assumption here being that a TrueColor of less than 16 bits is
+ really just a PseudoColor visual with a pre-allocated color cube.)
+
+ The next best thing is a PseudoColor visual of any type. After that
+ come the non-colormappable visuals, and non-color visuals.
+ */
+ if ((visual = pick_best_visual_of_class (screen, TrueColor)) &&
+ visual_depth (screen, visual) >= 16)
+ return visual;
+ }
+
+#define TRY_CLASS(CLASS) \
+ if ((visual = pick_best_visual_of_class (screen, CLASS)) && \
+ (!color_only || visual_depth(screen, visual) > 1)) \
+ return visual
+ TRY_CLASS(PseudoColor);
+ TRY_CLASS(TrueColor);
+ TRY_CLASS(DirectColor);
+ TRY_CLASS(StaticColor);
+ if (!color_only)
+ {
+ TRY_CLASS(GrayScale);
+ TRY_CLASS(StaticGray);
+ }
+#undef TRY_CLASS
+
+ visual = DefaultVisualOfScreen (screen);
+ if (!color_only || visual_depth(screen, visual) > 1)
+ return visual;
+ else
+ return 0;
+}
+
+static Visual *
+pick_mono_visual (Screen *screen)
+{
+ Display *dpy = DisplayOfScreen (screen);
+ XVisualInfo vi_in, *vi_out;
+ int out_count;
+
+ vi_in.depth = 1;
+ vi_in.screen = screen_number (screen);
+ vi_out = XGetVisualInfo (dpy, (VisualDepthMask | VisualScreenMask),
+ &vi_in, &out_count);
+ if (vi_out)
+ {
+ Visual *v = (out_count > 0 ? vi_out [0].visual : 0);
+ if (v && vi_out[0].depth != 1)
+ v = 0;
+ XFree ((char *) vi_out);
+ return v;
+ }
+ else
+ return 0;
+}
+
+
+static Visual *
+pick_best_visual_of_class (Screen *screen, int visual_class)
+{
+ /* The best visual of a class is the one which on which we can allocate
+ the largest range and number of colors, which means the one with the
+ greatest depth and number of cells.
+
+ (But actually, for XDaliClock, all visuals of the same class are
+ probably equivalent - either we have writable cells or we don't.)
+ */
+ Display *dpy = DisplayOfScreen (screen);
+ XVisualInfo vi_in, *vi_out;
+ int out_count;
+
+ vi_in.class = visual_class;
+ vi_in.screen = screen_number (screen);
+ vi_out = XGetVisualInfo (dpy, (VisualClassMask | VisualScreenMask),
+ &vi_in, &out_count);
+ if (vi_out)
+ {
+ /* choose the 'best' one, if multiple */
+ int i, best;
+ Visual *visual;
+/* for (i = 0, best = 0; i < out_count; i++) */
+ for (i = out_count-1, best = i; i >= 0; i--) /* go backwards */
+ /* It's better if it's deeper, or if it's the same depth with
+ more cells (does that ever happen? Well, it could...) */
+ if ((vi_out [i].depth > vi_out [best].depth) ||
+ ((vi_out [i].depth == vi_out [best].depth) &&
+ (vi_out [i].colormap_size > vi_out [best].colormap_size)))
+ best = i;
+ visual = (best < out_count ? vi_out [best].visual : 0);
+ XFree ((char *) vi_out);
+ return visual;
+ }
+ else
+ return 0;
+}
+
+static Visual *
+pick_best_gl_visual (Screen *screen)
+{
+ /* The best visual for GL is a TrueColor visual that is half as deep as
+ the screen. If such a thing doesn't exist, then TrueColor is best.
+ Failing that, the deepest available color visual is best.
+
+ Compare this function to get_gl_visual() in visual-gl.c.
+ This function tries to find the best GL visual using Xlib calls,
+ whereas that function does the same thing using GLX calls.
+ */
+ Display *dpy = DisplayOfScreen (screen);
+ XVisualInfo vi_in, *vi_out;
+ int out_count;
+ Visual *result = 0;
+
+ int ndepths = 0;
+ int *depths = XListDepths (dpy, screen_number (screen), &ndepths);
+ int screen_depth = (depths && ndepths) ? depths[ndepths - 1] : 0;
+ XFree (depths);
+
+ vi_in.class = TrueColor;
+ vi_in.screen = screen_number (screen);
+ vi_in.depth = screen_depth / 2;
+ vi_out = XGetVisualInfo (dpy, (VisualClassMask | VisualScreenMask |
+ VisualDepthMask),
+ &vi_in, &out_count);
+ if (out_count > 0)
+ result = vi_out[0].visual;
+
+ if (vi_out)
+ XFree ((char *) vi_out);
+
+ if (!result && screen_depth > 24)
+ {
+ /* If it's a 32-deep screen and we didn't find a depth-16 visual,
+ see if there's a depth-12 visual. */
+ vi_in.class = TrueColor;
+ vi_in.screen = screen_number (screen);
+ vi_in.depth = 12;
+ vi_out = XGetVisualInfo (dpy, (VisualClassMask | VisualScreenMask |
+ VisualDepthMask),
+ &vi_in, &out_count);
+ if (out_count > 0)
+ result = vi_out[0].visual;
+ }
+
+ if (!result)
+ /* No half-depth TrueColor? Ok, try for any TrueColor (the deepest.) */
+ result = pick_best_visual_of_class (screen, TrueColor);
+
+ if (!result)
+ /* No TrueColor? Ok, try for anything. */
+ result = pick_best_visual (screen, False, False);
+
+ return result;
+}
+
+
+static XVisualInfo *
+visual_info_id (Screen *screen, int id)
+{
+ Display *dpy = DisplayOfScreen (screen);
+ XVisualInfo vi_in;
+ int out_count;
+ vi_in.screen = screen_number (screen);
+ vi_in.visualid = id;
+ return XGetVisualInfo (dpy, VisualScreenMask | VisualIDMask,
+ &vi_in, &out_count);
+}
+
+static XVisualInfo *
+visual_info (Screen *screen, Visual *visual)
+{
+ XVisualInfo *vi_out = visual_info_id (screen, XVisualIDFromVisual (visual));
+ if (! vi_out) abort ();
+ return vi_out;
+}
+
+Visual *
+id_to_visual (Screen *screen, int id)
+{
+ XVisualInfo *vi_out = visual_info_id (screen, id);
+ if (vi_out)
+ {
+ Visual *v = vi_out[0].visual;
+ XFree ((char *) vi_out);
+ return v;
+ }
+ return 0;
+}
+
+int
+visual_depth (Screen *screen, Visual *visual)
+{
+ XVisualInfo *vi_out = visual_info (screen, visual);
+ int d = vi_out [0].depth;
+ XFree ((char *) vi_out);
+ return d;
+}
+
+
+/* You very probably don't want to be using this.
+ Pixmap depth doesn't refer to the depths of pixmaps, but rather, to
+ the depth of protocol-level on-the-wire pixmap data, that is, XImages.
+ To get this info, you should be looking at XImage->bits_per_pixel
+ instead. (And allocating the data for your XImage structures by
+ multiplying ximage->bytes_per_line by ximage->height.)
+
+ Still, it can be useful to know bits_per_pixel before the XImage exists.
+
+ XCreateImage calls _XGetBitsPerPixel to figure this out, but that function
+ is private to Xlib.
+
+ For some reason, _XGetBitsPerPixel tries a hard-coded list of depths if
+ it doesn't find a matching pixmap format, but I (Dave Odell) couldn't
+ find any justification for this in the X11 spec. And the XFree86 CVS
+ repository doesn't quite go back far enough to shed any light on what
+ the deal is with that.
+ http://cvsweb.xfree86.org/cvsweb/xc/lib/X11/ImUtil.c
+
+ The hard-coded list apparently was added between X11R5 and X11R6.
+ See <ftp://ftp.x.org/pub/>.
+ */
+int
+visual_pixmap_depth (Screen *screen, Visual *visual)
+{
+ Display *dpy = DisplayOfScreen (screen);
+ int vdepth = visual_depth (screen, visual);
+ int pdepth = vdepth;
+ int i, pfvc = 0;
+ XPixmapFormatValues *pfv = XListPixmapFormats (dpy, &pfvc);
+
+ /* Return the first matching depth in the pixmap formats. If there are no
+ matching pixmap formats (which shouldn't be able to happen at all) then
+ return the visual depth instead. */
+ for (i = 0; i < pfvc; i++)
+ if (pfv[i].depth == vdepth)
+ {
+ pdepth = pfv[i].bits_per_pixel;
+ break;
+ }
+ if (pfv)
+ XFree (pfv);
+ return pdepth;
+}
+
+
+int
+visual_class (Screen *screen, Visual *visual)
+{
+ XVisualInfo *vi_out = visual_info (screen, visual);
+ int c = vi_out [0].class;
+ XFree ((char *) vi_out);
+ return c;
+}
+
+Bool
+has_writable_cells (Screen *screen, Visual *visual)
+{
+ switch (visual_class (screen, visual))
+ {
+ case GrayScale: /* Mappable grays. */
+ case PseudoColor: /* Mappable colors. */
+ case DirectColor: /* Like TrueColor, but with three colormaps:
+ one each for red, green, and blue. */
+ return True;
+ case StaticGray: /* Fixed grays. */
+ case TrueColor: /* Fixed colors. */
+ case StaticColor: /* Like PseudoColor with an unmodifiable colormap. */
+ return False;
+ default:
+ abort();
+ return False;
+ }
+}
+
+void
+describe_visual (FILE *f, Screen *screen, Visual *visual, Bool private_cmap_p)
+{
+ char n[10];
+ XVisualInfo *vi_out = visual_info (screen, visual);
+ if (private_cmap_p)
+ sprintf(n, "%3d", vi_out->colormap_size);
+ else
+ strcpy(n, "default");
+
+ fprintf (f, "0x%02x (%s depth: %2d, cmap: %s)\n",
+ (unsigned int) vi_out->visualid,
+ (vi_out->class == StaticGray ? "StaticGray, " :
+ vi_out->class == StaticColor ? "StaticColor," :
+ vi_out->class == TrueColor ? "TrueColor, " :
+ vi_out->class == GrayScale ? "GrayScale, " :
+ vi_out->class == PseudoColor ? "PseudoColor," :
+ vi_out->class == DirectColor ? "DirectColor," :
+ "UNKNOWN: "),
+ vi_out->depth, n);
+ XFree ((char *) vi_out);
+}
+
+int
+screen_number (Screen *screen)
+{
+ Display *dpy = DisplayOfScreen (screen);
+ int i;
+ for (i = 0; i < ScreenCount (dpy); i++)
+ if (ScreenOfDisplay (dpy, i) == screen)
+ return i;
+ abort ();
+ return 0;
+}
+
+int
+visual_cells (Screen *screen, Visual *visual)
+{
+ XVisualInfo *vi_out = visual_info (screen, visual);
+ int c = vi_out [0].colormap_size;
+ XFree ((char *) vi_out);
+ return c;
+}
+
+Visual *
+find_similar_visual(Screen *screen, Visual *old_visual)
+{
+ Display *dpy = DisplayOfScreen (screen);
+ XVisualInfo vi_in, *vi_out;
+ Visual *result = 0;
+ int out_count;
+
+ vi_in.screen = screen_number (screen);
+ vi_in.class = visual_class (screen, old_visual);
+ vi_in.depth = visual_depth (screen, old_visual);
+
+ /* Look for a visual of the same class and depth.
+ */
+ vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualClassMask |
+ VisualDepthMask),
+ &vi_in, &out_count);
+ if (vi_out && out_count > 0)
+ result = vi_out[0].visual;
+ if (vi_out) XFree (vi_out);
+ vi_out = 0;
+
+ /* Failing that, look for a visual of the same class.
+ */
+ if (!result)
+ {
+ vi_out = XGetVisualInfo (dpy, (VisualScreenMask | VisualClassMask),
+ &vi_in, &out_count);
+ if (vi_out && out_count > 0)
+ result = vi_out[0].visual;
+ if (vi_out) XFree (vi_out);
+ vi_out = 0;
+ }
+
+ /* Failing that, return the default visual. */
+ if (!result)
+ result = DefaultVisualOfScreen (screen);
+
+ return result;
+}
+
+
+void
+visual_rgb_masks (Screen *screen, Visual *visual, unsigned long *red_mask,
+ unsigned long *green_mask, unsigned long *blue_mask)
+{
+ XVisualInfo *vi_out = visual_info (screen, visual);
+ *red_mask = vi_out->red_mask;
+ *green_mask = vi_out->green_mask;
+ *blue_mask = vi_out->blue_mask;
+ XFree ((char *) vi_out);
+}
diff --git a/utils/visual.h b/utils/visual.h
new file mode 100644
index 0000000..18ff7a6
--- /dev/null
+++ b/utils/visual.h
@@ -0,0 +1,36 @@
+/* xscreensaver, Copyright (c) 1993-2014 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
+ * 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 __VISUAL_H__
+#define __VISUAL_H__
+
+extern Visual *get_visual (Screen *, const char *name, Bool, Bool);
+extern Visual *get_visual_resource (Screen *, char *, char *, Bool);
+extern int visual_depth (Screen *, Visual *);
+extern int visual_pixmap_depth (Screen *, Visual *);
+extern int visual_class (Screen *, Visual *);
+extern int visual_cells (Screen *, Visual *);
+extern int screen_number (Screen *);
+extern Visual *find_similar_visual (Screen *, Visual *old);
+extern void describe_visual (FILE *f, Screen *, Visual *, Bool private_cmap_p);
+extern Visual *get_overlay_visual (Screen *, unsigned long *pixel_return);
+extern Bool has_writable_cells (Screen *, Visual *);
+extern Visual *id_to_visual (Screen *, int);
+extern void visual_rgb_masks (Screen *screen, Visual *visual,
+ unsigned long *red_mask,
+ unsigned long *green_mask,
+ unsigned long *blue_mask);
+
+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 *);
+
+#endif /* __VISUAL_H__ */
diff --git a/utils/vms-gtod.c b/utils/vms-gtod.c
new file mode 100644
index 0000000..7b1df5a
--- /dev/null
+++ b/utils/vms-gtod.c
@@ -0,0 +1,31 @@
+/*
+ * UNIX-style Time Functions, by pmoreau@cena.dgac.fr <Patrick MOREAU>
+ * (picked up from XVMSUTILS unix emulation routines for VMS by
+ * Trevor Taylor, Patrick Mahans and Martin P.J. Zinser)
+ *
+ * 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.
+ */
+#include <stdio.h>
+#include <signal.h>
+#include <time.h>
+#include "vms-gtod.h"
+
+/*
+ * gettimeofday(2) - Returns the current time
+ */
+
+int gettimeofday(tv)
+struct timeval *tv;
+{
+ timeb_t tmp_time;
+ ftime(&tmp_time);
+ tv->tv_sec = tmp_time.time;
+ tv->tv_usec = tmp_time.millitm * 1000;
+ return (0);
+}
diff --git a/utils/vms-gtod.h b/utils/vms-gtod.h
new file mode 100644
index 0000000..ffd6586
--- /dev/null
+++ b/utils/vms-gtod.h
@@ -0,0 +1,85 @@
+/* @(#)time.h 2.9 87/01/17 SMI; from UCB 7.1 6/4/86 */
+
+/*
+ Definitions of various structures used on UNIX for
+ time-related syscalls.
+*/
+
+/*
+ * Copyright (c) 1982, 1986 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#ifndef _VMS_GTOD_
+#define _VMS_GTOD_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Structure returned by gettimeofday(2) system call,
+ * and used in other calls.
+ */
+#ifndef __DECC
+struct timeval
+{
+ long tv_sec; /* seconds */
+ long tv_usec; /* and microseconds */
+};
+#else
+#if __DECC_VER < 50200000
+struct timeval
+{
+ long tv_sec; /* seconds */
+ long tv_usec; /* and microseconds */
+};
+#endif /* __DECC_VER */
+#endif /* __DECC */
+
+/*
+ * Operations on timevals.
+ *
+ * NB: timercmp does not work for >= or <=.
+ */
+#define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec)
+#define timercmp(tvp, uvp, cmp) \
+ ((tvp)->tv_sec cmp (uvp)->tv_sec || \
+ (tvp)->tv_sec == (uvp)->tv_sec && (tvp)->tv_usec cmp (uvp)->tv_usec)
+#define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0
+
+/*
+ * Names of the interval timers, and structure
+ * defining a timer setting.
+ */
+#define ITIMER_REAL 0
+#define ITIMER_VIRTUAL 1
+#define ITIMER_PROF 2
+
+#ifndef __DECC
+struct itimerval
+{
+ struct timeval it_interval; /* timer interval */
+ struct timeval it_value; /* current value */
+};
+#else
+#if __DECC_VER < 50200000
+struct itimerval
+{
+ struct timeval it_interval; /* timer interval */
+ struct timeval it_value; /* current value */
+};
+#endif /* __DECC_VER */
+#endif /* __DECC */
+
+#ifndef KERNEL
+#include <time.h>
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*!_VMS_GTOD_*/
+
diff --git a/utils/vms-strdup.c b/utils/vms-strdup.c
new file mode 100644
index 0000000..1afc257
--- /dev/null
+++ b/utils/vms-strdup.c
@@ -0,0 +1,25 @@
+/*
+ * strdup.c
+ *
+ * Simple version of strdup for machines without it (ie DEC Ultrix 4.2)
+ * Apparently VMS only got strdup in 1995 (v5.2...)
+ *
+ * By David Chatterton
+ * 29 July 1993
+ *
+ * You can do anything you like to this... :)
+ * I've stolen it from xpilot and added it to the xvmstuils MPJZ ;-)
+ */
+
+#if (__VMS_VER < 70000000)
+#include <stdlib.h>
+#include <string.h>
+
+char* strdup (const char* s1)
+{
+ char* s2;
+ if (s2 = (char*)malloc(strlen(s1)+1))
+ strcpy(s2,s1);
+ return s2;
+}
+#endif
diff --git a/utils/vroot.h b/utils/vroot.h
new file mode 100644
index 0000000..65097b8
--- /dev/null
+++ b/utils/vroot.h
@@ -0,0 +1,156 @@
+/* -*- Mode: C; tab-width: 2 -*- */
+/*****************************************************************************/
+/** Copyright 1991 by Andreas Stolcke **/
+/** Copyright 1990 by Solbourne Computer Inc. **/
+/** Longmont, Colorado **/
+/** **/
+/** All Rights Reserved **/
+/** **/
+/** 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 permis- **/
+/** sion notice appear in supporting documentation, and that the **/
+/** name of Solbourne not be used in advertising **/
+/** in publicity pertaining to distribution of the software without **/
+/** specific, written prior permission. **/
+/** **/
+/** ANDREAS STOLCKE AND SOLBOURNE COMPUTER INC. DISCLAIMS ALL WARRANTIES **/
+/** WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF **/
+/** MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL ANDREAS STOLCKE **/
+/** OR SOLBOURNE 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. **/
+/*****************************************************************************/
+/*
+ * vroot.h -- Virtual Root Window handling header file
+ *
+ * This header file redefines the X11 macros RootWindow and DefaultRootWindow,
+ * making them look for a virtual root window as provided by certain `virtual'
+ * window managers like swm and tvtwm. If none is found, the ordinary root
+ * window is returned, thus retaining backward compatibility with standard
+ * window managers.
+ * The function implementing the virtual root lookup remembers the result of
+ * its last invocation to avoid overhead in the case of repeated calls
+ * on the same display and screen arguments.
+ * The lookup code itself is taken from Tom LaStrange's ssetroot program.
+ *
+ * Most simple root window changing X programs can be converted to using
+ * virtual roots by just including
+ *
+ * #include <X11/vroot.h>
+ *
+ * after all the X11 header files. It has been tested on such popular
+ * X clients as xphoon, xfroot, xloadimage, and xaqua.
+ * It also works with the core clients xprop, xwininfo, xwd, and editres
+ * (and is necessary to get those clients working under tvtwm).
+ * It does NOT work with xsetroot; get the xsetroot replacement included in
+ * the tvtwm distribution instead.
+ *
+ * Andreas Stolcke <stolcke@ICSI.Berkeley.EDU>, 9/7/90
+ * - replaced all NULL's with properly cast 0's, 5/6/91
+ * - free children list (suggested by Mark Martin <mmm@cetia.fr>), 5/16/91
+ * - include X11/Xlib.h and support RootWindowOfScreen, too 9/17/91
+ *
+ * Jamie Zawinski <jwz@jwz.org>, 28-Apr-1997
+ * - use ANSI C
+ *
+ * Jamie Zawinski <jwz@jwz.org>, 3-Sep-2003
+ * - if the environment variable "XSCREENSAVER_WINDOW" is set, use that
+ * as the root window instead of searching for __SWM_VROOT.
+ *
+ * Jamie Zawinski <jwz@jwz.org>, 14-Aug-2004
+ * - changes to get gcc to stop whining about "type punning".
+ *
+ * Jamie Zawinski <jwz@jwz.org>, 16-Dec-2004
+ * - fixed that last fix.
+ */
+
+#ifndef _VROOT_H_
+#define _VROOT_H_
+#define _XSCREENSAVER_VROOT_H_
+
+#if !defined(lint) && !defined(SABER)
+static const char vroot_rcsid[] =
+ "#Id: vroot.h,v 1.8 2004/12/16 05:33:54 jwz Exp #" "\n"
+ "#Id: vroot.h,v 1.4 1991/09/30 19:23:16 stolcke Exp stolcke #";
+#endif
+
+#include <X11/X.h>
+#include <X11/Xatom.h>
+#include <X11/Xlib.h>
+
+static Window
+#ifdef __STDC__ /* ANSIfication added by jwz, to avoid superfluous warnings. */
+VirtualRootWindowOfScreen(Screen *screen)
+#else /* !__STDC__ */
+VirtualRootWindowOfScreen(screen) Screen *screen;
+#endif /* !__STDC__ */
+{
+ static Screen *save_screen = (Screen *)0;
+ static Window root = (Window)0;
+
+ if (screen != save_screen) {
+ Display *dpy = DisplayOfScreen(screen);
+ Atom __SWM_VROOT = None;
+ int i;
+ Window rootReturn, parentReturn, *children;
+ unsigned int numChildren;
+
+ /* first check for a hex or decimal window ID in the environment */
+ const char *xss_id = getenv("XSCREENSAVER_WINDOW");
+ if (xss_id && *xss_id) {
+ unsigned long id = 0;
+ char c;
+ if (1 == sscanf (xss_id, " 0x%lx %c", &id, &c) ||
+ 1 == sscanf (xss_id, " %lu %c", &id, &c)) {
+ root = (Window) id;
+ save_screen = screen;
+ return root;
+ }
+ }
+
+ root = RootWindowOfScreen(screen);
+
+ /* go look for a virtual root */
+ __SWM_VROOT = XInternAtom(dpy, "__SWM_VROOT", False);
+ if (XQueryTree(dpy, root, &rootReturn, &parentReturn,
+ &children, &numChildren)) {
+ for (i = 0; i < numChildren; i++) {
+ Atom actual_type;
+ int actual_format;
+ unsigned long nitems, bytesafter;
+ unsigned char *newRoot = 0;
+
+ if (XGetWindowProperty(dpy, children[i],
+ __SWM_VROOT, 0, 1, False, XA_WINDOW,
+ &actual_type, &actual_format,
+ &nitems, &bytesafter,
+ &newRoot) == Success
+ && newRoot) {
+ root = *((Window *) newRoot);
+ break;
+ }
+ }
+ if (children)
+ XFree((char *)children);
+ }
+
+ save_screen = screen;
+ }
+
+ return root;
+}
+
+#undef RootWindowOfScreen
+#define RootWindowOfScreen(s) VirtualRootWindowOfScreen(s)
+
+#undef RootWindow
+#define RootWindow(dpy,screen) VirtualRootWindowOfScreen(ScreenOfDisplay(dpy,screen))
+
+#undef DefaultRootWindow
+#define DefaultRootWindow(dpy) VirtualRootWindowOfScreen(DefaultScreenOfDisplay(dpy))
+
+#endif /* _VROOT_H_ */
diff --git a/utils/xdbe.c b/utils/xdbe.c
new file mode 100644
index 0000000..d62183e
--- /dev/null
+++ b/utils/xdbe.c
@@ -0,0 +1,75 @@
+/* xscreensaver, Copyright (c) 1998, 1999, 2006
+ * 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
+ * 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.
+ */
+
+/* The XDBE (Double Buffering) extension is pretty tricky to use, since you
+ can get X errors at inconvenient times during initialization. This file
+ contains a utility routine to make it easier to deal with.
+ */
+
+#include "utils.h"
+#include "xdbe.h"
+#include "resources.h" /* for get_string_resource() */
+
+/* #define DEBUG */
+
+#ifdef DEBUG
+# include <X11/Xmu/Error.h>
+#endif
+
+extern char *progname;
+
+#ifdef HAVE_DOUBLE_BUFFER_EXTENSION /* whole file */
+
+static Bool xdbe_got_x_error = False;
+static int
+xdbe_ehandler (Display *dpy, XErrorEvent *error)
+{
+ xdbe_got_x_error = True;
+
+#ifdef DEBUG
+ fprintf (stderr, "\n%s: ignoring X error from DOUBLE-BUFFER:\n", progname);
+ XmuPrintDefaultErrorMessage (dpy, error, stderr);
+ fprintf (stderr, "\n");
+#endif
+
+ return 0;
+}
+
+
+XdbeBackBuffer
+xdbe_get_backbuffer (Display *dpy, Window window,
+ XdbeSwapAction action)
+{
+ XdbeBackBuffer b;
+ XErrorHandler old_handler;
+ int maj, min;
+
+ if (!get_boolean_resource(dpy, "useDBE", "Boolean"))
+ return 0;
+
+ if (!XdbeQueryExtension (dpy, &maj, &min))
+ return 0;
+
+ XSync (dpy, False);
+ xdbe_got_x_error = False;
+ old_handler = XSetErrorHandler (xdbe_ehandler);
+ b = XdbeAllocateBackBufferName(dpy, window, XdbeUndefined);
+ XSync (dpy, False);
+ XSetErrorHandler (old_handler);
+
+ if (xdbe_got_x_error)
+ return 0;
+
+ return b;
+}
+
+#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
diff --git a/utils/xdbe.h b/utils/xdbe.h
new file mode 100644
index 0000000..26f2de8
--- /dev/null
+++ b/utils/xdbe.h
@@ -0,0 +1,27 @@
+/* xscreensaver, Copyright (c) 1998, 1999 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
+ * 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.
+ */
+
+/* The XDBE (Double Buffering) extension is pretty tricky to use, since you
+ can get X errors at inconvenient times during initialization. This file
+ contains a utility routine to make it easier to deal with.
+ */
+
+#ifndef __XSCREENSAVER_XDBE_H__
+
+#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
+
+# include <X11/extensions/Xdbe.h>
+
+extern XdbeBackBuffer xdbe_get_backbuffer (Display *, Window, XdbeSwapAction);
+
+#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
+
+#endif /* __XSCREENSAVER_XDBE_H__ */
diff --git a/utils/xft.c b/utils/xft.c
new file mode 100644
index 0000000..9245752
--- /dev/null
+++ b/utils/xft.c
@@ -0,0 +1,364 @@
+/* xscreensaver, Copyright (c) 2014-2018 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.
+ */
+
+/* Compatibility layer using XDrawString, XDrawString16() or Xutf8DrawString().
+ This layer is used by X11 systems without Xft, and by MacOS / iOS.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifndef HAVE_XFT
+
+# include "utils.h"
+# include "resources.h"
+# include "xft.h"
+# include "utf8wc.h"
+
+extern const char *progname;
+
+struct _XftDraw {
+ Display *dpy;
+ Drawable drawable;
+ GC gc;
+ unsigned long pixel;
+ Font fid;
+ Visual *visual;
+ Colormap colormap;
+};
+
+
+XftFont *
+XftFontOpenXlfd (Display *dpy, int screen, _Xconst char *xlfd)
+{
+ XftFont *ff = (XftFont *) calloc (1, sizeof(*ff));
+
+ if (!dpy || !xlfd) abort();
+ if (!ff) return 0;
+ ff->xfont = XLoadQueryFont (dpy, xlfd);
+ if (!ff->xfont)
+ {
+ free (ff);
+ return 0;
+ }
+
+ ff->name = strdup (xlfd);
+ ff->ascent = ff->xfont->ascent;
+ ff->descent = ff->xfont->descent;
+ ff->height = ff->ascent + ff->descent;
+
+# ifdef HAVE_XUTF8DRAWSTRING
+ {
+ 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.
+ char *xlfd_resolved = NULL;
+
+ char **missing_charset_list_return;
+ int missing_charset_count_return;
+ char *def_string_return;
+
+ char *ss;
+
+ for (i = 0; i != ff->xfont->n_properties; ++i) {
+ if (ff->xfont->properties[i].name == XA_FONT) {
+ xlfd_resolved = XGetAtomName (dpy, ff->xfont->properties[i].card32);
+ if (xlfd_resolved)
+ xlfd = xlfd_resolved;
+ break;
+ }
+ }
+
+ ss = (char *) malloc (strlen(xlfd) + 10);
+ strcpy (ss, xlfd);
+ strcat (ss, ",*");
+ ff->fontset = XCreateFontSet (dpy, ss,
+ &missing_charset_list_return,
+ &missing_charset_count_return,
+ &def_string_return);
+
+# if 0
+ {
+ int i;
+ for (i = 0; i < missing_charset_count_return; i++)
+ fprintf (stderr, "%s: missing charset: %s\n",
+ ss, missing_charset_list_return[i]);
+ }
+# endif
+
+ /* Apparently this is not to be freed. */
+ /* if (def_string_return) XFree (def_string_return); */
+
+ if (missing_charset_list_return)
+ XFreeStringList (missing_charset_list_return);
+
+ free (ss);
+ free (xlfd_resolved);
+ }
+# endif
+
+ return ff;
+}
+
+
+void
+XftFontClose (Display *dpy, XftFont *font)
+{
+ if (!dpy || !font) abort();
+ free (font->name);
+ XFreeFont (dpy, font->xfont);
+# ifdef HAVE_XUTF8DRAWSTRING
+ XFreeFontSet (dpy, font->fontset);
+# endif
+ free (font);
+}
+
+
+Bool
+XftColorAllocName (Display *dpy,
+ _Xconst Visual *visual,
+ Colormap cmap,
+ _Xconst char *name,
+ XftColor *result)
+{
+ XColor color;
+ if (!dpy || !visual || !name || !result) abort();
+
+ if (! XParseColor (dpy, cmap, name, &color))
+ {
+ fprintf (stderr, "%s: can't parse color %s", progname, name);
+ return False;
+ }
+ else if (! XAllocColor (dpy, cmap, &color))
+ {
+ fprintf (stderr, "%s: couldn't allocate color %s", progname, name);
+ return False;
+ }
+ else
+ {
+ XRenderColor color2;
+ color2.red = color.red;
+ color2.green = color.green;
+ color2.blue = color.blue;
+ color2.alpha = 0xFFFF;
+ XftColorAllocValue (dpy, visual, cmap, &color2, result);
+ result->pixel = color.pixel;
+ return True;
+ }
+}
+
+
+static short
+maskbase (unsigned long m)
+{
+ short i;
+ if (!m)
+ return 0;
+ i = 0;
+ while (! (m&1))
+ {
+ m >>= 1;
+ i++;
+ }
+ return i;
+}
+
+
+static short
+masklen (unsigned long m)
+{
+ unsigned long y;
+ y = (m >> 1) & 033333333333;
+ y = m - y - ((y >>1) & 033333333333);
+ return (short) (((y + (y >> 3)) & 030707070707) % 077);
+}
+
+
+Bool
+XftColorAllocValue (Display *dpy,
+ _Xconst Visual *visual,
+ Colormap cmap,
+ _Xconst XRenderColor *color,
+ XftColor *result)
+{
+ if (!dpy || !visual || !color || !result) abort();
+ if (visual->class == TrueColor)
+ {
+ int red_shift = maskbase (visual->red_mask);
+ int red_len = masklen (visual->red_mask);
+ int green_shift = maskbase (visual->green_mask);
+ int green_len = masklen (visual->green_mask);
+ int blue_shift = maskbase (visual->blue_mask);
+ int blue_len = masklen (visual->blue_mask);
+ result->pixel = (((color->red >> (16 - red_len)) << red_shift) |
+ ((color->green >> (16 - green_len)) << green_shift) |
+ ((color->blue >> (16 - blue_len)) << blue_shift));
+# ifdef HAVE_JWXYZ
+ result->pixel |= BlackPixel(dpy, 0); /* alpha */
+# endif
+ }
+ else
+ {
+ XColor xcolor;
+ xcolor.red = color->red;
+ xcolor.green = color->green;
+ xcolor.blue = color->blue;
+ if (!XAllocColor (dpy, cmap, &xcolor))
+ return False;
+ result->pixel = xcolor.pixel;
+ }
+ result->color.red = color->red;
+ result->color.green = color->green;
+ result->color.blue = color->blue;
+ result->color.alpha = color->alpha;
+ return True;
+}
+
+
+void
+XftColorFree (Display *dpy,
+ Visual *visual,
+ Colormap cmap,
+ XftColor *color)
+{
+ if (!dpy || !visual || !color) abort();
+ if (visual->class != TrueColor)
+ XFreeColors (dpy, cmap, &color->pixel, 1, 0);
+}
+
+
+XftDraw *
+XftDrawCreate (Display *dpy,
+ Drawable drawable,
+ Visual *visual,
+ Colormap colormap)
+{
+ XftDraw *dd = (XftDraw *) calloc (1, sizeof(*dd));
+ if (!dpy || !drawable || !visual) abort();
+ if (!dd) return 0;
+
+ dd->dpy = dpy;
+ dd->drawable = drawable;
+ dd->visual = visual;
+ dd->colormap = colormap;
+ dd->gc = XCreateGC (dpy, drawable, 0, 0);
+ return dd;
+}
+
+
+void
+XftDrawDestroy (XftDraw *draw)
+{
+ if (!draw) abort();
+ XFreeGC (draw->dpy, draw->gc);
+ free (draw);
+}
+
+
+void
+XftTextExtentsUtf8 (Display *dpy,
+ XftFont *font,
+ _Xconst FcChar8 *string,
+ int len,
+ XGlyphInfo *extents)
+{
+ XCharStruct overall;
+
+ if (!dpy || !font || !string || !extents) abort();
+
+# ifdef HAVE_XUTF8DRAWSTRING
+ {
+ XRectangle ink;
+ int advancement =
+ Xutf8TextExtents (font->fontset, (const char *) string, len, &ink, 0);
+ XmbRectangle_to_XCharStruct (ink, overall, advancement);
+ }
+# else /* !HAVE_XUTF8DRAWSTRING */
+ {
+ char *s2 = (char *) malloc (len + 1);
+ int direction, ascent, descent;
+ XChar2b *s16;
+ int s16_len = 0;
+ strncpy (s2, (char *) string, len);
+ s2[len] = 0;
+ s16 = utf8_to_XChar2b (s2, &s16_len);
+ XTextExtents16 (font->xfont, s16, s16_len,
+ &direction, &ascent, &descent, &overall);
+ free (s2);
+ free (s16);
+ }
+# endif /* !HAVE_XUTF8DRAWSTRING */
+
+ XCharStruct_to_XGlyphInfo (overall, *extents);
+}
+
+
+void
+XftDrawStringUtf8 (XftDraw *draw,
+ _Xconst XftColor *color,
+ XftFont *font,
+ int x,
+ int y,
+ _Xconst FcChar8 *string,
+ int len)
+{
+ if (!draw || !color || !font || !string) abort();
+
+ if (color->pixel != draw->pixel)
+ {
+ XSetForeground (draw->dpy, draw->gc, color->pixel);
+ draw->pixel = color->pixel;
+ }
+ if (font->xfont->fid != draw->fid)
+ {
+ XSetFont (draw->dpy, draw->gc, font->xfont->fid);
+ draw->fid = font->xfont->fid;
+ }
+
+# ifdef HAVE_XUTF8DRAWSTRING
+ /* If we have Xutf8DrawString, use it instead of XDrawString16 because
+ there is some chance it will handle characters of more than 16 bits
+ (beyond the Basic Multilingual Plane).
+ */
+
+ /* #### I guess I don't really understand how FontSet works, because when
+ using the real X11 implementation of Xutf8DrawString, this seems
+ to just truncate the text at the first non-ASCII character.
+
+ The XDrawString16() path works, however, at the expense of losing
+ everything above Basic Multilingual. However, that path is only
+ taken on X11 systems that are old enough to not have libXft,
+ which means that the chance of Unicode working was already slim.
+ */
+ Xutf8DrawString (draw->dpy, draw->drawable, font->fontset, draw->gc, x, y,
+ (const char *) string, len);
+# else
+ {
+ int s16_len = 0;
+ char *s2 = (char *) malloc (len + 1);
+ XChar2b *s16;
+ strncpy (s2, (char *) string, len);
+ s2[len] = 0;
+ s16 = utf8_to_XChar2b (s2, &s16_len);
+ free (s2);
+ XDrawString16 (draw->dpy, draw->drawable, draw->gc, x, y, s16, s16_len);
+ free (s16);
+ }
+# endif
+}
+
+#else /* HAVE_XFT */
+
+const int Wempty_translation_unit_is_a_dumb_warning = 0;
+
+#endif /* HAVE_XFT */
diff --git a/utils/xft.h b/utils/xft.h
new file mode 100644
index 0000000..385e28b
--- /dev/null
+++ b/utils/xft.h
@@ -0,0 +1,167 @@
+/* xscreensaver, Copyright (c) 2014-2015 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.
+ */
+
+/* Compatibility layer using XDrawString, XDrawString16() or Xutf8DrawString().
+ This layer is used by X11 systems without Xft, and by MacOS / iOS.
+ */
+
+#ifndef __XSCREENSAVER_XFT_H__
+#define __XSCREENSAVER_XFT_H__
+
+/* The XGlyphInfo field names and values are, of course, arbitrarily
+ different from XCharStruct for no sensible reason. These macros
+ translate between them.
+ */
+
+# define XGlyphInfo_to_XCharStruct(G,C) do { \
+ (C).lbearing = -(G).x; \
+ (C).rbearing = (G).width - (G).x; \
+ (C).ascent = (G).y; \
+ (C).descent = (G).height - (G).y; \
+ (C).width = (G).xOff; \
+} while (0)
+
+# define XCharStruct_to_XGlyphInfo(C,G) do { \
+ (G).x = -(C).lbearing; \
+ (G).y = (C).ascent; \
+ (G).xOff = (C).width; \
+ (G).yOff = 0; \
+ (G).width = (C).rbearing - (C).lbearing; \
+ (G).height = (C).ascent + (C).descent; \
+} while (0)
+
+/* Xutf8TextExtents returns a bounding box in an XRectangle, which
+ conveniently interprets everything in the opposite direction
+ from XGlyphInfo!
+ */
+# define XCharStruct_to_XmbRectangle(C,R) do { \
+ (R).x = (C).lbearing; \
+ (R).y = -(C).ascent; \
+ (R).width = (C).rbearing - (C).lbearing; \
+ (R).height = (C).ascent + (C).descent; \
+} while (0)
+
+# define XmbRectangle_to_XCharStruct(R,C,ADV) do { \
+ (C).lbearing = (R).x; \
+ (C).rbearing = (R).width + (R).x; \
+ (C).ascent = -(R).y; \
+ (C).descent = (R).height + (R).y; \
+ (C).width = (ADV); \
+} while (0)
+
+
+# ifdef HAVE_XFT
+
+# include <X11/Xft/Xft.h>
+
+# else /* !HAVE_XFT -- the rest of the file */
+
+# ifdef HAVE_COCOA
+# include "jwxyz.h"
+#elif defined(HAVE_ANDROID)
+# include "jwxyz.h"
+# else
+# include <X11/Xlib.h>
+# endif
+
+/* This doesn't seem to work right under X11. See comment in xft.c. */
+# ifndef HAVE_COCOA
+# undef HAVE_XUTF8DRAWSTRING
+# endif
+
+
+# ifndef _Xconst
+# define _Xconst const
+# endif
+
+typedef struct _XGlyphInfo {
+ unsigned short width, height; /* bounding box of the ink */
+ short x, y; /* distance from upper left of bbox to glyph origin. */
+ short xOff, yOff; /* distance from glyph origin to next origin. */
+} XGlyphInfo;
+
+
+typedef struct _XftFont {
+ XFontStruct *xfont;
+# ifdef HAVE_XUTF8DRAWSTRING
+ XFontSet fontset;
+# endif
+ char *name;
+ int ascent;
+ int descent;
+ int height;
+} XftFont;
+
+typedef struct {
+ unsigned short red;
+ unsigned short green;
+ unsigned short blue;
+ unsigned short alpha;
+} XRenderColor;
+
+typedef struct _XftColor {
+ unsigned long pixel;
+ XRenderColor color;
+} XftColor;
+
+typedef struct _XftDraw XftDraw;
+
+typedef unsigned char FcChar8;
+
+
+XftFont *XftFontOpenXlfd (Display *dpy, int screen, _Xconst char *xlfd);
+#define XftFontOpenName XftFontOpenXlfd
+
+void XftFontClose (Display *dpy, XftFont *font);
+
+Bool XftColorAllocName (Display *dpy,
+ _Xconst Visual *visual,
+ Colormap cmap,
+ _Xconst char *name,
+ XftColor *result);
+
+Bool XftColorAllocValue (Display *dpy,
+ _Xconst Visual *visual,
+ Colormap cmap,
+ _Xconst XRenderColor *color,
+ XftColor *result);
+
+void XftColorFree (Display *dpy,
+ Visual *visual,
+ Colormap cmap,
+ XftColor *color);
+
+XftDraw *XftDrawCreate (Display *dpy,
+ Drawable drawable,
+ Visual *visual,
+ Colormap colormap);
+
+void XftDrawDestroy (XftDraw *draw);
+
+void
+XftTextExtentsUtf8 (Display *dpy,
+ XftFont *pub,
+ _Xconst FcChar8 *string,
+ int len,
+ XGlyphInfo *extents);
+
+void
+XftDrawStringUtf8 (XftDraw *draw,
+ _Xconst XftColor *color,
+ XftFont *pub,
+ int x,
+ int y,
+ _Xconst FcChar8 *string,
+ int len);
+
+# endif /* !HAVE_XFT */
+
+#endif /* __XSCREENSAVER_XFT_H__ */
diff --git a/utils/xmu.c b/utils/xmu.c
new file mode 100644
index 0000000..2f273d4
--- /dev/null
+++ b/utils/xmu.c
@@ -0,0 +1,173 @@
+/* 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.
+ */
+
+#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 "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 */
+
+/*
+ * 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)
+{
+ 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;
+}
+
+#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
new file mode 100644
index 0000000..48084f7
--- /dev/null
+++ b/utils/xmu.h
@@ -0,0 +1,14 @@
+/* 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.
+ */
+
+#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/xscreensaver-intl.h b/utils/xscreensaver-intl.h
new file mode 100644
index 0000000..50c6414
--- /dev/null
+++ b/utils/xscreensaver-intl.h
@@ -0,0 +1,36 @@
+/* xscreensaver, Copyright (c) 2002 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 __XSCREENSAVER_INTL_H__
+#define __XSCREENSAVER_INTL_H__
+
+#ifdef ENABLE_NLS
+# include <libintl.h>
+# define _(String) dgettext(GETTEXT_PACKAGE,(String))
+# ifdef gettext_noop
+# define N_(String) gettext_noop((String))
+# else /* !gettext_noop */
+# define N_(String) (String)
+# endif /* !gettext_noop */
+
+#else /* !ENABLE_NLS */
+
+# define _(String) (String)
+# define N_(String) (String)
+# define textdomain(String) (String)
+# define gettext(String) (String)
+# define dgettext(Domain,String) (String)
+# define dcgettext(Domain,String,Type) (String)
+# define bindtextdomain(Domain,Directory) (Domain)
+
+#endif /* !ENABLE_NLS */
+
+#endif /* __XSCREENSAVER_INTL_H__ */
diff --git a/utils/xshm.c b/utils/xshm.c
new file mode 100644
index 0000000..8992140
--- /dev/null
+++ b/utils/xshm.c
@@ -0,0 +1,340 @@
+/* xscreensaver, Copyright (c) 1993-2017 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.
+ */
+
+/* The MIT-SHM (Shared Memory) extension is pretty tricky to use.
+ This file contains the common boiler-plate for creating a shared
+ XImage structure, and for making sure that the shared memory segments
+ get allocated and shut down cleanly.
+
+ This code currently deals only with shared XImages, not with shared Pixmaps.
+ It also doesn't use "completion events", but so far that doesn't seem to
+ be a problem (and I'm not entirely clear on when they would actually be
+ needed, anyway.)
+
+ If you don't have man pages for this extension, see
+ https://www.x.org/releases/current/doc/xextproto/shm.html
+
+ (This document seems not to ever remain available on the web in one place
+ for very long; you can search for it by the title, "MIT-SHM -- The MIT
+ Shared Memory Extension".)
+
+ To monitor the system's shared memory segments, run "ipcs -m".
+ */
+
+#include "utils.h"
+
+/* #define DEBUG */
+
+#include <errno.h> /* for perror() */
+
+#ifdef HAVE_JWXYZ
+# include "jwxyz.h"
+#else
+# include <X11/Xutil.h> /* for XDestroyImage() */
+#endif
+
+#include "xshm.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;
+
+
+/* The documentation for the XSHM extension implies that if the server
+ supports XSHM but is not the local machine, the XShm calls will return
+ False; but this turns out not to be the case. Instead, the server
+ throws a BadAccess error. So, we need to catch X errors around all
+ of our XSHM calls, sigh.
+ */
+
+#ifdef HAVE_XSHM_EXTENSION
+
+static Bool shm_got_x_error = False;
+XErrorHandler old_handler = 0;
+static int
+shm_ehandler (Display *dpy, XErrorEvent *error)
+{
+ shm_got_x_error = True;
+
+#ifdef DEBUG
+ fprintf (stderr, "\n%s: ignoring X error from XSHM:\n", progname);
+ XmuPrintDefaultErrorMessage (dpy, error, stderr);
+ fprintf (stderr, "\n");
+#endif
+
+ return 0;
+}
+
+
+#define CATCH_X_ERROR(DPY) do { \
+ XSync((DPY), False); \
+ shm_got_x_error = False; \
+ if (old_handler != shm_ehandler) \
+ old_handler = XSetErrorHandler (shm_ehandler); \
+} while(0)
+
+#define UNCATCH_X_ERROR(DPY) do { \
+ XSync((DPY), False); \
+ if (old_handler) \
+ XSetErrorHandler (old_handler); \
+ old_handler = 0; \
+} while(0)
+
+#endif /* HAVE_XSHM_EXTENSION */
+
+
+static void
+print_error (int err)
+{
+ fprintf(stderr, "%s: %s\n", progname, strerror(err));
+}
+
+static XImage *
+create_fallback (Display *dpy, Visual *visual,
+ unsigned int depth,
+ int format, XShmSegmentInfo *shm_info,
+ unsigned int width, unsigned int height)
+{
+ XImage *image = XCreateImage (dpy, visual, depth, format, 0, NULL,
+ width, height, BitmapPad(dpy), 0);
+ shm_info->shmid = -1;
+
+ if (!image) {
+ print_error (ENOMEM);
+ } else {
+ /* 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);
+ if (error) {
+ print_error (error);
+ XDestroyImage (image);
+ image = NULL;
+ } else {
+ memset (image->data, 0, image->height * image->bytes_per_line);
+ }
+ }
+
+ return image;
+}
+
+
+XImage *
+create_xshm_image (Display *dpy, Visual *visual,
+ unsigned int depth,
+ int format, XShmSegmentInfo *shm_info,
+ unsigned int width, unsigned int height)
+{
+#ifndef HAVE_XSHM_EXTENSION
+
+ return create_fallback (dpy, visual, depth, format, shm_info, width, height);
+
+#else /* HAVE_XSHM_EXTENSION */
+
+ Status status;
+ XImage *image = 0;
+ if (!get_boolean_resource(dpy, "useSHM", "Boolean") ||
+ !XShmQueryExtension (dpy)) {
+ return create_fallback (dpy, visual, depth, format, shm_info,
+ width, height);
+ }
+
+ CATCH_X_ERROR(dpy);
+ image = XShmCreateImage(dpy, visual, depth,
+ format, NULL, shm_info, width, height);
+ UNCATCH_X_ERROR(dpy);
+ if (shm_got_x_error)
+ return create_fallback (dpy, visual, depth, format, shm_info,
+ width, height);
+
+#ifdef DEBUG
+ fprintf(stderr, "\n%s: XShmCreateImage(... %d, %d)\n", progname,
+ width, height);
+#endif
+
+ shm_info->shmid = shmget(IPC_PRIVATE,
+ image->bytes_per_line * image->height,
+ IPC_CREAT | 0777);
+#ifdef DEBUG
+ fprintf(stderr, "%s: shmget(IPC_PRIVATE, %d, IPC_CREAT | 0777) ==> %d\n",
+ progname, image->bytes_per_line * image->height, shm_info->shmid);
+#endif
+
+ if (shm_info->shmid == -1)
+ {
+ char buf[1024];
+ sprintf (buf, "%s: shmget failed", progname);
+ perror(buf);
+ XDestroyImage (image);
+ image = 0;
+ XSync(dpy, False);
+ }
+ else
+ {
+ shm_info->readOnly = False;
+ image->data = shm_info->shmaddr = shmat(shm_info->shmid, 0, 0);
+
+#ifdef DEBUG
+ fprintf(stderr, "%s: shmat(%d, 0, 0) ==> %d\n", progname,
+ shm_info->shmid, (int) image->data);
+#endif
+
+ CATCH_X_ERROR(dpy);
+ status = XShmAttach(dpy, shm_info);
+ UNCATCH_X_ERROR(dpy);
+ if (shm_got_x_error)
+ status = False;
+
+ if (!status)
+ {
+ fprintf (stderr, "%s: XShmAttach failed!\n", progname);
+ XDestroyImage (image);
+ XSync(dpy, False);
+ shmdt (shm_info->shmaddr);
+ image = 0;
+ }
+#ifdef DEBUG
+ else
+ fprintf(stderr, "%s: XShmAttach(dpy, shm_info) ==> True\n", progname);
+#endif
+
+ XSync(dpy, False);
+
+ /* Delete the shared segment right now; the segment won't actually
+ go away until both the client and server have deleted it. The
+ server will delete it as soon as the client disconnects, so we
+ should delete our side early in case of abnormal termination.
+ (And note that, in the context of xscreensaver, abnormal
+ termination is the rule rather than the exception, so this would
+ leak like a sieve if we didn't do this...)
+
+ #### Are we leaking anyway? Perhaps because of the window of
+ opportunity between here and the XShmAttach call above, during
+ which we might be killed? Do we need to establish a signal
+ handler for this case?
+ */
+ shmctl (shm_info->shmid, IPC_RMID, 0);
+
+#ifdef DEBUG
+ fprintf(stderr, "%s: shmctl(%d, IPC_RMID, 0)\n\n", progname,
+ shm_info->shmid);
+#endif
+ }
+
+ if (!image) {
+ return create_fallback (dpy, visual, depth, format, shm_info,
+ width, height);
+ }
+
+ return image;
+
+#endif /* HAVE_XSHM_EXTENSION */
+}
+
+
+Bool
+put_xshm_image (Display *dpy, Drawable d, GC gc, XImage *image,
+ int src_x, int src_y, int dest_x, int dest_y,
+ unsigned int width, unsigned int height,
+ XShmSegmentInfo *shm_info)
+{
+#ifdef HAVE_XSHM_EXTENSION
+ assert (shm_info); /* Don't just s/XShmPutImage/put_xshm_image/. */
+ if (shm_info->shmid != -1) {
+ /* XShmPutImage is asynchronous; the contents of the XImage must not be
+ modified until the server has placed the pixels on the screen and the
+ client has received an XShmCompletionEvent. Breaking this rule can cause
+ tearing. That said, put_xshm_image doesn't provide a send_event
+ parameter, so we're always breaking this rule. Not that it seems to
+ matter; everything (so far) looks fine without it.
+
+ ####: Add a send_event parameter. And fake it for XPutImage.
+ */
+ return XShmPutImage (dpy, d, gc, image, src_x, src_y, dest_x, dest_y,
+ width, height, False);
+ }
+#endif /* HAVE_XSHM_EXTENSION */
+
+ return XPutImage (dpy, d, gc, image, src_x, src_y, dest_x, dest_y,
+ width, height);
+}
+
+
+Bool
+get_xshm_image (Display *dpy, Drawable d, XImage *image, int x, int y,
+ unsigned long plane_mask, XShmSegmentInfo *shm_info)
+{
+#ifdef HAVE_XSHM_EXTENSION
+ if (shm_info->shmid != -1) {
+ return XShmGetImage (dpy, d, image, x, y, plane_mask);
+ }
+#endif /* HAVE_XSHM_EXTENSION */
+ return XGetSubImage (dpy, d, x, y, image->width, image->height, plane_mask,
+ image->format, image, 0, 0) != NULL;
+}
+
+
+void
+destroy_xshm_image (Display *dpy, XImage *image, XShmSegmentInfo *shm_info)
+{
+#ifdef HAVE_XSHM_EXTENSION
+ if (shm_info->shmid == -1) {
+#endif /* HAVE_XSHM_EXTENSION */
+
+ /* Don't let XDestroyImage free image->data. */
+ thread_free (image->data);
+ image->data = NULL;
+ XDestroyImage (image);
+ return;
+
+#ifdef HAVE_XSHM_EXTENSION
+ }
+
+ Status status;
+
+ CATCH_X_ERROR(dpy);
+ status = XShmDetach (dpy, shm_info);
+ UNCATCH_X_ERROR(dpy);
+ if (shm_got_x_error)
+ status = False;
+ if (!status)
+ fprintf (stderr, "%s: XShmDetach failed!\n", progname);
+#ifdef DEBUG
+ else
+ fprintf (stderr, "%s: XShmDetach(dpy, shm_info) ==> True\n", progname);
+#endif
+
+ XDestroyImage (image);
+ XSync(dpy, False);
+
+ status = shmdt (shm_info->shmaddr);
+
+ if (status != 0)
+ {
+ char buf[1024];
+ sprintf (buf, "%s: shmdt(0x%lx) failed", progname,
+ (unsigned long) shm_info->shmaddr);
+ perror(buf);
+ }
+#ifdef DEBUG
+ else
+ fprintf (stderr, "%s: shmdt(shm_info->shmaddr) ==> 0\n", progname);
+#endif
+
+ XSync(dpy, False);
+
+#endif /* HAVE_XSHM_EXTENSION */
+}
diff --git a/utils/xshm.h b/utils/xshm.h
new file mode 100644
index 0000000..6159b36
--- /dev/null
+++ b/utils/xshm.h
@@ -0,0 +1,54 @@
+/* xscreensaver, Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998, 2001
+ * 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
+ * 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.
+ */
+
+/* The MIT-SHM (Shared Memory) extension is pretty tricky to use.
+ This file contains the common boiler-plate for creating a shared
+ XImage structure, and for making sure that the shared memory segments
+ get allocated and shut down cleanly.
+ */
+
+#ifndef __XSCREENSAVER_XSHM_H__
+#define __XSCREENSAVER_XSHM_H__
+
+#ifdef HAVE_XSHM_EXTENSION
+
+# include <sys/ipc.h>
+# include <sys/shm.h>
+# include <X11/extensions/XShm.h>
+
+#else /* !HAVE_XSHM_EXTENSION */
+
+typedef struct {
+ int shmid; /* Always -1. */
+} dummy_segment_info;
+
+/* In case XShmSegmentInfo */
+#undef XShmSegmentInfo
+#define XShmSegmentInfo dummy_segment_info
+
+#endif
+
+extern XImage *create_xshm_image (Display *dpy, Visual *visual,
+ unsigned int depth,
+ int format, XShmSegmentInfo *shm_info,
+ unsigned int width, unsigned int height);
+extern Bool put_xshm_image (Display *dpy, Drawable d, GC gc, XImage *image,
+ int src_x, int src_y, int dest_x, int dest_y,
+ unsigned int width, unsigned int height,
+ XShmSegmentInfo *shm_info);
+extern Bool get_xshm_image (Display *dpy, Drawable d, XImage *image,
+ int x, int y, unsigned long plane_mask,
+ XShmSegmentInfo *shm_info);
+extern void destroy_xshm_image (Display *dpy, XImage *image,
+ XShmSegmentInfo *shm_info);
+
+#endif /* __XSCREENSAVER_XSHM_H__ */
diff --git a/utils/yarandom.c b/utils/yarandom.c
new file mode 100644
index 0000000..f450735
--- /dev/null
+++ b/utils/yarandom.c
@@ -0,0 +1,139 @@
+/* yarandom.c -- Yet Another Random Number Generator.
+ * Copyright (c) 1997-2014 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
+ * 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.
+ */
+
+/* The unportable mess that is rand(), random(), drand48() and friends led me
+ to ask Phil Karlton <karlton@netscape.com> what the Right Thing to Do was.
+ He responded with this. It is non-cryptographically secure, reasonably
+ random (more so than anything that is in any C library), and very fast.
+
+ I don't understand how it works at all, but he says "look at Knuth,
+ Vol. 2 (original edition), page 26, Algorithm A. In this case n=55,
+ k=24 and m=2^32."
+
+ So there you have it.
+
+ ---------------------------
+ Note: xlockmore 4.03a10 uses this very simple RNG:
+
+ if ((seed = seed % 44488 * 48271 - seed / 44488 * 3399) < 0)
+ seed += 2147483647;
+ return seed-1;
+
+ of which it says
+
+ ``Dr. Park's algorithm published in the Oct. '88 ACM "Random Number
+ Generators: Good Ones Are Hard To Find" His version available at
+ ftp://cs.wm.edu/pub/rngs.tar Present form by many authors.''
+
+ Karlton says: ``the usual problem with that kind of RNG turns out to
+ be unexepected short cycles for some word lengths.''
+
+ Karlton's RNG is faster, since it does three adds and two stores, while the
+ xlockmore RNG does two multiplies, two divides, three adds, and one store.
+
+ Compiler optimizations make a big difference here:
+ gcc -O: difference is 1.2x.
+ gcc -O2: difference is 1.4x.
+ gcc -O3: difference is 1.5x.
+ SGI cc -O: difference is 2.4x.
+ SGI cc -O2: difference is 2.4x.
+ SGI cc -O3: difference is 5.1x.
+ Irix 6.2; Indy r5k; SGI cc version 6; gcc version 2.7.2.1.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h> /* for getpid() */
+#endif
+#include <sys/time.h> /* for gettimeofday() */
+
+#include "yarandom.h"
+# undef ya_rand_init
+
+
+/* The following 'random' numbers are taken from CRC, 18th Edition, page 622.
+ Each array element was taken from the corresponding line in the table,
+ except that a[0] was from line 100. 8s and 9s in the table were simply
+ skipped. The high order digit was taken mod 4.
+ */
+#define VectorSize 55
+static unsigned int a[VectorSize] = {
+ 035340171546, 010401501101, 022364657325, 024130436022, 002167303062, /* 5 */
+ 037570375137, 037210607110, 016272055420, 023011770546, 017143426366, /* 10 */
+ 014753657433, 021657231332, 023553406142, 004236526362, 010365611275, /* 14 */
+ 007117336710, 011051276551, 002362132524, 001011540233, 012162531646, /* 20 */
+ 007056762337, 006631245521, 014164542224, 032633236305, 023342700176, /* 25 */
+ 002433062234, 015257225043, 026762051606, 000742573230, 005366042132, /* 30 */
+ 012126416411, 000520471171, 000725646277, 020116577576, 025765742604, /* 35 */
+ 007633473735, 015674255275, 017555634041, 006503154145, 021576344247, /* 40 */
+ 014577627653, 002707523333, 034146376720, 030060227734, 013765414060, /* 45 */
+ 036072251540, 007255221037, 024364674123, 006200353166, 010126373326, /* 50 */
+ 015664104320, 016401041535, 016215305520, 033115351014, 017411670323 /* 55 */
+};
+
+static int i1, i2;
+
+unsigned int
+ya_random (void)
+{
+ register int ret = a[i1] + a[i2];
+ a[i1] = ret;
+ if (++i1 >= VectorSize) i1 = 0;
+ if (++i2 >= VectorSize) i2 = 0;
+ return ret;
+}
+
+void
+ya_rand_init(unsigned int seed)
+{
+ int i;
+ if (seed == 0)
+ {
+ struct timeval tp;
+#ifdef GETTIMEOFDAY_TWO_ARGS
+ struct timezone tzp;
+ gettimeofday(&tp, &tzp);
+#else
+ gettimeofday(&tp);
+#endif
+ /* Since the multiplications will have a larger effect on the
+ upper bits than the lower bits, after every addition in the
+ seed, perform a bitwise rotate by an odd number, resulting
+ in a better distribution of randomness throughout the bits.
+ -- Brian Carlson, 2010.
+ */
+#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 = ROT (seed, 7);
+ seed += (1003 * getpid());
+ seed = ROT (seed, 13);
+ }
+
+ a[0] += seed;
+ for (i = 1; i < VectorSize; i++)
+ {
+ seed = seed*999;
+ seed = ROT (seed, 9);
+ seed += a[i-1]*1001;
+ seed = ROT (seed, 15);
+ a[i] += seed;
+ }
+
+ i1 = a[0] % VectorSize;
+ i2 = (i1 + 24) % VectorSize;
+}
diff --git a/utils/yarandom.h b/utils/yarandom.h
new file mode 100644
index 0000000..711aadd
--- /dev/null
+++ b/utils/yarandom.h
@@ -0,0 +1,103 @@
+/* xscreensaver, Copyright (c) 1997, 1998, 2003 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
+ * 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 __YARANDOM_H__
+#define __YARANDOM_H__
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+
+#undef random
+#undef rand
+#undef drand48
+#undef srandom
+#undef srand
+#undef srand48
+#undef frand
+#undef RAND_MAX
+
+#ifdef VMS
+# include "vms-gtod.h"
+#endif
+
+extern unsigned int ya_random (void);
+extern void ya_rand_init (unsigned int);
+
+#define random() ya_random()
+#define RAND_MAX 0xFFFFFFFF
+
+/*#define srandom(i) ya_rand_init(0)*/
+
+/* Define these away to keep people from using the wrong APIs in xscreensaver.
+ */
+#define rand __ERROR_use_random_not_rand_in_xscreensaver__
+#define drand48 __ERROR_use_frand_not_drand48_in_xscreensaver__
+#define srandom __ERROR_do_not_call_srandom_in_xscreensaver__
+#define srand __ERROR_do_not_call_srand_in_xscreensaver__
+#define srand48 __ERROR_do_not_call_srand48_in_xscreensaver__
+#define ya_rand_init __ERROR_do_not_call_ya_rand_init_in_xscreensaver__
+
+
+#if defined (__GNUC__) && (__GNUC__ >= 2)
+ /* Implement frand using GCC's statement-expression extension. */
+
+# define frand(f) \
+ __extension__ \
+ ({ double tmp = ((((double) random()) * ((double) (f))) / \
+ ((double) ((unsigned int)~0))); \
+ tmp < 0 ? (-tmp) : tmp; })
+
+#else /* not GCC2 - implement frand using a global variable.*/
+
+static double _frand_tmp_;
+# define frand(f) \
+ (_frand_tmp_ = ((((double) random()) * ((double) (f))) / \
+ ((double) ((unsigned int)~0))), \
+ _frand_tmp_ < 0 ? (-_frand_tmp_) : _frand_tmp_)
+
+#endif /* not GCC2 */
+
+/* Compatibility with the xlockmore RNG API
+ (note that the xlockmore hacks never expect negative numbers.)
+ */
+#define LRAND() ((long) (random() & 0x7fffffff))
+
+/* The first NRAND(n) is much faster, when uint64_t is available to allow it.
+ * Especially on ARM and other processors without built-in division.
+ *
+ * n must be greater than zero.
+ *
+ * The division by RAND_MAX+1 should optimize down to a bit shift.
+ *
+ * Although the result here is never negative, this needs to return signed
+ * integers: A binary operator in C requires operands have the same type, and
+ * if one side is signed and the other is unsigned, but they're both the same
+ * size, then the signed operand is cast to unsigned, and the result is
+ * similarly unsigned. This can potentially cause problems when idioms like
+ * "NRAND(n) * RANDSIGN()" (where RANDSIGN() returns either -1 or 1) is used
+ * to get random numbers from the range (-n,n).
+ */
+#ifdef HAVE_INTTYPES_H
+# define NRAND(n) ((int32_t) ((uint64_t) random() * (uint32_t) (n) / \
+ ((uint64_t) RAND_MAX + 1)))
+#else
+# define NRAND(n) ((int) (LRAND() % (n)))
+#endif
+
+#define MAXRAND (2147483648.0) /* unsigned 1<<31 as a float */
+#define SRAND(n) /* already seeded by screenhack.c */
+
+#endif /* __YARANDOM_H__ */