diff options
author | Simon Rettberg | 2018-10-16 10:08:48 +0200 |
---|---|---|
committer | Simon Rettberg | 2018-10-16 10:08:48 +0200 |
commit | d3a98cf6cbc3bd0b9efc570f58e8812c03931c18 (patch) | |
tree | cbddf8e50f35a9c6e878a5bfe3c6d625d99e12ba /utils | |
download | xscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.tar.gz xscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.tar.xz xscreensaver-d3a98cf6cbc3bd0b9efc570f58e8812c03931c18.zip |
Original 5.40
Diffstat (limited to 'utils')
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 Binary files differnew file mode 100644 index 0000000..1355767 --- /dev/null +++ b/utils/images/logo-180.gif 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 Binary files differnew file mode 100644 index 0000000..fcfcfd7 --- /dev/null +++ b/utils/images/logo-50.gif 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 Binary files differnew file mode 100644 index 0000000..5ea3da2 --- /dev/null +++ b/utils/images/logo-big.gif 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 Binary files differnew file mode 100644 index 0000000..fdb8e13 --- /dev/null +++ b/utils/images/screensaver-cmndln.png diff --git a/utils/images/screensaver-colorselector.png b/utils/images/screensaver-colorselector.png Binary files differnew file mode 100644 index 0000000..f18c86f --- /dev/null +++ b/utils/images/screensaver-colorselector.png diff --git a/utils/images/screensaver-diagnostic.png b/utils/images/screensaver-diagnostic.png Binary files differnew file mode 100644 index 0000000..52de31a --- /dev/null +++ b/utils/images/screensaver-diagnostic.png diff --git a/utils/images/screensaver-locking.png b/utils/images/screensaver-locking.png Binary files differnew file mode 100644 index 0000000..61ee436 --- /dev/null +++ b/utils/images/screensaver-locking.png diff --git a/utils/images/screensaver-power.png b/utils/images/screensaver-power.png Binary files differnew file mode 100644 index 0000000..38c861d --- /dev/null +++ b/utils/images/screensaver-power.png diff --git a/utils/images/screensaver-snap.png b/utils/images/screensaver-snap.png Binary files differnew file mode 100644 index 0000000..720f51a --- /dev/null +++ b/utils/images/screensaver-snap.png 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') { // A + 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] == '#') { // A + 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') /* */ + 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__ */ |