[Pkg-wmaker-commits] [wmbubble] 01/207: Initial checkin from upstream (asked; he doesn't have anything older)

Doug Torrance dtorrance-guest at moszumanska.debian.org
Mon Aug 24 04:17:46 UTC 2015


This is an automated email from the git hooks/post-receive script.

dtorrance-guest pushed a commit to branch master
in repository wmbubble.

commit 8a500c12bcc27bb8da3e705fb93fa612b49f8b99
Author: Robert Jacobs <rnjacobs at mit.edu>
Date:   Mon Aug 29 19:00:41 2011 -0700

    Initial checkin from upstream (asked; he doesn't have anything older)
---
 ChangeLog             |  154 +++++
 INSTALL               |   22 +
 Makefile              |   81 +++
 Makefile.FreeBSD      |   37 ++
 Makefile.NetBSD       |   37 ++
 README                |  128 ++++
 SUPPORTED_SYSTEMS     |    5 +
 bubblemon.c           | 1579 +++++++++++++++++++++++++++++++++++++++++++++++++
 doc/COPYING           |    3 +
 doc/Xdefaults.sample  |   12 +
 include/bubblemon.h   |  139 +++++
 include/digits.h      |   81 +++
 include/ducks.h       |   59 ++
 include/load_screen.h |  464 +++++++++++++++
 include/master.xpm    |   71 +++
 include/mem_screen.h  |  466 +++++++++++++++
 include/sys_include.h |   31 +
 misc/load_1.1.xcf     |  Bin 0 -> 7339 bytes
 misc/mem_1.1.xcf      |  Bin 0 -> 7809 bytes
 misc/wak.wav          |  Bin 0 -> 4012 bytes
 misc/wakwak.sh        |    3 +
 sys_freebsd.c         |  210 +++++++
 sys_linux.c           |  176 ++++++
 sys_netbsd.c          |  132 +++++
 sys_openbsd.c         |  130 ++++
 sys_sunos.c           |  325 ++++++++++
 26 files changed, 4345 insertions(+)

diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..dc3bcaf
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,154 @@
+This ChangeLog file is backwards.  Press "G" in vi to go to the end of it.
+
+Sun, 7 Jan 2001 - 1.0
+    Initial FreeBSD port
+
+Fri, 12 Jan 2001 - 1.0pl1
+    Duck "upside down" mode
+    Initial version of "memory info" screen
+
+Mon, 15 Jan 2001 - 1.0pl2
+    FreeBSD memory code fixes
+
+Tue, 16 Jan 2001 - 1.0pl3
+    Most drawing operations rewritten and optimized
+    Modular changes - extra features under #ifdef
+    FreeBSD fixes
+
+Tue, 16 Jan 2001 - 1.0pl4
+    More fixes
+
+Thu, 18 Jan 2001 - 1.0pl6
+    Code reorganization
+    Command line options
+
+Thu, 18 Jan 2001 - 1.0pl7
+    All floating point calculations eliminated
+    FreeBSD changes
+    Added Xresource parsing for color, etc options
+    Load average/Memory screen toggle via shift key
+
+Sun, 21 Jan 2001 - 1.0pl8
+    Load average graph inside load average screen
+    system-dependent code updates
+    more features #ifdef'd
+
+Sun, 21 Jan 2001 - 1.0pl9
+    Load average / memory info screens, "picture lock".
+
+Sun, 21 Jan 2001 - 1.1test1
+    bubblemon_update() cleanup
+    bubblemon.h cleanup
+    load average graph updates
+    session_defaults() update
+    documentation updates
+
+Sun, 21 Jan 2001 - 1.1test2
+    argv count bug found and fixed
+    range checking for values read from Xdefaults
+    performance improvements in bubblemon_update()
+    FreeBSD memory code changes
+    documentation updates
+    removed last pieces of floating point numbers
+
+Mon, 22 Jan 2001 - 1.1test3
+    bubblemon_update() cleanup
+
+Thu, 25 Jan 2001 - 1.1test4
+    Code reorganization
+    Main Makefile will detect OS if GNU make is used
+    Moved system dependent code into sys_(uname).c
+    Changes to system-dependent code structure
+    Reorganization of include files and directory structure
+    History graphs for load average and memory use updates
+    Performance improvements
+    Some functions renamed
+    Off-by-one error in rgb image data fixed
+    BlackBox don't-draw-on-win feature
+    bubblemon_update() cleanup
+    Swapped load / memory screen order
+    FreeBSD memory code updates
+
+Sun, 28 Jan 2001 - 1.1test5
+    Load average logic change, update to Linux and FreeBSD dependent code
+    Other misc changes
+
+Mon, 29 Jan 2001 - 1.1test6
+    BubbleMonData is now a static structure
+    Performance improvements
+
+Wed, 31 Jan 2001 - 1.1test7
+    Documentation updates
+    Possible buffer overflow fix in session_defaults()
+
+Thu 01 Feb 2001 - 1.1
+    Minor documentation update
+    sys_freebsd math update
+    Version 1.1 released
+
+Wed 14 Feb 2001 - 1.2test1
+    SunOS port added
+
+Thu 15 Feb 2001 - 1.2
+    SunOS port fixed
+    Version 1.2 released
+
+Mon 19 Feb 2001 - 1.21test1
+    Various updates to the SunOS port
+    Added -k command line switch to display memory/swap in megabytes instead
+    of kilobytes.  Useful for machines with > 1024mb memory, since kilobytes
+    display stops at 999mb for both swap and physical ram
+    Portability fixes
+
+Thu 22 Feb 2001 - 1.21
+    Fix for FreeBSD CPU usage problem under high load
+    Released version 1.21
+
+Sun 25 Feb 2001 - 1.22
+    Fixed segfault which occured under certain low memory conditions, found
+    and fixed by "John H. Robinson, IV" <jaqque at ucsd.edu>
+    Released version 1.22
+
+Sat 10 Mar 2001 - 1.23
+    Patch from Dan Price to fix Shift Key detection on all platforms
+    Tracked down another segfault related to off-by-one-scanline error
+    Increased bm.bubblebuf allocation because bubbles created at the very
+    bottom of the "water" are drawn outside of 56x56 region.
+    Released version 1.23
+
+Fri 16 Mar 2001 - 1.3
+    Fixed load average graph - I don't know what the hell I was doing that
+    it worked before, but the way the code was written it was never supposed
+    to work :)
+    Added some contributed code to hopefully catch most of bubble-related
+    segfaults.  Thanks to "John H. Robinson, IV" <jaqque at ucsd.edu>
+    Updated Makefile to use proper libs when linking with gdk, etc.  Should
+    stop complaints about "missing library dependencies"
+    This is a recommented upgrade if you use bubblemon version 1.2 or newer.
+    Released version 1.3
+
+Sat 14 Apr 2001 - 1.31
+    FreeBSD machines were compiling bubblemon as "big-endian", resulting in
+    fairly weird looking color problem.  This has been fixed :)  Minor change
+    to Makefile.FreeBSD to put bubblemon in /usr/X11R6 during install.
+    Released version 1.31
+    
+Mon 16 Apr 2001 - 1.32
+    Important security update for FreeBSD - previous versions did not drop
+    kmem privileges, and programs started by clicking on the dockapp were
+    started with elevated privileges.  This is a required upgrade for FreeBSD
+    users.
+
+Tue 28 Aug 2001 - 1.4
+    Added OpenBSD support. Thanks to Peter Stromberg <wilfried at openbsd.org>.
+
+Wed  1 Oct 2003 - 1.41
+    Added support for Linux kernel 2.6
+    Fixed 101% cpu usage problem on kernel 2.6
+
+Thu 13 May 2004 - 1.45
+    Added support for NetBSD. Thanks to Metalhead <metalhead at metalhead.ws>
+    This support is untested, use Makefile.NetBSD to compile.
+
+Sat 15 May 2004 - 1.46
+    Compile fix for FreeBSD-5.x, forgotten include. 
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..b599e81
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,22 @@
+Install instructions:
+
+1. read README
+1a. On Linux 2.6, edit Makefile and uncommend top line that adds -DKERNEL_26
+2. make (on FreeBSD, make -f Makefile.FreeBSD)
+3. make install (this will put bubblemon in /usr/local/bin)
+4. bubblemon &
+
+Using GNU make bubblemon should compile without changes on any system listed
+in SUPPORTED_SYSTEMS file.  If not, feel free to fix it and send me a diff -u.
+
+Check README file for configuration options - you can either permanently
+disable a feature by editing Makefile and commenting out any of the EXTRA
+defines, or disable it at run-time by using command-line switches. Colors
+and bubble physics can also be configured through ~/.Xdefaults file.
+
+If your FreeBSD system doesn't have GNU Make, use Makefile.FreeBSD. If it
+does, regular Makefile should be able to detect things correctly. Also,
+on FreeBSD, you can do make install as root to install in /usr/local/bin
+and give bubblemon proper permissions, or you'll have to give bubblemon
+kmem access yourself:
+root:~# chown root:kmem bubblemon; chmod g+s bubblemon
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..1396075
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,81 @@
+# bubblemon configuration
+EXTRA = -DENABLE_DUCK
+EXTRA += -DENABLE_CPU
+EXTRA += -DENABLE_MEMSCREEN
+EXTRA += -DKERNEL_26
+# EXTRA += -DKDE_DOCKAPP
+# EXTRA += -DUPSIDE_DOWN_DUCK
+
+# where to install this program
+PREFIX = /usr/local
+
+# no user serviceable parts below
+EXTRA += $(WMAN)
+# optimization cflags
+CFLAGS = -O3 -ansi -Wall `gtk-config --cflags` ${EXTRA}
+# profiling cflags
+# CFLAGS = -ansi -Wall -pg -O3 `gtk-config --cflags` ${EXTRA} -DPRO
+# test coverage cflags
+# CFLAGS = -fprofile-arcs -ftest-coverage -Wall -ansi -g `gtk-config --cflags` ${EXTRA} -DPRO
+
+
+SHELL=sh
+OS = $(shell uname -s)
+OBJS = bubblemon.o
+CC = gcc
+
+# special things for Linux
+ifeq ($(OS), Linux)
+    OBJS += sys_linux.o
+    LIBS = `gtk-config --libs | sed "s/-lgtk//g"`
+    INSTALL = -m 755
+endif
+
+# special things for FreeBSD
+ifeq ($(OS), FreeBSD)
+    OBJS += sys_freebsd.o
+    LIBS = `gtk-config --libs | sed "s/-lgtk//g"` -lkvm
+    INSTALL = -c -g kmem -m 2755 -o root
+endif
+
+# special things for OpenBSD
+ifeq ($(OS), OpenBSD)
+    OBJS += sys_openbsd.o
+    LIBS = `gtk-config --libs | sed "s/-lgtk//g"`
+endif
+
+#special things for SunOS
+ifeq ($(OS), SunOS)
+
+    # try to detect if gcc is available (also works if you call gmake CC=cc to
+    # select the sun compilers on a system with both)
+    COMPILER=$(shell \
+        if [ `$(CC) -v 2>&1 | egrep -c '(gcc|egcs|g\+\+)'` = 0 ]; then \
+	    echo suncc; else echo gcc; fi)
+
+    # if not, fix up CC and the CFLAGS for the Sun compiler
+    ifeq ($(COMPILER), suncc)
+	CC=cc
+	CFLAGS=-v -xO3
+    endif
+
+    ifeq ($(COMPILER), gcc)
+	CFLAGS=-O3 -Wall
+    endif
+    CFLAGS +=`gtk-config --cflags` ${EXTRA}
+    OBJS += sys_sunos.o
+    LIBS = `gtk-config --libs` -lkstat -lm
+    INSTALL = -m 755
+endif
+
+
+all: bubblemon
+
+bubblemon: $(OBJS)
+	$(CC) $(CFLAGS) -o bubblemon $(OBJS) $(LIBS)
+
+clean:
+	rm -f bubblemon *.o *.bb* *.gcov gmon.* *.da *~
+
+install:
+	install $(INSTALL) bubblemon $(PREFIX)/bin
diff --git a/Makefile.FreeBSD b/Makefile.FreeBSD
new file mode 100644
index 0000000..04f53c5
--- /dev/null
+++ b/Makefile.FreeBSD
@@ -0,0 +1,37 @@
+# bubblemon configuration
+EXTRA = -DENABLE_DUCK
+EXTRA += -DENABLE_CPU 
+EXTRA += -DENABLE_MEMSCREEN
+EXTRA += -DUPSIDE_DOWN_DUCK
+
+EXTRA += $(WMAN)
+
+# no user serviceable parts below
+CC = gcc
+
+# optimization cflags
+CFLAGS = -O3 -ansi -Wall `gtk-config --cflags` ${EXTRA}
+# profiling cflags
+# CFLAGS = -ansi -Wall -pg -O3 `gtk-config --cflags` ${EXTRA} -DPRO
+# test coverage cflags
+# CFLAGS = -fprofile-arcs -ftest-coverage -Wall -ansi -g `gtk-config --cflags` ${EXTRA} -DPRO
+
+LIBS = `gtk-config --libs | sed "s/-l.*//g"` -lgdk12 -lkvm
+PREFIX = /usr/X11R6
+VPATH = include
+
+all: bubblemon
+
+bubblemon: bubblemon.o sys_freebsd.o
+	gcc ${CFLAGS} -o bubblemon bubblemon.o sys_freebsd.o ${LIBS}
+
+clean:
+	rm -f bubblemon bubblemon.o *.o *.bb* *.gcov gmon.* *.da winglue.c bubblemon32 *.so win32.spec *~ *.gmon *.s *.core
+
+install:
+	install -c -g kmem -m 2755 -o root bubblemon ${PREFIX}/bin
+
+bubblemon.o: bubblemon.h ducks.h master.xpm sys_include.h digits.h \
+	load_screen.h mem_screen.h
+
+sys_freebsd.o: bubblemon.h
diff --git a/Makefile.NetBSD b/Makefile.NetBSD
new file mode 100644
index 0000000..88534cf
--- /dev/null
+++ b/Makefile.NetBSD
@@ -0,0 +1,37 @@
+# bubblemon configuration
+EXTRA = -DENABLE_DUCK
+EXTRA += -DENABLE_CPU 
+EXTRA += -DENABLE_MEMSCREEN
+#EXTRA += -DUPSIDE_DOWN_DUCK
+
+EXTRA += $(WMAN)
+
+# no user serviceable parts below
+CC = gcc
+
+# optimization cflags
+CFLAGS = -O2 -ansi -Wall `gtk-config --cflags` ${EXTRA}
+# profiling cflags
+# CFLAGS = -ansi -Wall -pg -O3 `gtk-config --cflags` ${EXTRA} -DPRO
+# test coverage cflags
+# CFLAGS = -fprofile-arcs -ftest-coverage -Wall -ansi -g `gtk-config --cflags` ${EXTRA} -DPRO
+
+LIBS = `gtk-config --libs | sed "s/-l.*//g"` -lgdk -lkvm
+PREFIX = /usr/X11R6
+VPATH = include
+
+all: bubblemon
+
+bubblemon: bubblemon.o sys_netbsd.o
+	gcc ${CFLAGS} -o bubblemon bubblemon.o sys_netbsd.o ${LIBS}
+
+clean:
+	rm -f bubblemon bubblemon.o *.o *.bb* *.gcov gmon.* *.da winglue.c bubblemon32 *.so win32.spec *~ *.gmon *.s *.core
+
+install:
+	install -c -g kmem -m 2755 -o root bubblemon ${PREFIX}/bin
+
+bubblemon.o: bubblemon.h ducks.h master.xpm sys_include.h digits.h \
+	load_screen.h mem_screen.h
+
+sys_netbsd.o: bubblemon.h
diff --git a/README b/README
new file mode 100644
index 0000000..5306cc8
--- /dev/null
+++ b/README
@@ -0,0 +1,128 @@
+For copyright/authors/contributors see top of bubblemon.c.  For list of
+supported operating systems, see SUPPORTED_SYSTEMS.
+
+Abstract:
+
+This program is a dockapp-style CPU, memory, swap and load average monitor.
+Based on the GNOME BubbleMon applet, this program has been considerably
+improved.  Many new features have been added.  This is version 1.3.
+
+Features:
+
+On the surface, dockapp BubbleMon follows the same style as original GNOME
+applet. Main screen area is split into 2 parts - air and water. Water level
+depends on how much physical and virtual memory is used by the system. CPU
+activity makes water "boil" and creates bubbles. CPU meter near the bottom
+shows actual value in percent. As memory usage increases, water level goes
+up. When system runs out of physical memory and begins using swap, both
+water and air colors change depending on amount of swap used. There is a
+cute yellow duck swimming from one corner of the dockapp to another. The
+duck really doesn't do anything at the moment, but in a future version it's
+speed might correspond to system load average or another variable. This is
+the "main" mode of BubbleMon.
+
+There are 2 additional screens available - memory and load average.  Load
+average screen is accessed by simply hovering the mouse pointer over BubbleMon
+window. Memory screen is accessed same way, except you must hold down either
+left or right "Shift" key before moving the mouse pointer over BubbleMon
+window. Both Memory and Load average screens fade in slowly for a reason -
+during fade, you can click "Right" mouse button to lock currently fading
+screen.  This way you can see both CPU load screen and either memory or load
+average screen. To exit "locked" mode, simply move the mouse pointer in and
+out of the BubbleMon window.
+
+Memory screen displays current amount of free memory and swap, in kilobytes
+and percent.  Top number is amount of used memory, in kilobytes and percent,
+and bottom number is amount of used swap.  Under Linux implementation, used
+swap is set to "0" until 100% of system memory is used.  Below these numbers
+is a graph of recent memory use.  Unless you are running something that
+dynamically allocates and deallocates huge amounts of memory, this graph is
+most likely going to be more or less a straight line. Percentage and kilobyte
+counters will change color in case of memory or swap use over 90%.
+Load average screen displays system load average, same way as presented by
+"uptime" command. Approximately last 3 minutes of system load are graphed
+below the load average numbers.  Default "light blue" color of load average
+and memory screens can be changed to a "pale" version by using "-p" command
+line switch.
+
+You can start BubbleMon with up to 2 command-line argumens (not counting
+switches), each being a path to a program or shell script to execute when
+you click Left or Middle mouse button inside BubbleMon window. These must
+be the last 2 parameters.  There is a .wav file and a simple shell script
+to play it, inside misc/ directory, which you can use to make some duck
+sounds with bubblemon.
+
+Configuration:
+
+BubbleMon is very configurable. Previous section explains many features, but
+all of them can be disabled, either through compile-time settings or with
+command-line switches at startup. Either the general Makefile or FreeBSD-
+specific Makefile contain compilation defines near the top. You can comment out
+a particular line, to disable that feature. Alternatively, you can run
+"bubblemon -h" for a list of command line options. This will show command-line
+switches which can be used to disable certain BubbleMon modes, and modify color
+scheme used in memory and load average screens. You can also change colors of
+the air, water, various physics constants which control bubble generation, and
+maximum number of bubbles to make. All of these settings are read on start-up
+from the user's HOME directory, using .Xdefaults file. If you don't have a
+.Xdefaults file in your home directory, you can copy Xdefaults.sample which
+is distributed with BubbleMon. If you already have some settings in .Xdefaults
+you can simply append BubbleMon settings file to your current configuration:
+hostname:~$ cat /path/to/bubblemon-src/Xdefaults.sample >> ~/.Xdefaults
+However if you are happy with the current color scheme or bubble physics, you
+don't need to do anything at all, because BubbleMon has default settings
+compiled in.
+
+Information about original GNOME BubbleMon applet:
+
+You can get the original BubbleMon applet from
+http://www.nada.kth.se/~d92-jwa/code - but that version requires GNOME, does
+not have a cute duck, uses more CPU, and doesn't allow you to start programs
+by clicking on it. But, I guess if you like GNOME, you might want to check
+it out.
+
+Programming details:
+
+It's been a long tradition that dockapps use Xlib to draw, mainly because
+that's what the first dockapp used and because there are some abstraction
+layers to hide some of Xlib ugliness (libdockapp, wmgeneral, etc). Xlib is
+fine if all you do is change a couple pixels every other second, like most
+dockapps do. But if you deal with 3D, or any kind of large amount of pixel
+shuffling, Xlib really starts to suck. Common mistake when doing lots of
+pixel shuffling in Xlib is using XPutPixel or XCopyArea. Say, you got a 
+56x56 dockapp, and 80% of it is changed every 10ms. That's almost 2.5
+thousand pixel ops. And a 1x1 XCopyArea takes as much server overhead as a
+64x64 XCopyArea. Since X11 sucks, each one of these puts a request in the
+server queue and will waste ungodly amounts of bandwidth (if you run a
+remote X session) and use CPU time on the server machine. X11 really doesn't
+provide any simple way to deal with drawing stuff on screen without messing
+with colormaps or other serious ugliness. If you are familiar with game
+programming and that kind of stuff, you know that screen is usually drawn on
+a back buffer and then switched, so the user sees smooth animation instead
+of watching the screen redraw. X11 doesn't really have this feature, because
+even drawing to a off-screen pixmap is still slow - and requires contacting
+the server, and still requires dealing with colormaps.
+
+Solution is simple. GDK. Gimp Drawing toolKit. And a large buffer to draw
+in. Render your screen on the "back buffer", which is completely in memory
+and thus doesn't need to contact the server, and then use gdk_draw_rgb_image
+to quicky slap that on-screen. That's about the only GDK function you will
+ever need to use. Results are impressive - very complex scenes could be
+rendered in local memory, fast, and the only network I/O generated is from
+copying backbuffer to the screen, which is minimal compared to updating the
+same screen pixel by pixel. Since bubblemon does a lot of pixel shuffling,
+it uses this technique to draw. Thanks to gdkrgb, BubbleMon achieves fluid
+animation at 33 frames per second.  Some window managers, like BlackBox,
+don't require dockapps to draw on the main window, only on the icon window.
+You can run make with "make WMAN=-DBLACKBOX" to remove code dealing with
+drawing on main window, for a marginal performance improvement, though it's
+very unlikely you will notice the difference unless you are profiling.
+
+timecop at japan.co.jp
+
+
+Notes from the FreeBSD port author:
+For FreeBSD, the percentage of used memory is calculated as
+number_of_active_pages / total_number_of_pages_in_the_system * 100%.
+If you have any concerns regarding this or FreeBSD port of BubbleMon
+in general, please email oleg dashevskii <od at iclub.nsu.ru>.
diff --git a/SUPPORTED_SYSTEMS b/SUPPORTED_SYSTEMS
new file mode 100644
index 0000000..cfae4e9
--- /dev/null
+++ b/SUPPORTED_SYSTEMS
@@ -0,0 +1,5 @@
+Linux - timecop at japan.co.jp, added support for kernel 2.6
+FreeBSD - od at iclub.nsu.ru
+OpenBSD - wilfried at openbsd.org
+NetBSD - metalhead at metalhead.ws
+Solaris/SunOS - wplu13 at netscape.net, dp at rampant.org
diff --git a/bubblemon.c b/bubblemon.c
new file mode 100644
index 0000000..c0679c1
--- /dev/null
+++ b/bubblemon.c
@@ -0,0 +1,1579 @@
+/*  BubbleMon dockapp 1.32
+ *
+ *  - dockapp for Window Maker/Blackbox/E/Afterstep/SawBabble
+ *  - Code outside of bubblemon_update copyright 2000, 2001
+ *    timecop at japan.co.jp
+ *  - oleg dashevskii <od at iclub.nsu.ru> made changes to collect memory
+ *    and cpu information on FreeBSD.  Some major performance improvements
+ *    and other cool hacks.  Useful ideas - memscreen, load screen, etc.
+ *  - Adrian B <midnight at bigpond.net.au> came up with the idea of load
+ *    meter.
+ *  - tarzeau at space.ch sent in cute duck gfx and suggestions, plus some
+ *    code and duck motion fixes.
+ *  - Phil Lu <wplu13 at netscape.net> Dan Price <dp at rampant.org> - Solaris/SunOS
+ *    port
+ *  - Everything else copyright one of the guys below
+ *
+ *  TODO: Anything else? Add fish?
+ *
+ *  *************************************************************************
+ * 
+ *  Bubbling Load Monitoring Applet
+ *  - A GNOME panel applet that displays the CPU + memory load as a
+ *    bubbling liquid.
+ *  Copyright (C) 1999-2000 Johan Walles
+ *  - d92-jwa at nada.kth.se
+ *  Copyright (C) 1999 Merlin Hughes
+ *  - merlin at merlin.org
+ *  - http://nitric.com/freeware/
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+#define _GNU_SOURCE
+
+#define VERSION "1.41"
+
+/* general includes */
+#include <stdio.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* x11 includes */
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+#include <X11/Xresource.h>
+
+#include "include/master.xpm"
+#include "include/bubblemon.h"
+#include "include/sys_include.h"
+
+#ifdef ENABLE_DUCK
+#include "include/ducks.h"
+#endif
+#if defined(ENABLE_CPU)
+#include "include/digits.h"
+#endif
+#if defined(ENABLE_MEMSCREEN)
+#include "include/load_screen.h"
+#include "include/mem_screen.h"
+#endif
+
+/* #define DEBUG_DUCK 1 */
+
+/* local prototypes *INDENT-OFF* */
+static void bubblemon_setup_samples(void);
+static void bubblemon_setup_colors(void);
+static void bubblemon_allocate_buffers(void);
+static void bubblemon_update(int proximity);
+static void make_new_bubblemon_dockapp(void);
+static void get_memory_load_percentage(void);
+static void bubblemon_session_defaults(void);
+static int get_screen_selection(void);
+#if defined(ENABLE_CPU) || defined(ENABLE_MEMSCREEN)
+/* draw functions for load average / memory screens */
+static void draw_pixel(unsigned int x, unsigned int y, unsigned char *buf,
+		       unsigned char *c);
+static void draw_history(int num, int size, unsigned int *history,
+			 unsigned char *buf);
+static void draw_digit(int srcx, int srcy, int destx, int desty);
+static void draw_string(char *string, int x, int y, int color);
+static void draw_cpudigit(const int what, const int where,
+			  unsigned char *kit);
+
+static void render_secondary(void);
+static void realtime_alpha_blend_of_cpu_usage(int cpu, int proximity);
+static void roll_membuffer(void);
+static void roll_history(void);
+#endif
+#ifdef ENABLE_DUCK
+static int animate_correctly(void);
+static void duck_set(int x, int y, int nr, int rev, int upsidedown);
+static void duck_swimmer(int posy);
+#endif
+#ifdef __FreeBSD__
+extern int init_stuff();	/* defined in sys_freebsd.c */
+#endif
+/* local prototypes end *INDENT-ON* */
+
+/* global variables */
+BubbleMonData bm;
+
+/* compiled-in options string */
+char options[1024];
+
+#ifdef ENABLE_DUCK
+int duck_enabled = 1;
+#ifdef UPSIDE_DOWN_DUCK
+int upside_down_duck_enabled = 1;
+#endif				/* UPSIDE_DOWN_DUCK */
+#endif				/* ENABLE_DUCK */
+#ifdef ENABLE_CPU
+int cpu_enabled = 1;
+#endif				/* ENABLE_CPU */
+#ifdef ENABLE_MEMSCREEN
+int memscreen_enabled = 1;
+int memscreen_megabytes = 0;
+#endif				/* ENABLE_MEMSCREEN */
+
+#define INT_VAL 0
+#define DOUBLE_VAL 1
+#define COLOR_VAL 2
+
+static void bubblemon_session_defaults(void)
+{
+    /* handy way to collect all this stuff in one place */
+    typedef struct {
+	char *name;		/* name as appears in Xdefaults */
+	int type;		/* int, double, or color, see up */
+	void *var;		/* pointer to value - only handles INT atm */
+    } xrm_vars;
+
+    /* XResource stuff */
+    char name[BUFSIZ] = "", *ptr;
+    XrmDatabase db = NULL;
+    XrmValue val;
+    char *type;
+    int i;
+
+    xrm_vars tab[] = {
+	{"bubblemon.maxbubbles", INT_VAL, &bm.maxbubbles},
+	{"bubblemon.air_noswap", COLOR_VAL, &bm.air_noswap},
+	{"bubblemon.air_maxswap", COLOR_VAL, &bm.air_maxswap},
+	{"bubblemon.liquid_noswap", COLOR_VAL, &bm.liquid_noswap},
+	{"bubblemon.liquid_maxswap", COLOR_VAL, &bm.liquid_maxswap},
+	{"bubblemon.ripples", DOUBLE_VAL, &bm.ripples},
+	{"bubblemon.gravity", DOUBLE_VAL, &bm.gravity},
+	{"bubblemon.volatility", DOUBLE_VAL, &bm.volatility},
+	{"bubblemon.viscosity", DOUBLE_VAL, &bm.viscosity},
+	{"bubblemon.speed_limit", DOUBLE_VAL, &bm.speed_limit}
+    };
+
+    /* number of CPU load samples */
+    bm.samples = 16;
+
+    /* default colors.  changeable from Xdefaults */
+    bm.air_noswap = 0x2299ff;
+    bm.liquid_noswap = 0x0055ff;
+    bm.air_maxswap = 0xff0000;
+    bm.liquid_maxswap = 0xaa0000;
+
+    /* default bubble engine parameters.  Changeable from Xdefaults */
+    bm.maxbubbles = 100;
+    bm.ripples = 0.2;
+    bm.gravity = 0.01;
+    bm.volatility = 1.0;
+    bm.viscosity = 0.98;
+    bm.speed_limit = 1.0;
+
+    db = NULL;
+    XrmInitialize();
+
+    /* get users's local Xdefaults */
+    if ((ptr = getenv("HOME")) != NULL) {
+	snprintf(name, sizeof(name), "%s/.Xdefaults", ptr);
+    }
+
+    /* get the database and parse resources if we have some */
+    if ((db = XrmGetFileDatabase(name)) != NULL) {
+	for (i = 0; i < (sizeof(tab) / sizeof(tab[0])); i++) {
+	    if (XrmGetResource(db, tab[i].name, tab[i].name, &type, &val)) {
+		if (val.size > 0)	/* no empty strings and shit like that */
+		    switch (tab[i].type) {
+		    case INT_VAL:
+			*(int *) tab[i].var = atoi(val.addr);
+			break;
+		    case DOUBLE_VAL:
+			*(double *) tab[i].var = atof(val.addr);
+			break;
+		    case COLOR_VAL:
+			sscanf(val.addr, "#%x", (int *) tab[i].var);
+			break;
+		    default:
+			/* WTF? */
+			break;
+		    }
+	    }
+	}
+    }
+#define RANGE_CHECK(x, min, max, def) \
+    if ((x) > (max) || (x) < (min)) { \
+	fprintf(stderr, #x" value is out of range. Using default value ("#def")\n"); \
+	(x) = (def); \
+    }
+
+    /* range validation. 3l33t hackerz NO PASARAN */
+    RANGE_CHECK(bm.air_noswap, 0, 0xffffff, 0x2299ff);
+    RANGE_CHECK(bm.liquid_noswap, 0, 0xffffff, 0x0055ff);
+    RANGE_CHECK(bm.air_maxswap, 0, 0xffffff, 0xff0000);
+    RANGE_CHECK(bm.liquid_maxswap, 0, 0xffffff, 0xaa0000);
+
+    RANGE_CHECK(bm.maxbubbles, 10, 200, 100);
+    RANGE_CHECK(bm.ripples, 0, 1, 0.2);
+    RANGE_CHECK(bm.gravity, 0.005, 0.5, 0.01);
+    RANGE_CHECK(bm.volatility, 0.1, 2, 1.0);
+    RANGE_CHECK(bm.viscosity, 0, 1.0, 0.98);
+    RANGE_CHECK(bm.speed_limit, 0.5, 2, 1.0);
+
+#undef RANGE_CHECK
+
+    /* convert doubles into integer representation */
+    bm.ripples_int = MAKE_INTEGER(bm.ripples);
+    bm.gravity_int = MAKE_INTEGER(bm.gravity);
+    bm.volatility_int = MAKE_INTEGER(bm.volatility);
+    bm.viscosity_int = MAKE_INTEGER(bm.viscosity);
+    bm.speed_limit_int = MAKE_INTEGER(bm.speed_limit);
+}
+
+#undef INT_VAL
+#undef DOUBLE_VAL
+#undef COLOR_VAL
+
+/* *INDENT-OFF* */
+static void print_usage(void)
+{
+    printf( "BubbleMon version "VERSION", features: %s\n"
+	    "Usage: bubblemon [switches] [program_1] [program_2]\n\n"
+	    "Disable compiled-in features\n"
+#ifdef ENABLE_DUCK
+	    " -d\tdisable swimming duck\n"
+#ifdef UPSIDE_DOWN_DUCK
+	    " -u\tdisable upside-down duck\n"
+#endif /* UPSIDE_DOWN_DUCK */
+#endif /* ENABLE_DUCK */
+#ifdef ENABLE_CPU
+	    " -c\tdisable CPU meter\n"
+#endif /* ENABLE_CPU */
+#ifdef ENABLE_MEMSCREEN
+	    " -m\tdisable memory screen\n"
+#endif /* ENABLE_MEMSCREEN */
+	    "\nGeneral options\n"
+#ifdef ENABLE_MEMSCREEN
+	    " -p\tuse alternative color scheme in memory info screen\n"
+	    " -k\tdisplay memory and swap statistics in megabytes\n"
+#endif
+	    " -h\tdisplay this help\n",
+	    options /* this is the global static string with compiled features */
+    );
+}
+/* *INDENT-ON* */
+
+int main(int argc, char **argv)
+{
+    char execute[256];
+    int proximity = 0;
+    int ch;
+#ifdef FPS
+    int f, o;
+    time_t y;
+#endif
+#ifdef PRO
+    int cnt = 25000;
+#endif
+    GdkEvent *event;
+
+#ifdef FPS
+    o = f = y = 0;
+#endif
+
+    /* initialize GDK */
+    if (!gdk_init_check(&argc, &argv)) {
+	fprintf(stderr,
+		"GDK init failed, bye bye.  Check \"DISPLAY\" variable.\n");
+	exit(-1);
+    }
+    gdk_rgb_init();
+
+    /* dynamically generate getopt string depending on compile options
+     * we are going to borrow 256 char string from exec function, and
+     * also build up the "compiled features" string */
+    memset(execute, 0, 256);
+    strcat(execute, "h");	/* help, always in */
+#ifdef ENABLE_DUCK
+    strcat(options, "DUCK ");
+    strcat(execute, "d");
+#ifdef UPSIDE_DOWN_DUCK
+    strcat(options, "INVERT ");
+    strcat(execute, "u");
+#endif				/* UPSIDE_DOWN_DUCK */
+#endif				/* ENABLE_DUCK */
+#ifdef ENABLE_CPU
+    strcat(options, "CPU ");
+    strcat(execute, "c");
+#endif				/* ENABLE_CPU */
+#ifdef ENABLE_MEMSCREEN
+    strcat(options, "MEMSCREEN ");
+    strcat(execute, "pmk");
+#endif				/* ENABLE_MEMSCREEN */
+
+    /* command line options */
+    while ((ch = getopt(argc, argv, execute)) != -1) {
+	switch (ch) {
+#ifdef ENABLE_DUCK
+	case 'd':
+	    duck_enabled = 0;
+	    break;
+#ifdef UPSIDE_DOWN_DUCK
+	case 'u':
+	    upside_down_duck_enabled = 0;
+	    break;
+#endif				/* UPSIDE_DOWN_DUCK */
+#endif				/* ENABLE_DUCK */
+#ifdef ENABLE_CPU
+	case 'c':
+	    cpu_enabled = 0;
+	    break;
+#endif				/* ENABLE_CPU */
+#ifdef ENABLE_MEMSCREEN
+	case 'm':
+	    memscreen_enabled = 0;
+	    break;
+	case 'p':
+	    {
+		/* no sense having -p if memscreen isn't compiled in, right?
+		 * what we are going to do is to change the colors as follows:
+		 * 
+		 * (48,140,240) replaced with (158,196,237) - more pale blue
+		 * (237,23,23) replaced with (0,255,233) */
+		unsigned char *p = mem_screen;
+
+		while (p < mem_screen + sizeof(mem_screen))
+		    if (*p == 48) {	/* hopefully no other colors beginning with 48 */
+			*p++ = 158;
+			*p++ = 196;
+			*p++ = 237;
+		    } else if (*p == 237) {	/* hopefully no other colors beginning with 237 */
+			*p++ = 0;
+			*p++ = 255;
+			*p++ = 233;
+		    } else
+			p += 3;
+
+		p = load_screen;
+
+		while (p < load_screen + sizeof(load_screen))
+		    if (*p == 48) {	/* hopefully no other colors beginning with 48 */
+			*p++ = 158;
+			*p++ = 196;
+			*p++ = 237;
+		    } else
+			p += 3;
+	    }
+	    break;
+	case 'k':
+	    memscreen_megabytes = 1;
+	    break;
+#endif				/* ENABLE_MEMSCREEN */
+	default:
+	    print_usage();
+	    exit(-1);
+	    break;
+	}
+    }
+
+    argc -= optind;
+    argv += optind;
+
+    /* zero data structure */
+    memset(&bm, 0, sizeof(bm));
+
+#ifdef __FreeBSD__
+    if (init_stuff())
+	exit(-1);
+#endif
+
+    /* set default things, from Xresources or compiled-in defaults */
+    bubblemon_session_defaults();
+
+    /* create dockapp window. creates windows, allocates memory, etc */
+    make_new_bubblemon_dockapp();
+
+#ifdef PRO
+    while (cnt--) {
+#else
+    while (1) {
+#endif
+	while (gdk_events_pending()) {
+	    event = gdk_event_get();
+	    if (event) {
+		switch (event->type) {
+		case GDK_DESTROY:
+		    gdk_exit(0);
+		    exit(0);
+		    break;
+		case GDK_BUTTON_PRESS:
+		    if (event->button.button == 3) {
+			bm.picture_lock = 1;
+			break;
+		    }
+		    if (event->button.button <= argc) {
+			snprintf(execute, 250, "%s &",
+				 argv[event->button.button - 1]);
+			system(execute);
+		    }
+		    break;
+#if defined(ENABLE_CPU) || defined(ENABLE_MEMSCREEN)
+		case GDK_ENTER_NOTIFY:
+		    /* mouse in: make it darker, and eventually bring up
+		     * meminfo */
+		    proximity = 1;
+
+		    bm.screen_type = get_screen_selection();
+		    bm.picture_lock = 0;
+		    break;
+		case GDK_LEAVE_NOTIFY:
+		    /* mouse out: back to light */
+		    proximity = 0;
+		    break;
+#endif				/* ENABLE_CPU || ENABLE_MEMSCREEN */
+		default:
+		    break;
+		}
+	    }
+	}
+#ifndef PRO
+	usleep(15000);
+#else
+	/* amazingly enough just calling this function takes insane
+	 * amount of time.
+	 usleep(0); */
+#endif
+	/* get system statistics */
+	get_memory_load_percentage();
+	/* update main rgb buffer: bm.rgb_buf */
+	bubblemon_update(proximity);
+
+/* *INDENT-OFF* */
+#ifdef FPS
+	/* render frames per second on bottom-right corner :)
+	 * This is GCC-specific (functions inside functions)
+	 * and very unoptimized. this is obfuscated 'cause its ugly */
+    	f++;{int b;void q(int sx,int sy,int dx,int dy){int i,j;char *from,*to;
+	for(j=0;j<8;j++){from=mem_screen+56*3*(sy+j)+sx*3;to=bm.rgb_buf+56*3*
+	(dy+j)+dx*3;i=12;while(i--)*to++=*from++;}}b=o;if(b>=100){q((b/100)*4,
+	60,43,46);b=b%100;}q((b/10)*4,60,47,46);q((b%10)*4,60,51,46);}if(time(
+	NULL)!=y){o=f;f=0;y=time(NULL);}
+#endif
+/* *INDENT-ON* */
+
+	/* actually draw the screen */
+#ifndef BLACKBOX
+	gdk_draw_rgb_image(bm.win, bm.gc, 4, 4, 56, 56,
+			   GDK_RGB_DITHER_NONE, bm.rgb_buf, 56 * 3);
+#endif
+	gdk_draw_rgb_image(bm.iconwin, bm.gc, 4, 4, 56, 56,
+			   GDK_RGB_DITHER_NONE, bm.rgb_buf, 56 * 3);
+#ifdef ENABLE_MEMSCREEN
+	/* update graph histories */
+	if (memscreen_enabled)
+	    roll_history();
+#endif				/* ENABLE_MEMSCREEN */
+    }
+    return 0;
+}				/* main */
+
+/*
+ * This determines if the left or right shift keys are depressed.
+ */
+static int get_screen_selection(void)
+{
+    static KeyCode lshift_code, rshift_code;
+    static int first_time = 1;
+    char keys[32];
+
+    if (first_time) {
+	first_time = 0;
+	lshift_code = XKeysymToKeycode(GDK_WINDOW_XDISPLAY(bm.win),
+				       XStringToKeysym("Shift_L"));
+	rshift_code = XKeysymToKeycode(GDK_WINDOW_XDISPLAY(bm.win),
+				       XStringToKeysym("Shift_R"));
+    }
+
+    XQueryKeymap(GDK_WINDOW_XDISPLAY(bm.win), keys);
+
+#if 0
+    if (0) {			/* debug */
+	int i = 0;
+	printf("lshift_code = 0x%x (index = %d, bit = %d\n", lshift_code,
+	       lshift_code >> 3, lshift_code % 8);
+	printf("rshift_code = 0x%x (index = %d, bit = %d\n", rshift_code,
+	       rshift_code >> 3, rshift_code % 8);
+	for (i = 0; i < (sizeof(keys) / sizeof(keys[0])); i++) {
+	    if (0 == (i % 8)) {
+		printf("\n%2d:", i);
+	    }
+	    printf(" %2d", keys[i]);
+	}
+	printf("\n");
+    }
+#endif
+
+    if ((keys[lshift_code >> 3] == (1 << (lshift_code % 8))) ||
+	(keys[rshift_code >> 3] == (1 << (rshift_code % 8)))) {
+	return 0;
+    } else {
+	return 1;
+    }
+}
+
+/* This is the function that actually creates the display widgets */
+static void make_new_bubblemon_dockapp(void)
+{
+#define MASK GDK_BUTTON_PRESS_MASK | \
+    GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK
+
+    GdkWindowAttr attr;
+    GdkWindowAttr attri;
+    Window win;
+    Window iconwin;
+
+    XSizeHints sizehints;
+    XWMHints wmhints;
+
+    attr.width = 64;
+    attr.height = 64;
+    attr.title = "bubblemon";
+    attr.event_mask = MASK;
+    attr.wclass = GDK_INPUT_OUTPUT;
+    attr.visual = gdk_visual_get_system();
+    attr.colormap = gdk_colormap_get_system();
+    attr.wmclass_name = "bubblemon";
+    attr.wmclass_class = "bubblemon";
+    attr.window_type = GDK_WINDOW_TOPLEVEL;
+
+    sizehints.flags = USSize;
+    sizehints.width = 64;
+    sizehints.height = 64;
+
+    bm.win = gdk_window_new(NULL, &attr,
+			    GDK_WA_TITLE | GDK_WA_WMCLASS |
+			    GDK_WA_VISUAL | GDK_WA_COLORMAP);
+    if (!bm.win)
+	fprintf(stderr, "Cannot make toplevel window\n");
+
+    attri.width = 64;
+    attri.height = 64;
+    attri.title = "bubblemon";
+    attri.event_mask = MASK;
+    attri.wclass = GDK_INPUT_OUTPUT;
+    attri.visual = gdk_visual_get_system();
+    attri.colormap = gdk_colormap_get_system();
+    attri.wmclass_name = "bubblemon";
+    attri.wmclass_class = "bubblemon";
+    attri.window_type = GDK_WINDOW_TOPLEVEL;
+
+    bm.iconwin = gdk_window_new(bm.win, &attri,
+				GDK_WA_TITLE | GDK_WA_WMCLASS);
+    if (!bm.iconwin)
+	fprintf(stderr, "Cannot make icon window\n");
+
+    win = GDK_WINDOW_XWINDOW(bm.win);
+    iconwin = GDK_WINDOW_XWINDOW(bm.iconwin);
+    XSetWMNormalHints(GDK_WINDOW_XDISPLAY(bm.win), win, &sizehints);
+
+    wmhints.initial_state = WithdrawnState;
+    wmhints.icon_window = iconwin;
+    wmhints.icon_x = 0;
+    wmhints.icon_y = 0;
+    wmhints.window_group = win;
+    wmhints.flags =
+	StateHint | IconWindowHint | IconPositionHint | WindowGroupHint;
+    XSetWMHints(GDK_WINDOW_XDISPLAY(bm.win), win, &wmhints);
+
+    bm.gc = gdk_gc_new(bm.win);
+
+    bm.pixmap =
+	gdk_pixmap_create_from_xpm_d(bm.win, &(bm.mask), NULL, master_xpm);
+    gdk_window_shape_combine_mask(bm.win, bm.mask, 0, 0);
+    gdk_window_shape_combine_mask(bm.iconwin, bm.mask, 0, 0);
+
+    gdk_window_set_back_pixmap(bm.win, bm.pixmap, False);
+    gdk_window_set_back_pixmap(bm.iconwin, bm.pixmap, False);
+
+    gdk_window_show(bm.win);
+#ifdef KDE_DOCKAPP
+    /* makes the dockapp visible inside KDE wm */
+    gdk_window_show(bm.iconwin);
+#endif
+
+    /* We begin with zero bubbles */
+    bm.n_bubbles = 0;
+
+    /* Allocate memory for calculations */
+    bubblemon_allocate_buffers();
+
+    bubblemon_setup_samples();
+
+    bubblemon_setup_colors();
+#undef MASK
+}				/* make_new_bubblemon_dockapp */
+
+/*
+ * This function, bubblemon_update, gets the CPU usage and updates
+ * the bubble array and main rgb buffer.
+ */
+static void bubblemon_update(int proximity)
+{
+    Bubble *bubbles = bm.bubbles;
+    unsigned int i, loadPercentage, *col, x, y;
+    unsigned char *ptr, *buf, *buf_ptr;
+    unsigned int aircolor, watercolor, aliascolor;
+    unsigned int waterlevels_goal;
+    /*int current_waterlevel_goal; */
+
+    /* These values are for keeping track of where we have to start
+       drawing water. */
+    unsigned int waterlevel_min, waterlevel_max;
+    unsigned int real_waterlevel_min, real_waterlevel_max;
+
+    /* These values are for keeping track how deep the duck is inside water */
+    unsigned int action_min = 56;
+    static unsigned int last_action_min = 0;
+
+    /* Find out the CPU load */
+    loadPercentage = system_cpu();
+
+#ifdef ENABLE_MEMSCREEN
+    /* get loadavg */
+    if (memscreen_enabled)
+	system_loadavg();
+#endif				/* ENABLE_MEMSCREEN */
+
+    /*
+       The buf is made up of ints (0-(NUM_COLORS-1)), each pointing out
+       an entry in the color table.  A pixel in the buf is accessed
+       using the formula buf[row * w + column].
+     */
+
+
+    /* y coordinates are counted from here multiplied by 256 */
+    /* to get actual screen coordinate, divide by 256 */
+    buf = bm.bubblebuf;
+    col = bm.colors;
+
+    waterlevel_max = 0;
+    waterlevel_min = MAKEY(56);
+
+    /* Move the water level with the current memory usage. */
+    waterlevels_goal = MAKEY(56) - ((bm.mem_percent * MAKEY(56)) / 100);
+
+    /* Guard against boundary errors */
+    waterlevels_goal -= (1 << (POWER2 - 1));
+
+    bm.waterlevels[0] = waterlevels_goal;
+    bm.waterlevels[55] = waterlevels_goal;
+
+    for (x = 1; x < 55; x++) {
+	/* Accelerate the current waterlevel towards its correct value */
+	bm.waterlevels_dy[x] +=
+	    (((bm.waterlevels[x - 1] + bm.waterlevels[x + 1] -
+	       2 * bm.waterlevels[x]) * bm.volatility_int) >> (POWER2 +
+							       1));
+
+	bm.waterlevels_dy[x] *= bm.viscosity_int;
+	bm.waterlevels_dy[x] >>= POWER2;
+
+	if (bm.waterlevels_dy[x] > bm.speed_limit_int)
+	    bm.waterlevels_dy[x] = bm.speed_limit_int;
+	else if (bm.waterlevels_dy[x] < -bm.speed_limit_int)
+	    bm.waterlevels_dy[x] = -bm.speed_limit_int;
+    }
+
+    for (x = 1; x < 55; x++) {
+	/* Move the current water level */
+	bm.waterlevels[x] = bm.waterlevels[x] + bm.waterlevels_dy[x];
+
+	if (bm.waterlevels[x] > MAKEY(56)) {
+	    /* Stop the wave if it hits the floor... */
+	    bm.waterlevels[x] = MAKEY(56);
+	    bm.waterlevels_dy[x] = 0;
+	} else if (bm.waterlevels[x] < 0) {
+	    /* ... or the ceiling. */
+	    bm.waterlevels[x] = 0;
+	    bm.waterlevels_dy[x] = 0;
+	}
+	/* Keep track of the highest and lowest water levels */
+	if (bm.waterlevels[x] > waterlevel_max)
+	    waterlevel_max = bm.waterlevels[x];
+	if (bm.waterlevels[x] < waterlevel_min)
+	    waterlevel_min = bm.waterlevels[x];
+    }
+
+    real_waterlevel_min = REALY(waterlevel_min);
+    real_waterlevel_max = REALY(waterlevel_max);
+
+    if (action_min > real_waterlevel_min)
+	action_min = real_waterlevel_min;
+
+    /*
+       Vary the colors of air and water with how many
+       percent of the available swap space that is in use.
+       32 = (99_numcolors / 3) - 1
+     */
+
+    watercolor = ((32 * bm.swap_percent) / 100) * 3;
+    aliascolor = watercolor + 1;
+    aircolor = watercolor + 2;
+
+    /*
+       Draw the air-and-water background
+
+       The waterlevel_max is the HIGHEST VALUE for the water level, which is
+       actually the LOWEST VISUAL POINT of the water.  Confusing enough?
+
+       So we want to draw from top to bottom:
+       Just air from (y == 0) to (y <= waterlevel_min)
+       Mixed air and water from (y == waterlevel_min) to (y <= waterlevel_max)
+       Just water from (y == waterlevel_max) to (y <= h)
+
+       Three loops is more code than one, but should be faster (fewer comparisons)
+     */
+
+    /* Air only */
+    memset(buf, aircolor, real_waterlevel_min * 56);
+
+    /* Air and water */
+    for (x = 0; x < 56; x++) {
+	/* Air... */
+	for (y = real_waterlevel_min;
+	     (signed) y < REALY(bm.waterlevels[x]); y++)
+	    buf[y * 56 + x] = aircolor;
+
+	/* ... and water */
+	for (; y < real_waterlevel_max; y++)
+	    buf[y * 56 + x] = watercolor;
+    }
+
+    /* Water only */
+    memset(buf + real_waterlevel_max * 56, watercolor,
+	   (56 - real_waterlevel_max) * 56);
+
+    /*
+       Here comes the bubble magic.  Pixels are drawn by setting values in
+       buf to 0-NUM_COLORS.
+     */
+
+    /* Create a new bubble if the planets are correctly aligned... */
+    if ((bm.n_bubbles < bm.maxbubbles)
+	&& ((rand() % 101) <= loadPercentage)) {
+	/* We don't allow bubbles on the edges 'cause we'd have to clip them */
+	bubbles[bm.n_bubbles].x = (rand() % 54) + 1;
+	bubbles[bm.n_bubbles].y = MAKEY(56) - 256;
+	bubbles[bm.n_bubbles].dy = 0;
+#ifdef DEBUG_DUCK
+	fprintf (stderr, "new bubble:  bubbles[bm.n_bubbles].x = %i\n",
+			 bubbles[bm.n_bubbles].x);
+#endif
+
+	if (bm.ripples_int != 0) {
+	    /* Raise the water level above where the bubble is created */
+	    if (bubbles[bm.n_bubbles].x > 2)
+		bm.waterlevels[bubbles[bm.n_bubbles].x - 2] -=
+		    bm.ripples_int;
+	    bm.waterlevels[bubbles[bm.n_bubbles].x - 1] -= bm.ripples_int;
+	    bm.waterlevels[bubbles[bm.n_bubbles].x] -= bm.ripples_int;
+	    bm.waterlevels[bubbles[bm.n_bubbles].x + 1] -= bm.ripples_int;
+	    if (bubbles[bm.n_bubbles].x < 53)
+		bm.waterlevels[bubbles[bm.n_bubbles].x + 2] -=
+		    bm.ripples_int;
+	}
+
+	/* Count the new bubble */
+	bm.n_bubbles++;
+    }
+
+    /* Update and draw the bubbles */
+    for (i = 0; i < bm.n_bubbles; i++) {
+	/* Accelerate the bubble */
+	bubbles[i].dy -= bm.gravity_int;
+
+	/* Move the bubble vertically */
+	bubbles[i].y += bubbles[i].dy;
+
+	/* is the bubble grossly out of bounds? */
+	if (bubbles[i].x < 1 || bubbles[i].x > 54 ||
+			bubbles[i].y > MAKEY(56)) {
+#ifdef DEBUG_DUCK
+		fprintf (stderr, "bubble out of bounds "
+				"bubbles[%i].x=%i, bubbles[%i].y=%i\n", 
+				i, bubbles[i].x, i, bubbles[i].y);
+#endif
+		
+	    /* Yes; nuke it */
+	    bubbles[i].x = bubbles[bm.n_bubbles - 1].x;
+	    bubbles[i].y = bubbles[bm.n_bubbles - 1].y;
+	    bubbles[i].dy = bubbles[bm.n_bubbles - 1].dy;
+	    bm.n_bubbles--;
+
+	    /*
+	       We must check the previously last bubble, which is
+	       now the current bubble, also.
+	     */
+	    i--;
+	    continue;
+	}
+		
+	/* Did we lose it? */
+	if (bubbles[i].y < bm.waterlevels[bubbles[i].x]) {
+	    if (bm.ripples_int != 0) {
+		/* Lower the water level around where the bubble is
+		   about to vanish */
+		bm.waterlevels[bubbles[i].x - 1] += bm.ripples_int;
+		bm.waterlevels[bubbles[i].x] += 3 * bm.ripples_int;
+		bm.waterlevels[bubbles[i].x + 1] += bm.ripples_int;
+	    }
+
+	    /* Yes; nuke it */
+	    bubbles[i].x = bubbles[bm.n_bubbles - 1].x;
+	    bubbles[i].y = bubbles[bm.n_bubbles - 1].y;
+	    bubbles[i].dy = bubbles[bm.n_bubbles - 1].dy;
+	    bm.n_bubbles--;
+
+	    /*
+	       We must check the previously last bubble, which is
+	       now the current bubble, also.
+	     */
+	    i--;
+	    continue;
+	}
+
+	/* Draw the bubble */
+	x = bubbles[i].x;
+	y = bubbles[i].y;
+
+	/*
+	   Clipping is not necessary for x, but it *is* for y.
+	   To prevent ugliness, we draw aliascolor only on top of
+	   watercolor, and aircolor on top of aliascolor.
+	 */
+
+	/* Top row */
+	buf_ptr = &(buf[(((REALY(y) - 1) * 56) + 56) + x - 1]);
+	if (y > bm.waterlevels[x]) {
+	    if (*buf_ptr != aircolor) {
+		(*buf_ptr)++;
+	    }
+	    buf_ptr++;
+
+	    *buf_ptr = aircolor;
+	    buf_ptr++;
+
+	    if (*buf_ptr != aircolor) {
+		(*buf_ptr)++;
+	    }
+	    buf_ptr += 54;
+	} else {
+	    buf_ptr += 56;
+	}
+
+	/* Middle row - no clipping necessary */
+	*buf_ptr = aircolor;
+	buf_ptr++;
+	*buf_ptr = aircolor;
+	buf_ptr++;
+	*buf_ptr = aircolor;
+	buf_ptr += 54;
+
+	/* Bottom row */
+	if (y < (MAKEY(56) - 256)) {
+	    if (*buf_ptr != aircolor) {
+		(*buf_ptr)++;
+	    }
+	    buf_ptr++;
+
+	    *buf_ptr = aircolor;
+	    buf_ptr++;
+
+	    if (*buf_ptr != aircolor) {
+		(*buf_ptr)++;
+	    }
+	}
+    }
+
+    /* Drawing magic resides below this point */
+    ptr = bm.rgb_buf;
+    buf_ptr = buf;
+    i = 56 * 56;
+
+    while (i--) {
+	unsigned char *rgb = (unsigned char *) &col[*buf_ptr++];
+#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && (__BYTE_ORDER == __LITTLE_ENDIAN)) || defined(_LITTLE_ENDIAN) || (BYTE_ORDER == LITTLE_ENDIAN)
+	*ptr++ = rgb[2];
+	*ptr++ = rgb[1];
+	*ptr++ = rgb[0];
+#else				/* big-endian. */
+	*ptr++ = rgb[1];
+	*ptr++ = rgb[2];
+	*ptr++ = rgb[3];
+#endif
+    }
+#ifdef ENABLE_DUCK
+    if (duck_enabled) {
+	duck_swimmer((last_action_min <
+		      action_min) ? last_action_min - 14 : action_min -
+		     14);
+    }
+#endif
+
+    /* damn, thats ugly. Of course, the first solution that comes to mind
+     * about this isn't the right one :) */
+#if defined(ENABLE_CPU) && defined(ENABLE_MEMSCREEN)
+    if (cpu_enabled || memscreen_enabled) {
+	realtime_alpha_blend_of_cpu_usage(loadPercentage, proximity);
+    }
+#endif
+#if defined(ENABLE_CPU) && !defined(ENABLE_MEMSCREEN)
+    if (cpu_enabled) {
+	realtime_alpha_blend_of_cpu_usage(loadPercentage, proximity);
+    }
+#endif
+#if !defined(ENABLE_CPU) && defined(ENABLE_MEMSCREEN)
+    if (memscreen_enabled) {
+	realtime_alpha_blend_of_cpu_usage(loadPercentage, proximity);
+    }
+#endif
+
+    /* Remember where we have been poking around this round */
+    last_action_min = action_min;
+}				/* bubblemon_update */
+
+#ifdef ENABLE_MEMSCREEN
+/* draws 4x8 digits for the memory/swap panel */
+static void draw_digit(int srcx, int srcy, int destx, int desty)
+{
+    int i, j;
+    char *from, *to;
+
+    for (j = 0; j < 8; j++) {
+	from = mem_screen + 56 * 3 * (srcy + j) + srcx * 3;
+	to = bm.mem_buf + 56 * 3 * (desty + j) + destx * 3;
+	i = 12;
+	while (i--)
+	    *to++ = *from++;
+    }
+}
+
+/* draws a string using previous function. non-digits and non-K/M = space */
+static void draw_string(char *string, int x, int y, int color)
+{
+    unsigned char c;
+
+    while ((c = *string++)) {
+	if (c == 'K') {
+	    draw_digit(40, (color) ? 69 : 60, x, y);
+	} else if (c == 'M') {
+	    draw_digit(44, (color) ? 69 : 60, x, y);
+	} else if (c == ' ') {
+	    draw_digit(50, 60, x, y);	/* blank space */
+	} else {
+	    c -= '0';
+	    draw_digit(c * 4, (color) ? 69 : 60, x, y);
+	}
+	x += 4;
+    }
+}
+
+static void draw_pixel(unsigned int x, unsigned int y, unsigned char *buf,
+		       unsigned char *c)
+{
+    unsigned char *ptr;
+    ptr = buf + y * 56 * 3 + x * 3 + 6;	/* +6 = x + 2 */
+    *ptr++ = *c++;
+    *ptr++ = *c++;
+    *ptr++ = *c++;
+}
+
+/* draw graph num x size, data taken from history, into rgb buffer buf.
+ * this is called not very often: only 1 time out of 250 */
+static void draw_history(int num, int size, unsigned int *history,
+			 unsigned char *buf)
+{
+    int pixels_per_byte;
+    int j, k;
+    int *p;
+    int d;
+
+    pixels_per_byte = 100;
+    p = history;
+
+    for (j = 0; j < num; j++) {
+	if (p[0] > pixels_per_byte)
+	    pixels_per_byte += 100;
+	p++;
+    }
+
+    p = history;
+
+    for (k = 0; k < num; k++) {
+	d = (1.0 * p[0] / pixels_per_byte) * size;
+
+	for (j = 0; j < size; j++) {
+	    if (j < d - 2)
+		draw_pixel(k, size - j - 1, buf, "\x00\x7d\x71");
+	    else if (j < d)
+		draw_pixel(k, size - j - 1, buf, "\x20\xb6\xae");
+	}
+	p++;
+    }
+
+    for (j = pixels_per_byte - 100; j > 0; j -= 100) {
+	for (k = 0; k < num; k++) {
+	    d = ((float) size / pixels_per_byte) * j;
+	    draw_pixel(k, size - d - 1, buf, "\x71\xe3\x71");
+	}
+    }
+}
+
+/* refreshes memory/swap screen */
+static void render_secondary(void)
+{
+    char percent[4];
+    char number[8];
+    int i;
+    /* mem: 2, 24
+     * mem %: 38, 24
+     * swap: 2, 43
+     * 38, 43
+     * digits: 0, 60 and 0, 69 */
+
+    /* make a clean buffer with blank spaces. */
+    memcpy(bm.mem_buf, bm.screen_type ? load_screen : mem_screen,
+	   56 * 56 * 3);
+
+    if (bm.screen_type) {
+	for (i = 0; i < 3; i++) {
+	    sprintf(number, "%2d", bm.loadavg[i].i);
+	    draw_string(number, 19 * i, 8, 0);
+	    sprintf(number, "%02d", bm.loadavg[i].f);
+	    draw_string(number, 19 * i + 10, 8, 0);
+	}
+	/* copy history graph from previous rollover */
+	memcpy(bm.mem_buf + 19 * 56 * 3, bm.his_bufb, 56 * 33 * 3);
+    } else {
+	/* draw memory */
+	if (memscreen_megabytes)
+	    snprintf(number, 8, "%6lluM", bm.mem_used >> 20);
+	else
+	    snprintf(number, 8, "%6lluK", bm.mem_used >> 10);
+	snprintf(percent, 4, "%03d", bm.mem_percent);
+	draw_string(number, 2, 1, (bm.mem_percent > 90) ? 1 : 0);
+	draw_string(percent, 38, 1, (bm.mem_percent > 90) ? 1 : 0);
+
+	/* draw swap */
+	if (memscreen_megabytes)
+	    snprintf(number, 8, "%6lluM", bm.swap_used >> 20);
+	else
+	    snprintf(number, 8, "%6lluK", bm.swap_used >> 10);
+	snprintf(percent, 4, "%03d", bm.swap_percent);
+	draw_string(number, 2, 10, (bm.swap_percent > 90) ? 1 : 0);
+	draw_string(percent, 38, 10, (bm.swap_percent > 90) ? 1 : 0);
+
+	/* copy history graph from previous rollover */
+	memcpy(bm.mem_buf + 21 * 56 * 3, bm.his_bufa, 56 * 31 * 3);
+    }
+}
+
+static void roll_membuffer(void)
+{
+    static int delay;
+
+    if (++delay < 30)
+	return;
+
+    delay = 0;
+    render_secondary();
+}
+
+static void roll_history(void)
+{
+    unsigned int yep, j;
+    static int update, doit;
+
+    if (doit-- <= 0) {
+	doit = ROLLVALUE;
+	if (update-- <= 0) {
+
+	    /* roll history buffers, averaging last 5 samples */
+	    if (bm.history[52])
+		bm.history[52] /= bm.hisadd;
+
+	    if (bm.memhist[52])
+		bm.memhist[52] /= bm.memadd;
+
+	    for (j = 1; j < 53; j++) {
+		bm.history[j - 1] = bm.history[j];
+		bm.memhist[j - 1] = bm.memhist[j];
+	    }
+	    bm.history[52] = 0;
+	    bm.hisadd = 0;
+	    bm.memhist[52] = 0;
+	    bm.memadd = 0;
+
+	    /* refresh backgrounds */
+	    memcpy(bm.his_bufa, mem_screen + 21 * 56 * 3, 31 * 56 * 3);
+	    memcpy(bm.his_bufb, load_screen + 19 * 56 * 3, 33 * 56 * 3);
+
+	    /* render memory graph */
+	    draw_history(52, 31, bm.memhist, bm.his_bufa);
+	    /* render load average graph */
+	    draw_history(52, 33, bm.history, bm.his_bufb);
+
+	    /* reset counter */
+	    update = 5;
+	}
+
+	/* do load average history update */
+	yep = bm.loadavg[0].f + (bm.loadavg[0].i * 100);
+	bm.history[52] += yep;
+	bm.hisadd++;
+
+	/* do memory history update */
+	yep = bm.mem_percent;
+	bm.memhist[52] += yep;
+	bm.memadd++;
+    }
+}
+#endif				/* ENABLE_MEMSCREEN */
+
+#ifdef ENABLE_CPU
+/* draws digits for the CPU meter. This function is very specific
+ * to the meter.  Arguments it takes are not what they seem initially */
+static void draw_cpudigit(const int what, const int where,
+			  unsigned char *kit)
+{
+    unsigned int len, y;
+    unsigned char *to, *from;
+    for (y = 0; y < 9; y++) {
+	len = 21;
+	to = kit + y * 75 + where;
+	from = digits + y * 285 + what;
+	while (len--)
+	    *to++ = *from++;
+    }
+}
+#endif				/* ENABLE_CPU */
+
+#if defined(ENABLE_CPU) || defined(ENABLE_MEMSCREEN)
+static void realtime_alpha_blend_of_cpu_usage(int cpu, int proximity)
+{
+    /* where is the text going to be (now, bottom-center) */
+#define POSX 16
+#define POSY 46
+    int bob;
+
+    /* memory window */
+    static int blend = MAXBLEND;
+#ifdef ENABLE_MEMSCREEN
+    static int memblend = 256;
+    static int showmem = 0;
+#endif				/* ENABLE_MEMSCREEN */
+#ifdef ENABLE_CPU
+    static int yoh;
+    static int avg;
+    int hibyte, y, pos;
+
+    /* CPU load buffer */
+    static unsigned char kit[25 * 3 * 9 + 1];
+    unsigned char *kitptr;
+
+    /* the plan is simple.  we don't want to redraw the digits every update
+     * because that doesn't look so good.  so we average it, and draw only
+     * once every 10 updates. We alpha blend the static buffer so we still
+     * get cool transparency effects. */
+    avg += cpu;
+
+    while (++yoh > 10) {
+	cpu = avg / 10;
+	avg ^= avg;		/* zero.  Haha, I guess these are not */
+	yoh ^= yoh;		/* register vars, optimizer just zeros them */
+	hibyte = cpu / 10;	/* but it's cool to know it understands xor a, a */
+	if (hibyte == 10) {
+	    draw_cpudigit(18, 0, kit);
+	    draw_cpudigit(0, 18, kit);
+	    draw_cpudigit(0, 36, kit);
+	} else {
+	    draw_cpudigit(216, 0, kit);
+	    draw_cpudigit(hibyte * 18, 18, kit);
+	    draw_cpudigit((cpu % 10) * 18, 36, kit);
+	}
+	/* percent sign is always there */
+	draw_cpudigit(180, 54, kit);
+    }
+#endif				/* ENABLE_CPU */
+    /* sexy fade effect */
+    if (proximity) {
+	blend -= 4;
+	if (blend < MINBLEND) {
+	    blend = MINBLEND;
+#ifdef ENABLE_MEMSCREEN
+	    if (memscreen_enabled) {
+		if (!showmem) {
+		    /* first time here, update memory stats */
+		    render_secondary();
+		}
+		showmem = 1;
+		if (!bm.picture_lock)
+		    memblend -= 6;
+		if (memblend < 40) {
+		    roll_membuffer();
+		    memblend = 40;
+		}
+	    }
+#endif				/* ENABLE_MEMSCREEN */
+	}
+    } else {
+	blend += 4;
+#ifdef ENABLE_MEMSCREEN
+	if (bm.picture_lock)
+	    roll_membuffer();
+
+	if (memscreen_enabled && !bm.picture_lock)
+	    memblend += 10;
+#endif				/* ENABLE_MEMSCREEN */
+	if (blend > MAXBLEND) {
+	    blend = MAXBLEND;
+	}
+#ifdef ENABLE_MEMSCREEN
+	if (memscreen_enabled && memblend > 256) {
+	    memblend = 256;
+	    showmem = 0;
+	}
+#endif				/* ENABLE_MEMSCREEN */
+    }
+
+#ifdef ENABLE_CPU
+    if (cpu_enabled) {
+	/* bit shifts result in smaller and faster code without an extra jns
+	 * which appears if we / 128 instead of >> 7. 
+	 */
+	kitptr = kit;
+	for (y = 0; y < 9; y++) {
+	    unsigned char src;
+	    pos = (y + POSY) * 56 * 3 + (POSX * 3);
+	    bob = 75;		/* 25 * 3 */
+	    while (bob--) {
+		src = bm.rgb_buf[pos];
+
+		if (!src)
+		    bm.rgb_buf[pos++] = *kitptr++;
+		else
+		    bm.rgb_buf[pos++] =
+			(blend * src + (256 - blend) * *kitptr++) >> 8;
+	    }
+	}
+    }
+#endif				/* ENABLE_CPU */
+
+#ifdef ENABLE_MEMSCREEN
+    /* we hovered long enough to print some memory info */
+    if (memscreen_enabled && showmem) {
+	unsigned char *ptr, *ptr2, src;
+	ptr = bm.mem_buf;
+	ptr2 = bm.rgb_buf;
+	bob = 9408;		/* 56 * 56 * 3 */
+	while (bob--) {
+	    src = *ptr2;
+	    *ptr2++ = (memblend * src + (256 - memblend) * *ptr++) >> 8;
+	}
+    }
+#endif				/* ENABLE_MEMSCREEN */
+#undef POSY
+#undef POSX
+}
+#endif
+
+#ifdef ENABLE_DUCK
+static void duck_set(int x, int y, int nr, int rev, int upsidedown)
+{
+    int w, h;
+    int rw;
+#ifdef UPSIDE_DOWN_DUCK
+    int rh;
+#endif
+    int pos;
+    int dw, di, dh, ds;
+    int cmap;			/* index into duck colors */
+#define _R(idx) ((int)duck_cmap[idx][0])
+#define _G(idx) ((int)duck_cmap[idx][1])
+#define _B(idx) ((int)duck_cmap[idx][2])
+#define GETME(x, y, idx) ((int)duck_data[idx][y * 18 + x])
+    ds = 0;
+    if (y < 0)
+	ds = -(y);
+    dh = 17;
+    if ((y + 17) > 56)
+	dh = 56 - y;
+    dw = 18;
+    if (x > 38)
+	dw = 18 - (x - 38);
+    di = 0;
+    if (x < 0)
+	di = -(x);
+    for (h = ds; h < dh; h++) {
+	/* calculate this only once */
+	int ypos = (h + y) * 56;
+#ifdef UPSIDE_DOWN_DUCK
+	rh = (upsidedown && upside_down_duck_enabled) ? 17 - h : h;
+#endif
+	for (w = di; w < dw; w++) {
+	    rw = (rev) ? 17 - w : w;
+#ifdef UPSIDE_DOWN_DUCK
+	    if ((cmap = GETME(rw, rh, nr)) != 0) {
+#else
+	    if ((cmap = GETME(rw, h, nr)) != 0) {
+#endif
+		unsigned char r, g, b;
+		pos = (ypos + w + x) * 3;
+
+		r = _R(cmap);
+		g = _G(cmap);
+		b = _B(cmap);
+
+		/* and now we'll blend the duck part that in water */
+		/* if we use integers here we speed up this function about
+		 * 40%. */
+		if (h + y < REALY(bm.waterlevels[w + x])) {
+		    bm.rgb_buf[pos++] = r;
+		    bm.rgb_buf[pos++] = g;
+		    bm.rgb_buf[pos] = b;
+		} else {
+		    bm.rgb_buf[pos] = (DUCKBLEND * (int) bm.rgb_buf[pos]
+				       + (256 - DUCKBLEND) * (int) r) >> 8;
+		    bm.rgb_buf[pos + 1] =
+			(DUCKBLEND * (int) bm.rgb_buf[pos + 1]
+			 + (256 - DUCKBLEND) * (int) g) >> 8;
+		    bm.rgb_buf[pos + 2] =
+			(DUCKBLEND * (int) bm.rgb_buf[pos + 2]
+			 + (256 - DUCKBLEND) * (int) b) >> 8;
+		}
+	    }
+	}
+    }
+#undef _R
+#undef _G
+#undef _B
+#undef GETME
+}
+
+static int animate_correctly(void)
+{
+    /* returns the correct order of framenumber 0,1,2,1,0,1,2...
+       instead of 0,1,2,0,1,2 <- this way the duck looks really ugly
+       instead of keeping 2 counters we just made it longer */
+
+    static int outp[48] =
+	{ 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0,
+	1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2,
+	2, 2, 1, 1, 1, 1
+    };
+    static int totalcounter = -1;
+
+    if (++totalcounter > 47)
+	totalcounter = 0;
+
+    return outp[totalcounter];
+}
+
+static void duck_swimmer(int posy)
+{
+    static int tx = -19;
+    static int rp;
+    static int rev = 1;
+    static int upsidedown = 0;
+
+#ifdef UPSIDE_DOWN_DUCK
+    /* dive */
+    if (upside_down_duck_enabled) {
+	if (upsidedown == 0 && posy < 2)
+	    upsidedown = 1;
+	else if (upsidedown == 1 && posy > 5)	/* jump out */
+	    upsidedown = 0;
+
+	if (upsidedown)
+	    posy += 10;
+    }
+#endif
+    if (rp++ < 10) {
+	duck_set(tx, posy, animate_correctly(), rev, upsidedown);
+	return;
+    }
+
+    rp = 0;
+    if (!rev) {
+	if (tx-- < -18) {
+	    tx = -18;
+	    rev = 1;
+	}
+    } else {
+	if (tx++ > 57) {
+	    tx = 57;
+	    rev = 0;
+	}
+    }
+    duck_set(tx, posy, animate_correctly(), rev, upsidedown);
+}
+#endif				/* ENABLE_DUCK */
+
+static void bubblemon_setup_samples(void)
+{
+    int i;
+    u_int64_t load = 0, total = 0;
+
+    if (bm.load) {
+	load = bm.load[bm.loadIndex];
+	free(bm.load);
+    }
+
+    if (bm.total) {
+	total = bm.total[bm.loadIndex];
+	free(bm.total);
+    }
+
+    bm.loadIndex = 0;
+    bm.load = malloc(bm.samples * sizeof(u_int64_t));
+    bm.total = malloc(bm.samples * sizeof(u_int64_t));
+    for (i = 0; i < bm.samples; i++) {
+	bm.load[i] = load;
+	bm.total[i] = total;
+    }
+}
+
+static void bubblemon_setup_colors(void)
+{
+#define NUM_COLORS 99
+    int i, j, *col;
+    int r_air_noswap, g_air_noswap, b_air_noswap;
+    int r_liquid_noswap, g_liquid_noswap, b_liquid_noswap;
+    int r_air_maxswap, g_air_maxswap, b_air_maxswap;
+    int r_liquid_maxswap, g_liquid_maxswap, b_liquid_maxswap;
+    int actual_colors = NUM_COLORS / 3;
+
+    if (!bm.colors)
+	bm.colors = malloc(NUM_COLORS * sizeof(int));
+
+    col = bm.colors;
+
+    r_air_noswap = (bm.air_noswap >> 16) & 0xff;
+    g_air_noswap = (bm.air_noswap >> 8) & 0xff;
+    b_air_noswap = (bm.air_noswap) & 0xff;
+
+    r_liquid_noswap = (bm.liquid_noswap >> 16) & 0xff;
+    g_liquid_noswap = (bm.liquid_noswap >> 8) & 0xff;
+    b_liquid_noswap = (bm.liquid_noswap) & 0xff;
+
+    r_air_maxswap = (bm.air_maxswap >> 16) & 0xff;
+    g_air_maxswap = (bm.air_maxswap >> 8) & 0xff;
+    b_air_maxswap = (bm.air_maxswap) & 0xff;
+
+    r_liquid_maxswap = (bm.liquid_maxswap >> 16) & 0xff;
+    g_liquid_maxswap = (bm.liquid_maxswap >> 8) & 0xff;
+    b_liquid_maxswap = (bm.liquid_maxswap) & 0xff;
+
+    for (i = 0; i < actual_colors; i++) {
+	int r, g, b;
+	int r_composite, g_composite, b_composite;
+
+	j = i >> 1;
+
+	/* Liquid */
+	r = (r_liquid_maxswap * j +
+	     r_liquid_noswap * ((actual_colors - 1) -
+				j)) / (actual_colors - 1);
+	g = (g_liquid_maxswap * j +
+	     g_liquid_noswap * ((actual_colors - 1) -
+				j)) / (actual_colors - 1);
+	b = (b_liquid_maxswap * j +
+	     b_liquid_noswap * ((actual_colors - 1) -
+				j)) / (actual_colors - 1);
+
+	r_composite = r;
+	g_composite = g;
+	b_composite = b;
+	col[(i * 3)] = (r << 16) | (g << 8) | b;
+
+	/* Air */
+	r = (r_air_maxswap * j +
+	     r_air_noswap * ((actual_colors - 1) - j)) / (actual_colors -
+							  1);
+	g = (g_air_maxswap * j +
+	     g_air_noswap * ((actual_colors - 1) - j)) / (actual_colors -
+							  1);
+	b = (b_air_maxswap * j +
+	     b_air_noswap * ((actual_colors - 1) - j)) / (actual_colors -
+							  1);
+	r_composite += r;
+	g_composite += g;
+	b_composite += b;
+	col[(i * 3) + 2] = (r << 16) | (g << 8) | b;
+
+	/* Anti-alias */
+	r = r_composite >> 1;
+	g = g_composite >> 1;
+	b = b_composite >> 1;
+	col[(i * 3) + 1] = (r << 16) | (g << 8) | b;
+    }
+#undef NUM_COLORS
+}
+
+static void bubblemon_allocate_buffers(void)
+{
+    int i;
+
+    /* storage for bubbles */
+    bm.bubbles = (Bubble *) malloc(sizeof(Bubble) * bm.maxbubbles);
+
+    /* Allocate (zeroed) bubble memory */
+    if (bm.bubblebuf)
+	free(bm.bubblebuf);
+
+    bm.bubblebuf = calloc(56 * 60, sizeof(char));
+
+    /* Allocate water level memory */
+    if (bm.waterlevels)
+	free(bm.waterlevels);
+
+    bm.waterlevels = malloc(56 * sizeof(int));
+    for (i = 0; i < 56; i++) {
+	bm.waterlevels[i] = MAKEY(56);
+    }
+
+    /* Allocate water level velocity memory */
+    if (bm.waterlevels_dy)
+	free(bm.waterlevels_dy);
+
+    bm.waterlevels_dy = calloc(56, sizeof(int));
+}
+
+static void get_memory_load_percentage(void)
+{
+    /* system_memory() will return true on initial run so that we get
+     * correct memory info, but may subsequently return 0 if memory
+     * is not changing */
+    if (system_memory()) {
+	/* new memory/swap data is in, calculate things */
+	bm.mem_percent = (100 * bm.mem_used) / bm.mem_max;
+
+	if (bm.swap_max != 0) {
+	    bm.swap_percent = (100 * bm.swap_used) / bm.swap_max;
+	} else {
+	    bm.swap_percent = 0;
+	}
+    }
+}
+
+/* ex:set ts=8: */
diff --git a/doc/COPYING b/doc/COPYING
new file mode 100644
index 0000000..6d23ef0
--- /dev/null
+++ b/doc/COPYING
@@ -0,0 +1,3 @@
+#include <GPL.v2>
+On a Debian system, you can find the GPL license in
+/usr/share/common-licenses/GPL
diff --git a/doc/Xdefaults.sample b/doc/Xdefaults.sample
new file mode 100644
index 0000000..f1d5544
--- /dev/null
+++ b/doc/Xdefaults.sample
@@ -0,0 +1,12 @@
+! BubbleMon settings 
+! vim: syntax=xdefaults
+bubblemon.maxbubbles: 100
+bubblemon.air_noswap: #2299FF
+bubblemon.air_maxswap: #FF0000
+bubblemon.liquid_noswap: #0055FF
+bubblemon.liquid_maxswap: #AA0000
+bubblemon.ripples: 0.2
+bubblemon.gravity: 0.01
+bubblemon.volatility: 1.0
+bubblemon.viscosity: 0.98
+bubblemon.speed_limit: 1.0
diff --git a/include/bubblemon.h b/include/bubblemon.h
new file mode 100644
index 0000000..1c25016
--- /dev/null
+++ b/include/bubblemon.h
@@ -0,0 +1,139 @@
+/*  BubbleMon dockapp 1.2
+ *  
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef _BUBBLEMON_H_
+#define _BUBBLEMON_H_
+
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+
+/* CPU load alpha-blending: smaller values = ligher text
+ * minblend = mouseout
+ * maxblend = mousein 
+ * min = 0
+ * max = 128 */
+#if defined(ENABLE_CPU) || defined(ENABLE_MEMSCREEN)
+# define MINBLEND 80
+# define MAXBLEND 190
+#endif
+
+#ifdef ENABLE_DUCK
+#define DUCKBLEND 100
+#endif
+
+#define MULTIPLIER 4096.0
+#define POWER2 12
+#define REALY(y) ((y) >> POWER2)
+#define MAKEY(y) ((y) << POWER2)
+#define MAKE_INTEGER(x) ((int)((x)*MULTIPLIER+0.5))
+#define ROLLVALUE 100		/* frequency of history rollover */
+
+#ifdef sun
+#include <sys/types.h>
+#if defined (uint64_t)
+  typedef uint64_t u_int64_t;
+#else
+  typedef unsigned long long u_int64_t;
+#endif /* defined (uint64_t) */
+#endif
+
+typedef struct {
+    int x;			/* Horizontal coordinate */
+    int y;			/* Vertical coordinate   */
+    int dy;			/* Vertical velocity     */
+} Bubble;
+
+typedef struct {
+	int i;			/* integer part */
+	int f;			/* fractional part */
+} LoadAvg;
+
+typedef struct {
+    /* X11 stuff */
+    Display *display;
+    GdkWindow *win;		/* main window */
+    GdkWindow *iconwin;		/* icon window */
+    GdkGC *gc;			/* drawing GC */
+    GdkPixmap *pixmap;		/* main dockapp pixmap */
+    GdkBitmap *mask;		/* dockapp mask */
+
+    /* main image buffer */
+    unsigned char rgb_buf[56 * 56 * 3 + 1];
+
+#ifdef ENABLE_MEMSCREEN
+    /* memory / swap screen buffer */
+    unsigned char mem_buf[56 * 56 * 3 + 1];
+    /* memory screen graph buffer */
+    unsigned char his_bufa[56 * 31 * 3 + 1];
+    /* loadavg screen graph buffer */
+    unsigned char his_bufb[56 * 33 * 3 + 1];
+
+    int screen_type;		/* 0 - memory, 1 - cpu */
+    int picture_lock;		/* blend coeff not changed when this is not 0 */
+#endif
+
+    /* bubble stuff */
+    int samples;
+    unsigned char *bubblebuf;
+    int *colors;
+    int *waterlevels;
+    int *waterlevels_dy;
+    Bubble *bubbles;
+    int n_bubbles;
+
+    /* Color definitions */
+    int air_noswap, liquid_noswap, air_maxswap, liquid_maxswap;
+
+    /* CPU percentage stuff.  soon to go away */
+    int loadIndex;
+    u_int64_t *load, *total;
+
+    /* various params */
+    int maxbubbles;		/* max bubbles number */
+    double ripples;		/* Do we make ripples on the surface after bubbles? */
+    double gravity;		/* How fast do the bubbles rise? */
+    double volatility;		/* How fast do the water levels accelerate? */
+    double viscosity;		/* 0.0 means the liquid never moves.
+				   1.0 means the liquid will continue to oscillate forever. */
+    double speed_limit;		/* How fast are the water levels allowed to move? */
+
+    /* stuff above in integer format */
+    int ripples_int;
+    int gravity_int;
+    int volatility_int;
+    int viscosity_int;
+    int speed_limit_int;
+
+    /* system stuff. Moved here because various places need it */
+    u_int64_t mem_used;
+    u_int64_t mem_max;
+    u_int64_t swap_used;
+    u_int64_t swap_max;
+    unsigned int swap_percent;	/* swap used, in percent */
+    unsigned int mem_percent;	/* memory used, in percent */
+    /* history of memory use */
+    unsigned int memhist[53];
+    unsigned int memadd;
+
+    /* loadavg stuff */
+    LoadAvg loadavg[3];
+    /* history of loadavgs */
+    unsigned int history[53];
+    unsigned int hisadd;
+} BubbleMonData;
+#endif				/* _BUBBLEMON_H_ */
diff --git a/include/digits.h b/include/digits.h
new file mode 100644
index 0000000..9f0f852
--- /dev/null
+++ b/include/digits.h
@@ -0,0 +1,81 @@
+/* digits for the CPU counter */
+unsigned char digits[95 * 9 * 3 + 1] =
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\40\260\254\40\260\254\40\260\254\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0}"
+  "q\0\0\0\0\0\0\0}q\40\260\254\40\260\254\40\260\254\0}q\0\0\0\0}q\40\260\254"
+  "\40\260\254\40\260\254\0}q\0\0\0\0}q\0\0\0\0\0\0\0\0\0\0}q\0\0\0\0}q\40\260"
+  "\254\40\260\254\40\260\254\0}q\0\0\0\0}q\40\260\254\40\260\254\40\260\254"
+  "\0}q\0\0\0\0}q\40\260\254\40\260\254\40\260\254\0}q\0\0\0\0}q\40\260\254"
+  "\40\260\254\40\260\254\0}q\0\0\0\0}q\40\260\254\40\260\254\40\260\254\0}"
+  "q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\40\260\254\0\0\0\0\0\0\0\0\0\40\260\254\0\0\0\0\0\0\0\0\0\0\0\0\40\260\254"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\40\260\254\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\40\260\254\0\0\0\40\260\254\0\0\0\0\0\0\0\0\0\40\260\254\0\0\0\40\260"
+  "\254\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\40\260\254\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\40\260\254\0\0\0\40\260\254\0\0\0\0\0\0\0\0\0"
+  "\40\260\254\0\0\0\40\260\254\0\0\0\0\0\0\0\0\0\40\260\254\0\0\0\40\260\254"
+  "\0\0\0\0\0\0\0\0\0\40\260\254\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\40\260\254"
+  "\0\0\0\0\0\0\0\0\0\40\260\254\0\0\0\0\0\0\0\0\0\0\0\0\40\260\254\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\40\260\254\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\40"
+  "\260\254\0\0\0\40\260\254\0\0\0\0\0\0\0\0\0\40\260\254\0\0\0\40\260\254\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\40\260\254\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\40\260\254\0\0\0\40\260\254\0\0\0\0\0\0\0\0\0\40\260"
+  "\254\0\0\0\40\260\254\0\0\0\0\0\0\0\0\0\40\260\254\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\40\260\254\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0}q\0\0\0\0\0\0\0"
+  "\0\0\0}q\0\0\0\0\0\0\0\0\0\0\0\0\0}q\0\0\0\0\0\0\0}q\40\260\254\40\260\254"
+  "\40\260\254\0}q\0\0\0\0\0\0\40\260\254\40\260\254\40\260\254\0}q\0\0\0\0"
+  "}q\40\260\254\40\260\254\40\260\254\0}q\0\0\0\0}q\40\260\254\40\260\254\40"
+  "\260\254\0}q\0\0\0\0}q\40\260\254\40\260\254\40\260\254\0}q\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0}q\0\0\0\0IA\40\260\254\40\260\254\40\260\254\0IA\0\0\0"
+  "\0}q\40\260\254\40\260\254\40\260\254\0}q\0\0\0\0\0\0\0\0\0\40\260\254\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\40\260\254\0\0\0\0\0\0\0\0"
+  "\0\40\260\254\0\0\0\0\0\0\0\0\0\0\0\0\40\260\254\0\0\0\0\0\0\40\260\254\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\40\260\254\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\40\260\254\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\40\260\254"
+  "\0\0\0\40\260\254\0\0\0\0\0\0\0\0\0\40\260\254\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\40\260\254\0\0\0\40\260\254\0\0\0\0\0\0\0\0\0\40\260\254\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\40\260\254\0\0\0\0\0\0\40\260\254\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\40\260\254\0\0\0\0\0\0\0\0\0\40\260\254"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\40\260\254\0\0\0\0\0\0\40\260\254\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\40\260\254\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\40\260\254\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\40\260\254\0\0\0\40\260"
+  "\254\0\0\0\0\0\0\0\0\0\40\260\254\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\40\260\254"
+  "\0\0\0\40\260\254\0\0\0\0\0\0\0\0\0\40\260\254\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\40\260\254\0\0\0\40\260\254\0\0\0\0\0\0\0\0\0\40\260\254\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\40\260\254\40\260\254\40\260\254\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\40\260\254\0\0\0\0\0\0\0}q\40\260\254\40\260\254\40"
+  "\260\254\0}q\0\0\0\0}q\40\260\254\40\260\254\40\260\254\0}q\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0}q\0\0\0\0}q\40\260\254\40\260\254\40\260\254\0}q\0\0\0"
+  "\0}q\40\260\254\40\260\254\40\260\254\0}q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "}q\0\0\0\0}q\40\260\254\40\260\254\40\260\254\0}q\0\0\0\0}q\40\260\254\40"
+  "\260\254\40\260\254\0}q\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0";
diff --git a/include/ducks.h b/include/ducks.h
new file mode 100644
index 0000000..b09559b
--- /dev/null
+++ b/include/ducks.h
@@ -0,0 +1,59 @@
+static char duck_cmap[4][3] = {
+	{ 32,152,248},
+	{248,252,  0},
+	{248,176, 64},
+	{  0,  0,  0}
+	};
+static int duck_data[3][306] = {
+       {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,1,1,1,1,0,0,0,0,0,0,0,0,
+	0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,
+	0,2,2,2,1,3,1,1,1,1,0,0,0,0,0,0,0,0,
+	0,0,2,2,1,1,1,1,1,1,0,0,0,0,0,0,0,0,
+	0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,1,1,0,1,1,1,1,0,0,0,0,0,
+	0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,
+	0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,
+	0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
+	0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,
+	0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,
+	0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,
+	0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,
+	0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,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,1,1,1,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,
+	0,2,2,2,1,3,1,1,1,1,0,0,0,0,0,0,0,0,
+	0,0,2,2,1,1,1,1,1,1,0,0,0,0,0,0,0,0,
+	0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,
+	0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,
+	0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
+	0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,
+	0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,
+	0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,
+	0,0,0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,
+	0,0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+       {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,1,1,1,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,
+	0,0,2,2,2,1,3,1,1,1,1,0,0,0,0,0,0,0,
+	0,0,0,2,2,1,1,1,1,1,1,0,0,0,0,0,0,0,
+	0,0,0,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,
+	0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,
+	0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,
+	0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,
+	0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,
+	0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
+	0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,
+	0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,
+	0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,
+	0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,
+	0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0}
+};
diff --git a/include/load_screen.h b/include/load_screen.h
new file mode 100644
index 0000000..0f3cb72
--- /dev/null
+++ b/include/load_screen.h
@@ -0,0 +1,464 @@
+unsigned char load_screen[56 * 80 * 3 + 1] =
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\300\303\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\300\303"
+  "\0\300\303\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\300\303\0\0\0\0\300\303\0\300"
+  "\303\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\300\303\0\300\303\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\300"
+  "\303\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\300\303\0\300\303\0\0\0\0\300\303\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\300\303\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\300\303"
+  "\0\300\303\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\300\303\0\0\0\0\300\303\0\300"
+  "\303\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\300\303\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\300"
+  "\303\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\300\303\0\0\0\0\0\0\0\300\303\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\300\303\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\300\303\0\300\303"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\300\303\0\0\0\0\300\303\0\300\303\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""0\212\356"
+  "0\212\3560\212\356\0\0\0""0\212\3560\212\3560\212\356\0\0\0\0\0\0\0\0\0""0"
+  "\212\3560\212\3560\212\356\0\0\0""0\212\3560\212\3560\212\356\0\0\0\0\0\0"
+  """0\212\3560\212\3560\212\356\0\0\0""0\212\3560\212\3560\212\356\0\0\0\0"
+  "\0\0\0\0\0""0\212\3560\212\3560\212\356\0\0\0""0\212\3560\212\3560\212\356"
+  "\0\0\0\0\0\0""0\212\3560\212\3560\212\356\0\0\0""0\212\3560\212\3560\212"
+  "\356\0\0\0\0\0\0\0\0\0""0\212\3560\212\3560\212\356\0\0\0""0\212\3560\212"
+  "\3560\212\356\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0"
+  "\212\356\0\0\0\0\0\0\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0\212\356\0"
+  "\0\0""0\212\356\0\0\0\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0\212\356"
+  "\0\0\0""0\212\356\0\0\0\0\0\0\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0"
+  "\212\356\0\0\0""0\212\356\0\0\0\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0"
+  "\212\356\0\0\0""0\212\356\0\0\0\0\0\0\0\0\0""0\212\356\0\0\0""0\212\356\0"
+  "\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0"
+  """0\212\356\0\0\0""0\212\356\0\0\0\0\0\0\0\0\0""0\212\356\0\0\0""0\212\356"
+  "\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0\0\0\0""0\212\356\0\0\0""0\212\356"
+  "\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0\0\0\0\0\0\0""0\212\356\0\0\0""0"
+  "\212\356\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0\0\0\0""0\212\356\0\0\0""0"
+  "\212\356\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0\0\0\0\0\0\0""0\212\356\0"
+  "\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0"
+  """0\212\356\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0\0\0\0\0\0\0""0\212\356"
+  "\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0\0\0\0""0\212\356"
+  "\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0\0\0\0\0\0\0""0"
+  "\212\356\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0\0\0\0""0"
+  "\212\356\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0\0\0\0\0"
+  "\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0"
+  """0\212\356\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0\0\0"
+  "\0\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0\212\356\0"
+  "\0\0\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0\212\356"
+  "\0\0\0\0\0\0\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0"
+  "\212\356\0\0\0\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0"
+  "\212\356\0\0\0\0\0\0\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0\212\356\0"
+  "\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0"
+  """0\212\356\0\0\0\0\0\0\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0\212\356"
+  "\0\0\0""0\212\356\0\0\0\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0\212\356"
+  "\0\0\0""0\212\356\0\0\0\0\0\0\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0"
+  "\212\356\0\0\0""0\212\356\0\0\0\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0"
+  "\212\356\0\0\0""0\212\356\0\0\0\0\0\0\0\0\0""0\212\356\0\0\0""0\212\356\0"
+  "\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0"
+  """0\212\356\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0\212"
+  "\356\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0\0\0\0""0\212\356\0\0\0""0\212"
+  "\356\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0\212\356"
+  "\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0\0\0\0""0\212\356"
+  "\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0\212\356\0\0"
+  "\0""0\212\356\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0\212\356\0\0\0""0"
+  "\212\3560\212\3560\212\356\0\0\0""0\212\3560\212\3560\212\356\0\0\0""0\212"
+  "\356\0\0\0""0\212\3560\212\3560\212\356\0\0\0""0\212\3560\212\3560\212\356"
+  "\0\0\0\0\0\0""0\212\3560\212\3560\212\356\0\0\0""0\212\3560\212\3560\212"
+  "\356\0\0\0""0\212\356\0\0\0""0\212\3560\212\3560\212\356\0\0\0""0\212\356"
+  "0\212\3560\212\356\0\0\0\0\0\0""0\212\3560\212\3560\212\356\0\0\0""0\212"
+  "\3560\212\3560\212\356\0\0\0""0\212\356\0\0\0""0\212\3560\212\3560\212\356"
+  "\0\0\0""0\212\3560\212\3560\212\356\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0""0\212\3560\212\3560\212\3560\212\3560\212\356"
+  "0\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\356"
+  "0\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\356"
+  "0\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\356"
+  "0\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\356"
+  "0\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\356"
+  "0\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\356\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\0\0\0\0\0\0\0\0\0\0\0\0\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6"
+  "*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\0\0\0\0\0\0\0\0\0\0\0\0\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\0\0\0\0\0\0\0\0\0\0\0\0\6*\0\6*\0\6*\0\6*\0\6*\0\6"
+  "*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0"
+  "\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6"
+  "*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0"
+  "\6*\0\6*\0\6*\0\0\0\0\0\0\0\0\0\0\0\0\0\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6"
+  "*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\0\0\0\0\0\0\0\0\0\0\0\0\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\0\0\0\0\0\0\0\0\0\0\0\0\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6"
+  "*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\0\0\0\0\0\0\0\0\0\0\0\0\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*"
+  "\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0"
+  "\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6"
+  "*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\0\0\0\0\0\0\0\0\0\0\0\0\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\0\0\0\0\0\0\0\0\0\0\0\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\0\0\0\0\0\0\0\0\0\0\0\0\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\0\0\0\0\0\0\0\0\0\0\0\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6"
+  "*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0"
+  "\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6"
+  "*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0"
+  "\6*\0\0\0\0\0\0\0\0\0\0\0\0\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6"
+  "*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\0\0\0\0\0\0\0\0\0\0\0\0\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\0\0\0\0\0\0\0\0\0\0\0\0\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6"
+  "*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\0\0\0\0\0\0\0\0\0\0\0\0\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\0\0\0\0\0\0\0\0\0\0\0\0\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6"
+  "*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\0\0\0\0\0\0\0\0\0\0\0\0\6*\0\6"
+  "*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0"
+  "\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6"
+  "*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0"
+  "\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\0\0\0\0\0\0\0\0\0\0\0\0\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\0\0\0\0\0\0\0\0\0\0\0\0\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""0\212\3560\212\3560\212\3560\212"
+  "\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212"
+  "\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212"
+  "\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212"
+  "\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212"
+  "\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212"
+  "\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212"
+  "\356\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\376\376\376\376\376\376\376\376"
+  "\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376"
+  "\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376"
+  "\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376"
+  "\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376"
+  "\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376"
+  "\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376"
+  "\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376"
+  "\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376"
+  "\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""0\213\357"
+  "0\213\3570\213\357\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213\3570\213\357"
+  "0\213\357\0\0\0""0\213\3570\213\3570\213\357\0\0\0\0\0\0\0\0\0""0\213\357"
+  "\0\0\0""0\213\3570\213\3570\213\357\0\0\0""0\213\3570\213\3570\213\357\0"
+  "\0\0""0\213\3570\213\3570\213\357\0\0\0""0\213\3570\213\3570\213\357\0\0"
+  "\0""0\213\3570\213\3570\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""0"
+  "\213\357\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213\357\0"
+  "\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0"
+  """0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213"
+  "\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357"
+  "\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0""0\213\357\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0\0\0\0\0"
+  "\0\0""0\213\357\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213"
+  "\357\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0"
+  "\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0"
+  "\213\357\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0"
+  "\0\0\0\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357"
+  "\0\0\0\0\0\0\0\0\0""0\213\3570\213\3570\213\357\0\0\0\0\0\0\0\0\0""0\213"
+  "\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357"
+  "\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213\357\0\0"
+  "\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213\3570\213\3570\213\357\0\0\0\0\0\0"
+  """0\213\3570\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\3570"
+  "\213\3570\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0""0"
+  "\213\357\0\0\0""0\213\3570\213\3570\213\357\0\0\0""0\213\357\0\0\0""0\213"
+  "\357\0\0\0""0\213\3570\213\357\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213\357\0"
+  "\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0""0\213\357\0\0\0""0\213\3570\213\3570\213\357\0\0\0\0\0\0\0\0\0""0\213"
+  "\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0"
+  """0\213\357\0\0\0""0\213\357\0\0\0""0\213\3570\213\3570\213\357\0\0\0""0"
+  "\213\357\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0\0\0\0\0"
+  "\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0"
+  """0\213\357\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357"
+  "\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0"
+  "\213\357\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213\357\0"
+  "\0\0""0\213\357\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0""0\213\3570\213\3570\213\357\0\0\0\0\0\0\0\0\0""0\213"
+  "\357\0\0\0""0\213\3570\213\3570\213\357\0\0\0""0\213\3570\213\3570\213\357"
+  "\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213\3570\213\3570\213\357\0\0\0""0"
+  "\213\3570\213\3570\213\357\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213\357"
+  "0\213\3570\213\357\0\0\0""0\213\3570\213\3570\213\357\0\0\0""0\213\357\0"
+  "\0\0""0\213\357\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\354"
+  "\27\27\354\27\27\354\27\27\0\0\0\0\0\0\0\0\0\354\27\27\0\0\0\354\27\27\354"
+  "\27\27\354\27\27\0\0\0\354\27\27\354\27\27\354\27\27\0\0\0\0\0\0\0\0\0\354"
+  "\27\27\0\0\0\354\27\27\354\27\27\354\27\27\0\0\0\354\27\27\354\27\27\354"
+  "\27\27\0\0\0\354\27\27\354\27\27\354\27\27\0\0\0\354\27\27\354\27\27\354"
+  "\27\27\0\0\0\354\27\27\354\27\27\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\0\0\0\0\0\0\354\27\27\0\0\0\354\27"
+  "\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0"
+  "\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27"
+  "\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354"
+  "\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\354\27\27\0"
+  "\0\0\354\27\27\0\0\0\0\0\0\0\0\0\354\27\27\0\0\0\0\0\0\0\0\0\354\27\27\0"
+  "\0\0\0\0\0\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27"
+  "\0\0\0\0\0\0\0\0\0\354\27\27\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\354\27\27\0\0"
+  "\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27"
+  "\27\0\0\0\354\27\27\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\0\0\0\0\0\0\354"
+  "\27\27\0\0\0\0\0\0\0\0\0\354\27\27\0\0\0\0\0\0\0\0\0\354\27\27\0\0\0\354"
+  "\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\0\0\0\0\0\0\354\27\27\354\27"
+  "\27\354\27\27\0\0\0\0\0\0\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27"
+  "\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\354"
+  "\27\27\0\0\0\354\27\27\0\0\0\0\0\0\0\0\0\354\27\27\0\0\0\354\27\27\354\27"
+  "\27\354\27\27\0\0\0\0\0\0\354\27\27\354\27\27\0\0\0\354\27\27\0\0\0\354\27"
+  "\27\0\0\0\354\27\27\354\27\27\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0"
+  "\0\0\0\0\0\0\0\0\354\27\27\0\0\0\354\27\27\354\27\27\354\27\27\0\0\0\354"
+  "\27\27\0\0\0\354\27\27\0\0\0\354\27\27\354\27\27\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\354\27\27\0"
+  "\0\0\354\27\27\0\0\0\0\0\0\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\354\27\27\0\0\0\354\27\27\354\27\27\354\27\27\0\0\0\0\0"
+  "\0\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\0\0\0\0\0\0\354"
+  "\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\354\27\27\354\27\27"
+  "\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\0"
+  "\0\0\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0"
+  "\0\354\27\27\0\0\0\0\0\0\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27"
+  "\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\0\0\0\0\0\0\354\27\27\0\0\0\354\27"
+  "\27\0\0\0\354\27\27\0\0\0\0\0\0\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354"
+  "\27\27\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\354\27\27\354\27\27\354\27\27\0\0\0\0\0\0\0\0\0\354\27\27\0"
+  "\0\0\354\27\27\354\27\27\354\27\27\0\0\0\354\27\27\354\27\27\354\27\27\0"
+  "\0\0\0\0\0\0\0\0\354\27\27\0\0\0\354\27\27\354\27\27\354\27\27\0\0\0\354"
+  "\27\27\354\27\27\354\27\27\0\0\0\0\0\0\0\0\0\354\27\27\0\0\0\354\27\27\354"
+  "\27\27\354\27\27\0\0\0\354\27\27\354\27\27\354\27\27\0\0\0\354\27\27\0\0"
+  "\0\354\27\27\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0";
diff --git a/include/master.xpm b/include/master.xpm
new file mode 100644
index 0000000..4941a88
--- /dev/null
+++ b/include/master.xpm
@@ -0,0 +1,71 @@
+/* XPM */
+static char * master_xpm[] = {
+"64 64 4 1",
+" 	c None",
+".	c #000000",
+"+	c #2299FF",
+"@	c #ABBAC6",
+"                                                                ",
+"                                                                ",
+"                                                                ",
+"   ..........................................................   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   .++++++++++++++++++++++++++++++++++++++++++++++++++++++++@   ",
+"   @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@   ",
+"                                                                ",
+"                                                                ",
+"                                                                "};
diff --git a/include/mem_screen.h b/include/mem_screen.h
new file mode 100644
index 0000000..12f62ea
--- /dev/null
+++ b/include/mem_screen.h
@@ -0,0 +1,466 @@
+unsigned char mem_screen[56 * 80 * 3 + 1] =
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  """0\213\357\0\0\0""0\213\3570\213\3570\213\357\0\0\0""0\213\3570\213\357"
+  "0\213\357\0\0\0""0\213\3570\213\3570\213\357\0\0\0""0\213\3570\213\3570\213"
+  "\357\0\0\0""0\213\3570\213\3570\213\357\0\0\0""0\213\357\0\0\0""0\213\357"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""0\213\3570\213\357"
+  "0\213\357\0\0\0""0\213\3570\213\3570\213\357\0\0\0""0\213\3570\213\3570\213"
+  "\357\0\0\0""0\213\357\0\0\0\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0\0\0\0""0\213"
+  "\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357"
+  "\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0"
+  "\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0"
+  "\213\357\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""0\213\357"
+  "\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0"
+  "\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0""0\213"
+  "\357\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213"
+  "\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357"
+  "\0\0\0\0\0\0\300\303\0\300\303\0\300\303\0\300\303\0\0\0\0\0\0\0\0\0\0""0"
+  "\213\357\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213\357\0"
+  "\0\0""0\213\357\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0""0\213"
+  "\3570\213\3570\213\357\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213\357\0\0"
+  "\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0"
+  "\213\357\0\0\0\0\0\0\300\303\0\0\0\0\300\303\0\0\0\0\300\303\0\0\0\0\0\0"
+  "\0""0\213\357\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213"
+  "\357\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\3570\213\3570\213\357\0"
+  "\0\0""0\213\357\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213"
+  "\3570\213\3570\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357"
+  "0\213\357\0\0\0\0\0\0\0\0\0\300\303\0\0\0\0\300\303\0\0\0\0\300\303\0\0\0"
+  "\0\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0"
+  "\213\3570\213\3570\213\357\0\0\0\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0""0\213\3570\213\3570\213\357\0\0\0\0\0\0\0\0\0""0\213\357\0"
+  "\0\0""0\213\357\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213"
+  "\357\0\0\0""0\213\357\0\0\0""0\213\3570\213\3570\213\357\0\0\0""0\213\357"
+  "\0\0\0""0\213\357\0\0\0\0\0\0\300\303\0\0\0\0\300\303\0\0\0\0\300\303\0\0"
+  "\0\0\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0"
+  """0\213\357\0\0\0""0\213\357\0\0\0\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0"
+  "\0\0""0\213\357\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213"
+  "\357\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0"
+  """0\213\357\0\0\0\0\0\0\300\303\0\0\0\0\300\303\0\0\0\0\300\303\0\0\0\0\0"
+  "\0\0""0\213\357\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213"
+  "\357\0\0\0""0\213\357\0\0\0\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213\3570\213\3570\213\357\0"
+  "\0\0""0\213\3570\213\3570\213\357\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213"
+  "\3570\213\3570\213\357\0\0\0""0\213\3570\213\3570\213\357\0\0\0""0\213\357"
+  "\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""0"
+  "\213\3570\213\3570\213\357\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213\357"
+  "0\213\3570\213\357\0\0\0""0\213\357\0\0\0\0\0\0""0\213\357\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""0\213\3570\213\3570\213\357\0\0\0""0"
+  "\213\357\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0""0\213\3570\213\3570\213\357\0\0\0""0\213\3570\213\3570\213\357\0"
+  "\0\0""0\213\3570\213\3570\213\357\0\0\0""0\213\357\0\0\0\0\0\0""0\213\357"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  """0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213\357"
+  "\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0"
+  "\0""0\213\357\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0"
+  "\213\357\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0\300\303\0\300\303\0\300\303\0"
+  "\300\303\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0"
+  """0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0""0\213\357"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0"
+  "\0\0\0\0\300\303\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0"
+  "\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213"
+  "\357\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0"
+  """0\213\3570\213\357\0\0\0\0\0\0\0\0\0\0\0\0\300\303\0\300\303\0\300\303"
+  "\0\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0"
+  "\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0\0\0\0""0\213\357\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\300\303\0\0\0\0\0\0\0""0\213\357\0\0\0""0"
+  "\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213"
+  "\357\0\0\0\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0"
+  """0\213\357\0\0\0""0\213\357\0\0\0\0\0\0\300\303\0\300\303\0\300\303\0\300"
+  "\303\0\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0"
+  "\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0\0\0\0""0\213\357\0"
+  "\0\0""0\213\357\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0""0\213\3570\213\3570\213\357\0\0\0""0\213\357\0\0\0""0\213"
+  "\357\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""0\213\3570\213"
+  "\3570\213\357\0\0\0""0\213\3570\213\3570\213\357\0\0\0""0\213\3570\213\357"
+  "0\213\357\0\0\0""0\213\357\0\0\0\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""0\212\3560\212\3560\212"
+  "\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212"
+  "\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212"
+  "\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212"
+  "\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212"
+  "\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212"
+  "\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212"
+  "\3560\212\356\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\0\0\0\0\0\0\0\0\0\0\0\0\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\0\0\0\0\0\0\0\0\0\0\0\0\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6"
+  "*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0"
+  "\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6"
+  "*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\0\0\0\0\0\0\0\0\0\0\0\0\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\0\0\0\0\0\0\0\0\0\0\0\0\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6"
+  "*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\0\0\0\0\0\0\0\0\0\0\0\0\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\0\0\0\0\0\0\0\0\0\0\0\0\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6"
+  "*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\0\0\0\0\0\0\0\0\0\0\0\0\6*\0\6*\0\6*\0\6*\0\6*\0"
+  "\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6"
+  "*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0"
+  "\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6"
+  "*\0\6*\0\6*\0\6*\0\0\0\0\0\0\0\0\0\0\0\0\0\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\0\0\0\0\0\0\0\0\0\0\0\0\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6"
+  "*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\0\0\0\0\0\0\0\0\0\0\0\0\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\0\0\0\0\0\0\0\0\0\0\0\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6"
+  "*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\0\0\0\0\0\0\0\0\0\0\0\0\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0"
+  "\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6"
+  "*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0"
+  "\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\0\0\0\0\0\0\0\0\0\0\0\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6"
+  "*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\0\0\0\0\0\0\0\0\0\0\0\0\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\0\0\0\0\0\0\0\0\0\0\0\0\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6"
+  "*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\0\0\0\0\0\0\0\0\0\0\0\0\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\0\0\0\0\0\0\0\0\0\0\0\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*"
+  "\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0"
+  "\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6"
+  "*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0\6*\0"
+  "\6*\0\6*\0\0\0\0\0\0\0\0\0\0\0\0\0\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6"
+  "*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\0\0\0\0\0\0\0\0\0\0\0\0\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\40\40\40\40\40\40\40\40\6*\0\40\40\40\40\40\40\40\40\40\40"
+  "\40\40\40\40\40\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0""0\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212"
+  "\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212"
+  "\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212"
+  "\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212"
+  "\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212"
+  "\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212\3560\212"
+  "\3560\212\3560\212\3560\212\3560\212\3560\212\356\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376"
+  "\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376"
+  "\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376"
+  "\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376"
+  "\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376"
+  "\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376"
+  "\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376"
+  "\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376"
+  "\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376\376"
+  "\376\376\376\376\376\376\376\376\376\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""0\213\3570\213\3570\213\357\0\0\0\0"
+  "\0\0\0\0\0""0\213\357\0\0\0""0\213\3570\213\3570\213\357\0\0\0""0\213\357"
+  "0\213\3570\213\357\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213\3570\213\357"
+  "0\213\357\0\0\0""0\213\3570\213\3570\213\357\0\0\0""0\213\3570\213\3570\213"
+  "\357\0\0\0""0\213\3570\213\3570\213\357\0\0\0""0\213\3570\213\3570\213\357"
+  "\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213"
+  "\357\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0"
+  """0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213"
+  "\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357"
+  "\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0"
+  "\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\3570\213\357"
+  "0\213\357\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""0\213\357"
+  "\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0""0\213\357"
+  "\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0"
+  "\213\357\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""0\213"
+  "\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357"
+  "\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\3570\213\3570\213\357\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213"
+  "\357\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0\0\0"
+  "\0\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0"
+  "\0\0\0\0\0\0\0\0""0\213\3570\213\3570\213\357\0\0\0\0\0\0\0\0\0""0\213\357"
+  "\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0"
+  "\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213\357"
+  "\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213\3570\213\3570\213\357\0\0\0\0"
+  "\0\0""0\213\3570\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357"
+  "0\213\3570\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0""0"
+  "\213\357\0\0\0""0\213\3570\213\3570\213\357\0\0\0""0\213\357\0\0\0""0\213"
+  "\357\0\0\0""0\213\3570\213\357\0\0\0\0\0\0""0\213\357\0\0\0""0\213\357\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0"
+  "\213\357\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0""0\213\357\0\0\0""0\213\3570\213\3570\213\357\0\0\0\0\0\0\0"
+  "\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0""0\213"
+  "\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\3570\213\3570\213\357"
+  "\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213"
+  "\357\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0"
+  """0\213\357\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213\357"
+  "\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0""0"
+  "\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0\0\0\0\0\0\0""0\213\357\0"
+  "\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0""0\213\3570\213\3570\213"
+  "\357\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213\3570\213\3570\213\357\0\0"
+  "\0""0\213\3570\213\3570\213\357\0\0\0\0\0\0\0\0\0""0\213\357\0\0\0""0\213"
+  "\3570\213\3570\213\357\0\0\0""0\213\3570\213\3570\213\357\0\0\0\0\0\0\0\0"
+  "\0""0\213\357\0\0\0""0\213\3570\213\3570\213\357\0\0\0""0\213\3570\213\357"
+  "0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213\357\0\0\0""0\213"
+  "\357\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\354\27\27\354\27\27\354\27\27\0\0\0\0"
+  "\0\0\0\0\0\354\27\27\0\0\0\354\27\27\354\27\27\354\27\27\0\0\0\354\27\27"
+  "\354\27\27\354\27\27\0\0\0\0\0\0\0\0\0\354\27\27\0\0\0\354\27\27\354\27\27"
+  "\354\27\27\0\0\0\354\27\27\354\27\27\354\27\27\0\0\0\354\27\27\354\27\27"
+  "\354\27\27\0\0\0\354\27\27\354\27\27\354\27\27\0\0\0\354\27\27\354\27\27"
+  "\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\354\27\27\0\0\0\354"
+  "\27\27\0\0\0\0\0\0\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0"
+  "\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27"
+  "\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354"
+  "\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0"
+  "\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\354\27\27\354\27\27\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\354\27\27\0\0\0\354\27\27"
+  "\0\0\0\0\0\0\0\0\0\354\27\27\0\0\0\0\0\0\0\0\0\354\27\27\0\0\0\0\0\0\0\0"
+  "\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\0\0\0"
+  "\0\0\0\354\27\27\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\354\27\27\0\0\0\354\27\27"
+  "\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354"
+  "\27\27\0\0\0\354\27\27\354\27\27\354\27\27\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\0\0\0\0\0\0\354"
+  "\27\27\0\0\0\0\0\0\0\0\0\354\27\27\0\0\0\0\0\0\0\0\0\354\27\27\0\0\0\354"
+  "\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\0\0\0\0\0\0\354\27\27\354\27"
+  "\27\354\27\27\0\0\0\0\0\0\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27"
+  "\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354"
+  "\27\27\0\0\0\354\27\27\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\354\27\27\0\0\0\354\27\27\0\0\0\0\0\0\0\0\0\354\27\27\0\0\0\354\27\27"
+  "\354\27\27\354\27\27\0\0\0\0\0\0\354\27\27\354\27\27\0\0\0\354\27\27\0\0"
+  "\0\354\27\27\0\0\0\354\27\27\354\27\27\354\27\27\0\0\0\354\27\27\0\0\0\354"
+  "\27\27\0\0\0\0\0\0\0\0\0\354\27\27\0\0\0\354\27\27\354\27\27\354\27\27\0"
+  "\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\354\27\27\0\0\0\0\0\0\354"
+  "\27\27\0\0\0\354\27\27\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\354\27\27\0\0\0\354\27\27\0\0\0\0\0\0\0\0\0\354\27\27\0\0\0\354\27\27"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\354\27\27\0\0\0\354\27\27\354\27\27\354\27"
+  "\27\0\0\0\0\0\0\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\0\0"
+  "\0\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\354\27"
+  "\27\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27"
+  "\27\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\354\27\27\0\0\0"
+  "\354\27\27\0\0\0\0\0\0\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0"
+  "\0\0\354\27\27\0\0\0\354\27\27\0\0\0\0\0\0\0\0\0\354\27\27\0\0\0\354\27\27"
+  "\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\0\0\0\0\0\0\354\27"
+  "\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\0\0\0\0\0\0\354\27\27\0\0\0\354"
+  "\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\354\27\27\354\27\27\354\27\27\0\0\0"
+  "\0\0\0\0\0\0\354\27\27\0\0\0\354\27\27\354\27\27\354\27\27\0\0\0\354\27\27"
+  "\354\27\27\354\27\27\0\0\0\0\0\0\0\0\0\354\27\27\0\0\0\354\27\27\354\27\27"
+  "\354\27\27\0\0\0\354\27\27\354\27\27\354\27\27\0\0\0\0\0\0\0\0\0\354\27\27"
+  "\0\0\0\354\27\27\354\27\27\354\27\27\0\0\0\354\27\27\354\27\27\354\27\27"
+  "\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\354\27\27\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+  "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
+
diff --git a/include/sys_include.h b/include/sys_include.h
new file mode 100644
index 0000000..8597fbd
--- /dev/null
+++ b/include/sys_include.h
@@ -0,0 +1,31 @@
+/*  BubbleMon dockapp 1.2
+ *  
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef _SYS_INCLUDE_H_
+#define _SYS_INCLUDE_H_
+
+/* these routines must be written for each new platform */
+int system_cpu(void);		/* return total CPU load in percent */
+int system_memory(void);	/* set memory related values in BubbleMonData
+				   and return 1, or return 0 if memory didn't
+				   change */
+#ifdef ENABLE_MEMSCREEN
+void system_loadavg(void);	/* get current load average and put into
+				   bm->loadavg[].{i,f} */
+#endif
+#endif /* _SYS_INCLUDE_H_ */
diff --git a/misc/load_1.1.xcf b/misc/load_1.1.xcf
new file mode 100644
index 0000000..b3a11aa
Binary files /dev/null and b/misc/load_1.1.xcf differ
diff --git a/misc/mem_1.1.xcf b/misc/mem_1.1.xcf
new file mode 100644
index 0000000..d44f1ef
Binary files /dev/null and b/misc/mem_1.1.xcf differ
diff --git a/misc/wak.wav b/misc/wak.wav
new file mode 100644
index 0000000..6b3f4c4
Binary files /dev/null and b/misc/wak.wav differ
diff --git a/misc/wakwak.sh b/misc/wakwak.sh
new file mode 100644
index 0000000..3ee379d
--- /dev/null
+++ b/misc/wakwak.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+play wak.wav > /dev/null
+play wak.wav > /dev/null
diff --git a/sys_freebsd.c b/sys_freebsd.c
new file mode 100644
index 0000000..4ae0de0
--- /dev/null
+++ b/sys_freebsd.c
@@ -0,0 +1,210 @@
+/*  BubbleMon dockapp 1.2 - FreeBSD specific code
+ *  Copyright (C) 2001, oleg dashevskii <od at iclub.nsu.ru>
+ *  
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <kvm.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/dkstat.h>
+#include <sys/vmmeter.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/sysctl.h>
+#include <vm/vm_param.h>
+#include <time.h>
+#include "include/bubblemon.h"
+#include "include/sys_include.h"
+
+extern BubbleMonData bm;
+
+static kvm_t *kd = NULL;
+static struct nlist nlst[] = {
+    {"_cp_time", 0},
+    {"_cnt", 0},
+    {"_bufspace", 0},
+    {0, 0}
+};
+static int pageshift;
+
+#define pagetob(size) ((size) << pageshift)
+
+int init_stuff()
+{
+    /* calculate page shift to convert pages into kilobytes */
+    int pagesize = getpagesize();
+    pageshift = 0;
+
+    while (pagesize > 1) {
+	pageshift++;
+	pagesize >>= 1;
+    }
+
+    /* open kernel memory */
+    kd = kvm_open(NULL, NULL, NULL, O_RDONLY, "kvm_open");
+
+    if (kd == NULL) {
+	puts("Could not open kernel virtual memory");
+	return 1;
+    }
+
+    kvm_nlist(kd, nlst);
+
+    if (nlst[0].n_type == 0 || nlst[1].n_type == 0 || nlst[2].n_type == 0) {
+	puts("Error extracting symbols");
+	return 2;
+    }
+
+    /* drop setgid & setuid (the latter should not be there really) */
+    seteuid(getuid());
+    setegid(getgid());
+
+    if (geteuid() != getuid() || getegid() != getgid()) {
+	puts("Unable to drop privileges");
+	return 3;
+    }
+
+    return 0;
+}
+
+/* Returns the current CPU load in percent */
+int system_cpu(void)
+{
+    int loadPercentage;
+    int previous_total, previous_load;
+    int total, load;
+    unsigned long int cpu_time[CPUSTATES];
+    int i;
+
+    if (kvm_read(kd, nlst[0].n_value, &cpu_time, sizeof(cpu_time))
+	!= sizeof(cpu_time))
+	return 0;
+
+    load = cpu_time[CP_USER] + cpu_time[CP_SYS] + cpu_time[CP_NICE];
+    total = load + cpu_time[CP_IDLE];
+
+    i = bm.loadIndex;
+    previous_load = bm.load[i];
+    previous_total = bm.total[i];
+
+    bm.load[i] = load;
+    bm.total[i] = total;
+    bm.loadIndex = (i + 1) % bm.samples;
+
+    if (previous_total == 0)
+	loadPercentage = 0;	/* first time here */
+    else
+	if (total == previous_total)
+	    loadPercentage = 100;
+    	else
+	    loadPercentage = (100 * (load - previous_load)) /
+	    	(total - previous_total);
+
+    return loadPercentage;
+}
+
+int system_memory(void)
+{
+    u_int64_t my_mem_used, my_mem_max;
+    u_int64_t my_swap_used, my_swap_max;
+    struct vmmeter sum;
+    int bufspace;
+    static int swappgsin = -1;
+    static int swappgsout = -1;
+    static int swap_firsttime = 1;
+    static int swapavail = 0, swapused = 0;
+    static time_t last_time_swap = 0;
+    time_t curr_time;
+	
+    if (kvm_read(kd, nlst[1].n_value, &sum, sizeof(sum)) != sizeof(sum))
+	return 0;		/* _cnt */
+
+    if (kvm_read(kd, nlst[2].n_value, &bufspace, sizeof(bufspace)) !=
+	sizeof(bufspace))
+	return 0;		/* _bufspace */
+
+    my_mem_max = pagetob((u_int64_t) sum.v_page_count);
+    my_mem_used = pagetob((u_int64_t) sum.v_active_count);
+
+    /* only calculate when first time or when changes took place */
+    /* do not call it more than 1 time per 2 seconds */
+    /* otherwise it can eat up to 50% of CPU time on heavy swap activity */
+    curr_time = time(NULL);
+    
+    if (swap_firsttime ||
+	(((sum.v_swappgsin > swappgsin) || (sum.v_swappgsout > swappgsout)) &&
+	curr_time > last_time_swap + 1)) {
+	
+	struct kvm_swap swap;
+	int n;
+
+	swapavail = 0;
+	swapused = 0;
+
+	n = kvm_getswapinfo(kd, &swap, 1, 0);
+	if (n >= 0 && swap.ksw_total != 0) {
+	    swapavail = pagetob(swap.ksw_total);
+	    swapused = pagetob(swap.ksw_used);
+	}
+
+	swap_firsttime = 0;
+	last_time_swap = curr_time;
+    }
+
+    my_swap_used = swapused;
+    my_swap_max = swapavail;
+
+    swappgsin = sum.v_swappgsin;
+    swappgsout = sum.v_swappgsout;
+
+    bm.mem_used = my_mem_used;
+    bm.mem_max = my_mem_max;
+    bm.swap_used = my_swap_used;
+    bm.swap_max = my_swap_max;
+    return 1;
+}
+
+#ifdef ENABLE_MEMSCREEN
+void system_loadavg(void)
+{
+    static int avg_delay;
+
+    if (avg_delay-- <= 0) {
+	struct loadavg loadinfo;
+        int i, mib[2];
+	size_t size;
+
+	mib[0] = CTL_VM;
+	mib[1] = VM_LOADAVG;
+	size = sizeof (loadinfo);
+	
+	if (sysctl(mib, 2, &loadinfo, &size, NULL, 0) >= 0)
+	    for (i = 0; i < 3; i++) {
+	    	bm.loadavg[i].i = loadinfo.ldavg[i] / loadinfo.fscale;
+	    	bm.loadavg[i].f = ((loadinfo.ldavg[i] * 100 + 
+			loadinfo.fscale / 2) / loadinfo.fscale) % 100;
+	    }
+
+	avg_delay = ROLLVALUE;
+    }
+}
+#endif				/* ENABLE_MEMSCREEN */
+
+/* ex:set ts=8: */
diff --git a/sys_linux.c b/sys_linux.c
new file mode 100644
index 0000000..0aaeb7a
--- /dev/null
+++ b/sys_linux.c
@@ -0,0 +1,176 @@
+/*  BubbleMon dockapp 1.2 - Linux specific code
+ *  Copyright 2000, 2001 timecop at japan.co.jp
+ *  
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "include/bubblemon.h"
+#include "include/sys_include.h"
+
+extern BubbleMonData bm;
+
+/* returns current CPU load in percent, 0 to 100 */
+int system_cpu(void)
+{
+    unsigned int cpuload;
+    u_int64_t load, total, oload, ototal;
+    u_int64_t ab, ac, ad, ae;
+    int i;
+    FILE *stat;
+
+    stat = fopen("/proc/stat", "r");
+    fscanf(stat, "%*s %Ld %Ld %Ld %Ld", &ab, &ac, &ad, &ae);
+    fclose(stat);
+
+    /* Find out the CPU load */
+    /* user + sys = load
+     * total = total */
+    load = ab + ac + ad;	/* cpu.user + cpu.sys; */
+    total = ab + ac + ad + ae;	/* cpu.total; */
+
+    /* "i" is an index into a load history */
+    i = bm.loadIndex;
+    oload = bm.load[i];
+    ototal = bm.total[i];
+
+    bm.load[i] = load;
+    bm.total[i] = total;
+    bm.loadIndex = (i + 1) % bm.samples;
+
+    /*
+       Because the load returned from libgtop is a value accumulated
+       over time, and not the current load, the current load percentage
+       is calculated as the extra amount of work that has been performed
+       since the last sample. yah, right, what the fuck does that mean?
+     */
+    if (ototal == 0)		/* ototal == 0 means that this is the first time
+				   we get here */
+	cpuload = 0;
+    else if ((total - ototal) <= 0)
+	cpuload = 100;
+    else
+	cpuload = (100 * (load - oload)) / (total - ototal);
+
+    return cpuload;
+}
+
+int system_memory(void)
+{
+    u_int64_t my_mem_used, my_mem_max;
+    u_int64_t my_swap_used, my_swap_max;
+#ifdef KERNEL_26
+    char *p;
+#endif
+
+    static int mem_delay = 0;
+    FILE *mem;
+    static u_int64_t aa, ab, ac, ad;
+#ifndef KERNEL_26
+    static u_int64_t ae, af, ag, ah;
+#endif
+    /* put this in permanent storage instead of stack */
+    static char shit[2048];
+
+    /* we might as well get both swap and memory at the same time.
+     * sure beats opening the same file twice */
+    if (mem_delay-- <= 0) {
+#ifdef KERNEL_26
+	mem = fopen("/proc/meminfo", "r");
+	memset(shit, 0, sizeof(shit));
+	fread(shit, 2048, 1, mem);
+	p = strstr(shit, "MemTotal");
+	if (p) {
+	    sscanf(p, "MemTotal:%Ld", &aa);
+	    my_mem_max = aa << 10;
+
+	    p = strstr(p, "Active");
+	    if (p) {
+		sscanf(p, "Active:%Ld", &ab);
+		my_mem_used = ab << 10;
+
+		p = strstr(p, "SwapTotal");
+		if (p) {
+		    sscanf(p, "SwapTotal:%Ld", &ac);
+		    my_swap_max = ac << 10;
+
+		    p = strstr(p, "SwapFree");
+		    if (p) {
+			sscanf(p, "SwapFree:%Ld", &ad);
+			my_swap_used = my_swap_max - (ad << 10);
+
+			bm.mem_used = my_mem_used;
+			bm.mem_max = my_mem_max;
+			bm.swap_used = my_swap_used;
+			bm.swap_max = my_swap_max;
+		    }
+		}
+	    }
+	}
+	fclose(mem);
+	mem_delay = 25;
+#else
+	mem = fopen("/proc/meminfo", "r");
+	fgets(shit, 2048, mem);
+	
+	fscanf(mem, "%*s %Ld %Ld %Ld %Ld %Ld %Ld", &aa, &ab, &ac,
+	       &ad, &ae, &af);
+	fscanf(mem, "%*s %Ld %Ld", &ag, &ah);
+	fclose(mem);
+	mem_delay = 25;
+
+	/* calculate it */
+	my_mem_max = aa;	/* memory.total; */
+	my_swap_max = ag;	/* swap.total; */
+
+	my_mem_used = ah + ab - af - ae;	/* swap.used + memory.used - memory.cached - memory.buffer; */
+
+	if (my_mem_used > my_mem_max) {
+	    my_swap_used = my_mem_used - my_mem_max;
+	    my_mem_used = my_mem_max;
+	} else {
+	    my_swap_used = 0;
+	}
+
+	bm.mem_used = my_mem_used;
+	bm.mem_max = my_mem_max;
+	bm.swap_used = my_swap_used;
+	bm.swap_max = my_swap_max;
+#endif
+
+	/* memory info changed - update things */
+	return 1;
+    }
+    /* nothing new */
+    return 0;
+}
+
+#ifdef ENABLE_MEMSCREEN
+void system_loadavg(void)
+{
+    FILE *avg;
+    static int avg_delay;
+    if (avg_delay-- <= 0) {
+	avg = fopen("/proc/loadavg", "r");
+	fscanf(avg, "%d.%d %d.%d %d.%d", &bm.loadavg[0].i, &bm.loadavg[0].f,
+		&bm.loadavg[1].i, &bm.loadavg[1].f,
+		&bm.loadavg[2].i, &bm.loadavg[2].f);
+	fclose(avg);
+	avg_delay = ROLLVALUE;
+    }
+}
+#endif				/* ENABLE_MEMSCREEN */
diff --git a/sys_netbsd.c b/sys_netbsd.c
new file mode 100644
index 0000000..c80ba19
--- /dev/null
+++ b/sys_netbsd.c
@@ -0,0 +1,132 @@
+/*  BubbleMon dockapp 1.2 - NetBSD specific code
+ *  Copyright (C) 2001, Peter Stromberg <wilfried at openbsd.org>
+ *  
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/dkstat.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/resource.h>
+#include <sys/sched.h>
+
+#include <uvm/uvm_object.h>
+#include <uvm/uvm_extern.h>
+#include <sys/swap.h>
+
+#include "include/bubblemon.h"
+#include "include/sys_include.h"
+
+extern BubbleMonData bm;
+
+/* Returns the current CPU load in percent */
+int system_cpu(void)
+{
+	int loadPercentage;
+	int previous_total, previous_load;
+	int total, load;
+	long cpu_time[40];
+	int i;
+
+	int mib[] = { CTL_KERN, KERN_CP_TIME };
+	size_t size;
+
+	size = sizeof (cpu_time);
+
+	if (sysctl(mib, 2, &cpu_time, &size, NULL, 0) < 0)
+	return 0;
+
+	load = cpu_time[CP_USER] + cpu_time[CP_SYS] + cpu_time[CP_NICE];
+	total = load + cpu_time[CP_IDLE];
+
+	i = bm.loadIndex;
+	previous_load = bm.load[i];
+	previous_total = bm.total[i];
+
+	bm.load[i] = load;
+	bm.total[i] = total;
+	bm.loadIndex = (i + 1) % bm.samples;
+
+	if (previous_total == 0)
+		loadPercentage = 0;	/* first time here */
+	/* Ok, this is ugly. Return 0 unless at least 3 clock cycles have been
+	 * performed since last check. Flattens the data considerably, but otherwise
+	 * we get really ugly zick-zack loads all the time. */
+	else if ((total == previous_total) || (total == previous_total + 1) || (total == previous_total + 2))
+		loadPercentage = 0;
+	else
+		loadPercentage = (100 * (load - previous_load)) / (total - previous_total);
+
+	return loadPercentage;
+}
+
+int system_memory(void)
+{
+#define pagetob(size) ((size) << (uvmexp.pageshift))
+	struct uvmexp uvmexp;
+	int nswap, rnswap, i;
+	int mib[] = { CTL_VM, VM_UVMEXP };
+	size_t size = sizeof (uvmexp);
+
+	if (sysctl(mib, 2, &uvmexp, &size, NULL, 0) < 0)
+		return 0;
+
+	bm.mem_used = pagetob(uvmexp.active);
+	bm.mem_max = pagetob(uvmexp.npages);
+	bm.swap_used = 0;
+	bm.swap_max = 0;
+	if ((nswap = swapctl(SWAP_NSWAP, 0, 0)) != 0) {
+		struct swapent *swdev = malloc(nswap * sizeof(*swdev));
+		if((rnswap = swapctl(SWAP_STATS, swdev, nswap)) != nswap) {
+			for (i = 0; i < nswap; i++) {
+				if (swdev[i].se_flags & SWF_ENABLE) {
+					bm.swap_used += (swdev[i].se_inuse / (1024 / DEV_BSIZE));
+					bm.swap_max += (swdev[i].se_nblks / (1024 / DEV_BSIZE));
+				}
+			}
+		}
+		free(swdev);
+	}
+
+	return 1;
+}
+
+#ifdef ENABLE_MEMSCREEN
+void system_loadavg(void)
+{
+	static int avg_delay;
+
+	if (avg_delay-- <= 0) {
+		struct loadavg loadinfo;
+		int i;
+		int mib[] = { CTL_VM, VM_LOADAVG };
+		size_t size = sizeof (loadinfo);
+
+		if (sysctl(mib, 2, &loadinfo, &size, NULL, 0) >= 0)
+			for (i = 0; i < 3; i++) {
+				bm.loadavg[i].i = loadinfo.ldavg[i] / loadinfo.fscale;
+				bm.loadavg[i].f = ((loadinfo.ldavg[i] * 100 + 
+				loadinfo.fscale / 2) / loadinfo.fscale) % 100;
+			}
+
+		avg_delay = ROLLVALUE;
+	}
+}
+#endif				/* ENABLE_MEMSCREEN */
+
+/* ex:set sw=4 ts=4: */
diff --git a/sys_openbsd.c b/sys_openbsd.c
new file mode 100644
index 0000000..a07ee72
--- /dev/null
+++ b/sys_openbsd.c
@@ -0,0 +1,130 @@
+/*  BubbleMon dockapp 1.2 - OpenBSD specific code
+ *  Copyright (C) 2001, Peter Stromberg <wilfried at openbsd.org>
+ *  
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/dkstat.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/resource.h>
+
+#include <uvm/uvm_object.h>
+#include <uvm/uvm_extern.h>
+#include <sys/swap.h>
+
+#include "include/bubblemon.h"
+#include "include/sys_include.h"
+
+extern BubbleMonData bm;
+
+/* Returns the current CPU load in percent */
+int system_cpu(void)
+{
+	int loadPercentage;
+	int previous_total, previous_load;
+	int total, load;
+	long cpu_time[CPUSTATES];
+	int i;
+
+	int mib[2];
+	size_t size;
+
+	mib[0] = CTL_KERN;
+	mib[1] = KERN_CPTIME;
+	size = sizeof (cpu_time);
+
+	if (sysctl(mib, 2, &cpu_time, &size, NULL, 0) < 0)
+	return 0;
+
+	load = cpu_time[CP_USER] + cpu_time[CP_SYS] + cpu_time[CP_NICE];
+	total = load + cpu_time[CP_IDLE];
+
+	i = bm.loadIndex;
+	previous_load = bm.load[i];
+	previous_total = bm.total[i];
+
+	bm.load[i] = load;
+	bm.total[i] = total;
+	bm.loadIndex = (i + 1) % bm.samples;
+
+	if (previous_total == 0)
+		loadPercentage = 0;	/* first time here */
+	else if (total == previous_total)
+		loadPercentage = 100;
+	else
+		loadPercentage = (100 * (load - previous_load)) / (total - previous_total);
+
+	return loadPercentage;
+}
+
+int system_memory(void)
+{
+#define pagetob(size) ((size) << (uvmexp.pageshift))
+	struct uvmexp uvmexp;
+	int nswap, rnswap, i;
+	int mib[] = { CTL_VM, VM_UVMEXP };
+	size_t size = sizeof (uvmexp);
+
+	if (sysctl(mib, 2, &uvmexp, &size, NULL, 0) < 0)
+		return 0;
+
+	bm.mem_used = pagetob(uvmexp.active);
+	bm.mem_max = pagetob(uvmexp.npages);
+	bm.swap_used = 0;
+	bm.swap_max = 0;
+	if ((nswap = swapctl(SWAP_NSWAP, 0, 0)) != 0) {
+		struct swapent *swdev = malloc(nswap * sizeof(*swdev));
+		if((rnswap = swapctl(SWAP_STATS, swdev, nswap)) != nswap) {
+			for (i = 0; i < nswap; i++) {
+				if (swdev[i].se_flags & SWF_ENABLE) {
+					bm.swap_used += (swdev[i].se_inuse / (1024 / DEV_BSIZE));
+					bm.swap_max += (swdev[i].se_nblks / (1024 / DEV_BSIZE));
+				}
+			}
+		}
+		free(swdev);
+	}
+
+	return 1;
+}
+
+#ifdef ENABLE_MEMSCREEN
+void system_loadavg(void)
+{
+	static int avg_delay;
+
+	if (avg_delay-- <= 0) {
+		struct loadavg loadinfo;
+		int i;
+		int mib[] = { CTL_VM, VM_LOADAVG };
+		size_t size = sizeof (loadinfo);
+
+		if (sysctl(mib, 2, &loadinfo, &size, NULL, 0) >= 0)
+			for (i = 0; i < 3; i++) {
+				bm.loadavg[i].i = loadinfo.ldavg[i] / loadinfo.fscale;
+				bm.loadavg[i].f = ((loadinfo.ldavg[i] * 100 + 
+				loadinfo.fscale / 2) / loadinfo.fscale) % 100;
+			}
+
+		avg_delay = ROLLVALUE;
+	}
+}
+#endif				/* ENABLE_MEMSCREEN */
+
+/* ex:set sw=4 ts=4: */
diff --git a/sys_sunos.c b/sys_sunos.c
new file mode 100644
index 0000000..9bae147
--- /dev/null
+++ b/sys_sunos.c
@@ -0,0 +1,325 @@
+/*  BubbleMon dockapp 1.2 - SunOS specific code
+ *  Copyright 2001 Phil Lu <wplu13 at netscape.net>
+ *  Copyright 2001 Dan Price <dp at rampant.org>
+ *  vim: ts=4 sw=4
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+/*
+ * This file is best viewed with tab stop set to 4 spaces ...
+ *
+ *	For Nedit, from ~/.nedit:
+ *		nedit.tabDistance: 4
+ *	For vi*, from ~/.exrc:
+ *		set ts=4 sw=4
+ */
+
+#include <sys/kstat.h>
+#include <sys/cpuvar.h>
+#include <sys/swap.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <strings.h>
+#include <kstat.h>
+#include <utmp.h>
+#include <math.h>
+
+#include "include/bubblemon.h"
+#include "include/sys_include.h"
+
+extern BubbleMonData bm;
+
+static kstat_ctl_t *kc = 0;
+static kstat_t **cpu_ksp_list = 0;
+static int ncpus = 0;
+
+static void GetMemoryStats(u_int64_t *pMemMax, u_int64_t *pMemFree);
+static void GetSwapStats(u_int64_t *pSwapTotal, u_int64_t *pSwapFree);
+static void GetCPULoadAverage(float *one_m, float *five_m, float *fift_m);
+
+static int dbg_print_mem = 0;	/* from environment: DBG_PRINT_MEM=interval */
+static int dbg_print_cpu = 0;	/* from environment: DBG_PRINT_CPU=interval */
+static int dbg_hardcode = 0;	/* from environment: DBG_HARDCODE */
+
+
+/*
+ * setup_system() gets called to initialize everything specific to Solaris,
+ * and when kstat_chain_update() indicates that the kernel's kstat chain has
+ * altered.
+ *
+ * When that occurs, CPUs may have come on- or off-line, so we need to
+ * rediscover the system cpus.
+ */
+void setup_system()
+{
+	char *str = 0;
+	kstat_t *ksp = 0;
+	static int bootstrap = 1;
+	int i = 0;
+
+	if (bootstrap) {
+		/* grab debugging flags from environment */
+		if ((str = getenv("DBG_PRINT_MEM")))
+			dbg_print_mem = atoi(str);
+		if ((str = getenv("DBG_PRINT_CPU")))
+			dbg_print_cpu = atoi(str);
+		if ((str = getenv("DBG_HARDCODE")))
+			dbg_hardcode = 1;
+
+		if ((kc = kstat_open()) == NULL) {
+			perror("can't open /dev/kstat");
+			exit(1);
+		}
+		bootstrap = 0;
+	}
+
+	/*
+	 * User selected to monitor all CPUs.  First, count them.
+	 */
+	for (i = 0, ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
+		if (strcmp(ksp->ks_module, "cpu_stat") == 0)
+			i++;
+	}
+
+	if (cpu_ksp_list) {
+		free(cpu_ksp_list);
+	}
+
+	cpu_ksp_list = (kstat_t **) calloc(i * sizeof (kstat_t *), 1);
+	ncpus = i;
+
+	/*
+	 * stash the ksp for each CPU.
+	 */
+	for (i = 0, ksp = kc->kc_chain; ksp; ksp = ksp->ks_next) {
+		if (strcmp(ksp->ks_module, "cpu_stat") == 0) {
+			cpu_ksp_list[i] = ksp;
+			i++;
+		}
+	}
+}
+
+/* returns current CPU load in percent, 0 to 100 */
+int system_cpu(void)
+{
+	static int previous_total = 0, previous_used = 0;
+	int used = 0, idle = 0, total = 0, i = 0, t = 0;
+	cpu_stat_t stat;
+
+	if (dbg_hardcode)
+		return 20;
+
+	if (kc == NULL || kstat_chain_update(kc)) {
+		setup_system();
+	}
+
+	/*
+	 * Read each cpu's data.  If the kstat chain has changed (a state change
+	 * has happened, maybe a new cpu was added to the system or one went
+	 * away), then reinitialize everything with setup_system().  Finally,
+	 * recursively call system_cpu()
+	 *
+	 * We'll need to do a little better than this in the future, since we
+	 * could recurse too much in the pathological case here.
+	 */
+
+	for (i = 0; i < ncpus; i++) {
+		if (kstat_read(kc, cpu_ksp_list[i], (void *)&stat) == -1) {
+			setup_system();
+			return (system_cpu());
+		}
+		used += stat.cpu_sysinfo.cpu[CPU_USER];   /* user */
+		used += stat.cpu_sysinfo.cpu[CPU_KERNEL]; /* sys */
+		used += stat.cpu_sysinfo.cpu[CPU_WAIT]; /* wait */
+		idle += stat.cpu_sysinfo.cpu[CPU_IDLE];   /*idle ("free") */
+	}
+
+	total = used + idle;
+	t = 100 * (double)(used - previous_used) /
+	    (double)(total - previous_total);
+	previous_total = total;
+	previous_used = used;
+
+	if (dbg_print_cpu) {
+		static int i = 0;
+		if (0 == (i % dbg_print_cpu)) {
+			printf("system_cpu: %d%%, total=%d\n", t, total);
+			printf("system_cpu: used=%d, idle=%d\n", used, idle);
+		}
+		i++;
+	}
+	return (t);
+}
+
+typedef struct TMyMem {
+	u_int64_t lMemMax;
+	u_int64_t lMemFree;
+	u_int64_t lSwapMax;
+	u_int64_t lSwapFree;
+} MyMem;
+
+int system_memory(void)
+{
+	static MyMem last = { 100, 20, 200, 10, };
+	MyMem         cur = { 100, 20, 200, 10, };
+	int rc = 0;
+
+	if (dbg_hardcode) {
+		bm.mem_max   = 100;
+		bm.mem_used  =  20;
+		bm.swap_max  = 200;
+		bm.swap_used =   0;
+		return 1;
+	}
+
+	GetSwapStats(&cur.lSwapMax, &cur.lSwapFree);
+	bm.swap_max = cur.lSwapMax;
+	bm.swap_used = cur.lSwapMax - cur.lSwapFree;
+
+	GetMemoryStats(&cur.lMemMax, &cur.lMemFree);
+	bm.mem_max = cur.lMemMax + cur.lSwapMax;
+	bm.mem_used = cur.lMemMax - cur.lMemFree + bm.swap_used;
+
+	if (dbg_print_mem) {
+		static int i = 0;
+		if (0 == (i % dbg_print_mem)) {
+			printf("system_memory: mem:  max=%llu used=%llu\n",
+			    bm.mem_max, bm.mem_used);
+			printf("system_memory: swap: max=%llu used=%llu\n",
+			    bm.swap_max, bm.swap_used);
+		}
+		i++;
+	}
+
+	/* if memory info changed - update things */
+	rc = (0 == memcmp(&last, &cur, sizeof(last)) ? 0 : 1);
+
+	memcpy(&last, &cur, sizeof(last));
+	return rc;
+}
+
+#ifdef ENABLE_MEMSCREEN
+void system_loadavg(void)
+{
+	static int avg_delay = 0;
+	float one_m = 0, five_m = 0, fift_m = 0;
+
+	if (dbg_hardcode) {
+		bm.loadavg[0].i = 0; bm.loadavg[0].f = 53;  /* 0.53 */
+		bm.loadavg[1].i = 0; bm.loadavg[1].f = 45;  /* 0.45 */
+		bm.loadavg[2].i = 0; bm.loadavg[2].f = 38;  /* 0.38 */
+		return;
+	}
+
+	if (avg_delay-- <= 0) {
+		GetCPULoadAverage(&one_m, &five_m, &fift_m);
+
+		if (dbg_print_cpu) {
+			static int i = 0;
+			if (0 == (i % dbg_print_cpu))
+				printf("loadavg: %0.2f %0.2f %0.2f\n",
+				    one_m, five_m, fift_m);
+			i++;
+		}
+
+		bm.loadavg[0].i = floor(one_m);
+		bm.loadavg[0].f = 100 * (one_m - floor(one_m));
+		bm.loadavg[1].i = floor(five_m);
+		bm.loadavg[1].f = 100 * (five_m - floor(five_m));
+		bm.loadavg[2].i = floor(fift_m);
+		bm.loadavg[2].f = 100 * (fift_m - floor(fift_m));
+		avg_delay = ROLLVALUE;
+	}
+}
+#endif				/* ENABLE_MEMSCREEN */
+
+static void GetMemoryStats(u_int64_t *pMemMax, u_int64_t *pMemFree)
+{
+	uint_t lPagesToBytesMult = sysconf(_SC_PAGESIZE);
+
+	*pMemMax  = (uint64_t)sysconf(_SC_PHYS_PAGES)   * lPagesToBytesMult;
+	*pMemFree = (uint64_t)sysconf(_SC_AVPHYS_PAGES) * lPagesToBytesMult;
+
+	if (dbg_print_mem) {
+		static int i = 0;
+		if (0 == (i % dbg_print_mem)) {
+			printf("GetMemoryStats:  pMemMax=%llu Bytes\n", *pMemMax);
+			printf("GetMemoryStats: pMemFree=%llu Bytes\n", *pMemFree);
+		}
+		i++;
+	}
+}
+
+static void GetSwapStats(u_int64_t *pSwapTotal, u_int64_t *pSwapFree)
+{
+	struct anoninfo anon;
+	uint_t lPagesToBytesMult = sysconf(_SC_PAGESIZE);
+
+	if (swapctl(SC_AINFO, &anon) == -1) {
+		perror("swapctl failed");
+		/* let's not blow up code by setting stuff to 0 :) */
+		*pSwapTotal = *pSwapFree = 1;
+		return;
+	}
+
+	*pSwapTotal = lPagesToBytesMult * (anon.ani_max);
+	*pSwapFree  = lPagesToBytesMult * (anon.ani_max - anon.ani_resv);
+
+	if (dbg_print_mem) {
+		static int i = 0;
+		if (0 == (i % dbg_print_mem)) {
+			(void) printf("GetSwapStats:  pSwapMax=%llu Bytes\n",
+			    *pSwapTotal);
+			(void) printf("GetSwapStats: pSwapFree=%llu Bytes\n",
+			    *pSwapFree);
+		}
+		i++;
+	}
+}
+
+/*
+ * we'd prefer to use getloadavg(3C) but it wasn't present in Solaris until
+ * sunos 5.7. (sigh)
+ */
+static void GetCPULoadAverage(float *one_m, float *five_m, float *fift_m)
+{
+	kstat_named_t *kn = 0;
+	kstat_t *ks = 0;
+
+	if (kc == NULL || kstat_chain_update(kc)) {
+		setup_system();
+	}
+
+	ks = kstat_lookup(kc, "unix", 0, "system_misc");
+	if (kstat_read(kc, ks, 0) == -1) {
+		perror("kstat_read");
+		exit(1);
+	}
+
+	/*
+	 *  Get the 1, 5 and 15min load average.
+	 */
+	kn = kstat_data_lookup(ks, "avenrun_1min");
+	*one_m = kn->value.ul / (ncpus * 256.0);
+
+	kn = kstat_data_lookup(ks, "avenrun_5min");
+	*five_m = kn->value.ul / (ncpus * 256.0);
+
+	kn = kstat_data_lookup(ks, "avenrun_15min");
+	*fift_m = kn->value.ul / (ncpus * 256.0);
+}

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-wmaker/wmbubble.git



More information about the Pkg-wmaker-commits mailing list