diff --git a/building/linux64ARMv8/squeak.cog.spur/build.assert/mvm b/building/linux64ARMv8/squeak.cog.spur/build.assert/mvm index 1fe5e22339..acccfc0153 100755 --- a/building/linux64ARMv8/squeak.cog.spur/build.assert/mvm +++ b/building/linux64ARMv8/squeak.cog.spur/build.assert/mvm @@ -6,24 +6,19 @@ INSTALLDIR=assert/sqcogspur64ARMv8linuxht MACHINE="-march=armv8-a -mtune=cortex-a72" OPT="-g3 -O1 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -DDEBUGVM=0" -if [ `uname` = "OpenBSD" ]; then - DUALMAP="-DDUAL_MAPPED_CODE_ZONE=0" # librt and libpthread functions now supplied by libc. -# Many Linux systems supply empty library files but -# OpenBSD does not. - LIBRT="" -# OpenBSD has problems with fast-bitblt under gcc and clang - FASTBITBLT="" +# Many Linux systems supply empty library files. +LIBRT="-lrt" + # Prefer clang over gcc if available if [ -n "$(command -v clang || true)" ]; then CC=clang; else CC=gcc; fi -else # non-OpenBSD Linux - DUALMAP="-DDUAL_MAPPED_CODE_ZONE=1" - LIBRT="-lrt" + +DUALMAP="-DDUAL_MAPPED_CODE_ZONE=1" # Linux on ARMv8 properly compiles fast-bitblt under gcc # but compiles-and-segfaults with clang. Use gcc for now. - FASTBITBLT=" --enable-fast-bitblt " - CC=gcc -fi +FASTBITBLT=" --enable-fast-bitblt " +CC=gcc + if [ $# -ge 1 ]; then INSTALLDIR="$1"; shift diff --git a/building/linux64ARMv8/squeak.cog.spur/build.debug/mvm b/building/linux64ARMv8/squeak.cog.spur/build.debug/mvm index 235c119042..f221574d7d 100755 --- a/building/linux64ARMv8/squeak.cog.spur/build.debug/mvm +++ b/building/linux64ARMv8/squeak.cog.spur/build.debug/mvm @@ -6,24 +6,15 @@ INSTALLDIR=debug/sqcogspur64ARMv8linuxht MACHINE="-march=armv8-a -mtune=cortex-a72" OPT="-g3 -O0 -DDEBUGVM=1 -DAIO_DEBUG=1" -if [ `uname` = "OpenBSD" ]; then - DUALMAP="-DDUAL_MAPPED_CODE_ZONE=0" -# librt and libpthread functions now supplied by libc. -# Many Linux systems supply empty library files but -# OpenBSD does not. - LIBRT="" -# OpenBSD has problems with fast-bitblt under gcc and clang - FASTBITBLT="" # Prefer clang over gcc if available if [ -n "$(command -v clang || true)" ]; then CC=clang; else CC=gcc; fi -else # non-OpenBSD Linux - DUALMAP="-DDUAL_MAPPED_CODE_ZONE=1" - LIBRT="-lrt" + +DUALMAP="-DDUAL_MAPPED_CODE_ZONE=1" +LIBRT="-lrt" # Linux on ARMv8 properly compiles fast-bitblt under gcc # but compiles-and-segfaults with clang. Use gcc for now. - FASTBITBLT=" --enable-fast-bitblt " - CC=gcc -fi +FASTBITBLT=" --enable-fast-bitblt " +CC=gcc if [ $# -ge 1 ]; then INSTALLDIR="$1"; shift diff --git a/building/linux64ARMv8/squeak.cog.spur/build/mvm b/building/linux64ARMv8/squeak.cog.spur/build/mvm index cc6e643826..831ae1d983 100755 --- a/building/linux64ARMv8/squeak.cog.spur/build/mvm +++ b/building/linux64ARMv8/squeak.cog.spur/build/mvm @@ -6,30 +6,15 @@ INSTALLDIR=sqcogspur64ARMv8linuxht # tpr - add enablementisation of fast bitblt ben avison code MACHINE="-march=armv8-a -mtune=cortex-a72" OPT="-g -O2 -DNDEBUG -DDEBUGVM=0 -D_GNU_SOURCE -DUSEEVDEV" -##OPT="-g -O3 -DMUSL -DNDEBUG -DDEBUGVM=0" -if [ `uname` = "OpenBSD" ]; then - OPT="$OPT -DMUSL" - CFLAGS="$CFLAGS $OPT -I/usr/local/include" - LIBS="$LIBS -lexecinfo" - LDFLAGS="$LDFLAGS -L/usr/local/lib" - DUALMAP="-DDUAL_MAPPED_CODE_ZONE=0" +DUALMAP="-DDUAL_MAPPED_CODE_ZONE=1" # librt and libpthread functions now supplied by libc. -# Many Linux systems supply empty library files but -# OpenBSD does not. - LIBRT="" -# OpenBSD has problems with fast-bitblt under gcc and clang - FASTBITBLT="" -# Prefer clang over gcc if available - if [ -n "$(command -v clang || true)" ]; then CC=clang; else CC=gcc; fi -else # non-OpenBSD Linux - DUALMAP="-DDUAL_MAPPED_CODE_ZONE=1" - LIBRT="-lrt" +# Many Linux systems supply empty library file. +LIBRT="-lrt" # Linux on ARMv8 properly compiles fast-bitblt under gcc # but compiles-and-segfaults with clang. Use gcc for now. - FASTBITBLT=" --enable-fast-bitblt " - CC=gcc -fi +FASTBITBLT=" --enable-fast-bitblt " +CC=gcc if [ $# -ge 1 ]; then INSTALLDIR="$1"; shift diff --git a/building/linux64ARMv8/squeak.cogmt.spur/build/mvm b/building/linux64ARMv8/squeak.cogmt.spur/build/mvm index e816f75044..338842e35a 100755 --- a/building/linux64ARMv8/squeak.cogmt.spur/build/mvm +++ b/building/linux64ARMv8/squeak.cogmt.spur/build/mvm @@ -4,8 +4,14 @@ set -e INSTALLDIR=sqcogspurmt64ARMv8linuxht # armv8.N-a all fail in signalSemaphoreWithIndex for N in 1,2,3,4,5 MACHINE="-march=armv8-a -mtune=cortex-a72" -OPT="-g -O2 -DNDEBUG -DDEBUGVM=0 -DMUSL -D_GNU_SOURCE -DUSEEVDEV" -##OPT="-g -O3 -DNDEBUG -DDEBUGVM=0" +OPT="-g -O2 -DNDEBUG -DDEBUGVM=0 -DUSEEVDEV" +CFLAGS="$CFLAGS $OPT -I/usr/local/include" +LIBS="$LIBS -lexecinfo" +LDFLAGS="$LDFLAGS -L/usr/local/lib" +DUALMAP="-DDUAL_MAPPED_CODE_ZONE=0" +# librt and libpthread functions now supplied by libc. +# Many Linux systems supply empty library files. +LIBRT="-lrt" if [ $# -ge 1 ]; then INSTALLDIR="$1"; shift @@ -23,9 +29,9 @@ test -f config.h || ../../../../platforms/unix/config/configure \ --without-npsqueak \ --with-scriptname=spur64 \ INTERP=cointerpmt \ - CC=clang \ + CC=gcc \ CFLAGS="$MACHINE $OPT -DCOGMTVM=1 -DDUAL_MAPPED_CODE_ZONE=1" \ - LIBS="-lrt" + LIBS=$LIBRT ## --without-vm-display-fbdev --without-npsqueak \ rm -f vm/sqUnixMain.o # nuke version info rm -rf ../../../../products/$INSTALLDIR diff --git a/building/linux64ARMv8/squeak.stack.spur/build.assert/mvm b/building/linux64ARMv8/squeak.stack.spur/build.assert/mvm index 8d0f450a18..461b2278b3 100755 --- a/building/linux64ARMv8/squeak.stack.spur/build.assert/mvm +++ b/building/linux64ARMv8/squeak.stack.spur/build.assert/mvm @@ -4,11 +4,7 @@ set -e INSTALLDIR=assert/sqstkspur64ARMv8linuxht OPT="-g3 -O1 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -DDEBUGVM=0" -if [ `uname` = "OpenBSD" ]; then - DUALMAP="-DDUAL_MAPPED_CODE_ZONE=0" -else - DUALMAP="-DDUAL_MAPPED_CODE_ZONE=1" -fi +DUALMAP="-DDUAL_MAPPED_CODE_ZONE=1" # Prefer clang over gcc if available if [ -n "$(command -v clang || true)" ]; then CC=clang; else CC=gcc; fi diff --git a/building/linux64ARMv8/squeak.stack.spur/build.debug/mvm b/building/linux64ARMv8/squeak.stack.spur/build.debug/mvm index 5e1a334e9c..d1b3053079 100755 --- a/building/linux64ARMv8/squeak.stack.spur/build.debug/mvm +++ b/building/linux64ARMv8/squeak.stack.spur/build.debug/mvm @@ -4,13 +4,7 @@ set -e INSTALLDIR=debug/sqstkspur64ARMv8linuxht OPT="-g3 -O0 -DDEBUG -DDEBUGVM=1 -DDEBUG_EVENTS -DDEBUG_KEYBOARD_EVENTS -DDEBUG_MOUSE_EVENTS -DUSEEVDEV -DMUSL" -### OPT="-g3 -O0 -DDEBUGVM=1" - -if [ `uname` = "OpenBSD" ]; then - DUALMAP="-DDUAL_MAPPED_CODE_ZONE=0" -else - DUALMAP="-DDUAL_MAPPED_CODE_ZONE=1" -fi +DUALMAP="-DDUAL_MAPPED_CODE_ZONE=1" # Prefer clang over gcc if available if [ -n "$(command -v clang || true)" ]; then CC=clang; else CC=gcc; fi diff --git a/building/linux64ARMv8/squeak.stack.spur/build/mvm b/building/linux64ARMv8/squeak.stack.spur/build/mvm index 08e022da22..883369dbbe 100755 --- a/building/linux64ARMv8/squeak.stack.spur/build/mvm +++ b/building/linux64ARMv8/squeak.stack.spur/build/mvm @@ -3,13 +3,8 @@ set -e # Stack Spur VM with VM profiler and threaded heartbeat INSTALLDIR=sqstkspur64ARMv8linuxht OPT="-g -O2 -DNDEBUG -DDEBUGVM=0 -DMUSL -D_GNU_SOURCE -DUSEEVDEV" -### OPT="-g -O2 -DNDEBUG -DDEBUGVM=0" -if [ `uname` = "OpenBSD" ]; then - DUALMAP="-DDUAL_MAPPED_CODE_ZONE=0" -else - DUALMAP="-DDUAL_MAPPED_CODE_ZONE=1" -fi +DUALMAP="-DDUAL_MAPPED_CODE_ZONE=1" # Prefer clang over gcc if available if [ -n "$(command -v clang || true)" ]; then CC=clang; else CC=gcc; fi diff --git a/building/linux64x64/squeak.cog.spur/build.assert.itimerheartbeat/mvm b/building/linux64x64/squeak.cog.spur/build.assert.itimerheartbeat/mvm index b4029e102e..896c49f896 100755 --- a/building/linux64x64/squeak.cog.spur/build.assert.itimerheartbeat/mvm +++ b/building/linux64x64/squeak.cog.spur/build.assert.itimerheartbeat/mvm @@ -2,7 +2,13 @@ set -e # assert VM with VM profiler and itimer heartbeat INSTALLDIR=assert/sqcogspur64linux -OPT="-g3 -O1 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -DDEBUGVM=0" +OPT="-g3 -O1 -DDEBUGVM=0" + +# librt and libpthread funs now supplied by libc +# Many Linux systems supply empty library files +CFLAGS="$CFLAGS $OPT -msse2 -DCOGMTVM=0" +LIBS="$LIBS -lrt" +LDFLAGS="$LDFLAGS" # Prefer clang over gcc if available if [ -n "$(command -v clang || true)" ]; then CC=clang; else CC=gcc; fi diff --git a/building/linux64x64/squeak.cog.spur/build.assert/mvm b/building/linux64x64/squeak.cog.spur/build.assert/mvm index f6c8c94075..44e74a29e4 100755 --- a/building/linux64x64/squeak.cog.spur/build.assert/mvm +++ b/building/linux64x64/squeak.cog.spur/build.assert/mvm @@ -2,26 +2,16 @@ set -e # assert VM with VM profiler and threaded heartbeat INSTALLDIR=assert/sqcogspur64linuxht -OPT="-g3 -O1 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -DDEBUGVM=0" +OPT="-g3 -O1 -DDEBUGVM=0" # Prefer clang over gcc if available if [ -n "$(command -v clang || true)" ]; then CC=clang; else CC=gcc; fi # librt and libpthread funs now supplied by libc # Many Linux systems supply empty library files -# but OpenBSD does not. -if [ `uname` = "OpenBSD" ]; then LIBRT=""; else LIBRT="-lrt"; fi - -CFLAGS="$OPT -msse2 -DCOGMTVM=0" -LIBS=$LIBRT -LDFLAGS="" - -# Special treatment for OpenBSD Linux -if [ `uname` = "OpenBSD" ]; then - CFLAGS="$CFLAGS -I/usr/local/include" - LIBS="$LIBS -lexecinfo" - LDFLAGS="$LDFLAGS -L/usr/local/lib" -fi +CFLAGS="$CFLAGS $OPT -msse2 -DCOGMTVM=0" +LIBS="$LIBS -lrt" +LDFLAGS="$LDFLAGS" if [ $# -ge 1 ]; then INSTALLDIR="$1"; shift diff --git a/building/linux64x64/squeak.cog.spur/build.debug.itimerheartbeat/mvm b/building/linux64x64/squeak.cog.spur/build.debug.itimerheartbeat/mvm index bbb63282c5..5f68567f15 100755 --- a/building/linux64x64/squeak.cog.spur/build.debug.itimerheartbeat/mvm +++ b/building/linux64x64/squeak.cog.spur/build.debug.itimerheartbeat/mvm @@ -4,6 +4,12 @@ set -e INSTALLDIR=debug/sqcogspur64linux OPT="-g3 -O0 -DDEBUGVM=1" +# librt and libpthread funs now supplied by libc +# Many Linux systems supply empty library files +CFLAGS="$CFLAGS $OPT -msse2 -DCOGMTVM=0" +LIBS="$LIBS -lrt" +LDFLAGS="$LDFLAGS" + # Prefer clang over gcc if available if [ -n "$(command -v clang || true)" ]; then CC=clang; else CC=gcc; fi diff --git a/building/linux64x64/squeak.cog.spur/build.debug/mvm b/building/linux64x64/squeak.cog.spur/build.debug/mvm index 5814694860..0ea89cd1a8 100755 --- a/building/linux64x64/squeak.cog.spur/build.debug/mvm +++ b/building/linux64x64/squeak.cog.spur/build.debug/mvm @@ -4,24 +4,14 @@ set -e INSTALLDIR=debug/sqcogspur64linuxht OPT="-g3 -O0 -DDEBUGVM=1" -# Prefer clang over gcc if available -if [ -n "$(command -v clang || true)" ]; then CC=clang; else CC=gcc; fi - # librt and libpthread funs now supplied by libc # Many Linux systems supply empty library files -# but OpenBSD does not. -if [ `uname` = "OpenBSD" ]; then LIBRT=""; else LIBRT="-lrt"; fi - -CFLAGS="$OPT -msse2 -DCOGMTVM=0" -LIBS=$LIBRT -LDFLAGS="" +CFLAGS="$CFLAGS $OPT -msse2 -DCOGMTVM=0" +LIBS="$LIBS -lrt" +LDFLAGS="$LDFLAGS" -# Special treatment for OpenBSD Linux -if [ `uname` = "OpenBSD" ]; then - CFLAGS="$CFLAGS -I/usr/local/include" - LIBS="$LIBS -lexecinfo" - LDFLAGS="$LDFLAGS -L/usr/local/lib" -fi +# Prefer clang over gcc if available +if [ -n "$(command -v clang || true)" ]; then CC=clang; else CC=gcc; fi if [ $# -ge 1 ]; then INSTALLDIR="$1"; shift diff --git a/building/linux64x64/squeak.cog.spur/build/mvm b/building/linux64x64/squeak.cog.spur/build/mvm index 94a4f829ab..0fc571ce98 100755 --- a/building/linux64x64/squeak.cog.spur/build/mvm +++ b/building/linux64x64/squeak.cog.spur/build/mvm @@ -10,20 +10,9 @@ if [ -n "$(command -v clang || true)" ]; then CC=clang; else CC=gcc; fi # librt and libpthread funs now supplied by libc # Many Linux systems supply empty library files -# but OpenBSD does not. -if [ `uname` = "OpenBSD" ]; then LIBRT=""; else LIBRT="-lrt"; fi - -# Special treatment for OpenBSD Linux -if [ `uname` = "OpenBSD" ]; then - OPT="$OPT -DMUSL" - CFLAGS="$CFLAGS $OPT -I/usr/local/include" - LIBS="$LIBS -lexecinfo" - LDFLAGS="$LDFLAGS -L/usr/local/lib" -else - CFLAGS="$CFLAGS $OPT -msse2 -DCOGMTVM=0" - LIBS="$LIBS -lrt" - LDFLAGS="$LDFLAGS" -fi +CFLAGS="$CFLAGS $OPT -msse2 -DCOGMTVM=0" +LIBS="$LIBS -lrt" +LDFLAGS="$LDFLAGS" if [ $# -ge 1 ]; then INSTALLDIR="$1"; shift diff --git a/building/linux64x64/squeak.sista.spur/build.assert/mvm b/building/linux64x64/squeak.sista.spur/build.assert/mvm index 96918def63..b546a0a7db 100755 --- a/building/linux64x64/squeak.sista.spur/build.assert/mvm +++ b/building/linux64x64/squeak.sista.spur/build.assert/mvm @@ -2,7 +2,7 @@ set -e # assert Sista Spur VM with VM profiler and threaded heartbeat INSTALLDIR=assert/sqsisspur64linuxht -OPT="-g3 -O1 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -DDEBUGVM=0" +OPT="-g3 -O1 -DDEBUGVM=0" # Prefer clang over gcc, but use gcc if clang isn't available... CC=gcc diff --git a/building/linux64x64/squeak.stack.spur/build.assert/mvm b/building/linux64x64/squeak.stack.spur/build.assert/mvm index 420b62f575..378f711924 100755 --- a/building/linux64x64/squeak.stack.spur/build.assert/mvm +++ b/building/linux64x64/squeak.stack.spur/build.assert/mvm @@ -2,7 +2,7 @@ set -e # assert Stack Spur VM with VM profiler and threaded heartbeat INSTALLDIR=assert/sqstkspur64linuxht -OPT="-g3 -O1 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -DDEBUGVM=0" +OPT="-g3 -O1 -DDEBUGVM=0" # Prefer clang over gcc, but use gcc if clang isn't available... CC=gcc diff --git a/building/openbsd64ARMv8/HowToBuild b/building/openbsd64ARMv8/HowToBuild new file mode 100644 index 0000000000..d9c6f5b5b8 --- /dev/null +++ b/building/openbsd64ARMv8/HowToBuild @@ -0,0 +1,353 @@ +How To Build On Linux +--------------------- + +Note: These instructions are for aarch64/arm64 CPUs. +See building/linux32ARMv6/HowToBuild + or building/linux32ARMv7/HowToBuild for 32 bit ARM images. + + +Contents: + - Overview + - Checking out sources to build out-of-the-box + - Building out of the box + - Building the VM Simulator Support Libraries + - How to configure and build a VM on Unix + - Debugging configuration failures + - Testing an external plugin has completely linked + - Optimization level and gcc version (please read!) + - Installing support libraries + - Building with MUSL rather than libc + + +Overview +-------- +The "Cog" VM comes in a bewildering variety of forms. The first distinction +is between Squeak/Croquet VMs that run Squeak, Pharo, Cuis, Croquet images +and their ilk, and between Newspeak VMs that run Newspeak. + +Another distinction is between Stack, Cog and Sista VMs. Stack VMs are those +with context-to-stack mapping that optimise message sending by keeping method +activations on a stack instead of in contexts. These are pure interpreters but +significantly faster than the standard context-based Interpreter VM. Cog VMs +add a JIT to the mix, compiling methods used more than once to maxchine code on +the fly. Sista VMs, as yet unrealised and in development, add support for +adaptive optimization that does speculative inlining at the bytecode-to-bytecode +level. These are targeted for release in 2015. + +Another distinction is between "v3" VMs and Spur VMs. "v3" is the original +object representation for Squeak as described in the back-to-the-future paper. +Spur, as described on the www.mirandabanda.org blog, is a faster object +representation which uses generation scavenging, lazy forwarding for fast +become, and a single object header format common to 32 and 64 bit versions. + +Another distinction is between normal single-threaded VMs that schedule "green" +Smalltalk processes above a single-threaded VM, and "multi-threaded" VMs that +share the VM between any number of native threads such that only one native +thread owns the VM at any one time, switching between threads on FFI calls and +callbacks or on Smalltalk process switches when Smalltalk processes are owned +by threads. This multi-threaded support is as yet experimental. + +A distinction on linux is between VMs with an itimer hearbeat or a threaded +heartbeat. VMs with an itimer hearbeat use setitimer to deliver a SIGALRM +signal at regular intervals to interrupt the VM to check for events. These +signals can be troublesome, interrupting foreign code that cannot cope with +such signals. VMs with a threaded heartbeat use a high-priority thread that +loops, blocking on nanosleep and then interrupting the VM, performing the same +function as the itimer heartbeat but without using signals. These VMs are to +be preferred but suport for multiple thread priorities in user-level processes +has only been available on linux in kernels later than 2.6.12. + +The final distinction is between production, assert and debug VMs. Production +VMs are fully optimized, although they may include debugging symbols, and as +their name implies are for use in production. Assert and debug VMs include +many assert checks that are disabled in the production VMs. These asserts are +very helpful in debugging VM problems but significantly impact performance. +The difference between assert and debug VMs is that assert VMs are compiled +with moderate optimization, which improves the performance of the asserts, +whereas debug VMs are compiled with no optimization at all, providing maximum +debuggability with minimum performance. + +This directory tree provides build directories for some of this matrix. For +example, squeak.cog.v3 contains build directories for Smalltalk Cog VMs using +the old object representation, newspeak.stack.spur contains build directories +for Newspeak Stack VMs using the Spur object representation. Build as desired. + + +Checking out sources to build out-of-the-box +-------------------------------------------- +Check-out the repository from github: + git clone http://www.github.com/OpenSmalltalk/opensmalltalk-vm oscogvm + cd ./oscogvm + more README.md + + +Building out of the box +----------------------- +Install the tools (gcc, X11-devel, etc, e.g. libpng, libuuid libX11 & libxt +source). See "Installing support libraries" below. If the configure step fails +when "checking for C compiler default output file name", you have yet to install +all the necessary support packages (e.g. libuuid). +Then cd to the build directory of your choice, e.g. + building/linux64x64/squeak.cog.spur/build +Then execute + ./mvm +answering "y" to perform a clean build or "n" to rebuild without reconfiguring. +Again, if the configure step fails when "checking for C compiler default output +file name", you have yet to install all the necessary support (e.g. lubuuid). + +The subdirectories conform to the production/assert/debug x itimer vs threaded +heartbeat x single vs multi-threaded parts of the matrix described above. For +example, building/linux64x64/squeak.cog.v3 includes + + build + build.itimerheartbeat + build.multithreaded + + build.assert + build.assert.itimerheartbeat + build.multithreaded.assert + + build.debug + build.multithreaded.debug + build.debug.itimerheartbeat + +subdirectories. It includes two convenience scripts that will make all +configurations: + makeallclean + makealldirty + +Each build directory contains three files + mvm + plugins.int + plugins.ext +The mvm script runs ../../platforms/unix/config/configure with the relevant +options, runs make, and then make install to create a VM directory tree in +../../products, ../../products/assert or ../../products/debug as appropriate. +plugins.int and plugins.ext determine the set of plugins to be taken from +the supplied plugins directory (which defaults to ../../src/plugins), and which +are to be linked into the VM (plugins.int) or compiled as external shared +objects to be dynamically linked at run-time (plugins.ext). + +Finally, at the building/linux64ARMv8 level the makeall script will run all the +makeallclean scripts it can find. + + +Building the VM Simulator Support Libraries +------------------------------------------- +If you want to get the Cog VM simulator working you'll need to build one or more +of the processor simulator plugins, each of which has support libraries that +must be built: + Processor Plugin Support Library + x86 BochsIA32Plugin building/linux64x64/bochsx86 + x86_64/x64 BochsX64Plugin building/linux64x64/bochsx64 + ARMv5 GdbARMPlugin building/linux64x64/gdbarm32 +cd to the relevant directories; run conf.COG and then the build script, e.g. + $ cd building/linux64x64/bochsx86 + $ ./conf.COG + $ ./makeem + +Then when Squeak VMs are built they will include the plugin(s) for which support +libraries have been provided. + + +How to configure and build a VM on Unix +--------------------------------------- +The mvm scripts are themselves wrappers around an adaptation of Ian Piumarta's +Squeak build system above autoconf to the Cog sources. One can choose the vm +source files, plugin source files, and optimization level to compile a VM of +your choice. To find the full set of options via + + ../../platforms/unix/config/configure --help + +You can see the use of configure in the various mvm scripts in each build +directory. + +e.g. + ../../../platforms/unix/config/configure --without-npsqueak CFLAGS="-g -O2 -msse2 -D_GNU_SOURCE -DNDEBUG -DITIMER_HEARTBEAT=1 -DCOGMTVM=0 -DDEBUGVM=0" LIBS=-lpthread + make install prefix=WhereYouWantTheVmToGo + + N.B. If you're on a 64-bit linux read 3e below!! + N.B. On Ubuntu *do not* supply "LIBS=-lpthread -luuid", i.e. use + ../../../platforms/unix/config/configure --without-npsqueak CFLAGS="-g -O2 -msse2 -D_GNU_SOURCE -DNDEBUG -DITIMER_HEARTBEAT=1 -DCOGMTVM=0 -DDEBUGVM=0" + + +N.B. The plugin set is defined by plugins.ext and plugins.int in the build dir. + +Be prepared to install libuuid support. e.g. on CentOS 6.5 use +sudo yum -y install libuuid-devel + + +Debugging configuration failures +-------------------------------- +If your development system does not have the required libraries installed then +the configure step run by the mvm script will fail cryptically. You will see +something like + checking sanity of generated src directory... okay + checking build system type... i686-pc-linux-gnu + checking host system type... i686-pc-linux-gnu + checking target system type... i686-pc-linux-gnu + + Configuring Squeak (.-) for i686-pc-linux-gnu + + checking whether make sets $(MAKE)... yes + checking for gcc... gcc -m32 + checking for C compiler default output file name... configure: error: C compiler cannot create executables + See `config.log' for more details. +But config.log is missing the relevant details. It only contains the failing gcc +invocation, not the output from that failing command. To diagnose, grep to find +the gcc invocation: + $ grep gcc config.log + ... + configure:2269: gcc -m32 -g3 -O0 -fwrapv -DDEBUGVM=1 -DEnforceAccessControl=0 -msse2 -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -Wl,-z,now conftest.c -lpthread -luuid >& +and then repeat the compilation supplying your own test file, e.g. + $ gcc -m32 -g3 -O0 -fwrapv -DDEBUGVM=1 -DEnforceAccessControl=0 -msse2 -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -Wl,-z,now helloworld.c -lpthread -luuid + helloworld.c: In function 'main': + /usr/bin/ld: cannot find -luuid + collect2: ld returned 1 exit status +From which one can infer that one needs to install either the 64-bit or the 32-bit +version of libuuid, e.g. sudo yum install libuuid-devel + + +Testing an external plugin has completely linked +------------------------------------------------ +You may find that an external plugin compiles and links but does not load. +This is usually because it contans undefined symbols. To find undefined +symbols, remake the plugin, capturing the link step and then supply + -Wl,--warn-unresolved-symbols -Wl,--no-allow-shlib-undefined +when manually repeating the link command + + +Optimization level and gcc version +---------------------------------- +There are issues with gcc version > 4.2.1. Any of the following flags may break the build at -O2: +-ftree-pre +-fpartial-inlining +-fcaller-saves + +So turn them off. e.g. + ../../../platforms/unix/config/configure --without-npsqueak CFLAGS="-g -O2 -msse2 -fno-caller-saves -fno-partial-inlining -fno-tree-pre -D_GNU_SOURCE -DNDEBUG -DCOGMTVM=0 -DDEBUGVM=0" LIBS="-lpthread -luuid" +See http://smallissimo.blogspot.fr/2013/02/compiling-squeak-cog-virtual-machine-on.html + +People have reported that the OSProcessPlugin is broken on gcc versions > 4.8 +on Debian. + + +Installing support libraries +---------------------------- +Different linux distributions have different mechanisms for loading packages. +Here are some examples: + +CentOS + sudo yum install -y cairo-devel + sudo yum install -y pango-devel + sudo yum install -y libuuid-devel + sudo yum install -y libX11-devel + sudo yum install -y mesa-libGL-devel + sudo yum install -y openssl-devel + sudo yum install -y cmake + sudo yum install -y gcc-c++ +N.B. if you get failures due to version conflicts try + sudo yum update +and then retry. + +Ubuntu + sudo apt install uuid-dev libcairo2-dev libpango1.0-dev libgl1-mesa-dev + sudo apt install libgl1-mesa-glx libssl-dev libevdev-dev m4 libpulse-dev + sudo apt install libxrandr-dev + +Manjaro + sudo pacman -Sy gcc clang gdb make + sudo pacman -S uuid-dev libgl1-mesa-dev libgl1-mesa-glx libssl-dev + sudo pacman -S xf86-video-fbdeV + +Debian (64-bit) + A complete build configuration (dockerized) can be found here: + https://github.com/LinqLover/squeak-raspi-docker/tree/master/osvm-mvm + +More advice and examples for other distros gratefully received. + + + +Building with MUSL rather than libc +----------------------------------- +There are some differences in include file definitons when +using MUSL in place of libc. Note: https://musl.libc.org + +You should check your Linux distro for libc development support +libraries or include files needed. + +The following has been tested on both aarch64 and amd64 Alpine Linux +(MUSL+busybox). + +install musl-dev [e.g. sudo apk add musl-dev ]. + +Due to the continued evolution of the OpenSmalltalk VM +it is not possible to use patch files, but the changes +to be made are simple to describe. + +Basically, building works fine but one needs to + +[A] add "-DMUSL -D_GNU_SOURCE" to CFLAGS so that include +expansion is not confused between libc and MUSL definitions. + +[B] elide (remove) some definitions which use 'FILE'. + + +A simple way to do [A] is to add the definitions to OPT in the +'mvm' file in the 'build' directory. + +For [B] one needs to make small changes to files + platforms/Cross/vm/sqVirtualMachine.c +and + platforms/unix/vm/sqUnixMain.c +to skip definitions of pushOutputFile() and popOutputFile(). + + +[B.1] platforms/Cross/vm/sqVirtualMachine.c +... +#ifndef MUSL + #define STDOUT_STACK_SZ 5 + static int stdoutStackIdx = -1; + static FILE stdoutStack[STDOUT_STACK_SZ]; +#endif +... +#ifndef MUSL + void + pushOutputFile(char *filenameOrStdioIndex) + { +... + } + + void + popOutputFile() + { + ... + } +#endif + + +[B.2] platforms/unix/vm/sqUnixMain.c +... +#ifdef MUSL +void pushOutputFile(char *fileNameOrStdioIndex) {;} +void popOutputFile() {;} +#endif +... + + +That's it. You should be able to invoke 'mvm' in the 'build' +directory, answer 'y' to the 'clean?' prompt, and get a +proper build. + +If running the resultant squeak vm gives an error something like + mprotect(x,y,PROT_READ|PROT_EXEC) +or + memory_alias_map: shm_open: Permission denied +you need to enable shared memory for the COG JIT. + +As root: + chmod 777 /dev/shm + echo 'none /dev/shm tmpfs rw,nosuid,nodev 0 0' >> /etc/fstab + mount /dev/shm + +The squeak vm should now work. diff --git a/building/openbsd64ARMv8/makeall b/building/openbsd64ARMv8/makeall new file mode 100755 index 0000000000..923f2bef7a --- /dev/null +++ b/building/openbsd64ARMv8/makeall @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -e +trap 'exit 2' HUP INT PIPE TERM +for d in *.spur *.v3; do + if test -d "$d"; then + (cd ./$d;./makealldirty "$@") + else + echo no $d directory found + fi +done diff --git a/building/openbsd64ARMv8/makeallclean b/building/openbsd64ARMv8/makeallclean new file mode 100755 index 0000000000..1480133451 --- /dev/null +++ b/building/openbsd64ARMv8/makeallclean @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -e +trap 'exit 2' HUP INT PIPE TERM +for d in *.spur *.v3; do + if test -d "$d"; then + (cd ./$d; if test -x makeallclean; then ./makeallclean "$@"; else ./makeclean "$@"; fi) + else + echo no $d directory found + fi +done diff --git a/building/openbsd64ARMv8/makeallmakefiles b/building/openbsd64ARMv8/makeallmakefiles new file mode 100755 index 0000000000..18f4d62873 --- /dev/null +++ b/building/openbsd64ARMv8/makeallmakefiles @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -e +trap 'exit 2' HUP INT PIPE TERM +for td in *.v3 *.spur; do + for d in $td/build*; do + if test -d "$d"; then + (cd ./$d;../../../../platforms/unix/config/mkmf) + else + echo no $d directory found + fi + done +done diff --git a/building/openbsd64ARMv8/makeallsqueak b/building/openbsd64ARMv8/makeallsqueak new file mode 100755 index 0000000000..3d08d6cfc8 --- /dev/null +++ b/building/openbsd64ARMv8/makeallsqueak @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -e +trap 'exit 2' HUP INT PIPE TERM +for d in squeak.*; do + if test -d "$d"; then + (cd ./$d;./makedirty "$@") + else + echo no $d directory found + fi +done diff --git a/building/openbsd64ARMv8/squeak.cog.spur/README.OpenBSD b/building/openbsd64ARMv8/squeak.cog.spur/README.OpenBSD new file mode 100644 index 0000000000..e6839c493c --- /dev/null +++ b/building/openbsd64ARMv8/squeak.cog.spur/README.OpenBSD @@ -0,0 +1,6 @@ +For OpenBSD one MUST install Cog executable files under /usr/local. + +Otherwise the OS will report: + + Could not allocate JIT Memort: Not supported + diff --git a/building/openbsd64ARMv8/squeak.cog.spur/build.assert/mvm b/building/openbsd64ARMv8/squeak.cog.spur/build.assert/mvm new file mode 100755 index 0000000000..b127ba7d60 --- /dev/null +++ b/building/openbsd64ARMv8/squeak.cog.spur/build.assert/mvm @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +set -e +# assert Cog Spur VM with VM profiler and threaded heartbeat +INSTALLDIR=assert/sqcogspur64ARMv8openbsdht +# armv8.N-a all fail in signalSemaphoreWithIndex for N in 1,2,3,4,5 +MACHINE="-march=armv8-a -mtune=cortex-a72" +OPT="-g3 -O1 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -DDEBUGVM=0 -D_GNU_SOURCE -DUSEEVDEV -DMUSL" +CFLAGS="$CFLAGS $OPT -I/usr/local/include" +LIBS="$LIBS -lexecinfo" +LDFLAGS="$LDFLAGS -L/usr/local/lib" +DUALMAP="-DDUAL_MAPPED_CODE_ZONE=0" +# librt and libpthread functions now supplied by libc. +# Many Linux systems supply empty library files but +# OpenBSD does not. +LIBRT="" +# OpenBSD has problems with fast-bitblt under gcc and clang +FASTBITBLT="" + +if [ $# -ge 1 ]; then + INSTALLDIR="$1"; shift +fi +if ../../../../scripts/checkSCCSversion ; then exit 1; fi +echo -n "clean? " +read a +case $a in +n|no|N|NO) echo "ok but this isn't safe!!";; +*) rm -f config.h; test -f Makefile && make reallyclean +esac +../../../../scripts/copylinuxpluginspecfiles +test -f config.h || ../../../../platforms/unix/config/configure \ + --with-vmversion=5.0 --with-src=src/spur64.cog \ + --without-vm-display-fbdev --without-npsqueak \ + --with-scriptname=spur64 \ + CC=$CC \ + CFLAGS="$MACHINE $OPT -DCOGMTVM=0 $DUALMAP" \ + LIBS=$LIBRT + +rm -f vm/sqUnixMain.o # nuke version info +rm -rf ../../../../products/$INSTALLDIR +# prefer make install prefix=`readlink -f \`pwd\`/../../../../products/$INSTALLDIR` +# but older openbsd readlinks lack the -f flag +make install-squeak install-plugins prefix=`(cd ../../../../;pwd)`/products/$INSTALLDIR 2>&1 | tee LOG ; test ${PIPESTATUS[0]} -eq 0 diff --git a/building/openbsd64ARMv8/squeak.cog.spur/build.debug/mvm b/building/openbsd64ARMv8/squeak.cog.spur/build.debug/mvm new file mode 100755 index 0000000000..8b0837d1d3 --- /dev/null +++ b/building/openbsd64ARMv8/squeak.cog.spur/build.debug/mvm @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +set -e +# debug Cog Spur VM with VM profiler and threaded heartbeat +INSTALLDIR=debug/sqcogspur64ARMv8openbsdht +# armv8.N-a all fail in signalSemaphoreWithIndex for N in 1,2,3,4,5 +MACHINE="-march=armv8-a -mtune=cortex-a72" +OPT="-g3 -O0 -DDEBUGVM=1 -DAIO_DEBUG=1 -D_GNU_SOURCE -DUSEEVDEV -DMUSL" +CFLAGS="$CFLAGS $OPT -I/usr/local/include" +LIBS="$LIBS -lexecinfo" +LDFLAGS="$LDFLAGS -L/usr/local/lib" +DUALMAP="-DDUAL_MAPPED_CODE_ZONE=0" +# librt and libpthread functions now supplied by libc. +# Many Linux systems supply empty library files but +# OpenBSD does not. +LIBRT="" +# OpenBSD has problems with fast-bitblt under gcc and clang +FASTBITBLT="" + +if [ $# -ge 1 ]; then + INSTALLDIR="$1"; shift +fi +if ../../../../scripts/checkSCCSversion ; then exit 1; fi +echo -n "clean? " +read a +case $a in +n|no|N|NO) echo "ok but this isn't safe!!";; +*) rm -f config.h; test -f Makefile && make reallyclean +esac +../../../../scripts/copylinuxpluginspecfiles +test -f config.h || ../../../../platforms/unix/config/configure \ + --with-vmversion=5.0 --with-src=src/spur64.cog \ + --without-vm-display-fbdev --without-npsqueak \ + --with-scriptname=spur64 \ + CC=$CC \ + CFLAGS="$MACHINE $OPT -DCOGMTVM=0 $DUALMAP" \ + LIBS=$LIBRT + +rm -f vm/sqUnixMain.o # nuke version info +rm -rf ../../../../products/$INSTALLDIR +# prefer make install prefix=`readlink -f \`pwd\`/../../../../products/$INSTALLDIR` +# but older openbsd readlinks lack the -f flag +make install-squeak install-plugins prefix=`(cd ../../../../;pwd)`/products/$INSTALLDIR 2>&1 | tee LOG ; test ${PIPESTATUS[0]} -eq 0 diff --git a/building/openbsd64ARMv8/squeak.cog.spur/build/mvm b/building/openbsd64ARMv8/squeak.cog.spur/build/mvm new file mode 100755 index 0000000000..970901675e --- /dev/null +++ b/building/openbsd64ARMv8/squeak.cog.spur/build/mvm @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +set -e +# Cog Spur VM with VM profiler and threaded heartbeat +INSTALLDIR=sqcogspur64ARMv8openbsdht +# armv8.N-a all fail in signalSemaphoreWithIndex for N in 1,2,3,4,5 +# tpr - add enablementisation of fast bitblt ben avison code +MACHINE="-march=armv8-a -mtune=cortex-a72" +OPT="-g -O2 -DNDEBUG -DDEBUGVM=0 -D_GNU_SOURCE -DUSEEVDEV -DMUSL" +CFLAGS="$CFLAGS $OPT -I/usr/local/include" +LIBS="$LIBS -lexecinfo" +LDFLAGS="$LDFLAGS -L/usr/local/lib" +DUALMAP="-DDUAL_MAPPED_CODE_ZONE=0" +# librt and libpthread functions now supplied by libc. +# Many Linux systems supply empty library files but +# OpenBSD does not. +LIBRT="" +# OpenBSD has problems with fast-bitblt under gcc and clang +FASTBITBLT="" + +# Prefer clang over gcc if available +if [ -n "$(command -v clang || true)" ]; then CC=clang; else CC=gcc; fi + +if [ $# -ge 1 ]; then + INSTALLDIR="$1"; shift +fi +if ../../../../scripts/checkSCCSversion ; then exit 1; fi +echo -n "clean? " +read a +case $a in +n|no|N|NO) echo "ok but this isn't safe!!";; +*) rm -f config.h; test -f Makefile && make reallyclean +esac +../../../../scripts/copylinuxpluginspecfiles +test -f config.h || ../../../../platforms/unix/config/configure \ + --with-vmversion=5.0 --with-src=src/spur64.cog \ + --without-npsqueak \ + --with-scriptname=spur64 \ + $FASTBITBLT \ + CC=$CC \ + CFLAGS="$MACHINE $OPT -DCOGMTVM=0 $DUALMAP" \ + LIBS=$LIBRT +## --without-vm-display-fbdev --without-npsqueak \ +rm -f vm/sqUnixMain.o # nuke version info +rm -rf ../../../../products/$INSTALLDIR +# prefer make install prefix=`readlink -f \`pwd\`/../../../../products/$INSTALLDIR` +# but older linux readlinks lack the -f flag +make install-squeak install-plugins prefix=`(cd ../../../../;pwd)`/products/$INSTALLDIR 2>&1 | tee LOG ; test ${PIPESTATUS[0]} -eq 0 diff --git a/building/openbsd64ARMv8/squeak.cog.spur/makeclean b/building/openbsd64ARMv8/squeak.cog.spur/makeclean new file mode 100755 index 0000000000..a7cac6bd4e --- /dev/null +++ b/building/openbsd64ARMv8/squeak.cog.spur/makeclean @@ -0,0 +1,15 @@ +#!/bin/sh -e +trap 'exit 2' HUP INT PIPE TERM +if [ "$1" = -fork ]; then + shift + for d in `dirname $0`/build*; do + (cd ./$d + echo y | ./mvm "$@") & + done + wait +else + for d in `dirname $0`/build*; do + (cd ./$d + echo y | ./mvm "$@") + done +fi diff --git a/building/openbsd64ARMv8/squeak.cog.spur/makedirty b/building/openbsd64ARMv8/squeak.cog.spur/makedirty new file mode 100755 index 0000000000..11f39e8808 --- /dev/null +++ b/building/openbsd64ARMv8/squeak.cog.spur/makedirty @@ -0,0 +1,15 @@ +#!/bin/sh -e +trap 'exit 2' HUP INT PIPE TERM +if [ "$1" = -fork ]; then + shift + for d in `dirname $0`/build*; do + (cd ./$d + echo n | ./mvm "$@") & + done + wait +else + for d in `dirname $0`/build*; do + (cd ./$d + echo n | ./mvm "$@") + done +fi diff --git a/building/openbsd64ARMv8/squeak.cog.spur/plugins.ext b/building/openbsd64ARMv8/squeak.cog.spur/plugins.ext new file mode 100644 index 0000000000..c06e7f571b --- /dev/null +++ b/building/openbsd64ARMv8/squeak.cog.spur/plugins.ext @@ -0,0 +1,26 @@ +# Copied, perhaps edited, from ../../../src/examplePlugins.ext +EXTERNAL_PLUGINS = \ +B3DAcceleratorPlugin \ +BochsIA32Plugin \ +BochsX64Plugin \ +ClipboardExtendedPlugin \ +FileAttributesPlugin \ +MIDIPlugin \ +Squeak3D \ +SqueakFFIPrims \ +SqueakSSL \ +LocalePlugin \ +UnicodePlugin \ +UnixOSProcessPlugin \ +UUIDPlugin \ +ImmX11Plugin \ +XDisplayControlPlugin \ +DESPlugin \ +MD5Plugin \ +SHA2Plugin \ +VectorEnginePlugin \ +PseudoTTYPlugin \ +## CameraPlugin -- fails on OpenBSD +# GdbARMPlugin # fails to compile +# GdbARMv8Plugin # ditto + diff --git a/building/openbsd64ARMv8/squeak.cog.spur/plugins.int b/building/openbsd64ARMv8/squeak.cog.spur/plugins.int new file mode 100644 index 0000000000..102ddaca84 --- /dev/null +++ b/building/openbsd64ARMv8/squeak.cog.spur/plugins.int @@ -0,0 +1,39 @@ +# Copied, perhaps edited, from ../../../src/examplePlugins.int +INTERNAL_PLUGINS = \ +ADPCMCodecPlugin \ +AioPlugin \ +AsynchFilePlugin \ +B2DPlugin \ +BitBltPlugin \ +BMPReadWriterPlugin \ +CroquetPlugin \ +HostWindowPlugin \ +ZipPlugin \ +DropPlugin \ +DSAPrims \ +FFTPlugin \ +FileCopyPlugin \ +FilePlugin \ +FileDialogPlugin \ +Float64ArrayPlugin \ +FloatArrayPlugin \ +FloatMathPlugin \ +IA32ABI \ +JoystickTabletPlugin \ +JPEGReaderPlugin \ +JPEGReadWriter2Plugin \ +Klatt \ +LargeIntegers \ +Matrix2x3Plugin \ +MiscPrimitivePlugin \ +Mpeg3Plugin \ +RePlugin \ +SecurityPlugin \ +SerialPlugin \ +SocketPlugin \ +SoundCodecPrims \ +SoundGenerationPlugin \ +SoundPlugin \ +StarSqueakPlugin \ +SurfacePlugin \ +VMProfileLinuxSupportPlugin diff --git a/building/openbsd64ARMv8/squeak.stack.spur/build.assert/mvm b/building/openbsd64ARMv8/squeak.stack.spur/build.assert/mvm new file mode 100755 index 0000000000..479c02b942 --- /dev/null +++ b/building/openbsd64ARMv8/squeak.stack.spur/build.assert/mvm @@ -0,0 +1,43 @@ +#!/usr/bin/env bash +set -e +# assert Stack Spur VM with VM profiler and threaded heartbeat +INSTALLDIR=assert/sqstkspur64ARMv8openbsdht +OPT="-g3 -O1 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -DDEBUGVM=0 -D_GNU_SOURCE -DUSEEVDEV -DMUSL" +CFLAGS="$CFLAGS $OPT -I/usr/local/include" +LIBS="$LIBS -lexecinfo" +LDFLAGS="$LDFLAGS -L/usr/local/lib" +DUALMAP="-DDUAL_MAPPED_CODE_ZONE=0" +# librt and libpthread functions now supplied by libc. +# Many Linux systems supply empty library files but +# OpenBSD does not. +LIBRT="" +# OpenBSD has problems with fast-bitblt under gcc and clang +FASTBITBLT="" + +# Prefer clang over gcc if available +if [ -n "$(command -v clang || true)" ]; then CC=clang; else CC=gcc; fi + +if [ $# -ge 1 ]; then + INSTALLDIR="$1"; shift +fi +if ../../../../scripts/checkSCCSversion ; then exit 1; fi +echo -n "clean? " +read a +case $a in +n|no|N|NO) echo "ok but this isn't safe!!";; +*) rm -f config.h; test -f Makefile && make reallyclean +esac +../../../../scripts/copylinuxpluginspecfiles +test -f config.h || ../../../../platforms/unix/config/configure \ + --with-vmversion=5.0 \ + --with-src=src/spur64.stack --disable-cogit \ + --without-vm-display-fbdev --without-npsqueak \ + --with-scriptname=spur64 \ + TARGET_ARCH="-march=armv8-a" \ + CC=$CC \ + CFLAGS="$OPT -D__ARM_ARCH_ISA_A64 -DARM64 -D__arm__ -D__arm64__ -D__aarch64__ $DUALMAP" +rm -f vm/sqUnixMain.o # nuke version info +rm -rf ../../../../products/$INSTALLDIR +# prefer make install prefix=`readlink -f \`pwd\`/../../../../products/$INSTALLDIR` +# but older linux readlinks lack the -f flag +make install-squeak install-plugins prefix=`(cd ../../../../;pwd)`/products/$INSTALLDIR 2>&1 | tee LOG ; test ${PIPESTATUS[0]} -eq 0 diff --git a/building/openbsd64ARMv8/squeak.stack.spur/build.debug/mvm b/building/openbsd64ARMv8/squeak.stack.spur/build.debug/mvm new file mode 100755 index 0000000000..649b14a446 --- /dev/null +++ b/building/openbsd64ARMv8/squeak.stack.spur/build.debug/mvm @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +set -e +# debug Stack Spur VM with VM profiler and threaded heartbeat +INSTALLDIR=debug/sqstkspur64ARMv8openbsdht +OPT="-g3 -O0 -DDEBUG -DDEBUGVM=1 -DAIO_DEBUG -D_GNU_SOURCE -DUSEEVDEV -DMUSL" + +CFLAGS="$CFLAGS $OPT -I/usr/local/include" +LIBS="$LIBS -lexecinfo" +LDFLAGS="$LDFLAGS -L/usr/local/lib" +DUALMAP="-DDUAL_MAPPED_CODE_ZONE=0" +# librt and libpthread functions now supplied by libc. +# Many Linux systems supply empty library files but +# OpenBSD does not. +LIBRT="" +# OpenBSD has problems with fast-bitblt under gcc and clang +FASTBITBLT="" + +# Prefer clang over gcc if available +if [ -n "$(command -v clang || true)" ]; then CC=clang; else CC=gcc; fi + +if [ $# -ge 1 ]; then + INSTALLDIR="$1"; shift +fi +if ../../../../scripts/checkSCCSversion ; then exit 1; fi +echo -n "clean? " +read a +case $a in +n|no|N|NO) echo "ok but this isn't safe!!";; +*) rm -f config.h; test -f Makefile && (make -n reallyclean;make reallyclean) +esac +../../../../scripts/copylinuxpluginspecfiles +test -f config.h || ../../../../platforms/unix/config/configure \ + --with-vmversion=5.0 \ + --with-src=src/spur64.stack --disable-cogit \ + --without-npsqueak \ + --with-scriptname=spur64 \ + TARGET_ARCH="-march=armv8-a" \ + CC=$CC \ + CFLAGS="$OPT -D__ARM_ARCH_ISA_A64 -DARM64 -D__arm__ -D__arm64__ -D__aarch64__ $DUALMAP" +## --without-vm-display-fbdev --without-npsqueak \ +rm -f vm/sqUnixMain.o # nuke version info +rm -rf ../../../../products/$INSTALLDIR +# prefer make install prefix=`readlink -f \`pwd\`/../../../../products/$INSTALLDIR` +# but older linux readlinks lack the -f flag +make install-squeak install-plugins prefix=`(cd ../../../../;pwd)`/products/$INSTALLDIR 2>&1 | tee LOG ; test ${PIPESTATUS[0]} -eq 0 diff --git a/building/openbsd64ARMv8/squeak.stack.spur/build/mvm b/building/openbsd64ARMv8/squeak.stack.spur/build/mvm new file mode 100755 index 0000000000..7d92a10992 --- /dev/null +++ b/building/openbsd64ARMv8/squeak.stack.spur/build/mvm @@ -0,0 +1,45 @@ + +#!/usr/bin/env bash +set -e +# Stack Spur VM with VM profiler and threaded heartbeat +INSTALLDIR=sqstkspur64ARMv8openbsdht +OPT="-g -O2 -DNDEBUG -DDEBUGVM=0 -DMUSL -D_GNU_SOURCE -DUSEEVDEV -DMUSL" +CFLAGS="$CFLAGS $OPT -I/usr/local/include" +LIBS="$LIBS -lexecinfo" +LDFLAGS="$LDFLAGS -L/usr/local/lib" +DUALMAP="-DDUAL_MAPPED_CODE_ZONE=0" +# librt and libpthread functions now supplied by libc. +# Many Linux systems supply empty library files but +# OpenBSD does not. +LIBRT="" +# OpenBSD has problems with fast-bitblt under gcc and clang +FASTBITBLT="" + +# Prefer clang over gcc if available +if [ -n "$(command -v clang || true)" ]; then CC=clang; else CC=gcc; fi + +if [ $# -ge 1 ]; then + INSTALLDIR="$1"; shift +fi +if ../../../../scripts/checkSCCSversion ; then exit 1; fi +echo -n "clean? " +read a +case $a in +n|no|N|NO) echo "ok but this isn't safe!!";; +*) rm -f config.h; test -f Makefile && make reallyclean +esac +../../../../scripts/copylinuxpluginspecfiles +test -f config.h || ../../../../platforms/unix/config/configure \ + --with-vmversion=5.0 \ + --with-src=src/spur64.stack --disable-cogit \ + --without-npsqueak \ + --with-scriptname=spur64 \ + TARGET_ARCH="-march=armv8-a" \ + CC=$CC \ + CFLAGS="$OPT -D__ARM_ARCH_ISA_A64 -DARM64 -D__arm__ -D__arm64__ -D__aarch64__ $DUALMAP" + +rm -f vm/sqUnixMain.o # nuke version info +rm -rf ../../../../products/$INSTALLDIR +# prefer make install prefix=`readlink -f \`pwd\`/../../../../products/$INSTALLDIR` +# but older linux readlinks lack the -f flag +make install-squeak install-plugins prefix=`(cd ../../../../;pwd)`/products/$INSTALLDIR 2>&1 | tee LOG ; test ${PIPESTATUS[0]} -eq 0 diff --git a/building/openbsd64ARMv8/squeak.stack.spur/makeallclean b/building/openbsd64ARMv8/squeak.stack.spur/makeallclean new file mode 100755 index 0000000000..a7cac6bd4e --- /dev/null +++ b/building/openbsd64ARMv8/squeak.stack.spur/makeallclean @@ -0,0 +1,15 @@ +#!/bin/sh -e +trap 'exit 2' HUP INT PIPE TERM +if [ "$1" = -fork ]; then + shift + for d in `dirname $0`/build*; do + (cd ./$d + echo y | ./mvm "$@") & + done + wait +else + for d in `dirname $0`/build*; do + (cd ./$d + echo y | ./mvm "$@") + done +fi diff --git a/building/openbsd64ARMv8/squeak.stack.spur/makedirty b/building/openbsd64ARMv8/squeak.stack.spur/makedirty new file mode 100755 index 0000000000..11f39e8808 --- /dev/null +++ b/building/openbsd64ARMv8/squeak.stack.spur/makedirty @@ -0,0 +1,15 @@ +#!/bin/sh -e +trap 'exit 2' HUP INT PIPE TERM +if [ "$1" = -fork ]; then + shift + for d in `dirname $0`/build*; do + (cd ./$d + echo n | ./mvm "$@") & + done + wait +else + for d in `dirname $0`/build*; do + (cd ./$d + echo n | ./mvm "$@") + done +fi diff --git a/building/openbsd64ARMv8/squeak.stack.spur/plugins.ext b/building/openbsd64ARMv8/squeak.stack.spur/plugins.ext new file mode 100644 index 0000000000..bb3f5546b2 --- /dev/null +++ b/building/openbsd64ARMv8/squeak.stack.spur/plugins.ext @@ -0,0 +1,22 @@ +# Copied, perhaps edited, from ../../../src/examplePlugins.ext +EXTERNAL_PLUGINS = \ +B3DAcceleratorPlugin \ +ClipboardExtendedPlugin \ +FileAttributesPlugin \ +MIDIPlugin \ +Squeak3D \ +SqueakFFIPrims \ +SqueakSSL \ +LocalePlugin \ +UnicodePlugin \ +UnixOSProcessPlugin \ +UUIDPlugin \ +ImmX11Plugin \ +XDisplayControlPlugin \ +DESPlugin \ +MD5Plugin \ +SHA2Plugin \ +VectorEnginePlugin \ +PseudoTTYPlugin \ +## CameraPlugin \ -- fails on OpenBSD + diff --git a/building/openbsd64ARMv8/squeak.stack.spur/plugins.int b/building/openbsd64ARMv8/squeak.stack.spur/plugins.int new file mode 100644 index 0000000000..102ddaca84 --- /dev/null +++ b/building/openbsd64ARMv8/squeak.stack.spur/plugins.int @@ -0,0 +1,39 @@ +# Copied, perhaps edited, from ../../../src/examplePlugins.int +INTERNAL_PLUGINS = \ +ADPCMCodecPlugin \ +AioPlugin \ +AsynchFilePlugin \ +B2DPlugin \ +BitBltPlugin \ +BMPReadWriterPlugin \ +CroquetPlugin \ +HostWindowPlugin \ +ZipPlugin \ +DropPlugin \ +DSAPrims \ +FFTPlugin \ +FileCopyPlugin \ +FilePlugin \ +FileDialogPlugin \ +Float64ArrayPlugin \ +FloatArrayPlugin \ +FloatMathPlugin \ +IA32ABI \ +JoystickTabletPlugin \ +JPEGReaderPlugin \ +JPEGReadWriter2Plugin \ +Klatt \ +LargeIntegers \ +Matrix2x3Plugin \ +MiscPrimitivePlugin \ +Mpeg3Plugin \ +RePlugin \ +SecurityPlugin \ +SerialPlugin \ +SocketPlugin \ +SoundCodecPrims \ +SoundGenerationPlugin \ +SoundPlugin \ +StarSqueakPlugin \ +SurfacePlugin \ +VMProfileLinuxSupportPlugin diff --git a/building/openbsd64x64/HowToBuild b/building/openbsd64x64/HowToBuild new file mode 100644 index 0000000000..f7e4d11e35 --- /dev/null +++ b/building/openbsd64x64/HowToBuild @@ -0,0 +1,265 @@ +How To Build On Linux +--------------------- + + +Contents: + - Overview + - Checking out sources to build out-of-the-box + - Building out of the box + - Building the VM Simulator Support Libraries + - How to configure and build a VM on Unix + - Debugging configuration failures + - Testing an external plugin has completely linked + - Optimization level and gcc version (please read!) + - Installing support libraries + + +Overview +-------- +The "Cog" VM comes in a bewildering variety of forms. The first distinction +is between Squeak/Croquet VMs that run Squeak, Pharo, Cuis, Croquet images +and their ilk, and between Newspeak VMs that run Newspeak. + +Another distinction is between Stack, Cog and Sista VMs. Stack VMs are those +with context-to-stack mapping that optimise message sending by keeping method +activations on a stack instead of in contexts. These are pure interpreters but +significantly faster than the standard context-based Interpreter VM. Cog VMs +add a JIT to the mix, compiling methods used more than once to maxchine code on +the fly. Sista VMs, as yet unrealised and in development, add support for +adaptive optimization that does speculative inlining at the bytecode-to-bytecode +level. These are targeted for release in 2015. + +Another distinction is between "v3" VMs and Spur VMs. "v3" is the original +object representation for Squeak as described in the back-to-the-future paper. +Spur, as described on the www.mirandabanda.org blog, is a faster object +representation which uses generation scavenging, lazy forwarding for fast +become, and a single object header format common to 32 and 64 bit versions. + +Another distinction is between normal single-threaded VMs that schedule "green" +Smalltalk processes above a single-threaded VM, and "multi-threaded" VMs that +share the VM between any number of native threads such that only one native +thread owns the VM at any one time, switching between threads on FFI calls and +callbacks or on Smalltalk process switches when Smalltalk processes are owned +by threads. This multi-threaded support is as yet experimental. + +A distinction on linux is between VMs with an itimer hearbeat or a threaded +heartbeat. VMs with an itimer hearbeat use setitimer to deliver a SIGALRM +signal at regular intervals to interrupt the VM to check for events. These +signals can be troublesome, interrupting foreign code that cannot cope with +such signals. VMs with a threaded heartbeat use a high-priority thread that +loops, blocking on nanosleep and then interrupting the VM, performing the same +function as the itimer heartbeat but without using signals. These VMs are to +be preferred but suport for multiple thread priorities in user-level processes +has only been available on linux in kernels later than 2.6.12. + +The final distinction is between production, assert and debug VMs. Production +VMs are fully optimized, although they may include debugging symbols, and as +their name implies are for use in production. Assert and debug VMs include +many assert checks that are disabled in the production VMs. These asserts are +very helpful in debugging VM problems but significantly impact performance. +The difference between assert and debug VMs is that assert VMs are compiled +with moderate optimization, which improves the performance of the asserts, +whereas debug VMs are compiled with no optimization at all, providing maximum +debuggability with minimum performance. + +This directory tree provides build directories for some of this matrix. For +example, squeak.cog.v3 contains build directories for Smalltalk Cog VMs using +the old object representation, newspeak.stack.spur contains build directories +for Newspeak Stack VMs using the Spur object representation. Build as desired. + + +Checking out sources to build out-of-the-box +-------------------------------------------- +Check-out the repository from github: + git clone http://www.github.com/OpenSmalltalk/opensmalltalk-vm oscogvm + cd ./oscogvm + more README.md + + +Building out of the box +----------------------- +Install the tools (gcc, X11-devel, etc, e.g. libpng, libuuid libX11 & libxt +source). See "Installing support libraries" below. If the configure step fails +when "checking for C compiler default output file name", you have yet to install +all the necessary support packages (e.g. libuuid). +Then cd to the build directory of your choice, e.g. + building/linux64x64/squeak.cog.spur/build +Then execute + ./mvm + +answering "y" to perform a clean build or "n" to rebuild without reconfiguring. +Again, if the configure step fails when "checking for C compiler default output +file name", you have yet to install all the necessary support (e.g. lubuuid). + +The subdirectories conform to the production/assert/debug x itimer vs threaded +heartbeat x single vs multi-threaded parts of the matrix described above. For +example, building/linux64x64/squeak.cog.v3 includes + + build + build.itimerheartbeat + build.multithreaded + + build.assert + build.assert.itimerheartbeat + build.multithreaded.assert + + build.debug + build.multithreaded.debug + build.debug.itimerheartbeat + +subdirectories. It includes two convenience scripts that will make all +configurations: + makeallclean + makealldirty + +Each build directory contains three files + mvm + plugins.int + plugins.ext +The mvm script runs ../../platforms/unix/config/configure with the relevant +options, runs make, and then make install to create a VM directory tree in +../../products, ../../products/assert or ../../products/debug as appropriate. +plugins.int and plugins.ext determine the set of plugins to be taken from +the supplied plugins directory (which defaults to ../../src/plugins), and which +are to be linked into the VM (plugins.int) or compiled as external shared +objects to be dynamically linked at run-time (plugins.ext). + +Finally, at the building/linux64x64 level the makeall script will run all the +makeallclean scripts it can find. + + +Building the VM Simulator Support Libraries +------------------------------------------- +If you want to get the Cog VM simulator working you'll need to build one or more +of the processor simulator plugins, each of which has support libraries that +must be built: + Processor Plugin Support Library + x86 BochsIA32Plugin building/linux64x64/bochsx86 + x86_64/x64 BochsX64Plugin building/linux64x64/bochsx64 + ARMv5 GdbARMPlugin building/linux64x64/gdbarm32 +cd to the relevant directories; run conf.COG and then the build script, e.g. + $ cd building/linux64x64/bochsx86 + $ ./conf.COG + $ ./makeem + +Then when Squeak VMs are built they will include the plugin(s) for which support +libraries have been provided. + + +How to configure and build a VM on Unix +--------------------------------------- +The mvm scripts are themselves wrappers around an adaptation of Ian Piumarta's +Squeak build system above autoconf to the Cog sources. One can choose the vm +source files, plugin source files, and optimization level to compile a VM of +your choice. To find the full set of options via + + ../../platforms/unix/config/configure --help + +You can see the use of configure in the various mvm scripts in each build +directory. + +e.g. + ../../../platforms/unix/config/configure --without-npsqueak CFLAGS="-g -O2 -msse2 -D_GNU_SOURCE -DNDEBUG -DITIMER_HEARTBEAT=1 -DCOGMTVM=0 -DDEBUGVM=0" LIBS=-lpthread + make install prefix=WhereYouWantTheVmToGo + + N.B. If you're on a 64-bit linux read 3e below!! + N.B. On Ubuntu *do not* supply "LIBS=-lpthread -luuid", i.e. use + ../../../platforms/unix/config/configure --without-npsqueak CFLAGS="-g -O2 -msse2 -D_GNU_SOURCE -DNDEBUG -DITIMER_HEARTBEAT=1 -DCOGMTVM=0 -DDEBUGVM=0" + + +N.B. The plugin set is defined by plugins.ext and plugins.int in the build dir. + +Be prepared to install libuuid support. e.g. on CentOS 6.5 use +sudo yum -y install libuuid-devel + + +Debugging configuration failures +-------------------------------- +If your development system does not have the required libraries installed then +the configure step run by the mvm script will fail cryptically. You will see +something like + checking sanity of generated src directory... okay + checking build system type... i686-pc-linux-gnu + checking host system type... i686-pc-linux-gnu + checking target system type... i686-pc-linux-gnu + + Configuring Squeak (.-) for i686-pc-linux-gnu + + checking whether make sets $(MAKE)... yes + checking for gcc... gcc -m32 + checking for C compiler default output file name... configure: error: C compiler cannot create executables + See `config.log' for more details. +But config.log is missing the relevant details. It only contains the failing gcc +invocation, not the output from that failing command. To diagnose, grep to find +the gcc invocation: + $ grep gcc config.log + ... + configure:2269: gcc -m32 -g3 -O0 -fwrapv -DDEBUGVM=1 -DEnforceAccessControl=0 -msse2 -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -Wl,-z,now conftest.c -lpthread -luuid >& +and then repeat the compilation supplying your own test file, e.g. + $ gcc -m32 -g3 -O0 -fwrapv -DDEBUGVM=1 -DEnforceAccessControl=0 -msse2 -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -Wl,-z,now helloworld.c -lpthread -luuid + helloworld.c: In function 'main': + /usr/bin/ld: cannot find -luuid + collect2: ld returned 1 exit status +From which one can infer that one needs to install either the 64-bit or the 32-bit +version of libuuid, e.g. sudo yum install libuuid-devel + + +Testing an external plugin has completely linked +------------------------------------------------ +You may find that an external plugin compiles and links but does not load. +This is usually because it contans undefined symbols. To find undefined +symbols, remake the plugin, capturing the link step and then supply + -Wl,--warn-unresolved-symbols -Wl,--no-allow-shlib-undefined +when manually repeating the link command + + +Optimization level and gcc version +---------------------------------- +There are issues with gcc version > 4.2.1. Any of the following flags may break the build at -O2: +-ftree-pre +-fpartial-inlining +-fcaller-saves + +So turn them off. e.g. + ../../../platforms/unix/config/configure --without-npsqueak CFLAGS="-g -O2 -msse2 -fno-caller-saves -fno-partial-inlining -fno-tree-pre -D_GNU_SOURCE -DNDEBUG -DCOGMTVM=0 -DDEBUGVM=0" LIBS="-lpthread -luuid" +See http://smallissimo.blogspot.fr/2013/02/compiling-squeak-cog-virtual-machine-on.html + +There appear to be issues with 3.4.x gcc version on RedHat. In particular +compiling the Newspeak VM with either of + gcc version 3.4.6 20060404 (Red Hat 3.4.6-3) + gcc version 3.4.6 20060404 (Red Hat 3.4.6-10) +using -O2 results in a VM that segfaults early in startup. For these compilers +it is probably wise to use -O1, even though -O3 seems to work. + +People have reported that the OSProcessPlugin is broken on gcc versions > 4.8 +on Debian. + + +Installing support libraries +---------------------------- +Different linux distributions have different mechanisms for loading packages. +Here are some examples: + +CentOS + sudo yum install -y cairo-devel + sudo yum install -y pango-devel + sudo yum install -y libuuid-devel + sudo yum install -y libX11-devel + sudo yum install -y mesa-libGL-devel + sudo yum install -y openssl-devel + sudo yum install -y cmake + sudo yum install -y gcc-c++ +N.B. if you get failures due to version conflicts try + sudo yum update +and then retry. + +Ubuntu + sudo apt install clang + sudo apt install uuid-dev libcairo2-dev libpango1.0-dev libgl1-mesa-dev + sudo apt install libssl-dev libevdev-dev m4 libpulse-dev + sudo apt install libxrandr-dev + sudo apt install libgl1-mesa-glx # before Ubuntu 18.04 + sudo apt install libgl1 libglx-mesa0 # since Ubuntu 18.04 + (gcc-multilib libgl1-mesa-glx:i386 for 32-bit builds on on 64-bit installations) + +More advice and examples for other distros gratefully received. diff --git a/building/openbsd64x64/makeall b/building/openbsd64x64/makeall new file mode 100755 index 0000000000..923f2bef7a --- /dev/null +++ b/building/openbsd64x64/makeall @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -e +trap 'exit 2' HUP INT PIPE TERM +for d in *.spur *.v3; do + if test -d "$d"; then + (cd ./$d;./makealldirty "$@") + else + echo no $d directory found + fi +done diff --git a/building/openbsd64x64/makeallclean b/building/openbsd64x64/makeallclean new file mode 100755 index 0000000000..53083e5189 --- /dev/null +++ b/building/openbsd64x64/makeallclean @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -e +trap 'exit 2' HUP INT PIPE TERM +for d in *.spur *.v3; do + if test -d "$d"; then + (cd ./$d;./makeallclean "$@") + else + echo no $d directory found + fi +done diff --git a/building/openbsd64x64/makeallmakefiles b/building/openbsd64x64/makeallmakefiles new file mode 100755 index 0000000000..18f4d62873 --- /dev/null +++ b/building/openbsd64x64/makeallmakefiles @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -e +trap 'exit 2' HUP INT PIPE TERM +for td in *.v3 *.spur; do + for d in $td/build*; do + if test -d "$d"; then + (cd ./$d;../../../../platforms/unix/config/mkmf) + else + echo no $d directory found + fi + done +done diff --git a/building/openbsd64x64/makeallsqueak b/building/openbsd64x64/makeallsqueak new file mode 100755 index 0000000000..7c86642aa0 --- /dev/null +++ b/building/openbsd64x64/makeallsqueak @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -e +trap 'exit 2' HUP INT PIPE TERM +for d in squeak.* + if test -d "$d"; then + (cd ./$d;./makealldirty "$@") + else + echo no $d directory found + fi +done diff --git a/building/openbsd64x64/makeproduct b/building/openbsd64x64/makeproduct new file mode 100755 index 0000000000..9585288fb9 --- /dev/null +++ b/building/openbsd64x64/makeproduct @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -e +trap 'exit 2' HUP INT PIPE TERM +for d in newspeak.cog.spur squeak.cog.spur; do + if test -d "$d"; then + (cd ./$d;./makealldirty "$@") + else + echo no $d directory found + fi +done diff --git a/building/openbsd64x64/makeproductclean b/building/openbsd64x64/makeproductclean new file mode 100755 index 0000000000..2c6cb37619 --- /dev/null +++ b/building/openbsd64x64/makeproductclean @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -e +trap 'exit 2' HUP INT PIPE TERM +for d in newspeak.cog.spur squeak.cog.spur; do + if test -d "$d"; then + (cd ./$d;./makeallclean "$@") + else + echo no $d directory found + fi +done diff --git a/building/openbsd64x64/squeak.cog.spur/README.OpenBSD b/building/openbsd64x64/squeak.cog.spur/README.OpenBSD new file mode 100644 index 0000000000..e6839c493c --- /dev/null +++ b/building/openbsd64x64/squeak.cog.spur/README.OpenBSD @@ -0,0 +1,6 @@ +For OpenBSD one MUST install Cog executable files under /usr/local. + +Otherwise the OS will report: + + Could not allocate JIT Memort: Not supported + diff --git a/building/openbsd64x64/squeak.cog.spur/build.assert.itimerheartbeat/mvm b/building/openbsd64x64/squeak.cog.spur/build.assert.itimerheartbeat/mvm new file mode 100755 index 0000000000..8e86ccb73a --- /dev/null +++ b/building/openbsd64x64/squeak.cog.spur/build.assert.itimerheartbeat/mvm @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +set -e +# assert VM with VM profiler and itimer heartbeat +INSTALLDIR=assert/sqcogspur64openbsd +OPT="-g3 -O1 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -DDEBUGVM=0 -D_GNU_SOURCE -DUSEEVDEV -DMUSL" + + +# Prefer clang over gcc if available +if [ -n "$(command -v clang || true)" ]; then CC=clang; else CC=gcc; fi + +# librt and libpthread funs now supplied by libc +# Many Openbsd systems supply empty library files +# but OpenBSD does not. +LIBRT="" + +CFLAGS="$OPT -msse2 -DCOGMTVM=0" +LIBS=$LIBRT +LDFLAGS="" + +CFLAGS="$CFLAGS -I/usr/local/include" +LIBS="$LIBS -lexecinfo" +LDFLAGS="$LDFLAGS -L/usr/local/lib" + +if [ $# -ge 1 ]; then + INSTALLDIR="$1"; shift +fi + +if ../../../../scripts/checkSCCSversion ; then exit 1; fi +echo -n "clean? " +read a +case $a in +n|no|N|NO) echo "ok but this isn't safe!!";; +*) test -f Makefile && make reallyclean +esac +../../../../scripts/copylinuxpluginspecfiles +test -f config.h || ../../../../platforms/unix/config/configure --without-npsqueak \ + --with-vmversion=5.0 \ + --with-src=src/spur64.cog \ + --with-scriptname=spur64 \ + TARGET_ARCH="-m64" \ + CC=$CC \ + CFLAGS="$OPT -msse2 -DCOGMTVM=0 -DITIMER_HEARTBEAT=1" +rm -f vm/sqUnixMain.o # nuke version info +rm -rf ../../../../products/$INSTALLDIR +# prefer make install prefix=`readlink -f \`pwd\`/../../../../products/$INSTALLDIR` +# but older openbsd readlinks lack the -f flag +make install-squeak install-plugins prefix=`(cd ../../../../;pwd)`/products/$INSTALLDIR 2>&1 | tee LOG ; test ${PIPESTATUS[0]} -eq 0 diff --git a/building/openbsd64x64/squeak.cog.spur/build.assert/mvm b/building/openbsd64x64/squeak.cog.spur/build.assert/mvm new file mode 100755 index 0000000000..fe2080e8ba --- /dev/null +++ b/building/openbsd64x64/squeak.cog.spur/build.assert/mvm @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +set -e +# assert VM with VM profiler and threaded heartbeat +INSTALLDIR=assert/sqcogspur64openbsdht +OPT="-g3 -O1 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -DDEBUGVM=0 -DMUSL" + +# Prefer clang over gcc if available +if [ -n "$(command -v clang || true)" ]; then CC=clang; else CC=gcc; fi + +# librt and libpthread funs now supplied by libc +# Many Openbsd systems supply empty library files +# but OpenBSD does not. +LIBRT="" + +CFLAGS="$OPT -msse2 -DCOGMTVM=0" +LIBS=$LIBRT +LDFLAGS="" + +CFLAGS="$CFLAGS -I/usr/local/include" +LIBS="$LIBS -lexecinfo" +LDFLAGS="$LDFLAGS -L/usr/local/lib" + +if [ $# -ge 1 ]; then + INSTALLDIR="$1"; shift +fi + +if ../../../../scripts/checkSCCSversion ; then exit 1; fi +echo -n "clean? " +read a +case $a in +n|no|N|NO) echo "ok but this isn't safe!!";; +*) test -f Makefile && make reallyclean +esac +../../../../scripts/copylinuxpluginspecfiles +test -f config.h || ../../../../platforms/unix/config/configure --without-npsqueak \ + --with-vmversion=5.0 \ + --with-src=src/spur64.cog \ + --with-scriptname=spur64 \ + TARGET_ARCH="-m64" \ + CC=$CC \ + CFLAGS="$CFLAGS" \ + LIBS="$LIBS" \ + LDFLAGS="$LDFLAGS" + +rm -f vm/sqUnixMain.o # nuke version info +rm -rf ../../../../products/$INSTALLDIR +# prefer make install prefix=`readlink -f \`pwd\`/../../../../products/$INSTALLDIR` +# but older openbsd readlinks lack the -f flag +make install-squeak install-plugins prefix=`(cd ../../../../;pwd)`/products/$INSTALLDIR 2>&1 | tee LOG ; test ${PIPESTATUS[0]} -eq 0 diff --git a/building/openbsd64x64/squeak.cog.spur/build.debug.itimerheartbeat/mvm b/building/openbsd64x64/squeak.cog.spur/build.debug.itimerheartbeat/mvm new file mode 100755 index 0000000000..6cbd639e87 --- /dev/null +++ b/building/openbsd64x64/squeak.cog.spur/build.debug.itimerheartbeat/mvm @@ -0,0 +1,47 @@ +#!/usr/bin/env bash +set -e +# debug Spur VM with VM profiler and itimer heartbeat +INSTALLDIR=debug/sqcogspur64openbsd +OPT="-g3 -O0 -DDEBUGVM=1 -D_GNU_SOURCE -DUSEEVDEV -DMUSL" + +# Prefer clang over gcc if available +if [ -n "$(command -v clang || true)" ]; then CC=clang; else CC=gcc; fi + +# librt and libpthread funs now supplied by libc +# Many Openbsd systems supply empty library files +# but OpenBSD does not. +LIBRT="" + +CFLAGS="$OPT -msse2 -DCOGMTVM=0" +LIBS=$LIBRT +LDFLAGS="" + +CFLAGS="$CFLAGS -I/usr/local/include" +LIBS="$LIBS -lexecinfo" +LDFLAGS="$LDFLAGS -L/usr/local/lib" + + +if [ $# -ge 1 ]; then + INSTALLDIR="$1"; shift +fi + +if ../../../../scripts/checkSCCSversion ; then exit 1; fi +echo -n "clean? " +read a +case $a in +n|no|N|NO) echo "ok but this isn't safe!!";; +*) test -f Makefile && make reallyclean +esac +../../../../scripts/copylinuxpluginspecfiles +test -f config.h || ../../../../platforms/unix/config/configure --without-npsqueak \ + --with-vmversion=5.0 \ + --with-src=src/spur64.cog \ + --with-scriptname=spur64 \ + TARGET_ARCH="-m64" \ + CC=$CC \ + CFLAGS="$OPT -msse2 -DCOGMTVM=0 -DITIMER_HEARTBEAT=1" +rm -f vm/sqUnixMain.o # nuke version info +rm -rf ../../../../products/$INSTALLDIR +# prefer make install prefix=`readlink -f \`pwd\`/../../../../products/$INSTALLDIR` +# but older openbsd readlinks lack the -f flag +make install-squeak install-plugins prefix=`(cd ../../../../;pwd)`/products/$INSTALLDIR 2>&1 | tee LOG ; test ${PIPESTATUS[0]} -eq 0 diff --git a/building/openbsd64x64/squeak.cog.spur/build.debug/mvm b/building/openbsd64x64/squeak.cog.spur/build.debug/mvm new file mode 100755 index 0000000000..948d928149 --- /dev/null +++ b/building/openbsd64x64/squeak.cog.spur/build.debug/mvm @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +set -e +# debug Spur VM with VM profiler and threaded heartbeat +INSTALLDIR=debug/sqcogspur64openbsdht +OPT="-g3 -O0 -DDEBUGVM=1 -DMUSL" + +# Prefer clang over gcc if available +if [ -n "$(command -v clang || true)" ]; then CC=clang; else CC=gcc; fi + +# librt and libpthread funs now supplied by libc +# Many Openbsd systems supply empty library files +# but OpenBSD does not. +LIBRT="" + +CFLAGS="$OPT -msse2 -DCOGMTVM=0" +LIBS=$LIBRT +LDFLAGS="" + +CFLAGS="$CFLAGS -I/usr/local/include" +LIBS="$LIBS -lexecinfo" +LDFLAGS="$LDFLAGS -L/usr/local/lib" + + +if [ $# -ge 1 ]; then + INSTALLDIR="$1"; shift +fi + +if ../../../../scripts/checkSCCSversion ; then exit 1; fi +echo -n "clean? " +read a +case $a in +n|no|N|NO) echo "ok but this isn't safe!!";; +*) test -f Makefile && make reallyclean +esac +../../../../scripts/copylinuxpluginspecfiles +test -f config.h || ../../../../platforms/unix/config/configure --without-npsqueak \ + --with-vmversion=5.0 \ + --with-src=src/spur64.cog \ + --with-scriptname=spur64 \ + TARGET_ARCH="-m64" \ + CC=$CC \ + CFLAGS="$CFLAGS" \ + LIBS="$LIBS" \ + LDFLAGS="$LDFLAGS" + +rm -f vm/sqUnixMain.o # nuke version info +rm -rf ../../../../products/$INSTALLDIR +# prefer make install prefix=`readlink -f \`pwd\`/../../../../products/$INSTALLDIR` +# but older openbsd readlinks lack the -f flag +make install-squeak install-plugins prefix=`(cd ../../../../;pwd)`/products/$INSTALLDIR 2>&1 | tee LOG ; test ${PIPESTATUS[0]} -eq 0 diff --git a/building/openbsd64x64/squeak.cog.spur/build.itimerheartbeat/mvm b/building/openbsd64x64/squeak.cog.spur/build.itimerheartbeat/mvm new file mode 100755 index 0000000000..986a12ff96 --- /dev/null +++ b/building/openbsd64x64/squeak.cog.spur/build.itimerheartbeat/mvm @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +set -e +# Spur VM with VM profiler and itimer heartbeat +INSTALLDIR=sqcogspur64openbsd +# Some gcc versions create a broken VM using -O2 +OPT="-g -O2 -DNDEBUG -DDEBUGVM=0 -D_GNU_SOURCE -DUSEEVDEV -DMUSL" + +# Prefer clang over gcc if available +if [ -n "$(command -v clang || true)" ]; then CC=clang; else CC=gcc; fi + +if [ $# -ge 1 ]; then + INSTALLDIR="$1"; shift +fi + +if ../../../../scripts/checkSCCSversion ; then exit 1; fi +echo -n "clean? " +read a +case $a in +n|no|N|NO) echo "ok but this isn't safe!!";; +*) test -f Makefile && make reallyclean +esac +../../../../scripts/copylinuxpluginspecfiles +test -f config.h || ../../../../platforms/unix/config/configure --without-npsqueak \ + --with-vmversion=5.0 \ + --with-src=src/spur64.cog \ + --with-scriptname=spur64 \ + TARGET_ARCH="-m64" \ + CC=$CC \ + CFLAGS="$OPT -msse2 -DCOGMTVM=0 -DITIMER_HEARTBEAT=1" +rm -f vm/sqUnixMain.o # nuke version info +rm -rf ../../../../products/$INSTALLDIR +# prefer make install prefix=`readlink -f \`pwd\`/../../../../products/$INSTALLDIR` +# but older openbsd readlinks lack the -f flag +make install-squeak install-plugins prefix=`(cd ../../../../;pwd)`/products/$INSTALLDIR 2>&1 | tee LOG ; test ${PIPESTATUS[0]} -eq 0 diff --git a/building/openbsd64x64/squeak.cog.spur/build/mvm b/building/openbsd64x64/squeak.cog.spur/build/mvm new file mode 100755 index 0000000000..6d1f91eb40 --- /dev/null +++ b/building/openbsd64x64/squeak.cog.spur/build/mvm @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +set -e +# Spur VM with VM profiler and threaded heartbeat +INSTALLDIR=sqcogspur64openbsdht +# Some gcc versions create a broken VM using -O2 +OPT="-g -O2 -DNDEBUG -DDEBUGVM=0 -D_GNU_SOURCE -DUSEEVDEV -DMUSL" + +# Prefer clang over gcc if available +if [ -n "$(command -v clang || true)" ]; then CC=clang; else CC=gcc; fi + +# librt and libpthread funs now supplied by libc +# Many Openbsd systems supply empty library files +# but OpenBSD does not. +LIBRT="" +CFLAGS="$CFLAGS $OPT -I/usr/local/include" +LIBS="$LIBS -lexecinfo" +LDFLAGS="$LDFLAGS -L/usr/local/lib" + +if [ $# -ge 1 ]; then + INSTALLDIR="$1"; shift +fi + +if ../../../../scripts/checkSCCSversion ; then exit 1; fi +echo -n "clean? " +read a +case $a in +n|no|N|NO) echo "ok but this isn't safe!!";; +*) test -f Makefile && make reallyclean +esac +../../../../scripts/copylinuxpluginspecfiles +test -f config.h || ../../../../platforms/unix/config/configure --without-npsqueak \ + --with-vmversion=5.0 \ + --with-src=src/spur64.cog \ + --with-scriptname=spur64 \ + TARGET_ARCH="-m64" \ + CC=$CC \ + CFLAGS="$CFLAGS" \ + LIBS="$LIBS" \ + LDFLAGS="$LDFLAGS" +rm -f vm/sqUnixMain.o # nuke version info +rm -rf ../../../../products/$INSTALLDIR +# prefer make install prefix=`readlink -f \`pwd\`/../../../../products/$INSTALLDIR` +# but older openbsd readlinks lack the -f flag +make install-squeak install-plugins prefix=`(cd ../../../../;pwd)`/products/$INSTALLDIR 2>&1 | tee LOG ; test ${PIPESTATUS[0]} -eq 0 diff --git a/building/openbsd64x64/squeak.cog.spur/makeallclean b/building/openbsd64x64/squeak.cog.spur/makeallclean new file mode 100755 index 0000000000..a7cac6bd4e --- /dev/null +++ b/building/openbsd64x64/squeak.cog.spur/makeallclean @@ -0,0 +1,15 @@ +#!/bin/sh -e +trap 'exit 2' HUP INT PIPE TERM +if [ "$1" = -fork ]; then + shift + for d in `dirname $0`/build*; do + (cd ./$d + echo y | ./mvm "$@") & + done + wait +else + for d in `dirname $0`/build*; do + (cd ./$d + echo y | ./mvm "$@") + done +fi diff --git a/building/openbsd64x64/squeak.cog.spur/makealldirty b/building/openbsd64x64/squeak.cog.spur/makealldirty new file mode 100755 index 0000000000..11f39e8808 --- /dev/null +++ b/building/openbsd64x64/squeak.cog.spur/makealldirty @@ -0,0 +1,15 @@ +#!/bin/sh -e +trap 'exit 2' HUP INT PIPE TERM +if [ "$1" = -fork ]; then + shift + for d in `dirname $0`/build*; do + (cd ./$d + echo n | ./mvm "$@") & + done + wait +else + for d in `dirname $0`/build*; do + (cd ./$d + echo n | ./mvm "$@") + done +fi diff --git a/building/openbsd64x64/squeak.cog.spur/makethbdirty b/building/openbsd64x64/squeak.cog.spur/makethbdirty new file mode 100755 index 0000000000..4ebd17bc6a --- /dev/null +++ b/building/openbsd64x64/squeak.cog.spur/makethbdirty @@ -0,0 +1,15 @@ +#!/bin/sh -e +trap 'exit 2' HUP INT PIPE TERM +if [ "$1" = -fork ]; then + shift + for d in build.debug build.assert build; do + (cd ./$d + echo n | ./mvm "$@") & + done + wait +else + for d in build.debug build.assert build; do + (cd ./$d + echo n | ./mvm "$@") + done +fi diff --git a/building/openbsd64x64/squeak.cog.spur/plugins.ext b/building/openbsd64x64/squeak.cog.spur/plugins.ext new file mode 100644 index 0000000000..fc8936d3bd --- /dev/null +++ b/building/openbsd64x64/squeak.cog.spur/plugins.ext @@ -0,0 +1,27 @@ +# Copied, perhaps edited, from ../../../src/examplePlugins.ext +EXTERNAL_PLUGINS = \ +MIDIPlugin \ +B3DAcceleratorPlugin \ +ClipboardExtendedPlugin \ +BochsIA32Plugin \ +BochsX64Plugin \ +GdbARMPlugin \ +GdbARMv8Plugin \ +FileAttributesPlugin \ +Squeak3D \ +SqueakFFIPrims \ +SqueakSSL \ +LocalePlugin \ +UnicodePlugin \ +UnixOSProcessPlugin \ +UUIDPlugin \ +ImmX11Plugin \ +XDisplayControlPlugin \ +DESPlugin \ +MD5Plugin \ +SHA2Plugin \ +VectorEnginePlugin \ +HelloWorldPlugin \ +HelloExternalWorldPlugin \ +PseudoTTYPlugin \ + diff --git a/building/openbsd64x64/squeak.cog.spur/plugins.int b/building/openbsd64x64/squeak.cog.spur/plugins.int new file mode 100644 index 0000000000..102ddaca84 --- /dev/null +++ b/building/openbsd64x64/squeak.cog.spur/plugins.int @@ -0,0 +1,39 @@ +# Copied, perhaps edited, from ../../../src/examplePlugins.int +INTERNAL_PLUGINS = \ +ADPCMCodecPlugin \ +AioPlugin \ +AsynchFilePlugin \ +B2DPlugin \ +BitBltPlugin \ +BMPReadWriterPlugin \ +CroquetPlugin \ +HostWindowPlugin \ +ZipPlugin \ +DropPlugin \ +DSAPrims \ +FFTPlugin \ +FileCopyPlugin \ +FilePlugin \ +FileDialogPlugin \ +Float64ArrayPlugin \ +FloatArrayPlugin \ +FloatMathPlugin \ +IA32ABI \ +JoystickTabletPlugin \ +JPEGReaderPlugin \ +JPEGReadWriter2Plugin \ +Klatt \ +LargeIntegers \ +Matrix2x3Plugin \ +MiscPrimitivePlugin \ +Mpeg3Plugin \ +RePlugin \ +SecurityPlugin \ +SerialPlugin \ +SocketPlugin \ +SoundCodecPrims \ +SoundGenerationPlugin \ +SoundPlugin \ +StarSqueakPlugin \ +SurfacePlugin \ +VMProfileLinuxSupportPlugin diff --git a/building/openbsd64x64/squeak.stack.spur/build.assert/mvm b/building/openbsd64x64/squeak.stack.spur/build.assert/mvm new file mode 100755 index 0000000000..e118a4087c --- /dev/null +++ b/building/openbsd64x64/squeak.stack.spur/build.assert/mvm @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +set -e +# assert Stack Spur VM with VM profiler and threaded heartbeat +INSTALLDIR=assert/sqstkspur64openbsdht +OPT="-g3 -O1 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -DDEBUGVM=0" + +# Prefer clang over gcc, but use gcc if clang isn't available... +CC=gcc +if [ -x /usr/bin/clang ]; then CC=clang; fi + +# librt and libpthread funs now supplied by libc +# Many Linux systems supply empty library files +# but OpenBSD does not. +LIBRT="" + +OPT="$OPT -DMUSL" +CFLAGS="$CFLAGS $OPT -I/usr/local/include" +LIBS="$LIBS -lexecinfo" +LDFLAGS="$LDFLAGS -L/usr/local/lib" + +if [ $# -ge 1 ]; then + INSTALLDIR="$1"; shift +fi + +if ../../../../scripts/checkSCCSversion ; then exit 1; fi +echo -n "clean? " +read a +case $a in +n|no|N|NO) echo "ok but this isn't safe!!";; +*) rm -f config.h; test -f Makefile && make reallyclean +esac +../../../../scripts/copylinuxpluginspecfiles +test -f config.h || ../../../../platforms/unix/config/configure \ + --with-vmversion=5.0 \ + --with-src=src/spur64.stack --disable-cogit \ + --without-vm-display-fbdev --without-npsqueak \ + --with-scriptname=spur64 \ + TARGET_ARCH="-m64" \ + CC=$CC \ + CFLAGS="$OPT -msse2" + +rm -f vm/sqUnixMain.o # nuke version info +rm -rf ../../../../products/$INSTALLDIR +# prefer make install prefix=`readlink -f \`pwd\`/../../../../products/$INSTALLDIR` +# but older linux readlinks lack the -f flag +make install-squeak install-plugins prefix=`(cd ../../../../;pwd)`/products/$INSTALLDIR 2>&1 | tee LOG ; test ${PIPESTATUS[0]} -eq 0 diff --git a/building/openbsd64x64/squeak.stack.spur/build.debug/mvm b/building/openbsd64x64/squeak.stack.spur/build.debug/mvm new file mode 100755 index 0000000000..51fb7288c7 --- /dev/null +++ b/building/openbsd64x64/squeak.stack.spur/build.debug/mvm @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +set -e +# debug Stack Spur VM with VM profiler and threaded heartbeat +INSTALLDIR=debug/sqstkspur64openbsdht +OPT="-g3 -O0 -DDEBUGVM=1" + +# Prefer clang over gcc, but use gcc if clang isn't available... +CC=gcc +if [ -x /usr/bin/clang ]; then CC=clang; fi + +# librt and libpthread funs now supplied by libc +# Many Linux systems supply empty library files +# but OpenBSD does not. +LIBRT="" + +OPT="$OPT -DMUSL" +CFLAGS="$CFLAGS $OPT -I/usr/local/include" +LIBS="$LIBS -lexecinfo" +LDFLAGS="$LDFLAGS -L/usr/local/lib" + +if [ $# -ge 1 ]; then + INSTALLDIR="$1"; shift +fi + +if ../../../../scripts/checkSCCSversion ; then exit 1; fi +echo -n "clean? " +read a +case $a in +n|no|N|NO) echo "ok but this isn't safe!!";; +*) rm -f config.h; test -f Makefile && make reallyclean +esac +../../../../scripts/copylinuxpluginspecfiles +test -f config.h || ../../../../platforms/unix/config/configure \ + --with-vmversion=5.0 \ + --with-src=src/spur64.stack --disable-cogit \ + --without-vm-display-fbdev --without-npsqueak \ + --with-scriptname=spur64 \ + TARGET_ARCH="-m64" \ + CC=$CC \ + CFLAGS="$OPT -msse2" + +rm -f vm/sqUnixMain.o # nuke version info +rm -rf ../../../../products/$INSTALLDIR +# prefer make install prefix=`readlink -f \`pwd\`/../../../../products/$INSTALLDIR` +# but older linux readlinks lack the -f flag +make install-squeak install-plugins prefix=`(cd ../../../../;pwd)`/products/$INSTALLDIR 2>&1 | tee LOG ; test ${PIPESTATUS[0]} -eq 0 diff --git a/building/openbsd64x64/squeak.stack.spur/build/mvm b/building/openbsd64x64/squeak.stack.spur/build/mvm new file mode 100755 index 0000000000..33abdc02f6 --- /dev/null +++ b/building/openbsd64x64/squeak.stack.spur/build/mvm @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +set -e +# Stack Spur VM with VM profiler and threaded heartbeat +INSTALLDIR=sqstkspur64openbsdht +OPT="-g -O1 -DNDEBUG -DDEBUGVM=0" + +# Prefer clang over gcc, but use gcc if clang isn't available... +CC=gcc +if [ -x /usr/bin/clang ]; then CC=clang; fi + +# librt and libpthread funs now supplied by libc +# Many Linux systems supply empty library files +# but OpenBSD does not. +LIBRT="" + +OPT="$OPT -DMUSL" +CFLAGS="$CFLAGS $OPT -I/usr/local/include" +LIBS="$LIBS -lexecinfo" +LDFLAGS="$LDFLAGS -L/usr/local/lib" + +if [ $# -ge 1 ]; then + INSTALLDIR="$1"; shift +fi +if ../../../../scripts/checkSCCSversion ; then exit 1; fi +echo -n "clean? " +read a +case $a in +n|no|N|NO) echo "ok but this isn't safe!!";; +*) rm -f config.h; test -f Makefile && make reallyclean +esac +../../../../scripts/copylinuxpluginspecfiles +test -f config.h || ../../../../platforms/unix/config/configure \ + --with-vmversion=5.0 \ + --with-src=src/spur64.stack --disable-cogit \ + --without-vm-display-fbdev --without-npsqueak \ + --with-scriptname=spur64 \ + TARGET_ARCH="-m64" \ + CC=$CC \ + CFLAGS="$OPT -msse2" + +rm -f vm/sqUnixMain.o # nuke version info +rm -rf ../../../../products/$INSTALLDIR +# prefer make install prefix=`readlink -f \`pwd\`/../../../../products/$INSTALLDIR` +# but older linux readlinks lack the -f flag +make install-squeak install-plugins prefix=`(cd ../../../../;pwd)`/products/$INSTALLDIR 2>&1 | tee LOG ; test ${PIPESTATUS[0]} -eq 0 diff --git a/building/openbsd64x64/squeak.stack.spur/makeallclean b/building/openbsd64x64/squeak.stack.spur/makeallclean new file mode 100755 index 0000000000..a7cac6bd4e --- /dev/null +++ b/building/openbsd64x64/squeak.stack.spur/makeallclean @@ -0,0 +1,15 @@ +#!/bin/sh -e +trap 'exit 2' HUP INT PIPE TERM +if [ "$1" = -fork ]; then + shift + for d in `dirname $0`/build*; do + (cd ./$d + echo y | ./mvm "$@") & + done + wait +else + for d in `dirname $0`/build*; do + (cd ./$d + echo y | ./mvm "$@") + done +fi diff --git a/building/openbsd64x64/squeak.stack.spur/makealldirty b/building/openbsd64x64/squeak.stack.spur/makealldirty new file mode 100755 index 0000000000..11f39e8808 --- /dev/null +++ b/building/openbsd64x64/squeak.stack.spur/makealldirty @@ -0,0 +1,15 @@ +#!/bin/sh -e +trap 'exit 2' HUP INT PIPE TERM +if [ "$1" = -fork ]; then + shift + for d in `dirname $0`/build*; do + (cd ./$d + echo n | ./mvm "$@") & + done + wait +else + for d in `dirname $0`/build*; do + (cd ./$d + echo n | ./mvm "$@") + done +fi diff --git a/building/openbsd64x64/squeak.stack.spur/plugins.ext b/building/openbsd64x64/squeak.stack.spur/plugins.ext new file mode 100644 index 0000000000..777d09919a --- /dev/null +++ b/building/openbsd64x64/squeak.stack.spur/plugins.ext @@ -0,0 +1,21 @@ +# Copied, perhaps edited, from ../../../src/examplePlugins.ext +EXTERNAL_PLUGINS = \ +MIDIPlugin \ +B3DAcceleratorPlugin \ +ClipboardExtendedPlugin \ +FileAttributesPlugin \ +Squeak3D \ +SqueakFFIPrims \ +SqueakSSL \ +LocalePlugin \ +UnicodePlugin \ +UnixOSProcessPlugin \ +UUIDPlugin \ +ImmX11Plugin \ +XDisplayControlPlugin \ +DESPlugin \ +MD5Plugin \ +SHA2Plugin \ +VectorEnginePlugin \ +PseudoTTYPlugin \ + diff --git a/building/openbsd64x64/squeak.stack.spur/plugins.int b/building/openbsd64x64/squeak.stack.spur/plugins.int new file mode 100644 index 0000000000..102ddaca84 --- /dev/null +++ b/building/openbsd64x64/squeak.stack.spur/plugins.int @@ -0,0 +1,39 @@ +# Copied, perhaps edited, from ../../../src/examplePlugins.int +INTERNAL_PLUGINS = \ +ADPCMCodecPlugin \ +AioPlugin \ +AsynchFilePlugin \ +B2DPlugin \ +BitBltPlugin \ +BMPReadWriterPlugin \ +CroquetPlugin \ +HostWindowPlugin \ +ZipPlugin \ +DropPlugin \ +DSAPrims \ +FFTPlugin \ +FileCopyPlugin \ +FilePlugin \ +FileDialogPlugin \ +Float64ArrayPlugin \ +FloatArrayPlugin \ +FloatMathPlugin \ +IA32ABI \ +JoystickTabletPlugin \ +JPEGReaderPlugin \ +JPEGReadWriter2Plugin \ +Klatt \ +LargeIntegers \ +Matrix2x3Plugin \ +MiscPrimitivePlugin \ +Mpeg3Plugin \ +RePlugin \ +SecurityPlugin \ +SerialPlugin \ +SocketPlugin \ +SoundCodecPrims \ +SoundGenerationPlugin \ +SoundPlugin \ +StarSqueakPlugin \ +SurfacePlugin \ +VMProfileLinuxSupportPlugin diff --git a/building/qnx64ARMv8/HowToBuild b/building/qnx64ARMv8/HowToBuild new file mode 100644 index 0000000000..e9aed1ae14 --- /dev/null +++ b/building/qnx64ARMv8/HowToBuild @@ -0,0 +1,353 @@ +How To Build On QNX [RasPi5 self hosting] +--------------------- + +Note: These instructions are for aarch64/arm64 CPUs. +See building/linux32ARMv6/HowToBuild + or building/linux32ARMv7/HowToBuild for 32 bit ARM images. + + +Contents: + - Overview + - Checking out sources to build out-of-the-box + - Building out of the box + - Building the VM Simulator Support Libraries + - How to configure and build a VM on Unix + - Debugging configuration failures + - Testing an external plugin has completely linked + - Optimization level and gcc version (please read!) + - Installing support libraries + - Building with MUSL rather than libc + + +Overview +-------- +The "Cog" VM comes in a bewildering variety of forms. The first distinction +is between Squeak/Croquet VMs that run Squeak, Pharo, Cuis, Croquet images +and their ilk, and between Newspeak VMs that run Newspeak. + +Another distinction is between Stack, Cog and Sista VMs. Stack VMs are those +with context-to-stack mapping that optimise message sending by keeping method +activations on a stack instead of in contexts. These are pure interpreters but +significantly faster than the standard context-based Interpreter VM. Cog VMs +add a JIT to the mix, compiling methods used more than once to maxchine code on +the fly. Sista VMs, as yet unrealised and in development, add support for +adaptive optimization that does speculative inlining at the bytecode-to-bytecode +level. These are targeted for release in 2015. + +Another distinction is between "v3" VMs and Spur VMs. "v3" is the original +object representation for Squeak as described in the back-to-the-future paper. +Spur, as described on the www.mirandabanda.org blog, is a faster object +representation which uses generation scavenging, lazy forwarding for fast +become, and a single object header format common to 32 and 64 bit versions. + +Another distinction is between normal single-threaded VMs that schedule "green" +Smalltalk processes above a single-threaded VM, and "multi-threaded" VMs that +share the VM between any number of native threads such that only one native +thread owns the VM at any one time, switching between threads on FFI calls and +callbacks or on Smalltalk process switches when Smalltalk processes are owned +by threads. This multi-threaded support is as yet experimental. + +A distinction on linux is between VMs with an itimer hearbeat or a threaded +heartbeat. VMs with an itimer hearbeat use setitimer to deliver a SIGALRM +signal at regular intervals to interrupt the VM to check for events. These +signals can be troublesome, interrupting foreign code that cannot cope with +such signals. VMs with a threaded heartbeat use a high-priority thread that +loops, blocking on nanosleep and then interrupting the VM, performing the same +function as the itimer heartbeat but without using signals. These VMs are to +be preferred but suport for multiple thread priorities in user-level processes +has only been available on linux in kernels later than 2.6.12. + +The final distinction is between production, assert and debug VMs. Production +VMs are fully optimized, although they may include debugging symbols, and as +their name implies are for use in production. Assert and debug VMs include +many assert checks that are disabled in the production VMs. These asserts are +very helpful in debugging VM problems but significantly impact performance. +The difference between assert and debug VMs is that assert VMs are compiled +with moderate optimization, which improves the performance of the asserts, +whereas debug VMs are compiled with no optimization at all, providing maximum +debuggability with minimum performance. + +This directory tree provides build directories for some of this matrix. For +example, squeak.cog.v3 contains build directories for Smalltalk Cog VMs using +the old object representation, newspeak.stack.spur contains build directories +for Newspeak Stack VMs using the Spur object representation. Build as desired. + + +Checking out sources to build out-of-the-box +-------------------------------------------- +Check-out the repository from github: + git clone http://www.github.com/OpenSmalltalk/opensmalltalk-vm oscogvm + cd ./oscogvm + more README.md + + +Building out of the box +----------------------- +Install the tools (gcc, X11-devel, etc, e.g. libpng, libuuid libX11 & libxt +source). See "Installing support libraries" below. If the configure step fails +when "checking for C compiler default output file name", you have yet to install +all the necessary support packages (e.g. libuuid). +Then cd to the build directory of your choice, e.g. + building/linux64x64/squeak.cog.spur/build +Then execute + ./mvm +answering "y" to perform a clean build or "n" to rebuild without reconfiguring. +Again, if the configure step fails when "checking for C compiler default output +file name", you have yet to install all the necessary support (e.g. lubuuid). + +The subdirectories conform to the production/assert/debug x itimer vs threaded +heartbeat x single vs multi-threaded parts of the matrix described above. For +example, building/linux64x64/squeak.cog.v3 includes + + build + build.itimerheartbeat + build.multithreaded + + build.assert + build.assert.itimerheartbeat + build.multithreaded.assert + + build.debug + build.multithreaded.debug + build.debug.itimerheartbeat + +subdirectories. It includes two convenience scripts that will make all +configurations: + makeallclean + makealldirty + +Each build directory contains three files + mvm + plugins.int + plugins.ext +The mvm script runs ../../platforms/unix/config/configure with the relevant +options, runs make, and then make install to create a VM directory tree in +../../products, ../../products/assert or ../../products/debug as appropriate. +plugins.int and plugins.ext determine the set of plugins to be taken from +the supplied plugins directory (which defaults to ../../src/plugins), and which +are to be linked into the VM (plugins.int) or compiled as external shared +objects to be dynamically linked at run-time (plugins.ext). + +Finally, at the building/linux64ARMv8 level the makeall script will run all the +makeallclean scripts it can find. + + +Building the VM Simulator Support Libraries +------------------------------------------- +If you want to get the Cog VM simulator working you'll need to build one or more +of the processor simulator plugins, each of which has support libraries that +must be built: + Processor Plugin Support Library + x86 BochsIA32Plugin building/linux64x64/bochsx86 + x86_64/x64 BochsX64Plugin building/linux64x64/bochsx64 + ARMv5 GdbARMPlugin building/linux64x64/gdbarm32 +cd to the relevant directories; run conf.COG and then the build script, e.g. + $ cd building/linux64x64/bochsx86 + $ ./conf.COG + $ ./makeem + +Then when Squeak VMs are built they will include the plugin(s) for which support +libraries have been provided. + + +How to configure and build a VM on Unix +--------------------------------------- +The mvm scripts are themselves wrappers around an adaptation of Ian Piumarta's +Squeak build system above autoconf to the Cog sources. One can choose the vm +source files, plugin source files, and optimization level to compile a VM of +your choice. To find the full set of options via + + ../../platforms/unix/config/configure --help + +You can see the use of configure in the various mvm scripts in each build +directory. + +e.g. + ../../../platforms/unix/config/configure --without-npsqueak CFLAGS="-g -O2 -msse2 -D_GNU_SOURCE -DNDEBUG -DITIMER_HEARTBEAT=1 -DCOGMTVM=0 -DDEBUGVM=0" LIBS=-lpthread + make install prefix=WhereYouWantTheVmToGo + + N.B. If you're on a 64-bit linux read 3e below!! + N.B. On Ubuntu *do not* supply "LIBS=-lpthread -luuid", i.e. use + ../../../platforms/unix/config/configure --without-npsqueak CFLAGS="-g -O2 -msse2 -D_GNU_SOURCE -DNDEBUG -DITIMER_HEARTBEAT=1 -DCOGMTVM=0 -DDEBUGVM=0" + + +N.B. The plugin set is defined by plugins.ext and plugins.int in the build dir. + +Be prepared to install libuuid support. e.g. on CentOS 6.5 use +sudo yum -y install libuuid-devel + + +Debugging configuration failures +-------------------------------- +If your development system does not have the required libraries installed then +the configure step run by the mvm script will fail cryptically. You will see +something like + checking sanity of generated src directory... okay + checking build system type... i686-pc-linux-gnu + checking host system type... i686-pc-linux-gnu + checking target system type... i686-pc-linux-gnu + + Configuring Squeak (.-) for i686-pc-linux-gnu + + checking whether make sets $(MAKE)... yes + checking for gcc... gcc -m32 + checking for C compiler default output file name... configure: error: C compiler cannot create executables + See `config.log' for more details. +But config.log is missing the relevant details. It only contains the failing gcc +invocation, not the output from that failing command. To diagnose, grep to find +the gcc invocation: + $ grep gcc config.log + ... + configure:2269: gcc -m32 -g3 -O0 -fwrapv -DDEBUGVM=1 -DEnforceAccessControl=0 -msse2 -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -Wl,-z,now conftest.c -lpthread -luuid >& +and then repeat the compilation supplying your own test file, e.g. + $ gcc -m32 -g3 -O0 -fwrapv -DDEBUGVM=1 -DEnforceAccessControl=0 -msse2 -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -Wl,-z,now helloworld.c -lpthread -luuid + helloworld.c: In function 'main': + /usr/bin/ld: cannot find -luuid + collect2: ld returned 1 exit status +From which one can infer that one needs to install either the 64-bit or the 32-bit +version of libuuid, e.g. sudo yum install libuuid-devel + + +Testing an external plugin has completely linked +------------------------------------------------ +You may find that an external plugin compiles and links but does not load. +This is usually because it contans undefined symbols. To find undefined +symbols, remake the plugin, capturing the link step and then supply + -Wl,--warn-unresolved-symbols -Wl,--no-allow-shlib-undefined +when manually repeating the link command + + +Optimization level and gcc version +---------------------------------- +There are issues with gcc version > 4.2.1. Any of the following flags may break the build at -O2: +-ftree-pre +-fpartial-inlining +-fcaller-saves + +So turn them off. e.g. + ../../../platforms/unix/config/configure --without-npsqueak CFLAGS="-g -O2 -msse2 -fno-caller-saves -fno-partial-inlining -fno-tree-pre -D_GNU_SOURCE -DNDEBUG -DCOGMTVM=0 -DDEBUGVM=0" LIBS="-lpthread -luuid" +See http://smallissimo.blogspot.fr/2013/02/compiling-squeak-cog-virtual-machine-on.html + +People have reported that the OSProcessPlugin is broken on gcc versions > 4.8 +on Debian. + + +Installing support libraries +---------------------------- +Different linux distributions have different mechanisms for loading packages. +Here are some examples: + +CentOS + sudo yum install -y cairo-devel + sudo yum install -y pango-devel + sudo yum install -y libuuid-devel + sudo yum install -y libX11-devel + sudo yum install -y mesa-libGL-devel + sudo yum install -y openssl-devel + sudo yum install -y cmake + sudo yum install -y gcc-c++ +N.B. if you get failures due to version conflicts try + sudo yum update +and then retry. + +Ubuntu + sudo apt install uuid-dev libcairo2-dev libpango1.0-dev libgl1-mesa-dev + sudo apt install libgl1-mesa-glx libssl-dev libevdev-dev m4 libpulse-dev + sudo apt install libxrandr-dev + +Manjaro + sudo pacman -Sy gcc clang gdb make + sudo pacman -S uuid-dev libgl1-mesa-dev libgl1-mesa-glx libssl-dev + sudo pacman -S xf86-video-fbdeV + +Debian (64-bit) + A complete build configuration (dockerized) can be found here: + https://github.com/LinqLover/squeak-raspi-docker/tree/master/osvm-mvm + +More advice and examples for other distros gratefully received. + + + +Building with MUSL rather than libc +----------------------------------- +There are some differences in include file definitons when +using MUSL in place of libc. Note: https://musl.libc.org + +You should check your Linux distro for libc development support +libraries or include files needed. + +The following has been tested on both aarch64 and amd64 Alpine Linux +(MUSL+busybox). + +install musl-dev [e.g. sudo apk add musl-dev ]. + +Due to the continued evolution of the OpenSmalltalk VM +it is not possible to use patch files, but the changes +to be made are simple to describe. + +Basically, building works fine but one needs to + +[A] add "-DMUSL -D_GNU_SOURCE" to CFLAGS so that include +expansion is not confused between libc and MUSL definitions. + +[B] elide (remove) some definitions which use 'FILE'. + + +A simple way to do [A] is to add the definitions to OPT in the +'mvm' file in the 'build' directory. + +For [B] one needs to make small changes to files + platforms/Cross/vm/sqVirtualMachine.c +and + platforms/unix/vm/sqUnixMain.c +to skip definitions of pushOutputFile() and popOutputFile(). + + +[B.1] platforms/Cross/vm/sqVirtualMachine.c +... +#ifndef MUSL + #define STDOUT_STACK_SZ 5 + static int stdoutStackIdx = -1; + static FILE stdoutStack[STDOUT_STACK_SZ]; +#endif +... +#ifndef MUSL + void + pushOutputFile(char *filenameOrStdioIndex) + { +... + } + + void + popOutputFile() + { + ... + } +#endif + + +[B.2] platforms/unix/vm/sqUnixMain.c +... +#ifdef MUSL +void pushOutputFile(char *fileNameOrStdioIndex) {;} +void popOutputFile() {;} +#endif +... + + +That's it. You should be able to invoke 'mvm' in the 'build' +directory, answer 'y' to the 'clean?' prompt, and get a +proper build. + +If running the resultant squeak vm gives an error something like + mprotect(x,y,PROT_READ|PROT_EXEC) +or + memory_alias_map: shm_open: Permission denied +you need to enable shared memory for the COG JIT. + +As root: + chmod 777 /dev/shm + echo 'none /dev/shm tmpfs rw,nosuid,nodev 0 0' >> /etc/fstab + mount /dev/shm + +The squeak vm should now work. diff --git a/building/qnx64ARMv8/makeall b/building/qnx64ARMv8/makeall new file mode 100755 index 0000000000..923f2bef7a --- /dev/null +++ b/building/qnx64ARMv8/makeall @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -e +trap 'exit 2' HUP INT PIPE TERM +for d in *.spur *.v3; do + if test -d "$d"; then + (cd ./$d;./makealldirty "$@") + else + echo no $d directory found + fi +done diff --git a/building/qnx64ARMv8/makeallclean b/building/qnx64ARMv8/makeallclean new file mode 100755 index 0000000000..1480133451 --- /dev/null +++ b/building/qnx64ARMv8/makeallclean @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -e +trap 'exit 2' HUP INT PIPE TERM +for d in *.spur *.v3; do + if test -d "$d"; then + (cd ./$d; if test -x makeallclean; then ./makeallclean "$@"; else ./makeclean "$@"; fi) + else + echo no $d directory found + fi +done diff --git a/building/qnx64ARMv8/makeallmakefiles b/building/qnx64ARMv8/makeallmakefiles new file mode 100755 index 0000000000..18f4d62873 --- /dev/null +++ b/building/qnx64ARMv8/makeallmakefiles @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +set -e +trap 'exit 2' HUP INT PIPE TERM +for td in *.v3 *.spur; do + for d in $td/build*; do + if test -d "$d"; then + (cd ./$d;../../../../platforms/unix/config/mkmf) + else + echo no $d directory found + fi + done +done diff --git a/building/qnx64ARMv8/makeallsqueak b/building/qnx64ARMv8/makeallsqueak new file mode 100755 index 0000000000..3d08d6cfc8 --- /dev/null +++ b/building/qnx64ARMv8/makeallsqueak @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -e +trap 'exit 2' HUP INT PIPE TERM +for d in squeak.*; do + if test -d "$d"; then + (cd ./$d;./makedirty "$@") + else + echo no $d directory found + fi +done diff --git a/building/qnx64ARMv8/qnx-readme.txt b/building/qnx64ARMv8/qnx-readme.txt new file mode 100644 index 0000000000..ee220665e1 --- /dev/null +++ b/building/qnx64ARMv8/qnx-readme.txt @@ -0,0 +1,5 @@ +Tested on RasPi5 self hosted qnx. +https://www.qnx.com/developers/docs/qnxeverywhere/index.html?ref=qnxdevdesktop + +## In the shell: +>> sudo apk add screen diff --git a/building/qnx64ARMv8/squeak.cog.spur/build.debug/mvm b/building/qnx64ARMv8/squeak.cog.spur/build.debug/mvm new file mode 100755 index 0000000000..8e0aa16f09 --- /dev/null +++ b/building/qnx64ARMv8/squeak.cog.spur/build.debug/mvm @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +set -e +# debug Cog Spur VM with VM profiler and threaded heartbeat +INSTALLDIR=debug/sqcogspur64ARMv8linuxht +# armv8.N-a all fail in signalSemaphoreWithIndex for N in 1,2,3,4,5 +MACHINE="-march=armv8-a -mtune=cortex-a72" +OPT="-g3 -O0 -DDEBUGVM=1 -DAIO_DEBUG=1 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -DDEBUGVM=0 -D_GNU_SOURCE -DMUSL -DUSEEVDEV" + +# Prefer clang over gcc if available + if [ -n "$(command -v clang || true)" ]; then CC=clang; else CC=gcc; fi + +DUALMAP="-DDUAL_MAPPED_CODE_ZONE=1" + +if [ $# -ge 1 ]; then + INSTALLDIR="$1"; shift +fi +if ../../../../scripts/checkSCCSversion ; then exit 1; fi +echo -n "clean? " +read a +case $a in +n|no|N|NO) echo "ok but this isn't safe!!";; +*) rm -f config.h; test -f Makefile && make reallyclean +esac +../../../../scripts/copylinuxpluginspecfiles +test -f config.h || ../../../../platforms/unix/config/configure \ + --with-vmversion=5.0 --with-src=src/spur64.cog \ + --without-vm-display-fbdev --without-npsqueak \ + --with-scriptname=spur64 \ + $FASTBITBLT \ + --with-vm-display-qnxScreen=yes \ + TARGET_ARCH="-march=armv8-a" \ + CC=$CC \ + LDFLAGS="$LDFLAGS -lscreen" \ + CFLAGS="$OPT -D__ARM_ARCH_ISA_A64 -DARM64 -D__arm__ -D__arm64__ -D__aarch64__ $DUALMAP" + +rm -f vm/sqUnixMain.o # nuke version info +rm -rf ../../../../products/$INSTALLDIR +# prefer make install prefix=`readlink -f \`pwd\`/../../../../products/$INSTALLDIR` +# but older linux readlinks lack the -f flag +make install-squeak install-plugins prefix=`(cd ../../../../;pwd)`/products/$INSTALLDIR 2>&1 | tee LOG ; test ${PIPESTATUS[0]} -eq 0 diff --git a/building/qnx64ARMv8/squeak.cog.spur/build/mvm b/building/qnx64ARMv8/squeak.cog.spur/build/mvm new file mode 100755 index 0000000000..15d9a1f3f6 --- /dev/null +++ b/building/qnx64ARMv8/squeak.cog.spur/build/mvm @@ -0,0 +1,41 @@ +#!/usr/bin/env bash +set -e +# Cog Spur VM with VM profiler and threaded heartbeat +INSTALLDIR=sqcogspur64ARMv8linuxht +# armv8.N-a all fail in signalSemaphoreWithIndex for N in 1,2,3,4,5 +# tpr - add enablementisation of fast bitblt ben avison code +MACHINE="-march=armv8-a -mtune=cortex-a72" +OPT="-g -O2 -DNDEBUG -DDEBUGVM=0 -D_GNU_SOURCE -DMUSL -DUSEEVDEV" + +DUALMAP="-DDUAL_MAPPED_CODE_ZONE=1" + +# Prefer clang over gcc if available +if [ -n "$(command -v clang || true)" ]; then CC=clang; else CC=gcc; fi + +if [ $# -ge 1 ]; then + INSTALLDIR="$1"; shift +fi +if ../../../../scripts/checkSCCSversion ; then exit 1; fi +echo -n "clean? " +read a +case $a in +n|no|N|NO) echo "ok but this isn't safe!!";; +*) rm -f config.h; test -f Makefile && make reallyclean +esac +../../../../scripts/copylinuxpluginspecfiles +test -f config.h || ../../../../platforms/unix/config/configure \ + --with-vmversion=5.0 --with-src=src/spur64.cog \ + --without-npsqueak \ + --with-scriptname=spur64 \ + $FASTBITBLT \ + --with-vm-display-qnxScreen=yes \ + TARGET_ARCH="-march=armv8-a" \ + CC=$CC \ + LDFLAGS="$LDFLAGS -lscreen" \ + CFLAGS="$OPT -D__ARM_ARCH_ISA_A64 -DARM64 -D__arm__ -D__arm64__ -D__aarch64__ $DUALMAP" + +rm -f vm/sqUnixMain.o # nuke version info +rm -rf ../../../../products/$INSTALLDIR +# prefer make install prefix=`readlink -f \`pwd\`/../../../../products/$INSTALLDIR` +# but older linux readlinks lack the -f flag +make install-squeak install-plugins prefix=`(cd ../../../../;pwd)`/products/$INSTALLDIR 2>&1 | tee LOG ; test ${PIPESTATUS[0]} -eq 0 diff --git a/building/qnx64ARMv8/squeak.cog.spur/makeclean b/building/qnx64ARMv8/squeak.cog.spur/makeclean new file mode 100755 index 0000000000..a7cac6bd4e --- /dev/null +++ b/building/qnx64ARMv8/squeak.cog.spur/makeclean @@ -0,0 +1,15 @@ +#!/bin/sh -e +trap 'exit 2' HUP INT PIPE TERM +if [ "$1" = -fork ]; then + shift + for d in `dirname $0`/build*; do + (cd ./$d + echo y | ./mvm "$@") & + done + wait +else + for d in `dirname $0`/build*; do + (cd ./$d + echo y | ./mvm "$@") + done +fi diff --git a/building/qnx64ARMv8/squeak.cog.spur/makedirty b/building/qnx64ARMv8/squeak.cog.spur/makedirty new file mode 100755 index 0000000000..11f39e8808 --- /dev/null +++ b/building/qnx64ARMv8/squeak.cog.spur/makedirty @@ -0,0 +1,15 @@ +#!/bin/sh -e +trap 'exit 2' HUP INT PIPE TERM +if [ "$1" = -fork ]; then + shift + for d in `dirname $0`/build*; do + (cd ./$d + echo n | ./mvm "$@") & + done + wait +else + for d in `dirname $0`/build*; do + (cd ./$d + echo n | ./mvm "$@") + done +fi diff --git a/building/qnx64ARMv8/squeak.cog.spur/plugins.ext b/building/qnx64ARMv8/squeak.cog.spur/plugins.ext new file mode 100644 index 0000000000..2d4e9735a2 --- /dev/null +++ b/building/qnx64ARMv8/squeak.cog.spur/plugins.ext @@ -0,0 +1,17 @@ +# Copied, perhaps edited, from ../../../src/examplePlugins.ext +EXTERNAL_PLUGINS = \ +ClipboardExtendedPlugin \ +FileAttributesPlugin \ +MIDIPlugin \ +Squeak3D \ +SqueakFFIPrims \ +LocalePlugin \ +UnicodePlugin \ +UUIDPlugin \ +ImmX11Plugin \ +XDisplayControlPlugin \ +DESPlugin \ +MD5Plugin \ +SHA2Plugin \ +VectorEnginePlugin + diff --git a/building/qnx64ARMv8/squeak.cog.spur/plugins.int b/building/qnx64ARMv8/squeak.cog.spur/plugins.int new file mode 100644 index 0000000000..944743ff0d --- /dev/null +++ b/building/qnx64ARMv8/squeak.cog.spur/plugins.int @@ -0,0 +1,23 @@ +# Copied, perhaps edited, from ../../../src/examplePlugins.int +INTERNAL_PLUGINS = \ +BitBltPlugin \ +BMPReadWriterPlugin \ +FileCopyPlugin \ +FilePlugin \ +FileDialogPlugin \ +Float64ArrayPlugin \ +FloatArrayPlugin \ +FloatMathPlugin \ +IA32ABI \ +JPEGReaderPlugin \ +JPEGReadWriter2Plugin \ +LargeIntegers \ +Matrix2x3Plugin \ +MiscPrimitivePlugin \ +Mpeg3Plugin \ +RePlugin \ +SecurityPlugin \ +SerialPlugin \ +SocketPlugin \ +StarSqueakPlugin \ +SurfacePlugin diff --git a/building/qnx64ARMv8/squeak.stack.spur/build.assert/mvm b/building/qnx64ARMv8/squeak.stack.spur/build.assert/mvm new file mode 100755 index 0000000000..d6fe5640c2 --- /dev/null +++ b/building/qnx64ARMv8/squeak.stack.spur/build.assert/mvm @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +set -e +# assert Stack Spur VM with VM profiler and threaded heartbeat +INSTALLDIR=assert/sqstkspur64ARMv8linuxht +OPT="-g3 -O1 -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -DDEBUGVM=0" + +DUALMAP="-DDUAL_MAPPED_CODE_ZONE=1" + +# Prefer clang over gcc if available +if [ -n "$(command -v clang || true)" ]; then CC=clang; else CC=gcc; fi + +if [ $# -ge 1 ]; then + INSTALLDIR="$1"; shift +fi +if ../../../../scripts/checkSCCSversion ; then exit 1; fi +echo -n "clean? " +read a +case $a in +n|no|N|NO) echo "ok but this isn't safe!!";; +*) rm -f config.h; test -f Makefile && make reallyclean +esac +../../../../scripts/copylinuxpluginspecfiles +test -f config.h || ../../../../platforms/unix/config/configure \ + --with-vmversion=5.0 \ + --with-src=src/spur64.stack --disable-cogit \ + --without-vm-display-fbdev --without-npsqueak \ + --with-scriptname=spur64 \ + --with-vm-display-qnxScreen=yes \ + TARGET_ARCH="-march=armv8-a" \ + CC=$CC \ + LDFLAGS="$LDFLAGS -lscreen" \ + CFLAGS="$OPT -D__ARM_ARCH_ISA_A64 -DARM64 -D__arm__ -D__arm64__ -D__aarch64__ $DUALMAP" +rm -f vm/sqUnixMain.o # nuke version info +rm -rf ../../../../products/$INSTALLDIR +# prefer make install prefix=`readlink -f \`pwd\`/../../../../products/$INSTALLDIR` +# but older linux readlinks lack the -f flag +make install-squeak install-plugins prefix=`(cd ../../../../;pwd)`/products/$INSTALLDIR 2>&1 | tee LOG ; test ${PIPESTATUS[0]} -eq 0 diff --git a/building/qnx64ARMv8/squeak.stack.spur/build.debug/mvm b/building/qnx64ARMv8/squeak.stack.spur/build.debug/mvm new file mode 100755 index 0000000000..f8a20f097e --- /dev/null +++ b/building/qnx64ARMv8/squeak.stack.spur/build.debug/mvm @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +set -e +# debug Stack Spur VM with VM profiler and threaded heartbeat +INSTALLDIR=debug/sqstkspur64ARMv8linuxht +OPT="-g3 -O0 -DDEBUG -DDEBUGVM=1 -DDEBUG_EVENTS -DDEBUG_KEYBOARD_EVENTS -DDEBUG_MOUSE_EVENTS -DUSEEVDEV -DMUSL" + +DUALMAP="-DDUAL_MAPPED_CODE_ZONE=1" + +# Prefer clang over gcc if available +if [ -n "$(command -v clang || true)" ]; then CC=clang; else CC=gcc; fi + +if [ $# -ge 1 ]; then + INSTALLDIR="$1"; shift +fi +if ../../../../scripts/checkSCCSversion ; then exit 1; fi +echo -n "clean? " +read a +case $a in +n|no|N|NO) echo "ok but this isn't safe!!";; +*) rm -f config.h; test -f Makefile && (make -n reallyclean;make reallyclean) +esac +../../../../scripts/copylinuxpluginspecfiles +test -f config.h || ../../../../platforms/unix/config/configure \ + --with-vmversion=5.0 \ + --with-src=src/spur64.stack --disable-cogit \ + --without-npsqueak \ + --with-scriptname=spur64 \ + --with-vm-display-qnxScreen=yes \ + TARGET_ARCH="-march=armv8-a" \ + CC=$CC \ + LDFLAGS="$LDFLAGS -lscreen" \ + CFLAGS="$OPT -D__ARM_ARCH_ISA_A64 -DARM64 -D__arm__ -D__arm64__ -D__aarch64__ $DUALMAP" +## --without-vm-display-fbdev --without-npsqueak \ +rm -f vm/sqUnixMain.o # nuke version info +rm -rf ../../../../products/$INSTALLDIR +# prefer make install prefix=`readlink -f \`pwd\`/../../../../products/$INSTALLDIR` +# but older linux readlinks lack the -f flag +make install-squeak install-plugins prefix=`(cd ../../../../;pwd)`/products/$INSTALLDIR 2>&1 | tee LOG ; test ${PIPESTATUS[0]} -eq 0 diff --git a/building/qnx64ARMv8/squeak.stack.spur/build/mvm b/building/qnx64ARMv8/squeak.stack.spur/build/mvm new file mode 100755 index 0000000000..cd03b6a3bc --- /dev/null +++ b/building/qnx64ARMv8/squeak.stack.spur/build/mvm @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +set -e +# Stack Spur VM with VM profiler and threaded heartbeat +INSTALLDIR=sqstkspur64ARMv8linuxht +OPT="-g -O2 -DNDEBUG -DDEBUGVM=0 -DMUSL -D_GNU_SOURCE -DUSEEVDEV" + +DUALMAP="-DDUAL_MAPPED_CODE_ZONE=1" + +# Prefer clang over gcc if available +if [ -n "$(command -v clang || true)" ]; then CC=clang; else CC=gcc; fi + +if [ $# -ge 1 ]; then + INSTALLDIR="$1"; shift +fi +if ../../../../scripts/checkSCCSversion ; then exit 1; fi +echo -n "clean? " +read a +case $a in +n|no|N|NO) echo "ok but this isn't safe!!";; +*) rm -f config.h; test -f Makefile && make reallyclean +esac + +../../../../scripts/copylinuxpluginspecfiles +test -f config.h || ../../../../platforms/unix/config/configure \ + --with-vmversion=5.0 \ + --with-src=src/spur64.stack --disable-cogit \ + --without-npsqueak \ + --with-scriptname=spur64 \ + --with-vm-display-qnxScreen=yes \ + TARGET_ARCH="-march=armv8-a" \ + CC=$CC \ + LDFLAGS="$LDFLAGS -lscreen" \ + CFLAGS="$OPT -D__ARM_ARCH_ISA_A64 -DARM64 -D__arm__ -D__arm64__ -D__aarch64__ $DUALMAP" + +rm -f vm/sqUnixMain.o # nuke version info +rm -rf ../../../../products/$INSTALLDIR +# prefer make install prefix=`readlink -f \`pwd\`/../../../../products/$INSTALLDIR` +# but older linux readlinks lack the -f flag +make install-squeak install-plugins prefix=`(cd ../../../../;pwd)`/products/$INSTALLDIR 2>&1 | tee LOG ; test ${PIPESTATUS[0]} -eq 0 diff --git a/building/qnx64ARMv8/squeak.stack.spur/makeallclean b/building/qnx64ARMv8/squeak.stack.spur/makeallclean new file mode 100755 index 0000000000..a7cac6bd4e --- /dev/null +++ b/building/qnx64ARMv8/squeak.stack.spur/makeallclean @@ -0,0 +1,15 @@ +#!/bin/sh -e +trap 'exit 2' HUP INT PIPE TERM +if [ "$1" = -fork ]; then + shift + for d in `dirname $0`/build*; do + (cd ./$d + echo y | ./mvm "$@") & + done + wait +else + for d in `dirname $0`/build*; do + (cd ./$d + echo y | ./mvm "$@") + done +fi diff --git a/building/qnx64ARMv8/squeak.stack.spur/makedirty b/building/qnx64ARMv8/squeak.stack.spur/makedirty new file mode 100755 index 0000000000..11f39e8808 --- /dev/null +++ b/building/qnx64ARMv8/squeak.stack.spur/makedirty @@ -0,0 +1,15 @@ +#!/bin/sh -e +trap 'exit 2' HUP INT PIPE TERM +if [ "$1" = -fork ]; then + shift + for d in `dirname $0`/build*; do + (cd ./$d + echo n | ./mvm "$@") & + done + wait +else + for d in `dirname $0`/build*; do + (cd ./$d + echo n | ./mvm "$@") + done +fi diff --git a/building/qnx64ARMv8/squeak.stack.spur/plugins.ext b/building/qnx64ARMv8/squeak.stack.spur/plugins.ext new file mode 100644 index 0000000000..2d4e9735a2 --- /dev/null +++ b/building/qnx64ARMv8/squeak.stack.spur/plugins.ext @@ -0,0 +1,17 @@ +# Copied, perhaps edited, from ../../../src/examplePlugins.ext +EXTERNAL_PLUGINS = \ +ClipboardExtendedPlugin \ +FileAttributesPlugin \ +MIDIPlugin \ +Squeak3D \ +SqueakFFIPrims \ +LocalePlugin \ +UnicodePlugin \ +UUIDPlugin \ +ImmX11Plugin \ +XDisplayControlPlugin \ +DESPlugin \ +MD5Plugin \ +SHA2Plugin \ +VectorEnginePlugin + diff --git a/building/qnx64ARMv8/squeak.stack.spur/plugins.int b/building/qnx64ARMv8/squeak.stack.spur/plugins.int new file mode 100644 index 0000000000..944743ff0d --- /dev/null +++ b/building/qnx64ARMv8/squeak.stack.spur/plugins.int @@ -0,0 +1,23 @@ +# Copied, perhaps edited, from ../../../src/examplePlugins.int +INTERNAL_PLUGINS = \ +BitBltPlugin \ +BMPReadWriterPlugin \ +FileCopyPlugin \ +FilePlugin \ +FileDialogPlugin \ +Float64ArrayPlugin \ +FloatArrayPlugin \ +FloatMathPlugin \ +IA32ABI \ +JPEGReaderPlugin \ +JPEGReadWriter2Plugin \ +LargeIntegers \ +Matrix2x3Plugin \ +MiscPrimitivePlugin \ +Mpeg3Plugin \ +RePlugin \ +SecurityPlugin \ +SerialPlugin \ +SocketPlugin \ +StarSqueakPlugin \ +SurfacePlugin diff --git a/platforms/unix/config/aclocal.m4 b/platforms/unix/config/aclocal.m4 index e4d2d88d3f..7400c1f654 100644 --- a/platforms/unix/config/aclocal.m4 +++ b/platforms/unix/config/aclocal.m4 @@ -3597,10 +3597,22 @@ newos6*) lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; + *nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='$libname$release$shared_ext$versuffix $libname$release$shared_ext$major $libname$shared_ext' + soname_spec='$libname$release$shared_ext$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' lt_cv_deplibs_check_method=pass_all ;; + + openbsd* | bitrig*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`"; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' diff --git a/platforms/unix/config/configure b/platforms/unix/config/configure index d45920a1c8..7125fe69fd 100755 --- a/platforms/unix/config/configure +++ b/platforms/unix/config/configure @@ -828,6 +828,7 @@ with_gl enable_fast_bitblt with_custom_display with_vm_display_fbdev +with_vm_display_qnxScreen with_vm_sound_OSS with_vm_sound_Sun with_custom_sound @@ -1527,6 +1528,7 @@ Optional Packages: --with-x use the X Window System --with-custom-display enable custom window support default=disabled --without-vm-display-fbdev disable frame buffer vm display support default=enabled + --without-vm-display-qnxScreen disable QNX Screen display support --without-vm-sound-OSS disable OSS vm sound support (default=enabled) --without-vm-sound-Sun disable Sun vm sound support (default=enabled) --with-custom-sound enable custom sound support default=disabled @@ -17870,6 +17872,40 @@ $as_echo "no" >&6; } $as_echo "******** disabling ${plugin}" >&6; } disabled_plugins="${disabled_plugins} ${plugin}" fi + + +if test "${plibs}"; then + llibs="${LIBS}" + for l in ${plibs}; do + llibs="${llibs} -l${l}" + done + echo ${llibs} > ${plugin}.lib +fi +plugin="vm-display-qnxScreen" +plibs="" +rm -f vm-display-qnxScreen.sub vm-display-qnxScreen.lib +# -*- sh -*- +plugin="vm-display-qnxScreen" +plibs="" +rm -f vm-display-qnxScreen.sub vm-display-qnxScreen.lib +# -*- sh -*- + + +# Check whether --with-vm-display-qnxScreen was given. +if test "${with_vm_display_qnxScreen+set}" = set; then : + withval=$with_vm_display_qnxScreen; with_vm_display_qnxScreen="$withval" +else + with_vm_display_qnxScreen="no" +fi + +if test "$with_vm_display_qnxScreen" = "no"; then + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ******** disabling vm-display-qnxScreen" >&5 +$as_echo "******** disabling vm-display-qnxScreen" >&6; } + disabled_plugins="${disabled_plugins} vm-display-qnxScreen"; +fi + + if test "${plibs}"; then llibs="${LIBS}" for l in ${plibs}; do diff --git a/platforms/unix/vm-display-qnxScreen/Balloon.h b/platforms/unix/vm-display-qnxScreen/Balloon.h new file mode 100644 index 0000000000..62d3d71513 --- /dev/null +++ b/platforms/unix/vm-display-qnxScreen/Balloon.h @@ -0,0 +1,2169 @@ +/* GIMP header image file format (RGB): /home/kend/Pix/Balloon.h */ + +static unsigned int balloon_width_pixels = 183; +static unsigned int balloon_height_pixels = 188; + +static unsigned int balloon_depth_bits = 32; /*32 fixed for this image = bits-per-pixel */ +static unsigned int balloon_depth_bytes = 4; /*4 bits-per-pixel / bits-per-byte */ +static unsigned int balloon_width_bytes = 732; /*808 balloon_width_pixels * balloon_depth_bytes */ + +/* Call this macro repeatedly. After each use, the pixel data can be extracted */ + +#define BALLOON_PIXEL(data,pixel) {\ +pixel[0] = (((data[0] - 33) << 2) | ((data[1] - 33) >> 4)); \ +pixel[1] = ((((data[1] - 33) & 0xF) << 4) | ((data[2] - 33) >> 2)); \ +pixel[2] = ((((data[2] - 33) & 0x3) << 6) | ((data[3] - 33))); \ +data += 4; \ +} +static char *balloon_data = + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````\\O\\OS]P,I;'AD)S,C)C(@HZ^=X.SB)3$HZ_@" + "QM,#WNL;^PKU]`P0^@`0^0`(]P`![@4#U^OPL<;1C9VY<'VI:'2DJK;FY_0D````````````" + "````````````````````_PL[X^`@Q-$!J[?HDI[/AY/%BY?)BI;(EJ'3ML+ST=X." + "[_PL````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````Z/4E" + "G:G9<7ZMFZK0VNO\\^0`.^0`'^0`'^0`'^0`-^``3^0`'^P`.^@`2^P`2]``*]``'" + "^@`/\\@@*L,?+?(JR;'BIPX>`P\\_````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````_PL[Q]4$]U>CP^@`0^0`-^@`,^``7^``1^P`0^``5^P`5" + "^``4^P`4^0`0^@`0^@`2]P`'^@`1]``\"]``\"^@`+]P`#Z`+^F:R_8W\"?7VN<9W.E" + "<7RSE9GOT=0WV]P`U-4`WN$`WN,`W-\\`W>$`WN(`W=``U]D`SLP`U-4`R,@`Q,$`" + "HJ(3='Z]:G:HUN,3`P\\_````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````_PL[Y_0D" + "RM<'J+3FD9W/CIK,B9;(A9'#=X2V>8:WAY3%:W>H2U>(9'*;DZ6TJK[)Q-??TN;P" + "Y_S\\^@`+^@`+^@`+^P`5^``2^@`+^@`+^@`+_0`8^P`5^0`&]``%]``%^``4]``$" + "]``\"^0`+]P`$]P__]``$G;\"Y>8RB2%2\"?87-X.4`W>$`U=@`W^(`TM(`TM(`TM,`" + "TM(`S\\\\`S\\\\`V-H`UM<`U]D`S(2V;7JL?Y#*E*[XMM8DT.`_U/0`UO8`U_4`V/<`U?8`S>LU" + "MM(8M]09K,8*F;'R@YG7=8K&8'.J3EZ4/4Z\"/4Q^0%%^0U%Y4%^$9'*5CZ\"[U.CS" + "^0`'^0`'^0`+^@`3]``%]``%^0`.^@`*]``\"^0`+]P`#]P__]``*]@_[]@_[8W22" + "H:4\"U-4`U-4`W^,`TM(`TM(`V=P`S\\\\`S\\\\`TM$`T],`SX>YDJ'8K<4&U?0ZW/D`W/@`V_D`VO@`" + "VO<`V?@`VO<`VO<`V?8`V?<`VO<`VO@`V_<`U_8`UO0`U?0`R>P`R>P`TO(`U_8`" + "S>\\`Q>L`Q^T`Q^A:+G3F&41E1\\GK&][`;`^0`'^P`0^@`.]``%]P`(^@`0" + "]``\"^0`*]P`\"]P__^@`,]@_[W?;I/4A_U-4`U-4`WN$`TM(`TM(`W-\\`S\\\\`S\\\\`" + "V]T`SXJ_F*[PS>PTS_$`" + "S_$`V?@`SN``SN``SN``SN``SN``T?(`U_4`V?<`V_<`V?<`U_0`T/$`SN``SN``" + "TO(`S.\\`RN\\`U/,`U_0`TO$`R.P`R.P`T.``U?0`SN\\`Q>L`SN``T_,`O-XQ?)74" + "/TUZ>(FAW_7S^0`'^``4]``(]``%^@`1]``#^0`,]``$]``!]``%]@_[;7V?H:4!" + "U-4`WN(`TM(`TM(`U]H`S\\\\`UM<`SLT`S6VBJ.$J\"" + "1%621UJ40%.,.T=X>(:W@(Z_?HR]X`R>X`R>X`T/(`U_<`U_8`" + "S^\\`R.P`T.``U?0`SN``QNP`TO,`T.`_DK'X25N'7&N*QMO?^0`*^@`3]``%^P`0" + "^@`)^0`*]``$]``']0_]U^_G4%B8U-4`W^(`TM(`U=<`S\\\\`S\\\\`U]<`SX`R>X`SN``UO8`U?0`S.X`SN``U/0`S_(`RNX`" + "TO(`J\\P876^A25A^L\\?/^@`/^@`1]``*^0`1]``)]``%^@`-]@_[4%V*PL0JW-\\`" + "TM(`W-``S\\\\`VMT`SH:````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "`````````````````````````````````P\\_KKKKBIG0SN`_S_$`S_$`T?(`V_@`" + "V?<`T?(`S>``S>``S>``S>``V?8`T/$`T/$`T/$`T/$`T/$`T/$`T/$`R>DWJ\\<2" + "F++X@YC9<(3\"9WJX87.N8G6P:WJV;(3%@ISBE[3^IL41O^$QR^X`T?$`UO8`VO@`" + "U_8`S>``R>X`TO0`U?0`U/,`S_$`U/0`T?(`TO,`P^(NG_/V]``TM(`V]X`T],`T-$`TM0`T-$`FYX$.4:!AK'E" + "P`\\_SP``TP``Q@``Q0``S0``S0``P```P0``PP``S@``S```RP``PP``OP``OP``" + "OP``S0``L0``MP``P0``P@``M@``L0``L0``L@``H?$A:86V``S>``S>``S>``S>``S>``S>``S>``U_4]O]\\KIL(+" + "B*#E>(S.7F^J6&JC6VBA76F?=X*YE)C0M;#GSL7YWLYG+" + "E(R`?(\"U:7.K3%J02EF31UF24VBG<8G-CZKSK\\X9T^`[V/4`U?4`SO(`U/,`U_0`" + "U/0`U?(`T_,`S^XY@IC31U9_F*FZ\\`D.^P`0^@`-]``)\\`K`0DY`V]\\`TM,`TM4`" + "V=T`U-0`Q<8S5EZH5&^DN/TMTP``S@``Q0``T0``S@``PP``Q0``S```T@``S@``" + "P@``OP``OP``OP``P0``R0``S0``S@``S0``Q```PP``P0``P0``NP``O```QP``" + "Q```N@``L0``HNX><8:W@Y#!Z_@H````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````_PL[DY_0HKT#VOD`W?D`V_@`V_@`VO<`UO,ZJL4)?9'04V*<" + "3%J23EF045B/4EB-55B,:&J?AX2VKJ'4U;_P^]P,`^45`^86`^86`^86`^$1`]X." + "`]P,`]D)`]4%`]4%`]4%`]@(`]X.`^(2`^,3`^45`^04`]`0`]X.[<[_Q+#EH9W5" + "@(>`76JC2EJ215B26W&Q?)79J,(&S>HRU?0`U?4`V/8`U_4`T_,]D*?H1U>%A):P" + "Z_\\&^P`1^0`,;'N:LK@0V]P`V-H`U=8`G)[_-DA^E\\G[T```S@``SP``S0``R0``" + "SP``S```QP``OP``P0``R@``S0``S0``R```Q@``P0``N```N```N```N```N```" + "N0``J0``LP``N```J@``J0``L@``N@``O```Q0``P```PP``C]D)7V^@I+#A^P``" + "P.$OA9_E35R70DE\\?76FOZ77Z,/T`]P,`]X.`^(2`^(2`^45`^45`^(2`]T-`]L+" + "`]L+`]L+`]X.`]<'`]8&`]8&`]8&`]8&`]8&`]8&`]<'`]L+`]T-`]\\/`^$1`^(2" + "`^,3`^(2`^,3`^04`^(2`^$1`]`0`]\\/`^$1`^,3`-\\/XSAIO(<(&@X?/^R^#J9&^JW]``S](S7FJN5'\"C" + "Q`$QTP``T@``S```SP``RP``R```T0``T0``S0``N?LKG>45BLO\\?KKKX3G:G2&J;05^0.52$.U*\"/%*!.5!`/&\"04HJ[>LCYI`0TP```L```J0``J0``" + "J0``J0``J0``L```M0\\_?:_@56*3V.45````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "_0DY?XN\\KL4'TO(`N=`W?YSE2%F30DR\"G97)[M<'`^D9`^H:`^H:`^D9`^@8`^D9" + "`^@8`^<7`^<7`^86`^<7`^@8`^H:`^@8`^45`^,3`]X.`]X.`]\\/`]`0`^(2`^(2" + "`^,3`^,3`^,3`^04`^45`^45`^04`^45`^,3`^,3`^(2`^(2`^(2`^$1`]\\/`^(2" + "`^,3`^,3`^45`^86`^45`^45`^86`N45W\\?XMZG:C(F]76.63E>-2U>.86^H97>Q" + "/DY`7FN6.TAVE)WJ.$A_C+3EK-T-H-(\"B;CI=Z#19(FZ5G:G1V.3/%2$/%*!/%!^" + "1EJ(7F^<<(\"IA)&VE9Z`I:G&PK_6T,?9X-?GZ]_M]>KV`_@#`_@#`_@$`_H&^_+`" + "TL_HAYB^05:#.52#5H.T?[?HH>L;I`\\_J0``J0``G@``K@``K0``HO8F4VJ;L+SM" + "`P\\_````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````_0DY?8F[LG6E8F&02TU^,3II%B%2!1%\"!!!!$Q]0,3UM4EV'?(.IF9^`" + "M;71R\\KCX=WU]O$&`_P.`_P.`_L.`_P-`_L-`_L*`_L+`_H'`_L'`_H&`_@$`_@\"" + "`_@\"`_@!`_7``_7``_7^`_3\\`_3\\`_3\\`_3\\`_3\\`?+[V,[>EIJ[7&Z8.$IW/EB'" + "6(^`<<3U@_`P\\_````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````^P(5U\"!6%*#6%.$5U2$" + "6%:&5U:&:F:4WBEBXFQEI.[H)[$KJS.N;K8U-+OU]7SFY_\"35R\"5FJ05&J0" + "6FRD0D]Y,3EI,35K55238F*>14E^/T5U3U.!=WB?H)V[P+[9Y^#W`_H,`_D*`_D(" + "`_D(`_H+`_H)`_H*`_L)`_D(`_@%`_8#`_3^`_3\\`_3\\`_3\\`_3\\`_3\\`_3\\`_8!" + "`_8!`_8!`_<\"`_@\"`_@\"`_D&]>K\\O;G4A(RN36\"*+TAW1F>45I[.?]$!87*CK[OL" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````_0DYT=X.2E:'5E^2MJ+4`-L+`^45`^D9`^D9`^H:`]\\/`]T-`]L+`]L+`]L+" + "`]L+`]L+`]L+`]L+`]L+`]L+`]P,`^04`^<7`^04`]T-`]D)`]D)`]D)`]D)`]D)" + "`]D)`]D)`.,3X+SMO9_0F(.T=6F:656&5U2$5U6%5U:%9V22@7VHE9&YKJ?,QKO=" + "W-+NY-SU^_4*`_X1`_T3`_T4`_\\4`_X2`_X2`_T4`_T4`_X3`_X6`_T5`_X5^O0," + "K[#.5V.)4&*(EK;.U@,,A*2_9'BQPMXF6&J5GK#&2DUZI)+$3DZ%6UN8NJK^[=]>O^`_@&`_D%`_8\"`_/]`_/[" + "`_/\\`_;_`_8#`_@%`_L)`_L*`_H+`_L-`_L.`_H+`_H)`_D)`_@&`_L)`_'X`_/Z" + "`_H'`_H)X]OMI**\\7VB.)S5C(BY?FZ?7\\?XN````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````[_PLPL[_?XJ[;76FIY[/]-H*`^@8`^04`^@8`^04`]P," + "`]P,`]T-`^(2`]L+`]L+`]L+`]L+`]L+`]X.`^45`^<7`^86`]\\/`]D)`]D)`]D)" + "`]L+`]T-`^$1`^(2`^86X87EZ.7V..>'JAG)JZO[O4X]OM`/8$`_D&" + "`_H)`_P/`_T/`_T3`_T1`_P0`_L.`_H)`_L+`_X1`_\\4`_T3`_X2`_X-`_P0`_\\4" + "`_\\4`_P/`_T2^?4)L:[+86R/5&:*C:S$T/X'W``3W``2CK3(5VNEUO0_T_,`0%%`" + "^``0L<33/T1QZL[_X7\"F.#UTBX#-ZM(Q^-X`^M``^MX`^-X`Z<\\OP;$#GY76" + ">WFK3U1`3%)Z4U9[GFDN+;8Z>;]`_`6" + "`_T2`_T3`_X3`_X2`_T0`_L-`_D'`_D&`_D&`_L,`_T1`_T3`_X2`_T.`_H)`_H'" + "`_T/`_X3`_X3`_T/`_D'`_L/`_T2^O0'K*C!6&\"&2ER!B:J`U/\\'WP`3W``3X0`2" + "VP`.E;_-25J2TN`\\TO$`S_(`/D^$^P`2^@`0Q]OC0$1RWL'R`]X.^-4%HI##2$B!" + "8EZAQ+$'^-L`^-L`]]T`]]H`^-P`^=P`^-D`]]L`\\]0XR;,%IIK7A8*Q6ER'455\\" + "7V&#C8JDO;7'[-_I`_/Z`_/Z`_7_`_@&`_H)`_H+`_H+`_H+`_#R`^[M`^[M`_-T>XYT_0`T_(`S^``3F&;Y/G\\^P`0" + "^P`.X_;Z1$IUQ:S=`]H*`]L+`]`0V+GJ@W" + "R^\\`S_$`T_(`T/(`:('$O=+6]``*^@`-^@`,Y?W\\2D]ZN)S-`]P,`]\\/`]L+`]@(" + "_-0$JI'(3$N'7%6=NZ8!]MP_]=,`]]4`^=T`]]D`]<\\`]]H`^-P`]]D`],T`]M(`" + "]]@`]M8`]\\``WKDHHX_B:&.?/4)S55=`FI*DZ]C:`^WJ`^WK`_<\"`^_O`_/Y`_8!" + "`_#U`_#U`_3``^_Q`^[M`^[N`_3[`_@&`_<%`_'XN[3)8FV=K[OL^PL`R^X`TO,`@J'LE:BX^P`3^@`-]``%" + "]P`$]0D$8&6,@W\"A`]\\/`]8&`]L+`]L+`]8&`]L+W;?J;F:B-SIVE(#9[<\\T]]T`" + "]M(`]=$`^-L`^=L`]<``]<\\`]]D`^MX`]]D`]GVBT,SD`_X2`_`4`_T5" + "`_\\7`_`7`_X4``$9`_\\8`_L-`_L+`_L+`_L+`_X5`_X6`_X2`_P-`_@%`_@%`_@%" + "`_@%`_@%`_@)`_P1`_P1`_D(`_@#`_@#[.+QD9\"L1$]V:7^>M-_HUP`(W@`/X0`4" + "UP`)V0`)X@`4UP`'UP`(W@`0TP`\"V0`+U``(M.WF/4]^N]PKU_8`R.T`T_0`R^X`" + "PND`T?(`G\\,5<(\"@^@`.]``#^0`.^0`,]P__]@\\%=GR=>6B9`MT-`]0$`]X.`]0$" + "`]P,`]$!`]@(]\\G[GHK%146#9EVIT+(9]]H`^=T`],``]G:/X,_3`_7^`^_P`^WJ" + "`^WJ`^WJ`_/Y`_8!`_8!`_+Z`^[M`^[M`^[M`^_P`^_N^>OOEIK\":'2EW.D9````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````YO,C@XZ_\\M8&`]@(`](\"`^86`]P,`]P,`]P," + "`]P,`]X.`^<7`]L+`]0$`]0$`]0$`]4%`]T-`^$1`^(2`^$1`]D)`]4%M9K*34]\\" + "HJ+$_?L2``$8`_`7`_\\6`_P-`_L.`_`7`_X4`_L+`_L+`_P.`_\\6``$7`_`8`_P0" + "`_D'`_D'`_L/`_\\4`_@%`_H(`_X2`_P2`_D)`_@#`_@#`_@#`_@#P;O15V\"$4&&&" + "F<#/TPL$UP`(W``3WP`2U@`'UP`(X0`5U``*U0`%WP`1UP`&TP`\"V``/T``%O/?M" + "/$]\\MM8ET?$`R^X`S_$`Q>L`T?(`PND`T?(`N>$Y2UN&]``%^0`,]``+]P`!^P`/" + "]P`!]P`!D9BQ8UB)_M,#`]P,`](\"`]T-`\\_``]P,`\\S]`]D)`]0$SJOD8%J:2D>+" + "I8[K\\LX]^-L`^-L`]R2UI_>IFRQ/GWUP`(U``*X0`4VP`.U@`'U@`'W``3V@`,U0`%UP`(" + "W0`0TP`\"TP`\"W@`1S`__P`#T/E)]KLX:R^X`TO(`R.T`U?0`Q>L`TO(`PND`S^``" + "ON<`0U2$]``%^P`3]``#^@`0]P`!]``(]@`\"]`__I[#$4DQ\\]\\CY`^$1`\\[_`]H*" + "`]8&`](\"`]P,`\\O\\`]<'`],#[[WQB7V]/3U]BWG/Z<0R]M(`^=T`^-L`]86@XN\\_=`0`]4%`](\"`](\"`](\"`](\"`^@8`^<7`^(2`]P,`]4%" + "`]0$`]0$`]0$`]0$`]0$`]0$`]0$`]0$S:K;6%:$?7^G\\>G]`_L+`_L+`_P/`_`7" + "`_\\5`_X4`_`8`_\\6`_P/`_L+`_P/`_X5`_P.`_D'`_D'`_D'`_P0`_T5`_T4`_\\6" + "`_D,`_8!`_8!`_8!`_8!`_8!Y-SO1UN!EK_+U0T&UP`(V0`+W``4V0`*U@`'" + "U@`'W``3V@`,U0`%U0`%W@`2U@`%TP`\"T``$W0`/S`__Q`7X1%J!J,80R^X`U_0`" + "R.T`S>\\`Q^P`Q>L`RNX`PND`S>``ON<`1U>,\\0C`^@`+]``#^0`&]``#]P`(]@__" + "^0`&]@_]NL;22$5U[L'R`]P,`]0$`]$!`]P,`\\W^`]4%`]D)`\\K[`]D)`],#_L/U" + "IH_+04)_<66TWKLG]LX`]],`^=T`]M@`];O?H&G<'RL[/DI````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````T=X.@XJ[`.$1`](\"`](\"`](\"`](\"" + "`]\\/`^$1`\\3U`]@(`]H*`]0$`]0$`]0$`]0$`]0$`]0$`]0$`M,#NIO,5E2$>WVC" + "[NL$`_L+`_P/`_`9``$:`_`8`_X5`_L-`_L+`_L+`_P,`_X6`_X2`_D'`_D'`_P0" + "`_X5`_X3`_D+`_H)`_T1`_@'`_8!`_8!`_8!`_8!`_D(XMST8&>-56>+M-_GUP`(" + "UP`(WP`2W``2U@`'U@`'U@`'WP`3W0`0U0`%U0`%V@`,V``,TP`\"TP`\"U``(V0`)" + "S`__S@S]2&*$G;C`R^X`T.``R^X`R.T`UO4`Q>L`R^\\`PND`PND`S.X`ON<`7W2N" + "T.;E]``%^@`.]``#^@`/]P_`^P`-]@_\\]``*]@_ZR-C;0D!QY+KK`]4%`]P,`\\[_" + "`]8&`]D)`\\S]`]H*`]4%`\\K[`]8&`]<'`\\?XOYW62$B#;6.NW;LF]LX`]LX`]]<`" + "^-L`]],`]7MVP`,X@`7X0`4W@`/U@`'U@`'U@`'W0`2WP`1U0`%U0`%U0`%" + "WP`2T``$TP`\"TP`\"V``-T@`\"S`__SP[^57&/C*;IR^X`R^X`U/(`R.T`RNX`R>X`" + "Q>L`TO(`PND`PND`R.X`ON<`>)'6K<')]``%^@`2]``#]``&]P`%]P_`^0`,]@_\\" + "]``+]@_YU.;E0#]OV+#A`](\"`^$1`\\[_`\\[_`]T-`]$!`\\S]`]L+`]$!`\\K[`]8&" + "`]8&`\\?XR*'65U2/;6.NW;LF]LX`]LX`]LX`^-D`^=X`^-<`^-D`],4`\\\\4`^-D`" + "]L\\`\\[``]7*'Y\\W%`^35`^35`^35`^[K`^35" + "`^WK`^OD`^K@`^[L`^?;`^?<\\^3M;'>FPWN;6&*(ON7QVP`,W@`/Y@`;XP`9U@`'U@`'U@`'" + "VP`-W0`0U0`%U0`%U0`%V``.V0`,TP`\"TP`\"TP`\"WP`2T0`\"S`__S`__9XF??Y;5" + "R^X`R^X`U_8`R.T`R.T`U?,`Q>L`Q>L`TO,`PND`PND`Q>L`ON<`CJSZB)NN]``%" + "]``)]``$]``#^P`0]P_`]``$]``$]@_\\]``+]@_YWO#I04)RS*?8`](\"`]P,`]0$" + "`\\[_`],#`]L+`\\S]`\\[_`]P,`\\[_`\\K[`]0$`]8&`\\?XT*/55E.*;6FLX<4H]M4`" + "\\\\L`\\\\8`],T`]M@`\\L4`\\\\(`\\\\(`]=(`]M$`]L``\\[``]M,`].CUN4U1RQ[*R`^35`^KB`^79`^35`^;:`^_P`^C?`^_O`^?;`^?;^>+?9W*A" + "SML+````````````````````````````````````````````````````````````" + "````````````````````````````````````````````S=H*?WVN`MT-`](\"`]\\/" + "`]L+`](\"`](\"`^(2`\\3U`\\3U`\\3U`\\3U`\\3U`\\3U`\\3U^K[OD'6F3TU^NK#5`_T1" + "`_`8`_`:`_T1`_L,`_L,`_\\4`_L+`_L+`_X2`_\\7`_X4`_P0`_D'`_D'`_D'`_D'" + "`_D'`_D'`_P1`_L/`_8!`_@%`_L.`_H.`_8#`_8!`O3`HIZX25)YK<[@VP`,WP`3" + "X``:XP`6V@`,V@`,W``5VP`.X0`2U0`%U0`%U0`%UP`'W@`1TP`\"TP`\"TP`\"T``#" + "W0`/S`__S`__S`__@ZVZ8WFSR^X`R^X`S_$`S.\\`R.T`R.T`S>``Q>L`Q>L`R>T`" + "PND`PND`P>D`ON<`ILL?9'24]``%]``%^0`.]``#^0`%]``%]P_`^@`+]@_\\]@_\\" + "]``*]@_YYOKP1D=VPZ'2`](\"`]4%`]T-`\\[_`\\[_`]L+`](\"`\\S]`\\_``]L+`\\O\\" + "`\\K[`]4%`]@(`\\?XR:C90T-[>6>^Z[TW\\\\,`\\\\,`],\\`]P^R^X`R^X`UO,`" + "R.T`R.T`U/0`Q>L`Q>L`S.\\`PND`PND`P^L`ON<`ON<`O.0]1U>\"]``%]``%^@`2" + "]``#]``#^P`1]P_`]P_`]``-]@_\\]@_\\]``)]@_YY`#Q14AVQ:+3`](\"`](\"`^$1" + "`\\[_`\\[_`]$!`]X.`\\S]`\\S]`]0$`]L+`\\K[`\\K[`](\"`]D)`M,#IXW(/SU\\L)#X" + "\\\\,`\\\\,`]L``\\\\4`]L``]\"]-W:`^35`^35`^35`^;:`^_Q`_'T`^?;`^?;K9ZH>(2U" + "`P\\_````````````````````````````````````````````````````````````" + "````````````````````````````_`P\\=H&R]-<'`]P,`](\"`](\"`](\"`](\"`]P," + "`\\3U`\\3U`\\3U`\\3U`\\3U`\\3URZ+344]_J*+(`/\\7`_P/`_X2`_\\6`_L,`_L,`_L," + "`_P0`_`7``$:`_H+`_D%`_T.`_\\4`_D'`_D'`_D'`_D'`_D)`_\\4`_T1`_P-`_@'" + "`_8!`_8!`_8!`_8!`_8!^^[[?GZ=:7B:S_P$X``7W``3W@`1X@`6V@`,V@`,W@`2" + "Y0`9X0`5UP`(UP`(V``.WP`2WP`3TP`\"TP`\"TP`\"TP`\"U``*T``%S`__S`__S`__" + "LNOD/$Q`PN0UR^X`R^X`V/8`R.T`R.T`R.T`TO,`Q>L`Q>L`T_,`PND`PND`QNP`" + "ON<`ON<`ON<`0U6$]``%]``%]P`(]``&]``#]``#]``)]P_`]``!]``&]@_\\]P_^" + "^0`&]@_YZ0#O3$U\\R*35`](\"`](\"`]T-`]4%`\\[_`\\[_`]@(`]8&`\\S]`\\S]`]<'" + "`]4%`\\K[`\\K[`],#`\\GZ]<'W<&2B5TZ:W+(G\\\\,`]]0`\\\\,`\\\\0`]M0`],<`\\\\(`" + "]M0`\\\\8`\\\\(`]L`Q>L`Q>L`TO(`PND`PND`R>T`ON<`ON<`ON<`0U2']@X#]``%]``%^@`2]``#" + "]``#^@`/]P_`]P_`]``']@_^]@_\\]P`!]P`\"]@_YZP/P2DYZSJG:`](\"`](\"`]4%" + "`]P,`\\[_`\\[_`\\_``]X.`\\W^`\\S]`\\S]`]L+`]$!`\\W^`[_P`](\"`\\+SRZ;B/CQ]" + "H87H\\\\,`]M4`\\\\,`\\\\,`],<`]M0`\\\\,`]L`Q>L`Q>L`R.L`PND`PND`S.X`ON<`ON<`" + "ON<`56FBW//O]``%]``%^``2]``#]``#]``#^@`,]P_`]P_`^@`.]@_\\]@_\\]P`$" + "]P_^]@_YY`#N1TMXU:[?`](\"`](\"`](\"`^$1`\\[_`\\[_`\\[_`]4%`]@(`\\S]`\\S]" + "`\\[_`]X.`[WN`[[O`]4%`\\3U^<7YF^T,3=?VL*]`^35" + "`^35`^C>`^+0`^/1`]J\\C(.2F*35````````````````````````````````````" + "````````````````````````````````````````````WNL;BX.T`\\7V`](\"`](\"" + "`],#`]D)`\\3U`\\;W`]8&`](\"`\\3URYS-2TIYZ>/X`_L,`_`8`_P0`_\\6`_\\8`_P/" + "`_L,`_L,`_\\5`_L-`_D%`_D%`_D%`_D%`_D%`_\\3`_\\4`_L,`_H(`_+X`_+X`_+X" + "`_+X`_+X`_/\\`_@&`_H,`_H*T25=`K-+BVP`,VP`,V``,X``8VP`-X@`5X0`5" + "V@`,WP`3W@`1UP`(UP`(W@`3W@`1W``1TP`\"T0`!T0`!T@`#V``/V0`-RP_YR0_V" + "R0_VR0_VU@`$;Y>E@9G7S_$`S_$`VO<`U_4`R.T`R.T`R.T`SN``QNL`Q>L`Q>L`" + "R^X`PND`PND`PND`S>\\`ON<`ON<`ON<`9GZ`PM?:]``%]``%]``']``(]``#]``#" + "^@`.]P_`]P_`]P_`]``+]@_\\]@_\\]``%]0_\\]@_YX?KJ1$EVWL+S`]X.`]T-`]@(" + "`]X.`],#`\\[_`\\[_`\\[_`]\\/`]<'`],#`\\/T`]@(`\\3U`[SM`](\"`\\S]`\\S]P)W:" + ".#=XLY/\\]M8`\\\\,`\\\\,`\\\\,`\\\\,`]M,`\\\\H`]],`\\\\0`\\\\(`\\\\(`\\\\(`]L``]]0`" + "\\\\0`\\[``\\[``]LH`MYO\\+3-AI9:>`^?A`]JY`]BW`^/-`]JZ_.+86665X.T=````" + "````````````````````````````````````````````````````````````````" + "````````E:'2Y:76`[?H`]8&`],#`]<'`\\_``]8&`\\GZ`\\3U`\\3UO9/$6E6$^/0*" + "`_\\7`_\\9`_`7`_P0`_L,`_L,`_L,`_T0`_\\2`_D%`_D%`_D%`_D%`_P1`_\\5`_P," + "`_D%`_T/`_3``_+X`_+X`_+X`_+X`_+X`_+X`_+X`_+X`/'[BXNK8'*5SP(!VP`," + "VP`,WP`3W``3X@`6X0`5V@`,V@`,XP`8V0`)UP`(W0`1WP`2UP`(X0`3T0`!T0`!" + "T0`!U``*U``*U``*R`_ZR0_VR0_VRP_WUP`'F]3,5&F;S_$`S_$`S_$`U_4`VO4`" + "R^X`R.T`R.T`U/,`Q>L`Q>L`Q>L`T_,`PND`PND`PND`SN``ON<`ON<`ON<`>)7<" + "IKK%]``%]``%]``%^@`3]``#]``#]``#^0`-]P_`]P_`]P`#]P`#]@_\\]@_\\]``*" + "]@_Z]``#UO':0$1P\\+[O`\\S]`\\S]`\\[_`]H*`]0$`\\S]`\\CY`\\CY`]H*`\\K[`\\/T" + "`\\/T`]<'`\\GZ`[SM`]$!`\\W^`\\O\\\\K;I4TV->FB_]=(]\\\\,`\\\\,`\\\\,`\\\\,`\\\\0`" + "]M0`]L``],L`\\\\(`\\\\(`\\\\(`\\\\(`]<\\`]]8`\\[``]\\`U_4`S>``R.P`Q>L`Q>L`Q>L`T/$`PND`" + "PND`PND`S^``ON<`RNT`Q^P`BJGUCJ\"U^@`3^0`.]``%^@`.]``#]``#]``#^0`+" + "]P__]P_`]P_`^0`,]@_\\]@_\\]@_\\^@`*]`__\\@_GP];72D=W_S24.*Y,,M\\\\,`\\\\,`\\\\,`\\\\,`\\\\,`],D`]M8`]<``\\\\(`\\\\(`\\\\(`\\\\(`\\\\(`" + "]M,`]M0`\\*``\\;,`]]-3A\\`R^X`R^X`R^X`" + "VO<`T?$`U?0`U/0`S^\\`SN``S.\\`S^``T?$`T_0`O.4`L-X`L-X`G+P,>(FD^0`&" + "^0`&^P`1^@`1]``(]``#]``#]``#^@`0]P_`]P_`]P_`^@`-]@_\\]P`%]``&]P__" + "\\@_G\\P_RHK&\\:5J+`\\S]`\\S]`\\S]`]X.`]8&`\\S]`\\CY`\\CY`],#`\\_``\\[_`\\/T" + "`\\CY`\\O\\`],#`[WN`\\_``[[O`\\_``\\3UP);,-3=SSJX6\\\\,`\\\\,`\\\\,`\\\\,`\\\\,`" + "\\\\,`],\\`]M@`\\\\,`\\\\(`\\\\(`],H`]" + "`]BV`^78`^7:SK\"C5V.4_PL[````````````````````````````````````````" + "````````````````````````?HJ[_+/D`[?H`\\S]`\\'R`ZO<`[+C`\\S]`\\3UO)+#" + "7%6%`/L2`_D%`_T1`_L,`_L,`_L,`_P1`_\\2`_H)`_X4`_T0`_D%`_D%`_D%`_D%" + "`_D%`_D&`_P.`_+X`_+X`_+X`_+X`_+X`_@#`_H*`_3_`_+X`?#W@X&<;GV=U0L&" + "V0`*Y0`8Y@`;W``2V@`,V@`,V@`,V@`,X@`7V@`,X@`5V@`+UP`(UP`(V0`*V``." + "T0`!U@`'V@`.T0`!T0`!T``%T0`!R0_VR`_XU@`'R0_VR0_V>JFN>9#)S_$`S_$`" + "V_<`S_$`V?8`R^X`R^X`R^X`V?<`SO$`Q>L`Q>L`Q>L`U/0`N^4`N^4`N^4`ON4`" + "RNX`L-X`L-X`L-X`HLD@8W27^0`&^0`&^0`&^0`&^P`1^0`+^@`0^@`1^@`0]``'" + "^0`*]``*^@`/^0`+\\`_R\\`_Q]P`%\\P_M\\@_G]0_Y=GJ;GH*S`\\S]`\\S]`]@(`\\S]" + "`]<'`\\GZ`\\CY`\\CY`]L+`\\O\\`]$!`\\/T`\\O\\`\\CY`\\_``\\'R`]$!`[SM`\\[_`\\GZ" + "W:'2.#EQIXWO\\\\,`\\\\,`\\\\,`\\\\,`\\\\,`\\\\,`\\\\0`]]8`]LL`],P`\\+8`\\+,`\\+,`" + "\\\\H`]15F&S>\\^S_$`VO<`S_$`UO4`R^X`R^X`R^X`U_4`T_(`Q>L`Q>L`" + "Q>L`R^\\`T/(`N^4`N^4`N^4`S.X`QNL`L-X`L-X`O^8`J-0T4&\"(^0`&^0`&^0`&" + "^P`1^P`2]``!]``!]``!]``!^0`,]@_Z]@_Z]@_Z]``-\\`_Q\\`_Q]P_]]P_`\\@_G" + "]0_W[@OH14=TU:K;`\\S]`\\S]`\\_``\\S]`]H*`\\CY`\\CY`\\O\\`\\[_`\\K[`],#`\\/T" + "`]$!`\\7V`\\K[`\\K[`\\_``[SM`\\;W`\\W^]JW>34=\\AG7)],T`]=(`]-(`]L\\`]4%5ZO.'NV0`*W0`0Y@`:V``0WP`2" + "V@`,V@`,V@`,W``4X@`6W@`0UP`(UP`(UP`(UP`(W0`/U@`)U``)V@`,T0`!T0`!" + "T0`!T@`\"U0`'R0_VUP`&RP_XR0_VR0_VQ`[U16%`N-@AT/(`VO<`S_$`S_$`UO4`" + "R^X`R^X`U?0`S.X`U/,`Q>L`Q>L`Q>L`SO$`S.``N^4`N^4`ON8`P.<`P>@`L-X`" + "L-X`P^H`L-X`1E5`^0`&^0`&^0`&^@`3^@`/]``!]``!]``!]``\"^0`+]@_Z]@_Z" + "]@_Z]``,]@_Z\\`_Q\\`_Q]@_Z\\`_U\\@_G]0_VV.[?/#IK^,3U`\\S]`]P,`\\S]`\\S]" + "`]H*`\\CY`\\CY`]@(`\\CY`\\GZ`]8&`\\/T`]4%`\\/T`\\;W`\\[_`\\[_`[WN`[[O`\\_`" + "_[?H956/;UNT[[$_\\+(`\\+(`\\+(`\\+(`\\+(`\\[X`\\;<`\\L,`\\+,`\\+,`\\+,`\\+@`" + "\\+H`\\;L`\\[``\\+,`],(`\\+(`FH'<*S%=S[JX`]JZ5EN$S-D)````````````````" + "````````````````````````````````````````@HZ_^+'B`\\GZ`[?H`\\/T`ZO<" + "`ZO<[9[/0CIKY-_Z`_D&`_D%`_D%`_D'`_`5`_/\\`_4!`_L.`_D%`_D%`_D%`_D%" + "`_D%`_D%`_P)`_H(`_+X`_@&`_D'`_+[`_+X`_+X`_+X`_+X`_+X`_+XP[G*4%=\\" + "SOP\"VP`+X@`7X0`6VP`.V@`,V@`,XP`7V@`,X``8W@`3UP`(UP`(UP`(UP`(UP`(" + "W@`1U0`&V``/T@`\"T0`!T0`!T0`!T0`!UP`(RP_ZU@`'R0_VR0_VR0_VR0_V=Z2L" + "@IG7TO,`U_8`S_$`S_$`U_4`R^X`R^X`T_,`S>\\`S>\\`Q^P`Q>L`Q>L`U/0`Q>L`" + "P>D`N^4`N^4`S.``N^4`N^4`L-X`L-X`N>(`L-X`152!^0`&^0`&^0`&^0`*^@`'" + "]``\"]``!]``!]``'^0`\"]@_^]@_Z]@_Z]``+^0`&\\`_Q\\`_Q]P`#]0_Z\\@_G]@_Z" + "\\@_GI[#\":5J+`\\S]`]P,`\\S]`\\S]`\\S]`]L+`\\CY`\\CY`]<'`\\CY`\\CY`]@(`\\/T" + "`]<'`\\/T`\\/T`],#`\\S]`[[O`[SM`\\_``K_P;V\"98E*F[K$^\\+(`\\+(`\\+(`\\+(`" + "\\+(`\\KT`\\+4`\\\\8`\\+,`\\+,`\\+,`]<@`\\+,`\\+4`\\\\8`\\+0`],$`\\*``P9X()2M;" + "EX>/CWZ#FJ;7````````````````````````````````````````````````````" + "^`@X'U/0_UO4`S_$`S_$`S_$`U?,`R^X`T?(`T/$`" + "R^X`U?,`Q>L`Q>L`S>``QNP`R^T`N^4`N^4`O>8`P.D`N^4`L]``L-X`ON<`L-X`" + "L-X`0U6\"^0`&^0`&^P`0^0`&^0`&^0`+]``!]``!^0`(]``!^0`,]@_Z]@_Z^0`)" + "]@_Z]0_Y\\`_Q]P`!\\`_Q]P_]\\@_H\\P_Q\\@_G8F.+NI;'`\\[_`\\[_`\\S]`\\S]`\\S]" + "`]P,`\\CY`]$!`\\K[`\\CY`\\CY`]@(`\\/T`]4%`\\/T`\\/T`](\"`\\W^`[[O`[SM`\\;W" + "`\\K[=F.=8E\"F[[$_\\+(`\\+(`\\+(`\\+(`]<@`\\+(`\\+,`\\\\@`\\+,`\\+,`\\+,`],@`" + "\\+,`\\+,`\\\\@`\\;4`]+``\\*``W*LH0T1U,#-6D9W.````````````````````````" + "````````````````````````````X.T=C(N\\`[?H`[?H`\\7V`ZO<`*G:64AYN;34" + "`_H(`_D%`_D&`_\\3`_L*`_@%`_+Y`_+Y`_+Y`_+Y`_+Y`_+Y`_H)`_H+`_X2`_@%" + "`_+X`_+X`_+X`_+X`_+X`_+X`_+X`_+X`_+X`_+XH9NR;GNL`QNL`S>\\`Q>L`S^\\`N^4`N^4`" + "R^X`N^4`ON<`L-X`L-X`P^H`L-X`L-X`0E.#^0`&^0`&^P`4^0`&^0`&^@`1]``!" + "]``!^@`,]``!]``+]@_Z]@_Z]``%]@_Z]P`'\\`_Q\\`_S\\`_T]0_V\\@_M]@_\\\\@_G" + "YP'G/CYM]<+S`]H*`\\S]`\\S]`\\S]`\\S]`]@(`\\CY`]H*`\\CY`\\CY`\\CY`]<'`\\;W" + "`\\[_`\\/T`\\/T`\\K[`](\"`\\#Q`[SM`[[O`\\_`R\\+(`\\+(`\\+(`\\+(`],8`" + "\\+(`\\+(`\\+(`],D`\\+,`\\+,`\\;L`\\KD`\\+,`\\+,`\\\\4`\\KD`\\[``\\*``[+$\\%QY2" + "7&B9_`P\\````````````````````````````````````````````````PNY#+TO(`S_$`S_$`S_$`T/$`T?(`R^X`U_0`R^X`R^X`TO(`Q>L`" + "Q>L`U/0`Q>L`Q>L`SN\\`N^4`O><`PN@`N^4`Q.L`L-X`L-X`NN(`L-X`L-X`05.$" + "^0`&^0`&^@`*^0`&^0`&^``2]``!]``!^P`/]``!]``!]`_`]@_Z]@_^]@_Z]P_[" + "]@_X\\`_Q]``\"\\`_Q]P_`\\@_J\\P_N\\@_GK\\#&:UR-`]L+`\\S]`\\S]`\\S]`\\S]`\\W^" + "`]<'`\\GZ`]$!`\\CY`\\CY`\\CY`]8&`\\K[`\\O\\`\\/T`\\/T`\\7V`]0$`\\#Q`[SM`[SM" + "`LK[9%:4?6/$\\+(`\\+(`\\+(`\\;@`\\+0`\\+(`\\+(`\\+(`\\\\D`\\+,`\\+,`\\\\<`\\+,`" + "\\+,`\\+,`\\[T`\\[``\\K\\`\\*``SYH<GW@`/V0`*VP`+XP`7V@`,V@`,W@`1X@`6" + "V``/W@`2U@`'U@`'U@`'U@`'U@`'V@`,W0`3VP`.V``.V0`+TP`#T0`!T0`!T0`!" + "V``.S`_^R0_VR0_VR0_VR0_VR0_VR0_VN?SI0E6#SNX\\S_$`S_$`S_$`S_$`VO<`" + "R^X`V/8`R^X`R^X`R^X`UO4`Q>L`SN``QNL`Q>L`Q>L`PN@`N^4`S>X`N^4`N^4`" + "QNP`L-X`ON8`L-X`L-X`L-X`0%*%^0`&^@`0^0`&^0`&^0`&^0`,]``!]``!^@`/" + "]``!]``!]``,]@_Z]@_Z]0_]]@_Z]``&\\`_Q]P`$\\`_Q\\`_Q]0_X]P_^\\@_G\\@_G" + "7V:)OY_0`\\W^`\\S]`\\S]`\\S]`\\S]`\\[_`]0$`]<'`\\CY`\\CY`\\CY`\\CY`]4%`](\"" + "`\\;W`\\/T`\\/T`\\/T`]8&`\\+S`[SM`\\?X`,'R4$>%DW';\\+(`\\+(`\\+(`\\\\(`\\+(`" + "\\+(`\\+(`\\+(`]<@`\\+0`\\+,`],<`\\+,`\\+,`\\+,`\\+<`\\\\8`\\KH`\\*``ZJPZ55Z4" + "UN,3````````````````````````````````````````````LK[ON8R]`[?H`\\3U" + "I7.D:6>0`OH(`_P/`_P-`_D%`_D%`_H*`_+Y`_+Y`_+Y`_+Y`_+Y`_<#`_@&`_+Y" + "`_<\"`^KD`^KD`^KD`^KD`^KD`^KD`^KD`^KD`^KD`^KD`^_QL:S#9X&?V0`*V0`*" + "VP`,WP`2V@`,V@`.X``8VP`-V``0W0`/U@`'U@`'U@`'U@`'UP`(X0`4VP`.R`_Z" + "R`_ZR`_ZR`_ZR`_[T@`\"V@`+V``/TP`#TP`#TP`\"TP`\"T0_`S`_`T0_^S@_[57\"1" + "KLD,S_$`S_$`S_$`S_$`T/(`T.``V/<`R^X`R^X`R^X`S.X`RNT`QNL`SN\\`Q>L`" + "Q>L`R>X`N^4`O><`PN@`N^4`N^4`RNX`L-X`Q.L`L-X`L-X`L-X`05.&]`\\%^P`5" + "^0`&^0`&^0`&^0`&]``$]``!^@`/]``!]``!^0`*]@_Z]@_Z]P`#]@_Z]@_\\]0_W" + "]0_Y\\`_Q\\`_Q\\`_Z\\P_P\\@_I\\@_GW_K>/#UK^M(\"`\\S]`\\S]`\\S]`\\S]`\\S]`\\[_" + "`],#`]D)`\\CY`\\CY`\\CY`\\CY`]0$`]8&`\\/T`\\/T`\\/T`\\/T`]0$`\\/T`\\O\\`ZS=" + "^;SM.C=UKX7Z\\+(`\\+(`],@`\\+(`\\+(`\\+(`\\+(`\\+(`],8`\\+8`\\+L`\\;@`\\+,`" + "\\+,`\\+,`\\+,`]L`U/0`Q>L`Q>L`Q>L`T/$`N^4`R^``N^4`N^4`N^4`R>X`L-X`" + "N>,`L-X`L-X`L-X`15:-\\@D!^@`,^0`&^0`&^0`&^0`&^@`-]``!^@`/]``!]``!" + "]``!]P`#]@_Z]``(]@_Z]@_Z]``'\\`_Q]0_]\\`_Q\\`_Q]P_^]@_Z\\@_G\\@_GE*BM" + "@WBG`\\S]`\\S]`\\S]`\\S]`\\S]`\\S]`](\"`]4%`\\O\\`\\CY`\\CY`\\CY`\\CY`]$!`]@(" + "`\\/T`\\/T`\\/T`\\/T`\\[_`\\_``ZK;`[GJZK'B+\"YJR9<6\\+(`],,`\\+(`\\+(`\\+(`" + "\\+(`\\+(`\\+(`\\L,`\\;@`]86:5>(ZJO<0#YN]?,(`_T-" + "`_D%`_D%`_D%`_T0`_+Y`_+Y`_+Y`_+Z`_H+`_/]`_+Y`_+Y`_/_`^OH`^KD`^KD" + "`^KD`^KD`^KD`^KD`^KD`^KD`^SK`_+ZY=+335E\\V@@/V0`*W``2W0`0W``2X0`5" + "V@`,V@`,V``/W@`/U@`'U@`'U@`'VP`+W``2U@`'V``/R`_ZR`_ZR`_ZR`_ZR`_Z" + "R`_ZU``*S`__RP_WO@_HO@_HO@_HO@_HO@_HO@_HR0_VOP?L.T][P^4TS.\\`U_4`" + "T/$`S_$`T_,`V/8`S.X`R^X`R^X`R^X`R^X`T?,`S_$`Q>L`Q>L`Q>L`Q>L`S>``" + "O><`PN@`N^4`N^4`N^4`R>T`O.4`L-X`L-X`L-X`L-X`1UR2[@,&^0`&^0`&^0`&" + "^0`&^0`&^P`2]``!^@`/]``!]``!]``!^@`-]@_Z]``+]@_Z]@_Z]0_\\\\`_U]``$" + "\\`_Q\\`_Q\\`_T\\`_X\\@_G\\@_G[`WF/TMPXK3E`\\S]`\\S]`\\S]`\\S]`\\S]`\\S]`]4%" + "`]H*`\\CY`\\CY`\\CY`\\CY`\\CY`\\[_`]8&`\\/T`\\/T`\\/T`\\[_`\\W^`[+C`ZK;`\\7V" + "T9_3+B]LW:4L\\+,`\\+8`\\+(`\\+(`\\+(`\\+(`\\+(`\\+(`\\;\\`\\;L`],(`\\+,`\\+,`" + "\\+,`\\+,`\\+,`\\\\(`\\+D`X9(X6626W^P<````````````````````````````````" + "````\\?XN76>85T5UR\\GG`_D&`_D%`_D%`_D%`_T1`_+Y`_+Y`_+Y`_D'`_8#`_+Y" + "`_+Y`_+Y`_/\\`^[N`^KD`^KD`^KD`^KD`^KD`^KD`^KD`^OG`_'Z`^KH^>'>35-T" + "O_3RV@`+W``3WP`3XP`8V@`,V@`,V@`,V``/W0`/U@`'U@`'U@`'X0`4UP`*U@`'" + "V@`.S0_\\R`_ZR`_ZR`_ZR`_ZT0__U``(R`_ZTP`!O@_HO@_HO@_HO@_HO@_HO@_H" + "SP_\\OP_K9Y6X`R^X`R^X`R^X`R^X`T.``" + "Q^P`S>\\`Q>L`Q>L`Q>L`Q>L`Q.L`S>X`N^4`N^4`N^4`N^4`QNL`Q.D`L-X`L-X`" + "L-X`L-X`25V8Z?X&^0`&^0`&^0`&^0`&^0`&^0`0]``!^P`/]``!]``!]``!]``%" + "]@_Z]``+]@_Z]@_Z]@_Z]``']@_]\\`_Q\\`_Q\\`_Q]@_^]@_V\\@_G\\@_GP-C%55>!" + "`]P,`]H*`]8&`](\"`\\S]`\\S]`\\S]`]H*`]0$`\\CY`\\CY`\\CY`\\CY`\\CY`\\S]`]8&" + "`\\O\\`\\?X`[7F`[7F`\\S]`Z[?`ZS=`[GJK8>[/CE_ZJXY],4`\\+(`\\+(`\\+(`\\+(`" + "\\+(`\\+(`\\+(`\\KP`\\L4`\\+<`\\+,`\\+,`\\+,`\\;D`\\KT`\\[<`Z9$`L(C[9'\"A_PL[" + "`````````````````````````````````P\\_,S]P5E>!`_D%`_D%`_D%`_D%`_P0" + "`_+Y`_+Y`_8\"`_@&`_+Y`_+Y`_+Y`_+Y`_+Z`_#V`^KD`^KD`^KD`^KD`^KD`^KD" + "`^KE`_+Z`^SL`^KD`^KD9&)_J]7;WP`2XP`6Y0`9V``/V@`,V@`,V@`,V``/W0`/" + "U@`'U@`'W0`/W@`/U@`'U@`'V@`,SP_^R`_ZR`_ZR`_ZR`_ZU``*SP_^R`_ZT@`!" + "O@_HO@_HO@_HO@_HO@_HP0_KS@_]O@_HJ?/62%Z,S.\\`S.\\`S.\\`S.\\`S.\\`VO<`" + "T?$`R^X`R^X`R^X`R^X`R^X`U?0`U/0`Q>L`Q>L`Q>L`Q>L`R.X`O.8`PNH`N^4`" + "N^4`N^4`N^4`P.@`NN0`L-X`L-X`L-X`L-X`2E^;X_CZ^0`&^0`&^0`&^0`&^0`&" + "^@`)]``!^@`+]``!]``!]``!]``!^0`'^0`*]@_Z]@_Z]@_Z]@_\\]0_W]@_W\\`_Q" + "\\`_Q\\`_Q]P_`\\@_G\\@_G]@_W7VR%QI?(`\\'R`\\'R`\\'R`\\?X`]$!`]<'`]H*`]X." + "`]0$`]<'`]8&`]4%`],#`\\_``\\_``[_P`[7F`[7F`[7F`\\CY`\\CY`ZK;`[CI`['B" + "@6F>54F7\\\\@_\\+(`\\+(`\\+(`\\+(`\\+(`\\+(`\\+(`\\+(`\\;H`],P`\\+,`\\+8`\\[``" + "[)P`ZY4`\\*``[ZP`[)\\`>H\"YO,CY````````````````````````````````````" + "/TM\\GINV`_D%`_D%`_D%`_P/`_+[`_/]`_H*`_+Z`_+Y`_+Y`_+Y`_+Y`_+Y`_3]" + "`^KD`^KD`^KD`^KD`^KD`^KD`_+Y`^[O`^KD`^KD`^KDI)FG@).KS@_\\Y@`:WP`2" + "V@`,V@`,V@`,V@`,V``.W0`/U@`'V0`+W``4U@`'U@`'U@`'UP`*T@`#R`_ZR`_Z" + "R`_ZSP_^V0`)R`_ZR`_ZSP_]PP_PO@_HO@_HO@_HO@_HQP_UQ`_SO@_HO@_H2FR$" + "K\\X8S.\\`S.\\`S.\\`S.\\`U/0`U_4`U?0`T?(`R^X`R^X`R^X`R^X`TO,`Q>L`Q>L`" + "Q>L`Q>L`Q>L`SN``S>``N^4`N^4`N^4`N^4`N^4`Q>H`L-X`L-X`L-X`L-X`L-X`" + "3F.?W_;T^0`&^0`&^0`&^0`&^0`&^0`&^0`&^0`)]``!]``!]``!]``!^@`-^0`$" + "]@_Z]@_Z]@_Z]@_Z]``']P`\"\\`_Q\\`_Q\\`_Q]@_Y\\`_T\\@_G\\0_CV?/7/SUK`<#Q" + "`\\'R`\\'R`\\'R`\\'R`\\'R`\\'R`\\_``](\"`[WN`[WN`[WN`[WN`[WN`[WN`\\[_`[?H" + "`[7F`[7F`[7F`\\+S`\\GZ`ZK;`\\3U`K#A5DM`>V>`\\+(`\\+(`\\+(`\\+(`\\+(`\\+(`" + "\\+(`\\+(`\\+4`\\[\\`\\\\<`[J0`ZY4`ZY4`ZY4`[J@`[J8`Z9,`UYXE4%N-\\_`P````" + "````````````````````````^@8V86R<\\-W?`_P)`_D%`_P-`_/^`_H+`_/]`_+Y" + "`_+Y`_+Y`_+Y`_+Y`_+Y`_T`RNT`" + "UO4`S^\\`R^X`T_,`S>\\`Q>L`Q>L`Q>L`Q>L`Q>L`S_(`PNH`N^4`N^4`N^4`N^4`" + "N^4`QNH`L-X`L-X`LM\\`P.<`L-\\`3V6?W//Q^@`2^@`*^0`&^0`&^0`&^0`&^P`/" + "^0`&]``!]``!]``!]``!]``$]P_^]@_Z]@_Z]@_Z]@_Z]@_^]P`#\\`_Q\\`_Q\\`_Q" + "\\`_Q]P`#]@_U[@_0[`_;>(65IX&R`\\'R`\\'R`\\'R`\\'R`\\'R`\\'R`]0$`\\;W`\\/T" + "`[WN`[WN`[WN`[WN`[WN`\\[_`\\S]`[7F`[7F`[7F`\\GZ`[7F`\\/T`ZO<`[KK^*_@" + "-3-IGW_F\\KD`\\KX`\\KT`\\+H`\\;4`[Z<`ZYH`ZY<`ZY<`\\K@`ZY4`ZY4`ZY4`ZY4`" + "ZYD`ZY4`[[$`[JH`@FK(GZO<````````````````````````````P\\_`K*B``^WK" + "`_L.`_L+`_H+`_8#`_+Y`_+Y`_+Y`_+Y`_+Y`_+Y`_+Y`_7``^KE`^KD`^KD`^KD" + "`^_R`_'V`^KD`^KD`^KD`^KD`^KD_N;A2TYPP?;QV``-U0`&WP`4V@`,V@`,V@`," + "V``.V``0W0`-W0`0U@`'U@`'U@`'U@`'U@`&V@`+R`_ZR`_ZSP_^V0`)R`_ZR`_Z" + "R`_ZR`_ZT``\"O@_HO@_HO@_HOP_JS@_]O@_HO@_HO@_HN`SF.5%VP.$QS.\\`S.\\`" + "S.\\`VO<`S.\\`V/8`R>T`R>T`R>T`R>T`SN``UO4`U_4`Q>L`Q>L`Q>L`Q>L`Q>L`" + "Q>L`T/$`N^4`N^4`N^4`N^4`N^4`ON@`O.0`O.4`O>8`H]8`G=,`I-<`5&J>VO'J" + "]P_`]P`#^0`0^@`0^0`&^0`&^P`2]``\"]``!]``!]``!]``!]``!^0`)]@_^]@_Z" + "]@_Z]@_Z]@_Z]``&]0_R\\`_Q\\`_Q\\`_Q]0_V\\P_O[@_0[@_0XO_3.3EH_;WN`\\'R" + "`\\'R`\\'R`\\'R`\\'R`]4%`\\'R`](\"`[WN`[WN`[WN`[WN`[WN`],#`[WN`\\GZ`[7F" + "`[7F`[;G`[[O`[?H`[KK`[GJ`ZS=YJ;7)2==M'<#ZY<`ZY<`ZY<`ZY<`ZY<`ZY<`" + "ZY<`ZYL`[)@`[ZL`ZY4`ZY4`ZY4`ZY4`[I\\`[I\\`ZI8`Y9TX6F67Y_0D````````" + "`````````````@X^?XN\\_^KI`^WK`_3^`_L+`_+Y`_+Y`_+Y`_+Y`_+Y`_+Y`_+Y" + "`_+Y`_3\\`^SH`^KD`^KD`^[M`_/Y`^KD`^KD`^KD`^KD`^KD`^KD`^KD@WV2F+;&" + "U``*VP`.TP`#U@`'VP`-V@`,W0`.W0`1X@`5U@`(U@`'U@`'U@`'U@`'U@`'VP`." + "R`_ZR`_ZUP`(S`_`R`_ZR`_ZR`_ZR`_ZS``!OP_JO@_HO@_HQ0_RR0_VO@_HO@_H" + "O@_HO@_HT`R>T`R>T`R>T`R>T`" + "V/4`PND`RN\\`T?(`T_,`T?(`R>X`RNX`Q.H`N^4`O>4`P^H`QNP`RNX`S>\\`LN$`" + "G=,`G=,`G=,`G=,`M>$`5FN?V._H]P_`]P_`]P_`]P_`^0`+^@`2^P`1]``!]``!" + "]``!]``!]``!]``!^0`,]``$]@_Z]@_Z]@_Z]@_Z]P_^]``!\\`_Q\\`_Q]P_`]0_Q" + "\\`_R[@_0[@_0\\@_IB92BF'>H`\\'R`\\'R`\\'R`\\'R`\\'R`](\"`\\'R`\\'R`\\S]`[WN" + "`[WN`[WN`[WN`\\[_`[WN`\\'R`[_P`[7F`[7F`\\O\\`[7F`[[O`[/D`\\3U`ZK;TYW." + "(\")T`R>T`R>T`R>T`R>T`U_4`U?0`P.@`P.@`P.@`P.@`P.@`P>@`T/(`N^0`" + "L]``L-X`L-X`L-X`L-X`P^@`G=,`G=,`G=,`G=,`G]0`IM<`5VR>U^[G]P_`]P_`" + "]P_`]P_`]P_`]P_`^@`0^@`.^@`.^@`)]``!]``!]``!]P`#^0`+]@_Z]@_Z]@_Z" + "]@_Z]@_Z^0`*]@_\\]@_Y\\0_B\\0_B]0_X[@_1[@_0\\`_JX`/.-S9F^[OL`\\'R`\\'R" + "`\\'R`\\'R`\\O\\`\\'R`\\'R`\\GZ`[_P`[WN`[WN`[WN`\\7V`[WN`[WN`\\GZ`[;G`[7F" + "`[CI`[GJ`[7F`\\/T`Z[?`[KK`ZK;M8N_)\"1CUXLJZY<`ZY<`ZY<`ZY<`ZY<`\\+0`" + "ZY<`ZY<`[J@`ZY4`ZY4`ZY4`\\+$`ZY4`[9P`ZY\\`YY8]8&N=W^P<````````````" + "````FZ?8X-?I`^WK`_3_`^_Q`^?<`^?<`^_P`_/^`_+Y`_+Y`_+Y`_+Y`_'X`^OH" + "`_/Y`^KG`^KD`^KD`^KD`^KD`^KD`^KD`^KD`^KD_N;A14IOQOGWVP`)U0`%TP`#" + "TP`#TP`#W0`/W``6U@`'U@`'U@`'U@`'U@`'U@`'U@`'V@`-R`_ZU0`'T0`!R`_Z" + "R`_ZR`_ZR`_ZR`_ZR`_ZS`_`O@_HO@_ISP_\\O@_HO@_HO@_HO@_HO@_HO@_H9I>;" + "E['TS.\\`TO,`U/,`S.\\`S.\\`S.\\`S^\\`R>T`R>T`R>T`R>T`U?0`R>T`SN``P.@`" + "P.@`P.@`P.@`P.@`SN``R.L`L-X`L-X`L-X`L-X`L-X`Q.D`N^8`G=,`G=,`G=,`" + "G=,`L^$`G=,`5VR>U^[G]P_`]P_`]P_`]P_`]P_`]P`\"]P`(]@_\\]@_[]@_[]@__" + "]``*^P`0^P`,^@`0]``$]``'^0`(]``*]P`']P`'\\0_E\\0_B\\0_B\\0_B]@_Y\\@_J" + "[@_0\\@_A[@_0BH^EEG6F`\\'R`\\'R`\\'R`\\'R`\\/T`\\'R`\\'R`\\'R`]0$`[WN`[WN" + "`[WN`[WN`\\/T`[WN`[WN`\\W^`[7F`[7F`\\O\\`[7F`[7F`\\CY`[?H`ZW>`ZK;@VF@" + "0#.$Z)4]ZY<`ZY<`ZY<`ZY<`\\+(`ZY<`ZY<`\\;(`ZY4`ZY4`ZY4`\\+(`ZY4`ZY4`" + "\\;,`\\*``F6OD@(R]````````````^PT`R>T`" + "R>T`R>T`U?0`RNT`S>``P>@`P.@`P.@`P.@`P.@`QNL`Q>L`ON8`L-X`L-X`L-X`" + "L-X`M-``M>$`N>0`G=,`G=,`G=,`G=,`K-L`G=,`5FNT`R>T`R>T`T_0`R^X`R>T`U?0`P.@`P.@`P.@`P.@`" + "P>@`S.X`PN@`L=X`L-X`L-X`L-X`L-X`Q>L`L-X`M.$`G=,`G=,`G=,`K]X`G=,`" + "G=,`56>7VO+J]P_`]P_`]P_`]P_`]P`']P`\"]P_`]P`(]@_[]@_[]@_[]@_[]@_[" + "]P_`]P`\"\\`_Q\\`_Q\\`_Q\\`_Q\\`_Q]P`%]``!\\0_B\\0_B\\0_B]0_Y\\0_B\\0_;[@_0" + "\\P_G[@_0?X*=HGZO`\\'R`\\'R`]$!`\\'R`\\'R`\\'R`\\'R`\\'R`\\_``[WN`[WN`[WN" + "`],#`[WN`[WN`[WN`\\'R`[[O`[7F`\\GZ`[7F`[7F`[7F`\\/T`[KK`ZK;V)'\"$AI." + "T8@CZY<`ZY<`[)L`ZY<`ZY<`ZY<`ZY<`\\;(`ZY4`ZY4`[:8`ZY4`ZY4`ZY4`[[$`" + "[ZP`D&'=@HZ_````````GZOT`R>T`R>T`TO,`RN\\`" + "R>T`R>T`S>``P.@`P.@`P.@`P.@`T?$`P.@`R>P`L-X`L-X`L-X`L-X`O.0`L-X`" + "L-X`K=T`G=,`G=,`G=,`L]``G=,`G=,`4V64W?7M]P_`]P_`]P_`]P_`^@`+]P_`" + "]P_`^0`*]@_[]@_[]@_[]@_[]@_[^0`,]@_[]0_V\\`_Q\\`_Q\\`_Q\\`_Q]P`#]@_\\" + "\\0_B\\0_B\\0_B\\`_W\\0_B\\`_Q[@_0\\@_K[@_0W/C0.C9G`\\'R`\\'R`]0$`\\'R`\\'R" + "`\\'R`\\'R`\\'R`\\'R`\\_``[WN`[WN`\\_``[WN`[WN`[WN`[WN`\\K[`[;G`\\+S`[7F" + "`[7F`[7F`[?H`\\'R`ZO<`ZK;;U6'8$>FZY<`ZY<`\\*P`ZY<`ZY<`ZY<`ZY<`ZY@`" + "[J4`ZY4`ZYH`ZY4`ZY4`ZY4`ZY8`\\+(`XHTX.T9YZO86V`^_R`_#Q`^[N" + "`^C?`^?<`^?<`^?<`^?<`^?=`_'S`^G@`]_)`]_(`]_(`]_(`]_(`]_)`^C<`^WJ" + "`^[N`^KE`^KD`^KDI)JJ?IJPSP__U``)TP`#TP`#W@`0TP`#W0`.S@_\\S@_\\S@_\\" + "S@_\\S@_\\S@_\\T@`\"U0`&TP`\"U@`&U@`&T0`!R`_ZR`_ZR`_ZR`_ZR`_ZT``$R`_Z" + "O@_HO@_HO@_HO@_HO@_HO@_HO@_HO@_HO@_H7H*8J<0%S.\\`S.\\`S.\\`S.\\`S.\\`" + "S.\\`U/0`R>T`R>T`T_$`S.X`R>T`R>T`T/$`P.@`P.@`P.@`P.@`S>``P.@`P.@`" + "R>P`L-X`L-X`L-X`L-X`O>8`L-X`L-X`I-8`G=,`G=,`J=H`G=,`G=,`G=,`3V./" + "X?GP]P_`]P_`]P_`^@`/]P_`]P_`]P_`]``,]@_[]@_[]@_[]@_[]@_[]``)]@_[" + "]``!\\`_Q\\`_Q\\`_Q\\`_Q]P`\"\\`_Q\\`_O\\0_B\\0_B\\`_V\\0_B\\@_I[@_1\\0_D[@_0" + "[@_08F2'PY7&`\\'R`]8&`\\'R`\\'R`\\'R`\\'R`\\'R`\\'R`\\;W`\\'R`[WN`\\;W`[WN" + "`[WN`[WN`[WN`[WN`\\W^`[7F`\\?X`[7F`[7F`[7F`[[O`\\;W`ZK;Z*#1#A=+SX#B1%!URPOYW0`1TP`#TP`#" + "W@`1TP`#VP`.S@_\\S@_\\S@_\\S@_\\S@_\\S@_\\UP`'V@`,O@_HO@_HO@_HO@_HO@_H" + "P`_NSP_]U@`&U@`'TP`\"RP_XQ0_PQ@_RQ@_RQ@_SQ0_RQP_SQ@_SQ@_PQ0_RM/KD" + "05>#S.\\`S.\\`S.\\`S.\\`S.\\`S.\\`TO(`R>T`R>T`T/$`S>X`R>T`R>T`R>T`UO4`" + "P.@`P.@`P.@`R.X`P>@`P.@`P.@`P>D`L-X`L-X`L-X`P^H`L-X`L-X`L]``G=,`" + "G=,`G=,`MN(`G=,`G=,`G=,`3%V+YO[S]P_`]P_`]``%]P`$]P_`]P_`]P_`^@`." + "]@_[]@_[]@_[]@_[]@__]@_\\]@_[]``'\\`_Q\\`_Q\\`_Q\\`_Q]@__\\`_Q]P__\\0_B" + "\\0_B\\`_Q\\0_B\\0_B\\@_I[@_3[@_2[@_0O]6`64M\\`\\'R`](\"`\\'R`\\'R`\\'R`\\'R" + "`\\'R`\\'R`\\'R`](\"`[WN`[WN`\\+S`[WN`[WN`[WN`[WN`[[O`\\;W`\\7V`[7F`[7F" + "`[7F`[7F`\\+S`[SM`[/D9TV'9$BKZY<`\\;(`ZY<`ZY<`ZY<`ZY<`ZY<`ZYD`[9``" + "ZY4`[JP`ZY4`ZY4`ZY4`ZY4`[[8`E6;CE*#1W>H:@8*F`^WK`^WK`_'T`^?<`^?<" + "`^?<`^OD`^OJ`^?<`^?<`^KD`]_(`]_(`]_(`]_(`]_(`]_(`]_(`]_(`]_(`]_(" + "`^77=7&(FT`" + "SN``S>``R>T`R>T`R>T`R>T`RNT`P.@`P.@`PND`RNT`P.@`P.@`P>@`LM\\`L-X`" + "L-X`M-``MN(`L-X`L-X`NN,`G=,`G=,`H]8`H=4`G=,`G=,`G=,`1E:$[@7Y]P_`" + "]P_`^@`.]P_`]P_`]P_`]P_`^0`+]@_[]@_[]@_[]@_[^0`+]@_[]@_[]``&\\`_Q" + "\\`_Q\\`_Q\\`_Q]0_Y\\`_Q]@_]\\0_B\\0_B\\`_M\\0_B\\0_B\\`_O[@_0\\0_C[@_0[@_0" + "-SMF[[/D`\\K[`\\'R`\\'R`\\'R`\\'R`\\'R`\\'R`\\'R`\\'R`\\O\\`[WN`\\W^`[WN`[WN" + "`[WN`[WN`[WN`\\3U`[OL`\\/T`[7F`[7F`[7F`[7F`\\GZ`[?HWH&R#19+UHLI[J8`" + "ZY<`ZY<`ZY<`ZY<`ZY<`ZY<`\\+0`ZY4`\\+$`ZY4`ZY4`ZY4`ZY4`[ZL`C6;7F*35" + "R]@(G9>L`^WK`^WL`^GB`^?<`^?<`^SI`^OF`^?<`^?<`^C@`^#,`]_(`]_(`]_(" + "`]_(`]_(`]_(`]_(`]_(`]_(`^KD[=\"`1DUOTP`!U0`&U0`&VP`-TP`#TP`#V``." + "S@_\\S@_\\S@_\\S@_\\S@_]V@`,S@_\\UP`)O@_HO@_HO@_HO@_HO@_HO@_HO@_HO@_H" + "SP_]Q0_RJ0_/J0_/J0_/J0_/J0_/J0_/J0_/J0_/J0_/L`_\\`S.\\`S.\\`S.\\`T/,`RNT`S^``SN\\`R>T`R>T`R>T`R>T`T?(`P.@`P.@`P.@`" + "S_$`P.@`P.@`P.@`QNT`L-X`L-X`L-X`Q>H`L-X`L-X`L-X`N^4`G=,`G=,`MN(`" + "G=,`G=,`G=,`G=,`/T]\\\\`S^]P_`]``-]P_`]P_`]P_`]P_`]P_`^0`*]@_[]@_[" + "]@_[]@_[]``)]@_[]@_[]@_]\\`_Q\\`_Q\\`_Q\\`_Q\\`_R\\`_Q\\`_Q\\@_L\\0_B\\P_H" + "\\0_B\\0_B\\0_B\\0_;\\`_K[@_0[@_0AI>=EW>H`\\+S`\\'R`\\'R`\\'R`\\'R`\\'R`\\'R" + "`\\'R`\\'R`\\O\\`[[O`](\"`[WN`[WN`[WN`[WN`[WN`[WN`\\O\\`\\K[`[7F`[7F`[7F" + "`[7F`[7F`\\?X`XFZ5$:&=52\\ZY<`ZY<`ZY<`ZY<`ZY<`ZY<`ZY<`ZYL`[)\\`\\+(`" + "ZY4`ZY4`ZY4`ZY4`ZY4`<%ZVK+CIP\\_`JJ6[`^WK`_'X`^?<`^?<`^_N`^KB`^?<" + "`^?<`^?<`^[K`]_(`]_(`]_(`]_(`]_(`]_(`]_(`]_(`^37`^;=`]_(BWV(E+:_" + "V``0UP`)V0`,TP`#TP`#VP`,S@_\\S@_\\S@_\\S@_\\T0_`U``*S@_\\T@`\"P@_MO@_H" + "O@_HO@_HO@_HO@_HO@_HP0_KR`_ZO@_HM`_BJ0_/J0_/J0_/J0_/J0_/J0_/J0_/" + "J0_/MP_?K`_87IJ1A:'KON8`ON8`SN\\`S.\\`S.\\`S.\\`V/4`S^``T/(`R>T`R>T`" + "R>T`R>T`R>T`U?0`P.@`P.@`T/(`P.@`P.@`P.@`P.@`R>T`L-X`L-X`O.0`L=X`" + "L-X`L-X`L-X`O.4`G=,`GM,`I]@`G=,`G=,`G=,`G=,`/4QX]P_`]P`\"]``']P_`" + "]P_`]P_`]P_`]P_`]``%]@_[]@_[]@_[]@__]@_\\]@_[]@_[]@_[]P_[\\`_Q\\`_Q" + "]0_W\\`_Q\\`_Q\\`_Q]P_^\\0_B\\0_B\\0_C\\0_B\\0_B\\`_Q\\0_G[@_0[@_0TO*`0$!N" + "`\\'R`\\'R`\\'R`\\'R`\\'R`\\'R`\\'R`\\'R`\\'R`\\'R`],#`]$!`[WN`[WN`[WN`[WN" + "`[WN`[WN`[WN`\\W^`[[O`[7F`[7F`[7F`[_P`[#A`Y+#QH>\\%1M3XY(WZY<`ZY<`" + "ZY<`ZY<`ZY<`ZY<`ZY<`\\;4`\\*\\`ZY4`ZY4`ZY4`ZY4`ZY4`5D>8P,S]P`^?<`^?<`^?<`^?<`^KF`]_(`]_(`]_(`]_(`]_(`]_(" + "`]_(`^KD`^#,`]_(`]_(/$%DUPD)V@`-U``)TP`#TP`#T``$T``$S@_\\S@_\\S@_\\" + "U0`%T``%S@_\\S@_\\T``#O@_HO@_HO@_HO@_HO@_HO@_HP`_OR@_WO@_HQ@_SJ0_/" + "J0_/J0_/J0_/J0_/J0_/J0_/J0_/NP_FJ`_3I@O--$YTO>0^ON8`ON8`ON8`U/0`" + "S.\\`SN``S^``T?(`R>T`R>T`R>T`R>T`R>T`R>T`Q^T`P.@`RN\\`P>D`P.@`P.@`" + "P.@`P.@`P^H`L-X`L-X`ON<`L-X`L-X`L-X`L-X`N.0`G=,`L]``G=,`G=,`G=,`" + "G=,`G=,`/4QX]P_`^P`0]P_`]P_`]P_`]P_`]P_`]P_`]P`!]@_[]@_[]@_[^0`+" + "]@_[]@_[]@_[]@_[]P`$\\`_Q\\`_Q]0_]\\`_Q\\`_Q\\`_Q]@_^\\0_B\\0_B\\0_G\\0_B" + "\\0_B\\@_H[P_8[@_0[@_0[@_0.4)IZ;OL`\\CY`\\'R`\\'R`\\'R`\\'R`\\'R`\\'R`\\'R" + "`\\'R`\\7V`\\W^`[WN`[WN`[WN`[WN`[WN`[WN`[WN`[[O`\\[_`[7F`[OL`[/D`YG*" + "`YS-`ZW>`YK+-S%LDF+>ZY<`ZY<`ZY<`ZY<`ZY<`ZY<`ZY<`[9X`\\*P`ZY4`ZY4`" + "ZY4`ZYX`[*(`0SB'RM<'Q-$!HIZV`^[L`^GD`_#T`^?<`^?<`^?<`^?<`^?<`^?=" + "`^+0`]_(`]_(`]_(`]_(`]_(`^77`^;=`]_(`]_(`]_(U;JP6VB'W0`/U0`$TP`#" + "TP`#TP`#W0`/S@_\\S@_\\S@_\\V@`)S`__S@_\\S@_\\UP`'O@_HO@_HO@_HO@_HO@_H" + "O@_HR0_VPP_PO@_HO@_HM@_>J0_/J0_/J0_/J0_/J0_/J0_/J0_/N`_GJ@_0J0_/" + ";;2<=9#,ON8`ON8`ON8`ON8`P.8`T?(`V/8`T_,`R>T`R>T`R>T`R>T`R>T`R>T`" + "T_,`P.@`Q.H`Q^P`P.@`P.@`P.@`P.@`P.@`MN$`L-X`PND`L-X`L-X`L-X`L-X`" + "L-X`L^$`G=,`K=P`G=,`G=,`G=,`G=,`G=,`.TIT]``(]P`\"]P_`]P_`]P_`]P_`" + "]P_`]P_`]P_`]P_`]@_[]@_[]``)]@_[]@_[]@_[]@_[^0`'\\`_Q\\`_Q]``!\\`_Q" + "\\`_Q\\`_Q\\`_R\\P_I\\0_B\\`_N\\0_B\\0_B\\0_B\\`_I\\0_?[@_0[@_0@(Z8G&R=`ZO<" + "`ZW>`[GJ`\\7V`\\S]`\\_``]$!`\\K[`\\+S`\\'R`](\"`\\'R`[WN`[WN`[WN`[WN`[WN" + "`[WN`\\#Q`\\W^`[[O`Z'2`YG*`YG*`YG*`ZS=`XFZJG&F+2AOZY<`ZY<`ZY<`ZY<`" + "ZY<`ZY<`ZY<`ZY<`\\;<`ZY4`ZY8`[ZL`Y'H`XFX`.C)[S]P,SML+CHVL`_/\\`^_R" + "`^?<`^?<`^?<`^?<`^?<`^?<`^[I`]_(`]_(`]_(`]_(`]_(`^KD`^#,`]_(`]_(" + "`]_(`]_(@'>'G\\+5TP`$TP`#TP`#TP`#V@`+S@_]S@_\\S@_\\VP`,S@_\\S@_\\S@_\\" + "S@_\\R`_ZO@_HO@_HO@_HO@_HO@_HS0_ZP0_KO@_HO@_HQ@_SJ0_/J0_/J0_/J0_/" + "J0_/J0_/J0_/O@_JJ0_/J0_/J0_/+TUJM=LSON8`ON8`ON8`ON8`ON8`S.\\`U?0`" + "R>T`R>T`R>T`R>T`R>T`R>T`R>T`T_,`P.@`S?$`P.@`P.@`P.@`P.@`P.@`QNL`" + "L-X`M-``M^(`L-X`L-X`L-X`L-X`L-X`J]P`K=P`G=,`G=,`G=,`G=,`G=,`G=,`" + ".$=R^0`,]P_`]P_`]P_`]P_`]P_`]P_`]P_`]P_`^0`&]@_[]@_`]@_\\]@_[]@_[" + "]@_[]@_[]P`#\\`_Q\\`_Q]P`$\\`_Q\\`_Q\\`_Q\\`_Q]@_]\\0_B\\`_Q\\0_B\\0_B\\0_B" + "\\`_O\\P_J[@_0[P_5O]ZQ44)Q`ZO<`ZO<`ZO<`ZO<`ZO<`ZO<`ZO<`ZO<`['B`[[O" + "`\\CY`\\W^`\\3U`\\'R`[OL`[7F`Z[?`Z;7`Z76`Z76`[?H`YG*`YG*`YG*`YG*`ZG:" + "`Z#1_*?8&1U4L'3_ZY<`ZY<`ZY<`ZY<`ZY<`ZY<`ZY<`[)\\`[ZX`Z(X`XFT`XFT`" + "YXL`,R]VTM\\/W.D9<7:<`^_L`^KB`^?<`^?<`^?<`^?<`^?<`^?<`^SH`]_(`]_(" + "`]_(`^76`^KB`]_(`]_(`]_(`]_(`]_(`]_(-3]ES0C]TP`#TP`#TP`#TP`#U0`&" + "S@_\\SP__VP`,S@_\\S@_\\S@_\\S@_\\UP`'O@_HO@_HO@_HO@_HO@_HSP_]O@_HO@_H" + "O@_HO@_HM@_@J0_/J0_/J0_/J0_/J0_/J0_/OP_KJ0_/J0_/J0_/@-&L6G6FON8`" + "ON8`ON8`ON8`ON8`P.8`T/$`Q>H`U/4`R>T`R>T`R>T`R>T`R>T`R>T`QNT`T/(`" + "P.@`P.@`P.@`P.@`P.@`P.@`RNT`L-X`Q>H`L-X`L-X`L-X`L-X`L-X`L-X`H-4`" + "M>$`G=,`G=,`G=,`G=,`G=,`G=,`-D9U]P_`]P_`]P_`]P_`]P_`]P_`]P_`]P_`" + "]P_`]``)]@_[^0`*]@_[]@_[]@_[]@_[]@_[]@_[\\`_U\\`_Q]``$\\`_Q\\`_Q\\`_Q" + "\\`_Q]@__\\0_B\\`_T\\0_B\\0_B\\0_B\\0_B\\`_P[@_0\\0_DZ0[&*2U8_:?8`ZO<`ZO<" + "`ZO<`ZO<`ZO<`ZO<`ZO<`ZO<`ZO<`\\#Q`\\#Q`Z76`Z76`Z76`Z76`Z76`Z76`Z76" + "`['B`[?H`YG*`YG*`YG*`YG*`Z_@`Z[?`Y_0?5J04CV7ZY<`ZYP`[J0`[:<`[:0`" + "[)D`Z(D`[)D`YG\\`XFT`XFT`XFT`ZH``,C%SU.$1[/DIBY;'`^GD`]S!`^KD`^?=" + "`^?<`^?<`^?<`^?<`^/3`]_(`]_(`^KD`^#,`]_(`]_(`]_(`]_(`]_(`]_(T+:M" + "4&R$TP`#TP`#TP`#TP`#W0`/S@_\\T@`!UP`&S@_\\S@_\\S@_\\S@_\\T@`!PP_NO@_H" + "O@_HO@_HP0_KS0_\\O@_HO@_HO@_HO@_HQ@_RJ0_/J0_/J0_/J0_/J0_/J`_2N`_G" + "J0_/J0_/J0_/J0_//69TJ,P>ON8`ON8`ON8`ON8`P><`R^X`S.``O>8`O>8`S>T`" + "T/$`R>T`R>T`R>T`T_(`S>\\`P.@`P.@`P.@`P.@`P.@`P.@`P.@`Q>H`O>8`L=X`" + "L-X`L-X`L-X`L-X`L-X`M>$`I]D`GM,`G=,`G=,`G=,`G]0`K]X`E,@S0E-X]P`$" + "]P`%]P_`]P_`]P_`]P_`]P_`]P_`]P_`^@`-]@_[]``)]@_[]@_[]@_[]@_[]@_[" + "]@_[]P_`\\`_Q]P`$\\`_Q\\`_Q\\`_Q\\`_Q\\`_T\\0_G\\`_V\\0_B\\0_B\\0_B\\0_B\\`_U" + "[@_0Z`_.ZP_$6EYZQ(6V`ZO<`ZO<`ZO<`ZO<`ZO<`ZO<`ZO<`ZO<`ZS=`[CI`[CI" + "`Z76`Z76`Z76`Z76`Z76`Z76`Z76`[OL`Z;7`Z+3`YG*`YG*`YG*`[/D`Y[/`Y#!" + "Y8:W\"Q1)TW\\IY7D`Y7@`Y7@`Y7@`Y7@`Z8@`YH$`XF``XFT`XFT`Y'L`XF``,#)O" + "U.$1_@HZ:G:G`^OC`]N]`]N]`^+1`^KG`^?<`^?<`^OG`]_(`^77`^?=`]_(`]_(" + "`]_(`]_(`]_(`]_(`]_(`]_(=G*$AL&VU@`(TP`#TP`#U``)SP_]U@`&TP`\"S@_\\" + "S@_\\S@_\\S@_\\S@_\\U0`$O@_HO@_HO@_HPP_OR@_WO@_HO@_HO@_HO@_HOP_HM0_>" + "J0_/J0_/J0_/J0_/K`_6M`_BJ0_/J0_/J0_/J0_/E_2`0%N#ON8`ON8`ON8`ON8`" + "P><`RNT`P><`O^<`O>8`O>8`O>8`ON8`T_,`RNT`R>T`U?0`Q>L`P.@`P.@`P.@`" + "P.@`P.@`P.@`P.@`N.(`ON<`L-X`L-X`L-X`L-X`L-X`L-X`N^0`MN(`G=,`G=,`" + "H]8`K=P`C,D`?K``C;XC5&6!\\`_O\\`_O]`_`^@`(]P_`]P_`]P_`]P_`]P_`^@`-" + "]@_^]P_\\]@_[]@_[]@_[]@_[]@_[]@_[]``'\\`_Q]P`!\\`_Q\\`_Q\\`_Q\\`_Q\\`_Q" + "]0_Z]0_Y\\0_B\\0_B\\0_B\\0_B\\@_H\\0_FYP^OZ@^^EZ.?@5R-`ZO<`ZO<`ZO<`ZO<" + "`ZO<`ZO<`ZO<`ZO<`\\+S`ZO<`ZO<`ZW>`Z76`Z76`Z76`Z76`Z76`Z76`\\#Q`Z76" + "`[?H`YG*`YG*`YG*`[;G`YG*`ZK;`ZG:2#E`@$G-Y7@`Y7@`Y7@`Y7@`YGX`Z(H`" + "YH(`XFT`XFT`XFT`ZI4`XFT`+C)MU>(2````9W.D]-_=`]N]`]N]`]N]`]N]`^G?" + "`^C@`^[K`^KD`^#,`]_(`]_(`]_(`]_(`]_(`]_(`]_(`]_(`-W&+SMBN@KFT0`\"" + "TP`#TP`#U``'VP`+SP_^S@_\\S@_\\S@_\\S@_\\S@_\\U0`&O@_IO@_HO@_HQ`_UP`_P" + "O@_HO@_HO@_HO@_HO@_HQ0_SJ0_/J0_/J0_/J0_/L@_9L`_=J0_/J0_/J0_/J0_/" + "J0_/5H^(CZSPON8`ON8`ON8`P><`RNT`ON8`S.\\`O>8`O>8`O>8`O>8`O>8`O>8`" + "QNP`U/0`S>\\`P.@`P.@`P.@`P.@`P.@`P.@`P.@`Q>L`PND`L-X`L-X`L-X`L-X`" + "L-X`L-X`L-X`O>4`H]8`K-L`I=@`@L(`?K``?K``@L(`<*4/9WB-\\`_O\\`_O\\`_O" + "\\`_O]@_^]``)]P_`]P_`]P_`^@`,^0`*]@_[]@_[]@_[]@_[]@_[]@_[]@_[]``&" + "\\`_Q]P_Z\\`_Q\\`_Q\\`_Q\\`_Q\\`_Q]@`!]0_Y\\0_B\\0_B\\0_B\\0_B\\0_B\\@_JYP^O" + "Y`^\\R>*U13AI`ZO<`ZO<`ZO<`ZO<`ZO<`ZO<`ZO<`ZS=`[CI`ZO<`ZO<`[[O`Z76" + "`Z76`Z76`Z76`Z76`Z76`[WN`Z76`[7F`YG*`YG*`YG*`[;G`YG*`ZO<`Z76JF>D" + "+2-OY7@`Y7@`Y7@`Y7@`[)@`Y7@`Z8X`XFT`XFT`XFX`Y7``XFT`*\"]FV.45````" + "EZ/4Q[O'`][#`]N]`]N]`]N]`]N]`^#*`^WI`^'2`]_(`]_(`]_(`]_(`]_(`]_(" + "`]_(`]_(`]_(P*FE77F/O@_IP@_OTP`#W0`/VP`,S@_\\S@_\\S@_\\S@_\\S@_\\S@_\\" + "S@_\\S0_[O@_HO@_HS0_ZO`_JO@_HO@_HO@_HO@_HO@_HOP_HL`_0^ON8`ON8`PN@`RNT`ON8`ON8`" + "R^\\`O>8`O>8`O>8`O>8`O>8`O>8`O>8`SN``M.$`P>H`RNX`S?$`R>X`P.@`P.@`" + "P.@`R>\\`N.,`L-X`L-X`L-X`L-X`L-X`M>$`N^0`PN<`H-,`?[``?K``?K``?K``" + "?K``G-$`79'[=HJ5\\`_O\\`_O\\`_O\\`_O\\`_O\\`_O]P_]^0`']P_`]``+]``)]@_[" + "]@_[]@_[]@_[]@_[]@_[]@_[]@_^\\`_Q\\`_T\\`_Q\\`_Q\\`_Q\\`_Q\\`_Q\\`_U]0_Y" + "\\0_B\\0_B\\0_B\\P_O\\0_A\\0_?YP^OY`^XYPVV(2)2_JC9`ZO<`ZO<`ZO<`ZO<`ZO<" + "`ZO<`\\'R`ZO<`ZO<`ZO<`[_P`Z76`Z76`Z76`Z76`Z76`Z76`[3E`Z76`Z76`Z76" + "`YG*`YG*`[+C`YG*`YG*`Y_0^XJ[$1=/O683Y7@`Y7@`ZYP`Y7@`Y7@`ZY8`XFT`" + "XFT`Z8X`XFT`XFT`'BAT`ON8`ON8`P^D`O>8`O>8`O>8`O>8`O>8`O>8`O>8`S_$`Q^P`" + "L-X`L-X`L-X`L-X`L-X`NN,`Q^L`S>\\`RN``ON<`O.4`N>(`L-\\`J-@`F]$`E\\\\`" + "G=(`I]@`?K``?K``?K``?K``?K``@<(`B\\@`8(OBB)VA\\`_O\\`_O\\`_O\\`_O\\`_O" + "\\`_O\\`_O\\`_O]P_\\^0`,]@_^]@_[]@_[]@_[]@_[]@_[]@_[]@_[]@_[\\`_\\\\`_Q" + "\\`_Q\\`_Q\\`_Q\\`_Q\\`_Q\\`_Q]``!\\0_B\\0_D\\`_PZ`_&ZP_$\\0_@YP^OYP^SYP^O" + "345PSXN\\`ZO<`ZO<`ZO<`ZO<`ZO<`ZW>`[3E`ZO<`ZO<`ZO<`[+C`Z76`Z76`Z76" + "`Z76`Z76`Z;7`Z?8`Z76`Z76`[GJ`YG*`YG*`Z_@`YG*`YG*`Z_@`Z769$>+;$\"W" + "Y7@`ZY8`Y7D`Y7@`Y7@`[)H`XFT`XFT`Z8``XFT`XFT`$!Q-X^`@````W.D97F&&" + "`^?:`]N]`]N]`]N]`]N]`^7:`^/4`]:P`]:P`]:P`]:P`]:Q`]_'`^;8`^;9`]_)" + "^=?#,3MAO@_IO@_IO@_ITP`#U0`&S@_\\S@_\\S@_\\S@_\\S@_\\S@_\\S`_^Q@_SOP_J" + "S0_\\O@_HO@_HO@_HO@_HO@_HO@_HO@_HOP_IL@_P`ON8`ON8`ON8`S^``O>8`O>8`" + "O>8`O>8`O>8`O>8`S_$`O>8`NN,`L-X`L-X`L-X`L-X`L-X`L-X`L-X`P>@`J]D`" + "E\\\\`E\\\\`E\\\\`E\\\\`E\\\\`E\\\\`E\\\\`K]P`F,``?K``?K``?K``?K``?K``G]0`?K``" + "88/)G+*P\\`_O\\`_O\\`_O\\`_O\\`_O\\`_O\\`_O\\`_O\\`_O]``#\\P_J\\P_Q]`_`]P`$" + "]@`#]P_\\]@_[]@_[]@_[^0`*\\`_Q\\`_Q\\`_Q\\`_Q\\`_Q\\`_Q\\`_Q]``$\\P_Q[@_8" + "ZP_$ZP_$ZP_$[@_5YP^OYP^OYP^O?':0G6V>`ZO<`ZO<`ZO<`ZO<`ZO<`\\3U`ZO<" + "`ZO<`ZO<`ZO<`ZO<`[3E`Z76`Z76`Z76`Z76`[+C`Z76`Z76`Z76`[/D`YG*`YG*" + "`ZK;`YG*`YG*`Z'2`ZK;PFF<&QM:YXP]YG\\`Y7@`Y7@`Y7@`ZYL`XFT`Y'L`XF\\`" + "XFT`V6HV!!!![OLK````]P,S6V:7`^G@`]N]`]N]`]N]`]_)`]R_`^;7`]:P`]:P" + "`]:P`]:P`]:P`]:P`]:P`]:P`]J]K)NA;8>9O@_IO@_IS`_^O@_HMP_@T0`\"S`_]" + "S@_\\S@_\\S@_\\S@_\\U@`'P@_NRP_XO@_HO@_HO@_HO@_HO@_HO@_HO@_HO@_HQ@_S" + "J0_/J0_/O`_JJ0_/J0_/J0_/J0_/J0_/J0_/J0_/J0_/F/;!/51`ON8`PN@`R>P`" + "ON8`ON8`ON8`ON8`Q^L`O>8`O>8`O>8`O>8`O>8`S>\\`O>8`Q>L`L-X`L-X`L-X`" + "L-X`L-X`L-X`L-X`NN,`N.,`E\\\\`E\\\\`E\\\\`E\\\\`E\\\\`E\\\\`E\\\\`K-L`E\\\\`A,,`" + "?K``?K``?K``?K``@<$`B\\<`?K``7'BQL,>^\\`_O\\`_O\\`_O\\`_O\\`_O\\`_O\\`_O" + "\\`_O]``$]@_X\\P_J\\P_J\\P_J\\P_J\\P_J\\`_O]P_\\]``#]``%^0`)]@_X]0_[]`__" + "]P`!]`_`]P_\\]@_Z]P_[ZP_$ZP_$ZP_$ZP_$[0_.ZP_&YP^PYP^OY`^TIJNL:T]`" + "`ZO<`ZO<`ZO<`ZO<`Z[?`[3E`ZO<`ZO<`ZO<`ZO<`ZO<`\\#Q`Z76`Z76`Z76`Z76" + "`[SM`Z76`Z76`Z76`Z76`ZC9`YG*`Z+3`YG*`YG*`YG*`ZS=`(J[%AM2LV`&Y7@`" + "Y7@`Y7@`Y7@`ZID`XFT`ZI4`XFT`XFT`O6D2!!!!_0DY````````3EJ*[M;2`]N]" + "`]N]`]N]`^C=`]N]`^35`]:P`]:P`]:P`]:P`]:P`]:P`]:P`]:P`]:P6E-FI-_2" + "O@_IQ`_WR@_WMP_@MP_@MP_@P@_NU@`&S@_\\S@_\\TP`#Q`_UQ0_RO@_HO@_HO@_H" + "O@_HO@_HO@_HO@_HO@_HOP_ILP_9J0_/OP_KJ0_/J0_/J0_/J0_/J0_/J0_/J0_/" + "J0_/J0_/79N.@9SCPN@`R.L`ON8`ON8`ON8`ON8`R.P`O>8`O>8`O>8`O>8`O>8`" + "R>P`O^@`O>8`R.L`L-X`L-X`L-X`L-X`L-X`L-X`LM``O.8`ON@`E\\\\`E\\\\`E\\\\`" + "E\\\\`E\\\\`E\\\\`F]$`HM4`HM8`?K``?K``?K``?K``?K``G=,`?K``?K``4VF:P]S," + "\\`_O\\`_O\\`_O\\`_O\\`_O\\`_O\\`_O]P_`\\`_O]P_Z\\P_J\\P_J\\P_J\\P_J\\P_J\\P_J" + "\\P_J\\P_J\\P_J]P`![`_;[`_;[`_;[`_;[`_;[`_;[`_;]0_UZP_$ZP_$ZP_$ZP_$" + "[`_:ZP_$ZP^`YP^OY`^XS.\"^/C-D`ZO<`ZO<`ZO<`ZO<`\\/T`ZO<`ZO<`ZO<`ZO<" + "`ZO<`ZO<`[WN`Z76`Z76`Z76`Z76`\\#Q`Z76`Z76`Z76`Z76`[KK`YG*`YG*`YK+" + "`YG*`YG*`ZS=`Z'29D%Z:3ZSY7@`Y7@`Y7@`Y7@`ZI,`XFX`Y7P`XFT`XFT`E5WE" + "8&R=````````````CIK+O*RQ`]N]`]N]`]R_`^')`]N]`^/4`]:P`]:P`]:P`]:P" + "`]:P`]:P`]:P`]:P_-&M,SE>O@_IO`_MQP_SS@_]MP_@MP_@MP_@MP_@MP_@SP_^" + "T0_`U``(O`_JO@_HO@_HO@_HO@_HO@_HO@_HO@_HO@_HO@_HQ@_SJP_2N`_GJ0_/" + "J0_/J0_/J0_/J0_/J0_/J0_/J0_/J0_/J0_/,$ANNM\\SR.P`ON8`ON8`ON8`ON8`" + "ON8`S^\\`O>8`O>8`O>8`O>8`R.T`P.@`O>8`O>8`P.@`L-X`L-X`L-X`L-X`L-X`" + "L-X`P^H`L-X`ON8`E\\\\`E\\\\`E\\\\`E\\\\`E\\\\`E\\\\`L-\\`E\\\\`J]L`?K``?K``?K``" + "?K``@<$`C,D`?K``?K``1%6\"V?/<\\`_O\\`_O\\`_O\\`_O\\`_O\\`_O]0_\\\\P_Q\\`_O" + "]P_[\\P_J\\P_J\\P_J\\P_J\\P_J\\P_J\\P_J\\P_J]@_V]0_V[`_;[`_;[`_;[`_;[`_;" + "[`_;[`_;[`_C[0_,ZP_$ZP_$ZP_$[`_@ZP_$Z`_.YP^OY`^\\Z0G!&AU.`ZO<`ZO<" + "`ZO<`Z[?`[/D`ZO<`ZO<`ZO<`ZO<`ZO<`ZO<`Z[?`ZG:`Z76`Z76`Z76`[SM`Z76" + "`Z76`Z76`Z76`['B`YG*`YG*`Z+3`YG*`YG*`YG*`ZW>L&*3+B9NY7@`Y7@`Y7@`" + "Y7@`Z(P`Z(X`XFT`XFT`XFT`8$:FGJK;````````````O,CYAGV/`]N]`]N]`^?9" + "`]N]`]N]`^#-`]:P`]:P`]:P`]:P`]:P`]:P`]:P`]:PP*FG9'6)O@_ISP_^O@_I" + "Q@_TMP_@MP_@MP_@MP_@MP_@MP_@S@_]QP_TRP_VQP_TO@_IO@_HO@_HO@_HO@_H" + "O@_HO@_HO@_JM@_>N0_EJ0_/J0_/J0_/J0_/J0_/J0_/J0_/J0_/J0_/J0_/C..V" + "2E^5R.P`ON8`ON8`ON8`ON8`ON8`ON8`Q>H`O>8`O>8`O>8`Q.H`P^D`O>8`O>8`" + "P>@`L-X`L-X`L-X`L-X`L-X`L-X`P^@`L-X`L-X`L=T`E\\\\`E\\\\`E\\\\`E\\\\`E\\\\`" + "I]H`F,``E\\\\`J]P`?K``?K``?K``?K``G=(`?K``?K``?K``,T)L[@GK\\`_O\\`_O" + "\\`_O\\`_O\\`_O]@_V]0_V\\`_O\\`_O]@_\\\\P_J\\P_J\\P_J\\P_J\\P_J\\P_J\\P_J\\P_J" + "]@_[\\`_S[`_;[`_;[`_;[`_;[`_;[`_;\\P_L[`_;[0_6ZP_$ZP_$ZP_$\\0_BZP_$" + "[@_7YP^OZ@^`YP^P*RE9[)W.`ZO<`ZO<`\\/T`ZO<`ZO<`ZO<`ZO<`ZO<`ZO<`ZO<" + "`ZO<`[KK`Z76`Z76`Z76`[/D`Z76`Z76`Z76`Z76`Z76`ZO<`YG*`ZK;`YG*`YG*" + "`YG*`[+CX7FJ!A%#Y'@_Y7@`Y7@`Y7@`Y($`ZI(`XFT`XFT`WVP\\-D!ST-T-````" + "````````V>864U-T`]N^`]N]`^76`]N]`]N]`]W$`]:P`]:P`]:P`]:P`]:P`]:P" + "`]:P`]S\"?&]ZD;V^RP_[O@_IP@_OMP_AMP_@MP_@MP_@MP_@MP_@R0_XQ0_RH`_(" + "H`_(H`_(IP_*M@_=P`_PR0_WQ`_UO`_JO@_HR@_VN0_BJ0_/J0_/J0_/J0_/J0_/" + "J0_/J0_/J0_/J0_/J@_/J`_45HB-C:GPON8`ON8`ON8`ON8`ON8`ON8`R>X`O>8`" + "O>8`O>8`PN@`QNL`O>8`O>8`O>8`R>L`L-X`L-X`L-X`L-X`L-X`N^0`LM\\`L-X`" + "L=\\`F](`E\\\\`E\\\\`E\\\\`E\\\\`F,\\`I]D`E\\\\`E\\\\`I=@`?K``?K``?K``@,$`C,D`" + "?K``?K``?K``+#MC\\`_O\\`_O\\`_O\\`_O\\`_O\\`_Q]0_\\\\`_O\\`_O\\`_O]@_[\\P_J" + "\\P_J\\P_J\\P_J\\P_J\\P_J\\P_J]0_X\\P_J\\`_R[`_;[`_;[`_;[`_;[`_;[`_;]0_U" + "[`_;[`_>ZP_$ZP_$ZP_$[`_AZP_$[@_7YP^OZP_\"YP^O245NRXFZ`ZO<`Z[?`[+C" + "`ZO<`ZO<`ZO<`ZO<`ZO<`ZO<`ZO<`ZO<`\\+S`Z76`Z76`Z;7`Z?8`Z76`Z76`Z76" + "`Z76`Z76`[GJ`YG*`[+C`YG*`YG*`YG*`Z/4[(^`!!!!VG,TY7@`Y7@`Y7@`YG``" + "XF\\`XFT`XG$`H&;O,CYP^`@X````````````]P,S.D9W_=K'`^'-`]N]`]N]`]N]" + "`]N]`]BU`]:P`]:P`]:P`]:P`]:P`]JZ`]N`0$!8`O>8`O^<`R>T`O>8`O>8`O>8`O>8`P^H`L-X`" + "L-X`L-X`L-X`L^$`N^4`L-X`L-X`O.4`E\\\\`E\\\\`E\\\\`E\\\\`E\\\\`L=X`E\\\\`E\\\\`" + "E\\\\`FM$`?K``?K``?K``G=(`?K``?K``?K``?+T[,#YE\\`_O\\`_O\\`_O\\`_O\\`_O" + "]@_`\\`_O\\`_O\\`_O\\`_O]P_]\\P_J\\P_J\\P_J\\P_J\\P_J\\P_J\\P_J]@_Y\\P_J\\P_N" + "[`_;[`_;[`_;[`_;[`_;[`_;\\@_H[`_;\\0_DZP_$ZP_$ZP_$[`_H`ZO<`\\3U`ZO<`ZO<`ZO<`ZO<`ZO<`ZO<`ZO<`ZO<`ZO<`[CI" + "`Z76`Z76`[/D`Z76`Z76`Z76`Z76`Z76`Z76`Z[?`YG*`[3E`YG*`YG*`YG*`YG*" + "XYS-!!!!WG4XY7@`Y7@`YG``ZY4`XFT`YXL`X6L`.#1ZJ[?H````````````````" + "````=(\"QO:JN`^?>`]N]`]N]`]N]`]N]`]S\"`]:P`]:P`]:P`]:P`]>S`^#)`M6P" + "*31;R`_ZO@_IO@_IR`_XMP_@MP_@MP_@MP_@R0_WMP_@O0_FH`_(H`_(H`_(H`_(" + "H`_(H`_(H`_(H`_(H`_(L`_=L@_:D0^QD0^QD0^QD0^QD0^QD0^QD0^QD0^QD0^Q" + "D0^QD0^QHP_&?=VF15V6M.$`O^8`ON8`ON8`ON8`ON8`O^<`PN@`O>8`O>8`R^X`" + "O>8`O>8`O>8`O>8`ON8`MN(`L-X`L-X`L-X`L-X`PND`L-X`L-X`L-X`O^<`E\\\\`" + "E\\\\`E\\\\`E\\\\`H=4`G-(`E\\\\`E\\\\`E\\\\`A<0`?K``?K``@,$`CLD`?K``?K``?K``" + "<*LB1U=S\\`_O\\`_O\\`_O\\`_O]P`#\\`_O\\`_O\\`_O\\`_O\\`_O]@_^\\P_J\\P_J\\P_J" + "\\P_J\\P_J\\P_J]@_[\\P_J\\P_J\\P_L[`_;[`_;[`_;[`_;[`_;\\0_F[`_;[`_;\\@_I" + "ZP_$ZP_$ZP_$[@_3ZP_$Z`_,YP^OZ`_)YP^O>86,D6:7`[+C`[#A`ZO<`ZO<`ZO<" + "`ZO<`ZO<`ZO<`ZO<`ZO<`ZO<`ZO<`Z_@`Z76`[OL`Z76`Z76`Z76`Z76`Z76`Z76" + "`Z76`ZW>`[?H`YG*`YG*`YG*`YG*SXZ_\"A-'Y7@`Y7@`Y7@`Z8L`YXH`Y7\\`W$T`" + "I6CV(\"Q=\\?XN````````````````````Q-$!8F%]`][#`]N]`]N]`]N]`]N]`^#+" + "`]:P`]:P`]:P`]:P`^+0`]:PZ<*E/5%PO@_IO@_IOP_JNP_FMP_@MP_@MP_@Q`_V" + "MP_@MP_@Q@_RH`_(H`_(H`_(H`_(H`_(H`_(H`_(H`_(MP_@IP_,LP_;D0^QD0^Q" + "D0^QD0^QD0^QD0^QD0^QD0^QD0^QD0^QI`_.E0^W28YY``O>8`O>8`SN``O>8`O>8`O>8`O>8`O>8`QNL`L-X`L-X`L-X`L-X`" + "P^D`L-X`L-X`L-X`L-X`MN(`E\\\\`E\\\\`E\\\\`E\\\\`KMX`E\\\\`E\\\\`E\\\\`G]0`?K``" + "?K``?K``G-,`?K``?K``?K``?K``9)<#87.%\\`_O\\`_O\\`_O]`_`\\`_O\\`_O\\`_O" + "\\`_O\\`_O\\`_O]P_^\\P_J\\P_J\\P_J\\P_J\\P_J\\P_J]0_X\\P_J\\P_J\\P_J[`_<[`_;" + "[`_;[`_;[`_;\\`_S[`_;[`_;\\0_HZP_$ZP_$ZP_$ZP_&ZP_$ZP_$Y`^YZ`_,YP^O" + "BI^2>EB)`\\3U`ZO<`ZO<`ZO<`ZO<`ZO<`ZO<`ZO<`ZO<`ZO<`ZO<`ZO<`[WN`Z76" + "`\\#Q`Z76`Z76`Z76`Z76`Z76`Z76`Z76`[GJ`[;G`YG*`YG*`YG*`YG*MW&B'1Y<" + "YGT`Z(P`Z9$`[9P`X%L`W$T`X78\\+#)LJK;G````````````````````````]`0T" + "-T-S],^V`]N]`]N]`]N]`]N]`^/2`]:P`]:P`]:P`^35`]:P`]:PS:R84&R$O@_I" + "O@_IR@_XMP_@MP_@MP_@Q`_VMP_AMP_@MP_@P0_LH`_(H`_(H`_(H`_(H`_(H`_(" + "H`_(N@_DI0_)H`_(J@_0D0^QD0^QD0^QD0^QD0^QD0^QD0^QD0^QD0^QJP_0DP^T" + "D0^Q)4)AG8`SO$`O>8`O>8`O>8`O>8`" + "O>8`O>8`QNL`L-X`L-X`L-X`O>8`LM\\`L-X`L-X`L-X`L-X`I-8`E\\\\`E\\\\`E\\\\`" + "K]T`E\\\\`E\\\\`E\\\\`E\\\\`J]H`?K``?K``?[``CLH`?K``?K``?K``?K``8HKC?)\"8" + "\\`_O\\`_O]0_Y]0_T\\`_O\\`_O\\`_O\\`_O\\`_O\\`_O]@_^\\P_J\\P_J\\P_J\\P_J\\P_J" + "]@_\\\\P_J\\P_J\\P_J\\P_J\\0_B[`_;[`_;[`_;[`_;\\P_M[`_;[`_;\\@_HZP_$ZP_$" + "[0_/ZP_$ZP_$ZP_$ZP_([@_/YP^OEK..9D]``Z_@`ZO<`ZO<`ZO<`ZO<`ZO<`ZO<" + "`ZO<`ZO<`ZO<`ZO<`ZO<`\\#Q`Z76`[WN`Z76`Z76`Z76`Z76`Z76`Z76`Z76`ZW>" + "`[7F`YG*`YG*`YG*`YG*HFJ;+B5PX%``X%``YX<`WUX`W$T`XW$`@US-/TM\\]`0T" + "````````````````````````````CYO+EXB1`^#'`]N]`]N]`]N]`^35`]:P`]:P" + "`^/2`]:P`]:P`]:PN9V087R/O@_IO@_IS0_ZMP_@MP_@Q`_VMP_AMP_@MP_@MP_@" + "K0_2H`_(H`_(H`_(H`_(H`_(H`_(NP_EH`_(H`_(I0_)E@^VD0^QD0^QD0^QD0^Q" + "D0^QD0^QD0^QD0^QJ`_4D0^QD0^Q@/&D,4MTIM@`IM@`IM@`MN$`ON8`ON8`PN@`" + "O^<`SN\\`O>8`O>8`O>8`O>8`O>8`O>8`O>8`N^4`L-X`L-X`M>(`N.,`L-X`L-X`" + "L-X`L-X`N.(`E\\\\`E\\\\`E\\\\`G-(`HM0`E\\\\`E\\\\`E\\\\`E\\\\`K=P`?K``?K``G-(`" + "?K``?K``?K``?K``?K``6WN^F*ZM\\`_O\\`_S]@_Z\\`_O\\`_O\\`_O\\`_O\\`_O\\`_O" + "\\`_O]@_^\\P_J\\P_J\\P_J\\P_J\\P_K]@_T\\P_J\\P_J\\P_J\\P_J\\0_E[`_;[`_;[`_;" + "\\0_C[`_;[`_;[`_;\\0_FZP_$ZP_$[`_9ZP_$ZP_$ZP_$[P_4[@_/YP^OH<&-5T]Z" + "`ZO<`ZO<`ZO<`ZO<`ZO<`ZO<`ZO<`ZO<`ZO<`ZO<`ZO<`ZO<`[+C`Z76`[+C`Z76" + "`Z76`Z76`Z76`Z76`Z76`Z76`Z76`[OL`YG*`YG*`Z35`X6VE5B).25]X6D`YX,`" + "YX,`W$T`X&,`PE`;-D)SQM,#````````````````````````````````VN<73UB&" + "`]>S`^/3`]N]`]N]`^38`]:P`^#+`]>R`]:P`]:P`]:PKY6+8X.-P0_LO@_IP@_O" + "MP_@Q`_VMP_AMP_@MP_@MP_@PP_NH`_(H`_(H`_(H`_(H`_(I0_)NP_EH`_(H`_(" + "H`_(L0_7D0^QD0^QD0^QD0^QD0^QD0^QD0^QD0^RJ`_4D0^QD0^QD0^Q6:N%9(.`" + "IM@`IM@`IM@`IM@`Q.L`ON8`S>``R^T`ON8`O>8`O>8`O>8`O>8`O>8`O>8`P^D`" + "L-X`L-X`L-X`P>@`L-X`L-X`L-X`L-X`L-X`P.@`E\\\\`E\\\\`E\\\\`L=\\`E\\\\`E\\\\`" + "E\\\\`E\\\\`E\\\\`J-H`?K``?[``CLD`?K``?K``?K``?K``?K``3F>=M,S!\\`_O]`__" + "\\`_O\\`_O\\`_O\\`_O\\`_O\\`_O\\`_O\\`_O]P_`\\P_J\\P_J\\P_J\\P_J]P_]\\P_J\\P_J" + "\\P_J\\P_J\\P_J\\@_J[`_;[`_;[`_;\\`_R[`_;[`_;[`_;[`_>ZP_$ZP_$[`_@ZP_$" + "ZP_$ZP_$[P_8[0_1YP^OI\\B13$!K`Z;7`[+C`[;G`[?H`[/D`ZO<`ZO<`ZO<`ZO<" + "`ZO<`ZO<`ZO<`ZO<`[CI`Z;7`Z76`Z76`Z76`Z76`Z76`Z76`Z76`Z76`[KK`YS-" + "`YO,`V^@`VZ?B56(0BN'Y'<`YGP`W$\\`W%4`W6<[.SMZ?HJ[`@X^````````````" + "`````````````````````@X^3%B(T*V6`]2K`]_*`]_&`^/5`]S\"`]FY`]:P`]:P" + "`]:P`]:PK)**98&,RP_YQ0_SMP_@Q`_VMP_AMP_@MP_@MP_@MP_@Q0_RH`_(H`_(" + "H`_(H`_(I`_,M`_AH`_(H`_(H`_(H`_(LP_:D0^QD0^QD0^QD0^QD0^QD0^QD`^T" + "J0_/D0^QD0^QD0^QD0^Q,V9GB[,*IM@`IM@`IM@`IM@`J-D`Q.H`T?$`O^<`O>8`" + "O>8`O>8`O>8`O>8`O>8`O>8`R.T`L-X`L-X`Q.L`L-X`L-X`L-X`L-X`L-X`L-X`" + "N^0`E\\\\`E\\\\`J=H`E\\\\`E\\\\`E\\\\`E\\\\`E\\\\`E\\\\`G-(`?K``F]$`?K``?K``?K``" + "?K``?K``?K``.TQ]T>O6]P`#\\`_O\\`_O\\`_O\\`_O\\`_O\\`_O\\`_O\\`_O\\`_O]P__" + "\\P_J\\P_J\\P_J\\P_M\\P_P\\P_J\\P_J\\P_J\\P_J\\P_J\\@_M[`_;[`_;[`_;\\`_P[`_;" + "[`_;[`_;[`_;Z`_*ZP_$\\0_AZP_$ZP_$ZP_$[@_7[@_3YP^OJ,2D3#1E`X^``X^`" + "`X^``X^``X^``X^``YK+`ZG:`[+C`[?H`[CI`['B`ZO<`\\/T`Z76`Z76`Z76`Z35" + "`ZC9`ZW>`Z[?`[#A`[#A`[+C`X6V`VZ?`VZ?`W:G?TB!2\"V.X&(`XVL`W$X`XW<`" + ">$[!+CIK[OLK````````````````````````````````````````ML+S;V5U`]2K" + "`]2K`]>U`^;;`]_$`]:P`]:P`]:P`]:P`]:PL9:,8WJ&P`_PS@_\\Q`_VMP_AMP_@" + "MP_@MP_@MP_@MP_@N0_BH`_(H`_(H`_(J@_1M0_8`O>8`O>8`O>8`O>8`O>8`O>8`O>8`P>@`L-X`O^@`" + "L=X`L-X`L-X`L-X`L-X`L-X`L-X`K-L`E\\\\`F<``I]@`E\\\\`E\\\\`E\\\\`E\\\\`E\\\\`" + "E\\\\`B<<`?[``D,L`?K``?K``?K``?K``?K``?K``(S)@\\PC^\\`_O\\`_O\\`_O\\`_O" + "\\`_O\\`_O\\`_O\\`_O\\`_O\\`_O]P_`\\P_J\\P_J\\P_J]P__\\P_J\\P_J\\P_J\\P_J\\P_J" + "\\P_J\\P_N[`_;[`_;[`_?[`_>[`_;[`_;[`_;[`_;[P_6ZP_$[`_@ZP_$ZP_$ZP_$" + "Z`_1[@_2YP^OH[FC4C=H`X^``X^``X^``X^``X^``X^``X^``X^``X^``X^``X^`" + "`X^``Y_0`[;G`YS-`Y3%`XN\\`X*S`X&R`X&R`X&R`X&R`X.T`Y_0`VZ?`VZ?`VZ?" + "`Y7&>$>+32J6YX8`W$T`Y7T`JD@#)C)CQ=(\"````````````````````````````" + "````````````````[OLK/4EY^\\ZH`]2K`]2K`]>V`]BW`]W#`^+-`]J\\`]:P`]:P" + "O)^166M]K0_2S`_^MP_AMP_@MP_@MP_@MP_@MP_@N`_GI0_)H`_(H`_(K0_4L0_9" + "H`_(H`_(H`_(H`_(H`_(I`_-D@^RD0^QD0^QD0^QD0^QF`^_G`_$D0^QD0^QD0^Q" + "D0^QD0^Q=^&=-U)\\IM@`IM@`IM@`IM@`IM@`N>(`N^4`J=D`P^D`O>8`O>8`O>8`" + "O>8`O>8`O>8`P.<`LM\\`MN$`M>,`L-X`L-X`L-X`L-X`L-X`L-X`M-``E]$`E\\\\`" + "L-\\`E\\\\`E\\\\`E\\\\`E\\\\`E\\\\`E\\\\`G=(`?K``F](`?K``?K``?K``?K``?K``?K``" + ">[PZ(3!?\\P_Q\\`_O\\`_O\\`_O\\`_O\\`_O\\`_O\\`_O\\`_O\\`_O\\`_O]P`!\\P_J\\P_J" + "\\`_O\\`_O\\P_J\\P_J\\P_J\\P_J\\P_J\\P_J]0_R[`_;[`_;\\`_P[`_;[`_;[`_;[`_;" + "[`_;[`_?ZP_$[P_E*#1`P\\_" + "````````````````````````````````````````````````>X>XKI2,`]2K`]2K" + "`]2K`^//`]\"C`]\"C`]\"C`]:T`^#,R[&J3%API@_*OP_IN0_CMP_@MP_@MP_@MP_@" + "MP_@Q@_RH`_(H`_(LP_9J`_1H`_(H`_(H`_(H`_(H`_(H`_(L0_:D0^QD0^QD0^Q" + "D0^QH@_&FP^]D0^QD0^QD0^QD0^QD0^QD0^Q5**!88*^IM@`IM@`IM@`IM@`N^8`" + "I]@`N.(`H=4`H=4`NN4`O^<`O>8`O>8`O>8`O>8`R.P`L=X`O^@`L-X`L-X`L-X`" + "L-X`L-X`L-X`L-X`O><`E\\\\`H]<`F]$`E\\\\`E\\\\`E\\\\`E\\\\`E\\\\`E\\\\`J=H`?[``" + "D\\T`?K``?K``?K``?K``?K``B,8`@+,8/4YQ]0_W\\`_O\\`_O\\`_O\\`_O\\`_O\\`_O" + "\\`_O\\`_O\\`_O\\`_O]P_`\\P_J\\P_J]P_^\\P_J\\P_J\\P_J\\P_J\\P_J\\P_J\\P_J]@_U" + "[`_;[`_;\\`_R[`_;[`_;[`_;[`_;[`_;\\0_FZP_$[@_3ZP_$ZP_$ZP_$ZP_$[@_8" + "Z`_*?WZ*=DEZ`X^``X^``X^``X^``X^``X^``X^``X^``X^``X^``Z76`YO,`X^`" + "`Z76`X&R`X&R`X&R`X&R`X&R`X&R`X&R`YW.`X&R`YS-`VZ?`VZ?`X\"Q`VZ?9D25" + "6CBCX6T`VU,^1C\"+6666^04U````````````````````````````````````````" + "````````````S-D)8&6/`]2K`]2K`]2K`^'-`]\"C`]\"C`]\"C`]\"C`]\"CX;:6.SY>" + "IP_+K@_4HP_'O@_HMP_@MP_@MP_@MP_@P@_LH`_(M0_8`IM@`IM@`KMP`H=4`H=4`H=4`I]D`P^D`O>8`O>8`" + "O>8`QNH`Q.D`L-X`L-X`L-X`L-X`L-X`L-X`L-X`L-X`ON8`E\\\\`K=P`E\\\\`E\\\\`" + "E\\\\`E\\\\`E\\\\`E\\\\`E\\\\`K-T`FM$`?K``?K``?K``?K``C\\L`C\\P`8*X`7HWQ8G=`" + "[P_5[`_C]@_Y\\`_O\\`_O\\`_O\\`_O\\`_O\\`_O\\`_O\\`_O]P_`\\P_J\\P_R\\P_M\\P_J" + "\\P_J\\P_J\\P_J\\P_J\\P_J\\P_J]@_U[`_;[`_<\\@_B[`_;[`_;[`_;[`_;[`_;\\0_G" + "ZP_$ZP_&ZP_$ZP_$ZP_$ZP_$[`_;ZP^_9%A\\D%:'`X^``X^``X^``X^``X^``X^`" + "`X^``X^``X^``ZO<`Y/$`X^``X^``Y[/`X&R`X&R`X&R`X&R`X&R`X&R`XV^`XJ[" + "`X&R`YO,`VZ?`VZ?`Y?(`VZ?74&(82^LX%X`=33$&B97X^`@````````````````" + "````````````````````````````````````````^PN0_CMP_@MP_@K@_5" + "N0_BI@_+H`_(H`_(H`_(H`_(H`_(H`_(H`_(H`_(G@_#D0^QD0^QJP_0D`^TD0^Q" + "D0^QD0^QD0^QD0^QD0^QD0^QD0^Q&3%5G,PQIM@`J=H`N.0`IM@`IM@`K=L`H=4`" + "H=4`H=4`H=4`H=4`H=4`NN4`P.<`O>8`Q.L`L-X`L-X`L-X`L-X`L-X`L-X`L-X`" + "L-X`L-X`LMX`K]X`E\\\\`E\\\\`E\\\\`E\\\\`E\\\\`E\\\\`E\\\\`E\\\\`J-L`DLT`?K``?K``" + "E\\\\`@<,`7:T`7:T`>KX`1F_!A9V3[P_5[P_5[P_5\\@_D]@_Y\\`_O\\`_O\\`_O\\`_O" + "\\`_O\\`_O]``!\\P_J]P__\\P_J\\P_J\\P_J\\P_J\\P_J\\P_J\\P_J\\P_J]P_X[`_;\\P_M" + "[`_;[`_;[`_;[`_;[`_;[`_;\\P_J[@_.ZP_$ZP_$ZP_$ZP_$ZP_$[`_:Y0^F0SEE" + "KV66`X^``X^``X^``X^``X^``X^``X^``Y+#`Z[?`X^``X^``X^``X^``Y/$`X&R" + "`X&R`X&R`X&R`X&R`X*S`YO,`X&R`X&R`Y;'`VZ?`VZ?`X&R`VZ?3S1^;3RYJC\\%" + "&R98NL;W````````````````````````````````````````````````````````" + "````````GZO,`H=4`H=4`H=4`H=4`H=4`H=4`H=4`JML`Q>L`MN$`" + "L-X`L-X`L-X`L-X`L-X`L-X`L-X`L-X`L-X`HM<`H-0`E\\\\`E\\\\`E\\\\`E\\\\`E\\\\`" + "E\\\\`E\\\\`E\\\\`J]H`?[``F,``?;\\`7:T`7:T`7:T`8K$`<;D`0ER1JL6J[P_5[P_5" + "[P_5[P_5[P_5\\0_D]@_W\\`_O\\`_O\\`_O\\`_O]``!]0_S\\P_K\\P_J\\P_J\\P_J\\P_J" + "\\P_J\\P_J\\P_J\\P_J]P_X[`_;\\`_S[`_;[`_;[`_;[`_;[`_;[`_;\\P_H[P_9ZP_$" + "ZP_$ZP_$ZP_$ZP_$[0_/YP^T%QM,UWFJ`X^``X^``X^``X^``X^``X^``YG*`Z?8" + "`X^``X^``X^``X^``XZ_`X:W`X&R`X&R`X&R`X&R`X&R`Z35`X&R`X&R`X&R`X^`" + "`VZ?`XFZ`VZ?`VZ?.BMY<2[\"'!I=@X^``@X^````````````````````````````" + "````````````````````````````````````W^P<6625`M.K`]2K`^//`]>S`].I" + "`]\"C`]\"C`]\"C`]\"C-#13GNK+M@_?FP^]FP^]FP^]FP^]F`^^OP_KM0_?JP_1H`_(" + "H`_(H`_(H`_(H`_(H`_(H`_(H`_(L@_;D0^RJ`_3D0^QD0^QD0^QD0^QD0^QD0^Q" + "D0^QD0^QD0^QD0^Q:LF2/E:0M>(`K]T`IM@`IM@`IM@`IM@`NN0`H=4`H=4`H=4`" + "H=4`H=4`H=4`H=4`K]T`LM\\`C\\H`I-<`M^,`O^<`N^0`L-X`L-X`L-X`L-X`N^0`" + "L]X`E\\\\`E\\\\`E\\\\`E\\\\`E\\\\`E\\\\`E\\\\`E\\\\`G]0`HM<`>;X`7:T`7:T`7:T`7:T`" + "7:T`A,0`7:T`*SYHT.[\"[P_5[P_5[P_5[P_5[P_5[P_5[P_5\\@_E]@_W\\`_O\\`_O" + "]P`!]@_^\\P_J\\P_J\\P_J\\P_J\\P_J\\P_J\\P_J\\P_J\\P_J]@_X[`_;\\@_E[`_;[`_;" + "[`_;[`_;[`_;[`_;\\0_D[`_@ZP_$ZP_$ZP_$[0_*Z0^_Z`_#T_:N\"!)#^XN\\`X^`" + "`X^``X^``X^``X^``Z35`YS-`X^``X^``X^``X^``X^``Y;'`X&R`X&R`X&R`X&R" + "`X&R`YK+`X.T`X&R`X&R`X&R`X2U`VZ?`Y7&`VZ?`VZ?(QMD,1QV/TM\\\\O\\O````" + "````````````````````````````````````````````````````````````````" + "`@X^7&B9P:69`]2K`][(`]2K`^#)`]\"C`]\"C`]\"C`]\"C5TYAC,*WN0_@FP^]FP^]" + "FP^]FP^]H0_%L@_:BP^HBP^HD`^RJ0_.L`_>M@_=JP_0H`_(H`_(H`_(K@_5J@_/" + "D0^QD0^QD0^QD0^QD0^QD0^QD0^QD0^QD0^QD0^QD0^Q3YI^87N`J-D`IM@`IM@`" + "IM@`IM@`IM@`K]T`H=4`H=4`H=4`H=4`H=4`H=4`LM\\`I]@`JMH`CLH`CLH`CLH`" + "CLH`CLH`G-,`L-X`O.4`O.8`P>@`H]8`J=H`JMH`J-D`H]8`F-$`C,D`?L$`<[H`" + "E\\``7:T`7:T`7:T`7:T`7:T`7:T`=[P`7ZX`7*L\\$R%-[0W4[P_5[P_5[P_5[P_5" + "[P_5[P_5[P_5[P_5[P_5\\@_E]@_W]P`#\\P_J\\P_J\\P_J\\P_J\\P_J\\P_J\\P_J\\P_J" + "\\P_J\\P_J]@_Y\\0_I[`_;[`_;[`_;[`_;[`_;[`_;[`_;\\0_?\\0_BZP_$ZP_$[0_2" + "X`^CYP^VY`^UJKR;+215`X^``X^``X^``X^``X^``ZK;`Y/$`X^``X^``X^``X^`" + "`X^``X^``Z#1`X&R`X&R`X&R`X&R`X>X`Y#!`X&R`X&R`X&R`X&R`W2E`W*C`WBI" + "`VZ?^FN&=N=IV?MP_AFP^]FP^]FP^]FP^]L`_=L0_9BP^HBP^HBP^HBP^HBP^H" + "BP^HB`^JG`_!KP_8MP_>K@_5HP_)H`_)H`_)H`_)H`_(H@_&H@_&H0_#H0_#GP^_" + "G0^`F0^[0&MV=9CLIM@`IM@`IM@`IM@`IM@`K-P`H=4`H=4`H=4`H=4`H=4`H=4`" + "M.$`I=D`H=4`E]$`CLH`CLH`CLH`CLH`CLH`CLH`CLH`CLH`F,``G]0`<[H`<[H`" + "<[H`<[H`<[H`<[H`<[H`<[H`CLD`C\\L`7:T`7:T`7:T`7:T`7:T`8*X`=;H`7:T`" + "3I(4-$1B[P_5[P_5[P_5[P_5[P_5[P_5[P_5[P_5[P_5[P_5[P_5\\@_D\\`_U]0_O" + "\\`_S\\`_M\\P_J\\P_J\\P_J\\P_J\\P_J\\P_J\\P_J]0_X]0_T[`_;[`_;[`_;[`_;[`_;" + "[`_;[`_;[`_;\\0_BZ`_)ZP_%XP^;XP^;Z@_!Y0^I?8SUN`X^``X^``X^``Y'\"" + "`ZW>`XZ_`X^``X^``X^``X^``X^``X^``X^``Z76`X&R`X&R`X&R`X&R`Z#1`X&R" + "`X&R`X&R`X&R`X>X`VZ?`Y#!`VZ?`VZ?0RA;!!!!N,3U````````````````````" + "````````````````````````````````````````````````````````````]P,S" + "-D)SZL&B`]2M`]6M`]2L`]:S`]\"C`]\"C`]\"CFX)[77B&M`_@FP^]FP^]FP^]H@_%" + "G`_$K`_9BP^HBP^HBP^HBP^HBP^HBP^HBP^HBP^HBP^HIP_+?@^8?@^8?@^8?@^8" + "?@^8?@^8?@^8?@^8?@^8?@^8?@^8?@^8F@^\\(D-:C+82IM@`IM@`IM@`IM@`IM@`" + "N.,`H=4`H=4`H=4`H=4`H=4`N>(`H]8`H=4`J=H`CLH`CLH`CLH`CLH`CLH`CLH`" + "CLH`CLH`FM$`F=$`B,4`<[H`<[H`<[H`<[H`<[H`<[H`<[H`A\\8`>;P`D[0_*[0_*[0_*[@_5\\@_H\\`_Q]0_P\\P_K\\P_J\\P_J" + "\\`_U\\@_K[`_;[`_;[`_;[`_;[`_;[`_;[`_;[`_;[`_?Y@^MXP^;XP^;Y@^HXP^?" + "YP^K4$]LCU6&`X^``X^``Y?(`ZG:`X^``X^``X^``X^``X^``X^``X^``X^``X^`" + "`Z?8`X&R`X&R`X&R`Z/4`X&R`X&R`X&R`X&R`X&R`Y'\"`VZ?`Y#!`VZ?`VZ?8#ML" + "256&````````````````````````````````````````````````````````````" + "````````````````````````````G:G:@WJ+`]2K`]J[`]2K`^+.`]\"C`]\"C`]\"C" + "OYV)/E-MM0_@FP^]FP^]FP^]M0_=FP^]L0_8BP^HBP^HBP^HBP^HBP^HBP^HBP^H" + "BP^HJ0_,BP^I?@^8?@^8?@^8?@^8?@^8?@^8?@^8?@^8?@^8?@^8?@^8E`^X@0^;" + "#!Y(B<,VL]\\`IM@`IM@`IM@`IM@`N>4`H=4`H=4`H=4`H=4`N>0`H=4`H=4`H=4`" + "L=\\`CLH`CLH`CLH`CLH`CLH`CLH`CLH`F,``G-(`E\\X`<[H`<[H`<[H`<[H`<[H`" + "<[H`<[H`>[\\`A<0`<[H`A<8`7:T`7:T`7:T`7:T`<[H`8:\\`7:T`7:T`3&JDB:&5" + "[P_5[P_5[P_5[P_5[P_5[P_5[P_5[P_5\\@_I[`_@[P_5[P_5[@_/[0_*[0_*[0_*" + "[0_*[0_*[0_*[0_*[0_2\\0_F\\`_P]@_W\\@_D\\0_E\\0_B\\0_@[`_<[@_4Z`_-Z@_\"" + "ZP_+Y0^MXP^;XP^;XP^;ZP_%Y0^HZ0^V&B!.PF^@`X^``Z'2`Y_0`X^``X^``X^`" + "`X^``X^``X^``X^``X^``X^``X^``Z76`X&R`X&R`Y/$`X>X`X&R`X&R`X&R`X&R" + "`X&R`Y?(`WJK`W&B`VZ?`VZ?63QMJ;7F````````````````````````````````" + "````````````````````````````````````````````````````````Y/$A3EJ*" + "_,^H`]_(`]2K`]N[`]\"C`]\"C`]\"CX[B7'RQ3M0_=FP^]FP^]HP_'GP_\"FP^]K@_5" + "BP^HBP^HBP^HBP^HBP^HBP^HBP^HG`_\"C0^JC0^K?@^8?@^8?@^8?@^8?@^8?@^8" + "?@^8?@^8?@^8?@^8DP^R@`^?=/R2$25-CLH`F=$`J=H`IM@`IM@`IM@`L=X`H=4`" + "H=4`H=4`N>(`H=4`H=4`H=4`H=4`K=T`CLH`CLH`CLH`CLH`CLH`CLH`ELX`GM0`" + "CLH`H]<`<[H`<[H`<[H`<[H`<[H`<[H`=+L`C\\P`<[H`<[H`:[4`7:T`7:T`7:T`" + "7JT`>+X`7:T`7:T`7:T`,T5PMM*R[P_5[P_5[P_5[P_5[P_5[P_5[P_8\\`_M[P_5" + "[P_5[P_5\\@_?[0_*[0_*[0_*[0_*[0_*[0_*[0_*[0_*[0_*[0_*[@_3\\0_EY`^T" + "Y`^TY`^TY`^TY`^TY`^TY`^TY`^XZP_)XP^Y0^IY`^TR_\"H!A%\"" + "]8BY`ZO<`Y/$`X^``X^``X^``X^``X^``X^``X^``X^``X^``X^``X^``Y_0`X&R" + "`X:W`Y3%`X&R`X&R`X&R`X&R`X&R`X&R`YO,`Y7&`VZ?`VZ?]&B9*#)CW.D9````" + "````````````````````````````````````````````````````````````````" + "````````````````````````=H*SHI\"1`^+/`]2K`]2K`]N``]\"C`]\"C`L^C%1Y*" + "HO?,FP^]FP^]L`_=FP^]FP^]K0_4BP^HBP^HBP^HBP^HBP^HBP^HD`^SE`^VBP^H" + "CP^M?@^8?@^8?@^8?@^8?@^8?@^8?@^8?@^8?@^8CP^MAP^C?@^89-N&(T%ACLH`" + "CLH`L=\\`IM@`IM@`JMD`HM4`H=4`HM4`N.(`H=4`H=4`H=4`H=4`H=4`GM,`CLH`" + "CLH`CLH`CLH`CLH`E,X`H-0`CLH`CLH`I=<`<[H`<[H`<[H`<[H`<[H`<[H`E\\``" + "<[H`<[H`@,$`7:T`7:T`7:T`7:T`A<4`7:T`7:T`7:T`7*L\\#QQ)X`/.[P_5[P_5" + "[P_5[P_5[P_5\\P_I\\0_@[P_5[P_5[P_5[P_5\\@_H[0_*[0_*[0_*[0_*[0_*[0_*" + "[0_*[0_*[0_*[P_5[P_9\\0_=Y`^TY`^TY`^TY`^TY`^TY`^TY`^T[@_7ZP_$XP^;" + "XP^;XP^;Z@^_XP^;Z0^[EK>%+\"96`ZW>`XZ_`X^``X^``X^``X^``X^``X^``X^`" + "`X^``X^``X^``X^``X^``Y?(`X&R`Z+3`X&R`X&R`X&R`X&R`X&R`X&R`X&R`YK+" + "`XFZ`VZ?`W:GF%>(3UN,`0T]````````````````````````````````````````" + "````````````````````````````````````````````````````T]`06F65`.'/" + "`]2K`]2K`^#+`]\"C`]\"C`]\"C6%)G<:J=FP^]HP_'GP_\"FP^]FP^]JP_2BP^HBP^H" + "BP^HBP^HBP^HB`^IH@_%BP^HBP^HCP^N?@^8?@^8?@^8?@^8?@^8?@^8?@^8?@^8" + "B@^GC0^K?@^8?@^85KU\\-%EXCLH`CLH`D,L`KMP`IM@`M^,`H=4`I-8`MN$`H=4`" + "H=4`H=4`H=4`H=4`IM@`CLH`CLH`CLH`CLH`CLH`D\\T`HM<`CLH`CLH`CLH`E<\\`" + "<[H`<[H`<[H`<[H`<[H`D\\T`<[H`<[H`<[H`D,P`7:T`7:T`7:T`;[@`9+$`7:T`" + "7:T`7:T`3(X.*SM;[P_5[P_5[P_5[P_5[`_=\\P_L[P_5[P_5[P_5[P_5[P_5[P_5" + "\\@_K[0_*[0_*[0_*[0_*[0_*[0_*[0_*[0_*[P_7[`_6[0_*[P_6Y`^TY`^TY`^T" + "Y`^TY`^TY`^T[0_.Y`^UZP_*XP^;XP^;XP^;Y`^XXP^;Z@^^8WME7DAY`Y'\"`X^`" + "`X^``X^``X^``X^``X^``X^``X^``X^``X^``X^``X^``X^``XBY`Y_0`X&R`X&R" + "`X&R`X&R`X&R`X&R`X&R`X&R`YW.`VZ?`X2U`6:7*RM`]2K`]2K`]:Q`]*J`]\"C`]\"CI)\"20E9MFP^]" + "L`_>FP^]FP^]FP^]J0_/BP^HBP^HBP^HBP^HBP^HJ@_.BP^HBP^HBP^HD0^P?@^8" + "?@^8?@^8?@^8?@^8?@^8?@^8AP^AC`^P?@^8?@^8?@^82J1S0FN,CLH`CLH`CLH`" + "I-<`IM@`N^,`I=@`LM``H=4`H=4`H=4`H=4`H=4`H=4`K]X`CLH`CLH`CLH`CLH`" + "DKX`<[H`<[H`<[H`<[H`A\\4`>;T`<[H`<[H`<[H`" + "C\\H`7:T`7:T`7:T`?L$`7:T`7:T`7:T`7:T`0F_.77%Y[P_5[P_5[P_5\\P_K[`_>" + "[P_5[P_5[P_5[P_5[P_5[P_5[P_5\\@_E[0_*[0_*[0_*[0_*[0_*[0_*[0_*[P_7" + "[P_6[0_*[0_*[0_+Y`^TY`^TY`^TY`^TY`^TZ0^\\Z@_!Y`^TZ`_+XP^;XP^;Z0^V" + "XP^;XP^;ZP_!+S98E4M\\`WFJ`XBY`YC)`Z'2`Z35`Z#1`Y3%`X^``X^``X^``X^`" + "`X^``X^``Y?(`Y#!`XFZ`X&R`X&R`X&R`X&R`X&R`X&R`X&R`X&R`YS-`W^P`TQ]" + "JFB9+CIK]P,S````````````````````````````````````````````````````" + "````````````````````````````````````````````````SML+5F\"0`=*J`]2K" + "`]2K`^'+`]\"C`]\"C\\]3##QI'F/O!G@_!FP^]FP^]FP^]I`_,BP^HBP^HBP^HBP^H" + "I@_)BP^HBP^HBP^HBP^HDP^R?@^8?@^8?@^8?@^8?@^8?@^8@P^>E0^T?@^8?@^8" + "?@^8?@^80(YL4'JBCLH`CLH`CLH`CLH`LM\\`N.,`L-\\`H=4`H=4`H=4`H=4`H=4`" + "H=4`H=4`K]T`CLH`CLH`CLH`D,L`IM@`CLH`CLH`CLH`CLH`GM,`<[H`<[H`<[H`" + "<[H`?;``@L0`<[H`<[H`<[H`<[H`@\\0`7:T`7:T`@L,`7:T`7:T`7:T`7:T`7:T`" + ".%*-D*F:[P_5[`_<\\P_L[P_5[P_5[P_5[P_5[P_5[P_5[P_5[P_5[P_5[`_:[0_*" + "[0_*[0_*[0_*[0_*[0_*[`_:[@_4[0_*[0_*[0_)Z0^ZY`^TY`^TY`^TY`^TY`^T" + "[P_4Y`^TY`^TZ@_$XP^;XP^;Z@_#XP^;XP^;U?BT!1!!SV*3`W>H`W>H`W>H`W>H" + "`W>H`W>H`WFJ`XBY`YC)`Z'2`Z35`Z#1`Y3%`Z'2`YW.`X&R`X&R`XBY`Y#!`Y/$" + "`Y;'`Y;'`Y7&`Y?(`VR=`TI[_7FJ*\"]@KKKK````````````````````````````" + "````````````````````````````````````````````````````````````````" + "`````````````0T]8&R=J8Z&`]2K`]2K`][%`]\"C`]\"C`]W\"5$]D;:>>FP^]FP^]" + "FP^]FP^]I@_(BP^HBP^HBP^HF0^[D@^PBP^HBP^HBP^HBP^HE0^T?@^8?@^8?@^8" + "?@^8?@^8?`^:FP^\\?@^8?@^8?@^8?@^8?@^8-GIE686WCLH`CLH`CLH`CLH`H-8`" + "L]``H=4`H=4`H=4`H=4`H=4`H=4`H=4`H=4`H]8`CLH`CLH`C\\L`I]H`CLH`CLH`" + "CLH`CLH`CLH`I-D`<[H`<[H`<[H`=;L`C\\H`<[H`<[H`<[H`<[H`=+H`:+,`7:T`" + ":K4`:+,`7:T`7:T`7:T`7:T`7:T`&\"=6Q^2\\\\`_O[`_;[P_5[P_5[P_5[P_5[P_5" + "[P_5[P_5[P_5[P_5[P_9[0_+[0_*[0_*[0_*[0_*[0_*[`_9[@_3[0_*[0_*[0_*" + "[P_2Y`^TY`^TY`^TY`^TY`^T[@_2Y`^TY`^TY`^TZ0^WXP^;Y0^FX`^@XP^;XP^;" + "D*R*%!9'`':G`W>H`W>H`W>H`W>H`W>H`W>H`W>H`W>H`W>H`W>H`W>H`W>H`XR]" + "`Z/4`WNL`W&B`V.4`V*3`V*3`V*3`V*3`V*3`X&R`X\"Q`TI[`W*CD6V>.45V]`0T" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````U.$11U*\"^LZM`]2K`]2L" + "`]>V`]\"D`]2MJXZ!,T]HG0^_FP^]FP^]FP^]H@_&BP^HBP^HCP^MFP^^BP^HBP^H" + "BP^HBP^HBP^HE0^V?@^8?@^8?@^8?@^8?@^8G0^^?@^8?@^8?@^8?@^8?@^8?@^8" + "+FE?7XO-CLH`CLH`CLH`F,``I-8`AL4`J]L`H-4`H=4`H=4`H=4`H=4`H=4`H]8`" + "DH`W>H`W>H`W>H`W>H`W>H`W>H" + "`W>H`W>H`W>H`W>H`X*S`YO,`X6V`VN<`V*3`V*3`V*3`V*3`V*3`V*3`V*3`XN\\" + "`WJK`TQ]`V66Z7.D1E*#O\"`][&`]2K`^+.`]FW`]\"C]<6>\"AA%COJTIP_+FP^]FP^]" + "GP_\"BP^HBP^HIP_+BP^HBP^HBP^HBP^HBP^HBP^HE0^V?@^8?@^8?@^8?@^8G@_\"" + "?@^8?@^8?@^8?@^8?@^8?@^8?@^8)UI:88_@CLH`CLH`ELX`GM0`HM8`@L,`@L,`" + "GM,`I]D`H=4`H=4`H=4`H=4`K=L`CLH`CLH`J=H`CLH`CLH`CLH`CLH`CLH`CLH`" + "CLH`BL<`<[H`<[H`D\\X`<[H`<[H`<[H`<[H`<[H`<[H`DH`W>H`W>H`W>H`W>H`W>H`W>H`W>H`W>H`WNL`YW.`WRM`W>H`Y/$`V*3`V*3" + "`V*3`V*3`V*3`V*3`VF:`XBY`V25`VB9`U2%`VB95UF*9'\"A_PL[````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````Y/$A,S]OXK:3`]_*`]N\\`]['" + "`]\"C`]\"C2$EA5[\"\"CP^NJ`_3FP^]F`^^BP^HJ0_,BP^HBP^HBP^HBP^HBP^HBP^H" + "BP^HEP^W?@^8?@^8?@^8GP^`?@^8?@^8?@^8?@^8?@^8?@^8?@^8?@^8($Q58I'R" + "CLH`E,X`G]0`CLH`IM<`@L,`@L,`@L,`C,D`K=P`H=4`H=4`H=4`L-X`CLH`JML`" + "CLH`CLH`CLH`CLH`CLH`CLH`CLH`E,T`=+H`<[H`BL<`>+T`<[H`<[H`<[H`<[H`" + "<[H`<[H`C\\P`9[,`:[4`7:T`7:T`7:T`;+8`=KP`3*(`-E&1@YV&Z@^^\\0_=[P_>" + "[P_5[P_5[P_5[P_5[P_5[P_5[P_5[P_5[P_5\\0_J[0_*[0_*[0_*[`_>[@_/[0_*" + "[0_*[0_*[0_*[0_*[0_*[`_9Y`^TY`^TY`^T[@_6Y`^TY`^TY`^TY`^TZ`_&XP^;" + "Z@^_XP^;XP^;XP^;?Y6$$A9'^G.D`W>H`W>H`W>H`W>H`W>H`W>H`W>H`WBI`YO," + "`X6V`W>H`W>H`Y#!`V*3`V*3`V*3`V*3`V*3`V*3`W2E`WNL`V*3`X*S`TM\\`W.D" + "K7BI!!!!X.T=````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````I[/D55=Y`\\Z>`]FY`^'/`]\"C`]\"CFX)[-V%LBP^IBP^II0_+G`_#H0_$" + "C0^JBP^HBP^HBP^HBP^HBP^HBP^HBP^HF0^Y?@^8?@^8F`^`?@^8?@^8?@^8?@^8" + "?@^8?@^8?@^8?@^8?@^8'4-4:);ZD\\T`HM<`CLH`CLH`J-D`@L,`@L,`@L,`@L,`" + "@L,`H]<`I-<`H=4`J-D`J]P`CLH`CLH`CLH`CLH`CLH`CLH`CLH`CLH`H]8`<[H`" + "?;``@\\,`<[H`<[H`<[H`<[H`<[H`<[H`<[H`?[``A,0`7:T`7:T`;K<`=+H`2)``" + "19X`=+D]$B%/O-VEZ@^^Z@^^Z@^`[`_?\\0_>[P_5[P_5[P_5[P_5[P_5[P_5[P_5" + "\\@_C[0_*[0_*\\0_@[0_/[0_*[0_*[0_*[0_*[0_*[0_*[0_*Z`_.Y`^TY`^TZ`_%" + "Z@^[Y`^TY`^TY`^TY`^T[0_,XP^;Z0^ZXP^;XP^;W`R:(RQ2;#IK`W>H`W>H`W>H" + "`W>H`W>H`W>H`W>H`Y/$`XZ_`W>H`W>H`W>H`WBI`X*S`V*3`V*3`V*3`V*3`V*3" + "`X&R`VZ?`V*3`W.D`U&\"`WRMY&.435F*J[?H````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````^@8V2U>(L9>0`\\Z>`]J\\`]*K`]W\"" + "Y<:S#1M'APBFBP^IBP^IF0^\\J@_/F0^\\BP^IBP^HBP^HBP^HBP^HBP^HBP^HE`^Z" + "?@^8F@^\\?P^9?@^8?@^8?@^8?@^8?@^8?@^8?@^8?@^8?@^8&SM4;9K^I-<`CLH`" + "CLH`CLH`I]D`@L,`@L,`@L,`@L,`@L,`@L,`E,X`K-P`K=L`CLH`CLH`CLH`CLH`" + "CLH`CLH`CLH`CLH`CLH`H]<`=;L`CLD`<[H`<[H`<[H`<[H`<[H`<[H`<[H`=;L`" + "@,,`7:T`=+H`;K<`1IX`19X`19X`9[(`-X$*%\"%+Y`V]Z@^^Z@^^Z@^^Z@^^Z@_!" + "[`_@[`_:[P_5[P_5[P_5[P_5[P_5[@_3[0_*\\@_A[0_.[0_*[0_*[0_*[0_*[0_*" + "[0_*[0_*[0_*Z0^]Y`^TY`^U[0_-Y`^TY`^TY`^TY`^TY`^TZP_)YP^RXP^;XP^;" + "XP^;FKQ^!1!!UV66`W>H`W>H`W>H`W>H`W>H`X:W`Y'\"`W>H`W>H`W>H`W>H`W>H" + "`Y;'`V*3`V*3`V*3`V*3`V*3`XR]`V25`V*3`V*3`W.D`W*C_$Q].#QM;'BI_@HZ" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````TM\\/4EZ.\\<&9`\\Z>`][)`\\R9`\\R9,#549LF.BP^IBP^IBP^IGP_!?0^7?P^9" + "C`^OG`_!H@_%F0^YBP^HBP^HF0^\\E@^V@@^=?@^8?@^8?@^8?@^8?@^8?@^8?@^8" + "?@^8?@^8?@^8&394?JH`W>H`W>H`W>H`X2U`YO," + "`WFJ`W>H`W>H`W>H`W>H`W>H`W^P`W*C`V*3`V*3`V*3`V:7`XJ[`V*3`V*3`V*3" + "`X\"Q`V66`U.$9$EZ,CYOZ_@H````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````DY_07%U\\`\\Z>`]N^`]BT`\\R9?6EK" + "2'EXBP^IBP^IBP^II@_)?0^7?0^7?0^7?0^7?0^7?0^7B`^KG0^_I@_,F`^_F@^\\" + "FP^\\FP^\\F0^ZF0^ZEP^YE@^UD`^UD0^PCP^NBP^H&3%6;9X\"CLH`CLH`CLH`CLH`" + "F],`@L,`@L,`@L,`@L,`@L,`@L,`H=8`F-(`:[4`:[4`:[4`;;8`A<0`G=,`I=<`" + "F<``CLH`CLH`F](`<[H`<[H`<[H`>[\\`B,<`CLH`C\\P`C,D`@\\,`BL8`19X`19X`" + "19X`19X`19X`19X`:K4`19X`*#UKDZ^/Z@^^Z@^^Z@^^Z@^^Z@^^Z@^^Z@^^Z@^^" + "Z@^^ZP_'\\0_D[P_6\\P_F\\0_B[0_,[0_*[0_*[0_*[0_*[0_*[0_*[0_*[0_*[0_*" + "[P_:Y`^TZ`_)Y`^WY`^TY`^TY`^TY`^TY`^TY`^TY`^YX`^BXP^;YP^OK]6%!!!!" + "MEB)`W>H`W>H`WRM`YO,`WVN`W>H`W>H`W>H`W>H`W>H`W>H`W>H`Y?(`V*3`V*3" + "`V*3`W&B`W^P`V*3`V*3`V*3`VV>`V\"1`V25DT%R!!!!SML+````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "]0$Q1%\"!K)>5`\\Z>`]_'`\\R:QZ\"$&RM0BP^IBP^IBP^IF0^Z?P^9?0^7?0^7?0^7" + "?0^7?0^7?0^7?0^7GP_\"=@^.<`^,<`^,<`^,<`^,<`^,<`^,<`^,<`^,<`^,<`^," + "@0^<%S-1@*?`CLH`CLH`CLH`CLH`DY`^W[0_)Y`^TY`^TY`^TY`^TY`^TY`^T" + "YP^UZ`_%XP^H`W>H`W>H`W>H`W>H" + "`W>H`W>H`W>H`XR]`V66`V*3`V*3`WRM`W*C`V*3`V*3`V*3`V*3`WRM`W6FO3IK" + "(2Q=K;GJ````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````TM\\/2U>(Y[N9`]J_`][#`,J8%!U'H`W>H`W>H`W>H`W>H`W>H`W>H`W>H`W>H`W>H`XBY`V*3`V*3`XJ[`VB9`V*3" + "`V*3`V*3`V*3`WNL`WJKV$!Q,3MLC9G*`@X^````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "G:G:<'JI`,R=`]F[`]2N8%1A5XZ$BP^IBP^IE0^VH0_%?0^7?0^7?0^7?0^7?0^7" + "?0^7A`^E?@^8E`^W<`^,<`^,<`^,<`^,<`^,<`^,<`^,<`^,<`^,AP^D=@^.%SA/" + "7I#YH]<`CLH`CLH`E\\\\`@L,`@L,`@L,`A,0`G]0`@L,`@L,`@L,`C\\H`:[4`:[4`" + ":[4`:[4`:[4`:[4`:[4`A<0`H`W>H`W>H`W>H`W>H`W>H`W>H`W>H`W>H`W>H`W>H" + "`Y3%`V*3`V.4`XN\\`V*3`V*3`V*3`V*3`V*3`V>8`X\"QWT1U'!A);WJK^`@X````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````^`@X9W.DA'F$`]R``]J]KHU\\*SQ;BP^IBP^I" + "E0^UFP^\\?0^7?0^7?0^7?0^7?0^7?0^7G0^^?0^7F0^\\<`^,<`^,<`^,<`^,<`^," + "<`^,<`^,<`^,<`^,DP^T<`^,&#Q/6XSS@L(`H]4`CLH`G]4`@L,`@L,`A,4`G],`" + "@L,`@L,`@L,`@L,`?;``:[4`:[4`:[4`:[4`:[4`:[4`A,4`<[D`:[4`=+D`4Z8`" + "4Z8`4Z8`4Z8`4Z8`4Z8`;;8`6ZH`4Z8`=[L`19X`19X`19X`19X`<;@`19X`19X`" + "094O\"!1$O^\"GZ@^^Z@^^Z@^^Z@^^Z@^^Z@^^ZP_#[P_>Z`_(Z@^^Z@^^Z@^^[P_9" + "Y@^KY@^KY@^KY@^KY@^KY@^KY@^KY@^KY@^KY@^LZP_&[`_>[0_/ZP_\"Z@^YYP^O" + "Y0^@X0^2X0^0X0^0Y`^SX`^=W0][W0]^SOB3#!9%@D-T`W>H`W>H`W>H`W>H`W>H" + "`W>H`W>H`W>H`W>H`W>H`W>H`WNL`W>H`VJ;`X6V`V*3`V*3`V*3`V*3`V*3`V*3" + "`X>XZ$]`)\"!18&R=]@(R````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````Z/4E" + ",CYOQZ61`]:V]M*\\#!9$>.F;BP^IE0^WBP^IBP^H?0^7?0^7?0^7?0^7?0^7F@^Z" + "?0^7D@^S<`^,<`^,<`^,<`^,<`^,<`^,<`^,<`^,C@^K<`^,<`^,&T516H?F@<(`" + "F=$`CLH`I=@`@L,`AL8`G=,`@L,`@L,`@L,`@L,`AL4`:[4`:[4`:[4`:[4`:[4`" + ":[4`A,4`<[D`:[4`;+8`6:D`4Z8`4Z8`4Z8`4Z8`4Z8`9*``8JX`4Z8`4Z8`;K8`" + "19X`19X`19X`<+@`19X`19X`19X`+VK@(3%2Z@^^Z@^^Z@^^Z@^^Z@^^Z`_$[P_>" + "ZP_'Z@^^Z@^^Z@^^Z@^^ZP^`Z@^XY@^KY@^KY@^KY@^KY@^KY@^KY@^KY@^KY@^K" + "Y@^K[0_-Z`_,X0^0X0^0X0^0X0^0X0^0X0^0X0^0Z0^ZYP^LW0][W0][Y0^J;H!L" + "#Q1%\\&^@`W>H`W>H`W>H`W>H`W>H`W>H`W>H`W>H`W>H`W>H`W>H`Y;'`WFJ`W>H" + "`V*3`V*3`V*3`V*3`V*3`V*3`WBIZ6J;*R9756&2\\/TM````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````P@0^=0^-<`^,<`^,<`^,<`^,<`^,<`^," + "<`^,C0^K<`^,<`^,'TY36(;8@<(`@<(`J-D`J-H`AL8`FM$`@L,`@L,`@L,`@L,`" + "@L,`D\\X`:[4`:[4`:[4`:[4`:[4`A,0`<[D`:[4`:[4`?+\\`4Z8`4Z8`4Z8`4Z8`" + "4Z8`7:T`:[4`4Z8`4Z8`5:<`3Z4`19X`19X`6ZP`3:(`19X`19X`19X`+4B#;85Z" + "Z@^^Z@^^Z@^^ZP_([P_>ZP_$Z@^^Z@^^Z@^^Z@^^Z@^^Z@^^[@_8Y@^KY@^KY@^K" + "Y@^KY@^KY@^KY@^KY@^KY@^KY`^YZ`_)Y@^KY@^RX0^0X0^0X0^0X0^0X0^0X0^0" + "Y`^ZX0^0X`^@W0][XP^=S?UZ$!E&=CAI`VV>`X*S`Y3%`YK+`Y7&`XBY`W>H`W>H" + "`W>H`W>H`W>H`X:W`XBY`VZ?`V*3`V*3`V*3`V*3`V*3`V*3`V25YW>H*B=85V.4" + "[OLK````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "`````````````````````````````````````````````````````````P\\_CIK+" + "3$QK`=6TKYF6)C56BP^IE`^XBP^IGP_\"?0^7?0^7?0^7?0^7F@^Z?0^7?0^7?0^7" + "A`^D<`^,<`^,<`^,<`^,<`^,<`^,D0^P<`^,<`^,<`^,(UA65('%@<(`@<(`C,D`" + "J]L`F=$`@L,`@L,`@L,`@L,`@L,`@L,`F](`:[4`:[4`:[4`:[4`A,0`<[D`:[4`" + ":[4`:[4`AL4`4Z8`4Z8`4Z8`4Z8`5Z<`=+D`4Z8`4Z8`4Z8`;K8`19X`19X`29``" + "9*``19X`19X`19X`0),L!Q-#N-BCZ@^^[0_*[`_[X`4Z8`" + "4Z8`4Z8`4Z8`>;P`19X`19X`<[H`19X`19X`19X`19X`*F+6(3!3[0[-[`_1G\">@<(`@<(`CLH`F]$`@<,`" + "ELX`@L,`@L,`@L,`@L,`@L,`EL\\`:[4`:[4`A,,`<[H`:[4`:[4`:[4`:[4`:[4`" + "0^3@0^<<`^,<`^,<`^,<`^," + "-H1C/66,@<(`@<(`H=4`F](`<+@`X`VJ;`XN\\`U*#`U*#`U*#" + "`U*#`U*#`U2%`W^P`VB9IE:'*S9G@8V^^@8V````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "`````````````````````````````````````````````````````P\\_CYO,0TAQ" + "0T):4)%_BP^IBP^IE`^X?0^7?0^7G@_\"?0^7?0^7?0^7?0^7@`^@<`^,<`^,<`^," + "<`^,E`^W<`^,<`^,<`^,<`^,<`^,/YAI,E5Y@<(`@\\,`C,@`F\\``<+@`<+@`<+@`" + "D`^6<`^,<`^,<`^,<`^,<`^,2:YO)$%F" + "@<(`GM,`@<(`G=,`<+@`<+@`<+@`<+@`?;``FM(`C,D`@L,`<[H`:[4`:[4`:[4`" + ":[4`:[4`:[4`:[4`A,0`4Z8`;K4`6ZL`4Z8`4Z8`4Z8`4Z8`4Z8`4Z8`=[P`=+L`" + "19X`6ZP`:K0`.Y<`.9<`7ZX_&2M(" + "_&R=7CQM!!!!K+CI`@X^````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````]0$Q;WJK*#-D" + "27]VF0^\\BP^IGP_%C0^M?0^7?0^7?0^7?0^7?0^7?0^7D`^U<`^,<`^,E@^W<`^," + "<`^,<`^,<`^,<`^,<`^,4\\5V%BU4@<(`F=$`@<(`F],`<+@`<+@`<+@`<+@`<+@`" + ";X`7JP`:K0`.Y<`.9<`.9<`1YX`.GS^!Q-#TOFFYP^P" + "YP^PYP^PYP^PYP^PY`^V[@_7Z@_!Z@^^Z@^^Z@^^Z@_!Y`^WY@^KZ@_%Z0^[Y@^K" + "Y@^KY@^KY@^KY@^KY@^KY@^KY@^MY0^CX0^0X0^4YP^UX0^0X0^0X0^0X0^0X`^H" + "X`^?W0]^M^-Q#!E%:C1E`VJ;`VJ;`VJ;`WFJ`XN\\`VN<`VJ;`VJ;`VJ;`XN\\`U*#" + "`U*#`U*#`U*#`W&B`VZ?`U*#[6J;/R]@&B97QM,#````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````^PX>X!!!!4ZUZHP_&G@_!G@^`?0^7?0^7?0^7?0^7" + "?0^7?0^7FP^\\<`^,@`^?=`^1<`^,<`^,<`^,<`^,<`^,<`^,7MY^!A1#C\\@^@<(`" + "@<(`F],`<+@`<+@`<+@`<+@`<+@`<[H`D\\T`6*D`9K$`?[``A\\4`@,$`:[4`:[4`" + ":[4`:[4`=+H`(`X\"Q`U2%`U*#SF.4(!]0/TM\\W.D9" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "`````````````````````````````````````````````````````@X^7FJ;\"!=$" + "?P^9H0_#F0^Z?0^7?0^7?0^7?0^7?0^7?0^7E@^W<`^,E0^V<`^,<`^,<`^,<`^," + "<`^,<`^,<`^,:ON&!!!!D<(F@<(`@<(`G=,`<+@`<+@`<+@`<+@`<+@`E,T`B<@`" + "6*D`6*D`6*D`6*D`6*D`:K4`@\\(`A\\4`?+\\`?\\$`;K8`=KH`=KP`<[@`:+,`6*H`" + "1I\\`1)T`=[P`.9<`.9<`.9<`.9<`.9<`:K,`-8XN\"19%H,\".YP^PYP^PYP^PYP^P" + "YP^PYP^PYP^PYP^PYP^PYP^PZ`_)[P_1[P_:Z@^`Y@^KY@^KY@^KY@^KY@^KY@^K" + "Y@^KY@^KY@^KY@^KY@^RX0^6Y@^OX0^0X0^0X0^0X0^0X0^0Y@^EY@^JXP^<66IF" + "\"A)#T5B)`WBI`Y#!`VV>`VJ;`VJ;`VJ;`VJ;`VJ;`XN\\`U*#`U*#`U*#`W&B`VR=" + "`U*#`U*#K%>(#!5&8&R=[/DI````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````\\O\\O,CYO;,Z3?P^9GP_#A@^CE@^WE`^ZC0^K?0^7?0^7" + "A0^BB@^I=0^-<`^,<`^,<`^,<`^,<`^,<`^,<`^,<`^,\"1E%:YT&@<(`@<(`G=,`" + "<+@`<+@`<+@`<+@`AL8``B7" + "D@^Q@`^A;X`0YT`0YT`0YT`0YT`0YT`0YT`0YT`;;8`1Y\\`" + "19\\`.9<`.9<`.9<`0)L`4Z<`.98_'S)A<8MWYP^PYP^PYP^PYP^PYP^PYP^PYP^P" + "YP^PYP^PY`^V[@_2Y`^VZ@^\\XP^:XP^:XP^:X`^?Y`^XZP_&ZP_$Y@^OY@^KY@^K" + "Y@^KZ@_%Y@^QX0^0X0^0X0^0X0^0X0^0X0^0XP^EX`^@ILM\\!Q%\":41U`W&B`VJ;" + "`VJ;`VJ;`VJ;`VJ;`VJ;`VJ;`XN\\`U*#`U*#`W:G`V:7`U*#`U*#_%6&7S=H!!!!" + "JK;G`0T]````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "`````````````````0T]=X.T4X6&?P^9H0_#0^4" + "-(A?,%&!B,<`@<(`G=0`<+@`<+@`B<4`_Z9C`^O>@^4+T`6*D`6JH`2:$`0YT`0YT`0YT`0YT`" + "19X`:+(`0YT`0YT`3*,`.9<`.9<`3Z0`1)X`.9<`,XDE!Q-#IL>1YP^PYP^PYP^P" + "YP^PYP^P[@_0Z@_#YP^PYP^PYP^PYP^PZP_)XP^:XP^:XP^:XP^:XP^:XP^:XP^:" + "XP^:XP^:YP^PZ0^XZ0^\\W0]^W0]^W0]^W0]^W0]^W@^$Y@^JY0^HU@.).#9;%!9'" + "V%N,`VJ;`VJ;`VJ;`VJ;`VJ;`VJ;`VJ;`XN\\`U^0`WRM`U*#`U*#`U*#`U*#J4AY" + "#11%56&2ZOZ0_#X`^?Z0^XW0]`W0]^W0]^W0]^W0]^" + "X@^4XP^;Y0^JV@B'0T9?\"A)#P5.$`VJ;`VJ;`VJ;`VJ;`VJ;`VJ;`VJ;`XN\\`WRM" + "`V&2`U*#`U*#`U*#]T]`9S-D!!!!AY/$]P,S````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````\\_`P256&7JR+@0^;C0^J+P`0YT`0YT`0YT`0YT`;;8`0YT`0YT`" + "0YT`<+D`.9<`.9<`:[4`.9<`.9<`-Y$U$2!/A:*!YP^PYP^PZ@_&Z`_,YP^PYP^P" + "YP^PYP^PYP^PYP^PYP^PZP_\"XP^:XP^:XP^:XP^:XP^:XP^:XP^:Z@^YYP^NXP^:" + "Y0^DX0^2W0]^W0]^W0]^W0]^X`^DWP^*XP^AW@V)4%E@!A%\"K5V.`VV>`VJ;`VJ;" + "`VJ;`VJ;`VJ;`VJ;`XR]`WRM`U*#`U*#`U*#`U*#MSYO(QU.&B97NL;W`@X^````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````V^@8,C]O?.\"CD0^Q<`^," + "`^7`W:G`WFJWFR=" + "2R]@!!!!=(\"QY_0D````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````M<'R35N)=OZ3EP^Y@^4[\\`<+@`<+@`<+@`<+@`>;T`6*D`6*D`" + "8:X`;+4`6*D`6*D`6*D`6*D`9[(`0YT`0YT`4*4`6*@`0YT`0YT`0YT`6ZP`.9<`" + "1YX`3*(`.9<`.9<`.)4]%2A@;(-Y[0_1YP^RYP^PYP^PYP^PYP^PYP^PYP^PYP^P" + "YP^PYP^QY`^TXP^:XP^:XP^:XP^:XP^:Z@_!Y0^GXP^:XP^:XP^:Z0^]W0]^W0]^" + "W0]^WP^)Y0^FW0]^W@^,XP^7:G]E!!!!ASEJ`V\"1`V\"1`V\"1`V\"1`V\"1`VV>`XN\\" + "`W:G`T9W`T9W`T9W_$5VA#5F\"Q-$.45VQ=(\"`@X^````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "`````````````````````````````````````````0T]>H:W*E=>APRC?P^:X`V:7`WVN`VB9`T9W`T9W`TAY[&N<" + "8#5F!!!!9'\"AVN<7````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````\\_`P=X.T/4IZ8;V*<`^,+X`B,4`>KX`6:D`6*D`6*D`6*D`6*D`6*D`=[L`0YT`;;8`0YT`0YT`0YT`" + "0YT`0YT`4J8`6JL`/IH`0)L`:+(`/YH`1G[V!1%\"P.:5Y0^EY0^H[0_/Y`^VYP^P" + "YP^PYP^PYP^PYP^PYP^PZP_&XP^:XP^:Y`^UYP^RXP^:XP^:XP^:XP^:XP^:XP^:" + "YP^QW0]^W0^!Y@^MW0]^W0]^W0]^Y0^M?9UL!!!!:3!A`GJK`XFZ`W&B`V\"1`VB9" + "`W^P`T9W`T9W`TU^`':GG41U%!I+-D)SO\\O\\_`P\\````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````_`P\\ML+S$1Y.,&UB;0*'+X`D)9M!!!!" + "5S=H`'6F`V\"1`V\"1`V\"1`X2U`UJ+`T9W`U2%`W:GU$AY/2U>!!!!DI[/\\O\\O````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````X^`@5V.4,TAN=>.;D`^S" + "B@^GD`^TA0^B:`^\":`^\":`^\":`^\":`^\":O^&!Q5$5HS[E,X`8J``8J``8J``8Z``" + "AL4`7ZT`>;P`>KT`9[(`6*D`6*D`6*D`<[H`7:L`0YT`0YT`0YT`0YT`1I\\`6*D`" + ">;P`2)``,)$`,)$`1IT`,7;Z!!!!M=J0Y0^EY0^EY0^EY0^EY0^EY0^EZ@_$ZP_$" + "YP^PYP^PZ@^\\ZP^_Y0^HXP^:XP^:XP^:XP^:XP^:XP^:XP^:Y`^SW@^#XP^>WP^0" + "W0]^W0]^W0]^VP6:6W%C!!!!62Q=_EZ/`V\"1`V\"1`V^@`W:G`T9W`U^0`W:GZTEZ" + ":3AI&B977&B9V.45````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````^P@^3D0^Q>0^2=0^-:`^$:0]_8P]W8P]W" + ")6%7,5\";C\\D`8J``8J``8J``A\\8`?K``2J$`2J$`2J$`3*(`9[,`>KT`=KL`>KX`" + ";K8`<+D`;+4`8*\\`3Z,`.I<`:K4`,Y(`,)$`,)$`/9@`3*$_'C1P2%U?Y0^EY0^E" + "Y0^EY0^EY0^EY0^EY0^EY0^EY0^H[0_/ZP_-Z0^[XP^:XP^:XP^:XP^:XP^:XP^:" + "XP^:XP^:X`^BX@^9Y0^MW0^!W0]^W0]^W0]^L]F\"*S93!A%\"?39G`5^0`V\"1`V.4" + "`X.T`TY_`V>8`V^@^T5VBCIK$1E*)C)CL[_P_0DY````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````Q-$!&B97+'!:8`5[" + ";@^#C@^M8P]W8P]W8P]W8P]W8P]W3-)J!1-#;JHB8J``8J``<;D`:K0`?+\\`2J$`" + "2J$`2J$`2J$`2J$`2J$`>;P`.)8`.)8`.)8`.)8`.)8`.)8`:K4`9[$`,)$`,)$`" + "-90`5J<`*6GF!A)\"N^\"3Y0^EY0^EY0^EY0^EY0^EY0^EY0^EY0^IZP_%Z`_,Y@^I" + "YP^UZ@^[Y0^KXP^:XP^:XP^:XP^:XP^:XP^:Y@^TY@^JW0]^W0]^W0]^V0I];8MB" + "!Q)\"(!E*P4M\\`V\"1`V\"1`WRM`VF:`V^@`VJ;`D9WJ3AI(R-4!!!!EZ/4\\/TM````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````X^`@3UR,&#I/5N1S;@^$DP^Q8P]W8P]W8P]W8P]W8P]W(%13" + "-E>?=KP`8J``A<8`8J``>;X`2J$`2J$`2J$`2J$`2J$`>;P`9;,`.)8`.)8`.)8`" + ".)8`.)8`:;,`.94`2)\\`,)$`,)$`7ZT`+HPW%2A;5VYFY0^EY0^EY0^EY0^EY0^E" + "YP^KZ`_(Z@_%Y0^IYP^OX`^BW`^-W`^-W`^-W`^-X@^;Y`^WZ@^[Y0^HXP^:Z@^_" + "XP^@W0]^W0^\"X0^3Q.N4-$18!!!!8RY?\\UN,`V\"1`V:7`WVN`W6F`V.4`49WLC5F" + ",RA9!!!!A9'\"X^`@````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````]`0TAI+#)S1C0J]F" + ";@^$DP^T8`]X8P]W8P]W8P]W4N-N!Q9%:YX&A,0`8J``8J``=KL`2J$`2J$`2J$`" + "2J$`=+L`2J$`;K8`.)8`.)8`.)8`.)8`9K(`.I<`6ZP`,)$`,)$`9*``,)$`)E>\\" + "$!Y'SO:;Y0^EY0^EY0^HZ`_%ZP_'Y@^KY0^EY0^EY0^MY@^LW`^-W`^-W`^-W`^-" + "W`^-W`^-W`^-W`^-X@^8ZP_%XP^CX0^5WP^$VP]RFL%I$AQ'%A='M$=X`V\"1`V\"1" + "`X:W`W^P`U>(^T1UGC%B*AY/!!!!=H*SWNL;````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````Q=(\"&B97)&%59_Z\"DP^R9`]]8P]W8P]W8P]W/8YH'C1F" + ";[4Z8J``8J``=+H`2J$`2J$`2J$`;[<`3:,`2J$`;;4`.)8`.)8`.)8`8:X`/)@`" + ".)8`8J\\`,)$`8:X`,(\\`*'@/!A-$A*)ZY0^GZ`_%Z`_(Y@^MY0^EY0^EY0^EY0^E" + "Y0^HY@^PW`^-W`^-W`^-W`^-W`^-W`^-W`^-YP^PY`^TYP^TV`]TVP]RVP]RV`Y]" + "=8YT!1!!-2=8XWFJ`WRM`W.D`XFZ`'*CQ%B):CIK%!A)!!!!BY?(W.D9`P\\_````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````Y/$A4V\"0%#5-" + "6=]XD@^Q:@^\"8P]W8P]W7`AV&3=4/6>`8J``8J``<;D`2J$`2J$`:K,`4:<`2J$`" + "2J$`7ZP`.)8`.)8`7JL`/YH`.)8`1)X`-I0`5ZD`-)0`+HLT$BEH/5!AZ@S(YP^P" + "Y0^EY0^EY0^EY0^EY0^EY0^EY0^FYP^UW`^-W`^-W`^-W`^-W`^-XP^8Y`^YX`^D" + "X0^4Y0^IVP]RVP]RW0]ZW06A4EI@!!!!7BM<^'FJ`W^P[5J+KS9G:3QM'1]0!!!!" + "1E*#KKKK[/DI````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````]@(R@HZ_)S1C1[%LC0^K<@^)8P]W8P]W9M>)!Q9$:*$." + "8J``;+4`2J$`8:X`5ZD`2J$`2J$`2J$`2)\\`.)8`5ZD`0YP`.)8`.)8`9K(`3J,`" + "/YL`,(\\_)D:/$1])S?&LY0^EY0^EY0^EY0^EY0^EY0^EY0^EY0^EY`^ZW`^-W`^-" + "W`^-W`^-Y@^KY`^UX0^2W`^-X`^AX0^5VP]RVP]UX`^CP>Q_,S)6!Q%\">3UNH3QM" + ";#9G,\"E:!1%\"!!!!5V.4J+3EV^@8_`P\\````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "`````````````````````````````````````````````````````@X^M<'R$1U." + "*VE<@`2D=P^08P]W8P]W.X)I%S)C?;LX:+4`6JH`7ZX`2J$`2J$`2J$`5:@`.)8`" + "4Z8`1Y\\`.)8`.)8`.)8`6JL`1Y\\`7JT`,UJD\"!1#I,E`X@^9ZP_$YP^LY0^EY0^E" + "Y0^EY0^EY0^EZ0^`W`^-W`^-X0^4YP^WY0^IW`^-W`^-W`^-YP^MW0^#VP]TX`^C" + "VPN'=I1D\"Q1#\"1%\"#A1%!!!!!!!!256&DI[/PL[_ZOB%CQ-*E:G>;P`" + ">;X`2J$`2J$`2J$`2J$`9[$`3J(`3*,`.)8`.)8`.)8`5ZD`9K(`3J$^+U>F!1)\"" + "D;-YX@^8X@^8X@^8Y0^HZP_&Y0^EY0^EY0^EZ@^`W`^-Y0^GZ0^WX0^6W`^-W`^-" + "W`^-W`^-Y`^SV`]UX`^@W`^/AZU?\"!1#!!!!!!!!:G:GI[/DSML+\\/TM````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````]P,S!Q-$$1Y." + "\"QI'5;)\\@P^@90]Z7^%^!Q=$.G7N=KP`0YT`9K$`<+<`7:L`<[D`5Z@`2I``6ZP`" + "9[$`:+(`9+$`)8D[*DN2!1)\"B*AUX@^8X@^8X@^8X@^8X@^8X@^8Z0^^Z0^TZ@^_" + "Y`^YY0^IW`^-W`^-W`^-W`^-W`^-X0^4Y0^JX0^8X@^4V@YRD[=L&\"51&B97H*S=" + "]P,S````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````WNL;%B)3I;'B;7FJ!!!!,G!B@P6BB@^H.)Y?\"QU+:J<@0YP`" + "/)@`/)@`/)@`Y@^PX`^IZ0^RX0>MHL5]5FYF#QU'!!!!@(R]W.D9````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````S]P,&\"15````Q-$!+CIKU.$1;GJK]`HQT0_`K_7>%2530F>^19P`/)@`" + ";;8`7JL`+(\\`,I,`7*L`0(D4$\");%B9*M]Z'X@^8Y@^OZ0^`Y`^XY0^HZ@^\\XP^>" + "W0]_W0]_W0]_W0]_W0]_W@^(XP^AV0\"HKLZ4?)>\"/D]C\"A=&!!!!56&2KKKKY_0D" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````T]`0$1U.````Y?(BI+#A````````" + "````````````O\\O\\!A)$4(/Q0IL`2I\\`5J@`,I,`5ZD`2(#S\"AI/)#=2S?&OZ@^`" + "X`^KX@^8Y@^KYP^PW0^'W0]_W0]_X@^:W06GRN^DJLN5@IV'6F]W+CQ?!A)#!!!!" + "$1U.>H:WN,3UY/$A`P\\_````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "X.T=!!!!^04U````````````````````````````````@(R]F;8!<+<`/)@`4*4`" + "5Z@`8:``+46*(S)9S_B4X@^8X@^8Y0^MX@^X>^@8V````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````\\O\\O!!!!K;GJ````````````````````````" + "````````````````[P0`Q^P`G=,`G-,`Y?X`_`P\\`@X^^P`:ZP_(Y`^TX`VF/U19" + "\"QA$!!!!!!!!!!!!!1%\"!!!!&B97R=8&Y/$A^`@X````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````_0DY)S-C" + "%B)3Y_0D````````````````````````````````````````````````````````" + "```````````````_^``=]@@2$!U,!A)#=H*SK;GJ2%2%!!!!$1U.DI[/````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````^`@X,#QL!1%!,CYO`@X^````````````````````````" + "````````````````````````````````````````````````P\\_`!!!!E:'2````" + "````A9'\":'2E!!!!P\\_`````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````^P]='\":!!!!" + "5F*2ZO)<55U#19&\"A9&4U^0CYO,M<'RR]@(U.$1" + "Z_@H`@X^````\\/TML;WN76F:#1E)!!!!#AI+#AE(!!!!U.$1````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````2E:'`O$5`>'_GI.[(B).IUUI(2E2!!!!Y82(`Y:4`Z:L" + "\\)J@C&V*,RQ5\"1-#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\"!-$34UZ.S]M\"A5&" + "(BI245V.`0T]````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````_0DY1E&\"`_(4`^H(@'BB" + "1CI@DUQP(\"E1!!!!\\YNC`Z>L`Z6H`Z6H`ZNP`Z:K_:ZXWYZNPHN@N(^KHG:0/CAC" + "&\"%,!1%\">F*$3T]]`^H,N[#6%B!.!1!!O,CY````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````\\?XN6&.4`^X1`^X1B'^F.S)5" + "`\\?955)^O;#7&B11!1%!6F:7````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "XN\\?-CQK`^8(`^`4]MCW&2%0*RU6%B!+%QI'5T)D*RY:)B93,2]92CUC>5M[O8^H" + "`+._`[6``[W,<%M\\+S5;!1%!Z*[\"`]/I9U^';&N5+S9=!!!!>(2U````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````Z_@H2%.$`MOV`^@(`^\\1M:O2!A)\"!A)\"$!I)" + "P*S/[M`#`^0\"]MCX[-#QP*[2=G\";-#5BI'B3`+.^)BM6*3!6.39@`\\'1`]CR/CYJ" + "HI>`%1]-3TUV7VJ;````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "`````````````````````````````````````````````````````````@X^/4AY" + "J8BD`]_Z`^X0`^T0'293!Q-\"1$1Q`^0\"`^8&`^T.`^0\"`^0\"`^\\2`^0\"]=?W@GRD" + "+S)@)BY8!1%!AVJ*`\\'1J92X9&*-`^P.^MK[DG&04EZ.````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````=H*S)BM9`]7M`^8%`^D%:6J-!1%\"$QY.J9J_`N,!" + "`^\\2`^0\"`^0\"`^`3`^0\"`^0\"`^0\"9&*.)S!8!!!!V:2YQ9NW-SUK].($`^0!`\\G=" + "8$YT=8&R````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````@(N\\$1I*GX>J" + "`\\C<`^D)ZM3W\\=O^\\M;W;V^9.T!ON*O3`.T0`^4$`^X1`^0\"`^0\"`N\\2)B]<(2I2" + "#!9'?6B,$AM+M*K0`^,!`]3MXZJ_\"1-#OLK[````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````2E:'J9&S#A='R:?%`]KU`^+``][Z`^D*`^H+WL[Q:V6/,#9D" + "9620BH:PEHZWH9K\"@GNE'\"53!!!!*3%@I)O\"_^H,`^H,`][Z`[K)649K-D)S]P,S" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````_`P\\$1U.`-+KDGZA%!Q+OYJW" + "`\\#/`]3K`^'``^@(`]_]`^X/_.H+V+_AN*G.KJ3*J9O#;FB1$1M((\"=6Y,GI`^#^" + "`]'H`\\+3`\\WAN8JB!!!!O`]#FFGB6\"A5%@&6%_KO)`\\;8`\\[C`^8%`]SX`]SX`^#\\`^4!" + "`]_\\`^'^`^0!N:G+\\,SJ`]7M`]'F`\\WD`\\+2M7>*$1E(=(\"Q_`P\\````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````Z?8F!A)#`L#0`\\O?`\\'1Q9JS)B=4*BQ9" + "LHJD`K7\"#" + "\"!)\"*C9G\\_`P````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````[?HJ" + "!!!!Y:R``\\'2`\\+3`\\WB^[\"\\CW\"0&1Y,*2Q9A7&2TJ&Z`:2H`ZJS`[O(`[\"Z`Z6I" + "`Z6I`ZFP`Y:4\\(N+G&)U,BU6!!!!\"1)\"JK;G````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "`````````````````````````0T].45VE'.2`\\'1`\\O?`\\[D`[6``\\K?^:^[GG2." + "/C9>!1!!$1E(03IB8$]S=5Q[>V2$>F2%84]S+2M4!1!!!A%\"13A>FF=]!!!!T-T-" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````LK[O+3=G" + "\\K7'`]+G`\\O>`[6``[S,`[;\"`[6``[6`YZ[#I7V9>51P5D!B.C!7-RY6-S%<1CI@" + ":41AHF)SZ(:)`ZRQAU!F!!!!\\/TM````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````^PH:W````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````XN\\?)C)C=&>." + "`K2_`[6``[6``\\G;`[6``[O)`Z6H`Z6H`[?\"`Z6H`Z6H`Z6H`ZZV`Y21`Z*F`Y>5" + "`YB886````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````V>86)C)C5D=M\\*FW`[6``[C%`[K(`\\77`Z6H`Z6H`Z6H" + "`[S)`Z6H`ZBL`Y>6`Y21`Y21`[*\\LWB-!1%\"DI[/````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````Y/$A6666.$1T" + "F'22_+\"]`\\K?`\\?:`Z6H`Z6H`Z6H`[&Z`Z>L`[C!`Y21`Y21_I&/CUEP\"11$8V^@" + "]`0T````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````^P-#%;&1]-!!!!!!!!@(R]T]`0`@X^````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "`````````````````````````````P\\_Z?8FR=8&J[?HH*S=H*S=H:W>L[_PR]@(" + "\\?XN````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````````````````````````````````````````````````````" + "````````````````"; diff --git a/platforms/unix/vm-display-qnxScreen/Makefile b/platforms/unix/vm-display-qnxScreen/Makefile new file mode 100644 index 0000000000..8183e7f4ff --- /dev/null +++ b/platforms/unix/vm-display-qnxScreen/Makefile @@ -0,0 +1,191 @@ +# Makefile for framebuffer support -*- makefile -*- +# +# Copyright (C) 1996-2004 by Ian Piumarta and other authors/contributors +# listed elsewhere in this file. +# All rights reserved. +# +# This file is part of Unix Squeak. +# +# You are NOT ALLOWED to distribute modified versions of this file +# under its original name. If you modify this file then you MUST +# rename it before making your modifications available publicly. +# +# This file 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. +# +# You may use and/or distribute this file ONLY as part of Squeak, under +# the terms of the Squeak License as described in `LICENSE' in the base of +# this distribution, subject to the following additional restrictions: +# +# 1. The origin of this software must not be misrepresented; you must not +# claim that you wrote the original software. If you use this software +# in a product, an acknowledgment to the original author(s) (and any +# other contributors mentioned herein) in the product documentation +# would be appreciated but is not required. +# +# 2. You must not distribute (or make publicly available by any +# means) a modified copy of this file unless you first rename it. +# +# 3. This notice must not be removed or altered in any source distribution. +# +# Using (or modifying this file for use) in any context other than Squeak +# changes these copyright conditions. Read the file `COPYING' in the +# directory `platforms/unix/doc' before proceeding with any such use. +# +# Author: ian.piumarta@inria.fr +# +# Last edited: 2004-04-12 11:56:39 by piumarta on emilia.local + + +# make.cfg.in -- mf fragment for configured variables -*- makefile -*- +# +# Copyright (C) 1996-2015 by Ian Piumarta and other authors/contributors +# listed elsewhere in this file. +# All rights reserved. +# +# This file is part of Unix Squeak. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. + +# Author: Ian.Piumarta@inria.fr +# +# Last edited: Wed Nov 16 14:47:35 PST 2016 by eliot + +MAKEFLAGS= --no-print-directory + + + +host= aarch64-rpi4-qnx-gnu +host_cpu= aarcg64 +target_cpu= aarch64 +host_vendor= rpi4 +host_os= qnx-gnu + +topdir= /home/kend/QNX-VM +cfgdir= /home/kend/QNX-VM/platforms/unix/config +srcdir= /home/kend/QNX-VM/src/spur64.stack +vmmcfg= /home/kend/QNX-VM/building/qnx64ARMv8/squeak.stack.spur/build +blddir= /home/kend/QNX-VM/building/qnx64ARMv8/squeak.stack.spur/build + +scriptname= spur64 + +top_builddir= /home/kend/QNX-VM/building/qnx64ARMv8/squeak.stack.spur/build + +prefix= /usr/local +exec_prefix= ${prefix} + +bindir= ${exec_prefix}/bin +libdir= ${exec_prefix}/lib +datarootdir= ${prefix}/share +datadir= ${datarootdir} +mandir= ${datarootdir}/man +imgdir= ${prefix}/lib/squeak +plgdir= . +docdir= $(prefix)/doc/squeak + +SHELL= /bin/bash +MKINSTALLDIRS= mkdir -p +INSTALL= /usr/bin/install -c +INSTALL_PROG= ${INSTALL} $(INSTALL_ARGS) +INSTALL_SCRIPT= ${INSTALL} $(INSTALL_ARGS) +INSTALL_DATA= ${INSTALL} -m 644 $(INSTALL_ARGS) +UNINSTALL= $(SHELL) $(cfgdir)/uninstall +AS= as +AWK= mawk +RANLIB= ranlib +LIBTOOL= $(SHELL) $(top_builddir)/libtool +NM= /usr/bin/nm -B +LN= ln +LN_S= ln -s + +CC= $(QNX_CC) +DEFS= -DHAVE_CONFIG_H +INCLUDES= -I/home/kend/QNX-VM/building/qnx64ARMv8/squeak.stack.spur/build -I/home/kend/QNX-VM/building/qnx64ARMv8/squeak.stack.spur/build -I/home/kend/QNX-VM/platforms/unix/vm -I/home/kend/QNX-VM/platforms/Cross/vm -I/home/kend/QNX-VM/src/spur64.stack -I/usr/local/include +CPPFLAGS= -Wno-missing-braces -Wno-unknown-pragmas -Wno-unused-value -Wno-unused-label -Wno-unused-function -Wno-unused-variable -Wno-unused-but-set-variable $(QNX_CFLAGS) +CFLAGS= -Wall -fPIC -g -O2 -DNDEBUG -DDEBUGVM=0 -DCOGMTVM=0 -DLSB_FIRST=1 $(QNX_CFLAGS) +WFLAGS= +LDFLAGS= -Wl,-z,now -lscreen $(QNX_LIBS) $(QNX_LDFLAGS) +BITBLT_OBJS= BitBltPlugin.o +IA32ABI_OBJS= IA32ABI.o AlienSUnitTestProcedures.o xabicc.o +VM_DISPX11_OBJS= +BITBLT_FLAGS= +VM_DISPX11_BITBLT_FLAGS= +ARM_ARCH= +LIBM_CFLAGS= -O + +FT2_PLUGIN_CFLAGS = +FT2_PLUGIN_LIBS = +UNICODE_PLUGIN_CFLAGS = +UNICODE_PLUGIN_LIBS = + +LIBS= -lz -lm $(QNX_LIBS) $(QNX_LDFLAGS) + + +X_CFLAGS= +X_INCLUDES= +X_LIBS= + + +INTERP= gcc3x-interp + +VM_APP_ICONS= + +npsqueak= +install_nps= +uninstall_nps= + +# make.ext.in -- mf fragment for external plugins -*- makefile -*- +# +# Author: Ian.Piumarta@inria.fr +# +# Last edited: Sep 1 18:56:15 PDT 2010 by eliot; LINKXX for plugins using C++ + +o = .lo +a = .la +COMPILE = $(CC) $(CFLAGS) $(CPPFLAGS) $(XCFLAGS) $(DEFS) $(XDEFS) \ + $(INCLUDES) $(XINCLUDES) $(CPPFLAGS) $(XCPPFLAGS) $(TARGET_ARCH) -c -o +CXXFLAGS = $(CFLAGS) # Hack; can't be bothered to add CXXFLAGS to the configure mess +COMPILE.cpp = $(COMPILE.cc) +COMPILE.cc = $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(XCFLAGS) $(DEFS) $(XDEFS) \ + $(INCLUDES) $(XINCLUDES) $(CPPFLAGS) $(XCPPFLAGS) $(TARGET_ARCH) -shared -c -o +LINK = $(CC) $(CFLAGS) $(XCFLAGS) \ + $(LDFLAGS) $(XLDFLAGS) $(TARGET_ARCH) -shared -o +LINKXX = $(CXX) $(CFLAGS) $(XCFLAGS) \ + $(LDFLAGS) $(XLDFLAGS) $(TARGET_ARCH) -shared -o +RANLIB = : + +TARGET = vm-display-qnxScreen.so +OBJS = sqQNXScreen$o + +#XCFLAGS = $(X_CFLAGS) -Wall -Werror -Wno-unknown-pragmas +XCFLAGS = $(X_CFLAGS) -Wall -Wno-unknown-pragmas + +XINCLUDES = -I/home/kend/QNX-VM/platforms/unix/vm-display-qnxScreen $(X_INCLUDES) $(QNX_CFLAGS) \ + -I$(topdir)/platforms/Cross/plugins/FilePlugin \ + -I$(topdir)/platforms/Cross/plugins/B3DAcceleratorPlugin \ + -I$(topdir)/platforms/unix/plugins/B3DAcceleratorPlugin + +$(TARGET) : $(OBJS) Makefile + $(LINK) $(TARGET) $(OBJS) + +sqQNXScreen$o : /home/kend/QNX-VM/platforms/unix/vm-display-qnxScreen/sqQNXScreen.c + $(COMPILE) sqQNXScreen$o /home/kend/QNX-VM/platforms/unix/vm-display-qnxScreen/sqQNXScreen.c + +.force : diff --git a/platforms/unix/vm-display-qnxScreen/Makefile.in b/platforms/unix/vm-display-qnxScreen/Makefile.in new file mode 100644 index 0000000000..82ddc68b77 --- /dev/null +++ b/platforms/unix/vm-display-qnxScreen/Makefile.in @@ -0,0 +1,60 @@ +# Makefile for framebuffer support -*- makefile -*- +# +# Copyright (C) 1996-2004 by Ian Piumarta and other authors/contributors +# listed elsewhere in this file. +# All rights reserved. +# +# This file is part of Unix Squeak. +# +# You are NOT ALLOWED to distribute modified versions of this file +# under its original name. If you modify this file then you MUST +# rename it before making your modifications available publicly. +# +# This file 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. +# +# You may use and/or distribute this file ONLY as part of Squeak, under +# the terms of the Squeak License as described in `LICENSE' in the base of +# this distribution, subject to the following additional restrictions: +# +# 1. The origin of this software must not be misrepresented; you must not +# claim that you wrote the original software. If you use this software +# in a product, an acknowledgment to the original author(s) (and any +# other contributors mentioned herein) in the product documentation +# would be appreciated but is not required. +# +# 2. You must not distribute (or make publicly available by any +# means) a modified copy of this file unless you first rename it. +# +# 3. This notice must not be removed or altered in any source distribution. +# +# Using (or modifying this file for use) in any context other than Squeak +# changes these copyright conditions. Read the file `COPYING' in the +# directory `platforms/unix/doc' before proceeding with any such use. +# +# Author: ian.piumarta@inria.fr +# +# Last edited: 2004-04-12 11:56:39 by piumarta on emilia.local + +[make_cfg] +[make_plg] + +TARGET = vm-display-qnxScreen$a +OBJS = sqQNXScreen$o + +#XCFLAGS = $(X_CFLAGS) -Wall -Werror -Wno-unknown-pragmas +XCFLAGS = $(X_CFLAGS) -Wall -Wno-unknown-pragmas + +XINCLUDES = [includes] $(X_INCLUDES) $(QNX_CFLAGS) \ + -I$(topdir)/platforms/Cross/plugins/FilePlugin \ + -I$(topdir)/platforms/Cross/plugins/B3DAcceleratorPlugin \ + -I$(topdir)/platforms/unix/plugins/B3DAcceleratorPlugin + +$(TARGET) : $(OBJS) Makefile + $(LINK) $(TARGET) $(OBJS) + $(RANLIB) $(TARGET) + +[make_targets] + +.force : diff --git a/platforms/unix/vm-display-qnxScreen/README.qnx b/platforms/unix/vm-display-qnxScreen/README.qnx new file mode 100644 index 0000000000..73fba4ab5f --- /dev/null +++ b/platforms/unix/vm-display-qnxScreen/README.qnx @@ -0,0 +1,17 @@ +This is a vm-display specialized for QNX 8.0 based on the Screen display API +and requires QNX includes & libraries. + +Note: + https://qnx.com/getqnx + https://www.qnx.com/developers/docs/8.0/com.qnx.doc.screen/topic/manual/cscreen_about.html + +Interaction is similar in pattern to vm-display-fbdev + +TESTED Raspberry Pi 5 Self hosted [sudo apk add screen] + +Note: vm-display-qnxScreen uses _screen_ to take over the display, mouse, and keyboard. +It requires RasPi5 self-hosting to build, but can be run without the hosted GUI. +It is NOT (yet) a windowed app. + +"sudo apk add qnx-screen" + diff --git a/platforms/unix/vm-display-qnxScreen/acinclude.m4 b/platforms/unix/vm-display-qnxScreen/acinclude.m4 new file mode 100644 index 0000000000..34f9bffdb8 --- /dev/null +++ b/platforms/unix/vm-display-qnxScreen/acinclude.m4 @@ -0,0 +1,9 @@ +# -*- sh -*- + +AC_ARG_WITH(vm-display-qnxScreen, +[ --without-vm-display-qnxScreen disable QNX Screen display support [default=disabled]], + [with_vm_display_qnxScreen="$withval"], + [with_vm_display_qnxScreen="no"]) +if test "$with_vm_display_qnxScreen" = "no"; then + AC_PLUGIN_DISABLE_PLUGIN(vm-display-qnxScreen); +fi diff --git a/platforms/unix/vm-display-qnxScreen/qnxDisplayTest.c b/platforms/unix/vm-display-qnxScreen/qnxDisplayTest.c new file mode 100644 index 0000000000..8d087a0160 --- /dev/null +++ b/platforms/unix/vm-display-qnxScreen/qnxDisplayTest.c @@ -0,0 +1,157 @@ +/* qnxDisplayTest.c -- test basic rendering */ + +/* + source ./sourceMe.sh ## in Bash Shell + $QNX_CC $QNX_CFLAGS -trigraphs $QNX_LDFLAGS -lscreen -o displayTest qnxDisplayTest.c + scp displayTest qnxuser@192.168.TARGET:/home/qnxuser/bin +## Test on QNX RasPi4 Target +*/ + + +#include +#include +#include /* sleep() */ +#include +#include +#include + +/* Pixels are kept as 32 bits: uint32_t */ +typedef uint32_t pixel_t; +#include "Balloon.h" /* Squeak Balloon image */ + +/* Forward declarations */ +static void showBalloons( void *bufPtr ); +static void showBalloonAt(void *bufPtr, int left, int top); +static inline void putPixel(void *bufPtr, int x, int y, pixel_t pix); + + +screen_context_t screenContext = NULL; +screen_event_t event; +screen_window_t window; +screen_buffer_t buffer; +void* bufPointer; /* buffer pointer */ +int stride; /* buffer stride (bytes per scan line) */ +int size[2]; /* {width,height} in pixels */ +const int alwaysTrue = 1; + + +int main(void) { + + int sessionVisible = SCREEN_PROPERTY_VISIBLE; /* => active */ + int usage = SCREEN_USAGE_NATIVE; + int eventType = 0; + + if (screen_create_context(&screenContext,SCREEN_APPLICATION_CONTEXT) < 0) { + printf("\nqnx screenTest: Event creation failure with errno %d\n", errno); + return -1; + } + + if (screen_create_event(&event) < 0) { + printf("\nqnx screenTest: Event creation failure with errno %d\n", errno); + return -1; + } + + if (screen_create_window_type(&window, + screenContext, + (SCREEN_APPLICATION_WINDOW |SCREEN_ROOT_WINDOW)) < 0) { + printf("\nqnx screenTest: Window creation failure with errno %d\n", errno); + return -1; + } + + if (screen_create_window_buffers(window, 1) < 0) { + printf("\nqnx screenTest: Single buffer creation failure with errno %d\n", errno); + return -1; + } + + /* Render Setup */ + screen_set_window_property_iv(window, SCREEN_PROPERTY_FORMAT, + (const int[]){ SCREEN_FORMAT_RGBX8888 }); + screen_set_window_property_iv(window, SCREEN_PROPERTY_USAGE, + (const int[]) { SCREEN_USAGE_WRITE | SCREEN_USAGE_NATIVE }); + screen_get_window_property_iv(window, SCREEN_PROPERTY_BUFFER_SIZE,size); + screen_get_window_property_pv(window, SCREEN_PROPERTY_BUFFERS, (void **)&buffer); + screen_get_buffer_property_pv(buffer, SCREEN_PROPERTY_POINTER, &bufPointer); + screen_get_buffer_property_iv(buffer, SCREEN_PROPERTY_STRIDE, &stride); + + screen_fill(screenContext, + buffer, /* chartreuse2 */ + (const int[]){ SCREEN_BLIT_COLOR, 0x0076EE00, SCREEN_BLIT_END }); + + screen_set_window_property_iv(window, SCREEN_PROPERTY_VISIBLE, &alwaysTrue); + + screen_flush_blits(screenContext, SCREEN_WAIT_IDLE); + screen_post_window(window, buffer, 0, NULL, SCREEN_WAIT_IDLE); + + sleep( 1 ); + + printf("\nDisplay (width , height) = (%d , %d)", size[0], size[1]); + printf("\n Depth = 32 bits/pixel = 4 bytes/pixel"); + printf("\n stride = %d bytes per scan line", stride); + printf("\n"); + + showBalloons(bufPointer); + screen_flush_blits(screenContext, SCREEN_WAIT_IDLE); + screen_post_window(window, buffer, 0, NULL, SCREEN_WAIT_IDLE); + + + + sleep( 10 ) ; /* let the user see it */ + + printf("\nExiting Display Test (Normal timeout)\n\n"); + + screen_destroy_window( window ); + screen_destroy_context( screenContext ); + + return 0; +} + + +static void showBalloons( void *bufPtr ) { + int x, y; + + x = size[0] / 2; + y = size[1] / 2; + showBalloonAt(bufPtr,x,y) ; + showBalloonAt(bufPtr,x+(x/2),y-(y/2)) ; + showBalloonAt(bufPtr,x+(x/2),y+(y/2)) ; + showBalloonAt(bufPtr,x-(x/2),y-(y/2)) ; + showBalloonAt(bufPtr,x-(x/2),y+(y/2)) ; +} + + +static void showBalloonAt(void *bufPtr, int left, int top) +{ + int x, y; + char *data = balloon_data, pixel[4]; + pixel_t myPixel; + int balloon_bytes_per_pixel = 4; /* 32 bits */ + + /* Center Balloon on x,y point */ + left -= balloon_width_pixels / 2; + top -= balloon_height_pixels / 2; + for (y = 0; y < balloon_height_pixels; y++) { + for (x = 0; x < balloon_width_pixels; x++) { + /* extract RGB values from Balloon data */ + BALLOON_PIXEL( data, pixel ); + /* above side effect: data += balloon_bytes_per_pixel */ + putPixel(bufPtr, + left + x, + top + y, + ((pixel[0] << 16) | (pixel[1] << 8) | pixel[2])); /* RGB */ + } + } +} + +static inline void putPixel(void *bufPtr, int x, int y, pixel_t pix) +{ + if ((x >= 0) && (y >= 0) && (x < size[0]) && (y < size[1])) /* size[width,height] */ + { + *((pixel_t *)(bufPtr + + (x * 4) /* 4 = (32/8) = (bits-per-pixel/bits-per-byte) */ + + (y * stride))) + = pix; + } +} + + +/* --- E O F --- */ diff --git a/platforms/unix/vm-display-qnxScreen/qnxScreenTest.c b/platforms/unix/vm-display-qnxScreen/qnxScreenTest.c new file mode 100644 index 0000000000..99361ffa48 --- /dev/null +++ b/platforms/unix/vm-display-qnxScreen/qnxScreenTest.c @@ -0,0 +1,635 @@ +/* qnxScreenTest.c -- test basic rendering */ + +/* + source ./sourceMe.sh ## in Bash Shell + $QNX_CC $QNX_CFLAGS -trigraphs $QNX_LDFLAGS -lscreen -o screenTest qnxScreenTest.c + scp screenTest qnxuser@192.168.TARGET:/home/qnxuser/bin +## Test on QNX RasPi4 Target +*/ + + +#include +#include +#include /* sleep() */ +#include +#include +#include + +/* Pixels are kept as 32 bits: uint32_t */ +typedef uint32_t pixel_t; +#include "Balloon.h" /* Squeak Balloon image */ + +/* Forward declarations */ +void handleKeyboardEvent(screen_event_t keyEvent); +void handlePointerEvent(screen_event_t keyEvent); /* mouse events */ +static void showBalloons( void *bufPtr ); +static void showBalloonAt(void *bufPtr, int left, int top); +static inline void putPixel(void *bufPtr, int x, int y, pixel_t pix); +void printKeyFlags(int flags); +void printModifiers(int modifiers); +void printMouseButtons(int buttons); +void printPCKeys(int keyCode); + +/* Global loop control */ +int keyValue = 0; +int loopCount = 0; +const int maxLoopCount = 80; /*@@TEST@@*/ + +screen_context_t screenContext = NULL; +screen_event_t event; +screen_window_t window; +screen_session_t keyboardSession; +/* screen_pixmap_t pixMap; */ +/* screen_buffer_t buffers[2]; */ +screen_buffer_t buffer; +void* bufPointer; /* buffer pointer */ +int stride; /* buffer stride (bytes per scan line) */ +int size[2]; /* {width,height} in pixels */ +const int alwaysTrue = 1; + + +int main(void) { + + int sessionVisible = SCREEN_PROPERTY_VISIBLE; /* => active */ + int usage = SCREEN_USAGE_NATIVE; + int eventType = 0; + int objectType = 0; + + if (screen_create_context(&screenContext,SCREEN_APPLICATION_CONTEXT) < 0) { + printf("\nqnx screenTest: Event creation failure with errno %d\n", errno); + return -1; + } + + if (screen_create_window_type(&window, + screenContext, + (SCREEN_APPLICATION_WINDOW |SCREEN_ROOT_WINDOW)) < 0) { + printf("\nqnx screenTest: Window creation failure with errno %d\n", errno); + return -1; + } + + if (screen_create_window_buffers(window, 1) < 0) { + printf("\nqnx screenTest: Single buffer creation failure with errno %d\n", errno); + return -1; + } + + /* Render Setup */ + screen_set_window_property_iv(window, SCREEN_PROPERTY_FORMAT, + (const int[]){ SCREEN_FORMAT_RGBX8888 }); + screen_set_window_property_iv(window, SCREEN_PROPERTY_USAGE, + (const int[]) { SCREEN_USAGE_READ | SCREEN_USAGE_WRITE }); + screen_get_window_property_iv(window, SCREEN_PROPERTY_BUFFER_SIZE,size); + screen_get_window_property_pv(window, SCREEN_PROPERTY_BUFFERS, (void **)&buffer); + screen_get_buffer_property_pv(buffer, SCREEN_PROPERTY_POINTER, &bufPointer); + screen_get_buffer_property_iv(buffer, SCREEN_PROPERTY_STRIDE, &stride); + + screen_fill(screenContext, + buffer, /* chartreuse2 */ + (const int[]){ SCREEN_BLIT_COLOR, 0x0076EE00, SCREEN_BLIT_END }); + + screen_set_window_property_iv(window, SCREEN_PROPERTY_VISIBLE, &alwaysTrue); + + screen_flush_blits(screenContext, SCREEN_WAIT_IDLE); + screen_post_window(window, buffer, 0, NULL, SCREEN_WAIT_IDLE); + + sleep( 1 ); + + printf("\nDisplay (width , height) = (%d , %d)", size[0], size[1]); + printf("\n Depth = 32 bits/pixel = 4 bytes/pixel"); + printf("\n stride = %d bytes per scan line", stride); + printf("\n"); + + showBalloons(bufPointer); + screen_flush_blits(screenContext, SCREEN_WAIT_IDLE); + screen_post_window(window, buffer, 0, NULL, SCREEN_WAIT_IDLE); + + sleep( 2 ) ; /* let the user see it */ + + + /* FOR THE USER */ + + if (screen_create_event(&event) != 0) { + printf("\nqnx screenTest: Event creation failure with errno %d\n", errno); + return -1; + } + + printf("\nQNX Keyboard test. Type 'x' to exit\n"); + + while ((keyValue != KEYCODE_X) && (loopCount < maxLoopCount)) { + + if (screen_get_event( screenContext, event, 10000000000) != 0) { + printf("\nqnx screenTest: screen_get_event() errno %d\n", errno); + break; + /* ~0L => Don't wait, else nanoSecs to sleep */ + } + + if (screen_get_event_property_iv(event,SCREEN_PROPERTY_OBJECT_TYPE,&objectType) + != 0) { + printf("\nEvent Object type failure. Errno = 0x%lx", errno); + break; + } + /* else { */ + /* printf("\nEvent Object Type: 0x%lx", objectType); */ + /* switch (objectType) { */ + /* case SCREEN_OBJECT_TYPE_CONTEXT: */ + /* printf(": Context"); */ + /* break; */ + /* case SCREEN_OBJECT_TYPE_GROUP: */ + /* printf(": Group"); */ + /* break; */ + /* case SCREEN_OBJECT_TYPE_DISPLAY: */ + /* printf(": Display"); */ + /* break; */ + /* case SCREEN_OBJECT_TYPE_DEVICE: */ + /* printf(": Device"); */ + /* break; */ + /* case SCREEN_OBJECT_TYPE_PIXMAP: */ + /* printf(": Pixmap"); */ + /* break; */ + /* case SCREEN_OBJECT_TYPE_SESSION: */ + /* printf(": Session"); */ + /* break; */ + /* case SCREEN_OBJECT_TYPE_STREAM: */ + /* printf(": Stream"); */ + /* break; */ + /* case SCREEN_OBJECT_TYPE_WINDOW: */ + /* printf(": Window"); */ + /* break; */ + /* default: */ + /* break; */ + /* } */ + /* } */ + + if (objectType == SCREEN_OBJECT_TYPE_WINDOW) { + + loopCount += 1; + + if (screen_get_event_property_iv(event,SCREEN_PROPERTY_TYPE,&eventType) != 0) { + printf("\nEvent type failure. Errno = 0x%lx", errno); + break; + } + + switch (eventType) { + + case SCREEN_EVENT_NONE: + printf("\nGot NULL Event"); + break; + + case SCREEN_EVENT_KEYBOARD: + /* printf("\nGot KEYBOARD Event"); */ + handleKeyboardEvent(event); + break; + + case SCREEN_EVENT_POINTER: + /* printf("\nGot MOUSE POINTER Event"); */ + handlePointerEvent(event); + break; + + case SCREEN_EVENT_GAMEPAD: + case SCREEN_EVENT_JOYSTICK: + printf("\nGot Joystick/Game Event"); + /* handleJoystickEvent(event); */ + break; + default: + printf("\nGot UNHANDLED Event Type: 0x%lx", eventType); + break; + } + } + } + + if (loopCount >= maxLoopCount) + printf("\nTimeout"); + printf("\nExiting Screen Test\n\n"); + + /* screen_destroy_session( keyboardSession ); */ + screen_destroy_window( window ); + screen_destroy_context( screenContext ); + + return 0; +} + + +static void showBalloons( void *bufPtr ) { + int x, y; + + x = size[0] / 2; + y = size[1] / 2; + showBalloonAt(bufPtr,x,y) ; + showBalloonAt(bufPtr,x+(x/2),y-(y/2)) ; + showBalloonAt(bufPtr,x+(x/2),y+(y/2)) ; + showBalloonAt(bufPtr,x-(x/2),y-(y/2)) ; + showBalloonAt(bufPtr,x-(x/2),y+(y/2)) ; +} + + +static void showBalloonAt(void *bufPtr, int left, int top) +{ + int x, y; + char *data = balloon_data, pixel[4]; + pixel_t myPixel; + int balloon_bytes_per_pixel = 4; /* 32 bits */ + + /* Center Balloon on x,y point */ + left -= balloon_width_pixels / 2; + top -= balloon_height_pixels / 2; + for (y = 0; y < balloon_height_pixels; y++) { + for (x = 0; x < balloon_width_pixels; x++) { + /* extract RGB values from Balloon data */ + BALLOON_PIXEL( data, pixel ); + /* above side effect: data += balloon_bytes_per_pixel */ + putPixel(bufPtr, + left + x, + top + y, + ((pixel[0] << 16) | (pixel[1] << 8) | pixel[2])); /* RGB */ + } + } +} + +static inline void putPixel(void *bufPtr, int x, int y, pixel_t pix) +{ + if ((x >= 0) && (y >= 0) && (x < size[0]) && (y < size[1])) /* size[width,height] */ + { + *((pixel_t *)(bufPtr + + (x * 4) /* 4 = (32/8) = (bits-per-pixel/bits-per-byte) */ + + (y * stride))) + = pix; + } +} + +/* KEYBOARD */ + +void +handleKeyboardEvent(screen_event_t keyEvent) { +/* +Event Type: SCREEN_EVENT_KEYBOARD + + SCREEN_PROPERTY_DEVICE + SCREEN_PROPERTY_FLAGS + SCREEN_PROPERTY_KEY_ALTERNATE_SYM + SCREEN_PROPERTY_KEY_CAP + SCREEN_PROPERTY_MODIFIERS + SCREEN_PROPERTY_SCAN + SCREEN_PROPERTY_SEQUENCE_ID + SCREEN_PROPERTY_SYM +*/ +/* NB: keyValue is global loop flag */ + int keyFlags = 0; + int keyModifiers = 0; + int keyCap = 0; + int keySym = 0; + int keyScan = 0; + + screen_get_event_property_iv(keyEvent, SCREEN_PROPERTY_SYM, &keyValue); + screen_get_event_property_iv(keyEvent, SCREEN_PROPERTY_FLAGS, &keyFlags); + screen_get_event_property_iv(keyEvent, SCREEN_PROPERTY_MODIFIERS, &keyModifiers); + if (keyFlags & SCREEN_FLAG_CAP_VALID) { + screen_get_event_property_iv(keyEvent, SCREEN_PROPERTY_KEY_CAP, &keyCap); + } + + if ((keyValue >= 0x20) && (keyValue <= 0x7F)) + printf("\nASCII '%c' ", keyValue); + else + printf("\n"); + if ((keyModifiers & KEYMOD_CTRL) && (keyCap < 0x7F)) + printf("CTL ^%c ", (keyCap - 0x20)); + + if ((keyModifiers & KEYMOD_ALT) && (keyCap < 0x7F)) + printf("ALT %c ", keyCap); + + printPCKeys(keyValue); /* NON-ASII, e.g. keypadkeys, home, .. */ + printModifiers(keyModifiers); /* SHIFT, etc. */ + printf(" KeyCode=0x%lx ", keyValue); + printKeyFlags(keyFlags); + + if (keyFlags & SCREEN_FLAG_CAP_VALID) { + screen_get_event_property_iv(keyEvent, SCREEN_PROPERTY_KEY_CAP, &keyCap); + printf(" keyCap=0x%lx", keyCap); + } + + if (keyFlags & SCREEN_FLAG_SYM_VALID) { + screen_get_event_property_iv(keyEvent, SCREEN_PROPERTY_SYM, &keySym); + printf(" keySym=0x%lx", keySym); + } + /* NB: For control keys, keySym is not valid. */ + + if (keyFlags & SCREEN_FLAG_SCAN_VALID) { + screen_get_event_property_iv(keyEvent, SCREEN_PROPERTY_SCAN, &keyScan); + printf(" location=0x%lx", keyScan); + } +} + +void printKeyFlags(int flags) { + + if (flags & SCREEN_FLAG_KEY_DOWN) + printf("KeyDOWN "); + else + printf("KeyUP "); + + if (flags & SCREEN_FLAG_KEY_REPEAT) + printf("KeyRepeat "); + + if (flags & SCREEN_FLAG_SCAN_VALID) + printf("KeyScanValid "); + + if (flags & SCREEN_FLAG_SYM_VALID) + printf("KeySym "); + + if (flags & SCREEN_FLAG_CAP_VALID) + printf("KeyCap "); + + if (flags & SCREEN_FLAG_DISPLACEMENT_VALID) + printf("KeyDisplacment "); + + if (flags & SCREEN_FLAG_POSITION_VALID) + printf("KeyPosition "); + + if (flags & SCREEN_FLAG_SOURCE_POSITION_VALID) + printf("KeySourcePosition "); + + if (flags & SCREEN_FLAG_SIZE_VALID) + printf("KeySize "); +} + +/* MOUSE POINTER */ + +void +handlePointerEvent(screen_event_t keyEvent) { +/* + Event Type: SCREEN_EVENT_POINTER + + SCREEN_PROPERTY_BUTTONS + SCREEN_PROPERTY_DEVICE + SCREEN_PROPERTY_MODIFIERS + SCREEN_PROPERTY_MOUSE_HORIZONTAL_WHEEL + SCREEN_PROPERTY_MOUSE_WHEEL + SCREEN_PROPERTY_POSITION + SCREEN_PROPERTY_SOURCE_POSITION +*/ +/* NB: keyValue is global loop flag */ + int buttons = 0; + int modifiers = 0; + int wheelHoriz = 0; + int wheelVert = 0; + int position[2]; + int sourcePosition[2]; + + screen_get_event_property_iv(keyEvent, SCREEN_PROPERTY_BUTTONS, &buttons); + screen_get_event_property_iv(keyEvent, SCREEN_PROPERTY_MODIFIERS, &modifiers); + screen_get_event_property_iv(keyEvent, SCREEN_PROPERTY_POSITION, + (int *)&position); + screen_get_event_property_iv(keyEvent, SCREEN_PROPERTY_SOURCE_POSITION, + (int *)&sourcePosition); + screen_get_event_property_iv(keyEvent, SCREEN_PROPERTY_MOUSE_HORIZONTAL_WHEEL, + &wheelHoriz); + screen_get_event_property_iv(keyEvent, SCREEN_PROPERTY_MOUSE_WHEEL, + &wheelVert); + + printf("\n Mouse Point @ (%ld,%ld) ", position[0], position[1]); + printMouseButtons(buttons); + printModifiers(modifiers); + if (wheelHoriz != 0) + printf("\n Horizontal wheel clicks = %d", wheelHoriz); + if (wheelVert != 0) + printf("\n Vertical wheel clicks = %d", wheelVert); +} + +void printMouseButtons(int buttons) { + /* Just a bitmask */ + if (buttons != 0) { + printf(" MouseButton: "); + if (1 & buttons) printf("Left "); + if (2 & buttons) printf("Middle "); + if (4 & buttons) printf("Right "); + } +} + +void printModifiers(int modifiers) +{ + if (modifiers & KEYMOD_SHIFT) + printf("SHIFT "); + if (modifiers & KEYMOD_CTRL) + printf("CTRL "); + if (modifiers & KEYMOD_ALT) + printf("ALT "); + if (modifiers & KEYMOD_ALTGR) + printf("ALTGR "); + if (modifiers & KEYMOD_SHL3) + printf("SHL3 "); + if (modifiers & KEYMOD_MOD6) + printf("MOD6 "); + if (modifiers & KEYMOD_MOD7) + printf("MOD7 "); + if (modifiers & KEYMOD_MOD8) + printf("MOD8 "); + if (modifiers & KEYMOD_SHIFT_LOCK) + printf("ShiftLock "); + if (modifiers & KEYMOD_CTRL_LOCK) + printf("CTRLLock "); + if (modifiers & KEYMOD_ALT_LOCK) + printf("ALTLock "); + if (modifiers & KEYMOD_ALTGR_LOCK) + printf("ALTGRLock "); + if (modifiers & KEYMOD_SHL3_LOCK) + printf("SHL3Lock "); + if (modifiers & KEYMOD_MOD6_LOCK) + printf("MOD6Lock "); + if (modifiers & KEYMOD_MOD7_LOCK) + printf("MOD7Lock "); + if (modifiers & KEYMOD_MOD8_LOCK) + printf("MOD8Lock "); + if (modifiers & KEYMOD_CAPS_LOCK) + printf("CapsLock "); + if (modifiers & KEYMOD_NUM_LOCK) + printf("NumLock "); + if (modifiers & KEYMOD_SCROLL_LOCK ) + printf("ScrollLock "); +} + +void printPCKeys(int keyCode) +{ + if ((keyCode > KEYCODE_PC_KEYS) && (keyCode <= KEYCODE_F12)) { + switch (keyCode) { + case KEYCODE_PAUSE: + printf("PAUSE "); + break; + case KEYCODE_SCROLL_LOCK: + printf("SCROLL_LOCK "); + break; + case KEYCODE_PRINT: + printf("PRINT "); + break; + case KEYCODE_SYSREQ: + printf("SYSREQ "); + break; + case KEYCODE_BREAK: + printf("BREAK "); + break; + case KEYCODE_ESCAPE: + printf("ESCAPE "); + break; + case KEYCODE_BACKSPACE: + printf("BACKSPACE "); + break; + case KEYCODE_TAB: + printf("TAB "); + break; + case KEYCODE_BACK_TAB: + printf("BACK_TAB "); + break; + case KEYCODE_RETURN: + printf("RETURN "); + break; + case KEYCODE_CAPS_LOCK: + printf("CAPS_LOCK "); + break; + case KEYCODE_LEFT_SHIFT: + printf("LEFT_SHIFT "); + break; + case KEYCODE_RIGHT_SHIFT: + printf("RIGHT_SHIFT "); + break; + case KEYCODE_LEFT_CTRL: + printf("LEFT_CTRL "); + break; + case KEYCODE_RIGHT_CTRL: + printf("RIGHT_CTRL "); + break; + case KEYCODE_LEFT_ALT: + printf("LEFT_ALT "); + break; + case KEYCODE_RIGHT_ALT: + printf("RIGHT_ALT "); + break; + case KEYCODE_MENU: + printf("MENU "); + break; + case KEYCODE_LEFT_HYPER: + printf("LEFT_HYPER "); + break; + case KEYCODE_RIGHT_HYPER: + printf("RIGHT_HYPER "); + break; + case KEYCODE_INSERT: + printf("INSERT "); + break; + case KEYCODE_HOME: + printf("HOME "); + break; + case KEYCODE_PG_UP: + printf("PG_UP "); + break; + case KEYCODE_DELETE: + printf("DELETE "); + break; + case KEYCODE_END: + printf("END "); + break; + case KEYCODE_PG_DOWN: + printf("PG_DOWN "); + break; + case KEYCODE_LEFT: + printf("LEFT "); + break; + case KEYCODE_RIGHT: + printf("RIGHT "); + break; + case KEYCODE_UP: + printf("UP "); + break; + case KEYCODE_DOWN: + printf("DOWN "); + break; + case KEYCODE_NUM_LOCK: + printf("NUM_LOCK "); + break; + case KEYCODE_KP_PLUS: + printf("KP_PLUS "); + break; + case KEYCODE_KP_MINUS: + printf("KP_MINUS "); + break; + case KEYCODE_KP_MULTIPLY: + printf("KP_MULTIPLY "); + break; + case KEYCODE_KP_DIVIDE: + printf("KP_DIVIDE "); + break; + case KEYCODE_KP_ENTER: + printf("KP_ENTER "); + break; + case KEYCODE_KP_HOME: + printf("KP_HOME "); + break; + case KEYCODE_KP_UP: + printf("KP_UP "); + break; + case KEYCODE_KP_PG_UP: + printf("KP_PG_UP "); + break; + case KEYCODE_KP_LEFT: + printf("KP_LEFT "); + break; + case KEYCODE_KP_FIVE: + printf("KP_FIVE "); + break; + case KEYCODE_KP_RIGHT: + printf("KP_RIGHT "); + break; + case KEYCODE_KP_END: + printf("KP_END "); + break; + case KEYCODE_KP_DOWN: + printf("KP_DOWN "); + break; + case KEYCODE_KP_PG_DOWN: + printf("KP_PG_DOWN "); + break; + case KEYCODE_KP_INSERT: + printf("KP_INSERT "); + break; + case KEYCODE_KP_DELETE: + printf("KP_DELETE "); + break; + case KEYCODE_F1: + printf("F1 "); + break; + case KEYCODE_F2: + printf("F2 "); + break; + case KEYCODE_F3: + printf("F3 "); + break; + case KEYCODE_F4: + printf("F4 "); + break; + case KEYCODE_F5: + printf("F5 "); + break; + case KEYCODE_F6: + printf("F6 "); + break; + case KEYCODE_F7: + printf("F7 "); + break; + case KEYCODE_F8: + printf("F8 "); + break; + case KEYCODE_F9: + printf("F9 "); + break; + case KEYCODE_F10: + printf("F10 "); + break; + case KEYCODE_F11: + printf("F11 "); + break; + case KEYCODE_F12: + printf("F12 "); + break; + default: + break; + } + } +} + + +/* --- E O F --- */ diff --git a/platforms/unix/vm-display-qnxScreen/sqQNXScreen.c b/platforms/unix/vm-display-qnxScreen/sqQNXScreen.c new file mode 100644 index 0000000000..69415bde03 --- /dev/null +++ b/platforms/unix/vm-display-qnxScreen/sqQNXScreen.c @@ -0,0 +1,1589 @@ + +/* sqQNXScreenDisplay.c -- display driver for QNX Screen subsystem + * + * Author: Ken Dickey + */ + +/* + * Copyright (C) 2025 Kenneth Alan Dickey + * All Rights Reserved. + * + * This file is part of the OpenSmalltalk-VM + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +/* + OpenSmalltalk-vm + https://OpenSmalltalk.org + https://github.com/OpenSmalltalk/opensmalltalk-vm + + QNX free licence & details at + https://qnx.com/getqnx + + QNX 8.0 Screen Developer Documentation + https://www.qnx.com/developers/docs/8.0/ + com.qnx.doc.screen/topic/manual/cscreen_about.html + + Source cross-compiled on Ubuntu/Mint Linux on x86_64 + for target system: Raspberry Pi 4 (aarch64) + QNX 8.0 + + VM Interface + -- struct SqDisplay = access via ioGetDisplayModule() + VM/platforms/unix/vm/SqDisplay.h -- struct sqDisplay def + VM/platforms/Cross/vm/sq.h -- Display/Keyboard/Mouse + events + VM/platforms/unix/vm/sqUnixEvent.c -- SqPoint, mousePosition, recordMouseEvent() + VM/platforms/unix/vm-display-custom/sqUnixCustomModule.h -- generic starting point +*/ + +/* OpenSmalltalk VM */ +#include "sq.h" +#include "sqUnixMain.h" +#include "sqUnixGlobals.h" +#include "sqaio.h" + +#include "SqDisplay.h" + +#if defined(ioMSecs) +# undef ioMSecs +#endif + +/* POSIX */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* QNX */ +#include +#include + +//---------------------------------------------------------------- + +#include "sqUnixEvent.c" + +//static inline int min(int a, int b) { return a < b ? a : b; } +//static inline int max(int a, int b) { return a > b ? a : b; } + +/* Splash Screen Display Image: Squeak Balloon */ + +/* Pixels are kept as 32 bits: uint32_t */ +typedef uint32_t pixel_t; +#include "Balloon.h" /* Squeak Balloon image */ +/* Forward declarations */ +static void failPermissions(const char *who); +void handleKeyboardEvent(screen_event_t keyEvent); +void handlePointerEvent(screen_event_t keyEvent); /* mouse events */ +void printQNXKeyFlags(int flags); +void printQNXModifiers(int modifiers); +void printQNXMouseButtons(int buttons); +void printQNXPCKeys(int keyCode); +static void showBalloons(void * bufPtr); +static void showBalloonAt(void *bufPtr, int left, int top); +static inline void putPixel(int x, int y, pixel_t pix); +static inline pixel_t getPixel(int x, int y); +const pixel_t blackPixel = 0x00000000; +const pixel_t whitePixel = 0x00FFFFFF; +static void showCursor(void); +static int cursorIn(int l, int r, int t, int b); +static inline void showCursorIn(int l, int r, int t, int b); +static inline void hideCursorIn(int l, int r, int t, int b); +static void setCursor(char *bits, char *mask, int xoff, int yoff); +static void advanceCursor(int dx, int dy); +static void cursorTo(int x, int y); + + +/* Software Defined Cursor Info */ +static int cursorBits[] = { + 0b0000000000000000, + 0b0100000000000000, + 0b0110000000000000, + 0b0111000000000000, + 0b0111100000000000, + 0b0111110000000000, + 0b0111111000000000, + 0b0111111100000000, + 0b0111111110000000, + 0b0111110000000000, + 0b0110110000000000, + 0b0100011000000000, + 0b0000011000000000, + 0b0000001100000000, + 0b0000001100000000, + 0b0000000000000000 +}; +static int maskBits[] = { + 0b1100000000000000, + 0b1110000000000000, + 0b1111000000000000, + 0b1111100000000000, + 0b1111110000000000, + 0b1111111000000000, + 0b1111111100000000, + 0b1111111110000000, + 0b1111111111000000, + 0b1111111111100000, + 0b1111111000000000, + 0b1110111100000000, + 0b1100111100000000, + 0b1000011110000000, + 0b0000011110000000, + 0b0000001110000000 +}; + +struct softCursor { + SqPoint position; + SqPoint offset; + int visible; + uint16_t bits[16]; + uint16_t mask[16]; + pixel_t back[16][16]; +}; + +/* QNX data structures */ +screen_context_t screenContext = NULL; +screen_event_t userEvent; +screen_window_t window; +screen_session_t keyboardSession; +screen_buffer_t buffer; +const int screen_cursor[] = { SCREEN_CURSOR_SHAPE_NONE }; +void* bufPointer; /* buffer pointer */ +int stride; /* buffer stride (bytes per scan line) */ +int displaySize[2]; /* {width,height} in pixels */ +const int alwaysTrue = 1; + +static inline int screenWidth(void) { return displaySize[0]; } +static inline int screenHeight(void) { return displaySize[1]; } + + +/* OVERVIEW: + - Create a Screen/Graphic Context + - Create a Render Target + + Set Render Properties + - Allocate Pixmap Buffers + - Render into Buffers + + Post/Update to (re)draw a Buffer + - Attache Devices [Keyboard,Mouse/Pointer,MultiTouch,Joystick] + - Run Event Loop + + Note that microkernel message passing implies copying event data + from external io managers into local storage. When an event is + received, an io manager process dealloctes its event data. + + Here we are staying simple. Our application (the VM) is assumed + here with a single Display, a Mouse, and a Keyboard. Windowing + is our own Smalltalk Windows/Morphs within a single QNX Window + which is the size of the single/main Display. Software rendering. + + QNX architects for multiple displays, Windows, touch events, joystick, game pad.. + Future projects not addressed here. Touch events will need VM support. +*/ + +#if (DEBUG) +static bool DPRINTF_redirecting = false; +typedef struct _debugmsg debugmsg; +struct _debugmsg { + char* msg; + debugmsg* next; +}; +static debugmsg* DPRINTF_debugmsg = NULL; +static debugmsg* DPRINTF_debugmsg_new(void) +{ + debugmsg* msg = calloc(1, sizeof(debugmsg)); + if (!msg) { + perror("no mem for redirect"); + exit(1); + } + if (!DPRINTF_debugmsg) { + DPRINTF_debugmsg = msg; + } else { + debugmsg* cur = DPRINTF_debugmsg; + while (cur->next != NULL) { + cur = cur->next; + } + cur->next = msg; + } + return msg; +} + +static void DPRINTF(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + if (DPRINTF_redirecting) { + debugmsg* new = DPRINTF_debugmsg_new(); + vasprintf(&(new->msg), fmt, ap); + } else { + vprintf(fmt, ap); + } + va_end(ap); +} + +static void DPRINTF_REDIRECT(bool flag) +{ + if (flag) { + printf("DEBUG: saving incoming debug messages\n"); + fflush(stdout); + fflush(stderr); + DPRINTF_redirecting = true; + } else { + DPRINTF_redirecting = false; + fflush(stdout); + fflush(stderr); + printf("DEBUG: replaying saved debug messages\n"); + debugmsg* cur = DPRINTF_debugmsg; + while (cur != NULL) { + printf("%s", cur->msg); + debugmsg* next = cur->next; + free(cur); + cur=next; + } + fflush(stdout); + fflush(stderr); + } +} +#else +#define DPRINTF(fmt, ...) +#define DPRINTF_REDIRECT(b) +#endif + +static void fatalError(const char *who) +{ + perror(who); + exit(1); +} + +static void fatal(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, "\n"); + exit(1); +} + +static void outOfMemory(void) +{ + fatal("out of memory"); +} + + +//---------------------------------------------------------------- +/* PIXELS */ + +static inline int pixelPosition(int x, int y) { + return ( (x * 4) /* 4 = (32/8) = bits-per-pixel/bits-per-byte = bytes/pixel */ + + (y * stride) ); /* stride = bytes per scan line */ +} + +static inline void putPixel(int x, int y, pixel_t pix) +{ + if ((x >= 0) && (y >= 0) && (x < screenWidth()) && (y < screenHeight())) + { + *((pixel_t *)(bufPointer + pixelPosition(x,y))) = pix; + } +} + +static inline pixel_t getPixel(int x, int y) +{ + return ((x >= 0) && (y >= 0) && (x < screenWidth()) && (y < screenHeight())) + ? *((pixel_t *)(bufPointer + pixelPosition(x,y))) + : 0; +} + + static inline void drawPixel(int x, int y, int r, int g, int b) + { + putPixel(x, y, (pixel_t)((r << 16) | (g << 8) | (b << 0))); + } + + +//---------------------------------------------------------------- +/* Soft(ware) Cursor Management */ + +struct softCursor cursor; + +void initCursor(void) +{ + int x,y; + + cursor.position.x = screenHeight() / 2; + cursor.position.y = screenWidth() / 2; + cursor.offset.x = 0; /* Cuis has cursor: -1@-1, mask: 0@0 */ + cursor.offset.y = 0; + cursor.visible = 0; + + for (x = 0; x < 16; x++) { + cursor.bits[x] = cursorBits[x]; + cursor.mask[x] = maskBits[x]; + for (y = 0; y < 16; y++) { + cursor.back[x][y] = 0; + } + } + showCursor(); +} + +static void hideCursor(void) +{ + if (cursor.visible) + { + int xo= cursor.position.x + cursor.offset.x; + int yo= cursor.position.y + cursor.offset.y; + int x, y; + for (y= 0; y < 16; y++) + for (x= 0; x < 16; x++) + putPixel( xo + x, yo + y, cursor.back[y][x] ); + cursor.visible= 0; + } +} + +static void showCursor(void) +{ + if (!cursor.visible) + { + int xo= cursor.position.x + cursor.offset.x; + int yo= cursor.position.y + cursor.offset.y; + int y; + for (y= 0; y < 16; y += 1) + { + unsigned short bits= cursor.bits[y]; + unsigned short mask= cursor.mask[y]; + int x; + for (x= 0; x < 16; x += 1) + { + /* Look at top bit, then shift & look at next bit.. */ + cursor.back[y][x]= getPixel( xo + x, yo + y ); + if (bits & 0x8000) putPixel( xo + x, yo + y, blackPixel ); + else if (mask & 0x8000) putPixel( xo + x, yo + y, whitePixel ); + bits <<= 1; + mask <<= 1; + } + } + cursor.visible = 1; + } +} + +static int cursorIn(int l, int r, int t, int b) +{ + int cl= cursor.position.x + cursor.offset.x; + int cr= cl + 15; + int ct= cursor.position.y + cursor.offset.y; + int cb= ct + 15; + return !((cr < l) || (cl > r) || (ct > b) || (cb < t)); +} + +static inline void hideCursorIn(int l, int r, int t, int b) +{ + if (cursorIn(l, r, t, b)) + hideCursor(); +} + +static inline void showCursorIn(int l, int r, int t, int b) +{ + if (cursorIn(l, r, t, b)) + showCursor(); +} + + +static void setCursor(char *bits, char *mask, int xoff, int yoff) +{ + int y; + hideCursor(); + cursor.offset.x= xoff; + cursor.offset.y= yoff; + for (y= 0; y < 16; y = y+1) + { + /* Pick off top 16 bits of 32 bit elements; lower 16 unused */ + cursor.bits[y]= (((pixel_t *)bits)[y]) >> 16; + if (mask) { + cursor.mask[y]= (((pixel_t *)mask)[y]) >> 16; + } else { /* unmasked cursor */ + cursor.mask[y]= cursor.bits[y]; /* Black Bits matter */ + } + } + showCursor(); +} + + +static void advanceCursor(int dx, int dy) +{ + hideCursor(); + cursor.position.x= max(0, min(cursor.position.x + dx, screenWidth() - 1)); + cursor.position.y= max(0, min(cursor.position.y + dy, screenHeight() - 1)); + showCursor(); +} + +static void cursorTo(int x, int y) +{ + hideCursor(); + cursor.position.x= x; + cursor.position.y= y; + showCursor(); +} + +//---------------------------------------------------------------- + +static sqInt display_ioBeep(void) +{ + /* @@FIXME: NYI@@ */ + return 0; +} + + +static sqInt display_ioRelinquishProcessorForMicroseconds(sqInt microSeconds) +{ + aioSleepForUsecs(microSeconds); + return 0; +} + + +static sqInt display_ioProcessEvents(void) +{ + int objectType, eventType; + int pollMax = 0; + + while ((pollMax < 1) && (screen_get_event( screenContext, userEvent, 0) == 0)) { /* zero on success */ + + pollMax += 1; + + if (screen_get_event_property_iv(userEvent,SCREEN_PROPERTY_OBJECT_TYPE,&objectType) + != 0) { + DPRINTF("\nEvent Object type failure. Errno = 0x%lx", errno); + break; + } + if (screen_get_event_property_iv(userEvent,SCREEN_PROPERTY_OBJECT_TYPE,&objectType) + != 0) { + DPRINTF("\nEvent Object type failure. Errno = 0x%lx", errno); + break; + } + /* else { */ + /* printf("\nEvent Object Type: 0x%lx", objectType); */ + /* switch (objectType) { */ + /* case SCREEN_OBJECT_TYPE_CONTEXT: */ + /* printf(": Context"); */ + /* break; */ + /* case SCREEN_OBJECT_TYPE_GROUP: */ + /* printf(": Group"); */ + /* break; */ + /* case SCREEN_OBJECT_TYPE_DISPLAY: */ + /* printf(": Display"); */ + /* break; */ + /* case SCREEN_OBJECT_TYPE_DEVICE: */ + /* printf(": Device"); */ + /* break; */ + /* case SCREEN_OBJECT_TYPE_PIXMAP: */ + /* printf(": Pixmap"); */ + /* break; */ + /* case SCREEN_OBJECT_TYPE_SESSION: */ + /* printf(": Session"); */ + /* break; */ + /* case SCREEN_OBJECT_TYPE_STREAM: */ + /* printf(": Stream"); */ + /* break; */ + /* case SCREEN_OBJECT_TYPE_WINDOW: */ + /* printf(": Window"); */ + /* break; */ + /* default: */ + /* break; */ + /* } */ + /* } */ + if (objectType == SCREEN_OBJECT_TYPE_WINDOW) { + + if (screen_get_event_property_iv(userEvent,SCREEN_PROPERTY_TYPE,&eventType) != 0) { + DPRINTF("\nEvent type failure. Errno = 0x%lx", errno); + break; + } + + switch (eventType) { + + case SCREEN_EVENT_NONE: + DPRINTF("\nGot NULL Event"); + break; + + case SCREEN_EVENT_KEYBOARD: + /* DPRINTF("\nGot KEYBOARD Event"); */ + handleKeyboardEvent(userEvent); + break; + + case SCREEN_EVENT_POINTER: + /* DPRINTF("\nGot MOUSE POINTER Event"); */ + handlePointerEvent(userEvent); + break; + + case SCREEN_EVENT_GAMEPAD: + case SCREEN_EVENT_JOYSTICK: + DPRINTF("\nGot Joystick/Game Event"); + /* handleJoystickEvent(userEvent); */ + break; + default: + DPRINTF("\nGot UNHANDLED Event Type: 0x%lx", eventType); + break; + } + } + } + + pollMax = 0; /* reset */ + + return 0; +} + + +static sqInt display_ioScreenDepth(void) +{ + return 32; /* bits per pixel @@REVISIT: dynamic ask QNX? @@ */ +} + + +static double display_ioScreenScaleFactor(void) +{ + return 1; +} + +static sqInt display_ioScreenSize(void) +{ /* QNX Screen: displaySize[2] => {width, height} */ + return ((displaySize[0] << 16) | displaySize[1]); +} + + +static sqInt display_ioSetCursorWithMask(sqInt cursorBitsIndex, sqInt cursorMaskIndex, sqInt offsetX, sqInt offsetY) +{ + setCursor((char *)cursorBitsIndex, + (char *)cursorMaskIndex, + (int)offsetX, + (int)offsetY); + return 0; +} + + +static sqInt display_ioSetCursorARGB(sqInt cursorBitsIndex, sqInt extentX, sqInt extentY, sqInt offsetX, sqInt offsetY) +{ + return 0; +} + +static inline unsigned long pixel_position(int x, int y) { + return (x * sizeof(pixel_t)) + (y * stride); +} + +static sqInt display_ioShowDisplay(sqInt dispBitsIndex, + sqInt width, sqInt height, + sqInt depth, + sqInt left, sqInt right, + sqInt top, sqInt bottom) +{ + int x, y; + char *bits; + + if ((depth != display_ioScreenDepth()) + || (width != screenWidth()) + || (height != screenHeight()) + || (right < left) + || (bottom < top)) + return 0; + + hideCursorIn(left, right, top, bottom); + bits = pointerForOop(dispBitsIndex); + for (y= top; y < bottom; y += 1) + { + pixel_t *in= (pixel_t *)(bits + ((left + (y * screenWidth())) * 4)); + pixel_t *out= (pixel_t *)(bufPointer + pixelPosition(left, y)); + for (x= left; x < right; x += 1, in += 1, out += 1) + { + out[0]= in[0]; + } + } + showCursorIn(left, right, top, bottom); + return 0; +} + + +static sqInt display_ioHasDisplayDepth(sqInt i) +{ + DPRINTF("hasDisplayDepth %d (%d) => %d\n", i, 32, (i == 32)); + return (i == 32); +} + + +static void openDisplay(void) +{ + int sessionVisible = SCREEN_PROPERTY_VISIBLE; /* => active */ + int usage = SCREEN_USAGE_NATIVE; + int eventType = 0; + int objectType = 0; + + DPRINTF("openDisplay\n"); + DPRINTF_REDIRECT(true); + if (screen_create_context(&screenContext,SCREEN_APPLICATION_CONTEXT) < 0) { + perror("QNX: Cannot create Screen Context"); + exit(errno); + } + + if (screen_create_window_type(&window, + screenContext, + (SCREEN_APPLICATION_WINDOW |SCREEN_ROOT_WINDOW)) < 0) { + perror("QNX: Cannot create QNX Display Window"); + exit(errno); + } + + if (screen_create_window_buffers(window, 1) < 0) { + perror("QNX: Cannot create Window Buffer"); + exit(errno); + } + + /* Render Setup */ + screen_set_window_property_iv(window, SCREEN_PROPERTY_FORMAT, + (const int[]){ SCREEN_FORMAT_RGBX8888 }); + screen_set_window_property_iv(window, SCREEN_PROPERTY_USAGE, + (const int[]) { SCREEN_USAGE_READ | SCREEN_USAGE_WRITE }); + screen_get_window_property_iv(window, SCREEN_PROPERTY_BUFFER_SIZE, displaySize); + screen_get_window_property_pv(window, SCREEN_PROPERTY_BUFFERS, (void **)&buffer); + screen_get_buffer_property_pv(buffer, SCREEN_PROPERTY_POINTER, &bufPointer); + screen_get_buffer_property_iv(buffer, SCREEN_PROPERTY_STRIDE, &stride); + + screen_fill(screenContext, + buffer, + (const int[]){ SCREEN_BLIT_COLOR, whitePixel, SCREEN_BLIT_END }); + + screen_set_window_property_iv(window, SCREEN_PROPERTY_VISIBLE, &alwaysTrue); + screen_create_session_type(keyboardSession, &screenContext, SCREEN_EVENT_POINTER ); + screen_set_window_property_iv(window, SCREEN_PROPERTY_CURSOR, &screen_cursor); + + screen_flush_blits(screenContext, SCREEN_WAIT_IDLE); + screen_post_window(window, buffer, 0, NULL, SCREEN_WAIT_IDLE); + + showBalloons(bufPointer); + screen_flush_blits(screenContext, SCREEN_WAIT_IDLE); + screen_post_window(window, buffer, 0, NULL, SCREEN_WAIT_IDLE); + + sleep( 1 ); /* Let the user see splash screen */ + + /* FOR THE USER */ + + if (screen_create_event(&userEvent) != 0) { + perror("QNX: Cannot create User Event holder"); + exit(errno); + } + + /* ioSetInputSemaphore( 1 ) ; *@@??@@*/ +} + + +static void closeDisplay(void) +{ + DPRINTF("closeDisplay\n"); + DPRINTF_REDIRECT(false); + screen_destroy_window( window ); + screen_destroy_context( screenContext ); +} + + +static char *display_winSystemName(void) +{ + return "qnxScreenDisplay"; +} + + +static void display_winInit(void) +{ +} + + +static void display_winOpen(int argc, char *dropFiles[]) +{ + openDisplay(); + initCursor(); +} + + +static void failPermissions(const char *who) +{ + fprintf(stderr, "Cannot open %s\n", who); + fprintf(stderr, "You should be running QNX on a Raspberry Pi 4/5\n"); + fprintf(stderr, " with a Display, Keyboard, & Mouse\n"); + fprintf(stderr, "Check sources at github.com/OpenSmalltalk/opensmalltalk-vm\n"); + fprintf(stderr, " /platforms/unix/vm-display-qnxScreen\n"); + fprintf(stderr, "Ask/Report on vm-dev@lists.squeakfoundation.org\n"); + exit(1); +} + + +static void display_printUsage(void) +{ + printf("\nNO currently used QNX Display options\n"); +} + + +static void display_printUsageNotes(void) +{ + ; /* skip */ +} + + +static void display_parseEnvironment(void) +{ + /* Currently NO Environment Variables Used */ + + /* How2: + char *ev= 0; + if ((ev= getenv("SQUEAK_FBDEV"))) fbDev= strdup(ev); + if ((ev= getenv("SQUEAK_KBMAP"))) kmPath= strdup(ev); + */ +} + + +static int display_parseArgument(int argc, char **argv) +{ + /* Currently NO Arguments Used */ + + /* how2: */ + /* int n= 1; */ + /* char *arg= argv[0]; */ + + /* if (!strcmp(arg, "-vtlock")) vtLock= 1; */ + /* else if (!strcmp(arg, "-vtswitch")) vtSwitch= 1; */ + /* else if (argv[1]) /\* option requires an argument *\/ */ + /* { */ + /* n= 2; */ + /* if (!strcmp(arg, "-fbdev")) fbDev= argv[1]; */ + /* else if (!strcmp(arg, "-kbmap")) kmPath= argv[1]; */ + /* else if (!strcmp(arg, "-msdev")) msDev= argv[1]; */ + /* else if (!strcmp(arg, "-kbdev")) kbDev.kbName= argv[1]; */ + /* else if (!strcmp(arg, "-msproto")) msProto= argv[1]; */ + /* else */ + /* n= 0; /\* not recognised *\/ */ + /* } */ + /* else */ + /* n= 0; */ + /* return n; */ + + return( 0 ) ; +} + +//---------------------------------------------------------------- +/* KEYBOARD */ + +/* Map between QNX Screen World & OpenSmalltalk VM World */ +/* Smalltalk: `Sensor kbdTest.` */ +int keyMap( int keyValue, int keyFlags, int sqModifiers, int keyCap, int keySym ) { + int keyResult; + + if (keyValue == 0) { + keyResult = keyCap; /* ctrl, alt */ + } else { + keyResult = keyValue; + } + + if (sqModifiers & CtrlKeyBit) { /* Control Keys */ + keyResult &= 0x00FF; + keyResult -= 0x60; /* e.g. m=0x6D ^M=0x0D */ + if (keyResult > 0x20) { + DPRINTF("\nkeyMap(): Bogus control key 0x%x\n", keyResult); + return( 0 ) ; + } + return( keyResult ); + } + + if (keyResult <= 0x7F) { /* simple ASCII */ + return( keyResult ); + } + + if ((keyResult > KEYCODE_PC_KEYS) && (keyResult <= KEYCODE_F12)) { + switch ( keyResult ) { + /* Nota Bene: VM only handles some keys: `Sensor kbdTest.` */ + /* case KEYCODE_PAUSE: */ + /* printf("PAUSE "); */ + /* break; */ + /* case KEYCODE_SCROLL_LOCK: */ + /* printf("SCROLL_LOCK "); */ + /* break; */ + /* case KEYCODE_PRINT: */ + /* printf("PRINT "); */ + /* break; */ + /* case KEYCODE_SYSREQ: */ + /* printf("SYSREQ "); */ + /* break; */ + /* case KEYCODE_BREAK: */ + /* printf("BREAK "); */ + /* break; */ + case KEYCODE_ESCAPE: + keyResult = 0x1B; + break; + case KEYCODE_BACKSPACE: + keyResult = 0x08; + break; + case KEYCODE_TAB: + keyResult = 0x09; + break; + /* case KEYCODE_BACK_TAB: */ + /* printf("BACK_TAB "); */ + /* break; */ + case KEYCODE_RETURN: + keyResult = 0x0D; /* CR */ + break; + /* case KEYCODE_CAPS_LOCK: */ + /* printf("CAPS_LOCK "); */ + /* break; */ + /* case KEYCODE_LEFT_SHIFT: */ + /* printf("LEFT_SHIFT "); */ + /* break; */ + /* case KEYCODE_RIGHT_SHIFT: */ + /* printf("RIGHT_SHIFT "); */ + /* break; */ + /* case KEYCODE_LEFT_CTRL: */ + /* printf("LEFT_CTRL "); */ + /* break; */ + /* case KEYCODE_RIGHT_CTRL: */ + /* printf("RIGHT_CTRL "); */ + /* break; */ + /* case KEYCODE_LEFT_ALT: */ + /* printf("LEFT_ALT "); */ + /* break; */ + /* case KEYCODE_RIGHT_ALT: */ + /* printf("RIGHT_ALT "); */ + /* break; */ + /* case KEYCODE_MENU: */ + /* printf("MENU "); */ + /* break; */ + /* case KEYCODE_LEFT_HYPER: */ + /* printf("LEFT_HYPER "); */ + /* break; */ + /* case KEYCODE_RIGHT_HYPER: */ + /* printf("RIGHT_HYPER "); */ + /* break; */ + case KEYCODE_INSERT: + keyResult = 5; + break; + case KEYCODE_HOME: + keyResult = 1; + break; + case KEYCODE_PG_UP: + keyResult = 11; + break; + case KEYCODE_DELETE: + keyResult = 127; + break; + case KEYCODE_END: + keyResult = 4; + break; + case KEYCODE_PG_DOWN: + keyResult = 12; + break; + case KEYCODE_LEFT: /* arrow */ + keyResult = 28; + break; + case KEYCODE_RIGHT: /* arrow */ + keyResult = 29; + break; + case KEYCODE_UP: /* arrow */ + keyResult = 30; + break; + case KEYCODE_DOWN: /* arrow */ + keyResult = 31; + break; + /* case KEYCODE_NUM_LOCK: */ + /* printf("NUM_LOCK "); */ + /* break; */ + case KEYCODE_KP_PLUS: + keyResult = 0x2B; + break; + case KEYCODE_KP_MINUS: + keyResult = 0x2D; + break; + case KEYCODE_KP_MULTIPLY: + keyResult = 0x2A; + break; + case KEYCODE_KP_DIVIDE: + keyResult = 0x2F; + break; + case KEYCODE_KP_ENTER: + keyResult = 0x0D; + break; + case KEYCODE_KP_HOME: + keyResult = 1; + break; + case KEYCODE_KP_UP: + keyResult = 30; + break; + case KEYCODE_KP_PG_UP: + keyResult = 11; + break; + case KEYCODE_KP_LEFT: + keyResult = 28; + break; + case KEYCODE_KP_FIVE: + keyResult = 0x35; + break; + case KEYCODE_KP_RIGHT: + keyResult = 29; + break; + case KEYCODE_KP_END: + keyResult = 4; + break; + case KEYCODE_KP_DOWN: + keyResult = 31; + break; + case KEYCODE_KP_PG_DOWN: + keyResult = 12; + break; + case KEYCODE_KP_INSERT: + keyResult = 5; + break; + case KEYCODE_KP_DELETE: + keyResult = 127; + break; + /* case KEYCODE_F1: */ + /* printf("F1 "); */ + /* break; */ + /* case KEYCODE_F2: */ + /* printf("F2 "); */ + /* break; */ + /* case KEYCODE_F3: */ + /* printf("F3 "); */ + /* break; */ + /* case KEYCODE_F4: */ + /* printf("F4 "); */ + /* break; */ + /* case KEYCODE_F5: */ + /* printf("F5 "); */ + /* break; */ + /* case KEYCODE_F6: */ + /* printf("F6 "); */ + /* break; */ + /* case KEYCODE_F7: */ + /* printf("F7 "); */ + /* break; */ + /* case KEYCODE_F8: */ + /* printf("F8 "); */ + /* break; */ + /* case KEYCODE_F9: */ + /* printf("F9 "); */ + /* break; */ + /* case KEYCODE_F10: */ + /* printf("F10 "); */ + /* break; */ + /* case KEYCODE_F11: */ + /* printf("F11 "); */ + /* break; */ + /* case KEYCODE_F12: */ + /* printf("F12 "); */ + /* break; */ + default: + DPRINTF("\nUHANDLED PC_KEY: 0x%x\n", keyResult ); + keyResult = 0; /* UNHANDLED */ + break; + } + return( keyResult ); + } + return( 0 ); /* Not handled */ +} + +void +handleKeyboardEvent(screen_event_t keyEvent) { +/* +Event Type: SCREEN_EVENT_KEYBOARD + + SCREEN_PROPERTY_DEVICE + SCREEN_PROPERTY_FLAGS + SCREEN_PROPERTY_KEY_ALTERNATE_SYM + SCREEN_PROPERTY_KEY_CAP + SCREEN_PROPERTY_MODIFIERS + SCREEN_PROPERTY_SCAN + SCREEN_PROPERTY_SEQUENCE_ID + SCREEN_PROPERTY_SYM +*/ + int keyValue = 0; + int keyFlags = 0; + int keyModifiers = 0; + int keyCap = 0; + int keySym = 0; + int keyScan = 0; + int keyCodeSupplied = 0; + int sqModifiers = 0; + int sqPressCode = 0; + + screen_get_event_property_iv(keyEvent, SCREEN_PROPERTY_SYM, &keyValue); + screen_get_event_property_iv(keyEvent, SCREEN_PROPERTY_FLAGS, &keyFlags); + screen_get_event_property_iv(keyEvent, SCREEN_PROPERTY_MODIFIERS, &keyModifiers); + if (keyFlags & SCREEN_FLAG_CAP_VALID) + screen_get_event_property_iv(keyEvent, SCREEN_PROPERTY_KEY_CAP, &keyCap); + if (keyFlags & SCREEN_FLAG_SYM_VALID) + screen_get_event_property_iv(keyEvent, SCREEN_PROPERTY_SYM, &keySym); + + /* Map between QNX Screen World & OpenSmalltalk VM World */ + if (keyModifiers & KEYMOD_SHIFT) { sqModifiers |= ShiftKeyBit; } + if (keyModifiers & KEYMOD_CTRL) { sqModifiers |= CtrlKeyBit; } + if (keyModifiers & KEYMOD_ALT) { sqModifiers |= CommandKeyBit; + /* NB: ALT+. NOT CTL+. */ + if (keyValue == 0x2E) { /* Command+period = meta+dot */ + setInterruptPending(true); + return; + } + } + + if (keyFlags & SCREEN_FLAG_KEY_DOWN) { + sqPressCode = EventKeyDown; + } else { + sqPressCode = EventKeyUp; + } + + keyCodeSupplied = keyMap( keyValue, keyFlags, sqModifiers, keyCap, keySym ); + + if ((keyCodeSupplied != 0) && (keyCodeSupplied <= 0x7F)) { +#if defined(DEBUG) + printf("\nKeyCodeSupplied: 0x%x", keyCodeSupplied); +#endif + /*@@@ if (keyCodeSupplied < 0x20) { sqModifiers |= CtrlKeyBit; } @@@*/ + recordKeyboardEvent( keyCodeSupplied, sqPressCode, sqModifiers, keyCodeSupplied ); + if (sqPressCode == EventKeyDown) { + recordKeyboardEvent( keyCodeSupplied, EventKeyChar, sqModifiers, keyCodeSupplied ); + } + } + +#if defined(DEBUG) + + if ((keyValue >= 0x20) && (keyValue <= 0x7F)) + printf("\nASCII '%c' ", keyValue); + else + printf("\n"); + if ((keyModifiers & KEYMOD_CTRL) && (keyCap < 0x7F)) + printf("CTL ^%c ", (keyCap - 0x20)); + + if ((keyModifiers & KEYMOD_ALT) && (keyCap < 0x7F)) + printf("ALT %c ", keyCap); + + printQNXPCKeys(keyValue); /* NON-ASII, e.g. keypadkeys, home, .. */ + printQNXModifiers(keyModifiers); /* SHIFT, etc. */ + printf(" KeyCode=0x%x ", keyValue); + printQNXKeyFlags(keyFlags); + + if (keyFlags & SCREEN_FLAG_CAP_VALID) { + screen_get_event_property_iv(keyEvent, SCREEN_PROPERTY_KEY_CAP, &keyCap); + printf(" keyCap=0x%x", keyCap); + } + + if (keyFlags & SCREEN_FLAG_SYM_VALID) { + screen_get_event_property_iv(keyEvent, SCREEN_PROPERTY_SYM, &keySym); + printf(" keySym=0x%x", keySym); + } + /* NB: For control keys, keySym is not valid. */ + + if (keyFlags & SCREEN_FLAG_SCAN_VALID) { /* Physical Keyboard Key Location */ + screen_get_event_property_iv(keyEvent, SCREEN_PROPERTY_SCAN, &keyScan); + printf(" location=0x%x", keyScan); + } +#endif +} + +void printQNXKeyFlags(int flags) { + + if (flags & SCREEN_FLAG_KEY_DOWN) + printf("KeyDOWN "); + else + printf("KeyUP "); + + if (flags & SCREEN_FLAG_KEY_REPEAT) + printf("KeyRepeat "); + + /* if (flags & SCREEN_FLAG_SCAN_VALID) */ + /* printf("KeyScanValid "); */ + + /* if (flags & SCREEN_FLAG_SYM_VALID) */ + /* printf("KeySym "); */ + + /* if (flags & SCREEN_FLAG_CAP_VALID) */ + /* printf("KeyCap "); */ + + /* if (flags & SCREEN_FLAG_DISPLACEMENT_VALID) */ + /* printf("KeyDisplacment "); */ + + /* if (flags & SCREEN_FLAG_POSITION_VALID) */ + /* printf("KeyPosition "); */ + + /* if (flags & SCREEN_FLAG_SOURCE_POSITION_VALID) */ + /* printf("KeySourcePosition "); */ + + /* if (flags & SCREEN_FLAG_SIZE_VALID) */ + /* printf("KeySize "); */ +} + +//---------------------------------------------------------------- +/* MOUSE POINTER */ + +void +handlePointerEvent(screen_event_t keyEvent) { +/* + Event Type: SCREEN_EVENT_POINTER + + SCREEN_PROPERTY_BUTTONS + SCREEN_PROPERTY_DEVICE + SCREEN_PROPERTY_MODIFIERS + SCREEN_PROPERTY_MOUSE_HORIZONTAL_WHEEL + SCREEN_PROPERTY_MOUSE_WHEEL + SCREEN_PROPERTY_POSITION + SCREEN_PROPERTY_SOURCE_POSITION +*/ +/* NB: keyValue is global loop flag */ + int qnxButtons = 0; + int qnxModifiers = 0; + int wheelHoriz = 0; + int wheelVert = 0; + int position[2]; + int sourcePosition[2]; + + screen_get_event_property_iv(keyEvent, SCREEN_PROPERTY_BUTTONS, &qnxButtons); + screen_get_event_property_iv(keyEvent, SCREEN_PROPERTY_MODIFIERS, &qnxModifiers); + screen_get_event_property_iv(keyEvent, SCREEN_PROPERTY_POSITION, + (int *)&position); + /* screen_get_event_property_iv(keyEvent, SCREEN_PROPERTY_SOURCE_POSITION, */ + /* (int *)&sourcePosition); */ + screen_get_event_property_iv(keyEvent, SCREEN_PROPERTY_MOUSE_HORIZONTAL_WHEEL, + &wheelHoriz); + screen_get_event_property_iv(keyEvent, SCREEN_PROPERTY_MOUSE_WHEEL, + &wheelVert); + + /* map between QNX Screen World & OpenSmalltalk VM World */ + mousePosition.x = position[0]; + mousePosition.y = position[1]; + /* NYI -- no single button mouse in QNX + * red button honours the modifiers: + * red+ctrl = yellow button + * red+command = blue button + */ + buttonState = 0; + if (qnxButtons & 1) { buttonState |= RedButtonBit; } /* Left */ + if (qnxButtons & 2) { buttonState |= YellowButtonBit; }/* Middle */ + if (qnxButtons & 4) { buttonState |= BlueButtonBit; } /* Right */ + modifierState = 0; + if (qnxModifiers & KEYMOD_SHIFT) { modifierState |= ShiftKeyBit; } + if (qnxModifiers & KEYMOD_CTRL) { modifierState |= CtrlKeyBit; } + if (qnxModifiers & KEYMOD_ALT) { modifierState |= CommandKeyBit; } + + cursorTo(mousePosition.x, mousePosition.y); + + if (wheelVert != 0) { + recordMouseWheelEvent(0, (- wheelVert)); /* invert wheel direction */ + } + else { + recordMouseEvent(); + } + +#if defined(EVENT_MOUSE) + printf("\n Mouse Point @ (%d,%d) ", position[0], position[1]); + printQNXMouseButtons(qnxButtons); + printQNXModifiers(qnxModifiers); + if (wheelHoriz != 0) + printf("\n Horizontal wheel clicks = %d", wheelHoriz); + if (wheelVert != 0) + printf("\n Vertical wheel clicks = %d", wheelVert); +#endif +} + +void printQNXMouseButtons(int buttons) { + /* Just a bitmask */ + if (buttons != 0) { + printf(" MouseButton: "); + if (1 & buttons) printf("Left/Red "); + if (2 & buttons) printf("Middle/Yellow "); + if (4 & buttons) printf("Right/Blue "); + } +} + +void printQNXModifiers(int modifiers) +{ + if (modifiers & KEYMOD_SHIFT) + printf("SHIFT "); + if (modifiers & KEYMOD_CTRL) + printf("CTRL "); + if (modifiers & KEYMOD_ALT) + printf("ALT "); + if (modifiers & KEYMOD_ALTGR) + printf("ALTGR "); + if (modifiers & KEYMOD_SHL3) + printf("SHL3 "); + if (modifiers & KEYMOD_MOD6) + printf("MOD6 "); + if (modifiers & KEYMOD_MOD7) + printf("MOD7 "); + if (modifiers & KEYMOD_MOD8) + printf("MOD8 "); + if (modifiers & KEYMOD_SHIFT_LOCK) + printf("ShiftLock "); + if (modifiers & KEYMOD_CTRL_LOCK) + printf("CTRLLock "); + if (modifiers & KEYMOD_ALT_LOCK) + printf("ALTLock "); + if (modifiers & KEYMOD_ALTGR_LOCK) + printf("ALTGRLock "); + if (modifiers & KEYMOD_SHL3_LOCK) + printf("SHL3Lock "); + if (modifiers & KEYMOD_MOD6_LOCK) + printf("MOD6Lock "); + if (modifiers & KEYMOD_MOD7_LOCK) + printf("MOD7Lock "); + if (modifiers & KEYMOD_MOD8_LOCK) + printf("MOD8Lock "); + if (modifiers & KEYMOD_CAPS_LOCK) + printf("CapsLock "); + if (modifiers & KEYMOD_NUM_LOCK) + printf("NumLock "); + if (modifiers & KEYMOD_SCROLL_LOCK ) + printf("ScrollLock "); +} + +void printQNXPCKeys(int keyCode) +{ + if ((keyCode > KEYCODE_PC_KEYS) && (keyCode <= KEYCODE_F12)) { + switch (keyCode) { + case KEYCODE_PAUSE: + printf("PAUSE "); + break; + case KEYCODE_SCROLL_LOCK: + printf("SCROLL_LOCK "); + break; + case KEYCODE_PRINT: + printf("PRINT "); + break; + case KEYCODE_SYSREQ: + printf("SYSREQ "); + break; + case KEYCODE_BREAK: + printf("BREAK "); + break; + case KEYCODE_ESCAPE: + printf("ESCAPE "); + break; + case KEYCODE_BACKSPACE: + printf("BACKSPACE "); + break; + case KEYCODE_TAB: + printf("TAB "); + break; + case KEYCODE_BACK_TAB: + printf("BACK_TAB "); + break; + case KEYCODE_RETURN: + printf("RETURN "); + break; + case KEYCODE_CAPS_LOCK: + printf("CAPS_LOCK "); + break; + case KEYCODE_LEFT_SHIFT: + printf("LEFT_SHIFT "); + break; + case KEYCODE_RIGHT_SHIFT: + printf("RIGHT_SHIFT "); + break; + case KEYCODE_LEFT_CTRL: + printf("LEFT_CTRL "); + break; + case KEYCODE_RIGHT_CTRL: + printf("RIGHT_CTRL "); + break; + case KEYCODE_LEFT_ALT: + printf("LEFT_ALT "); + break; + case KEYCODE_RIGHT_ALT: + printf("RIGHT_ALT "); + break; + case KEYCODE_MENU: + printf("MENU "); + break; + case KEYCODE_LEFT_HYPER: + printf("LEFT_HYPER "); + break; + case KEYCODE_RIGHT_HYPER: + printf("RIGHT_HYPER "); + break; + case KEYCODE_INSERT: + printf("INSERT "); + break; + case KEYCODE_HOME: + printf("HOME "); + break; + case KEYCODE_PG_UP: + printf("PG_UP "); + break; + case KEYCODE_DELETE: + printf("DELETE "); + break; + case KEYCODE_END: + printf("END "); + break; + case KEYCODE_PG_DOWN: + printf("PG_DOWN "); + break; + case KEYCODE_LEFT: + printf("LEFT "); + break; + case KEYCODE_RIGHT: + printf("RIGHT "); + break; + case KEYCODE_UP: + printf("UP "); + break; + case KEYCODE_DOWN: + printf("DOWN "); + break; + case KEYCODE_NUM_LOCK: + printf("NUM_LOCK "); + break; + case KEYCODE_KP_PLUS: + printf("KP_PLUS "); + break; + case KEYCODE_KP_MINUS: + printf("KP_MINUS "); + break; + case KEYCODE_KP_MULTIPLY: + printf("KP_MULTIPLY "); + break; + case KEYCODE_KP_DIVIDE: + printf("KP_DIVIDE "); + break; + case KEYCODE_KP_ENTER: + printf("KP_ENTER "); + break; + case KEYCODE_KP_HOME: + printf("KP_HOME "); + break; + case KEYCODE_KP_UP: + printf("KP_UP "); + break; + case KEYCODE_KP_PG_UP: + printf("KP_PG_UP "); + break; + case KEYCODE_KP_LEFT: + printf("KP_LEFT "); + break; + case KEYCODE_KP_FIVE: + printf("KP_FIVE "); + break; + case KEYCODE_KP_RIGHT: + printf("KP_RIGHT "); + break; + case KEYCODE_KP_END: + printf("KP_END "); + break; + case KEYCODE_KP_DOWN: + printf("KP_DOWN "); + break; + case KEYCODE_KP_PG_DOWN: + printf("KP_PG_DOWN "); + break; + case KEYCODE_KP_INSERT: + printf("KP_INSERT "); + break; + case KEYCODE_KP_DELETE: + printf("KP_DELETE "); + break; + case KEYCODE_F1: + printf("F1 "); + break; + case KEYCODE_F2: + printf("F2 "); + break; + case KEYCODE_F3: + printf("F3 "); + break; + case KEYCODE_F4: + printf("F4 "); + break; + case KEYCODE_F5: + printf("F5 "); + break; + case KEYCODE_F6: + printf("F6 "); + break; + case KEYCODE_F7: + printf("F7 "); + break; + case KEYCODE_F8: + printf("F8 "); + break; + case KEYCODE_F9: + printf("F9 "); + break; + case KEYCODE_F10: + printf("F10 "); + break; + case KEYCODE_F11: + printf("F11 "); + break; + case KEYCODE_F12: + printf("F12 "); + break; + default: + break; + } + } +} + +/* CLIPBOARD */ + +static sqInt display_clipboardSize(void) { return 0; } +static sqInt display_clipboardWriteFromAt(sqInt n, sqInt ptr, sqInt off) { return 0; } +static sqInt display_clipboardReadIntoAt(sqInt n, sqInt ptr, sqInt off) { return 0; } +static char **display_clipboardGetTypeNames(void) { return 0; } +static sqInt display_clipboardSizeWithType(char *typeName, int ntypeName) { return 0; } + +static void display_clipboardWriteWithType(char *data, size_t ndata, char *typeName, size_t ntypeName, int isDnd, int isClaiming) {} + +static sqInt display_dndOutStart(char *types, int ntypes) { return 0; } +static void display_dndOutSend(char *bytes, int nbytes) { return ; } +/* UNUSED static void display_dndLaunchFile(char *fileName) { return ; } */ +static sqInt display_dndOutAcceptedType(char * buf, int nbuf) { return 0; } +static sqInt display_dndReceived(char *fileName) { return 0; } + +static sqInt display_ioFormPrint(sqInt bits, sqInt w, sqInt h, sqInt d, double hs, double vs, sqInt l) { return 0; } + +static sqInt display_ioSetFullScreen(sqInt fullScreen) { return 0; } /* Our 1 window is already fullscreen */ + +static sqInt display_ioForceDisplayUpdate(void) +{ + screen_flush_blits(screenContext, SCREEN_WAIT_IDLE); + screen_post_window(window, buffer, 0, NULL, SCREEN_WAIT_IDLE); + return 0; +} + +static sqInt display_ioSetDisplayMode(sqInt width, sqInt height, sqInt depth, sqInt fullscreenFlag) { return 0; } +static void display_winSetName(char *imageName) { return ; } +static void display_winExit(void) { return ; } +static long display_winImageFind(char *buf, int len) { return 0; } +static void display_winImageNotFound(void) { return ; } + + +//---------------------------------------------------------------- + +// OSPP +static void *display_ioGetDisplay(void) { return 0; } +static void *display_ioGetWindow(void) { return 0; } + + +static sqInt display_primitivePluginBrowserReady() { return primitiveFail(); } +static sqInt display_primitivePluginRequestURLStream() { return primitiveFail(); } +static sqInt display_primitivePluginRequestURL() { return primitiveFail(); } +static sqInt display_primitivePluginPostURL() { return primitiveFail(); } +static sqInt display_primitivePluginRequestFileHandle() { return primitiveFail(); } +static sqInt display_primitivePluginDestroyRequest() { return primitiveFail(); } +static sqInt display_primitivePluginRequestState() { return primitiveFail(); } + +// Host Windows + +#if (SqDisplayVersionMajor >= 1 && SqDisplayVersionMinor >= 2) +static long display_hostWindowClose(long index) { return 0; } +static long display_hostWindowCreate(long w, long h, long x, long y, + char *list, long attributeListLength) { return 0; } +static long display_hostWindowShowDisplay(unsigned char *dispBitsIndex, long width, long height, long depth, + long left, long right, long top, long bottom, sqIntptr_t windowIndex) { return 0; } +static long display_hostWindowGetSize(long windowIndex) { return -1; } +static long display_hostWindowSetSize(long windowIndex, long w, long h) { return -1; } +static long display_hostWindowGetPosition(long windowIndex) { return -1; } +static long display_hostWindowSetPosition(long windowIndex, long x, long y) { return -1; } +static long display_hostWindowSetTitle(long windowIndex, char *newTitle, long sizeOfTitle) { return -1; } +static long display_hostWindowCloseAll(void) { return 0; } +#endif + +/* OpenGL */ + +static sqInt display_ioGLinitialise(void) { return 0; } +static sqInt display_ioGLcreateRenderer(glRenderer *r, sqInt x, sqInt y, sqInt w, sqInt h, sqInt flags) { return 0; } +static void display_ioGLdestroyRenderer(glRenderer *r) { } +static void display_ioGLswapBuffers(glRenderer *r) { } +static sqInt display_ioGLmakeCurrentRenderer(glRenderer *r) { return 0; } +static void display_ioGLsetBufferRect(glRenderer *r, sqInt x, sqInt y, sqInt w, sqInt h) { } + + +// new stubs for the CogVM +#if SqDisplayVersionMajor >= 1 && SqDisplayVersionMinor >= 3 +static long display_ioSetCursorPositionXY(long x, long y) { return 0; } +static long display_ioPositionOfScreenWorkArea (long windowIndex) { return -1; } +static long display_ioSizeOfScreenWorkArea (long windowIndex) { return -1; } +static void *display_ioGetWindowHandle() { return 0; } +static long display_ioPositionOfNativeDisplay(void *windowHandle) { return -1; } +static long display_ioSizeOfNativeDisplay(void *windowHandle) { return -1; } +static long display_ioPositionOfNativeWindow(void *windowHandle) { return -1; } +static long display_ioSizeOfNativeWindow(void *windowHandle) { return -1; } +#if SqDisplayVersionMajor >= 1 && SqDisplayVersionMinor >= 7 +static long display_ioScreenRectangles(void) { return 0; } +#endif // SqDisplayVersionMajor >= 1 && SqDisplayVersionMinor >= 7 +#endif // SqDisplayVersionMajor >= 1 && SqDisplayVersionMinor >= 3 + +//---------------------------------------------------------------- +/* Balloon splash image */ + +static void showBalloons(void *bufPtr) { + int x, y; + + x = screenWidth() / 2; + y = screenHeight() / 2; + showBalloonAt(bufPtr,x,y) ; + showBalloonAt(bufPtr,x+(x/2),y-(y/2)) ; + showBalloonAt(bufPtr,x+(x/2),y+(y/2)) ; + showBalloonAt(bufPtr,x-(x/2),y-(y/2)) ; + showBalloonAt(bufPtr,x-(x/2),y+(y/2)) ; +} + + +static void showBalloonAt(void *bufPtr, int left, int top) +{ + int x, y; + char *data = balloon_data, pixel[4]; + pixel_t myPixel; + int balloon_bytes_per_pixel = 4; /* 32 bits */ + + /* Center Balloon on x,y point */ + left -= balloon_width_pixels / 2; + top -= balloon_height_pixels / 2; + for (y = 0; y < balloon_height_pixels; y++) { + for (x = 0; x < balloon_width_pixels; x++) { + /* extract RGB values from Balloon data */ + BALLOON_PIXEL( data, pixel ); + /* above side effect: data += balloon_bytes_per_pixel */ + putPixel(left + x, + top + y, + ((pixel[0] << 16) | (pixel[1] << 8) | pixel[2])); /* RGB */ + } + } +} + + +//---------------------------------------------------------------- + + +#include "SqModule.h" + +SqDisplayDefine(qnxScreen); + +static void *display_makeInterface(void) +{ + return &display_qnxScreen_itf; +} + +SqModuleDefine(display, qnxScreen); + + +/* ------------------ E O F ------------------- */ diff --git a/platforms/unix/vm/include_ucontext.h b/platforms/unix/vm/include_ucontext.h index d599e987f2..a73cd7cf1b 100644 --- a/platforms/unix/vm/include_ucontext.h +++ b/platforms/unix/vm/include_ucontext.h @@ -22,6 +22,8 @@ #elif __sun /* Single UNIX Specification (SUS), Version 2 specifies */ # include +#elif __QNX__ +# include #else # include #endif @@ -113,6 +115,12 @@ # define _PC_IN_UCONTEXT sc_x[22] # define _FP_IN_UCONTEXT sc_x[21] # define _SP_IN_UCONTEXT sc_x[23] +#elif __QNX__ && (__arm64__ || __aarch64__ || ARM64) +/* See QNX includes: aarch64/context.h sys/ucontext.h */ +# define _PC_IN_UCONTEXT uc_mcontext.cpu.elr +# define _FP_IN_UCONTEXT uc_mcontext.cpu.gpr[AARCH64_REG_X29] +# define _SP_IN_UCONTEXT uc_mcontext.cpu.gpr[AARCH64_REG_SP] +/* Note: AARCH64_REG_SP == AARCH64_REG_X31 */ #endif #if !defined(_PC_IN_UCONTEXT) # error need to implement extracting pc from a ucontext_t on this system diff --git a/platforms/unix/vm/sqUnixCharConv.c b/platforms/unix/vm/sqUnixCharConv.c index 83adeca2a7..812d07820c 100644 --- a/platforms/unix/vm/sqUnixCharConv.c +++ b/platforms/unix/vm/sqUnixCharConv.c @@ -40,7 +40,9 @@ #include #include +#if !defined(__QNX__) static inline int min(int x, int y) { return (x < y) ? x : y; } +#endif static int convertCopy(char *from, int fromLen, char *to, int toLen, int term) { diff --git a/platforms/unix/vm/sqUnixSpurMemory.c b/platforms/unix/vm/sqUnixSpurMemory.c index 38df718b91..07f79e0d47 100644 --- a/platforms/unix/vm/sqUnixSpurMemory.c +++ b/platforms/unix/vm/sqUnixSpurMemory.c @@ -39,7 +39,9 @@ #if DUAL_MAPPED_CODE_ZONE # if !__APPLE__ # if !__OpenBSD__ +# if !__QNX__ # include +# endif # endif # endif #ifdef HAVE_SYS_STAT_H @@ -105,12 +107,19 @@ int mmapErrno = 0; # define MAP_FLAGS (MAP_ANON | MAP_PRIVATE) # endif +#if !defined(__QNX__) static int min(int x, int y) { return (x < y) ? x : y; } static int max(int x, int y) { return (x > y) ? x : y; } // a hint of the lowest possible address for mmap -#define lowestPageAlignedAddressForMMap() \ +# define lowestPageAlignedAddressForMMap() \ (assert(pageSize), (void *)roundUpToPage((usqInt)sbrk(0))) +#else +// QNX does not usefully implement sbrk() +# define lowestPageAlignedAddressForMMap() \ + 0 +#endif + /* Answer the address of minHeapSize rounded up to page size bytes of memory. */